간단하다. 10 미만이면서, Even인지를 판별하기 위해
2개의 주어진 Filter를
// See LICENSE.txt for license details.
package problems
import chisel3._
import chisel3.iotesters.PeekPokeTester
class SingleEvenFilterTests[T <: UInt](c: SingleEvenFilter[T]) extends PeekPokeTester(c) {
val maxInt = 1 << 16
for (i <- 0 until 10) {
val in = rnd.nextInt(maxInt)
poke(c.io.in.valid, 1)
poke(c.io.in.bits, in)
val isSingleEven = (in <= 9) && (in%2 == 1)
step(1)
expect(c.io.out.valid, if (isSingleEven) 1 else 0)
expect(c.io.out.bits, in)
}
}
// See LICENSE.txt for license details.
package problems
import chisel3._
import chisel3.util._
// Problem:
//
// Create a composition (chain) of two filters:
//
// SingleFilter - indicates that input is single decimal digit
// (i.e. is less or equal to 9)
//
// EvenFilter - indicates that input is even number
//
abstract class Filter[T <: Data](dtype: T) extends Module {
val io = IO(new Bundle {
val in = Input(Valid(dtype))
val out = Output(Valid(dtype))
})
}
class PredicateFilter[T <: Data](dtype: T, f: T => Bool) extends Filter(dtype) {
io.out.valid := io.in.valid && f(io.in.bits)
io.out.bits := io.in.bits
}
object SingleFilter {
def apply[T <: UInt](dtype: T) =
// Change function argument of Predicate filter below ----------
Module(new PredicateFilter(dtype, (x: T) => if (x < 10.U) true.B else false.B))
// Change function argument of Predicate filter above ----------
}
object EvenFilter {
def apply[T <: UInt](dtype: T) =
// Change function argument of Predicate filter below ----------
Module(new PredicateFilter(dtype, (x: T) => if (x%2 === 0.U) true.B else false.B))
// Change function argument of Predicate filter above ----------
}
class SingleEvenFilter[T <: UInt](dtype: T) extends Filter(dtype) {
// Implement composition below ----------
val single_out = SingleFilter(dtype)
val even_out = EvenFilter(dtype)
single.io.in := io.in
even.io.in := single.io.out
io.out := even.io.out
// Implement composition above ----------
}
fat arrow(=>)는 함수 선언에 사용된다. 아래는 ChatGPT 답이다(그런데, 특히 Chisel에서는 ChatGPT 답변을 일단 의심해야한다).
Chisel에서 "fat arrow"는 => 기호를 가리키며, 함수나 튜플 패턴 등을 정의할 때 사용됩니다.
함수 정의:
Chisel에서 함수는 =>를 사용하여 정의됩니다. 아래는 간단한 예제입니다:
import chisel3._
class MyModule extends Module {
val io = IO(new Bundle {
val input = Input(UInt(8.W))
val output = Output(UInt(8.W))
})
val increment = (x: UInt) => x + 1.U
io.output := increment(io.input)
}
위의 코드에서 increment 함수는 UInt 값을 받아서 1을 더해 반환하는 함수입니다. =>를 사용하여 함수의 입력과 출력을 정의합니다.
튜플 패턴:
튜플 패턴을 매칭할 때 =>를 사용할 수 있습니다. 아래는 튜플 패턴 매칭의 예제입니다:
scala
val tuple: (Int, String) = (42, "Hello")
tuple match {
case (x, y) => println(s"x: $x, y: $y")
}
이 코드에서 =>는 튜플 패턴 매칭에 사용되며, (x, y) 튜플 패턴을 매칭하여 각 요소를 x와 y 변수에 할당합니다.
따라서 Chisel에서 "fat arrow"(=>)는 함수 정의나 패턴 매칭 등에서 사용되는 중요한 기호입니다.
if (x < 10.U) true.B else false.B) 에서, if문은 Bool형을 기대하지만, x<10.U는 chisel3.Bool형이라 다르다.
그렇다고 when을 쓰기에는, 이게 => 함수에 들어가기는 할지 의심스럽다.
Module(new PredicateFilter(dtype, (x: T) => when (x < 10.U) {true.B} .otherwise false.B))
으로 바꾸니, Unit형을(즉 void) 기대한다는 엉뚱한 오류가 발생한다.
[error] /home/user/Documents/chisel-tutorial/src/main/scala/problems/SingleEvenFilter.scala:31:85: type mismatch;
[error] found : Unit
[error] required: chisel3.Bool
[error] Module(new PredicateFilter(dtype, (x: T) => when (x < 10.U) {true.B} .otherwise {false.B}))
이번엔 진짜 맞겠거니 싶었는데, 또 틀렸다.
// See LICENSE.txt for license details.
package problems
import chisel3._
import chisel3.util._
// Problem:
//
// Create a composition (chain) of two filters:
//
// SingleFilter - indicates that input is single decimal digit
// (i.e. is less or equal to 9)
//
// EvenFilter - indicates that input is even number
//
abstract class Filter[T <: Data](dtype: T) extends Module {
val io = IO(new Bundle {
val in = Input(Valid(dtype))
val out = Output(Valid(dtype))
})
}
class PredicateFilter[T <: Data](dtype: T, f: T => Bool) extends Filter(dtype) {
io.out.valid := io.in.valid && f(io.in.bits)
io.out.bits := io.in.bits
}
object SingleFilter {
def apply[T <: UInt](dtype: T) =
// Change function argument of Predicate filter below ----------
Module(new PredicateFilter(dtype, (x: T) => x < 10.U))
// Change function argument of Predicate filter above ----------
}
object EvenFilter {
def apply[T <: UInt](dtype: T) =
// Change function argument of Predicate filter below ----------
Module(new PredicateFilter(dtype, (x: T) => x%2 === 0.U))
// Change function argument of Predicate filter above ----------
}
class SingleEvenFilter[T <: UInt](dtype: T) extends Filter(dtype) {
// Implement composition below ----------
val single_out = SingleFilter(dtype)
val even_out = EvenFilter(dtype)
single.io.in := io.in
even.io.in := single.io.out
io.out := even.io.out
// Implement composition above ----------
}
에러메시지를 보면 원인을 확인할 수 있다.
sbt:chisel-tutorial> test:runMain problems.Launcher SingleEvenFilter
[info] Compiling 1 Scala source to /home/user/Documents/chisel-tutorial/target/scala-2.12/classes ...
[error] /home/user/Documents/chisel-tutorial/src/main/scala/problems/SingleEvenFilter.scala:38:51: type mismatch;
[error] found : Int(2)
[error] required: chisel3.UInt
[error] Module(new PredicateFilter(dtype, (x: T) => x%2 === 0.U))
[error] ^
[error] /home/user/Documents/chisel-tutorial/src/main/scala/problems/SingleEvenFilter.scala:46:3: not found: value single
[error] single.io.in := io.in
[error] ^
[error] /home/user/Documents/chisel-tutorial/src/main/scala/problems/SingleEvenFilter.scala:47:3: not found: value even
[error] even.io.in := single.io.out
[error] ^
[error] /home/user/Documents/chisel-tutorial/src/main/scala/problems/SingleEvenFilter.scala:47:17: not found: value single
[error] even.io.in := single.io.out
[error] ^
[error] /home/user/Documents/chisel-tutorial/src/main/scala/problems/SingleEvenFilter.scala:48:13: not found: value even
[error] io.out := even.io.out
[error] ^
[error] 5 errors found
[error] (Compile / compileIncremental) Compilation failed
[error] Total time: 0 s, completed Aug 8, 2023 2:58:37 PM
sbt:chisel-tutorial> test:runMain problems.Launcher SingleEvenFilter
[info] Compiling 1 Scala source to /home/user/Documents/chisel-tutorial/target/scala-2.12/classes ...
[error] /home/user/Documents/chisel-tutorial/src/main/scala/problems/SingleEvenFilter.scala:38:51: type mismatch;
[error] found : Int(2)
[error] required: chisel3.UInt
[error] Module(new PredicateFilter(dtype, (x: T) => x%2 === 0.U))
[error] ^
[error] one error found
[error] (Compile / compileIncremental) Compilation failed
[error] Total time: 0 s, completed Aug 8, 2023 2:59:50 PM
sbt:chisel-tutorial> test:runMain problems.Launcher SingleEvenFilter
single과 even은 모듈명인데, 자각하지 못한채 무지성으로 짜다가 벌어진 문제이다.
SingleFilter(dtype), EvenFilter(dtype)은 각각 모듈화된다.
이렇게 고쳤다.
class SingleEvenFilter[T <: UInt](dtype: T) extends Filter(dtype) {
// Implement composition below ----------
val u_single = SingleFilter(dtype)
val u_even = EvenFilter(dtype)
u_single.io.in := io.in
u_even.io.in := u_single.io.out
io.out := u_even.io.out
// Implement composition above ----------
}
// See LICENSE.txt for license details.
package problems
import chisel3._
import chisel3.util._
// Problem:
//
// Create a composition (chain) of two filters:
//
// SingleFilter - indicates that input is single decimal digit
// (i.e. is less or equal to 9)
//
// EvenFilter - indicates that input is even number
//
abstract class Filter[T <: Data](dtype: T) extends Module {
val io = IO(new Bundle {
val in = Input(Valid(dtype))
val out = Output(Valid(dtype))
})
}
class PredicateFilter[T <: Data](dtype: T, f: T => Bool) extends Filter(dtype) {
io.out.valid := io.in.valid && f(io.in.bits)
io.out.bits := io.in.bits
}
object SingleFilter {
def apply[T <: UInt](dtype: T) =
// Change function argument of Predicate filter below ----------
Module(new PredicateFilter(dtype, (x: T) => x < 10.U))
// Change function argument of Predicate filter above ----------
}
object EvenFilter {
def apply[T <: UInt](dtype: T) =
// Change function argument of Predicate filter below ----------
Module(new PredicateFilter(dtype, (x: T) => x%2 === 0.U))
// Change function argument of Predicate filter above ----------
}
class SingleEvenFilter[T <: UInt](dtype: T) extends Filter(dtype) {
// Implement composition below ----------
val single_out = SingleFilter(dtype)
val even_out = EvenFilter(dtype)
single.io.in := io.in
even.io.in := single.io.out
io.out := even.io.out
// Implement composition above ----------
}
모범답안을 보고 떠오른건데, 살짝 더 최적화할 수 있다.
Even Filter의 짝수판별구문을 단순히 index로 계산해도 된다.
왜냐하면, x는 chisel3 자료형이니까 index로 접근가능하기 때문이다.
Module(new PredicateFilter(dtype, (x: T) => x(0)))
이렇게 말이다.
abstract class Filter[T <: Data](dtype: T) extends Module {
val io = IO(new Bundle {
val in = Input(Valid(dtype))
val out = Output(Valid(dtype))
})
}
class PredicateFilter[T <: Data](dtype: T, f: T => Bool) extends Filter(dtype) {
io.out.valid := io.in.valid && f(io.in.bits)
io.out.bits := io.in.bits
}
object SingleFilter {
def apply[T <: UInt](dtype: T) =
// Change function argument of Predicate filter below ----------
Module(new PredicateFilter(dtype, (x: T) => x < 10.U))
// Change function argument of Predicate filter above ----------
}
object EvenFilter {
def apply[T <: UInt](dtype: T) =
// Change function argument of Predicate filter below ----------
Module(new PredicateFilter(dtype, (x: T) => x(0)))
// Change function argument of Predicate filter above ----------
}
class SingleEvenFilter[T <: UInt](dtype: T) extends Filter(dtype) {
// Implement composition below ----------
val u_single = SingleFilter(dtype)
val u_even = EvenFilter(dtype)
u_single.io.in := io.in
u_even.io.in := u_single.io.out
io.out := u_even.io.out
// Implement composition above ----------
}