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:
parent
2e4ef6f71f
commit
0ee8181733
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@ -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();
|
||||
|
||||
44
rust/rust.cc
44
rust/rust.cc
@ -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) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user