ICS PA1
首先是实验需要准备的Debian虚拟机11.03,我用的VMware装的,装的时候碰到了不少坑,后续再讲开篇介绍了CPU的寄存器结构,大二的时候上计算机组成原理这门课大致听过一些相关内容,同时在《CSAPP》第三章上有相关内容的体现,实验中只介绍了32位寄存器(EAX、EBX、ECX、EDX)以及32位之下寄存器的介绍,但是目前现有的已经是64位寄存器(RAX、RBX…)。前辈引入指令这个概念,来
ICS PA实验启
首先是实验需要准备的Debian虚拟机11.03,我用的VMware装的,装的时候碰到了不少坑,后续再讲
PA1:
开篇介绍了CPU的寄存器结构,大二的时候上计算机组成原理这门课大致听过一些相关内容,同时在《CSAPP》第三章上有相关内容的体现,实验中只介绍了32位寄存器(EAX、EBX、ECX、EDX)以及32位之下寄存器的介绍,但是目前现有的已经是64位寄存器(RAX、RBX…)。
前辈引入指令这个概念,来告诉CPU如何对数据进行处理,同时很容易可以想到,我们可以自行设计指令来使CPU自动运行我们写出来的程序。如何告诉COU执行哪里的指令呢?,前人引入了程序计数器(program counter,PC)这个概念,在x86中叫EIP
while (1) {
从EIP指示的存储器位置取出指令;
执行指令;
更新EIP;
}
后续还介绍了相关加法器,计数器,本科没有接触过任何电路知识的我略显慌张…任重而道远嘛~
NEMU框架介绍:
ics2021
├── abstract-machine # 抽象计算机
├── am-kernels # 基于抽象计算机开发的应用程序
├── fceux-am # 红白机模拟器
├── init.sh # 初始化脚本
├── Makefile # 用于工程打包提交
├── nemu # NEMU
└── README.md
我们主要关注nemu部分:
Monitor(监视器)模块是为了方便地监控客户计算机的运行状态而引入的. 它除了负责与GNU/Linux进行交互(例如读入客户程序)之外, 还带有调试器的功能, 为NEMU的调试提供了方便的途径. 从概念上来说, monitor并不属于一个计算机的必要组成部分, 但对NEMU来说, 它是必要的基础设施. 如果缺少monitor模块, 对NEMU的调试将会变得十分困难.
nemu
├── configs # 预先提供的一些配置文件
├── include # 存放全局使用的头文件
│ ├── common.h # 公用的头文件
│ ├── config # 配置系统生成的头文件, 用于维护配置选项更新的时间戳
│ ├── cpu
│ │ ├── cpu.h
│ │ ├── decode.h # 译码相关
│ │ ├── difftest.h
│ │ ├── exec.h # 执行相关
│ │ └── ifetch.h # 取指相关
│ ├── debug.h # 一些方便调试用的宏
│ ├── device # 设备相关
│ ├── difftest-def.h
│ ├── generated
│ │ └── autoconf.h # 配置系统生成的头文件, 用于根据配置信息定义相关的宏
│ ├── isa.h # ISA相关
│ ├── macro.h # 一些方便的宏定义
│ ├── memory # 访问内存相关
│ ├── rtl
│ │ ├── pseudo.h # RTL伪指令
│ │ └── rtl.h # RTL指令相关定义
│ └── utils.h
├── Kconfig # 配置信息管理的规则
├── Makefile # Makefile构建脚本
├── README.md
├── resource # 一些辅助资源
├── scripts # Makefile构建脚本
│ ├── build.mk
│ ├── config.mk
│ ├── git.mk # git版本控制相关
│ └── native.mk
├── src # 源文件
│ ├── cpu
│ │ └── cpu-exec.c # 指令执行的主循环
│ ├── device # 设备相关
│ ├── engine
│ │ └── interpreter # 解释器的实现
│ ├── filelist.mk
│ ├── isa # ISA相关的实现
│ │ ├── mips32
│ │ ├── riscv32
│ │ ├── riscv64
│ │ └── x86
│ ├── memory # 内存访问的实现
│ ├── monitor
│ │ ├── monitor.c
│ │ └── sdb # 简易调试器
│ │ ├── expr.c # 表达式求值的实现
│ │ ├── sdb.c # 简易调试器的命令处理
│ │ └── watchpoint.c # 监视点的实现
│ ├── nemu-main.c # 你知道的…
│ └── utils # 一些公共的功能
│ ├── log.c # 日志文件相关
│ ├── rand.c
│ ├── state.c
│ └── timer.c
└── tools # 一些工具
├── fixdep # 依赖修复, 配合配置系统进行使用
├── gen-expr
├── kconfig # 配置系统
├── kvm-diff
├── qemu-diff
└── spike-diff
接下来在x86中有个assertion fail,但我选的是riscv32好像没有这个坑,具体讲就是需要把32位,16位的gtr数组结构体改成匿名union,因为匿名union能够同时共享内存,符合x86架构的32位,16位、8位访问
接着实现简易调试器,因为代码都封装好了,给出了模拟CPU运行的函数 cpu_exec,所以我们在sdb.c中进行cmd_si函数的定义以及编写就可了
static int cmd_si(char *args){
char *arg=strtok(args," ");
if(arg==NULL)
{
printf("too few arguments\n");
return 1;
}
int n=atoi(arg);
cpu_exec(n);
return 0;
}
主要的就是strtok函数的使用
char *strtok(char *str, const char *delim)
str – 要被分解成一组小字符串的字符串。
delim – 包含分隔符的 C 字符串。
C 库函数 char *strtok(char *str, const char *delim) 分解字符串 str 为一组字符串,delim 为分隔符。
注意:首次调用时,str指向要分解的字符串,之后再次调用要把str设成NULL
实现打印寄存器
因为本次选的是riscv32架构,和x86架构不一样,所以讲义中给出的x86架构对我们来说没有意义了,只能翻看源码来寻找相关结构,发现在isadef.h文件中找到了类似于riscv32 32个寄存器的结构体,我们模仿x86的色剂,将32个寄存器名字放进struct里,并且和之前的gpr[32]数组合并成一个union,这样可以一起访问共同内存。
typedef struct {
union{
struct {
rtlreg_t _32;
} gpr[32];
struct{rtlreg_t $0, ra, sp, gp, tp, t0, t1, t2,
s0, s1, a0, a1, a2, a3, a4, a5,
a6, a7, s2, s3, s4, s5, s6, s7,
s8, s9, s10, s11, t3, t4, t5, t6; };
};
vaddr_t pc;
} riscv32_CPU_state;
更多推荐
所有评论(0)