23구현 문제
범용 hold 레지스터 만들기
1. 요구 동작
Hold[T <: Data](gen)은 어떤 payload 타입에도 사용할 수 있는 레지스터입니다.
| 조건 | 동작 |
|---|---|
en이 1인 클록 에지 | in을 저장합니다 |
en이 0인 클록 에지 | 저장된 값을 유지합니다 |
out | 가장 최근에 저장한 값을 출력합니다 |
저장한 값은 저장이 일어난 에지 직후 out에 반영됩니다. 첫 저장 전의 출력은
정의하지 않습니다. PixelHold는 같은 생성기를 필드 세 개의 Pixel로 고정한 모듈입니다.
시작 코드는 in을 out에 직접 연결합니다. 출력이 매 사이클 입력을 따라가므로 아무 값도
유지되지 않습니다. Hold에 필요한 레지스터를 추가하세요. 공개 실행은
Hold(UInt(8.W))와 PixelHold를 모두 만들므로 본문은 모든 T에서 동작해야 합니다.
클래스 이름, 타입 매개변수, 포트는 그대로 둡니다.
2. 시작 코드 읽기
gen이 쓰이는 곳을 찾아보세요. gen은 in과 out의 형태를 정하고, en은 항상
Bool입니다. 템플릿 자체는 어디에도 연결되지 않습니다. 본문은 T의 폭이나 필드 이름을
알지 못하며, gen이 기술하는 형태만 사용할 수 있습니다.
3. 실행 결과 예측
공개 실행은 입력을 인가하고 클록을 한 번 진행한 뒤 out을 출력합니다. UInt
테스트의 입력은 7, 8, 9, 10, 11이며 en은 7과 10에서만 1입니다. 다섯 out 값과
Pixel의 세 줄을 먼저 적어 보세요. 시작 코드는 모든 줄에서 입력을 그대로 출력합니다.
4. 실행 결과 해석
수정한 설계를 실행해 보세요. UInt 줄의 out은 en이 참인 줄에서만 바뀌어야 하고,
Pixel 줄은 세 필드를 함께 유지해야 합니다. 같은 본문이 타입 이름을 하나도 쓰지 않고
한 인스턴스에는 8비트 레지스터를, 다른 인스턴스에는 필드 세 개의 레지스터를 만든
과정을 설명해 보세요.
5. 완료 조건
out은en이 1이던 에지 뒤에만 바뀝니다.en이 0이면in이 바뀌어도 몇 사이클이든out이 유지됩니다.Bundlepayload의 모든 필드가 함께 저장됩니다.- 같은 본문이
UInt와Pixel에서 모두 컴파일되고 올바르게 동작합니다.
6. 단계형 힌트
힌트 1
여러 사이클에 걸쳐 값을 유지하려면 상태가 필요합니다. 순차 회로 장에서 값을 저장하고
:=로 갱신하는 구성 요소를 떠올려 보세요.
힌트 2
레지스터의 타입은 T여야 하고, T를 기술하는 값은 gen뿐입니다. UInt(8.W) 같은
고정 타입을 쓰면 Pixel 인스턴스에서 컴파일 오류가 발생합니다.
힌트 3
레지스터는 when(io.en) 안에서 갱신하고, out은 입력이 아니라 레지스터에서
연결하세요.
개념 설명
gen은 Chisel 타입, 즉 하드웨어의 형태를 정하는 템플릿입니다. Input(gen),
Output(gen), Reg(gen)은 각각 같은 형태의 별도 하드웨어 값을 만듭니다. 범용 본문은
:=와 when처럼 모든 Data가 지원하는 연산만 사용합니다. 그래서 같은 코드가 한
인스턴스에서는 8비트 레지스터를, 다른 인스턴스에서는 24비트 Bundle 레지스터를
생성합니다.
7. 추가 실험
gen 대신 Reg(io.in)을 쓰면 무엇이 달라질지 예측해 보세요. 이어서
new Hold(0.U(8.W))의 elaboration 결과와 실패하는 단계를 예측해 보세요.