make partitioner handle arcs with no locations

This commit is contained in:
SpaceCat-Chan 2023-03-11 13:51:32 +01:00 committed by Lofty
parent da2892fc28
commit 0bc945fbc3
5 changed files with 402 additions and 297 deletions

56
Cargo.lock generated
View File

@ -24,6 +24,7 @@ name = "awooter"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"colored", "colored",
"enumflags2",
"indicatif", "indicatif",
"itertools", "itertools",
"libc", "libc",
@ -116,6 +117,26 @@ version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
[[package]]
name = "enumflags2"
version = "0.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e75d4cd21b95383444831539909fbb14b9dc3fdceb2a6f5d36577329a1f55ccb"
dependencies = [
"enumflags2_derive",
]
[[package]]
name = "enumflags2_derive"
version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f58dc3c5e468259f19f2d46304a6b28f1c3d034442e14b322d2b850e36f6d5ae"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]] [[package]]
name = "hermit-abi" name = "hermit-abi"
version = "0.1.19" version = "0.1.19"
@ -190,6 +211,24 @@ version = "0.3.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "15eb2c6e362923af47e13c23ca5afb859e83d54452c55b0b9ac763b8f7c1ac16" checksum = "15eb2c6e362923af47e13c23ca5afb859e83d54452c55b0b9ac763b8f7c1ac16"
[[package]]
name = "proc-macro2"
version = "1.0.51"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5d727cae5b39d21da60fa540906919ad737832fe0b1c165da3a34d6548c849d6"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b"
dependencies = [
"proc-macro2",
]
[[package]] [[package]]
name = "rayon" name = "rayon"
version = "1.6.0" version = "1.6.0"
@ -219,6 +258,17 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]]
name = "syn"
version = "1.0.107"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]] [[package]]
name = "terminal_size" name = "terminal_size"
version = "0.1.17" version = "0.1.17"
@ -229,6 +279,12 @@ dependencies = [
"winapi", "winapi",
] ]
[[package]]
name = "unicode-ident"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc"
[[package]] [[package]]
name = "unicode-width" name = "unicode-width"
version = "0.1.10" version = "0.1.10"

View File

@ -16,3 +16,4 @@ indicatif = { version = "0.17", features = ["rayon"] }
rayon = "1.6" rayon = "1.6"
colored = "2" colored = "2"
itertools = "0.10.5" itertools = "0.10.5"
enumflags2 = "0.7.5"

View File

@ -61,9 +61,9 @@ fn extract_arcs_from_nets(ctx: &npnr::Context, nets: &npnr::Nets) -> Vec<route::
for sink_wire in ctx.sink_wires(net, *sink_ref) { for sink_wire in ctx.sink_wires(net, *sink_ref) {
arcs.push(route::Arc::new( arcs.push(route::Arc::new(
source_wire, source_wire,
source, Some(source),
sink_wire, sink_wire,
sink, Some(sink),
net.index(), net.index(),
nets.name_from_index(net.index()), nets.name_from_index(net.index()),
)); ));

View File

@ -5,6 +5,7 @@ use std::{
}; };
use colored::Colorize; use colored::Colorize;
use enumflags2::{bitflags, BitFlags};
use indicatif::{ParallelProgressIterator, ProgressBar, ProgressStyle}; use indicatif::{ParallelProgressIterator, ProgressBar, ProgressStyle};
use itertools::Itertools; use itertools::Itertools;
use rayon::prelude::*; use rayon::prelude::*;
@ -14,12 +15,52 @@ use crate::{
route::Arc, route::Arc,
}; };
#[bitflags]
#[repr(u8)]
#[derive(Clone, Copy, Debug, PartialEq, Eq)] #[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Quadrant { pub enum Quadrant {
Northeast, Northeast = 1,
Southeast, Southeast = 2,
Southwest, Southwest = 8,
Northwest, Northwest = 4,
}
impl Quadrant {
fn flip_east_west(self) -> Self {
match self {
Self::Northeast => Self::Northwest,
Self::Northwest => Self::Northeast,
Self::Southeast => Self::Southwest,
Self::Southwest => Self::Southeast,
}
}
fn flip_north_south(self) -> Self {
match self {
Self::Northeast => Self::Southeast,
Self::Northwest => Self::Southwest,
Self::Southeast => Self::Northeast,
Self::Southwest => Self::Northwest,
}
}
fn flip_diagonal(self) -> Self {
match self {
Self::Northeast => Self::Southwest,
Self::Northwest => Self::Southeast,
Self::Southeast => Self::Northwest,
Self::Southwest => Self::Northeast,
}
}
}
// manual bit fiddling because using .iter().map().collect() compiles down to a loop
fn flip_quads_north_south(q: BitFlags<Quadrant>) -> BitFlags<Quadrant> {
BitFlags::from_bits((q.bits() & 0b1010) >> 1 | (q.bits() & 0b0101) << 1).unwrap()
}
fn flip_quads_east_west(q: BitFlags<Quadrant>) -> BitFlags<Quadrant> {
BitFlags::from_bits((q.bits() & 0b1100) >> 2 | (q.bits() & 0b0011) << 2).unwrap()
}
fn flip_quads_diagonal(q: BitFlags<Quadrant>) -> BitFlags<Quadrant> {
BitFlags::from_bits(q.bits().reverse_bits() >> 4).unwrap()
} }
#[derive(Clone, Copy, Debug, PartialEq, Eq)] #[derive(Clone, Copy, Debug, PartialEq, Eq)]
@ -182,6 +223,7 @@ impl From<npnr::Loc> for Coord {
} }
} }
} }
impl Into<npnr::Loc> for Coord { impl Into<npnr::Loc> for Coord {
fn into(self) -> npnr::Loc { fn into(self) -> npnr::Loc {
npnr::Loc { npnr::Loc {
@ -192,6 +234,78 @@ impl Into<npnr::Loc> for Coord {
} }
} }
struct SegmentedArc {
arc: Arc,
source_quads: BitFlags<Quadrant>,
estimated_source_location: Coord,
sink_quads: BitFlags<Quadrant>,
estimated_sink_location: Coord,
}
impl SegmentedArc {
fn new(arc: Arc, partition_point: &Coord, ctx: &npnr::Context) -> Self {
let (source_quads, sum_source_pos, source_count) = if let Some(src) = arc.get_source_loc() {
let src: Coord = src.into();
(src.segment_from(partition_point).into(), src, 1)
} else {
ctx.get_uphill_pips(arc.source_wire())
.map(|pip| {
let c: Coord = ctx.pip_location(pip).into();
c
})
.fold(
(BitFlags::empty(), Coord::new(0, 0), 0),
|(quads, pos, count), c| {
(
quads | c.segment_from(partition_point),
Coord::new(pos.x + c.x, pos.y + c.y),
count + 1,
)
},
)
};
let (sink_quads, sum_sink_pos, sink_count) = if let Some(sink) = arc.get_sink_loc() {
let sink: Coord = sink.into();
(sink.segment_from(partition_point).into(), sink, 1)
} else {
ctx.get_downhill_pips(arc.sink_wire())
.map(|pip| {
let c: Coord = ctx.pip_location(pip).into();
c
})
.fold(
(BitFlags::empty(), Coord::new(0, 0), 0),
|(quads, pos, count), c| {
(
quads | c.segment_from(partition_point),
Coord::new(pos.x + c.x, pos.y + c.y),
count + 1,
)
},
)
};
assert!(
source_count != 0 && sink_count != 0,
"absolutely unroutable arc found"
);
Self {
arc,
source_quads,
estimated_source_location: Coord::new(
sum_source_pos.x / source_count,
sum_source_pos.y / source_count,
),
sink_quads,
estimated_sink_location: Coord::new(
sum_sink_pos.x / sink_count,
sum_sink_pos.y / sink_count,
),
}
}
}
pub fn find_partition_point( pub fn find_partition_point(
ctx: &npnr::Context, ctx: &npnr::Context,
nets: &npnr::Nets, nets: &npnr::Nets,
@ -207,8 +321,14 @@ pub fn find_partition_point(
let mut x_diff = 0; //(x_finish - x_start) / 4; let mut x_diff = 0; //(x_finish - x_start) / 4;
let mut y_diff = 0; //(y_finish - y_start) / 4; let mut y_diff = 0; //(y_finish - y_start) / 4;
// TODO(SpaceCat~Chan): chache more stuff involved in created SegmentedArc to avoid doing so much ffi?
while x_diff != 0 { while x_diff != 0 {
let (ne, se, sw, nw) = approximate_partition_results(arcs, (x, y)); let segmented_arcs = arcs
.iter()
.map(|arc| SegmentedArc::new(arc.clone(), &Coord::new(x, y), ctx))
.collect::<Vec<_>>();
let (ne, se, sw, nw) = approximate_partition_results(&segmented_arcs[..], (x, y));
let north = ne + nw; let north = ne + nw;
let south = se + sw; let south = se + sw;
@ -244,10 +364,15 @@ pub fn find_partition_point(
y_diff >>= 1; y_diff >>= 1;
} }
let segmented_arcs = arcs
.iter()
.map(|arc| SegmentedArc::new(arc.clone(), &Coord::new(x, y), ctx))
.collect::<Vec<_>>();
let (ne, se, sw, nw, special) = partition( let (ne, se, sw, nw, special) = partition(
ctx, ctx,
nets, nets,
arcs, &segmented_arcs[..],
pips, pips,
x, x,
y, y,
@ -273,7 +398,7 @@ pub fn find_partition_point(
} }
fn approximate_partition_results( fn approximate_partition_results(
arcs: &[Arc], arcs: &[SegmentedArc],
partition_point: (i32, i32), partition_point: (i32, i32),
) -> (usize, usize, usize, usize) { ) -> (usize, usize, usize, usize) {
let mut count_ne = 0; let mut count_ne = 0;
@ -282,66 +407,66 @@ fn approximate_partition_results(
let mut count_nw = 0; let mut count_nw = 0;
for arc in arcs { for arc in arcs {
// TODO(SpaceCat~Chan): stop being lazy and merge Loc and Coord already // TODO(SpaceCat~Chan): stop being lazy and merge Loc and Coord already
let source_is_north = arc.get_source_loc().x < partition_point.0; if !(arc.source_quads & arc.sink_quads).is_empty() {
let source_is_east = arc.get_source_loc().y < partition_point.1; match (arc.source_quads & arc.sink_quads).iter().next().unwrap() {
let sink_is_north = arc.get_sink_loc().x < partition_point.0; Quadrant::Northeast => count_ne += 1,
let sink_is_east = arc.get_sink_loc().y < partition_point.1; Quadrant::Southeast => count_se += 1,
if source_is_north == sink_is_north && source_is_east == sink_is_east { Quadrant::Southwest => count_sw += 1,
match (source_is_north, source_is_east) { Quadrant::Northwest => count_nw += 1,
(true, true) => count_ne += 1,
(false, true) => count_se += 1,
(false, false) => count_sw += 1,
(true, false) => count_nw += 1,
} }
} else if source_is_north != sink_is_north && source_is_east == sink_is_east { } else if !(flip_quads_north_south(arc.source_quads) & arc.sink_quads).is_empty() {
if source_is_east { match (flip_quads_north_south(arc.source_quads) & arc.sink_quads)
.iter()
.next()
.unwrap()
{
Quadrant::Northeast | Quadrant::Southeast => {
count_ne += 1; count_ne += 1;
count_se += 1; count_se += 1;
} else { }
Quadrant::Northwest | Quadrant::Southwest => {
count_nw += 1; count_nw += 1;
count_sw += 1; count_sw += 1;
} }
} else if source_is_north == sink_is_north { }
if source_is_north { } else if !(flip_quads_east_west(arc.source_quads) & arc.sink_quads).is_empty() {
match (flip_quads_east_west(arc.source_quads) & arc.sink_quads)
.iter()
.next()
.unwrap()
{
Quadrant::Northeast | Quadrant::Northwest => {
count_ne += 1; count_ne += 1;
count_nw += 1; count_nw += 1;
} else { }
Quadrant::Southeast | Quadrant::Southwest => {
count_se += 1; count_se += 1;
count_sw += 1; count_sw += 1;
} }
}
} else { } else {
// all of this calculation is not be needed and an approximation would be good enough // all of this calculation is not be needed and an approximation would be good enough
// but i can't be bothered (yes this is all copy-pasted from the actual partitioner) // but i can't be bothered (yes this is all copy-pasted from the actual partitioner)
let mut middle_horiz = ( let middle_horiz = (
partition_point.0, partition_point.0,
split_line_over_x( split_line_over_x(
(arc.get_source_loc(), arc.get_sink_loc()), (arc.estimated_source_location, arc.estimated_sink_location),
partition_point.0, partition_point.0,
), ),
); );
let seg1 = (flip_quads_diagonal(arc.source_quads) & arc.sink_quads)
let mut middle_vert = ( .iter()
split_line_over_y( .next()
(arc.get_source_loc(), arc.get_sink_loc()), .unwrap();
partition_point.1, let horiz_happens_first = (middle_horiz.1 < partition_point.1)
), == matches!(seg1, Quadrant::Northeast | Quadrant::Southeast);
partition_point.1,
);
// need to avoid the partition point
if middle_horiz.1 == partition_point.1 || middle_vert.0 == partition_point.0 {
if source_is_east != sink_is_north {
middle_horiz.1 = partition_point.1 + 1;
middle_vert.0 = partition_point.0 - 1;
} else {
middle_horiz.1 = partition_point.1 + 1;
middle_vert.0 = partition_point.0 + 1;
}
}
let horiz_happens_first = (middle_horiz.1 < partition_point.1) == source_is_east;
// note: if you invert all the bools it adds to the same things, not sure how make less redundant // note: if you invert all the bools it adds to the same things, not sure how make less redundant
match (source_is_north, source_is_east, horiz_happens_first) { match (
matches!(seg1, Quadrant::Northeast | Quadrant::Northwest),
matches!(seg1, Quadrant::Northeast | Quadrant::Southeast),
horiz_happens_first,
) {
(true, true, true) => { (true, true, true) => {
count_ne += 1; count_ne += 1;
count_se += 1; count_se += 1;
@ -392,7 +517,7 @@ fn approximate_partition_results(
/// finds the y location a line would be split at if you split it at a certain x location /// finds the y location a line would be split at if you split it at a certain x location
/// ///
/// the function assumes the line goes on forever in both directions, and it truncates the actual coordinate /// the function assumes the line goes on forever in both directions, and it truncates the actual coordinate
fn split_line_over_x(line: (npnr::Loc, npnr::Loc), x_location: i32) -> i32 { fn split_line_over_x(line: (Coord, Coord), x_location: i32) -> i32 {
if line.0.x == line.1.x { if line.0.x == line.1.x {
// the line is a straight line in the direction, there is either infinite solutions, or none // the line is a straight line in the direction, there is either infinite solutions, or none
// we simply average the y coordinate to give a "best effort" guess // we simply average the y coordinate to give a "best effort" guess
@ -407,20 +532,12 @@ fn split_line_over_x(line: (npnr::Loc, npnr::Loc), x_location: i32) -> i32 {
} }
/// finds the x location a line would be split at if you split it at a certain y location, assuming the line goes on forever in both directions /// finds the x location a line would be split at if you split it at a certain y location, assuming the line goes on forever in both directions
fn split_line_over_y(line: (npnr::Loc, npnr::Loc), y_location: i32) -> i32 { fn split_line_over_y(line: (Coord, Coord), y_location: i32) -> i32 {
// laziness supreme! // laziness supreme!
split_line_over_x( split_line_over_x(
( (
npnr::Loc { Coord::new(line.0.y, line.0.x),
x: line.0.y, Coord::new(line.1.y, line.1.x),
y: line.0.x,
z: 0,
},
npnr::Loc {
x: line.1.y,
y: line.1.x,
z: 0,
},
), ),
y_location, y_location,
) )
@ -430,7 +547,7 @@ fn split_line_over_y(line: (npnr::Loc, npnr::Loc), y_location: i32) -> i32 {
fn partition( fn partition(
ctx: &npnr::Context, ctx: &npnr::Context,
nets: &npnr::Nets, nets: &npnr::Nets,
arcs: &[Arc], arcs: &[SegmentedArc],
pips: &[npnr::PipId], pips: &[npnr::PipId],
x: i32, x: i32,
y: i32, y: i32,
@ -474,8 +591,6 @@ fn partition(
progress.set_message(format!("overused wires: {}", overused_wires)); progress.set_message(format!("overused wires: {}", overused_wires));
let mut bad_nets = std::collections::HashSet::new();
let _is_general_routing = |wire: &str| { let _is_general_routing = |wire: &str| {
wire.contains("H00") wire.contains("H00")
|| wire.contains("V00") || wire.contains("V00")
@ -487,72 +602,28 @@ fn partition(
|| wire.contains("V06") || wire.contains("V06")
}; };
for arc in arcs {
if bad_nets.contains(&arc.net()) {
continue;
}
let source_loc = arc.get_source_loc();
let source_coords: Coord = source_loc.into();
let sink_loc = arc.get_sink_loc();
let sink_coords: Coord = sink_loc.into();
// test for annoying special case
let mut have_any_in_same_segment = false;
for pip in ctx.get_downhill_pips(arc.source_wire()) {
let pip_coord: Coord = ctx.pip_location(pip).into();
let pip_seg = pip_coord.segment_from(&partition_coords);
have_any_in_same_segment |= pip_seg == source_coords.segment_from(&partition_coords)
}
if !have_any_in_same_segment {
bad_nets.insert(arc.net());
}
let mut have_any_in_same_segment = false;
for pip in ctx.get_uphill_pips(arc.sink_wire()) {
let pip_coord: Coord = ctx.pip_location(pip).into();
let pip_seg = pip_coord.segment_from(&partition_coords);
have_any_in_same_segment |= pip_seg == sink_coords.segment_from(&partition_coords)
}
if !have_any_in_same_segment {
bad_nets.insert(arc.net());
}
}
let arcs = arcs let arcs = arcs
.into_par_iter() .into_par_iter()
.progress_with(progress) .progress_with(progress)
.flat_map(|arc| { .flat_map(|arc| {
let raw_net = nets.net_from_index(arc.net()); let raw_net = nets.net_from_index(arc.arc.net());
let source_loc = arc.get_source_loc();
let source_coords: Coord = source_loc.into();
let source_is_north = source_coords.is_north_of(&partition_coords);
let source_is_east = source_coords.is_east_of(&partition_coords);
let sink_loc = arc.get_sink_loc();
let sink_coords: Coord = sink_loc.into();
let sink_is_north = sink_coords.is_north_of(&partition_coords);
let sink_is_east = sink_coords.is_east_of(&partition_coords);
let _name = ctx let _name = ctx
.name_of(nets.name_from_index(arc.net())) .name_of(nets.name_from_index(arc.arc.net()))
.to_str() .to_str()
.unwrap() .unwrap()
.to_string(); .to_string();
let _verbose = false; //name == "soc0.processor.with_fpu.fpu_0.fpu_multiply_0.rin_CCU2C_S0_4$CCU2_FCI_INT"; let _verbose = false; //name == "soc0.processor.with_fpu.fpu_0.fpu_multiply_0.rin_CCU2C_S0_4$CCU2_FCI_INT";
if bad_nets.contains(&arc.net()) { if !(arc.source_quads & arc.sink_quads).is_empty() {
special.lock().unwrap().push(arc.clone()); let seg = (arc.source_quads & arc.sink_quads).iter().next().unwrap();
return vec![]; vec![(seg, arc.arc.clone())]
} } else if !(arc.source_quads & flip_quads_north_south(arc.sink_quads)).is_empty() {
let seg1 = (arc.source_quads & flip_quads_north_south(arc.sink_quads))
.iter()
.next()
.unwrap();
let seg2 = seg1.flip_north_south();
if source_is_north == sink_is_north && source_is_east == sink_is_east {
let seg = source_coords.segment_from(&partition_coords);
vec![(seg, arc.clone())]
} else if source_is_north != sink_is_north && source_is_east == sink_is_east {
let (seg1, seg2) = match (source_is_north, source_is_east) {
(true, true) => (Quadrant::Northeast, Quadrant::Southeast),
(true, false) => (Quadrant::Northwest, Quadrant::Southwest),
(false, true) => (Quadrant::Southeast, Quadrant::Northeast),
(false, false) => (Quadrant::Southwest, Quadrant::Northwest),
};
if let Some(partition) = partition_single_arc( if let Some(partition) = partition_single_arc(
ctx, ctx,
&pip_selector, &pip_selector,
@ -565,32 +636,8 @@ fn partition(
) { ) {
partition partition
} else { } else {
let (seg1, seg2, seg3, seg4) = match (source_is_north, source_is_east) { let (seg2, seg3, seg4) =
(true, true) => ( (seg1.flip_east_west(), seg2.flip_east_west(), seg2);
Quadrant::Northeast,
Quadrant::Northwest,
Quadrant::Southwest,
Quadrant::Southeast,
),
(true, false) => (
Quadrant::Northwest,
Quadrant::Northeast,
Quadrant::Southeast,
Quadrant::Southwest,
),
(false, true) => (
Quadrant::Southeast,
Quadrant::Southwest,
Quadrant::Northwest,
Quadrant::Northeast,
),
(false, false) => (
Quadrant::Southwest,
Quadrant::Southeast,
Quadrant::Northeast,
Quadrant::Northwest,
),
};
partition_single_arc( partition_single_arc(
ctx, ctx,
&pip_selector, &pip_selector,
@ -603,13 +650,12 @@ fn partition(
) )
.expect("failed to partition arc on NorthSouth axis") .expect("failed to partition arc on NorthSouth axis")
} }
} else if source_is_north == sink_is_north && source_is_east != sink_is_east { } else if !(arc.source_quads & flip_quads_east_west(arc.sink_quads)).is_empty() {
let (seg1, seg2) = match (source_is_north, source_is_east) { let seg1 = (arc.source_quads & flip_quads_east_west(arc.sink_quads))
(true, true) => (Quadrant::Northeast, Quadrant::Northwest), .iter()
(true, false) => (Quadrant::Northwest, Quadrant::Northeast), .next()
(false, true) => (Quadrant::Southeast, Quadrant::Southwest), .unwrap();
(false, false) => (Quadrant::Southwest, Quadrant::Southeast), let seg2 = seg1.flip_east_west();
};
if let Some(partition) = partition_single_arc( if let Some(partition) = partition_single_arc(
ctx, ctx,
&pip_selector, &pip_selector,
@ -622,32 +668,8 @@ fn partition(
) { ) {
partition partition
} else { } else {
let (seg1, seg2, seg3, seg4) = match (source_is_north, source_is_east) { let (seg2, seg3, seg4) =
(true, true) => ( (seg1.flip_north_south(), seg2.flip_north_south(), seg2);
Quadrant::Northeast,
Quadrant::Southeast,
Quadrant::Southwest,
Quadrant::Northwest,
),
(true, false) => (
Quadrant::Northwest,
Quadrant::Southwest,
Quadrant::Southeast,
Quadrant::Northeast,
),
(false, true) => (
Quadrant::Southeast,
Quadrant::Northeast,
Quadrant::Northwest,
Quadrant::Southwest,
),
(false, false) => (
Quadrant::Southwest,
Quadrant::Northwest,
Quadrant::Northeast,
Quadrant::Southeast,
),
};
partition_single_arc( partition_single_arc(
ctx, ctx,
&pip_selector, &pip_selector,
@ -661,56 +683,31 @@ fn partition(
.expect("failed to partition arc on EastWest axis") .expect("failed to partition arc on EastWest axis")
} }
} else { } else {
let middle_horiz = (x, split_line_over_x((source_loc, sink_loc), x)); let middle_horiz = (
let horiz_happens_first = (middle_horiz.1 < y) == source_is_east; x,
split_line_over_x(
(arc.estimated_source_location, arc.estimated_sink_location),
x,
),
);
let seg1 = (arc.source_quads & flip_quads_diagonal(arc.sink_quads))
.iter()
.next()
.unwrap();
let horiz_happens_first = (middle_horiz.1 < y)
== matches!(seg1, Quadrant::Northeast | Quadrant::Southeast);
let (seg2, seg3) = (
if horiz_happens_first {
seg1.flip_east_west()
} else {
seg1.flip_north_south()
},
seg1.flip_diagonal(),
);
let grab_segment_order = |horiz_happens_first| match (
source_is_north,
source_is_east,
horiz_happens_first,
) {
(true, true, true) => (
Quadrant::Northeast,
Quadrant::Southeast,
Quadrant::Southwest,
),
(true, false, true) => (
Quadrant::Northwest,
Quadrant::Southwest,
Quadrant::Southeast,
),
(false, true, true) => (
Quadrant::Southeast,
Quadrant::Northeast,
Quadrant::Northwest,
),
(false, false, true) => (
Quadrant::Southwest,
Quadrant::Northwest,
Quadrant::Northeast,
),
(true, true, false) => (
Quadrant::Northeast,
Quadrant::Northwest,
Quadrant::Southwest,
),
(true, false, false) => (
Quadrant::Northwest,
Quadrant::Northeast,
Quadrant::Southeast,
),
(false, true, false) => (
Quadrant::Southeast,
Quadrant::Southwest,
Quadrant::Northwest,
),
(false, false, false) => (
Quadrant::Southwest,
Quadrant::Southeast,
Quadrant::Northeast,
),
};
let (seg1, seg2, seg3) = grab_segment_order(horiz_happens_first);
if let Some(partition) = partition_single_arc( if let Some(partition) = partition_single_arc(
ctx, ctx,
&pip_selector, &pip_selector,
@ -723,8 +720,8 @@ fn partition(
) { ) {
partition partition
} else { } else {
// flip `horiz_happens_first` and hope for the best // go other way around
let (seg1, seg2, seg3) = grab_segment_order(!horiz_happens_first); let seg2 = seg2.flip_diagonal();
partition_single_arc( partition_single_arc(
ctx, ctx,
&pip_selector, &pip_selector,
@ -861,16 +858,17 @@ fn partition(
fn partition_single_arc( fn partition_single_arc(
ctx: &npnr::Context, ctx: &npnr::Context,
pip_selector: &PipSelector, pip_selector: &PipSelector,
arc: &Arc, arc: &SegmentedArc,
raw_net: *mut npnr::NetInfo, raw_net: *mut npnr::NetInfo,
partition_point: Coord, partition_point: Coord,
min_bounds: &Coord, min_bounds: &Coord,
max_bounds: &Coord, max_bounds: &Coord,
segments: &[Quadrant], segments: &[Quadrant],
) -> Option<Vec<(Quadrant, Arc)>> { ) -> Option<Vec<(Quadrant, Arc)>> {
let start_coord: Coord = arc.get_source_loc().into(); let start_coord: Coord = arc.estimated_source_location;
let end_coord: Coord = arc.get_sink_loc().into(); let end_coord: Coord = arc.estimated_sink_location;
let mut current_arc = arc.clone(); let mut current_coming_from = start_coord;
let mut current_arc = arc.arc.clone();
let mut arcs = vec![]; let mut arcs = vec![];
for (from_quad, to_quad) in segments.iter().tuple_windows() { for (from_quad, to_quad) in segments.iter().tuple_windows() {
let direction = Direction::between(*from_quad, *to_quad).unwrap(); let direction = Direction::between(*from_quad, *to_quad).unwrap();
@ -880,14 +878,39 @@ fn partition_single_arc(
let pip = pip_selector.find_pip( let pip = pip_selector.find_pip(
ctx, ctx,
intersection.into(), intersection.into(),
current_arc.get_source_loc(), current_coming_from.into(),
current_arc.net(), current_arc.net(),
raw_net, raw_net,
)?; )?;
current_coming_from = ctx.pip_location(pip).into();
let (before_arc, after_arc) = current_arc.split(ctx, pip); let (before_arc, after_arc) = current_arc.split(ctx, pip);
if *from_quad == Quadrant::Northwest {
println!(
"full arc: ({:?}, {:?}, {:?}, {:?})\ninserting: ({:?}, {:?})\nsegments: {:?}\n",
arc.source_quads,
arc.estimated_source_location,
arc.sink_quads,
arc.estimated_sink_location,
before_arc.get_source_loc(),
before_arc.get_sink_loc(),
segments,
);
}
arcs.push((*from_quad, before_arc)); arcs.push((*from_quad, before_arc));
current_arc = after_arc; current_arc = after_arc;
} }
if *segments.last().unwrap() == Quadrant::Northwest {
println!(
"full arc: ({:?}, {:?}, {:?}, {:?})\ninserting: ({:?}, {:?})\nsegments: {:?}\n",
arc.source_quads,
arc.estimated_source_location,
arc.sink_quads,
arc.estimated_sink_location,
current_arc.get_source_loc(),
current_arc.get_sink_loc(),
segments,
);
}
arcs.push((*segments.last().unwrap(), current_arc)); arcs.push((*segments.last().unwrap(), current_arc));
Some(arcs) Some(arcs)
} }
@ -922,83 +945,107 @@ pub fn find_partition_point_and_sanity_check(
println!("\nne:"); println!("\nne:");
for arc in &ne { for arc in &ne {
if arc.get_source_loc().x > x_part if arc.get_source_loc().map(|v| v.x > x_part).unwrap_or(false)
|| arc.get_source_loc().y > y_part || arc.get_source_loc().map(|v| v.y > y_part).unwrap_or(false)
|| arc.get_sink_loc().x > x_part || arc.get_sink_loc().map(|v| v.x > x_part).unwrap_or(false)
|| arc.get_sink_loc().y > y_part || arc.get_sink_loc().map(|v| v.y > y_part).unwrap_or(false)
{ {
invalid_arcs_in_ne += 1; invalid_arcs_in_ne += 1;
} }
if arc.get_source_loc().x <= x_start if arc
|| arc.get_source_loc().y <= y_start .get_source_loc()
|| arc.get_sink_loc().x <= x_start .map(|v| v.x <= x_start)
|| arc.get_sink_loc().y <= y_start .unwrap_or(false)
|| arc
.get_source_loc()
.map(|v| v.y <= y_start)
.unwrap_or(false)
|| arc.get_sink_loc().map(|v| v.x <= x_start).unwrap_or(false)
|| arc.get_sink_loc().map(|v| v.y <= y_start).unwrap_or(false)
{ {
println!( //println!(
"oob: {:?} -> {:?}", // "oob: {:?} -> {:?}",
arc.get_source_loc(), // arc.get_source_loc(),
arc.get_sink_loc() // arc.get_sink_loc()
); //);
out_of_bound_arcs_in_ne += 1; out_of_bound_arcs_in_ne += 1;
} }
} }
println!("\nse:"); println!("\nse:");
for arc in &se { for arc in &se {
if arc.get_source_loc().x < x_part if arc.get_source_loc().map(|v| v.x < x_part).unwrap_or(false)
|| arc.get_source_loc().y > y_part || arc.get_source_loc().map(|v| v.y > y_part).unwrap_or(false)
|| arc.get_sink_loc().x < x_part || arc.get_sink_loc().map(|v| v.x < x_part).unwrap_or(false)
|| arc.get_sink_loc().y > y_part || arc.get_sink_loc().map(|v| v.y > y_part).unwrap_or(false)
{ {
invalid_arcs_in_se += 1; invalid_arcs_in_se += 1;
} }
if arc.get_source_loc().x >= x_finish if arc
|| arc.get_source_loc().y <= y_start .get_source_loc()
|| arc.get_sink_loc().x >= x_finish .map(|v| v.x >= x_finish)
|| arc.get_sink_loc().y <= y_start .unwrap_or(false)
|| arc
.get_source_loc()
.map(|v| v.y <= y_start)
.unwrap_or(false)
|| arc.get_sink_loc().map(|v| v.x >= x_finish).unwrap_or(false)
|| arc.get_sink_loc().map(|v| v.y <= y_start).unwrap_or(false)
{ {
println!( //println!(
"oob: {:?} -> {:?}", // "oob: {:?} -> {:?}",
arc.get_source_loc(), // arc.get_source_loc(),
arc.get_sink_loc() // arc.get_sink_loc()
); //);
out_of_bound_arcs_in_se += 1; out_of_bound_arcs_in_se += 1;
} }
} }
println!("\nsw:"); println!("\nsw:");
for arc in &sw { for arc in &sw {
if arc.get_source_loc().x < x_part if arc.get_source_loc().map(|v| v.x < x_part).unwrap_or(false)
|| arc.get_source_loc().y < y_part || arc.get_source_loc().map(|v| v.y < y_part).unwrap_or(false)
|| arc.get_sink_loc().x < x_part || arc.get_sink_loc().map(|v| v.x < x_part).unwrap_or(false)
|| arc.get_sink_loc().y < y_part || arc.get_sink_loc().map(|v| v.y < y_part).unwrap_or(false)
{ {
invalid_arcs_in_sw += 1; invalid_arcs_in_sw += 1;
} }
if arc.get_source_loc().x >= x_finish if arc
|| arc.get_source_loc().y >= y_finish .get_source_loc()
|| arc.get_sink_loc().x >= x_finish .map(|v| v.x >= x_finish)
|| arc.get_sink_loc().y >= y_finish .unwrap_or(false)
|| arc
.get_source_loc()
.map(|v| v.y >= y_finish)
.unwrap_or(false)
|| arc.get_sink_loc().map(|v| v.x >= x_finish).unwrap_or(false)
|| arc.get_sink_loc().map(|v| v.y >= y_finish).unwrap_or(false)
{ {
println!( //println!(
"oob: {:?} -> {:?}", // "oob: {:?} -> {:?}",
arc.get_source_loc(), // arc.get_source_loc(),
arc.get_sink_loc() // arc.get_sink_loc()
); //);
out_of_bound_arcs_in_sw += 1; out_of_bound_arcs_in_sw += 1;
} }
} }
println!("\nnw:"); println!("\nnw:");
for arc in &nw { for arc in &nw {
if arc.get_source_loc().x > x_part if arc.get_source_loc().map(|v| v.x > x_part).unwrap_or(false)
|| arc.get_source_loc().y < y_part || arc.get_source_loc().map(|v| v.y < y_part).unwrap_or(false)
|| arc.get_sink_loc().x > x_part || arc.get_sink_loc().map(|v| v.x > x_part).unwrap_or(false)
|| arc.get_sink_loc().y < y_part || arc.get_sink_loc().map(|v| v.y < y_part).unwrap_or(false)
{ {
invalid_arcs_in_nw += 1; invalid_arcs_in_nw += 1;
} }
if arc.get_source_loc().x <= x_start if arc
|| arc.get_source_loc().y >= y_finish .get_source_loc()
|| arc.get_sink_loc().x <= x_start .map(|v| v.x <= x_start)
|| arc.get_sink_loc().y >= y_finish .unwrap_or(false)
|| arc
.get_source_loc()
.map(|v| v.y >= y_finish)
.unwrap_or(false)
|| arc.get_sink_loc().map(|v| v.x <= x_start).unwrap_or(false)
|| arc.get_sink_loc().map(|v| v.y >= y_finish).unwrap_or(false)
{ {
println!( println!(
"oob: {:?} -> {:?}", "oob: {:?} -> {:?}",

View File

@ -16,9 +16,9 @@ use crate::{
#[derive(Clone, Hash, PartialEq, Eq)] #[derive(Clone, Hash, PartialEq, Eq)]
pub struct Arc { pub struct Arc {
source_wire: WireId, source_wire: WireId,
source_loc: Loc, source_loc: Option<Loc>,
sink_wire: WireId, sink_wire: WireId,
sink_loc: Loc, sink_loc: Option<Loc>,
net: NetIndex, net: NetIndex,
name: IdString, name: IdString,
} }
@ -26,9 +26,9 @@ pub struct Arc {
impl Arc { impl Arc {
pub fn new( pub fn new(
source_wire: WireId, source_wire: WireId,
source_loc: Loc, source_loc: Option<Loc>,
sink_wire: WireId, sink_wire: WireId,
sink_loc: Loc, sink_loc: Option<Loc>,
net: NetIndex, net: NetIndex,
name: IdString, name: IdString,
) -> Self { ) -> Self {
@ -43,6 +43,7 @@ impl Arc {
} }
pub fn split(&self, ctx: &npnr::Context, pip: npnr::PipId) -> (Self, Self) { pub fn split(&self, ctx: &npnr::Context, pip: npnr::PipId) -> (Self, Self) {
// should this still set the sink and source using the pip? not sure
let pip_src = ctx.pip_src_wire(pip); let pip_src = ctx.pip_src_wire(pip);
let pip_dst = ctx.pip_dst_wire(pip); let pip_dst = ctx.pip_dst_wire(pip);
( (
@ -50,13 +51,13 @@ impl Arc {
source_wire: self.source_wire, source_wire: self.source_wire,
source_loc: self.source_loc, source_loc: self.source_loc,
sink_wire: pip_src, sink_wire: pip_src,
sink_loc: ctx.pip_location(pip), sink_loc: Some(ctx.pip_location(pip)),
net: self.net, net: self.net,
name: self.name, name: self.name,
}, },
Self { Self {
source_wire: pip_dst, source_wire: pip_dst,
source_loc: ctx.pip_location(pip), source_loc: Some(ctx.pip_location(pip)),
sink_wire: self.sink_wire, sink_wire: self.sink_wire,
sink_loc: self.sink_loc, sink_loc: self.sink_loc,
net: self.net, net: self.net,
@ -74,10 +75,10 @@ impl Arc {
pub fn net(&self) -> npnr::NetIndex { pub fn net(&self) -> npnr::NetIndex {
self.net self.net
} }
pub fn get_source_loc(&self) -> Loc { pub fn get_source_loc(&self) -> Option<Loc> {
self.source_loc self.source_loc
} }
pub fn get_sink_loc(&self) -> Loc { pub fn get_sink_loc(&self) -> Option<Loc> {
self.sink_loc self.sink_loc
} }
} }