×
Samples Blogs Make Payment About Us Reviews 4.9/5 Order Now

Create A Game Of Simon In MIPS Assembly Language (Running On MARS Simulator) Assignment Solution

July 06, 2024
Rehana Magnus
Rehana Magnus
🇨🇦 Canada
Assembly Language
Rehana Magnus, PhD in Computer Science from the esteemed Acadia Institute of Technology, Canada. With 6 years of experience, specializes in assembly language programming. Proficient in low-level coding, optimizing performance, and enhancing system functionality.
Key Topics
  • Instructions
  • Requirements and Specifications
Tip of the day
Familiarize yourself with OCaml's pattern matching; it simplifies handling recursive data structures like lists and trees, making your code concise and easier to debug.
News
In 2024, Girls Who Code introduced a Data Science + AI track in their free summer programs for high school students, fostering skills in cybersecurity and creative coding​

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:

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.