1use crate::conv::Context;
2use crate::conv::utils::get_component;
3use crate::ir::{
4 Component, Expression, IrResult, Op, Shape, ShapeRef, Signature, VarIndex, VarPath, VarSelect,
5 VarSelectOp,
6};
7use crate::ir_error;
8use crate::literal::TypeLiteral;
9use crate::symbol::ClockDomain;
10use crate::symbol::{Direction, SymbolId};
11use crate::value::Value;
12use std::fmt;
13use veryl_parser::resource_table::StrId;
14use veryl_parser::token_range::TokenRange;
15
16#[derive(Clone, Default, Debug)]
17pub struct PartSelect {
18 pub pos: usize,
19 pub r#type: Type,
20}
21
22impl fmt::Display for PartSelect {
23 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
24 format!("{}: {}", self.pos, self.r#type).fmt(f)
25 }
26}
27
28#[derive(Clone, Debug)]
29pub struct PartSelectPath {
30 pub base: Type,
31 pub path: VarPath,
32 pub part_select: Vec<PartSelect>,
33}
34
35impl PartSelectPath {
36 pub fn to_base_select(&self, context: &mut Context, select: &VarSelect) -> Option<VarSelect> {
37 let mut pos_width: Option<(Expression, usize, Option<usize>)> = None;
38
39 let range_select = if let Some((op, end)) = &select.1 {
40 let (beg, end) = op.eval_expr(select.0.last().unwrap(), end);
41 Some((beg, end))
42 } else {
43 None
44 };
45
46 let mut select = select.0.as_slice();
47 if range_select.is_some() {
48 select = &select[0..select.len() - 1];
49 }
50
51 let token = TokenRange::default();
52 let comptime = Box::new(Comptime::create_unknown(token));
53
54 let base_select = [PartSelect {
55 pos: 0,
56 r#type: self.base.clone(),
57 }];
58 let part_select = itertools::chain(&base_select, self.part_select.iter());
59 let len = self.part_select.len() + 1;
60
61 for (i, x) in part_select.enumerate() {
62 let has_sub_part = i != (len - 1);
63 let dims = x.r#type.width.dims();
64 let select_dims = select.len().min(dims);
65 let remaining_dims = dims - select_dims;
66 let is_select = !select.is_empty();
67
68 if has_sub_part && dims > select.len() {
70 return None;
71 }
72
73 let index = if is_select {
74 let sel = &select[0..select_dims];
75 select = &select[select_dims..];
76
77 if remaining_dims != 0 {
80 let mut sel = sel.to_vec();
81 for _ in 0..remaining_dims {
82 sel.push(Expression::create_value(Value::new(0, 32, false), token));
83 }
84 x.r#type.width.calc_index_expr(&sel)?
85 } else {
86 x.r#type.width.calc_index_expr(sel)?
87 }
88 } else {
89 Expression::create_value(Value::new(0, 32, false), TokenRange::default())
90 };
91
92 let remaining_width = x.r#type.width.as_shape_ref();
93 let remaining_width = ShapeRef::new(&remaining_width[select_dims..]);
94
95 let width = if is_select {
96 let mut r#type = x.r#type.clone();
97 r#type.set_concrete_width(remaining_width.to_owned());
98 r#type.total_width()?
99 } else {
100 x.r#type.total_width()?
101 };
102
103 let range_width = if let Some(x) = remaining_width.first() {
104 let x = (*x)?;
105 Some(width / x)
106 } else {
107 None
108 };
109
110 let x_pos = Expression::create_value(Value::new(x.pos as u64, 32, false), token);
112
113 let expr = if remaining_dims != 0 {
114 Expression::Binary(Box::new(x_pos), Op::Add, Box::new(index), comptime.clone())
116 } else {
117 let expr = Expression::create_value(Value::new(width as u64, 32, false), token);
118 let expr =
119 Expression::Binary(Box::new(expr), Op::Mul, Box::new(index), comptime.clone());
120 Expression::Binary(Box::new(x_pos), Op::Add, Box::new(expr), comptime.clone())
121 };
122
123 if let Some((pos, _, _)) = pos_width {
124 let expr =
125 Expression::Binary(Box::new(pos), Op::Add, Box::new(expr), comptime.clone());
126 pos_width = Some((expr, width, range_width));
127 } else {
128 pos_width = Some((expr, width, range_width));
129 }
130 }
131
132 if let Some((pos, width, range_width)) = pos_width {
133 let single = width == 1;
134 let width = Expression::create_value(Value::new(width as u64, 32, false), token);
135
136 let one = Expression::create_value(Value::new(1, 32, false), token);
139 let minus_one = Expression::Unary(Op::Sub, Box::new(one.clone()), comptime.clone());
140 let expr = Expression::Binary(
141 Box::new(pos.clone()),
142 Op::Add,
143 Box::new(width.clone()),
144 comptime.clone(),
145 );
146 let expr = Expression::Binary(
147 Box::new(expr),
148 Op::Add,
149 Box::new(minus_one.clone()),
150 comptime.clone(),
151 );
152 let mut beg = expr;
153 let mut end = pos;
154
155 if let Some((range_beg, range_end)) = range_select {
158 let range_width =
159 Expression::create_value(Value::new(range_width? as u64, 32, false), token);
160
161 let expr = Expression::Binary(
162 Box::new(range_beg),
163 Op::Add,
164 Box::new(one.clone()),
165 comptime.clone(),
166 );
167 let expr = Expression::Binary(
168 Box::new(expr),
169 Op::Mul,
170 Box::new(range_width.clone()),
171 comptime.clone(),
172 );
173 let expr = Expression::Binary(
174 Box::new(expr),
175 Op::Add,
176 Box::new(minus_one),
177 comptime.clone(),
178 );
179 beg = Expression::Binary(
180 Box::new(end.clone()),
181 Op::Add,
182 Box::new(expr),
183 comptime.clone(),
184 );
185
186 let expr = Expression::Binary(
187 Box::new(range_end),
188 Op::Mul,
189 Box::new(range_width),
190 comptime.clone(),
191 );
192 end = Expression::Binary(Box::new(end), Op::Add, Box::new(expr), comptime);
193 }
194
195 beg.eval_comptime(context, None);
196 end.eval_comptime(context, None);
197
198 if single {
199 Some(VarSelect(vec![beg], None))
200 } else {
201 Some(VarSelect(vec![beg], Some((VarSelectOp::Colon, end))))
202 }
203 } else {
204 None
205 }
206 }
207}
208
209impl fmt::Display for PartSelectPath {
210 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
211 let mut ret = format!("{}: ", self.path);
212
213 for x in &self.part_select {
214 ret.push_str(&format!("[{x}]"));
215 }
216
217 ret.fmt(f)
218 }
219}
220
221#[derive(Copy, Clone, Default, Debug)]
222pub struct ExpressionContext {
223 pub width: usize,
224 pub signed: bool,
225 pub is_const: bool,
226 pub is_global: bool,
227}
228
229impl ExpressionContext {
230 pub fn merge(&self, other: ExpressionContext) -> ExpressionContext {
231 ExpressionContext {
232 width: self.width.max(other.width),
233 signed: self.signed & other.signed,
234 is_const: self.is_const & other.is_const,
235 is_global: self.is_global & other.is_global,
236 }
237 }
238}
239
240#[derive(Clone, Default, Debug)]
241pub struct Comptime {
242 pub value: ValueVariant,
243 pub r#type: Type,
244 pub is_const: bool,
245 pub is_global: bool,
246 pub part_select: Option<PartSelectPath>,
247 pub clock_domain: ClockDomain,
248 pub expr_context: ExpressionContext,
249 pub evaluated: bool,
250 pub token: TokenRange,
251}
252
253impl Comptime {
254 pub fn create_unknown(token: TokenRange) -> Self {
255 Self {
256 value: ValueVariant::Unknown,
257 r#type: Type {
258 kind: TypeKind::Unknown,
259 ..Default::default()
260 },
261 token,
262 ..Default::default()
263 }
264 }
265
266 pub fn create_value(value: Value, token: TokenRange) -> Self {
267 let width = value.width();
268 Self {
269 value: ValueVariant::Numeric(value),
270 r#type: Type {
271 kind: TypeKind::Bit,
272 width: Shape::new(vec![Some(width)]),
273 ..Default::default()
274 },
275 is_const: true,
276 is_global: true,
277 token,
278 ..Default::default()
279 }
280 }
281
282 pub fn from_type(r#type: Type, clock_domain: ClockDomain, token: TokenRange) -> Self {
283 Self {
284 r#type,
285 clock_domain,
286 token,
287 ..Default::default()
288 }
289 }
290
291 pub fn get_value(&self) -> IrResult<&Value> {
292 if let ValueVariant::Numeric(x) = &self.value {
293 Ok(x)
294 } else {
295 Err(ir_error!(self.token))
296 }
297 }
298}
299
300#[derive(Clone, Default, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
301pub enum ValueVariant {
302 Numeric(Value),
303 NumericArray(Vec<Value>),
304 Type(Type),
305 #[default]
306 Unknown,
307}
308
309impl ValueVariant {
310 pub fn expand_value(&mut self, width: usize) {
311 if let ValueVariant::Numeric(x) = self {
312 x.expand(width, false);
313 }
314 }
315
316 pub fn is_unknown(&self) -> bool {
317 matches!(self, ValueVariant::Unknown)
318 }
319}
320
321#[derive(Clone, Default, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
322pub struct Type {
323 pub kind: TypeKind,
324 pub signed: bool,
325 pub is_positive: bool,
326 pub array: Shape,
327 width: Shape,
328 width_expr: Vec<crate::ir::WidthExpr>,
329}
330
331impl Type {
332 pub fn width(&self) -> &Shape {
333 &self.width
334 }
335
336 pub fn width_mut(&mut self) -> &mut Shape {
337 &mut self.width
338 }
339
340 pub fn width_expr(&self) -> &[crate::ir::WidthExpr] {
341 &self.width_expr
342 }
343
344 pub fn new(kind: TypeKind) -> Type {
345 Type {
346 kind,
347 ..Default::default()
348 }
349 }
350
351 pub fn create_unknown() -> Type {
352 Type {
353 kind: TypeKind::Unknown,
354 ..Default::default()
355 }
356 }
357
358 pub fn set_concrete_width(&mut self, shape: Shape) {
359 self.width_expr = crate::ir::WidthExpr::from_shape(&shape);
360 self.width = shape;
361 }
362
363 pub fn set_parametric_width(&mut self, shape: Shape, width_expr: Vec<crate::ir::WidthExpr>) {
364 debug_assert_eq!(
365 shape.as_slice().len(),
366 width_expr.len(),
367 "shape and width_expr length mismatch"
368 );
369 self.width = shape;
370 self.width_expr = width_expr;
371 }
372
373 pub fn clear_width(&mut self) {
374 self.width = Shape::default();
375 self.width_expr.clear();
376 }
377
378 pub fn to_sv_type_name(&self) -> Option<&'static str> {
379 match &self.kind {
380 TypeKind::Bit => Some("bit"),
381 TypeKind::Logic => Some("logic"),
382 TypeKind::F32 => Some("shortreal"),
383 TypeKind::F64 => Some("real"),
384 TypeKind::String => Some("string"),
385 TypeKind::Clock | TypeKind::ClockPosedge | TypeKind::ClockNegedge => Some("logic"),
386 TypeKind::Reset
387 | TypeKind::ResetAsyncHigh
388 | TypeKind::ResetAsyncLow
389 | TypeKind::ResetSyncHigh
390 | TypeKind::ResetSyncLow => Some("logic"),
391 _ => None,
392 }
393 }
394
395 pub fn to_sv_width(&self) -> String {
396 if self.width_expr.is_empty() {
397 return String::new();
398 }
399 let mut s = String::new();
400 for dim in &self.width_expr {
401 s.push_str(&dim.to_sv_width_string());
402 }
403 s
404 }
405
406 pub fn is_4state(&self) -> bool {
407 match &self.kind {
408 TypeKind::Struct(x) => x.is_4state(),
409 TypeKind::Union(x) => x.is_4state(),
410 TypeKind::Enum(x) => x.is_4state(),
411 _ => matches!(self.kind, TypeKind::Logic) | self.is_clock() | self.is_reset(),
412 }
413 }
414
415 pub fn is_2state(&self) -> bool {
416 match &self.kind {
417 TypeKind::Struct(x) => x.is_2state(),
418 TypeKind::Union(x) => x.is_2state(),
419 TypeKind::Enum(x) => x.is_2state(),
420 _ => {
421 matches!(self.kind, TypeKind::Bit | TypeKind::F32 | TypeKind::F64)
422 }
423 }
424 }
425
426 pub fn is_clock(&self) -> bool {
427 matches!(
428 self.kind,
429 TypeKind::Clock | TypeKind::ClockPosedge | TypeKind::ClockNegedge
430 )
431 }
432
433 pub fn is_reset(&self) -> bool {
434 matches!(
435 self.kind,
436 TypeKind::Reset
437 | TypeKind::ResetAsyncHigh
438 | TypeKind::ResetAsyncLow
439 | TypeKind::ResetSyncHigh
440 | TypeKind::ResetSyncLow
441 )
442 }
443
444 pub fn is_explicit_reset(&self) -> bool {
445 matches!(
446 self.kind,
447 TypeKind::ResetAsyncHigh
448 | TypeKind::ResetAsyncLow
449 | TypeKind::ResetSyncHigh
450 | TypeKind::ResetSyncLow
451 )
452 }
453
454 pub fn is_type(&self) -> bool {
455 matches!(self.kind, TypeKind::Type)
456 }
457
458 pub fn is_unknown(&self) -> bool {
459 matches!(self.kind, TypeKind::Unknown)
460 }
461
462 pub fn is_array(&self) -> bool {
463 !self.array.is_empty()
464 }
465
466 pub fn is_binary(&self) -> bool {
467 self.total_width() == Some(1)
468 }
469
470 pub fn is_struct(&self) -> bool {
471 matches!(&self.kind, TypeKind::Struct(_))
472 }
473
474 pub fn is_union(&self) -> bool {
475 matches!(&self.kind, TypeKind::Union(_))
476 }
477
478 pub fn is_struct_union(&self) -> bool {
479 matches!(&self.kind, TypeKind::Struct(_) | TypeKind::Union(_))
480 }
481
482 pub fn is_interface(&self) -> bool {
483 match &self.kind {
484 TypeKind::Instance(_, kind) => *kind == InstanceKind::Interface,
485 TypeKind::Modport(_, _) | TypeKind::AbstractInterface(_) => true,
486 _ => false,
487 }
488 }
489
490 pub fn is_interface_instance(&self) -> bool {
491 match &self.kind {
492 TypeKind::Instance(_, kind) => *kind == InstanceKind::Interface,
493 _ => false,
494 }
495 }
496
497 pub fn is_string(&self) -> bool {
498 matches!(&self.kind, TypeKind::String)
499 }
500
501 pub fn is_systemverilog(&self) -> bool {
502 matches!(&self.kind, TypeKind::SystemVerilog)
503 }
504
505 pub fn get_member_type(&self, name: StrId) -> Option<Type> {
506 if let TypeKind::Struct(x) = &self.kind {
507 for x in &x.members {
508 if x.name == name {
509 return Some(x.r#type.clone());
510 }
511 }
512 }
513 None
514 }
515
516 pub fn is_inferable_width(&self) -> bool {
517 self.width.dims() == 1 && self.width.last().unwrap().is_none()
518 }
519
520 pub fn total_width(&self) -> Option<usize> {
521 Some(self.kind.width()? * self.width.total()?)
522 }
523
524 pub fn total_array(&self) -> Option<usize> {
525 self.array.total()
526 }
527
528 pub fn compatible(&self, src: &Comptime) -> bool {
529 if self.is_unknown()
531 | self.is_systemverilog()
532 | src.r#type.is_unknown()
533 | src.r#type.is_systemverilog()
534 {
535 true
536 } else if let Some(mut dst_sig) = self.kind.signature() {
537 dst_sig.parameters.clear();
538 if let Some(mut src_sig) = src.r#type.kind.signature() {
539 src_sig.parameters.clear();
540 dst_sig.to_string() == src_sig.to_string()
541 } else {
542 false
543 }
544 } else if self.is_type() || src.r#type.is_type() {
545 self.is_type() && src.r#type.is_type()
546 } else if self.is_2state() {
547 src.r#type.is_2state()
548 } else if self.is_array() || src.r#type.is_array() {
549 array_compatible(&self.array, &src.r#type.array)
550 } else if self.is_clock() {
551 src.r#type.is_clock() || src.is_const
552 } else if self.is_reset() {
553 !src.r#type.is_clock() || src.is_const
554 } else {
555 true
557 }
558 }
559
560 pub fn expand_struct_union(
561 &self,
562 path: &VarPath,
563 part_select: &[PartSelect],
564 base: Option<&Type>,
565 ) -> Vec<PartSelectPath> {
566 let base = if base.is_some() { base } else { Some(self) };
567 match &self.kind {
568 TypeKind::Struct(x) => x.expand_struct_union(path, part_select, base),
569 TypeKind::Union(x) => x.expand_struct_union(path, part_select, base),
570 _ => vec![],
571 }
572 }
573
574 pub fn expand_interface(
575 &self,
576 context: &mut Context,
577 path: &VarPath,
578 token: TokenRange,
579 ) -> IrResult<Vec<(VarPath, Type)>> {
580 let mut ret = vec![];
581 match &self.kind {
582 TypeKind::Modport(sig, name) => {
583 let component = get_component(context, sig, token)?;
584 let Component::Interface(component) = component.as_ref() else {
585 unreachable!();
586 };
587
588 let modport_members = component.get_modport(name);
589
590 let mut temp = vec![];
591 for (id, variable) in &component.variables {
592 if modport_members.contains_key(&variable.path.first()) {
593 let mut member_path = variable.path.clone();
594 member_path.add_prelude(&path.0);
595 temp.push((id, member_path, variable.r#type.clone()));
596 }
597 }
598 temp.sort_by_key(|x| x.0);
599 ret = temp.into_iter().map(|x| (x.1, x.2)).collect();
600 }
601 TypeKind::Instance(sig, kind) if *kind == InstanceKind::Interface => {
602 let component = get_component(context, sig, token)?;
603 let Component::Interface(component) = component.as_ref() else {
604 unreachable!();
605 };
606 let mut temp = vec![];
607 for (id, variable) in &component.variables {
608 let mut member_path = variable.path.clone();
609 member_path.add_prelude(&path.0);
610 temp.push((id, member_path, variable.r#type.clone()));
611 }
612 temp.sort_by_key(|x| x.0);
613 ret = temp.into_iter().map(|x| (x.1, x.2)).collect();
614 }
615 _ => (),
616 }
617 Ok(ret)
618 }
619
620 pub fn expand_modport(
621 &self,
622 context: &mut Context,
623 path: &VarPath,
624 token: TokenRange,
625 ) -> IrResult<Vec<(VarPath, Direction)>> {
626 let mut ret = vec![];
627 if let TypeKind::Modport(sig, name) = &self.kind {
628 let component = get_component(context, sig, token)?;
629 let Component::Interface(component) = component.as_ref() else {
630 unreachable!();
631 };
632
633 let modport_members = component.get_modport(name);
634
635 let mut temp = vec![];
636 for (id, variable) in &component.variables {
637 if let Some(x) = modport_members.get(&variable.path.first()) {
638 let mut member_path = variable.path.clone();
639 member_path.add_prelude(&path.0);
640 temp.push((id, member_path, *x));
641 }
642 }
643 temp.sort_by_key(|x| x.0);
644 ret = temp.into_iter().map(|x| (x.1, x.2)).collect();
645 }
646 Ok(ret)
647 }
648
649 pub fn flatten_struct_union_enum(&mut self) {
650 match self.kind.clone() {
651 TypeKind::Struct(_) => {
652 let width = self.total_width();
653 self.kind = if self.is_2state() {
654 TypeKind::Bit
655 } else {
656 TypeKind::Logic
657 };
658 self.signed = false;
659 self.set_concrete_width(Shape::new(vec![width]));
660 }
661 TypeKind::Union(_) => {
662 let width = self.total_width();
663 self.kind = if self.is_2state() {
664 TypeKind::Bit
665 } else {
666 TypeKind::Logic
667 };
668 self.signed = false;
669 self.set_concrete_width(Shape::new(vec![width]));
670 }
671 TypeKind::Enum(x) => {
672 self.kind = x.r#type.kind;
673 self.signed = x.r#type.signed;
674 let mut array = x.r#type.array;
675 let mut width = x.r#type.width;
676 array.append(&mut self.array);
677 width.append(&mut self.width);
678 self.array = array;
679 self.set_concrete_width(width);
680 }
681 _ => (),
682 }
683 }
684
685 pub fn prepend_array(&mut self, array: &ShapeRef) {
686 if !array.is_empty() {
687 let mut array = array.to_owned();
688 array.append(&mut self.array);
689 self.array = array;
690 }
691 }
692
693 pub fn selected_dimension(&self, index: &VarIndex, select: &VarSelect) -> (usize, usize) {
694 let array_dim = self.array.dims();
695 let width_dim = self.width.dims();
696
697 let array_dim = array_dim.saturating_sub(index.dimension());
698 let width_dim = width_dim.saturating_sub(select.dimension());
699
700 if self.total_width() == Some(1) {
701 (array_dim, 0)
702 } else {
703 (array_dim, width_dim)
704 }
705 }
706}
707
708fn array_compatible(a: &Shape, b: &Shape) -> bool {
711 a.dims() == b.dims()
712 && a.iter().zip(b.iter()).all(|(x, y)| match (x, y) {
713 (None, _) | (_, None) => true,
714 (Some(x), Some(y)) => x == y,
715 })
716}
717
718impl From<&TypeLiteral> for Type {
719 fn from(value: &TypeLiteral) -> Self {
720 let kind = match value {
721 TypeLiteral::Bit => TypeKind::Bit,
722 TypeLiteral::BBool => TypeKind::Bit,
723 TypeLiteral::LBool => TypeKind::Logic,
724 TypeLiteral::Clock => TypeKind::Clock,
725 TypeLiteral::ClockPosedge => TypeKind::ClockPosedge,
726 TypeLiteral::ClockNegedge => TypeKind::ClockNegedge,
727 TypeLiteral::F32 => TypeKind::F32,
728 TypeLiteral::F64 => TypeKind::F64,
729 TypeLiteral::I8 => TypeKind::Bit,
730 TypeLiteral::I16 => TypeKind::Bit,
731 TypeLiteral::I32 => TypeKind::Bit,
732 TypeLiteral::I64 => TypeKind::Bit,
733 TypeLiteral::Logic => TypeKind::Logic,
734 TypeLiteral::Reset => TypeKind::Reset,
735 TypeLiteral::ResetAsyncHigh => TypeKind::ResetAsyncHigh,
736 TypeLiteral::ResetAsyncLow => TypeKind::ResetAsyncLow,
737 TypeLiteral::ResetSyncHigh => TypeKind::ResetSyncHigh,
738 TypeLiteral::ResetSyncLow => TypeKind::ResetSyncLow,
739 TypeLiteral::String => TypeKind::Unknown,
740 TypeLiteral::U8 => TypeKind::Bit,
741 TypeLiteral::U16 => TypeKind::Bit,
742 TypeLiteral::U32 => TypeKind::Bit,
743 TypeLiteral::U64 => TypeKind::Bit,
744 };
745
746 let signed = matches!(
747 value,
748 TypeLiteral::F32
749 | TypeLiteral::F64
750 | TypeLiteral::I8
751 | TypeLiteral::I16
752 | TypeLiteral::I32
753 | TypeLiteral::I64
754 );
755
756 let width = match value {
757 TypeLiteral::Bit
758 | TypeLiteral::BBool
759 | TypeLiteral::LBool
760 | TypeLiteral::Clock
761 | TypeLiteral::ClockPosedge
762 | TypeLiteral::ClockNegedge
763 | TypeLiteral::Logic
764 | TypeLiteral::Reset
765 | TypeLiteral::ResetAsyncHigh
766 | TypeLiteral::ResetAsyncLow
767 | TypeLiteral::ResetSyncHigh
768 | TypeLiteral::ResetSyncLow
769 | TypeLiteral::String => Shape::new(vec![Some(1)]),
770 TypeLiteral::F32 => Shape::new(vec![Some(32)]),
771 TypeLiteral::F64 => Shape::new(vec![Some(64)]),
772 TypeLiteral::I8 => Shape::new(vec![Some(8)]),
773 TypeLiteral::I16 => Shape::new(vec![Some(16)]),
774 TypeLiteral::I32 => Shape::new(vec![Some(32)]),
775 TypeLiteral::I64 => Shape::new(vec![Some(64)]),
776 TypeLiteral::U8 => Shape::new(vec![Some(8)]),
777 TypeLiteral::U16 => Shape::new(vec![Some(16)]),
778 TypeLiteral::U32 => Shape::new(vec![Some(32)]),
779 TypeLiteral::U64 => Shape::new(vec![Some(64)]),
780 };
781
782 Type {
783 kind,
784 signed,
785 width,
786 ..Default::default()
787 }
788 }
789}
790
791impl fmt::Display for Type {
792 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
793 let mut ret = if self.signed {
794 "signed ".to_string()
795 } else {
796 String::new()
797 };
798 ret.push_str(&self.kind.to_string());
799
800 if !self.width.is_empty() {
801 ret.push_str(&format!("<{}>", self.width));
802 }
803
804 if !self.array.is_empty() {
805 ret.push_str(&format!("[{}]", self.array));
806 }
807
808 ret.fmt(f)
809 }
810}
811
812#[derive(Clone, Default, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
813pub enum InstanceKind {
814 #[default]
815 Module,
816 Interface,
817 SystemVerilog,
818}
819
820#[derive(Clone, Default, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
821pub enum TypeKind {
822 Clock,
823 ClockPosedge,
824 ClockNegedge,
825 Reset,
826 ResetAsyncHigh,
827 ResetAsyncLow,
828 ResetSyncHigh,
829 ResetSyncLow,
830 Bit,
831 F32,
832 F64,
833 Logic,
834 Struct(TypeKindStruct),
835 Union(TypeKindUnion),
836 Enum(TypeKindEnum),
837 Module(Signature),
838 Interface(Signature),
839 Modport(Signature, StrId),
840 Package(Signature),
841 Instance(Signature, InstanceKind),
842 AbstractInterface(Option<StrId>),
843 Type,
844 String,
845 SystemVerilog,
846 Void,
847 #[default]
848 Unknown,
849}
850
851impl TypeKind {
852 pub fn width(&self) -> Option<usize> {
853 match self {
854 TypeKind::Clock
855 | TypeKind::ClockPosedge
856 | TypeKind::ClockNegedge
857 | TypeKind::Reset
858 | TypeKind::ResetAsyncHigh
859 | TypeKind::ResetAsyncLow
860 | TypeKind::ResetSyncHigh
861 | TypeKind::ResetSyncLow
862 | TypeKind::Bit
863 | TypeKind::F32
864 | TypeKind::F64
865 | TypeKind::Logic
866 | TypeKind::Type
867 | TypeKind::String
868 | TypeKind::Unknown
869 | TypeKind::SystemVerilog
870 | TypeKind::Module(_)
871 | TypeKind::Interface(_)
872 | TypeKind::Modport(_, _)
873 | TypeKind::Package(_)
874 | TypeKind::Instance(_, _)
875 | TypeKind::AbstractInterface(_) => Some(1),
876 TypeKind::Union(x) => x.width(),
877 TypeKind::Struct(x) => x.width(),
878 TypeKind::Enum(x) => x.width(),
879 TypeKind::Void => None,
880 }
881 }
882
883 pub fn is_float(&self) -> bool {
884 matches!(self, TypeKind::F32 | TypeKind::F64)
885 }
886
887 pub fn signature(&self) -> Option<Signature> {
888 match self {
889 TypeKind::Module(x)
890 | TypeKind::Interface(x)
891 | TypeKind::Package(x)
892 | TypeKind::Instance(x, _) => Some(x.clone()),
893 TypeKind::Modport(x, _) => Some(x.clone()),
894 _ => None,
895 }
896 }
897}
898
899impl fmt::Display for TypeKind {
900 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
901 match self {
902 TypeKind::Clock => "clock".fmt(f),
903 TypeKind::ClockPosedge => "clock_posedge".fmt(f),
904 TypeKind::ClockNegedge => "clock_negedge".fmt(f),
905 TypeKind::Reset => "reset".fmt(f),
906 TypeKind::ResetAsyncHigh => "reset_async_high".fmt(f),
907 TypeKind::ResetAsyncLow => "reset_async_low".fmt(f),
908 TypeKind::ResetSyncHigh => "reset_sync_high".fmt(f),
909 TypeKind::ResetSyncLow => "reset_sync_low".fmt(f),
910 TypeKind::Bit => "bit".fmt(f),
911 TypeKind::F32 => "f32".fmt(f),
912 TypeKind::F64 => "f64".fmt(f),
913 TypeKind::Logic => "logic".fmt(f),
914 TypeKind::Struct(x) => x.fmt(f),
915 TypeKind::Union(x) => x.fmt(f),
916 TypeKind::Enum(x) => x.fmt(f),
917 TypeKind::Module(x) => format!("module {x}").fmt(f),
918 TypeKind::Interface(x) => format!("interface {x}").fmt(f),
919 TypeKind::Modport(x, _) => format!("modport {x}").fmt(f),
920 TypeKind::Package(x) => format!("package {x}").fmt(f),
921 TypeKind::Instance(x, _) => format!("instance {x}").fmt(f),
922 TypeKind::AbstractInterface(x) => {
923 if let Some(x) = x {
924 format!("interface::{x}").fmt(f)
925 } else {
926 "interface".fmt(f)
927 }
928 }
929 TypeKind::Type => "type".fmt(f),
930 TypeKind::String => "string".fmt(f),
931 TypeKind::SystemVerilog => "systemverilog".fmt(f),
932 TypeKind::Unknown => "unknown".fmt(f),
933 TypeKind::Void => "void".fmt(f),
934 }
935 }
936}
937
938#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
939pub struct TypeKindStruct {
940 pub id: SymbolId,
941 pub members: Vec<TypeKindMember>,
942}
943
944impl TypeKindStruct {
945 pub fn is_4state(&self) -> bool {
946 self.members.iter().any(|x| x.r#type.is_4state())
947 }
948
949 pub fn is_2state(&self) -> bool {
950 self.members.iter().all(|x| x.r#type.is_2state())
951 }
952
953 pub fn width(&self) -> Option<usize> {
954 let mut ret = 0;
955 for x in &self.members {
956 ret += x.width()?;
957 }
958 Some(ret)
959 }
960
961 pub fn expand_struct_union(
962 &self,
963 path: &VarPath,
964 part_select: &[PartSelect],
965 base: Option<&Type>,
966 ) -> Vec<PartSelectPath> {
967 let mut ret = vec![];
968 let mut offset = 0;
969 for x in self.members.iter().rev() {
970 let width = x.width().unwrap_or(1);
971 let x = x.expand_struct_union(path, part_select, base);
972 for mut x in x.into_iter().rev() {
973 if let Some(x) = x.part_select.get_mut(part_select.len()) {
974 x.pos += offset;
975 }
976 ret.push(x);
977 }
978 offset += width;
979 }
980 ret.reverse();
981 ret
982 }
983}
984
985impl fmt::Display for TypeKindStruct {
986 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
987 let mut text = String::new();
988 for x in &self.members {
989 text.push_str(&format!(", {x}"));
990 }
991 let text = if text.is_empty() { &text } else { &text[2..] };
992
993 format!("struct {{{}}}", text).fmt(f)
994 }
995}
996
997#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
998pub struct TypeKindUnion {
999 pub id: SymbolId,
1000 pub members: Vec<TypeKindMember>,
1001}
1002
1003impl TypeKindUnion {
1004 pub fn is_4state(&self) -> bool {
1005 self.members.iter().any(|x| x.r#type.is_4state())
1006 }
1007
1008 pub fn is_2state(&self) -> bool {
1009 self.members.iter().all(|x| x.r#type.is_2state())
1010 }
1011
1012 pub fn width(&self) -> Option<usize> {
1013 self.members.first()?.width()
1014 }
1015
1016 pub fn expand_struct_union(
1017 &self,
1018 path: &VarPath,
1019 part_select: &[PartSelect],
1020 base: Option<&Type>,
1021 ) -> Vec<PartSelectPath> {
1022 let mut ret = vec![];
1023 for x in &self.members {
1024 ret.append(&mut x.expand_struct_union(path, part_select, base));
1025 }
1026 ret
1027 }
1028
1029 pub fn expand_union(&self, path: &VarPath, array: &ShapeRef) -> Vec<(VarPath, Type)> {
1030 let mut ret = vec![];
1031 for x in &self.members {
1032 ret.append(&mut x.expand_union(path, array));
1033 }
1034 ret
1035 }
1036}
1037
1038impl fmt::Display for TypeKindUnion {
1039 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1040 let mut text = String::new();
1041 for x in &self.members {
1042 text.push_str(&format!(", {x}"));
1043 }
1044 let text = if text.is_empty() { &text } else { &text[2..] };
1045
1046 format!("union {{{}}}", text).fmt(f)
1047 }
1048}
1049
1050#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
1051pub struct TypeKindMember {
1052 pub name: StrId,
1053 pub r#type: Type,
1054}
1055
1056impl TypeKindMember {
1057 pub fn width(&self) -> Option<usize> {
1058 self.r#type.total_width()
1059 }
1060
1061 pub fn expand_struct_union(
1062 &self,
1063 path: &VarPath,
1064 part_select: &[PartSelect],
1065 base: Option<&Type>,
1066 ) -> Vec<PartSelectPath> {
1067 let mut path = path.clone();
1068 path.push(self.name);
1069
1070 let mut part_select = part_select.to_vec();
1071 part_select.push(PartSelect {
1072 pos: 0,
1073 r#type: self.r#type.clone(),
1074 });
1075
1076 let mut ret = self.r#type.expand_struct_union(&path, &part_select, base);
1077
1078 ret.push(PartSelectPath {
1079 base: base.unwrap().clone(),
1080 path: path.clone(),
1081 part_select,
1082 });
1083
1084 ret
1085 }
1086
1087 pub fn expand_union(&self, path: &VarPath, array: &ShapeRef) -> Vec<(VarPath, Type)> {
1088 let mut path = path.clone();
1089 path.push(self.name);
1090 let mut r#type = self.r#type.clone();
1091 r#type.array = array.to_owned();
1092 vec![(path, r#type)]
1093 }
1094}
1095
1096impl fmt::Display for TypeKindMember {
1097 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1098 format!("{}: {}", self.name, self.r#type).fmt(f)
1099 }
1100}
1101
1102#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
1103pub struct TypeKindEnum {
1104 pub id: SymbolId,
1105 pub r#type: Box<Type>,
1106}
1107
1108impl TypeKindEnum {
1109 pub fn is_4state(&self) -> bool {
1110 self.r#type.is_4state()
1111 }
1112
1113 pub fn is_2state(&self) -> bool {
1114 self.r#type.is_2state()
1115 }
1116
1117 pub fn width(&self) -> Option<usize> {
1118 self.r#type.total_width()
1119 }
1120}
1121
1122impl fmt::Display for TypeKindEnum {
1123 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1124 format!("enum {{{}}}", self.r#type).fmt(f)
1125 }
1126}
1127
1128#[cfg(test)]
1129mod tests {
1130 use super::*;
1131 use veryl_parser::resource_table;
1132
1133 fn create_logic(width: usize) -> Type {
1134 let mut t = Type {
1135 kind: TypeKind::Logic,
1136 array: Shape::default(),
1137 signed: false,
1138 is_positive: false,
1139 ..Default::default()
1140 };
1141 t.set_concrete_width(Shape::new(vec![Some(width)]));
1142 t
1143 }
1144
1145 fn create_logic_multi_dim(width: &[Option<usize>]) -> Type {
1146 let mut t = Type {
1147 kind: TypeKind::Logic,
1148 array: Shape::default(),
1149 signed: false,
1150 is_positive: false,
1151 ..Default::default()
1152 };
1153 t.set_concrete_width(Shape::new(width.to_vec()));
1154 t
1155 }
1156
1157 fn create_struct(members: &[(&'static str, Type)], width: usize) -> Type {
1158 let members = members
1159 .into_iter()
1160 .map(|(n, t)| TypeKindMember {
1161 name: resource_table::insert_str(n),
1162 r#type: t.clone(),
1163 })
1164 .collect();
1165 let mut t = Type {
1166 kind: TypeKind::Struct(TypeKindStruct {
1167 id: SymbolId::default(),
1168 members,
1169 }),
1170 array: Shape::default(),
1171 signed: false,
1172 is_positive: false,
1173 ..Default::default()
1174 };
1175 t.set_concrete_width(Shape::new(vec![Some(width)]));
1176 t
1177 }
1178
1179 fn create_union(members: &[(&'static str, Type)], width: usize) -> Type {
1180 let members = members
1181 .into_iter()
1182 .map(|(n, t)| TypeKindMember {
1183 name: resource_table::insert_str(n),
1184 r#type: t.clone(),
1185 })
1186 .collect();
1187 let mut t = Type {
1188 kind: TypeKind::Union(TypeKindUnion {
1189 id: SymbolId::default(),
1190 members,
1191 }),
1192 array: Shape::default(),
1193 signed: false,
1194 is_positive: false,
1195 ..Default::default()
1196 };
1197 t.set_concrete_width(Shape::new(vec![Some(width)]));
1198 t
1199 }
1200
1201 #[track_caller]
1202 fn check(
1203 path: &PartSelectPath,
1204 select: &[usize],
1205 end: Option<usize>,
1206 expect: Option<(usize, usize)>,
1207 ) {
1208 let mut expr = vec![];
1209 let token = TokenRange::default();
1210 for x in select {
1211 expr.push(Expression::create_value(
1212 Value::new(*x as u64, 32, false),
1213 token,
1214 ));
1215 }
1216 let end = if let Some(end) = end {
1217 Some((
1218 VarSelectOp::Colon,
1219 Expression::create_value(Value::new(end as u64, 32, false), token),
1220 ))
1221 } else {
1222 None
1223 };
1224 let select = VarSelect(expr, end);
1225
1226 let mut context = Context::default();
1227 let expr = path.to_base_select(&mut context, &select);
1228 let range = if let Some(expr) = expr {
1229 let r#type = Type::default();
1230 expr.eval_value(&mut context, &r#type, false)
1231 } else {
1232 None
1233 };
1234
1235 assert_eq!(range, expect)
1236 }
1237
1238 #[rustfmt::skip]
1239 #[test]
1240 fn expand_struct() {
1241 let x0 = create_struct(&[("a", create_logic(2)), ("b", create_logic(3))], 4);
1254 let x1 = create_struct(&[("c", create_logic(5)), ("d", create_logic(6))], 7);
1255 let x2 = create_struct(&[("e", x0.clone()), ("f", x1.clone())], 8);
1256
1257 let path = VarPath::new(resource_table::insert_str("x"));
1258
1259 let x0 = x0.expand_struct_union(&path, &[], None);
1260 let x1 = x1.expand_struct_union(&path, &[], None);
1261 let x2 = x2.expand_struct_union(&path, &[], None);
1262
1263 assert_eq!(x0[0].to_string(), "x.a: [3: logic<2>]");
1264 assert_eq!(x0[1].to_string(), "x.b: [0: logic<3>]");
1265 assert_eq!(x1[0].to_string(), "x.c: [6: logic<5>]");
1266 assert_eq!(x1[1].to_string(), "x.d: [0: logic<6>]");
1267 assert_eq!(x2[0].to_string(), "x.e.a: [77: struct {a: logic<2>, b: logic<3>}<4>][3: logic<2>]");
1268 assert_eq!(x2[1].to_string(), "x.e.b: [77: struct {a: logic<2>, b: logic<3>}<4>][0: logic<3>]");
1269 assert_eq!(x2[2].to_string(), "x.e: [77: struct {a: logic<2>, b: logic<3>}<4>]");
1270 assert_eq!(x2[3].to_string(), "x.f.c: [0: struct {c: logic<5>, d: logic<6>}<7>][6: logic<5>]");
1271 assert_eq!(x2[4].to_string(), "x.f.d: [0: struct {c: logic<5>, d: logic<6>}<7>][0: logic<6>]");
1272 assert_eq!(x2[5].to_string(), "x.f: [0: struct {c: logic<5>, d: logic<6>}<7>]");
1273
1274 check(&x0[0], &[0] , None , Some((4, 3)));
1275 check(&x0[0], &[0, 0] , None , Some((3, 3)));
1276 check(&x0[0], &[0, 1] , Some(0), Some((4, 3)));
1277 check(&x0[1], &[0, ] , None , Some((2, 0)));
1278 check(&x0[1], &[0, 2] , None , Some((2, 2)));
1279 check(&x0[1], &[0, 2] , Some(1), Some((2, 1)));
1280 check(&x1[0], &[0] , None , Some((10, 6)));
1281 check(&x1[1], &[0] , None , Some((5, 0)));
1282 check(&x2[0], &[0] , None , None);
1283 check(&x2[0], &[0, 0] , None , Some((81, 80)));
1284 check(&x2[0], &[0, 1] , None , Some((86, 85)));
1285 check(&x2[0], &[0, 2] , None , Some((91, 90)));
1286 check(&x2[0], &[0, 3] , None , Some((96, 95)));
1287 check(&x2[1], &[0] , None , None);
1288 check(&x2[1], &[0, 0] , None , Some((79, 77)));
1289 check(&x2[1], &[0, 1] , None , Some((84, 82)));
1290 check(&x2[1], &[0, 2] , None , Some((89, 87)));
1291 check(&x2[1], &[0, 3] , None , Some((94, 92)));
1292 check(&x2[1], &[0, 3] , None , Some((94, 92)));
1293 check(&x2[1], &[0, 3, 2], None , Some((94, 94)));
1294 check(&x2[1], &[0, 3, 1], Some(0), Some((93, 92)));
1295 check(&x2[2], &[0] , None , Some((96, 77)));
1296 check(&x2[2], &[0, 0] , None , Some((81, 77)));
1297 check(&x2[2], &[0, 1] , None , Some((86, 82)));
1298 check(&x2[2], &[0, 2] , None , Some((91, 87)));
1299 check(&x2[2], &[0, 3] , None , Some((96, 92)));
1300 check(&x2[2], &[0, 2] , Some(1), Some((91, 82)));
1301 check(&x2[3], &[0] , None , None);
1302 check(&x2[3], &[0, 0] , None , Some((10, 6)));
1303 check(&x2[3], &[0, 1] , None , Some((21, 17)));
1304 check(&x2[3], &[0, 2] , None , Some((32, 28)));
1305 check(&x2[3], &[0, 3] , None , Some((43, 39)));
1306 check(&x2[3], &[0, 4] , None , Some((54, 50)));
1307 check(&x2[3], &[0, 5] , None , Some((65, 61)));
1308 check(&x2[3], &[0, 6] , None , Some((76, 72)));
1309 check(&x2[4], &[0] , None , None);
1310 check(&x2[4], &[0, 0] , None , Some((5, 0)));
1311 check(&x2[4], &[0, 1] , None , Some((16, 11)));
1312 check(&x2[4], &[0, 2] , None , Some((27, 22)));
1313 check(&x2[4], &[0, 3] , None , Some((38, 33)));
1314 check(&x2[4], &[0, 4] , None , Some((49, 44)));
1315 check(&x2[4], &[0, 5] , None , Some((60, 55)));
1316 check(&x2[4], &[0, 6] , None , Some((71, 66)));
1317 check(&x2[5], &[0] , None , Some((76, 0)));
1318 check(&x2[5], &[0, 0] , None , Some((10, 0)));
1319 check(&x2[5], &[0, 1] , None , Some((21, 11)));
1320 check(&x2[5], &[0, 2] , None , Some((32, 22)));
1321 check(&x2[5], &[0, 3] , None , Some((43, 33)));
1322 check(&x2[5], &[0, 4] , None , Some((54, 44)));
1323 check(&x2[5], &[0, 5] , None , Some((65, 55)));
1324 check(&x2[5], &[0, 6] , None , Some((76, 66)));
1325 }
1326
1327 #[rustfmt::skip]
1328 #[test]
1329 fn expand_union() {
1330 let x0 = create_struct(&[("a", create_logic(2)), ("b", create_logic(3))], 2);
1343 let x1 = create_union (&[("e", x0.clone()), ("f", create_logic(10))], 2);
1344 let x2 = create_struct(&[("g", x1.clone()), ("h", create_logic(5))], 2);
1345
1346 let path = VarPath::new(resource_table::insert_str("x"));
1347
1348 let x0 = x0.expand_struct_union(&path, &[], None);
1349 let x1 = x1.expand_struct_union(&path, &[], None);
1350 let x2 = x2.expand_struct_union(&path, &[], None);
1351
1352 assert_eq!(x0[0].to_string(), "x.a: [3: logic<2>]");
1353 assert_eq!(x0[1].to_string(), "x.b: [0: logic<3>]");
1354 assert_eq!(x1[0].to_string(), "x.e.a: [0: struct {a: logic<2>, b: logic<3>}<2>][3: logic<2>]");
1355 assert_eq!(x1[1].to_string(), "x.e.b: [0: struct {a: logic<2>, b: logic<3>}<2>][0: logic<3>]");
1356 assert_eq!(x1[2].to_string(), "x.e: [0: struct {a: logic<2>, b: logic<3>}<2>]");
1357 assert_eq!(x1[3].to_string(), "x.f: [0: logic<10>]");
1358 assert_eq!(x2[0].to_string(), "x.g.e.a: [5: union {e: struct {a: logic<2>, b: logic<3>}<2>, f: logic<10>}<2>][0: struct {a: logic<2>, b: logic<3>}<2>][3: logic<2>]");
1359 assert_eq!(x2[1].to_string(), "x.g.e.b: [5: union {e: struct {a: logic<2>, b: logic<3>}<2>, f: logic<10>}<2>][0: struct {a: logic<2>, b: logic<3>}<2>][0: logic<3>]");
1360 assert_eq!(x2[2].to_string(), "x.g.e: [5: union {e: struct {a: logic<2>, b: logic<3>}<2>, f: logic<10>}<2>][0: struct {a: logic<2>, b: logic<3>}<2>]");
1361 assert_eq!(x2[3].to_string(), "x.g.f: [5: union {e: struct {a: logic<2>, b: logic<3>}<2>, f: logic<10>}<2>][0: logic<10>]");
1362 assert_eq!(x2[4].to_string(), "x.g: [5: union {e: struct {a: logic<2>, b: logic<3>}<2>, f: logic<10>}<2>]");
1363 assert_eq!(x2[5].to_string(), "x.h: [0: logic<5>]");
1364
1365 check(&x0[0], &[0] , None , Some((4, 3)));
1366 check(&x0[1], &[0] , None , Some((2, 0)));
1367 check(&x1[0], &[0] , None , None);
1368 check(&x1[0], &[0, 0] , None , Some((4, 3)));
1369 check(&x1[0], &[0, 1] , None , Some((9, 8)));
1370 check(&x1[1], &[0] , None , None);
1371 check(&x1[1], &[0, 0] , None , Some((2, 0)));
1372 check(&x1[1], &[0, 1] , None , Some((7, 5)));
1373 check(&x1[1], &[0, 1, 2], None , Some((7, 7)));
1374 check(&x1[1], &[0, 1, 1], Some(0), Some((6, 5)));
1375 check(&x1[2], &[0] , None , Some((9, 0)));
1376 check(&x1[2], &[0, 0] , None , Some((4, 0)));
1377 check(&x1[2], &[0, 1] , None , Some((9, 5)));
1378 check(&x1[3], &[0] , None , Some((9, 0)));
1379 check(&x1[3], &[0, 5] , None , Some((5, 5)));
1380 check(&x1[3], &[0, 5] , Some(4), Some((5, 4)));
1381 check(&x2[0], &[0] , None , None);
1382 check(&x2[0], &[0, 0] , None , None);
1383 check(&x2[0], &[0, 0, 0], None , Some((9, 8)));
1384 check(&x2[0], &[0, 0, 1], None , Some((14, 13)));
1385 check(&x2[0], &[0, 1] , None , None);
1386 check(&x2[0], &[0, 1, 0], None , Some((19, 18)));
1387 check(&x2[0], &[0, 1, 1], None , Some((24, 23)));
1388 check(&x2[1], &[0] , None , None);
1389 check(&x2[1], &[0, 0] , None , None);
1390 check(&x2[1], &[0, 0, 0], None , Some((7, 5)));
1391 check(&x2[1], &[0, 0, 1], None , Some((12, 10)));
1392 check(&x2[1], &[0, 1] , None , None);
1393 check(&x2[1], &[0, 1, 0], None , Some((17, 15)));
1394 check(&x2[1], &[0, 1, 1], None , Some((22, 20)));
1395 check(&x2[2], &[0] , None , None);
1396 check(&x2[2], &[0, 0] , None , Some((14, 5)));
1397 check(&x2[2], &[0, 0, 0], None , Some((9, 5)));
1398 check(&x2[2], &[0, 0, 1], None , Some((14, 10)));
1399 check(&x2[2], &[0, 0, 1], Some(0), Some((14, 5)));
1400 check(&x2[2], &[0, 1] , None , Some((24, 15)));
1401 check(&x2[2], &[0, 1, 0], None , Some((19, 15)));
1402 check(&x2[2], &[0, 1, 1], None , Some((24, 20)));
1403 check(&x2[3], &[0, ] , None , None);
1404 check(&x2[3], &[0, 0] , None , Some((14, 5)));
1405 check(&x2[3], &[0, 1] , None , Some((24, 15)));
1406 check(&x2[4], &[0, ] , None , Some((24, 5)));
1407 check(&x2[4], &[0, 0] , None , Some((14, 5)));
1408 check(&x2[4], &[0, 1] , None , Some((24, 15)));
1409 check(&x2[5], &[0, ] , None , Some((4, 0)));
1410 check(&x2[5], &[0, 3] , None , Some((3, 3)));
1411 check(&x2[5], &[0, 3] , Some(2), Some((3, 2)));
1412 }
1413
1414 #[rustfmt::skip]
1415 #[test]
1416 fn expand_struct_with_multi_dim() {
1417 let x0 = create_struct(&[("a", create_logic_multi_dim(&[Some(2), Some(4)])), ("b", create_logic_multi_dim(&[Some(3), Some(6)]))], 4);
1422
1423 let path = VarPath::new(resource_table::insert_str("x"));
1424
1425 let x0 = x0.expand_struct_union(&path, &[], None);
1426
1427 assert_eq!(x0[0].to_string(), "x.a: [18: logic<2, 4>]");
1428 assert_eq!(x0[1].to_string(), "x.b: [0: logic<3, 6>]");
1429
1430 check(&x0[0], &[0] , None , Some((25, 18)));
1431 check(&x0[0], &[0, 0] , None , Some((21, 18)));
1432 check(&x0[0], &[0, 1] , None , Some((25, 22)));
1433 check(&x0[0], &[0, 1] , Some(0), Some((25, 18)));
1434 check(&x0[0], &[0, 0, 0], None , Some((18, 18)));
1435 check(&x0[0], &[0, 0, 1], None , Some((19, 19)));
1436 check(&x0[0], &[0, 0, 2], None , Some((20, 20)));
1437 check(&x0[0], &[0, 0, 3], None , Some((21, 21)));
1438 check(&x0[0], &[0, 0, 2], Some(1), Some((20, 19)));
1439 check(&x0[0], &[0, 1, 0], None , Some((22, 22)));
1440 check(&x0[0], &[0, 1, 1], None , Some((23, 23)));
1441 check(&x0[0], &[0, 1, 2], None , Some((24, 24)));
1442 check(&x0[0], &[0, 1, 3], None , Some((25, 25)));
1443 check(&x0[0], &[0, 1, 2], Some(1), Some((24, 23)));
1444 }
1445}