<!-- 113.2.3 -->
# **<font color="purple">"Advanced SoC Design" Course Study Journal</font>**
This study journal is created by Yeh Cheng-Hong, 112501538, CoSR department, NTHU.
Course: NTHU 11220EE525200 高階系统晶片設計(Advanced SOC Design)
For the study journal of SoC-design course last semester, please click [here](https://hackmd.io/@whywhytellmewhy/S1joJxm1p).
<br/><br/>
<!-- 113.2.3開始 -->
## Lab 1: Integrate FIR into FSIC
- 題目的Github位置:https://github.com/bol-edu/fsic_fpga/tree/main
- 更新後的Github位置(公布在eeclass上的):https://github.com/bol-edu/caravel-soc_fpga-lab/tree/main/fsic-sim
- 記錄一下有改到的部分:
1. Add FIR-related files from `/Final_project` (in [SoC design course](https://github.com/whywhytellmewhy/SOC-design)) into `/lab_1/fsic_fpga/rtl/user/user_subsys/user_prj/user_prj1/rtl`
2. `/lab_1/fsic_fpga/rtl/user/user_subsys/user_prj/user_prj1/rtl/user_prj1.v`
3. `/lab_1/fsic_fpga/rtl/user/user_subsys/user_prj/user_prj1/rtl/rtl.f`
4. `/lab_1/fsic_fpga/rtl/user/testbench/tc/filelist`
5. `/lab_1/fsic_fpga/rtl/user/testbench/tb_fsic.v`
- issue
1. tb_fsic中要「Program [‘h3000_5000] = **32’h01**」(**而非32’h02**)才可將user_project_1 enable?
- 因為發現當沒有特別去program它時,會為default值0,此時user_project_0可運作
- 當特別將它program為1時,user_project_1可運作,user_project_0不運作
- 可由`/lab_1/fsic_fpga/rtl/user/config_ctrl/rtl/config_ctrl.v`中的下圖:

以及`/lab_1/fsic_fpga/rtl/user/user_subsys/axil_slav/rtl/axil_slav.v`中的下圖得知。

- 但此與 [workbook這一頁](https://docs.google.com/presentation/d/1V06u84HeIAGzz7sjz3WoeaC0yEsZNmcE/edit#slide=id.p16) 說法不一致
- ➜ 最後決定先使用「Program [‘h3000_5000] = **32’h01**」
2. 若將FIR放在user_project_1,會發現read SoC configuration時有下列情況:

~~即使FIR已經handshake但WB仍沒有傳送回ACK~~
:::info
**(更新版)** 最後先在user_project_0中完成後再將FIR放入user_project_1,此時有傳送回ACK,但值會讀到user_project_0的AA55AA55

:::
➜但若將FIR放到user_project_0(原本放在user_project_0的先換到user_project_1):

並**先不設定**「Program [‘h3000_5000] = 32’h01」,就可以正常運作:

➜ 最後決定**先將其放在user_project_0**
- **Solution**:
1. 在`/lab_1/fsic_fpga/rtl/user/rtl/fsic.v`中搜尋「wbs_rdata」,得知其來自`/lab_1/fsic_fpga/rtl/user/config_ctrl/rtl/config_ctrl.v`
2. 在`config_ctrl.v`中搜尋「wbs_rdata」,發現其來自「wb_axi_rdata」


➜ 再追溯得知來自「m_axi_rdata」
➜ 「m_axi_rdata」來自「axi_rdata2」(與user project有關的部分)


3. 再追溯得知來自 `/lab_1/fsic_fpga/rtl/user/user_subsys/axil_slav/rtl/axil_slav.v`的「axi_rdata」
➜ 在`axil_slav.v`中

➜ ~~可知output為 user_project_0 ~ user_project_3 的相對應output直接做OR得到,而非透過user_prj_sel選出~~ <font color="blue">**發現在上圖第117行、第122行、第126行、...的 `...? XX_0 : 0 ;`,應改為`XX_1`**</font>。
<br/>
<!-- 113.4.3開始 -->
## Lab 2-1: Catapult FIR
- 題目的Github位置:https://github.com/bol-edu/caravel-soc_fpga-lab/tree/main/catapult_hls
- 記錄一下要完成的部分:
1. catapult_setup(NTHU).pptx
- [x] 修改`.tcshrc`
- [x] 複製`/home/course/ee5252/catapult`資料夾到自己的working space
- [x] 執行`source sun_catapult`
- [x] 跑一遍lab1_fir <font color="#E5E7E9">➜在113.4.5~ 03:03 a.m.在屏東完成</font>
- [x] create “bin” folder to save execution file
- 記錄一下實作的過程:
1. **01_walkthrough_loops**
1. `cd /catapult/catapult-for-soc-course/lab1_fir/01_walkthrough_loops`
2. `mkdir bin`,不然`make`後會error
3. `make`
4. `./bin/SCVerify_fir.exe`
5. 剩下的部分按照"Step_by_step_lab1_FIR.pdf"的 p.11 ~ p.31 的步驟實作
2. **02_mem_ifc**
1. 按照"Step_by_step_lab1_FIR.pdf"的 p.32 ~ p.40 的步驟實作
3. **03_multi_blks**
1. 按照"Step_by_step_lab1_FIR.pdf"的 p.41 ~ p.59 的步驟實作
2. Improve the throughput from 10 to 1:
1. 將block0、block1的「SHIFT」及「MAC」做 "Unroll"
2. 將block0、block1、block2的「main」做 "Pipeline (II=1)"
3. 按下「RTL」步驟後,執行結果為

其中top.v1為初始設定;top.v2為尚未將block2的「main」做 "Pipeline (II=1)"時的結果;top.v3則為最終結果。
3. 按照"Step_by_step_lab1_FIR.pdf"的 p.61 的步驟實作
- ### ==**C/C++轉換成HLS的過程中需要注意的事項**==
1. From "Step_by_step_lab1_FIR.pdf"
- header要記得加上
```C
#include <ac_int.h>
#include <ac_channel.h>
#include <mc_scverify.h>
```
有時候會需要加上fix point的小數(有如floating point,但硬體上必須fix其bit數)
```C
#include <ac_fixed.h>
```
:::warning
若在C程式碼中有`#include <math.h>`,則要修改為Catapult提供的`#include <ac_math.h>`
:::
- 每個class一定要有initialization/constructor,例如:
```C
class fir {
private:
...
public:
fir() {
...
}
}
```
- 在class中的top function前要加上`#pragma hls_design interface`,且top function要改寫如下:
1. 原本的C程式碼為
```C
void run(int input, int coeffs[8],int &output) {
...
}
```
2. 改寫成HLS後變為
```C
#pragma hls_design interface
void CCS_BLOCK(run)(ac_channel<int8> &input, int8 coeffs[8], ac_channel<int8> &output) {
...
}
```
- 讀取input值要從`A=input;`變為`A=input.read();`
- 輸出output值要從`output=temp;`變為`output.write(temp);`
- 除了for loop中宣告的`int i`以外,`int temp;`要改寫為`int數字 temp;`
- 每個for loop前加上label,且for loop中的`i`盡量寫為相同順序,例如:
1. 原本的C程式碼為
```C
for (int i=7; i>=0; i--) {
...
}
for (int i=0; i<8; i++) {
...
}
```
2. 改寫成HLS後變為
```C
SHIFT:for (int i=7; i>=0; i--) {
...
}
MAC:for (int i=7; i>=0; i--) {
...
}
```
- ### Memory Interface
要改為memory interface,則需要修改:
- 原本為
```C
#pragma hls_design interface
void CCS_BLOCK(run)(ac_channel<int8> &input,
int8 coeffs[8],
ac_channel<int8> &output) {
...
}
```
變為
```C
#pragma hls_design interface
void CCS_BLOCK(run)(ac_channel<int8> &input,
ac_int<8> coeffs[32][8],
ac_channel<ac_int<5,false>> &coeff_addr,
ac_channel<int8> &output) {
...
}
```
- 除了for loop中宣告的`int i`以外,`int數字 temp;`要改寫為`ac_int<數字> temp;`
- 原本的`coeffs[8]`為input,要改為memory interface
```C
ac_int<5,false> addr = coeff_addr.read();
```
並以`coeffs[addr][i]`來讀取其值
- ### Multiple Blocks
要實作multiple blocks,則需要注意:
- top design要使用`#pragma hls_design interface top`;其他(底層的)block用`#pragma hls_design interface`
- 各block之間使用ac_channel相連接,在top function中使用:
```C
class top {
ac_channel<ac_int<8>> connect0;
fir block0;
fir block1;
public:
top () {}
#pragma hls_design interface top
void CCS_BLOCK(run)(ac_channel<ac_int<8>> &din,
...,
ac_channel<ac_int<8>> &dout) {
block0.run(din, ..., connect0);
block1.run(connect0, ..., dout);
}
}
```
<br/>
<!-- 113.4.6開始 -->
## Lab 2-2: Catapult Edge Detect
- 題目的Github位置:https://github.com/bol-edu/caravel-soc_fpga-lab/tree/main/catapult_hls (與 lab2-1 同一個Github)
- 記錄一下實作的過程:
1. **01_edgedetect**
1. `cd /catapult/catapult-for-soc-course/lab2_edgedetec_fsic/01_edgedetect`
2. `make`
3. `cd bin`
4. `source run.sh`(不知道為什麼直接用`./run.sh`會Permission denied)
5. `cd ../catapult_work`
6. `catapult &`,再按照"Step_by_step_lab2_EdgeDetect.pdf"的 p.34 ~ p.???????????? 的步驟實作
2. **02_edgedetect_fsic**
1. `cd /catapult/catapult-for-soc-course/lab2_edgedetec_fsic/02_edgedetect_fsic/hls_c/inc`
2. `cp ../../../01_edgedetect/hls_c/inc/* .`並修改複製過來的這些檔案
- 過程中得知的重點:
1. From "Step_by_step_lab2_EdgeDetect.pdf"
- "DirectInput" is used for the stable ports avoiding the unnecessary pipeline registers inserted
- data input channel is set as "ccs_in_wait_coupled" avoiding extra FIFO buffer
2. From "EdgeDetect_VerDer.h"
- 若for loop的上限為變數時,可以透過「移除上限的限制式,而`i`使用 bit-accurate 的 data type以增加更多可能的情況,最後再設定break條件」的方式使其可以合成:
```C
for (uint8 i = 0; ; i++) {
...
if (i == upper_bound) {
break;
}
}
```
<br/>
<!-- 113.4.10開始 -->
## Lab 3: Synopsys IC flow
- 記錄一下實作過程中遇到的問題及解法:
1. 在`/lab2_pnr`中遇到error:

:::success
**Solution**:換伺服器(ws44➜ws27)後就沒有error了
:::
2. 在`/lab_pt`中遇到error:

:::success
**Solution**:將`/lab_pt/work/Makefile`中的`/bin/tclsh ./../script/gen_pt_cmd.tcl`換成
```console
tclsh ./../script/gen_pt_cmd.tcl
```
:::
3. 在`/lab_pt`中遇到error:

上網搜尋`primetime Error: Library Compiler executable path is not set. (PT-063)`得知是未設定`SYNOPSYS_LC_ROOT`這個environment variable([參考資料1](https://www.fasteda.cn/post/240.html)、[參考資料2](https://bbs.eetop.cn/thread-906741-1-1.html)、[參考資料3](https://www.eecs.umich.edu/dco/docs/ecad/synopsys.html)、[參考資料4](https://blog.csdn.net/m0_61544122/article/details/129873760)、[參考資料5](https://zhuanlan.zhihu.com/p/401603501))
:::info
💡 在terminal中使用`printenv SYNOPSYS_LC_ROOT`未回傳任何資訊,可知的確未設定`SYNOPSYS_LC_ROOT`
:::
最後在Google搜尋時發現path設定所需指向的資料夾:

並在電機系工作站中透過`ls /usr/cad/synopsys/lc/cur`確認此資料夾存在。
:::success
**Solution**:因此到`.tcshrc`中加入此行:
```console
setenv SYNOPSYS_LC_ROOT /usr/cad/synopsys/lc/cur
```
即可正常執行!
:::
4. 在`/lab4_finishing`中遇到error:

這個error解了超久QAQ。線索來自`/lab4_finishing/scripts/step7_finishing.tcl`的第23行 "Use correct ICV version":

因此我懷疑是因為 IC compiler II (icc2_shell) 與 IC Validator (icv) 的版本不同(icc2_shell不支援icv的版本導致吃不到binary file)所導致的。
先上網搜尋相關指令,最主要參考了[這個網站](https://www.cnblogs.com/ASIC-Horizon/p/17071009.html)得知與 "ICV_HOME_DIR" 、 "ICV_INCLUDES" 和 "PATH" 這些環境變數有關。另外由[ASoC課程教材](https://drive.google.com/drive/folders/1cGNs2LfW5ZdoaEpi_Nh6iANl7V4f6rtv?usp=sharing)中的「Reference > icc2ug.pdf」的第543頁(如下圖,此為透過搜尋「ICV」關鍵字而找到的)可知的確需要搭配正確的version才可正常執行。

因此在`icc2_shell`中使用`report_versions`得知`source /usr/cadtool/user_setup/08-icc2.csh`所對應的icc2_shell版本為2020年,並不支援2022年版的icv(`source /usr/cadtool/user_setup/08-icv.csh`),上述版本的部分也可從[電機系的 CAD Tool List網頁](https://web.ee.nthu.edu.tw/p/405-1175-169285,c4918.php?Lang=zh-tw)得知。
雖然icc2_shell也有2021.06的版本(`source /usr/cadtool/cad/synopsys/CIC/icc2_2021.cshrc`),但仍無法支援2022年版的icv,後來誤打誤撞發現Synopsys的tool會被分在兩大資料夾中:`/usr/cadtool/cad/synopsys`與`/usr/cadtool/user_setup`,感覺後者是為了方便版本控制而新建立的區域。在`/usr/cadtool/cad/synopsys/icvalidator`中有 2021.06 的版本,跟icc2_shell的2021.06的版本是可以互相支援的!但並沒有相關的.csh檔可以方便source,因此我參考前面所述的幾個 .csh / .cshrc 的寫法,以及參考上圖中所介紹需要設定"ICV_HOME_DIR" 和 "path",而寫出了`/home/course/m112501538/ASoC_lab3.csh`,並在`.tcshrc`中source它。
:::success
**Solution**:建立`/home/course/m112501538/ASoC_lab3.csh`檔案,其內容為
```console
setenv ICV_HOME_DIR "/usr/cadtool/cad/synopsys/icvalidator/2021.06"
set path = (/usr/cadtool/cad/synopsys/icvalidator/2021.06/bin/LINUX.64 $path)
```
接著到`.tcshrc`中執行下列3個步驟:
1. 將`source /usr/cadtool/user_setup/08-icc2.csh`改為`source /usr/cadtool/cad/synopsys/CIC/icc2_2021.cshrc`
2. 註解`source /usr/cadtool/user_setup/08-icv.csh`
3. 加入此行:`source /home/course/m112501538/ASoC_lab3.csh`
:::
5. 在`/lab_formal`中遇到error:

:::success
**Solution**:將`/lab_formal/work/Makefile`中的`/bin/tclsh ./../script/gen_formality_cmd.tcl`換成
```console
tclsh ./../script/gen_formality_cmd.tcl
```
:::
6. 在`/lab_formal`中遇到error:

發現是因為在電機系工作站沒辦法用`fm_shell`指令開啟formality:

使用`vim /usr/cadtool/user_setup/08-formality.csh`

得知tool安裝在`/usr/cad/synopsys/formality/`中。
一層層往資料夾內搜尋執行檔所在位置:

因此可使用
```console
/usr/cad/synopsys/formality/2021.06/bin/fm_shell
```
指令來開啟formality軟體:

:::success
**Solution**:將`/lab_formal/work/Makefile`中的`FM_EXEC = fm_shell`換成
```console
FM_EXEC = /usr/cad/synopsys/formality/2021.06/bin/fm_shell
```
即可正常執行!
:::
<br/>
<!-- 113.5.12~開始 -->
## Lab 4: Simulation & Validation of FSIC with FPGA
- 關於「將 lab 1 所更新的內容(/fsic_fpga/rtl/user/user_subsys/axil_slav/rtl/axil_slav.v)更新到[bol-edu/fsic_fpga](https://github.com/bol-edu/fsic_fpga/tree/main)」:十分感謝Michael Kao 所提供的[參考網站](https://gitbook.tw/chapters/github/pull-request)
1. 將 [bol-edu/fsic_fpga](https://github.com/bol-edu/fsic_fpga/tree/main) 這個repository **fork** 到自己Github帳號下
2. 修改fork過來的(自己帳號下的)檔案
3. `git add`、`git commit`、`git push`到自己的帳號下
4. 到 [bol-edu/fsic_fpga](https://github.com/bol-edu/fsic_fpga/tree/main) 新增 Pull request
- 記錄一下實作過程中的發現:
- (/fsic_fpga/vivado/fsic_tb.sv) `fork ... join_none`的用途可參考[這個網站](https://blog.csdn.net/a52228254/article/details/106184602)
- /fsic_fpga/vivado/fsic_tb.sv 中寫到:
```csharp
fork
fw_mb_st_t();
join_none
@(fw_mb_st_event);
fork
fw_mb_wd_t();
join_none
@(fw_mb_wd_event);
```
其中`fw_mb_st_t()`及`fw_mb_wd_t()`這兩個task的定義為:
```csharp
task fw_mb_st_t;
begin
wait(DUT.design_1_i.caravel_0_mprj_o[37] == 1'b0);
$display($time, "=> FW starts MB writing, caravel_0_mprj_o[37] = %0b", DUT.design_1_i.caravel_0_mprj_o[37]);
->> fw_mb_st_event;
end
endtask
task fw_mb_wd_t;
begin
wait(DUT.design_1_i.caravel_0_mprj_o[37] == 1'b1);
$display($time, "=> FW finishs MB writing, caravel_0_mprj_o[37] = %0b", DUT.design_1_i.caravel_0_mprj_o[37]);
->> fw_mb_wd_event;
end
endtask
```
由此可知 /fsic_fpga/testbench/fsic/fsic.c 中的
```csharp
case 5:
reg_mprj_datah = 0x00; //set mprj_io[37] to 1'b0 to indicate FW going to waiting fpga MB test
reg_fsic_aa_mb0 = 0x5a5a5a5a;
reg_fsic_cc = 0x00000004;
reg_mprj_datah = 0x20; //set mprj_io[37] to 1'b0 to indicate FW going to waiting fpga MB test
break;
```
應改為
```csharp
reg_mprj_datah = 0x00; //set mprj_io[37] to 1'b0 to indicate FW going to "write" fpga MB test
reg_mprj_datah = 0x20; //set mprj_io[37] to "1'b1" to indicate FW "has finished writing" fpga MB
```
- (/fsic_fpga/vivado/fsic_tb.sv 與 /fsic_fpga/testbench/fsic/fsic.c)
Mailbox的讀寫分為兩個方向:
- Task SocLocal_MbWrite() 為SoC side寫給FPGA side,流程如下:
1. 先將「PL_AA(16'h2100) offset=0」位址的值寫作1,不確定是不是指要將FPGA side的aa_irq_en開啟的用途
2. SoC side寫值至 mailbox(reg_fsic_aa_mb0),並透過 mprj_io[37] 來告知寫完
3. FPGA side 至 PL_AA_MB(16'h2000)位址接收mailbox傳來的值
4. FPGA side:此時的 aa_mb_irq status(aa_mb_irq值)應為1,可透過read PL_AA(16'h2100) offset=4 來得知
5. FPGA side將「PL_AA(16'h2100) offset=4」位址的值寫入**1**,它就會自動變為**0**(表示將aa_mb_irq值回復成0),非常神奇!
- Task FpgaLocal_MbWrite() 為FPGA side寫給SoC side,流程如下:
1. SoC side將 reg_fsic_aa_irq_en 的值寫為1,並透過 reg_fsic_cc 來告知寫完
2. FPGA side 寫值至 mailbox(PL_AA_MB(16'h2000) offset=0)
3. SoC side 至 reg_fsic_aa_mb0 接收mailbox傳來的值
4. SoC side:此時的 aa_irq status(reg_fsic_aa_irq_sts值)應為1
5. SoC side透過`reg_fsic_aa_irq_sts = 1;`將 reg_fsic_aa_irq_sts 值寫入**1**,它就會自動變為**0**(表示將reg_fsic_aa_irq_sts值回復成0),非常神奇!
- 記錄一下有改到的部分:
- Integrate FIR into FSIC,參考lab1的「記錄一下有改到的部分」:
1. Add FIR-related files from `/lab1-1/lab_1/fsic_fpga/rtl/user/user_subsys/user_prj/user_prj1/rtl` (in [Github of Advanced SoC design course](https://github.com/whywhytellmewhy/Advanced-SoC-design)) into `/ASoC_lab4_FSIC_FPGA/rtl/user/user_subsys/user_prj/user_prj1/rtl`
2. Copy the content from `/lab1-1/lab_1/fsic_fpga/rtl/user/user_subsys/user_prj/user_prj1/rtl/user_prj1.v` to `/ASoC_lab4_FSIC_FPGA/rtl/user/user_subsys/user_prj/user_prj1/rtl/user_prj1.v`
3. Copy the content from `/lab1-1/lab_1/fsic_fpga/rtl/user/user_subsys/user_prj/user_prj1/rtl/rtl.f` to `/ASoC_lab4_FSIC_FPGA/rtl/user/user_subsys/user_prj/user_prj1/rtl/rtl.f`
4. `/lab1-1/lab_1/fsic_fpga/rtl/user/testbench/tc/filelist`
5. Copy the content from `/lab1-1/lab_1/fsic_fpga/rtl/user/testbench/tb_fsic.v` to `/ASoC_lab4_FSIC_FPGA/rtl/user/testbench/tb_fsic.v`
- Integrate FIR into Vivado project 的 source files:
1. Add FIR-related files from `/lab1-1/lab_1/fsic_fpga/rtl/user/user_subsys/user_prj/user_prj1/rtl` into `/ASoC_lab4_FSIC_FPGA/vivado/vvd_srcs/caravel_soc/rtl/user/user_subsys/user_prj/user_prj1/rtl`
2. Copy the content from `/lab1-1/lab_1/fsic_fpga/rtl/user/user_subsys/user_prj/user_prj1/rtl/user_prj1.v` to `/ASoC_lab4_FSIC_FPGA/vivado/vvd_srcs/caravel_soc/rtl/user/user_subsys/user_prj/user_prj1/rtl/user_prj1.v`
3. Copy the content from `/lab1-1/lab_1/fsic_fpga/rtl/user/user_subsys/user_prj/user_prj1/rtl/rtl.f` to `/ASoC_lab4_FSIC_FPGA/vivado/vvd_srcs/caravel_soc/rtl/user/user_subsys/user_prj/user_prj1/rtl/rtl.f`
- Modify userDMA
1. Modify "BUF_LEN" in `/ASoC_lab4_FSIC_FPGA/vivado/vitis_prj/hls_userdma/userdma.h`
2. Comment the lines related to "in_Img_width" in `/ASoC_lab4_FSIC_FPGA/vivado/vitis_prj/hls_userdma/userdma.cpp`
3. Develop a new Vitis project as `/ASoC_lab4_FSIC_FPGA/vivado/vitis_prj/userdma_fir` directory
- Simulation testbench
1. Modify the original `fsic_tb.sv` into `/ASoC_lab4_FSIC_FPGA/vivado/fsic_tb2.sv`
2. Modify `/ASoC_lab4_FSIC_FPGA/vivado/vvd_caravel_fpga_fsic_sim.tcl`
3. After running `./run_vivado_fsic_sim` in `/ASoC_lab4_FSIC_FPGA/vivado`, 可在`/ASoC_lab4_FSIC_FPGA/vivado/vvd_caravel_fpga_sim/vvd_caravel_fpga_sim.sim/sim_1/behav/xsim`資料夾中找到 .vcd 檔,並在`/Advanced_SoC/lab_4/fsic_fpga/vivado`資料夾中找到 "updma_input.log"、"updma_output.log"
- Validation
1. Modify `/ASoC_lab4_FSIC_FPGA/vivado/vvd_caravel_fpga_fsic.tcl`
2. After running `./run_vivado_fsic` in `/ASoC_lab4_FSIC_FPGA/vivado`, open the vivado project located in `/ASoC_lab4_FSIC_FPGA/vivado/vvd_caravel_fpga`, then add our userDMA IP into block design, and 用[這個討論區](https://github.com/bol-edu/HLS-SOC-Discussions/discussions/221)所述的方式接線:「兩條instream跟outstream需要自己手動接到userdmaso跟userdmasir」
3. 將產生的.bit及.hwh檔放置於`/ASoC_lab4_FSIC_FPGA/vivado/jupyter_notebook_fir`資料夾
4. 上傳相關檔案至 onlineFPGA,如[Github協作repository](https://github.com/ZheChen-Bill/ASoC_lab4_FSIC_FPGA/tree/main/vivado/jupyter_notebook_result)中的README.md的敘述
5. 將 onlineFPGA 執行完畢的檔案下載下來並放置於`/ASoC_lab4_FSIC_FPGA/vivado/jupyter_notebook_result`資料夾中
- 過程中遇到的兩大difficulties:
- 在 **run simulation** 時,明明有將 "BUF_LEN" 改為64,並重新開一個Vitis project,再輸出IP,還是會產生 deadlock,從 2024.5.17~ 一直到 2024.5.18~ 才解決。最後是在詢問學弟後得知應該只要改 "BUF_LEN" 的值再輸出project應該就可以,於是我們將其他拿來debug用的code改回原樣,突然就可以了,也不知道到底背後的原因出在哪裡
- 在 **run onlineFPGA** 時,在read SoC內部的state(例如 read SOC_CC 位址的值)時,會讓整個板子壞掉,state變成 "unknown",然後就不能用了。這次debug過程從 2024.5.18~ 大約4:00 a.m.開始,弄壞了好幾塊板子後,已無板子可用,因此必須等到5點~6點的系統重置後才有板子可用。隔天(2024.5.19)下午也弄壞幾塊板子後,終於發現是在configure LA_DMA 或 userDMA 的那段 code 會使「read SoC 內部的state」時板子會壞掉(不知道「write SoC 內部的state」會不會也是不能成功,但因為read不出來,因此無法得知write是否成功),但仍可成功「read LA_DMA/userDMA 內部的state」。因此我們決定「先configure SoC內部的訊號,再configure userDMA的訊號,並且將 LA_DMA 的功能關閉」,最後終於成功了!>w<
<br/>
<!-- 113.6.11開始 -->
## Final project: Optical Flow
- Final project的部分有另外開了一個共用的 [Github repository](https://github.com/whywhytellmewhy/ASoC-Final_project-optical_flow)
- 關於 Catapult HLS 的實作部分:
1. 前面的function過程中有遇到超多issue導致HLS的模擬結果與algorithm的結果不同,但當時只記錄在Github的commit中,沒有註記在這裡
2. 在實作`OpticalFlow_flow_calc.h`後,發現testbench的結果除了在邊界處會與algorithm差很多外,在內部也幾乎都error超過1。
**<Debug過程>**
1. 從testbench所print在螢幕上的資訊選定一個pixel (x, y)=(451,62)來觀察
2. 在`OpticalFlow_flow_calc.h` (HLS) 中加入debug用的程式碼:

3. 在`OpticalFlow_Algorithm.h` (algorithm C) 中加入debug用的程式碼:

4. 觀察print在螢幕上的結果可發現其實input值都沒有差很多,但output值光是denominator就差10倍:

5. 想到可能是精細度不夠,在`OpticalFlow_outer_product.h`中:

是兩個`pixel_t` type相乘(`gradient_t` type的component為`pixel_t` type),得到`outer_pixel_t` type(`outer_t` type的component為`outer_pixel_t` type)。
但在`OpticalFlow_defs.h`中發現整數部分的確有擴充為 13\*2+1=27 bits,但小數部分卻只剩下 5 bits:

這個quantization error導致後續計算上差異非常大(將前面的值計算出來,即可發現兩者差異的確很大)
**<解法>**
將
```csharp
const int OUTER_PIXEL_T_BIT_WIDTH = 32;
```
改為
```csharp
const int OUTER_PIXEL_T_BIT_WIDTH = 64;
```
print在螢幕上的結果:

計算後可發現變得很接近了!<br/><br/>
**<仍有issue>**
雖然前面的那個pixel已經解決,但執行testbench後發現仍有許多pixel的error還是很大,例如 (x, y)=(362,399):

計算上圖結果發現HLS的unput算出來應該要大約是 $143.485*307.77-189.532*189.532=8237.999426$,也很接近,但卻輸出46.8251189...,看起來是因為overflow的關係,也就是bit數不夠。<br/><br/>
**<解法>**
在`OpticalFlow_flow_calc.h` 中的`denominator_value`原本是pixel_t type,但透過其運算`denominator_value = tensor_value.val[0]*tensor_value.val[1] - tensor_value.val[3]*tensor_value.val[3];`得知它在worst case應該要有 $27*2+1=55$ bits的整數部分,但pixel_t type的整數部分卻只有13 bits,難怪會overflow(8237.99426的整數部分至少需15 bits才不會overflow),因此將`denominator_value`改為`vel_pixel_t` type:

同一個pixel的模擬結果就正確了許多:

另外,也因為`total_output_value`是尚未除過 denominator 的值,因此應也要用64 bits才可避免overflow,因此將`OpticalFlow_defs.h`中的
```csharp
const int VEL_PIXEL_T_BIT_WIDTH = 32;
const int VEL_PIXEL_T_INTEGER_PART = 13;
```
改為
```csharp
const int VEL_PIXEL_T_BIT_WIDTH = 64;
const int VEL_PIXEL_T_INTEGER_PART = 56;
```
即可解決此pixel的問題!<br/><br/>
**<仍有issue>**
雖然前面的那些pixel已經解決,但執行testbench後發現仍有許多pixel出現inf的結果,例如 (x, y)=(317,189):

表示分母為0,可能是因為小數位數不夠,導致無法記錄下很小的值:

由此圖可發現這次的情況是當數值都很小時,可能會因為小數位數不足而使誤差大。<br/><br/>
**<解法>**
將`OpticalFlow_defs.h`中的
```csharp
const int VEL_PIXEL_T_INTEGER_PART = 56;
```
改為
```csharp
const int VEL_PIXEL_T_INTEGER_PART = 32;
```
使整數位數減少(應該不會那麼常出現worst case),小數位數可因此allocate多一些

即可解決此pixel的問題!<br/><br/>
**<仍有issue>**
雖然前面的那些pixel已經解決,但執行testbench後發現仍有許多pixel出現inf或error大於1的結果,例如 (x, y)=(785,287):

看起來是小數位數依然不夠,需要再給更多位。但有些pixel的值很大(可能上萬),有些又很小。對於很大的值,其實小數點後的部分影響不大;對於很小的值,整數部分又皆為0,不需花32 bits來記錄,因此目前prefer的解法為將有值的部分 "**adaptive shift**" 到 32 bit,並記錄下shift的量,即可同時兼顧太大及太小的數據。(軟體的部分不會有這個問題,即使是 e-10 的數量級也依然能算出結果。)<br/><br/>
**<解法>**
如Github中的「`update with 'shift' feature in OpticalFlow_flow_calc.h`」這次commit的更新內容。增加shift的功能後(過程中也遇到type無法成功轉換的問題,最後是先將ac_fixed透過`.to_int()`的method轉換成32-bit的整數,再用整數乘法,結果存至64-bit的整數type輸出,才不出現compile error)即可使很小的小數也能計算出正確結果,且由於分母和分子皆同時乘上 $2^N$(其中$N$表示shift的次數),因此相除後的結果即為最終結果,不需再shift。
<br/><br/>
**<仍有issue>**
雖然前面的那些pixel已經解決,但執行testbench後發現仍有許多error大於1的結果,例如 (x, y)=(354,277):

看起來是當tensor_value更小的時候仍會有error。<br/><br/>
**<解法>**
1. 因為改變各種type的bit數都影響不大,只有當`PIXEL_T_INTEGER_PART`從13變小時,才會變好,但也無法到非常接近,因此只好將 algorithm 的各function及HLS的function output皆print出來比對看看,結果發現HLS的Ix應該要是00000...000卻變成11111...111(input frame在此pixel附近連續5個I值為255, 255, 255, 255, 255),導致Ix轉成decimal後的值不為0,尤其在值很小的時候error比例更大:

2. 在看[Catapult HLS的bluebook](https://cse.usf.edu/~haozheng/teach/cda4253/doc/hls/hls_bluebook_uv.pdf)時,發現有`AC_RND`這個選項:

因此試著將
```csharp
typedef ac_fixed<PIXEL_T_BIT_WIDTH,PIXEL_T_INTEGER_PART, true, AC_TRN, AC_WRAP> pixel_t;
```
改為
```csharp
typedef ac_fixed<PIXEL_T_BIT_WIDTH,PIXEL_T_INTEGER_PART, true, AC_RND, AC_WRAP> pixel_t;
```
可以變精準很多,Ix也變為00000...000:


若將其他的type也使用`AC_RND`則可以變更準:


3. 到目前的版本放在Github的「debug with input of very very small differences, using AC_RND to replace AC_TRN」這個commit中<br/><br/>
**<仍有issue>**
雖然前面的那些pixel已經解決,但執行testbench後發現仍有許多error大於1的結果,例如 (x, y)=(358,250)和(586,150):


由圖中「Algorithm_denominator_value」這行可發現這些都是出現在值更小時(可能到 e-20 的等級甚至更小)<br/><br/>
**<解法>**
將shift的功能改成在超小值的源頭,這樣一來shift之後可以留下更小的bit(目前是將shift功能放在`OpticalFlow_flow_calc.h`中,但此時已經沒有更小的bit(更LSB)的資訊了)。
首先觀察上圖發現源頭在「Algorithm_tensor/HLS_tensor」處,因此決定將shift功能改到「`OpticalFlow_tensor_weight_x.h`」中,有底下兩種實作方法:
1. 此版本為Github的「failed version: shift and slice first, then do filtering」這個commit。由於此function的output設定為32 bits,故先將要相乘的兩個值(input以及filter coefficient)皆只留下16 bits,如此一來相乘後就會是32 bits了,因此先將小數值向左shift,並且切(slice)出MSB的16 bits,即可。此方式的好處為只需要16-bit乘16-bit的乘法器即可。但寫完後模擬發現效果沒有很佳(也可能其實很佳,只是因為取的pixel剛好是(Ix,Iy,It)=(0,0,0)的outlier,導致看起來結果差很多)。
2. 此版本為Github的「complete moving 'shift' feature from OpticalFlow_flow_calc.h to OpticalFlow_tensor_weight_x.h」這個commit。做法是先將精準的乘法算出並暫存至 64+32 bits 的register中,再將MSB的32 bits取出並輸出即可。此方法成功再進一步優化 (x, y)=(354,277) 的精準度:


<br/><br/>
**<仍有issue>**
雖然前面的那些pixel已經解決,但執行testbench後發現仍有許多error大於1的結果,大部分的denominator都很小(可能到 e-20 的等級甚至更小),例如 (x, y)=(371,147):
<br/><br/>
**<解法>**
由上圖可發現其實這個pixel的(Ix,Iy,It)=(0,0,0),因此算出來的那些很小的數值應該只是quantization error,實際上應趨近0,只要值稍微差一點點,除起來就會有巨大的差異!因此我們應該要在計算LK方程式之前,先判斷此pixel是否為(Ix,Iy,It)=(0,0,0),若是,則應該直接輸出「u=0, v=0」即可。目前尚未實作此功能。<br/><br/>
3. 在Catapult tool中FIFO數目最高限制是128個,因此無法使用原本的方式計算Ix、Iy、It,因為這樣一來會需要將Ix及It透過2個row數目的FIFO存起來,太多了。我們將其改成類似lab2的作法,如下圖為討論後的運算流程:

因此有重新修改各function之間的interface,並有使用 (x, y)=(354,277) 來確認結果與修改之前(透過`source run.sh > simˋulation_ver1--no_store_pixel_data.log`指令將print在螢幕上的內容存到檔案中)相同。修改後的版本為Github的「rearrange the order of functions: first compute Iy, then compute Ix & It」這個commit。
4. 在push到GitHub時不知道是不是因為ws44負載過重,導致無法上傳:

上網搜尋error後,經過 [參考資料1](https://stackoverflow.com/questions/77816301/git-error-rpc-failed-http-400-curl-22-the-requested-url-returned-error-400)、[參考資料2](https://www.cnblogs.com/yourstars/p/15533706.html),使用了參考資料2中的方法2,將buffer提升為1GB(5242880000÷5=1048576000)即可解決:在 "/ASoC-Final_project-optical_flow/.git/config" 中加入此行:
```console
[http]
postBuffer = 1048576000
```
- 關於 FSIC-FPGA 的實作部分(類似lab 4的流程),記錄一下有改到的部分:
- Integrate OpticalFlow into Vivado project 的 source files
1. Add OpticalFlow-related files (`spram.v`、`concat_rtl.v`) from `/ASoC-Final_project-optical_flow/rtl/user/user_subsys/user_prj/user_prj2/rtl` into `/ASoC-Final_project-optical_flow/vivado/vvd_srcs/caravel_soc/rtl/user/user_subsys/user_prj/user_prj2/rtl`
2. Copy the content from `/ASoC-Final_project-optical_flow/rtl/user/user_subsys/user_prj/user_prj2/rtl/user_prj2.v` to `/ASoC-Final_project-optical_flow/vivado/vvd_srcs/caravel_soc/rtl/user/user_subsys/user_prj/user_prj2/rtl/user_prj2.v`
3. Copy the content from `/ASoC-Final_project-optical_flow/rtl/user/user_subsys/user_prj/user_prj2/rtl/rtl.f` to `/ASoC-Final_project-optical_flow/vivado/vvd_srcs/caravel_soc/rtl/user/user_subsys/user_prj/user_prj2/rtl/rtl.f`
- Modify userDMA
1. Modify "BUF_LEN" in `/ASoC-Final_project-optical_flow/vivado/vitis_prj/hls_userdma/userdma.h`
2. Modify some lines (denoted as "--> uncomment in final froject" and "modified in final project") in `/ASoC-Final_project-optical_flow/vivado/vitis_prj/hls_userdma/userdma.cpp`
3. Develop a new Vitis project as `/ASoC-Final_project-optical_flow/vivado/vitis_prj/userdma_opticalFlow` directory<br/><br/>
:::info
💡 到目前為止對應到 GitHub中的「`[double update][About FSIC-FPGA] copy OpticalFlow-related project into Vivado project; modify userDMA`」這次commit的版本。
:::
- Simulation testbench
1. Copy the content from `/ASoC-Final_project-optical_flow/rtl/user/testbench/tc/pattern` to `/ASoC-Final_project-optical_flow/vivado/test_pattern`
2. Modify `fsic_tb.sv`
3. Modify `/ASoC-Final_project-optical_flow/vivado/vvd_caravel_fpga_fsic_sim.tcl`
4. After running `./run_vivado_fsic_sim` in `/ASoC-Final_project-optical_flow/vivado`, 可在`/ASoC-Final_project-optical_flow/vivado`資料夾中找到 "updma_input.log"、"updma_output.log"、"updma_output_gold.log"。另外,若沒有註解掉這幾行:

則可在`/ASoC-Final_project-optical_flow/vivado/vvd_caravel_fpga_sim/vvd_caravel_fpga_sim.sim/sim_1/behav/xsim`資料夾中找到 .vcd 檔。
- Validation
1. Modify `/ASoC-Final_project-optical_flow/vivado/vvd_caravel_fpga_fsic.tcl`
2. Modify `/ASoC-Final_project-optical_flow/vivado/jupyter_notebook/caravel_fpga_fsic.ipynb`
3. 剩下的部分如上方 [Lab 4](https://hackmd.io/@whywhytellmewhy/r15D2Ao56#Lab-4-Simulation-amp-Validation-of-FSIC-with-FPGA) 中的做法
### How to run HLS simulation
```console
cd optical_flow_catapult
make
cd bin
source run.sh
```
### How to run simulation about RTL integrated into FSIC
```console
cd rtl/user/testbench/tc
make all
```
### How to run FSIC-FPGA simulation
```console
cd vivado
./run_vivado_fsic_sim
```
### How to run FSIC-FPGA validation
```console
cd vivado
./run_vivado_fsic
```
<br/>
<!-- 113.6.22~開始 -->
## Optional lab 1: Design for Test
- 從「design_for_test_tutorial.pdf」得知:
1. DFT deployment generally follows or in parallel with the synthesis flow,但在這個lab中 DFT will be inserted in the flow after synthesis.
2. 先做synthesis才會有gate-level netlist,接著才能做ATPG。可看PDF中的第14頁的流程圖(Figure 2.1)。
-
<br/>
<!-- 113.6.29~113.6.30開始 -->
## 附註:實用的 git 指令
- ([參考資料](https://june.monster/git-github-checkout-reset-revert/)) **回復到舊的commit**,但不會刪掉任何的commit,而是新建立一個新commit,內容還原到舊commit時:
```console
# 把目前所在的 branch 裡最新的 commit 給逆向操作一遍,做完後會發現多一個 commit,裡面內容是復原最新 commit 的改動
git revert HEAD
# 新增一個 commit,內容是反向去復原 6be9cb5 做的改動
git revert 6be9cb5
```
:::warning
:warning: 特別注意:
1. revert 後會直接replace新commit的所有改動,**並非 merge**。也就是說,會完全回到當時的repository狀態,即使後來有新增檔案,也會被刪除
2. 若`revert 6be9cb5`,則會將`6be9cb5`所做的改動還原,也就是回到`6be9cb5`這個commit的「**前一個**」commit時的檔案
:::
<br/>
## Reference
1. [如何取得Github的PAT(personal access token)](https://hackmd.io/@cIKaSz9PQoq3bVHvsCI30Q/rkq1vXIgK)
2. [使用Https方式存取Github時不需每次都輸入帳號密碼的設定方式](https://blog.51cto.com/u_15302822/5687803):`git config --global credential.helper store`(也可不加`--global`,如此一來就只設定當下所在的repository)
3. [關於Github的fork以及其他Git的知識](https://gitbook.tw/chapters/github/pull-request)
4. [To show an image with given size in HackMD.io](https://www.facebook.com/hackmdio/photos/now-you-can-show-the-image-with-given-size/1098614316862443/)
5. [如何修改git的最新一次的commit message](https://gitbook.tw/chapters/using-git/amend-commit1):`git commit --amend -m "<新訊息>"`
6.