FPGA_学习_16_IP核_ROM(延迟一拍输出)

news2024/11/17 19:51:11

在寻找APD最合适的偏压的过程中,一般会用到厂商提供一条曲线,横坐标是温度的变化,纵坐标表示击穿偏压的变化,但每个产品真正的击穿偏压是有差异的。 为了能够快速的找到当前温度下真实的击穿偏压,我们可以这样做,我先根据温度,得到厂商提供的击穿偏压。 然后再用厂商提供的击穿偏压,减去几伏。 我们以此作为寻找真实击穿偏压的起点。以一个固定的步长提升APD的偏压,直到满足我们设定的击穿判断条件。 但是呢,在整个这个流程中,我们需要解决一个问题,就如何在FPGA程序中实时的去获取当前温度下对应的击穿偏压。 如果是dsp或者stm32等嵌入式平台,可以直接把温度-击穿偏压数据做成一个数据表存到一个数组,然后直接查表。 但是在FPGA中,我们不能用数组了,但可以选择用ROM IP核 去实现。 在FPGA中,一些固定的初始化参数也可以用ROM来保存。 本文记录ROM的使用方法。

1 ROM是什么

ROM 是只读存储器(Read-Only Memory)的简称,是一种只能读出事先所存数据的固态半导体存储器。其特性是一旦储存资料就无法再将之改变或删除,且资料不会因为电源关闭而消失。而事实上在 FPGA 中通过 IP 核生成的 ROM 或 RAM 调用的都是 FPGA 内部的 RAM 资源,掉电内容都会丢失(这也很容易解释,FPGA 芯片内部本来就没有掉电非易失存储器单元)。用 IP 核生成的 ROM 模块只是提前添加了数据文件(.coe 格式),在 FPGA 运行时通过数据文件给 ROM 模块初始化,才使得 ROM 模块像个“真正”的掉电非易失存储器;也正是这个原因,ROM 模块的内容必须提前在数据文件中写死,无法在电路中修改。

简单说就是FPGA的ROM你随便搞,不用担心一次写死后,后面再也不能改了。

2 .coe文件生成

ROM 作为只读存储器,在进行 IP 核设置时需要指定初始化文件,即写入存储器中的 数据,数据要以规定的格式才能正确写入 ROM,这种格式就是 coe 文件。coe Vivado 规定的一种文件格式,下图为文件格式示意图

 下面提供一个.coe文件的 MatLAB生成代码,一键即可生成你想要的.coe

clear;clear all;clc;

FileName=['mycoe','.coe']; 

fid = fopen(FileName,'w'); 

fprintf(fid,'memory_initialization_radix = 16;\n');
fprintf(fid,'memory_initialization_vector =\n');
% 位宽
Width = 16;
% 深度
Depth = 20;

Hexlen = Width / 4;

for i=1:Depth
    data = i;
    
    % 根据位宽补0
	HexCode = dec2hex(data);
	HexSize = size(HexCode,2);
	ZeroCode='';
    for j=1:(Hexlen-HexSize)
        ZeroCode=['0',ZeroCode];
    end
	str0 = [ZeroCode,HexCode];
    
    % 判断是否为最后一行
    if i < Depth
        Hexstr = [str0,','];
        fprintf(fid,'%s\n',Hexstr);
    elseif i==Depth
        Hexstr = [str0,';'];
        fprintf(fid,'%s',Hexstr);
    end
end
fclose(fid);

open(FileName);

3 ROM IP 配置

ROM分单口ROM和双口ROM,它们配置的区别仅仅只是Basic这一页Memory Type的选项的区别,其他的都是一样的。 所以本文仅以单口ROM的配置为例。

 傻瓜式截图,从最原始的IP Catalog开始

取名这里,还是关注一下,比如我是用的单口rom,深度20,位宽16位。我的IP核命名就可以是 s_rom_20x16b。 比如我是用双口rom,深度256,位宽8位呢,那IP核命名则为 d_rom_256x8b。 这样的命名,能做到一目了然。

 👆上面这个图有个值得关注的点: Totoal Port A Read Latency :1 Clock Cycle 。 意思是读的时候要输出要延迟一个时钟周期。👆

IP生成了,这个参数文件也被成功加载过来了。 

瞅一眼是怎么例化的。

 4 Modelsim仿真

ROM在读取数据的时候,要给ROM IP核输入你的ROM地址。 而ROM地址应该是从0开始的。 比如你Rom的深度是20(= 0x14),那你的ROM读地址就是 0x00 ~ 0x13(10进制是19)。那地址 0x00对应的是ROM存的第一个数据(本例中是0x0001)。 0x13对应的是ROM存的最后一个数据(本例中是0x0014)。

源码如下:

`timescale 1ns / 1ps

module lab_rom(
        input   wire    clk,
        input   wire    rst_n
);


//==================================================================
//                        Parameter define
//==================================================================
parameter       MAX_ADDRA       = 20 - 1;


//==================================================================
//                        Internal Signals
//==================================================================
reg     [4:0]   addra;
wire    [15:0]  douta;

//----------------------------- addra自增 -----------------------------
always @(posedge clk or negedge rst_n) begin
        if (rst_n == 1'b0) begin
            addra <= 'd0;        
        end
        else if(addra == MAX_ADDRA)begin
                addra <= 'd0;
        end
        else begin
                addra <= addra + 1'b1;
        end
end

//----------------------------- s_rom_20x16b例化 -----------------------------
s_rom_20x16b s_rom_20x16b_inst (
        .clka(clk),    // input wire clka
        .addra(addra),  // input wire [4 : 0] addra
        .douta(douta)  // output wire [15 : 0] douta
);

endmodule

 约束文件

create_clock	-period			20.000		[	get_ports	clk	]

set_property    PACKAGE_PIN		N18			[	get_ports	clk			]
set_property    PACKAGE_PIN		T12			[	get_ports	rst_n		]

set_property    IOSTANDARD      LVCMOS33	[	get_ports	clk			]  
set_property    IOSTANDARD      LVCMOS33	[	get_ports	rst_n		]  

仿真代码

`timescale 1ns/1ps
module tb_lab_rom (); /* this is automatically generated */

    // clock
    reg clk;
    initial begin
        clk = 1'b0;
        forever #(10) clk = ~clk;
    end

    // asynchronous reset
    reg rst_n;
    initial begin
        rst_n <= 1'b0;
        #10
        rst_n <= 1'b1;
    end

    // (*NOTE*) replace reset, clock, others
    parameter MAX_ADDRA = 20 - 1;

    lab_rom #(.MAX_ADDRA(MAX_ADDRA)) inst_lab_rom (.clk(clk), .rst_n(rst_n));

endmodule

 仿真结果

5 ila在线调试

本着再复习一下ila在线调试的原则,这里做一个在线调试的测试。

代码

`timescale 1ns / 1ps

module lab_rom(
        input   wire    clk,
        input   wire    rst_n
);


//==================================================================
//                        Parameter define
//==================================================================
parameter       MAX_ADDRA       = 20 - 1;


//==================================================================
//                        Internal Signals
//==================================================================
(* MARK_DEBUG="true" *) reg     [4:0]   addra;    // 修改🔺
(* MARK_DEBUG="true" *) wire    [15:0]  douta;    // 修改🔺

//----------------------------- addra自增 -----------------------------
always @(posedge clk or negedge rst_n) begin
        if (rst_n == 1'b0) begin
            addra <= 'd0;        
        end
        else if(addra == MAX_ADDRA)begin
                addra <= 'd0;
        end
        else begin
                addra <= addra + 1'b1;
        end
end

//----------------------------- s_rom_20x16b例化 -----------------------------
s_rom_20x16b s_rom_20x16b_inst (
        .clka(clk),    // input wire clka
        .addra(addra),  // input wire [4 : 0] addra
        .douta(douta)  // output wire [15 : 0] douta
);

endmodule

 Run Synthesis - Open Synthesized Design    运行综合 - 打开已综合的设计

 Set up Debug → Next   设置调试→下一步 

添加要观测的信号并设置时钟域

 由于项目比较简单,刚刚截图的瞬间,系统刚刚应该是自动Run synthesis了一遍,并且还Run完了。

 编译完之后直接 Open Hareware Manager 打开硬件管理器 - 直接烧写程序,刷新设备

 在线调试功能正常。

参考文献

Vivado 下 IP核 之ROM 读写_OliverH-yishuihan的博客-CSDN博客

在给rom IP核命名的时候,我发现FPGA的代码应该有一个统一遵循的规范,包括ip核 模块 变量 参数的命名规则、注释、缩进风格等都应该有一个规范, 后续应该会有一篇博客讲规范,不过目前初学阶段接触的FPGA相关内容还不够全面,因此这篇博客应该是在初学阶段的尾声部分。 另外,约束文件中关于时序部分的约束也是后续关注的一个重点。  

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

YOLO入门介绍

YOLO&#xff08;You Only Look Once&#xff09;是一种基于深度学习的目标检测算法&#xff0c;它的核心思想是将目标检测任务转化为一个回归问题&#xff0c;通过单次前向传播即可完成目标检测。相比于传统的目标检测算法&#xff0c;YOLO具有更快的检测速度和更高的准确率&a…

定时检测接口是否正常飞书告警脚本

第一版 支持多个接口地址&#xff0c;循环检测&#xff0c;定时每分钟执行一次脚本 告警效果 脚本 飞书机器人创建忽略跳过&#xff0c;各大协作平台大同小异拿出机器人hook地址 #!/bin/bash URL_LIST(https://gatewaxxxxxxxxxxxxxxxxxx https://sandbox-gatexxxxxxxxxxxxxxx…

机器学习深度学习——NLP实战(情感分析模型——textCNN实现)

&#x1f468;‍&#x1f393;作者简介&#xff1a;一位即将上大四&#xff0c;正专攻机器学习的保研er &#x1f30c;上期文章&#xff1a;机器学习&&深度学习——NLP实战&#xff08;情感分析模型——RNN实现&#xff09; &#x1f4da;订阅专栏&#xff1a;机器学习…

NDK 的配置记录~

NDK 的配置 NDK配置 NDK设置在 AS 路径中设置在 local.properties设置在 build.gradle ndk 和 gradle 对应关系gradle的插件和版本对应关系gradle 插件和NDK对应关系 NDK NDK&#xff08;Native Development Kit&#xff09;是一组工具和库&#xff0c;用于在 Android 平台上开…

加强预算管理一体化,走进全面预算管理的数智化时代

自2021年&#xff0c;国务院印发《国务院关于进一步深化预算管理制度改革的意见》&#xff08;国发〔2021〕5号&#xff09;以来&#xff0c;中央政府对企业实施全面预算管理越来越重视&#xff0c;预算绩效管理逐渐进入大家的视线。各个企业逐步落实应用&#xff0c;推进预算管…

C++的常用基础知识100个

1、定义一个常量 2、数据类型-整型 3、数据类型-字符型 4、数据的输入 5、运算符 6、三目运算符 7、循环案例-99乘法表 8、数组 9、冒泡排序 10、函数的定义 11、函数的分文件编写 12、指针 12、结构体 13、通讯录项目 创建一个空项目&#xff0c;并命名为通讯录管理系统。 14…

“我来拿”APP设计报告

1.设计摘要 想必大家对学校的悬赏互助群并不陌生&#xff0c;学生们在群里提出要求并标明价格&#xff0c;就可以找人帮忙。我们的跑腿平台就是以此为灵感&#xff0c;让学生之间通过一个专门的020平台实现有报酬的互助跑腿&#xff0c;但是相比QQ、微信群&#xff0c;我们让定…

js数组常用的方法(总结)

目录 1.数组头和尾操作——push、pop、unshift/shift 2、数组转为字符串 —— join() 3、数组截取 —— slice() 4、数组更新 —— splice() 5、反转数组 —— reverse() 6、连接数组 —— concat() 7、ES6连接数组 —— ... ES5数组新增方法 8、索引方法 —— indexO…

PgSQL中的DATE_PART使用

用法&#xff1a; DATE_PART(field, source) 这个DATE_PART()函数返回类型为double precision的值 century decade year month day hour minute second microseconds milliseconds dow doy epoch isodow isoyear timezone timezone_hour timezone_minute

水经微图网页版发布

水经微图网页版&#xff0c;可轻松将关注的地点制作成你的个人地图。 你可以在任意位置添加标注点或绘制地图&#xff0c;查找地点并将其保存到你的地图中&#xff0c;或导入地图数据迅速制作地图并保存&#xff0c;你还可以运用图标和颜色展示个性风采&#xff0c;从而可让每…

线程阻塞队列

阻塞队列 一、BlockingQueue 接口 BlockingQueue 是阻塞队列接口实现机制是使用两条线程&#xff0c;允许两个线程同时操作队列一个线程用于写入 Put ,一个线程用于读取 Take当队列中没有数据的情况下&#xff0c;读取线程会自动阻塞&#xff0c;直到有数据放入队列当队列中数…

opencv进阶12-EigenFaces 人脸识别

EigenFaces 通常也被称为 特征脸&#xff0c;它使用主成分分析&#xff08;Principal Component Analysis&#xff0c;PCA&#xff09; 方法将高维的人脸数据处理为低维数据后&#xff08;降维&#xff09;&#xff0c;再进行数据分析和处理&#xff0c;获取识别结果。 基本原理…

蓝牙资讯|消息称富士康投资4亿美元在印度生产苹果 AirPods 耳机

根据印度最大通讯社 PTI 报道&#xff0c;苹果和富士康已经签署一项新的协议&#xff0c;富士康将投资 4 亿美元在印度第四大城市海得拉巴扩建工厂&#xff0c;负责为苹果生产 AirPods TWS 耳机。 报道称苹果已经决定在印度本土生产 AirPods 耳机&#xff0c;富士康计划投资 …

测试框架pytest教程(2)-用例依赖库-pytest-dependency

对于 pytest 的用例依赖管理&#xff0c;可以使用 pytest-dependency 插件。该插件提供了更多的依赖管理功能&#xff0c;使你能够更灵活地定义和控制测试用例之间的依赖关系。 Using pytest-dependency — pytest-dependency 0.5.1 documentation 安装 pytest-dependency 插…

ipad手写笔有必要买吗?开学便宜又好用电容笔推荐

苹果电容笔之所以能够被iPad用户广泛使用&#xff0c;很大程度上是因为其的优秀性能&#xff0c;具有着独特的重力压感功能。但苹果原装的电容笔&#xff0c;价格相对比较高&#xff0c;所以很多人&#xff0c;都选择了普通的平替电容笔。如今许多人都爱用iPad来画图或写笔记&a…

Go 数组

一、复合类型&#xff1a; 二、数组 如果要存储班级里所有学生的数学成绩&#xff0c;应该怎样存储呢&#xff1f;可能有同学说&#xff0c;通过定义变量来存储。但是&#xff0c;问题是班级有80个学生&#xff0c;那么要定义80个变量吗&#xff1f; 像以上情况&#xff0c;最…

攻防世界-command_execution

原题 解题思路 题目告诉了&#xff0c;这可以执行ping命令且没WAF&#xff0c;那就可以在ping命令后连接其他命令。 服务器一般使用Linux&#xff0c;在Linux中可使用“&”连接命令。 ping 127.0.0.1&find / -name "flag*" ping 127.0.0.1&cat /home/f…

Linux中shell脚本常用命令、条件语句与if、case语句

目录 一.shell脚本常用命令 1.1.echo命令 1.2.date命令 1.3.cal命令 1.4.tr命令 1.5.cut命令 1.6.sort命令 1.7.uniq命令 1.8.cat多行重定向 二.条件语句 2.1.条件测试&#xff08;三种测试方法&#xff09; 2.2.正整数值比较 2.3.字符串比较 2.4.逻辑测试 三.i…

深入了解 Java 中 Files 类的常用方法及抽象类的 final 修饰

文章目录 Files 类常用方法抽象类的 final 修饰 &#x1f389;欢迎来到Java学习路线专栏~深入了解 Java 中 Files 类的常用方法及抽象类的 final 修饰 ☆* o(≧▽≦)o *☆嗨~我是IT陈寒&#x1f379;✨博客主页&#xff1a;IT陈寒的博客&#x1f388;该系列文章专栏&#xff1a…

【C语言学习】二分法查找有序数组中的数

二分查找的基本原理 二分查找的基本逻辑就是每次找区间的中间数&#xff0c;然后与要查找的数进行比较&#xff0c;不断的缩小区间&#xff0c;最后区间中只剩一个数&#xff0c;即为要查找的数。如果不是&#xff0c;则没有该数。 二分查找只适用于有序数组 以数组中的数从左…