Warm tip: This article is reproduced from serverfault.com, please click

Infinite loops seemingly not working in NASM?

发布于 2020-12-21 18:44:22

I'm trying to make a DOS program in NASM that uses interrupt 10h to display a pixel cycling through the 16 available colors in the top left corner. I also use interrupt 21h to only make the program run every 1/100 seconds (100 fps).

segment .data
    pixelcolor: db 0
    pixelx: dw 100
    pixely: dw 100
    timeaux: db 0 ; used later on to force the program to run at 100fps
segment .text
    global _start
    
_start:
    mov ah,00h
    mov al,0dh
    int 10h
    
    mov ah,0bh
    mov bh,00h
    mov bl,00h
    int 10h
    
    .infinite:
        mov ah,2ch
        int 21h ; get system time
        cmp dl,timeaux ; if 1/100 seconds haven't passed yet...
        je .infinite ; ...skip current frame
        ; else, continue normally
        mov byte[timeaux],dl
        
        mov ah,00h
        mov al,0dh
        int 10h
        mov ah,0bh
        mov bh,00h
        mov bl,00h
        int 10h
        
        mov ah,0ch
        mov al,pixelcolor
        mov cx,pixelx
        mov dx,pixely
        int 10h
        inc byte[pixelcolor]
        
        jmp .infinite

However, when I actually run the program in DOSBox, the pixel just stays red. Does anyone know why my infinite loops aren't working? (Note: I'm very new to NASM, so honestly I'm not even suprised my programs only work 15% of the time.)

Questioner
NabeGameDev
Viewed
0
Michael Petch 2020-12-22 05:01:08

The problem isn't actually the loop itself. What the loop is doing each iteration is the problem. Some issues and observations I have are:

  • Since this is a DOS COM program you will need an org 100h at the top since a COM program is loaded by the DOS loader to offset 100h of the current program segment. Without this the offsets of your data will be incorrect leading to data being read/written to from the wrong memory locations.

  • You have a problem with mov al,pixelcolor. It needs to be mov al,[pixelcolor]. Without square brackets1 the offset of pixelcolor is moved to AL, not what is stored at offset of pixelcolor. The same goes for pixelx and pixely. Your code prints the same pixel color (red in your case) to the wrong place2 on the screen repeatedly. This code:

      mov ah,0ch
      mov al,pixelcolor
      mov cx,pixelx
      mov dx,pixely
      int 10h
      inc byte[pixelcolor]
    

    should be:

      mov ah,0ch
      mov al,[pixelcolor]
      mov cx,[pixelx]
      mov dx,[pixely]
      int 10h
      inc byte[pixelcolor]
    
  • It should be noted that the resolution of the timer by default will only be 18.2 times a second (~55ms). This is less resolution than the 1/100 of a second you are aiming for.

  • Some versions of DOS may always return 0 for the 1/100 of a second value.

  • Use of the BIOS to write pixels to the screen may make coding simpler (it abstracts away differences in the video modes) but will be quite slow compared to writing pixels directly to memory.

  • I would recommend Borland's Turbo Debugger (TD) for debugging DOS software. Turbo Debugger is included in a number of Borland's DOS C/C++ compiler suites.


Footnotes

  • 1The use of brackets [] in NASM differs from MASM/TASM/JWASM.
  • 2Although your question says you want to write to the upper left of the screen, the code suggests you really intended to write the pixel at coordinate 100,100.