MIPS程序集从一个非常具体的描述中编写函数

时间:2017-02-23 17:37:18

标签: function assembly mips

我有一个关于如何编写一个名为tim2string的函数的具体描述,我已经编写了这个函数,但我不确定我是否按照它在描述中的说法进行操作。我试图在MARS上运行我的代码,我得到了这个ERROR。注意在代码的末尾添加了tim2string

timetemplate.asm line 99: Runtime exception at 0x00400118: address out of range 0x00005958

功能说明如下

名称:子程序必须被称为time2string。 参数(二):寄存器$ a0包含内存中某个区域的地址,适合大小 time2string的输出。寄存器$ a1的16个最低有效位包含有组织的时间信息 作为四个NBCD编码的数字,每个4位。寄存器$ a1中的所有其他位可以具有任何值 被忽略了。

示例:寄存器$ a0可以包含地址0x100100017,寄存器$ a1可以包含值0x00001653。 返回值:无。 必要的行动:

必须将以下六个字符序列写入内存区域 寄存器$ a0指出。

1)两个ASCII编码的数字显示分钟数,根据另外两个 输入参数的重要NBCD编码数字。示例:'1','6'(ASCII 0x31,0x36):

2)冒号字符(ASCII:,代码0x3A)。

3)两个ASCII编码的数字显示秒数,根据两个少 输入参数的重要NBCD编码数字。示例:'5','3'(ASCII 0x35,0x33)。 4.空字节(ASCII NUL,代码0x00)。 注意:必须使用函数hexasc将每个NBCD编码的数字转换为相应的数字 ASCII码。使用sb指令将每个字节存储在目标位置。宏PUSH和POP 用于保存和恢复寄存器。

  # timetemplate.asm
  # Written 2015 by F Lundevall
  # Copyright abandonded - this file is in the public domain.
.macro  PUSH (%reg)
    addi    $sp,$sp,-4
    sw  %reg,0($sp)
.end_macro

.macro  POP (%reg)
    lw  %reg,0($sp)
    addi    $sp,$sp,4
.end_macro

    .data
    .align 2
mytime: .word 0x5957
timstr: .ascii "text more text lots of text\0"
    .text
main:
    # print timstr
    la  $a0,timstr
    li  $v0,4
    syscall
    nop
    # wait a little
    li  $a0,2
    jal delay
    nop
    # call tick
    la  $a0,mytime
    jal tick
    nop
    # call your function time2string
    la  $a0,timstr
    la  $t0,mytime
    lw  $a1,0($t0) #load the adress contained in $t0 into $a1
    jal time2string
    nop
    # print a newline
    li  $a0,10
    li  $v0,11
    syscall
    nop
    # go back and do it all again
    j   main
    nop
# tick: update time pointed to by $a0
tick:   lw  $t0,0($a0)  # get time
    addiu   $t0,$t0,1      # increase
    andi    $t1,$t0,0xf # check lowest digit
    sltiu   $t2,$t1,0xa # if digit < a, okay
    bnez    $t2,tiend
    nop
    addiu   $t0,$t0,0x6     # adjust lowest digit
    andi    $t1,$t0,0xf0    # check next digit
    sltiu   $t2,$t1,0x60    # if digit < 6, okay
    bnez    $t2,tiend
    nop
    addiu   $t0,$t0,0xa0    # adjust digit
    andi    $t1,$t0,0xf00   # check minute digit
    sltiu   $t2,$t1,0xa00   # if digit < a, okay
    bnez    $t2,tiend
    nop
    addiu   $t0,$t0,0x600      # adjust digit
    andi    $t1,$t0,0xf000  # check last digit
    sltiu   $t2,$t1,0x6000  # if digit < 6, okay
    bnez    $t2,tiend
    nop
    addiu   $t0,$t0,0xa000  # adjust last digit
tiend:  sw  $t0,0($a0)      # save updated result
    jr  $ra                 # return
    nop

  # you can write your code for subroutine "hexasc" and  below this line
  #
hexasc:  
    andi    $a0,$a0,0xf       #only 4 least significant bits ignore other bits  
    addi    $v0,$zero,0x30    #$v0 = 0x30 ('0')
    addi    $t0,$zero,0x9     #t0 = 0x9

    ble     $a0,$t0,L1        #branch if a0 <= 0x9
    nop
    addi    $v0,$v0,0x7       #v0 = v0 +0x7

   L1:
    add     $v0,$a0,$v0       #v0 = V0 +a0
    jr      $ra
    nop
 delay:
    jr      $ra
    nop

 time2string:
    PUSH    ($t2)           
    PUSH    ($t0)
    PUSH    ($a1)

    lb      $t0, 0($a1)      #load one byte from a1     "LINE 99" ERROR
    andi    $t2, $t0,0xf     #check the 4 lowest bits ignore other
    jal     hexasc           # call hexasc
    nop
    sb      $t0, 0($a1)      #stor back that byte in a1


    lb      $t0, 1($a1)      # load the next byte
    andi    $t2, $t0,0xf0
    jal     hexasc
    nop
    sb      $t0, 1($a1)


    lb  $t0, 2($a1)
    andi    $t2, $t0,0xf00
    jal hexasc
    nop
    sb  $t0, 2($a1)


    lb  $t0, 3($a1)
    andi    $t2, $t0,0xf000
    jal hexasc
    nop
    sb  $t0, 3($a1)


    POP ($a1)
    POP ($t0)
    POP ($t2)


    jr  $ra
    nop 

更新1.0

到目前为止我写了time2string函数已经取得了一些进展 而且我还需要一些帮助。 我单步执行我的代码,它正常工作,直到这一行sb $v0, 0($t0) #stor that 4 bits in that location that a0 points to

我收到此错误timetemplate.asm line 115: Runtime exception at 0x00400158: address out of range 0x00000009

这是更新后的代码

time2string:
PUSH    ($t0)           
PUSH    ($t1)
PUSH    ($t2)
PUSH    ($t3)
PUSH    ($t4)
PUSH    ($t5)
PUSH    ($ra)           #nested subroutine must store $ra too

add     $t0,$0,$a0      #contaisn the adress of string (timstr)
add     $t1,$0,$a1      #contains the time-info(0x5957)

andi    $t2,$t1,0xf000      #check the 4 most signifaicant bits ignore other bits
srl     $a0,$t2,12      #shift the MSB to LSB position (hexasc take only 4 bits in the LSB position)
jal     hexasc      # call hexasc
nop     
sb      $v0, 0($t0)     #stor that 4 bits in that location that a0 points to

andi    $t3,$t1,0x0f00  #mask to get those 4 bits you and ignore other bits
srl     $a0,$t3,8       #shift those bits to the LSB position(0x000f)
jal     hexasc      
nop
sb      $v0,1($t0)      

li      t5,0x3A
sb      $t5,2($t0)


andi    $t4,$t1,0x00f0
srl     $a0,$t4,4
jal     hexasc
nop
sb      $v0,3($t0)


move    $a0,$t1
jal     hexasc
nop
sb      $v0, 4($t0)


POP ($ra)
POP ($t5)
POP ($t4)
POP ($t3)
POP ($t2)
POP ($t1)   
POP ($t0)

jr  $ra
nop 

1 个答案:

答案 0 :(得分:1)

    lb      $t0, 0($a1)      #load one byte from a1

这将从地址a1的内存中加载一个字节。

a1不包含有效地址,它包含BCD时间值,如0x5958,即时间59:58。

因此您不需要从内存加载时间值,您已经加载了a1中的值。你必须分别挑选每组4位(从低16位),这是4位数字的编码。

哦,这个:

  

我试图在MARS上运行我的代码

那不是,人们如何在大会上编程。你没有运行你的代码。您逐步调试调试器中的单个指令,在每条指令之后进行验证,它确实只更改了应该更改的寄存器/内存,并且只改变了应该如何更改它的方式。

(这就是为什么你需要第一个描述算法的英文评论,因为否则你无法推断指令是否做了你想做的......当然它总会做,做什么,根据CPU文档,当你的指令本身无法正常执行时,你几乎不会遇到这种情况(虽然技术上可行,当一些电子“跳过”所谓的路径的“墙壁”时,通常在被一些质子击中之后从X射线/等...也许如果你能活得足够长,它可能会发生在你身边一两次......很可能你永远不会注意到,因为SW可能会幸存下来,或像往常一样崩溃来自代码错误))

还要确保你避免大脑在你身上耍花招,采取快捷方式来节省它的努力,所以不用你的大脑读取屏幕上的内容,它会试着告诉你,你想要写什么并看到那里

就像在代码sb $t0,0($a1)而不是sb $t0,0($a0)中写一样,如果您在编写代码后不久会尝试重新阅读来源,那么您将阅读sb $t0,0($a0),除非您专注非常努力,确保你的大脑不会欺骗你。

同样适用于调试和检查寄存器中的结果值等。如果您在1中期望值为t1,并且偶然在t2中结束,则可能很容易错过了1确实在t2而不是在t1中发生变化这一事实,因为您的大脑主要关心结果是1。等。

这很棘手。这就是为什么人们喜欢汇编,并编写几乎所有内容的原因。