Scala&Chisel学习笔记
注:本人学习Chisel和Scala的笔记
材料主要来源:https://github.com/freechipsproject/chisel-bootcamp
欢迎留言讨论
Interpolated string
println(s”wordwordword$var”)
printf(p”$io”)
s”wordwordword${max + max}”
seq操作
1
2
3
4
5
6
7val seq = Seq("a", 1, 0.0)
seq.foreach { x => {
...}
}
map操作
1
2
3
4
5
6
7
8
9
10
11
12
13val intList = List(1, 2, 3)
val stringList = intList.map { i =>
i.toString
}//或者写成.map {_.tostring} _代表下标
val map = Map("a" -> 1)
map.get("a") //= Some(1)
map.get("b") //= None
map("a") // = 1
map("b") //报错
//Some和None都是抽象类Option的子类
OptionOption的方法
- get方法,对None执行get会报错
- getOrElse(default)方法,找不到时返回default
- isDefined,对Some返回真,对None返回假
Option[UInt] = None常用于可选参数,比如optionResetValue
1
2
3
4val reg = resetValue match {
case Some(r) => RegInit(r)
case None => Reg(UInt())
}reduce操作
list.reduce(\_+\_)
list.fold(initial)(\_+\_)
带初值的reducelist.scan(initial)(_prev+_next)
把reduce的每一步生成列表也有
reduceRight
等等Vec使用
优先推荐Seq或List,除非以下情形:
- Bundle的集合
- 访问Vec的索引i和电路有关
两个Vec对应元素的操作
(vec_a zip vec_b).map {case (a, b) => a * b}
list.zipWithIndex
:List((‘a’, 0), (‘b’, 1), …)Vec初始化0
RegInit( Vec(32, UInt(32.W)).fromBits(0.U) )
class
class Passthrough(param1 : Int, param2) extends Module {
}
tester代码模版
1
2
3
4
5
6
7
8
9class MyOperatorsTester(c: MyOperators) extends PeekPokeTester(c) {
expect(c.io.out_add, 5)
expect(c.io.out_sub, 1)
expect(c.io.out_mul, 8)
//using peek if you don't want to compare out signal
}
val testResult = Driver(() => new MyOperators) {c => new MyOperatorsTester(c)}
assert(testResult)
println("SUCCESS!!")查看firrtl
println(getVerilog(new Passthough))
println(getFirrtl(new Passthrough))
print的几种出现场合
- println(s”${io.in}”)在电路中:出现在generation的环节,即编译器Design Elaborating时,可以知道io.in是chisel3.core.UInt@e
- printf(p”$io”)在电路中,出现在simulation环节,显示Bundle(in->3, out->3)
- printf()在testbench中,显示[info] blabla
Arbiter的逻辑
FIFO的输入,一分为二输出
1
2pe0_valid := fifo_valid & pe0_ready
pe1_valid := fifo_valid & pe1_ready & (~pe0_ready)`list
列表的值一旦被定义,就不能被改变
var site: List[Int] = List(1, 2, 3, 4) //=1 :: (2 :: (3 :: (4 :: Nil)))
连接列表
listcat = List.concat(l1, l2) //l1 ::: l2
list.fill(3)("abc")
list.tabulate(6)(n => n * n)
通过给定的函数创建列表List(1, 2, 3, 4).permutations.foreach { case i0 :: i1 :: i2 :: i3 :: Nil => ... }
实现四个数的全排列list.filter(s => s.length == 3)
输出指定条件的所有元素list.foreach(s => s)
将函数应用到列表的所有元素
常用的函数式语法:map, zip, reduce, fold, scan
状态机
val idle :: coding :: writing :: grad :: Nil = Enum(4)
RegNext(next: T, init: T)用法
生成一个隐式的reg用于储存括号内的数,在下一拍生效
在写时序的时候注意一个状态的分步写,很可能被认为是重复赋值,只取最后一次赋值!
多时钟/reset
1
2
3
4
5
6
7import chisel3.experimental.{withClock, withReset, withClockAndReset}
withClock(io.alternateClock) {
val altClk = RegInit(0.U(10.W))
altClk := io.in
io.outAlternateClock := altClk
}参数检查:在Elaboration前
1
2
3
4class className(Param1: Int) extends Module {
require(Param1 >= 0)
val io = blabla
}Match/Case语句
用处:
- switch case
1
2
3
4
5
6
7val x = y match {
case 0 => "zero"
case 1 => {
"one"
}
case _ => "many"
}type matching
1
2
3
4x match {
case _: String => blabla
case _: Int => blabla
}
可选硬件IO条目
val carryIn = if (hasCarry) Some(Input(UInt(1.W))) else None
或者这样写(访问0位宽的变量总得到0):
val carryIn = Input(if (hasCarry) UInt(1.W) else UInt(0.W))
隐式参数
个人感觉没大用处。。
具体写法详见bootcamp.3.1_parameters.ipynb
事先声明一个隐变量。一个类型只能指定一个隐变量的值
在定义函数时加隐式参数声明
在调用函数时可以不写隐参数(也可以写),让编译器自己去找该类型对应的隐变量的声明的值。
提到的一个用处:做日志显示的开关
函数也可以做参数/变量
在自动机的例子中,转换表成为自动机的参数,这样写:
stateTransition: (Int, Int) => Int
电路实现时,使用函数
stateTransition(i, j)
得到Int值调用电路时,定义函数
stateTransition
闭包与匿名函数
1
2var factor = 3
val multiplier = (i:Int) => i * factor生成的multipiler是一个函数,multiplier(x) = 3x
Trait特征
类似于Java的抽象类,可以被多重继承
构造顺序:
- 超类的构造
- 特征从左到右构造
- 先构造父特征、父特征不会被重复构造
- 构造子类
Decoupled
Decoupled(任何对象)
成为DecoupledIO Bundle增加valid: Output(Bool), ready: Input(Bool), bits: Output(任何对象)
Queue:即FIFO,注意FIFO是时序逻辑
val io.out = Decoupled(UInt(8.W))
val io.in = Flipped(Decoupled(UInt(8.W)))
Flipped对调输入输出val queue = Queue(io.in, 2)
io.out <> queue
保证io.in和io.out都是DecoupledIO
Arbiters:把n个DecoupledIO送入1个DecoupledIO
分为Arbiter: 优先考虑低索引的生产者,和RRArbiter:Round-robin挑选
这是纯组合逻辑
1
2
3
4
5
6
7val io = IO(new Bundle {
val in = Flipped(Vec(2, Decoupled(UInt(8.W))))
val out = Decoupled(UInt(8.W))
})
val arbiter = Module(new Arbiter(UInt(8.W), 2)) // 2 to 1 Priority Arbiter
arbiter.io.in <> io.in
io.out <> arbiter.io.outArbiter.io(i).ready恒为0
内置Utility函数
- PopCount(sth)
- Reverse(sth)
- Integer.parseInt(“00000000”, 2)转为2进制
- io.out.toInt.toBinaryString
- UInt和OneHot相互转化:UIntToOH(), OHToUInt()
Muxes
Priority Mux:
PriorityMux
低索引的优先(List[Bool, Data])OneHot Mux:
Mux1H
必须保证输入是OneHot的Mux也可以接收Vec型的条件和输入,达到多选的效果
Counter
val counter = Counter(3)
Range是[0..2]conunter.inc()
counter.value
def和val生成的函数的区别
val x = Random.nextInt
不会重复执行(成为值)def y = Random.nextInt
会生成新的随机值(类似指针指向该函数)11/08/18这天看完了3.4_functional_programming.ipynb