본문으로 건너뛰기
code0.HDL

27구현 문제

trigger를 3 사이클 펄스로 늘리기

1. 요구 동작

PulseStretch는 trigger를 3 사이클 이상의 펄스로 늘립니다. count는 out이 앞으로 몇 사이클 더 1이어야 하는지 저장하고, out은 count가 0이 아니면 1입니다.

에지에서의 입력에지 뒤의 count
trig = 13
trig = 0, count ≠ 0count - 1
trig = 0, count = 00

1 사이클 trigger는 그 에지 뒤 3 사이클 동안 out을 1로 만듭니다. 펄스 도중 새 trigger가 들어오면 3 사이클을 처음부터 다시 셉니다. 리셋은 count를 0으로 만듭니다.

2. 관찰되는 증상

시작 코드는 count를 선언만 하고 갱신하지 않습니다. 그래서 out이 한 번도 1이 되지 않습니다.

TODO 줄을 count 갱신 로직으로 바꾸세요. 포트, count 선언, out 줄, 공개 테스트벤치는 그대로 둡니다.

3. 실행 전 예측

공개 테스트벤치는 expect로 설계를 검사하고, expect마다 시나리오를 설명하는 메시지를 붙입니다. 테스트벤치는 FailedExpectException을 잡아 메시지를 FAILED 줄로 출력합니다. 따라서 검사가 실패해도 실행은 정상 종료되고, 처음 실패한 expect가 출력에 남습니다. 모든 검사를 통과하면 시나리오마다 PASS 줄이 하나씩 나옵니다.

실행하기 전에 poke와 step이 끝날 때마다 trig, count, out을 표로 적고 다음 질문에 답해 보세요.

  • trig를 poke한 직후, step 전에는 왜 out이 아직 0이어야 할까요?
  • 재trigger 시나리오에서 두 번째 trigger가 에지를 만날 때 첫 펄스는 몇 사이클 남아 있을까요?

그다음 시작 코드를 실행하고 FAILED 줄을 읽어 보세요.

4. 원인 진단

FAILED 줄의 메시지는 테스트벤치 장에서 본 형식과 같습니다. step 번호, 포트 이름, 실제 값과 기대값, 시나리오 메시지가 차례로 나옵니다. step 번호는 테스트 본문이 시작된 뒤의 클록 step 수이므로 표의 한 행을 가리킵니다.

갱신 로직을 작성한 뒤 다시 실행하세요. 실패 위치가 뒤쪽 step으로 옮겨 가면 그 앞의 시나리오는 통과한 것입니다. 새 메시지는 재trigger처럼 아직 틀린 시나리오를 가리킵니다.

5. 완료 조건

  • 1 사이클 trigger는 trigger를 받은 에지부터 정확히 3 사이클 동안 out을 1로 만듭니다.
  • out이 1인 동안 들어온 trigger는 남은 사이클이 1이든 2이든 3 사이클을 다시 시작합니다.
  • 여러 사이클 동안 유지된 trigger는 out을 계속 1로 두고, 마지막 에지 뒤 3 사이클이 이어집니다.
  • count는 0 아래로 순환하지 않고, 동기 리셋은 다음 상승 에지에서 펄스를 끝냅니다.

6. 힌트

힌트 1

규칙을 우선순위가 있는 두 경우, 곧 trig가 있는 에지와 나머지 에지로 나눠 보세요. 두 번째 경우에는 별도의 조건이 하나 더 있습니다.

힌트 2

when과 .elsewhen을 쓰세요. 감소에는 count가 이미 0이 아닌지 확인하는 조건이 필요합니다. 이 조건이 없으면 2비트 레지스터가 3으로 순환합니다.

개념 설명

메시지가 있는 expect는 불일치를 step, 포트, 값, 시나리오가 담긴 보고로 바꿉니다. println으로만 출력한 틀린 값은 사람이 읽고 발견해야 합니다. 반면 expect가 잡은 틀린 값은 그 값이 처음 나타난 사이클에서 테스트를 멈춥니다.

7. 추가 실험

첫 펄스가 1 사이클만 남았을 때 두 번째 trigger가 들어오도록 테스트벤치를 한 step 늦춰 보세요. 첫 trigger의 에지부터 out이 모두 몇 사이클 동안 1인지 예측하고, 실행해 확인해 보세요.

개념 다시 보기
준비

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

Main.scala