【学习笔记】Verilog之四:结构建模方法

简介: Verilog 提供两种建模方法:行为建模和结构建模。行为建模专注于电路功能描述,类似高级编程语言,不涉及底层实现。数据流建模使用 `assign` 进行连续赋值,适合描述组合逻辑。线网可以在声明时直接赋值。顺序行为建模通过 `initial` 和 `always` 语句实现,`initial` 用于一次性初始化,`always` 则用于响应特定事件的重复执行。时序控制包括时延和事件控制,用于精确控制电路行为。阻塞和非阻塞赋值决定了语句执行的顺序和并发性。过程性连续赋值如 `assign-deassign` 和 `force-release` 提供了更多灵活性。

Verilog 提供两种主要的建模方法:行为建模和结构建模。结构建模聚焦于电路的具体物理结构描述,而行为建模则侧重于电路功能的描述,类似于高级编程语言的风格,如C语言,不涉及底层实现细节。

3.1 数据流行为建模

数据流建模是一种简洁的行为建模方式,核心在于使用assign关键字进行连续赋值,适用于描述组合逻辑电路。

连续赋值语句
  • 语法:assign LHS_target = RHS_expression;
  • LHS_target: 目标线网
  • RHS_expression: 赋值操作表达式

示例:

Verilog

wire[3:0] z, preset, clear;
assign z = preset & clear;
  • 赋值目标: 包括标量线网、向量线网、向量的位选择、向量的部分选择及这些类型的连接结果。
  • 执行机制: 右侧操作数变化时,表达式重新计算并将新结果赋给左侧线网。
  • 时延: 支持上升时延、下降时延和关闭时延,语法为assign #(rise, fall, turn-off) LHS_target = RHS_expression;。
线网声明赋值

线网可在声明时直接赋值,例如:

Verilog

wire[3:0] sum = 4'b0;

时延的概念

  • 时延: 定义程序暂停的单位时间长度,默认时延为0。
  • 线网时延: 时延可内置于线网声明中,用于控制赋值的时机。

数据流建模实例:一位全加器

使用数据流建模方式实现一位全加器,可以直观展示连续赋值语句的使用。

Verilog

module FullAdder(input a, b, cin, output sum, cout);
    wire carry;
    assign sum = a ^ b ^ cin;
    assign carry = (a & b) | (a & cin) | (b & cin);
    assign cout = carry | (sum & cin);
endmodule

在这个例子中,a、b和cin是输入,sum和cout是输出。sum是半加器的输出,而cout是进位输出,通过连续赋值语句assign直接计算得出。





3.2 语句块


3.2.1 顺序行为建模:Initial与Always语句

在Verilog的顺序行为描述中,initial和always语句是构建动态逻辑行为的核心。它们不仅限于单一语句,而是引导了一系列的过程或结构,允许更复杂的控制流和时序逻辑的描述。

Initial语句

  • 执行时机:仅执行一次,在仿真启动的瞬间(时刻0)。
  • 封装结构:通常采用begin-end块封装多条语句,形成顺序执行的语句块。
  • 局部变量:若语句块中使用局部变量,如integer Index;,则需命名该语句块。

示例:

Verilog

parameter SIZE = 1024;
reg[7:0] RAM [0:SIZE-1];
reg RibReg;

initial begin: SEQ_BLK_A
   integer Index;
   RibReg = 0;
   for (Index = 0; Index < SIZE; Index = Index + 1)
       RAM[Index] = 0;
end

Always语句

  • 执行时机:从时刻0开始,依据时序控制条件重复执行。
  • 时序控制:通过@符号定义事件触发或使用wait关键字定义电平敏感事件。
  • 执行模式:与initial不同,always可根据条件多次触发执行。

语法格式:

Verilog

1always [timing_control] procedural_statement

其中,

  • timing_control:时序控制,可为时延控制或事件控制。
  • procedural_statement:过程语句,描述具体的逻辑行为。

示例:

Verilog

always @(posedge clk or negedge rst)
    if (!rst)
        Q <= 1'b0;
    else
        Q <= D;

小结

在Verilog设计中,initial和always语句是实现顺序行为建模的关键工具。initial语句适用于一次性初始化,而always语句则用于响应特定事件或条件的重复执行,两者结合提供了灵活的时序逻辑描述能力。通过适当的封装和时序控制,可以精确控制电路的动态行为,满足复杂逻辑设计的需求。






3.2.2 时序控制

时序控制是Verilog中用于精确控制电路行为的重要机制,主要包括时延控制和事件控制两大类。

时延控制

时延控制允许在指定的时间间隔后执行操作,主要形式包括:

  • 语句前时延
  • 单独时延
  • 语句内时延

示例:

Verilog

Done = #5 (A & B);

等价于:

Verilog

begin
    tmp = (A & B);
    #5 Done = tmp;
end

值得注意的是,显示零时延(#0)将导致当前仿真时间点的执行挂起,直到所有同时发生的事件处理完毕。

事件控制

事件控制通过监测特定事件的发生来触发操作,分为边沿触发事件和电平敏感事件。

边沿触发事件

使用@符号定义,可监测一个或多个事件,多个事件间使用or关键字分隔。

示例:

Verilog

always @(posedge clk or negedge rst)
    if (!rst)
        Q <= 1'b0;
    else
        Q <= D;
电平敏感事件

使用wait关键字定义,等待条件满足后执行后续过程。

示例:

Verilog

wait (condition);
    // process statements

其中,condition定义了电平敏感事件的触发条件。

小结

通过时延控制和事件控制,Verilog提供了丰富的机制来精确控制电路的时序行为。无论是简单的时延操作,还是复杂的边沿触发和电平敏感事件,都能有效地模拟和控制电路的动态特性。理解并熟练运用这些时序控制机制,是Verilog设计中不可或缺的一部分。





3.2.3 Verilog中的语句块与赋值机制


在Verilog中,语句块分为两类:顺序语句块和并行语句块,分别用于控制语句的执行顺序和并行度。

  1. 顺序语句块:使用begin-end结构,确保语句按顺序执行。
  2. 并行语句块:使用fork-join结构,使语句块中的语句并行执行,不依赖于书写顺序。

过程性赋值

过程性赋值是Verilog中最常用的赋值形式,特点如下:

  • 出现在initial和always语句中。
  • 专用于寄存器变量赋值。
  • 右侧表达式可以是任意类型。

过程性赋值分为阻塞和非阻塞两种:

  1. 阻塞过程赋值:使用=操作符,执行赋值时会阻塞后续语句。
  2. 非阻塞过程赋值:使用<=操作符,赋值与后续语句并行执行。

混合使用阻塞与非阻塞赋值

在Verilog设计中,阻塞与非阻塞赋值的混合使用是常见的,需要根据设计需求和性能考虑来决定。

过程性连续赋值

不同于标准的连续赋值,过程性连续赋值结合了过程赋值的灵活性和连续赋值的响应性,支持对寄存器和线网赋值。

  • assign-deassign:用于寄存器赋值,assign赋值,deassign取消赋值。
  • force-release:用于线网和寄存器的强制赋值和释放,force覆盖当前值,release恢复原状。

示例代码

以下示例代码,展示assign-deassign和force-release的使用:

Verilog

module DEF(D, Clr, Clk, Q);
    input D, Clr, Clk;
    output Q;
    reg Q;

    always @(negedge Clk)
        Q = D;

    always @(Clr)
        if (!Clr) begin
            assign Q = 0;
        end else begin
            deassign Q;
        end
endmodule


// Force-release example
module ForceRelease(Colt);
    reg[2:0] Colt;
    wire prt;
    or #1 (prt, Std, Dzx); // Or gate definition

    initial begin
        Colt = 2;
        force Colt = 1;
        release Colt;
        assign Colt = 5;
        force Colt = 3;
        release Colt;
    end

    initial begin
        force prt = Dzx & Srd;
        #5;
        release prt;
    end
endmodule


以上代码展示了assign-deassign和force-release的使用,以及如何通过fork-join和begin-end块来控制语句的执行顺序和并行性。通过这些机制,Verilog提供了强大的手段来描述和控制电路行为。




3.2.5 If语句

If语句用于条件分支控制,如果一个分支包含多条过程语句,应使用begin-end块将其包裹,类似于C语言中的大括号{}。



3.2.6 Case语句

Case语句用于多路分支选择,特别指出的是,当条件表达式或分支表达式中的某些位出现未知值x或高阻态z时,这些值在比较中仍具有意义,只要在相同位置出现x或z,就被视为相等。

  • casex和casezcasex和casez语句提供了特殊处理x和z的方式:
  • casez:在比较中,值z被视为无关值,即在该位出现z时,该位在比较中被忽略。
  • casex:值x和z都被视为无关位,只要其余位匹配,即认为两个值相等。



3.2.7 循环语句

循环语句允许重复执行一组过程语句,Verilog提供了多种循环控制结构。

  1. forever循环
    forever循环持续不断地执行过程语句,无需声明循环变量。其语法格式为:
  2. Verilog
forever
    procedural_statement
  1. 注意:forever循环中必须包含时序控制,否则将在0时延后无限循环。forever循环常用于生成周期性波形,作为仿真测试信号。
  2. repeat循环
    repeat循环执行固定次数的过程语句,通过loop_count控制循环次数。语法格式如下:
  3. Verilog
repeat(loop_count)
    procedural_statement
  1. 若loop_count为不确定值(如x或z),则循环次数被视为0。
    示例:
  2. Verilog
repeat(Count) @ (posedge Clk) Sum <= Sum + 1;
  1. 此示例中,首先计算Sum + 1的值,然后等待Clk的上升沿,最后执行赋值操作。
  2. while循环
    while循环在条件为真时重复执行过程语句,直至条件变为假。
  3. for循环
    for循环提供了一种结构化的循环控制,包括初始化、条件检查和循环变量更新三个部分。

示例代码

以下示例代码,展示了Verilog中的控制结构使用:

Verilog

module ControlStructures(
    input wire clk,
    input wire reset,
    output reg [3:0] counter
);

    always @(posedge clk or posedge reset) begin
        if (reset) begin
            counter <= 4'b0;
        end else begin
            if (counter == 4'b1111) begin
                counter <= 4'b0;
            end else begin
                counter <= counter + 1;
            end
        end
    end

    always @(counter) begin
        case(counter)
            4'b0000: output <= "Zero";
            4'b0001: output <= "One";
            4'b0010: output <= "Two";
            default: output <= "Other";
        endcase
    end

    initial begin
        forever #10 counter <= counter + 1;
    end

    always @(counter) begin
        repeat(4) @(negedge clk);
    end

endmodule

以上代码展示了if语句、case语句、forever循环以及repeat循环的使用,体现了Verilog中控制结构的多样性和灵活性。



相关文章
|
6月前
|
数据采集 人工智能 算法
大模型竞赛——从参数膨胀到效能革命的转折
2023年至2025年,全球人工智能领域经历了一场前所未有的“大模型军备竞赛”。
701 0
|
程序员 人工智能 Serverless
通义灵码保姆级教程:官网、安装、使用指南、常见问题、线上活动、官方答疑
通义灵码保姆级教程:官网、安装、使用指南、常见问题、线上活动、官方答疑
24509 1
|
10月前
|
文字识别 数据可视化 算法
基于 YOLOv8 的智能车牌定位检测系统设计与实现—从模型训练到 PyQt 可视化落地的完整实战方案
本项目基于YOLOv8实现智能车牌定位检测,涵盖数据处理、模型训练、评估优化及PyQt5可视化界面开发,支持图片、视频、摄像头实时检测。系统精度高、响应快,提供完整代码与预训练模型,适合毕设、课程设计及二次开发,助力智慧交通应用落地。(238字)
715 7
基于 YOLOv8 的智能车牌定位检测系统设计与实现—从模型训练到 PyQt 可视化落地的完整实战方案
|
芯片 异构计算
第三章 硬件描述语言verilog(三)功能描述-时序逻辑
第三章 硬件描述语言verilog(三)功能描述-时序逻辑
1046 0
第三章 硬件描述语言verilog(三)功能描述-时序逻辑
|
移动开发 前端开发 数据安全/隐私保护
iOS发布证书.p12文件无密码解决办法及导出带密码的新.p12文件方法
本文将以iOS技术博主身份,分享解决使用无密码的.p12文件发布应用时遇到的问题,并介绍如何以带密码的方式重新导出.p12文件的方法。通过本文提供的步骤,开发者可以顺利完成证书的发布流程。
|
消息中间件 算法 Java
金石推荐 |【算法数据结构专题】「延时队列算法」史上手把手教你针对层级时间轮(TimingWheel)实现延时队列的开发实战落地(上)
金石推荐 |【算法数据结构专题】「延时队列算法」史上手把手教你针对层级时间轮(TimingWheel)实现延时队列的开发实战落地(上)
571 1
|
前端开发 JavaScript API
赶快收藏!全网最佳websocket封装:完美支持断网重连、自动心跳!
【8月更文挑战第17天】赶快收藏!全网最佳websocket封装:完美支持断网重连、自动心跳!
1168 3
赶快收藏!全网最佳websocket封装:完美支持断网重连、自动心跳!
|
Kubernetes 大数据 Docker
Kubernetes 应用问题的通用排查思路 - 大数据从业者之 Kubernetes 必知必会
Kubernetes 应用问题的通用排查思路 - 大数据从业者之 Kubernetes 必知必会
|
存储 机器学习/深度学习 人工智能
图的存储及基本操作总结(邻接矩阵、邻接表)及C/C++代码实现
图的存储及基本操作总结(邻接矩阵、邻接表)及C/C++代码实现
2395 1
|
移动开发 前端开发 JavaScript
移动端H5网页开发常见问题汇总
H5网页开发常见问题汇总
1448 0