【问题标题】:Need help with MIPS program在 MIPS 程序方面需要帮助
【发布时间】:2011-05-09 23:21:15
【问题描述】:

我正在开发一个将在 pcspim 上运行的 mips 程序,我需要一些帮助。程序的描述是:编写一个程序,读取一个字符串(从键盘),将它存储在内存中,计算并打印每个字符的频率;然后它反转字符串并打印反转的字符串。

到目前为止我是...

    .data   # Data declaration section
userString: .space 256
Prompt:     .asciiz "\nEnter a word: "
newLine:    .asciiz "\n"
    .text


main:       # Start of code section
li $v0, 4
la $a0, Prompt
syscall

li $v0, 8
la $a0, userString
li $a1, 256
    syscall
jr $ra

la $a0, userString
move $t0, $a0


lb $t1, 0($t0) 
li $v0, 4
move $a0, $t1
syscall     # prints first letter of word

现在我只是想看看我是否真的将输入存储到了 userString 数组中。所以最后我试图打印出第一个字母。但它似乎没有打印任何东西。

有什么建议吗? 谢谢。

【问题讨论】:

  • 我从未使用过 PCSPIM,但看起来 syscall 4 打印的是字符串而不是字符。您可能想尝试删除lb 指令并将整个字符串移动到$a0。 (它已经在那里了,但你可以在那里做一个move $a0, $t0
  • 我已经忘记了我对 MIPS 汇编的了解,但在前面几行中,您使用 la $a0, Prompt 展示了 Prompt 中的内容。那么你为什么不通过:la $a0,userString 显示 userString 的内容?为什么所有其他说明可能正确也可能不正确?
  • 是的,我只是不确定如何将用户输入字符串存储到数组中。我在网上四处查看并尝试了他们的一些代码。所以我不确定。我真的很讨厌mips。 :(

标签: mips


【解决方案1】:

我已将您的代码分解为三个部分:提示、输入、显示。我假设前两部分是给你的,第三部分是你现在关注的。我将解释第一个到部分正在做什么,然后解释第三个现在正在做什么以及此时您可能希望它做什么。

    .data   # Data declaration section
userString: .space 256
Prompt:     .asciiz "\nEnter a word: "
newLine:    .asciiz "\n"
    .text

# Part I
main:       # Start of code section
li $v0, 4
la $a0, Prompt
syscall

# Part II
li $v0, 8
la $a0, userString
li $a1, 256
    syscall
jr $ra

# Part III
la $a0, userString
move $t0, $a0
lb $t1, 0($t0) 
li $v0, 4
move $a0, $t1
syscall     # prints first letter of word

第一部分

这很简单,当我们开始执行程序时,计数器将设置为main 标签的地址。它将值4 加载到$v0(这似乎是打印字符串系统调用号),然后将Prompt 字符串的地址加载到第一个参数寄存器$a0。最后一位只是执行将字符串放在屏幕上的系统调用。

第二部分

现在"Enter a word: " 字符串已经打印在屏幕上,我们想要实际读取用户正在输入的内容。看起来我们在这里使用了系统调用#8(可能是读取字符串),所以我们将该值加载到$v0 中,为syscall 做准备。然后,由于我们想将用户字符串读入userString,我们将该标签的地址加载到$a0(读取字符串函数的第一个参数)然后,由于我们是精明的程序员,我们给出上限userString$a1 中可以容纳多少字节(256)。然后我们执行系统调用,你在键盘上输入一个字符串并回车,我们返回下一行代码。

那行是jr $ra,意思是“跳转到存储在寄存器$ra(返回地址)中的位置”。您可能不希望这样做,因为它标志着 main 函数的结束,并且您的程序可能在此时退出回命令行,最好将其删除。

第三部分

同样,您将userString 的地址加载到$a0 中(并将其移动到下一行的$t0 中)。现在它变得很奇怪,你将userString 的第一个字节0($t0) 加载到$t1 中。这是一个 ASCII 字符值(如 72 之类的)。然后你用打印字符串系统调用(#4)和$t1的参数再次启动系统调用。你认为这会打印单词的第一个字母,我不同意。这就是为什么。如果用户键入字符串“Hello, world!”这是它在内存中的样子:

userString: H  e  l  l  o  ,     w  o  r  l  d  !
    offset: 0  1  2  3  4  5  6  7  8  9 10 11 12

因此,加载0($t0) 会将字母H 移动到寄存器$t1 中,然后当您执行系统调用时,它会尝试将从H 开始的字符串打印到屏幕上。但是,没有以字母H 开头的字符串,它以userString 的地址开头。因此,如果您只是将userString 的地址移动到寄存器$a0,然后执行系统调用#4,它应该将userString 打印到屏幕上。

【讨论】:

    【解决方案2】:

    @mjshultz

    我已经改变了一点。没想到我需要 2 个循环。我也将它增加了四,因为我认为每个字符是 4 个字节,所以要转到下一个字母,我需要将偏移量增加四。

            .data   # Data declaration section
    userString: .space 256
    Prompt:     .asciiz "\nEnter a word: "
    newSpace:   .asciiz " " 
    newLine:    .asciiz "\n"
    
        .text
    
    
    main:       # Start of code section
    li $v0, 4
    la $a0, Prompt
    syscall
    
    
    la $a0, userString
    li $a1, 256
    li $v0, 8
        syscall
    
    la $a0, userString
    move $s0, $a0
    
    loop:   
    lb $t1, 0($s0)
    li $v0, 1
    move $a0, $t1
    syscall 
    
    li $v0, 4
    la $a0, newSpace
    syscall 
    addi $s0, $s0, 4
    
    blt $s0, 256, loop
    

    【讨论】:

    • 关于字符的大小,每个字符都是1字节的实体(使用lb或加载字节指令),字是4字节的实体(使用lw或加载字指令)。至于为什么它只显示一个字母,你认为在分支操作时$s0 中存储了什么值?是userString的地址吧?你认为是什么,是小于还是大于 256?
    猜你喜欢
    • 1970-01-01
    • 2011-08-06
    • 2015-05-21
    • 1970-01-01
    • 1970-01-01
    • 2011-10-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多