FPGA中一些基本概念原理的区分

一、wire型变量与reg变量

在 Verilog 中,wire 和 reg 是两种不同类型的变量,它们有着不同的特性和用途

1.1 wire 变量

  1. wire 变量用于连接模块中的输入、输出以及内部信号线。

  2. 它主要用于表示连续赋值的逻辑连接,类似于硬件电路中的导线。

  3. wire 变量不能在 always 块或 initial 块中赋值,它们只能通过连续赋值“assign”语句连接到其他信号,

1.2 reg 变量

  1. 它主要用于表示时序逻辑中的寄存器或存储单元。
  2. reg 变量可以在 always 块或 initial 块中赋值,用于描述时序逻辑的行为。

因此,wire 变量和 reg 变量的本质区别在于它们的用途和赋值方式。wire 主要用于连接信号,而 reg 主要用于存储时序逻辑的状态值。

1.3 使用场景

module ExampleModule(input a, input b, output c);
  
  // 使用 wire 连接输入和输出
  wire w1;
  assign w1 = a & b;  // 连接输入信号 a 和 b

  assign c = w1;  // 连接输出信号 c

  // 使用 reg 存储状态值
  reg [3:0] counter;  // 定义一个 4 位寄存器
  
  always @(posedge clk) begin
    if (reset) begin
      counter <= 4'b0000;  // 在上升沿时重置寄存器的值
    else
      counter <= counter + 1;  // 在上升沿时递增寄存器的值
    end
  end

endmodule

在这个示例中,wire 变量 w1 用于连接输入信号 a 和 b 到输出信号 c,而 reg 变量 counter 被用作一个 4 位的寄存器,用于存储时序逻辑中的状态值。wire 用于连接逻辑,而 reg 用于存储状态。

二、阻塞赋值与非阻塞赋值

2.1 阻塞赋值

·阻塞赋值使用“=”符号进行赋值。
·在 always 块中使用阻塞赋值时,会按照代码的顺序依次执行赋值语句。
·每次遇到阻塞赋值语句时,会立即计算并更新被赋值的变量。
·阻塞赋值会导致并发赋值,可能会引起意外的结果,特别是在多个赋值操作的情况下。

2.2 非阻塞赋值

·非阻塞赋值使用“<=”符号进行赋值。
·在 always 块中使用非阻塞赋值时,所有赋值语句会同时执行,但在时钟信号的边沿才会生效更新被赋值的变量。
·非阻塞赋值可以用于描述时序逻辑中的寄存器更新操作,确保时序逻辑的正确性。
·非阻塞赋值消除了并发赋值问题,避免了多个赋值操作之间的相互影响,提高了代码的可读性和可维护性。

2.3 使用场景

(1)阻塞赋值的使用情况:
·适用于组合逻辑电路或者需要立即更新变量值的情况。
·在同一个 always 块内多个赋值语句的情况下,可能会导致意外结果。
 

module blocking_example (
    input wire a,
    input wire b,
    output reg c
);

always @ (a, b)
begin
    // 阻塞赋值,立即更新变量值
    c = a & b;
end

endmodule


(2)非阻塞赋值的使用情况:
·适用于时序逻辑电路中需要保持状态稳定性的情况。
·用于在时钟信号的边沿更新寄存器值,避免并发赋值问题。


module non_blocking_example (
    input wire clk,
    input wire rst,
    input wire data,
    output reg reg_data
);

always @(posedge clk or posedge rst)
begin
    if (rst)
    begin
        // 重置寄存器值
        reg_data <= 0;
    end
    else
    begin
        // 非阻塞赋值,在时钟信号的边沿更新寄存器值
        reg_data <= data;
    end
end

endmodule


通过以上示例,可以看到阻塞赋值适用于需要立即更新变量值的情况,而非阻塞赋值适用于时序逻辑中需要保持状态稳定性的情况。在实际设计中,根据逻辑需求选择合适的赋值方式可以确保设计的正确性和性能。

三、常见条件语句

在Verilog中,常见的条件语句包括if语句、case语句和unique case语句。以下是它们的区别和用法:

3.1 if 语句

if语句用于在条件满足时执行特定的操作。
可以包含多个else if和else部分。
在每个时钟周期只能选择一个分支执行。


module if_statement_example (
    input wire a,
    output reg b
);

always @ (a)
begin
    if (a == 1)
        b = 1;
    else if (a == 0)
        b = 0;
    else
        b = 0; // 默认情况
end

endmodule


3.2 case 语句


case语句根据输入信号的不同值执行相应的操作。
可以使用case、casex或casez,分别表示精确匹配、模糊匹配X值、模糊匹配Z值。
每个case分支可以有多个值或范围。

module case_statement_example (
    input wire [1:0] opcode,
    output reg result
);

always @ (*)
begin
    case (opcode)
        2'b00: result = 4'b0000;
        2'b01: result = 4'b0011;
        2'b10: result = 4'b1111;
        default: result = 4'bXXXX; // 默认情况
    endcase
end

endmodule

 

3.3 unique case 语句


unique case语句用于确保每个分支值都唯一,不会有重复的情况。
如果出现多个分支值相同的情况,编译器会报错。


module unique_case_statement_example (
    input wire [1:0] sel,
    output reg out
);

always @ (*)
begin
    unique case (sel)
        2'b00, 2'b01: out = 1;
        2'b10: out = 0;
        default: out = 0; // 默认情况
    endcase
end

endmodule

四、常见操作运算符

4.1 逻辑运算符

与(&):两个输入都为高时输出高,否则输出低。
或(|):两个输入至少有一个高时输出高。
非(~):对输入取反,即高变低,低变高。
异或(^):两个输入不同时为高或者不同时为低时输出高,否则输出低。

FPGA中一些基本概念原理的区分_第1张图片

4.2 算术运算符

加法(+):对两个数进行加法运算。
减法(-):对两个数进行减法运算。
乘法(*):对两个数进行乘法运算。
除法(/):对两个数进行除法运算,通常需要使用特殊的算法实现。FPGA中一些基本概念原理的区分_第2张图片

4.3 比较运算符

等于(==):判断两个操作数是否相等。
不等于(!=):判断两个操作数是否不相等。
大于(>):判断左操作数是否大于右操作数。
小于(<):判断左操作数是否小于右操作数。
大于等于(>=):判断左操作数是否大于等于右操作数。
小于等于(<=):判断左操作数是否小于等于右操作数。

FPGA中一些基本概念原理的区分_第3张图片

与‘==’不同,全等将x和z都当成确定的值进行比较,当表述完全相同时输出1;此外,在做全等比较时,对于两个比较位数不等的情况,不会像处理操作符‘==’那样作高位补0操作,而会直接判断两数据不等。

4.4 移位运算符

左移(<<):将操作数向左移动指定的位数,右侧空出的位用0填充。
右移(>>):将操作数向右移动指定的位数,左侧空出的位根据有符号或无符号右移来填充。

4.5 位运算符

与(&):按位与操作。
或(|):按位或操作。
非(~):按位取反操作。
异或(^):按位异或操作。

结尾语

后来啊,
新年到了,我就来了…
鞭炮响了,我就走了…
好像…我才是那年兽
2024-2-16
FPGA中一些基本概念原理的区分_第4张图片

你可能感兴趣的:(fpga开发)