libreda_lefdef/
def_writer.rs

1// Copyright (c) 2021-2021 Thomas Kramer.
2// SPDX-FileCopyrightText: 2022 Thomas Kramer <code@tkramer.ch>
3//
4// SPDX-License-Identifier: AGPL-3.0-or-later
5
6//! Write DEF data structure into DEF file format.
7
8use crate::common::PinDirection;
9use crate::def_ast::{
10    Blockage, ComponentSource, DEFSignalUse, NetTerminal, PlacementBlockageType, RectOrPolygon,
11    SpacingOrDesignRuleWidth, DEF,
12};
13use libreda_db::prelude::{SimpleRPolygon, TryBoundingBox};
14use num_traits::PrimInt;
15use std::fmt;
16use std::fmt::{Debug, Display};
17use std::io::Write;
18
19/// Error type that can happen when serializing a DEF file.
20#[derive(Debug)]
21pub enum DEFWriterError {
22    /// IO Error.
23    IOError(std::io::Error),
24}
25
26impl From<std::io::Error> for DEFWriterError {
27    fn from(err: std::io::Error) -> Self {
28        match err.kind() {
29            _ => DEFWriterError::IOError(err),
30        }
31    }
32}
33
34impl fmt::Display for DEFWriterError {
35    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
36        use DEFWriterError::*;
37        match self {
38            IOError(e) => write!(f, "{}", e),
39        }
40    }
41}
42
43/// Write the point of a polygon in the DEF format: ( x1 y1 ) ( x2 y2 ) ...
44fn write_polygon<W: Write, T: PrimInt + Display>(
45    w: &mut W,
46    p: &SimpleRPolygon<T>,
47) -> Result<(), DEFWriterError> {
48    for point in p.points() {
49        write!(w, "( {} {} ) ", point.x, point.y)?;
50    }
51    Ok(())
52}
53
54/// Write the DEF data structure into its ASCII representation.
55/// Ordering of the statements follows the official recommendation.
56pub fn write_def<W: Write>(w: &mut W, def: &DEF) -> Result<(), DEFWriterError> {
57    let indent = |w: &mut W, level: u32| -> Result<(), std::io::Error> {
58        for _ in 0..level {
59            write!(w, "    ")?;
60        }
61        Ok(())
62    };
63
64    // VERSION
65    for v in &def.version {
66        writeln!(w, "VERSION {} ;", v)?;
67    }
68
69    // // NAMESCASESENSITIVE (not needed in DEF version 5.6 or later)
70    // writeln!(w, "NAMESCASESENSITIVE ON ;")?;
71
72    // DIVIDERCHAR
73    writeln!(w, r#"DIVIDERCHAR "{}" ;"#, def.dividerchar)?;
74
75    // BUSBITCHARS
76    writeln!(
77        w,
78        r#"BUSBITCHARS "{}{}" ;"#,
79        def.busbitchars.0, def.busbitchars.1
80    )?;
81
82    // DESIGN
83    for n in &def.design_name {
84        writeln!(w, "DESIGN {} ;", n)?;
85    }
86
87    // TECHNOLOGY
88    for n in &def.technology {
89        writeln!(w, "TECHNOLOGY {} ;", n)?;
90    }
91
92    // UNITS
93    writeln!(w, "UNITS DISTANCE MICRONS {} ;", def.units)?;
94
95    // HISTORY
96    for h in &def.history {
97        // TODO: Escape or deny special characters.
98        writeln!(w, "HISTORY {} ;", h)?;
99    }
100
101    // PROPERTYDEFINITIONS
102    if !def.property_definitions.is_empty() {
103        writeln!(w, "PROPERTYDEFINITIONS")?;
104        for (name, p) in &def.property_definitions {
105            indent(w, 1)?;
106            write!(w, "{} {} {} ", p.object_type, name, p.property_type)?;
107            if let Some((min, max)) = &p.range {
108                write!(w, "RANGE {} {} ", min, max)?;
109            }
110            if let Some(default) = &p.default_value {
111                write!(w, "{} ", default)?;
112            }
113            writeln!(w, ";")?;
114        }
115        writeln!(w, "END PROPERTYDEFINITIONS")?;
116    }
117
118    // DIEAREA
119    if let Some(area) = &def.die_area {
120        write!(w, "DIEAREA ")?;
121        if area.len() == 4 {
122            // This is a rectangle.
123            let rect = area.try_bounding_box().unwrap(); // Unwrap is safe since there are four points.
124            write!(
125                w,
126                "( {} {} ) ( {} {} ) ",
127                rect.lower_left().x,
128                rect.lower_left().y,
129                rect.upper_right().x,
130                rect.upper_right().y
131            )?;
132        } else {
133            write_polygon(w, area)?;
134        }
135        writeln!(w, ";")?;
136    }
137
138    // ROWS
139    for (row_name, row) in &def.rows {
140        write!(
141            w,
142            "ROW {} {} {} {} {}",
143            row_name, row.site_name, row.orig.0, row.orig.1, row.site_orient
144        )?;
145        write!(
146            w,
147            " DO {} BY {}",
148            row.step_pattern.num_x, row.step_pattern.num_y
149        )?;
150        if let Some((dx, dy)) = row.step_pattern.step {
151            write!(w, " STEP {} {}", dx, dy)?;
152        }
153        if !row.properties.is_empty() {
154            writeln!(w)?;
155            for (name, value) in &row.properties {
156                indent(w, 1)?;
157                writeln!(w, "+ PROPERTY {} {}", name, value)?;
158            }
159        }
160        writeln!(w, " ;")?;
161    }
162
163    // TRACKS
164    for tracks in &def.tracks {
165        let xy = if tracks.is_horizontal { "Y" } else { "X" };
166        write!(
167            w,
168            "TRACKS {} {} DO {} STEP {}",
169            xy, tracks.start, tracks.num_tracks, tracks.step
170        )?;
171        if let Some((mask_num, same_mask)) = &tracks.mask {
172            write!(w, " MASK {}", mask_num)?;
173            if *same_mask {
174                write!(w, " SAMEMASK")?;
175            }
176        }
177        if !tracks.layers.is_empty() {
178            write!(w, " LAYER")?;
179            for layer in &tracks.layers {
180                write!(w, " {}", layer)?;
181            }
182        }
183        writeln!(w, " ;")?;
184    }
185
186    // GCELLGRID
187    // VIAS
188    // STYLES
189    // NONDEFAULTRULES
190
191    // REGIONS
192    if !def.regions.is_empty() {
193        writeln!(w, "REGIONS {} ;", def.regions.len())?;
194        for (name, region) in &def.regions {
195            indent(w, 1)?;
196            write!(w, "- {} ", name)?;
197            // Write rectangles that define the region.
198            for r in &region.regions {
199                write!(w, "( {} {} ) ", r.lower_left(), r.upper_right())?;
200            }
201            writeln!(w)?;
202
203            // TYPE
204            for region_type in &region.region_type {
205                indent(w, 2)?;
206                writeln!(w, "+ TYPE {} ", region_type)?;
207            }
208
209            // TODO: PROPERTY
210        }
211        writeln!(w, "END REGIONS")?;
212    }
213
214    // COMPONENTMASKSHIFT
215
216    // COMPONENTS
217    if !def.components.is_empty() {
218        writeln!(w, "COMPONENTS {} ;", def.components.len())?;
219        for comp in &def.components {
220            indent(w, 1)?;
221            write!(w, "- {} {} ", comp.name, comp.model_name)?;
222
223            for m in &comp.eeq_master {
224                write!(w, "+ EEQMASTER {} ", m)?;
225            }
226
227            if comp.source != ComponentSource::default() {
228                write!(w, "+ SOURCE {} ", comp.source)?;
229            }
230
231            // Position
232            // TODO: COVER
233            match &comp.position {
234                None => write!(w, "+ UNPLACED ")?,
235                Some((p, orient, false)) => write!(w, "+ PLACED ( {} {} ) {} ", p.x, p.y, orient)?,
236                Some((p, orient, true)) => write!(w, "+ FIXED ( {} {} ) {} ", p.x, p.y, orient)?,
237            }
238
239            // TODO: MASKSHIFT
240
241            // HALO
242            for (soft, left, bottom, right, top) in &comp.halo {
243                write!(w, "+ HALO ")?;
244                if *soft {
245                    write!(w, "SOFT ")?;
246                }
247                write!(w, "{} {} {} {} ", left, bottom, right, top)?;
248            }
249            // ROUTEHALO
250            for (dist, min_layer, max_layer) in &comp.route_halo {
251                write!(w, "+ ROUTEHALO {} {} {} ", dist, min_layer, max_layer)?;
252            }
253
254            // WEIGHT
255            if comp.weight != 0 {
256                write!(w, "+ WEIGHT {} ", comp.weight)?;
257            }
258
259            // REGION
260            for r in &comp.region {
261                write!(w, "+ REGION {} ", r)?;
262            }
263
264            // PROPERTY: TODO
265            writeln!(w, ";")?;
266        }
267        writeln!(w, "END COMPONENTS")?;
268    }
269
270    // PINS
271    if !def.pins.is_empty() {
272        writeln!(w, "PINS {} ;", def.pins.len())?;
273
274        for pin in &def.pins {
275            indent(w, 1)?;
276            writeln!(w, "- {} + NET {}", pin.pin_name, pin.net_name)?;
277            if pin.special {
278                indent(w, 2)?;
279                writeln!(w, "+ SPECIAL")?;
280            }
281            if let Some(dir) = pin.direction {
282                indent(w, 2)?;
283                writeln!(w, "+ DIRECTION {}", dir)?;
284            }
285            if let Some(expr) = &pin.net_expr {
286                indent(w, 2)?;
287                writeln!(w, "+ NETEXPR \"{}\"", expr)?;
288            }
289            if let Some(s) = &pin.supply_sensitivity {
290                indent(w, 2)?;
291                writeln!(w, "+ SUPPLYSENSITIVITY {}", s)?;
292            }
293            if let Some(s) = &pin.ground_sensitivity {
294                indent(w, 2)?;
295                writeln!(w, "+ GROUNDSENSITIVITY {}", s)?;
296            }
297            if pin.signal_use != DEFSignalUse::default() {
298                indent(w, 2)?;
299                writeln!(w, "+ USE {}", pin.signal_use)?;
300            }
301            // TODO Antenna stuff.
302
303            // PORT
304            for port in &pin.ports {
305                indent(w, 2)?;
306                writeln!(w, "+ PORT")?;
307            }
308
309            indent(w, 1)?;
310            writeln!(w, " ;")?;
311        }
312
313        writeln!(w, "END PINS")?;
314    }
315
316    // PINPROPERTIES
317    // BLOCKAGES
318
319    if !def.blockages.is_empty() {
320        writeln!(w, "BLOCKAGES {} ;", def.blockages.len())?;
321
322        for blockage in &def.blockages {
323            match blockage {
324                Blockage::PlacementBlockage(block) => {
325                    indent(w, 1)?;
326                    writeln!(w, "- PLACEMENT")?;
327
328                    if let Some(t) = &block.blockage_type {
329                        indent(w, 2)?;
330                        match t {
331                            PlacementBlockageType::Soft => writeln!(w, "+ SOFT")?,
332                            PlacementBlockageType::Partial(max_density) => {
333                                writeln!(w, "+ PARTIAL {}", max_density)?
334                            }
335                        }
336                    }
337
338                    if block.pushdown {
339                        indent(w, 2)?;
340                        writeln!(w, "+ PUSHDOWN")?;
341                    }
342
343                    if let Some(component_name) = &block.component {
344                        indent(w, 2)?;
345                        writeln!(w, "+ COMPONENT {}", component_name)?;
346                    }
347
348                    for r in &block.rects {
349                        indent(w, 2)?;
350                        writeln!(
351                            w,
352                            "RECT ( {} {} ) ( {} {} )",
353                            r.lower_left().x,
354                            r.lower_left().y,
355                            r.upper_right().x,
356                            r.upper_right().y
357                        )?;
358                    }
359
360                    indent(w, 1)?;
361                    writeln!(w, " ;")?;
362                }
363                Blockage::LayerBlockage(block) => {
364                    indent(w, 1)?;
365                    writeln!(w, "- LAYER {}", block.layer)?;
366
367                    if block.slots {
368                        indent(w, 2)?;
369                        writeln!(w, "+ SLOTS")?;
370                    }
371
372                    if block.fills {
373                        indent(w, 2)?;
374                        writeln!(w, "+ FILLS")?;
375                    }
376
377                    if block.pushdown {
378                        indent(w, 2)?;
379                        writeln!(w, "+ PUSHDOWN")?;
380                    }
381
382                    if block.except_pg_net {
383                        indent(w, 2)?;
384                        writeln!(w, "+ EXCEPTPGNET")?;
385                    }
386
387                    if let Some(component_name) = &block.component {
388                        indent(w, 2)?;
389                        writeln!(w, "+ COMPONENT {}", component_name)?;
390                    }
391
392                    if let Some(s) = &block.spacing_or_designrule_width {
393                        indent(w, 2)?;
394                        match s {
395                            SpacingOrDesignRuleWidth::MinSpacing(s) => {
396                                writeln!(w, "+ SPACING {}", s)?
397                            }
398                            SpacingOrDesignRuleWidth::DesignRuleWidth(width) => {
399                                writeln!(w, "+ DESIGNRULEWIDTH {}", width)?
400                            }
401                        };
402                    }
403
404                    if let Some(mask_num) = block.mask_num {
405                        indent(w, 2)?;
406                        writeln!(w, "+ MASK {}", mask_num)?;
407                    }
408
409                    for shape in &block.blockage_shapes {
410                        indent(w, 2)?;
411                        match shape {
412                            RectOrPolygon::Rect(r) => {
413                                writeln!(
414                                    w,
415                                    "RECT ( {} {} ) ( {} {} )",
416                                    r.lower_left().x,
417                                    r.lower_left().y,
418                                    r.upper_right().x,
419                                    r.upper_right().y
420                                )?;
421                            }
422                            RectOrPolygon::Polygon(p) => {
423                                write!(w, "POLYGON ")?;
424                                for point in p.iter() {
425                                    write!(w, "( {} {} ) ", point.x, point.y)?;
426                                }
427                                writeln!(w)?;
428                            }
429                        };
430                    }
431                    indent(w, 1)?;
432                    writeln!(w, " ;")?;
433                }
434            }
435        }
436
437        writeln!(w, "END BLOCKAGES")?;
438    }
439
440    // SLOTS
441    // FILLS
442    // SPECIALNETS
443
444    // NETS
445    if !def.nets.is_empty() {
446        writeln!(w, "NETS {} ;", def.nets.len())?;
447        for net in &def.nets {
448            indent(w, 1)?;
449
450            if let Some(name) = &net.name {
451                write!(w, "- {}", name)?;
452                for term in &net.terminals {
453                    match term {
454                        NetTerminal::ComponentPin {
455                            component_name,
456                            pin_name,
457                        } => write!(w, " ( {} {} )", component_name, pin_name)?,
458                        NetTerminal::IoPin(pin_name) => write!(w, " ( PIN {} )", pin_name)?,
459                    };
460                }
461            }
462
463            // SHIELDEDNET
464            if !net.shield_nets.is_empty() {
465                writeln!(w)?;
466                for s in &net.shield_nets {
467                    indent(w, 1)?;
468                    writeln!(w, "+ SHIELDEDNET {}", s)?;
469                }
470            }
471
472            // VPIN
473            // SUBNET
474
475            // XTALK
476            if net.xtalk_class != 0 {
477                indent(w, 1)?;
478                writeln!(w, "+ XTALK {}", net.xtalk_class)?;
479            }
480
481            // NONDEFAULTRULE
482            if let Some(r) = &net.non_default_rule {
483                indent(w, 1)?;
484                writeln!(w, "+ NONDEFAULTRULE {}", r)?;
485            }
486
487            // regular wiring
488            for wiring in &net.regular_wiring {
489                // TODO
490                indent(w, 1)?;
491                writeln!(w, "+ {}", wiring.class)?;
492                for wiring_stmt in &wiring.wiring {
493                    // TODO
494                }
495            }
496
497            // SOURCE
498            if net.source != Default::default() {
499                indent(w, 1)?;
500                writeln!(w, "+ SOURCE {}", net.source)?;
501            }
502
503            // FIXEDBUMP
504            if net.fixed_bump {
505                indent(w, 1)?;
506                writeln!(w, "+ FIXEDBUMP")?;
507            }
508
509            // FREQUENCY
510            if let Some(f) = net.frequency {
511                indent(w, 1)?;
512                writeln!(w, "+ FREQUENCY {}", f)?;
513            }
514
515            // Original
516            if let Some(o) = &net.original {
517                indent(w, 1)?;
518                writeln!(w, "+ ORIGINAL {}", o)?;
519            }
520
521            // USE
522            if net.net_use != Default::default() {
523                indent(w, 1)?;
524                writeln!(w, "+ USE {}", net.net_use)?;
525            }
526
527            // PATTERN
528            if net.pattern != Default::default() {
529                indent(w, 1)?;
530                writeln!(w, "+ PATTERN {}", net.pattern)?;
531            }
532
533            // ESTCAP
534            if let Some(c) = net.est_cap {
535                indent(w, 1)?;
536                writeln!(w, "+ ESTCAP {}", c)?;
537            }
538
539            // WEIGHT
540            if net.weight != 1 {
541                indent(w, 1)?;
542                writeln!(w, "+ WEIGHT {}", net.weight)?;
543            }
544
545            // PROPERTY
546            for (name, value) in &net.properties {
547                indent(w, 1)?;
548                writeln!(w, "+ PROPERTY {} {}", name, value)?;
549            }
550
551            writeln!(w, " ;")?;
552        }
553        writeln!(w, "END NETS")?;
554    }
555
556    // SCANCHAINS
557    // GROUPS
558    // BEGINEXT
559
560    writeln!(w, "END DESIGN")?;
561    Ok(())
562}