【ZYNQ Ultrascale+ MPSOC FPGA教程】第六章 FPGA片内RAM读写测试实验

原创声明:

本原创教程由芯驿电子科技(上海)有限公司(ALINX)创做,版权归本公司全部,如需转载,需受权并注明出处。node

适用于板卡型号:

AXU2CGA/AXU2CGB/AXU3EG/AXU4EV-E/AXU4EV-P/AXU5EV-E/AXU5EV-P /AXU9EG/AXU15EG缓存

实验Vivado工程为“ram_test”。

RAM是FPGA中经常使用的基础模块,可普遍用于缓存数据的状况,一样它也是ROM,FIFO的基础。本实验将为你们介绍如何使用FPGA内部的RAM以及程序对该RAM的数据读写操做。工具

1.实验原理

Xilinx在VIVADO里为咱们已经提供了RAM的IP核, 咱们只需经过IP核例化一个RAM,根据RAM的读写时序来写入和读取RAM中存储的数据。实验中会经过VIVADO集成的在线逻辑分析仪ila,咱们能够观察RAM的读写时序和从RAM中读取的数据。测试

2.建立Vivado工程

在添加RAM IP以前先新建一个ram_test的工程, 而后在工程中添加RAM IP,方法以下:spa

2.1 点击下图中IP Catalog,在右侧弹出的界面中搜索ram,找到Block Memory Generator,双击打开。3d

2.2 将Component Name改成ram_ip,在Basic栏目下,将Memory Type改成Simple Dual Prot RAM,也就是伪双口RAM。通常来说"Simple Dual Port RAM"是最经常使用的,由于它是两个端口,输入和输出信号独立。code

2.3 切换到Port A Options栏目下,将RAM位宽Port A Width改成16,也就是数据宽度。将RAM深度Port A Depth改成512,深度指的是RAM里能够存放多少个数据。使能管脚Enable Port Type改成Always Enable。orm

2.4 切换到Port B Options栏目下,将RAM位宽Port B Width改成16,使能管脚Enable Port Type改成Always Enable,固然也能够Use ENB Pin,至关于读使能信号。而Primitives Output Register取消勾选,其功能是在输出数据加上寄存器,能够有效改善时序,但读出的数据会落后地址两个周期。不少状况下,不使能这项功能,保持数据落后地址一个周期。blog

2.5 在Other Options栏目中,这里不像ROM那样须要初始化RAM的数据,咱们能够在程序中写入,因此配置默认便可,直接点击OK。教程

2.6 点击“Generate”生成RAM IP。

3. RAM的端口定义和时序

Simple Dual Port RAM 模块端口的说明以下:

信号名称 方向 说明
clka in 端口A时钟输入
wea in 端口A使能
addra in 端口A地址输入
dina in 端口A数据输入
clkb in 端口B时钟输入
addrb in 端口B地址输入
doutb out 端口B数据输输出

RAM的数据写入和读出都是按时钟的上升沿操做的,端口A数据写入的时候须要置高wea信号,同时提供地址和要写入的数据。下图为输入写入到RAM的时序图。

RAM写时序

而端口B是不能写入数据的,只能从RAM中读出数据,只要提供地址就能够了,通常状况下能够在下一个周期采集到有效的数据。

RAM读时序

4. 测试程序编写

下面进行RAM的测试程序的编写,因为测试RAM的功能,咱们向RAM的端口A写入一串连续的数据,只写一次,并从端口B中读出,使用逻辑分析仪查看数据。代码以下

`timescale1ns/1ps ////////////////////////////////////////////////////////////////////////////////// module ram_test( input clk, //25MHz时钟  input rst_n //复位信号,低电平有效  ); //----------------------------------------------------------- reg [8:0] w_addr; //RAM PORTA写地址 reg [15:0] w_data; //RAM PORTA写数据 reg wea; //RAM PORTA使能 reg [8:0] r_addr; //RAM PORTB读地址 wire [15:0] r_data; //RAM PORTB读数据  //产生RAM PORTB读地址 always@(posedge clk ornegedge rst_n) begin if(!rst_n) r_addr <=9'd0; elseif(|w_addr) //w_addr位或,不等于0  r_addr <= r_addr+1'b1; else r_addr <=9'd0; end //产生RAM PORTA写使能信号 always@(posedge clk ornegedge rst_n) begin if(!rst_n) wea <=#11'b0; else begin if(&w_addr)//w_addr的bit位全为1,共写入512个数据,写入完成  wea <=#11'b0; else wea <=#11'b1;//ram写使能 end end //产生RAM PORTA写入的地址及数据 always@(posedge clk ornegedge rst_n) begin if(!rst_n) begin w_addr <=9'd0; w_data <=16'd1; end else begin if(wea) //ram写使能有效  begin if(&w_addr)//w_addr的bit位全为1,共写入512个数据,写入完成  begin w_addr <= w_addr ;//将地址和数据的值保持住,只写一次RAM  w_data <= w_data ; end else begin w_addr <= w_addr +1'b1; w_data <= w_data +1'b1; end end end end //----------------------------------------------------------- //实例化RAM ram_ip ram_ip_inst ( .clka (clk ),// input clka .wea (wea ),// input [0 : 0] wea .addra (w_addr ),// input [8 : 0] addra .dina (w_data ),// input [15 : 0] dina .clkb (clk ),// input clkb .addrb (r_addr ),// input [8 : 0] addrb .doutb (r_data )// output [15 : 0] doutb ); //实例化ila逻辑分析仪 ila_0 ila_0_inst ( .clk (clk ), .probe0 (r_data ), .probe1 (r_addr ) ); endmodule 

为了能实时看到RAM中读取的数据值,咱们这里添加了ila工具来观察RAM PORTB的数据信号和地址信号。关于如何生成ila你们请参考”PL的”Hello World”LED实验”。

程序结构以下:

绑定引脚

##################Compress Bitstream############################
set_property BITSTREAM.GENERAL.COMPRESS TRUE [current_design]set_property PACKAGE_PIN AB11 [get_ports clk]set_property IOSTANDARD LVCMOS33 [get_ports clk]create_clock -period 40.000 -name clk -waveform {0.000 20.000} [get_ports clk]set_property PACKAGE_PIN AA13 [get_ports rst_n]set_property IOSTANDARD LVCMOS33 [get_ports rst_n]

5. 仿真

仿真方法参考”PL的”Hello World”LED实验”,仿真结果以下,从图中能够看出地址1写入的数据是0002,在下个周期,也就是时刻2,有效数据读出。

6. 板上验证

生成bitstream,并下载bit文件到FPGA。接下来咱们经过ila来观察一下从RAM中读出的数据是否为咱们初始化的数据。

在Waveform的窗口设置r_addr地址为0做为触发条件,咱们能够看到r_addr在不断的从0累加到1ff, 随着r_addr的变化, r_data也在变化, r_data的数据正是咱们写入到RAM中的512个数据,这里须要注意,r_addr出现新地址时,r_data对应的数据要延时两个时钟周期才会出现,数据比地址出现晚两个时钟周期,与仿真结果一致。

相关文章
相关标签/搜索