make annotations easier to use

This commit is contained in:
Jacob Lifshay 2024-10-01 19:54:17 -07:00
parent f35d88d2bb
commit f3d6528f5b
Signed by: programmerjake
SSH key fingerprint: SHA256:B1iRVvUJkvd7upMIiMqn6OyxvD2SgJkAH3ZnUOj6z+c
6 changed files with 163 additions and 51 deletions

View file

@ -8,6 +8,7 @@ use serde::{Deserialize, Serialize};
use std::{ use std::{
fmt, fmt,
hash::{Hash, Hasher}, hash::{Hash, Hasher},
iter::FusedIterator,
ops::Deref, ops::Deref,
}; };
@ -118,6 +119,9 @@ pub struct CustomFirrtlAnnotation {
pub additional_fields: CustomFirrtlAnnotationFields, 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)] #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash, Serialize, Deserialize)]
pub struct SVAttributeAnnotation { pub struct SVAttributeAnnotation {
pub text: Interned<str>, pub text: Interned<str>,
@ -139,16 +143,64 @@ pub struct DocStringAnnotation {
pub text: Interned<str>, pub text: Interned<str>,
} }
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)] #[derive(Clone, PartialEq, Eq, Hash, Debug)]
#[non_exhaustive] #[non_exhaustive]
pub enum Annotation { pub enum Annotation {
DontTouch, DontTouch(DontTouchAnnotation),
SVAttribute(SVAttributeAnnotation), SVAttribute(SVAttributeAnnotation),
BlackBoxInline(BlackBoxInlineAnnotation), BlackBoxInline(BlackBoxInlineAnnotation),
BlackBoxPath(BlackBoxPathAnnotation), BlackBoxPath(BlackBoxPathAnnotation),
DocString(DocStringAnnotation), DocString(DocStringAnnotation),
CustomFirrtl(CustomFirrtlAnnotation), CustomFirrtl(CustomFirrtlAnnotation),
} }
}
#[derive(Clone, PartialEq, Eq, Hash, Debug)] #[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub struct TargetedAnnotation { pub struct TargetedAnnotation {
@ -212,10 +264,70 @@ impl IntoAnnotations for &'_ mut Annotation {
} }
} }
impl<T: IntoIterator<Item = Annotation>> IntoAnnotations for T { pub struct IterIntoAnnotations<T: Iterator<Item: IntoAnnotations>> {
type IntoAnnotations = Self; outer: T,
inner: Option<<<T::Item as IntoAnnotations>::IntoAnnotations as IntoIterator>::IntoIter>,
}
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 { fn into_annotations(self) -> Self::IntoAnnotations {
self IterIntoAnnotations {
outer: self.into_iter(),
inner: None,
}
} }
} }

View file

@ -4,7 +4,7 @@
use crate::{ use crate::{
annotations::{ annotations::{
Annotation, BlackBoxInlineAnnotation, BlackBoxPathAnnotation, CustomFirrtlAnnotation, Annotation, BlackBoxInlineAnnotation, BlackBoxPathAnnotation, CustomFirrtlAnnotation,
DocStringAnnotation, SVAttributeAnnotation, DocStringAnnotation, DontTouchAnnotation, SVAttributeAnnotation,
}, },
array::Array, array::Array,
bundle::{Bundle, BundleField, BundleType}, bundle::{Bundle, BundleField, BundleType},
@ -1805,7 +1805,7 @@ impl<'a> Exporter<'a> {
} }
fn annotation(&mut self, path: AnnotationTargetPath, annotation: &Annotation) { fn annotation(&mut self, path: AnnotationTargetPath, annotation: &Annotation) {
let data = match annotation { let data = match annotation {
Annotation::DontTouch => AnnotationData::DontTouch, Annotation::DontTouch(DontTouchAnnotation {}) => AnnotationData::DontTouch,
Annotation::SVAttribute(SVAttributeAnnotation { text }) => { Annotation::SVAttribute(SVAttributeAnnotation { text }) => {
AnnotationData::AttributeAnnotation { description: *text } AnnotationData::AttributeAnnotation { description: *text }
} }

View file

@ -4,7 +4,7 @@
use crate::{ use crate::{
annotations::{ annotations::{
Annotation, BlackBoxInlineAnnotation, BlackBoxPathAnnotation, CustomFirrtlAnnotation, Annotation, BlackBoxInlineAnnotation, BlackBoxPathAnnotation, CustomFirrtlAnnotation,
DocStringAnnotation, SVAttributeAnnotation, TargetedAnnotation, DocStringAnnotation, DontTouchAnnotation, SVAttributeAnnotation, TargetedAnnotation,
}, },
array::ArrayType, array::ArrayType,
bundle::{Bundle, BundleField, BundleType}, bundle::{Bundle, BundleField, BundleType},

View file

@ -1,7 +1,10 @@
// SPDX-License-Identifier: LGPL-3.0-or-later // SPDX-License-Identifier: LGPL-3.0-or-later
// See Notices.txt for copyright information // See Notices.txt for copyright information
pub use crate::{ pub use crate::{
annotations::Annotation, annotations::{
BlackBoxInlineAnnotation, BlackBoxPathAnnotation, CustomFirrtlAnnotation,
DocStringAnnotation, DontTouchAnnotation, SVAttributeAnnotation,
},
array::{Array, ArrayType}, array::{Array, ArrayType},
cli::Cli, cli::Cli,
clock::{Clock, ClockDomain, ToClock}, clock::{Clock, ClockDomain, ToClock},

View file

@ -1,16 +1,8 @@
// SPDX-License-Identifier: LGPL-3.0-or-later // SPDX-License-Identifier: LGPL-3.0-or-later
// See Notices.txt for copyright information // See Notices.txt for copyright information
use fayalite::{ use fayalite::{
annotations::{ assert_export_firrtl, firrtl::ExportOptions, intern::Intern,
BlackBoxInlineAnnotation, BlackBoxPathAnnotation, CustomFirrtlAnnotation, module::transform::simplify_enums::SimplifyEnumsKind, prelude::*, ty::StaticType,
DocStringAnnotation, SVAttributeAnnotation,
},
assert_export_firrtl,
firrtl::ExportOptions,
intern::Intern,
module::transform::simplify_enums::SimplifyEnumsKind,
prelude::*,
ty::StaticType,
}; };
use serde_json::json; use serde_json::json;
@ -3057,30 +3049,30 @@ circuit check_memory_of_array_of_enum:
#[hdl_module(outline_generated)] #[hdl_module(outline_generated)]
pub fn check_annotations() { pub fn check_annotations() {
m.annotate_module(Annotation::CustomFirrtl(CustomFirrtlAnnotation { m.annotate_module(CustomFirrtlAnnotation {
class: "the.annotation.Example".intern(), class: "the.annotation.Example".intern(),
additional_fields: json!({ additional_fields: json!({
"bar": "a nice module!", "bar": "a nice module!",
}) })
.try_into() .try_into()
.unwrap(), .unwrap(),
})); });
m.annotate_module(Annotation::DocString(DocStringAnnotation { m.annotate_module(DocStringAnnotation {
text: r"This module is used as a test that fayalite's firrtl text: r"This module is used as a test that fayalite's firrtl
backend properly emits annotations. backend properly emits annotations.
Testing... Testing...
" "
.intern(), .intern(),
})); });
#[hdl] #[hdl]
let raddr: UInt<8> = m.input(); let raddr: UInt<8> = m.input();
annotate(raddr, Annotation::DontTouch); annotate(raddr, DontTouchAnnotation);
#[hdl] #[hdl]
let rdata: Array<UInt<4>, 2> = m.output(); let rdata: Array<UInt<4>, 2> = m.output();
annotate( annotate(
rdata, rdata,
Annotation::CustomFirrtl(CustomFirrtlAnnotation { CustomFirrtlAnnotation {
class: "the.annotation.ExampleClass".intern(), class: "the.annotation.ExampleClass".intern(),
additional_fields: json!({ additional_fields: json!({
"foo": "bar", "foo": "bar",
@ -3088,7 +3080,7 @@ Testing...
}) })
.try_into() .try_into()
.unwrap(), .unwrap(),
}), },
); );
#[hdl] #[hdl]
let waddr: UInt<8> = m.input(); let waddr: UInt<8> = m.input();
@ -3098,21 +3090,21 @@ Testing...
let wmask: Array<Bool, 2> = m.input(); let wmask: Array<Bool, 2> = m.input();
annotate( annotate(
wmask[1], wmask[1],
Annotation::CustomFirrtl(CustomFirrtlAnnotation { CustomFirrtlAnnotation {
class: "some.annotation.Class".intern(), class: "some.annotation.Class".intern(),
additional_fields: json!({ additional_fields: json!({
"baz": "second mask bit", "baz": "second mask bit",
}) })
.try_into() .try_into()
.unwrap(), .unwrap(),
}), },
); );
#[hdl] #[hdl]
let clk: Clock = m.input(); let clk: Clock = m.input();
#[hdl] #[hdl]
let mut mem = memory(); let mut mem = memory();
mem.depth(0x100); mem.depth(0x100);
mem.annotate(Annotation::CustomFirrtl(CustomFirrtlAnnotation { mem.annotate(CustomFirrtlAnnotation {
class: "the.annotation.ExampleClass2".intern(), class: "the.annotation.ExampleClass2".intern(),
additional_fields: json!({ additional_fields: json!({
"bar": "foo", "bar": "foo",
@ -3120,18 +3112,18 @@ Testing...
}) })
.try_into() .try_into()
.unwrap(), .unwrap(),
})); });
let read_port = mem.new_read_port(); let read_port = mem.new_read_port();
annotate( annotate(
read_port, read_port,
Annotation::CustomFirrtl(CustomFirrtlAnnotation { CustomFirrtlAnnotation {
class: "the.annotation.ExampleClass3".intern(), class: "the.annotation.ExampleClass3".intern(),
additional_fields: json!({ additional_fields: json!({
"foo": "my read port", "foo": "my read port",
}) })
.try_into() .try_into()
.unwrap(), .unwrap(),
}), },
); );
connect_any(read_port.addr, raddr); connect_any(read_port.addr, raddr);
connect(read_port.en, true); connect(read_port.en, true);
@ -3140,14 +3132,14 @@ Testing...
let write_port = mem.new_write_port(); let write_port = mem.new_write_port();
annotate( annotate(
write_port.data[0], write_port.data[0],
Annotation::CustomFirrtl(CustomFirrtlAnnotation { CustomFirrtlAnnotation {
class: "some.annotation.Class".intern(), class: "some.annotation.Class".intern(),
additional_fields: json!({ additional_fields: json!({
"baz": "first mask bit", "baz": "first mask bit",
}) })
.try_into() .try_into()
.unwrap(), .unwrap(),
}), },
); );
connect_any(write_port.addr, waddr); connect_any(write_port.addr, waddr);
connect(write_port.en, true); connect(write_port.en, true);
@ -3157,35 +3149,35 @@ Testing...
#[hdl_module(extern)] #[hdl_module(extern)]
fn black_box1() { fn black_box1() {
m.verilog_name("BlackBox1"); m.verilog_name("BlackBox1");
m.annotate_module(Annotation::BlackBoxInline(BlackBoxInlineAnnotation { m.annotate_module(BlackBoxInlineAnnotation {
path: "black_box1.v".intern(), path: "black_box1.v".intern(),
text: r"(* blackbox *) text: r"(* blackbox *)
module BlackBox1(); module BlackBox1();
endmodule endmodule
" "
.intern(), .intern(),
})); });
} }
#[hdl] #[hdl]
let black_box1_instance = instance(black_box1()); let black_box1_instance = instance(black_box1());
annotate(black_box1_instance, Annotation::DontTouch); annotate(black_box1_instance, DontTouchAnnotation);
#[hdl_module(extern)] #[hdl_module(extern)]
fn black_box2() { fn black_box2() {
m.verilog_name("BlackBox2"); m.verilog_name("BlackBox2");
m.annotate_module(Annotation::BlackBoxPath(BlackBoxPathAnnotation { m.annotate_module(BlackBoxPathAnnotation {
path: "black_box2.v".intern(), path: "black_box2.v".intern(),
})); });
} }
#[hdl] #[hdl]
let black_box2_instance = instance(black_box2()); let black_box2_instance = instance(black_box2());
annotate(black_box2_instance, Annotation::DontTouch); annotate(black_box2_instance, DontTouchAnnotation);
#[hdl] #[hdl]
let a_wire: (SInt<1>, Bool) = wire(); let a_wire: (SInt<1>, Bool) = wire();
annotate( annotate(
a_wire.1, a_wire.1,
Annotation::SVAttribute(SVAttributeAnnotation { SVAttributeAnnotation {
text: "custom_sv_attr = \"abc\"".intern(), text: "custom_sv_attr = \"abc\"".intern(),
}), },
); );
connect(a_wire, (0_hdl_i1, false)); connect(a_wire, (0_hdl_i1, false));
} }

View file

@ -1163,7 +1163,7 @@
"Annotation": { "Annotation": {
"data": { "data": {
"$kind": "Enum", "$kind": "Enum",
"DontTouch": null, "DontTouch": "Visible",
"SVAttribute": "Visible", "SVAttribute": "Visible",
"BlackBoxInline": "Visible", "BlackBoxInline": "Visible",
"BlackBoxPath": "Visible", "BlackBoxPath": "Visible",
@ -1171,6 +1171,11 @@
"CustomFirrtl": "Visible" "CustomFirrtl": "Visible"
} }
}, },
"DontTouchAnnotation": {
"data": {
"$kind": "Struct"
}
},
"SVAttributeAnnotation": { "SVAttributeAnnotation": {
"data": { "data": {
"$kind": "Struct", "$kind": "Struct",