Verilog:$readmemb和$readmemh系统函数的使用与其中的初始化地址相关问题(详细细节)

相关阅读

Verilog基础icon-default.png?t=N7T8https://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指的是要读取数据的文本文件名,文件名可以使用绝对路径或相对路径,相对指的是相对当前仿真器的工作目录(一般为项目文件所在文件夹)。

        要读取数据的文件有以下三点要求:

  • 用于分隔数字的空白字符(空格、换行符、制表符、换页符)
  • 注释(两种形式的注释都可以,即//或/* */)
  • 二进制或十六进制数字(这里指的是纯数字,不含任何其他指示性的符号,即111,fff这种,且不能包含正负号+、-)

        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);
endmoduledata.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
endmoduledata.txt //data[5], data[6], data[7]未初始化
00 //地址为1
01 //地址为2
10 //地址为3
11 //地址为4data.txt //恰好全部初始化
00 //地址为1
01 //地址为2
10 //地址为3
11 //地址为4
00 //地址为5
01 //地址为6
10 //地址为7data.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
endmoduledata.txt //data[1]和data[6], data[7]未初始化
00 //地址为2
01 //地址为3
10 //地址为4
11 //地址为5data.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,默认地址递增
endmoduledata.txt //data[1], data[5], data[6], data[7]未初始化
00 //地址为2
01 //地址为3
10 //地址为4data.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,默认地址递减
endmoduledata.txt //data[1], data[2], data[6], data[7]未初始化
00 //地址为5
01 //地址为4
10 //地址为3data.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 //地址为9data.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
endmoduledata.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的原值01data.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,

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/114988.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Merge之后,还没有Push,如何回滚

Merge之后,还没有Push,如何回滚 Merge之后,还没有Push,如何回滚 1:代码操作: 1:git log 查看git执行历史记录 GIT所有的执行记录会以倒叙呈现;最上面的就是需要回滚的merge序列号&a…

爬虫 — Scrapy 框架(一)

目录 一、介绍1、同步与异步2、阻塞与非阻塞 二、工作流程三、项目结构1、安装2、项目文件夹2.1、方式一2.2、方式二 3、创建项目4、项目文件组成4.1、piders/__ init __.py4.2、spiders/demo.py4.3、__ init __.py4.4、items.py4.5、middlewares.py4.6、pipelines.py4.7、sett…

芯科蓝牙BG27开发笔记9-蓝牙温控器例程阅读

源码: https://download.csdn.net/download/hxkrrzq/88353283 以上源码都是官方资源,可以自行gitbub下载(参见之前笔记) 蓝牙广播格式化 之前的笔记中广播数据是直接使用的十六进制字符串,关于这32bytes数据的格式化…

【Linux】系统编程线程互斥与同步(C++)

目录 【1】线程互斥 【1.1】进程线程间的互斥相关背景概念 【1.2】互斥量mutex 【1.3】互斥量实现原理探究 【1.4】RAII的加锁风格 【2】可重入VS线程安全 【2.1】概念 【2.2】常见的线程不安全的情况 【2.3】常见的线程安全的情况 【2.4】常见不可重入的情况 【2.5…

Linux之ASCII码表查询tools(五十九)

简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀 人生格言: 人生…

基于复旦微的FMQL45T900全国产化ARM核心模块(100%国产化)

TES745D是一款基于上海复旦微电子FMQL45T900的全国产化ARM核心板。该核心板将复旦微的FMQL45T900(与XILINX的XC7Z045-2FFG900I兼容)的最小系统集成在了一个87*117mm的核心板上,可以作为一个核心模块,进行功能性扩展,能…

Flask框架-2-[单聊]: flask-socketio实现websocket的功能,实现单对单聊天,flask实现单聊功能

一、概述和项目结构 在使用flask-socketio实现单聊时,需要将会话id(sid) 与用户进行绑定,通过emit(事件,消息,tosid) ,就可以把消息单独发送给某个用户了。 flask_websocket |--static |--js |--jquery-3.7.0.min.js |--socket.io_4.3.1.js |--template…

实验五 熟悉 Hive 的基本操作

实验环境: 1.操作系统:CentOS 7。 2.Hadoop 版本:3.3.0。 3.Hive 版本:3.1.2。 4.JDK 版本:1.8。 实验内容与完成情况: (1)创建一个内部表 stocks,字段分隔符为英文逗号…

Linux 中的make/makefile

一:背景 make是一个命令工具,是一个解释makefifile中指令的命令工具,一般来说,大多数的IDE都有这个命令,比如:Delphi的make,Visual C的nmake,Linux下GNU的make。可见,mak…

《Python等级考试(1~6级)历届真题解析》专栏总目录

❤️ 专栏名称:《Python等级考试(1~6级)历届真题解析》 🌸 专栏介绍:中国电子学会《全国青少年软件编程等级考试》Python编程(1~6级)历届真题解析。 🚀 订阅专栏:订阅后可…

为什么伦敦金获得连续盈利这么难

相信在伦敦金市场中投资的投资者都有这个感受,我们很容易在市场中获取力量利润,但是要长期的在市场中稳定的盈利,持续不断地获利,这对很多投资者来说都有点难,可以这么说,稳定盈利是普通投资者一个阶段性的…

【SpringCloud】微服务技术栈入门2 - Nacos框架与Feign

目录 Nacos下载 Nacos 并运行配置 NacosNacos 集群Nacos 负载均衡Nacos 环境隔离Nacos 注册细节Nacos 更多配置项快速上手自动更新 Feign取代 RestTemplateFeign 自定义配置性能优化 Nacos 下载 Nacos 并运行 首先下载对应的 release 包,主要要选择已经打包编译好…