当前位置:网站首页>吃透Chisel语言.03.写给Verilog转Chisel的开发者(没有Verilog基础也可以看看)
吃透Chisel语言.03.写给Verilog转Chisel的开发者(没有Verilog基础也可以看看)
2022-07-04 12:50:00 【github-3rr0r】
写给Verilog转Chisel的开发者——以组合逻辑电路为例,对比Chisel和Verilog的基本语法(没有Verilog基础也可以看看)
一个CPU或者其他数字芯片,本质上都是一个大型的数字逻辑电路,如果设计一个硬件描述语言来设计CPU,必然需要支持所有数字逻辑电路的基本组件,Verilog如此,Chisel当然也不例外。这一篇文章我们就以组合逻辑电路为例,对比Chisel和Verilog的基本语法。
那么我们先回顾一下组合逻辑电路有哪些基本单元。组合逻辑电路是一种没有状态的数字逻辑电路,其输出仅和输入有关,基本单元除了输入信号、输出信号以外,就是由逻辑门构成的门电路了。
单比特输入/输出和模块的编写
输入/输出信号通常为二进制值,一位的输入/输出信号可以为0或1,多位的输入/输出信号就可以组合成为多位二进制小信号,根据特定的编码/解码约定可以表示一个特定的二进制数。一位信号就可以称为一个bit,多位二进制信号称为bits。
具有单bit输入、且输入直接硬连线到输出的模块在Verilog中表述方法如下:
module module_sample {
input wire in_sample_bit, // 一位的线网型数据输入
output wire out_sample_bit // 一位的线网型数据输出
};
assign out_sample_bit = in_sample_bit;
endmodule
其中,module
和endmodule
之间的部分定义了一个模块,module_sample
为模块名,input
、output
表示该信号是输入还是输出,wire
指定了信号类型,这里可以省略,因为Verilog中默认信号为wire
类型,in_sample_bit
和out_sample_bit
都是信号名。
而在Chisel中的表述稍有不同,直接看例子:
import chisel3._
class ModuleSample extends Module {
val io = IO(new Bundle {
val in_sample_bit = Input(Bool())
val out_sample_bit = Output(Bool())
})
io.out_sample_bit := io.in_sample_bit
}
解释如下:
- 首先我们需要导入
chisel3._
包,使得Scala支持Chisel; - Chisel中实现的模块是个类,继承于Chisel的内置类
Module
; - Chisel模块中的输入输出是
IO
类的实例,实例化的变量是一个Bundle
的实例,这个Bundle
后面会说,现在可以简单理解为一个结构体; Bundle
实例化的参数为两个信号,分别是Input
类和Output
类的实例,实例化的参数均为Bool()
,表示他们是Bool
类型的输入/输出信号;- 使用输入/输出信号时,信号均为
IO
实例io
的成员,用io.xxxx
的方式引用,使用:=
运算符表示硬连线;
我们可以通过getVerilogString
函数输出上述模块对应的Verilog代码,完整代码如下:
import chisel3._
class ModuleSample extends Module {
val io = IO(new Bundle {
val in_sample_bit = Input(Bool())
val out_sample_bit = Output(Bool())
})
io.out_sample_bit := io.in_sample_bit
}
object MyModule extends App {
println(getVerilogString(new ModuleSample()))
}
输出如下:
module ModuleSample(
input clock,
input reset,
input io_in_sample_bit,
output io_out_sample_bit
);
assign io_out_sample_bit = io_in_sample_bit; // @[temp.scala 10:23]
endmodule
可以看到,除了省略的类型wire
和额外生成但未使用的时钟、复位信号,其他与Verilog代码基本一致。
关于高阻态和不定态(可跳过)
这里需要注意的是,Verilog中有四种逻辑状态,分别为0
、1
、z
和x
,分别对应低电平、高电平、高阻态、不定态,而在Chisel中并没有高阻态和不定态。
但是这对于我们来说没有什么影响,因为在绝大多数芯片内部的设计中是用不到这两种逻辑状态的,设计中使用这种状态可能会带来危害,而且只有0
、1
的设计简化了模型,便于分析设计的行为。
当然,Chisel 3.1+版本的Experimental
包中还定义了模拟类型Analog
(等价于Verilog中的inout
),也叫做黑盒类型(BlackBox Type),用于覆盖诸如高阻态和不定态这类特性。其中定义了模拟线网、三态线网、双向线网和电源线网(对“地线”或“电源线”建模)。虽然是实验性质的,但也表示Chisel未来可能会更好地支持这些特性,即使我们基本上用不上这些。
Analog
是一种没有方向的类型,所以多个Analog
类型可以通过attach
操作符连接到一起。也可以用<>
操作符连接Analog
类型一次,但是多次就不行了。比如:
val a = IO(Analog(1.W))
val b = IO(Analog(1.W))
val c = IO(Analog(1.W))
// 可以这么连
attach(a, b)
attach(a, c)
// 或者这么连
a <> b
// 这样就不行,因为'a'连接了多次
a <> b
a <> c
多比特信号
我们可能在复位信号、使能信号中使用单比特信号,但是绝大多数时候我们要处理的信号或者说数据是多比特的。比如输入信号是两个有符号整数,输出是这两个整数的和,因此硬件设计语言必须支持多比特信号。
Verilog中使用数组来表示多比特的信号,比如下面的模块是实现了4位无符号数截断加法:
module module_sample {
input wire [3:0] in_a, // 4位的无符号数in_a
input wire [3:0] in_b, // 4位的无符号数in_b
output wire [3:0] out_c // in_a和in_b的和,溢出则截断取后四位
};
assign out_c = in_a + in_b;
endmodule
可以看到,我们用[3:0]
指定了信号的宽度。如果未指定是否有符号,则wire
类型的信号默认为无符号数,如果是有符号数,则需要使用signed
关键字。下面是4位有符号数加法:
module module_sample {
input wire signed [3:0] in_a, // 4位的无符号数in_a
input wire signed [3:0] in_b, // 4位的无符号数in_b
output wire signed [3:0] out_c // in_a和in_b的和,溢出则截断取后四位
};
assign out_c = in_a + in_b;
endmodule
而Chisel中则分别用UInt
和SInt
类型表示无符号数和有符号数,使用方法和Bool
类似,区别是需要指定信号宽度。例如,Chisel中4位有符号数加法模块的实现如下:
class ModuleSample extends Module {
val io = IO(new Bundle {
val in_a = Input(SInt(4.W))
val in_b = Input(SInt(4.W))
val out_c = Output(SInt(4.W))
})
io.out_c := io.in_a + io.in_b
}
其中,SInt()
内的4.W
定义了信号宽度,格式为宽度.W
,如果不给定的话,就很可能无法进行宽度推理,运行时会抛出Uninferred width for target below. (Did you forget to assign to it?)
错误。输出的Verilog代码如下:
module ModuleSample(
input clock,
input reset,
input [3:0] io_in_a,
input [3:0] io_in_b,
output [3:0] io_out_c
);
assign io_out_c = $signed(io_in_a) + $signed(io_in_b); // @[temp.scala 11:25]
endmodule
可以看到,虽然在定义输入输出未指定是否为有符号数,但是在运算过程中将两个4位输入都作为有符号操作数了,因此与前面Verilog定义的4位有符号数加法模块也是等价的。
UInt
用法类似,在此不做赘述。
常量
顾名思义,常量就是值不能被改变的恒定值,下面分别说说整数常量在Verilog和Scala里的表示。
Verilog中整数的格式为+/-<位宽>'<进制><数字>
,其中+/-
为符号位,正数可以省略,<位宽>
表示二进制宽度,默认32位,然后用单引号分开,后面跟着的<进制>
有四种:
- 二进制:
b
或B
; - 十进制:
d
或D
或默认; - 十六进制:
h
或H
; - 八进制:
o
或O
;
例如,以下数字在Verilog中是等价的:
10
32'd10
32'b1010
32'ha
32'o12
而在Chisel中,常量或者说字面值通过将Scala整数或字符串传递给类型的构造器来得到,所以说Chisel中的常量和Scala中的常量应该区分开来,示例如下:
// 无符号整数
10.U // 从十进制Scala Int构造,10,二进制表示为4位
"ha".U // 从十六进制表示的Scala字符串构造,10,二进制表示为4位
"o12".U // 从八进制表示的Scala字符串构造,10,二进制表示为4位
"b1010".U // 从二进制表示的Scala字符串,还是10,二进制表示为4位
// 有符号整数
5.S // 从十进制Scala Int构造,有符号整数5,二进制表示为4位(0101)
-8.S // 从十进制Scala Int构造,有符号整数-8,二进制表示为4位(1111)
5.U // 从十进制Scala Int构造,无符号整数5,二进制表示为3位(101)
// 也可以指定常量的宽度
8.U(4.W) // 4位无符号整数,值为8
-152.S(32.W)// 32位有符号整数,值为-152
// 最后是Bool类型,即单比特常量
true.B // 从Scala布尔类型构造,值为1,一位
false.B // 从Scala布尔类型构造,值为0,一位
对于比较长的串,我们在Verilog和Chisel中都可以使用下划线来分隔,以增加代码可读性,不过Verilog是用在数字里面的:
32'h_dead_beef // 在Verilog中等价于32'hdeadbeef
而Chisel是用在字符串里面的:
"h_dead_beef".U // 在Chisel中等价于"hdeadbeef".U
默认来说,Chisel编译器会把每个常量定长度为能放下常量的最小尺寸,包括有符号类型的符号位,我们也可以通过.W
来指定,上面已经演示过了。
下面解释一下类似.U
和.W
这类用法(这一段到下一小节之前都可以跳过):
.W
前面是一个Scala整数,.W
就是将这个整数转换为一个Chisel宽度类型的对象;.U
前面是一个Scala对象,.U
就是对这个Scala对象调用了UInt
的构造器asUInt
,比如:
"ha".asUInt(8.W) // 等价于"ha".U(8.W)
"o12".asUInt(6.W) // 等价于"o12".U(6.W)
"b1010".asUInt(12.W) // 等价于"b1010".U(12.W)
// 同理
5.asSInt(7.W) // 等价于5.S(7.W)
5.asUInt(8.W) // 等价于
我们也可以利用asUInt
这种构造器进行强制类型转换,但是注意不能显式指定宽度:
val sint = 3.S(4.W) // 4-bit SInt
val uint = sint.asUInt // 将SInt转换为UInt
uint.asSInt // 将UInt转换为SInt
因为没有宽度参数,Chisel会按需自己扩展或截断,这种转换也能用在时钟类型Clock
上,但是得小心一点,这里就不详细说了。
总结
这一篇文章对Verilog和Chisel的模块编写、基本数据类型和整数常量进行了简单的对比,主要是给你一个简单的印象。
如果你以前是写Verilog的,看完应该感觉到Chisel其实也差不多,包括暂时还没提到的时钟、寄存器等。
就算你之前对Verilog有没有了解,看到这里应该都有了一个初步的印象了,甚至再简单了解下基本语法就可以直接上手开写Chisel模块了。
下一篇文章开始,我们就正式一点点开始学习Chisel的语法和特性了,这套系列跟下来必须拿捏Chisel!
边栏推荐
- The Secretary of Homeland Security warned immigrants "not to embark on a dangerous journey"
- 美国土安全部长:国内暴力极端主义是目前美面临的最大恐怖主义威胁之一
- Getting started with microservices
- 近日小结(非技术文)
- 锐成芯微冲刺科创板:年营收3.67亿拟募资13亿 大唐电信是股东
- ASP. Net core introduction I
- Oracle was named the champion of Digital Innovation Award by Ventana research
- Don't turn down, three sentences to clarify the origin of cross domain resource request errors
- C语言个人通讯录管理系统
- Node の MongoDB安装
猜你喜欢
动画与过渡效果
Detailed explanation of Fisher information quantity detection countermeasure sample code
ASP. Net core introduction I
逆向调试入门-PE结构-资源表07/07
【Antd踩坑】Antd Form 配合Input.Group时出现Form.Item所占据的高度不对
.Net之延迟队列
Summary of recent days (non-technical article)
2022kdd pre lecture | 11 first-class scholars take you to unlock excellent papers in advance
基于链表管理的单片机轮询程序框架
Install Trinity and solve error reporting
随机推荐
2022g3 boiler water treatment examination question simulation examination question bank and simulation examination
C language dormitory management query software
[C question set] of VII
HAProxy高可用解决方案
Install Trinity and solve error reporting
CVPR 2022 | 大幅减少零样本学习所需的人工标注,提出富含视觉信息的类别语义嵌入(源代码下载)...
Web knowledge supplement
2022 hoisting machinery command examination simulation 100 questions simulation examination platform operation
MySQL 45 lecture - learn the actual combat notes of MySQL in Geek time 45 lecture - 06 | global lock and table lock_ Why are there so many obstacles in adding a field to the table
C foundation in-depth learning II
【Antd踩坑】Antd Form 配合Input.Group时出现Form.Item所占据的高度不对
Fs4056 800mA charging IC domestic fast charging power IC
美国土安全部长:国内暴力极端主义是目前美面临的最大恐怖主义威胁之一
Five "potential errors" in embedded programming
嵌入式编程中五个必探的“潜在错误”
unity不识别rider的其中一种解决方法
2022 Shandong Province safety officer C certificate examination question bank and online simulation examination
Introduction to XML III
面试拆解:系统上线后Cpu使用率飙升如何排查?
FS7867S是一款应用于数字系统供电电源电压监控的电压检测芯片