# # 378.asm - Translate 378 object code to SPIM assembler # # system calls PRINT_INT = 1 PRINT_STRING = 4 READ_INT = 5 SBRK = 9 EXIT = 10 OPEN = 11 READ = 12 WRITE = 13 CLOSE = 14 magic = 0x20383733 # "378 " is magic number at top of object file .data input_file_name: .asciiz "378.binary" output_file_name: .asciiz "spim.asm" message_success: .asciiz "Translation Completed\n" message_error_cannot_open_input_file: .asciiz ": cannot open input file\n" message_error_invalid_file_format: .asciiz ": invalid file format\n" message_error_cannot_open_output_file: .asciiz ": cannot open output file\n" .text .globl main main: # # PROLOG CODE # subu $sp, $sp, 44 # main sw $ra, 0($sp) # push return address sw $fp, 4($sp) # push frame pointer sw $s0, 8($sp) # push saved registers sw $s1, 12($sp) sw $s2, 16($sp) sw $s3, 20($sp) sw $s4, 24($sp) # # INITIALIZE VARIABLES # move $fp, $sp # $fp = frame pointer la $s0, 28($fp) # $s0 = address of 16 byte header buffer move $s1, $0 # $s1 = input file handle (0=not open) move $s4, $0 # $s4 = output file handle (0=not open) # # OPEN INPUT FILE # la $a0, input_file_name li $a1, 0x8000 # _O_BINARY | _O_RDONLY move $a2, $0 # unused for input file li $v0, OPEN syscall bltz $v0, error_cannot_open_input_file move $s1, $v0 # $s1 = input file handle move $a0, $s1 # READ HEADER FROM INPUT FILE move $a1, $s0 # header buffer on stack li $a2, 16 # size of header li $v0, READ syscall bne $v0, $a2, error_invalid_file_format # # CHECK MAGIC NUMBER # li $t0, magic # Compare first four bytes in buffer lw $t1, 0($s0) # with magic number and bail if wrong bne $t0, $t1, error_invalid_file_format # # CALCULATE ENTIRE FILE SIZE # li $s2, 16 # size of header lw $t0, 4($s0) add $s2, $s2, $t0 # plus data size lw $t0, 8($s0) add $s2, $s2, $t0 # plus code size # $s2 = size of input file # # ALLOCATE INPUT BUFFER # move $a0, $s2 # $a0 = bytes needed li $v0, SBRK syscall move $s3, $v0 # $s3 = buffer address # # COPY HEADER TO NEW BUFFER # lw $t0, 0($s0) # copy bytes 1-4 sw $t0, 0($s3) lw $t0, 4($s0) # copy bytes 5-8 sw $t0, 4($s3) lw $t0, 8($s0) # copy bytes 9-12 sw $t0, 8($s3) lw $t0, 12($s0) # copy bytes 13-16 sw $t0, 12($s3) # # READ INPUT FILE # move $a0, $s1 # $a0 = file handle move $a1, $s3 # $a1 = position in buffer after header addi $a1, 16 move $a2, $s2 # $a2 = size of file less header addi $a2, -16 li $v0, READ syscall bne $v0, $a2, error_invalid_file_format # # OPEN OUTPUT FILE # la $a0, output_file_name # $a0 = output file name li $a1, 0x8302 # $a1 = _O_BINARY | _O_TRUNC | _O_CREAT | _O_RDWR li $a2, 0x180 # $a2 = _S_IREAD | _S_IWRITE li $v0, OPEN syscall bltz $v0, error_cannot_open_output_file move $s4, $v0 # $s4 = output file handle # # GENERATE OUTPUT FILE # move $a0, $s4 # $a0 = output file handle move $a1, $s3 # $a1 = 378 code buffer jal translate_378 # translate the 378 code la $a0, message_success li $v0, PRINT_STRING syscall j exit # # REPORT INPUT OPEN FILE ERROR # error_cannot_open_input_file: la $a0, input_file_name li $v0, PRINT_STRING syscall la $a0, message_error_cannot_open_input_file li $v0, PRINT_STRING syscall j exit # # REPORT INPUT INVALID FILE ERROR # error_invalid_file_format: la $a0, input_file_name li $v0, PRINT_STRING syscall la $a0, message_error_invalid_file_format li $v0, PRINT_STRING syscall j exit # # REPORT OUTPUT INVALID FILE ERROR # error_cannot_open_output_file: la $a0, output_file_name li $v0, PRINT_STRING syscall la $a0, message_error_cannot_open_output_file li $v0, PRINT_STRING syscall j exit exit: # # CLOSE INPUT FILE (if necessary) # beqz $s1, input_file_closed # check first and then close move $a0, $s1 # $a0 = file handle li $v0, CLOSE syscall move $s1, $0 # clear file handle input_file_closed: # # CLOSE OUTPUT FILE (if necessary) # beqz $s4, output_file_closed # check first and then close move $a0, $s4 # $a0 = file handle li $v0, CLOSE syscall move $s4, $0 # clear file handle output_file_closed: # # EPILOG CODE # move $sp, $fp # restore stack pointer lw $s4, 24($sp) # pop saved registers lw $s3, 20($sp) lw $s2, 16($sp) lw $s1, 12($sp) lw $s0, 8($sp) lw $fp, 4($sp) # pop frame pointer lw $ra, 0($sp) # pop return address addu $sp, $sp, 44 jr $ra # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # translate_378 # # arguments: # # $a0 = output file handle (0 for console) # $a1 = Address of 378 object block # # returns: # # nothing # .data spim_data_header: .ascii "\n" .ascii " # DATA SEGMENT\n" .ascii " .data\n" .ascii " .align 2\n" .asciiz "data_begin:\n" spim_data_footer: .asciiz "data_end:\n" spim_data_word_prefix: .asciiz " .word 0x" spim_data_word_suffix: .asciiz "\n" spim_jump_table_header: .ascii "\n" .ascii " # JUMP TABLE\n" .ascii " .data\n" .ascii " .align 2\n" .asciiz "jump_begin:\n" spim_jump_table_prefix: .asciiz " .word code" spim_jump_table_suffix: .asciiz "\n" spim_jump_table_footer: .asciiz "jump_end:\n" spim_code_header: .ascii "\n" .ascii " # CODE\n" .ascii "\n" .ascii " # system calls\n" .ascii " PRINT_INT = 1\n" .ascii " PRINT_STRING = 4\n" .ascii " READ_INT = 5\n" .ascii " EXIT = 10\n" .ascii "\n" .ascii " .data\n" .ascii "newline:\n" .ascii " .byte 10, 0\n" .ascii "return_code_prefix:\n" .ascii " .asciiz \"Program exited with code \"\n" .ascii "return_code_suffix:\n" .ascii " .byte 10, 0\n" .ascii "\n" .ascii " .text\n" .ascii "main:\n" .ascii " .globl main\n" .ascii " move $fp, $sp # save stack pointer\n" .asciiz "\n" spim_code_label_prefix: .asciiz "code" spim_code_label_infix: .asciiz ": #" spim_code_label_suffix: .asciiz "\n" spim_code_initial_jump_prefix: .asciiz " j code" spim_code_initial_jump_suffix: .asciiz " # Jump to initial PC position\n" spim_code_footer: .ascii "success:\n" .ascii " li $t9, 0 # NORMAL EXIT\n" .ascii " j exit\n\n" .ascii "runtime_error_underflow:\n" .ascii " li $t9, 1 # STACK UNDERFLOW\n" .ascii " j exit\n\n" .ascii "runtime_error_bad_opcode:\n" .ascii " li $t9, 2 # BAD OPCODE\n" .ascii " j exit\n\n" .ascii "runtime_error_bad_address:\n" .ascii " li $t9, 3 # BAD ADDRESS\n" .ascii " j exit\n\n" .ascii "runtime_error_bad_jump:\n" .ascii " li $t9, 4 # BAD JUMP\n" .ascii " j exit\n\n" .ascii "exit:\n" .ascii " move $sp, $fp\n" .ascii " li $v0, PRINT_STRING\n" .ascii " la $a0, return_code_prefix\n" .ascii " syscall\n" .ascii " li $v0, PRINT_INT\n" .ascii " move $a0, $t9\n"; .ascii " syscall\n" .ascii " li $v0, PRINT_STRING\n" .ascii " la $a0, return_code_suffix\n" .ascii " syscall\n" .ascii " li $v0, EXIT\n" .asciiz " syscall\n" .text translate_378: # # PROLOG CODE # subu $sp, $sp, 28 # translate_378 sw $ra, 0($sp) # push return address sw $fp, 4($sp) # push frame pointer sw $s0, 8($sp) # push saved registers sw $s1, 12($sp) sw $s2, 16($sp) sw $s3, 20($sp) sw $s4, 24($sp) # # INITIALIZE VARIABLES # move $fp, $sp # $fp = frame pointer move $s0, $a0 # $s0 = output file handle (0 for console) move $s1, $a1 # $s1 = base of 378 object buffer # # EMIT DATA SEGMENT # move $a0, $s0 # emit data segment header la $a1, spim_data_header jal emit_string addi $s2, $s1, 16 # $s2 = address of data segment lw $s3, 4($s1) # $s3 = size of data segment in bytes t378_data_loop_start: blez $s3, t378_data_loop_end # No words remaining, we are done move $a0, $s0 # emit data word prefix la $a1, spim_data_word_prefix jal emit_string move $a0, $s0 # emit hex value of word lw $a1, ($s2) jal emit_hex move $a0, $s0 # emit data word suffix la $a1, spim_data_word_suffix jal emit_string addi $s2, $s2, 4 # move to next word addi $s3, $s3, -4 # one less word j t378_data_loop_start t378_data_loop_end: move $a0, $s0 # emit data segment footer la $a1, spim_data_footer jal emit_string # # EMIT JUMP TABLE # move $a0, $s0 # emit jump table header la $a1, spim_jump_table_header jal emit_string move $s2, $0 # $s2 = code segment addresses lw $s3, 8($s1) # $s3 = size of code segment in bytes t378_jump_loop_start: blez $s3, t378_jump_loop_end # No words remaining, we are done move $a0, $s0 # emit jump table prefix la $a1, spim_jump_table_prefix jal emit_string move $a0, $s0 # emit hex value of code offset move $a1, $s2 jal emit_hex move $a0, $s0 # emit jump table suffix la $a1, spim_jump_table_suffix jal emit_string addi $s2, $s2, 4 # move to next word addi $s3, $s3, -4 # one less word j t378_jump_loop_start t378_jump_loop_end: move $a0, $s0 # emit data segment footer la $a1, spim_jump_table_footer jal emit_string # # EMIT CODE # move $a0, $s0 # emit code segment header la $a1, spim_code_header jal emit_string move $a0, $s0 # emit initial jump prefix la $a1, spim_code_initial_jump_prefix jal emit_string move $a0, $s0 # emit hex value of initial PC lw $a1, 12($s1) # $a1 = initial PC from header jal emit_hex move $a0, $s0 # emit initial jump suffix la $a1, spim_code_initial_jump_suffix jal emit_string move $s2, $0 # $s2 = code segment addresses lw $s3, 8($s1) # $s3 = size of code segment in bytes addi $t0, $s1, 16 # $t0 = address of data segment lw $t1, 4($s1) # $t1 = size of data segment in bytes add $s4, $t0, $t1 # $s4 = base address of code segment t378_code_loop_start: blez $s3, t378_code_loop_end # No words remaining, we are done move $a0, $s0 # emit code label prefix la $a1, spim_code_label_prefix jal emit_string move $a0, $s0 # emit hex value of code offset move $a1, $s2 jal emit_hex move $a0, $s0 # emit code label infix la $a1, spim_code_label_infix jal emit_string move $a0, $s0 # emit hex value of opcode as comment add $t0, $s4, $s2 lw $a1, ($t0) jal emit_hex move $a0, $s0 # emit code label suffix la $a1, spim_code_label_suffix jal emit_string move $a0, $s0 # emit translated SPIM code add $t0, $s4, $s2 lw $a1, ($t0) jal emit_instruction addi $s2, $s2, 4 # move to next word addi $s3, $s3, -4 # one less word j t378_code_loop_start t378_code_loop_end: move $a0, $s0 # emit code footer la $a1, spim_code_footer jal emit_string # # EPILOG CODE # move $sp, $fp # restore stack pointer lw $s4, 24($sp) # pop saved registers lw $s3, 20($sp) lw $s2, 16($sp) lw $s1, 12($sp) lw $s0, 8($sp) lw $fp, 4($sp) # pop frame pointer lw $ra, 0($sp) # pop return address addu $sp, $sp, 28 jr $ra # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # emit_instruction # # arguments: # # $a0 = output file handle (0 for console) # $a1 = opcode to interpret # # returns: # # nothing # .data .align 2 opcode_table: .word emit_instruction_undefined # 0 - 0000 - UNDEFINED .word emit_instruction_add # 1 - 0001 - Add .word emit_instruction_sub # 2 - 0010 - Subtract .word emit_instruction_mult # 3 - 0011 - Multiply .word emit_instruction_undefined # 4 - 0100 - UNDEFINED .word emit_instruction_bgtz # 5 - 0101 - Branch-greater-than-zero .word emit_instruction_bez # 6 - 0110 - Branch-equal-to-zero .word emit_instruction_jump # 7 - 0111 - Jump to addr in top of stack .word emit_instruction_load # 8 - 1000 - Load memory to stack top .word emit_instruction_store # 9 - 1001 - Store from stack to memory .word emit_instruction_interrupt # A - 1010 - Invoke operating system .word emit_instruction_undefined # B - 1011 - UNDEFINED .word emit_instruction_undefined # C - 1100 - UNDEFINED .word emit_instruction_clear # D - 1101 - Clear stack .word emit_instruction_push # E - 1110 - Push immediate value on stack .word emit_instruction_undefined # F - 1111 - UNDEFINED .text emit_instruction: # # PROLOG CODE # subu $sp, $sp, 8 # emit_instruction sw $ra, 0($sp) # push return address sw $fp, 4($sp) # push frame pointer # # INITIALIZE VARIABLES # move $fp, $sp # $fp = frame pointer # # DISPATCH VIA JUMP TABLE # li $t0, 0xf0000000 # Mask off top four bits and $t0, $a1, $t0 srl $t0, $t0, 26 # Shift to bits 2-6 for word addressing la $t1, opcode_table add $t1, $t1, $t0 lw $t2, ($t1) # Load routine from jump table jalr $t2 # Call indirect # # EPILOG CODE # move $sp, $fp # restore stack pointer lw $fp, 4($sp) # pop frame pointer lw $ra, 0($sp) # pop return address addu $sp, $sp, 8 jr $ra # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # strings common to many instructions # .data spim_code_pop2: .ascii " addu $t9, $sp, 8\n" .ascii " bgtu $t9, $fp, runtime_error_underflow\n" .ascii " lw $t0, 0($sp) # POP $t0\n" .ascii " lw $t1, 4($sp) # POP $t1\n" .asciiz " move $sp, $t9\n" spim_code_pop1: .ascii " addu $t9, $sp, 4\n" .ascii " bgtu $t9, $fp, runtime_error_underflow\n" .ascii " lw $t0, 0($sp) # POP $t0\n" .asciiz " move $sp, $t9\n" spim_code_push1: .ascii " subu $sp, $sp, 4\n" .asciiz " sw $t0, 0($sp) # PUSH $t0\n" # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # emit_instruction_undefined # # arguments: # # $a0 = output file handle (0 for console) # $a1 = opcode to interpret # # returns: # # nothing # .data spim_code_instruction_undefined: .asciiz " j runtime_error_bad_opcode\n" .text emit_instruction_undefined: # # PROLOG CODE # subu $sp, $sp, 8 # emit_instruction_undefined sw $ra, 0($sp) # push return address sw $fp, 4($sp) # push frame pointer # # INITIALIZE VARIABLES # move $fp, $sp # $fp = frame pointer # # EMIT CODE # la $a1, spim_code_instruction_undefined jal emit_string # # EPILOG CODE # move $sp, $fp # restore stack pointer lw $fp, 4($sp) # pop frame pointer lw $ra, 0($sp) # pop return address addu $sp, $sp, 8 jr $ra # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # emit_instruction_add # # arguments: # # $a0 = output file handle (0 for console) # $a1 = opcode to interpret # # returns: # # nothing # .data spim_code_instruction_add: .asciiz " add $t0, $t0, $t1 # ADD\n" .text emit_instruction_add: # # PROLOG CODE # subu $sp, $sp, 12 # emit_instruction_add sw $ra, 0($sp) # push return address sw $fp, 4($sp) # push frame pointer sw $s0, 8($sp) # push saved register # # INITIALIZE VARIABLES # move $fp, $sp # $fp = frame pointer move $s0, $a0 # $s0 = output file handle (0 for console) # # EMIT CODE # move $a0, $s0 la $a1, spim_code_pop2 jal emit_string move $a0, $s0 la $a1, spim_code_instruction_add jal emit_string move $a0, $s0 la $a1, spim_code_push1 jal emit_string # # EPILOG CODE # move $sp, $fp # restore stack pointer lw $s0, 8($sp) # pop saved registers lw $fp, 4($sp) # pop frame pointer lw $ra, 0($sp) # pop return address addu $sp, $sp, 12 jr $ra # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # emit_instruction_sub # # arguments: # # $a0 = output file handle (0 for console) # $a1 = opcode to interpret # # returns: # # nothing # .data spim_code_instruction_sub: .asciiz " sub $t0, $t1, $t0 # SUB\n" .text emit_instruction_sub: # # PROLOG CODE # subu $sp, $sp, 12 # emit_instruction_sub sw $ra, 0($sp) # push return address sw $fp, 4($sp) # push frame pointer sw $s0, 8($sp) # push saved register # # INITIALIZE VARIABLES # move $fp, $sp # $fp = frame pointer move $s0, $a0 # $s0 = output file handle (0 for console) # # EMIT CODE # move $a0, $s0 la $a1, spim_code_pop2 jal emit_string move $a0, $s0 la $a1, spim_code_instruction_sub jal emit_string move $a0, $s0 la $a1, spim_code_push1 jal emit_string # # EPILOG CODE # move $sp, $fp # restore stack pointer lw $s0, 8($sp) # pop saved register lw $fp, 4($sp) # pop frame pointer lw $ra, 0($sp) # pop return address addu $sp, $sp, 12 jr $ra # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # emit_instruction_mult # # arguments: # # $a0 = output file handle (0 for console) # $a1 = opcode to interpret # # returns: # # nothing # .data spim_code_instruction_mult: .ascii " mult $t0, $t1 # SUB\n" .asciiz " mflo $t0\n" .text emit_instruction_mult: # # PROLOG CODE # subu $sp, $sp, 12 # emit_instruction_mult sw $ra, 0($sp) # push return address sw $fp, 4($sp) # push frame pointer sw $s0, 8($sp) # push saved register # # INITIALIZE VARIABLES # move $fp, $sp # $fp = frame pointer move $s0, $a0 # $s0 = output file handle (0 for console) # # EMIT CODE # move $a0, $s0 la $a1, spim_code_pop2 jal emit_string move $a0, $s0 la $a1, spim_code_instruction_mult jal emit_string move $a0, $s0 la $a1, spim_code_push1 jal emit_string # # EPILOG CODE # move $sp, $fp # restore stack pointer lw $s0, 8($sp) # pop saved registers lw $fp, 4($sp) # pop frame pointer lw $ra, 0($sp) # pop return address addu $sp, $sp, 12 jr $ra # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # emit_instruction_bgtz # # arguments: # # $a0 = output file handle (0 for console) # $a1 = opcode to interpret # # returns: # # nothing # .data spim_code_instruction_bgtz_prefix: .asciiz " bgtz $t0, code" spim_code_instruction_bgtz_suffix: .asciiz " # BGTZ\n" .text emit_instruction_bgtz: # # PROLOG CODE # subu $sp, $sp, 16 # emit_instruction_bgtz sw $ra, 0($sp) # push return address sw $fp, 4($sp) # push frame pointer sw $s0, 8($sp) # push saved registers sw $s1, 12($sp) # # INITIALIZE VARIABLES # move $fp, $sp # $fp = frame pointer move $s0, $a0 # $s0 = output file handle (0 for console) move $s1, $a1 # $s1 = opcode to interpret # # EMIT CODE # move $a0, $s0 la $a1, spim_code_pop1 jal emit_string move $a0, $s0 la $a1, spim_code_instruction_bgtz_prefix jal emit_string move $a0, $s0 li $a1, 0x0fffffff and $a1, $a1, $s1 jal emit_hex move $a0, $s0 la $a1, spim_code_instruction_bgtz_suffix jal emit_string # # EPILOG CODE # move $sp, $fp # restore stack pointer lw $s1, 12($sp) # pop saved registers lw $s0, 8($sp) lw $fp, 4($sp) # pop frame pointer lw $ra, 0($sp) # pop return address addu $sp, $sp, 16 jr $ra # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # emit_instruction_bez # # arguments: # # $a0 = output file handle (0 for console) # $a1 = opcode to interpret # # returns: # # nothing # .data spim_code_instruction_bez_prefix: .asciiz " beqz $t0, code" spim_code_instruction_bez_suffix: .asciiz " # BEZ\n" .text emit_instruction_bez: # # PROLOG CODE # subu $sp, $sp, 16 # emit_instruction_bez sw $ra, 0($sp) # push return address sw $fp, 4($sp) # push frame pointer sw $s0, 8($sp) # push saved registers sw $s1, 12($sp) # # INITIALIZE VARIABLES # move $fp, $sp # $fp = frame pointer move $s0, $a0 # $s0 = output file handle (0 for console) move $s1, $a1 # $s1 = opcode to interpret # # EMIT CODE # move $a0, $s0 la $a1, spim_code_pop1 jal emit_string move $a0, $s0 la $a1, spim_code_instruction_bez_prefix jal emit_string move $a0, $s0 li $a1, 0x0fffffff and $a1, $a1, $s1 jal emit_hex move $a0, $s0 la $a1, spim_code_instruction_bez_suffix jal emit_string # # EPILOG CODE # move $sp, $fp # restore stack pointer lw $s1, 12($sp) # pop saved registers lw $s0, 8($sp) lw $fp, 4($sp) # pop frame pointer lw $ra, 0($sp) # pop return address addu $sp, $sp, 16 jr $ra # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # emit_instruction_jump # # arguments: # # $a0 = output file handle (0 for console) # $a1 = opcode to interpret # # returns: # # nothing # .data spim_code_instruction_jump: .ascii " bltz $t0, runtime_error_bad_jump\n" .ascii " la $t9, jump_begin\n" .ascii " la $t8, jump_end\n" .ascii " add $t9, $t9, $t0\n" .ascii " bgeu $t9, $t8, runtime_error_bad_jump\n" .ascii " lw $t9, ($t9)\n" .asciiz " jr $t9 # JUMP\n" .text emit_instruction_jump: # # PROLOG CODE # subu $sp, $sp, 12 # emit_instruction_jump sw $ra, 0($sp) # push return address sw $fp, 4($sp) # push frame pointer sw $s0, 8($sp) # push saved register # # INITIALIZE VARIABLES # move $fp, $sp # $fp = frame pointer move $s0, $a0 # $s0 = output file handle (0 for console) # # EMIT CODE # move $a0, $s0 la $a1, spim_code_pop1 jal emit_string move $a0, $s0 la $a1, spim_code_instruction_jump jal emit_string # # EPILOG CODE # move $sp, $fp # restore stack pointer lw $s0, 8($sp) # pop saved register lw $fp, 4($sp) # pop frame pointer lw $ra, 0($sp) # pop return address addu $sp, $sp, 12 jr $ra # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # emit_instruction_load # # arguments: # # $a0 = output file handle (0 for console) # $a1 = opcode to interpret # # returns: # # nothing # .data spim_code_instruction_load: .ascii " bltz $t0, runtime_error_bad_address\n" .ascii " la $t9, data_begin\n" .ascii " la $t8, data_end\n" .ascii " add $t9, $t9, $t0\n" .ascii " bgeu $t9, $t8, runtime_error_bad_address\n" .asciiz " lw $t0, ($t9) # LOAD\n" .text emit_instruction_load: # # PROLOG CODE # subu $sp, $sp, 12 # emit_instruction_load sw $ra, 0($sp) # push return address sw $fp, 4($sp) # push frame pointer sw $s0, 8($sp) # push saved register # # INITIALIZE VARIABLES # move $fp, $sp # $fp = frame pointer move $s0, $a0 # $s0 = output file handle (0 for console) # # EMIT CODE # move $a0, $s0 la $a1, spim_code_pop1 jal emit_string move $a0, $s0 la $a1, spim_code_instruction_load jal emit_string move $a0, $s0 la $a1, spim_code_push1 jal emit_string # # EPILOG CODE # move $sp, $fp # restore stack pointer lw $s0, 8($sp) # pop saved register lw $fp, 4($sp) # pop frame pointer lw $ra, 0($sp) # pop return address addu $sp, $sp, 12 jr $ra # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # emit_instruction_store # # arguments: # # $a0 = output file handle (0 for console) # $a1 = opcode to interpret # # returns: # # nothing # .data spim_code_instruction_store: .ascii " bltz $t0, runtime_error_bad_address\n" .ascii " la $t9, data_begin\n" .ascii " la $t8, data_end\n" .ascii " add $t9, $t9, $t0\n" .ascii " bgeu $t9, $t8, runtime_error_bad_address\n" .asciiz " sw $t1, ($t9) # STORE\n" .text emit_instruction_store: # # PROLOG CODE # subu $sp, $sp, 12 # emit_instruction_store sw $ra, 0($sp) # push return address sw $fp, 4($sp) # push frame pointer sw $s0, 8($sp) # push saved register # # INITIALIZE VARIABLES # move $fp, $sp # $fp = frame pointer move $s0, $a0 # $s0 = output file handle (0 for console) # # EMIT CODE # move $a0, $s0 la $a1, spim_code_pop2 jal emit_string move $a0, $s0 la $a1, spim_code_instruction_store jal emit_string # # EPILOG CODE # move $sp, $fp # restore stack pointer lw $s0, 8($sp) # pop saved register lw $fp, 4($sp) # pop frame pointer lw $ra, 0($sp) # pop return address addu $sp, $sp, 12 jr $ra # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # emit_instruction_interrupt # # arguments: # # $a0 = output file handle (0 for console) # $a1 = opcode to interpret # # returns: # # nothing # .data spim_code_interrupt_terminate: .asciiz " j success # interrupt 0 - exit\n" spim_code_interrupt_print: .ascii " li $v0, PRINT_INT # interrupt 1 - print\n" .ascii " move $a0, $t0\n" .ascii " syscall\n" .ascii " li $v0, PRINT_STRING\n" .ascii " la $a0, newline\n" .asciiz " syscall\n" spim_code_interrupt_read: .ascii " li $v0, READ_INT # interrupt 2 - read\n" .ascii " syscall\n" .asciiz " move $t0, $v0\n" .text emit_instruction_interrupt: # # PROLOG CODE # subu $sp, $sp, 16 # emit_instruction_interrupt sw $ra, 0($sp) # push return address sw $fp, 4($sp) # push frame pointer sw $s0, 8($sp) # push saved registers sw $s1, 12($sp) # # INITIALIZE VARIABLES # move $fp, $sp # $fp = frame pointer move $s0, $a0 # $s0 = output file handle (0 for console) move $s1, $a1 # $s1 = opcode to interpret li $t0, 0x0fffffff # $t0 = interrupt number and $t0, $t0, $s1 # # DISPATCH TO SPECIFIC INTERRUPT # beq $t0, 0, ei_terminate beq $t0, 1, ei_print beq $t0, 2, ei_read jal emit_instruction_undefined # if we get here, undefined j ei_exit # # EMIT TERMINATE CODE # ei_terminate: move $a0, $s0 la $a1, spim_code_interrupt_terminate jal emit_string j ei_exit # # EMIT PRINT CODE # ei_print: move $a0, $s0 la $a1, spim_code_pop1 jal emit_string move $a0, $t0 la $a1, spim_code_interrupt_print jal emit_string j ei_exit # # EMIT READ CODE # ei_read: move $a0, $s0 la $a1, spim_code_interrupt_read jal emit_string move $a0, $s0 la $a1, spim_code_push1 jal emit_string j ei_exit ei_exit: # # EPILOG CODE # move $sp, $fp # restore stack pointer lw $s1, 12($sp) # pop saved registers lw $s0, 8($sp) lw $fp, 4($sp) # pop frame pointer lw $ra, 0($sp) # pop return address addu $sp, $sp, 16 jr $ra # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # emit_instruction_clear # # arguments: # # $a0 = output file handle (0 for console) # $a1 = opcode to interpret # # returns: # # nothing # .data spim_code_instruction_clear: .asciiz " move $sp, $fp # CLEAR\n" .text emit_instruction_clear: # # PROLOG CODE # subu $sp, $sp, 12 # emit_instruction_clear sw $ra, 0($sp) # push return address sw $fp, 4($sp) # push frame pointer sw $s0, 8($sp) # push saved register # # INITIALIZE VARIABLES # move $fp, $sp # $fp = frame pointer move $s0, $a0 # $s0 = output file handle (0 for console) # # EMIT SPIM CODE # move $a0, $s0 la $a1, spim_code_instruction_clear jal emit_string # # EPILOG CODE # move $sp, $fp # restore stack pointer lw $s0, 8($sp) # pop saved register lw $fp, 4($sp) # pop frame pointer lw $ra, 0($sp) # pop return address addu $sp, $sp, 12 jr $ra # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # emit_instruction_push # # arguments: # # $a0 = output file handle (0 for console) # $a1 = opcode to interpret # # returns: # # nothing # .data spim_code_instruction_push_prefix: .asciiz " li $t0, 0x" spim_code_instruction_push_suffix: .asciiz " # PUSH\n" .text emit_instruction_push: # # PROLOG CODE # subu $sp, $sp, 16 # emit_instruction_push sw $ra, 0($sp) # push return address sw $fp, 4($sp) # push frame pointer sw $s0, 8($sp) # push saved registers sw $s1, 12($sp) # # INITIALIZE VARIABLES # move $fp, $sp # $fp = frame pointer move $s0, $a0 # $s0 = output file handle (0 for console) move $s1, $a1 # $s1 = opcode to interpret move $a0, $s0 la $a1, spim_code_instruction_push_prefix jal emit_string move $a0, $s0 li $a1, 0x0fffffff and $a1, $a1, $s1 jal emit_hex move $a0, $s0 la $a1, spim_code_instruction_push_suffix jal emit_string move $a0, $s0 la $a1, spim_code_push1 jal emit_string # # EPILOG CODE # move $sp, $fp # restore stack pointer lw $s1, 12($sp) # pop saved registers lw $s0, 8($sp) lw $fp, 4($sp) # pop frame pointer lw $ra, 0($sp) # pop return address addu $sp, $sp, 16 jr $ra # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # emit_hex # # arguments: # # $a0 = output file handle (0 for console) # $a1 = word to emit in hex # # returns: # # nothing # emit_hex: # # PROLOG CODE # subu $sp, $sp, 20 # emit_hex sw $ra, 0($sp) # push return address sw $fp, 4($sp) # push frame pointer # bytes 8-17 - string buffer # # INITIALIZE VARIABLES # move $fp, $sp # $fp = frame pointer move $t0, $a1 # $t0 = number to be output la $t1, 8($fp) # $t1 = output string buffer (on stack) li $t2, 32 # $t2 = bits to be output li $t3, 10 # $t3 = 10 (for comparisons) li $t5, 0xf0000000 # $t5 = mask for top 4 bits # # BUILD STRING # eh_loop: beqz $t2, eh_end and $t9, $t0, $t5 # Mask off top 4 bits srl $t9, $t9, 28 # Shift to bottom 4 bits bgeu $t9, $t3, eg_alpha # If >= 10, translate as A-F eg_digit: # convert nybble to 0-9 addi $t9, $t9, '0' j eh_cont eg_alpha: # convert nybble to A-F addi $t9, $t9, 55 # 55 = ASCII A - 10 eh_cont: sb $t9, ($t1) # store in string sll $t0, $t0, 4 # shift off top 4 bits addi $t1, $t1, 1 # increment string ptr addi $t2, $t2, -4 # decrement number of bits j eh_loop eh_end: sb $0, ($t1) # Add null to string # # EMIT STRING # # $a0 = output handle la $a1, 8($fp) # $a1 = address of ASCIIZ string jal emit_string # # EPILOG CODE # move $sp, $fp # restore stack pointer lw $fp, 4($sp) # pop frame pointer lw $ra, 0($sp) # pop return address addu $sp, $sp, 20 jr $ra # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # emit_string # # arguments: # # $a0 = output file handle (0 for console) # $a1 = address of ASCIIZ string # # returns: # # nothing # emit_string: # # PROLOG CODE # subu $sp, $sp, 8 # emit_string sw $ra, 0($sp) # push return address sw $fp, 4($sp) # push frame pointer # # INITIALIZE VARIABLES # move $fp, $sp # $fp = frame pointer move $t0, $a0 # $t0 = output file handle (0 for console) move $t1, $a1 # $t1 = address of ASCIIZ string # # CHECK FOR CONSOLE OUTPUT # beqz $t0, es_console # console output when handle = 0 es_file: # # OUTPUT TO FILE # # determine string length move $t2, $0 # $t2 = current length move $t3, $a1 # $t3 = current position es_len_loop: lb $t4, ($t3) # $t4 = character at $t3 beqz $t4, es_len_done # found null, exit loop with length in $t2 addi $t2, $t2, 1 addi $t3, $t3, 1 j es_len_loop es_len_done: move $a0, $t0 # $a0 = output file handle move $a1, $t1 # $a1 = output buffer move $a2, $t2 # $a2 = buffer length li $v0, WRITE syscall # DISREGARDING ERRORS HERE j es_exit es_console: # # OUTPUT TO CONSOLE # move $a0, $a1 # $a0 = string address li $v0, PRINT_STRING syscall es_exit: # # EPILOG CODE # move $sp, $fp # restore stack pointer lw $fp, 4($sp) # pop frame pointer lw $ra, 0($sp) # pop return address addu $sp, $sp, 8 jr $ra