当前位置: 首页 > news >正文

模块功能的描述方法

目录

行为描述方法

语句块

过程赋值语句

高级程序语句

循环语句

数据流描述

结构描述

混合描述方法


module 模块名(端口列表);    // 模块声明// 端口定义input   [数据类型] [位宽]  输入端口列表;           output [数据类型] [位宽]  输出端口列表; inout   [数据类型] [位宽]  双向端口列表; // 数据类型定义wire  [位宽] 线网名,线网名,…;     reg  [位宽] 变量名,变量名,…;//函数与任务声明function [位宽] 函数名; ...; endfuctiontask 任务名; ...; endtask// 功能描述 assign 线网名=函数表达式;            // 数据流描述方式always/initial过程语句;                // 行为描述方式例化模块名 实例名(端口关联列表);    // 结构描述方式endmodule

行为描述方法

  行为描述(Behavioral Modeling)以过程语句为基本单位,在过程体内部应用高级语句和操作符描述模块的行为特性,不考虑具体的实现方法。过程语句有initial语句和always语句两种形式。

   initial过程语句称为初始化语句,无触发条件,从0时刻开始只执行一次。initial语句用在testbench文件中,用于对变量进行初始化或者产生特定的信号波形。

initial语句的语法格式为:
initial begin块内变量说明;[延时控制1] 语句1; ...end 
initial beginclk = 0;#10 clk = 1;#20 clk = 0; 
end

  当模块中存在多个的initial语句时,则所有initial语句同时从0时刻开始执行。

always 语句

  always语句有两种过程状态:等待状态和执行状态。当事件列表中无事件发生时,always语句处于等待状态;当事件列表中有事件发生时,always语句进入执行状态,执行完毕后自动返回等待状态。

  always语句应用的语法格式为:always @(事件列表)begin [:语句块名]块内变量说明;[延时控制1] 语句1; …… [延时控制n] 语句n; end

  事件列表示触发启动always过程语句执行的条件,分为电平敏感事件和边沿触发事件两种类型。

电平敏感事件是指线网/变量的电平发生变化时,触发过程语句进入执行状态。 其语法格式为: @(电平敏感量1 or … or 电平敏感量n) 语句块;

always @ (*) begin……end

  边沿触发事件是指线网/变量发生边沿跳变时执行语句块,分为上升沿触发和下降沿触发两种,分别用关键词posedge和negedge表示。

边沿触发事件的语法格式为:      @(边沿触发事件1 or … or 边沿触发事件n) 语句块;

D触发器的描述。module d_ff(clk,d,q);input clk,d;output reg q;always @( posedge clk )   // 上升沿锁存数据q <= d;endmodule
4位二进制计数器的描述。module cnt4b(clk,q);parameter Nbits = 4;input clk;output reg [Nbits-1:0] q;// 下降沿计数always @( negedge clk )  q <= q + 1'b1;endmodule

  always过程语句也可以没有触发条件,表示永远反复执行,用来产生周期性的波形,但不可综合,只能用于测试平台文件中。

  需要强调的是:在always语句的事件列表中,电平敏感事件和边沿触发事件不能混合使用。一旦事件列表中含有由posedge或者negedge引导的边沿触发事件,则不能再出现电平敏感事件,即下述形式是错误的: always @( posedge clk or rst_n)

 always @( posedge clk or negedge rst_n)if ( !rst_n )  ...else ...
过程语句应用示例。module clk_gen(clk1,clk2);output clk1,clk2;reg clk1,clk2;initial            // 定义初值beginclk1 = 0;clk2 = 0;endalways      // 产生周期性波形#50 clk1 = ~clk1;always#100 clk2 = ~clk2;endmodule

语句块

   语句块(block)是将两条或者两条以上的语句组合在一起,使其在形式上如同一条语句,其作用与C语言中的大括号“{}”相同。  语句块有顺序语句块和并行语句块两种类型。

  顺序语句块(sequential block)由关键词begin和end定义,按语句的书写顺序执行块中的语句,即前一条语句执行完后才能执行后一条语句。若使用延迟,则每条语句的延迟时间均相对于上一条语句的执行时刻而言。

顺序语句块定义的语法格式为:begin [:块名]语句1;...语句n;end
其中块名可以省略。
reg a,b,c,d;
initial begina = 1'b0;           // 仿真时刻0时执行#5  b = 1'b1;     // 仿真时刻5时执行#10 c = 1'b0;     // 仿真时刻15(=10+5)时执行#15 d = 1'b1;     // 仿真时刻30(=15+10+5)时执行end

  并行语句块(parallel block)由关键词fork和join定义,块中的所有语句从块被调用的时刻同时开始执行。若使用延迟,则每条语句的延迟时间均相对于块调用的开始时刻而言,与语句的具体书写顺序无关。

reg a,b,c,d;
initial forka = 1'b0;           // 仿真时刻0时执行#5  b = 1'b1;      // 仿真时刻5时执行#10 c = 1'b0;      // 仿真时刻10时执行#15 d = 1'b1;      // 仿真时刻15时执行join

时序控制

  时序控制用于定义从开始遇到语句到真正执行该语句时的等待时间。时序控制只用于仿真,综合时所有的延时控制将被忽略。

  时序控制有常规延时和内嵌延时两种书写形式。

应用常规延时的语法格式为:    

[#延时量] 线网/变量 = 表达式;

应用内嵌延时的语法格式为:    

线网/变量 = [#延时量] 表达式;

  在Verilog HDL中,延迟量的单位由预编译指令“`timescale”进行定义。例如,在文件头中添加语句:      `timescale 1ns /1ps 表示仿真时间单位为1ns,仿真精度为1ps。根据该命令,仿真工具才认为 #10 表示延时时间为10ns。

过程赋值语句

过程赋值(procedural assignment)语句是指在initial/always语句内部对变量进行赋值的赋值语句。

过程赋值语句的语法格式为:    <变量> <赋值操作符> <赋值表达式> ;

  赋值操作符分为两类:“=”和“<=”,分别表示阻塞赋值(blocking assignment)和非阻塞赋值(non-blocking assignment)。

  阻塞赋值按照语句的书写顺序进行赋值。也就是说,在前一条赋值语句执行结束之前,后一条语句被阻塞,不能执行。只有前一条赋值语句执行结束后,后一条语句才能被执行。

module eq1b(a,b,eq);input a,b;output reg eq;reg tmp1,tmp2;always @(a,b)begintmp1 = ~a & ~b;tmp2 = a & b;eq = tmp1 | tmp2;end
endmodule

  非阻塞赋值是指多条赋值语句同时赋值,与语句的书写顺序无关,即后面赋值语句的执行不受前面赋值语句的影响。  由于阻塞赋值与非阻塞赋值的赋值方法不同,因此综合出的电路存在差异,所以必须正确地区分和应用这两类赋值语句。

 module blocking(din,clk,reg1,reg2);input din,clk;output reg reg1,reg2;always @(posedge clk)beginreg1 = din;reg2 = reg1;endendmodule

  当模块中既包含组合逻辑又包含时序逻辑时,应该将组合逻辑和时序逻辑分开进行描述。可以用一个always语句描述时序逻辑,用另一个always语句描述组合逻辑,或者改用连续赋值语句描述组合逻辑。

 module blocking(din,clk,reg1,reg2);input din,clk;output reg reg1,reg2;always @(posedge clk)beginreg1 <= din;reg2 <= reg1;endendmodule

高级程序语句

  Verilog HDL中的高级程序语句和C语言一样,用于控制代码的流向,分为条件语句、分支语句和循环语句三种类型。

  条件语句(conditional statement)使用关键词if和else,根据条件表达式的真假确定执行的操作,用于对赋值过程进行控制,分为简单条件语句、分支条件语句和多重语句三种类型。

module d_latch(clk,d,q);  input clk,d;output reg q;always @(clk,d)if (clk) q <= d;endmodule

  由于简单条件语句没有定义条件表达式为假时执行的操作,隐含条件表达式为假时不执行任何操作,所以被赋值的变量应该保持不变,因而会综合出时序电路。

分支条件语句的语法格式为:   if(条件表达式)     条件表达式为真时执行的语句块;   else     条件表达式为假时执行的语句块;

module mux2to1 (y,d0,d1,sel);input d0,d1,sel;output reg y;always @(d0,d1,sel)beginif ( !sel ) y = d0;elsey = d1;endendmodule

如果用下述代码描述双向口:

module BiDir_Port(dir,a,b);input dir;     // 双向控制端inout a,b;     // 两个双向口reg atmp,btmp;assign a=atmp;assign b=btmp;always @ (dir,a,b) if ( dir )  atmp = b;  else btmp = a;  
endmodule

描述双向口正确的Verilog代码参考如下:

module BiDir_Port(dir,a,b);input dir;       // 双向控制端inout a,b;       // 两个双向口reg atmp,btmp;assign a=atmp;assign b=btmp;always @ (dir,a,b) if (dir) begin atmp = b; btmp = 1’bz; endelse begin btmp = a; atmp = 1’bz; end
endmodule

具有异步复位功能的4位二进制计数器的描述

module cnt4b(clk,rst_n,q);input clk,rst_n;output [3:0] q;reg [3:0] q;always @(posedge clk or negedge rst_n)beginif ( !rst_n )  // 低电平有效q <= 4'b0000;elseq <= q + 1'b1;end
endmodule

多重条件语句常用于多路选择, 其语法格式为:

if(条件表达式1) 条件表达式1为真时执行的语句块;  

else if(条件表达式2)   条件表达式2为真时执行的语句块;    ……    

else if(条件表达式n)      条件表达式n为真时执行的语句块;    

else      条件表达式1~n均为假时执行的语句块;

  多重条件语句对条件表达式的判断有先后次序,隐含有优先级的关系,先判断的条件表达式优先级高,后判断的条件表达式优先级低。因此,多重条件语句通常用于描述有优先级的逻辑电路。

4线-2线优先编码器的描述。module prior_encoder(d,c,b,a,y);input d,c,b,a;output reg [1:0] y;always @ (d,c,b,a)beginif (d) y = 2'b11;else if (c) y = 2'b10;else if (b) y = 2'b01;else  y = 2'b00;endendmodule 

分支语句使用关键词case...endcase引导,功能相当于C语言中的switch语句,用于实现多路选择。

 用分支语句描述2选一数据选择器。
module mux2to1(d0,d1,sel,y);input d0,d1,sel;output y;reg y;always @ (d0,d1,sel) case ( sel )1'b0:  y = d0;1'b1:  y = d1;default: y= d0;endcaseendmodule

  在Verilog HDL中,通常用字符“?”代替字符x和z,表示无关位。

  always @ (d,c,b,a)begincasez({d,c,b,a})4'b1???: y = 2'b11;4'b01??: y = 2'b10;4'b001?: y = 2'b01;4'b0001: y = 2'b00;default: y = 2'b00;endcaseendendmodule

循环语句

  循环语句的作用与C语言相同。Verilog HDL支持4类循环语句:for、while、repeat和forever语句,其中for语句、while语句的用法与C语言相同。

用移位累加方法描述乘法器。module multi(result,op_a,op_b);parameter Nbits=8;          // 参数定义input [Nbits:1] op_a,op_b;  // 被乘数与乘数output [2*Nbits:1] result;   // 乘法结果reg [2*Nbits:1] result;integer i;                      // 循环变量always @(op_a, op_b)begin  result = 0;for(i=1;i<=Nbits;i=i+1)if(op_b[i]) result = result+(op_a<<(i-1));  endendmodule

需要注意的是,Verilog不支持i++和i--这种循环增量的书写方式,递加和递减只能写成i=i+1和i=i-1。

while语句的语法格式为: while(循环条件表达式)   语句块;

  如果while循环中条件表达式的值为x或者z时,则循环次数为0。

parameter Nbits=8;
reg [2*Nbits:1] atmp;   // 定义内部变量
reg [Nbits:1]  btmp;    
integer i;                // 定义循环变量
always @(op_a,op_b)begin  result = 0;atmp = {{Nbits{1'b0}},op_a};  // 拼接扩展btmp = op_b;   i = Nbits;while (i>0)  begin if ( btmp[1] ) result = result + atmp;  i = i-1;               // 循环次数减1atmp = atmp << 1;   // 左移一位 btmp = btmp >> 1;   // 右移一位end       end

repeat语句的语法格式为:   repeat(循环次数表达式)              语句块;

parameter Nbits=8;
reg [2*Nbits:1] atmp;
reg [Nbits:1] btmp;
always @(op_a,op_b)beginresult = 0;atmp = op_a;btmp = op_b;repeat (Nbits)    // 循环次数由Nbits确定begin if ( btmp[1] ) result = result + atmp;atmp = atmp << 1; btmp = btmp >> 1;endend

数据流描述

  数据流描述(Dataflow Modeling)采用连续赋值语句,基于表达式和操作符描述线网的功能,用于组合逻辑电路的描述。连续赋值语句的语法格式为:   assign [#延迟量] 线网名 = 赋值表达式;

用数据流描述2选一数据选择器。module MUX2to1(y,d0,d1,sel);input d0,d1,sel;output y;assign y= ~sel & d0 | sel & d1; endmodule

  需要说明的是:(1)连续赋值语句用于对线网进行赋值,不能对变量进行赋值;(2)连续赋值语句和过程语句为平等关系,不能相互嵌套使用;(3)连续赋值语句的执行顺序与语句书写的顺序无关。

结构描述

  结构描述(Structural Modeling)方法类似于原理图设计,是将电路中的基元、模块和功能IP之间的连接关系由连线转换为文字表达。

  Verilog HDL预定义了26个基本元器件(primitives,简称基元),包括逻辑门和三态门,上拉电阻和下拉电阻,以及MOS开关和双向开关。

 Verilog基元分为以下六种类型: ▪ 多输入门:and, nand, or, nor, xor, xnor ▪ 多输出门:buf, not ▪ 三态门:bufif0, bufif1, notif0, notif1 ▪ 上拉电阻/下拉电阻:pullup, pulldown ▪ MOS开关:cmos, nmos, pmos, rcmos, rnmos, rpmos ▪ 双向开关:tran, tranif0, tranif1, rtran, rtranif0, rtranif1

结构描述的代码参考如下:module mux2to1(y,a,b,sel);output y;input a,b,sel;wire sel_n,a1,b1;not G1 (sel_n,sel);and G2 (a1,a,sel_n);and G3 (b1,b,sel);or G4 (y,a1,b1);endmodule

混合描述方法

  Verilog HDL支持三种描述方式的混合使用,即在同一模块中可以混合使用过程语句、连续赋值语句和例化语句。

全加器的混合描述。module Full_Adder(A,B,Cin,Sum,Co);input A,B,Cin;output Sum,Co;reg Co;wire Wtmp;xor U1(Wtmp,A,B);                    // 结构描述,实现Wtmp=A^Bassign Sum = Wtmp ^ Cin;            // 数据流描述,实现Sum=Wtmp^Cinalways @ ( A or B or Cin )            // 行为描述Co = A & Cin | B & Cin | A & B;    // 过程赋值语句endmodule


http://www.mrgr.cn/news/65855.html

相关文章:

  • 《毛选》:变优秀最直接的方法,学会复盘
  • 关于Linux系统调试和性能优化技巧有哪些?
  • 老板电器芯邦CBM7332触摸式净化水槽硬件和程序
  • Redis 的使⽤和原理
  • 程序《工资分类收税》
  • word试题转excel(最简单的办法,无格式要求)
  • 理解数据加载器(Data Loader)
  • OSI参考模型
  • Java 8的关键新特性:JDK加解密、Lambda表达式、日期时间API及Optional类
  • Vue全栈开发旅游网项目(6)-接口开发
  • Java 基本数据类型 和 输入输出语句
  • 【编程语言】Kotlin快速入门 - 泛型
  • 全面解析:云计算技术及其应用
  • 【Linux 27】HTTP 协议中的 cookie 和 session
  • C++算法练习-day34——257.二叉树的所有路径
  • MATLAB实现图像恢复设计报告
  • 掌握 In-Context Learning (ICL):构建高效 Prompt 的技巧与调优策略
  • Java | Leetcode Java题解之第539题最小时间差
  • 使用QtWebEngine的Mac应用如何发布App Store
  • 文件操作和 IO(二):文件内容操作 => 流对象
  • 小北的字节跳动青训营与LangChain实战课:深入解析模型I/O与提示模板(持续更新中~~~)
  • Java 入门
  • DFS求解迷宫最长移动路线
  • 助力风力发电风机设备智能化巡检,基于YOLOv8全系列【n/s/m/l/x】参数模型开发构建无人机巡检场景下风机叶片缺陷问题智能化检测预警模型
  • Java基础06(代码运行时的内存图)
  • 基于matlab的图像形状与分类的方法比较