#![allow(clippy::result_unit_err)]
use lazy_mut::lazy_mut;
use intmap::IntMap;
use crate::{RstbResult, seamap::SeaMap};
use crate::sim_if::{ObjectKind, SIM_IF};
use crate::SimpleResult;
use crate::trigger::Trigger;
use crate::value::Val;
lazy_mut! {
static mut SIG_MAP_NAME: SeaMap<String, usize> = SeaMap::new();
}
lazy_mut! {
static mut SIG_MAP: IntMap<SimObject> = IntMap::new();
}
#[derive(Clone, Copy, Debug)]
pub struct SimObject {
handle: usize,
kind: ObjectKind,
size: i32,
_signed: bool,
}
impl SimObject {
pub fn handle(&self) -> usize {
self.handle
}
pub fn kind(&self) -> ObjectKind {
self.kind
}
pub fn name(&self) -> String {
SIM_IF
.get_full_name(self.handle)
.expect("Couldn't get name of ObjectInner")
}
pub fn size(&self) -> i32 {
self.size
}
pub fn is_signed(&self) -> bool {
SIM_IF.is_signed(self.handle)
}
pub fn is_modifiable(&self) -> bool {
!matches!(self.kind, ObjectKind::Other)
}
pub fn has_value(&self) -> bool {
!matches!(self.kind, ObjectKind::Other)
}
#[allow(clippy::needless_question_mark)] pub fn get_child(&self, name: &str) -> SimpleResult<Self> {
let mut child_name = self.name();
child_name.push('.');
child_name.push_str(name);
Ok(SimObject::from_name(child_name.as_str())?)
}
#[allow(clippy::clone_on_copy)]
pub fn from_handle(handle: usize) -> SimpleResult<Self> {
if let Some(signal) = unsafe { SIG_MAP.get(handle as u64) } {
Ok(signal.clone())
} else {
Err(())
}
}
pub fn from_name(full_name: &str) -> SimpleResult<Self> {
let handle = unsafe { SIG_MAP_NAME.get(full_name) }
.map(|h| h.to_owned());
match handle {
Some(h) => SimObject::from_handle(h),
_ => Ok(SimObject::new_from_name(full_name)?),
}
}
fn new_from_name(full_name: &str) -> SimpleResult<Self> {
let handle = SIM_IF.get_handle_by_name(full_name)?;
Ok(SimObject::new_from_handle(handle))
}
fn new_from_handle(handle: usize) -> Self {
let signal = SimObject {
handle,
kind: SIM_IF.get_kind(handle),
size: SIM_IF.get_size(handle),
_signed: SIM_IF.is_signed(handle),
};
unsafe {
SIG_MAP.insert(handle as u64, signal);
SIG_MAP_NAME.insert(signal.name(), handle);
};
signal
}
pub fn get_root() -> SimpleResult<Self> {
Ok(SimObject::new_from_handle(SIM_IF.get_root_handle()?))
}
pub fn i32(&self) -> i32 {
if matches!(self.kind, ObjectKind::Bits) && self.size <= 32 {
let val = SIM_IF.get_value_int(self.handle()).unwrap() as i64;
let ceil = 1i64 << (self.size - 1);
if val >= ceil {
(-2 * ceil + val) as i32
} else {
val as i32
}
} else {
panic!("Couldn't get value of {} as i32 type.", self.name());
}
}
pub fn u32(&self) -> u32 {
if matches!(self.kind, ObjectKind::Bits) && self.size <= 32 {
let val = SIM_IF.get_value_int(self.handle()).unwrap() as i64;
let ceil = 1i64 << self.size;
if val < 0 {
(val + ceil) as u32
} else {
val as u32
}
} else {
panic!("Couldn't get value of {} as u32 type.", self.name());
}
}
pub fn bin(&self) -> String {
SIM_IF.get_value_bin(self.handle).unwrap()
}
pub fn c(&self, name: &str) -> Self {
self.get_child(name)
.unwrap_or_else(|_| panic!("Could not get object with name {}.{}", self.name(), name))
}
pub fn release(&self) {
SIM_IF.release(self.handle).unwrap();
}
pub fn set(&self, val: i32) {
self._set(val, false);
}
pub fn force(&self, val: i32) {
self._set(val, true);
}
#[inline]
fn _set(&self, val: i32, force: bool) {
if !matches!(self.kind, ObjectKind::Bits) {
panic!(
"Can't set signal {} of kind {:?} using set() or set_u32()",
self.name(),
self.kind
);
}
SIM_IF.set_value_int(self.handle, val, force).unwrap();
}
pub fn set_u32(&self, val: u32) {
self._set_u32(val, false)
}
pub fn force_u32(&self, val: u32) {
self._set_u32(val, true)
}
#[inline]
fn _set_u32(&self, val: u32, force: bool) {
if val >= 1 << 31 {
let val_i32: i32 = unsafe { std::mem::transmute(val) };
self._set(val_i32, force);
} else {
self._set(val as i32, force);
}
}
pub fn set_bin(&self, val: &str) {
self._set_bin(val, false)
}
pub fn force_bin(&self, val: &str) {
self._set_bin(val, true)
}
#[inline]
fn _set_bin(&self, val: &str, force: bool) {
let stripped = val.replace("0b", "");
let stripped = stripped.replace("_", "");
if stripped.len() == self.size as usize {
let is_valid = stripped.chars().all(valid_char);
if is_valid {
SIM_IF.set_value_bin(self.handle, stripped, force).unwrap();
} else {
panic!("Can't set {} to {}. Invalid characters.", self.name(), val);
}
} else {
panic!("Can't set {} to {}. Length mismatch.", self.name(), val);
}
}
pub fn rising_edge(self) -> Trigger {
Trigger::rising_edge(self)
}
pub async fn rising_edge_ro(self) -> RstbResult {
self.rising_edge().await;
Trigger::read_only().await;
Ok(Val::None)
}
pub async fn rising_edge_rw(self) -> RstbResult {
self.rising_edge().await;
Trigger::read_write().await;
Ok(Val::None)
}
pub fn falling_edge(self) -> Trigger {
Trigger::falling_edge(self)
}
pub fn edge(self) -> Trigger {
Trigger::edge(self)
}
}
fn valid_char(c: char) -> bool {
let l = c.to_ascii_lowercase();
l == '0' || l == '1' || l == 'z' || l == 'x'
}