So I am trying to draw a circle but only 4 dots appear on the screen. How do I generate more dots and connect them? I have included a picture so you can see how it is displayed in mars.
midpoint circle algorithm
.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
Your pixel addressing appears to be wrong.
width
is [your variable for] the display width which is 64
. But, in your example, the bitmap has a width of 512 and height of 256 [which are the default values in mars
].
So, you either need to change the display geometry in mars
or set your width
variable to match. Same thing for height.
Note: mars
does not retain the values you set, so if you want to use a non-default geometry, you'll have to set it every time. So, maybe the easy way is to use the mars
default values.
UPDATE:
I changed the values to match the default but still errors. I'm thinking maybe I need to change something in the setpixel code n also add a counter somewhere
I'm afraid there were a number of bugs. Mostly, your functions did not save/restore $ra
on the stack and do a jr $ra
at the end.
Also, it seemed [to me] that your octant reflection code was much more complex [and therefore error prone] than it needed to be.
I created two versions. The first is your original code with annotations about [some of] the bugs. The second one is a full rework that works.
Here's the annotated version [please pardon the gratuitous style cleanup]:
.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
Here's the cleaned up, refactored, working version.
When I did the rework, I tried using the algorithm from wikipedia's page for the circle algorithm, but either their version is broken, or I broke it. It doesn't produce a circle, but a diamond/hexagon pattern. So, I left it in as an option.
So, I added John Kennedy's [Santa Monica College] version [from the OSU website]. It works.
I also added some options to autosize to the display and automatically calculate the centroid. Check the display values as it assumes 512x256 and the "static" display base address.
I also added some options to allow concentric circles to be drawn, just for amusement.
# 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"
I recently did a MIPS answer for struct/linked list. I also added a lot of suggestions about how to write MIPS code well. It may be of some help to you in understanding what I did here. See: MIPS linked list
Note: This answer is a continuation of my previous one, which would not have fit, for space reasons, into the first answer.
After experimentation, the only viable display mapping is the "heap" mapping with the geometry shown below. It's a limitation of mars.
Here's an updated/improved version that does color:
# 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: