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

调用MIPS矩阵乘法函数导致PSP崩溃的问题求助

问题排查与解决方案

崩溃原因分析

  • 存储宏笔误:sm4宏中最后一条指令错误重复使用r\mnum\()02,而非正确的r\mnum\()03,导致内存数据被错误覆盖,触发崩溃。
  • VFPU指令误用:单条vmmul.q是按元素乘法,并非数学意义上的矩阵乘法,无法完成4x4矩阵的正确计算,错误的运算逻辑会破坏寄存器或内存数据。
  • 内存对齐违规:VFPU的lv.q/sv.q指令要求地址必须16字节对齐,栈上默认分配的float数组无法保证该对齐要求,会触发硬件异常导致死机。
  • CMake配置缺失:原配置未明确构建汇编库的步骤,虽然临时解决了链接错误,但库的构建逻辑不规范,可能导致符号或代码加载异常。

修复步骤

1. 修正存储宏的笔误

修改matrixmul.s中的sm4宏:

.macro sm4 mnum adr
    sv.q r\mnum\()00, 0(\adr\())
    sv.q r\mnum\()01, 16(\adr\())
    sv.q r\mnum\()02, 32(\adr\())
    sv.q r\mnum\()03, 48(\adr\())  # 替换原有的r\mnum\()02
.endm

2. 实现正确的VFPU 4x4矩阵乘法

替换原有的乘法逻辑,使用VFPU的乘加指令完成数学意义上的矩阵乘法:

.globl matrixmul4x4
# $a0 = 输入矩阵A地址(行优先)
# $a1 = 输入矩阵B地址(行优先)
# $a2 = 结果矩阵地址(行优先)
matrixmul4x4:
    # 初始化栈帧,保存返回地址和VFPU保存寄存器
    addiu $sp, $sp, -32
    sw $ra, 28($sp)
    sv.q r16, 0($sp)

# 按行加载矩阵A的宏
.macro load_mat_row mat_num addr
    lv.s r\mat_num\()00, 0(\addr\())
    lv.s r\mat_num\()01, 4(\addr\())
    lv.s r\mat_num\()02, 8(\addr\())
    lv.s r\mat_num\()03, 12(\addr\())
    lv.s r\mat_num\()04, 16(\addr\())
    lv.s r\mat_num\()05, 20(\addr\())
    lv.s r\mat_num\()06, 24(\addr\())
    lv.s r\mat_num\()07, 28(\addr\())
    lv.s r\mat_num\()08, 32(\addr\())
    lv.s r\mat_num\()09, 36(\addr\())
    lv.s r\mat_num\()10, 40(\addr\())
    lv.s r\mat_num\()11, 44(\addr\())
    lv.s r\mat_num\()12, 48(\addr\())
    lv.s r\mat_num\()13, 52(\addr\())
    lv.s r\mat_num\()14, 56(\addr\())
    lv.s r\mat_num\()15, 60(\addr\())
.endm

# 按列加载矩阵B的宏(转置以适配VFPU乘法)
.macro load_mat_col mat_num addr
    lv.s r\mat_num\()00, 0(\addr\())
    lv.s r\mat_num\()04, 4(\addr\())
    lv.s r\mat_num\()08, 8(\addr\())
    lv.s r\mat_num\()12, 12(\addr\())
    lv.s r\mat_num\()01, 16(\addr\())
    lv.s r\mat_num\()05, 20(\addr\())
    lv.s r\mat_num\()09, 24(\addr\())
    lv.s r\mat_num\()13, 28(\addr\())
    lv.s r\mat_num\()02, 32(\addr\())
    lv.s r\mat_num\()06, 36(\addr\())
    lv.s r\mat_num\()10, 40(\addr\())
    lv.s r\mat_num\()14, 44(\addr\())
    lv.s r\mat_num\()03, 48(\addr\())
    lv.s r\mat_num\()07, 52(\addr\())
    lv.s r\mat_num\()11, 56(\addr\())
    lv.s r\mat_num\()15, 60(\addr\())
.endm

# 按行存储结果矩阵的宏
.macro store_mat_row mat_num addr
    sv.s r\mat_num\()00, 0(\addr\())
    sv.s r\mat_num\()01, 4(\addr\())
    sv.s r\mat_num\()02, 8(\addr\())
    sv.s r\mat_num\()03, 12(\addr\())
    sv.s r\mat_num\()04, 16(\addr\())
    sv.s r\mat_num\()05, 20(\addr\())
    sv.s r\mat_num\()06, 24(\addr\())
    sv.s r\mat_num\()07, 28(\addr\())
    sv.s r\mat_num\()08, 32(\addr\())
    sv.s r\mat_num\()09, 36(\addr\())
    sv.s r\mat_num\()10, 40(\addr\())
    sv.s r\mat_num\()11, 44(\addr\())
    sv.s r\mat_num\()12, 48(\addr\())
    sv.s r\mat_num\()13, 52(\addr\())
    sv.s r\mat_num\()14, 56(\addr\())
    sv.s r\mat_num\()15, 60(\addr\())
.endm

    # 加载输入矩阵
    load_mat_row 0, $a0
    load_mat_col 1, $a1

    # 计算结果矩阵的每一行(乘加运算)
    vmul.q m200, m000, m100
    vmadd.q m200, m001, m101
    vmadd.q m200, m002, m102
    vmadd.q m200, m003, m103

    vmul.q m201, m004, m100
    vmadd.q m201, m005, m101
    vmadd.q m201, m006, m102
    vmadd.q m201, m007, m103

    vmul.q m202, m008, m100
    vmadd.q m202, m009, m101
    vmadd.q m202, m00a, m102
    vmadd.q m202, m00b, m103

    vmul.q m203, m00c, m100
    vmadd.q m203, m00d, m101
    vmadd.q m203, m00e, m102
    vmadd.q m203, m00f, m103

    # 存储结果矩阵
    store_mat_row 2, $a2

    # 恢复寄存器与栈帧
    lv.q r16, 0($sp)
    lw $ra, 28($sp)
    addiu $sp, $sp, 32

    jr $ra

3. 保证内存对齐

修改main.c中的数组定义,添加对齐属性:

float m0[] __attribute__((aligned(16))) = {5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8};
float m1[] __attribute__((aligned(16))) = {5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8};
float m2[16] __attribute__((aligned(16))) = {};

4. 修正CMake配置

明确汇编库的构建流程:

cmake_minimum_required(VERSION 3.27.3)

project(psp-vfputhing)

# 构建matrixmul静态库
add_library(matrixmul STATIC src/matrixmul.s)

add_executable(vfputhing
    src/main.c
    src/callbacks.c
)

target_include_directories(vfputhing PRIVATE include)

if(PLATFORM_PSP)
    create_pbp_file(
        TARGET vfputhing
        TITLE "Dingus Console"
        ICON_PATH NULL
        PREVIEW_PATH NULL
        BUILD_PRX
    )

    target_link_libraries(vfputhing matrixmul pspdebug pspdisplay pspge pspgu pspgum)
endif()

额外注意事项

  • PSP的VFPU指令对内存对齐要求严格,所有向量操作的地址必须是对应数据宽度的整数倍(如16字节对齐用于.q类型,4字节对齐用于.s类型)。
  • 矩阵乘法中对矩阵B进行转置加载,是为了适配VFPU的并行运算逻辑,提升计算效率。
  • 遵循MIPS ABI规范,函数调用时需保存返回地址和非临时寄存器(包括VFPU的保存寄存器),避免破坏调用者的上下文。

内容的提问来源于stack exchange,提问作者Jayanky

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 14:15:57