/* * memtest.v * * vim: ts=4 sw=4 * * Copyright (C) 2020-2021 Sylvain Munaut * SPDX-License-Identifier: CERN-OHL-P-2.0 */ `default_nettype none module memtest #( parameter integer ADDR_WIDTH = 32, // auto parameter integer AL = ADDR_WIDTH - 1 )( // Memory interface output wire [AL:0] mi_addr, output wire [ 6:0] mi_len, output wire mi_rw, output wire mi_valid, input wire mi_ready, output wire [31:0] mi_wdata, output wire [ 3:0] mi_wmsk, input wire mi_wack, input wire [31:0] mi_rdata, input wire mi_rstb, // Wishbone interface input wire [31:0] wb_wdata, output wire [31:0] wb_rdata, input wire [ 8:0] wb_addr, input wire wb_we, input wire wb_cyc, output wire wb_ack, // Clock / Reset input wire clk, input wire rst ); // Signals // ------- // Buffers wire [ 7:0] bw_waddr; wire [31:0] bw_wdata; wire bw_wren; reg [ 7:0] bw_raddr; wire [31:0] bw_rdata; wire bw_rden; reg [ 7:0] br_waddr; wire [31:0] br_wdata; wire br_wren; wire [ 7:0] br_raddr; wire [31:0] br_rdata; wire br_rden; // Wishbone reg wb_ack_i; reg wb_we_cmd; reg wb_we_addr; // Commands reg cmd_valid; reg cmd_start; reg cmd_read; reg [ 6:0] cmd_len; reg [AL:0] cmd_addr; reg cmd_dual; // Validate reg val_ok; // Buffers // ------- ram_sdp #( .AWIDTH(8), .DWIDTH(32) ) buf_wr_I ( .wr_addr (bw_waddr), .wr_data (bw_wdata), .wr_ena (bw_wren), .rd_addr (bw_raddr), .rd_data (bw_rdata), .rd_ena (bw_rden), .clk (clk) ); ram_sdp #( .AWIDTH(8), .DWIDTH(32) ) buf_rd_I ( .wr_addr (br_waddr), .wr_data (br_wdata), .wr_ena (br_wren), .rd_addr (br_raddr), .rd_data (br_rdata), .rd_ena (br_rden), .clk (clk) ); // Wishbone interface // ------------------ // Ack always @(posedge clk) wb_ack_i <= wb_cyc & ~wb_ack_i; assign wb_ack = wb_ack_i; // Read Mux assign wb_rdata = wb_ack_i ? (wb_addr[8] ? br_rdata : { 30'h00000000, val_ok, mi_ready }) : 32'h00000000; // Buffer accesses assign bw_waddr = wb_addr[7:0]; assign bw_wdata = wb_wdata; assign bw_wren = wb_ack_i & wb_we & wb_addr[8]; assign br_raddr = wb_addr[7:0]; assign br_rden = 1'b1; // Write Strobes always @(posedge clk) if (wb_ack_i) begin wb_we_cmd <= 1'b0; wb_we_addr <= 1'b0; end else begin wb_we_cmd <= wb_cyc & wb_we & ~wb_addr[8] & ~wb_addr[0]; wb_we_addr <= wb_cyc & wb_we & ~wb_addr[8] & wb_addr[0]; end always @(posedge clk) cmd_start <= wb_we_cmd; always @(posedge clk) if (rst) cmd_valid <= 1'b0; else cmd_valid <= (cmd_valid & (~mi_ready | cmd_dual)) | cmd_start; always @(posedge clk) if (wb_we_cmd) cmd_dual <= wb_wdata[18]; else if (mi_ready & mi_valid) cmd_dual <= 1'b0; always @(posedge clk) if (wb_we_cmd) begin cmd_read <= wb_wdata[ 16]; cmd_len <= wb_wdata[ 6: 0]; end always @(posedge clk) if (wb_we_addr) cmd_addr <= wb_wdata[ADDR_WIDTH-1:0]; else if (mi_ready & mi_valid) cmd_addr <= cmd_addr + cmd_len + 1; // Memory interface // ---------------- // Requests assign mi_addr = cmd_addr; assign mi_len = cmd_len; assign mi_rw = cmd_read; assign mi_valid = cmd_valid; // Write data (and read-validate) always @(posedge clk) if (wb_we_cmd) bw_raddr <= wb_wdata[15:8]; else bw_raddr <= bw_raddr + bw_rden; assign mi_wdata = bw_rdata; assign mi_wmsk = 4'h0; assign bw_rden = (cmd_read ? mi_rstb : mi_wack) | cmd_start; // Read data assign br_wdata = mi_rdata; assign br_wren = mi_rstb; always @(posedge clk) if (wb_we_cmd) br_waddr <= wb_wdata[15:8]; else br_waddr <= br_waddr + mi_rstb; // Data validation always @(posedge clk) if (wb_we_cmd) val_ok <= val_ok | wb_wdata[17]; else val_ok <= val_ok & (~mi_rstb | (mi_rdata == bw_rdata)); endmodule