// TODO: find out the new way to have a reset signal
class KnightRider(resetSignal: Bool = null, frequ: Int)
//extends Module(_reset = resetSignal) {
extends Module {
val io = IO(new Bundle {
val led = Output(Bits(6.W))
})
//定义了一个枚举类型,包含两个状态goLeft和goRight,用于控制FSM。
val goLeft :: goRight :: Nil = Enum(2) //定义枚举类型
val stateReg = RegInit(goLeft)
val ledReg = RegInit(1.U(6.W))
val tick = Module(new Tick(frequ))
// Update FSM state and registers only with low frequency tick
when(tick.io.tick === 1.U) {
// State change one tick earlier
when(ledReg(4) === 1.U) {
stateReg := goRight
}.elsewhen(ledReg(1) === 1.U) {
stateReg := goLeft
}
when(stateReg === goLeft) {
ledReg := ledReg << 1
}.otherwise {
ledReg := ledReg >> 1
}
}
io.led := ledReg
}
=
和 :=
的区别。大体来讲,=
用来定义一个val,:=
用来连线。
reg
接下来,我们来定义寄存器register
//reg的各种写法
val r = Reg(UInt(4.W))
val r = Reg(init = 0.U(32.W) )
val r = Reg(init = UInt(0, width = 1))
val pcReg = Reg(next= pcNext, init= 0.U(32.W))
val r = RegNext(io.in)
val reg = RegInit(0.U)
val reg = RegInit(0.U(max.getwidth.W))
Example 1.1.3
val r = Reg(UInt(4.W))
r := io.in
io.out := r
对应生成的Verilog代码是:
reg [3:0] r;
always @(posedge clock) begin
r <= io_in;
end
assign io_out = r;
Example 1.1.3 的前两行可以简化为一行:
val r = RegNext(io.in)
这里 RegNext 表示一个寄存器,其参数为该寄存器的输入。r 会被推断为一个4-bit unsigned register,因为io.in是一个4-bit unsigned input。
更进一步,example 1.1.3可以压缩为一行代码:
io.out := RegNext(io.in)
或val reg =Reg(next = in)
另外,如果想在reset时初始化一个register,可以使用 RegInit:
val r = RegInit(0.U(4.W))
r := io.in
对应的Verilog代码如下:
reg [3:0] r;
always @(posedge clock) begin
if (reset) begin
r <= 4'h0;
end else begin
r <= io_in;
end
end
reg + next + init
val pcReg = Reg(next= pcNext, init= 0.U(32.W))
上升沿检测器
def risingedge(x:Bool) = x && !Reg(next = x)
计数器
def counter(max: UInt) = {
val x = Reg(init = 0.U(max.getWidth.W))
x := Mux(x === max, 0.U, x + 1.U)
x
}
// 下边是自己写的
def counter(max:UInt) {
val reg = RegInit(0.UInt(max.getwidth.W))
when(reg===max){
reg := 0.U
}.otherwise{
reg := reg + 1.U
}
wire reg
val data = Wire(UInt(10.W)) // This is a 10-bit wire
val dataR = Reg(UInt(10.W)) // This is a 10-bit register
val cnt = RegInit(0.U(8.W))
cnt := cnt + 1.U // increases by 1 each clock cycle
uint
你可以对 UInt 进行比特提取操作。假设 a 是一个8bit数据,你可提取 a 的 bit1 至 bit3 生成一个新的信号。
val a = "b10010110".U
val b = a(3, 1) // b is "b011".U
bool
Bool 表示布尔值,共有两个状态: true.B 或 false.B
val a = Wire(Bool())
a := true.B
Bool 可以被赋予 UInt 中的某一个比特
val data = Reg(UInt(7.W))
val bit0 = data(0) // Bool
val bit2 = data(2) // Bool
Note: 对于 UInt 信号的某一比特进行赋值是不支持的。下面的代码会导致编译报错: chisel3.internal.ChiselException: Cannot reassign to read-only …
val data = Wire(UInt(7.W))
data(2) := false.B // Error !! Not supported.
一种可行的替换方案是用 Vector of Bools.
val b = Wire(Vec(7, Bool()))
b(2) := someBool
data := b.asUInt
===
等于and =/=
如需比较两个信号值是否相同或不同,用 === 和 =/=
假设 data0 和 data1 是 UInt 类型,如果 data0 等于 data1,下面的代码会设置 eq 的值为 true.B
val eq = data0 === data1 // eq is inferred as type Bool
val ne = data0 =/= data1 // ne is inferred as type Bool
Note: == is for Scala type, === is for Chisel hardware type.
Cat
Cat 可以将多个 UInt 或者 Bool 值拼成(catenate)一个新的 UInt.
val a = Wire(UInt(3.W))
val b = Wire(Bool())
a := 2.U
b := true.B
val c = Cat(4.U(3.W), b, a) // c = "b1001010".U
Note: “b1001010”.U can also be written as “b100_1_010”.U to make it more readable. The underscore is ignored.
mux
Mux(condition, x, y)
when
when (condA) {
r := x
}.elsewhen (condB) {
r := y
}.otherwise {
r := z
}
和 Verilog 类似,如果不定义 otherwise 的话,会认为 otherwise 为保持不变。因此要注意如果上例中 r 为 Wire 类型,不写 otherwise 的话则会生成 latch,这种情况一定要避免。
r := y
when (condA) { r := x }
Mux1H
在 chisel3.util 的package里提供了 one-hot 选择器 Mux1H。当我想实现一个 one-hot 的选择器时,我会选择用 Mux1H。
Bundle
Bundle 用来表示一组信号,例如下例中 x, y, z 三个信号组成一个 Bundle 信号 A
Example 1.0
class A extends Bundle {
val x = Bool()
val y = UInt(2.W)
val z = UInt(4.W)
}
Directional Bundle
输入输出 Bundle 信号是有方向的,下例中 IO 接口包含一个 Input 和 Output Bundle 信号。
class Example extends Module {
val io = IO(new Bundle() {
val in = Input(new A)
val out = Output(new A)
})
io.out := io.in
}
Valid & Decoupled IO
在实际工作中,我们经常会遇到数据信号携带一个 valid 指示,或者握手信号 valid/ready。Chisel 提供了 Valid 和 Decoupled 方法来给信号加入valid 或 valid/ready 信号。
例如对于开头 Example 1.0 里的 Bundle 信号 A,使用 Valid 方法可以得到 output valid 和 output A 。需要注意的是,要用 bits 来表示数据部分,也就是本例中的 A.
val outWithValid = Valid(new A)
...
val out_valid = outWithValid.valid
val out_A = outWithValid.bits // Bundle A
val out_A_x = outWithValid.bits.x // x of Bundle A
如果需要 Input 形式的 Valid IO,可以用 Flipped 或 Input
val inWithValid = Flipped(Valid(new A))
val inWithValid = Input(Valid(new A))
Decoupled 方法可以再提供一个 input 的 ready。如下例所示:
val in = Decoupled(new A)
val out_valid = in.valid
val out_A = in.bits
in.ready := in_ready
同样,可以用 Flipped 进行方向取反操作,得到 output 的 ready 和 input 的 valid/bits
另外,Decoupled 信号还定义了一个 fire 信号。in.fire 等价于 in.valid && in.ready。