split pip selection into seperate struct
This commit is contained in:
parent
8b06c073b9
commit
a1b9222bd2
@ -117,13 +117,23 @@ impl WireId {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub struct Loc {
|
pub struct Loc {
|
||||||
pub x: libc::c_int,
|
pub x: libc::c_int,
|
||||||
pub y: libc::c_int,
|
pub y: libc::c_int,
|
||||||
pub z: libc::c_int,
|
pub z: libc::c_int,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<(i32, i32)> for Loc {
|
||||||
|
fn from(pos: (i32, i32)) -> Self {
|
||||||
|
Self {
|
||||||
|
x: pos.0,
|
||||||
|
y: pos.1,
|
||||||
|
z: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct Context {
|
pub struct Context {
|
||||||
_private: [u8; 0],
|
_private: [u8; 0],
|
||||||
|
@ -18,6 +18,18 @@ pub enum Segment {
|
|||||||
Northwest,
|
Northwest,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub enum FullSegment {
|
||||||
|
Northeast,
|
||||||
|
Southeast,
|
||||||
|
Southwest,
|
||||||
|
Northwest,
|
||||||
|
North,
|
||||||
|
South,
|
||||||
|
East,
|
||||||
|
West,
|
||||||
|
Exact,
|
||||||
|
}
|
||||||
|
|
||||||
// (x < P.x)
|
// (x < P.x)
|
||||||
// N
|
// N
|
||||||
// ^
|
// ^
|
||||||
@ -64,6 +76,26 @@ impl Coord {
|
|||||||
(false, false) => Segment::Southwest,
|
(false, false) => Segment::Southwest,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn full_segment(&self, from: &Self) -> FullSegment {
|
||||||
|
match (
|
||||||
|
self.is_north_of(from),
|
||||||
|
self.is_east_of(from),
|
||||||
|
self.is_south_of(from),
|
||||||
|
self.is_west_of(from),
|
||||||
|
) {
|
||||||
|
(true, true, false, false) => FullSegment::Northeast,
|
||||||
|
(true, false, false, true) => FullSegment::Northwest,
|
||||||
|
(false, true, true, false) => FullSegment::Southeast,
|
||||||
|
(false, false, true, true) => FullSegment::Southwest,
|
||||||
|
(true, false, false, false) => FullSegment::North,
|
||||||
|
(false, true, false, false) => FullSegment::East,
|
||||||
|
(false, false, true, false) => FullSegment::South,
|
||||||
|
(false, false, false, true) => FullSegment::West,
|
||||||
|
(false, false, false, false) => FullSegment::Exact,
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<npnr::Loc> for Coord {
|
impl From<npnr::Loc> for Coord {
|
||||||
@ -222,17 +254,6 @@ fn partition<R: RangeBounds<i32>>(
|
|||||||
) -> (Vec<Arc>, Vec<Arc>, Vec<Arc>, Vec<Arc>) {
|
) -> (Vec<Arc>, Vec<Arc>, Vec<Arc>, Vec<Arc>) {
|
||||||
let partition_coords = Coord::new(x, y);
|
let partition_coords = Coord::new(x, y);
|
||||||
|
|
||||||
// first direction: where is this pip going
|
|
||||||
// second direction: where is this pip located
|
|
||||||
let mut pips_n_e = Vec::new();
|
|
||||||
let mut pips_e_n = Vec::new();
|
|
||||||
let mut pips_s_e = Vec::new();
|
|
||||||
let mut pips_w_n = Vec::new();
|
|
||||||
let mut pips_n_w = Vec::new();
|
|
||||||
let mut pips_e_s = Vec::new();
|
|
||||||
let mut pips_s_w = Vec::new();
|
|
||||||
let mut pips_w_s = Vec::new();
|
|
||||||
|
|
||||||
let mut ne: Vec<Arc> = Vec::new();
|
let mut ne: Vec<Arc> = Vec::new();
|
||||||
let mut se: Vec<Arc> = Vec::new();
|
let mut se: Vec<Arc> = Vec::new();
|
||||||
let mut sw: Vec<Arc> = Vec::new();
|
let mut sw: Vec<Arc> = Vec::new();
|
||||||
@ -249,222 +270,7 @@ fn partition<R: RangeBounds<i32>>(
|
|||||||
y_str.bold()
|
y_str.bold()
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut candidates = 0;
|
let pip_selector = PipSelector::new(ctx, pips, (x_bounds, y_bounds), (x, y).into());
|
||||||
let mut north = 0;
|
|
||||||
let mut east = 0;
|
|
||||||
let mut south = 0;
|
|
||||||
let mut west = 0;
|
|
||||||
for &pip in pips {
|
|
||||||
let loc = ctx.pip_location(pip);
|
|
||||||
if (loc.x == x || loc.y == y) && x_bounds.contains(&loc.x) && y_bounds.contains(&loc.y) {
|
|
||||||
//correctly classifying the pips on the partition point is pretty much impossible
|
|
||||||
//just avoid the partition point
|
|
||||||
if loc.x == x && loc.y == y {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let is_general_routing = |wire: &str| {
|
|
||||||
wire.contains("H01")
|
|
||||||
|| wire.contains("V01")
|
|
||||||
|| wire.contains("H02")
|
|
||||||
|| wire.contains("V02")
|
|
||||||
|| wire.contains("H06")
|
|
||||||
|| wire.contains("V06")
|
|
||||||
};
|
|
||||||
|
|
||||||
let src_wire = ctx.pip_src_wire(pip);
|
|
||||||
let dst_wire = ctx.pip_dst_wire(pip);
|
|
||||||
let src_name = ctx.name_of_wire(src_wire).to_str().unwrap();
|
|
||||||
let dst_name = ctx.name_of_wire(dst_wire).to_str().unwrap();
|
|
||||||
if !is_general_routing(src_name) || !is_general_routing(dst_name) {
|
|
||||||
// ECP5 hack: whitelist allowed wires.
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
candidates += 1;
|
|
||||||
|
|
||||||
let pip_arc = std::sync::Arc::new((pip, AtomicUsize::new(0)));
|
|
||||||
if loc.y == y {
|
|
||||||
// pip is on east-west border
|
|
||||||
|
|
||||||
let (mut src_has_east, mut src_has_west, mut src_has_middle) =
|
|
||||||
(false, false, false);
|
|
||||||
let (mut dst_has_east, mut dst_has_west, mut dst_has_middle) =
|
|
||||||
(false, false, false);
|
|
||||||
|
|
||||||
for src_pip in ctx.get_uphill_pips(ctx.pip_src_wire(pip)) {
|
|
||||||
let src_pip_coord: Coord = ctx.pip_location(src_pip).into();
|
|
||||||
if (src_pip_coord.x < x) == (loc.x < x) {
|
|
||||||
src_has_middle |= src_pip_coord.y == loc.y;
|
|
||||||
src_has_east |= src_pip_coord.is_east_of(&partition_coords);
|
|
||||||
src_has_west |= src_pip_coord.is_west_of(&partition_coords);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for dst_pip in ctx.get_downhill_pips(ctx.pip_dst_wire(pip)) {
|
|
||||||
let dst_pip_coord: Coord = ctx.pip_location(dst_pip).into();
|
|
||||||
if (dst_pip_coord.x < x) == (loc.x < x) {
|
|
||||||
dst_has_middle |= dst_pip_coord.y == loc.y;
|
|
||||||
dst_has_east |= dst_pip_coord.is_east_of(&partition_coords);
|
|
||||||
dst_has_west |= dst_pip_coord.is_west_of(&partition_coords);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (src_has_east && (dst_has_west || dst_has_middle))
|
|
||||||
|| (src_has_middle && dst_has_west)
|
|
||||||
{
|
|
||||||
west += 1;
|
|
||||||
if loc.x < x {
|
|
||||||
pips_w_n.push(pip_arc.clone());
|
|
||||||
} else {
|
|
||||||
pips_w_s.push(pip_arc.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (src_has_west && (dst_has_east || dst_has_middle))
|
|
||||||
|| (src_has_middle && dst_has_east)
|
|
||||||
{
|
|
||||||
east += 1;
|
|
||||||
if loc.x < x {
|
|
||||||
pips_e_n.push(pip_arc.clone());
|
|
||||||
} else {
|
|
||||||
pips_e_s.push(pip_arc.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// pip is on south-north border
|
|
||||||
|
|
||||||
let (mut src_has_north, mut src_has_south, mut src_has_middle) =
|
|
||||||
(false, false, false);
|
|
||||||
let (mut dst_has_north, mut dst_has_south, mut dst_has_middle) =
|
|
||||||
(false, false, false);
|
|
||||||
|
|
||||||
for src_pip in ctx.get_uphill_pips(ctx.pip_src_wire(pip)) {
|
|
||||||
let src_pip_coord: Coord = ctx.pip_location(src_pip).into();
|
|
||||||
if (src_pip_coord.y < y) == (loc.y < y) {
|
|
||||||
src_has_middle |= src_pip_coord.x == loc.x;
|
|
||||||
src_has_north |= src_pip_coord.is_north_of(&partition_coords);
|
|
||||||
src_has_south |= src_pip_coord.is_south_of(&partition_coords);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for dst_pip in ctx.get_downhill_pips(ctx.pip_dst_wire(pip)) {
|
|
||||||
let dst_pip_coord: Coord = ctx.pip_location(dst_pip).into();
|
|
||||||
if (dst_pip_coord.y < y) == (loc.y < y) {
|
|
||||||
dst_has_middle |= dst_pip_coord.x == loc.x;
|
|
||||||
dst_has_north |= dst_pip_coord.is_north_of(&partition_coords);
|
|
||||||
dst_has_south |= dst_pip_coord.is_south_of(&partition_coords);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (src_has_north && (dst_has_south || dst_has_middle))
|
|
||||||
|| (src_has_middle && dst_has_south)
|
|
||||||
{
|
|
||||||
south += 1;
|
|
||||||
if loc.y < y {
|
|
||||||
pips_s_e.push(pip_arc.clone());
|
|
||||||
} else {
|
|
||||||
pips_s_w.push(pip_arc.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (src_has_south && (dst_has_north || dst_has_middle))
|
|
||||||
|| (src_has_middle && dst_has_north)
|
|
||||||
{
|
|
||||||
north += 1;
|
|
||||||
if loc.y < y {
|
|
||||||
pips_n_e.push(pip_arc.clone());
|
|
||||||
} else {
|
|
||||||
pips_n_w.push(pip_arc.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
log_info!(
|
|
||||||
" Out of {} candidate pips:\n",
|
|
||||||
candidates.to_string().bold()
|
|
||||||
);
|
|
||||||
log_info!(" {} are north-bound\n", north.to_string().bold());
|
|
||||||
log_info!(" {} are east-bound\n", east.to_string().bold());
|
|
||||||
log_info!(" {} are south-bound\n", south.to_string().bold());
|
|
||||||
log_info!(" {} are west-bound\n", west.to_string().bold());
|
|
||||||
|
|
||||||
//let mut unique_sinks = HashSet::new();
|
|
||||||
//let mut unique_sources = HashSet::new();
|
|
||||||
//for pip in pips_n.iter().flat_map(|(_, pips)| pips.iter()) {
|
|
||||||
// unique_sources.insert(ctx.pip_src_wire(pip.0));
|
|
||||||
// unique_sinks.insert(ctx.pip_dst_wire(pip.0));
|
|
||||||
//}
|
|
||||||
//log_info!("among the north-bound pips, there are:\n");
|
|
||||||
//log_info!(
|
|
||||||
// " {} unique sources\n",
|
|
||||||
// unique_sources.len().to_string().bold()
|
|
||||||
//);
|
|
||||||
//log_info!(
|
|
||||||
// " {} unique sinks\n",
|
|
||||||
// unique_sinks.len().to_string().bold()
|
|
||||||
//);
|
|
||||||
|
|
||||||
let mut used_pips: HashMap<npnr::PipId, Mutex<Option<npnr::NetIndex>>> = HashMap::new();
|
|
||||||
let mut used_wires: HashMap<npnr::WireId, Mutex<Option<npnr::NetIndex>>> = HashMap::new();
|
|
||||||
|
|
||||||
used_pips.reserve(pips.len());
|
|
||||||
|
|
||||||
let selected_pips = pips_n_e
|
|
||||||
.iter()
|
|
||||||
.chain(pips_e_n.iter())
|
|
||||||
.chain(pips_e_s.iter())
|
|
||||||
.chain(pips_s_e.iter())
|
|
||||||
.chain(pips_s_w.iter())
|
|
||||||
.chain(pips_w_s.iter())
|
|
||||||
.chain(pips_w_n.iter())
|
|
||||||
.chain(pips_n_w.iter());
|
|
||||||
|
|
||||||
for pip in selected_pips {
|
|
||||||
let (pip, _) = pip.as_ref();
|
|
||||||
used_pips.insert(*pip, Mutex::new(None));
|
|
||||||
used_wires.insert(ctx.pip_src_wire(*pip), Mutex::new(None));
|
|
||||||
used_wires.insert(ctx.pip_dst_wire(*pip), Mutex::new(None));
|
|
||||||
}
|
|
||||||
|
|
||||||
let find_best_pip = |pips: &Vec<std::sync::Arc<(npnr::PipId, AtomicUsize)>>, arc: &Arc| {
|
|
||||||
let (selected_pip, pip_uses) = pips
|
|
||||||
.iter()
|
|
||||||
.map(|a| a.as_ref())
|
|
||||||
.find(|(pip, _uses)| {
|
|
||||||
let source = ctx.pip_src_wire(*pip);
|
|
||||||
let sink = ctx.pip_dst_wire(*pip);
|
|
||||||
|
|
||||||
let (mut source, mut sink) = match sink.cmp(&source) {
|
|
||||||
Ordering::Greater => {
|
|
||||||
let source = used_wires.get(&source).unwrap().lock().unwrap();
|
|
||||||
let sink = used_wires.get(&sink).unwrap().lock().unwrap();
|
|
||||||
(source, sink)
|
|
||||||
}
|
|
||||||
Ordering::Equal => return false,
|
|
||||||
Ordering::Less => {
|
|
||||||
let sink = used_wires.get(&sink).unwrap().lock().unwrap();
|
|
||||||
let source = used_wires.get(&source).unwrap().lock().unwrap();
|
|
||||||
(source, sink)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut candidate = used_pips.get(pip).unwrap().lock().unwrap();
|
|
||||||
if candidate.map(|net| net != arc.net()).unwrap_or(false) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if source.map(|net| net != arc.net()).unwrap_or(false) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if sink.map(|net| net != arc.net()).unwrap_or(false) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
*candidate = Some(arc.net());
|
|
||||||
*source = Some(arc.net());
|
|
||||||
*sink = Some(arc.net());
|
|
||||||
|
|
||||||
true
|
|
||||||
})
|
|
||||||
.expect("unable to find a pip");
|
|
||||||
pip_uses.fetch_add(1, std::sync::atomic::Ordering::Release);
|
|
||||||
*selected_pip
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut explored_pips = AtomicUsize::new(0);
|
let mut explored_pips = AtomicUsize::new(0);
|
||||||
|
|
||||||
@ -510,15 +316,9 @@ fn partition<R: RangeBounds<i32>>(
|
|||||||
if middle.1 == y {
|
if middle.1 == y {
|
||||||
middle.1 = y + 1;
|
middle.1 = y + 1;
|
||||||
}
|
}
|
||||||
let pips = match (source_is_north, source_is_east) {
|
|
||||||
(true, false) => &pips_s_w,
|
|
||||||
(false, false) => &pips_n_w,
|
|
||||||
(true, true) => &pips_s_e,
|
|
||||||
(false, true) => &pips_n_e,
|
|
||||||
};
|
|
||||||
|
|
||||||
let selected_pip = find_best_pip(pips, arc);
|
let selected_pip =
|
||||||
explored_pips.fetch_add(pips.len(), std::sync::atomic::Ordering::Relaxed);
|
pip_selector.find_pip(ctx, middle.into(), source_loc, arc.net());
|
||||||
|
|
||||||
if verbose {
|
if verbose {
|
||||||
log_info!(
|
log_info!(
|
||||||
@ -556,15 +356,8 @@ fn partition<R: RangeBounds<i32>>(
|
|||||||
middle.0 = x + 1;
|
middle.0 = x + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
let pips = match (source_is_east, source_is_north) {
|
let selected_pip =
|
||||||
(true, false) => &pips_w_s,
|
pip_selector.find_pip(ctx, middle.into(), source_loc, arc.net());
|
||||||
(false, false) => &pips_e_s,
|
|
||||||
(true, true) => &pips_w_n,
|
|
||||||
(false, true) => &pips_e_n,
|
|
||||||
};
|
|
||||||
|
|
||||||
let selected_pip = find_best_pip(pips, arc);
|
|
||||||
explored_pips.fetch_add(pips.len(), std::sync::atomic::Ordering::Relaxed);
|
|
||||||
|
|
||||||
if verbose {
|
if verbose {
|
||||||
log_info!(
|
log_info!(
|
||||||
@ -603,8 +396,6 @@ fn partition<R: RangeBounds<i32>>(
|
|||||||
middle_vert.1.clamp(1, ctx.grid_dim_y() - 1),
|
middle_vert.1.clamp(1, ctx.grid_dim_y() - 1),
|
||||||
);
|
);
|
||||||
|
|
||||||
let horiz_happens_first = (middle_horiz.1 < y) == source_is_east;
|
|
||||||
|
|
||||||
// need to avoid the partition point
|
// need to avoid the partition point
|
||||||
if middle_horiz.1 == y || middle_vert.0 == x {
|
if middle_horiz.1 == y || middle_vert.0 == x {
|
||||||
if source_is_east != sink_is_north {
|
if source_is_east != sink_is_north {
|
||||||
@ -615,35 +406,34 @@ fn partition<R: RangeBounds<i32>>(
|
|||||||
middle_vert.0 = x + 1;
|
middle_vert.0 = x + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
let horiz_happens_first = (middle_horiz.1 < y) == source_is_east;
|
||||||
|
|
||||||
let pips = match (source_is_north, source_is_east, horiz_happens_first) {
|
let (horiz_pip, vert_pip) = if horiz_happens_first {
|
||||||
(true, false, true) => &pips_s_w,
|
let horiz =
|
||||||
(false, false, true) => &pips_n_w,
|
pip_selector.find_pip(ctx, middle_horiz.into(), source_loc, arc.net());
|
||||||
(true, true, true) => &pips_s_e,
|
(
|
||||||
(false, true, true) => &pips_n_e,
|
horiz,
|
||||||
(true, false, false) => &pips_s_e,
|
pip_selector.find_pip(
|
||||||
(false, false, false) => &pips_n_e,
|
ctx,
|
||||||
(true, true, false) => &pips_s_w,
|
middle_vert.into(),
|
||||||
(false, true, false) => &pips_n_w,
|
middle_horiz.into(),
|
||||||
|
arc.net(),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
let vert =
|
||||||
|
pip_selector.find_pip(ctx, middle_vert.into(), source_loc, arc.net());
|
||||||
|
(
|
||||||
|
pip_selector.find_pip(
|
||||||
|
ctx,
|
||||||
|
middle_horiz.into(),
|
||||||
|
middle_vert.into(),
|
||||||
|
arc.net(),
|
||||||
|
),
|
||||||
|
vert,
|
||||||
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
let horiz_pip = find_best_pip(pips, arc);
|
|
||||||
explored_pips.fetch_add(pips.len(), std::sync::atomic::Ordering::Relaxed);
|
|
||||||
|
|
||||||
let pips = match (source_is_east, source_is_north, horiz_happens_first) {
|
|
||||||
(true, false, true) => &pips_w_n,
|
|
||||||
(false, false, true) => &pips_e_n,
|
|
||||||
(true, true, true) => &pips_w_s,
|
|
||||||
(false, true, true) => &pips_e_s,
|
|
||||||
(true, false, false) => &pips_w_s,
|
|
||||||
(false, false, false) => &pips_e_s,
|
|
||||||
(true, true, false) => &pips_w_n,
|
|
||||||
(false, true, false) => &pips_e_n,
|
|
||||||
};
|
|
||||||
|
|
||||||
let vert_pip = find_best_pip(pips, arc);
|
|
||||||
explored_pips.fetch_add(pips.len(), std::sync::atomic::Ordering::Relaxed);
|
|
||||||
|
|
||||||
if verbose {
|
if verbose {
|
||||||
log_info!(
|
log_info!(
|
||||||
"split arc {} to {} across pips {} and {}\n",
|
"split arc {} to {} across pips {} and {}\n",
|
||||||
@ -713,8 +503,6 @@ fn partition<R: RangeBounds<i32>>(
|
|||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
let overuse = overuse.into_inner().unwrap();
|
|
||||||
|
|
||||||
for (segment, arc) in arcs {
|
for (segment, arc) in arcs {
|
||||||
match segment {
|
match segment {
|
||||||
Segment::Northeast => ne.push(arc),
|
Segment::Northeast => ne.push(arc),
|
||||||
@ -898,3 +686,278 @@ pub fn find_partition_point_and_sanity_check(
|
|||||||
|
|
||||||
(x_part, y_part, ne, se, sw, nw)
|
(x_part, y_part, ne, se, sw, nw)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct PipSelector {
|
||||||
|
used_pips: HashMap<npnr::PipId, Mutex<Option<npnr::NetIndex>>>,
|
||||||
|
used_wires: HashMap<npnr::WireId, Mutex<Option<npnr::NetIndex>>>,
|
||||||
|
|
||||||
|
// first direction: where is this pip going
|
||||||
|
// second direction: where is this pip located
|
||||||
|
pips_n_e: Vec<npnr::PipId>,
|
||||||
|
pips_e_n: Vec<npnr::PipId>,
|
||||||
|
pips_s_e: Vec<npnr::PipId>,
|
||||||
|
pips_w_n: Vec<npnr::PipId>,
|
||||||
|
pips_n_w: Vec<npnr::PipId>,
|
||||||
|
pips_e_s: Vec<npnr::PipId>,
|
||||||
|
pips_s_w: Vec<npnr::PipId>,
|
||||||
|
pips_w_s: Vec<npnr::PipId>,
|
||||||
|
|
||||||
|
partition_loc: npnr::Loc,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PipSelector {
|
||||||
|
fn new<R: RangeBounds<i32>>(
|
||||||
|
ctx: &npnr::Context,
|
||||||
|
pips: &[npnr::PipId],
|
||||||
|
bounds: (R, R),
|
||||||
|
partition_point: npnr::Loc,
|
||||||
|
) -> Self {
|
||||||
|
let mut pips_n_e = vec![];
|
||||||
|
let mut pips_e_n = vec![];
|
||||||
|
let mut pips_s_e = vec![];
|
||||||
|
let mut pips_w_n = vec![];
|
||||||
|
let mut pips_n_w = vec![];
|
||||||
|
let mut pips_e_s = vec![];
|
||||||
|
let mut pips_s_w = vec![];
|
||||||
|
let mut pips_w_s = vec![];
|
||||||
|
|
||||||
|
let mut candidates = 0;
|
||||||
|
let mut north = 0;
|
||||||
|
let mut east = 0;
|
||||||
|
let mut south = 0;
|
||||||
|
let mut west = 0;
|
||||||
|
for &pip in pips {
|
||||||
|
let loc = ctx.pip_location(pip);
|
||||||
|
if (loc.x == partition_point.x || loc.y == partition_point.y)
|
||||||
|
&& bounds.0.contains(&loc.x)
|
||||||
|
&& bounds.1.contains(&loc.y)
|
||||||
|
{
|
||||||
|
//correctly classifying the pips on the partition point is pretty much impossible
|
||||||
|
//just avoid the partition point
|
||||||
|
if loc.x == partition_point.x && loc.y == partition_point.y {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let is_general_routing = |wire: &str| {
|
||||||
|
wire.contains("H01")
|
||||||
|
|| wire.contains("V01")
|
||||||
|
|| wire.contains("H02")
|
||||||
|
|| wire.contains("V02")
|
||||||
|
|| wire.contains("H06")
|
||||||
|
|| wire.contains("V06")
|
||||||
|
};
|
||||||
|
|
||||||
|
let src_wire = ctx.pip_src_wire(pip);
|
||||||
|
let dst_wire = ctx.pip_dst_wire(pip);
|
||||||
|
let src_name = ctx.name_of_wire(src_wire).to_str().unwrap();
|
||||||
|
let dst_name = ctx.name_of_wire(dst_wire).to_str().unwrap();
|
||||||
|
if !is_general_routing(src_name) || !is_general_routing(dst_name) {
|
||||||
|
// ECP5 hack: whitelist allowed wires.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
candidates += 1;
|
||||||
|
|
||||||
|
if loc.y == partition_point.y {
|
||||||
|
// pip is on east-west border
|
||||||
|
|
||||||
|
let (mut src_has_east, mut src_has_west, mut src_has_middle) =
|
||||||
|
(false, false, false);
|
||||||
|
let (mut dst_has_east, mut dst_has_west, mut dst_has_middle) =
|
||||||
|
(false, false, false);
|
||||||
|
|
||||||
|
for src_pip in ctx.get_uphill_pips(ctx.pip_src_wire(pip)) {
|
||||||
|
let src_pip_coord: Coord = ctx.pip_location(src_pip).into();
|
||||||
|
if (src_pip_coord.x < partition_point.x) == (loc.x < partition_point.x) {
|
||||||
|
src_has_middle |= src_pip_coord.y == loc.y;
|
||||||
|
src_has_east |= src_pip_coord.is_east_of(&partition_point.into());
|
||||||
|
src_has_west |= src_pip_coord.is_west_of(&partition_point.into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for dst_pip in ctx.get_downhill_pips(ctx.pip_dst_wire(pip)) {
|
||||||
|
let dst_pip_coord: Coord = ctx.pip_location(dst_pip).into();
|
||||||
|
if (dst_pip_coord.x < partition_point.x) == (loc.x < partition_point.x) {
|
||||||
|
dst_has_middle |= dst_pip_coord.y == loc.y;
|
||||||
|
dst_has_east |= dst_pip_coord.is_east_of(&partition_point.into());
|
||||||
|
dst_has_west |= dst_pip_coord.is_west_of(&partition_point.into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (src_has_east && (dst_has_west || dst_has_middle))
|
||||||
|
|| (src_has_middle && dst_has_west)
|
||||||
|
{
|
||||||
|
west += 1;
|
||||||
|
if loc.x < partition_point.x {
|
||||||
|
pips_w_n.push(pip);
|
||||||
|
} else {
|
||||||
|
pips_w_s.push(pip);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (src_has_west && (dst_has_east || dst_has_middle))
|
||||||
|
|| (src_has_middle && dst_has_east)
|
||||||
|
{
|
||||||
|
east += 1;
|
||||||
|
if loc.x < partition_point.x {
|
||||||
|
pips_e_n.push(pip);
|
||||||
|
} else {
|
||||||
|
pips_e_s.push(pip);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// pip is on south-north border
|
||||||
|
|
||||||
|
let (mut src_has_north, mut src_has_south, mut src_has_middle) =
|
||||||
|
(false, false, false);
|
||||||
|
let (mut dst_has_north, mut dst_has_south, mut dst_has_middle) =
|
||||||
|
(false, false, false);
|
||||||
|
|
||||||
|
for src_pip in ctx.get_uphill_pips(ctx.pip_src_wire(pip)) {
|
||||||
|
let src_pip_coord: Coord = ctx.pip_location(src_pip).into();
|
||||||
|
if (src_pip_coord.y < partition_point.y) == (loc.y < partition_point.y) {
|
||||||
|
src_has_middle |= src_pip_coord.x == loc.x;
|
||||||
|
src_has_north |= src_pip_coord.is_north_of(&partition_point.into());
|
||||||
|
src_has_south |= src_pip_coord.is_south_of(&partition_point.into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for dst_pip in ctx.get_downhill_pips(ctx.pip_dst_wire(pip)) {
|
||||||
|
let dst_pip_coord: Coord = ctx.pip_location(dst_pip).into();
|
||||||
|
if (dst_pip_coord.y < partition_point.y) == (loc.y < partition_point.y) {
|
||||||
|
dst_has_middle |= dst_pip_coord.x == loc.x;
|
||||||
|
dst_has_north |= dst_pip_coord.is_north_of(&partition_point.into());
|
||||||
|
dst_has_south |= dst_pip_coord.is_south_of(&partition_point.into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (src_has_north && (dst_has_south || dst_has_middle))
|
||||||
|
|| (src_has_middle && dst_has_south)
|
||||||
|
{
|
||||||
|
south += 1;
|
||||||
|
if loc.y < partition_point.y {
|
||||||
|
pips_s_e.push(pip);
|
||||||
|
} else {
|
||||||
|
pips_s_w.push(pip);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (src_has_south && (dst_has_north || dst_has_middle))
|
||||||
|
|| (src_has_middle && dst_has_north)
|
||||||
|
{
|
||||||
|
north += 1;
|
||||||
|
if loc.y < partition_point.y {
|
||||||
|
pips_n_e.push(pip);
|
||||||
|
} else {
|
||||||
|
pips_n_w.push(pip);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log_info!(
|
||||||
|
" Out of {} candidate pips:\n",
|
||||||
|
candidates.to_string().bold()
|
||||||
|
);
|
||||||
|
log_info!(" {} are north-bound\n", north.to_string().bold());
|
||||||
|
log_info!(" {} are east-bound\n", east.to_string().bold());
|
||||||
|
log_info!(" {} are south-bound\n", south.to_string().bold());
|
||||||
|
log_info!(" {} are west-bound\n", west.to_string().bold());
|
||||||
|
|
||||||
|
let mut used_pips = HashMap::with_capacity(pips.len());
|
||||||
|
let mut used_wires = HashMap::new();
|
||||||
|
|
||||||
|
let selected_pips = pips_n_e
|
||||||
|
.iter()
|
||||||
|
.chain(pips_e_n.iter())
|
||||||
|
.chain(pips_e_s.iter())
|
||||||
|
.chain(pips_s_e.iter())
|
||||||
|
.chain(pips_s_w.iter())
|
||||||
|
.chain(pips_w_s.iter())
|
||||||
|
.chain(pips_w_n.iter())
|
||||||
|
.chain(pips_n_w.iter());
|
||||||
|
|
||||||
|
for pip in selected_pips {
|
||||||
|
used_pips.insert(*pip, Mutex::new(None));
|
||||||
|
used_wires.insert(ctx.pip_src_wire(*pip), Mutex::new(None));
|
||||||
|
used_wires.insert(ctx.pip_dst_wire(*pip), Mutex::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,
|
||||||
|
partition_loc: partition_point,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// finds a pip hopefully close to `desired_pip_location` which has a source accessable from `coming_from`
|
||||||
|
fn find_pip(
|
||||||
|
&self,
|
||||||
|
ctx: &npnr::Context,
|
||||||
|
desired_pip_location: npnr::Loc,
|
||||||
|
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 selected_pip = pips
|
||||||
|
.iter()
|
||||||
|
.find(|&pip| {
|
||||||
|
let source = ctx.pip_src_wire(*pip);
|
||||||
|
let sink = ctx.pip_dst_wire(*pip);
|
||||||
|
|
||||||
|
let (mut source, mut sink) = match sink.cmp(&source) {
|
||||||
|
Ordering::Greater => {
|
||||||
|
let source = self.used_wires.get(&source).unwrap().lock().unwrap();
|
||||||
|
let sink = self.used_wires.get(&sink).unwrap().lock().unwrap();
|
||||||
|
(source, sink)
|
||||||
|
}
|
||||||
|
Ordering::Equal => return false,
|
||||||
|
Ordering::Less => {
|
||||||
|
let sink = self.used_wires.get(&sink).unwrap().lock().unwrap();
|
||||||
|
let source = self.used_wires.get(&source).unwrap().lock().unwrap();
|
||||||
|
(source, sink)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut candidate = self.used_pips.get(pip).unwrap().lock().unwrap();
|
||||||
|
if candidate.map(|other| other != net).unwrap_or(false) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if source.map(|other| other != net).unwrap_or(false) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if sink.map(|other| other != net).unwrap_or(false) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
*candidate = Some(net);
|
||||||
|
*source = Some(net);
|
||||||
|
*sink = Some(net);
|
||||||
|
|
||||||
|
true
|
||||||
|
})
|
||||||
|
.expect("unable to find a pip");
|
||||||
|
|
||||||
|
*selected_pip
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user