[CSE228A] Lecture 3 - Combinational Logic

YumeIroVillain·2023년 8월 9일
0

Chisel 독학

목록 보기
32/44

출처

Lecture 3 - Combinational Logic

Mux

  • Mux(select, in1, in0) 으로 선언가능
  • Verilog/C의 ternary operator와 동일.
  • MuxCase, Mux1H 등 여러 flavor가 존재함. 참고

Scala's Class

  • 알다시피 Scala는 OOP다.
class MyClass(argS: String, argI: Int) {
    val name = argS
    println("Created " + argS)
}

로 선언해도, 클래스 자체는 된다.

  • 이것처럼, Class 생성시 val name 및 println 함수가 실행되는 것을 확인할 수 있고,
  • mc.name을 통해 접근도 가능하다.

특징

  • argument로 들어가는 것들은 Constructor parameter로 동작한다.
    얘들을 통해서, 모듈의 parameterize가 가능하다.
  • Default Scope는 public이다.
  • public으로 되기 위한 argument는 val로 선언되어야 한다.
  • method와 overloading을 cover할 것이다.
  • internal들은 instantiation시 evaluate된다.

Scala의 if/else

  • Scala 종특으로, if/else문은 마지막 evaluate된 clause의 value를 리턴한다.

Chisel의 if/else(는 없고, Mux와 when만 있다.)

  • 반드시 구분하여 써야한다. 완전히 다르다.

Mux를 쓸 때

val absX = Mux(x < 0.S, -x, x)
  • 분기문이 actual circuit input에 의존할 때 사용
  • 결과적으로 HW는 true path와 false path를 둘 다 구현하게 됨

if/else를 쓸 때

val invX = if (invert) -x else x
  • 분기문이 circuit input이 아니라, generator parameter에 의존할 때 사용
  • 결과적으로 HW는 조건문이 true인 경우에 대해서만 path를 구현하게 됨
  • 즉, 위처럼, invert 변수가 true면 좌측 그림처럼 구현되고, false면 우측그림처럼 각각 단일하게만 구현될 뿐임.

Scala Value는 Chisel Object의 참조이다.

  • Backend의 Generator는, 단순히 Chisel object를 instantiate하고 connect 하는 일만 담당할 뿐이다.
  • := 연산자는 assignment이 아니라, connect 연산자로, 물리적으로 연결시킴을 의미한다.
  • 중간결과를 참조하기 위해서는, 그냥 Scala reference를 사용해도 무방하다.
class MyXOR extends Module {
    val io = IO(new Bundle {
        val a   = Input(Bool())
        val b   = Input(Bool())
        val c   = Output(Bool())
    })
    val myGate = io.a ^ io.b
    io.c := myGate
}
// println(getVerilog(new MyXOR))

Chisel Wire

  • when 문과 자주 사용됨.
  • connect 해야하는데, simultaneous하게 end할지 여부가 불확실할 때 사용(이해못함)
class MyXOR2 extends Module {
    val io = IO(new Bundle {
        val a   = Input(Bool())
        val b   = Input(Bool())
        val c   = Output(Bool())
    })
    val myWire = Wire(Bool())
    myWire := io.a ^ io.b
    io.c := myWire
}
println(getVerilog(new MyXOR2))
  • elaborate 결과는 위와 동일함

Chisel When

class MyWMux(w: Int) extends Module {
    val io = IO(new Bundle {
        val s   = Input(Bool())
        val in0 = Input(UInt(w.W))
        val in1 = Input(UInt(w.W))
        val out = Output(UInt(w.W))
    })
    when (io.s) {
        io.out := io.in1
    } .otherwise {
        io.out := io.in0
    }
}
println(getVerilog(new MyWMux(8))
  • 주로 Mux로 구현되게 됨

Chisel's Last Connect Schematics

class LastC extends Module {
    val io = IO(new Bundle {
        val x   = Input(Bool())
        val y   = Output(UInt())
    })
    val w = Wire(UInt())
    w := 1.U
    when (io.x) {
        w := 7.U
    }
    io.y := w
}
println(getVerilog(new LastC))
  • wire을 여러 번 연결할 수 있음.
  • 마지막으로 evaluate된 connection이 WIN한다.
  • 이걸 이용해서, 기본값을 구현할 수 있다.

example

class WhenAbs(w: Int) extends Module {
    val io = IO(new Bundle {
        val x    = Input(SInt(w.W))
        val absX = Output(SInt(w.W))
    })
    io.absX := io.x
    when (io.x < 0.S) {
        io.absX := -io.x
    }
}
println(getVerilog(new WhenAbs(4)))
  • val로 선언했지만, :=하는 것은 val x 자체를 바꾸는 것이 아니라
    val x가 포함된 graph를 바꾸는 것이기에, x 자체는 immutable 이 맞다.

Bitwidth Truncation

  • Add 같은 연산자는, +나 +%로 truncate를 할수도 있고,
  • +&을 통해 grow시켜서 data를 보존시킬수도 있다. Carry out을 의미하는듯.
  • 자세한건, Chisel Cheat Sheet 참조
class MyAdder(w: Int) extends Module {
    val io = IO(new Bundle {
        val a = Input(UInt(w.W))
        val b = Input(UInt(w.W))
        val c = Output(UInt())
    })
    io.c := io.a + io.b // returns output [7:0] io_c
//     io.c := io.a +% io.b
//     io.c := io.a +& io.b // returns output [8:0] io_c
}
println(getVerilog(new MyAdder(8)))

Sign & Magnitude를 받아서, 2의 보수로 바꾸는 모듈

class SignMagConv(w: Int) extends Module {
    val io = IO(new Bundle {
        val sign = Input(Bool())
        val mag  = Input(UInt(w.W))
        val twos = Output(UInt((w+1).W))
    })
    when (io.sign) {
        io.twos := ~io.mag +& 1.U
    } .otherwise {
        io.twos := io.mag
    }
}
  • +& 연산자를 통해 추가된 MSB에 Carry out을 넣을 수 있어서, 편히 구현할 수 있다.

Bit 접근

범위접근: x(hi, lo)

  • 주의) extracted range에 대해 assign할 수 없음.
    아니, 이게 안된다고?
    아무튼, extraced range는 :=의 LHS에 못 나오는 것으로 외우자.

bit 저격: x(n)

Concatenation

  • Cat (x,y)
    x에 y를 append함

Fill

  • Fill(n,x)
    x를 n회 반복함
class SignExtender(win: Int, wout: Int) extends Module {
    val io = IO(new Bundle {
        val in = Input(UInt(win.W))
        val out = Output(UInt(wout.W))
    })
    assert(win > 0)
    assert(win < wout)
    val signBit = io.in(win-1)
    val extension = Fill(wout-win, signBit)
    io.out := Cat(extension, io.in)
}
println(getVerilog(new SignExtender(4,8)))
profile
HW SW 둘다 공부하는 혼종의 넋두리 블로그 / SKKU SSE 17 / SWM 11th

0개의 댓글