diff --git a/common/route/awooter.cc b/common/route/awooter.cc index 7ae89642..7637c521 100644 --- a/common/route/awooter.cc +++ b/common/route/awooter.cc @@ -214,15 +214,12 @@ extern "C" { bool npnr_context_debug(const Context *const ctx) { return ctx->debug; } int npnr_context_id(const Context *const ctx, const char *const str) { return ctx->id(str).hash(); } const char *npnr_context_name_of(const Context *const ctx, IdString str) { return ctx->nameOf(str); } + const char *npnr_context_name_of_pip(const Context *const ctx, uint64_t pip) { return ctx->nameOfPip(unwrap_pip(pip)); } + const char *npnr_context_name_of_wire(const Context *const ctx, uint64_t wire) { return ctx->nameOfWire(unwrap_wire(wire)); } bool npnr_context_verbose(const Context *const ctx) { return ctx->verbose; } uint64_t npnr_context_get_netinfo_source_wire(const Context *const ctx, const NetInfo *const net) { return wrap(ctx->getNetinfoSourceWire(net)); } - uint64_t npnr_context_get_netinfo_sink_wire(const Context *const ctx, const NetInfo *const net, const PortRef *const sink, uint32_t n) { - if (ctx == nullptr) { - return 0; - } - return wrap(ctx->getNetinfoSinkWire(net, *sink, n)); - } + uint64_t npnr_context_get_netinfo_sink_wire(const Context *const ctx, const NetInfo *const net, const PortRef *const sink, uint32_t n) { return wrap(ctx->getNetinfoSinkWire(net, *sink, n)); } uint32_t npnr_context_nets_leak(const Context *const ctx, int **names, NetInfo ***nets) { auto name_vec = std::vector{}; diff --git a/common/route/awooter/rust/src/lib.rs b/common/route/awooter/rust/src/lib.rs index 49a71d14..ab4c4c64 100644 --- a/common/route/awooter/rust/src/lib.rs +++ b/common/route/awooter/rust/src/lib.rs @@ -23,9 +23,9 @@ pub extern "C" fn npnr_router_awooter(ctx: Option>) -> bo }) } -fn extract_arcs_from_nets(ctx: &npnr::Context, nets: npnr::Nets) -> Vec { +fn extract_arcs_from_nets(ctx: &npnr::Context, nets: &npnr::Nets) -> Vec { let mut arcs = vec![]; - for (name, net) in nets.iter() { + for (name, net) in nets.to_vec().iter() { let net = unsafe { net.as_mut().unwrap() }; if net.is_global() { continue; @@ -36,7 +36,7 @@ fn extract_arcs_from_nets(ctx: &npnr::Context, nets: npnr::Nets) -> Vec bool { log_info!("Found {} nets\n", nets_str.bold()); let mut count = 0; - for (name, net) in nets.iter() { - let _src = ctx.source_wire(*net); + for (&name, net) in nets.to_vec().iter() { + let _src = ctx.source_wire(**net); let net = unsafe { net.as_mut().unwrap() }; - let users = nets.users_by_name(*name).unwrap().iter(); + let users = nets.users_by_name(name).unwrap().iter(); for user in users { count += ctx.sink_wires(net, *user).len(); } @@ -92,7 +92,9 @@ fn route(ctx: &mut npnr::Context) -> bool { log_info!("Found {} arcs\n", count.to_string().bold()); - let (name, net) = nets + let binding = nets + .to_vec(); + let (name, net) = binding .iter() .max_by_key(|(name, net)| { let net = unsafe { net.as_mut().unwrap() }; @@ -109,7 +111,7 @@ fn route(ctx: &mut npnr::Context) -> bool { let net = unsafe { net.as_mut().unwrap() }; let count = nets - .users_by_name(*name) + .users_by_name(**name) .unwrap() .iter() .fold(0, |acc, sink| acc + ctx.sink_wires(net, *sink).len()) @@ -117,7 +119,7 @@ fn route(ctx: &mut npnr::Context) -> bool { log_info!( "Highest non-global fanout net is {}\n", - ctx.name_of(*name).to_str().unwrap().bold() + ctx.name_of(**name).to_str().unwrap().bold() ); log_info!(" with {} arcs\n", count.bold()); @@ -126,7 +128,7 @@ fn route(ctx: &mut npnr::Context) -> bool { let mut x1 = 0; let mut y1 = 0; - for sink in nets.users_by_name(*name).unwrap().iter() { + for sink in nets.users_by_name(**name).unwrap().iter() { let cell = sink.cell().unwrap().location(); x0 = x0.min(cell.x); y0 = y0.min(cell.y); @@ -147,12 +149,15 @@ fn route(ctx: &mut npnr::Context) -> bool { rayon::current_num_threads().to_string().bold() ); + + let start = Instant::now(); - let arcs = extract_arcs_from_nets(ctx, nets); + let arcs = extract_arcs_from_nets(ctx, &nets); let (x_part, y_part, ne, se, sw, nw) = partition::find_partition_point_and_sanity_check( ctx, + &nets, &arcs[..], pips, 0, @@ -166,7 +171,7 @@ fn route(ctx: &mut npnr::Context) -> bool { log_info!("Partitioning took {:.2}s\n", time.as_secs_f32()); let mut router = route::Router::new(Coord::new(0, 0), Coord::new(x_part, y_part)); - router.route(ctx, &ne); + router.route(ctx, &nets, &ne); /*log_info!("=== level 2 NE:\n"); let _ = find_partition_point(&ne, x_start, x, y_start, y); diff --git a/common/route/awooter/rust/src/npnr.rs b/common/route/awooter/rust/src/npnr.rs index 0bcd5252..c7facc89 100644 --- a/common/route/awooter/rust/src/npnr.rs +++ b/common/route/awooter/rust/src/npnr.rs @@ -278,6 +278,14 @@ impl Context { unsafe { CStr::from_ptr(npnr_context_name_of(self, s)) } } + pub fn name_of_pip(&self, pip: PipId) -> &CStr { + unsafe { CStr::from_ptr(npnr_context_name_of_pip(self, pip)) } + } + + pub fn name_of_wire(&self, wire: WireId) -> &CStr { + unsafe { CStr::from_ptr(npnr_context_name_of_wire(self, wire)) } + } + pub fn verbose(&self) -> bool { unsafe { npnr_context_verbose(self) } } @@ -331,6 +339,8 @@ extern "C" { fn npnr_context_debug(ctx: *const Context) -> bool; fn npnr_context_id(ctx: *const Context, s: *const c_char) -> IdString; fn npnr_context_name_of(ctx: *const Context, s: IdString) -> *const libc::c_char; + fn npnr_context_name_of_pip(ctx: *const Context, pip: PipId) -> *const libc::c_char; + fn npnr_context_name_of_wire(ctx: *const Context, wire: WireId) -> *const libc::c_char; fn npnr_context_verbose(ctx: *const Context) -> bool; fn npnr_context_get_netinfo_source_wire(ctx: *const Context, net: *const NetInfo) -> WireId; @@ -376,6 +386,9 @@ pub struct Nets<'a> { _data: PhantomData<&'a Context>, } +unsafe impl Send for Nets<'_> {} +unsafe impl Sync for Nets<'_> {} + impl<'a> Nets<'a> { /// Create a new store for the nets of a context. /// @@ -430,8 +443,19 @@ impl<'a> Nets<'a> { self.nets.len() } - pub fn iter(&self) -> std::collections::hash_map::Iter<'_, IdString, *mut NetInfo> { - self.nets.iter() + pub fn name_from_index(&self, index: NetIndex) -> IdString { + self.index_to_net[index.0 as usize] + } + + pub fn net_from_index(&self, index: NetIndex) -> *mut NetInfo { + *self.nets.get(&self.name_from_index(index)).unwrap() + } + + pub fn to_vec(&self) -> Vec<(&IdString, &*mut NetInfo)> { + let mut v = Vec::new(); + v.extend(self.nets.iter()); + v.sort_by_key(|(name, _net)| name.0); + v } } diff --git a/common/route/awooter/rust/src/partition.rs b/common/route/awooter/rust/src/partition.rs index 2a94dfcf..36de7505 100644 --- a/common/route/awooter/rust/src/partition.rs +++ b/common/route/awooter/rust/src/partition.rs @@ -71,6 +71,7 @@ impl From for Coord { pub fn find_partition_point( ctx: &npnr::Context, + nets: &npnr::Nets, arcs: &[Arc], pips: &[npnr::PipId], x_start: i32, @@ -91,6 +92,7 @@ pub fn find_partition_point( while x_diff != 0 { (ne, se, sw, nw) = partition( ctx, + nets, arcs, pips, x, @@ -135,6 +137,7 @@ pub fn find_partition_point( (ne, se, sw, nw) = partition( ctx, + nets, arcs, pips, x, @@ -200,6 +203,7 @@ fn split_line_over_y(line: (npnr::Loc, npnr::Loc), y_location: i32) -> i32 { // A big thank you to @Spacecat-chan for fixing my broken and buggy partition code. fn partition>( ctx: &npnr::Context, + nets: &npnr::Nets, arcs: &[Arc], pips: &[npnr::PipId], x: i32, @@ -243,6 +247,22 @@ fn partition>( 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))); @@ -328,7 +348,7 @@ fn partition>( let progress = ProgressBar::new(arcs.len() as u64); progress.set_style( - ProgressStyle::with_template("[{elapsed}] [{bar:40.cyan/blue}] {msg}") + ProgressStyle::with_template("[{elapsed}] [{bar:40.cyan/blue}] {msg:30!}") .unwrap() .progress_chars("━╸ "), ); @@ -362,6 +382,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 = name == "decode_to_execute_IS_RS2_SIGNED_LUT4_D_1_Z_CCU2C_B1_S0_CCU2C_S0_3_B1"; 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())] @@ -383,6 +405,10 @@ fn partition>( let selected_pip = find_best_pip(pips, arc); explored_pips.fetch_add(pips.len(), std::sync::atomic::Ordering::Relaxed); + if verbose { + log_info!("split arc {} to {} vertically across pip {}\n", ctx.name_of_wire(arc.get_source_wire()).to_str().unwrap(), ctx.name_of_wire(arc.get_sink_wire()).to_str().unwrap(), ctx.name_of_pip(selected_pip).to_str().unwrap()); + } + let (src_to_pip, pip_to_dst) = arc.split(ctx, selected_pip); let (seg1, seg2) = match (source_is_north, source_is_east) { (true, true) => (Segment::Northeast, Segment::Southeast), @@ -410,6 +436,10 @@ fn partition>( let selected_pip = find_best_pip(pips, arc); explored_pips.fetch_add(pips.len(), std::sync::atomic::Ordering::Relaxed); + if verbose { + log_info!("split arc {} to {} horizontally across pip {}\n", ctx.name_of_wire(arc.get_source_wire()).to_str().unwrap(), ctx.name_of_wire(arc.get_sink_wire()).to_str().unwrap(), ctx.name_of_pip(selected_pip).to_str().unwrap()); + } + let (src_to_pip, pip_to_dst) = arc.split(ctx, selected_pip); let (seg1, seg2) = match (source_is_north, source_is_east) { (true, true) => (Segment::Northeast, Segment::Northwest), @@ -458,6 +488,10 @@ fn partition>( let vert_pip = find_best_pip(pips, arc); explored_pips.fetch_add(pips.len(), std::sync::atomic::Ordering::Relaxed); + if verbose { + log_info!("split arc {} to {} across pips {} and {}\n", ctx.name_of_wire(arc.get_source_wire()).to_str().unwrap(), ctx.name_of_wire(arc.get_sink_wire()).to_str().unwrap(), ctx.name_of_pip(horiz_pip).to_str().unwrap(), ctx.name_of_pip(vert_pip).to_str().unwrap()); + } + let horiz_loc: Coord = ctx.pip_location(horiz_pip).into(); 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 { @@ -610,6 +644,7 @@ fn partition>( pub fn find_partition_point_and_sanity_check( ctx: &npnr::Context, + nets: &npnr::Nets, arcs: &[Arc], pips: &[npnr::PipId], x_start: i32, @@ -618,7 +653,7 @@ pub fn find_partition_point_and_sanity_check( y_finish: i32, ) -> (i32, i32, Vec, Vec, Vec, Vec) { let (x_part, y_part, ne, se, sw, nw) = - find_partition_point(ctx, arcs, pips, 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 13445f01..397deefc 100644 --- a/common/route/awooter/rust/src/route.rs +++ b/common/route/awooter/rust/src/route.rs @@ -1,4 +1,6 @@ -use std::collections::{BinaryHeap, HashMap}; +use std::{collections::{BinaryHeap, HashMap}, time::Duration}; + +use indicatif::{ProgressBar, ProgressStyle}; use crate::{ npnr::{self, NetIndex, PipId}, @@ -64,6 +66,9 @@ impl Arc { pub fn get_sink_wire(&self) -> npnr::WireId { self.sink_wire } + pub fn net(&self) -> npnr::NetIndex { + self.net + } } #[derive(Copy, Clone)] @@ -118,34 +123,62 @@ impl Router { } } - pub fn route(&mut self, ctx: &npnr::Context, arcs: &[Arc]) { + pub fn route(&mut self, ctx: &npnr::Context, nets: &npnr::Nets, arcs: &[Arc]) { + let progress = ProgressBar::new(arcs.len() as u64); + progress.set_style( + ProgressStyle::with_template("[{elapsed}] [{bar:40.magenta/red}] {msg:30!}") + .unwrap() + .progress_chars("━╸ "), + ); + + progress.enable_steady_tick(Duration::from_secs_f32(0.2)); for arc in arcs { - self.route_arc(ctx, arc); + let net = unsafe { nets.net_from_index(arc.net).as_ref().unwrap() }; + let name = ctx.name_of(nets.name_from_index(arc.net)).to_str().unwrap().to_string(); + + 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); } + progress.finish_and_clear() } - fn route_arc(&mut self, ctx: &npnr::Context, arc: &Arc) { + 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; + + let name = ctx.name_of(nets.name_from_index(arc.net)).to_str().unwrap().to_string(); + let verbose = name == "decode_to_execute_IS_RS2_SIGNED_LUT4_D_1_Z_CCU2C_B1_S0_CCU2C_S0_3_B1"; + while let Some(source) = queue.pop() { if source.wire == arc.sink_wire { - panic!("found the sink!"); + found_sink = true; break; } + if verbose { + log_info!("{}:\n", ctx.name_of_wire(source.wire).to_str().unwrap()); + } + for pip in ctx.get_downhill_pips(source.wire) { - let pip_loc = ctx.pip_location(pip); + /*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)) @@ -175,7 +208,7 @@ impl Router { continue; } - let driver = self.wire_driver.get(&sink); + /*let driver = self.wire_driver.get(&sink); if let Some(&driver) = driver { if driver != pip { continue; @@ -183,10 +216,14 @@ impl Router { 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 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); @@ -194,16 +231,21 @@ impl Router { } } + assert!(found_sink, "didn't find sink wire for net {} between {} and {}", name, ctx.name_of_wire(arc.source_wire).to_str().unwrap(), ctx.name_of_wire(arc.sink_wire).to_str().unwrap()); + let mut wire = arc.sink_wire; while wire != arc.source_wire { - let pip = *visited.get(&wire).unwrap(); + /*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); } } fn bind_pip(&mut self, pip: PipId, net: NetIndex) { - assert!(!self.bound_pip.contains_key(&pip)); + //assert!(!self.bound_pip.contains_key(&pip)); self.bound_pip.insert(pip, net); } }