aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--atk16_fpga/.gitignore3
-rw-r--r--atk16_fpga/alu_gtkw_translate_sel.txt8
-rw-r--r--atk16_fpga/alu_tb.gtkw54
-rw-r--r--atk16_fpga/alu_tb.v26
-rw-r--r--atk16_fpga/bram.v37
-rw-r--r--atk16_fpga/cu.v201
-rw-r--r--atk16_fpga/cu_tb.gtkw77
-rw-r--r--atk16_fpga/cu_tb.v77
-rw-r--r--atk16_fpga/mem_fsm.v67
-rw-r--r--atk16_fpga/mem_fsm_tb.gtkw32
-rw-r--r--atk16_fpga/mem_fsm_tb.v82
-rw-r--r--atk16_fpga/top.v18
12 files changed, 659 insertions, 23 deletions
diff --git a/atk16_fpga/.gitignore b/atk16_fpga/.gitignore
index 5b8789e..c09389c 100644
--- a/atk16_fpga/.gitignore
+++ b/atk16_fpga/.gitignore
@@ -1,6 +1,9 @@
*.dblite
*.out
*.vcd
+*.rpt
+*.svg
+*.dot
hardware.bin
hardware.json
hardware.asc
diff --git a/atk16_fpga/alu_gtkw_translate_sel.txt b/atk16_fpga/alu_gtkw_translate_sel.txt
new file mode 100644
index 0000000..ac71a28
--- /dev/null
+++ b/atk16_fpga/alu_gtkw_translate_sel.txt
@@ -0,0 +1,8 @@
+0 ADD
+1 MINUS
+2 AND
+3 OR
+4 XOR
+5 SHL
+6 SHR
+7 SAR
diff --git a/atk16_fpga/alu_tb.gtkw b/atk16_fpga/alu_tb.gtkw
new file mode 100644
index 0000000..0ef8322
--- /dev/null
+++ b/atk16_fpga/alu_tb.gtkw
@@ -0,0 +1,54 @@
+[*]
+[*] GTKWave Analyzer v3.4.0 (w)1999-2022 BSI
+[*] Tue Dec 24 12:08:19 2024
+[*]
+[dumpfile] "/Users/jantuomi/Projects/Personal/ATK16/atk16_fpga/alu_tb.vcd"
+[dumpfile_mtime] "Tue Dec 24 11:56:07 2024"
+[dumpfile_size] 1623
+[savefile] "/Users/jantuomi/Projects/Personal/ATK16/atk16_fpga/alu_tb.gtkw"
+[timestart] 0
+[size] 1280 600
+[pos] -1 -1
+*-17.259954 120300 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] alu_tb.
+[sst_width] 240
+[signals_width] 170
+[sst_expanded] 1
+[sst_vpaned_height] 159
+@2025
+^1 /Users/jantuomi/Projects/Personal/ATK16/atk16_fpga/alu_gtkw_translate_sel.txt
+alu_tb.dut.sel[2:0]
+@420
+alu_tb.dut.a[15:0]
+alu_tb.dut.b[15:0]
+alu_tb.dut.result[15:0]
+@28
+alu_tb.dut.flags[3:0]
+[pattern_trace] 1
+[pattern_trace] 0
diff --git a/atk16_fpga/alu_tb.v b/atk16_fpga/alu_tb.v
index 7569e2d..559e23b 100644
--- a/atk16_fpga/alu_tb.v
+++ b/atk16_fpga/alu_tb.v
@@ -11,11 +11,11 @@
`define SAR 3'd7
`define TESTCASE(ma, msel, mb, mexpected, mflags) \
- sel <= `msel; \
- a <= ma; \
- b <= mb; \
+ sel = `msel; \
+ a = ma; \
+ b = mb; \
#5 if (result != $unsigned(mexpected) || flags !== mflags) begin \
- failed <= 1; \
+ failed = 1; \
$write("\033[0;31m[FAIL]\033[0m "); \
$display("%d msel %0d = %0d, flags %04b", a, b, result, flags); \
$display("_ expected result %0d", $unsigned(mexpected)); \
@@ -44,20 +44,20 @@ module alu_tb();
reg failed;
initial begin
- failed <= 0;
+ failed = 0;
$dumpfile(`DUMPSTR(`VCD_OUTPUT));
$dumpvars(0, alu_tb);
- `TESTCASE(10, PLUS, 20, 30, 4'b0000)
- `TESTCASE(-1, PLUS, 1, 0, 4'b1001)
+ `TESTCASE(16'd10, PLUS, 16'd20, 16'd30, 4'b0000)
+ `TESTCASE(-16'd1, PLUS, 16'd1, 16'd0, 4'b1001)
`TESTCASE(16'h7fff, PLUS, 16'h7fff, 16'hfffe, 4'b0110)
- `TESTCASE(30, MINUS, 30, 0, 4'b0001)
- `TESTCASE(30, MINUS, 40, -16'd10, 4'b1010)
- `TESTCASE(16'h7fff, MINUS, 16'h7fff, 0, 4'b0001)
+ `TESTCASE(16'd30, MINUS, 16'd30, 16'd0, 4'b0001)
+ `TESTCASE(16'd30, MINUS, 16'd40, -16'd10, 4'b1010)
+ `TESTCASE(16'h7fff, MINUS, 16'h7fff, 16'd0, 4'b0001)
`TESTCASE(16'h8000, MINUS, 16'h1, 16'h7fff, 4'b0100)
- `TESTCASE(3'b110, AND, 3'b101, 3'b100, 4'b0000)
- `TESTCASE(3'b110, OR, 3'b101, 3'b111, 4'b0000)
- `TESTCASE(3'b110, XOR, 3'b101, 3'b011, 4'b0000)
+ `TESTCASE(16'b110, AND, 16'b101, 16'b100, 4'b0000)
+ `TESTCASE(16'b110, OR, 16'b101, 16'b111, 4'b0000)
+ `TESTCASE(16'b110, XOR, 16'b101, 16'b011, 4'b0000)
`TESTCASE(16'b110, SHL, 16'd3, 16'b110000, 4'b0000)
`TESTCASE(16'b1100_0000_0000_0000, SHR, 16'd3, 16'b0001_1000_0000_0000, 4'b0000)
`TESTCASE(16'b1100_0000_0000_0000, SAR, 16'd3, 16'b1111_1000_0000_0000, 4'b0010)
diff --git a/atk16_fpga/bram.v b/atk16_fpga/bram.v
new file mode 100644
index 0000000..c814c67
--- /dev/null
+++ b/atk16_fpga/bram.v
@@ -0,0 +1,37 @@
+`default_nettype none
+
+/*
+ * Copyright 2020 Brian O'Dell
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+module bram (
+ input clk,
+ input [15:0] addr,
+ input cs_n,
+ input wr_n,
+ input rd_n,
+ input [15:0] bram_data_in,
+ output reg [15:0] bram_data_out
+);
+
+ reg [15:0] mem [16'hEFFF:0];
+
+ always @(posedge clk)
+ if (cs_n == 1'b0) begin
+ if (wr_n == 1'b0) mem[addr] <= bram_data_in;
+ if (rd_n == 1'b0) bram_data_out <= mem[addr];
+ end
+ endmodule
diff --git a/atk16_fpga/cu.v b/atk16_fpga/cu.v
new file mode 100644
index 0000000..915ce8e
--- /dev/null
+++ b/atk16_fpga/cu.v
@@ -0,0 +1,201 @@
+`default_nettype none
+
+`define PH_RESET 3'd0
+`define PH_FETCH 3'd1
+`define PH_DECODE 3'd2
+`define PH_EXECUTE 3'd3
+
+`define FL_CARRY 2'd3
+`define FL_OVERFLOW 2'd2
+`define FL_NEGATIVE 2'd1
+`define FL_ZERO 2'd0
+
+// Legend:
+// T = target register select
+// L = left operand register select
+// R = right operand register select
+// I = immediate operand
+// S = ALU operation select
+// A = absolute (1) / relative (0) addressing
+// D = direct (1) / indirect (0) load
+// M = immediate mode (1) / register mode (0)
+
+// ALR (arithmetic-logic, register)
+// 0000 TTTL LLRR RSSS
+`define OP_ALR 4'b0000
+// ALI (arithmetic-logic, immediate)
+// 0001 TTTL LLII ISSS
+`define OP_ALI 4'b0001
+// LDR (load by register)
+// 0010 TTTR RRXX XXAD
+`define OP_LDR 4'b0010
+// STR (store to memory)
+// 0011 XXXL LLRR RMAD
+`define OP_STR 4'b0011
+// LDI (load by immediate)
+// 0100 TTTD IIII IIII
+`define OP_LDI 4'b0100
+
+module cu(
+ input wire clk,
+ input wire rst
+);
+ reg [2:0] alu_sel;
+ reg [15:0] alu_a;
+ reg [15:0] alu_b;
+ wire [15:0] alu_result;
+ wire [3:0] alu_flags;
+ reg [15:0] regbank [0:7];
+ reg [15:0] decoded_tmp;
+ reg [2:0] phase = `PH_RESET;
+ reg [15:0] pc;
+ reg [15:0] ir;
+
+ reg [15:0] mem_addr;
+ reg [15:0] mem_data_in;
+ reg mem_read_en, mem_write_en;
+ wire mem_done;
+ wire [15:0] mem_data_out;
+ mem_fsm mem_fsm_inst(
+ .clk(clk),
+ .addr(mem_addr),
+ .data_in(mem_data_in),
+ .read_en(mem_read_en),
+ .write_en(mem_write_en),
+ .data_out(mem_data_out),
+ .done(mem_done)
+ );
+
+ alu alu_inst(
+ .sel(alu_sel),
+ .a(alu_a),
+ .b(alu_b),
+ .result(alu_result),
+ .flags(alu_flags)
+ );
+
+ // Named reg wires for debugging purposes
+ wire [15:0] ra, rb, rc, rd, re, rf, rg, rh;
+ assign ra = regbank[0];
+ assign rb = regbank[1];
+ assign rc = regbank[2];
+ assign rd = regbank[3];
+ assign re = regbank[4];
+ assign rf = regbank[5];
+ assign rg = regbank[6];
+ assign rh = regbank[7];
+
+ integer i;
+ always @(posedge clk or posedge rst) begin
+ // Handle reset button
+ if (rst) begin
+ phase <= `PH_RESET;
+ end
+
+ else if (phase == `PH_RESET) begin
+ phase <= `PH_FETCH;
+
+ pc <= 16'd0;
+ mem_read_en <= 0;
+ mem_write_en <= 0;
+
+ for (i = 0; i < 8; i = i + 1) begin
+ regbank[i] <= 16'd0;
+ end
+ end
+
+ // Fetch stage
+ else if (phase == `PH_FETCH) begin
+ mem_read_en <= 1;
+ mem_write_en <= 0;
+ mem_addr <= pc;
+
+ if (mem_done) begin
+ mem_read_en <= 0;
+ mem_write_en <= 0;
+ ir <= mem_data_out;
+ phase <= `PH_DECODE;
+ pc <= pc + 16'd1;
+ end
+ end
+
+ // Decode stage
+ else if (phase == `PH_DECODE) begin
+ phase <= `PH_EXECUTE;
+
+ case (ir[15:12])
+ `OP_ALR: begin
+ alu_sel <= ir[2:0]; // select ALU operation
+ alu_a <= regbank[ir[8:6]]; // read operand A
+ alu_b <= regbank[ir[5:3]]; // read operand B
+ end
+ `OP_ALI: begin
+ alu_sel <= ir[2:0]; // select ALU operation
+ alu_a <= regbank[ir[8:6]]; // read operand A
+ alu_b <= ir[5:3]; // read immediate operand
+ end
+ `OP_LDR: begin
+ // set target reg value to address, dereference in execute phase
+ if (ir[1] == 1 && ir[0] == 1) // addressing mode: absolute, direct
+ decoded_tmp <= regbank[ir[8:6]];
+ else if (ir[1] == 0 && ir[0] == 1) // addressing mode: pc relative, direct
+ decoded_tmp <= regbank[ir[8:6]] + pc - 1;
+ /*else if (ir[1] == 1 && ir[0] == 0) begin // addressing mode: absolute, indirect
+ bram_wr <= 0;
+ bram_rd <= 1;
+ bram_addr <= regbank[ir[8:6]];
+ decoded_tmp <= bram_data_out;
+ end
+ else if (ir[1] == 0 && ir[0] == 0) begin // addressing mode: pc relative, indirect
+ bram_wr <= 0;
+ bram_rd <= 1;
+ bram_addr <= regbank[ir[8:6]] + pc - 1;
+ decoded_tmp <= bram_data_out;
+ end*/
+ end
+ `OP_STR: begin
+ // ir[2] = M = immediate mode (1) / register mode (0)
+ // ir[1] = A = absolute (1) / relative (0) addressing
+ // ir[0] = D = direct (1) / indirect (0) load
+ // TODO
+ end
+ default: begin
+ `ifdef __SYNTHESIS__
+ $fatal(1, "decode: unhandled opcode %04b", ir[15:12]);
+ `endif
+ end
+ endcase
+ end
+
+ // Execute stage
+ else if (phase == `PH_EXECUTE) begin
+ case (ir[15:12])
+ `OP_ALR, `OP_ALI: begin
+ regbank[ir[11:9]] <= alu_result; // write result
+ phase <= `PH_FETCH;
+ end
+ `OP_LDR: begin
+ //$display("ir[11:9] %d, reg val: %d, mem_data_out: %d, mem_done: %d\n", ir[11:9], regbank[ir[11:9]], mem_data_out, mem_done);
+ mem_read_en <= 1;
+ mem_write_en <= 0;
+ mem_addr <= decoded_tmp;
+
+ if (mem_done) begin
+ regbank[ir[11:9]] <= mem_data_out; // dereference address
+ mem_read_en <= 0;
+ mem_write_en <= 0;
+ phase <= `PH_FETCH;
+ end
+ end
+ `OP_STR: begin
+ // TODO
+ end
+ default: begin
+ `ifdef __SYNTHESIS__
+ $fatal(1, "execute: unhandled opcode %04b", ir[15:12]);
+ `endif
+ end
+ endcase
+ end
+ end
+endmodule
diff --git a/atk16_fpga/cu_tb.gtkw b/atk16_fpga/cu_tb.gtkw
new file mode 100644
index 0000000..b297fcc
--- /dev/null
+++ b/atk16_fpga/cu_tb.gtkw
@@ -0,0 +1,77 @@
+[*]
+[*] GTKWave Analyzer v3.4.0 (w)1999-2022 BSI
+[*] Thu Dec 26 10:23:44 2024
+[*]
+[dumpfile] "/Users/jantuomi/Projects/Personal/ATK16/atk16_fpga/cu_tb.vcd"
+[dumpfile_mtime] "Thu Dec 26 10:23:28 2024"
+[dumpfile_size] 3558
+[savefile] "/Users/jantuomi/Projects/Personal/ATK16/atk16_fpga/cu_tb.gtkw"
+[timestart] 0
+[size] 1728 1051
+[pos] -1 -1
+*-18.634130 214600 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] cu_tb.
+[treeopen] cu_tb.dut.
+[sst_width] 240
+[signals_width] 325
+[sst_expanded] 1
+[sst_vpaned_height] 317
+@28
+cu_tb.dut.clk
+cu_tb.dut.rst
+@25
+cu_tb.dut.phase[2:0]
+@22
+cu_tb.dut.pc[15:0]
+@28
+cu_tb.dut.ir[15:0]
+@420
+cu_tb.dut.alu_a[15:0]
+cu_tb.dut.alu_b[15:0]
+cu_tb.dut.alu_sel[2:0]
+cu_tb.dut.alu_result[15:0]
+@28
+cu_tb.dut.alu_flags[3:0]
+@22
+cu_tb.dut.ra[15:0]
+cu_tb.dut.rb[15:0]
+cu_tb.dut.rc[15:0]
+cu_tb.dut.rd[15:0]
+cu_tb.dut.re[15:0]
+cu_tb.dut.rf[15:0]
+cu_tb.dut.rg[15:0]
+cu_tb.dut.rh[15:0]
+cu_tb.dut.bram_addr[15:0]
+cu_tb.dut.bram_data_in[15:0]
+cu_tb.dut.bram_data_out[15:0]
+@28
+cu_tb.dut.bram_rd
+cu_tb.dut.bram_wr
+[pattern_trace] 1
+[pattern_trace] 0
diff --git a/atk16_fpga/cu_tb.v b/atk16_fpga/cu_tb.v
new file mode 100644
index 0000000..18a9a37
--- /dev/null
+++ b/atk16_fpga/cu_tb.v
@@ -0,0 +1,77 @@
+`default_nettype none
+`define DUMPSTR(x) `"x.vcd`"
+`timescale 10 ns / 100 ps
+
+module cu_tb();
+
+ reg clk, rst;
+
+ cu dut(
+ .clk(clk),
+ .rst(rst)
+ );
+
+ // Clock generation
+ always #5 clk = ~clk; // 100 MHz clock
+
+ reg failed;
+ initial begin
+ failed = 0;
+ $dumpfile(`DUMPSTR(`VCD_OUTPUT));
+ $dumpvars(0, cu_tb);
+
+ clk = 0;
+ rst = 0;
+
+ #10 // Wait for reset phase to finish
+
+ // test ALR
+ dut.regbank[0] = 16'd10;
+ dut.regbank[1] = 16'd20;
+ dut.mem_fsm_inst.bram_inst.mem[0] = { 4'b0000, 3'd2, 3'd0, 3'd1, 3'd0 }; // ALR RC, RA, RB, S=PLUS
+
+ #200 if (dut.regbank[2] == 16'd30) begin
+ $display("\033[0;32m[PASS]\033[0m ALR ok");
+ end else begin
+ $display("\033[0;31m[FAIL]\033[0m ALR not working, target reg contains %04h", dut.regbank[2]);
+ failed = 1;
+ end
+ rst = 1; #10 rst = 0; #10
+
+ // test LDR, absolute addressing
+ dut.mem_fsm_inst.bram_inst.mem[16'd100] = 16'hffff;
+ dut.regbank[1] = 16'd100;
+ dut.mem_fsm_inst.bram_inst.mem[16'd0] = { 4'b0010, 3'd0, 3'd1, 4'd0, 1'd1, 1'd1 }; // LDR RA, RB, absolute, direct
+
+ #200 if (dut.regbank[0] == 16'hffff) begin
+ $display("\033[0;32m[PASS]\033[0m LDR absolute ok");
+ end else begin
+ $display("\033[0;31m[FAIL]\033[0m LDR absolute not working, target reg contains %04h", dut.regbank[0]);
+ failed = 1;
+ end
+ rst = 1; #10 rst = 0; #10
+
+ // test LDR, relative addressing
+ dut.mem_fsm_inst.bram_inst.mem[16'd10] = 16'hffff;
+ dut.regbank[1] = 16'd10;
+ dut.mem_fsm_inst.bram_inst.mem[16'd0] = { 4'b0010, 3'd0, 3'd1, 4'd0, 1'd0, 1'd1 }; // LDR RA, RB, relative, direct
+
+ #200 if (dut.regbank[0] == 16'hffff) begin
+ $display("\033[0;32m[PASS]\033[0m LDR relative ok");
+ end else begin
+ $display("\033[0;31m[FAIL]\033[0m LDR relative not working, target reg contains %04h", dut.regbank[0]);
+ failed = 1;
+ end
+ rst = 1; #10 rst = 0; #10
+
+ #5
+ if (failed) begin
+ $display("🛑 \033[0;31mTest suite failed\033[0m");
+ //$fatal(1);
+ end else
+ $display("✅ \033[0;32mTest suite passed\033[0m");
+
+ $finish;
+ end
+
+endmodule
diff --git a/atk16_fpga/mem_fsm.v b/atk16_fpga/mem_fsm.v
new file mode 100644
index 0000000..d5419c5
--- /dev/null
+++ b/atk16_fpga/mem_fsm.v
@@ -0,0 +1,67 @@
+`default_nettype none
+
+`define ST_IDLE 3'd0
+`define ST_READ1 3'd1
+`define ST_READ2 3'd2
+`define ST_WRITE1 3'd4
+`define ST_WRITE2 3'd5
+`define ST_END 3'd7
+
+module mem_fsm(
+ input clk,
+ input [15:0] addr,
+ input [15:0] data_in,
+ input read_en,
+ input write_en,
+
+ output wire [15:0] data_out,
+ output reg done
+);
+ reg wr, rd;
+ reg [15:0] bram_addr;
+ reg [2:0] state = 0;
+ bram bram_inst(
+ .clk(clk),
+ .addr(bram_addr),
+ .cs_n(0),
+ .wr_n(~wr),
+ .rd_n(~rd),
+ .bram_data_in(data_in),
+ .bram_data_out(data_out)
+ );
+
+ always @(posedge clk) begin
+ case (state)
+ `ST_IDLE: begin
+ done <= 0;
+ if (~done && read_en) begin
+ state <= `ST_READ1;
+ bram_addr <= addr;
+ rd <= 1;
+ wr <= 0;
+ end
+ else if (~done && write_en) begin
+ state <= `ST_WRITE1;
+ bram_addr <= addr;
+ rd <= 0;
+ wr <= 1;
+ end
+ end
+ `ST_READ1: begin
+ state <= `ST_READ2;
+ end
+ `ST_READ2: begin
+ state <= `ST_IDLE;
+ done <= 1;
+ end
+ `ST_WRITE1: begin
+ state <= `ST_WRITE2;
+ end
+ `ST_WRITE2: begin
+ state <= `ST_IDLE;
+ done <= 1;
+ end
+ endcase
+ end
+
+endmodule
diff --git a/atk16_fpga/mem_fsm_tb.gtkw b/atk16_fpga/mem_fsm_tb.gtkw
new file mode 100644
index 0000000..6e8015a
--- /dev/null
+++ b/atk16_fpga/mem_fsm_tb.gtkw
@@ -0,0 +1,32 @@
+[*]
+[*] GTKWave Analyzer v3.4.0 (w)1999-2022 BSI
+[*] Thu Dec 26 11:58:12 2024
+[*]
+[dumpfile] "/Users/jantuomi/Projects/Personal/ATK16/atk16_fpga/mem_fsm_tb.vcd"
+[dumpfile_mtime] "Thu Dec 26 11:57:15 2024"
+[dumpfile_size] 1302
+[savefile] "/Users/jantuomi/Projects/Personal/ATK16/atk16_fpga/mem_fsm_tb.gtkw"
+[timestart] 0
+[size] 1280 600
+[pos] -1 -1
+*-16.373917 -1 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
+[treeopen] mem_fsm_tb.
+[treeopen] mem_fsm_tb.dut.
+[sst_width] 240
+[signals_width] 144
+[sst_expanded] 1
+[sst_vpaned_height] 159
+@28
+mem_fsm_tb.clk
+mem_fsm_tb.start_read
+mem_fsm_tb.start_write
+@22
+mem_fsm_tb.addr[15:0]
+mem_fsm_tb.data_in[15:0]
+mem_fsm_tb.data_out[15:0]
+@28
+mem_fsm_tb.done
+@29
+mem_fsm_tb.dut.state[2:0]
+[pattern_trace] 1
+[pattern_trace] 0
diff --git a/atk16_fpga/mem_fsm_tb.v b/atk16_fpga/mem_fsm_tb.v
new file mode 100644
index 0000000..5c5029c
--- /dev/null
+++ b/atk16_fpga/mem_fsm_tb.v
@@ -0,0 +1,82 @@
+`default_nettype none
+`define DUMPSTR(x) `"x.vcd`"
+`timescale 10 ns / 100 ps
+
+module mem_fsm_tb();
+
+ reg clk, rst, start_read, start_write;
+ reg [15:0] addr, data_in;
+ wire done;
+ wire [15:0] data_out;
+
+ mem_fsm dut(
+ .clk(clk),
+ .addr(addr),
+ .data_in(data_in),
+ .start_read(start_read),
+ .start_write(start_write),
+ .data_out(data_out),
+ .done(done)
+ );
+
+ // Clock generation
+ always #5 clk = ~clk; // 100 MHz clock
+
+ reg failed;
+ initial begin
+ failed = 0;
+ $dumpfile(`DUMPSTR(`VCD_OUTPUT));
+ $dumpvars(0, mem_fsm_tb);
+
+ clk = 0;
+ rst = 0;
+ start_read = 0;
+ start_write = 0;
+ #10
+
+ // test read
+ dut.bram_inst.mem[0] = 16'hffff;
+ addr = 16'd0;
+ start_read = 1;
+ start_write = 0;
+
+ #40
+ if (data_out == 16'hffff && done == 1) begin
+ $display("\033[0;32m[PASS]\033[0m Read: data is available and done is 1 as expected");
+ end else begin
+ $display("\033[0;31m[FAIL]\033[0m Read: done is %d (expected 1), data is %04h (expected ffff)", done, data_out);
+ failed = 1;
+ end
+
+ start_read = 0;
+ start_write = 0;
+ #10
+
+ // test write
+ addr = 16'd1;
+ data_in = 16'hffff;
+ start_read = 0;
+ start_write = 1;
+
+ #40
+ if (dut.bram_inst.mem[1] == 16'hffff && done == 1) begin
+ $display("\033[0;32m[PASS]\033[0m Write: data is available and done is 1 as expected");
+ end else begin
+ $display("\033[0;31m[FAIL]\033[0m Write: done is %d (expected 0), data is %04h (expected FFFF)", done, data_out);
+ failed = 1;
+ end
+
+ start_read = 0;
+ start_write = 0;
+
+ #5
+ if (failed) begin
+ $display("🛑 \033[0;31mTest suite failed\033[0m");
+ $fatal(1);
+ end else
+ $display("✅ \033[0;32mTest suite passed\033[0m");
+
+ $finish;
+ end
+
+endmodule
diff --git a/atk16_fpga/top.v b/atk16_fpga/top.v
index c456b31..386d6e3 100644
--- a/atk16_fpga/top.v
+++ b/atk16_fpga/top.v
@@ -1,18 +1,16 @@
+`default_nettype none
+
module top(
input wire SYSCLK,
+ input wire BUT1,
output wire LED1
);
- assign LED1 = SYSCLK;
-
- wire [15:0] result;
- wire [3:0] flags;
- alu alu_inst(
- .sel(3'd0),
- .a(16'd0),
- .b(16'd0),
- .result(result),
- .flags(flags)
+ cu cu_inst(
+ .clk(SYSCLK),
+ .rst(BUT1)
);
+ assign LED1 = BUT1;
+
endmodule