Files
FPGA-Neural/sim/memory_interface_tb.v
T
micheleandClaude Sonnet 5 7e2711fa27 feat: widen ADDR_WIDTH to 23 bits for full 8MB PSRAM addressing
Bumps ADDR_WIDTH's default from 22 to 23 bits across every RTL
module (neuron_memory, layer_sequencer, spi_engine, spi_neuron_top,
mem_arbiter, int8_memory_access, memory_interface, psram_controller,
memory_model) and every testbench that mirrors it, so the system's
byte-address space reaches the full 8 MiB the recommended PSRAM part
(ISSI IS66WVE4M16EBLL-70BLI, docs/FPGA-Neural-Hardware-Design.md §3)
actually provides -- previously only 4 MiB (half the chip) was
reachable, since int8_memory_access.v's byte->word address shift
(addr >> 1) turned the old 22-bit byte address into only 21 real word
bits, one short of the chip's real 22-bit word address (A0-A21). At
23 bits, that same shift lands exactly on all 22 chip address lines,
so the whole part is usable now instead of deferred to a future
widening.

Also fixes a stray 22'd11-sized literal in layer_sequencer.v's
descriptor-table address increment (numerically already safe via
Verilog's zero-extension, but now correctly unsized so it always
matches ADDR_WIDTH instead of silently assuming 22).

Updated docs/FPGA-NeuralNetwork-Engine.md's SPI protocol address-field
note (23 bits, top 1 reserved bit instead of 2) and
docs/FPGA-Neural-Hardware-Design.md's PSRAM section (the "chip has
one spare address line" framing is gone now that all 22 are wired
and used).

Full regression (all 11 ADDR_WIDTH-touching testbenches, plus a
Yosys elaboration check of spi_neuron_top with the new default and
no override) passes clean.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WQV3vS9TXaGDJ5cRfnfidt
2026-09-02 21:00:46 +02:00

319 lines
7.0 KiB
Verilog

`timescale 1ns/1ps
module memory_interface_tb;
parameter ADDR_WIDTH = 23;
parameter DATA_WIDTH = 16;
reg clk;
reg rst;
// Host side
reg req;
reg wr;
reg [ADDR_WIDTH-1:0] addr;
reg [DATA_WIDTH-1:0] wdata;
wire [DATA_WIDTH-1:0] rdata;
wire ready;
// Memory side
wire mem_req;
wire mem_wr;
wire [ADDR_WIDTH-1:0] mem_addr;
wire [DATA_WIDTH-1:0] mem_wdata;
wire [DATA_WIDTH-1:0] mem_rdata;
wire mem_ready;
// ------------------------------------------------------------
// Clock
// ------------------------------------------------------------
initial begin
clk = 1'b0;
forever #5 clk = ~clk;
end
// ------------------------------------------------------------
// DUT: Memory Interface
// ------------------------------------------------------------
memory_interface #(
.ADDR_WIDTH(ADDR_WIDTH),
.DATA_WIDTH(DATA_WIDTH)
) dut (
.clk(clk),
.rst(rst),
.req(req),
.wr(wr),
.addr(addr),
.wdata(wdata),
.rdata(rdata),
.ready(ready),
.mem_req(mem_req),
.mem_wr(mem_wr),
.mem_addr(mem_addr),
.mem_wdata(mem_wdata),
.mem_rdata(mem_rdata),
.mem_ready(mem_ready)
);
// ------------------------------------------------------------
// Memory model
// ------------------------------------------------------------
memory_model #(
.ADDR_WIDTH(ADDR_WIDTH),
.DATA_WIDTH(DATA_WIDTH),
.DEPTH(4096),
.READ_LATENCY(2)
) memory (
.clk(clk),
.rst(rst),
.req(mem_req),
.wr(mem_wr),
.addr(mem_addr),
.wdata(mem_wdata),
.rdata(mem_rdata),
.ready(mem_ready)
);
// ------------------------------------------------------------
// Test utilities
// ------------------------------------------------------------
task write_mem;
input [ADDR_WIDTH-1:0] address;
input [DATA_WIDTH-1:0] data;
begin
@(posedge clk);
addr <= address;
wdata <= data;
wr <= 1'b1;
req <= 1'b1;
@(posedge clk);
req <= 1'b0;
wait (ready);
@(posedge clk);
$display(
"WRITE addr=0x%08h data=0x%04h PASS",
address,
data
);
end
endtask
task read_mem;
input [ADDR_WIDTH-1:0] address;
input [DATA_WIDTH-1:0] expected;
reg [DATA_WIDTH-1:0] received;
begin
@(posedge clk);
addr <= address;
wr <= 1'b0;
req <= 1'b1;
@(posedge clk);
req <= 1'b0;
wait (ready);
received = rdata;
@(posedge clk);
if (received === expected) begin
$display(
"READ addr=0x%08h data=0x%04h PASS",
address,
received
);
end else begin
$display(
"READ addr=0x%08h got=0x%04h expected=0x%04h FAIL",
address,
received,
expected
);
$fatal;
end
end
endtask
// ------------------------------------------------------------
// Test sequence
// ------------------------------------------------------------
initial begin
// Defaults
rst = 1'b1;
req = 1'b0;
wr = 1'b0;
addr = {ADDR_WIDTH{1'b0}};
wdata = {DATA_WIDTH{1'b0}};
// Reset
repeat (3)
@(posedge clk);
rst = 1'b0;
$display("");
$display("========================================");
$display("MEMORY INTERFACE V1 TEST");
$display("ADDR_WIDTH = %0d", ADDR_WIDTH);
$display("DATA_WIDTH = %0d", DATA_WIDTH);
$display("========================================");
$display("");
// --------------------------------------------------------
// Test 1
// --------------------------------------------------------
write_mem(
22'h000001,
16'h1234
);
read_mem(
22'h000001,
16'h1234
);
// --------------------------------------------------------
// Test 2
// --------------------------------------------------------
write_mem(
22'h000010,
16'hABCD
);
read_mem(
22'h000010,
16'hABCD
);
// --------------------------------------------------------
// Test 3
// --------------------------------------------------------
write_mem(
22'h000100,
16'h55AA
);
read_mem(
22'h000100,
16'h55AA
);
// --------------------------------------------------------
// Test 4
// --------------------------------------------------------
// Consecutive different addresses
write_mem(
22'h000200,
16'h0001
);
write_mem(
22'h000201,
16'h0002
);
write_mem(
22'h000202,
16'h0003
);
read_mem(
22'h000200,
16'h0001
);
read_mem(
22'h000201,
16'h0002
);
read_mem(
22'h000202,
16'h0003
);
// --------------------------------------------------------
// Test 5
// --------------------------------------------------------
// Zero value
write_mem(
22'h000300,
16'h0000
);
read_mem(
22'h000300,
16'h0000
);
// --------------------------------------------------------
// Test 6
// --------------------------------------------------------
// Full 16-bit value
write_mem(
22'h000301,
16'hFFFF
);
read_mem(
22'h000301,
16'hFFFF
);
// --------------------------------------------------------
// Finished
// --------------------------------------------------------
$display("");
$display("========================================");
$display("MEMORY INTERFACE V1 TEST PASSED");
$display("========================================");
$display("");
$finish;
end
// ------------------------------------------------------------
// VCD
// ------------------------------------------------------------
initial begin
$dumpfile("sim/memory_interface.vcd");
$dumpvars(0, memory_interface_tb);
end
endmodule