定义一个指令集体系结构,包括定义各种状态元素、指令集和它们的编码、一组编程规范和异常事件处理。
Y86处理器状态类似于I32。可以访问和修改程序寄存器、条件码、程序计数器和存储器,状态码指明程序是否运行正常。
RF:程序寄存器 %eax,%ecx,%edx,%ebx,%esi,%edi,%esp(出栈、入栈、调用和返回指令作为栈指针),%ebp CC:条件码 ZF、SF、OF(都是一位条件码,用来保存最近的算术或逻辑指令所造成影响的有关信息。) PC:程序计数器 存放当前正在执行的指令 DMEM:存储器 很大的字节数组,保存着程序和数据。Y86程序用虚拟地址来引用存储器位置。 Stat:程序状态码 它表明程序执行的总体状态。它会指示是正常运行还是出现了某种异常。
- IA32的movl指令分成了4个不同的指令:irmovl、rrmovl、mrmovl和rmmovl。分别显示地指明源和目的的格式。(源可以是立即数i,寄存器r,或存储器m;目的可以使寄存器r和存储器m。)两个存储器传送指令中的存储器引用方式是简单的基址和偏移量形式。在地址计算中,不支持第二变址寄存器和任何寄存器值的伸缩。同IA32一样,不允许从一个存储器地址直接传送到另一个存储器地址。也不允许将立即数传送到存储器。 - 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。
程序员可见的状态包括状态码stat描述程序执行的总体状态。
代码值 名字 含义
1 AOK 正常操作
2 HLT 处理器执行halt指令
3 ADR 遇到非法地址
4 INS 遇到非法指令
当遇到这些异常时可以简单的让处理器停止执行指令,在更完整的设计中,通常会调用一个异常处理程序,可配置不同的结果如放弃程序或者调用一个用户自定义的信号处理程序。
一些小示例:
以“.”开头的是汇编器命令,告诉汇编器调用地址。
.pos0 告诉汇编器应该从0地址开始产生代码,这个地址是所有Y86程序的起点 irmovl Stack,%esp 初始化栈指针 irmovl Stack,%ebp 初始化帧指针 结尾申明标号Stack(Stack:),用.pos指明地址0x100(.pos 0x100),栈会从这里开始向低地址增长。
声明一个4个元素的数组,标号array表示是这个数组的起始
.align 4 ;表明在四字节边界处对齐 array: .long 0xd .long 0xc0 .long 0xb00 .long 0xa000
YIS:指令集模拟器 目的是模拟Y86机器代码程序的执行,而不用试图去模拟任何具体的处理器实现的行为。
模拟输出的第一行总结了执行以及PC和程序状态的结果值,只打印出改变了的寄存器或存储器中的字,左边是原始值,右边是最终值。
pushl指令会把栈指针减4并且将一个寄存器的值写入存储器中,因此执行 pushl %esp时处理器的行为是不正确的,因为要入栈的寄存器会被同一条指令修改。有两种约定:
1 压入%esp的原始值 2 压入减去4的%esp的值
同样popl %esp 可以将%esp设置为从存储器中读出的值,也可以设置为加上4后的栈指针。
逻辑1:高压 逻辑0:低压
实现一个数字系统需要三个组成部分:
计算对位进行操作的函数的组合逻辑
存储位的存储器元素
控制存储器元素更新的时钟信号
HCL语言:描述不同处理器设计的控制逻辑。
逻辑门是数字电路的基本计算元素,输出为输入位值的某个布尔函数。
HCL表达式:
AND: && OR: || NOT: !
逻辑门只对单个位的数进行操作,而不是整个字。
常见的n路操作表示,例:AND门,输入为a,b,c,HCL表示为a&&b&&c
逻辑门总是活动的,一旦输入变化了,输出会相应的变化。
将很多的门组合成网构建计算块,称为组合电路
构建的两条限制:
两个或多个逻辑门的输出不能连接在一起,否则会使线上的信号矛盾
网必须是无环的,也就是不能形成一个回路
例:检测位相等的组合电路
bool eq = (a && b) || (!a && !b)
"="将一个信号名与一个表达式联系起来,和C不同,这不是执行了一次计算并将结果放入存储器中的某个位置,它只是用一个名字来称谓一个表达式。
例:多路复用器
单个位的多路复用器中,两个输入数据a、b,一个控制信号s。s=1输出为a,s=0输出为b
bool out = (s && a) || (!s && b)
组合逻辑电路和C表达式区别:
1 组合电路中输出会持续的响应输入的变化,C表达式只会在程序执行过程中被遇到时才进行求值。 2 C表达式允许参数是任意整数,0表示FALSE,其他都表示TRUE。逻辑门只对位值0和1操作。 3 C表达式可以只被部分求值,如果第一个参数求值就能确定不会求值第二个参数,而组合逻辑没有部分求值。
执行字级计算的组合电路根据输入字的各个位,用逻辑门来计算输出字的各个位。
例:测试32位字A和B是否相等
用32个单个位相等电路的输出用一个AND连起来实现。
HCL中所有字级信号都声明为int,不指定字的大小,上述电路可表达成
bool Eq = (A == B)
A和B都是int型的,‘=’为赋值,‘==’是相等运算符。
例:字级的多路复用电路,控制位s,32位的Out为A/B
32个位级多路复用器组成,其中只产生一次!s,重复使用。
HCL中,多路复用函数是用情况表达式描述的,通用格式如下:
[
select_1 : expr_1 select_2 : expr_2 : select_k : expr_k ] 布尔表达式和整数表达式,前者表明什么时候该选择,后者指明得到的值
同switch语句不同,这里不要求不同的选择表达式之间互斥,顺序求值,第一个求值为1的情况会被选中。
字级多路器HCL表示:
int Out = [ s: A; 1: B; ]; 第二个选择表达式为1,如果前面的没被选中就选这种情况,这是HCL中指定默认情况的方法,几乎所有的都是依次结尾。
选择表达式可以是任意的布尔表达式,可以有任意多的情况,书上还有四路复用器和找最小值的例子。
注:任何以#开头到行尾结束的文字都是注释。
组合逻辑电路可以设计成在字级数据上执行许多不同类型的操作。
例:算术/逻辑单元(ALU)
三个输入:A、B两个数据输入和一个控制输入,根据控制输入可执行不同的算术或逻辑操作,控制值和Y86指令操作的功能码相对应。
0 addl
1 subl
2 andl
3 xorl
例:从两位信号code中选择高位和低位
可以用相等测试来表示:
bool s1 = code == 2 || code == 3; bool s0 = code == 1 || code == 3;
用更简洁的集合关系表示:
bool s1 = code in {2,3}; bool s0 = code in {1,3};
判断集合关系的通用格式是:
iexpr in {iexpr1,iexpr2,...,iexprk} 被测试值 待匹配值 都是整数表达式
为了产生时序电路,引入按位存储信息的设备,存储设备由一个时钟控制,时钟是一个周期性信号,决定什么时候要把新值加载到设备中。两类存储器设备:
时钟寄存器:存储单个位或字,时钟信号控制寄存器加载输入值
随机访问存储器:存储多个字,用地址来选择该读或该写哪个字
在硬件中,寄存器直接将他的输入和输出线连接到电路的其它部分。在机器级编程中,寄存器代表的是CPU中为数不多的可寻址的字,这里的地址是寄存器ID,这两类称为“硬件寄存器”和”程序寄存器“
当时钟到达上升沿时,值才会从寄存器的输入传送到输出,Y86处理器会用时钟寄存器来保存程序计数器PC、条件代码CC和程序状态Stat。
例:寄存器文件
两个读端口A/B,一个写端口W。电路可以读两个程序寄存器的值同时更新第三个寄存器的状态。每个端口都有一个地址输入,表明该选择哪个程序寄存器,地址是寄存器标识符。读端口有地址输入srcA和srcB和数据输出valA和valB,写端口有地址输入dstW和数据输入valW。
读数据:以地址为输入,以数据为输出,当srcA或srcB被设成某个寄存器的ID,存储在寄存器中的值会出现在valA或valB上。
写入字:由时钟信号控制,时钟上升时,输入valW上的值会被写入输入dstW上的寄存器ID对应的程序寄存器中。ID为0xF时,不会写入任何程序寄存器中。
例:随机访问存储器
一个地址输入,一个写的数据输入,一个读的数据输出。
读:输入address上提供地址,write控制信号设为0,存储在地址上的值会出现在输出data上。
写:将address设置为期望的地址,data in设置为期望的值,write设置为1,时钟上升沿时会更新存储器中指定的位置。
如果地址不合法,error会被设置为1。
SEQ处理器顺序处理,每个时钟周期上,SEQ会执行一条完整指令,这需要很长的时钟周期,因此时钟周期频率会很低,最终目标是事项一个高效的、流水线化的处理器。
把每条指令组织成特殊的阶段序列,各个阶段通用框架:
取指:从存储器读取指令字节,地址为程序计数器PC的值。 指令指示符字节的两个4位为icode指令代码和ifun指令功能。还可能有寄存器指示符和四字节常数字。 按顺序方式计算下一条指令的地址valp=PC+已取出指令的长度。 译码:从寄存器文件读入最多两个操作数读入指令rA、rB指明的寄存器或%esp。 执行:算术逻辑单元ALU执行操作或计算存储器引用的有效地址,增加或减少栈指针,也可能设置条件码。 访存:将数据写入存储器或者从存储器读数据。 写回:最多可以写两个结果到寄存器文件。 更新PC:将PC设置成下一条指令的地址。
处理器无限循环执行这些指令。异常:执行halt或非法指令,非法地址。完整的设计中有异常处理模式。
具体示例:
1、OPl整数和逻辑运算、rrmovl寄存器-寄存器传送、irmovl立即数-寄存器传送
2、存储器读写指令rmmovl/mrmovl
3、入栈出栈指令pushl/popl
4、三类控制转移指令:各种跳转、call和ret
在硬件结构的抽象表示中信息流从最低端先向上再向右,同各个阶段相关的硬件单元负责执行处理。在右边,反馈线路向下,包括要写到寄存器文件的更新值,以及更新的程序计数器的值。
硬件单元与各个处理阶段相关联:
取指
译码
执行
访存
写回
硬件图的画图惯例:
浅灰色方框表示硬件单元
控制逻辑块是用灰色圆角矩形表示的
线路的名字在白色椭圆中说明
宽度为字长的数据连接用中等粗度的线表示
宽度为字节或更窄的数据连接有细线表示
单个位的连接用虚线来表示
一个时钟变化会引发一个经过组合逻辑的流来执行整个指令。
SEQ的实现包括组合逻辑和两种存储器设备:
时钟寄存器:程序计数器和条件码寄存器
随机访问存储器:寄存器文件、指令存储器和数据存储器
组合逻辑不需要时序或控制。
四个硬件单元需要时序进行明确控制:程序计数器、条件码寄存器、数据存储器和寄存器文件,通过一个时钟信号来控制,它触发将新值装载到寄存器以及将值写到随机访问存储器。即要控制处理器中的时序,只需要寄存器和存储器的时钟控制。
一条重要原则:
处理器从来不需要为了完成一条指令的执行而去读由该指令更新了的状态。
课本上还有具体的示例来说明这条原则。
在控制逻辑中必须被显式引用的常数:(常数值都是大写的)
nop指令只是简单的经过各个阶段,除了将PC加1,不进行任何处理。halt指令是处理器状态被设置为HLT,导致处理器停止运行。
1、取指阶段
以PC作为起始地址,从指令存储器中读出六个字节。
根据这些字节,产生出各个指令字段。PC增加模块计算信号valP。
2、译码和写回阶段
指令字段译码,产生寄存器文件使用的四个地址(两个读和两个写)的寄存器标识符。
从寄存器文件中读出的值成为信号valA和valB。两个写回值valE和valM作为写操作的数据。
3、执行阶段
ALU要么为整数运算指令执行操作,要么作为加法器。
根据ALU的值,设置条件码寄存器。检测条件码的值,判断是否该选择分支。
4、访存阶段
数据存储器既可以写,也可以读存储器的值。从存储器读出的值就形成了信号valM。
5、更新PC阶段
根据指令代码和分支标志,从信号valC、valM和valP中选出下一个PC的值。