存儲器實驗--FPGA中RAM讀寫實驗
- 一. 實驗目的
- 二. 實驗裝置及環境
- 三. 實驗任務
- 四. 實驗步驟
一. 實驗目的
1、了解FPGA中RAM子產品ram的功能
2、掌握RAM的參數設定和使用方法
3、掌握RAM作為随機存儲器RAM的工作特性和讀寫方法
二. 實驗裝置及環境
三. 實驗任務
- 學習存儲器的設計及原理,了解RAM 讀寫時序,同步和異步的差別。
- 學習 ISE工具中調用庫 IP 的方法,通過調用xilinx庫IP執行個體化一塊RAM,執行個體化的 RAM 選擇為同步RAM。
- 本次實驗的 RAM 建議設定為兩個端口, 一個端口用來正常的讀寫, 另一個端口作為調試端口,隻使用讀功能用于觀察存儲器内部資料。
- 将以上設計作為一個單獨的子產品,通過編寫代碼設計一個外圍子產品去調用該子產品。外圍子產品中需調用封裝好的 LCD 觸摸屏子產品,顯示RAM的正常端口的位址、待寫入的資料和讀出的資料,顯示調試端口的位址和讀出的資料,并需要利用觸摸功能輸入正常端口的位址和寫資料,以及調試端口的位址。
- 對代碼進行綜合布局布線下載下傳到實驗箱裡 FPGA 闆上,進行上闆驗證。
四. 實驗步驟
data_ram_display.v檔案内容如下:
`timescale 1ns / 1ps
//*************************************************************************
// > 檔案名: data_ram_display.v
// > 描述 :資料存儲器子產品顯示子產品,調用FPGA闆上的IO接口和觸摸屏
// > 作者 : LOONGSON
// > 日期 : 2016-04-14
//*************************************************************************
module data_ram_display(
//時鐘與複位信号
input clk,
input resetn, //字尾"n"代表低電平有效
//撥碼開關,用于産生寫使能和選擇輸入數
input [3:0] wen,
input [1:0] input_sel,
//led燈,用于訓示寫使能信号,和正在輸入什麼資料
output [3:0] led_wen,
output led_addr, //訓示輸入讀寫位址
output led_wdata, //訓示輸入寫資料
output led_test_addr, //訓示輸入test位址
//觸摸屏相關接口,不需要更改
output lcd_rst,
output lcd_cs,
output lcd_rs,
output lcd_wr,
output lcd_rd,
inout[15:0] lcd_data_io,
output lcd_bl_ctr,
inout ct_int,
inout ct_sda,
output ct_scl,
output ct_rstn
);
//-----{LED顯示}begin
assign led_wen = wen;
assign led_addr = (input_sel==2'd0);
assign led_wdata = (input_sel==2'd1);
assign led_test_addr = (input_sel==2'd2);
//-----{LED顯示}end
//-----{調用資料儲存器子產品}begin
//資料存儲器多增加一個讀端口,用于讀出特定記憶體位址顯示在觸摸屏上
reg [31:0] addr;
reg [31:0] wdata;
wire [31:0] rdata;
reg [31:0] test_addr;
wire [31:0] test_data;
data_ram data_ram_module(
.clka (clk ),
.wea (wen ),
.addra (addr[9:2] ),
.dina (wdata ),
.douta (rdata ),
.clkb (clk ),
.web (4'd0 ),
.addrb (test_addr[9:2]),
.doutb (test_data ),
.dinb (32'd0 )
);
//-----{調用寄存器堆子產品}end
//---------------------{調用觸摸屏子產品}begin--------------------//
//-----{執行個體化觸摸屏}begin
//此小節不需要更改
reg display_valid;
reg [39:0] display_name;
reg [31:0] display_value;
wire [5 :0] display_number;
wire input_valid;
wire [31:0] input_value;
lcd_module lcd_module(
.clk (clk ), //10Mhz
.resetn (resetn ),
//調用觸摸屏的接口
.display_valid (display_valid ),
.display_name (display_name ),
.display_value (display_value ),
.display_number (display_number),
.input_valid (input_valid ),
.input_value (input_value ),
//lcd觸摸屏相關接口,不需要更改
.lcd_rst (lcd_rst ),
.lcd_cs (lcd_cs ),
.lcd_rs (lcd_rs ),
.lcd_wr (lcd_wr ),
.lcd_rd (lcd_rd ),
.lcd_data_io (lcd_data_io ),
.lcd_bl_ctr (lcd_bl_ctr ),
.ct_int (ct_int ),
.ct_sda (ct_sda ),
.ct_scl (ct_scl ),
.ct_rstn (ct_rstn )
);
//-----{執行個體化觸摸屏}end
//-----{從觸摸屏擷取輸入}begin
//根據實際需要輸入的數修改此小節,
//建議對每一個數的輸入,編寫單獨一個always塊
//當input_sel為2'b00時,表示輸入數為讀寫位址,即addr
always @(posedge clk)
begin
if (!resetn)
begin
addr <= 32'd0;
end
else if (input_valid && input_sel==2'd0)
begin
addr[31:2] <= input_value[31:2];
end
end
//當input_sel為2'b01時,表示輸入數為寫資料,即wdata
always @(posedge clk)
begin
if (!resetn)
begin
wdata <= 32'd0;
end
else if (input_valid && input_sel==2'd1)
begin
wdata <= input_value;
end
end
//當input_sel為2'b10時,表示輸入數為test位址,即test_addr
always @(posedge clk)
begin
if (!resetn)
begin
test_addr <= 32'd0;
end
else if (input_valid && input_sel==2'd2)
begin
test_addr[31:2] <= input_value[31:2];
end
end
//-----{從觸摸屏擷取輸入}end
//-----{輸出到觸摸屏顯示}begin
//根據需要顯示的數修改此小節,
//觸摸屏上共有44塊顯示區域,可顯示44組32位資料
//44塊顯示區域從1開始編号,編号為1~44,
always @(posedge clk)
begin
case(display_number)
6'd1:
begin
display_valid <= 1'b1;
display_name <= "ADDR ";
display_value <= addr;
end
6'd2:
begin
display_valid <= 1'b1;
display_name <= "WDATA";
display_value <= wdata;
end
6'd3:
begin
display_valid <= 1'b1;
display_name <= "RDATA";
display_value <= rdata;
end
6'd5:
begin
display_valid <= 1'b1;
display_name <= "T_ADD";
display_value <= test_addr;
end
6'd6:
begin
display_valid <= 1'b1;
display_name <= "T_DAT";
display_value <= test_data;
end
default :
begin
display_valid <= 1'b0;
display_name <= 40'd0;
display_value <= 32'd0;
end
endcase
end
//-----{輸出到觸摸屏顯示}end
//----------------------{調用觸摸屏子產品}end---------------------//
data_ram_tb.v檔案内容如下:
`timescale 1ns / 1ps //仿真機關時間為1ns,精度為1ps
module data_ram_tb;
// Inputs
// reg en;
reg [31:0] addr;
reg clk;
reg [31:0] test_addr;
reg [31:0] wdata;
reg [3:0] wen;
//output
wire [31:0] rdata;
wire [31:0] test_data;
//wire cout;
//Instantiate the Unit Under Test(UUT)
data_ram uut(
.clka (clk ),
.wea (wen ),
.addra (addr[6:2] ),
.dina (wdata ),
.douta (rdata ),
.clkb (clk ),
.web (4'd0 ),
.addrb (test_addr[6:2]),
.doutb (test_data ),
.dinb (32'd0 )
);
initial begin
// Initialize Inputs
// en=1;
addr=0;
clk=0;
//Wait 100ns for global reset to finish
#100;
//Add stimulus here
end
//always #10 operand1=$random;//$random為系統任務,産生一個随機的32位數
always #10 addr=$random; //#10表示等待10個機關時間(10ns),即每過10ns,指派一個随機的32位數
always #10 clk= {$random}%2; //加了拼接符,{$random}産生一個非負數,除2取餘得到0或1
// always #10 en= {$random}%2;