FPGA零基础学习:IP CORE 之 RAM设计
本系列将带来FPGA的系统性学习,从最基本的数字电路基础开始,最详细操作步骤,最直白的言语描述,手把手的“傻瓜式”讲解,让电子、信息、通信类专业学生、初入职场小白及打算进阶提升的职业开发者都可以有系统性学习的机会。
系统性的掌握技术开发以及相关要求,对个人就业以及职业发展都有着潜在的帮助,希望对大家有所帮助。后续会陆续更新 Xilinx 的 Vivado、ISE 及相关操作软件的开发的相关内容,学习FPGA设计方法及设计思想的同时,实操结合各类操作软件,会让你在技术学习道路上无比的顺畅,告别技术学习小BUG卡破脑壳,告别目前忽悠性的培训诱导,真正的去学习去实战应用。话不多说,上货。
IP CORE 之 RAM设计
作者:郝旭帅 校对:陆辉
本篇实现基于叁芯智能科技的SANXIN -B01 FPGA开发板,以下为配套的教程,如有入手开发板,可以登录官方淘宝店购买,还有配套的学习视频。
随机存取存储器(random access memory,RAM)又称作"随机存储器"。存储单元的内容可按需随意取出或存入,且存取的速度与存储单元的位置无关的存储器。这种存储器在断电时将丢失其存储内容,故主要用于存储短时间使用的程序。按照存储单元的工作原理,随机存储器又分为静态随机存储器(Static RAM,SRAM)和动态随机存储器(Dynamic RAM,DRAM)。在FPGA内部的存储块为SRAM。
设计要求
设计一个深度为256,宽度为8的RAM。不需要初始化内容。
设计原理
RAM,此种存储器支持写操作,支持读操作。在存储器建造时,可以进行初始化数据,也可以不进行初始化数据。RAM的初始化文件也是mif文件,原理和ROM类似。
本次设计RAM是利用FPGA片内嵌入的M9K构成的。
由于设计RAM深度为256,故而地址的宽度为8位。
RAM工作原理为,在时钟上升沿采样到rden为1时,将addr所指示的存储空间的数据进行输出;在时钟上升沿采样到wren为1时,将wdata存储到addr所指示的存储空间中去。
架构设计和信号说明
此模块命名为ram_test。ram_my为ip core。
调用 ip core 之 RAM
建立好工程,打开tools -> ip catalog。按照下图的方式,找到RAM :1-port。
选择verilog,找到对应路径,命名为ram_my。
选择深度为256,宽度为8,单时钟。点击Next。
选择q端被寄存,引出rden信号。点击Next。
当读写相同地址时,ram应该怎么操作,在这边选择默认。点击Next。
询问是否初始化,我们保持默认,即不初始化。点击Next。
保持默认,点击Next。
选择ram_my_inst.v,然后点击finish。
点此ip core 添加进工程。点击Yes。
顶层设计
顶层负责调用ram_my,例化文件在ip core -> ram_my -> ram_my_inst.v中。
设计代码为:
代码语言:javascript复制module ram_test (
input wire clk,
input wire [7:0] addr,
input wire wren,
input wire [7:0] wdata,
input wire rden,
output wire [7:0] rdata
);
ram_my ram_my_inst (
.address ( addr ),
.clock ( clk ),
.data ( wdata ),
.rden ( rden ),
.wren ( wren ),
.q ( rdata )
);
endmodule
RTL仿真
在某些地址中,写入一些数据,然后读出来。由于写进去后,还需要读出来,所以地址不在使用随机值,固定在0,100,200,255地址写入随机值。
仿真代码为:
代码语言:javascript复制`timescale 1ns/1ps
module ram_test_tb;
reg clk;
reg [7:0] addr;
reg wren;
reg [7:0] wdata;
reg rden;
wire [7:0] rdata;
ram_test ram_test_inst(
.clk (clk),
.addr (addr),
.wren (wren),
.wdata (wdata),
.rden (rden),
.rdata (rdata)
);
initial clk = 1'b0;
always # 10 clk = ~clk;
initial begin
addr = 8'd0;
wren = 1'b0;
wdata = 8'd0;
rden = 1'b0;
@ (posedge clk);
# 2;
addr = 8'd0;
wren = 1'b1;
wdata = {$random} % 256;
@ (posedge clk);
# 2;
addr = 8'd100;
wren = 1'b1;
wdata = {$random} % 256;
@ (posedge clk);
# 2;
addr = 8'd200;
wren = 1'b1;
wdata = {$random} % 256;
@ (posedge clk);
# 2;
addr = 8'd255;
wren = 1'b1;
wdata = {$random} % 256;
@ (posedge clk);
# 2;
addr = 8'd0;
wren = 1'b0;
wdata = 8'd0;
# 200
@ (posedge clk);
# 2;
addr = 8'd0;
rden = 1'b1;
@ (posedge clk);
# 2;
addr = 8'd100;
rden = 1'b1;
@ (posedge clk);
# 2;
addr = 8'd200;
rden = 1'b1;
@ (posedge clk);
# 2;
addr = 8'd255;
rden = 1'b1;
@ (posedge clk);
# 2;
addr = 8'd0;
rden = 1'b0;
# 200
$stop;
end
endmodule
经过设置后,进行RTL仿真。
通过波形图中,可以看出,在地址为0时,写入数据为36;在地址为100时,写入数据为129;在地址为200时,写入数据为9;在地址为255时,写入数据为99。经过一段时间后,对上述几个地址进行读取,输出的数据与写入数据相同(输出时,输出数据要比地址晚两拍)。