如何在mips程序集中连接中点算法中的点

时间:2016-04-11 22:14:38

标签: assembly mips geometry

所以我想画一个圆圈,但屏幕上只出现4个点。如何生成更多点并连接它们?我已经包含了一张图片,因此您可以看到它在火星中的显示方式。enter image description here

中点圆算法

.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

2 个答案:

答案 0 :(得分:2)

您的像素寻址似乎有误。

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

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

当我做返工时,我尝试使用维基百科页面中的算法来获得圆算法,但是他们的版本被破坏了,或者打破了它。它不会产生圆形,而是钻石/六边形图案。所以,我把它留作了一个选项。

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

我还添加了一些选项来自动调整显示并自动计算质心。检查显示值,因为它采用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"

我最近为结构/链接列表做了MIPS答案。我还添加了很多关于如何编写MIPS代码的建议。在理解我在这里所做的事情时,你可能会有所帮助。请参阅:MIPS linked list

答案 1 :(得分:0)

注意:这个答案是我之前的答案的延续,由于空间原因,这个答案不适合第一个答案。

经过实验,唯一可行的显示映射是&#34;堆&#34;使用下面显示的几何图进行映射这是火星的限制。

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

# 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: