verilog
1、verilog的基本设计单元是模块(block)。一个模块是有两部分组成的 ,一部分描述接口,另一部分描述逻辑功能,及定义输入时如何影响输出的。下图为模块结构的组成。
模块特点
Verilog HDL程序是由模块构成的。每个模块的内容都是嵌在module和endmodule两个语句之间。每个模块实现特定的功能。模块可以进行层次嵌套。
每个模块要进行端口定义,并说明输入输出口,然后对模块的功能进行行为逻辑描述。
Verilog HDL程序的书写格式自由,一行可以写几个语句,一个语句也可以分写多行。
除了endmodule语句外,每个语句和数据定义的最后必须有分号。
可以用/…../和//…….对Verilog HDL程序的任何部分作注释。一个好的,有使
用价值的源程序都应当加上必要的注释,以增强程序的可读性和可维护性。
模块的结构
module <模块名> (<端口列表>)
<I/O说明>
<内部信号声明>
<功能定义>
endmodule
模块的端口定义:
模块的端口声明了模块的输入输出口。格式:
module 模块名(口1,口2,口3,口4,......)
- 1
模块的内容:
I/O说明
输入口(input 端口名1,端口名2,……端口名n)
输出口(output 端口名1,端口名2,……端口名n)
I/O\说明也可以卸载端口声明语句中: module module_name(input port1,input port2,…output port1,output port2…)
内部信号说明
在模块内用到的和与端口有关的wire和reg变量的声明,比如:reg[width-1:0] R1,R2…; wire[width-1:0] W1,W2…
功能定义
模块中最重要的部分是逻辑功能定义部分。有三种方法可在模块中产生逻辑:
用“assign”声明语句
“assign”,后面再加一个方程式即可
assign a = b & c;//两个输入的与门
“assign”语句是描述组合逻辑最常用的方法之一
用实例元件
and and_inst( q, a, b );
采用实例元件的方法象在电路图输入方式下,调入库元件一样。键入元件的名字和相连的引脚即可,
表示在设计中用到一个跟与门(and)一样的名为and_inst的与门,其输入端为a, b,输出为q。要求
每个实例元件的名字必须是唯一的,以避免与其他调用与门(and) 的实例混
模块(module)是Verilog 的基本描述单位,用于描述某个设计的功能或结构及与其他模块通信的外部端口。
模块在概念上可等同一个器件就如我们调用通用器件(与门、三态门等)或通用宏单元(计数器、ALU、cpu)等,因此,一个模块可在另一个模块中调用。
一个电路设计可由多个模块组合而成,因此一个模块的设计只是一个系统设计中的某个层次设计,模块设计可采用多种建模方式。
过程块
- always过程块
模板:
always @(<敏感信号表达式>)
begin
//过程赋值
//if语句
//case语句
//while、repeat、for语句
//task、function调用
end
当敏感信号表达式的值改变时候,就执行一遍块内语句。同时always过程块是不能够嵌套使用的。
关键字posedge
与negedge
关键字分别是上升沿以及下降沿
例如:同步时序电路的时钟信号为clk,clear为异步清零信号。敏感信号可写为:
//上升沿触发,高电平清0有效
always @(posedge clk or posedge clear)
//上升沿触发,低电平清0有效
always @(posedge clk or negedge clear)
例如当negedge clear
表示当clear==0
时
always @(posedge clk or negedge clear)
begin
if(!clear)//当clear==0时候,always会由事件驱动
qout=0;
else
qout=in;
end
- initial过程块
initial模板:
initial
begin
语句1;
语句2;
......
end
对变量和存贮器初始化
initial
begin
reg1=0;
for(addr=0;addr<size;addr=addr+1)
memory[addr]=0;
end
initial语句主要面向功能模拟,通常不具有可综合性。
模拟0时刻开始执行,只执行一次
同一模块内的多个initial过程块,模拟0时刻开始并行执行。
initial与always语句一样,是不能嵌套使用的。即在initial语句中不能再次嵌套initial语句块。
连续赋值
用连续赋值语句表达的是: assign val=newval;
任何一个输入的改变都将立即导致输出更新;
module orand(out,a,b,c,d,e);
input a,b,c,d,e;
output out;
assign out=3&(a|b)&(c|d);
endmodule
过程赋值语句
过程赋值语句常用于对reg变量进行赋值。一般分为两种,阻塞赋值与非阻塞赋值
阻塞与非阻塞赋值
赋值的类型选择取决于建模的逻辑类型。
在时序块的RTL代码中使用非阻塞赋值
<=
。非阻塞赋值在块结束后才完成赋值操作。此赋值方式可以避免在仿真出现魔仙和竞争现象。在组合的RTL代码中使用阻塞赋值
=
。使用阻塞赋值方式对一个变量进行赋值时,此变量的值在赋值语句执行完后之后就立即改变。
compare
使用非阻塞赋值方式进行赋值时,各个赋值语句同步执行;因此通常在一个时钟沿对临时变量进行赋值,而在另一个时钟沿对其进行采样。因为在相同的时钟沿采样赋值,采样的还是原来的值,赋值操作是在块结束时进行。
- 阻塞赋值
下面模块会综合成为触发器
module block(clk,a,b);
input clk,a;
output b;
reg b;
always @(posedge clk)
begin
y=a;
b=y;
end
endmodule
- 非阻塞赋值
下面的模块会综合成两个触发器
module block(clk,a,b);
input clk,a;
output b;
reg b;
always @(posedge clk)
begin
y<=a;
b<=y;
end
endmodule
上图左侧是阻塞赋值的综合结果,右侧则为非阻塞赋值。相比左侧,右侧的例子会造成一个时钟周期的延迟
小程序
加法器
module addr(a,b,cin,count,sum);
input [2,0]a;
input [2,0]b;
input cin;
output count;
output [2,0]sum;
assign {count,sum}=a+b+cin
endmodule
上面的程序描述的是一个3位加法器,可以看出来,程序从module开始,以endmodule结束。
input [2,0]a
表示声明一个3bit的输入变量,命名为a
assign {count,sum}=a+b+cin
表明为线网类型赋值,{}
是连接符号,count是1bit,sum是3bit,所以连接之后是4bit,最高位是count。等式右边是2个3bit相加,再加上一个1bit的,实现的全加器。
比较器
module compare (equal,a,b);
input [1:0] a,b; // declare the input signal ;
output equare ; // declare the output signal;
assign equare = (a == b) ? 1:0 ;
/ * if a = b , output 1, otherwise 0;*/
endmodule
逻辑部分是一个三目运算符号,有C语言基础的都可以看懂。
三态驱动器
module mytri (din, d_en, d_out);
input din;
input d_en;
output d_out;
// -- Enter your statements here -- //
assign d_out = d_en ? din :'bz;
endmodule
module trist (din, d_en, d_out);
input din;
input d_en;
output d_out;
// --statements here -- //
mytri u_mytri(din,d_en,d_out);
endmodule
全加器
一位全加器
如上图是一位全加器
这里先说明下什么是全加器,并说下全加器半加器的区别:
半加器不考虑低位过来的进位,只计算2个一位二进制数相加。产生一个本位和,还有一个向高位的进位信号。
全加器考虑低位过来的进位,计算2个一位二进制数相加。产生一个本位和,还有一个向高位的进位信号。
即半加器有二个输入,二个输出。全加器有三个输入,2个输出。
module FA_struct (A, B, Cin, Sum, Count);
input A;
input B;
input Cin;
output Sum;
output Count;
wire S1, T1, T2, T3;
// -- statements -- //
xor x1 (S1, A, B);
xor x2 (Sum, S1, Cin);
and A1 (T3, A, B );
and A2 (T2, B, Cin);
and A3 (T1, A, Cin);
or O1 (Cout, T1, T2, T3 );
endmodule
该实例显示了一个全加器由两个异或门、三个与门、一个或门构成。S1、T1、T2、T3则是门与门之间的连线。代码显示了用纯结构的建模方式,其中xor 、and、or 是Verilog HDL 内置的器件。以 xor x1 (S1, A, B) 该例化语句为例:
xor 表明调用一个内置的异或门,器件名称xor ,代码实例化名x1(类似原理图输入方式)。括号内的S1,A,B 表明该器件管脚的实际连接线(信号)的名称,其中 A、B是输入,S1是输出。其他同。
两位全加器
两位的全加器可通过调用两个一位的全加器来实现。该设计的设计层次示意图和结构图如下:
module Four_bit_FA (FA, FB, FCin, FSum, FCout ) ;
parameter SIZE = 2;
input [SIZE:1] FA;
input [SIZE:1] FB;
input FCin;
output [SIZE:1] FSum;
output FCout;
wire FTemp;
FA_struct FA1(
.A (FA[1]),
.B (FB[1]),
.Cin (FCin) ,
.Sum (FSum[1]),
.Cout (Ftemp)
);
FA_struct FA2(
.A (FA[2]),
.B (FB[2]),
.Cin (FTemp) ,
.Sum (FSum[2]),
.Cout (FCount )
);
endmodule
除了低位的进位Fcin,输入FA与FB都是两位,将输入的两位分别放到两个一位全加器上面,就好像我们在做两位数加法时,也是将个位、十位分别相加,再加上进位。
该实例用结构化建模方式进行一个两位的全加器的设计,顶层模块Four_bit_FA 调用了两个一位的全加器 FA_struct 。在这里,以前的设计模块FA_struct 对顶层而言是一个现成的器件,顶层模块只要进行例化就可以了。注意这里的例化中,端口映射(管脚的连线)采用名字关联,如 .A (FA[2]) ,其中.A 表示 调用器件的管脚A,括号中的信号表示接到该管脚A的电路中的具体信号。wire 保留字表明信号Ftemp 是属线网类型(下面有具体描述)。
Verilog建模
Verilog有三种建模方式,分别是
结构化描述方式
数据流描述方式
行为描述方式
其中数据流描述方式经常使用连续赋值语句,某个值被赋给某个网线变量。
assign [delay] net_name = expression;
注意在各assign 语句之间,是并行执行的,即各语句的执行与语句之间的顺序无关。
行为描述方式经常使用always、initial语句赋值。使用reg进行寄存器的声明。always是指一直在重复运行,由always后面括号的变量变化时触发。在always以及end之间是串行顺序执行的。
文章最后发布于: 2018-07-10 22:39:54
相关阅读
代码模版: [js] view plain copy print? $.ajax({ type: "POST",
文章转自:http://blog.sina.com.cn/s/blog_4ed902a50102e9a0.html 版权归原作者。 在英语中通常用下列方式表示的词:在形容词或
1 2 3 4 5 6 7 8 9 10 11 CREATE PROC [ EDURE ] procedure_name [ ; number ]
英语语法:have/ has的用法 英语初学者对have/has的用法还不是很清楚吧,快来学习一下吧! 作谓语 1谓语动词have表示“有”,有两种形
Python join() 方法用于将序列中的元素以指定的字符连接生成一个新的字符串。 返回通过指定字符连接序列中元素后生成的新字符串