尝试绘制 Bresenham 圆,无法获得视觉效果 MARS IDE

Trying to draw Bresenham's Circle, cannot get visuals MARS IDE

所以我尝试使用 Bresenham 算法绘制一个圆,但我似乎无法在位图显示上获得任何输出。也许我的绘图工作不正常,因为它似乎没有将颜色保存到目标地址。

这是我正在关注的文章,可帮助指导我完成此过程。它是用 C++ 编写的 Bresenham's Circle

我很难找到解释如何修改显示的可靠来源,我根据这篇文章写了我的显示内存。 drawing a 8x8 unit in BitMap Display Mips

我有注释解释过程,使用$a寄存器作为指定参数寄存器

.text

main:
    li   $a0, 50      # x
    li   $a1, 50      # y
    li   $a2, 30      # r2
    
    jal circleBres 
    
    li   $v0, 10
    syscall


# $a0: passed as xc
# $a1: passed as yc
# $a2: passed as the radius - r
circleBres:
    li $s0, 0x00FF0000  #loads the color red into the register $a2
    
    add  $sp, $sp, 4
    sw   $ra, 0($sp)
    
    move $s1, $a0      # this is xc
    move $s2, $a1      # this is yc 
    move $s3, $a2      # this is r - this is y
    li   $s4, 0
    li   $a0, 3
    li   $a1, 2
    sub  $s5, $a0, $a1 # d = 3 - 2
    mul  $s5, $s5, $s3 # d = d * r
    
    move $a0, $s1      # Set parameter registers
    move $a1, $s2      # to proper values and call
    move $a2, $s4      # the first draw
    move $a3, $s3
    jal drawCircle  
circleBresLoop:
    bge  $s3, $s4, end # Break if y >= x
    add  $s4, $s4, 1   # x++
    blt  $s5, 0, else  # if (d > 0) otherwise else
    sub  $s3, $s3, 1   # y--
    # d = d + 4 * (x - y) + 10
    sub  $t0, $s4, $s3 # $t0 = (x - y)
    mul  $t0, $t0, 4   # $t0 = $t0 * 4
    add  $t0, $t0, $s5 # $t0 = $t0 + d
    add  $t0, $t0, 10  # $t0 = $t0 + 10
    j skip
else:
    # d = d + 4 * x + 6
    mul  $t0, $s4, 4   # $t0 = x * 4
    add  $t0, $t0, $s5 # $t0 = $t0 + d
    add  $t0, $t0, 6
skip:
    move $a0, $s1      # Set parameter registers
    move $a1, $s2      # to proper values and call
    move $a2, $s4      # draw
    move $a3, $s3
    jal drawCircle  
    
    j circleBresLoop
    
end:
    lw   $ra, 0($sp)
    add  $sp, $sp, 4    

    jr $ra

# $a0: passed as xc
# $a1: passed as yc
# $a2: passed as x
# $a3: passed as y
drawCircle:
    add  $sp, $sp, -4
    sw   $ra, 0($sp)
    
    #1
    add  $s1, $a0, $a2  # xc + x
    add  $s2, $a1, $a3  # yc + y
    move $a0, $s1
    move $a1, $s2
    jal   drawPixel    
    #2
    sub  $s1, $a0, $a2  # xc - x
    add  $s2, $a1, $a3  # yc + y
    move $a0, $s1
    move $a1, $s2
    jal   drawPixel
    #3
    add  $s1, $a0, $a2  # xc + x
    sub  $s2, $a1, $a3  # yc - y
    move $a0, $s1
    move $a1, $s2
    jal   drawPixel
    #4
    sub  $s1, $a0, $a2  # xc - x
    sub  $s2, $a1, $a3  # yc - y
    move $a0, $s1
    move $a1, $s2
    jal   drawPixel
    #5
    add  $s1, $a0, $a3  # xc + y
    add  $s2, $a1, $a2  # xc + x
    move $a0, $s1
    move $a1, $s2
    jal   drawPixel
    #6
    sub  $s1, $a0, $a3  # xc - y
    add  $s2, $a1, $a2  # yc + x
    move $a0, $s1
    move $a1, $s2
    jal   drawPixel
    #7
    add  $s1, $a0, $a3  # xc + y
    sub  $s2, $a1, $a2  # yc - x
    move $a0, $s1
    move $a1, $s2
    jal   drawPixel
    #8
    sub  $s1, $a0, $a3  # xc - y
    sub  $s2, $a1, $a2  # yc - x
    move $a0, $s1
    move $a1, $s2
    jal   drawPixel
    
    lw   $ra, 0($sp)
    add  $sp, $sp, 4
    
    jr   $ra    
        
                
    
# $a0: passed as x
# $a1: passed as y
drawPixel:

    move $t3, 0x10000100 #t3 = first Pixel of the screen
    
    sll  $t0, $a1, 9    # y = y * 512
    addu $t0, $a0, $a1  # $t0 = x + y
    sll  $t0, $t0, 2    # $t0 = xy * 4
    addu $t0, $t3, $t0  # adds xy to first pixel ($t3)
    sw   $s0, 0($t0)    # Put RED ($s0) in $t0 memory spot
    
    jr   $ra

我也尝试将此作为概念证明,以查看我是否可以获得视觉效果,但我不完全理解定位或原因

.text
    li   $a2, 0x00FF0000     #loads the color red into the register $a2

    li   $s3, 50             #y1 = y position of the tail
    li   $s0, 50             #x2 = x position of the head

DrawPixel:

    li   $t3, 0x10000100     #t3 = first Pixel of the screen

    sll   $t0, $s3, 9        #y = y * 512
    addu  $t0, $t0, $s0      # (xy) t0 = x + y
    sll   $t0, $t0, 2        # (xy) t0 = xy * 4
    addu  $t0, $t3, $t0      # adds xy to the first pixel ( t3 )
    sw    $a2, ($t0)         # put the color red ($a2) in $t0

第一个添加到$sp的符号有误

您是否注意到在单步执行中,也许在从 circleBres 调用 drawCircle 之后,您在 s 寄存器中的局部变量被破坏了?

您要注意保留 $ra 寄存器供以后使用,但不要保留 s 寄存器。

s 寄存器并不神奇 — 如果您要使用它们,则必须保留它们的原始值。这里,drawCircle 重新利用了一些 s 寄存器,而它们同时被 circleBres 使用,所以这是一个冲突,最后修改 wins。调用约定说那些需要被保留,这通常是通过在序言中保存它们的值并在退出时恢复这些原始值来完成的。根据调用约定,drawCircle 应该做同样的事情,但是 main 不会将任何值放入 s 寄存器,所以这里无关紧要。


无论您是否意识到,您都面临着如何在多个函数之间共享有限数量的 CPU 寄存器的困境。有两种方法可以解决这个问题:

  1. 在不同的函数中使用完全不同的寄存器——在有限的情况下这可能是一种优化,但你可以想象,如果你有超过4-6个函数左右。

  2. 使用调用约定:大多数此类约定将寄存器分为两组:调用破坏和调用保留。前一组中的寄存器可以不受惩罚地使用,但需要注意的是,它们不会在具有与调用前相同值的函数调用中存活下来。可以使用后一组中的寄存器,但前提是在返回给调用者之前将它们恢复为原始值。这两个集合服务于两种常见的使用模式(temporaries/scratch,以及跨函数调用所需的变量)。

call clobbered set 对于需要在内部完成一些工作而不涉及函数调用的函数很有用。这些寄存器可以随意使用,就其性质而言,不需要 save/restore.

的开销

调用保留集对于需要围绕函数调用做一些工作的函数很有用——例如,如果您在寄存器中有一些您想要的变量,并且这些变量在函数调用之前建立(设置)并在函数调用之后使用.这些寄存器将在函数调用后继续存在——但前提是所有函数都遵守规则,即如果它们也想使用这些寄存器,则它们必须在返回给调用者之前恢复原始值。

我已经说明了这一点:调用约定说需要保留调用保留寄存器(这里是 s),这通常是通过在输入时保存它们的值来完成的序言并在退出时恢复这些原始值 结语,如果它们被函数使用。

所以,免费免费使用s寄存器,按照规则保存即可。这种保存与您已经处理 $ra 寄存器的方式非常相似,因此请对其进行扩展。 (您还可以找到示例程序,它们将进一步演示如何正确使用 s 寄存器。)

t 寄存器不一定像 a 寄存器那样在函数调用后仍然存在。

再说一遍:没有魔法——s 寄存器在函数调用中幸存下来的唯一原因是函数遵守使用规则。 ta 寄存器不一定在函数调用后仍然存在的原因也是协议(调用约定)。


考虑到上述情况,让我们看一下以下代码段:

#1
add  $s1, $a0, $a2  # xc + x
add  $s2, $a1, $a3  # yc + y
move $a0, $s1    <-------- what do you think happens to xc here?? (hint: $a0 holding xc is overwritten, not by drawPixel but by this very instruction
move $a1, $s2
jal   drawPixel    
#2
sub  $s1, $a0, $a2  # xc - x  <--- what do you think is in $a0 here, after you've already clobbered it above? (hint: nothing useful)

您需要考虑变量中保存的值以及这些变量在 assembly/machine 代码中的存储位置,而不仅仅是单个指令。没有魔法:如果你覆盖了一个包含重要值的寄存器,那么它就消失了。处理器将盲目地按照您说的去做;它不知道你的意图。

因为你需要 xcx 两者,在调用之后但它们在 a 寄存器中,你需要将它们移动到某个地方,以便在函数调用中继续存在 —可能是 s 寄存器,或内存。

没有意义

add  $s1, $a0, $a2  # xc + x
...
move $a0, $s1   <--- should target $a0 directly, above, instead of putting into $s1 then moving here to $a0
...
jal   drawPixel
...
sub  $s1, $a0, $a2 <--- overwriting $s1 proves that we didn't need xc+x to be preserved from above

您在这里使用 s 寄存器作为临时寄存器(这是不合适的)并且还期望 a 寄存器在第一次调用 drawPixel 后仍然存在(如您所见即使是传递一个参数的行为也会破坏 $a0).


哦,还有一件事:位图显示通常位于 0x10010000(不是 0x10000100)。