Linux第五次学习笔记

处理器体系结构

Y86指令集体系结构

定义一个指令集体系结构 ,包括定义各种状态元素、指令集和它们的编码、一组编程规范和异常事件处理。

程序员可见的状态

  • Y86程序中的每条指令都会读取或修改处理器状态的某些部分。
  • 程序员:
    • 1.用汇编代码写程序的人。
    • 2.产生机器级代码的编译器。
  • 类似IA32,存在8个程序寄存器。
  • 3个一位的条件码:ZF、SF、OF
  • 程序计数器PC存放当前正在执行指令的地址
  • 存储器,保存程序和数据。Y86用虚拟地址来引用存储器位置
  • 状态码Stat,表明程序执行的总体状态——可行or异常

Y86指令

  • movl指令:
    • irmovl
    • rrmovl
    • mrmovl
    • rmmovl
    • 第一个字母表示源的类型,第二个字母表示目的的类型
    • i-立即数 r-寄存器 m-存储器
  • OPl(整数操作指令):
    • addl
    • subl
    • andl
    • xorl
    • 只对寄存器数据进行操作,不对存储器数据进行操作
    • 将会设置ZF(zero flag)、SF(sign flag)、OF(over flag)
  • 跳转指令:
    • jmp 跳转
    • jle 有符号≤
    • jl 有符号<
    • je 相等/零
    • jne 不相等/非零
    • jge 有符号≥
    • jg 有符号>
  • cmovXX(条件传送指令):
    • cmovle
    • cmovl
    • cmove
    • cmovne
    • cmovge
    • cmovg
    • 仅当条件码满足所需要的约束时,才会更新目的寄存器的值。
    • 需注意条件传送只发生在两个寄存器之间,不会将数据传送到存储器。
  • call:
    • 将返回地址入栈,跳到目的地址
  • ret:
    • 返回地址入PC,并跳到返回地址
  • pushl和popl:
    • 入栈和出栈操作
  • halt:
    • 这个指令将会终止指令的执行。

指令编码

  • 每条指令的第一个字节表明指令的类型
    • 该字节分为两个部分,每个部分4位
      • 高4位是代码部分,取值范围0~0xB
      • 低4位是功能部分
    • 传送指令 代码部分为2
    • 整数部分 代码部分为6
    • 分支指令 代码部分为7
  • 8个程序寄存器每个都有相应的0~7的寄存器标识符
    • 0 —— %eax
    • 1 —— %ecx
    • 2 —— %edx
    • 3 —— %ebx
    • 4 —— %esp
    • 5 —— %ebp
    • 6 —— %esi
    • 7 —— %edi
    • F —— 无寄存器
  • 有些指令需要一个附加的4字节常数字,这个字能作为irmovl的立即数数据mrmmovl和mrmovl的抵制指示符的偏移量,以及分支指令和调用指令的目的地址。(!分支指令和调用指令的目的地址是一个绝对地址)
  • Y86的重要性质:字节编码必须有唯一的解释。

IA32和Y86的不同 详见p235

Y86异常

  • 状态码Stat:
    • AOK —— 程序执行正常
    • HLT —— 处理器执行halt指令
    • ADR —— 遇到非法地址
    • INS —— 遇到非法指令

Y86程序

  • Y86代码与IA32代码的主要区别在于:它可能需要多条指令来执行一条IA32指令所完成的功能。
  • 在Y86代码中,以“.”开头的词为汇编器命令,它们告诉汇编器调整地址,以便在那儿产生代码或插入一些数据
YIS(指令模拟器)
  • 目的是模拟Y86机器代码程序的执行,而不用试图区模拟任何具体处理器实现的行为。
  • 模拟输出的第一行总结了执行以及PC和程序状态的结果值。
  • 模拟器只打印出在模拟过程中被改变了的寄存器或存储器中的字。左边是原始值,右边是最终值。

一些Y86指令的详情

  • pushl 把栈指针减4,并且将一个寄存器值写入存储器。
  • pushl %esp时,处理器的行为是不确定的,通常有两种约定:
    • 压入%esp的原始值
    • 压入减去4的%esp的值

逻辑设计和硬件控制语言HCL

  • 要实现一个数字系统需要三个主要的组成部分:
    • 计算对位进行操作的函数的组合逻辑
    • 存储位的存储器元素
    • 控制存储器元素更新的时钟信号
  • HCL
    • 它是一种文本表示,用来描述硬件结构而不是程序行为的。
    • 最常用的语言是verilog,类似C语言
    • 另一种是VHDL,类似Ada

逻辑门

  • 逻辑门是数字电路的基本计算元素。
  • 它们的输出,等于它们输入位值的某个布尔函数。
  • 只对单个位的数进行操作。
    • 所以三个输入的AND门,输入为a、b和c,用HCL表示就是a&&b&&c。
C语言中运算符的逻辑门对应的HCL表达式
  • AND —— &&
  • OR —— ||
  • NOT —— !

组合电路和HCL布尔表达式

  • 将很多的逻辑门组合成一个网,就能构建计算块,称为组合电路。
  • 构建需要两条限制:
    • 两个或多个逻辑门的输出不能连接在一起。否则它们可能会使线上的信号矛盾,可能会导致一个不合法的电压或电路故障;
    • 这个网必须是无环的。也就是在网中不能有路径经过一系列的门而形成一个回路,这样的回路会导致该网络计算的函数有歧义。

多路复用器(MUX)

  • 可以根据输入控制信号的值,从一组不同的数据信号中选出一个。

字级的组合电路和HCL整数表达式

  • 我们设计能对数据字进行操作的电路,有一些位级信号,代表一个整数或一些控制模式。
  • 执行字级计算的组合电路根据输入字的各个位,用逻辑门来计算输出字的各个位。
  • 在HCL中,我们将所有字级的信号都声明为int,不指定字的大小。
  • 在HCL中,多路复用函数是用情况表达式来描述的。
    • 其通用格式为:

        [
      select_1 : expr_1 # words
      select_2 : expr_2 # words
      .
      .
      .
      select_k : expr_k # words
      ]
      select 表明什么时候该选择这种情况
      expr 指明得到的值
      words 表示注释,跟在#后

算术/逻辑单元(ALU)

  • 根据函数输入的设置,该电路会执行四种算术和逻辑运算中的一种

集合关系

  • 判断集合关系的通用格式:
    • iexpr in {iexpr1,iexpr2,iexpr3,····,iexprk} 此处被测试的值iexpr和待匹配的值iexpr1~iexprk都是整数表达式。
    • 例如bool s1 == code in { 2,3 } 等同于 bool s1 = code == 2 || code == 3

存储器和时钟

  • 组合电路从本质上是不存储任何信息,仅是响应输入信号,产生等于输入的某个函数的输出。
  • 时序电路
    • 有状态并且在这个状态进行计算的系统。
    • 为实现该电路,必须引入按位存储信息的设备。
    • 存储设备由同一个时钟控制,时钟是一个周期性信号。
  • 两类存储器设备:
    • 时钟寄存器(简称寄存器)存储单个位或字。时钟信号控制寄存器加载输入值。
      • 注意区别硬件寄存器和程序寄存器
    • 随机访问存储器(简称存储器)存储多个字,用地址来选择该读或该写哪个字。

寄存器文件

  • 其有两个读端口(A和B),一个写端口(W)。
  • 可随机访问存储器允许同时进行多个读和写操作。
  • 寄存器文件不是组合电路,因为它有内部存储。
  • 向寄存器文件写入字是由时钟信号控制的,控制方式类似于将值加载到时钟寄存器。
  • 在大多数实际系统中,存在具有双端口的存储器:一个用来读指令,另一个用来读或写数据。

Y86的顺序实现

将处理组织成阶段(六个基本阶段)

  • 取指(fetch):取指阶段从存储器读取指令字节,地址位程序计数器(PC)的值。
  • 译码(decode):译码截断从寄存器文件读入最多两个操作数,得到值valA和valB。
  • 执行)(exectue):算术/逻辑单元(ALU)要么执行指令指明的操作(根据ifun的值),计算存储器引用的有效地址,要么增加或减少栈指针。得到的值为valE。
  • 访存(memory):可以将数据写入存储器,或者从存储器独处数据。独处的值位valM。
  • 写回(write back):写回截断最多可以写两个结果到寄存器文件。
  • 更新PC(PC update):将PC设置成下一条指令的抵制。
  • 处理器无限循环,执行这些阶段。
  • 当发生异常时,处理器就会停止。完整的设计中,处理器还将进入异常处理模式,开始执行由异常的类型决定的特殊代码。

Y86指令OPl,rrmovl,irmovl在顺序实现中的计算:

Linux第五次学习笔记

icode:ifun表明指令字节的两个组成部分,rA:rB表明寄存器指示符字节的两个组成部分。符号M1[x]表示访问存储器位置x处的一个字节,而M4[x]表示访问四个字节

Y86指令存储器读写指令rmmovl和mrmovl所需处理:

Linux第五次学习笔记

Y86指令pushl和popl所需处理:

Linux第五次学习笔记

Y86指令三类控制转移指令所需处理:

Linux第五次学习笔记

SEQ硬件结构

硬件单元与各个处理阶段相关联:

  • 取值:将程序计数器寄存器作为地址,指令存储器读取指令的字节。PC曾佳琪计算valP,即增加了的程序计数器。
  • 译码:寄存器文件有两个度端口A和B,从这两个端口同时读寄存器值valA和valB。
  • 执行:执行截断会根据指令的类型,将算术/逻辑单元(ALU)用于不同的目的。对整数的操作,它要执行指令所指定的运算。对其他指令,它会作为一个加法器来计算增加或减少栈指针,或者计算有效地址,或者只是简单地加0,将一个输入传递到输出。
  • 访存:在执行访存操作,数据存储器独处或写入一个存储器字。指令和数据存储器访问的是相同的存储器位置,但是用于不同的目的。
  • 写回:寄存器文件由两个写端口。端口E用来写ALU计算出来的值,而端口M用来写从数据存储器中读出的值。

SEQ画图惯例

  • 浅灰色方框表示硬件单元。
  • 控制逻辑块用灰色圆角矩形表示的。
  • 线路的名字在白色圆角方框中说明。
  • 宽度为字长的数据连接用中等粗度的线表示。
  • 宽度为字节或更窄的数据连接用细线表示。
  • 单个位的连接用许仙来表示。

SEQ的时序

  • 时间寄存器(程序计数器和条件码寄存器)
  • 随机访问存储器(寄存器文件、指令存储器和数据存储器)
  • 组合逻辑补需要任何时序或控制
  • 程序计数器、条件码寄存器、数据存储器和寄存器文件需要对它们的时序进行明确的控制
    • 每个时钟周期,程序计数器都会装在新的指令地址。
    • 只有在执行整数运算指令时,才会装在条件码寄存器。
    • 只有在执行rmmovl、pushl、call指令时,才会写数据存储器。
    • 寄存器端口的两个写端口允许每个时钟周期更新两个程序寄存器,可用特殊的寄存器ID 0xF作为端口地址,来表示在词端口不应该执行写操作。

保持等价性的原则:

处理器从来不需要为了完成一条指令的执行而取读由该指令更新了的状态。

SEQ阶段的实现

基本的内容与Y86阶段的一致,细节的差异查看教材p263以后的相应内容。

实验练习

根据指令输入

Linux第五次学习笔记

得到结果如下

Linux第五次学习笔记

遇到的问题

在对于Y86模拟器进行安装时,make后出现cannot find -lfl。在答疑小组找到了同样问题的同学,参照老师您给出的解决方法,安装了flex,但再一次make后的结果提示cannot find -ltk cannot find -ltcl。此问题在答疑小组中也有同学出现并提出疑问,链接在此http://group.cnblogs.com/topic/73191.html,我也试着百度下解决问题的方法,得到的结果是缺少libxxx.o,但我不知道需要怎么来填补这个缺少的文件。截至blog发出时,此问题还未解决,劳老师您费心帮忙找到解决的方法。

参考资料

1.《Computer.Systems.A.Programmer's.Perspective.2nd.CN》教材

2.《X86的孪生兄弟,Y86指令体系结构》左潇龙的技术博客 http://www.cnblogs.com/zuoxiaolong/p/computer21.html?utm_source=tuicool&utm_medium=referral

上一篇:我和Lua并非一见钟情,我们期待着日久生情(相遇篇)


下一篇:分布式锁 基于Redis