歡迎大家關注我的微信公眾賬號,支持程序媛寫出更多優秀的文章
Verilog中總共有十九種數據類型,我們先介紹四個最基本的數據類型,他們是:
reg型、wire型、integer型、parameter型
1 常量
1.1 數字integer
整數:b二進制 d十進制 h十六進制 o八進制
表達方式:<位寬=default><進制=d><數字>
Eg. 8‘b10100100,2'h0a3,3'o455,4’d2435
注意,當僅有位寬被忽略時,即'b, 'd, 'o'等形式,數據默認位寬為當前機器的字節寬度,常為32位。
X與Z值:x代表不定值,z代表高阻值
可以用於定義當前進制數的1位(如h下可表達1位十六進制數)。
負數:位寬前加減號
下划線:分割數的表達,提高可讀性,無意義
1.2 參數parameter
定義一個標識符代表一個常量,即標識符形式的常量。提高可讀性。格式如下:
parameter para1=3'b010, para2=4'd1432,...,paran=2'h6a;
parameter ave_delay = (r+f)/2;
常用於定義延遲時間和變量寬度,以及改變在被引用模塊或實例中已定義的參數。如:
1 module Decode(A,F); 2 parameter Width=1, Polarity=1; 3 ... 4 endmodule 5 6 module Top; 7 wire[3:0] A4; 8 wire[4:0] A5; 9 wire[15:0] F16; 10 wire[31:0] F32; 11 Decode #(4,0) D1(A4,F16);//w=4,p=0 12 Decode #(5) D2(A5,F32);//w=5 13 endmodule
在實例時使用 #() 的方式來更改引用模塊參數。
2 變量
2.1 net(default)
網絡數據類型net表示結構實體(如門)之間的物理連接,它不能儲存值,而且必須受到驅動器的驅動。如無驅動器連接,則呈現高阻Z態。
wire(default)
單門驅動或連續賦值語句驅動的網絡型數據。
常用來表示以assign關鍵字指定的組合邏輯信號。
tri
多驅動器驅動的網絡型數據。
(多驅動源下,若無定義邏輯強度,邏輯值會發生沖突產生不確定值X)
1 wire [n-1:0] name1, name2, ... , namei; 2 wire [n:1] name1, name2, ... , namei; 3 wire name;
2.2 register
寄存器是數據儲存單元的抽象,通過賦值語句可以改變寄存器儲存的值,作用與改變觸發器儲存的值相當。
常用來表示always塊內的指定信號,代表觸發器。
always塊中被賦值的每一個信號都必須定義成reg型。
reg被賦值如同一組觸發器存儲單元的值被改變。
1 reg [n-1:0] name1, name2, ... , namei; 2 reg [n:1] name1, name2, ... , namei; 3 reg rega;
默認初始值為x。可以賦正負值,但當該reg是一個表達式中的操作數時,被作為無符號數處理。
reg型只表示被定義的信號將用在always塊內,雖常為寄存器、觸發器的輸出,但並非總是如此。
2.3 memory
Verilog通過建立reg型變量的數組來對存儲器進行建模,描述RAM/ROM型存儲器和reg文件。
Verilog中不存在多維數組,memory型數據通過擴展reg型數據的地址范圍來生成。
1 reg [n-1:0] mem1[m-1:0]; 2 3 reg [n-1:0] mem2[m:1]; 4 5 reg [7:0] mem[255:0]; //定義了一個名為mem 的存儲器,該存儲器擁有 256個 數據位寬為8 存儲器,地址范圍是從0到255 6 7 reg [n-1:0] rega; // rega 是一個n位的寄存器 8 rega = 0; // rega 可以由一個賦值語句賦值 9 reg mema[n-1:0]; // mema 是一個由n個1位寄存器單元構成的存儲器 10 mema[0] = 0; 11 mema[1] = 0; 12 ... 13 mema[n-1] = 0; // mema 必須一個一個單元地賦值
如果想對memory中的存儲單元進行讀寫操作,必須指定該單元在存儲器中的地址。
3 基本運算符號
按操作數個數: 有單目、雙目、三目運算符,分別可帶一個、兩個、三個操作數。
按功能:
1) 算術運算符+、-、×、/、%
加、減、乘、除、求余
整數除法結果值略去小數部分,取模運算符號位采用模運算式中第一個操作數的符號位。
2) 賦值運算符=、<=
同一個always塊中,只能全使用阻塞賦值或全使用非阻塞賦值。
* 非阻塞賦值<=:當前語句的執行不會阻塞下一語句的執行。
在塊語句結束時才完成賦值操作,塊內的賦值語句同時賦值。
可以看作兩個步驟的過程:
賦值時刻開始時,計算非阻塞賦值右操作數表達式。
賦值時刻結束時,更新非阻塞賦值左操作數。
1 reg a=1, b=2, c=3, d=4; 2 always @(posedge clk) 3 { 4 a <= b; 5 b <= c; 6 c <= d; 7 }
並行,電路實現往往與觸發沿有關,常被綜合成時序邏輯電路。
* 阻塞賦值=:完成當前語句后才能做下一句的操作
在該語句結束時就完成賦值操作,塊內的阻塞賦值語句順序執行。
順序執行,一般不能設定有延遲,常被綜合成組合邏輯電路。
3)關系運算符>、<、>=、<=
4)邏輯運算符&&、||、!
&&和 || 是雙目運算符,優先級低於算術運算符
! 是單目運算符,優先級高於算術運算符
1 (a>b) && (x>y) 相當於 a>b && x>y 2 (a==b) || (x==y) 相當於 a==b || x==y 3 (!a) || (a>b) 相當於 !a || a>b
5)條件運算符 ? :
6)位運算符~、|、^、&、^~
取反、或、異或、與、同或
1 // 除相應雙目位運算外還可用作單目運算符縮減運算 2 3 reg [3:0] A = 0101; 4 reg B; 5 B = &A; 6 // 相當於B = 0 & 1 & 0 & 1 7 // 即將A的所有位進行位運算
7)移位運算符<<、>>
a>>n; // 將操作數a右移n位,去尾,縮小
a<<n; // 將操作數a左移n位,補0 ,放大
8)拼接運算符{ }
把兩個/多個信號的某些位拼接起來運算。
1 a = 1'b0; 2 b = 8'b11101100; 3 c = 1'b1; 4 5 //用法1 6 r = {a, b[3:0], c, 3'b101}; 7 //此時r = 0 1100 1 101 8 9 //用法2 10 r = {4{a}}; 11 //此時r = 0000 12 //嵌套用法 13 r = {b[7:5], {3{c,a}}}; 14 //此時r = 111 101010
易混知識點:
位運算符:按位進行運算,原來的操作數有幾位,結果就有幾位,若2個操作數位數不同,則位短的數據左端會自動補0
邏輯運算符:如果操作數是多位的,則將操作數看作整體,若操作數中每一位都是0值,則為邏輯0值,若操作數中有1,則為邏輯1值
4 塊語句
4.1 順序塊
塊內語句順序執行,上一條語句行完畢后,下一條語句才能執行
每條語句的延遲時間是相對於前一條語句的仿真時間而言的(也就是說,順序塊內一條語句的延遲時間是指從前一條語句仿真完畢到當前語句仿真完畢的間隔)
直到最后一條語句執行完,程序流程控制才跳出該語句塊。
1 begin 2 語句1; 3 語句2; 4 end 5 6 begin:block_name 7 assignments; 8 語句1; 9 語句2; 10 end
4.2 並行塊
1)塊內語句同時執行,程序流程控制一進入到該並行塊,塊內語句則開始同時並行地執行,
2)塊內每條語句的延遲時間是相對於程序流程控制進入到塊內的仿真時間的(也就是說,並行塊內一條語句的延遲時間是指從程序流程控制進入到塊內到該條語句執行完畢的間隔;這個延遲時間是用來給賦值語句提供執行時序的),
3)當按延遲時間的時序中排在最后的語句執行完畢或一個disable語句執行時,程序流程控制跳出該程序塊。
1 fork 2 語句1; 3 語句2; 4 join 5 6 fork:塊名 7 assignments; 8 語句1; 9 語句2; 10 end
4.3 生成塊
generate生成塊的本質是使用循環內的一條語句來代替多條重復的Verilog語句,簡化用戶的編程
用法:
1. generate 語法有 generate for 、genreate if 和 generate case 三種
2. generate for 語句必須有 genvar 關鍵字定義 for 的變量
3. for 的內容必須加 begin 和 end
4. 必須給 for 語段起個名字
1 1. generate for例子: 2 generate 3 genvar i; //generate 8 samll fifo for in_data[i] 8X72 4 for(i=0; i<NUM_QUEUES; i=i+1) 5 begin: in_arb_queues //NUM_QUEUES = 8 6 small_fifo 7 #( .WIDTH(DATA_WIDTH+CTRL_WIDTH), .MAX_DEPTH_BITS(2)) 8 in_arb_fifo 9 (// Outputs 10 .dout ({fifo_out_ctrl[i], fifo_out_data[i]}), 11 .full (), 12 .nearly_full (nearly_full[i]), 13 .prog_full (), 14 .empty (empty[i]), 15 // Inputs 16 .din ({in_ctrl[i], in_data[i]}), 17 .wr_en (in_wr[i]), 18 .rd_en (rd_en[i]), 19 .reset (reset), 20 .clk (clk)); 21 end // block: in_arb_queues 22 endgenerate 23 24 2.generate if例子: 25 generate 26 if (REG_WIDTH == WRITE_WIDTH) 27 begin : new_data_a_generation 28 assign new_data_a = merge_update ? merge_wr_data : held_wr_data_a; 29 end 30 else begin 31 assign new_data_a = merge_update ? 32 {{(REG_WIDTH - WRITE_WIDTH - 1){merge_wr_data_sign}}, merge_wr_data} : 33 {{(REG_WIDTH - WRITE_WIDTH){held_wr_data_sign_a}}, held_wr_data_a}; 34 end 35 endgenerate 36 37 3.generate還可以進行多個assign賦值! 38 module anytest_v( 39 input clk, 40 input[7:0] datain, 41 output[7:0] dataout, 42 output finish 43 ); 44 45 wire[7:0] mem[31:0]; 46 wire[32*8-1:0] xxx; 47 //reg[7:0] i; 48 49 generate 50 genvar i; 51 for(i=0;i<=31;i=i+1) 52 begin :wiertech 53 assign mem[i]= 8'b0; 54 end 55 endgenerate 56 57 endmodule