# 軟硬體協同設計報告
# HW1 Vivado usage (4-bit full adder )
學生: 陳奕霖 M1125143 | 指導老師:林宏益教授
>[color=#6038af]實驗目的:
在VScode使用verilog撰寫一個4-bits全加器,並輸出v檔在Vivado模擬schematic和在gtkwave模擬波形圖。
>[color=#6038af]實驗原理:
>全加法器: 將被加數、加數與前一個低位元相加
>
>四位元加法器最右不會有溢位因此只需要使用半加法器
>
>
>
>
>[color=#6038af]實驗材料: PC,VScode,Vivado,gtkwave
---
>[color=#6038af]實驗步驟:首先在 VScode上撰寫 4-bit adder verilog
```verilog=
// 1位元加法器模組
module add1 (
a, // 被加數
b, // 加數
cin, // 進位輸入
cout, // 進位輸出
sum // 總和
);
input a, b, cin;
output cout, sum;
assign {cout, sum} = a + b + cin;
endmodule
// 4位元加法器模組
module add4 (
a, // 被加數
b, // 加數
cin, // 進位輸入
cout, // 進位輸出
sum
);
input [3:0] a, b;
input cin;
output cout;
output [3:0] sum;
wire c0, c1, c2; // 中間進位信號
// 實例化4個1位元加法器
add1 add1_0 (.a(a[0]), .b(b[0]), .cin(cin), .cout(c0), .sum(sum[0]));
add1 add1_1 (.a(a[1]), .b(b[1]), .cin(c0), .cout(c1), .sum(sum[1]));
add1 add1_2 (.a(a[2]), .b(b[2]), .cin(c1), .cout(c2), .sum(sum[2]));
add1 add1_3 (.a(a[3]), .b(b[3]), .cin(c2), .cout(cout), .sum(sum[3]));
endmodule
```
>[color=#6038af]依自己測試需求撰寫testbench測試,接著用makefile合出 .vcp檔模擬波形
>
>[color=#6038af]在gtkwave中模擬波形
>
>[color=#6038af]最後把檔案add進Vivado跑Schematic,以下為Schematic圖

---
>[color=#6038af]實驗討論:
>這次遇到了很奇怪的麻煩,當我加入test.v檔後不知為何會一直同步跑到simulation source底下,導致我加入test_tb跑behavior simulation時波形怪怪的,在想是不是include module導致,所以我只好使用gtkwave來跑波形圖。
>[color=#6038af]實驗心得:
做了這份作業後我學到了很多我原本不知道的東西,例如`include與Topmodule的觀念,testbench的撰寫。完整操作過一遍也加深了對操作流程的印象,但完成後也使我心裡有點恐懼,因為要能對此瞭若指掌還得經過一次次的失敗和嘗試才能出師,不過我相信日後積累的失敗必定能使我有顯著的成長。
參考資料:
https://www.youtube.com/watch?v=kyFW1UuknRE&t=345s&ab_channel=.DeltaMOOCx
https://www.youtube.com/watch?v=f-MyEpbChGw&ab_channel=%E5%90%B3%E9%A0%86%E5%BE%B7
https://www.youtube.com/watch?v=r-XmmhPIR14&list=PLI6pJZaOCtF1-GOBBFwGtAYclboJfTFws&index=23&ab_channel=.DeltaMOOCx
# HW2 BCD to Decimal Decode
>[color=#6038af]實驗目的:
編寫BCD解碼器透過testbench驗證正確性,並在Vivado模擬schematic觀察與RTL差別與分析功率及面積報告
>
>[color=#6038af]實驗材料: PC,VScode,Vivado,gtkwave
---
>[color=#6038af]實驗步驟:首先先編寫BCD解碼器,加入Preset與Reset按鈕
## 1.RTL
```verilog=
module BCD2DD(
bcd,
dec,
Reset_n,
Preset
);
input [3:0] bcd;
input Reset_n,Preset;
output [9:0] dec;
reg [9:0] dec;
always @(bcd or Reset_n or Preset)
begin
if(Preset == 1)
begin
dec = 10'b0000001111;
end
else if(Reset_n == 0 )
case (bcd)
4'bxxxx : dec = 10'b0000000000;
endcase
else
case (bcd)
4'b0000 : dec = 10'b1111111110;
4'b0001 : dec = 10'b1111111101;
4'b0010 : dec = 10'b1111111011;
4'b0011 : dec = 10'b1111110111;
4'b0100 : dec = 10'b1111101111;
4'b0101 : dec = 10'b1111011111;
4'b0110 : dec = 10'b1110111111;
4'b0111 : dec = 10'b1101111111;
4'b1000 : dec = 10'b1011111111;
4'b1001 : dec = 10'b0111111111;
4'b1010 : dec = 10'b1111111111;
4'b1011 : dec = 10'b1111111111;
4'b1100 : dec = 10'b1111111111;
4'b1101 : dec = 10'b1111111111;
4'b1110 : dec = 10'b1111111111;
4'b1111 : dec = 10'b1111111111;
endcase
end
endmodule
```
## 2.TestBench
````verilog=
module BCD2DD_tb;
reg [3:0] bcd;
wire [9:0] dec;
reg Reset_n, Preset;
integer i;
BCD2DD uut (
.bcd(bcd),
.dec(dec),
.Reset_n(Reset_n),
.Preset(Preset)
);
initial
begin
Reset_n = 1;
#50;
Preset = 0;
$dumpfile("BCD2DD.vcd");
$dumpvars(0,BCD2DD_tb);
$monitor ("Reset_n = %b Preset = %b bcd = %b dec = %b", Reset_n , Preset , bcd , dec);
for( i=0 ; i<16 ; i=i+1 )
begin
bcd = i;
#50;
end
Reset_n = 0;
bcd = 4'bxxx;
#50;
Preset = 1;
#50;
end
endmodule
````
<br/>
## 3.TestBench結果

## 4. 模擬波形

* 當reset_n=0時,輸出歸0
* 當preset=1時,輸出10'b0000001111
## 5.功率分析

>[color=#6038af] 從這次的功率分析看到 I/O、Logic、Signals占比分別是91% : 5% : 4%,I/O占了絕大功耗,推測可能跟輸出有10bit有關。
## 6.面積報告

>[color=#6038af]面積占用比很低,推測使用到此FPGA的logic很少。
## 7.Schematic

>[color=#6038af]Schematic相較上一個實驗些許複雜,多了許多電子元件需要一一去理解其功能,需花費時間理解,依我目前功力不能確定實質是否正確,但這是我未來應該努力去開發學習的地方。
---
>[color=#6038af]實驗心得:
這次實驗在verilog語法上使用到if else的應用,testbench放入if else對在編寫testbench時增加了編寫效率,日後會大量使用,另外也嘗試使用更簡短的方式編寫但還是有出錯的地方未找到,關於分析的部分要多多累積經驗才能分析出有用的結論,這是現在我還未能掌握到的很重要的一環。
## FPGA燒錄
### Preset = 1

### Reset = 0

### 影片連結
https://youtube.com/shorts/CM5NgQ9XwXU?feature=share
# HW3 & 4 Decimal to 7-Seg Display Lab
>[color=#6038af]實驗目的 :
>編寫七段顯示器RTL並驗證正確性,並在Vivado合成schematic,觀察與RTL差異與分析功率
>[color=#6038af]實驗材料: PC,VScode,Vivado,工作站
---
## 實驗原理

**共陽極的接法**: 低電位發光,高電位熄滅,共陽極接法的LED,是將多個直接點亮接法的LED的陽極接再一起,共陽極接法的點亮方式和直接點亮接法原理相同,只要在LED的雙端接上正確的電壓就可點亮

## RTL
```verilog=
module seg(
in,
seg,
Reset
);
input [3:0] in;
input Reset;
output [7:0] seg;
reg [7:0] seg;
always @(in or Reset)
begin
if(Reset == 0)
begin
seg = 8'b1001_0001;
end
else
case (in)
4'b0000 : seg = 8'b0000_0011;
4'b0001 : seg = 8'b1001_1111;
4'b0010 : seg = 8'b0010_0101;
4'b0011 : seg = 8'b0000_1101;
4'b0100 : seg = 8'b1001_1001;
4'b0101 : seg = 8'b0100_1001;
4'b0110 : seg = 8'b0100_0001;
4'b0111 : seg = 8'b0100_0001;
4'b1000 : seg = 8'b0001_1111;
4'b1001 : seg = 8'b0000_0001;
4'b1010 : seg = 8'b0000_1001;
4'b1011 : seg = 8'b0001_0001;
4'b1100 : seg = 8'b1100_0001;
4'b1101 : seg = 8'b1000_0101;
4'b1110 : seg = 8'b0110_0001;
4'b1111 : seg = 8'b0111_0001;
endcase
end
endmodule
```
## TestBench
```verilog=
module t_seg;
reg [3:0] in;
wire [7:0] seg;
reg Reset;
integer i;
seg instantiate (
.in(in),
.seg(seg),
.Reset(Reset)
);
initial begin
Reset = 1;
$dumpfile("seg.vcd");
$dumpvars(0,t_seg);
$monitor ("Reset = %b in = %b seg = %b", Reset , in , seg);
for( i=0 ; i<16 ; i=i+1 )
begin
in = i;
#50;
end
#50;
Reset = 0;
#50;
end
endmodule
```
## TestBench結果

## 模擬波形

## 工作站波行模擬


<br/>
## 功率分析

## 面積使用率

## Schematic

## 實驗心得
>[color=#6038af] 這次的實驗思路與上次作業BCD解碼器相似,因此使用switch case完成,也把Power和上次實驗做了比較,發現Power用量較低,可能跟這次沒有Preset開關有關,LUT相比之下也因此少了3個。
>工作站VCS和Verdi的初步使用沒有一開始想像的那麼複雜,另外比較要注意的是工作站波形模擬尚未找到好的顯示方式。
## FPGA燒錄
### Reset = H

### 0000 = 0

### 0001 = 1

### 0010 = 2

### 0011 = 3

### 1111 = F

# HW5 Improve code coverage of your Design
>[color=#6038af]實驗目的 :
提升 (1) Line (2) FSM (3) Condition (4) Branch 的coverage覆蓋率
>[color=#6038af]實驗需求: 工作站
---
## 實驗原理
行覆蓋率(Line Coverage):評估程式中每一行是否已經被testbench執行過。
條件覆蓋率(Condition Coverage):用來確保每個條件語句(如if語句)的所有可能結果都被測試過。
有限狀態機覆蓋率(Finite State Machine Coverage):確保有限狀態機的所有可能狀態和狀態轉換都被測試過。
分支覆蓋率(Branch Coverage):用來確保每個程式碼分支(如if/else語句)和邏輯分支都被測試過。
實驗: 試著一一提升覆蓋率
## 初始覆蓋率

---
## Line coverage

根據紅框這行default沒有被執行到,因此我將他暫時移除,移除後可以發現Line coverage因此提升到100%

## Branch coverage
根據系統紅框提示,這行條件敘述應該有沒有執行到的地方。我將?:條件敘述改為 if else實驗,Branch coverage稍微提升



## FSM coverage
### Test 1
增加一個狀態 S2 (2'd3) 補齊2bit的4種狀態(00,01,10,11),但是FSM只提升到了83.3%。依然發現一樣的問題,S0沒有轉換到IDLE,所以轉為修改Test_bench。

### Test 2

根據波形圖(200ns、400ns)可以發現S0在過程中並沒有觸發到inp1 =0 到IDLE狀態。
修改Testbench,原本延遲為100ns,把延遲時間縮小到可以成功觸發S0 -> IDLE。根據clk正緣觸發週期,inp1=0延續時間必須大於5ns

結果:經過Testbench 延遲時間修正到>5ns,<15ns(下一次的正緣觸發之前) 可以讓S0成功轉換到IDLE進而將FSM Coverage提升到100%

## 實驗心得
提升Coverage的覆蓋率得對自己正在執行的程式聊若指掌,不然得付出大量的時間,程式所有的細節都會影響的機會,這次的作業FSM覆蓋率的部分經過非常多次的嘗試修改,最後確認是S0少跑一個狀態導致。
# HW6 7-Seg Display Controlled by UART
>[color=#6038af]實驗目的 :
>編寫RTL程式燒錄到FPGA面版,使用UART接收PC端TX訊號並將收到的訊號顯示在七段顯示器
>[color=#6038af]實驗材料: PC,Vivado,工作站
## UART簡介
:::info
UART發送端與接收端並不是由共同的時鐘信號來持續對齊,而是透過事先決定好頻率與開始、停止信號來判斷何時讀取資料。

封包由一個Start bit + 8Bits data + 1Stop bit(奇偶較驗位),共10bits組成。

開始位元為高電位轉為第一個的低電位,接收完個8bits完至奇偶較驗位(高電位)
:::
## 實作影片紀錄
:::info
https://youtu.be/Dy2nt7xT2bo
:::
## RTL
### UART架構(rx)

#### Top module
````VERILOG=
`timescale 1ns / 1ps
module rx_top(
input clk,
input rst,
input rx_pin_in,
output [7:0] seg7
);
wire [7:0] rx_data;
wire rx_band_sig;
wire clk_bps;
rx_band_gen rx_band_gen(
.clk( clk ),
.rst( rst ),
.band_sig( rx_band_sig ),
.clk_bps( clk_bps )
);
H2L_detect rx_in_detect(
.clk( clk ),
.rst( rst ),
.pin_in( rx_pin_in ),
.sig_H2L( rx_pin_H2L )
);
rx_ctl rx_ctl(
.clk( clk ),
.rst( rst ),
.rx_pin_in( rx_pin_in ),
.rx_band_sig( rx_band_sig ),
.rx_clk_bps( clk_bps ),
.rx_data( rx_data ),
.rx_done_sig( rx_done_sig )
);
ASCII27 ASCII27(
.rst( rx_done_sig ),
.ascii( rx_data ), //rx_data訊號->ASCII
.seg7(seg7)
);
endmodule
````
#### (H2L_detect):偵測start訊號
````VERILOG=
`timescale 1ns / 1ps
module H2L_detect(
input clk,
input rst,
input pin_in,
output sig_H2L
);
reg pin_pre;
assign sig_H2L = !pin_in & pin_pre;
always @( posedge clk or posedge rst )
if( rst )
pin_pre <= 1'b0;
else
pin_pre <= pin_in;
endmodule
````
#### rx_ctl 狀態機出發接收動作
````VERILOG=
`timescale 1ns / 1ps
module rx_ctl(
input clk,
input rst,
input rx_pin_in,
input rx_pin_H2L,
output reg rx_band_sig,
input rx_clk_bps,
output reg[7:0] rx_data,
output reg rx_done_sig
) ;
localparam [3:0] IDLE = 4'd0, BEGIN = 4'd1, DATA0 = 4'd2,
DATA1 = 4'd3, DATA2 = 4'd4, DATA3 = 4'd5,
DATA4 = 4'd6, DATA5 = 4'd7, DATA6 = 4'd8,
DATA7 = 4'd9, END = 4'd10 , BFREE = 4'd11;
//選擇使用4位元表示狀態是為了確保有足夠的位元數來表示所有可能的狀態(獨一無二定義數)
reg [3:0] pos;
always@( posedge clk or posedge rst )
if( rst )
begin
rx_band_sig <= 1'b0;
rx_data <= 8'd0;
pos <= IDLE;
rx_done_sig <= 1'b0;
end
else
case( pos )
IDLE:
if( rx_pin_H2L)
begin
rx_band_sig <= 1'b1;
pos <= pos + 1'b1;
rx_data <= 8'd0;
end
if( rx_clk_bps)
begin
if( rx_pin_in == 1'b0 )
begin
pos <= pos + 1'b1;
end
else
begin
rx_band_sig <= 1'b0;
pos <= IDLE;
end
end
DATA0,DATA1,DATA2,DATA3,DATA4,DATA5,DATA6,DATA7 //接續儲存
if( rx_clk_bps)
begin
rx_data[ pos - DATA0 ] <= rx_pin_in;
pos <= pos + 1'b1;
end
END:
if( rx_clk_bps)
begin
rx_done_sig <= 1'b1;
pos <= pos + 1'b1;
rx_band_sig <= 1'b0;
end
BFREE:
begin
rx_done_sig <= 1'b0;
pos <= IDLE;
end
endcase
endmodule
````
#### rx_band_gen 產生9600bps 接收資料
````VERILOG=
`timescale 1ns / 1ps
module rx_band_gen(
input clk,
input rst,
input band_sig,
output reg clk_bps
);
parameter SYS_RATE = 125000000;
parameter BAND_RATE = 9600;
parameter CNT_BAND = SYS_RATE / BAND_RATE;
parameter HALF_CNT_BAND = CNT_BAND / 2;
reg [13:0] cnt_bps;
always @( posedge clk or posedge rst )
if( rst )
begin
cnt_bps <= HALF_CNT_BAND;
clk_bps <= 1'b0;
end
else if( !band_sig )
begin
cnt_bps <= HALF_CNT_BAND;
clk_bps <= 1'b0;
end
else if( cnt_bps == CNT_BAND )
begin
cnt_bps <= 14'd0;
clk_bps <= 1'b1;
end
else
begin
cnt_bps <= cnt_bps + 1'b1;
clk_bps <= 1'b0;
end
endmodule
````
#### ASCII27
````VERILOG=
module ASCII27 (
rst,
Ascii,
seg7
);
input rst;
input [7:0] Ascii;
reg [7:0] seg7;
output [7:0] seg7_out;
always@( posedge rst )
begin
case (Ascii) //Spyglass requires nonblocking
8'b0011_0000 : seg7 <=8'b0000_0011;
8'b0011_0001 : seg7 <=8'b1001_1111;
8'b0011_0010 : seg7 <=8'b0010_0101;
8'b0011_0011 : seg7 <=8'b0000_1101;
8'b0011_0100 : seg7 <=8'b1001_1001;
8'b0011_0101 : seg7 <=8'b0100_1001;
8'b0011_0110 : seg7 <=8'b0100_0001;
8'b0011_0111 : seg7 <=8'b0001_1111;
8'b0011_1000 : seg7 <=8'b0000_0001;
8'b0011_1001 : seg7 <=8'b0000_1001;
8'b0100_0001 : seg7 <=8'b0001_0001;
8'b0100_0010 : seg7 <=8'b1100_0001;
8'b0100_0011 : seg7 <=8'b1110_0101;
8'b0100_0100 : seg7 <=8'b1000_0101;
8'b0100_0101 : seg7 <=8'b0110_0001;
8'b0100_0110 : seg7 <=8'b0111_0001;
default : seg7 <=8'b0110_0001;
endcase
assign seg7_out=seg7;
end
endmodule
````
## TestBench
````verilog=
module rx_tb();
reg clk;
reg rst;
reg uart_rx;
wire [7:0] seg7;
rx_top u_rx_top(
.clk(clk),
.rst(rst),
.rx_pin_in(uart_rx),
.seg7(seg7)
);
initial begin
clk=0; //INIT
rst=1; //觸發start posedge 開始接收訊號
rst=0; //復位
uart_rx=1; //(確保高電位)
//Start bit
#130208 uart_rx = 0;
//Ascii test
#130208 uart_rx = 1;
#130208 uart_rx = 0;
#130208 uart_rx = 0;
#130208 uart_rx = 0;
#130208 uart_rx = 0;
#130208 uart_rx = 0;
#130208 uart_rx = 0;
#130208 uart_rx = 0;
//Stop bit
#130208 uart_rx = 1;
#130208 uart_rx = 1;
#130208 uart_rx = 1;
#130208 uart_rx = 1;
end
always #10 clk=~clk;
endmodule
````
* Teshbench參考參考資料 2。
* 波特率=每秒可傳輸bits的速率,實驗用板子時脈=125MHz,1bit所需傳輸時間125M/9600=130208(ns)
## Simulation
:::success

9600(baud/second): 每個訊號間格為1/9600=104µs
經過104µs低電位(Start bit)後開始接收訊號,但由於訊號還不穩定所以會先等54µs後才真正開始儲存來源訊號(per data bit)。
:::
## Schematic

## Coverage
:::success

* 開始的Test bench寫法跑coverage覆蓋率很低(TB如上),所以把實驗要求所有情況和default都補上,重跑一遍後覆蓋率有顯著提升。
* Branch coverage: 原本Module rx_ctl部分缺少 else和 default ,因此覆蓋率只有85%左右 拉低了整體覆蓋率。所以加上 default的條件與Coverage on/off提升,並防止line Coverage下降。
* FSM coverage: 由於參考的程式碼沒有跑出FSM coverage,找出原因發現狀態轉換敘述不完整,所以想用Current state ,Next state..去化簡原本的12個狀態,試著嘗試很多次修改程式碼仍然效果不好,所以最後未在Makefile加入執行FSM coverage。(經過Spyglass發現有可能是因為同時含有兩個邏輯敘述導致不會出現FSM Coverage)
* Line coverage: 沿用 //coverage on //coverage off屏蔽掉未執行到的程式碼提升了覆蓋率。
:::

## Lint(SPYGLASS)
:::success

### Warnings

Sequential and Combinational parts of FSM desciption should be seperated :
* 時序和組合邏輯部分在同一個Top module 中造成。因為同一個區塊中用了時序(正負緣觸發)和組合邏輯(ascii27)導致,所以盡量不要把這兩個邏輯敘述放在一起,不然會導致程式提高複雜性,進而降低程式的可讀性,在使用Tool上也會增加負擔,得回去重新修改RTL Code.
:::
## 參考資料
https://www.youtube.com/watch?v=IyGwvGzrqp8
https://blog.csdn.net/qq_24287711/article/details/130294198?utm_medium=distribute.pc_relevant.none-task-blog-2
# HW7 人月神話專案管理讀書心得
## 1.外科手術團隊:
如同人月神話篇章所提,一個項目的完成速度不是由人數來取決,軟件工程的工作之間往往存在一個前後關係,得完成一項才能接著另一項,加進來的人手並不能馬上展開後面的工作,所以透過增加人手來加速開發往往只是一種神話。但作者提出參照外科手術的團隊概念,讓人佩服,彷彿可以輕鬆解決這項難題,像是Steve Jobs所說一個聰明的人可以抵過50個平凡的人,只要多數人圍繞在主治動刀醫生的周邊作為輔助,就可以大大提升項目成功機率。
## 3.沒有銀彈:
銀彈也就是銀做的子彈,傳說中為了殺死狼人必須使用白銀材質的子彈才行,軟體猶如一般人,但一出了差錯便有可能化身為恐怖的狼人,這個篇章中銀彈代表著能徹地解決問題的方法或技能,希望能一槍將狼人斃命。但是在軟件工程管理中,一定會遇到無法解決的困難,過程中不可能如願一帆風順,作者對此也給出了原因,其一是電腦技術發展速度過於迅速,工程師必須不斷學習新技術與知識,同時也要面對社會需求給軟體帶來的變化,其二,作者提出了複雜性(組織管理,技術)、配合性(規則的差異)、異變性(需求變化)、與隱匿性(語言交流和認知困難)。
最後作者也盡可能改善這些困難造成的困境,第一是採用高階語言以化繁為簡提升開發效率,第二是透過專家系統,專家系統具有推理引擎和知識庫,可以接收資料來推導結果,也利用更上層的人工智慧成為研發助力。