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::{
transform::simplify_memories::simplify_memories, AnnotatedModuleIO, Block,
ExternModuleBody, ExternModuleParameter, ExternModuleParameterValue, Module, ModuleBody,
NameId, NormalModuleBody, Stmt, StmtConnect, StmtDeclaration, StmtIf, StmtInstance,
StmtMatch, StmtReg, StmtWire,
NameId, NormalModuleBody, Stmt, StmtConnect, StmtDeclaration, StmtFormal, StmtFormalKind,
StmtIf, StmtInstance, StmtMatch, StmtReg, StmtWire,
},
reset::{AsyncReset, Reset, SyncReset},
source_location::SourceLocation,
@ -1954,6 +1954,33 @@ impl<'a> Exporter<'a> {
)
.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 {
mut cond,
mut source_location,

View file

@ -5,7 +5,7 @@ use crate::{
annotations::{Annotation, IntoAnnotations, TargetedAnnotation},
array::ArrayType,
bundle::{Bundle, BundleField, BundleType},
clock::ClockDomain,
clock::{Clock, ClockDomain},
enum_::{Enum, EnumMatchVariantsIter, EnumType},
expr::{
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)]
pub struct StmtIf<S: ModuleBuildingStatus = ModuleBuilt> {
pub cond: Expr<Bool>,
@ -450,6 +496,8 @@ wrapper_enum! {
pub enum Stmt<S: ModuleBuildingStatus = ModuleBuilt> {
#[is = is_connect, as_ref = connect]
Connect(StmtConnect),
#[is = is_formal, as_ref = formal]
Formal(StmtFormal),
#[is = is_if, as_ref = if_]
If(StmtIf<S>),
#[is = is_match, as_ref = match_]
@ -462,7 +510,7 @@ wrapper_enum! {
impl<S: ModuleBuildingStatus> Stmt<S> {
pub fn sub_stmt_blocks(&self) -> &[S::Block] {
match self {
Stmt::Connect(_) => &[],
Stmt::Connect(_) | Stmt::Formal(_) => &[],
Stmt::If(v) => &v.blocks,
Stmt::Match(v) => &v.blocks,
Stmt::Declaration(v) => v.sub_stmt_blocks(),
@ -609,6 +657,14 @@ impl NameIdGen {
rhs: _,
source_location: _,
})
| Stmt::Formal(StmtFormal {
kind: _,
clk: _,
pred: _,
en: _,
text: _,
source_location: _,
})
| Stmt::If(StmtIf {
cond: _,
source_location: _,
@ -888,6 +944,7 @@ impl From<NormalModuleBody<ModuleBuilding>> for NormalModuleBody {
let stmts = Interned::from_iter(stmts.into_iter().map(|stmt| {
match stmt {
Stmt::Connect(stmt) => stmt.into(),
Stmt::Formal(stmt) => stmt.into(),
Stmt::If(StmtIf {
cond,
source_location,
@ -1608,6 +1665,7 @@ impl AssertValidityState {
self.set_connect_side_written(lhs, source_location, true, block);
self.set_connect_side_written(rhs, source_location, false, block);
}
Stmt::Formal(_) => {}
Stmt::If(if_stmt) => {
let sub_blocks = if_stmt.blocks.map(|block| self.make_block_index(block));
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)
}
#[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]
pub fn connect_any_with_loc<Lhs: ToExpr, Rhs: ToExpr>(
lhs: Lhs,

View file

@ -538,7 +538,9 @@ impl Folder for State {
}
.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::{
AnnotatedModuleIO, Block, BlockId, ExternModuleBody, ExternModuleParameter,
ExternModuleParameterValue, Instance, Module, ModuleBody, ModuleIO, NameId,
NormalModuleBody, ScopedNameId, Stmt, StmtConnect, StmtDeclaration, StmtIf, StmtInstance,
StmtMatch, StmtReg, StmtWire,
NormalModuleBody, ScopedNameId, Stmt, StmtConnect, StmtDeclaration, StmtFormal,
StmtFormalKind, StmtIf, StmtInstance, StmtMatch, StmtReg, StmtWire,
},
reg::Reg,
reset::{AsyncReset, Reset, SyncReset},

View file

@ -14,8 +14,9 @@ pub use crate::{
int::{Bool, DynSize, KnownSize, SInt, SIntType, Size, UInt, UIntType},
memory::{Mem, MemBuilder, ReadUnderWrite},
module::{
annotate, connect, connect_any, incomplete_wire, instance, memory, memory_array,
memory_with_init, reg_builder, wire, Instance, Module, ModuleBuilder,
annotate, connect, connect_any, hdl_assert, hdl_assert_with_enable, hdl_assume,
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,
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": {
"$kind": "Enum",
"Connect": "Visible",
"Formal": "Visible",
"If": "Visible",
"Match": "Visible",
"Declaration": "Visible"
@ -1088,6 +1089,25 @@
"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": {
"data": {
"$kind": "Struct",