mirror of
https://github.com/YosysHQ/nextpnr.git
synced 2026-01-11 23:53:21 +00:00
rust: small updates (#1560)
This commit is contained in:
parent
22041ed5df
commit
2e4ef6f71f
@ -1,5 +1,5 @@
|
||||
[workspace]
|
||||
|
||||
resolver = "2"
|
||||
members = [
|
||||
"nextpnr",
|
||||
"example_printnets",
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "nextpnr"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
edition = "2024"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
|
||||
@ -21,6 +21,7 @@ pub struct CellInfo {
|
||||
}
|
||||
|
||||
impl CellInfo {
|
||||
#[must_use]
|
||||
pub fn location(&self) -> Loc {
|
||||
unsafe { npnr_cellinfo_get_location(self) }
|
||||
}
|
||||
@ -36,10 +37,12 @@ impl NetInfo {
|
||||
unsafe { npnr_netinfo_driver(self) }
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn is_global(&self) -> bool {
|
||||
unsafe { npnr_netinfo_is_global(self) }
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn index(&self) -> NetIndex {
|
||||
unsafe { npnr_netinfo_udata(self) }
|
||||
}
|
||||
@ -50,6 +53,7 @@ impl NetInfo {
|
||||
pub struct NetIndex(i32);
|
||||
|
||||
impl NetIndex {
|
||||
#[must_use]
|
||||
pub fn into_inner(self) -> i32 {
|
||||
self.0
|
||||
}
|
||||
@ -61,6 +65,7 @@ pub struct PortRef {
|
||||
}
|
||||
|
||||
impl PortRef {
|
||||
#[must_use]
|
||||
pub fn cell(&self) -> Option<&CellInfo> {
|
||||
// SAFETY: handing out &s is safe when we have &self.
|
||||
unsafe { npnr_portref_cell(self) }
|
||||
@ -76,14 +81,21 @@ pub struct IdString(libc::c_int);
|
||||
#[repr(transparent)]
|
||||
pub struct BelId(u64);
|
||||
|
||||
impl Default for BelId {
|
||||
fn default() -> Self {
|
||||
Self::null()
|
||||
}
|
||||
}
|
||||
|
||||
impl BelId {
|
||||
/// Return a sentinel value that represents an invalid bel.
|
||||
#[must_use]
|
||||
pub fn null() -> Self {
|
||||
// SAFETY: BelId() has no safety requirements.
|
||||
unsafe { npnr_belid_null() }
|
||||
npnr_belid_null()
|
||||
}
|
||||
|
||||
/// Check if this bel is invalid.
|
||||
#[must_use]
|
||||
pub fn is_null(self) -> bool {
|
||||
self == Self::null()
|
||||
}
|
||||
@ -93,9 +105,16 @@ impl BelId {
|
||||
#[repr(transparent)]
|
||||
pub struct PipId(u64);
|
||||
|
||||
impl Default for PipId {
|
||||
fn default() -> Self {
|
||||
Self::null()
|
||||
}
|
||||
}
|
||||
|
||||
impl PipId {
|
||||
#[must_use]
|
||||
pub fn null() -> Self {
|
||||
unsafe { npnr_pipid_null() }
|
||||
npnr_pipid_null()
|
||||
}
|
||||
}
|
||||
|
||||
@ -103,14 +122,22 @@ impl PipId {
|
||||
#[repr(transparent)]
|
||||
pub struct WireId(u64);
|
||||
|
||||
impl Default for WireId {
|
||||
fn default() -> Self {
|
||||
Self::null()
|
||||
}
|
||||
}
|
||||
|
||||
impl WireId {
|
||||
/// Return a sentinel value that represents an invalid wire.
|
||||
#[must_use]
|
||||
pub fn null() -> Self {
|
||||
// SAFETY: WireId() has no safety requirements.
|
||||
unsafe { npnr_wireid_null() }
|
||||
npnr_wireid_null()
|
||||
}
|
||||
|
||||
/// Check if this wire is invalid.
|
||||
#[must_use]
|
||||
pub fn is_null(self) -> bool {
|
||||
self == Self::null()
|
||||
}
|
||||
@ -144,11 +171,13 @@ pub struct Context {
|
||||
|
||||
impl Context {
|
||||
/// Get grid X dimension. All bels and pips must have X coordinates in the range `0 .. getGridDimX()-1` (inclusive).
|
||||
#[must_use]
|
||||
pub fn grid_dim_x(&self) -> i32 {
|
||||
unsafe { npnr_context_get_grid_dim_x(self) }
|
||||
}
|
||||
|
||||
/// Get grid Y dimension. All bels and pips must have Y coordinates in the range `0 .. getGridDimY()-1` (inclusive).
|
||||
#[must_use]
|
||||
pub fn grid_dim_y(&self) -> i32 {
|
||||
unsafe { npnr_context_get_grid_dim_y(self) }
|
||||
}
|
||||
@ -166,11 +195,12 @@ impl Context {
|
||||
}
|
||||
|
||||
/// Returns true if the bel is available. A bel can be unavailable because it is bound, or because it is exclusive to some other resource that is bound.
|
||||
#[must_use]
|
||||
pub fn check_bel_avail(&self, bel: BelId) -> bool {
|
||||
unsafe { npnr_context_check_bel_avail(self, bel) }
|
||||
}
|
||||
|
||||
/// Bind a wire to a net. This method must be used when binding a wire that is driven by a bel pin. Use bindPip() when binding a wire that is driven by a pip.
|
||||
/// Bind a wire to a net. This method must be used when binding a wire that is driven by a bel pin. Use `bindPip` when binding a wire that is driven by a pip.
|
||||
pub fn bind_wire(&mut self, wire: WireId, net: &mut NetInfo, strength: PlaceStrength) {
|
||||
let _lock = ARCH_MUTEX.lock().unwrap();
|
||||
unsafe { npnr_context_bind_wire(self, wire, net, strength) }
|
||||
@ -195,36 +225,44 @@ impl Context {
|
||||
}
|
||||
|
||||
/// Get the source wire for a pip.
|
||||
#[must_use]
|
||||
pub fn pip_src_wire(&self, pip: PipId) -> WireId {
|
||||
unsafe { npnr_context_get_pip_src_wire(self, pip) }
|
||||
}
|
||||
|
||||
/// Get the destination wire for a pip.
|
||||
#[must_use]
|
||||
pub fn pip_dst_wire(&self, pip: PipId) -> WireId {
|
||||
unsafe { npnr_context_get_pip_dst_wire(self, pip) }
|
||||
}
|
||||
|
||||
// TODO: Should this be a Duration? Does that even make sense?
|
||||
#[must_use]
|
||||
pub fn estimate_delay(&self, src: WireId, dst: WireId) -> f32 {
|
||||
unsafe { npnr_context_estimate_delay(self, src, dst) }
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn pip_delay(&self, pip: PipId) -> f32 {
|
||||
unsafe { npnr_context_get_pip_delay(self, pip) }
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn wire_delay(&self, wire: WireId) -> f32 {
|
||||
unsafe { npnr_context_get_wire_delay(self, wire) }
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn delay_epsilon(&self) -> f32 {
|
||||
unsafe { npnr_context_delay_epsilon(self) }
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn source_wire(&self, net: &NetInfo) -> WireId {
|
||||
unsafe { npnr_context_get_netinfo_source_wire(self, net) }
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn sink_wires(&self, net: &NetInfo, sink: &PortRef) -> Vec<WireId> {
|
||||
let mut v = Vec::new();
|
||||
let mut n = 0;
|
||||
@ -239,41 +277,48 @@ impl Context {
|
||||
v
|
||||
}
|
||||
|
||||
pub fn bels(&self) -> BelIter {
|
||||
#[must_use]
|
||||
pub fn bels(&self) -> BelIter<'_> {
|
||||
let iter = unsafe { npnr_context_get_bels(self) };
|
||||
BelIter { iter, phantom_data: PhantomData }
|
||||
}
|
||||
|
||||
pub fn pips(&self) -> PipIter {
|
||||
#[must_use]
|
||||
pub fn pips(&self) -> PipIter<'_> {
|
||||
let iter = unsafe { npnr_context_get_pips(self) };
|
||||
PipIter { iter, phantom_data: PhantomData }
|
||||
}
|
||||
|
||||
pub fn wires(&self) -> WireIter {
|
||||
#[must_use]
|
||||
pub fn wires(&self) -> WireIter<'_> {
|
||||
let iter = unsafe { npnr_context_get_wires(self) };
|
||||
WireIter { iter, phantom_data: PhantomData }
|
||||
}
|
||||
|
||||
pub fn get_downhill_pips(&self, wire: WireId) -> DownhillPipsIter {
|
||||
#[must_use]
|
||||
pub fn get_downhill_pips(&self, wire: WireId) -> DownhillPipsIter<'_> {
|
||||
let iter = unsafe { npnr_context_get_pips_downhill(self, wire) };
|
||||
DownhillPipsIter {
|
||||
iter,
|
||||
phantom_data: Default::default(),
|
||||
phantom_data: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_uphill_pips(&self, wire: WireId) -> UphillPipsIter {
|
||||
#[must_use]
|
||||
pub fn get_uphill_pips(&self, wire: WireId) -> UphillPipsIter<'_> {
|
||||
let iter = unsafe { npnr_context_get_pips_uphill(self, wire) };
|
||||
UphillPipsIter {
|
||||
iter,
|
||||
phantom_data: Default::default(),
|
||||
phantom_data: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn pip_location(&self, pip: PipId) -> Loc {
|
||||
unsafe { npnr_context_get_pip_location(self, pip) }
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn pip_direction(&self, pip: PipId) -> Loc {
|
||||
let mut src = Loc{x: 0, y: 0, z: 0};
|
||||
let mut dst = Loc{x: 0, y: 0, z: 0};
|
||||
@ -305,6 +350,7 @@ impl Context {
|
||||
Loc{x: dst.x - src.x, y: dst.y - src.y, z: 0}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn pip_avail_for_net(&self, pip: PipId, net: &mut NetInfo) -> bool {
|
||||
unsafe { npnr_context_check_pip_avail_for_net(self, pip, net) }
|
||||
}
|
||||
@ -313,42 +359,48 @@ impl Context {
|
||||
unsafe { npnr_context_check(self) }
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn debug(&self) -> bool {
|
||||
unsafe { npnr_context_debug(self) }
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn id(&self, s: &str) -> IdString {
|
||||
let s = std::ffi::CString::new(s).unwrap();
|
||||
unsafe { npnr_context_id(self, s.as_ptr()) }
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn name_of(&self, s: IdString) -> &CStr {
|
||||
let _lock = RINGBUFFER_MUTEX.lock().unwrap();
|
||||
unsafe { CStr::from_ptr(npnr_context_name_of(self, s)) }
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn name_of_pip(&self, pip: PipId) -> &CStr {
|
||||
let _lock = RINGBUFFER_MUTEX.lock().unwrap();
|
||||
unsafe { CStr::from_ptr(npnr_context_name_of_pip(self, pip)) }
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn name_of_wire(&self, wire: WireId) -> &CStr {
|
||||
let _lock = RINGBUFFER_MUTEX.lock().unwrap();
|
||||
unsafe { CStr::from_ptr(npnr_context_name_of_wire(self, wire)) }
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn verbose(&self) -> bool {
|
||||
unsafe { npnr_context_verbose(self) }
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
unsafe extern "C" {
|
||||
pub fn npnr_log_info(format: *const c_char);
|
||||
pub fn npnr_log_error(format: *const c_char);
|
||||
|
||||
fn npnr_belid_null() -> BelId;
|
||||
fn npnr_wireid_null() -> WireId;
|
||||
fn npnr_pipid_null() -> PipId;
|
||||
safe fn npnr_belid_null() -> BelId;
|
||||
safe fn npnr_wireid_null() -> WireId;
|
||||
safe fn npnr_pipid_null() -> PipId;
|
||||
|
||||
fn npnr_context_get_grid_dim_x(ctx: &Context) -> libc::c_int;
|
||||
fn npnr_context_get_grid_dim_y(ctx: &Context) -> libc::c_int;
|
||||
@ -461,14 +513,15 @@ 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.
|
||||
pub fn new(ctx: &'a Context) -> Nets<'a> {
|
||||
#[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,
|
||||
&mut names as *mut *mut libc::c_int,
|
||||
&mut nets_ptr as *mut *mut *mut NetInfo,
|
||||
&raw mut names,
|
||||
&raw mut nets_ptr,
|
||||
)
|
||||
};
|
||||
let mut nets = HashMap::new();
|
||||
@ -481,9 +534,9 @@ impl<'a> Nets<'a> {
|
||||
// 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, &mut users_ptr as *mut *mut *const PortRef) };
|
||||
unsafe { npnr_netinfo_users_leak(net, &raw mut users_ptr) };
|
||||
let users_slice =
|
||||
unsafe { slice::from_raw_parts(users_ptr as *mut &PortRef, len as usize) };
|
||||
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 {
|
||||
@ -502,27 +555,33 @@ impl<'a> Nets<'a> {
|
||||
}
|
||||
|
||||
/// Find net users given a net's name.
|
||||
#[must_use]
|
||||
pub fn users_by_name(&self, net: IdString) -> Option<&&[&PortRef]> {
|
||||
self.users.get(&net)
|
||||
}
|
||||
|
||||
/// Return the number of nets in the store.
|
||||
#[must_use]
|
||||
pub fn len(&self) -> usize {
|
||||
self.nets.len()
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.nets.len() == 0
|
||||
}
|
||||
|
||||
#[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());
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user