相关阅读
Verilog基础https://blog.csdn.net/weixin_45791458/category_12263729.html?spm=1001.2014.3001.5482
$readmemb和$readmemh两个系统函数用于将文件中的数据加载到存储器或者被称为数组的memory中。首先给出他们的语法的BNF范式,有关BNF范式的内容可以在之前的文章中找到:
首先要注意的是,作为系统函数的一类,这些语句都是能在过程块initial和always中使用的。
load_memory_tasks分为两类,一类是以二进制解析文件中的数据,而另一类是以十六进制解析。特别提醒,$readmemb和$readmemh中美元符$和后面的关键词之间必须连续,不能有空白。
file_name指的是要读取数据的文本文件名,文件名可以使用绝对路径或相对路径,相对指的是相对当前仿真器的工作目录(一般为项目文件所在文件夹)。
要读取数据的文件有以下三点要求:
memory_name指的是需要初始化的存储器名,数字的长度不能高于存储器的数据位宽,否则当读取到不符合要求的数据会报错,无法继续读取。未知值(x或X)、高阻抗值(z或Z)和下划线(_)可用于指定数字,应使用若干空白字符和/或注释来分隔数字,下面是一些例子。
test.v
module test();
reg [7:0]data[7:0];//和reg [7:0]data[0:7];效果相同
initial
$readmemb("../data.txt", data);
endmodule
data.txt
//前5个数据正常读取,直到0b报错无法解析
11 01 11111 11 100 0b101 110 111 1000 001 100001
//第一个数据太大了,报错无法解析
11111111111 11 01 11111 11
//可以在数字中插入_
11_00 1122 2344
//可以用换行符分隔
11
22
33
//可以用注释分隔数字
11/*55555*/01 11111 11 100
//可以在数字中使用x或z
z1 x1 11 12
当指定的数字位宽小于存储器的位宽时,将会进行位宽拓展,这里的拓展规则只和数据有关而与存储器变量的类型无关,类似于Verilog基础:表达式中的整数常量(integer)一文中“无符号数字的位宽小于位宽常数指定的大小”一样,如果数字最高位是1或0,则补0至存储器的数据位宽,如果是z则补z,如果是x则补x。
当文件数据被从上至下,从左至右读取时,每个数据被分配给索引从低到高的各个存储器变量,寻址可以通过在系统任务调用中指定开始和/或结束地址以及在数据文件中使用符号指定地址来控制。
当地址出现在数据文件中时,格式为@字符,后跟十六进制数字,如下所示:
@hhh
@HHH
@HhH
@ 1h1 //错误
数字中允许同时使用大写和小写数字。@和数字之间不允许有空格,可以使用数据文件中所需的任意多的地址规范,当系统任务遇到地址规范时,它会从该内存地址开始加载后续数据,并将数据填入对应地址索引的寄存器变量中。
文件中的所有数字都有默认的地址,分为几种情况:
test.v
module test();
reg [7:0]data[7:1];
initial
$readmemb("data.txt", data);//地址范围1到7
endmodule
data.txt //data[5], data[6], data[7]未初始化
00 //地址为1
01 //地址为2
10 //地址为3
11 //地址为4
data.txt //恰好全部初始化
00 //地址为1
01 //地址为2
10 //地址为3
11 //地址为4
00 //地址为5
01 //地址为6
10 //地址为7
data.txt //全部初始化
00 //地址为1
01 //地址为2
10 //地址为3
11 //地址为4
00 //地址为5
01 //地址为6
10 //地址为7
11 //地址为8,当试图读取这个数时会提示超出范围(Too many data words read on line 8 of file)
//并结束读取
test.v
module test();
reg [7:0]data[7:1];
initial
$readmemb("data.txt", data, 2);//起始地址为2(必须在1到7之间),则地址范围是2到7
endmodule
data.txt //data[1]和data[6], data[7]未初始化
00 //地址为2
01 //地址为3
10 //地址为4
11 //地址为5
data.txt //data[1]未初始化
00 //地址为2
01 //地址为3
10 //地址为4
11 //地址为5
00 //地址为6
01 //地址为7,读取完这个数据遇到文件结束,结束读取
data.txt //data[1]未初始化
00 //地址为2
01 //地址为3
10 //地址为4
11 //地址为5
00 //地址为6
01 //地址为7
10 //地址为8,当试图读取这个数时会提示超出范围(Too many data words read on line 7 of file)
//并结束读取
test.v
module test();
reg [7:0]data[7:1];
initial
$readmemb("data.txt", data, 2, 5);//起始地址为2,终止地址为5(必须在1到7之间),则地
//址的范围是2到5,默认地址递增
endmodule
data.txt //data[1], data[5], data[6], data[7]未初始化
00 //地址为2
01 //地址为3
10 //地址为4
data.txt //data[1]未初始化
00 //地址为2
01 //地址为3
10 //地址为4
11 //地址为5
00 //地址为6
01 //地址为7,读取完这个数据遇到文件结束,结束读取
data.txt //data[1]未初始化
00 //地址为2
01 //地址为3
10 //地址为4
11 //地址为5
00 //地址为6
01 //地址为7
10 //地址为8,当试图读取这个数时会提示超出范围(Too many data words read on line 7 of file)
//并结束读取
test.v
module test();
reg [7:0]data[7:1];
initial
$readmemb("data.txt", data, 5, 2);//起始地址为5,终止地址为2(必须在1到7之间),则地
//址的范围是2到5,默认地址递减
endmodule
data.txt //data[1], data[2], data[6], data[7]未初始化
00 //地址为5
01 //地址为4
10 //地址为3
data.txt //data[1], data[6], data[7]未初始化
00 //地址为5
01 //地址为4
10 //地址为3
11 //地址为2,读取完这个数据遇到文件结束,结束读取
data.txt //data[1], data[6], data[7]未初始化
00 //地址为5
01 //地址为4
10 //地址为3
11 //地址为2
00 //地址为1,当试图读取这个数时会提示超出范围(Too many data words read on line 5 of file)
//并结束读取
01 //地址为0
data.txt //系统函数中起始地址小于终止地址,或没有终止地址,或没有起始和终止地址,则递增
00 //地址为-2
01 //地址为-1
10 //地址为0
@1
00 //地址为1
01 //地址为2
10 //地址为3
@7
00 //地址为7
01 //地址为8
10 //地址为9
data.txt //系统函数中起始地址大于终止地址,则递减
00 //地址为9
01 //地址为8
10 //地址为7
11 //地址为6
@5
00 //地址为5
01 //地址为4
10 //地址为3
11 //地址为2
@6
00 //地址为6
01 //地址为5
10 //地址为4
11 //地址为3
在读取有地址标号的文件时,首先会定位到地址和起始地址相同的那条数据(当没有起始地址时,是定位到存储器对应的最小地址,上面的第一种情况中为1),然后开始从左到右,从上到下,一条一条数据依次读取数据,直到文件结束(所以可能会出现初始化覆盖的情况,如下所示),或者有数据的地址超出了范围才结束读取。
test.v
module test();
reg [7:0]data[7:1];
initial
$readmemb("data.txt", data, 2);//起始地址为2(必须在1到7之间),则地址范围是2到7
endmodule
data.txt
00 //地址为-1
01 //地址为0
10 //地址为1
11 //地址为2, 从这里开始读取
@3
00 //地址为3
01 //地址为4
10 //地址为5
11 //地址为6
@0
00 //地址为1
00 //地址为2,覆盖了地址为2的原值11
11 //地址为3,覆盖了地址为3的原值00
00 //地址为4,覆盖了地址为4的原值01
data.txt
00 //地址为-1
01 //地址为0
10 //地址为1
11 //地址为2, 从这里开始读取
@3
00 //地址为3
01 //地址为4
10 //地址为5
11 //地址为6
11 //地址为7
11 //地址为8,当试图读取这个数时会提示超出范围(Too many data words read on line 11 of
//file并结束读取,因此后面不会覆盖
@0
00 //地址为1
00 //地址为2,
11 //地址为3,
00 //地址为4,