首页 Verilog

Verilog

举报
开通vip

Verilog一, FPGA概述 1. FPGA的最小系统主要包括:FPGA芯片,下载电路,外部时钟,复位电路和电源如果要使用NIOSII软嵌入式处理器还要包括:SDRAM和FLASH。 2. FPGA的管脚主要包括:用户I/O,配置管脚,电源,时钟及特殊应用管脚 用户I/O:可用作输入或输出,或者双向口,同时可作为LVDS差分对的负端 3. FPGA是SRAM型结构,本身不能固化程序,因此FPGA需要一片FLASH结构的配置芯片来存储逻辑配置信息,用于进行上电配置。以ALTERA公司的FPGA为例,配置芯片分为串行EPCS...

Verilog
一, FPGA概述 1. FPGA的最小系统主要包括:FPGA芯片,下载电路,外部时钟,复位电路和电源如果要使用NIOSII软嵌入式处理器还要包括:SDRAM和FLASH。 2. FPGA的管脚主要包括:用户I/O,配置管脚,电源,时钟及特殊应用管脚 用户I/O:可用作输入或输出,或者双向口,同时可作为LVDS差分对的负端 3. FPGA是SRAM型结构,本身不能固化程序,因此FPGA需要一片FLASH结构的配置芯片来存储逻辑配置信息,用于进行上电配置。以ALTERA公司的FPGA为例,配置芯片分为串行EPCSX和并行EPCX两种,其中EPCX为老款配置芯片,体积较大,价格高。而EPCSX系列芯片与之相比体积小,价格低。此外也可以使用FLASH+CPLD的方式去配置FPGA。 4. 在把程序固化到配置芯片之前,一般先使用JTAG调试程序也就是把程序下载到FPGA芯片上运行。虽然这种方式断电以后程序会丢失,但是充分利用了FPGA的无限擦写性。所以一般FPGA有两个下载接口:JTAG调试接口和AS(或PS)模式下载接口。所不同的是前者下载至FPGA,后者是编程配置芯片(如EPCSX),然后再配置FPGA。 5. FPGA的内部结构基于查找 关于同志近三年现实表现材料材料类招标技术评分表图表与交易pdf视力表打印pdf用图表说话 pdf 结构的,一般由三种可编程电路和一个用于存放编程数据的静态存储器SRAM组成。这三种可编程电路是:可编程逻辑模块,输入/输出模块(IOB)和互连资源,CLB是实现逻辑功能的基本单元,它们通常规则地排列成一个阵列,散布于整个芯片;可编程输入/输出模块IOB主要完成芯片上的逻辑与外部封装脚的接口,它通常排列在芯片的四周;可编程互连资源包括各种长度的连接线段和一些可编程连接开关,它们将各个CLB之间或CLB,IOB之间以及IOB之间连接起来,构成特定功能的电路。CLB主要由逻辑函数发生器,触发器,数据选择器等电路组成。输入/输出模块IOB提供了器件引脚和内部逻辑阵列之间的连接。它主要由输入触发器,输入缓冲器和输出触发/锁存器,输出缓冲器组成。以上为以XilinxFPGA内部结构为例。 6. 在Verilog HDL中可使用如下方式描述: a.结构化描述形式 1)内置门原语(在门级); 2)开关级原语(在晶体管级); 3)用户定义的原语(在门级); 4)模块实例 (创建层次结构) b.数据流级建模 c.行为级建模 2, VERILOG HDL 基础 1. 例1 module adder(count,sum,a,b,cin); input [2:0] a,b; input cin; output count; output [2:0] sum; assign {count,sum}=a+b+cin; endmodule 例2, module trist2(out,in,enable); Output out; Input in,enable; Bufif1 mybuf_name (out,in,enable); Endmodule 每个模块要进行端口定义,并说明输入输出口,然后对模块的功能进行行为逻辑描述,书写格式自由,一行可以写几个语句,一个语句也可以分写多行,除了endmodule语句外,每个语句和数据定义的最后必须有分号。可用/**/ 或//进行注释。 2. 模块框架 1.模块的书写 (1).I/O声明:声明了模块的输入输出端口, Module 模块名(端口1,端口2,端口3,); (2)I/O说明 a.输入口:input 端口名1,端口名2; 输出口:output 端口名1,端口名2; 输入/输出双向端口:inout端口名1,端口名2; 也可在端口声明语句里 Module module_name(input port1); b.所有的端口隐含地声明为wire类型如果输出类型的端口需要保存数值,则必须将其显式地声明为reg数据类型只适用于output其它类型反映外部信号的变化而不能保存这些信号的值 c. 输入端口从模块外部可以连接到线网或reg 输出端口从模块外部可以连接到线网的变量而不能连接到reg类型的变量 输入端口从模块内部可以连接到线网的变量而不能连接到reg类型的变量 输出端口从模块内部可以连接到线网或reg d.端口与外部信号的连接 顺序端口连接 命名端口连接:在此方法中,需要与外部信号连接的端口必须用名字进行说明,而不需要连接的端口只需要简单地忽略掉即可 例:fulladd4 fa_byname(.C_OUT(c_out),.SUM(sum)); sum为外部信号 SUM为模块端口名 (3)内部信号声明 在模块内用到的和端口有关的wire和reg 变量的声明 Reg [width-1:0] R 变量1,R变量2.。。; Wire [width-1:0]W 变量1,W 变量2….; (4)功能定义 ①用“assign”声明语句 Assign a=b&c; ②用实例元件 And and_inst(q,a,b); ③用“always”块 Always @(posedge clk or posedge clr) begin//时钟上升沿触发,异步清零 If(clr ) q<=0; //清零 Else if(en) q<=d;//使能赋值 End 上面3个例子分别采用了“assign”语句,实例元件和“always”块,如果把3项写到一个Verilog模块文件中去,它们的次序不会影响逻辑实现的功能,同时执行并发的。 然而在“always”模块内,逻辑是按照指定的顺序执行的。 (5)层次命名由一连串使用”.”分隔的标识符组成,每个标识符代表一个层次,这样设计者就可以在设计中的任何地方通过指定完整的层次名对每个标示符进行访问。 2.模块的调用 模块调用时的阵列调用方式 <被调用模块名> <实例阵列名>[阵列左边界:阵列右边界](<端口连接表>) 例 NAND NAND_ARREY[3:0](out,ina,inb); 相当于NAND NAND_ARREY[0](out[0],ina[0],inb[0]); NAND NAND_ARREY[1](out[1],ina[1],inb[1]); NAND NAND_ARREY[2](out[2],ina[2],inb[2]); NAND NAND_ARREY[3](out[3],ina[3],inb[3]); 3. 常用数据类型 常用的4个最基本的数据类型reg型 wire型intege型 parameter型及一个time型 Verilog语言也有常量和变量之分,它们分别属于以上这些类型。 1.常量 (1)..数字 a,<位宽><进制><数字> <进制><数字>//位宽采用缺省位宽(由具体的机器系统决定至少32位) <数字>//采用缺省进制十进制 例8‘b10101100 8‘ha2 b. X和Z值 X代表不定值 Z代表高阻值 c.负数 -8‘d5 d.下划线. 16’b1010_1011_1111 (2).参数(parameter) Parameter [signed] [range] 参数名1=表达式,参数名2=表达式;上述赋值语句的右边必须是一个常数表达式。例 parameter msb=7; parameter signed [31:0] mux_selector=0; 常用于定义延迟时间和变量宽度,在模块或实例引用时可通过参数传递改变在被引用模块或实例中defparam定义的参数。 例module Decode(A,F); Parameter with=1,polarity=1; Endmodule Module Top; Decode #(4,0) D1(A4,F16); Decode #(5) D2(A5,F32); 局部参数使用关键字Localparam来定义但其值不能通过参数重载语句defparam或通过有序参数列表或命名参数赋值来直接修改。 2.变量 (1)网络类型变量:表示结构实体之间的物理连接不能储存值,而且它必需受到驱动器(例如门或连续赋值语句,assign)的驱动,如果没有驱动器连接到网络类型的变量上则该变量高阻Z。常用的wire和tri用于连接器件单元,它们具有相同的语法格式和功能。Wire型变量通常是用来表示单个门驱动或连续赋值语句,驱动的网络型数据,tri型表示多驱动器驱动的。如果wire或tri没有定义逻辑强度,在多驱动源的情况下产生不确定,Verilog程序模块中输入/输出信号类型缺省时自动定义为wire型,wire型变量可以用作任何方程式的输入也可以用作“assign”语句或实例元件的输出 wire[n-1:0]变量名1,变量名2,……,变量名I; wire a;定义了一个一位的wire型变量。 (2)寄存器型数据与连线型数据的区别在于:寄存器型数据保持最后一次的赋值,而连线型数据需要有持续的驱动。寄存器是数据存储单元的抽象,通过赋值语句可以改变寄存器存储的值,缺省初始值为不定值X.reg型变量常用来表示用于“always”模块内的指定信号。“always”块内被赋值的每一个信号都必须定义成reg型。其可以赋正值也可以赋负值,但当一个reg型变量是一个表达式中的操作数时,它的值将被当作是无符号值,即正值。 “字符串”保存在reg中reg长度>字符串长度左补零<截去字符串最左边的位,对于字符串它必须在一行中书写完不能包含回车符。 寄存器也可以声明为带符号的reg signed [63:0] m;//64位带符号的值integer I ;//32位带符号的 “initial”语句中可以出现wire类型变量。 (3)实数 例:real delta;delta=4e10;delta=2.13如将一个实数赋给一个整数,那么实数将会被取整为最接近的整数 (4)可变的向量域选择 例:reg [255:0] data1; reg [0:255] data2; byte=data1[31-:8];// (data1[31:24]) byte=data2[31-:8];// (data2[24:31]) data2的最高有效位是它的第0位 (5)存储器型变量 通过对reg型变量建立数组来对存储器建模用于描述RAM型ROM存储器和reg文件。数组中的每一个单元通过一个数组索引进行寻址。由于在Verilog语言中没有多维数组存在,因此memery型数据是通过扩展reg型数据的地址范围来生成的。 例: reg [n-1:0] 存储器名 [m-1:0] reg [n-1:0]定义了存储器中每一个存储单元的大小。 [m-1:0]定义了该存储器中有多少个这样的寄存器 Reg [7:0] mema[255:0]; 256X8的存储器 Reg mema [n-1:0];由n个1位寄存器构成的存储器组 一个n位的寄存器赋值 rega=0; Memory中的存储单元 mema[3]=0; 为存储器赋值的另一种方法是使用系统任务: 1) $re a d m e m b (加载二进制值) 2) $re a d m e m b (加载十六进制值) 这些系统任务从指定的文本文件中读取数据并加载到存储器。文本文件必须包含相应的二进制或者十六进制数。例如:r e g [1:4] RomB [7:1] ; $ r e a d m e m b ("ram.patt", RomB); R o m b是存储器。文件“r a m . p a t t”必须包含二进制值。文件也可以包含空白空间和注释。 (6)time时间寄存器:用来保存仿真时间 realtime :00实时时间 5.数据流建模 自动将电路的数据流设计直接转化为门级结构这个过程也称为逻辑综合 在数字设计领域RTL(寄存器传输级)通常是指数据流建模和行为级建模的结合 1.常用的运算符(规则1.左边补零 2.含XZ则为X(除了与上0或上1)) (1)算术运算符 + - X / % 例: 10%3 1 12%3 0 -10%3 -1 结果取第一个操作数的符号位 如果操作数的任意一位为X,那么运算结果的全部位为X。 (2)位运算符 ~取反 &按位与 |按位或 ^按位异或 ^~按位同或(异或非) 不同长度的数据进行位运算系统会自动将两者按右端对齐。位数少的操作数会在相应的高位用0填满,以使两个操作数按位进行操作。 (3)逻辑 && || !(X一般按假处理) (4)关系运算符 < > <= >= 所有的关系运算符有着相同的优先级别,关系运算符的优先级别低于算术运算符的优先级别 (5)= = != 对于X Z 结果为X = = = != = 对不定值X高阻Z也进行比较相同1 不同 0. (6)<< >> a>>n; n代表要移几位,两种移位都用0来填补移出的空位。 <<< >>> 算术移位根据表达式的内容来确定空余位的填充值。 (7)位拼接运算符{}可把两个或多个信号的某些拼接起来进行运算操作 例:{a,b[3:0],w,3’b101}拼接表达式中不允许存在没有指明位数的信号也可{4{w}}等同于{w,w,w,w}.{b,{3{a,b}}}等同于{b,a,b,a,b,a,b} (8) 缩减运算符 过程1.先将操作数的第一与第二位进行与或非运算 2.将运算结果与第三位进行与或非运算,以此类推直至最后一位。 例:reg[3:0] B; Reg c; C=&B;相当于C=((B[0]&B[1])&B[2])&B[3]; 2.连续赋值语句(assign) 显式连续赋值语句: 线网型数据类型 (赋值驱动强度)[线网型数据位宽] 线网型数据名; Assign [drive_strength] [delay3] list_of_net_assignments 隐式连续赋值语句: 线网型数据类型 (赋值驱动强度)[线网型数据位宽] #(延时量)线网型数据名=赋值表达式; a,连续赋值语句的左值必须是一个(标量或向量)线网或者是(标量或向量)线网的拼接,而不能是(标量或向量)寄存器 b.连续赋值语句总是处于激活状态。只要任意一个操作数发生变化,表达式就会被立即重新计算,并且将结果赋给等号左边的线网。 c.操作数可以是标量或向量的线网或寄存器也可以是函数调用 d.延迟 普通赋值延迟 assign #10 out=in1&in2; 线网声明延迟 wire #10 out; Assign out=in1&in2;等效于wire out; assign #10 out=in1&in2; 4. 行为级建模 1.结构说明语句 Initial和always其它所有的行为语句只能出现在这两种结构化过程语句里。 (1)initial 说明语句 Initial begin 语句1;语句2;语句n; end 或 initial 语句;(仿真期间只能执行一次)可用于仿真开始时对各变量进行初始化或生成激励波形作为电路的测试仿真信号,一个模块可以有多个initial块它们都是并行执行的。Initial块常用于测试文件和虚拟模块的编写,用来产生仿真测试信号和设置信号记录等仿真环境 (2)always语句 Always<时序控制><语句>(仿真开始顺序执行其中的行为语句,由于其不断重复执行的特性,只有和一定的时序控制结合在一起才有用。如果一个always语句没有时序控制,则这个always语句将会发成一个仿真死锁)其的时间控制可以是沿触发也可以是电平触发可以单个信号也可以多个信号中间需要用关键字OR连接 例;always@(posedge clock OR posedge reset) (3)基于事件的时序控制 事件是指某一个寄存器或线网变量的值发生了变化事件可以用来触发声明语句或块语句的执行。4种类型的事件控制:常规事件控制,命名事件控制,OR事件控制和电平敏感时序控制 A,常规事件控制,使用@来说明@(clock)@(posedge clock) 正向跳变@(negedge clock)负向跳变 B,命名事件控制 例:a,event received_data. (不能保存任何值) b,->received_data;触发该事件 c,判断事件发生@(received_data) C,OR事件控制 例:@(reset or clock or d)或@(reset,clock,d) 如果组合逻辑块语句的输入变量很多,那么编写敏感列表会很繁琐并且容易出错。@*和@(*)它们都表示对其后语句块中的所有输入变量的变化是敏感的。 D,电平敏感时序控制 Wait(条件表达式) 语句块; Wait(条件表达式) 行为语句; Wait(条件表达式) ; 表示等待电平敏感的条件为真,那么语句块立即得到执行;否则语句块要一直等到条件表达式变为“真”时再开始执行。 2.块语句:通常用来将两条或多条语句组合在一起使其在格式上看更像一条语句。块语句主要有两种:一种begin_end语句通常用来标识顺序执行的语句,用它来标识的块称为顺序块,另一种是fork_join语句,通常用来标识并行执行的语句,用它来标识的块称为并行块。 (1)顺序块 a.块内的语句是按顺序执行的,即只有上面一条语句执行完后下面的语句才能执行 b,每条语句的延迟时间是相对于前一条语句的仿真时间而言的。 C,直到最后一条语句执行完,程序 流程 快递问题件怎么处理流程河南自建厂房流程下载关于规范招聘需求审批流程制作流程表下载邮件下载流程设计 控制才跳出该语句块 例:begin begin:块名 语句1; 或者 块内声明语句(参数声明 reg integer real) 语句2; 语句1; 语句3; 语句2; end end begin areg=nreg; #10 creg=areg;//#10两条赋值语句间延迟10个时间单位) end (2) 并行块 A,块内语句是同时执行的即程序流程控制一进入该并行块,块内语句则开始同时并行地执行 B,块内每条语句的延迟时间是相对于程序流程控制进入到块内时的仿真时间 C,延迟时间是用来给赋值语句提供执行时序的 D,当按时间时序排序在最后的语句执行完后或一个disable语句执行时,程序流程控制跳出该程序块 例: Fork 或者 fork:块名 语句1; 块内声明语句 语句2; 语句1; 语句n; 语句2; Join join 注:块名即标识该块的一个名字相当于一个标识符 块内说明语句可以是参数说明语句reg integer real time event (3) 对于块名的说明,加入块名可以在块内定义局部变量即只在块内使用的变量,可以允许块被其它语句调用如被disable语句 (4)verilog里所有的变量都是静态的即所有的变量都只有一个唯一的存储地址,因此进入或跳出块并不影响后面的语句只有在该块完全执行后后面的语句才可以执行。 3.赋值语句 过程赋值语句只能用于对寄存器类的变量(寄存器reg,整型 integer,实型real或时间型time变量)进行赋值操作。过程赋值语句的两种赋值方式:非阻塞赋值方式和阻塞赋值方式 (1)非阻塞赋值方式b<=a; 1.在begin_end串行语句块中,一条非阻塞型过程赋值语句的执行不会阻塞下一条语句的执行,也就是说在本条非阻塞型过程赋值语句对应的赋值操作执行完毕之前,下一条语句也可以开始执行。2.仿真进程在遇到非阻塞过程赋值语句后首先计算其右端赋值表达式的值,然后要等到当前仿真时间步结束时再将该计算结果赋值给赋值变量。也就是说,这种情况下的赋值操作是在同一仿真时刻上(相同的延时时刻)的其它普通操作结束之后才得到执行的。 例 initial Begin a<=0; a<=#5 1; a<=#10 0; a<=#15 1; end 上述仿真结果__ __ __ __ __ — — — — —__ __ __ __ __— — — — —(每一小横杠代表一个时间单位) 因为其非阻塞性质,使得在begin_end块中的非阻塞赋值语句有并行性质。 D o n e = #5 'b1; //语句内部时延控制 与 b e g i n T e m p = 'b1; #5 D o n e = T e m p; //语句间时延控制 e n d 相同。而语句 Q = @(p o s e d g e C l k ) D; //语句内事件控制 与 b e g i n T e m p = D; @ (p o s e d g e C l k) //语句间事件控制 Q = T e m p; e n d 相同。 r e p e a t(e x p r e s s) @ (e v e n t _ e x p r e s s i o n) 这种控制形式用于根据一定数量的 1个或多个事件来定义时延。例如, D o n e = r e p e a t(2) @ (n e g e d g e C l k A) A _ R E G + B _ R E G 这一语句执行时先计算右端的值,即 A _ R e g + B _ R e g 的值,然后等待时钟C l k A上的两个负沿,再将右端值赋给D o n e 。这一重复事件控制实例的等价形式如下: b e g i n T e m p = A_REG + B _ R E G @ (n e g e d g e C l k A) ; @ (n e g e d g e C l k A) ; D o n e = T e m p; e n d 这种形式的时延控制方式在给某些边或一定数量的边的同步赋值过程(语句)中非常有用。 (2) 阻塞赋值方式 b=a;(串行行为,如果左右不等右>左高位丢弃右<左高补零) 串行块中的各条阻塞型过程赋值语句将以它们在顺序块中的先后排列次序一次得到执行;而fork_join并行块中的各条阻塞型过程赋值语句则是同时得到执行的。 阻塞型过程赋值语句的执行过程是:首先计算右端赋值表达式的取值,然后立即将计算结果赋值给“=”左端的被赋值变量。 阻塞型过程赋值的这两个特点表明:仿真进程在遇到阻塞赋值过程赋值语句时将计算表达式的值并立即将其结果赋给等式左边的被赋值变量;在串行语句块中,下一条语句的执行会被本条阻塞型过程赋值语句所阻塞,只有在当前这条阻塞型过程赋值语句所对应的赋值操作执行完毕后下一条语句才能开始执行。 例:a, always@(posedge clk) begin b<=a; c<=b; end b, always@(posedge clk) begin b=a; c=b; end 阻塞赋值完成之后才执行非阻塞赋值,不要在同一个always块中混合使用阻塞和非阻塞赋值语句 (3)过程连续赋值(用于异步置位,异步清零)允许在有限时间段内将表达式的值连续地加(驱动)到寄存器或线网。过程连续赋值改写了寄存器或线网上现有值。过程连续赋值给一般过程赋值语句提供了一种有用的扩展。 A,assign和deassign用来表示第一类过程连续赋值语句。过程连续赋值状态下的寄存器忽视普通过程赋值语句对它的过程赋值操作。左值必须是寄存器或一个拼接的寄存器组,不能是线网类型变量的部分位选择,位选择或寄存器组。过程连续赋值语句可以改写常用的过程赋值的结果。过程连续赋值一般只用于受控制的一段时间。 B,force和release:既可以改写(覆盖)寄存器上的赋值也可以改写(覆盖)线网上的赋值(优先级高于assign),其典型的应用是在交互式调试过程中。此时,某些寄存器或线网被强制赋值,并且提示对其他寄存器和线网的影响。建议不要在设计模块的内部使用force和release语句,它们应当只出现在激励中,或仅作为调试语句。 4.延迟:从开始执行到执行完成的时间 外延迟(#5 y=x+z;)它推迟的是整个赋值语句的执行 内延迟(y=#5 x+z;)内嵌延迟首先立即计算右侧表达式的值推迟指定时间后,再将这个值赋予左侧变量 门级延迟例:and #(4,5,6) (上延迟,下延迟,关断延迟) And #(4,5) (上延迟,下延迟) min(4,5)为关断延迟 And #(4) (上延迟,下延迟,关断延迟) And #(3:4:5,5:6:7) 最小典型时延值,中等典型时延值,最大典型时延值,仿真时可选。 5.高级语言结构 (1) if (表达式) 语句;(表达式若为0,X或Z按“假”处理) if (表达式) 语句1; else 语句2; if(表达式1) else if(表达式2) else if(表达式3) else if(表达式m) else if和else后面可以包含一个内嵌的操作语句,也可以有多个操作语句,此时用begin_end关键词将几个语句包含起来成为一个复合块语句如下所示。 A,允许将if(expression)代替if(expression==1) B,else总是与它上面的最近的if配对,如果if与else的数目不一样,为了实现程序设计者的企图可用begin_end限定。 (2) case语句 通常用于微处理器的指令译码 Case(表达式) endcase Casez(表达式) endcase 不考虑Z状态 Casex(表达式) endcase 不考虑ZX状态 的一般语法格式 分支表达式:语句 缺省项(default):语句 上述提到的if和case 语句都只能应用于always语句内部如需要在always语句之外应用,则可采用assign data=(sel)?a:b; (3)forever 语句;forever begin 多条语句 end 常用于产生周期性的波形,用来作为仿真测试信号它与always语句不同之处在于它不能独立写在程序中,必须写在initial块中。 (4)repeat (表达式) 语句; Repeat (表达式) begin 多条语句 end 例 repeat(size) begin end (5) while (表达式) 语句; While (表达式) begin 多条语句 end (6) for(表达式1;表达式2;表达式3) 语句; 6.函数与任务 任务和函数都用来对设计中多处使用的公共代码进行定义。使用任务和函数可以将模块分割成许多个可独立管理的子单元,增强了模块的可读性和可维护性。它们和C语言中的子程序起着相同的作用。 (1) 任务 任务用于代替普通的verilog代码其中可以包括延迟时序事件等语法结构(注意:只有寄存器类的变量才能与任务的输出端口相对应) A,任务的定义(任务定义结构内不允许出现过程块(initial或always过程块)。注意只有寄存器类的变量才能与任务的输出端口相对应) Task [automatic] <任务名>;//automatic表示是否可重入 <端口及数据类型声明语句>如寄存器,时间,整数,实数和事件 <语句1> <语句n> Endtask; B,任务的调用及变量传递 <任务名>(端口1,端口2,端口n);//任务的调用只能出现在过程块内 (2) 函数 函数用于代替表示纯组合逻辑的verilog代码,在仿真时刻0就开始执行,只能有一个输出。因此函数一般用于完成各类转换和常用的计算。 A,函数定义语法 Function [automatic] [signed]<返回值的类型或范围>(函数名); <输入端口说明语句><局部变量说明>begin <语句> end Endfunction <返回值的类型或范围>这一项是可选项,如果缺省则返回值为一位寄存器类型数据。 函数的定义把函数返回值所赋值寄存器的名称初始化为与函数同名的内部变量。 输入端口说明语句的语法与模块定义时的输入端口说明语句的语法是一致的。 B,函数调用 <函数名><输入表达式> //(既能出现在过程块中,也能出现在assign连续赋值语句中) (3) 函数与任务对比说明 A,任务可以具有输入,输出和输入/输出(双向)变量,而函数输入只有输入变量。 B,可以在任务和函数中声明局部变量,如寄存器变量,时间,整数,实数和事件,但是不能声明线网类的变量。 C,在任务和函数中只能使用行为级语句,但是不能包含always和initial块。设计者可以在always块,initial块以及其他的任务和函数中调用任务和函数。 D,任务和函数都必须在模块内进行定义,其作用范围仅局限于定义它们的模块。在第一行中不能出现端口名列表。 E,可重入任务使用关键字automatic进行定义,它的每一次调用都对不同的地址空间进行操作。因此,在被多次并发调用时仍然可以获得正确的结果。 F,任务中可以使用延迟,事件和时序控制结构,在任务中可以调用其他的任务和函数,可使用disable终止语句,中断正在执行的任务,继而返回到调用任务的地方继续向下执行。函数中不能使用延迟,事件和时序控制结构,在函数中可以调用其它函数,但是不能调用任务,不允许使用disable终止语句; G,任务调用语句只能出现在过程块内,一条单独的任务调用语句实现,注意只有寄存器类的变量才能与任务的输出端口相对应。 H,函数调用时不能单独作为一条语句出现,它只能作为一个操作数出现在调用语句内,即可出现在过程块中,也能出现在assign连续赋值语句中。 6.门级建模 (1)and与or 门的端口列表中的第一个端口必定是输出端口,其后为输入端口,门级原语实例引用的时候可以不指定具体实例的名字也可以超过两个输入端口 例:and al(OUT,IN1,IN2); Nand nal_3inp(OUT,IN1,IN2,IN3); And (OUT,IN1,IN2); (2)buf/not 有一个标量输入和多个标量输出,输入端口必须是实例端口列表的最后一个,除buf/not门之外有4个贷有控制信号端口的buf/not门 例:bufif1 b1 (OUT,IN,CTRL) 7.用户自定义原语 例如and nand or nor 和not等,它们是该语言的一部分即通常所说的内置原语。UDP是自成体系的,在UDP中不能调用(实例引用)其他模块或者其他原语。 Primitive (输出端口名,输入端口名)//端口说明语句 Output <输出端口名>; Input <输入端口名>; Reg <输出端口名>;(可选只有表示时序逻辑的UDP才需要) //UDP初始化(可选只有表示时序逻辑的UDP才需要初始化) Initial <输出端口名>=<值> Table <状态表> Endtable Endprimitive UDP的定义规则 (1) UDP只能采用标量(即1位)输入端口,允许有多个输入端口 (2) UDP只能允许一个标量(即1位)输出端口。输出端口必须出现在端口列表的第一个位置,绝对不允许有多个输出端口 (3) 在声明部分,输出端口以关键字OUTPUT声明。因为表示时序逻辑的UDP需要保存状态所以其输出端口必须声明为reg类型。 (4) 输入端口以关键字input声明 (5) 表示时序逻辑的UDP中的状态可以用initial语句初始化,该语句是可选的,它将一个1位的值赋给reg类型的输出 (6) 状态表的项可以包含值0,1或X。UDP不能处理Z值。传送给UDP的Z值被当做X值 (7) UDP与模块同级,因而UDP不能在模块内部定义,但可以在模块内部调用(实例引用)。UDP的调用方法与门级原语的调用方法完全相同 (8) UDP不支持INOUT端口 例:primitive udp_and (out,a,b); Output out; Input a, b; Table // A b : out ; 0 0 : 0; 0 1 : 0; 1 0 : 0; 1 1 ; 1; Endtable Endprimitive 状态表注:?代表0,1,X 1. 状态表每一行中的顺序必须与它们在端口列表中的出现顺序相同 2. 输入和输出以“:”分隔 3. 状态表的每一行以“;”结束 4. 能够产生确定输出值的所有输入项组合都必须在状态表中列出。否则如果在状态表各行中找不到与这组输入对应的项,相应的输出就是X 表示时序逻辑的UDP (1) 表示时序逻辑的UDP的输出必须声明为reg类型 (2) 表示时序逻辑的UDP的输出可以用initial语句初始化 (3) 状态表的格式也稍有不同 <输入><输入i><输入N>:<当前状态>:<下一状态>; (4) 表示时序逻辑的UDP的状态表的每行由三部分组成分别是:输入部分,当前状态部分和输出状态部分 (5) 状态表的输入项可以是电平或者跳变沿的形式 (6) 当前状态就是输出寄存器的当前值 (7) 下一状态由输入和当前状态计算得出。下一状态的值就成为输出寄存器的新值 (8) 表示时序逻辑的UDP必须在状态表各行的输入项中列出所有可能的输入组合,以避免出现不确定的输出值。 注:-破折号表示保持原值不变 (10)代表输入的下降沿 (1X) (0?) 状态表的每行最多只能输入一个跳变沿 关于电平敏感的状态表的输入项,其优先级高于边沿敏感的状态表的输入项。若边沿敏感的输入项和电平敏感的输入项在同一个输入端口发生冲突则输出由电平敏感的状态表的输出项决定,因为它的优先级高于边沿敏感的状态表的输出项。 8,系统命令 (1)系统任务 有$的形式 $display(p1,p2,p3,….,pn); p1,p2,p3,….,pn是双引号括起来的字符串,变量或者表达式,会自动在字符串,变量或者表达式,会自动在字符串结尾处插入一个换行符 例:$display(“at time %d virtual address is %h”,$time,virtual_addr);//%m显示层次名 $monitor只需调用一次即可在整个仿真过程中生效,这一点与$display不同对参数列表中的变量值进行不间断的监视当其中任何一个发生变化的时候,显示所有参数的数值。(最后一次声明有效)。 $monitor on; $monitor off; 例:$monitor($time,”value of signals clock=%b reset=%b”,clock,reset); $stop $finishi用于结束仿真 (2) 编译指令 ` 例:`define WORD_SIZE 32 宏定义如C中#define `include “文件名”可以在编译期间将一个verilog源文件包含在另一个verilog文件中,类似C语言中的#include结构常用于将内容全局或公用定义的头文件包含在设计文件中在模块外部进行定义。 (3) 条件编译 `ifdef TEST `ifndef (条件编译标志可以用`define语句设置) `else `elseif `endif (4) 条件执行 $test$plusargs 例: if($test $plusargs(“DISPLAY_VAR”)) $display(“Display=%b”,{a,b,c}) ; Else $display(“No Display”); End 仅当在运行时设置了标志DISPLAY_VAR时才显示变量可以指定+DISPLAY_VAR选项在程序运行时设置标志 (4) 时间尺度 通常,在某次仿真中,一个模块中的延迟值需要用某个时间单位来定义比如1us.然而另一个模块中的延迟值需要用另一个时间单位来定义比如100ns,模拟器总是定位在所有模块的最小时延精度上,并且所有时延都相应地换算为最小时延精度。 `timescale/ 时间精度指定仿真过程中延迟值进位取整的精度 $time任务按照调用该任务的模块的参考时间单位报告仿真时间。 9.生成块 当对向量中的多个位进行重复操作时,或者当进行多个模块的实例引用的重复操作时或者在根据参数的定义来确定程序中是否应该包括某段verilog代码的时候,使用生成语句能够大大简化程序的编写过程。 Generate endgenerate 例:genvar j ; 生成变量的定义 Generate for(j=0;jout)=9; (b=>out)=9; (c=>out)=11; (d=>out)=11; Endspecify //是模块中的一个独立部分且不在任何其他块内出现 Specify块内部语句 (1) 并行连接=> =>=; (2) 全连接*> 描述源中的每一位和目标中的每一位之间的延迟 (3) 边沿敏感路径,用于输入到输出延迟的时序建模这种结构仅当源信号上出现特定边沿时才有用。例:(posedge clock=>(out+:in))=(10:8) 定义specparam常量,在specify内部使用。 11.时序检查 系统任务来进行时序检查的系统任务$setup $hold $width. $setup和$hold任务用来检查设计中时序元件的建立和保持约束。在时序元件(如边沿触发的触发器)中,建立时间是数据必须在有效时钟边沿之前到达的最小时间,保持时间是数据在有效时钟边沿之后保持不变的最小时间。 例:$setup(data_event,reference_event,limit); data_event 被检查的信号,检查它是否违反约束 reference_event 用于检查data_event信号的参考信号Limit需要的最小建立时间 同理 $hold (reference_event,data_event,limit); $width(reference_event,limit); Reference_event边沿触发事件(信号的边沿跳变)(上升沿和下降沿) Limit 脉冲最小宽度 12.使用Verilog HDL进行逻辑综合 逻辑综合是在 标准 excel标准偏差excel标准偏差函数exl标准差函数国标检验抽样标准表免费下载红头文件格式标准下载 单元库和特定的设计约束的基础上,把设计的高层次描述转换成优化的门级网表的过程。为了逻辑综合的目的,目前都在寄存器传输级RTL层次用硬件描述语言HDL编写设计。术语RTL用于表示HDL的一种风格,该风格的HDL描述采用了数据流和行为结构相结合的方式。逻辑综合工具接受寄存器传输级HDL描述并把它转化为优化的门级网表。 可进行逻辑综合的Verilog HDL结构 端口 input inout output 参数 parameter 模块定义 module 信号和变量 wire,reg,tri 允许使用向量表示 调用(实例引用)module instance,primitive gate instance 例如:mymux m1(out,i0,i1,s);nand(out,a,b); 函数和任务 function ,task 不考虑时序结构 过程 always,if,then,else,case,casex,casez 不支持initial 过程块 begin,end,named blocks,disable 命名块的禁止是允许的 数据流 assign 不考虑延迟信息 循环 for,while,forever while和forever循环必须包含@(posedge clock)或@(negedge clock) 因不支持initial结构的转换,因而设计者必须使用复位机制来取代initial结构,进行电路信号的初始化。建议明确地指定信号和变量宽度。定义未指定宽度的变量可能产生庞大的门级网表,因为综合工具可能根据变量定义生成不必要的逻辑。 只有= = =和!= =这种与X Z相关的操作符不能用于逻辑综合,因为等于逻辑值X 和Z在逻辑综合中没有实际的意义。编写表达式时,推荐使用圆括号来使逻辑更清晰,达到预期的目的。如果依赖操作符的优先级,逻辑综合工具有可能产生不尽人意的逻辑结构。 &逻辑综合建模技巧 (1) 使用有意义的信号和变量名称 (2) 避免混合使用上升沿和下降沿触发的触发器,可能在时钟树中引入反向器和缓冲器。一般不希望出现这种情况,因为这将在电路中引入时钟偏斜 (3) 使用基本构造模块与使用连续赋值语句的对比 连续assign语句是一种非常简洁的表示功能的方式,通常能生成性能很好的随机逻辑电路。然而,最终的逻辑结构并不一定是对称的。调用基本构造模块可以产生对称的设计,并且逻辑综合工具能够更高效地优化小模块。 (4) 调用多路选择器与使用if-else或者case语句的对比如果需要结构化的实现,最好直接使用多路选择器来实现模块,因为if-else或者case语句可能使综合工具产生不可预期的随机逻辑。调用多路选择器的方式更容易控制,综合速度也更快,但它存在依赖于工艺的不利因素,并且表达多路选择器的代码比较长。另一方面,if-else和case语句可以简洁地表示多路选择器,常用于建立不依赖工艺的RTL描述。 (5) 使用圆括号优化逻辑结构 (6) 使用算术操作符* 、 和%与使用现有构造模块的对比。* / %操作在逻辑和面积上的实现代价很高。然而,这些算术操作符能够以不依赖于工艺的简明方式实现所需的功能。另一方面,设计自定义模块来完成乘除和取模操作,可能要花费大量的时间,并且RTL描述会变得与工艺相关。 (7) 注意多条赋值语句对同一个变量赋值的情况 (8) 显示地定义if-else或者case语句。在if-else或者case语句中必须说明各种可能的条件分支,否则可能产生电平敏感的锁存器,而不是多路选择器。 D Q clk D Q clk a b c clk D Q clk a b c clk
本文档为【Verilog】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑, 图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
该文档来自用户分享,如有侵权行为请发邮件ishare@vip.sina.com联系网站客服,我们会及时删除。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。
本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。
网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。
下载需要: 免费 已有0 人下载
最新资料
资料动态
专题动态
is_760641
暂无简介~
格式:doc
大小:104KB
软件:Word
页数:16
分类:互联网
上传时间:2013-04-13
浏览量:51