天天看点

计算机组成原理实验报告 存储器实验--FPGA中RAM读写实验

存储器实验--FPGA中RAM读写实验

  • ​​一. 实验目的​​
  • ​​二. 实验设备及环境​​
  • ​​三. 实验任务​​
  • ​​四. 实验步骤​​

一. 实验目的

1、了解FPGA中RAM模块ram的功能

2、掌握RAM的参数设置和使用方法

3、掌握RAM作为随机存储器RAM的工作特性和读写方法

二. 实验设备及环境

三. 实验任务

  1. 学习存储器的设计及原理,理解RAM 读写时序,同步和异步的区别。
  2. 学习 ISE工具中调用库 IP 的方法,通过调用xilinx库IP实例化一块RAM,实例化的 RAM 选择为同步RAM。
  3. 本次实验的 RAM 建议设置为两个端口, 一个端口用来正常的读写, 另一个端口作为调试端口,只使用读功能用于观察存储器内部数据。
  4. 将以上设计作为一个单独的模块,通过编写代码设计一个外围模块去调用该模块。外围模块中需调用封装好的 LCD 触摸屏模块,显示RAM的正常端口的地址、待写入的数据和读出的数据,显示调试端口的地址和读出的数据,并需要利用触摸功能输入正常端口的地址和写数据,以及调试端口的地址。
  5. 对代码进行综合布局布线下载到实验箱里 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;