I'm trying to create a line-drawing algorithm in assembly (more specifically Bresenham's line algorithm). After trying an implementation of this algorithm, the algorithm fails to work properly even though I almost exactly replicated the plotLineLow() function from this Wikipedia page.
It should be drawing a line between 2 points, but when I test it, it draws points in random places in the window. I really don't know what could be going wrong because debugging in assembly is difficult.
I'm using NASM to convert the program to binary, and I run the binary in QEMU.
[bits 16] ; 16-bit mode
[org 0x7c00] ; memory origin
section .text ; code segmant
global _start ; tells the kernal where to begin the program
_start: ; where to start the program
; main
call cls ; clears the screen
update: ; main loop
mov cx, 0x0101 ; line pos 1
mov bx, 0x0115 ; line pos 2
call line ; draws the line
jmp update ; jumps to the start of the loop
; functions
cls: ; function to clear the screen
mov ah, 0x00 ; set video mode
mov al, 0x03 ; text mode (80x25 16 colours)
int 0x10 ; BIOS interrupt
ret ; returns to where it was called
point: ; function to draw a dot at a certain point (dx)
mov bx, 0x00ff ; clears the bx register and sets color
mov cx, 0x0001 ; clears the cx register and sets print times
mov ah, 0x02 ; set cursor position
int 0x10 ; BIOS interrupt
mov ah, 0x09 ; write character
mov al, ' ' ; character to write
int 0x10 ; BIOS interrupt
ret ; returns to where it was called
line: ; function to draw a line at two points (bx, cx)
push cx ; saves cx for later
push bx ; saves bx for later
sub bh, ch ; gets the value of dx
mov [dx_L], bh ; puts it into dx
sub bl, cl ; gets the value of dy
mov [dy_L], bl ; puts it into dy
mov byte [yi_L], 1 ; puts 1 into yi (positive slope)
cmp byte [dy_L], 0 ; checks if the slope is negative
jl .negative_y ; jumps to the corresponding sub-label
jmp .after_negative_y ; if not, jump to after the if
.negative_y: ; if statement destination
mov byte [yi_L], -1 ; sets yi to -1 (negative slope)
neg byte [dy_L] ; makes dy negative as well
.after_negative_y: ; else statement destination
mov ah, [dy_L] ; moves dy_L into a temporary register
add ah, ah ; multiplies it by 2
sub ah, [dx_L] ; subtracts dx from that
mov [D_L], ah ; moves the value into D
pop bx ; pops bx to take a value off
mov [y_L], bh ; moves the variable into the output
pop cx ; pops the stack back into cx
mov ah, bh ; moves x0 into ah
mov al, ch ; moves x1 into al
.loop_x: ; loop to go through every x iteration
mov dh, ah ; moves the iteration count into dh
mov dl, [y_L] ; moves the y value into dl to be plotted
call point ; calls the point function
cmp byte [D_L], 0 ; compares d to 0
jg .greater_y ; if greater, jumps to the if statement
jmp .else_greater_y ; if less, jumps to the else statement
mov bh, [dy_L] ; moves dy into a temporary register
.greater_y: ; if label
mov bl, [yi_L] ; moves yi into a temporary register
add [y_L], bl ; increments y by the slope
sub bh, [dx_L] ; dy and dx
add bh, bh ; multiplies bh by 2
add [D_L], bh ; adds bh to D
jmp .after_greater_y ; jumps to after the if statement
.else_greater_y: ; else label
add bh, bh ; multiplies bh by 2
add [D_L], bh ; adds bh to D
.after_greater_y: ; after teh if statement
inc ah ; increments the loop variable
cmp ah, al ; checks to see if the loop should end
je .end_loop_x ; if it ended jump to the end of teh loop
jmp .loop_x ; if not, jump back to the start of the loop
.end_loop_x: ; place to send the program when the loop ends
ret ; returns to where it was called
section .data ; data segmant
dx_L: db 0 ; used for drawing lines
dy_L: db 0 ; ^
yi_L: db 0 ; ^
xi_L: db 0 ; ^
D_L: db 0 ; ^
y_L: db 0 ; ^
x_L: db 0 ; ^
section .text ; code segmant
; boot the OS
times 510-($-$$) db 0 ; fills up bootloader space with empty bytess
db 0x55, 0xaa ; defines the bootloader bytes