CSAPP学习笔记 -- 第四章 处理器体系结构(一)

前言

一个处理器支持的指令和指令的字节集编码称为他的指令集体系结构。
 
为什么要了解处理器设计
  • 从智力方面来讲,处理器设计有趣且重要
  • 理解处理器如何工作能够帮助理解整个计算机系统如何工作
  • 虽然很少有人设计处理器,但是很多人设计包含处理器的硬件系统
  • 我们的工作可能就是处理器设计
 
本章背景
  • 数字硬件设计
  • 基于第二章对布尔代数和位级操作的讨论
  • 硬件控制语言HCL
 
本章顺序
  1. 基于顺序操作、功能正确但不实用的Y86-64处理器
  2. 流水线化的处理器
 
 
4.1 Y86-64指令集体系结构

4.1.1 程序员可见的状态
程序员可见状态
  • Y86-64程序中的每条指令都会读取或修改处理器状态的某些部分
  • 这里的“程序员”既可以是用汇编代码写程序的人,也可以是产生机器级代码的编译器
 
Y86-64状态与x86-64类似
  • 寄存器除了没有%r15,其余一样
  • 3个条件码:ZF零标志、SF符号标志、OF溢出标志
  • 程序计数器PC
  • 内存
    • 概念上来讲是一个很大的字节数组
    • Y86-64用虚拟地址引用内存位置,硬件和操作系统将其翻译成物理(实际)地址
  • 状态码Stat,表明程序执行的总体状态。
 
4.1.2 Y86-64指令
Y86-64指令集基本上是x86-64指令集的一个子集,只有8字节整数操作,称之为‘字’
 
Y86-64指令相关
  • movq分成了四个指令irmovq,rrmovq,mrmovq,rmmovq分别显式地指明了源和目的地址的格式,内存引用方式是简单的基址和偏移量形式,不支持第二变址寄存器和寄存器值的伸缩,同样的,Y86-64不允许从内存到内存的传送
  • 有4个整数操作指令:addq,subq,andq,xorq,只对寄存器数据进行操作,这些指令设置3个条件码
  • 有7个跳转指令:jmp,jle,jl,je,jne,jge,jg
  • 有6个条件传送指令:cmovle,cmovl,cmove,cmovne,cmovge,cmovg,格式与rrmovq一样但仅当条件码满足条件时才会更新目的寄存器的值
  • call指令将返回地址入栈,然后跳到目的地址,ret指令返回
  • pushq和popq指令实现了入栈和出栈
  • halt指令停止指令的执行(和x86-64的hlt一样),处理器停止,并将状态码设置成HLT
 
4.1.3 指令编码
指令的字节级编码
  • 每条指令需要1-10字节
  • 第一个字节表明指令的类型
    • 高四位是代码部分
    • 第四位是功能部分
  • 15个寄存器都有与之相对应的寄存器标识符(与x86-64相同)
  • 那些只需要一个寄存器操作数的指令将另一个寄存器指示符设为0xF
  • 一个附加的8字节的常数字,这个字能作为irmovq的立即数数据,也可以作为rmmovq和mrmovq的地址指示符的偏移量,以及分支指令和调用指令的目的地址
  • 分支指令和调用指令的目的是一个绝对地址(简单)
  • 小端法
  • 指令集的一个重要性质就是字节编码必须有唯一的解释
    • 任意一个字节序列要么是一个唯一的指令序列的编码,要么就不是一个合法的字节序列
    • 这个性质保证了处理器可以无二义地执行目标代码程序
 
4.1.4 Y86-64异常
状态码Stat
  • 对于Y86-64,当遇到这些异常时,简单的让处理器停止执行指令
  • 在更完整的设计中,处理器常会调用一个异常处理程序
 
4.1.5 Y86-64程序
  • Y86-64将常数加载到寄存器(第2~3行),因为它在算术指令中不能使用立即数
  • 要实现从内存读取一个数值并将其与一个寄存器相加,Y86-64代码需要两条指令(第8~9行),而x86-64只需要一条addq指令(第5行)
  • subq指令(第11行)同时还设置了条件码
 
  • 在这个程序中,以“.”开头的词是汇编器伪指令(assembler directives),它们告诉汇编器调整地址,以便在那儿产生代码或插入一些数据。伪指令.pos0(第2行)告诉汇编器应该从地址0处开始产生代码。这个地址是所有Y86-64程序的起点。接下来的一条指令(第3行)初始化栈指针。我们可以看到程序结尾处(第40行)声明了标号stack,并且用一个.pos伪指令(第39行)指明地址0x200。因此栈会从这个地址开始,向低地址增长。我们必须保证栈不会增长得太大以至于覆盖了代码或者其他程序数据。
  • 程序的第8~13行声明了一个4个字的数组,值分别为0x000d000d000d000d,0x00c000c000c000c00,x0b000b000b000b00,0xa000a000a000a000标号array表明了这个数组的起始,并且在8字节边界处对齐(用.align伪指令指定)。第16~19行给出了“main”过程,在过程中对那个四字数组调用了sum函数,然后停止。
  • 正如例子所示,由于我们创建Y86-64代码的唯一工具是汇编器,程序员必须执行本来通常交给编译器、链接器和运行时系统来完成的任务。幸好我们只用Y86-64来写一些小的程序,对此一些简单的机制就足够了。
 
仔细研究
 
4.1.6 一些Y86-64指令的详情
pushq指令会把栈指针减8,并且将一个寄存器值写入内存中。因此,当执行pushq rsp指令时,处理器的行为是不确定的,因为要入栈的寄存器会被同一条指令修改。通常有两种不同的约定:1)压入rsp的原始值,2)压入减去8的rsp的值。
 
 
4.2 逻辑设计和硬件控制语言HCL

4.2.1 逻辑门
 
4.2.2 组合电路和HCL布尔表达式
组合电路:多个逻辑门的组合
  • 每个逻辑门的输入必须连接到下述选项之一
    • 一个系统输入(称为主输入)
    • 某个存储器单元的输出
    • 某个逻辑门的输出。
  • 两个或多个逻辑门的输出不能连接在一起
    • 否则它们可能会使线上的信号矛盾,可能会导致一个不合法的电压或电路故障。
  • 这个网必须是无环的
    • 也就是在网中不能有路径经过一系列的门而形成一个回路,这样的回路会导致该网络计算的函数有歧义。
 
多路复用器
  • 根据输入控制信号的值,从一组不同的数据信号中选出一个
 
HCL表达式和C语言中逻辑表达式的不同点
  • 组合电路的输入变化,在一定的延迟之后,输出也会发生变化
    • C表达式只在程序执行过程中被遇到时才会求值
  • C逻辑表达式允许参数是任何整数,0表示False,其余表示True
    • 逻辑门只对位值0/1进行操作
  • C逻辑表达式可能只对部分求值(短路原理)
    • 逻辑门只是简单地响应输入的变化
 
4.2.3 字级的组合电路和HCL表达式
执行字级计算的组合电路根据输入字的各个位,用逻辑门来计算输出字的各个位
 
在HCL中,我们将所有字级信号都声明为int,不指定字的大小(为了简单)。在全功能的硬件描述语言中,每个字都可以声明为有特定的位数
 
多路复用器在HCL中是用情况表达式来描述的,不同的选择表达式之间不互斥,实际的硬件多路复用器的信号必须互斥
 
算术/逻辑单元ALU
  • 三个输入:数据A、数据B、控制输入
 
4.2.4 集合关系
 
4.2.5 存储器和时钟
为了产生时序电路(sequential circuit),也就是有状态并且在这个状态上进行计算的系统,我们必须引入按位存储信息的设备。存储设备都是由同一个时钟控制的,时钟是一个周期性信号,决定什么时候要把新值加载到设备中。
  • 时钟寄存器(简称寄存器)存储单个位或字。时钟信号控制寄存器加载输入值
  • 随机访问存储器(简称内存)存储多个字,用地址来选择该读或该写哪个字
 
寄存器
  • 在硬件中,(硬件)寄存器直接将它的输入和输出线连接到电路的其他部分。
  • 在机器级编程中,(程序)寄存器代表的是CPU中为数不多的可寻址的字,这里的地址是寄存器ID。
 
寄存器文件
  • 两个读端口,一个写端口
  • 每个端口都有一个地址输入,表明该选择哪个程序寄存器,另外还有一个数据输出或对应该程序寄存器的输入值
  • 虽然寄存器文件不是组合电路,因为它有内部存储
  • 向寄存器文件写入字是由时钟信号控制的,控制方式类似于将值加载到时钟寄存器。每次时钟上升时,输入valW上的值会被写入输入dstw上的寄存器ID指示的程序寄存器。当dstw设为特殊的ID值0xF时,不会写任何程序寄存器
 
随机访问存储器
posted @ 2020-08-18 15:52  Yoke_cc  阅读(542)  评论(0编辑  收藏  举报