rust: extend example_printnets to demo iterators

This commit is contained in:
Lofty 2025-09-26 12:09:25 +01:00
parent 0ee8181733
commit 8f8181c717
3 changed files with 95 additions and 20 deletions

View File

@ -3,7 +3,23 @@ use nextpnr::Context;
#[no_mangle]
pub extern "C" fn rust_example_printnets(ctx: &mut Context) {
println!("Nets in design:");
for (name, _net) in &ctx.nets() {
println!(" {}", ctx.name_of(name).to_str().unwrap());
for (name, net) in &ctx.nets() {
let net = unsafe { &*net };
let driver = net.driver();
println!(" {}:", ctx.name_of(name).to_str().unwrap());
if let Some(driver) = driver {
let cell = driver.cell().map_or("(no cell)", |cell| ctx.name_of(cell.name()).to_str().unwrap());
let port = ctx.name_of(driver.port()).to_str().unwrap();
println!(" driver: {cell}.{port}");
} else {
println!(" driver: (no driver)");
}
println!(" sinks:");
for (user, port) in net.users() {
let user = unsafe { &*user };
let user = ctx.name_of(user.name()).to_str().unwrap();
let port = ctx.name_of(port).to_str().unwrap();
println!(" {user}.{port}");
}
}
}

View File

@ -24,6 +24,11 @@ impl CellInfo {
pub fn location(&self) -> Loc {
unsafe { npnr_cellinfo_get_location(self) }
}
#[must_use]
pub fn name(&self) -> IdString {
IdString(unsafe { npnr_cellinfo_name(self) })
}
}
#[repr(C)]
@ -32,7 +37,7 @@ pub struct NetInfo {
}
impl NetInfo {
pub fn driver(&mut self) -> Option<&mut PortRef> {
pub fn driver(&self) -> Option<&PortRef> {
unsafe { npnr_netinfo_driver(self) }
}
@ -45,6 +50,14 @@ impl NetInfo {
pub fn index(&self) -> NetIndex {
unsafe { npnr_netinfo_udata(self) }
}
#[must_use]
pub fn users(&self) -> NetUserIter<'_> {
NetUserIter {
iter: unsafe { npnr_context_net_user_iter(self) },
phantom_data: PhantomData
}
}
}
#[repr(transparent)]
@ -69,6 +82,11 @@ impl PortRef {
// SAFETY: handing out &s is safe when we have &self.
unsafe { npnr_portref_cell(self) }
}
#[must_use]
pub fn port(&self) -> IdString {
IdString(unsafe { npnr_portref_port(self) })
}
}
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
@ -459,14 +477,15 @@ unsafe extern "C" {
n: u32,
) -> WireId;
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_driver(net: &NetInfo) -> Option<&PortRef>;
fn npnr_netinfo_is_global(net: &NetInfo) -> bool;
fn npnr_netinfo_udata(net: &NetInfo) -> NetIndex;
fn npnr_netinfo_udata_set(net: &mut NetInfo, value: NetIndex);
fn npnr_portref_cell(port: &PortRef) -> Option<&CellInfo>;
fn npnr_cellinfo_get_location(info: &CellInfo) -> Loc;
fn npnr_portref_port(port: &PortRef) -> libc::c_int;
fn npnr_cellinfo_get_location(cell: &CellInfo) -> Loc;
fn npnr_cellinfo_name(cell: &CellInfo) -> libc::c_int;
fn npnr_context_get_pips_downhill(ctx: &Context, wire: WireId) -> &mut RawDownhillIter;
fn npnr_delete_downhill_iter(iter: &mut RawDownhillIter);
@ -511,6 +530,13 @@ unsafe extern "C" {
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;
fn npnr_context_net_user_iter(net: &NetInfo) -> &mut RawNetUserIter;
fn npnr_delete_net_user_iter(iter: &mut RawNetUserIter);
fn npnr_inc_net_user_iter(iter: &mut RawNetUserIter);
fn npnr_deref_net_user_iter_cell(iter: &mut RawNetUserIter) -> &mut CellInfo;
fn npnr_deref_net_user_iter_port(iter: &mut RawNetUserIter) -> libc::c_int;
fn npnr_is_net_user_iter_done(iter: &mut RawNetUserIter) -> bool;
}
/// Store for the nets of a context.
@ -781,6 +807,37 @@ impl Drop for CellIter<'_> {
}
}
#[repr(C)]
struct RawNetUserIter {
content: [u8; 0],
}
pub struct NetUserIter<'a> {
iter: &'a mut RawNetUserIter,
phantom_data: PhantomData<&'a CellInfo>,
}
impl Iterator for NetUserIter<'_> {
type Item = (*const CellInfo, IdString);
fn next(&mut self) -> Option<Self::Item> {
if unsafe { npnr_is_net_user_iter_done(self.iter) } {
None
} else {
let cell = unsafe { &raw const *npnr_deref_net_user_iter_cell(self.iter) };
let port = IdString(unsafe { npnr_deref_net_user_iter_port(self.iter) });
unsafe { npnr_inc_net_user_iter(self.iter) };
Some((cell, port))
}
}
}
impl Drop for NetUserIter<'_> {
fn drop(&mut self) {
unsafe { npnr_delete_net_user_iter(self.iter) };
}
}
macro_rules! log_info {
($($t:tt)*) => {
let s = std::ffi::CString::new(format!($($t)*)).unwrap();

View File

@ -85,6 +85,9 @@ using NetIterWrapper = IterWrapper<NetIter>;
using CellIter = decltype(Context(ArchArgs()).cells.begin());
using CellIterWrapper = IterWrapper<CellIter>;
using NetUserIter = decltype(NetInfo(IdString()).users.begin());
using NetUserIterWrapper = IterWrapper<NetUserIter>;
extern "C" {
USING_NEXTPNR_NAMESPACE;
@ -229,6 +232,16 @@ int npnr_deref_cell_iter_first(CellIterWrapper *iter) { return wrap(iter->curren
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); }
NetUserIterWrapper *npnr_context_net_user_iter(NetInfo *net)
{
return new NetUserIterWrapper(net->users.begin(), net->users.end());
}
void npnr_delete_net_user_iter(NetUserIterWrapper *iter) { delete iter; }
void npnr_inc_net_user_iter(NetUserIterWrapper *iter) { ++iter->current; }
CellInfo *npnr_deref_net_user_iter_cell(NetUserIterWrapper *iter) { return (*iter->current).cell; }
uint64_t npnr_deref_net_user_iter_port(NetUserIterWrapper *iter) { return wrap((*iter->current).port.index); }
bool npnr_is_net_user_iter_done(NetUserIterWrapper *iter) { return !(iter->current != iter->end); }
PortRef *npnr_netinfo_driver(NetInfo *net)
{
if (net == nullptr) {
@ -237,19 +250,6 @@ PortRef *npnr_netinfo_driver(NetInfo *net)
return &net->driver;
}
uint32_t npnr_netinfo_users_leak(const NetInfo *net, const PortRef ***users)
{
auto size = net->users.entries();
*users = new const PortRef *[size];
auto idx = 0;
for (auto &item : net->users) {
(*users)[idx] = &item;
idx++;
}
// Yes, by not freeing `users`, we leak memory.
return size;
}
#ifdef ARCH_ECP5
bool npnr_netinfo_is_global(NetInfo *net) { return net->is_global; }
#else
@ -260,7 +260,9 @@ int32_t npnr_netinfo_udata(NetInfo *net) { return net->udata; }
void npnr_netinfo_udata_set(NetInfo *net, int32_t value) { net->udata = value; }
CellInfo *npnr_portref_cell(const PortRef *port) { return port->cell; }
Loc npnr_cellinfo_get_location(const CellInfo *info) { return info->getLocation(); }
uint64_t npnr_portref_port(const PortRef *port) { return wrap(port->port); }
Loc npnr_cellinfo_get_location(const CellInfo *cell) { return cell->getLocation(); }
uint64_t npnr_cellinfo_name(const CellInfo *cell) { return wrap(cell->name.index); }
void rust_example_printnets(Context *ctx);
}