1use libreda_db::prelude as db;
9use libreda_db::prelude::reference_access::*;
10use libreda_db::prelude::{
11 Angle, CoordinateType, Direction, MapPointwise, Scale, TerminalId, ToPolygon, TryBoundingBox,
12 TryCastCoord,
13};
14use libreda_db::traits::*;
15
16use crate::common::{Orient, PinDirection};
17use crate::def_ast::{Component, Net, NetTerminal, Pin, DEF};
18use crate::def_writer::write_def;
19use crate::import::transform_to_def_orient;
20use crate::lef_ast::{Shape, SignalUse, LEF};
21use num_traits::{NumCast, PrimInt};
22use std::cmp::Ordering;
23use std::collections::HashMap;
24use std::fmt::Formatter;
25
26#[derive(Debug, Clone)]
28pub enum LefDefExportError {
29 NameAlreadyExists(String),
31 UnknownLayerName,
33 Other(String),
35}
36
37impl std::fmt::Display for LefDefExportError {
38 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
39 match self {
40 LefDefExportError::NameAlreadyExists(name) => {
41 write!(f, "Name already exists in LEF/DEF structure: {}", name)
42 }
43 LefDefExportError::UnknownLayerName => {
44 write!(f, "No LEF/DEF layer name is known for a data-base layer.")
45 }
46 LefDefExportError::Other(msg) => write!(f, "{}", msg),
47 };
48
49 Ok(())
50 }
51}
52
53#[derive(Clone)]
78pub struct DEFExportOptions<C: L2NBase> {
79 pub export_nets: bool,
81 pub keep_unconnected_nets: bool,
83 pub export_components: bool,
85 pub layer_mapping: HashMap<C::LayerId, String>,
88 pub outline_layer: Option<C::LayerId>,
91}
92
93impl<C: L2NBase> Default for DEFExportOptions<C> {
94 fn default() -> Self {
95 Self {
96 export_nets: true,
97 keep_unconnected_nets: false,
98 export_components: true,
99 layer_mapping: Default::default(),
100 outline_layer: Default::default(),
101 }
102 }
103}
104
105fn get_cell_outline_bbox<C, Crd>(
106 cell: &CellRef<C>,
107 outline_layer: &C::LayerId,
108) -> Option<db::Rect<Crd>>
109where
110 Crd: NumCast + Ord + CoordinateType + PrimInt + std::fmt::Display,
111 C: L2NBase<Coord = Crd>,
112{
113 let shapes: Vec<_> = cell.each_shape_per_layer(outline_layer).collect();
114
115 if shapes.len() == 1 {
116 let shape = shapes.first().unwrap();
117 let geometry = shape.geometry_cloned();
118 let bbox = geometry.try_bounding_box();
119 if bbox.is_none() {
120 log::error!(
121 "Outline shape of cell '{}' has no defined bounding box.",
122 cell.name()
123 );
124 }
125 bbox
126 } else {
127 log::error!(
128 "Cell '{}' should have exactly one outline shape but has {}.",
129 cell.name(),
130 shapes.len()
131 );
132 None
133 }
134}
135
136pub fn export_db_to_def<C, Crd>(
138 options: &DEFExportOptions<C>,
139 chip: &C,
140 top_cell: &C::CellId,
141 def: &mut DEF,
142) -> Result<(), LefDefExportError>
143where
144 Crd: NumCast + Ord + CoordinateType + PrimInt + std::fmt::Display,
145 C: L2NBase<Coord = Crd>,
146{
147 log::info!("Export cell to DEF structure: {}", chip.cell_name(top_cell));
148
149 def.design_name = Some(chip.cell_name(top_cell).into());
151
152 def.units = chip.dbu().to_u32().ok_or_else(|| {
154 LefDefExportError::Other(format!(
155 "Cannot convert DBU ({}) into a unsigned 32-bit integer.",
156 chip.dbu()
157 ))
158 })?;
159
160 let top = chip.cell_ref(top_cell);
161
162 if options.outline_layer.is_none() {
163 return Err(LefDefExportError::Other(
164 "Outline layer must be specified in export options.".into(),
165 ));
166 }
167 let outline_layer = options
168 .outline_layer
169 .as_ref()
170 .expect("outline_layer is not specified.");
171
172 {
174 let top_cell_outline_shapes: Vec<_> = chip.each_shape_id(top_cell, outline_layer).collect();
175
176 if top_cell_outline_shapes.len() == 1 {
177 let shape_id = top_cell_outline_shapes.first().unwrap();
179 let geometry = chip.with_shape(shape_id, |_layer, s| s.clone());
180 let polygon = geometry.to_polygon().exterior;
181 if let Some(rpolygon) = db::SimpleRPolygon::try_new(polygon.points()) {
182 let rpolygon: db::SimpleRPolygon<i32> = rpolygon.try_cast().ok_or_else(|| {
183 LefDefExportError::Other(
184 "Failed to convert DIEAREA into i32 coordinates.".into(),
185 )
186 })?; def.die_area = Some(rpolygon);
188 } else {
189 log::error!("Failed to convert die area into a rectilinear polygon.");
190 }
191 } else {
192 log::warn!(
193 "Top cell should have exactly one outline shape but has {}. DIEAREA is not set.",
194 top_cell_outline_shapes.len()
195 );
196 }
197 }
198
199 let macro_outlines = {
202 let mut macro_outlines = HashMap::new();
203 let mut cells_without_outline: Vec<CellRef<C>> = Vec::new();
204 for subcell in top.each_cell_dependency() {
205 if let Some(outline) = get_cell_outline_bbox(&subcell, outline_layer) {
206 macro_outlines.insert(subcell.id(), outline);
207 } else {
208 cells_without_outline.push(subcell);
209 }
210 }
211 if !cells_without_outline.is_empty() {
212 log::error!(
213 "Number of cells without outline: {}",
214 cells_without_outline.len()
215 );
216 for cell in &cells_without_outline {
217 log::error!("Cell '{}' has no outline.", cell.name());
218 }
219 return Err(LefDefExportError::Other(format!(
220 "{} cells have no outline.",
221 cells_without_outline.len()
222 )));
223 }
224 macro_outlines
225 };
226
227 let instance_names = export_instances_to_def(options, top.clone(), ¯o_outlines, def)?;
230
231 let net_names = export_nets_and_pins_to_def(options, top.clone(), &instance_names, def)?;
233
234 Ok(())
235}
236
237fn compare_name<S: Ord>(a: &Option<S>, b: &Option<S>) -> Ordering {
239 match (a, b) {
240 (None, None) => Ordering::Equal,
241 (_, None) => Ordering::Less,
242 (None, _) => Ordering::Greater,
243 (Some(a), Some(b)) => a.cmp(&b),
244 }
245}
246
247fn export_instances_to_def<C, Crd>(
251 options: &DEFExportOptions<C>,
252 top: CellRef<C>,
253 macro_outlines: &HashMap<C::CellId, db::Rect<Crd>>,
254 def: &mut DEF,
255) -> Result<HashMap<C::CellInstId, String>, LefDefExportError>
256where
257 Crd: NumCast + Ord + CoordinateType + PrimInt,
258 C: L2NBase<Coord = Crd>,
259{
260 log::info!("Export instances to DEF: {}", top.num_child_instances());
261
262 let mut instances: Vec<_> = top.each_cell_instance().collect();
264 instances.sort_by(|a, b| compare_name(&a.name(), &b.name()));
266
267 let mut instance_names = HashMap::new();
269 let mut instance_name_counter = 1;
270 let mut get_instance_name = |inst: &CellInstRef<C>| -> String {
271 let name = instance_names.entry(inst.id()).or_insert_with(|| {
272 if let Some(name) = inst.name() {
273 name.into()
274 } else {
275 loop {
276 let new_name = format!("__{}__", instance_name_counter);
277 instance_name_counter += 1;
278 if top.cell_instance_by_name(new_name.as_str()).is_none() {
279 break new_name;
281 }
282 }
283 }
284 });
285 name.clone()
286 };
287
288 for inst in instances {
290 let mut component = Component::default();
292 component.name = get_instance_name(&inst);
293 component.model_name = inst.template().name().into();
295
296 let is_fixed = false; let tf = inst.get_transform();
299 let displacement: db::Point<_> = {
301 let outline = macro_outlines
302 .get(&inst.template_id())
303 .expect("Macro outline not found.");
304 let outline_transformed = outline.transform(|p| tf.transform_point(p));
305 outline_transformed.lower_left().cast()
306 };
307 let orient = transform_to_def_orient(&tf);
308 component.position = Some((displacement, orient, is_fixed));
309
310 def.components.push(component)
311 }
312
313 Ok(instance_names)
315}
316
317fn export_nets_and_pins_to_def<C, Crd>(
324 options: &DEFExportOptions<C>,
325 top: CellRef<C>,
326 instance_names: &HashMap<C::CellInstId, String>,
327 def: &mut DEF,
328) -> Result<HashMap<C::NetId, String>, LefDefExportError>
329where
330 C: L2NBase<Coord = Crd>,
331{
332 log::info!("Export nets to DEF: {}", top.num_internal_nets());
333
334 let mut net_names = HashMap::new();
337 let mut net_name_generator = 1;
338 let mut create_new_net_name = |prefix: &str| -> String {
339 loop {
340 let new_name = format!("__{}{}__", prefix, net_name_generator);
341 net_name_generator += 1;
342 if top.net_by_name(new_name.as_str()).is_none() {
343 break new_name;
345 }
346 }
347 };
348 let mut get_net_name = |net: &NetRef<C>| -> String {
349 let name = net_names.entry(net.id()).or_insert_with(|| {
350 if let Some(name) = net.name() {
351 name.into()
352 } else {
353 create_new_net_name("")
354 }
355 });
356 name.clone()
357 };
358
359 let mut nets: Vec<_> = top.each_net().collect();
360 nets.sort_by(|a, b| compare_name(&a.name(), &b.name()));
361
362 for net_ref in nets {
364 let mut net = Net::default();
366 net.name = Some(get_net_name(&net_ref).to_string());
368
369 for pin in net_ref.each_pin() {
371 net.terminals.push(NetTerminal::IoPin(pin.name().into()));
372 }
373 for pin in net_ref.each_pin_instance() {
374 net.terminals.push(NetTerminal::ComponentPin {
375 component_name: instance_names
376 .get(&pin.cell_instance().id())
377 .expect("Cell instance not found.")
378 .to_string(),
379 pin_name: pin.pin().name().into(),
380 });
381 }
382
383 if !net.terminals.is_empty() || options.keep_unconnected_nets {
384 def.nets.push(net);
385 }
386 }
387
388 let mut pins: Vec<_> = top.each_pin().collect();
390 pins.sort_by_key(|pin| pin.name());
391
392 for pin_ref in pins {
393 let mut pin = Pin::default();
394 pin.pin_name = pin_ref.name().into();
396 pin.net_name = pin_ref
398 .net()
399 .map(|net| {
400 net_names
401 .get(&net.id())
402 .expect("Net name not found.")
403 .clone()
404 })
405 .unwrap_or_else(|| {
406 let new_net_name = create_new_net_name("pin_unconnected");
410
411 let mut net = Net::default();
413 net.name = Some(new_net_name.clone());
414 def.nets.push(net);
415
416 new_net_name
417 });
418
419 def.pins.push(pin);
421 }
422
423 Ok(net_names)
424}
425
426#[test]
427fn test_export_to_def() {
428 use db::traits::*;
429 use libreda_db::prelude as db;
430
431 let mut chip = db::Chip::new();
432 let outline_layer = chip.create_layer(1, 0);
433 let top_cell = chip.create_cell("TOP".to_string());
434
435 let pin_a = chip.create_pin(&top_cell, "Input_A".to_string(), db::Direction::Input);
437 let pin_b = chip.create_pin(&top_cell, "Output_Y".to_string(), db::Direction::Output);
438
439 let net_a = chip.create_net(&top_cell, Some("net_a".to_string()));
441 let net_b = chip.create_net(&top_cell, Some("net_b".to_string()));
442
443 chip.connect_pin(&pin_a, Some(net_a.clone()));
444 chip.connect_pin(&pin_b, Some(net_b.clone()));
445
446 let sub_cell = chip.create_cell("SUB".to_string());
448 chip.insert_shape(
450 &sub_cell,
451 &outline_layer,
452 db::Rect::new((0, 0), (10, 10)).into(),
453 );
454
455 let inst1 = chip.create_cell_instance(&top_cell, &sub_cell, Some("inst1".to_string()));
457
458 chip.set_transform(
459 &inst1,
460 db::SimpleTransform::new(true, Angle::R0, 1, (100, 200).into()),
461 );
462
463 chip.create_cell_instance(&top_cell, &sub_cell, Some("inst2".to_string()));
464 chip.create_cell_instance(&top_cell, &sub_cell, None);
466 chip.create_cell_instance(&top_cell, &sub_cell, None);
467
468 let mut def = DEF::default();
469 let mut export_options = DEFExportOptions::default();
470 export_options.outline_layer = Some(outline_layer);
471 let result = export_db_to_def(&export_options, &chip, &top_cell, &mut def);
472 if result.is_err() {
473 dbg!(&result);
474 }
475 result.expect("DEF export failed.");
476
477 let mut buffer: Vec<u8> = Vec::new();
478 write_def(&mut buffer, &def).expect("Writing DEF failed.");
479
480 let def_string = String::from_utf8(buffer).expect("DEF writer output is not valid UTF-8.");
481 println!("{}", &def_string);
482
483 assert!(def_string.contains("+ PLACED ( 100 190 ) FS"));
485}