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

AVR虚拟处理器RJMP指令C实现异常问题排查求助

解决AVR虚拟处理器RJMP指令的两个核心问题

看起来你在RJMP的汇编测试和C实现上都踩了坑,我来帮你逐一梳理修复:

1. 先修正你的汇编测试代码

你写的rjmp ldi r16, 0x00是完全错误的——AVR的RJMP指令操作数必须是标签,不能直接指定指令。你需要先给目标指令定义标签,再跳转。比如你想跳到ldi r17, 0x32,可以这么写:

.text
.global main
.type main, @function
main:
    ldi r30, 0x00
    mov r3, r1
    mov r4, r2
    rjmp target_r17 ; 跳转到预定义的标签
    ldi r16, 0x00
    ldi r16, 0x01
target_r17: ; 给目标指令添加标签
    ldi r17, 0x32

如果想跳回main的首条指令,直接写rjmp main即可。另外你提到用$+2报错,AVR GAS汇编里$代表当前PC,但RJMP的偏移是字偏移(1个单位对应2字节),所以rjmp $是无限循环,rjmp $+1才是跳转到下一条指令(+1个单位=+2字节)。

2. 修复C语言的RJMP实现逻辑

你的F_JMP_REL函数有3个关键错误,完全不符合AVR的RJMP指令规范:

错误点梳理

  • 偏移量提取错误:RJMP的偏移量是低11位有符号数,你用0x0FFF提取了12位,多取的一位直接导致偏移计算混乱。
  • PC基准值错误:AVR执行指令时,PC会先自增2(指向当前指令的下一条),再执行跳转逻辑,你直接用当前指令的PC作为基准是错的。
  • 偏移量转换错误:RJMP的偏移是字偏移(1单位=2字节),你直接按字节偏移计算,导致跳转地址偏差一倍。

修正后的代码

#include <stdint.h> // 需要引入这个头文件处理有符号整数

void F_JMP_REL(void) {
    uint16_t current_pc = getPC();
    uint16_t opcode = getOpcode();
    
    // 提取低11位的有符号偏移量k,自动完成符号扩展
    int16_t k = (int16_t)(opcode & 0x07FF);
    // 计算目标地址:当前PC+2(下一条指令地址) + 偏移量*2(转成字节偏移)
    uint16_t target_pc = current_pc + 2 + (k * 2);

    printf("0x%04X[0x%04X]: JMP PC+0x%04X -> 0x%04X\n", 
           current_pc, opcode, (k * 2), target_pc);
    
    setPC(target_pc);
    addCounter(1);
}

逻辑验证

比如你提到的测试场景:如果RJMP指令地址是0x0001,opcode低11位为0x001(k=1),那么目标地址应为0x0001 + 2 + (1*2) = 0x0005,这才是符合AVR规范的跳转结果,之前的错误逻辑就是因为偏移提取、基准PC和字节转换的三重错误,才跳到了错误的0x07FB。

内容的提问来源于stack exchange,提问作者Patryk Woźniak

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 07:11:11