mirror of
https://github.com/allaunthefox/Research-Stack.git
synced 2026-07-31 03:05:21 +00:00
863 lines
36 KiB
Verilog
863 lines
36 KiB
Verilog
// Braid-Encoded Serial Communication Interface
|
||
// Derived from Lean: Semantics/BraidSerial.lean
|
||
// Target: Gowin GW1NR-9 (Tang Nano 9K)
|
||
// Q0.16 fixed-point arithmetic for phase encoding
|
||
// Replaces standard UART with braid-topology parallel encoding
|
||
|
||
`timescale 1ns / 1ps
|
||
|
||
// ═══════════════════════════════════════════════════════════════════════════
|
||
// Q0.16 Fixed-Point Arithmetic (Pure Fraction: range [-1, 1 - 2^-16])
|
||
// ═══════════════════════════════════════════════════════════════════════════
|
||
module q0_16_add (
|
||
input signed [15:0] a,
|
||
input signed [15:0] b,
|
||
output signed [15:0] sum,
|
||
output overflow
|
||
);
|
||
wire signed [16:0] ext = $signed({a[15], a}) + $signed({b[15], b});
|
||
assign overflow = (a[15] == b[15]) && (ext[16] != a[15]);
|
||
assign sum = overflow ? (a[15] ? 16'sh8000 : 16'sh7FFF) : ext[15:0];
|
||
endmodule
|
||
|
||
module q0_16_mul (
|
||
input signed [15:0] a,
|
||
input signed [15:0] b,
|
||
output signed [15:0] product
|
||
);
|
||
wire signed [31:0] full = $signed(a) * $signed(b);
|
||
assign product = full[31:16]; // Q0.16 multiply: keep upper 16 bits
|
||
endmodule
|
||
|
||
// ═══════════════════════════════════════════════════════════════════════════
|
||
// Byte to Q0.16 Phase Conversion
|
||
// Maps 0-255 to [-1, 1) range: 0→-1.0, 127→0.0, 255→0.999985
|
||
// Formula: phase = (byte * 2 - 255) * 65535 / 255
|
||
// Simplified: phase = (byte * 2 - 255) * 257
|
||
// Q0.16: 0x8000 = -1.0, 0x0000 = 0.0, 0x7FFF = 0.999985
|
||
// ═══════════════════════════════════════════════════════════════════════════
|
||
module byte_to_phase (
|
||
input wire [7:0] byte_in,
|
||
output reg signed [15:0] phase_out
|
||
);
|
||
// Convert byte (0-255) to signed Q0.16 phase (-32768 to 32767)
|
||
// Linear mapping: phase = (byte - 128) * 256
|
||
// This maps 0 -> -32768, 128 -> 0, 255 -> 32767
|
||
wire signed [23:0] offset = {16'b0, byte_in} - 24'sd128;
|
||
wire signed [23:0] mult = offset * 24'sd256;
|
||
assign phase_out = mult[15:0]; // Extract lower 16 bits for signed result
|
||
endmodule
|
||
|
||
// ═══════════════════════════════════════════════════════════════════════════
|
||
// Q0.16 Phase to Byte Conversion
|
||
// Inverse of byte_to_phase with clamping to [0, 255]
|
||
// Formula: byte = (phase * 255 + 65535) / 65535 / 2 + 128
|
||
// Q0.16: 0x8000 = -1.0, 0x0000 = 0.0, 0x7FFF = 0.999985
|
||
// ═══════════════════════════════════════════════════════════════════════════
|
||
module phase_to_byte (
|
||
input wire signed [15:0] phase_in,
|
||
output reg [7:0] byte_out
|
||
);
|
||
// Convert signed Q0.16 phase (-32768 to 32767) back to byte (0-255)
|
||
// Inverse mapping: byte = (phase / 256) + 128
|
||
// This maps -32768 -> 0, 0 -> 128, 32767 -> 255
|
||
wire signed [23:0] phase_ext = {{8{phase_in[15]}}, phase_in}; // Sign-extend to 24 bits
|
||
wire signed [23:0] div_result = phase_ext / 24'sd256;
|
||
wire signed [23:0] byte_result = div_result + 24'sd128;
|
||
|
||
// Clamp to [0, 255] range
|
||
wire [7:0] byte_clamped = (byte_result < 0) ? 8'd0 :
|
||
(byte_result > 255) ? 8'd255 :
|
||
byte_result[7:0];
|
||
assign byte_out = byte_clamped;
|
||
endmodule
|
||
|
||
// ═══════════════════════════════════════════════════════════════════════════
|
||
// Modulation Mode Selector
|
||
// 00: None (direct Q0.16)
|
||
// 01: QPSK (4-phase modulation, 2 bits/symbol)
|
||
// 10: QAM-16 (16-point constellation, 4 bits/symbol)
|
||
// 11: DMT (Discrete Multi-Tone, strand subcarriers)
|
||
// ═══════════════════════════════════════════════════════════════════════════
|
||
localparam MOD_NONE = 2'b00;
|
||
localparam MOD_QPSK = 2'b01;
|
||
localparam MOD_QAM16 = 2'b10;
|
||
localparam MOD_DMT = 2'b11;
|
||
|
||
// ═══════════════════════════════════════════════════════════════════════════
|
||
// QPSK Modulator
|
||
// Maps 2 bits to 4 phase states: 00→45°, 01→135°, 10→225°, 11→315°
|
||
// Q0.16: 45°=0x4000, 135°=0xC000, 225°=0x4000 (signed), 315°=0xC000 (signed)
|
||
// ═══════════════════════════════════════════════════════════════════════════
|
||
module qpsk_modulator (
|
||
input wire [1:0] symbols_in, // 2 bits per symbol
|
||
output reg signed [15:0] phase_out
|
||
);
|
||
// QPSK constellation: 4 distinct phase angles
|
||
// 00→0° (1.0), 01→90° (0.0 + 1.0j), 10→180° (-1.0), 11→270° (0.0 - 1.0j)
|
||
// In Q0.16: 0°=0x7FFF, 90°=0x4000, 180°=0x8000, 270°=0xC000
|
||
always @(*) begin
|
||
case (symbols_in)
|
||
2'b00: phase_out = 16'sh7FFF; // 1.0 (0°)
|
||
2'b01: phase_out = 16'sh4000; // 0.0 (90° - using phase as I component)
|
||
2'b10: phase_out = 16'sh8000; // -1.0 (180°)
|
||
2'b11: phase_out = 16'shC000; // 0.0 (270° - using phase as I component)
|
||
default: phase_out = 16'sd0;
|
||
endcase
|
||
end
|
||
endmodule
|
||
|
||
// QPSK Demodulator
|
||
module qpsk_demodulator (
|
||
input signed [15:0] phase_in,
|
||
output reg [1:0] symbols_out
|
||
);
|
||
// Demodulate by comparing phase to 4 constellation points
|
||
// 00→0x7FFF, 01→0x4000, 10→0x8000, 11→0xC000
|
||
always @(*) begin
|
||
if (phase_in >= 16'sh6000) begin
|
||
symbols_out = 2'b00; // 0° (0x7FFF)
|
||
end else if (phase_in >= 16'sh2000) begin
|
||
symbols_out = 2'b01; // 90° (0x4000)
|
||
end else if (phase_in >= 16'shA000) begin
|
||
symbols_out = 2'b11; // 270° (0xC000)
|
||
end else begin
|
||
symbols_out = 2'b10; // 180° (0x8000)
|
||
end
|
||
end
|
||
endmodule
|
||
|
||
// ═══════════════════════════════════════════════════════════════════════════
|
||
// QAM-16 Modulator
|
||
// Maps 4 bits to 16 phase/amplitude combinations
|
||
// ═══════════════════════════════════════════════════════════════════════════
|
||
module qam16_modulator (
|
||
input wire [3:0] symbols_in, // 4 bits per symbol
|
||
output reg signed [15:0] phase_out,
|
||
output reg signed [15:0] amp_out // Amplitude modulation
|
||
);
|
||
// QAM-16 constellation: 16 points with varying phase and amplitude
|
||
// Use 4x4 grid: 4 amplitude levels × 4 phase levels
|
||
always @(*) begin
|
||
case (symbols_in)
|
||
4'b0000: begin phase_out = 16'sh7FFF; amp_out = 16'sh7FFF; end // Max amp, 0°
|
||
4'b0001: begin phase_out = 16'sh4000; amp_out = 16'sh7FFF; end // Max amp, 90°
|
||
4'b0010: begin phase_out = 16'sh8000; amp_out = 16'sh7FFF; end // Max amp, 180°
|
||
4'b0011: begin phase_out = 16'shC000; amp_out = 16'sh7FFF; end // Max amp, 270°
|
||
4'b0100: begin phase_out = 16'sh7FFF; amp_out = 16'sh5FFF; end // High amp, 0°
|
||
4'b0101: begin phase_out = 16'sh4000; amp_out = 16'sh5FFF; end // High amp, 90°
|
||
4'b0110: begin phase_out = 16'sh8000; amp_out = 16'sh5FFF; end // High amp, 180°
|
||
4'b0111: begin phase_out = 16'shC000; amp_out = 16'sh5FFF; end // High amp, 270°
|
||
4'b1000: begin phase_out = 16'sh7FFF; amp_out = 16'sh3FFF; end // Mid amp, 0°
|
||
4'b1001: begin phase_out = 16'sh4000; amp_out = 16'sh3FFF; end // Mid amp, 90°
|
||
4'b1010: begin phase_out = 16'sh8000; amp_out = 16'sh3FFF; end // Mid amp, 180°
|
||
4'b1011: begin phase_out = 16'shC000; amp_out = 16'sh3FFF; end // Mid amp, 270°
|
||
4'b1100: begin phase_out = 16'sh7FFF; amp_out = 16'sh1FFF; end // Low amp, 0°
|
||
4'b1101: begin phase_out = 16'sh4000; amp_out = 16'sh1FFF; end // Low amp, 90°
|
||
4'b1110: begin phase_out = 16'sh8000; amp_out = 16'sh1FFF; end // Low amp, 180°
|
||
4'b1111: begin phase_out = 16'shC000; amp_out = 16'sh1FFF; end // Low amp, 270°
|
||
default: begin phase_out = 16'sd0; amp_out = 16'sd0; end
|
||
endcase
|
||
end
|
||
endmodule
|
||
|
||
// QAM-16 Demodulator
|
||
module qam16_demodulator (
|
||
input signed [15:0] phase_in,
|
||
input signed [15:0] amp_in,
|
||
output reg [3:0] symbols_out
|
||
);
|
||
// Demodulate by comparing phase and amplitude to constellation
|
||
always @(*) begin
|
||
// Determine phase (lower 2 bits)
|
||
// 00→0x7FFF, 01→0x4000, 10→0x8000, 11→0xC000
|
||
if (phase_in >= 16'sh6000) symbols_out[1:0] = 2'b00; // 0°
|
||
else if (phase_in >= 16'sh2000) symbols_out[1:0] = 2'b01; // 90°
|
||
else if (phase_in >= 16'shA000) symbols_out[1:0] = 2'b11; // 270°
|
||
else symbols_out[1:0] = 2'b10; // 180°
|
||
|
||
// Determine amplitude (upper 2 bits)
|
||
// 0→0x7FFF, 1→0x5FFF, 2→0x3FFF, 3→0x1FFF
|
||
if (amp_in > 16'sh6000) symbols_out[3:2] = 2'b00; // Max
|
||
else if (amp_in > 16'sh4000) symbols_out[3:2] = 2'b01; // High
|
||
else if (amp_in > 16'sh2000) symbols_out[3:2] = 2'b10; // Mid
|
||
else symbols_out[3:2] = 2'b11; // Low
|
||
end
|
||
endmodule
|
||
|
||
// ═══════════════════════════════════════════════════════════════════════════
|
||
// DMT-like Multi-Carrier Modulator
|
||
// Uses strand index as subcarrier frequency offset
|
||
// ═══════════════════════════════════════════════════════════════════════════
|
||
module dmt_modulator (
|
||
input wire [7:0] byte_in,
|
||
input wire [2:0] subcarrier_idx, // Strand index (0-7)
|
||
output reg signed [15:0] phase_out
|
||
);
|
||
// DMT: each subcarrier has different phase offset
|
||
// Phase offset = subcarrier_idx * 45°
|
||
// Data modulates the phase offset
|
||
wire signed [23:0] offset = {16'b0, byte_in} - 24'sd128;
|
||
wire signed [23:0] base_phase = offset * 24'sd256;
|
||
wire signed [15:0] subcarrier_offset = subcarrier_idx * 16'sh2000; // 45° increments
|
||
assign phase_out = (base_phase[15:0] + subcarrier_offset);
|
||
endmodule
|
||
|
||
// DMT Demodulator
|
||
module dmt_demodulator (
|
||
input signed [15:0] phase_in,
|
||
input wire [2:0] subcarrier_idx,
|
||
output reg [7:0] byte_out
|
||
);
|
||
// Remove subcarrier offset, then convert back to byte
|
||
// Use same offset calculation as modulator: subcarrier_idx * 0x2000
|
||
wire signed [15:0] subcarrier_offset = subcarrier_idx * 16'sh2000; // 45° increments
|
||
wire signed [15:0] demod_phase = phase_in - subcarrier_offset;
|
||
|
||
// Convert phase back to byte using inverse of byte_to_phase
|
||
// byte = (phase / 256) + 128
|
||
wire signed [23:0] phase_ext = {{8{demod_phase[15]}}, demod_phase};
|
||
wire signed [23:0] div_result = phase_ext / 24'sd256;
|
||
wire signed [23:0] byte_result = div_result + 24'sd128;
|
||
|
||
// Clamp to [0, 255] range
|
||
wire [7:0] byte_clamped = (byte_result < 0) ? 8'd0 :
|
||
(byte_result > 255) ? 8'd255 :
|
||
byte_result[7:0];
|
||
assign byte_out = byte_clamped;
|
||
endmodule
|
||
|
||
// ═══════════════════════════════════════════════════════════════════════════
|
||
// Hydrogenic Phi-Torsion Phase Generator
|
||
// gamma(theta) = phi * theta where phi = 1.6180339887498948482
|
||
// theta = frameNum * 0.01 (evolution parameter)
|
||
// ═══════════════════════════════════════════════════════════════════════════
|
||
module phi_torsion_phase (
|
||
input wire [31:0] frame_num,
|
||
output reg signed [31:0] phi_phase // Q16.16 output
|
||
);
|
||
// phi in Q16.16: 1.6180339887498948482 * 65536 ≈ 106039
|
||
localparam signed [31:0] PHI = 32'sh00019E97;
|
||
|
||
// theta = frameNum * 0.01 in Q16.16
|
||
// 0.01 in Q16.16 = 655.36 ≈ 656
|
||
localparam signed [31:0] THETA_SCALE = 32'sh00000290;
|
||
|
||
wire signed [47:0] theta_mult = $signed({16'b0, frame_num}) * THETA_SCALE;
|
||
wire signed [31:0] theta = {{16{theta_mult[31]}}, theta_mult[31:16]};
|
||
wire signed [63:0] gamma = $signed(theta) * PHI;
|
||
assign phi_phase = gamma[47:16];
|
||
endmodule
|
||
|
||
// ═══════════════════════════════════════════════════════════════════════════
|
||
// Bracket Admissibility Check
|
||
// Derived from Lean: Semantics/BraidBracket.lean
|
||
// Checks if bracket bounds are valid and gap is conserved
|
||
// ═══════════════════════════════════════════════════════════════════════════
|
||
module bracket_admissible (
|
||
input wire signed [15:0] phi, // Phase angle
|
||
input wire signed [15:0] lower_bound, // Bracket lower bound
|
||
input wire signed [15:0] upper_bound, // Bracket upper bound
|
||
input wire gap_conserved, // Gap conservation flag
|
||
output wire admissible // Overall admissibility
|
||
);
|
||
wire in_bounds = (phi >= lower_bound) && (phi <= upper_bound);
|
||
assign admissible = in_bounds && gap_conserved;
|
||
endmodule
|
||
|
||
// ═══════════════════════════════════════════════════════════════════════════
|
||
// Encoded Strand Structure (matches Lean EncodedStrand)
|
||
// ═══════════════════════════════════════════════════════════════════════════
|
||
module encoded_strand (
|
||
input wire clk,
|
||
input wire rst_n,
|
||
|
||
// Encoding interface
|
||
input wire encode_enable,
|
||
input wire [7:0] byte_in,
|
||
input wire [2:0] slot_in, // Slot 0-7
|
||
input wire parity_in,
|
||
input signed [15:0] residue_in,
|
||
input wire [1:0] modulation_mode, // 00=None, 01=QPSK, 10=QAM16, 11=DMT
|
||
|
||
// Decoding interface
|
||
input wire decode_enable,
|
||
input signed [15:0] phase_in,
|
||
input signed [15:0] amp_in, // Amplitude for QAM-16
|
||
output reg [7:0] byte_out,
|
||
|
||
// Strand output (for parallel transmission)
|
||
output wire signed [15:0] phase_acc,
|
||
output wire [2:0] slot,
|
||
output wire parity,
|
||
output wire signed [15:0] residue,
|
||
output wire signed [15:0] amplitude, // Amplitude for QAM-16
|
||
output wire admissible
|
||
);
|
||
// Phase accumulator
|
||
reg signed [15:0] phase_reg;
|
||
reg [2:0] slot_reg;
|
||
reg parity_reg;
|
||
reg signed [15:0] residue_reg;
|
||
|
||
// Bracket bounds (simplified: fixed bounds for now)
|
||
localparam signed [15:0] LOWER_BOUND = 16'sh8000; // -1.0
|
||
localparam signed [15:0] UPPER_BOUND = 16'sh7FFF; // 0.999985
|
||
|
||
// Byte to phase conversion (direct)
|
||
wire signed [15:0] phase_from_byte;
|
||
byte_to_phase byte_conv (.byte_in(byte_in), .phase_out(phase_from_byte));
|
||
|
||
// Modulation outputs
|
||
wire signed [15:0] qpsk_phase;
|
||
wire signed [15:0] qam16_phase;
|
||
wire signed [15:0] qam16_amp;
|
||
wire signed [15:0] dmt_phase;
|
||
|
||
// QPSK modulator (encode byte as 4 QPSK symbols)
|
||
// Byte 0x01 -> symbols: 00,00,00,01 -> phases: 0x7FFF, 0x7FFF, 0x7FFF, 0x4000
|
||
// But we only have one phase output per strand, so we need a different approach
|
||
// Simplified: Use byte value directly to select one of 4 phases
|
||
// byte[1:0] selects the phase
|
||
qpsk_modulator qpsk_mod (.symbols_in(byte_in[1:0]), .phase_out(qpsk_phase));
|
||
|
||
// QAM-16 modulator (encode byte as 2 QAM-16 symbols)
|
||
// byte[3:0] selects the constellation point
|
||
qam16_modulator qam16_mod (.symbols_in(byte_in[3:0]), .phase_out(qam16_phase), .amp_out(qam16_amp));
|
||
|
||
// DMT modulator (uses slot as subcarrier index)
|
||
dmt_modulator dmt_mod (.byte_in(byte_in), .subcarrier_idx(slot_in), .phase_out(dmt_phase));
|
||
|
||
// Modulation multiplexer
|
||
reg signed [15:0] modulated_phase;
|
||
reg signed [15:0] modulated_amp;
|
||
|
||
always @(*) begin
|
||
case (modulation_mode)
|
||
MOD_NONE: begin
|
||
modulated_phase = phase_from_byte;
|
||
modulated_amp = 16'sh7FFF; // Full amplitude
|
||
end
|
||
MOD_QPSK: begin
|
||
modulated_phase = qpsk_phase;
|
||
modulated_amp = 16'sh7FFF;
|
||
end
|
||
MOD_QAM16: begin
|
||
modulated_phase = qam16_phase;
|
||
modulated_amp = qam16_amp;
|
||
end
|
||
MOD_DMT: begin
|
||
modulated_phase = dmt_phase;
|
||
modulated_amp = 16'sh7FFF;
|
||
end
|
||
default: begin
|
||
modulated_phase = phase_from_byte;
|
||
modulated_amp = 16'sh7FFF;
|
||
end
|
||
endcase
|
||
end
|
||
|
||
// Phase to byte conversion (direct)
|
||
wire [7:0] byte_from_phase;
|
||
phase_to_byte phase_conv (.phase_in(phase_in), .byte_out(byte_from_phase));
|
||
|
||
// Demodulation outputs
|
||
wire [1:0] qpsk_symbols;
|
||
wire [3:0] qam16_symbols;
|
||
wire [7:0] dmt_byte;
|
||
|
||
// QPSK demodulator
|
||
qpsk_demodulator qpsk_demod (.phase_in(phase_in), .symbols_out(qpsk_symbols));
|
||
|
||
// QAM-16 demodulator
|
||
qam16_demodulator qam16_demod (.phase_in(phase_in), .amp_in(amp_in), .symbols_out(qam16_symbols));
|
||
|
||
// DMT demodulator
|
||
dmt_demodulator dmt_demod (.phase_in(phase_in), .subcarrier_idx(slot_in), .byte_out(dmt_byte));
|
||
|
||
// Demodulation multiplexer
|
||
reg [7:0] demodulated_byte;
|
||
|
||
always @(*) begin
|
||
case (modulation_mode)
|
||
MOD_NONE: demodulated_byte = byte_from_phase;
|
||
MOD_QPSK: demodulated_byte = {6'b0, qpsk_symbols}; // Lower 2 bits from QPSK
|
||
MOD_QAM16: demodulated_byte = {4'b0, qam16_symbols}; // Lower 4 bits from QAM-16
|
||
MOD_DMT: demodulated_byte = dmt_byte;
|
||
default: demodulated_byte = byte_from_phase;
|
||
endcase
|
||
end
|
||
|
||
// Admissibility check
|
||
bracket_admissible bracket_check (
|
||
.phi(modulated_phase),
|
||
.lower_bound(LOWER_BOUND),
|
||
.upper_bound(UPPER_BOUND),
|
||
.gap_conserved(1'b1), // Simplified: always conserved
|
||
.admissible(admissible)
|
||
);
|
||
|
||
// Combinational output assignment - phase_acc reflects current modulated_phase when encoding
|
||
assign phase_acc = encode_enable ? modulated_phase : phase_reg;
|
||
assign slot = encode_enable ? slot_in : slot_reg;
|
||
assign parity = encode_enable ? parity_in : parity_reg;
|
||
assign residue = encode_enable ? residue_in : residue_reg;
|
||
assign amplitude = encode_enable ? modulated_amp : 16'sh7FFF;
|
||
|
||
always @(posedge clk or negedge rst_n) begin
|
||
if (!rst_n) begin
|
||
phase_reg <= 16'sd0;
|
||
slot_reg <= 3'd0;
|
||
parity_reg <= 1'b0;
|
||
residue_reg <= 16'sd0;
|
||
byte_out <= 8'd0;
|
||
end else begin
|
||
if (encode_enable) begin
|
||
phase_reg <= modulated_phase;
|
||
slot_reg <= slot_in;
|
||
parity_reg <= parity_in;
|
||
residue_reg <= residue_in;
|
||
end else if (decode_enable) begin
|
||
byte_out <= demodulated_byte;
|
||
end
|
||
end
|
||
end
|
||
endmodule
|
||
|
||
// ═══════════════════════════════════════════════════════════════════════════
|
||
// Braid Frame Encoder
|
||
// Encodes serial packet into 8-wire parallel braid frame
|
||
// ═══════════════════════════════════════════════════════════════════════════
|
||
module braid_frame_encoder (
|
||
input wire clk,
|
||
input wire rst_n,
|
||
|
||
// Packet input
|
||
input wire encode_start,
|
||
input wire [7:0] packet_type,
|
||
input wire [15:0] seq_num,
|
||
input wire [7:0] payload_len,
|
||
input wire [63:0] payload_data, // 8 bytes max for simplicity
|
||
input wire [31:0] frame_num,
|
||
input wire [1:0] modulation_mode, // 00=None, 01=QPSK, 10=QAM16, 11=DMT
|
||
|
||
// 8-wire parallel output
|
||
output wire signed [15:0] wire_phase [0:7],
|
||
output wire [2:0] wire_slot [0:7],
|
||
output wire wire_parity [0:7],
|
||
output wire signed [15:0] wire_amplitude [0:7], // Amplitude for QAM-16
|
||
output wire frame_valid,
|
||
output wire signed [31:0] phi_phase
|
||
);
|
||
// Packet assembly - direct wire assignments for debugging
|
||
wire [7:0] all_bytes [0:7];
|
||
assign all_bytes[0] = packet_type;
|
||
assign all_bytes[1] = seq_num[7:0];
|
||
assign all_bytes[2] = seq_num[15:8];
|
||
assign all_bytes[3] = payload_len;
|
||
assign all_bytes[4] = payload_data[7:0];
|
||
assign all_bytes[5] = payload_data[15:8];
|
||
assign all_bytes[6] = payload_data[23:16];
|
||
assign all_bytes[7] = payload_data[31:24];
|
||
// Note: For full 64-bit payload, would need 8 more wires, but keeping it simple for now
|
||
|
||
// Encoding state
|
||
reg [3:0] encode_state;
|
||
reg [2:0] current_slot;
|
||
reg frame_valid_reg;
|
||
reg encode_enable_delayed; // Delayed version of encode_start
|
||
|
||
// Phi-torsion phase
|
||
wire signed [31:0] phi_torsion;
|
||
phi_torsion_phase phi_gen (.frame_num(frame_num), .phi_phase(phi_torsion));
|
||
|
||
// 8 strand encoders
|
||
wire signed [15:0] phase_acc [0:7];
|
||
wire [2:0] slot_out [0:7];
|
||
wire parity_out [0:7];
|
||
wire signed [15:0] amplitude_out [0:7];
|
||
wire admissible [0:7];
|
||
|
||
genvar i;
|
||
generate
|
||
for (i = 0; i < 8; i = i + 1) begin : strand_gen
|
||
encoded_strand strand_inst (
|
||
.clk(clk),
|
||
.rst_n(rst_n),
|
||
.encode_enable(encode_start),
|
||
.byte_in(all_bytes[i]),
|
||
.slot_in(i[2:0]),
|
||
.parity_in(frame_num[0]), // Frame parity
|
||
.residue_in(16'sd0),
|
||
.modulation_mode(modulation_mode),
|
||
.decode_enable(1'b0),
|
||
.phase_in(16'sd0),
|
||
.amp_in(16'sd0),
|
||
.byte_out(),
|
||
.phase_acc(phase_acc[i]),
|
||
.slot(slot_out[i]),
|
||
.parity(parity_out[i]),
|
||
.residue(),
|
||
.amplitude(amplitude_out[i]),
|
||
.admissible(admissible[i])
|
||
);
|
||
end
|
||
endgenerate
|
||
|
||
// Frame valid directly from encode_start (simplified)
|
||
assign frame_valid = encode_start;
|
||
assign phi_phase = phi_torsion;
|
||
|
||
// Wire output assignments
|
||
genvar j;
|
||
generate
|
||
for (j = 0; j < 8; j = j + 1) begin : wire_assign
|
||
assign wire_phase[j] = phase_acc[j];
|
||
assign wire_slot[j] = slot_out[j];
|
||
assign wire_parity[j] = parity_out[j];
|
||
assign wire_amplitude[j] = amplitude_out[j];
|
||
end
|
||
endgenerate
|
||
endmodule
|
||
|
||
// ═══════════════════════════════════════════════════════════════════════════
|
||
// Braid Frame Decoder
|
||
// Decodes 8-wire parallel braid frame back to serial packet
|
||
// ═══════════════════════════════════════════════════════════════════════════
|
||
module braid_frame_decoder (
|
||
input wire clk,
|
||
input wire rst_n,
|
||
|
||
// 8-wire parallel input
|
||
input wire signed [15:0] wire_phase [0:7],
|
||
input wire [2:0] wire_slot [0:7],
|
||
input wire wire_parity [0:7],
|
||
input wire signed [15:0] wire_amplitude [0:7], // Amplitude for QAM-16
|
||
input wire frame_valid_in,
|
||
input wire signed [31:0] phi_phase_in,
|
||
input wire [1:0] modulation_mode, // 00=None, 01=QPSK, 10=QAM16, 11=DMT
|
||
|
||
// Decoded packet output
|
||
output reg [7:0] packet_type,
|
||
output reg [15:0] seq_num,
|
||
output reg [7:0] payload_len,
|
||
output reg [63:0] payload_data,
|
||
output reg decode_valid,
|
||
output reg admissible_out
|
||
);
|
||
// Decoded bytes
|
||
reg [7:0] decoded_bytes [0:11];
|
||
|
||
// 8 strand decoders
|
||
wire [7:0] byte_out [0:7];
|
||
wire admissible [0:7];
|
||
|
||
genvar i;
|
||
generate
|
||
for (i = 0; i < 8; i = i + 1) begin : strand_dec_gen
|
||
encoded_strand strand_inst (
|
||
.clk(clk),
|
||
.rst_n(rst_n),
|
||
.encode_enable(1'b0),
|
||
.byte_in(8'd0),
|
||
.slot_in(i[2:0]), // Pass actual strand index for DMT demodulation
|
||
.parity_in(1'b0),
|
||
.residue_in(16'sd0),
|
||
.modulation_mode(modulation_mode),
|
||
.decode_enable(frame_valid_in),
|
||
.phase_in(wire_phase[i]),
|
||
.amp_in(wire_amplitude[i]),
|
||
.byte_out(byte_out[i]),
|
||
.phase_acc(),
|
||
.slot(),
|
||
.parity(),
|
||
.residue(),
|
||
.amplitude(),
|
||
.admissible(admissible[i])
|
||
);
|
||
end
|
||
endgenerate
|
||
|
||
// Decode state machine
|
||
reg [3:0] decode_state;
|
||
reg frame_valid_in_delayed; // Delayed version for timing
|
||
|
||
always @(posedge clk or negedge rst_n) begin
|
||
if (!rst_n) begin
|
||
decode_state <= 4'd0;
|
||
frame_valid_in_delayed <= 1'b0;
|
||
packet_type <= 8'd0;
|
||
seq_num <= 16'd0;
|
||
payload_len <= 8'd0;
|
||
payload_data <= 64'd0;
|
||
decode_valid <= 1'b0;
|
||
admissible_out <= 1'b0;
|
||
end else begin
|
||
frame_valid_in_delayed <= frame_valid_in;
|
||
case (decode_state)
|
||
4'd0: begin
|
||
decode_valid <= 1'b0;
|
||
if (frame_valid_in_delayed) begin
|
||
// Extract header from slots 0-3 in one cycle
|
||
packet_type <= byte_out[0];
|
||
seq_num <= {byte_out[2], byte_out[1]};
|
||
payload_len <= byte_out[3];
|
||
// Extract payload from slots 4-7
|
||
payload_data <= {32'd0, byte_out[7], byte_out[6], byte_out[5], byte_out[4]};
|
||
// Check admissibility
|
||
admissible_out <= admissible[0] && admissible[1] && admissible[2] && admissible[3] &&
|
||
admissible[4] && admissible[5] && admissible[6] && admissible[7];
|
||
decode_valid <= 1'b1;
|
||
decode_state <= 4'd1;
|
||
end
|
||
end
|
||
4'd1: begin
|
||
// Hold valid for one cycle
|
||
decode_valid <= 1'b0;
|
||
decode_state <= 4'd0;
|
||
end
|
||
default: decode_state <= 4'd0;
|
||
endcase
|
||
end
|
||
end
|
||
endmodule
|
||
|
||
// ═══════════════════════════════════════════════════════════════════════════
|
||
// Braid Serial Top-Level Module
|
||
// Replaces uart_tx_opt with braid-encoded parallel interface
|
||
// ═══════════════════════════════════════════════════════════════════════════
|
||
module braid_serial_top (
|
||
input wire clk, // Pin 52 (27MHz)
|
||
input wire rst_n, // Pin 4 (Reset_Button)
|
||
|
||
// Transmission interface
|
||
input wire tx_start,
|
||
input wire [7:0] tx_packet_type,
|
||
input wire [15:0] tx_seq_num,
|
||
input wire [7:0] tx_payload_len,
|
||
input wire [63:0] tx_payload_data,
|
||
input wire [31:0] tx_frame_num,
|
||
input wire [1:0] tx_modulation_mode, // 00=None, 01=QPSK, 10=QAM16, 11=DMT
|
||
|
||
// Reception interface
|
||
input wire rx_frame_valid,
|
||
input signed [15:0] rx_wire_phase [0:7],
|
||
input wire [2:0] rx_wire_slot [0:7],
|
||
input wire rx_wire_parity [0:7],
|
||
input signed [15:0] rx_wire_amplitude [0:7], // Amplitude for QAM-16
|
||
input signed [31:0] rx_phi_phase,
|
||
input wire [1:0] rx_modulation_mode, // 00=None, 01=QPSK, 10=QAM16, 11=DMT
|
||
|
||
// 8-wire parallel physical interface (replace UART TX/RX)
|
||
output signed [15:0] tx_wire_phase [0:7],
|
||
output wire [2:0] tx_wire_slot [0:7],
|
||
output wire tx_wire_parity [0:7],
|
||
output signed [15:0] tx_wire_amplitude [0:7], // Amplitude for QAM-16
|
||
output wire tx_frame_valid,
|
||
output signed [31:0] tx_phi_phase,
|
||
|
||
// Decoded output
|
||
output reg [7:0] rx_packet_type,
|
||
output reg [15:0] rx_seq_num,
|
||
output reg [7:0] rx_payload_len,
|
||
output reg [63:0] rx_payload_data,
|
||
output reg rx_decode_valid,
|
||
output reg rx_admissible
|
||
);
|
||
// Encoder instance
|
||
wire signed [15:0] enc_phase [0:7];
|
||
wire [2:0] enc_slot [0:7];
|
||
wire enc_parity [0:7];
|
||
wire signed [15:0] enc_amplitude [0:7];
|
||
wire enc_valid;
|
||
wire signed [31:0] enc_phi;
|
||
|
||
braid_frame_encoder encoder_inst (
|
||
.clk(clk),
|
||
.rst_n(rst_n),
|
||
.encode_start(tx_start),
|
||
.packet_type(tx_packet_type),
|
||
.seq_num(tx_seq_num),
|
||
.payload_len(tx_payload_len),
|
||
.payload_data(tx_payload_data),
|
||
.frame_num(tx_frame_num),
|
||
.modulation_mode(tx_modulation_mode),
|
||
.wire_phase(enc_phase),
|
||
.wire_slot(enc_slot),
|
||
.wire_parity(enc_parity),
|
||
.wire_amplitude(enc_amplitude),
|
||
.frame_valid(enc_valid),
|
||
.phi_phase(enc_phi)
|
||
);
|
||
|
||
// Decoder instance
|
||
braid_frame_decoder decoder_inst (
|
||
.clk(clk),
|
||
.rst_n(rst_n),
|
||
.wire_phase(rx_wire_phase),
|
||
.wire_slot(rx_wire_slot),
|
||
.wire_parity(rx_wire_parity),
|
||
.wire_amplitude(rx_wire_amplitude),
|
||
.frame_valid_in(rx_frame_valid),
|
||
.phi_phase_in(rx_phi_phase),
|
||
.modulation_mode(rx_modulation_mode),
|
||
.packet_type(rx_packet_type),
|
||
.seq_num(rx_seq_num),
|
||
.payload_len(rx_payload_len),
|
||
.payload_data(rx_payload_data),
|
||
.decode_valid(rx_decode_valid),
|
||
.admissible_out(rx_admissible)
|
||
);
|
||
|
||
// Physical output assignments
|
||
assign tx_wire_phase = enc_phase;
|
||
assign tx_wire_slot = enc_slot;
|
||
assign tx_wire_parity = enc_parity;
|
||
assign tx_wire_amplitude = enc_amplitude;
|
||
assign tx_frame_valid = enc_valid;
|
||
assign tx_phi_phase = enc_phi;
|
||
endmodule
|
||
|
||
// ═══════════════════════════════════════════════════════════════════════════
|
||
// Testbench for Braid Serial Interface
|
||
// ═══════════════════════════════════════════════════════════════════════════
|
||
module braid_serial_tb;
|
||
reg clk;
|
||
reg rst_n;
|
||
|
||
// TX interface
|
||
reg tx_start;
|
||
reg [7:0] tx_packet_type;
|
||
reg [15:0] tx_seq_num;
|
||
reg [7:0] tx_payload_len;
|
||
reg [63:0] tx_payload_data;
|
||
reg [31:0] tx_frame_num;
|
||
|
||
// RX interface (loopback)
|
||
reg rx_frame_valid;
|
||
reg signed [15:0] rx_wire_phase [0:7];
|
||
reg [2:0] rx_wire_slot [0:7];
|
||
reg rx_wire_parity [0:7];
|
||
reg signed [31:0] rx_phi_phase;
|
||
|
||
// Physical wires
|
||
wire signed [15:0] tx_wire_phase [0:7];
|
||
wire [2:0] tx_wire_slot [0:7];
|
||
wire tx_wire_parity [0:7];
|
||
wire tx_frame_valid;
|
||
wire signed [31:0] tx_phi_phase;
|
||
|
||
// Decoded output
|
||
wire [7:0] rx_packet_type;
|
||
wire [15:0] rx_seq_num;
|
||
wire [7:0] rx_payload_len;
|
||
wire [63:0] rx_payload_data;
|
||
wire rx_decode_valid;
|
||
wire rx_admissible;
|
||
|
||
// Instantiate DUT
|
||
braid_serial_top dut (
|
||
.clk(clk),
|
||
.rst_n(rst_n),
|
||
.tx_start(tx_start),
|
||
.tx_packet_type(tx_packet_type),
|
||
.tx_seq_num(tx_seq_num),
|
||
.tx_payload_len(tx_payload_len),
|
||
.tx_payload_data(tx_payload_data),
|
||
.tx_frame_num(tx_frame_num),
|
||
.rx_frame_valid(rx_frame_valid),
|
||
.rx_wire_phase(rx_wire_phase),
|
||
.rx_wire_slot(rx_wire_slot),
|
||
.rx_wire_parity(rx_wire_parity),
|
||
.rx_phi_phase(rx_phi_phase),
|
||
.tx_wire_phase(tx_wire_phase),
|
||
.tx_wire_slot(tx_wire_slot),
|
||
.tx_wire_parity(tx_wire_parity),
|
||
.tx_frame_valid(tx_frame_valid),
|
||
.tx_phi_phase(tx_phi_phase),
|
||
.rx_packet_type(rx_packet_type),
|
||
.rx_seq_num(rx_seq_num),
|
||
.rx_payload_len(rx_payload_len),
|
||
.rx_payload_data(rx_payload_data),
|
||
.rx_decode_valid(rx_decode_valid),
|
||
.rx_admissible(rx_admissible)
|
||
);
|
||
|
||
// Clock generation (27MHz)
|
||
initial clk = 0;
|
||
always #18.5185 clk = ~clk;
|
||
|
||
// Loopback connection
|
||
integer i;
|
||
always @(posedge clk) begin
|
||
if (tx_frame_valid) begin
|
||
rx_frame_valid <= tx_frame_valid;
|
||
rx_phi_phase <= tx_phi_phase;
|
||
for (i = 0; i < 8; i = i + 1) begin
|
||
rx_wire_phase[i] <= tx_wire_phase[i];
|
||
rx_wire_slot[i] <= tx_wire_slot[i];
|
||
rx_wire_parity[i] <= tx_wire_parity[i];
|
||
end
|
||
end else begin
|
||
rx_frame_valid <= 1'b0;
|
||
end
|
||
end
|
||
|
||
// Test stimulus
|
||
initial begin
|
||
// Initialize
|
||
rst_n = 0;
|
||
tx_start = 0;
|
||
tx_packet_type = 8'd0;
|
||
tx_seq_num = 16'd0;
|
||
tx_payload_len = 8'd0;
|
||
tx_payload_data = 64'd0;
|
||
tx_frame_num = 32'd0;
|
||
rx_frame_valid = 1'b0;
|
||
rx_phi_phase = 32'sd0;
|
||
|
||
#100;
|
||
rst_n = 1;
|
||
|
||
#100;
|
||
|
||
// Test 1: Simple packet
|
||
$display("Test 1: Simple packet");
|
||
tx_packet_type = 8'h01;
|
||
tx_seq_num = 16'h0001;
|
||
tx_payload_len = 8'd4;
|
||
tx_payload_data = 64'hDEADBEEFCAFEBABE;
|
||
tx_frame_num = 32'd0;
|
||
tx_start = 1;
|
||
#20;
|
||
tx_start = 0;
|
||
#200;
|
||
|
||
// Wait for decode
|
||
#200;
|
||
$display("Decoded: type=%h, seq=%h, len=%d, data=%h, valid=%b, admissible=%b",
|
||
rx_packet_type, rx_seq_num, rx_payload_len, rx_payload_data,
|
||
rx_decode_valid, rx_admissible);
|
||
|
||
// Test 2: Another packet
|
||
$display("Test 2: Second packet");
|
||
tx_packet_type = 8'h02;
|
||
tx_seq_num = 16'h0002;
|
||
tx_payload_len = 8'd8;
|
||
tx_payload_data = 64'h123456789ABCDEF0;
|
||
tx_frame_num = 32'd1;
|
||
tx_start = 1;
|
||
#20;
|
||
tx_start = 0;
|
||
#200;
|
||
|
||
// Wait for decode
|
||
#200;
|
||
$display("Decoded: type=%h, seq=%h, len=%d, data=%h, valid=%b, admissible=%b",
|
||
rx_packet_type, rx_seq_num, rx_payload_len, rx_payload_data,
|
||
rx_decode_valid, rx_admissible);
|
||
|
||
#100;
|
||
$finish;
|
||
end
|
||
endmodule
|