【问题标题】:how do i connect dots in midpoint algorithm in mips assembly我如何在mips程序集中的中点算法中连接点
【发布时间】:2016-08-02 07:06:26
【问题描述】:

所以我想画一个圆圈,但屏幕上只出现了 4 个点。如何生成更多点并将它们连接起来?我已经附上了一张图片,所以你可以看到它在 mars 中是如何显示的。

中点圆算法

.data
#midpoint circle algorithm variables

radius: .word 10
err: .word -10
#yvalue = radius
colour: .word 0x00FFFFFF

bmp: .space 0x80000
height: .word 64
width: .word 64
base: .word 0x10040000


.text

lw $a0, radius # x
li $a1, 0 # y

drawn:
bge $a0, $a1, loading

loading:

lw $t1, err
jal plot8points

add $t1, $t1, $a1 #err += y
addi $a1, $a1, 1 #y++
add $t1, $t1, $a1 #err + = y

bltz $a0, drawn


sub $t1, $t1, $a0 # err -= x
addi $a0, $a0, -1 # x--
sub $t1, $t1, $a0 # err-= x


plot8points:


lw $t3, radius # xcenter
li $t4, 0 # ycenter

move $t7, $a0 # x
move $t8, $a1 # y


jal plot4points 

blt $a0, $a1, end_loading

jal plot4points

jal plot4morepoints 

#jal exit


end_loading:

jr $ra


plot4points:


add $a0, $t7, $t3
add $a1, $t8, $t4
jal setpixel

sub $a0, $t3, $t7
add $a1, $t4, $t8
jal setpixel

add $a0, $t3, $t7
sub $a1, $t4, $t8
jal setpixel

sub $a0, $t3, $7
sub $a1, $t4, $t8
jal setpixel


plot4morepoints:

add $a0, $t3, $t8
add $a1, $t4, $t7
jal setpixel

sub $a0, $t3, $t8
add $a1, $t4, $t7
jal setpixel

add $a0, $t3, $t8
sub $a1, $t4, $t7
jal setpixel

sub $a0, $t3, $t8
sub $a1, $t4, $t7
jal setpixel


setpixel:
lw $t0, colour
lw $s4, width
lw $s2, base
mul $t6, $a1, $s4
add $t6, $t6, $a0
sll $t6, $t6, 2
add $t6, $t6, $s2
sw $t0, ($t6)
jr $ra



#exit:
li $v0, 10
syscall

【问题讨论】:

    标签: assembly mips geometry


    【解决方案1】:

    您的像素寻址似乎有误。

    width 是 [您的变量] 显示宽度,即 64。但是,在您的示例中,位图的宽度为 512,高度为 256 [这是mars 中的默认值]。

    因此,您要么需要更改 mars 中的显示几何图形,要么将 width 变量设置为匹配。身高也是一样。

    注意:mars保留你设置的值,所以如果你想使用非默认几何体,你必须设置它每次。所以,也许最简单的方法是使用mars 默认值。


    更新:

    我更改了值以匹配默认值,但仍然有错误。我在想也许我需要更改 setpixel 代码中的某些内容,并在某处添加一个计数器

    恐怕有很多错误。大多数情况下,您的函数没有在堆栈上保存/恢复$ra,并在最后执行jr $ra

    此外,[对我来说]您的八分圆反射代码似乎比它需要的复杂得多 [因此容易出错]。

    我创建了两个版本。第一个是您的原始代码,其中包含关于 [某些] 错误的注释。第二个是完整的返工。


    这是带注释的版本[请原谅无偿的风格清理]:

        .data
        # midpoint circle algorithm variables
    
    radius:     .word       10
    err:        .word       -10
    colour:     .word       0x00FFFFFF
        # yvalue = radius
    
    bmp:        .space      0x80000
    dpy_width:  .word       512
    dpy_height: .word       256
    dpy_base:   .word       0x10040000
    
        .text
    
        lw      $a0,radius              # x
        li      $a1,0                   # y
    
    # BUG: this bge has no meaning since, either way, it goes to "loading"
    # probably should be "end_loading"
    drawn:
        bge     $a0,$a1,loading
    
    # BUG: this falls through into the plot8points function
    loading:
        lw      $t1,err
        jal     plot8points
    
        add     $t1,$t1,$a1             # err += y
        addi    $a1,$a1,1               # y++
        add     $t1,$t1,$a1             # err + = y
    
        bltz    $a0,drawn
    
        sub     $t1,$t1,$a0             # err -= x
        addi    $a0,$a0,-1              # x--
        sub     $t1,$t1,$a0             # err-= x
    
    # BUG: this is a function but has no return and does _not_ save $ra
    plot8points:
        lw      $t3,radius              # xcenter
        li      $t4,0                   # ycenter
    
        move    $t7,$a0                 # x
        move    $t8,$a1                 # y
    
        jal     plot4points
    # BUG: we're in a function but this jumps to a label outside the function
        blt     $a0,$a1,end_loading
    
        jal     plot4points
        jal     plot4morepoints
    
        # jal exit
    
    end_loading:
        jr      $ra
    
    # BUG: this is a function but has no return and does _not_ save $ra
    plot4points:
        add     $a0,$t7,$t3
        add     $a1,$t8,$t4
        jal     setpixel
    
        sub     $a0,$t3,$t7
        add     $a1,$t4,$t8
        jal     setpixel
    
        add     $a0,$t3,$t7
        sub     $a1,$t4,$t8
        jal     setpixel
    
        sub     $a0,$t3,$7
        sub     $a1,$t4,$t8
        jal     setpixel
    
    # BUG: this is a function but has no return and does _not_ save $ra
    plot4morepoints:
        add     $a0,$t3,$t8
        add     $a1,$t4,$t7
        jal     setpixel
    
        sub     $a0,$t3,$t8
        add     $a1,$t4,$t7
        jal     setpixel
    
        add     $a0,$t3,$t8
        sub     $a1,$t4,$t7
        jal     setpixel
    
        sub     $a0,$t3,$t8
        sub     $a1,$t4,$t7
        jal     setpixel
    
    # setpixel -- draw pixel on display
    #
    # arguments:
    #   a0 -- X coord
    #   a1 -- Y coord
    setpixel:
        lw      $t0,colour              # color
        lw      $s4,dpy_width           # display width
        lw      $s2,dpy_base            # display base address
    
        mul     $t6,$a1,$s4             # get y * width
        add     $t6,$t6,$a0             # get (y * width) + x
        sll     $t6,$t6,2               # convert to offset
        add     $t6,$t6,$s2             # add in base address
    
        sw      $t0,($t6)               # store pixel
        jr      $ra
    
        # exit:
        li      $v0,10
        syscall
    

    这是经过清理、重构的工作版本。

    当我进行返工时,我尝试使用 wikipedia 页面中的算法用于圆形算法,但要么他们的版本坏了,要么 坏了它。它不会产生圆形,而是菱形/六边形图案。所以,我把它作为一个选项留了下来。

    所以,我添加了约翰肯尼迪的 [圣莫尼卡学院] 版本 [来自俄勒冈州立大学网站]。它有效。

    我还添加了一些选项来自动调整显示大小并自动计算质心。检查显示值,因为它假定为 512x256 和“静态”显示​​基地址。

    我还添加了一些选项来允许绘制同心圆,仅供娱乐。

    # breshenham circle algorithm
    
        .data
    radius:     .word       10
    center_x:   .word       0
    center_y:   .word       0
    dpy_color:  .word       0x00FFFFFF
        # midpoint circle algorithm variables
    
    bmp:        .space      0x80000
    dpy_width:  .word       512
    dpy_height: .word       256
    dpy_base:   .word       0x10010000
        .eqv    dpy_margin      8
    
    ask_diamond:    .word   0
    ask_radmin: .word       0
    ask_radinc: .word       16
    
    msg_nl:     .asciiz     "\n"
    msg_comma:  .asciiz     ","
    
        .text
    
        .globl  main
    
    main:
        .eqv    dflg            $fp
        li      dflg,0                  # clear debug flag
    
        # prompt user for ask_diamond value
        la      $a0,_S_000              # prompt user
        li      $v0,4                   # print string
        syscall
        li      $v0,5
        syscall
        sw      $v0,ask_diamond
    
        # prompt user for ask_radmin value
        la      $a0,_S_001              # prompt user
        li      $v0,4                   # print string
        syscall
        li      $v0,5
        syscall
        sw      $v0,ask_radmin
    
        lw      $t0,ask_radmin
        beqz    $t0,main_skipinc
    
        # prompt user for ask_radinc value
        la      $a0,_S_002              # prompt user
        li      $v0,4                   # print string
        syscall
        li      $v0,5
        syscall
        sw      $v0,ask_radinc
    
    main_skipinc:
        lw      $t0,ask_radmin
    
        # compute circle center from display geometry
        lw      $s6,dpy_width
        srl     $s6,$s6,1
        sw      $s6,center_x
    
        lw      $s5,dpy_height
        srl     $s5,$s5,1
        sw      $s5,center_y
    
        # set radius to min((width / 2) - 16,(height / 2) - 16)
        move    $s0,$s6
        blt     $s6,$s5,main_gotradius
        move    $s0,$s5
    
    main_gotradius:
        subi    $s0,$s0,dpy_margin      # give us some margin
        sw      $s0,radius
    
    main_loop:
        # output circle
        jal     kdraw
        jal     radbump
    
        # output diamond/hexagon
        lw      $t0,ask_diamond         # is it enabled?
        beqz    $t0,main_next           # if no, skip
        jal     wdraw
        jal     radbump
    
    main_next:
        bnez    $v0,main_loop           # done with concentric circles? if no, loop
    
    main_done:
        li      $v0,10
        syscall
    
    # wdraw -- draw circle (wikipedia)
    #
    # NOTES:
    #   (1) this is wikipedia's algorithm for a circle, but it is more like a
    #       diamond or polygon
    #   (2) https://en.wikipedia.org/wiki/Midpoint_circle_algorithm
    #   (2) either it's "broken" or _I_ broke it
    #
    # registers:
    #   s0 -- x
    #   s1 -- y
    #   s2 -- decision/error term (err)
    #
    # * void
    # * DrawCircle(int x0,int y0,int radius)
    # * {
    # *     int x = radius;
    # *     int y = 0;
    # *
    # *     // Decision criterion divided by 2 evaluated at x=r, y=0
    # *     int decisionOver2 = 1 - x;
    # *
    # *     while (y <= x) {
    # *         DrawPixel(x + x0,y + y0);       // Octant 1
    # *         DrawPixel(y + x0,x + y0);       // Octant 2
    # *         DrawPixel(-x + x0,y + y0);      // Octant 4
    # *         DrawPixel(-y + x0,x + y0);      // Octant 3
    # *         DrawPixel(-x + x0,-y + y0);     // Octant 5
    # *         DrawPixel(-y + x0,-x + y0);     // Octant 6
    # *         DrawPixel(x + x0,-y + y0);      // Octant 7
    # *         DrawPixel(y + x0,-x + y0);      // Octant 8
    # *
    # *         y++;
    # *
    # *         // Change in decision criterion for y -> y+1
    # *         if (decisionOver2 <= 0) {
    # *             decisionOver2 += 2 * y + 1;
    # *         }
    # *
    # *         // Change for y -> y+1, x -> x-1
    # *         else {
    # *             x--;
    # *             decisionOver2 += 2 * (y - x) + 1;
    # *         }
    # *     }
    # * }
    wdraw:
        subi    $sp,$sp,4
        sw      $ra,0($sp)
    
        lw      $s0,radius              # x = radius
        li      $s1,0                   # y = 0
    
        # get initial decision (err = 1 - x)
        li      $s2,1                   # err = 1
        sub     $s2,$s2,$s0             # err = 1 - x
    
    wdraw_loop:
        bgt     $s1,$s0,wdraw_done      # y <= x? if no, fly (we're done)
    
        # draw pixels in all 8 octants
        jal     draw8
    
        addi    $s1,$s1,1               # y += 1
    
        bgtz    $s2,wdraw_case2         # err <= 0? if no, fly
    
    # change in decision criterion for y -> y+1
    #   err += (2 * y) + 1
    wdraw_case1:
        sll     $t0,$s2,1               # get 2 * y
        addu    $s2,$s2,$t0             # err += 2 * y (NOTE: this can overflow)
        add     $s2,$s2,1               # err += 1
        j       wdraw_loop
    
    # change for y -> y+1, x -> x-1
    #   x -= 1
    #   err += (2 * (y - x)) + 1
    wdraw_case2:
        subi    $s0,$s0,1               # x -= 1
        sub     $t0,$s1,$s0             # get y - x
        sll     $t0,$t0,1               # get 2 * (y - x)
        addi    $t0,$t0,1               # get 2 * (y - x) + 1
        add     $s2,$s2,$t0             # add it to err
        j       wdraw_loop
    
    wdraw_done:
        lw      $ra,0($sp)
        addi    $sp,$sp,4
        jr      $ra
    
    # kdraw -- draw circle (john kennedy)
    #
    # NOTES:
    # (1) this is John Kennedy's algorithm from:
    #     http://web.engr.oregonstate.edu/~sllu/bcircle.pdf
    #
    # registers:
    #   s0 -- x
    #   s1 -- y
    #   s2 -- raderr
    #   s3 -- xchg
    #   s4 -- ychg
    #
    # * void
    # * PlotCircle(int CX, int CY, int r)
    # * {
    # *     int x;
    # *     int y;
    # *     int xchg;
    # *     int ychg;
    # *     int raderr;
    # *
    # *     x = r;
    # *     y = 0;
    # *
    # *     xchg = 1 - (2 * r);
    # *     ychg = 1;
    # *
    # *     raderr = 0;
    # *
    # *     while (x >= y) {
    # *         draw8(x,y);
    # *         y += 1;
    # *
    # *         raderr += ychg;
    # *         ychg += 2;
    # *
    # *         if (((2 * raderr) + xchg) > 0) {
    # *             x -= 1;
    # *             raderr += xchg;
    # *             xchg += 2;
    # *         }
    # *     }
    # * }
    kdraw:
        subi    $sp,$sp,4
        sw      $ra,0($sp)
    
        lw      $s0,radius              # x = radius
        li      $s1,0                   # y = 0
    
        # initialize: xchg = 1 - (2 * r)
        li      $s3,1                   # xchg = 1
        sll     $t0,$s0,1               # get 2 * r
        sub     $s3,$s3,$t0             # xchg -= (2 * r)
    
        li      $s4,1                   # ychg = 1
        li      $s2,0                   # raderr = 0
    
    kdraw_loop:
        blt     $s0,$s1,kdraw_done      # x >= y? if no, fly (we're done)
    
        # draw pixels in all 8 octants
        jal     draw8
    
        addi    $s1,$s1,1               # y += 1
        add     $s2,$s2,$s4             # raderr += ychg
        addi    $s4,$s4,2               # ychg += 2
    
        sll     $t0,$s2,1               # get 2 * raderr
        add     $t0,$t0,$s3             # get (2 * raderr) + xchg
        blez    $s2,kdraw_loop          # >0? if no, loop
    
        subi    $s0,$s0,1               # x -= 1
        add     $s2,$s2,$s3             # raderr += xchg
        addi    $s3,$s3,2               # xchg += 2
        j       kdraw_loop
    
    kdraw_done:
        lw      $ra,0($sp)
        addi    $sp,$sp,4
        jr      $ra
    
    # draw8 -- draw single point in all 8 octants
    #
    # arguments:
    #   s0 -- X coord
    #   s1 -- Y coord
    #
    # registers:
    #   t8 -- center_x
    #   t9 -- center_y
    draw8:
        subi    $sp,$sp,4
        sw      $ra,0($sp)
    
        #+drawctr $t8,$t9
        lw      $t8,center_x            #+
        lw      $t9,center_y            #+
        #+
    
        # draw [+x,+y]
        add     $a0,$t8,$s0
        add     $a1,$t9,$s1
        jal     setpixel
    
        # draw [+y,+x]
        add     $a0,$t8,$s1
        add     $a1,$t9,$s0
        jal     setpixel
    
        # draw [-x,+y]
        sub     $a0,$t8,$s0
        add     $a1,$t9,$s1
        jal     setpixel
    
        # draw [-y,+x]
        add     $a0,$t8,$s1
        sub     $a1,$t9,$s0
        jal     setpixel
    
        # draw [-x,-y]
        sub     $a0,$t8,$s0
        sub     $a1,$t9,$s1
        jal     setpixel
    
        # draw [-y,-x]
        sub     $a0,$t8,$s1
        sub     $a1,$t9,$s0
        jal     setpixel
    
        # draw [+x,-y]
        add     $a0,$t8,$s0
        sub     $a1,$t9,$s1
        jal     setpixel
    
        # draw [+y,-x]
        sub     $a0,$t8,$s1
        add     $a1,$t9,$s0
        jal     setpixel
    
        lw      $ra,0($sp)
        addi    $sp,$sp,4
        jr      $ra
    
    # setpixel -- draw pixel on display
    #
    # arguments:
    #   a0 -- X coord
    #   a1 -- Y coord
    #
    # clobbers:
    #   v0 -- bitmap offset/index
    #   v1 -- bitmap address
    # trace:
    #   v0,a0
    setpixel:
        bnez    dflg,setpixel_show      # debug output? if yes, fly
    
    setpixel_go:
        lw      $v0,dpy_width           # off = display width
    
        mul     $v0,$a1,$v0             # off = y * width
        add     $v0,$v0,$a0             # off += x
        sll     $v0,$v0,2               # convert to offset
    
        lw      $v1,dpy_base            # ptr = display base address
        add     $v1,$v1,$v0             # ptr += off
    
        lw      $v0,dpy_color           # color
        sw      $v0,($v1)               # store pixel
        jr      $ra
    
    setpixel_show:
        move    $a2,$a0
        move    $a3,$a1
    
        # print x
        li      $v0,1
        move    $a0,$a2
        syscall
    
        # print comma
        li      $v0,4
        la      $a0,msg_comma
        syscall
    
        # print y
        li      $v0,1
        move    $a0,$a3
        syscall
    
        # print newline
        li      $v0,4
        la      $a0,msg_nl
        syscall
    
        move    $a0,$a2
        move    $a1,$a3
        j       setpixel_go
    
    # radbump -- bump down radius
    #
    # RETURNS:
    #   v0 -- 1=more to do, 0=done
    #
    # registers:
    #   t0 -- radius value
    radbump:
        lw      $t0,radius
        lw      $t1,ask_radinc
        sub     $t0,$t0,$t1
    
        lw      $v0,ask_radmin          # do multiple rings?
        beqz    $v0,radbump_store       # if no, fly
    
        slt     $v0,$v0,$t0             # radius < ask_radmin?
    
    radbump_store:
        beqz    $t0,radbump_safe
        sw      $t0,radius
    
    radbump_safe:
        jr      $ra
    
        #+dfnc
        #+
    
        .data
    _S_000:     .asciiz     "output diamond pattern? "
    _S_001:     .asciiz     "minimum radius (0=single) > "
    _S_002:     .asciiz     "radius decrement > "
    _S_003:     .asciiz     "dpy_width"
    _S_004:     .asciiz     "dpy_height"
    _S_005:     .asciiz     "radius"
    

    我最近为 struct/linked list 做了一个 MIPS 答案。我还添加了很多关于如何写好 MIPS 代码的建议。它可能对您理解我在这里所做的有所帮助。见:MIPS linked list

    【讨论】:

    • 我更改了值以匹配默认值,但仍然有错误。我在想也许我需要更改 setpixel 代码中的某些内容并在某处添加一个计数器
    • 哇!非常感谢。我真的需要帮助,这太棒了:)我很感谢你这样做,对我来说意义重大:)
    • 不客气。自从我看到你的一个更新的问题后,我开始认为你错过了我的更新版本。另外,请查看上面的“MIPS 链表”链接。此外,在我的代码的基本版本正常工作后,我决定找点乐子并添加颜色。彩色版本是一个新的答案。另外,请务必注意$ra 在函数开始/结束时如何从堆栈中保存/恢复。这对于fncA-&gt;fncB-&gt;fncC 正常工作至关重要
    【解决方案2】:

    注意:此答案是我之前的答案的延续,由于篇幅原因,该答案不适合第一个答案。

    经过实验,唯一可行的显示映射是具有如下所示几何形状的“堆”映射。这是火星的限制。

    这是一个更新/改进的颜色版本:

    # mipscirc/fix2.asm -- breshenham circle algorithm
    
    # this _must_ be first
        .data
        .eqv    dpy_max         4194304 # maximum display area
    dpy_width:  .word       512
    dpy_height: .word       256
    dpy_base:   .word       0x10040000      # heap
    dpy_now:    .word       0               # current base [for debug]
    dpy_blit:   .word       0               # 1=do offscreen blit (currently broken)
        .eqv    dpy_stride      9       # left shift
        .eqv    dpy_size        524288  # display size (bytes)
    
        .eqv    dpy_margin      8       # radius margin
    
        .data
    
    sdata:
    radius:     .word       10
    center_x:   .word       0
    center_y:   .word       0
        # midpoint circle algorithm variables
    
    color_octant:   .space  32
    
    dpy_radius: .word       10
    dpy_color:  .word       0x00FFFFFF
    
    ask_diamond:    .word   0               # 1=do diamond pattern
    ask_radmin: .word       0               # minimum radius (0=single circle)
    ask_radinc: .word       16              # radius decrement amount
    ask_colorinc:   .word   0               # color increment (0=single color)
    
    bitmap:     .space      dpy_size
    
        .text
    
        .globl  main
    
    main:
        # this _must_ be first
        li      $a0,dpy_size            # maximum size
        li      $v0,9                   # sbrk
        syscall
        lw      $v1,dpy_base            # get what we expect
        beq     $v0,$v1,dpyinit_done
        la      $a0,_S_000
        li      $v0,4                   # puts
        syscall
    
    dpyinit_done:
    
        .eqv    mrzhow          $fp
        li      $v1,0                   # clear mask
    
        .eqv    MRZDBGPRT       0x00000001  # output numbers
        .eqv    _MRZDBGPRT      0       # output numbers
    
        .eqv    MRZDPYSHOW      0x00000002  # show display coordinates
        .eqv    _MRZDPYSHOW     1       # show display coordinates
    
        .eqv    MRZDPYCHK       0x00000004  # check display area bounds
        .eqv    _MRZDPYCHK      2       # check display area bounds
    
        move    mrzhow,$v1              # set final register value
    
        # prompt user for ask_diamond value
        la      $a0,_S_001              # prompt user
        li      $a1,0                   # set default
        jal     qask
        sw      $v0,ask_diamond         # place to store
    
        # prompt user for ask_radmin value
        la      $a0,_S_002              # prompt user
        li      $a1,4                   # set default
        jal     qask
        sw      $v0,ask_radmin          # place to store
    
        lw      $t0,ask_radmin
        beqz    $t0,main_skipinc
    
        # prompt user for ask_radinc value
        la      $a0,_S_003              # prompt user
        li      $a1,6                   # set default
        jal     qask
        sw      $v0,ask_radinc          # place to store
    
    main_skipinc:
    
        # prompt user for ask_colorinc value
        la      $a0,_S_004              # prompt user
        li      $a1,-2                  # set default
        jal     qask
        sw      $v0,ask_colorinc        # place to store
    
        lw      $t0,ask_radmin
    
        # compute circle center from display geometry
        lw      $s6,dpy_width
        srl     $s6,$s6,1
        sw      $s6,center_x
    
        lw      $s5,dpy_height
        srl     $s5,$s5,1
        sw      $s5,center_y
    
        # set radius to min((width / 2) - 16,(height / 2) - 16)
        move    $s0,$s6
        blt     $s6,$s5,main_gotradius
        move    $s0,$s5
    
    main_gotradius:
        subi    $s0,$s0,dpy_margin      # give us some margin
        sw      $s0,dpy_radius
    
    main_loop:
        jal     colorgo
    
        jal     colorinc
        bnez    $v0,main_loop
    
    main_done:
        li      $v0,10
        syscall
    
    # colorgo -- draw all items with single color
    colorgo:
        subi    $sp,$sp,4
        sw      $ra,0($sp)
    
        jal     dpybase
    
    # reset the radius
    colorgo_noblit:
        lw      $t0,dpy_radius
        sw      $t0,radius
    
    colorgo_loop:
        # output circle
        jal     kdraw
        jal     radbump
    
        # output diamond/hexagon
        lw      $t0,ask_diamond         # is it enabled?
        beqz    $t0,colorgo_next        # if no, skip
        jal     wdraw
        jal     radbump
    
    colorgo_next:
        bnez    $v0,colorgo_loop        # done with concentric circles? if no, loop
    
        jal     dpyblit                 # blit to screen (if mode applicable)
    
    colorgo_done:
        lw      $ra,0($sp)
        addi    $sp,$sp,4
        jr      $ra
    
    # colorinc -- increment to next color
    #
    # RETURNS:
    #   v0 -- 1=more to do, 0=done
    #
    # registers:
    #   t0 -- color value
    colorinc:
        subi    $sp,$sp,4
        sw      $ra,0($sp)
    
        lw      $v0,ask_colorinc        # get option that controls increment
        beqz    $v0,colorinc_done       # do increment? if no, fly
    
        bltz    $v0,colorinc_rand       # random increment? if yes, fly
    
        lw      $t0,dpy_color           # get current color
        addi    $t0,$t0,1               # increment it
        andi    $t0,$t0,0x00FFFFFF      # keep it clean
        sw      $t0,dpy_color           # save it back
    
        li      $v0,1
        j       colorinc_done
    
    colorinc_rand:
        jal     colorany                # get random colors
        lw      $t0,color_octant        # the first one
        sw      $t0,dpy_color           # save to the single color
    
        # without a delay, the colors blast by too fast to be enjoyed
        ###li       $t0,1000000
        li      $t0,500000
    
    colorinc_loop:
        subi    $t0,$t0,1
        bgtz    $t0,colorinc_loop
    
        li      $v0,1
    
    colorinc_done:
        lw      $ra,0($sp)
        addi    $sp,$sp,4
        jr      $ra
    
    # colorany -- get random colors
    colorany:
        lw      $t0,ask_colorinc        # get option
        li      $t1,-3                  # get value for the "spin" option
        bne     $t0,$t1,colorany_noslide    # slide mode? if no, fly
    
        li      $t0,7
        la      $t1,color_octant
        subi    $t1,$t1,4
    
    # slide all colors to make room for single new one
    colorany_slide:
        addi    $t1,$t1,4               # advance
        lw      $a0,4($t1)              # get ptr[1]
        sw      $a0,0($t1)              # set ptr[0]
        subi    $t0,$t0,1               # more to do?
        bnez    $t0,colorany_slide      # if yes, loop
    
        # set new random first element
        li      $v0,41                  # randint
        syscall
        andi    $a0,$a0,0x00FFFFFF      # clean the value
        sw      $a0,4($t1)
        j       colorany_done
    
    colorany_noslide:
        li      $t0,8
        la      $t1,color_octant
    
    colorany_loop:
        li      $v0,41                  # randint
        syscall
        andi    $a0,$a0,0x00FFFFFF      # clean the value
    
        sw      $a0,0($t1)              # store it
        subi    $t0,$t0,1               # decrement remaining count
        addi    $t1,$t1,4               # advance pointer
        bnez    $t0,colorany_loop       # done? if no, loop
    
    colorany_done:
        jr      $ra
    
    # radbump -- bump down radius
    #
    # RETURNS:
    #   v0 -- 1=more to do, 0=done
    #
    # registers:
    #   t0 -- radius value
    radbump:
        lw      $t0,radius
        lw      $t1,ask_radinc
        sub     $t0,$t0,$t1
    
        lw      $v0,ask_radmin          # do multiple rings?
        beqz    $v0,radbump_store       # if no, fly
    
        slt     $v0,$v0,$t0             # radius < ask_radmin?
    
    radbump_store:
        beqz    $t0,radbump_safe
        sw      $t0,radius
    
    radbump_safe:
        jr      $ra
    
    # wdraw -- draw circle (wikipedia)
    #
    # NOTES:
    #   (1) this is wikipedia's algorithm for a circle, but it is more like a
    #       diamond or polygon
    #   (2) https://en.wikipedia.org/wiki/Midpoint_circle_algorithm
    #   (2) either it's "broken" or _I_ broke it
    #
    # registers:
    #   s0 -- x
    #   s1 -- y
    #   s2 -- decision/error term (err)
    #
    # * void
    # * DrawCircle(int x0,int y0,int radius)
    # * {
    # *     int x = radius;
    # *     int y = 0;
    # *
    # *     // Decision criterion divided by 2 evaluated at x=r, y=0
    # *     int decisionOver2 = 1 - x;
    # *
    # *     while (y <= x) {
    # *         DrawPixel(x + x0,y + y0);       // Octant 1
    # *         DrawPixel(y + x0,x + y0);       // Octant 2
    # *         DrawPixel(-x + x0,y + y0);      // Octant 4
    # *         DrawPixel(-y + x0,x + y0);      // Octant 3
    # *         DrawPixel(-x + x0,-y + y0);     // Octant 5
    # *         DrawPixel(-y + x0,-x + y0);     // Octant 6
    # *         DrawPixel(x + x0,-y + y0);      // Octant 7
    # *         DrawPixel(y + x0,-x + y0);      // Octant 8
    # *
    # *         y++;
    # *
    # *         // Change in decision criterion for y -> y+1
    # *         if (decisionOver2 <= 0) {
    # *             decisionOver2 += 2 * y + 1;
    # *         }
    # *
    # *         // Change for y -> y+1, x -> x-1
    # *         else {
    # *             x--;
    # *             decisionOver2 += 2 * (y - x) + 1;
    # *         }
    # *     }
    # * }
    wdraw:
        subi    $sp,$sp,4
        sw      $ra,0($sp)
    
        lw      $s0,radius              # x = radius
        li      $s1,0                   # y = 0
    
        # get initial decision (err = 1 - x)
        li      $s2,1                   # err = 1
        sub     $s2,$s2,$s0             # err = 1 - x
    
    wdraw_loop:
        bgt     $s1,$s0,wdraw_done      # y <= x? if no, fly (we're done)
    
        # draw pixels in all 8 octants
        jal     draw8
    
        addi    $s1,$s1,1               # y += 1
    
        bgtz    $s2,wdraw_case2         # err <= 0? if no, fly
    
    # change in decision criterion for y -> y+1
    #   err += (2 * y) + 1
    wdraw_case1:
        sll     $t0,$s2,1               # get 2 * y
        addu    $s2,$s2,$t0             # err += 2 * y (NOTE: this can overflow)
        add     $s2,$s2,1               # err += 1
        j       wdraw_loop
    
    # change for y -> y+1, x -> x-1
    #   x -= 1
    #   err += (2 * (y - x)) + 1
    wdraw_case2:
        subi    $s0,$s0,1               # x -= 1
        sub     $t0,$s1,$s0             # get y - x
        sll     $t0,$t0,1               # get 2 * (y - x)
        addi    $t0,$t0,1               # get 2 * (y - x) + 1
        add     $s2,$s2,$t0             # add it to err
        j       wdraw_loop
    
    wdraw_done:
        lw      $ra,0($sp)
        addi    $sp,$sp,4
        jr      $ra
    
    # kdraw -- draw circle (john kennedy)
    #
    # NOTES:
    # (1) this is John Kennedy's algorithm from:
    #     http://web.engr.oregonstate.edu/~sllu/bcircle.pdf
    #
    # registers:
    #   s0 -- x
    #   s1 -- y
    #   s2 -- raderr
    #   s3 -- xchg
    #   s4 -- ychg
    #
    # * void
    # * PlotCircle(int CX, int CY, int r)
    # * {
    # *     int x;
    # *     int y;
    # *     int xchg;
    # *     int ychg;
    # *     int raderr;
    # *
    # *     x = r;
    # *     y = 0;
    # *
    # *     xchg = 1 - (2 * r);
    # *     ychg = 1;
    # *
    # *     raderr = 0;
    # *
    # *     while (x >= y) {
    # *         draw8(x,y);
    # *         y += 1;
    # *
    # *         raderr += ychg;
    # *         ychg += 2;
    # *
    # *         if (((2 * raderr) + xchg) > 0) {
    # *             x -= 1;
    # *             raderr += xchg;
    # *             xchg += 2;
    # *         }
    # *     }
    # * }
    kdraw:
        subi    $sp,$sp,4
        sw      $ra,0($sp)
    
        lw      $s0,radius              # x = radius
        li      $s1,0                   # y = 0
    
        # initialize: xchg = 1 - (2 * r)
        li      $s3,1                   # xchg = 1
        sll     $t0,$s0,1               # get 2 * r
        sub     $s3,$s3,$t0             # xchg -= (2 * r)
    
        li      $s4,1                   # ychg = 1
        li      $s2,0                   # raderr = 0
    
    kdraw_loop:
        blt     $s0,$s1,kdraw_done      # x >= y? if no, fly (we're done)
    
        # draw pixels in all 8 octants
        jal     draw8
    
        addi    $s1,$s1,1               # y += 1
        add     $s2,$s2,$s4             # raderr += ychg
        addi    $s4,$s4,2               # ychg += 2
    
        sll     $t0,$s2,1               # get 2 * raderr
        add     $t0,$t0,$s3             # get (2 * raderr) + xchg
        blez    $s2,kdraw_loop          # >0? if no, loop
    
        subi    $s0,$s0,1               # x -= 1
        add     $s2,$s2,$s3             # raderr += xchg
        addi    $s3,$s3,2               # xchg += 2
        j       kdraw_loop
    
    kdraw_done:
        lw      $ra,0($sp)
        addi    $sp,$sp,4
        jr      $ra
    
    # draw8 -- draw single point in all 8 octants
    #
    # arguments:
    #   s0 -- X coord
    #   s1 -- Y coord
    #
    # registers:
    #   t8 -- center_x
    #   t9 -- center_y
    draw8:
        subi    $sp,$sp,4
        sw      $ra,0($sp)
    
        lw      $t8,center_x
        lw      $t9,center_y
        lw      $a2,dpy_color
    
        lw      $t0,ask_colorinc
        li      $t1,-2
        ble     $t0,$t1,draw8_octant
    
        # draw [+x,+y]
        add     $a0,$t8,$s0
        add     $a1,$t9,$s1
        jal     dpypixel
    
        # draw [+y,+x]
        add     $a0,$t8,$s1
        add     $a1,$t9,$s0
        jal     dpypixel
    
        # draw [-y,+x]
        add     $a0,$t8,$s1
        sub     $a1,$t9,$s0
        jal     dpypixel
    
        # draw [-x,+y]
        sub     $a0,$t8,$s0
        add     $a1,$t9,$s1
        jal     dpypixel
    
        # draw [-x,-y]
        sub     $a0,$t8,$s0
        sub     $a1,$t9,$s1
        jal     dpypixel
    
        # draw [-y,-x]
        sub     $a0,$t8,$s1
        sub     $a1,$t9,$s0
        jal     dpypixel
    
        # draw [+x,-y]
        add     $a0,$t8,$s0
        sub     $a1,$t9,$s1
        jal     dpypixel
    
        # draw [+y,-x]
        sub     $a0,$t8,$s1
        add     $a1,$t9,$s0
        jal     dpypixel
        j       draw8_done
    
    draw8_octant:
        la      $t7,color_octant
    
        # draw [+x,+y]
        add     $a0,$t8,$s0
        add     $a1,$t9,$s1
        lw      $a2,0($t7)
        addi    $t7,$t7,4
        jal     dpypixel
    
        # draw [+y,+x]
        add     $a0,$t8,$s1
        add     $a1,$t9,$s0
        lw      $a2,0($t7)
        addi    $t7,$t7,4
        jal     dpypixel
    
        # draw [-y,+x]
        add     $a0,$t8,$s1
        sub     $a1,$t9,$s0
        lw      $a2,0($t7)
        addi    $t7,$t7,4
        jal     dpypixel
    
        # draw [-x,+y]
        sub     $a0,$t8,$s0
        add     $a1,$t9,$s1
        lw      $a2,0($t7)
        addi    $t7,$t7,4
        jal     dpypixel
    
        # draw [-x,-y]
        sub     $a0,$t8,$s0
        sub     $a1,$t9,$s1
        lw      $a2,0($t7)
        addi    $t7,$t7,4
        jal     dpypixel
    
        # draw [-y,-x]
        sub     $a0,$t8,$s1
        sub     $a1,$t9,$s0
        lw      $a2,0($t7)
        addi    $t7,$t7,4
        jal     dpypixel
    
        # draw [+x,-y]
        add     $a0,$t8,$s0
        sub     $a1,$t9,$s1
        lw      $a2,0($t7)
        addi    $t7,$t7,4
        jal     dpypixel
    
        # draw [+y,-x]
        sub     $a0,$t8,$s1
        add     $a1,$t9,$s0
        lw      $a2,0($t7)
        addi    $t7,$t7,4
        jal     dpypixel
    
    draw8_done:
        lw      $ra,0($sp)
        addi    $sp,$sp,4
        jr      $ra
        # marzmca/marzdpy.inc -- mars display functions
    
    # dpypixel -- draw pixel on display
    #
    # arguments:
    #   a0 -- X coord
    #   a1 -- Y coord
    #   a2 -- color
    #   a3 -- display base address
    #
    # clobbers:
    #   v1 -- bitmap offset/index
    # trace:
    #   v0,a0
    dpypixel:
    
    dpypixel_go:
        lw      $v1,dpy_width           # off = display width
        mul     $v1,$a1,$v1             # off = y * width
    
        add     $v1,$v1,$a0             # off += x
        sll     $v1,$v1,2               # convert to offset
    
        add     $v1,$a3,$v1             # ptr = base + off
    
        sw      $a2,($v1)               # store pixel
        jr      $ra
    
    # dpybase -- get display base address
    #
    # RETURNS:
    #   a3 -- display base address
    dpybase:
        lw      $a3,dpy_base            # direct draw to display
    
        lw      $t0,dpy_blit
        beqz    $t0,dpybase_done
    
        la      $a3,bitmap              # draw to bitmap
    
    dpybase_done:
        sw      $a3,dpy_now             # remember it [for debug]
        jr      $ra
    
    # dpyblit -- blit bitmap to display
    dpyblit:
        lw      $a0,dpy_blit            # blit mode?
        beqz    $a0,dpyblit_done        # if no, fly
    
        li      $t0,2                   # zap the background first?
        blt     $a0,$t2,dpyblit_init    # if no, fly
    
        # zero out the display
        lw      $a0,dpy_base            # get the base address
        addi    $a1,$a0,dpy_size        # get the end address
    
    dpyblit_zap:
        sw      $zero,0($a0)            # set black
        addi    $a0,$a0,4               # advance current pointer
        blt     $a0,$a1,dpyblit_zap     # more to do? if yes, loop
    
    # setup for blit
    dpyblit_init:
        lw      $a0,dpy_base            # get the base address
        addi    $a1,$a0,dpy_size        # get the end address
        la      $a2,bitmap              # get offscreen address
    
    dpyblit_loop:
        lw      $t0,0($a2)              # fetch from offscreen image
        addi    $a2,$a2,4               # advance offscreen pointer
        sw      $t0,0($a0)              # store to live area
        addi    $a0,$a0,4               # advance current pointer
        blt     $a0,$a1,dpyblit_loop    # more to do? if yes, loop
    
    dpyblit_done:
        jr      $ra
        # marzmca/marzqask.inc -- extra prompting functions
    
        .eqv    qask_siz        100
    
    # qask -- prompt user for number (possibly hex)
    #
    # RETURNS:
    #   v0 -- value
    #
    # arguments:
    #   a0 -- prompt string
    #   a1 -- default value
    #
    # registers:
    #   a2 -- save for a0
    #   a3 -- save for a1
    #   t0 -- current buffer char
    #   t1 -- offset into qask_hex
    #   t2 -- current hex string char
    #   t3 -- current hex string pointer
    #   t6 -- 1=negative
    #   t7 -- number base
    qask:
        move    $a2,$a0                 # remember for reprompt
        move    $a3,$a1                 # remember for reprompt
    
    qask_retry:
        # output the prompt
        move    $a0,$a2
        li      $v0,4
        syscall
    
        la      $a0,qask_dft1
        li      $v0,4
        syscall
    
        # output the default value
        move    $a0,$a3
        li      $v0,1
        syscall
    
        la      $a0,qask_dft2
        li      $v0,4
        syscall
    
        # read in string
        li      $v0,8
        la      $a0,qask_buf
        la      $a1,qask_siz
        syscall
    
        lb      $t0,0($a0)              # get first buffer char
        li      $t1,0x0A                # get newline
        beq     $t0,$t1,qask_dft        # empty line? if yes, use default
    
        li      $v0,0                   # zap accumulator
    
        # decide if we have a negative number
        li      $t6,0
        lb      $t0,0($a0)              # get first buffer char
        li      $t1,'-'
        bne     $t0,$t1,qask_tryhex
        li      $t6,1                   # set negative number
        addi    $a0,$a0,1               # skip over '-'
    
    # decide if want hex
    qask_tryhex:
        li      $t7,10                  # assume base 10
        li      $t1,'x'
        bne     $t0,$t1,qask_loop
        addi    $a0,$a0,1               # skip over 'x'
        li      $t7,16                  # set base 16
    
    qask_loop:
        lb      $t0,0($a0)              # get character
        addi    $a0,$a0,1               # advance buffer pointer
    
        # bug out if newline -- we are done
        li      $t1,0x0A
        beq     $t0,$t1,qask_done
    
        la      $t3,qask_hex
        li      $t1,0
    
    qask_trymatch:
        lb      $t2,0($t3)              # get next hex char
        addi    $t3,$t3,1               # advance hex string pointer
    
        beq     $t2,$t0,qask_match      # got a match
    
        addi    $t1,$t1,1               # advance hex offset
        blt     $t1,$t7,qask_trymatch   # too large? if no, loop
        j       qask_retry              # if yes, the input char is unknown
    
    qask_match:
        mul     $v0,$v0,$t7             # acc *= base
        add     $v0,$v0,$t1             # acc += digit
        j       qask_loop
    
    qask_dft:
        move    $v0,$a3
        j       qask_exit
    
    qask_done:
        beqz    $t6,qask_exit
        neg     $v0,$v0                 # set negative number
    
    qask_exit:
        jr      $ra
    
        .data
    qask_dft1:  .asciiz     " ["
    qask_dft2:  .asciiz     "] > "
    qask_buf:   .space      qask_siz
    qask_hex:   .asciiz     "0123456789ABCDEF"
    
        .text
    
        .data
    _S_000:     .asciiz     "dpyinit: mismatch\n"
    _S_001:     .asciiz     "output diamond pattern?"
    _S_002:     .asciiz     "minimum radius (0=single)"
    _S_003:     .asciiz     "radius decrement"
    _S_004:     .asciiz     "color increment (-1=rand, -2=rand/octant, -3=spin)"
    _S_005:     .asciiz     "dpy_width"
    _S_006:     .asciiz     "dpy_height"
    _S_007:     .asciiz     "dpy_radius"
        .data                           #+
    #+
    edata:
    

    【讨论】:

    • 谢谢!我尝试更好地使用 jr $ra,感谢您的指导和演示。它有很大帮助:) 我查看了链接列表链接,我将尝试使用提示来指导我完成编码。我很高兴你再举一个例子,你真是太酷了,太棒了:)这让我很开心:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-16
    • 1970-01-01
    相关资源
    最近更新 更多