• ALTERA FPGA IPCORE核之单口RAM详细教程


    ALTERA FPGA IPCORE之单口RAM详细教程

    若要观看该博客配套的视频教程,可点击此链接

    一. RAM简介

    RAM:是英文Random Access Memory的缩写,即随机存取存储器,也叫主存,是与CPU直接交换数据的内部存储器。相对FIFO来说,RAM工作时可随时从任何一个指定地址写入或读出信息。
    在QuartusII中,生成RAM IPCORE时有两种可选

    • 单口RAM(1-PORT)
      只有一个端口,可读可写,但无法同时进行
    • 双口RAM(2-PORT)
      有两个独立的端口,其中一个端口只读,另一端口只写

    二. 单端口RAM IPCORE生成步骤及参数介绍

    我们先生成一个写数据位宽8,读数据位宽8的单口RAM,利用Modelsim仿真来观察单口RAM的时序波形。

    2.1 首先打开QuartusII软件,新建一个工程,命令为single_ram_test

    新建工程的步骤就不一一说明,为了方便上板验证,选用我们开发板上的器件:EP4CE6F17C8

    2.2 单口RAM IPCORE配置
    2.2.1 生成IPCORE,命名为single_ram_w8r8_d1024
    我们在对IPCORE命名时,最好能体现出该IPCORE的一些主要特性,比如我们上面的命名,我们知道是一个单口RAM,写数据位宽8,读数据位宽8,深度1024。
    生成步骤如下图所示在这里插入图片描述在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    当生成好后可以看到左边RAM框图已经显示出了RAM的输入输出接口,同时在左下角还能看到这个RAM需要占用的资源情况。
    2.2.2 RAM接口定义如下:
    aclr:异步清零信号,高电平有效。该清零信号只能清楚输出端口的数据,并不会清除存储器内部存储的内容。
    address:地址线,位宽为10bit。由于我们调用的 RAM 为单口 RAM,所以只有一组地址线。
    clock:读写时钟。
    data:写入 RAM 的数据,位宽为 8bit。
    rd_en:读使能信号,高电平有效。该信号在配置时刻可选择不生成。
    wr_en:写使能信号,高电平有效。在 RAM 中,该信号固定存在。
    q:读出 RAM 中的数据,位宽也是 8bit。
    其中“ q”为输出信号,其余信号都为该模块的输入信号,需要我们产生输入。为了测试生成的RAM IPCORE,我们做一个测试例程,向RAM地址0到3中写入4个数据,然后再从地址3~0,把数据读出来,看一下读出的数据和写入的数据是否一致。我们通过仿真来验证。

    三. Verilog代码设计

    `timescale 1ns / 100ps
        module single_ram_test(
        	input	clk			,//时钟,频率50MHZ
        	input	rst_n		,//复位信号,低电平有效
        	output	[7:0]	dout //ram输出数据
        	);
        	reg	[8:0]	cnt;
        	wire[9:0]	address;
        	reg	[7:0]	wrdata;
        	reg	[1:0]	wraddr;
        	reg	[1:0]	rdaddr;
        	reg			wren;
        	reg			rden;
        	//用assign做一个选择,当wren为高电平时,输入ram的地址等于写ram地址,
        	//否则输入ram的地址等于读ram地址
        	assign	address=(wren)?{8'h00,wraddr}:{8'h00,rdaddr};
        	//计数器,以此计数器来生成RAM读写使能及读写地址和写的数据
        	always@(posedge clk or negedge rst_n)begin
        		if(!rst_n)
        			cnt<=0;
        		else 
        			cnt<=cnt+1;
        	end
        	//生成写地址,写数据和写使能
        	always@(posedge clk or negedge rst_n)begin
        		if(!rst_n)begin
        			wraddr	<=3;
        			wrdata	<=0;
        			wren	<=0;
        		end else if(cnt>0&&cnt<=4)begin
        			wraddr	<=wraddr+1;
        			wrdata	<=cnt;
        			wren	<=1;
        		end else begin
        			wraddr	<=3;
        			wren	<=0;
        		end
        	end
        	//生成读地址和读使能
        	always@(posedge clk or negedge rst_n)begin
        		if(!rst_n)begin
        			rdaddr	<=0;
        			rden	<=0;
        		end else if(cnt>5&&cnt<=9)begin
        			rdaddr	<=rdaddr-1;
        			rden	<=1;
        		end else begin
        			rdaddr	<=0;
        			rden	<=0;
        		end
        	end
        	//例化RAM IPCORE
        	single_ram_w8r8_d1024 Usingle_ram_w8r8_d1024 (
        	.aclr		(~rst_n		),//异步清零信号
        	.address	(address	),//读写地址线
        	.clock		(clk		),//使用系统时钟作为读写时钟
        	.data		(wrdata		),//写入 RAM 的数据
        	.wren		(wren		),//写 RAM 使能
        	.rden		(rden		),//输出读 RAM 数据
        	.q  (dout		) //输出读 RAM 数据
        	);
        endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62

    四. Verilog测试代码设计

        `timescale 1ns / 100ps
        module single_ram_test_tb;
        	reg					clk			=1;
        	reg					rst_n		=0;
        initial
        	begin
        		#1000
        		rst_n=1;
        	end
        //生成激励时钟
        always #10 clk<=~clk;
        //例化被测试模块
        single_ram_test Usingle_ram_test(
        	.clk			(clk),//50MHZ
        	.rst_n			(rst_n),
        	.dout   	()
        	);
        endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    五. 仿真波形分析

    在这里插入图片描述

    通过上面的仿真图,我们可以看到,当wren为高电平时,写入的地址依次是0,1,2,3,写入的数据依次是1,2,3,4。这样就相当于建立了一张表,如下图所示:
    在这里插入图片描述
    那么如果我们读地址3的数据就应该是4,地址2的数据是3,地址1的数据是2,地址0的数据是1。可以看到仿真波形中,当rden为高电平时,读地址依次是3,2,1,0,读出的数据依次是4,3,2,1(有效数据在rden拉高后延时一个时钟周期才输出),与存储的表格相符。
    如果大家想要该工程的源码,测试激励文件用来学习,可以直接联系工程师,感谢大家的阅读!

  • 相关阅读:
    【Graph】NetworkX官方基础教程
    12.并发之ForkJoin框架详解
    产品结构设计的主要内容有哪些?
    【推荐系统中的Hash 1】Hash Trick:原始数据—>特征,尽可能避免冲突
    Java项目实战记录:雷达数据插值
    基于python+django+vue.js开发的停车管理系统
    springboot+nacos使用
    香港中文大学卢煜明教授荣获诺贝尔奖的“风向标”--拉斯克奖
    对线性插值的理解
    Qt应用开发(基础篇)——列表视图 QListView
  • 原文地址:https://blog.csdn.net/Moon_3181961725/article/details/126686401