diff --git a/common/route/awooter/rust/src/lib.rs b/common/route/awooter/rust/src/lib.rs index ce1d42d7..9c11350d 100644 --- a/common/route/awooter/rust/src/lib.rs +++ b/common/route/awooter/rust/src/lib.rs @@ -184,6 +184,7 @@ fn route(ctx: &mut npnr::Context) -> bool { ctx, &partitionable_arcs[..], pips, + &nets, 0, ctx.grid_dim_x(), 0, diff --git a/common/route/awooter/rust/src/npnr.rs b/common/route/awooter/rust/src/npnr.rs index 8be3b6c2..32d93d26 100644 --- a/common/route/awooter/rust/src/npnr.rs +++ b/common/route/awooter/rust/src/npnr.rs @@ -46,7 +46,7 @@ impl NetInfo { } #[repr(transparent)] -#[derive(Clone, Copy, PartialEq, Eq)] +#[derive(Clone, Copy, PartialEq, Eq, Hash)] pub struct NetIndex(i32); #[repr(C)] diff --git a/common/route/awooter/rust/src/partition.rs b/common/route/awooter/rust/src/partition.rs index 69c75e1b..e9b6d39f 100644 --- a/common/route/awooter/rust/src/partition.rs +++ b/common/route/awooter/rust/src/partition.rs @@ -2,14 +2,17 @@ use std::{ cmp::Ordering, collections::HashMap, ops::RangeBounds, - sync::{atomic::AtomicUsize, Mutex}, + sync::{atomic::AtomicUsize, Mutex, RwLock}, }; use colored::Colorize; use indicatif::{ParallelProgressIterator, ProgressBar, ProgressStyle}; use rayon::prelude::*; -use crate::{npnr, route::Arc}; +use crate::{ + npnr::{self, NetIndex}, + route::Arc, +}; pub enum Segment { Northeast, @@ -111,6 +114,7 @@ pub fn find_partition_point( ctx: &npnr::Context, arcs: &[Arc], pips: &[npnr::PipId], + nets: &npnr::Nets, x_start: i32, x_finish: i32, y_start: i32, @@ -131,6 +135,7 @@ pub fn find_partition_point( ctx, arcs, pips, + nets, x, y, x_start..=x_finish, @@ -175,6 +180,7 @@ pub fn find_partition_point( ctx, arcs, pips, + nets, x, y, x_start..=x_finish, @@ -247,6 +253,7 @@ fn partition>( ctx: &npnr::Context, arcs: &[Arc], pips: &[npnr::PipId], + nets: &npnr::Nets, x: i32, y: i32, x_bounds: R, @@ -270,7 +277,7 @@ fn partition>( y_str.bold() ); - let pip_selector = PipSelector::new(ctx, pips, (x_bounds, y_bounds), (x, y).into()); + let pip_selector = PipSelector::new(ctx, pips, (x_bounds, y_bounds), (x, y).into(), nets); let mut explored_pips = AtomicUsize::new(0); @@ -613,13 +620,14 @@ pub fn find_partition_point_and_sanity_check( ctx: &npnr::Context, arcs: &[Arc], pips: &[npnr::PipId], + nets: &npnr::Nets, x_start: i32, x_finish: i32, y_start: i32, y_finish: i32, ) -> (i32, i32, Vec, Vec, Vec, Vec) { let (x_part, y_part, ne, se, sw, nw) = - find_partition_point(ctx, arcs, pips, x_start, x_finish, y_start, y_finish); + find_partition_point(ctx, arcs, pips, nets, x_start, x_finish, y_start, y_finish); let mut invalid_arcs_in_ne = 0; let mut invalid_arcs_in_se = 0; @@ -691,26 +699,21 @@ struct PipSelector { used_pips: HashMap>>, used_wires: HashMap>>, - // first direction: where is this pip going - // second direction: where is this pip located - pips_n_e: Vec, - pips_e_n: Vec, - pips_s_e: Vec, - pips_w_n: Vec, - pips_n_w: Vec, - pips_e_s: Vec, - pips_s_w: Vec, - pips_w_s: Vec, + // how to derive index described in `find_pip_index` + pips: [Vec; 8], + pip_selection_cache: [HashMap>>; 8], partition_loc: npnr::Loc, } impl PipSelector { + /// explores the pips and creates a pip selector from the results fn new>( ctx: &npnr::Context, pips: &[npnr::PipId], bounds: (R, R), partition_point: npnr::Loc, + nets: &npnr::Nets, ) -> Self { let mut pips_n_e = vec![]; let mut pips_e_n = vec![]; @@ -877,17 +880,33 @@ impl PipSelector { used_wires.insert(ctx.pip_dst_wire(*pip), Mutex::new(None)); } + let mut caches = [ + HashMap::new(), + HashMap::new(), + HashMap::new(), + HashMap::new(), + HashMap::new(), + HashMap::new(), + HashMap::new(), + HashMap::new(), + ]; + + let nets = nets.to_vec(); + for cache in &mut caches { + for (_, net) in nets.iter() { + let net = unsafe { net.as_ref().unwrap() }; + cache.insert(net.index(), RwLock::new(None)); + } + } + PipSelector { used_pips, used_wires, - pips_n_e, - pips_e_n, - pips_s_e, - pips_w_n, - pips_n_w, - pips_e_s, - pips_s_w, - pips_w_s, + pips: [ + pips_w_n, pips_w_s, pips_e_n, pips_e_s, pips_s_e, pips_s_w, pips_n_e, pips_n_w, + ], + pip_selection_cache: caches, + partition_loc: partition_point, } } @@ -900,24 +919,19 @@ impl PipSelector { coming_from: npnr::Loc, net: npnr::NetIndex, ) -> npnr::PipId { - let desired_coord: Coord = desired_pip_location.into(); - let from_coord: Coord = coming_from.into(); - let pips = match ( - desired_coord.full_segment(&self.partition_loc.into()), - from_coord.is_north_of(&self.partition_loc.into()), - from_coord.is_east_of(&self.partition_loc.into()), - ) { - (FullSegment::North, _, true) => &self.pips_w_n, - (FullSegment::South, _, true) => &self.pips_w_s, - (FullSegment::North, _, false) => &self.pips_e_n, - (FullSegment::South, _, false) => &self.pips_e_s, - (FullSegment::East, true, _) => &self.pips_s_e, - (FullSegment::West, true, _) => &self.pips_s_w, - (FullSegment::East, false, _) => &self.pips_n_e, - (FullSegment::West, false, _) => &self.pips_n_w, - (FullSegment::Exact, _, _) => panic!("can't find pips on the partition point"), - _ => panic!("pip must be on partition boundaries somewhere"), - }; + let pip_index = self.find_pip_index(desired_pip_location, coming_from); + // adding a scope to avoid holding the lock for too long + { + let cache = self.pip_selection_cache[pip_index] + .get(&net) + .unwrap() + .read() + .unwrap(); + if let Some(pip) = *cache { + return pip; + } + } + let pips = &self.pips[pip_index]; let selected_pip = pips .iter() @@ -958,6 +972,37 @@ impl PipSelector { }) .expect("unable to find a pip"); + { + let mut cache = self.pip_selection_cache[pip_index] + .get(&net) + .unwrap() + .write() + .unwrap(); + *cache = Some(*selected_pip); + } + *selected_pip } + + /// takes in a desired pip location and where the arc is coming from and figures out which index to use in the `self.pips` array + fn find_pip_index(&self, desired_pip_location: npnr::Loc, coming_from: npnr::Loc) -> usize { + let desired_coord: Coord = desired_pip_location.into(); + let from_coord: Coord = coming_from.into(); + match ( + desired_coord.full_segment(&self.partition_loc.into()), + from_coord.is_north_of(&self.partition_loc.into()), + from_coord.is_east_of(&self.partition_loc.into()), + ) { + (FullSegment::North, _, true) => 0, + (FullSegment::South, _, true) => 1, + (FullSegment::North, _, false) => 2, + (FullSegment::South, _, false) => 3, + (FullSegment::East, true, _) => 4, + (FullSegment::West, true, _) => 5, + (FullSegment::East, false, _) => 6, + (FullSegment::West, false, _) => 7, + (FullSegment::Exact, _, _) => panic!("can't find pips on the partition point"), + _ => panic!("pip must be on partition boundaries somewhere"), + } + } }