You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Basys3 MicroBlaze汇编冒泡排序代码故障排查请求

MicroBlaze冒泡排序故障排查

问题背景

为Basys 3开发MicroBlaze汇编程序,基于Vivado 2019.1的Xilinx SDK。程序可通过UART接收10个字符存入数组,但实现的冒泡排序sort函数无法正常工作。

原始代码

#Equates
.set NUMLOOPS, 10
.set SWITCH_DATA, 0x40000000
.set SEV_SEG_DATA, 0x40010000
.set UART, 0x40600000


#Memory Section
$msgBegin:
    .asciz "\r\n Program Start.\r\n"
    .text
    .align 2
$msgWithChar:
    .asciz  "Character %d - %c\r\n"
    .text
    .align  2
$Nums:
    .fill 10, 4, 65
    .data
    .align 4
$msgLoop:
    .asciz "\r\n Embedded Systems Loop #%2d.\r\n"
    .text
    .align 2
$msgEnd:
    .asciz "\r\n Program Stop.\r\n"
    .text
    .align 2
$msgTest1:
    .asciz "\r\n Test 1."
    .text
    .align 2
$msgTest2:
    .asciz "\r\n Test 2."
    .text
    .align 2
$msgTest3:
    .asciz "\r\n Test 3."
    .text
    .align 2
$msgSpace:
    .asciz "\r\n"
    .text
    .align 2

#Main Program
.globl  main
main:
    addi  r5, r0, $msgBegin # Store string to print
    addi  r1, r1, -4        # Push r15 onto stack
    swi   r15,r1, 0
    brlid r15,xil_printf    # Call print func; retn addr in r15
    nop                     # Unfilled delay slot
    lwi   r15,r1, 0         # Pop r15 off the stack
    addi  r1, r1, 4
    addi  r19, r0, NUMLOOPS # Initialize R19 to NUMLOOPS
    addi  r20, r0, 1        # Initialize R20 to one
    addi  r22, r0, 0        # Initialize R22 to 0
.globl  loop
loop:
    beqi  r19, sort         # If R19==0, branch to done; stop program
    nop
    rsub  r19,r20,r19       # Decrement loop counter (R19) by 1 (R20)
    lwi   r11, r0, SWITCH_DATA  # Read data from switches
    swi   r11, r0, SEV_SEG_DATA # Write switch data to 7-segment disp
    addi  r5, r0, UART      # Set R5 arg to UART memory address
    addi  r1, r1, -4        # Push r15 onto stack
    swi   r15, r1, 0
    brlid r15, XUartLite_RecvByte # Call UART Receive function
    nop
    lwi   r15, r1, 0        # Pop r15 off stack
    addi  r1, r1, 4
    swi   r3, r22, $Nums    # Store value into $Nums array at offset R22
    add   r6, r0, r3        # Move char R3 into R6 to display to UART
    addi  r1, r1, -4        # Push r15 on stack
    swi   r15, r1, 0
    brlid r15, XUartLite_SendByte # Call Uart Send function
    nop
    lwi   r15, r1, 0        # Pop r15 off stack
    addi  r1, r1, 4
    addi  r22, r22, 4       # Increment R22 by 4 bytes
    bri   loop
    nop

.globl sort
sort:
    addi r23, r0, 10        # Initialize R23 for outer loop counter
    addi r24, r0, 10        # Initialize R24 for inner loop counter
    addi r22, r0, 0         # Reinitialize R22 to zero
    addi r29, r0, 0         # Initialize R29 for address offset of a[0]

for1:
    #Print Test
    addi  r5, r0, $msgTest1 # Store string to print
    addi  r1, r1, -4        # Push r15 onto stack
    swi   r15,r1, 0
    brlid r15,xil_printf    # Call print func; retn addr in r15
    nop                     # Unfilled delay slot
    lwi   r15,r1, 0         # Pop r15 off the stack
    addi  r1, r1, 4


    beqid r23, disp            # If R23==0, branch to disp
    nop
    addi r23, r23, -1          # Decrement outer loop counter (R23) by 1
    addi r24, r0, 10   # Initialize R24 for inner loop counter
    addi r24, r24, -1           # Subtract 1 from R24 (since we are comparing i and i+1)

for2:
    #Print Test
    addi  r5, r0, $msgTest2 # Store string to print
    addi  r1, r1, -4        # Push r15 onto stack
    swi   r15,r1, 0
    brlid r15,xil_printf    # Call print func; retn addr in r15
    nop                     # Unfilled delay slot
    lwi   r15,r1, 0         # Pop r15 off the stack
    addi  r1, r1, 4


    beqid r24, for1            # If R24==0, branch to for1
    nop
    addi r24, r24, -1          # Decrement inner loop counter (R24) by 1
    addi r25, r0, 0            # Initialize R25 for address offset of a[i]
    muli r25, r24, 4 # Calculate address offset for a[i]
    lwi r26, r25, $Nums        # Load a[i] into R26
    addi r25, r25, 4 # Increment R25 for address offset of a[i+1]
    lwi r27, r25, $Nums        # Load a[i+1] into R27

    addi r28, r0, 0
    cmp r28, r26, r27
    bgtid r28, for2       # If a[i] > a[i+1], skip the swap
    nop


swap:
    #Print Test
    addi  r5, r0, $msgTest3 # Store string to print
    addi  r1, r1, -4        # Push r15 onto stack
    swi   r15,r1, 0
    brlid r15,xil_printf    # Call print func; retn addr in r15
    nop                     # Unfilled delay slot
    lwi   r15,r1, 0         # Pop r15 off the stack
    addi  r1, r1, 4


    swi r26, r25, $Nums        # Store R26 (a[i]) into a[i+1] location
    swi r27, r25, $Nums        # Store R27 (a[i+1]) into a[i] location (using R25 - ARRAY_OFFSET)
    rsubi r25, r25, -4
    bri for2
    nop



.globl  disp
disp:
    addi  r19, r0, NUMLOOPS # Reinitialize R19 to NUMLOOPS
    addi  r22, r0, 0        # Reinitialize R22 to zero
    addi  r5, r0, $msgSpace # 1st arg R5 is format string
    add   r6, r0, r22       # 2nd arg R6 is address offset
    lwi   r7, r22, $Nums    # 3rd arg R7 is array value at this offset
    addi  r1, r1, -4        # Push r15 on stack
    swi   r15, r1, 0
    brlid r15, xil_printf   # Call printf
    nop
    lwi   r15, r1, 0        # Pop r15 off stack
    addi  r1, r1, 4
.globl loop2
loop2:
    beqi  r19, done         # If R19==0, branch to done; stop program
    nop
    rsub  r19,r20,r19       # Decrement loop counter (R19) by 1 (R20)
    addi  r5, r0, $msgWithChar # 1st arg R5 is format string
    add   r6, r0, r22       # 2nd arg R6 is address offset
    lwi   r7, r22, $Nums    # 3rd arg R7 is array value at this offset
    addi  r1, r1, -4        # Push r15 on stack
    swi   r15, r1, 0
    brlid r15, xil_printf   # Call printf
    nop
    lwi   r15, r1, 0        # Pop r15 off stack
    addi  r1, r1, 4
    addi  r22, r22, 4       # Increment R22 by 4 bytes
    bri   loop2
.globl  done
done:
    addi  r5, r0, $msgEnd   # Store string to print
    addi  r1, r1, -4        # Push r15 onto stack
    swi   r15,r1, 0
    brlid r15,xil_printf    # Call print func; retn addr in r15
    nop                     # Unfilled delay slot
    lwi   r15,r1, 0         # Pop r15 off the stack
    addi  r1, r1, 4

故障点分析及修复

1. 比较分支逻辑完全反转

冒泡排序的核心规则是当a[i] > a[i+1]时执行交换,但现有代码中:

cmp r28, r26, r27
bgtid r28, for2       # If a[i] > a[i+1], skip the swap

bgtid r28, for2表示当r26 > r27(即a[i] > a[i+1])时跳转到for2,跳过交换操作,完全违背排序逻辑。

修复:将分支指令改为bleid r28, for2,即当a[i] <= a[i+1]时跳过交换:

cmp r28, r26, r27
bleid r28, for2       # If a[i] <= a[i+1], skip the swap

2. 交换操作的地址错误

现有交换代码中,两次swi都使用r25(a[i+1]的偏移)作为目标地址,且后续的rsubi r25, r25, -4是给地址加4,完全错误:

swi r26, r25, $Nums        # Store R26 (a[i]) into a[i+1] location
swi r27, r25, $Nums        # Store R27 (a[i+1]) into a[i] location (using R25 - ARRAY_OFFSET)
rsubi r25, r25, -4

修复:先将r25减4回到a[i]的偏移,再执行第二次存储:

swi r26, r25, $Nums        # 将a[i]存入a[i+1]
addi r25, r25, -4          # 回到a[i]的偏移地址
swi r27, r25, $Nums        # 将a[i+1]存入a[i]

3. 外层循环计数冗余

外层循环r23初始值为10,执行10次,但冒泡排序对n个元素只需要执行n-1次外层循环(9次)。虽然多执行一次不会导致功能错误,但可以优化:

sort:
    addi r23, r0, 9        # 外层循环初始值改为9,执行9次
    ...

4. 内层循环计数逻辑优化(可选)

现有内层循环每次都从9开始遍历,冒泡排序可以优化内层循环次数(每次外层循环后,末尾的k个元素已排序,无需再比较),修改后可以提升效率:

for1:
    ...
    addi r23, r23, -1          # 外层循环计数器减1
    addi r24, r0, 9            # 内层循环初始值为9
    sub r24, r24, r23          # 内层循环次数 = 9 - 外层循环已执行次数

修正后的sort函数示例

.globl sort
sort:
    addi r23, r0, 9        # 外层循环执行9次(n-1)
    addi r22, r0, 0         # Reinitialize R22 to zero

for1:
    #Print Test
    addi  r5, r0, $msgTest1 # Store string to print
    addi  r1, r1, -4        # Push r15 onto stack
    swi   r15,r1, 0
    brlid r15,xil_printf    # Call print func; retn addr in r15
    nop                     # Unfilled delay slot
    lwi   r15,r1, 0         # Pop r15 off the stack
    addi  r1, r1, 4

    beqid r23, disp            # If R23==0, branch to disp
    nop
    addi r24, r0, 9            # 内层循环初始值为9
    sub r24, r24, r23          # 内层循环次数随外层循环递减
    addi r23, r23, -1          # Decrement outer loop counter (R23) by 1

for2:
    #Print Test
    addi  r5, r0, $msgTest2 # Store string to print
    addi  r1, r1, -4        # Push r15 onto stack
    swi   r15,r1, 0
    brlid r15,xil_printf    # Call print func; retn addr in r15
    nop                     # Unfilled delay slot
    lwi   r15,r1, 0         # Pop r15 off the stack
    addi  r1, r1, 4

    beqid r24, for1            # If R24==0, branch to for1
    nop
    muli r25, r24, 4 # Calculate address offset for a[i]
    lwi r26, r25, $Nums        # Load a[i] into R26
    addi r25, r25, 4 # Increment R25 for address offset of a[i+1]
    lwi r27, r25, $Nums        # Load a[i+1] into R27

    addi r28, r0, 0
    cmp r28, r26, r27
    bleid r28, for2       # If a[i] <= a[i+1], skip the swap
    nop

swap:
    #Print Test
    addi  r5, r0, $msgTest3 # Store string to print
    addi  r1, r1, -4        # Push r15 onto stack
    swi   r15,r1, 0
    brlid r15,xil_printf    # Call print func; retn addr in r15
    nop                     # Unfilled delay slot
    lwi   r15,r1, 0         # Pop r15 off the stack
    addi  r1, r1, 4

    sw
相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 11:26:38