strix/fpga/rtl/amp_path.v

123 lines
5 KiB
Verilog

// One amplifier path: the generator streams are merged into one stream, which then passes
// three stages in series. Merging before amplifying is equivalent to amplifying each stream
// with the same first stage and merging after (the random walk is distributive), and needs a
// third of the stages. Amplified bits are tallied per sub-trial and per trial.
module amp_path #(
parameter GENERATORS = 4
) (
input wire clk,
input wire restart,
input wire [GENERATORS-1:0] in_valid,
input wire [GENERATORS-1:0] in_bit,
input wire [2:0] stage_mode,
input wire [47:0] stage_param, // stage s at [16*s +: 16]
input wire sub_end, // pulse: close the current sub-trial
input wire [3:0] sub_index, // sub-trial being closed
input wire trial_end, // pulse: start a new trial (after the last sub_end)
output reg [31:0] trial_bits, // amplified bits in the current trial
output reg [31:0] trial_ones,
output reg [15:0] votes, // bit i: sub-trial i voted 1
output reg [15:0] voted, // bit i: sub-trial i had a majority
output reg [4:0] vote_count, // sub-trials that voted (registered from voted)
output reg [4:0] one_votes, // of those, voted 1
output reg overflow // a merge input arrived before the last was taken
);
// Merge: each generator's latest bit waits in its own slot; one slot is drained per clock,
// lowest index first. Generators deliver at most one bit per `temporal` (>= 1, default 5)
// clocks in lockstep, so with up to 4 generators the slots never overflow at temporal >= 4
// (flagged if they do).
reg [GENERATORS-1:0] pending, pending_bit, take;
reg merged_valid, merged_bit;
integer i;
always @(*) begin
take = {GENERATORS{1'b0}};
for (i = 0; i < GENERATORS; i = i + 1)
if (pending[i] && take == {GENERATORS{1'b0}}) take[i] = 1'b1;
end
always @(posedge clk) begin
merged_valid <= |take && !restart;
for (i = 0; i < GENERATORS; i = i + 1)
if (take[i]) merged_bit <= pending_bit[i];
if (restart) begin
pending <= {GENERATORS{1'b0}};
overflow <= 1'b0;
end else begin
for (i = 0; i < GENERATORS; i = i + 1) begin
if (in_valid[i]) begin
if (pending[i] && !take[i]) overflow <= 1'b1;
pending[i] <= 1'b1;
pending_bit[i] <= in_bit[i];
end else if (take[i]) begin
pending[i] <= 1'b0;
end
end
end
end
// Stages
wire first_valid, first_bit, second_valid, second_bit, out_valid, out_bit;
amp_stage first (
.clk(clk), .restart(restart), .mode(stage_mode[0]), .param(stage_param[15:0]),
.in_valid(merged_valid), .in_bit(merged_bit), .out_valid(first_valid), .out_bit(first_bit)
);
amp_stage second (
.clk(clk), .restart(restart), .mode(stage_mode[1]), .param(stage_param[31:16]),
.in_valid(first_valid), .in_bit(first_bit), .out_valid(second_valid), .out_bit(second_bit)
);
amp_stage third (
.clk(clk), .restart(restart), .mode(stage_mode[2]), .param(stage_param[47:32]),
.in_valid(second_valid), .in_bit(second_bit), .out_valid(out_valid), .out_bit(out_bit)
);
// Tallies. A bit arriving in a sub_end or trial_end cycle counts towards the next one, so
// the trial count and the sum of its sub-trial counts can differ by one bit.
reg [23:0] sub_bits, sub_ones;
function [4:0] count_ones(input [15:0] value);
integer b;
begin
count_ones = 5'd0;
for (b = 0; b < 16; b = b + 1) count_ones = count_ones + value[b];
end
endfunction
always @(posedge clk) begin
if (restart || trial_end) begin
trial_bits <= out_valid ? 32'd1 : 32'd0;
trial_ones <= (out_valid && out_bit) ? 32'd1 : 32'd0;
votes <= 16'd0;
voted <= 16'd0;
end else if (out_valid) begin
trial_bits <= trial_bits + 32'd1;
trial_ones <= trial_ones + out_bit;
end
if (restart || sub_end) begin
sub_bits <= out_valid ? 24'd1 : 24'd0;
sub_ones <= (out_valid && out_bit) ? 24'd1 : 24'd0;
end else if (out_valid) begin
sub_bits <= sub_bits + 24'd1;
sub_ones <= sub_ones + out_bit;
end
// Registered counts, ready one cycle after the last vote of a trial
vote_count <= count_ones(voted);
one_votes <= count_ones(votes & voted);
if (!restart && sub_end && sub_bits != 0 && {sub_ones, 1'b0} != sub_bits) begin
voted[sub_index] <= 1'b1;
votes[sub_index] <= {sub_ones, 1'b0} > sub_bits;
end
end
endmodule