相关阅读
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,