一、标量和向量
Verilog中常用的数据类型为wire、reg,两者都可以定义为一位变量和多位变量,其中一位的称为标量,多位的称为向量。
- 1bit的时序器件即为一个触发器;16bit的时序器件即为一个能够存储16bit数据的存储器。
- 若没有指定wire或reg的位宽,则认为1bit的标量;若指定了位宽,则wire或reg变成多比特实体向量。
1、表达方式
wire a1; // 单比特wire型标量
wire [7:0] a2; // 8-bit wire型矢量
reg a3; // 单比特reg型变量
reg [31:0] a4; // 32 bit 存储地址的矢量变量
2、位宽规范性
位宽的表达方式在上下代码中应统一风格,一般以最左边为最高位,最右边为最低位。
wire [msb:lsb] b1;
integer msb_1;
wire [15:0] b2; // 合法表达,msb = 15, lsb = 0
wire [msb_1: 2] b3; // 非法表达
msb以及lsb可以是任何整数值–正负或零,不允许使用变量,而且Isb的值可以大于、等于或小于msb的值。但为了保持风格统一,也就是左边的值要比右边的值大,所以不建议lsb大于或等于msb。
3、位选择
向量中的各个位都是可以被单独选中进行操作,如赋值,运算等。例如:
reg [7:0] addr; // 8-bit reg variable [7, 6, 5, 4, 3, 2, 1, 0]
addr [0] = 1; // assign 1 to bit 0 of addr
addr [3] = 0; // assign 0 to bit 3 of addr
结果示意图:
reg [31:0] addr;
addr [23:16] = 8'h23; // 23至16位被赋值为8'h23
若想要进行批量操作,可以使用:
[<start_bit> +: <width>] // 选中宽度为start_bit再加上width
[<start_bit> -: <width>] // 选中宽度为start_bit再减去width
例如:
module weikuan;
reg [31:0] data;
int i;
initial begin
data = 32'hFACE_CAFE;
for (i = 0; i < 4; i = i+ 1) begin
$display ("data[8*%0d +: 8] = 0x%0h", i, data[8*i +: 8]);
end
$display ("data[7:0] = 0x%0h", data[7:0]);
$display ("data[15:8] = 0x%0h", data[15:8]);
$display ("data[23:16] = 0x%0h", data[23:16]);
$display ("data[31:24] = 0x%0h", data[31:24]);
end
endmodule
仿真结果:
data[8*0 +: 8] = 0xfe // 等价于 data [8*0+8 : 8*0]
data[8*1 +: 8] = 0xca // 等价于 data [8*1+8 : 8*1]
data[8*2 +: 8] = 0xce // 等价于 data [8*2+8 : 8*2]
data[8*3 +: 8] = 0xfa // 等价于 data [8*3+8 : 8*3]
data[7:0] = 0xfe
data[15:8] = 0xca
data[23:16] = 0xce
data[31:24] = 0xfa
二、多维数组和存储器
在Verilog中,多维数组对应存储器,而向量可悲认为是一个深度为0的二维数组。
常用的二维数组有RAM、ROM等,主要由深度和位宽两个参数。
reg y1 [11:0]; // reg型数组,深度为12,位宽为1
wire [7:0] y2 [3:0] // wire型数组,深度为4,位宽为8
reg [7:0] y3 [0:1][0:3]; // reg型三维数组,2行(rows = 2)3列(cols = 3),每个单元数据位宽8bit
1、多维数组赋值
例子:
module mem();
reg [7:0] mem1; // reg vector 8-bit wide
reg [7:0] mem2 [0:3]; // 8-bit wide vector array with depth=4
reg [15:0] mem3 [0:3][0:1]; // 16-bit wide vector 2D array with rows=4,cols=2
initial begin
integer i;
mem1 = 8'ha9;
$display ("mem1 = 0x%0h", mem1);
mem2[0] = 8'haa;
mem2[1] = 8'hbb;
mem2[2] = 8'hcc;
mem2[3] = 8'hdd;
for(i = 0; i < 4; i = i + 1) begin
$display("mem2[%0d] = 0x%0h", i, mem2[i]);
end
for(int i = 0; i < 4; i += 1) begin
for(int j = 0; j < 2; j += 1) begin
mem3[i][j] = i + j;
$display("mem3[%0d][%0d] = 0x%0h", i, j, mem3[i][j]);
end
end
end
endmodule
仿真结果:
mem1 = 0xa9
mem2[0] = 0xaa
mem2[1] = 0xbb
mem2[2] = 0xcc
mem2[3] = 0xdd
mem3[0][0] = 0x0
mem3[0][1] = 0x1
mem3[1][0] = 0x1
mem3[1][1] = 0x2
mem3[2][0] = 0x2
mem3[2][1] = 0x3
mem3[3][0] = 0x3
mem3[3][1] = 0x4
2、RAM二维数组
mem为一个shendu256,位宽8bit的内存空间。
3、寄存器变量案例
- 一维数组案例:具体功能为:复位时,对寄存器赋0初值;当sel和wr有效时,将输入值赋给寄存器;其他情况,寄存器保持不变。
module dff(
input clk,
input rst_n,
input wr,
input sel,
input [15:0] wdata,
output [15:0] rdata );
reg [15:0] reg;
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
reg <= 16'b0;
else begin
if(sel & wr)
reg <= wdata;
else
reg <= reg;
end
end
assign rdata = (sel & ~wr) ? reg : 16'b0;
endmodule
- 二维数组案列:
module mem(
input clk,
input rst_n,
input [1:0] addr,
input wr,
input sel,
input [15:0] wdata,
output [15:0] rdata );
reg [15:0]mem[3:0];
integer i;
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
for(i = 0; i < 4; i = i + 1)begin
mem[i] <= 16'b0;
end
end
else begin
if(sel & wr)
mem[addr] <= wdata;
else
mem[addr] <= mem[addr];
end
end
assign rdata = (sel & ~wr) ? mem[addr] : 16'b0;
endmodule