use crate::{BsdlError, Entity};
#[derive(Debug, Clone, PartialEq)]
pub enum CellFunction {
Internal,
ObserveOnly,
Clock,
Input,
Output2,
Output3,
Control,
ControlR,
Bidir,
Unknown(String),
Missing,
}
impl CellFunction {
fn from_str(s: Option<&str>) -> CellFunction {
if let Some(s) = s {
let s = s.trim().to_lowercase();
let s = s.as_str();
match s {
"internal" => CellFunction::Internal,
"observeonly" => CellFunction::ObserveOnly,
"clock" => CellFunction::Clock,
"input" => CellFunction::Input,
"output2" => CellFunction::Output2,
"output3" => CellFunction::Output3,
"control" => CellFunction::Control,
"controlr" => CellFunction::ControlR,
"bidir" => CellFunction::Bidir,
_ => CellFunction::Unknown(s.to_string()),
}
} else {
CellFunction::Missing
}
}
pub fn is_input(&self) -> bool {
match self {
CellFunction::Bidir
| CellFunction::Clock
| CellFunction::Input
| CellFunction::ObserveOnly => true,
_ => false,
}
}
pub fn is_output(&self) -> bool {
match self {
CellFunction::Bidir | CellFunction::Output2 | CellFunction::Output3 => true,
_ => false,
}
}
}
impl std::fmt::Display for CellFunction {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{self:?}")
}
}
#[derive(Debug, Clone, PartialEq)]
#[allow(non_camel_case_types)]
pub enum CellType {
BC(u8),
AC(u8),
Other(String),
}
impl CellType {
fn from_str(s: Option<&str>) -> Result<CellType, BsdlError> {
if let Some(s) = s {
let s = s.trim();
if s.starts_with("BC_") {
let n = &s[3..];
let n = u8::from_str_radix(n, 10)?;
Ok(CellType::BC(n))
} else if s.starts_with("AC_") {
let n = &s[3..];
let n = u8::from_str_radix(n, 10)?;
Ok(CellType::AC(n))
} else {
Ok(CellType::Other(s.to_string()))
}
} else {
Err(BsdlError::ParseError(format!("")))
}
}
}
impl std::fmt::Display for CellType {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{self:?}")
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum LogicVal {
Zero = 0,
One = 1,
X = 2,
Z = 3,
None = 4,
}
impl LogicVal {
fn from_str(s: Option<&str>) -> Result<LogicVal, BsdlError> {
if let Some(s) = s {
let s = s.trim();
match s {
"0" => Ok(LogicVal::Zero),
"1" => Ok(LogicVal::One),
"x" | "X" => Ok(LogicVal::X),
"z" | "Z" => Ok(LogicVal::Z),
_ => Err(BsdlError::ParseError(format!(
"LogicVal can only be created from '0', '1', 'x', 'X', 'z', 'Z', not {s}"
))),
}
} else {
Ok(LogicVal::None)
}
}
}
impl std::fmt::Display for LogicVal {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
let rv = match self {
LogicVal::Zero => '0',
LogicVal::One => '1',
LogicVal::X => 'x',
LogicVal::Z => 'z',
LogicVal::None => '-',
};
write!(f, "{rv}")
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum DisableResult {
Pull0 = 0,
Pull1 = 1,
Weak0 = 2,
Weak1 = 3,
Keeper = 4,
Z = 5,
None,
}
impl std::fmt::Display for DisableResult {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{self:?}")
}
}
impl DisableResult {
fn from_str(s: Option<&str>) -> Result<DisableResult, BsdlError> {
if let Some(s) = s {
let s = s.trim();
let s = s.to_lowercase();
match s.as_str() {
"pull0" => Ok(DisableResult::Pull0),
"pull1" => Ok(DisableResult::Pull1),
"weak0" => Ok(DisableResult::Weak0),
"weak1" => Ok(DisableResult::Weak1),
"z" => Ok(DisableResult::Z),
_ => Err(BsdlError::ParseError(format!(
"DisableResult cannot be created from {s}"
))),
}
} else {
Ok(DisableResult::None)
}
}
}
#[derive(Debug, Clone)]
pub struct ScanCell {
pub ctype: CellType,
pub port: Option<usize>,
pub function: CellFunction,
pub safe: LogicVal,
pub ccell: Option<usize>,
pub disval: LogicVal,
pub disresult: DisableResult,
}
impl ScanCell {
pub(crate) fn default() -> ScanCell {
ScanCell {
ctype: CellType::BC(0),
port: None,
function: CellFunction::Internal,
safe: LogicVal::None,
ccell: None,
disval: LogicVal::None,
disresult: DisableResult::None,
}
}
pub(crate) fn from_string(
s: &str,
entity: &mut Entity,
cellnum: usize,
) -> Result<ScanCell, BsdlError> {
let mut s = s.trim().split(',');
let ctype = CellType::from_str(s.next())?;
let mut port = s.next().ok_or(BsdlError::AttributeError)?.trim();
if port == "*" {
port = "";
}
let function = s.next();
let safe = s.next();
let ccell = s.next();
let ccell = match ccell {
Some(x) => Some(usize::from_str_radix(x.trim(), 10)?),
None => None,
};
let disval = s.next();
let disresult = s.next();
let port_index = entity.port_number_from_portname(port);
let rv = ScanCell {
ctype,
port: port_index,
function: CellFunction::from_str(function),
safe: LogicVal::from_str(safe)?,
ccell,
disval: LogicVal::from_str(disval)?,
disresult: DisableResult::from_str(disresult)?,
};
if let Some(port_index) = port_index {
if rv.function.is_input() {
let port = &mut entity.ports.v[port_index];
port.cell_i = Some(cellnum);
}
if rv.function.is_output() {
let port = &mut entity.ports.v[port_index];
port.cell_o = Some(cellnum);
}
}
Ok(rv)
}
}
impl std::fmt::Display for ScanCell {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(
f,
"ctype: {}, port = {:?}, function = {}, safe = {}, ccell = {:?}, dv = {}, dr = {}",
self.ctype,
self.port,
self.function,
self.safe,
self.ccell,
self.disval,
self.disresult
)
}
}