在FPGA设计的世界里,Verilog表达式是构建复杂硬件逻辑的基石。
本文将深入探索Verilog表达式的各个方面,提供详尽的示例代码,帮助读者从基础到高级,全面掌握Verilog表达式的使用。
一、Verilog表达式基础
Verilog表达式由操作符和操作数构成,用于执行算术、逻辑、位操作等多种计算。
表达式可以在模块的任何部分出现,如连续赋值、过程赋值、条件语句等。
示例:
a|b ;
a + 1'b1 ;
二、操作数类型
操作数可以是常量、变量、位选择、位切片、函数调用等。
操作数的使用必须符合语法结构的要求,以确保表达式的正确性。
示例代码:
module test_expression;
// 变量定义
reg [3:0] reg1, reg2;
wire [7:0] result;
// 函数定义
function [3:0] add_two;
input [3:0] a;
add_two = a + 2;
endfunction
always @(posedge clk) begin
// 过程赋值中使用表达式
result = reg1 + reg2;
reg1 = add_two(reg2);
end
endmodule
三、操作符详解
Verilog提供了多种操作符,包括算术操作符、关系操作符、逻辑操作符、位操作符等。每种操作符都有其特定的用途和优先级。
1、算术操作符
算术操作符用于执行数值计算,包括加(+)、减(-)、乘(*)、除(/)、模(%)和幂(**)。
这里需要注意的是除(/)、模(%)和幂(**)不能直接应用于可综合的语句中。
示例:
// 算术表达式
result = reg1 * reg2 + 5;
+ 和 - 也可以用来表示操作数的正负性。
示例:
wire [3:0] a = -4'd6 ;
parameter OFFSET = - 125。
2、关系操作符
关系操作符用于比较两个值的关系,如大于(>)、小于(<)、等于(==)、不等于(!=),全等(===),非全等(!==)等。
其中全等和非全等操作符可以比较 x
或 z
值,而逻辑相等和不等操作符则不能。
示例:
// 关系表达式
wire is_less = reg1 < 10;
3、逻辑操作符
逻辑操作符用于执行布尔逻辑运算,包括逻辑与(&&)、逻辑或(||)、逻辑非(!)等。
示例:
// 逻辑表达式
wire is_active = !flag && is_less;
4、位操作符
位操作符用于对位进行操作,包括按位与(&)、按位或(|)、按位异或(^)等。
示例代码:
reg [7:0] reg1;
wire [7:0] bit_and;
assign bit_and = reg1 & 8'b1111_0000;
5、移位操作符
移位操作符包括左移(<<)、右移(>>)、算术左移(<<<)、算术右移(>>>),用于实现数据的位移。
算术左移和逻辑左移时,右边最低位会补 0。
逻辑右移时,左边最高位会补 0;
算术右移时,左边最高位会补充符号位,需要将信号声明成有符号数,注意使用这个操作符容易出错。
示例:
reg [7:0] a;
wire [3:0] b;
assign b = a>>3;
6、归约操作符
归约操作符是一个特殊的操作符,只有一个操作数,将整个操作数的逐位进行操作,生成1bit的结果。
这个操作符包括:归约与(&),归约与非(~&),归约或(|),归约或非(~|),归约异或(^),归约同或(~^)。
示例:
vector_a = 8'b11100100; // 给向量赋值
// 检查向量中是否所有位都是1
all_ones = &vector_a; // 预期结果为0,因为不是所有位都是1
// 检查向量中是否至少有一位是1
any_ones = |vector_a; // 预期结果为1,因为至少有一位是1
7、拼接操作符
拼接操作符使用大括号 “{}” 来表示,用于将多个操作数拼接成一个新的操作数,信号间使用逗号“,”隔开。
注意拼接符中所有操作数必须指定位宽,否则会报错。
示例:
// 拼接操作符
wire [15:0] concatenated = {8'd255, 8'd128};
8、复制操作符
复制操作符可以将一个操作数重复多次以形成一个更宽的向量。这种操作符在初始化宽向量或生成重复模式时非常有用。
复制操作符的一般语法是 {n{expression}} ,其中 n 表示复制的次数,而 expression 是要复制的位模式或值。
复制操作符可以用于常量或变量,并且可以嵌套使用。
示例:
// 复制操作符
wire [7:0] repeated_pattern = {4{2'b10}};
9、条件表达式
条件表达式是Verilog中的一种三元操作符,格式为 condition ? true_exp : false_exp 。
示例代码:
// 条件表达式
wire [7:0] mux_output = is_active ? reg1 : reg2;
10、表达式的优先级
不同操作符之间的优先级不同,如下表所示:
当然也可以用括号来明确优先级。
示例代码:
// 使用括号明确优先级
result = (reg1 + reg2) * (reg3 - reg4);
四、 综合实例:一个简单的ALU
这里是一个简单的算术逻辑单元(ALU),展示了如何使用Verilog表达式实现算术和逻辑运算。
module alu(
input [7:0] a, b,
input [1:0] operation, // 00 - ADD, 01 - SUB, 10 - AND, 11 - OR
output reg [7:0] result
);
always @(*) begin
case(operation)
2'b00: result = a + b;
2'b01: result = a - b;
2'b10: result = a & b;
2'b11: result = a | b;
default: result = 8'b0; // 无效操作
endcase
end
endmodule