feat: add per-second GCP-format trials with history, watch and HTTP access (FPGA v10)

This commit is contained in:
randogoth 2026-10-25 18:23:18 +02:00
parent d821b77d3b
commit 6bee626b7f
12 changed files with 475 additions and 29 deletions

View file

@ -1,5 +1,5 @@
// Board-independent STRIX logic: entropy generators with health monitors, entropy byte
// stream, live statistics, bias amplifier, source selection, raw capture, frequency counter
// stream, live statistics, bias amplifier, per-second GCP-style trials, source selection, raw capture, frequency counter
// and the SPI register interface to the SAMD21.
//
// SPI protocol (mode 0, one transaction per ss_n low period): the first byte is a command,
@ -20,7 +20,8 @@
// Statistics channels 0-3 are the generators' processed outputs, channel 4 is the XOR of the
// healthy generators' outputs. Reading STATS returns the latest trial snapshot (layout in
// stats_block.v) byte by byte, starting at byte 0 in every transaction. AMP does the same for
// the bias amplifier's trial snapshot (layout in bias_amplifier.v). Reading STREAM returns
// the bias amplifier's trial snapshot (layout in bias_amplifier.v), and GCP for the per-second
// trial snapshot (layout in gcp_block.v). Reading STREAM returns
// entropy bytes from the stream FIFO, removing each byte once it has been clocked out; read
// at most STREAM_LEVEL bytes (an empty FIFO returns 0x00).
module strix_core #(
@ -28,7 +29,8 @@ module strix_core #(
parameter FREQ_GATE_BITS = 24,
parameter RINGS_PER_GEN = 90,
parameter DEAD_WINDOW_BITS = 16,
parameter TICK_CYCLES = 120000 // clk cycles per millisecond
parameter TICK_CYCLES = 120000, // clk cycles per millisecond
parameter GCP_TRIAL_MS = 1000
) (
input wire clk,
input wire reset,
@ -41,7 +43,7 @@ module strix_core #(
output reg nina_gpio0_in // GPIO0 is driven by the module (to the SAMD21), not to it
);
localparam [7:0] VERSION = 8'h09;
localparam [7:0] VERSION = 8'h0A;
localparam GENERATORS = 4;
localparam [6:0] REG_ID0 = 7'h00, // "STRX"
@ -93,6 +95,7 @@ module strix_core #(
REG_STATS = 7'h40, // burst read of the statistics trial snapshot
REG_STREAM = 7'h44, // burst read of entropy bytes
REG_AMP = 7'h42, // burst read of the amplifier trial snapshot
REG_GCP = 7'h46, // burst read of the per-second trial snapshot
REG_AMP_CTRL = 7'h50, // bit 0 von Neumann on the amplifier path;
// write bit 1: restart the amplifier, sequence 0
REG_AMP_SOURCES = 7'h51, // generators feeding the amplifier (healthy only)
@ -220,6 +223,18 @@ module strix_core #(
.trial_end(trial_end)
);
// Per-second GCP-style trials, fed from the same registered generator outputs
reg [7:0] gcp_index;
wire [7:0] gcp_byte;
wire gcp_trial_end;
gcp_block #(.GENERATORS(GENERATORS), .TRIAL_MS(GCP_TRIAL_MS), .TICK_CYCLES(TICK_CYCLES)) gcp (
.clk(clk), .reset(reset), .gen_bit(stats_bits[GENERATORS-1:0]), .gen_valid(stats_valid),
.healthy(stats_healthy), .read_index(gcp_index), .read_byte(gcp_byte),
.trial_end(gcp_trial_end)
);
// Source selection
reg [3:0] source_a, source_b;
@ -367,6 +382,7 @@ module strix_core #(
REG_DATA: burst_byte = capture_byte;
REG_STATS: burst_byte = stats_byte;
REG_AMP: burst_byte = amp_byte;
REG_GCP: burst_byte = gcp_byte;
REG_STREAM: burst_byte = stream_available ? stream_head : 8'h00;
default: begin
burst_byte = 8'h00;
@ -411,6 +427,7 @@ module strix_core #(
amp_stage_mode <= 3'b000;
amp_stage_param <= {16'd4, 16'd8, 16'd8}; // random walk 8 x 8 x 4 = bound 256
amp_index <= 8'd0;
gcp_index <= 8'd0;
stream_source <= 3'd4;
nina_enable <= 1'b0;
nina_gpio0_in <= 1'b0;
@ -425,6 +442,11 @@ module strix_core #(
else if (tx_loaded && is_read && reg_addr == REG_AMP)
amp_index <= amp_index + 8'd1;
if (!selected)
gcp_index <= 8'd0;
else if (tx_loaded && is_read && reg_addr == REG_GCP)
gcp_index <= gcp_index + 8'd1;
if (!selected)
stats_index <= 8'd0;
else if (tx_loaded && is_read && reg_addr == REG_STATS)