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: