EDA总结

更新时间:2024-05-04 04:48:01 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

一.CPLD和FPGA的主要区别

1. 结构上的不同:CPLD-乘积项 FPGA-基于查找表(LUT) 2. 集成度的不同

CPLD:500 - 50000门;FPGA:1K – 几千万门 3 应用范围的不同

CPLD逻辑能力强而寄存器少(1K左右), 适用于控制密集型系统;FPGA逻辑能力较弱但寄存器多,适于数据密集型系 CPLD CPLD逻辑密集型----适于简单逻辑功能 逻辑密集型----适于简单逻辑功能2、中小规模(1000 ~ 50000) 2、中小规模(1000 ~ 50000)3、布线延迟固定,时序特性稳定 3、布线延迟固定,时序特性稳定4、编程数据不丢失,电路简单 4、编程数据不丢失,电路简单5、保密性好 5、保密性好 HDL功能: HDL功能 数字系统设计、综合(部分语法支持)

二.Verilog HDL适用的描述层次:

1、系统级(System) 部分可物理实现,主要用于仿真 2、算法级(Alogrthem) 部分可物理实现,主要用于仿真 3、寄存器传输级(RTL)可完全物理实现,用于电路设计 4、逻辑级(Logic) 可完全物理实现,用于电路设计 5、门级(Gate) 可完全物理实现,用于电路设计

6、电路开关级(Switch)软件中不涉及,用于芯片设计

三.电路的两种基本计算机输入方式——原理图输入和硬件描述语言输入 四.语言输入与原理图输入方式相比的优点: 1、容易把设计移植到不同厂家的不同芯片中去;

2、信号位数容易修改,可以很方便的适应不同规模的应用; 3、与实现工艺无关;Verilog HDL综合器生成标准的电子设计互换格式(EDIF)文件,方便文档交换与保存;

FPGA 1、数据密集型——适于复杂的时序逻辑 2、大规模设计(5000 ~ 数百万门) 3、布线灵活,但时序特性不稳定 4、需用专用的 ROM 进行数据配置 5、保密性较差 数字系统仿真、验证(全部语法支持) 五.软核、固核、硬核的概念 软核(Soft Core):功能经过验证的、可综合的、实现后电路结构总门数在5000门以上

的Verilog HDL模型。由软核构成的器件称为虚拟器件。三者中灵活性最高。 固核(Firm Core):指在某一种现场可编程门阵列(FPGA)器件上实现的、经验证是正确的、总门数在5000门以上电路结构编码文件。 硬核(Hard Core):指在某一种专用集成电路(ASIC)工艺的器件上实现的、经验证是正确的、总门数在5000门以上的电路结构版图掩膜

六.Verilog的两种描述——如果只从行为和功能的角度来描述某一电路模块,就称为行为模块;如果从电路结构的角度来描述该电路模块,就称为结构模块。 七.综合的概念——Verilog模块(程序)通过计算机上运行的综合软件工具(属EDA软件)把行为描述通过逻辑表达式的中间形式自动转换为结构描述的模块,这个过程叫做综合(Synthesis)。

八.元件例化(层次设计方法)——这种引用现成元件或模块的方法叫做实例化或实例引用,是表示电路构造的一种常用语法现象。 例子

module trist1(sout,sin,ena);

output sout; input sin,ena;

mytri tri_inst(.out(sout), .in(sin), .enable(ena)); endmodule

module mytri(out,in,enable); output out; input in,enable;

assign out=enable ? in: ‘bz; Endmodule

九.在模块中产生逻辑的3种方法

用“assign”连续赋值语句

用元件例化方法(即元件调用)

用“always”块

用input定义的端口信号没有类型说明,只有output定义的信号和内部信号具有wire、reg类型声明要求。信号定义为output类型时默认隐含为wire型。

十.常量

1.整型常量有4种进制表示形式: 二进制整数(b或B),

十进制整数(d或D),

十六进制整数(h或H), 八进制整数(o或O)。

2.数字表达方式有以下3种:1) <位宽><进制><数字> 这是一种全面的描述方式。 2) <进制><数字> 数字的位宽采用缺省位宽(这由具体的机器系统决定,但至少32位)。

3) <数字>采用缺省进制(十进制),位宽采用缺省位宽。 3.位宽始终表示的是二进制位数,与进制符号无关。

4.在一个模块中改变另一个模块的参数时,使用defparam命令。

十一.变量

1.Wire型

说明:(1)wire网络数据类型表示结构实体(例如门)之间的物理连接。

(2)网络类型的变量不能储存值,而且它必须受到驱动器的驱动。如果没有驱动器连接到网络类型的变量上,则该变量就是高阻的,即其值为z。

(3)wire型数据常用来表示以assign关键字指定的组合逻辑信号。

(4)Verilog程序模块中输出信号类型默认时自动定义为wire型。wire型信号可以用做任何方程式的输入,也可以用做“assign”语句或实例元件的输出。

2.reg型

说明:(1)reg型是寄存器数据类型。

(2)reg类型数据的默认初始值为不定值x。

(3)reg型数据常用来表示“always”模块内的指定信号,常代表触发器。(4)在\”块内被赋值的每一个信号都必须定义成reg型。

(4)reg型信号并不一定是寄存器或触发器的输出,它只表示被定义的信号将用在“always”块内。而当reg型信号确实是寄存器或触发器的输出时,只有always块或initial块可以操作该类型信号

3.memory型

说明:(1)Memory型即存储器类型; (2)Verilog HDL通过对reg型变量建立数组来对存储器建模,可以描述RAM型存储器,ROM存储器和reg文件。

(3)数组中的每一个单元通过一个数组索引进行寻址。 (4)在Verilog语言中没有多维数组存在。

(5)memory型数据的格式如下:

reg [n-1:0] 存储器名 [m-1:0] 或 reg [n-1:0] 存储器名 [m:1]

说明:reg [n-1:0]定义了存储器中每一个存储单元的大小,即该存储单元是一个n位的寄存器,存储器名后的[m-1:0]或[m:1]则定义了该存储器中有多少个这样的寄存器,最后用分号结束定义语句。

(6)一个由n个1位寄存器构成的存储器组是不同于一个n位的寄存器的,一个n位的寄存器可以在一条赋值语句里进行赋值,而一个完整的存储器则不行,如果想对memory中的存储单元进行读写操作,必须指定该单元在存储器中的地址。

十二.运算符及表达式

1. 基本的算术运算符

规则:(1)在进行整数除法运算时,结果值要略去小数部分,只取整数部分;

(2)进行取模运算时,结果值的符号位采用模运算式里第一个操作数的符号位。 (3)在进行算术运算操作时,如果某一个操作数有不确定的值x,则整个结果也为不定值x。

2. 位运算符

1) 取反(~) 2)按位与(& )

3)按位或(|) 4)按位异或( ^ )

5)按位同或( ^ ~)

注意:不同长度的数据进行位运算;系统自动的将两者按右端对齐。位数少的操作数会在相应的高位用0填满,以使两个操作数按位进行操作。

十三.运算符、赋值语句和结构说明语句

1.逻辑运算符

(1) &&逻辑与; (2) ||逻辑或; (3) !逻辑非。

2.关系运算符

关系运算符共有以下4种:(1) ab —a大于b(3) a<=b—a小于或等于b (4) a>=b —a大于或等于b

关系为假(flase),则返回值是0;关系为真(true),则返回值是1;如果某个操作数的值不定,则关系是模糊的,返回值是不定值x 3.等式运算符

(1) ==(等于); (2) !=(不等于); (3) ===(等于); (4) !==(不等于)。

注意:(1)“==”和“!=”又称为逻辑等式运算符,其结果由两个操作数的值决定。由于操作数中某些位可能是不定值x和高阻值z,结果可能为不定值x。

(2)“===”和“!==”运算符在对操作数进行比较时对不定值x和高阻值z也进行比较,两个操作数必须完全一致,其结果才是1,否则为0。“===”和“!==”运算符常用于case表达式的判别,所以又称为“case等式运算符”。关键点:结果不会出现x,只能是1或0。

if(A==1’bx) $display(“A is X”); (当A等于x时,这个语句不执行) if(A===1’bx) $display(“A is X”); (当A等于X时,这个语句执行)

4.移位运算符

“<<”(左移位运算符)和“>>”(右移位运算符)。 左移位宽增加,右移位宽不变 5.位拼接运算符

用这个运算符可以把两个或多个信号的某些位拼接起来进行运算操作。其使用方法如下: {信号1的某几位,信号2的某几位,??信号n的某几位}

即把某些信号的某些位详细地列出来,中间用逗号分开,最后用大括号括起来表示一个整体信号。

6.缩减运算符

缩减运算是对单个操作数进行与、或、异或、同或等的递推运算,最后的运算结果是1位的二进制数。

缩减运算的具体运算过程是:(1)先将操作数的第1位与第2位进行与、或等运算;(2)将运算结果与第3位进行与、或等运算,依次类推,直至最后1位。 7.运算符优先级

非运算(! ~ ) 》算术运算符(* / % + - ) 》移位运算符(<< >>)》关系运算符(< <= > >=)》等号运算符(== != === !==)》位运算符(& ^ ^~ | )》逻辑运算符(&& || )》条件运算符( ?: ) 8.赋值语句

(1)非阻塞赋值“<=”:

●在语句块中,上面语句所赋的变量值不能立即就为下面的语句所用; ●块结束后才完成赋值操作,块结束前被赋值的变量保持上一次所赋的值;

●在编写可综合的时序逻辑模块时,这是最常用的赋值方法。意即,在always块中经常使用。

(2)阻塞赋值“=”:

●赋值语句执行完后,块才结束;

●b的值在赋值语句执行完后立刻就改变;

●在时序逻辑中使用时(在沿触发的always块中使用时),综合后可能会产生意想不到的结果。 9.块语句

(1)顺序块:begin_end块

●块内的语句是按顺序执行的,即只有上面一条语句执行完后下面的语句才能执行。 ●每条语句的延迟时间是相对于前一条语句的仿真时间而言的。 ●直到最后一条语句执行完,程序流程控制才跳出该语句块。

(2)并行块:fork_ join块

●块内语句是同时执行的,即程序流程控制一进入到该并行块,块内语句则开始同时并行地执行。

●块内每条语句的延迟时间是相对于程序流程控制进入到块内的仿真时间。 ●延迟时间是用来给赋值语句提供执行时序的。

●当按时间时序排序在最后的语句执行完后或一个disable语句执行时,程序流程控制跳出该程序块 (3)块名

这样做的原因有以下几点:1)可以在块内定义局部变量,即只在块内使用的变量;2)可以允许块被其他语句调用,如disable语句;3) 块名提供了一个在任何仿真时刻确认变量值的方法。

(4)起始时间和结束时间

对于顺序块,起始时间就是第一条语句开始被执行的时间,结束时间就是最后一条语句执行完的时间;

对于并行块,起始时间对于块内所有的语句是相同的,即程序流程控制进入该块的时间,其结束时间是按时间排序在最后的语句执行结束的时间。 当一个块嵌入另一个块时,块的起始时间和结束时间是很重要的。跟在块后面的语句在该块的结束时间到了才能开始执行,也就是说,只有该块完全执行完后,后面的语句才可以执行。

十四.条件语句、循环语句、块语句与生成语句

1.条件语句(if_else语句)

1)if(表达式)语句

2)if(表达式)

语句1; else

语句2; (3)if(表达式) 语句1; else if(表达式2) 语句2; else if(表达式3) 语句3; ??

else if(表达式m) 语句m; else 语句n;

注意:条件语句必须在过程块语句中使用。所谓过程块语句是指由initial和always语句引导的执行语句集合。除了这两种块语句引导的begin end块中可以编写条件语句外,模块中的其他地方都不能编写

说明:

1)if语句在if后面都有“表达式”,一般为逻辑表达式或关系表达式。系统对表达式的值进行判断,若为0,x,z,按“假”处理;若为1,按“真”处理,执行指定的语句 2)第2)、3)种形式的if语句,在每个else前面有一个分号,整个语句结束处有一个分 3)允许一定形式的表达式简写方式。如下面的例子:

if(expression) 等同与 if(expression==1) if(!expression) 等同与 if(expression!=1) (5)if语句的嵌套。在if语句中又包含一个或多个if语句称为if语句的嵌套。一般形式如下:

if(epression1)

if(expression2) 语句1;(内嵌if) else 语句2; else

if(expression3) 语句3;(内嵌if) else 语句4; else总是与它上面最近的if配对 2.case语句

一般形式如下:

(1) case (表达式) endcase (2) casez (表达式) endcase (3) casex (表达式) endcase case(?)

分支表达式1: 语句; 分支表达式2: 语句;

默认项(default项): 语句; endcase 说明:

1)case括弧内的表达式称为控制表达式,case分支项中的表达式称为分支表达式。 2)当控制表达式的值与分支表达式的值相等时,执行分支表达式后面的语句。如果所有的分支表达式的值都没有与控制表达式的值相匹配,就执行default后面的语句。 3)一个case语句里只准有一个default项。对于default项:

若分支表达式将所有情况列出,可不写default项;若有未列出的可能值,应写default项。 4)每一个case分项的分支表达式的值必须互不相同,否则就会出现矛盾(对表达式的同一个值,有多种执行方案)。

5)执行完case分项后的语句,则跳出该case语句结构,终止case语句的执行。(注:与C语言不同,Verilog中的case语句不需要写break) 6)在用case语句表达式进行比较的过程中,只有当信号的对应位的值能明确进行比较时,比较才能成功。因此,要注意详细说明case分项的分支表达式的值。

7)case语句的所有表达式值的位宽必须相等,只有这样,控制表达式和分支表达式才能进行对应位的比较。一个经常犯的错误是用’bx,’bz来替代n’bx,n‘bz,这是不对的,因为信号x,z的默认宽度是机器的字节宽度,通常是32位(此处n是case控制表达式的位宽)。 3.case语句与if_else_if语句的区别: (1)if_else_if结构中的条件表达式更为直观。

(2)对于那些分支表达式中存在不定值x和高阻值z的位时,case语句提供了处理这种情况的手段。

(3)if语句具有优先级,可用于描述具有优先级的电路;case语句不具有优先级,只能用于描述无优先级的电路。

要点:

1.在\块内,如果在给定的条件下变量没有赋值,这个变量将保持原值,也就是说会生成一个锁存器。

2.为避免产生不必要的锁存器,应遵循下面两个原则: 1)、如果用到if语句,最好写上else项;2)、如果用case语句,最好写上default项。 4.循环语句 1)forever语句 格式如下:

forever 语句; 或

forever begin

多条语句

end

forever循环语句常用于产生周期性的波形,作为仿真测试信号。它与always语句不同之处在于它不能独立写在程序中,而必须写在initial块中。 2)repeat语句

repeat语句的格式如下:

repeat(表达式) 语句; 或

repeat(表达式) begin

多条语句 end

在repeat语句中,其表达式通常为常量表达式。 3)while语句

while语句的格式如下: while(表达式) 语句

while(表达式)

begin

多条语句 end 4)for语句

for语句的一般形式为:

for(循环变量赋初值;循环结束条件;循环变量增值) 执行语句;

十五.结构说明语句

initial语句只执行一次,而always语句则是不断地重复活动着,直到仿真过程结束。 无条件的always语句是不允许的,将造成仿真死锁!如:always clock=~clock;) 1. initial语句 initial语句的格式如下: initial

begin

语句1; 语句2; ?? 语句n;

end

(1)用initial 块对存储器变量赋初始值 initial begin

areg=0; //初始化寄存器areg

for(index=0;index

(2)用initial语句来生成激励波形

initial

begin

inputs=’b000000; //初始时刻为0 #10 inputs=’b011001; #10 inputs=’b011011; #10 inputs=’b011000; #10 inputs=’b001000; end

2. always语句

声明格式如下: always <时序控制> <语句>

要点:

always的时间控制可以是边沿触发也可以是电平触发;

可以是单个信号也可以是多个信号,当有多个信号时中间需要用关键字or连接。

要点:

沿触发的always块用于描述时序逻辑,如有限状态机; 电平触发的always块用来描述组合逻辑。 3. task和function说明语句

task和function说明语句的不同点

(1) 函数只能与主模块共用同一个仿真时间单位,而任务可以定义自己 的仿真时间单位。

(2) 函数不能启动任务,而任务能启动其他任务和函数。

(3) 函数至少要有一个输入变量,而任务可以没有或有多个任何类型的 输入变量。

(4) 函数返回一个值,而任务则不返回值。 (5) task和function的调用方法不同

16位字字节互换任务的调用为:switch_bytes(old_word,new_word); 16位字字节互换函数的调用为:new_word=switch_bytes(old_word); 4.task说明语句

(1)任务的定义。定义任务的语法如下:

task <任务名>;

<端口及数据类型声明语句> <语句1>

<语句2> ?? <语句n>

endtask (2)任务的调用及变量的传递

启动任务并传递输入,输出变量的声明语句的语法如下: 任务的调用:

<任务名> (端口1,端口2,?,端口n); 5.function说明语句 (1)定义函数的语法:

function <返回值的类型或范围> (函数名);

<端口说明语句>

<变量类型说明语句> begin <语句> ?? end

endfunction

注意:<返回值的类型或范围>这一项是可选项,如缺省则返回值为一位寄存器类型数据。 (2)从函数返回的值:

函数的定义隐含声明了与函数同名的内部寄存器。

如在函数的声明语句中<返回值的类型或范围>为缺省,则这个寄存器是一位的,否则是与函数定义中<返回值的类型或范围>一致的寄存器。 (3)函数的调用:

函数的调用是通过将函数作为表达式中的操作数来实现的。其调用格式如下:

变量=<函数名> (<表达式>, <表达式>, ??);

其中,函数名作为确认符。 (4)函数的使用规则:

●函数的定义不能包含有任何的时间控制语句,即任何用#、@或wait 来标识的语句;

●函数不能启动任务;

●定义函数时至少要有一个输入参数;

●在函数的定义中必须有一条赋值语句给函数的一个内部变量赋结果 值,该内部变量和函数同名。 (5)函数的使用举例 1.奇偶校验位 1)偶校验

偶校验——数据中“1”的个数为偶数的时候,这个校验位就是“0”,否则这个校验位就是“1”。即加上校验位,1的个数始终为偶数。 module parity; reg [31:0] addr;

reg parity; initial begin

addr=32’h3456_789a; #10 addr=32’hc4c6_78ff; #10 addr=32’hff56_ff9a; #10 addr=32’h3faa_aaaa

end

//每当地址值发生变化,计算新的偶校验位 always @(addr) bein

parity=calc_parity(addr);

$display(“Parity calculated=%b”,cal_parity(addr)); end

//定义偶校验计算函数 function calc_parity;

input [31:0] address; begin

calc_parity= ^address;//返回所有地址位的异或值 end endfunction endmodule 2)奇校验

2.左/右移位寄存器

module shifter;

`define LEFT_SHIFT 1’b0 `define RIGHT_SHIFT 1’b1 reg [31:0] addr,left_addr,right_addr; reg control; always @(addr)

begin

left_addr=shift(addr,`LEFT_SHIFT); right_addr=shift(addr,`RIGHT_SHIFT); end

function [31:0] shift; input [31:0] address; input control;

begin

shift=(control==`LEFT_SHIFT)?(address<<1):(address>>1); end

endfunction endmodule

6.常用的系统任务

(1)$display和$write任务

格式:

$display(p1,p2,?,pn); $write(p1,p2,?,pn);

这两个函数和系统任务是用来输出信息,即将参数p2~pn按参数p1给定的格式输出。参数p1通常称为“格式控制”,参数p2~pn通常称为“输出表列”。这两个任务的作用基本相同。

$display自动地在输出后进行换行,$write则不进行自动换行。如果想在一行里输出多个信息,可以使用$write。在$display和$write中,其输出格式控制是用双引号括起来的字符串。 输出数据的显示宽度:

可以通过在%和表示进制的字符中间插入一个0,便自动调整显示输出数据宽度的方式。见下例:

$display(“d=%0h a=%0h”,data,addr);

这样在显示输出数据时,在经过格式转换以后,总是用最少的位数来显示表达式的当前值。 如果输出列表中表达式的值包含有不确定的值或高阻值,其结果输出遵循以下规则。 ●如果表达式值的所有位均为不定值,则输出结果为小写的x;部分位为不定制,则输出大写的X;

●如果表达式值的所有位均为高阻值,则输出结果为小写的z;部分位为高阻值,则输出大写的Z。

在输出格式为十六进制和八进制的情况下,每个x或z表示每4位或每3位的二进制数: 对于二进制输出格式,表达式值的每一位的输出结果为0、1、x、z。下面举例说明: $display(‘‘%d”,1’bx); x $display(“%h”,14’bx0_1010); xxXa $display(“%h%o”,12’b001x_xx10_1x01,12’b001_xxx_101_x01); XXX 1x5X

7.选通显示

$strobe系统任务

$strobe系统任务与$display使用方法相同。 它们之间的区别在于:

如果许多其他语句与$display任务在同一个时间单位执行,那么这些语句与$display任务的执行顺序是不确定的。

而$strobe总是在同时刻的其他赋值语句执行完成后才执行。 always @(posedge clock) begin a=b; c=d; end

always @(posedge clock)

$strobe(“Displaying a=%b,c=%b”,a,c); //在a、b被赋值后才执行

十六.调试用系统任务和常用编译预处理语句

1 系统任务$monitor

格式:

$monitor(p1,p2,?,pn);

作用:监控和输出参数列表中的表达式或变量值。其参数列表的规则和$display一样。 每当参数列表中变量或表达式的值发生变化时,将自动输出显示。 在$monitor中,参数可以是$time系统函数。

$monitor($time,,“rxd=%b txd=%b”,rxd,txd); 注:, ,表示空参数,显示为空格。

$monitor与$display的不同之处还在于$monitor往往在initial块中调用,只要不调用$monitoroff,$monitor便不间断地对其所设定的信号进行监视。

2 时间度量系统函数$time

1)系统函数$time(整型时间值)

$time可以返回一个以64位的整数来表示当前的仿真时刻值。该时刻是以模块的仿真时间尺度为基准的。下面举例说明。

`timescale 10 ns/1ns//表示时间长度的具体值,精确到0.1ns module test; reg set;

parameter p=1.6; initial

begin

$monitor($time,,“set=”,set); #p set=0; #p set=1; end

endmodule 输出结果为: 0 set=x

2 set=0

3 set=1

2)$realtime系统函数

$realtime和$time的作用是一样的,只是$realtime返回的时间数字是一个实型数,该数字也是以时间尺度为基准的。下面举例说明: `timescale 10ns/1ns module test;

reg set;

parameter p=1.55;//先四舍五入 Initial //再延迟 begin

$monitor($realtime,,“set=”,set); #p set=0: #p set=1; end endmodule

3 系统任务$random

该函数返回一个32位的随机数,它是一个带符号的整型数。

$random一般的用法是:$random%b,其中b>0。它给出了一个范围在(-b+1):(b-1)中的随机数。下面给出一个产生随机数的例子: reg [23:0]rand; rand=$random%60;

上面的例子给出了一个范围在-59到59之间的随机数,下面的例子通过位拼接操作产生一个值在0~59之间的数。

reg[23:0]rand; rand={$random}%60; 拼接运算是相对于无符号数而言的

4 编译预处理

1宏定义'define

用一个指定的标识符(即名字)来代表一个字符串,它的一般形式为: `define标识符(宏名) 字符串(宏内容)

这种方法使用户能以一个简单的名字代替一个长的字符串,也可以用一个有含义的名字来代替没有含义的数字和符号,因此把这个标识符(名字)称为“宏名”。在编译预处理时将宏名替换成字符串的过程称为“宏展开”。`define是宏定义命令。 2“文件包含”处理'include

所谓“文件包含”处理是一个源文件可以将另外一个源文件的全部内容包含进来,即将另外的文件包含到本文件之中。Verilog HDL语言提供了'include命令来实现“文件包含”的操作。其一般形式为: `include “文件名” 3 时间尺度timescale

`timescale命令用来说明跟在该命令后的模块的时间单位和时间精度。 `timescale命令的格式如下:`timescale<时间单位>/<时间精度>

如果在同一个程序设计里,存在多个’timescale命令,则用最小的时间精度值来决定仿真的时间单位。另外时间精度至少要和时间单位一样精确,时间精度值不能大于时间单位值。 在`timescale命令中,用于说明时间单位和时间精度参量值的数字必须是整数,其有效数字为1,10,100,单位为s,ms,us,ns,ps,fs `timescale命令的用法

`timescale 1ns/1ps;

在这个命令之后,模块中所有的时间值都表示是1 ns的整数倍。这是因为在‘timescale命令中,定义了时间单位为1 ns。模块中的延迟时间可表达为带3位小数的实型数,因为’timescale命令定义时间精度为1 ps。 9.1 门级结构描述

8个基本的门类型关键字和它们所表示的门的类型: and —— 与门; nand —— 与非门; nor —— 或非门; or —— 或门; xor —— 异或门; xnor ——同或门;

buf —— 缓冲器; not —— 非门。 门声明语句的格式如下:

<门的类型>[<驱动能力><延时>]<门实例1>[,<门实例2>,?,<门实例n>]; 门的类型是门声明语句所必须的,驱动能力和延时是可选项。 例如:

nand #10 nd1(a,data,clock,clear);

该例说明在模块中使用了一个名为nd1的与非门(nand),输入为data、clock和clear,输出为a,输出与输入的延时为10个单位时间。 用触发器组成带清零端的4位寄存器。 `include “flop.v”

module hardreg(d,clk,clrb,q); Input clk,clrb;

input [3:0] d; output [3:0] q;

flop f1(d[0],clk,clrb,q[0],), //注意结束时用逗号,最后才用分号 f2(d[1],clk,clrb,q[1],), //表示f1到f4都是flop f3(d[2],clk,clrb,q[2],), f4(d[3],clk,clrb,q[3],); endmodule

module flop(data,clock,clear,q,qb); input data,clock,clear;

output q,qb;

nand #10 nd1(a,data,clock,clear), //注意结束时用逗号,最后才用分号 nd2(b,ndata,clock),//表示nd1到nd8都是nand(与非门) nd4(d,c,b,clear), nd5(e,c,nclock), nd6(f,d,nclock), nd8(qb,q,f,clear); nand #9 nd3(c,a,d),

nd7(q,e,qb); not #10 iv1(ndata,data),

iv2(nclock,clock); endmodule

用行为描述的方法来描述带清零端的4位寄存器。

module hardreg(d,clk,clrb,q);

input clk,clrb; input [3:0] d; output [3:0] q; reg [3:0]q;

always @(posedge clk or posedge clrb) begin

if(clrb)

q<=0; else

q<=d;

end endmodule

10.1 加法器

4位并行加法器:

module add_4(X,Y,sum,C); input [3:0] X,Y; output[3:0] sum; output C;

assign {C, sum}=X+Y; endmodule

16位并行加法器:

module add_16(X,Y,sum,C); input [15:0] X,Y; output [15;0] sum; output C;

assign {C, sum}=X+Y; endmodule

10.2 乘法器

4位乘法器

module mult_4(X,Y,Product); input [3:0] X,Y; output [7:0] Product; assign Product=X*Y; endmodule

8位乘法器:

module mult 8(X,Y,Product); input [7:0] X,Y;

output [15:0] Product; assign Product=X*Y; endmodule

10.3 比较器

module compare_n (X,Y,XGY,XSY,XEY); else XEY=0; input [width-1:0] X,Y; if(X>Y) output XGY, XSY,XEY; XGY=1; reg XGY, XSY, XEY; parameter width=8; always @(X or Y) begin

if(X==Y) XEY=1; 10.4

else XGY=0; if(X

XSY=1; else XSY=0; end endmodule

多路选择器

module Mux_8(addr,in1,in2,in3,in4,in5,in6,in7,in8,Mout,nCS); input [2:0] addr;

input [with-1:0] in1,in2,in3,in4,in5,in6,in7,in8;

input nCS;

output [wdth-1:0] Mout; reg [wdth-1:0] Mout; parameter with=8;

always@ (addr or in1 or in2 or in3 or in4 or in5 or in6 or in7 or in8 or nCS) begin

if(!nCS) //nCS低电平使多路选择器工作 case(addr)

3’b000: Mout=in1; 3’b001: Mout=in2; 3’b010: Mout=in3; 3’b011: Mout=in4; 3’b100: Mout=in5; 3’b101: Mout=in6; 3’b110: Mout=in7; 3’b111: Mout=in8;

endcase

else //nCS高电子关闭多路选择器 Mout=0; end endmodule 10.6

流水线

提高速度的有效方法:在已设计好的数字逻辑中插入寄存器,形成流水线,可以大大提高处理速度。

流水线加法器和组合逻辑加法器的比较:

16位全加器

组合逻辑加法器:占用34个宏单元,总延迟45.6ns 流水线加法器:占用81个宏单元,总延迟15.1ns

运算吞吐量增加了3倍!

重要概念: 数字系统设计中的一个矛盾问题:面积 —— 速度

第12章 同步状态机的原理、结构和设计

1.什么是有限状态机

- 有限状态机是由寄存器组和组合逻辑构成的硬件时序电路;

- 其状态(即由寄存器组的1和0的组合状态所构成的有限个状态)只能在同一时钟跳变沿的情况下才能从一个状态转向另一个状态;

- 究竟转向哪一状态不但取决于各个输入值,还取决于当前状态。

- 状态机可用于产生在时钟跳变沿时刻开关的复杂的控制逻辑,是数字逻辑的控制核心。 2.Moore状态机

定义:如果时序逻辑的输出只取决于当前的状态,称之为Moore状态机。

结构:

高速状态机设计方法

1.在设计高速电路时,把状态变量直接用作输出

2.在输出逻辑G后面再加一组与时钟同步的寄存器输出流水线寄存器,即完全同步地输出,这种输出称为流水线化的输出(Pipelined outputs)的Mealy状态机。 要点:

对于用FPGA实现的有限状态机建议采用独热码。因为虽然独热编码多用了两个触发器,但所用组合电路可省一些,因而使电路的速度和可靠性有显著提高,而总的单元数并无显著增加。

采用独热编码后出现多余的状态,即一些不可到达的状态,因此,在case语句的最后需要增加default分支项。 有限状态机设计的一般步骤:

(1)逻辑抽象,得出状态转换图;——手工完成

(2)状态化简;——手工或计算机完成

如果在状态转移图中出现这样两个状态:它们在相同的输入下转换到同一状态去,并得到相同的输出,则称它们为等价状态。等价状态是重复的,可以合并为一个。 (3)状态分配(状态编码);——手工完成

在触发器资源丰富的FPGA或ASIC设计中,采用独热编码(one-hot-coding)。 (4)选定触发器的类型并求出状态方程、驱动方程和输出方程。——计算机完成 (5)按照方程得出逻辑图。——计算机完成

13.1Verilog HDL设计可综合的状态机的指导原则

1、在采用FPGA设计状态机时最好用One—Hot编码;采用CPLD器件设计状态机时采用顺序编码方式(自然二进制数);

2、采用case、casex或casez语句建立状态机模型,注意Default项,并将状态变量设为初始状态或’bx;

3、状态机应该有一个异步或同步复位端,以便在加电时将电路复位到有效状态,CPLD/FPGA器件都支持异步复位;

4、状态转换只能由一个时钟控制,即设计为同步状态机,否则综合工具将生成错误电路。 5、如果一定要设计异步状态机,建议采用电路图输入的方法,或用实例引用的写法把几个引用的实例用异步时钟连接起来,而不要直接用Verilog RTL级别的描述方法通过综合来产生。

本文来源:https://www.bwwdw.com/article/37ig.html

Top