在 MIPS 中编写子程序,将整数 0 到 15 转换为 ASCII 字符 '0' 到 'F'

Posted

技术标签:

【中文标题】在 MIPS 中编写子程序,将整数 0 到 15 转换为 ASCII 字符 \'0\' 到 \'F\'【英文标题】:Write subroutine in MIPS that convert integer 0 through 15 into ASCII character '0' through 'F'在 MIPS 中编写子程序,将整数 0 到 15 转换为 ASCII 字符 '0' 到 'F' 【发布时间】:2017-02-15 14:53:17 【问题描述】:

编写一个小子程序,将 0 到 15 范围内的数字转换为 可打印的 ASCII 编码字符:“0”到“9”,或“A”到“F”,具体取决于数字。 对于不在 0 到 15 范围内的数字,一些位将被忽略。

名称:子程序必须被称为 hexasc 。 参数:一,在寄存器 $a0 中。 4 个最低有效位指定一个从 0 到 15 的数字。 寄存器 $a0 中的所有其他位可以具有任何值,并且必须被忽略。 返回值:寄存器 $v0 中的 7 个最低有效位必须是如下所述的 ASCII 码。 当您的函数返回时,所有其他位必须为零。 所需操作:该函数必须将输入值 0 到 9 转换为数字的 ASCII 代码 分别是“0”到“9”。输入值 10 到 15 必须转换为 ASCII 码 分别是字母“A”到“F”。

.text

 main:
      li    $a0,0       # change this to test different values

      jal   hexasc      # call hexasc
      nop               # delay slot filler (just in case)  

      move  $a0,$v0     # copy return value to argument register

      li    $v0,11      # syscall with v0 = 11 will print out
      syscall           # one byte from a0 to the Run I/O window

stop:   j   stop        # stop after one run
       nop              # delay slot filler (just in case)

我在这里写了我的hexasc 子例程,出于某种我不明白的原因,它不起作用。我无法弄清楚我在哪一部分有错误,也许我没有按照上面的规范中所说的那样做。 任何帮助将不胜感激,在此先感谢。

hexasc:
        addi    $sp,$sp,-4      #make space on the stack
        sw      $a0,0($sp)      #store $a0 on the stack
        li      $t0,0x30        #$t0 = 0x30 ('0' in ascii)
        andi    $a0,$a0,0xf     #only 4 least significant bits is 
                                #needed ignore other bits
loop:       
        add     $a0,$a0,$t0     #$a0 i will think why i did this
        addi    $t0,$t0,1       #increment $t0 by 1
        beq     $t0,0x39,loop2  # if $t0 = 0x39 (9 in ascii)
        j       loop


        li      $t1,0x41       # $t1 = 0x41 ( A in ascii)
loop2:  
        andi    $a0,$a0,0xf    # only 4 LSB ignore other bits
        add     $a0,$a0,$t1    # ???? i will think about this
        beq     $t1,0x46,done  # if $t1 = 0x46 (F in ascii)
        j       loop2

done:           
        add     $v0,$a0,$a0    # return  $a0 in $v0 suspicious ...?
        lw      $a0,0($sp)     # restore the $a0 
        addi    $sp,$sp,4      # put back the stack
        jr      $ra

【问题讨论】:

在模拟器中在hexasc上设置断点,然后单步执行函数,找出产生错误结果的原因。 为什么在返回之前恢复a0? (并将其存储在开头)。 IIRC MIPS 调用约定,子程序可以修改参数值。加上a0 应该在末尾包含返回值,所以将其恢复到原始值有点.. 不幸...无论如何肯定尝试调试器(我没有阅读例程正文,只是制作的推送/弹出序列我轻笑)。 (现在我瞥见了正文……您可能只想删除它并在纸上写下所有 0 - 15 个值,然后在它们旁边写下所有 ASCII 目标值(48 '0'49 '1'、. ..) 盯着他们看 5 分钟 你能通过包含代码 cmets 来解释你的算法吗?否则我们无法弄清楚问题是你做错了事,还是你试图做正确的事但失败了。第一个函数注释很好,但第二个函数只是一堵代码。 是的,请在图表的一侧显示 0 到 15,在另一侧显示 ascii 值。然后解释你的算法如何连接这些点。 哦..实际上我错了..返回值在v0..你恢复a0无害...所以..你可以看,错误地读取代码很容易......使用调试器更好。 ;)(我仍然认为修改a0 是可以的,调用者不应该期望参数会保持原样吗?) 【参考方案1】:

这两个帖子中有一个小错误值得一提,li $v0,0x41 应该是li $v0,0x7。这是由于您的规范,10 的输入值应以 ASCII 格式打印出字符A,但如果您有li $v0,0x41,则输出将为K 而不是A 的输入值@987654328 @。 这是hexasc 的另一个版本,它会打印出你的规范中所说的那些。

hexasc:
      andi  $a0,$a0,0x0f
      addi  $v0,$zero,0x30
      addi  $t0,$zero,0x9

      ble   $a0,$t0,L1
      nop
      addi  $v0,$v0,0x7

L1:
      add   $v0,$a0,$v0
      jr    $ra
nop

【讨论】:

【参考方案2】:

几个问题...

您在十进制测试期间破坏了 $a0 值,因此十六进制部分的值错误。

你的跳跃是[无限]循环。他们应该是done:

我创建了您的代码的两个版本。一个带有注释,一个带有更正的代码[请原谅无缘无故的样式清理]。

这是带注释的版本:

hexasc:
# NOTE/BUG: stack save/restore of $a0 is not needed due to MIPS ABI
    addi    $sp,$sp,-4              # make space on the stack
    sw      $a0,0($sp)              # store $a0 on the stack
    li      $t0,0x30                # $t0 = 0x30 ('0' in ascii)
    andi    $a0,$a0,0xf             # only 4 least significant bits is
                                    # needed ignore other bits

# NOTE/BUG: altering $a0 further destroys the value for the hex test
loop:
    add     $a0,$a0,$t0             # $a0 i will think why i did this
    addi    $t0,$t0,1               # increment $t0 by 1

# NOTE/BUG: beq is wrong -- we want bgt
# NOTE/BUG: the range test for decimal should be 0x09 and _not_ 0x39
    beq     $t0,0x39,loop2          # if $t0 = 0x39 (9 in ascii)

# NOTE/BUG: looping is wrong -- this should be 'j done'
    j       loop

    li      $t1,0x41                # $t1 = 0x41 ( A in ascii)

# NOTE/BUG: $a0 is now wrong because of add above
loop2:
    andi    $a0,$a0,0xf             # only 4 LSB ignore other bits
    add     $a0,$a0,$t1             # ???? i will think about this

# NOTE/BUG: no range check needed as all values are in range
    beq     $t1,0x46,done           # if $t1 = 0x46 (F in ascii)

# NOTE/BUG: no looping required
    j       loop2

done:
    add     $v0,$a0,$a0             # return  $a0 in $v0 suspicious ...?
    lw      $a0,0($sp)              # restore the $a0
    addi    $sp,$sp,4               # put back the stack
    jr      $ra

这是更正的版本:

hexasc:
    andi    $a0,$a0,0xf             # only 4 least significant bits is needed

    # check for decimal
    li      $v0,0x30                # set 0x30 ('0' in ascii)
    ble     $a0,0x09,hexasc_done    # value in range 0x0-0x9? if yes, fly

    li      $v0,0x41                # set 0x41 ('A' in ascii)

hexasc_done:
    add     $v0,$v0,$a0             # convert value to ascii
    jr      $ra

【讨论】:

感谢您的回答,这对我有帮助。 不客气。 asm 一开始可能会让人望而生畏,但它会变得更容易。顺便说一句,由于您对 SO 比较陌生,因此习惯上以物质方式对一个好的答案表示感谢:通过投票/接受答案。见:***.com/help/someone-answers

以上是关于在 MIPS 中编写子程序,将整数 0 到 15 转换为 ASCII 字符 '0' 到 'F'的主要内容,如果未能解决你的问题,请参考以下文章

在MIPS中存储用户输入

学习MIPS汇编:读取文本并写入文件

MIPS汇编程序设计——四则运算计算器

在 mips 汇编器中编写棋盘格的 bmp 文件

MIPS 到 C 的翻译

java 编写一个程序,提示用户输入0~15之间的一个整数,显示其对应的十六进制数