Computer science 在mips中打印ascii字符
我正在修一门计算机设计课程,是MIPS编程(我们正在使用火星模拟器) 我们接到了一个任务,我很困惑。我是新手,有一些问题。 我的任务如下: 在.data中定义以下内容 buf:.空间21 buf1:。空间20 使用syscall 8从用户处获取一个20字符长的字符串,并执行以下操作: 比较buf[i]和buf[i+1]的ASCII值 如果为正,则将“+”复制到buf1,如果为负,则复制到do“-”,如果等于do'=' 最后打印buf1和buf1中的“=”号 到目前为止,我得到的是:Computer science 在mips中打印ascii字符,computer-science,mips32,mars-simulator,Computer Science,Mips32,Mars Simulator,我正在修一门计算机设计课程,是MIPS编程(我们正在使用火星模拟器) 我们接到了一个任务,我很困惑。我是新手,有一些问题。 我的任务如下: 在.data中定义以下内容 buf:.空间21 buf1:。空间20 使用syscall 8从用户处获取一个20字符长的字符串,并执行以下操作: 比较buf[i]和buf[i+1]的ASCII值 如果为正,则将“+”复制到buf1,如果为负,则复制到do“-”,如果等于do'=' 最后打印buf1和buf1中的“=”号 到目前为止,我得到的是: .data
.data
buf: .space 21
buf1: .space 20
msg1: .asciiz "The number of identical char in a row is: "
#+ is 43 in ascii
#- is 45 in ascii
#= is 61 in ascii decimal
################# Code segment ####################
#
.text
.globl main
main: # main program entry
la $a0, buf
li $a1, 20
li $v0, 8
syscall
loop:
la $s0, buf
lb $t0, 0($s0) #buf[0]
addi $s0, $s0, 1 # buf++
lb $t1, 0($s0) #buf[1]
beqz $t0, exit #if null, terminate
bgt $t0, $t1, greater
blt $t0, $t1, lesser
beq $t0, $t1, equal
greater:
lb $t1, 43
sb $t1, buf1
la $a0, buf1
li $v0, 4
syscall
j loop
lesser:
j loop
equal:
j loop
print:
la $a0, buf1
li $v0, 4
syscall
exit:
li $v0, 10 # Exit program
syscall
因此,我使用$t0和$t1比较buf[0]和buf[1],并将bgt与更大的标签进行比较
如何从ascii“复制”符号并打印它们?我对自己说,“+”是43 ASCII值。我该怎么处理它?如何将其添加到buf1,然后在最后打印?
我知道代码不完整,但我将感谢任何帮助
谢谢大家!
main: # main program entry
la $a0, buf
li $a1, 20
li $v0, 8
syscall
长度参数应为21(查看有关MARS“8”服务的文档,它最多读取n-1个字符,如果可能,添加换行符,并用零填充剩余内存)。这就是为什么任务描述中建议将buf
定义为.space 21
loop:
la $s0, buf
每次循环时,您都将覆盖源地址s0
(您是如何将其发送到SO的?…您不是在调试程序中一步一步地运行代码,检查寄存器和CPU中发生了什么吗?)
由于您不再在任何其他地方使用s0
,您可以通过执行lb$t1,1($s0)
来避免addi
。然后,当您每次停止重置s0
时,addi
可能又很方便了,因此这只是指出内存操作数语法中确实存在偏移部分
beqz $t0, exit #if null, terminate
还可以考虑检查换行符,除非您也要处理该换行符(任务描述似乎没有明确说明如何处理它,但从措辞上看,似乎只处理可打印字符)
此外,如果第一个字符不是零终止符,则检查它。但这太晚了,因为这意味着零终止符之前的一次迭代已经在第二个字符t1
中,所以您确实比较了前一个循环中的最后一个字符和零值
bgt $t0, $t1, greater
blt $t0, $t1, lesser
beq $t0, $t1, equal
顺便说一句,bgt
和blt
是伪指令。如果您检查最终机器代码的反汇编,您将看到它们转换为多个MIPS指令。通常情况下,您没有太多需要注意的地方,特别是当您刚开始使用MIPS汇编时,但是在这种特殊情况下,您编写的代码会让任何有经验的MIPS程序员感到厌烦
首先,请先执行beq
,因为这是本机MIPS指令。
然后,您可以执行bgt
或blt
,任您选择。最后,完全避免第三个分支,因为只有在剩下的第三种情况下才能到达代码的那个点,所以没有必要用另一个分支指令再次验证这一点。这实际上保存了两条本机指令,因为这些较大/较小的分支是由其中两条指令组成的
lb $t1, 43
从地址43加载字节值。您可能想使用li$t1,43
,将'+'
字符值加载到t1
寄存器中。另外,为了使源代码更易于阅读,您可以尝试直接编写li$t1,“+”
。大多数优秀的汇编器都会将ASCII字符转换为值,所以您不需要记住头部的所有ASCII表
sb $t1, buf1
这会将buf1[0]
字符写入内存。如果您知道s0
以buf
值开头,并且buf1
距离它有21个字节,那么您也可以滥用s0
值来写入buf1
,比如sb$t1,20($s0)
(+20,因为addi
s0的增量发生在值比较期间)。或者,如果您希望代码不那么神秘,请预先加载地址为buf1
的其他寄存器,如la$s1,buf1
,然后使用该寄存器
您可以在结束时输出整个buf1
字符串(但在适当的索引处写入+/-/=
字符,而不是一直覆盖buf1[0]
。并且在最后一个字符(最多19个,找出原因)后添加零终止符
如何从ascii“复制”符号并打印它们?我告诉自己“+”是43 ascii值。我该如何处理它?如何将其添加到buf1,然后在最后打印它 您必须首先在MARS模拟机中了解什么是“字符串”。如果您要在调试器中运行代码,您可以在“执行”窗口中看到数据段内容。不幸的是,我没有找到如何将其从“word”视图切换到“byte”在火星上查看,所以你必须理解小尾端是什么意思,以及内存在字节级上是如何显示的,即使在“word”显示值。您至少可以打开/关闭值的ASCII解释,这仍然是小端调整,因此您的
msg1
字符串由字节…20 6e 75 6d 62 65 72…
组成,这些字节是ASCII字符“number”
。在MARS中,当它在调试器中显示“words”时,“numb”将显示为“b m u n”(如果下一个单词从'n'
地址开始,在我下面的源代码中,它实际上是有点不同的,在“…e number…”周围的那部分作为单词“u n e”
“r e b m”
)
因此,内存中的字符串是连续内存区域,其中每个字节包含一个编码单个字符的ASCII值。对于输出服务v0=4
打印字符串,最后一个字节应包含零,以便让MARS服务知道这是字符串的结尾
即指令。asciiz“AB01”
将组装为五个
sb $t1, buf1
.data
buf: .space 21
buf1: .space 20
msg1: .asciiz "\nThe number of identical char in a row is: "
msg1_end:
.text
.globl main
main: # main program entry
la $s0, buf # load "buf" address into s0, also for later usage
# let the user input 20 character long string into memory (at address "buf")
move $a0, $s0
li $a1, 21
li $v0, 8
syscall
# set up registers before main processing loop (s0 is already "buf" address)
la $t2, buf1 # output string address
li $t3, '\n' # newline character in t2
li $t4, '+'
li $t5, '-'
li $t6, '='
move $s1, $zero # s1 will be counter of equal chars
# compare each inputted character with next one, and produce output string
compareEachCharInInput:
lb $t0, 0($s0) # buf[i]
addi $s0, $s0, 1 # ++i
lb $t1, 0($s0) # buf[i+1]
beq $t1, $zero, outputResultNL # if later char is zero, end processing
beq $t1, $t3, outputResult # if later char is newline, end processing
beq $t0, $t1, equal
blt $t0, $t1, lesser
# greater case
sb $t4, ($t2) # buf1[j] = '+'
addi $t2, $t2, 1 # ++j
j compareEachCharInInput
lesser:
sb $t5, ($t2) # buf1[j] = '-'
addi $t2, $t2, 1 # ++j
j compareEachCharInInput
equal:
sb $t6, ($t2) # buf1[j] = '='
addi $t2, $t2, 1 # ++j
addi $s1, $s1, 1 # ++equal_counter
j compareEachCharInInput
outputResultNL: # output newline character, when user did enter full 20 characters
move $a0, $t3 # reuse the newline char in t3 (still there)
li $v0, 11
syscall # because the output for less than 20 chars contains \n from input
outputResult:
sb $zero, ($t2) # add zero terminator to output string
la $a0, buf1 # output string address
li $v0, 4
syscall
# output number of identical neighbour chars
la $a0, msg1
li $v0, 4
syscall # label outputted
move $a0, $s1
li $v0, 1
syscall # counter outputted
# Exit program
li $v0, 10
syscall
11223344556677889900
=-=-=-=-=-=-=-=-=+=
The number of identical char in a row is: 10