MIPS 程序集根据非常具体的描述编写函数
MIPS assembly writing a function from a very specific description
我有关于如何编写一个名为 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。
Return 值:None。
所需操作:
必须将以下六个字符序列写入内存中的区域
由寄存器 $a0 指向。
1) 显示分钟数的两个 ASCII 编码数字,根据另外两个
输入参数的重要 NBCD 编码数字。示例:“1”、“6”(ASCII 0x31、0x36):
2) 一个冒号字符(ASCII : , 代码 0x3A)。
3)两个ASCII编码的数字显示秒数,根据少两个
输入参数的重要 NBCD 编码数字。示例:“5”、“3”(ASCII 0x35、0x33)。
4. 空字节(ASCII NUL,代码 0x00)。
Notes:You 必须使用函数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[=11=]"
.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,[=12=],$a0 #contaisn the adress of string (timstr)
add $t1,[=12=],$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
lb $t0, 0($a1) #load one byte from a1
这将从地址 a1
的内存中加载一个字节。
但a1
不包含有效地址,它包含BCD时间值,如0x5958
,表示时间59:58。
因此您不需要从内存中加载时间值,您已经加载了 a1
中的值。你必须分别挑选出每组4位(从低16位开始),这就是4位数字的编码。
哦,还有这个:
I have tried to run my code on MARS
这不是人们在 Assembly 中编程的方式。您没有 运行 您的代码。您在调试器中逐条执行单条指令,在每条指令后验证它确实只更改了它应该更改的 registers/memory,并且只更改了它应该更改的方式。
(这就是为什么您首先需要描述算法的英文注释,因为否则您无法推断指令是否按照您的要求执行...当然它总是会执行,它执行的操作,根据 CPU 文档,你一生中几乎不会遇到指令本身无法正确执行的情况(尽管在技术上是可行的,当一些电子 "jump" 超过 "walls"假设的路径,通常是在被来自 X-rays/etc 的一些质子重击之后......也许如果你活得足够长,它可能会在你附近发生一两次......你很可能永远不会注意到,因为SW 可能会幸存下来,或者像代码错误一样正常崩溃))
还要确保你避免大脑捉弄你,走捷径来节省它的精力,所以你的大脑不会阅读屏幕上的内容,而是会尝试告诉你,你确实想写什么,看到那里。
就像你在代码中写 sb $t0,0($a1)
而不是 sb $t0,0($a0)
,如果你在写完后不久尝试重新阅读源代码,你会读到 sb $t0,0($a0)
,除非你非常专注,确保你的大脑没有欺骗你。
同样适用于调试和检查寄存器中的结果值等。例如,如果您期望 t1
中的值 1
,而它不小心以 t2
结束,您可能很容易忽略 1
确实在 t2
中发生了变化,而不是在 t1
中发生变化的事实,因为你的大脑最关心的是结果是 1
。等等
这很棘手。这就是为什么人们喜欢 Assembly 并在其中编写几乎所有代码的原因。
我有关于如何编写一个名为 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。 Return 值:None。 所需操作:
必须将以下六个字符序列写入内存中的区域 由寄存器 $a0 指向。
1) 显示分钟数的两个 ASCII 编码数字,根据另外两个 输入参数的重要 NBCD 编码数字。示例:“1”、“6”(ASCII 0x31、0x36):
2) 一个冒号字符(ASCII : , 代码 0x3A)。
3)两个ASCII编码的数字显示秒数,根据少两个 输入参数的重要 NBCD 编码数字。示例:“5”、“3”(ASCII 0x35、0x33)。 4. 空字节(ASCII NUL,代码 0x00)。 Notes:You 必须使用函数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[=11=]"
.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,[=12=],$a0 #contaisn the adress of string (timstr)
add $t1,[=12=],$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
lb $t0, 0($a1) #load one byte from a1
这将从地址 a1
的内存中加载一个字节。
但a1
不包含有效地址,它包含BCD时间值,如0x5958
,表示时间59:58。
因此您不需要从内存中加载时间值,您已经加载了 a1
中的值。你必须分别挑选出每组4位(从低16位开始),这就是4位数字的编码。
哦,还有这个:
I have tried to run my code on MARS
这不是人们在 Assembly 中编程的方式。您没有 运行 您的代码。您在调试器中逐条执行单条指令,在每条指令后验证它确实只更改了它应该更改的 registers/memory,并且只更改了它应该更改的方式。
(这就是为什么您首先需要描述算法的英文注释,因为否则您无法推断指令是否按照您的要求执行...当然它总是会执行,它执行的操作,根据 CPU 文档,你一生中几乎不会遇到指令本身无法正确执行的情况(尽管在技术上是可行的,当一些电子 "jump" 超过 "walls"假设的路径,通常是在被来自 X-rays/etc 的一些质子重击之后......也许如果你活得足够长,它可能会在你附近发生一两次......你很可能永远不会注意到,因为SW 可能会幸存下来,或者像代码错误一样正常崩溃))
还要确保你避免大脑捉弄你,走捷径来节省它的精力,所以你的大脑不会阅读屏幕上的内容,而是会尝试告诉你,你确实想写什么,看到那里。
就像你在代码中写 sb $t0,0($a1)
而不是 sb $t0,0($a0)
,如果你在写完后不久尝试重新阅读源代码,你会读到 sb $t0,0($a0)
,除非你非常专注,确保你的大脑没有欺骗你。
同样适用于调试和检查寄存器中的结果值等。例如,如果您期望 t1
中的值 1
,而它不小心以 t2
结束,您可能很容易忽略 1
确实在 t2
中发生了变化,而不是在 t1
中发生变化的事实,因为你的大脑最关心的是结果是 1
。等等
这很棘手。这就是为什么人们喜欢 Assembly 并在其中编写几乎所有代码的原因。