Verilog HDL 及Modelsim仿真

Slides:



Advertisements
Similar presentations
高级服务器设计和实现 1 —— 基础与进阶 余锋
Advertisements

Introduction to Verilog
实验四 利用中规模芯片设计时序电路(二).
Oracle数据库 Oracle 子程序.
C++中的声音处理 在传统Turbo C环境中,如果想用C语言控制电脑发声,可以用Sound函数。在VC6.6环境中如果想控制电脑发声则采用Beep函数。原型为: Beep(频率,持续时间) , 单位毫秒 暂停程序执行使用Sleep函数 Sleep(持续时间), 单位毫秒 引用这两个函数时,必须包含头文件
在PHP和MYSQL中实现完美的中文显示
Greatest Common Divisor ---最大公约数
第10章 Verilog操作符 学习内容: 熟悉Verilog语言的操作符.
Chapter 5 Verilog 硬體描述語言
Chapter 5 Verilog硬體描述語言
EBNF 请用扩展的 BNF 描述 C语言里语句的结构; 请用扩展的 BNF 描述 C++语言里类声明的结构;
Verilog HDL 数字系统设计及实践 第5章 时序逻辑建模.
Ch01-2 Verilog語法 資料流(DataFlow)設計 行為(Behavior)設計
第17章 Verilog中的高级结构 学习内容: 任务和函数的定义和调用 怎样使用命名块 怎样禁止命名块和任务 有限状态机(FSM)及建模.
EDA技术 廖义奎.
第四阶段实验 ISP器件的设计与应用 一、实验目的 二、实验内容与要求 三、ISP器件的开发流程 四、EDA Pro2K实验系统介绍
FPGA设计.
管理信息结构SMI.
走进编程 程序的顺序结构(二).
辅导课程六.
网络常用常用命令 课件制作人:谢希仁.
第四阶段实验 Verilog HDL简介 1 Verilog描述的一般结构 2 Verilog HDL基础知识 3 设计举例
第一单元 初识C程序与C程序开发平台搭建 ---观其大略
Verilog 数字系统设计教程 -- 建模、仿真、综合、验证和实现 -- 北京航空航天大学 夏宇闻 2004年版.
第十章 IDL访问数据库 10.1 数据库与数据库访问 1、数据库 数据库中数据的组织由低到高分为四级:字段、记录、表、数据库四种。
以ISI平台为例,为您演示一下如何在Endnote文献中查看该文献的References
Verilog HDL 基础语法入门.
语法进阶.
第二章 Java语言基础.
数字集成电路设计入门 --从HDL到版图 于敦山 北大微电子学系.
CPU结构和功能.
复杂数字逻辑系统的 Verilog HDL 设计方法简介
精简指令集(RISC)CPU的构造原理和设计方法
用event class 从input的root文件中,由DmpDataBuffer::ReadObject读取数据的问题
SOA – Experiment 2: Query Classification Web Service
第一章 函数与极限.
C语言程序设计 主讲教师:陆幼利.
EBNF与操作语义 请用扩展的 BNF 描述 javascript语言里语句的结构;并用操作语义的方法描述对应的语义规则
简单介绍 用C++实现简单的模板数据结构 ArrayList(数组, 类似std::vector)
学习目标 1、什么是字符集 2、字符集四个级别 3、如何选择字符集.
数字电子技术 Digital Electronics Technology
第14章 对验证的支持 学习内容 理解Verilog文本输出 理解不同的读取仿真时间的系统函数 理解 Verilog文件I/O功能.
计算机EDA设计 教 程 北航计算机学院 艾明晶.
(Random Access Memory)
第二章 补充知识 2.1 总线和三态门 一、总线(BUS) 三总线结构 数据总线DB(Data Bus)
设计示例一 用门级结构描述D触发器:.
项目二:HTML语言基础.
语法要点详细讲解 有关测试模块编写的语法 ; 语法的高级部分: 函数、任务、文件、存贮器建立模型、 双向总线、UDP、综合指令。。。。
成绩是怎么算出来的? 16级第一学期半期考试成绩 班级 姓名 语文 数学 英语 政治 历史 地理 物理 化学 生物 总分 1 张三1 115
信号量(Semaphore).
第4章 Excel电子表格制作软件 4.4 函数(一).
第九节 赋值运算符和赋值表达式.
iSIGHT 基本培训 使用 Excel的栅栏问题
长春理工大学 电工电子实验教学中心 数字电路实验 数字电路实验室.
3.16 枚举算法及其程序实现 ——数组的作用.
《数字电子技术基础》(第五版)教学课件 清华大学 阎石 王红
Chapter 18 使用GRASP的对象设计示例.
多层循环 Private Sub Command1_Click() Dim i As Integer, j As Integer
魏新宇 MATLAB/Simulink 与控制系统仿真 魏新宇
HSC高速输出例程 HORNER APG.
第二节 函数的极限 一、函数极限的定义 二、函数极限的性质 三、小结 思考题.
基于列存储的RDF数据管理 朱敏
C++语言程序设计 C++语言程序设计 第一章 C++语言概述 第十一组 C++语言程序设计.
FPGA组合逻辑 王安然.
Verilog HDL 基本语法 STEP 2016/12/3.
按键处理部分 王安然.
Verilog HDL 基础语法入门.
本节内容 如何调试驱动程序? 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
使用Fragment 本讲大纲: 1、创建Fragment 2、在Activity中添加Fragment
学习目标 1、什么是列类型 2、列类型之数值类型.
Presentation transcript:

Verilog HDL 及Modelsim仿真 范益波

Acknowledgment This slides is revised from “Verilog HDL基础语法入门” by夏宇闻

Outline Verilog 简介 简单的 Verilog HDL 模块 Verilog 语法要点 Verilog 的逻辑值和数据类型 存储器及有限状态机建模 可综合风格的Verilog

什么是verilog Verilog是一种硬件设计语言(Hardware Description Language, HDL) 主要用于数字逻辑电路设计 跟VHDL类似

Verilog与C语言的关系 Verilog HDL作为一种高级的硬件描述编程语言,有着类似C语言的风格。其中有许多语句如:if语句、case语句等和C语言中的对应语句十分相似。如果读者已经掌握C语言编程的基础,那么学习 Verilog HDL并不困难,我们只要对Verilog HDL某些语句的特殊方面着重理解,并加强上机练习就能很好地掌握它,利用它的强大功能来设计复杂的数字逻辑电路。 但是注意:Verilog是硬件设计语言,跟软件设计有本质区别

Verilog具有不同的抽象级别 系统级(system): 用高级语言结构实现设计模块的外部性能的模型。 算法级(algorithmic): 用高级语言结构实现设计算法的模型。 RTL级(Register Transfer Level): 描述数据在寄存器之间流动和如何处理这些数据的模型。 可综合 相对高层的描述 门级(gate-level): 描述逻辑门以及逻辑门之间的连接的模型。

模块的抽象及 数字电路的基本设计流程 技术指标: RTL/功能级: 门级/结构级: 版图布局/物理级: RTL design 综合前仿真 逻辑综合 综合前仿真 综合后仿真 布局布线 技术指标: 用文字表示 用算法表示 用高级行为的Verilog模块表示 RTL/功能级: 用可综合的Verilog模块表示 门级/结构级: 用实例引用的Verilog模块表示 版图布局/物理级: 用几何形状来表示

Verilog的层次性架构 一个复杂电路的完整Verilog HDL模型是由若个 Verilog HDL 模块构成的,每一个模块又可以由若干个子模块构成。 利用Verilog HDL语言结构所提供的这种功能就可以构造一个模块间的清晰层次结构来描述极其复杂的大型设计。 Verilog HDL行为描述语言作为一种结构化和过程性的语言,其语法结构非常适合于算法级和RTL级的模型设计。

Outline Verilog 简介 简单的 Verilog HDL 模块 Verilog 语法要点 Verilog 的逻辑值和数据类型 存储器及有限状态机建模 可综合风格的Verilog

module adder ( count,sum,a,b,cin ); 举例1 例[2.1.1]: module adder ( count,sum,a,b,cin ); input [2:0] a,b; //声明输出信号equal input cin; //声明输入信号 output count; output [2:0] sum; assign {count,sum}=a+b+cin; endmodule 这个例子描述了一个三位的加法器。从例子中可以看出整个Verilog HDL程序是嵌套在module和endmodule声明语句里的。

举例2 例[2.1.2]: module compare ( equal,a,b ); output equal; input [1:0] a,b; assign equal=(a==b)?1:0; /*如果两个输入信号相等,输出为1。否则为0*/ endmodule 这个程序描述了一个比较器.在这个程序中,/*........*/和//.........表示注释部分,注释只是为了方便程序员理解程序,对编译是不起作用的。

举例3 output out; input in, enable; mytri tri_inst(out,in,enable); 例[2.1.3]: module trist1(out,in,enable); output out; input in, enable; mytri tri_inst(out,in,enable); endmodule module mytri(out,in,enable); assign out = enable? In : 'bz; 上述程序例子通过另一种方法描述了一个三态门。 在这个例子中存在着两个模块:模块trist1调用模块 mytri 的实例元件。通过这种结构性模块构造可构成特大型模块。

简单举例后的小结 整个Verilog HDL程序是嵌套在module和endmodule声明语句里的。 每个模块要进行端口定义,并说明输入输出口,然后对模块的功能进行行为逻辑描述。 Verilog HDL程序是由模块构成的。模块是可以进行层次嵌套的。 除了endmodule(及后面会学到的initial,end等)语句外,每个语句和数据定义的最后必须有分号 可以用/*.....*/和//...对Verilog HDL程序的任何部分作注释。

模块的测试:基本概念 被测模块 激励和控制信号 输出响应和验证

测试模块的常见形式 module t; reg …; //被测模块输入/输出变量类型定义 wire…; //被测模块输入/输出变量类型定义 initial begin …; …; …; end … …//产生测试信号 always #delay begin …; end … …//产生测试信号 Testedmd m (.in1(ina), .in2(inb), .out1(outa), .out2(outb) ); //被测模块的实例引用 initial begin ….; ….; …. end //记录输出和响应 endmodule

测试模块中常用的过程块 所有的过程块都在0时刻同时启动;它们是并行的,在模块中不分前后。 initial always

如何描述激励信号 module t; reg a, b, sel; wire out; //引用多路器实例 mux2 m (out, a, b, sel); //加入激励信号 initial begin a=0; b=1; sel=0; #10 b=0; #10 b=1; sel=1; #10 a=1; #10 $stop; end endmodule

建立时钟 虽然有时在设计中会包含时钟,但时钟通常用在测试模块中。 简单的对称方波时钟: reg clk; always begin #period/2 clk=0; #period/2 clk=1; end

仿真工具简介 Mentor公司的ModleSim Cadence的NC-Verilog Synopsys的VCS Learn from the ‘help’ manual of the software Learn from some teaching books Cadence的NC-Verilog Synopsys的VCS

Outline Verilog 简介 简单的 Verilog HDL 模块 Verilog 语法要点 Verilog 的逻辑值和数据类型 存储器及有限状态机建模 可综合风格的Verilog

Verilog与C的主要不同点 Verilog 有许多语法规则与 C 语言一致,但与 C 语言有根本的区别: 并行性 块的含义: initial 块 和 always块 两种赋值语句: 阻塞赋值 “ = ” 非阻塞赋值 “〈= ”

整数和实常数 整数可以标明位数也可以不标明位数,表示方法: 《位数》‘《基数》《值》 其中《位数》表明该数用二进制的几位来表示 《基数》可以是二(b)、八(O)、十(d)或 十六(h)进制 《数值》可以是所选基数的任何合法的值包括 不定值 x 位和高阻值 z。 如:64‘hff01 8’b1101_0001 ‘h83a 实常数可以用十进制表示也可以用科学浮点数表示,如:32e-4 (表示0.0032) 4.1E3( 表示 4100)

标识符 所谓标识别符就是用户为程序描述中的Verilog 对象所起的名字。 标识符必须以英语字母(a-z, A-Z)起头,或者用下横线符( _ )起头。其中可以包含数字、$符和下横线符。 标识符最长可以达到1023个字符。 模块名、端口名和实例名都是标识符。 Verilog语言是大小写敏感的,因此sel 和 SEL 是两个不同的标识符。

合法和非法标识符举例 合法的: 非法的: shift_reg_a busa_index bus263 34net //不能用数字开头 a*b_net //不能含有非字母符号* n@263 //不能含有非字母符号@

$<标识符> ‘$’ 符号表示 Verilog 的系统任务和函数 常用的系统任务和函数有下面几种: $time //找到当前的仿真时间 $display, $monitor //显示和监视信号值的变化 $stop //暂停仿真 $finish //结束仿真 ------------------------------------------------------- 例: initial $monitor($time,,”a=%b, b=%b”, a, b); //每当a 或b值变化时该系统任务都显示当前的仿真时刻并分别用二进制和十六进制显示信号a和 b的值

特殊符号 “#” 特殊符号 “#” 常用来表示延迟: 在过程赋值语句时表示延迟。 例:initial begin #10 rst=1; #50 rst=0; end 在门级实例引用时表示延迟。 例:not #1 not1(nsel, sel); and #2 and2(a1, a, nsel);

编译引导语句 编译引导语句用主键盘左上角小写键 “ ` ” 起头 用于指导仿真编译器在编译时采取一些特殊处理 编译引导语句用主键盘左上角小写键 “ ` ” 起头 用于指导仿真编译器在编译时采取一些特殊处理 编译引导语句一直保持有效,直到被取消或重写 `resetall 编译引导语句把所有设置的编译引导恢复到缺省状态 常用的编译引导有: `define `include `timescale ……..

编译引导语句: `define 使用`define 编译引导能提供简单的文本替代功能 在编译时会用宏文本来替代源代码中的宏名。 合理地使用`define可以提高程序的可读性 举例说明: `define on 1’b1 `define off 1’b0 `define and_delay #3 在程序中可以用有含义的文字来表示没有意思的数码提高了程序 的可读性,在程序中可以用 `on, `off, `and_delay 分别表 示 1,0,和 #3 。

编译引导语句: `include `include “global.v” `include “parts/counter.v” 举例说明: `include “global.v” `include “parts/counter.v” `include “../../library/mux.v” 合理地使用`include 可以使程序简洁、清晰、条理清楚、易于查错。

编译引导语句: `timescale `timescale 用于说明程序中的时间单位和仿真精度 举例说明: `timescale 1ns/100ps `timescale 语句必须放在模块边界前面 举例说明: `timescale 1ns/100ps module MUX2_1(out,a,b,sel); … … not #1 not1(nsel, sel); and #2 and1(a1, a, nsel); endmodule 尽可能地使精度与时间单位接近,只要满足设计的实际需要就行。 举例说明:在上例中所有的时间单位都是1ns的整数倍

Outline Verilog 简介 简单的 Verilog HDL 模块 Verilog 语法要点 Verilog 的逻辑值和数据类型 存储器及有限状态机建模 可综合风格的Verilog

Verilog 的四种逻辑值 1 X Z buf bufif1 0、低、伪、逻辑低、地、VSS、负插入 1 X Z buf bufif1 0、低、伪、逻辑低、地、VSS、负插入 1、高、真、逻辑高、电源、VDD、正插入 X、不确定:逻辑冲突无法确定其逻辑值 HiZ、高阻抗、三态、无驱动源

Verilog主要的数据类型 Nets 表示器件之间的物理连接, 称为网络连接类型;一般用wire来表示 Register Parameter 表示运行时的常数,称为参数类型

如何选择正确的数据类型? 输入口(input)可以由寄存器或网络连接驱动,但它本身只能驱动网络连接。 输出口 (output)可以由寄存器或网络连接驱动,但它本身只能驱动网络连接。 输入/输出口(inout)只可以由网络连接驱动,但它本身只能驱动网络连接。 如果信号变量是在过程块 (initial块 或 always块)中被赋值的,必须把它声明为寄存器类型变量

举例说明数据类型的选择 module top; wire y; reg a, b; DUT u1(y,a,b); initial begin end endmodule 模块DUT的边界 输入口 输出口 输出/入口 net net/register inout module DUT(Y, A, B_); output Y; input A,B: wire Y, A, B; and (Y, A, B); endmodule

选择数据类型时常犯的错误 在过程块中对变量赋值时,忘了把它定义为寄存器类型(reg)或已把它定义为连接类型了(wire) 把实例的输出连接出去时,把它定义为寄存器类型了 把模块的输入信号定义为寄存器类型了。

主要的数据类型:parameters 常用参数来声明运行时的常数。 可用字符串表示的任何地方,都可以用定义的参数来代替。 参数是本地的,其定义只在本模块内有效。 举例说明: module md1(out,in1,in2); ….. parameter cycle=20, prop_del=3, setup=cycle/2-prop_del, p1=8, x_word=16’bx, file = “/user1/jmdong/design/mem_file.dat”; wire [p1:0] w1; //用参数来说明wire 的位宽 …. initial begin $open(file); ……. #20000 display(“%s”,file); $stop end endmodule

练习1 学习modelsim的用法 实现例1,2,3并编写相应的测试文件,在modelsim中仿真实现 语法要点 Verilog逻辑值 整数表示方法 标示符 编译引导语句 Verilog逻辑值 Verilog 的数据类型

Outline Verilog 简介 简单的 Verilog HDL 模块 Verilog 语法要点 Verilog 的逻辑值和数据类型 存储器及有限状态机建模 可综合风格的Verilog

寄存器阵列 integer NUMS [7:0]; // 8个整型变量的寄存器阵列 举例说明: integer NUMS [7:0]; // 8个整型变量的寄存器阵列 time t_vals [3:0]; //4个时间变量的寄存器阵列 数据类型为 reg 的阵列常称为存储器(即 memory): reg [15:0] MEM [0:1023]; // 1K x 16 位的存储器 注意:这种方式写的存储器面积非常大 reg [7:0] PREP [‘hfffe : ‘hffff]; // 2 x 8 位的存储器 可以用参数来表示存储器的大小: parameter wordsize = 16; parameter memsize = 1024; reg [wordsize-1:0] MEM3[memsize-1:0];

存储器建模必须注意以下两个方面的问题: 声明存储器容量的大小。 明确对存储器访问操作的权限。 语法详细讲解 存储器建模 例如:指出可以对存储器做以下哪几种操作: 1)只读 2)读写 3)同步读写 4)多次读,同时进行一次写 5)多次同步读写,同时提供一些方法保证一致性

语法详细讲解 简单 ROM 建模 `timescale 1ns/10ps module myrom(read_data,addr,read_en_); input read_en_; input [3:0] addr; output [3:0] read_data; reg [3:0] read_data; reg [3:0] mem [0:15]; initial $readmemb(“my_rom_data”,mem); always @ (addr or read_en_) if(!read_en_) read_data=mem[addr]; endmodule my_rom_data 0000 0101 1100 0011 1101 0010 1111 1000 1001 0001 1010 ROM的数据存储在另外的一个独立的文件中

上页所示的ROM模型说明: 语法详细讲解 简单ROM建模 如何在Verilog中用二维的寄存器组来定义存储器。

语法详细讲解 简单RAM建模 `timescale 1ns/1ns module mymem(data,addr,read,write); inout [3:0] data; inout [3:0] addr; input read, write; reg [3:0] memory [0:15]; //4 bits, 16 words //从存储器读出到总线上 assign data=read? memory[addr]:4’bz; //从总线写入存储器 always @ (posedge write) memory[addr]=data; endmodule

语法详细讲解 简单RAM建模 RAM模型比ROM模型稍微复杂: 它必须具有读写能力; 进行读写时通常使用相同的数据总线; 需要新技术来处理双向总线; 当读信号无效时,RAM模型与总线脱离,如果此时写 信号也无效,总线无驱动源,则总线进入高阻状态, 这就避免了RAM中的读写竞争。 上页的 RAM 模块是可综合的,但综合出来是一大堆寄存器,占比较大的面积,经济上不太合算。

语法详细讲解 存储量可变的只读存储器建模 例: module scalable_ROM (mem_word, address); parameter addr_bits=8; //size of address bus parameter wordsize=8; //width of a word parameter words=(1<<addr_bits); //size of mem output [wordsize:1] mem_word; //word of memory input [addr_bits:1] address; //address bus reg [wordsize:1] mem [0 : words-1]; //mem declaration //output one word of memory wire [wordsize:1] mem_word=mem[address]; endmodule

上述的例子演示了怎样通过设置字长和地址位数来编 写 只读存储器的行为模块。 语法详细讲解 存储量可变的只读存储器建模 上述的例子演示了怎样通过设置字长和地址位数来编 写 只读存储器的行为模块。 [注意] !! 在上例中,存储字的范围从0开始的,而不是从1开始,这是因为存储单元是直接通过地址线寻址定位的。 同样地,也可以用下面的方法来定义存储器和寻址: reg [wordsize:1] mem [1:words]; //存储器地址 从1 开始 //地址一个一个地增加直到包含了每个地址对应的存储器 wire [wordsize:1] mem_word = mem[address+1];

语法详细讲解 存储器的加载 可以在初始化块中用一个循环或系统任务把初始数据存入存储器的每个单元。 使用循环把值赋给存储器数组。 for(i=0;i<memsize;i=i+i) // initialize memory mema[i]={wordsize{1’b1}}; 调用$readmem系统任务。 //从文件 mem_file.txt 中, 把初始数据存入存储器(mem)的每个单元 $readmemb(“mem_file.txt”,mem); 注意:上面两项必须写 在initial 块中,加载这些初始化数据不需要时间。

语法详细讲解 怎样使用双向口 使用inout关键字声明端口为双向口。 inout [7:0] databus; 使用双向口必需遵循下面的规则: inout口只能声明为网络连接类型, 不允许把它声明为寄存器类型。(所以仿真器能确定多个驱动源的最终值。) 在设计中,每次只能从一个方向来驱动inout口。 例如:当使用总线读RAM中的数据时,如果同时又向RAM模型的双向数据总线写数据,就会产生逻辑竞争,导致总线数据无法确定。所以必须为inout口设计控制逻辑,只有这样才能保证正确的操作。

语法详细讲解 双向口建模 使用连续赋值为双向口建模: en_a_b bus_a bus_b en_b_a module bus_xcvr (bus_a,bus_b,en_a_b,en_b_a); inout bus_a,bus_b; input en_a_b,en_b_a; assign bus_b=en_a_b? bus_a:’bz; assign bus_a=en_b_a? bus_b:’bz; //结构模块逻辑 endmodule 当en_a_b=1时,bus_a的值传到bus_b上 当en_b_a=1时,bus_b的值传到bus_a上 控制信号 en_a_b 和 en_b_a 在时间上分开

有限状态机 1 1 识别11序列 datain = 0 module exp(out, datain, clk, rst); 1 datain = 0 datain = 1 module exp(out, datain, clk, rst); input clk, rst, datain; output out; reg out; reg state; always @(posedge clk or posedge rst) if(rst) {state, out}=2’b00; else case(state) 1’b0: begin out=1’b0; if(!datain) state=1’b0; else state=1’b1; end 1’b1 begin out=datain; state=1’b0; default: {state, out}=2’b00; endcase endmodule 状态变量 case语句 1 识别11序列 clk rst out 转到下一个状态 默认状态指针

有限状态机讨论 在过程块中可以使用一个时钟沿和 case 语句来描述一个显式状态机。 必须指定一个状态变量,来记录状态机的状态。 要改变当前的状态,必须改变状态变量的值, 其改变要与时钟沿同步。 写得比较好的状态机常为不应产生的条件规定一个默认动作。

Outline Verilog 简介 简单的 Verilog HDL 模块 Verilog 语法要点 Verilog 的逻辑值和数据类型 存储器及有限状态机建模 可综合风格的Verilog

两种可综合风格的 Verilog建模类型 组合逻辑: 时序逻辑: 任何时候,如果输出信号直接由当前的输入信号的组合决定,则此逻辑为组合逻辑。 如果逻辑中具有记忆功能,则此逻辑为时序逻辑。在任何给定的时刻,如果输出不能完全由输入信号确定,则此逻辑具有记忆功能。

不能综合的 Verilog结构 Initial 循环语句: 一部分数据类型 过程连续赋值语句 部分操作符 Repeat Forever While for 的非结构用法 一部分数据类型 Event Real Time UDPs fork…join 块 wait 过程连续赋值语句 assign 和 deassign force 和 release 部分操作符 = = = != =

过程块 由输入信号中任意一个电平发生变化所引起的过程块,可以通过综合产生组合逻辑。该过程块称为组合块。 always @(a or b) // 实现与门 y=a&b; 由控制信号的跳变沿(下降沿或上升沿)启动的过程块通过综合可以生成同步逻辑。该过程块称为同步块。 always @(posedge clk) //实现 D 触发器 q<=d; always @(posedge clk or negedge rst_) if(!rst_) q<=0; else

同步寄存器示例1 在下面的例子中,rega 仅用作临时存储器,因此在综合时它将被优化掉。 module ex1reg(d, clk, q); input d, clk; output q; reg q, rega; always @(posedge clk) begin rega = 0; if(d) rega = 1; q = rega; end endmodule

同步寄存器示例2 在下面的例子中,用两个always块,它们的触发条件是相同的:即 用同一时钟沿来处理两个存储元素,这样就可以使综合器在综合过 程中保留rega,使它不被优化掉。 module ex2reg(d, clk, q); input d, clk; output q; reg q, rega; always @(posedge clk) begin rega=0; if(d) rega=1; end q = rega; endmodule

组合寄存器示例1 y和rega 不断被赋新值(因为语句中有else rega = 0;),综合出的电路是一个纯组合逻辑。 rega 是临时变量,在综合中会被优化掉。 module ex3reg(y, a, b, c); input a, b, c; output y; reg y, rega; always @(a or b or c) begin if(a&b) rega=c; else rega=0; y=rega; end endmodule

组合寄存器示例2 在下面的例子中,rega 只是有时被赋新值 (没有else 语句,rega在条件不符合时保持原值);因此综合出来的是一个以 y 作为输出的锁存器。 rega 是临时变量,在综合中会被优化掉。 moudule ex4reg(y, a, b, c); input a, b, c; output y; reg y, rega; always @(a or b or c) begin if(a&b) rega=c; y=rega; end endmodule

完整的电平敏感列表 module sens(q, a, b, sl); input a, b, sl; output q; reg q; always @(sl or a or b) begin if(!sl) q=a; else q=b; end endmodule

不完整电平敏感列表 在电平敏感列表中最好包括所有的输入。对于不完整的列表,不同的综合工具处理的方法不同 module sens(a, q, b, sl); input a, b, sl; output q; reg q; always @(sl) begin if(!sl) q=a; else q=b; end endmodule

连续赋值 用连续赋值语句表达的是:任何一个输入的改变都将立即导致输出 更新;与理想的与、或、非门的线路连接一致。 module orand(out, a, b, c, d, e); input a, b, c, d, e; output out; assign out=3&(a|b)&(c|d); endmodule

case条件语句 module comcase(a, b, c, d, e); input a, b, c, d; output e; reg e; always @(a or b or c or d) case ({a,b}) 2’b11: e=d; 2’b10: e=~c; 2’b01: e=1’b0; 2’b00: e=1’b1; endcase endmodule

if条件语句 module compif(a, b, c, d, e); input a, b, c, d; output e; reg e; always @(a or b or c or d) if(a&b) e=d; else if (a&~b) e=~c; else if (~ a&b) e=1’b0; else if (~a&~b) e=1’b1; endmodule

不完整条件语句1 module inccase(a, b, c, d, e); input a, b, c, d; output e; reg e; always @(a or b or c ord) case ({a,b}) 2’b11: e=d; 2’b10: e=~c; endcase Endmodule 当 a 为 0 时,没有值赋给 e。因此,e 将保存原来的值,直到 a 变为 1。此行为与锁存器的特性相同。

不完整条件语句2 module incpif(a, b, c, d, e); input a, b, c, d; output e; reg e; always @(a or b or c or d) if (a&b) e=d; else if(a&~b) e=~c; endmodule

带有缺省项的完整条件语句 module comcase(a, b, c, d, e); input a, b, c, d; output e; reg e; always @(a or b or c or d) case ({a,b}) 2’b11: e=d; 2’b10: e=~c; default: e=‘bx; endmodule 虽然没有定义所有可能的选择,但为没有定义的选择定义了缺省的行为。因此,它们都是纯的组合逻辑,并没有产生额外的锁存器。

带有缺省项的完整条件语句 module compif(a, b, c, d, e); input a, b, c, d; output e; reg e; always @(a or b or c or d) if (a&b) e=d; else if (a&~b) e=~c; else e=‘bx; endmodule

怎样产生锁存器 在 always 块中,如果没有规定所有的条件,则会产生锁存器。在下面的例子中,当 enable 为低电平时,没有定义怎样处理 q 和 data,因此 data 的值将会被保存下来。综合器必须使用存储元件来编译此逻辑。 module latch(q, data, enable); input data,enable; output q; reg q; always @(enable or data) if(enable) q=data; endmodule

阻塞与非阻塞(赋值方式) 赋值的类型的选择取决于建模的逻辑类型 在时序块的 RTL 代码中使用非阻塞赋值。 非阻塞赋值在块结束后才完成赋值操作,此赋值方式可以避免在仿真出现冒险和竞争现象。 在组合的 RTL 代码中使用阻塞赋值。 使用阻塞方式对一个变量进行赋值时,此变量的值在在赋值语句执行完后就立即改变。

阻塞与非阻塞(赋值方式) 使用非阻塞赋值方式进行赋值时,各个赋值语句同步执行;因此,通常在一个时钟沿对临时变量进行赋值,而在另一个时钟沿对其进行采样。 下面的模块综合为触发器, 其中采用了阻塞赋值方式: module bloc(clk,a,b); input clk, a; output b; reg b; reg y; always @(posedge clk) begin y=a; b=y; end endmodule 下面的模块综合为两个触发器 ,其中采用了非阻塞赋值方式: module nonbloc(clk,a,b); input clk, a; output b; reg b; reg y; always @(posedge clk) begin y<=a; b<=y; end endmodule

阻塞与非阻塞(赋值方式) 上面的两个例子的综合的结果不同,左边的例子使用了阻塞赋值方式,综合器将其综合为一个触发器。右边的例子使用了非阻塞赋值方式,综合器将其综合为两个触发器,y 将出现在综合列表中,作为第二个触发器的输入。综合结果如下所示: a y b b a clk clk

复位建模 复位是可综合风格代码的重要组成部分,通常在有限状态机中使用复位建模。 同步复位: module sync(q,ck,r,d); input ck, d, r; output q; reg q; always @(negedge ck) if(r) q<=0; else q<=d; endmodule 同步块中的异步复位: module async(q,ck,r,d); input ck, d, r; output q; reg q; always @(negedge ck or posedge r) if(r) q<=0; else q<=d; endmodule

复位建模 在下面的例子中,使用了一个独立的异步复位来实现异步复位。 module async(q, ck, r, d); input ck, d, r; output q; reg q; always @(negedge ck) if(!r) q<=d; always @(posedge r) q<=0; endmodule 不提倡使用上述风格的异步复位代码,上述代码是不可综合的。在 仿真时,若 r 和 ck 同时在同一个时间单元中改变,则结果是不确定 的。

锁存器复位 下面的例子演示了更加复杂的复位建模。其中的敏感列表是完全的, 因为这是一个锁存器。 module latch(q, enable, set, clr, d); input enable, d, set, clr; output q; reg q; always @(enable or set or clr or d) begin if(set) q<=1; else if (clr) q<=0; else if (enable) q<=d; end endmodule

练习2 存储器 有限状态机 同步寄存器 组合寄存器 电平敏感列表 Case 语句 If 语句 阻塞与非阻塞 复位方式