PA2.1实现dumy

  • 实现思路
  • 实验过程
    • 修改opcode_table数组
    • 修改rtl.h文件
    • 实现对应的操作
  • 实验结果

实现思路

在进行代码编写之前,最重要的就是阅读实验手册,确保自己真的理解了实验手册中的内容,再下手也不迟,正所谓磨刀不误砍柴工。PA2实验对我来说还是有一点点的新奇,因为自己并没有接触过编译,所幸自己对计算机组成原理有一点的学习,知道指令的执行和操作过程,理解起来也就变的容易很多啦。
首先,我先根据实验手册中的指示,阅读dumy-x86-nemu.txt文件,弄清楚自己需要实现的指令及指令代码。

00100000 <_start>:                                                                                                     100000:   bd 00 00 00 00          mov    $0x0,%ebp100005:   bc 00 7c 00 00          mov    $0x7c00,%esp10000a:   e8 01 00 00 00          call   100010 <_trm_init>10000f:   90                      nop 00100010 <_trm_init>:100010:   55                      push   %ebp100011:   89 e5                   mov    %esp,%ebp100013:   83 ec 08                sub    $0x8,%esp100016:   e8 05 00 00 00          call   100020 <main>10001b:   d6                      (bad)  10001c:   eb fe                   jmp    10001c <_trm_init+0xc>10001e:   66 90                   xchg   %ax,%ax00100020 <main>:100020:   55                      push   %ebp100021:   89 e5                   mov    %esp,%ebp100023:   31 c0                   xor    %eax,%eax100025:   5d                      pop    %ebp100026:   c3                      ret

根据这个文件列出所需要实现的操作指令:

指令 编码 Description
call e8 Call near, displacement relativeto next instruction
push 50 + rw /rb Push register word/dword
sub 83 Subtract sign-extended immediate byte from r/m word
xor 31 Exclusive-OR dword register to r/m word/dword
pop 58+rw/rb Pop top of stack into word/dword register
ret c3 Return (near) to caller

这里我介绍下我的debug之路

Created with Raphaël 2.2.0 Start 阅读i386手册 修改ics-pa/nemu/src/cpu/exec/exec.c中的opcode_able 修改ics-pa/nemu/include/cpu/rtl.h中的操作函数 实现ics-pa/nemu/src/cpu/* 中的操作函数 测试 测试是否通过 End yes no

(第一次用markdown画流程图。。有点丑,以后会慢慢改进的。。)

实验过程

修改opcode_table数组

首先在all-insert中添加所需要的指令名字:

make_EHelper(call);          // control.c
make_EHelper(push);         //data-mov.c
make_EHelper(sub);          //arith.c
make_EHelper(xor);          //logic.c
make_EHelper(pop);          //data-mov.c
make_EHelper(ret);          //control.c

修改opcode_table

/* 0x80, 0x81, 0x83 */                                                                                               make_group(gp1,   EX(add), EX(or), EX(adc), EX(sbb),EX(and), EX(sub),EX(xor), EX(cmp))/* 0xe8 */    IDEX(J,call), IDEX(J,jmp), IDEX(I,jmp_rm), IDEXW(J,jmp,1),
/* 0x50 */    IDEX(r,push), IDEX(r,push), IDEX(r,push), IDEX(r,push),
/* 0x54 */    IDEX(r,push), IDEX(r,push), IDEX(r,push), IDEX(r,push),
/* 0x58 */    IDEX(r,pop), IDEX(r,pop), IDEX(r,pop), IDEX(r,pop),
/* 0x5c */    IDEX(r,pop), IDEX(r,pop), IDEX(r,pop), IDEX(r,pop),
/* 0x30 */    IDEXW(G2E,xor,1), IDEX(G2E,xor), IDEXW(E2G,xor,1),IDEX(E2G,xor),
/* 0x34 */    IDEXW(I2a,xor,1), IDEX(I2a,xor), EMPTY, EMPTY,
/* 0xc0 */  IDEXW(gp2_Ib2E, gp2, 1), IDEX(gp2_Ib2E, gp2), IDEXW(I,ret,2), EX(ret),

修改rtl.h文件

  1. push和pop操作
    按i386手册和框架中给出的提示完成入栈和出栈的操作。
static inline void rtl_push(const rtlreg_t* src1) {// esp <- esp - 4rtl_subi(&cpu.esp,&cpu.esp,4);// M[esp] <- src1rtl_sm(&cpu.esp,src1,4);
}   static inline void rtl_pop(rtlreg_t* dest) {// dest <- M[esp]//*dest = vaddr_read(cpu.esp,4);rtl_lm(dest,&cpu.esp,4);// esp <- esp + 4//cpu.esp += 4;rtl_addi(&cpu.esp,&cpu.esp,4);
}
  1. 更新标志符操作
static inline void rtl_setrelopi(uint32_t relop, rtlreg_t *dest,const rtlreg_t *src1, int imm) {// dest <- (src1 relop imm ? 1 : 0)rtl_li(&at, imm);*dest = interpret_relop(relop, *src1, at);
}  static inline void rtl_msb(rtlreg_t* dest, const rtlreg_t* src1, int width) {// dest <- src1[width * 8 - 1]rtl_shri(dest, src1, width*8 - 1);
}
static inline void rtl_update_ZF(const rtlreg_t* result, int width) {// eflags.ZF <- is_zero(result[width * 8 - 1 .. 0])rtl_shli(&at, result, 32 - width * 8);if(at == 0) cpu.eflags.ZF = 1;else cpu.eflags.ZF = 0;
}  static inline void rtl_update_SF(const rtlreg_t* result, int width) {// eflags.SF <- is_sign(result[width * 8 - 1 .. 0])rtl_msb(&at, result, width);cpu.eflags.SF = at;
}

实现对应的操作

  1. call指令
    CALL:读取要压栈的eip值,然后用rtl_push压栈,然后设置跳转。
make_EHelper(call) {               // the target address is calculated at the decode stage// Don't forget to add push eiprtl_push(eip);                   rtl_j(decoding.jmp_eip);         print_asm("call %x", decoding.jmp_eip);
}
  1. push和pop指令
make_EHelper(push) {                    rtl_push(&id_dest->val);            print_asm_template1(push);
}   make_EHelper(pop) {                     rtl_pop(&id_src->val);              operand_write(id_dest,&id_src->val);print_asm_template1(pop);
}
  1. sub指令(参考sbb指令)
    在实现sub指令前需要写eflags结构体(这个根据i386进行编写即可。)
make_EHelper(sub) {          rtl_sub(&t2, &id_dest->val, &id_src->val);rtl_setrelop(RELOP_LTU, &t3, &id_dest->val, &t2);operand_write(id_dest, &t2);rtl_update_ZFSF(&t2, id_dest->width);rtl_setrelop(RELOP_LTU, &t0, &id_dest->val, &t2);rtl_or(&t0, &t3, &t0);rtl_set_CF(&t0);rtl_xor(&t0, &id_dest->val, &id_src->val);rtl_xor(&t1, &id_dest->val, &t2);rtl_and(&t0, &t0, &t1);rtl_msb(&t0, &t0, id_dest->width);rtl_set_OF(&t0);print_asm_template2(sub);
}

注意,还需要实现**static inline make_DopHelper(SI)**内的功能,这个按照注释实现就可以了。
4. xor指令

make_EHelper(xor) {rtl_xor(&id_dest->val, &id_dest->val, &id_src->val);operand_write(id_dest,&id_dest->val);rtl_li(&t0,0);rtl_set_CF(&t0);rtl_set_OF(&t0);//CF = OF = 0rtl_update_ZFSF(&id_dest->val, id_dest->width);print_asm_template2(xor);
}
  1. ret指令
make_EHelper(ret) {         rtl_pop(&decoding.jmp_eip);rtl_j(decoding.jmp_eip);print_asm("ret");
}

实验结果

PA2.1 运行dumy相关推荐

  1. c语言正则表达式_CS143:编译原理|PA2:正则表达式和词法分析

    本文使用 Zhihu On VSCode 创作并发布 这是本人实现斯坦福CS143变编程作业的笔记,对应第二次作业PA2.有关文章目录.环境搭建和一些说明请看第一篇:CS143:编译原理 | 环境搭建 ...

  2. PA2.2 PA2.3

    PA2.2 讲义中的问题 堆和栈在哪里? 首先明确什么是堆和栈: 栈(stack):是自动分配变量,以及函数调用所使用的一些空间(所谓的局部变量),地址由高向低减少; 堆(heap):由malloc, ...

  3. Git 教程 - Git 基本用法

    Git 是当前最流行的版本控制程序之一,文本包含了 Git 的一些基本用法 创建 git 仓库 初始化 git 仓库 mkdir project  # 创建项目目录  cd project  # 进入 ...

  4. 4、Lctech Pi(F1C200S)linux5.7.1移植在RAM运行修改默认调试串口为uart1(CherryPi,Mangopi,F1C100S)

    本次主要参考: http://nano.lichee.pro/build_sys/bootargs.html https://wiki.sipeed.com/soft/Lichee/zh/Nano-D ...

  5. 计算机组成原理实验---PA实验PA2.22.3

    目录 文章目录 目录 思考题 1.什么是 API 2.AM 属于硬件还是软件? 3.堆和栈在哪里? 4.回忆运行过程 5.神奇的`eflags` 6.这是巧合吗? 7.nemu的本质 8.设备是如何工 ...

  6. NEMU PA2实验思路

    PA2实验思路 版权归zzy所有,不许外传! 本文主要是提供PA2思路,为了避免踩了一堆坑而浪费时间.若想copy代码请移步他处,本文仅供学习交流用,谢谢! 阅读前请确保仔细阅读了PA2实验指导书的有 ...

  7. 南航 PA2.2PA2.3

    目录 思考题 1.什么是 API 2.AM 属于硬件还是软件? 3.堆和栈在哪⾥? 4.回忆运⾏过程 5.神奇的eflags(2) 6.这是巧合吗? 7.nemu的本质 8.设备是如何⼯作的? 9. ...

  8. spring boot项目 中止运行 最常用的几种方法

    spring boot项目 中止运行 最常用的几种方法: 1. 调用接口,停止应用上下文 @RestController public class ShutdownController impleme ...

  9. Docker安装Apache与运行简单的web服务——httpd helloworld

    Docker运行简单的web服务--httpd helloworld目录[阅读时间:约5分钟] 一.Docker简介 二.Docker的安装与配置[CentOS环境] 三.Docker运行简单的web ...

最新文章

  1. AI一分钟 | 搜狗王小川:今年重点战略是输入法升级和发展机器翻译;北京无人驾驶试验场下半年正式运营
  2. 松开手,你可以拥有更多
  3. STL中算法锦集(四)
  4. java kafka 多线程消费
  5. html如何播放h264视频,浏览器 – 我如何播放H264视频?
  6. 幼儿课外活动游戏_泰国清迈大小学校介绍 --【Little Star小星星幼儿园】
  7. JAVA分布式篇3——Dubbo
  8. ViewSwitcher用法浅析
  9. vue表格刷新数据_Vue.js的列表数据的同步更新方法
  10. 为什么我们拒绝使用 Docker
  11. Revit API切换三维视图
  12. DID 起步:图说去中心化身份 | ArcBlock 博客
  13. DOS的net命令详解
  14. 轻松打造自己的站内搜索引擎
  15. kubernetes入门之Downward API
  16. 花 3 分钟时间了解技术人应具备的思维能力 - 抽象
  17. 某猫电影 css 加密解决方案
  18. 线路负载及故障检测装置(2019全国大学生电子设计大赛C题:国家级一等奖)
  19. IE8浏览器Silverlight已被阻止解决办法
  20. 工具总结篇——vault

热门文章

  1. JavaScript语法糖的简析
  2. Elasticsearch和PHP
  3. DeFi收益来源全面概述
  4. NVIDIA Jetson 刷机大全
  5. java计算机毕业设计民宿运营管理网站源码+系统+mysql数据库+lw文档+部署
  6. Linux磁盘管理:lvcreate 常用命令
  7. python中nonlocal是什么意思_Python中的global和nonlocal
  8. 【redis6】redis6.2版本windows下载
  9. win10系统改变文本的默认打开方式
  10. 小鹏飞行汽车完成海外公开首飞;统一充电接口或让苹果每年损失百亿;Linus电脑内存问题致Linux 6.1补丁合并推迟|极客头条...