add assert/assume/cover
All checks were successful
/ test (push) Successful in 4m33s

This commit is contained in:
Jacob Lifshay 2024-09-23 19:10:51 -07:00
parent 716c65edcd
commit 28aad19bf5
Signed by: programmerjake
SSH key fingerprint: SHA256:B1iRVvUJkvd7upMIiMqn6OyxvD2SgJkAH3ZnUOj6z+c
7 changed files with 282 additions and 9 deletions

View file

@ -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,

View file

@ -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,

View file

@ -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)
}
} }
} }

View file

@ -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},

View file

@ -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},

View file

@ -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]
"#,
};
}

View file

@ -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",