一: 基础知识:
- verilog一个字符需要8bit
- wire 类型表示硬件单元之间的物理连线,由其连接的器件输出端连续驱动。如果没有驱动元件连接到 wire 型变量,缺省值一般为 “Z”。
- 寄存器(reg)用来表示存储单元,它将保持数据的原始值,直到被重写。
- 位宽大于 1 可以用向量表示:reg [3:0] counter ;
- Verilog 支持可变向量域选择:byte1[j] = data1[(j 1)8-1 : j8];
- [bit : width] : 从起始 bit 位宽为 width。
- [bit-: width] : 从起始 bit 位宽为 width。
- 数据拼接:temp1 = {byte1[0][7:0], data1[31:8]};
- 实数用 real 可以用十进制或科学计数法来表示:real data1=3.75
- 整数用 integer 声明位宽与编译器有关,一般为32 bit。
- reg 型变量为无符号数, integer 变量为符号数。
- time 变量宽度一般为 64 bit,通过 $time 获取当前的仿真时间:time current_time= $time
- Verilog 中允许声明 reg, wire, integer, time, real 数组及其向量类型。变量的右侧是维度,左侧是宽度
integer flag [7:0] ; 数组由//8个整数组成 reg [3:0] counter [3:0] ; //由4个4bit计数器组成的数组 wire [7:0] addr_bus [3:0] ; //由4个8bit wire由类型变量组成的数组 wire data_bit[7:0][5:0] ; //声明1bit wire类型变量的二维数组 reg [31:0] data_4d[11:0][3:0][3:0][255:0] ; 声明4维32bit数据变量数组 //数据操作如下: flag [1] = 32'd0 ; //将flag第二组元素赋值32bit的0值 counter[3] = 4'hF ; //将数组counter第四个元素的值赋值为4bit 十六进制数F,等效于counter[3][3:0] = 4'hF,可以省略宽度; assign addr_bus[0] = 8'b0 ; /将数组addr_bus中第一个元素的值赋值为0
assign data_bit[0][1] = 1'b1; //将数组data_bit的第1行第2列的元素赋值为1,这里不能省略第二个访问标号,即 assign data_bit[0] = 1'b1; 是非法的。
data_4d[0][0][0][0][15:0] = 15'd3 ; //将数组data_4d中标号为[0][0][0][0]的寄存器单元的15~0bit赋值为3
- parameter、local parameter、
define:
define全局有效,且在编译的时候替换的。parameter 、localparam 只在定义的本模块内有效。 两者的区别是 parameter 可以进行参数例化,而 localparam 则不可以 - 字符串类型:reg [0: 14*8-1] str= “run.runoob.com”;
- a^b:a 异或 b 。 同或~ + ^.
- 逻辑相等 " == " 逻辑不等 “!=”
- 全相等 “===” : 正常结果有 2 种:为真(1)或假(0) 不全等 “!= =”:全等比较时,如果按位比较有相同的 x 或 z,返回结果也可以为 1,即全等比较可比较 x 或 z。所以,全等比较的结果一定不包含 x。
- 算术左移(<<<),算术右移(>>>):算术右移时,左边高位会补充符号位,以保证数据缩小后值的正确性。其余都是0补位。可以利用算是右移进行有符号数的除法:把一个数右移n位,相当于除以该数2的n次方:
A = 4'b1100 ;
B = 4'b0010 ;
C = B + (A>>>2); //结果为 2 + (-4/4) = 1, 4'b0001
-
条件表达式有 3 个操作符,结构描述如下:A ? B : C
-
`timescale time_unit /time_precision time_unit 表示时间单位,time_precision 表示时间精度 时间精度大小不能超过时间单位大小
-
`default_nettype:该指令用于为隐式的线网变量指定为线网类型,即将没有被声明的连线定义为线网类型。
-
resetall:该编译器指令将所有的编译指令重新设置为缺省值: 1、resetall 可以使得缺省连线类型为线网类型。 2、当 resetall 加到模块最后时,可以将当前的 timescale 取消防止进一步传递,只保证当前的 timescale 在局部有效,避免 `timescale 的错误继承。
-
celldefine, endcelldefine: 用于将模块标记为单元模块
关于连续赋值:assign
1、assign LHS_target = RHS_expression ;
- LHS_target 必须是一个标量或者线型向量,而不能是寄存器类型
- RHS_expression 的类型没有要求,可以是标量或线型或存器向量,也可以是函数调用
- 只要 RHS_expression 表达式的操作数有事件发生(值的变化)时,RHS_expression 就会立刻重新计算,同时赋值给 LHS_target
关于时延:Verilog 时延
- 普通时延,A&B计算结果延时10个时间单位赋值给Z
wire Z, A, B ;
assign #10 Z = A & B ;
- 隐式时延,声明一个wire型变量时对其进行包含一定时延的连续赋值。
wire A, B;
wire #10 Z = A & B;
- 声明时延,声明一个wire型变量是指定一个时延。因此对该变量所有的连续赋值都会被推迟到指定的时间。除非门级建模中,一般不推荐使用此类方法建模。
wire A, B;
wire #10 Z ;
assign Z =A & B
惯性时延
Z 获取新的值之前,A 或 B 任意一个值又发生了变化,那么计算 Z 的新值时会取 A 或 B 当前的新值
过程结构
过程结构语句有 2 种:initial 与 always,不可相互嵌套。但是 initial 语句或 always 语句内部可以理解为是顺序执行的(非阻塞赋值除外)。
阻塞&非阻塞赋值
- Verilog 代码设计时,切记不要在一个过程结构中混合使用阻塞赋值与非阻塞赋值
- 更多时候,在设计电路时,always 时序逻辑块中多用非阻塞赋值,always 组合逻辑块中多用阻塞赋值;在仿真电路时,initial 块中一般多用阻塞赋值。
- 使用非阻塞赋值可以避免竞争冒险
Verilog 时序控制
- 时延控制:时延可以是数字、标识符或者表达式
- 边沿触发事件控制:@(敏感信号表)、触发信号用 ->、@(*)、@(posedge clk)、@(negedge clk)
- 电平敏感事件控制: wait ( )
case分支语句
case(case_expr)
condition1 : true_statement1 ;
condition2 : true_statement2 ;
……
default : default_statement ;
endcase
- case支持嵌套
- casex/casez 语句:用来表示条件选项中的无关项。
casez(sel)
4'b???1: sout_t = p0 ;
4'b??1?: sout_t = p1 ;
4'b?1??: sout_t = p2 ;
4'b1???: sout_t = p3 ;
default: sout_t = 2'b0 ;
endcase
Verilog 循环语句
- while,
- for,
- repeat,
- forever
过程连续赋值
- assign,deassign:取消过程赋值操作:赋值对象只能是寄存器或寄存器组,而不能是 wire 型变量。
- force, release:赋值对象可以是 reg 型变量,也可以是 wire 型变量。
Verilog 带参数例化
- defparam: 通过模块层次调用的方法,来改写低层次模块的参数值
defparam u_ram_4x4.MASK = 7 ;
module ram_4x4
(
input CLK ,
input [4-1:0] A ,
input [4-1:0] D ,
input EN ,
input WR , //1 for write and 0 for read
output reg [4-1:0] Q );
parameter MASK = 3 ;
……
endmodule
- 带参数模块例化
//例化
ram #(.AW(4), .DW(4))
u_ram
(
.CLK (clk),
.A (a[AW-1:0]),
.D (d),
.EN (en),
.WR (wr), //1 for write and 0 for read
.Q (q)
);
//ram模型
module ram
#( parameter AW = 2 ,
parameter DW = 3 )
(
input CLK ,
input [AW-1:0] A ,
input [DW-1:0] D ,
input EN ,
input WR , //1 for write and 0 for read
output reg [DW-1:0] Q
);
reg [DW-1:0] mem [0:(1<<AW)-1] ;
always @(posedge CLK) begin
if (EN && WR) begin
mem[A] <= D ;
end
else if (EN && !WR) begin
Q <= mem[A] ;
end
end
endmodule
状态机类型
- Moore 型状态机:输出只与当前状态有关,与当前输入无关。
- Mealy 型状态机:输出,不仅与当前状态有关,还取决于当前的输入信号。
竞争与冒险
-
竞争:在组合逻辑电路中,不同路径的输入信号变化传输到同一点门级电路时,在时间上有先有后,这种先后所形成的时间差称为竞争(Competition)。
-
冒险:由于竞争的存在,输出信号需要经过一段时间才能达到期望状态,过渡时间内可能产生瞬间的错误输出,例如尖峰脉冲。这种现象被称为冒险(Hazard)。
-
竞争不一定有冒险,但冒险一定会有竞争
-
判断方法: -代数法:Y = A + A’或者Y = A · A’ -卡诺图法:
-
消除方法: -增加滤波电容,滤除窄脉冲 -修改逻辑,增加冗余项:对数字逻辑 Y = A’B’ + AC 增加冗余项 B’C,则此电路逻辑可以表示为 Y = A’B’ + AC + B’C。此时电路就不会再存在竞争与冒险。 -使用时钟同步电路,利用触发器进行打拍延迟: