这是记录学习chisel官方文档的笔记。原文档pdf下载链接在这里:
http://www.imm.dtu.dk/~masca/chisel-book-chinese.pdf
写这篇文章找到了另一篇官方的中文简介文章,可作为学习阶段反复阅读复习用的材料。
(下载链接:http://www.aiotek.pro/aiotek/doclib/chisel/chisel-getting-started-chinese.pdf)
sbt "runMain <对象名(而不是文件名)>"
sbt
project
project <工程名>
ctrl+C
[error] (run-main-0) java.lang.NoSuchMethodException: Hello.main([Ljava.lang.String;)
main就是object;代码中只有class是不够的;
[error] /home/cwq/6_chisel_book_and_example/1_cwq_example/2_Hello_hardware.scala:2:8: not found: object chisel3
缺少编译配置文件,默认是build.sbt;需要从别的工程里复制出来用;
确认JAVA_HOME路径的方法:https://www.cnblogs.com/huaisn/articles/14499330.html
val result = Mux(<条件>, <条件为真的输出选择>, <条件为假的输出选择>)
val cntReg = RegInit(0.U(8.W))
cntReg := Mux(cntReg === 10.U, 0.U, cntReg+1.U)
val initVal = Wire(new Channel())
initVal.data := 0.U
initVal.valid := false.B
val channelReg = RegInit(initVal)
sbt "runMain xxx"
sbt "testOnly xxx"
def delay(x:UInt) = RegNext(x)
def delay(x:UInt) = RegNext(x)
val delOut = delay(delay(defIn))
“因为我们感兴趣的是同步设计,所以当我们说时序电路时,就意味着是同步时序电路”
val q = RegNext(d)
val valReg = RegInit(0.U(4.W))
val enableReg = Reg(UInt(4.W))
when(enable) { enableReg := inVal }
val resetEnableReg = RegInit(0.U(4.W))
when(enable) { resetEnableReg := inVal }
val outReg = RegInit(0.U(4.W))
outReg := Cat(serIn, outReg(3, 1))
val q = outReg
when(load) {
loadReg := d
} otherwise {
loadReg := Cat(0.U, loadReg(3, 1))
}
val serOut = loadReg(0)
class ForwardingMemory() extends Module {
val io = IO(new Bundle {
val rdAddr = Input(UInt(10.W))
val rdData = Output(UInt(8.W))
val wrEna = Input(Bool())
val wrData = Input(UInt(8.W))
val wrAddr = Input(UInt(10.W))
})
val mem = SyncReadMem(1024, UInt(8.W))
val wrDataReg = RegNext(io.wrData )
val doForwardReg = RegNext(io.wrAddr === io.rdAddr && io.wrEna)
val memData = mem.read(io.rdAddr)
when(io.wrEna) {
mem.write(io.wrAddr, io.wrData)
}
io.rdData := Mux(doForwardReg, wrDataReg, memData)
}
val btnSync = RegNext(RegNext(btn))
val FAC = 100000000/100
val btnDebReg = Reg(Bool())
val cntReg = RegInit(0.U(32.W))
val tick = cntReg === (FAC-1).U
//相当于bool变量的定义:tick为cntReg寄存器和(FAC-1).U常量的比较结果(硬件);虽然后面没有显式地更新tick,但它在硬件运行过程中不断自动变化。
cntReg := cntReg + 1 .U
when (tick) {
cntReg := 0.U
btnDebReg := btnSync
}
def filter(v: Bool, t: Bool);
def tickGen(fac: Int);
val stateReg = RegInit(<状态1>)
“通常问题会很复杂,以至于不能用单个fsm去描述。这种情况下,问题可以被分为两个或更多的更小、更简单的fsm。然后那些fsm使用信号去通信。一个fsm的输出是另一个fsm的输入,同时也观察其它fsm的输出。当我们分成一个大的fsm为许多简单fsm,这称为“分解fsm”。但是,fsm通信经常直接根据spec来设计,因为如果实现成单个fsm会是不可实现的大。”
class DecoupledIO [T <: Data] (gen: T) extends Bundle {
val ready = Input(Bool())
val valid = Output(Bool())
val bits = Output(gen)
}
val add8 = Module(new ParamAdder(8))
val add16 = Module(new ParamAdder(16))
def myMux[T <: Data](sel: Bool, tPath: T, fPath: T): T = {
...
}
def myMux[T <: Data](sel: Bool, tPath: T, fPath: T): T = {
val ret = Wire(fPath.cloneType)
...
ret
}
class xx(xx) extends Module {...}
def xx(xx) = {...}
class NocRouter[T <: Data](data: T, n: Int) extends Module {
val io = IO(new Bundle {
val inPort = Input(Vec(n, data))
val address = Input(Vec(n, UInt(8.W)))
val outPort = Output(Vec(n, data))
})
}
class Payload extends Bundle {
val data = UInt(16.W)
val flag = Bool()
}
val router = Module(new NocRouter(new Payload, 2))
val router = Module(new NocRouter2(new Port(new Payload), 2))
class NocRouter2[T :< Data](dt: T, n: Int) extends Module {
val io = IO(new Bundle) {
...
val inPort = Input(Vec(n, dt))
}
}
class Port [T <: Data](private val dt: T) extends Bundle {
...
val address = dt.cloneType //保证这里cloneType的结果就是Port()定义时选用的参数类型T?
}
abstract class Ticker (n:Int) extends Module {
val io = IO(new Bundle {
val tick = Output(Bool())
})
}
class UpTicker(n:Int) extends Ticker(n) {
...
io.tick := cntReg === N
}
class DownTicker(n:Int) extends Ticker(n) {
...
io.tick := cntReg === N
}
class NerdTicker(n:Int) extends Ticker(n) {
...
io.tick := false.B
when(...) {
io.tick := true.B
}
}
import chisel3.iotesters.PeekPokeTester
import org.scalatest._
class TickerTester[T <: Ticker](dut: T, n: Int) extends PeekPokeTester(dut: T) {
...
step(1)
}
class TickerSpec extends FlatSpec with Matchers {
"UpTicker 5" should "pass" in {
chisel3.iotesters.Driver(() => new UpTicker(5)) { c =>
new TickerTester(c, 5)
} should be (true)
}
"DownTicker 7" should "pass" in{
chisel3.iotesters.Driver(() => new DownTicker(7)) { c =>
new TickerTester(c, 7)
} should be (true)
}
"NerdTicker 11" should "pass" in{
chisel3.iotesters.Driver(() => new NerdTicker(11)) { c =>
new TickerTester(c, 11)
} should be (true)
}
}
执行命令以开始单元测试:sbt "testOnly TickerSpec"
def add(a:UInt, b:UInt) = a + b
val sum = vec.reduce(add)
val sum = vec.reduce(_ + _)
val sum = vec.reduceTree(_ + _)
class WriterIO(size: Int) extends Bundle {
val write = Input(Bool())
val full = Output(Bool())
val din = Input(UInt(size.W))
}
class ReaderIO(size: Int) extends Bundle {
val read = Input(Bool())
val empty = Output(Bool())
val dout = Output(UInt(size.W))
}
class FifoRegister(size: Int) extends Module {
val io = IO(newBundle{
val enq = new WriterIO(size)
val deq = new ReaderIO(size)
val empty::full::Nil = Enum(2) //即使是单级fifo,也是一个小状态机
val stateReg = RegInit(empty)
val dataReg = RegInit(0.U(size.W))
... //状态机实现
})
class BubbleFifo(size: Int, depth: Int) extends Module {
val io = IO(new Bundle {
val enq = new WriterIO(size)
val deq = new ReaderIO(size)
})
val buffers = Array.fill(depth) {Module(new FifoRegister(size))}
for(i <- 0 until depth - 1) {
buffers(i+1).io.enq.din := buffers(i).io.deq.dout
buffers(i+1).io.enq.write := ~buffers(i).io.deq.empty
buffers(i).io.deq.read := ~buffers(i+1).io.enq.full
}
io.enq <> buffers(0).io.enq //Bundle的整体双向互联,可用批量连接运算符"<>":Bundle中识别为同名的信号val,会互联到一起
io.deq <> buffers(depth-1).io.deq
}
class Tx(frequency: Int, baudRate: Int) extends Module {
val io = IO(newBundle{
val txd = Output(Bits(1.W))
val channel = newChannel()
})
val BIT_CNT = ((frequency+baudRate/2)/baudRate - 1).asUInt()
val shiftReg = RegInit(0x7ff.U) //移位寄存器:bit0输出到输出引脚tdx,即右移,低bit先发
val cntReg = RegInit(0.U(20.W)) //分频系数寄存器:从时钟频率到串口波特率的分频
val bitsReg = RegInit(0.U(4.W)) //移位bit数计数寄存器:从11个bit倒计数到0
io.channel.ready := (cntReg === 0.U) && (bitsReg === 0.U)
io.txd := shiftReg(0)
when(cntReg === 0.U){
cntReg := BIT_CNT
when(bitsReg =/= 0.U) { //chisel中“不等于”的运算符是这样表示的:"=/="
val shift = shiftReg>>1
shiftReg := Cat(1.U,shift(9,0)) //寄存器的移位操作:总是用Cat(新bit值, 其余bit值)来实现的
bitsReg := bitsReg1.U
} .otherwise {
when(io.channel.valid){
//two stop bits, data, one start bit
//移位寄存器shiftReg的11bit定义(从右向左看,和波形时序相反): 1bit start的0、8bit的data、2bit stop的11
shiftReg := Cat(Cat(3.U,io.channel.data),0.U)
bitsReg := 11.U
} .otherwise {
shiftReg := 0x7ff.U
}
}
} .otherwise {
cntReg := cntReg - 1.U
}
}
addi 0x3
addi -1
subi 2
ldi 0xab
and 0x0f
or 0xc3
val prog = Array[Int] (
0x0903, //addi 0x3
0x09ff, //addi -1
0x0d02, //subi 2
0x21ab, //ldi 0xab
0x230f, //and 0x0f
0x25c3, //or 0xc3
0x0000
)