Lecture 2 - Hello Chisel
Binder 링크
Scala Summary
Feature
- OOP with strong static type system
- functional programming도 가능
- JVM 위에서 돌아서, java binary와 inter-operate 가능
- Compile time에 여러 potential error를 잡아줌
Reason for Using Scala
- embedded domain-specific language 개발하기 편해서
- OOP 적 특성이 generator 생성에 도움을 줌
- 많은 것을 standard library로부터 가져올 수 있음(collections. 라던지)
Scala Execution Mechanism
표준: Compile and Execute
- Scala -> Java bytecode -> Run on JVM
- Code needs to be structured in class
- Code needs to have a main
- Typically use appropriate build tool like sbt
- Typically use appropriate IDE like IntelliJ
REPL
- write and evaluate single line at a time
- Great for testing
- Almond Extension과 함께, 실습환경을 Jupyter로써 배포할 수 있음.
Scala Literals
Common Simple Scala Types
- Int, Float, Long, Double, Byte, Char, String
Scala Type Inference
- Scala는 type을 infer할 수 있다. 그래서, 가끔 우리는 자료형을 누락할 수 있다.
- C와 다르게, 변수명 뒤에 콜론/점이 붙고, 그 뒤 자료형이 붙는다.
Var vs Val
Var
- Variable
- Mutable variable
- 비추
Val
- value
- Immutable variable
- 추천
- Compiler가 Optimize할때 큰 도움이 됨.
var mutX = 0
mutX = 2 // RUNS OK
val constX = 42
constX = 0 // ERROR OCCURS
- Generated Circuit 파일.
- Backend에 전달되어, Simulation이나 Implementation하는데 사용됨.
- Concrete Instantization of my code
- Verilog로 짠다면, 바로 .fir을 짜는 것과 다름없다고 볼 수 있음. instance화까지 Verilog에서 진행하니까.
- .scala 파일을 Frontend에서 .fir로 만듬.
- .fir 파일을 Backend에서 .v로 만들고, 필요하면 Simulation을 수행함.
Simple Chisel Types
- Bool: .B
- UInt: .U
- SInt: .S
- UInt와 SInt는 Bitwidth를 inferred하게 set할 수 있음.
- 표기) UInt<8>(6)이라면, 8bit width에 6이 들어있다는 뜻임.
Chisel Operator
Chisel Cheat Sheet 참조
- === 같은 몇몇 연산자 외에는 동일
- Logical: !, &&, ||
- Arithmetic: +, -, *, /, %
- Bitwise: ~, &, |, ^
- Relational: ===, =/=, <, <=, >, >=
- Shifts: <<, >>
- Others: extraction, fill, concatenation, mux, reductions
- fir를 가지고 simulate를 하고,
- fir를가지고 FIRRTL을 거쳐서 verilog로 만든다. 이 과정은 매우 신속하다.
Looking At Generated Design
println(getVerilog(new myModule))
- 해당 모듈을 Verilog로 만든 파일을 출력함.
visualize(() => new myModule)
- Diagram으로 해당 모듈을 보여줌.
- 인수로 들어간 건 anonymous function인데, lambda같은거다.
Module 선언 및 테스트 실행
class MyXOR extends Module {
val io = IO(new Bundle {
val a = Input(Bool())
val b = Input(Bool())
val c = Output(Bool())
})
io.c := io.a ^ io.b
}
를 테스트하는 코드
test(new MyXOR()) { x =>
x.io.a.poke(0.B)
x.io.b.poke(0.B)
x.io.c.expect(0.B)
x.io.a.poke(0.B)
x.io.b.poke(1.B)
x.io.c.expect(1.B)
x.io.a.poke(1.B)
x.io.b.poke(0.B)
x.io.c.expect(1.B)
x.io.a.poke(1.B)
x.io.b.poke(1.B)
x.io.c.expect(0.B)
}
- poke: wire에 값을 씀
- peek: wire로부터 값을 scala형으로 읽음
- expect: assert의 역할
- new MyXOR가 먼저 eval되고, 그 결과가 x로 넘어가서 해당 command들을 수행하게 됨.
- We DO NOT have to explicitly deal with Clock, Reset