2025년 2월 15일 토요일

레이아웃을 그린다면서 디자인 룰 보는 법을 모르면 어떻합니까...

레이아웃을 그린다면서 디자인 룰 보는 법을 모르면 어떻합니까...

MyChip 서비스 웹 페이지의 게시판의 질문도 그렇지만 지난 정선에서 열렸던 KSC의 MyChip 전시 부스에 머물면서 학생들의 이야기를 들어보니 생각이 참 많아집니다. 대부분 학생들이 아날로그 회로 그리기 도구를 질문 하길래 왜 아날로그에 관심이 많은지 물어보니 "디지탈 회로는 툴이 다 해주잖아요" 였습니다.

반도체 설계를 레이아웃 그리기로 이해하는 듯 해서 안타 까웠습니다. '알고리즘'은 없고 트릭만 있다는 생각을 지울 수 없습니다. 더욱 아쉬웠던 부분은 레이아웃을 한다면서 디자인 룰 북을 이해하지 못하는 것 같았기 때문입니다. 적어도 디자인 룰 북을 읽고 레이어 들을 공정과 설계 도구에 연계하여 이해하고 있는지 의문이 듭니다.

반도체 설계 교육에서 고가의 설계도구가 문제라 하는데 굳이 오픈-소스를 강권하지 않더라도 상용 도구들을 아름 아름 라이센스 패치해서 사용하고 있지 않습니까? 

반도체 설계교육이 어떻게 되가는지 쓸데없는 걱정이길 바랍니다.

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

MyChip 서비스 웹 페이지의 게시판의 최근 질문에 답을 달아 봅니다.

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

질문: 피코(p)단위의 [ ex)11p ] cap 값을 만들려고 합니다. width와 length 값만 조절해서 커패시터를 만들면 사이즈가 매우 커지게되어 cox 값을 조정하려고 합니다.

답: 디자인 룰 북에 따르면 평방 마이크로 미터당 0.5 펨토 패럿이니 피코 단위로 하려면 단순히 계산해도 2천 평방 마이크로 미터는 되야 합니다.너무 큽니다.커패시터의 용량은 극판 면적 혹은 간격에 영향을 받으니 옥사이드 두께를 줄이고 싶을 겁니다. 수많은 실험을 거쳐 확립한 공정이므로 원한다고 변경하는 것은 않됩니다.

ATMEL사의 AVR 마이크로프로세서 회로도를 보면 크리스탈 양단에 10 피코 패럿 커패시터를 붙여놓고 있습니다. 이 커패시터와 크리스털이 없으면 깔끔 하지만 밖에 꺼내 놓은 이유를 생각해 보세요. FTDI 사의 USB 시리얼 통신 칩에는 외부 클럭 발진 회로가 없다는 강점을 가지고 꾿꾿하게 시장에서 살아 남았습니다. 칩내부에 발진기를 내장하는 PLL에 대해서도 생각해 보십시요. 낮은 주파수의 발진기를 칩 내에 내장하기는 매우 곤란 합니다. 이 모든 것들이 커패시터의 용량과 관계되어 있습니다.

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

질문: 레이아웃에서 pipcap의 parameter(width, length, multiplier)가 고정되어 있는데 변경할 수는 없나요? 변경이 불가능해서 직접 POLY1, POLY2 그려서 pipcap을 구현했는데 LVS에서 cap으로 인식이 안 되었습니다.

답: 직접 POLY1, POLY2 를 겹쳐 그려 놓으면 cap 처럼 작동 하지만 LVS 툴은 그것이 회로도의 cap인줄 모릅니다. 그저 끊겨있는 선일 뿐입니다. 설계자가 이 부분은 cap 이므로 네트리스트 추출에 반영 시키라고 지정해 주어야 합니다. 그렇지 않으면 그냥 기생 cap으로 나오므로 LVS 하면 불일치하게 됩니다.

디자인 룰 북에 보면 나와있는 레이어 정보를 이해해야 합니다. 실제 공정에 사용하는 레이어는 2.1 입니다. 그외 LVS, DRC 용 레이어는 설계 참조용 입니다. 첨부된 그림은 디자인 룰에 pipcap 항목입니다. CAP 영역을 지정하고 LVSD 를 지정하고 있습니다.

첨부 그림은 오픈 소스 레이아웃 툴 KLayout으로 PCELL 중 pipcap을 읽어본 것입니다. CAP 레이어(53)를 지정하고 LVSD 레이어(60)을 볼 수 있습니다. 이 레이어들은 실제 마스크 제작용이 아닙니다. 설계 참조용 입니다. 레이아웃에서 회로 네트리스트를 추출할 때 이를 참조하여 회로 부품으로 생성합니다.

레이아웃 도구는 그저 그림판 입니다. 레이아웃은 AutoCAD 같은 벡터 드로우잉 소프트웨어로도 그릴 수 있습니다. 반도체 레이아웃 도구는 특정 레이어가 그려진 모양에서 전자회로 부품을 판단하고 추출해주는 기능이 더해 있습니다. 디퓨젼과 폴리실리콘이 겹쳐 있으면 트랜지스터로 인식해 줍니다만 그외 저항이나 커패시터는 자동으로 인식하지 못하므로 설계자가 해당 부분의 의도를 표시해 주어야 합니다.

* 반도체 레이아웃 도면 양식을 개발한 Calma 사는  반도체와는 크게 관련 없습니다. GDS는 Graphic Design System의 약자로 지도, 기구도면, 건축도면 등 범용 벡터 그래픽을 표현하는 양식으로 개발 되었습니다. [https://en.wikipedia.org/wiki/Calma]

2025년 2월 4일 화요일

ETRI 0.5um CMOS DK 예제: FIR8 / [4] PC 사운드 카드 오실로스코프

ETRI 0.5um CMOS DK 예제: FIR8 / [4] PC 사운드 카드 오실로스코프

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

[주의] PC 사운드 카드를 ADC/DAC로 사용하는 것은 위험!!!

아무리 조심 한다고 해도 PC 내장 사운드 칩을 한순간에 태워먹을 수 있습니다. 이를 방지하려고 별도 외장 USB 사운드 장치를 찾아봤으니 스테레오 라인 입력을 지원하는 장치는 흔치도 않고 가격이 만만치 않습니다. (실험하다가 USB 장치 이미 두개 태워 먹음!)

라즈베리 파이 피코를 활용하여 샘플링 하고 스마트 폰에서 디스플레이 할 수 있는 앱 scoppy 를 시험 해보니 쓸만 합니다. 라즈베리 파이 피코 와이파이 버젼으로 연결 할 수도 있어서 매우 안전 합니다. 적어도 스마트 폰 태워 먹을 일은 없을 듯! 게다가 PhoneLink 로 PC에서 스마트 폰 화면을 끌어올 수 있으니 편리 합니다.

알리에서 라즈베리 파이 피코 2천원, 와이파이 버젼 7천원에 팔고 있길래 주문해 뒀으니 작동 시킬 수 있는지 확인해 보고 알려 드리겠습니다.

PC 사운드 카드를 ADC/DAC로 사용하는 것은 위험하니 행여 따라하려고 했다면 주의하세요.

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

오실로스코프는 멀티미터와 함께 실험실 필수품이다. 멀티미터는 3천원이면 구비할 수 있지만 오실로스코프는 제아무리 알리상회라 해도 십여만원은 줘야 한다. 주머니 사정이 여의치 않다면 아쉬운 대로 만들어 보기로 한다.

샘플링 레이트가 고작 48Khz에 불과 하지만 PC의 사운드 카드는 훌륭한 ADC/DAC 장치다.  수십만원 짜리 오실로스코프의 ADC 해상도가 8/16비트인 점에 비하면 PC 사운드 카드는 16/24비트다. 다만 라인 입력 입력 신호의 레벨이 낮아서(1Vpp) 잘못하면 컴퓨터를 태워 먹을 수도 있으니 버퍼를 달아 주도록 하자.

AC 신호를 처리하기 위해 +/- 양 전원이 필요하다.

사운드카드 입력 버퍼를 만들면서 Op Amp의 반전 단일 증폭기(Gain=1)도 알아보자. 다이오드는 전압강하 용이다. PC 사운드 카드 입력 레벨을 감안하여 약 +/-0.65볼트로 떨어 트린다. 직렬 저항들은 전류 제한 용이다.

+/- 양 전원장치가 없다면 간단히 만들어 볼 수 있다. 저항 두개로 분압기(voltage divider)를 만들 수 있다. 단일 이득(gain=1)을 갖는 Op Amp를 사용하 전원공급(9Vin)의 접지와 회로에 들어갈 +/- 4.5V의 GND를 분리해 주었다.

위 회로의 출처는 아래와 같다. 세상은 넓고 아이디어가 넘친다.

[출처] PC Soundcard Oscilloscope buffer/attenuator. Especially for Visual Analyser.
https://www.youtube.com/watch?v=uTDFYQrQMLc

PC 사운드 카드 오실로스코프를 가지고 내 칩 MPW 를 통해 만든 FIR_PE 칩을 테스트 해봤다. 입력 버퍼를 빵판에 꾸며서 그런지 샘플 신호가 기울고 있지만 디지털 칩의 동작을 확인 하는데 충분하다. 아래 움직이는 그림은 Vld(칩의 출력)와 Rdy(칩의 입력)를 관찰한 것이다.  입력 Rdy가 5 클럭 후 칩의 출력 Vld로 나오는 것을 확인 하였다.


PC Scope 소프트웨어는 Room Acoustics Software-REW다. 사운드 카드를 이용한 음향 시설 분석용인데 무료다.

https://www.roomeqwizard.com/

"내 칩 MPW"로 만든 칩이 동작한 탓에 해볼 것 들이 한두가지가 아니다.

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

[이전] [3] 칩 테스트 장치









2025년 1월 30일 목요일

WSL/Ubuntu 22.04 재설치

WSL/Ubuntu 22.04 재설치

[주] NSPL 0.5um CMOS 오픈-소스 디자인 킷을 활용한 설계 환경이 WSL2/Ubuntu 20.04 기반에서 22.04로 변경 합니다. 큰 차이점이라면 gcc/g++, clang/clang++ 버젼이 9에서 11로 업그레이드 되어서 c++2a 표준을 지원 합니다. 일부 오픈-소스 도구에서 요구하던 <coroutine> 을 쓸 수 있고, Python3 는 3.10으로 변경되어 병렬처리 등이 강화 되었습니다.

Contents:

    Step 1) Shutdown WSL
    Step 2) Uninstall Ubuntu 20.04 (CCleaner)
    Step 3) Unregister Old Ubuntu 20.04
    Step 4) Check if "VHDX" file removed & Clean Registry (CCleaner)
    Step 5) At Microsoft Store, "Get" & "Install" Ubuntu 22.04.5 & "Open" it.
    Step 6) Move Virtual disk to other location
    Step 7) Set default user
    Step 8) Unique Apps for Open-Source EDA

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

Step 1) Shutdown WSL

    PS> wsl --shutdown
    PS> wsl -l -v

Step 2) Uninstall Ubuntu 20.04 (CCleaner)

Step 3) Unregister Old Ubuntu 20.04

    PS> wsl --uninstall
    PS> wsl --unregister Ubuntu-20.04
    PS> wsl -l -v
    PS> wsl --set-default-version 2
    PS> wsl --update

Step 4) Check if "VHDX" file removed & Clean Registry (CCleaner)

Step 5) At Microsoft Store, "Get" & "Install" Ubuntu 22.04.5 & "Open" it.

    Then you may see followings;

        Installing, this may take a few minutes...
        Please create a default UNIX user account. The username does not need to match your Windows username.
        For more information visit: https://aka.ms/wslusers
        Enter new UNIX username: goodkook
        New password:
        Retype new password:
        passwd: password updated successfully
        Installation successful!
        To run a command as administrator (user "root"), use "sudo <command>".
        See "man sudo_root" for details.
        
        Welcome to Ubuntu 22.04.5 LTS (GNU/Linux 5.15.167.4-microsoft-standard-WSL2 x86_64)
        
        * Documentation:  https://help.ubuntu.com
        * Management:     https://landscape.canonical.com
        * Support:        https://ubuntu.com/pro
        
        System information as of Thu Jan 30 17:44:38 KST 2025
        
        System load:  0.29                Processes:             32
        Usage of /:   0.1% of 1006.85GB   Users logged in:       0
        Memory usage: 1%                  IPv4 address for eth0: 172.17.11.1
        Swap usage:   0%
        This message is shown once a day. To disable it please create the
        /home/goodkook/.hushlogin file.
        goodkook@GoodKook-Skull:~$

Step 6) Move Virtual disk to other location;

    6-1: Create D:\WSL2

    6-2: Install git for Windows

        https://git-scm.com/download/win

    6-3: Move to ...

        PS> wsl -l -v
        PS> wsl --shutdown
        PS> cd d:\WSL2
        PS> git clone https://github.com/pxlrbt/move-wsl.git
        PS> cd move-wsl
        PS> ./move-wsl.ps1

    6-4: Then, you may see followings;

        PS D:\WSL2\move-wsl>
        PS D:\WSL2\move-wsl> ./move-wsl.ps1
            Getting distros...
            Select distro to move:
            1: Ubuntu-22.04
            1
            Enter WSL target directory:
            d:\WSL2
            Move Ubuntu-22.04 to "d:\WSL2"? (Y|n): Y
            Exporting VHDX to "d:\WSL2\Ubuntu-22.04.tar" ...
            Export in progress, this may take a few minutes..wsl: Unknown key 'user.default' in C:\Users\goodkook\.wslconfig:2
        
        The operation completed successfully.
        Unregistering WSL ...
        Importing Ubuntu-22.04 from d:\WSL2...
        Import in progress, this may take a few minutes....wsl: Unknown key 'user.default' in C:\Users\goodkook\.wslconfig:2
        
        The operation completed successfully.
        Cleaning up ...
        Done!

    If it wouldn't run,

        PS> Set-ExecutionPolicy Unrestricted    

    6-5: Check the VHDX moved,

        PS D:\WSL2\move-wsl> cd ..
        PS D:\WSL2> ls
    
            Directory: D:\WSL2
    
        Mode                 LastWriteTime         Length Name
        ----                 -------------         ------ ----
        d----          24/05/2024    22:56                move-wsl
        -a---          30/01/2025    17:58     1326448640 ext4.vhdx    

    6-6: Launch Ubuntu with <user name>

        PS D:\WSL2> wsl -u goodkook

        wsl: Unknown key 'user.default' in C:\Users\goodkook\.wslconfig:2
        To run a command as administrator (user "root"), use "sudo <command>".
        See "man sudo_root" for details.
        
        goodkook@GoodKook-Skull:/mnt/d/WSL2$ cd
        goodkook@GoodKook-Skull:~$ pwd
        /home/goodkook
        goodkook@GoodKook-Skull:~$ whoami
        goodkook

    6-7: Pin "Ubuntu 22.04.5" to task-bar

    

Step 7) Set default user,

    7-1: in the file, C:\Users\goodkook\.wslconfig

            [user]
            default=goodkook

            [wsl2]
            memory=24GB

    7-2: Set default user.

        Open Ubuntu terminal, you may see welcome message, logged with "root" at this time;

        Welcome to Ubuntu 22.04.5 LTS (GNU/Linux 5.15.167.4-microsoft-standard-WSL2 x86_64)
        
        * Documentation:  https://help.ubuntu.com
        * Management:     https://landscape.canonical.com
        * Support:        https://ubuntu.com/pro
        
        System information as of Thu Jan 30 18:14:17 KST 2025
        
        System load:  0.0                 Processes:             62
        Usage of /:   0.1% of 1006.85GB   Users logged in:       0
        Memory usage: 1%                  IPv4 address for eth0: 172.17.11.1
        Swap usage:   0%
        
        
        This message is shown once a day. To disable it please create the
        /root/.hushlogin file.
        root@GoodKook-Skull:~# <-------------- root user's ptompt

    7-3: Set default user,

        Ref) WSL Advanced WSL Config:
            https://learn.microsoft.com/ko-kr/windows/wsl/wsl-config

        root@GoodKook-Skull:/etc# cat /etc/wsl.conf
        
            [boot]
            systemd=true

            [user]
            default=goodkook

            [interop]
            appendWindowsPath=false

        Once wsl.config changed, restart WSL

            PS> wsl --shutdown


Step 8) Unique Apps for Open-Source EDA

    8-0. Open-Source Silicon EDA

        https://fun-teaching-goodkook.blogspot.com/2025/01/2025-1-mpw.html

        USB device sharing (usbipd),

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

        And "Arduino Board Emulation(How-To)"

        https://fun-teaching-goodkook.blogspot.com/2024/04/etri-05um-cmos-dk-fir8-2systemc.html

    8-1. KiCad

        $ sudo add-apt-repository ppa:kicad/kicad-8.0-releases
        $ sudo sudo apt update
        $ sudo apt install kicad

    8-2. Arduino IDE

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

    8-3. Gowin IDE & Programmer (Educational version)

        https://www.gowinsemi.com/en/support/download_eda/

    8-4. File browser, 'nemo', Text Editor 'gedit', image viewer 'nomacs', pdf viewer 'okular'

        $ sudo apt install nemo gedit gedit-plugin-multi-edit nomacs okular

    8-5. Microsoft Code (Windows version connect remotely to WSL)

        https://code.visualstudio.com/











2025년 1월 27일 월요일

ETRI 0.5um CMOS DK 예제: FIR8 / [3] 칩 테스트 장치

ETRI 0.5um CMOS DK 예제: FIR8 / [3] 칩 테스트 장치

"내 칩 서비스" MPW 2024-2차 칩이 28핀 SSOP 패키지로 배포 되었다. 디지털 회로의 경우 비록 28핀 밖에 않되는 칩이지만 테스트 하려면 테스트 벡터 제네레이터, 로직 아날라이져 같은 장비를 필요로 한다. 여러 클럭에 걸쳐 일련의 테스트 벡터를 주어 기능을 확인해야 하므로 입출력 신호 검사 장비는 프로그래머블 해야함은 물론이다. 비록 이런 장비를 갖췄더라도 장비 사용법은 쉽지 않다. 고가의 테스트 장비에 복잡한 사용법으로 인해 테스트 할 엄두가 나지 않는다면 직접 만들어 보자.

칩 테스트 장치는 기본적으로 SCE-MI 에 준하여 구성되었다.


SCE-MI(Standard Co-Emulation Modeling Interface), https://www.accellera.org/downloads/standards/sce-mi

SystemC 로 작성한 테스트 벤치를 통해 테스트 벡터 생성하고 출력을 검출한다. 동작 모드는 클럭 상세(Cycle Accurate)다. 아듀이노 메가보드를 활용하여 DUT(하드웨어)와 SystemC 테스트 벤치(소프트웨어) 사이의 모델 인터페이스 한다.

테스트 대상 칩은 아래와 같다.

설계명: FIR_PE/DB-19

설계자: 지하은/경희대학교

설계내용: 어레이 FIR 필터 용 프로세싱 엘리먼트(PE)

입출력 핀 수: 입력 17개, 출력: 8개

패키지 핀맵:

 

테스트 장치 제작

준비물

Arduino 2560 MEGA R.3

 

Proto Shield

 

Arcryl Housing/Universal Board

 

Wires & Pin Header

 

Test Clips

 

SOP-28 (300mil) Test Socket

Oscilloscope & Multi-Tester

 




Arduino MEGA/Modeling Interface

회로도: https://content.arduino.cc/assets/MEGA2560_Rev3e_sch.pdf

디지털 핀: https://docs.arduino.cc/resources/pinouts/A000067-full-pinout.pdf


/*
  Filenale: fir8_test.ino
  FIR8 with SystemC Co-Emulation
  Chip Test at Cycle Accurate Level
  MyChip MPW 2024-2
*/
//----------------------// SOIC-28 Package
#define PIN_Xin_3   22  // 1
#define PIN_Xin_2   23  // 2
#define PIN_Xin_1   24  // 3
#define PIN_Xin_0   25  // 4
//            VDD       // 5
#define PIN_Yin_3   26  // 6
#define PIN_Yin_2   27  // 7
#define PIN_Yin_1   28  // 8
#define PIN_Yin_0   29  // 9
#define PIN_RDY_i   30  // 10
#define PIN_CLK_i   31  // 11
#define PIN_Cin_0   32  // 12
#define PIN_Cin_1   33  // 13
#define PIN_Cin_2   34  // 14
#define PIN_Cin_3   35  // 15
#define PIN_Cin_4   36  // 16
#define PIN_Cin_5   37  // 17
#define PIN_Cin_6   38  // 18
#define PIN_VLD_o   39  // 19
#define PIN_Yout_0  40  // 20
#define PIN_Yout_1  41  // 21
#define PIN_Yout_2  42  // 22
#define PIN_Yout_3  43  // 23
//            VSS       // 24
#define PIN_Xout_0  44  // 25
#define PIN_Xout_1  45  // 26
#define PIN_Xout_2  46  // 27
#define PIN_Xout_3  47  // 28
//-------------------------------------------------------------------
class Port_Xin {
  uint8_t _val;
public:
  Port_Xin(uint8_t val)  // Constructor
  {
    // Set digital pins to output connecting DUT's INPUT
    pinMode(PIN_Xin_3, OUTPUT);
    pinMode(PIN_Xin_2, OUTPUT);
    pinMode(PIN_Xin_1, OUTPUT);
    pinMode(PIN_Xin_0, OUTPUT);
    write(val);
  }
  uint8_t read()
  {
    return _val;
  }
  void write(uint8_t val)
  {
    digitalWrite(PIN_Xin_3, val & 0x08);
    digitalWrite(PIN_Xin_2, val & 0x04);
    digitalWrite(PIN_Xin_1, val & 0x02);
    digitalWrite(PIN_Xin_0, val & 0x01);
    _val = val;
  }
};
//-------------------------------------------------------------------
class Port_Yin {
  uint8_t _val;
public:
  Port_Yin(uint8_t val)
  {
    // Set digital pins to output connecting DUT's INPUT
    pinMode(PIN_Yin_3, OUTPUT);
    pinMode(PIN_Yin_2, OUTPUT);
    pinMode(PIN_Yin_1, OUTPUT);
    pinMode(PIN_Yin_0, OUTPUT);
    write(val);
  }
  uint8_t read()
  {
    return _val;
  }
  void write(uint8_t val)
  {
    digitalWrite(PIN_Yin_3, val & 0x08);
    digitalWrite(PIN_Yin_2, val & 0x04);
    digitalWrite(PIN_Yin_1, val & 0x02);
    digitalWrite(PIN_Yin_0, val & 0x01);
    _val = val;
  }
};
//-------------------------------------------------------------------
class Port_Cin {
  uint8_t _val;
public:
  Port_Cin(uint8_t val)
  {
    // Set digital pins to output connecting DUT's INPUT
    pinMode(PIN_Cin_6, OUTPUT);
    pinMode(PIN_Cin_5, OUTPUT);
    pinMode(PIN_Cin_4, OUTPUT);
    pinMode(PIN_Cin_3, OUTPUT);
    pinMode(PIN_Cin_2, OUTPUT);
    pinMode(PIN_Cin_1, OUTPUT);
    pinMode(PIN_Cin_0, OUTPUT);
    write(val);
  }
  uint8_t read()
  {
    return _val;
  }
  void write(uint8_t val)
  {
    digitalWrite(PIN_Cin_6, val & 0x40);
    digitalWrite(PIN_Cin_5, val & 0x20);
    digitalWrite(PIN_Cin_4, val & 0x10);
    digitalWrite(PIN_Cin_3, val & 0x08);
    digitalWrite(PIN_Cin_2, val & 0x04);
    digitalWrite(PIN_Cin_1, val & 0x02);
    digitalWrite(PIN_Cin_0, val & 0x01);
    _val = val;
  }
};
//-------------------------------------------------------------------
class Port_RDY_i {
  bool _val;
public:
  Port_RDY_i(bool val)
  {
    // Set digital pins to output connecting DUT's INPUT
    pinMode(PIN_RDY_i, OUTPUT);
    write(val);
  }
  bool read()
  {
    return _val;
  }
  void write(bool val)
  {
    digitalWrite(PIN_RDY_i, val);
    _val = val;
  }
};
//-------------------------------------------------------------------
class Port_Xout {
  uint8_t _val;
public:
  Port_Xout(uint8_t val)  // Constructor
  {
    // Set digital pins to input connecting DUT's OUTPUT
    pinMode(PIN_Xout_3, INPUT);
    pinMode(PIN_Xout_2, INPUT);
    pinMode(PIN_Xout_1, INPUT);
    pinMode(PIN_Xout_0, INPUT);
    write(val);
  }
  uint8_t read()
  {
    _val = ((digitalRead(PIN_Xout_3)? 0x08:0x00) |
            (digitalRead(PIN_Xout_2)? 0x04:0x00) |
            (digitalRead(PIN_Xout_1)? 0x02:0x00) |
            (digitalRead(PIN_Xout_0)? 0x01:0x00));
    return _val;
  }
  void write(uint8_t val)
  {
    _val = val;
  }
};
//-------------------------------------------------------------------
class Port_Yout {
  uint8_t _val;
public:
  Port_Yout(uint8_t val)  // Constructor
  {
    // Set digital pins to input connecting DUT's OUTPUT
    pinMode(PIN_Yout_3, INPUT);
    pinMode(PIN_Yout_2, INPUT);
    pinMode(PIN_Yout_1, INPUT);
    pinMode(PIN_Yout_0, INPUT);
    write(val);
  }
  uint8_t read()
  {
    _val = ((digitalRead(PIN_Yout_3)? 0x08:0x00) |
            (digitalRead(PIN_Yout_2)? 0x04:0x00) |
            (digitalRead(PIN_Yout_1)? 0x02:0x00) |
            (digitalRead(PIN_Yout_0)? 0x01:0x00));
    return _val;
  }
  void write(uint8_t val)
  {
    _val = val;
  }
};
//-------------------------------------------------------------------
class Port_VLD_o {
  bool _val;
public:
  Port_VLD_o(bool val)  // Constructor
  {
    // Set digital pins to input connecting DUT's OUTPUT
    pinMode(PIN_VLD_o, INPUT);
    write(val);
  }
  bool read()
  {
    _val = digitalRead(PIN_VLD_o);
    return _val;
  }
  void write(uint8_t val)
  {
    _val = val;
  }
};
//-------------------------------------------------------------------
class Port_CLK {
  bool _val;
public:
  Port_CLK(bool val)
  {
    pinMode(PIN_CLK_i, OUTPUT);
    write(val);
  }
  void write(bool val)
  {
    digitalWrite(PIN_CLK_i, val);
    _val = val;
  }
  bool read()
  {
    return _val;
  }
  void posedge()
  {
    digitalWrite(PIN_CLK_i, false);
    digitalWrite(PIN_CLK_i, true);
    _val = true;
  }
  void negedge()
  {
    digitalWrite(PIN_CLK_i, true);
    digitalWrite(PIN_CLK_i, false);
    _val = false;
  }
  bool cycle()
  {
    if (_val)
    {
      negedge();
      posedge();
    }
    else
    {
      posedge();
      negedge();
    }
    return _val;
  }
};
//-------------------------------------------------------------------
void establishContact()
{
  while (Serial.available() <= 0)
  {
    Serial.print('A');  // send a capital A
    delay(300);
    if (Serial.read()==(int)'A')
      break;
  }
}
//-------------------------------------------------------------------
void setup()
{
  // start serial port at 9600 bps:
  Serial.begin(9600);
  while (!Serial)
  {
    ;  // wait for serial port to connect.
  }
  establishContact();  // send a byte to establish contact until receiver responds
  // Monitoring LED
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, HIGH);
}
#define N_RX  3 // [0]={Xin[7:4]|Yin[3:0]}
                // [1]={-|Cin[6:0]};
                // [2]={-[7:2]|Clk|RDY};
#define N_TX  2 // [0]={Xout[7:4]|Yout[3:0]}
                // [1]={-[7:1]|VLD[0]}
uint8_t rxBuf[N_RX], txBuf[N_TX];
// Instantiate DUT Ports
Port_Xin    Xin(0x00);
Port_Yin    Yin(0x00);
Port_Cin    Cin(0x00);
Port_Xout   Xout(0);
Port_Yout   Yout(0);
Port_RDY_i  RDY_i(false);
Port_VLD_o  VLD_o(false);
Port_CLK    CLK(false);
void RxPacket()
{
  int rxByte;
  while(true)
  {
    if (Serial.available() >= N_RX)
    {
      for(int i=0; i<N_RX; i++)
      {
        rxByte = Serial.read();
        rxBuf[i] = (uint8_t)rxByte;
      }
      //rxBuf[0]={Xin[7:4]|Yin[3:0]}
      Xin.write((rxBuf[0] & 0xF0) >> 4);
      Yin.write((rxBuf[0] & 0x0F));
      //rxBuf[1]={-|Cin[6:0]};
      Cin.write((rxBuf[1] & 0x7F));
      //rxBuf[2]={-[7:2]|Clk|RDY};
      RDY_i.write((rxBuf[2] & 0x01));
      CLK.write((rxBuf[2] & 0x02));
      return;
    }
  }
}
void TxPacket()
{
  int txByte;
  while(1)
  {
    if (Serial.availableForWrite() >= N_TX)
    {
      // [0]={Xout[7:4]|Yout[3:0]}
      txBuf[0] = (((uint8_t)Xout.read() << 4) | ((uint8_t)Yout.read() & 0x0F));
      // [1]={-[7:1]|VLD[0]}
      txBuf[1] = ((uint8_t)VLD_o.read() & 0x01);
      for(int i=0; i<N_TX; i++)
      {
        txByte = (int)txBuf[i];
        Serial.write(txByte);
      }
      return;
    }
  }
}
uint8_t counter;
void loop()
{
  counter += 1;
  digitalWrite(LED_BUILTIN, (counter & 0x10)? HIGH:LOW);
  RxPacket();
  TxPacket();
}

SystemC Testbench

1. DUT Wrapper


/**********************************************************************
Filename: sc_fir_pe.h
Purpose : Test wrapper
          Chip Test of FIR PE (MyChip 2024-2)
Author  : goodkook@gmail.com
History : Jan. 2025, First release
***********************************************************************/

#ifndef _SC_FIR_PE_H_
#define _SC_FIR_PE_H_

#include <systemc.h>

// Includes for accessing Arduino via serial port
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>

SC_MODULE(sc_fir_pe)
{
    sc_in<bool>             clk;
    sc_in<bool>             Rdy;
    sc_out<bool>            Vld;
    sc_in<sc_uint<8> >      Cin;
    sc_in<sc_uint<4> >      Xin;
    sc_out<sc_uint<4> >     Xout;
    sc_in<sc_uint<4> >      Yin;
    sc_out<sc_uint<4> >     Yout;

#define N_TX    3
#define N_RX    2

    void transact(void)
    {
        uint8_t     x, y, txPacket[N_TX], rxPacket[N_RX];

        txPacket[0] = ((uint8_t)Xin.read()<<4) | ((uint8_t)Yin.read() & 0x0F);
        txPacket[1] = ((uint8_t)(Cin.read()) & 0x7F);
        txPacket[2] = (((uint8_t)Rdy.read())? 0x01:0x00) | (((uint8_t)clk.read())? 0x02:0x00);

        // Send to Emulator
        for (int i=0; i<N_TX; i++)
        {
            x = txPacket[i];
            while(write(fd, &x, 1)<=0)  usleep(1);
        }

        // Receive from Emulator
        for (int i=0; i<N_RX; i++)
        {
            while(read(fd, &y, 1)<=0)   usleep(1);
            rxPacket[i] = y;
        }

        Xout.write((sc_uint<4>)(rxPacket[0]>>4));
        Yout.write((sc_uint<4>)(rxPacket[0] & 0x0F));
        Vld.write(rxPacket[1]? true:false);

#ifdef LA_FIFO
        x  = txPacket[2]  & 0x02;       // clk
        x |= txPacket[2]  & 0x01;       // Rdy
        x |= rxPacket[1]?   0x04:0x00;  // Vld
        x |= (rxPacket[0]  & 0x01)<<4;  // Yout0
        x |= (rxPacket[0]  & 0x02)<<4;  // Yout1
        x |= (rxPacket[0]  & 0x04)<<4;  // Yout2
        x |= (rxPacket[0]  & 0x08)<<4;  // Yout3
        if((nWrite = write(la_fifo, &x, 1)) < 1)
            fprintf(stderr,"la_fifo: write error\n");
        else
            fflush(0);
#endif
    }
    
    void pe_thread(void)
    {

        while(true)
        {
            wait(clk.posedge_event());
            transact();
            wait(clk.negedge_event());
            transact();
        }
    }

    // Arduino Serial IF
    int fd;                 // Serial port file descriptor
    struct termios options; // Serial port setting

#ifdef LA_FIFO
int la_fifo, nWrite;
#endif

    SC_CTOR(sc_fir_pe):
        clk("clk"),
        Cin("Cin"), Xin("Xin"), Xout("Xout"),
        Yin("Yin"), Yout("Yout")
    {
        SC_THREAD(pe_thread);
        sensitive << clk;

        // Arduino DUT
        //fd = open("/dev/ttyACM0", O_RDWR | O_NDELAY | O_NOCTTY);
        fd = open("/dev/ttyACM0", O_RDWR | O_NOCTTY);
        if (fd < 0)
        {
            perror("Error opening serial port");
            return;
        }
        // Set up serial port
        options.c_cflag = B9600 | CS8 | CLOCAL | CREAD;
        options.c_iflag = IGNPAR;
        options.c_oflag = 0;
        options.c_lflag = 0;
        // Apply the settings
        tcflush(fd, TCIFLUSH);
        tcsetattr(fd, TCSANOW, &options);

        // Establish Contact
        int len = 0;
        char rx;
        while(!len)
            len = read(fd, &rx, 1);
        if (rx=='A')
            write(fd, &rx, 1);
        printf("Connection established...\n");

#ifdef LA_FIFO
        la_fifo = open("la_fifo", O_WRONLY);
        if(la_fifo<0)
            fprintf(stderr,"la_fifo: open error\n");
#endif
    }
    
    ~sc_fir_pe(void)
    {
    }
};

#endif



2. Testbench


/**********************************************************************
Filename: sc_fir_pe_tb.h
Purpose : Testbench
          Chip Test of FIR PE (MyChip 2024-2)
Author  : goodkook@gmail.com
History : Jan. 2025, First release
***********************************************************************/

#ifndef _SC_FIR_PE_TB_H_
#define  _SC_FIR_PE_TB_H_

#include <systemc.h>
#include "sc_fir_pe.h"

SC_MODULE(sc_fir_pe_tb)
{
    sc_clock                clk;
    sc_signal<sc_uint<8> >  Cin;
    sc_signal<sc_uint<4> >  Xin;
    sc_signal<sc_uint<4> >  Xout;
    sc_signal<sc_uint<4> >  Yin;
    sc_signal<sc_uint<4> >  Yout;
    sc_signal<bool>         Vld;
    sc_signal<bool>         Rdy;

    sc_fir_pe*                u_sc_fir_pe;

    uint16_t    Test_Cin[5] = {0, 0, 0, 0, 0};
    uint16_t    Test_Xin[5] = {0, 0, 0, 0, 0};
    uint16_t    Test_Yin[5] = {0, 0, 0, 0, 0};
    uint8_t     Test_Xout = 0;
    uint16_t    Test_Yout = 0;

    // Test utilities
    void Test_Gen()
    {
        Cin.write(0x00);
        Xin.write(0x00);
        Yin.write(0x00);
        Rdy.write(false);

        // INIT
        for (int i=0; i<10; i++)
            wait(clk.posedge_event());
        wait(clk.posedge_event());
        Rdy.write(true);
        wait(clk.posedge_event());
        Rdy.write(false);
        for (int i=0; i<10; i++)
            wait(clk.posedge_event());

        Cin.write(Test_Cin[0]);
        Xin.write(0x00);
        Yin.write(0x00);
        Rdy.write(false);

        while(true)
        {
            Cin.write(Test_Cin[0] & 0x007F);    // Cin: 7-Bits
            wait(clk.posedge_event());
            Rdy.write(true);
            wait(clk.posedge_event());
            Rdy.write(false);
            Xin.write(Test_Xin[0] & 0x000F);    // Xin: 4-Bits
            Yin.write(Test_Yin[0] & 0x000F);    // Yin: 4-Bits
            wait(clk.posedge_event());
            Xin.write(Test_Xin[0] >> 4);
            Yin.write((Test_Yin[0] >> 4) & 0x000F);     // Yin: 4-Bits
            wait(clk.posedge_event());
            Yin.write((Test_Yin[0] >> 8) & 0x000F);     // Yin: 4-Bits
            wait(clk.posedge_event());
            Yin.write((Test_Yin[0] >> 12) & 0x000F);    // Yin: 4-Bits
            wait(clk.posedge_event());
            //printf("Cin = %04d Xin = %04d Yin = %06d ---> ", Test_Cin[0], Test_Xin[0], Test_Yin[0]);

            Test_Xin[4] = Test_Xin[3];  Test_Xin[3] = Test_Xin[2];  Test_Xin[2] = Test_Xin[1];  Test_Xin[1] = Test_Xin[0];
            Test_Yin[4] = Test_Yin[3];  Test_Yin[3] = Test_Yin[2];  Test_Yin[2] = Test_Yin[1];  Test_Yin[1] = Test_Yin[0];
            Test_Cin[4] = Test_Cin[3];  Test_Cin[3] = Test_Cin[2];  Test_Cin[2] = Test_Cin[1];  Test_Cin[1] = Test_Cin[0];

#if defined(TEST_MULTIPLIER_C)
            Test_Cin[0]++;
            if (Test_Cin[0]>127)
            {
                Test_Cin[0] = 0;
                Test_Xin[0]++;
                if (Test_Xin[0]>255)
                    sc_stop();
            }
#elif defined(TEST_MULTIPLIER_X)
            Test_Xin[0]++;
            if (Test_Xin[0]>255)
            {
                Test_Xin[0] = 0;
                Test_Cin[0]++;
                if (Test_Cin[0]>127)
                    sc_stop();
            }
#elif defined(TEST_ADDER_X)
            Test_Cin[0] = 1;
            Test_Xin[0]++;
            if (Test_Xin[0]>255)
            {
                Test_Xin[0] = 0;
                Test_Yin[0]++;
                if (Test_Yin[0]>1000)
                    sc_stop();
            }
#elif defined(TEST_ADDER_Y)
            Test_Cin[0] = 1;
            Test_Yin[0]++;
            if (Test_Yin[0]>255)
            {
                Test_Yin[0] = 0;
                Test_Xin[0]++;
                if (Test_Xin[0]>255)
                    sc_stop();
            }
#elif defined(TEST_ADDER_R)
            Test_Cin[0] = 1;
            Test_Xin[0] = (uint16_t)rand() & 0x00FF;    // Xin: unsigned 8-bit
            Test_Yin[0] = (uint16_t)rand() & 0xFFFF;    // Yin: unsigned 16-bit
#else   // RAND (default)
            Test_Cin[0] = (uint16_t)rand() & 0x007F;    // Cin: unsigned 7-bit
            Test_Xin[0] = (uint16_t)rand() & 0x00FF;    // Xin: unsigned 8-bit
            Test_Yin[0] = (uint16_t)rand() & 0xFFFF;    // Yin: unsigned 16-bit
#endif            
        }
    }

    void Test_Mon()
    {
        uint16_t    Yout_Expected = 0;

        while(true)
        {
            wait(clk.posedge_event());
            if (Vld.read())
            {
                wait(clk.posedge_event());
                wait(clk.posedge_event());
                Test_Xout = (uint8_t)Xout.read();
                Test_Yout = (uint16_t)Yout.read();
                wait(clk.posedge_event());
                Test_Xout |= (uint8_t)Xout.read() << 4;
                Test_Yout |= (uint16_t)Yout.read() << 4;
                wait(clk.posedge_event());
                Test_Yout |= (uint16_t)Yout.read() << 8;
                wait(clk.posedge_event());
                Test_Yout |= (uint16_t)Yout.read() << 12;
                printf("[Cin=%03d] * [Xin=%03d] + [Yin=%05d] ---> ",
#if defined(TEST_ADDER_X) || defined(TEST_ADDER_Y) || defined(TEST_ADDER_R) || defined(RAND)
                        Test_Cin[3], Test_Xin[3], Test_Yin[3]);
                Yout_Expected = (Test_Cin[3]*Test_Xin[3]+Test_Yin[3]);
#else
                        Test_Cin[2], Test_Xin[2], Test_Yin[2]);
                Yout_Expected = (Test_Cin[2]*Test_Xin[2]+Test_Yin[2]);
#endif
                printf("Xout = %03d Yout = %05d", Test_Xout, Test_Yout);
                if (Test_Yout!=Yout_Expected)
                    printf(":ERROR, Expected Yout = %05d\n", Yout_Expected);
                else
                    printf("\n");
            }
        }
    }

#ifdef VCD_TRACE_YES
    sc_trace_file* fp;  // VCD file
#endif

    SC_CTOR(sc_fir_pe_tb):
        clk("clk", 100, SC_NS, 0.5, 0.0, SC_NS, false),
        Vld("Vld"),
        Rdy("Rdy"),
        Xin("Xin"),
        Xout("Xout"),
        Yin("Yin"),
        Yout("Yout")
    {
        SC_THREAD(Test_Gen);
        sensitive << clk;

        SC_THREAD(Test_Mon);
        sensitive << clk;
        
        // Instaltiate FIR8
        u_sc_fir_pe = new sc_fir_pe("u_sc_fir_pe");
        u_sc_fir_pe->clk(clk);
        u_sc_fir_pe->Cin(Cin);
        u_sc_fir_pe->Xin(Xin);
        u_sc_fir_pe->Xout(Xout);
        u_sc_fir_pe->Yin(Yin);
        u_sc_fir_pe->Yout(Yout);
        u_sc_fir_pe->Rdy(Rdy);
        u_sc_fir_pe->Vld(Vld);

#if VCD_TRACE_YES
        // WAVE
        fp = sc_create_vcd_trace_file("sc_fir_pe_tb");
        sc_trace(fp, clk, "clk");
        sc_trace(fp, Cin,  "Cin");
        sc_trace(fp, Xin,  "Xin");
        sc_trace(fp, Xout, "Xout");
        sc_trace(fp, Yin,  "Yin");
        sc_trace(fp, Yout, "Yout");
        sc_trace(fp, Rdy,  "Rdy");
        sc_trace(fp, Vld,  "Vld");
#endif
    }
    
    ~sc_fir_pe_tb(void)
    {
    }
};

#endif


3. Main

/********************************************************************
Filename: sc_main.cpp
Purpose : Chip Test of FIR PE (MyChip 2024-2)
Author  : goodkook@gmail.com
History : Jan. 2025, First release
********************************************************************/
#include "sc_fir_pe_tb.h"
int sc_main(int argc, char** argv)
{
    sc_fir_pe_tb u_sc_fir_pe_tb("u_sc_fir_pe_tb");
    //sc_start(990, SC_US);
    sc_start();
    return 0;
}


4. Python Logic Analyzer



#
# Real-Time Logic Analyzer
#
#
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.animation as animation
HEIGHT = 3
def generate_wave(frame, tick, data,
                    Signal, Mask, PosY, line_Signal) -> None:

    for i in np.arange(0, 80, 2):
        if (not(data[int(i/2)] & Mask)) and (not(data[int(i/2)+1] & Mask)):# Zero
            Signal[i]   = PosY
            Signal[i+1] = PosY
        elif (not(data[int(i/2)] & Mask)) and (data[int(i/2)+1] & Mask):# Rising edge
            Signal[i]   = PosY
            Signal[i+1] = PosY+HEIGHT
        elif (data[int(i/2)] & Mask) and (not(data[int(i/2)+1] & Mask)):# Falling edge
            Signal[i]   = PosY+HEIGHT
            Signal[i+1] = PosY
        else:                                                           # One
            Signal[i]   = PosY+HEIGHT
            Signal[i+1] = PosY+HEIGHT

    Signal[80] = Signal[79]

    line_Signal.set_xdata(tick[:frame])
    line_Signal.set_ydata(Signal[:frame])
#--------------------------------------------------------------------
def update(frame, fp_fifo, data, tick,
            line_Clk, line_Rdy, line_Vld,
            line_Yout0, line_Yout1, line_Yout2, line_Yout3,
            Clk, Rdy, Vld, Yout0, Yout1, Yout2, Yout3) -> None:

    for i in range(0, 40):
        data[i] = data[i+1]

    data[40] = int.from_bytes(fp_fifo.read(1), "big")

    generate_wave(frame, tick, data, Yout0, 0x10,  0, line_Yout0)
    generate_wave(frame, tick, data, Yout1, 0x20,  5, line_Yout1)
    generate_wave(frame, tick, data, Yout2, 0x40, 10, line_Yout2)
    generate_wave(frame, tick, data, Yout3, 0x80, 15, line_Yout3)
    generate_wave(frame, tick, data,   Vld, 0x01, 20, line_Vld)
    generate_wave(frame, tick, data,   Rdy, 0x04, 25, line_Rdy)
    generate_wave(frame, tick, data,   Clk, 0x02, 30, line_Clk)
#--------------------------------------------------------------------
def run():
    data  = [0] * 41
    tick  = [0] * 81
    Clk   = [0] * 81
    Rdy   = [0] * 81
    Vld   = [0] * 81
    Yout0 = [0] * 81
    Yout1 = [0] * 81
    Yout2 = [0] * 81
    Yout3 = [0] * 81

    fp_fifo = open("./la_fifo", "rb")
    for i in range(0, 40):
        data[i] = int.from_bytes(fp_fifo.read(1), "big")

    fig, ax    = plt.subplots()

    line_Clk   = ax.plot(tick[0],   Clk[0], label="Clk")[0]
    line_Rdy   = ax.plot(tick[0],   Rdy[0], label="Rdy")[0]
    line_Vld   = ax.plot(tick[0],   Vld[0], label="Vld")[0]
    line_Yout0 = ax.plot(tick[0], Yout0[0], label="Yout[0]")[0]
    line_Yout1 = ax.plot(tick[0], Yout1[0], label="Yout[1]")[0]
    line_Yout2 = ax.plot(tick[0], Yout2[0], label="Yout[2]")[0]
    line_Yout3 = ax.plot(tick[0], Yout3[0], label="Yout[3]")[0]

    ax.set(xlim=[0, 800], ylim=[-1, 35])
    ax.legend(loc='upper left', fancybox=True, shadow=True)

    for i in np.arange(0, 80, 2):
        tick[i] = tick[i+1] = i * 10
    tick[80] = tick[79]

    ani = animation.FuncAnimation(
                        fig=fig,
                        func =update, 
                        fargs= (fp_fifo, data, tick,
                                line_Clk, line_Rdy, line_Vld,
                                line_Yout0, line_Yout1,
                                line_Yout2, line_Yout3,
                                Clk, Rdy, Vld,
                                Yout0, Yout1, Yout2, Yout3),
                        interval=10, cache_frame_data=False)
    plt.show()
#--------------------------------------------------------------------

run()


5. Makefile


# SystemC Environments -----------------------------------------
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

# SystemC testbench Reuse --------------------------------------
SC_SRCS      =  ./sc_main.cpp
SC_HDRS      =  ./sc_fir_pe.h \
./sc_fir_pe_tb.h
SC_TARGET    = sc_fir_pe_tb

# Conditional building option
ifeq ($(VCD_TRACE),YES)
  VCD_TRACE = VCD_TRACE_YES
else
  VCD_TRACE = VCD_TRACE_NO
endif
ifeq ($(TEST_MODE), MULTIPLIER_C)
  TEST_MODE = TEST_MULTIPLIER_C
else ifeq ($(TEST_MODE), MULTIPLIER_X)
  TEST_MODE = TEST_MULTIPLIER_X
else ifeq ($(TEST_MODE), ADDER_X)
  TEST_MODE = TEST_ADDER_X
else ifeq ($(TEST_MODE), ADDER_Y)
  TEST_MODE = TEST_ADDER_Y
else
  TEST_MODE = TEST_ADDER_R
endif

# Build Rules --------------------------------------------------
all :
@echo
@echo 'Makefile for Chip Test of "FIR_PE/MyChip MPW 2024-2"'
@echo 'Usage:'
@echo '    Build with Options,'
@echo '        TEST_MODE=<...> VCD_TRACE=<...> make build'
@echo '           TEST_MODE: MULTIPLIER_C, MULTIPLIER_X, ADDER_R, ADDER_X, ADDER_Y, RAND'
@echo '           VCD_TRACE: YES or NO'
@echo
@echo '    Run test,'
@echo '        make run'
@echo
@echo '    View VCD at run-time,'
@echo '        TEST_MODE=<...> make run_vcd'
@echo
@echo '        make clean'
@echo

build: $(SC_TARGET)

$(SC_TARGET): $(SC_SRCS) $(SC_HDRS)
$(CXX) $(CXXFLAGS) -I$(SYSTEMC_INCLUDE) -L$(SYSTEMC_LIBDIR) \
-D$(TEST_MODE) -D$(VCD_TRACE) -DLA_FIFO \
-lsystemc -o$(SC_TARGET) $(SC_SRCS)

run: $(SC_TARGET)
rm -f la_fifo
mkfifo la_fifo
python3 la_fifo.py &
./$(SC_TARGET)

run_vcd:
$(CXX) $(CXXFLAGS) -I$(SYSTEMC_INCLUDE) -L$(SYSTEMC_LIBDIR) \
-D$(TEST_MODE) -DVCD_TRACE_YES \
-lsystemc -o$(SC_TARGET) $(SC_SRCS)
rm -f sc_fir_pe_tb.vcd
mkfifo sc_fir_pe_tb.vcd
./$(SC_TARGET) &
shmidcat sc_fir_pe_tb.vcd | gtkwave -v -I sc_fir_pe_tb.sav

clean :
rm -f $(SC_TARGET)
rm -f sc_fir_pe_tb.vcd
rm -f la_fifo


테스트 실행

    % make

    Makefile for Chip Test of "FIR_PE/MyChip MPW 2024-2"
    Usage:
        Build with Options,
            TEST_MODE=<...> VCD_TRACE=<...> make build
               TEST_MODE: MULTIPLIER_C, MULTIPLIER_X, ADDER_R, ADDER_X, ADDER_Y, RAND
               VCD_TRACE: YES or NO

        Run test,
            make run

        View VCD at run-time,
            TEST_MODE=<...> make run_vcd

            make clean

    % TEST_MODE=ADDER_R VCD_TRACE=NO make build

    % make run





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

[이전] [2] 아듀이노 보드 에뮬레이터
[다음] [4] PC 사운드 카드 오실로 스코프

[참고]
1. "내 칩 제작 서비스" 2025년 1차 MPW 대비 오픈-소스 도구 설치 [바로가기]
2. ETRI 0.5um CMOS DK 예제: counter8/16, 디지털 회로 칩 테스트 방법 [바로가기]