Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions fpga/vivado/gf16_add.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// GF(2^4) Addition — bitwise XOR
// L-DPC1 verified on XC7A100T (2026-05-10)
`timescale 1ns/1ps

module gf16_add (
input [3:0] a,
input [3:0] b,
output [3:0] sum
);
// GF(2^4) addition is bitwise XOR
assign sum = a ^ b;

endmodule
31 changes: 31 additions & 0 deletions fpga/vivado/gf16_dot4.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// GF(2^4) Dot Product — 4 elements, phi-constant weights
// weights = [phi0, phi1, phi2, phi3] — configured via parameters
// Default weights = 4'h1 each (identity test for L-DPC1)
// L-DPC1 verified on XC7A100T (2026-05-10)
`timescale 1ns/1ps

module gf16_dot4 #(
parameter [3:0] W0 = 4'h1, // phi-constant weight 0
parameter [3:0] W1 = 4'h2, // phi-constant weight 1
parameter [3:0] W2 = 4'h4, // phi-constant weight 2
parameter [3:0] W3 = 4'h8 // phi-constant weight 3
) (
input [3:0] x0,
input [3:0] x1,
input [3:0] x2,
input [3:0] x3,
output [3:0] dot
);
wire [3:0] p0, p1, p2, p3;
wire [3:0] s01, s23;

gf16_mul u_mul0 (.a(x0), .b(W0), .product(p0));
gf16_mul u_mul1 (.a(x1), .b(W1), .product(p1));
gf16_mul u_mul2 (.a(x2), .b(W2), .product(p2));
gf16_mul u_mul3 (.a(x3), .b(W3), .product(p3));

gf16_add u_add01 (.a(p0), .b(p1), .sum(s01));
gf16_add u_add23 (.a(p2), .b(p3), .sum(s23));
gf16_add u_add_final (.a(s01), .b(s23), .sum(dot));

endmodule
83 changes: 83 additions & 0 deletions fpga/vivado/gf16_heartbeat_top.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
// GF16 Heartbeat Top-Level — L-DPC1 Hardware Verification
// XC7A100T (Arty A7-100T)
// phi-heartbeat: D5 (R23) + D6 (T23) — 3-phase via STARTUPE2.CFGMCLK ~66MHz
// gf16_dot4 output: J26 (LED LD0 or GPIO)
// BOTH verified simultaneously on real silicon — 2026-05-10
//
// Toolchain: openXC7 → FASM → xc7frames2bit → XVC (ESP32-JTAG) → board
// Clock source: STARTUPE2.CFGMCLK (~66MHz, no external oscillator needed)
//
// Next: ROM via $readmemh after DSP48 routing resolved
`timescale 1ns/1ps

module gf16_heartbeat_top (
// Heartbeat LEDs (phi 3-phase)
output reg led_d5, // R23 — phi phase 0
output reg led_d6, // T23 — phi phase 1
// GF16 dot4 result LED
output led_j26 // J26 — dot4 LSB output
);
// ---- Clock from STARTUPE2 (~66 MHz internal) ----
wire clk_cfg;
(* KEEP = "TRUE" *)
STARTUPE2 #(
.PROG_USR("FALSE"),
.SIM_CCLK_FREQ(66.0)
) STARTUPE2_inst (
.CFGCLK (),
.CFGMCLK (clk_cfg),
.EOS (),
.PREQ (),
.CLK (1'b0),
.GSR (1'b0),
.GTS (1'b0),
.KEYCLEARB(1'b1),
.PACK (1'b0),
.USRCCLKO (clk_cfg),
.USRCCLKTS(1'b0),
.USRDONEO (1'b1),
.USRDONETS(1'b0)
);

// ---- Phi-heartbeat: 3-phase counter (~0.5 Hz visible blink) ----
// 66MHz / 2^26 ~ 0.99 Hz per phase
reg [26:0] counter;
reg [1:0] phi_phase;

always @(posedge clk_cfg) begin
counter <= counter + 1'b1;
if (counter == 27'd0) begin
phi_phase <= phi_phase + 1'b1;
if (phi_phase >= 2'd2)
phi_phase <= 2'd0;
end
end

always @(*) begin
case (phi_phase)
2'd0: begin led_d5 = 1'b1; led_d6 = 1'b0; end
2'd1: begin led_d5 = 1'b0; led_d6 = 1'b1; end
2'd2: begin led_d5 = 1'b1; led_d6 = 1'b1; end
default: begin led_d5 = 1'b0; led_d6 = 1'b0; end
endcase
end

// ---- GF16 dot4 with phi-constants ----
// Input vector driven by counter bits for visible pattern
wire [3:0] dot_result;
gf16_dot4 #(
.W0(4'h3), // phi-constant 0: x+1
.W1(4'h5), // phi-constant 1: x^2+1
.W2(4'h6), // phi-constant 2: x^2+x
.W3(4'h9) // phi-constant 3: x^3+1
) u_dot4 (
.x0(counter[10:7]),
.x1(counter[14:11]),
.x2(counter[18:15]),
.x3(counter[22:19]),
.dot(dot_result)
);

assign led_j26 = dot_result[0]; // LSB drives J26

endmodule
34 changes: 34 additions & 0 deletions fpga/vivado/gf16_mul.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// GF(2^4) Multiplication — LUT-based, polynomial x^4 + x + 1 (0x13)
// NO DSP48 — abc9 routing issue workaround (see COMMON_PITFALLS.md)
// L-DPC1 verified on XC7A100T (2026-05-10)
`timescale 1ns/1ps

module gf16_mul (
input [3:0] a,
input [3:0] b,
output [3:0] product
);
// Primitive polynomial: x^4 + x + 1
// Reduction: if bit 4 set, XOR with 0x3 (x+1)
wire [6:0] raw;
wire [3:0] p;

// Schoolbook multiplication in GF(2)[x] mod (x^4 + x + 1)
assign raw[0] = a[0] & b[0];
assign raw[1] = (a[1] & b[0]) ^ (a[0] & b[1]);
assign raw[2] = (a[2] & b[0]) ^ (a[1] & b[1]) ^ (a[0] & b[2]);
assign raw[3] = (a[3] & b[0]) ^ (a[2] & b[1]) ^ (a[1] & b[2]) ^ (a[0] & b[3]);
assign raw[4] = (a[3] & b[1]) ^ (a[2] & b[2]) ^ (a[1] & b[3]);
assign raw[5] = (a[3] & b[2]) ^ (a[2] & b[3]);
assign raw[6] = a[3] & b[3];

// Reduce mod x^4 + x + 1:
// x^4 = x + 1 => bit4 -> bit1, bit0
// x^5 = x^2 + x
// x^6 = x^3 + x^2
assign product[0] = raw[0] ^ raw[4];
assign product[1] = raw[1] ^ raw[4] ^ raw[5];
assign product[2] = raw[2] ^ raw[5] ^ raw[6];
assign product[3] = raw[3] ^ raw[6];

endmodule
Loading