上海古都建筑设计集团,上海办公室装修设计公司,上海装修公司高质量的内容分享社区,上海装修公司我们不是内容生产者,我们只是上海办公室装修设计公司内容的搬运工平台

FPGA简单双端口RAM——IP核

guduadmin281月前

文章目录

  • 前言
  • 一、双端口 RAM
    • 1、简单双端口与真双端口
    • 2、简单双端口RAM框图
    • 二、 IP核配置
      • 1、RAM双端口 IP 核配置
      • 2、PLL IP 核配置
      • 三、源码
        • 1、ram_wr(写模块)
        • 2、ram_rd(读模块)
        • 3、ip_2port_ram(顶层文件)
        • 四、仿真
          • 1、仿真文件
          • 2、波形仿真
          • 五、SignalTap II在线验证
          • 六、总结
          • 七、参考资料

            前言

            环境:

            1、Quartus18.0

            2、vscode

            3、板子型号:原子哥开拓者2(EP4CE10F17C8)

            要求:

            使用 Altera RAM IP 核生成一个简单双端口的 RAM,然后对 RAM 进行读写操作,并通过 Modelsim 软件进行仿真及 SignalTap 软件进行在线调试。


            一、双端口 RAM

            由前面的单端口学习我们知道RAM IP核分为单端口RAM以及双端口RAM,即RAM IP核的读写端口数。对于单端口,读写共用一对地址线,所以无法同时读写不同地址的数据。对于双端口,读写地址线是分开的,所以具备同时读写能力。

            1、简单双端口与真双端口

            双端口 RAM 又分为简单双端口 RAM 和真双端口 RAM,顾名思义,简单双端口 RAM 虽然有两个端口,但是一个端口只能用来写,另一个端口只能用来读,所以简单双端口 RAM 也称为伪双端口 RAM。而真双端口 RAM 是指两个端口都可以用来写或者读,可以理解成具有两个独立的单端口的 RAM,一般用于需要多路写入和读出的情况,而不用例化两个单端口的 RAM,在使用上更为方便。

            • 简而言之,在都需要读写的情况下,如果需要多路写入、读出的情况则选择真双端口。

              2、简单双端口RAM框图

              • 模块框图:

                FPGA简单双端口RAM——IP核,在这里插入图片描述,第1张

              • 端口框图:

                FPGA简单双端口RAM——IP核,在这里插入图片描述,第2张

              • 端口描述:

                data:RAM 写数据端口;

                wraddress:RAM 写地址端口;

                wren:写使能信号,高电平有效;

                byteena:字节使能控制,该功能屏蔽了输入数据,这样仅写入数据中指定字节,未被写入的字节保留之前写入的值。当写入数据的位宽为 16 位、18 位、32 位和 36 位时,M9K 模块将支持字节使能,wren 信号以及字节 byteena 信号一起控制 RAM 模块的写操作。byteena 信号在 RAM IP 核创建过程中是可选的,可选择是否使用字节使能控制功能。

                wr_addressstall:写地址时钟使能控制,当 wr_addressstall 信号为高电平时,有效地址时钟使能就会保持之前的地址。wr_addressstall 信号在 RAM IP 核创建过程中是可选的,可选择是否使用地址使能控制功能。

                wrclock:写时钟;

                wrclocken:写时钟使能信号,高电平有效;

                aclr:异步复位信号,高电平有效;

                rdaddress:RAM 读地址端口;

                rden:读使能信号,高电平有效;

                q:从 RAM 中读出的数据;

                rd_addressstall:读地址时钟使能控制,当 rd_addressstall 信号为高电平时,有效地址时钟使能就会保持之前的地址。rd_addressstall 信号在 RAM IP 核创建过程中是可选的,可选择是否使用地址使能控制功能。

                rdclock:读时钟;

                rdclocken:读时钟使能信号,高电平有效;

                二、 IP核配置

                1、RAM双端口 IP 核配置

                • 查找RAM IP:

                  FPGA简单双端口RAM——IP核,在这里插入图片描述,第3张

                • 双击过后添加IP核路径以及命名文件:

                  FPGA简单双端口RAM——IP核,在这里插入图片描述,第4张

                • 选择端口类型以及存储器大小:

                  FPGA简单双端口RAM——IP核,在这里插入图片描述,第5张

                  上面的选项是选择简单双端口还是真双端口;下面一个是用于指定存储器大小的单位words or bits。

                  • 设置RAM的存储深度以及位宽:

                    FPGA简单双端口RAM——IP核,在这里插入图片描述,第6张

                  • 勾选独立时钟以及读使能信号:

                    FPGA简单双端口RAM——IP核,在这里插入图片描述,第7张

                    “What clocking method do you want to use?”:用于设置双端口 RAM 的时钟,此处选择第二个(Dualclock:use separate ‘read’ and ‘write’ clocks),即写端口和读端口选择独立的时钟。

                    “Create a ‘rden’ read enable signal”:选择是否勾选读使能信号,如果不勾选则一直在读。

                    • 取消寄存输出信号q:

                      FPGA简单双端口RAM——IP核,在这里插入图片描述,第8张

                      这里如果选中的话,从RAM中读到的q会多延时一个时钟周期输出。

                      • 保持对RAM的初始化:

                        FPGA简单双端口RAM——IP核,在这里插入图片描述,第9张

                      • 保持默认,next:

                        FPGA简单双端口RAM——IP核,在这里插入图片描述,第10张

                      • 勾选ram_2_inst.v 和 ram_2_bb.v:

                        FPGA简单双端口RAM——IP核,在这里插入图片描述,第11张

                      • 点击finish过后点击YES将IP核添加到工程:

                        FPGA简单双端口RAM——IP核,在这里插入图片描述,第12张

                      • 效果:

                        FPGA简单双端口RAM——IP核,在这里插入图片描述,第13张

                        2、PLL IP 核配置

                        由于之前的文章早已详细介绍过,这里不在进行赘述:

                        IP核简介及PLL_IP核的调用

                        三、源码

                        我们配置了IP但我们仍然需要写驱动文件去调用他们。

                        1、ram_wr(写模块)

                        module ram_wr (
                            input               clk         ,
                            input               rst_n       ,
                            output              ram_wr_en   ,//写使能
                            output reg [4:0]    ram_wr_addr ,//写地址
                            output reg [7:0]    ram_wr_data  //写数据
                        );
                        /*****************
                        该写模块中,在计数器从0累加到31时向ram写入数据,在到达63后计数器保持不变
                        该模块只在上电后写入一次
                        ******************/
                        reg [5:0] wr_cnt;
                        //写使能在计数到0~31是为高电平
                        assign ram_wr_en = ((wr_cnt >= 6'd0) && (wr_cnt <= 6'd31) && rst_n) ? 1'b1 : 1'b0;
                        //计数器
                        always @(posedge clk or negedge rst_n) begin
                            if(!rst_n)begin
                                wr_cnt <= 6'd0;
                            end
                            else if(wr_cnt == 6'd63)
                                wr_cnt <=wr_cnt;
                            else
                                wr_cnt <= wr_cnt + 1'b1;
                        end
                        //产生写数据信号
                        always @(posedge clk or negedge rst_n) begin
                            if(!rst_n)
                                ram_wr_data <= 8'd0;
                            else if(wr_cnt >= 6'd0 && wr_cnt <= 6'd31)
                                ram_wr_data <= ram_wr_data + 1'b1;
                            else
                                ram_wr_data <= 8'd0;
                        end
                        //写地址信号
                        always @(posedge clk or negedge rst_n) begin
                            if(!rst_n)
                                ram_wr_addr <= 5'd0;
                            else if(wr_cnt >= 6'd0 && wr_cnt <= 6'd31)
                                ram_wr_addr <= ram_wr_addr + 1'b1;
                            else
                                ram_wr_addr <= 5'd0;
                        end
                        endmodule
                        

                        2、ram_rd(读模块)

                        module ram_rd(
                            input               clk             ,
                            input               rst_n           ,
                            input   [7:0]       ram_rd_data     ,//读数据
                            output              ram_rd_en       ,//读使能
                            output  reg [4:0]   ram_rd_addr      //读地址
                        );
                        reg [5:0] rd_cnt;
                        assign ram_rd_en = ((rd_cnt >= 6'd0) && (rd_cnt <= 6'd31) && rst_n) ? 1'b1 :1'b0;
                        //读计数器
                        always @(posedge clk or negedge rst_n)begin
                            if(!rst_n)
                                rd_cnt <= 6'd0;
                            else if(rd_cnt == 6'd63)
                                rd_cnt <= 6'd0;
                            else
                                rd_cnt <= rd_cnt + 1'b1;
                        end
                        //读地址范围
                        always @(posedge clk or negedge rst_n)begin
                            if(!rst_n)
                                ram_rd_addr <= 5'd0;
                            else if(rd_cnt >= 6'd0 && rd_cnt <= 6'd31)
                                ram_rd_addr <= ram_rd_addr + 1'b1;
                            else
                                ram_rd_addr <= 5'd0;
                        end
                        endmodule
                        

                        3、ip_2port_ram(顶层文件)

                        module  ip_2port_ram(
                            input     sys_clk   ,
                            input     sys_rst_n
                        );
                        wire clk_50m;
                        wire clk_25m;
                        wire locked;
                        wire rst_n;
                        wire       ram_wr_en  ;
                        wire [4:0] ram_wr_addr;
                        wire [7:0] ram_wr_data;
                        wire       ram_rd_en  ;
                        wire [4:0] ram_rd_addr;
                        wire [7:0] ram_rd_data;
                        assign rst_n = sys_rst_n & locked;
                        //锁相环,用于产生两个时钟
                        pll_clk pll_clk_inst(
                        	.areset         (~sys_rst_n),
                        	.inclk0         (sys_clk),
                        	.c0             (clk_50m),
                        	.c1             (clk_25m),
                        	.locked         (locked)
                        );
                        //RAM写模块
                        ram_wr ram_wr_inst(
                            .clk            (clk_50m),
                            .rst_n          (rst_n),
                            .ram_wr_en      (ram_wr_en  ),//写使能
                            .ram_wr_addr    (ram_wr_addr),//写地址
                            .ram_wr_data    (ram_wr_data) //写数据
                        );
                        //RAM读模块
                        ram_rd ram_rd_inst(
                            .clk             (clk_25m),
                            .rst_n           (rst_n),
                            .ram_rd_en       (ram_rd_en  ),//读使能
                            .ram_rd_addr     (ram_rd_addr), //读地址
                            .ram_rd_data     (ram_rd_data)//读数据
                        );
                        //简单双端口RAM
                        ram_2 ram_2_inst(
                        	.data           (ram_wr_data),
                        	.rdaddress      (ram_rd_addr),
                        	.rdclock        (clk_25m),
                        	.rden           (ram_rd_en),
                        	.wraddress      (ram_wr_addr),
                        	.wrclock        (clk_50m),
                        	.wren           (ram_wr_en),
                        	.q              (ram_rd_data)
                        );
                        endmodule
                        

                        四、仿真

                        1、仿真文件

                        `timescale 1ns/1ns
                        module tb_ip_2port_ram();
                        parameter T = 20;
                        reg    sys_clk;
                        reg    sys_rst_n;
                        initial begin
                            sys_clk = 1'b0;
                            sys_rst_n = 1'b0;
                            #(T+1)
                            sys_rst_n = 1'b1;
                            #(3000)
                            $stop;
                        end
                        always #(T/2) sys_clk = ~sys_clk;
                        ip_2port_ram ip_2port_ram_inst(
                            .sys_clk        (sys_clk),
                            .sys_rst_n      (sys_rst_n)
                        );
                        endmodule
                        

                        2、波形仿真

                        FPGA简单双端口RAM——IP核,在这里插入图片描述,第14张

                        • 波形分析:

                          黄线所在时刻既是写使能时刻也是读使能时刻,所以此时既在写又在读。当 ram 地址为 0 时,写入的数据也是 0;当 ram 地址为 1 时,写入的数据也是 1,我们总共向 ram 中写入 32 个数据。ram 中读出的数据 ram_rd_data 在延时一个时钟周期之后,开始输出数据,输出的数据为 0,1,2……,和我们写入的值是相等的

                          FPGA简单双端口RAM——IP核,在这里插入图片描述,第15张

                          • 波形分析:

                            只在开始时写入一次,随后不再写入,而是每隔一段时间读取一次

                            五、SignalTap II在线验证

                            • 读状态:

                              FPGA简单双端口RAM——IP核,在这里插入图片描述,第16张

                            • 分析:

                              ram_rd_en(读使能)信号拉高之后,ram_addr 从 0 开始增加,也就是说从 ram 的地址 0 开始读数据;ram 中读出的数据 ram_rd_data 在延时一个时钟周期之后,开始输出数据,输出的数据为 0,1,2……,和我们写入的值是相等的。与仿真结果一致。并且每隔一段时间读一遍。

                              • 写状态:

                                额,这里的写状态波形不知道怎的抓不到波形,这里因为写只是上电后写一次,后面不需要再写了,所以我设置了一个上升沿为触发条件,但他还是没有波形。应该是SignalTap II的使用还不太熟练,不太熟悉一些更复杂的操作。


                                六、总结

                                今天的实验是在昨天的单端口之上的另一内容,简单双端口可以同时进行读写,比单端口更加丰富。通过这次实验对IP核的配置越发熟练,每天都有在进步!

                                七、参考资料

                                以上资料均来自正点原子的教学视频或开拓者2开发教程:原子官方

网友评论

搜索
最新文章
热门文章
热门标签
 
 梦见火山爆发浓烟滚滚  梦见一个特别大的蜘蛛  梦见新鞋什么预兆