1.框图
-
-
-
- 定义数据存储单元 RAM
-
-
名称为 RAM, Native 单口 RAM,无 ECC 校验,最小面积算法。可看到有 5 组 I/O 引脚。
-
-
-
- 数据 RAM 的例化
-
-
1).读写都是 32 位数据,一共有 16384 个数据,形成 64KB 的 RAM
2).需要初始化文件,初始化文件是 dmem32.coe
上一步注意,刚创建的项目是没有初始文件和相应的路径的,所以在创建 RAM 的时候可以先设置成没有初始文件。
创建好 RAM 后,将 Classfiles\ip\ram 中的初始化文件有存储器初始化文件 dmem32.coe 拷贝到 minisys/minisys.srcs/sources_1/ip/ram/中。
双击刚建立的 RAM IP 核,重新设置其为有初始化文件,并选择已经拷贝好的 dmem32.coe 文件。
3).按 OK 就行了
4).数据 RAM 初始化文件
2.子模块设计
wire ram_clk = !ram_clk_i;
因为使用Block ram的固有延迟,RAM的地址线来不及在时钟上升沿准备好,使得时钟上升沿数据读出有误,所以采用反相时钟,使得读出数据比地址准备好要晚大约半个时钟,从而得到正确地址。
wire kickOff = upg_rst_i | (~upg_rst_i & upg_done_i);
kickOff = 1的时候CPU 正常工作,否则就是串口下载程序。
仿真顶层模块设置地址为0x00000010,先从这个地址读出原始的数据为0x00000000,然后设置MemWrit为高电平,并设置写数write_data为0xa00000f5。写完之后将MenWrite设置为低电平从0x00000010地址上读数据,读出的数据为0xa00000f5。
五、程序清单
1.设计文件
`timescale 1ns / 1ps
module dmemory32 (
input ram_clk_i,
input ram_wen_i, // 来自控制单元
input [13:0] ram_adr_i, // 来自memorio模块
input [31:0] ram_dat_i, // 来自译码单元的read_data2
output [31:0] ram_dat_o, // 从存储器中获得的数据
input upg_rst_i, // UPG reset (Active High)
input upg_clk_i, // UPG ram_clk_i (10MHz)
input upg_wen_i, // UPG write enable
input [13:0] upg_adr_i, // UPG write address
input [31:0] upg_dat_i, // UPG write data
input upg_done_i // 1 if programming is finished
);
// 因为使用Block ram的固有延迟,RAM的地址线来不及在时钟上升沿准备好,
// 使得时钟上升沿数据读出有误,所以采用反相时钟,使得读出数据比地址准
// 备好要晚大约半个时钟,从而得到正确地址。
// kickOff = 1的时候CPU 正常工作,否则就是串口下载程序。
wire kickOff = upg_rst_i | (~upg_rst_i & upg_done_i);
// 分配64KB RAM,编译器实际只用 64KB RAM
ram ram (
.clka (kickOff ? ram_clk : upg_clk_i),
.wea (kickOff ? ram_wen_i : upg_wen_i),
.addra (kickOff ? ram_adr_i : upg_adr_i),
.dina (kickOff ? ram_dat_i : upg_dat_i),
.douta (ram_dat_o)
);
endmodule
2.仿真文件
`timescale 1ns / 1ps
module ram_sim ();
// input
reg[31:0] address = 32'h00000010; //来自memorio模块,源头是来自执行单元算出的alu_result
reg[31:0] write_data = 32'ha0000000; //来自译码单元的read_data2
reg Memwrite = 1'b0; //来自控制单元
reg clock = 1'b0;
reg zero =1'b0;
reg[31:0] zero32= 32'h00000000;
reg one = 1'b1;
// output
wire[31:0] read_data;
dmemory32 Uram (
.ram_clk_i (clock),
.ram_wen_i (Memwrite), // 来自控制单元
.ram_adr_i (address[15:2]),
// 来自memorio模块,源头是来自执行单元算出的alu_result
.ram_dat_i (write_data), // 来自译码单元的read_data2
.ram_dat_o (read_data), // 从存储器中获得的数据
// UART Programmer Pinouts
.upg_rst_i (zero), // UPG reset (Active High)
.upg_clk_i (zero), // UPG ram_clk_i (10MHz)
.upg_wen_i (zero), // UPG write enable
.upg_adr_i (zero32), // UPG write address
.upg_dat_i (zero32), // UPG write data
.upg_done_i (one) // 1 if programming is finished
);
initial begin
#200 begin write_data = 32'hA00000F5;Memwrite = 1'b1; end
#200 Memwrite = 1'b0;
end
always #50 clock = ~clock;
endmodule
六、时序仿真结果及分析和硬件测试结果及分析
1.程序仿真图:
2.管脚分配图: