From 1375277171e49006109eee785659bb72666d87fd Mon Sep 17 00:00:00 2001 From: Lofty Date: Sat, 3 Dec 2022 06:26:15 +0000 Subject: [PATCH] awooter: router improvements and a bugfix --- common/route/awooter.cc | 2 + common/route/awooter/rust/src/lib.rs | 21 +- common/route/awooter/rust/src/npnr.rs | 13 ++ common/route/awooter/rust/src/partition.rs | 17 +- common/route/awooter/rust/src/route.rs | 234 ++++++++++++++------- 5 files changed, 195 insertions(+), 92 deletions(-) diff --git a/common/route/awooter.cc b/common/route/awooter.cc index 7637c521..759e7da2 100644 --- a/common/route/awooter.cc +++ b/common/route/awooter.cc @@ -146,6 +146,7 @@ extern "C" { float npnr_context_get_wire_delay(const Context *const ctx, uint64_t wire) { return ctx->getDelayNS(ctx->getWireDelay(unwrap_wire(wire)).maxDelay()); } float npnr_context_delay_epsilon(const Context *const ctx) { return ctx->getDelayNS(ctx->getDelayEpsilon()); } Loc npnr_context_get_pip_location(const Context *const ctx, uint64_t pip) { return ctx->getPipLocation(unwrap_pip(pip)); } + bool npnr_context_check_pip_avail_for_net(const Context *const ctx, uint64_t pip, NetInfo *net) { return ctx->checkPipAvailForNet(unwrap_pip(pip), net); } // This method's in C++ temporarily, while I figure out some better way of getting a pip iterator. Loc npnr_context_get_pip_direction(const Context *const ctx, uint64_t _pip) { @@ -286,6 +287,7 @@ extern "C" { #endif int32_t npnr_netinfo_udata(NetInfo *const net) { return net->udata; } + void npnr_netinfo_udata_set(NetInfo *const net, int32_t value) { net->udata = value; } CellInfo* npnr_portref_cell(const PortRef *const port) { return port->cell; } Loc npnr_cellinfo_get_location(const CellInfo *const info) { return info->getLocation(); } diff --git a/common/route/awooter/rust/src/lib.rs b/common/route/awooter/rust/src/lib.rs index 9c11350d..d1ab7823 100644 --- a/common/route/awooter/rust/src/lib.rs +++ b/common/route/awooter/rust/src/lib.rs @@ -34,6 +34,13 @@ fn extract_arcs_from_nets(ctx: &npnr::Context, nets: &npnr::Nets) -> Vec Vec bool { let (x_part, y_part, ne, se, sw, nw) = partition::find_partition_point_and_sanity_check( ctx, + &nets, &partitionable_arcs[..], pips, - &nets, 0, ctx.grid_dim_x(), 0, @@ -221,7 +234,7 @@ fn route(ctx: &mut npnr::Context) -> bool { partitions.par_iter().for_each(|(box_ne, box_sw, arcs)| { let mut router = route::Router::new(*box_ne, *box_sw); - router.route(ctx, &nets, arcs, &progress); + router.route(ctx, &nets, wires, arcs, &progress); }); log_info!("Routing miscellaneous arcs\n"); @@ -229,7 +242,7 @@ fn route(ctx: &mut npnr::Context) -> bool { Coord::new(0, 0), Coord::new(ctx.grid_dim_x(), ctx.grid_dim_y()), ); - router.route(ctx, &nets, &special_arcs, &progress); + router.route(ctx, &nets, wires, &special_arcs, &progress); let time = format!("{:.2}", (Instant::now() - start).as_secs_f32()); log_info!("Routing took {}s\n", time.bold()); diff --git a/common/route/awooter/rust/src/npnr.rs b/common/route/awooter/rust/src/npnr.rs index 32d93d26..cd152034 100644 --- a/common/route/awooter/rust/src/npnr.rs +++ b/common/route/awooter/rust/src/npnr.rs @@ -49,6 +49,12 @@ impl NetInfo { #[derive(Clone, Copy, PartialEq, Eq, Hash)] pub struct NetIndex(i32); +impl NetIndex { + pub fn into_inner(self) -> i32 { + self.0 + } +} + #[repr(C)] pub struct PortRef { private: [u8; 0], @@ -271,6 +277,10 @@ impl Context { unsafe { npnr_context_get_pip_direction(self, pip) } } + pub fn pip_avail_for_net(&self, pip: PipId, net: *mut NetInfo) -> bool { + unsafe { npnr_context_check_pip_avail_for_net(self, pip, net) } + } + pub fn check(&self) { unsafe { npnr_context_check(self) } } @@ -346,6 +356,7 @@ extern "C-unwind" { fn npnr_context_get_pips_leak(ctx: *const Context, pips: *mut *mut PipId) -> u64; fn npnr_context_get_pip_location(ctx: *const Context, pip: PipId) -> Loc; fn npnr_context_get_pip_direction(ctx: *const Context, pip: PipId) -> Loc; + fn npnr_context_check_pip_avail_for_net(ctx: *const Context, pip: PipId, net: *const NetInfo) -> bool; fn npnr_context_check(ctx: *const Context); fn npnr_context_debug(ctx: *const Context) -> bool; @@ -377,6 +388,7 @@ extern "C-unwind" { fn npnr_netinfo_users_leak(net: *mut NetInfo, users: *mut *mut *mut PortRef) -> u32; fn npnr_netinfo_is_global(net: *const NetInfo) -> bool; fn npnr_netinfo_udata(net: *const NetInfo) -> NetIndex; + fn npnr_netinfo_udata_set(net: *mut NetInfo, value: NetIndex); fn npnr_portref_cell(port: *const PortRef) -> *mut CellInfo; fn npnr_cellinfo_get_location(info: *const CellInfo) -> Loc; @@ -434,6 +446,7 @@ impl<'a> Nets<'a> { let index = index_to_net.len() as i32; index_to_net.push(name); net_to_index.insert(net, index); + unsafe { npnr_netinfo_udata_set(net, NetIndex(index)); } } // Note: the contents of `names` and `nets_ptr` are now lost. Self { diff --git a/common/route/awooter/rust/src/partition.rs b/common/route/awooter/rust/src/partition.rs index e9b6d39f..db3a0357 100644 --- a/common/route/awooter/rust/src/partition.rs +++ b/common/route/awooter/rust/src/partition.rs @@ -112,9 +112,9 @@ impl From for Coord { pub fn find_partition_point( ctx: &npnr::Context, + nets: &npnr::Nets, arcs: &[Arc], pips: &[npnr::PipId], - nets: &npnr::Nets, x_start: i32, x_finish: i32, y_start: i32, @@ -133,9 +133,9 @@ pub fn find_partition_point( while x_diff != 0 { (ne, se, sw, nw) = partition( ctx, + nets, arcs, pips, - nets, x, y, x_start..=x_finish, @@ -178,9 +178,9 @@ pub fn find_partition_point( (ne, se, sw, nw) = partition( ctx, + nets, arcs, pips, - nets, x, y, x_start..=x_finish, @@ -251,9 +251,9 @@ fn split_line_over_y(line: (npnr::Loc, npnr::Loc), y_location: i32) -> i32 { /// result which is correct, without any care about speed or actual pathing optimality fn partition>( ctx: &npnr::Context, + nets: &npnr::Nets, arcs: &[Arc], pips: &[npnr::PipId], - nets: &npnr::Nets, x: i32, y: i32, x_bounds: R, @@ -307,9 +307,8 @@ fn partition>( 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.name_of(nets.name_from_index(arc.net())).to_str().unwrap().to_string(); - let verbose = false; // name == "IBusCachedPlugin_fetchPc_pc_LUT4_Z_15_B_CCU2C_S0$CCU2_FCI_INT"; - //"soc0.processor.with_fpu.fpu_0.fpu_multiply_0.rin_CCU2C_S0_24_B1_LUT4_Z_B_CCU2C_S0_CIN_CCU2C_COUT_S1_LUT4_D_Z_LUT4_Z_D_CCU2C_S0_CIN_CCU2C_COUT_CIN_CCU2C_COUT$CCU2_FCI_INT"; + let name = ctx.name_of(nets.name_from_index(arc.net())).to_str().unwrap().to_string(); + let verbose = false; //name == "soc0.processor.with_fpu.fpu_0.fpu_multiply_0.rin_CCU2C_S0_4$CCU2_FCI_INT"; if source_is_north == sink_is_north && source_is_east == sink_is_east { let seg = source_coords.segment_from(&Coord::new(x, y)); vec![(seg, arc.clone())] @@ -618,16 +617,16 @@ fn partition>( pub fn find_partition_point_and_sanity_check( ctx: &npnr::Context, + nets: &npnr::Nets, 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, nets, x_start, x_finish, y_start, y_finish); + find_partition_point(ctx, nets, arcs, pips, x_start, x_finish, y_start, y_finish); let mut invalid_arcs_in_ne = 0; let mut invalid_arcs_in_se = 0; diff --git a/common/route/awooter/rust/src/route.rs b/common/route/awooter/rust/src/route.rs index a1a0af71..449c5e04 100644 --- a/common/route/awooter/rust/src/route.rs +++ b/common/route/awooter/rust/src/route.rs @@ -3,7 +3,7 @@ use std::collections::{BinaryHeap, HashMap}; use indicatif::{MultiProgress, ProgressBar, ProgressStyle}; use crate::{ - npnr::{self, NetIndex, PipId}, + npnr::{self, NetIndex, PipId, WireId}, partition, }; @@ -106,11 +106,28 @@ impl PartialOrd for QueuedWire { } } + +struct PerNetData { + wires: HashMap, +} + +struct PerWireData { + wire: WireId, + curr_cong: u32, + hist_cong: f32, + unavailable: bool, + reserved_net: Option, + pip_fwd: PipId, + visited_fwd: bool, +} + pub struct Router { box_ne: partition::Coord, box_sw: partition::Coord, - bound_pip: HashMap, - wire_driver: HashMap, + nets: Vec, + wire_to_idx: HashMap, + flat_wires: Vec, + dirty_wires: Vec, } impl Router { @@ -118,8 +135,10 @@ impl Router { Self { box_ne, box_sw, - bound_pip: HashMap::new(), - wire_driver: HashMap::new(), + nets: Vec::new(), + wire_to_idx: HashMap::new(), + flat_wires: Vec::new(), + dirty_wires: Vec::new(), } } @@ -127,9 +146,28 @@ impl Router { &mut self, ctx: &npnr::Context, nets: &npnr::Nets, + wires: &[npnr::WireId], arcs: &[Arc], progress: &MultiProgress, ) { + log_info!("Setting up router...\n"); + for _ in 0..nets.len() { + self.nets.push(PerNetData { wires: HashMap::new() }); + } + + for (idx, &wire) in wires.iter().enumerate() { + self.flat_wires.push(PerWireData { + wire, + curr_cong: 0, + hist_cong: 0.0, + unavailable: false, + reserved_net: None, + pip_fwd: PipId::null(), + visited_fwd: false + }); + self.wire_to_idx.insert(wire, idx as u32); + } + let progress = progress.add(ProgressBar::new(arcs.len() as u64)); progress.set_style( ProgressStyle::with_template("[{elapsed}] [{bar:40.magenta/red}] {msg:30!}") @@ -148,8 +186,7 @@ impl Router { if net.is_global() { continue; } - //log_info!("{}\n", name); - //log_info!(" {} to {}\n", ctx.name_of_wire(arc.source_wire).to_str().unwrap(), ctx.name_of_wire(arc.sink_wire).to_str().unwrap()); + progress.inc(1); progress.set_message(name); self.route_arc(ctx, nets, arc); @@ -159,10 +196,7 @@ impl Router { fn route_arc(&mut self, ctx: &npnr::Context, nets: &npnr::Nets, arc: &Arc) { let mut queue = BinaryHeap::new(); - let mut visited = HashMap::new(); - queue.push(QueuedWire::new(0.0, 0.0, arc.source_wire)); - visited.insert(arc.source_wire, npnr::PipId::null()); let mut found_sink = false; @@ -171,8 +205,7 @@ impl Router { .to_str() .unwrap() .to_string(); - let verbose = false; - //name == "decode_to_execute_IS_RS2_SIGNED_LUT4_D_1_Z_CCU2C_B1_S0_CCU2C_S0_3_B1"; + let verbose = false; //name == "soc0.processor.with_fpu.fpu_0.fpu_multiply_0.rin_CCU2C_S0_4$CCU2_FCI_INT"; while let Some(source) = queue.pop() { if source.wire == arc.sink_wire { @@ -185,62 +218,65 @@ impl Router { } for pip in ctx.get_downhill_pips(source.wire) { - let pip_loc = ctx.pip_location(pip); - let pip_coord = partition::Coord::from(pip_loc); - if pip_coord.is_north_of(&self.box_ne) || pip_coord.is_east_of(&self.box_ne) { - continue; - } - if pip_coord.is_south_of(&self.box_sw) || pip_coord.is_west_of(&self.box_sw) { - continue; - } - - /* - if (!ctx->checkPipAvailForNet(dh, net)) - continue; - WireId next = ctx->getPipDstWire(dh); - int next_idx = wire_to_idx.at(next); - if (was_visited_fwd(next_idx)) { - // Don't expand the same node twice. - continue; - } - auto &nwd = flat_wires.at(next_idx); - if (nwd.unavailable) - continue; - // Reserved for another net - if (nwd.reserved_net != -1 && nwd.reserved_net != net->udata) - continue; - // Don't allow the same wire to be bound to the same net with a different driving pip - auto fnd_wire = nd.wires.find(next); - if (fnd_wire != nd.wires.end() && fnd_wire->second.first != dh) - continue; - if (!thread_test_wire(t, nwd)) - continue; // thread safety issue - */ - - let sink = ctx.pip_dst_wire(pip); - if visited.contains_key(&sink) { - continue; - } - - /*let driver = self.wire_driver.get(&sink); - if let Some(&driver) = driver { - if driver != pip { - continue; - } - if *self.bound_pip.get(&driver).unwrap() != arc.net { - continue; - } - }*/ - - visited.insert(sink, pip); - if verbose { log_info!(" {}\n", ctx.name_of_pip(pip).to_str().unwrap()); } + let pip_loc = ctx.pip_location(pip); + let pip_coord = partition::Coord::from(pip_loc); + if pip_coord.is_north_of(&self.box_ne) || pip_coord.is_east_of(&self.box_ne) { + if verbose { + log_info!(" out-of-bounds (NE)\n"); + } + continue; + } + if pip_coord.is_south_of(&self.box_sw) || pip_coord.is_west_of(&self.box_sw) { + if verbose { + log_info!(" out-of-bounds (SW)\n"); + } + continue; + } + if !ctx.pip_avail_for_net(pip, nets.net_from_index(arc.net())) { + if verbose { + log_info!(" pip unavailable for net\n"); + } + continue; + } + let wire = ctx.pip_dst_wire(pip); + let sink = *self.wire_to_idx.get(&wire).unwrap(); + if self.was_visited_fwd(sink) { + if verbose { + log_info!(" already visited\n"); + } + continue; + } + let nd = &mut self.nets[arc.net().into_inner() as usize]; + let nwd = &self.flat_wires[sink as usize]; + if nwd.unavailable { + if verbose { + log_info!(" unavailable\n"); + } + continue; + } + if let Some(net) = nwd.reserved_net && net != arc.net() { + if verbose { + log_info!(" reserved for other net\n"); + } + continue; + } + // Don't allow the same wire to be bound to the same net with a different driving pip + if let Some((found_pip, _)) = nd.wires.get(&wire) && *found_pip != pip { + if verbose { + log_info!(" driven by other pip\n"); + } + continue; + } + + self.set_visited_fwd(sink, pip); + let delay = - source.cost + ctx.pip_delay(pip) + ctx.wire_delay(sink) + ctx.delay_epsilon(); - let qw = QueuedWire::new(delay, ctx.estimate_delay(sink, arc.sink_wire), sink); + source.cost + ctx.pip_delay(pip) + ctx.wire_delay(wire) + ctx.delay_epsilon(); + let qw = QueuedWire::new(delay, ctx.estimate_delay(wire, arc.sink_wire), wire); queue.push(qw); } } @@ -253,24 +289,64 @@ impl Router { ctx.name_of_wire(arc.sink_wire).to_str().unwrap() ); - let mut wire = arc.sink_wire; - while wire != arc.source_wire { - /*if verbose { - println!("Wire: {}", ctx.name_of_wire(wire).to_str().unwrap()); - }*/ - let pip = *visited.get(&wire).unwrap_or_else(|| { - panic!( - "Expected wire {} to have driving pip", - ctx.name_of_wire(wire).to_str().unwrap() - ) - }); - self.bind_pip(pip, arc.net); - wire = ctx.pip_src_wire(pip); + let source_wire = *self.wire_to_idx.get(&arc.source_wire).unwrap(); + let mut wire = *self.wire_to_idx.get(&arc.sink_wire).unwrap(); + while wire != source_wire { + if verbose { + println!("Wire: {}", ctx.name_of_wire(self.flat_wires[wire as usize].wire).to_str().unwrap()); + } + let pip = self.flat_wires[wire as usize].pip_fwd; + assert!(pip != PipId::null()); + self.bind_pip_internal(arc.net(), wire, pip); + wire = *self.wire_to_idx.get(&ctx.pip_src_wire(pip)).unwrap(); } + + self.reset_wires(); } - fn bind_pip(&mut self, pip: PipId, net: NetIndex) { - //assert!(!self.bound_pip.contains_key(&pip)); - self.bound_pip.insert(pip, net); + fn was_visited_fwd(&self, wire: u32) -> bool { + self.flat_wires[wire as usize].visited_fwd } + + fn set_visited_fwd(&mut self, wire: u32, pip: PipId) { + let wd = &mut self.flat_wires[wire as usize]; + if !wd.visited_fwd { + self.dirty_wires.push(wire); + } + wd.pip_fwd = pip; + wd.visited_fwd = true; + } + + fn bind_pip_internal(&mut self, net: NetIndex, wire: u32, pip: PipId) { + let wireid = self.flat_wires[wire as usize].wire; + let net = &mut self.nets[net.into_inner() as usize]; + if let Some((bound_pip, usage)) = net.wires.get_mut(&wireid) { + assert!(*bound_pip == pip); + *usage += 1; + } else { + net.wires.insert(wireid, (pip, 1)); + self.flat_wires[wire as usize].curr_cong += 1; + } + } + + fn reset_wires(&mut self) { + for &wire in &self.dirty_wires { + self.flat_wires[wire as usize].pip_fwd = PipId::null(); + self.flat_wires[wire as usize].visited_fwd = false; + } + self.dirty_wires.clear(); + } + /* + void unbind_pip_internal(PerNetData &net, store_index user, WireId wire) + { + auto &wd = wire_data(wire); + auto &b = net.wires.at(wd.w); + --b.second; + if (b.second == 0) { + // No remaining arcs of this net bound to this wire + --wd.curr_cong; + net.wires.erase(wd.w); + } + } + */ }