当前位置: 首页 > article >正文

一生一芯 预学习阶段 NEMU代码学习(2)

接上回:一生一芯 预学习阶段 NEMU代码学习(1)

上次说到这里

static int cmd_c(char *args) {
  cpu_exec(-1);
  return 0;
}

当输入c时,会执行:cpu_exec(-1);

void cpu_exec(uint64_t n) {
  g_print_step = (n < MAX_INST_TO_PRINT);
  switch (nemu_state.state) {
    case NEMU_END: case NEMU_ABORT:
      printf("Program execution has ended. To restart the program, exit NEMU and run again.\n");
      return;
    default: nemu_state.state = NEMU_RUNNING;
  }

  uint64_t timer_start = get_time();

  execute(n);

  uint64_t timer_end = get_time();
  g_timer += timer_end - timer_start;

  switch (nemu_state.state) {
    case NEMU_RUNNING: nemu_state.state = NEMU_STOP; break;

    case NEMU_END: case NEMU_ABORT:
      Log("nemu: %s at pc = " FMT_WORD,
          (nemu_state.state == NEMU_ABORT ? ANSI_FMT("ABORT", ANSI_FG_RED) :
           (nemu_state.halt_ret == 0 ? ANSI_FMT("HIT GOOD TRAP", ANSI_FG_GREEN) :
            ANSI_FMT("HIT BAD TRAP", ANSI_FG_RED))),
          nemu_state.halt_pc);
      // fall through
    case NEMU_QUIT: statistic();
  }
}

g_print_step 是一个全局变量,用于控制是否逐步输出执行的指令信息;

如果要执行的指令数量 n 小于预定义的常量 MAX_INST_TO_PRINT,则将 g_print_step 置为 true,表示会逐步打印指令执行的过程。

uint64_t timer_start = get_time();

uint64_t timer_end = get_time();

get_time() 函数返回当前的时间,用于记录 CPU 执行开始的时间以及指令执行结束时的时间。

并将执行的时间差累加到全局变量 g_timer 中。

最后,根据执行完后的 nemu_state.state 状态值进行判断;

如果 nemu_state.state == NEMU_ABORT:说明程序处于 "中止" 状态,输出 "ABORT",并且使用 ANSI_FG_RED 红色格式化显示。
否则,检查 nemu_state.halt_ret:
如果 halt_ret == 0,表示程序正常终止(触发了 "GOOD TRAP"),输出 "HIT GOOD TRAP",并使用 ANSI_FG_GREEN 绿色显示。
如果 halt_ret != 0,表示程序遇到错误终止(触发了 "BAD TRAP"),输出 "HIT BAD TRAP",并使用 ANSI_FG_RED 红色显示。

再看(execute(n);):

static void execute(uint64_t n) {
  Decode s;
  for (;n > 0; n --) {
    exec_once(&s, cpu.pc);
    g_nr_guest_inst ++;
    trace_and_difftest(&s, cpu.pc);
    if (nemu_state.state != NEMU_RUNNING) break;
    IFDEF(CONFIG_DEVICE, device_update());
  }
}

这个 execute 函数的作用是在 NEMU 中执行模拟 CPU 的指令。它会循环执行传入的 n 条指令,并在每次执行后进行跟踪、差异测试和设备状态更新。

exec_once(&s, cpu.pc);

static void exec_once(Decode *s, vaddr_t pc) {
  s->pc = pc;
  s->snpc = pc;
  isa_exec_once(s);
  cpu.pc = s->dnpc;
#ifdef CONFIG_ITRACE
  char *p = s->logbuf;
  p += snprintf(p, sizeof(s->logbuf), FMT_WORD ":", s->pc);
  int ilen = s->snpc - s->pc;
  int i;
  uint8_t *inst = (uint8_t *)&s->isa.inst.val;
  for (i = ilen - 1; i >= 0; i --) {
    p += snprintf(p, 4, " %02x", inst[i]);
  }
  int ilen_max = MUXDEF(CONFIG_ISA_x86, 8, 4);
  int space_len = ilen_max - ilen;
  if (space_len < 0) space_len = 0;
  space_len = space_len * 3 + 1;
  memset(p, ' ', space_len);
  p += space_len;

#ifndef CONFIG_ISA_loongarch32r
  void disassemble(char *str, int size, uint64_t pc, uint8_t *code, int nbyte);
  disassemble(p, s->logbuf + sizeof(s->logbuf) - p,
      MUXDEF(CONFIG_ISA_x86, s->snpc, s->pc), (uint8_t *)&s->isa.inst.val, ilen);
#else
  p[0] = '\0'; // the upstream llvm does not support loongarch32r
#endif
#endif
}


http://www.kler.cn/a/392433.html

相关文章:

  • C++ 面向对象编程:继承、继承方式
  • rust windwos 两个edit框
  • 邮箱手机号脱敏
  • 跟我学c++中级篇——C++中的缓存利用
  • LangChain教程 - 表达式语言 (LCEL) -构建智能链
  • Nmap基础入门及常用命令汇总
  • C++总结
  • 【AI大模型】ELMo模型介绍:深度理解语言模型的嵌入艺术
  • Git - 命令杂谈 - reset、revert和clean
  • 容器docker的ulimit
  • 设备接入到NVR管理平台EasyNVR多品牌NVR管理工具/设备的音视频配置参考
  • Redis相关技术内容
  • 一条SQL查询语句的执行流程(MySQL)
  • 微信小程序进行md5加密 ,base64 转码
  • nuxt3添加wowjs动效
  • mysql 实现分库分表之 --- 基于 MyCAT 的分片策略详解
  • windows中docker安装redis和redisinsight记录
  • 什么时候用 Tailwind 什么时候用 CSS
  • 第 8 章 - Go语言 数组与切片
  • 大语言模型安全威胁
  • [Docker#3] LXC | 详解安装docker | docker的架构与生态
  • Three.js 纹理与网格的优化
  • Linux将二进制软件包编译成rpm软件包教程详解
  • unity3d————四元数的计算
  • 【每日推荐】使用 Ollama 平台上的 Llama 3.2-vision 模型进行视频目标检测
  • 【PGCCC】Postgresql Toast 原理