》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文章
19159浏览量
229113 -
RTL
+关注
关注
1文章
385浏览量
59697 -
Pipeline
+关注
关注
0文章
28浏览量
9345 -
VaR
+关注
关注
0文章
38浏览量
11316 -
HDL语言
+关注
关注
0文章
46浏览量
8909
原文标题:pipeline高端玩法(二)——成员一览
文章出处:【微信号:Spinal FPGA,微信公众号:Spinal FPGA】欢迎添加关注!文章转载请注明出处。
发布评论请先 登录
相关推荐
评论