This commit is contained in:
parent
716c65edcd
commit
28aad19bf5
|
@ -20,8 +20,8 @@ use crate::{
|
||||||
module::{
|
module::{
|
||||||
transform::simplify_memories::simplify_memories, AnnotatedModuleIO, Block,
|
transform::simplify_memories::simplify_memories, AnnotatedModuleIO, Block,
|
||||||
ExternModuleBody, ExternModuleParameter, ExternModuleParameterValue, Module, ModuleBody,
|
ExternModuleBody, ExternModuleParameter, ExternModuleParameterValue, Module, ModuleBody,
|
||||||
NameId, NormalModuleBody, Stmt, StmtConnect, StmtDeclaration, StmtIf, StmtInstance,
|
NameId, NormalModuleBody, Stmt, StmtConnect, StmtDeclaration, StmtFormal, StmtFormalKind,
|
||||||
StmtMatch, StmtReg, StmtWire,
|
StmtIf, StmtInstance, StmtMatch, StmtReg, StmtWire,
|
||||||
},
|
},
|
||||||
reset::{AsyncReset, Reset, SyncReset},
|
reset::{AsyncReset, Reset, SyncReset},
|
||||||
source_location::SourceLocation,
|
source_location::SourceLocation,
|
||||||
|
@ -1954,6 +1954,33 @@ impl<'a> Exporter<'a> {
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
Stmt::Formal(StmtFormal {
|
||||||
|
kind,
|
||||||
|
clk,
|
||||||
|
pred,
|
||||||
|
en,
|
||||||
|
text,
|
||||||
|
source_location,
|
||||||
|
}) => {
|
||||||
|
let clk = self.expr(Expr::canonical(clk), &definitions, false);
|
||||||
|
let pred = self.expr(Expr::canonical(pred), &definitions, false);
|
||||||
|
let en = self.expr(Expr::canonical(en), &definitions, false);
|
||||||
|
let kind = match kind {
|
||||||
|
StmtFormalKind::Assert => "assert",
|
||||||
|
StmtFormalKind::Assume => "assume",
|
||||||
|
StmtFormalKind::Cover => "cover",
|
||||||
|
};
|
||||||
|
let text = EscapedString {
|
||||||
|
value: &text,
|
||||||
|
raw: false,
|
||||||
|
};
|
||||||
|
writeln!(
|
||||||
|
body,
|
||||||
|
"{indent}{kind}({clk}, {pred}, {en}, {text}){}",
|
||||||
|
FileInfo::new(source_location),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
Stmt::If(StmtIf {
|
Stmt::If(StmtIf {
|
||||||
mut cond,
|
mut cond,
|
||||||
mut source_location,
|
mut source_location,
|
||||||
|
|
|
@ -5,7 +5,7 @@ use crate::{
|
||||||
annotations::{Annotation, IntoAnnotations, TargetedAnnotation},
|
annotations::{Annotation, IntoAnnotations, TargetedAnnotation},
|
||||||
array::ArrayType,
|
array::ArrayType,
|
||||||
bundle::{Bundle, BundleField, BundleType},
|
bundle::{Bundle, BundleField, BundleType},
|
||||||
clock::ClockDomain,
|
clock::{Clock, ClockDomain},
|
||||||
enum_::{Enum, EnumMatchVariantsIter, EnumType},
|
enum_::{Enum, EnumMatchVariantsIter, EnumType},
|
||||||
expr::{
|
expr::{
|
||||||
ops::VariantAccess,
|
ops::VariantAccess,
|
||||||
|
@ -199,6 +199,52 @@ impl fmt::Debug for StmtConnect {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
|
||||||
|
pub enum StmtFormalKind {
|
||||||
|
Assert,
|
||||||
|
Assume,
|
||||||
|
Cover,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl StmtFormalKind {
|
||||||
|
pub fn as_str(self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
Self::Assert => "assert",
|
||||||
|
Self::Assume => "assume",
|
||||||
|
Self::Cover => "cover",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub struct StmtFormal {
|
||||||
|
pub kind: StmtFormalKind,
|
||||||
|
pub clk: Expr<Clock>,
|
||||||
|
pub pred: Expr<Bool>,
|
||||||
|
pub en: Expr<Bool>,
|
||||||
|
pub text: Interned<str>,
|
||||||
|
pub source_location: SourceLocation,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for StmtFormal {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
let Self {
|
||||||
|
kind,
|
||||||
|
clk,
|
||||||
|
pred,
|
||||||
|
en,
|
||||||
|
text,
|
||||||
|
source_location: _,
|
||||||
|
} = self;
|
||||||
|
f.debug_struct(kind.as_str())
|
||||||
|
.field("clk", clk)
|
||||||
|
.field("pred", pred)
|
||||||
|
.field("en", en)
|
||||||
|
.field("text", text)
|
||||||
|
.finish_non_exhaustive()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq, Hash)]
|
#[derive(Clone, PartialEq, Eq, Hash)]
|
||||||
pub struct StmtIf<S: ModuleBuildingStatus = ModuleBuilt> {
|
pub struct StmtIf<S: ModuleBuildingStatus = ModuleBuilt> {
|
||||||
pub cond: Expr<Bool>,
|
pub cond: Expr<Bool>,
|
||||||
|
@ -450,6 +496,8 @@ wrapper_enum! {
|
||||||
pub enum Stmt<S: ModuleBuildingStatus = ModuleBuilt> {
|
pub enum Stmt<S: ModuleBuildingStatus = ModuleBuilt> {
|
||||||
#[is = is_connect, as_ref = connect]
|
#[is = is_connect, as_ref = connect]
|
||||||
Connect(StmtConnect),
|
Connect(StmtConnect),
|
||||||
|
#[is = is_formal, as_ref = formal]
|
||||||
|
Formal(StmtFormal),
|
||||||
#[is = is_if, as_ref = if_]
|
#[is = is_if, as_ref = if_]
|
||||||
If(StmtIf<S>),
|
If(StmtIf<S>),
|
||||||
#[is = is_match, as_ref = match_]
|
#[is = is_match, as_ref = match_]
|
||||||
|
@ -462,7 +510,7 @@ wrapper_enum! {
|
||||||
impl<S: ModuleBuildingStatus> Stmt<S> {
|
impl<S: ModuleBuildingStatus> Stmt<S> {
|
||||||
pub fn sub_stmt_blocks(&self) -> &[S::Block] {
|
pub fn sub_stmt_blocks(&self) -> &[S::Block] {
|
||||||
match self {
|
match self {
|
||||||
Stmt::Connect(_) => &[],
|
Stmt::Connect(_) | Stmt::Formal(_) => &[],
|
||||||
Stmt::If(v) => &v.blocks,
|
Stmt::If(v) => &v.blocks,
|
||||||
Stmt::Match(v) => &v.blocks,
|
Stmt::Match(v) => &v.blocks,
|
||||||
Stmt::Declaration(v) => v.sub_stmt_blocks(),
|
Stmt::Declaration(v) => v.sub_stmt_blocks(),
|
||||||
|
@ -609,6 +657,14 @@ impl NameIdGen {
|
||||||
rhs: _,
|
rhs: _,
|
||||||
source_location: _,
|
source_location: _,
|
||||||
})
|
})
|
||||||
|
| Stmt::Formal(StmtFormal {
|
||||||
|
kind: _,
|
||||||
|
clk: _,
|
||||||
|
pred: _,
|
||||||
|
en: _,
|
||||||
|
text: _,
|
||||||
|
source_location: _,
|
||||||
|
})
|
||||||
| Stmt::If(StmtIf {
|
| Stmt::If(StmtIf {
|
||||||
cond: _,
|
cond: _,
|
||||||
source_location: _,
|
source_location: _,
|
||||||
|
@ -888,6 +944,7 @@ impl From<NormalModuleBody<ModuleBuilding>> for NormalModuleBody {
|
||||||
let stmts = Interned::from_iter(stmts.into_iter().map(|stmt| {
|
let stmts = Interned::from_iter(stmts.into_iter().map(|stmt| {
|
||||||
match stmt {
|
match stmt {
|
||||||
Stmt::Connect(stmt) => stmt.into(),
|
Stmt::Connect(stmt) => stmt.into(),
|
||||||
|
Stmt::Formal(stmt) => stmt.into(),
|
||||||
Stmt::If(StmtIf {
|
Stmt::If(StmtIf {
|
||||||
cond,
|
cond,
|
||||||
source_location,
|
source_location,
|
||||||
|
@ -1608,6 +1665,7 @@ impl AssertValidityState {
|
||||||
self.set_connect_side_written(lhs, source_location, true, block);
|
self.set_connect_side_written(lhs, source_location, true, block);
|
||||||
self.set_connect_side_written(rhs, source_location, false, block);
|
self.set_connect_side_written(rhs, source_location, false, block);
|
||||||
}
|
}
|
||||||
|
Stmt::Formal(_) => {}
|
||||||
Stmt::If(if_stmt) => {
|
Stmt::If(if_stmt) => {
|
||||||
let sub_blocks = if_stmt.blocks.map(|block| self.make_block_index(block));
|
let sub_blocks = if_stmt.blocks.map(|block| self.make_block_index(block));
|
||||||
self.process_conditional_sub_blocks(block, sub_blocks)
|
self.process_conditional_sub_blocks(block, sub_blocks)
|
||||||
|
@ -2336,6 +2394,119 @@ pub fn match_with_loc<T: Type>(
|
||||||
T::match_variants(expr.to_expr(), source_location)
|
T::match_variants(expr.to_expr(), source_location)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[track_caller]
|
||||||
|
pub fn formal_with_enable_and_loc(
|
||||||
|
kind: StmtFormalKind,
|
||||||
|
clk: Expr<Clock>,
|
||||||
|
pred: Expr<Bool>,
|
||||||
|
en: Expr<Bool>,
|
||||||
|
text: &str,
|
||||||
|
source_location: SourceLocation,
|
||||||
|
) {
|
||||||
|
ModuleBuilder::with(|m| {
|
||||||
|
m.impl_
|
||||||
|
.borrow_mut()
|
||||||
|
.body
|
||||||
|
.builder_normal_body()
|
||||||
|
.block(m.block_stack.top())
|
||||||
|
.stmts
|
||||||
|
.push(
|
||||||
|
StmtFormal {
|
||||||
|
kind,
|
||||||
|
clk,
|
||||||
|
pred,
|
||||||
|
en,
|
||||||
|
text: text.intern(),
|
||||||
|
source_location,
|
||||||
|
}
|
||||||
|
.into(),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[track_caller]
|
||||||
|
pub fn formal_with_enable(
|
||||||
|
kind: StmtFormalKind,
|
||||||
|
clk: Expr<Clock>,
|
||||||
|
pred: Expr<Bool>,
|
||||||
|
en: Expr<Bool>,
|
||||||
|
text: &str,
|
||||||
|
) {
|
||||||
|
formal_with_enable_and_loc(kind, clk, pred, en, text, SourceLocation::caller());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[track_caller]
|
||||||
|
pub fn formal_with_loc(
|
||||||
|
kind: StmtFormalKind,
|
||||||
|
clk: Expr<Clock>,
|
||||||
|
pred: Expr<Bool>,
|
||||||
|
text: &str,
|
||||||
|
source_location: SourceLocation,
|
||||||
|
) {
|
||||||
|
formal_with_enable_and_loc(kind, clk, pred, true.to_expr(), text, source_location);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[track_caller]
|
||||||
|
pub fn formal(kind: StmtFormalKind, clk: Expr<Clock>, pred: Expr<Bool>, text: &str) {
|
||||||
|
formal_with_loc(kind, clk, pred, text, SourceLocation::caller());
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! make_formal {
|
||||||
|
($kind:ident, $formal_with_enable_and_loc:ident, $formal_with_enable:ident, $formal_with_loc:ident, $formal:ident) => {
|
||||||
|
#[track_caller]
|
||||||
|
pub fn $formal_with_enable_and_loc(
|
||||||
|
clk: Expr<Clock>,
|
||||||
|
pred: Expr<Bool>,
|
||||||
|
en: Expr<Bool>,
|
||||||
|
text: &str,
|
||||||
|
source_location: SourceLocation,
|
||||||
|
) {
|
||||||
|
formal_with_enable_and_loc(StmtFormalKind::$kind, clk, pred, en, text, source_location);
|
||||||
|
}
|
||||||
|
#[track_caller]
|
||||||
|
pub fn $formal_with_enable(clk: Expr<Clock>, pred: Expr<Bool>, en: Expr<Bool>, text: &str) {
|
||||||
|
formal_with_enable(StmtFormalKind::$kind, clk, pred, en, text);
|
||||||
|
}
|
||||||
|
#[track_caller]
|
||||||
|
pub fn $formal_with_loc(
|
||||||
|
clk: Expr<Clock>,
|
||||||
|
pred: Expr<Bool>,
|
||||||
|
text: &str,
|
||||||
|
source_location: SourceLocation,
|
||||||
|
) {
|
||||||
|
formal_with_loc(StmtFormalKind::$kind, clk, pred, text, source_location);
|
||||||
|
}
|
||||||
|
#[track_caller]
|
||||||
|
pub fn $formal(clk: Expr<Clock>, pred: Expr<Bool>, text: &str) {
|
||||||
|
formal(StmtFormalKind::$kind, clk, pred, text);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
make_formal!(
|
||||||
|
Assert,
|
||||||
|
hdl_assert_with_enable_and_loc,
|
||||||
|
hdl_assert_with_enable,
|
||||||
|
hdl_assert_with_loc,
|
||||||
|
hdl_assert
|
||||||
|
);
|
||||||
|
|
||||||
|
make_formal!(
|
||||||
|
Assume,
|
||||||
|
hdl_assume_with_enable_and_loc,
|
||||||
|
hdl_assume_with_enable,
|
||||||
|
hdl_assume_with_loc,
|
||||||
|
hdl_assume
|
||||||
|
);
|
||||||
|
|
||||||
|
make_formal!(
|
||||||
|
Cover,
|
||||||
|
hdl_cover_with_enable_and_loc,
|
||||||
|
hdl_cover_with_enable,
|
||||||
|
hdl_cover_with_loc,
|
||||||
|
hdl_cover
|
||||||
|
);
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
pub fn connect_any_with_loc<Lhs: ToExpr, Rhs: ToExpr>(
|
pub fn connect_any_with_loc<Lhs: ToExpr, Rhs: ToExpr>(
|
||||||
lhs: Lhs,
|
lhs: Lhs,
|
||||||
|
|
|
@ -538,7 +538,9 @@ impl Folder for State {
|
||||||
}
|
}
|
||||||
.into()),
|
.into()),
|
||||||
},
|
},
|
||||||
Stmt::Connect(_) | Stmt::If(_) | Stmt::Declaration(_) => stmt.default_fold(self),
|
Stmt::Connect(_) | Stmt::Formal(_) | Stmt::If(_) | Stmt::Declaration(_) => {
|
||||||
|
stmt.default_fold(self)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,8 +21,8 @@ use crate::{
|
||||||
module::{
|
module::{
|
||||||
AnnotatedModuleIO, Block, BlockId, ExternModuleBody, ExternModuleParameter,
|
AnnotatedModuleIO, Block, BlockId, ExternModuleBody, ExternModuleParameter,
|
||||||
ExternModuleParameterValue, Instance, Module, ModuleBody, ModuleIO, NameId,
|
ExternModuleParameterValue, Instance, Module, ModuleBody, ModuleIO, NameId,
|
||||||
NormalModuleBody, ScopedNameId, Stmt, StmtConnect, StmtDeclaration, StmtIf, StmtInstance,
|
NormalModuleBody, ScopedNameId, Stmt, StmtConnect, StmtDeclaration, StmtFormal,
|
||||||
StmtMatch, StmtReg, StmtWire,
|
StmtFormalKind, StmtIf, StmtInstance, StmtMatch, StmtReg, StmtWire,
|
||||||
},
|
},
|
||||||
reg::Reg,
|
reg::Reg,
|
||||||
reset::{AsyncReset, Reset, SyncReset},
|
reset::{AsyncReset, Reset, SyncReset},
|
||||||
|
|
|
@ -14,8 +14,9 @@ pub use crate::{
|
||||||
int::{Bool, DynSize, KnownSize, SInt, SIntType, Size, UInt, UIntType},
|
int::{Bool, DynSize, KnownSize, SInt, SIntType, Size, UInt, UIntType},
|
||||||
memory::{Mem, MemBuilder, ReadUnderWrite},
|
memory::{Mem, MemBuilder, ReadUnderWrite},
|
||||||
module::{
|
module::{
|
||||||
annotate, connect, connect_any, incomplete_wire, instance, memory, memory_array,
|
annotate, connect, connect_any, hdl_assert, hdl_assert_with_enable, hdl_assume,
|
||||||
memory_with_init, reg_builder, wire, Instance, Module, ModuleBuilder,
|
hdl_assume_with_enable, hdl_cover, hdl_cover_with_enable, incomplete_wire, instance,
|
||||||
|
memory, memory_array, memory_with_init, reg_builder, wire, Instance, Module, ModuleBuilder,
|
||||||
},
|
},
|
||||||
reg::Reg,
|
reg::Reg,
|
||||||
reset::{AsyncReset, Reset, SyncReset, ToAsyncReset, ToReset, ToSyncReset},
|
reset::{AsyncReset, Reset, SyncReset, ToAsyncReset, ToReset, ToSyncReset},
|
||||||
|
|
|
@ -3182,3 +3182,55 @@ circuit check_uninit_1:
|
||||||
",
|
",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[hdl_module(outline_generated)]
|
||||||
|
pub fn check_formal() {
|
||||||
|
#[hdl]
|
||||||
|
let clk: Clock = m.input();
|
||||||
|
#[hdl]
|
||||||
|
let en1: Bool = m.input();
|
||||||
|
#[hdl]
|
||||||
|
let en2: Bool = m.input();
|
||||||
|
#[hdl]
|
||||||
|
let en3: Bool = m.input();
|
||||||
|
#[hdl]
|
||||||
|
let pred1: Bool = m.input();
|
||||||
|
#[hdl]
|
||||||
|
let pred2: Bool = m.input();
|
||||||
|
#[hdl]
|
||||||
|
let pred3: Bool = m.input();
|
||||||
|
hdl_assert_with_enable(clk, pred1, en1, "en check 1");
|
||||||
|
hdl_assume_with_enable(clk, pred2, en2, "en check 2");
|
||||||
|
hdl_cover_with_enable(clk, pred3, en3, "en check 3");
|
||||||
|
hdl_assert(clk, pred1, "check 1");
|
||||||
|
hdl_assume(clk, pred2, "check 2");
|
||||||
|
hdl_cover(clk, pred3, "check 3");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_formal() {
|
||||||
|
let _n = SourceLocation::normalize_files_for_tests();
|
||||||
|
let m = check_formal();
|
||||||
|
dbg!(m);
|
||||||
|
#[rustfmt::skip] // work around https://github.com/rust-lang/rustfmt/issues/6161
|
||||||
|
assert_export_firrtl! {
|
||||||
|
m =>
|
||||||
|
"/test/check_formal.fir": r#"FIRRTL version 3.2.0
|
||||||
|
circuit check_formal:
|
||||||
|
module check_formal: @[module-XXXXXXXXXX.rs 1:1]
|
||||||
|
input clk: Clock @[module-XXXXXXXXXX.rs 2:1]
|
||||||
|
input en1: UInt<1> @[module-XXXXXXXXXX.rs 3:1]
|
||||||
|
input en2: UInt<1> @[module-XXXXXXXXXX.rs 4:1]
|
||||||
|
input en3: UInt<1> @[module-XXXXXXXXXX.rs 5:1]
|
||||||
|
input pred1: UInt<1> @[module-XXXXXXXXXX.rs 6:1]
|
||||||
|
input pred2: UInt<1> @[module-XXXXXXXXXX.rs 7:1]
|
||||||
|
input pred3: UInt<1> @[module-XXXXXXXXXX.rs 8:1]
|
||||||
|
assert(clk, pred1, en1, "en check 1") @[module-XXXXXXXXXX.rs 9:1]
|
||||||
|
assume(clk, pred2, en2, "en check 2") @[module-XXXXXXXXXX.rs 10:1]
|
||||||
|
cover(clk, pred3, en3, "en check 3") @[module-XXXXXXXXXX.rs 11:1]
|
||||||
|
assert(clk, pred1, UInt<1>(0h1), "check 1") @[module-XXXXXXXXXX.rs 12:1]
|
||||||
|
assume(clk, pred2, UInt<1>(0h1), "check 2") @[module-XXXXXXXXXX.rs 13:1]
|
||||||
|
cover(clk, pred3, UInt<1>(0h1), "check 3") @[module-XXXXXXXXXX.rs 14:1]
|
||||||
|
"#,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
|
@ -1067,6 +1067,7 @@
|
||||||
"data": {
|
"data": {
|
||||||
"$kind": "Enum",
|
"$kind": "Enum",
|
||||||
"Connect": "Visible",
|
"Connect": "Visible",
|
||||||
|
"Formal": "Visible",
|
||||||
"If": "Visible",
|
"If": "Visible",
|
||||||
"Match": "Visible",
|
"Match": "Visible",
|
||||||
"Declaration": "Visible"
|
"Declaration": "Visible"
|
||||||
|
@ -1088,6 +1089,25 @@
|
||||||
"source_location": "Visible"
|
"source_location": "Visible"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"StmtFormalKind": {
|
||||||
|
"data": {
|
||||||
|
"$kind": "Enum",
|
||||||
|
"Assert": null,
|
||||||
|
"Assume": null,
|
||||||
|
"Cover": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"StmtFormal": {
|
||||||
|
"data": {
|
||||||
|
"$kind": "Struct",
|
||||||
|
"kind": "Visible",
|
||||||
|
"clk": "Visible",
|
||||||
|
"pred": "Visible",
|
||||||
|
"en": "Visible",
|
||||||
|
"text": "Visible",
|
||||||
|
"source_location": "Visible"
|
||||||
|
}
|
||||||
|
},
|
||||||
"StmtIf": {
|
"StmtIf": {
|
||||||
"data": {
|
"data": {
|
||||||
"$kind": "Struct",
|
"$kind": "Struct",
|
||||||
|
|
Loading…
Reference in a new issue