跳转到内容
新建笔记

02. 四态逻辑、位宽、进制与有符号数

Verilog 的一个数不只有“数值”,还至少有 位宽、进制、每一位的逻辑状态、是否有符号。忽略任何一项,都可能得到表面能编译、硬件却错误的代码。

四态逻辑与常量结构

值含义常见场景
0确定的逻辑低电平GND、条件为假
1确定的逻辑高电平VCC、条件为真
x未知,当前无法判断是 0 还是 1未复位寄存器、驱动冲突、未知传播
z高阻,当前驱动器近似断开三态总线、未驱动线网

x 不是硬件中的“第三种稳定电平”。它主要是仿真器告诉你:信息不足或存在冲突。看到 x 时,不要急着用条件把它隐藏,而应追查未初始化、复位和多驱动。

z 表示该驱动端不驱动总线:

assign data_bus = output_enable ? data_out : 8'bz;

现代 FPGA 内部通常不会保留任意三态网络;三态多用于芯片 I/O。综合工具可能把内部三态转换为多路选择逻辑。

格式是:

<位宽>'<进制><数值>

常见进制:

  • b:二进制,例如 8'b1010_0101;
  • o:八进制,例如 6'o52;
  • d:十进制,例如 8'd165;
  • h:十六进制,例如 8'hA5。

下划线只为阅读分组,不改变数值:

16'b1010_0101_1100_0011
32'h1234_ABCD
25_000_000 // 未指定位宽的十进制常量
wire [3:0] a = 4'b1010; // 4 位,a[3] 是最高位
wire [7:0] b = 8'hA5; // 8 位
wire c = 1'b1; // 1 位

[7:0] 一共有 7 - 0 + 1 = 8 位。常见选取方式:

wire [7:0] data;
wire msb = data[7];
wire [3:0] high = data[7:4];
wire [3:0] low = data[3:0];

目标更窄:高位被截断

跳转到“目标更窄:高位被截断”
wire [3:0] low = 8'b1011_0110;
// low 得到 4'b0110

无符号值通常补 0;有符号值在满足表达式规则时会进行符号扩展。不要依赖自己没推导过的隐式规则,关键位置明确转换或拼接:

wire [3:0] small = 4'b1010;
wire [7:0] zero_extended = {4'b0000, small};

两个 8 位无符号数的最大值都是 255,和最大为 510,需要 9 位表示:

wire [7:0] a;
wire [7:0] b;
wire [8:0] sum;
assign sum = {1'b0, a} + {1'b0, b};

显式在输入前补一位,比假设表达式会自动保留进位更安全、更容易审查。

教材为了入门把 100 解释为常见实现中的 32 位十进制数。工程中还要注意:无位宽十进制常量通常参与有符号运算,其精确宽度规则会影响表达式扩展。推荐:

  • 寄存器值、掩码、比较终值尽量写明确位宽;
  • 大数字可用下划线分组;
  • 不要把负数直接塞进没有想清楚符号属性的向量。
localparam [7:0] LIMIT = 8'd99;
assign done = (counter == LIMIT);
wire signed [7:0] temperature;
wire signed [7:0] offset;
wire signed [8:0] adjusted;
assign adjusted = temperature + offset;

8 位二进制补码 8'b1111_1111:

  • 按无符号解释是 255;
  • 按有符号解释是 -1。

位模式相同,解释不同。混合 signed 与 unsigned 时,结果可能转为你没预期的无符号比较。建议让同一表达式中的操作数位宽和符号属性保持一致,并为结果保留足够位数。

a == b // 逻辑相等;遇到 X/Z,结果可能为 X
a === b // 全等;X/Z 也逐位参与比较

RTL 设计的正常数据判断通常使用 ==。=== 更常用于 testbench 检查,例如确认某信号确实为 x。不要用 === 掩盖设计中的未知状态。

普通标识符可由字母、数字、下划线和 $ 组成,但首字符必须是字母或下划线,并区分大小写:count 与 Count 是两个名字。

推荐约定:

  • 普通信号小写加下划线:cpu_addr;
  • 参数大写:DATA_WIDTH;
  • 低有效信号带 _n:rst_n;
  • 时钟名包含 clk:sys_clk;
  • 实例名以 u_ 开头:u_uart_rx;
  • 名字表达角色,不用 a1、temp2 等模糊名称。
wire [7:0] data = 4'hF; // 合法但会补宽;最好明确意图
wire [3:0] data2 = 8'hAB; // 高 4 位被截断
wire [7:0] sum = a + b; // 可能丢失进位
wire result = signed_a < b; // signed/unsigned 混合比较要警惕
  1. 把十进制 45 写成 8 位二进制和 8 位十六进制常量。
  2. 4'b1111 + 4'b0001 至少需要多少位才能无损保存?
  3. 8'hF2[7:4] 的概念值是什么?实际代码中应先把常量赋给向量再做位选。
  4. 解释 x 与 z 的区别,并各写出一个可能出现它们的场景。

参考答案:8'b0010_1101、8'h2D;加法结果需要 5 位;高半字节是 4'hF;x 表示未知,z 表示不驱动。

上一篇:硬件思维 · 返回目录 · 下一篇:信号、端口与模块