基于PLPTool 5.2的MIPS汇编回文检查程序跳转异常排查求助
问题
我正在完成课程作业,使用PLPTool 5.2编写MIPS汇编程序,该程序需通过UART接收字符串,检查是否为回文后调用打印函数输出“Yes”或“No”。我已填充完给定的模板代码,程序编译无错误,但逐行调试发现,即使通过UART输入正确内容,程序也始终无法跳转到palindrome_check标签。以下是我的代码:
.org 0x10000000 # Initializations # NOTE: You may add initializations after line 10, but please do not # remove or change the initializations to $sp, $s0, $s1, or $s2 li $sp, 0x10fffffc # Starting address of empty stack li $s0, 0xf0000000 # UART base address li $s1, array_ptr # Array head pointer li $s2, array_ptr # Array tail pointer #################################################################### # Do not make changes to the jump to main, the allocation of # memory for the array, or the main loop #################################################################### j main nop array_ptr: # Label pointing to 100 word array .space 100 main: jal poll_UART nop jal period_check nop jal space_check nop jal case_check nop jal array_push nop j main nop #################################################################### # ****************************************************************** #################################################################### # The "poll_UART" function should poll the status register of the UART. # If the 2^1 bit position (ready bit) is set to 1 then it # should copy the receive buffer's value into $v0 and send # a clear status command (2^1) to the command register before # returning (a return statement is already included). In order to # receive full credit, $s0 must contain the base address of the UART # and must be used with the appropriate offsets to access UART # registers and buffers poll_UART: lw $t0, 4($s0) li $t1, 0b10 and $t2, $t0, $t1 beq $t2, $zero, poll_UART nop lw $v0, 8($s0) sw $t1, 0($s0) jr $ra nop # The "period_check" function should check if the current character ($v0) # is a period ("."). If it is a period then the function should go to the # label, "palindrome_check". If the character is not a period then it # should make a nested function call to palindrome_check period_check: li $t3, 0x2E beq $v0, $t3, palindrome_check nop jr $ra nop # The "space_check" function should check if the current character ($v0) # is a space (" "). If it is then it should jump to "main" so # that it skips saving the space character. If not it should # use the included return. space_check: li $t4, 0x20 beq $t4, $v0, main nop jr $ra nop # The "case_check" function should perform a single inequality check. # If the current character ($v0) is greater than the ASCII value of 'Z', # which indicates the current character is lowercase, then it should convert # the value of $v0 to the uppercase equivalent and then return. If the # current character ($v0) is already uppercase (meaning the inequality # mentioned before was not true) then the function should return without # performing a conversion. case_check: li $t5, 0x5A slt $t6, $v0, $t5 li $t7, 1 beq $t6, $t7, upper_case nop jr $ra nop upper_case: addiu $v0, $v0, -32 jr $ra nop # The "array_push" function should save the current character ($v0) to the # current location of the tail pointer, $s2. Then it should increment the # tail pointer so that it points to the next element of the array. Last # it should use the included return statement. array_push: sw $v0, 0($s2) addiu $s2, $s2, 4 jr $ra nop # The "palindrome_check" subroutine should be jumped to by the period # check function if a period is encountered. This subroutine should contain # a loop that traverses the array from the front towards the back (using the # head pointer, $s1) and from the back towards the front(using the tail # pointer, $s2). If the string is a palindrome then as the array is traversed # the characters pointed to should be equal. If the characters are not equal # then the string is not a palindrome and the print function should be used # to print "No". If the pointers cross (i.e. the head pointer's address is # greater than or equal to the tail pointer's address) and the compared # characters are equal then the string is a palindrome and "Yes" should be # printed. # # Remember to restore the head and tail pointers to the first element # of the array before the subroutine jumps back to main to begin processing the # next string. Also, keep in mind that because the tail pointer is updated at # the end of "array_push" it technically points one element past the last # character in the array. You will need to compensate for this by either # decrementing the pointer once at the start of the array or using an offset # from this pointer's address. palindrome_check: addiu $s2, $s2, -4 scan: lw $t8, 0($s1) lw $t9, 0($s2) bne $t8, $t9, FALSE nop addiu $s2, $s2, -4 addiu $s1, $s1 4 slt $t7, $s2, $s1 beq $t7, $zero, scan nop j TRUE nop TRUE: li $a0, 1 call project3_print li $s1, array_ptr li $s2, array_ptr j main nop FALSE: li $a0, 0 call project3_print li $s1, array_ptr li $s2, array_ptr j main nop
排查方法
- 验证
poll_UART的字符读取正确性:在poll_UART返回后,立即查看寄存器$v0的值,确认输入句号时是否读取到了ASCII值0x2E。如果值不对,检查UART寄存器偏移是否符合PLPTool的规范,比如接收缓冲区的偏移是否真的是8($s0),状态寄存器的偏移是否是4($s0)。 - 检查
period_check的分支触发情况:在period_check的beq $v0, $t3, palindrome_check指令处设置断点,输入句号后,查看$v0和$t3(0x2E)是否相等,以及分支是否被触发(调试器会显示分支是否taken)。如果分支未触发,说明$v0的值不正确,回到poll_UART排查读取逻辑。 - 确认主循环的执行流程:当输入句号时,
period_check的跳转应该直接跳到palindrome_check,跳过后续的space_check、case_check等调用。调试时跟踪程序计数器(PC),确认执行beq后PC是否跳转到palindrome_check的地址。 - 检查
palindrome_check标签的有效性:查看汇编后的机器码,确认beq指令的跳转目标地址是否与palindrome_check的实际地址一致,避免因汇编地址计算错误导致跳转失败。 - 排除其他函数的干扰:暂时注释掉主循环中
period_check之后的函数调用,单独测试period_check的跳转是否正常,排除后续函数对寄存器或执行流程的意外影响。
内容的提问来源于stack exchange,提问作者Jonathan Alvaro
相关产品推荐
相关产品推荐

