跳转到内容

可编程逻辑/Verilog 数据类型

来自维基教科书,开放的书籍,开放的世界

数据值

[编辑 | 编辑源代码]

Verilog 有四种值,任何信号都可以取这些值

意义
0 二进制值为 0。对应于零伏。
1 二进制值为 1。根据底层制造工艺,可能对应于 +5V、+3.3V 或其他一些正值。
x “无关紧要”的值。x值既不是 0 也不是 1,应将其视为未知值。
z 当控制信号未被断言时,来自三态缓冲器的阻抗值很高。对应于未连接或“浮动”的导线。

在实践中,xz值难以在综合中使用,通常应避免使用,除非有非常具体的理由使用它们。

线,用 wire 关键字指定,表示从一个模块到另一个模块的物理线,承载电信号。线不存储任何数据,必须不断提供值,否则它们将不包含值。线不能是阻塞或顺序赋值的目标。

线有三种类型

类型 功能
线 这些线将简单数据从一个端口传输到另一个端口。
wor 这些线是对应用于该线的​​所有输入数据值的逻辑或运算。这些综合为具有多个输入端口的或门。
wand 这些线是对应用于该线的​​所有输入数据值的逻辑与运算。这些综合为具有多个输入端口的与门。


线可以使用以下方法分配值assign关键字。所有assign声明被认为是并发且持续运行的。

在以下情况下,a 的值取决于 bc 的值。bc 的任何变化都会导致 a 的值自动且立即发生变化。

wire a, b, c;
assign a = b & c;

使用assign关键字不能进行循环赋值,因为这会产生一个连续循环。在以下示例中,a 的值未定义,因为它依赖于自身通过组合逻辑(即异步、连续运行)传递。

wire a, b;
assign a = a | b;

对于 wandwor 数据类型,对该线的​​所有赋值都被认为是逻辑门的端口。例如,以下代码

wire a, b, c;
wor x;
assign x = a;
assign x = b;
assign x = c;

等效于此代码

wire a, b, c, x
assign x = (a | b | c);

虽然使用worwand可能看起来工作量更大,但它们可以极大地简化一些复杂的逻辑操作,并且可以帮助提高代码的可读性。

寄存器

[编辑 | 编辑源代码]

检查语法

一个寄存器,用 reg 关键字表示,是一个内存存储位置。寄存器存储值而无需持续赋值,但它们必须使用阻塞或顺序赋值手动更新。寄存器值都被视为无符号值,任何将值扩展到更大寄存器的操作都不会导致逻辑符号扩展。

寄存器可与“=”和“<="

b <= y + z;
阻塞赋值的使用会在综合设计中生成额外的存储和时序电路。如果不需要,则不应使用这些赋值,因为它们需要额外的资源。

使用“=”运算符的赋值是阻塞赋值,它们将按顺序执行。使用“<=”运算符的赋值是非阻塞的。特定代码块中的所有非阻塞赋值将同时开始。该块将不会终止,直到所有非阻塞赋值完成。

向量是变量的集合,用相同名称但不同的下标表示,例如:[2:0]i;

         assign y=i[2]^i[1];
         assign y=i[1]^i[0];
         endmodule

整数,用 integer 关键字指定,在功能上类似于寄存器,只是它们被隐式视为有符号数。整数将在赋值时进行逻辑符号扩展。

实数可以用以下两种形式之一指定。

  1. 十进制表示法:此形式的数字示例包括:2.0、5.678、1154.76、0.1
  2. 科学计数法:此形式的数字示例包括
      23_5.1e2   23510.0 (underscores are ignored)
      3.6e2      360.0 (e and E are the same)
      5E-4       0.0005

参数类似于 C 中的预定义标识符。它用于声明全局常量

  example: parameter u=8;
           local parameter is used to declare single digit
6 位总线。

寄存器和线类型可以指定为多位总线。此赋值是在使用 [] 运算符的变量声明中进行的。例如

wire [5:0] a;

这将线 a 声明为 6 根线的总线,其中位 5 (a[5]) 是 MSB,位 0 (a[0]) 是 LSB。LSB 的位数必须低于 MSB 的位数,但不必为零。

位选择

[编辑 | 编辑源代码]

总线中的各个线或寄存器可以直接与之交互,并且可以操纵总线的子集。给定以下声明

wire [15:0] a;

以下代码将为总线的位 14 设置一个值

assign a[14] = 1'b1;

以下代码将为总线的低 8 位分配一个值

assign a[7:0] = 8'b01101101;

同样,我们也可以从总线的某一部分读取。以下代码将 8 位总线 b 分配为 16 位总线 a 的高 8 位

wire [15:0] a;
wire [7:0] b;
assign b[7:0] = a[15:8];

部分选择运算符让编译器根据起点和数据宽度大小计算范围;

wire [15:0] a;
wire [7:0] b;
assign b[7:0] = a[15:8];
assign b[7:0] = a[8+:8];  // equivalent
assign b[7:0] = a[15-:8]; // equivalent
华夏公益教科书