来源:RISC-V BOOM documentation

RISC-V BOOM核学习

The Berkeley Out-of-Oder Machine

INTRODUCTION

RV64GC


Fig. 1 Detailed BOOM Pipeline. ’s denote where the core can be configured.

The BOOM Pipline


Fig. 2 Simplified BOOM Pipeline with Stages

BOOM为10级流水线,实际实现为7级:(1)Fetch (2)Decode/Rename (3)Rename/Dispatch (4)Issue/RegisterRead (5)Execute (6)Memory (7)WriteBack,commit异步发生,不属于流水线。

  1. Fetch:从instruction memory取指后放入FIFO queue(即Fetch Buffer),分支预测按需重定向取指。
    Branch:BOOM支持全分支推测与分支预测。每条指令都有Branch Tag标记其处于哪一个分支预测之下,预测错误的分支需要终止依赖于该分支的所有指令。分支指令Rename时,其Register Rename TableFree List将被复制,预测错误时会恢复处理器状态。

  2. Decode:从Fetch Buffer取指,生成微操作Micro-Ops(即UOPs)放入流水线。

  3. Rename:ISA/logical register specifier(寄存器说明符,eg.x0-x31)-> physical register specifier。

  4. Dispatch:UOPs分派到一系列Issue Queue中。

  5. Issue:位于Issue queue的UOPs的所有操作数就绪后issue(发出),乱序的开始。

  6. Register Read:被发出的UOPs首先从unified Physical Register File(统一的寄存器文件)或Bypass Network(旁路网络)读取寄存器操作数。

  7. Execute:然后进入functional units(功能单元)所在的Execute阶段,发出的memory oprations(内存操作)在执行阶段进行地址计算后将结果地址存储在Memory阶段的Load/Store Unit(加载/存储单元)。

  8. Memory:Load/Store Unit包括三个队列:

    • LAQ(Load Address Queeu):LAQ中有地址时从内存中加载数据
    • SAQ(Store Address Queue)、SDQ(Store Data Queue):Commit time向内存存储数据,address和data都放入SAQSDQ时才能被commit。
  9. Writeback:ALU操作和Load操作被写回Physical Register File

  10. Commit:ROB(Reorder Buffer)跟踪流水线中每条指令的状态。ROB头不忙时,ROB提交指令。对于Store,ROB向Store Queue(SAQ/SDQ)队首的store操作发送store信号,表示可将数据写入内存。


Fig. 3 Detailed BOOM Pipeline. ’s denote where the core can be configured.

The Chisel Hardware Construction Language

The RISC-V ISA

Rocket Chip SoC Generator


Fig. 4 A single-core “BOOM-chip”, with no L2 last-level cache

CORE OVERVIEW

01 Instruction Fetch


Fig. 5 The BOOM Front-end

  • Front-end:Fetch和Branch Prediction阶段(从i-cache取指)
  • Back-end:从Dispatch到WriteBack阶段,指令执行、解决依赖、解决分支。
  • Fetch Packet:Front-end返回的一个包,包含一组连续指令,其中mask(掩码)表示哪些指令有效,以及和instruction fetch和branch prediction有关的meta-data,Fetch PC指向Fetch Packet中第一条有效指令。
  • Fetch Boundary:i-cache response末尾字节,可能是RVC指令的一半。

BOOM核与Rocket核均实例化自己的Front-end。Front-end在多个取指周期(F0,F1…)重定向指令流。如果在Back-end检测到预测错误,或者BOOM预测器希望将流水线重定向到另一个方向,会向front-end发送请求并开始沿新的指令路径取指。

由于支持superscaler fetch(超标量取指),Front-end从instruction memory中检索指令的Fetch Packet并将其放入Fetch Buffer。Fetch Packet包含一些其他meta-data,如valid mask(有效掩码,包中哪些指令有效)、一些branch prediction信息。此外,PC和branch prediction信息被存储在Fetch Target Queue

The Rocket Core I-Cache

BOOM实例化了取自Rocket Processor源代码的i-cache,i-cache是virtually indexed(虚拟索引)和physical tagged(物理标记)关联的cache。

为了降低功耗,i-cache读出固定字节(aligned对齐)存入fetch register,后续取指由该寄存器管理。i-cache只有在fetch register耗尽或分支预测将PC指向其他地方时才会再次启动。

目前,i-cache不支持跨cache-lines取指,也不支持超标量未对齐取指。

目前,i-cache不支持hit-under-miss。如果i-cache miss,i-cache不接受任何进一步请求直到miss被处理,这对于流水线发现预测失误后的重定向 i-cache以沿正确路径取指不理想。

Fetching Compressed Instructions

压缩指令RVC对于32b指令无对齐要求,可以从半字处开始取指,所有16b指令都直接映射到较长的2b指令。

在Front-end阶段,BOOM从i-cache中检索Fetch Packet,快速decode用于branch prediction的指令,并将Fetch Packet存入Fetch Buffer,带来需要处理的问题是:

  • 解码复杂度增加
  • 找到指令起始处
  • 在整个代码库中删除+4预测,尤其是分支处理
  • 未对齐指令,尤其是从cache lines和virtual pages上运行的指令

对于最后一点,需要在Fetch Unit增加额外的statefulness(状态),因为获取一条指令的所有部分可能需要多个周期。

下面通过描述指令的生命周期来描述RVC在BOOM的实现:

  • Front-End返回FetchWidth16bits宽的Fetch Packet*。
  • 在F3,维持statefulness,Fetch Packets从i-cache response queue出队进入Fetch Buffer
  • F3跟踪最后一个Fetch Packet的后16b、PC、指令边界,这些位与当前Fetch Packet组合扩展为FetchWidth×32bits以便进入Fetch Buffer,Predecode确定此Fetch Packet中每条指令的起始地址,同时为Fetch Buffer生成掩码。
  • 存储到内存时,Fetch Buffer压缩无效或未对齐指令。

其他实现细节:

  • 处理跨取指边界指令,认为这些指令属于包含其高16bits的Fetch Packet,在确定这些指令PC时,跟踪最初在Fetch Boundary上未对齐的所有指令。
  • 流水线需要跟踪指令最初为16b还是32b,用于计算PC+4或PC+2。

The Fetch Buffer

来自i-cache的Fetch Packet被放入Fetch Buffer,Fetch Buffer将Front-End取指和Back-End执行分离。Fetch Buffer是参数化的,大小可变,并且可以切换是否以flow-through queue实现。

The Fetch Target Queue

Fetch Target Queue保存从i-cache接收的PC以及与该地址关联的分支预测信息,供流水线执行UOP时参考。ROB在指令被commit时将其出队,并在流水线重定向/执行错误时update。

02 Branch Prediction


Fig.6 The BOOM Front-End

BOOM有两种分支预测:

  • NLP(Next-Line Predictor):fast,Branch Target Buffer
  • BPU(Backing Predictor):slow but complex, GShare predictor结构(更复杂)

NLP:由Branch Target Buffer (BTB)、Return Address Stack (RAS)、Bi-Modal Table (BIM)构成,用于快速预测以redirect the Front-End。
BTB :分支目标缓冲区,表项中的PC用于查找匹配目标,如果命中,指定的目标将用于redirect the pipeline。
RAS:流水线返回地址栈:用于跟踪函数调用的堆栈,JAL或 JALR时PC入栈,RET时PC出栈。
BIM:一个计数表。

BPU:用于跟踪更长历史,BOOM核中有多种不同类型BPU(TAGE, GShare…)。

The Next-Line Predictor (NLP)

Front-End取指并在预测每个cycle从何处取下一条指令,若Back-End检测出misprediction,或自身BPD希望redirect the pipeline,会向Front-end发送request并开始沿新的指令路径取指。

NLP接收当前用于取指的PC(the Fetch PC,Fetch Packet instruction group头对应的PC),并综合预测下一周期应在何处取指,若预测正确则无流水线气泡(pipeline bubbles)。

NLP Predictions

Fetch PC 首先执行目标匹配,以找到唯一匹配的BTB条目。若命中,BTB条目与RSA共同预测,以确定Fetch Packet中是否存在branch、jump、return指令,以及Fetch Packet中哪条指令是错误的。BIM用于确定所作的prediction是否执行了branch。BTB条目还包含了一个预测的目标PC,作为下一周期的Fetch PC。


Fig.7 NLP unit。Fetch PC搜索BTB的PC tags进行匹配。若命中,BIM和RAS做出final verdict(最终裁决)。若条目为ret,则tagrt来自RAS;若条目为无条件jmp,则不咨询BIM。“bidx”(或称branch index)标记了超标量Fetch Packet中造成控制流预测的指令,这对于屏蔽Fetch Packet中经过分支执行的其他指令。

BIM中的hysteresis bits(滞后位)仅在BTB条目命中且预测指令为branch时被使用。

如果BTB条目包含return指令,RAS栈将提供预测的return PC作为下一条Fetch PC,实际的RAS管理(何时执行/堆栈)由外部控制。

为提高空间利用率,PC tags和PC targets的高位被存储在压缩为文件中。

NLP Updates

沿pipline传递的每个分支不仅记住自身的PC,还有它的Fetch PC(Fetch Packet的头指令的PC)。

BTB Updates

仅在Front-End被Branch Unit(Exexute stage)或BPD(稍后的Fetch stage)重定向去执行branch或jump时,BTB才会更新。

若没有与执行的branch或jump对应的BTB条目,则为其分配一个新条目。

RAS Updates

一旦Fetch Packet中的指令被decode,RAS就在Fetch stage更新。若执行的指令为call,return address入栈RAS,或执行的指令为return,return address出栈RAS。

注:虽然RISC-V没有专用的call指令,但可以通过检查JAL或JALR指令来推断,该指令的写回目标寄存器是x1(也称为返回地址寄存器)。

Superscalar Predictions

NLP进行预测时,实际上是使用BTB tag匹配rediction branch的Fetch PC,而非其本身的PC。这是由于NLP必须在整个Fetch Packet中预测众多可能的分支中哪一个是重定向PC的控制分支(dominating branch)。

The Backing Predictor (BPD)

NLP预测良好时,处理器Back-end具有完整的执行指令流。NLP能够提供快速的单周期预测,因为它成本高(面积与功率)、非常小(只能记住几十个分支)、实现简单(BIM滞后位不能学习复杂且冗长的历史模式)。

为捕获更多分支和更复杂的分支分支行为,BOOM提供了BPD,BPD的目标是在密集区域提供高准确率。BPD只进行执行/不执行预测,因此它依赖于一些代理来提供哪些指令是branches以及它们的targets是什么的信息。BPD可以使用BTB获取这些信息,也可以等待指令从i-cache中取出后自行解码。这样就无需在BPD内存储存储PC tags和branch targts。

BPD在整个Fetch stage被访问,与i-cache和BTB并行,这允许BPD存储在顺序存储器中(i.e.SRAM而非flip-flops触发器),通过一些精巧的架构,BPD可以存储在单端口SRAM中来达到所需密度。


Fig.8 The BOOM Front-End,图下方可以看到BTB和分支预测器。从i-cache返回 的指令被快速解码;从BTB或BPD预测的任意banches将会在F4中重定向Front-end。prediction snapshots(预测快照 )和和metadata存储在Branch Rename Snapshots(预测失误后修复预测器)和FTQ(Fetch Target Queue,在commit阶段更新预测器。)

Making Predictions

BP预测时,提供:(1)是否进行预测;(2)执行/不执行预测的位向量(a bit-vector)。对于(1),BPD可能决定不做预测,预测器需要使用tags来标记预测是否有效以及可能存在的结构风险,以此来阻止的预测进行。

BPD使用bit-vector标记执行/未执行预测,bit-vector的大小与流水线的Fetch Width相匹配(Fetch Packet中一条指令一位),Fetch stage后续将对Fetch Packet中的指令decode,计算branch targets,并结合BPD的bit vector决定是否进行redirect Front-end。

Jump and Jump-Register Instructions

BPD只预测条件分支的方向(执行/不执行),无条件JAL、JALR指令的处理与BPD分离。NLP记录所有执行指令的PC和target PC,因此能够预测JAL和JALR指令。

若NLP未对JAL指令预测,流水线会在F4阶段redirect Front-end。若NLP未对JALR指令预测,指令将沿流水线发送,这是因为JALR需要读寄存器文件来推断jump target,若NLP未预测则无法执行任何操作。

Updating the Backing Predictor

一般来说,BPD在commit stage更新,这可以防止BPD被错误路径信息污染。然而,由于BPD使用了全局历史,每当redirect Front-end时,必须重置全局历史。因此在misprediction时,BPD需要在Execute阶段(部分)更新,以重置在Fetch阶段发生的任何推断性更新。

在进行预测时,BPD向流水线发送一个“response info packet”相应信息包,在commit time前,这个信息包存储在FTQ(Fetch Target Queue)中。一旦信息包对应所有指令commit,信息包被设置为BPD(包括分支的最终结果),BPD更新。用于预测的FTQ包含FTQ,FTQ处理commit时更新预测器所需的快照信息。Rename Snapshot State(重命名快照状态)包含Branch Rename Snapshots(分支重命名快照),处理在Execute stage发生misspeculation时更新预测器所需的快照信息。

Managing the Global History Register (GHR)

GHR(Global History Register,全局历史寄存器)是分支预测器的重要部分,包含了前N个branches的结果(N是GHR的大小)。在对branch-i取指时,先前i-N个branches指令的结果是可用的,这对做出正确预测是十分必要的。等到commit阶段再更新GHR太晚(几十条branches将会inflight无法反映),因此,一旦fetch branch并预测,就必须预测性的更新GHR。

若misprediction发生,必须重置并更新GHR以反映真实历史。这意味着一旦发生misprediction,每一个branch(更准确的说,每一个Fetch Packet)都必须快照GHR

最后还有一个问题——流水线行为异常。虽然每一个branch都有一个GHR快照,但任何指令都可能抛出异常,从而导致Front-end redirect,此类事件会导致GHR损坏。对于较少发生的异常,这似乎是可接受的,陷阱处理程序总会导致GHR污染。然而一些异常事件(包括pipeline replays 流水线重放——一条指令导致流水线刷新且指令被重新取指重新执行)。因此,BPD会维护GHRcommit副本,并在任何类型的流水线冲刷事件中重置。

The Fetch Target Queue (FTQ) for Predictions

ROB维护了所有inflight指令的记录。同样,FTQ维护了所有inflight branch prediction和PC信息的记录。这两个结构是解耦的,因为FTQ条目极其昂贵,且并非所有ROB条目都包含branch指令。由于每6条指令中只有1条指令是branch指令,FTQ可以比ROB具有更少条目。

每一个FTQ条目对应一个Fetch cycle。对于所作的每一个预测,分支预测器都会收集它之后执行更新所需的数据。如,分支预测器希望记录预测来自的index,以便稍后更新index处的counters(计数器)。该数据存储在FTQ中。

Fetch Packet的最后一条指令commit后,FTQ条目解除分配并返回分支预测器。使用存储在FTQ条目中的数据,分支预测器可以对其预测状态执行任何所需的更新。

commit后更新分支预测器有很多原因。预测器只学习正确的信息是至关重要的。在data cache中,从错误执行路径获取的memory稍后执行不同的路径时可能会变得有用。但对于分支预测器来说,错误路径更新会对污染信息编码,这将使存储的无用信息占用有用条目。即使以后迭代确实执行了不同路径,获取它的历史也会不同。最后,cache被完全标记后,分支预测器使用部分tag会受到解构混淆(deconstructive aliasing)的影响。

当然,Fetch和commit间的延迟是不方便的,如果多个loop迭代进行,可能会造成额外misprediction。然而,FTQ可以绕过分支预测来缓解这个问题。目前,BOOM还不支持这种绕过操作。

Rename Snapshot State

FTQ保存commit时(正确/错误预测)更新分支预测器所需的分支预测器数据。然而,在分支预测其做出错误预测且必须立即更新时,还需要额外的state。如,misprediction时,推测性更新的GHR必须重置为正确值,处理器才可以再次开始取指和预测。

这种state非常昂贵但是一旦在execute阶段解决了branch就可以释放。因此,state和Branch Rename Snapshot并行存储。在DecodeRename期间,将会为每一个branch分配一个branch tag,并制作rename tables的snapshot,以便在misprediction发生时进行单周期回滚。与branch tag和Rename Map Tabel snapshots一样,在Execute阶段,一旦Branch Unit解决branch后,对应的Branch Rename Snapshot将被释放。


Fig.9 The Branch Prediction Pipline.图表有助于显示分支预测流水线中的I/O,Friint-end将下一个PC(即Req)发往F0,在"Abstract Predictor"中,hashig由其wrapper(包装器)管理。然后,"Abstract Predictor"返回一个BPD Resp,或者说,返回对Fetch Packet中每条指令的prediction(预测)。

The Abstract Branch Predictor Class

为了便于研究不同的基于global history的BPD设计,提供了一个抽象的**“BrPredictor”类**。它为BPD和控制逻辑提供了标准接口,用于管理global history register。抽象类在Fig.9中为“Abstract Predictor”,更详细的例子在Fig.12中。

Global History

正如在Managing the Global History Register(GHR)中讨论的,global history时分支预测器的关键部分。因此,它由抽象 BranchPredictor 类处理,任何扩展抽象 BranchPredictor 类的分支预测器都能够访问global history而无需快照、更新、绕过。

######Operating System-aware Global Histories

尽管其益处才初步展现,BOOM提供支持操作系统的global history。通常的global history会跟来自所有特权级别的所有指令。二级user-only global history仅跟踪user-level指令。

The Two-bit Counter Tables

大部分branch predictor的基本构造块是2BC(Two-bit Counter table,2bit计数器表)。当重复执行某个特定分支时,计数器会向上饱和到最大值3(0b11)或强制执行。同样的,重复未执行分支会使计数器向下饱和到最小值0(0b00)。高位指定prediction,低位指定hysteresis(prediction的强度)。


Fig.10 GShare Predictor使用global history与PC的hash来索引2BCs,高位进行预测。

2BCs被放在一个表中。理想情况下,一个好的分支预测器知道哪一个计数器索引能够做出最优预测。然而,为将2BCs放入密集SRAM中,对2BC的有限状态机做了一些修改——weakly not-taken下的mispreddiction会使2BC进入strongly taken(weakly taken下的misprediction亦然->strongly taken),FSM见Fig.11。

虽然它在严格意义上不算计数器了,但这一修改允许我们分离出对predicton位和hystersis位的读写要求,并将他们单独放在顺序内存表中。2BC表的硬件实现如下:

The P-bit(prediction):

  • Read - 每周期做一个prediction。
  • Write - 仅当misprediction发生时(h-bit的值)。

The H-bit(hysteresis):

  • Read - 仅当misprediction发生时。

  • Write - branch被解析(写入分支的方向)。


Fig. 11 2BC的状态机

通过分离P-bit和H-bit,我们可以将他们放入1读/1写SRAM。misprediction很少见,分支解决不一定在每个周期都发生。此外,写操作可能被延迟甚至删除。因此,h-table可以使用1端口读/写SRAM来实现,方法是将写操作排队,并在不执行读操作时将其排空。同样,p-table也可以通过1端口读/写SRAM实现——在没有读冲突的情况下进行缓冲区写入和耗尽。

最后一点:SRAM对2BC表所需的"长窄"不适用。解决方法也很简单——”长窄“表可以简单地转化为矩形内存结构,索引的高位对应于SRAM行,低位可用于从SRAM行内多路输出特定位。

The GShare Predictor

GShare是一个简单且高效的分支预测器。通过对指令地址和GHR进行hash(通过是简单XOR)后在2BC表中索引进行预测。Fig.10显示了GShare predictor的逻辑架构,Fig.12显示了GShare predictor的物理实现和结构。注意当请求地址被发送到预测器时,预测在F0开始,但一旦指令从i-cache返回且prediction state已经从p-table读取,预测将在稍后的F3进行。


Fig. 12 The GShare Predictor 流水线

The TAGE Predictor


Fig.13 The TAGE predictor.请求地址(PC)和global history被输入到每个表的idx_hash和tag_hash。每个表都提供自己的预测(或无预测),history最长的表获胜

BOOM实现了TAGE条件分支预测器。TAGE是一个高度参数化、最先进的hlobal history预测器。其设计从极小规模到极大规模都能够维持较高精确度,也能够快速学习短history,同时也能学习非常长(超过1000个分支历史)的history。

**TAGE(TAgged GEometric)**作为一组predictor tables(预测表)被实现。每个表项包含:a prediction countera usefulness countera tag。prediction counter提供预测(并维持一些hysteresis以确定预测taken/not-taken的程度),usefulness counter跟踪特定条目过去在提供正确预测方面的有效性,tag允许table只有在特定请求指令地址和global history的tag匹配时进行预测。

每一个表都有不同数量(几何级数增长)与之相关的history,每个表的history用于与请求指令地址hash以生成index hashtag hash。每个表都将做出自己的预测(若无tag匹配,则不预测)。history最长的表预测胜利。

misprediction时,TAGE尝试分配新的条目,它只会覆盖无效条目(ubits==0)。

TAGE Global History and the Circular Shift Registers (CSRs)

每一个TAGE表都有自己的global history(且每个表的history都比上一个表几何倍多)。history可以用来索引TAGE表,因此必须”folded"适应。包含1024表项的表使用10位来索引,因此如果表中使用了20位global history,那么表的高10位history和低10位history时被异或的。

global hisitory被存储在**循环移位寄存器(CSR)**中,而不是在每个cycle动态折叠很长的history register。global history已经折叠存储,只需要提供新的history bit和最旧的history bit即可执行更新。Listing 2是CSR示例。

Listing 2.The circular shift register. 当添加新的分支结果时,register移位,新结果被添加,最早的结果被删除。

Example:A 12 bit value (0b_0111_1001_1111) folded onto a 5 bit CSR becomes(0b_0_0010), which can be found by:/-- history[12] (evict bit)|c[4], c[3], c[2], c[1], c[0]|                        ^|                        |\_______________________/ \---history[0] (newly taken bit)(c[4] ^ h[ 0] generates the new c[0]).
(c[1] ^ h[12] generates the new c[2]).

每个表必须维护3个CSRs,第一个CSR用于计算index hash,其大小为n=log(num_table_entries)。由于CSR包含folded history,任何与CSR长度匹配的周期历史模式都将XOR为全0(可能很常见)。因此,有两个用于计算tag hash的CSR,一个宽度为n,另一个宽度为n-1.

每个表必须维护三个CSR。第一个CSR用于计算索引哈希,其大小为n=log(num_table_entries)。由于CSR包含折叠历史,任何与CSR长度匹配的周期历史模式都将XOR为全零(可能非常常见)。因此,有两个用于计算标记哈希的CSR,一个是宽度n,另一个是宽度n-1。

如果发生misprediction,必须对三个CSR(每个表)进行快照并重置。必须维护这些CSRs的另外三个commit副本,以处理流水线冲刷。

Usefulness counters (u-bits)

表项的"usefulness"存储在u-bit counter中。粗略的说,如果一个表项提供了正确预测,那么u-bit counter增加,如果提供了错误预测,那么u-bit counter递减。当预测失误时,TAGE尝试分配新的表项。为防止覆盖有用表项,它只会在现有表项的usefulness为0时分配。然而,如果分配失败,由于所有潜在表项都是有用的,所有潜在表项数目会减少,以便为将来的分配腾出空间。

为了防止TAGE只填写有用但很少使用的条目,TAGE必须提供一个随时间“降级”u-bits的方案。这有许多方案可供选择,一个选择是定时降低u-bits counter的定时器,另一个选择是跟踪失败分配的数量(失败分配时递增,成功分配时递减),一旦计数器饱和,所有u-bits都会降级。

TAGE Snapshot State

对于每个预测,如果发生分支预测失误,必须对所有三个CSR(每个表)进行快照并重置。TAGE还必须记住用于预测检查的每个表的索引(以便以后可以正确更新每个表的表项)。最后,TAGE必须记住为每个表计算的tag——稍后若分配新表项需要这些tag。

Other Predictors

BOOM提供了一些其他类型的预测器,可能会提供有用信息。

The Base Only Predictor

Base Only Predictor使用BTBs BIM来预测是否执行分支。

The Null Predictor

在不需要BPD时,使用空预测器(Null Predictor),它总会预测为不执行(not taken)。

The Random Predictor

Random Prediction使用LFSR随机“是否预测”和“Fetch Packet中的每一条branch的方向”。这对于torturing-test和在比较分支预测器时提供最差情况下的性能基线来说非常有用。

03 The Decode Stage

Decode阶段从Fetch Buffer获取指令,对其进行解码,并根据每条指令的需要分配所需资源。如果不是所有的资源都可用,Decode stage将根据需要停止。

RVC Changes

RVC decode是通过使用Rocket的RVCExpander扩展RVC指令实现的,不会改变Decode阶段的正常功能。

04 The Rename Stage

Rename将指令的ISA/logic register specifilers(寄存器说明符)映射为physical register specifiers

The Purpose of Renaming

Renaming将指令的ISA/logic register specifilers映射到新的physical register space实现重命名。register renaming的目的是打破指令间的输出依赖(WAW)和反依赖(WAR),只留下真正的依赖(RAW)。在体系架构术语中,register renaming消除了WAW和WAR危险,这是由以下两点引入的:a)只有有限数量的ISA寄存器用作说明符;b)loops,每次循环迭代会使用相同寄存器说明符。

The Explicit Renaming Design


Fig. 14 A PRF design (left) and a data-in-ROB design (right)

BOOM是一种”显式重命名“/”物理寄存器文件“乱序处理器设计。Physical Register File包含的寄存器比ISA规定的多,同时包含了commit和speculative寄存器状态。Rename Map Table包含了恢复commit state所需的信息。当指令rename时,他们的寄存器说明符会显示更新以指向位于Physical Register File中的physical register。

这与”隐式重命名“/”data-in-ROB“乱序处理器设计形成对比。**Architectural Register File(ARF)**只保存committed register状态,而ROB保存推测性write-back数据。在commit时,ROB推测性数据传输到ARF。

The Rename Map Table


Fig. 15 The Rename Stage. logic寄存器说明符读取Rename Map Table以获取其physical说明符。对于超标量重命名,对Map Tables的任何更改都必须绕过相关指令。physical源说明符能够读取Busy TableStale说明符用于跟踪指令稍后commit时释放physical register。Physical Register File中的P0始终为0。

Rename Map Table(缩写为Map Table)保存了从ISA register到physical register的推测性映射。

每一个branch都有自己的Rename Map Table副本。在misprediction时,Rename Map Table可以立即通过发生misprediciton的branch的Rename Map Table副本进行重置。

由于RV64G使用位置固定的寄存说明符(无隐式寄存器说明符),因此,能够在Decode前读取Map Table,Decode和Rename阶段可以结合。

Resets on Exceptions and Flushes

另一个可选的”Committed Map Table“保存了commited architectural state时的rename map。如果启用,则允许在流水线冲刷和异常期间对流水线进行单周期重置(当前map table重置为Committed Map Table)。否则,流水线冲刷需要多周期”unwind(放开)“ROB,以便在commit point以rename state写回,每周期一行ROB。

The Busy Table

Busy Table跟踪每个physical register的就绪状态,如果所有物理操作数就绪,指令就可以发出(issued)。

The Free List

Free List跟踪当前未使用的physical register,并用于将新的physical register分配给通过Rename stage的指令。Free List通过a-bit vector实现,可以使用优先级解码器来查找第一个空闲寄存器。BOOM使用级联的优先级解码器在每个周期分配多个寄存器。

在每个branch(或JALR)对Rename Map Table进行快照,以允许对misprediciton进行单周期恢复。同样,Free List也会留出一个新的”Allocation List“,初始化为0。当新的physical register被分配,每个banch的Allocation List也会更新,以跟踪branch后分配的所有physical register。如果misprediction,branch的Allocation List与FreeList进行OR后添加回Free List。

Stale Destination Specifiers

对于将要写入寄存器的指令,Map Table被读取以获得stale physical destination specifier(过时的物理目标说明符,stale pdst)。一旦指令commit,stale pdst将返回到Free List,因为将来没有指令读取它。

05 The Recorder Buffer(ROB) and the Dispatch Stage

ROB(Reorder buffer)跟踪流水线中所有inflight指令的状态,ROB的作用是向编程者提供一种它的程序在按顺序执行的错觉(illusion)。指令被decode和rename后,被dispatch到ROB和Issue Queue,并被标记为busy。指令执行完毕后,会通知ROB并被标记为not busy。一旦ROB的“头”不busy,指令被commit,其architectural state可见。如果发生异常且异常指令位于ROB头,则流水线冲刷且在异常指令公布后无架构改变。ROB重定向PC到相应的异常处理程序。

The ROB Organization


Fig.16 The Reorder Buffer for a two-wide BOOM with three-issue. Dispatched UOPs(dis uops)被写入ROB底部(rob tail)。Committed UOPs(com uops)从ROB顶部(rob head)被交付,并更新rename state。执行完毕的UOPs(wb uops)清楚busy位。注意:dis uops被一起写入ROB同一行,并连续存储在内存中,一个PC能够表示整行。

ROB从概念上讲是一个跟踪所有顺序inflight指令的循环缓冲区。最早的指令由commit head指向,最新的指令被添加在rob tail。为方便超标量dispatch和commit,ROB由具有w个bank的循环缓冲区实现(w是dispatch和commit的宽度)。结构如Fig.16所示。

在dispatch时,多达w条指令从Fetch Packet写入ROB行,每条指令被写入该行的不同bank。由于Fetch Packet中的指令在内存中连续(且对齐),这允许整个Fetch Packet由一个PC表示(并且指令在Fetch Packet中的位置向它们自身的PC提供低位)。这意味着分支代码将在ROB中留下bubble(气泡),但由于昂贵的成本在ROB行被分摊,使得向ROB中添加更多指令的成本很低。

ROB State

每个ROB条目包含如下状态:

  • 是否有效valid
  • 是否忙碌busy
  • 是否为异常exception
  • 分支掩码(该条目在那个分支预测下)
  • rename状态 (logic目标和过时的physical目标)
  • 浮点状态更新
  • 其他数据 (e.g. 有助于统计跟踪)

PC和分支预测信息按行存储(见PC Storage),Exception State仅跟踪最早的异常指令。

Exception State

ROB跟踪最早的异常指令,若该指令到达ROB头,就抛出异常。

每个ROB条目由单bit标记,以表示该指令是否遇到异常行为,但额外的异常状态(e.g.错误的虚拟地址和异常原因)仅针对最早的异常指令进行跟踪。不按条目存储可以节省大量状态。

PC Storage

ROB必须知道所有inflight指令的PC,用于如下情况:

  • 任何指令都可能导致异常,必须知道异常PC。
  • branch和jump指令需要知道其自身PC,以进行目标计算。
  • JALR指令需要知道其自身PC和程序中后续指令的PC,用于验证Front-end是否预测了正确的JR目标。

这些信息的存储成本很高。branch和jump指令在Register-read阶段访问ROB的“PC File”用于Branch Unit的是哟个,而非沿流水线传递PC。这使用了两种优化:

  • ROB每行仅存储一个PC。
  • PC File存储在2个banks中,允许一个读端口同时读取连续两个条目(供JR指令使用)。

The Commit Stage

位于commit头的指令不busy(且非异常)时将被提交,也就是说它对机器架构状态的改变时可见的。对于超标量commit,将分析整个ROB行的not busy指令(因此,一个周期最多可以提交整个ROB行)。ROB将commit每行尽可能多的指令,以尽快释放资源。ROB目前不支持跨多行查找可提交的指令。

存储只有在被commit后才能送往memory。对于超标量的存储提交,Load/Store Unit (LSU)被告知被标记为提交的存储的数量。LSU视情况将提交的存储排入memory。

当一条指令(写入register)commit,会释放stale physical destination register(过时的物理目标寄存器),之后stale pdst会被自由的重新分配给新的指令。

Exceptions and Flushes

异常处理发生在commit头的指令异常时,之后流水线被冲刷,ROB被排空。Rename Map Tables需要被重置以表示真实的、非预测性的交付状态(committed state),Front-end重定向到相应的PC。如果是架构异常,异常指令的PC(称为异常向量)被送往CSR(Control/Status Register)文件。如果是微体系架构异常(如load/store排序错误),会重新读取失败的指令,并重新开始执行。

Parameterization - Rollback versus Single-cycle Reset

重置Rename Map Tables的行为是参数化的。第一个参数是每cycle回滚一行ROB以释放rename state(这是MIPS R10k的行为)。对于每条指令,stale pdst被写回Map Table作为其逻辑目标说明符。

更快的单周期重置是可用的,它通过使用另一个跟踪rename tables的committed state的rename快照实现。这个Commited Map Table随着指令的提交更新。

Causes

RV64G提供给的异常源相对较少:

  • Load/Store Unit:页面错误(page fault)
  • Branch Unit:未对齐取指(misaligned fetches)
  • Decode Stage:在指令dispatch到ROB前,可以处理所有的异常和中断。

注意,内存排序预测错误也源于LSU,在BOOMM流水线上被视为异常(实际只导致流水线“retry”)。

Point of No Return (PNR)

point-of-no-return头在ROB commit头前面,标记下一条可能被误判或生成异常的指令,包括未解析的分支和未翻译的内存操作。因此,在commit头前面和PNR头后面的指令保证是non-speculaitive(非推测行)的,即使它们尚未被写回。

目前,PNR仅用于RoCC指令。RoCC协处理器通常希望它们的指令顺序,且不出现误判。因此,我们只能在一条指令通过PNR头后再向协处理器issue,此时不再是推测性的。

06 The Issue Unit

Issue Queue保存了dispatch但未execute的UOPs。当UOP的全部操作数就绪,issue slot将其“requet”位置1,之后issue选择发出一个断言了request信号的slot。UOP一旦被issued,就会从Issue Queue移除,以便为更多派发的指令腾出空间。

BOOM使用拆分的Issue Queues,特定类型的指令放入唯一对应的ISssue Queue(整数、浮点、memory)。

Speculative Issue

尽管尚不支持,但未来的设计可能会选择预测性地发出UOPs以提高性能(例如,假设负载数据在旁路网络中可用,推测load指令将命中cache,从而发出相关UOPs)。在这种情况下,Issue Queue无法删除预测性发出的UOP,直到预测的问题得到解决。如果预测性发出的UOP故障,则必须终止预测窗口内所有已发出的UOP,并从 Issue Queue中重试。还有更先进的技术。

Issue Slot

Fig17显示了来自Issue Queue的单个issue slot。指令被diapatch到Issue Queue,从这里开始,它们等待所有操作数就绪(“p”是存在位,标记了操作数合适出现在register file)。一旦就绪,issue slot将断言其“request”信号,并等待被发出。

Issue Select Logic


Fig. 17 A single issue slot from the Issue Queue.

每个Issue Select Logic端口都是一个静态优先级编码器,用于获取Issue Queue中第一个可用UOP。每个端口只调度该端口能够处理器的UOP(如floating point UOPs只调度到管理Floating Point Unit的端口上)。这将为可以彼此调用相同UOPs的端口创建级联的优先级编码器。

如果某个功能单元不可用,将取消其可用信号的断言,并且不会向其发出指令(如,一个非流水线divider)。

Un-ordered Issue Queue

BOOM中由两种可用的调度策略。

第一种是类似MIPS R10K的Un-ordered Issue Queue。dispatch指令被放在第一个可用的Issue Queue slot中,并一直保持在该位置直到issued。这可能会导致严重 的性能低下,尤其在不可预测branch被放置在优先级较低的slot,直到ROB file被填满且Issue Window被耗尽才能被issue。由于branch后的指令仅隐式依赖于该branch,因此处理填充ROB,没有其他强制函数能够使branch尽早issue。

Age-ordered Issue Queue

第二种可用策略是Age-ordered Issue Queue。dispatch指令被放在Issue Queue底部(最低优先级)。每周期,每条指令向上移动。因此,最早的指令处于最高issue优先级。虽然这可以通过尽早调度早的branch和load提高性能,但由于每个周期每个Issue Queue slot都可能被读写,会带来潜在的能量损失。

Wake-up

BOOM中有两类wake-up——fast wakeup和slow wakeup(也称long latency wakeup)。由于ALU UOPs可以通过bypass network发送写回数据,因此发出的ALU UOPs将在发issue时向Issue Queue广播其wakeup。

但是,floating-point操作、loads、可变延迟操作不会通过bypass network发送wakeup信号,而是在write-back阶段来自register file端口。

07 The Register File and Bypass Network


Fig. 18 An example multi-issue pipeline. Integer register file需要6个读端口和3个写端口,用于当前的execution unit。FP register file需要3个读端口和2个写端口。FP和memory操作对integer and FP register file共享1个长延迟写端口。为简化写端口的调度,ALU流水线被延长以匹配FPU演出。ALU能够从任何阶段绕过Register Read stage的相关指令。

BOOM是一种统一的Physical Register File (PRF) 设计。register file保存着committe state和speculative state。另外,还有两个register file:一个用于整数,另一个用于浮点寄存器值。Rename Map Tables跟踪哪个physical register对应哪个ISA register。

BOOM使用Berkeley hardfloat floating point units,该单元使用内部65-bit操作数格式。因此,所有的physical floating point register都是65-bits。

Register Read

寄存器文件静态的所有issued指令所需的寄存器读端口。如,如果issue port #0对应一个整型ALU且issue port #1对应memory unit,那么前两个寄存器读端口将静态的为ALU服务,接下来两个寄存器读端口将为memory unit服务,一共四个读端口。

Dynamic Read Port Scheduling

未来的设计可以通过提供更少的寄存器读端口,并使用动态调度来仲裁这些端口,从而提高区域效率。由于大多数指令只需要一个操作数,这将会很有用。然而,它确实增加了额外的设计复杂性,如机型仲裁和检测结构危险的额外流水线阶段。它还需要能够终止已发布的微操作(UOP),并在后续周期中从Issue Queue中重新发布。

Bypass Network

ALU操作可以通过Bypass Network转发write-back values来进行back-to-back issue。Bypassing发生在Register Read阶段的末尾。

08 The Execute PipLines


Fig.19 2-issue BOOM的流水线示例。第一个issue端口将UOPs调度到Excute Unit #0,该Unit可以接收ALU操作、FPU操作、整数乘法操作。第二个issue端口调度ALU操作,整数除法指令(非流水线)、load/store操作,ALU操作能够绕过相关指令。注意处于Execution Unit #0的ALU填充流水线寄存器来匹配FPU和iMil单元的延迟,从未简化写端口的调度。每个Execute Unit都有一个专用的issue端口,其中包含了一些低级别的Functional Units。

Execution pipeline包括UOPs的execution和write-back。尽管UOPs会按issue顺序沿流水线向下移动,但UOPs本身可能以无序方式被issue到Execution Pipeline。Fig.19显示了2-issue BOOM的Execution Pipeline示例。

Execution Units


Fig.20 Execution Unit示例。本特定示例显示了一个整数ALU(可以将结果绕过相关指令)和非流水线divider(在操作时变忙),两个Functional Unit共享一个写端口。Execution Unit接收kill信号和branch resolution信号,并根据将它们传递给内部Functional Unit。

Execution Unit模块的issue port将UOPs调度到该模块,并包含一些组合的Functional Units。换言之,Issue Queue的每一个issue port仅和一个Execution Unit对话。一个Execution Unit可以只包含一个简单的整数ALU,也可以包含整个浮点单元、整数ALU和乘法的实现。

Execution Unit的目的是提供一个灵活的抽象,能够提供架构师将哪种Execution Unit添加到流水线的大量控制。

Scheduling Readiness

Execution Unit提供了可用于issue调度器的Functional Unit的a-bit vector。issue调度器仅调度Execution Unit支持的UOPs。对于并非总是就绪的Functional Units(如非流水线divider),bit-vector中对应的位向量可能不使能。

Functional Unit


Fig.21The abstract Pipelined Functional Unit class. 抽象流水线Funcitonal Unit类。一个专家编写的、low-level Functional Unit在Functional Unit被实例化。request/response端口被抽象化,同时提供了bypass和branch speculation支持。UOPs在退出low-level Function Unit时,通过关闭其response被单独kill。

Functional Units时CPU的肌肉,根据指令的需要计算必要的操作。Functional Units通常需要一位知识渊博的领域专家来实现以确保准确、高效。

基于这个原因,BOOM使用一个抽象Functional Unit class来包装Rocket库(参考Rocket Chip SoC Generator)中专家编写的low-level Functional Unit。这个为Rocket顺序处理器设计的Functional Units是基于顺序issue和commit设想的(即一旦指令被dispatch到functional units就永远无需kill),这一设想在BOOM中被打破。

然而,BOOM没有重写或fork Functional Unit,而是提供了一个抽象Functional Unit class,用参数化的自动生成支持的代码包装low-level functional units,使其能够在BOOM中工作。request/response端口是抽象的,允许Functional Units提供统一的、可交替的接口。

Pipelined Functional Units

Fig.21显示了一个Pipelined Functional Unit。Pipelined Functional Units每周期能够接收一个新的UOPs,每个UOP采用已知的固定延迟。

预测支持是通过一条自动生成的流水线提供的,流水线在专家编写的Functional Unit内与UOP并行传递UOP meta-data和branch mask。如果UOP预测失误,其相应在离开functioncal unit取消断言。

Un-pipelined Functional Units

Un-pipelined Functional Units(如.divider)采用可变周期数来实现单次操作。一旦被占用,将取消其就绪信号的断言,并且不会为他们安排额外的UOPs。

预测支持通过跟踪Functional Unit的UOP的branch mask提供。

专家编写的un-pipelined Functional Unit的唯一要求是提供kill信号以快速移除misspeculated UOPs。


Fig.22 椭圆虚线是专家编写的low-level Functional Units,方形是实例化low-level Functional Units的具体类,八角形是提供通用推测支持并与BOOM流水线接口的抽象类。浮点除法和平方根单元既不适合pipelined抽象类,也不适合upipelined抽象类,因此直接从FunctionalUnit超类继承。

Branch Unit & Branch Speculation

Branch Unit处理所有branch和jump指令的解析。

所有在流水线中inflight(具有一个分配的ROB条目)的UOPs都有一个branch mask,其中的每bit对应UOP推测中的未执行的infight branch的tag。每个banch在Decode是被分配一个branch tag,所有后续的UOPs将在branch mask中设置相应bit(直到Branch Unit解析该branch)。

如果branches(或jumps)被Front-end正确推测,Branch Units唯一的操作是向所有inflight UOPs广播对应的branch tag,表明该branch已被正确解析。然后,每一个UOP都能够清楚它们branch mask中的相应bit,之后这个branch tag就可以在Decode阶段被分配给新的branch。

如果branch(或jump)被预测错误,Branch Unit必须重定向PC到正确目标,kill Front-end和Fetch Buffer,并且广播预测错误的branch tag,以便所有相关的inflight UOPs被kill。PC重定向信号立即发出,以减少预测错误的惩罚。然而,kill信号由于关键路径将被延迟一周期。

Front-end必须在流水线中传递合适的branch speculation meta-data,以便评估正确的方向和预测一致。JALR指令通过将正确目标和ROB中下一条指令的PC(若不可用,假定预测失败)进行比较来评估。Jump在Front-end评估和处理(因为一旦指令decode,它们的方向和目标就已知)。

BOOM当前只支持一个Branch Unit。

Load/Store Unit

**Load/Store Unit (LSU)**处理load、store、atomic和fence操作,更多信息见LSU。

BOOM目前支持一个LSU(因此每周期只能向内存发送一个load/store)。

Floating Point Units


Fig.23 FPU的类层次结构。专家编写的代码包含在hardfloat和rocket库中。FPU类实例化Rocket组件,组件本身由抽象Functional Unit类进一步包装(提供out-of-order推测支持)。

BOOM使用的low-level floating point units来自Rocket处理器和hardfloat库。Fig.显示了FPU的累成词结构。

为了简化写端口调度,所有pipelined FP units被填充为相同延迟。

Floating Point Divide and Square-root Unit

BOOM使用单个FDiv/Sqrt(简称fdiv)完全支持浮点除法和平方根操作。BOOM通过从hardfloat库实例化一个双精度单元来实现这一点。该unit具有以下特点/限制:

  • 需要65位重新编码的双精度输入
  • 提供65位重新编码的双精度输出
  • 能够同时执行除法运算和平方根运算
  • 操作unpipelined,需要未知、可变的延迟。
  • 提供不稳定的FIFO接口

单精度运算将操作数扩展到双精度(之后将输出缩小)。

尽管该单元unpipelined,但它并不完全适合其他Functional Units使用的Pipelined/Unpipelined抽象。这是因为该unit提供了不稳定的FIFO接口:尽管这个unit可以在cycle i提供一个ready信号,但不能保证在cycle i+1继续ready,即使没有操作数队列。事实证明这是一个挑战,因为Issue Queue可能会尝试issue指令,但不能确定在稍后的周期到达该unit后是否会接收该指令。

解决的方法是在unit中添加额外的buffer来保存指令,直到它们可以直接释放到unit,如果unit的buffer被填满,可以安全的向Issue Queue提供back pressure。

Parameterization

BOOM在指定issue宽度和Functional Units组合方面提供了灵活性。关于BOOM中如何实例化execution pipeline的详细信息参考src/main/scala/exu/execution-units.scala

在配置设置(src/main/common/config-mixins.scala)中可以找到与FP单元延迟等相关的其他参数。

Control/Status Register Instructions

一组CSR(Control/Status Register,控制/状态寄存器)指令允许对CSR原子读/写。这些体系架构寄存器与整数和浮点寄存器分开,包括周期技术,失效指令计数,状态、异常PC、异常向量寄存器(以及更多)。每一个CSR都有自己所需的读写权限级别,一些在读/写时存在副作用。

BOOM(目前)没有rename任何CSRs,除了读写CSR可能带来的副作用,BOOM只会非推测性的执行CSR指令。这通过将CSR指令标记为“唯一”(“序列化”)指令来实现,ROB在进入Issue Queue前必须为空(在完成执行并被ROB交付前,任何指令都不能跟随他)。之后由Issue Queue发出,从physical register file读取相应的操作数,然后发送到CSRFile。CSR指令在CSRFile执行,然后根据需要向Physical Register File写回数据。作为CSR指令执行的一部分,CSRFile还可能发出PC重定向和异常(如,syscall)。

The Rocket Custom Co-Processor Interface (RoCC)

RoCC interface(The Rocket Custom Co-Processor Interface,Rocket定制协处理器接口)从控制处理器的标量Register File接收RoCC指令和最多两个寄存器输入。RoCC指令实际上是由控制处理器(Control Processor)获取整个RISC-V指令。因此,每一个RoCC queue表项的大小至少为2*XPRLEN + 32 bits(额外的RoCC指令可能会使用更长的指令格式编码额外的行为)。

由于BOOM不会将指令位存储在ROB中,因此一个独立的数据结构(RoCC Shim)会保存指令,直到RoCC指令可以交付并将RoCC命令发送到协处理器。

源操作数也需要访问BOOM的register file。RoCC指令被dispatch到Issue Window,并进行调度,一旦操作数可用,它们就会访问register file的读端口。之后操作数被写入存储了操作数和指令bit的RoCC Shim,直到它们能够被发送到协处理器。这需要重要状态。

在发出RoCC后,我们跟踪一个in-flight RoCC指令队列,因为我们需要将逻辑目的寄存器标识符从RoCC相应转换为之前rename的物理目的寄存器标识符。

目前RoCC接口不支持中断、异常、BOOM FPU重用、直接访问L1 data cache。这很容易添加,并将随着需求的增加完成。

09 The Load/Store Unit(LSU)


Fig. 24 The Load/Store Unit

Load/Store Unit (LSU)负责决定何时向memory system发起内存操作。有两个队列:Load Queue (LDQ)和Store Queue (STQ)。Load指令生成"uopLD",被issue时,"uopLD"计算load address并将结果放在LDQ。Store指令生成两个uops,“uopSTA”(Store address Generation)和“uopSTD”(Store Data Generation)。STA UOP计算store address并将address更新到 STQ中,STD UOP将store data移动到STQ中。一旦这些操作数就绪,这些UOPs就会从Issue Window发出。

Store Instructions

Store Queue的条目在Decode阶段分配(stq(i).valid置位)。有效位(valid)标志STQ表项存储的地址有效且数据有效(stq(i).bits.addr.valid && stq(i).bits.data.valid)。

一旦store指令commit,STQ中对应的表项被标记为committed。然后,store在方便时被发送到memory system。store按程序顺序被发送到memory。

Store Micro-Ops

store作为一条指令被放入到issue window(而非分解为独立的addr-gen个data-gen)。这可以防止昂贵的issue window条目被浪费,以及LSU在issue端口的额外争用。两个操作数就绪的store可以作为一个UOP被发送到LSU,该UOP项LSU提供地址和数据。虽然这需要store指令访问两个寄存器文件读端口,其动机是不希望store-heavy code上性能减半。涉及到堆栈存储的序列应在IPC-1时操作。

然而,通常在存储数据已知前就知晓存储地址。存储地址需要尽快移动到STQ以便稍后loads,以避免memory ordering failures。因此,issue window将按需发出uopSTA或uopSTD,但保留存储区剩余的一半,直到第二个操作数就绪。

Load Instructions

LDQ中的表项在Decode阶段(ldq(i).valid)被分配。在Decode,每一个load表项被赋予一个store mask(ldq(i).bits.st_dep_mask),标记了给定load依赖于SDQ中的哪一个stores。当store被发往memory并离开STQ,store mask中的相应位被清除。

一旦load address被计算出并放在LDQ,相应的valid为被置位(ldq(i).addr.valid)。

loads在到达LSU时被发送到memory(提前发出load是out-of-order pipeline乱序流水线带来的巨大好处)。同时,load指令将其地址与它依赖的所有store地址进行比较。如果匹配,memory request被终止(kill)。如果存在相应的store data,store data将被转发给load并且load将自身标记为已成功(succeeded)。如果store data不存在,load进入休眠状态(sleep)。已休眠的load在以后会重试。

The BOOM Memory Model

BOOM遵循RVWMO内存一致模型。

BOOM目前有如下行为:

  1. Write -> Read约束放宽(新loads可能在旧stores前执行)。
  2. Read -> Read约束保持(对同一地址顺序loads)。
  3. 线程可以很早地读取自身写操作。
Ordering Loads to the Same Address

RISC-V WMO内存模型对相同地址的loads排序。这需要loads针对其他loads从查找潜在的地址冲突。如果新load在具有匹配地址的旧load前执行,则必须重放新load并在流水线冲刷它之后的指令。然而,只有在cache一致探测事件探测到memory,将重排序暴露给其他线程时,才需要这种方案。如果没有发生探测事件,就可以安全进行load重排序。

Memory Ordering Failures

LSU需要注意store->load存储依赖关系。为获取最佳性能,需要尽快将loads发往memory。

sw x1 -> 0(x2)
ld x3 <- 0(x4)

然而,如果x2和x4引用相同的内存地址,那么示例中的load取决于之前的store。如果load向内存issue前store已经issue,load将从memory读取错误的值,并且发生内存排序失败(memory ordering failure)。排序失败时,流水线必须被刷新并且重置 Rename Map Table。这是一个十分昂贵的操作。

为了发现排序失败,在store commit时,它会检查整个LDQ是否存在任何地址匹配。如果存在匹配项,store将检查load是否已执行,是否从memory中获取data,或者data是否从较旧的store转发。在这两种情况下,都发生了内存排序失败。

有关LSU的更多信息,参见图24。

10 The Memory System

由于新的DCache实现,本节已于19年8月26日过期。

USAGE

OTHERS

RISC-V BOOM核学习相关推荐

  1. 计组学习笔记2(RISC v版)

    指令集解释 (规定:R[r]表示通用寄存器r的内容,M[addr]表示存储单元addr的内容,SEXT[imm]表示对imm进行符号扩展,ZEXT[imm]表示对imm进行零扩展) 整数运算类 -U型 ...

  2. Cyclone V SoC FPGA学习之路第一章:综述

    Cyclone V SoC FPGA学习之路第一章:总体了解 关键词: adaptive logic modules – ALM 自适应逻辑模块 logic array block --LAB 逻辑阵 ...

  3. linux中内核中machine_desc,Linux-内核-学习笔记(13):移植三星官方内核

    Linux-内核-学习笔记(13):移植三星官方内核 一.移植前的准备 当拿到源代码时,首先要在window下利用SourceInsight创建一个工程,并将uboot源代码加载到SI中,方便修改和查 ...

  4. RISC V (RV32+RV64) 架构 整体介绍

    文章目录 riscv 市场 芯片介绍 软件介绍 开发板介绍 PC介绍 riscv 架构 编程模型(指令集/寄存器/ABI/SBI) 运行状态 指令集 寄存器 riscv32和riscv64两者的区别 ...

  5. Cyclone V SoC FPGA学习之路第二章:硬件篇

    Cyclone V SoC FPGA学习之路第二章:硬件篇(内部资源) 前言 上一章了解了<cycloneV device datasheet>,其中数据手册里重点介绍了电源要求,时序参数 ...

  6. IP核学习之PLL锁相环

    IP核学习之PLL锁相环 IP核是什么 Xilinx7 系列 "clocking resource " IP核实验 IP核是什么 IP核就是知识产权核或知识产权模块的意思,在EDA ...

  7. 开放性32位RISC处理器IP核的比较与分析(Z)

    引言 随着VLSI设计技术和深亚微米制造技术的飞速发展,SOC(SystemonChip)技术逐渐成为了集成电路设计的主流技术.SOC已经在便携式手持设备.无线网络终端和多媒体娱乐设备等领域得到了广泛 ...

  8. XIlinx MIG 控制DDR3 SO-DIMM内存条(二):MIG IP核学习

    目录 1 简介 2 IP核自定义 2.1 设置IP核参数 2.1.1 Pin Compatible FPGAs 2.1.2 Memory Selection 2.1.3 Controller Opti ...

  9. MicroBlaze:Xilinx官方软核学习与一些实验测试

    目录 一.引言 二.HelloWorld实验 三.AXI_GPIO实验 四.一些注意 一.引言 1.MicroBlaze简介. 用于做嵌入式处理操作的软核,来加速系统设计.与传统独立CPU相比,软核嵌 ...

最新文章

  1. c语言为什么提供函数声明机制,通过实战理解C语言精要——函数篇
  2. [存储过程]中的事务(rollback)回滚
  3. [Animations] 快速上手 iOS10 属性动画
  4. CF407 E. k-d-sequence(线段树+单调栈)
  5. 查看 linux 硬件信息:内存、分区、系统、环境变量、防火墙、路由、端口监听、进程、CPU...
  6. 使用HDFS客户端java api读取hadoop集群上的信息
  7. ES6学习笔记(四):教你轻松搞懂ES6的新增语法
  8. ENVI:There are no available ROls or EVFs associated with this input file.
  9. java 图片转pdf_在Java语言中将图像转换为PDF?Spire.PDF for Java轻松搞定!
  10. win10系统,字体及软件内容特别小(亲试有效)
  11. 如何避免工程项目翻车?
  12. vb.net产生随机数Random代码实例
  13. formidable词根词缀_实用文档之英语单词(词根词缀)
  14. 基于制导武器的分布式半实物仿真系统ETest研究
  15. 【IT微小说】CISO琳达的一天
  16. 钱多多的程序猿的2020大计划
  17. qemu搭建arm嵌入式linux开发环境
  18. 使用EKF融合odometry及imu数据
  19. Linux添加Additional Perl modules
  20. dhu oj 题目列表

热门文章

  1. 蓝桥杯 日志统计 Python
  2. chrome使用的开源工程
  3. 生日快乐网站模板(个人制作)(HTML5+CSS3+JS)
  4. python:写prt头文件
  5. 波兰式和逆波兰的相互转化
  6. (初学者)使用DOSBox编写汇编程序
  7. 客户体验的全景分析:从了解到行动
  8. 《Ted:记忆的虚构》——Elizabeth Loftus(有感)
  9. R 语言:简短的示例
  10. 多仓库移动机器人时空约束分层调度策略