FPGA(一)verilog语句基础

        Verilog 是一种硬件描述语言(HDL),常用于数字电路的设计、模拟和验证,特别是用于 FPGAASIC 的设计。Verilog 让设计者能够描述和模拟硬件系统的行为和结构,最终将其转化为硬件电路。

一、模块结构

        Verilog 中的设计是基于模块的,一个模块可以代表一个电路单元、一个功能模块或者整个系统。模块的基本结构如下:

/*
    module_name:模块的名称,自定义。
    input1, input2:输入端口,表示外部信号进入模块。
    output:输出端口,表示模块的输出信号。
*/
module module_name (input1, input2, output);
  
// Module code here

endmodule

        Verilog 中的信号通常分为 输入(input)、输出(output)和 双向(inout)。输入是从外部传入模块的信号,输出是从模块传出的信号。 双向可作为输入或输出,通常用于双向信号,如总线。

1. 模块的结构

 举例1:二选一数据选择器的Verilog描述。

module MUX21a(a,b,s,y);
    input a,b,s;
    output y;
    assign y=(s?a:b);
endmodule

 举例2:边沿D触发器的Verilog描述。

module D_flip_flop (
  input clk,      // 时钟信号
  input D,        // 数据输入
  output reg Q    // 数据输出
);
  always @(posedge clk) begin  // 每当时钟上升沿触发
    Q <= D;  // 非阻塞赋值
  end
endmodule

 2. 模块的实例化

        是 Verilog 语言中的一个重要概念,它允许你在一个顶层模块中创建和使用其他子模块。通过模块实例化,你可以将设计中的一个功能(即模块)“复制”并在另一个模块中使用,从而实现模块化设计。

//1. 定义了一个D触发器的模块
module D_flip_flop(
    input CLK,         // 时钟信号
    input D,           // 数据输入
    output reg Q       // 数据输出
);
    always @(posedge CLK) begin
        Q <= D;  // 在时钟的上升沿,将 D 的值传递给 Q
    end
endmodule

module top_module(
    input clk,          // 时钟信号
    input d,            // 输入信号 d
    input a,            // 输入信号 a
    output reg q        // 输出信号 q
);

    wire d1;            // OR 门的输出信号
    wire q1;            // 第一个 D 触发器的输出信号

    // OR 门逻辑:d1 = a | q
    assign d1 = a | q;

    // 第一个 D 触发器实例化
    DFF dff1 (
        .CLK(clk),       // 时钟信号
        .D(d1),          // 输入信号 d1
        .Q(q1)           // 输出信号 q1
    );

    // 第二个 D 触发器实例化
    DFF dff2 (
        .CLK(clk),       // 时钟信号
        .D(q1),          // 输入信号 q1
        .Q(q)            // 输出信号 q
    );

endmodule

3. 原门

        原门(Primitive Gates) 是在硬件描述语言(如 Verilog)中用来描述基本逻辑功能的基本模块,它们通常对应于实际硬件中的逻辑门(如与门、或门、非门等)。这些门提供了最基础的逻辑运算,并且是构建更复杂逻辑电路的基础。在 Verilog 中,原门是直接使用 andornot 等关键字来描述的,不需要额外声明模块。

(1)与门:输出只有在所有输入都为1时才为1。

and (out, in1, in2);

(2)非门:输出为输入的反向。

not (out, in);

(3)或门:输出当至少有一个输入为1时为1。

or (out, in1, in2);

 (4)异或门:输出当输入不相同时为1。

xor (out, in1, in2);

 (5)同或门:输出当输入相同时为1。

xnor (out, in1, in2);

 (6)与非门:输出为与门输出的反向,即输入全为1时输出为0。

nand (out, in1, in2);

  (6)或非门:输出为或门输出的反向,即至少一个输入为1时输出为0。

nor (out, in1, in2);

二、数据类型  

        Verilog 支持几种基本数据类型:regwire。数据位宽如果不做说明的话,默认是1位。数据类型不做说明的话,默认是wire型的。

       1.  reg:用于存储数据的类型,通常用于描述存储元素。在 Verilog 中,reg 类型信号是用来存储数据的,通常用于描述时序逻辑(例如触发器、寄存器)。reg 可以是 单一值 或 多位数组,并且在 Verilog 中支持对数组进行定义和操作。

reg [7:0] my_array [0:3]; // 定义一个大小为 4 的数组,每个元素是 8 位
//my_array 是一个包含 4 个元素的数组,每个元素有 8 位宽度。你可以通过下标(0 到 3)访问数组中的各个元素。


reg [3:0] matrix [0:2][0:2]; // 定义一个 3x3 的二维数组,每个元素是 4 位

        2.  wire:表示连线或信号的类型,常用于描述模块之间的连接。wire 类型是用于连接不同模块之间的信号,表示的是物理连接,它的值通常是由其他信号驱动的,并且不能存储数据。因此,wire 类型不适合用来描述时序逻辑或数组。它的主要用途是将信号从一个地方传递到另一个地方。

        但是wire 数组本身是可以定义的,但其用途通常仅限于表示并行的物理连接,而不是存储数据。但需要注意,不能通过 assignalways 语句来修改 wire 数组的元素,wire 数组只是用来传递信号。

wire [7:0] wire_array [0:3]; // 定义一个 4 元素的 wire 数组,每个元素 8 位宽

●综合示例:

module SimpleExample(input A, output B);
  wire X; // 定义一个 wire 类型的信号
  reg Y;  // 定义一个 reg 类型的信号,寄存器数据类型

  assign X = A; // 将输入 A 赋值给 X
  always @(A)    // 每当 A 改变时,执行以下语句
    Y = X;       // 将 X 的值赋给 Y
  
  assign B = Y;  // 将 Y 的值赋给输出 B
endmodule

三、时序与组合电路

Verilog 中有两种主要的电路模型:组合电路时序电路

        1. 组合电路:其输出仅依赖于当前输入,不考虑历史状态。通常使用 assign 语句(连续赋值语句)来描述,连续赋值语句总是处于激活状态,只要操作数有变化马上进行计算和赋值。

assign C = A & B; // C 是 A 和 B 的与运算

        2. 时序电路:其输出不仅依赖于当前输入,还依赖于过去的状态。通常使用 always 语句和触发器(如 flip-flop)来描述时序逻辑。

always @(posedge clk) // 每当时钟上升沿时
  Q <= D;             // 将 D 的值赋给 Q(非阻塞赋值)

四、always语句块

1. 特点

        (1)always语句本身不是单一的有意义的一条语句,而是和下面的语句一起构成一个语句块,称之为过程块。

        (2)过程块中的赋值语句称过程赋值语句。该语句块不是总处于激活状态,当满足激活条件时才能被执行,否则被挂起。

        (3)赋值目标必须是reg型。

 2. 激活条件

        其由敏感信号条件表决定,当敏感条件满足时过程块被激活。

        敏感条件有两种,一种是边沿敏感,一种是电平敏感。

always @ (posedge clk) begin
  Q <= D; // 时钟上升沿触发
end

 (1)边沿敏感

always @(posedge clk)  // 时钟的上升沿触发
always @(negedge clk)  // 时钟的下降沿触发

(2)电平敏感

        电平敏感意味着列表中的某个信号的电平变化(高或低)都会触发过程块的执行。

always @(a or b)  // 当 a 或 b 电平变化时触发
begin
    // 组合逻辑
end

3. assign 语句的区别

(1)

        使用assign 语句赋值时,赋值目标必须是wire类型。使用always语句赋值时,赋值目标必须是reg类型。

(2)

         always语句块中除了可以使用表达式赋值以外,还可以使用if,case等行为描述语句,还能够描述边沿变化,因此其功能比assign语句更强大(assign语句不能使用if等语句,也不能描述边沿变化) 

always @(posedge clk) begin
    if (reset) begin
        q <= 0;
    end else begin
        q <= d;
    end
end

(3)

        always语句块中只有一条语句时,begin和end可以省略。但是有多个语句时,就不可以省略。assign语句中没有begin和end。

4. 阻塞赋值和非阻塞赋值

        阻塞赋值(Blocking Assignment)和非阻塞赋值(Non-blocking Assignment)是两种不同的赋值方式,它们的行为在模拟过程(尤其是时序模拟)中有显著的不同。理解这两种赋值的区别对于正确设计时序逻辑和避免潜在的仿真错误至关重要。

(1)阻塞赋值

        阻塞赋值使用 = 操作符,它会在当前语句执行完毕后,立即将值赋给变量,并暂停继续执行后面的代码。换句话说,当前语句阻塞了后续语句的执行,直到赋值操作完成。

always @(posedge clk) begin
    a = b;     // 阻塞赋值
    c = a;     // 等待上一个赋值完成后再执行
end

  执行过程:a = b; 会立即执行,并将 b 的值赋给 a。c = a; 会在 a = b; 完成之后才会执行,因此它会取到 a 的新值。

(2)非阻塞赋值

        非阻塞赋值使用 <= 操作符,它在赋值时并不会立即改变变量的值。相反,它会在当前时钟周期的末尾(即在所有语句都执行完后)才将值赋给变量。因此,非阻塞赋值允许在同一个时钟周期内并行更新多个变量,而不会互相阻塞。

always @(posedge clk) begin
    a <= b;     // 非阻塞赋值
    c <= a;     // 同时执行,c 会在下一个时钟周期看到 a 的旧值
end

        执行过程:a <= b; 并不会立即改变 a 的值,而是将赋值操作推迟到时钟周期结束时。 c <= a; 也会推迟执行,且由于 a <= b; 是非阻塞的,c 会在下一个时钟周期看到 a 的旧值(即赋值前的值)。

★应用

        设计组合电路时常用阻塞赋值;设计时序电路时常用非阻塞赋值。但不是绝对的。 不能在一个always块中混合使用阻塞赋值和非阻塞赋值!!可能会导致一些难以察觉的错误和不一致的行为。

五、常见Verilog结构示例

1. 简单的与门(AND Gate)

module AND_gate (
  input A, B,    // 输入信号
  output C      // 输出信号
);
  assign C = A & B; // 组合逻辑,A 和 B 的与运算
endmodule

2. D触发器(D Flip-Flop)

module D_flip_flop (
  input clk,      // 时钟信号
  input D,        // 数据输入
  output reg Q    // 数据输出
);
  always @(posedge clk) begin  // 每当时钟上升沿触发
    Q <= D;  // 非阻塞赋值
  end
endmodule

3. 计数器(Counter)

module Counter (
    input wire [3:0] A,       // 输入信号 A
    input wire [3:0] B,       // 输入信号 B
    input wire RST,           // 复位信号
    input wire CLK,           // 时钟信号
    input wire SEL,           // 多路选择器控制信号
    output reg [3:0] Q        // 输出信号 Q
);
    wire [3:0] sum;           // 加法器输出
    wire [3:0] mux_out;       // 多路选择器输出

    // 加法器模块:计算 A + B
    assign sum = A + B;

    // 多路选择器:根据 SEL 选择 sum 或寄存器的反馈值 Q
    assign mux_out = (SEL == 1'b0) ? sum : Q;

    // D 触发器(寄存器):存储多路选择器的输出
    always @(posedge CLK or posedge RST) begin
        if (RST) begin
            Q <= 4'b0000;    // 复位时输出清零
        end else begin
            Q <= mux_out;    // 时钟上升沿更新 Q 的值
        end
    end

endmodule

六、Verilog常用运算符

        这里大部分运算符和C语言一致,但是部分还是有区别(如缩减运算符、拼接复制运算符),由于那些有区别的运算符我们不常用,这里就不做过多解释,详情可以自己查看其他博客。这里我们主要了解下面数据的表达形式即可。

七、高级特性

1. 任务和函数

        用于封装重复代码,简化设计。

task multiply;
  input [3:0] A, B;  // 输入 A 和 B,4 位宽
  output [7:0] result; // 输出 result,8 位宽
  begin
    result = A * B;  // 执行乘法操作
  end
endtask

  multiply 是一个 task,它有两个输入参数 AB,以及一个输出参数 result。任务内部进行的是 乘法操作,并将结果存储到 result 中。你可以在其他地方调用这个 task 来执行乘法操作。

multiply(A, B, result);  // 调用任务 multiply,将 A 和 B 作为输入,result 用来接收输出

 2. 生成(Generate)

        用于在设计中创建重复结构(例如多个寄存器、加法器等)。是 Verilog 中的一种结构,用来在设计中生成重复的硬件结构或模块。它类似于 for 循环,可以用来实例化多个相同或类似的模块。这对于处理多位数据或多个模块的情况非常有用。

// 定义一个模块 D_flip_flop
module D_flip_flop(
    input clk,         // 时钟信号
    input D,           // 数据输入
    output reg Q       // 数据输出
);
    always @(posedge clk) begin
        Q <= D;  // 在时钟的上升沿,将 D 的值传递给 Q
    end
endmodule

// 顶层模块
module top_module(
    input clk,             // 时钟信号
    input [7:0] data,      // 8 位宽的数据输入
    output [7:0] out       // 8 位宽的数据输出
);
    // 定义循环变量 i
    genvar i;

    generate
        // 循环生成 8 个 D_flip_flop 实例
        for (i = 0; i < 8; i = i + 1) begin: gen_block
            // 每个 D_flip_flop 的输入 data[i],输出 out[i]
            D_flip_flop DFF (
                .clk(clk),           // 时钟信号连接
                .D(data[i]),         // 数据输入连接到 data 的第 i 位
                .Q(out[i])           // 数据输出连接到 out 的第 i 位
            );
        end
    endgenerate

endmodule


 八、Verilog三种描述方法

1. 结构化描述(门级描述)

        结构化描述通常使用基本的门原语(如与门、或门、非门等)来构建电路。这种描述方式接近硬件实现,能反映出每一个逻辑门的连接关系。

module mux4to1(
    output out,        // 输出
    input i0, i1, i2, i3,  // 输入信号
    input s1, s0          // 选择线
);
    wire s1n, s0n;        // 选择线的反向信号
    wire y0, y1, y2, y3;  // 中间的与门输出

    // 反向选择线
    not (s1n, s1);  // s1n = ~s1
    not (s0n, s0);  // s0n = ~s0

    // 根据选择线选择输入信号
    and (y0, i0, s1n, s0n);  // y0 = i0 & ~s1 & ~s0
    and (y1, i1, s1n, s0);   // y1 = i1 & ~s1 & s0
    and (y2, i2, s1, s0n);   // y2 = i2 & s1 & ~s0
    and (y3, i3, s1, s0);    // y3 = i3 & s1 & s0

    // 最终输出为所有中间信号的或运算
    or (out, y0, y1, y2, y3);  // out = y0 | y1 | y2 | y3

endmodule

2. 数据流级描述

        数据流级描述是通过 assign 语句来描述电路的信号流动和计算逻辑,适合用来描述组合逻辑电路。

module mux4to1(out, i0, i1, i2, i3, s1, s0);
    output out;
    input i0, i1, i2, i3;  // 输入信号
    input s1, s0;           // 选择线

    // 使用条件赋值表达式来实现多路选择器
    assign out = (~s1 & ~s0 & i0) | (~s1 & s0 & i1) | (s1 & ~s0 & i2) | (s1 & s0 & i3);

endmodule

3. 行为级描述

        行为级描述通过 always 块来描述电路的行为,通常结合 ifcase 语句,用来定义电路在不同输入条件下的响应。这种方式更接近软件编程,抽象度较高,适合用于描述时序电路。

module mux4to1(out, i0, i1, i2, i3, s1, s0);
    output reg out;          // 输出为reg类型,因为在always块中赋值
    input i0, i1, i2, i3;   // 输入信号
    input s1, s0;            // 选择线

    always @(s1 or s0 or i0 or i1 or i2 or i3) begin
        case ({s1, s0})       // 根据选择线组合选择对应输入
            2'b00: out = i0;  // 当s1=0, s0=0时,选择i0
            2'b01: out = i1;  // 当s1=0, s0=1时,选择i1
            2'b10: out = i2;  // 当s1=1, s0=0时,选择i2
            2'b11: out = i3;  // 当s1=1, s0=1时,选择i3
            default: out = 1'bx; // 如果没有匹配,输出不确定值(x)
        endcase
    end

endmodule

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/941544.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

故障诊断 | 信号降噪算法合集

往期精彩内容&#xff1a; Python-凯斯西储大学&#xff08;CWRU&#xff09;轴承数据解读与分类处理 基于FFT CNN - BiGRU-Attention 时域、频域特征注意力融合的轴承故障识别模型-CSDN博客 基于FFT CNN - Transformer 时域、频域特征融合的轴承故障识别模型-CSDN博客 P…

easegen将教材批量生成可控ppt课件方案设计

之前客户提出过一个需求&#xff0c;就是希望可以将一本教材&#xff0c;快速的转换为教学ppt&#xff0c;虽然通过人工程序脚本的方式&#xff0c;已经实现了该功能&#xff0c;但是因为没有做到通用&#xff0c;每次都需要修改脚本&#xff0c;无法让客户自行完成所有流程&am…

AI,cursor快速上手思维导图

https://cursor101.com/zh/tutorial/learn-cursor-tab

Echarts实现大屏可视化

一、效果展示 二、简介 该项目涉及到的图表有&#xff1a; 渐变堆叠面积图中国地图涟漪特效散点图饼图横向柱状图竖向柱状图圆环饼图 该项目主要展示的是使用Echarts制作的大屏可视化&#xff0c;所用到的技术有&#xff1a; 2.1 前端&#xff1a; vue3、vite、echarts、pi…

ECharts关系图-关系图11,附视频讲解与代码下载

引言&#xff1a; 关系图&#xff08;或称网络图、关系网络图&#xff09;在数据可视化中扮演着至关重要的角色。它们通过节点&#xff08;代表实体&#xff0c;如人、物体、概念等&#xff09;和边&#xff08;代表实体之间的关系或连接&#xff09;的形式&#xff0c;直观地…

javaEE--计算机是如何工作的-1

目录 一.计算机的组成: 各组件的功能: 衡量cpu好坏的标准: 二.指令(instruction) 三.操作系统Operating System 四.进程/任务process/tesk 五.进程在系统中如何管理 1.进程在系统中的管理,从两个角度来分类: 2.进程控制块PCB&#xff08;Process Control Block)) 3.P…

目标检测-R-CNN

R-CNN在2014年被提出&#xff0c;算法流程可以概括如下&#xff1a; 候选区域生成&#xff1a;利用选择性搜索(selective search)方法找出图片中可能存在目标的候选区域(region proposal) CNN网络提取特征&#xff1a;对候选区域进行特征提取(可以使用AlexNet、VGG等网络) 目…

Blender 中投影仪的配置与使用

Blender 中投影仪的配置与使用 Blenderdownloadbasic Projectordownloadinstallconfigure 利用Blender中的投影仪搭建一个简单的结构光仿真系统&#xff0c;通过调整被测对象的材质和投影仪位姿以及投影来获得不同的渲染图像。 Blender download 在官网中下载相应安装包&…

MYSQL慢查询日志(开启慢查询配置、explain执行计划SQL优化、各个字段详解、索引失效)

大家好&#xff0c;我是此林。 今天来分享一下MYSQL慢查询日志记录。 目录 1. 定义 2. 开启慢查询 方法一&#xff1a;命令行 方法二&#xff1a;修改配置文件 3. explain性能分析 4. 索引失效 1. 最左前缀法则 2. 对字段做运算、字段类型不匹配 3. 模糊匹配 4. OR…

Leetcode打卡:考场就坐

执行结果&#xff1a;通过 题目&#xff1a; 855 考场就坐 在考场里&#xff0c;有 n 个座位排成一行&#xff0c;编号为 0 到 n - 1。 当学生进入考场后&#xff0c;他必须坐在离最近的人最远的座位上。如果有多个这样的座位&#xff0c;他会坐在编号最小的座位上。(另外&am…

2024.2 ACM Explainability for Large Language Models: A Survey

Explainability for Large Language Models: A Survey | ACM Transactions on Intelligent Systems and Technology 问题 可解释性问题&#xff1a;大语言模型&#xff08;LLMs&#xff09;内部机制不透明&#xff0c;难以理解其决策过程&#xff0c;如在自然语言处理任务中&…

解决“SVN无法上传或下载*.so、*.a等二进制文件“问题

今天&#xff0c;在使用Subversion提交代码到服务器时&#xff0c;发现无法提交*.a、*.so等二进制文件&#xff0c;右击这些文件&#xff0c;发现其属性为ignores。     问题原因&#xff1a;SVN的配置文件里&#xff0c;屏蔽了*.a、*.so文件的上传与下载&#xff0c;并把这些…

层序遍历练习

层次遍历 II 给定一个二叉树&#xff0c;返回其节点值自底向上的层次遍历。 &#xff08;即按从叶子节点所在层到根节点所在的层&#xff0c;逐层从左向右遍历&#xff09; 思路 相对于102.二叉树的层序遍历&#xff0c;就是最后把result数组反转一下就可以了。 C代码&…

京东大数据治理探索与实践 | 京东零售技术实践

01背景和方案 在当今的数据驱动时代&#xff0c;数据作为关键生产要素之一&#xff0c;其在商业活动中的战略价值愈加凸显&#xff0c;京东也不例外。 作为国内领先的电商平台&#xff0c;京东在数据基础设施上的投入极为巨大&#xff0c;涵盖数万台服务器、数 EB 级存储、数百…

【论文阅读笔记】Learning to sample

Learning to sample 前沿引言方法问题声明S-NET匹配ProgressiveNet: sampling as ordering 实验分类检索重建 结论附录 前沿 这是一篇比较经典的基于深度学习的点云下采样方法 核心创新点&#xff1a; 首次提出了一种学习驱动的、任务特定的点云采样方法引入了两种采样网络&…

[AIGC知识] layout理解

前言 要开组会了&#xff0c;随便讲个凑数吧。 参考论文 https://arxiv.org/html/2303.17189? 什么是layout数据&#xff1f; 像下图这样&#xff0c;Layout是每个图片的布局&#xff0c;其中包含一些物体的相应边界框和类别 layout信息如何整合表示并作为条件加入到网络…

【macos java反编译工具Java Decompiler】

mac上能用的反编译工具 https://java-decompiler.github.io/

C#+OpenCv深度学习开发(常用模型汇总)

在使用 OpenCvSharp 结合深度学习进行机器视觉开发时&#xff0c;有许多现成的模型可以使用。以下是一些常用的深度学习模型&#xff0c;适用于不同的机器视觉任务&#xff0c;包括物体检测、图像分类和分割等。 使用示例 在 OpenCvSharp 中加载和使用这些模型的基本示例&…

【生成模型之七】Classifier-free diffusion guidance

论文&#xff1a;classifier-free diffusion guidance 一、Background 分类器引导是一种最近引入的方法&#xff0c;用于在训练后的条件扩散模型中权衡样本丰富度和样本保真度&#xff0c;其思想与其他类型生成模型中的低温采样或截断相同。 分类器引导将扩散模型的分数估计…

【LeetCode每日一题】——415.字符串相加

文章目录 一【题目类别】二【题目难度】三【题目编号】四【题目描述】五【题目示例】六【题目提示】七【解题思路】八【时空频度】九【代码实现】十【提交结果】 一【题目类别】 字符串 二【题目难度】 简单 三【题目编号】 415.字符串相加 四【题目描述】 给定两个字符…