将以下 C 函数重写为具有相同行为的汇编语言子例程
Rewrite the following C function as an assembly-language subroutine with the same behavior
void delay( int ms ) /* Wait a number of milliseconds,
specified by the parameter value. */
{
int i;
while( ms > 0 )
{
ms = ms – 1;
/* Executing the following for loop should take 1 ms */
for( i = 0; i < 4711; i = i + 1 )
/* The constant 4711 must be easy to change! */
{
/* Do nothing. */
}
}
}
我已经将其转换如下,这个子例程是一个更大的子例程的一部分。
delay:
PUSH ($s0)
PUSH ($ra)
addi $s0,[=11=],0 #i = 0
addi $t1,[=11=],4711
move $t0,$a0 #move the argument to t0
while:
bgt $t0,$s0,done #branch to done if ms > 0
addi $t0,$t0,-1 #decrement ms by 1
for:
beq $s0,$t1,done
addi $s0,$s0,1
j for
j while
done:
POP ($ra)
POP ($s0)
jr $ra
nop
使用 MARS 测试您的程序。调整for循环中的常量得到1000ms的延迟
调用delay时参数值为1000,调用delay时延迟3000ms
参数值为 3000.
Q1:所以我不确定我是否正确转换。
问题 2:如何调整该常量以获得该延迟量。
任何建议、提示都会提前great.Thanks。
我没有考虑所有关于空可观察行为的大惊小怪,因为我认为这是一个包含错误命令文本的汇编练习。
所以从今以后,我假装代码不是 C,而是一种称为 C 伪代码 的新语言,其语法类似于 C 的语法,并且每个语句都有可观察到的语义效果。
汇编代码不正确。
我不会纠正你的错误或编写任何代码,我只会指出 一些 错误。
执行for
# $s0 = i
# $t1 = 4711
for:
beq $s0,$t1,done
addi $s0,$s0,1
j for
至少有两个问题:
- 退出时跳转到
done
。
这也对应于退出 while
循环,而不是 C 伪代码中的 for
在退出时对 while
进行另一次迭代。
- 寄存器
$s0
从未重新初始化。
计数器 i
在 while
的每次迭代中初始化 - 您的实现相反,在开始时执行一次。
while
条件的执行是
# $s0 = i
# $t0 = ms
bgt $t0, $s0, done #branch to done if ms > 0
您可以在注释的帮助下亲眼看到它对应于 ms > i
作为您的代码。
在 MIPS 中,您有一个始终为零的寄存器。
一些小技巧:
您可以避免使用任何 $s
寄存器。
有足够的 $t
寄存器可用 - 保存 $s
立即使 reader 想到内部调用,而代码中有 none。
用更简单的形式编写 C 伪代码。
您可以将 for
重写为
i = 0;
for_begin:
if (i >= 4711)
goto for_end
/* FOR BODY */
i = i + 1;
goto for_begin
for_end:
这应该更容易翻译成汇编。
void delay( int ms ) /* Wait a number of milliseconds,
specified by the parameter value. */
{
int i;
while( ms > 0 )
{
ms = ms – 1;
/* Executing the following for loop should take 1 ms */
for( i = 0; i < 4711; i = i + 1 )
/* The constant 4711 must be easy to change! */
{
/* Do nothing. */
}
}
}
我已经将其转换如下,这个子例程是一个更大的子例程的一部分。
delay:
PUSH ($s0)
PUSH ($ra)
addi $s0,[=11=],0 #i = 0
addi $t1,[=11=],4711
move $t0,$a0 #move the argument to t0
while:
bgt $t0,$s0,done #branch to done if ms > 0
addi $t0,$t0,-1 #decrement ms by 1
for:
beq $s0,$t1,done
addi $s0,$s0,1
j for
j while
done:
POP ($ra)
POP ($s0)
jr $ra
nop
使用 MARS 测试您的程序。调整for循环中的常量得到1000ms的延迟 调用delay时参数值为1000,调用delay时延迟3000ms 参数值为 3000.
Q1:所以我不确定我是否正确转换。
问题 2:如何调整该常量以获得该延迟量。
任何建议、提示都会提前great.Thanks。
我没有考虑所有关于空可观察行为的大惊小怪,因为我认为这是一个包含错误命令文本的汇编练习。
所以从今以后,我假装代码不是 C,而是一种称为 C 伪代码 的新语言,其语法类似于 C 的语法,并且每个语句都有可观察到的语义效果。
汇编代码不正确。
我不会纠正你的错误或编写任何代码,我只会指出 一些 错误。
执行for
# $s0 = i
# $t1 = 4711
for:
beq $s0,$t1,done
addi $s0,$s0,1
j for
至少有两个问题:
- 退出时跳转到
done
。
这也对应于退出while
循环,而不是 C 伪代码中的for
在退出时对while
进行另一次迭代。 - 寄存器
$s0
从未重新初始化。
计数器i
在while
的每次迭代中初始化 - 您的实现相反,在开始时执行一次。
while
条件的执行是
# $s0 = i
# $t0 = ms
bgt $t0, $s0, done #branch to done if ms > 0
您可以在注释的帮助下亲眼看到它对应于 ms > i
作为您的代码。
在 MIPS 中,您有一个始终为零的寄存器。
一些小技巧:
您可以避免使用任何
$s
寄存器。
有足够的$t
寄存器可用 - 保存$s
立即使 reader 想到内部调用,而代码中有 none。用更简单的形式编写 C 伪代码。
您可以将for
重写为i = 0; for_begin: if (i >= 4711) goto for_end /* FOR BODY */ i = i + 1; goto for_begin for_end:
这应该更容易翻译成汇编。