데이터 경로의 많은 부분은 선택입니다. 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 |
| 50 | x > 10 | 1 |
| 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가 선택자 ival 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 |
|---|---|---|
0100 | 2 | 33 |
0110 | 1과 2 | 22. 인덱스가 가장 작은 쪽입니다 |
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가 선택자 ival y = Mux1H(grant, values) // grant: one-hot인 UInt(4.W)grant | 참인 선택자 | y |
|---|---|---|
0100 | 2 | 33 |
0000 | 없음 | 문서상 정의되지 않음. 이 UInt 구현은 0을 반환합니다 |
0110 | 1과 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 |
muxLookup | sel을 키로 쓰고 키 0부터 2와 기본값 입력 3으로 만든 MuxLookup |
oneHot | hit 네 비트를 선택자로 쓰는 Mux1H |
priority | hit 네 비트를 선택자로 쓰는 PriorityMux |
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의 모든 값을 인가하고 다섯 출력을 한 줄에 나란히 출력합니다.
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 문제에 이 개념을 적용해 보세요.
실행하기 전에 예측해 보세요.
- 다섯 열 가운데 두 열의 값이 다른
sel이 있을까요? 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 전제도 항상 성립합니다. 그래도 다섯 구문이 생성하는 회로는 다릅니다. 그
차이는 전제가 깨질 때만 출력에 나타나며, 다음 예제가 일부러 그 상황을 만듭니다.
직접 바꿔 보세요.
MuxLookup표 끝에 중복 키1.U -> 99.U를 추가해 보세요.sel=1줄에서lookup열만 99가 되고 나머지 열은 22입니다. 표는 연쇄로 만들어지고 마지막 항목이 가장 바깥에 놓이므로, 중복 키는 앞의 항목을 경고 없이 덮어씁니다.- 중첩
Mux의 마지막 입력을-1.S로 바꿔 보세요.can't create Mux with heterogeneous types class chisel3.UInt and class chisel3.SInt와 함께elaboration이 중단됩니다. - 첫
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가 대응합니다. 출력 세 개가 이 값들 가운데 하나를
고릅니다.
| 출력 | 함수 | 선택 규칙 |
|---|---|---|
lowFirst | PriorityMux | 번호가 가장 작은 요청 |
highFirst | 요청자 3부터 0 순서로 쓴 MuxCase, 기본값 0 | 번호가 가장 큰 요청 |
oneHot | Mux1H | 요청이 정확히 하나여야 함 |
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는 요청 패턴 네 개를 인가하고 최상위 비트부터 출력합니다. 요청 하나, 인접한 요청
둘, 떨어진 요청 둘, 요청 없음 순서입니다.
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 | 요청자 | low | high | onehot |
|---|---|---|---|---|
0100 | 2 | ? | ? | ? |
0110 | 1, 2 | ? | ? | ? |
1010 | 1, 3 | ? | ? | ? |
0000 | 없음 | ? | ? | ? |
결과 확인.
| 출력 줄 | 확인할 내용 |
|---|---|
req=0100 | 세 열 모두 33입니다. 요청이 하나면 어느 구문도 틀리지 않습니다 |
req=0110 | low=22와 high=33은 각 목록의 순서를 따릅니다. onehot=55는 22 OR 33으로, 어느 요청자의 값도 아닙니다 |
req=1010 | low=22, high=44입니다. onehot=62는 22 OR 44입니다 |
req=0000 | low=44는 연쇄의 끝, high=0은 명시한 기본값, onehot=0은 모든 값을 0과 AND한 결과입니다 |
onehot 열의 값은 3.2절의 AND-OR 구조를 그대로 보여 줍니다. 다만 이 값에 기대는 코드는
쓰지 마세요. 계약상 결과는 정의되지 않으며, 입력 타입이나 Chisel 버전이 바뀌면 생성 구조도
달라질 수 있습니다.
직접 바꿔 보세요.
MuxCase목록을 요청자 0부터 시작하도록 뒤집어 보세요. 요청이 있는 모든 줄에서high가low와 같아집니다.0000에서만 0과 44로 여전히 다른데, 두 함수가 "요청 없음"을 다르게 처리하기 때문입니다.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. 확인 문제
-
mux-family예제에서 모든sel에 대해 다섯 열이 같은 이유는 무엇일까요?정답 보기
hit(i)는sel === i이므로 어떤sel에서도hit비트는 정확히 하나만 참입니다. 우선순위가 작동할 상황이 없고Mux1H의 one-hot 전제도 항상 성립합니다. -
요청이 없을 때 44를 반환한 함수는 무엇이고, 그 이유는 무엇일까요?
정답 보기
PriorityMux입니다. 기본값 인자가 없으므로 참인 선택자가 없으면 연쇄의 끝인 마지막 값 44가 반환됩니다. -
req=1010줄의 62는 어떻게 계산될까요?정답 보기
요청자 1과 3이 함께 요청했으므로
Mux1H가 22(010110)와 44(101100)를 OR합니다. 결과111110은 62입니다. -
PriorityMux를Mux1H로 바꾸면 출력 말고 회로에서는 무엇이 달라질까요?정답 보기
PriorityMux는 2입력 멀티플렉서의 연쇄를 만듭니다. 입력이 N개면 합성 도구가 재구성하기 전까지 N - 1단입니다.Mux1H는 AND 게이트들과 OR 하나를 만들어 선택 경로를 줄일 수 있지만, 참인 선택자가 정확히 하나일 때만 결과가 보장됩니다. -
MuxCase(0.U, Seq(sel === 0.U -> a))가 컴파일되지 않는 이유와 고치는 방법은 무엇일까요?정답 보기
->가===보다 먼저 결합하므로 Scala는 쌍0.U -> a를 먼저 만들고sel과 쌍을 비교하려 합니다.(sel === 0.U) -> a로 괄호를 쓰세요.