跳到主要内容

数据类型

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 的区别

特性wirereg
赋值方式连续赋值(assign)过程赋值(always/initial)
物理意义连线寄存器或连线
默认值zx
综合结果组合逻辑组合或时序逻辑

存储器类型

使用 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 的区别

特性parameterlocalparam
可覆盖性可以被覆盖不能被覆盖
用途模块参数化内部常量定义
作用域模块级模块级

数组

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 代码的基础。下一章将介绍运算符。