define 就是一个宏定义
define 原变量 新的值或者名称或表达式
再使用的时候可以原变量代替
undef是取消定义宏 `undef 原变量 即可完成取消
`include "文件名.V"这样可以将文件名.V的全部内容赋值并插入到这条语句所出现的地方,并且在编译中将包含了
文件名.V的文件作为源文件进行编译,最好还是写绝对路径,并且每次只能指定一个被包含文件
如果要实现包含的层层引用,那么最里面的文件最先被include
timescale <time_unit>/<time_precision>前者是时间的基准单位,后者是该模块模拟时间的精确程度 例如
timescale 10ns/1ns定义模块的时间单位是10ns,时间精度为1ns,所以模块中的所有时间值应该是10ns的整数
倍,并且以1ns为精度
整形数据表达
x:未知 z:高阻
5'H0328
其中5表示共有多少位,后面是表达的数字,如果定义长度比实际数字大,通常是在左边补0,但是如果最左边是x或z
那么就补同样的字母,若定义长度比实际数短,那么就会截断左边超出部分
*************线网类型数据
wire/tri/wor/tiror/wand/triand/trireg/tri1/tri0/supply0/supply1
定义变量 net_kind [msb:lsb] net1;msb与lsb是定义范围的常量表达式,位数是msb-lsb+1(前提:msb大于lsb)
wire(连线)与tri(三态线)语法语义一致
wire [3:2]Cla,Pla,Sla
assign Cla = Pla&Sla 在这里Pla和Sla是驱动器,他们每个位按照wire的规律对应相与赋给Cla的对应位
wor和trior线或线网也是一致,也是根据规律得出结果(若一个驱动为1,则结果为1)
同理wand和triand(若一个驱动为0,则结果为0)
trireg(三态寄存器)线网 可以用来存储数值,当三台寄存器的所有驱动都处于高阻态z时,trireg线网将保留作
用在该先网上的最后一个值,缺省值是x
tri0和tri1线网 若无驱动源,tri0的值为0,tri1的值为1
supply0和supply1线网,其中supply0用于对地建模,也就是低电平0,supply1用于对电源建模,也就是高电平1
*************寄存器类型数据(注意和寄存器打交道就是和01打交道)
reg/integer/time/real/realtime
reg [1:32] Cnt则是32位寄存器
reg [1:4] Comb //本身是4位寄存器,所以最后只保留四位
如果Comb=-2,则相当于求-2的补码(负数补码,先写出包含符号位的二进制,除符号位以外取反,最后+1)
interger整型寄存器,存放整数,默认32位,所以定义一个interger变量J=6,那么就是J=32'b000...0110
整数不能位访问,譬如J[2]是不行的
time型寄存器(和前面的不一样,他的数位放在后面)存放64位
time Events[0:31]定义一个时间值数组
time CurrTime 存储一个时间
real和realtime寄存器用法一致,当命名一个real变量,其中含有x或z,统一会被当成0处理
连接操作符{}
采用{}将多个信号的位连接在一起组成新信号{a,b[3:0],3'b110}
复制法{4{3'b010}}就能得到12'b010010010
***********行为语句
initial和always是并行语句,执行顺序与在模块的先后顺序无关,其中initial对应的过程块常用于方针的初始化
工作,并且只执行一次,但是always是不断执行的
initial是在时刻0便开始执行,若想在initial中进行顺序过程,那么就要采用begin-end
initial
begin
....
end
如此便会按照顺序执行
如果想在initial中进行延迟控制,那么就在句子前面加个 #数字
多个initial是并行的
always语句
反复执行其中语句,但是语句顺序执行的触发条件是时序控制,他是从0时刻开始执行,满足条件无限循环
它也可以顺序执行和延迟控制
always@(时序控制)
其中时序控制也可以是电平触发也可是边沿触发,若为多个信号触发,信号间要用or连接
不同的always和initial块语句是交叉执行的,若某个always或initial块使用等待@,#或者wait执行时,那么其他的
们单元、持续赋值语句以及其他always/initial块的语句就可以继续执行,也是因为always语句必须等待某个条件
满足才执行,所以容易产生锁存器
if-else语句(只能放在行为建模)
begin-end其实相当于C的{},含有多重if-else,记得使用begin-end来加以区分
条件操作符(既可以放在门级建模也可以放在行为建模)
expression = expression1?expression2:expression3
其中expression1可以是表达式
case语句
和C的差不多,只是少了break,执行完一个就会跳出case,同时如果各个case长度不一致,那么就会统一为最长的
长度
casex:值x和z都认为是无关项
casez:只有z是无关项,感觉优先译码器可以使用到
循环语句:
forever:连续执行某个或某些语句序列
repeat:执行某个语句固定次数
while:同C中while
for:(按下列顺序进行)
1.对控制执行次数的变量赋值
2.计算表达式的值,若结果为0跳出,否则执行,然后执行下一步
3.修改控制变量值,返回2
注意,可以使用disable来跳出循环,在使用forever语句,如果不加入时序控制语句,那么就会0延迟不断循环
repeat (执行次数)
begin
...
end若执行次数表达式的值不确定,要么为x要么为z那么按照0处理
repeat (count)//表示循环
@(posedge clk) sum=sum+1,每次clk一个上升沿,sum+1,直到执行count次数,sum统计的值是count计数过程中
时钟拍数
sum = repeat(count)
@(posedge clk) sum=sum+1
直到repeat结束以后,再赋值给sum
repeat (num_of_times)@(negedge clk)
num_of_times = num_of_times-1;
这里的意思是执行repeat后的语句之前,必须等待num_of_times次clk下降沿
while语句
while(条件)若条件为真则一直执行,若为假则不执行,若为x或者z一样不执行
for语句
也是同C中for
disable能够种植任何begin-end,所以写begin-end块时,可以把块名写在begin后边
begin:块名
...
if (...) disable 块名;
end
如果满足了if的条件,直接跳出块名包含的整个begin-end
*********事件控制
感觉就是 @+(事件控制)
其中事件控制包含 边沿触发事件控制和电平敏感事件控制
posedge包含了0->Z,X,1 Z,X->1
negedge包含了1->Z,X,0 Z,X->0
电平敏感触发事件
通常配合wait语句来使用,wait顾名思义就是要等到某个条件满足才执行
wait(condition)
statement
**********持续赋值(用于wire,tri类型)
wire/tri必须是事先定义好的,关键字是assign
assign left = right,都要是wire/tri类型数据,
***补充一个小点 设置一个多位的变量,比如input [1:0]那么就是2位的,它能表达的十进制数字范围是0-3
**********过程赋值(用于寄存器型、整型、时间型和存储器型数据)
过程赋值通常放在initial和always中,只能对寄存器型变量赋值
其实形式就是普通的赋值一样,直接用一个等号即可,通常是按照顺序逻辑来进行赋值
过程赋值分为阻塞赋值语句和非阻塞赋值语句,其中阻塞赋值语句对应电路结构仅仅和输入电平变化有关
而非阻塞赋值语句和出发沿有关
在always块中,阻塞赋值语句产生组合逻辑,非阻塞语句产生时序逻辑
组合逻辑:任意时刻的输出仅取决于当前时刻的输入,与原来状态无关
时序逻辑:不仅取决于当前输入,还取决于原来状态
阻塞赋值 = (他执行完了才会执行同一个块的后续语句,串行)
要注意一个逻辑问题,就是假设有两个过程快,一个阻塞赋值的右边式子变量涉及到另一个过程块的
左边式子变量,那么当他们两个同时倍调度执行,容易发生条件竞争,出现逻辑错误
非阻塞赋值 <= (在时刻开始计算右边表达式的值,在时钟拍结束赋给左边表达式,同时同块后续语句
不受影响执行,各自独立,并行,只能对寄存器型数据使用)
而且不受begin-end的顺序执行影响,还是同时起步各做各的
在一个块中对同一个变量非阻塞赋值,最终的才有效
*********阻塞赋值通常用在组合逻辑设计,非阻塞赋值用在时序逻辑设计,若同时出现,则使用非阻塞
不可以再一个module内定义UDP,UDP只能在module之间,或者用`include将写在另一个文件的UDP包含到当前设计
模块格式
module module_name(list_of_ports);
{module_item}
endmodule
其中list_of_ports是用于与外界通信的端口,他们必须定义为input/output/inout(双向端口)
并且端口都默认为wire类型,除非自己修改位其他类型比如说reg
模块参数化
1.使用参数定义语句defparam
注意这种方式只能是高层模块对低层模块的示例化,并且最好能指出参数的层次名
区分高层,低层就是看高层中调用低层来建立变量
假设高层模块叫做top,低层叫做vdff,vdff中本身parameter变量a=1
在模块top中 vdff(变量)类型的变量为m1,m2
后来在另一个模块采用defparam来重载m1,m2的parameter就这样做
top.m1.a = 5,top.m2.1=9;
示例化就感觉是好像之前建立起来一个类,然后自己建立一个对象