aboutsummaryrefslogtreecommitdiffstats
path: root/atk16_fpga
diff options
context:
space:
mode:
authorJan Tuomi <jan@jantuomi.fi>2024-12-24 13:21:55 +0200
committerJan Tuomi <jan@jantuomi.fi>2024-12-24 13:49:39 +0200
commit822fac04e863623706298c4f44469ad3575667d2 (patch)
tree111a17f487173362b5ff056fa0967c5d889c97f0 /atk16_fpga
parentaa93181f87e12189445342b181b91ea4b51c9434 (diff)
Add initial FPGA setup
Diffstat (limited to 'atk16_fpga')
-rw-r--r--atk16_fpga/.gitignore6
-rw-r--r--atk16_fpga/alu.v35
-rw-r--r--atk16_fpga/alu_tb.v73
-rw-r--r--atk16_fpga/apio.ini3
-rw-r--r--atk16_fpga/ice40hx8k-evb.pcf70
-rw-r--r--atk16_fpga/top.v18
6 files changed, 205 insertions, 0 deletions
diff --git a/atk16_fpga/.gitignore b/atk16_fpga/.gitignore
new file mode 100644
index 0000000..5b8789e
--- /dev/null
+++ b/atk16_fpga/.gitignore
@@ -0,0 +1,6 @@
+*.dblite
+*.out
+*.vcd
+hardware.bin
+hardware.json
+hardware.asc
diff --git a/atk16_fpga/alu.v b/atk16_fpga/alu.v
new file mode 100644
index 0000000..ea78328
--- /dev/null
+++ b/atk16_fpga/alu.v
@@ -0,0 +1,35 @@
+`default_nettype none
+
+module alu (
+ input wire [2:0] sel,
+ input wire [15:0] a,
+ input wire [15:0] b,
+ output reg [15:0] result,
+ output reg [3:0] flags // { carry, overflow, negative, zero }
+);
+ always @(*) begin
+ flags[2] = 0;
+ flags[3] = 0;
+
+ case (sel)
+ 3'd0: begin
+ {flags[3], result} = a + b; // compute carry and result
+ flags[2] = (a[15] == b[15] && result[15] != a[15]); // compute overflow
+ end
+ 3'd1: begin
+ {flags[3], result} = a - b; // compute carry and result
+ flags[2] = (a[15] != b[15] && result[15] != a[15]); // compute overflow
+ end
+ 3'd2: result = a & b;
+ 3'd3: result = a | b;
+ 3'd4: result = a ^ b;
+ 3'd5: result = a << b;
+ 3'd6: result = a >> b;
+ 3'd7: result = $signed(a) >>> b;
+ endcase
+
+ flags[1] = ($signed(result) < 0);
+ flags[0] = (result == 0);
+ end
+
+endmodule
diff --git a/atk16_fpga/alu_tb.v b/atk16_fpga/alu_tb.v
new file mode 100644
index 0000000..7569e2d
--- /dev/null
+++ b/atk16_fpga/alu_tb.v
@@ -0,0 +1,73 @@
+`default_nettype none
+`define DUMPSTR(x) `"x.vcd`"
+
+`define PLUS 3'd0
+`define MINUS 3'd1
+`define AND 3'd2
+`define OR 3'd3
+`define XOR 3'd4
+`define SHL 3'd5
+`define SHR 3'd6
+`define SAR 3'd7
+
+`define TESTCASE(ma, msel, mb, mexpected, mflags) \
+ sel <= `msel; \
+ a <= ma; \
+ b <= mb; \
+ #5 if (result != $unsigned(mexpected) || flags !== mflags) begin \
+ 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)); \
+ $display("_ expected flags %04b", mflags); \
+ end \
+ else begin \
+ $write("\033[0;32m[PASS]\033[0m "); \
+ $display("%d msel %0d = %0d, flags %04b", a, b, result, flags); \
+ end
+
+`timescale 10 ns / 100 ps
+module alu_tb();
+
+ reg [2:0] sel;
+ reg [15:0] a, b;
+ wire [15:0] result;
+ wire [3:0] flags;
+
+ alu dut (
+ .sel(sel),
+ .a(a),
+ .b(b),
+ .result(result),
+ .flags(flags)
+ );
+
+ reg failed;
+ initial begin
+ 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'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'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, 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)
+
+ #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/apio.ini b/atk16_fpga/apio.ini
new file mode 100644
index 0000000..c205966
--- /dev/null
+++ b/atk16_fpga/apio.ini
@@ -0,0 +1,3 @@
+[env]
+board = iCE40-HX8K-EVB
+top-module = top
diff --git a/atk16_fpga/ice40hx8k-evb.pcf b/atk16_fpga/ice40hx8k-evb.pcf
new file mode 100644
index 0000000..540987f
--- /dev/null
+++ b/atk16_fpga/ice40hx8k-evb.pcf
@@ -0,0 +1,70 @@
+# Whenever possible, pin names have been taken from the official schematic
+# <https://github.com/OLIMEX/iCE40HX8K-EVB/blob/master/HARDWARE/REV-B/iCE40HX8K-EVB_Rev_B.pdf>
+
+# Clock
+set_io -nowarn SYSCLK J3 # GBIN6
+
+# LEDs
+set_io -nowarn LED1 M12
+set_io -nowarn LED2 R16
+
+# Buttons
+set_io -nowarn BUT1 K11
+set_io -nowarn BUT2 P13
+
+# SPI Flash
+set_io -nowarn CDONE M10
+set_io -nowarn CRESET N11
+set_io -nowarn SDO P12
+set_io -nowarn SDI P11
+set_io -nowarn SCK R11
+set_io -nowarn SS_B R12
+
+# Programming connector
+set_io -nowarn RxD L11
+set_io -nowarn TxD T16
+
+# SRAM
+set_io -nowarn SRAM_CS T6
+set_io -nowarn SRAM_OE L9
+set_io -nowarn SRAM_WE T7
+set_io -nowarn SA[0] N6
+set_io -nowarn SA[1] T1
+set_io -nowarn SA[2] P4
+set_io -nowarn SA[3] R2
+set_io -nowarn SA[4] N5
+set_io -nowarn SA[5] T2
+set_io -nowarn SA[6] P5
+set_io -nowarn SA[7] R3
+set_io -nowarn SA[8] R5
+set_io -nowarn SA[9] T3
+set_io -nowarn SA[10] R4
+set_io -nowarn SA[11] M7
+set_io -nowarn SA[12] N7
+set_io -nowarn SA[13] P6
+set_io -nowarn SA[14] M8
+set_io -nowarn SA[15] T5
+set_io -nowarn SA[16] R6
+set_io -nowarn SA[17] P8
+set_io -nowarn SD[0] T8
+set_io -nowarn SD[1] P7
+set_io -nowarn SD[2] N9
+set_io -nowarn SD[3] T9
+set_io -nowarn SD[4] M9
+set_io -nowarn SD[5] R9
+set_io -nowarn SD[6] K9
+set_io -nowarn SD[7] P9
+set_io -nowarn SD[8] R10
+set_io -nowarn SD[9] L10
+set_io -nowarn SD[10] P10
+set_io -nowarn SD[11] N10
+set_io -nowarn SD[12] T10
+set_io -nowarn SD[13] T11
+set_io -nowarn SD[14] T15
+set_io -nowarn SD[15] T14
+
+# JTAG
+set_io -nowarn TDI R14
+set_io -nowarn TMS R15
+set_io -nowarn TCK P14
+set_io -nowarn TDO P15
diff --git a/atk16_fpga/top.v b/atk16_fpga/top.v
new file mode 100644
index 0000000..c456b31
--- /dev/null
+++ b/atk16_fpga/top.v
@@ -0,0 +1,18 @@
+module top(
+ input wire SYSCLK,
+ 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)
+ );
+
+endmodule