Verilog 时延与过程结构

简介: 连续赋值延时语句中的延时,用于控制任意操作数发生变化到语句左端赋予新值之间的时间延时。时延一般是不可综合的。寄存器的时延也是可以控制的,这部分在时序控制里加以说明。连续赋值时延一般可分为普通赋值时延、隐式时延、声明时延。下面 3 个例子实现的功能是等效的,分别对应 3 种不同连续赋值时延的写法。

一、关键词:时延, 惯性时延

连续赋值延时语句中的延时,用于控制任意操作数发生变化到语句左端赋予新值之间的时间延时。

时延一般是不可综合的。

寄存器的时延也是可以控制的,这部分在时序控制里加以说明。

连续赋值时延一般可分为普通赋值时延、隐式时延、声明时延。

下面 3 个例子实现的功能是等效的,分别对应 3 种不同连续赋值时延的写法。

//普通时延,A&B计算结果延时10个时间单位赋值给Z
wire Z, A, B ;
assign #10    Z = A & B ;
//隐式时延,声明一个wire型变量时对其进行包含一定时延的连续赋值。
wire A, B;
wire #10        Z = A & B;
//声明时延,声明一个wire型变量是指定一个时延。因此对该变量所有的连续赋值都会被推迟到指定的时间。除非门级建模中,一般不推荐使用此类方法建模。
wire A, B;
wire #10 Z ;
assign           Z =A & B

1、惯性时延

在上述例子中,A 或 B 任意一个变量发生变化,那么在 Z 得到新的值之前,会有 10 个时间单位的时延。如果在这 10 个时间单位内,即在 Z 获取新的值之前,A 或 B 任意一个值又发生了变化,那么计算 Z 的新值时会取 A 或 B 当前的新值。所以称之为惯性时延,即信号脉冲宽度小于时延时,对输出没有影响。

因此仿真时,时延一定要合理设置,防止某些信号不能进行有效的延迟。

对一个有延迟的与门逻辑进行时延仿真。

module time_delay_module(
    input   ai, bi,
    output  so_lose, so_get, so_normal);
    assign #20      so_lose      = ai & bi ;
    assign  #5      so_get       = ai & bi ;
    assign          so_normal    = ai & bi ;
endmodule

testbench 参考如下:

`timescale 1ns/1ns
module test ;
    reg  ai, bi ;
    wire so_lose, so_get, so_normal ;
    initial begin
        ai        = 0 ;
        #25 ;      ai        = 1 ;
        #35 ;      ai        = 0 ;        //60ns
        #40 ;      ai        = 1 ;        //100ns
        #10 ;      ai        = 0 ;        //110ns
    end
    initial begin
        bi        = 1 ;
        #70 ;      bi        = 0 ;
        #20 ;      bi        = 1 ;
    end
    time_delay_module  u_wire_delay(
        .ai              (ai),
        .bi              (bi),
        .so_lose         (so_lose),
        .so_get          (so_get),
        .so_normal       (so_normal));
    initial begin
        forever begin
            #100;
            //$display("---gyc---%d", $time);
            if ($time >= 1000) begin
                $finish ;
            end
        end
    end
endmodule

仿真结果如下:

信号 so_normal 为正常的与逻辑。

由于所有的时延均大于 5ns,所以信号 so_get 的结果为与操作后再延迟 5ns 的结果。

信号 so_lose 前一段是与操作后再延迟 20ns 的结果。

由于信号 ai 第二个高电平持续时间小于 20ns,so_lose 信号会因惯性时延而漏掉对这个脉冲的延时检测,所以后半段 so_lose 信号仍然为 0。

2、源码下载

Download

二、关键词:initial, always

过程结构语句有 2 种,initial 与 always 语句。它们是行为级建模的 2 种基本语句。

一个模块中可以包含多个 initial 和 always 语句,但 2 种语句不能嵌套使用。

这些语句在模块间并行执行,与其在模块的前后顺序没有关系。

但是 initial 语句或 always 语句内部可以理解为是顺序执行的(非阻塞赋值除外)。

每个 initial 语句或 always 语句都会产生一个独立的控制流,执行时间都是从 0 时刻开始。

1、initial语句

initial 语句从 0 时刻开始执行,只执行一次,多个 initial 块之间是相互独立的。

如果 initial 块内包含多个语句,需要使用关键字 begin 和 end 组成一个块语句。

如果 initial 块内只要一条语句,关键字 begin 和 end 可使用也可不使用。

initial 理论上来讲是不可综合的,多用于初始化、信号检测等。

对上一节代码稍作修改,进行仿真,代码如下。

`timescale 1ns/1ns
module test ;
    reg  ai, bi ;
    initial begin
        ai         = 0 ;
        #25 ;      ai        = 1 ;
        #35 ;      ai        = 0 ;        //absolute 60ns
        #40 ;      ai        = 1 ;        //absolute 100ns
        #10 ;      ai        = 0 ;        //absolute 110ns
    end
    initial begin
        bi         = 1 ;
        #70 ;      bi        = 0 ;        //absolute 70ns
        #20 ;      bi        = 1 ;        //absolute 90ns
    end
    //at proper time stop the simulation
    initial begin
        forever begin
            #100;
            //$display("---gyc---%d", $time);
            if ($time >= 1000) begin
                $finish ;
            end
        end
   end
endmodule

仿真结果如下:

可以看出,2 个 initial 进程语句分别给信号 ai,bi 赋值时,相互间并没有影响。

信号 ai,bi 的值按照赋值顺序依次改变,所以 initial 内部语句也可以看做是顺序执行。

2、always 语句

与 initial 语句相反,always 语句是重复执行的。always 语句块从 0 时刻开始执行其中的行为语句;当执行完最后一条语句后,便再次执行语句块中的第一条语句,如此循环反复。

由于循环执行的特点,always 语句多用于仿真时钟的产生,信号行为的检测等。

下面用 always 产生一个 100MHz 时钟源,并在 1010ns 时停止仿真代码如下。

代码如下:

`timescale 1ns/1ns
module test ;
    parameter CLK_FREQ   = 100 ; //100MHz
    parameter CLK_CYCLE  = 1e9 / (CLK_FREQ * 1e6) ;   //switch to ns
    reg  clk ;
    initial      clk = 1'b0 ;      //clk is initialized to "0"
    always     # (CLK_CYCLE/2) clk = ~clk ;       //generating a real clock by reversing
    always begin
        #10;
        if ($time >= 1000) begin
            $finish ;
        end
    end
endmodule

仿真结果如下:

可见,时钟周期是我们想要得到的 100MHz。而且仿真在 1010ns 时停止。

3、源码下载

Download

相关文章
|
存储 编解码 算法
信道编码概述 |带你读《5G空口特性与关键技术》之六
纠错编码的目的,是通过尽可能小的冗余开销确保接收端能自动地纠正数据传输中所发生的差错。在同样的误码率下,所需要的开销越小,编码的效率也就越高。
11505 2
信道编码概述 |带你读《5G空口特性与关键技术》之六
|
存储 缓存 5G
时域结构 | 带你读《5G 空口设计与实践进阶 》之十七
在时域,NR 支持基于符号灵活定义的帧结构,以满足各种时延需求。
时域结构 | 带你读《5G 空口设计与实践进阶 》之十七
路径损耗计算模型 | 带你读《大规模天线波束赋形技术原理与设计 》之二十五
本小节介绍 3D 信道的路损模型,是以 ITU 信道为基础拓展得到的。
12696 0
路径损耗计算模型  | 带你读《大规模天线波束赋形技术原理与设计 》之二十五
|
5月前
|
算法 数据安全/隐私保护 异构计算
基于FPGA的MSK调制解调系统verilog开发,包含testbench,同步模块,高斯信道模拟模块,误码率统计模块
升级版FPGA MSK调制解调系统集成AWGN信道模型,支持在Vivado 2019.2中设置不同SNR仿真误码率。示例SNR值从0到15,结果展示解调质量随SNR提升。MATLAB仿真验证了MSK性能,图片显示了仿真结果。 ### 理论概要 研究聚焦于软件无线电中的MSK调制解调,利用Verilog实现。MSK是一种相位连续、恒包络的二进制调制技术,优点包括频谱效率高。系统采用无核设计,关键模块包括调制器、解调器和误码检测。复位、输入数据、中频信号等关键信号通过Verilog描述,并通过Chipscope在线观察。
115 6
基于FPGA的MSK调制解调系统verilog开发,包含testbench,同步模块,高斯信道模拟模块,误码率统计模块
|
5G 调度 芯片
5G 帧结构 |带你读《5G空口特性与关键技术》之七
虽然在较高的载波频率下通常不使用较小的子载波间隔,但是参数集可以独立于频段进行选择。不同子载波间隔可用于不同的场景下。如对于室外宏覆盖和微小区,可以采用 30kHz 子载波间隔;而室内站则可以采用 60kHz 子载波间隔;对于毫米波,则可以采用更大的子载波间隔,如 120kHz。
11471 2
5G 帧结构 |带你读《5G空口特性与关键技术》之七
|
芯片 异构计算
第三章 硬件描述语言verilog(三)功能描述-时序逻辑
第三章 硬件描述语言verilog(三)功能描述-时序逻辑
279 0
第三章 硬件描述语言verilog(三)功能描述-时序逻辑
|
前端开发 调度 芯片
【芯片前端】根据数据有效选择输出的握手型FIFO结构探究
【芯片前端】根据数据有效选择输出的握手型FIFO结构探究
带你读《5G大规模天线增强技术》——2.2.1 信道的表达式
带你读《5G大规模天线增强技术》——2.2.1 信道的表达式
|
存储 缓存 算法
m基于FPGA的交织解交织系统verilog实现,包含testbench
m基于FPGA的交织解交织系统verilog实现,包含testbench
316 0