宁波网站建设 华企立方,找晚上做的工作去哪个网站,网店推广软文范例,无锡网站开发定制开发01、引言
由于接口控制信号上的差异#xff0c;要实现Bluespec SystemVerilog(BSV)生成的代码和外部Verilog代码之间的正确交互是一件比较麻烦同时容易出错的事情。在BSV中, 模块之间的交互都是基于Action或ActionValue这两类method完成。下图展示了使用BSV设计的某一模块的接…01、引言
由于接口控制信号上的差异要实现Bluespec SystemVerilog(BSV)生成的代码和外部Verilog代码之间的正确交互是一件比较麻烦同时容易出错的事情。在BSV中, 模块之间的交互都是基于Action或ActionValue这两类method完成。下图展示了使用BSV设计的某一模块的接口定义及其实际生成的硬件端口。由图可见除了被显式地定义为函数输入参数或返回类型的数据信号外每个method都隐含着一对控制信号即en和rdy。 其中rdy信号指示该方法已经准备好被调用而当外部模块调用该方法时会拉高对应的en信号。en-rdy控制信号和AXI总线中valid-ready信号的作用类似这两对信号都保证了当通信双方都准备好时才能完成一拍数据的传输。虽然完成的功能相同但这两对信号在具体的实现机制上仍存在一定差异:
首先en-rdy和valid-ready并不是一一对应的关系。对于某个模块en永远是输入信号而rdy永远是输出信号。而在valid-ready握手协议中master端输出valid接收ready而slave端输出ready接收valid。因此这两对信号有如下表所示的对应关系
masterslavevalidrdyenreadyenrdy
其次是控制信号之间依赖关系的差异。在BSV中method的en信号依赖于rdy信号具体来说一个method只有在其准备好(rdy为高)时才能被调用。下图展示了这一依赖关系在硬件上的具体实现即输入的en信号需要和输出的rdy信号相与后传递给下一级。而在AXI协议中为了避免产生死锁(通信双方都等待对方准备好后再响应)其明确规定master输出的valid信号不能依赖于ready信号即不能等待slave侧准备好后再发起请求相反slave端输出的ready信号可以依赖于输入的valid即可以等待master发起请求后再作响应。 在大部分使用Verilog实现的电路中我们都会基于valid-ready握手协议实现模块之间的交互。如果在一个项目中我们需要将BSV生成的代码和基于Verilog的设计进行交互通常还需要实现一个转换模块来处理valid-ready和en-rdy控制信号之间的交互。
除了控制信号的差异外BSV生成的Verilog代码还存在如下问题如果在BSV中将多个相关的输入/输出信号封装在一个结构体那么在生成的Verilog接口中所有封装在一起的字段都会合并成单个信号。例如在BSV中使用AXI-Stream总线时为了方便信号传递通常会将总线上的信号封装成一个结构体后在方法之间传递:
typedef struct {Bit#(TMul#(keepWidth, 8)) tData;Bit#(keepWidth) tKeep;Bit#(usrWidth) tUser;Bool tLast;
} AxiStream#(numeric type keepWidth, numeric type usrWidth) deriving(Bits);interface AxiStreamExample;interface Put#(AxiStream#(8, 1)) axiStreamSlave;interface Get#(AxiStream#(8, 1)) axiStreamMaster;
endinterface
而在生成的Verilog代码中结构体里定义的所有字段都合并到了axiStreamSlave_put/axiStreamMaster_get信号里:
module mkAxiStreamExample(CLK,RST_N,axiStreamSlave_put,EN_axiStreamSlave_put,RDY_axiStreamSlave_put,EN_axiStreamMaster_get,axiStreamMaster_get,RDY_axiStreamMaster_get
);
如果我们要将上述代码与其他Verilog模块交互需要添加一个额外的模块对生成的mkAxiStreamExample进行封装。该模块需要完成两件事
1将合并的信号解析成每个独立的信号
2将en-rdy转换为valid-ready握手协议。
以Master端信号的封装为例具体的实现代码如下
module mkAxiStreamExampleWrapper(input clk,input reset_n,output m_axis_tvalid,input m_axis_tready,output m_axis_tlast,output m_axis_tuser,output [63:0] m_axis_tdata,output [ 7:0] m_axis_tkeep,
);mkAxiStreamExample axiStreamExampleInst (.CLK ( clk),.RST_N (reset_n),.RDY_axiStreamMaster_get (m_axis_tvalid),.EN_axiStreamMaster_get (m_axis_tvalid m_axis_tready),.axiStreamMaster_get ({m_axis_tdata, m_axis_tkeep, m_axis_tuser, m_axis_tlast}));
endmodule
虽然上面展示的Verilog封装模块可以保证模块间正确的交互但仍存在一些缺陷。首先解析打包信号的方式与BSV中结构体的定义相关如果结构的内容发生更改封装模块解析出的结果就可能出错。其次手动地处理en-rdy和valid-ready信号对之间的转换也容易出错。这些问题都降低了BSV项目的可维护性。
为了方便BSV和Verilog之间的交互我们实现了blue-wrapper项目并提供了等同于上述Verilog封装的BSV实现使得经过封装的BSV模块所生成的代码能够直接和其他Verilog模块进行交互。下文将介绍blue-wrapper的具体实现及其使用方式主要包括三部分内容:
PipeOut/PipeIn接口的定义对应代码实现见 src/SemiFifo.bsv基于PipeOut/PipeIn和Get/Put接口实现握手控制信号转换, 详细代码实现可见 src/BusConversion.bsv;在控制信号转换的基础上还需要对完成对数据信号的解析blue-wrapper中分别提供了对AXI-StreamAXI4-Lite和AXI4-Full等协议的支持;
下文将结合实际代码分别介绍这三部分的具体实现。 02、PipeOut/PipeIn接口
在基于valid-ready控制信号对的数据交互场景下交互双方可分为Master和Slave。其中Master端发起数据传输可对应BSV中常用的Get接口而Slave负责接收数据因此可以对应BSV中的Put接口。除了Get/Put外为了方便实现握手控制信号的转换blue-wrapper中还额外定义了PipeOut/PipeIn接口这两个接口分别封装了FIFOF接口出队侧(deq)和入队(enq)侧的方法具体定义如下:
interface PipeIn#(type dType);method Action enq(dType data);method Bool notFull();
endinterfaceinterface PipeOut#(type dType);method dType first();method Action deq();method Bool notEmpty();
endinterface
从实现功能的角度上看PipeOut/PipeIn和Get/Put接口类似都可分别实现数据的输出/输入。但对于Get/Put接口其get/put方法所隐含的en-rdy控制信号在BSV中是无法访问的。而对于PipeOut/PipeIn接口其将deq/enq方法对应的rdy信号分别通过notEmpty/notFull方法暴露出来使得我们可以直接在BSV中对其进行访问而这一点将极大地方便握手控制信号的转换。 03、握手控制信号转换
显式定义valid-ready信号
实现接口转换的第一步需要在interface中定义valid和ready信号对应的method一方面使得生成的Verilog代码直接包含valid-ready信号对另一方面方便我们在BSV中操纵这两个信号实现握手协议转换。在BSV中一个方法的返回值对应Verilog的输出端口而方法的输入参数对应输入端口基于该原则valid-ready协议的Master/Slave侧接口的BSV定义如下:
(* always_ready, always_enabled )
interface RawBusMaster#(type dType);( result data ) method dType data;( result valid*) method Bool valid;(* prefix ) method Action ready(( port ready ) Bool rdy);
endinterface( always_ready, always_enabled )
interface RawBusSlave#(type dType);( prefix ) method Action validData(( port valid ) Bool valid,( port data ) dType data);( result ready *) method Bool ready;
endinterface
上述代码中编译属性“always_ready”和“always_enabled”消除了每个method隐含的en-rdy控制信号对。同时我们可以通过设置输出method的“result”属性和每个输入参数的“port”属性来指定生成的Verilog中每个端口的具体名称。
en-rdy和valid-ready之间的转换
在定义好包含valid-ready控制信号的interface后下一步需要完成en-rdy到valid-ready握手控制信号的转换。blue-wrapper项目分别提供了两种不同的转换思路
1. 将需要封装的PipeOut/PipeIn接口作为参数传入转换模块供valid/ready信号对应的method调用;
2. 将RawBusMaster/Slave接口分别封装成PipeIn/PipeOut接口供其他BSV模块调用;
基于第一种思路实现的转换模块包括: mkPipeOutToRawBusMaster/mkPipeInToRawBusSlave以及mkGetToRawBusMaster和mkPutToRawBusSlave。以mkPipeOutToRawBusMaster为例该模块接收PipeOut接口作为输入参数并返回RawBusMaster接口其中各个method的实现思路和具体代码如下:
valid: 对于Master端其valid信号对应BSV中的rdy信号而PipeOut接口通过notEmpty方法暴露出了deq方法对应的rdy因此valid方法直接返回notEmpty的值data: 对应PipeOut接口的first方法ready: 作为方法输入参数传递的ready信号对应BSV中的en控制信号该值为真时需要调用PipeOut接口的deq方法。由于在BSV中调用任意method编译器都会自动保证上文提到的en-rdy的依赖关系因此在调用deq方法时不需要额外检查其rdy信号来保证握手成功。
module mkPipeOutToRawBusMaster#(PipeOut#(dType) pipe
)(RawBusMaster#(dType));RWire#(dType) dataW - mkRWire;Wire#(Bool) readyW - mkBypassWire;rule passWire if (pipe.notEmpty);dataW.wset(pipe.first);endrulerule passReady if (readyW);pipe.deq;endrulemethod Bool valid pipe.notEmpty;method dType data fromMaybe(?, dataW.wget);method Action ready(Bool rdy);readyW rdy;endmethod
endmodule
对于PipeIn到RawBusSlave的转换其实现的原理和Master端类似具体代码如下:
module mkPipeInToRawBusSlave#(PipeIn#(dType) pipe
)(RawBusSlave#(dType));Wire#(Bool) validW - mkBypassWire;Wire#(dType) dataW - mkBypassWire;rule passData if (validW);pipe.enq(dataW);endrulemethod Action validData(Bool valid, dType data);validW valid;dataW data;endmethodmethod Bool ready pipe.notFull;
endmodule
对于Get/Put接口由于在BSV中无法直接访问get/put方法的rdy信号直接进行转换无法提取出master输出的valid信号以及slave输出的ready信号。因此在blue-wrapper的实现中我们通过添加一个额外的FIFOF模块作为媒介将Get/Put接口转换成PipeOut/PipeIn接口后调用上面展示的两个模块实现控制信号的转换以Get接口为例具体的代码实现如下:
module mkGetToRawBusMaster#(Get#(dType) get
)(RawBusMaster#(dType));FIFOF#(dType) fifo - mkFIFOF;mkConnection(get, toPut(fifo));let rawBus - mkPipeOutToRawBusMaster(convertFifoToPipeOut(fifo));return rawBus;
endmodule
第二种实现思路对应代码中的mkRawBusMasterToPut/mkRawBusMasterToGet以及mkRawBusMasterToPipeIn/mkRawBusMasterToPipeOut四个模块。这种转换方式分别用PipeIn/PipeOut或Put/Get接口封装RawBusMaster/RawBusSlave接口。对于其他BSV模块可以通过PipeIn/Put接口将数据传入转换模块然后从RawBusMaster发送出去同时可以通过PipeOut/Get接口获取从RawBusSlave上接收到的数据。这种实现方式和BSV提供的BVI接口类似。以master侧为例具体的转换实现如下:
首先我们需要定义RawBusMasterToPipeIn接口其由两个子接口RawBusMaster和PipeIn组成其中PipeIn用于封装RawBusMaster使其可供其他BSV模块调用。
对于RawBusMaster接口其实现代码主要是在进行信号的传递, 从validData中取出valid和data方法的返回值并将ready方法的输入参数传递给readyW。
对于PipeIn接口, notFull方法返回readyW的值enq方法将传入的参数写入validData。同时为了保证握手成功enq方法需要被readyW所守卫(guarded), 即当输入的ready信号为高时才可调用enq方法传入数据。
interface RawBusMasterToPipeIn#(type dType);interface RawBusMaster#(dType) rawBus;interface PipeIn#(dType) pipe;
endinterfacemodule mkRawBusMasterToPipeIn(RawBusMasterToPipeIn#(dType));RWire#(dType) validData - mkRWire;Wire#(Bool) readyW - mkBypassWire;interface RawBusMaster rawBus;method Bool valid isValid(validData.wget);method dType data fromMaybe(?, validData.wget);method Action ready(Bool rdy);readyW rdy;endmethodendinterfaceinterface PipeIn pipe;method Bool notFull readyW;method Action enq(dType data) if (readyW);validData.wset(data);endmethodendinterface
endmodule对于Get/Put接口也可以使用上述方法对RawBusSlave/RawBusMaster接口进行封装其实现的关键点都是要为get和put方法设置正确的守卫信号以保证握手成功.
死锁问题
为了避免master和slave之间互相等待而产生死锁AXI文档中规定master不能等待slave侧拉高ready后再输出有效的valid和data但允许slave侧在master拉高valid之后再置ready为高。在BSV中对于每个methoden只有在rdy信号拉高后才能拉高。由于en-rdy和valid-ready不同的依赖关系在交互的过程中就有可能导致双方产生死锁。下文将主要针对上面提到的两种封装方法分析其是否会引入死锁问题。
第一种封装方式相当于是在转换模块中调用传入的PipeOut/PipeIn接口的方法。在BSV中调用任何方法编译器都会自动地为en添加对于rdy的依赖具体的en-rdy和valid-ready间的交互可以由下图所示。其中en-rdy之间的依赖关系如红色虚线所示。当Slave侧为Verilog实现时valid和ready之间可能存在如黑色虚线所示的依赖关系。由图可知这两种依赖关系同向因此不会产生死锁。 第二种封装方式类似于BSV提供的BVI接口其将Verilog信号封装成BSV中的method供其他模块调用。同样的对于这些methodBSV会给en信号添加对rdy的依赖如下图红色虚线所示。而基于Verilog实现的Slave端口其valid-ready之间可能存在如黑色虚线所示的依赖关系。由图可见en-rdy和valid-ready之间正好形成了一个死锁环路即master端等待ready拉高后输出有效的valid而slave等待master输出有效valid后再拉高ready。因此在使用mkRawBusMasterToPipeOut转换模块时需要保证所对接的slave侧Verilog实现中不存在ready对valid的依赖。 04、信号解析
完成控制信号的转换后我们已经实现了可生成valid-ready控制信号的RawBusMaster#(dType)和RawBusSlave#(dType)接口。但是如果dType是用户定义的struct结构体则生成的Verilog会将struct中的所有字段打包到一个信号中。因此我们仍然需要在BSV中将结构体的每个字段解析为单独的信号以生成直接可用的Verilog代码。blue-wrapper分别提供了针对AXI-Stream, AXI4-Lite以及AXI4-Full三种总线协议的信号解析实现。以Master端的AXI-Stream接口为例其信号解析代码如下:
(*always_ready, always_enabled*)
interface RawAxiStreamMaster#(numeric type dataWidth, numeric type usrWidth);(* result tvalid *) method Bool tValid;(* result tdata *) method Bit#(dataWidth) tData;(* result tkeep *) method Bit#(keepWidth) tKeep;(* result tlast *) method Bool tLast;(* result tuser *) method Bit#(usrWidth) tUser;(* always_enabled, prefix *) method Action tReady((* porttready *) Bool ready);
endinterfacemodule mkPipeOutToRawAxiStreamMaster#(PipeOut#(AxiStream#(dataWidth, usrWidth)) pipe
)(RawAxiStreamMaster#(dataWidth, usrWidth));let rawBus - mkPipeOutToRawBusMaster(pipe);return convertRawBusToRawAxiStreamMaster(rawBus);interface RawAxiStreamMaster;method Bool tValid rawBus.valid;method Bit#(dataWidth) tData rawBus.data.tData;method Bit#(keepWidth) tKeep rawBus.data.tKeep;method Bool tLast rawBus.data.tLast;method Bit#(usrWidth) tUser rawBus.data.tUser;method Action tReady(Bool rdy);rawBus.ready(rdy);endmethodendinterface
endmodule
除了使用blue-wrapper中提供的三种常用总线接口的转换模块外用户也可以仿照上述代码为自定义的接口实现对应的转换模块具体的实现步骤如下:
首先需要实现自定义Verilog接口对应的BSV接口。其中每个输出信号都需要独立定义成一个method每个输入信号都需定义成Action方法的一个输入参数;使用使用上文的介绍的握手控制信号转换模块将Get/Put或PipeOut/PipeIn转换成RawBusMaster/RawBusSlave;在得到RawBusMaster/RawBusSlave后将结构体中的字段和对应的method相连。 05、总结
对于BSV生成的硬件代码其接口通常是基于en-rdy控制信号进行交互而使用Verilog设计时我们通常采用valid-ready信号对实现模块之间的交互。由于控制信号上的差异将BSV生成的代码和Verilog设计进行交互通常需要额外的转换模块。针对该问题blue-wrapper项目为BSV代码实现了相应的封装模块使得封装后生成的Verilog代码能够直接和外部的Verilog代码进行交互。本文主要介绍了blue-wrapper背后的实现原理具体包括: 定义PipeOut/PipeIn接口以提取出rdy信号两种不同的握手控制信号转换的思路以及解析struct结构体为每个字段生成独立的信号等三部分内容。 06、相关链接
Flute:
https://github.com/bluespec/Flute/tree/master/src_Testbench/Fabrics/AXI4_Lite
Blue-AXI:
https://github.com/esa-tu-darmstadt/BlueAXI
bsc-contrib:
https://github.com/B-Lang-org/bsc-contrib/tree/main
欢迎大家关注和支持blue-crc项目GitHub仓库地址
https://github.com/datenlord/blue-crc 07、往期推荐
基于BSV的高性能并行CRC硬件电路生成器 达坦科技DatenLord专注下一代云计算——“天空计算”的基础设施技术致力于拓宽云计算的边界。达坦科技打造的新一代开源跨云存储平台DatenLord通过软硬件深度融合的方式打通云间壁垒实现数据高效跨云访问建立海量异地、异构数据的统一存储访问机制为云上应用提供高性能安全存储支持。以满足不同行业客户对海量数据跨云、跨数据中心高性能访问的需求。
公众号达坦科技DatenLord
DatenLord官网
https://datenlord.github.io/zh-cn/
知乎账号
达坦科技DatenLord - 知乎
B站
https://space.bilibili.com/2017027518