16검증 문제
요청과 tag를 함께 지연시키기
1. 요구 동작
Retime은 TaggedLink를 한 사이클 지연시키는 파이프라인 레지스터입니다.
TaggedLink는 Link의 data, valid에 4비트 tag를 추가한 번들입니다. tag는
요청을 보낸 유닛의 번호입니다. out의 모든 필드는 한 사이클 전 in의 필드와 같아야
하며, 요청과 tag는 항상 같은 사이클에 도착해야 합니다.
2. 관찰되는 증상
시작 코드는 컴파일되고 data와 valid를 올바르게 지연시킵니다. 그러나 각 요청은 바로
뒤 요청의 tag와 함께 출력됩니다. 이 tag로 응답을 라우팅하면 응답이 다른 유닛으로 갑니다.
tag가 파이프라인 레지스터를 거치지 않는 원인을 찾아, 링크 전체가 레지스터를 통과하도록 고치세요. 번들 클래스와 포트는 그대로 둡니다.
3. 실행 전 예측
테스트벤치는 사이클마다 요청 하나를 제시합니다. 순서는 (data, valid, tag) =
(10,1,1), (20,1,2), (30,0,3), (40,1,4)이고 마지막은 빈 요청입니다. 각 줄의
왼쪽은 그 사이클의 입력이고 오른쪽은 out입니다. 레지스터에 리셋 값이 없으므로
사이클 0은 출력하지 않습니다.
올바른 지연 단에서는 각 줄의 오른쪽이 한 사이클 전 입력과 같습니다. 첫 출력 줄인 사이클
1에는 출력하지 않은 사이클 0의 입력 (10,1,1)이 나타나야 합니다. 이 예측을 적은 뒤
시작 코드를 실행하고, 각 줄에서 tag 열과 data 열을 비교해 보세요.
4. 원인 진단
stage의 선언과 stage로 들어가는 연결을 읽고 다음을 확인하세요.
Link에는 어떤 필드가 있을까요?- 오른쪽에만 있는 필드를
:=는 어떻게 처리할까요?
out.tag를 직접 구동하는 줄은 원인이 아닙니다. 레지스터에서 빠진 tag를 보충하려고
추가한 줄이며, 원인이 남긴 증상입니다.
5. 실행 결과 해석
수정한 지연 단을 실행해 보세요. 모든 줄에서 오른쪽이 한 사이클 전 입력과 같고, 각 tag가
함께 보낸 data와 같은 줄에 나타나야 합니다. out.tag를 구동하는 줄이 아니라
레지스터 타입을 바꾼 것이 tag를 요청과 함께 이동시킨 이유를 설명해 보세요.
6. 완료 조건
out.data,out.valid,out.tag가 모두 한 사이클 전in의 값과 같습니다. 필드 값의 어떤 조합에서도 성립해야 합니다.data는 그대로이고tag만 바뀌는 경우에도 tag는 한 사이클 뒤에 도착합니다.- tag 없는 지연 단 옆에 tag용 레지스터를 따로 두는 방식은 의도와 다릅니다. 지연 레지스터가 인터페이스 전체를 보관해야 합니다.
7. 힌트
힌트 1
stage := io.in은 두 쪽의 인터페이스 타입이 달라도 컴파일됩니다. 인터페이스 장에서
:=가 복사하는 필드와 경고 없이 버리는 필드를 확인해 보세요.
힌트 2
파이프라인 레지스터를 포트와 같은 인터페이스 타입으로 선언하세요. 그다음 out을
레지스터 전체에서 연결해, 어떤 필드도 in에서 직접 가져오지 않게 하세요.
개념 설명
인터페이스 타입은 함께 이동해야 하는 신호를 정하는 계약입니다. 링크를 부모 클래스
타입의 레지스터에 저장하거나 부모 클래스 타입으로 연결하면 하위 클래스가 추가한
필드가 빠집니다. :=는 이 손실을 오류 없이 허용하므로, 문제는 한참 뒤에 타이밍이나
라우팅 오류로만 드러납니다.
8. 추가 실험
Link 레지스터는 그대로 두고, 지연 단으로 들어가는 연결을 := 대신 :<>=로 썼다고
가정해 보세요. 타입 불일치가 어느 단계에서 보고되는지 예측하고, 그 단계에서 오류가
발생했다면 이 결함이 생기지 않았을 이유를 설명해 보세요.