1use crate::Modal;
9use libreda_db::layout::prelude::*;
10
11use crate::base_types::*;
12
13use libreda_db::layout::traits::LayoutBase;
14use std::borrow::Borrow;
15use std::io::Write;
16
17#[derive(Copy, Clone, Debug, Default)]
19pub enum OASISValidationScheme {
20 #[default]
21 None,
22 }
25
26#[derive(Clone, Debug, Default)]
28pub struct OASISWriterConfig {
29 table_offsets_at_start: bool,
32
33 pub explicit_ids: bool,
35
36 pub validation_scheme: OASISValidationScheme,
38}
39
40#[derive(Copy, Clone, Debug, Default)]
41struct Offset {
42 flag: UInt,
43 offset: UInt,
44}
45
46#[derive(Clone, Debug, Default)]
47struct OffsetTable {
48 cellname: Offset,
49 textstring: Offset,
50 propname: Offset,
51 propstring: Offset,
52 layername: Offset,
53 xname: Offset,
54}
55
56fn write_offset_table<W: Write>(writer: &mut W, t: &OffsetTable) -> Result<(), OASISWriteError> {
58 for o in &[
59 t.cellname,
60 t.textstring,
61 t.propname,
62 t.propstring,
63 t.layername,
64 t.xname,
65 ] {
66 write_unsigned_integer(writer, o.flag)?;
67 write_unsigned_integer(writer, o.offset)?;
68 }
69
70 Ok(())
71}
72
73fn bit(index: UInt, value: bool) -> UInt {
75 (value as UInt) << index
76}
77
78fn write_path<W: Write, C>(
80 writer: &mut W,
81 modal: &mut Modal<C>,
82 p: &Path<Coord>,
83 layer_index: UInt,
84 layer_datatype: UInt,
85) -> Result<(), OASISWriteError> {
86 trace!("Write PATH record");
87 write_unsigned_integer(writer, 22)?; if !p.is_empty() {
90 let offset = p.points.points.first().unwrap(); let point_list = PointList::from_points_explicit(p.points.points.iter().copied());
92
93 let (x, y) = offset.into();
94 let half_width = (p.width as UInt) / 2; let (start_ext, end_ext) = match p.path_type {
97 PathEndType::Flat => (0, 0),
98 PathEndType::Extended(s, e) => (s, e),
99 PathEndType::Round => unimplemented!("Round path endings are not supported yet."), };
101
102 let write_layer_number = modal.layer != Some(layer_index);
104 let write_datatype = modal.layer != Some(layer_datatype);
105 let write_x = modal.geometry_x != x;
106 let write_y = modal.geometry_y != y;
107 let write_repetition = false; let write_point_list = Some(&point_list) != modal.path_point_list.as_ref();
110 let write_half_width_present = modal.path_halfwidth != Some(half_width);
111 let write_extension_scheme_present = modal.path_start_extension != Some(start_ext)
112 || modal.path_end_extension != Some(end_ext);
113
114 let path_info_byte = bit(7, write_extension_scheme_present)
115 | bit(6, write_half_width_present)
116 | bit(5, write_point_list)
117 | bit(4, write_x)
118 | bit(3, write_y)
119 | bit(2, write_repetition)
120 | bit(1, write_datatype)
121 | bit(0, write_layer_number);
122 write_byte(writer, path_info_byte as u8)?;
123
124 if write_layer_number {
125 write_unsigned_integer(writer, layer_index)?
126 };
127 if write_datatype {
128 write_unsigned_integer(writer, layer_datatype)?
129 };
130 if write_half_width_present {
131 write_unsigned_integer(writer, half_width)?
132 };
133 if write_extension_scheme_present {
134 let ss = match start_ext {
135 0 => 0b01, x if x == half_width as SInt => 0b10, x if Some(x) == modal.path_start_extension => 0b00, _ => 0b11, };
140 let ee = match end_ext {
141 0 => 0b01, x if x == half_width as SInt => 0b10, x if Some(x) == modal.path_end_extension => 0b00, _ => 0b11, };
146
147 let extension_scheme = (ss << 2) | ee;
148
149 write_byte(writer, extension_scheme)?;
151
152 if ss == 0b11 {
153 write_signed_integer(writer, start_ext)?;
155 }
156
157 if ee == 0b11 {
158 write_signed_integer(writer, end_ext)?;
160 }
161 };
162 if write_point_list {
163 write_pointlist(writer, &point_list)?
164 };
165 if write_x {
166 write_signed_integer(writer, x)?
167 };
168 if write_y {
169 write_signed_integer(writer, y)?
170 };
171 if write_repetition {
172 modal.repetition = None;
173 unimplemented!();
174 };
175
176 modal.path_point_list = Some(point_list);
178 modal.path_halfwidth = Some(half_width);
179 modal.path_start_extension = Some(start_ext);
180 modal.path_end_extension = Some(end_ext);
181
182 modal.geometry_x = x;
183 modal.geometry_y = y;
184
185 modal.datatype = Some(layer_datatype);
186 modal.layer = Some(layer_index);
187 } else {
188 }
190 Ok(())
191}
192
193fn write_rect<W: Write, C>(
195 writer: &mut W,
196 modal: &mut Modal<C>,
197 r: &Rect<Coord>,
198 layer_index: UInt,
199 layer_datatype: UInt,
200) -> Result<(), OASISWriteError> {
201 trace!("Write RECT record");
202 write_unsigned_integer(writer, 20)?;
203
204 let width = r.width() as UInt;
206 let height = r.height() as UInt;
207 let (x, y) = r.lower_left.into();
208
209 let is_square = width == height;
210 let write_layer_number = modal.layer != Some(layer_index);
211 let write_datatype = modal.datatype != Some(layer_datatype);
212 let write_width = modal.geometry_w != Some(width);
213 let write_height = !is_square && modal.geometry_h != Some(height);
214 let write_x = modal.geometry_x != x;
215 let write_y = modal.geometry_y != y;
216 let write_repetition = false; let rectangle_info_byte = bit(7, is_square)
218 | bit(6, write_width)
219 | bit(5, write_height)
220 | bit(4, write_x)
221 | bit(3, write_y)
222 | bit(2, write_repetition)
223 | bit(1, write_datatype)
224 | bit(0, write_layer_number);
225 write_byte(writer, rectangle_info_byte as u8)?;
226
227 if write_layer_number {
228 write_unsigned_integer(writer, layer_index)?
229 };
230 if write_datatype {
231 write_unsigned_integer(writer, layer_datatype)?
232 };
233 if write_width {
234 write_unsigned_integer(writer, width)?
235 };
236 if write_height {
237 write_unsigned_integer(writer, height)?
238 };
239 if write_x {
240 write_signed_integer(writer, x)?
241 };
242 if write_y {
243 write_signed_integer(writer, y)?
244 };
245 if write_repetition {
246 unimplemented!();
247 };
248
249 modal.geometry_w = Some(width);
250 modal.geometry_h = Some(height);
251 modal.geometry_x = x;
252 modal.geometry_y = y;
253
254 modal.datatype = Some(layer_datatype);
255 modal.layer = Some(layer_index);
256 Ok(())
257}
258
259fn write_simple_polygon<W: Write, C>(
261 writer: &mut W,
262 modal: &mut Modal<C>,
263 p: &SimplePolygon<Coord>,
264 layer_index: UInt,
265 layer_datatype: UInt,
266) -> Result<(), OASISWriteError> {
267 trace!("Write POLYGON record");
268
269 write_unsigned_integer(writer, 21)?;
270
271 if p.len() > 1 {
272 let offset = p.points().first().unwrap(); let point_list = PointList::from_points_explicit(p.points().iter().copied());
274
275 let (x, y) = offset.into();
276
277 let write_layer_number = modal.layer != Some(layer_index);
279 let write_datatype = modal.layer != Some(layer_datatype);
280 let write_x = modal.geometry_x != x;
281 let write_y = modal.geometry_y != y;
282 let write_repetition = false; let is_pointlist_present = Some(&point_list) != modal.polygon_point_list.as_ref();
285
286 let polygon_info_byte = bit(5, is_pointlist_present)
287 | bit(4, write_x)
288 | bit(3, write_y)
289 | bit(2, write_repetition)
290 | bit(1, write_datatype)
291 | bit(0, write_layer_number);
292 write_byte(writer, polygon_info_byte as u8)?;
293 if write_layer_number {
294 write_unsigned_integer(writer, layer_index)?
295 };
296 if write_datatype {
297 write_unsigned_integer(writer, layer_datatype)?
298 };
299 if is_pointlist_present {
300 write_pointlist(writer, &point_list)?
301 };
302 if write_x {
303 write_signed_integer(writer, x)?
304 };
305 if write_y {
306 write_signed_integer(writer, y)?
307 };
308 if write_repetition {
309 modal.repetition = None;
310 unimplemented!();
311 };
312
313 modal.polygon_point_list = Some(point_list);
315
316 modal.geometry_x = x;
317 modal.geometry_y = y;
318
319 modal.datatype = Some(layer_datatype);
320 modal.layer = Some(layer_index);
321 } else {
322 }
324 Ok(())
325}
326
327fn write_text<W: Write, C>(
329 writer: &mut W,
330 modal: &mut Modal<C>,
331 text: &Text<Coord>,
332 layer_index: UInt,
333 layer_datatype: UInt,
334) -> Result<(), OASISWriteError> {
335 trace!("TEXT record");
336
337 write_unsigned_integer(writer, 19)?; let text_string = text.text();
340 let x = text.x();
341 let y = text.y();
342
343 let write_text_reference = modal.text_string.as_ref() != Some(text_string);
346 let write_reference_number = false;
349
350 let write_textlayer = modal.textlayer != Some(layer_index);
351 let write_texttype = modal.texttype != Some(layer_datatype);
352 let write_x = modal.text_x != x;
353 let write_y = modal.text_y != y;
354
355 let write_repetition = false; let text_info_byte = bit(6, write_text_reference)
358 | bit(5, write_reference_number)
359 | bit(4, write_x)
360 | bit(3, write_y)
361 | bit(2, write_repetition)
362 | bit(1, write_texttype)
363 | bit(0, write_textlayer);
364 write_byte(writer, text_info_byte as u8)?;
365
366 if write_text_reference {
367 if write_reference_number {
368 unimplemented!()
370 } else {
371 write_ascii_string(writer, text_string.as_bytes())?
373 }
374 }
375
376 if write_textlayer {
377 write_unsigned_integer(writer, layer_index)?
378 };
379 if write_texttype {
380 write_unsigned_integer(writer, layer_datatype)?
381 };
382 if write_x {
383 write_signed_integer(writer, x)?
384 };
385 if write_y {
386 write_signed_integer(writer, y)?
387 };
388 if write_repetition {
389 modal.repetition = None;
390 unimplemented!();
391 };
392
393 modal.text_x = x;
395 modal.text_y = y;
396 modal.texttype = Some(layer_datatype);
397 modal.textlayer = Some(layer_index);
398 if write_text_reference {
399 modal.text_string = Some(text_string.clone());
400 }
401 Ok(())
402}
403
404pub fn write_layout<W: Write, L: LayoutBase<Coord = SInt>>(
407 writer: &mut W,
408 layout: &L,
409 conf: &OASISWriterConfig,
410) -> Result<(), OASISWriteError> {
411 trace!("Write layout to OASIS");
412
413 let mut modal = Modal::default();
415
416 write_magic(writer)?;
417 write_unsigned_integer(writer, 1)?;
419 write_ascii_string(writer, "1.0".as_bytes())?;
421
422 if layout.dbu().is_zero() {
424 return Err(OASISWriteError::DbuIsZero);
425 }
426 let resolution = Real::PositiveWholeNumber(layout.dbu() as u32);
427 write_real(writer, resolution)?;
428
429 let offset_flag = if conf.table_offsets_at_start { 0 } else { 1 };
431 write_unsigned_integer(writer, offset_flag)?;
432 if conf.table_offsets_at_start {
433 write_offset_table(writer, &OffsetTable::default())?; }
436
437 let mut _cellname_id_counter = 0..;
440 let mut _textstrings_id_counter = 0..;
441 let mut _propname_id_counter = 0..;
442 let mut _propstrings_id_counter = 0..;
443
444 for cell in layout.each_cell() {
446 let cell_name_raw = layout.cell_name(&cell);
447 let cell_name: &str = cell_name_raw.borrow();
448 trace!("write cell '{:?}'", cell_name);
449
450 write_unsigned_integer(writer, 14)?;
453 write_name_string(writer, cell_name.as_bytes())?;
454
455 modal.reset();
456
457 for layer_id in layout.each_layer() {
459 trace!("write shapes on layer '{:?}'", layer_id);
460 let layer_info = layout.layer_info(&layer_id);
461 let layer_index = layer_info.index;
462 let layer_datatype = layer_info.datatype;
463
464 let mut shapes = Vec::new();
467 layout.for_each_shape(&cell, &layer_id, |_id, geo| shapes.push(geo.clone()));
468
469 for geometry in &shapes {
470 match geometry {
471 Geometry::Rect(r) => {
472 write_rect(writer, &mut modal, r, layer_index, layer_datatype)?
473 }
474 Geometry::SimplePolygon(p) => {
475 write_simple_polygon(writer, &mut modal, p, layer_index, layer_datatype)?
476 }
477 Geometry::SimpleRPolygon(p) =>
478 {
480 write_simple_polygon(
481 writer,
482 &mut modal,
483 &p.to_simple_polygon(),
484 layer_index,
485 layer_datatype,
486 )?
487 }
488 Geometry::Polygon(p) => {
489 if !p.interiors.is_empty() {
490 unimplemented!("Polygons with holes are not supported yet.");
492 }
493 write_simple_polygon(
494 writer,
495 &mut modal,
496 &p.exterior,
497 layer_index,
498 layer_datatype,
499 )?;
500 }
501 Geometry::Path(p) => {
502 write_path(writer, &mut modal, p, layer_index, layer_datatype)?
503 }
504 Geometry::Text(text) => {
505 write_text(writer, &mut modal, text, layer_index, layer_datatype)?
506 }
507 Geometry::Edge(_) => {
508 }
510 Geometry::Point(_) => {
511 }
513 }
514 }
515 }
516
517 for inst in layout.each_cell_instance(&cell) {
519 let placement_cell = layout.template_cell(&inst);
521
522 let tf = layout.get_transform(&inst);
523
524 if tf.magnification == 1 {
525 write_unsigned_integer(writer, 17)?; let (x, y) = tf.displacement.into();
528
529 let aa = match tf.rotation {
531 Angle::R0 => 0,
532 Angle::R90 => 1,
533 Angle::R180 => 2,
534 Angle::R270 => 3,
535 };
536
537 let is_explicit_reference = modal.placement_cell.as_ref() != Some(&placement_cell);
540 let is_cell_ref_present = false; let is_flip = tf.mirror; let write_x = modal.placement_x != x; let write_y = modal.placement_y != y; let write_repetition = false; let placement_info_byte = bit(0, is_flip)
550 | (aa << 1)
551 | bit(3, write_repetition)
552 | bit(4, write_y)
553 | bit(5, write_x)
554 | bit(6, is_cell_ref_present)
555 | bit(7, is_explicit_reference);
556
557 write_byte(writer, placement_info_byte as u8)?;
558
559 if is_explicit_reference {
560 if is_cell_ref_present {
561 unimplemented!();
563 } else {
564 let n = layout.cell_name(&placement_cell);
567 let name: &str = n.borrow();
568 write_name_string(writer, name.as_bytes())?;
569 }
570 }
571
572 if write_x {
573 write_signed_integer(writer, x)?
574 };
575 if write_y {
576 write_signed_integer(writer, y)?
577 };
578 if write_repetition {
579 modal.repetition = None;
580 unimplemented!();
581 };
582
583 modal.placement_cell = Some(placement_cell);
584 modal.placement_x = x;
585 modal.placement_y = y;
586 } else {
587 unimplemented!("Magnifications other than 1 are not supported yet.");
588 }
589 }
590 }
591
592 let mut end_record_buf = Vec::new();
594 write_unsigned_integer(&mut end_record_buf, 2)?; if !conf.table_offsets_at_start {
597 write_offset_table(&mut end_record_buf, &OffsetTable::default())?;
599 }
600
601 let padding_length = 256 - end_record_buf.len() - 1 - 1 - 2;
607 writer.write_all(end_record_buf.as_slice())?;
608 write_byte_string(writer, vec![0u8; padding_length].as_slice())?;
609
610 let validation_scheme = match conf.validation_scheme {
613 OASISValidationScheme::None => 0,
614 };
615 write_unsigned_integer(writer, validation_scheme)?;
616
617 match conf.validation_scheme {
619 OASISValidationScheme::None => {
620 write_unsigned_integer(writer, 0)?;
621 }
622 };
623
624 writer.flush()?;
626
627 Ok(())
628}