logicaffeine_compile/codegen_sva/
crdt_rtl.rs1pub fn merge_lane(a: u32, b: u32) -> u32 {
16 a.max(b)
17}
18
19pub fn emit_crdt_merge_verilog() -> String {
22 r#"// crdt_merge — the CRDT (G-Counter) join-semilattice merge in silicon.
23// merged[i] = max(a[i], b[i]) per replica lane; value = sum(merged).
24// Byte-identical to logicaffeine_data::crdt::GCounter::merge (proven by
25// crdt_merge_unit_matches_the_gcounter_oracle). 4 replicas x 32-bit.
26module crdt_merge(
27 input [127:0] a, // {a3,a2,a1,a0}, one 32-bit count per replica
28 input [127:0] b,
29 output [127:0] merged, // per-replica max (the lattice join)
30 output [33:0] value // sum of the four merged lanes
31);
32 wire [31:0] a0 = a[31:0], a1 = a[63:32], a2 = a[95:64], a3 = a[127:96];
33 wire [31:0] b0 = b[31:0], b1 = b[63:32], b2 = b[95:64], b3 = b[127:96];
34 wire [31:0] m0 = (a0 >= b0) ? a0 : b0;
35 wire [31:0] m1 = (a1 >= b1) ? a1 : b1;
36 wire [31:0] m2 = (a2 >= b2) ? a2 : b2;
37 wire [31:0] m3 = (a3 >= b3) ? a3 : b3;
38 assign merged = {m3, m2, m1, m0};
39 assign value = m0 + m1 + m2 + m3; // 34-bit LHS ⇒ no truncation
40endmodule
41"#
42 .to_string()
43}
44
45pub fn emit_dpu_ingest_verilog() -> String {
55 r#"// dpu_ingest — the DPU near-data compute tile: sequential CRDT merge-on-ingest.
56// On each posedge clk with in_valid, acc <= per-replica-max(acc, in_state) — the same
57// join-semilattice merge as crdt_merge (proven == GCounter::merge), now folded over a
58// stream. Order-invariant by the certified lattice laws, so it is correct even when the
59// deterministic controller delivers ingest beats out of logical order. 4 replicas x 32-bit.
60module dpu_ingest(
61 input clk,
62 input rst, // synchronous clear of the accumulator
63 input in_valid, // a beat of near-data arrived this cycle
64 input [127:0] in_state, // {s3,s2,s1,s0}, one 32-bit count per replica
65 output [127:0] state, // the accumulated join so far
66 output [33:0] value // sum of the four accumulated lanes
67);
68 reg [127:0] acc;
69 wire [31:0] a0 = acc[31:0], a1 = acc[63:32], a2 = acc[95:64], a3 = acc[127:96];
70 wire [31:0] b0 = in_state[31:0], b1 = in_state[63:32], b2 = in_state[95:64], b3 = in_state[127:96];
71 wire [31:0] m0 = (a0 >= b0) ? a0 : b0;
72 wire [31:0] m1 = (a1 >= b1) ? a1 : b1;
73 wire [31:0] m2 = (a2 >= b2) ? a2 : b2;
74 wire [31:0] m3 = (a3 >= b3) ? a3 : b3;
75 always @(posedge clk) begin
76 if (rst) acc <= 128'd0;
77 else if (in_valid) acc <= {m3, m2, m1, m0};
78 end
79 assign state = acc;
80 assign value = acc[31:0] + acc[63:32] + acc[95:64] + acc[127:96]; // 34-bit LHS ⇒ no truncation
81endmodule
82"#
83 .to_string()
84}
85
86pub fn emit_crdt_merge_testbench(n: usize) -> String {
89 format!(
90 r#"// tb_crdt_merge — HW G-Counter merge vs the software CRDT oracle (per-replica max).
91`timescale 1ns/1ps
92module tb_crdt_merge;
93 reg [127:0] a, b;
94 reg [127:0] oa [0:{last}];
95 reg [127:0] ob [0:{last}];
96 reg [127:0] om [0:{last}];
97 wire [127:0] merged;
98 wire [33:0] value;
99 reg [33:0] ev;
100 integer i, errors = 0;
101 crdt_merge dut(.a(a), .b(b), .merged(merged), .value(value));
102 initial begin
103 $readmemh("crdt_a.hex", oa);
104 $readmemh("crdt_b.hex", ob);
105 $readmemh("crdt_m.hex", om);
106 for (i = 0; i < {n}; i = i + 1) begin
107 a = oa[i]; b = ob[i]; #1;
108 ev = {{2'b0, om[i][31:0]}} + {{2'b0, om[i][63:32]}} + {{2'b0, om[i][95:64]}} + {{2'b0, om[i][127:96]}};
109 if (merged !== om[i]) begin errors = errors + 1; $display("FAIL merged %0d", i); end
110 if (value !== ev) begin errors = errors + 1; $display("FAIL value %0d", i); end
111 end
112 if (errors == 0) $display("PASS: {n} CRDT merges (per-replica max join + value) match the software oracle");
113 else $display("FAIL: %0d CRDT merge mismatches", errors);
114 $finish;
115 end
116endmodule
117"#,
118 last = n - 1,
119 n = n,
120 )
121}
122
123fn crdt_vectors(n: usize) -> (String, String, String) {
126 let mut st: u64 = 0x00C0_FFEE_D0D0_CAFE;
127 let mut next = || {
128 st = st
129 .wrapping_mul(6364136223846793005)
130 .wrapping_add(1442695040888963407);
131 (st >> 33) as u32
132 };
133 let (mut ha, mut hb, mut hm) = (String::new(), String::new(), String::new());
134 for _ in 0..n {
135 let a = [next(), next(), next(), next()];
136 let b = [next(), next(), next(), next()];
137 let m = [
138 merge_lane(a[0], b[0]),
139 merge_lane(a[1], b[1]),
140 merge_lane(a[2], b[2]),
141 merge_lane(a[3], b[3]),
142 ];
143 ha.push_str(&format!(
145 "{:08x}{:08x}{:08x}{:08x}\n",
146 a[3], a[2], a[1], a[0]
147 ));
148 hb.push_str(&format!(
149 "{:08x}{:08x}{:08x}{:08x}\n",
150 b[3], b[2], b[1], b[0]
151 ));
152 hm.push_str(&format!(
153 "{:08x}{:08x}{:08x}{:08x}\n",
154 m[3], m[2], m[1], m[0]
155 ));
156 }
157 (ha, hb, hm)
158}
159
160#[cfg(test)]
161#[path = "../../../logicaffeine_tests/unit/logicaffeine_compile/codegen_sva/crdt_rtl/tests.rs"]
162mod tests;