I don't know if anyone will be able to help me, but I will try to explain my problem as clearly, as possible. I am learning 8086 FPU with YASM. I want to draw y = cos(x^2 x 1) This is how this graph looks like. I am doing it in DosBox, and I am emulating 8086 processor.
My problem: How to normalize graph's(red) ratio, so it could be readable in DosBox.
So far, I managed to draw a coordinate plane. And I think I managed to draw this graph, but the ratio is too small to check if it is really good. This is how it looks so far GRAPH IMAGE](https://i.stack.imgur.com/0Hy6X.jpg).
I am using FPU, to calculate Y coordinates. I am using stack to calculate Y coordinate. X coordinate will go from 320 to 0 (with dec si), as you can see in my code.
In this code, I am trying to calculate Y (di) every with different X (si). And put the pixel in the spot, that it has to be in.
;------------------------------------------------------------------------
%include 'yasmmac.inc'
org 100h
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
section .text ; Code starts here
startas:
call procSetGraphicsMode
;;;;;;;;;;;;;;;;;;;;;;;;; COORDINATE PLANE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
mov di, 200
mov si, 160
.vertical:
mov cl, 15
call procPutPixel
dec di
jnz .vertical
mov si, 320
.horizontal:
mov di, 100
mov cl, 15 ; 15 = white color
call procPutPixel
dec si
jnz .horizontal
; y = di
; x = si
mov si, 320
mov di, 100
;;;;;;;;;;;;;;;;;;;;;;;; GRAPH ;;;;;;;;;;;;;;;;;;;;;;;;
.loop:
mov [value1], si
mov [value2], si
finit
fild dword [value1]
fild dword [value1]
fild dword [value3] ; move to stack 1
fmul dword [value1]
fadd st0, st1 ; add x in stack head
fadd st0, st3 ; add 1 in stack head
fcos ; cos(x^2 x 1)
frndint ; round
fistp word [y] ; Load rounded answer to [y] variable
add di, [y] ; Add [y] to di
mov cl, 4 ; 4 = Red color
call procPutPixel
dec si
jnz .loop
;;;;;;;;;;;;;;;;;;;;;;;; WAIT FOR ESC ;;;;;;;;;;;;;;;;;;;;;;;;
call procWaitForEsc
exit
%include 'yasmlib.asm'
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
section .data ; data
value1:
dd 0.0
value2:
dd 0.0
value3:
dd 1.0
xc:
dw 160
yc:
dw 100
x:
dw 0
y:
dw 0
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
section .bss
yasmlib.asm If it helps
CodePudding user response:
The axes are the easy part
Since you are working on a graphics screen that has a resolution of 320 x 200, the X coordinates range from 0 to 319 and the Y coordinates range from 0 to 199. Your code erroneously outputs in X's of 320 and y's of 200 and you don't use the X's of 0 or the Y's of 0.
xor di, di ; Y
.vertical:
mov si, 160 ; X
mov cl, 15 ; Color
call procPutPixel
inc di
cmp di, 199 ; MaxY
jbe .vertical
xor si, si ; X
.horizontal:
mov di, 100 ; Y
mov cl, 15 ; Color
call procPutPixel
inc si
cmp si, 319 ; MaxX
jbe .horizontal
; y = di
; x = si
mov si, 320
mov di, 100
The data definitions
value1: dd 0.0 value2: dd 0.0 value3: dd 1.0
Your FPU instructions are dealing with values stored in memory, but are doing so in incompatible ways! eg. value1 can't be both an integer dword and an single precision float at the same time. You primed this variable with the value from the 16-bit integer register SI, so deal with it as a 16-bit integer.
valueX: dw 0
The calculation
finit
(better use the non-waiting fninit
) is best held outside of the loop.
frndint
is redundant since fistp word [y]
will automatically do the rounding for you.
fmul st0
can square the value from st0.
fld1
can load the value 1 to the FPU stack. No need for a memory based variable and also no need to reload it for every X.
xor si, si ; X
fninit
fld1 ; CONST 1
.loop:
mov [valueX], si ; X
fild word [valueX] ; st0 = X
fmul st0 ; st0 = X^2
fiadd word [valueX] ; st0 = X^2 X
fadd st0, st1 ; st0 = X^2 X 1
fcos ; st0 = cos(X^2 X 1) [-1, 1]
...
fistp word [y] ; {-1,0, 1}
mov di, 100 ; Y
add di, [y] ; -> Y={99,100,101}
mov cl, 4 ; Color
call procPutPixel
inc si
cmp si, 319
jbe .loop
fstp ; Clean FPU stack, removing the CONST 1
Getting the output readable
The cosine value that the FPU delivers ranges from -1 to 1, but storing this value in the integer memory variable y will produce but 3 discrete values -1, 0, and 1.
What is needed is scaling the cosine by some factor like say 60.
Add this to the data:
scaleY: dw 60
and at the ellipses you add fimul word [scaleY]
, producing:
fcos ; st0 = cos(X^2 X 1) [-1, 1]
fimul word [scaleY] ; st0 = cos(X^2 X 1) * 60
fistp word [y] ; [-60, 60]
mov di, 100 ; Y
add di, [y] ; -> Y=[40,160]