》Stageable、StageableKey stageable、StageableKey是最整個pipeline中的基本數據類型元素:
object Stageable{ def apply[T <: Data](gen : => T) = new Stageable(gen) def apply[T <: Data](gen : HardType[T]) = new Stageable(gen.craft()) } class Stageable[T <: Data](gen : => T) extends HardType(gen) with Nameable { } case class StageableOffset(val value : Any) object StageableOffsetNone extends StageableOffset(null) case class StageableKey(stageable: Stageable[Data], key : Any){ override def toString = { var name = stageable.getName() if(key != null) name = name + "_" + key name } }
對于Stageabel,我們可以傳入任何SpinalHDL下面定義的隸屬于Data的類型,不同于我們在電路里生命一個電路對象:
vala=UInt(8bits)
此時,電路對象是立即生命存在的,如果我們不對他進行賦值會報錯。而:
valb=Stageable(UInt(8bits))
此時b并未真正生成電路對象,即使不對他進行賦值也并不會報錯。
對于StageableKey,字如其名,其主要用作Key使用,用于建立Stageable映射時的key使用。
》Stage
借用上一篇文章中的圖:
Stage主要用于實現pipeline的功能實現。那么Stage則定義了這些功能的輸入、輸出:
val input = new{ val valid = Bool() varready : Bool = null } val output = newArea { val valid = Bool() varready : Bool = null }
以及一些列的內部保存變量:
val arbitration = new{ varisRemoved : Bool = null varisFlushed : Bool = null varisThrown : Bool = null varisForked : Bool = null varisFlushingNext : Bool = null varisFlushingRoot : Bool = null varisHalted : Bool = null varisHaltedByOthers : Bool = null varpropagateReady = false } val request = new{ val halts = ArrayBuffer[Bool]() val throws = ArrayBuffer[Bool]() val throwsRoot = ArrayBuffer[Bool]() val forks = ArrayBuffer[Bool]() val spawns = ArrayBuffer[Bool]() val flush = ArrayBuffer[Bool]() val flushRoot = ArrayBuffer[Bool]() val flushNext = ArrayBuffer[Bool]() } val stageableToData = mutable.LinkedHashMap[StageableKey, Data]() val stageableOverloadedToData = mutable.LinkedHashMap[StageableKey, Data]() val stageableResultingToData = mutable.LinkedHashMap[StageableKey, Data]() val stageableTerminal = mutable.LinkedHashSet[StageableKey]()
這些變量暫時看不懂也沒關系,后續會通過例子逐一進行講解。通過這些內部變量,pipeline在構建電路時處理Stage之間的依賴關系。
》Connection
顧名思義,Connection用于負責Stage之間的連接關系,即其負責處理上一級Stage的output與下一級Stage的input之間的連接。在Lib中,Connection定義了四種連接關系:
DIRECT:類似一兩個Stream直接相連
M2S:類似于Stream中的M2SPipe,對valid、payload進行打拍輸出
S2M:類似于Stream中的S2MPipe,對于ready進行打拍輸出
乍看其實現你會發現其中有好多參數一時不知用途,無妨,先放一放,回頭逐一講解。
》pipeline
Pipeline中核心是一個build函數。當我們描述完各Stage的功能之后,通過調用Pipeline的build函數即可構建整個的流水線電路,其也是整個pipelines構建的核心,直接上來看可能會略覺麻煩,后面通過例子一點點來理解。
》第一個例子
先有個概念之后,我們再來一個pipeline的第一個例子:
caseclassdemo() extendsComponent{ val io=newBundle{ val data_in=slave Flow(UInt(8bits)) val data_out=master Flow(UInt(8bits)) } noIoPrefix() val pip=newPipeline{ val paylaod=Stageable(UInt(8bits)) val stage0=newStage{ importinternals._ input.valid:=io.data_in.valid this(paylaod):=io.data_in.payload } val stage1=newStage(Connection.M2S()) val stage2=newStage(Connection.M2S()){ io.data_out.valid:=internals.output.valid io.data_out.payload:=this(paylaod) } } pip.build() }
這個例子的功能是將Flow data_in打兩拍輸出給data_out,一個最簡單的流水線結構,不牽涉到任何halt、flush等相關操作。如果你看不懂,可以先看它生成的RTL代碼:
moduledemo ( input data_in_valid, input [7:0] data_in_payload, output data_out_valid, output [7:0] data_out_payload, input clk, input reset ); reg[7:0] pip_stage1_paylaod; reg[7:0] pip_stage2_paylaod; wire[7:0] pip_stage0_paylaod; wirepip_stage0_valid; regpip_stage1_valid; regpip_stage2_valid; assignpip_stage0_valid = data_in_valid; assignpip_stage0_paylaod = data_in_payload; assigndata_out_valid = pip_stage2_valid; assigndata_out_payload = pip_stage2_paylaod; always@(posedge clk or posedge reset) begin if(reset) begin pip_stage1_valid <= 1'b0; ??????pip_stage2_valid <= 1'b0; ????end?else begin ??????pip_stage1_valid <= pip_stage0_valid; ??????pip_stage2_valid?<= pip_stage1_valid; ????end ??end ??always @(posedge clk) begin ????pip_stage1_paylaod <= pip_stage0_paylaod; ????pip_stage2_paylaod?<= pip_stage1_paylaod; ??end endmodule
一眼看去,可能覺得很怪,有很多疑問。比如說data_in的valid信號是如何從stage0傳輸到stage1的等等。
審核編輯:劉清
-
處理器
+關注
關注
68文章
19165瀏覽量
229131 -
RTL
+關注
關注
1文章
385瀏覽量
59703 -
Pipeline
+關注
關注
0文章
28瀏覽量
9345 -
VaR
+關注
關注
0文章
38瀏覽量
11316 -
HDL語言
+關注
關注
0文章
46瀏覽量
8910
原文標題:pipeline高端玩法(二)——成員一覽
文章出處:【微信號:Spinal FPGA,微信公眾號:Spinal FPGA】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論