use celox::SimulatorBuilder;
#[path = "test_utils/mod.rs"]
#[macro_use]
#[allow(unused_macros)]
mod test_utils;
use std::time::Instant;
fn linear_sec_source(p: u32) -> String {
let encoder = test_utils::veryl_std::source(&["coding", "linear_sec_encoder.veryl"]);
let decoder = test_utils::veryl_std::source(&["coding", "linear_sec_decoder.veryl"]);
let top = format!(
r#"
module Top #(
param P: u32 = {p},
const K: u32 = (1 << P) - 1,
const N: u32 = K - P,
)(
i_word : input logic<N>,
o_codeword : output logic<K>,
o_word : output logic<N>,
o_corrected: output logic,
) {{
inst u_enc: linear_sec_encoder #(P: P) (
i_word,
o_codeword,
);
inst u_dec: linear_sec_decoder #(P: P) (
i_codeword: o_codeword,
o_word,
o_corrected,
);
}}
"#
);
format!("{encoder}\n{decoder}\n{top}")
}
fn build_linear_sec(p: u32) -> std::time::Duration {
let src = linear_sec_source(p);
let start = Instant::now();
let _sim = SimulatorBuilder::new(&src, "Top").build().unwrap();
start.elapsed()
}
#[test]
fn linear_sec_scaling_p5_to_p6() {
let _ = build_linear_sec(5);
const SAMPLES: usize = 3;
let mut times_p5 = Vec::with_capacity(SAMPLES);
let mut times_p6 = Vec::with_capacity(SAMPLES);
for _ in 0..SAMPLES {
times_p5.push(build_linear_sec(5));
times_p6.push(build_linear_sec(6));
}
times_p5.sort();
times_p6.sort();
let median_p5 = times_p5[SAMPLES / 2].as_secs_f64();
let median_p6 = times_p6[SAMPLES / 2].as_secs_f64();
let ratio = median_p6 / median_p5;
println!("[scaling] linear_sec P=5 median: {median_p5:.3}s");
println!("[scaling] linear_sec P=6 median: {median_p6:.3}s");
println!("[scaling] ratio P6/P5: {ratio:.2}x");
assert!(
ratio < 10.0,
"optimizer scaling regression: P6/P5 ratio = {ratio:.2}x (limit: 10x)"
);
}
const COUNTER_TEMPLATE: &str = r#"
module Top #(
param N: u32 = {N},
)(
clk: input clock,
rst: input reset,
cnt: output logic<32>[N],
cnt0: output logic<32>,
) {
assign cnt0 = cnt[0];
for i in 0..N: g {
always_ff (clk, rst) {
if_reset {
cnt[i] = 0;
} else {
cnt[i] += 1;
}
}
}
}
"#;
fn build_counter(n: u32) -> std::time::Duration {
let src = COUNTER_TEMPLATE.replace("{N}", &n.to_string());
let start = Instant::now();
let _sim = SimulatorBuilder::new(&src, "Top").build().unwrap();
start.elapsed()
}
#[test]
fn counter_scaling_n500_to_n1000() {
let _ = build_counter(100);
const SAMPLES: usize = 3;
let mut times_small = Vec::with_capacity(SAMPLES);
let mut times_large = Vec::with_capacity(SAMPLES);
for _ in 0..SAMPLES {
times_small.push(build_counter(500));
times_large.push(build_counter(1000));
}
times_small.sort();
times_large.sort();
let median_small = times_small[SAMPLES / 2].as_secs_f64();
let median_large = times_large[SAMPLES / 2].as_secs_f64();
let ratio = median_large / median_small;
println!("[scaling] counter N=500 median: {median_small:.3}s");
println!("[scaling] counter N=1000 median: {median_large:.3}s");
println!("[scaling] ratio N1000/N500: {ratio:.2}x");
assert!(
ratio < 6.0,
"optimizer scaling regression: N1000/N500 ratio = {ratio:.2}x (limit: 6x)"
);
}