feat: add per-second GCP-format trials with history, watch and HTTP access (FPGA v10)
This commit is contained in:
parent
d821b77d3b
commit
6bee626b7f
12 changed files with 475 additions and 29 deletions
131
fpga/rtl/gcp_block.v
Normal file
131
fpga/rtl/gcp_block.v
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
// Per-second trials in the format of Global Consciousness Project (GCP) style network analyses,
|
||||
// running alongside the other outputs. Every TRIAL_MS milliseconds (one second) each generator
|
||||
// yields:
|
||||
// - the sum of the first SAMPLE_BITS bits of the second, the GCP trial (expected 100, sd 7.07);
|
||||
// - the sum of all its bits during the second, for a full-rate z-score.
|
||||
// Both use XOR-masked bits: bit i of the second is inverted when i is odd, so a constant bias
|
||||
// cancels. All generators deliver in lockstep, so one bit count serves them all; generators that
|
||||
// were not healthy for the whole second are flagged in the snapshot, not excluded from counting.
|
||||
//
|
||||
// Snapshot layout (big-endian), latched at the end of each second:
|
||||
// 0-3 sequence number, starting at 1 (0: no second completed yet)
|
||||
// 4 generators healthy during the whole second (bit g)
|
||||
// 5 SAMPLE_BITS
|
||||
// 6-7 0
|
||||
// 8-11 bits per generator during the second
|
||||
// 12+5g generator g: sample sum (1), masked ones during the second (4)
|
||||
// 32-35 sequence number again; a mismatch with bytes 0-3 means a torn read
|
||||
module gcp_block #(
|
||||
parameter GENERATORS = 4,
|
||||
parameter SAMPLE_BITS = 200,
|
||||
parameter TRIAL_MS = 1000,
|
||||
parameter TICK_CYCLES = 120000 // clk cycles per millisecond
|
||||
) (
|
||||
input wire clk,
|
||||
input wire reset,
|
||||
input wire [GENERATORS-1:0] gen_bit,
|
||||
input wire gen_valid,
|
||||
input wire [GENERATORS-1:0] healthy,
|
||||
input wire [7:0] read_index,
|
||||
output reg [7:0] read_byte, // one cycle after read_index
|
||||
output reg trial_end // pulse: a new snapshot is available
|
||||
);
|
||||
|
||||
localparam SNAPSHOT_BYTES = 12 + 5 * GENERATORS + 4;
|
||||
localparam [7:0] SAMPLE_SIZE = SAMPLE_BITS;
|
||||
|
||||
// Trial timing
|
||||
|
||||
reg [16:0] tick_count;
|
||||
reg [15:0] ms_count;
|
||||
wire tick = (tick_count == TICK_CYCLES - 1);
|
||||
|
||||
always @(posedge clk) begin
|
||||
trial_end <= 1'b0;
|
||||
if (reset) begin
|
||||
tick_count <= 17'd0;
|
||||
ms_count <= 16'd0;
|
||||
end else begin
|
||||
tick_count <= tick ? 17'd0 : tick_count + 17'd1;
|
||||
if (tick && ms_count == TRIAL_MS - 1) begin
|
||||
ms_count <= 16'd0;
|
||||
trial_end <= 1'b1;
|
||||
end else if (tick) begin
|
||||
ms_count <= ms_count + 16'd1;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// Counters. As in stats_block, the bit arriving in the trial_end cycle opens the next second.
|
||||
|
||||
reg [31:0] bit_count;
|
||||
reg [7:0] sampled; // bits taken into the sample sums this second
|
||||
reg odd; // the next bit has an odd index in the second
|
||||
reg [7:0] sample_sum [0:GENERATORS-1];
|
||||
reg [31:0] masked_ones [0:GENERATORS-1];
|
||||
reg [31:0] sequence_number;
|
||||
reg [GENERATORS-1:0] healthy_during;
|
||||
|
||||
wire mask = trial_end ? 1'b0 : odd;
|
||||
wire in_sample = trial_end || sampled < SAMPLE_BITS;
|
||||
wire [GENERATORS-1:0] masked = gen_bit ^ {GENERATORS{mask}};
|
||||
|
||||
reg [8*SNAPSHOT_BYTES-1:0] snapshot_next;
|
||||
reg [7:0] snapshot [0:SNAPSHOT_BYTES-1];
|
||||
|
||||
integer k;
|
||||
always @(*) begin
|
||||
snapshot_next = {SNAPSHOT_BYTES{8'h00}};
|
||||
snapshot_next[8*SNAPSHOT_BYTES-1 -: 96] = {sequence_number,
|
||||
{8-GENERATORS{1'b0}}, healthy_during & healthy,
|
||||
SAMPLE_SIZE, 16'd0, bit_count};
|
||||
for (k = 0; k < GENERATORS; k = k + 1)
|
||||
snapshot_next[8*SNAPSHOT_BYTES-1-96-40*k -: 40] = {sample_sum[k], masked_ones[k]};
|
||||
snapshot_next[31:0] = sequence_number;
|
||||
end
|
||||
|
||||
integer g, b;
|
||||
always @(posedge clk) begin
|
||||
if (reset) begin
|
||||
bit_count <= 32'd0;
|
||||
sampled <= 8'd0;
|
||||
odd <= 1'b0;
|
||||
sequence_number <= 32'd1;
|
||||
healthy_during <= {GENERATORS{1'b1}};
|
||||
for (g = 0; g < GENERATORS; g = g + 1) begin
|
||||
sample_sum[g] <= 8'd0;
|
||||
masked_ones[g] <= 32'd0;
|
||||
end
|
||||
end else begin
|
||||
if (gen_valid) begin
|
||||
bit_count <= (trial_end ? 32'd0 : bit_count) + 32'd1;
|
||||
sampled <= in_sample ? (trial_end ? 8'd0 : sampled) + 8'd1 : sampled;
|
||||
odd <= ~mask;
|
||||
for (g = 0; g < GENERATORS; g = g + 1) begin
|
||||
sample_sum[g] <= (trial_end ? 8'd0 : sample_sum[g]) + (in_sample && masked[g]);
|
||||
masked_ones[g] <= (trial_end ? 32'd0 : masked_ones[g]) + masked[g];
|
||||
end
|
||||
end else if (trial_end) begin
|
||||
bit_count <= 32'd0;
|
||||
sampled <= 8'd0;
|
||||
odd <= 1'b0;
|
||||
for (g = 0; g < GENERATORS; g = g + 1) begin
|
||||
sample_sum[g] <= 8'd0;
|
||||
masked_ones[g] <= 32'd0;
|
||||
end
|
||||
end
|
||||
if (trial_end) begin
|
||||
for (b = 0; b < SNAPSHOT_BYTES; b = b + 1)
|
||||
snapshot[b] <= snapshot_next[8*(SNAPSHOT_BYTES-1-b) +: 8];
|
||||
sequence_number <= sequence_number + 32'd1;
|
||||
healthy_during <= healthy;
|
||||
end else begin
|
||||
healthy_during <= healthy_during & healthy;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
always @(posedge clk)
|
||||
read_byte <= (read_index < SNAPSHOT_BYTES) ? snapshot[read_index] : 8'h00;
|
||||
|
||||
endmodule
|
||||
Loading…
Add table
Add a link
Reference in a new issue