所以,我在上次家庭作业中表现得很好,其中我还必须在 MIPS 汇编中将程序作为任务来实现。在一点帮助下我理解了它的概念和逻辑。但是,MIPS 对我来说仍然很新,我仍在学习并希望提高我使用 MIPS 进行编码的技能。
但这一次,我完全困惑了。任务的整个逻辑非常奇怪和令人困惑。我无法理解错误消息。
任务是实现一个罗马数字解码器,乍一听起来很简单。但我必须使用给定的寄存器,并且不允许我更改标签功能之上
roman.
.data
str_input: .asciiz "numeral: "
str_return_value: .asciiz "\nReturn value: "
romdigit_table: .word 0, 0, 0, 100, 500, 0, 0, 0, 0, 1, 0, 0, 50, 1000, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 10, 0, 0, 0, 0, 0, 0, 0
.text
.eqv SYS_PUTSTR 4
.eqv SYS_PUTCHAR 11
.eqv SYS_PUTINT 1
.eqv SYS_EXIT 10
main:
# roman numeral is output:
li $v0, SYS_PUTSTR
la $a0, str_input
syscall
li $v0, SYS_PUTSTR
la $a0, test_numeral
syscall
li $v0, SYS_PUTSTR
la $a0, str_return_value
syscall
move $v0, $zero
# calling the function roman:
la $a0, test_numeral
jal roman
# return value is output:
move $a0, $v0
li $v0, SYS_PUTINT
syscall
# end of program execution:
li $v0, SYS_EXIT
syscall
# help function: int romdigit(char digit);
romdigit:
move $v0, $zero
andi $t0, $a0, 0xE0
addi $t1, $zero, 0x40
beq $t0, $t1, _romdigit_not_null
addi $t1, $zero, 0x60
beq $t0, $t1, _romdigit_not_null
jr $ra
_romdigit_not_null:
andi $t0, $a0, 0x1F
sll $t0, $t0, 2
la $t1, romdigit_table
add $t1, $t1, $t0
lw $v0, 0($t1)
jr $ra
.data
test_numeral: .asciiz "DCCXLVI"
.text
roman:
li $t0, 0 # result
li $t1, 0 # Index in 'test_numeral'
roman_decoder:
la $a0, test_numeral # reseting $a0
add $a0, $t1, $a0 # adding the new index to the pointer $a0
lb $t2, 0($a0) # first number in 'test_numeral'
lb $t3, 1($a0) # second number in 'test_numeral'
beqz $t3, exit # exit if zero is reached
lb $a0, 0($a0) # given help function 'romdigit' needs $a0 as the argument
bgt $t3, $t2, subtract # if $t3 > $t2 subtract $t2 from result
j add
subtract: # subtract $t2 from the result
jal romdigit # calling 'romdigit'
sub $t0, $t0, $v0 # in $v0 is the encrypted decimal number
addi $t1, $t1, 1
j roman_decoder
add: # add $t2 to the result
jal romdigit # calling 'romdigit'
add $t0, $t0, $v0 # in $v0 is the encrypted decimal number
addi $t1, $t1, 1
j roman_decoder
exit:
jr $ra
我的代码背后的逻辑很简单。迭代
test_numeral
直到 \0
;读取罗马数字并使用 romdigit
进行解码;将 $v0
中存储的值添加到结果寄存器。
我仍然很困惑,我必须使用
$a0
作为指向 test_numeral
的指针,并作为要在 romdigit
中使用的当前罗马数字的持有者。
我认为这段代码理论上可以工作,但我无法让它正常运行。我真的很绝望。
我的意思是有很多方法可以真正解决这个问题。这是我能想到的最简单的一个。但我总是收到“地址超出范围”错误,我不明白为什么......
我认为为索引
$t1
设置一个计数器是有意义的,每次读取罗马数字时索引都会增加 1,并且在我在 romdigit 中使用 $a0
后,将 $t1
添加回$a0
获取 test_numeral
中的新索引。但这效果不太好,我不知道如何以其他方式做到这一点。
我将不胜感激对此的任何提示。先谢谢你们了!
我很忙,所以我无法再真正编写代码了。
但我想我现在有一个工作代码了。唯一的问题是它不会停止:
.data
test_numeral: .asciiz "DCCXLVI"
.text
roman:
move $t3, $a0
li $t2, 0
li $t4, 0
roman_decoder:
move $t4, $v0
lb $a0, 0($t3)
beqz $a0, exit
jal romdigit
bgt $v0, $t4, subtract
add $t2, $t2, $v0
addi $t3, $t3, 1
j roman_decoder
subtract:
sub $t2, $t2, $t4
sub $t2, $t2, $t4
add $t2, $t2, $v0
addi $t3, $t3, 1
j roman_decoder
exit:
move $v0, $t2
jr $ra
当
$a0
为零时,代码跳转到 exit
。将 $t2
移动到 $v0
中并且应该结束,因为我说的是 jr $ra
,所以它应该跳回 main 来结束程序,对吧?我做错了什么?
提前非常感谢!
问题可能是 romdigit 函数本身使用 jr 回调在 roman_decoder 中继续。在此过程中,它还会更改 $ra 寄存器的值,因此 exit 函数会再次调用 romand_decoder 而不是 main 函数。尝试在调用 romdigit 之前将 $ra 的值存储在额外的寄存器中,并在退出函数中在使用回调之前将值加载回 $ra 寄存器