기술노트13: Arduino, VitisHLS, Quartus
목차:
1. 개요
2. Arduino
2-1. Arduino 설치
a. Arduino IDE(Integrated Development Environment)
b. Arduino CLI(Command-Line Interface)
2-2. 아듀이노 타깃 보드
a. Arduino DUE
b. Raspberry Pi Pico
c. ESP32
2-3. 아듀이노 타깃 보드의 리눅스 연결
a. 타깃 보드(윈도우즈 USB 장치)를 WSL에 연결
b. 타깃 보드(윈도우즈 USB 장치)를 가상 머신 리눅스에 연결
2-4. Arduino IDE에서 Blink 예제
a. Arduino DUE
b. Raspberry Pi Pico
c. ESP32
2-5. Arduino CLI에서 Blink 예제
a. Arduino DUE
b. Raspberry Pi Pico
c. ESP32
2-6. "남의 칩/Arduino DUE(ARM 코어)"에서 FIR 디지털 필터 실행 시키기
a. 개요
b. 실습
3. VitisHLS
3-1. VitisHLS 설치
3-2. FIR 필터 알고리즘의 HLS
a. 고위합성 실시
b. HLS 결과 보기
c. RTL-SystemC 시뮬레이션
4-1. Quartus 및 Questa 설치
4-2. FIR 필터의 에뮬레이션 검증
5. FIR 필터의 "내 칩" 레이아웃
5-1. "내 칩" 표준 셀로 합성
5-2. 시뮬레이션
5-3. 자동 배치와 배선
5-4. LVS
5-5. 레이아웃
6. 맺음말
---------------------------------------------------------------------------
1. 개요
우리는 내 칩을 설계 하기 위해 남이 만든 칩을 활용 한다. 남이 만든 칩으로 꾸민 컴퓨터에서 컴퓨팅 언어로 알고리즘을 기술하고 도면을 그리며 시뮬레이션을 수행한다. "내 칩"을 만들기 위해 남이 만들어 놓은 컴퓨터를 활용하면서 하드웨어는 물론 소프트웨어에 이르기까지 폭 넓은 이해를 요한다. 게다가 "내 칩"을 제작하려면 상당한 비용이 드는데, 다행히 "내 칩 제작 서비스" 사업으로 나라에서 무료로 제작해 준다고 한다. 공고문에 따르면 도면을 공장에 제출 하고 내 칩을 받기까지 무려 반년의 기간이 소요된다. 시간을 감안 하면 공짜가 아니라는 뜻이다. 수 개월 후에 받아든 내 칩이 설계된 의도대로 작동하길 바란다면 확실히 검증되어야 한다. 시뮬레이터는 반도체 설계의 검증용으로 만들어진 응용 프로그램이다. 이 복잡한 응용 프로그램에 오류는 없을까? 내가 만든 테스트 벤치에 예기치 못한 헛점은 없을까?
남이 만들어 놓은 칩 중에 특별히 기능을 정해 놓지 않은 것들이 있다. 기능이 정해진 바 없는 마이크로 프로세서에 프로그램을 써 넣어 마치 "내 칩" 처럼 작동 하도록 흉내낼 수 있다. "내 칩"에서 작동할 알고리즘의 검증을 비록 남의 칩이지만 하드웨어로 검증이 가능 하다. 그런데 "내 칩"은 RTL 이지만 "남의 칩"에 구현된 알고리즘은 "시스템 수준" 알고리즘이다. "내 칩"의 최종 추상화 목표와 마이크로 프로세서라는 "남의 칩"에 구현된 알고리즘의 추상성 격차가 있다. 이런 추상성 격차가 있음에도 불구하고 굳이 남의 칩, 마이크로 프로세서를 동원하여 검증할 필요가 있을까? "내 칩"의 검증을 위해 작성한 테스트 벤치에 물림으로써 시뮬레이션 모델에 대한 걱정을 덜 수 있다.
[출처] OpenROAD: Toward a Self-Driving, Open-Source Digital Layout Implementation Tool Chain
"남의 칩"을 활용하면서 얻는 또다른 잇점으로 검증 시간의 단축을 들 수 있다. 시제품을 만들어보는 의미로 프로토 타이핑(proto-typing)이 있다. 반도체 설계에서 프로토-타이핑은 "내 칩"의 설계에 "남의 칩(특히 FPGA)"을 적극적으로 활용하는 방법론이다. 반도체 설계에서 프로토 타이핑에 드리는 비용은 상당하다. 반도체 칩은 시제품 제작에 엄청난 비용이 들 뿐만 아니라 일단 칩이 만들어 진 후 실수가 발견되면 재 제작 외에 다른 방법은 없다. 오류를 찾아 수정할 수 있는 초기 개발 NRE(Non-Recursive Engineering)비용이 매우 높기 때문에 검증의 비중이 높아질 수 밖에 없다.
프로그래밍 언어 C/C++를 이해하고 있다면 "내 칩"을 만들 수 있다. 이 문서는 이에 필요한 반도체 설계 자동화 도구들을 소개한다. 예제는 C 로 작성한 디지털 FIR 필터다[연구노트9]. 최고의 수준에서 가장 낮은 회로 단계의 레이아웃에 이르기까지 급격한 추상성 변화의 과정에 자동화 도구들이 활용 된다. 자동화 도구를 무작정 신뢰하기에는 위험성이 크다. 자동화 도구들이 내놓은 결과물의 검증은 오로지 설계자의 몫이다. 성공적인 "내 칩" 만들기에 "남의 칩"과 도구즐을 적극적으로 활용하는 방법을 알아보기로 한다.
2. Arduino
아듀이노는 Atmel 사의 8-비트 또는 32-비트 마이크로 컨트롤러를 장착한 보드 응용 보드로 시작 됐다. 오픈-소스 하드웨어로서 회로도는 물론 개발 도구가 모두 공개되어있다. 이에 수많은 기여자들이 참여하여 범용 내장형 시스템의 개발 플랫폼이 되었다. GNU C/C++ 컴파일러가 준비되었을 경우 Atmel 뿐만 아니라 라즈베리 파이, ESP32 등 다양한 마이크로 컨트롤러를 수용한다. 이루 헤아릴 수 없을 만큼 다양한 응용 보드와 쉴드 보드들이 구동 라이브러리와 함께 공개적으로 제공된다. 교육용은 물론 전문 연구 개발의 영역에서도 널리 활용되고있다.
2-1. Arduino 설치
a. Arduino IDE(Integrated Development Environment)
Arduino-IDE는 아듀이노 보드에 응용 프로그램을 작성하고 컴파일된 바이너리 코드를 올려 놓을 수 있는 통합 개발환경이다. 이 개발 환경은 윈도우즈와 리눅스 운영체제에서 작동한다. "내 칩 설계 환경[연구노트2]"의 일부로 리눅스용 Arduino-IDE의 설치하는 방법을 설명한다.
아래 다운로드 링크 페이지에서 "Linux AppImage (64-bit X86-64)" 를 내려받는다. 편의상 도구들을 디렉토리 /opt/Arduino 에 저장해 둔다.
https://www.arduino.cc/en/software/
또는
$ sudo mkdir /opt/Arduino
$ cd /opt/Arduino
$ sudo wget https://downloads.arduino.cc/arduino-ide/arduino-ide_2.3.6_Linux_64bit.AppImage
내려받은 파일명은 arduino-ide_2.3.6_Linux_64bit.AppImage 다. 이 파일이 실행 속성을 가지지 않고 있다면 이를 변경한다.
$ sudo chmod +x arduino-ide_2.3.6_Linux_64bit.AppImage
.AppImage 파일은 소스 코드 편집기, 타깃 마이크로 컨트롤러의 C/C++ 컴파일러 운용 그리고 바이너리 이미지 올리기(upload)등 일련의 개발 도구들을 패키지화 하여 한개의 파일에 모아놓은 것이다. .AppImage를 실행 시키려면 libfuse2 가 설치되어야 한다.
$ sudo apt install libfuse2
[주] libfuse2 는 "내 칩 디자인 킷"의 도구와 함께 이미 설치했다[연구노트2].
임의로 내려받아 저장한 응용 프로그램을 리눅스의 파일 시스템 실행 경로에 포함시키기 위해 아래와 같이 소프트 링크(바로가기)를 만들어 준다.
$ sudo ln -s /opt/Arduino/arduino-ide_2.3.6_Linux_64bit.AppImage /usr/bin/arduino-ide
어느 디렉토리 위치 에서도 아듀이노 개발 환경을 사용할 수 있다.
[주] arduino-ide 가 샌드박스(SandBox) 보안 때문에 실행 되지 않을 경우 --no-sandbox 스위치를 주고 실행한다.
b. Arduino CLI (Command-Line Interface)
Arduino IDE는 그래픽 사용자 인터페이스 환경(GUI, Graphic User Interface)이다. 프로그램 개발에 필요한 모든 도구들을 통합한 환경은 사용이 편리 하지만 개발 중 컴파일과 바이너리를 타깃 보드에 올리기 위해 반복적으로 GUI 를 띄우려면 번거롭다. 매번 여러 단계 메뉴를 선택하고 버튼을 눌러줘야 한다. 번거롭게 느끼는 틈으로 사용자의 실수가 끼어든다. 아듀이노는 GUI외에 명령줄 환경을 제공한다. Makefile 스크립트를 활용할 수 있다. 별도의 설치 방법은 없다. 아래처럼 링크에서 내려 받아,
$ cd /opt/Arduino
$ sudo wget https://downloads.arduino.cc/arduino-cli/arduino-cli_latest_Linux_64bit.tar.gz
압축을 풀어놓고,
$ sudo tar xvf arduino-cli_latest_Linux_64bit.tar.gz
바로가기 링크를 건다.
$ sudo ln -s /opt/Arduino/arduino-cli /usr/bin/arduino-cli
2-2. 아듀이노 타깃 보드
아듀이노는 마이크로 컨트롤러 보드 회로도와 개발 도구를 모두 공개하였다. 타깃 마이크로 컨트롤러로 Atmel 사의 8-비트 또는 32-비트 마이크로 컨트롤러를 장착한 보드를 출시하였다. 오픈-소스 하드웨어 개발 환경이 모두 공개된 탓에 각종 응용 라이브러리는 물론 다양한 응용 보드들이 많은 개발자들에 의해 자발적으로 추가되었다. Atmel 사 뿐만 아니라 라즈베리 파이(Raspberry PI), ESP32, RISC-V 등 다수의 마이크로 컨트롤러(GNU C/C++ 컴파일러가 준비된)를 채택한 보드들도 아듀이노 개발 환경에서 사용 할 수 있게 되었다. 지금의 아듀이노는 마이크로 컨트롤러 특정하지 않고 범용 개발 환경으로서 더 큰 가치를 가진다. 오픈-소스 하드웨어 집단 지성의 표본이라고 하겠다.
"내 칩 디자인 킷[링크]"의 검증과 칩 테스트에 아듀이노를 사용할 것이다. 아듀이노 보드로 Atmel의 ARM 코어를 장착한 Arduimo DUE, Raspberry Pi Pico 그리고 Xtensa/RISC-V 코어가 내장된 ESP32-S/C 보드를 사용한다. 이들 보드들은 매우 저렴한 가격으로 오픈-마켓에서 판매되고 있다.
a. Arduino DUE
Arduino DUE는 32비트 ARM 코어를 내장한 Atmel 사의 마이크로 컨트롤러 SAM3X8E 를 장착한 개발 보드다. 아래 링크에서 이 보드의 기술 정보를 찾을 수 있다.
https://docs.arduino.cc/hardware/due/
[주] 오픈-마켓에서 구입 할 수 있는 Arduino DUE 보드
아뉴이노는 마이크로 컨트롤러 내장형 개발 플랫 폼이다. 특정 마이크로 컨트롤러용 개발 도구들을 따로 설치해 주어야 한다. 타깃 보드 Arduino DUE 용 개발 도구(C/C++ 컴파일러와 업로더)를 설치하는 절차는 아래와 같다.
(1) 보드 매니져
(2) "DUE" 보드 검색
(3) 설치
b. Raspberry Pi Pico
"라즈베리 Pi Pico/RP2040" 보드는 아듀이노의 공식 보드 매니져에 가 포함되어 있지 않다. 다음 절차에 따라 깃허브에서 다운 받는다.
(1) 메뉴 File -> Preference
(2) 보드의 개발도구 URL 추가
(3) 아래의 깃허브 링크 추가 후 OK
https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json
(4) 보드 매니져
(5) RP2040 검색lephilhowe
(6) Earlephilhower의 RP2040/2050 선택 설치
[주] "Using the Pi Pico with the Arduino IDE"
https://www.upesy.com/blogs/tutorials/install-raspberry-pi-pico-on-arduino-ide-software
[주] 오픈-마켓에서 구입할 수 있는 Raspberry Pi Pico 보드.
c. ESP32
에스프레시프 시스템즈(Espressif Systems)의 ESP32 보드 개발 환경 설치 방법은 다음과 같다. ESP32 를 채택한 보드가 다수 발매되고 있다. 아래의 예는 에스프레시프 시스템즈사에서 발매한 보드를 사용하는 경우다.
(1) 보드 매니져
(2) ESP32 검색
(3) Espressif System의 esp32 선택 설치
[주] 오픈-마켓에서 구입할 수 있는 ESP32 보드,
2-3. 아듀이노 타깃 보드의 리눅스 연결
a. 타깃 보드(윈도우즈 USB 장치)를 WSL로 연결
WSL은 USB 장치를 지원하지 않기 때문에 직접 연결 할 수 없다. 아듀이노 개발 환경에서 타깃 보드를 연결하여 바이너리 코드를 올리려면 가상의 IP를 통해 USB 장치를 연결해 주는 usbipd-win을 설치해야 한다.
[주] WSL에서 USB 장치를 연결 방법의 자세한 설명은 아래 링크 참조,
https://learn.microsoft.com/ko-kr/windows/wsl/connect-usb
1) USBIPD-WIN의 최신 버젼 설치 프로그램을 아래 링크에서 내려 받아 실행한다.
https://github.com/dorssel/usbipd-win/releases
2) Arduino DUE 타깃 보드를 PC의 USB 포트에 연결하면 시리얼 포트로 인식된다.
3) 파워 쉘을 관리자 권한으로 열어 USBIPD-WIN으로 공유할 수 있는 USB 장치를 검색한다.
PS> usbipd list
BUSID 6-4 로 할당된 COM4 장치를 윈도우즈와 WSL 사이에 공유 시킨다.
PS> usbipd bind --busid 6-4
PS> usbipd list
[주] BUSID와 시리얼 포드(COM) 번호는 PC의 상태에 따라 바뀐다. 공유(bind)는 관리자 권한의 파워 쉘 명령창에서 가능하다. 한번 공유된 장치는 다시 공유 시키지 않아도 된다.
4) 공유한 USB 장치(타깃 보드)를 WSL에 연결 한다.
PS> usbipd attach --wsl --busid 6-4
5) 리눅스 터미널에서 USB 장치들을 확인해 본다.
$ lsusb
아듀이노 DUR 보드의 프로그래밍 포트가 USB 장치로 인식되었다.
b. 타깃 보드(윈도우즈 USB 장치)를 가상 머신 리눅스로 연결
가상 머신에 설치된 리눅스에 USB 장치를 연결하기 위해 우회할 필요 없다. 리눅스 머신 그 자체이기 때문이다. 윈도우즈 PC의 USB에 연결된 아듀이노 DUE 보드를 가상 머신(VirtualBox) 리눅스로 인식 시킨다. USB 아이콘에 마우스 오른쪽 버튼을 누르면,
연결 가능한 장치 목록이 나열된다. "Arduino DUE Programing Port"를 선택한다.
2-4. 보드 테스트(Blink 예제)
아듀이노 개발환경이 설치되었다. 구입 한 보드를 간단한 예제 Blink(내장된 LED 깜빡이기)를 가지고 테스트 한다.
a. Arduino DUE
간단한 응용 프로그램으로 Arduino DUE 보드에 내장된 LED를 깜빡여 본다. Arduino IDE 를 실행 시켜 연결된 타깃 보드(Select Board)를 확인한다.
메뉴 File > Examples > Blink 선택하여 간단한 예제를 불러온 후 컴파일 하고 타깃 보드에 업로드 하면 LED가 깜빡이는 것을 보게 될 것이다.
b. Raspberry Pi Pico
라즈베리 파이 "피코"는 아듀이노의 규격을 따르는 보드가 아니다. 컴파일된 바이너리를 타깃 보드로 올리는 절차가 다르다. 보드 위에 BOOTSEL 버튼을 누른채 부팅 시키면 PC의 이동식 저장 장치로 인식된다. 이 저장 장치에 바이너리 파일(UF2 형식)을 복사해 주면 이를 컨트롤러에 적재하고 재부팅 된다. 아듀이노는 이 과정을 지원하지만 문제는 WSL에 설치된 리눅스다. USB 장치를 직접 연결할 수 없는 WSL은 피코 보드를 BOOTSEL 모드로 전환 시킬 수 있지만 usbipd의 간여 없이 자동 재연결이 불가하다. 윈도우즈 디스크를 재연결 시키지 않아 타깃 보드 찾기에 실패 한다.
이를 해결할 방법은 아듀이노 환경에서 직접 올리지 않고 디스크 장치에 복사하는 방법이 있다.
1) 타깃 보드를 인식 시킬 필요 없이 강제로 RP2040을 지정한다. 메뉴 Tools > Board: > Raspberry PI: > Raspberry Pi Pico 를 따라가면 타깃 보드를 지정할 수 있다.
(2) 메뉴 Sketch > Export Compile Binary를 선택하면 타깃 보드에 업로드 하지 않고 파일로 저장한다.
컴파일 한 바이너리 파일(.UF2)은 프로젝트 디렉토리에서 아래로 다음에 위치한다.
.../Blink/build/rp2040.rp2040.rpipico/Blink.ino.uf2
(3) "피코" 보드를 BOOTSEL 모드로 부팅(BOOTSEL 버튼을 누른채 리셋 또는 전원인가)하면 윈도우즈의 USB 저장장치로 인식된다.
(4) RP2 드라이브를 WSL의 적당한 디렉토리(아래는 _uf2_)에 마운트 한다.
$ mkdir ~/_uf2_
$ sudo mount -t drvfs f: ~/_uf2_
(5) 위의 (4)에서 생성한 컴파일 바이너리를 ~/_uf2_ 로 복사 한다.
$ cp Blink/build/rp2040.rp2040.rpipico/Blink.ino.uf2 ~/_uf2_
"피코"보드는 uf2 파일이 복사되는 즉시 재부팅 되어 바이너리를 컨트롤러 메모리에 적재한다. 보드의 LED 가 반짝이는 것을 보게될 것이다.
c. ESP32-S/C
Espressif Systems 사의 32비트 마이크로 컨트롤러를 채용한 보드다. ESP32 보드는 같은 이름이지만 두개의 다른 코어를 사용한다. C 시리즈는 RISC-V, S 시리즈는 Tensilica Xtensa 코어를 사용한 SoC다. 제조사에서 새 프로젝트에 C 시리즈를 추천하고 있다. 두 코어는 기계어 수준의 호환성이 없다. 서로 다른 코어지만 높은 수준의 C/C++언어 개발 환경에서 이를 구분하지 않는다. 명령 체계가 다른 코어지만 입출력 장치들의 호환성을 가지고 있기 때문이다. 높은 추상화 수준의 언어로 작성된 코드들은 각각의 언어 변환기(컴파일러)로 다른 CPU에 이식 될 수 있다. 이식성(portablity)은 C/C++ 언어의 특장점이다. 이식성의 걸림돌은 입출력 장치의 호환성이다. 하드웨어 구조상 호환성이 없다면 중간에 위치한 장치 구동 라이브러리로 이를 보완 할 수 있다.
앞의 예제 Blink를 ESP32-S3 코어를 채택한 보드에서 실행 시켜본다.
1) ESP32-S3 보드를 PC의 USB에 꼽으면 시리얼 포트로 인식된다.
2) WSL 사용자라면 usbipd 를 통해 리눅스로 공유 후 연결되도록 한다.
PS > usbipd list
Connected:
BUSID VID:PID DEVICE STATE
6-2 1a86:55d3 USB-Enhanced-SERIAL CH343(COM6) Not shared
PS> usbipd bind --busid 6-2
PS> usbipd attach --wsl --busid 6-2
3) ESP32 타깃 보드는 아듀이노 환경에 잘 어울린다. 메뉴 Tools > Board > ESP32: 를 따라간 후 타깃 보드를 선택한다. C 또는 S 시리즈를 비롯하여 다양한 보드들이 망라되어있다.
4) 타깃 보드가 선정되면 예제의 소스 코드에 수정없이 컴파일 되어 바이너리를 올릴 수 있다.
앞서 시험해 본 타깃 보드(Arduino DUE, Raspberry Pi Pico)의 프로세서 코어는 모두 32비트 ARM이었다. 동일한 코드를 ESP32 프로세서 코어를 채택한 보드에서 실행 될 수 있다. 프로세서 코어는 물론 세가지 보드들의 구성(회로도)도 다르지만 사용자들에 의해 호환성을 유지 할 수 있는 라이브러리 들을 개발하여 나눔으로써 아듀이노는 하드웨어와 소프트웨어를 모두 아우른 개발 플랫 폼이 되었다. 물론 매우 단순한 예제이긴 하지만 이런 이식성은 아듀이노 개발 플랫폼과 라이브러리 제작에 기여한 집단지성의 성과다.
2-5. Arduino CLI
직관적인 통합 환경은 도구 사용은 직관적이 있으나 번거롭다. 아유이노는 명령줄에서 실행 할 수 있는 CLI를 제공한다. 스크립트를 사용하면 IDE에서 여러차례 버튼을 부르고 명령마다 옵션을 선택하는 번러로움을 피할 수 있다. CLI는 그외 다양한 장점이 있다.
[주] Arduino CLI and the art of command line,
https://www.youtube.com/watch?app=desktop&v=cVod8k713_8
[주] Arduino-CLI Getting Started,
https://arduino.github.io/arduino-cli/1.3/getting-started/
앞서 통합 환경에서 마이크로 컨트롤러(코어)와 타깃 보드 용 개발 도구들을 모두 설치한 상태다. 아듀이노 CLI는 IDE에서 설치했던 각종 라이브러리와 보드 도구들을 공유하므로 재설치 할 필요 없다. 예제 Blink 를 CLI 환경에서 수행해본다.
a. Arduino DUE
디렉토리로 이동,
$ cd ~/ETRI050_DesignKit/Tutorials/2-13_Arduino_Blink
예제의 Makefile 을 작성해 두었다.
$ make
Arduino-CLI
Usage:
make help
make config
NEW_SKETCH=[MyNewSketsh] make new_sketch
FQBN=[board name] SKETCH=[sketch name] make compile
PORT=[/dev/ttyACM0] FQBN=[board name] SKETCH=[sketch name] make upload
make board_list
make core_list
BOARD_NAME=[name] make board_listall
CORE_NAME=[name] make core_list
make update_cache ; update installed local cache
make core_update ; Update local cache for added 3rd party board
CORE_NAME=[name] make install_core
LIB_NAME=[libname] make lib_search
LIB_NAME=[libname] make lib_install
먼저 어떤 보드가 연결되었는지 확인한다.
$ make board_list
arduino-cli board list
Port ..... FQBN Core
/dev/ttyACM0 ..... arduino:sam:arduino_due_x_dbg arduino:sam
현재 연결된 보드의 풀-네임(FQBN, Fully Quarified Board Name)과 코어를 알 수 있다. 이를 인수로 주고 예제 Blink 를 컴파일 한다.
$ FQBN=arduino:sam:arduino_due_x_dbg SKETCH=Blink make compile
arduino-cli compile --fqbn arduino:sam:arduino_due_x_dbg Blink
Sketch uses 10692 bytes (2%) of program storage space. Maximum is 524288 bytes.
컴파일이 완료 되었으면 타깃 보드에 바이너리를 올려보자.
$ PORT=/dev/ttyACM0 FQBN=arduino:sam:arduino_due_x_dbg SKETCH=Blink make upload
arduino-cli upload -p /dev/ttyACM0 --fqbn arduino:sam:arduino_due_x_dbg Blink
Atmel SMART device 0x285e0a60 found
Erase flash
done in 0.039 seconds
Write 11872 bytes to flash (47 pages)
[==============================] 100% (47/47 pages)
done in 2.818 seconds
Set boot flash true
CPU reset.
New upload port: /dev/ttyACM0 (serial)
b. Raspberry Pi Pico
"피코" 보드에 바이너리를 올리려면 통합 환걍에서 나와 몇가지 절차가 필요했다(WSL 인 경우에 한함). 이 절차를 Makefile에 기술하였다.
타깃 보드가 연결되었는지 보자.
$ make board_list
arduino-cli board_list
Port ... ... FQBN Core
/dev/ttyACM0 ... ... rp2040:rp2040:degz_suibo rp2040:rp2040
rp2040:rp2040:evn_alpha rp2040:rp2040
rp2040:rp2040:generic rp2040:rp2040
rp2040:rp2040:sea_picro rp2040:rp2040
rp2040:rp2040:rpipicow rp2040:rp2040
포트에 한개의 보드가 꼽혀 있지만 여러가지 보드들이 나열된다. 모두 호환되는 목록들이다. FQBN을 변수로 주고 컴파일 한다.
$ FQBN=rp2040:rp2040:generic SKETCH=Blink make compile
arduino-cli compile --fqbn rp2040:rp2040:generic Blink
Sketch uses 58832 bytes (2%) of program storage space. Maximum is 2093056 bytes.
Global variables use 9640 bytes (3%) of dynamic memory, leaving 252504 bytes for local variables. Maximum is 262144 bytes.
"피코" 보드에 컴파일된 바이너리를 업로드 하자.
$ PORT=/dev/ttyACM0 FQBN=rp2040:rp2040:generic SKETCH=Blink make upload
arduino-cli upload -p /dev/ttyACM0 --fqbn rp2040:rp2040:generic Blink
Resetting /dev/ttyACM0
Converting to uf2, output size: 151040, start address: 0x2000
Scanning for RP2040 devices
No drive to deploy.
Failed uploading: uploading error: exit status 1
업로드를 실패했다. 그유는 앞서 설명한 대로다. 컴파일한 후 바이너리를 따로 저장하는 옵션은 -e 다. Makefile에 "피코"를 위한 타깃을 아래와 같이 작성하였다.
compile_pico:
arduino-cli compile --fqbn $(FQBN) $(SKETCH) -e
바이너리를 "피코" 보드에 올리기 전에 디스크 마운트 먼저한 후 바이너리를 복사한다.
upload_pico: $(SKETCH)/build/rp2040.rp2040.generic/$(SKETCH).ino.uf2
sudo mount -t drvfs f: ~/_uf2_
cp $(SKETCH)/build/rp2040.rp2040.rpipicow/$(SKETCH).ino.uf2 ~/_uf2_
c. ESP32
ESP32 보드는 아듀이노 환경과 잘 어울린다. 보드 연결을 확인해 보자.
$ make board_list
arduino-cli board list
Port Protocol Type Board Name FQBN Core
/dev/ttyACM0 serial Serial Port (USB) Unknown
아쉽게도 보드 이름을 확인 하지 못한다. 하지만 보드 이름을 알고 있으므로 FQBN 만 얻으면 된다. 설치된 도구의 지원 목록에서 esp32s3 를 찾아본다.
$ BOARD_NAME=esp32s3 make board_listall
arduino-cli board listall esp32s3
Board Name FQBN
...
ESP32-S3 PowerFeather esp32:esp32:esp32s3_powerfeather
ESP32-S3-Box esp32:esp32:esp32s3box
ESP32-S3-USB-OTG esp32:esp32:esp32s3usbotg
ESP32S3 Dev Module esp32:esp32:esp32s3
...
ESP32 S3 보드의 FQBN을 알아냈다. 컴파일 해보자.
$ FQBN=esp32:esp32:esp32s3 SKETCH=Blink make compile
arduino-cli compile --fqbn esp32:esp32:esp32s3 Blink
Sketch uses 315247 bytes (24%) of program storage space. Maximum is 1310720 bytes.
Global variables use 20568 bytes (6%) of dynamic memory, leaving 307112 bytes for local variables. Maximum is 327680 bytes.
보드에 바이너리 올리기,
$ PORT=/dev/ttyACM0 FQBN=esp32:esp32:esp32s3 SKETCH=Blink make upload
arduino-cli upload -p /dev/ttyACM0 --fqbn esp32:esp32:esp32s3 Blink
esptool v5.0.0
Connected to ESP32-S3 on /dev/ttyACM0:
Chip type: ESP32-S3 (QFN56) (revision v0.1)
Features: Wi-Fi, BT 5 (LE), Dual Core + LP Core, 240MHz, Embedded PSRAM 8MB (AP_3v3)
Crystal frequency: 40MHz
MAC: f4:12:fa:ce:e4:60
...
New upload port: /dev/ttyACM0 (serial)
ESP32-S3 코어가 WiFi 가 내장 되었다고 한다. 앞으로 뭔가 해볼꺼리가 많아 보인다.
2-6. "남의 칩/Arduino DUE(ARM 코어)"에서 FIR 필터 알고리즘 실행시키기
LED 깜빡이기는 너무 단순했다. FIR 필터 알고리즘[연구노트9]을 "내 칩"으로 설계하기 전에 "남의 칩"에서 실행 시켜보자.
a. 개요
FIR 필터 알고리즘을 검증하기 위해 C++로 테스트벤치를 작성했었다[연구노트9]. FIR 알고리즘을 "내 컴퓨터"에서 실행하기 위한 테스트 벤치는 다음과 같다. FIR 필터 함수 fir()를 기술한 fir8.cpp 를 테스트벤치 fir8_tb.cpp 와 함께 컴파일 하고 실행 하면 "내 컴퓨터"에서 알고리즘을 시험하게 된다.
// Filename: ~/ETRI050_DesignKit/Tutorials/2-5_Lab3_FIR8/c_untimed/fir8_tb.cpp
int main(void)
{
data_t x[F_SAMPLE];
acc_t y[F_SAMPLE], yn;
......
for (int t=0; t<F_SAMPLE; t++)
{
......
fir(&yn, x[t]); // FIR Filter
......
}
......
return 0;
}
이번에는 fir() 를 "남의 칩", 아듀이노 DUE 보드에 장착된 ARM 코어에서 실행 되도록 옮겨보자.
+---------------+
| FIR8_TL.cpp |
| main() |
+----------+ |
+---+ +----------+ +---+ +----------+| |
| | | fir8.cpp | | | | fir8.cpp || |
| | | fir() | | |<--USB/UART-->| fir() || |
| | +----------+ | | +----------+| |
| +--------------+ | +----------+ |
| FIR8.ino | | |
+----------------------+ +---------------+
|<--Arduino DUE(ARM)-->| |<-My Computer->|
알고리즘 fir()은 "남의 칩(Arduino DUE보드의 ARM)"에서 실행될 것이며 "내 컴퓨터"는 USB의 시리얼 통신 포트를 통해 입력을 주고 출력을 받아온다. "남의 칩"에서 FIR 필터 알고리즘 fir()의 수행을 위해 시리얼 통신 인터페이스를 감싼 아듀이노 코드 FIR8.ino는 다음과 같다. 시리얼 통신으로 받은 값을 입력으로 FIR 필터 함수 fir()를 호출하고 계산된 값을 내보낸다.
// Filename: ~/ETRI050_DesignKit/Tutorials/2-15_Lab6_FIR8_c_untimed_Arduino/emulation/FIR8.ino
#include <Arduino.h>
#include "fir8.h"
void setup()
{
// start serial port
Serial.begin(9600);
while (!Serial);
establishContact();
}
void loop()
{
data_t x; // unsigned 8-bit
acc_t y; // unsigned 16-bit
......
// Receive Emulator/DUT in-vector from HOST
if (Serial.available() >= N_RX)
{
x = Serial.read();
if (Serial.availableForWrite() >= N_RX)
Serial.write((data_t)x); // Loop-Back
}
else return;
fir( &y, x); // FIR Filter @ fir8.cpp
if (Serial.availableForWrite() >= N_TX)
{
Serial.write((data_t)(y>>0) & 0x0FF); // LSB
Serial.write((data_t)(y>>8) & 0x0FF); // MSB
}
......
}
"내 컴퓨터"의 테스트벤치 FIR8_TL.cpp 는 위의 fir8_tb.cpp와 동일하다. 외견상 함수 fir() 이 "남의 칩"에서 실행 되는지 모른다. 알 필요도 없다. "내 컴퓨터"의 fir() 함수는 아래와 같다. 시리얼 통신 포트를 통해 "남의 칩"으로 보내고 결과를 받아올 뿐이다.
// Filename: ~/ETRI050_DesignKit/Tutorials/2-15_Lab6_FIR8_c_untimed_Arduino/emulation/fir8.cpp
bool fir(acc_t* Yout, data_t Xin)
{
uint8_t _tx, _rx;
uint16_t _Yout;
//---------------------------------------------------------
// Connect Arduino via Serial Port
//---------------------------------------------------------
static int fd = 0; // Serial port file descriptor
if (fd<=0)
{
. . . . . .
}
//------------------------------------------------------------
// Send to Emulator
//------------------------------------------------------------
_tx = Xin;
while(write(fd, &_tx, 1)<=0) usleep(10);
while(read(fd, &_rx, 1)<=0) usleep(10); // Loop-Back
if (_tx != _rx) // Loop-Back Test
{
fprintf(stderr, "COMM Error......\n");
return false;
}
//------------------------------------------------------------
// Receive from Emulator
//------------------------------------------------------------
while(read(fd, &_rx, 1)<=0) usleep(10);
_Yout = (uint16_t)_rx;
while(read(fd, &_rx, 1)<=0) usleep(10);
_Yout |= ((uint16_t)_rx<<8);
*Yout = _Yout;
return true;
}
b. 실습
"남의 칩"에서 FIR 필터 알고리즘 실행시키기의 예제 디렉토리로 이동,
$ cd ~/ETRI050_DesignKit/Tutorials/2-15_Lab6_FIR8_c_untimed_Arduino
$ tree
.
├── emulation
│ ├── fir8.cpp
│ ├── fir8.h
│ ├── FIR8_TL.cpp
│ └── sc_timed
│ ├── Makefile
│ ├── sc_fir8.gtkw
│ ├── sc_fir8.h
│ ├── sc_fir8.sav
│ ├── sc_fir8_tb.cpp
│ ├── sc_fir8_tb.h
│ └── sc_main.cpp
├── FIR8
│ ├── fir8.cpp -> ../../2-5_Lab3_FIR8/c_untimed/fir8.cpp
│ ├── fir8.h -> ../../2-5_Lab3_FIR8/c_untimed/fir8.h
│ └── FIR8.ino
├── Makefile
└── sc_plotDFT.py
아듀이노 DUE 용 바이너리 빌드,
$ make build
arduino-cli compile --clean \
--fqbn arduino:sam:arduino_due_x_dbg FIR8 \
--build-property compiler.cpp.extra_flags=-DFIR_SHIFTER_VERSION
Sketch uses 10964 bytes (2%) of program storage space. Maximum is 524288 bytes.
컴파일된 바이너리 업로드,
$ make upload
arduino-cli upload \
-p /dev/ttyACM0 \
--fqbn arduino:sam:arduino_due_x_dbg FIR8
Atmel SMART device 0x285e0a60 found
Erase flash
done in 0.042 seconds
Write 12144 bytes to flash (48 pages)
[==============================] 100% (48/48 pages)
done in 2.860 seconds
Set boot flash true
CPU reset.
New upload port: /dev/ttyACM0 (serial)
"남의 칩"에서 실행,
$ make run
3. VitisHLS
Vitis와 Vivado 는 자일링스(Xilinx) FPGA 개발 도구를 모아놓은 패키지다. 자사의 FPGA에 특화된 합성과 배치배선 도구뿐만 아니라 다양한 설계 자동화 도구들로 구성되었다. 특히 VitisHLS 는 고위 합성(HLS, High-Level Systhesis) 도구다. 표준 C/C++ 구문을 베릴로그 RTL 로 변환(합성)해준다. 변환된 베릴로그 RTL 코드는 범용성을 가지고 있어서 다른 FPGA 뿐만 아니라 ASIC 용으로도 사용할 수 있다. 여기에는 "내 칩 제작 서비스"의 표준 셀 기반 디자인 킷을 적용 할 수 있다. 자일링스의 도구들은 몇가지 기능(합성 후 분석도구 등)을 제외하면 무료 사용 할 수 있다.
3-1. VitisHLS 설치
자일링스의 도구 내려받기 사이트의 링크는 아래와 같다.
https://www.xilinx.com/support/download.html
리눅스 설치도구를 내려받는다.
AMD Unified Installer for FPGAs & Adaptive SoCs 2025.1: Linux Self Extracting Web Installer (BIN - 335.53 MB)
설치 파일을 내려받기 위해 AMD의 계정이 필요하다. AMD 계정이 없다면 새로 만들도록 한다. 신청서를 성실히 채워 넣으면 즉시 확인 메일이 올 것이다.
내려받은 설치 파일을 실행 한다. 내려받은 파일에 실행 설정이 되어 있지 않을 경우 다음과 같이 파일설정을 변경한 후 관리자로 실행한다.
$ chmod +x FPGAs_AdaptiveSoCs_Unified_SDI_2025.1_0530_0145_Lin64.bin
$ sudo ./FPGAs_AdaptiveSoCs_Unified_SDI_2025.1_0530_0145_Lin64.bin
표준 보다는 전문가 답게 기업형으로 설치한다. 표준형 도구에 VitisHLS가 빠져있다. 기업형 이라 해서 사용료를 요구하고 그러지 않는다.
설계 도구로 Vivado와 함께 VitisHLS 선택, FPGA 제품군으로 Artix-7만 선택해도 좋다. 여러 제품군을 고를 수록 설치용량이 거대해 진다.

선택했던 내용을 살펴보고 설치를 시작하자. 설치할 디렉토리 위치를 /opt/Xilinx 로 했다.
무려 20GByte 정도를 내려받아 설치용량이 57GByte 다. 인터넷 속도에 달렸지만 족히 한시간은 걸릴 것이니 참고 기다리다 보면 설치가 완료된다. 자일링스 도구들을 사용하려면 로케일을 맞춰준다.
$ sudo locale-gen en_US.UTF-8
3-2. FIR 필터 알고리즘의 HLS
HLS(High-Level Synthesis)은 다음편에 배우기로 하고 HLS 맛보기다. C/C++로 작성한 FIR 필터[연구노트9]를 RTL 로 합성해보자. 고위합성의 최근 경향과 안내는 아래 링크를 참조한다.
고위합성 자동화 도구의 동향(Automatic High-Level Code Deployment)
https://hls-goodkook.blogspot.com/2023/10/automatic-high-level-code-deployment.html
고위합성 예제 디렉토리,
$ cd ~/ETRI050_DesignKit/Tutorials/2-8_Lab6_FIR8_c_untimed_Vitis-HLS
$ tree
.
├── /emulation : FPGA 에뮬레이션
├── /ETRI050 : "내 칩 서비스" ASIC
├── /simulation : RTL/SystemC 시뮬레이션
│ ├── Makefile
│ ├── fir_TL_Bulk.cpp
│ ├── fir_TL.cpp
│ ├── sc_fir_TB.cpp
│ ├── sc_fir_TB.h
│ └── sc_main.cpp
├── Makefile
├── fir.cfg : HLS 합성 조건
└── Vitis-HLS.tcl : VitisHLS 스크립트
$ make
Vitis-HLS Project: fir
make csynth
make view_rpt
make co-sim
make co-emu
make clean
* command-line variable HW_STYLE must be set before build
HW_STYLE=[MACC | SHIFT | ARRAY] make csynth
a. 고위합성
C 로 작성한 언타임드 FIR 필터 fir8.cpp [연구노트9]를 가져다 고위합성 한다.
$ make csynth
vitis-run --mode hls --tcl Vitis-HLS.tcl
****** vitis-run v2024.2 (64-bit)
**** SW Build 5239630 on 2024-11-10-11:19:46
**** Start of session at: Mon Aug 18 16:37:10 2025
** Copyright 1986-2022 Xilinx, Inc. All Rights Reserved.
** Copyright 2022-2024 Advanced Micro Devices, Inc. All Rights Reserved.
**** HLS Build v2024.2 5238294
로그를 보면서 고위합성이 진행되는 과정을 간략히 살펴보자.
Sourcing Tcl script '~/ETRI050_DesignKit/Tutorials/2-8_Lab6_FIR8_c_untimed_Vitis-HLS/Vitis-HLS.tcl'
-DFIR_MAC_VERSION
언타임드 C 소스 코드의 합성 가능성을 분석하고 RTL로 변환 시작,
INFO: [HLS 200-1510] Running: csynth_design
INFO: [HLS 200-10] Analyzing design file '../2-5_Lab3_FIR8/c_untimed/fir8.cpp' ...
INFO: [HLS 214-376] automatically set the pipeline for Loop< SHIFTER_LOOP> at ../2-5_Lab3_FIR8/c_untimed/fir8.cpp:56:5
INFO: [HLS 214-376] automatically set the pipeline for Loop< MACC_LOOP> at ../2-5_Lab3_FIR8/c_untimed/fir8.cpp:66:5
INFO: [HLS 200-10] Starting code transformations ...
INFO: [HLS 200-10] Checking synthesizability ...
INFO: [HLS 200-10] Starting hardware synthesis ...
INFO: [HLS 200-10] Synthesizing 'fir' ...
반복문 내에 파이프라인 스케쥴링과 자원 공유(resource sharing) 가능성 분석,
INFO: [HLS 200-10] ----------------------------------------------------------------
INFO: [HLS 200-42] -- Implementing module 'fir_Pipeline_SHIFTER_LOOP'
INFO: [HLS 200-10] ----------------------------------------------------------------
INFO: [SCHED 204-11] Starting scheduling ...
INFO: [SCHED 204-61] Pipelining loop 'SHIFTER_LOOP'.
INFO: [HLS 200-1470] Pipelining result : Target II = NA, Final II = 1, Depth = 2, loop 'SHIFTER_LOOP'
INFO: [BIND 205-100] Starting micro-architecture generation ...
INFO: [BIND 205-101] Performing variable lifetime analysis.
INFO: [BIND 205-101] Exploring resource sharing.
INFO: [BIND 205-101] Binding ...
반복문 구조에서 클럭 소요(iteration)의 목표 클럭 수에 맞춰(예에서 목표 클럭 수 지정은 없음), 초기 지연(II) 1 클럭, 반복 준비(Depth)에 5클럭이 소요되도록 합성되었다(시뮬레이션 결과 파형 참조).
INFO: [HLS 200-42] -- Implementing module 'fir_Pipeline_MACC_LOOP'
INFO: [HLS 200-10] ----------------------------------------------------------------
INFO: [SCHED 204-11] Starting scheduling ...
INFO: [SCHED 204-61] Pipelining loop 'MACC_LOOP'.
INFO: [HLS 200-1470] Pipelining result : Target II = NA, Final II = 1, Depth = 5, loop 'MACC_LOOP'
INFO: [BIND 205-100] Starting micro-architecture generation ...
INFO: [BIND 205-101] Performing variable lifetime analysis.
INFO: [BIND 205-101] Exploring resource sharing.
RTL 하드웨어 코드 생성(합성 가능 베릴로그 및 VHDL),
INFO: [HLS 200-10] ----------------------------------------------------------------
INFO: [HLS 200-42] -- Implementing module 'fir'
INFO: [HLS 200-10] ----------------------------------------------------------------
INFO: [HLS 200-10] ----------------------------------------------------------------
INFO: [HLS 200-10] -- Generating RTL for module 'fir_Pipeline_SHIFTER_LOOP'
INFO: [HLS 200-10] ----------------------------------------------------------------
INFO: [HLS 200-10] ----------------------------------------------------------------
INFO: [HLS 200-10] -- Generating RTL for module 'fir_Pipeline_MACC_LOOP'
INFO: [HLS 200-10] ----------------------------------------------------------------
합성된 RTL 하드웨어는 fir() 수행에 여러 클럭이 소요되므로 입출력 신호 핸드쉐이크(인터페이스 합성),
INFO: [HLS 200-10] ----------------------------------------------------------------
INFO: [HLS 200-10] -- Generating RTL for module 'fir'
INFO: [HLS 200-10] ----------------------------------------------------------------
INFO: [RTGEN 206-500] Setting interface mode on port 'fir/y' to 'ap_vld'.
INFO: [RTGEN 206-500] Setting interface mode on port 'fir/x' to 'ap_none'.
INFO: [RTGEN 206-500] Setting interface mode on function 'fir' to 'ap_ctrl_hs'.
고위합성 후 생성된 RTL은 ./fir/hls_component/syn 폴더에 저장되었다.
~/ETRI050_DesignKit/Tutorials/2-8_Lab6_FIR8_c_untimed_Vitis-HLS
├── /emulation
├── /ETRI050
├── /simulation
├── /logs
│ └── hls_run_tcl.log
├── /fir
│ ├── hls.app
│ └── /hls_component
│ ├── hls_component.log
│ ├── /impl
│ │ ├── /verilog
│ │ └── /vhdl
│ └── /syn
│ ├── /report
│ │ ├── csynth_design_size.rpt
│ │ ├── csynth.rpt
│ │ ├── fir_csynth.rpt
│ │ ├── fir_Pipeline_MACC_LOOP_csynth.rpt
│ │ └── fir_Pipeline_SHIFTER_LOOP_csynth.rpt
│ ├── verilog
│ │ ├── fir_fir_Pipeline_MACC_LOOP_filter_taps_ROM_AUTO_1R.dat
│ │ ├── fir_fir_Pipeline_MACC_LOOP_filter_taps_ROM_AUTO_1R.v
│ │ ├── fir_fir_Pipeline_MACC_LOOP.v
│ │ ├── fir_fir_Pipeline_SHIFTER_LOOP.v
│ │ ├── fir_flow_control_loop_pipe_sequential_init.v
│ │ ├── fir_mac_muladd_8ns_6ns_16ns_16_4_1.v
│ │ ├── fir_shift_reg_RAM_AUTO_1R1W.dat
│ │ ├── fir_shift_reg_RAM_AUTO_1R1W.v
│ │ └── fir.v
│ └── vhdl
├── fir.cfg
├── Makefile
└── Vitis-HLS.tcl
b. HLS 결과 보기
$ make view_rpt
================================================================
== Vitis HLS Report for 'fir'
================================================================
* Project: fir
* Solution: hls_component (Vivado IP Flow Target)
* Product family: aartix7
* Target device: xa7a100t-csg324-2I
자일링스의 FPGA를 기준으로 작성된 보고서 이지만 소요 클럭과 연산회로, 플립플롭의 갯수등을 살펴볼 수 있다.
================================================================
== Performance Estimates
================================================================
+ Timing:
* Summary:
+--------+---------+----------+------------+
| Clock | Target | Estimated| Uncertainty|
+--------+---------+----------+------------+
|ap_clk | 1.00 us| 4.570 ns| 0.27 us|
+--------+---------+----------+------------+
구현 목표를 타 FPGA나 ASIC으로 전환 하는 경우 소요클럭 수는 유의미 하다.
+ Latency:
* Summary:
+---------+---------+-----------+-----------+-----+-----+---------+
| Latency (cycles) | Latency (absolute) | Interval | Pipeline|
| min | max | min | max | min | max | Type |
+---------+---------+-----------+-----------+-----+-----+---------+
| 27| 27| 27.000 us| 27.000 us| 28| 28| no|
+---------+---------+-----------+-----------+-----+-----+---------+
반복문에 대하여 상세 레이턴시 클럭수는 다음과 같다. fir8.cpp 에서 매크로 FIR_MAC_VERSION가 적용된 함수 fir()의 계산에 두번의 for-반복문이 있다. SHIFTER_LOOP에 10클럭, MACC_LOOP은 13 클럭을 쓰고 있다.
+ Detail:
* Instance:
+---------------------------+--------+------+-----+-----+--------------------+
| |Latency(cycles)| Interval | Pipeline |
| Module | min | max | min | max | Type |
+---------------------------+--------+------+-----+-----+--------------------+
|fir_Pipeline_SHIFTER_LOOP | 10| 10| 9| 9|loop auto-rewind stp|
|fir_Pipeline_MACC_LOOP | 13| 13| 9| 9|loop auto-rewind stp|
+---------------------------+--------+------+-----+-----+--------------------+
================================================================
== Utilization Estimates
================================================================
* Summary:
+-----------------+---------+-----+--------+-------+-----+
| Name | BRAM_18K| DSP | FF | LUT | URAM|
+-----------------+---------+-----+--------+-------+-----+
|FIFO | -| -| -| -| -|
|Instance | 0| 1| 112| 205| -|
|Memory | 0| -| 16| 1| 0|
|Multiplexer | -| -| 0| 78| -|
|Register | -| -| 15| -| -|
+-----------------+---------+-----+--------+-------+-----+
|Total | 0| 1| 143| 284| 0|
+-----------------+---------+-----+--------+-------+-----+
|Available | 270| 240| 126800| 63400| 0|
+-----------------+---------+-----+--------+-------+-----+
|Utilization (%) | 0| ~0| ~0| ~0| 0|
+-----------------+---------+-----+--------+-------+-----+
MACC_LOOP 심볼의 반복문 내 곱셈기는 DSP 블록으로 구현되었다.
+ Detail:
* Instance:
+---------------------------+---------+----+-----+-----+-----+
| Module | BRAM_18K| DSP| FF | LUT | URAM|
+---------------------------+---------+----+-----+-----+-----+
|fir_Pipeline_MACC_LOOP | 0| 1| 100| 115| 0|
|fir_Pipeline_SHIFTER_LOOP | 0| 0| 12| 90| 0|
+---------------------------+---------+----+-----+-----+-----+
| Total | 0| 1| 112| 205| 0|
+---------------------------+---------+----+-----+-----+-----+
================================================================
== Interface
================================================================
* Summary:
+----------+-----+-----+------------+--------------+--------------+
| RTL Ports| Dir | Bits| Protocol | Source Object| C Type |
+----------+-----+-----+------------+--------------+--------------+
|ap_clk | in| 1| ap_ctrl_hs| fir| return value|
|ap_rst | in| 1| ap_ctrl_hs| fir| return value|
|ap_start | in| 1| ap_ctrl_hs| fir| return value|
|ap_done | out| 1| ap_ctrl_hs| fir| return value|
|ap_idle | out| 1| ap_ctrl_hs| fir| return value|
|ap_ready | out| 1| ap_ctrl_hs| fir| return value|
|y | out| 16| ap_vld| y| pointer|
|y_ap_vld | out| 1| ap_vld| y| pointer|
|x | in| 8| ap_none| x| scalar|
+----------+-----+-----+------------+--------------+--------------+
c. RTL-SystemC 시뮬레이션
HLS로 생성된 베릴로그를 SystemC 테스트벤치에 물려 시뮬레이션 한다.
$ make co-sim
make -C simulation run
make[1]: Entering directory '~/ETRI050_DesignKit/Tutorials/2-8_Lab6_FIR8_c_untimed_Vitis-HLS/simulation'
verilator --sc --pins-sc-uint \
-Wno-WIDTHTRUNC -Wno-WIDTHEXPAND \
--trace --timing --top-module fir --exe --build \
-CFLAGS -g -CFLAGS -I../../../2-5_Lab3_FIR8/c_untimed \
-CFLAGS -I../../emulation -CFLAGS -DVCD_TRACE_TEST_TB \
-CFLAGS -DVCD_TRACE_DUT_VERILOG \
-CFLAGS -DSC_INCLUDE_FX \
-LDFLAGS -lm -LDFLAGS -lgsl -CFLAGS -DFIR_MAC_VERSION \
../fir/hls_component/syn/verilog/*.v \
./sc_fir_TB.cpp ./sc_main.cpp \
../../2-5_Lab3_FIR8/c_untimed/fir8.cpp \
../../2-5_Lab3_FIR8/c_untimed/cnoise.cpp
......
make[2]: Leaving directory '~/ETRI050_DesignKit/Tutorials/2-8_Lab6_FIR8_c_untimed_Vitis-HLS/simulation/obj_dir'
- V e r i l a t i o n R e p o r t: Verilator 5.039 ......
- Verilator: Built from 0.325 MB sources in 9 modules, ......
rm -f fir_fifo
mkfifo fir_fifo
python3 ./sc_plotDFT.py &
cp ../fir/hls_component/syn/verilog/*.dat .
./obj_dir/Vfir
SystemC 3.0.2-Accellera --- Jun 13 2025 17:49:45
Copyright (c) 1996-2025 by all Contributors,
ALL RIGHTS RESERVED
Info: (I703) tracing timescale unit set: 100 ps (sc_fir_tb.vcd)
[ 0] y= 0:Y= 0 OK
[ 1] y= 916:Y= 916 OK
[ 2] y= 3064:Y= 3064 OK
[ 3] y= 7281:Y= 7281 OK
[ 4] y=12313:Y=12313 OK
[ 5] y=17000:Y=17000 OK
[ 6] y=20017:Y=20017 OK
......
[4795] y=19408:Y=19408 OK
[4796] y=17472:Y=17472 OK
[4797] y=15344:Y=15344 OK
[4798] y=13738:Y=13738 OK
[4799] y=13102:Y=13102 OK
고위 합성으로 얻은 fir()의 베릴로그 RTL의 시뮬레이션 파형을 살펴보면 다음과 같다. SHIFTER_LOOP와 MACC_LOOP 구문이 연속적으로 진행된 모습을 관찰 할 수 있다. MACC_LOOP의 경우 초기준비에 1클럭, 반복 준비에 5 클럭 지연 후 매클럭마다 8번의 곱셈과 누산이 연속(pipeline)되는 것을 볼 수 있다.
4. Quartus
Quartus 는 알테라(Altera) FPGA 개발 도구를 모아놓은 패키지다. 자사의 FPGA에 특화된 합성과 배치배선 도구 그리고 QuestaSim HDL 시뮬레이터로 구성되었다. Quartus는 지멘스 EDA의 시뮬레이터 제품으로 무료가 아니지만 1년짜리 시험 사용 라이센스를 발급 받을 수 있다. 라이센스는 재발급 할 수 있다. 횟수 제한 없이 자동 발급된다. 라이센스를 발급받으려면 아래 링크에서 계정을 생성해 둔다. 물론 무료다.
4-1. Quartus 및 Questa 설치
아래의 링크에서 설치 파일(리눅스용 표준 판)을 내려받는다.
https://www.intel.com/content/www/us/en/collections/products/fpga/software/downloads.html
Intel® Quartus® Prime Standard Edition Design Software Version 24.1 for Linux
또는,
내려받은 파일에 실행 속성이 없을 경우,
$ chmod +x qinst-standard-linux-24.1std-1077.run
설치 프로그램 실행한다. 도구들의 설치 위치를 편의상 /opt 로 하기 위해 관리자 권한으로 실행 한다.
$ cd ~/Downloads
$ sudo ./qinst-standard-linux-24.1std-1077.run
설치 프로그램 실행한다. 도구들의 설치 위치를 편의상 /opt 로 하기 위해 관리자 권한으로 실행 한다. 설치 사항으로 Quartus Prime와 Questa-Altera FPGA Starter Edition을 선택한다. FPGA 제품군으로 Cyclone IV 와 V 를 고른다. 설치 위치를 /opt/intelFPGA_standard/24.1std 로 변경한다.
옵션을 확인 하고 설치 시작.
설치를 확인해보자. Quartus의 설치 경로를 환경변수 PATH에 추가한 후 quartus 실행,
$ export PATH=/opt/intelFPGA_standard/24.1std/quartus/bin:$PATH
$ quartus
30-일 평가사용(Evaluation) 할 수 있다. 만일 평가기간이 만료되었다고 하면 ~/.altera.quartus 디렉토리를 삭제하면 다시 평가사용 기간이 시작된다.
$ rm -rf ~/.altera.quartus
Questa 는 업계 공인 최고수준의 HDL 시뮬레이터다. Verilog, SystemVerilog, VHDL은 물론 SystemC까지 혼합 시뮬레이션이 가능하다. Intel/Altera에서 이 시뮬레이터의 라이센스를 Quartus 와 함께 무료 공급하고 있다. 라이센스는 "Acquire" 버튼을 눌러 자동으로 발급 받을 수 있다. 라이센스 파일은 ~/.altera.quartus/quartus2_lic.dat 다. 환경 변수에 LM_LICENSE_FILE에 다음과 같이 추가한다.
$ export LM_LICENSE_FILE=/home/goodkook/.altera.quartus/quartus2_lic.dat
라이센스를 설정하면 Questa HDL 시뮬레이터를 무료로 1년간 사용할 수 있다. 기간이 만료되면 다시 발급 받아 사용할 수 있다. Questa 가 설치된 경로를 추가한 후 실행시켜보자.
$ export PATH=/opt/intelFPGA_standard/24.1std/quartus/bin:$PATH
$ export PATH=/opt/intelFPGA_standard/24.1std/questa_fse/bin:$PATH
$ export LM_LICENSE_FILE=~/.altera.quartus/quartus2_lic.dat
$ vsim
4-2. FIR 필터의 에뮬레이션 검증
VitisHLS 로 얻은 FIR 필터의 베릴로그 RTL을 알테라 FPGA에 담아 검증한다.
MyChip-On-MyDesk
"내 책상"위에서 "내 칩"을 설계하고 검증하며 테스트할 수 있는 환경을 꾸며보자.
-
Altera Cyclone-IV FPGA 보드와 어댑터 보드
FPGA 다운로더. Xilinx 케이블 이지만 호환성이 뛰어나 범용 JTAG 케이블로 사용할 수 있다. Digilent HS2로 작동, Xilinx 및 Altera FPGA 다운로더로 사용
Arduino DUE 모듈과 어댑터 보드
- ARM-M3 코어, 512K바이트 롬, 96K 바이트 램 내장
- 디지털 IO 54개(PWM 가능 12개), 아날로그 IO(ADC 6채널, DAC 2채널)
자작 오실로스코프/로직 아날라이져 Scoppy PI Pico와 입출력 보드
- Scoppy는 안드로이드 앱이다. 휴대전화를 오실로스코프/로직아날라이져의 표시장치로 활용
어댑터 보드의 회로도와 PCB 거버파일은 "디자인 킷" 포함되어있다.
https://github.com/GoodKook/ETRI-0.5um-CMOS-MPW-Std-Cell-DK/tree/main/PSCE_API/Board
C 코드로부터 고위 합성된 베릴로그 RTL을 알테라의 FPGA Cyclone IV 로 합성한다. Quartus 는 명령줄에서 tcl 스크립트로 실행,
.....
자일링스 JTAG 다운로더 케이블 활용 FPGA로 다운 로드,
$ openFPGALoader -c digilent_HS2 output_file.rbf
시뮬레이션 검증에서 쓰였연 테스트벤치를 재사용하여 에뮬레이션,
$ make co-emul
5. FIR 필터의 "내 칩" 레이아웃
"남의 칩"으로 검증을 마친 FIR 필터를 "내 칩"으로 제작하기 위한 레이아웃을 생성해보자.
작업 디렉토리로 이동,
$ ~/ETRI050_DesignKit/Tutorials/2-8_Lab6_FIR8_c_untimed_Vitis-HLS/ETRI050
준비된 Makefile 을 사용하기로 한다. 합성과 배치배선을 거쳐 레이아웃을 생성한다.
$ make synthesize
시뮬레이션.
$ cd simulation
$ make build_net
$ make run
배치
$ make place
배선
$ make route
표준 셀 병합
$ make migrate
LVS
$ make lvs
코어 크기
$ make size
코어의 크기가 1023.600 x 985.050 다. 아쉽게도 "내 칩" MPW에서 요구하는 면적보다 약간 크다. 설계 최적화가 필요하다. 코어의 GDS(레이아웃)은 다음과 같다.
$ cd layout
$ make mag2gds
$ make klayout
<그림>
6. 맺음말
C 로 기술한 FIR 필터 알고리즘을 고위합성 도구 VitisHLS를 사용하여 베릴로그 RTL로 변환 하고 FPGA로 검증을 실시하였으며 이를 최종적으로 "내 칩"으로 제작하기 위한 레이아웃까지 생성하는 과정을 기술했다. 최고 추상화 수준에서 가장 낮은 레이아웃에 이르기까지 오픈-소스 도구와 무료로 제공되는 FPGA 도구들이 사용됐다. 추상화 수준이 낮춰질 때마다 시뮬레이션과 에뮬레이션 검증을 거쳤다. SystemC로 작성된 테스트벤치가 재사용되고 있다는 점에 주목한다. 반도체 설계 자동화 도구들의 소개를 위한 목적이므로 기법들을 자세히 설명하지 못했다. 깃허브를 통해 배포된 예제를 따라 해보면서 설계과정을 익히기 바란다. 그리고 그 과정이 필요한 이유를 토론해보기 바란다. C/C++ 언어를 이해 한다면 반도체 칩을 설계 할 수 있다는 말이 허사가 아님을 알아챘길 바란다. 각 추상화 단계별 설계 기법의 세밀한 내용은 향후 학습 노트에서 설명할 것이다. 중소규모 산업과 교육 현장에서디 지털 반도체 설계에 도구의 장벽은 무너졌다.
-------------------------------------
[참고]
[1] "내 칩 제작 서비스 디자인 킷" 배포처, https://github.com/GoodKook/ETRI-0.5um-CMOS-MPW-Std-Cell-DK.git
[2] Roadmap and Recommendations for Open Source EDA in Europe, https://fossi-foundation.org/resources/eu-roadmap
[3] Are Open-Source EDA Tools Ready for a Multi-Million-Gate, Linux-Booting RV64 SoC Design?, https://arxiv.org/html/2405.04257v2
[4] OpenROAD: Toward a Self-Driving, Open-Source Digital Layout Implementation Tool Chain, https://par.nsf.gov/servlets/purl/10171024
댓글 없음:
댓글 쓰기