I'm writing a DOS program in assembly: I'm trying to draw the Mandelbrot set. I'm now trying to translate this piece of C code in assembly:
double x0 = i * 3.2 / maxX - 2.1; //scaled x coordinate of pixel (-2.1, 1.1)
I've translated it as:
finit
fld scaleX ;contains 3.5, declared with
fimul xCoord ;the i coordinate
fidiv maxX ;maximum width (320)
fsub offsetX ;result is scaleX * xCoord / maxX - offsetX
fstp x0 ;store the result in x0
Unfortunately the first fld
fails. The WD debugger tells me that fld
stores nan
in the ST(0)
FPU register. Why? What am I doing wrong? Here's the complete program: http://pastebin.com/KDrn5aLD
.387
assume cs:cseg, ds:dseg
uint TYPEDEF word
integer TYPEDEF word
float TYPEDEF real4
double TYPEDEF real8
largh = 320 ;larghezza dello schermo
alt = 200 ;altezza dello schermo
dseg SEGMENT para public 'data'
maxX integer 0
maxY integer 0
xCoord integer 0
yCoord integer 0
x0 double 0.0 ;coordinata x del pixel riscalata a (-2.1 - 1.1)
y0 double 0.0 ;coordinata y del pixel riscalata a (-2.1 - 1.1)
scaleX double 3.2
scaleY double 2.0 ;scala in X ed in Y delle coordinate
offsetX double 2.1
offsetY double 1.0
x double 0.0
y double 0.0 ;valori della serie in un determinato punto (xo, yo)
zeroConst double 0.0 ;costante double 0.0
dseg ENDS
cseg SEGMENT
START:
mov maxX, largh
mov maxY, alt
mov xCoord, 0
forX: cmp xCoord, largh
jae finish
;mov dl,69
;mov ah,2
;int 21h ;test loop forX
mov yCoord, 0
cmp yCoord, alt
jae nextX
forY: cmp yCoord, alt
jnb nextX
;forY code here
finit
fld scaleX ;coordinate X
fimul xCoord
fidiv maxX
fsub offsetX ;calcolo scala * coordinata / coordinataMax - offset
fstp x0
; fld scaleY ;coordinate Y
; fimul yCoord
; fidiv maxY
; fsub offsetY ;calcolo scala * coordinata / coordinataMax - offset
; fstp y0
;
; fld zeroConst
; fst x
; fstp y
inc yCoord
jmp forY
nextX: inc xCoord
jmp forX
finish: mov dl, 70
mov ah, 2
int 21h
mov ah, 4Ch ;DOS terminate opcode
xor al, al
int 21h ;DOS call
cseg ENDS
END START
One problem I'm seeing is that you are not setting ds
and es
to point to the dseg
segment. It is your responsibility to do that for .EXE programs, not DOS', assembler's or linker's.
Modify the code like so:
cseg SEGMENT
START:
mov ax, dseg
mov ds, ax
mov es, ax
mov maxX, largh
mov maxY, alt
...
Also you don't have any stack segment, which is bad as interrupts may overwrite your code or data.
Add one:
sseg segment stack 'stack'
dw 2048 dup (?)
sseg ends