逻辑电路部分已经在学校的课程学过了,这部分过的比较快
Combination Logic
略
Sequential Logic
几个关键名词
Maximum Clock Frequency
讨论clock速度在不影响性能的前提下可以达到多快
需要考虑的因素
- setup time and hold time
- clock-to-q time
- combinational logic delay
The Critical Path
两个寄存器之间电路的最长延迟,时钟周期必须比这个长
注意最后还有个setup time
Pipelining
减小delay,提高performance的方式:增加path中的寄存器数量
尽管执行第一条指令需要的时间从一个周期变为两个周期,但紧随其后的每一条指令间隔时间大大缩短
- faster clock rate -> higher throughput
- more stages -> higher startup latency
FSM 有限状态机
Functional Units
计算机CPU中执行特定功能的部分
- Arithmetic Logic Unit(ALU)
- Floating Point Unit
- Load/Store Unit
ALU
主要通过mux来选择运算种类
Adder and Subtractor
one bit adder
略
补码的加减法实现
Overflow
unsigned overflow
- 加法时,最高位出现进位1
- 减法时,最高位没有进位(进行0-5,变成很大的数字)
signed overflow
分正负两种情况,总之就是最高两位的进位不同时出现
Datapath
这部分介绍指令的具体执行过程(?)
CPU
CPU主要是两部分
- Datapath:包括所有执行运算需要的硬件(根据Control的信号,执行具体操作)
- Control(根据输入的指令,决定datapath需要做什么)
Designing Datapath
需要figure out CPU都需要执行什么运算,根据六种指令的类型开始分析
R-type
流程
- get instruction
- parse instruction fields(rd,rs1,rs2,op)
- read data from operands
- perform op
- write result to dest
1.get inst
- PC储存当前指令地址
- 指令储存在IMEM中,根据PC输出的地址去IMEM取
- 执行完之后PC自增(+4) ,所以PC输出经过自增接回PC的输入
2.parse
根据R指令的组成,取出三个寄存器的部分,输入进Register File,指定rs1,rs2,rd分别是什么寄存器
3.read
利用reg file读取需要的寄存器值
Register File
实际上只有31个寄存器(zero reg不需要)
4.perform
- reg file输出rs1,rs2储存的值,作为operand输入进ALU,指令输入进Control部分,解析指令,根据R指令的func3,func7决定运算的种类,输出ALUsel输入进ALU,选择正确的运算
5.write
ALU输出的运算结果,输入进reg file,写入需要写入的寄存器
Arithmetic I-type
这种情况下不需要rs2的值,取而代之的是一个立即数,通过控制逻辑Bsel=1,选中立即数作为第二个操作数输入ALU。
该立即数通过读取指令的高12位,通过立即数生成器生成
Control部分通过读指令知道这是一个I-type,ImmSel=1使能生成器,生成器读入指令的高12位,copy到立即数的低12位,剩余位通过sign extension补全后输出
Load I-type
通过ALU计算rs1+imm的值,读取DMEM中对应地址的值,写进rd,ALU的输出不是简单接入DataD,需要新的组件
最右边的MUX叫做Write Back MUX,决定写进rd的是ALU的计算结果,还是内存中的数据
这里的DMEM目前当做Idealized Memory
Notes
- 显然R-type指令不需要用到全部的组件(DMEM),load需要用到全部,所以load指令用来计算Critical Path
- 掌握各个控制信号的含义
S-type
- 需要把rs2的值写进DMEM,多一条线
- 这类指令无rd,不需要写值进rd,所以需要控制信号(control bit)决定是否写值进rd
控制信号为RegWEn
SB-type
- 需要比较两寄存器值的大小
- 需要操作PC(跳转)
- PCSel:决定是PC自增还是写入跳转到的新PC
- ASel:决定输入进ALU的是PC还是rs1(结合BSel,把imm和PC输入进ALU,计算得到新PC)
- BrLt和BrEq作为输入信号,决定其他控制信号的值
Jumping I-type
跳转部分已经在branch指令处完成的差不多了,只需要做到Link:把当前下一条指令的PC写进ra(在该语境下是rd)
J-type
已经不需要再添加更多线路
Design Principle
CPU Control and Pipeline
Control的实现
- combinational logic
- ROM
Instruction Timing
一条指令执行周期可以分为以下部分,每部分都需要一定时间,其中lw指令每部分都需要做,执行时间最长,将最长的时间设为一个clock周期时间
性能提升
性能提升可分为以下方面
- 执行一个任务需要的时间(latency)
- 单位时间执行的任务数量(throughput)
- 电池寿命
类比:
latency是trip time(从起点到终点的时间)
throughput运送100名乘客需要的时间
Processor Performance
程序执行时间
Inst per Program
影响因素
- 具体任务
- 算法
- 编程语言
- 编译器
- 指令集(ISA)
这个是Input
clk cycle per inst
- 指令集(ISA)(CISC RISC)
- CPU的具体构造(几级流水)
- superscalar processors
Time per Cycle
- CPU构造(逻辑电路)
- 技术
- power budget
pipeline execution
- 流水提升throughput 不改变latency(同时进行多个进程)
- 流水的级数的概念(stages)
- 流水速度由流水级数和最慢的阶段决定
- 因此要求各个阶段耗时相近,否则效率不会有太大提升
pipeline datapath
RISCV指令的stages:
- 取指令
- 读取寄存器的值
- ALU
- 内存
- 写进寄存器
取最慢的stage时间200ps作为流水中每个阶段的时间
虽然指令一条指令一共需要的时间短了(latency),但是throughput大大提高
通过在各个stage之间增加寄存器,减小关键路径
流水的控制信号
每个stage的控制信号都储存在pipeline寄存器中,也就是需要同时保存五个stage的状态信号
流水的细节
- PC+4传进Write back reg需要多个寄存器,为了节省硬件,在最后+4,节省寄存器
- write back会将数据写会reg file但此时reg file在执行其他的指令,为此需要把原来的指令一起传进reg file(最下面的电路)
Pipeline Hazards
因为进行流水,所以需要处理的一些问题(situation that prevents starting the next instruction in the next clock cycle)
- Structural hazards
- Data hazards
- Control hazards
Structural Hazards
流水中的两条指令同时需要使用同一个硬件设备
reg file hazard
Inst Decode 和 Write Back两个stage都需要使用reg file
- 永远的solution:adding more Hardware
为此只需增加reg file的接口,同时可读可写就可以了(PortA, PortB, PortW) - 另外的solution:double pumping
在时钟上升沿写,下降沿读(注意这个先写后读的顺序)
Memory hazard
Inst fetch和Memory两阶段都需要读内存(IMEM和DMEM),RISCV中指令和数据都储存在RAM中
指令和数据储存在内存的不同区域,有专用的cache(buffer)进行数据读写
Data Hazards
后面的指令需要使用同样在流水线中前面的指令新写入的数据(Data dependency)
R-type
add t0,t1,t2
sub t4,t0,t3
and t5,t0,t6
xor t9,t0,t10
sub指令读取t0的值是在ID stage,但add指令写进t0的值是在WB stage
图中可以看到sub和and指令的t0根本没有准备好(如果有double pumping,or指令的t0就没问题)
solution1:stall(拖延)
- 在有冲突的指令之间插入bubble(什么都不做的空白stage 比如add x0,x0,x0)
- 编译器判断是否有冲突,有就增加bubble
- 降低throughput,降低performance
solution2:Forwarding
直接使用计算结果(ALU计算得出之后直接输入进ALU,无需等先写入reg file),但是需要增加新的电路(more datapath and control)
在有double pumping的前提下,可能会产生Hazard的是下两条指令
所以当第一条指令计算结果从ALU进入aluM时,读取两条指令进入Control Logic,生成控制信号来选择ALU的第一个操作数,可以是一个clock cycle后的ALU结果,也可以是两个周期后的ALU结果
Load Instruction
是在同一个stage中,lw指令需要写入t0的值被取出,这个值要写进ALU作为操作数,因此Forwarding不适用了,只能stalling
Hardware Interlock 和 nop
等效的两种stall的方式,硬件暂停和插入nop
solution: Reordering
编译器或者程序员修改指令顺序,在不影响代码含义的同时尽可能避免load hazard
Control Hazards
需要取的下一条指令取决于分支的结果
Branching
根据Datapath的电路,分支的结果由ALU计算得出,所以接下来两条指令的取指令会受到影响,所以需要两个stalls
move branch comparator to ID stage
第二阶段计算PC,这样分支只需要一个nop
但是这样新PC的计算需要在ID阶段完成
但是这样会产生新的Data Hazard,并且硬件设计也更复杂 pass
branch prediction
默认take branch,如果发现猜测错误,再修复,take 2 stalls(branch penalty)
速度比default stalling快得多(对的不会拖慢,错了也是和stall速度一样)
使用Dynamic branch prediction
superscalar processor
因为有多套硬件,所以可以同时执行多条指令
需要高级算法来arrange ASM code(dependency)