第五周
Y86指令集体系结构
定义一个指令集体系结构,包括定义各种状态元素、指令集和它们的编码、一组编程规范和异常事件处理。
程序员可见状态
Y86处理器状态类似于I32。可以访问和修改程序寄存器、条件码、程序计数器和存储器,状态码指明程序是否运行正常。
RF:程序寄存器 %eax,%ecx,%edx,%ebx,%esi,%edi,%esp(出栈、入栈、调用和返回指令作为栈指针),%ebp
CC:条件码 ZF、SF、OF(都是一位条件码,用来保存最近的算术或逻辑指令所造成影响的有关信息。)
PC:程序计数器 存放当前正在执行的指令
DMEM:存储器 很大的字节数组,保存着程序和数据。Y86程序用虚拟地址来引用存储器位置。
Stat:程序状态码 它表明程序执行的总体状态。它会指示是正常运行还是出现了某种异常。
Y86指令
IA32指令集的一个子集,只包括四字节整数操作。寻址方式比较少,操作也比较少。
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
只有当条件码满足所需要的约束时,才会更新目的寄存器的值。
call指令将返回地址入栈,然后跳到目的地址。ret指令从这样的过程调用中返回。
pushl和popl指令实现了入栈和出栈。
halt指令停止指令的执行。对于Y86来说,执行halt指令会导致处理器停止,并将状态码设置为HLT。
指令编码
每条指令的第一个字节表明指令的类型。这个字节分为两个部分,每部分4位:高4位是代码部分,低4位是功能部分。功能值只有在一组相关指令共用一个代码时才有用。
整数操作里代码部分均为6,功能部分区分addl,subl,andl,xorl
分支指令里代码部分均为7
传送指令里代码部分均为2
8个程序寄存器中每个都有相应的0~7的寄存器标识符。
程序寄存器存在一个寄存器文件中,这个寄存器文件就是一个小的、以寄存器ID作为地址的随机访问存储器。当需要指明不应访问任何寄存器时,用ID值0xF表示。
没有寄存器操作数(分支指令和call指令),就没有寄存器指示符字节。
只需要一个寄存器操作数的指令(irmovl、pushl、popl),将另一个寄存器指示符设为0xF。
一个附加的4字节常数字,可作为:irmovl的立即数数据,rmmovl和mrmovl的地址指示符偏移量,分支指令和调用指令的目的地址。
注意:
分支指令和调用指令的目的地址是一个相对地址,而不是相对寻址方式。
所有整数采用小端法编码。当指令按反汇编格式书写时这些字节就以相反的顺序出现。
Y86异常
Y86状态码
出现异常时Y86处理器停止运行指令。可以调用一个异常处理程序使其更完整。
Y86程序
Y86代码与IA32代码的主要区别:
Y86可能需要多条指令来执行一条IA32指令所完成的功能。
Y86没有伸缩寻址模式。
命令指明应该将代码或数据放在什么位置,以及如何对齐。这个程序详细说明了栈的放置、数据初始化、程序初始化和程序结束等问题。
以“.”开头的词是汇编命令,他们告诉汇编器调整地址,以便在那儿产生代码或插入一些数据。
创建Y86代码的唯一工具是汇编器。
指令集模拟器YIS
二. 逻辑设计和硬件控制语言HCL
要实现一个数字系统需要三个主要的组成部分:
计算对位进行操作的函数的组合逻辑
存储位的存储器元素
控制存储器元素更新的时钟信号
逻辑门
AND &&
OR ||
NOT !
逻辑门只对单个位的数进行操作,而不是整个字。
组合电路和HCL布尔表达式
储器来存储程序数据。
处理器还包括另外一个只读存储器,用来读指令。
在大多数实际系统中,这两个存储器被合并为一个具有双端口的存储器:一个用来读指令,一个用来读或写数据。
Y86的顺序实现
SEQ 顺序处理器
每个时钟周期上,SEQ执行一条完整指令所需的所有步骤
六个基本阶段
- 取指 - 译码 - 执行 - 访存 - 写回 - 更新PC
SEQ
-SEQ抽象视图
程序计数器放在寄存器中
信息沿线流动
各个阶段相关的硬件单元负责执行这些处理
反馈线路包括要写到存储器文件的更新值,以及更新的程序计数器值
在SEQ中,所有硬件单元的处理都在一个时钟周期内完成
画图惯例
浅灰色方块表示硬件单元
控制逻辑块是用灰色圆角矩形表示的
线路的名字在白色椭圆中说明
宽度为字长的数据连接用中等粗度的线表示
宽度为字节或更窄的数据连接用细线表示
单个位的连接用虚线
SEQ的时序
SEQ的实现包括组合逻辑和两种存储器设备
时钟寄存器 程序计数器和条件码寄存器
随机访问存储器 寄存器文件、指令存储器和数据存储器
组合逻辑不需要任何时序或控制
由于指令存储器只用来读指令,我们可以将这个单元看成是组合逻辑
剩下四个(程序计数器、条件码寄存器、数据存储器和寄存器文件)需要对他们的时序进行明确的控制。
条件码寄存器 只在执行整数运算指令时装载
数据存储器 只在执行rmmovl、pushl或call时写入
寄存器文件 两个写端口允许每个时钟周期更新两个程序寄存器。(特殊寄存器ID 0xF表明此端口不应执行写操作)
组织计算原则
处理器从来不需要为了完成一条指令的执行而去读由该指令更新了的状态。
用时钟来控制状态元素的更新,值通过组合逻辑传播。
取指阶段
以PC为第一个字节的地址,一次读6个字节。
icode 控制逻辑块计算指令
ifun 功能码
三个一位的信号(根据icode值计算)
instr_valid 发现不合法的指令
need_regids 包含寄存器指示符字节吗
need_valC 包括常数字吗
后五个字节是寄存器指示符字节和常数字的组合编码。
译码和写回阶段
都需要访问寄存器文件,根据四个端口的情况,判断应该读哪个寄存器产生信号valA、valB。
寄存器文件,支持同时进行两个读和两个写,每个端口有一个地址连接(寄存器ID)和一个数据连接(32根线路),既可以作为寄存器文件的输出字,又可以作为他的输入字。
执行阶段
包括算数/逻辑单元(ALU),输出为valE信号。
ALU通常作为加法器使用
包括条件码寄存器
每次运行产生:
符号、溢出、产生信号set_cc
访存阶段
读或者写程序数据。
两个数据块产生存储器地址和存储器输入证据的值,两个产生控制信号表明应该是读还是写。当执行读操作时,数据存储器产生valM。
根据icode,imem_error,instr_valid,dmem_error,从指令执行的结果计算状态码Stat。
更新PC阶段
产生程序计数器的新值,依据指令的类型和是否要选择分支,新的PC可能是valC、valM或者valP。
实验
构建环境
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