본문으로 건너뛰기
code0.HDL

MuxCase·MuxLookup·PriorityMux·Mux1H로 선택하기

MuxCase·MuxLookup·PriorityMux·Mux1H로 여러 입력 가운데 하나를 고르고, 선택 신호의 성질에 따라 어떤 것을 쓸지 정합니다.

이 장에서 배울 내용

  • 같은 선택을 중첩 Mux, MuxCase, MuxLookup으로 각각 쓸 수 있습니다
  • 선택 신호가 겹칠 수 있는지로 PriorityMux와 Mux1H 가운데 하나를 고를 수 있습니다
  • 선택 신호가 둘 이상 켜졌을 때 Mux1H의 결과를 예측할 수 있습니다
  • 선택 신호가 하나도 켜지지 않았을 때 각 구문의 출력을 말하고, 명세가 요구하는 기본값에 맞는 구문을 고를 수 있습니다
  • VecInit 표를 하드웨어 인덱스로 인덱싱하고, 정적 인덱스와 멀티플렉서를 만드는 인덱스를 구별할 수 있습니다
이 장에서 배우는 개념
  • MuxCase·MuxLookup·PriorityMux·Mux1H로 선택하기
먼저 알아야 할 개념

데이터 경로의 많은 부분은 선택입니다. ALU에 어느 레지스터를 넣을지, 버스를 어느 요청자에게 줄지, 인덱스가 표의 어느 항목을 가리키는지 모두 멀티플렉서가 정합니다. Chisel의 기본 요소는 2입력 Mux 하나이고, chisel3.util의 함수들이 이를 조합해 더 넓은 선택 회로를 만듭니다. 이 함수들은 계산 결과보다 선택 신호에 두는 전제가 서로 다릅니다. 이 장은 공식 Chisel 문서 Explanations의 "Muxes and Input Selection"을 다루며, 각 함수의 전제를 시뮬레이션 결과로 확인합니다.

먼저 알아 두면 좋은 것. Bool·UInt와 연산자 장의 ===와 비교 연산자, Mux·when·Wire 장의 Mux(cond, a, b)를 사용합니다. Scala의 쌍 목록 Seq(키 -> 값, ...)도 자주 나옵니다. a -> b는 쌍 (a, b)를 만드는 Scala 표기입니다. 하드웨어 표 타입인 Vec은 2.3절에서 인덱싱하는 데 필요한 만큼만 먼저 소개합니다.

이 장의 함수는 모두 elaboration 중에 실행됩니다. 모듈을 생성할 때 한 번 호출되고, 그 결과로 2입력 멀티플렉서의 트리나 AND-OR 게이트가 회로에 남습니다. 회로 안에 "MuxCase 하드웨어"라는 별도의 구성 요소는 없습니다. 우선순위와 one-hot 규칙은 생성된 트리의 성질이며 시뮬레이션에서 관찰됩니다.

1. 2입력 Mux

1.1 형식과 의미

Mux는 Bool 하나로 두 값 가운데 하나를 고르는 식입니다. 값을 반환하므로 대입하거나 다른 식에 전달해서 씁니다.

형식

Mux(조건, 참일_때_값, 거짓일_때_값)
val max = Mux(a > b, a, b)
구성 요소의미
a > b선택 신호입니다. 하드웨어 Bool이어야 합니다
a선택 신호가 1일 때의 결과입니다
b선택 신호가 0일 때의 결과입니다
결과 타입두 분기에 공통인 타입입니다. 여기서는 UInt입니다
결과 폭두 분기 가운데 넓은 쪽의 폭입니다

예를 들어 Mux(c, 3.U(2.W), 200.U(8.W))의 폭은 8비트이고 값은 3 또는 200입니다.

주의. 두 분기는 같은 종류의 Data여야 합니다. Mux(c, 1.U, -1.S)처럼 UInt와 SInt를 섞으면 java.lang.AssertionError: can't create Mux with heterogeneous types class chisel3.UInt and class chisel3.SInt 메시지와 함께 elaboration이 중단됩니다. asSInt 같은 변환으로 한쪽을 명시적으로 맞추세요. 두 분기의 타입이 같다면 Bundle과 Vec 장의 집합 타입도 분기로 쓸 수 있습니다.

1.2 Mux 중첩하기

입력이 셋 이상이면 Mux를 중첩합니다. 안쪽 Mux가 바깥 Mux의 거짓 분기가 됩니다.

val y = Mux(s0, a, Mux(s1, b, Mux(s2, c, d)))

s0를 가장 먼저 검사하므로 s0가 1이면 s1도 1이더라도 a가 선택됩니다. 먼저 검사한 조건이 이기는 이 순서가 우선순위입니다. 아래에서 배울 함수들은 목록을 받아 이런 연쇄를 대신 만들어 줍니다. 직접 중첩한 Mux는 세 단계를 넘으면 읽기 어려워지므로 그때부터 함수를 쓰는 편이 낫습니다.

2. 조건 목록과 키로 선택하기

2.1 MuxCase: 처음 참인 조건이 선택됨

MuxCase는 기본값 하나와 조건 -> 값 쌍의 목록을 받습니다. 목록에서 처음으로 참인 조건의 값을 반환하고, 참인 조건이 없으면 기본값을 반환합니다.

형식

MuxCase(기본값, Seq(
  조건1 -> 값1,
  조건2 -> 값2
))
val level = MuxCase(0.U, Seq(
  (x > 100.U) -> 2.U,
  (x > 10.U)  -> 1.U
))
입력 x참인 조건level
5없음기본값 0
50x > 101
150둘 다2. 목록에서 x > 100이 먼저입니다

목록 순서가 곧 우선순위입니다. 두 줄의 순서를 바꾸면 x = 150에서 1이 반환됩니다.

주의. 쌍 안의 비교식은 괄호로 감싸세요. Scala에서 ->는 >, === 같은 비교 연산자보다 먼저 결합합니다. x === 0.U -> a는 x === (0.U -> a)로 해석되어 컴파일되지 않습니다.

2.2 MuxLookup: 키 하나를 상수와 비교

MuxLookup은 키 신호 하나를 상수 키 목록과 비교합니다. 키들은 한 신호의 서로 다른 값이므로 일치하는 키는 많아야 하나입니다. 올바른 표에서는 우선순위가 의미를 갖지 않습니다.

형식

MuxLookup(키, 기본값)(Seq(
  키1 -> 값1,
  키2 -> 값2
))
val result = MuxLookup(op, 0.U)(Seq(
  0.U -> (a + b),
  1.U -> (a - b),
  2.U -> (a & b)
))
구성 요소의미
MuxLookup(op, 0.U)첫 번째 인자 목록. 키와 기본값입니다
(Seq(...))두 번째 인자 목록. 키 -> 값 쌍의 표입니다
0.U -> (a + b)op === 0.U이면 결과는 a + b입니다
표에 없는 키op가 3이면 기본값 0을 반환합니다

ChiselEnum과 상태 머신 장에서 열거형을 배우고 나면, 키와 표의 키를 열거형 값으로 쓸 수도 있습니다. MuxLookup(color, 0.U)(Seq(Color.red -> 10.U, Color.green -> 20.U))는 Color.blue에서 0을 반환합니다.

주의. Chisel 6에서는 표를 두 번째 인자 목록에 씁니다. 인자 세 개를 한 번에 전달하는 이전 형태 MuxLookup(op, 0.U, Seq(...))는 컴파일되지 않습니다.

2.3 조회 표로 쓰는 Vec 인덱싱

키가 정확히 0, 1, 2, ...이고 모든 인덱스에 항목이 있다면 표를 키로 인덱싱하는 편이 더 직접적입니다. 단, 이 표는 Scala Seq로 만들 수 없습니다. values = Seq(11.U, 22.U, 33.U, 44.U) 같은 Seq는 생성기가 실행되는 동안에만 있는 Scala 값입니다. values(2)는 Scala가 세 번째 원소를 꺼내 주는 것으로 끝나고, 선택을 위한 하드웨어는 생기지 않습니다. 인덱스도 Scala Int여야 하므로 values(io.sel)은 type mismatch; found: chisel3.UInt, required: Int와 함께 컴파일되지 않습니다.

회로가 직접 인덱싱할 수 있는 표는 Vec입니다. Vec은 같은 Chisel 타입의 원소를 정해진 개수만큼 묶은 하드웨어이고, VecInit은 하드웨어 값들로 Vec을 만듭니다.

형식

VecInit(값0, 값1, 값2, 값3)   // 값들이 구동하는 Vec wire
table(i)      // i가 Scala Int: 정해진 원소 하나
table(sel)    // sel이 하드웨어 UInt: 멀티플렉서
val table = VecInit(11.U, 22.U, 33.U, 44.U)
val y = table(io.sel)   // sel이 2이면 33
val z = table(2)        // 항상 33
구성 요소의미
VecInit(11.U, ...)원소 네 개짜리 wire입니다. 원소 타입은 가장 넓은 값을 따라 6비트가 됩니다
table(2)정적 인덱스입니다. elaboration 중에 정해져 원소 2에 대한 연결만 남습니다
table(io.sel)동적 인덱스입니다. 회로가 동작하는 동안 고르므로 멀티플렉서가 생깁니다

출력한 CHIRRTL에서도 차이가 보입니다. table[2]는 원소 하나를 가리키고, table[io.sel]은 뒤 단계의 변환에서 원소 네 개 전체를 고르는 멀티플렉서로 바뀝니다.

확인 문제

values = Seq(1.U, 2.U, 3.U), table = VecInit(1.U, 2.U, 3.U)일 때 회로에 멀티플렉서를 만드는 줄은 어느 것일까요?

답

표에 빈 키가 있거나 기본값이 필요하면 MuxLookup을, 인덱스가 빈틈없는 범위를 덮으면 Vec 인덱싱을 쓰세요. Vec 포트, Vec(n, 타입), Scala 인덱스와 하드웨어 인덱스의 전체 규칙은 Bundle과 Vec 장에서 다맑니다.

3. 선택자 벡터로 선택하기

3.1 PriorityMux: 인덱스가 가장 작은 선택자가 선택됨

PriorityMux는 Bool 선택자 목록과 값 목록을 받아, 참인 선택자 가운데 번호가 가장 작은 쪽의 값을 반환합니다.

형식

PriorityMux(선택자_목록, 값_목록)        // Seq[Bool]과 값의 Seq
PriorityMux(Seq(sel0 -> v0, sel1 -> v1)) // 같은 내용을 쌍으로
PriorityMux(선택자_UInt, 값_목록)        // UInt의 bit i가 선택자 i
val values = Seq(11.U, 22.U, 33.U, 44.U)
val y = PriorityMux(req, values)   // req: UInt(4.W)
req (bit 3부터 bit 0)참인 선택자y
0100233
01101과 222. 인덱스가 가장 작은 쪽입니다
0000없음44. 마지막 값입니다

주의. PriorityMux에는 기본값 인자가 없습니다. 참인 선택자가 없으면 연쇄의 끝인 마지막 값이 반환되므로, "아무도 요청하지 않음"과 "마지막 요청자가 요청함"이 출력만으로는 구분되지 않습니다.

3.2 Mux1H: 참인 선택자가 정확히 하나

Mux1H는 선택자가 one-hot, 곧 정확히 하나만 1이어야 합니다. 이 전제 덕분에 연쇄를 만들 필요가 없습니다. 각 값을 자기 선택자와 AND한 뒤 결과를 모두 OR합니다.

형식

Mux1H(선택자_목록, 값_목록)          // Seq[Bool]과 값의 Seq
Mux1H(Seq(sel0 -> v0, sel1 -> v1))   // 같은 내용을 쌍으로
Mux1H(선택자_UInt, 값_목록)          // UInt의 bit i가 선택자 i
val y = Mux1H(grant, values)   // grant: one-hot인 UInt(4.W)
grant참인 선택자y
0100233
0000없음문서상 정의되지 않음. 이 UInt 구현은 0을 반환합니다
01101과 2계약상 정의되지 않습니다. 현재 버전은 22 OR 33 = 55를 출력합니다

AND-OR 구조는 선택 경로를 줄일 수 있지만, 최종 면적과 지연은 데이터 형태와 합성 결과에 따라 달라집니다. 그 대가로 전제가 깨지면 어느 입력의 값도 아닌 값이 출력되며, Chisel과 시뮬레이터 모두 경고하지 않습니다.

3.3 한눈에 비교하기

함수선택 신호여러 개가 참일 때하나도 참이 아닐 때
Mux(c, a, b)Bool 하나해당 없음b
MuxCase(기본값, 쌍)서로 독립인 조건목록에서 먼저 나온 조건기본값
MuxLookup(키, 기본값)(쌍)키 하나와 상수 표키가 서로 다르면 일어나지 않음기본값
PriorityMux(선택자, 값)우선순위 순서의 Bool인덱스가 가장 작은 쪽마지막 값
Mux1H(선택자, 값)one-hot Bool정의되지 않음정의되지 않음. 현재 버전은 0

확인 문제

상태 레지스터를 one-hot으로 관리합니다. 매 사이클 네 비트 가운데 정확히 하나만 1이고, 각 비트가 출력값 하나를 고릅니다. 가장 알맞은 구문은 무엇일까요?

답

확인 문제

요청자 네 명이 버스 하나를 공유합니다. 요청자 0이 가장 급하고, 아무도 요청하지 않으면 출력이 0이어야 합니다. 호출 한 번으로 이를 표현하는 구문은 무엇일까요?

답

4. 예제: 같은 선택을 다섯 가지로 쓰기

Select.scala는 상수 입력 11, 22, 33, 44 가운데 하나를 2비트 sel로 선택합니다. 다음 순서로 읽으세요.

  • Seq.tabulate(4)는 elaboration 중에 Bool 네 개를 만듭니다. hit(i)는 io.sel === i.U이므로 어떤 sel에서도 정확히 하나만 참입니다.
  • 출력 다섯 개가 같은 선택을 서로 다른 방법으로 기술합니다.
출력구성
nested직접 중첩한 Mux 세 개. 입력 3이 최종 거짓 분기입니다
muxCase조건 세 개와 기본값 입력 3으로 만든 MuxCase
muxLookupsel을 키로 쓰고 키 0부터 2와 기본값 입력 3으로 만든 MuxLookup
oneHothit 네 비트를 선택자로 쓰는 Mux1H
priorityhit 네 비트를 선택자로 쓰는 PriorityMux
Select.scala
import chisel3._
import chisel3.util._

class Select extends Module {
  val io = IO(new Bundle {
    val sel       = Input(UInt(2.W))
    val nested    = Output(UInt(8.W))
    val muxCase   = Output(UInt(8.W))
    val muxLookup = Output(UInt(8.W))
    val oneHot    = Output(UInt(8.W))
    val priority  = Output(UInt(8.W))
  })
  val values = Seq(11.U, 22.U, 33.U, 44.U)
  // 입력마다 Bool 하나. 어떤 sel에서도 정확히 하나만 참이다.
  val hit = Seq.tabulate(4)(i => io.sel === i.U)

  io.nested    := Mux(hit(0), values(0), Mux(hit(1), values(1), Mux(hit(2), values(2), values(3))))
  io.muxCase   := MuxCase(values(3), Seq(hit(0) -> values(0), hit(1) -> values(1), hit(2) -> values(2)))
  // MuxLookup은 sel을 각 키와 비교한다. 일치하는 키가 없으면 기본값을 쓴다.
  io.muxLookup := MuxLookup(io.sel, values(3))(Seq(0.U -> values(0), 1.U -> values(1), 2.U -> values(2)))
  io.oneHot    := Mux1H(hit, values)
  io.priority  := PriorityMux(hit, values)
}

Tb.scala는 sel의 모든 값을 인가하고 다섯 출력을 한 줄에 나란히 출력합니다.

Tb.scala
import chisel3._
import chiseltest._
import chiseltest.RawTester.test

object Main extends App {
  test(new Select) { dut =>
    for (sel <- 0 until 4) {
      dut.io.sel.poke(sel.U)
      val outs = Seq("nested" -> dut.io.nested, "case" -> dut.io.muxCase, "lookup" -> dut.io.muxLookup,
        "onehot" -> dut.io.oneHot, "priority" -> dut.io.priority)
      println(s"sel=$sel " + outs.map { case (name, port) => s"$name=${port.peek().litValue}" }.mkString(" "))
    }
  }
}

이 개념 실습하기

다음 단계로 짧은 Chisel 문제에 이 개념을 적용해 보세요.

실행하기 전에 예측해 보세요.

  1. 다섯 열 가운데 두 열의 값이 다른 sel이 있을까요?
  2. sel=3에서 기본값이나 최종 거짓 분기로 44에 도달하는 출력은 무엇이고, 참인 선택자로 44에 도달하는 출력은 무엇일까요?

결과 확인.

출력 줄확인할 내용
sel=0부터 sel=2다섯 열이 모두 차례로 11, 22, 33을 선택합니다
sel=3다섯 열이 모두 44입니다. nested, case, lookup은 기본값으로, onehot과 priority는 hit(3)으로 44를 선택합니다

다섯 열은 서로 다를 수 없습니다. hit 비트가 구조적으로 배타적이므로 우선순위가 작동할 상황이 없고 one-hot 전제도 항상 성립합니다. 그래도 다섯 구문이 생성하는 회로는 다릅니다. 그 차이는 전제가 깨질 때만 출력에 나타나며, 다음 예제가 일부러 그 상황을 만듭니다.

직접 바꿔 보세요.

  1. MuxLookup 표 끝에 중복 키 1.U -> 99.U를 추가해 보세요. sel=1 줄에서 lookup 열만 99가 되고 나머지 열은 22입니다. 표는 연쇄로 만들어지고 마지막 항목이 가장 바깥에 놓이므로, 중복 키는 앞의 항목을 경고 없이 덮어씁니다.
  2. 중첩 Mux의 마지막 입력을 -1.S로 바꿔 보세요. can't create Mux with heterogeneous types class chisel3.UInt and class chisel3.SInt와 함께 elaboration이 중단됩니다.
  3. 첫 MuxCase 조건을 io.sel === 0.U -> values(0)으로 써 보세요. 컴파일러가 === 위치에서 type mismatch; found: (chisel3.UInt, chisel3.UInt), required: chisel3.UInt를 보고합니다. 쌍이 먼저 만들어진 뒤 ===에 전달되었기 때문입니다.

5. 예제: 선택자가 겹칠 때

Pick.scala는 4비트 요청 벡터 req를 asBools로 Bool 네 개로 나눕니다. bit 0이 요청자 0입니다. 요청자 0부터 3에는 값 11부터 44가 대응합니다. 출력 세 개가 이 값들 가운데 하나를 고릅니다.

출력함수선택 규칙
lowFirstPriorityMux번호가 가장 작은 요청
highFirst요청자 3부터 0 순서로 쓴 MuxCase, 기본값 0번호가 가장 큰 요청
oneHotMux1H요청이 정확히 하나여야 함
Pick.scala
import chisel3._
import chisel3.util._

class Pick extends Module {
  val io = IO(new Bundle {
    val req       = Input(UInt(4.W))
    val lowFirst  = Output(UInt(8.W))
    val highFirst = Output(UInt(8.W))
    val oneHot    = Output(UInt(8.W))
  })
  val values = Seq(11.U, 22.U, 33.U, 44.U)
  val req    = io.req.asBools

  // PriorityMux: 참인 선택자 가운데 번호가 가장 작은 쪽이 선택된다.
  io.lowFirst  := PriorityMux(req, values)
  // MuxCase: 목록에서 처음 참인 조건이 선택되므로 목록 순서가 우선순위다.
  io.highFirst := MuxCase(0.U, Seq(req(3) -> values(3), req(2) -> values(2), req(1) -> values(1), req(0) -> values(0)))
  // Mux1H는 참인 선택자가 정확히 하나여야 한다. 없거나 둘 이상이면 결과는 정의되지 않는다.
  io.oneHot    := Mux1H(req, values)
}

Tb.scala는 요청 패턴 네 개를 인가하고 최상위 비트부터 출력합니다. 요청 하나, 인접한 요청 둘, 떨어진 요청 둘, 요청 없음 순서입니다.

Tb.scala
import chisel3._
import chiseltest._
import chiseltest.RawTester.test

object Main extends App {
  test(new Pick) { dut =>
    for (req <- Seq(0x4, 0x6, 0xa, 0x0)) {
      dut.io.req.poke(req.U)
      val req4 = req.toBinaryString.reverse.padTo(4, '0').reverse
      println(s"req=$req4 low=${dut.io.lowFirst.peek().litValue} high=${dut.io.highFirst.peek().litValue} onehot=${dut.io.oneHot.peek().litValue}")
    }
  }
}

이 개념 실습하기

다음 단계로 짧은 Chisel 문제에 이 개념을 적용해 보세요.

실행하기 전에 예측해 보세요. 다음 표를 채운 뒤 실행하세요. 요청이 둘일 때 oneHot 열은 두 값을 이진수로 OR합니다. 22는 010110, 33은 100001, 44는 101100입니다.

req요청자lowhighonehot
01002???
01101, 2???
10101, 3???
0000없음???

결과 확인.

출력 줄확인할 내용
req=0100세 열 모두 33입니다. 요청이 하나면 어느 구문도 틀리지 않습니다
req=0110low=22와 high=33은 각 목록의 순서를 따릅니다. onehot=55는 22 OR 33으로, 어느 요청자의 값도 아닙니다
req=1010low=22, high=44입니다. onehot=62는 22 OR 44입니다
req=0000low=44는 연쇄의 끝, high=0은 명시한 기본값, onehot=0은 모든 값을 0과 AND한 결과입니다

onehot 열의 값은 3.2절의 AND-OR 구조를 그대로 보여 줍니다. 다만 이 값에 기대는 코드는 쓰지 마세요. 계약상 결과는 정의되지 않으며, 입력 타입이나 Chisel 버전이 바뀌면 생성 구조도 달라질 수 있습니다.

직접 바꿔 보세요.

  1. MuxCase 목록을 요청자 0부터 시작하도록 뒤집어 보세요. 요청이 있는 모든 줄에서 high가 low와 같아집니다. 0000에서만 0과 44로 여전히 다른데, 두 함수가 "요청 없음"을 다르게 처리하기 때문입니다.
  2. Mux1H에 구조적으로 one-hot인 벡터를 전달해 보세요. Mux1H(UIntToOH(PriorityEncoder(io.req)), values)로 바꾸면 PriorityEncoder가 가장 낮은 1 비트의 인덱스를 구하고, UIntToOH가 그 인덱스를 다시 한 비트짜리 one-hot 벡터로 만듭니다. onehot 열이 모든 줄에서 low와 같아지고, 0000에서도 44가 됩니다. PriorityEncoder도 입력이 0이면 마지막 인덱스를 반환합니다.

확인 문제

Pick.scala의 values를 Seq(5.U, 6.U, 9.U, 12.U)로 바꾸고 req = 0101을 인가하면 low와 onehot은 무엇일까요?

답

6. 자주 하는 실수

6.1 분기의 타입이 다름

// 잘못된 코드: UInt 분기와 SInt 분기
val y = Mux(c, a, -1.S)

// 바른 코드: 두 분기를 모두 SInt로 맞춤
val y = Mux(c, a.asSInt, -1.S)

Mux는 값 하나를 반환하므로 그 타입이 두 분기를 모두 기술해야 합니다. Chisel은 변환을 추측하지 않고 can't create Mux with heterogeneous types로 elaboration을 중단합니다.

6.2 쌍 안의 비교식에 괄호가 없음

// 잘못된 코드: sel === (0.U -> a)로 해석됨
MuxCase(d, Seq(sel === 0.U -> a))

// 바른 코드
MuxCase(d, Seq((sel === 0.U) -> a))

->가 ===보다 먼저 결합합니다. 컴파일러는 === 위치를 가리키며 type mismatch; found: (chisel3.UInt, chisel3.UInt), required: chisel3.UInt를 보고합니다.

6.3 인자 세 개짜리 MuxLookup

// 잘못된 코드: 이전 Chisel 형태
MuxLookup(op, 0.U, Seq(0.U -> a, 1.U -> b))

// 바른 코드: Chisel 6은 표를 두 번째 인자 목록으로 받음
MuxLookup(op, 0.U)(Seq(0.U -> a, 1.U -> b))

컴파일러는 UInt 키용과 EnumType 키용 apply 두 개를 나열하고, 어느 쪽도 인자 세 개에 cannot be applied to라고 보고합니다.

6.4 겹칠 수 있는 선택자에 Mux1H 사용

// 잘못된 코드: 요청이 둘이면 두 값의 OR가 출력됨
val data = Mux1H(io.req, values)

// 바른 코드: 우선순위 함수로 고르거나, 먼저 one-hot으로 만듦
val data = PriorityMux(io.req, values)

Mux1H는 배타성이 구조적으로 보장될 때만 쓰세요. 디코딩한 인덱스, one-hot 상태 레지스터, arbiter의 grant 벡터가 그런 선택 신호입니다.

6.5 Scala Boolean을 선택 신호로 사용

// 잘못된 코드: true는 하드웨어가 생기기 전에 정해지는 Scala Boolean
val y = Mux(true, a, b)

// 바른 코드(하드웨어에서 선택): 하드웨어 Bool로 선택
val y = Mux(io.useA, a, b)

// 바른 코드(elaboration에서 선택): Scala if 사용
val y = if (useA) a else b

잘못된 코드는 type mismatch; found: Boolean(true), required: chisel3.Bool 컴파일 오류가 발생합니다. Mux는 회로가 동작하는 동안 전환되는 멀티플렉서를 만듭니다. 생성기가 실행될 때 이미 정해지는 선택은 Scala if로 쓰며, 이때는 멀티플렉서가 생기지 않습니다. 생성기 매개변수에서 이미 이 방법을 썼고, 다형성과 매개변수화 장에서는 이 방법으로 설정 전체를 구성합니다.

7. 정리

구문쓰는 곳기억할 규칙
Mux(c, a, b)입력 두 개두 분기는 같은 종류의 Data. 폭은 넓은 분기를 따름
MuxCase(d, 쌍)순서가 의도된 조건 목록처음 참인 조건이 선택됨. 없으면 d
MuxLookup(k, d)(쌍)UInt나 열거형 키로 찾는 빈틈 있는 표두 번째 인자 목록. 중복 키는 마지막 항목이 이김
VecInit(...)(i)0부터 빈틈없는 표하드웨어 인덱스는 멀티플렉서를 만듦. Scala Seq는 하드웨어 인덱스를 받지 못함
PriorityMux(선택자, 값)우선순위 순서의 요청 벡터인덱스가 가장 작은 쪽. 기본값 없이 마지막 값으로 감
Mux1H(선택자, 값)구조적으로 one-hot인 선택자AND-OR. 최종 크기와 깊이는 합성에 따라 달라짐. 전제가 깨지면 정의되지 않음

8. 확인 문제

  1. mux-family 예제에서 모든 sel에 대해 다섯 열이 같은 이유는 무엇일까요?

    정답 보기

    hit(i)는 sel === i이므로 어떤 sel에서도 hit 비트는 정확히 하나만 참입니다. 우선순위가 작동할 상황이 없고 Mux1H의 one-hot 전제도 항상 성립합니다.

  2. 요청이 없을 때 44를 반환한 함수는 무엇이고, 그 이유는 무엇일까요?

    정답 보기

    PriorityMux입니다. 기본값 인자가 없으므로 참인 선택자가 없으면 연쇄의 끝인 마지막 값 44가 반환됩니다.

  3. req=1010 줄의 62는 어떻게 계산될까요?

    정답 보기

    요청자 1과 3이 함께 요청했으므로 Mux1H가 22(010110)와 44(101100)를 OR합니다. 결과 111110은 62입니다.

  4. PriorityMux를 Mux1H로 바꾸면 출력 말고 회로에서는 무엇이 달라질까요?

    정답 보기

    PriorityMux는 2입력 멀티플렉서의 연쇄를 만듭니다. 입력이 N개면 합성 도구가 재구성하기 전까지 N - 1단입니다. Mux1H는 AND 게이트들과 OR 하나를 만들어 선택 경로를 줄일 수 있지만, 참인 선택자가 정확히 하나일 때만 결과가 보장됩니다.

  5. MuxCase(0.U, Seq(sel === 0.U -> a))가 컴파일되지 않는 이유와 고치는 방법은 무엇일까요?

    정답 보기

    ->가 ===보다 먼저 결합하므로 Scala는 쌍 0.U -> a를 먼저 만들고 sel과 쌍을 비교하려 합니다. (sel === 0.U) -> a로 괄호를 쓰세요.

확인 지점

예제를 실행해 예측과 비교합니다

참고 자료

참고한 자료의 라이선스와 고지