diff options
| -rw-r--r-- | atk16_fpga/sram.v | 60 | ||||
| -rw-r--r-- | atk16_fpga/sram_tb.gtkw | 56 | ||||
| -rw-r--r-- | atk16_fpga/sram_tb.v | 94 |
3 files changed, 210 insertions, 0 deletions
diff --git a/atk16_fpga/sram.v b/atk16_fpga/sram.v new file mode 100644 index 0000000..c1ccb86 --- /dev/null +++ b/atk16_fpga/sram.v @@ -0,0 +1,60 @@ +`default_nettype none +`timescale 1 ns / 100 ps + +// This is a memory model of the SRAM chip on the iCE40HX8K-EVB. +// Relevant specs: +// - 256Kx16 capacity +// - 18-bit address bus, 16-bit data bus +// - 10 ns read or write cycle time +// - 3 ns output hold from address change +module sram( + input wire cs_n, + input wire wr_n, + input wire rd_n, + input wire [17:0] addr, + input wire [15:0] data_in, + output reg [15:0] data_out +); + + reg [15:0] mem [0:262143]; // 256K x 16 memory + reg [17:0] last_addr = -1; + reg [15:0] last_data_in = -1; + reg last_wr_n, last_rd_n, last_cs_n = 0; + reg trigger = 0; + + always @(posedge trigger) begin + if (cs_n == 1'b0) begin + if (wr_n == 1'b0) begin + mem[addr] = 16'hx; + //$display("wrote %04h at time %0d ns", mem[addr], $time); + #7 mem[addr] = data_in; + //$display("wrote %04h at time %0d ns", mem[addr], $time); + end + if (rd_n == 1'b0) begin + data_out = 16'hx; + //$display("read %04h at time %0d ns", data_out, $time); + #7 data_out = mem[addr]; + //$display("read %04h at time %0d ns", data_out, $time); + end + end + end + + always @(*) begin + if (addr != last_addr || + data_in != last_data_in || + wr_n != last_wr_n || + rd_n != last_rd_n || + cs_n != last_cs_n + ) begin + //$display("SRAM: addr=%h data_in=%h", addr, data_in); + last_addr = addr; + last_data_in = data_in; + last_wr_n = wr_n; + last_rd_n = rd_n; + last_cs_n = cs_n; + trigger = 0; + #3 trigger = 1; + end + end + +endmodule diff --git a/atk16_fpga/sram_tb.gtkw b/atk16_fpga/sram_tb.gtkw new file mode 100644 index 0000000..2b61ccd --- /dev/null +++ b/atk16_fpga/sram_tb.gtkw @@ -0,0 +1,56 @@ +[*] +[*] GTKWave Analyzer v3.4.0 (w)1999-2022 BSI +[*] Sun Dec 29 21:48:27 2024 +[*] +[dumpfile] "/Users/jantuomi/Projects/Personal/ATK16/atk16_fpga/sram_tb.vcd" +[dumpfile_mtime] "Sun Dec 29 21:48:18 2024" +[dumpfile_size] 1502 +[savefile] "/Users/jantuomi/Projects/Personal/ATK16/atk16_fpga/sram_tb.gtkw" +[timestart] 0 +[size] 1280 600 +[pos] -1 -1 +*-15.091954 14300 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +[markername] AA +[markername] BB +[markername] CC +[markername] DD +[markername] EE +[markername] FF +[markername] GG +[markername] HH +[markername] II +[markername] JJ +[markername] KK +[markername] LL +[markername] MM +[markername] NN +[markername] OO +[markername] PP +[markername] QQ +[markername] RR +[markername] SS +[markername] TT +[markername] UU +[markername] VV +[markername] WW +[markername] XX +[markername] YY +[markername] ZZ +[treeopen] sram_tb. +[sst_width] 240 +[signals_width] 177 +[sst_expanded] 1 +[sst_vpaned_height] 159 +@28 +sram_tb.dut.cs_n +sram_tb.dut.rd_n +sram_tb.dut.wr_n +@22 +sram_tb.dut.last_addr[17:0] +sram_tb.dut.addr[17:0] +sram_tb.dut.data_in[15:0] +sram_tb.dut.data_out[15:0] +@23 +sram_tb.debug_mem100[15:0] +[pattern_trace] 1 +[pattern_trace] 0 diff --git a/atk16_fpga/sram_tb.v b/atk16_fpga/sram_tb.v new file mode 100644 index 0000000..c734395 --- /dev/null +++ b/atk16_fpga/sram_tb.v @@ -0,0 +1,94 @@ +`default_nettype none +`define DUMPSTR(x) `"x.vcd`" +`timescale 1 ns / 100 ps + +module sram_tb(); + + reg clk, cs_n, wr_n, rd_n; + reg [17:0] addr; + reg [15:0] data_in; + wire [15:0] data_out; + + sram dut( + .cs_n(cs_n), + .wr_n(wr_n), + .rd_n(rd_n), + .addr(addr), + .data_in(data_in), + .data_out(data_out) + ); + + wire [15:0] debug_mem100; + assign debug_mem100 = dut.mem[100]; + + reg failed; + initial begin + failed = 0; + $dumpfile(`DUMPSTR(`VCD_OUTPUT)); + $dumpvars(0, sram_tb); + + cs_n = 1; + wr_n = 1; + rd_n = 1; + addr = 18'd0; + data_in = 16'h0; + #10 + + // test write + cs_n = 0; + wr_n = 0; + addr = 18'd100; + data_in = 16'h1234; + + #5 + if (debug_mem100 === 16'hx) begin + $display("\033[0;32m[PASS]\033[0m Write: data is invalid at time: %0d ns", $time); + end else begin + $display("\033[0;31m[FAIL]\033[0m Write: data is valid too early, got %04h at time %0d ns", debug_mem100, $time); + failed = 1; + end + + #5 + if (debug_mem100 == 16'h1234) begin + $display("\033[0;32m[PASS]\033[0m Write: data is written as expected"); + end else begin + $display("\033[0;31m[FAIL]\033[0m Write: data is %04h (expected 1234)", debug_mem100); + failed = 1; + end + + cs_n = 1; + wr_n = 1; + #100; + + // test read + cs_n = 0; + rd_n = 0; + addr = 18'd100; + + #5 + if (data_out === 16'hx) begin + $display("\033[0;32m[PASS]\033[0m Read: data is invalid at time: %0d ns", $time); + end else begin + $display("\033[0;31m[FAIL]\033[0m Read: data is valid too early, got %04h at time %0d ns", data_out, $time); + failed = 1; + end + + #5 + if (data_out == 16'h1234) begin + $display("\033[0;32m[PASS]\033[0m Read: data is available as expected"); + end else begin + $display("\033[0;31m[FAIL]\033[0m Read: data is %04h (expected 1234)", data_out); + failed = 1; + end + + #100 + + if (!failed) begin + $display("\033[0;32m[PASS]\033[0m All tests passed"); + end else begin + $display("\033[0;31m[FAIL]\033[0m Some tests failed"); + end + $finish; + end + +endmodule |
