# Verilog HDL
## Verilog HDL 訊號命名原則
訊號命名原則跟 coding style 一樣重要,尤其代碼量多的工程,一看訊號名稱就大概知道此訊號的特徵也方便 debug 。以下是我個人常用的方法。
除特殊訊號外FPGA輸入實際名稱用大寫,字跟字間用底線區分。
`input SIGNAL_NAME`
除特殊訊號外FPGA輸出實際名稱用大寫,字跟字間用底線區分。
`output SIGNAL_NAME`
sub module 輸入訊號前面加i
`input iSignalName`
sub module 輸出訊號前面加o
`output oSignalName`
reg 類型訊號前面加r
`reg rSignalName`
wire 類型訊號前面加w
`wire wSignalName`
輸入訊號為 vectors 類型訊號前面加 iv
`input [7:0] ivSignalName`
輸出訊號為 vectors 類型訊號前面加 ov
`output [7:0] ovSignalName`
reg 為 vectors 類型前面加rv
`reg [7:0] rvSignalName`
wire 為 vectors 類型前面加 wv
`wire [7:0] wvSignalName`
輸入訊號為 low active 前面加大寫 N
`input SignalNameN`
D Flip Flop 輸出端後面加 _q
`reg rSignalName_q`
D Flip Flop 輸入端後面加 _d
`reg rSignalName_d`
---
## Generate 用法
Generate 好用之處在於可以依不同條件下產生不同實體模組這樣對 coding 的靈活性有很大的幫助。
(1) generate 有 generate for, generate if 及 generate case 三種用法。
(2) generate for 變數要以 genvar 關鍵字定義。
(3) generate for 內容需加 begin end 包起來。
(4) generate for 後面需加名子 ex : begin : name
以下是使用 generate for, generate if 及 generate case 的範例
* 二位元加法器
``` verilog=0
`timescale 1ns/100ps
////// ... . .. --.. . - .... . -- --- -- . -. - //////
// Author : TienYao
// Source Code Name : adder_2.v
// Function Description: 2 bits Adder function
// ===========================================================
module adder_2 (
input [1:0] a,
input [1:0] b,
output [2:0] c
);
assign c = a + b;
endmodule
```
* 四位元加法器
``` verilog=0
`timescale 1ns/100ps
////// ... . .. --.. . - .... . -- --- -- . -. - //////
// Author : TienYao
// Source Code Name : adder_4.v
// Function Description: 4 bits Adder function
// ===========================================================
module adder_4 (
input [3:0] a,
input [3:0] b,
output [4:0] c
);
assign c = a + b;
endmodule
```
* 十六位元加法器
``` verilog=0
`timescale 1ns/100ps
////// ... . .. --.. . - .... . -- --- -- . -. - //////
// Author : TienYao
// Source Code Name : adder_16.v
// Function Description: 2 byte Adder function
// ===========================================================
module adder_16 (
input [15:0] a,
input [15:0] b,
output [16:0] c
);
assign c = a + b;
endmodule
```
* 八位元計數器
``` verilog=0
`timescale 1ns/100ps
////// ... . .. --.. . - .... . -- --- -- . -. - //////
// Author : TienYao
// Source Code Name : counter_width_8.v
// Function Description: counter
// ===========================================================
module counter_width_8
#(parameter width = 8) (
input clk,
input rstN,
output [width - 1 : 0] rvCounterOut
);
reg [width - 1 : 0] rvCounter_d;
reg [width - 1 : 0] rvCounter_q;
always @(posedge clk or negedge rstN) begin
if(!rstN)
rvCounter_q <= {width{1'b0}};
else
rvCounter_q <= rvCounter_d;
end
always @(*) begin
rvCounter_d = rvCounter_q + 1;
end
assign rvCounterOut = rvCounter_q;
endmodule
```
* 十六位元計數器
``` verilog=0
`timescale 1ns/100ps
////// ... . .. --.. . - .... . -- --- -- . -. - //////
// Author : TienYao
// Source Code Name : counter_width_16.v
// Function Description: counter
// ===========================================================
module counter_width_16
#(parameter width = 16) (
input clk,
input rstN,
output [width - 1 : 0] rvCounterOut
);
reg [width - 1 : 0] rvCounter_d;
reg [width - 1 : 0] rvCounter_q;
always @(posedge clk or negedge rstN) begin
if(!rstN)
rvCounter_q <= {width{1'b0}};
else
rvCounter_q <= rvCounter_d;
end
always @(*) begin
rvCounter_d = rvCounter_q + 1;
end
assign rvCounterOut = rvCounter_q;
endmodule
```
* 使用範例
``` verilog=0
`timescale 1ns/100ps
////// ... . .. --.. . - .... . -- --- -- . -. - //////
// Author : TienYao
// Source Code Name : generate_test.v
// Function Description: generate method test
// ===========================================================
module generate_test #(
parameter length_for = 8,
parameter select_if = 16,
parameter select_case = 4 ) (
input CLK,
input RESET_N,
input [length_for - 1 : 0] INPUT_FOR,
output [length_for - 1 : 0] OUTPUT_FOR,
output [select_if - 1 : 0] OUTPUT_IF,
input [select_case - 1 : 0] A_CASE,
input [select_case - 1 : 0] B_CASE,
output [select_case : 0] OUTPUT_CASE
);
generate
genvar i;
for(i = 0; i <= length_for - 1 ; i = i + 1) begin : generate_for
assign OUTPUT_FOR[i] = INPUT_FOR[i];
end
endgenerate
generate
if(select_if == 8) begin
wire [select_if - 1 : 0] wvCounterWidth;
counter_width_8 #(.width(select_if))
counter_width_8_isnt (
.clk (CLK),
.rstN (RESET_N),
.rvCounterOut (wvCounterWidth)
);
assign OUTPUT_IF = wvCounterWidth;
end
else begin
wire [select_if - 1 : 0] wvCounterWidth;
counter_width_16 #(.width(select_if))
counter_width_16_isnt (
.clk (CLK),
.rstN (RESET_N),
.rvCounterOut (wvCounterWidth)
);
assign OUTPUT_IF = wvCounterWidth;
end
endgenerate
generate
case(select_case)
2: adder_2 adder_2_inst (.a(A_CASE), .b(B_CASE), .c(OUTPUT_CASE));
4: adder_4 adder_4_inst (.a(A_CASE), .b(B_CASE), .c(OUTPUT_CASE));
6: adder_6 adder_6_inst (.a(A_CASE), .b(B_CASE), .c(OUTPUT_CASE));
8: adder_8 adder_8_inst (.a(A_CASE), .b(B_CASE), .c(OUTPUT_CASE));
default: adder_16 (.a(A_CASE), .b(B_CASE), .c(OUTPUT_CASE));
endcase
endgenerate
endmodule
```
---
## 計數器設計
FPGA 幾乎會用到計數器相關設計,如 Watch dog、 PWM 、除頻器等等。
而計數器設計大致會有二個條件 :
1.什麼條件下計數
2.什麼條件下重新計數
掌握了這二個條件就可以設計計數器,以下為一個簡單計數器設計。
(1)在 iEn 為 1 時計數器加一。
`assign AddCnt = iEn;`
(2)在計數器數到使用者設定的值時,下一個clock進來時重新計數。
`assign EndCnt = AddCnt && (rvCnt_q == MOD — 1);`
而 iClr 為 1 時計數器清 0,iLoad 為 1 時可填入計數初始值。
掌握了這二個條件就可以設計計數器了。
``` verilog=0
`timescale 1ns/100ps
////// ... . .. --.. . - .... . -- --- -- . -. - //////
// Author : TienYao
// Source Code Name : counter.v
// Function Description: Mod [3:0] Counter
// ===========================================================
module counter
#(parameter MOD = 10) (
input clk,
input rstN,
input iClr,
input iEn,
input iLoad,
input [3:0] iModValue,
output oCntDone,
output [3:0] ovCntValue
);
wire AddCnt;
wire EndCnt;
reg [3:0] rvCnt_d , rvCnt_q;
assign AddCnt = iEn;
assign EndCnt = AddCnt && (rvCnt_q == MOD - 1);
always @(posedge clk or negedge rstN) begin
if(!rstN)
rvCnt_q <= 4'h0;
else
rvCnt_q <= rvCnt_d;
end
always @(*) begin
if(EndCnt || iClr)
rvCnt_d = 4'h0;
else if(iLoad)
rvCnt_d = iModValue;
else if(AddCnt)
rvCnt_d = rvCnt_q + 1'b1;
else
rvCnt_d = rvCnt_q;
end
assign ovCntValue = rvCnt_q;
assign oCntDone = AddCnt && (rvCnt_q == MOD - 1) ? 1'b1 : 1'b0;
endmodule
```

---