forked from libre-chip/fayalite
		
	make annotations easier to use
This commit is contained in:
		
							parent
							
								
									f35d88d2bb
								
							
						
					
					
						commit
						f3d6528f5b
					
				
					 6 changed files with 163 additions and 51 deletions
				
			
		|  | @ -8,6 +8,7 @@ use serde::{Deserialize, Serialize}; | |||
| use std::{ | ||||
|     fmt, | ||||
|     hash::{Hash, Hasher}, | ||||
|     iter::FusedIterator, | ||||
|     ops::Deref, | ||||
| }; | ||||
| 
 | ||||
|  | @ -118,6 +119,9 @@ pub struct CustomFirrtlAnnotation { | |||
|     pub additional_fields: CustomFirrtlAnnotationFields, | ||||
| } | ||||
| 
 | ||||
| #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash, Serialize, Deserialize)] | ||||
| pub struct DontTouchAnnotation; | ||||
| 
 | ||||
| #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash, Serialize, Deserialize)] | ||||
| pub struct SVAttributeAnnotation { | ||||
|     pub text: Interned<str>, | ||||
|  | @ -139,15 +143,63 @@ pub struct DocStringAnnotation { | |||
|     pub text: Interned<str>, | ||||
| } | ||||
| 
 | ||||
| #[derive(Clone, PartialEq, Eq, Hash, Debug)] | ||||
| #[non_exhaustive] | ||||
| pub enum Annotation { | ||||
|     DontTouch, | ||||
|     SVAttribute(SVAttributeAnnotation), | ||||
|     BlackBoxInline(BlackBoxInlineAnnotation), | ||||
|     BlackBoxPath(BlackBoxPathAnnotation), | ||||
|     DocString(DocStringAnnotation), | ||||
|     CustomFirrtl(CustomFirrtlAnnotation), | ||||
| macro_rules! make_annotation_enum { | ||||
|     ( | ||||
|         $(#[$meta:meta])* | ||||
|         $vis:vis enum $Annotation:ident { | ||||
|             $($Variant:ident($T:ident),)* | ||||
|         } | ||||
|     ) => { | ||||
|         $(#[$meta])* | ||||
|         $vis enum $Annotation { | ||||
|             $($Variant($T),)* | ||||
|         } | ||||
| 
 | ||||
|         $(impl IntoAnnotations for $T { | ||||
|             type IntoAnnotations = [$Annotation; 1]; | ||||
| 
 | ||||
|             fn into_annotations(self) -> Self::IntoAnnotations { | ||||
|                 [$Annotation::$Variant(self)] | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         impl IntoAnnotations for &'_ $T { | ||||
|             type IntoAnnotations = [$Annotation; 1]; | ||||
| 
 | ||||
|             fn into_annotations(self) -> Self::IntoAnnotations { | ||||
|                 [$Annotation::$Variant(*self)] | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         impl IntoAnnotations for &'_ mut $T { | ||||
|             type IntoAnnotations = [$Annotation; 1]; | ||||
| 
 | ||||
|             fn into_annotations(self) -> Self::IntoAnnotations { | ||||
|                 [$Annotation::$Variant(*self)] | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         impl IntoAnnotations for Box<$T> { | ||||
|             type IntoAnnotations = [$Annotation; 1]; | ||||
| 
 | ||||
|             fn into_annotations(self) -> Self::IntoAnnotations { | ||||
|                 [$Annotation::$Variant(*self)] | ||||
|             } | ||||
|         })* | ||||
|     }; | ||||
| } | ||||
| 
 | ||||
| make_annotation_enum! { | ||||
|     #[derive(Clone, PartialEq, Eq, Hash, Debug)] | ||||
|     #[non_exhaustive] | ||||
|     pub enum Annotation { | ||||
|         DontTouch(DontTouchAnnotation), | ||||
|         SVAttribute(SVAttributeAnnotation), | ||||
|         BlackBoxInline(BlackBoxInlineAnnotation), | ||||
|         BlackBoxPath(BlackBoxPathAnnotation), | ||||
|         DocString(DocStringAnnotation), | ||||
|         CustomFirrtl(CustomFirrtlAnnotation), | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Clone, PartialEq, Eq, Hash, Debug)] | ||||
|  | @ -212,10 +264,70 @@ impl IntoAnnotations for &'_ mut Annotation { | |||
|     } | ||||
| } | ||||
| 
 | ||||
| impl<T: IntoIterator<Item = Annotation>> IntoAnnotations for T { | ||||
|     type IntoAnnotations = Self; | ||||
| pub struct IterIntoAnnotations<T: Iterator<Item: IntoAnnotations>> { | ||||
|     outer: T, | ||||
|     inner: Option<<<T::Item as IntoAnnotations>::IntoAnnotations as IntoIterator>::IntoIter>, | ||||
| } | ||||
| 
 | ||||
|     fn into_annotations(self) -> Self::IntoAnnotations { | ||||
|         self | ||||
| impl<T: Iterator<Item: IntoAnnotations>> Iterator for IterIntoAnnotations<T> { | ||||
|     type Item = Annotation; | ||||
| 
 | ||||
|     fn next(&mut self) -> Option<Self::Item> { | ||||
|         loop { | ||||
|             if let Some(inner) = &mut self.inner { | ||||
|                 let Some(retval) = inner.next() else { | ||||
|                     self.inner = None; | ||||
|                     continue; | ||||
|                 }; | ||||
|                 return Some(retval); | ||||
|             } else { | ||||
|                 self.inner = Some(self.outer.next()?.into_annotations().into_iter()); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn size_hint(&self) -> (usize, Option<usize>) { | ||||
|         if let (0, Some(0)) = self.outer.size_hint() { | ||||
|             self.inner | ||||
|                 .as_ref() | ||||
|                 .map(|v| v.size_hint()) | ||||
|                 .unwrap_or((0, Some(0))) | ||||
|         } else { | ||||
|             ( | ||||
|                 self.inner.as_ref().map(|v| v.size_hint().0).unwrap_or(0), | ||||
|                 None, | ||||
|             ) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn fold<B, F>(self, init: B, f: F) -> B | ||||
|     where | ||||
|         Self: Sized, | ||||
|         F: FnMut(B, Self::Item) -> B, | ||||
|     { | ||||
|         self.inner | ||||
|             .into_iter() | ||||
|             .chain(self.outer.map(|v| v.into_annotations().into_iter())) | ||||
|             .flatten() | ||||
|             .fold(init, f) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl< | ||||
|         T: FusedIterator< | ||||
|             Item: IntoAnnotations<IntoAnnotations: IntoIterator<IntoIter: FusedIterator>>, | ||||
|         >, | ||||
|     > FusedIterator for IterIntoAnnotations<T> | ||||
| { | ||||
| } | ||||
| 
 | ||||
| impl<T: IntoIterator<Item: IntoAnnotations>> IntoAnnotations for T { | ||||
|     type IntoAnnotations = IterIntoAnnotations<T::IntoIter>; | ||||
| 
 | ||||
|     fn into_annotations(self) -> Self::IntoAnnotations { | ||||
|         IterIntoAnnotations { | ||||
|             outer: self.into_iter(), | ||||
|             inner: None, | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -4,7 +4,7 @@ | |||
| use crate::{ | ||||
|     annotations::{ | ||||
|         Annotation, BlackBoxInlineAnnotation, BlackBoxPathAnnotation, CustomFirrtlAnnotation, | ||||
|         DocStringAnnotation, SVAttributeAnnotation, | ||||
|         DocStringAnnotation, DontTouchAnnotation, SVAttributeAnnotation, | ||||
|     }, | ||||
|     array::Array, | ||||
|     bundle::{Bundle, BundleField, BundleType}, | ||||
|  | @ -1805,7 +1805,7 @@ impl<'a> Exporter<'a> { | |||
|     } | ||||
|     fn annotation(&mut self, path: AnnotationTargetPath, annotation: &Annotation) { | ||||
|         let data = match annotation { | ||||
|             Annotation::DontTouch => AnnotationData::DontTouch, | ||||
|             Annotation::DontTouch(DontTouchAnnotation {}) => AnnotationData::DontTouch, | ||||
|             Annotation::SVAttribute(SVAttributeAnnotation { text }) => { | ||||
|                 AnnotationData::AttributeAnnotation { description: *text } | ||||
|             } | ||||
|  |  | |||
|  | @ -4,7 +4,7 @@ | |||
| use crate::{ | ||||
|     annotations::{ | ||||
|         Annotation, BlackBoxInlineAnnotation, BlackBoxPathAnnotation, CustomFirrtlAnnotation, | ||||
|         DocStringAnnotation, SVAttributeAnnotation, TargetedAnnotation, | ||||
|         DocStringAnnotation, DontTouchAnnotation, SVAttributeAnnotation, TargetedAnnotation, | ||||
|     }, | ||||
|     array::ArrayType, | ||||
|     bundle::{Bundle, BundleField, BundleType}, | ||||
|  |  | |||
|  | @ -1,7 +1,10 @@ | |||
| // SPDX-License-Identifier: LGPL-3.0-or-later
 | ||||
| // See Notices.txt for copyright information
 | ||||
| pub use crate::{ | ||||
|     annotations::Annotation, | ||||
|     annotations::{ | ||||
|         BlackBoxInlineAnnotation, BlackBoxPathAnnotation, CustomFirrtlAnnotation, | ||||
|         DocStringAnnotation, DontTouchAnnotation, SVAttributeAnnotation, | ||||
|     }, | ||||
|     array::{Array, ArrayType}, | ||||
|     cli::Cli, | ||||
|     clock::{Clock, ClockDomain, ToClock}, | ||||
|  |  | |||
|  | @ -1,16 +1,8 @@ | |||
| // SPDX-License-Identifier: LGPL-3.0-or-later
 | ||||
| // See Notices.txt for copyright information
 | ||||
| use fayalite::{ | ||||
|     annotations::{ | ||||
|         BlackBoxInlineAnnotation, BlackBoxPathAnnotation, CustomFirrtlAnnotation, | ||||
|         DocStringAnnotation, SVAttributeAnnotation, | ||||
|     }, | ||||
|     assert_export_firrtl, | ||||
|     firrtl::ExportOptions, | ||||
|     intern::Intern, | ||||
|     module::transform::simplify_enums::SimplifyEnumsKind, | ||||
|     prelude::*, | ||||
|     ty::StaticType, | ||||
|     assert_export_firrtl, firrtl::ExportOptions, intern::Intern, | ||||
|     module::transform::simplify_enums::SimplifyEnumsKind, prelude::*, ty::StaticType, | ||||
| }; | ||||
| use serde_json::json; | ||||
| 
 | ||||
|  | @ -3057,30 +3049,30 @@ circuit check_memory_of_array_of_enum: | |||
| 
 | ||||
| #[hdl_module(outline_generated)] | ||||
| pub fn check_annotations() { | ||||
|     m.annotate_module(Annotation::CustomFirrtl(CustomFirrtlAnnotation { | ||||
|     m.annotate_module(CustomFirrtlAnnotation { | ||||
|         class: "the.annotation.Example".intern(), | ||||
|         additional_fields: json!({ | ||||
|             "bar": "a nice module!", | ||||
|         }) | ||||
|         .try_into() | ||||
|         .unwrap(), | ||||
|     })); | ||||
|     m.annotate_module(Annotation::DocString(DocStringAnnotation { | ||||
|     }); | ||||
|     m.annotate_module(DocStringAnnotation { | ||||
|         text: r"This module is used as a test that fayalite's firrtl
 | ||||
| backend properly emits annotations. | ||||
| 
 | ||||
| Testing... | ||||
| " | ||||
|         .intern(), | ||||
|     })); | ||||
|     }); | ||||
|     #[hdl] | ||||
|     let raddr: UInt<8> = m.input(); | ||||
|     annotate(raddr, Annotation::DontTouch); | ||||
|     annotate(raddr, DontTouchAnnotation); | ||||
|     #[hdl] | ||||
|     let rdata: Array<UInt<4>, 2> = m.output(); | ||||
|     annotate( | ||||
|         rdata, | ||||
|         Annotation::CustomFirrtl(CustomFirrtlAnnotation { | ||||
|         CustomFirrtlAnnotation { | ||||
|             class: "the.annotation.ExampleClass".intern(), | ||||
|             additional_fields: json!({ | ||||
|                 "foo": "bar", | ||||
|  | @ -3088,7 +3080,7 @@ Testing... | |||
|             }) | ||||
|             .try_into() | ||||
|             .unwrap(), | ||||
|         }), | ||||
|         }, | ||||
|     ); | ||||
|     #[hdl] | ||||
|     let waddr: UInt<8> = m.input(); | ||||
|  | @ -3098,21 +3090,21 @@ Testing... | |||
|     let wmask: Array<Bool, 2> = m.input(); | ||||
|     annotate( | ||||
|         wmask[1], | ||||
|         Annotation::CustomFirrtl(CustomFirrtlAnnotation { | ||||
|         CustomFirrtlAnnotation { | ||||
|             class: "some.annotation.Class".intern(), | ||||
|             additional_fields: json!({ | ||||
|                 "baz": "second mask bit", | ||||
|             }) | ||||
|             .try_into() | ||||
|             .unwrap(), | ||||
|         }), | ||||
|         }, | ||||
|     ); | ||||
|     #[hdl] | ||||
|     let clk: Clock = m.input(); | ||||
|     #[hdl] | ||||
|     let mut mem = memory(); | ||||
|     mem.depth(0x100); | ||||
|     mem.annotate(Annotation::CustomFirrtl(CustomFirrtlAnnotation { | ||||
|     mem.annotate(CustomFirrtlAnnotation { | ||||
|         class: "the.annotation.ExampleClass2".intern(), | ||||
|         additional_fields: json!({ | ||||
|             "bar": "foo", | ||||
|  | @ -3120,18 +3112,18 @@ Testing... | |||
|         }) | ||||
|         .try_into() | ||||
|         .unwrap(), | ||||
|     })); | ||||
|     }); | ||||
|     let read_port = mem.new_read_port(); | ||||
|     annotate( | ||||
|         read_port, | ||||
|         Annotation::CustomFirrtl(CustomFirrtlAnnotation { | ||||
|         CustomFirrtlAnnotation { | ||||
|             class: "the.annotation.ExampleClass3".intern(), | ||||
|             additional_fields: json!({ | ||||
|                 "foo": "my read port", | ||||
|             }) | ||||
|             .try_into() | ||||
|             .unwrap(), | ||||
|         }), | ||||
|         }, | ||||
|     ); | ||||
|     connect_any(read_port.addr, raddr); | ||||
|     connect(read_port.en, true); | ||||
|  | @ -3140,14 +3132,14 @@ Testing... | |||
|     let write_port = mem.new_write_port(); | ||||
|     annotate( | ||||
|         write_port.data[0], | ||||
|         Annotation::CustomFirrtl(CustomFirrtlAnnotation { | ||||
|         CustomFirrtlAnnotation { | ||||
|             class: "some.annotation.Class".intern(), | ||||
|             additional_fields: json!({ | ||||
|                 "baz": "first mask bit", | ||||
|             }) | ||||
|             .try_into() | ||||
|             .unwrap(), | ||||
|         }), | ||||
|         }, | ||||
|     ); | ||||
|     connect_any(write_port.addr, waddr); | ||||
|     connect(write_port.en, true); | ||||
|  | @ -3157,35 +3149,35 @@ Testing... | |||
|     #[hdl_module(extern)] | ||||
|     fn black_box1() { | ||||
|         m.verilog_name("BlackBox1"); | ||||
|         m.annotate_module(Annotation::BlackBoxInline(BlackBoxInlineAnnotation { | ||||
|         m.annotate_module(BlackBoxInlineAnnotation { | ||||
|             path: "black_box1.v".intern(), | ||||
|             text: r"(* blackbox *)
 | ||||
| module BlackBox1(); | ||||
| endmodule | ||||
| " | ||||
|             .intern(), | ||||
|         })); | ||||
|         }); | ||||
|     } | ||||
|     #[hdl] | ||||
|     let black_box1_instance = instance(black_box1()); | ||||
|     annotate(black_box1_instance, Annotation::DontTouch); | ||||
|     annotate(black_box1_instance, DontTouchAnnotation); | ||||
|     #[hdl_module(extern)] | ||||
|     fn black_box2() { | ||||
|         m.verilog_name("BlackBox2"); | ||||
|         m.annotate_module(Annotation::BlackBoxPath(BlackBoxPathAnnotation { | ||||
|         m.annotate_module(BlackBoxPathAnnotation { | ||||
|             path: "black_box2.v".intern(), | ||||
|         })); | ||||
|         }); | ||||
|     } | ||||
|     #[hdl] | ||||
|     let black_box2_instance = instance(black_box2()); | ||||
|     annotate(black_box2_instance, Annotation::DontTouch); | ||||
|     annotate(black_box2_instance, DontTouchAnnotation); | ||||
|     #[hdl] | ||||
|     let a_wire: (SInt<1>, Bool) = wire(); | ||||
|     annotate( | ||||
|         a_wire.1, | ||||
|         Annotation::SVAttribute(SVAttributeAnnotation { | ||||
|         SVAttributeAnnotation { | ||||
|             text: "custom_sv_attr = \"abc\"".intern(), | ||||
|         }), | ||||
|         }, | ||||
|     ); | ||||
|     connect(a_wire, (0_hdl_i1, false)); | ||||
| } | ||||
|  |  | |||
|  | @ -1163,7 +1163,7 @@ | |||
|         "Annotation": { | ||||
|             "data": { | ||||
|                 "$kind": "Enum", | ||||
|                 "DontTouch": null, | ||||
|                 "DontTouch": "Visible", | ||||
|                 "SVAttribute": "Visible", | ||||
|                 "BlackBoxInline": "Visible", | ||||
|                 "BlackBoxPath": "Visible", | ||||
|  | @ -1171,6 +1171,11 @@ | |||
|                 "CustomFirrtl": "Visible" | ||||
|             } | ||||
|         }, | ||||
|         "DontTouchAnnotation": { | ||||
|             "data": { | ||||
|                 "$kind": "Struct" | ||||
|             } | ||||
|         }, | ||||
|         "SVAttributeAnnotation": { | ||||
|             "data": { | ||||
|                 "$kind": "Struct", | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue