while(1) work();
반응형
본 게시글은 KUEE 정보공개 프로젝트에 포함된 글입니다.
https://blog.youhogeon.com/65

본 자료의 저작권은 모두 저에게 있으며
학업에 참고 자료로만 사용하시길 바랍니다.
부득이하게 인용해야 하는 경우 반드시 출처(KUEE 정보공개 프로젝트)와 링크를 남겨주시길 바랍니다.

p1.pdf
1.37MB
src.zip
0.59MB

 

VLSI 설계 및 실험보고서 Project 1 # Overview 1. Interleaver 물리적인 통신 과정에서 신호를 전송할 때 오류가 발생하여 데이터가 유실되는 경우가 발생할 수 있다. 이러한 오류가 연속적인 비트 상에서 발생하게되면, 수신측에서 FEC를 통해 오류를 정정하는데 어려움이 생긴다. 따라서 오류가 발생한 비트가 연속적이지 않고 퍼져있도록 하기 위해 송신측에서는 Interleaving 과정을 통해 비트를 분산시킨(섞은) 데이터를 전송한다. 비트를 무작위로 섞게 되면 원본 데이터 자체가 손실되므로, 송수신측간에 합의한 특정한 규칙에 따라 비트를 분산시킨다. 2. De-interleaver Interleaved된 데이터를 수신측이 수신하면 de-interleaving 과정을 통해 원본 데이터를 복원한다. De-interleaving은 interleaving의 역과정을 통해 수행된다. 만약 통신 과정에서 연속적인 비트 오류가 발생하였다면, de-interleaving 과정을 통해 오류 비트들은 데이터 전역에 골고루 퍼지게 되며 FEC 알고리즘을 이용해 비트 오류를 복구해낼 수 있다. 3. Project Introduction 본 프로젝트에서는 interleaving된 데이터를 de-interleaving시키는 de-interleaver를 구현할 것이다. 데이터는 총 8개의 branch로 나누어져 있으며 각각의 branch의 데이터를 분산시키는 규칙은 위 사진과 같다. 각 branch는 12bit의 symbol을 1536개 가지고 있다. 더불어, 이러한 데이터가 symbol단위로 실시간으로 수신되어 de-interleaver로 입력된다고 가정한다. 총 symbol의 갯수가 (8 branch) * (1536 symbol / branch) = 12288 symbol 이고 각 symbol은 12개의 비트로 이루어져있으므로, 12888x12 메모리 한개를 이용해 본 프로젝트를 구현할 수 있다. 먼저 de-interleaver에 symbol이 입력되면 순차적으로 메모리에 저장한다. 메모리가 가득 차면 de-interleaving 규칙에 따라 데이터를 순차적으로 꺼내 출력하며 해당 메모리 셀에는 새로 입력된 symbol을 저장한다. 이러한 과정을 반복하면 이론적으로 12288 symbol만큼의 latency를 가지고 de-interleaving된 데이터를 실시간 출력하는 de-interleaver를 구현할 수 있다. # Implementation 1. Wires & Registers 이름 구분 크기 목적 data_out output 12bit de-interleaving된 symbol 출력 data_in input interleaving된 symbol 입력 in_enable 1bit symbol 입력 여부 전달 clk 클럭 reset reset 신호 본 프로젝트에 사용된 I/O 포트는 위와 같다. 이름 구분 크기 목적 mem_in wire 12bit 메모리에 입력을 위해 flip-flop을 거친 data_in mem_out 메모리의 출력(flip-flop을 거쳐 data_out으로 나옴) d_in_enable 1bit in_enable신호 두 클럭 지연 dd_in_enable counter reg 15bit 클럭마다 증가하는 카운터 cycle 3bit 12288 symbol마다 증가하는 카운터 addr 12bit 메모리 주소 계산을 위한 레지스터 const[7][7] 각 11bit 메모리 주소 계산을 위한 상수를 담은 레지스터 본 프로젝트에 사용된 wire와 register는 위와 같다. counter, cycle, addr, const 레지스터는 메모리 주소를 계산하기 위해 사용되며, 자세한 설명은 아래 [2. Memory Address]에 후술하였다. 2. Memory Address 초기 12288 symbol이 입력되는 동안 메모리에는 순차적으로 symbol들이 저장된다. 이후에는 de-interleaving을 위해 규칙에 따라 데이터를 순차적으로 꺼내 출력하며 해당 메모리 셀에는 새로 입력된 symbol을 저장한다. 이러한 과정을 위해 다음에 사용할 메모리 주소를 계산하는 로직이 필요하다. 먼저, 두 클럭마다 새로운 symbol이 입력되기 때문에(한 클럭동안은 메모리를 출력하고, 다음 한 클럭동안은 메모리에 입력되기 때문에) counter의 LSB를 제외한 나머지 비트를 사용함으로써 2 cycle마다 증가하는 counter를 얻는다. counter의 LSB는 메모리의 NWRT 신호로 사용할 수도 있으나, 본 프로젝트에서는 in_enable신호가 별도로 존재하기 때문에 !in_enable신호를 메모리의 NWRT 신호로 사용한다. 또한, counter[3:1]을 통해 0부터 7까지의 branch 번호를 순차적으로 얻을 수 있고, counter[14:4] 를 각 branch별 sequence(0~ 1535)로 간주하여 메모리 주소 구조를 설계할 수 있다. 12288 symbol을 한 cycle이라고 정의하고 de-interleaving 규칙에서 사용되는 값들을 고윳값(0, 768, 1152, 384, 1344, 192, 960, 576)이라고 정의한다면, 각 branch상에서 저장된 데이터의 시작점(branch의 0번째 symbol의 sequence)은 아래와 같이 구할 수 있다. 시작점     고윳값  이 값은 계산하면 아래 표와 같고, 8 cycle마다 반복됨을 확인할 수 있다. 따라서 cycle 카운터는 3bit으로 구현 가능하며, 12288 symbol이 입력될 때 마다 cycle 카운터를 증가시키고 counter를 초기화한다. Branch 번호가 counter[3:1]이고 각 branch의 시작점은 위 수식과 같으므로 매 클럭마다(혹은 두 클럭마다) 접근해야 하는 메모리 address는 아래와 같이 구할 수 있다. 그러나 address를 구하기 위해 multiplier를 사용하는 것은 비효율적이다. 또한 mod operator 역시 간단한 게이트들로 대체할 수 있다. address = {   고윳값       ,    } 1) 먼저, mutiplier의 첫 번째 피연산자인 cycle no가 0~7로 제한되고, 두 번째 피연산자인 고윳값 역시 8가지 뿐이므로 64개의 값을 미리 계산한 상수를 사용함으로써 multiplier를 대체할 수 있다. 이 상수값들은 위에서 계산한 시작점들을 나타낸 표와 같다. 따라서 매 클럭마다(혹은 두 클럭마다) 접근해야 하는 메모리 address는 아래와 같이 단순화된다. Branch ID가 counter[3:1]이므로 아래 두 식은 동일하다. address = {   에 따른 상수값       ,    } address = {    에 따른 상수값       ,    } 상수값의 범위는 0 ~ 1344로 제한되고 counter는 12288 symbol마다 초기화되므로 counter[14:4]의 범위는 0 ~ 1535으로 제한된다. 따라서 두 값의 합의 최댓값은 2879이며 이는 3072(1536 * 2) 보다 작다. 따라서 mod operator 대신 상수값     이 1536보다 크다면 1536을 빼주는 로직을 사용할 수 있다. 1536은 이진수 표현으로 11’b11000000000이고 피연산자의 최댓값이 12bit이기 때문에, 1536보다 크다면 1536을 빼주는 로직은 몇 개의 게이트들로 단순화시킬 수 있다. 피연산자 만약 1536보다 크다면 1536을 뺀 값 000x xxxx xxxx 000x xxxx xxxx 001x xxxx xxxx 001x xxxx xxxx 010x xxxx xxxx 010x xxxx xxxx 011x xxxx xxxx 000x xxxx xxxx 100x xxxx xxxx 001x xxxx xxxx 101x xxxx xxxx 010x xxxx xxxx 110x xxxx xxxx 피연산자 최댓값이 2879 = 1011 0011 1111이므로 불가능 111x xxxx xxxx 위 표와 같이 피연산자의 값에 따라 1536보다 크다면 1536을 빼준 값을 알 수 있다. 피연산자의 MSB를 A, MSB-1를 B, MSB-2를 C라고 하고, 계산된 값의 MSB를 A`, MSB-1를 B`, MSB-2를 C`라고 한다면 카르노 맵 등의 기법을 이용해 아래와 같은 식을 구할 수 있다. ′   ′      ′     따라서 피연산자를 x[11:0], 결과값을 y[10:0]이라고 한다면 1536보다 크다면 1536을 빼주는 로직은 아래 회로와 같이 별도의 adder 없이 몇 개의 gate로 구현할 수 있다. 1) { }는 verilog의 bit concatenate 연산자 3. Memory Structure [2. Memory Address]에 설명한 방식과 같이 메모리의 address를 계산하게 되면 아래와 같이 메모리에 symbol들이 저장된다. 표의 row를 하위비트로 나타냈기 때문에 아래의 표들의 값은 위에서 아래로 읽어야 메모리에 저장된 순서와 같다. 먼저 첫 번째 cycle이 끝나면(12288 symbol의 입력이 들어오고 나면) 메모리에는 위과 같이 입력이 들어온 순서대로 값이 저장된다. 각 branch의 0번째 symbol부터 값을 읽어야 하므로 [2. Memory Address]에서 만든 address 계산식을 이용해 메모리에서 순서대로 값을 출력하고, 두 번째 cycle에서 들어온 값을 해당 자리에 저장한다. 즉 메모리를 읽고 다시 쓰는 순서(address 계산식의 계산 결과)는 아래와 같다. {11’d0, 3’b000}, {11’d768, 3’b001}, {11’d1152, 3’b010}, {11’d384, 3’b011}, {11’d1344, 3’b100}, {11’d192, 3’b101}, {11’d960, 3’b110}, {11’d576, 3’b111}, {11’d1, 3’b000}, ... {11’d575, 3’b111} 다시 한 cycle이 지나는 동안 위와 같은 순서로 메모리의 값이 변경된다. 두 번째 cycle이 끝나고 난 뒤의 메모리 구조는 위의 표와 같다. [2. Memory Address]에서 각 branch의 시작점(0번 symbol이 오는 위치)를 구한 표를 이용해 메모리 구조를 파악할 수 있다. 예를 들어 시작점 표에서 cycle이 2일 때 6번 branch의 시작점은 384이므로, 6번 branch의 0번 symbol(f0)은 {11’d384, 3’b101}에 위치하게 될 것이다. 또 다시 한 cycle이 지나서 세 번째 cycle이 끝나게 되었을 때 메모리 구조는 위와 같다. 이후 cycle에 대한 메모리 구조는 아래 표에 나타내었으며 역시 같은 규칙으로 값이 저장된다. 여덟 개의 cycle이 지나면 메모리 구조는 다시 초기 메모리 구조와 같아진다. 4. Expected Timing Diagram 두 cycle 동안의 expected timing diagram은 위와 같다. 한 cycle이 지나고 입출력 latency가 지나면 첫 번째 cycle의 입력이 de-interleaving되어 출력되기 시작한다. 5. Expected Block Diagram 구현한 verilog 코드를 통해 synthesize 결과는 위와 같은 block diagram이 될 것으로 예측할 수 있다. Gates for check if counter=24576 으로 표시된 회로는 cycle 레지스터 값을 증가시키기 위해 counter 값이 24576인지 확인하는 회로이며, const 레지스터는 cycle 값과 counter[3:1] 값을 통해 상수를 결정할 수 있다. 상수값이 결정되면 counter[14:4]와 상수값을 더함으로써 address(혹은 address 보다 1536 큰 값)가 생성되며, 이는 [2. Memory Address]에서 설명한 gates for conditional substract 회로를 통해 address값으로 변환된다. 이 회로는 [2. Memory Address]의 사진과 같으므로 black box로 도식화하였다. 마지막으로 address가 결정되면 메모리에 address값을 입력함으로써 메모리의 적절한 위치에 있는 데이터를 출력하고, 해당 위치에 새로 들어온 데이터를 쓸 수 있다. 위 문단에서 설명한 path가 가장 시간이 많이 소요될 것으로 예상되므로, critical path가 될 것으로 추측할 수 있다. # Results 1. Timing Diagram 구현한 de-interleaver의 동작을 테스트하기 위해 테스트벤치 코드를 이용해 파형을 확인하였다. 사전에 주어진 총 86016개(7 cycle * 1536 symbol/branch * 8 branch/cycle)의 input/output data를 이용해 정상 동작 여부를 확인한 결과 모든 vector data가 구현한 de-interleaver의 출력과 파형이 일치하였다. 따라서 회로가 올바르게 동작함을 확인할 수 있었다. 더불어, 첫 번째 cycle(cycle = 0)에서는 아무런 출력이 나오지 않다가, 두 번째 cycle(cycle = 1)에서부터 메모리의 값이 출력되기 시작하였고, 실시간 입력이 종료되고 나서(cycle = 7) 마지막 cycle의 출력이 나타남을 확인할 수 있었다. 첫 출력의 초반부와 마지막 출력의 후반부는 위 사진과 같았다. 첫 입력으로부터 첫 출력까지 아래와 같은 latency를 가짐을 확인할 수 있었다. 이 중 1.5 symbol(3 cycle)의 latency는 메모리의 latency와 메모리 입출력단의 flip-flop으로 인해 발생하였다. 1 cycle + 1.5 symbol = 24579 clock 2. Synthesize result & Critical Path 합성 후 de-interleaver의 block diagram은 위와 같았다. Counter 레지스터에 1을 증가시킨 뒤 다시 상수값을 더하고 [#Implementation > 2. Memory Address]에서 설명한 조건부 뺄셈을 하는 경로가 critical path임을 확인할 수 있었다. Counter값이 24576이면 counter를 초기화하고 cycle을 증가시키는 회로는 critical path에 포함되지 않았다. 이는 몇 개의 gate로 비교 연산을 할 수 있고, 하나의 adder로 cycle 값을 증가시킬 수 있기 때문에, 두 개의 adder를 사용하는 critical path보다 연산 속도가 빠르기 때문이다. 더불어, 조건부 뺄셈을 gate level로 구현했을 때와 behavior level로 구현했을 때 synthesize 결과는 매우 유사하였다. 따라서 본 보고서에는 가독성이 좋은 behavior level 코드를 첨부하였다. 3. Timing Report 클럭 주기를 초기에 6.0ns로 설정 후 점차 낮추어가며 회로가 동작할 수 있는 가장 빠른 클럭을 찾아보았다. 각 클럭 주기에 대한 slack값과 state는 아래와 같았다. 클럭 주기(ns) Data required time(ns) Slack State 6.0 5.57 0.32 MET 5.0 4.57 0.00 MET 4.5 4.07 0.00 MET 4.3 3.95 0.00 MET 4.1 3.78 0.00 MET 4.0 3.69 0.00 MET 3.9 3.58 -0.03 VIOLATED 따라서 본 회로가 동작할 수 있는 가장 낮은 클럭 주기는 4.0ns이고, 약 250MHz의 클럭에서 가장 빠르게 작동할 수 있다는 것을 확인할 수 있었다. 이 때의 timing report는 아래와 같았다. Timing report에 따르면 본 회로의 critical path는 - - - 이다. 이는 [2. Synthesize Result & Critical Path]에서 확인한 바와 유사하였다. 4. Area Report & Power Report 메모리를 제외한 본 회로의 total cell area는 19616.27μm², total dynamic power는 4.8577mW임을 알 수 있었다.

반응형
profile

while(1) work();

@유호건

❤️댓글은 언제나 힘이 됩니다❤️ 궁금한 점이나 잘못된 내용이 있다면 댓글로 남겨주세요.

검색 태그