Как нарисовать круг с симулятором MARS MIPS? [Растровый дисплей] [дубликат]

Я не думаю, что вы сможете найти чисто портативное решение на основе python без использования / proc или утилит командной строки, по крайней мере, не в самом python. Парсинг os.system не уродлив - кто-то должен иметь дело с несколькими платформами, будь то вы или кто-то еще. Реализация этого для ОС, которую вы заинтересованы, должна быть довольно простой, честно.

0
задан cjj20 11 April 2016 в 22:14
поделиться

2 ответа

Ваша адресация пикселей кажется неправильной.

width - [ваша переменная] для ширины экрана, которая является 64. Но в вашем примере битмап имеет ширину 512 и высоту 256 [которые являются значениями по умолчанию в mars].

Итак, вам нужно либо изменить геометрию отображения в mars или установите для параметра width значение. То же самое для высоты.

Примечание: mars выполняет not сохранение установленных вами значений, поэтому, если вы хотите использовать геометрию, отличную от значения по умолчанию , вам нужно будет установить каждое время. Итак, возможно, простой способ - использовать значения по умолчанию mars.


UPDATE:

Я изменил значения, чтобы они совпадали с ошибками по умолчанию, но все же. Я думаю, может быть, мне нужно что-то изменить в коде setpixel. N также добавить счетчик где-нибудь

. Боюсь, что появилось множество ошибок. В основном, ваши функции сделали не сохранение / восстановление $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 для алгоритма круга, но либо их версия сломана, либо I сломал ее , Он не создает круг, а образец алмаза / шестиугольника. Итак, я оставил его в качестве опции.

Итак, я добавил версию Джону Кеннеди [Santa Monica College] [с сайта OSU]. Он работает.

Я также добавил некоторые опции для автоматического отображения на дисплей и автоматического вычисления центроида. Проверьте значения дисплея, так как он предполагает 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 список

2
ответ дан Community 19 August 2018 в 12:26
поделиться
  • 1
    Я изменил значения в соответствии с ошибками по умолчанию, но все же ошибками. Я думаю, может быть, мне нужно что-то изменить в коде setpixel. N также добавить счетчик где-то – cjj20 13 April 2016 в 15:44
  • 2
    Вау! Большое спасибо за это. Мне действительно нужен человек помощи. Это просто потрясающе :) Я так благодарна, что ты это сделал, много значит для меня :) – cjj20 24 April 2016 в 00:37
  • 3
    Пожалуйста. Поскольку я видел более недавний ваш вопрос, я начал думать, что вы пропустили мою обновленную версию. Также, пожалуйста, посмотрите на ссылку выше для «Связанного списка MIPS». Кроме того, после того, как я получил базовую версию моего кода, я решил немного повеселиться и добавить цвет. Цветная версия в новом ответе. Кроме того, обязательно обратите внимание на то, как $ra сохраняется / восстанавливается из стека в начале / конце функций. Это важно для правильной работы fncA->fncB->fncC – Craig Estey 24 April 2016 в 01:58

Примечание: этот ответ является продолжением моей предыдущей, которая не поместилась бы по соображениям космоса в первый ответ.

После экспериментов единственным жизнеспособным отображением отображения является «куча», отображение с геометрией, показанной ниже. Это ограничение марса.

Вот обновленная / улучшенная версия, которая делает цвет:

# 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:
0
ответ дан Craig Estey 19 August 2018 в 12:26
поделиться
  • 1
    благодаря! Я стараюсь использовать jr $ ra лучше, спасибо за руководство и демонстрацию. Это помогает много :) Я посмотрел ссылку связанного списка, и я попытаюсь использовать советы, которые помогут мне в кодировании. Я так взволнован, что ты даешь еще один пример: Thats действительно круто и потрясающе из вас :) Это сделало мой день :) – cjj20 24 April 2016 в 23:17
Другие вопросы по тегам:

Похожие вопросы: