Ring Buffer를 Verilog로 설계해보았다.
그냥 FIFO를 사용해도 되겠지만 이럴 경우 clock이 뛸 때 마다 항상 shift를 해줘야하기 때문에 Energy Efficiency측면에서 좋지 않다. 따라서 현재 어느 위치를 가리키고 있는지 그리고 다음 Clock에서 명령어에 따라 그 위치에 대한 Data를 출력 혹은 입력을 진행하고 다음 위치를 가리키는 것이 더 효율적일 것이다.
위치를 가리키는 또다른 레지스터를 선언해야하기 때문에 Area가 커진다는 단점이 있을 수 있지만 만약 Buffer사이즈가 많이 크다면 포인터를 가리키는 레지스터의 크기는 Buffer사이즈의 log2값을 따르기 때문에 충분히 Trade-Off가 가능하다고 볼 수 있다.
안정적인 동작을 위해서 FSM으로 설계해보도록 하겠다. 내가 설계한 Ring Buffer의 FSM은 다음과 같다.
S0: Buffer가 빈 상태
S1: Buffer에 내용물이 있지만 꽉 차진 않은 상태
S2: Buffer가 꽉 찬 상태
이때 S1의 조건인 ptr_W + 1 != ptr_R을 살펴보면 합성시에 ptr_W+1에서 Adder가 생성될 것이다. 이럴 경우 Area의 크기가 커질 것이다. 예를들어 ptr의 size가 4라고 가정해보자.
Full Adder에 필요한 트랜지스터의 개수: 28개
Half Adder에 필요한 트랜지스터의 개수: 14개
총 28 * 2 + 14 = 70개 필요
비교기에 필요한 AND 게이트 6개
각각의 AND게이트에 들어가는 트랜지스터 6개
총 36개 필요
(NAND를 활용하면 더 적게 소요할 수 있을 것 같긴하지만 뒤에 설명할 새로운 비교기에 비하면 크게 영향 없을 듯)
전체 트랜지스터는 70 + 36 = 106개가 필요하다. 반면 다음과 같이 비교기를 설정해보자.
ptr의 사이즈를 log2(BUFFER_SIZE)+1로 설정하면 다음과 같이 기존 버퍼보다 2배 큰 가상의 버퍼의 위치를 가리킬 수 있다.
ptr_W + 1 값과 ptr_R값이 같다는 것은 Virtual Buffer상에서 서로 가리키고 있는 값이 buffer size만큼 차이가 난다는 것이다. 그리고 가리키는 값을 2진수로 나타내면 서로의 MSB만 다르고 나머지 값은 같은 것을 확인할 수 있다. 이를 활용한 비교기는 2번째 그림과 같다.
결국 전가산기 필요없이 비교기만 설계하면 된다. 비교기 설계에 필요한 트랜지스터는 6 * 6 + 8 = 44개이다.
필요한 트랜지스터의 양이 절반도 안되게 줄어든다. 물론 실제로 이를 설계할 때에는 PMOS와 NMOS의 모빌리티를 고려한 W를 설정하여 정확한 Area을 계산해야할 것이다. 하지만 그렇게 계산 하더라도 가산기를 뺀 비교기는 훨씬 더 Area를 적게 차지할 것이다.
이를 반영한 Ring Buffer의 Verilog코드와 Test Bench는 다음과 같다.