当我们定义了一个向量,在使用这个向量时,可能是整个向量全部都使用,也有可能只是使用向量的其中一部分。verilog 语言语法支持可变的向量域选择,方便用户的使用。
1.语法:(向量使用方法)
- 向量名 [ 起始位 +: 位宽 ]
在不改变原本向量声明的高低有效位顺序的情况下,从起始位开始(包括起始位), 宽度为位宽,从起始位递增到位宽的一段向量区域。
例:
wire [31 : 0] a; a [0 +: 8] 等效为 a[7 : 0]; // 起始位 在最右侧
wire [0 : 31] b; b [0 +: 8] 等效为 b[0 : 7]; // 起始位 在最左侧
- 向量名 [ 起始位 -: 位宽 ]
在不改变原本向量声明的高低有效位顺序的情况下,从起始位开始(包括起始位), 宽度为位宽,从起始位递减到位宽的一段向量区域。
wire [31 : 0] a; a [7 -: 8] 等效为 a[7 : 0]; // 起始位 在最左侧
wire [0 : 31] b; b [7 -: 8] 等效为 b[0 : 7]; // 起始位 在最右侧
- 起始位可以是变量,但位宽必须是常量
例:
for (i = 0; i < 4; i = i + 1)
a[(i*8) +: 8] = i;
例1:
`timescale 1ns / 1ps
module tb;
wire [7:0] a = 8'h7f;
reg [3:0] b;
initial
begin
b = a[0 +: 4];
$display("time = %d, b = %h", $time, b);
#10;
b = a[3:0];
$display("time = %d, b = %h", $time, b);
#10;
b = a[7 -: 4];
$display("time = %d, b = %h", $time, b);
#10;
b = a[7:4];
$display("time = %d, b = %h", $time, b);
#10;
end
endmodule
仿真的结果:
time = 0, b = f time = 10, b = f time = 20, b = 7 time = 30, b = 7
2.向量定义
wire [63:0] a; // a[0] 是最低有效位, a[63] 是最高有效位
reg [0:63] b; // b[0] 是最高有效位,b[63] 是最低有效位
例2:
`timescale 1ns / 1ps
module tb;
wire [63:0] a; // a[0] 是最低有效位, a[63] 是最高有效位
reg [0:63] b; // b[0] 是最高有效位, b[63] 是最低有效位
assign a = 64'h0123_4567_89ab_cdef;
reg [23:0] c;
initial
begin
b = 64'h0123_4567_89ab_cdef;
c = a[31 -: 24]; // 从bit[31]位开始(包括bit[31]位), 宽度为24位。 相当于 c = a [31:08];
$display ("time = %d, c = %h", $time , c );
#10;
c = a[ 8 +: 24]; // 从bit[8]位开始(包括bit[8]位), 宽度为24位。 相当于 c = a [31:08];
$display ("time = %d, c = %h", $time , c );
#10;
c = b[31 -: 24]; // 从bit[31]位开始(包括bit[31]位), 宽度为24位。 相当于 c = b [08:31];
$display ("time = %d, c = %h", $time , c );
#10;
c = b[ 8 +: 24]; // 从bit[8]位开始(包括bit[8]位), 宽度为24位。 相当于 c = b [08:31];
$display ("time = %d, c = %h", $time , c );
#10;
end
endmodule
控制台输出的结果:
time = 0, c = 89abcd
time = 10, c = 89abcd
time = 20, c = 234567
time = 30, c = 234567
可变的向量域选择通常用于向量的初始化赋值, 当然在平时使用时,也是可以用于赋值语句的。 可变的向量域选择是可仿真的, 也是可综合的语法。
例3:
`timescale 1ns / 1ps
module tb;
integer i;
reg [31:0] a;
reg [31:0] b;
initial
begin
for (i = 0; i < 4; i = i + 1)
begin
a[(i*8) +: 8] = i;
end
#10;
$display("a[31:24] = %h", a[31:24]);
$display("a[23:16] = %h", a[23:16]);
$display("a[15:08] = %h", a[15:08]);
$display("a[07:00] = %h", a[07:00]);
#10;
b[31:24] = 3;
b[23:16] = 2;
b[15:08] = 1;
b[07:00] = 0;
#10;
$display("b[31:24] = %h", b[31:24]);
$display("b[23:16] = %h", b[23:16]);
$display("b[15:08] = %h", b[15:08]);
$display("b[07:00] = %h", b[07:00]);
end
endmodule
控制台输出结果:
a[31:24] = 03
a[23:16] = 02
a[15:08] = 01
a[07:00] = 00
b[31:24] = 03
b[23:16] = 02
b[15:08] = 01
b[07:00] = 00
我们会看到, 上个例子中, 如果使用可变向量选择, 会使得代码变得更加简洁灵活。特别是在for 循环中经常会使用可变向量域选择这种方式。
对应视频:
学习本篇文章后有几点收获,1、可变向量域的使用方式,向量名[起始位 +:位宽]、向量名[起始位 -:位宽];2、起始位可以是变量,但是位宽必须是常量;3、注意[63:0]a、[0:63]b二者的区别;
本篇文章举例论证非常详实,阅读后收获满满,很棒!