本原创教程由芯驿电子科技(上海)有限公司(ALINX)创做,版权归本公司全部,如需转载,需受权并注明出处。node
AXU2CGA/AXU2CGB/AXU3EG/AXU4EV-E/AXU4EV-P/AXU5EV-E/AXU5EV-P /AXU9EG/AXU15EG网络
本文主要介绍verilog基础模块,夯实基础,对深刻学习FPGA会有很大帮助。dom
常量异步
整数:整数能够用二进制b或B,八进制o或O,十进制d或D,十六进制h或H表示,例如, 8’b00001111表示8位位宽的二进制整数,4’ha表示4位位宽的十六进制整数。学习
X和Z:X表明不定值,z表明高阻值,例如,5’b00x11,第三位不定值,3’b00z表示最低位为高阻值。spa
下划线:在位数过长时能够用来分割位数,提升程序可读性,如8’b0000_1111设计
参数parameter: parameter能够用标识符定义常量,运用时只使用标识符便可,提升可读性及维护性,如定义parameter width = 8 ; 定义寄存器reg [width-1:0] a; 即定义了8位宽度的寄存器。3d
参数的传递:在一个模块中若是有定义参数,在其余模块调用此模块时能够传递参数,并能够修改参数,以下所示,在module后用#()表示。code
例如定义模块以下调用模块orm
module rom #( parameter depth =15, parameter width =8 ) ( input[depth-1:0] addr , input[width-1:0] data , output result ); endmodule module top(); wire[31:0] addr ; wire[15:0] data ; wire result ; rom #( .depth(32), .width(16) ) r1 ( .addr(addr), .data(data), .result(result) ); endmodule
Parameter能够用于模块间的参数传递,而localparam仅用于本模块内使用,不能用于参数传递。Localparam多用于状态机状态的定义。
变量
变量是指程序运行时能够改变其值的量,下面主要介绍几个经常使用了变量类型
1.Wire 型
Wire 类型变量,也叫网络类型变量,用于结构实体之间的物理链接,如门与门之间,不能储存值,用连续赋值语句assign赋值,定义为wire [n-1:0] a ; 其中n表明位宽,如定义wire a ; assign a = b ; 是将b的结点链接到连线a上。以下图所示,两个实体之间的连线便是wire类型变量。
2.Reg 型
Reg 类型变量,也称为寄存器变量,可用来储存值,必须在always语句里使用。其定义为
reg [n-1:0] a ; 表示n位位宽的寄存器,如reg [7:0] a; 表示定义8位位宽的寄存器a。以下所示定义了寄存器q,生成的电路为时序逻辑,右图为其结构,为D触发器。
module top(d, clk, q); input d ; input clk ; outputreg q ; always@(posedge clk) begin q <= d ; end endmodule
也能够生成组合逻辑,如数据选择器,敏感信号没有时钟,定义了reg Mux,最终生成电路为组合逻辑。
module top(a, b, c, d, sel, Mux); input a ; input b ; input c ; input d ; input[1:0] sel ; outputreg Mux ; always@(sel or a or b or c or d) begin case(sel) 2'b00: Mux = a ; 2'b01: Mux = b ; 2'b10: Mux = c ; 2'b11: Mux = d ; endcase end endmodule
3.Memory型
能够用memory类型来定义RAM,ROM等存储器,其结构为reg [n-1:0] 存储器名[m-1:0],意义为m个n位宽度的寄存器。例如,reg [7:0] ram [255:0]表示定义了256个8位寄存器,256也便是存储器的深度,8为数据宽度。
运算符可分为如下几类:
算术运算符
“+”(加法运算符),”-“(减法运算符),”*”(乘法运算符),”/”(除法运算符,如7/3 =2),“%”(取模运算符,也即求余数,如7%3=1,余数为1)
赋值运算符
“=”阻塞赋值,”<=”非阻塞赋值。阻塞赋值为执行完一条赋值语句,再执行下一条,可理解为顺序执行,并且赋值是当即执行;非阻塞赋值可理解为并行执行,不考虑顺序,在always块语句执行完成后,才进行赋值。以下面的阻塞赋值:
代码以下:激励文件以下
module top(din,a,b,c,clk); input din; input clk; outputreg a,b,c; always@(posedge clk) begin a = din; b = a; c = b; end endmodule `timescale1 ns/1 ns module top_tb(); reg din ; reg clk ; wire a,b,c ; initial begin din =0; clk =0; forever begin #({$random}%100) din =~din ; end end always#10 clk =~clk ; top t0(.din(din),.a(a),.b(b),.c(c),.clk(clk)); endmodule
能够从仿真结果看到,在clk的上升沿,a的值等于din,并当即赋给b,b的值赋给c。
若是改成非阻塞赋值,仿真结果以下,在clk上升沿,a的值没有当即赋值给b,b为a原来的值,一样,c为b原来的值
能够从二者的RTL图看出明显不一样:
阻塞赋值RTL图非阻塞赋值RTL图
通常状况下,在时序逻辑电路中使用非阻塞赋值,可避免仿真时出现竞争冒险现象;在组合逻辑中使用阻塞赋值,执行赋值语句后当即改变;在assign语句中必须用阻塞赋值。
用于表示两个操做数之间的关系,如a>b,a<b,多用于判断条件,例如:
If (a>=b) q <=1’b1 ; else q <= 1’b0 ;表示若是a的值大于等于b的值,则q的值为1,不然q的值为0 |
“&&”(两个操做数逻辑与),”||”(两个操做数逻辑或),”!”(单个操做数逻辑非)例如:
If (a>b && c <d) 表示条件为a>b而且c<d; if (!a)表示条件为a的值不为1,也就是0。
“?:”为条件判断,相似于if else,例如assign a = (i>8)?1’b1:1’b0 ;判断i的值是否大于8,若是大于8则a的值为1,不然为0。
“~”按位取反,”|”按位或,”^”按位异或,”&”按位与,”^”按位同或,除了”~”只须要一个操做数外,其余几个都须要两个操做数,如a&b,a|b。具体应用在后面的组合逻辑一节中有讲解。
“<<”左移位运算符,”>>”右移位运算符,如a<<1表示,向左移1位,a>>2,向右移两位。
“{ }”拼接运算符,将多个信号按位拼接,如{a[3:0], b[1:0]},将a的低4位,b的低2位拼接成6位数据。另外,{n{a[3:0]}}表示将n个a[3:0]拼接,{n{1’b0}}表示n位的0拼接。如{8{1’b0}}表示为8’b0000_0000.
各类运算符的优先级别以下:
本节主要介绍组合逻辑,组合逻辑电路的特色是任意时刻的输出仅仅取决于输入信号,输入信号变化,输出当即变化,不依赖于时钟。
在verilog中以“&”表示按位与,如c=a&b,真值表以下,在a和b都等于1时结果才为1,RTL表示如右图
代码实现以下:激励文件以下:
module top(a, b, c); input a ; input b ; output c ; assign c = a & b ; endmodule `timescale1 ns/1 ns module top_tb(); reg a ; reg b ; wire c ; initial begin a =0; b =0; forever begin #({$random}%100) a =~a ; #({$random}%100) b =~b ; end end top t0(.a(a),.b(b),.c(c)); endmodule
仿真结果以下:
若是a和b的位宽大于1,例如定义input [3:0] a, input [3:0]b,那么a&b则指a与b的对应位相与。如a[0]&b[0],a[1]&b[1]。
在verilog中以“|”表示按位或,如c = a|b , 真值表以下,在a和b都为0时结果才为0。
代码实现以下:激励文件以下
module top(a, b, c); input a ; input b ; output c ; assign c = a | b ; endmodule `timescale1 ns/1 ns module top_tb(); reg a ; reg b ; wire c ; initial begin a =0; b =0; forever begin #({$random}%100) a =~a ; #({$random}%100) b =~b ; end end top t0(.a(a),.b(b),.c(c)); endmodule
仿真结果以下:
同理,位宽大于1,则是按位或。
在verilog中以“~”表示按位取反,如b=~a,真值表以下,b等于a的相反数。
代码实现以下:激励文件以下:
module top(a, b); input a ; output b ; assign b =~a ; endmodule `timescale1 ns/1 ns module top_tb(); reg a ; wire b ; initial begin a =0; forever begin #({$random}%100) a =~a ; end end top t0(.a(a),.b(b)); endmodule
仿真结果如以下:
在verilog中以“^”表示异或,如c= a^b ,真值表以下,当a和b相同时,输出为0。
代码实现以下:激励文件以下:
module top(a, b, c); input a ; input b ; output c ; assign c = a ^ b ; endmodule `timescale1 ns/1 ns module top_tb(); reg a ; reg b ; wire c ; initial begin a =0; b =0; forever begin #({$random}%100) a =~a ; #({$random}%100) b =~b ; end end top t0(.a(a),.b(b),.c(c)); endmodule
仿真结果以下:
在verilog中以大于“>”,等于”==”,小于”<”,大于等于”>=”,小于等于”<=”,不等于”!=”表示,以大于举例,如c= a > b ;表示若是a大于b,那么c的值就为1,不然为0。真值表以下:
代码实现以下:激励文件以下:
module top(a, b, c); input a ; input b ; output c ; assign c = a > b ; endmodule `timescale1 ns/1 ns module top_tb(); reg a ; reg b ; wire c ; initial begin a =0; b =0; forever begin #({$random}%100) a =~a ; #({$random}%100) b =~b ; end end top t0(.a(a),.b(b),.c(c)); endmodule
仿真结果以下:
半加器和全加器是算术运算电路中的基本单元,因为半加器不考虑从低位来的进位,因此称之为半加器,sum表示相加结果,count表示进位,真值表可表示以下:
可根据真值表写出代码以下:激励文件以下:
module top(a, b, sum, count); input a ; input b ; output sum ; output count ; assign sum = a ^ b ; assign count = a & b ; endmodule `timescale1 ns/1 ns module top_tb(); reg a ; reg b ; wire sum ; wire count ; initial begin a =0; b =0; forever begin #({$random}%100) a =~a ; #({$random}%100) b =~b ; end end top t0(.a(a),.b(b), .sum(sum),.count(count)); endmodule
仿真结果以下:
而全加器须要加上低位来的进位信号cin,真值表以下:
代码以下:激励文件以下:
module top(cin, a, b, sum, count); input cin ; input a ; input b ; output sum ; output count ; assign{count,sum}= a + b + cin ; endmodule `timescale1 ns/1 ns module top_tb(); reg a ; reg b ; reg cin ; wire sum ; wire count ; initial begin a =0; b =0; cin =0; forever begin #({$random}%100) a =~a ; #({$random}%100) b =~b ; #({$random}%100) cin =~cin ; end end top t0(.cin(cin),.a(a),.b(b), .sum(sum),.count(count)); endmodule
仿真结果以下:
乘法的表示也很简单,利用”*”便可,如a*b,举例代码以下:
module top(a, b, c); input[1:0] a ; input[1:0] b ; output[3:0] c ; assign c = a * b ; endmodule `timescale1 ns/1 ns module top_tb(); reg[1:0]a ; reg[1:0]b ; wire[3:0]c ; initial begin a =0; b =0; forever begin #({$random}%100) a =~a ; #({$random}%100) b =~b ; end end top t0(.a(a),.b(b),.c(c)); endmodule
仿真结果以下:
在verilog中常常会用到数据选择器,经过选择信号,选择不一样的输入信号输出到输出端,以下图真值表,四选一数据选择器,sel[1:0]为选择信号,a,b,c,d为输入信号,Mux为输出信号。
代码以下:激励文件以下:
module top(a, b, c, d, sel, Mux); input a ; input b ; input c ; input d ; input[1:0] sel ; outputreg Mux ; always@(sel or a or b or c or d) begin case(sel) 2'b00: Mux = a ; 2'b01: Mux = b ; 2'b10: Mux = c ; 2'b11: Mux = d ; endcase end endmodule `timescale1 ns/1 ns module top_tb(); reg a ; reg b ; reg c ; reg d ; reg[1:0] sel ; wire Mux ; initial begin a =0; b =0; c =0; d =0; forever begin #({$random}%100) a ={$random}%3; #({$random}%100) b ={$random}%3; #({$random}%100) c ={$random}%3; #({$random}%100) d ={$random}%3; end end initial begin sel =2'b00; #2000 sel =2'b01; #2000 sel =2'b10; #2000 sel =2'b11; end top t0(.a(a),.b(b),.c(c),.d(d),.sel(sel), .