天天看點

計算機組成原理實驗報告 存儲器實驗--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;