亂序執(zhí)行
1. 設(shè)計(jì)原則
以下介紹QuSim用到的主要的設(shè)計(jì)原則。其中,有一些設(shè)計(jì)原則是貫穿始終的(例如亂序執(zhí)行以提高ILP的原則),另外一些設(shè)計(jì)原則可能只是應(yīng)用于具體的部件(例如前端異步流水線原則)。在提及具體部件的設(shè)計(jì)時(shí),我們還會(huì)引用這些原則。
1.1. 亂序執(zhí)行
QuSim被設(shè)計(jì)成支持亂序執(zhí)行以提高ILP(Instruction Level Parallelism)。具體而言,為了在亂序執(zhí)行的同時(shí)保證對(duì)精確異常和中斷的支持,QuSim采用了Tomasulo with Reorder Buffer算法,通過(guò)“順序發(fā)射、亂序執(zhí)行、順序提交”,允許異常和中斷的精確處理。 亂序執(zhí)行的硬件設(shè)計(jì)遠(yuǎn)比順序流水線結(jié)構(gòu)復(fù)雜,會(huì)帶來(lái)一系列設(shè)計(jì)上的挑戰(zhàn),同時(shí)會(huì)遇到順序流水線中不存在的沖突問(wèn)題。例如:
訪存時(shí)的內(nèi)存訪問(wèn)順序與內(nèi)存重命名(Memory Disambiguation)。
內(nèi)存模型。一些Load操作必須是強(qiáng)順序的。
亂序執(zhí)行中的全局狀態(tài),例如CSR寄存器。
復(fù)雜的邏輯帶來(lái)較大的門(mén)延遲,限制主頻進(jìn)一步提升。
我們會(huì)在各個(gè)部件的設(shè)計(jì)中提及如何解決這些問(wèn)題。
1.2. Load Speculation
警告
讀取預(yù)測(cè)和重發(fā)射尚未被實(shí)現(xiàn)。
Load Speculation允許我們?cè)赟tore的地址尚未確定的時(shí)候就執(zhí)行Load操作,從而所有的內(nèi)存Load操作都不會(huì)遇到阻塞;然而這樣的Load Speculation可能會(huì)失敗,此時(shí)我們需要回滾已有的操作。簡(jiǎn)單的策略是視為分支預(yù)測(cè)失敗并Flush ROB,但是會(huì)帶來(lái)嚴(yán)重的效率損失。我們采用一種“重發(fā)射”的方法,對(duì)受到影響的指令進(jìn)行精確重放。
指令數(shù)據(jù)依賴(lài)關(guān)系:假如后一條指令需要前一條指令的計(jì)算結(jié)果,那么我們稱(chēng)后一條指令依賴(lài)于前一條指令。我們可以發(fā)現(xiàn),一條指令需要被重新計(jì)算,當(dāng)且僅當(dāng)這條指令間接依賴(lài)了錯(cuò)誤的Load。
指令數(shù)據(jù)依賴(lài)關(guān)系的確定和存儲(chǔ):我們使用一個(gè)Mask來(lái)表示ROB表項(xiàng)之間的依賴(lài)關(guān)系。一條指令的Target的Mask等于指令的Operands的Mask之或(將Mask同時(shí)存儲(chǔ)在重命名表里可以降低查找ROB的延遲)。當(dāng)ROB表項(xiàng)正確提交時(shí),依賴(lài)關(guān)系消失,所有的Mask抹去依賴(lài)關(guān)系中的這一位。
保留站中包含當(dāng)前指令的Mask:需要被取消的計(jì)算會(huì)被取消。(I/O operation一定沒(méi)有執(zhí)行,所以可以被安全取消。)
LQ/SQ中所有元素被記為無(wú)效。
重命名站被清空。
ROB從錯(cuò)誤的Load指令開(kāi)始,要求Dispatcher重新分發(fā)每一條指令:對(duì)于所有的指令,重命名站和Mask會(huì)被重新設(shè)置,LQ/SQ會(huì)被重新設(shè)置為有效;但是當(dāng)遇到不需要重新發(fā)射的指令時(shí),保留站不做任何操作,LQ/SQ不需要清空操作。
當(dāng)最后一條指令被分發(fā)完畢時(shí),重發(fā)射狀態(tài)結(jié)束,繼續(xù)正常指令發(fā)射。
預(yù)測(cè)讀取失?。寒?dāng)我們發(fā)現(xiàn)一條Load指令失敗時(shí),我們可以確定需要重新發(fā)射的指令的集合。此時(shí),ROB進(jìn)入一種“重發(fā)射”的狀態(tài):
重發(fā)射狀態(tài)可以被重入:在重發(fā)射時(shí),假如再次發(fā)現(xiàn)Load Speculation Fail,則再次從開(kāi)始重新發(fā)射。
重發(fā)射狀態(tài)可以被打斷:清空ROB的條件不變。
1.3. AXI總線協(xié)議
QuSim使用AXI總線協(xié)議,對(duì)內(nèi)存和外設(shè)進(jìn)行操作。 AXI總線協(xié)議的特點(diǎn):
通過(guò)若干個(gè)Channel(讀地址、讀數(shù)據(jù)、寫(xiě)地址、寫(xiě)數(shù)據(jù)、寫(xiě)完成)提供以Burst為單位的外設(shè)訪問(wèn)。完整的Slave實(shí)現(xiàn)較為可能復(fù)雜,但Master實(shí)現(xiàn)比較簡(jiǎn)單。
與Xilinx系列IP核高度兼容(例如可以直接由AXI協(xié)議訪問(wèn)Block RAM/ROM、PS控制的DRAM、封裝的GPIO等)。
Xilinx提供AXI Interconnect以實(shí)現(xiàn)總線復(fù)用等功能。
基于以上原因,我們使用AXI總線協(xié)議與外設(shè)進(jìn)行交互。
QuSim使用了以下的Master:
L1 DCache/ICache,可以用總線讀取數(shù)據(jù)或者向總線寫(xiě)回?cái)?shù)據(jù)。
Page Table Walker,硬件直接從總線訪問(wèn)頁(yè)表。
QuSim需要使用以下的Slave:
GPIO,控制狀態(tài)指示燈和開(kāi)關(guān)等。
SRAM。盡管理論上SRAM可以在一個(gè)周期內(nèi)完成讀或?qū)懖僮?,但是由于需要等待狀態(tài)穩(wěn)定,SRAM也可以通過(guò)Burst操作來(lái)減少狀態(tài)轉(zhuǎn)移帶來(lái)的效率損失(2周期讀1次->9周期讀8次)。
串口。
1.4. 前端:異步流水線
QuSim的前端流水線由PC、TLB、訪存、分支預(yù)測(cè)、指令隊(duì)列等部分組成。這些流水線級(jí)具有以下特點(diǎn):
需要的周期數(shù)長(zhǎng)于1周期且不定:TLB段可能需要多次訪存以查詢(xún)頁(yè)表,訪存段可能遇到Cache Miss,指令發(fā)射可能會(huì)被重發(fā)射阻塞等。
可能會(huì)被打斷,但是不能簡(jiǎn)單重置:例如,可能在訪存段訪總線的時(shí)候發(fā)現(xiàn)分支預(yù)測(cè)失敗,但是AXI協(xié)議不支持操作的取消。
操作可以認(rèn)為是無(wú)副作用的:分支預(yù)測(cè)(尤其是RAS的維護(hù))可以回滾,Cache的誤操作和TLB的誤讀取不會(huì)造成本質(zhì)問(wèn)題。
受到AXI協(xié)議的啟發(fā),QuSim要求前端的各個(gè)流水段作為“異步流水線”:
流水段支持的接口:clk, rst, in_ready, in_valid, din, out_ready, out_valid, cancel。
流水段之間的數(shù)據(jù)通信必須經(jīng)過(guò)類(lèi)似AXI Channel的握手才能進(jìn)行。這允許“后面的流水段阻塞反饋到前面的流水段”的類(lèi)似功能。
流水段總會(huì)完成一整個(gè)操作,但是假如流水段在完成這個(gè)操作的中間收到了一個(gè)取消信號(hào)(例如,分支預(yù)測(cè)失敗清空前端流水線),那么它將不會(huì)向下一個(gè)流水段發(fā)射運(yùn)算結(jié)果。
這樣的異步流水線的行為可以用以下的狀態(tài)轉(zhuǎn)移模型來(lái)描述:
異步流水線內(nèi)除了計(jì)算單元,還包括一個(gè)和dout等大的dout_store和一個(gè)cancelled寄存器。
閑置態(tài):當(dāng)流水段被Reset時(shí)進(jìn)入這個(gè)狀態(tài)。此時(shí)in_ready=1,out_valid=0。當(dāng)in_valid為1時(shí),進(jìn)入計(jì)算態(tài),cancelled設(shè)為0;否則停留在閑置態(tài)。
計(jì)算態(tài):試圖完成流水線需要的計(jì)算。計(jì)算可能只需要一個(gè)周期,也可能需要多個(gè)周期。
為了節(jié)約周期數(shù),在計(jì)算的最后一個(gè)周期,直接將out_valid設(shè)為1:假如此時(shí)out_ready也為1,則將in_ready也設(shè)為1,下一個(gè)周期直接進(jìn)行下一輪計(jì)算。 在計(jì)算態(tài)的任何周期內(nèi),假如cancel被設(shè)為1,則cancelled置1,之后out_valid不再設(shè)為1,并且允許將in_ready置為1(如同本輪計(jì)算結(jié)果被下一級(jí)流水線吸收了)盡早開(kāi)始下一輪計(jì)算。 假如在計(jì)算的最后一個(gè)周期,這輪操作沒(méi)有被取消而out_ready為0,則將計(jì)算結(jié)果存入dout_store,并且進(jìn)入到輸出態(tài)。
輸出態(tài):dout=dout_store,out_valid=1,in_ready=in_valid。假如out_ready=1時(shí),in_valid為1,則進(jìn)入計(jì)算態(tài)進(jìn)行下一輪計(jì)算;否則,進(jìn)入閑置態(tài)。
在輸出態(tài)的任何周期內(nèi),假如cancel被設(shè)為1,則out_valid不再設(shè)為1(同上),并且允許盡早開(kāi)始下一輪計(jì)算。
計(jì)算單元應(yīng)該具有“寄存器輸出接入組合邏輯”的結(jié)構(gòu),例如,BRAM的輸入線路可以直接作為din,因?yàn)锽RAM可以被看成“一個(gè)寄存器的輸出接到了一組數(shù)據(jù)選擇器上,輸出所選擇的值”。
1.5. 內(nèi)存模型
QuSim使用一個(gè)比RVWMO還要弱的內(nèi)存模型。
所有的內(nèi)存讀操作是亂序的,所有的內(nèi)存寫(xiě)操作是順序的,允許forwarding。因?yàn)槭菃魏饲闆r,所以不考慮同地址讀取的亂序問(wèn)題。
所有的IO操作都是強(qiáng)制順序的:一條指令必須在其能被立即提交時(shí)才能開(kāi)始IO操作,并且這條指令的提交不能被中斷或者異常打斷。
Fence指令只支持fence rwio, rwio,不提供更細(xì)粒度的內(nèi)存圍欄支持。
Fence.I指令會(huì)導(dǎo)致Cache的寫(xiě)回。
CSR寄存器強(qiáng)制順序執(zhí)行:只有當(dāng)ROB為空的時(shí)候,才發(fā)射他們,且它們的提交不能被異?;蛑袛啻驍啵ǔ遣僮鞅旧韺?dǎo)致了異常)。
Memory attribute:0x000000080000000開(kāi)始的8M物理地址空間屬于RAM,IO空間分布在物理地址空間中,剩余的物理地址空間為空白。