diff --git a/common/route/awooter.cc b/common/route/awooter.cc index bf7f97a3..a7164d0f 100644 --- a/common/route/awooter.cc +++ b/common/route/awooter.cc @@ -134,6 +134,8 @@ extern "C" { uint64_t npnr_context_get_pip_src_wire(const Context *const ctx, uint64_t pip) { return wrap(ctx->getPipSrcWire(unwrap_pip(pip))); } uint64_t npnr_context_get_pip_dst_wire(const Context *const ctx, uint64_t pip) { return wrap(ctx->getPipDstWire(unwrap_pip(pip))); } float npnr_context_estimate_delay(const Context *const ctx, uint64_t src, uint64_t dst) { return ctx->getDelayNS(ctx->estimateDelay(unwrap_wire(src), unwrap_wire(dst))); } + float npnr_context_get_pip_delay(const Context *const ctx, uint64_t pip) { return ctx->getDelayNS(ctx->getPipDelay(unwrap_pip(pip)).maxDelay()); } + 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)); } @@ -270,6 +272,8 @@ extern "C" { bool npnr_netinfo_is_global(NetInfo *const net) { return false; } #endif + int32_t npnr_netinfo_udata(NetInfo *const net) { return net->udata; } + 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 a037ec0d..8739a7c9 100644 --- a/common/route/awooter/rust/src/lib.rs +++ b/common/route/awooter/rust/src/lib.rs @@ -2,6 +2,8 @@ use std::{ptr::NonNull, time::Instant}; use colored::Colorize; +use crate::partition::Coord; + #[macro_use] mod npnr; mod partition; @@ -206,6 +208,9 @@ fn route(ctx: &mut npnr::Context) -> bool { println!("count in nw: {}", invalid_arcs_in_nw.to_string().bold()); } + let mut router = route::Router::new(Coord::new(0, 0), Coord::new(x_part, y_part)); + router.route(ctx, &ne); + /*log_info!("=== level 2 NE:\n"); let _ = find_partition_point(&ne, x_start, x, y_start, y); log_info!("=== level 2 SE:\n"); diff --git a/common/route/awooter/rust/src/npnr.rs b/common/route/awooter/rust/src/npnr.rs index ab7fecfc..cd7c281c 100644 --- a/common/route/awooter/rust/src/npnr.rs +++ b/common/route/awooter/rust/src/npnr.rs @@ -1,5 +1,5 @@ use core::slice; -use std::{collections::HashMap, ffi::CStr, marker::PhantomData, os::raw::c_void}; +use std::{collections::HashMap, ffi::CStr, marker::PhantomData}; use libc::c_char; @@ -39,8 +39,16 @@ impl NetInfo { pub fn is_global(&self) -> bool { unsafe { npnr_netinfo_is_global(self) } } + + pub fn index(&self) -> NetIndex { + unsafe { npnr_netinfo_udata(self) } + } } +#[repr(transparent)] +#[derive(Clone, Copy, PartialEq, Eq)] +pub struct NetIndex(i32); + #[repr(C)] pub struct PortRef { private: [u8; 0], @@ -91,7 +99,7 @@ impl PipId { } } -#[derive(Clone, Copy, PartialEq, Eq)] +#[derive(Clone, Copy, PartialEq, Eq, Hash)] #[repr(transparent)] pub struct WireId(u64); @@ -187,6 +195,18 @@ impl Context { unsafe { npnr_context_estimate_delay(self, src, dst) as f32 } } + pub fn pip_delay(&self, pip: PipId) -> f32 { + unsafe { npnr_context_get_pip_delay(self, pip) } + } + + pub fn wire_delay(&self, wire: WireId) -> f32 { + unsafe { npnr_context_get_wire_delay(self, wire) } + } + + pub fn delay_epsilon(&self) -> f32 { + unsafe { npnr_context_delay_epsilon(self) } + } + pub fn source_wire(&self, net: *const NetInfo) -> WireId { unsafe { npnr_context_get_netinfo_source_wire(self, net) } } @@ -290,7 +310,10 @@ extern "C" { fn npnr_context_unbind_pip(ctx: *mut Context, pip: PipId); fn npnr_context_get_pip_src_wire(ctx: *const Context, pip: PipId) -> WireId; fn npnr_context_get_pip_dst_wire(ctx: *const Context, pip: PipId) -> WireId; - fn npnr_context_estimate_delay(ctx: *const Context, src: WireId, dst: WireId) -> libc::c_float; + fn npnr_context_estimate_delay(ctx: *const Context, src: WireId, dst: WireId) -> f32; + fn npnr_context_delay_epsilon(ctx: *const Context) -> f32; + fn npnr_context_get_pip_delay(ctx: *const Context, pip: PipId) -> f32; + fn npnr_context_get_wire_delay(ctx: *const Context, wire: WireId) -> f32; fn npnr_context_get_wires_leak(ctx: *const Context, wires: *mut *mut WireId) -> u64; 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; @@ -321,6 +344,7 @@ extern "C" { fn npnr_netinfo_driver(net: *mut NetInfo) -> *mut PortRef; 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_portref_cell(port: *const PortRef) -> *mut CellInfo; fn npnr_cellinfo_get_location(info: *const CellInfo) -> Loc; @@ -334,6 +358,8 @@ extern "C" { pub struct Nets<'a> { nets: HashMap, users: HashMap, + index_to_net: Vec, + net_to_index: HashMap<*mut NetInfo, i32>, _data: PhantomData<&'a Context>, } @@ -353,6 +379,8 @@ impl<'a> Nets<'a> { }; let mut nets = HashMap::new(); let mut users = HashMap::new(); + let mut index_to_net = Vec::new(); + let mut net_to_index = HashMap::new(); for i in 0..size { let name = unsafe { IdString(*names.add(i as usize)) }; let net = unsafe { *nets_ptr.add(i as usize) }; @@ -365,11 +393,16 @@ impl<'a> Nets<'a> { unsafe { slice::from_raw_parts(users_ptr as *mut &mut PortRef, len as usize) }; nets.insert(name, net); users.insert(name, users_slice); + let index = index_to_net.len() as i32; + index_to_net.push(name); + net_to_index.insert(net, index); } // Note: the contents of `names` and `nets_ptr` are now lost. Self { nets, users, + index_to_net, + net_to_index, _data: PhantomData, } } diff --git a/common/route/awooter/rust/src/partition.rs b/common/route/awooter/rust/src/partition.rs index 05f37fdc..4e30e5ec 100644 --- a/common/route/awooter/rust/src/partition.rs +++ b/common/route/awooter/rust/src/partition.rs @@ -42,6 +42,14 @@ impl Coord { self.y < other.y } + pub fn is_south_of(&self, other: &Self) -> bool { + self.x > other.x + } + + pub fn is_west_of(&self, other: &Self) -> bool { + self.y > other.y + } + pub fn segment_from(&self, other: &Self) -> Segment { match (self.is_north_of(other), self.is_east_of(other)) { (true, true) => Segment::Northeast, @@ -52,6 +60,15 @@ impl Coord { } } +impl From for Coord { + fn from(other: npnr::Loc) -> Self { + Self { + x: other.x, + y: other.y, + } + } +} + pub fn find_partition_point( ctx: &npnr::Context, arcs: &[Arc], diff --git a/common/route/awooter/rust/src/route.rs b/common/route/awooter/rust/src/route.rs index ad54068e..e24ee1bd 100644 --- a/common/route/awooter/rust/src/route.rs +++ b/common/route/awooter/rust/src/route.rs @@ -1,21 +1,23 @@ -use crate::npnr; +use std::collections::{BinaryHeap, HashMap}; + +use crate::{npnr::{self, NetIndex, PipId}, partition}; pub struct Arc { source_wire: npnr::WireId, source_loc: npnr::Loc, sink_wire: npnr::WireId, sink_loc: npnr::Loc, - net: *mut npnr::NetInfo, + net: npnr::NetIndex, } impl Arc { - pub fn new(source_wire: npnr::WireId, source_loc: npnr::Loc, sink_wire: npnr::WireId, sink_loc: npnr::Loc, net: *mut npnr::NetInfo) -> Self { + pub fn new(source_wire: npnr::WireId, source_loc: npnr::Loc, sink_wire: npnr::WireId, sink_loc: npnr::Loc, net: NetIndex) -> Self { Self { source_wire, source_loc, sink_wire, sink_loc, net } } - pub fn split(&self, ctx: &npnr::Context, pip: npnr::PipId) -> (Self, Self) { + pub fn split(&mut self, ctx: &npnr::Context, pip: npnr::PipId) -> (Self, Self) { let pip_src = ctx.pip_src_wire(pip); let pip_dst = ctx.pip_dst_wire(pip); (Self { @@ -35,6 +37,147 @@ impl Arc { } } -pub struct Router { - arcs: Vec +#[derive(Copy, Clone)] +struct QueuedWire { + cost: f32, + togo: f32, + wire: npnr::WireId, +} + +impl QueuedWire { + pub fn new(cost: f32, togo: f32, wire: npnr::WireId) -> Self { + Self { + cost, + togo, + wire, + } + } +} + +impl PartialEq for QueuedWire { + fn eq(&self, other: &Self) -> bool { + self.cost == other.cost && self.togo == other.togo && self.wire == other.wire + } +} + +impl Eq for QueuedWire {} + +impl Ord for QueuedWire { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + let me = self.cost + self.togo; + let other = other.cost + other.togo; + other.total_cmp(&me) + } +} + +impl PartialOrd for QueuedWire { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +pub struct Router { + box_ne: partition::Coord, + box_sw: partition::Coord, + bound_pip: HashMap, + wire_driver: HashMap, +} + +impl Router { + pub fn new(box_ne: partition::Coord, box_sw: partition::Coord) -> Self { + Self { + box_ne, + box_sw, + bound_pip: HashMap::new(), + wire_driver: HashMap::new(), + } + } + + pub fn route(&mut self, ctx: &npnr::Context, arcs: &[Arc]) { + for arc in arcs { + self.route_arc(ctx, arc); + } + } + + fn route_arc(&mut self, ctx: &npnr::Context, 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()); + + while let Some(source) = queue.pop() { + if source.wire == arc.sink_wire { + panic!("found the sink!"); + break; + } + + 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); + + 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); + queue.push(qw); + } + } + + let mut wire = arc.sink_wire; + while wire != arc.source_wire { + let pip = *visited.get(&wire).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)); + self.bound_pip.insert(pip, net); + } }