吃透Chisel语言.18.Chisel模块详解(五)——Chisel中使用Verilog模块
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
不同,不会隐式包含时钟和复位信号:
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代码在这种方式中,以字符串字面值的形式给出,开头有个s
或f
,然后三对双引号括起来的就是,用竖线|
可以放格式很好看的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
})
注意,HasBlackBoxInline
、HasBlackBoxResource
、HasBlackBoxPath
这三个类都是从Chisel的BlackBox
类拓展出来的traits
(特质),也就是说class Example extends BlackBox with HasBlackBoxInline
和class Example extends HasBlackBoxInline
是等价的。
结语
这一篇文章解决了Chisel中使用Verilog代码的问题,在项目中需要的时候可以通过BlackBox
类型使用Verilog模块,将相应的模块与相应的接口连接起来就可以了。关于Chisel模块的内容到这里就结束了,下一大部分我们会一起学习Chisel中的组合电路的相关语法,敬请期待!
吃透Chisel语言.18.Chisel模块详解(五)——Chisel中使用Verilog模块相关推荐
- struts2 18拦截器详解(五)
I18nInterceptor 该拦截器处理defaultStack第四的位置,是用来方便国际化的,如果说我们的一个Web项目要支持国际化的话,通常的做法是给定一个下拉框列出所支持的语言,当用户选择了 ...
- C 语言 运算符怎么使用,详解C++编程中运算符的使用
C++的运算符十分丰富,使得C++的运算十分灵活方便.例如把赋值号(=)也作为运算符处理,这样,a=b=c=4就是合法的表达式,这是与其他语言不同的.C++提供了以下运算符: 算术运算符 +(加) ...
- C程序语言表达式运算顺序,详解C++编程中表达式的语义与计算顺序
表达式根据其运算符的优先级和分组来计算. 计算顺序请看以下示例: // expre_pluslang__pluslang_Order_of_Evaluation.cpp // compile with ...
- python re模块详解_python与正则表达式:re模块详解
re模块是python中处理正在表达式的一个模块 正则表达式知识储备:http://www.cnblogs.com/huamingao/p/6031411.html 1. match(pattern, ...
- 【lua 编程 模块详解】——详细lua编程的模块使用
点个赞留个关注吧!!! lua是一款很好用的软件,用来多控手机,今天给大家详细讲一下某些常用模块的使用 需要使用触动精灵中控进行控制 1.writePasteboard 这段代码可以将[文本]两字存入 ...
- c语言之 malloc函数详解 在堆中动态分配内存malloc和new的区别
一.原型:extern void *malloc(unsigned int num_bytes); 头文件:#include <malloc.h> 或 #include <alloc ...
- c语言 头文件卫士详解,C/C++中的“头文件卫士”
在Objective C中可以用#import来防止重复包含,但在C/C++中就不同了,只能用"头文件卫士"了. 下面的程序是有错误的: // global.h 文件 // #if ...
- Ansible基本使用及常用模块详解
一.ansible基本使用 定义主机组 定义被管理节点列表的文件/etc/ansible/hosts,在定义被管理节点的时候,可以单独基于主机做定义,也可以将多个主机定义成一个主机组. 在上篇博文安装 ...
- matplotlib 的 spines模块详解
spines 模块详解 matplotlib 设计了一个 spines模块,用于在创建 axes 时生成 Spine对象(坐标轴线). spines模块定义了一个 Spine 类,为类定义了 25 个 ...
- python中 xlrd/xlwt模块详解
python中 xlrd/xlwt模块详解 1.什么是xlrd模块 python操作excel主要用到xlrd和xlwt两个库,即xlrd是读excel,xlwt是写excel库 一.安装xlrd模块 ...
最新文章
- android 顺序执行任务
- 使用Git生成patch和应用patch
- STM32 进阶教程 15 - 串口DMA收发
- 弹性地基梁板法计算原理_建筑混凝土结构设计和计算方法,老师傅总结:其原理就是这么简单...
- 笔记-项目管理过程组与知识领域(基础)
- javamailsender注入失败_关于SpringBoot使用Redis空指针的问题(不能成功注入的问题)...
- POJ 1011 Sticks
- 并发的线程入门到并发安全原理解析,offer拿到手软
- 解决tex中参考文献出现[S.l.: s.n.]、[S.l.]、 [s.n.]问题
- python: glob模块
- STL容器 之 list
- 电务段子系统网络管理服务器,CSM-TD铁路电务管理信息系统
- windows10计算机用户密码,win10系统更改administrator账户密码图文教程
- 计算机操作系统笔记总结:Part1 计算机系统概述
- 面试计算机有什么优势和不足,面试时如何介绍自己的优缺点
- uos打包——公网deb包转uos的deb包
- CAD中插入外部参照字体会变繁体_CAD外部参照无法绑定怎么办?
- curl模拟发送post请求参数通过json格式传输时需要对引号进行转义
- (2021年)IT技术分享社区个人文章汇总(编程技术篇)
- xMAP/NMAP/MIAP/移动办公/手机办公/移动适配
热门文章
- 企业管理:名片的重要性
- doraemon的python 守护进程和Process
- 7-3 查找奥运五环色的位置 (25分)
- c语言 Say Hello to Integers
- 大满足!史上最全|托盘类自动化立体库视频合集
- Spring中IoC和DI的理解
- 回溯法解决八人过河问题
- sql2000 mysql 兼容_sql2005兼容2000 | 向后兼容组件
- E.04.08 They Survived Taiwan’s Train Crash. Their Loved Ones Did Not.
- [用友]年度结转 资料 ----------网络