본문으로 건너뛰기
code0.HDL

15검증 문제

같은 사이클에 레지스터 파일 읽기

1. 요구 동작

RegFile은 작은 프로세서용 8비트 레지스터 8개를 보관합니다. decode 단계의 명령어는 raddrA와 raddrB에 소스 레지스터 번호 두 개를 제시하고, 같은 사이클에 두 값을 모두 받아야 합니다. execute 단계가 다음 클록 에지에서 두 값을 가져갑니다.

wen, waddr, wdata로 들어온 쓰기는 클록 에지에서 반영됩니다. 따라서 쓰기 사이클에 같은 레지스터를 읽으면 이전 값이 반환됩니다.

2. 관찰되는 증상

시작 코드는 컴파일되고 모든 쓰기를 저장합니다. 그러나 두 읽기 포트는 매번 바로 앞 명령어가 지정한 레지스터의 값을 반환합니다.

읽기 포트가 한 사이클 늦게 응답하는 원인을 찾아, 두 포트가 요청한 사이클에 응답하도록 고치세요. 포트와 쓰기 로직은 그대로 둡니다.

3. 실행 전 예측

테스트벤치는 레지스터 r에 10 * r + 1을 씁니다. 따라서 r3은 31, r5는 51입니다. 그다음 사이클마다 피연산자 쌍 하나를 제시합니다. 순서는 (3, 5), (0, 7), (2, 2), (6, 1), (6, 1)입니다.

올바른 레지스터 파일의 rdataA, rdataB 열을 먼저 적어 보세요. 시작 코드를 실행한 뒤 두 결과를 줄마다 비교하세요. 시작 코드가 예측과 일치하는 줄은 하나뿐입니다. 그 줄의 주소에 어떤 특징이 있는지 확인해 보세요.

4. 원인 진단

출력 데이터가 항상 바로 앞 줄에서 제시한 주소의 값이라면, 읽기 포트가 주소를 레지스터에 저장한 뒤 읽는다는 뜻입니다. 시작 코드에서 이런 읽기 타이밍을 가진 메모리 타입을 찾아보세요. 그다음 쓰기 동작은 같고 같은 사이클에 데이터를 반환하는 메모리 타입을 정하세요.

5. 실행 결과 해석

메모리 타입을 바꾸고 다시 실행해 보세요. 모든 줄에서 두 포트가 지정한 레지스터의 10 * r + 1 값이 출력되어야 합니다. 두 포트가 모두 r2를 읽는 줄도 마찬가지입니다. 시작 코드에서 마지막 줄만 맞았던 이유와, 수정 후에는 그 줄이 더 이상 특별하지 않은 이유를 설명해 보세요.

6. 완료 조건

  • 두 포트는 레지스터 번호가 제시된 사이클에 현재 내용을 반환합니다. 두 포트가 같은 레지스터를 읽는 경우도 포함합니다.
  • 쓰기는 클록 에지 다음 사이클부터 보입니다. 쓰기 사이클에 같은 레지스터를 읽으면 이전 값이 반환됩니다.
  • 같은 사이클의 읽기와 쓰기는 다른 레지스터에 영향을 주지 않습니다.
  • 공개 피연산자 쌍에만 맞춘다고 완료되지 않습니다. 실제 사용에서는 피연산자 쌍이 매 사이클 바뀝니다.

7. 힌트

힌트 1

마지막 줄은 바로 앞 쌍을 반복합니다. 한 사이클 늦은 포트도 주소가 바뀌지 않으면 올바르게 보입니다.

힌트 2

메모리 장은 쓰기 포트가 같고 읽기 지연만 다른 읽기/쓰기 메모리 두 가지를 비교합니다. 레지스터 파일에는 조합 읽기를 하는 쪽이 필요합니다.

개념 설명

메모리 타입은 저장 방식이면서 타이밍 계약입니다. 동기 읽기 메모리는 SRAM으로 구현될 수 있지만 데이터가 한 사이클 늦게 출력됩니다. 같은 사이클에 데이터를 사용하는 로직에는 조합 읽기 메모리가 필요합니다. 이 레지스터 파일에는 64비트의 저장 공간과 읽을 값을 선택하는 로직이 필요하며, 실제 구현은 합성 대상에 따라 달라집니다.

8. 추가 실험

decode가 두 사이클로 나뉘어 레지스터 번호를 한 사이클 먼저 알 수 있다고 가정해 보세요. 이 경우 시작 코드의 메모리가 올바른지, 그리고 디코더의 어떤 신호가 읽기 주소를 구동해야 하는지 예측해 보세요.

개념 다시 보기
준비

CheerpJ로 브라우저에서 실행합니다. 첫 실행에는 Java 약 14.5 MB와 JAR 약 47 MB를 내려받습니다. 컴파일에 1분 정도 걸릴 수 있습니다. 라이선스

Main.scala