logicaffeine_compile/codegen_sva/
arbiter_rtl.rs1pub const SM64_GAMMA: u64 = 0x9E37_79B9_7F4A_7C15;
18pub const SM64_MIX1: u64 = 0xBF58_476D_1CE4_E5B9;
19pub const SM64_MIX2: u64 = 0x94D0_49BB_1331_11EB;
20
21pub fn sm64_next(state: &mut u64) -> u64 {
24 *state = state.wrapping_add(SM64_GAMMA);
25 let mut z = *state;
26 z = (z ^ (z >> 30)).wrapping_mul(SM64_MIX1);
27 z = (z ^ (z >> 27)).wrapping_mul(SM64_MIX2);
28 z ^ (z >> 31)
29}
30
31pub fn emit_seeded_arbiter_verilog() -> String {
35 format!(
36 r#"// seeded_arbiter_prng — the NoC arbiter's deterministic entropy core.
37// SplitMix64, bit-identical to logicaffeine_system::concurrency::SplitMix64.
38module seeded_arbiter_prng(
39 input clk,
40 input rst,
41 input [63:0] seed,
42 input load,
43 input step,
44 output reg [63:0] draw,
45 output reg draw_valid
46);
47 reg [63:0] state;
48 // Combinational mix of the NEXT state (state + gamma).
49 wire [63:0] s1 = state + 64'h{gamma:016x};
50 wire [63:0] z1 = (s1 ^ (s1 >> 30)) * 64'h{mix1:016x};
51 wire [63:0] z2 = (z1 ^ (z1 >> 27)) * 64'h{mix2:016x};
52 wire [63:0] mixed = z2 ^ (z2 >> 31);
53 always @(posedge clk) begin
54 if (rst) begin
55 state <= 64'd0; draw <= 64'd0; draw_valid <= 1'b0;
56 end else begin
57 draw_valid <= 1'b0;
58 if (load) begin
59 state <= seed;
60 end else if (step) begin
61 state <= s1;
62 draw <= mixed;
63 draw_valid <= 1'b1;
64 end
65 end
66 end
67endmodule
68"#,
69 gamma = SM64_GAMMA,
70 mix1 = SM64_MIX1,
71 mix2 = SM64_MIX2,
72 )
73}
74
75pub fn emit_seeded_arbiter_testbench(n: usize) -> String {
78 format!(
79 r#"// tb_seeded_arbiter — HW SplitMix64 draws vs the software scheduler oracle.
80`timescale 1ns/1ps
81module tb_seeded_arbiter;
82 reg clk = 0; always #5 clk = ~clk;
83 reg rst = 1, load = 0, step = 0;
84 reg [63:0] seed;
85 reg [63:0] oracle [0:{last}];
86 wire [63:0] draw; wire draw_valid;
87 integer got = 0, errors = 0;
88 seeded_arbiter_prng dut(.clk(clk), .rst(rst), .seed(seed), .load(load), .step(step),
89 .draw(draw), .draw_valid(draw_valid));
90 always @(posedge clk) if (draw_valid) begin
91 if (draw !== oracle[got]) begin errors = errors + 1; $display("FAIL draw %0d", got); end
92 got = got + 1;
93 end
94 initial begin
95 $readmemh("arbiter_seq.hex", oracle);
96 seed = 64'h{seed:016x};
97 rst = 1; repeat (3) @(posedge clk); #1 rst = 0;
98 @(posedge clk); #1 load = 1;
99 @(posedge clk); #1 load = 0;
100 repeat ({n}) begin @(posedge clk); #1 step = 1; @(posedge clk); #1 step = 0; end
101 repeat (4) @(posedge clk);
102 if (got !== {n}) $display("FAIL: got %0d of {n} draws", got);
103 else if (errors == 0) $display("PASS: {n} HW SplitMix64 draws match the software scheduler bit-exact");
104 $finish;
105 end
106endmodule
107"#,
108 last = n - 1,
109 n = n,
110 seed = ARBITER_TEST_SEED,
111 )
112}
113
114pub const ARBITER_TEST_SEED: u64 = 0x1234_5678_9ABC_DEF0;
116
117#[cfg(test)]
118#[path = "../../../logicaffeine_tests/unit/logicaffeine_compile/codegen_sva/arbiter_rtl/tests.rs"]
119mod tests;