Verilog学习笔记(完整版)

Verilog

1.概述

  • IC概述
    • 摩尔定理
      • 晶体管数量24个月翻一倍,芯片性能18月翻一倍
    • IC分类
      • MSI
      • LSI
      • VLSI
      • ULSI
    • 层级描述
      • function:系统级、行为级,RTL
      • logic
      • circuit
      • layout
    • 自上而下
  • IC设计方法发展
    • CAD:
      • 传统电路验证工具,不能分析公差和验证功能
      • 低速
      • 1960-1970:layout DRC
        • 电路仿真
          • HW:16-bit 电脑
          • SW:交互式原理图/布局编辑和设计规则检查
          • 解决了数学电路方程问题
          • SPEICE:第一个电路仿真程序
            • 第一个版本:SPICE2G
            • 1981:SPICE2G6
            • 现在:SPICE3、HSPICE、Spectre、PSPICE、fast SPICE
    • CAE:
      • 布局布局和布线 + 逻辑仿真 + LVS(布局与原理图)
      • HW:32b工作站
      • SW:完整的前后端工具链,包括逻辑原理图输入、逻辑仿真、电路仿真、自动布局和
      • 物理检查
        • DRC + ERC (Electrical Rule Check) + LPE (Layout Parameter Extraction) + LVS
    • EDA:
      • Top_down Design;
        • 硬件描述语言(HDL),例如VHDL、Verilog HDL
        • 综合工具:高级/逻辑
        • 技术独立:实现HDL源代码,使用不同的库获得不同的电路格式(ASIC、FPGA)
      • Behavioral Description ;
      • High-Level Synthesis;
        • 输入:行为级描述
        • 输出:结构场中的结构RTL宏块
      • RTL Description;
        • 自动将硬件描述语言 (HDL) 模型转换为满足一组设计标准(面积、速度、功耗、可测试性)的门级网表。
        • RTL 综合 = 翻译 + 优化 + 映射
          • 翻译:RTL描述->门级描述
          • 优化:面积、速度、功率
      • Logic Synthesis
    • VDSM EDA
      • 子系统/宏块(IP - Intellectual Property)采用自上而下的设计方法设计
      • 具有IP(知识产权)的SoC实施 — 自下而上
    • Deep sumicron technology
      • 亚微米(SM)- < 1微米
      • 深亚微米(DSM)- < 1/2 微米
      • 极深亚微米 (VDSM) - < 1/4 微米
      • 挑战:
        互连延迟:上升
        电源、时钟、系统可靠性
        设备建模
        设计能力
        信号完整性
    • SoC:
      • 在适当的技术水平下将系统集成到单个芯片中
      • 超深亚微米技术
        • 包括一个或多个微处理器存储器和至少 100,000 个门的随机逻辑
        • CPU、DSP、数字电路、模拟电路、内存等
    • IP(知识产权)
      • 可用性和复用性
      • 为了满足TTM(Time To Market)的要求,基于平台的设计方法是利用可用块(IP)来集成SoC
      • 软核心:可合成的HDL代码
      • firm核心:网表
      • 硬核:GDSII。
      • 验证核心
        行为水平HDL模型
        无法合成的代码
        仅用于功能验证

2. Verilog 框架

  • 复习
    • 电子系统可由哪些抽象级别描述?
      • 门级
      • 行为级
      • 数据流级
      • 开关级
    • 描述EDA设计流程(数字集成电路设计流程)
      1. 明确设计要求
      2. 进行行为描述
      3. Rtl 级描述
      4. 功能验证和调试
      5. 逻辑综合
      6. 门级网表
      7. 逻辑验证和测试
      8. 版图规划和自动布局布线
      9. 物理版图
      10. 版图是实现
    • 集成电路产业分工如何划分的
      设计、代工、封装、测试
    • Verilog HDL特点/优点?
      是一种通用硬件描述语言,类似 c 易学易用
      允许同一个电路模型内进行不同抽象层级的描述
      大多数综合工具都支持
      所有制造厂商都提供用于综合之后的逻辑仿真元件库
      编程接口,可以通过 c 代码访问 verilog 内部的数据结构
    • IP核的两个重要的特征及含义
      可用性和复用性
      为了满足上市时间的要求,基于平台的设计方法是利用可用块(ip)集成 soc
    • IP核种类以及对应种类IP核的特征
      • 软核:可以综合的 HDL 代码
      • Firm核:网表
      • 硬核:GDS 2
      • 验证核心:
        • 行为水平的 HDL 模型
        • 无法综合的代码
        • 仅用于功能验证
    • SoC具有的特征
      • 包括一个或多个微处理器、存储器和至少 100000 个门的随机逻辑
      • Cpu、DSP、数字电路、模拟电路、内存等
    • 如何看待反向设计方法?
      • 反向设计是从已有的硬件或功能描述出发逆向推导 verilog 代码的过程
      • 能够帮助理解复杂系统
      • 能够帮助学习
      • 调试和验证
      • 逆向工程
      • 设计重用
    • RTL如何理解
      • RTL=翻译+优化+映射,是指自动将硬件描述语言转化为一组设计标准的门级网表
  • 芯片系统(参见1.2)
  • 设计方法
    • 芯片设计
      • 向前vs向后
      • 从下到上vs自底而上
    • 反向设计
      • 布局复制、DRC、ERC;采用相同的技术:侵权(tort)
      • 布局分析,电路提取,逻辑提取,逻辑仿真,电路仿真,布局重设计,布局严整(DRC,ERC,LVS)
      • ![[Pasted image 20240819191108.png]]
  • Verilog HDL框架
    • HDL硬件描述语言
    • 设计电子系统的输入,是设计流程的开始
    • 用于最终的物理实现
    • VHDL:超高速集成电路
    • Verilog HDL
      • 基于c语言发展
      • 与c语言对比:
        • c语言按函数编写,verilog按模块编写
        • c语言有一个main函数,verilog中所有模块都是等效的,verilog也有一个top模块
        • c语言顺序执行,verilog代码并行执行
      • 特征:
        • 几乎所有级别的精确或复合描述
        • 设计、验证的语法相同
        • 独立于技术的更高层次描述
        • 运算符:如算术、逻辑、位运算等。
        • 高级编程语句,如if-else,case,loop等。
        • 包括完整的内置组合逻辑元素,如和,或,异或等。
      • 电子系统设计层级
        • 系统层级:C,C++,system C
        • 行为级:函数、算数
        • 数据流(RT级):寄存器、包括可合成行为和数据流描述的逻辑
        • 门级:基本门(逻辑级)
        • 开关级:晶体管作为开关
        • 物理级:布局
      • 系统分层设计
        • 系统建模
          • 顶部模块:连接各功能模块
            • SoC平台
          • 功能模块:功能相对独立
            • CPU、timer、DMA
        • 验证和结果评估
          • 验证:仿真、形式检验、物理验证、信号完整性等
          • 综合:面积、速率、功率
          • 评估:时序分析、计算能力等
      • 模块
        • verilog HDL由模块组成
        • 一个模块代表一个具有固定功能的对象,如:逻辑门、计数器、存储器或系统等
        • 模块以关键字“module”开始,“endmodule”结束
          	   module module_name(Port_list);
          
          			   Port Declaration;
          
          			   Data Type Declaration;
          									
          			   Circuit Function Description;
          
          	   endmodule
          
      • 验证
        • 功能
        • 时间
          • 建立时间还是保持时间
        • 软件验证的限制
          • 所有情况都尝试了?
          • 所有路径都仿真了?每一个选择吗?
        • 验证环境包括
          • 设计验证(DUV)
          • 验证向量(刺激)
          • 监控或检查
        • 验证过程
          • DUT实例化
          • 刺激
          • 结果检查和报告
      • SystemVerilog HDL
      • SystemC
      • 接口
      • 仿真

3.Verilog基础

  • 开始
    • Verilog模块在“module”、“endmodule”之间
    • 模块主要内容
      • 模块名、端口列表、i/o方向声明、内部信号声明、电路功能声明
    • 层级抽象
      • 系统层级:系统行为的顶层抽象描述
      • 行为级:实现算法运行模型
      • RT-级:描述寄存器之间的数据流以及如何处理控制流
      • 门级:描述门之间的连接
      • 开关级:对晶体管与存储节点设备及其连接的描述
    • 硬件模块的三种风格
      • 行为描述:单个复杂功能
      • 结构描述:层次化模块
      • 数据流描述:相对简单的组合逻辑功能
    • 总结:
      • 模块可以分层引用
      • 各模块列出了端口,给出了输入输出端口的声明,然后对模块功能做了说明
      • 程序编写个事自由,几条语句可以在一行也可以分成多行
      • 除了begin、end、endmodule语句外,其他语句(包括数据声明语句)应以分号结束
      • 两种注释
    • 基本语法
      • 术语
        • 空格标志
        • identifier:对象名称,例如:模块名称、端口名称
        • 词汇:和c语言类似
        • LSB:最低有效位
        • MSB:最高有效位
      • 注释
      • 常量
        • integer

          • “下划线”作为分割线
          • 大小写不敏感
        • real

          • 十进制或者科学记数法
        • string

          • 没有该数据类型,通常用于显示命令中
        • identifier

          • 对象名称
          • 大小写敏感
          • 所有关键字使用小写
        • 特殊标志

          //1、#
          //进程分配语句中的延迟
          # 10 rst=1;
          //门级实例的延迟
          not # 1 not1(nsel,sel);
          and # 2 and2(a1,a,nsel);
          //模块实例中参数传递
          adder #(.WORDSIZE(32)) U1(……)
          //2、$
          系统任务和功能
          $ stop
          $ finish
          //3、`代表编译器引导
          //内置指令使仿真编译器执行一些特殊的操作
          ` resetall //重置所有编译引导的默认值
          //4、替换(提升代码可读性、定义全局变量、缩写verilog命令)
          `define not_delay # 1 //定义not_delay
          not `not_delay not1(sel_,sel); //使用not_delay
          //4、`include命令,可引入宏定义、提高代码可维护性
          //5、 `timescale,如果不是用ns作为默认,必须出现在模块之前
          `timescale 1 ns/10 ps
          //决定仿真精度,仿真时间单位由所有模块中精度最高的决定
          
        • 数据类型

          • Net
            • 设备间物理连接
            • 需要持续驱动,可由门或模块驱动,当线网驱动发生变化时,新值会自动的传送到线网
            • 默认:1比特wire
              ![[Pasted image 20240820140719.png]]
          • Register
            • 抽象存储单元
            • 分配新值前,保持原值
            • 使用行为样式描述为寄存器赋值
              ![[Pasted image 20240820142026.png]]
          • net对比register
            • net:
              • 驱动方法:1.连接到门或模块输出;2、使用“assign”语句(数据流方式)
              • 电荷保持效果:无(三重器除外),未驱动时为高阻抗状态
              • 相关硬件:物理连接线
            • register
              • 驱动方法:使用“流程分配语句”分配
              • 电荷保持效果:在下次分配之前保持不变
              • 相关硬件:触发器、锁存器和组合逻辑
          • Parameter
            • 运行时常量
          • signal和数据类型
            • 端口信号和内部信号
            • signal默认是线网类型
            • 端口信号默认是对应位宽wire类型
            • 内部信号默认是1bit wire类型
            • inout端口仅在最顶层的模块中使用,中间模块不能使用
          • 错误类型
            //在进程 BLCOK 中分配一个 net 类型或尚未声明的信号
            info: illegal .......assignment.
            //连接到信号的输出实例,其类型被声明为寄存器
            info: <namr> has illegal output port specification.
            //模块输入信号声明为寄存器类型
            info: incompatible declaration,<signal name>......
            
          • register array
            //向量
            reg [7:0] mem_word;
            //存储器行数
            reg mem_word[7:0];
            
            • Verilog语法规定,给出2个或多个索引时会导致编译错误
            • 要访问内存字的某些位,您只能通过寄存器
          • parameters
            • 语法
              • parameter <list_of_assignment>;
              • 不支持在module之前定义全局参数
              • 可以定义多个参数,用逗号分隔
              • 参数将数字替换为文本
              • 参数的定义仅在当前模块生效
          • operator(操作符)
            • 一元、二元、三元运算符
            • Verilog根据表达式中变量的长度对表达式的值自动地进行调整。
            • Verilog自动截断或扩展赋值语句中右边的值以适应左边变量的长度。
            • 当一个负数赋值给无符号变量如reg时,Verilog自动完成二进制补码计算
            • 0, z, x组合的向量中,有x逻辑值为x,无x而有z,值为z
            • 逻辑操作的结果不可能为z!!
            • 比较是one bit by one bit,任何操作数有z, x值,比较的结果为1‘bx
          • ~和!有什么不同?
            • ~ 进行1的补码操作,将向量中的每一位取反
            • !将一个操作数归约为一位true或false结果
          • &&和&有什么不同?
            • & 将操作数从低到高的对应位进行与操作
            • && 将每个操作数归约为一位true或false,然后对归约结果进行与操作

4.行为风格建模

  • 电路描述样式

    • 行为描述
      • 专注于模块行为或功能的抽象描述(RTL)
        • 如果电路包含多个行为,分开他们
        • 时间控制
          • 具体时间节点电路应该做什么
          • 满足某些条件时,电路做什么
    • 结构描述
      • 重点对实现的模块内部结构进行详细描述
    • 数据流描述:
      • 关注从一个阶段到下一个阶段的数据流
  • 模块、过程块、块语句

    • 关系说明

      • 一个模块包含一个或多个并行过程块
      • 过程块行为取决于过程语句(initial vs. always)和块语句(begin-end vs. fork- join
      • 除了过程语句:过程声明 blocking vs. nonblocking
      • 一条initial/always就是一个过程块
    • always

      • 时钟同步电路
      • 异步清除电路
    • 过程块总结

      • 一个模块可能有多个initial块和(或)always块,他们相互独立,并发执行
    • initial vs. always

      • 多个块在0时刻并发执行,initial块执行一次,always块重复执行
      • always块通常有触发条件,并且总是重复执行,initial相反
    • 例题:描述一个具有相同相位的双时钟产生模块,时钟周期分别是200延时单位和100延时单位,占空比50%。

      moudle clock_gen(p1,p2);
      	output p1,p2;
      	reg p1,p2;
      	initial begin
      		p1=0;p2=0;
      	end
      	always # 100 p1=~p1;
      	always @(posedge p1)
      	begin
      		p2=1;
      		# 50 p2=0;
      		# 50 p2=1;
      		# 50 p2=0;
      	end
      endmoudle
      
    • 例题:说明verilog中给一个向量赋负数如何处理

      wire signed [7:0] signed_vector;
      assign signed_vector = -128; // 直接赋值为有符号的负数
      
  • 简答

    • 操作符有哪些?
      • 按位操作、逻辑操作、缩位操作、关系操作、相等操作、条件操作
    • 同步复位/置位与异步复位/置位的区别?
      • 异步复位(Asynchronous Reset):
        异步复位不受时钟信号的控制,可以直接在任何时间点触发复位操作。
        复位信号通常与时钟信号无关,可以立即将寄存器或触发器的状态重置到预定义的初始状态。
        异步复位通常用于系统级的初始复位,或者在需要快速响应复位请求时使用。
        异步复位可能引入冒险(race condition),因为复位信号可能会在时钟边沿之前或之后到达寄存器,这可能导致元数据(metastability)问题。
      • 同步复位(Synchronous Reset):
        同步复位与时钟信号同步,复位操作仅在时钟的上升沿或下降沿触发。
        复位信号的效应仅在时钟周期内传播,这有助于避免元数据问题,并确保复位操作的确定性。
        同步复位通常用于寄存器或触发器的复位,以确保复位行为与时钟信号同步。
        同步复位有助于简化时序分析,因为它减少了复位信号与数据信号之间的时序关系。
        		module reset_example(
        	    input wire clk,        // 时钟信号
        	    input wire reset_async, // 异步复位信号
        	    input wire reset_sync,  // 同步复位信号
        	    output reg q            // 输出寄存器
        	);
        	
        	// 异步复位逻辑
        	always @(posedge clk or posedge reset_async) begin
        	    if (reset_async) begin
        	        q <= 1'b0; // 异步复位到初始值0
        	    end else begin
        	        q <= q + 1; // 正常操作,q加1
        	    end
        	end
        	
        	// 同步复位逻辑
        	always @(posedge clk) begin
        	    if (reset_sync) begin
        	        q <= 1'b1; // 同步复位到初始值1
        	    end
        	end
        	
        	endmodule
        
    • HDL描述硬件行为的三种风格
      • 行为描述、结构描述、数据流描述
    • 模块,过程块(过程语句)和块语句之间关系
      一个Verilog设计由多个模块组成。
      每个模块可以包含多个过程块,模块中的所有过程块是并发执行
      每个过程块由一个过程语句开始,并包含一个或多个语句块。
      语句块包含实际执行的Verilog语句。
    • always过程块敏感表注意问题:敏感列表完整性、避免无限循环、避免阻塞非阻塞赋值混用
  • 顺序块、并行块返回

    • begin end
      • 用于顺序块
      • 顺序块特点
        • 顺序块中的语句按照指定的顺序进行处理。只有在执行了前一个语句之后,才会执行该语句。
        • 如果指定了延迟,则它是相对于块中前一个语句完成执行时的模拟时间。
    • fork join
      • 用于并行块
      • 特点
        • 并行块中语句同时执行
        • 执行顺序由延迟控制,或者由分配给每个语句的事件控制
        • 如果指定了延迟,则它是想对于进入区块时刻的延迟
    • 使用begin end或者fork join交换数据
      	begin
      		# 0 temp = a;
      		# 5 a=b;
      		# 5 b=temp;
      	end
      	fork
      		# 5 a=b;
      		# 10 b=a;
      	join
      
  • named - block

    • 容易控制(disable命令)
    • verilog中,如果块不命名,不能声明局部变量(变量只能是寄存器类型)
  • 过程分配语句“assign”

    • 仅在过程块内进行
    • 仅赋值给具有寄存器类型的变量
    • 过程分配语句类型
      • 阻塞:“=”
      • 非阻塞:“<=”
      • 不要再一个过程块中混合使用阻塞和非阻塞
  • 时序控制

    • 基于延迟
      • 常规延迟控制
        • 在程序分配的左侧指定非零延迟
      • 内部赋值延迟
        • 将延迟分配给分配赋值语句的右侧
      • 零延迟控制
        • 一种确保在执行该模拟时间内的所有其他语句之后最后执行语句的方法。它提供了一种有用的机制来控制模拟中语句的执行顺序
    • 基于事件
      • 事件是寄存器或线网上的值发生变化
      • 常规时间控制
        • @、posedge
      • 命名时间控制
        • 由事件关键字控制,事件由“->”符号触发,时间的触发由“@”控制
      • OR事件控制
        • 它由关键字声明,或用于指定多个触发器。多个信号或事件中的任何一个的转换都可以触发一个语句或一个语句块的执行。
        always@(reset or clock or d)//多个触发条件
        
    • wait关键字
      • 用于用于级别敏感结构
      • 语句在执行语句或语句块之前等待某个条件为真。
      always
      	wait(count_enable)# 20 count =count+1;//不可综合
      	//如果count_enable是逻辑1,语句在20个时间单位后执行
      	//如果持续为1,每20个时间单位执行一次
      
    • 外部和内部
      分配语句
      • 交换(fork join)可以内嵌延迟
    • 简答
      • 顺序块与并发块异同?
      • 数据交换操作正确处理方式
      • 命名块优点?
        • 增加可读性,声明局部变量,便于调程序
      • 阻塞/非阻塞赋值异同?
        • 多过程块时,阻塞赋值的变量在其它过程块中引用可能引起竞争
        • 在使用阻塞赋值的always块中,所有赋值语句按照它们在代码中出现的顺序依次执行。
        • 在使用非阻塞赋值的always块中,所有赋值语句在当前时间点记录下要执行的操作,然后在时间点结束时同时更新所有变量的值。
      • 时序控制方法?
        • delay, event;external, internal
      • 四位串行移位器RTL描述
      	module shift_register_4bit(
      	    input wire clk,          // 时钟信号
      	    input wire reset,        // 复位信号
      	    input wire serial_in,    // 串行数据输入
      	    input wire shift_en,    // 移位使能信号
      	    output reg [3:0] data_out // 并行数据输出
      	);
      	
      	// 定义四位寄存器用于存储移位数据
      	reg [3:0] shift_reg;
      	
      	// 在时钟上升沿和复位信号下操作
      	always @(posedge clk or posedge reset) begin
      	    if (reset) begin
      	        // 异步复位:将移位寄存器清零
      	        shift_reg <= 4'b0;
      	    end else if (shift_en) begin
      	        // 如果移位使能,将数据左移一位,并把serial_in的数据放入最低位
      	        shift_reg <= {shift_reg[2:0], serial_in};
      	    end
      	end
      	
      	// 将移位寄存器的值赋给输出端口
      	always @(posedge clk) begin
      	    data_out <= shift_reg;
      	end
      	
      endmodule
      
    • 高级语句
      //1、分支语句
      case ( expression )
      	alternative1:  statement1;
      	alternative2:  statement2;
      	//多个情况公用一结果
      	3'b100 , 3'b101 : result = rega * regb; 
      		…
      		…
      	Default:default_statement;
      endcase
      //casex把x和z看成无关项,casez把z看成无关项
      //casez和casex综合的结果是一致的
      
      //2、repeat
      repeat(times)<statements>
      //3、while
      while(condition) <statements>
      //4、forever
      forever<statemeents>
      //5、for
      for(initialization;condition;caculate) <statements>
      	```
      
  • 一般声明完端口才能声明信号类型

  • 交通信号控制程序

		define Y2RDELAY 4 `define R2GDELAY 9
		module trafic_ctl(hwy, cntry, x, clk, rst);
		output [1 : 0] hwy, cntry;
		input x, clk, rst;
		// parameter Y2RDELAY = 4;
		// parameter R2GDELAY = 9;
		parameter RED = 2'd0;
		parameter YELLOW = 2'd1;
		parameter GREEN = 2'd2;
		parameter S0 = 3'd0;
		parameter S1 = 3'd1;
		parameter S2 = 3'd2;
		parameter S3 = 3'd3;
		parameter S4 = 3'd4;
		reg [1 : 0] hwy, cntry;
		reg y2r_start, y2r_ov, r2g_start, r2g_ov;
		reg [31 : 0] y2r_cnt, r2g_cnt;
		reg [2 : 0] state, nt_state;
		always @(posedge clk) begin
		if (rst) begin
		state <= S0;
		// nt_state <= S0; //multi drivers
		end
		else state <= nt_state;
		end
		always @(state) begin
		hwy <= GREEN;
		cntry <= RED;
		case (state)
		S0 : ;
		S1 : hwy <= YELLOW;
		S2 : hwy <= RED;
		S3 : begin
		hwy <= RED;
		cntry <= GREEN;
		end
		S4 : begin
		hwy <= RED;
		cntry <= YELLOW;
		end
		endcase
		end
		always @(state, x, y2r_ov, r2g_ov) begin
		case (state)
		S0 :
		if(x) nt_state <= S1;
		else nt_state <= S0;
		S1 : begin
		if (y2r_ov) begin
		nt_state <= S2;
		y2r_start <= 1'b0;
		end
		else begin
		nt_state <= S1;
		y2r_start <= 1'b1;
		end
		end
		S2 : begin
		if (r2g_ov) begin
		nt_state <= S3;
		r2g_start <= 1'b0;
		end
		else begin
		nt_state <= S2;
		r2g_start <= 1'b1;
		end
		end
		S3 : begin
		if (x)
		nt_state <= S3;
		else
		nt_state <= S4;
		end
		S4 : begin
		if (y2r_ov) begin
		nt_state <= S0;
		y2r_start <= 1'b0;
		end
		else begin
		nt_state <= S4;
		y2r_start <= 1'b1;
		end
		end
		default : nt_state <= S0;
		endcase
		end
		always @(posedge clk) begin //y2rcount
		if (rst) begin
		y2r_ov <=1'b0;
		y2r_cnt <= 0;
		end
		else begin
		if (y2r_start) begin
		if (y2r_cnt == `Y2RDELAY) begin
		y2r_ov <= 1'b1;
		y2r_cnt <= 0;
		end
		else begin
		y2r_ov <= 1'b0;
		y2r_cnt <= y2r_cnt + 1;
		end
		end
		else begin
		y2r_ov <=1'b0;
		y2r_cnt <= 0;
		end
		end
		end
		always @(posedge clk) begin //r2gcount
		if (rst) begin
		r2g_ov <=1'b0;
		r2g_cnt <= 0;
		end
		else begin
		if (r2g_start) begin
		if (r2g_cnt == `R2GDELAY) begin
		r2g_ov <= 1'b1;
		r2g_cnt <= 0;
		end
		else begin
		r2g_ov <= 1'b0;
		r2g_cnt <= r2g_cnt + 1;
		end
		end
		else begin
		r2g_ov <=1'b0;
		r2g_cnt <= 0;
		end
		end
		end
		endmodule

5.任务和函数

  • 复习

    • if语句格式
    • casex和casez异同
    • case语句中多条件项与表达式值匹配时如何处理
      • 如果 case 语句后面没有跟着 unique 或 priority 关键字,它将匹配所有表达式值的项,这称为多匹配 case 语句。
      • 在多匹配 case 语句中,所有匹配的 case 项都会被执行,这可能会导致不期望的行为,因为它们可能包含相互冲突的赋值。
    • for循环格式(reg类型循环变量注意的问题)
    • if语句和case语句如何避免产生latch逻辑
      • 确保分支条件完整
      • case语句中添加default语句
      • 使用同步复位
    • while循环语句可综合的必要条件
      • 有限、不包含阻塞赋值
      • 不能有begin语句
      • 不能有非确定性语句、时间控制语句、循环调用
    • 状态机设计时三段论是指什么
      • 确定性(Determinism):
        状态机应该是确定性的,意味着对于每个状态和输入组合,下一个状态和要执行的动作都是明确定义的,没有歧义。
      • 完整性(Completeness):
        设计的状态机应该能够处理所有可能的输入情况,确保没有遗漏的状态或转换,从而实现完整的行为覆盖。
      • 一致性(Consistency):
        状态机的设计应该是一致的,即在相同的条件下,状态机的行为应该是可预测和重复的。
  • task

    task task_name;	
    	 port and type declaration;
    	 local variables declaration;
    	 
    	 block statement;
    	…
    endtask
    
    
    • 特点:
      • 通常用于验证或抽象的行为描述
      • 可能包括输入、输出、输入端口
      • 可能包括定时控制(EX:# delays, @, wait);
      • 任务可以调用其他任务和函数
    • 使用条件(满足任一)
      • 子程序由延时、时序或事件控制语句
      • 没有输出或输出变量大于1
      • 没有输入变量
    • 一些系统任务
      //1、$monitor
      $ monitor (p1, p2,……,pn);     
       $ monitoron   enable $monitor task;
       $ monitoroff  disable $monitor task
      
      //2、$display
       $ display (“outp=%h, inp=%h”, outp, inp);
       $ display (“\nError at time %0t:”, $time);
       //%0t表示无空隔
      
      //3、$finish
      //退出仿真器,返回操作系统
      $ finish;
      $ finish(n);
      /*
      0------ 不导出任何信息
      1------ 导出当前仿真时间和位置
      2------导出当前仿真时间、位置和仿真过程CPU时间统计
       */
      
      //4、$stop
      //将EDA工具设置为暂停模式,并在仿真环境中给出交互式命令提示符。
      $ stop;
      $ stop(n);
      
      //5、$readmemb/$readmemh
      //将数据从文件读取到内存中。使用文件中的数据初始化内存。
      $readmemb/$readmemh (“<file name ”,<mem name>,< Starting address>, < End address>); 
      $ readmemb(“<file name> ”,<mem name>);
      $ readmemb(“<file name> ”,<mem name>,< Starting address>);
      $ readmemh((“<file name >”,<mem name>,< Starting address>);
      //EX:
       module test;
           reg [7:0] memory [0:1023]
           integer i;
           initial  begin $ readmemb ("init.dat", memory);
                                for (i=0;i<1024;i=i+1;)
                                $ display ("memory [%0d]=%b",  i, memory);
      				end
      endmodule    
      
      //6、$dumpfile/$dumpvars
      //系统任务,可以记录仿真结果
      $ dumpfile(“file.dump”);  //打开转储文件
      $ dumpvars();             //选择需要记录的变量
      //转存文件的格式为(VCD)
      //$dumpvars()如果没有层次的描述,转储所有信号,(0,top),转储top开始的所有层次的信号;(1,top),只转储top本层的所有信号;
      $ dumpvars;          // record all the changes of signal in each level
      $ dumpvars(0,  top.u2,  top.u1.u13.q); //record signals of top. u2 hierarchically as well as top.u1.u13.q
      $ dumpvars(1,  top); //record signals only in top module 
      $ dumpvars(2,  top.u1);//record signals in top.u1 and the son of top.u1
      $ dumpvars(3, top.u1); // record signals in top.u1, the son and grandson of top.u1。
      
      
      	```
      
      
  • 函数(function)

    function <range> function_name;
         input port and type declaration;
    	 local variables declaration; 
    	 block statement; 
    endfunction
    
    • 特点:
      • 一般用于计算/替换组合逻辑;
      • 至少一个输入,但不输出;
      • 不包括时序控制(EX:# delays, @, wait),函数在时间零执行;
      • 函数可以调用其他函数,但不能调用其他任务
      • 结果由 function_name 返回
    • 使用条件(满足所有)
      • 子程序不含延时、时序或控制结构
      • 子程序只有一个返回值
      • 至少有一个输入变量
      • 没有输出/双向变量
      • 不含有非阻塞赋值语句
    • 系统函数
      	//$time / $realtime
      $ time //return Integer value;
      $ realtime //return real value;
      //返回值与时间刻度相关
      
       $ random/$ random(seed)
       //系统函数,提供一个产生伪随机整数的手段。
      rand=$ random % b;  //产生[-b+1,b-1]的整数
      rand={$ random} % b;//产生[0,b-1]的整数
      a = {$random(2)}%256 ; //在random中给具体的值,不能得到随机数
      initial     seed = 2;
      a = {$random(seed)}%256 ;//以2为种子的随机序列
      
      $ fopen
      //文件打开,fopen()要有库支持,fdisplay()往文件中写入数据
      〈file_handle〉=$fopen("文件名");
      $fdisplay  (<文件描述号>,p1,p2,….pn);
      $fmonitor (<文件描述号>,p1,p2,….pn);
      $fclose(<文件描述号>);
      integer handle1;
      initial  begin
                        handle1= $fopen("file1.out"); 
                end 
      
  • 对比task、function

    • 任务和函数中不能声明线网类型变量,只能包含行为语句(高级编程语句和时序控制语句),但不能包含initial和always块!任务和函数可以在always 和initial块中调用
函数任务
函数不能有时序控制。任务可以包含计时控制。
函数不能调用任务任务可以调用其他任务和函数
函数必须至少有一个输入参数一个任务可以有零个或多个任何类型的参数
一个函数返回一个值一个任务输出多个值
  • 作业
    • 检测“11010”的rtl模型
module monitor_1001(din,clk,rst_,find);
  input din, clk, rst_;   output find;
  reg[3:0] shift_d4; reg[1:0] satur_timer ; reg find;
  always @(posedge clk or negedge rst_)
  begin
	if(!rst_) begin shift_d4=4’b0; find=1’b0; satur_timer=2’b0; end
	else begin
		shift_d4=shift_d4>>1;
		shift_d4[3]=din;
		 if((shift_d4==4’b1001)||(| satur_timer)) begin 
		     find=1’b1; 
                   if ((shift_d4==4’b1001)       // &&(& satur_timer)) 
		        satur_timer = 2’b01;
                   else satur_count; 
               end
               else begin
			find=1’b0; satur_timer=2’b00; end
	 end 
  end
  
  task satur_count;
      satur_timer = satur_timer + 2’b01;	
  endtask

endmodule

6、结构描述和门级建模

  • 复习
    task与function区别(时序控制语句)
    如何声明自动/可重入task/function?
    
    always/initial与task/function之间关系
    
    $monitor与$display的异同?
    相同点:
    两者都是在仿真环境中使用的,用于在控制台上显示信息。
    两者都可以用来调试和验证硬件设计,通过输出信号的值或其他信息。
    不同点:
    输出内容:
    $display 用于输出文本信息,可以是信号的值、变量的内容或自定义的文本消息。
    monitor 通常用于监视信号的变化,当指定的信号发生变化时,monitor 会输出相关信息。
    触发条件:
    $display 可以在任何时候被调用,不需要特定的触发条件。
    monitor 是由仿真环境中的事件触发的,例如信号值的变化。
    
    $time/$rtime作用
    $readmemb/$readmemh使用方法
    $random作用及使用注意问题($random(2),{$random}%N,……)
    
    
  • 结构描述
    • 电路描述方式
      • 行为描述:重点描述模块的行为,用基本门描述电路
      • 结构描述:关注模块的内部结构,用模块代替逻辑门描述电路
      • 数据流描述:关注数据流
  • 门级描述
    • 门级基元(14)
    • 开关级基元(12)
/*
1、and、nand、or、nor、xor、nxor
	gate-name(output,input1,input2,..);
	feature:only one ouput
2、buf、not
	gate-name(output1,output2,…,input)
	feature:only one input
3、bufif1、bufif0、notif1、notif0
	gate-name (output,input,enable);
	feature:include the enable->tri-state output
4、pullup、pulldown
	gate-name (ouptut);
	feature:only the output
	*/
//e.g.
or (outp, in1, in2, in3);  //无实例名称的原始实例
buf U0 (outp, in1);  //指定实例名称
notif0 #5 n0(outp, inp, enable);  //指定延迟

//全加器行为描述实例:
module fadder (sum, cout, a, b, cin);
// -------- 端口声明
   output sum, cout;
   input a, b, cin;
// -------- 数据类型声明
   reg sum, cout;
// -------- 行为级描述
      always @(a or b or cin)//过程语句
          begin			     //
            sum = a ^ b ^ cin;	     //过程赋值语句
            cout = (a & b) | ( b & cin) | (cin & a);
          end
endmodule
//全加器门级描述实例
module fadder (sum, cout, a, b, cin);
   //----------- 端口声明
  output sum, cout;
   input a, b, cin;
   wire sum, net1, net2, net3, cout;
  // ----------- 门级互连
   		xor  U0(sum, a, b, cin);
   		and U1(net1, a, b);
   		and U2(net2, a, cin);
   		and U3(net3, b, cin);
   		or    U4(cout, net1, net2, net3);
endmodule
  • 基本门、导线延迟
    • 分类
      • 门延迟:从输入端口到输出端口
      • 线网延迟:信号在线路上的传输延迟
      • 分配延迟:从右侧到左侧
#(d1,d2,d3)
d1:rise delay
d2:fall delay
d3:turn off delay-transition to tri-state
//assign有时可以表示门延时,有时可以表示传输延时
//如果只出现一个延时值,表示统一代表所有状态转移的延时;如果出现2个值,则代表d1,d2
/*
assign连续赋值语句的完整格式:
assign (对1驱动强度,对0驱动强度)#(延迟)赋值;
连线类型说明的完整格式:
连线类型 (对1驱动强度,对0驱动强度)#(延迟)连线名表项;
trireg (电荷模式说明) #(延迟)连线名表项;
基本门元件调用的完整格式:
门名 (对1驱动强度,对0驱动强度)#(延迟)调用名 (端口名表项);
当没有使用强度时,Verilog的缺省值是Strong Drive,即(strong0,strong1)
当两个驱动强度不同的连线相连时,会以强度等级较高的 连线输出为结果 
*/
  • 代码风格
    • 使代码更具可读性、可重用性和可维护性
    • 确保与大多数合成工具的兼容性。
    • 不良的编码风格会导致 RTL 和 gate 级仿真不匹配
/*
Create a block level diagram of your design before you begin coding
Always think of the poor guy who has to read your RTL code // readable
Make hierarchy
Use separate always@ processes for sequential and combinational logic
Use (=) for comb logic and (<=) for seq logic (or use <= anyway???)
Know whether you have prioritized or parallel conditions  //how to implement this?  The answer is no
Completely specify all branches of conditional statements  //avoid latch
Initialize variables  before they are assigned values in conditional statements  //avoid latch
Use high level constructs ( case, if, always@ ) as much as possible
Use technology-independent libraries such as DesignWare Libraries
Don’t instantiate gates (technology dependent) unless you have to 
Don't have combinational feedback loops
Completely specify sensitivity lists
Keep in Mind When You Writing RTL:
What can/can’t be synthesized?
What kind of results  can be expected?  
Think of  physical implementation when writing RTL code
不要在 RTL 代码中使用任何延迟
对于仿真,建议在测试台外部调整来自 RTL 的接口时序
Latch 将导致 Synthesis、STA、DFT 和 routing 中的时序分析变得困难
在边缘敏感结构中使用非阻塞过程分配
原因:避免综合前和综合后模拟之间的不匹配
所有在过程块外面赋值,且在过程块中被读取值的变量都应该在过程块的敏感表中!
不完整的敏感度列表可能会导致 RTL 模型和综合逻辑之间的仿真不匹配

*/

7、设计实例

  • 复习
结构风格建模两个主要的核心:例化什么模块,被例化的模块之间、被例化模块与其顶层模块的信号如何连接(被例化模块的端口映射)?
基本门的使用(利用结构风格描述复杂的逻辑功能)
设计经验:避免产生latch,避免RTL与门级模拟结果不一致,工艺无关的设计,并行与优先级编码逻辑(//parallel_case, full_case)
设计之前,先完成由功能规范到具体实现的设计文档(图、表、文字,信号、功能)
  • 寄存器传输级(RTL)
    • 寄存器传输级(RTL)是一种对同步数字电路的抽象模型,这种模型是根据数字信号在硬件寄存器、存储器、组合逻辑电路和总线等逻辑单元之间的流动,以及其逻辑代数运作方式来确定的。
  • 组合逻辑
组合逻辑的两种Verilog HDL表示:
-用 assign 语句:
    assign q = a1 & b1 ;  //可以用过程语句等效

-用 always 块:
 always @(al or b1) 
    begin  
         if (al==1)  q = b1 ;
         else  q = 0; 
    end
//2选1
module mux21 (outp, a, b, sel); 
    parameter SIZE = 8;
    input [SIZE – 1 : 0] a, b;
    input sel;
    output [SIZE – 1 : 0] outp; 

    assign  outp = sel ? a : b;
endmodule

注意使用 always 块时,必须注意电平敏感信号表是否完全

用 always @(沿敏感)的块语句可以为时序逻辑建模, 有三种情况:
1)无复位
   always @(posedge clock)
         flip-flop_update;
2)同步复位
   always @(posedge clock)
         if ( !reset )
              flip_flop_reset;
         else 
              flip-flop_update;
3)异步复位(低电平有效用negedge,高电平有效用posedge)
always @(posedge clock or negedge reset)
      if ( ~reset )
           flip_flop_reset;
      else if  ( condition1 )
           flip-flop_update1;
      else if ( condition2 )
           flip-flop_update2;
       else
           flip-flop_update2;

  • 什么是有限状态机( FSM ) ?
    • 有限状态机是由寄存器组和组合逻辑构成的
      硬件时序电路;
    • 其状态(即由寄存器组的 1 和 0 的组合状态所
      构成的有限个状态)只能在时钟跳变沿
      的情况下才能从一个状态转向另一个状态;
    • 究竟转向哪一状态不但取决于各个输入值,
      还取决于当前状态。
    • 状态机是数字逻辑的控制核心。
    • 根据输出信号的特点有限状态机可分为:
      Moore 状态机
      下一个状态 = F (当前状态,输入信号) 输出信号 = G (当前状态);
      Mealy 状态机
      下一个状态 = F(当前状态,输入信号);输出信号 = G(当前状态,输入信号);
    • SM 小结:
      1)在过程块中可以使用一个时钟沿和 case 语句来描述一个状态机。
      2)必须指定一个状态变量,来记录状态机的状态。
      3)要改变当前的状态,必须改变状态变量的值,其改变要与时钟沿同步。
      4)好的状态机通常为不应产生的条件规定一个默认动作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值