chisel编码初体验

本文记录了初次使用chisel编码时遇到的一些问题及解决办法,希望对以后的工作有所帮助。

1、内部信号赋值

1.1 单bit数信号定义

    单bit使能需要定义为Bool型,在io端口定义如下

val pipe_en = Input(Bool())

 

注意:"Bool"后需要加"()"

1.2 寄存器打拍

    Chisel中支持的Reg类型有RegNext、RegInit、RegEnable、ShiftRegister,具体的差别和使用方法可参考Chisel中的几种常见的寄存器_CrazyUncle的博客-CSDN博客

    我们在编码时常需要对信号打拍的操作,可以用到的语句有RegNext和ShiftRegister,两者的使用方法:

RegNext是跟随寄存器,每个时钟的上升沿,都会采样一次传入的参数。

示例:

无复位: val reg0 = RegNext(io.a)

有复位: val reg1 = RegNext(io.a,0.U)

ShiftRegister是移位寄存器,第一个参数是待移位数据;第二个参数是需要延迟的周期数;第三个参数是指定的复位值,可以省略;第四个参数是移位的使能信号,默认值是1。

示例:

val reg2 = ShiftRegister(io.a,3,0.U,io.en)

表示reg2为在“io.en”为高时,对“io.a”打三拍之后的信号,复位后其值为0。

ShiftRegister可以代替RegNext,只需要将ShiftRegister的第二个参数改为1

RegNext只能打1拍,ShiftRegister可以打n拍,并可以加入打拍的使能信号

笔者在使用的过程中感到ShiftRegister比RegNext好用很多,甚至可以完全代替RegNext。因为RegNext只能打1拍,ShiftRegister可以打n拍,并可以加入打拍的使能信号。只需要将ShiftRegister的第二个参数改为1,就可以替代RegNext的功能。

1.3 数据字面量

可以通过BigInt、Int、Long和String四种类型的Scala字面量来构造UInt和SInt。按Scala的语法,其中BigInt、Int、Long三种类型默认是十进制的,但可以加前缀“0x”或“0X”变成十六进制。对于字符串类型的字面量,Chisel编译器默认也是十进制的,但是可以加上首字母“h”、“o”、“b”来分别表示十六进制、八进制和二进制。此外,字符串字面量可以用下划线间隔。

可以通过Boolean类型的字面量——true和false——来构造fromBooleanToLiteral类型的对象,然后调用名为B和asBool的方法进一步构造Bool类型的对象。例如:

1.U                // 字面值为“1”的UInt对象

-8.S               // 字面值为“-8”的SInt对象

"b0101".U     // 字面值为“5”的UInt对象

true.B            // 字面值为“true”的Bool对象 

1.4 二维数组使用示例

import chisel3._
import chisel3.experimental.RawModule
 
class Hello extends RawModule {
  val io = IO(new Bundle {
  })
  val v = Wire(Vec(3, UInt(4.W)))
  val a = Wire(UInt(4.W))
 
  val idx = 1.U(2.W)
  v(0) := 1.U
  v(1) := 3.U
  v(2) := 5.U
 
  a := v(idx)
 
}
 
object TesterApp extends App {
    chisel3.Driver.execute(Array("-td", "chisel"), () => new Hello())
}


转verilog:

module Hello( //@[chiseltest.scala 4:21]
 
);
 
wire [3:0] v[2:0]; //@[chiseltest.scala 7:15]
 
wire [3:0] a; //@[chiseltest.scala 8:15]
 
assign v[0] = 4'h1; //@[chiseltest.scala 10:8]
 
assign v[1] = 4'h3; //@[chiseltest.scala 11:8]
 
assign v[2] = 4'h5; //@[chiseltest.scala 12:8]
 
assign a = v[1]; //@[chiseltest.scala 13:5]
 
endmodule


1.5 模块例化

// mux4.scala
package test
 
import chisel3._
class Mux4 extends Module {
  val io = IO(new Bundle {
    val in0 = Input(UInt(1.W))
    val in1 = Input(UInt(1.W))
    val in2 = Input(UInt(1.W))
    val in3 = Input(UInt(1.W))
    val sel = Input(UInt(2.W))
    val out = Output(UInt(1.W))
  })
  val m0 = Module(new Mux2)
  m0.io.sel := io.sel(0)
  m0.io.in0 := io.in0
  m0.io.in1 := io.in1
  val m1 = Module(new Mux2)
  m1.io.sel := io.sel(0)
  m1.io.in0 := io.in2
  m1.io.in1 := io.in3
  val m2 = Module(new Mux2)
  m2.io.sel := io.sel(1)
  m2.io.in0 := m0.io.out
  m2.io.in1 := m1.io.out
  io.out := m2.io.out


重复多次例化某模块

// mux4_2.scala
package test
 
import chisel3._
class Mux4_2 extends Module {
  val io = IO(new Bundle {
    val in0 = Input(UInt(1.W))
    val in1 = Input(UInt(1.W))
    val in2 = Input(UInt(1.W))
    val in3 = Input(UInt(1.W))
    val sel = Input(UInt(2.W))
    val out = Output(UInt(1.W))
  })
  val m = VecInit(Seq.fill(3)(Module(new Mux2).io))  // 例化了三个Mux2,并且参数是端口字段io
  m(0).sel := io.sel(0)  // 模块的端口通过下标索引,并且路径里没有“io”
  m(0).in0 := io.in0
  m(0).in1 := io.in1
  m(1).sel := io.sel(0)
  m(1).in0 := io.in2
  m(1).in1 := io.in3
  m(2).sel := io.sel(1)
  m(2).in0 := m(0).out
  m(2).in1 := m(1).out
  io.out := m(2).out
}

1.6 二维数组使用示例

import chisel3._
import chisel3.experimental.RawModule
class Hello extends RawModule {
  val io = IO(new Bundle {
  })
  val v = Wire(Vec(3, UInt(4.W)))
  val a = Wire(UInt(4.W))
  val idx = 1.U(2.W)
  v(0) := 1.U
  v(1) := 3.U
  v(2) := 5.U
  a := v(idx)
}

1.7 寄存器组

        当我们用寄存器写一个fifo的时候,往往会用到寄存器组,我们可以先看一下用chisel来实现它的定义和使用。

val fifo = RegInit(VecInit(Seq.fill(3)(0.U(dw.W))))
val waddr = RegInit(0.U(2.W))
when(io.vld) {waddr := waddr + 1.U}
when(io.vld) {
	fifo(3) := io.data
	switch(waddr){
		is(0.U) fifo(0) := io.data
		is(1.U) fifo(1) := io.data
		is(2.U) fifo(2) := io.data
	}
}

1)、定义

   Vec代表相同类型的信号的集合(矢量)。每个元素都可以由索引访问。Chisel Vec类似于其他编程语言中的数组数据结构。Vec是通过调用带有两个参数的构造函数来创建的:元素的数量和元素的类型(元素的类型也可以是Vec)。

wire型的使用见右侧,此处主要讨论reg型

15行为定义寄存器组

RegInit表示定义带复位的寄存器

Seq是将变量打包成数组

VecInit:接受一个Seq作为参数来构造向量。VecInit常把有字面值的数据作为参数,用于初始化寄存器组等操作。

 

 

你可能感兴趣的:(scala)