调用IP实现数据加速

前言

在数字系统设计中,提升数据处理速度和效率是关键目标。本实验着眼于利用双端口RAM和异步FIFO对IP核ROM中的数据进行加速处理,通过这两种硬件组件的有效结合来优化数据访问和传输。双端口RAM允许同时进行读写操作,提高数据处理的并行性和吞吐量,而异步FIFO则解决了不同时钟域之间的数据传输问题,实现了高效的数据缓冲和同步。设计一个集成了双端口RAM和异步FIFO的FPGA系统,验证其在加速数据处理方面的性能。

正文

一、调用IP实现数据加速

1.项目需求

通过ROM,RAM,FIFO与锁相环四个ip核结合起来进行一个综合设计,本设计主要是利用双端口ram和异步fifo对Ip核rom中的数据进行加速处理。

2.技术介绍

双端口RAM:拥有两个独立的读写端口,可同时进行读写操作。提供了更高的数据吞吐量和更低的访问延迟,适用于需要并行处理的应用场景。

异步FIFO:通过内部的读写指针和状态标志位,实现了数据的无缝缓冲和处理,有效解决了数据传输中的速率不匹配问题。是一种先进先出(FIFO)的数据缓存器,能够跨时钟域进行数据传输。

RAM(Random Access Memory,随机访问存储器):RAM是一种易失性存储器,即断电后存储的数据会丢失。它支持随机读写,这意味着可以跳过前面的内存地址,直接对任何地址上的数据进行访问。RAM通常用于快速存储正在被CPU使用的程序和数据,以提高响应速度和效率。它通常用于操作系统和应用程序的内存分配,因为它能够以非常快的速度进行读写操作。

ROM(Read-Only Memory,只读存储器):ROM是一种非易失性存储器,即使电源关闭,其中存储的数据也可以保持不变。它只能进行读操作,不能进行写操作,或者是写操作受到限制,需要特殊的硬件或软件条件才能进行。ROM通常用于存储固件或固化的代码,这些信息不应当被修改,或者是在设备启动的时候需要使用这些数据。例如,BIOS(基本输入输出系统)就是一种ROM,它储存了计算机启动和检测硬件所需的基本指令。mif文件保存正弦波数据。

FIFO(First-In First-Out,先进先出队列):FIFO是一种数据结构,遵循先进先出的原则,即最早进入队列的数据或元素是第一个被处理的。FIFO在软件中是一种算法,而在硬件中则可能是一个专门的组件。在FPGA中,FIFO通常由专门的硬件逻辑实现,它可以跨越不同的时钟域工作,支持不同速度的数据源和使用者之间的高效数据传输。FIFO用于在数据处理的不同阶段之间缓冲数据,保证数据流不受速度差异的影响,避免数据丢失或乱序。在多任务系统和实时系统中,FIFO是一种常见的数据交互机制。

在实际的数字系统设计中,RAM、ROM和FIFO可以通过不同的搭配方式来提高数据处理的效率和性能。进行数据预取与缓存流程为

1.ROM读取:从ROM中读取数据或指令。

2.数据存储:将数据存储到RAM中,以便进行快速访问和处理。

3.FIFO缓冲:将数据从RAM通过FIFO传输到处理单元,FIFO在数据传输过程中进行缓冲,避免由于处理速度不匹配而导致的数据丢失。

基于IP核,本章将讲述如何实现利用双端口ram和异步fifo对Ip核rom中的数据进行加速处理。

3.顶层架构

数据保存在rom中通过ram写控制模块读出数据并写入到ram中,ram的数据通过ram读控制模块读出并通过fifo写控制模块写入到fifo中,数据最终通过fifo读控制模块读出。

4.端口描述

|-------------|-------------|
| clk | 系统时钟 |
| rst_n | 复位按键(低电平有效) |
| data[7:0] | 读出数据 |

二、代码验证

rd_fifo_ctrl模块:

module rd_fifo_ctrl(
 
	input clk,
	input rst_n,
	input empty,//标志信号,指示FIFO是否为空。为空时,无法进行读操作。
	input full,//标志信号,指示FIFO是否已满。FIFO满时,无法进行写操作。
	
	output reg rdreq//读请求信号,表示请求从FIFO中读取数据。
);
 
always @(posedge clk,negedge rst_n)
begin
	if(rst_n == 0)
		rdreq <= 1'b0;
	else
		if(full == 1)//FIFO已满
			rdreq <= 1'b1;//开始读
		else
			if(empty == 1)//FIFO为空
				rdreq <= 1'b0;//停止读
			else
				rdreq <= rdreq;
end 
endmodule 

rd_ram_ctrl模块:

module rd_ram_ctrl(

	input clk,
	input rst_n,
	input wren,//ram写使能
	
	output reg rden,//ram读使能信号
	output reg [7:0] rd_addr//读地址
);

reg wren_r;
reg wren_rr;
wire neg_flag;

always @(posedge clk,negedge rst_n)
begin
	if(rst_n == 0)
		begin
			wren_r <= 1'b0;
			wren_rr <= 1'b0;
		end 
	else
		begin
			wren_r <= wren;//暂存写使能信号
			wren_rr <= wren_r;
		end 
end 

assign neg_flag = ~wren_r & wren_rr;//ram写使能信号下降沿检测

always @(posedge clk,negedge rst_n)
begin
	if(rst_n == 0)
		rden <= 1'b0;
	else
		if(neg_flag == 1)//写使能拉低
			rden <= 1'b1;//读使能有效
		else
			if(rd_addr == 255)
				rden <= 1'b0;
			else
				rden <= rden;
end 

always @(posedge clk,negedge rst_n)//地址切换逻辑
begin
	if(rst_n == 0)
		rd_addr <= 8'd0;
	else
		if(rden == 1)
			rd_addr <= rd_addr +8'd1;
		else
			rd_addr <= 8'd0;
end 

endmodule 

wr_fifo_ctrl模块:

module wr_fifo_ctrl(

	input clk,
	input rst_n,
	input rden,//ram的读使能信号
	input [7:0] data,//写入FIFO的数据
	
	output reg wrreq,//fifo写使能
	output [7:0] fifo_data//fifo写数据
);

assign fifo_data = data;

always @(posedge clk,negedge rst_n)
begin
	if(rst_n == 0)
		wrreq <= 1'b0;
	else
		wrreq <= rden;//ram读使能时fifo写使能
end 

endmodule 

wr_ram_ctrl模块:

module wr_ram_ctrl(

	input clk,
	input rst_n,
	input empty,//标志信号,指示FIFO是否为空。为空时,无法进行读操作。
	input [7:0] data,//rom读出的数据
	
	output reg [7:0] rom_addr,//rom的地址
	output reg wren,//ram写使能
	output reg [7:0] wr_addr,//ram写地址
	output [7:0] wr_data//ram写数据
);

reg rd_rom_en;//读rom使能信号
reg wren_r;

reg [1:0] state;
parameter s0 = 2'd0;//fifo数据是否读空状态
parameter s1 = 2'd1;//控制从rom中读取数据
parameter s2 = 2'd2;//判断fifo是否写入数据

//状态机
always @(posedge clk,negedge rst_n)
begin
	if(rst_n == 0)
		begin
			state <= s0;
			rd_rom_en <= 1'b0;
		end 
	else
		case(state)
			s0	:	begin
						rd_rom_en <= 1'b0;//读rom使能信号停止
						if(empty == 1)//fifo为空,状态跳转
							state <= s1;
						else
							state <= s0;
					end 
			s1	:	begin
						if(rom_addr == 255)//rom的地址读完
							begin
								rd_rom_en <= 1'b0;
								state <= s2;
							end 
						else
							begin
								rd_rom_en <= 1'b1;
								state <= s1;
							end 
					end 
			s2	:	begin
						rd_rom_en <= 1'b0;
						if(empty == 0)//fifo不为空
							state <= s0;
						else
							state <= s2;
					end 
			default	:	begin rd_rom_en <= 1'b0;state <= s0; end 
		endcase
end 

always @(posedge clk,negedge rst_n)//地址递增
begin
	if(rst_n == 0)
		rom_addr <= 8'd0;
	else
		if(rd_rom_en == 1)
			rom_addr <= rom_addr + 8'd1;
		else
			rom_addr <= 8'd0;
end 

always @(posedge clk,negedge rst_n)//
begin
	if(rst_n == 0)
		wren <= 1'b0;
	else
		wren <= rd_rom_en;	//ram写使能=rom读使能
end 

always @(posedge clk,negedge rst_n)
begin
	if(rst_n == 0)
		wr_addr <= 8'd0;
	else
		wr_addr <= rom_addr;
end 

assign wr_data = data;//rom读出数据等于ram写入数据

endmodule 

data_speed_up模块:顶层连线

module data_speed_up(

	input clk,
	input rst_n,
	
	output [7:0] data
);

	wire wr_ram_clk;//20
	wire rd_ram_clk;//50
	wire rd_fifo_clk;//120
	wire locked;
	wire [7:0] rom_addr;
	wire [7:0] rom_data;
	wire empty;
	wire wren;
	wire [7:0] wr_addr;
	wire [7:0] wr_data;
	wire rden;
	wire [7:0] rd_addr;
	wire [7:0] rd_data;
	wire wrreq;
	wire [7:0] fifo_data;
	wire rdfull;
	wire rdreq;
	wire wrfull;
	wire wrempty;
	wire [7:0] wrusedw;
	wire [7:0] rdusedw;

my_pll	my_pll_inst (
	.areset ( ~rst_n ),
	.inclk0 ( clk ),
	.c0 ( wr_ram_clk ),
	.c1 ( rd_ram_clk ),
	.c2 ( rd_fifo_clk ),
	.locked ( locked )
);

my_rom	my_rom_inst (
	.address ( rom_addr ),
	.clock ( wr_ram_clk ),
	.q ( rom_data )
	);

wr_ram_ctrl wr_ram_ctrl_inst(

			.clk(wr_ram_clk),
			.rst_n(locked),
			.empty(empty),
			.data(rom_data),
			
			.rom_addr(rom_addr),
			.wren(wren),
			.wr_addr(wr_addr),
			.wr_data(wr_data)
);

double_ram	double_ram_inst (
	.data ( wr_data ),
	.rdaddress ( rd_addr ),
	.rdclock ( rd_ram_clk ),
	.rden ( rden ),
	.wraddress ( wr_addr ),
	.wrclock ( wr_ram_clk ),
	.wren ( wren ),
	.q ( rd_data )
	);
	
rd_ram_ctrl rd_ram_ctrl_inst(

			.clk(rd_ram_clk),
			.rst_n(locked),
			.wren(wren),
			
			.rden(rden),
			.rd_addr(rd_addr)
);

wr_fifo_ctrl wr_fifo_ctrl_inst(

			.clk(rd_ram_clk),
			.rst_n(locked),
			.rden(rden),
			.data(rd_data),
			
			.wrreq(wrreq),
			.fifo_data(fifo_data)
);

rd_fifo_ctrl rd_fifo_ctrl_inst(

			.clk(rd_fifo_clk),
			.rst_n(locked),
			.full(rdfull),
			.empty(empty),
			
			.rdreq(rdreq)
);

asyn_fifo	asyn_fifo_inst (

			.data ( wr_data ),//输入信号,将要写入FIFO的数据。
			.rdclk ( rd_clk ),//读操作的时钟信号,控制FIFO读操作的时序。
			.rdreq ( rdreq ),//读请求信号,表示请求从FIFO中读取数据。
			.wrclk ( wr_clk ),//写操作的时钟信号,控制FIFO写操作的时序。
			.wrreq ( wrreq ),//写请求信号,表示请求将数据写入FIFO。
			.q ( data ),//输出信号,从FIFO中读取的数据。
			.rdempty ( rdempty ),//标志信号,指示FIFO是否为空。为空时,无法进行读操作。
			.rdfull ( rdfull ),//标志信号,指示FIFO是否已满。FIFO满时,无法进行写操作。
			.rdusedw ( rdusedw ),//信号,指示当前FIFO中已被使用的单元数量。
			.wrempty ( wrempty ),//标志信号,指示FIFO在写操作时是否为空。
			.wrfull ( wrfull ),//标志信号,指示FIFO在写操作时是否已满。
			.wrusedw ( wrusedw )//信号,指示当前FIFO中已被写入的单元数量。
);

endmodule 

仿真文件

`timescale 1ns/1ps
module data_speed_up_tb;

	reg clk;
	reg rst_n;
	
	wire [7:0] data;

data_speed_up data_speed_up_inst(

	.clk(clk),
	.rst_n(rst_n),
	
	.data(data)
);

initial clk = 0;
always #10 clk = ~clk;

initial begin
	rst_n = 0;
	#200
	rst_n = 1;
	#30000
	$stop;
end 

endmodule 

三、仿真验证

观看仿真波形图,数据可以正常读出:

调出中间数据进行分析,可以看到读rom/写ram,读ram/写fifo,读fifo三个阶段分别使用依次变慢的时钟,对数据进行降速处理。

三阶段数据均位有丢失。

既然依次变慢的时钟会对数据读取有减速效果,同理,将锁相环输出时钟依次变快

由此,数据加速完成,利用双端口ram和异步fifo对Ip核rom中的数据进行加速处理成功。

参考资料

IP核FIFO调用及验证(2)

IP核RAM调用及验证(2)

相关推荐
贾saisai3 小时前
Xilinx系FPGA学习笔记(四)VIO、ISSP(Altera)及串口学习
笔记·学习·fpga开发
行者..................5 小时前
FPGA 时序逻辑 组合逻辑 连接 语句
fpga开发·fpga
廊桥遗梦72811 小时前
FPGA开发:条件语句 × 循环语句
算法·fpga开发
cckkppll12 小时前
vivado 创建时间约束2
fpga开发
北京太速科技股份有限公司17 小时前
太速科技-1路万兆光纤SFP+和1路千兆网络 FMC子卡模块
fpga开发
楠了个难1 天前
UART串口通信——FPGA学习笔记9
笔记·学习·fpga开发
FPGA狂飙1 天前
1分钟 快速掌握 双向信号(inout信号)
fpga开发·verilog·fpga·xilinx
通信小小昕1 天前
基于I2S的音频ADC_DAC的_FPGA的驱动
fpga开发·音频·adc·fifo·dac·i2s
十三啊嘞2 天前
Xilinx FPGA 原语解析(三):OBUFDS差分输出缓冲器(示例源码及仿真)
fpga开发
廊桥遗梦7282 天前
FPGA开发:模块 × 实例化
fpga开发