关于体系结构基础(以MIPS为例)的简要介绍。学习记录随笔。以MIPS的视角来学习计算机体系结构。内容从静态流水线到动态流水线,会包括TLB,CACHE等内容。
- 数据相关的指令不能并行执行
- 寄存器的数据相关比较容易判断
- 存储器的数据相关不容易判断(转出虚拟地址之后通过TLB转成物理地址再判断)
比较源操作数寄存器,后续每个阶段的是否与目标寄存器的一致,控制前面的阶段继续(但会阻塞)
- 在EX阶段的运算结果出来后直接送到后续指令的EX阶段
- LW 要阻塞,可以通过调度减少阻塞
reg名字相关会引起。
reg名字相关会引起。
- 使用专门的地址运算部件把地址计算提前到译码阶段可以少等一拍
- 使用转移指令DELAY SLOT,可以不用等待
有例外处理了才能跑OS
例外是每个模块都要加东西,不是一个专门的模块来处理例外。所以在编写流水线的时候就要考虑例外。
例外要考虑周全
- I/O请求:外部中断
- 指令例外:用户请求指令
- 系统调用,断点,跟踪调试指令
- 运算部件
- 整数运算溢出,浮点异常
- 存储管理部件
- 访存地址不对齐,用户访存系统空间,TLB失效,缺页,存储保护错(写只读页)
- 保留指令错:未实现指令
- 硬件错
- etc.
- 取指:访存例外(没找到指令)
- 译码:保留指令、中断指令如Trap,Syscall
- 执行:整数溢出,浮点异常(如除零),etc.
- 访存:访存意外
- 其他:外部中断,可能在任何时候发生
- 同步与异步(如敲键盘)
- 用户请求与系统强制
- 可屏蔽与不可屏蔽
- 指令内(除法溢出)与指令间(敲键盘)
- 可恢复与结束
发生例外的前面的指令要给他执行完,发生例外的后面指令不给他执行。
- store指令要保证前面没有发生例外,发生例外不能让store写
- 多条指令发生例外,要优先处理最前面的例外
- 延迟槽指令发生例外:
- 处理完后要退回到跳转分支指令
- 任何一级流水发生例外时,在流水线中记录下发生例外的事件,直到WB阶段再处理
- 如果再EX阶段要修改机器状态(如状态寄存器),保留下来直到WB阶段再修改,如果是MEM阶段,是STORE,要写值,要看WB的指令有没有发生例外,如果发生了,则STORE不能写。
- 指令的PC值随指令流水前进到WB阶段例外处理专用
- 外部中断作为IF的例外处理
- 指定一个通用寄存器中的某一个为例外处理时保留PC值专用 (告诉OS哪条指令发生了例外,发生了什么例外)
- 发生例外的指令在WB阶段时:
- 保留该指令的PC(也在WB阶段),有些机器还保留其状态
- 设置PC值为例外处理程序入口地址(都是操作系统的地址)
- 定点ALU
- 定点乘法
- 浮点ALU
- 浮点乘法
- 访存
- 定点ALU 1 拍,
- 定点乘法2拍
- 浮点ALU 4 拍
- 浮点乘法7拍
- 访存部件延迟不确定(CACHE不命中、访存总线竞争、动态存储器刷新等原因),每次只能一个操作(内部不流水)
- 访存部件不流水引起多个访存操作的等待
- 结果总线相关:不同功能部件的延迟不一致。定点ALU操作的MEM周期就是为了避免结果总线冲突的stall操作
- 即使多端口写也会阻塞
- 读数总在较前的ID阶段
- 有些操作需要多拍产生结果
- FORWARDING的作用也很有限
- 例外处理更加困难,例外发生难以意料
- 比较目标寄存器号与源寄存器号
- 通过请求与仲裁允许流水线前进
- 不管指令执行多少拍,都要顺序写回寄存器,而且所有例外在写回阶段进行统一处理
每条指令时钟周期数,是目前最重要的指标。 = 理想CPI + 结构相关+ 3种数据相关 +控制相关
用在编译器。改变有相关性的指令的执行顺序。
过度展开Cache会放不下,所以要把控展开的幅度。
是乱序执行处理器的关键特性。把程序中的寄存器名映射到大量的内部物理寄存器。 条件执行的问题是不管条件是否成立,都必须给这些指令中的寄存器分配相应的物理寄存器。但内部物理寄存器的可用性是影响乱序处理器的关键性能资源。 消除假相关之后可以进行编译调度(改变指令从次序)。
存储单元的重命名比较困难。
- 只有访存指令与访存指令之间才有存储器相关性。
- 执行之后也有可能导致速度没有之前的快(Cache放不下了)。
例如双发射结构。一次发射2条指令。
- 要有特定的机制来保证程序行为不被改变
- 关键是程序的数据与结构相关性得以保持
- 硬件调度一般只能在百条指令的范围内进行调度
- 可以掌控软件编译时还不明确的相关性信息。尤其是对访存相关与控制相关。
- 与软件调度是互补的。
- 在译码阶段把指令“隔开”来解决相关
- 只要有1条指令停止,后面指令就不能前进,像是一种译码部件的结构相关
- 对编译要求高,最好是编译把相关指令隔开
- 有些信息在译码时难以确定,如:是否发生例外、访存操作需要多少周期等。
- 基本思想:有序进入,乱序执行,有序结束
- 前面指令的等待不影响后面指令继续前进
- 把相关的解决尽量往后拖延(用的时候再判断相关)
- 把译码阶段分为2个阶段:发射和读操作数
- 发射:指令译码,检查结构相关(如2条除法指令接续过来,要等)
- 读操作数:如果操作数准备好就读数,否则等待(在哪等?)-->(添加一个空间让他们等待,不要堵住后面的指令?)
- 当一条指令在读操作数阶段等待时,后面指令的发射可以继续进行
- 乱序执行的基本做法:
- 指令进入是有序的
- 执行可以乱序,只要没有相关就可以执行,多条指令同时执行
- 结束也是有序的(精确例外)(如何把乱序变成有序?) --->(有个队列来给指令排好队,让他们有序结束)
- 与静态调度相比
- 有些相关编译无法检测,编译器更加简单、程序性能对机器依赖少。
有了这些,WAW 与WAR相关不用阻塞了。可以彻底消除。
- 每个功能部件的输入端有一些**寄存器**。(微结构寄存器,软件读不了,硬件自用)
- 每个寄存器(包括功能部件输入端的寄存器以及通用寄存器)都记录一个功能部件号,指定它当前接收到哪个功能部件的值。
- 每个功能部件的输出接到每个功能部件的输入。
- 支持猜测性执行
-
**保留站/保留队列(微结构重命名寄存器)**内容:
-
Busy:忙位
-
Op:操作码
-
Vj,Vk:源操作数的值
-
Qj,Qk:保存没有准备好的源操作数的保留站号(0表示操作数已经准备好了。)
-
作用:
- 有序变乱序,指令等待的地方
- 重命名寄存器的作用,消除假相关。
-
-
结构寄存器增加1个域:
- 结果状态域:空表示寄存器值可用,否则保存产生寄存器结果的保留站号
-
结果总线:
- 除了送回结果值以外,还要送回产生该结果的保留站号
Tomasulo小结:
- 通过动态调度缓解流水线阻塞
- 例如减少cache失效对性能的影响
- 保留站:重命名寄存器+缓存源操作数
- 避免寄存器成为瓶颈
- 避免假相关阻塞
- 缺点:
- 硬件复杂性
- 结果总线成为瓶颈,多条结果总线增加硬件复杂度
- **精确例外的要求:**再处理例外时,发射例外指令前面的所有指令都哦执行完,例外发生之后的指令都未执行。
- 非精确例外的原因:再乱序执行时,前面的指令发生例外时,后面的指令已经执行完并修改了寄存器或存储单元
- Tomasulo算法与计分板都是非精确例外
- 只要保证后面的指令修改机器状态时,前面的指令都已不会发生例外即可。
执行的结果先不写回寄存器,确定前面不会发生例外,再写回结构寄存器里面去。
- 处理方法一:把后面指令对机器状态的修改延迟到前面指令都已经执行完
- 有些指令在EX阶段也修改机器状态,如运算指令修改结果状态。
- 在i执行阶段停止流水线会影响后面的指令执行。
- 处理方法二:可以用一些微结构缓冲器来临时保存执行结果,当前面的所有指令执行完之后,再把保存在缓冲器中的结果写回到寄存器或存储器。
- 在流水线修改机器状态时(在执行或者写回阶段),写到缓冲器
- 增加**提交(Commit)**阶段,把缓冲器中的内容写回到寄存器或者存储器。
- 提交阶段只有前面指令都结束才能进行。
- 有序提交:乱序执行,有序结束。
- 所用的缓冲器常被称为***Record Buffer(ROB)***
- 在**猜测执行(?)**中也用到上述机制
- 都是在 某些情况不确定下先执行,但留有反悔的余地。
内容:目标地址(存数地址或寄存器号)、值、操作类型
写回时写回到ROB。因此,后面的指令有可能从ROB中读取操作数
使用ROB作为重命名号(原来使用保留站号),一条指令的结果寄存器被重命名为其结果ROB号
- 保留站重命名源寄存器号
- ROB重命名结果寄存器号
提交时把结果写回寄存器或存储器,如果其他寄存器要读新值,要去读ROB的值
只要一条指令没有提交,它就不会对寄存器或存储器的内容进行修改,在一条指令没有提交之前,很容易取消该指令(由于前面指令发生了例外或者由于猜测执行不正确)
ROB可以和WriteBuffer合并
- 发射:把操作队列的指令根据操作类型送到保留站(如果保留站以及ROB有空),并且在ROB中指定一项作为临时保存该指令结果之用;发射过程中读寄存器的值与结果状态域,如果结果状态域指出结果寄存器已被重命名到ROB,则读ROB。
- 执行:如果所需的操作数都准备好,则执行,否则根据结果ROB号侦听结果总线并且接受结果总线的值
- 写回:把结果送到结果总线,释放保留站;ROB根据结果总线修改相应项
- 提交:如果队列中第一条指令的结果以及写回并且没发生例外,把该指令的结果从ROB协会到寄存器或者存储器,释放ROB的相应项。如果队列头的指令发生例外或是猜测错误的转移指令,清除操作队列以及ROB等。
防止一堵堵一大片。
- 乱序执行的关键技术
- 动态调度流水线数据通路
- 保留站的组织
- 寄存器与保留站的关系
- 寄存器重命名方法
- 多发射结构数据通路
- 指令缓存结构:
- 独立保留站:每个运算部件都有一个
- 组保留站: 定点一个、浮点一个
- 全局保留站:所有共用一个
- 读取寄存器内容时间
- 保留站前读
- 保留站后读
- 寄存器重命名的方法
- 重命名寄存器和物理寄存器分开
- 重命名寄存器与物理寄存器合并
- 独立保留站:
每个保留站项数较少,只要一个写端口和一个读端口。输出选择比较简单。**但是利用率低,闲的闲死,忙的忙死甚至引起堵塞。**结果总线送到所有保留站,连线长,结果写回可能需要单独一拍,(决定CPU主频目前是连线的长度。)
- 组保留站:
每个保留站项数较多,每个保留站需要多个写入端口,多个读端口,保留站读出可能需要单独一拍。效率较高。**结果总线不用送到每个功能部件。**一般划分时考虑定点、浮点、访存。
- 全局保留站:
保留站项数很多。读出写入端口都很多。读出时间长,保留站控制很复杂。效率高。结果总线只送回到全局保留站。
- 保留站前读寄存器
- 保留站中有值域,较复杂
- 操作数没准备好就读寄存器,保留站侦听总线结果
- 有序发射
寄存器的输出作为保留站的输入。
- 操作数没有准备好就读寄存器,保留站侦听结果总线获取没写回的值
- 有序读寄存器
- 保留站值的来源:寄存器、重命名寄存器、进入保留站时侦听、进入保留站后侦听
- 保留站中有值域,因此比较复杂
- 寄存器读端口数为发射宽度
- 保留站后读寄存器
- 保留站中无值域
- 操作数全部准备好之后才能读寄存器
- 乱序发射
保留站的输出作为寄存器的输入
- 保留站确信所有值都已经准备好后再写回寄存器,有可能有前递的情况。
- 乱序读寄存器
- 保留站中没有值域,只存寄存器号,寄存器只要读一遍,写一遍
- 寄存器读端口数为相应功能部件
- 双重作用:
- 例外或转移猜测错误时取消后面的操作
- 解决假相关
- 核心思想
- 一个操作写寄存器时重命名到其他寄存器
- 一个操作结束时再写到结构寄存器
多种多样
- 软件重命名
- 重命名到保留站
- 重命名到ROB
- 重命名到发射队列
- ==重命名寄存器与结构寄存器不分开:==建立物理寄存器到逻辑寄存器的映射(主流)(老的,即为使用过的逻辑寄存器在提交之后就可以释放给别的指令使用)
- 这种重命名的好处(比起重命名到ROB):省功耗。【每次只要写到一个地方】
- 刚分配的时候只有一个最新的
- ==为每个逻辑寄存器动态分配物理寄存器,需要建立逻辑寄存器和物理寄存器的映射表。(哪些有空,哪些是最新的)。==
- ==映射表可以是RAM的方式,即:逻辑寄存器有那么多项,也可以是CAM的方式,即物理寄存器有那么多项。==
==就是只要找到一个方法临时存数据==
- 为目标寄存器分配一个空闲的重命名寄存器
- 为源寄存器找到相应的重命名或结构寄存器号
- 读操作数(注意三种操作数来源)并送入保留站
- 在保留站中找操作数准备好的操作进行运算,不涉及重命名
- 执行结果协会到重命名寄存器
- 写回到侦听该重命名寄存器值的保留站
- 不写回结构寄存器
- 把重命名寄存器的值写回到相对应得结构寄存器
- 释放相应的重命名寄存器
- 取消后面的已经建立的重命名关系
- 把结构寄存器的状态都置为有效
- 把重命名寄存器的状态都置为空
- **EMPTY:**表示该寄存器没被重命名(重命名后又已经释放)
- MAPPED:表示已经被重命名但结果还没写回
- WRIYEBACK:表示结果已经写回重命名寄存器但没有Commit到结构寄存器
- VALID:表示相应寄存器的值可用
- INVALID:表示相应寄存器的值不可用
- 可在结构寄存器中增加一个指向重命名寄存器的重命名寄存器号域
假设保留站后读寄存器
- 把目标寄存器映射到一个空闲的物理寄存器
- 为源寄存器根据依赖关系找到相应的物理寄存器号
- 把重命名后的寄存器号写入保留站
- 判断所需的操作数是否已经准备好,或(forwarding情况下)正在写回
- 从物理寄存器或结果总线中读寄存器的值
- 执行结果根据目标物理寄存器号写回到物理寄存器
- 不用写回到保留站
- 修改重命名表,确认目标寄存器的重命名关系
- 释放老的目标寄存器重命名关系
- 修改重命名表取消后面的已经建立的重命名关系
- 把状态为MAPPED或WRITEBACK的都置为EMPTY
- 确认状态为COMIIT的映射为相应的逻辑寄存器的最新映射
- 可以用CAM或者RAM的方法
- 项数与物理寄存器一样
- name:相对应的逻辑寄存器号
- state :状态:EMPTY:表示该寄存器没有被重命名(重命名后又已经被释放);MAPPED:表示已经被重命名但结果还没被写回;WRITEBACK:表示结果已经写回重命名寄存器但没有Commit到结构寄存器,Commit:表示结果已经被确认
- vaild:在一个逻辑寄存器对应多个物理寄存器的情况下表示最新映射。
三方面考虑。
- 保留站结构(独立,分组,全局)
- 读操作数时机(译码(战前),发射(战后))
- 重命名方式(重命名寄存器与结构寄存器分开/不分开)
所以有3*2*2=12种组合方式。
- 保留站后读操作数可以减少一次源操作数拷贝(从寄存器到保留站)
- 物理寄存器堆可以减少一次结果操作数拷贝(从物理寄存器到结构寄存器)
- 数据通路变宽
- Alpha21264:取值4条,发射6条,写回6条,commite11条
- 寄存器读端口变多
- 访存端口要求也增加
- 同一排发射的指令之间的相关
- 入在重命名阶段发射同一拍之间的关系
- 流水线复杂度与发射宽度成平方关系
- 如发射队列(保留站)变大 *(读端口变多+侦听端口变多)发射宽度变宽,发射队列要变长
- 如寄存器重命名端口变多*同一拍重命名指令相关 相关判断
- 同时提交多条指令
- 重命名把有序变乱序,要除了**“前后看”还要“左右看”**
- 提交把无序变成有序,也要左右看:同一排可以提交多条,第二条是否提交要看第一条是否提交,等等。
- 指令发射与读寄存器
- 多端口寄存器是物理设计的难点:会增加延迟、面积、功耗、四发射结构一般需要4写8读的寄存器
- 指令发射逻辑:从保留站中同时找出多条数据准备好了的指令,为了性能要适当考虑在数据准备好了的情况下前面的指令先发射
- 多功能部件
- 增加回端口:寄存器堆、重命名寄存器、重命名寄存器表、ROB、发射队列
- 尤其是多访存部件会大大增加设计复杂度
- 把逻辑寄存器号转化为物理寄存器号
- 消除WAR与WAW相关,奖励RAW相关关系
- State :四个状态:EMPTY,MAPPEAD,WRITEBACK,COMMIT(任何逻辑寄存器处于提交状态的物理寄存器只有一个)
- Name: 该物理寄存器对应的逻辑寄存器号
- valid:在多个物理寄存器对于一个逻辑寄存器时表示哪个是最近是被映射的
- 其他
- 重命名:为目标寄存器分配一个空闲的物理寄存器(状态置为MAPPED),为源寄存器根据依赖关系找到相应的物理寄存器号
- 执行:把重命名寄存器的状态置为WRITEBACK
- 提交:把目标寄存器的值变为软件可见。(把重命名寄存器的状态置为COMMIT),释放原来的重命名寄存器(状态置为EMPTY)
- 转移猜错或例外:取消后面的已经建立的重命名关系。
- 操作寄存器重命名后进入发射队列,取指和译码过程中发生例外的操作不进入发射队列
- 对于每个功能部件每次在已经准备号可以发射的操作中找最早进入队列的进行发射,发射队列中增加age域。表示谁先进来谁后进来。
- 寄存器重命名阶段根据物理寄存器状态表判断该物理寄存器是否可用
- 操作队列侦听有关的功能部件的写回结果,把等待该结果的操作数置为有效
- fu: 执行该操作的功能部件号,全1表示空
- roqid,brqid: Reorder队列和转移队列索引,写回时用
- op : 操作码
- pdest: 物理目标寄存器号
- psrc1,psrc2:物理源寄存器号
- prdy1,prdy2: 源寄存器准备好表示
- taken:转移猜测结果,为1表示猜测跳转
- imm:定点队列为16位立即数
- fmt:辅助操作码,浮点队列为5位fmt
- age: 表示一个操作在操作队列中等待的时间的长短
- ....
- ROB还保存部分执行结果,如evzoui,例外,JR等
- 寄存器重命名后有序进入,乱序执行,有序结束
- 重命名: 每次按序把重命名后的操作送入ROB
- 写回:根据结果总线的roqid号修改相应操作的状态,执行过程中的例外写回ex和excode,浮点操作写回evzoui,JR和JALR写回PC
- 提交:每次按序提交四个已写回的操作,例外操作不提交
- 形成例外总线:例外操作必须成为ROB第一个操作才能形成例外总线
- state: EMPTY,MAPPED,BRWTBK 和WTBK
- op:8位操作码
- odest:7位,dest原来对于的物理寄存器
- pdest:7位,物理目标寄存器号
- brqid:转移队列号
- evzoui:6位,浮点操作的EVZOUI结果写到此域
- ex:1位,表示是否发射例外
- excode:6位,例外原因
- brerr:表示转移猜测错误
- taken:表示转移成功
- c:1位,用于保存浮点比较结果
- bd:1位,表示是否位延迟槽操作
- ....
CPU的功能部件主要有三大部份,一是运算逻辑部件、二是寄存器部件、三是控制部件
1、运算逻辑部件:运算逻辑部件,可以执行定点或浮点算术运算操作、移位操作以及逻辑操作,也可执行地址运算和转换。
2、寄存器部件:通用寄存器又可分定点数和浮点数两类,它们用来保存指令执行过程中临时存放的寄存器操作数和中间的操作结果。通用寄存器是中央处理器的重要组成部分,大多数指令都要访问到通用寄存器。
3、控制部件:控制部件,主要是负责对指令译码,并且发出为完成每条指令所要执行的各个操作的控制信号
- 定点补码加法器设计
- 定点ALU设计
- 定点补码乘法器的设计
- 一位全加器
- 三个输入:A,B,Cin
- 两个输出:S,Cout
- 串行进位加法器
- 很简单,但缺点:延时长
- 进位从低位传送,形成c16需要32级门延迟
- 延迟随位数增长线性增长
-
gi=ai&bi 为进位生成因子,只要gi为1,就有进位。
-
pi=ai|bi 为进位传递因子。只要pi为1,就把低位进位向前传递。
-
只要低位有一个进位生成,而且被传递,则进位输出为1。
-
因此可以根据这个来制作并行进位加法器
[A]补 - [B]补 = [A - B]补 = [ A ]补 + [ - B]补
- [ - B]
补的计算:[B]补取反加一 - 只要在B输入端对B进行取反并置进位为1
-
加法:A 与 B 的符号位相同,但结果的符号位与A 与 B 的符号位不同 ,即正数相加得负 或 负数相加得正
assign ov_add =( ~s31 & a31 & b31 )| (s31 & ~a31 & ~b31 )
-
减法:正数减负数,结果为负数,或者负数减正数,结果为正数
assign ov_sub = (s31 * ~a31 & b31) | (~s31 & a31 & ~b31)
-
因此,运算器溢出条件为:
assign ov =(isADD & ( ~s31 & a31 & b31 )| (s31 & ~a31 & ~b31 )) | (isSUB & (s31 * ~a31 & b31) | (~s31 & a31 & ~b31))
ALU 表示算术逻辑单元
- 实现加减法器
- 实现逻辑运算*(a&b,a|b,a xor b在加法器中产生)*
- 实现比较器
- 实现移位器
最后根据操作类型,从多个结果中选择
- 可以使用异或逻辑逐位判断,来判断多比特的A与B信号是否相等。
- 每个比特结果,有任何一个为1,则输出为0
- 多输入或非门,位数多时需要多级逻辑
- 使用A-B>0来判断大小
- A-B符号位为0,则代表A>B
- 小心溢出
CondA<B = OV & S63~ | OV & ~S63 = a63 & S63 | ~b63 & S63 | a63 & ~b63
//会不会比较废面积?
- 对于移动N位数的移位操作,使用N选1来实现
- 根据要移动的位数。从N个输入中选一个
- 每个输入将输入移动特定位数,不需要延迟和逻辑
- 每种移位结果再根据移位操作类型选择
[X]补 ==+== [Y]补 = [X+Y]补 , 但[X]补 ==*== [Y]补 != [X*Y]补
只需要16拍
- 串行把16个数相加,需要15次加法时间
- 64位加法需要2+10+3=15级门延迟
- 用15个加法器组织乘树状,需要4次加法时间,浪费硬件
- n个全加器每次把3个n位的数相加转换成两个数相加
- 因此。n个全加器每次可以把m个n位数相加转换成2m/3个数相加,再用一层全加器转换成4m/9个数相加,知道转换成2个数,再用加法器把最后2个数相加
- 进位要往高处连
基本原理:
- 多进程环境下统一的编程空间
- 多进程环境下的共享与保护
- 支持大于实际物理内存的编程空间
虚实地址分开,建立一种从虚地址空间映射到物理内存的机制
- 把2个层次的存储转换为1个层次的存储
- 物理内存实际上是磁盘的一个Cache
Translation Looaside Buffer . 旁路转换缓冲,页表缓冲,里面存放的是一些页表文件==(虚拟地址到物理地址的转换表)==。1024项-->1M-->1^20^ 。
- 在页的范围内,虚实地址相等
- TLB是页表的Cache
页: **操作系统对内存管理按页来管理 ,**以页为单位来管理。不论软件需要多少字节,最小单位都是1页。 物理页的大小是4k。虚页。
操作系统负责维护页表。负责把虚地址变成物理地址。 CPU要维护TLB,TLB是页表的Cache。
TLB实际上是操作系统中页表的Cache
- TLB 主要负责完成用户空间到物理空间的转换
- 一般与Cache访问同时进行
- TLB内容:虚地址(Cache的Tag),物理地址(Cache的Data),保护位(Cache的状态)
TLB失效处理:
- TLB失效时需要把相应页表内容从内存取到TLB
- TLB失效时硬件和软件**(如MIPS的特殊例外)来填充TLB**
Cache都是物理地址,是内存的子集
- TLB是页表的Cache
- 负责地址转换,一页管4kb以上数据
- 页表由操作系统管理,存在系统空间
- 内存是硬盘的Cache
- 负责数据缓冲,一字节就是一字节
- 用户程序的数据都在用户空间
- 分段,段内分页
- TLB
- 特殊的控制寄存器
- 特殊指令
- 专用的例外入口
VPN:虚页号
C:允许是否数据进Cache
V:1->有效 0->找不到
D:1->允许写,0->允许读不允许写
MASK:页大小
MFC0, MTC0 :
- 在通用寄存器与控制寄存器之间搬运数据
TLBR:
- 以INDEX寄存器为索引把TLB的内容读到PageMask,EntryHi和EntryLo0/1等寄存器
TLBP:
- 检查EntryHi种指定的虚页是否在TLB中
TLBWR,TLBWI
- 分别以Random与Index寄存器为索引,把Pagemask,EntryHi与EntryLo0/1寄存器的内容写入TLB
置BadVaddr,Context,EntryHi
- PC=例外入口地址
- TLB Refill入口为0x8000_0000
- 其他入口为0x8000_0180
- 置Status,Cause
- Refill
- 如果查找TLB没找到一个虚地址匹配(VPN2+ASID/C)
- 例外入口:0x80000000(除非exl = 1 )
- TLB invaild
- 如果找到一个虚地址匹配项,但其v=0
- 例外入口:0x80000180
- 细分为2部分:TLBL for loads , TLBS for stores
- TLB modify
- 如果找到一个虚地址匹配项,但其v=1,但D=0,且访问为store
- 例外入口0x80000180
- 例外处理器在核心态下进行
- 不允许在核心态下执行一条用户指令
- 不允许在用户态下执行指令核心指令
- 例外返回的两种方式
- jr+mtc0: mtc0必须在jr的延迟槽中
- eret:eret没有延迟槽
静态流水线是基础。是动态流水线的基础。
RISC技术极大地简化了指令之间的相关性。
-
有序进入,乱序执行,有序结束
-
主要数据结构
- 保留站(发射队列)把有序变成乱序,临时存指令
- 重命名寄存器用于保存未提交的临时结果,临时存数据
- ROB把乱序重新变成有序
-
乱序的能力和有关队列大小紧密相关
- 现代高性能CPU一般都有100条指令在流水线中乱序执行。
-
**保留站(发射队列)在读寄存器前比较容易。**只需要存一些状态,只要数据好了就走。省功耗,面积。
-
在写回阶段,物理寄存器堆重命名不断变状态,根据重命名表来分配寄存器进行写回。
-
多发射:路变宽,端口变多,前后看还要左右看。
- 运算器不是CPU设计的重点,重点是如何更高效地提取指令以及运算数。
- 运算器还可以继续做出优化
PIC:位置无关代码
- RV32I:固定不变的基础整数指令集,RV核心内容。
- RV32M:乘法与除法
- RV32F,RV32D:浮点操作
- RV32A :原子操作
- RV32C:可选的压缩拓展
- RV32V:向量拓展。它通过向量寄存器指定数据类型与长度
- RV64G:64位地址版本。
所有指令都是32位长度。
RV指令提供3个寄存器操作数
寄存器-寄存器操作
用于短立即数与访存load操作
用于访存store操作
用于条件跳转操作。B类型的立即数字段在S类型的基础上旋转了1位。
用于长立即数
用于无条件跳转。J类型的直接字段在U类型的基础上旋转了12位。
RV32I指令集的各种指令
-
TODO: *所有位为0是非法的RV32I指令。*因此,试图跳转到被清零的内存区域的错误跳转会触发异常。
-
TODO:所有位都是1的指令也是非法指令,它将捕获其他常见的错误,诸如未变成的EEPROM设备、断开链接的内存BUS或者坏掉的内存芯片。
-
B 和 J 格式的分支和跳转地址必须向左移动 1 位以将地址乘以 2
其中,x0号寄存器恒为0,还包括其他各种指针(sp,gp,tp,fp)寄存器。保存寄存器(s0-s11),临时寄存器(t0-t6),PC指针寄存器。
- 有符号字节和半字,符号拓展为32位之后再写入目的寄存器,无符号字节都被无符号拓展至32位。
- 加载和存储的支持的位移寻址模式是符号拓展12位立即数到基地址寄存器。
- 不支持延迟加载。
- 普通的加载和存储指令支持不对齐访问。
其中。sltu判断充当低位到高位的加法的进位。
获得PC值可以用auipc zero来获取
jal作用:
- 返回地址寄存器ra,实现过程调用
- 使用 0号寄存器替代ra做模板寄存器,实现无条件跳转。
控制状态寄存器指令(csrrc,csrrs,csrrw,csrrci,csrrsi,csrrwi),可以轻松范围一些程序性能计数器,对于这些64位的计数器,我们一次可以读取32位。这些计数器包括了系统时间,时钟周期,以及执行的指令数目。
变量应该尽量存放在寄存器而不是内存中,调试也要注意避免频繁地保存和恢复寄存器。移位它们同样会访问内存。
如果参数与局部变量太多:
允许各个文件独立的进行编译与汇编,在改动部分文件时,不需要重新编译全部源代码。
其中rem
是向目的寄存器写回余数