主体内容摘自:https://blog.csdn.net/qq_34291505/article/details/87862433
前两章介绍了基本的数据类型和硬件类型,已经足够编写基本的小规模电路。至于要如何生成Verilog,会在后续章节讲解。如果要编写大型电路,当然也可以一砖一瓦地搭建,但是费时费力,完全体现不出软件语言的优势。Chisel在语言库里定义了很多常用的硬件原语,读者可以直接导入相应的包来使用。让编译器多干活,让程序员少费力。
一、多路选择器因为多路选择器是一个很常用的电路模块,所以Chisel内建了几种多路选择器。
-
第一种形式是二输入多路选择器“
Mux(sel, in1, in2)
”。sel是Bool类型,in1和in2的类型相同,都是Data的任意子类型。当sel为true.B时,返回in1,否则返回in2。Mux在chisel3包里。 -
因为Mux仅仅是把一个输入返回,所以Mux可以内嵌Mux,构成n输入多路选择器,类似于嵌套的三元操作符。其形式为“
Mux(c1, a, Mux(c2, b, Mux(..., default)))
”。第二种就是针对上述n输入多路选择器的简便写法,形式为“MuxCase(default, Array(c1 -> a, c2 -> b, ...))
”,它的展开与嵌套的Mux是一样的。第一个参数是默认情况下返回的结果,第二个参数是一个数组,数组的元素是对偶“(成立条件(Bool类型
),被选择的输入)”。MuxCase在chisel3.util包里。 -
第三种是MuxCase的变体,它相当于把MuxCase的成立条件依次换成从0开始的索引值,就好像一个查找表,其形式为“
MuxLookup(idx, default, Array(0.U -> a, 1.U -> b, ...))
”。它的展开相当于“MuxCase(default, Array((idx === 0.U) -> a, (idx === 1.U) -> b, ...))
”。MuxLookup也在chisel3.util包里。 -
第四种多路选择器是Mux1H ,是chisel3.util包里的独热码多路选择器,它的选择信号是一个独热码。如果零个或多个选择信号有效,则行为未定义。它有以下几种常用的定义形式:
val hotValue = Mux1H(io.selector,Seq(2.U,4.U,8.U,11.U))
val hotValue = Mux1H(Seq(io.selector(0),io.selector(1),io.selector(2),io.selector(3)),Seq(2.U,4.U,8.U,11.U))
val hotValue = Mux1H(Seq(
io.selector(0) -> 2.U,
io.selector(1) -> 4.U,
io.selector(2) -> 8.U,
io.selector(3) -> 11.U
))
以上三种形式是等价的,io.selector是一个UInt类型的数据,并且位宽不能小于待选择数据的个数。在第一种形式中,Mux1H会从低到高依次将io.selector的每一位作为一个选择信号,并和提供的被选择数据一一对应。
- 第五种多路选择器是chisel3.util包里的优先级选择器PriorityMux,当多个选择信号有效时,按照定义时的顺序,返回更靠前的被选数据。有以下三种定义形式:
val priorityValue = PriorityMux(io.selector,Seq(2.U,4.U,8.U,11.U))
val priorityValue = PriorityMux(Seq(io.selector(0),io.selector(1),
io.selector(2),io.selector(3)),Seq(2.U,4.U,8.U,11.U))
val priorityValue = PriorityMux(Seq(
io.selector(0) -> 2.U,
io.selector(1) -> 4.U,
io.selector(2) -> 8.U,
io.selector(3) -> 11.U,
))
以上三种形式是等价的,io.selector是一个Bits类型的数据,位宽不小于待选择数据的个数。
内建的多路选择器会转换成Verilog的三元操作符“? :”,这对于构建组合逻辑而言是完全足够的,而且更推荐这种做法,所以when语句常用于给寄存器赋值,而很少用来给线网赋值。
读者可能习惯用always语句块来编写电路,但这存在一些问题:
- 首先,always既可以综合出时序逻辑又能综合出组合逻辑,导致reg变量存在二义性,常常使得新手误解reg就是寄存器;
- 其次,if…else 不能传播控制变量的未知态x(某些EDA工具可以),使得仿真阶段无法发现一些错误,但是assign语句会在控制变量为x时也输出x。
注1:
对这句话的理解是,verilog中的if是不能写成if(a==x) b=0
这种形式的,即使你在testbench里面将a赋值为x,这条分支也不成立,总之这样写是不对的。正是因为这样,在仿真的时候,由于分支if(a==x)
不成立,那么b就不会为0,那么你就错误的认为a不等于x,所以a的未知态就没有传播出去。
工业级的Verilog,都是用assign语句来构建电路。时序逻辑也是通过例化触发器模块来完成的,相应的端口都是由assign来驱动,而且触发器会使用SystemVerilog的断言来寻找always语句里的x和z。整个设计应该尽量避免使用always语句。
二、优先编码器Chisel内建了两种优先编码器,它的作用是对多个输入信号中优先级最高的一个信号进行编码。
- 第一种优先编码器是
PriorityEncoder
,它有两种定义形式:
PriorityEncoder("b1010".U)
PriorityEncoder(Seq(true.B, false.B, true.B, false.B))
以上两种形式是等价的,返回值类型都是UInt,值为1.U。
- 第二种优先编码器是
PriorityEncoderOH
,它也有两种定义形式:
PriorityEncoderOH("b1010".U)
PriorityEncoderOH(Seq(false.B, true.B, true.B, false.B))
它和第一种编码器的区别在于该编码器会把编码结果转换成独热码。第一种形式返回一个UInt的数据2.U,第二种形式返回一个Seq:Seq(false.B, true.B, false.B, false.B)。
三、ROM可以通过apply
方法“VecInit[T
最近更新
- 深拷贝和浅拷贝的区别(重点)
- 【Vue】走进Vue框架世界
- 【云服务器】项目部署—搭建网站—vue电商后台管理系统
- 【React介绍】 一文带你深入React
- 【React】React组件实例的三大属性之state,props,refs(你学废了吗)
- 【脚手架VueCLI】从零开始,创建一个VUE项目
- 【React】深入理解React组件生命周期----图文详解(含代码)
- 【React】DOM的Diffing算法是什么?以及DOM中key的作用----经典面试题
- 【React】1_使用React脚手架创建项目步骤--------详解(含项目结构说明)
- 【React】2_如何使用react脚手架写一个简单的页面?