diff --git a/crates/fayalite/src/annotations.rs b/crates/fayalite/src/annotations.rs index 8e645c3..6b96d01 100644 --- a/crates/fayalite/src/annotations.rs +++ b/crates/fayalite/src/annotations.rs @@ -118,10 +118,35 @@ pub struct CustomFirrtlAnnotation { pub additional_fields: CustomFirrtlAnnotationFields, } +#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash, Serialize, Deserialize)] +pub struct SVAttributeAnnotation { + pub text: Interned, +} + +#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash, Serialize, Deserialize)] +pub struct BlackBoxInlineAnnotation { + pub path: Interned, + pub text: Interned, +} + +#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash, Serialize, Deserialize)] +pub struct BlackBoxPathAnnotation { + pub path: Interned, +} + +#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash, Serialize, Deserialize)] +pub struct DocStringAnnotation { + pub text: Interned, +} + #[derive(Clone, PartialEq, Eq, Hash, Debug)] #[non_exhaustive] pub enum Annotation { DontTouch, + SVAttribute(SVAttributeAnnotation), + BlackBoxInline(BlackBoxInlineAnnotation), + BlackBoxPath(BlackBoxPathAnnotation), + DocString(DocStringAnnotation), CustomFirrtl(CustomFirrtlAnnotation), } diff --git a/crates/fayalite/src/firrtl.rs b/crates/fayalite/src/firrtl.rs index 13f211f..0be61b5 100644 --- a/crates/fayalite/src/firrtl.rs +++ b/crates/fayalite/src/firrtl.rs @@ -2,7 +2,10 @@ // See Notices.txt for copyright information #![allow(clippy::type_complexity)] use crate::{ - annotations::CustomFirrtlAnnotation, + annotations::{ + Annotation, BlackBoxInlineAnnotation, BlackBoxPathAnnotation, CustomFirrtlAnnotation, + DocStringAnnotation, SVAttributeAnnotation, + }, array::Array, bundle::{Bundle, BundleField, BundleType}, clock::Clock, @@ -665,6 +668,17 @@ enum AnnotationData { }, #[serde(rename = "firrtl.transforms.DontTouchAnnotation")] DontTouch, + #[serde(rename = "firrtl.AttributeAnnotation")] + AttributeAnnotation { description: Interned }, + #[serde(rename = "firrtl.transforms.BlackBoxInlineAnno")] + BlackBoxInlineAnno { + name: Interned, + text: Interned, + }, + #[serde(rename = "firrtl.transforms.BlackBoxPathAnno")] + BlackBoxPathAnno { path: Interned }, + #[serde(rename = "firrtl.DocStringAnnotation")] + DocStringAnnotation { description: Interned }, #[allow(dead_code)] #[serde(untagged)] Other { @@ -675,7 +689,7 @@ enum AnnotationData { } #[derive(Serialize)] -struct Annotation { +struct FirrtlAnnotation { #[serde(flatten)] data: AnnotationData, target: AnnotationTarget, @@ -690,7 +704,7 @@ struct Exporter<'a> { module: ModuleState, type_state: TypeState, circuit_name: Ident, - annotations: Vec, + annotations: Vec, } struct PushIndent<'a> { @@ -1770,7 +1784,7 @@ impl<'a> Exporter<'a> { memory_name.0.to_string(), contents, )?; - self.annotations.push(Annotation { + self.annotations.push(FirrtlAnnotation { data: AnnotationData::MemoryFileInline { filename, hex_or_binary, @@ -1789,14 +1803,25 @@ impl<'a> Exporter<'a> { }); Ok(()) } - fn annotation( - &mut self, - path: AnnotationTargetPath, - annotation: &crate::annotations::Annotation, - ) { + fn annotation(&mut self, path: AnnotationTargetPath, annotation: &Annotation) { let data = match annotation { - crate::annotations::Annotation::DontTouch => AnnotationData::DontTouch, - crate::annotations::Annotation::CustomFirrtl(CustomFirrtlAnnotation { + Annotation::DontTouch => AnnotationData::DontTouch, + Annotation::SVAttribute(SVAttributeAnnotation { text }) => { + AnnotationData::AttributeAnnotation { description: *text } + } + Annotation::BlackBoxInline(BlackBoxInlineAnnotation { path, text }) => { + AnnotationData::BlackBoxInlineAnno { + name: *path, + text: *text, + } + } + Annotation::BlackBoxPath(BlackBoxPathAnnotation { path }) => { + AnnotationData::BlackBoxPathAnno { path: *path } + } + Annotation::DocString(DocStringAnnotation { text }) => { + AnnotationData::DocStringAnnotation { description: *text } + } + Annotation::CustomFirrtl(CustomFirrtlAnnotation { class, additional_fields, }) => AnnotationData::Other { @@ -1804,7 +1829,7 @@ impl<'a> Exporter<'a> { additional_fields: (*additional_fields).into(), }, }; - self.annotations.push(Annotation { + self.annotations.push(FirrtlAnnotation { data, target: AnnotationTarget { circuit: self.circuit_name, diff --git a/crates/fayalite/src/module/transform/visit.rs b/crates/fayalite/src/module/transform/visit.rs index 440eecb..77079dd 100644 --- a/crates/fayalite/src/module/transform/visit.rs +++ b/crates/fayalite/src/module/transform/visit.rs @@ -2,7 +2,10 @@ // See Notices.txt for copyright information #![allow(clippy::multiple_bound_locations)] use crate::{ - annotations::{Annotation, CustomFirrtlAnnotation, TargetedAnnotation}, + annotations::{ + Annotation, BlackBoxInlineAnnotation, BlackBoxPathAnnotation, CustomFirrtlAnnotation, + DocStringAnnotation, SVAttributeAnnotation, TargetedAnnotation, + }, array::ArrayType, bundle::{Bundle, BundleField, BundleType}, clock::Clock, diff --git a/crates/fayalite/tests/module.rs b/crates/fayalite/tests/module.rs index b4998da..70b3f56 100644 --- a/crates/fayalite/tests/module.rs +++ b/crates/fayalite/tests/module.rs @@ -1,8 +1,15 @@ // SPDX-License-Identifier: LGPL-3.0-or-later // See Notices.txt for copyright information use fayalite::{ - annotations::CustomFirrtlAnnotation, assert_export_firrtl, firrtl::ExportOptions, - intern::Intern, module::transform::simplify_enums::SimplifyEnumsKind, prelude::*, + annotations::{ + BlackBoxInlineAnnotation, BlackBoxPathAnnotation, CustomFirrtlAnnotation, + DocStringAnnotation, SVAttributeAnnotation, + }, + assert_export_firrtl, + firrtl::ExportOptions, + intern::Intern, + module::transform::simplify_enums::SimplifyEnumsKind, + prelude::*, ty::StaticType, }; use serde_json::json; @@ -3058,6 +3065,14 @@ pub fn check_annotations() { .try_into() .unwrap(), })); + m.annotate_module(Annotation::DocString(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); @@ -3139,6 +3154,40 @@ pub fn check_annotations() { connect(write_port.clk, clk); connect(write_port.data, wdata); connect(write_port.mask, wmask); + #[hdl_module(extern)] + fn black_box1() { + m.verilog_name("BlackBox1"); + m.annotate_module(Annotation::BlackBoxInline(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); + #[hdl_module(extern)] + fn black_box2() { + m.verilog_name("BlackBox2"); + m.annotate_module(Annotation::BlackBoxPath(BlackBoxPathAnnotation { + path: "black_box2.v".intern(), + })); + } + #[hdl] + let black_box2_instance = instance(black_box2()); + annotate(black_box2_instance, Annotation::DontTouch); + #[hdl] + let a_wire: (SInt<1>, Bool) = wire(); + annotate( + a_wire.1, + Annotation::SVAttribute(SVAttributeAnnotation { + text: "custom_sv_attr = \"abc\"".intern(), + }), + ); + connect(a_wire, (0_hdl_i1, false)); } #[test] @@ -3156,6 +3205,11 @@ circuit check_annotations: %[[ "bar": "a nice module!", "target": "~check_annotations|check_annotations" }, + { + "class": "firrtl.DocStringAnnotation", + "description": "This module is used as a test that fayalite's firrtl\nbackend properly emits annotations.\n\nTesting...\n", + "target": "~check_annotations|check_annotations" + }, { "class": "firrtl.transforms.DontTouchAnnotation", "target": "~check_annotations|check_annotations>raddr" @@ -3196,10 +3250,35 @@ circuit check_annotations: %[[ "class": "some.annotation.Class", "baz": "first mask bit", "target": "~check_annotations|check_annotations>mem.w1.data[0]" + }, + { + "class": "firrtl.transforms.DontTouchAnnotation", + "target": "~check_annotations|check_annotations>black_box1_instance" + }, + { + "class": "firrtl.transforms.DontTouchAnnotation", + "target": "~check_annotations|check_annotations>black_box2_instance" + }, + { + "class": "firrtl.AttributeAnnotation", + "description": "custom_sv_attr = \"abc\"", + "target": "~check_annotations|check_annotations>a_wire.1" + }, + { + "class": "firrtl.transforms.BlackBoxInlineAnno", + "name": "black_box1.v", + "text": "(* blackbox *)\nmodule BlackBox1();\nendmodule\n", + "target": "~check_annotations|black_box1" + }, + { + "class": "firrtl.transforms.BlackBoxPathAnno", + "path": "black_box2.v", + "target": "~check_annotations|black_box2" } ]] type Ty0 = {addr: UInt<8>, en: UInt<1>, clk: Clock, data: UInt<4>[2], mask: UInt<1>[2]} type Ty1 = {addr: UInt<8>, en: UInt<1>, clk: Clock, flip data: UInt<4>[2]} + type Ty2 = {`0`: SInt<1>, `1`: UInt<1>} module check_annotations: @[module-XXXXXXXXXX.rs 1:1] input raddr: UInt<8> @[module-XXXXXXXXXX.rs 2:1] output rdata: UInt<4>[2] @[module-XXXXXXXXXX.rs 3:1] @@ -3224,6 +3303,17 @@ circuit check_annotations: %[[ connect `mem`.w1.clk, clk @[module-XXXXXXXXXX.rs 17:1] connect `mem`.w1.data, wdata @[module-XXXXXXXXXX.rs 18:1] connect `mem`.w1.mask, wmask @[module-XXXXXXXXXX.rs 19:1] + inst black_box1_instance of black_box1 @[module-XXXXXXXXXX.rs 21:1] + inst black_box2_instance of black_box2 @[module-XXXXXXXXXX.rs 23:1] + wire a_wire: Ty2 @[module-XXXXXXXXXX.rs 24:1] + wire _bundle_literal_expr: Ty2 + connect _bundle_literal_expr.`0`, SInt<1>(0h0) + connect _bundle_literal_expr.`1`, UInt<1>(0h0) + connect a_wire, _bundle_literal_expr @[module-XXXXXXXXXX.rs 25:1] + extmodule black_box1: @[module-XXXXXXXXXX.rs 20:1] + defname = BlackBox1 + extmodule black_box2: @[module-XXXXXXXXXX.rs 22:1] + defname = BlackBox2 "#, }; } diff --git a/crates/fayalite/visit_types.json b/crates/fayalite/visit_types.json index f1969eb..7064df2 100644 --- a/crates/fayalite/visit_types.json +++ b/crates/fayalite/visit_types.json @@ -1164,9 +1164,38 @@ "data": { "$kind": "Enum", "DontTouch": null, + "SVAttribute": "Visible", + "BlackBoxInline": "Visible", + "BlackBoxPath": "Visible", + "DocString": "Visible", "CustomFirrtl": "Visible" } }, + "SVAttributeAnnotation": { + "data": { + "$kind": "Struct", + "text": "Visible" + } + }, + "BlackBoxInlineAnnotation": { + "data": { + "$kind": "Struct", + "path": "Visible", + "text": "Visible" + } + }, + "BlackBoxPathAnnotation": { + "data": { + "$kind": "Struct", + "path": "Visible" + } + }, + "DocStringAnnotation": { + "data": { + "$kind": "Struct", + "text": "Visible" + } + }, "CustomFirrtlAnnotation": { "data": { "$kind": "Opaque"