模块(module)verilog的基本设计单元是模块,一个模块是由两部分组成的,一部分是描述接口,另一部分是描述逻辑功能。
module block(a, b, c, d);
/***************************/input a, b;
outpupt c, d;
/********以上是描述接口*******//***************************/assign c = a|b;
assign d = a&b;
/********以上是描述逻辑功能****/endmodule
从上面的例子可以看出verilog结构完全嵌在module和endmodule声明语句之间,每个verilog程序包括四个主要的部分:
端口定义,IO说明,内部信号声明,功能定义。
模块的端口定义 module 模块名(port1,port2,port3.....);
IO说明 input port1, port2, port3.......;
output port1, port2, port3.......;
也可以把IO说明写到端口定义中
module 模块名(input port1,input port2,output port3.....);
内部信号说明 在模块内用到的和与端口有关的wire和reg变量的声明。
功能定义 模块中最重要的部分是逻辑功能定义部分。有三种方法可在模块中产生逻辑。
1,用assign声明语句
assign a = b&c;
两输入的与门。
2,用实例元件
and and_inst(o, a, b);
3, 用always块
*** 在always模块内,逻辑是按照制定的顺序执行的,但是多个always模块是同时执行的。 wire型wire型数据常用来表示用于以assign关键字指定的组合逻辑信号。
可以用作任何方程式的输入,也可以用作assign或者实例元件的输出。缺省值为高阻(z)。
reg型寄存器是数据储存单元的抽象。缺省值为未知(x)。
在always和inital块中被赋值的每一个信号都必须定义为reg。 reg型数据可以赋正值,也可以赋负值。但是当一个reg型数据时一个表达式中的操作数时,它的值被当做是无符号的正值。
example: 当一个四位的寄存器用作表达式中的操作数时,如果开始寄存器被赋值为-1, 则在表达式中进行运算时,其值被认为是+15<补码>;
memory型 reg [n-1:0] mem[m-1:0]; //定义了有256个8位的储存器mem。
赋值:
mem = 0; //error
mem[3] = 0; //给mem的第三个储存单元赋值
比较= =和= = ===和!=, 比较的结果是由两个操作数的值决定,由于操作数中某些位可能是不定值x或高阻值z,结构可能为不定值x。而===和!==则不同,它在对操作数进行比较时对某些位的不定值和高阻值也进行比较,两个操作数必须完全一致,结果才是1,否则为0。
以下是真值表:=== 0 1 x z == 0 1 x z0 1 0 0 0 0 1 0 x x1 0 1 0 0 1 0 1 x xx 0 0 1 0 x x x x xz 0 0 0 1 z x x x x赋值语句在verilog HDL语句中,有两种赋值方式
1, 非阻塞(non_block) example: b <= a;
1) 块结束后才完成赋值操作;
2) b的值并不会立刻就改变的;
3)这是一种比较常用的赋值方法。
2,阻塞(block) example: b = a;
1)赋值语句执行完后,块才结束;
2)b的值在赋值语句执行完后立刻就改变的;
3)可能会产生意想不到的结果。
块语句 顺序块: 通常用begin end来标示。
特点:
1,快内的语句是按顺序执行的;
2,每条语句的延迟时间是相对于前一条语句的方针是而言的;
3,直到最后一天雨具执行完,程序流程控制才跳出该语句块。
example: begin:[block_name] statement_1; statement_2; ..... end 并行块: 通常用fork join来标示。
特点:
1,块内雨具是同时执行的;
2,块内每条语句的延迟时间是相对于程序流程控制进入块内时的仿真时间;
3,延迟时间使用来给赋值语句提供执行时序的;
4,当按时间时序排序在最后的语句执行完后或一个disable语句执行时,程序流程控制跳出该程序块。
example: fork: [block_name] statement_1; statement_2; .... join***********由于使用条件语句不当在设计中生成了原本没想到的锁存器 verilog HDL设计中容易犯的一个通病是由于不正确使用语言生成了并不想要的锁存器always @(a or d) always @(a or d)
begin begin
if (a) q <= d; if (a) q <= d;
end else q <= 0;
end
有锁存器 无锁存器
检查一下左边的always块,if语句保证了只有当a=1时,q才取d的值,而没有写出a=0的情况。 在always块内,如果在给定的条件下变量没有赋值,这个变量将保持原值,也就是说会生成一个锁存器。
在case语句中如果没有加上default,也会自动生成锁存器。 always语句由于不断重复执行的特性,只有和一定的时序控制结合在一起才有用。
always areg = ~areg; //这样会发生一个仿真死锁
always #half_period areg = ~areg; //ok
阅读(2455) | 评论(1) | 转发(0) |