blob: 9b81a5fa7d3437c31ee9419243a52d20c1bc51f0 [file] [log] [blame]
// SPDX-License-Identifier: MIT
// SPDX-FileCopyrightText: 2021 Tamas Hubai
`default_nettype none
module mem_mesh_tb();
parameter CORES = 8;
parameter DEPTH = 256;
parameter DATA_WIDTH = 16;
parameter ADDR_WIDTH = 8;
parameter SPREAD_LAYERS = 3;
parameter SPREAD_WIDTH = 3;
parameter USE_IO = 1;
parameter IO_PORTS = 16;
parameter IO_FIRST = 5;
reg clk;
reg rst_n;
reg we[CORES-1:0];
reg [ADDR_WIDTH-1:0] waddr[CORES-1:0];
reg [SPREAD_WIDTH-1:0] wspread[CORES-1:0];
reg [DATA_WIDTH-1:0] wdata[CORES-1:0];
reg [ADDR_WIDTH-1:0] raddr[CORES-1:0];
wire [DATA_WIDTH-1:0] rdata[CORES-1:0];
// io directions are according to the cpu & memory, so they are
// reversed from the point of view of the testbench / external world
reg io_dir[IO_PORTS-1:0];
reg io_receiving[IO_PORTS-1:0];
wire io_sending[IO_PORTS-1:0];
reg [DATA_WIDTH-1:0] io_input[IO_PORTS-1:0];
wire [DATA_WIDTH-1:0] io_output[IO_PORTS-1:0];
wire [CORES-1:0] we_raw;
wire [CORES*ADDR_WIDTH-1:0] waddr_raw;
wire [CORES*SPREAD_WIDTH-1:0] wspread_raw;
wire [CORES*DATA_WIDTH-1:0] wdata_raw;
wire [CORES*ADDR_WIDTH-1:0] raddr_raw;
wire [CORES*DATA_WIDTH-1:0] rdata_raw;
wire [IO_PORTS-1:0] io_active_in_raw;
wire [IO_PORTS-1:0] io_active_out_raw;
wire [IO_PORTS*DATA_WIDTH-1:0] io_data_in_raw;
wire [IO_PORTS*DATA_WIDTH-1:0] io_data_out_raw;
generate genvar core;
for (core=0; core<CORES; core=core+1) begin:g_core
assign we_raw[core] = we[core];
assign waddr_raw[core*ADDR_WIDTH +: ADDR_WIDTH] = waddr[core];
assign wspread_raw[core*SPREAD_WIDTH +: SPREAD_WIDTH] = wspread[core];
assign wdata_raw[core*DATA_WIDTH +: DATA_WIDTH] = wdata[core];
assign raddr_raw[core*ADDR_WIDTH +: ADDR_WIDTH] = raddr[core];
assign rdata[core] = rdata_raw[core*DATA_WIDTH +: DATA_WIDTH];
end
endgenerate
generate genvar port;
for (port=0; port<IO_PORTS; port=port+1) begin:g_port
assign io_active_in_raw[port] = io_dir[port] ? 1'b0 : io_receiving[port];
assign io_sending[port] = io_dir[port] ? io_active_out_raw[port] : 1'b0;
assign io_data_in_raw[port*DATA_WIDTH +: DATA_WIDTH] = io_dir[port] ? {(DATA_WIDTH){1'b0}} : io_input[port];
assign io_output[port] = io_dir[port] ? io_data_out_raw[port*DATA_WIDTH +: DATA_WIDTH] : {(DATA_WIDTH){1'b0}};
end
endgenerate
mem_mesh #(
.CORES(CORES),
.DEPTH(DEPTH),
.DATA_WIDTH(DATA_WIDTH),
.ADDR_WIDTH(ADDR_WIDTH),
.SPREAD_LAYERS(SPREAD_LAYERS),
.SPREAD_WIDTH(SPREAD_WIDTH),
.USE_IO(USE_IO),
.IO_PORTS(IO_PORTS),
.IO_FIRST(IO_FIRST)
) mem_mesh_dut (
.clk(clk),
.rst_n(rst_n),
.we(we_raw),
.waddr(waddr_raw),
.wspread(wspread_raw),
.wdata(wdata_raw),
.raddr(raddr_raw),
.rdata(rdata_raw),
.io_active_in(io_active_in_raw),
.io_active_out(io_active_out_raw),
.io_data_in(io_data_in_raw),
.io_data_out(io_data_out_raw)
);
always #5 clk = ~clk;
integer i;
// for synchronization checking
reg io_sending_reg[IO_PORTS-1:0];
reg [DATA_WIDTH-1:0] io_output_reg[IO_PORTS-1:0];
always @(posedge clk) begin
for (i=0; i<IO_PORTS; i=i+1) begin
io_sending_reg[i] <= io_sending[i];
io_output_reg[i] <= io_output[i];
end
end
initial begin
raddr[2] = 8;
raddr[3] = 8;
raddr[6] = 8;
raddr[7] = 192;
wspread[2] = 0;
io_input[3] = 0;
$monitor("time=%t mem[2][8]=%d mem[3][8]=%d mem[6][8]=%d mem[7][192]=%d io_dir[3]=%d io_sending[3]=%d io_out[3]=%d",
$time, rdata[2], rdata[3], rdata[6], rdata[7], io_dir[3], io_sending_reg[3], io_output_reg[3]);
for (i=0; i<CORES; i=i+1) begin
we[i] = 0;
end
for (i=0; i<IO_PORTS; i=i+1) begin
io_dir[i] = 1;
end
clk = 0;
rst_n = 1;
#10 rst_n = 0;
#10 rst_n = 1;
#20
we[2] = 1;
waddr[2] = 8;
wspread[2] = 0;
wdata[2] = 100;
#20
waddr[2] = 8;
wspread[2] = 1;
wdata[2] = 200;
#20
waddr[2] = 8;
wspread[2] = 2;
wdata[2] = 300;
#20
waddr[2] = 8;
wspread[2] = 3;
wdata[2] = 400;
#20
waddr[2] = 8;
wspread[2] = 4;
wdata[2] = 500;
#20
io_dir[3] = 0;
io_receiving[3] = 0;
#20
io_receiving[3] = 1;
io_input[3] = 1234;
#20 $stop;
end
endmodule
`default_nettype wire