【问题标题】:Bresenham's line algorithm in MIPSMIPS 中的 Bresenham 线算法
【发布时间】:2021-04-15 12:30:07
【问题描述】:

我需要使用 Bresenham 的线条算法在 32x32 白色/黑色图像上画一条线。我已经读过_bmp 和 save_bmp 函数,以及设置颜色的函数、绘制像素的函数和绘制线条的函数。不幸的是,当我编译我的代码时,result.bmp 文件中只显示了像素。

.eqv    pHeader 0
.eqv    filesize 4
.eqv    pImg    8
.eqv    width   12
.eqv    height  16
.eqv    linesbytes 20

.eqv    bi_imgoffset  10
.eqv    bi_imgwidth   18
.eqv    bi_imgheight  22

.eqv    max_file_size 2048

    .data
filename:   .asciiz "white32x32.bmp"
resultfile: .asciiz "result.bmp"
color_err:  .asciiz "Incorrect color - should be 0 or 1"

num_one:      .word 1
num_neg_one:  .word -1
mult2:  .word 2
loop:   .word 32
        .align  4
descriptor: .word   0, 0, 0, 0, 0, 0, 0, 0, 0

filebuf:    .space max_file_size

    .text
    
    
    move $t0, $zero 
    lw   $s0, loop 
main:
    la $a0, filename
    la $a1, descriptor
    la $t0, filebuf
    sw $t0, pHeader($a1)
    li $t0, max_file_size
    sw $t0, filesize($a1)
    jal read_bmp_file
    # check for errors
    
    
        la   $a0, descriptor
        li   $a1, 6  #cx
        li   $a2, 8  #cy
        li   $a3, 0  #color
        li $s0, 10   #x
        li $s1, 12   #y
        jal line_to
        addi $t0, $t0, 32
        j main
        
        move $t0, $zero 
    lw   $s0, loop 
    li $v0, 10
    syscall
    
line_to:
    

# |register|   variable  |
# | t0     |   cx        |   
# | t1     |   cy        |
# | t2     |    dx - dy  |   
# | t3     |   ai        |
# | t4     |   bi        |
# | s0     |   x         |
# | s1     |   y         |
# | s2     | dx = x-cx   |
# | s3     } dy = y-cy   |      
# | s4     |   xi        |
# | s5     |   yi        |


    sub $s3, $s0, $t0 #s3 = x - cx
    sub $s4, $s1, $t1 #s4 = y - cy

#if (dx < 0) { xi = 1 } else { xi = -1}
    slt $t0, $s0, $s1   #dx = -dx;
    beq $t0, $zero, if_1_else  
    if_1_then:
     lw $s4, num_one
         j if_1_exit
    if_1_else:
         lw $s4, num_neg_one
    if_1_exit:

#if (dy < 0) { yi = 1 } else { yi = -1}
    slt $t0, $s0, $s1   #dy = -dy;
    beq $t0, $zero, if_2_else  
    if_2_then:
        lw $s5, num_one
         j if_2_exit
    if_2_else:
         lw $s5, num_neg_one
    if_2_exit:

    sub $t2, $s2, $s3 #   dy - dx

    lw $t0, num_neg_one
    mult $t0, $s3
    mflo $s3 # s3 = -dy

    move $t0, $a0 # t0 = cx
    move $t1, $a1 # t1 = cy
    move $s1, $s0 # s0 = x
    move $s2, $s1 # s1 = y
    jal set_next_pixel

loop_cond:
    

    sub $t3, $s1, $t0 
    sub $t4, $s2, $t1 
    add $t3, $t3, $t4 
    beqz $t3, loop1_end
    
    lw $t3, mult2
        mult $t3, $t2
        mflo $t3
        
        slt $t4, $s3, $t3 
    beqz $t4, loop1_end
    
    lopp_if_1_then:
        add $t2, $t2, $s3 
        add $t0, $t0, $s4 
        loop1_end:
        
        slt $t4, $t3, $s2 
        beqz $t4, loop2_end
        loop_if_2_then:
        add $t2, $t2, $s2 
        add $t1, $t1, $s5 
        loop2_end:

        j loop_cond 
        
 #loop_cond_end:
         
        
    jr $ra
set_next_pixel:
    lw $t0, linesbytes($a0)
    mul $t0, $t0, $a2   # $t0 offset of the beginning of the row
    
    sra $t1, $a1, 3     # pixel byte offset within the row
    add $t0, $t0, $t1   # pixel byte offset within the image
    
    lw $t1, pImg($a0)
    add $t0, $t0, $t1   # address of the pixel byte
    
    lb $t1, 0($t0)
    
    and $a1, $a1, 0x7   # pixel offset within the byte
    li $t2, 0x80
    srlv $t2, $t2, $a1  # mask on the position of pixel
    
    jal set_color
#   sub $a3, $a3, 1
#   bnez $a3, set_next_pixel
    
    la $a0, resultfile
    la $a1, descriptor
    jal save_bmp_file
    
    li $v0, 10
    syscall
    
set_color:
    addi $v1, $zero, 1
    blt $a3, $zero, print_color_err     # if a3 < 0, then error
    bgt $a3, $v1, print_color_err   #if a3 > 1, then error
    beq $a3,$v1, white  # if a3 = 1, then white
        beq $a3,$zero, black    # if a3 = 0, then black
        jr $ra
black:
    xor $t1, $t1, $t2    # set proper pixel to 0 (black)
    sb $t1, 0($t0)
    jr $ra
white:
    or $t1, $t1, $t2    # set proper pixel to 1 (white)
    sb $t1, 0($t0)
    jr $ra
print_color_err:
    li $v0, 4
    la $a0, color_err
    syscall


read_bmp_file:
    # $a0 - file name 
    # $a1 - file descriptor
    #   pHeader - contains pointer to file buffer
    #   filesize - maximum file size allowed
    move $t0, $a1
    li $a1, 0
    li $a2, 0
    li $v0, 13 # open file
    syscall
    # check for errors: $v0 < 0
    
    move $a0, $v0
    lw $a1, pHeader($t0)
    lw $a2, filesize($t0)
    li $v0, 14
    syscall
    
    sw $v0, filesize($t0)  # actual size of bmp file

    li $v0, 16 # close file
    syscall

    lhu $t1, bi_imgoffset($a1)
    add $t1, $t1, $a1
    sw $t1, pImg($t0)
    
    lhu $t1, bi_imgwidth($a1)
    sw $t1, width($t0)
    
    lhu $t1, bi_imgheight($a1)
    sw $t1, height($t0)
    
    # number of words in a line: (width + 31) / 32
    # number of bytes in a line: ((width + 31) / 32) * 4
    lw $t1, width($t0)
    add $t1, $t1, 31
    sra $t1, $t1, 5 # t1 contains number of words
    sll $t1, $t1, 2
    sw $t1, linesbytes($t0)
    jr $ra
    


save_bmp_file:
    # $a0 - file name 
    # $a1 - file descriptor
    #   pHeader - contains pointer to file buffer
    #   filesize - maximum file size allowed
    move $t0, $a1
    li $a1, 1  # write
    li $a2, 0
    li $v0, 13 # open file
    syscall
    # check for errors: $v0 < 0
    
    move $a0, $v0
    lw $a1, pHeader($t0)
    lw $a2, filesize($t0)
    li $v0, 15
    syscall
    
    li $v0, 16 # close file
    syscall

除了 line_to 之外的每个函数都可以正常工作,但我不知道是什么导致 line_to 出现问题。

【问题讨论】:

    标签: algorithm mips mars-simulator bresenham


    【解决方案1】:

    您需要一种调试理念。

    静态调试

    • 确保您的 C/伪代码算法确实有效,否则当您还在学习汇编时,很难在汇编中调试设计问题。 (最好的方法是用 C 编写伪代码并实际运行它。)

    • 阅读代码并验证指令中命名的每个寄存器是否对应于算法中的正确变量。例如,

      # | s3     } dy = y-cy   |      
      # | s4     |   xi        |
      # | s5     |   yi        |
      
      sub $s3, $s0, $t0 #s3 = x - cx    # here s3 is dx, but comment above says s3 is dy
      sub $s4, $s1, $t1 #s4 = y - cy    # here s4 is dy, but comment above says s4 is xi
      
      

    可以看到cmets和code不匹配。

    (顺便说一句,+1 用于编写寄存器变量映射。)

    动态调试

    • 在每个函数的开头检查参数是否正确传递
    • 从最简单的测试用例开始,例如一条水平线和/或一条垂直线——甚至可能是一条只有 1 点长的线。
    • 单步执行,按照每条指令的效果
      • 在每条指令之后,验证每个寄存器是否具有您期望的值
      • 在每条指令之后,验证分支的控制流是否正确
      • 验证内存是否按照存储指令的预期更新

    其他问题

    • 您的静态调用链有main 调用line_toline_to 调用set_next_pixelset_next_pixel 调用set_color。每次使用jal 时,它都会重新调整$ra 寄存器的用途,但是这些函数中的每一个都需要它们自己的$ra 值才能返回给它们的调用者。通常这是通过创建一个堆栈帧并将$ra 存储在非叶例程中来处理的,然后在返回给调用者之前重新加载$ra。 (叶函数——不调用其他函数的函数——不需要这样做。)

    • set_next_pixel 不完整,缺少返回给调用者的信息。

    • print_color_err 的代码完全属于read_bmp_file。它应该返回,或者可能结束程序。

    其他观察

    • 不要将 lw 与常量一起使用以将 +1 或 -1 放入寄存器 - 只需使用 li $t0, -1(或 addi $t0, $0, -1,如果您不想使用伪指令。)

    • set_color 处的代码测试了太多条件,应该简化。它正在测试$a3 for 1, = 1, = 0,并且仍然有一个else 子句以防这些测试都不成功。

    • 通过0-x 比使用乘法-1*i 更容易进行求反

    • 通过移位 1 (sll $trg, $src, 1) 比使用乘法更容易实现加倍

    • 您的调用约定是非标准的。这没关系,但会使其他人更难阅读代码,并且更容易出错。

    【讨论】:

    • 到目前为止,除了动态调试之外,我已经做了所有事情,我有一个问题:如何处理静态调用链?
    • 通常这是通过在非叶子例程中创建一个堆栈帧并将 $ra 存储在那里,然后在返回给调用者之前重新加载 $ra 来处理的。 (叶函数——不调用其他函数的函数——不需要这样做。)
    • 另外我不知道 line_to 函数中还有什么(例如在 loop_cond_end :)。据我了解,仅算法就可以(在 C 中检查)。
    • 调用其他函数的函数需要保留其 $ra 参数,以便在返回给调用者时可以在最后使用该值。查找 MIPS 函数调用和堆栈帧。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-15
    相关资源
    最近更新 更多