一、Verilog语法学习
1.数据物理类型:
线性数据:用于连续赋值语句(assign)描述组合逻辑或module间的信号连接线;
wire:线性,可综合;
wire [3:0] a;
tri0/tri1:带下拉/上拉电阻的线性,没有驱动时会有默认值0/1,一般可综合代码不用;
tri0 s0;
寄存器类型:用于过程赋值语句(always,initial)描述组合逻辑或时序逻辑;
always @(*) 敏感变量列表一般指组合逻辑的输入(可综合)
initial 仿真时用,一般不可综合。
2.数据类型
一维标量类型(变量)
wire [3:0] da,db; ---------默认为无符号数
wire signed [3:0] s0; ----------有符号数的声明
多维标量类型(变量)
wire [3:0] array_0 [0:7]; --------8个4bit数组组成的数组
wire [13:0] array_1 [0:255];-----------256个14bit数组组成的数组
reg [7:0] array_2 [0:15][0:255]; ------------多维数组
assign array_0[0] = array_1[255][7:4]; ------第一个中括号选择成员,第二个中括号选择bit
计算位宽时,都要转成二进制来计算,因为时序元件只能存储二值电平。
对于4'h0,由于是这里的0是十六进制的,它表示二进制的4'b0000,所以是四位的。
对于16'h4012,每个数字表示4位,一共4个数字,所以一共是4*4=16位。
3.运算符
assign d0=|a; // d0 = a[0] | a[1] | a[2] | a[3] | a[4]
assign d1=&b; // d0 = b[0] & b[1] & b[2] & b[3] & b[4]
整体逻辑操作:&&,||,!,==,!=
将两边看做一个1bit的整体,为0则为0,非0则为1
bit位选择用[ ] / 拼接用{ }
+:操作:a1[0 +: 8] 等价于 a1[7:0] ------从0位开始向上取,总共取8bit
二、verilog描述组合逻辑&时序逻辑
1.有符号数符号位扩展
wire [15:0] a,b; //signed number
wire [16:0] out0;
wire [16:0] out1;
assign out0 = {a[15], a} - {b[15], b}; //17'h00001-17'h1ffff
assign out1 = a - b; //17'h00001-17'h0ffff (机器默认无符号数,自动高位补0)
如不进行符号位扩展,计算不到我们想要的结果
测试序列: a b
16'h0001 16'h0001
16'h0001 16'hffff
2.时序逻辑:
同步复位: posedge clk中!rstn
异步复位: posedge clk中!rstn or negedge rstn
3.可综合code建议
1)描述组合逻辑使用“=”赋值
2)描述时序逻辑(DFF)使用“<=”赋值
3)#1(delay)可以用,综合会被忽略
4)不要在多个语句块中,对同一个变量赋值
三、FSM(状态机)
Mearly型:输出由当前状态和输入共同决定;
Moore型:输出只与当前状态有关;
1)1段式/2段式/3段式状态机的描述方法在电路综合时影响不大
2)1段式/2段式比3段式更节省code量,但2段式/3段式写起来更顺手
3)做cycle级的pipeline,FSM可能会妨碍pipeline
用FSM/移位寄存器可实现序列检测
四、function & task
1.function
function定义位宽,它的返回值就是function name,它只有input;
function为一个模块,可以在其他区域调用function,通常用来描述组合逻辑的功能(不能插入时延);
例:function [2:0] cal_1n_bias;
2.task
task可以有n个input,n个output,内部可以插入时延(#1);
task是在一个module里面的定义的,可以访问module内部已经定义好的reg型的变量,对它进行赋值;
3.系统function
系统function有很多,可以自行查找
$time:获取当前仿真时间
$fopen,$fdisplay:文件操作
$sign:无符号转化为有符号数
$random:生成随机数
$finish:停止仿真
4.逻辑功能结构
一个实用功能(DMA,UART,I2C)通常分为两段主要逻辑功能:control path,data path;需要后续上手实例后进行体会。