将以下 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

至少有两个问题:

  1. 退出时跳转到done
    这也对应于退出 while 循环,而不是 C 伪代码中的 for 在退出时对 while 进行另一次迭代。
  2. 寄存器 $s0 从未重新初始化。
    计数器 iwhile 的每次迭代中初始化 - 您的实现相反,在开始时执行一次。

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:
    

    这应该更容易翻译成汇编。