相关阅读Verilog基础https://blog.csdn.net/weixin_45791458/category_12263729.html?spm1001.2014.3001.5482$readmemb和$readmemh两个系统任务用于将文件中的数据加载到存储器或者被称为数组的memory中。首先给出他们的语法的BNF范式有关BNF范式的内容可以在之前的文章中找到首先要注意的是作为系统任务的一类这些语句都是能在过程块initial和always中使用的。load_memory_tasks分为两类一类是以二进制解析文件中的数据而另一类是以十六进制解析。特别提醒$readmemb和$readmemh中美元符$和后面的关键词之间必须连续不能有空白。file_name指的是要读取数据的文本文件名文件名可以使用绝对路径从根目录开始的路径使用/开头和相对路径使用./或../开头./可省略这里的相对路径指的是相对仿真器的当前工作文件夹。要读取数据的文件有以下三点要求用于分隔数字的空白字符空格、换行符、制表符、换页符注释两种形式的注释都可以即//或/* */二进制或十六进制数字这里指的是纯数字不含任何其他指示性的符号即111fff这种且不能包含正负号、-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 //错误数字中允许同时使用大写和小写数字。和数字之间不允许有空格可以使用数据文件中所需的任意多的地址规范当系统任务遇到地址规范时它会从该内存地址开始加载后续数据并将数据填入对应地址索引的寄存器变量中。文件中的所有数字都有默认的地址分为几种情况如果系统任务中没有规定起始地址和终止地址数据文件中也没有显式的地址则数据的默认地址为从寄存器变量的最小地址开始依次加1。读取将从寄存器变量的最小地址开始依次读取后面的数据直到有一个数据的默认地址大于寄存器变量的最大地址因为此时的数据地址范围要求为从寄存器变量的最小地址到最大地址之间或者数据读完。举例说明如下所示。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 //并结束读取如果系统任务中只规定了起始地址它必须在存储器的地址范围内数据文件中也没有显式的地址则数据的默认地址为从起始地址开始依次加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 //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 //并结束读取如果系统任务中规定了起始地址和结束地址它们必须在存储器的地址范围内数据文件中也没有显式的地址则数据的默认地址为从起始地址因此它必须在存储器的地址范围内开始依次加1或减1这取决于起始地址和结束地址的大小如果结束地址大于起始地址则为加1否则为减1。读取将从起始地址开始依次读取后面的数据直到有一个数据的默认地址大于寄存器变量的最大地址或小于最小地址因为此时的数据地址范围要求为从寄存器变量的最小地址到最大地址之间或者数据读完。举例说明如下所示。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
阅读完成 · 觉得有帮助?