cpld的verilog学习
2011-01-06 17:17 2842人阅读 评论(0) 收藏 举报
integer存储语言编译器moduleinput
以前浪费了太多机会了。以后就用这些来记录下自己到底学会了什么。用到了什么。做出了什么。 verilog的整体结构 模块的结构
verilog的基本设计单元是“模块”(block)。包括(接口描述、逻辑功能描述) 例子:
module block(a, b, c, d); input a, b; output c, d;
assign c = a | b; 【连续赋值:assign,问号表达式(?:)】 assign d = a & b; endmodule
由例子可以看出,verilog结构位于在module和endmodule声明语句之间,每个verilog程序包括4个主要部分:端口定义、I/O说明、内部信号声明和功能定义。
1、 模块的端口定义
模块端口声明了模块的输入输出。格式:
module 模块名(口1,口2,口3,口4,…..); 模块的端口表示模块的输入还是输出名。 引用模块时其端口可以用两种方法连接:
(1) 在引用时,严格按照定义的端口顺序连接,不用标明原模块定义时规定的端口
(2) 在引用时用”.”符号,标明原模块是定义时规定的端口名。 2、 模块内容
模块的内容包括I/O说明、内部信号声明和功能定义。 (1) I/O说明的格式
输入口:input [信号位宽-1 : 0] 端口名1; 输出口:output [信号位宽-1 : 0] 端口名1; 输入输出口:inout [信号位宽-1 : 0] 断口名1; (2) 内部信号说明
在模块内用到的与端口有关的wire和reg类型变量的声明。
Reg [width-1 : 0] R变量1,R变量2…; 【reg不和实际的电路如寄存器对应,高层次的描述时用】
Wire [width-1 : 0]W变量1,W变量2…;【与实际的物理连接对应】 (3) 功能定义
模块中最重要的部分时逻辑功能定义。由3种方法可以在模块中产生逻辑。 1) 用assign声明语句
如assign a = b&c; 2) 用实例元件 and #2 u1(q, a, b);
3) 用always块【变量必须声明为reg,还有initial。】 always @(posedge clk or posedge clr) begin if(clr) q <= 0; else if(en) q <= d; end
采用assign是描述组合逻辑最常用的方法之一。而always既可用来描述组合逻辑电路也可以用来描述时序逻辑。 (4) 要点
1) 在verilog模块中所有过程块(initial, always)、连续赋值语句、实例引用都是并行的;
2) 他们表示的是一种通过变量名互相连接的关系 3) 在同一模块中这三者出现的先后顺序没有关系。
只有联系赋值的语句assign和实例引用语句可以独立与过程块而存在于模块功能定义部分
程序例子
偶数分频器的verilog实现(先学习偶数,我用的单片机用到分频器)
偶数倍分频:偶数倍分频应该是大家都比较熟悉的分频,通过计数器计数是完全可以实现的。如进行N倍偶数分频,那么可以通过由待分频的时钟触发计数器计数,当计数器从0计数到N/2-1时,输出时钟进行翻转,并给计数器一个复位信号,使得下一个时钟从零开始计数。以此循环下去。这种方法可以实现任意的偶数分频。
module odd_division(clk,rst,count,clk_odd); input clk,rst; output clk_odd; output[3:0] count; reg clk_odd; reg[3:0] count;
parameter N = 6; 【常数】
always @ (posedge clk) 【always模块:(敏感表可以为电平、沿信号posedge/negedge;通常和@连用)】
if(! rst) 【任务定义:task??endtask】 begin
count <= 1'b0; 【 赋值符号:= 和 <= (阻塞和非阻塞赋值,在具体设计中时很有讲究的)】 clk_odd <= 1'b0; end else
if ( count < N/2-1) begin
count <= count + 1'b1; end else begin count <= 1'b0;
clk_odd <= ~clk_odd; end endmodule 注:数据结构详解
整数、实数和时间寄存器类型
整数是一种通用的寄存器数据类型,用于对数量进行操作,使用integer进行声明。
integer counter; //一般用途的变量用作计数器 initial
counter = -1; //把-1存储到寄存器中
实数:实常量和实数寄存器数据类型使用关键字real来声明,可以用十进制或科学计数法来表示。实数声明不能带有范围,其默认值为0.如果将一个实数赋予一个整数,那么实数将会被取为最接近的整数。 real delta; //定义一个名为delta的实型变量
时间寄存器:仿真是按照仿真时间进行的,verilog使用一个特殊的时间寄存器数据类型来保存仿真时间。时间变量通过使用关键字time来声明,其宽度与具体实现无关,最小为64位。通过调用系统函数$time可以取得当前的仿真时间。 2 数组
Verilog中允许声明reg、integer、time、real、realtime及其向量类型的数组,对数组的维数没有限制,即可声明任意维数的数组。线网数组也可用于连接实例的端口,数组中的每个元素都可以作为一个标量或者向量,以同样的方式来使用,形如<数组名>[<下标>]。
Integer count[0:7]; //由八位计数变量组成的数组
reg bool [31:0]; //由32个1位的布尔寄存器变量组成的数组 wire [7:0] w_array2 [5:0]; //声明8位向量的数组
注意:不要把数组和线网或寄存器向量混淆起来。向量是一个单独的元件,它的位宽是n,数组由多个元件组成,其中每个元件的位宽为n或1. 3 存储器【重点】
Verilog中使用寄存器一维数组来表示存储器。数字的每个元素成为一个元素或一个字(word),由一个数组索引来指定。每个字的位宽为1位或者多位。注意n个1位寄存器和一个n位寄存器是不同的。如果需要访问存储器中的一个特定的字,则可通过子的地址作为数组的下标来完成。 reg mem1bit[0:1023]; //1k的1位存储器
reg [7:0] membyte [0:1023]; //1k的字节(8位)存储器membyte membyet[511] //取出membyte中地址511所处的字节 4 参数