• 售前

  • 售后

热门帖子
入门百科

吃透Chisel语言.18.Chisel模块详解(五)——Chisel中使用Verilog模块

[复制链接]
123457281 显示全部楼层 发表于 2022-8-2 09:26:02 |阅读模式 打印 上一主题 下一主题
Chisel模块详解(五)——Chisel中使用Verilog模块

上一篇文章陈诉了用函数实现轻量级模块的方法,可以大幅度提拔编码服从。Chisel中也提供了一些好用的函数,方便我们编写代码,也方便Chisel编译器优化天生的硬件电路。在Chisel中除了使用我们写的模块或函数硬件天生器,我们大概还须要使用现有的IP,而这些IP通常是用Verilog来写的,我们该怎样使用这些IP呢?这一篇文章就来说说。
偶尔候我们须要在项目中使用一个模块,这个模块大概是个IP,大概是之前项目中比力成熟的模块,但通常都是Verilog形貌的电路。又大概我们渴望确保某个模块天生的Verilog代码有特定的结构,渴望以此来让综合工具辨认并映射到一个好用的原语。又大概有个硬件构造Chisel形貌不了,只能用Verilog形貌。再大概须要毗连到Chisel中未界说的FPGA大概其他IP中。Chisel中就有BlackBox和ExtModule这两个类帮我们在Chisel中使用Verilog代码形貌的模块。
这两个类的使用是雷同的,都须要用Map[String, Param]来参数化,用于转换为天生的Verilog代码中的模块参数。此中BlackBox以独立地Verilog文件发射,而ExtModule是雷同占位符一样的存在,作为无源码的模块实例发射。这个特性使得ExtModule偶尔候很有效,比如针对Xilinx或Intel装备中雷同时钟或输入缓存这类原语的时间。
先看一个BlackBox的例子,这里的BUFGCE是FPGA中的一个原语,是带偶尔钟使能端的全局缓冲,有一个时钟输入I,一个使能端CE以及一个输出O,注意BlockBox类和Module差异,不会隐式包罗时钟和复位信号:
  1. import chisel3._
  2. import chisel3.util._
  3. class BUFGCE extends BlackBox(Map("SIM_DEVICE" -> "7SERIES")) {
  4.     val io = IO(new Bundle {
  5.         val I = Input(Clock())
  6.         val CE = Input(Bool())
  7.         val O = Output(Clock())
  8.     })
  9. }
  10. class Top extends Module {
  11.     val io = IO(new Bundle {})
  12.     val bufgce = Module(new BUFGCE)
  13.     // 连接BUFGCE的时钟输入端口到顶层模块的时钟信号
  14.     bufgce.io.I := clock
  15. }
复制代码
天生的Verilog代码如下:
  1. module Top(
  2.   input   clock,
  3.   input   reset
  4. );
  5.   wire  bufgce_I; // @[hello.scala 18:24]
  6.   wire  bufgce_CE; // @[hello.scala 18:24]
  7.   wire  bufgce_O; // @[hello.scala 18:24]
  8.   BUFGCE #(.SIM_DEVICE("7SERIES")) bufgce ( // @[hello.scala 18:24]
  9.     .I(bufgce_I),
  10.     .CE(bufgce_CE),
  11.     .O(bufgce_O)
  12.   );
  13.   assign bufgce_I = clock; // @[hello.scala 20:17]
  14.   assign bufgce_CE = 1'h0;
  15. endmodule
复制代码
可以看到顶层模块Top内里包罗了一个用参数实例化了的BUFGCE,然后它的端口分别毗连到了Top中对应的线网上。
ExtModule也是雷同的,不外在Chisel 3.5中须要导入实行性包:
  1. import chisel3._
  2. import chisel3.util._
  3. import chisel3.experimental.ExtModule
  4. class alt_inbuf extends ExtModule(Map("io_standard" -> "1.0 V",
  5.                                      "location" -> "IOBANK_1",
  6.                                      "enable_bus_hold" -> "on",
  7.                                      "weak_pull_up_resistor" -> "off",
  8.                                      "termination" -> "parallel 50 ohms")) {
  9.     val io = IO(new Bundle {
  10.         val i = Input(Bool())
  11.         val o = Output(Bool())
  12.     })
  13. }
  14. class Top extends Module {
  15.     val io = IO(new Bundle {})
  16.     val inbuf = Module(new alt_inbuf)
  17. }
复制代码
输出的Verilog代码如下:
  1. module Top(
  2.   input   clock,
  3.   input   reset
  4. );
  5.   wire  inbuf_io_i; // @[hello.scala 21:23]
  6.   wire  inbuf_io_o; // @[hello.scala 21:23]
  7.   alt_inbuf
  8.     #(.termination("parallel 50 ohms"), .location("IOBANK_1"), .enable_bus_hold("on"), .io_standard("1.0 V"), .weak_pull_up_resistor("off"))
  9.     inbuf ( // @[hello.scala 21:23]
  10.     .io_i(inbuf_io_i),
  11.     .io_o(inbuf_io_o)
  12.   );
  13.   assign inbuf_io_i = 1'h0;
  14. endmodule
复制代码
天生了如许的代码之后,我们只须要给出对应的模块的Verilog实现就可以或许使用了。
我们有三种方法给出对应的Verilog实现,比如对于下面的加法器的IO端口:
  1. class BlockBoxAdderIO extends Bundle {
  2.     val a = Input(UInt(32.W))
  3.     val b = Input(UInt(32.W))
  4.     val cin = Input(Bool())
  5.     val c = Output(UInt(32.W))
  6.     val cout = Output(Bool())
  7. }
复制代码
第一种方法是Chisel代码中内联Verilog代码:
  1. class InlineBlackBoxAdder extends HasBlackBoxInline {
  2.     val io = IO(new BlockBoxAdderIO)
  3.     setInline("InlineBlackBoxAdder.v",
  4.              s"""
  5.              |module InlineBlackBoxAdder(a, b, cin, c, cout);
  6.              |input [31:0] a, b;
  7.              |input cin;
  8.              |output [31:0] c;
  9.              |output cout;
  10.              |wire [32:0] sum;
  11.              |
  12.              |assign sum = a + b + cin;
  13.              |assign c = sum[31:0];
  14.              |assign cout = sum[32];
  15.              |
  16.              |endmodule
  17.              """.stripMargin)
  18. }
  19. class Top extends Module {
  20.     val io = IO(new Bundle {})
  21.     val adder = Module(new InlineBlackBoxAdder)
  22. }
复制代码
Verilog代码在这种方式中,以字符串字面值的情势给出,开头有个s或f,然后三对双引号括起来的就是,用竖线|可以放格式很悦目的Verilog代码。别的,这种方法也可以参数化,由于Scala变量可以用$或${}插入到字符串内里。末了的stripMargin方法会在发射代码的时间移除竖线和制表符。
另有两种方法是直接导入Verilog源文件,须要Verilog源代码放在一个单独的文件内里,可以这么写:
  1. class ResourceBlackBoxAdder extends HasBlackBoxResource {
  2.     val io = IO(new BlackBoxAdderIO)
  3.     addResource("/ResourceBlackBoxAdder.v")
  4. }
复制代码
还可以这么写:
  1. class PathBlackBoxAdder extends HasBlackBoxPath {
  2.     val io = IO(new BlackBoxAdderIO)
  3.     addResource("./src/main/resources/ResourceBlackBoxAdder.v")
  4. }
复制代码
此中HasBlackBoxPath版本的写法要提供项目文件夹的相对路径,而HasBlackBoxResource会默认在./src/main/resources文件夹下搜索Verilog代码。
上面的例子输出的Verilog代码雷同下面的代码:
  1. module Top(
  2.   input   clock,
  3.   input   reset
  4. );
  5.   wire [31:0] adder_a; // @[hello.scala 37:23]
  6.   wire [31:0] adder_b; // @[hello.scala 37:23]
  7.   wire  adder_cin; // @[hello.scala 37:23]
  8.   wire [31:0] adder_c; // @[hello.scala 37:23]
  9.   wire  adder_cout; // @[hello.scala 37:23]
  10.   InlineBlackBoxAdder adder ( // @[hello.scala 37:23]
  11.     .a(adder_a),
  12.     .b(adder_b),
  13.     .cin(adder_cin),
  14.     .c(adder_c),
  15.     .cout(adder_cout)
  16.   );
  17.   assign adder_a = 32'h0;
  18.   assign adder_b = 32'h0;
  19.   assign adder_cin = 1'h0;
  20. endmodule
复制代码
使用emitVerilog发射Verilog代码时,还会天生一个InlineBlackBoxAdder.v的实现:
  1. module InlineBlackBoxAdder(a, b, cin, c, cout);
  2. input [31:0] a, b;
  3. input cin;
  4. output [31:0] c;
  5. output cout;
  6. wire [32:0] sum;
  7. assign sum = a + b + cin;
  8. assign c = sum[31:0];
  9. assign cout = sum[32];
  10. endmodule
复制代码
BlackBox和其他模块的实例化是一样的,用个Module封装就行了,即Module(new BlackBoxModule),前面的例子已经展示过。但是BlackBox类是不能直接测试的,必须要封装到测试代码中的一个定名类或匿名类中,这两种方法都允许和BlackBox有雷同的IO端口:
  1. class InlineAdder extends Module {
  2.     val io = IO(new BlackBoxAdderIO)
  3.     val adder = Module(new InlineBlackBoxAdder)
  4.     io <> adder.io
  5. }
复制代码
大概:
  1. test(new Module {
  2.     val io = IO(new BlackBoxAdderIO)
  3.     val adder = Module(new InlineBlackBoxAdder)
  4.     io <> adder.io
  5. })
复制代码
注意,HasBlackBoxInline、HasBlackBoxResource、HasBlackBoxPath这三个类都是从Chisel的BlackBox类拓展出来的traits(特质),也就是说class Example extends BlackBox with HasBlackBoxInline和class Example extends HasBlackBoxInline是等价的。
结语

这一篇文章办理了Chisel中使用Verilog代码的题目,在项目中须要的时间可以通过BlackBox范例使用Verilog模块,将相应的模块与相应的接口毗连起来就可以了。关于Chisel模块的内容到这里就竣事了,下一大部门我们会一起学习Chisel中的组合电路的相干语法,敬请等候!

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

帖子地址: 

回复

使用道具 举报

分享
推广
火星云矿 | 预约S19Pro,享500抵1000!
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

草根技术分享(草根吧)是全球知名中文IT技术交流平台,创建于2021年,包含原创博客、精品问答、职业培训、技术社区、资源下载等产品服务,提供原创、优质、完整内容的专业IT技术开发社区。
  • 官方手机版

  • 微信公众号

  • 商务合作