FPGA PYNQ 시작하기, Overlay Tutorial
Get board files
이 문서에서는 pynq-z2 보드를 기준으로 개발한다. pynq가 뭔지 모른다면 공식문서를 보고 구매할 수 있다. 가격도 합리적이라 연구용 구매에 부담도 없다.
이 보드로 개발하기 위해서는 여기에 맞는 board file을 미리 설치해야 한다.
https://dpoauwgwqsy2x.cloudfront.net/Download/pynq-z2.zip 에서 board files을 다운받고
(Xilinx Path)/Vivado/2020.1/data/boards/board_files 경로에 압축을 푼다.
VIVADO HLS
우선 VIVADO와 VIVADO HLS를 설치해야 한다. 설치는 자일링스 공식 문서나 다른 블로그를 참고하면 된다. 소프트웨어 개발 툴 치고 개인적으로 설치가 어렵고 용량도 몹시 커서 시간이 오래 걸릴 수 있어서 한나절 정도 시간을 잡고 설치 하길 권장 한다.
FPGA는 기본적으로 verilog 또는 VHDL으로 실행된다. 그러나 소프트웨어 개발자가 이런 언어로 회로 코드를 설계하기 어렵기 때문에 C언어 같이 상대적으로 고급 언어로 FPGA 회로 설계를 가능하게 해 주는게 VIVADO HLS이다.
C언어로 코드를 짜면, 그걸 verilog 또는 VHDL코드로 바꿔주기 때문에 따로 verilog나 VHDL를 배우지 않아도 된다. (대신 VIVADO HLS 배워야 하지만... 소프트웨어 개발자 입장에선 차라리 이게 더 쉬울 거 같다.)
OS 버전과 VIVADO 버전이 중요한데, 이 문서에서는 Ubuntu 18.04에 Vivado v2020.1 (64-bit)와 HLS를 설치했다. 운영체제 버전과 Vivado 버전에 따라 일부 기능에 차이가 있거나 메뉴얼대로 해도 안되는 디테일한 부분들이 다르기 때문에 버전에 유의해야 한다. 특히 용량이 커서 여러 버전을 한 환경에 설치 하기 부담이 크다. 프로젝트에 따라 한 가지 버전을 정해놓고 하는것이 좋다.
우선 VIVADO를 실행하면 이런 메인 페이지가 나오는데. Create New Project로 새 프로젝트를 생성한다.
프로젝트 경로와 이름을 설정한다. 나중에 HLS 프로젝트도 생성해야 하기 때문에 이 위치와 이름을 알아보기 좋게 설정하고 기억 해 둬야 한다. 이 프로젝트에서는 32bit int 값을 더하는 단순한 샘플이기 때문에 이름을 adder로 한다.
Top Function은 add로, Design Files는 New File을 눌러서 adder.cpp 파일을 생성한다.
Part를 타겟보드에 맞게 설정해야 합니다. 이 문서에서 쓰는 pynq-z2에 맞게 설정한다.
프로젝트가 생성되면 좌측 Explorer에 adder(프로젝트 이름) 아래 있는 Source 밑에 생성 한 adder.cpp가 있다. 참고한 문서대로 아래 코드를 입력한다.
<pre class="wp-block-syntaxhighlighter-code">void add(int a, int b, int& c) {
#pragma HLS INTERFACE ap_ctrl_none port=return
#pragma HLS INTERFACE s_axilite port=a
#pragma HLS INTERFACE s_axilite port=b
#pragma HLS INTERFACE s_axilite port=c
c = a + b;
}
위 코드를 보면 복잡한 paragma는 무시하고 대충 봐도 a, b, c를 파라미터로 받고 a와 b를 더해서 c에 넣는 간단한 구조이다.
adder.cpp 파일을 저장하고 상단 바에 재생버튼(Run C Synthesis)로 합성을 한다.
Synthesis가 끝나면 이런 리포트가 올라온다. 타켓 보드에서의 시간과 자원을 얼마나 사용하는지 등이 나오는데 간단한 adder이기 때문에 이 부분이 지금 중요하진 않다.
상단에 Export RTL을 눌러 RTL을 내보낸다.
Verilog나 VHDL로 내보낼 수 있다. 그냥 Verilog RTL로 설정하고 OK를 누른다.
Verilog RTL Export에는 몇 초 정도 시간이 걸립니다.
끝나면 좌측 Explorer에 solution1/impl/misc/drivers/add_v1_0/src/xadd_hw.h 파일을 보면 레지스터 오프셋이 있다. 0x10은 Data a, 0x18은 Data b, 0x20은 Data c가 위치해 있다.
VIVADO
위에서는 HLS인데, 지금부터는 그냥 VIVADO이다.
HLS는 High-Level Synthesis라는 뜻으로.. C언어로 회로를 만드는 것(?) 이라고 이해하면 되고, VIVADO는 (HLS로 합성된 회로를 가지고) 최종 결과물(?)을 내는 것이기 때문이 개발 툴 자체가 다르다. HLS 개발을 하면 이 두개를 용도에 맞게 둘 다 써야 한다.
HLS와 다른 위치에 프로젝트를 생성 한다.
RTL Project를 선택한다.
Part를 pynq-z2로 선택한다.
프로젝트가 생성되면 좌측 Flow Navigator에서 IP INTEGRATOR -> Create Block Design을 눌러서 Block Design을 생성한다.
Block Design이 생성되면 우측 상단에 Diagram 창이 있고 Add IP로 IP를 추가할 수 있다.
ZYNQ7를 검색해서 추가 해 주면 이렇게 블럭이 하나 생긴다. 근데 이 블럭만으로는 잘 돌아가지 않으니 기본적으로 필요 한 걸 자동으로 만들어 줘야 한다. 상단에 민트색 바에 있는 Run Block Automation을 누르고 기본 설정으로 적용한다.
그러면 이렇게 DDR과 외부 IO를 자동으로 연결 해 준다. 여기 까지가 그냥 PYNQ 보드를 기본적으로 쓸 수 있는 상태(?)이고 여기 에다가 위에서 만든 adder를 연결해야 한다.
위에 HLS로 만든 IP를 추가하기 위해서 그 경로를 설정해야 한다.
상단 툴바 Tools -> Settings... 으로 들어가간다.
Project Setting에서 IP에서 Repository에서 IP Repositories를 추가한다. 경로를 잘 설정했다면 위에 HLS에서 만든 Add를 잘 로드한다.
다시 Block Design으로 가서 방금 추가 한 Add Block를 추가하면 이렇게 추가된다.
예제과 똑같이 하기 위해서 Add Block를 선택하고 좌측에서 Block 설정에서 이름을 scalar_add으로 바꾼다.
새로운 Block이 추가됐기 때문에 Run Connection Automation으로 자동 연결을 실행한다.
제대로 자동 연결이 됐다면 이렇게 연결된다.
이제 이걸 저장해야 하는데, Design Source에서 design_1 우클릭해서 Create HDL Wrapper를 눌러서 auto-update한다. 그러면 HDL Wrapper가 생성된다.
비트스트림 생성을 위해서 좌측 하단에 PROGRAM AND DEBUG에서 Generate Bitstream을 누른다. 컴퓨터 사양에 따라서 시간이 좀 걸린다.
비트스트림이 생성되면 File -> Export -> Export Block Design으로 TCL 파일을 Export 한다.
<pre class="wp-block-syntaxhighlighter-code">(base) [dkdk@~/fpga/adder_vivado/project_1] $ ls -al
합계 100K
drwxrwxr-x 9 dkdk dkdk 4.0K 6월 19 14:57 .
drwxrwxr-x 3 dkdk dkdk 4.0K 6월 19 14:14 ..
-rw-rw-r-- 1 dkdk dkdk 42K 6월 19 14:57 design_1.tcl
drwxrwxr-x 4 dkdk dkdk 4.0K 6월 19 14:55 project_1.cache
drwxrwxr-x 3 dkdk dkdk 4.0K 6월 19 14:15 project_1.hbs
drwxrwxr-x 2 dkdk dkdk 4.0K 6월 19 14:15 project_1.hw
drwxrwxr-x 2 dkdk dkdk 4.0K 6월 19 14:15 project_1.ip_user_files
drwxrwxr-x 9 dkdk dkdk 4.0K 6월 19 14:55 project_1.runs
drwxrwxr-x 2 dkdk dkdk 4.0K 6월 19 14:15 project_1.sim
drwxrwxr-x 3 dkdk dkdk 4.0K 6월 19 14:17 project_1.srcs
-rw-rw-r-- 1 dkdk dkdk 20K 6월 19 14:57 project_1.xpr
위와 같이 tcl 파일이 저장된 것을 볼 수 있다.
이름을 알아보기 좋게 바꾸고 추가로 필요한 파일을 아래와 같이 복사해 온다.
- design_1.tcl파일을 adder.tcl로 바꾼다.
- project_1.runs/impl_1/design_1_wrapper.bit 파일을 adder.bit으로 복사해 온다.
- project_1.srcs/sources_1/bd/design_1/hw_handoff/design_1.hwh 파일을 adder.hwh으로 복사해 온다,.
xilinx@pynq:~/pynq/overlays/adder$ ls -al
total 4152
drwxrwsr-x 2 xilinx xilinx 4096 Jun 18 00:21 .
drwxr-sr-x 6 xilinx xilinx 4096 Jun 17 18:34 ..
-rw-rw-r-- 1 xilinx xilinx 4045676 Jun 18 00:21 adder.bit
-rw-rw-r-- 1 xilinx xilinx 149007 Jun 18 00:21 adder.hwh
-rw-rw-r-- 1 xilinx xilinx 42939 Jun 18 00:21 adder.tcl
프로젝트에서 생성된 adder.bit, adder.hwh, adder.tcl 3개의 파일을 PYNQ 보드로 복사 해야 한다.
PYNQ 보드가 기본세팅이 안돼있다면 보드에 맞는 petalinux(페타리눅스)를 설치해야 한다. 라즈베리 파이에 라즈비안을 설치 하듯이.. xilinx에서 만든 리눅스 배포판이다. 버전에 맞게 SD카드를 만들어서 부팅하면 된다. PYthon과 Jupyter도 된다.
petalinux로 부팅 한 후에 ~/pynq/overlays/adder에 adder.bit, adder.hwh, adder.tcl 3개의 파일을 복사 한다.
sftp로 옮기던지.. 아무튼 파일을 복사한다.
보드 ip의 80 port로 접속하면 jupyter가 뜨는데 여기서 위와 같이 overlays된 파일을 사용하면 덧셈 연산이 실행 된다. 단순히 덧셈만 하기 때문에 cpu에 비해서 연산 속도가 월등히 빠르거나 하진 않다. (오히려 느리다.)
하지만 이 문서는 전체 프로세스를 샘플로 실행하는 것이기 때문에... 이것을 이용해서 HLS의 코드(PL) 역할에 따라서 FPGA를 이용할 수 있을 것으로 기대 한다.