FPGA學習

一、module?:

? ? ? ?定義:?是構建數字系統的基本單元,用于封裝電路的結構和行為。它可以表示從簡單的邏輯門到復雜的處理器等任何硬件組件。

1.?module?的基本定義
module 模塊名 (端口列表);// 端口聲明input [位寬] 輸入端口1;output [位寬] 輸出端口1;inout [位寬] 雙向端口1;  // 雙向I/O(如三態總線)// 內部信號聲明wire [位寬] 內部連線;reg [位寬] 寄存器;// 邏輯功能實現// - 連續賦值語句(assign)// - 過程塊(always)// - 模塊實例化// - 任務(task)和函數(function)endmodule
  • 特點
    • 硬件抽象:每個模塊對應實際電路的一個功能單元。
    • 層次性:模塊可以嵌套實例化,構建復雜系統。
    • 端口隔離:模塊通過端口與外部通信,內部實現對外部透明。

2. 簡單模塊示例

示例 1:2 輸入與門
module and_gate (input a,      // 輸入端口ainput b,      // 輸入端口boutput y      // 輸出端口y
);assign y = a & b;  // 連續賦值語句,實現邏輯與endmodule
示例 2:帶寄存器的計數器
module counter (input clk,        // 時鐘信號input reset,      // 復位信號(高有效)input enable,     // 使能信號output reg [7:0] count  // 8位計數器輸出(聲明為reg類型)
);always @(posedge clk) beginif (reset)count <= 8'b0;      // 復位時計數器清零else if (enable)count <= count + 1; // 使能時每個時鐘周期加1
endendmodule

3. 模塊實例化與連接

模塊通過實例化(Instantiation)嵌入到其他模塊中,形成層次化設計。

示例 3:使用 and_gate 構建更復雜的電路
module top_module (input x, y, z,output f
);wire w1, w2;  // 內部連線// 實例化and_gate模塊(兩個與門)and_gate u1 (.a(x),    // 連接到輸入x.b(y),    // 連接到輸入y.y(w1)    // 輸出連接到內部信號w1);and_gate u2 (.a(w1),   // 輸入連接到u1的輸出w1.b(z),    // 輸入連接到輸入z.y(w2)    // 輸出連接到內部信號w2);// 最終輸出assign f = w2;endmodule

4. 參數化模塊

使用?parameter?可以定義可配置的常量,增強模塊的靈活性。

示例 4:參數化的計數器
module param_counter #(parameter WIDTH = 8,      // 計數器位寬,默認8位parameter INIT = 0        // 初始值,默認0
) (input clk, reset, enable,output reg [WIDTH-1:0] count
);always @(posedge clk) beginif (reset)count <= INIT;        // 復位時加載初始值else if (enable)count <= count + 1;
endendmodule

image

  • assign?是連續賦值語句,用于描述組合邏輯(無記憶,輸出實時跟隨輸入變化)。
  • 功能:將輸入?a?和?b?相加,結果賦值給輸出?cVerilog 會自動處理位寬擴展(2 位 + 2 位 = 3 位,匹配?c?的位寬)。
  • 模塊實例化部分(adder u1(.a(in1), .b(in2), .c(in3));

    這部分是復用已定義的模塊adder),并將其端口與外部信號連接,類似 “在電路板上焊接芯片并接線”。

  • adder:要實例化的模塊名(必須和前面定義的?module adder?一致)。
  • u1:實例名(自定義,同一模塊可實例化多次,如?u2u3?等,用于區分不同實例)。
  • .端口名(外部信號)命名端口映射把模塊的內部端口和外部信號一一對應:
    • .a(in1):模塊的?a?端口 ? 外部信號?in1in1?需是 2 位信號)。
    • .b(in2):模塊的?b?端口 ? 外部信號?in2in2?需是 2 位信號)。
    • .c(in3):模塊的?c?端口 ? 外部信號?in3in3?需是 3 位信號)。
  • 外部信號的要求
  • 聲明in1in2in3?必須在當前作用域(比如上層模塊)中提前聲明,例如:

    verilog

    • wire [1:0] in1, in2;  // 2位輸入信號(wire類型,因為是組合邏輯連接)
      wire [2:0] in3;       // 3位輸出信號(wire類型,因為模塊輸出是wire)

二、數據類型及常量變量

1、Verilog HDL有四種基本的值

image

(1)其中x和z不區分大小寫;

(2)z也可以使用?表示,雖然不懂為什么不是表示未知……

2、Verilog HDL三類常量

?(1)整型:直接用數字序列表示的整數,默認采用十進制。

??????????????1,-2;

  • 特點:書寫簡單,但無法明確指定數值的位寬和進制。
  • 注意:負數只能用十進制表示,不能用基數表示法表示負數。

B、基數表示:<位寬>’<進制><數字>?

image??

  • b?或?B:二進制
  • o?或?O:八進制
  • d?或?D:十進制
  • h?或?H:十六進制

?image

下劃線(_):可以在數字中插入下劃線,提高可讀性,但不影響數值

image

  • 無符號數:默認情況下,整型常量是無符號數。
  • 有符號數:在常量前加負號(-),但負數只能用十進制表示。
  • -8'd10     // 錯誤!不能用基數表示法表示負數
    -10        // 正確!十進制負數
  • 不定值(x)和高阻值(z):在二進制、八進制和十六進制中,可以使用?x?或?z?表示不定值或高阻值。

(2)實數型:實數型常量用于表示帶有小數部分的數值,有兩種表示形式:

1. 十進制形式

直接用數字和小數點表示的實數。

3.14159      // 圓周率
-0.001       // 負數
0.5          // 小數
5.           // 等同于5.0
2. 科學計數法形式

使用指數表示的實數,格式為:<數字>e<指數>?或?<數字>E<指數>

3.6e4        // 3.6×10?,即36000
-1.23e-2     // -1.23×10?2,即-0.0123
5E7          // 5×10?,即50000000
3. 實數與整數的轉換
  • 實數賦值給整數變量時,會自動截斷小數部分,只保留整數部分。
integer a;
a = 3.9;     // a的值為3(截斷小數部分)

  • 整數賦值給實數變量時,會自動轉換為實數。
real b;
b = 10;      // b的值為10.0(轉換為實數)

三、字符串型常量

字符串型常量用于表示一串字符,用雙引號(")括起來。

"Hello, World!"    // 字符串常量
"Verilog HDL"      // 包含空格的字符串
"12345"            // 包含數字的字符串
1. 轉義字符

在字符串中,可以使用轉義字符表示特殊字符。

"\n"        // 換行符
"\t"        // 制表符
"\""        // 雙引號
"\\"        // 反斜杠
2. 字符串的存儲
  • 字符串在 Verilog 中被存儲為一系列的 ASCII 字符,每個字符占用 8 位(1 字節)。
  • 字符串的長度由字符的個數決定,不包括雙引號。
"ABC"       // 長度為3的字符串,占用24位(3×8)
3. 字符串操作
  • 字符串可以賦值給 reg 類型的變量,但變量的位寬必須足夠容納字符串的所有字符。
reg [7:0] str [0:2];    // 聲明一個3個字符的字符串數組
initial beginstr[0] = "A";  // 或 8'd65 或 8'h41str[1] = "B";  // 或 8'd66 或 8'h42str[2] = "C";  // 或 8'd67 或 8'h43
endinitial begin$sformatf(str, "%s", "ABC");  // 格式化字符串到數組$display("str = %s", str);  // 輸出:str = ABC
end
  • reg [7:0]:每個元素是 8 位寬的寄存器(對應 1 個 ASCII 字符)。
  • str [0:2]:數組索引范圍是?0?到?2,共?3 個元素
  • 等效理解:這是一個?3 行 8 列?的二維數組,可存儲 3 個 ASCII 字符。

  • Verilog 不直接支持字符串的拼接、比較等操作,需要使用系統任務或函數。
$display("The value is %d", 10);    // 系統任務輸出字符串和變量

四、WIRE類型

(1)wire類型是一種基本的數據類型,用于表示硬件電路中的物理連線。它是組合邏輯設計的核心元素,下面詳細介紹其定義、用法和注意事項:

一、核心定義

? wire?用于建模信號連接類似電路板上的導線,主要特點:

  1. 信號載體:用于傳遞和連接模塊、門電路之間的信號。
  2. 被動賦值:不能存儲值,必須由驅動源(如?assign、門級實例、模塊輸出)持續驅動。
  3. 默認狀態:若無驅動,值為高阻態?z
  4. 硬件對應:直接映射到物理連線或組合邏輯輸出。

二、聲明語法

wire [位寬] 信號名1, 信號名2, ...;
  • 位寬(可選):指定信號的二進制位數,默認為 1 位。
  • 示例
wire clk;                // 1位wire信號(時鐘)
wire [7:0] data;         // 8位向量(數據總線)
wire [3:0] addr, enable; // 同時聲明多個wire

三、常見用法

1.?連續賦值(assign?語句)

通過表達式持續驅動?wire

wire a, b, c;
assign c = a & b;        // c等于a和b的邏輯與wire [3:0] x, y, z;
assign z = x + y;        // z等于x和y的和(組合邏輯加法)
2.?門級實例化連接

作為門電路的輸入 / 輸出:

wire a, b, c;
and gate1(c, a, b);      // 與門實例化,輸出到c
3.?模塊間信號連接

連接不同模塊的端口:

module top;wire clk, rst, data_in, data_out;// 實例化時鐘生成模塊clock_gen clk_gen (.clk(clk), .rst(rst));// 實例化數據處理模塊data_proc proc (.clk(clk), .rst(rst), .in(data_in), .out(data_out));
endmodule
4.?三態門驅動

用于總線共享場景:

wire data_bus;
wire enable;// 三態緩沖器
assign data_bus = enable ? data_out : 1'bz; // 使能時輸出數據,否則高阻

五、REG類型

? ?REG?是一種基本的數據類型,主要用于存儲數值,對應硬件中的觸發器(Flip-Flop)或鎖存器(Latch)。下面詳細介紹其定義、用法和注意事項:

一、核心定義

reg?用于表示存儲元件,具有以下特點:

  1. 存儲能力:能保持當前值,直到被新值覆蓋。
  2. 主動賦值:通過過程塊(initial?或?always)賦值。
  3. 默認狀態:初始值為不定態?x(除非顯式初始化)。
  4. 硬件對應:綜合后通常映射為觸發器(時序邏輯)或鎖存器(組合邏輯)。

?二、聲明語法

reg [位寬] 信號名1, 信號名2, ...;
  • 位寬(可選):指定信號的二進制位數,默認為 1 位。

示例

reg clk;                // 1位reg信號
reg [7:0] data;         // 8位向量(可存儲0~255)
reg [3:0] count;        // 4位計數器

三、常見用法

1.?時序邏輯(觸發器)

在時鐘邊沿觸發的?always?塊中使用:

reg [3:0] counter;always @(posedge clk or negedge rst_n) beginif (!rst_n)         // 異步復位(低電平有效)counter <= 4'b0;else if (en)        // 使能時計數counter <= counter + 1;
end
2.?組合邏輯(鎖存器)

在電平敏感的?always?塊中使用(需謹慎,易產生鎖存器):

reg data_out;always @(*) beginif (sel)data_out = data_in;  // 組合邏輯賦值(=)// 缺少else分支 → 綜合出鎖存器(不推薦)
end
3.?初始化(initial?塊)

僅用于仿真,不可綜合:

reg [7:0] mem [0:15];  // 存儲器數組initial begin// 初始化存儲器內容mem[0] = 8'hAA;mem[1] = 8'h55;// ...
end

?4.?函數和任務中的變量

function [7:0] multiply(input [3:0] a, b);reg [7:0] result;  // 函數內部變量beginresult = a * b;multiply = result;end
endfunction

?四、與?wire?的對比

特性regwire
存儲能力有存儲能力(保持值直到下一次賦值)無存儲,僅傳遞信號
賦值方式只能在?initial?或?always?塊中賦值由?assign、門或模塊驅動
適用場景時序邏輯(如觸發器)、變量存儲組合邏輯連接、模塊間通信
默認值不定值?x高阻態?z
賦值符號非阻塞賦值(<=)或阻塞賦值(=僅連續賦值(assign
硬件對應觸發器、鎖存器等存儲元件物理連線、組合邏輯輸出

五、使用注意事項

(1)在always語句和initial語句中的賦值對象只能是reg類型,reg類型信號也只能在always語句和initial語句中被賦值,

(2)所以,always、initial塊外的賦值對象和連線用wire型信號,always、initial塊內的賦值對象用reg型

六、運算符與運算表達式

image

1、算術運算符

用于數值計算,支持整數和定點數運算。

運算符描述示例
+加法c = a + b;
-減法c = a - b;
*乘法c = a * b;
/除法c = a / b;(整數除法)
%取模(取余)c = a % b;
**乘方(SystemVerilog)c = a ** b;(a 的 b 次方)

2、邏輯運算符

符號=(阻塞賦值)、<=(非阻塞賦值)
功能:將值賦給變量,核心區別在于執行時序

類型語法應用場景關鍵特性
阻塞賦值reg_a = reg_b;組合邏輯(always @(*)立即賦值,語句順序影響結果(如?a=1; b=a;?中b會立即等于 1)。
非阻塞賦值reg_a <= reg_b;時序邏輯(always @(posedge clk)

3、關系運算符

符號>(大于)、<(小于)、>=(大于等于)、<=(小于等于)
功能:比較兩數大小,結果為1 位布爾值1/0/X)。

示例說明
a > b無符號數比較(Verilog 默認,SystemVerilog 可通過signed聲明有符號比較)。
a <= b若操作數含X/Z,結果可能為X(如?4'b10x0 <= 4'b1000?結果為X)。

4、相等運算符

符號==(邏輯相等)、!=(邏輯不等)
功能:比較兩數是否相等(==)或不等(!=),不嚴格匹配X/Z

示例說明
a == b僅比較0/1位,若含X/Z,結果可能為X(如?4'b10x0 == 4'b1000?結果為X)。
a != b只要有一位0/1不同,結果為1;含X時結果可能為X
擴展===(全等,嚴格匹配X/Z)和!==(非全等),圖中未列但常用。

5、邏輯運算符

符號&&(邏輯與)、||(邏輯或)、!(邏輯非)
功能:對布爾值(非零視為,零為)進行邏輯運算,結果為1 位

示例說明
(a>0) && (b<5)兩邊均為(非零)時,結果為1;否則為0
!(a==0)a非零,結果為1;否則為0
與位運算符的區別
  • 邏輯運算:結果 1 位;位運算(如&/|)逐位處理,結果位寬同操作數。
  • 示例:wire log = (a && b);(邏輯與) vs?wire bit = a & b;(位與)。

6、位運算符

符號~(按位取反)、&(按位與)、|(按位或)、^(按位異或)
功能:對操作數逐位進行邏輯運算,結果位寬與操作數一致。

運算符示例說明
~~4'b1010 = 4'b0101每一位取反(1→00→1)。
&4'b1010 & 4'b1100 = 4'b1000逐位與(1&1=1,否則0)。
```4'b10104'b1100 = 4'b1110`逐位或(`00=0,否則1`)。
^4'b1010 ^ 4'b1100 = 4'b0110逐位異或(相同為0,不同為1)。
擴展:同或(~^?或?^~),即異或非(如?4'b1010 ~^ 4'b1100 = 4'b1001)。

7、移位運算符

符號<<(邏輯左移)、>>(邏輯右移)
功能:將操作數按位移動,空位補 0(邏輯移位)。

運算符示例說明
<<4'b1010 << 1 = 4'b0100左移 1 位,低位補 0(值變為原來的 2 倍,注意位寬截斷)。
>>4'b1010 >> 1 = 4'b0101右移 1 位,高位補 0(值變為原來的 1/2,整數除法)。
注意
  • Verilog 的>>對有符號數也會補 0(邏輯移位),SystemVerilog 的>>>才是算術移位(補符號位)。
  • 移位位數需為常量(綜合要求),如?a << 2(合法),a << b(非法,b需是常量)。

8、條件運算符

符號?:(三元運算符)
語法condition ? expr1 : expr2
功能:條件為(非零)時,結果為expr1;否則為expr2

示例說明
assign mux = sel ? a : b;sel=1asel=0b(實現多路選擇器)。
assign max = (a>b) ? a : b;ab中的較大者(支持嵌套,如三數取最大)。
注意expr1expr2需位寬兼容,否則會截斷(如16'b08'b1拼接會報錯,需顯式擴展位寬)。

9、連接和復制操作符

符號{}(大括號)
功能

  • 連接(Concatenation):將多個信號按位拼接。
  • 復制(Replication):將信號重復拼接(格式:{n{expr}}n為常量)。
1. 連接示例
// 示例1:簡單拼接
wire [3:0] a = 4'b1010, b = 4'b0011;
wire [7:0] c = {a, b};  // 結果:8'b1010_0011(a是高4位,b是低4位)// 示例2:位逆序(圖中案例)
assign bus[3:0] = {bus[0], bus[1], bus[2], bus[3]};  
// 原bus[3:0] = 4'b1010(位3=1,位2=0,位1=1,位0=0)→ 拼接后為{0,1,0,1} → 4'b0101(位序反轉)。

2. 復制示例?

// 示例1:信號復制
wire [1:0] a = 2'b10;
wire [5:0] b = {3{a}};  // 結果:6'b10_10_10(a重復3次)// 示例2:圖中案例
assign bus[3:0] = {2{bus[0]}, 2{bus[3]}};  
// 假設bus[0]=1(1位),bus[3]=0(1位)→ 復制后:{1,1,0,0} → 4'b1100。

九、begin_end

1、定義:

??? 用于將多條語句組合成一個順序執行的代碼塊,類似于 C 語言中的花括號{}。它主要用于alwaysinitialtaskfunction等過程塊中,確保語句按順序執行。

begin語句1;語句2;// ... 更多語句
end
  • 順序執行:塊內語句按書寫順序依次執行(僅適用于過程塊)。
  • 命名塊:可通過begin: 塊名為塊命名,用于調試或聲明局部變量。

?2. 在always塊中的應用

示例 1:組合邏輯(阻塞賦值)

always @(*) beginif (sel == 1'b0)out = a;elseout = b;
end

  • 說明
    • begin-endif-else語句組合為一個整體。
    • 使用阻塞賦值=),確保語句按順序執行。
示例 2:時序邏輯(非阻塞賦值)
always @(posedge clk or posedge reset) beginif (reset)q <= 1'b0;      // 異步復位elseq <= d;         // 時鐘上升沿更新
end
  • 說明
    • 使用非阻塞賦值<=),避免競爭冒險。
    • begin-end包裹復位和賦值操作。

3. 在initial塊中的應用

示例:測試平臺的初始化
initial begin// 初始化信號clk = 0;reset = 1;data = 8'h00;// 控制時序#10 reset = 0;      // 10個時間單位后釋放復位#20 data = 8'h55;   // 再20個時間單位后寫入數據#30 $finish;        // 結束仿真
end
  • initial塊僅執行一次,常用于測試平臺(Testbench)。
  • begin-end組合多條初始化和延時語句。

4. 在taskfunction中的應用

示例:任務(task)中的順序操作

???????

2、語句:順序塊

(1)塊內的語句順序執行

(2)每條語句的延時為相對前一句

(3)最后一句執行完,才能跳出該塊

image

十、fork_join語句:并行塊

(1)塊內語句同時執行

(2)每條語句的延時為相對于進入塊仿真的時間

(較為少用)

image

十一、if else語句(需要在always塊中使用)

if(表達式)   語句;
else if(表達式)  語句;
else   語句;
(多個語句需放在begin end間)

image

十二、case語句:多分支語句(需要在always塊中使用)

case(表達式)分支:語句……default:語句;endcase

十三、forever連續執行,常用于產生時鐘信號

image

十四、while執行語句

image

十五、repeat

??? 連續執行語句n次

??? repeat(表達式),在此表達式通常為常量表達式,表示重復次數。

??? begin語句;end

十六、for

image

十七、initial

????????initial:是一種用于初始化和仿真控制的過程塊,主要用于測試平臺(Testbench)和仿真場景。initial?塊的特點如下:
  1. 執行一次:在仿真開始時執行一次,執行完畢后不再執行。
  2. 仿真專用:不可綜合為硬件,僅用于仿真驗證。
  3. 并行執行:多個?initial?塊并行執行(與代碼順序無關)。
  4. 行為描述:用于控制信號時序、生成激勵或監控輸出。

二、語法格式

initial begin// 語句序列
end
  • begin-end:可選,若有多條語句則必須使用;單條語句可省略。

示例

initial begina = 1'b0;      // 初始化信號a為0#10 a = 1'b1;  // 延遲10個時間單位后,a置為1#20 $finish;   // 再延遲20個時間單位后,結束仿真
end
  • #10?是 Verilog 的延遲語句,表示暫停執行 10 個時間單位(時間單位由仿真器或?timescale?指令定義)。
  • 延遲結束后,執行?a = 1'b1
#20 $finish;
  • 功能:再延遲 20 個時間單位后,調用系統任務?$finish?結束仿真。
  • 語法
    • $finish?是 Verilog 的系統任務,用于終止當前仿真。
    • 整個?initial?塊的執行時間為?30 個時間單位(10 + 20)。

三、常見用法

1.?信號初始化

在仿真開始時設置信號初始值:

reg clk, rst_n;
reg [7:0] data;initial beginclk = 1'b0;      // 初始化時鐘為0rst_n = 1'b0;    // 初始化復位信號為低(復位狀態)data = 8'h00;    // 初始化數據為0
end
  • clk = 1'b0??1'b0?表示 1 位二進制數(1'b?是 Verilog 的二進制字面量格式)
    將時鐘信號初始化為低電平。通常配合后續的時鐘生成代碼(如forever #5 clk = ~clk)。
  • rst_n = 1'b0
    將復位信號初始化為低電平。大多數設計采用異步低電平復位,即rst_n=0時電路進入復位狀態。
  • data = 8'h00
    將數據信號初始化為 0。8'h00表示 8 位十六進制數00(二進制0000_0000)。
2.?生成時鐘信號

通過循環生成周期性時鐘:

initial beginforever begin#5 clk = ~clk;  // 每5個時間單位翻轉一次,生成周期為10的時鐘end
end
3.?產生測試激勵

按特定時序提供輸入信號:

initial begin// 復位序列rst_n = 1'b0;#20 rst_n = 1'b1;  // 20個時間單位后釋放復位// 輸入數據序列#10 data = 8'hAA;  // 釋放復位后10個時間單位,發送數據AA#20 data = 8'h55;  // 再20個時間單位后,發送數據55#30 $finish;       // 結束仿真
end
4.?文件操作

讀取測試數據或寫入仿真結果:

integer file;
reg [7:0] data;initial beginfile = $fopen("input.txt", "r");  // 打開輸入文件if (file == 0) begin$display("Error: Cannot open file!");$finish;endwhile (!$feof(file)) begin$fscanf(file, "%h", data);  // 從文件讀取16進制數據#10;                        // 等待10個時間單位end$fclose(file);
end
5.?仿真控制

使用系統任務控制仿真流程:

initial begin#1000 $finish;  // 1000個時間單位后自動結束仿真// 打印關鍵信息$display("Simulation started at time %0t", $time);$monitor("At time %0t: a=%b, b=%b, sum=%b", $time, a, b, sum);
end

十八、always?塊

????????是用于描述時序邏輯或組合邏輯的核心結構。它允許代碼在特定條件下重復執行,是構建硬件電路行為模型的基礎。

1.?always?塊的基本定義

always @(觸發條件) begin// 過程化語句
end
  • 功能always?塊會在觸發條件滿足時執行,執行完畢后等待下一次觸發。
  • 觸發條件(敏感列表):
    • 邊沿觸發(時序邏輯):@(posedge clk)(上升沿)或?@(negedge clk)(下降沿)。
    • 電平觸發(組合邏輯):@(a or b)?或?@(*)(自動推斷所有輸入信號)。

????????????????1.?@(a or b)?的含義

????????????????????????觸發條件:當信號ab的值發生變化時,always塊內的代碼會立即執行。??

? ? ?2、@(*)?的含義

????????????????????????自動推斷:編譯器會自動分析always塊內的代碼,將所有讀操作的輸入信號添加到敏感列表中。

always @(*) begin  // 等價于 @(a or b or c)out = a & b | c;  // 自動推斷敏感信號為a、b、c
end

2. 時序邏輯中的?always?塊

用途:描述觸發器、寄存器等時序元件。

示例 1:同步復位的 D 觸發器
always @(posedge clk) beginif (reset)        // 同步復位(高電平有效)q <= 1'b0;    // 復位時輸出清零elseq <= d;       // 時鐘上升沿時,d的值賦給q
end
  • 特點
    • 使用非阻塞賦值<=)保證正確的時序行為。
    • 僅在時鐘上升沿觸發,復位信號?reset?必須與時鐘同步。
示例 2:帶使能的計數器
reg [7:0] count;
always @(posedge clk) beginif (reset)count <= 8'b0;else if (enable)count <= count + 1;  // 每個時鐘周期加1
end

?3. 組合邏輯中的?always?塊

用途:描述邏輯門、多路選擇器等組合電路。

示例 3:4 選 1 多路選擇器
always @(*) begin  // 敏感列表為*,自動包含所有輸入case (sel)2'b00: out = a;2'b01: out = b;2'b10: out = c;2'b11: out = d;default: out = 1'bx;  // 避免鎖存器生成endcase
end
第 1 行:always @(*)
  • 觸發條件*表示敏感列表自動包含所有在塊內被讀取的信號(即selabcd)。
  • 組合邏輯標志always @(*)是 Verilog 中定義組合邏輯的標準寫法。
第 2-7 行:case語句
  • 選擇邏輯
    • sel2'b00時,輸出a
    • sel2'b01時,輸出b
    • sel2'b10時,輸出c
    • sel2'b11時,輸出d
第 8 行:default: out = 1'bx
  • 默認分支:處理sel為非法值(如2'bx2'bz)的情況。
  • 避免鎖存器:明確指定所有可能的輸入場景,防止綜合工具生成不必要的鎖存器。
  • 特點
    • 使用阻塞賦值=)保證語句按順序執行。
    • 敏感列表需包含所有輸入信號(或用?*?自動推斷),否則可能導致仿真與綜合結果不一致。
示例 4:組合邏輯實現的加法器

always @(a or b) begin  // 等價于 @(*)sum = a + b;
end

4. 混合邏輯中的?always?塊

用途:同時包含時序和組合邏輯的復雜電路。

示例 5:帶保持功能的寄存器
always @(posedge clk or posedge reset) beginif (reset)q <= 1'b0;else if (load)q <= d;         // 加載新數據elseq <= q;         // 保持原數據(等價于不操作)
end

5. 無限循環的?always?塊

用途:生成時鐘信號(僅用于仿真)。

示例 6:時鐘生成
reg clk;
always #5 clk = ~clk;  // 生成10個時間單位周期的時鐘(50%占空比)

6. 敏感列表的注意事項

  1. 組合邏輯必須包含所有輸入

// 錯誤示例:敏感列表遺漏b,可能導致仿真錯誤
always @(a) beginout = a & b;  // 當b變化時,out不會更新
end// 正確寫法:
always @(a or b) begin ... end  // 或使用 @(*)

時序邏輯通常僅對時鐘邊沿敏感:?

// 同步復位的正確寫法
always @(posedge clk) beginif (reset) ...
end// 異步復位的寫法(復位信號獨立觸發)
always @(posedge clk or posedge reset) beginif (reset) ...
end

7. 阻塞賦值和非阻塞賦值類型對比

特性阻塞賦值(=)非阻塞賦值(<=)
執行順序立即執行,按順序執行并行執行,在時間步結束時更新
適用場景組合邏輯時序邏輯
硬件對應邏輯門觸發器 / 寄存器

?image

十九、function

用于定義可重復使用的組合邏輯單元,類似于軟件中的函數。它接收輸入參數,執行計算,并返回單個結果。

1.?function?的基本定義

function [返回值位寬] 函數名;input [參數位寬] 參數1;input [參數位寬] 參數2;// 局部變量聲明reg [位寬] 變量名;// 函數體begin// 計算邏輯函數名 = 表達式;  // 將結果賦給函數名本身end
endfunction
  • 特點
    • 組合邏輯:函數內不能包含時序控制(如?#延遲@事件)。
    • 立即返回:執行完畢后立即返回結果。
    • 單一返回值:通過函數名本身賦值返回結果。

2. 簡單函數示例

?示例 1:計算兩個數的和

function [7:0] add_numbers;input [7:0] a;input [7:0] b;
beginadd_numbers = a + b;  // 返回a和b的和
end
endfunction

調用方式

result = add_numbers(10, 20);  // result = 30

示例 2:判斷奇偶性?

function bit is_odd;input [7:0] num;
beginis_odd = (num % 2 == 1);  // 返回1(奇數)或0(偶數)
end
endfunction

調用方式:??

 result = is_odd(number);  // result = 1'b1

3. 帶局部變量的函數

function [7:0] max_of_three;input [7:0] a, b, c;reg [7:0] temp;  // 局部變量
begintemp = (a > b) ? a : b;max_of_three = (temp > c) ? temp : c;  // 返回三者中的最大值
end
endfunction

調用方式:?

max_value = max_of_three(a, b, c);  // max_value = 25

?4. 多維數組作為參數

function [7:0] sum_array;input [7:0] array [0:3];  // 4元素的數組參數reg [7:0] i, sum;
beginsum = 0;for (i = 0; i < 4; i = i + 1) beginsum = sum + array[i];endsum_array = sum;  // 返回數組元素的和
end
endfunction

?調用方式

  initial begin// 初始化數組元素my_array[0] = 8'd10;my_array[1] = 8'd20;my_array[2] = 8'd30;my_array[3] = 8'd40;// 調用函數計算數組總和result = sum_array(my_array);  // result = 100 (8'd100)

5. 函數的遞歸調用

// 計算階乘(n!)
function [31:0] factorial;input [7:0] n;
beginif (n == 0)factorial = 1;elsefactorial = n * factorial(n-1);  // 遞歸調用
end
endfunction

??調用方式

module test_factorial;reg [7:0] input_n;     // 輸入值reg [31:0] result;     // 存儲結果initial begininput_n = 5;       // 計算 5!// 調用函數result = factorial(input_n);  // result = 120 (5! = 120)$display("%d的階乘是: %d", input_n, result);  // 輸出: 120end

二十、task:

????????用于定義可復用的代碼塊,類似于function,但功能更強大。與function只能實現組合邏輯不同,task可以包含時序控制(如延時、事件觸發),支持多輸出參數,且不要求立即返回結果。

1.?task的基本定義

task 任務名;input [位寬] 輸入參數1;    // 輸入參數(可選)output [位寬] 輸出參數1;   // 輸出參數(可選)inout [位寬] 雙向參數1;    // 雙向參數(可選)reg [位寬] 局部變量;       // 局部變量(可選)// 任務體begin// 可包含時序控制和過程化語句#延遲;                 // 延時語句@(事件);               // 事件觸發wait(條件);            // 等待條件滿足// 邏輯操作輸出參數1 = 表達式;     // 賦值給輸出參數end
endtask
  • 特點
    • 時序支持:可包含#延遲@事件wait等時序控制語句。
    • 多參數傳遞:通過outputinout參數返回多個值。
    • 過程化執行:任務內的語句按順序執行。

2. 簡單任務示例

示例 1:帶延時的信號生成
task generate_pulse;input [7:0] width;  // 脈沖寬度(時間單位)output pulse;       // 輸出脈沖信號
beginpulse = 1'b1;       // 脈沖置高#width;             // 保持width個時間單位pulse = 1'b0;       // 脈沖置低
end
endtask

調用方式

reg my_pulse;
generate_pulse(10, my_pulse);  // 生成寬度為10的脈沖
示例 2:帶輸入輸出的任務
task add_numbers;input [7:0] a, b;   // 輸入兩個數output [8:0] sum;   // 輸出和(9位以避免溢出)
beginsum = a + b;        // 計算和
end
endtask

?調用方式

reg [7:0] x = 5, y = 10;
reg [8:0] result;
add_numbers(x, y, result);  // result = 15 (9'd15)

?3. 包含時序控制的任務

task wait_and_check;input signal;       // 待監測的信號input [7:0] timeout; // 超時時間output success;     // 檢查結果(成功/失敗)
beginsuccess = 1'b0;     // 默認失敗// 等待信號變高或超時forkbegin@(posedge signal);  // 等待信號上升沿success = 1'b1;     // 成功endbegin#timeout;           // 超時等待endjoin_anydisable fork;       // 終止未完成的線程
end
endtask

調用方式

reg flag, check_result;
wait_and_check(flag, 100, check_result);  // 等待flag上升沿,最多100個時間單位

4. 在模塊中調用任務

module test_task;reg clk, reset, enable;reg [7:0] data_in, data_out;initial begin// 初始化信號clk = 0;reset = 1;enable = 0;// 調用任務initialize_system();  // 初始化系統generate_clock(10);   // 生成周期為10的時鐘// 執行操作#50;reset = 0;  // 釋放復位#20;process_data(8'd42, data_out);  // 處理數據end// 任務定義task initialize_system;begin// 系統初始化操作reset = 1;enable = 0;#20;  // 保持復位20個時間單位endendtasktask generate_clock;input period;beginforever begin#(period/2) clk = ~clk;  // 生成時鐘endendendtasktask process_data;input [7:0] input_data;output [7:0] output_data;begin@(posedge clk);  // 等待時鐘上升沿if (!reset && enable) begin// 數據處理邏輯output_data = input_data * 2;endendendtask
endmodule

    函數與任務(task)的對比

    特性函數(function)任務(task)
    返回值必須有一個返回值(通過函數名賦值)可以沒有返回值,或通過 output 參數返回
    時序控制不能包含(如?#@wait可以包含時序控制語句
    調用可在表達式中直接調用必須單獨作為一條語句調用
    適用場景組合邏輯計算時序邏輯或復雜操作

    本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
    如若轉載,請注明出處:http://www.pswp.cn/pingmian/87291.shtml
    繁體地址,請注明出處:http://hk.pswp.cn/pingmian/87291.shtml
    英文地址,請注明出處:http://en.pswp.cn/pingmian/87291.shtml

    如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

    相關文章

    26-計組-存儲器與Cache機制

    一、存儲器與局部性原理 1. 局部性原理 基礎概念&#xff1a; 時間局部性&#xff1a;一個存儲單元被訪問后&#xff0c;短時間內可能再次被訪問&#xff08;例如循環變量&#xff09;。空間局部性&#xff1a;一個存儲單元被訪問后&#xff0c;其附近單元可能在短時間內被訪…

    I/O 線程 7.3

    前言 以下&#xff1a; 概述 1.基礎 2.代碼演示 3.練習 4.分析題 1.基礎 一、線程基礎概念 并發執行原理 通過時間片輪轉實現多任務"并行"效果 實際為CPU快速切換執行不同線程 線程 vs 進程 線程共享進程地址空間&#xff0c;切換開銷更小 進程擁有獨立資源&am…

    MySQL JSON數據類型完全指南:從版本演進到企業實踐的深度對話

    &#x1f4ca; MySQL JSON數據類型完全指南&#xff1a;從版本演進到企業實踐的深度對話 在當今數據驅動的時代&#xff0c;MySQL作為最受歡迎的關系型數據庫之一&#xff0c;不斷演進以滿足現代應用的需求。JSON數據類型的引入&#xff0c;讓MySQL在保持關系型數據庫優勢的同時…

    BI × 餐飲行業 | 以數據應用重塑全鏈路業務增長路徑

    在競爭激烈的餐飲行業中&#xff0c;數據已成為企業保持競爭力的關鍵資產。通過深入分析顧客數據&#xff0c;餐飲企業能夠洞察消費者的需求和偏好&#xff0c;從而提供更加精準和個性化的服務。此外&#xff0c;利用數據優化業務管理&#xff0c;降低成本&#xff0c;并提高運…

    【學習線路】機器學習線路概述與內容關鍵點說明

    文章目錄 零、機器學習的企業價值一、基礎概念1. 機器學習定義2. 學習類型3. 學習范式 二、核心算法與技術1. 監督學習2. 無監督學習3. 模型評估與優化 三、深度學習與神經網絡1. 神經網絡基礎2. 深度學習框架3. 應用場景 四、工具與實踐1. 數據處理2. 模型部署3. 機器學習的生…

    Linux 命令:cp

    Linux cp 命令詳細教程 cp 是 Linux 系統中最常用的命令之一&#xff0c;用于復制文件或目錄。它可以將源文件/目錄復制到指定的目標位置&#xff0c;支持批量復制、強制覆蓋、保留文件屬性等功能。下面詳細介紹其用法。資料已經分類整理好&#xff1a;https://pan.quark.cn/s…

    java分頁插件| MyBatis-Plus分頁 vs PageHelper分頁:全面對比與最佳實踐

    MyBatis-Plus分頁 vs PageHelper分頁&#xff1a;全面對比與最佳實踐 一、分頁技術概述 在Java持久層框架中&#xff0c;分頁是高頻使用的功能。主流方案有&#xff1a; MyBatis-Plus分頁&#xff1a;MyBatis增強工具的內置分頁方案PageHelper分頁&#xff1a;獨立的MyBatis…

    PROFINET轉MODBUS TCP網關在機械臂通信操作中的應用研究

    在特定的汽車零部件生產工廠焊接生產線上&#xff0c;機械臂被應用于焊接作業&#xff0c;其控制體系基于Profinet協議。同時&#xff0c;工廠的自動化控制體系以西門子S7-1200PLC為核心&#xff0c;通過ModbusTCP協議實現數據交換。為實現焊接過程的自動化控制以及生產數據的實…

    Mac中如何Chrome禁用更新[update chflags macos]

    寫在前面 在 macOS 系統中&#xff0c;系統更新提示的小紅點常常讓人不勝其擾。 尤其是當你希望保持現有系統的穩定性&#xff0c;或因兼容性問題暫不想升級時&#xff0c;這個小紅點就像一個頑固的提醒。 - windowsMac版直接刪除更新程序, 有效 cd ~/Library/Google/Googl…

    LoRA使用-多個LoRA

    LoRA的風格分類 不用去記它有什么很特別的風格&#xff0c;簡單來說基礎模型就像一個全能畫手&#xff0c;什么都能畫&#xff0c;而LoRA是在某個風格中經過特訓的它的一個分身。使得它更精通該風格。 關于LoR風格分類&#xff1a;提示詞撰寫公式 Checkpoint&LoRA對比 訓…

    牛客刷題 — 【排序】[NOIP2012] 國王的游戲(高精度結構體排序)

    1.題面&#xff1a;傳送門 2. 思路&#xff1a; 相鄰的兩個大臣的先后順序只會互相影響&#xff0c;并不會影響其他人的金幣數。 假設前 i-1 個人左手上的數乘積為 s 。 ① 若 A 大臣排在B 大臣的前面&#xff0c;則&#xff1a; s 此時的金幣數最大值為 。 ② 若B大臣排…

    grpc 和限流Sentinel

    基于gRPC的微服務通信模塊技術方案書 1. 總體架構設計 #mermaid-svg-TiN9cudEfW5mCWHm {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-TiN9cudEfW5mCWHm .error-icon{fill:#552222;}#mermaid-svg-TiN9cudEfW5mCWHm…

    經典灰狼算法+編碼器+雙向長短期記憶神經網絡,GWO-Transformer-BiLSTM多變量回歸預測,作者:機器學習之心!

    經典灰狼算法編碼器雙向長短期記憶神經網絡&#xff0c;GWO-Transformer-BiLSTM多變量回歸預測&#xff0c;作者&#xff1a;機器學習之心&#xff01; 目錄 經典灰狼算法編碼器雙向長短期記憶神經網絡&#xff0c;GWO-Transformer-BiLSTM多變量回歸預測&#xff0c;作者&#…

    VGG Image Annotator (VIA):一款免費的數據標注軟件介紹與使用

    VGG Image Annotator (VIA)&#xff1a;一款免費的數據標注軟件介紹與使用 在計算機視覺領域&#xff0c;數據標注是訓練機器學習模型的基礎步驟之一&#xff0c;而標注工具的選擇直接影響標注的效率和準確性。眾多標注工具中&#xff0c;VGG Image Annotator (VIA) 是一個開源…

    CSS實現百分比水柱圖

    背景 在echarts沒發現有可以直接使用的展示百分比的柱形圖,只好自己封裝一個組件使用 實現思路 一、圖形拆解 要實現的組件是一個 可配置的圓柱形液柱圖組件&#xff0c;常用于展示比例進度&#xff0c;比如任務完成度、指標達成率等。把圖拆成最小單元然后拼接起來&#x…

    詳解 rzsz 工具:Windows 與 Linux 文件傳輸

    &#xff08;Linux之軟件包管理器&#xff08;CentOS系統&#xff09; —— yum-CSDN博客&#xff09;rzsz工具之前我在這篇文章中介紹過&#xff0c;現在重新詳細介紹一下該工具。rzsz 是一個用于在 Windows 和 Linux 系統之間傳輸文件的工具集&#xff0c;通常通過終端模擬器…

    網絡編程1(UDP)

    網絡編程套接字&#xff08;socket api&#xff09; 了解了網絡的一些概念&#xff0c;接下來就要進行網絡中的跨主機通信&#xff0c;了解網絡中的一些API&#xff0c;這里談到的API都是針對傳輸層進行的&#xff0c;這是因為我們編寫的代碼是在應用層&#xff0c;而傳輸層就…

    【電機】定點線性映射

    這是一個定點數線性映射的問題&#xff0c;通常用于將浮點型的物理量&#xff08;如速度、位置、扭矩&#xff09;轉換為嵌入式系統中使用的整型數據格式&#xff0c;便于通過 CAN 總線或其它通信協議發送給電機控制器。 我們來逐步解析這個過程&#xff0c;并以“速度”為例說…

    Spring Cloud 微服務(遠程調用與熔斷機制深度解析)

    &#x1f4cc; 摘要 在微服務架構中&#xff0c;服務之間的遠程調用是構建分布式系統的核心環節。然而&#xff0c;隨著服務數量的增加和網絡復雜度的提升&#xff0c;調用失敗、延遲高、異常等問題變得越來越頻繁。 為此&#xff0c;Spring Cloud 提供了強大的遠程調用組件 …

    electron-vite 抽離config.js

    1、將config.js 放到resources下的config目錄下 module.exports {url: http://192.168.1.17:8000,wsUrl: ws://192.168.1.17:8000, }2、在preload.js 暴露讀取API src/preload/index.js(或你的preload入口) const fs require(fs); const path require(path);function getCo…