计算机取指令PA,PA 代码+笔记

如果有什么地方有误 请多多指教;

写这个不是让同学们直接抄的,请弄懂原理哦,我觉得我解释的蛮清楚了。

遇到了问题也可以评论留言或者私信我;

pa1代码➕思路17元,pa2代码+思路30元,pa3仙剑奇侠传仅代码自己看13元。扫码备注邮箱,一般立刻发,如果有事24小时内发。

935c93bc7db2d473040ce272ac00c420.png          d8fb13b271a88fe28054f6b10ca28217.png

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

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

讲义中提到使用union,前面知道CPU的寄存器是公用内存的,所以把gpr[8]结构体改成了union,但是实验报错,然后继续改,看到下面的eax,ecx之类的寄存器,于是在外面又套了一个union,但是还是报错,后来在网上搜,看到简书上面有一个解答,就是在eax,ecx之类的寄存器外面套一个struct,尝试之后成功了,但是原理不知道。

修改后的结构体:

7a35876e19484361822f984e495ccc2c.png

进入nemu:6d24d1eaa64a15710283d67c0c845db5.png

af50d861e8e68626acf377a7d26dc7c4.png

在cmd_c()函数中调用cpu_exec()传入参数-1,根据讲义,我在cpu_exec()看到如下:

3a2bc31fb250a5e67083033d44305156.png

建一个commit,恢复master暂存区文件到工作区,将pa0合并到当前分支,新建一个分支pa1。366ace7fb362a27e3fbffd10985f8c72.png

配置X Servier。安装结束后为SSH打开X11转发功能(每次);

虽然显示有error,但是马里奥可以玩。

NEMU是什么?

NEMU是一个虚拟出来的计算机系统,通过程序实现物理计算机的基本功能。

2)初识虚拟化。在Windows中使用Docker安装了一个GNU/Linux container,然后在container中完成PA,通过NEMU运行Hello World程序的层次图:

-------------------------------

“Hello World”program

-------------------------------

Simulated x86 hardware

--------------------------------

NEMU

--------------------------------

GNU/Linux

---------------------------------

Docker

----------------------------------

Computer hardware

1.2 开天辟地的故事

32位

8位

8位

16

1.3 RTFSC

思考题:一个程序是从main函数开始执行的。

实现正确的寄存器结构体。

究竟要执行多久?

n是无符号整型,所以-1就是无符号最大的数字,那么for循环可以执行最大次数的循环,而ecex_wrapper()函数就是执行%eip指向的当前指令并更新%eip。最终就可以执行完所有指令。

温故而知新

opcode_table数组是一个函数指针数组(helper函数),对应某条指令的某种形式。

return语句是返回结果,并终止当前函数。全局对象的析构函数会在main函数之后执行,用atexit注册的函数也会在main之后执行。main函数执行完之后还要去执行一些诸如释放空间之类的操作。Main函数结束时会隐式的调用exit()函数,运行时会执行由atexit()函数登记的函数,做一些清理,刷新所有输出流,关闭所有打开的流。所以应该是exit()函数指示吧。

证明在main函数返回后可以再执行的代码:

#include #include void fn1(void)

{

printf("next.\n");

}

int main(void)

{

atexit(fn1);

puts("This is executed first.");

return 0;

}

1.4 基础设施

解析命令

单步执行

1)在ui.c中看到:

71187016ed1bce63257ac5a7f9243a45.png

谁来指示程序的结束?

readline(),读取一行文本。

strtok(),根据给定的字符结点,将字符串分解成一段段的字符串。

sscanf(),根据字符串读入相符的数据

看了代码之后,就明白了是用readline读取文本行之后,用strtok()分解第一个字符串,与cmd_table[]中的name比较,执行对应的操作。

于是做如下变动:

fad9e7f67fe2c05ae71d1e17287dcf47.png

cmd_si函数读取字符串参数,用sscanf转化为相符的数据,执行对应指令。

46547f7398f022b12ad170fd91206b43.png

代码如下:

static int cmd_si(char *args){

char *arg = strtok(NULL," ");

int i=0;

if(arg == NULL){

cpu_exec(1);

return 0;

}

sscanf(arg,"%d",&i);

if(i

结果截图

cb78009fc9cf47f6e4d53036e1eeb140.png

cd5c58497c33ea56a9b7969376a99788.png

4ac228253e5eb1206c795737b16d66a9.png

打印寄存器

1)regsl[],32位寄存器,regsw[],16位寄存器,regsb[],8位寄存器。在前面实现寄存器的正确结构时知道cpu.gpr[i]._32是uint32_t地址。判断参数为r后输出32位寄存器的地址。

ff6a96fa4191b09384659e3a42fa0fc4.png

代码如下:

static int cmd_info(char *args)

{

char *arg=strtok(NULL," ");

if(strcmp(arg,"r")==0)  {

for(int i=0;i<8;i++) {

printf("%s %x %d\n",regsl[i],cpu.gpr[i]._32,cpu.gpr[i]._32);

}

}

return 0;

}

2)结果

04e12fb84c0d524d3cbdc55b7fb29e70.png

扫描内存

1)讲义中提到过vaddr_read()在memory.c中,查看如下:

d261190b2bb70804890cf52131c431b8.png

其实就是vaddr_read函数调用paddr_read,传入两个参数:起始地址,扫描长度。

所以我们通过strtok分别获得字符串型的地址和扫描长度,用sscanf转换为要求的形式,而后循环调用vaddr_read函数扫描内存。

4d0bd98760213889fc2ddb243b9d1104.png

代码如下:

static int cmd_x(char *args)

{

char *arg1=strtok(NULL," ");

char *arg2=strtok(NULL," ");

int len;

vaddr_t address;

sscanf(arg1,"%d",&len);

sscanf(arg2,"%x",&address);

printf("0x%x:",address);

for(int i=0;i

结果

6723b6dbed45baa7203c71378cd9f742.png

pa1全部代码7元,pa2全部代码15元。扫码备注邮箱。

935c93bc7db2d473040ce272ac00c420.png          d8fb13b271a88fe28054f6b10ca28217.png

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值