1use 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#[derive(Debug)]
21pub enum DEFWriterError {
22 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
43fn 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
54pub 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 for v in &def.version {
66 writeln!(w, "VERSION {} ;", v)?;
67 }
68
69 writeln!(w, r#"DIVIDERCHAR "{}" ;"#, def.dividerchar)?;
74
75 writeln!(
77 w,
78 r#"BUSBITCHARS "{}{}" ;"#,
79 def.busbitchars.0, def.busbitchars.1
80 )?;
81
82 for n in &def.design_name {
84 writeln!(w, "DESIGN {} ;", n)?;
85 }
86
87 for n in &def.technology {
89 writeln!(w, "TECHNOLOGY {} ;", n)?;
90 }
91
92 writeln!(w, "UNITS DISTANCE MICRONS {} ;", def.units)?;
94
95 for h in &def.history {
97 writeln!(w, "HISTORY {} ;", h)?;
99 }
100
101 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 if let Some(area) = &def.die_area {
120 write!(w, "DIEAREA ")?;
121 if area.len() == 4 {
122 let rect = area.try_bounding_box().unwrap(); 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 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 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 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 for r in ®ion.regions {
199 write!(w, "( {} {} ) ", r.lower_left(), r.upper_right())?;
200 }
201 writeln!(w)?;
202
203 for region_type in ®ion.region_type {
205 indent(w, 2)?;
206 writeln!(w, "+ TYPE {} ", region_type)?;
207 }
208
209 }
211 writeln!(w, "END REGIONS")?;
212 }
213
214 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 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 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 for (dist, min_layer, max_layer) in &comp.route_halo {
251 write!(w, "+ ROUTEHALO {} {} {} ", dist, min_layer, max_layer)?;
252 }
253
254 if comp.weight != 0 {
256 write!(w, "+ WEIGHT {} ", comp.weight)?;
257 }
258
259 for r in &comp.region {
261 write!(w, "+ REGION {} ", r)?;
262 }
263
264 writeln!(w, ";")?;
266 }
267 writeln!(w, "END COMPONENTS")?;
268 }
269
270 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 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 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 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 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 if net.xtalk_class != 0 {
477 indent(w, 1)?;
478 writeln!(w, "+ XTALK {}", net.xtalk_class)?;
479 }
480
481 if let Some(r) = &net.non_default_rule {
483 indent(w, 1)?;
484 writeln!(w, "+ NONDEFAULTRULE {}", r)?;
485 }
486
487 for wiring in &net.regular_wiring {
489 indent(w, 1)?;
491 writeln!(w, "+ {}", wiring.class)?;
492 for wiring_stmt in &wiring.wiring {
493 }
495 }
496
497 if net.source != Default::default() {
499 indent(w, 1)?;
500 writeln!(w, "+ SOURCE {}", net.source)?;
501 }
502
503 if net.fixed_bump {
505 indent(w, 1)?;
506 writeln!(w, "+ FIXEDBUMP")?;
507 }
508
509 if let Some(f) = net.frequency {
511 indent(w, 1)?;
512 writeln!(w, "+ FREQUENCY {}", f)?;
513 }
514
515 if let Some(o) = &net.original {
517 indent(w, 1)?;
518 writeln!(w, "+ ORIGINAL {}", o)?;
519 }
520
521 if net.net_use != Default::default() {
523 indent(w, 1)?;
524 writeln!(w, "+ USE {}", net.net_use)?;
525 }
526
527 if net.pattern != Default::default() {
529 indent(w, 1)?;
530 writeln!(w, "+ PATTERN {}", net.pattern)?;
531 }
532
533 if let Some(c) = net.est_cap {
535 indent(w, 1)?;
536 writeln!(w, "+ ESTCAP {}", c)?;
537 }
538
539 if net.weight != 1 {
541 indent(w, 1)?;
542 writeln!(w, "+ WEIGHT {}", net.weight)?;
543 }
544
545 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 writeln!(w, "END DESIGN")?;
561 Ok(())
562}