FPU хранит nan с fld

Пишу DOS-программу на ассемблере: пытаюсь нарисовать множество Мандельброта. Сейчас я пытаюсь перевести этот фрагмент кода C на ассемблере:

double x0 = i * 3.2 / maxX - 2.1; //scaled x coordinate of pixel (-2.1, 1.1)

Я перевел это как:

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

К сожалению, первый fld терпит неудачу. Отладчик WD сообщает мне, что fld хранит nan в регистре ST(0) FPU. Почему? Что я делаю не так? Вот полная программа: 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

person user1527576    schedule 20.01.2013    source источник
comment
Я могу ошибаться, но разве это не должно быть fld [scaleX], так как scaleX — это метка (адрес) в сегменте данных?   -  person Axel Gneiting    schedule 20.01.2013
comment
@AxelGneiting masm должен это понять. Основная проблема в том, что ds не указывает на dseg, поэтому fld будет считывать данные неизвестно откуда.   -  person Alexey Frunze    schedule 20.01.2013


Ответы (1)


Одна проблема, которую я вижу, заключается в том, что вы не устанавливаете ds и es так, чтобы они указывали на сегмент dseg. Вы несете ответственность за это для программ .EXE, а не для DOS, ассемблера или компоновщика.

Измените код следующим образом:

cseg    SEGMENT
START:
        mov     ax, dseg
        mov     ds, ax
        mov     es, ax
        mov     maxX, largh
        mov     maxY, alt
        ...

Также у вас нет сегмента стека, что плохо, поскольку прерывания могут перезаписать ваш код или данные.

Добавить один:

sseg segment stack 'stack'
  dw 2048 dup (?)
sseg ends
person Alexey Frunze    schedule 20.01.2013
comment
Кажется, теперь это работает :) Спасибо! Сейчас сделаю другой тест! - person user1527576; 20.01.2013