找回密码
 立即注册
首页 业界区 业界 auipc指令在NEMU中的执行过程

auipc指令在NEMU中的执行过程

姨番单 昨天 12:25
假设


  • 指令集为RV64I
  • 内存地址开始于0x8000 0000
  • 使用如下的代码:
    1. static const uint32_t img [] = {
    2.     0x00000297,  // auipc t0,0
    3.     0x00028823,  // sb  zero,16(t0)
    4.     0x0102c503,  // lbu a0,16(t0)
    5.     0x00100073,  // ebreak (used as nemu_trap)
    6.     0xdeadbeef,  // some data
    7. };
    复制代码
  • Decode的定义如下
    1. typedef struct Decode {
    2.     uint64_t pc;
    3.     uint64_t snpc; // static next pc
    4.     uint64_t dnpc; // dynamic next pc
    5.     struct {
    6.         uint32_t inst;
    7.     } isa;
    8. } Decode;
    复制代码
  • cpu.pc初始值为0x8000 0000
  • 从调用exec_once()并开始执行auipc开始考虑
  • 忽略trace和difftest相关的操作
exec_once(&s, cpu.pc);

调用exec_once(&s, cpu.pc),当前cpu.pc值为0x8000 0000
进入exec_once()后,更新s:
  1. s->pc = 0x80000000;
  2. 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:
  1. s->pc = 0x80000000;
  2. s->snpc = 0x80000004;
  3. s->isa.inst = 0x80000000;
复制代码
之后执行decode_exec(s)并将其结果返回.
decode_exec(s)

更新s->dnpc = s->snpc, 此时s:
  1. s->pc = 0x80000000;
  2. s->snpc = 0x80000004;
  3. s->dnpc = 0x80000004;
  4. s->isa.inst = 0x80000000;
复制代码
定义标签地址, 用于之后跳转:
  1. const void * __instpat_end = &&__instpat_end_;
复制代码
指令匹配:
  1. INSTPAT("??????? ????? ????? ??? ????? 00101 11", auipc  , U, R(rd) = s->pc + imm);
  2. INSTPAT("??????? ????? ????? 100 ????? 00000 11", lbu    , I, R(rd) = Mr(src1 + imm, 1));
  3. INSTPAT("??????? ????? ????? 000 ????? 01000 11", sb     , S, Mw(src1 + imm, 1, src2));
  4. INSTPAT("0000000 00001 00000 000 00000 11100 11", ebreak , N, NEMUTRAP(s->pc, R(10))); // R(10) is $a0
  5. INSTPAT("??????? ????? ????? ??? ????? ????? ??", inv    , N, INV(s->pc));
复制代码
INSTPAT() 指令匹配宏

宏展开后, 匹配成功第一条规则:
  1. do {
  2.     uint64_t key, mask, shift;
  3.     pattern_decode("??????? ????? ????? ??? ????? 00101 11",
  4.         (sizeof("??????? ????? ????? ??? ????? 00101 11") - 1), &key, &mask, &shift);
  5.     if ((((uint64_t)((s)->isa.inst) >> shift) & mask) == key) {
  6.         {
  7.             int rd = 0;
  8.             word_t src1 = 0, src2 = 0, imm = 0;
  9.             decode_operand(s, &rd, &src1, &src2, &imm, TYPE_U);
  10.             (cpu.gpr[check_reg_idx(rd)]) = s->pc + imm ;
  11.         };
  12.         goto *(__instpat_end);
  13.     }
  14.     } 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)中:

  • 若str是'1', __key左移并且低位补1; 若不是, __key左移并且低位补0;
  • 若str是'?', __mask左移并且低位补0;
    若不是, __mask左移并且低位补1
  • 若str是'?', __shift加1, 否则立刻清0
通过:
  1. #define macro2(i)  macro(i);   macro((i) + 1)
  2. #define macro4(i)  macro2(i);  macro2((i) + 2)
  3. #define macro8(i)  macro4(i);  macro4((i) + 4)
  4. #define macro16(i) macro8(i);  macro8((i) + 8)
  5. #define macro32(i) macro16(i); macro16((i) + 16)
  6. #define macro64(i) macro32(i); macro32((i) + 32)
  7.   macro64(0);
复制代码
处理指令掩码中的38个字符.
本例中, __key最终为0010111, __mask最终为000...00(共25个0)1111111, __shift最终为0
跳转到finish标签后执行:
  1. finish:
  2.   *key = __key >> __shift;
  3.   *mask = __mask >> __shift;
  4.   *shift = __shift;
复制代码
然后退出pattern_decode()宏, 进入INSTPAT宏的:
  1. if ((((uint64_t)INSTPAT_INST(s) >> shift) & mask) == key) { \
  2. INSTPAT_MATCH(s, ##__VA_ARGS__); \
  3. goto *(__instpat_end); \
  4. } \
复制代码
(uint64_t)INSTPAT_INST(s)即执行的指令inst. inst被右移shift位, 然后和mask按位与, 判断是否和key完全相等
如果相等, 则执行:
  1. INSTPAT_MATCH(s, ##__VA_ARGS__); \
  2. goto *(__instpat_end); \
复制代码
ISNT_MATCH() 执行指令宏

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

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

昨天 23:02

举报

很好很强大  我过来先占个楼 待编辑
您需要登录后才可以回帖 登录 | 立即注册