2024년 4월 3일 수요일

ETRI 0.5um CMOS DK 예제: FIR8 / [2] 아듀이노 보드 에뮬레이션

ETRI 0.5um CMOS DK 예제: FIR8

[2부] 아듀이노 보드 에뮬레이션

목차:

1. 개요

2. WSL에서 USB 장치 사용법

3. 아듀이노 개발환경 설치

4. 아듀이노 보드에 FIR8 알고리즘 구현

5. 에뮬레이션 프로토콜 정의

6. 테스트벤치 재사용: 시뮬레이터와 에뮬레이션의 병행

7. Co-Simulation /  Co-Emulation & Testbench Re-Use

8. 시뮬레이션 가속기/참고문헌

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

1. 개요

SystemC는 하드웨어의 행위(hardware behavior)를 묘사하기 위한 크래스(C++ class)와 동시실행 시뮬레이터(concurrency simulator)가 포함된 C++의 라이브러리다. 레지스터 전송수준(RTL)은 물론 트랜잭션 수준(TLM, Transaction Level Modeling)을 비롯하여 시스템 수준까지 매우 넓은 추상화 수준(abstraction level)을 지원한다. 합성가능(synthesizable)한 RTL의 CPU에서부터 운영체제 그리고 응용 프로그램까지 설계 할 수 있다는 의미다. 별도의 언어체계가 아닌 C++ 그 자체이기 때문에 컴퓨터로 할 수 있는 모든 것이 가능하다[SystemC는 최신방법론 인가?]. 물론 설계자의 상상력에 달려 있긴 하다. SystemC의 활용의 예로 시뮬레이션과 에뮬레이션을 함께 수행하는 기법(Co-Simulation/Co-Emulation)을 소개한다. 에뮬레이션은 컴퓨터 시스템의 주변장치로 연결된 하드웨어를 시뮬레이터로 끌어들인다. 이더(Ethernet)으로 연결된 다수의 컴퓨터를 동원하여 대규모 병렬 컴퓨팅을 구현할 수 있다. 주변장치와 컴퓨터 시스템 사이의 인터페이스 병목을 해결하면 FPGA는 물론 GPU 활용 시뮬레이션 가속기(HDL simulation accelerator)로 활용할 수 있다.

앞서 다룬 FIR8 알고리즘[바로가기]을 아듀이노 보드(Arnuino)에 구현하고 이를 에뮬레이션 하드웨어로 사용하는 예를 살펴본다. 컴퓨터와 아듀이노 보드 사이의 USB 인터페이스가 고속이라고 할 수 없는 직렬통신(serial communication)이기에 가속기로서 의미는 없지만 SystemC의 가능성을 엿볼 수 있을 것이다. 향후 MPW로 제공받은 칩 테스트의 용도로 쓰일 수 있다. 시뮬레이션과 에뮬레이션을 엮어 동시에 수행하게 되므로 테스트벤치를 재사용 할 수 있다.

2. WSL에서 USB 장치 사용법

리눅스 운영체제에서 직렬 포트는 터미널의 용도로 널리 사용되어 왔기에 주변장치로 매우 안정된 작동을 보여준다. WSL 서비스의 가상 머신(virtual machine)으로 리눅스가 설치되었다면 윈도우즈 운영체제의 장치 드라이버를 연결해 주어야 한다.

참고] Windows WSL: Connect USB device, https://learn.microsoft.com/en-us/windows/wsl/connect-usb

원래 윈도우즈의 USB 장치는 WSL에 연결되어 있지 않기 때문에 USBIPD-WIN 도구를 설치 하자. 아래 링크에서 .msi 설치 프로그램을 내려받아 실행 한다.

    https://github.com/dorssel/usbipd-win/releases

윈도우즈 파워-쉘(Power-Shell)을 관리자 권한으로 열어 가상 머신 리눅스와 공유가능한 USB 장치의 목록을 확인한다.

    PS C:\> usbipd list

    Connected:
    BUSID  VID:PID    DEVICE                         STATE
    2-8    045e:09c0  USB Input Device               Not shared
    2-10   8087:0026  Intel(R) Wireless Bluetooth(R) Not shared
    4-2    343c:0000  USB Type-C Digital AV Adapter  Not shared
    4-3    2a03:0043  USB Serial Device (COM3)       Not shared

이 목록은 컴퓨터에 연결된 장치에 따라 다르다. 나열된 장치들이 모두 공유되어 있지 않다. 아듀이노 보드의 USB 장치를 찾아 공유 시킨다. 아듀이노 보드는 USB의 직렬 포트로 연결된다. 위의 목록에서 "USB Serial Device (COM3)" 다. 윈도우즈에서 아듀이노 IDE를 설치했다면 "Arduino Uno (COM3)"로 목록에 표시될 것이다. 아듀이노 보드의 BUSID를 WSL에 공유시키는 명령은 아래와 같다.

    PS C:\> usbipd bind --busid 4-3

공유가 이뤄 졌는지 확인해보자.

    PS C:\> usbipd list

    Connected:
    BUSID  VID:PID    DEVICE                         STATE
    2-8    045e:09c0  USB Input Device               Not shared
    2-10   8087:0026  Intel(R) Wireless Bluetooth(R) Not shared
    4-2    343c:0000  USB Type-C Digital AV Adapter  Not shared
    4-3    2a03:0043  USB Serial Device (COM3)       Shared

공유된 USB 장치를 WSL에 연결(attach)시킨다. 장치 식별번호 busid 에 유의한다. 파워-쉘이 관리자 권한이어야 한다.

    PS C:\> usbipd attach --wsl --busid 4-3

    usbipd: info: Using WSL distribution 'Ubuntu-20.04' to attach; the device will be available in all WSL 2 distributions.
    usbipd: info: Using IP address 172.17.128.1 to reach the host.

리눅스 터미널을 열어 lsusb 명령으로 USB 장치들의 목록을 확인해 보자.

    ~$ lsusb

    Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
    Bus 001 Device 002: ID 2a03:0043 dog hunter AG Arduino Uno Rev3
    Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

나열된 목록에 윈도우즈에서 연결시킨 아듀이노 보드가 보인다.

3. 아듀이노 개발환경 설치

아듀이노 개발환경(IDE, integrated development environment)은 윈도우즈와 리눅스용이 있다. 아래 링크에서 64비트 리눅스용 압축 파일을 내려받는다.

    https://www.arduino.cc/en/software

압출 파일을 적당한 위치에 푼다. 옵션 폴더 /opt 에 풀기를 권장한다. 시스템이 관리하는 폴더이므로 관리자 권한으로 실행한다.

    $ cd /opt
    $ sudo unzip arduino-ide_2.3.2_Linux_64bit.zip
    $ sudo chown -R <user> arduino-ide_2.3.2_Linux_64bit

아듀이노 개발환경 실행 파일을 /usr/bin 에 심볼 링크(바로가기) 한다.

    $ sudo ln -s /opt/arduino-ide_2.3.2_Linux_64bi/arduino-ide arduino-ide

리눅스의 실행 파일 경로에 바로가기가 생성되었으므로 어느 위치에서도 아듀이노 IDE를 실행할 수 있다.

    $ cd
    $ cd ETRI-0.5u-CMOS-MPW-DK-Example--FIR8/0_algorithm/sc_emulated/
    $ arduino-ide fir8_ino

아두이노 보드가 리눅스의 장치 /dev/ttyACM0 에 연결된 것을 확인한다.

4. 아듀이노 보드에 FIR8 알고리즘 구현

아듀이노 보드는 8비트 마이크로 프로세서 ATMEGA(AVR)을 내장하고 있다. 프로그램 개발도구로 전용 C/C++ 컴파일러를 사용한다. 이 도구는 오픈-소스로서 표준 C/C++다. 따라서 앞 장에서 다뤘던 언-타임드 FIR8 알고리즘 fir8.cpp 을 변경 없이 구현 할 수 있다. 아듀이노 에뮬레이션 코드는 아래와 같다.

    fir8_ino.ino

아듀이노는 단순히 마이크로 프로세서 활용 보드를 넘어 개방형 시스템 개발 도구로 성공적인 모습을 보여준다. 수없이 많은 개발자(취미가들도 상당부분을 차지한다)들이 다양한 입출력 장치 프로그램의 라이브러리를 제공하여 아듀이노 개발환경을 풍요롭게 하고있다. USB 직렬 포트 구동 라이브러리도 그중 하나다. 사용법도 매우 단순하다. 설정 함수에서 보오 율(baud rate)을 설정하고 호스트 컴퓨터의 연결을 시도한다.

    void setup()
    {
      Serial.begin(9600);
      while (!Serial)
      {
        ;  // wait for serial port to connect(native USB port only)
      }

      establishContact();  // send a byte to establish contact

      pinMode(LED_BUILTIN, OUTPUT);
      digitalWrite(LED_BUILTIN, HIGH);
    }

아듀이노 보드는 별도의 운영체제를 갖지 않으므로 펌웨어 내부에서 무한반복하며 시리얼 포트의 입력을 기다린다.

    void loop()
    {
      if (Serial.available() > 0)
      {
        digitalWrite(LED_BUILTIN, LOW);
        incomingByte = Serial.read();
        x = (uint8_t)incomingByte;

        fir(&y, x);

        for (int i=0; i<FILTER_TAP_NUM; i++)
        {
          outingByte = (int)(shift_reg[i]);
          Serial.write(outingByte); // Send shift register X
        }

        outingByte = (int)(y & 0x00FF);
        Serial.write(outingByte); // LSB of y
        outingByte = (int)((y>>8) & 0x00FF);
        Serial.write(outingByte); // MSB of y

        digitalWrite(LED_BUILTIN, HIGH);
      }
    }

직렬 포트를 통해 8비트 입력를 받아 필터 함수 fir(*y, x)를 호출한다. 계산 결과 y는 16비트 이므로 두번에 걸쳐 전송한다. 디버깅을 위해 쉬프트 레지스터 격인 shift_reg[]를 결과 이전에 전송하고 있다.

5. 에뮬레이션 프로토콜 정의

호스트에서 실행중인 SystemC 테스트 벤치와 아듀이노 에뮬레이션 보드 사이의 프로토콜(protocol, 통신규칙)을 정의한다. 이 통신규칙은 설계물에 따라 입출력 신호의 비트 폭이 다르다. 직렬통신은 8비트 단위의 데이터 전송이므로 비트 단위로 조합과(또는) 분할로 에뮬레이션 될 설계물(함수)에 맞춰져야 한다. 통신이 발생하는 시점은 전적으로 호스트 쪽의 타임드 테스트벤치 모델에 의해 결정된다. 에뮬레이션을 위한 fir8 의 SystemC 모듈은 아래와 같다.

    sc_fir8.h

입출력 포트는 타임드 모형과 동일하다. 하위 모듈로 8개의 PE를 두고 연속적으로 연결한 배열 구조 대신 에뮬레이터 보드와 통신을 수행한다. 에뮬레이션 보드와 통신을 개시하는 시점은 타임드 모형과 클럭 동기를 맞춘 클럭 상승 엣지 사건이 발생되었을 때다. 

    SC_MODULE(sc_fir8)
    {
        sc_in<bool>             clk;
        sc_in<sc_uint<8> >      Xin;
        sc_out<sc_uint<8> >     Xout;
        sc_in<sc_uint<16> >     Yin;
        sc_out<sc_uint<16> >    Yout;

        sc_signal<sc_uint<8> >  X[FILTER_TAP_NUM];

        void fir8_thread(void)
        {
            while(true)

            {
                wait(clk.posedge_event());
                x = (uint8_t)Xin.read();
                while(write(fd, &x, 1)<=0)  // Send Byte
                    ......
                y = (uint16_t)(yH<<8) | (uint16_t)(yL);

                Yout.write(y);
            }
        }

        SC_CTOR(sc_fir8): clk("clk"),
            ......
        {
            SC_THREAD(fir8_thread);
            sensitive << clk;
                ......
        }
    };

모듈이 사례화(instantiate)되면 크래스의 구성자가 최초 실행된다. 이 구성자 내에서 운영체제의 직렬 포트 장치 구동기를 초기화 하고 에뮬레이션 보드와 연결을 시도한다. 리눅스 운영체제는 주변장치를 파일로 취급하므로 표준 입출력 장치 stdio.h 의 open(), read(), write()로 접근한다. 연결 시도 규칙은 에뮬레이션 보드에서 'A'를 보내오면 호스트는 이를 반송하여 연결을 확인토록 하였다. WSL 리눅스에서 아듀이노 보드가 연결된 장치명은 /dev/ttyACM0 였다. 이 장치를 입출력이 가능하도록 설정하고 보오율은 아듀이노 보드 측의 펌웨어 설정과 동일한 9600 이다.

        SC_CTOR(sc_fir8): clk("clk"),......
        {
            ......
            // Arduino DUT
            fd = open("/dev/ttyACM0", O_RDWR | O_NOCTTY);

            // Set up serial port
            options.c_cflag = B9600 | CS8 | CLOCAL | CREAD;
                ......
            tcsetattr(fd, TCSANOW, &options);

            // Establish Contact
            while(!len)
                len = read(fd, &rx, 1);
            if (rx=='A')
                write(fd, &rx, 1);
        }

클럭 clk 에 의해 구동되는 쓰레드 함수 fir8_thread()는 아래와 같다.

        sc_signal<sc_uint<8> >  X[FILTER_TAP_NUM];

        void fir8_thread(void)
        {
            uint8_t     x;
            uint8_t     yL, yH;
            uint16_t    y;

            while(true)
            {
                wait(clk.posedge_event());
                x = (uint8_t)Xin.read();
                while(write(fd, &x, 1)<=0)  // Send Byte
                    usleep(100);

                for (int i=0; i<FILTER_TAP_NUM; i++)
                {
                    while(read(fd, &x, 1)<=0)  // Shift Register of X
                        usleep(100);
                    X[i].write(sc_uint<8>(x));
                }

                while(read(fd, &yL, 1)<=0)  // LSB of y
                    usleep(100);
                while(read(fd, &yH, 1)<=0)  // MSB of y
                    usleep(100);
                y = (uint16_t)(yH<<8) | (uint16_t)(yL);

                Yout.write(y);
            }
        }

클럭 clk에 상승 엣지 사건이 발생하면 에뮬레이션 보드로 8비트 Xin을 전송하면서 통신이 개시된다. 호스트 모듈(SystemC의 테스트벤치)은 에뮬레이터로부터 출력이 전송되기를 기다리며 시뮬레이터의 시간을 멈춘채 대기한다.

에뮬레이터는 직렬 포트로 전송된 x 를 받아 fir()을 호출하고 필터 계산을 수행한 뒤 그 결과를 호스트로 전송한다. 계산결과를 전송하기 전에 디버깅 목적으로 8개 쉬프트 레지스터 값을 먼저 내보낸다. 필터 함수 fir()의 계산 결과 y 는 16비트 이므로 2번에 걸쳐 전송된다. 이때 하위 바이트 먼저 전송하기로 하였다.

호스트의 SystemC 에뮬레이터 구동 모듈은 직렬 포트를 통해 전송된 8비트 데이터를 받아 이를 16비트로 재조립하여 Yout로 내보낸다. SystemC 시뮬레이터는 비로서 제어권을 받아 시간을 진행 시킨다.

디버깅 용으로 전송받은 쉬프트 레지스터의 값을 시간 순으로 VCD 기록한다.

#ifdef VCD_TRACE_FIR8
        // WAVE
        fp = sc_create_vcd_trace_file("sc_fir8");
        fp->set_time_unit(100, SC_PS);  // resolution (trace) ps
        sc_trace(fp, clk, "clk");
        sc_trace(fp, Xin,  "Xin");
        sc_trace(fp, Xout, "Xout");
        sc_trace(fp, Yin,  "Yin");
        sc_trace(fp, Yout, "Yout");
        char szTrace[8];
        for (int i=0; i<FILTER_TAP_NUM; i++)
        {
            sprintf(szTrace, "X_%d", i);
            sc_trace(fp, X[i], szTrace);
        }
#endif

6. 테스트벤치 재사용: 시뮬레이터와 에뮬레이션의 병행

에뮬레이션에서는 하위 SystemC 모듈로 구성 하였던  타임드 모형 sc_fir8.h 을 장치 구동 쓰레드 함수로 대체되었을 뿐 외형은 변함이 없다. 따라서 타임드 알고리즘의 시험에 사용했던 테스트 벤치를 변경없이 적용 한다. 시뮬레이션과 에뮬레이션이 병행된 검증용 메이크 파일은 다음과 같다.

    Makefile

메이크 유틸리티로 컴파일,

    ~$ cd
    ~$ cd ETRI-0.5u-CMOS-MPW-DK-Example--FIR8/0_algorithm/sc_emulated/
    ~$ make

실행,

    ~$ make run

아래 그림은 재활용된 테스트 벤치 sc_fir8_tb.h와 에뮬레이션 구동 모듈로 재구성된 sc_fir8.h 그리고 아듀이노 보드의 관계를 보여준다.

타임드 모델에서 sc_fir8,h 는 PE를 사례화 하고 어레이 구조를 구성 했었다. 이에 반해 에뮬레이션 모델은 아듀이노 보드와 통신하는 역활을 수행한다. 언타임드 모델의 fir8() 함수가 그대로 아듀이노 보드에 구현되어있다.

    타임드 모델의 sc_fir8.h

    에뮬레이션 모델의 sc_fir8.h
    아듀이노 보드에서 fir(), fir8_ino.ino

에뮬레이션의 결과를 VCD로 확인 할 수 있다. SystemC 테스트 벤치의 클럭 동기에 맞춰 에뮬레이션이 진행되고 있다.

참고] FIR8 예제 깃-허브:
    https://github.com/GoodKook/ETRI-0.5u-CMOS-MPW-DK-Example--FIR8.git

7. Co-Simulation/Co-Emulation

https://www.youtube.com/watch?v=Wr1XdpmyJ-w&t=58s


8. 시뮬레이션 가속(Simulation Acceleration) 참고문헌

1. UVM Simulation Acceleration, https://www.aldec.com/en/solutions/hardware_emulation_solutions/acceleration

2. Simulation Acceleration—Maximizing Simulator Performance, https://community.cadence.com/cadence_blogs_8/b/fv/posts/simulation-acceleration-maximizing-simulator-performance

3. Accelerating video and image processing design for FPGA using HDL coder and simulink, https://ieeexplore.ieee.org/abstract/document/7446221

4. A Full-System VM-HDL Co-Simulation Framework for Servers with PCIe-Connected FPGAs, https://par.nsf.gov/servlets/purl/10061085

5. Speeding-Up Simulation-Based Fault Injection of Complex HDL Models, https://ieeexplore.ieee.org/abstract/document/7781836

6. Linear Acceleration of HDL Simulation Using Naive Parallel Processing, https://webinars.sw.siemens.com/en-US/linear-acceleration-of-hdl-simulati/

7. Connecting reality and simulation: Couple high speed FPGAs with your HDL simulation, https://www.design-reuse.com/articles/13384/connecting-reality-and-simulation-couple-high-speed-fpgas-with-your-hdl-simulation.html

8. VHDL simulation acceleration using specialized functions, https://ieeexplore.ieee.org/document/621458

9. Simulation Acceleration with HW Re-Compilation Avoidance, https://ieeexplore.ieee.org/document/4450547

10. HDL Simulation Acceleration Solution for Microchip FPGA Designs, https://www.aldec.com/en/support/resources/documentation/whitepapers?file=2103

11. Integrating SystemVerilog and SCE-MI for Faster Emulation Speed, Developing your own Emulation API, https://www.aldec.com/en/company/blog/55--integrating-systemverilog-and-sce-mi-for-faster-emulation-speed


-------------------------------------------------------------
[이전] [1] FIR 알고리즘 및 병렬처리 구조 탐색
[다음]









2024년 3월 30일 토요일

SystemC는 여전히 최신 방법론인가?

SystemC는 여전히 최신 방법론인가?

반도체 설계에 언어가 사용된지 반세기가 지났다. 시스템 수준 설계 방법론 이라며 SystemC 를 제시한다. 새로운 컴퓨팅 언어를 다뤄야 한다면 그 부담이 크다. 내 분야가 아니라며 제쳐두던가 체계적인 학습을 기대하며 관련 학습 컨텐츠를 찾아보거나 교과서를 찾는다. 제쳐두면 당장 편할지 몰라도 미래는 없다. 학습을 원한다면 "체계적인"에 너무 집착하지 않기 바란다. 우리는 이미 컴퓨팅 언어에 익숙해 있다. 게다가 현재 컴퓨팅 실력이 체계적 교육의 결과였는지 되짚어보자. 관심과 연습의 결과였을 것이다. 예제를 찾아 적용해 보는 과정에서 실수를 반복하고 정정하는 과정에서 능력을 쌓아왔다. 컴퓨팅 언어의 예약어와 문법은 대동소이하다는 점을 알아두자. 하드웨어 언어와 소프트웨어 언어는 단지 구문의 실행 방식이 다를 뿐이다. 컴퓨터의 프로그램으로 병렬 실행을 모의하기 위해 사건기반의 콜백 함수 호출 기법(event drivel call-back)이 활용된다. 이는 컴퓨팅 언어의 특성이라기 보다 컴퓨터 운영체제와 인터럽트 서비스 같은 프로그래밍 기법의 이해가 필요하다. SystemC에 관한 각종 교육 컨텐츠는 많지만 '체계적'인 책은 많지 않다. 굳이 SystemC에 대한 체계적인 학습을 원한다면 아래의 책을 찾아보기 바란다.

System Design with SystemC, https://link.springer.com/book/10.1007/b116588

이 책은 2002년에 출판되었다. SystemC 가 1.0 때다(현재 3.0). SystemC의 를 원론적으로 설명한다. 시스템 수준 설계에 C++ 언어가 동원되고 병렬 시뮬레이션을 어떻게 모의하는지 설명한다. 하드웨어 언어 시뮬레이터의 원리를 이해할 수 있을 정도다. 여러명의 저자들에 의해 쓰여진 탓에 표현의 일관성이 흐트러져 아쉽다. 저자들은 모두 당시 현직 개발자들이었기 때문에 사용한 용어들이 어렵다. 한글 번역판[바로가기]이 있다. 번역판은 원 저자들과 서신을 주고 받으며 원문의 내용에 상당한 주석을 달았다. 도서관에 비치되어 있다면 굳이 구입할 필요 없다.

SystemC: From the Ground-Up, https://link.springer.com/book/10.1007/978-0-387-69958-5

SystemC 가 2.0으로 발전하며 표준화 된 이후 출판 되었다. 학습용으로 유용할 것이다. 초판의 한글 번역판[바로가기]이 출간 되었다. 초판에 애매한 부분이 상당히 있어서 번역본을 만들면서 저자와 교신하며 주석을 달았다. 현재 영문 책은 상당부분을 수정하여 2판이 나왔다. 서문에 초판 한글 번역자의 지적을 수정하였다고 밝히고 있다.

위의 책 외에도 SystemC를 설명한 책과 컨텐츠들이 다수 있다. 아쉽게도 SystemC를 마치 또다른 RTL 언어로 설명하고 그 수준에서 머무는 경향이 있다. SystemC는 시스템 수준의 모델링을 위해 활용될 때 그 가치를 찾을 수 있다. SystemC 는 C++ 그 자체다. 달리 말하면 하드웨어 설계를 위해 컴퓨터와 운영체제의 모든 요소를 활용 할 수 있다. 베릴로그 RTL로 설계한 6502 CPU를 검증하기 위해 Apple-1 컴퓨터를 SystemC로 모델링 한 예제가 있으니 살펴보기 바란다[바로가기].

SystemC가 표준화된지 20년이 지났음에도 쉽게 받아들여지지 않고 있는 이유는 방법론의 혁명성일지도 모른다. UCI(캘리포니아 대학교, 어바인) 2020년 대학원 강좌의 학습자료로 위에서 언급한 책들을 제시하고 있는 것을 보면 하드웨어 설계자(또는 교육자)들의 C++에 대한 이해부족(또는 게으름?)도 한몪한다.

https://newport.eecs.uci.edu/~doemer/w20_eecs222/syllabus.html

무려 20년전에 익혀둔 SystemC 를 변함없이 최신기법이라고 이야기 할 수 있는 것은 행운일까?

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


2024년 3월 28일 목요일

ETRI 0.5um CMOS DK 예제: FIR8 / [1] 알고리즘 및 병렬처리 구조 탐색

ETRI 0.5um CMOS DK 예제: FIR8

[1부] 알고리즘 및 병렬처리 구조 탐색

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

목차:

1. 개요

2. FIR 필터 알고리즘

    2-1. FIR 알고리즘의 언-타임드 모형 (Un-Timed C/C++ model)

    2-2. FIR 알고리즘의 타임드 모형(Timed C++/SystemC model)

        2-2-1. 타임드 모형 시뮬레이션 도구

        2-2-2. 언-타임드 모형의 구조 탐색

        2-2-3. 파이프라인 배열 구조 묘사

        2-2-3. 타임드 모형 테스트벤치

        2-2-5. 패드 제한(pad-limit) 검토

3. 예제 따라하기

4. 참고

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

1. 개요

내칩(My Chip) MPW에서 제공하는 칩은 크기는 제한되어 있다. 면적은 1900x1900um이며 패키지까지 제공 받으려면 28핀내에 설계되어야 한다[바로가기]. 디지털 설계의 경우 패드 라이브러리의 크기를 감안하면 코어의 설계 면적은 1000x1000um 이내로 제한된다. 이런 한도 내에서 구현할 수 있는 알고리즘은 많지않다. 경희대학교 반도체 전공 트랙에서 개발한 표준 셀 라이브러리 설계 키트[바로가기]를 사용했을 경우 8비트 가감산및 논리연산기와 3개의 8비트 레지스터, 8비트 곱셈기와 입출력 제어용 FSM을 넣을 수 있는 수준이다[바로가기].

규모있는 알고리즘을 구현하기 위한 방안으로 설계를 분할 하여 다수의 프로젝트를 지원해 보는 것도 한 방법이 될 수 있을 것이다. 또다른 방안은 파이프 라인 배열 구조로 구현하는 방법이다. 디지털 신호처리, 신경망[바로가기] 등의 알고리즘은 벡터 곱셈(콘볼루션)을 기초로 한다. 이 알고리즘들은 전형적인 병렬처리(Parallel Processing)/파이프라인(Pipeline)/배열연산기(Array Processing) 구조를 갖는다. MPW에서 10개 이상의 패키지된(!) 칩이 제공될 것으로 예상되므로 각 칩을 배열의 처리단위(PE, Processing Element)로 사용하는 방법이다.

[출처] https://youtu.be/GVsUOuSjvcg?si=D580dNr1eZ9mojgj&t=319

본 예제는 파이프라인 배열 구조에 적용될 디지털 FIR 필터[바로가기]의 PE다. MPW의 칩 제한 규정에 여유가 없으므로 8비트 부호없는 정수를 입력받아 처리하는 8탭 FIR 필터의 PE를 설계한다. 이렇게 느슨하게 설계된 필터의 용도는 매우 제한적이다. 좁은 대역폭을 갖는 SSB 음성 통신의 저대역 통과 필터로 사용할 수 있을 것이다[바로가기]. 예제의 원시 코드들의 깃-허브 저장소는 아래와 같다.

Git-Hub: https://github.com/GoodKook/ETRI-0.5u-CMOS-MPW-DK-Example--FIR8.git

깃-허브 저장소에서 예제의 소스코드들을 내려 받는 방법은 다음과 같다.

    ~$ cd
    ~$ git clone https://github.com/GoodKook/ETRI-0.5u-CMOS-MPW-DK-Example--FIR8.git
    ~$ cd ETRI-0.5u-CMOS-MPW-DK-Example--FIR8

깃-허브 원격 저장소는 원작자(그리고 허용된 참여자)에 의해 수시로 갱신된다. 그때마다 모두 내려받을 필요는 없다. 작업 폴더로 이동 한 후 원격저장소에서 갱신된 파일만을 내려 받는 git 명령은 pull 이다.

    ~$ cd
    ~$ cd ETRI-0.5u-CMOS-MPW-DK-Example--FIR8
    ~$ git pull


2. FIR 필터 알고리즘

FIR 필터의 '급수합' 알고리즘은 잘 알려져 있다[바로가기]. 이 알고리즘은 배열 구조 병렬처리에 적용되는 전형적인 예이기도 하다.


[출처] https://en.wikipedia.org/wiki/Finite_impulse_response

필터의 계수는 T-Filter 웹 도구[바로가기]를 통하여 구했다. 필터 탭의 계수가 갖는 수의 범위가 크지 않다.

위의 웹 도구를 통해 얻은 필터 계수를 활용한 C 코드는 다음과 같다.

    fir8.h

    fir8.cpp

필터를 시험하기 위한 테스트 벤치는 다음과 같다.

    fir8_tb.cpp

시험용 입력으로 몇가지 주파수를 갖는 신호에 백색 잡음을 혼합하여 생성하였다. 필터 알고리즘의 시험은 순수 C 프로그램 수준에서 실시한다. 하드웨어의 시간개념이 포함되지 않은 순수 C 코드로 작성된 모델을 "언-타임드(un-timed)" 라고 한다.

2-1. FIR 알고리즘의 언-타임드 모형 (Un-Timed C/C++ model)

개발 중 컴파일과 실행을 반복하게 된다. 그때마다 명령줄에서 매번 복잡한 옵션과 함게 명령입력을 해주려면 짜증나는 일이다. 메이크 유틸리티(make utility)를 사용하면 매우 유용하다[바로가기]. FIR 필터의 알고리즘 시험용 언-타임드 C 모델의 빌드와 실행을 용이하게 해줄 Makefile을 작성하였다.

    Makefile

필터 알고리즘 시험용 테스트 벤치는 한회에 4800개의 시계열 입력 자료를 생성하고 필터를 거친 출력을 얻는다. 수없이 나열된 숫자들을 보고 그 결과를 판단 할 수는 없다. 다양한 가시화 도구(visualization tools)를 갖춘 파이썬(Python)은 알고리즘 분석의 필수 도구다. FIR 필터 알고리즘을 시험한 결과를 시각화하기 위한 파이썬 코드는 아래와 같다.

    plotDFT.py

알고리즘의 언-타임드 시험을 해보자. C 모델이 저장된 폴더로 이동,

    ~$ cd
    ~$ cd cd ETRI-0.5u-CMOS-MPW-DK-Example--FIR8
    ~$ cd 0_algorithm/c_untimed

미리 만들어둔 메이크 파일로 컴파일 한다.

    ~$ make

그리고 실행,

    ~$ make run

필터를 거친 4800개의 숫자가 나열된다. 이들 숫자들을 보는 것으로 알고리즘의 결과를 확인해 보기는 불가능하므로 스펙트럼을 보며 필터 결과를 관찰해 보기로 하자. 집단지성의 덕분에 다양한 라이브러리들이 공개적으로 제공되는 파이썬은 알고리즘의 개발과 분석에 매우 효과적이다.  오늘날 컴퓨팅 언어로 가장 활용도가 높다[바로가기]. 파이썬의 도표 그리기 라이브러리는 matplotlib 다. 파이썬의 pip 도구를 사용해 라이브러리 추가 설치할 수 있다.

    ~$ python3 -m pip install -U matplotlib

파이썬 코드를 실행하여 필터링 된 출력 신호들의 주파수 파워 스펙트럼을 살펴보면 저역 필터의 효과를 확인 할 수 있다.


    ~$ make plot_fy

-------

2-2. FIR 알고리즘의 타임드 모형(Timed C++/SystemC model)

알고리즘을 하드웨어로 구현할 목적이라면 그에 맞게 레지스터 전송 수준(RTL, Register-Transfer Level)으로 기술되어야 한다. RTL에서는 클럭 단위로 하드웨어의 작동을 묘사한다. 아울러 각 객체들(신호선, 와이어)은 비트 단위로 상세히(clock/bit-detailed) 기술된다. 합성을 목표로 하는 경우 하드웨어 묘사는 추상화 수준이 낮은 RTL에서 이뤄진다. 하드웨어 언어는 기본적으로 동시작동 원칙에 절차적 행동을 묘사할 수 있는 장치를 갖추고 있지만 알고리즘의 개발과 시험에 사용할 만큼 높은 추상화 수준에 이르지 못한다. 게다가 동시실행성(concurrency)은 알고리즘 개발에 오히려 방해일 뿐이다.

2-2-1. 타임드 모형 시뮬레이션 도구

순수 C/C++ 는 컴퓨터에서 실행될 소프트웨어를 기술하는 언어로 컴퓨팅 언어의 최강자 자리에 있다. 진즉에 기계어(어셈블리어)를 밀어낸 C/C++는 폭넓은 추상화 수준을 수용할 수 있어서 응용 프로그램(application) 뿐만 아니라 운영체제(operating system), 장치 구동기(device driver) 제작에 사용된다. 하지만 하드웨어를 묘사할 수 있는 요소(동시실행과 절차성을 모두 함축한 클럭의 개념)를 갖추고 있지 않다.

최근 인공지능과 함께 연산전용의 (범용 컴퓨터에 비해 낮은 클럭으로 작동하는 저전력) 고성능 컴퓨팅 수요가 증가하고 있다. 대용량 FPGA를 보조 연산장치로 장착한 컴퓨터에서 알고리즘 개발 도구로 C/C++에서 직접 RTL로 변환하는 고위합성(HLS, High-Level Synthesis)이 실용화 단계에 이르럿다[바로가기][고위합성 튜토리얼]. HLS이 생성해내는 RTL 코드는 상당한 여분(redundancy)을 안고 있지만 재구성 가능한 FPGA를 사용하므로 크게 문제되지 않는다. 향후 고성능 컴퓨팅 방법으로 커다란 발전을 기대하고 있다[바로가기].

지난 수십년간 소프트웨어 언어로 기술된 알고리즘을 하드웨어로 구현하기 위해 RTL로 변환하는 방법이 수없이 등장했다 사라졌다[바로가기]. C/C++ 언어에서 부족한 시간의 개념을 도입하기 위해 여러 유사언어가 등장 했으나 2005년 SystemC가 IEEE 1666 [바로가기]으로 표준화된 이후  모두 사라졌다[바로가기]. 표준 C++ 만 남았다. SystemC는 하드웨어의 특성을 묘사하기 위한 C++ 크래스와 동시실행 시뮬레이션 엔진이 포함된 라이브러리다. 개발에 표준 C++ 컴파일러가 필요할 뿐이다.

2-2-2. 언-타임드 모형의 구조 탐색

본 예제는 FIR 필터의 배열형 병렬처리 계산기 구조를 탐색하고 처리단위를 모형화 한다. 하드웨어 구조의 병렬성을 묘사한 후 모의실험의 도구로 SystemC를 활용한다. 언-타임드 순수 C/C++로 작성된 알고리즘을 하드웨어로 구현하는 첫 단계는 변수들 사이의 의존관계를 따져 병렬성을 탐지해 내는 일이다. 이를 근거로 동시처리가 가능한 요소로 분할하고 클럭 단위의 스케쥴링을 수립한다.

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

두 구조는 각각 장단점이 있으므로 조건과 용도에 맞게 선택한다. 고위합성기 HLS를 활용하는 경우 원하는 하드웨어의 구조를 지정할 수 있다[HLS예 바로가기]. 본 예제는 HLS를 사용하지 않을 뿐더러 MPW 칩의 제한을 감안하여 배열 계산기 전체가 아닌 PE 만을 설계한다. SystemC로 기술한 PE는 아래와 같다.

    sc_fir_pe.h

배열구조의 한 처리요소 PE를 SystemC의 묘듈로 기술하면 아래와 같다.

SystemC로 기술된 내용을 보면 마치 새로운 언어처럼 보이지만 C++의 #define 매크로를 적극적으로 활용하여 마치 HDL의 외형과 유사해 보인다. 실제로 SC_MODULE()을 정의한 매크로는 다음과 같다.

    #define SC_MODULE(user_module_name)   \
        struct user_module_name : sc_module

따라서 위의 sc_fir_pe 는 아래와 같이 C++의 크래스를 의미한다.

    class sc_fir_pe : public sc_core::sc_module
    {
        public:
            ......
    }

하드웨어 모듈의 행동은 C++ 크래스의 소속함수로 기술한다. SC_CTOR() 매크로는 모듈이 사례화(instantiate) 될 때 처음 실행되는 크래스 구성자(constructor)다. 소속함수를 클럭의 사건에 감응(sensitize)토록 지정하였다.

C++의 추상화 수준은 프로그래밍 언어의 최고 위치에 있을 뿐만 아니라 폭넓은 범위를 수용한다. SystemC는 C++의 크래스와 각종 객체를 유연하게  선언할 수 있도록 허용하는 템플릿(C++ class template, 바로가기)을 매우 폭넓게 활용하고 있다. C++ 언어의 진수를 보여준다고 할만하다. 프로그래밍 언어에 익숙치 않은 하드웨어 기술자에게 매우 낮설 수 있지만 그동안 쌓아온 경험을 가지고 예제들을 읽어보면 상식적인 수준에서 이해될 수 있을 것이다. 위의 PE를 기술한 모듈의 소속함수를 읽어보기 바란다. 베릴로그 HDL에 비하여 어렵지 않을 것이다.

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

주] SystemC는 새로운 설계방법론일까? [바로가기]

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

FIR8의 처리요소 PE는 매 클럭당 계수 곱셈과 누산을 수행한다. 소속함수 pe_thread()는 입력 clk의 변화(사건, event)에 호출되도록 감응이 지정되었고 내부 행동은 clk의 상승 엣지 사건 일때 까지 대기한다.

    wait(clk.posedge_event());

언-타임드 모형에서 함수호출은 프로그래머가 놓아둔 구문의 순서를 따르지만 SystemC로 기술된 쓰레드(또는 메쏘드)함수는 지정된 신호의 사건에 의해 시뮬레이터가 호출한다. 그리고 구문수행에 시간의 개념(클럭 동기)이 포함되어 있다. 이를 '타임드(timed)' 모형이라고 한다. 시간은 병렬실행을 모사하는 기준이다. 사건이 발생하면 시뮬레이터는 시간을 멈춰놓은 후 이에 감응이 지정된 모든 함수를 호출한다(event & call-back). 각 함수의 출력을 검사하여 다음 시간에 일어날 사건들을 수집하고 시간을 진행 시킨다. 시뮬레이터가 하드웨어의 병렬수행을 모의하는 작동 원리다. SystemC는 C++의 크래스(class)와 템플릿(template)를 활용하여 하드웨어 객체(입출력 방향 및 와이어와 레지스터)를 표현하며 병렬 시뮬레이터를 내장한 라이브러리다.

2-2-3. 파이프라인 배열 구조 묘사

파이프라인 처리 배열구조 병렬처리 계산기는 별도의 제어기 없이 데이터의 흐름 만으로 알고리즘을 수행한다. 초기 클럭 지연 이후 매 클럭마다 결과를 내므로 낮은 클럭율(clock rate)의 매우 효율적(고속 및 저전력)인 전용 하드웨어 구조다. 위에서 설계한 8개의 처리요소 PE들을 사용한 배열을 구조를 묘사하면 아래와 같다.

    sc_fir8.h

병렬처리 배열구조에 입력과 출력 그리고 클럭 이외의 다른 제어선은 없다.

    SC_MODULE(sc_fir8)

    {
        sc_in<bool>             clk;
        sc_in<sc_uint<8> >      Xin;
        sc_out<sc_uint<8> >     Xout;
        sc_in<sc_uint<16> >     Yin;
        sc_out<sc_uint<16> >    Yout;

        sc_fir_pe*      u_fir_pe[N_PE_ARRAY];

        sc_signal<sc_uint<8> >  X[N_PE_ARRAY-1];    // X-input
        sc_signal<sc_uint<16> > Y[N_PE_ARRAY-1];    // Accumulated
        sc_signal<sc_uint<8> >  C[N_PE_ARRAY];      // Filter-Tabs Coeff

        SC_CTOR(sc_fir8): clk("clk"),...
        {...}

        .....
    };

모듈 크래스 SC_MODULE 의 구성자 내에서 N_PE_ARRAY=8개의 sc_fir_pe 를 하위 모듈로 생성(사례화, instantiate)하고 이들 사이에 시그널 채널(signal channel)을 통해 연결 한다. SystemC의 채널은 베릴로그의 하드웨어 객체, 레지스터 reg 와 같다.

    SC_CTOR(sc_fir8): clk("clk"), Xin("Xin"), ...... , Yout("Yout")
    {
        char    szPeName[16];
        for (int i=0; i<N_PE_ARRAY; i++)
        {
            sprintf(szPeName, "u_PE_%d", i);
            u_fir_pe[i] = new sc_fir_pe(szPeName); // Instantiate PE

            C[i].write(sc_uint<8>(filter_taps[i])); // Set Coeffs.

            u_fir_pe[i]->Cin(C[i]);    // Bind Coeffs.
            u_fir_pe[i]->clk(clk);     //  and Clock
        }

        // 0-th PE
        u_fir_pe[0]->Xin(Xin);
        u_fir_pe[0]->Xout(X[0]);
        u_fir_pe[0]->Yin(Yin);
        u_fir_pe[0]->Yout(Y[0]);

        // Systolic Array
        for (int i=1; i<N_PE_ARRAY-1; i++)
        {
            u_fir_pe[i]->Xin(X[i-1]);
            u_fir_pe[i]->Xout(X[i]);
            u_fir_pe[i]->Yin(Y[i-1]);
            u_fir_pe[i]->Yout(Y[i]);
        }

        // Last PE
        u_fir_pe[N_PE_ARRAY-1]->Xin(X[N_PE_ARRAY-2]);
        u_fir_pe[N_PE_ARRAY-1]->Xout(Xout);
        u_fir_pe[N_PE_ARRAY-1]->Yin(Y[N_PE_ARRAY-2]);
        u_fir_pe[N_PE_ARRAY-1]->Yout(Yout);

    }


2-2-4. 타임드 모형 테스트벤치

배열구조 sc_fir8를 시험하기위한 테스트 벤치는 다음과 같다.

    sc_fir8_tb.h

피시험 설계물(DUT, Design Under Test) sc_fir8의 입출력에 연결한 시그널 채널 sc_signal<>들을 테스트벤치 크래스 내에 선언하였다. 상위 테스트벤치는 입출력 신호를 갖지 않도록 했다. 테스트 벤치 크래스는 두 소속함수를 가지는데 각각 시험용 신호의 생성과 DUT로부터 출력되는 필터의 결과를 취하여 언-타임드 알고리즘 계산과 비교한다.

    SC_MODULE(sc_fir8_tb)
    {
        sc_clock                clk;
        sc_signal<sc_uint<8> >  Xin;
        sc_signal<sc_uint<8> >  Xout;
        sc_signal<sc_uint<16> > Yin;
        sc_signal<sc_uint<16> > Yout;

        sc_fir8*                u_sc_fir8;

        // Test utilities
        void Test_Gen();
        void Test_Mon();

        SC_CTOR(sc_fir8_tb):
            clk("clk", 100, SC_NS, 0.5, 0.0, SC_NS, false),......
        { .... }

    };

구성자에서 테스트 벤치 크래스를 구성하면서 모듈 내에서 사용될 포트와 채널들의 초기화는 객체에 이름 붙이기다. 이는 디버깅용으로 필수 사항은 아니다. 클럭 객체 sc_clock의 경우 특별히 클럭 발생기로서 작동하도록 초기화한다. 아래 예에서 sc_clock 객체로 선언된 clk는 주기 100 나노 초, 듀티 비 0.5로 반복적인 클럭 신호를 생성한다. 

        SC_CTOR(sc_fir8_tb):
            clk("clk", 100, SC_NS, 0.5, 0.0, SC_NS, false),
            Xin("Xin"), ...... , Yout("Yout")
        {
            SC_THREAD(Test_Gen);
            sensitive << clk;

            SC_THREAD(Test_Mon);
            sensitive << clk;

            // Instaltiate FIR8
            u_sc_fir8 = new sc_fir8("u_sc_fir8");
            u_sc_fir8->clk(clk);
            u_sc_fir8->Xin(Xin);
            u_sc_fir8->Xout(Xout);
            u_sc_fir8->Yin(Yin);
            u_sc_fir8->Yout(Yout);

        }

테스트벤치 모듈 내의 두 소속함수는 쓰레드로 작동하기 위해 SC_THREAD()로 지정하였고 clk로 감응 되었다. 두 스레드 소속함수는 별도의 파일로 작성되었다.

    sc_fir8_tb.cpp

DUT에 주입될 시험 신호 생성용 쓰레드 함수는 Test_Gen() 아다. 모듈 크래스의 소속함수로 신호의 사건에 감응되어 호출될 메쏘드 또는 쓰레드 함수는 입력과 되돌림이 없어야 한다.

    void sc_fir8_tb::Test_Gen()
    {
        double      X_in[F_SAMPLE]; // Noise
        uint16_t    yn;
        int         t = 0;

        // Generate tests & reference from C-Model 
        srand(time(NULL));
        cnoise_generate_colored_noise_uniform( X_in, F_SAMPLE, 0, NOISE_RANGE );

        for (t=0; t<F_SAMPLE; t++)
        {
            x[t] = sc_uint<8>(AMPLITUDE/16.0
                            *
(cos((2*M_PI/F_SAMPLE)*51.0*t
                                    +(float)(rand() %  10)/ 10.0)+1))
                  + ......
                  + sc_uint<8>(X_in[t]+NOISE_RANGE);

            fir(&yn, x[t]); // Un-Timed C-Model FIR Filter

            y[t] = yn;
        }

        Yin.write(0);

        t = 0;

        while(true)
        {
            wait(clk.posedge_event());
            Xin.write(x[t]);
            t = ((++t) % F_SAMPLE);
        }
    }

몇개의 각기 다른 주파수의 유효신호와 백색잡음을 섞어 시험신호를 생성한다. 이 값들을 언-타임드 알고리즘에 주고 그 결과를 DUT 출력과 비교하기 위해 담아 두었다. 쓰레드 함수는 한번 호출되면 재호출 되지 않는다. 따라서 함수내에 무한 반복문 while(true) {......} 을 포함한다. 시그널 clk에 감응된 이 쓰레딩 함수는 상승 엣지 사건을 대기 후 재개한다.

테스트벤치 크래스의 다른 쓰레드 함수 Test_Mon()은 DUT의 출력과 표준 참조값과 비교하여 오류를 검사한다.

    void sc_fir8_tb::Test_Mon()
    {
        int         n = 0;
        uint16_t    yout;

        FILE *fp = fopen ( "sc_fir8_tb_out.txt", "w" );

        while(true)
        {
            wait(clk.posedge_event());
            yout = (uint16_t)Yout.read();

            if (yout==0)    continue;

            if (y[n]!=yout)
                printf("Error:");

            printf("[%4d] y=%d / Yout=%d\n", n, (uint16_t)y[n], yout);
            fprintf(fp, "%5d %5d\n", (uint16_t)x[n], (uint16_t)yout);   //y[i]);

            n++;
            if (n==F_SAMPLE)
            {
                fflush(fp);
                fclose(fp);
                sc_stop();
            }
        }
    }

매 클럭마다 DUT의 출력을 취하도록 clk의 상승 엣지 사건에 대기 후 비교를 재개한다. 시험을 마친 후 파일에 저장해 두었던 결과는 파이썬 프로그램으로 시각적 분석한다. 다양한 수리 라이브러리를 활용할 수 있는 파이썬은 과학기술 용으로 매우 유용하게 사용된다.

    sc_plotDFT.py

SystemC로 작성한 타임드 모형의 시뮬레이션 Makefile은 아래와 같다.

    Makefile

SystemC로 작성된 코드에서 읽어들일 인클루드 폴더의 지정과 링크용 라이브러리 그리고 컴파일 후 실행시 필요한 동적 라이브러리(so, shared-object)의 위치등을 변수로 설정해 놨다.

    export SYSTEMC          = /usr/local/systemc-3.0.0
    export SYSTEMC_HOME     = $(SYSTEMC)
    export SYSTEMC_INCLUDE  = $(SYSTEMC_HOME)/include
    export SYSTEMC_LIBDIR   = $(SYSTEMC_HOME)/lib-linux64
    export LD_LIBRARY_PATH :=$(LD_LIBRARY_PATH):$(SYSTEMC_LIBDIR)
    export CXX              = clang++
    export CXXFLAGS         = -std=c++17

시뮬레이션을 수행하려면 명령줄에서 작업 폴더로 이동,

    ~$ cd
    ~$ cd cd ETRI-0.5u-CMOS-MPW-DK-Example--FIR8
    ~$ cd 0_algorithm/sc_timed

메이크 유틸리티로 빌드,

    ~$ make

실행,

    ~$ make run

SystemC는 VCD(Value-Changed Dump) 파형 기록을 지원한다. 타임드 시뮬레이션을 수행하며 시간상 발생한 시그널 채널과 포트의 사건을 VCD형식 파형으로 기록할 수 있다.


신호처리 알고리즘들은 수없이 많은 자료를 다룬다. 입출력 신호를 파형으로 살펴보기는 지루하기 짝이 없는 노릇이지만 개발중 확인 용도로 유용하다.

2-2-5. 패드 제한(pad-limit) 검토

클럭 및 비트 단위 상세히 기술된 경우 언어에 상관 없이 수월하게 합성 할 수 있다. SystemC로 작성된 PE의 타임드 모형은 합성이 가능할 정도의 RTL로서 언타임드 알고리즘과 비교 검증 역시 완료되었다. 하지만 '내칩(MyChip)' MPW의 핀수 조건을 만족하지 못한다. PE의 코어가 차지할 면적이 작지만 외부로 연결된 핀의 갯수가 무려 60여개에 이른다. 데이터 패쓰는 디지털 설계의 큰 골칫꺼리다. 이의 해결을 위해 클럭 소모를 감수하고 비트 단위 또는 디지트 단위 입출력과 연산을 고려해야 한다.

3. 예제 수행

깃-허브에서 예제 다운로드

    $ cd
    $ git clone https://github.com/GoodKook/ETRI-0.5u-CMOS-MPW-DK-Example--FIR8.git

FIR8의 언타임드 시뮬레이션

    $ cd
    $ cd ETRI-0.5u-CMOS-MPW-DK-Example--FIR8/0_algorithm/
    $ cd c_untimed
    $ make
    $ make run
    $ make plot_fy

배열형 병렬 계산기 구조 처리단위(PE, processing element)의 타임드 시뮬레이션

    $ cd
    $ cd ETRI-0.5u-CMOS-MPW-DK-Example--FIR8/0_algorithm/
    $ cd sc_timed
    $ make
    $ make run


4. 참고

Git-Hub:

1. 디자인 킷, https://github.com/GoodKook/ETRI-0.5um-CMOS-MPW-Std-Cell-DK.git

2. 예제 ALU8, https://github.com/GoodKook/ETRI-0.5u-CMOS-MPW-DK-Example--ALU8.git

3. 예제 FIR8, https://github.com/GoodKook/ETRI-0.5u-CMOS-MPW-DK-Example--FIR8.git 

유용한 바로가기:

1. KION MPW 안내문 공지: http://mpw.kion.or.kr/info/notice_list.asp

2. Design of FIR Filters, https://www.robots.ox.ac.uk/~gari/teaching/cdt/A3/readings/Filtering_and_FFT/3F3_5_Design_of_FIR_Filters.pdf

3. Finite Impulse Response, https://en.wikipedia.org/wiki/Finite_impulse_response

4. TFilter, http://t-filter.engineerjs.com/

5. Make 유틸리티 강좌, http://ebook.pldworld.com/_eBook/make/make_utility_lecture_(cWyANG).pdf

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

7. 고위합성 튜토리얼, https://hls-goodkook.blogspot.com/2021/08/ug871-xilinx-high-level-synthesis.html

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

9. oneAPI DPC++(Data Parallel C++), https://www.intel.com/content/www/us/en/developer/tools/oneapi/dpc-compiler.html

10. High-Level Synthesis, https://en.wikipedia.org/wiki/High-level_synthesis

11. IEEE1666 SystemC LRM, https://ieeexplore.ieee.org/document/10246125

12. SystemC, https://en.wikipedia.org/wiki/SystemC

13. SystemC는 새로운 설계방법론일까?, https://fun-teaching-goodkook.blogspot.com/2024/03/systemc.html

14. 클래스 템플릿, https://learn.microsoft.com/ko-kr/cpp/cpp/class-templates

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

[다음] [2] 아듀이노 보드 에뮬레이션







2024년 3월 25일 월요일

반도체 설계 언어, 예제를 모아두면 편리하다

반도체 설계 언어, 예제를 모아두면 편리하다

반도체 설계에 동원되는 컴퓨팅 언어들은 한두가지가 아니다. 베릴로그, VHDL 을 포함한 하드웨어 기술 언어뿐만 아니라 시스템 모형과 알고리즘 개발 그리고 검증용으로 C/C++, 파이썬 등이 있다. 언어에 더하여 엄청나게 다양한 API들을 활용해야 하는데 일일이 다 외우기는 커녕 그 활용법 조차 만만치 않다. 천여쪽에 달하는 언어의 LRM(Language Reference Manual) 앞에 질리지 말자.

언어의 기본적인 특성 정도 만 이해했다면 예제를 통해 익히는 방법이 좋다. 실예로 if~else~ 구문은 어떤 컴퓨팅 언어에도 등장하고 그 의미는 다르지 않다. for() 반복문도 마찬가지다. 물론 구문의 행동, 구문이 낳게될 결과는 다소 차이가 있지만 사용하면서 연습을 통해 익히도록 하자. 구문의 다양한 활용법 예제를 가지고 있다면 큰 도움이 된다. 참고하기 좋은 사이트와 저장소를 소개한다.

베릴로그의 예제들,
https://github.com/aklsh/getting-started-with-verilog

파이썬의 과학기술 활용,
https://pythonnumericalmethods.berkeley.edu/

C++ 표준 라이브러리
https://cplusplus.com/reference/

Learn SystemC with Examples,
https://www.learnsystemc.com/

Make 유틸리티
https://wiki.kldp.org/KoreanDoc/html/GNU-Make/GNU-Make-1.html

그리고 실용적인 예제들을 ETRI 0.5um CMOS MPW 예제와 함께 게시판과 깃-허브( https://github.com/goodkook )에 지속적으로 올리겠다.


* 도서모음

https://github.com/rangaeeeee/books-raspberrypimagazines