# 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 ``` ![](https://i.imgur.com/fJBQFh4.jpg) ---