use crate::{attribute::Parameter, logic::Logic};
#[derive(Debug, Clone, PartialEq, Eq, Hash, Copy, PartialOrd, Ord)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum DataType {
TwoState,
ThreeState,
FourState,
}
impl DataType {
pub fn boolean() -> Self {
DataType::TwoState
}
pub fn tristate() -> Self {
DataType::ThreeState
}
pub fn fourstate() -> Self {
DataType::FourState
}
pub fn logic() -> Self {
DataType::FourState
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
enum IdentifierType {
Normal,
BitSlice(usize),
Escaped,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Identifier {
name: String,
id_type: IdentifierType,
}
impl Identifier {
pub fn new(name: String) -> Self {
if name.is_empty() {
panic!("Identifier name cannot be empty");
}
if let Some(root) = name.strip_prefix('\\') {
return Identifier {
name: root.to_string(),
id_type: IdentifierType::Escaped,
};
}
let esc_chars = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
if esc_chars.contains(&name.chars().next().unwrap()) {
return Identifier {
name,
id_type: IdentifierType::Escaped,
};
}
let esc_chars = [
' ', '\\', '(', ')', ',', '+', '-', '$', '\'', '~', ';', '.', ',', '?', '!',
];
if name.chars().any(|c| esc_chars.contains(&c)) {
return Identifier {
name,
id_type: IdentifierType::Escaped,
};
}
if name.contains('[') && name.ends_with(']') {
let name_ind = name.find('[').unwrap();
let rname = &name[..name_ind];
let index_start = name_ind + 1;
let slice = name[index_start..name.len() - 1].parse::<usize>();
if let Ok(s) = slice {
return Identifier {
name: rname.to_string(),
id_type: IdentifierType::BitSlice(s),
};
}
}
Identifier {
name,
id_type: IdentifierType::Normal,
}
}
pub fn get_name(&self) -> &str {
&self.name
}
pub fn get_bit_index(&self) -> Option<usize> {
match self.id_type {
IdentifierType::BitSlice(index) => Some(index),
_ => None,
}
}
pub fn is_sliced(&self) -> bool {
matches!(self.id_type, IdentifierType::BitSlice(_))
}
pub fn is_escaped(&self) -> bool {
matches!(self.id_type, IdentifierType::Escaped)
}
pub fn emit_name(&self) -> String {
match &self.id_type {
IdentifierType::Normal => self.name.clone(),
IdentifierType::BitSlice(index) => format!("{}[{}]", self.name, index),
IdentifierType::Escaped => format!("\\{} ", self.name),
}
}
}
impl std::ops::Add for &Identifier {
type Output = Identifier;
fn add(self, rhs: Self) -> Identifier {
let lname = self.name.as_str();
let rname = rhs.name.as_str();
let new_type = match (self.id_type, rhs.id_type) {
(IdentifierType::Escaped, _)
| (_, IdentifierType::Escaped)
| (IdentifierType::BitSlice(_), _)
| (_, IdentifierType::BitSlice(_)) => IdentifierType::Escaped,
(IdentifierType::Normal, IdentifierType::Normal) => IdentifierType::Normal,
};
let new_name = match (self.id_type, rhs.id_type) {
(IdentifierType::BitSlice(l), IdentifierType::BitSlice(r)) => {
format!("{}_{}_{}_{}", lname, l, rname, r)
}
(IdentifierType::BitSlice(l), _) => format!("{}_{}_{}", lname, l, rname),
(_, IdentifierType::BitSlice(r)) => format!("{}_{}_{}", lname, rname, r),
_ => format!("{}_{}", lname, rname),
};
Identifier {
name: new_name,
id_type: new_type,
}
}
}
impl std::ops::Add for Identifier {
type Output = Identifier;
fn add(self, rhs: Self) -> Identifier {
&self + &rhs
}
}
impl From<&str> for Identifier {
fn from(name: &str) -> Self {
Identifier::new(name.to_string())
}
}
impl From<String> for Identifier {
fn from(name: String) -> Self {
Identifier::new(name)
}
}
impl std::fmt::Display for Identifier {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match &self.id_type {
IdentifierType::Normal => write!(f, "{}", self.name),
IdentifierType::BitSlice(index) => write!(f, "{}[{}]", self.name, index),
IdentifierType::Escaped => write!(f, "\\{} ", self.name),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Net {
identifier: Identifier,
data_type: DataType,
}
impl Net {
pub fn new(identifier: Identifier, data_type: DataType) -> Self {
Self {
identifier,
data_type,
}
}
pub fn new_logic(name: Identifier) -> Self {
Self::new(name, DataType::logic())
}
pub fn new_escaped_logic_bus(name: String, bw: usize) -> Vec<Self> {
let mut vec: Vec<Self> = Vec::with_capacity(bw);
for i in 0..bw {
vec.push(Self::new(
Identifier {
name: format!("{name}[{i}]"),
id_type: IdentifierType::Escaped,
},
DataType::logic(),
));
}
vec
}
pub fn set_identifier(&mut self, identifier: Identifier) {
self.identifier = identifier;
}
pub fn get_identifier(&self) -> &Identifier {
&self.identifier
}
pub fn take_identifier(self) -> Identifier {
self.identifier
}
pub fn get_type(&self) -> &DataType {
&self.data_type
}
pub fn with_name(&self, name: Identifier) -> Self {
Self::new(name, self.data_type)
}
}
#[macro_export]
macro_rules! format_id {
($($arg:tt)*) => {
$crate::Identifier::new(format!($($arg)*))
}
}
impl std::fmt::Display for Net {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.identifier.fmt(f)
}
}
impl From<&str> for Net {
fn from(name: &str) -> Self {
Net::new_logic(name.into())
}
}
pub trait Instantiable: Clone {
fn get_name(&self) -> &Identifier;
fn get_input_ports(&self) -> impl IntoIterator<Item = &Net>;
fn get_output_ports(&self) -> impl IntoIterator<Item = &Net>;
fn has_parameter(&self, id: &Identifier) -> bool;
fn get_parameter(&self, id: &Identifier) -> Option<Parameter>;
fn set_parameter(&mut self, id: &Identifier, val: Parameter) -> Option<Parameter>;
fn parameters(&self) -> impl Iterator<Item = (Identifier, Parameter)>;
fn from_constant(val: Logic) -> Option<Self>;
fn get_constant(&self) -> Option<Logic>;
fn is_seq(&self) -> bool;
fn is_parameterized(&self) -> bool {
self.parameters().next().is_some()
}
fn get_single_output_port(&self) -> &Net {
let mut iter = self.get_output_ports().into_iter();
let ret = iter.next().expect("Primitive has no output ports");
if iter.next().is_some() {
panic!("Primitive has more than one output port");
}
ret
}
fn get_output_port(&self, index: usize) -> &Net {
self.get_output_ports()
.into_iter()
.nth(index)
.expect("Index out of bounds for output ports")
}
fn get_input_port(&self, index: usize) -> &Net {
self.get_input_ports()
.into_iter()
.nth(index)
.expect("Index out of bounds for output ports")
}
fn find_input(&self, id: &Identifier) -> Option<usize> {
self.get_input_ports()
.into_iter()
.position(|n| n.get_identifier() == id)
}
fn find_output(&self, id: &Identifier) -> Option<usize> {
self.get_output_ports()
.into_iter()
.position(|n| n.get_identifier() == id)
}
fn is_driverless(&self) -> bool {
self.get_input_ports().into_iter().next().is_none()
}
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum Object<I>
where
I: Instantiable,
{
Input(Net),
Instance(Vec<Net>, Identifier, I),
}
impl<I> Object<I>
where
I: Instantiable,
{
pub fn get_single_net(&self) -> &Net {
match self {
Object::Input(net) => net,
Object::Instance(nets, _, _) => {
if nets.len() > 1 {
panic!("Instance has more than one output net");
} else {
nets.first().expect("Instance has no output net")
}
}
}
}
pub fn get_net(&self, index: usize) -> &Net {
match self {
Object::Input(net) => {
if index > 0 {
panic!("Index out of bounds for input net.")
}
net
}
Object::Instance(nets, _, _) => &nets[index],
}
}
pub fn get_instance_type(&self) -> Option<&I> {
match self {
Object::Input(_) => None,
Object::Instance(_, _, instance) => Some(instance),
}
}
pub fn get_instance_type_mut(&mut self) -> Option<&mut I> {
match self {
Object::Input(_) => None,
Object::Instance(_, _, instance) => Some(instance),
}
}
pub fn get_nets(&self) -> &[Net] {
match self {
Object::Input(net) => std::slice::from_ref(net),
Object::Instance(nets, _, _) => nets,
}
}
pub fn get_nets_mut(&mut self) -> &mut [Net] {
match self {
Object::Input(net) => std::slice::from_mut(net),
Object::Instance(nets, _, _) => nets,
}
}
}
impl<I> std::fmt::Display for Object<I>
where
I: Instantiable,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Object::Input(net) => write!(f, "Input({net})"),
Object::Instance(_nets, name, instance) => {
write!(f, "{}({})", instance.get_name(), name)
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn identifier_parsing() {
let id = Identifier::new("wire".to_string());
assert!(!id.is_escaped());
assert!(!id.is_sliced());
assert!(id.get_bit_index().is_none());
let id = Identifier::new("\\wire".to_string());
assert!(id.is_escaped());
assert!(!id.is_sliced());
let id = Identifier::new("wire[3]".to_string());
assert!(!id.is_escaped());
assert!(id.is_sliced());
assert_eq!(id.get_bit_index(), Some(3));
}
#[test]
fn assume_escaped_identifier() {
let id = Identifier::new("C++".to_string());
assert!(id.is_escaped());
}
#[test]
fn identifier_emission() {
let id = Identifier::new("wire".to_string());
assert_eq!(id.emit_name(), "wire");
let id = Identifier::new("\\wire".to_string());
assert!(id.is_escaped());
assert_eq!(id.emit_name(), "\\wire ");
assert_eq!(format!("{id}"), "\\wire ");
let id = Identifier::new("wire[3]".to_string());
assert!(id.is_sliced());
assert_eq!(id.emit_name(), "wire[3]");
}
#[test]
fn test_implicits() {
let net: Net = "hey".into();
assert_ne!(*net.get_type(), DataType::boolean());
assert_ne!(*net.get_type(), DataType::tristate());
assert_eq!(*net.get_type(), DataType::logic());
assert_eq!(*net.get_type(), DataType::fourstate());
}
}