make a theoretically correct partitioner
This commit is contained in:
parent
483e42d5e7
commit
6f940d29b9
@ -1,4 +1,8 @@
|
|||||||
use std::{collections::{HashMap, HashSet}, ops::RangeBounds, sync::{atomic::AtomicUsize, Mutex}};
|
use std::{
|
||||||
|
collections::{HashMap, HashSet},
|
||||||
|
ops::RangeBounds,
|
||||||
|
sync::{atomic::AtomicUsize, Mutex},
|
||||||
|
};
|
||||||
|
|
||||||
use colored::Colorize;
|
use colored::Colorize;
|
||||||
use indicatif::{ParallelProgressIterator, ProgressBar, ProgressStyle};
|
use indicatif::{ParallelProgressIterator, ProgressBar, ProgressStyle};
|
||||||
@ -215,10 +219,16 @@ fn partition<R: RangeBounds<i32>>(
|
|||||||
) -> (Vec<Arc>, Vec<Arc>, 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);
|
||||||
|
|
||||||
let mut pips_n = HashMap::new();
|
// first direction: where is this pip going
|
||||||
let mut pips_e = HashMap::new();
|
// second direction: where is this pip located
|
||||||
let mut pips_s = HashMap::new();
|
let mut pips_n_e = Vec::new();
|
||||||
let mut pips_w = HashMap::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();
|
||||||
@ -275,14 +285,15 @@ fn partition<R: RangeBounds<i32>>(
|
|||||||
if loc.y == y {
|
if loc.y == y {
|
||||||
// pip is on east-west border
|
// pip is on east-west border
|
||||||
|
|
||||||
let src_has_east = src_name.contains('E');
|
let (mut src_has_east, mut src_has_west, mut src_has_middle) =
|
||||||
let src_has_west = src_name.contains('W');
|
(false, false, false);
|
||||||
let dst_has_east = dst_name.contains('E');
|
let (mut dst_has_east, mut dst_has_west, mut dst_has_middle) =
|
||||||
let dst_has_west = dst_name.contains('W');
|
(false, false, false);
|
||||||
|
|
||||||
/*for src_pip in ctx.get_uphill_pips(ctx.pip_src_wire(pip)) {
|
for src_pip in ctx.get_uphill_pips(ctx.pip_src_wire(pip)) {
|
||||||
let src_pip_coord: Coord = ctx.pip_location(src_pip).into();
|
let src_pip_coord: Coord = ctx.pip_location(src_pip).into();
|
||||||
if (src_pip_coord.x < x) == (loc.x < x) {
|
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_east |= src_pip_coord.is_east_of(&partition_coords);
|
||||||
src_has_west |= src_pip_coord.is_west_of(&partition_coords);
|
src_has_west |= src_pip_coord.is_west_of(&partition_coords);
|
||||||
}
|
}
|
||||||
@ -290,45 +301,74 @@ fn partition<R: RangeBounds<i32>>(
|
|||||||
for dst_pip in ctx.get_downhill_pips(ctx.pip_dst_wire(pip)) {
|
for dst_pip in ctx.get_downhill_pips(ctx.pip_dst_wire(pip)) {
|
||||||
let dst_pip_coord: Coord = ctx.pip_location(dst_pip).into();
|
let dst_pip_coord: Coord = ctx.pip_location(dst_pip).into();
|
||||||
if (dst_pip_coord.x < x) == (loc.x < x) {
|
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_east |= dst_pip_coord.is_east_of(&partition_coords);
|
||||||
dst_has_west |= dst_pip_coord.is_west_of(&partition_coords);
|
dst_has_west |= dst_pip_coord.is_west_of(&partition_coords);
|
||||||
}
|
}
|
||||||
}*/
|
|
||||||
if dst_has_west {
|
|
||||||
west += 1;
|
|
||||||
pips_w
|
|
||||||
.entry((loc.x, loc.y))
|
|
||||||
.or_insert(vec![])
|
|
||||||
.push(pip_arc.clone());
|
|
||||||
}
|
}
|
||||||
if dst_has_east {
|
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;
|
east += 1;
|
||||||
pips_e
|
if loc.x < x {
|
||||||
.entry((loc.x, loc.y))
|
pips_e_n.push(pip_arc.clone());
|
||||||
.or_insert(vec![])
|
} else {
|
||||||
.push(pip_arc.clone());
|
pips_e_s.push(pip_arc.clone());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// pip is on south-north border
|
// pip is on south-north border
|
||||||
|
|
||||||
let src_has_north = src_name.contains('N');
|
let (mut src_has_north, mut src_has_south, mut src_has_middle) =
|
||||||
let src_has_south = src_name.contains('S');
|
(false, false, false);
|
||||||
let dst_has_north = dst_name.contains('N');
|
let (mut dst_has_north, mut dst_has_south, mut dst_has_middle) =
|
||||||
let dst_has_south = dst_name.contains('S');
|
(false, false, false);
|
||||||
|
|
||||||
if dst_has_south {
|
for src_pip in ctx.get_uphill_pips(ctx.pip_src_wire(pip)) {
|
||||||
south += 1;
|
let src_pip_coord: Coord = ctx.pip_location(src_pip).into();
|
||||||
pips_s
|
if (src_pip_coord.y < y) == (loc.y < y) {
|
||||||
.entry((loc.x, loc.y))
|
src_has_middle |= src_pip_coord.x == loc.x;
|
||||||
.or_insert(vec![])
|
src_has_north |= src_pip_coord.is_north_of(&partition_coords);
|
||||||
.push(pip_arc.clone());
|
src_has_south |= src_pip_coord.is_south_of(&partition_coords);
|
||||||
}
|
}
|
||||||
if dst_has_north {
|
}
|
||||||
|
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;
|
north += 1;
|
||||||
pips_n
|
if loc.y < y {
|
||||||
.entry((loc.x, loc.y))
|
pips_n_e.push(pip_arc.clone());
|
||||||
.or_insert(vec![])
|
} else {
|
||||||
.push(pip_arc.clone());
|
pips_n_w.push(pip_arc.clone());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -342,11 +382,31 @@ fn partition<R: RangeBounds<i32>>(
|
|||||||
log_info!(" {} are south-bound\n", south.to_string().bold());
|
log_info!(" {} are south-bound\n", south.to_string().bold());
|
||||||
log_info!(" {} are west-bound\n", west.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 is_special_case = |arc: &Arc| {
|
let is_special_case = |arc: &Arc| {
|
||||||
let src_name = ctx.name_of_wire(arc.get_source_wire()).to_str().unwrap();
|
let src_name = ctx.name_of_wire(arc.get_source_wire()).to_str().unwrap();
|
||||||
let dst_name = ctx.name_of_wire(arc.get_sink_wire()).to_str().unwrap();
|
let dst_name = ctx.name_of_wire(arc.get_sink_wire()).to_str().unwrap();
|
||||||
|
|
||||||
if src_name.contains("FCO_SLICE") || src_name.contains('J') || src_name.contains("DDR") || dst_name.contains("DDR") {
|
if src_name.contains("FCO_SLICE")
|
||||||
|
|| src_name.contains('J')
|
||||||
|
|| src_name.contains("DDR")
|
||||||
|
|| dst_name.contains("DDR")
|
||||||
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -355,18 +415,50 @@ fn partition<R: RangeBounds<i32>>(
|
|||||||
|
|
||||||
let mut congestion = HashMap::new();
|
let mut congestion = HashMap::new();
|
||||||
|
|
||||||
let find_best_pip = |pips: &Vec<std::sync::Arc<(npnr::PipId, AtomicUsize)>>, arc: &Arc, congestion: &HashMap<npnr::WireId, i32>| {
|
let used_pips = Mutex::new(HashMap::new());
|
||||||
|
let used_sinks = Mutex::new(HashMap::new());
|
||||||
|
let used_sources = Mutex::new(HashMap::new());
|
||||||
|
|
||||||
|
let find_best_pip = |pips: &Vec<std::sync::Arc<(npnr::PipId, AtomicUsize)>>,
|
||||||
|
arc: &Arc,
|
||||||
|
congestion: &HashMap<npnr::WireId, i32>| {
|
||||||
let (selected_pip, pip_uses) = pips
|
let (selected_pip, pip_uses) = pips
|
||||||
.iter()
|
.iter()
|
||||||
.map(|a| a.as_ref())
|
.map(|a| a.as_ref())
|
||||||
.min_by_key(|(pip, uses)| {
|
.find(|(pip, uses)| {
|
||||||
let src_to_pip = ctx.estimate_delay(arc.get_source_wire(), ctx.pip_src_wire(*pip));
|
let source = ctx.pip_src_wire(*pip);
|
||||||
let pip_to_snk = ctx.estimate_delay(ctx.pip_dst_wire(*pip), arc.get_sink_wire());
|
let sink = ctx.pip_dst_wire(*pip);
|
||||||
let uses = uses.load(std::sync::atomic::Ordering::Acquire);
|
let used_pips = used_pips.lock().unwrap();
|
||||||
let congestion = *congestion.get(&arc.get_sink_wire()).unwrap_or(&0) as f32;
|
let used_sinks = used_sinks.lock().unwrap();
|
||||||
(1000.0 * (src_to_pip + ((uses + 1) as f32) * (pip_to_snk + congestion))) as u64
|
let used_sources = used_sources.lock().unwrap();
|
||||||
|
if used_pips.get(pip).map(|v| *v != arc.net()).unwrap_or(false) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if used_sinks
|
||||||
|
.get(&source)
|
||||||
|
.map(|v| *v != arc.net())
|
||||||
|
.unwrap_or(false)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if used_sources
|
||||||
|
.get(&sink)
|
||||||
|
.map(|v| *v != arc.net())
|
||||||
|
.unwrap_or(false)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
true
|
||||||
})
|
})
|
||||||
.unwrap();
|
.expect("unable to find a pip");
|
||||||
|
let source = ctx.pip_src_wire(*selected_pip);
|
||||||
|
let sink = ctx.pip_dst_wire(*selected_pip);
|
||||||
|
let mut used_pips = used_pips.lock().unwrap();
|
||||||
|
let mut used_sinks = used_sinks.lock().unwrap();
|
||||||
|
let mut used_sources = used_sources.lock().unwrap();
|
||||||
|
used_pips.insert(*selected_pip, arc.net());
|
||||||
|
used_sinks.insert(source, arc.net());
|
||||||
|
used_sources.insert(sink, arc.net());
|
||||||
pip_uses.fetch_add(1, std::sync::atomic::Ordering::Release);
|
pip_uses.fetch_add(1, std::sync::atomic::Ordering::Release);
|
||||||
*selected_pip
|
*selected_pip
|
||||||
};
|
};
|
||||||
@ -422,9 +514,11 @@ 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 {
|
let pips = match (source_is_north, source_is_east) {
|
||||||
true => pips_s.get(&middle).unwrap(),
|
(true, false) => &pips_s_w,
|
||||||
false => pips_n.get(&middle).unwrap(),
|
(false, false) => &pips_n_w,
|
||||||
|
(true, true) => &pips_s_e,
|
||||||
|
(false, true) => &pips_n_e,
|
||||||
};
|
};
|
||||||
|
|
||||||
let selected_pip = find_best_pip(pips, arc, &congestion);
|
let selected_pip = find_best_pip(pips, arc, &congestion);
|
||||||
@ -465,9 +559,11 @@ fn partition<R: RangeBounds<i32>>(
|
|||||||
if middle.0 == x {
|
if middle.0 == x {
|
||||||
middle.0 = x + 1;
|
middle.0 = x + 1;
|
||||||
}
|
}
|
||||||
let pips = match source_is_east {
|
let pips = match (source_is_east, source_is_north) {
|
||||||
true => pips_w.get(&middle).unwrap(),
|
(true, false) => &pips_w_s,
|
||||||
false => pips_e.get(&middle).unwrap(),
|
(false, false) => &pips_e_s,
|
||||||
|
(true, true) => &pips_w_n,
|
||||||
|
(false, true) => &pips_e_n,
|
||||||
};
|
};
|
||||||
|
|
||||||
let selected_pip = find_best_pip(pips, arc, &congestion);
|
let selected_pip = find_best_pip(pips, arc, &congestion);
|
||||||
@ -521,17 +617,22 @@ fn partition<R: RangeBounds<i32>>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let pips = match source_is_north {
|
let pips = match (source_is_north, source_is_east) {
|
||||||
true => pips_s.get(&middle_horiz).unwrap(),
|
(true, false) => &pips_s_w,
|
||||||
false => pips_n.get(&middle_horiz).unwrap(),
|
(false, false) => &pips_n_w,
|
||||||
|
(true, true) => &pips_s_e,
|
||||||
|
(false, true) => &pips_n_e,
|
||||||
};
|
};
|
||||||
|
|
||||||
let horiz_pip = find_best_pip(pips, arc, &congestion);
|
let horiz_pip = find_best_pip(pips, arc, &congestion);
|
||||||
explored_pips.fetch_add(pips.len(), std::sync::atomic::Ordering::Relaxed);
|
explored_pips.fetch_add(pips.len(), std::sync::atomic::Ordering::Relaxed);
|
||||||
|
|
||||||
let pips = match source_is_east {
|
let pips = match (source_is_east, source_is_north) {
|
||||||
true => pips_w.get(&middle_vert).unwrap(),
|
// horiz pip forced to happen first, so we are now on ther other side of the north/south border
|
||||||
false => pips_e.get(&middle_vert).unwrap(),
|
(true, false) => &pips_w_n,
|
||||||
|
(false, false) => &pips_e_n,
|
||||||
|
(true, true) => &pips_w_s,
|
||||||
|
(false, true) => &pips_e_s,
|
||||||
};
|
};
|
||||||
|
|
||||||
let vert_pip = find_best_pip(pips, arc, &congestion);
|
let vert_pip = find_best_pip(pips, arc, &congestion);
|
||||||
@ -561,38 +662,23 @@ fn partition<R: RangeBounds<i32>>(
|
|||||||
|
|
||||||
let horiz_loc: Coord = ctx.pip_location(horiz_pip).into();
|
let horiz_loc: Coord = ctx.pip_location(horiz_pip).into();
|
||||||
let horiz_is_east = horiz_loc.is_east_of(&partition_coords);
|
let horiz_is_east = horiz_loc.is_east_of(&partition_coords);
|
||||||
let (src_to_mid1, mid1_to_mid2, mid2_to_dst) = if horiz_is_east == source_is_east {
|
let (src_to_mid1, mid1_to_mid2, mid2_to_dst) = {
|
||||||
let (a, b) = arc.split(ctx, horiz_pip);
|
let (a, b) = arc.split(ctx, horiz_pip);
|
||||||
let (b, c) = b.split(ctx, vert_pip);
|
let (b, c) = b.split(ctx, vert_pip);
|
||||||
(a, b, c)
|
(a, b, c)
|
||||||
} else {
|
|
||||||
let (a, b) = arc.split(ctx, vert_pip);
|
|
||||||
let (b, c) = b.split(ctx, horiz_pip);
|
|
||||||
(a, b, c)
|
|
||||||
};
|
};
|
||||||
let (seg1, seg2, seg3) = match (source_is_north, source_is_east, horiz_is_east) {
|
|
||||||
(true, true, true) => {
|
let (seg1, seg2, seg3) = match (source_is_north, source_is_east) {
|
||||||
|
(true, true) => {
|
||||||
(Segment::Northeast, Segment::Southeast, Segment::Southwest)
|
(Segment::Northeast, Segment::Southeast, Segment::Southwest)
|
||||||
}
|
}
|
||||||
(true, true, false) => {
|
(true, false) => {
|
||||||
(Segment::Northeast, Segment::Northwest, Segment::Southwest)
|
|
||||||
}
|
|
||||||
(true, false, true) => {
|
|
||||||
(Segment::Northwest, Segment::Northeast, Segment::Southeast)
|
|
||||||
}
|
|
||||||
(true, false, false) => {
|
|
||||||
(Segment::Northwest, Segment::Southwest, Segment::Southeast)
|
(Segment::Northwest, Segment::Southwest, Segment::Southeast)
|
||||||
}
|
}
|
||||||
(false, true, true) => {
|
(false, true) => {
|
||||||
(Segment::Southeast, Segment::Northeast, Segment::Northwest)
|
(Segment::Southeast, Segment::Northeast, Segment::Northwest)
|
||||||
}
|
}
|
||||||
(false, true, false) => {
|
(false, false) => {
|
||||||
(Segment::Southeast, Segment::Southwest, Segment::Northwest)
|
|
||||||
}
|
|
||||||
(false, false, true) => {
|
|
||||||
(Segment::Southwest, Segment::Southeast, Segment::Northeast)
|
|
||||||
}
|
|
||||||
(false, false, false) => {
|
|
||||||
(Segment::Southwest, Segment::Northwest, Segment::Northeast)
|
(Segment::Southwest, Segment::Northwest, Segment::Northeast)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -618,16 +704,6 @@ fn partition<R: RangeBounds<i32>>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
overused_wires = 0;
|
overused_wires = 0;
|
||||||
for (wire, usage) in overuse {
|
|
||||||
if usage > 1 {
|
|
||||||
overused_wires += 1;
|
|
||||||
if let Some(entry) = congestion.get_mut(&wire) {
|
|
||||||
*entry += usage;
|
|
||||||
} else {
|
|
||||||
congestion.insert(wire, usage);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
log_info!(
|
log_info!(
|
||||||
@ -720,10 +796,7 @@ fn partition<R: RangeBounds<i32>>(
|
|||||||
}),
|
}),
|
||||||
dist_str(nw_dist)
|
dist_str(nw_dist)
|
||||||
);
|
);
|
||||||
log_info!(
|
log_info!(" {} arcs special-cased\n", misc.len().to_string().bold());
|
||||||
" {} arcs special-cased\n",
|
|
||||||
misc.len().to_string().bold()
|
|
||||||
);
|
|
||||||
|
|
||||||
(ne, se, sw, nw, misc)
|
(ne, se, sw, nw, misc)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user