+1 (315) 557-6473 

Creation Of Game Of Simon In MIPS Assembly Language (Running On MARS Simulator) Assignment Solution.


Instructions

Objective
Write a MIPS assignment program to create a Game of Simon in assembly language (running on MARS simulator)

Requirements and Specifications

USE MARS SIMULATOR
Higher resolution display: when configuring the display, set Unit Width = 1, Unit Height = 1,Display Width = 256, display Height = 256. Play your old game with this configuration so you can see what it did and fix your code for the new resolution.
Use previous code and add this on to it:
(Prgm 2) Next we will modify the input If the user waits too long to enter the key they should also lose the game, even if they never press another key. This means you have to poll the keyboard interface because the get char syscall will not return. It should act as if the user entered the wrong key. Finally, add interrupts instead of polling to get the user input from the keyboard simulator. This will allow the user to hit a key while you are still redrawing the screen and/or beeping. It is OK if the display lags behind the user. Inside your handler, you should put the keys entered into a queue in case they enter more than one. I suggest working on this (and verifying) separately from the rest of lab. While it will make the rest of your code simpler, once you replace the built in exception handler, broken code can be extra confusing. You should use the exceptions.s Download exceptions.sI have posted to get you started.
Bonus: Make winning “funner”. You don’t have to show fireworks on the display while playing.
Queen’s “We are the Champions” on a marimba…that would not be worth enough points for all the time it would take. There is NO extra credit if you didn't get the rest of the lab meeting specifications, so you can not punt and make up for it here.
Screenshots of output
Game of Simon in MIPS assembly language
Game of Simon in MIPS assembly language 1
Game of Simon in MIPS assembly language 2
Game of Simon in MIPS assembly language 3
Source Code
       .data
        .word 0 : 40
Stack:
# Status register bits
EXC_ENABLE_MASK: .word 0x00000001
# Cause register bits
EXC_CODE_MASK: .word 0x0000003c # Exception code bits
EXC_CODE_INTERRUPT: .word 0 # External interrupt
EXC_CODE_ADDR_LOAD: .word 4 # Address error on load
EXC_CODE_ADDR_STORE: .word 5 # Address error on store
EXC_CODE_IBUS: .word 6 # Bus error instruction fetch
EXC_CODE_DBUS: .word 7 # Bus error on load or store
EXC_CODE_SYSCALL: .word 8 # System call
EXC_CODE_BREAKPOINT: .word 9 # Break point
EXC_CODE_RESERVED: .word 10 # Reserved instruction code
EXC_CODE_OVERFLOW: .word 12 # Arithmetic overflow
# Status and cause register bits
EXC_INT_ALL_MASK: .word 0x0000ff00 # Interrupt level enable bits
EXC_INT0_MASK: .word 0x00000100 # Software
EXC_INT1_MASK: .word 0x00000200 # Software
EXC_INT2_MASK: .word 0x00000400 # Display
EXC_INT3_MASK: .word 0x00000800 # Keyboard
EXC_INT4_MASK: .word 0x00001000
EXC_INT5_MASK: .word 0x00002000 # Timer
EXC_INT6_MASK: .word 0x00004000
EXC_INT7_MASK: .word 0x00008000
DigitTable:
        .byte ' ', 0,0,0,0,0,0,0,0,0,0,0,0
        .byte '0', 0x7e,0xff,0xc3,0xc3,0xc3,0xc3,0xc3,0xc3,0xc3,0xc3,0xff,0x7e
        .byte '1', 0x38,0x78,0xf8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18
        .byte '2', 0x7e,0xff,0x83,0x06,0x0c,0x18,0x30,0x60,0xc0,0xc1,0xff,0x7e
        .byte '3', 0x7e,0xff,0x83,0x03,0x03,0x1e,0x1e,0x03,0x03,0x83,0xff,0x7e
        .byte '4', 0xc3,0xc3,0xc3,0xc3,0xc3,0xff,0x7f,0x03,0x03,0x03,0x03,0x03
        .byte '5', 0xff,0xff,0xc0,0xc0,0xc0,0xfe,0x7f,0x03,0x03,0x83,0xff,0x7f
        .byte '6', 0xc0,0xc0,0xc0,0xc0,0xc0,0xfe,0xfe,0xc3,0xc3,0xc3,0xff,0x7e
        .byte '7', 0x7e,0xff,0x03,0x06,0x06,0x0c,0x0c,0x18,0x18,0x30,0x30,0x60
        .byte '8', 0x7e,0xff,0xc3,0xc3,0xc3,0x7e,0x7e,0xc3,0xc3,0xc3,0xff,0x7e
        .byte '9', 0x7e,0xff,0xc3,0xc3,0xc3,0x7f,0x7f,0x03,0x03,0x03,0x03,0x03
        .byte '+', 0x00,0x00,0x00,0x18,0x18,0x7e,0x7e,0x18,0x18,0x00,0x00,0x00
        .byte '-', 0x00,0x00,0x00,0x00,0x00,0x7e,0x7e,0x00,0x00,0x00,0x00,0x00
        .byte '*', 0x00,0x00,0x00,0x66,0x3c,0x18,0x18,0x3c,0x66,0x00,0x00,0x00
        .byte '/', 0x00,0x00,0x18,0x18,0x00,0x7e,0x7e,0x00,0x18,0x18,0x00,0x00
        .byte '=', 0x00,0x00,0x00,0x00,0x7e,0x00,0x7e,0x00,0x00,0x00,0x00,0x00
        .byte 'A', 0x18,0x3c,0x66,0xc3,0xc3,0xc3,0xff,0xff,0xc3,0xc3,0xc3,0xc3
        .byte 'B', 0xfc,0xfe,0xc3,0xc3,0xc3,0xfe,0xfe,0xc3,0xc3,0xc3,0xfe,0xfc
        .byte 'C', 0x7e,0xff,0xc1,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc1,0xff,0x7e
        .byte 'D', 0xfc,0xfe,0xc3,0xc3,0xc3,0xc3,0xc3,0xc3,0xc3,0xc3,0xfe,0xfc
        .byte 'E', 0xff,0xff,0xc0,0xc0,0xc0,0xfe,0xfe,0xc0,0xc0,0xc0,0xff,0xff
        .byte 'F', 0xff,0xff,0xc0,0xc0,0xc0,0xfe,0xfe,0xc0,0xc0,0xc0,0xc0,0xc0
# add additional characters here....
# first byte is the ascii character
# next 12 bytes are the pixels that are "on" for each of the 12 lines
        .byte 0, 0,0,0,0,0,0,0,0,0,0,0,0
prompt_lvl: .asciiz "Level? "
bad_lvl: .asciiz "\nLevel must be between 1 and 3\n"
win_msg: .asciiz "You win"
lose_msg: .asciiz "You lose"
ready: .asciiz "Ready..."
prompt: .asciiz "Input?: "
spaces: .asciiz "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
seq: .word 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 # array to hold sequence
color_table:
            .word 0x000000 #black
            .word 0x0000ff #blue
            .word 0x00ff00 #green
            .word 0xff0000 #red
            .word 0x00ffff #blue + green cyan
            .word 0xff00ff #blue + red magenta
            .word 0xffff00 #green + red yellow
            .word 0x4AABE5 #light blue
            .word 0x5AB661 #light green
            .word 0xDD3A35 #light red
            .word 0xEC6D2D #orange
            .word 0xffffff #white
box_table:
            .byte 128, 64, 10, 20, 52 # position of box 1, orange, radius 20, E1
            .byte 64, 128, 7, 20, 61 # position of box 2, blue, radius 20, C#
            .byte 192, 128, 9, 20, 64 # position of box 3, red, radius 20, E2
            .byte 128, 192, 8, 20, 69 # position of box 4, green, radius 20, A
level_len:
            .byte 5, 8, 11 # sequence lengths for all levels
cross_tab:
            .byte 50, 50, 156, 0
            .byte 51, 50, 155, 0
            .byte 50, 51, 155, 0
            .byte 50, 50, 156, 1
            .byte 51, 50, 155, 1
            .byte 50, 51, 155, 1
char_queue: .byte 0 : 256
queue_start: .word 0
queue_end: .word 0
.text
.globl main
main:
    la $sp, Stack
    jal init # initialize game
    li $s0, 0 # max = 0
    la $s1, seq # point to start of sequence
    jal read_level # read the level
    move $a0, $v0 # convert to sequence length
    jal level_seq_len # get sequence length
    move $s2, $v0 # save in $s2
game_loop:
    # generate number
    li $a0, 4 # generate a number between 0 and 3
    jal random # generate the number
    addi $a0, $a0, 1 # add 1 to start from 1
    # add to sequence
    sw $a0, 0($s1) # save random number in sequence
    addiu $s1, $s1, 4 # advance position in sequence
    addiu $s0, $s0, 1 # increment max
    # show sequence
    la $a0, seq # point to start of sequence
    move $a1, $s0 # pass max as the sequence size
    jal show_sequence # show the current sequence
    # get user sequence
    la $a0, seq # point to start of sequence
    move $a1, $s0 # pass max as the sequence size
    jal get_sequence # show the current sequence
    beqz $v0, fail # if user failed, end loop
    blt $s0, $s2, game_loop # if sequence was correct and max<5, repeat loop
win:
    li $a0, 2 # use green
    jal draw_cross # draw the cross
    # display win
    la $a0, win_msg # load address of win message
    jal put_string
    j exit # exit program
fail:
    li $a0, 3 # use red
    jal draw_cross # draw the cross
    # display lose
    la $a0, lose_msg # load address of lose message
    jal put_string
exit:
    li $v0, 10 # syscall to exit program
    syscall # exit the program
#------------------------------------------------------------------------------
# Procedure to initialize the game
#
init:
    addi $sp, $sp, -8 # allocate space in stack to save registers
    sw $ra, 0($sp) # save $ra
    sw $s0, 4($sp) # save $s0
    # get current time
    li $v0, 30 # syscall to get time
    syscall # get current time
    #initialize random seed using the current time
    move $a1, $a0 # use the time value (low part)
    li $a0, 0 # set generator id
    li $v0, 40 # syscall to set seed
    syscall # set the seed
    # Enable interrupts in status register
    mfc0 $t0, $12
    # Disable all interrupt levels
    lw $t1, EXC_INT_ALL_MASK
    not $t1, $t1
    and $t0, $t0, $t1
    # Enable console interrupt levels
    lw $t1, EXC_INT3_MASK
    or $t0, $t0, $t1
    #lw $t1, EXC_INT4_MASK
    #or $t0, $t0, $t1
    # Enable exceptions globally
    lw $t1, EXC_ENABLE_MASK
    or $t0, $t0, $t1
    mtc0 $t0, $12
    # Enable keyboard interrupts
    li $t0, 0xffff0000 # Receiver control register
    li $t1, 0x00000002 # Interrupt enable bit
    sw $t1, ($t0)
    li $t1, 0x00000001 # ready enable bit
    sw $t1, 8($t0)
    jal clear_disp # clear the display
    li $a0, 11 # use white
    jal draw_cross # draw the cross
    li $a0, 12 # clear display
    jal put_char
    li $s0, 1
show_loop:
    move $a0, $s0 # load element from sequence
    li $a1, 1 # use color
    li $a2, 1 # use sound
    jal draw_box_n # draw box
    # pause
    li $a0, 300 # wait for given time
    jal pause # pause
    addi $s0, $s0, 1
    ble $s0, 4, show_loop
    # pause
    li $a0, 500 # wait for given time
    jal pause # pause
    li $s0, 1
del_loop:
    move $a0, $s0 # load element from sequence
    li $a1, 0 # erase
    jal draw_box_n # draw box
    addi $s0, $s0, 1
    ble $s0, 4, del_loop
    lw $ra, 0($sp) # load $ra
    lw $s0, 4($sp) # load $s0
    addi $sp, $sp, 8 # remove allocated space from stack
    jr $ra # return to caller
#------------------------------------------------------------------------------
# Procedure to pause by a number of milliseconds
# On entry: $a0 = number of milliseconds to pause
pause:
    move $t0, $a0 # save number of milliseconds
    # get current time
    li $v0, 30 # syscall to get time
    syscall # get current time
    move $t1, $a0 # save low part of current time
ploop:
    syscall # get current time again
    subu $t2, $a0, $t1 # get elapsed time
    bltu $t2, $t0, ploop # if elapsed time < pause, repeat loop
    jr $ra # return to caller
#------------------------------------------------------------------------------
# Procedure to get a random number in a range
# On entry: $a0 = upper bound of range
# On return: $v0 = random number
random:
    move $a1, $a0 # use argument for the upper bound
    li $a0, 0 # generator id
    li $v0, 42 # syscall to generate a random number in a range
    syscall # generate the random number
    move $v0, $a0 # return generated number
    jr $ra # return to caller
#------------------------------------------------------------------------------
# Procedure to draw a filled box by number and blink it with the given delay
# On entry: $a0 = box number (1-4), $a1 = blink delay, $a2 = 0 no sound, 1 = sound,
# $a3 = wait at the end
# -1 = error sound
blink_box_n:
    addi $sp, $sp, -16 # allocate space in stack to save registers
    sw $ra, 0($sp) # save return address in stack
    sw $s0, 4($sp) # save $s0 in stack
    sw $s1, 8($sp) # save $s1 in stack
    sw $s2, 12($sp) # save $s2 in stack
    move $s0, $a0 # save arguments
    move $s1, $a1
    move $s2, $a3
    li $a1, 1 # use color
    jal draw_box_n # draw box
    # pause
    move $a0, $s1 # wait for given time
    jal pause # pause
    move $a0, $s0 # load element
    li $a1, 0 # erase
    li $a2, 0 # no sound
    jal draw_box_n # draw box
    li $a0, 12
    jal put_char
    beqz $s2, bb_end
    # pause
    srl $a0, $s1, 1 # wait for given time
    jal pause # pause
bb_end:
    lw $ra, 0($sp) # load return address from stack
    lw $s0, 4($sp) # load $s0 from stack
    lw $s1, 8($sp) # load $s1 from stack
    lw $s2,12($sp) # load $s2 from stack
    addi $sp, $sp, 16 # remove allocated space from stack
    jr $ra # return to caller
#------------------------------------------------------------------------------
# Procedure to show the current sequence
# On entry: $a0 = pointer to sequence array, $a1 = sequence size
show_sequence:
    addi $sp, $sp, -12 # allocate space in stack to save registers
    sw $ra, 0($sp) # save return address in stack
    sw $s0, 4($sp) # save $s0 in stack
    sw $s1, 8($sp) # save $s1 in stack
    move $s0, $a0 # load sequence pointer
    move $s1, $a1 # load sequence size
    # display ready message
    li $a0, 12
    jal put_char
    la $a0, ready # load address of ready message
    jal put_string
    # pause
    li $a0, 1000 # wait for 1s
    jal pause # pause
    # print newlines to clear screen
    li $a0, 12
    jal put_char
    # blink lights to show sequence
seq_loop:
    # print number
    lw $a0, 0($s0) # load element from sequence
    addi $a0, $a0, 48
    jal put_char t
    lw $a0, 0($s0) # load element from sequence
    li $a1, 1100 # wait for 1.5s
    li $a2, 1 # use sound
    li $a3, 1
    jal blink_box_n
    # print newlines
    li $a0, 12
    jal put_char
    addi $s0, $s0, 4 # advance to next element
    addi $s1, $s1, -1 # decrement size
    bne $s1, $zero, seq_loop # repeat while not zero
    lw $ra, 0($sp) # load return address from stack
    lw $s0, 4($sp) # load $s0 from stack
    lw $s1, 8($sp) # load $s1 from stack
    addi $sp, $sp, 12 # remove allocated space from stack
    jr $ra # return to caller
#------------------------------------------------------------------------------
# Procedure to get user sequence and compare to the current sequence
# On entry: $a0 = pointer to sequence array, $a1 = sequence size
# On return: $v0 = 1 if the used entered the sequence correctly, 0 otherwise
get_sequence:
    addi $sp, $sp, -16 # allocate space in stack to save registers
    sw $ra, 0($sp) # save return address in stack
    sw $s0, 4($sp) # save $s0 in stack
    sw $s1, 8($sp) # save $s1 in stack
    sw $s2, 12($sp) # save $s1 in stack
    move $s0, $a0 # load sequence pointer
    move $s1, $a1 # load sequence size
    jal flush_queue # remove previous chars
get_loop:
    # display prompt
    la $a0, prompt # load address of prompt message
    jal put_string
    # read number
    li $a0, 3000 # wait at most 3 s
    jal get_char
    addi $s2, $v0, -48 # convert ascii to number
    # print newline
    li $a0, 10 # newline char
    jal put_char
    move $a0, $s2 # load element input
    li $a1, 500 # wait for .5s
    li $a2, 1 # use sound
    li $a3, 0
    lw $t0, 0($s0) # load element from sequence
    beq $a0, $t0, skip # if the numbers are different, play error
    li $a2, -1
skip:
    jal blink_box_n
    lw $t2, 0($s0) # load element from sequence
    bne $t2, $s2, seq_fail # if the numbers are different, end with failure
    addi $s0, $s0, 4 # advance to next element
    addi $s1, $s1, -1 # decrement size
    bne $s1, $zero, get_loop # repeat while not zero
    li $v0, 1 # set 1 to indicate success
    j get_end # return
seq_fail:
    # blink correct position
    lw $a0, 0($s0) # load element from sequence
    li $a1, 700 # wait for 1s
    li $a2, 0
    jal blink_box_n
    lw $a0, 0($s0) # load element from sequence
    li $a1, 700 # wait for 1s
    li $a2, 0
    jal blink_box_n
    li $v0, 0 # return 0 to indicate it failed
get_end:
    lw $ra, 0($sp) # load return address from stack
    lw $s0, 4($sp) # load $s0 from stack
    lw $s1, 8($sp) # load $s1 from stack
    lw $s2,12($sp) # load $s1 from stack
    addi $sp, $sp, 16 # remove allocated space from stack
    jr $ra # return to caller
#------------------------------------------------------------------------------
# Procedure to calculate pixel address
# On entry: $a0 = x coord (0-255), $a1 = y coord (0-255)
# On return: $v0 = memory address
calc_addr:
    lui $v0, 0x1004 # load base address
    sll $t0, $a1, 8 # multiply y * 256
    add $t0, $t0, $a0 # add y*256 + x
    sll $t0, $t0, 2 # multiply by 4
    add $v0, $v0, $t0 # add 4*(y*256 + x) + base
    jr $ra # return to caller
#------------------------------------------------------------------------------
# Procedure to lookup color number
# On entry: $a2 = color number
# On return: $v1 = number to write to display
get_color:
    la $t0, color_table # load color table address
    sll $t1, $a2, 2 # multiply by 4
    add $t0, $t0, $t1 # add to base address
    lw $v1, 0($t0) # load color
    jr $ra # return to caller
#------------------------------------------------------------------------------
# Procedure to draw a dot
# On entry: $a0 = x coordinate (0-31), $a1 = y coordinate (0-31), $a2 = color number (0-7)
draw_dot:
    addi $sp, $sp, -4 # allocate space in stack to save registers
    sw $ra, 0($sp) # save $ra
    jal calc_addr # get pixel address
    jal get_color # load color
    sw $v1, 0($v0) # save pixel
    lw $ra, 0($sp) # load $ra
    addi $sp, $sp, 4 # remove allocated space from stack
    jr $ra # return to caller
#------------------------------------------------------------------------------
# Procedure to draw a horizontal line
# On entry: $a0 = x coordinate (0-31), $a1 = y coordinate (0-31), $a2 = color number (0-7)
# $a3 = length of the line (1-32)
horz_line:
    addi $sp, $sp, -12 # allocate space in stack to save registers
    sw $ra, 0($sp) # save $ra
    sw $a0, 4($sp) # save $a0
    sw $a3, 8($sp) # save $a3
horz_loop:
    jal draw_dot # draw pixel
    addi $a0, $a0, 1 # increment x
    addi $a3, $a3, -1 # decrement length
    bnez $a3, horz_loop # repeat while not zero
    lw $ra, 0($sp) # load $ra
    lw $a0, 4($sp) # load $a0
    lw $a3, 8($sp) # load $a3
    addi $sp, $sp, 12 # remove allocated space from stack
    jr $ra # return to caller
#------------------------------------------------------------------------------
# Procedure to draw a vertical line
# On entry: $a0 = x coordinate (0-31), $a1 = y coordinate (0-31), $a2 = color number (0-7)
# $a3 = length of the line (1-32)
vert_line:
    addi $sp, $sp, -12 # allocate space in stack to save registers
    sw $ra, 0($sp) # save $ra
    sw $a1, 4($sp) # save $a1
    sw $a3, 8($sp) # save $a3
vert_loop:
    jal draw_dot # draw pixel
    addi $a1, $a1, 1 # increment y
    addi $a3, $a3, -1 # decrement length
    bnez $a3, vert_loop # repeat while not zero
    lw $ra, 0($sp) # load $ra
    lw $a1, 4($sp) # load $a1
    lw $a3, 8($sp) # load $a3
    addi $sp, $sp, 12 # remove allocated space from stack
    jr $ra # return to caller
#------------------------------------------------------------------------------
# Procedure to draw a filled box
# On entry: $a0 = x coordinate (0-31), $a1 = y coordinate (0-31), $a2 = color number (0-7)
# $a3 = size of the box (1-32)
draw_box:
    addi $sp, $sp, -8 # allocate space in stack to save registers
    sw $ra, 0($sp) # save $ra
    sw $s0, 4($sp) # save $s0
    move $s0, $a3 # save size
box_loop:
    jal horz_line # draw line
    addi $a1, $a1, 1 # increment y
    addi $s0, $s0, -1 # decrement size
    bnez $s0, box_loop # repeat while not zero
    lw $ra, 0($sp) # load $ra
    lw $s0, 4($sp) # load $s0
    addi $sp, $sp, 8 # remove allocated space from stack
    jr $ra # return to caller
#------------------------------------------------------------------------------
# Procedure to clear the display
clear_disp:
    lui $t0, 0x1004 # load base address
    li $t1, 0x10000 # 256*256
clr_loop:
    sw $zero, 0($t0) # save pixel 0
    addi $t0, $t0, 4 # advance to next pixel
    addi $t1, $t1, -1 # repeat for all display
    bnez $t1, clr_loop
    jr $ra # return to caller
#------------------------------------------------------------------------------
# Procedure to draw a filled box by number
# On entry: $a0 = box number (1-4), $a1 = 0 to use black, 1 = to use table color
# $a2 = 1 use sound, 0=no sound, -1 incorrect sound
draw_box_n:
    addi $sp, $sp, -16 # allocate space in stack to save registers
    sw $ra, 0($sp) # save $ra
    sw $s0, 4($sp) # save $s0
    sw $s1, 8($sp) # save $s1
    sw $s2,12($sp) # save $s2
    move $s0, $a0
    move $s2, $a2
    la $t0, box_table # load address of box table
    blt $a0, 1, chk_snd # if incorrect number, only play sound
    bgt $a0, 4, chk_snd
    addi $t1, $a0, -1 # decrement to get 0-3
    sll $t2, $t1, 2 # multiply box by 5
    add $t1, $t1, $t2
    add $s1, $t0, $t1 # get address of box data
    beqz $a1, clear_box # if erasing, skip to draw box
    lbu $a0, 0($s1) # x
    lbu $a1, 1($s1) # y
    lbu $a2, 3($s1) # radius
    lbu $a3, 2($s1) # else set color from table
    jal draw_circle # draw circle
    lbu $t0, 3($s1) # radius
    lbu $a0, 0($s1) # x
    addi $a0, $a0, -5 # x - 5
    lbu $a1, 1($s1) # y
    addi $a1, $a1, -6 # y - 6
    addi $a2, $s0, 48 # number
    lbu $a3, 2($s1) # color from table
    jal out_char
chk_snd:
    beqz $s2, db_end # if no sound, end
    bltz $s2, play_err # if error play error
    lbu $a0, 4($s1) # load note for box
    li $a1, 500 # duration in milliseconds
    li $a2, 80 # instrument
    j play_snd
play_err:
    li $a0, 36 # else, load note for error
    li $a1, 700 # duration in milliseconds
    li $a2, 64 # instrument
play_snd:
    li $v0, 31
    li $a3, 120 # volume
    syscall # play the tone
    j db_end
clear_box:
    lbu $t1, 3($s1) # radius
    lbu $a0, 0($s1) # x - radius
    sub $a0, $a0, $t1
    lbu $a1, 1($s1) # y - radius
    sub $a1, $a1, $t1
    li $a2, 0 # black
    sll $a3, $t1, 1 # radius * 2 + 1
    add $a3, $a3, 1
    jal draw_box # draw box
db_end:
    lw $ra, 0($sp) # load $ra
    lw $s0, 4($sp) # load $s0
    lw $s1, 8($sp) # load $s1
    lw $s2,12($sp) # load $s2
    addi $sp, $sp, 16 # remove allocated space from stack
    jr $ra # return to caller
#------------------------------------------------------------------------------
# Procedure to read game level
# On return: $v0 = level 1-3
read_level:
    addi $sp, $sp, -4
    sw $ra, 0($sp)
    # display prompt for level
    la $a0, prompt_lvl # load address of prompt message
    jal put_string
    # read level
    li $a0, 0 # no timeout
    jal get_char
    addi $v0, $v0, -48
    slti $t0, $v0, 1 # if level < 1
    bnez $t0, error # print an error
    slti $t0, $v0, 4 # if level < 4
    bnez $t0, lvl_ok # return level
error:
    # display error
    la $a0, bad_lvl # load address of error message
    jal put_string
    j read_level
lvl_ok:
    lw $ra, 0($sp)
    addi $sp, $sp, 4
    jr $ra # return to caller
#------------------------------------------------------------------------------
# Procedure to get sequence length for a given level
# On entry: $a0 = level 1 - 3
# On return: $v0 = sequence length for level
level_seq_len:
    addi $a0, $a0, -1 # get level -1
    la $t0, level_len # load level length table
    add $t0, $t0, $a0 # get address of length
    lb $v0, 0($t0) # load level length
    jr $ra # return to caller
#------------------------------------------------------------------------------
# out_char: display an ascii character in white on the bit mapped display
# $a0 = horizontal pixel co-ordinate (0-255)
# $a1 = vertical pixel co-ordinate (0-255)
# $a2 = character
# $a3 = background color
out_char:
        addiu $sp, $sp, -24
        sw $ra, 20($sp)
        la $t3, DigitTable # find the character in the table
_text0:
        lb $t1, 0($t3) # get an entry from the table
        beq $t1, $a2, _text1
        beq $t1, $zero, _text1
        addiu $t3, $t3, 13 # go to the next entry in the table
        j _text0
_text1:
        move $a2, $a3
        jal get_color # load color
        move $a3, $v1
        la $t9, 0x10040000 # get the memory start address
        sll $t0, $a1, 8 # (a1 * 256)
        addu $t0, $t0, $a0
        sll $t0, $t0, 2
        addu $t9, $t9, $t0 # t9 = memory address for this pixel
        li $t8, 1 # line number in the digit array (1-12)
        addu $t3, $t3, 1 # advance to start of char bits
_text2:
        lb $t4, 0($t3) # bit map to be displayed
        sw $a3, 0($t9) # first pixel is black
        addiu $t9, $t9, 4
        li $t5, 8 # 8 bits to go out
_text3:
        move $t7, $a3
        andi $t6, $t4, 0x80 # mask out the bit (0=black, 1=white)
        beq $t6, $zero, _text4
        li $t7, 0xffffff
_text4:
        sw $t7, 0($t9) # write the pixel color
        addiu $t9, $t9, 4 # go to the next memory position
        sll $t4, $t4, 1 # and line number
        addiu $t5, $t5, -1 # and decrement down (8,7,...0)
        bne $t5, $zero, _text3
        sw $a3, 0($t9) # last pixel is black
        addiu $t9, $t9, 4
        addiu $t9, $t9, 984 # advance to the next line
        addu $t3, $t3, 1 # advance char line
        addiu $t8, $t8, 1 # increment the digit array offset (1-12)
        bne $t8, 13, _text2
        lw $ra, 20($sp)
        addiu $sp, $sp, 24
        jr $ra
#------------------------------------------------------------------------------
# Procedure to draw a filled circle
# On entry: $a0 = x, $a1 = y, $a2 = r, $a3 = color
draw_circle:
    addi $sp, $sp, -24
    sw $ra, 0($sp)
    sw $s0, 4($sp)
    sw $s1, 8($sp)
    sw $s2, 12($sp)
    sw $s3, 16($sp)
    sw $s4, 20($sp)
    move $s0, $a2 # x = radius
    li $s1, 0 # y = 0
    sll $t0, $a2, 1 # radius*2
    li $s2, 1
    sub $s2, $s2, $t0 # xChange = 1 - (radius *2)
    li $s3, 0 # yChange = 0
    li $s4, 0 # radiusError = 0
    move $t5, $a0 # preserve x0 and y0 arguments
    move $t6, $a1
    move $a2, $a3 # copy color to $a2
circ_loop: # while (x >= y)
    blt $s0, $s1, circ_end
    neg $t7, $s0 # i = -x
for1: # for (int i = - x; i <= x; i++)
    bgt $t7, $s0, for1_end
    add $a0, $t5, $t7
    add $a1, $t6, $s1
    jal draw_dot # set_pixel (x0 + i, y0 + y,color);
    add $a0, $t5, $t7
    sub $a1, $t6, $s1
    jal draw_dot # set_pixel (x0 + i, y0 - y,color);
    addi $t7, $t7, 1 # i++
    j for1
for1_end:
    beq $s0, $s1, for2_end
    neg $t7, $s1 # i = - y
for2: # for (int i = - y; i <= y; i++)
    bgt $t7, $s1, for2_end
    add $a0, $t5, $t7
    add $a1, $t6, $s0
    jal draw_dot # set_pixel (x0 + i, y0 + x,color);
    add $a0, $t5, $t7
    sub $a1, $t6, $s0
    jal draw_dot # set_pixel (x0 + i, y0 - x,color);
    addi $t7, $t7, 1 # i++
    j for2
for2_end:
    addi $s1, $s1, 1 # y++
    add $s4, $s4, $s3 # radiusError += yChange
    add $s3, $s3, 2 # yChange += 2
    # if (((radiusError << 1) + xChange) > 0)
    sll $t0, $s4, 1 # radiusError *2
    add $t0, $t0, $s2 # radiusError *2 + xChange
    blez $t0, circ_loop
    addi $s0, $s0, -1 # x--
    add $s4, $s4, $s2 # radiusError += xChange
    addi $s2, $s2, 2 # xChange += 2;
    j circ_loop
circ_end:
    lw $ra, 0($sp)
    lw $s0, 4($sp)
    lw $s1, 8($sp)
    lw $s2, 12($sp)
    lw $s3, 16($sp)
    lw $s4, 20($sp)
    addi $sp, $sp, 24
    jr $ra
#------------------------------------------------------------------------------
# Procedure to draw a white diagonal
# On entry: $a0 = x, $a1 = y, $a2 = length, $a3 = 0 if normal, 1 if inverted
# on stack = color
draw_diag:
    addi $sp, $sp, -20 # allocate space in stack to save registers
    sw $ra, 0($sp) # save $ra
    sw $s0, 4($sp) # save $s0
    sw $s1, 8($sp) # save $s1
    sw $s2,12($sp) # save $s2
    sw $s3,16($sp) # save $s3
    move $s0, $a0 # initial position x
    move $s1, $a1 # initial position y
    li $s2, 1 # increment
    move $s3, $a2 # load length
    beqz $a3, diag_loop
    li $t0, 256
    sub $s0, $t0, $s0 # invert x
    li $s2, -1 # decrement
diag_loop:
    move $a0, $s0 # x
    move $a1, $s1 # y
    lw $a2, 20($sp) # load color
    jal draw_dot # draw dot
    add $s0, $s0, $s2 # x+= inc
    add $s1, $s1, 1 # y++
    addiu $s3, $s3, -1 # len--
    bnez $s3, diag_loop
    lw $ra, 0($sp) # load $ra
    lw $s0, 4($sp) # load $s0
    lw $s1, 8($sp) # load $s1
    lw $s2,12($sp) # load $s2
    lw $s3,16($sp) # load $s3
    addi $sp, $sp, 20 # remove allocated space from stack
    jr $ra
#------------------------------------------------------------------------------
# Procedure to draw a cross
# Receives: $a0 = color
draw_cross:
    addi $sp, $sp, -12 # allocate space in stack to save registers
    sw $ra, 0($sp) # save $ra
    sw $s0, 4($sp) # save $s0
    sw $s1, 8($sp) # save $s1
    addi $sp, $sp, -4 # save color arg
    sw $a0, 0($sp)
    la $s0, cross_tab # point to cross table
    li $s1, 6 # draw 6 diagonals
cross_loop:
    lbu $a0, 0($s0) # initial position x
    lbu $a1, 1($s0) # initial position y
    lbu $a2, 2($s0) # length
    lbu $a3, 3($s0) # direction
    jal draw_diag # draw diagonal
    addi $s0, $s0, 4 # advance to next entry
    addi $s1, $s1, -1 # decrement number
    bnez $s1, cross_loop # repeat while not zero
    addi $sp, $sp, 4 # remove color
    lw $ra, 0($sp) # load $ra
    lw $s0, 4($sp) # load $s0
    lw $s1, 8($sp) # load $s1
    addi $sp, $sp, 12 # remove allocated space from stack
    jr $ra
#------------------------------------------------------------------------------
# Procedure to read a character using interrupts, echoes char on console
# Receives: $a0 = 0 if normal read, > 0 timeout
# Returns: $v0 = character read, or -1 if timeout
get_char:
    addi $sp, $sp, -12 # allocate space in stack to save registers
    sw $ra, 0($sp) # save $ra
    sw $s0, 4($sp) # save $s0
    sw $s1, 8($sp) # save $s1
    move $s0, $a0 # save argument
    # get current time
    li $v0, 30 # syscall to get time
    syscall # get current time
    move $s1, $a0 # save low part of current time
    la $t0, char_queue # load queue address
    la $t1, queue_start # load queue start index
    lw $t2, 0($t1) # load start of queue
    add $t0, $t0, $t2 # add to base address
    la $t3, queue_end # load queue end
gc_loop:
    beqz $s0, notime # if no timeout enabled, skip
    li $v0, 30 # syscall to get time
    syscall # get current time again
    subu $t4, $a0, $s1 # get elapsed time
    bgeu $t4, $s0, gc_tout # if elapsed time > timeout, return
notime:
    lw $t4, 0($t3) # load end
    beq $t4, $t2, gc_loop # if no chars, wait
    lb $s0, 0($t0) # load character
    addi $t2, $t2, 1 # increment start of queue
    andi $t2, $t2, 255 # wrap around if > 256
    sw $t2, 0($t1)
    move $a0, $s0 # echo on console
    jal put_char
    move $v0, $s0 # return char
    j gc_end
gc_tout:
    li $v0, -1 # timed out
gc_end:
    lw $ra, 0($sp) # load $ra
    lw $s0, 4($sp) # load $s0
    lw $s1, 8($sp) # load $s1
    addi $sp, $sp, 12 # remove allocated space from stack
    jr $ra
#------------------------------------------------------------------------------
# Procedure to print a character
# Receives: $a0 = character to print
put_char:
    li $t0, 0xffff0008
pc_loop:
    lw $t1, 0($t0) # load status
    andi $t1, $t1, 1 # test ready bit
    beqz $t1, pc_loop # if not ready, wait
    sw $a0, 4($t0) # save character
    jr $ra
#------------------------------------------------------------------------------
# Procedure to print a string
# Receives: $a0 = address of string to print
put_string:
    addi $sp, $sp, -8 # allocate space in stack to save registers
    sw $ra, 0($sp) # save $ra
    sw $s0, 4($sp) # save $s0
    move $s0, $a0 # copy string address
ps_loop:
    lb $a0, 0($s0) # load character from string
    beqz $a0, ps_end # if null, end print
    jal put_char # else, print character
    addi $s0, $s0, 1 # advance to next char
    j ps_loop
ps_end:
    lw $ra, 0($sp) # load $ra
    lw $s0, 4($sp) # load $s0
    addi $sp, $sp, 8 # remove allocated space from stack
    jr $ra
#------------------------------------------------------------------------------
# Procedure to reset input queue
flush_queue:
    la $t0, queue_start # load queue start index
    la $t1, queue_end # load queue end
    lw $t2, 0($t1) # load end of queue
    sw $t2, 0($t0) # save as start of queue
    jr $ra
 ########################################################################
 # Description:
 # Example SPIM exception handler
 # Derived from the default exception handler in the SPIM S20
 # distribution.
 #
 # History:
 # Dec 2009 J Bacon
 ########################################################################
 # Exception handling code. This must go first!
   .kdata
 __start_msg_: .asciiz " Exception "
 __end_msg_: .asciiz " occurred and ignored\n"
 # Messages for each of the 5-bit exception codes
 __exc0_msg: .asciiz " [Interrupt] "
 __exc1_msg: .asciiz " [TLB]"
 __exc2_msg: .asciiz " [TLB]"
 __exc3_msg: .asciiz " [TLB]"
 __exc4_msg: .asciiz " [Address error in inst/data fetch] "
 __exc5_msg: .asciiz " [Address error in store] "
 __exc6_msg: .asciiz " [Bad instruction address] "
 __exc7_msg: .asciiz " [Bad data address] "
 __exc8_msg: .asciiz " [Error in syscall] "
 __exc9_msg: .asciiz " [Breakpoint] "
 __exc10_msg: .asciiz " [Reserved instruction] "
 __exc11_msg: .asciiz ""
 __exc12_msg: .asciiz " [Arithmetic overflow] "
 __exc13_msg: .asciiz " [Trap] "
 __exc14_msg: .asciiz ""
 __exc15_msg: .asciiz " [Floating point] "
 __exc16_msg: .asciiz ""
 __exc17_msg: .asciiz ""
 __exc18_msg: .asciiz " [Coproc 2]"
 __exc19_msg: .asciiz ""
 __exc20_msg: .asciiz ""
 __exc21_msg: .asciiz ""
 __exc22_msg: .asciiz " [MDMX]"
 __exc23_msg: .asciiz " [Watch]"
 __exc24_msg: .asciiz " [Machine check]"
 __exc25_msg: .asciiz ""
 __exc26_msg: .asciiz ""
 __exc27_msg: .asciiz ""
 __exc28_msg: .asciiz ""
 __exc29_msg: .asciiz ""
 __exc30_msg: .asciiz " [Cache]"
 __exc31_msg: .asciiz ""
 __level_msg: .asciiz "Interrupt mask: "
 #########################################################################
 # Lookup table of exception messages
 __exc_msg_table:
  .word __exc0_msg, __exc1_msg, __exc2_msg, __exc3_msg, __exc4_msg
  .word __exc5_msg, __exc6_msg, __exc7_msg, __exc8_msg, __exc9_msg
  .word __exc10_msg, __exc11_msg, __exc12_msg, __exc13_msg, __exc14_msg
  .word __exc15_msg, __exc16_msg, __exc17_msg, __exc18_msg, __exc19_msg
  .word __exc20_msg, __exc21_msg, __exc22_msg, __exc23_msg, __exc24_msg
  .word __exc25_msg, __exc26_msg, __exc27_msg, __exc28_msg, __exc29_msg
  .word __exc30_msg, __exc31_msg
 # Variables for save/restore of registers used in the handler
 save_v0: .word 0
 save_a0: .word 0
 save_at: .word 0
 #########################################################################
 # This is the exception handler code that the processor runs when
 # an exception occurs. It only prints some information about the
 # exception, but can serve as a model of how to write a handler.
 #
 # Because this code is part of the kernel, it can use $k0 and $k1 without
 # saving and restoring their values. By convention, they are treated
 # as temporary registers for kernel use.
 #
 # On the MIPS-1 (R2000), the exception handler must be at 0x80000080
 # This address is loaded into the program counter whenever an exception
 # occurs. For the MIPS32, the address is 0x80000180.
 # Select the appropriate one for the mode in which SPIM is compiled.
  .ktext 0x80000180
  # Save ALL registers modified in this handler, except $k0 and $k1
  # This includes $t* since the user code does not explicitly
  # call this handler. $sp cannot be trusted, so saving them to
  # the stack is not an option. This routine is not reentrant (can't
  # be called again while it is running), so we can save registers
  # to static variables.
  sw $v0, save_v0
  sw $a0, save_a0
  # $at is the temporary register reserved for the assembler.
  # It may be modified by pseudo-instructions in this handler.
  # Since an interrupt could have occurred during a pseudo
  # instruction in user code, $at must be restored to ensure
  # that that pseudo instruction completes correctly.
  .set noat
  sw $at, save_at
  .set at
  # Determine cause of the exception
  mfc0 $k0, $13 # Get cause register from coprocessor 0
  srl $a0, $k0, 2 # Extract exception code field (bits 2-6)
  andi $a0, $a0, 0x1f
  # Check for program counter issues (exception 6)
  bne $a0, 6, ok_pc
  nop
  mfc0 $a0, $14 # EPC holds PC at moment exception occurred
  andi $a0, $a0, 0x3 # Is EPC word-aligned (multiple of 4)?
  beqz $a0, ok_pc
  nop
  # Bail out if PC is unaligned
  # Normally you don't want to do syscalls in an exception handler,
  # but this is MARS and not a real computer
  li $v0, 4
  la $a0, __exc3_msg
  syscall
  li $v0, 10
  syscall
 ok_pc:
  mfc0 $k0, $13
  srl $a0, $k0, 2 # Extract exception code from $k0 again
  andi $a0, $a0, 0x1f
  bnez $a0, non_interrupt # Code 0 means exception was an interrupt
  nop
  # External interrupt handler
  # Don't skip instruction at EPC since it has not executed.
  # Interrupts occur BEFORE the instruction at PC executes.
  # Other exceptions occur during the execution of the instruction,
  # hence for those increment the return address to avoid
  # re-executing the instruction that caused the exception.
      # check if we are in here because of a character on the keyboard simulator
   # go to nochar if some other interrupt happened
   # get the character from memory
   # store it to a queue somewhere to be dealt with later by normal code
    andi $a0, $k0, 0x100 # check if keyboard interrupt
    beqz $a0, return # if not keyboard, return
    nop
char:
    lui $a0, 0xffff # load keyboard char
    lw $v0, 4($a0)
    la $k0, char_queue # save char in queue
    la $k1, queue_end # load end
    lw $a0, 0($k1)
    add $k0, $k0, $a0 # save at end
    sb $v0, 0($k0)
    addi $a0, $a0, 1 # increment position
    andi $a0, $a0, 0xFF # wrap if >= 256
    sw $a0, 0($k1) # update end
  j return
nochar:
  # not a character
  # Print interrupt level
  # Normally you don't want to do syscalls in an exception handler,
  # but this is MARS and not a real computer
  li $v0, 4 # print_str
  la $a0, __level_msg
  syscall
  li $v0, 1 # print_int
  mfc0 $k0, $13 # Cause register
  srl $a0, $k0, 11 # Right-justify interrupt level bits
  syscall
  li $v0, 11 # print_char
  li $a0, 10 # Line feed
  syscall
  j return
 non_interrupt:
  # Print information about exception.
  # Normally you don't want to do syscalls in an exception handler,
  # but this is MARS and not a real computer
  li $v0, 4 # print_str
  la $a0, __start_msg_
  syscall
  li $v0, 1 # print_int
  mfc0 $k0, $13 # Extract exception code again
  srl $a0, $k0, 2
  andi $a0, $a0, 0x1f
  syscall
  # Print message corresponding to exception code
  # Exception code is already shifted 2 bits from the far right
  # of the cause register, so it conveniently extracts out as
  # a multiple of 4, which is perfect for an array of 4-byte
  # string addresses.
  # Normally you don't want to do syscalls in an exception handler,
  # but this is MARS and not a real computer
  li $v0, 4 # print_str
  mfc0 $k0, $13 # Extract exception code without shifting
  andi $a0, $k0, 0x7c
  lw $a0, __exc_msg_table($a0)
  nop
  syscall
  li $v0, 4 # print_str
  la $a0, __end_msg_
  syscall
  # Return from (non-interrupt) exception. Skip offending instruction
  # at EPC to avoid infinite loop.
  mfc0 $k0, $14
  addiu $k0, $k0, 4
  mtc0 $k0, $14
 return:
  # Restore registers and reset processor state
  lw $v0, save_v0 # Restore other registers
  lw $a0, save_a0
  .set noat # Prevent assembler from modifying $at
  lw $at, save_at
  .set at
  mtc0 $zero, $13 # Clear Cause register
  # Re-enable interrupts, which were automatically disabled
  # when the exception occurred, using read-modify-write cycle.
  mfc0 $k0, $12 # Read status register
  andi $k0, 0xfffd # Clear exception level bit
  ori $k0, 0x0001 # Set interrupt enable bit
  mtc0 $k0, $12 # Write back
  # Return from exception on MIPS32:
  eret
 #########################################################################
 # Standard startup code. Invoke the routine "main" with arguments:
 # main(argc, argv, envp)
  .text
  .globl __start
 __start:
  lw $a0, 0($sp) # argc = *$sp
  addiu $a1, $sp, 4 # argv = $sp + 4
  addiu $a2, $sp, 8 # envp = $sp + 8
  sll $v0, $a0, 2 # envp += size of argv array
  addu $a2, $a2, $v0
  jal main
  nop
  li $v0, 10 # exit
  syscall
  .globl __eoth
 __eoth: