Verilog语法(标量、向量,数组、寄存器组,存储器)——赋值、读写操作、常见误区

Verilog语法(标量、向量,数组、寄存器组,存储器)——赋值、读写操作、常见误区

一、Verilog通过对reg型变量建立数组来对存储器进行建模,可以描述RAM,ROM存储器和寄存器数组

//格式
reg[n-1:0]存储器名[m-1:0];
//reg[n-1:0]是定义了每一个存储器单元大小,为n位宽		[m-1:0]定义了存储器大小,即有多少存储器

reg [n-1:0]rega;//一个n位寄存器		
reg memb[m-1:0];//n个一位寄存器
rega = 0; 		//合法
memb = 0;		//不合法
//Verilog 中允许声明 reg, wire, integer, time, real 及其向量类型的数组。
//维数没有限制。线网数组也可以用于连接实例模块的端口。数组中的每个元素都可以作为一个标量或者向量,以同样的方式来使用,形如:<数组名>[<下标>]。对于多维数组来讲,用户需要说明其每一维的索引。例如:

integer          flag [7:0] ; //8个整数组成的数组
reg  [3:0]       counter [3:0] ; //由4个4bit计数器组成的数组
wire [7:0]       addr_bus [3:0] ; //由4个8bit wire型变量组成的数组
wire             data_bit[7:0][5:0] ; //声明1bit wire型变量的二维数组
reg [31:0]       data_4d[11:0][3:0][3:0][255:0] ; //声明4维的32bit数据变量数组

二、标量、向量,数组、寄存器组,存储器

1、标量、向量

在声明wire或reg变量时,如果不指定范围,那么此时的wire/reg就是一个标量(scalar);反之,如果指定了范围,那么此时的wire/reg就是一个向量(Vector)。

wire  [3:0]  n0;        //4位宽的向量wire
wire         n1;        //单位宽的标量wire

reg  [3:0]  d0;        //4位宽的向量reg
reg         d1;        //单位宽的标量reg

向量最左端的值被称为最高有效位MSB,最右端的值被称为最低有效位 LSB。MSB和LSB的值可以是任意整数(正整数、负整数和零),而且MSB即可以大于LSB,也可以小于LSB,但两者不能相等(相等就是标量了)

    对于向量,可以根据其地址,来对某一位或某几位进行操作

位操作和部分操作

reg  [31:0] addrs;       //声明一个8位宽的reg型变量(向量)addrs
addrs [0] = 1'b1;       //直接对addr的第0位进行操作,将其赋值为1
addrs [4] = 1'b0;		//直接对addr的第4位进行操作,将其赋值为0
addr[23:16] = 8'h22;	//直接对addr的第16~23位进行操作,将其赋值为8'h22

Verillog 还支持指定 bit 位后固定位宽的向量域选择访问。

    [bit+: width] : 从起始 bit 位开始递增,位宽为 width。
    [bit-: width] : 从起始 bit 位开始递减,位宽为 width。
//下面 2 种赋值是等效的
A = data1[31-: 8] ;
A = data1[31:24] ;
//下面 2 种赋值是等效的
B = data1[0+ : 8] ;
B = data1[0:7] ;

2、数组、寄存器组

在 Verilog 中可以声明 reg, wire, integer, time, real类型的数组(Array)。数组维数没有限制,其中的每个元素可以是标量或者向量。

integer          flag [7:0] ; //8个整数组成的数组
reg  [3:0]       counter [3:0] ; //由4个4bit计数器组成的数组
wire [7:0]       addr_bus [3:0] ; //由4个8bit wire型变量组成的数组
wire             data_bit[7:0][5:0] ; //声明1bit wire型变量的二维数组
reg [31:0]       data_4d[11:0][3:0][3:0][255:0] ; //声明4维的32bit数据变量数组

数组使用

1、定义

reg [w : 0] r_addrss, w_addrss;		//读和写的地址
reg [wordsize : 0] array_name [2**w-1 : 0];
reg [wordsize : 0] data_in, data_out;
reg data_out_0;

2、写和读操作

	my_memory[address] = data_in;	//写操作
 	data_out = my_memory[address];	//读操作

3、读出某单元的具体位

对某单元具体一位进行操作
方法一 直接索引		[单元索引][位索引]
reg [7:0] my_array[0:3];

initial begin
    my_array[0][3] = 1'b1;  // 写数组中的第一个单元的第 4 位
    wire single_bit = my_array[0][3];  // 读数组中的第一个单元的第 4 位
end
方法二 利用中间变量  
	data_out = my_memory[address];
	data_out_it_0 = data_out[0];

读或写某单元连续多位
reg [7:0] my_array[0:3];
initial begin
    wire [3:0] multiple_bits = my_array[0][3:0]; 
    // 进行相应的处理
end

4、初始化
初始化内存有多种方式,这里介绍的是使用 $ readmemb 和 $ readmemh系统任务来将保存在文件中的数据填充到内存单元中去。
$ readmemb 和 $ readmemh是类似的,不过 $ readmemb 用于 内存的二进制 表示,而 $ readmemh 则用于内存内容的16进制 表示。这里以$readmemh系统任务来介绍。

$readmemh("file_name", mem_array, start_addr, stop_addr);

  • file_name是包含数据的文本文件名
  • mem_array是要初始化的内存单元数组名
  • tart_addr 和 stop_addr是可选的,指示要初始化单元的起始地址和结束地址。
//	例子
module  memory ();
	reg [7:0] my_memory [0:255];
 
	initial begin
	$readmemh("memory.list", my_memory);
end
endmodule

这里使用内存文件memory.list来初始化my_memory数组。

而下面就是一个内存文件的例子。

	//  Comments are allowed 
	CC         // This is first address i.e 8'h00
	AA         // This is second address i.e 8'h01
	@55     // Jump to new address 8'h55
	5A         // This is address 8'h55
	69         // This is address 8'h56

对于内存文件,要注意的是下列几点:
a、注释标记//在内存文件中是被允许的;
b、使用@符号将跳到新的目标地址,没有@符号就表示地址将顺序递增。

如上述的内存文件就只初始化8’h00,8’h01,8’h55和8’h56 4个内存地址单元

关于系统任务,有下列常见的用法:

  1. 顺序初始化所有的数组单元;

    	这种情况下,可以使用@符号来指示地址,也可以不使用它,而只在每一行存放要存放的数据。	
    	这样数据将顺序按地址递增存放,从0地址开始。		
    
  2. 只初始化部分的数组单元;

    	这种情况下,可以使用@符号来指示下一个要初始化的地址,然后对该地址单元进行初始化
    
  3. 只初始化数组的地址区间的一部分单元。

    	这个时候,还可以使用$readmemh任务的start_addr 和 stop_addr选项来指定初始化的范围。
    
 例如,只初始化1001045个单元,就可以这么做:
 内存文件memory.list定义为:
	CC
	AA
	55 
	5A
	69

而$readmemh(“memory.list”, my_memory, 100, 104);就指定使用memory.list来初始化my_memory的100-104单元

5、使用常见误区

reg [n-1:0]rega;//一个n位寄存器		
reg memb[m-1:0];//n个一位寄存器
rega = 0; 		//合法
memb = 0;		//不合法,寄存器组有多个数组不许一次性进行赋值

reg       a1[3:0];                //1维数组,共有4个元素,每个元素位宽为1(即标量)
reg [3:0] a2[3:0];                //1维数组,共有4个元素,每个元素位宽为4
reg [3:0] a3[3:0][15:0];         //2维数组,共有4*16 = 64个元素,每个元素位宽为4

         数组与向量一样,也可以通过地址索引的方式进行访问。

a1 = 0;                        //非法赋值--不能同时对4个元素赋值
a1[0] = 1'b0;               //对a1的第0个元素赋值为1'b0
a2[2] = 4'b1010;          //对a2的第2个元素赋值为4'b1010
a3[3] [1] = 4'b1111;    //对a3的第3行、第1个元素赋值为4'b1111

三、存储器

存储器(Memory)就是一种寄存器数组,数组的维数不能大于2,它可以用来构建 RAM(可读写) 或 ROM(仅可读)

参考博客

  • 32
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值