ics-pa1

南京航空航天大学 计算机科学与技术系学院 计算机组成原理 课程实验

PA1 - 开天辟地的篇章:最简单的计算机

1.1 在开始愉快的PA之旅之前

配置X Server

NEMU是什么?
NEMU是个x86模拟器,NEMU是用程序来实现一个计算机系统的功能, 并不是一个物理上的计算机.

初识虚拟化
“hello world” program
Nemu OS
Simulated x86 hardware
NEMU
GNU/Linux
Virtual hardware
VMware
Windows
Computer hardware

1.2 开天辟地的故事

存储器:存储程序和数据
CPU:执行指令,处理数据
寄存器:暂时存储CPU正在处理的数据
PC(程序计数器、EIP):控制CPU执行下一条命令
TRM(图灵机):有存储器 、PC、寄存器、加法器

1.3 RTFSC

在实现功能之前改了一下common.h文件

这样方便修改nemu输出提示信息的样式

需要多费口舌吗?
从程序开始执行的地方开始读:src/main.c 和 nemu/src/monitor/monitor.c
然后读包含的.h文件

对vim的使用感到困难?
可以学习vimtutor和vim键盘图

实现正确的寄存器结构体

32位、16位、8位寄存器物理上并非独立的,所以将其包含在同一共用体中
32位寄存器eax,ebx,ecx,edx,esp,esi,edp,edi之间相互独立,所以包含在同一结构体中
gpr与eax,ebx,ecx,edx,esp,esi,edp,edi都表示寄存器,所以指向同一内存地址,包含在一个共用体中
eip与寄存器与通用寄存器相互独立,所以最终包含在同一结构体中

查看nemu-log.txt

究竟要执行多久?

-1传到uint64变成了最大的数,在cmd_c()函数中, 调用cpu_exec()的时候传入了参数-1,所以依次获取、解码、执行所有指令

温故而知新
opcode-table是opcode-entry类型的数组,数组元素都是一个opcode-entry结构体元素

谁来指示程序的结束
指令集决定程序结束,程序在cpu执行完所有指令时结束,这里,程序在ui_mainloop()的返回处就已经结束

理解框架代码

1.4 基础设施

首先添加cmd_table[]

基础设施-简易调试器
基础设施 - 提高项目开发效率
手输gcc编译出NEMU可执行文件需要300秒,一学期完成PA需要150000秒约41小时

解析命令
man readline、man strtok

单步执行

打印寄存器

遇到问题:这里想实现当输入info不带参数时输出help info,打算调用cmd_help函数,但其源码

Strtok函数在这里是第二次调用形式,这样不管参数args是什么都会打印全部帮助文档

所以改成如下形式


函数全部代码

扫描内存(直接读pmem[]和使用vaddr_read()函数两种方法)
注意:用vaddr_read()函数时要知道内存存放多位信息时是小端存储,每读4位打印时要调一下顺序

1.5 表达式求值

数学表达式求值
首先识别表达式单元
然后根据表达式的归纳定义进行递归求值

词法分析
学习正则表达式
使用正则表达式识别token
在框架代码中添加正则表达式和token组成的二元组

遇到问题:检查时发现”\d+”并没有匹配到十进制数,改为”[0-9]+”可以匹配
系统设计的黄金法则–KISS法则
调试公理 多做单元测试 少写没有测试过的“错误代码”
实现算术表达式的词法分析
完善make_token()函数
首先判断一下从EXPR中解析出的token数量是否超出限制

对各种token的处理

识别负数和指针

递归求值
Eval()递归函数

检查括号匹配

寻找dominant operator

实现算术表达式的递归求值
实现了判断括号匹配的算法
实现带有负数的算术表达式的求值(选座)
区分负号和减号:
添加了NEGTIVE标记,make_token时可以识别SUB标记时进一步判断是否为NEGTIVE标记,在eval()中若dominant operator为NEGTIVE标记时则返回负数
单目运算符在分裂时要注意什么:
在eval()函数中先判断,若定位dominant operator找到的是单目运算符则按运算规则返回运算符结合后面表达式tokens的值,否则按教程中的方法处理二元运算符

调试中的表达式求值
扩展功能提前补全了
Expr()函数(指针解引用和负数识别没有放到这里)

遇到问题:测试expr()函数时发现多重括号的表达式求值时有bug,检查问题原因发现find_dominant_operator()函数中实现跳过括号功能的部分代码并不能跳过多重包含的括号,修改如下后解决问题

测试expr()函数

测试结果

Show_tokens()函数供排错使用

实现更复杂的表达式求值
从表达式求值窥探编译器
机器是怎么读懂你的代码的?
先用词法分析识别源码中的tokens,然后进行表达式的递归求值,即将源码翻译成机器码
词法分析的应用:编译器原理 语法高亮
表达式求值的应用:C代码生成汇编代码(递归实现)

1.6 监视点

监视点
实现监视点池的管理
Cmd_w()函数设置监视点

New_wp()从监视点池中返回一个空闲监视点结构

Cmd_d()函数删除监视点

Free_wp()将监视点归还到监视点池中


温故而知新(2)
定义wp_pool等变量时用了static关键字
含义:表示静态全局变量
为何在此处使用:static声明在本文件内都是可见的而在本文件外是不可见的,这里使用static是为了保护监视点内部信息不被外部使用造成错误
实现监视点
修改cpu_exec()函数

Check_wp()函数

检测断点功能

断点
一点也不能长?
随心所欲的断点
NEMU的前世今生

1.7 i386手册

i386手册
学会使用目录
尝试通过目录定位关注的问题

逐步细化搜索范围

必答题:

理解基础设施:

调试时间 500 90% 30s * 20 = 27000s = 7.5h

查阅i386手册:

EFLAGS寄存器中CF位是什么意思?
是寄存器状态标志,CF(bit 0) [Carry flag] 若算术操作产生的结果在最高有效位(most-significant bit)发生进位或借位则将其置1,反之清零。这个标志指示无符号整型运算的溢出状态,这个标志同样在多倍精度运算(multiple-precision arithmetic)中使用。
ModR/M字节是什么?
ModR/M,它占一个字节,其格式为:
7 6 5 3 2 0 Mod Reg/Opcode R/M
可见,ModR/M是由Mod、Reg/Opcode和R/M三个部分组成的。每个部分所占的bit大小为:
Mod: 占最高位的6~7共2个bit Reg/Opcode: 占中间位的3~5共3个bit R/M: 占最低位的0~2共3个bit
Mov指令具体格式是怎么样的?
MOV 指令的基本格式如下:
movx source, destination

source 和 destination 的值可以是内存地址,存储在内存中的数据值,指令语句中定义的数据值,或者寄存器。

Shell命令:

PA1后nemu/目录下共有多少行代码?

1
4086

使用的命令:

1
find . -name *.[ch] | xargs wc -l

PA1相对于框架代码增加了多少行代码?

1
2
3
185294 - 184695 = 599
git checkout pa0 && find . -name *.[ch] |xargs cat | wc -l
git checkout pa1 && find . -name *.[ch] |xargs cat | wc -l

除去空行还有多少代码?

1
2
3372
find . -name *.[ch] | xargs cat | grep -v ^$ | wc -l

实现make count功能

顺便提一下cloc是一个不错的统计代码工具

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
karl@debian:~/ics2017/nemu$ cloc .
85 text files.
85 unique files.
3 files ignored.

github.com/AlDanial/cloc v 1.70 T=0.32 s (258.9 files/s, 13587.5 lines/s)
-------------------------------------------------------------------------------
Language files blankcomment code
-------------------------------------------------------------------------------
C 31 565 224 2542
C/C++ Header 17 156 56 543
D 31 0 0 100
make 1 14 6 34
Bourne Shell 1 6 0 33
Markdown 1 2 0 23
-------------------------------------------------------------------------------
SUM: 82 743 286 3275
-------------------------------------------------------------------------------

使用man:

W(warning),-Wall(显示所有警告),-Werror(将所有警告视为error)

部分Git log:

×

纯属好玩

扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

文章目录
  1. 1. 南京航空航天大学 计算机科学与技术系学院 计算机组成原理 课程实验
  2. 2. PA1 - 开天辟地的篇章:最简单的计算机
    1. 2.1. 1.1 在开始愉快的PA之旅之前
    2. 2.2. 1.2 开天辟地的故事
    3. 2.3. 1.3 RTFSC
    4. 2.4. 1.4 基础设施
    5. 2.5. 1.5 表达式求值
    6. 2.6. 1.6 监视点
    7. 2.7. 1.7 i386手册
  3. 3. 必答题:
    1. 3.1. 理解基础设施:
    2. 3.2. 查阅i386手册:
    3. 3.3. Shell命令:
    4. 3.4. 使用man:
  4. 4. 部分Git log: