#![allow(unsafe_op_in_unsafe_fn)]
use crate::*;
use std::ffi::{c_char, CStr, CString};
use std::ptr::NonNull;
mod ffi_status {
pub const SUCCESS: u32 = 0;
pub const MAX_STEPS_REACHED: u32 = 1;
pub const FALSE: u32 = 0;
pub const TRUE: u32 = 1;
pub const HIGH_Z: u32 = 0;
pub const UNDEFINED: u32 = 1;
pub const LOGIC_0: u32 = 2;
pub const LOGIC_1: u32 = 3;
}
#[allow(dead_code)]
#[rustfmt::skip]
#[repr(u32)]
enum FfiError {
NullPointer = 0x0000_0001,
PointerMisaligned = 0x0000_0002,
InvalidArgument = 0x0000_0003,
ArgumentOutOfRange = 0x0000_0004,
Utf8Encoding = 0x0000_0005,
Io = 0x0000_0006,
InvalidOperation = 0x0000_0007,
ResourceLimitReached = 0x0001_0001,
WireWidthMismatch = 0x0001_0002,
WireWidthIncompatible = 0x0001_0003,
OffsetOutOfRange = 0x0001_0004,
TooFewInputs = 0x0001_0005,
InvalidInputCount = 0x0001_0006,
InvalidComponentType = 0x0001_0007,
Conflict = 0x0002_0001,
InvalidWireId = 0x0002_0002,
InvalidComponentId = 0x0002_0003,
MalformedFormat = 0x0003_0001,
Unsupported = 0x0003_0002,
}
impl From<std::str::Utf8Error> for FfiError {
#[inline]
fn from(_: std::str::Utf8Error) -> Self {
Self::Utf8Encoding
}
}
impl From<std::io::Error> for FfiError {
#[inline]
fn from(_: std::io::Error) -> Self {
Self::Io
}
}
impl From<std::num::TryFromIntError> for FfiError {
#[inline]
fn from(_: std::num::TryFromIntError) -> Self {
Self::ArgumentOutOfRange
}
}
impl From<ToIntError> for FfiError {
#[inline]
fn from(value: ToIntError) -> Self {
match value {
ToIntError::InvalidWidth => Self::ArgumentOutOfRange,
ToIntError::Unrepresentable => Self::InvalidOperation,
}
}
}
impl From<ToBigIntError> for FfiError {
#[inline]
fn from(value: ToBigIntError) -> Self {
match value {
ToBigIntError::Unrepresentable => Self::InvalidOperation,
}
}
}
#[cfg(feature = "yosys-import")]
impl From<serde_json::Error> for FfiError {
fn from(value: serde_json::Error) -> Self {
use serde_json::error::Category;
match value.classify() {
Category::Io => Self::Io,
Category::Syntax | Category::Data | Category::Eof => Self::MalformedFormat,
}
}
}
#[cfg(feature = "yosys-import")]
impl From<crate::import::yosys::YosysModuleImportError> for FfiError {
fn from(value: crate::import::yosys::YosysModuleImportError) -> Self {
use crate::import::yosys::YosysModuleImportError;
match value {
YosysModuleImportError::ResourceLimitReached => Self::ResourceLimitReached,
YosysModuleImportError::InOutPort { .. }
| YosysModuleImportError::CellInOutPort { .. }
| YosysModuleImportError::UnsupportedWireWidth { .. }
| YosysModuleImportError::UnknownCellType { .. }
| YosysModuleImportError::UnsupportedCellType { .. } => Self::Unsupported,
YosysModuleImportError::MissingCellPortDirection { .. }
| YosysModuleImportError::InvalidCellPorts { .. }
| YosysModuleImportError::InvalidCellParameters { .. } => Self::MalformedFormat,
}
}
}
impl From<AddComponentError> for FfiError {
fn from(value: AddComponentError) -> Self {
match value {
AddComponentError::TooManyComponents => Self::ResourceLimitReached,
AddComponentError::InvalidWireId => Self::InvalidWireId,
AddComponentError::WireWidthMismatch => Self::WireWidthMismatch,
AddComponentError::WireWidthIncompatible => Self::WireWidthIncompatible,
AddComponentError::OffsetOutOfRange => Self::OffsetOutOfRange,
AddComponentError::TooFewInputs => Self::TooFewInputs,
AddComponentError::InvalidInputCount => Self::InvalidInputCount,
}
}
}
impl From<InvalidWireIdError> for FfiError {
#[inline]
fn from(_: InvalidWireIdError) -> Self {
Self::InvalidWireId
}
}
impl From<InvalidComponentIdError> for FfiError {
#[inline]
fn from(_: InvalidComponentIdError) -> Self {
Self::InvalidComponentId
}
}
#[repr(transparent)]
pub struct FfiResult(i32);
impl From<Result<u32, FfiError>> for FfiResult {
#[inline]
fn from(value: Result<u32, FfiError>) -> Self {
match value {
Ok(stat) => FfiResult(i32::try_from(stat).unwrap()),
Err(err) => FfiResult(-i32::try_from(err as u32).unwrap()),
}
}
}
#[inline]
fn check_ptr<T>(ptr: *mut T) -> Result<NonNull<T>, FfiError> {
let ptr = NonNull::new(ptr).ok_or(FfiError::NullPointer)?;
if (ptr.as_ptr() as usize) % std::mem::align_of::<T>() != 0 {
return Err(FfiError::PointerMisaligned);
}
Ok(ptr)
}
#[inline]
unsafe fn cast_ptr<'a, T>(ptr: *const T) -> Result<&'a T, FfiError> {
Ok(&*check_ptr(ptr.cast_mut())?.as_ptr())
}
#[inline]
unsafe fn cast_mut_ptr<'a, T>(ptr: *mut T) -> Result<&'a mut T, FfiError> {
Ok(&mut *check_ptr(ptr)?.as_ptr())
}
unsafe fn cast_slice<'a, T>(ptr: *const T, len: usize) -> Result<&'a [T], FfiError> {
let ptr = check_ptr(ptr.cast_mut())?.as_ptr().cast_const();
Ok(std::slice::from_raw_parts(ptr, len))
}
unsafe fn cast_slice_mut<'a, T>(ptr: *mut T, len: usize) -> Result<&'a mut [T], FfiError> {
let ptr = check_ptr(ptr)?.as_ptr();
Ok(std::slice::from_raw_parts_mut(ptr, len))
}
unsafe fn cast_c_str<'a>(ptr: *const c_char) -> Result<&'a str, FfiError> {
let ptr = NonNull::new(ptr.cast_mut()).ok_or(FfiError::NullPointer)?;
let c_str = CStr::from_ptr(ptr.as_ptr().cast_const());
let r_str = c_str.to_str()?;
Ok(r_str)
}
macro_rules! ffi_fn {
(
$(#[$attr:meta])*
$name:ident(
$($param_name:ident : $param_ty:ty),* $(,)?
) $body:block
) => {
$(#[$attr])*
#[no_mangle]
#[must_use]
pub unsafe extern "C" fn $name($($param_name : $param_ty),*) -> FfiResult {
#[inline]
unsafe fn fn_impl($($param_name : $param_ty),*) -> Result<u32, FfiError> $body
fn_impl($($param_name),*).into()
}
};
}
ffi_fn! {
string_free(s: *const c_char) {
let s = check_ptr(s.cast_mut())?;
let s = CString::from_raw(s.as_ptr());
std::mem::drop(s);
Ok(ffi_status::SUCCESS)
}
}
mod builder;
mod logic;
mod simulator;