1
0
mirror of https://github.com/YosysHQ/nextpnr.git synced 2026-01-11 23:53:21 +00:00

rust: rework ownership model

This commit is contained in:
Lofty 2025-09-25 09:09:55 +01:00
parent 2e4ef6f71f
commit 0ee8181733
3 changed files with 134 additions and 105 deletions

View File

@ -1,12 +1,9 @@
use nextpnr::{Context, Nets};
use nextpnr::Context;
#[no_mangle]
pub extern "C" fn rust_example_printnets(ctx: &mut Context) {
let nets = Nets::new(ctx);
let nets_vec = nets.to_vec();
println!("Nets in design:");
for (&name, _net) in nets_vec {
for (name, _net) in &ctx.nets() {
println!(" {}", ctx.name_of(name).to_str().unwrap());
}
}

View File

@ -1,5 +1,4 @@
use core::slice;
use std::{collections::HashMap, ffi::CStr, marker::PhantomData, sync::Mutex};
use std::{ffi::CStr, marker::PhantomData, sync::Mutex};
use libc::c_char;
@ -392,6 +391,11 @@ impl Context {
pub fn verbose(&self) -> bool {
unsafe { npnr_context_verbose(self) }
}
#[must_use]
pub fn nets(&self) -> Nets<'_> {
Nets { ctx: self }
}
}
unsafe extern "C" {
@ -455,12 +459,6 @@ unsafe extern "C" {
n: u32,
) -> WireId;
fn npnr_context_nets_leak(
ctx: &Context,
names: *mut *mut libc::c_int,
nets: *mut *mut *mut NetInfo,
) -> u32;
fn npnr_netinfo_driver(net: &mut NetInfo) -> Option<&mut PortRef>;
fn npnr_netinfo_users_leak(net: &NetInfo, users: *mut *mut *const PortRef) -> u32;
fn npnr_netinfo_is_global(net: &NetInfo) -> bool;
@ -499,94 +497,54 @@ unsafe extern "C" {
fn npnr_inc_wire_iter(iter: &mut RawWireIter);
fn npnr_deref_wire_iter(iter: &mut RawWireIter) -> WireId;
fn npnr_is_wire_iter_done(iter: &mut RawWireIter) -> bool;
fn npnr_context_net_iter(ctx: &Context) -> &mut RawNetIter;
fn npnr_delete_net_iter(iter: &mut RawNetIter);
fn npnr_inc_net_iter(iter: &mut RawNetIter);
fn npnr_deref_net_iter_first(iter: &RawNetIter) -> libc::c_int;
fn npnr_deref_net_iter_second(iter: &RawNetIter) -> &mut NetInfo;
fn npnr_is_net_iter_done(iter: &RawNetIter) -> bool;
fn npnr_context_cell_iter(ctx: &Context) -> &mut RawCellIter;
fn npnr_delete_cell_iter(iter: &mut RawCellIter);
fn npnr_inc_cell_iter(iter: &mut RawCellIter);
fn npnr_deref_cell_iter_first(iter: &mut RawCellIter) -> libc::c_int;
fn npnr_deref_cell_iter_second(iter: &mut RawCellIter) -> &mut CellInfo;
fn npnr_is_cell_iter_done(iter: &mut RawCellIter) -> bool;
}
/// Store for the nets of a context.
pub struct Nets<'a> {
nets: HashMap<IdString, &'a mut NetInfo>,
users: HashMap<IdString, &'a [&'a PortRef]>,
index_to_net: Vec<IdString>,
_data: PhantomData<&'a Context>,
ctx: &'a Context,
}
impl<'a> Nets<'a> {
/// Create a new store for the nets of a context.
///
/// Note that this leaks memory created by nextpnr; the intention is this is called once.
#[must_use]
pub fn new(ctx: &'a Context) -> Self {
let mut names: *mut libc::c_int = std::ptr::null_mut();
let mut nets_ptr: *mut *mut NetInfo = std::ptr::null_mut();
let size = unsafe {
npnr_context_nets_leak(
ctx,
&raw mut names,
&raw mut nets_ptr,
)
};
let mut nets = HashMap::new();
let mut users = HashMap::new();
let mut index_to_net = Vec::new();
for i in 0..size {
let name = unsafe { IdString(*names.add(i as usize)) };
let net = unsafe { &mut **nets_ptr.add(i as usize) };
let mut users_ptr = 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 len =
unsafe { npnr_netinfo_users_leak(net, &raw mut users_ptr) };
let users_slice =
unsafe { slice::from_raw_parts(users_ptr.cast::<&PortRef>(), len as usize) };
let index = index_to_net.len() as i32;
index_to_net.push(name);
unsafe {
npnr_netinfo_udata_set(net, NetIndex(index));
}
nets.insert(name, net);
users.insert(name, users_slice);
}
// Note: the contents of `names` and `nets_ptr` are now lost.
Self {
nets,
users,
index_to_net,
_data: PhantomData,
impl<'a> IntoIterator for &'a Nets<'a> {
type Item = (IdString, *const NetInfo);
type IntoIter = NetIter<'a>;
fn into_iter(self) -> Self::IntoIter {
NetIter {
iter: unsafe { npnr_context_net_iter(self.ctx) },
phantom_data: PhantomData,
}
}
}
/// Find net users given a net's name.
#[must_use]
pub fn users_by_name(&self, net: IdString) -> Option<&&[&PortRef]> {
self.users.get(&net)
}
pub struct Cells<'a> {
ctx: &'a Context,
}
/// Return the number of nets in the store.
#[must_use]
pub fn len(&self) -> usize {
self.nets.len()
}
impl<'a> IntoIterator for &'a Cells<'a> {
type Item = (IdString, *const CellInfo);
#[must_use]
pub fn is_empty(&self) -> bool {
self.nets.len() == 0
}
type IntoIter = CellIter<'a>;
#[must_use]
pub fn name_from_index(&self, index: NetIndex) -> IdString {
self.index_to_net[index.0 as usize]
}
#[must_use]
pub fn net_from_index(&self, index: NetIndex) -> &NetInfo {
self.nets.get(&self.name_from_index(index)).unwrap()
}
#[must_use]
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
fn into_iter(self) -> Self::IntoIter {
CellIter {
iter: unsafe { npnr_context_cell_iter(self.ctx) },
phantom_data: PhantomData,
}
}
}
@ -761,6 +719,68 @@ impl Drop for WireIter<'_> {
}
}
#[repr(C)]
struct RawNetIter {
content: [u8; 0],
}
pub struct NetIter<'a> {
iter: &'a mut RawNetIter,
phantom_data: PhantomData<&'a NetInfo>,
}
impl Iterator for NetIter<'_> {
type Item = (IdString, *const NetInfo);
fn next(&mut self) -> Option<Self::Item> {
if unsafe { npnr_is_net_iter_done(self.iter) } {
None
} else {
let s = IdString(unsafe { npnr_deref_net_iter_first(self.iter) });
let net = unsafe { &raw const *npnr_deref_net_iter_second(self.iter) };
unsafe { npnr_inc_net_iter(self.iter) };
Some((s, net))
}
}
}
impl Drop for NetIter<'_> {
fn drop(&mut self) {
unsafe { npnr_delete_net_iter(self.iter) };
}
}
#[repr(C)]
struct RawCellIter {
content: [u8; 0],
}
pub struct CellIter<'a> {
iter: &'a mut RawCellIter,
phantom_data: PhantomData<&'a CellInfo>,
}
impl Iterator for CellIter<'_> {
type Item = (IdString, *const CellInfo);
fn next(&mut self) -> Option<Self::Item> {
if unsafe { npnr_is_cell_iter_done(self.iter) } {
None
} else {
let s = IdString(unsafe { npnr_deref_cell_iter_first(self.iter) });
let cell = unsafe { &raw const *npnr_deref_cell_iter_second(self.iter) };
unsafe { npnr_inc_cell_iter(self.iter) };
Some((s, cell))
}
}
}
impl Drop for CellIter<'_> {
fn drop(&mut self) {
unsafe { npnr_delete_cell_iter(self.iter) };
}
}
macro_rules! log_info {
($($t:tt)*) => {
let s = std::ffi::CString::new(format!($($t)*)).unwrap();

View File

@ -17,7 +17,8 @@
*/
#include <array>
#include <numeric>
#include "arch.h"
#include "context.h"
#include "log.h"
#include "nextpnr.h"
@ -78,6 +79,12 @@ using PipIterWrapper = IterWrapper<PipIter>;
using WireIter = decltype(Context(ArchArgs()).getWires().begin());
using WireIterWrapper = IterWrapper<WireIter>;
using NetIter = decltype(Context(ArchArgs()).nets.begin());
using NetIterWrapper = IterWrapper<NetIter>;
using CellIter = decltype(Context(ArchArgs()).cells.begin());
using CellIterWrapper = IterWrapper<CellIter>;
extern "C" {
USING_NEXTPNR_NAMESPACE;
@ -150,21 +157,6 @@ uint64_t npnr_context_get_netinfo_sink_wire(const Context *ctx, const NetInfo *n
return wrap(ctx->getNetinfoSinkWire(net, *sink, n));
}
uint32_t npnr_context_nets_leak(const Context *ctx, int **names, NetInfo ***nets)
{
auto size = ctx->nets.size();
*names = new int[size];
*nets = new NetInfo *[size];
auto idx = 0;
for (auto &item : ctx->nets) {
(*names)[idx] = item.first.index;
(*nets)[idx] = item.second.get();
idx++;
}
// Yes, by never deleting `names` and `nets` we leak memory.
return size;
}
DownhillIterWrapper *npnr_context_get_pips_downhill(Context *ctx, uint64_t wire_id)
{
auto wire = unwrap_wire(wire_id);
@ -217,6 +209,26 @@ void npnr_inc_wire_iter(WireIterWrapper *iter) { ++iter->current; }
uint64_t npnr_deref_wire_iter(WireIterWrapper *iter) { return wrap(*iter->current); }
bool npnr_is_wire_iter_done(WireIterWrapper *iter) { return !(iter->current != iter->end); }
NetIterWrapper *npnr_context_net_iter(Context *ctx)
{
return new NetIterWrapper(ctx->nets.begin(), ctx->nets.end());
}
void npnr_delete_net_iter(NetIterWrapper *iter) { delete iter; }
void npnr_inc_net_iter(NetIterWrapper *iter) { ++iter->current; }
int npnr_deref_net_iter_first(NetIterWrapper *iter) { return wrap(iter->current->first.index); }
NetInfo *npnr_deref_net_iter_second(NetIterWrapper *iter) { return iter->current->second.get(); }
bool npnr_is_net_iter_done(NetIterWrapper *iter) { return !(iter->current != iter->end); }
CellIterWrapper *npnr_context_cell_iter(Context *ctx)
{
return new CellIterWrapper(ctx->cells.begin(), ctx->cells.end());
}
void npnr_delete_cell_iter(CellIterWrapper *iter) { delete iter; }
void npnr_inc_cell_iter(CellIterWrapper *iter) { ++iter->current; }
int npnr_deref_cell_iter_first(CellIterWrapper *iter) { return wrap(iter->current->first.index); }
CellInfo *npnr_deref_cell_iter_second(CellIterWrapper *iter) { return iter->current->second.get(); }
bool npnr_is_cell_iter_done(CellIterWrapper *iter) { return !(iter->current != iter->end); }
PortRef *npnr_netinfo_driver(NetInfo *net)
{
if (net == nullptr) {