定义一个指令集体系结构,包括定义各种状态元素、指令集和它们的编码、一组编程规范和异常事件处理。
Y86处理器状态类似于I32。可以访问和修改程序寄存器、条件码、程序计数器和存储器,状态码指明程序是否运行正常。
RF:程序寄存器 %eax,%ecx,%edx,%ebx,%esi,%edi,%esp(出栈、入栈、调用和返回指令作为栈指针),%ebp
CC:条件码 ZF、SF、OF(都是一位条件码,用来保存最近的算术或逻辑指令所造成影响的有关信息。)
PC:程序计数器 存放当前正在执行的指令
DMEM:存储器 很大的字节数组,保存着程序和数据。Y86程序用虚拟地址来引用存储器位置。
Stat:程序状态码 它表明程序执行的总体状态。它会指示是正常运行还是出现了某种异常。
指令编码长度从1个字节到6个字节不等,一条指令含有一个单字节的指令指示符,可能含有一个单字节的寄存器指示符,还可能含有一个四字节的常数字。字段fn指明是某个整数操作(OPL)、数据移动条件(cmovXX)或是分支条件(jXX)。所有数值都用十六进制表示
IA32的movl指令分成了4个不同的指令:irmovl、rrmovl、mrmovl和rmmovl。分别显示地指明源和目的的格式。
源操作数: 立即数i、寄存器r、存储器m
目的操作数: 寄存器r、存储器m
两个存储器传送指令中的存储器引用方式是简单的基址和偏移量形式。
4个整数操作指令
addl、subl、andl、xorl
7个跳转指令(jXX)
jmp、jle、jl、je、jne、jge、jg
有6个条件传送指令(cmovXX)
cmovle、cmovl、cmove、cmovne、cmovge、cmovg
只有当条件码满足所需要的约束时,才会更新目的寄存器的值。
halt指令停止指令的执行。对于Y86来说,执行halt指令会导致处理器停止,并将状态码设置为HLT。
每条指令的第一个字节表明指令的类型。这个字节分为两个部分,每部分4位:高4位是代码部分,低4位是功能部分。功能值只有在一组相关指令共用一个代码时才有用。
- 整数操作里代码部分均为6,功能部分区分addl,subl,andl,xorl
- 分支指令里代码部分均为7
- 传送指令里代码部分均为2
程序寄存器存在一个寄存器文件中,这个寄存器文件就是一个小的、以寄存器ID作为地址的随机访问存储器。当需要指明不应访问任何寄存器时,用ID值0xF表示。
有的指令需要一个附加的4字节常数字,可作为:irmovl的立即数数据,rmmovl和mrmovl的地址指示符偏移量,分支指令和调用指令的目的地址。
注意:
- 分支指令和调用指令的目的地址是一个相对地址,而不是相对寻址方式。
- 所有整数采用小端法编码。当指令按反汇编格式书写时这些字节就以相反的顺序出现。
指令集的一个重要性质就是字节编码必须有唯一的解释。这个性质保证了处理器可以无二义性地执行目标代码程序。即使代码嵌入在程序的其他字节中,只要从序列的第一个字节开始处理,我们仍然可以很容易地确定指令序列。反过来说,如果不知道一段代码序列的起始位置,我们就不能准确地确定怎样将序列划分成单独的指令。
创建Y86代码的唯一工具是汇编器。
指令集模拟器YIS
- 目的:模拟Y86机器代码程序的执行,而不用试图去模拟任何具体处理器实现的行为。
- 有助于在实际硬件可用之前调试程序,也有助于检查模拟硬件或者在硬件上运行程序的结果。
要实现一个数字系统需要三个主要的组成部分:
- 计算对位进行操作的函数的组合逻辑
- 存储位的存储器元素
- 控制存储器元素更新的时钟信号
逻辑门产生的输出,等于它们输入位值的某个布尔函数。
AND &&
OR ||
NOT !
逻辑门只对单个位的数进行操作,而不是整个字。
逻辑门总是活动的,一旦一个门的输入变化,在短时间内,输出就会跟着变化。
将逻辑门组合成一个网,构建计算块(组合电路)的限制
两个以上的逻辑门的输出不能连接在一起,否则可能使线上信号矛盾,导致一个不合法的电压或电路故障。
这个网必须是无环的,否则会导致网络计算有歧义。
组合逻辑电路和c语言中逻辑表达式都是用布尔操作来对输入进行计算的函数。
区别:
- 组合电路的输出会持续地响应输入变化,c语言表达式只有在执行过程中被遇到才求值
- C的逻辑表达式允许参数是任意整数,0是FALSE,其他任何值0的都是TRUE,逻辑门只对位值0和1操作。
- C的逻辑表达式可能被部分求值(第一个参数就能确定结果的就不会对第二个求值)
多路复用函数用情况表达式来描述
通用格式:
[
select_1(布尔表达式):expr_1(整数表达式)
select_2:expr_2
......
select_k:expr_k
]
- 从逻辑上讲,这些选择表达式是顺序求值的。
- 第一个求值为1的情况会被选中
- 选择表达式允许不互斥
组合逻辑电路可以设计成在字级数据上执行许多不同类型的操作。
判断集合关系的通用格式:
iexpr in {iexpr1,iexpr2,...,iexprk}
- 被测试的值iexpr和带匹配的值iexpr1~iexprk都是整数表达式。
时序电路的两类存储器设备
- 时钟寄存器(寄存器):储存单个位或字,用时钟信号控制寄存器加载输入值。
- 随机访问储存器(储存器):储存多个字,用地址选择该读/写哪个字。
在大多数实际系统中,这两个存储器被合并为一个具有双端口的存储器:一个用来读指令,一个用来读或写数据。
SEQ 顺序处理器
每个时钟周期上,SEQ执行一条完整指令所需的所有步骤
六个基本阶段
- 取指 从存储器读取指令字节,地址为程序计数器PC的值
- 译码 从寄存器读入最多两个操作数,得到valA或valB
- 执行 算术/逻辑单元要么执行指令指明的操作,计算存储器引用的有效地址,要么增加或减少栈指针。得到的值为valE。
- 访存 将数据写入存储器,或从存储器中读出数据,读出的值为valM。
- 写回 最多可以写两个结果到寄存器文件
- 更新PC 将PC设为下一条指令的地址
-SEQ抽象视图
在SEQ中,所有硬件单元的处理都在一个时钟周期内完成
单个位的连接用虚线
SEQ的实现包括组合逻辑和两种存储器设备
时钟寄存器 程序计数器和条件码寄存器
随机访问存储器 寄存器文件、指令存储器和数据存储器
组织计算原则
处理器从来不需要为了完成一条指令的执行而去读由该指令更新了的状态。
用时钟来控制状态元素的更新,值通过组合逻辑传播。
取指阶段
以PC为第一个字节的地址,一次读6个字节。
icode 控制逻辑块计算指令
ifun 功能码
三个一位的信号(根据icode值计算)
instr_valid 发现不合法的指令
need_regids 包含寄存器指示符字节吗
need_valC 包括常数字吗
执行阶段
包括算数/逻辑单元(ALU),输出为valE信号。
ALU通常作为加法器使用
包括条件码寄存器
每次运行产生:
零、符号、溢出、产生信号set_cc
- 管理复杂性是首要问题,尽量保持硬件设计的简单。
- 不需要直接实现ISA。
- 一开始就保证设计正确是非常重要的。
相关的两种形式
- 数据相关 下一条指令会用到这条指令计算出的结果;
- 控制相关 一条指令要确定下一条指令的位置,例如在执行跳转、调用或返回指令时,这些相关可能会导致流水线产生计算错误,称为冒险。同相关一样,冒险也可以分为两类:数据冒险和控制冒险。
这个逻辑必须处理以下4种控制情况,这些情况是其他机制(例如数据转发和分支预测)不能能处理的:
处理ret 流水线必须暂停直到ret指令到达写回阶段。
加载/使用冒险 流水线必须暂停一个周期。
预测错误的分支 在分支逻辑发现不应该选择分支之前,分支目标处的几条指令已经进流水线了。必须从流水线中去掉这些指令。
异常 当―条指令导致异常,我们想要禁止后面的指令更新程序员可见的状态,并睏异常指令到达写回阶段时,停止执行。
cd ~/Code/shiyanlou_cs413
wget http://labfile.oss.aliyuncs.com/courses/413/sim.tar
tar -xvf sim.tar
cd sim
sudo apt-get install tk
sudo ln -s /usr/lib/x86_64-linux-gnu/libtk8.6.so /usr/lib/libtk.so
sudo ln -s /usr/lib/x86_64-linux-gnu/libtk8.6.so /usr/lib/libtk.so
make
进入测试代码 cd y86-code
进行汇编 make asuml.yo
汇编所有代码结果 make all
1.实验楼构建实验环境的时候输入
wget csapp.cs.cmu.edu/2e/sim/tar
一直显示
解决:有同学问了这个问题,老师把输入的地址更改了,又做了一下,可以连接了
2.YIS模拟器
下载到我电脑上的虚拟机之后make命令显示‘asuml.yo’ is up to date.
参考资料1:深入理解计算机系统
参考资料2:(实验楼)深入理解计算机系统:实验五
参考资料3:ubuntu12.04 安装CS:APP Y86模拟器