数据类型
Verilog 提供了丰富的数据类型来描述硬件电路。本章详细介绍各种数据类型及其用法。
值系统
Verilog 使用四值逻辑系统来表示硬件信号:
| 值 | 含义 | 说明 |
|---|---|---|
| 0 | 逻辑 0 | 低电平、假、接地 |
| 1 | 逻辑 1 | 高电平、真、电源 |
| x | 不定态 | 未初始化或冲突 |
| z | 高阻态 | 悬空、未连接 |
值的含义
0 和 1
表示确定的逻辑电平:
wire a = 1'b0; // 逻辑 0
wire b = 1'b1; // 逻辑 1
x(不定态)
表示未知的值,常见于:
- 未初始化的寄存器
- 多驱动冲突
- 仿真初态
reg [7:0] data; // 未初始化,值为 xxxxxxxx
wire conflict = driver1 & driver2; // 如果驱动冲突,结果为 x
z(高阻态)
表示断开或悬空状态,常用于:
- 三态总线
- 双向端口
- 未连接的输入
wire [7:0] bus = enable ? data : 8'bz; // 三态缓冲
线网类型(Net Type)
线网类型表示硬件中的物理连线,其值由驱动源决定。
wire 类型
wire 是最常用的线网类型,用于表示单驱动源的连线:
wire a; // 1 位 wire
wire [7:0] data_bus; // 8 位 wire
wire [31:0] address; // 32 位 wire
wire 的赋值必须使用连续赋值语句(assign):
wire [7:0] sum;
wire [7:0] a, b;
assign sum = a + b;
其他线网类型
Verilog 还定义了其他线网类型,用于多驱动源情况:
| 类型 | 功能 | 多驱动解析 |
|---|---|---|
| wire | 普通连线 | 取决于驱动强度 |
| tri | 三态线 | 同 wire |
| wor | 线或 | 任一为 1 则为 1 |
| wand | 线与 | 任一为 0 则为 0 |
| trior | 三态线或 | 同 wor |
| triand | 三态线与 | 同 wand |
| tri0 | 下拉电阻 | 无驱动时为 0 |
| tri1 | 上拉电阻 | 无驱动时为 1 |
| supply0 | 接地 | 始终为 0 |
| supply1 | 电源 | 始终为 1 |
wor [7:0] bus; // 线或总线
wand [7:0] bus; // 线与总线
tri [7:0] data_bus; // 三态总线
tri0 reset; // 下拉复位信号
tri1 enable; // 上拉使能信号
多驱动解析示例
module multi_driver(
output wor bus_out,
input driver1,
input driver2
);
assign bus_out = driver1;
assign bus_out = driver2;
// 结果:bus_out = driver1 | driver2
endmodule
寄存器类型(Register Type)
寄存器类型表示能够存储数据的变量,在过程块中赋值。
reg 类型
reg 是基本的寄存器类型:
reg flag; // 1 位 reg
reg [7:0] counter; // 8 位 reg
reg [31:0] register; // 32 位 reg
reg 在过程块中赋值:
reg [7:0] counter;
always @(posedge clk) begin
counter <= counter + 1;
end
reg 与 wire 的区别
| 特性 | wire | reg |
|---|---|---|
| 赋值方式 | 连续赋值(assign) | 过程赋值(always/initial) |
| 物理意义 | 连线 | 寄存器或连线 |
| 默认值 | z | x |
| 综合结果 | 组合逻辑 | 组合或时序逻辑 |
存储器类型
使用 reg 数组定义存储器:
// 定义一个 256x8 的存储器
reg [7:0] memory [0:255];
// 访问存储器
wire [7:0] data_out;
wire [7:0] address;
assign data_out = memory[address];
存储器与寄存器数组的区别:
reg [7:0] mem [0:255]; // 存储器:256 个 8 位单元
reg [7:0] reg_array [7:0]; // 寄存器数组:8 个 8 位寄存器
有符号类型
Verilog-2001 引入了有符号类型支持。
signed 修饰符
reg signed [7:0] signed_reg; // 有符号 8 位寄存器
wire signed [15:0] signed_wire; // 有符号 16 位连线
有符号类型支持补码运算:
reg signed [7:0] a = -10; // 8 位有符号数
reg signed [7:0] b = 20;
wire signed [7:0] sum = a + b; // 结果为 10
有符号与无符号运算
reg signed [7:0] a = -1; // 值为 0xFF (-1)
reg unsigned [7:0] b = 255; // 值为 0xFF (255)
// 比较运算
wire eq = (a == b); // 结果为 1(位模式相同)
参数
参数用于定义常量,提高代码可读性和可维护性。
parameter
parameter 定义模块级常量:
module counter #(
parameter WIDTH = 8, // 默认位宽
parameter MAX_COUNT = 255 // 默认最大值
)(
input clk,
input reset,
output [WIDTH-1:0] count
);
reg [WIDTH-1:0] counter_reg;
always @(posedge clk) begin
if (reset)
counter_reg <= 0;
else if (counter_reg == MAX_COUNT)
counter_reg <= 0;
else
counter_reg <= counter_reg + 1;
end
assign count = counter_reg;
endmodule
参数覆盖
实例化时可以覆盖参数:
// 使用位置参数覆盖
counter #(
16, // WIDTH = 16
65535 // MAX_COUNT = 65535
) u_counter_16bit (
.clk(clk),
.reset(reset),
.count(count)
);
// 使用命名参数覆盖(推荐)
counter #(
.WIDTH(16),
.MAX_COUNT(65535)
) u_counter_16bit (
.clk(clk),
.reset(reset),
.count(count)
);
localparam
localparam 定义局部常量,不能被覆盖:
module state_machine(
input clk,
input reset,
input [1:0] state
);
// 状态定义,不允许外部覆盖
localparam IDLE = 2'b00;
localparam READ = 2'b01;
localparam WRITE = 2'b10;
localparam DONE = 2'b11;
// ...
endmodule
参数与 localparam 的区别
| 特性 | parameter | localparam |
|---|---|---|
| 可覆盖性 | 可以被覆盖 | 不能被覆盖 |
| 用途 | 模块参数化 | 内部常量定义 |
| 作用域 | 模块级 | 模块级 |
数组
Verilog 支持多维数组。
一维数组
reg [7:0] array_1d [0:15]; // 16 个 8 位元素
wire [31:0] data_array [7:0]; // 8 个 32 位元素
多维数组
Verilog-2001 支持多维数组:
reg [7:0] array_2d [0:15][0:7]; // 16x8 的二维数组
reg [31:0] array_3d [0:7][0:7][0:7]; // 8x8x8 的三维数组
数组访问
reg [7:0] mem [0:255];
// 读取
wire [7:0] data = mem[address];
// 写入(在过程块中)
always @(posedge clk) begin
mem[write_addr] <= write_data;
end
向量
向量是多位的信号。
向量声明
wire [7:0] byte_data; // 8 位向量,位 7 是最高位
wire [0:7] byte_data_rev; // 8 位向量,位 0 是最高位
reg [31:0] word_data; // 32 位向量
向量位选择
wire [31:0] data;
wire [7:0] byte0 = data[7:0]; // 选择低 8 位
wire [7:0] byte1 = data[15:8]; // 选择第 2 个字节
wire bit0 = data[0]; // 选择最低位
wire bit31 = data[31]; // 选择最高位
向量拼接
wire [7:0] a = 8'h12;
wire [7:0] b = 8'h34;
wire [15:0] c = {a, b}; // c = 16'h1234
wire [15:0] d = {8'h00, a[7:4]}; // d = 16'h00_1
// 重复操作
wire [31:0] all_ones = {32{1'b1}}; // 32 位全 1
wire [15:0] pattern = {4{4'b1010}}; // 16 位模式:1010_1010_1010_1010
整数和实数类型
integer 类型
integer 是 32 位有符号整数:
integer i;
integer count;
initial begin
for (i = 0; i < 10; i = i + 1) begin
$display("i = %d", i);
end
end
integer 主要用于仿真,通常不用于综合。
real 类型
real 是双精度浮点数:
real pi;
real temperature;
initial begin
pi = 3.14159265359;
temperature = 25.5;
$display("Pi = %f", pi);
end
real 类型只能用于仿真,不能综合。
time 类型
time 是 64 位无符号时间值:
time start_time;
time end_time;
initial begin
start_time = $time;
#100;
end_time = $time;
$display("Duration: %t", end_time - start_time);
end
类型转换
Verilog 提供了多种类型转换方式。
隐式转换
Verilog 会自动进行类型转换:
wire [7:0] a = 8'b1010_1010;
wire [3:0] b = a; // 截断高位,b = 4'b1010
wire [15:0] c = a; // 零扩展,c = 16'h00AA
显式转换
使用系统函数进行类型转换:
// 有符号与无符号转换
wire signed [7:0] signed_val = $signed(8'b1111_1111); // -1
wire [7:0] unsigned_val = $unsigned(signed_val); // 255
// 位宽转换
wire [15:0] extended = {{8{a[7]}}, a}; // 符号扩展
wire [15:0] zero_ext = {8'b0, a}; // 零扩展
位宽匹配
wire [3:0] a = 4'b1010;
wire [7:0] b;
// 符号扩展
assign b = {{4{a[3]}}, a}; // b = 8'b1111_1010
// 零扩展
assign b = {4'b0, a}; // b = 8'b0000_1010
常量
整数常量
8'b1010_1010 // 8 位二进制
16'hABCD // 16 位十六进制
32'd12345 // 32 位十进制
'o777 // 无符号八进制(32 位)
字符串常量
reg [8*8-1:0] message = "Hello!!!";
reg [8*5-1:0] name = "World";
实数常量
real pi = 3.14159;
real freq = 50.0e6; // 50 MHz
小结
本章介绍了 Verilog 的数据类型:
- 四值逻辑系统:0、1、x、z
- 线网类型:wire、tri、wor、wand 等
- 寄存器类型:reg、存储器
- 有符号类型:signed 修饰符
- 参数:parameter、localparam
- 数组和向量:多维数组、位选择、拼接
- 特殊类型:integer、real、time
- 类型转换:隐式转换和显式转换
理解数据类型是编写正确 Verilog 代码的基础。下一章将介绍运算符。