2026-10-25 14:59:27 +02:00
|
|
|
// Bias amplifier with two paths fed by the selected healthy generators:
|
|
|
|
|
// path 0 (bias): the generator bits themselves;
|
|
|
|
|
// path 1 (autocorrelation): each bit XNOR the previous bit of the same generator, so
|
|
|
|
|
// positive lag-1 autocorrelation becomes an excess of ones.
|
|
|
|
|
// An optional von Neumann extractor per generator runs before both paths.
|
|
|
|
|
//
|
|
|
|
|
// Trials consist of `subtrials` sub-trials of `sub_ms` milliseconds. Each sub-trial votes with
|
|
|
|
|
// the majority of its amplified bits (no vote on a tie or without bits); the trial result is
|
|
|
|
|
// the majority of the votes.
|
|
|
|
|
//
|
|
|
|
|
// Snapshot layout (big-endian), latched at each trial end:
|
|
|
|
|
// 0-3 trial sequence number
|
|
|
|
|
// 4 bits 3:0 generators used during the whole trial, bit 4 von Neumann during the
|
|
|
|
|
// whole trial, bit 5 merge overflow since restart (should never be set)
|
|
|
|
|
// 5 sub-trials per trial
|
|
|
|
|
// 6 sub-trial length in ms
|
|
|
|
|
// 7 0
|
|
|
|
|
// 8+16p path p: amplified bits (4), ones (4), votes (2), voted (2), vote count (1),
|
|
|
|
|
// result (1: bit 0 trial bit, bit 1 trial valid), 0 (2)
|
|
|
|
|
// 40-43 trial sequence number again; a mismatch with bytes 0-3 means a torn read
|
|
|
|
|
module bias_amplifier #(
|
|
|
|
|
parameter GENERATORS = 4,
|
|
|
|
|
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, // all generators deliver in lockstep
|
|
|
|
|
input wire [GENERATORS-1:0] sources, // selected and healthy generators
|
|
|
|
|
input wire von_neumann,
|
|
|
|
|
input wire [2:0] stage_mode,
|
|
|
|
|
input wire [47:0] stage_param,
|
|
|
|
|
input wire [7:0] sub_ms,
|
|
|
|
|
input wire [3:0] subtrials,
|
|
|
|
|
input wire restart,
|
|
|
|
|
input wire [7:0] read_index,
|
|
|
|
|
output reg [7:0] read_byte, // one cycle after read_index
|
|
|
|
|
output reg trial_end
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
localparam SNAPSHOT_BYTES = 44;
|
|
|
|
|
|
|
|
|
|
wire start_over = reset || restart;
|
|
|
|
|
|
|
|
|
|
// Von Neumann (01 -> 0, 10 -> 1) and autocorrelation conversion per generator
|
|
|
|
|
|
|
|
|
|
reg [GENERATORS-1:0] pair_first, have_first, previous_bit, has_previous;
|
|
|
|
|
wire [GENERATORS-1:0] vn_valid = von_neumann ? (gen_valid ? have_first & (gen_bit ^ pair_first) : {GENERATORS{1'b0}})
|
|
|
|
|
: {GENERATORS{gen_valid}};
|
|
|
|
|
wire [GENERATORS-1:0] vn_bit = von_neumann ? pair_first : gen_bit;
|
|
|
|
|
wire [GENERATORS-1:0] bias_valid = vn_valid & sources;
|
|
|
|
|
wire [GENERATORS-1:0] ac_valid = vn_valid & has_previous & sources;
|
|
|
|
|
wire [GENERATORS-1:0] ac_bit = ~(vn_bit ^ previous_bit);
|
|
|
|
|
|
|
|
|
|
always @(posedge clk) begin
|
|
|
|
|
if (start_over || !von_neumann) begin
|
|
|
|
|
have_first <= {GENERATORS{1'b0}};
|
|
|
|
|
end else if (gen_valid) begin
|
|
|
|
|
have_first <= ~have_first;
|
|
|
|
|
pair_first <= gen_bit;
|
|
|
|
|
end
|
|
|
|
|
if (start_over) begin
|
|
|
|
|
has_previous <= {GENERATORS{1'b0}};
|
|
|
|
|
end else begin
|
|
|
|
|
has_previous <= has_previous | vn_valid;
|
|
|
|
|
previous_bit <= (vn_valid & vn_bit) | (~vn_valid & previous_bit);
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
// Sub-trial and trial timing
|
|
|
|
|
|
|
|
|
|
reg [16:0] tick_count;
|
|
|
|
|
reg [7:0] ms_count;
|
|
|
|
|
reg [3:0] sub_index;
|
2026-10-25 15:29:30 +02:00
|
|
|
reg sub_end, trial_due;
|
2026-10-25 14:59:27 +02:00
|
|
|
wire tick = (tick_count == TICK_CYCLES - 1);
|
|
|
|
|
|
|
|
|
|
always @(posedge clk) begin
|
|
|
|
|
sub_end <= 1'b0;
|
2026-10-25 15:29:30 +02:00
|
|
|
trial_due <= 1'b0;
|
|
|
|
|
trial_end <= trial_due;
|
2026-10-25 14:59:27 +02:00
|
|
|
if (start_over) begin
|
|
|
|
|
tick_count <= 17'd0;
|
|
|
|
|
ms_count <= 8'd0;
|
|
|
|
|
sub_index <= 4'd0;
|
|
|
|
|
end else begin
|
|
|
|
|
tick_count <= tick ? 17'd0 : tick_count + 17'd1;
|
|
|
|
|
if (tick) begin
|
|
|
|
|
if (ms_count + 8'd1 >= sub_ms) begin
|
|
|
|
|
ms_count <= 8'd0;
|
|
|
|
|
sub_end <= 1'b1;
|
|
|
|
|
end else begin
|
|
|
|
|
ms_count <= ms_count + 8'd1;
|
|
|
|
|
end
|
|
|
|
|
end
|
2026-10-25 15:29:30 +02:00
|
|
|
// trial_end follows the last sub_end by two cycles, once its vote and the vote
|
|
|
|
|
// counts are registered.
|
2026-10-25 14:59:27 +02:00
|
|
|
if (sub_end) begin
|
|
|
|
|
if (sub_index + 4'd1 >= subtrials) begin
|
|
|
|
|
sub_index <= 4'd0;
|
2026-10-25 15:29:30 +02:00
|
|
|
trial_due <= 1'b1;
|
2026-10-25 14:59:27 +02:00
|
|
|
end else begin
|
|
|
|
|
sub_index <= sub_index + 4'd1;
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
// Paths
|
|
|
|
|
|
|
|
|
|
wire [31:0] trial_bits [0:1];
|
|
|
|
|
wire [31:0] trial_ones [0:1];
|
|
|
|
|
wire [15:0] votes [0:1];
|
|
|
|
|
wire [15:0] voted [0:1];
|
2026-10-25 15:29:30 +02:00
|
|
|
wire [4:0] vote_count [0:1];
|
|
|
|
|
wire [4:0] one_votes [0:1];
|
2026-10-25 14:59:27 +02:00
|
|
|
wire [1:0] overflow;
|
|
|
|
|
|
|
|
|
|
amp_path #(.GENERATORS(GENERATORS)) bias_path (
|
|
|
|
|
.clk(clk), .restart(start_over), .in_valid(bias_valid), .in_bit(vn_bit),
|
|
|
|
|
.stage_mode(stage_mode), .stage_param(stage_param),
|
|
|
|
|
.sub_end(sub_end), .sub_index(sub_index), .trial_end(trial_end),
|
|
|
|
|
.trial_bits(trial_bits[0]), .trial_ones(trial_ones[0]),
|
2026-10-25 15:29:30 +02:00
|
|
|
.votes(votes[0]), .voted(voted[0]), .vote_count(vote_count[0]), .one_votes(one_votes[0]),
|
|
|
|
|
.overflow(overflow[0])
|
2026-10-25 14:59:27 +02:00
|
|
|
);
|
|
|
|
|
|
|
|
|
|
amp_path #(.GENERATORS(GENERATORS)) autocorrelation_path (
|
|
|
|
|
.clk(clk), .restart(start_over), .in_valid(ac_valid), .in_bit(ac_bit),
|
|
|
|
|
.stage_mode(stage_mode), .stage_param(stage_param),
|
|
|
|
|
.sub_end(sub_end), .sub_index(sub_index), .trial_end(trial_end),
|
|
|
|
|
.trial_bits(trial_bits[1]), .trial_ones(trial_ones[1]),
|
2026-10-25 15:29:30 +02:00
|
|
|
.votes(votes[1]), .voted(voted[1]), .vote_count(vote_count[1]), .one_votes(one_votes[1]),
|
|
|
|
|
.overflow(overflow[1])
|
2026-10-25 14:59:27 +02:00
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// Snapshot
|
|
|
|
|
|
2026-10-25 15:29:30 +02:00
|
|
|
function [127:0] path_bytes(input [31:0] bits, input [31:0] ones, input [15:0] vote, input [15:0] cast,
|
|
|
|
|
input [4:0] cast_count, input [4:0] ones_cast);
|
|
|
|
|
reg valid, result;
|
2026-10-25 14:59:27 +02:00
|
|
|
begin
|
2026-10-25 15:29:30 +02:00
|
|
|
valid = cast_count != 0 && {ones_cast, 1'b0} != {1'b0, cast_count};
|
|
|
|
|
result = {ones_cast, 1'b0} > {1'b0, cast_count};
|
2026-10-25 14:59:27 +02:00
|
|
|
path_bytes = {bits, ones, vote, cast, 3'd0, cast_count, 6'd0, valid, result, 16'd0};
|
|
|
|
|
end
|
|
|
|
|
endfunction
|
|
|
|
|
|
|
|
|
|
reg [31:0] sequence_number;
|
|
|
|
|
reg [GENERATORS-1:0] sources_during;
|
|
|
|
|
reg von_neumann_during;
|
|
|
|
|
reg [7:0] snapshot [0:SNAPSHOT_BYTES-1]; // byte 0 first, indexed directly
|
|
|
|
|
|
|
|
|
|
wire [8*SNAPSHOT_BYTES-1:0] snapshot_next = {
|
|
|
|
|
sequence_number,
|
|
|
|
|
2'd0, |overflow, von_neumann_during & von_neumann, sources_during & sources,
|
|
|
|
|
4'd0, subtrials, sub_ms, 8'd0,
|
2026-10-25 15:29:30 +02:00
|
|
|
path_bytes(trial_bits[0], trial_ones[0], votes[0], voted[0], vote_count[0], one_votes[0]),
|
|
|
|
|
path_bytes(trial_bits[1], trial_ones[1], votes[1], voted[1], vote_count[1], one_votes[1]),
|
2026-10-25 14:59:27 +02:00
|
|
|
sequence_number
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
integer k;
|
|
|
|
|
always @(posedge clk) begin
|
|
|
|
|
if (start_over) begin
|
|
|
|
|
sequence_number <= 32'd0;
|
|
|
|
|
sources_during <= sources;
|
|
|
|
|
von_neumann_during <= von_neumann;
|
|
|
|
|
end else if (trial_end) begin
|
|
|
|
|
for (k = 0; k < SNAPSHOT_BYTES; k = k + 1)
|
|
|
|
|
snapshot[k] <= snapshot_next[8*(SNAPSHOT_BYTES-1-k) +: 8];
|
|
|
|
|
sequence_number <= sequence_number + 32'd1;
|
|
|
|
|
sources_during <= sources;
|
|
|
|
|
von_neumann_during <= von_neumann;
|
|
|
|
|
end else begin
|
|
|
|
|
sources_during <= sources_during & sources;
|
|
|
|
|
von_neumann_during <= von_neumann_during & von_neumann;
|
|
|
|
|
end
|
|
|
|
|
read_byte <= (read_index < SNAPSHOT_BYTES) ? snapshot[read_index] : 8'h00;
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
endmodule
|