feat: add two-path bias amplifier with random walk and majority vote stages (FPGA v6)
This commit is contained in:
parent
5305d66102
commit
8541cce59c
11 changed files with 741 additions and 58 deletions
|
|
@ -1,7 +1,7 @@
|
|||
// Testbench for strix_core: register access, generator XOR logic checked against the sampled
|
||||
// ring outputs, captures read back across transactions, generator enable, the frequency
|
||||
// counter, the health monitors with injected faults, and the statistics snapshots against a
|
||||
// reference model. Rings are replaced by the SIM model in ring_osc.v.
|
||||
// counter, the health monitors with injected faults, the statistics snapshots against a
|
||||
// reference model, and the bias amplifier's bit counts in several configurations. Rings are replaced by the SIM model in ring_osc.v.
|
||||
`timescale 1ns / 1ps
|
||||
|
||||
module tb_strix_core;
|
||||
|
|
@ -17,10 +17,16 @@ module tb_strix_core;
|
|||
REG_DATA = 7'h10, REG_RING_SELECT = 7'h11, REG_FREQ_COUNT0 = 7'h15,
|
||||
REG_GEN_ENABLE = 7'h16, REG_TEMPORAL = 7'h17, REG_FREQ_GEN = 7'h18,
|
||||
REG_HEALTHY = 7'h20, REG_HEALTH_CTRL = 7'h21, REG_TRIAL_LOW = 7'h27,
|
||||
REG_STATS_CTRL = 7'h28, REG_STATS = 7'h40;
|
||||
REG_STATS_CTRL = 7'h28, REG_STATS = 7'h40, REG_AMP = 7'h42,
|
||||
REG_AMP_CTRL = 7'h50, REG_AMP_SOURCES = 7'h51, REG_AMP_SUB_MS = 7'h52,
|
||||
REG_AMP_SUBS = 7'h53, REG_AMP_STAGE = 7'h54;
|
||||
localparam AMP_SNAPSHOT_BYTES = 44;
|
||||
localparam SNAPSHOT_BYTES = 72;
|
||||
localparam TICK_CYCLES = 1500; // 1 "ms" = 12.5 us: a 10 "ms" trial outlasts a 72-byte read
|
||||
localparam TRIAL_BITS = 10 * TICK_CYCLES / 5; // 10 "ms" trials at temporal 5
|
||||
// Amplifier trials in the tests: 3 sub-trials of 2 "ms" -> 9000 clk cycles -> 1800 output
|
||||
// bits per generator at temporal 5
|
||||
localparam AMP_GEN_BITS = 3 * 2 * TICK_CYCLES / 5;
|
||||
|
||||
// Per-generator health registers
|
||||
function [6:0] gen_reg(input integer generator, input integer index);
|
||||
|
|
@ -219,6 +225,43 @@ module tb_strix_core;
|
|||
end
|
||||
endtask
|
||||
|
||||
reg [7:0] amp [0:AMP_SNAPSHOT_BYTES-1];
|
||||
|
||||
function [31:0] amp_word(input integer index);
|
||||
amp_word = {amp[index], amp[index+1], amp[index+2], amp[index+3]};
|
||||
endfunction
|
||||
|
||||
// Configures the amplifier (stage bounds or windows, random walk), restarts it, waits for its
|
||||
// second trial and reads that trial's snapshot.
|
||||
task amp_trial(input [3:0] sources, input von_neumann, input [15:0] p0, input [15:0] p1, input [15:0] p2);
|
||||
reg [7:0] dummy;
|
||||
integer i;
|
||||
begin
|
||||
write_reg(REG_AMP_SOURCES, sources);
|
||||
write_reg(REG_AMP_STAGE + 1, p0 >> 8); write_reg(REG_AMP_STAGE + 2, p0);
|
||||
write_reg(REG_AMP_STAGE + 4, p1 >> 8); write_reg(REG_AMP_STAGE + 5, p1);
|
||||
write_reg(REG_AMP_STAGE + 7, p2 >> 8); write_reg(REG_AMP_STAGE + 8, p2);
|
||||
write_reg(REG_AMP_CTRL, {6'd0, 1'b1, von_neumann}); // restart
|
||||
@(posedge dut.amp_trial_end); @(posedge dut.amp_trial_end); #200;
|
||||
ss_n = 1'b0; #SCK_HALF;
|
||||
spi_byte({1'b1, REG_AMP}, dummy);
|
||||
for (i = 0; i < AMP_SNAPSHOT_BYTES; i = i + 1) spi_byte(8'h00, amp[i]);
|
||||
#SCK_HALF ss_n = 1'b1; #(4 * SCK_HALF);
|
||||
if (amp_word(0) !== amp_word(AMP_SNAPSHOT_BYTES - 4) || amp_word(0) !== 32'd1) begin
|
||||
$display("FAIL amplifier snapshot sequence %0d/%0d", amp_word(0), amp_word(AMP_SNAPSHOT_BYTES - 4));
|
||||
errors = errors + 1;
|
||||
end
|
||||
if (amp[4][5]) begin $display("FAIL amplifier merge overflow"); errors = errors + 1; end
|
||||
end
|
||||
endtask
|
||||
|
||||
task expect_range(input integer got, input integer low, input integer high, input [8*24-1:0] what);
|
||||
if (got < low || got > high) begin
|
||||
$display("FAIL %0s: %0d not in %0d..%0d", what, got, low, high);
|
||||
errors = errors + 1;
|
||||
end
|
||||
endtask
|
||||
|
||||
task wait_trial_end;
|
||||
begin
|
||||
@(posedge dut.trial_end);
|
||||
|
|
@ -237,7 +280,7 @@ module tb_strix_core;
|
|||
// Identification
|
||||
read_reg(REG_ID0, v); expect(v, "S", "ID0");
|
||||
read_reg(REG_ID3, v); expect(v, "X", "ID3");
|
||||
read_reg(REG_VERSION, v); expect(v, 8'h05, "VERSION");
|
||||
read_reg(REG_VERSION, v); expect(v, 8'h06, "VERSION");
|
||||
read_reg(REG_GENERATORS, v); expect(v, 8'd4, "GENERATORS");
|
||||
read_reg(REG_RINGS, v); expect(v, RINGS, "RINGS");
|
||||
read_reg(REG_TEMPORAL, v); expect(v, 8'd5, "TEMPORAL");
|
||||
|
|
@ -358,6 +401,34 @@ module tb_strix_core;
|
|||
end
|
||||
write_reg(REG_STATS_CTRL, 8'h00);
|
||||
|
||||
// Bias amplifier
|
||||
write_reg(REG_AMP_SUB_MS, 8'd2);
|
||||
write_reg(REG_AMP_SUBS, 8'd3);
|
||||
|
||||
// Passthrough (all bounds 1): every generator bit appears once on the bias path
|
||||
amp_trial(4'hF, 1'b0, 16'd1, 16'd1, 16'd1);
|
||||
expect(amp[4] & 8'h0F, 8'h0F, "amp sources");
|
||||
expect(amp[5], 8'd3, "amp sub-trials");
|
||||
expect_range(amp_word(8), 4 * AMP_GEN_BITS - 8, 4 * AMP_GEN_BITS + 8, "amp passthrough bits");
|
||||
expect_range(amp_word(24), 4 * AMP_GEN_BITS - 8, 4 * AMP_GEN_BITS + 8, "amp autocorr bits");
|
||||
expect_range(amp_word(12), 4 * AMP_GEN_BITS / 3, 4 * AMP_GEN_BITS * 2 / 3, "amp passthrough ones");
|
||||
if (amp[20] == 0) begin $display("FAIL amplifier cast no votes"); errors = errors + 1; end
|
||||
|
||||
// One source only
|
||||
amp_trial(4'h1, 1'b0, 16'd1, 16'd1, 16'd1);
|
||||
expect(amp[4] & 8'h0F, 8'h01, "amp single source");
|
||||
expect_range(amp_word(8), AMP_GEN_BITS - 2, AMP_GEN_BITS + 2, "amp single-source bits");
|
||||
|
||||
// Random walk bound 2 in stage 1: about a quarter of the bits (4 steps per output)
|
||||
amp_trial(4'hF, 1'b0, 16'd2, 16'd1, 16'd1);
|
||||
expect_range(amp_word(8), 4 * AMP_GEN_BITS / 6, 4 * AMP_GEN_BITS / 3, "amp bound-2 bits");
|
||||
|
||||
// Von Neumann keeps about a quarter of the bits
|
||||
amp_trial(4'hF, 1'b1, 16'd1, 16'd1, 16'd1);
|
||||
expect(amp[4] & 8'h10, 8'h10, "amp von Neumann flag");
|
||||
expect_range(amp_word(8), 4 * AMP_GEN_BITS / 6, 4 * AMP_GEN_BITS / 3, "amp von Neumann bits");
|
||||
write_reg(REG_AMP_CTRL, 8'h00);
|
||||
|
||||
if (xor_checks < 100) begin
|
||||
$display("FAIL only %0d temporal XOR checks ran", xor_checks);
|
||||
errors = errors + 1;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue