# 軟硬體協同設計HW5
### ● 作業標題:Improve code coverage of your design
### ● 班級姓名座號:國立高雄大學電機系大四 B1095117 黃致衡
### ● 授課老師:林宏益教授
---
## 一、作業內容:
###
針對上課講義內容所提及的 Finite State Machine codes 進行 code coverage 分析。
## 二、實作步驟:
### 1. 撰寫 simple_moore_fsm 的 RTL code (moore__fsm.v)
```
module simple_moore_fsm(
clk,
rst_n,
inpl,
outp
);
input clk, rst_n, inpl;
output outp;
reg [1:0] curr_state, next_state;
reg outp;
parameter IDLE = 2'd0;
parameter S0 = 2'd1;
parameter S1 = 2'd2;
//state transient
always @(posedge clk or negedge rst_n)
begin
if (!rst_n)
curr_state <= IDLE;
else
curr_state <= next_state;
end
always @(curr_state or inpl)
begin
case(curr_state)
IDLE: next_state = (inpl == 1'd1) ? S0 : IDLE;
S0: next_state = (inpl == 1'd1) ? S1 : IDLE;
S1: next_state = (inpl == 1'd1) ? S1 : IDLE;
// VCS coverage off
default: next_state = IDLE;
// VCS coverage on
endcase
end
always @(curr_state)
begin
case(curr_state[1:0])
IDLE: outp = 1'd0;
S0: outp = 1'd0;
S1: outp = 1'd1;
// VCS coverage off
default: outp = 1'd0;
// VCS coverage on
endcase
end
endmodule
```
### 2. 再撰寫 simple_moore_fsm 的 Testbench (moore__fsm__tb.v)
```
module simple_moore_fsm_tb;
reg clk_in, rst_n, inp;
wire fsm_out;
parameter clk_duration = 10;
simple_moore_fsm simple_moore_fsm_try(clk_in, rst_n, inp, fsm_out);
initial
clk_in = 1'b0;
always #(clk_duration/2) clk_in = ~ clk_in;
initial
begin
$dumpfile("hw_and_sw_hw5.vcd");
$dumpvars;
$fsdbDumpfile("hw_and_sw_hw5.fsdb");
$fsdbDumpvars;
$monitor("clk = %b, rst = %b, input = %b, output = %b", clk_in, rst_n, inp, fsm_out);
end
initial
begin
rst_n = 1'b0; inp = 1'b0;
#10 rst_n = 1'b1; inp = 1'b0;
#10 inp = 1'b1;
#10 inp = 1'b0;
#10 inp = 1'b1;
#10 inp = 1'b1;
#10 inp = 1'b1;
#10 inp = 1'b0;
#10
$finish;
end
endmodule
```
### 3. 使用 lcarus Verilog 經過 compile 產生 .vcd檔,並使用 GTKWave 預先查看合成前 simulation 的波型結果

> 由此張波型結果雖可以一步一步推斷各個時間所產生的值,但無法直接了解其所處的狀態 (如:IDLE, S0, S1) 為何?
### 4. 將所有 Verilog 檔案與 filelist.f 上傳至 EDA cloud,並將上述步驟改於工作站進行
### 5. 設定所要執行的 makefile 檔案功能,並於工作站使用指令 UNIX% make vcs_kdb 進行編譯
```
.PHONY:clean vcs_kdb vcs_cov verdi_kdb verdi_cov
VCS = Rvcs
VERDI = Rverdi
#***** coverage option *****
COV_METRICS_SEL = line+cond+fsm+branch
#COV_METRICS_SEL = line+cond+fsm+branch+tgl #for postsim
#***** VCS compile option *****
VCS_COMP_OPT = \
-full64 \
-debug_acc+all \
-j4 \
-lca \
-kdb \
-sverilog \
-Xkeyopt=rtopt \
-Mupdate \
-R \
+v2k \
#***** VCS simulate option *****
VCS_SIM_OPT = \
+vcs+fsdbon \
-timescale=1ns/1ps \
-l ./logfile/vcs_kdb_compiled.logfile/vcs_kdb_compiled\
+vcs_flush+all \
#***** VCS coverage option *****
VCS_COV_OPT = \
-cm $(COV_METRICS_SEL) \
-cm_log ./logfile/vcs_cov_$(COV_METRICS_SEL)_compiled.log \
-cm_dir ./coverage/coverage.vdb \
-cm_name coverage
#***** VCS compilation *****
vcs_kdb:
$(VCS) \
$(VCS_COMP_OPT) \
$(VCS_SIM_OPT) \
-file filelist.f \
vcs_cov:
$(VCS) \
$(VCS_COMP_OPT) \
$(VCS_SIM_OPT) \
$(VCS_COV_OPT) \
-file filelist.f \
#***** Verdi compilation *****
verdi_kdb:
$(VERDI) -f filelist.f -ssf novas.fsdb
verdi_cov:
$(VERDI) -cov -covdir ./coverage/coverage.vdb
clean:
rm -rf unrSimv* csrc* ./logfile/* *key *fsdb *vcd *Log *bak *el *report no_trace* *.dump
rm -rf simv* verdi_* partition* dprof* clk* *DB *dir work *lib *.daidir nWave* DVE* *.out
rm -rf novas* cm.* ./coverage/* *.log *.vdb
```
### 6. 使用指令 UNIX% make verdi_kdb 開啟 Verdi 檢視波型運行結果與其產生的 FSM diagram


> 藉由上課講義所提供的 FSM diagram,可驗證波型結果有成功運行到每個狀態,(moore__fsm.v) 與 (moore__fsm__tb.v) 撰寫正確無誤!
### 7. 使用指令 UNIX% make vcs_cov 進行 coverage 分析,並使用指令 UNIX% make verdi_cov 開啟 Verdi 檢視分析報告
> 分析結果顯示於「三、實作結果」。
## 三、實作結果:
### ◎ fullscore

### ◎ line coverage

### ◎ FSM coverage

### ◎ condition coverage

### ◎ branch coverage

## 四、實驗討論:
### 1. 要如何提升 Line coverage 數值?
###
如實驗結果,可見到在程式碼中大部分的程式碼都被標上了綠色的底色,代表該行程式碼有被執行到。而唯一一行沒有被執行到並被標上紅色底色的程式碼為 `default: outp = 1'd0;` 考慮到若 case 法中若不使用此設定,可能造成電路在合成結果時容易產生非預期的 latch 可能,因此將其保留。
而在分析時的 Line coverage 分數在 97 分的位置,落在可以接受的範圍內,因此此狀況不予理會。
### 2. 要如何提升 FSM coverage 數值?
###
由於此作業一開始給的 testbench 程式碼僅有 75% 的 FSM coverage,因此將其修改到 100% 為此次作業的重點目標。
首先,將原程式碼進行分析時,在 FSM coverage 跑出了此狀況(如下圖)。

由上圖可知,在狀態由 S0 跳回 IDLE 時是沒有被運行到的,藉由查找原程式碼的 testbench,發現於 initial 語法中的設定全部皆設定為 100 time units。
此設定方法會使第 30 行的設定 (如下圖) 原意是要由狀態 S0 跳回 IDLE,但 CLK 寫入的速度比起訊號的更動速度還要快,導致其一直維持著 `inp = 1'b1;` 便錯誤地由狀態 S0 跳到 S1,後續的設定更是無法驗證到「由狀態 S0 跳回 IDLE」此路徑。因此我將其先改成 time units 等於 #10,使其過了 10 個 time units 馬上產生 `inp = 1'b0;` 在 CLK posedge 前成功「由狀態 S0 跳回 IDLE」。

最後,考慮到訊號更動的 time units 若設定的與 CLK duration 不同步的話,容易在 sequential 電路中撰寫 testbench 時沒有成功驗證到所有預設的狀態,因此最後我將下列包含在 initial 裡面的設定都改成 10 個 time units,而成功達到 100% 的結果顯示於「三、實作結果」。

### 3. 要如何提升 Condition coverage 數值?
###
如實驗結果,可見到每個條件判斷句都成功執行到,因此達成率 100%。
### 4. 要如何提升 Branch coverage 數值?
###
如實驗結果,受限於程式碼 `default: outp = 1'd0;` 該行於 Line coverage 分析時並未成功執行到乃肇因於 case 語法中的所有設定皆已涵蓋所有結果,因此該行於 Line coverage 分析時並未執行;同理,branch coverage 分析時也不會跳躍到該行,因此無法達成到 100%。
## 五、實驗心得:
###
本次的作業學習到了數位IC設計前端所需的三大工具之一「VCS」,而對於此工具從未觸碰過的我其實在 makefile 的調整就一頭霧水,光 userguide 裡面所提供的功能更是不勝枚舉。
而本次的作業在調整分析時並不至於太難,但在 Verdi 這個軟體所具備的功能與操作方式,我僅學習到了冰山一角而已,看來在這條學習道路上,對於環境操作以及軟體熟悉程度,我還需要付出更多心力來學習。
## 六、參考文獻:
> EEF946〈軟硬體協同設計〉課堂參考講義