Research-Stack/5-Applications/out/verilog/q16_lut_core.v
Brandon Schneider 53e38e4c71 feat: 12 math enhancements — Q16 LUT, braid VCN encoder, FPGA Verilog, FFT, crypto
Pipeline:
- q16_lut_vcn.py: Q16_16 LUT generation + VCN frame encoding (8 ops)
- braid_vcn_encoder.py: Delta+RLE → RS ECC → ChaCha20 → VCN → MKV
- braid_search.py: Sidon set slots, soliton search, QUBO optimization
- test_braid_pipeline.py: 67 tests covering full round-trip

WebGPU/Scripts:
- braid_fft.wgsl: Cooley-Tukey radix-2 FFT on phase vectors
- reed_solomon_vcn.py: Reed-Solomon ECC for VCN frame data
- chacha20_braid.py: ChaCha20 encryption + key derivation
- polynomial_commitment.py: KZG scheme for receipt verification

Lean:
- BraidBitwiseODE.lean: XOR crossing, O(1) integration, 2 proved theorems

FPGA (Tang Nano 9K):
- q16_lut_core.v: 8-op arithmetic, 2-stage pipeline, BRAM reciprocal
- braid_crossing_core.v: 4-stage crossing residual, 7 Q16 instances
- Testbenches with edge cases + VCD dumps
2026-05-28 14:49:26 -05:00

169 lines
6.2 KiB
Verilog

// ============================================================================
// q16_lut_core.v - Q16_16 Fixed-Point LUT Arithmetic Core
// Target: Tang Nano 9K (GW1NR-9)
// Format: Q16.16 (16-bit integer, 16-bit fractional)
// Pipeline: 2 stages (compute/lookup + output register)
// ============================================================================
// Operations:
// 0: add (a + b)
// 1: sub (a - b)
// 2: mul (a * b, with LUT-assisted fractional handling)
// 3: div (a / b, LUT-based reciprocal approximation)
// 4: max (max(a, b))
// 5: min (min(a, b))
// 6: neg (-a)
// 7: abs (|a|)
// ============================================================================
module q16_lut_core (
input wire clk,
input wire rst,
input wire [2:0] op_select,
input wire [15:0] a,
input wire [15:0] b,
output reg [31:0] result,
output reg valid
);
// ----------------------------------------------------------------
// Q16_16 constants
// ----------------------------------------------------------------
localparam Q16_FRAC_BITS = 16;
localparam [31:0] Q16_ONE = 32'h0001_0000; // 1.0 in Q16.16
localparam [31:0] Q16_MAX = 32'h7FFF_FFFF; // max positive
localparam [31:0] Q16_MIN = 32'h8000_0000; // max negative
// ----------------------------------------------------------------
// Reciprocal LUT (block RAM inference)
// Stores 1/x for x in [1..255] scaled to Q16.16
// Index 0 stores 0 (division by zero guard)
// Size: 256 x 32-bit = 1 KB (fits in a single block RAM)
// ----------------------------------------------------------------
reg [31:0] recip_lut [0:255];
// Initialize reciprocal LUT using synthesis attribute
// recip_lut[i] = floor(65536.0 / i) for i=1..255
initial begin : init_recip_lut
integer i;
recip_lut[0] = 32'h7FFF_FFFF; // div-by-zero guard -> max
for (i = 1; i < 256; i = i + 1) begin
recip_lut[i] = 32'd65536 / i[31:0];
end
end
// ----------------------------------------------------------------
// Stage 1: Compute / Lookup
// ----------------------------------------------------------------
reg [31:0] result_s1;
reg valid_s1;
reg [2:0] op_s1;
// Sign-extend inputs to 32 bits for arithmetic
wire signed [31:0] a_ext = {{16{a[15]}}, a};
wire signed [31:0] b_ext = {{16{b[15]}}, b};
// Absolute values for division lookup
wire [15:0] a_abs = a[15] ? (~a + 16'd1) : a;
wire [15:0] b_abs = b[15] ? (~b + 16'd1) : b;
// Reciprocal LUT address: use lower 8 bits of |b|
wire [7:0] recip_addr = b_abs[7:0];
reg [31:0] recip_val;
// Multiplication intermediate (32x32 -> 64, take middle 32)
wire signed [63:0] mul_full = a_ext * b_ext;
wire [31:0] mul_result = mul_full[47:16]; // Q16.16 result
// Overflow detection for add/sub
wire add_overflow = (~a_ext[31] & ~b_ext[31] & result_s1[31]) |
( a_ext[31] & b_ext[31] & ~result_s1[31]);
always @(posedge clk) begin
if (rst) begin
result_s1 <= 32'd0;
valid_s1 <= 1'b0;
op_s1 <= 3'd0;
recip_val <= 32'd0;
end else begin
valid_s1 <= 1'b1;
op_s1 <= op_select;
// Latch reciprocal value for div operation
recip_val <= recip_lut[recip_addr];
case (op_select)
3'd0: begin // ADD
result_s1 <= a_ext + b_ext;
end
3'd1: begin // SUB
result_s1 <= a_ext - b_ext;
end
3'd2: begin // MUL
result_s1 <= mul_result;
end
3'd3: begin // DIV (LUT-based reciprocal approximation)
// a / b ≈ a * recip(b)
// Use upper bits of |b| for LUT index if > 255
if (b == 16'd0) begin
result_s1 <= (a[15]) ? Q16_MIN : Q16_MAX;
end else begin
// Approximate: sign * (|a| * recip(|b|))
result_s1 <= (a[15] ^ b[15]) ?
(-(a_ext[31:0] * recip_val >>> Q16_FRAC_BITS)) :
( a_ext[31:0] * recip_val >>> Q16_FRAC_BITS);
end
end
3'd4: begin // MAX
result_s1 <= (a_ext > b_ext) ? a_ext : b_ext;
end
3'd5: begin // MIN
result_s1 <= (a_ext < b_ext) ? a_ext : b_ext;
end
3'd6: begin // NEG
if (a == 16'h8000) begin
result_s1 <= 32'h0000_7FFF; // saturate
end else begin
result_s1 <= -a_ext;
end
end
3'd7: begin // ABS
if (a == 16'h8000) begin
result_s1 <= 32'h0000_7FFF; // saturate
end else begin
result_s1 <= a[15] ? (-a_ext) : a_ext;
end
end
default: begin
result_s1 <= 32'd0;
end
endcase
end
end
// ----------------------------------------------------------------
// Stage 2: Output Register (pipeline register)
// ----------------------------------------------------------------
always @(posedge clk) begin
if (rst) begin
result <= 32'd0;
valid <= 1'b0;
end else begin
valid <= valid_s1;
// Saturate on overflow for add/sub
case (op_s1)
3'd0, 3'd1: begin // ADD / SUB saturation
if (result_s1[31] == a_ext[31] && result_s1[31] != (op_s1 == 3'd0 ? b_ext[31] : ~b_ext[31])) begin
result <= result_s1[31] ? Q16_MIN : Q16_MAX;
end else begin
result <= result_s1;
end
end
default: begin
result <= result_s1;
end
endcase
end
end
endmodule