본문으로 건너뛰기
code0.HDL

13구현 문제

FIFO가 채워진 정도를 추적하게 하기

문제

의도한 동작. sync_fifo는 WIDTH비트 워드를 최대 DEPTH개까지 들어온 순서대로 담습니다. 상승 에지마다 push는 din을 저장된 워드들 뒤에 쓰고, pop은 가장 오래된 워드를 꺼냅니다. FIFO가 비어 있지 않은 동안 dout에는 늘 가장 오래된 워드가 보입니다. count는 저장된 워드의 수이고, full은 count가 DEPTH와 같을 때만, empty는 count가 0일 때만 1입니다. 가득 찼을 때의 push와 비었을 때의 pop은 무시합니다. 같은 에지에 둘이 함께 오면 허용되는 쪽은 모두 적용되므로, 한 워드가 들어오고 한 워드가 나가면 count는 그대로입니다. 리셋은 동기식 active-high이며 FIFO를 비웁니다.

현재 동작. 저장 공간과 두 포인터는 이미 동작하고, do_push와 do_pop도 full과 empty를 확인합니다. 그런데 count는 바뀌지 않고 두 플래그는 0에 묶여 있습니다. 공개 출력에서 count는 계속 0이고, 리셋 직후에도 empty가 0입니다. 0번 사이클의 pop이 빈 FIFO의 읽기 포인터를 옮기는 바람에 나중에 dout에 10 대신 20이 보이고, 5번과 6번 사이클의 50, 60 push는 10과 20을 덮어씁니다.

할 일. TODO 두 곳, 곧 클록 블록 안의 count 갱신과 두 플래그 대입을 채우세요. 저장 공간, 포인터, do_push, do_pop, 포트, 파라미터, 공개 테스트벤치는 그대로 둡니다.

먼저 출력을 예측하세요

출력 한 줄은 한 사이클입니다. 그 사이클 동안 넣은 입력과, 사이클을 끝내는 상승 에지 전에 보이는 출력이 적혀 있으므로, n번 사이클의 push는 n + 1번 사이클의 count에 나타납니다. 고치기 전에 DEPTH = 4인 올바른 FIFO의 count, full, empty를 열세 사이클 모두 적어 보세요.

  • full이 처음 1이 되는 사이클은 언제이고, 50과 60의 push는 어떻게 될까요?
  • 6번 사이클에서는 FIFO가 가득 찬 채로 push와 pop이 모두 1입니다. 7번 사이클의 count는 얼마일까요?
  • 11번 사이클에서는 FIFO가 빈 채로 둘 다 1입니다. 어느 쪽이 적용될까요?

고치고, 실행하고, 확인하세요

고친 코드를 실행해 적어 둔 표와 한 줄씩 비교하세요. 그다음 파형을 열어 봅니다. count는 상승 에지에서만 바뀌어야 합니다. full과 empty는 한 사이클 늦지 않게 갱신된 count를 반영해야 하며, 각각 가득 찬 상태나 빈 상태에 들어가거나 벗어날 때만 바뀝니다. empty가 1인 동안 dout에 예전 값이 보일 수 있지만, 그때의 dout에 기대는 회로는 없어야 합니다.

완료 조건

  • push와 pop이 함께 올 때, 가득 찼을 때, 비었을 때를 포함해 count는 늘 저장된 워드 수와 같습니다.
  • full과 empty는 같은 사이클에 count를 따릅니다.
  • dout은 push한 순서대로 워드를 돌려주며, 잃어버리거나 두 번 나오는 워드가 없습니다.
  • 양수인 WIDTH와 1부터 16까지의 DEPTH에서 동작합니다. 깊이는 2의 거듭제곱이 아니어도 됩니다. 기존 4비트 포인터 때문에 깊이는 최대 16이며, 추가하는 논리에서 깊이가 4라고 가정하면 안 됩니다.
  • 가득 찬 상태에서도 리셋은 FIFO를 비웁니다.

단계별 힌트

힌트 1

이 에지에서 count가 바뀌는 양은 실제로 들어온 워드 수에서 실제로 나간 워드 수를 뺀 값입니다. 설계에는 이미 "워드가 실제로 들어옴"과 "워드가 실제로 나감"을 가리키는 이름이 있습니다.

힌트 2

do_push와 do_pop은 1비트 값이고 같은 에지에 둘 다 1일 수 있습니다. 하나를 더하고 다른 하나를 빼는 대입 한 줄이면 네 가지 조합을 모두 처리합니다.

힌트 3

두 플래그는 count를 파라미터나 상수와 비교하는 식으로 쓰세요. DEPTH - 1과 비교하면 워드 하나가 모자란 상태에서 가득 찼다고 알리고, 숫자 4와 비교하면 다른 깊이에서 모두 틀립니다.

응용 실험

count를 저장하지 않고 포인터로 계산하도록 바꿔 봅니다. wr_ptr와 rd_ptr는 그대로 두고 full = (wr_ptr == rd_ptr)를 시도해 보세요. 먼저 이 식이 가득 찬 FIFO와 빈 FIFO를 왜 구분하지 못하는지 예측하고, 두 상태가 같은 포인터 값을 갖는 사이클을 파형에서 찾아보세요. 포인터마다 한 비트를 더하는 방법이나 방금 쓴 count가 무엇을 더해 주는지 설명해 보세요.

개념 다시 보기
준비
Main.v