use std::collections::BTreeMap;
use crate::model::Model;
use crate::passes::Hints;
pub fn run(model: &Model, hints: &mut [Hints]) -> BTreeMap<u8, u8> {
debug_assert_eq!(model.layers.len(), hints.len());
let mut prev_slot: u8 = 0;
let mut next_slot: u8 = 1;
for i in 0..hints.len() {
if hints[i].elided {
hints[i].bram_slot_in = Some(prev_slot);
hints[i].bram_slot_out = Some(prev_slot);
continue;
}
hints[i].bram_slot_in = Some(prev_slot);
hints[i].bram_slot_out = Some(next_slot);
std::mem::swap(&mut prev_slot, &mut next_slot);
}
let mut bank: BTreeMap<u8, u8> = BTreeMap::new();
for h in hints.iter() {
if h.elided || h.ic_parallelism <= 1 {
continue;
}
if let Some(slot) = h.bram_slot_in {
let entry = bank.entry(slot).or_insert(1);
*entry = (*entry).max(h.ic_parallelism as u8);
}
}
let _ = model;
bank
}
pub fn slot_count(hints: &[Hints]) -> usize {
let mut max_slot: u8 = 0;
for h in hints {
if let Some(s) = h.bram_slot_in {
max_slot = max_slot.max(s);
}
if let Some(s) = h.bram_slot_out {
max_slot = max_slot.max(s);
}
}
max_slot as usize + 1
}
#[cfg(test)]
mod tests {
use super::*;
use crate::model::tinyconv_mnist_from_cortexm;
use crate::passes::{Hints, fuse_conv_relu};
#[test]
fn ping_pong_uses_two_slots() {
let m = tinyconv_mnist_from_cortexm();
let mut hints = vec![Hints::default(); m.layers.len()];
let bank = run(&m, &mut hints);
assert_eq!(
slot_count(&hints),
2,
"sequential pipeline should fit in 2 ping-pong slots"
);
assert!(
bank.is_empty(),
"no banked slots when no layer has ic-parallel"
);
}
#[test]
fn fused_layers_dont_burn_a_slot() {
let m = tinyconv_mnist_from_cortexm();
let mut hints = vec![Hints::default(); m.layers.len()];
fuse_conv_relu::run(&m, &mut hints);
run(&m, &mut hints);
for i in 0..hints.len() {
if hints[i].elided {
assert_eq!(
hints[i].bram_slot_in, hints[i].bram_slot_out,
"elided layer {i} should have in==out slot"
);
}
}
assert_eq!(slot_count(&hints), 2);
}
#[test]
fn ic_parallel_consumer_marks_input_slot_for_banking() {
let m = tinyconv_mnist_from_cortexm();
let mut hints = vec![Hints::default(); m.layers.len()];
hints[3].ic_parallelism = 4;
let bank = run(&m, &mut hints);
let conv2_in = hints[3].bram_slot_in.unwrap();
assert_eq!(bank.get(&conv2_in), Some(&4));
}
}