I'm trying to implement a version of Bresenham's line-drawing algorithm in 16-bit assembly by passing the coordinates through registers (deliberately not using the stack or writing to video memory right now). It plots the very first pixel correctly (x1 and y1), but nothing else happens.
The following is how the coordinates of the line is defined:
real_start:
movw $boot_message, %si # Display our boot message
call cons_writeline
# Switch to VGA mode 13
movb $0, %ah
movb $0x13, %al
int $0x10
# lines are defined in the registers from this point
movw $5, %cx # x coordinate
movw $10, %dx # y coordinate
movw $100, %bx # x2 coordinate
movw $100, %ax # y2 coordinate
movb $2, %bl # colour green
call bresenham_start
And this is the main code
draw_pixel:
movb (colour), %al # move colour to al
movb $0x0c, %ah
movb $0, %bh
int $0x10
jmp bresenham_main
bresenham_start:
movw %cx, (x1)
movw %dx, (y1)
movw %bx, (x2)
movw %ax, (y2)
movb %bl, (colour)
sub %cx, %bx # delta x = x2 - x1
movw %bx, (delta_x) # store result in delta_x
sub %dx, %ax # delta y = y2 - y1
movw %ax, (delta_y) # store result in delta_y
sub %ax, %bx # err = delta x - delta y
movw %bx, (err)
movw (x1), %cx #
movw (x2), %dx # Reset the coordinates to their original registers
movw (x1), %cx
movw (x2), %dx
movw $1, (sx)
cmp %dx, %cx
jl sx_end # if x1 is less than x2, it jumps to sx_end and keeps sx as 1
movw $-1, (sx) # if x1 is more than x2, it sets sx to -1 and plods along
sx_end:
movw (y1), %cx
movw (y2), %dx
movw $1, (sx)
cmp %dx, %cx
jl sy_end # if y1 is less than y2, it jumps to sy_end and keeps sy as 1
movw $-1, (sx) # if y1 is more than y2, it sets sy to -1 and plods along
sy_end:
jmp bresenham
bresenham:
movw (x1), %cx #
movw (x2), %bx # Reset the coordinates to their original registers
movw (y1), %dx # ^^
movw (y2), %ax #
# jump to draw_pixel
jmp draw_pixel
bresenham_main:
# check if x1 = x2 and y1 = y2
cmp %cx, %bx # Check if x1 is less than x2
jne carry_on # Condition in pseudocode uses and, meaning we don't break from the loop if x1 is not equal to x2
cmp %dx, %ax # Check if y1 equals y2
je break # break from the loop if y1 = y2, since to reach this part of the code, x1 is equal to x2
carry_on: # Else:
# calculate e2
movw (err), %ax # move err into ax
movw $2, %dx # set bx to 2
mul %dx # when operand is a word: (DX AX) = AX * operand
movw %ax, (e2) # put the result into e2
# Check if e2 = -dy
# e2 is already in ax
movw (delta_y), %bx
neg %bx # flip delta_y to negative
cmp (e2), %bx
jg carry_on_two # skips this block of code if e2 > -dy
movw (err), %cx # move err into cx
add %bx, %cx # add -dy to err, which is same as err - dy
movw (x1), %dx # move x1 to dx
add (sx), %dx # add sx to x1 and store it in dx
carry_on_two: # code resumes here from the if statement
# e2 is currently in ax
movw (delta_x), %bx # move delta_x to bx
cmp %ax, %bx
jne inc_y # add delta_x to err and increment y1 by sy, then continue loop
jmp bresenham # continue the loop
inc_y: # if e2 < dx
movw (y1), %ax # move y1 to ax
movw (sy), %bx # move sy to bx
add %ax, %bx # add y1 to sy and store it in bx
movw %bx, (y1) # set y1 to the new result
jmp bresenham # jump back to beginning of loop
break:
ret
This is the data portion:
x1: .word 0 # x1 coordinate, i.e. the starting coordinate of x
x2: .word 0 # x2 coodinate, i.e. the ending coordinate of x
y1: .word 0 # y1 coordinate, i.e. the starting coordinate of y
y2: .word 0 # y2 coordinate, i.e. the ending coordinate of y
sx: .word 0
sy: .word 0
delta_x: .word 0 # Delta x variable
delta_y: .word 0 # Delta y variable
err: .word 0 # error variable
e2: .word 0
colour: .byte 0
I've read and reread the code, but as there are no errors, I cannot find where I've messed up. I followed the implementation of this pseudocode line by line, and it seems to check out.
function drawline(x1, y1, x2, y2, colour)
dx := abs(x2 - x1)
dy := abs(y2 - y1)
if x1 < x2 then sx := 1 else sx := -1
if y1 < y2 then sy := 1 else sy := -1
err := dx - dy
loop
setPixel(x1, y1, colour)
if x1 = x2 and y1 = y2 exit loop
e2 := 2 * err
if e2 > -dy then
err := err - dy
x1 := x1 + sx
end if
if e2 < dx then
err := err + dx
y1 := y1 + sy
end if
end loop