03구현 문제
누적과 전달을 두 단계로 나누기
1. 목표와 수정 범위
mkRuleOrder는 1, 2, 3, 4를 accumulator에 더한 뒤 완성된 합 10을 result로 정확히 한
번 옮겨야 합니다. 수집은 fill rule이, 전달은 drain rule이 맡습니다.
수정 대상은 TODO 아래 drain의 준비 조건 하나입니다. 두 rule의 본문, 레지스터
선언, method, mkTop은 그대로 두세요. 우선순위 어트리뷰트나 새 레지스터도 추가하지
않습니다.
2. 시작 코드 읽기
mkRuleOrder의 레지스터 다섯 개는 다음 역할을 합니다.
| 레지스터 | 역할 |
|---|---|
accumulator | 아직 전달하지 않은 누적값 |
result | emitted method가 반환하는 값 |
taken | 다음에 더할 항을 고르는 순번 |
collecting | 수집 단계이면 참 |
drained | 전달을 이미 했으면 참 |
시작 코드에서 fill과 drain의 준비 조건은 똑같이 collecting입니다. 두 rule은 같은
사이클에 함께 활성화됩니다. 두 rule 모두 accumulator를 읽고 쓰므로, 어느 쪽을 먼저
배치해도 다른 쪽의 읽기가 쓰기 뒤에 놓입니다. 따라서 같은 사이클에 함께 실행될 수 없습니다.
실행의 컴파일 단계에서는 fill을 우선 처리했다는 G0010 경고와, 생성된 schedule에서
drain이 실행될 수 없다는 G0021 경고가 출력됩니다.
3. 수정 전 결과 예측하기
실행하기 전에 다음 표를 예측하고, 수정 전 코드를 한 번 실행해 비교해 보세요.
| Cycle | total | emitted | filling | 상태 |
|---|---|---|---|---|
| 0 | 0 | 0 | 1 | 1을 더할 차례 |
| 1 | 1 | 0 | 1 | 2를 더할 차례 |
| 2 | 3 | 0 | 1 | 3을 더할 차례 |
| 3 | 6 | 0 | 1 | 4를 더하고 수집 종료 |
| 4 | 10 | 0 | 0 | 합은 완성됐지만 전달되지 않음 |
| 5 이후 | 10 | 0 | 0 | 상태 변화 없음 |
사이클을 더 기다려도 10은 전달되지 않습니다. collecting이 거짓이 되면 시작 코드의 두
준비 조건이 모두 거짓이 되기 때문입니다.
4. 단계 전환을 조건으로 표현하기
accumulator를 쓰는 시점을 두 단계로 나누세요. 수집 중에는 fill만 실행되고, 수집이
끝난 뒤에는 drain이 정확히 한 번 실행되어야 합니다.
drain의 준비 조건은 기존 상태로 두 사실을 함께 확인해야 합니다. 하나는 수집 단계가
끝났다는 사실이고, 다른 하나는 전달 기회가 아직 남아 있다는 사실입니다. 각 사실에
해당하는 레지스터가 그때 가져야 할 Boolean 값을 먼저 정한 뒤 조건식을 작성해 보세요.
채점은 조건식의 표기가 아니라 관찰되는 동작을 확인하므로 동등한 조건식도 허용됩니다.
5. 수정 후 실행 결과 해석하기
수정한 코드를 실행하고 cycle 4와 5를 확인해 보세요.
- cycle 4에서는 네 번째 덧셈이 반영되어
total이 10이고filling이 0입니다. - 이 사이클에
drain이 10을result에, 0을accumulator에 예약합니다. - 예약된 쓰기는 클록 에지에서 반영됩니다. 따라서 cycle 5에는
total이 0,emitted가 10으로 출력됩니다. drained가 참이 되므로 이후drain은 다시 실행되지 않습니다. 빈 누적값 0이 이미 전달한 10을 덮어쓰지 않습니다.
두 rule이 더 이상 accumulator를 두고 충돌하지 않는 이유와, drain이 완성된 합을
읽는 이유를 직접 설명해 보세요.
6. 완료 조건
- 누적값은 0, 1, 3, 6, 10 순서로 변합니다.
- 수집 중에는
drain이 실행되지 않습니다. - 수집이 끝난 뒤 전달은 한 번만 일어납니다.
- 전달 뒤
total은 0,emitted는 10입니다. - 이후 사이클에서도
emitted는 10을 유지합니다.
7. 단계형 힌트
힌트 1 — 단계 구분
drain은 fill이 실행되는 단계와 반대인 단계에서만 준비되어야 합니다.
힌트 2 — 한 번만 전달
반대 단계만 검사하면 전달이 여러 번 일어날 수 있습니다. 전달을 이미 했는지 기록하는 레지스터도 함께 검사하세요.
개념 설명
컴파일러는 각 rule의 조건과 읽고 쓰는 상태로 schedule을 만듭니다. 두 rule이 서로
상대가 쓰는 값을 읽으면 충돌하고, 한쪽은 그 사이클에서 제외됩니다. 같은 레지스터에 쓰기만
하는 두 rule은 함께 실행될 수 있으며, schedule 순서가 뒤인 쓰기가 남고 bsc가 덮인 쓰기를
경고합니다. 두 조건이 동시에 참이 될 수 없으면 충돌도 사라집니다.
8. 추가 실험
필수 수정을 확인한 뒤 accumulator의 초기값을 8로 바꾼다고 가정해 보세요. 누적값은 8,
9, 11, 14, 18로 변하고, 전달 뒤에는 total이 0, emitted가 18이어야 합니다. 이 실험으로
구현이 10을 고정해서 내보내지 않고 실제 누적값을 전달하는지 확인할 수 있습니다.