Computer science 在mips中打印ascii字符

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

我正在修一门计算机设计课程,是MIPS编程(我们正在使用火星模拟器)

我们接到了一个任务,我很困惑。我是新手,有一些问题。 我的任务如下: 在.data中定义以下内容 buf:.空间21 buf1:。空间20

使用syscall 8从用户处获取一个20字符长的字符串,并执行以下操作: 比较buf[i]和buf[i+1]的ASCII值 如果为正,则将“+”复制到buf1,如果为负,则复制到do“-”,如果等于do'=' 最后打印buf1和buf1中的“=”号

到目前为止,我得到的是:

.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