diff --git a/common/route/awooter.cc b/common/route/awooter.cc index 329b6078..d3341d8a 100644 --- a/common/route/awooter.cc +++ b/common/route/awooter.cc @@ -126,6 +126,19 @@ extern "C" { 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_delay_epsilon(const Context *const ctx) { return ctx->getDelayNS(ctx->getDelayEpsilon()); } + uint64_t npnr_context_get_wires_leak(const Context *const ctx, WireId **wires) { + auto wire_vec = std::vector{}; + for (auto wire : ctx->getWires()) { + wire_vec.push_back(wire); + } + wire_vec.shrink_to_fit(); + auto size = wire_vec.size(); + *wires = wire_vec.data(); + // Yes, by placement-newing over `wire_vec` we leak memory. + new (&wire_vec) std::vector; + return size; + } + void npnr_context_check(const Context *const ctx) { ctx->check(); } 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(); } @@ -158,33 +171,6 @@ extern "C" { return size; } - // Yes, this is quadratic. It gets imported once and then never worried about again. - // There are bigger fish to fry. - int npnr_context_nets_key(const Context *const ctx, uint32_t n) { - if (ctx == nullptr) { - return 0; - } - for (auto& item : ctx->nets) { - if (n == 0) { - return item.first.hash(); - } - n--; - } - return 0; - } - NetInfo* npnr_context_nets_value(const Context *const ctx, uint32_t n) { - if (ctx == nullptr) { - return nullptr; - } - for (auto& item : ctx->nets) { - if (n == 0) { - return item.second.get(); - } - n--; - } - return nullptr; - } - PortRef* npnr_netinfo_driver(NetInfo *const net) { if (net == nullptr) { return nullptr; @@ -221,8 +207,6 @@ extern "C" { NEXTPNR_NAMESPACE_BEGIN bool router_awooter(Context *ctx) { - static_assert(std::is_standard_layout::value == true, "IdString is not FFI-safe"); - log_info("Running Awooter...\n"); auto result = npnr_router_awooter(ctx); log_info("Router returned: %d\n", result); diff --git a/common/route/awooter/rust/src/lib.rs b/common/route/awooter/rust/src/lib.rs index 803c37ca..2edf772b 100644 --- a/common/route/awooter/rust/src/lib.rs +++ b/common/route/awooter/rust/src/lib.rs @@ -212,6 +212,9 @@ fn route(ctx: &mut npnr::Context) -> bool { ctx.grid_dim_y() ); + let wires = npnr::Wires::new(ctx); + log_info!("Found {} wires\n", wires.len()); + let nets = npnr::Nets::new(ctx); log_info!("Found {} nets\n", nets.len()); @@ -301,6 +304,8 @@ fn route(ctx: &mut npnr::Context) -> bool { log_info!("=== level 1:\n"); let (x, y, ne, se, sw, nw) = find_partition_point(&arcs, x_start, x_finish, y_start, y_finish); + todo!("figure out how to tell if a wire crosses the calculated partition boundaries"); + /*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 15283b6e..f31dddf1 100644 --- a/common/route/awooter/rust/src/npnr.rs +++ b/common/route/awooter/rust/src/npnr.rs @@ -1,4 +1,5 @@ -use std::{ffi::CStr, collections::{HashMap}, ptr::{NonNull}, marker::PhantomData}; +use core::slice; +use std::{ffi::CStr, collections::{HashMap}, marker::PhantomData}; use libc::c_char; @@ -69,9 +70,7 @@ pub struct IdString(libc::c_int); /// A type representing a bel name. #[derive(Clone, Copy, PartialEq, Eq)] #[repr(transparent)] -pub struct BelId { - _private: u64, -} +pub struct BelId(u64); impl BelId { /// Return a sentinel value that represents an invalid bel. @@ -88,9 +87,7 @@ impl BelId { #[derive(Clone, Copy)] #[repr(transparent)] -pub struct PipId { - _private: u64, -} +pub struct PipId(u64); impl PipId { pub fn null() -> Self { @@ -256,6 +253,7 @@ extern "C" { 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_get_wires_leak(ctx: *const Context, wires: *mut *mut WireId) -> u64; fn npnr_context_check(ctx: *const Context); fn npnr_context_debug(ctx: *const Context) -> bool; @@ -284,9 +282,7 @@ extern "C" { /// Store for the users of a net. pub struct NetUsers<'a> { - users: NonNull<*mut PortRef>, - size: u32, - _data: PhantomData<&'a NetInfo>, + users: &'a [*mut PortRef], } impl<'a> NetUsers<'a> { @@ -294,9 +290,9 @@ impl<'a> NetUsers<'a> { let mut users = std::ptr::null_mut(); // SAFETY: net is not null because it's a &mut, and users is only written to. // Leaking memory is the most convenient FFI I could think of. - let size = unsafe { npnr_netinfo_users_leak(net, &mut users as *mut *mut *mut PortRef) }; - let users = unsafe { NonNull::new_unchecked(users) }; - Self { users, size, _data: PhantomData } + let len = unsafe { npnr_netinfo_users_leak(net, &mut users as *mut *mut *mut PortRef) }; + let users = unsafe { slice::from_raw_parts(users, len as usize) }; + Self { users } } pub fn iter(&self) -> NetUsersIter<'_> { @@ -306,17 +302,14 @@ impl<'a> NetUsers<'a> { pub struct NetUsersIter<'a> { users: &'a NetUsers<'a>, - n: u32, + n: usize, } impl Iterator for NetUsersIter<'_> { type Item = *mut PortRef; fn next(&mut self) -> Option { - if self.n >= self.users.size { - return None; - } - let user = unsafe { *self.users.users.as_ptr().add(self.n as usize) }; + let user = *self.users.users.get(self.n)?; self.n += 1; Some(user) } @@ -389,6 +382,27 @@ impl<'a> Iterator for NetSinkWireIter<'a> { } } +pub struct Wires<'a> { + wires: &'a [WireId], +} + +impl<'a> Wires<'a> { + pub fn new(ctx: &'a Context) -> Wires<'a> { + let mut wires = std::ptr::null_mut(); + let len = unsafe { npnr_context_get_wires_leak(ctx, &mut wires as *mut *mut WireId) }; + let wires = unsafe { std::slice::from_raw_parts(wires, len as usize) }; + Self { wires } + } + + pub fn len(&self) -> usize { + self.wires.len() + } + + pub fn iter(&self) -> impl Iterator { + self.wires.iter() + } +} + macro_rules! log_info { ($($t:tt)*) => { let s = std::ffi::CString::new(format!($($t)*)).unwrap();