218 lines
6.3 KiB
Rust
218 lines
6.3 KiB
Rust
![]() |
use std::ffi::CStr;
|
||
|
|
||
|
use libc::c_char;
|
||
|
|
||
|
#[derive(Clone, Copy)]
|
||
|
#[repr(C)]
|
||
|
pub enum PlaceStrength {
|
||
|
None = 0,
|
||
|
Weak = 1,
|
||
|
Strong = 2,
|
||
|
Placer = 3,
|
||
|
Fixed = 4,
|
||
|
Locked = 5,
|
||
|
User = 6,
|
||
|
}
|
||
|
|
||
|
#[repr(C)]
|
||
|
pub struct CellInfo {
|
||
|
private: [u8; 0],
|
||
|
}
|
||
|
|
||
|
#[repr(C)]
|
||
|
pub struct NetInfo {
|
||
|
private: [u8; 0],
|
||
|
}
|
||
|
|
||
|
#[repr(C)]
|
||
|
pub struct IdString {
|
||
|
index: libc::c_int,
|
||
|
}
|
||
|
|
||
|
/// A type representing a bel name.
|
||
|
#[derive(Clone, Copy)]
|
||
|
#[repr(transparent)]
|
||
|
pub struct BelId {
|
||
|
_private: u64,
|
||
|
}
|
||
|
|
||
|
impl BelId {
|
||
|
pub fn null() -> Self {
|
||
|
unsafe { npnr_belid_null() }
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#[derive(Clone, Copy)]
|
||
|
#[repr(transparent)]
|
||
|
pub struct PipId {
|
||
|
_private: u64,
|
||
|
}
|
||
|
|
||
|
impl PipId {
|
||
|
pub fn null() -> Self {
|
||
|
todo!()
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#[derive(Clone, Copy)]
|
||
|
#[repr(transparent)]
|
||
|
pub struct WireId {
|
||
|
_private: u64,
|
||
|
}
|
||
|
|
||
|
impl WireId {
|
||
|
pub fn null() -> Self {
|
||
|
todo!()
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#[repr(C)]
|
||
|
pub struct Context {
|
||
|
_private: [u8; 0],
|
||
|
}
|
||
|
|
||
|
impl Context {
|
||
|
/// Get grid X dimension. All bels and pips must have X coordinates in the range `0 .. getGridDimX()-1` (inclusive).
|
||
|
pub fn grid_dim_x(&self) -> i32 {
|
||
|
unsafe { npnr_context_get_grid_dim_x(self) as i32 }
|
||
|
}
|
||
|
|
||
|
/// Get grid Y dimension. All bels and pips must have Y coordinates in the range `0 .. getGridDimY()-1` (inclusive).
|
||
|
pub fn grid_dim_y(&self) -> i32 {
|
||
|
unsafe { npnr_context_get_grid_dim_y(self) as i32 }
|
||
|
}
|
||
|
|
||
|
/// Bind a given bel to a given cell with the given strength.
|
||
|
pub fn bind_bel(&mut self, bel: BelId, cell: &mut CellInfo, strength: PlaceStrength) {
|
||
|
unsafe { npnr_context_bind_bel(self, bel, cell, strength) }
|
||
|
}
|
||
|
|
||
|
/// Unbind a bel.
|
||
|
pub fn unbind_bel(&mut self, bel: BelId) {
|
||
|
unsafe { npnr_context_unbind_bel(self, bel) }
|
||
|
}
|
||
|
|
||
|
/// 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.
|
||
|
pub fn check_bel_avail(&self, bel: BelId) -> bool {
|
||
|
unsafe { npnr_context_check_bel_avail(self, bel) }
|
||
|
}
|
||
|
|
||
|
/// Return the cell the given bel is bound to, or nullptr if the bel is not bound.
|
||
|
pub fn bound_bel_cell(&self, bel: BelId) -> Option<&CellInfo> {
|
||
|
unsafe { npnr_context_get_bound_bel_cell(self, bel).as_ref() }
|
||
|
}
|
||
|
|
||
|
/// 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) {
|
||
|
unsafe { npnr_context_bind_wire(self, wire, net, strength) }
|
||
|
}
|
||
|
|
||
|
/// Unbind a wire. For wires that are driven by a pip, this will also unbind the driving pip.
|
||
|
pub fn unbind_wire(&mut self, wire: WireId) {
|
||
|
unsafe { npnr_context_unbind_wire(self, wire) }
|
||
|
}
|
||
|
|
||
|
/// Bid a pip to a net. This also bind the destination wire of that pip.
|
||
|
pub fn bind_pip(&mut self, pip: PipId, net: &mut NetInfo, strength: PlaceStrength) {
|
||
|
unsafe { npnr_context_bind_pip(self, pip, net, strength) }
|
||
|
}
|
||
|
|
||
|
/// Unbind a pip and the wire driven by that pip.
|
||
|
pub fn unbind_pip(&mut self, pip: PipId) {
|
||
|
unsafe { npnr_context_unbind_pip(self, pip) }
|
||
|
}
|
||
|
|
||
|
/// Get the source wire for a pip.
|
||
|
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.
|
||
|
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?
|
||
|
pub fn estimate_delay(&self, src: WireId, dst: WireId) -> f32 {
|
||
|
unsafe { npnr_context_estimate_delay(self, src, dst) as f32 }
|
||
|
}
|
||
|
|
||
|
pub fn check(&self) {
|
||
|
unsafe { npnr_context_check(self) }
|
||
|
}
|
||
|
|
||
|
pub fn debug(&self) -> bool {
|
||
|
unsafe { npnr_context_debug(self)}
|
||
|
}
|
||
|
|
||
|
pub fn id(&self, s: &str) -> IdString {
|
||
|
let s = std::ffi::CString::new(s).unwrap();
|
||
|
unsafe { npnr_context_id(self, s.as_ptr()) }
|
||
|
}
|
||
|
|
||
|
pub fn name_of(&self, s: IdString) -> &CStr {
|
||
|
unsafe { CStr::from_ptr(npnr_context_name_of(self, s)) }
|
||
|
}
|
||
|
|
||
|
pub fn verbose(&self) -> bool {
|
||
|
unsafe { npnr_context_verbose(self) }
|
||
|
}
|
||
|
}
|
||
|
|
||
|
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_context_get_grid_dim_x(ctx: *const Context) -> libc::c_int;
|
||
|
fn npnr_context_get_grid_dim_y(ctx: *const Context) -> libc::c_int;
|
||
|
fn npnr_context_bind_bel(
|
||
|
ctx: *mut Context,
|
||
|
bel: BelId,
|
||
|
cell: *mut CellInfo,
|
||
|
strength: PlaceStrength,
|
||
|
);
|
||
|
fn npnr_context_unbind_bel(ctx: *mut Context, bel: BelId);
|
||
|
fn npnr_context_check_bel_avail(ctx: *const Context, bel: BelId) -> bool;
|
||
|
fn npnr_context_get_bound_bel_cell(ctx: *const Context, bel: BelId) -> *const CellInfo;
|
||
|
fn npnr_context_bind_wire(
|
||
|
ctx: *mut Context,
|
||
|
wire: WireId,
|
||
|
net: *mut NetInfo,
|
||
|
strength: PlaceStrength,
|
||
|
);
|
||
|
fn npnr_context_unbind_wire(ctx: *mut Context, wire: WireId);
|
||
|
fn npnr_context_bind_pip(
|
||
|
ctx: *mut Context,
|
||
|
pip: PipId,
|
||
|
net: *mut NetInfo,
|
||
|
strength: PlaceStrength,
|
||
|
);
|
||
|
fn npnr_context_unbind_pip(ctx: *mut Context, pip: PipId);
|
||
|
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_check(ctx: *const Context);
|
||
|
fn npnr_context_debug(ctx: *const Context) -> bool;
|
||
|
fn npnr_context_id(ctx: *const Context, s: *const c_char) -> IdString;
|
||
|
fn npnr_context_name_of(ctx: *const Context, s: IdString) -> *const libc::c_char;
|
||
|
fn npnr_context_verbose(ctx: *const Context) -> bool;
|
||
|
|
||
|
// fn npnr_context_nets(ctx: *const Context) -> *mut *mut NetInfo;
|
||
|
}
|
||
|
|
||
|
macro_rules! log_info {
|
||
|
($($t:tt)*) => {
|
||
|
let s = std::ffi::CString::new(format!($($t)*)).unwrap();
|
||
|
unsafe { crate::npnr::npnr_log_info(s.as_ptr()); }
|
||
|
};
|
||
|
}
|
||
|
|
||
|
macro_rules! log_error {
|
||
|
($($t:tt)*) => {
|
||
|
let s = std::ffi::CString::new(format!($($t)*)).unwrap();
|
||
|
unsafe { crate::npnr::npnr_log_error(s.as_ptr()); }
|
||
|
};
|
||
|
}
|