# FPGA 第六組 Lab 1結報
## 組員
| 姓名 | 學號 |
|:------:|:---------:|
| 劉永勝 | F94089032 |
| 蔡宗瑾 | E14083137 |
| 李宇洋 | E24099025 |
- [**文章網址**](https://hackmd.io/BV7OxZgaQLelm0RUrry8Hg?both)
## Problem 1 - RGB LED
- 透過修改`pynq-z2_v1.0.xdc`內容,我們在`top.v`引入了output `led4`和`led5`的**rgb控制項**,並透過`LED.v`的內部邏輯進行顏色變換的控制。
- 透過FPGA開發版上的input `sw` 進行顏色切換,`LED.v`內部電路設計的邏輯為判定switch input後更改顏色。
```verilog=
always@(posedge clk or posedge rst)begin
if(rst) begin
// Setup the initial output for 4-bit LED
led <= 4'b0000;
end
else begin
// Initialize LED output
led4_r <= 1'b0;
led4_g <= 1'b0;
led4_b <= 1'b0;
led5_r <= 1'b0;
led5_g <= 1'b0;
led5_b <= 1'b0;
case(sw)
// Color: White
2'b00: begin
led4_r <= 1'b1;
led4_g <= 1'b1;
led4_b <= 1'b1;
led5_r <= 1'b1;
led5_g <= 1'b1;
led5_b <= 1'b1;
end
// Color: Red
2'b01: begin
led4_r <= 1'b1;
led5_r <= 1'b1;
end
// Color: Green
2'b10: begin
led4_g <= 1'b1;
led5_g <= 1'b1;
end
// Color: Yellow
2'b11: begin
led4_r <= 1'b1;
led4_g <= 1'b1;
led5_r <= 1'b1;
led5_g <= 1'b1;
end
endcase
end
end
```
## Problem 2 - Traffic Light
- 一樣透過修改`pynq-z2_v1.0.xdc`內容,我們在`top.v`引入了input控制項`add`, `sub`, `c_rst`,其中`c_rst`為原本Problem 1中的button 0的位置,為調整秒數狀態的重置訊號。`rst`則被更改至button 3的位置(`rst`是global reset的訊號)。
- **c_rst (Button 0):** 當目前模式(switch)為調整模式時,可以將所有秒數重置為原本設定(一紅一綠 5s、皆為紅 1s、一黃一紅 1s)。
- **add (Button 1):** 當目前模式(switch)為調整模式時,可以用來增加選擇狀態(一紅一綠、皆為紅、一黃一紅)的秒數。
- **sub (Button 2):** 當目前模式(switch)為調整模式時,可以用來減少選擇狀態(一紅一綠、皆為紅、一黃一紅)的秒數。
- **rst (Button 3):** Global reset,不限任何模式(switch)皆可使用,會將所有狀態(state)與設定秒數重置為原本設定。
- `LED.v`內部的電路設計流程如下:
1. 建立**FSM**與**Output decoder**。
- FSM: 負責控管正常運作模式下的紅綠燈狀態(state)切換,以及判定是否reset。
- Output decoder: 用於控制不同模式(switch)及狀態(state)的RGB led以及4-bit led控制(即: output)。
2. 決定使用到的**Register**:
- **counter_red:** 紀錄皆為紅燈狀態下的秒數應為多少。
- **counter_green:** 紀錄一紅一綠狀態下的秒數應為多少。
- **counter_yellow:** 紀錄一黃一紅狀態下的秒數應為多少。
- **counter:** 儲存當前狀態的秒數,讓FSM能夠判定是否應該要切換state。
- **state:** 正常模式下的工作狀態,詳細工作模式見下列。
:::success
**switch type命名方式如下:**
```verilog=
parameter WORK = 2'd0,
G_ADJUST = 2'd1,
Y_ADJUST = 2'd2,
R_ADJUST = 2'd3;
```
:::
3. **FSM的狀態控制**: 負責管控紅綠燈的正常運作,藉由檢查計數器(Counter)是否為0來切換狀態(state),其運作包含的狀態如下圖:

每當切換狀態時就會將**下個狀態應該要有的秒數**assign給Counter,並且在每個Cycle不斷減少Counter的數字直到為0。
```verilog=
// FSM: Only work when the switch is in work mode
always @(posedge clk or posedge rst) begin
if(rst) begin
state <= HrVg;
counter <= 4'd5;
end
else begin
// Check if the switch is in work mode
if(sw == WORK) begin
counter <= counter - 1;
case(state)
HrVg: begin
if(counter == 0) begin
state <= HrVy;
counter <= counter_yellow;
end
else begin
state <= HrVg;
end
end
HrVy: begin
if(counter == 0) begin
state <= HrVr;
counter <= counter_red;
end
else begin
state <= HrVy;
end
end
HrVr: begin
if(counter == 0) begin
state <= HgVr;
counter <= counter_green;
end
else begin
state <= HrVr;
end
end
HgVr: begin
if(counter == 0) begin
state <= HyVr;
counter <= counter_yellow;
end
else begin
state <= HgVr;
end
end
HyVr: begin
if(counter == 0) begin
state <= HrVr_2;
counter <= counter_red;
end
else begin
state <= HyVr;
end
end
HrVr_2: begin
if(counter == 0) begin
state <= HrVg;
counter <= counter_green;
end
else begin
state <= HrVr_2;
end
end
endcase
end
end
end
```
4. **Output控制**: 負責管控不同模式時的output運作,會先藉由檢查switch type以及button input來控制led。
- 當**c_rst**被按下且為**調整模式**時: 重置秒數設定。
- 當**rst**被按下時: 重置秒數設定並關閉4-bit led。
```verilog=
if(c_rst && sw != WORK) begin
counter_green <= 4'd5;
counter_red <= 4'd1;
counter_yellow <= 4'd1;
end
if(rst) begin
led <= 4'b0000;
counter_green <= 4'd5;
counter_red <= 4'd1;
counter_yellow <= 4'd1;
end
```
- 當switch為**WORK**時:
- 根據狀態(state)不同調整RGB led的output。
- 將**Counter內儲存的當前秒數**assign給4-bit led作為output。
```verilog=
WORK: begin
case(state)
HrVg: begin
h_r <= 1'b1;
v_g <= 1'b1;
end
HrVy: begin
h_r <= 1'b1;
v_r <= 1'b1;
v_g <= 1'b1;
end
HrVr: begin
h_r <= 1'b1;
v_r <= 1'b1;
end
HgVr: begin
h_g <= 1'b1;
v_r <= 1'b1;
end
HyVr: begin
h_r <= 1'b1;
h_g <= 1'b1;
v_r <= 1'b1;
end
HrVr_2: begin
h_r <= 1'b1;
v_r <= 1'b1;
end
endcase
led <= counter;
```
- 當switch為**G_ADJUST**、**Y_ADJUST**、**R_ADJUST**時:
- RGB led的預設output為**off**。
- 將`counter_red` or `counter_green` or `counter_yellow`**內儲存的當前調整秒數**assign給4-bit led作為output。
- 當**add**、**sub**被按下時會先判定是否處於調整模式,若為真才可以進行調整;其中counter可以調整的**上限為15s、下限為1s**。
```verilog=
G_ADJUST: begin
if(add) begin
counter_green = (counter_green==15) ? 15 : counter_green + 1;
end
else if(sub) begin
counter_green = (counter_green==1) ? 1 : counter_green - 1;
end
led <= counter_green;
end
Y_ADJUST: begin
if(add) begin
counter_yellow = (counter_yellow==15) ? 15 : counter_yellow + 1;
end
else if(sub) begin
counter_yellow = (counter_yellow==1) ? 1 : counter_yellow - 1;
end
led <= counter_yellow;
end
R_ADJUST: begin
if(add) begin
counter_red = (counter_red==15) ? 15 : counter_red + 1;
end
else if(sub) begin
counter_red = (counter_red==1) ? 1 : counter_red - 1;
end
led <= counter_red;
end
```
:::warning
**在此Design中,因為counter與state在調整模式並不會被影響到,所以當switch從調整模式切換回正常運作模式時仍然會保留其在切換前的狀態與秒數。**
:::
- [Problem2的成果展示影片](https://youtu.be/osdEEp4heDc)
## Problem 3
1. 為什麼要加入"blinky.xdc" ?
該限制檔有下方兩個command,分別功用為:
- create_clock
在板子上,有一個產生clk的源頭(sysclk),稱為primary clock。timing constraints都是以此為基準來計算slack。因此,為了確保時序不被摻雜額外延遲,要把自己設計電路的clk定義在sysclk上。但這並不代表我們的系統和sysclk之間完全沒有延遲,而是藉由這條指令**忽略clk硬體延遲**,達到準確的timing分析。
- create_generated_clock
此指令可用於自行產生的clk。在自行生成不同頻率或offset的clk時,需要一個**master clk**,用來給自行產生的clk參考。因此先透過create_clock生成以**sysclk**為基準的master clk,之後再讓generated_clk做為參考,產生出divider clk。
2. Vivado的開發流程中, Synthesis和Implementation的結果差異在哪?
Sythesis是將RTL轉成實際的邏輯接線(netlist),之後implementation是將前一步驟產生的netlist做placement、rounting優化。
:::info
下圖為Implementation後Device截圖:
在Synthesis後,只會確定邏輯合成,所以Device上只有IO的位置被確定(最右側橘色亮點)。而Implementation後,電路擺放、繞線已經完成,因此可以看到下圖**藍色亮點出現,為邏輯電路實際擺放位置**。

:::