【System Beats!】第四章 处理器体系结构

news/2025/10/26 9:52:37/文章来源:https://www.cnblogs.com/namelessstory/p/19166501

ISA

  • 指令集架构(ISA)是连接计算机软件与硬件的一座桥梁,定义了程序如何与底层硬件进行交互。
  • ISA的设计覆盖从应用程序到物理芯片的整个软硬件协作过程。
  • Application → Compiler → OS → ISA → CPU → Circuit → Chip
  • ISA之上:专注于程序设计和指令序列的执行。
  • ISA之下:关注指令的高效执行和硬件设计指导。

Y86-64

  • 相比X86-64,数据类型、指令和寻址方式都要少一些
  • 字节级编码较为简单,机器代码相比不够紧凑
  • 每条指令都会读取或修改处理器状态的某些部分,称为程序员可见(写程序的人或者编译器)。

Y86-64的状态

  • 15个程序寄存器:%rdi,%rsi,%rax,%rbx,%rcx,%rdx,%rbp,%rsp,%r8~%r14,比x86-64少一个。
  • 它们并称为寄存器堆(Register File)。
  • 每个程序寄存器存储一个64位的字,%rsp的用法与x86-64相同。
  • 三个条件码SF,ZF和OF
  • 程序计数器(PC/%rip):存放当前执行指令的地址。
  • 程序用虚拟地址引用内存位置,硬件和OS联合起来翻译为物理地址。
  • 状态码(Stat):表明程序运行的整体状态。
  • 内存动态随机存储器,采用小端法存储。

Y86-64指令

  • 每条指令从1个字节10个字节不等。
  • 只包含8字节整数操作,寻址方式较少。
  • Y86-64中,将8字节称为
  • 内存寻址只包含基址偏移量形式,不支持第二变址寄存器寄存器值伸缩
  • 同样,不允许内存与内存之间传送,以及不允许立即数传送到内存
  • halt:字节编码为一字节00,停止程序执行。
  • nop:字节编码为一字节10,占位操作。
  • rrmovq rA,rB:字节编码为两字节20 rArB,寄存器之间数据传送。
  • cmovXX rA,rB:字节编码为两字节2fn rArB,寄存器之间条件传送。
  • irmovq V,rB:字节编码为十字节30 FrB V,立即数传送到寄存器。
  • rmmovq rA,D(rB):字节编码为十字节40 rArB D,寄存器传送到内存。
  • mrmovq D(rB),rA:字节编码为十字节50 rArB D,内存传送到寄存器。
  • OPq rA,rB:字节编码为两字节6fn rArB,进行整数操作,只在寄存器之间进行。
  • jXX Dest:字节编码为九字节7fn Dest,跳转到某个地址。
  • call Dest:字节编码为九字节80 Dest,调用某个地址的函数。
  • ret:字节编码为一字节90,返回上级函数。
  • pushq rA:字节编码为两字节A0 rAF,将寄存器中的值压入栈顶。
  • popq rB:字节编码为两字节B0 rAF,将栈顶的值弹出到寄存器中。
  • 注意到cmovXXrrmovq极为相像,因此下文会加以区分。
  • 注意到被寻址的永远为rB,但是字节的存储方式没有改变。
  • 注意到Y86-64没有testqcmpq语句,因此最近一次算术/逻辑运算结构设置条件码。
  • OPQfn
    • 0:表示addq
    • 1:表示subq
    • 2:表示andq
    • 3:表示xorq
  • JXXfn
    • 0:表示jmp
    • 1:表示jle
    • 2:表示jl
    • 3:表示je
    • 4:表示jne
    • 5:表示jge
    • 6:表示jg
  • cmovXXfn
    • 0:表示rrmovq
    • 1:表示cmovle
    • 2:表示cmovl
    • 3:表示cmove
    • 4:表示cmovne
    • 5:表示cmovge
    • 6:表示cmovg
  • 寄存器的字节表示
    • 0%rax
    • 1%rcx
    • 2%rdx
    • 3%rbx
    • 4%rsp
    • 5%rbp
    • 6%rsi
    • 7%rdi
    • 8%r8
    • 9%r9
    • 10%r10
    • 11%r11
    • 12%r12
    • 13%r13
    • 14%r14
    • 15无寄存器/F
  • Y86-64符合指令集的重要性质:字节编码必须有唯一的解释,要么唯一解释要么非法。
  • 地址是基于字节编码偏移的。

Y86-64状态码

  • 用程序状态码Stat表示
  • 1AOK,表示运行正常。
  • 2HLT,表示遇到halt指令。
  • 3ADR,表示试图读写非负地址。
  • 4INS,表示指令非法。
  • 处理器会停止,或调用异常处理指令。

RISC和CISC指令集的比较

  • CISC指令数量多RISC指令数量少
  • CISC长延迟指令RISC无长延迟指令
  • CISC编码长度可变RISC编码固定长度
  • CISC寻址方式复杂RISC寻址方式简单
  • CISC可对内存和立即数进行算术逻辑运算,RISC只能对寄存器进行算术逻辑计算。
  • CISC细节对机器级程序不可见RISC细节对机器级程序可见
  • CISC条件码RISC无条件码
  • CISC过程链接是栈密集的,RISC过程链接是寄存器密集的。
  • CISC过程频繁访问内存,RISC过程频繁访问寄存器。
  • CISC
    • 早期内存昂贵需要短指令
    • 编译器能力有限需要复杂指令
    • 处理器设计复杂,功耗高,价格昂贵
  • RISC
    • 更适合流水线操作
    • 简化指令集便于并行处理
  • 示例:RISC/ARM
    • 基于寄存器的指令集,典型设计包含32个通用寄存器。
    • 仅加载和存储指令(Load/Store)访问内存。
    • 不使用条件码,测试结果存储于寄存器中。
  • 现代指令集一般两者特点兼备。

逻辑设计

逻辑门与组合逻辑

  • 数字电路的基本单位
  • 基本逻辑门与门(And)或门(Or)非门(Not)
  • 只对单个位的数进行操作,常见是 \(n\) 路操作。
  • 输入高/低电平,输出对输入持续响应(有微小延迟)。
  • 组合逻辑:由逻辑门网络组成的电路,例如比较器、加法器等。
  • 每个逻辑门的输入必须连到
    • 一个系统输入/主输入
    • 某个存储器单元的输出
    • 某个逻辑门的输出
  • 注意,两个或多个逻辑门的输出不能直接连接,组合逻辑也不能存在环
  • HCL(Hardware Control Language)
    • 类似C语言逻辑表达式,用于描述硬件控制逻辑。
    • 不同于C语言的短路逻辑,HCL表达式不会省略任何分支
  • 多路复用器(MUX)
bool re = (s && a) || (!s && b)
  • 情况表达式(Case Expression)
T out = [select1 : Expr1;select2 : Expr2;
]
  • 算术/逻辑单元(ALU)
    • 抽象模型为两个数据输入与一个控制输入
    • 控制输入与字节编码中功能相同,选择计算功能并改变条件码
    • 堆叠多个运算黑箱,例如加法、减法、与、异或

时序逻辑与存储器

  • 时序逻辑中的寄存器不同于上文提到的通用寄存器,暂称其为时钟寄存器
  • 其行为受时钟信号(同一个时钟)控制。
  • 其由逻辑门组成的触发器堆叠而成。
  • 时钟到达上升沿时,加载输入,状态与输出均改变。
  • 时钟下降时,保持输出和状态稳定
  • 配备时钟寄存器后的时序电路不会出现震荡,可以实现反馈和循环
  • 震荡(Oscillation)
    • 电路输出在短时间内反复切换(高电平和低电平之间快速变化)的现象。
    • 这种现象通常是由于电路设计不当或信号反馈路径不稳定引起的。
    • 使得无法稳定在预期的逻辑电平,从而电路无法正常工作。

寄存器堆与RAM

  • 属于随机访问存储器,通过地址选择该读或该写哪个字。
  • 包含通用寄存器等用于存取数据的寄存器。
  • 两个读端口,一个写端口,允许同时进行多个读写操作(经典寄存器堆,不代表最终品质)。
  • 每个端口有一个地址输入,表示该选择哪个寄存器。
  • 另外还有一个数据输出或对应该寄存器的输入值。
  • 读端口有地址输入srcAsrcB,数据输出valAvalB
  • 写端口有地址输入dstW,数据输入valW
  • 写入由时钟信号控制,类似将值加载到时钟寄存器。

SEQ/顺序硬件架构

SEQ的主要状态单元

  • PC(Program Counter)寄存器:存储下一条指令的地址。
  • CC(Condition Code)寄存器:存储条件码,用于记录算术/逻辑单元(ALU)的结果状态。
  • 寄存器堆(Register File):用于存储临时变量,由程序显式管理的寄存器集合,具有两个读端口和两个写端口
  • Memories:包括指令内存(Instruction Memory)和数据内存(Data Memory)
  • 从不回读原则:不为了完成一条指令的执行而去读由该指令更新的状态。

SEQ的阶段

取指(Fetch)

  • 操作:从内存中读取指令字节,地址为程序计数器(PC)的值。
  • 读出的指令由以下部分组成:
    • icode:指明指令类型,指令字节低4位。
    • ifun:指令功能,指令字节高4位。
    • rA:第一个源操作数寄存器,通过need_regids控制。
    • rB:第二个源操作数寄存器,通过need_regids控制。
    • valC:立即数或操作地址,常量,通过need_valC控制。
    • 若指令地址不合法,由imem_error指明。
  • 生成PC的下一条指令地址valP

译码(Decode)

  • 操作:从寄存器堆读入最多两个操作数,得到valAvalB
  • 通常读入rArB对应寄存器,部分指令读入%rsp
  • 解析操作码:从指令中提取操作码和寄存器序号srcAsrcB
  • 确定操作类型:根据操作码识别指令类型(只使用icode)。
  • 确定写回指向:根据操作码确定dstEdstM
  • 读取操作数:从寄存器堆中提取源操作数valAvalB

执行(Execute)

  • 操作:算术/逻辑单元(ALU)进行运算。
  • 运算包含以下情况
    • 执行指令指明的操作(OPq)
    • 计算内存引用的地址(rmmovq mrmovq)
    • 增加/减少栈指针(pushq popq)
    • 一般而言运算为加法运算,除非ifun特别指定。
  • ALU操作:将源操作数valAvalB输入ALU,执行指定运算,输出运算结果valE
  • ALU输入分为两个部分
    • aluAvalA、valC以及+8、-8等常数决定。
    • aluBvalB决定。
  • 设置条件码:OPq设置CC中的条件码。
  • 条件判断:cmovXXJXX根据CC内容和ifun计算Cnd,决定是否跳转。
  • 注意到,没有一条指令又设置CC又使用CC,这是Arch Lab优化的关键!
  • 对于无需计算的指令,将寄存器编号于srcA中,提取出valAvalB置零,ALU输出的valE即为valA的值。
  • 对于地址传送指令,寄存器提取出valBaluA选择8-8执行。
  • 对于条件传送指令,根据Cnd决定是否将dstE设为F

访存(Memory)

  • 操作:将数据写入内存,或从内存读出数据。
  • 仅在需要访问内存的指令中进行,即load/storeY86-64中为mrmovqrmmovq
  • 读取内存:从valA(popq,ret)valE(mrmovq)中读出valM
  • 写入内存:向valE(rmmovq pushq call)中写入valA(rmmovq pushq)valP(call)

写回(Write Back)

  • 操作:最多可以写两个结果到寄存器文件。
  • 更新寄存器堆:将ALU或内存操作的结果存储到目标寄存器。
  • 更新PC:根据valP、valC(JXX/CALL)或者valM(ret)为下一条指令准备好新的PC。
  • 寄存器堆的更新只在时钟上升沿执行,保持写入稳定性。

SEQ实现示例

OPq rA,rB

  • 取指
    • PC为索引,从指令内存读取指令的操作码OPq
    • 计算下一条指令的PC值(PC+2),存放到valP
  • 译码
    • 解析操作码得到srcAsrcB
    • 根据ifun确定操作类型。
    • 选择dstErB
    • 从寄存器堆中提取源操作数valAvalB
  • 执行
    • 根据ifun使用ALU对valAvalB进行运算,结果存放到valE
    • 根据结果更新CC寄存器。
  • 访存
    • 无访存操作,跳过该阶段。
  • 写回
    • valE写回寄存器堆的rB寄存器。
    • PC更新为valP

rrmovq rA,rB

  • 取指
    • PC为索引,从指令内存读取指令的操作码rrmovq
    • 计算下一条指令的PC值(PC+2),存放到valP
  • 译码
    • 解析操作码得到srcA
    • 设置dstErB
    • 从寄存器堆中提取源操作数valA
  • 执行
    • 因为不计算只取原值,将valB置零。
    • 使用ALU计算valA+valB,结果存放到valE
  • 访存
    • 无访存操作,跳过该阶段。
  • 写回
    • valE写回寄存器堆的rB寄存器。
    • PC更新为valP

irmovq V,rB

  • 取指
    • PC为索引,从指令内存读取指令的操作码irmovq
    • 取出立即数,存放到valC
    • 计算下一条指令的PC值(PC+10),存放到valP
  • 译码
    • 设置dstErB
  • 执行
    • 因为不计算只取原值,将valB置零。
    • 使用ALU计算valC+valB,结果存放到valE
  • 访存
    • 无访存操作,跳过该阶段。
  • 写回
    • valE写回寄存器堆的rB寄存器。
    • PC更新为valP

rmmovq rA,D(rB)

  • 取指
    • PC为索引,从指令内存读取指令的操作码rmmovq
    • 取出偏移量,存放到valC
    • 计算下一条指令的PC值(PC+10),存放到valP
  • 译码
    • 解析操作码得到srcAsrcB
    • 从寄存器堆中提取源操作数valAvalB
  • 执行
    • 使用ALU对valB+valC进行运算,结果存放到valE
  • 访存
    • valE为地址,将valA写入。
  • 写回
    • PC更新为valP

mrmovq D(rB),rA

  • 取指
    • PC为索引,从指令内存读取指令的操作码mrmovq
    • 取出偏移量,存放到valC
    • 计算下一条指令的PC值(PC+10),存放到valP
  • 译码
    • 解析操作码得到srcB
    • 设置dstMrA
    • 从寄存器堆中提取源操作数valB
  • 执行
    • 使用ALU对valB+valC进行运算,结果存放到valE
  • 访存
    • valE为地址,取出valM
  • 写回
    • valM写回寄存器堆的rA寄存器。
    • PC更新为valP

pushq rA

  • 取指
    • PC为索引,从指令内存读取指令的操作码pushq
    • 计算下一条指令的PC值(PC+2),存放到valP
  • 译码
    • 解析操作码得到srcAsrcB默认为%rsp
    • 设置dstE%rsp
    • 从寄存器堆中提取源操作数valAvalB
  • 执行
    • 使用ALU对valB+(-8)进行运算,结果存放到valE
  • 访存
    • valE为地址,将valA写入。
  • 写回
    • valE写回寄存器堆的%rsp寄存器。
    • PC更新为valP

popq rA

  • 取指
    • PC为索引,从指令内存读取指令的操作码popq
    • 计算下一条指令的PC值(PC+2),存放到valP
  • 译码
    • srcA,srcB默认均为%rsp
    • 设置dstEdstMpopq
    • 从寄存器堆中提取源操作数valAvalB
  • 执行
    • 使用ALU对valB+8进行运算,结果存放到valE
  • 访存
    • valA为地址,取出valM
  • 写回
    • valE写回寄存器堆的%rsp寄存器。
    • valM写回寄存器堆的rA寄存器。
    • PC更新为valP

jXX Dest

  • 取指
    • PC为索引,从指令内存读取指令的操作码jXX Dest
    • 取出跳转地址,存放到valC
    • 计算下一条指令的PC值(PC+9),存放到valP
  • 译码
    • 无译码操作。
  • 执行
    • 根据CC寄存器内容和指令类型ifun计算cond,判断条件是否满足。
  • 访存
    • 无访存过程。
  • 写回
    • cond为真,PC更新为valC;反之更新为valP

Call Dest

  • 取指
    • PC为索引,从指令内存读取指令的操作码Call Dest
    • 取出调用地址,存放到valC
    • 计算下一条指令的PC值(PC+9),存放到valP
  • 译码
    • srcB默认为%rsp
    • 设置dstE%rsp
    • 从寄存器堆中提取源操作数valB
  • 执行
    • 使用ALU对valB+(-8)进行运算,结果存放到valE
  • 访存
    • valE为地址,将valP写入。
  • 写回
    • valE写回寄存器堆的%rsp寄存器。
    • PC更新为valC

ret

  • 取指
    • PC为索引,从指令内存读取指令的操作码ret
    • 计算下一条指令的PC值(PC+1),存放到valP
  • 译码
    • srcA和srcB默认为%rsp
    • 设置dstEret
    • 从寄存器堆中提取源操作数valAvalB
  • 执行
    • 使用ALU对valB+8进行运算,结果存放到valE
  • 访存
    • valA为地址,取出valM
  • 写回
    • valE写回寄存器堆的%rsp寄存器。
    • PC更新为valM

comvXX rA,rB

  • 取指
    • PC为索引,从指令内存读取指令的操作码cmovXX
    • 计算下一条指令的PC值(PC+2),存放到valP
  • 译码
    • 解析操作码得到srcA
    • 从寄存器堆中提取源操作数valAvalB
  • 执行
    • 由于不计算只取原值,将valB置零。
    • 使用ALU对valA+valB进行运算,结果存放到valE
    • 根据CC寄存器内容和指令类型ifun计算cond,若不满足,将rB设置为F
  • 访存
    • 无访存过程。
  • 写回
    • valE写回寄存器堆的rB寄存器,若为F则不写回。
    • PC更新为valP

最后,得到了SEQ的整体设计:

  • SEQ的缺点:时钟周期必须非常长,使信号能在一个周期内传播所有的阶段。

SEQ+硬件架构

  • 相比SEQ架构,每个时钟周期都可以取出下一条指令的地址,更新PC在一个时钟周期开始时执行,而非结束时执行。
  • 没有硬件寄存器来存放程序计数器,依据前一条指令保存下来的一些状态信息动态计算PC。

PIPE-/流水线硬件架构

概况

  • 类比生活中的流水线,流水线能够提高系统吞吐量,同时轻微增加延迟
  • 它讲顺序执行的指令流划分为多个阶段,每个阶段由不同的硬件单元执行,允许多条指令并行处理。
  • 吞吐量:单位时间内完成的指令数量
  • 单位:每秒千兆指令(GIPS,10^9 instructions per second,即10^{-9} s 执行多少指令)。
  • 运行时钟的速率是由最慢阶段的延迟限制的。
  • 流水线寄存器(即组合逻辑拆分后各阶段的时钟寄存器)在时钟上升沿写入数据,在时钟稳定期间保持稳定输入输出。
  • 流水线过深:会导致寄存器延迟占总延迟的比例逐渐升高,边际效益递减,收益下降,同时处理冒险、分支错误和清除流水线的成本也增加。
  • 反馈路径:由后阶段传递到前阶段的电路线,主要用于传递和指令执行相关的关键信息,如:
    • 预测的程序计数器(PC)值。
    • 分支信号(程序是否需要跳转)。

具体信息

  • 在流水线架构中,往往需要区分不同阶段之间的数据,数据有时稳定地存储在寄存器中,有时暂时地流经组合逻辑。

  • 大写前缀指的是流水线寄存器(即将由对应阶段进行处理),对应阶段开始时就是正确的值,在下一个时钟上升沿到来之前不会变化。

  • 小写前缀指的是流水线阶段,对应阶段中,完成相应运算后才会是正确的值。

  • PIPE-相比PIPE架构,没有对冒险的处理和转发逻辑,由SEQ+插入流水线寄存器而来。

  • 同时,增加了新模块SelectA来选择valA的来源。

  • 分支预测:由于流水线,因此每个时钟周期都要给出一个指令地址用于取指。

  • JXX指令的最简单策略:总是预测选择条件分支,即选取新PC为valC

  • ret指令:整个流水线停转,等待它通过写回W阶段,从而得到压栈的返回值并更新PC

  • 于是,得到PIPE-的整体设计:

流水线冒险(Hazard)

数据冒险(Data Hazard)

  • 定义:下一条指令需要使用当前指令计算的结果。
  • 例如,以下Y86-64指令序列:
addq %rax, %rbx    # 计算rax和rbx的和,存放到rbx中
movq %rbx, %rcx    # 将rbx的值复制到rcx中
  • 此时,当movq执行到D阶段时,需要提取%rbx的值。
  • 但是addq此时处于E阶段,需要到W阶段才能写回。
  • 有以下三种策略可以解决数据冒险

暂停(Stall)

  • 定义:保持状态,输入清空。
  • 在两条指令之间插入nop指令,以确保后一条指令的操作数已被前一条指令写回。
  • 这条指令,相当于延迟了下一条指令出现,同时它本身顺着流水线流动
  • 需要在软件层面修改汇编代码,具体如下:
addq %rax, %rbx    # 此时,addq指令运行到fetch
nop                # 此时,addq指令运行到decode
nop                # 此时,addq指令运行到execute
nop                # 此时,addq指令运行到memory
movq %rbx, %rcx    # 此时,addq指令运行到writeback,movq指令运行到fetch
...                # 此时,addq指令写回完毕,movq指令运行到decode,可以正确取出rbx的值

气泡(Bubble)

  • 定义:保持状态,输入清空。
  • 在两个指令之间插入bubble,以确保后一条指令的操作数已被前一条指令写回。
  • 这条指令,相当于延迟了下一条指令需要冒险的阶段,下一条指令及其之后的指令会被冻结在当前阶段。
  • bubble不随着流水线流动,在硬件层面加。
  • 注意:数据冒险中的bubble与控制冒险中的bubble含义不同。
  • 在PIPE-的基础上需要加入流水线控制单元,用于实现stallbubble
  • stall即暂停,数据冒险中的bubble(因为是硬件层面)。
  • bubble即气泡,控制冒险中的bubble,直接顶掉对应寄存器内容。

转发(Bypass)

  • 定义:将结果值直接从一个流水线阶段直接传到较早阶段的技术。
  • 例如,当指令进入D阶段时,如果它需要访问的寄存器值已经在后续的E阶段或M阶段,可以通过转发路径将该值直接传递给当前指令,可以避免流水线暂停,提升流水线效率。
  • 局限性:如果后续阶段的值仍然在内存中(例如执行mrmovqpopq指令时,该值仍在M阶段),此时无法进行数据转发,称为加载/使用冒险(load/use hazard)

加载/使用冒险(Load/Use Hazard)

  • 定义:只发生在mrmovqpopq后立即使用对应寄存器的情况。
  • 探测时机:E阶段为mrmovqpopq,且D阶段的对应寄存器为其中相关。
  • 解决策略:
    • 译码阶段中的指令暂停一个周期(硬件层面一般使用bubblestall定义)。
    • 然后进行转发。
  • 示例:
mrmovq (%rdi), %rax    # 取出rdi寄存器指向地址的数据,存放在rax中
andq %rax, %rax        # 对rax寄存器进行按位与

控制冒险(Control Hazard)

  • 定义:数据需要确定下一条指令的位置。
  • 即处理器无法根据处于取指阶段的当前指令来确定下一条指令的地址。
  • 通常分为以下几类:
    • 不传递控制:对于没有控制转移的指令,直接将valP设置为下一条PC值,通常不会出错。
    • 无条件跳转/调用(Jmp/Call):将valC设置为下一条PC值,总是正确的。
    • 条件跳转:"总是跳转策略"将valC设置为下一条PC值,正确性大概为60%。
    • 其他策略:当跳转发生在前面时,总是执行;当跳转发生在后面时,通常不执行。
    • 返回指令:处理器不进行任何预测。
    • 其中,只有条件跳转返回指令会产生控制冒险。

JXX冒险

  • 定义:当E阶段发现不应该选择分支时,已经取出了两条指令。
  • 探测时机:E阶段为条件跳转指令,且Cnd为假。
  • 此时,需要清空流水线,往下两条指令所在寄存器插入两个bubble,直接顶掉指令。

RET冒险

  • 定义:检测到ret指令后,不能再让错误指令进流水线。
  • 探测时机:RETD、E、M阶段。
  • 由于无法在F阶段插入bubble,因此其在接下来三个指令的D阶段均插入bubble,直接顶掉指令。

组合冒险

组合A:JXX+RET冒险

  • 定义:E阶段有一条预测错误分支的JXX指令,D阶段有一条ret指令。
  • 要求:ret位于不选择分支的目标处,此时策略为取消ret指令。
  • 由于跳转地址与F寄存器无关,因此为取消ret指令,将F阶段设为暂停。

组合B:Load/Use冒险+RET冒险

  • 定义:mrmovq指令设置寄存器%rspret指令用它作为源操作数。
  • 此时mrmovq会使D阶段暂停,而RET会使D中插入一个bubble
  • 定义:在同一阶段,StallBubble永远不同时为真。
  • 希望只考虑针对加载/使用冒险的动作,因此修改D_bubble的处理条件。

PIPE/流水线架构

  • 综上,相比PIPE-,添加转发逻辑,就得到了PIPE架构
  • 相比之下,它是我们从CEQ一步步优化而来的。

PIPE的各阶段实现

取指

  • 取当前指令的PC,若无变化则取F_predPC
  • 由于分支预测错误的存在,若M_icode==JXX并且!Con,取M_valA
  • 因为伴随JXX产生的valP,由D_valP→E_valA→M_valA
  • 同时,若W_icode==RET,则取W_valM
  • 根据imem_error判断是否取icodeifun
  • 通过instr_valid判断指令是否有效。
  • 获取指令的状态码f_stat
  • 判断指令是否需要寄存器和常数,得到need_regidsneed_valC
  • 预测下一个PC值,得到f_predPC
  • 根据是否为加载/使用冒险以及RET冒险,设置F_stall(F阶段bubble始终为假)。

译码

  • 根据指令类型取出d_srcAd_srcB
  • 决定E阶段计算结果和M阶段读出结果的写入寄存器d_srcEd_srcM
  • 求出d_valAd_valB,此处需要满足转发逻辑,从后续E、M或W阶段转发。
  • 若为跳转指令或调用指令,则valA保存D_valP
  • 根据是否为加载/使用冒险,设置D_stall
  • 根据是否为JXX冒险或(RET冒险且不满足加载/使用冒险),设置D_bubble

执行

  • 选择ALU的输入aluA,部分指令需要将aluA设为8-8
  • 选择ALU的输入aluB,部分指令需要将aluB设为0
  • 设置ALU的功能alufun,除了IOPQ,其它默认为ALUADD
  • 计算是否更新条件码set_cc,只在IOPQ和状态正常期间改变。
  • 为传递E_valM_valA,仅设置e_valA
  • 根据是否更新条件码set_cc,计算Cnd
  • 设置e_dstE,除非当前指令为JXX!Cnd,则设置为RNONE,其余设置为E_dstE
  • 根据是否为JXX冒险或加载/使用冒险,设置E_bubble(E阶段stall始终为假)。

访存

  • 选择访存地址mem_addr
    • 若为rmmovq,pushq,call,mrmovq,则设置为m_valE
    • 若为popq,ret,则设置为M_valA(由D_valA传递来)。
  • 决定是否读取内存mem_read,是否写入内存mem_write
  • 根据是否访问错误地址,更新条件码m_stat
  • 根据是否内存异常,设置M_bubble(M阶段stall始终为假)。

写回

  • 设置E端口寄存器w_dstEE端口值w_valE
  • 设置M端口寄存器w_dstMM端口值w_valM
  • 根据是否有气泡,更新条件码Stat
  • 根据是否内存异常,设置M_stall(M阶段bubble始终为假)。

后记

写了几天,终于写完了,算是综合了几位学长各有特色、部分有缺漏的笔记写成。

第四章的难度果然名不虚传.....

alt text

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/946612.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

申威 SW-64 架构安装 MySQL 8.0.18 (KY10系统 RPM包) 步骤指南

申威 SW-64 架构安装 MySQL 8.0.18 (KY10系统 RPM包) 步骤指南​ 这是一个在采用申威SW-64处理器的服务器上,安装特定版本 ​MySQL 8.0.18 数据库的简单教程。使用的安装包是专门为申威架构和麒麟KY10操作系统适配的R…

java learning

public class Demo {public static void main(String[] args){for(int i = 1988; i< 2019; i++) {if ((i%4==0 && i%100 != 0) || i%400 ==0) {System.out.println(i);}}} }public class Demo1 {public sta…

【11】C实战篇——C语言 【scanf、printf、fprintf、fscanf、sprintf、sscanf】的区别 - 详解

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

读AI赋能10助手

读AI赋能10助手1. GPS 1.1. 地图1.1.1. 在21世纪初之前,​“纸质地图”这个词并不存在,它们当时只是被称为“地图”​1.1.2. 物理世界缩小至我们的掌心,我们的视野却因此变得更加开阔1.2. 1973年,美国国防部启动了…

P13518 [KOI 2025 #2] 镜子

解题思路 核心观察:每次使用镜子相当于进行一次对称变换,位置从 a 变为 2b - a。经过数学推导可以发现,最终的终点位置可以表示为: 终点 = 2(某些镜子的位置) - 2(另一些镜子的位置) + ... + (-1)^N 初始位置 关键…

Correlation inequality小记

定义\(n\)元函数\(f\)单调递增:如果对于所有 \(x,y\), 如果\(x_i\leq y_i\)对于\(i=1...n\)成立,那么\(f(x)\leq f(y)\)。 如果\(f,g\)单调递增,那么\(E(fg)\geq E(f)E(g)\)(\(f,g\)的定义域相同) 证明:考虑归纳…

实用指南:TimescaleDB 超表 物理表解释

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

使用Prodfiler优化eBPF编译器性能:从内存分配到向量化的全面调优

本文详细介绍了如何利用Prodfiler性能分析工具对eBPF优化编译器K2进行深度优化,通过替换内存分配器、优化数据结构、应用PGO和LTO等技术,最终实现1.4-1.9倍的性能提升。使用Prodfiler优化eBPF优化编译器 如何在不修改…

详细介绍:JMeter接口测试

详细介绍:JMeter接口测试pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", &…

深入解析:GESP25年9月编程题解析

深入解析:GESP25年9月编程题解析pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco&q…

Anthropic Agent Skills 技术解析与实践

Anthropic Agent Skills 技术解析与实践2025-10-26 09:16 姜 萌@cnblogs 阅读(0) 评论(0) 收藏 举报前言 Anthropic 在 2025 年 10 月推出了 Agent Skills 框架,这是一个让通用 AI 获得专业技能的机制。本文通过分…

d40: vue杂项问题 - 详解

d40: vue杂项问题 - 详解pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", &q…

day04-Coze工作流案例(中草药识别-菜谱生成-智能换脸)

今日内容coze的工作流---》coze智能体中:工作流支持通过可视化的方式,对插件、大语言模型、代码块等功能进行组合,从而实现复杂、稳定的业务流程编排 干一件时间的流程:第一步干什么,第二步干什么,最后干什么。。…

记力扣2271.毯子覆盖的最多白色砖块数 练习理解 - 详解

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

实用指南:【Android之路】 Kotlin 的 data class、enum class、sealed interface

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

精通-Pandas-探索性分析-全-

精通 Pandas 探索性分析(全)原文:Mastering Exploratory Analysis with Pandas 协议:CC BY-NC-SA 4.0零、前言 在本书中,您将深入学习 Pandas,这是一个 Python 库,用于处理,转换和分析数据。 这是用于探索性数…

【图像处理-基础知识】SFIT特征解析 - 教程

【图像处理-基础知识】SFIT特征解析 - 教程pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "…

深入解析:【FPGA+DSP系列】——(2)DSP最小核心板进行ADC采样实验(采集电位器输出电压)

深入解析:【FPGA+DSP系列】——(2)DSP最小核心板进行ADC采样实验(采集电位器输出电压)pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !import…

精通-HTML5-表单-全-

精通 HTML5 表单(全)原文:zh.annas-archive.org/md5/835835C6B2E78084A088423A2DB0B9BD 译者:飞龙 协议:CC BY-NC-SA 4.0前言 Web 浏览者可能永远不会了解应用程序的背景,比如 HTML5、CSS3、响应式网页设计或 PH…

ABC429F Shortest Path Query 题解

AtCoder 写在前面 赛时没想出来,赛后经过大神和题解点拨有点思路了。之前确实没咋遇见过多少线段树维护矩阵的题。那就写写题解当积累trick了吧。 题意 给出一张\(3 \times N\) 的矩阵,内含# . 两种字符。其中# 代表…