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
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:
Similar Samples
Discover high-quality sample solutions for various programming assignments on ProgrammingHomeworkHelp.com. Our expertly crafted examples cover a wide range of topics and languages, offering clear and concise explanations to help you understand and excel in your programming tasks.
Assembly Language
Assembly Language
Assembly Language
Assembly Language
Assembly Language
Assembly Language
Assembly Language
Assembly Language
Assembly Language
Assembly Language
Assembly Language
Assembly Language
Assembly Language
Assembly Language
Assembly Language
Assembly Language
Assembly Language
Assembly Language
Assembly Language
Assembly Language