infrastructure for pre-routing

This commit is contained in:
Lofty 2023-03-23 21:06:54 +00:00
parent 0bc945fbc3
commit 4b635cf68c
4 changed files with 273 additions and 113 deletions

View File

@ -1,6 +1,3 @@
#![feature(c_unwind)]
#![feature(let_chains)]
use std::{ptr::NonNull, time::Instant};
use colored::Colorize;
@ -15,7 +12,7 @@ mod partition;
mod route;
#[no_mangle]
pub extern "C-unwind" fn npnr_router_awooter(
pub extern "C" fn npnr_router_awooter(
ctx: Option<NonNull<npnr::Context>>,
pressure: f32,
history: f32,
@ -59,18 +56,21 @@ fn extract_arcs_from_nets(ctx: &npnr::Context, nets: &npnr::Nets) -> Vec<route::
let sink = sink_ref.cell().unwrap();
let sink = sink.location();
for sink_wire in ctx.sink_wires(net, *sink_ref) {
arcs.push(route::Arc::new(
let arc = route::Arc::new(
source_wire,
Some(source),
sink_wire,
Some(sink),
net.index(),
nets.name_from_index(net.index()),
));
);
if !arcs.contains(&arc) {
arcs.push(arc);
}
if verbose {
let source_wire = ctx.name_of_wire(source_wire).to_str().unwrap();
let sink_wire = ctx.name_of_wire(sink_wire).to_str().unwrap();
let source_wire = ctx.name_of_wire(source_wire);
let sink_wire = ctx.name_of_wire(sink_wire);
dbg!(source_wire, sink_wire, net.index().into_inner());
}
}
@ -178,11 +178,22 @@ fn route(ctx: &mut npnr::Context, pressure: f32, history: f32) -> bool {
let arcs = extract_arcs_from_nets(ctx, &nets);
let router = route::Router::new(&nets, wires, pressure, history);
let progress = MultiProgress::new();
let mut thread = route::RouterThread::new(
Coord::new(0, 0),
Coord::new(ctx.grid_dim_x(), ctx.grid_dim_y()),
&arcs,
"pre-routing",
&progress
);
let arcs = router.find_general_routing(ctx, &nets, &mut thread);
let mut special_arcs = vec![];
let mut partitionable_arcs = Vec::with_capacity(arcs.len());
for arc in arcs {
let src_name = ctx.name_of_wire(arc.source_wire()).to_str().unwrap();
let dst_name = ctx.name_of_wire(arc.sink_wire()).to_str().unwrap();
let src_name = ctx.name_of_wire(arc.source_wire());
let dst_name = ctx.name_of_wire(arc.sink_wire());
if src_name.contains("FCO_SLICE")
|| src_name.contains("Q6_SLICE")
@ -208,7 +219,7 @@ fn route(ctx: &mut npnr::Context, pressure: f32, history: f32) -> bool {
String::from(""),
)];
for _ in 0..2 {
for _ in 0..0 {
let mut new_partitions = Vec::with_capacity(partitions.len() * 4);
for (min, max, partition, name) in &partitions {
log_info!("partition {}:\n", name);

View File

@ -302,10 +302,10 @@ impl Context {
unsafe { CStr::from_ptr(npnr_context_name_of_pip(self, pip)) }
}
pub fn name_of_wire(&self, wire: WireId) -> &CStr {
pub fn name_of_wire(&self, wire: WireId) -> &str {
static MUTEX: Mutex<()> = Mutex::new(());
let _lock = MUTEX.lock().unwrap();
unsafe { CStr::from_ptr(npnr_context_name_of_wire(self, wire)) }
unsafe { CStr::from_ptr(npnr_context_name_of_wire(self, wire)) }.to_str().unwrap()
}
pub fn verbose(&self) -> bool {
@ -313,7 +313,7 @@ impl Context {
}
}
extern "C-unwind" {
extern "C" {
pub fn npnr_log_info(format: *const c_char);
pub fn npnr_log_error(format: *const c_char);

View File

@ -177,12 +177,12 @@ impl Coord {
pub fn intersect(&self, other: &Self, axis: Axis, split_point: &Self) -> Self {
match axis {
Axis::NorthSouth => Coord {
x: split_line_over_y(((*self).into(), (*other).into()), split_point.y),
x: split_line_over_y((*self, *other), split_point.y),
y: split_point.y,
},
Axis::EastWest => Coord {
x: split_point.x,
y: split_line_over_x(((*self).into(), (*other).into()), split_point.x),
y: split_line_over_x((*self, *other), split_point.x),
},
}
}
@ -318,10 +318,10 @@ pub fn find_partition_point(
) -> (i32, i32, Vec<Arc>, Vec<Arc>, Vec<Arc>, Vec<Arc>, Vec<Arc>) {
let mut x = ((x_finish - x_start) / 2) + x_start;
let mut y = ((y_finish - y_start) / 2) + y_start;
let mut x_diff = 0; //(x_finish - x_start) / 4;
let mut y_diff = 0; //(y_finish - y_start) / 4;
let mut x_diff = 0;//(x_finish - x_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?
// TODO(SpaceCat~Chan): cache more stuff involved in created SegmentedArc to avoid doing so much ffi?
while x_diff != 0 {
let segmented_arcs = arcs
@ -884,33 +884,9 @@ fn partition_single_arc(
)?;
current_coming_from = ctx.pip_location(pip).into();
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));
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));
Some(arcs)
}
@ -1169,8 +1145,8 @@ impl PipSelector {
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();
let src_name = ctx.name_of_wire(src_wire);
let dst_name = ctx.name_of_wire(dst_wire);
if !is_general_routing(src_name) || !is_general_routing(dst_name) {
// ECP5 hack: whitelist allowed wires.
continue;

View File

@ -232,6 +232,153 @@ impl Router {
}
}
pub fn find_general_routing(&self, ctx: &npnr::Context, nets: &npnr::Nets, this: &mut RouterThread) -> Vec<Arc> {
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 mut delay = HashMap::new();
for arc in this.arcs {
delay.insert(arc, 1.0_f32);
}
let start = Instant::now();
let mut max_delay = 1.0;
let mut least_overuse = usize::MAX;
let mut iters_since_improvement = 0;
let mut route_arcs = Vec::from_iter(this.arcs.iter());
let progress = this.progress.add(ProgressBar::new(0));
progress.set_style(
ProgressStyle::with_template("[{elapsed}] [{bar:40.green/green}] {msg:30!}")
.unwrap()
.progress_chars("━╸ "),
);
let mut new_arcs = Vec::new();
let mut iterations = 0;
loop {
iterations += 1;
progress.set_position(0);
progress.set_length(route_arcs.len() as u64);
for arc in route_arcs.iter().sorted_by(|&i, &j| {
(delay.get(j).unwrap() / max_delay).total_cmp(&(delay.get(i).unwrap() / max_delay))
}) {
let name = ctx.name_of(arc.name).to_str().unwrap();
progress.inc(1);
let criticality = (delay.get(arc).unwrap() / max_delay).min(0.99).powf(2.5) + 0.1;
progress.set_message(format!("{} @ {}: {}", this.id, iterations, name));
*delay.get_mut(arc).unwrap() = self.route_arc(ctx, nets, arc, criticality);
}
let mut overused = HashSet::new();
for wd in self.flat_wires.iter() {
let mut wd = wd.write().unwrap();
if wd.curr_cong > 1 && !is_general_routing(ctx.name_of_wire(wd.wire)) {
overused.insert(wd.wire);
wd.hist_cong += (wd.curr_cong as f32) * self.history;
}
}
if overused.is_empty() {
break;
} else if overused.len() < least_overuse {
least_overuse = overused.len();
iters_since_improvement = 0;
progress.println(format!(
"{} @ {}: {} wires overused {}",
this.id,
iterations,
overused.len(),
"(new best)".bold()
));
} else {
iters_since_improvement += 1;
progress.println(format!(
"{} @ {}: {} wires overused",
this.id,
iterations,
overused.len()
));
}
let mut next_arcs = HashSet::new();
for arc in this.arcs {
let nets = &*self.nets.read().unwrap();
for wire in nets[arc.net.into_inner() as usize]
.wires
.keys()
{
if overused.contains(wire) {
next_arcs.insert(arc);
}
}
}
for &arc in &next_arcs {
self.ripup_arc(ctx, arc);
}
{
let nets = &mut *self.nets.write().unwrap();
for net in nets.iter_mut() {
net.done_sinks.clear();
}
}
if iters_since_improvement > 50 {
iters_since_improvement = 0;
least_overuse = usize::MAX;
progress.println(format!(
"{} @ {}: {}",
this.id,
iterations,
"bored; rerouting everything".bold()
));
route_arcs = Vec::from_iter(this.arcs.iter());
} else {
route_arcs = Vec::from_iter(next_arcs.into_iter());
}
max_delay = this
.arcs
.iter()
.map(|arc| *delay.get(arc).unwrap())
.reduce(f32::max)
.unwrap();
}
let now = start.elapsed().as_secs_f32();
progress.println(format!(
"{} @ {}: {} in {:.0}m{:.03}s",
this.id,
iterations,
"pre-routing complete".green(),
(now / 60.0).floor(),
now % 60.0
));
progress.finish_and_clear();
for arc in this.arcs {
let (source_wire, sink_wire) = self.ripup_arc_general_routing(ctx, arc);
new_arcs.push(Arc::new(source_wire, None, sink_wire, None, arc.net, arc.name));
}
new_arcs
}
pub fn route(&self, ctx: &npnr::Context, nets: &npnr::Nets, this: &mut RouterThread) {
let mut delay = HashMap::new();
@ -267,7 +414,7 @@ impl Router {
}) {
let name = ctx.name_of(arc.name).to_str().unwrap();
progress.inc(1);
let criticality = (delay.get(arc).unwrap() / max_delay).min(0.99).powf(2.5) + 0.1;
let criticality = (delay.get(arc).unwrap() / max_delay);
progress.set_message(format!("{} @ {}: {}", this.id, iterations, name));
*delay.get_mut(arc).unwrap() = self.route_arc(ctx, nets, arc, criticality);
}
@ -303,23 +450,27 @@ impl Router {
));
}
let mut next_arcs = Vec::new();
let mut next_arcs = HashSet::new();
for arc in this.arcs {
for wire in self.nets.read().unwrap()[arc.net.into_inner() as usize]
let nets = &*self.nets.read().unwrap();
for wire in nets[arc.net.into_inner() as usize]
.wires
.keys()
{
if overused.contains(wire) {
next_arcs.push(arc);
next_arcs.insert(arc);
}
}
}
for &arc in &route_arcs {
for &arc in &next_arcs {
self.ripup_arc(ctx, arc);
}
for net in self.nets.write().unwrap().iter_mut() {
net.done_sinks.clear();
{
let nets = &mut *self.nets.write().unwrap();
for net in nets.iter_mut() {
net.done_sinks.clear();
}
}
if iters_since_improvement > 50 {
@ -333,7 +484,7 @@ impl Router {
));
route_arcs = Vec::from_iter(this.arcs.iter());
} else {
route_arcs = next_arcs;
route_arcs = Vec::from_iter(next_arcs.into_iter());
}
max_delay = this
@ -492,74 +643,59 @@ impl Router {
dirty_wires.push(source_wire);
dirty_wires.push(sink_wire);
let already_done = self.nets.read().unwrap()[arc.net().into_inner() as usize]
.done_sinks
.contains(&arc.sink_wire);
if already_done {
midpoint = Some(*self.wire_to_idx.get(&arc.sink_wire).unwrap());
let mut wire = arc.sink_wire();
while wire != arc.source_wire() {
let nd = &self.nets.read().unwrap()[arc.net().into_inner() as usize];
let driver = nd.wires.get(&wire).unwrap().0;
self.set_visited_fwd(self.wire_to_idx[&wire], driver, &mut dirty_wires);
wire = ctx.pip_src_wire(driver);
while midpoint.is_none() {
// Step forward
if !self.step(
ctx,
nets,
arc,
criticality,
&mut fwd_queue,
&mut midpoint,
arc.sink_wire,
&mut dirty_wires,
Self::was_visited_fwd,
Self::set_visited_fwd,
Self::was_visited_bwd,
npnr::Context::get_downhill_pips,
npnr::Context::pip_dst_wire,
) {
break;
}
} else {
while midpoint.is_none() {
// Step forward
if !self.step(
ctx,
nets,
arc,
criticality,
&mut fwd_queue,
&mut midpoint,
arc.sink_wire,
&mut dirty_wires,
Self::was_visited_fwd,
Self::set_visited_fwd,
Self::was_visited_bwd,
npnr::Context::get_downhill_pips,
npnr::Context::pip_dst_wire,
) {
break;
}
// Step backward
/*if !self.step(
ctx,
nets,
arc,
criticality,
&mut bwd_queue,
&mut midpoint,
arc.source_wire,
&mut dirty_wires,
Self::was_visited_bwd,
Self::set_visited_bwd,
Self::was_visited_fwd,
npnr::Context::get_uphill_pips,
npnr::Context::pip_src_wire,
) {
break;
}*/
self.flat_wires[source_wire as usize]
.write()
.unwrap()
.visited_fwd = true;
self.flat_wires[sink_wire as usize]
.write()
.unwrap()
.visited_bwd = true;
// Step backward
if !self.step(
ctx,
nets,
arc,
criticality,
&mut bwd_queue,
&mut midpoint,
arc.source_wire,
&mut dirty_wires,
Self::was_visited_bwd,
Self::set_visited_bwd,
Self::was_visited_fwd,
npnr::Context::get_uphill_pips,
npnr::Context::pip_src_wire,
) {
break;
}
self.flat_wires[source_wire as usize]
.write()
.unwrap()
.visited_fwd = true;
self.flat_wires[sink_wire as usize]
.write()
.unwrap()
.visited_bwd = true;
}
assert!(
midpoint.is_some(),
"didn't find sink wire for net {} between {} and {}",
ctx.name_of(arc.name).to_str().unwrap(),
ctx.name_of_wire(arc.source_wire).to_str().unwrap(),
ctx.name_of_wire(arc.sink_wire).to_str().unwrap(),
ctx.name_of_wire(arc.source_wire),
ctx.name_of_wire(arc.sink_wire),
);
let mut wire = midpoint.unwrap();
@ -665,6 +801,43 @@ impl Router {
}
}
fn ripup_arc_general_routing(&self, ctx: &npnr::Context, arc: &Arc) -> (WireId, WireId) {
let is_general_routing = |wire: WireId| {
let wire = ctx.name_of_wire(wire);
wire.contains("H01")
|| wire.contains("V01")
|| wire.contains("H02")
|| wire.contains("V02")
|| wire.contains("H06")
|| wire.contains("V06")
};
let net = arc.net().into_inner() as usize;
let source_wire = arc.source_wire;
let mut wire = arc.sink_wire;
let mut last_was_general = false;
let mut w1 = arc.sink_wire;
let mut w2 = arc.source_wire;
while wire != source_wire {
let pip = self.nets.read().unwrap()[net].wires.get(&wire).expect("wire should have driving pip").0;
assert!(pip != PipId::null());
if is_general_routing(wire) {
if !last_was_general {
w1 = wire;
}
self.unbind_pip_internal(arc.net(), wire);
last_was_general = true;
} else {
if last_was_general {
w2 = wire;
}
last_was_general = false;
}
wire = ctx.pip_src_wire(pip);
}
(w2, w1)
}
fn reset_wires(&self, dirty_wires: &Vec<u32>) {
for &wire in dirty_wires {
let mut nwd = self.flat_wires[wire as usize].write().unwrap();