欢迎大家关注我的微信公众账号,支持程序媛写出更多优秀的文章
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