spefparse 0.2.0

SPEF parasitics parser
Documentation
//! Formatting utils that let you dump SPEF object to SPEF source.

use super::*;
use std::fmt::{ Display, Formatter, Result };
use itertools::Itertools;
use indexmap::IndexSet;

/// Name mapping.
/// 
/// Note that this definition contains **references** to Arc's,
/// which is different from that in spefpest.rs.
///
/// The index is the IndexSet index + 1.
type NameMap<'i> = IndexSet<(&'i Arc<HierName>, Option<isize>)>;

impl Display for Direction {
    #[inline]
    fn fmt(&self, f: &mut Formatter) -> Result {
        use Direction::*;
        write!(f, "{}", match self {
            I => "I", O => "O", B => "B"
        })
    }
}

impl Display for ParValue {
    #[inline]
    fn fmt(&self, f: &mut Formatter) -> Result {
        use ParValue::*;
        match self {
            Single(a) => write!(f, "{}", a),
            Three(a, b, c) => write!(f, "{}:{}:{}", a, b, c)
        }
    }
}

impl Display for SPEFConnAttr {
    #[inline]
    fn fmt(&self, f: &mut Formatter) -> Result {
        if let Some((x, y)) = self.coords {
            write!(f, " *C {} {}", x, y)?;
        }
        if let Some(v) = self.cap_load {
            write!(f, " *L {}", v)?;
        }
        if let Some((v1, v2)) = self.slew {
            write!(f, " *S {} {}", v1, v2)?;
        }
        if let Some(s) = &self.driving_cell {
            write!(f, " *D {}", s)?;
        }
        Ok(())
    }
}

struct BitIDFmt<'a>(isize, &'a SPEFHeader);

impl Display for BitIDFmt<'_> {
    #[inline]
    fn fmt(&self, f: &mut Formatter) -> Result {
        write!(f, "{}{}{}",
               self.1.bus_delimiter_left, self.0,
               self.1.bus_delimiter_right)
    }
}

struct HierNameFmt<'a>(&'a HierName, &'a SPEFHeader);

impl Display for HierNameFmt<'_> {
    #[inline]
    fn fmt(&self, f: &mut Formatter) -> Result {
        write!(f, "{}", self.0.0.iter().format(
            self.1.divider.encode_utf8(&mut [0; 1])))
    }
}

impl HierName {
    #[inline]
    fn display<'a>(&'a self, header: &'a SPEFHeader) -> HierNameFmt {
        HierNameFmt(self, header)
    }
}

struct SPEFHierPortPinRefFmt<'a>(
    &'a SPEFHierPortPinRef, &'a NameMap<'a>, &'a SPEFHeader);

impl Display for SPEFHierPortPinRefFmt<'_> {
    #[inline]
    fn fmt(&self, f: &mut Formatter) -> Result {
        let SPEFHierPortPinRefFmt(r, nm, header) = self;
        let raw_name = r.as_raw_name();
        let mut need_bit_output = false;
        if let Some(id) = nm.get_index_of(&raw_name) {
            write!(f, "*{}", id + 1)?;
        }
        else {
            write!(f, "{}", raw_name.0.display(header))?;
            need_bit_output = true;
        }
        if let Some(pin) = &r.1 {
            write!(f, "{}{}", header.delimiter, pin)?;
            need_bit_output = true;
        }
        if need_bit_output{
            if let Some(bit_id) = raw_name.1 {
                write!(f, "{}", BitIDFmt(bit_id, header))?;
            }
        }
        Ok(())
    }
}

impl SPEFHierPortPinRef {
    #[inline]
    fn as_raw_name(&self) -> (&Arc<HierName>, Option<isize>) {
        match &self.1 {
            Some(_) => (&self.0, None),
            None => (&self.0, self.2)
        }
    }
    
    #[inline]
    fn display<'a>(&'a self, nm: &'a NameMap<'a>, header: &'a SPEFHeader) -> SPEFHierPortPinRefFmt<'a> {
        SPEFHierPortPinRefFmt(self, nm, header)
    }
}

impl SPEFPort {
    #[inline]
    fn write_to_fmt(&self, f: &mut Formatter, nm: &NameMap, header: &SPEFHeader) -> Result {
        writeln!(f, "{} {}{}",
                 self.name.display(nm, header),
                 self.direction, self.conn_attr)
    }
}

impl SPEFNet {
    #[inline]
    fn write_to_fmt(&self, f: &mut Formatter, nm: &NameMap, header: &SPEFHeader) -> Result {
        writeln!(f, "*D_NET {} {}",
                 self.name.display(nm, header),
                 self.total_cap)?;
        
        writeln!(f, "*CONN")?;
        for conn in &self.conns {
            writeln!(f, "*{} {} {}{}",
                     if conn.name.1.is_some() { 'I' } else { 'P' },
                     conn.name.display(nm, header),
                     conn.direction, conn.conn_attr)?
        }
        
        writeln!(f, "*CAP")?;
        for (id, cap) in self.caps.iter().enumerate() {
            write!(f, "{} {}", id + 1, cap.a.display(nm, header))?;
            if let Some(b) = &cap.b {
                write!(f, " {}", b.display(nm, header))?;
            }
            writeln!(f, " {}", cap.val)?;
        }
        
        writeln!(f, "*RES")?;
        for (id, res) in self.ress.iter().enumerate() {
            writeln!(f, "{} {} {} {}",
                     id + 1,
                     res.a.display(nm, header),
                     res.b.display(nm, header),
                     res.val)?;
        }
        
        writeln!(f, "*END")?;
        Ok(())
    }
}

impl SPEF {
    #[inline]
    fn build_name_map(&self) -> NameMap {
        let mut ret = NameMap::new();
        ret.extend(self.top_ports.iter()
                   .map(|p| p.name.as_raw_name()));
        ret.extend(self.nets.iter()
                   .map(|p| p.name.as_raw_name()));
        for net in &self.nets {
            ret.extend(net.conns.iter()
                       .map(|c| c.name.as_raw_name()));
            ret.extend(net.caps.iter()
                       .map(|c| c.a.as_raw_name()));
            ret.extend(net.caps.iter()
                       .filter_map(|c| c.b.as_ref()
                                   .map(|b| b.as_raw_name())));
            ret.extend(net.ress.iter()
                       .map(|r| r.a.as_raw_name()));
            ret.extend(net.ress.iter()
                       .map(|r| r.b.as_raw_name()));
        }
        ret
    }

    #[inline]
    fn write_name_map(&self, f: &mut Formatter, nm: &NameMap) -> Result {
        if nm.len() == 0 {
            return Ok(());
        }
        writeln!(f, "*NAME_MAP")?;
        for (id, (name, bit_id)) in nm.iter().enumerate() {
            write!(f, "*{} {}",
                   id + 1, name.display(&self.header))?;
            if let Some(bit_id) = bit_id {
                write!(f, "{}", BitIDFmt(*bit_id, &self.header))?;
            }
            writeln!(f)?;
        }
        Ok(())
    }

    #[inline]
    fn write_header(&self, f: &mut Formatter) -> Result {
        /// Compute the best fit unit and ratio.
        macro_rules! fmt_unit {
            ($v:expr, $($k:expr => $u:expr),+) => {{
                let v = $v;
                let mut best: Option<(&'static str, f32, f32)> = None;
                $({
                    let v_div_log = (v / $u).ln().abs();
                    match best {
                        None => {
                            best = Some(($k, v_div_log, v / $u));
                        }
                        Some((_, w, _)) if w > v_div_log => {
                            best = Some(($k, v_div_log, v / $u));
                        }
                        _ => {}
                    }
                })+;
                let (best_unit, _, best_ratio) = best.unwrap();
                // (best_ratio, best_unit)
                format!("{} {}", best_ratio, best_unit)
            }}
        }
        
        let h = &self.header;
        write!(
            f, "\
*SPEF {:?}
*DESIGN {:?}
*DATE {:?}
*VENDOR {:?}
*PROGRAM {:?}
*VERSION {:?}
*DESIGN_FLOW {:?}
*DIVIDER {}
*DELIMITER {}
*BUS_DELIMITER {} {}
*T_UNIT {}
*C_UNIT {}
*R_UNIT {}
*L_UNIT {}
",
            h.edition, h.design, h.date, h.vendor, h.program,
            h.version, h.design_flow.iter().format(" "),
            h.divider, h.delimiter,
            h.bus_delimiter_left, h.bus_delimiter_right,
            fmt_unit!(h.time_unit, "NS" => 1e-9, "PS" => 1e-12),
            fmt_unit!(h.cap_unit, "PF" => 1e-12, "FF" => 1e-15),
            fmt_unit!(h.res_unit, "OHM" => 1., "KOHM" => 1e3),
            fmt_unit!(h.induct_unit, "HENRY" => 1., "MH" => 1e-3, "UH" => 1e-6))
    }
}

impl Display for SPEF {
    /// Dump SPEF object to SPEF source by just formatting it
    /// using `"{}"` (Display).
    fn fmt(&self, f: &mut Formatter) -> Result {
        self.write_header(f)?;
        writeln!(f)?;
        
        let name_map = self.build_name_map();
        self.write_name_map(f, &name_map)?;
        writeln!(f)?;
        
        if self.top_ports.len() != 0 {
            writeln!(f, "*PORTS")?;
            for port in &self.top_ports {
                port.write_to_fmt(f, &name_map, &self.header)?;
            }
            writeln!(f)?;
        }
        
        for net in &self.nets {
            net.write_to_fmt(f, &name_map, &self.header)?;
            writeln!(f)?;
        }
        Ok(())
    }
}