auipc指令在NEMU中的执行过程

假设

  1. 指令集为RV64I

  2. 内存地址开始于0x8000 0000

  3. 使用如下的代码:

    C 复制代码
    static const uint32_t img [] = {
        0x00000297,  // auipc t0,0
        0x00028823,  // sb  zero,16(t0)
        0x0102c503,  // lbu a0,16(t0)
        0x00100073,  // ebreak (used as nemu_trap)
        0xdeadbeef,  // some data
    };
  4. Decode的定义如下

    C 复制代码
    typedef struct Decode {
        uint64_t pc;
        uint64_t snpc; // static next pc
        uint64_t dnpc; // dynamic next pc
        struct {
            uint32_t inst;
        } isa;
    } Decode;
  5. cpu.pc初始值为0x8000 0000

  6. 从调用exec_once()并开始执行auipc开始考虑

  7. 忽略trace和difftest相关的操作

exec_once(&s, cpu.pc);

调用exec_once(&s, cpu.pc),当前cpu.pc值为0x8000 0000

进入exec_once()后,更新s:

C 复制代码
s->pc = 0x80000000;
s->snpc = 0x80000000;

调用isa_exec_once(s)

isa_exec_once(s)

利用inst_fetch(&s->snpc, 4)更新s。inst_fetch返回snpc对应的指令地址(uint32_t类型),并且更新snpc为下一条指令所在地址(s->snpc += 4, 即0x8000 0004)。 更新后的s:

C 复制代码
s->pc = 0x80000000;
s->snpc = 0x80000004;
s->isa.inst = 0x80000000;

之后执行decode_exec(s)并将其结果返回.

decode_exec(s)

更新s->dnpc = s->snpc, 此时s:

C 复制代码
s->pc = 0x80000000;
s->snpc = 0x80000004;
s->dnpc = 0x80000004;
s->isa.inst = 0x80000000;

定义标签地址, 用于之后跳转:

C 复制代码
const void * __instpat_end = &&__instpat_end_;

指令匹配:

C 复制代码
INSTPAT("??????? ????? ????? ??? ????? 00101 11", auipc  , U, R(rd) = s->pc + imm);
INSTPAT("??????? ????? ????? 100 ????? 00000 11", lbu    , I, R(rd) = Mr(src1 + imm, 1));
INSTPAT("??????? ????? ????? 000 ????? 01000 11", sb     , S, Mw(src1 + imm, 1, src2));

INSTPAT("0000000 00001 00000 000 00000 11100 11", ebreak , N, NEMUTRAP(s->pc, R(10))); // R(10) is $a0
INSTPAT("??????? ????? ????? ??? ????? ????? ??", inv    , N, INV(s->pc));

INSTPAT() 指令匹配宏

宏展开后, 匹配成功第一条规则:

C 复制代码
do {
    uint64_t key, mask, shift;
    pattern_decode("??????? ????? ????? ??? ????? 00101 11",
        (sizeof("??????? ????? ????? ??? ????? 00101 11") - 1), &key, &mask, &shift);
    if ((((uint64_t)((s)->isa.inst) >> shift) & mask) == key) {
        {
            int rd = 0;
            word_t src1 = 0, src2 = 0, imm = 0;
            decode_operand(s, &rd, &src1, &src2, &imm, TYPE_U);
            (cpu.gpr[check_reg_idx(rd)]) = s->pc + imm ;
        };
        goto *(__instpat_end);
    }
    } while (0)

其中(sizeof("??????? ????? ????? ??? ????? 00101 11") - 1) == 38

pattern_decode() 解码宏

进入pattern_decode()宏后, 定义临时变量uint64_t __key = 0, __mask = 0, __shift = 0;. 之后pattern_decode() 会利用辅助宏macro(i). 在macro(i)中:

  1. 若str[i]是'1', __key左移并且低位补1; 若不是, __key左移并且低位补0;
  2. 若str[i]是'?', __mask左移并且低位补0; 若不是, __mask左移并且低位补1
  3. 若str[i]是'?', __shift加1, 否则立刻清0

通过:

C 复制代码
#define macro2(i)  macro(i);   macro((i) + 1)
#define macro4(i)  macro2(i);  macro2((i) + 2)
#define macro8(i)  macro4(i);  macro4((i) + 4)
#define macro16(i) macro8(i);  macro8((i) + 8)
#define macro32(i) macro16(i); macro16((i) + 16)
#define macro64(i) macro32(i); macro32((i) + 32)
  macro64(0);

处理指令掩码中的38个字符. 本例中, __key最终为0010111, __mask最终为000...00(共25个0)1111111, __shift最终为0 跳转到finish标签后执行:

C 复制代码
finish:
  *key = __key >> __shift;
  *mask = __mask >> __shift;
  *shift = __shift;

然后退出pattern_decode()宏, 进入INSTPAT宏的:

C 复制代码
if ((((uint64_t)INSTPAT_INST(s) >> shift) & mask) == key) { \
INSTPAT_MATCH(s, ##__VA_ARGS__); \
goto *(__instpat_end); \
} \

(uint64_t)INSTPAT_INST(s)即执行的指令inst. inst被右移shift位, 然后和mask按位与, 判断是否和key完全相等 如果相等, 则执行:

C 复制代码
INSTPAT_MATCH(s, ##__VA_ARGS__); \
goto *(__instpat_end); \

ISNT_MATCH() 执行指令宏

在这个宏里, 会利用decode_operand()函数来译码出rd, src, src2, imm. 然后执行__VA_ARGS__ ;. __VA_ARGS__就是在INSTPAT()中传入的指令的具体操作. 对于auipc这条指令, __VA_ARGS就是R(rd) = s->pc + imm.

相关推荐
Ramble_Naylor18 小时前
Rust深度解读:高性能 Web 网关与 Axum 架构剖析
前端·架构·rust
低调小一19 小时前
客户端开发者学 Eino(01):从一次模型调用理解 Agent 架构
人工智能·架构·eino
Hello.Reader19 小时前
100 人同时操作一座三维城市,为什么不需要服务器渲染 6000 帧?Rust + wgpu 多端并发架构实战
服务器·架构·rust
当下新鲜事1 天前
面向印刷包装设备的运动控制方案架构:E530标准型伺服系统与AC500 PLC的分层设计与选型实施
架构
海宇AI1 天前
零信任架构实战:基于海宇个人风险报告构建自动化分期商城信用额度初审网关
运维·人工智能·架构·自动化
AUTOSAR组织1 天前
AUTOSAR架构下信息安全的实现方案
架构·汽车·autosar·软件架构·培训
涛声依旧-底层原理研究所1 天前
拆解 Cordis 底座:Agent 是如何被「组合」出来的
人工智能·架构
极限挑战哥1 天前
共享电单车联营平台分账架构实践:二清合规与自动分账零人工方案
java·大数据·人工智能·微信小程序·架构·微信公众平台
吴凡wudianmei1 天前
从 0 搭一个 AI Agent(三):SSE 流式输出,让 AI 边想边说
架构·llm·openai
各类产品分享11 天前
工业级 AR 巡检系统选型:核心参数与架构实现要点
架构·ar·ar巡检