FPGA 보드에서 특정 행렬을 연산하는 연산기를 설계하고, 이를 검증하는 프로젝트 HPS-FPGA 시스템을 이용했다.
DE1-SoC 보드를 사용함.
Quartus에서 제공하는 platform designer인 QSYS를 사용해서 Intel의 Avalon bus system을 사용했다.
![스크린샷 2024-11-13 오전 9 18 59](https://private-user-images.githubusercontent.com/54656519/385519575-1395b1cd-8bfb-4241-b3d6-151bf4737642.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3Mzg5MzQzMTAsIm5iZiI6MTczODkzNDAxMCwicGF0aCI6Ii81NDY1NjUxOS8zODU1MTk1NzUtMTM5NWIxY2QtOGJmYi00MjQxLWIzZDYtMTUxYmY0NzM3NjQyLnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNTAyMDclMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjUwMjA3VDEzMTMzMFomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPWZlYTA1N2VmYjgyNWQ2M2EzNDAzNjM0NWVhMmQyNjk5ZGFkYmMyY2NmNTM0Zjc3YmE4YTAyMjJiNzM5YmU1ODAmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0In0.UoleKl3QUOrtu2-L9HfENBQESHS8e53M_5MohEa7gw4)
On-chip SRAM 0의 0번지 주소를 통해 HPS와 FPGA가 hand-shanking(0 이면 IDLE, 1이면 Working)
- On-chip SRAM 0의 0번째 하위 32비트 값이 0이면 IDLE -> 동작 안함
- Write (SW)
- HPS는 on-chip SRAM 0의 4-15번지에 weight 값을 쓴다.(weight_ptr)
- HPS는 on-chip SRAM 1의 0-11번지에 fmapA 값을 쓴다. (fmap_ptr)
- HPS는 on-chip SRAM 2의 0-11번지에 fmapB 값을 쓴다. (fmap_ptr)
- Write (HW)
- HW는 on-chip SRAM1의 12-15번지에 mac result a를 쓴다.
- HW는 on-chip SRAM2의 12-15번지에 mac result b를 쓴다.
- HW는 On-chip SRAM 0의 0번지 하위 32비트의 1값을 다시 0으로 쓴다.
- HPS는 지속적으로 on-chip SRAM 0의 0번지를 읽으며, 해당 값이 0으로 바뀌면 matrix operation이 끝난 것을 인지한다.
![스크린샷 2024-11-13 오전 9 25 54](https://private-user-images.githubusercontent.com/54656519/385522292-a3d5f4c6-e95f-4c5c-9554-eadc058b55da.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3Mzg5MzQzMTAsIm5iZiI6MTczODkzNDAxMCwicGF0aCI6Ii81NDY1NjUxOS8zODU1MjIyOTItYTNkNWY0YzYtZTk1Zi00YzVjLTk1NTQtZWFkYzA1OGI1NWRhLnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNTAyMDclMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjUwMjA3VDEzMTMzMFomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTQ2NWVlNGQ4MjViNjQ5N2ExYzVmZDk2NTEyMDkzZDI4NmIxZGE0MzNmMDNlYTMyMzllOTJjY2NmOGIzMTNiOWMmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0In0.5m8SZkDkVQaAbGe8OUjCmsVWU8e4n0MrpDT3cbTreM8)
IP Generation을 통한 computer_system & FPGA 연결해주는 Top Module
- 기존의 M10K_read_write.v 모듈을 확장
- M10K_read_write.v에서 READ-WRITE state 사이에 CNN_RUN state를 추가했다 (다른 연산으로 변경 가능)
- 이전에 작성한 cnn_topCore 모듈 인스턴스 추가 (+관련 start, done 신호 추가)
- 3개의 M10K_read_buffer 존재 (SRAM0, SRAM1, SRAM2)
- 2개의 M10K_write 존재 (SRAM1, SRAM2)
- M10K_read_buffer에서 받아온 데이터를 다시 setup 해주어야 한다.
- cnn_topCore 에서 나온 data도 마찬가지로 setup 해서 M10K_write에서 write 해줘야 한다.
프로젝트의 변수들을 저장하고 있다. (const처럼 사용하기 위함)
DE1-SoC 보드의 자원한계로 기존에 Generate
구문으로 작성했던 것을 FSM으로 바꿔 작성해야 했다.
또한, 이에 맞춰 control signal을 다시 입력하는 문제, 타이밍 불일치 문제를 해결해야 했고, 이에 상당한 시간이 소요되었다.
![image](https://private-user-images.githubusercontent.com/54656519/385526068-b61d8af9-dffd-43ef-b236-228537afbd9e.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3Mzg5MzQzMTAsIm5iZiI6MTczODkzNDAxMCwicGF0aCI6Ii81NDY1NjUxOS8zODU1MjYwNjgtYjYxZDhhZjktZGZmZC00M2VmLWIyMzYtMjI4NTM3YWZiZDllLnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNTAyMDclMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjUwMjA3VDEzMTMzMFomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTI0YzFlZWUyZGU2N2RlZjY0OWIxODQ4YTcxZGEzYzgyYjQ5NDQ1MTk3ZTk1MTM2YWI4MDUyMjU4M2Y1NjFhNzgmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0In0.Q65UdTJKJVWdSsWoYpHoEOE9wQ0t38Nh_vB76p3cn9c)
![image](https://private-user-images.githubusercontent.com/54656519/385526170-dcc622a8-588f-4cbf-a044-16cc9c7f131f.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3Mzg5MzQzMTAsIm5iZiI6MTczODkzNDAxMCwicGF0aCI6Ii81NDY1NjUxOS8zODU1MjYxNzAtZGNjNjIyYTgtNTg4Zi00Y2JmLWEwNDQtMTZjYzljN2YxMzFmLnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNTAyMDclMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjUwMjA3VDEzMTMzMFomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTNlY2FhYmM0MjFhNjM0Njg1NDdhZGExMzU0YzA3M2QyZmFkNTE1YjczY2NmMDkxYmUyYjhkYjQyOTUwYjUzZGEmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0In0.UDJwsDKedo6UFjs1C_UcFVNQg7s66EFXtO8TsT9CBjU)
![image](https://private-user-images.githubusercontent.com/54656519/385526278-9e267979-5512-49b8-a15a-ad2ecd399467.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3Mzg5MzQzMTAsIm5iZiI6MTczODkzNDAxMCwicGF0aCI6Ii81NDY1NjUxOS8zODU1MjYyNzgtOWUyNjc5NzktNTUxMi00OWI4LWExNWEtYWQyZWNkMzk5NDY3LnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNTAyMDclMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjUwMjA3VDEzMTMzMFomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTAzNjNjMTc0ZDc2ZTZmOTZmYzgxOTE1MTU1MmQ1N2M4Zjk0YTYxNzA0YjQ1ZTc3YTY4NWRmMmNhOTBiY2MyZTUmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0In0.ij8_9KKwGbphqKiFKattRxe9hBO-oBsV3pTydiwowss)
![image](https://private-user-images.githubusercontent.com/54656519/385526597-fcb1e8ca-87f3-4d9c-9268-5a68c71eb140.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3Mzg5MzQzMTAsIm5iZiI6MTczODkzNDAxMCwicGF0aCI6Ii81NDY1NjUxOS8zODU1MjY1OTctZmNiMWU4Y2EtODdmMy00ZDljLTkyNjgtNWE2OGM3MWViMTQwLnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNTAyMDclMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjUwMjA3VDEzMTMzMFomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTJjYTMxYzI3NDEyNTlkNWExNmYzZDMyYTM0OTRlMmJlZDE3MzFhZGI1ZWM2NWZmY2M3ZjQ1YTUxZGEyYTcyZmMmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0In0.6v2jA7iuw407PmxF9MukM5818IpzunXH37xsKFj2lRA)
연산 결과가 일치한 모습을 볼 수 있다.
![image](https://private-user-images.githubusercontent.com/54656519/385526813-1c40c2dd-012f-4bf0-853c-944db2cac8c0.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3Mzg5MzQzMTAsIm5iZiI6MTczODkzNDAxMCwicGF0aCI6Ii81NDY1NjUxOS8zODU1MjY4MTMtMWM0MGMyZGQtMDEyZi00YmYwLTg1M2MtOTQ0ZGIyY2FjOGMwLnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNTAyMDclMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjUwMjA3VDEzMTMzMFomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTg3NTEzNWZmMDQ2Mzg0YWNhNmNkN2JmMjY5OTA5YzE3NmU4YjYwN2RhZDI4MGFlZWEyODU4MTdkMjAzZWU2YTImWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0In0.xEQuB4szpLqg6V34A9oIO0yZcH9ms5y3ZgVthAfacZc)
Cnn_core 시뮬레이션에서는 문제가 없었지만, FPGA 보드에 linux로 실행할 때 cnn_core에서 잘된 것과 대비되게 잘 실행되지 않았고 원인을 몇가지 분석했다.
- Timing 문제
- Cnn_core에서도 타이밍 때문에 고생했지만, mat_ops.v에서 역시 cnn_core를 instance로 사용하기 때문에 값이 오가는 타이밍을 잘 맞추지 못해 연산 결과가 다르게 나왔을 수도 있다.
- 비트 분산 문제
- Linux의 cnn을 수행하는 코드가 c로 짜여진 탓에 실제 메모리 공간을 활용할 때 데이터 사이에 빈 공간이 생겼다. 이를 벡터로 가져와 전처리, 후처리를 진행할 때 LSB, MSB를 헷갈려 틀렸을 수도 있다.
Generate 구문을 활용하는 것이 병렬 연산이 가능하기 때문에 Verilog 코드를 작성할 때 편했다.
하지만, M10K의 자원적 제약 때문에 각 모듈을 pipelining을 진행했을 때, 이론적으로는 완벽했지만, 각 모듈들의 timing을 맞추는 문제가 제일 어려웠다.
특히, cnn_core에서는 in_valid 신호가 generate일 때는 한 번만 넣어주면 되었기에 pipeline으로 바꿀 때 각 스테이지마다 새로운 in_valid 신호를 만들고, 이를 타이밍 맞게 넣는 것이 쉽지 않았다.
이번 프로젝트를 통해 자원 소모량과 소모 시간 간에 trade off가 있음을 느낄 수 있었고 실제 FPGA와 HPS 통신이 쉽지 않은 일임을 깨달을 수 있었다.