MIPS计算器

时间:2014-03-03 20:21:39

标签: mips

我正在尝试完成这个MIPS计算器,超级基本,我的第一个mips程序。它不必处理溢出或类似的东西,只需处理小的正数。

我没有检查我的算法是否有乘法和除法,因为我只是想加入工作。

我不能为我的生活找出为什么int不会读入而且当我调用lb $ a0时,我得到的内存超出界限,op显示运算符输出并且不明白为什么

我是新手,所以任何事情都可能有所帮助。提前谢谢。

        .data
                        # const string for welcome
welc:       .asciiz "Welcome to SPIM Calculator 1.0!\n" 
p_int:      .asciiz "\nPlease give an integer: "
p_op:       .asciiz "\nPlease give an operator: "
i_err:      .asciiz "\nInput Incorrect, bad operator!\n"
again_str:  .asciiz "Another calculation? (y/n)"
rmndr:      .asciiz " r: "
new_line:   .asciiz "\n"

int1:   .word 1         # space to hold int 1
int2:   .word 1         # space to hold int 2
raw_in: .space 1        # space to hold raw input
op:     .space 1        # space to hold operator char
a_char: .space 1        # space to hold again char

out:    .word 1         # space to hold output
remain: .word 1         # space to hold remainder

#operator constants
c_plus: .ascii "+"      # const for +
c_min:  .asciiz "-"     # const for -
c_mult: .asciiz "*"     # const for *
c_divi: .asciiz "/"     # const for /
c_eq:   .asciiz "="     # const for =
c_no:   .asciiz "n"     # const for n

        .text
        .globl main
main:   li $v0, 4               # syscall 4, print string
        la $a0, welc            # give argument: string
        syscall                 # actually print string

calc:   la $t6, remain          # load remainder variable
        move $t6, $zero         # store 0 in remainder (reset)

        li $v0, 4               # syscall 4, print string
        la $a0, p_int           # give argument: string
        syscall                 # actually print string

        li $v0, 5               # tell syscall we want to read int 1
        syscall                 # actually read in int 1
        la $s1, int1            # load int1 into $s1
        move $s1, $v0           # copy the integer from $v0 to int1

        li $v0, 4               # syscall 4, print string
        la $a0, p_int           # give argument: string
        syscall                 # actually print string

        li $v0, 5               # tell syscall we want to read int 2
        syscall                 # actually read in int 2
        la $s2, int2            # give $s2 the address to hold int 2
        move $s2, $v0           # copy the integer from $v0 to $s2

        li $v0, 4               # syscall 4, print string
        la $a0, p_op            # give argument: string
        syscall                 # actually print string

        li $v0, 8               # tell syscall we want to read operator
        la $a0, op              # give $a0 the address to hold the operator
        syscall                 # actually read in operator

        lb $t0, op              # load the first byte of op
        li $t1, '+'             # load const for plus
        li $t2, '-'             # load const for minus
        li $t3, '*'             # load const for multiplying
        li $t4, '/'             # load const for dividing

        la $s0, out             # load out to $s0

        beq $t0, $t1, plus      # we're adding
        beq $t0, $t2, minus     # we're subtracting
        beq $t0, $t3, multi     # we're multiplying
        beq $t0, $t4, divi      # we're dividing
        # else
        j error                 # incorrect input

plus:   add $s0, $s1, $s2       # add our ints, store in $t0
        j print

minus:  sub $s0, $s1, $s2       # subtract our ints, store in $t0
        j print

multi:  slt $t1, $t2, $s2       # if our counter is less than int2, set $t1 to 1
        beq $t1, $zero, print   # if we've reached int2, we're done
        add $s0, $s1, $s1       # add int1 and int1, store in out
        j multi                 # loop

divi:   la $t0 remain           # load remainder into $t0
        move $t0, $s1           # set remainder to dividend
        add $s0, $zero, $zero   # set out to 0, just in case
loop:   slt $t1, $t0, $s2       # if remainder is less than divisor, set 1
        beq $t1, $zero, print   # if we're done branch to done
        sub $t0, $t0, $s2       # sub divisor from remainder, store in remainder
        addi $s0, $s0, 1        # increment quotient by 1
        j loop                  # loop

print:  li $v0, 1               # tell syscall we want to print int
        la $a0, int1            # give syscall int1 to print
        syscall                 # actually print int
        li $v0, 4               # tell syscall we want to print string
        lb $a0, op              # tell syscall we want to print operator
        syscall                 # actually print string
        li $v0, 1               # tell syscall we want to print int
        la $a0, int2            # give syscall int2 to print
        syscall                 # actually print int
        li $v0, 4               # tell syscall we want to print string
        la $a0, c_eq            # tell syscall we want to print operator
        syscall                 # actually print string
        li $v0, 1               # tell syscall we want to print integer
        la $a0, out             # give syscall our output
        syscall                 # actually print int
        la $t0, remain          # load remainder
        beq $t0, $zero, again   # if we have no remainder, finish printing
        li $v0, 4               # tell syscall we want to print string
        la $a0, rmndr           # tell syscall we want to print remainder string
        syscall                 # print "r: "
        li $v0, 1               # tell syscall we want to print int
        la $a0, remain          # give syscall our remainder to print
        syscall                 # print remainder

again:  li $v0, 4               # tell syscall we want to print string
        la $a0, new_line        # tell syscall to print new line
        syscall
        la $a0, again_str       # load prompt for again string for syscall
        syscall
        li $v0, 8               # tell syscall we want to read string
        la $a0, a_char          # tell syscall to put it in $a0
        syscall
        lb $t0, a_char
        li $t1, 'n'             # get n char so we can compare
        beq $t0, $t1, exit      # if we are done, exit
        #else loop
        j calc                  # jump to beginning



error:  li $v0, 4               # tell syscall we want to print string
        la $a0, i_err           # give syscall what to print
        syscall                 # actually print
        j again                 # go to prompt for retry

exit:   li $v0, 10              # exit code
        syscall                 #exit!

screenshot

1 个答案:

答案 0 :(得分:3)

问题是您没有使用适当的指令来处理内存。

  1. 您应使用move(商店字)代替sw。此代码不会将int存储到int1

    la $s1, int1            # load int1 into $s1
    move $s1, $v0           # copy the integer from $v0 to int1
    

    相反,你应该写:

    la $s1, int1            # load address of int1 into $s1
    sw $v0, 0($s1)          # copy the integer from $v0 to int1
    
  2. 与存储一样,从内存加载需要两条指令:

    la $s1, p_op              # or whatever register you choose to use
    lb $a0, 0($s1)          # load byte from the address stored in $s0 (in index 0)
    

    如果您要将p_op的地址加载到$a0,则应使用la $a0, p_op,而不是lb