1use super::*;
5
6pub(super) struct Block {
9 count: u32,
11 layouts: Vec<Cost>,
13}
14
15pub(super) fn overflow(c: &Cost, limit: &Share) -> f64 {
18 let over = |used: u32, cap: u32| if used > cap { (used - cap) as f64 / cap.max(1) as f64 } else { 0.0 };
19 over(c.lut, limit.lut) + over(c.dsp, limit.dsp) + over(c.bram36, limit.bram36) + over(c.uram, limit.uram)
20}
21
22pub(super) fn place(blocks: &[Block], limit: &Share) -> Cost {
34 place_counts(blocks, limit).0
35}
36
37pub(super) fn place_counts(blocks: &[Block], limit: &Share) -> (Cost, Vec<Vec<u32>>) {
40 let mut counts: Vec<Vec<u32>> = blocks.iter().map(|b| {
42 let mut c = vec![0; b.layouts.len()];
43 c[0] = b.count;
44 c
45 }).collect();
46 let mut total = blocks.iter().fold(Cost::default(), |t, b| t.add(b.layouts[0], b.count));
47 if fits(&total, limit) {
48 return (total, counts);
49 }
50 let floor = |f: fn(&Cost) -> u32| blocks.iter().map(|b| b.count * b.layouts.iter().map(f).min().unwrap_or(0)).sum::<u32>();
53 if floor(|c| c.lut) > limit.lut || floor(|c| c.dsp) > limit.dsp || floor(|c| c.bram36) > limit.bram36 || floor(|c| c.uram) > limit.uram {
54 return (total, counts);
55 }
56 let sub = |t: Cost, c: Cost| Cost { lut: t.lut - c.lut, dsp: t.dsp - c.dsp, bram36: t.bram36 - c.bram36, uram: t.uram - c.uram };
57 loop {
58 let now = overflow(&total, limit);
59 if now == 0.0 {
60 return (total, counts);
61 }
62 let mut best: Option<(f64, usize, usize, usize)> = None;
64 for (i, b) in blocks.iter().enumerate() {
65 for from in 0..b.layouts.len() {
66 if counts[i][from] == 0 {
67 continue;
68 }
69 for to in 0..b.layouts.len() {
70 if to == from {
71 continue;
72 }
73 let t = sub(total, b.layouts[from]).add(b.layouts[to], 1);
74 let o = overflow(&t, limit);
75 if o < now - 1e-12 && best.is_none_or(|x| o < x.0) {
76 best = Some((o, i, from, to));
77 }
78 }
79 }
80 }
81 let Some((_, i, from, to)) = best else { return (total, counts) };
82 counts[i][from] -= 1;
83 counts[i][to] += 1;
84 total = sub(total, blocks[i].layouts[from]).add(blocks[i].layouts[to], 1);
85 }
86}
87
88pub(super) fn options(c: &Costs, own: Cost, bram: impl Fn(&BramLayout) -> Cost, machine: bool) -> Vec<Cost> {
92 match (c.bram_layout, machine) {
100 (Some(alt), true) => vec![own, lut_banks(own), bram(&alt)],
101 _ => vec![own],
102 }
103}
104
105pub(super) fn plain(_c: &Costs, own: Cost) -> Vec<Cost> {
108 vec![own]
109}
110
111pub fn sign_cost_within(p: &Profile, c: &Costs, limit: &Share, extra_lut: u32) -> Cost {
115 place(&sign_blocks(p, c, extra_lut), limit)
116}
117
118pub(super) fn sign_blocks(p: &Profile, c: &Costs, extra_lut: u32) -> Vec<Block> {
120 vec![
121 Block { count: 1, layouts: vec![Cost { lut: extra_lut, ..Cost::default() }] },
122 Block { count: p.sha, layouts: vec![c.sha_ring] },
123 Block { count: p.sc, layouts: vec![c.scalar_ring] },
124 Block { count: 1, layouts: plain(c, if p.fused { c.sign_controller_fused } else { c.sign_controller }) },
125 Block { count: p.fb, layouts: options(c, c.fb_machine, |a| a.fb_machine, true) },
126 Block { count: u32::from(!p.fused), layouts: options(c, c.cp_machine, |a| a.cp_machine, false) },
127 ]
128}
129
130pub fn sign_placement(p: &Profile, c: &Costs, limit: &Share, extra_lut: u32) -> [u32; 3] {
133 let (_, counts) = place_counts(&sign_blocks(p, c, extra_lut), limit);
134 machine_counts(&counts[4], p.fb)
135}
136
137pub fn verify_placement(v: &VerifyProfile, mode: VerifyMode, c: &Costs, limit: &Share, extra_lut: u32) -> [u32; 3] {
140 let (_, counts) = place_counts(&verify_blocks(v, mode, c, extra_lut), limit);
141 machine_counts(&counts[5], v.machines)
142}
143
144pub fn sign_cost_placed(p: &Profile, c: &Costs, extra_lut: u32, machines: [u32; 3]) -> Cost {
148 placed(&sign_blocks(p, c, extra_lut), 4, machines)
149}
150
151pub fn verify_cost_placed(v: &VerifyProfile, mode: VerifyMode, c: &Costs, extra_lut: u32, machines: [u32; 3]) -> Cost {
154 placed(&verify_blocks(v, mode, c, extra_lut), 5, machines)
155}
156
157pub(super) fn placed(blocks: &[Block], at: usize, machines: [u32; 3]) -> Cost {
160 blocks.iter().enumerate().fold(Cost::default(), |t, (i, b)| {
161 if i == at && b.layouts.len() == 3 {
162 (0..3).fold(t, |t, k| t.add(b.layouts[k], machines[k]))
163 } else {
164 t.add(b.layouts[0], b.count)
165 }
166 })
167}
168
169pub(super) fn machine_counts(c: &[u32], n: u32) -> [u32; 3] {
172 match c {
173 [u, l, b] => [*u, *l, *b],
174 _ => [n, 0, 0],
175 }
176}
177
178pub fn verify_cost_within(v: &VerifyProfile, mode: VerifyMode, c: &Costs, limit: &Share, extra_lut: u32) -> Cost {
180 place(&verify_blocks(v, mode, c, extra_lut), limit)
181}
182
183pub(super) fn verify_blocks(v: &VerifyProfile, mode: VerifyMode, c: &Costs, extra_lut: u32) -> Vec<Block> {
185 let machine = options(
186 c,
187 mode.machine(c),
188 |a| match mode {
189 VerifyMode::Strict | VerifyMode::Batch => a.verify_machine_strict,
190 VerifyMode::KnownKey => a.verify_machine_known_key,
191 },
192 true,
193 );
194 vec![
195 Block { count: 1, layouts: vec![Cost { lut: extra_lut, ..Cost::default() }] },
196 Block { count: v.sha, layouts: vec![c.sha_ring] },
197 Block { count: v.sc, layouts: vec![c.verify_scalar_ring] },
198 Block { count: 1, layouts: plain(c, c.verify_controller) },
199 Block { count: u32::from(mode == VerifyMode::KnownKey), layouts: options(c, c.key_loader, |a| a.key_loader, false) },
200 Block { count: v.machines, layouts: machine },
201 Block { count: v.cp, layouts: options(c, c.cp_machine, |a| a.cp_machine, false) },
202 ]
203}