2024년 8월 10일 토요일

"Verilog-Verilator-SystemC 방법론 기초" [5] 실습: FIR 필터

"Verilog-Verilator-SystemC 방법론 기초"
[5] 실습: FIR 필터

[알림] 아래 내용중 질문, 지적, 보강 등 어떤 사항도 환영 합니다.

"Verilog-Verilator-SystemC 방법론 기초"는 "내 칩(My Chip) MPW 서비스": 오픈-소스 도구 활용 반도체 설계 특별과정 중 두번째 강좌로서 베릴로그(Verilog)와 오픈-소스 시뮬레이션 도구 Verilator 그리고 시스템 수준 검증 방법론 SystemC의 입문 과정이다. 컴퓨팅 언어를 활용한 디지털 회로의 설계와 검증을 다룬다(Quantative approach to digital circuit design using computing language and Open-Source EDA tools).

강의 내용은 아래와 같다.

[1] 도구 설치 [링크]
[2] 설계 언어 Verilog 와 검증 언어 SystemC/C++[링크]
[3] 하드웨어 기술 언어의 코딩 스타일[링크]
[4] 실습: 쉬프트 레지스터 [링크]
[5] 실습: FIR 필터 [링크]
[6] "내 칩 MPW" 요건에 맞춘 FIR 필터의 PE 설계[링크]

[부록] FIR 필터 PE의 "내 칩MPW" 제출용 GDS 생성[링크]

----------------------------------------------------------

목차

I. 개요

II. 시스템 사양(System Specification)
    II-1. FIR 필터 알고리즘(FIR filter algorithm)
    II-2. FIR 필터 계수 구하기(FIR filter design)
    II-3. FIR 필터의 언-타임드 C++ 코드(Un-Timed C++ code)
    II-4. FIR 필터의 언- 타임드 C++ 테스트 벤치(Un-Timed C++ testbench)
    II-5. 실습. FIR 알고리즘의 시험(Lab. FIR filter algorithm test)
        a. 테스트벤치 빌드(Build Testbench)
        b. 테스트벤치 실행(Run Testbench)
        c. 파이썬(Python): 데이터 시각화(Data Visualization)
        d. 실습: FIR 필터 알고리즘(Lab. FIR filter algorithm)
        e. 파이썬 참고목록 (Python References)

III. 하드웨어 구조 탐색 (Architecture Exploration)
    III-1. FIR 알고리즘의 타임드 SystemC/C++ 모형(Timed SystemC/C++ model)
    III-2. 병렬처리 용 처리 요소(Processing Element for Parallel Processing)
    III-3. 파이프라인 구조 모델(Modeling Pipelined Architecture)
    III-4. 언-타임드 실행형 사양과 타임드 테스트벤치(Un-timed executable specitication and Timed Testbench)
    III-5. 실습. FIR 필터의 타임드 시뮬레이션(Lab. FIR filter Timed Model Simulation)

IV. 베릴로그 RTL
    IV-1. 처리요소의 RTL 베릴로그(Processing Element RTL Verilog)
    IV-2. 파이프라인 배열 구조의 RTL 베릴로그(Pipeline Array RTL Verilog)
    IV-3. 병행 시뮬레이션 테스트 벤치(Co-simulation Testbench)
    IV-4. 실습. FIR 필터의 병행 시뮬레이션(Lab. FIR filter Co-Simulation)

V. 맺음말


----------------------------------------------------------


I. 개요

"내 칩(My Chip) MPW 서비스": 오픈-소스 도구 활용 반도체 설계 특별과정의 첫 강좌에서 D-플립플롭을 트랜지스터 수준에서 설계하고 레이아웃을 그리는 연습을 했다. 이어 두번째 과정에서 D-플립플롭을 이용한 구조적 쉬프트 레지스터와 행위적 쉬프트 레지스터를 학습 했다[2].

이번에는 추상화 수준을 알고리즘 수준까지 끌어올려 본다. FIR 필터를 C++ 언어로 기술하고 이를 Verilog RTL로 설계한다. FIR 필터의 파이프라인 병렬처리 구조 탐색과 테스트 벤치는 SystemC로 작성한다. 디지털 신호처리 알고리즘을 검증하기 위해 매우 긴 테스트 신호가 생성되어야 한다. 필터의 성능 시험을 위한 잡음은 C++ GSL(GNU Scientific Library)[3]을 활용하여 생성한다. 테스트 벤치에 C++/SystemC 를 사용하므로써 얻는 혜택은 그동안 쌓인 라이브러리의 활용도 있다. 발전된 컴퓨터 성능을 활용하는 현대 알고리즘들은 대용량의 입출력 신호를 다룬다. 디지털 신호처리(DSP, Digital Signal Processing)도 그중 하나다. 이번에 학습할 디지털 FIR 필터 역시 매우 방대한 량의 입출력 신호를 처리한다. 많은 양의 입출력 신호의 시각화에 파이썬(Python)을 활용한다.

    [1] VLSI 레이아웃 설계 기초[8] Std-Cell 제작 실습: DFF-SR, https://fun-teaching-goodkook.blogspot.com/2024/07/vlsi-8-std-cell-dff-sr.html
    [2] Verilog-Verilator-SystemC 방법론 기초[4] 실습: 쉬프트 레지스터, https://fun-teaching-goodkook.blogspot.com/2024/08/verilog-verilator-systemc-4.html
    [3] GNU Scientific Library, https://www.gnu.org/software/gsl/


II. 시스템 사양(System Specification)

설계하려는 시스템 사양은 다음과 같다.

    설계 목표: 디지털 데이터의 저역 필터 설계 (Digital Low-Pass Filter)

        입력: 8 비트 부호없는 디지털 데이터 (8-bit unsigned integer)

        출력: 16비트 부호없는 디지털 데이터(16-bit unsigned integer)

    필터 특성:

        샘플링 주파수: 4800Hz

        차단 주파수: 1000Hz

        차단 이득: -20dB 이상

        알고리즘: FIR

위의 사양을 만족하는 필터를 디지털 하드웨어로 설계한다. 이 사양서에 입출력 신호의 타이밍 조건(In/Out timing requirement)이 빠져있다. RTL 설계에 앞서 컴퓨팅 언어 C++ 로 알고리즘을 기술하고 필터의 요구사양을 만족하는지 시험한다. C++로 작성하고 시험한 코드는 RTL 설계시 검증용 참고(golden reference)로 쓰인다. 문서가 아닌 실행형 설계사양(executable specification)이다.

II-1. FIR 필터 알고리즘(FIR filter algorthm)

DSP의 디지털 FIR 필터는 궤환이 없는 유한 길이의 선형성을 갖는 알고리즘으로 하드웨어 구현이 용이하다. 배열 구조 병렬처리(array parallel processing)에 적용되는 전형적인 예이기도 하다. 이산(discrete-time) 계수 곱의 합으로 표현하면 아래와 같다[1].

수식을 따지고 보면 매우 단순한 행렬의 벡터 곱(vector multiplication)이다. 어렵지 않게 C 언어로 구현할 수 있다.

입력 벡터에 곱해지는 계수에 따라 다양한 효과를 볼 수 있다. 결국 디지털 필터의 설계는 이 계수를 구하는 것이다.

[주] 필터의 사양에 따라 계수가 구해지면 상수로 고정된다. 응용에 따라 이 계수 테이블을 가변하여 다양한 임무를 수행 할 수 있다. 인공지능의 신경망[2]에서 학습은 곧 이 계수표를 효과적으로 갱신해 내는 것이다.

    [1] Finite Impulse Response, https://en.wikipedia.org/wiki/Finite_impulse_response
    [2] But what is a Neural Network?, https://www.3blue1brown.com/lessons/neural-networks

II-2. FIR 필터 계수 구하기

필터 계수 구하기는 이번 학습의 범위가 아니므로 외부 도구의 도움을 받기로 한다. 필터의 계수는 T-Filter 웹 도구[3]를 통하여 구했다. 저역 필터(Low-Pass Filter)로서 탭의 갯수는 8개, 샘플링 주파수 4.8Khz의 입력 신호에 대하여 차단 주파수는 1kHz로 잡았다. 계산은 모두 정수형으로 수행한다.

설계 옵션에 필터 탭의 수가 작고 정밀도가 낮아 계수가 갖는 수의 범위가 크지 않다. 취급할 수의 범위(dynamic range of numbers)에 따라 비트 폭(bit-width)이 결정된다. 이는 결국 하드웨어의 규모와 소요전력 등에 영향을 미치게 되므로 설계사양(design specification)의 중요한 요소다.

    [3] T-Filter, http://t-filter.engineerjs.com/


II-3. FIR 필터의 언-타임드 C++ 코드(un-timed C++ code)

위의 웹 도구 T-Filter[3]를 통해 얻은 필터 계수를 가지고 C++ 코드를 작성한다. 하드웨어 설계의 검증할 때 비교 표준(golden reference)으로 사용될 것이다. 필터의 계수들을 filter_taps[]에 저장해 둔 헤더파일 fir8.h 은 아래와 같다.

FIR 필터 계산의 C++ 코드는 아래와 같다. 쉬프트 레지스터와 계수 곱의 누적을 for 반복문 안에 기술 하였다. 즉시할당과 순차실행되는 C++에서 쉬프트 레지스터를 표현하기 위해 반복문의 색인 순서에 유의한다. 쉬프트 레지스터 shift_reg[]는 함수 fir() 되돌려진 후에도 계속 값을 유지하고 있어야 하므로 정적 할당(static allocation) 되었다.

하드웨어 설계를 목표로 하고 있지만 알고리즘 개발 단계에서 C++ 코드는 클럭과 병렬성의 개념이 포함되지 않은 언-타임드(un-timed) 추상화 모델(abstracted model)이다.

II-4. FIR 필터의 언-타임드 C++ 테스트 벤치(un-timed testbench)

웹 도구로 구한 필터 계수를 사용하여 작성한 FIR 필터의 C++ 코드를 시험하기 위한 테스트 벤치를 작성한다. 입력으로 사용할 대량의 잡음 신호는 cnoise 라이브러리를 사용하였다[4]. 이 C++ 원시 코드는 백색 잡음 생성에 GSL(GNU scientific Library)[5]를 활용한다.

DUT(FIR 필터)의 성능시험을 목적으로 백색잡음(white noise)에 몇가지 주파수를 갖는 신호를 혼합하여 생성하였다.

    [4] cnoise, Miroslav Stoyanov, Oak Ridge National Laboratory, https://people.sc.fsu.edu/~jburkardt/c_src/cnoise/cnoise.html
    [5] GSL(GNU scientific library), https://www.gnu.org/software/gsl/

II-5. 실습. FIR 알고리즘의 시험(Lab. un-timed algorith test)

필터 알고리즘의 시험은 순수 C 프로그램 수준에서 실시한다. 실습의 예제 코드는 경희대학교 디자인 킷[6]에 포함되어 있다. 하드웨어의 시간개념이 포함되지 않은 C++ 코드로 작성된 모델을 "언-타임드(un-timed)" 라고 한다.

    [6] 경희대학교 디자인 킷/ETRI 0.5um Std-Cell DK, https://github.com/GoodKook/ETRI-0.5um-CMOS-MPW-Std-Cell-DK

a. 테스트벤치 빌드(Build Testbench)

GNU C 컴파일러로 테스트 벤치를 빌드(build) 한다.

    gcc -I. -I/opt/local/include -o fir8_tb fir8.cpp fir8_tb.cpp calcDFT.cpp cnoise.cpp -lm -lgsl

GCC 가 수학(math library) 라이브러리와 GSL을 불러와 링크 시키도록 명령줄에 -lm-lgsl 가 추가되었다.

b. 테스트벤치 실행(Run Testbench)

GNU C++로 컴파일 하여 얻은 테스트벤치를 실행한다.

    $ ./fir8_tb
    0 167 36.857 668 36.263
    1 80 33.651 2324 22.740
    2 132 32.146 5663 22.891
    3 97 31.941 9650 22.948
    ......
    4797 110 31.941 15522 22.948
    4798 94 32.146 15909 22.891
    4799 39 33.651 15813 22.740

    $

FIR 필터 알고리즘 시험용 테스트 벤치는 한회에 4800개의 시계열(time domain) 입력 자료를 생성하고 필터를 거친 출력을 얻는다. 수없이 나열된 숫자들을 보고 그 결과를 판단 할 수는 없다. 대량 데이타를 저장해 두었다가 가시화(visualization) 도구를 통하여 분석(analysis) 하기로 한다.

명령줄에서 > 기호(리다이렉션, re-direction)를 사용하여 표준출력을 임의 파일로 바꿔줄 수 있다.

    $ ./fir8_tb > fir8_tb_out.txt

테스트벤치의 출력을 일반 파일(plain text file) fir8_tb_out.txt 로 저장한다. 파이썬(Python)은 다양한 데이터 가시화 라이브러리를 갖춘 알고리즘 분석의 좋은 도구다.

c. 파이썬(Python) 데이터 시각화(Data Visualization)

FIR 필터의 성능 분석에 파이썬을 활용한다. FIR 필터 알고리즘을 시험한 결과를 시각화하기 위한 파이썬 코드는 예제에서 plotDFT.py 다.

첫 줄에 이 스크립트가 파이썬3(python3)용 이라는 것을 표시하고 있다. 파이썬 스크립트는 별도의 지정이 없는 한 가장 먼저 만나는 줄에서 시작한다. 사용할 파이썬 라이브러리들을 불러온다(import libraries).  matplotlib 는 다차원 배열의 데이타를 시각화 해주는 라이브러리 다. numpy는 다차원 배열(행렬) 데이타를 다룰때 유용하다. 라이브러리 이름 뒤의 as 는 긴 라이브러리 이름을 쓰기 번거롭지 않도록 줄여준다.

명령줄에서 실행 인수(Command-line argument)의 갯수를 확인한다. 만족하지 않을 경우 도움말을 출력하고 운영체제로 나간다(스크립트 실행종료).

numpy 라이브러리를 사용할 수 있도록 변수들을 배열로 선언했다. 파이썬의 객체는 할당되는 값에 의해 자료형이 정해진다. 이는 객체의 자료형에 민감한 C/C++ 프로그래머에게 낮설지만 입문자에게 매우 편리한 면이라고 하겠다.

C/C++ 프로그래머가 보기에 파이썬은 지나치게 추상적인데, '척하면 알아서...' 해석해주는 느낌마져든다. 아래와 같은 반복문이 있다.

    for x in range(1, 10):
        print(x)

변수 x 는 자료형 선언이 없어도 range(1, 10) 가 숫자 1에서 10까지 반복하는 함수이므로 알아서 정수형이다. 게다가 range() 가 함수라고 하기에도 별나다. 1에서 시작하여 10이 되기 전까지 숫자들을 배열로 만들어준다. 위의 반복문은,

    for in [1,2,3,4,5,6,7,8,9]:
        print(x)

파이썬의 높은 추상성은 프로그래밍(코딩)을 시작하는 장벽을 낮추지만 외워야 할 것들이 늘어난다. 아래의 for 반복문은 FIR의 테스트벤치 출력을 저장한 파일 fir8_tb_out.txt 에서 1줄을 읽어 각변수에 저장한다. 파일을 열어 문자열을 읽고 open(), 이를 나눠서 .split(), 각변수에 넣기 .append() 까지 일련의 과정을 아주 간단히 수행한다.

파이썬의 극단적 추상성이자 인간 친화적인 면모를 볼 수 있다.

for 반복문의 구간이 in 에서 파일을 취급하고 있으므로  파일의 끝(End of File)까지다.

- 한줄에 여러 숫자를 공백 문자로 분리하자는 법칙(rule)은 없지만 보통 그렇게 하면 편리하니 그런것으로 하고 문자열 자료형에 .split()를 만들어 뒀다.

전통적 C 언어로 작성했더라면 수십줄의 코딩이 필요했을 것이다. 이러한 추상성은 오늘날 파이썬이 최고 인기를 구가하는 이유다. 라이브러리 공급자와 사용자 사이에 통념과 상식에 기반한 암묵적 동의를 바탕으로 최고의 추상성을 추구한다. 누구나 코딩의 부담에서 벗어나 알고리즘에 집중할 수 있다.

[주] 파이썬의 단점으로 실행 속도를 꼽기도 한다. 하지만 고속 CPU와 풍부한 컴퓨팅 자원 덕에 이를 문제 삼지 않는다.

파이썬의 사용자가 증가하면서 이들이 만들어 공개적으로 제공하는 라이브러리들 역시 다양하다. 공식적으로 배포되는 표준 라이브러리(Python Standard Library)는 물론 다수의 사용자에 의해 개발되어 배포되는 패키지들도 이루 헤아릴 수 없을 정도다. 파일 입출력, 복합 자료형 등 기본 내장 라이브러리 부터 그래픽, 과학기술, 수치해석, 통계, 운용체제 등 응용 프로그램 제작에 유용하게 사용될 수 있는 라이브러리들을 망라한다. 자체적으로 라이브러리의 설치운용 기능을 갖추고 있어 파이썬은 이제 개발 플랫폼이 됐다.

다음은 테스트벤치의 실행으로 얻은 DUT의 입출력 자료들을 읽어 시각화 하는 파이썬 코드의 일부다.

matplot은 다양한 데아타 가시화 기능을 갖춘 패키지다[]. 대량의 데이타를 수월하게 그래프로 그릴 수 있다. 테스트벤치를 실행 시켜 얻은 입출력 데이타를 matplot 패키지의 .plot(x, y)로 단번에 그래프로 표시해준다. 그래프를 꾸며주기 위해 몇가지 방법이 더 사용되었을 뿐이다.

그 외 명령줄에서 전달되는 인수를 받아오기 위해 sys 패키지[]의 argv[]를 참조하고 x-축에 눈금을 그릴 요량으로 벡터 데이터 생성에 numpy의 .arange(...)를 활용했다[]. 예제에 사용된 방법들은 패키지의 극히 일부에 지나지 않는다.

[주] 인공지능/신경망(neural network) 라이브러리 활용 필기체 숫자인식의 예[9]

d. 실습: FIR 필터 알고리즘

FIR 필터의 C++ 테스트벤치를 실행하여 얻은 결과 데이터를 시각화하여 평가한다. C++ 빌드와 실행 그리고 시각화를 위한 파이썬 실행은 미리 준비해 둔 메이크 스크립트 Makefile를 통해 이뤄진다. 예제는 경희대학교 디자인 킷[6]의 Tutorials 에 포함되어 있다. 또는 아래 링크를 통해 받을 수 있다.

https://github.com/GoodKook/ETRI-0.5um-CMOS-MPW-Std-Cell-DK/tree/main/Tutorials/2-5_Lab3_FIR8/c_untimed

예제 디렉토리로 이동,

    $ cd ~/ETRI050_DesignKit/Tutorials/2-5_Lab3_FIR8/c_untimed

C++ 테스트 벤치 빌드,

    $ make build
    gcc -I. -I/opt/local/include -lm -lgsl -o fir8_tb fir8.cpp fir8_tb.cpp calcDFT.cpp cnoise.cpp -lm -lgsl

실행,

    $ make run
    ./fir8_tb > fir8_tb_out.txt

테스트 신호 시간축에서 보기,

    $ make plot_x
    ./plotDFT.py input

테스트 입력 주파수 축 분석,

    $ make plot_fx
    ./plotDFT.py inputDFT

FIR 필터 출력의 시간 축 보기,주파수 분석,

    $ make plot_y
    ./plotDFT.py output

FIR 필터 출력의 주파수 분석,

    $ make plot_fy
    ./plotDFT.py outputDFT

입력과 출력의 주파수 분석을 비교해 보면 필터의 효과를 한눈에 확인할 수 있다.


e. 파이썬 참고목록

프로그래밍 언어를 이해하는 파이썬 학습자라면 아래목록 중 [1] 또는 [2] 하나로 충분하다. [3]은 과학기술 분야 응용에 많은 예제 코드들을 담고 있다.

[1] A Byte of Python(한글 번역본), https://byteofpython-korean.sourceforge.net/byte_of_python.pdf

[2] A Byte of Python, https://github.com/swaroopch/byte-of-python/releases/latest

[3] Python Programming And Numerical Methods: A Guide For Engineers And Scientists, https://pythonnumericalmethods.berkeley.edu/

[4] Python Standard Libraries, https://docs.python.org/3/library/index.html

[5] The Python Package Index (PyPI), https://pypi.org/

[6] Matplotlib: Visualization with Python, https://matplotlib.org/

[7] NumPy: The fundamental package for scientific computing with Python, https://numpy.org/

[8] sys — System-specific parameters and functions, https://docs.python.org/3/library/sys.html

[9] But what is a Neural Network?, https://www.3blue1brown.com/lessons/neural-networks , https://github.com/3b1b/videos/blob/master/_2017/nn/part1.py

-------

III. 하드웨어 구조 탐색

알고리즘을 하드웨어로 구현할 목적이라면 레지스터 전송 수준(RTL, Register-Transfer Level)으로 기술되어야 한다. RTL에서는 클럭 단위로 하드웨어의 작동을 묘사한다. 아울러 각 객체들(신호선, 와이어)은 비트 단위로 상세히(clock/bit-detailed) 기술한다.

알고리즘을 기술한 언-타임드(un-timed) C++ 코드를 하드웨어 언어로 바로 전이[1]하기에 추상화 수준의 간격이 너무 넓다. 게다가 하드웨어의 동시실행성(concurrency)은 알고리즘 C++ 코드에 포함되지 않은 개념이다.

[주] 알고리즘 C++ 를 RTL로 합성해주는  HLS(High Level Synthesis) 자동화 도구 가 부상하고 있다[1]. 여전히 수동변환이 다수를 차지한다.

    [1] Towards Automatic High-Level Code Deployment on Reconfigurable Platforms: A Survey of High-Level Synthesis Tools and Toolchains, IEEE Access, Vol.8,2020, https://ieeexplore.ieee.org/abstract/document/9195872


III-1. FIR 알고리즘의 타임드 모형(Timed model)

FIR 필터의 언- 타임드 C++에서 병렬성을 찾아내고 파이프라인 구조를 평가한다. 언-타임드 C/C++로 작성된 알고리즘을 하드웨어로 구현하는 첫 단계는 변수들 사이의 의존관계(dependency)를 따져 병렬성(parallelism)을 탐지해 내는 일이다. 이를 근거로 동시처리(concurrency)가 가능한 요소(processing element)로 분할하고 클럭 기반의 스케쥴링을 수립한다.

FIR 필터 알고리즘의 골자인 for() 반복문을 다루는 방법에 두가지 구조를 고려해 볼 수 있다. 첫째 구조는 반복문의 제어절차를 FSM으로 구현하고 누산기를 두는 방법이다. 두번째는 반복문 for()에서 반복변수 i를 펼쳐 놓고 자료의 의존관계를 살펴보는 것이다. 곱셈과 누적 연산 사이에 순방향 의존만 존재하므로 파이프라인 병렬처리 구조(pipelined-parallelism)가 가능하다. 두 구조는 각각 장단점이 있으므로 조건과 용도에 맞게 선택한다.

RTL에서 논리회로 네트리스트로 변환하는 합성이 발전할 수 있던 요인은 추상화 수준이 크게 다르지 않았기 때문이다. 병렬성과 클럭의 개념은 알고리즘에서 RTL 로 합성을 어렵게 한다. 프로그래밍 언어에서 따지지 않던 "클럭 싸이클(clock cycle)" 과 "레이턴시(latency)"는 하드웨어 설계의 중요 요구사항이 된다. 입출력 신호의 타이밍 요건은 알고리즘을 하드웨어로 구현할 때 구조를 결정하는 중요한 요소다.

FIR 필터의 입출력 타이밍 요구사항이 아래와 같다고 하자. 매 클럭마다 입력이 들어오고 실시간으로 출력을 내야 한다(interval=1). 프레임 단위로 입력을 저장해 두었다가 출력하는 방식이라면 계산기의 속도를 높여 실시간 처리가 가능하지만 상당한 버퍼링 지연을 감수해야 한다. 이에 비하여 파이프라인 병렬처리 구조의 경우 입력과 출력의 데이터 생성율(In/Out data rate)을 계산기의 클럭율(clock rate)과 일치시킬 수 있다. 계산에 사용되는 클럭율을 낮춰 얻을 수 있는 큰 장점은 전력효율이다. 굳이 전용 하드웨어가 필요한 이유다.


초기 레이턴시(initial latency)는 첫 유효 입력이 처리되어 출력으로 나오기까지 소요되는 클럭 갯수다. 이어진 연속 입력에 대하여 출력이 나오기까지 소요되는 클럭 갯수는 인터벌(interval)이다.

첫번째 구조는 데이터를 저장해 놓고 반복적으로 연산을 수행한다. 최소의 연산기를 사용하고 있다. 범용 계산기에서 프로그래밍으로 처리하는 방식과 유사하다. FSM이 CPU의 반복 명령을 대신한다. 두번째 구조는 파이프라인 병렬처리다. 초기 지연 클럭 수는 쉬프트 레지스터의 갯수 만큼이다. 인터벌은 1이다.

알고리즘 C++의 for 반복문 내에서 변수들의 반복색인(loop index)을 따져 보면, 변수 shift_reg 와 acc의 현재색인 [i] 값이 각각 이전색인 [i-1]의 값과 의존관계(dependency arc)에 있다. 이를 근거로 쉬프트 레지스터(shift register)와 누산기(multiplier-accumulator)를 파이프라인 병렬구조의 처리 단위(PE, Processing Element)로 삼는다.

Xin은 지역 변수 shift_reg[] 로 정적 선언되어 있고 할당의 좌우 색인 관계가 쉬프트 레지스터로 명확하다. 누산(accumulation)의 경우 반복문 내에서 이전값과 덧샘을 수행하고 있는 점에 유의한다.

MAC(multiplication accumulator)의 구조에서 곱셈과 덧셈을 이어놓을 경우 회로 경로(critical path)가 길어지는 것을 막기위해 곱셈과 덧셈 사이에 레지스터를 추가한다.


III-2. 처리 요소(Processing Element)

알고리즘 C++를 구현할 하드웨어 구조가 결정되었다고 곧바로 RTL 설계에 돌입할 수도 있겠지만 추상화 수준 차이를 극복하기는 쉽지 않다. 먼저 구조에 맞도록 알고리즘을 병렬처리 단위로 분할한 후 병렬처리 스케쥴(parallel processing schedule)에 부합하는지 확인한다.

[주] 고위 합성(High-Level Synthesis) 방법론은 자동화 도구가 알고리즘에서 병렬처리 구조를 도출해 낸다. 이때, 병렬처리 스케쥴의 검증이 중요하다. 예제 FIR의 경우 수동 분할과 병렬구조를 수립하였으므로 검증이라기 보다 확인이다.

언 타임드 C++ 의 for 반복문을 파이프라인 병렬 처리 구조로 풀어 놓으면 아래와 같다. MAC 연산기가 누산형에서 파이프라인 구조로 궤환 경로가 풀려있다(Loop un-lock).

배열을 반복적인 처리요소 PE로 분할했다. 파이프라인 병렬처리 MAC 연산기는 계수와 PE 갯수의 변경에 따라 다양한 응용이 가능하다. PE의 반복 재사용을 고려하여 모두 레지스터 출력이 되도록 아래와 같은 분할이 좋다. 파이프라인 병렬처리 처리요소 PE 를 SystemC 로 기술하면 아래와 같다. 클럭 사건에 반응하여 처리요소가 행동하도록 기술되었다.


III-3. 파이프라인 구조 모형

PE를 연속 배열한 파이프라인 처리 구조의 FIR 필터를 기술한 구조적 SystemC 모델은 아래와 같다.

SystemC의 모듈 크래스 SC_MODULE() 와 구성자 매크로 SC_CTOR(), 그리고 템플릿 크래스 객체 sc_in<>, sc_out<>, sc_signal<> 들이 조금 생소하지만 C++와 하드웨어 모델링의 눈으로 보면 어렵지 않게 이해될 것이다.

III-4. 언-타임드 실행형 사양과 타임드 테스트벤치

언-타임드 C++ 알고리즘을 참조 모델(golden reference)로 사용한다. 테스트 벤치내에 참조 모델이 호출 가능한 함수로 들어와 있다. 이를 실행형(executable specification) 사양이라 한다.


III-5. 실습. FIR 필터의 타임드 시뮬레이션

FIR 필터의 SystemC/C++ 타임드 테스트벤치를 실행하여 확인할 사항은 아래와 같다.

- 파이프라인 병렬처리 타이밍

- 언타임드 알고리즘의 결과와 타임드 모델의 결과 비교

SystemC/C++ 모델의 빌드와 실행 그리고 시각화를 위한 파이썬 실행은 미리 준비해 둔 메이크 스크립트 Makefile를 통해 이뤄진다. 예제는 경희대학교 디자인 킷[1]의 Tutorials 에 포함되어 있다. 또는 아래 링크를 통해 받을 수 있다.

https://github.com/GoodKook/ETRI-0.5um-CMOS-MPW-Std-Cell-DK/tree/main/Tutorials/2-5_Lab3_FIR8/sc_timed

    [1] 경희대학교 NSPL 0.5um 표준 셀 디자인 킷, https://github.com/GoodKook/ETRI-0.5um-CMOS-MPW-Std-Cell-DK

예제 디렉토리로 이동,

    $ cd ~/ETRI050_DesignKit/Tutorials/2-5_Lab3_FIR8/sc_timed

SystemC/C++ 테스트 벤치 빌드,

    $ make build
    clang++ -I. -I../c_untimed -DVCD_TRACE_FIR8 \
            -DVCD_TRACE_FIR8_TB \
            -o sc_fir8_tb -lsystemc -lm -lgsl \
                sc_main.cpp \
                sc_fir8_tb.cpp \
                ../c_untimed/fir8.cpp \
                ../c_untimed/cnoise.cpp

실행,

    $ make run
    ./sc_fir8_tb

        SystemC 3.0.0-Accellera --- Aug  9 2024 12:41:46
        Copyright (c) 1996-2024 by all Contributors,
        ALL RIGHTS RESERVED

    Info: (I703) tracing timescale unit set: 100 ps (sc_fir8.vcd)
    Info: (I703) tracing timescale unit set: 100 ps (sc_fir8_tb.vcd)
    [   0] y=944 / Yout=944
    [   1] y=3220 / Yout=3220
    [   2] y=7568 / Yout=7568
    [   3] y=12397 / Yout=12397
    [   4] y=16332 / Yout=16332
    .........
    [4796] y=15940 / Yout=15940
    [4797] y=16142 / Yout=16142
    [4798] y=15985 / Yout=15985
    [4799] y=15617 / Yout=15617

언타임드 표준 모델과 타임드 모델의 비교결과 오류없이 수행되었다. 

초기 지연은 9개 클럭 싸이클이 소요되었고 이어서 1클럭 마다 출력을 내고 있다. 파이프라인 병렬처리의 처리 요구 타이밍 스케줄을 만족한다.

FIR 필터 출력의 주파수 분석 DFT(Discrete Fourier Transform)은 파이썬 numpy 라이브러리를 활용하여 작성되었다[1].

    # DFT
    #

    import numpy as np

    def DFT(x):
        """
        Function to calculate the 
        discrete Fourier Transform 
        of a 1D real-valued signal x
        """

        N = len(x)
        n = np.arange(N)
        k = n.reshape((N, 1))
        e = np.exp(-2j * np.pi * k * n / N)

        X = np.dot(e, x)

        return X

IV. 베릴로그 RTL

SystemC의 목적이 RTL 기술은 아니다. 하지만 FIR 필터의 구조가 단순하여 SystemC/C++ 타임드 모델링 단계에서 이미 RTL 수준이 되었다. RTL SystemC/C++에서 베릴로그로 변환해주는 도구가 있으나 이번 예제는 수동 변환을 해보기로 한다.

IV-1. 처리요소의 RTL 베릴로그(Processing Element RTL Verilog)

FIR 필터의 처리요소의 베릴로그 모델은 다음과 같다.

IV-2. 파이프라인 배열 구조의 RTL 베릴로그(Pipeline Array RTL Verilog)

처리요소 fir_pe를 직렬로 연결한 파이프라인 구조 베릴로그 기술은 다음과 같다.

FIR 필터 계수는 상수 배열(coustants array)로 localparam 으로 정의 됐다. 처리요소 fir_pe는 하위 모듈(sub-module)로 for 반복문으로 사례화(instanciate)했다. SystemC의 구조적 기술과 비교해보면 내용(추상화 수준)면에서 일치한다. 베릴로그가 하드웨어 기술 전용 언어인 만큼표현은 매우 간결하다.

IV-3. 병행 시뮬레이션 테스트 벤치(Co-simulation Testbench)

RTL 베릴로그를 SystemC 로 변환한 모듈과 타임드 모델을 한 테스트벤치에 놓고 시뮬레이션 을 통해 검증한다. 이때 타임드 모델의 SystemC 테스트 벤치를 재사용한다.

타임드 테스트 벡터 생성 쓰레딩 함수 Test_Gen()는 다음과 같다. 언-타임드 C++ 알고리즘의 fir()로 테스트 신호를 미리 준비 시킨 후 클럭의 동기에 맞춰 두 타임드 모델에 입력을 주고 있다.

타임드 출력 모니터링 함수 Test_Mon()는 아래와 같다. 시뮬레이션 시작 전에 생성해둔 알고리즘의 출력을 표준으로 삼아 두 타임드 모델의 출력과 비교한다.

IV-4. 실습. FIR 필터의 병행 시뮬레이션(Lab. FIR filter Co-Simulation)

병행 시뮬레이션(Co-Simulation)은 추상화 수준이 상이한 모델을 함께 엮어 시험하는 검증기법이다. 앞서 시험했던 알고리즘 부터 타임드 모델에 덧붙여 RTL 까지 한데 모은 테스트 벤치를 가지고 시뮬레이션을 수행한다.

SystemC/C++ 모델의 빌드와 시뮬레이션 실행은 미리 준비해 둔 메이크 스크립트 Makefile를 통해 이뤄진다. 예제는 경희대학교 디자인 킷의 Tutorials 에 포함되어 있다. 또는 아래 링크를 통해 받을 수 있다.

https://github.com/GoodKook/ETRI-0.5um-CMOS-MPW-Std-Cell-DK/tree/main/Tutorials/2-5_Lab3_FIR8/RTL_Verilog

예제 디렉토리로 이동,

    $ cd ~/ETRI050_DesignKit/Tutorials/2-5_Lab3_FIR8/RTL_Verilog

SystemC/C++ 테스트 벤치 빌드,

    $ make build
    verilator --sc -Wall --trace --top-module fir8 --exe --build \
        -CFLAGS -std=c++17 -CFLAGS -I../sc_timed \
        -CFLAGS -DVCD_TRACE_FIR8 -CFLAGS -DVERILATED_CO_SIM \
        -LDFLAGS -lgsl \
        fir8.v fir_pe.v \
        ../sc_timed/sc_main.cpp ../sc_timed/sc_fir8_tb.cpp  \
        ../c_untimed/fir8.cpp ../c_untimed/cnoise.cpp

실행,

    $ make run
    ./obj_dir/Vfir8

        SystemC 3.0.0-Accellera --- Aug  9 2024 12:41:46
        Copyright (c) 1996-2024 by all Contributors,
        ALL RIGHTS RESERVED

    Info: (I703) tracing timescale unit set: 100 ps (sc_fir8.vcd)
    Warning: (W509) module construction not properly completed: did you forget to add a sc_module_name parameter to your module constructor?: module 'u_sc_fir8_tb'

    In file: ../../../src/sysc/kernel/sc_module.cpp:376
    [   0] y=704 / Yout=704
    [   1] y=2304 / Yout=2304
    [   2] y=5728 / Yout=5728
    [   3] y=9760 / Yout=9760
    ......
    [4795] y=23274 / Yout=23274
    [4796] y=22618 / Yout=22618
    [4797] y=21793 / Yout=21793
    [4798] y=20499 / Yout=20499
    [4799] y=19391 / Yout=19391

Info: /OSCI/SystemC: Simulation stopped by user.

언-타임드 표준 모델과 타임드 모델 그리고 RTL 모델의 비교결과 오류없이 수행되었다.

V. 맺음말

오픈-소스 도구를 사용하여 디지털 FIR 필터의 파이프라인 병렬처리 하드웨어 설계 과정을 살펴봤다. FIR 필터 알고리즘의 문서 사양을 토대로 언-타임드 C++ 로 기술하고 시험했다. 병렬 구조를 도출하여 SystemC 타임드 모델링 후 최종적으로 베릴로그 RTL로 기술했다. 베릴로그 RTL 모델의 검증에 언-타임드 알고리즘과 타임드 모델을 모두 엮은 병행 시뮬레이션 기법을 적용하였다. FIR 필터의 성능 시험에 GSL이 사용되었고 대용량 시뮬레이션 데이터는 파이썬의 가시화 패키지를 활용하였다.

설계와 검증에 사용된 도구 Verilator와 SystemC 그리고 GSL은 모두 C++ 언어 기반의 오픈-소스 도구들이다. 여기에 더하여 파이썬의 방대한 패키지(라이브러리)를 하드웨어 설계에 활용할수 있다. 베릴로그 HDL을 C++ 로 변환해주는 도구 Verilator와 시스템 수준 모델링 도구 SystemC를 사용한 반도체 설계 방법론은 기존에 축적된 방대한 자원들을 활용할 수 있게 해준다. 보다 실제적인 테스트 입력 데이터의 생성이 가능하며 가시화를 통해 방대한 시험 데이터의 분석이 용이하다.

반도체 설계에 Verilator-SystemC 방법론이 다소 낮설수 있으나 이미 C++를 비롯한 프로그래밍 언어의 코딩에 친숙해져 있다. 예제 프로젝트를 수행해 보면 반도체 설계 장벽이 그리 높지 않다는 것을 알게 될 것이다. 코딩은 도구 사용법 일 뿐이다. 도구의 사용자로서 무엇을 설계할지 고민해보자.

상용 도구의 사용법이 마치 고급 기술로 여겨지기도 한다. 사용하면서 닥치는 각종 장애를 해결하기도 쉽지 않다. 물어볼 곳 조차 마땅치 않다. 질문에 쓸만한 답을 얻으려면 비용을 지불해야 한다. 심지어 보안유지 서약까지 요구하니 그들만의 닫힌 세계다. 

그동안 우리는 소프트웨어 개발도구의 눈부신 발달을 목격했다. 공개 정책의 공이 크다. 이에 비하면 반도체 설계는 공정기술에 힘입어 규모만 키웠을 뿐이다. 다행히 반도체 설계에도 오픈-소스 바람이 불어 상당한 발전을 이루고 있다.

반도체 설계 신동이 나타날 날을 기대해 본다. 컴퓨터 학원에 시스템 반도체 설계 과목은 어떨까?



댓글 없음:

댓글 쓰기