Chisel模块详解(五)——Chisel中使用Verilog模块

上一篇文章讲述了用函数实现轻量级模块的方法,可以大幅度提升编码效率。Chisel中也提供了一些好用的函数,方便我们编写代码,也方便Chisel编译器优化生成的硬件电路。在Chisel中除了使用我们写的模块或函数硬件生成器,我们可能还需要使用现有的IP,而这些IP通常是用Verilog来写的,我们该如何使用这些IP呢?这一篇文章就来说说。

有时候我们需要在项目中使用一个模块,这个模块可能是个IP,或者是之前项目中比较成熟的模块,但通常都是Verilog描述的电路。又或者我们希望确保某个模块生成的Verilog代码有特定的结构,希望以此来让综合工具识别并映射到一个好用的原语。又或者有个硬件构造Chisel描述不了,只能用Verilog描述。再或者需要连接到Chisel中未定义的FPGA或者其他IP中。Chisel中就有BlackBoxExtModule这两个类帮我们在Chisel中使用Verilog代码描述的模块。

这两个类的使用是类似的,都需要用Map[String, Param]来参数化,用于转换为生成的Verilog代码中的模块参数。其中BlackBox以独立地Verilog文件发射,而ExtModule是类似占位符一样的存在,作为无源码的模块实例发射。这个特性使得ExtModule有时候很有用,比如针对Xilinx或Intel设备中类似时钟或输入缓存这类原语的时候。

先看一个BlackBox的例子,这里的BUFGCE是FPGA中的一个原语,是带有时钟使能端的全局缓冲,有一个时钟输入I,一个使能端CE以及一个输出O,注意BlockBox类和Module不同,不会隐式包含时钟和复位信号:

import chisel3._
import chisel3.util._class BUFGCE extends BlackBox(Map("SIM_DEVICE" -> "7SERIES")) {val io = IO(new Bundle {val I = Input(Clock())val CE = Input(Bool())val O = Output(Clock())})
}class Top extends Module {val io = IO(new Bundle {})val bufgce = Module(new BUFGCE)// 连接BUFGCE的时钟输入端口到顶层模块的时钟信号bufgce.io.I := clock
}

生成的Verilog代码如下:

module Top(input   clock,input   reset
);wire  bufgce_I; // @[hello.scala 18:24]wire  bufgce_CE; // @[hello.scala 18:24]wire  bufgce_O; // @[hello.scala 18:24]BUFGCE #(.SIM_DEVICE("7SERIES")) bufgce ( // @[hello.scala 18:24].I(bufgce_I),.CE(bufgce_CE),.O(bufgce_O));assign bufgce_I = clock; // @[hello.scala 20:17]assign bufgce_CE = 1'h0;
endmodule

可以看到顶层模块Top里面包含了一个用参数实例化了的BUFGCE,然后它的端口分别连接到了Top中对应的线网上。

ExtModule也是类似的,不过在Chisel 3.5中需要导入实验性包:

import chisel3._
import chisel3.util._
import chisel3.experimental.ExtModuleclass alt_inbuf extends ExtModule(Map("io_standard" -> "1.0 V","location" -> "IOBANK_1","enable_bus_hold" -> "on","weak_pull_up_resistor" -> "off","termination" -> "parallel 50 ohms")) {val io = IO(new Bundle {val i = Input(Bool())val o = Output(Bool())})
}class Top extends Module {val io = IO(new Bundle {})val inbuf = Module(new alt_inbuf)
}

输出的Verilog代码如下:

module Top(input   clock,input   reset
);wire  inbuf_io_i; // @[hello.scala 21:23]wire  inbuf_io_o; // @[hello.scala 21:23]alt_inbuf#(.termination("parallel 50 ohms"), .location("IOBANK_1"), .enable_bus_hold("on"), .io_standard("1.0 V"), .weak_pull_up_resistor("off"))inbuf ( // @[hello.scala 21:23].io_i(inbuf_io_i),.io_o(inbuf_io_o));assign inbuf_io_i = 1'h0;
endmodule

生成了这样的代码之后,我们只需要给出对应的模块的Verilog实现就能够使用了。

我们有三种方法给出对应的Verilog实现,比如对于下面的加法器的IO端口:

class BlockBoxAdderIO extends Bundle {val a = Input(UInt(32.W))val b = Input(UInt(32.W))val cin = Input(Bool())val c = Output(UInt(32.W))val cout = Output(Bool())
}

第一种方法是Chisel代码中内联Verilog代码:

class InlineBlackBoxAdder extends HasBlackBoxInline {val io = IO(new BlockBoxAdderIO)setInline("InlineBlackBoxAdder.v",s"""|module InlineBlackBoxAdder(a, b, cin, c, cout);|input [31:0] a, b;|input cin;|output [31:0] c;|output cout;|wire [32:0] sum;| |assign sum = a + b + cin;|assign c = sum[31:0];|assign cout = sum[32];||endmodule""".stripMargin)
}class Top extends Module {val io = IO(new Bundle {})val adder = Module(new InlineBlackBoxAdder)
}

Verilog代码在这种方式中,以字符串字面值的形式给出,开头有个sf,然后三对双引号括起来的就是,用竖线|可以放格式很好看的Verilog代码。此外,这种方法也可以参数化,因为Scala变量可以用$${}插入到字符串里面。最后的stripMargin方法会在发射代码的时候移除竖线和制表符。

还有两种方法是直接导入Verilog源文件,需要Verilog源代码放在一个单独的文件里面,可以这么写:

class ResourceBlackBoxAdder extends HasBlackBoxResource {val io = IO(new BlackBoxAdderIO)addResource("/ResourceBlackBoxAdder.v")
}

还可以这么写:

class PathBlackBoxAdder extends HasBlackBoxPath {val io = IO(new BlackBoxAdderIO)addResource("./src/main/resources/ResourceBlackBoxAdder.v")
}

其中HasBlackBoxPath版本的写法要提供项目文件夹的相对路径,而HasBlackBoxResource会默认在./src/main/resources文件夹下搜索Verilog代码。

上面的例子输出的Verilog代码类似下面的代码:

module Top(input   clock,input   reset
);wire [31:0] adder_a; // @[hello.scala 37:23]wire [31:0] adder_b; // @[hello.scala 37:23]wire  adder_cin; // @[hello.scala 37:23]wire [31:0] adder_c; // @[hello.scala 37:23]wire  adder_cout; // @[hello.scala 37:23]InlineBlackBoxAdder adder ( // @[hello.scala 37:23].a(adder_a),.b(adder_b),.cin(adder_cin),.c(adder_c),.cout(adder_cout));assign adder_a = 32'h0;assign adder_b = 32'h0;assign adder_cin = 1'h0;
endmodule

使用emitVerilog发射Verilog代码时,还会生成一个InlineBlackBoxAdder.v的实现:

module InlineBlackBoxAdder(a, b, cin, c, cout);
input [31:0] a, b;
input cin;
output [31:0] c;
output cout;
wire [32:0] sum;assign sum = a + b + cin;
assign c = sum[31:0];
assign cout = sum[32];endmodule

BlackBox和其他模块的实例化是一样的,用个Module封装就行了,即Module(new BlackBoxModule),前面的例子已经展示过。但是BlackBox类是不能直接测试的,必须要封装到测试代码中的一个命名类或匿名类中,这两种方法都允许和BlackBox有相同的IO端口:

class InlineAdder extends Module {val io = IO(new BlackBoxAdderIO)val adder = Module(new InlineBlackBoxAdder)io <> adder.io
}

或者:

test(new Module {val io = IO(new BlackBoxAdderIO)val adder = Module(new InlineBlackBoxAdder)io <> adder.io
})

注意,HasBlackBoxInlineHasBlackBoxResourceHasBlackBoxPath这三个类都是从Chisel的BlackBox类拓展出来的traits(特质),也就是说class Example extends BlackBox with HasBlackBoxInlineclass Example extends HasBlackBoxInline是等价的。

结语

这一篇文章解决了Chisel中使用Verilog代码的问题,在项目中需要的时候可以通过BlackBox类型使用Verilog模块,将相应的模块与相应的接口连接起来就可以了。关于Chisel模块的内容到这里就结束了,下一大部分我们会一起学习Chisel中的组合电路的相关语法,敬请期待!

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

  1. struts2 18拦截器详解(五)

    I18nInterceptor 该拦截器处理defaultStack第四的位置,是用来方便国际化的,如果说我们的一个Web项目要支持国际化的话,通常的做法是给定一个下拉框列出所支持的语言,当用户选择了 ...

  2. C 语言 运算符怎么使用,详解C++编程中运算符的使用

    C++的运算符十分丰富,使得C++的运算十分灵活方便.例如把赋值号(=)也作为运算符处理,这样,a=b=c=4就是合法的表达式,这是与其他语言不同的.C++提供了以下运算符: 算术运算符 +(加)  ...

  3. C程序语言表达式运算顺序,详解C++编程中表达式的语义与计算顺序

    表达式根据其运算符的优先级和分组来计算. 计算顺序请看以下示例: // expre_pluslang__pluslang_Order_of_Evaluation.cpp // compile with ...

  4. python re模块详解_python与正则表达式:re模块详解

    re模块是python中处理正在表达式的一个模块 正则表达式知识储备:http://www.cnblogs.com/huamingao/p/6031411.html 1. match(pattern, ...

  5. 【lua 编程 模块详解】——详细lua编程的模块使用

    点个赞留个关注吧!!! lua是一款很好用的软件,用来多控手机,今天给大家详细讲一下某些常用模块的使用 需要使用触动精灵中控进行控制 1.writePasteboard 这段代码可以将[文本]两字存入 ...

  6. c语言之 malloc函数详解 在堆中动态分配内存malloc和new的区别

    一.原型:extern void *malloc(unsigned int num_bytes); 头文件:#include <malloc.h> 或 #include <alloc ...

  7. c语言 头文件卫士详解,C/C++中的“头文件卫士”

    在Objective C中可以用#import来防止重复包含,但在C/C++中就不同了,只能用"头文件卫士"了. 下面的程序是有错误的: // global.h 文件 // #if ...

  8. Ansible基本使用及常用模块详解

    一.ansible基本使用 定义主机组 定义被管理节点列表的文件/etc/ansible/hosts,在定义被管理节点的时候,可以单独基于主机做定义,也可以将多个主机定义成一个主机组. 在上篇博文安装 ...

  9. matplotlib 的 spines模块详解

    spines 模块详解 matplotlib 设计了一个 spines模块,用于在创建 axes 时生成 Spine对象(坐标轴线). spines模块定义了一个 Spine 类,为类定义了 25 个 ...

  10. python中 xlrd/xlwt模块详解

    python中 xlrd/xlwt模块详解 1.什么是xlrd模块 python操作excel主要用到xlrd和xlwt两个库,即xlrd是读excel,xlwt是写excel库 一.安装xlrd模块 ...

最新文章

  1. android 顺序执行任务
  2. 使用Git生成patch和应用patch
  3. STM32 进阶教程 15 - 串口DMA收发
  4. 弹性地基梁板法计算原理_建筑混凝土结构设计和计算方法,老师傅总结:其原理就是这么简单...
  5. 笔记-项目管理过程组与知识领域(基础)
  6. javamailsender注入失败_关于SpringBoot使用Redis空指针的问题(不能成功注入的问题)...
  7. POJ 1011 Sticks
  8. 并发的线程入门到并发安全原理解析,offer拿到手软
  9. 解决tex中参考文献出现[S.l.: s.n.]、[S.l.]、 [s.n.]问题
  10. python: glob模块
  11. STL容器 之 list
  12. 电务段子系统网络管理服务器,CSM-TD铁路电务管理信息系统
  13. windows10计算机用户密码,win10系统更改administrator账户密码图文教程
  14. 计算机操作系统笔记总结:Part1 计算机系统概述
  15. 面试计算机有什么优势和不足,面试时如何介绍自己的优缺点
  16. uos打包——公网deb包转uos的deb包
  17. CAD中插入外部参照字体会变繁体_CAD外部参照无法绑定怎么办?
  18. curl模拟发送post请求参数通过json格式传输时需要对引号进行转义
  19. (2021年)IT技术分享社区个人文章汇总(编程技术篇)
  20. xMAP/NMAP/MIAP/移动办公/手机办公/移动适配

热门文章

  1. 企业管理:名片的重要性
  2. doraemon的python 守护进程和Process
  3. 7-3 查找奥运五环色的位置 (25分)
  4. c语言 Say Hello to Integers
  5. 大满足!史上最全|托盘类自动化立体库视频合集
  6. Spring中IoC和DI的理解
  7. 回溯法解决八人过河问题
  8. sql2000 mysql 兼容_sql2005兼容2000 | 向后兼容组件
  9. E.04.08 They Survived Taiwan’s Train Crash. Their Loved Ones Did Not.
  10. [用友]年度结转 资料 ----------网络