use std::io::Write;
use std::fmt;
use crate::def_ast::{DEF, NetTerminal, Blockage, SpacingOrDesignRuleWidth, BlockageShape, PlacementBlockageType, ComponentSource, DEFSignalUse};
use std::fmt::{Display, Debug};
use libreda_db::prelude::SimpleRPolygon;
use num_traits::PrimInt;
use crate::common::PinDirection;
#[derive(Debug)]
pub enum DEFWriterError {
IOError(std::io::Error),
}
impl From<std::io::Error> for DEFWriterError {
fn from(err: std::io::Error) -> Self {
match err.kind() {
_ => DEFWriterError::IOError(err)
}
}
}
impl fmt::Display for DEFWriterError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use DEFWriterError::*;
match self {
IOError(e) => write!(f, "{}", e)
}
}
}
fn write_polygon<W: Write, T: PrimInt + Display>(w: &mut W, p: &SimpleRPolygon<T>) -> Result<(), DEFWriterError> {
for point in p.points() {
write!(w, "( {} {} ) ", point.x, point.y)?;
}
Ok(())
}
pub fn write_def<W: Write>(w: &mut W, def: &DEF) -> Result<(), DEFWriterError> {
let indent = |w: &mut W, level: u32| -> Result<(), std::io::Error>{
for _ in 0..level {
write!(w, " ")?;
}
Ok(())
};
for v in &def.version {
writeln!(w, "VERSION {} ;", v)?;
}
writeln!(w, "NAMESCASESENSITIVE ON ;")?;
writeln!(w, r#"DIVIDERCHAR "{}" ;"#, def.dividerchar)?;
writeln!(w, r#"BUSBITCHARS "{}{}" ;"#, def.busbitchars.0, def.busbitchars.1)?;
for n in &def.design_name {
writeln!(w, "DESIGN {} ;", n)?;
}
for n in &def.technology {
writeln!(w, "TECHNOLOGY {} ;", n)?;
}
writeln!(w, "UNITS DISTANCE MICRONS {} ;", def.units)?;
for h in &def.history {
writeln!(w, "HISTORY {} ;", h)?;
}
if !def.property_definitions.is_empty() {
writeln!(w, "PROPERTYDEFINITIONS")?;
for (name, p) in &def.property_definitions {
indent(w, 1)?;
write!(w, "{} {} {} ", p.object_type, name, p.property_type)?;
if let Some((min, max)) = &p.range {
write!(w, "RANGE {} {} ", min, max)?;
}
if let Some(default) = &p.default_value {
write!(w, "{} ", default)?;
}
writeln!(w, ";")?;
}
writeln!(w, "END PROPERTYDEFINITIONS")?;
}
if let Some(area) = &def.die_area {
write!(w, "DIEAREA ")?;
write_polygon(w, area)?;
writeln!(w, ";")?;
}
for (row_name, row) in &def.rows {
write!(w, "ROW {} {} {} {} {}", row_name, row.site_name, row.orig.0, row.orig.1, row.site_orient)?;
write!(w, " DO {} BY {}", row.step_pattern.num_x, row.step_pattern.num_y)?;
if let Some((dx, dy)) = row.step_pattern.step {
write!(w, " STEP {} {}", dx, dy)?;
}
if !row.properties.is_empty() {
writeln!(w)?;
for (name, value) in &row.properties {
indent(w, 1)?;
writeln!(w, "+ PROPERTY {} {}", name, value)?;
}
}
writeln!(w, " ;")?;
}
for tracks in &def.tracks {
let xy = if tracks.is_horizontal { "Y" } else { "X" };
write!(w, "TRACKS {} {} DO {} STEP {}", xy, tracks.start, tracks.num_tracks, tracks.step)?;
if let Some((mask_num, same_mask)) = &tracks.mask {
write!(w, " MASK {}", mask_num)?;
if *same_mask {
write!(w, " SAMEMASK")?;
}
}
if !tracks.layers.is_empty() {
write!(w, " LAYER ")?;
for layer in &tracks.layers {
write!(w, " {}", layer)?;
}
}
writeln!(w, " ;")?;
}
if !def.regions.is_empty() {
writeln!(w, "REGIONS {} ;", def.regions.len())?;
for (name, region) in &def.regions {
indent(w, 1)?;
write!(w, "- {} ", name)?;
for r in ®ion.regions {
write!(w, "( {} {} ) ", r.lower_left(), r.upper_right())?;
}
writeln!(w)?;
for region_type in ®ion.region_type {
indent(w, 2)?;
writeln!(w, "+ TYPE {} ", region_type)?;
}
}
writeln!(w, "END REGIONS")?;
}
if !def.components.is_empty() {
writeln!(w, "COMPONENTS {} ;", def.components.len())?;
for comp in &def.components {
indent(w, 1)?;
write!(w, "- {} {} ", comp.name, comp.model_name)?;
for m in &comp.eeq_master { write!(w, "+ EEQMASTER {} ", m)?; }
if comp.source != ComponentSource::default() {
write!(w, "+ SOURCE {} ", comp.source)?;
}
match &comp.position {
None => write!(w, "+ UNPLACED ")?,
Some((p, orient, false)) => write!(w, "+ PLACED {} {} ", p, orient)?,
Some((p, orient, true)) => write!(w, "+ FIXED {} {} ", p, orient)?,
}
for (soft, left, bottom, right, top) in &comp.halo {
write!(w, "+ HALO ")?;
if *soft { write!(w, "SOFT ")?; }
write!(w, "{} {} {} {} ", left, bottom, right, top)?;
}
for (dist, min_layer, max_layer) in &comp.route_halo {
write!(w, "+ ROUTEHALO {} {} {} ", dist, min_layer, max_layer)?;
}
if comp.weight != 0 {
write!(w, "+ WEIGHT {} ", comp.weight)?;
}
for r in &comp.region {
write!(w, "+ REGION {} ", r)?;
}
writeln!(w, ";")?;
}
writeln!(w, "END COMPONENTS")?;
}
if !def.pins.is_empty() {
writeln!(w, "PINS {} ;", def.pins.len())?;
for pin in &def.pins {
indent(w, 1)?;
writeln!(w, "- {} + NET {}", pin.pin_name, pin.net_name)?;
if pin.special {
indent(w, 2)?;
writeln!(w, "+ SPECIAL")?;
}
if let Some(dir) = pin.direction {
indent(w, 2)?;
writeln!(w, "+ DIRECTION {}", dir)?;
}
if let Some(expr) = &pin.net_expr {
indent(w, 2)?;
writeln!(w, "+ NETEXPR \"{}\"", expr)?;
}
if let Some(s) = &pin.supply_sensitivity {
indent(w, 2)?;
writeln!(w, "+ SUPPLYSENSITIVITY {}", s)?;
}
if let Some(s) = &pin.ground_sensitivity {
indent(w, 2)?;
writeln!(w, "+ GROUNDSENSITIVITY {}", s)?;
}
if pin.signal_use != DEFSignalUse::default() {
indent(w, 2)?;
writeln!(w, "+ USE {}", pin.signal_use)?;
}
for port in &pin.ports {
indent(w, 2)?;
writeln!(w, "+ PORT")?;
}
indent(w, 1)?;
writeln!(w, " ;")?;
}
writeln!(w, "END PINS")?;
}
if !def.blockages.is_empty() {
writeln!(w, "BLOCKAGES {} ;", def.blockages.len())?;
for blockage in &def.blockages {
match blockage {
Blockage::PlacementBlockage(block) => {
indent(w, 1)?;
writeln!(w, "- PLACEMENT")?;
if let Some(t) = &block.blockage_type {
indent(w, 2)?;
match t {
PlacementBlockageType::Soft =>
writeln!(w, "+ SOFT")?,
PlacementBlockageType::Partial(max_density) =>
writeln!(w, "+ PARTIAL {}", max_density)?,
}
}
if block.pushdown {
indent(w, 2)?;
writeln!(w, "+ PUSHDOWN")?;
}
if let Some(component_name) = &block.component {
indent(w, 2)?;
writeln!(w, "+ COMPONENT {}", component_name)?;
}
for r in &block.rects {
indent(w, 2)?;
writeln!(w, "RECT ( {} {} ) ( {} {} )",
r.lower_left().x, r.lower_left.y, r.upper_right().x, r.upper_right().y)?;
}
indent(w, 1)?;
writeln!(w, " ;")?;
}
Blockage::LayerBlockage(block) => {
indent(w, 1)?;
writeln!(w, "- LAYER {}", block.layer)?;
if block.slots {
indent(w, 2)?;
writeln!(w, "+ SLOTS")?;
}
if block.fills {
indent(w, 2)?;
writeln!(w, "+ FILLS")?;
}
if block.pushdown {
indent(w, 2)?;
writeln!(w, "+ PUSHDOWN")?;
}
if block.except_pg_net {
indent(w, 2)?;
writeln!(w, "+ EXCEPTPGNET")?;
}
if let Some(component_name) = &block.component {
indent(w, 2)?;
writeln!(w, "+ COMPONENT {}", component_name)?;
}
if let Some(s) = &block.spacing_or_designrule_width {
indent(w, 2)?;
match s {
SpacingOrDesignRuleWidth::MinSpacing(s) =>
writeln!(w, "+ SPACING {}", s)?,
SpacingOrDesignRuleWidth::DesignRuleWidth(width) =>
writeln!(w, "+ DESIGNRULEWIDTH {}", width)?,
};
}
if let Some(mask_num) = block.mask_num {
indent(w, 2)?;
writeln!(w, "+ MASK {}", mask_num)?;
}
for shape in &block.blockage_shapes {
indent(w, 2)?;
match shape {
BlockageShape::Rect(r) => {
writeln!(w, "RECT ( {} {} ) ( {} {} )",
r.lower_left().x, r.lower_left.y, r.upper_right().x, r.upper_right().y)?;
}
BlockageShape::Polygon(p) => {
write!(w, "POLYGON ")?;
for point in p.iter() {
write!(w, "( {} {} ) ", point.x, point.y)?;
}
writeln!(w)?;
}
};
}
indent(w, 1)?;
writeln!(w, " ;")?;
}
}
}
writeln!(w, "END BLOCKAGES")?;
}
if !def.nets.is_empty() {
writeln!(w, "NETS {} ;", def.nets.len())?;
for net in &def.nets {
indent(w, 1)?;
if let Some(name) = &net.name {
write!(w, "{}", name)?;
for term in &net.terminals {
match term {
NetTerminal::ComponentPin { component_name, pin_name } => {
write!(w, " ( {} {} )", component_name, pin_name)?
}
NetTerminal::IoPin(pin_name) => {
write!(w, " ( PIN {} )", pin_name)?
}
};
}
}
if !net.shield_nets.is_empty() {
writeln!(w)?;
for s in &net.shield_nets {
indent(w, 1)?;
writeln!(w, "+ SHIELDEDNET {}", s)?;
}
}
if net.xtalk_class != 0 {
indent(w, 1)?;
writeln!(w, "+ XTALK {}", net.xtalk_class)?;
}
if let Some(r) = &net.non_default_rule {
indent(w, 1)?;
writeln!(w, "+ NONDEFAULTRULE {}", r)?;
}
for wiring in &net.regular_wiring {
indent(w, 1)?;
writeln!(w, "+ {}", wiring.class)?;
for wiring_stmt in &wiring.wiring {
}
}
if net.source != Default::default() {
indent(w, 1)?;
writeln!(w, "+ SOURCE {}", net.source)?;
}
if net.fixed_bump {
indent(w, 1)?;
writeln!(w, "+ FIXEDBUMP")?;
}
if let Some(f) = net.frequency {
indent(w, 1)?;
writeln!(w, "+ FREQUENCY {}", f)?;
}
if let Some(o) = &net.original {
indent(w, 1)?;
writeln!(w, "+ ORIGINAL {}", o)?;
}
if net.net_use != Default::default() {
indent(w, 1)?;
writeln!(w, "+ USE {}", net.net_use)?;
}
if net.pattern != Default::default() {
indent(w, 1)?;
writeln!(w, "+ PATTERN {}", net.pattern)?;
}
if let Some(c) = net.est_cap {
indent(w, 1)?;
writeln!(w, "+ ESTCAP {}", c)?;
}
if net.weight != 1 {
indent(w, 1)?;
writeln!(w, "+ WEIGHT {}", net.weight)?;
}
for (name, value) in &net.properties {
indent(w, 1)?;
writeln!(w, "+ PROPERTY {} {}", name, value)?;
}
writeln!(w, " ;")?;
}
writeln!(w, "END NETS")?;
}
writeln!(w, "END DESIGN")?;
Ok(())
}