我想写一个程序,使用俄罗斯农民乘法与mips,但我面临一些问题
/ A method to multiply two numbers using Russian Peasant method
unsigned int russianPeasant(unsigned int a, unsigned int b)
{
int res = 0; // initialize result
// While second number doesn't become 1
while (b > 0)
{
// If second number becomes odd, add the first number to result
if (b & 1)
res = res + a;
// Double the first number and halve the second number
a = a << 1;
b = b >> 1;
}
return res;
}
我用MARS环境将其翻译成mips
.data
msg1: .asciiz "give your first number"
msg2: .asciiz "give the second number"
.text
#a = $t1
#b = $t2
li $t3,0 #p
li $s1,1
li $s2,2
#display msg1
li $v0,4
la $a0,msg1
syscall
#read first number
li $v0,5
syscall
move $t1,$v0
#display msg2
li $v0,4
la $a0,msg2
syscall
#read second number
li $v0,5
syscall
move $t2,$v0
WHILE:
bgt $t2,$zero,DO
move $a0,$t3
li $v0,1
syscall
li $v0,10
syscall
DO:
div $t2,$s2
mfhi $s0 #r $s0 = $t2 / $s2
beq $s0,$s1,INC # IF b MOD 2 = 1 I jump to INC
#a = 2xa
mul $t1,$t1,$s2
div $t2,$s2
mflo $t2 # b = $t2/$s2
j WHILE
# i = i+ 1
INC:
add $t3,$t3,$t1
jr $ra
请,有人可以帮帮我吗?
修复“错误:无效的程序计数器值:0x00000000”
我搜索了如何解决它,但我有一个问题与$ ra
如何在$ ra中保存退货地址?
答案 0 :(得分:1)
jr $ra
将跳转到寄存器$ra
中存储的地址,该地址未由您的代码设置,因此它仍然为零(在运行代码之前来自MARS的初始寄存器值)。然后,CPU将跳转到地址零,这是失败,并报告。
使用jr $ra
来&#34;返回&#34;从某些代码中,您必须首先使用jal
指令(或修改$ra
内容的其他指令)来设置$ra
。此外,当您想要嵌套多个jal
&#34;子程序调用&#34;时,您必须存储/恢复外部调用的$ra
,以便不会丢失下一个嵌套{{1}的值。 1}}。
以下代码是使用配对jal
+ jal
进行&#34;子程序&#34; -like调用的示例,以及示例在汇编时这种算法的实现是多么简单(因为实际上C源代码更像C中的汇编,所以你的经验不足让你采用了一种非常复杂和复杂的方法,可以用原始C源几乎1:1的方式实现汇编:
jr $ra
子程序本身,可以在.text
main: # just minimal "main" to verify the code works
# read two integers as input
li $v0,5
syscall
move $a0, $v0 # $a0 = a
li $v0,5
syscall
move $a1, $v0 # $a1 = b
# call the russianPeasant subroutine
jal russianPeasant # $v0 = a * b
nop
# output result
move $a0, $v0
li $v0, 1
syscall
# terminate
li $v0, 10
syscall
和a0
中使用参数调用,并返回a1
的结果。
v0
代码是故意在每个分支# input: $a0 = a, $a1 = b
# output: $v0 = a * b
russianPeasant:
li $v0, 0 # res = 0
beq $a1, $zero, russianPeasant_b_zero
nop # neutralize "Delayed branching" setting ("nop" works with both ON/OFF setting)
russianPeasant_while_b:
andi $at, $a1, 1 # test if b is odd, for even b skip the res = res + a
beq $at, $zero, russianPeasant_b_even
nop # but such neutralization comes with performance cost of course
add $v0, $v0, $a0 # res = res + a
russianPeasant_b_even:
sll $a0, $a0, 1 # a = a << 1
srl $a1, $a1, 1 # b = b >> 1
bne $a1, $zero, russianPeasant_while_b # repeat when (b != 0)
nop # on real MIPS production code the instructions are reordered to avoid useless nop
russianPeasant_b_zero:
jr $ra # return res
nop
指令之后放置,以使其在延迟分支设置为ON或OFF时起作用。
尝试使用带有指令描述的MARS帮助(F1)来弄清楚它是如何工作的,还可以使用调试器的单步功能来注意操作中的代码,一次一条指令,观察所有寄存器值和代码流。
在具有延迟分支的真实MIPS CPU上,代码可以像这样进行优化(您可以在MARS设置中切换&#34;延迟分支&#34; ON,使其模拟真正的MIPS CPU,这种行为有点令人困惑..来自您的原始资源看起来您正在学习MIPS程序集而没有延迟分支,这对于刚刚开始汇编的人来说当然是合理的方法,但这并不是真正的MIPS CPU工作方式):
nop