forked from libre-chip/fayalite
Compare commits
76 commits
formal_mem
...
master
Author | SHA1 | Date | |
---|---|---|---|
|
3458c21f44 | ||
|
43797db36e | ||
|
cdd84953d0 | ||
|
86a1bb46be | ||
|
209d5b5fe1 | ||
|
d4ea826051 | ||
|
404a2ee043 | ||
|
e3a2ccd41c | ||
|
3771cea78e | ||
|
dcf865caec | ||
|
31d01046a8 | ||
|
c16726cee6 | ||
|
b63676d0ca | ||
|
7005fa3330 | ||
|
2ab8428062 | ||
|
9b06019bf5 | ||
|
36bad52978 | ||
|
21c73051ec | ||
|
304d8da0e8 | ||
|
2af38de900 | ||
|
c756aeec70 | ||
|
903ca1bf30 | ||
|
8d030ac65d | ||
|
562c479b62 | ||
|
393f78a14d | ||
|
8616ee4737 | ||
|
5087f16099 | ||
|
6b31e6d515 | ||
|
564ccb30bc | ||
|
ca759168ff | ||
|
e4cf66adf8 | ||
|
cd0dd7b7ee | ||
|
9654167ca3 | ||
|
3ed7827485 | ||
|
e504cfebfe | ||
|
9f42cab471 | ||
|
259bee39c2 | ||
|
643816d5b5 | ||
|
42afd2da0e | ||
|
15bc304bb6 | ||
|
4422157db8 | ||
|
d3f52292a1 | ||
|
fd45465d35 | ||
|
5e0548db26 | ||
|
12b3ba57f1 | ||
|
965fe53077 | ||
|
3abba7f9eb | ||
|
6446b71afd | ||
|
d36cf92d7f | ||
|
d744d85c66 | ||
|
358cdd10c8 | ||
|
9128a84284 | ||
|
546010739a | ||
|
9b5f1218fd | ||
|
89d84551f8 | ||
|
7851bf545c | ||
|
3e3da53bd2 | ||
|
fa50930ff8 | ||
|
9516fe03a1 | ||
|
52ab134673 | ||
|
698b8adc23 | ||
|
59be3bd645 | ||
|
913baa37e9 | ||
|
11ddbc43c7 | ||
|
c4b5d00419 | ||
|
09aa9fbc78 | ||
|
288a6b71b9 | ||
|
0095570f19 | ||
|
f54e55a143 | ||
|
a6e40839ac | ||
|
3106a6fff6 | ||
|
f338f37d3e | ||
|
277d3e0d4d | ||
|
b288d6f8f2 | ||
|
479d59b287 | ||
|
6f904148c4 |
|
@ -38,7 +38,7 @@ jobs:
|
||||||
z3 \
|
z3 \
|
||||||
zlib1g-dev
|
zlib1g-dev
|
||||||
- run: |
|
- run: |
|
||||||
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain 1.80.1
|
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain 1.82.0
|
||||||
source "$HOME/.cargo/env"
|
source "$HOME/.cargo/env"
|
||||||
echo "$PATH" >> "$GITHUB_PATH"
|
echo "$PATH" >> "$GITHUB_PATH"
|
||||||
- uses: https://code.forgejo.org/actions/cache/restore@v3
|
- uses: https://code.forgejo.org/actions/cache/restore@v3
|
||||||
|
@ -57,4 +57,5 @@ jobs:
|
||||||
save-if: ${{ github.ref == 'refs/heads/master' }}
|
save-if: ${{ github.ref == 'refs/heads/master' }}
|
||||||
- run: cargo test
|
- run: cargo test
|
||||||
- run: cargo build --tests --features=unstable-doc
|
- run: cargo build --tests --features=unstable-doc
|
||||||
|
- run: cargo test --doc --features=unstable-doc
|
||||||
- run: cargo doc --features=unstable-doc
|
- run: cargo doc --features=unstable-doc
|
||||||
|
|
48
Cargo.lock
generated
48
Cargo.lock
generated
|
@ -301,7 +301,7 @@ checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fayalite"
|
name = "fayalite"
|
||||||
version = "0.2.1"
|
version = "0.3.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitvec",
|
"bitvec",
|
||||||
"blake3",
|
"blake3",
|
||||||
|
@ -315,23 +315,25 @@ dependencies = [
|
||||||
"num-bigint",
|
"num-bigint",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
"os_pipe",
|
"os_pipe",
|
||||||
|
"petgraph",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"tempfile",
|
"tempfile",
|
||||||
"trybuild",
|
"trybuild",
|
||||||
|
"vec_map",
|
||||||
"which",
|
"which",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fayalite-proc-macros"
|
name = "fayalite-proc-macros"
|
||||||
version = "0.2.1"
|
version = "0.3.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"fayalite-proc-macros-impl",
|
"fayalite-proc-macros-impl",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fayalite-proc-macros-impl"
|
name = "fayalite-proc-macros-impl"
|
||||||
version = "0.2.1"
|
version = "0.3.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base16ct",
|
"base16ct",
|
||||||
"num-bigint",
|
"num-bigint",
|
||||||
|
@ -345,7 +347,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fayalite-visit-gen"
|
name = "fayalite-visit-gen"
|
||||||
version = "0.2.1"
|
version = "0.3.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"indexmap",
|
"indexmap",
|
||||||
"prettyplease",
|
"prettyplease",
|
||||||
|
@ -357,6 +359,12 @@ dependencies = [
|
||||||
"thiserror",
|
"thiserror",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fixedbitset"
|
||||||
|
version = "0.5.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "funty"
|
name = "funty"
|
||||||
version = "2.0.0"
|
version = "2.0.0"
|
||||||
|
@ -423,9 +431,9 @@ checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "indexmap"
|
name = "indexmap"
|
||||||
version = "2.2.6"
|
version = "2.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26"
|
checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"equivalent",
|
"equivalent",
|
||||||
"hashbrown",
|
"hashbrown",
|
||||||
|
@ -472,11 +480,10 @@ checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num-bigint"
|
name = "num-bigint"
|
||||||
version = "0.4.4"
|
version = "0.4.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0"
|
checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"autocfg",
|
|
||||||
"num-integer",
|
"num-integer",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
]
|
]
|
||||||
|
@ -515,6 +522,15 @@ dependencies = [
|
||||||
"windows-sys 0.59.0",
|
"windows-sys 0.59.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "petgraph"
|
||||||
|
version = "0.6.5"
|
||||||
|
source = "git+https://github.com/programmerjake/petgraph.git?rev=258ea8071209a924b73fe96f9f87a3b7b45cbc9f#258ea8071209a924b73fe96f9f87a3b7b45cbc9f"
|
||||||
|
dependencies = [
|
||||||
|
"fixedbitset",
|
||||||
|
"indexmap",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "prettyplease"
|
name = "prettyplease"
|
||||||
version = "0.2.20"
|
version = "0.2.20"
|
||||||
|
@ -527,9 +543,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.83"
|
version = "1.0.92"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0b33eb56c327dec362a9e55b3ad14f9d2f0904fb5a5b03b513ab5465399e9f43"
|
checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
@ -631,9 +647,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "2.0.66"
|
version = "2.0.93"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5"
|
checksum = "9c786062daee0d6db1132800e623df74274a0a87322d8e183338e01b3d98d058"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
@ -720,6 +736,12 @@ version = "0.2.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "vec_map"
|
||||||
|
version = "0.8.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "version_check"
|
name = "version_check"
|
||||||
version = "0.9.4"
|
version = "0.9.4"
|
||||||
|
|
19
Cargo.toml
19
Cargo.toml
|
@ -5,18 +5,18 @@ resolver = "2"
|
||||||
members = ["crates/*"]
|
members = ["crates/*"]
|
||||||
|
|
||||||
[workspace.package]
|
[workspace.package]
|
||||||
version = "0.2.1"
|
version = "0.3.0"
|
||||||
license = "LGPL-3.0-or-later"
|
license = "LGPL-3.0-or-later"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
repository = "https://git.libre-chip.org/libre-chip/fayalite"
|
repository = "https://git.libre-chip.org/libre-chip/fayalite"
|
||||||
keywords = ["hdl", "hardware", "semiconductors", "firrtl", "fpga"]
|
keywords = ["hdl", "hardware", "semiconductors", "firrtl", "fpga"]
|
||||||
categories = ["simulation", "development-tools", "compilers"]
|
categories = ["simulation", "development-tools", "compilers"]
|
||||||
rust-version = "1.80.1"
|
rust-version = "1.82.0"
|
||||||
|
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
fayalite-proc-macros = { version = "=0.2.1", path = "crates/fayalite-proc-macros" }
|
fayalite-proc-macros = { version = "=0.3.0", path = "crates/fayalite-proc-macros" }
|
||||||
fayalite-proc-macros-impl = { version = "=0.2.1", path = "crates/fayalite-proc-macros-impl" }
|
fayalite-proc-macros-impl = { version = "=0.3.0", path = "crates/fayalite-proc-macros-impl" }
|
||||||
fayalite-visit-gen = { version = "=0.2.1", path = "crates/fayalite-visit-gen" }
|
fayalite-visit-gen = { version = "=0.3.0", path = "crates/fayalite-visit-gen" }
|
||||||
base16ct = "0.2.0"
|
base16ct = "0.2.0"
|
||||||
bitvec = { version = "1.0.1", features = ["serde"] }
|
bitvec = { version = "1.0.1", features = ["serde"] }
|
||||||
blake3 = { version = "1.5.4", features = ["serde"] }
|
blake3 = { version = "1.5.4", features = ["serde"] }
|
||||||
|
@ -24,19 +24,22 @@ clap = { version = "4.5.9", features = ["derive", "env", "string"] }
|
||||||
ctor = "0.2.8"
|
ctor = "0.2.8"
|
||||||
eyre = "0.6.12"
|
eyre = "0.6.12"
|
||||||
hashbrown = "0.14.3"
|
hashbrown = "0.14.3"
|
||||||
indexmap = { version = "2.2.6", features = ["serde"] }
|
indexmap = { version = "2.5.0", features = ["serde"] }
|
||||||
jobslot = "0.2.19"
|
jobslot = "0.2.19"
|
||||||
num-bigint = "0.4.4"
|
num-bigint = "0.4.6"
|
||||||
num-traits = "0.2.16"
|
num-traits = "0.2.16"
|
||||||
os_pipe = "1.2.1"
|
os_pipe = "1.2.1"
|
||||||
|
# TODO: switch back to crates.io once petgraph accepts PR #684 and releases a new version
|
||||||
|
petgraph = { git = "https://github.com/programmerjake/petgraph.git", rev = "258ea8071209a924b73fe96f9f87a3b7b45cbc9f" }
|
||||||
prettyplease = "0.2.20"
|
prettyplease = "0.2.20"
|
||||||
proc-macro2 = "1.0.83"
|
proc-macro2 = "1.0.83"
|
||||||
quote = "1.0.36"
|
quote = "1.0.36"
|
||||||
serde = { version = "1.0.202", features = ["derive"] }
|
serde = { version = "1.0.202", features = ["derive"] }
|
||||||
serde_json = { version = "1.0.117", features = ["preserve_order"] }
|
serde_json = { version = "1.0.117", features = ["preserve_order"] }
|
||||||
sha2 = "0.10.8"
|
sha2 = "0.10.8"
|
||||||
syn = { version = "2.0.66", features = ["full", "fold", "visit", "extra-traits"] }
|
syn = { version = "2.0.93", features = ["full", "fold", "visit", "extra-traits"] }
|
||||||
tempfile = "3.10.1"
|
tempfile = "3.10.1"
|
||||||
thiserror = "1.0.61"
|
thiserror = "1.0.61"
|
||||||
trybuild = "1.0"
|
trybuild = "1.0"
|
||||||
|
vec_map = "0.8.2"
|
||||||
which = "6.0.1"
|
which = "6.0.1"
|
||||||
|
|
|
@ -83,6 +83,7 @@ impl ParsedBundle {
|
||||||
custom_bounds,
|
custom_bounds,
|
||||||
no_static: _,
|
no_static: _,
|
||||||
no_runtime_generics: _,
|
no_runtime_generics: _,
|
||||||
|
cmp_eq: _,
|
||||||
} = options.body;
|
} = options.body;
|
||||||
let mut fields = match fields {
|
let mut fields = match fields {
|
||||||
syn::Fields::Named(fields) => fields,
|
syn::Fields::Named(fields) => fields,
|
||||||
|
@ -437,6 +438,7 @@ impl ToTokens for ParsedBundle {
|
||||||
custom_bounds: _,
|
custom_bounds: _,
|
||||||
no_static,
|
no_static,
|
||||||
no_runtime_generics,
|
no_runtime_generics,
|
||||||
|
cmp_eq,
|
||||||
} = &options.body;
|
} = &options.body;
|
||||||
let target = get_target(target, ident);
|
let target = get_target(target, ident);
|
||||||
let mut item_attrs = attrs.clone();
|
let mut item_attrs = attrs.clone();
|
||||||
|
@ -765,6 +767,69 @@ impl ToTokens for ParsedBundle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.to_tokens(tokens);
|
.to_tokens(tokens);
|
||||||
|
if let Some((cmp_eq,)) = cmp_eq {
|
||||||
|
let mut where_clause =
|
||||||
|
Generics::from(generics)
|
||||||
|
.where_clause
|
||||||
|
.unwrap_or_else(|| syn::WhereClause {
|
||||||
|
where_token: Token,
|
||||||
|
predicates: Punctuated::new(),
|
||||||
|
});
|
||||||
|
let mut fields_cmp_eq = vec![];
|
||||||
|
let mut fields_cmp_ne = vec![];
|
||||||
|
for field in fields.named() {
|
||||||
|
let field_ident = field.ident();
|
||||||
|
let field_ty = field.ty();
|
||||||
|
where_clause
|
||||||
|
.predicates
|
||||||
|
.push(parse_quote_spanned! {cmp_eq.span=>
|
||||||
|
#field_ty: ::fayalite::expr::ops::ExprPartialEq<#field_ty>
|
||||||
|
});
|
||||||
|
fields_cmp_eq.push(quote_spanned! {span=>
|
||||||
|
::fayalite::expr::ops::ExprPartialEq::cmp_eq(__lhs.#field_ident, __rhs.#field_ident)
|
||||||
|
});
|
||||||
|
fields_cmp_ne.push(quote_spanned! {span=>
|
||||||
|
::fayalite::expr::ops::ExprPartialEq::cmp_ne(__lhs.#field_ident, __rhs.#field_ident)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
let cmp_eq_body;
|
||||||
|
let cmp_ne_body;
|
||||||
|
if fields_len == 0 {
|
||||||
|
cmp_eq_body = quote_spanned! {span=>
|
||||||
|
::fayalite::expr::ToExpr::to_expr(&true)
|
||||||
|
};
|
||||||
|
cmp_ne_body = quote_spanned! {span=>
|
||||||
|
::fayalite::expr::ToExpr::to_expr(&false)
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
cmp_eq_body = quote_spanned! {span=>
|
||||||
|
#(#fields_cmp_eq)&*
|
||||||
|
};
|
||||||
|
cmp_ne_body = quote_spanned! {span=>
|
||||||
|
#(#fields_cmp_ne)|*
|
||||||
|
};
|
||||||
|
};
|
||||||
|
quote_spanned! {span=>
|
||||||
|
#[automatically_derived]
|
||||||
|
impl #impl_generics ::fayalite::expr::ops::ExprPartialEq<Self> for #target #type_generics
|
||||||
|
#where_clause
|
||||||
|
{
|
||||||
|
fn cmp_eq(
|
||||||
|
__lhs: ::fayalite::expr::Expr<Self>,
|
||||||
|
__rhs: ::fayalite::expr::Expr<Self>,
|
||||||
|
) -> ::fayalite::expr::Expr<::fayalite::int::Bool> {
|
||||||
|
#cmp_eq_body
|
||||||
|
}
|
||||||
|
fn cmp_ne(
|
||||||
|
__lhs: ::fayalite::expr::Expr<Self>,
|
||||||
|
__rhs: ::fayalite::expr::Expr<Self>,
|
||||||
|
) -> ::fayalite::expr::Expr<::fayalite::int::Bool> {
|
||||||
|
#cmp_ne_body
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.to_tokens(tokens);
|
||||||
|
}
|
||||||
if let (None, MaybeParsed::Parsed(generics)) = (no_static, &self.generics) {
|
if let (None, MaybeParsed::Parsed(generics)) = (no_static, &self.generics) {
|
||||||
let static_generics = generics.clone().for_static_type();
|
let static_generics = generics.clone().for_static_type();
|
||||||
let (static_impl_generics, static_type_generics, static_where_clause) =
|
let (static_impl_generics, static_type_generics, static_where_clause) =
|
||||||
|
|
|
@ -155,7 +155,11 @@ impl ParsedEnum {
|
||||||
custom_bounds,
|
custom_bounds,
|
||||||
no_static: _,
|
no_static: _,
|
||||||
no_runtime_generics: _,
|
no_runtime_generics: _,
|
||||||
|
cmp_eq,
|
||||||
} = options.body;
|
} = options.body;
|
||||||
|
if let Some((cmp_eq,)) = cmp_eq {
|
||||||
|
errors.error(cmp_eq, "#[hdl(cmp_eq)] is not yet implemented for enums");
|
||||||
|
}
|
||||||
attrs.retain(|attr| {
|
attrs.retain(|attr| {
|
||||||
if attr.path().is_ident("repr") {
|
if attr.path().is_ident("repr") {
|
||||||
errors.error(attr, "#[repr] is not supported on #[hdl] enums");
|
errors.error(attr, "#[repr] is not supported on #[hdl] enums");
|
||||||
|
@ -211,6 +215,7 @@ impl ToTokens for ParsedEnum {
|
||||||
custom_bounds: _,
|
custom_bounds: _,
|
||||||
no_static,
|
no_static,
|
||||||
no_runtime_generics,
|
no_runtime_generics,
|
||||||
|
cmp_eq: _, // TODO: implement cmp_eq for enums
|
||||||
} = &options.body;
|
} = &options.body;
|
||||||
let target = get_target(target, ident);
|
let target = get_target(target, ident);
|
||||||
let mut struct_attrs = attrs.clone();
|
let mut struct_attrs = attrs.clone();
|
||||||
|
|
|
@ -49,10 +49,14 @@ impl ParsedTypeAlias {
|
||||||
custom_bounds,
|
custom_bounds,
|
||||||
no_static,
|
no_static,
|
||||||
no_runtime_generics: _,
|
no_runtime_generics: _,
|
||||||
|
cmp_eq,
|
||||||
} = options.body;
|
} = options.body;
|
||||||
if let Some((no_static,)) = no_static {
|
if let Some((no_static,)) = no_static {
|
||||||
errors.error(no_static, "no_static is not valid on type aliases");
|
errors.error(no_static, "no_static is not valid on type aliases");
|
||||||
}
|
}
|
||||||
|
if let Some((cmp_eq,)) = cmp_eq {
|
||||||
|
errors.error(cmp_eq, "cmp_eq is not valid on type aliases");
|
||||||
|
}
|
||||||
let generics = if custom_bounds.is_some() {
|
let generics = if custom_bounds.is_some() {
|
||||||
MaybeParsed::Unrecognized(generics)
|
MaybeParsed::Unrecognized(generics)
|
||||||
} else if let Some(generics) = errors.ok(ParsedGenerics::parse(&mut generics)) {
|
} else if let Some(generics) = errors.ok(ParsedGenerics::parse(&mut generics)) {
|
||||||
|
@ -95,6 +99,7 @@ impl ToTokens for ParsedTypeAlias {
|
||||||
custom_bounds: _,
|
custom_bounds: _,
|
||||||
no_static: _,
|
no_static: _,
|
||||||
no_runtime_generics,
|
no_runtime_generics,
|
||||||
|
cmp_eq: _,
|
||||||
} = &options.body;
|
} = &options.body;
|
||||||
let target = get_target(target, ident);
|
let target = get_target(target, ident);
|
||||||
let mut type_attrs = attrs.clone();
|
let mut type_attrs = attrs.clone();
|
||||||
|
|
|
@ -26,6 +26,7 @@ crate::options! {
|
||||||
CustomBounds(custom_bounds),
|
CustomBounds(custom_bounds),
|
||||||
NoStatic(no_static),
|
NoStatic(no_static),
|
||||||
NoRuntimeGenerics(no_runtime_generics),
|
NoRuntimeGenerics(no_runtime_generics),
|
||||||
|
CmpEq(cmp_eq),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2044,6 +2045,7 @@ pub(crate) mod known_items {
|
||||||
impl_known_item!(::fayalite::int::Size);
|
impl_known_item!(::fayalite::int::Size);
|
||||||
impl_known_item!(::fayalite::int::UInt);
|
impl_known_item!(::fayalite::int::UInt);
|
||||||
impl_known_item!(::fayalite::int::UIntType);
|
impl_known_item!(::fayalite::int::UIntType);
|
||||||
|
impl_known_item!(::fayalite::reset::ResetType);
|
||||||
impl_known_item!(::fayalite::ty::CanonicalType);
|
impl_known_item!(::fayalite::ty::CanonicalType);
|
||||||
impl_known_item!(::fayalite::ty::StaticType);
|
impl_known_item!(::fayalite::ty::StaticType);
|
||||||
impl_known_item!(::fayalite::ty::Type);
|
impl_known_item!(::fayalite::ty::Type);
|
||||||
|
@ -2068,11 +2070,16 @@ macro_rules! impl_bounds {
|
||||||
$(
|
$(
|
||||||
$Variant:ident,
|
$Variant:ident,
|
||||||
)*
|
)*
|
||||||
|
$(
|
||||||
|
#[unknown]
|
||||||
|
$Unknown:ident,
|
||||||
|
)?
|
||||||
}
|
}
|
||||||
) => {
|
) => {
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
$vis enum $enum_type {
|
$vis enum $enum_type {
|
||||||
$($Variant(known_items::$Variant),)*
|
$($Variant(known_items::$Variant),)*
|
||||||
|
$($Unknown(syn::TypeParamBound),)?
|
||||||
}
|
}
|
||||||
|
|
||||||
$(impl From<known_items::$Variant> for $enum_type {
|
$(impl From<known_items::$Variant> for $enum_type {
|
||||||
|
@ -2085,28 +2092,54 @@ macro_rules! impl_bounds {
|
||||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||||
match self {
|
match self {
|
||||||
$(Self::$Variant(v) => v.to_tokens(tokens),)*
|
$(Self::$Variant(v) => v.to_tokens(tokens),)*
|
||||||
|
$(Self::$Unknown(v) => v.to_tokens(tokens),)?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl $enum_type {
|
impl $enum_type {
|
||||||
$vis fn parse_path(path: Path) -> Result<Self, Path> {
|
$vis fn parse_path(path: Path) -> Result<Self, Path> {
|
||||||
|
#![allow(unreachable_code)]
|
||||||
$(let path = match known_items::$Variant::parse_path(path) {
|
$(let path = match known_items::$Variant::parse_path(path) {
|
||||||
Ok(v) => return Ok(Self::$Variant(v)),
|
Ok(v) => return Ok(Self::$Variant(v)),
|
||||||
Err(path) => path,
|
Err(path) => path,
|
||||||
};)*
|
};)*
|
||||||
|
$(return Ok(Self::$Unknown(syn::TraitBound {
|
||||||
|
paren_token: None,
|
||||||
|
modifier: syn::TraitBoundModifier::None,
|
||||||
|
lifetimes: None,
|
||||||
|
path,
|
||||||
|
}.into()));)?
|
||||||
Err(path)
|
Err(path)
|
||||||
}
|
}
|
||||||
|
$vis fn parse_type_param_bound(mut type_param_bound: syn::TypeParamBound) -> Result<Self, syn::TypeParamBound> {
|
||||||
|
#![allow(unreachable_code)]
|
||||||
|
if let syn::TypeParamBound::Trait(mut trait_bound) = type_param_bound {
|
||||||
|
if let syn::TraitBound {
|
||||||
|
paren_token: _,
|
||||||
|
modifier: syn::TraitBoundModifier::None,
|
||||||
|
lifetimes: None,
|
||||||
|
path: _,
|
||||||
|
} = trait_bound {
|
||||||
|
match Self::parse_path(trait_bound.path) {
|
||||||
|
Ok(retval) => return Ok(retval),
|
||||||
|
Err(path) => trait_bound.path = path,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
type_param_bound = trait_bound.into();
|
||||||
|
}
|
||||||
|
$(return Ok(Self::$Unknown(type_param_bound));)?
|
||||||
|
Err(type_param_bound)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parse for $enum_type {
|
impl Parse for $enum_type {
|
||||||
fn parse(input: ParseStream) -> syn::Result<Self> {
|
fn parse(input: ParseStream) -> syn::Result<Self> {
|
||||||
Self::parse_path(Path::parse_mod_style(input)?).map_err(|path| {
|
Self::parse_type_param_bound(input.parse()?)
|
||||||
syn::Error::new_spanned(
|
.map_err(|type_param_bound| syn::Error::new_spanned(
|
||||||
path,
|
type_param_bound,
|
||||||
format_args!("expected one of: {}", [$(stringify!($Variant)),*].join(", ")),
|
format_args!("expected one of: {}", [$(stringify!($Variant)),*].join(", ")),
|
||||||
)
|
))
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2114,6 +2147,7 @@ macro_rules! impl_bounds {
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
$vis struct $struct_type {
|
$vis struct $struct_type {
|
||||||
$($vis $Variant: Option<known_items::$Variant>,)*
|
$($vis $Variant: Option<known_items::$Variant>,)*
|
||||||
|
$($vis $Unknown: Vec<syn::TypeParamBound>,)?
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToTokens for $struct_type {
|
impl ToTokens for $struct_type {
|
||||||
|
@ -2125,42 +2159,63 @@ macro_rules! impl_bounds {
|
||||||
separator = Some(<Token![+]>::default());
|
separator = Some(<Token![+]>::default());
|
||||||
v.to_tokens(tokens);
|
v.to_tokens(tokens);
|
||||||
})*
|
})*
|
||||||
|
$(for v in &self.$Unknown {
|
||||||
|
separator.to_tokens(tokens);
|
||||||
|
separator = Some(<Token![+]>::default());
|
||||||
|
v.to_tokens(tokens);
|
||||||
|
})*
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const _: () = {
|
const _: () = {
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
$vis struct Iter($vis $struct_type);
|
#[allow(non_snake_case)]
|
||||||
|
$vis struct Iter {
|
||||||
|
$($Variant: Option<known_items::$Variant>,)*
|
||||||
|
$($Unknown: std::vec::IntoIter<syn::TypeParamBound>,)?
|
||||||
|
}
|
||||||
|
|
||||||
impl IntoIterator for $struct_type {
|
impl IntoIterator for $struct_type {
|
||||||
type Item = $enum_type;
|
type Item = $enum_type;
|
||||||
type IntoIter = Iter;
|
type IntoIter = Iter;
|
||||||
|
|
||||||
fn into_iter(self) -> Self::IntoIter {
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
Iter(self)
|
Iter {
|
||||||
|
$($Variant: self.$Variant,)*
|
||||||
|
$($Unknown: self.$Unknown.into_iter(),)?
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Iterator for Iter {
|
impl Iterator for Iter {
|
||||||
type Item = $enum_type;
|
type Item = $enum_type;
|
||||||
|
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
$(
|
$(
|
||||||
if let Some(value) = self.0.$Variant.take() {
|
if let Some(value) = self.$Variant.take() {
|
||||||
return Some($enum_type::$Variant(value));
|
return Some($enum_type::$Variant(value));
|
||||||
}
|
}
|
||||||
)*
|
)*
|
||||||
|
$(
|
||||||
|
if let Some(value) = self.$Unknown.next() {
|
||||||
|
return Some($enum_type::$Unknown(value));
|
||||||
|
}
|
||||||
|
)?
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused_mut, unused_variables)]
|
#[allow(unused_mut, unused_variables)]
|
||||||
fn fold<B, F: FnMut(B, Self::Item) -> B>(mut self, mut init: B, mut f: F) -> B {
|
fn fold<B, F: FnMut(B, Self::Item) -> B>(mut self, mut init: B, mut f: F) -> B {
|
||||||
$(
|
$(
|
||||||
if let Some(value) = self.0.$Variant.take() {
|
if let Some(value) = self.$Variant.take() {
|
||||||
init = f(init, $enum_type::$Variant(value));
|
init = f(init, $enum_type::$Variant(value));
|
||||||
}
|
}
|
||||||
)*
|
)*
|
||||||
|
$(
|
||||||
|
if let Some(value) = self.$Unknown.next() {
|
||||||
|
init = f(init, $enum_type::$Unknown(value));
|
||||||
|
}
|
||||||
|
)?
|
||||||
init
|
init
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2172,6 +2227,9 @@ macro_rules! impl_bounds {
|
||||||
$($enum_type::$Variant(v) => {
|
$($enum_type::$Variant(v) => {
|
||||||
self.$Variant = Some(v);
|
self.$Variant = Some(v);
|
||||||
})*
|
})*
|
||||||
|
$($enum_type::$Unknown(v) => {
|
||||||
|
self.$Unknown.push(v);
|
||||||
|
})?
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2190,6 +2248,7 @@ macro_rules! impl_bounds {
|
||||||
$(if let Some(v) = v.$Variant {
|
$(if let Some(v) = v.$Variant {
|
||||||
self.$Variant = Some(v);
|
self.$Variant = Some(v);
|
||||||
})*
|
})*
|
||||||
|
$(self.$Unknown.extend(v.$Unknown);)*
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2239,9 +2298,12 @@ impl_bounds! {
|
||||||
EnumType,
|
EnumType,
|
||||||
IntType,
|
IntType,
|
||||||
KnownSize,
|
KnownSize,
|
||||||
|
ResetType,
|
||||||
Size,
|
Size,
|
||||||
StaticType,
|
StaticType,
|
||||||
Type,
|
Type,
|
||||||
|
#[unknown]
|
||||||
|
Unknown,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2252,8 +2314,11 @@ impl_bounds! {
|
||||||
BundleType,
|
BundleType,
|
||||||
EnumType,
|
EnumType,
|
||||||
IntType,
|
IntType,
|
||||||
|
ResetType,
|
||||||
StaticType,
|
StaticType,
|
||||||
Type,
|
Type,
|
||||||
|
#[unknown]
|
||||||
|
Unknown,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2264,8 +2329,10 @@ impl From<ParsedTypeBound> for ParsedBound {
|
||||||
ParsedTypeBound::BundleType(v) => ParsedBound::BundleType(v),
|
ParsedTypeBound::BundleType(v) => ParsedBound::BundleType(v),
|
||||||
ParsedTypeBound::EnumType(v) => ParsedBound::EnumType(v),
|
ParsedTypeBound::EnumType(v) => ParsedBound::EnumType(v),
|
||||||
ParsedTypeBound::IntType(v) => ParsedBound::IntType(v),
|
ParsedTypeBound::IntType(v) => ParsedBound::IntType(v),
|
||||||
|
ParsedTypeBound::ResetType(v) => ParsedBound::ResetType(v),
|
||||||
ParsedTypeBound::StaticType(v) => ParsedBound::StaticType(v),
|
ParsedTypeBound::StaticType(v) => ParsedBound::StaticType(v),
|
||||||
ParsedTypeBound::Type(v) => ParsedBound::Type(v),
|
ParsedTypeBound::Type(v) => ParsedBound::Type(v),
|
||||||
|
ParsedTypeBound::Unknown(v) => ParsedBound::Unknown(v),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2277,8 +2344,10 @@ impl From<ParsedTypeBounds> for ParsedBounds {
|
||||||
BundleType,
|
BundleType,
|
||||||
EnumType,
|
EnumType,
|
||||||
IntType,
|
IntType,
|
||||||
|
ResetType,
|
||||||
StaticType,
|
StaticType,
|
||||||
Type,
|
Type,
|
||||||
|
Unknown,
|
||||||
} = value;
|
} = value;
|
||||||
Self {
|
Self {
|
||||||
BoolOrIntType,
|
BoolOrIntType,
|
||||||
|
@ -2286,9 +2355,11 @@ impl From<ParsedTypeBounds> for ParsedBounds {
|
||||||
EnumType,
|
EnumType,
|
||||||
IntType,
|
IntType,
|
||||||
KnownSize: None,
|
KnownSize: None,
|
||||||
|
ResetType,
|
||||||
Size: None,
|
Size: None,
|
||||||
StaticType,
|
StaticType,
|
||||||
Type,
|
Type,
|
||||||
|
Unknown,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2314,11 +2385,17 @@ impl ParsedTypeBound {
|
||||||
ParsedTypeBound::BoolOrIntType(known_items::BoolOrIntType(span)),
|
ParsedTypeBound::BoolOrIntType(known_items::BoolOrIntType(span)),
|
||||||
ParsedTypeBound::Type(known_items::Type(span)),
|
ParsedTypeBound::Type(known_items::Type(span)),
|
||||||
]),
|
]),
|
||||||
|
Self::ResetType(v) => ParsedTypeBounds::from_iter([
|
||||||
|
ParsedTypeBound::from(v),
|
||||||
|
ParsedTypeBound::StaticType(known_items::StaticType(span)),
|
||||||
|
ParsedTypeBound::Type(known_items::Type(span)),
|
||||||
|
]),
|
||||||
Self::StaticType(v) => ParsedTypeBounds::from_iter([
|
Self::StaticType(v) => ParsedTypeBounds::from_iter([
|
||||||
ParsedTypeBound::from(v),
|
ParsedTypeBound::from(v),
|
||||||
ParsedTypeBound::Type(known_items::Type(span)),
|
ParsedTypeBound::Type(known_items::Type(span)),
|
||||||
]),
|
]),
|
||||||
Self::Type(v) => ParsedTypeBounds::from_iter([ParsedTypeBound::from(v)]),
|
Self::Type(v) => ParsedTypeBounds::from_iter([ParsedTypeBound::from(v)]),
|
||||||
|
Self::Unknown(v) => ParsedTypeBounds::from_iter([ParsedTypeBound::Unknown(v)]),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2349,9 +2426,11 @@ impl From<ParsedSizeTypeBounds> for ParsedBounds {
|
||||||
EnumType: None,
|
EnumType: None,
|
||||||
IntType: None,
|
IntType: None,
|
||||||
KnownSize,
|
KnownSize,
|
||||||
|
ResetType: None,
|
||||||
Size,
|
Size,
|
||||||
StaticType: None,
|
StaticType: None,
|
||||||
Type: None,
|
Type: None,
|
||||||
|
Unknown: vec![],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2379,6 +2458,7 @@ impl ParsedBounds {
|
||||||
fn categorize(self, errors: &mut Errors, span: Span) -> ParsedBoundsCategory {
|
fn categorize(self, errors: &mut Errors, span: Span) -> ParsedBoundsCategory {
|
||||||
let mut type_bounds = None;
|
let mut type_bounds = None;
|
||||||
let mut size_type_bounds = None;
|
let mut size_type_bounds = None;
|
||||||
|
let mut unknown_bounds = vec![];
|
||||||
self.into_iter().for_each(|bound| match bound.categorize() {
|
self.into_iter().for_each(|bound| match bound.categorize() {
|
||||||
ParsedBoundCategory::Type(bound) => {
|
ParsedBoundCategory::Type(bound) => {
|
||||||
type_bounds
|
type_bounds
|
||||||
|
@ -2390,15 +2470,37 @@ impl ParsedBounds {
|
||||||
.get_or_insert_with(ParsedSizeTypeBounds::default)
|
.get_or_insert_with(ParsedSizeTypeBounds::default)
|
||||||
.extend([bound]);
|
.extend([bound]);
|
||||||
}
|
}
|
||||||
|
ParsedBoundCategory::Unknown(bound) => unknown_bounds.push(bound),
|
||||||
});
|
});
|
||||||
match (type_bounds, size_type_bounds) {
|
match (type_bounds, size_type_bounds, unknown_bounds.is_empty()) {
|
||||||
(None, None) => ParsedBoundsCategory::Type(ParsedTypeBounds {
|
(None, None, true) => ParsedBoundsCategory::Type(ParsedTypeBounds {
|
||||||
Type: Some(known_items::Type(span)),
|
Type: Some(known_items::Type(span)),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}),
|
}),
|
||||||
(None, Some(bounds)) => ParsedBoundsCategory::SizeType(bounds),
|
(None, None, false) => {
|
||||||
(Some(bounds), None) => ParsedBoundsCategory::Type(bounds),
|
errors.error(
|
||||||
(Some(type_bounds), Some(size_type_bounds)) => {
|
unknown_bounds.remove(0),
|
||||||
|
"unknown bounds: must use at least one known bound (such as `Type`) with any unknown bounds",
|
||||||
|
);
|
||||||
|
ParsedBoundsCategory::Type(ParsedTypeBounds {
|
||||||
|
Unknown: unknown_bounds,
|
||||||
|
..Default::default()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
(None, Some(bounds), true) => ParsedBoundsCategory::SizeType(bounds),
|
||||||
|
(None, Some(bounds), false) => {
|
||||||
|
// TODO: implement
|
||||||
|
errors.error(
|
||||||
|
unknown_bounds.remove(0),
|
||||||
|
"unknown bounds with `Size` bounds are not implemented",
|
||||||
|
);
|
||||||
|
ParsedBoundsCategory::SizeType(bounds)
|
||||||
|
}
|
||||||
|
(Some(bounds), None, _) => ParsedBoundsCategory::Type(ParsedTypeBounds {
|
||||||
|
Unknown: unknown_bounds,
|
||||||
|
..bounds
|
||||||
|
}),
|
||||||
|
(Some(type_bounds), Some(size_type_bounds), _) => {
|
||||||
errors.error(
|
errors.error(
|
||||||
size_type_bounds
|
size_type_bounds
|
||||||
.Size
|
.Size
|
||||||
|
@ -2415,6 +2517,7 @@ impl ParsedBounds {
|
||||||
pub(crate) enum ParsedBoundCategory {
|
pub(crate) enum ParsedBoundCategory {
|
||||||
Type(ParsedTypeBound),
|
Type(ParsedTypeBound),
|
||||||
SizeType(ParsedSizeTypeBound),
|
SizeType(ParsedSizeTypeBound),
|
||||||
|
Unknown(syn::TypeParamBound),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ParsedBound {
|
impl ParsedBound {
|
||||||
|
@ -2425,15 +2528,18 @@ impl ParsedBound {
|
||||||
Self::EnumType(v) => ParsedBoundCategory::Type(ParsedTypeBound::EnumType(v)),
|
Self::EnumType(v) => ParsedBoundCategory::Type(ParsedTypeBound::EnumType(v)),
|
||||||
Self::IntType(v) => ParsedBoundCategory::Type(ParsedTypeBound::IntType(v)),
|
Self::IntType(v) => ParsedBoundCategory::Type(ParsedTypeBound::IntType(v)),
|
||||||
Self::KnownSize(v) => ParsedBoundCategory::SizeType(ParsedSizeTypeBound::KnownSize(v)),
|
Self::KnownSize(v) => ParsedBoundCategory::SizeType(ParsedSizeTypeBound::KnownSize(v)),
|
||||||
|
Self::ResetType(v) => ParsedBoundCategory::Type(ParsedTypeBound::ResetType(v)),
|
||||||
Self::Size(v) => ParsedBoundCategory::SizeType(ParsedSizeTypeBound::Size(v)),
|
Self::Size(v) => ParsedBoundCategory::SizeType(ParsedSizeTypeBound::Size(v)),
|
||||||
Self::StaticType(v) => ParsedBoundCategory::Type(ParsedTypeBound::StaticType(v)),
|
Self::StaticType(v) => ParsedBoundCategory::Type(ParsedTypeBound::StaticType(v)),
|
||||||
Self::Type(v) => ParsedBoundCategory::Type(ParsedTypeBound::Type(v)),
|
Self::Type(v) => ParsedBoundCategory::Type(ParsedTypeBound::Type(v)),
|
||||||
|
Self::Unknown(v) => ParsedBoundCategory::Unknown(v),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn implied_bounds(self) -> ParsedBounds {
|
fn implied_bounds(self) -> ParsedBounds {
|
||||||
match self.categorize() {
|
match self.categorize() {
|
||||||
ParsedBoundCategory::Type(v) => v.implied_bounds().into(),
|
ParsedBoundCategory::Type(v) => v.implied_bounds().into(),
|
||||||
ParsedBoundCategory::SizeType(v) => v.implied_bounds().into(),
|
ParsedBoundCategory::SizeType(v) => v.implied_bounds().into(),
|
||||||
|
ParsedBoundCategory::Unknown(v) => ParsedBounds::from_iter([ParsedBound::Unknown(v)]),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3310,8 +3416,9 @@ impl ParsedGenerics {
|
||||||
ParsedTypeBound::BoolOrIntType(_)
|
ParsedTypeBound::BoolOrIntType(_)
|
||||||
| ParsedTypeBound::BundleType(_)
|
| ParsedTypeBound::BundleType(_)
|
||||||
| ParsedTypeBound::EnumType(_)
|
| ParsedTypeBound::EnumType(_)
|
||||||
| ParsedTypeBound::IntType(_) => {
|
| ParsedTypeBound::IntType(_)
|
||||||
errors.error(bound, "bound on mask type not implemented");
|
| ParsedTypeBound::ResetType(_) => {
|
||||||
|
errors.error(bound, "bounds on mask types are not implemented");
|
||||||
}
|
}
|
||||||
ParsedTypeBound::StaticType(bound) => {
|
ParsedTypeBound::StaticType(bound) => {
|
||||||
if bounds.StaticType.is_none() {
|
if bounds.StaticType.is_none() {
|
||||||
|
@ -3323,6 +3430,12 @@ impl ParsedGenerics {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ParsedTypeBound::Type(_) => {}
|
ParsedTypeBound::Type(_) => {}
|
||||||
|
ParsedTypeBound::Unknown(_) => {
|
||||||
|
errors.error(
|
||||||
|
bound,
|
||||||
|
"unknown bounds on mask types are not implemented",
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
bounds.add_implied_bounds();
|
bounds.add_implied_bounds();
|
||||||
|
|
|
@ -3,14 +3,20 @@
|
||||||
#![cfg_attr(test, recursion_limit = "512")]
|
#![cfg_attr(test, recursion_limit = "512")]
|
||||||
use proc_macro2::{Span, TokenStream};
|
use proc_macro2::{Span, TokenStream};
|
||||||
use quote::{quote, ToTokens};
|
use quote::{quote, ToTokens};
|
||||||
use std::io::{ErrorKind, Write};
|
use std::{
|
||||||
|
collections::{hash_map::Entry, HashMap},
|
||||||
|
io::{ErrorKind, Write},
|
||||||
|
};
|
||||||
use syn::{
|
use syn::{
|
||||||
bracketed, parenthesized,
|
bracketed,
|
||||||
|
ext::IdentExt,
|
||||||
|
parenthesized,
|
||||||
parse::{Parse, ParseStream, Parser},
|
parse::{Parse, ParseStream, Parser},
|
||||||
parse_quote,
|
parse_quote,
|
||||||
punctuated::Pair,
|
punctuated::{Pair, Punctuated},
|
||||||
spanned::Spanned,
|
spanned::Spanned,
|
||||||
AttrStyle, Attribute, Error, Item, ItemFn, Token,
|
token::{Bracket, Paren},
|
||||||
|
AttrStyle, Attribute, Error, Ident, Item, ItemFn, LitBool, LitStr, Meta, Token,
|
||||||
};
|
};
|
||||||
|
|
||||||
mod fold;
|
mod fold;
|
||||||
|
@ -19,6 +25,7 @@ mod hdl_enum;
|
||||||
mod hdl_type_alias;
|
mod hdl_type_alias;
|
||||||
mod hdl_type_common;
|
mod hdl_type_common;
|
||||||
mod module;
|
mod module;
|
||||||
|
mod process_cfg;
|
||||||
|
|
||||||
pub(crate) trait CustomToken:
|
pub(crate) trait CustomToken:
|
||||||
Copy
|
Copy
|
||||||
|
@ -59,14 +66,20 @@ mod kw {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
custom_keyword!(__evaluated_cfgs);
|
||||||
|
custom_keyword!(all);
|
||||||
|
custom_keyword!(any);
|
||||||
|
custom_keyword!(cfg);
|
||||||
|
custom_keyword!(cfg_attr);
|
||||||
custom_keyword!(clock_domain);
|
custom_keyword!(clock_domain);
|
||||||
|
custom_keyword!(cmp_eq);
|
||||||
custom_keyword!(connect_inexact);
|
custom_keyword!(connect_inexact);
|
||||||
custom_keyword!(custom_bounds);
|
custom_keyword!(custom_bounds);
|
||||||
custom_keyword!(flip);
|
custom_keyword!(flip);
|
||||||
custom_keyword!(hdl);
|
custom_keyword!(hdl);
|
||||||
custom_keyword!(hdl_module);
|
custom_keyword!(hdl_module);
|
||||||
custom_keyword!(input);
|
|
||||||
custom_keyword!(incomplete_wire);
|
custom_keyword!(incomplete_wire);
|
||||||
|
custom_keyword!(input);
|
||||||
custom_keyword!(instance);
|
custom_keyword!(instance);
|
||||||
custom_keyword!(m);
|
custom_keyword!(m);
|
||||||
custom_keyword!(memory);
|
custom_keyword!(memory);
|
||||||
|
@ -75,6 +88,7 @@ mod kw {
|
||||||
custom_keyword!(no_reset);
|
custom_keyword!(no_reset);
|
||||||
custom_keyword!(no_runtime_generics);
|
custom_keyword!(no_runtime_generics);
|
||||||
custom_keyword!(no_static);
|
custom_keyword!(no_static);
|
||||||
|
custom_keyword!(not);
|
||||||
custom_keyword!(outline_generated);
|
custom_keyword!(outline_generated);
|
||||||
custom_keyword!(output);
|
custom_keyword!(output);
|
||||||
custom_keyword!(reg_builder);
|
custom_keyword!(reg_builder);
|
||||||
|
@ -901,15 +915,346 @@ fn hdl_module_impl(item: ItemFn) -> syn::Result<TokenStream> {
|
||||||
Ok(contents)
|
Ok(contents)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn hdl_module(attr: TokenStream, item: TokenStream) -> syn::Result<TokenStream> {
|
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
|
||||||
let kw = kw::hdl_module::default();
|
pub(crate) enum CfgExpr {
|
||||||
hdl_module_impl(syn::parse2(quote! { #[#kw(#attr)] #item })?)
|
Option {
|
||||||
|
ident: Ident,
|
||||||
|
value: Option<(Token![=], LitStr)>,
|
||||||
|
},
|
||||||
|
All {
|
||||||
|
all: kw::all,
|
||||||
|
paren: Paren,
|
||||||
|
exprs: Punctuated<CfgExpr, Token![,]>,
|
||||||
|
},
|
||||||
|
Any {
|
||||||
|
any: kw::any,
|
||||||
|
paren: Paren,
|
||||||
|
exprs: Punctuated<CfgExpr, Token![,]>,
|
||||||
|
},
|
||||||
|
Not {
|
||||||
|
not: kw::not,
|
||||||
|
paren: Paren,
|
||||||
|
expr: Box<CfgExpr>,
|
||||||
|
trailing_comma: Option<Token![,]>,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn hdl_attr(attr: TokenStream, item: TokenStream) -> syn::Result<TokenStream> {
|
impl Parse for CfgExpr {
|
||||||
let kw = kw::hdl::default();
|
fn parse(input: ParseStream) -> syn::Result<Self> {
|
||||||
let item = quote! { #[#kw(#attr)] #item };
|
match input.cursor().ident() {
|
||||||
let item = syn::parse2::<Item>(item)?;
|
Some((_, cursor)) if cursor.eof() => {
|
||||||
|
return Ok(CfgExpr::Option {
|
||||||
|
ident: input.call(Ident::parse_any)?,
|
||||||
|
value: None,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
if input.peek(Ident::peek_any) && input.peek2(Token![=]) {
|
||||||
|
return Ok(CfgExpr::Option {
|
||||||
|
ident: input.call(Ident::parse_any)?,
|
||||||
|
value: Some((input.parse()?, input.parse()?)),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
let contents;
|
||||||
|
if input.peek(kw::all) {
|
||||||
|
Ok(CfgExpr::All {
|
||||||
|
all: input.parse()?,
|
||||||
|
paren: parenthesized!(contents in input),
|
||||||
|
exprs: contents.call(Punctuated::parse_terminated)?,
|
||||||
|
})
|
||||||
|
} else if input.peek(kw::any) {
|
||||||
|
Ok(CfgExpr::Any {
|
||||||
|
any: input.parse()?,
|
||||||
|
paren: parenthesized!(contents in input),
|
||||||
|
exprs: contents.call(Punctuated::parse_terminated)?,
|
||||||
|
})
|
||||||
|
} else if input.peek(kw::not) {
|
||||||
|
Ok(CfgExpr::Not {
|
||||||
|
not: input.parse()?,
|
||||||
|
paren: parenthesized!(contents in input),
|
||||||
|
expr: contents.parse()?,
|
||||||
|
trailing_comma: contents.parse()?,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
Err(input.error("expected cfg-pattern"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToTokens for CfgExpr {
|
||||||
|
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||||
|
match self {
|
||||||
|
CfgExpr::Option { ident, value } => {
|
||||||
|
ident.to_tokens(tokens);
|
||||||
|
if let Some((eq, value)) = value {
|
||||||
|
eq.to_tokens(tokens);
|
||||||
|
value.to_tokens(tokens);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CfgExpr::All { all, paren, exprs } => {
|
||||||
|
all.to_tokens(tokens);
|
||||||
|
paren.surround(tokens, |tokens| exprs.to_tokens(tokens));
|
||||||
|
}
|
||||||
|
CfgExpr::Any { any, paren, exprs } => {
|
||||||
|
any.to_tokens(tokens);
|
||||||
|
paren.surround(tokens, |tokens| exprs.to_tokens(tokens));
|
||||||
|
}
|
||||||
|
CfgExpr::Not {
|
||||||
|
not,
|
||||||
|
paren,
|
||||||
|
expr,
|
||||||
|
trailing_comma,
|
||||||
|
} => {
|
||||||
|
not.to_tokens(tokens);
|
||||||
|
paren.surround(tokens, |tokens| {
|
||||||
|
expr.to_tokens(tokens);
|
||||||
|
trailing_comma.to_tokens(tokens);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
|
||||||
|
pub(crate) struct Cfg {
|
||||||
|
cfg: kw::cfg,
|
||||||
|
paren: Paren,
|
||||||
|
expr: CfgExpr,
|
||||||
|
trailing_comma: Option<Token![,]>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Cfg {
|
||||||
|
fn parse_meta(meta: &Meta) -> syn::Result<Self> {
|
||||||
|
syn::parse2(meta.to_token_stream())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToTokens for Cfg {
|
||||||
|
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||||
|
let Self {
|
||||||
|
cfg,
|
||||||
|
paren,
|
||||||
|
expr,
|
||||||
|
trailing_comma,
|
||||||
|
} = self;
|
||||||
|
cfg.to_tokens(tokens);
|
||||||
|
paren.surround(tokens, |tokens| {
|
||||||
|
expr.to_tokens(tokens);
|
||||||
|
trailing_comma.to_tokens(tokens);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Parse for Cfg {
|
||||||
|
fn parse(input: ParseStream) -> syn::Result<Self> {
|
||||||
|
let contents;
|
||||||
|
Ok(Self {
|
||||||
|
cfg: input.parse()?,
|
||||||
|
paren: parenthesized!(contents in input),
|
||||||
|
expr: contents.parse()?,
|
||||||
|
trailing_comma: contents.parse()?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
|
||||||
|
pub(crate) struct CfgAttr {
|
||||||
|
cfg_attr: kw::cfg_attr,
|
||||||
|
paren: Paren,
|
||||||
|
expr: CfgExpr,
|
||||||
|
comma: Token![,],
|
||||||
|
attrs: Punctuated<Meta, Token![,]>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CfgAttr {
|
||||||
|
pub(crate) fn to_cfg(&self) -> Cfg {
|
||||||
|
Cfg {
|
||||||
|
cfg: kw::cfg(self.cfg_attr.span),
|
||||||
|
paren: self.paren,
|
||||||
|
expr: self.expr.clone(),
|
||||||
|
trailing_comma: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn parse_meta(meta: &Meta) -> syn::Result<Self> {
|
||||||
|
syn::parse2(meta.to_token_stream())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Parse for CfgAttr {
|
||||||
|
fn parse(input: ParseStream) -> syn::Result<Self> {
|
||||||
|
let contents;
|
||||||
|
Ok(Self {
|
||||||
|
cfg_attr: input.parse()?,
|
||||||
|
paren: parenthesized!(contents in input),
|
||||||
|
expr: contents.parse()?,
|
||||||
|
comma: contents.parse()?,
|
||||||
|
attrs: contents.call(Punctuated::parse_terminated)?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) struct CfgAndValue {
|
||||||
|
cfg: Cfg,
|
||||||
|
eq_token: Token![=],
|
||||||
|
value: LitBool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Parse for CfgAndValue {
|
||||||
|
fn parse(input: ParseStream) -> syn::Result<Self> {
|
||||||
|
Ok(Self {
|
||||||
|
cfg: input.parse()?,
|
||||||
|
eq_token: input.parse()?,
|
||||||
|
value: input.parse()?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) struct Cfgs<T> {
|
||||||
|
pub(crate) bracket: Bracket,
|
||||||
|
pub(crate) cfgs_map: HashMap<Cfg, T>,
|
||||||
|
pub(crate) cfgs_list: Vec<Cfg>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Default for Cfgs<T> {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
bracket: Default::default(),
|
||||||
|
cfgs_map: Default::default(),
|
||||||
|
cfgs_list: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Cfgs<T> {
|
||||||
|
fn insert_cfg(&mut self, cfg: Cfg, value: T) {
|
||||||
|
match self.cfgs_map.entry(cfg) {
|
||||||
|
Entry::Occupied(_) => {}
|
||||||
|
Entry::Vacant(entry) => {
|
||||||
|
self.cfgs_list.push(entry.key().clone());
|
||||||
|
entry.insert(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Parse for Cfgs<bool> {
|
||||||
|
fn parse(input: ParseStream) -> syn::Result<Self> {
|
||||||
|
let contents;
|
||||||
|
let bracket = bracketed!(contents in input);
|
||||||
|
let mut cfgs_map = HashMap::new();
|
||||||
|
let mut cfgs_list = Vec::new();
|
||||||
|
for CfgAndValue {
|
||||||
|
cfg,
|
||||||
|
eq_token,
|
||||||
|
value,
|
||||||
|
} in contents.call(Punctuated::<CfgAndValue, Token![,]>::parse_terminated)?
|
||||||
|
{
|
||||||
|
let _ = eq_token;
|
||||||
|
match cfgs_map.entry(cfg) {
|
||||||
|
Entry::Occupied(_) => {}
|
||||||
|
Entry::Vacant(entry) => {
|
||||||
|
cfgs_list.push(entry.key().clone());
|
||||||
|
entry.insert(value.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(Self {
|
||||||
|
bracket,
|
||||||
|
cfgs_map,
|
||||||
|
cfgs_list,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Parse for Cfgs<()> {
|
||||||
|
fn parse(input: ParseStream) -> syn::Result<Self> {
|
||||||
|
let contents;
|
||||||
|
let bracket = bracketed!(contents in input);
|
||||||
|
let mut cfgs_map = HashMap::new();
|
||||||
|
let mut cfgs_list = Vec::new();
|
||||||
|
for cfg in contents.call(Punctuated::<Cfg, Token![,]>::parse_terminated)? {
|
||||||
|
match cfgs_map.entry(cfg) {
|
||||||
|
Entry::Occupied(_) => {}
|
||||||
|
Entry::Vacant(entry) => {
|
||||||
|
cfgs_list.push(entry.key().clone());
|
||||||
|
entry.insert(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(Self {
|
||||||
|
bracket,
|
||||||
|
cfgs_map,
|
||||||
|
cfgs_list,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToTokens for Cfgs<()> {
|
||||||
|
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||||
|
let Self {
|
||||||
|
bracket,
|
||||||
|
cfgs_map: _,
|
||||||
|
cfgs_list,
|
||||||
|
} = self;
|
||||||
|
bracket.surround(tokens, |tokens| {
|
||||||
|
for cfg in cfgs_list {
|
||||||
|
cfg.to_tokens(tokens);
|
||||||
|
<Token![,]>::default().to_tokens(tokens);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn hdl_main(
|
||||||
|
kw: impl CustomToken,
|
||||||
|
attr: TokenStream,
|
||||||
|
item: TokenStream,
|
||||||
|
) -> syn::Result<TokenStream> {
|
||||||
|
fn parse_evaluated_cfgs_attr<R>(
|
||||||
|
input: ParseStream,
|
||||||
|
parse_inner: impl FnOnce(ParseStream) -> syn::Result<R>,
|
||||||
|
) -> syn::Result<R> {
|
||||||
|
let _: Token![#] = input.parse()?;
|
||||||
|
let bracket_content;
|
||||||
|
bracketed!(bracket_content in input);
|
||||||
|
let _: kw::__evaluated_cfgs = bracket_content.parse()?;
|
||||||
|
let paren_content;
|
||||||
|
parenthesized!(paren_content in bracket_content);
|
||||||
|
parse_inner(&paren_content)
|
||||||
|
}
|
||||||
|
let (evaluated_cfgs, item): (_, TokenStream) = Parser::parse2(
|
||||||
|
|input: ParseStream| {
|
||||||
|
let peek = input.fork();
|
||||||
|
if parse_evaluated_cfgs_attr(&peek, |_| Ok(())).is_ok() {
|
||||||
|
let evaluated_cfgs = parse_evaluated_cfgs_attr(input, Cfgs::<bool>::parse)?;
|
||||||
|
Ok((Some(evaluated_cfgs), input.parse()?))
|
||||||
|
} else {
|
||||||
|
Ok((None, input.parse()?))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
item,
|
||||||
|
)?;
|
||||||
|
let cfgs = if let Some(cfgs) = evaluated_cfgs {
|
||||||
|
cfgs
|
||||||
|
} else {
|
||||||
|
let cfgs = process_cfg::collect_cfgs(syn::parse2(item.clone())?)?;
|
||||||
|
if cfgs.cfgs_list.is_empty() {
|
||||||
|
Cfgs::default()
|
||||||
|
} else {
|
||||||
|
return Ok(quote! {
|
||||||
|
::fayalite::__cfg_expansion_helper! {
|
||||||
|
[]
|
||||||
|
#cfgs
|
||||||
|
{#[::fayalite::#kw(#attr)]} { #item }
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let item = syn::parse2(quote! { #[#kw(#attr)] #item })?;
|
||||||
|
let Some(item) = process_cfg::process_cfgs(item, cfgs)? else {
|
||||||
|
return Ok(TokenStream::new());
|
||||||
|
};
|
||||||
match item {
|
match item {
|
||||||
Item::Enum(item) => hdl_enum::hdl_enum(item),
|
Item::Enum(item) => hdl_enum::hdl_enum(item),
|
||||||
Item::Struct(item) => hdl_bundle::hdl_bundle(item),
|
Item::Struct(item) => hdl_bundle::hdl_bundle(item),
|
||||||
|
@ -921,3 +1266,11 @@ pub fn hdl_attr(attr: TokenStream, item: TokenStream) -> syn::Result<TokenStream
|
||||||
)),
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn hdl_module(attr: TokenStream, item: TokenStream) -> syn::Result<TokenStream> {
|
||||||
|
hdl_main(kw::hdl_module::default(), attr, item)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn hdl_attr(attr: TokenStream, item: TokenStream) -> syn::Result<TokenStream> {
|
||||||
|
hdl_main(kw::hdl::default(), attr, item)
|
||||||
|
}
|
||||||
|
|
|
@ -1109,7 +1109,7 @@ fn parse_quote_let_pat<T, R: ToTokens, C: Borrow<Token![:]>>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn wrap_ty_with_expr(ty: impl ToTokens) -> Type {
|
pub(crate) fn wrap_ty_with_expr(ty: impl ToTokens) -> Type {
|
||||||
parse_quote_spanned! {ty.span()=>
|
parse_quote_spanned! {ty.span()=>
|
||||||
::fayalite::expr::Expr<#ty>
|
::fayalite::expr::Expr<#ty>
|
||||||
}
|
}
|
||||||
|
@ -1586,7 +1586,7 @@ impl Visitor<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn empty_let() -> Local {
|
pub(crate) fn empty_let() -> Local {
|
||||||
Local {
|
Local {
|
||||||
attrs: vec![],
|
attrs: vec![],
|
||||||
let_token: Default::default(),
|
let_token: Default::default(),
|
||||||
|
@ -1672,7 +1672,7 @@ impl Fold for Visitor<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fold_local(&mut self, let_stmt: Local) -> Local {
|
fn fold_local(&mut self, mut let_stmt: Local) -> Local {
|
||||||
match self
|
match self
|
||||||
.errors
|
.errors
|
||||||
.ok(HdlAttr::<Nothing, kw::hdl>::parse_and_leave_attr(
|
.ok(HdlAttr::<Nothing, kw::hdl>::parse_and_leave_attr(
|
||||||
|
@ -1682,6 +1682,25 @@ impl Fold for Visitor<'_> {
|
||||||
Some(None) => return fold_local(self, let_stmt),
|
Some(None) => return fold_local(self, let_stmt),
|
||||||
Some(Some(HdlAttr { .. })) => {}
|
Some(Some(HdlAttr { .. })) => {}
|
||||||
};
|
};
|
||||||
|
let mut pat = &let_stmt.pat;
|
||||||
|
if let Pat::Type(pat_type) = pat {
|
||||||
|
pat = &pat_type.pat;
|
||||||
|
}
|
||||||
|
let Pat::Ident(syn::PatIdent {
|
||||||
|
attrs: _,
|
||||||
|
by_ref: None,
|
||||||
|
mutability: _,
|
||||||
|
ident: _,
|
||||||
|
subpat: None,
|
||||||
|
}) = pat
|
||||||
|
else {
|
||||||
|
let hdl_attr = HdlAttr::<Nothing, kw::hdl>::parse_and_take_attr(&mut let_stmt.attrs)
|
||||||
|
.ok()
|
||||||
|
.flatten()
|
||||||
|
.expect("already checked above");
|
||||||
|
let let_stmt = fold_local(self, let_stmt);
|
||||||
|
return self.process_hdl_let_pat(hdl_attr, let_stmt);
|
||||||
|
};
|
||||||
let hdl_let = syn::parse2::<HdlLet<HdlLetKind<Type>>>(let_stmt.into_token_stream());
|
let hdl_let = syn::parse2::<HdlLet<HdlLetKind<Type>>>(let_stmt.into_token_stream());
|
||||||
let Some(hdl_let) = self.errors.ok(hdl_let) else {
|
let Some(hdl_let) = self.errors.ok(hdl_let) else {
|
||||||
return empty_let();
|
return empty_let();
|
||||||
|
|
|
@ -3,22 +3,111 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
fold::{impl_fold, DoFold},
|
fold::{impl_fold, DoFold},
|
||||||
kw,
|
kw,
|
||||||
module::transform_body::{with_debug_clone_and_fold, Visitor},
|
module::transform_body::{empty_let, with_debug_clone_and_fold, wrap_ty_with_expr, Visitor},
|
||||||
Errors, HdlAttr, PairsIterExt,
|
Errors, HdlAttr, PairsIterExt,
|
||||||
};
|
};
|
||||||
use proc_macro2::{Span, TokenStream};
|
use proc_macro2::{Span, TokenStream};
|
||||||
use quote::{format_ident, quote_spanned, ToTokens, TokenStreamExt};
|
use quote::{format_ident, quote_spanned, ToTokens, TokenStreamExt};
|
||||||
|
use std::collections::BTreeSet;
|
||||||
use syn::{
|
use syn::{
|
||||||
fold::{fold_arm, fold_expr_match, fold_pat, Fold},
|
fold::{fold_arm, fold_expr_match, fold_local, fold_pat, Fold},
|
||||||
parse::Nothing,
|
parse::Nothing,
|
||||||
parse_quote_spanned,
|
parse_quote_spanned,
|
||||||
punctuated::Punctuated,
|
punctuated::Punctuated,
|
||||||
spanned::Spanned,
|
spanned::Spanned,
|
||||||
token::{Brace, Paren},
|
token::{Brace, Paren},
|
||||||
Arm, Attribute, Expr, ExprMatch, FieldPat, Ident, Member, Pat, PatIdent, PatOr, PatParen,
|
Arm, Attribute, Expr, ExprMatch, FieldPat, Ident, Local, Member, Pat, PatIdent, PatOr,
|
||||||
PatPath, PatRest, PatStruct, PatTupleStruct, PatWild, Path, PathSegment, Token, TypePath,
|
PatParen, PatPath, PatRest, PatStruct, PatTuple, PatTupleStruct, PatWild, Path, PathSegment,
|
||||||
|
Token, TypePath,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
macro_rules! visit_trait {
|
||||||
|
(
|
||||||
|
$($vis:vis fn $fn:ident($state:ident: _, $value:ident: &$Value:ty) $block:block)*
|
||||||
|
) => {
|
||||||
|
trait VisitMatchPat<'a> {
|
||||||
|
$(fn $fn(&mut self, $value: &'a $Value) {
|
||||||
|
$fn(self, $value);
|
||||||
|
})*
|
||||||
|
}
|
||||||
|
|
||||||
|
$($vis fn $fn<'a>($state: &mut (impl ?Sized + VisitMatchPat<'a>), $value: &'a $Value) $block)*
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
visit_trait! {
|
||||||
|
fn visit_match_pat_binding(_state: _, v: &MatchPatBinding) {
|
||||||
|
let MatchPatBinding { ident: _ } = v;
|
||||||
|
}
|
||||||
|
fn visit_match_pat_wild(_state: _, v: &MatchPatWild) {
|
||||||
|
let MatchPatWild { underscore_token: _ } = v;
|
||||||
|
}
|
||||||
|
fn visit_match_pat_rest(_state: _, v: &MatchPatRest) {
|
||||||
|
let MatchPatRest { dot2_token: _ } = v;
|
||||||
|
}
|
||||||
|
fn visit_match_pat_paren(state: _, v: &MatchPatParen<MatchPat>) {
|
||||||
|
let MatchPatParen { paren_token: _, pat } = v;
|
||||||
|
state.visit_match_pat(pat);
|
||||||
|
}
|
||||||
|
fn visit_match_pat_paren_simple(state: _, v: &MatchPatParen<MatchPatSimple>) {
|
||||||
|
let MatchPatParen { paren_token: _, pat } = v;
|
||||||
|
state.visit_match_pat_simple(pat);
|
||||||
|
}
|
||||||
|
fn visit_match_pat_or(state: _, v: &MatchPatOr<MatchPat>) {
|
||||||
|
let MatchPatOr { leading_vert: _, cases } = v;
|
||||||
|
for v in cases {
|
||||||
|
state.visit_match_pat(v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn visit_match_pat_or_simple(state: _, v: &MatchPatOr<MatchPatSimple>) {
|
||||||
|
let MatchPatOr { leading_vert: _, cases } = v;
|
||||||
|
for v in cases {
|
||||||
|
state.visit_match_pat_simple(v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn visit_match_pat_struct_field(state: _, v: &MatchPatStructField) {
|
||||||
|
let MatchPatStructField { field_name: _, colon_token: _, pat } = v;
|
||||||
|
state.visit_match_pat_simple(pat);
|
||||||
|
}
|
||||||
|
fn visit_match_pat_struct(state: _, v: &MatchPatStruct) {
|
||||||
|
let MatchPatStruct { match_span: _, path: _, brace_token: _, fields, rest: _ } = v;
|
||||||
|
for v in fields {
|
||||||
|
state.visit_match_pat_struct_field(v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn visit_match_pat_tuple(state: _, v: &MatchPatTuple) {
|
||||||
|
let MatchPatTuple { paren_token: _, fields } = v;
|
||||||
|
for v in fields {
|
||||||
|
state.visit_match_pat_simple(v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn visit_match_pat_enum_variant(state: _, v: &MatchPatEnumVariant) {
|
||||||
|
let MatchPatEnumVariant {match_span:_, variant_path: _, enum_path: _, variant_name: _, field } = v;
|
||||||
|
if let Some((_, v)) = field {
|
||||||
|
state.visit_match_pat_simple(v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn visit_match_pat_simple(state: _, v: &MatchPatSimple) {
|
||||||
|
match v {
|
||||||
|
MatchPatSimple::Paren(v) => state.visit_match_pat_paren_simple(v),
|
||||||
|
MatchPatSimple::Or(v) => state.visit_match_pat_or_simple(v),
|
||||||
|
MatchPatSimple::Binding(v) => state.visit_match_pat_binding(v),
|
||||||
|
MatchPatSimple::Wild(v) => state.visit_match_pat_wild(v),
|
||||||
|
MatchPatSimple::Rest(v) => state.visit_match_pat_rest(v),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn visit_match_pat(state: _, v: &MatchPat) {
|
||||||
|
match v {
|
||||||
|
MatchPat::Simple(v) => state.visit_match_pat_simple(v),
|
||||||
|
MatchPat::Or(v) => state.visit_match_pat_or(v),
|
||||||
|
MatchPat::Paren(v) => state.visit_match_pat_paren(v),
|
||||||
|
MatchPat::Struct(v) => state.visit_match_pat_struct(v),
|
||||||
|
MatchPat::Tuple(v) => state.visit_match_pat_tuple(v),
|
||||||
|
MatchPat::EnumVariant(v) => state.visit_match_pat_enum_variant(v),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
with_debug_clone_and_fold! {
|
with_debug_clone_and_fold! {
|
||||||
struct MatchPatBinding<> {
|
struct MatchPatBinding<> {
|
||||||
ident: Ident,
|
ident: Ident,
|
||||||
|
@ -53,6 +142,15 @@ with_debug_clone_and_fold! {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<P> MatchPatOr<P> {
|
||||||
|
/// returns the first `|` between two patterns
|
||||||
|
fn first_inner_vert(&self) -> Option<Token![|]> {
|
||||||
|
let mut pairs = self.cases.pairs();
|
||||||
|
pairs.next_back();
|
||||||
|
pairs.next().and_then(|v| v.into_tuple().1.copied())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<P: ToTokens> ToTokens for MatchPatOr<P> {
|
impl<P: ToTokens> ToTokens for MatchPatOr<P> {
|
||||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||||
let Self {
|
let Self {
|
||||||
|
@ -77,6 +175,19 @@ impl ToTokens for MatchPatWild {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
with_debug_clone_and_fold! {
|
||||||
|
struct MatchPatRest<> {
|
||||||
|
dot2_token: Token![..],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToTokens for MatchPatRest {
|
||||||
|
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||||
|
let Self { dot2_token } = self;
|
||||||
|
dot2_token.to_tokens(tokens);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
with_debug_clone_and_fold! {
|
with_debug_clone_and_fold! {
|
||||||
struct MatchPatStructField<> {
|
struct MatchPatStructField<> {
|
||||||
field_name: Ident,
|
field_name: Ident,
|
||||||
|
@ -159,6 +270,25 @@ impl ToTokens for MatchPatStruct {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
with_debug_clone_and_fold! {
|
||||||
|
struct MatchPatTuple<> {
|
||||||
|
paren_token: Paren,
|
||||||
|
fields: Punctuated<MatchPatSimple, Token![,]>,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToTokens for MatchPatTuple {
|
||||||
|
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||||
|
let Self {
|
||||||
|
paren_token,
|
||||||
|
fields,
|
||||||
|
} = self;
|
||||||
|
paren_token.surround(tokens, |tokens| {
|
||||||
|
fields.to_tokens(tokens);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
with_debug_clone_and_fold! {
|
with_debug_clone_and_fold! {
|
||||||
struct MatchPatEnumVariant<> {
|
struct MatchPatEnumVariant<> {
|
||||||
match_span: Span,
|
match_span: Span,
|
||||||
|
@ -194,6 +324,7 @@ enum MatchPatSimple {
|
||||||
Or(MatchPatOr<MatchPatSimple>),
|
Or(MatchPatOr<MatchPatSimple>),
|
||||||
Binding(MatchPatBinding),
|
Binding(MatchPatBinding),
|
||||||
Wild(MatchPatWild),
|
Wild(MatchPatWild),
|
||||||
|
Rest(MatchPatRest),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_fold! {
|
impl_fold! {
|
||||||
|
@ -202,6 +333,7 @@ impl_fold! {
|
||||||
Or(MatchPatOr<MatchPatSimple>),
|
Or(MatchPatOr<MatchPatSimple>),
|
||||||
Binding(MatchPatBinding),
|
Binding(MatchPatBinding),
|
||||||
Wild(MatchPatWild),
|
Wild(MatchPatWild),
|
||||||
|
Rest(MatchPatRest),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -212,6 +344,7 @@ impl ToTokens for MatchPatSimple {
|
||||||
Self::Paren(v) => v.to_tokens(tokens),
|
Self::Paren(v) => v.to_tokens(tokens),
|
||||||
Self::Binding(v) => v.to_tokens(tokens),
|
Self::Binding(v) => v.to_tokens(tokens),
|
||||||
Self::Wild(v) => v.to_tokens(tokens),
|
Self::Wild(v) => v.to_tokens(tokens),
|
||||||
|
Self::Rest(v) => v.to_tokens(tokens),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -278,6 +411,7 @@ trait ParseMatchPat: Sized {
|
||||||
fn or(v: MatchPatOr<Self>) -> Self;
|
fn or(v: MatchPatOr<Self>) -> Self;
|
||||||
fn paren(v: MatchPatParen<Self>) -> Self;
|
fn paren(v: MatchPatParen<Self>) -> Self;
|
||||||
fn struct_(state: &mut HdlMatchParseState<'_>, v: MatchPatStruct) -> Result<Self, ()>;
|
fn struct_(state: &mut HdlMatchParseState<'_>, v: MatchPatStruct) -> Result<Self, ()>;
|
||||||
|
fn tuple(state: &mut HdlMatchParseState<'_>, v: MatchPatTuple) -> Result<Self, ()>;
|
||||||
fn enum_variant(state: &mut HdlMatchParseState<'_>, v: MatchPatEnumVariant)
|
fn enum_variant(state: &mut HdlMatchParseState<'_>, v: MatchPatEnumVariant)
|
||||||
-> Result<Self, ()>;
|
-> Result<Self, ()>;
|
||||||
fn parse(state: &mut HdlMatchParseState<'_>, pat: Pat) -> Result<Self, ()> {
|
fn parse(state: &mut HdlMatchParseState<'_>, pat: Pat) -> Result<Self, ()> {
|
||||||
|
@ -462,7 +596,34 @@ trait ParseMatchPat: Sized {
|
||||||
}) => Ok(Self::simple(MatchPatSimple::Wild(MatchPatWild {
|
}) => Ok(Self::simple(MatchPatSimple::Wild(MatchPatWild {
|
||||||
underscore_token,
|
underscore_token,
|
||||||
}))),
|
}))),
|
||||||
Pat::Tuple(_) | Pat::Slice(_) | Pat::Const(_) | Pat::Lit(_) | Pat::Range(_) => {
|
Pat::Tuple(PatTuple {
|
||||||
|
attrs: _,
|
||||||
|
paren_token,
|
||||||
|
elems,
|
||||||
|
}) => {
|
||||||
|
let fields = elems
|
||||||
|
.into_pairs()
|
||||||
|
.filter_map_pair_value(|field_pat| {
|
||||||
|
if let Pat::Rest(PatRest {
|
||||||
|
attrs: _,
|
||||||
|
dot2_token,
|
||||||
|
}) = field_pat
|
||||||
|
{
|
||||||
|
Some(MatchPatSimple::Rest(MatchPatRest { dot2_token }))
|
||||||
|
} else {
|
||||||
|
MatchPatSimple::parse(state, field_pat).ok()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
Self::tuple(
|
||||||
|
state,
|
||||||
|
MatchPatTuple {
|
||||||
|
paren_token,
|
||||||
|
fields,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Pat::Slice(_) | Pat::Const(_) | Pat::Lit(_) | Pat::Range(_) => {
|
||||||
state
|
state
|
||||||
.errors
|
.errors
|
||||||
.error(pat, "not yet implemented in #[hdl] patterns");
|
.error(pat, "not yet implemented in #[hdl] patterns");
|
||||||
|
@ -497,6 +658,14 @@ impl ParseMatchPat for MatchPatSimple {
|
||||||
Err(())
|
Err(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn tuple(state: &mut HdlMatchParseState<'_>, v: MatchPatTuple) -> Result<Self, ()> {
|
||||||
|
state.errors.push(syn::Error::new(
|
||||||
|
v.paren_token.span.open(),
|
||||||
|
"matching tuples is not yet implemented inside structs/enums in #[hdl] patterns",
|
||||||
|
));
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
|
||||||
fn enum_variant(
|
fn enum_variant(
|
||||||
state: &mut HdlMatchParseState<'_>,
|
state: &mut HdlMatchParseState<'_>,
|
||||||
v: MatchPatEnumVariant,
|
v: MatchPatEnumVariant,
|
||||||
|
@ -515,6 +684,7 @@ enum MatchPat {
|
||||||
Or(MatchPatOr<MatchPat>),
|
Or(MatchPatOr<MatchPat>),
|
||||||
Paren(MatchPatParen<MatchPat>),
|
Paren(MatchPatParen<MatchPat>),
|
||||||
Struct(MatchPatStruct),
|
Struct(MatchPatStruct),
|
||||||
|
Tuple(MatchPatTuple),
|
||||||
EnumVariant(MatchPatEnumVariant),
|
EnumVariant(MatchPatEnumVariant),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -524,6 +694,7 @@ impl_fold! {
|
||||||
Or(MatchPatOr<MatchPat>),
|
Or(MatchPatOr<MatchPat>),
|
||||||
Paren(MatchPatParen<MatchPat>),
|
Paren(MatchPatParen<MatchPat>),
|
||||||
Struct(MatchPatStruct),
|
Struct(MatchPatStruct),
|
||||||
|
Tuple(MatchPatTuple),
|
||||||
EnumVariant(MatchPatEnumVariant),
|
EnumVariant(MatchPatEnumVariant),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -545,6 +716,10 @@ impl ParseMatchPat for MatchPat {
|
||||||
Ok(Self::Struct(v))
|
Ok(Self::Struct(v))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn tuple(_state: &mut HdlMatchParseState<'_>, v: MatchPatTuple) -> Result<Self, ()> {
|
||||||
|
Ok(Self::Tuple(v))
|
||||||
|
}
|
||||||
|
|
||||||
fn enum_variant(
|
fn enum_variant(
|
||||||
_state: &mut HdlMatchParseState<'_>,
|
_state: &mut HdlMatchParseState<'_>,
|
||||||
v: MatchPatEnumVariant,
|
v: MatchPatEnumVariant,
|
||||||
|
@ -560,6 +735,7 @@ impl ToTokens for MatchPat {
|
||||||
Self::Or(v) => v.to_tokens(tokens),
|
Self::Or(v) => v.to_tokens(tokens),
|
||||||
Self::Paren(v) => v.to_tokens(tokens),
|
Self::Paren(v) => v.to_tokens(tokens),
|
||||||
Self::Struct(v) => v.to_tokens(tokens),
|
Self::Struct(v) => v.to_tokens(tokens),
|
||||||
|
Self::Tuple(v) => v.to_tokens(tokens),
|
||||||
Self::EnumVariant(v) => v.to_tokens(tokens),
|
Self::EnumVariant(v) => v.to_tokens(tokens),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -622,10 +798,6 @@ struct RewriteAsCheckMatch {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Fold for RewriteAsCheckMatch {
|
impl Fold for RewriteAsCheckMatch {
|
||||||
fn fold_field_pat(&mut self, mut i: FieldPat) -> FieldPat {
|
|
||||||
i.colon_token = Some(Token));
|
|
||||||
i
|
|
||||||
}
|
|
||||||
fn fold_pat(&mut self, pat: Pat) -> Pat {
|
fn fold_pat(&mut self, pat: Pat) -> Pat {
|
||||||
match pat {
|
match pat {
|
||||||
Pat::Ident(mut pat_ident) => match parse_enum_ident(pat_ident.ident) {
|
Pat::Ident(mut pat_ident) => match parse_enum_ident(pat_ident.ident) {
|
||||||
|
@ -740,6 +912,30 @@ impl Fold for RewriteAsCheckMatch {
|
||||||
// don't recurse into expressions
|
// don't recurse into expressions
|
||||||
i
|
i
|
||||||
}
|
}
|
||||||
|
fn fold_local(&mut self, mut let_stmt: Local) -> Local {
|
||||||
|
if let Some(syn::LocalInit {
|
||||||
|
eq_token,
|
||||||
|
expr: _,
|
||||||
|
diverge,
|
||||||
|
}) = let_stmt.init.take()
|
||||||
|
{
|
||||||
|
let_stmt.init = Some(syn::LocalInit {
|
||||||
|
eq_token,
|
||||||
|
expr: parse_quote_spanned! {self.span=>
|
||||||
|
__match_value
|
||||||
|
},
|
||||||
|
diverge: diverge.map(|(else_, _expr)| {
|
||||||
|
(
|
||||||
|
else_,
|
||||||
|
parse_quote_spanned! {self.span=>
|
||||||
|
match __infallible {}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
fold_local(self, let_stmt)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct HdlMatchParseState<'a> {
|
struct HdlMatchParseState<'a> {
|
||||||
|
@ -747,7 +943,123 @@ struct HdlMatchParseState<'a> {
|
||||||
errors: &'a mut Errors,
|
errors: &'a mut Errors,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct HdlLetPatVisitState<'a> {
|
||||||
|
errors: &'a mut Errors,
|
||||||
|
bindings: BTreeSet<&'a Ident>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> VisitMatchPat<'a> for HdlLetPatVisitState<'a> {
|
||||||
|
fn visit_match_pat_binding(&mut self, v: &'a MatchPatBinding) {
|
||||||
|
self.bindings.insert(&v.ident);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_match_pat_or(&mut self, v: &'a MatchPatOr<MatchPat>) {
|
||||||
|
if let Some(first_inner_vert) = v.first_inner_vert() {
|
||||||
|
self.errors.error(
|
||||||
|
first_inner_vert,
|
||||||
|
"or-patterns are not supported in let statements",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
visit_match_pat_or(self, v);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_match_pat_or_simple(&mut self, v: &'a MatchPatOr<MatchPatSimple>) {
|
||||||
|
if let Some(first_inner_vert) = v.first_inner_vert() {
|
||||||
|
self.errors.error(
|
||||||
|
first_inner_vert,
|
||||||
|
"or-patterns are not supported in let statements",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
visit_match_pat_or_simple(self, v);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_match_pat_enum_variant(&mut self, v: &'a MatchPatEnumVariant) {
|
||||||
|
self.errors.error(v, "refutable pattern in let statement");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Visitor<'_> {
|
impl Visitor<'_> {
|
||||||
|
pub(crate) fn process_hdl_let_pat(
|
||||||
|
&mut self,
|
||||||
|
_hdl_attr: HdlAttr<Nothing, kw::hdl>,
|
||||||
|
mut let_stmt: Local,
|
||||||
|
) -> Local {
|
||||||
|
let span = let_stmt.let_token.span();
|
||||||
|
if let Pat::Type(pat) = &mut let_stmt.pat {
|
||||||
|
*pat.ty = wrap_ty_with_expr((*pat.ty).clone());
|
||||||
|
}
|
||||||
|
let check_let_stmt = RewriteAsCheckMatch { span }.fold_local(let_stmt.clone());
|
||||||
|
let Local {
|
||||||
|
attrs: _,
|
||||||
|
let_token,
|
||||||
|
pat,
|
||||||
|
init,
|
||||||
|
semi_token,
|
||||||
|
} = let_stmt;
|
||||||
|
self.require_normal_module_or_fn(let_token);
|
||||||
|
let Some(syn::LocalInit {
|
||||||
|
eq_token,
|
||||||
|
expr,
|
||||||
|
diverge,
|
||||||
|
}) = init
|
||||||
|
else {
|
||||||
|
self.errors
|
||||||
|
.error(let_token, "#[hdl] let must be assigned a value");
|
||||||
|
return empty_let();
|
||||||
|
};
|
||||||
|
if let Some((else_, _)) = diverge {
|
||||||
|
// TODO: implement let-else
|
||||||
|
self.errors
|
||||||
|
.error(else_, "#[hdl] let ... else { ... } is not implemented");
|
||||||
|
return empty_let();
|
||||||
|
}
|
||||||
|
let Ok(pat) = MatchPat::parse(
|
||||||
|
&mut HdlMatchParseState {
|
||||||
|
match_span: span,
|
||||||
|
errors: &mut self.errors,
|
||||||
|
},
|
||||||
|
pat,
|
||||||
|
) else {
|
||||||
|
return empty_let();
|
||||||
|
};
|
||||||
|
let mut state = HdlLetPatVisitState {
|
||||||
|
errors: &mut self.errors,
|
||||||
|
bindings: BTreeSet::new(),
|
||||||
|
};
|
||||||
|
state.visit_match_pat(&pat);
|
||||||
|
let HdlLetPatVisitState {
|
||||||
|
errors: _,
|
||||||
|
bindings,
|
||||||
|
} = state;
|
||||||
|
let retval = parse_quote_spanned! {span=>
|
||||||
|
let (#(#bindings,)* __scope,) = {
|
||||||
|
type __MatchTy<T> = <T as ::fayalite::ty::Type>::MatchVariant;
|
||||||
|
let __match_expr = ::fayalite::expr::ToExpr::to_expr(&(#expr));
|
||||||
|
::fayalite::expr::check_match_expr(__match_expr, |__match_value, __infallible| {
|
||||||
|
#[allow(unused_variables)]
|
||||||
|
#check_let_stmt
|
||||||
|
match __infallible {}
|
||||||
|
});
|
||||||
|
let mut __match_iter = ::fayalite::module::match_(__match_expr);
|
||||||
|
let ::fayalite::__std::option::Option::Some(__match_variant) = ::fayalite::__std::iter::Iterator::next(&mut __match_iter) else {
|
||||||
|
::fayalite::__std::unreachable!("#[hdl] let with uninhabited type");
|
||||||
|
};
|
||||||
|
let ::fayalite::__std::option::Option::None = ::fayalite::__std::iter::Iterator::next(&mut __match_iter) else {
|
||||||
|
::fayalite::__std::unreachable!("#[hdl] let with refutable pattern");
|
||||||
|
};
|
||||||
|
let (__match_variant, __scope) =
|
||||||
|
::fayalite::ty::MatchVariantAndInactiveScope::match_activate_scope(
|
||||||
|
__match_variant,
|
||||||
|
);
|
||||||
|
#let_token #pat #eq_token __match_variant #semi_token
|
||||||
|
(#(#bindings,)* __scope,)
|
||||||
|
};
|
||||||
|
};
|
||||||
|
match retval {
|
||||||
|
syn::Stmt::Local(retval) => retval,
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
pub(crate) fn process_hdl_match(
|
pub(crate) fn process_hdl_match(
|
||||||
&mut self,
|
&mut self,
|
||||||
_hdl_attr: HdlAttr<Nothing, kw::hdl>,
|
_hdl_attr: HdlAttr<Nothing, kw::hdl>,
|
||||||
|
|
2527
crates/fayalite-proc-macros-impl/src/process_cfg.rs
Normal file
2527
crates/fayalite-proc-macros-impl/src/process_cfg.rs
Normal file
File diff suppressed because it is too large
Load diff
|
@ -25,9 +25,11 @@ jobslot.workspace = true
|
||||||
num-bigint.workspace = true
|
num-bigint.workspace = true
|
||||||
num-traits.workspace = true
|
num-traits.workspace = true
|
||||||
os_pipe.workspace = true
|
os_pipe.workspace = true
|
||||||
|
petgraph.workspace = true
|
||||||
serde_json.workspace = true
|
serde_json.workspace = true
|
||||||
serde.workspace = true
|
serde.workspace = true
|
||||||
tempfile.workspace = true
|
tempfile.workspace = true
|
||||||
|
vec_map.workspace = true
|
||||||
which.workspace = true
|
which.workspace = true
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
|
|
@ -5,6 +5,9 @@ use std::{env, fs, path::Path};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
println!("cargo::rustc-check-cfg=cfg(todo)");
|
println!("cargo::rustc-check-cfg=cfg(todo)");
|
||||||
|
println!("cargo::rustc-check-cfg=cfg(cfg_false_for_tests)");
|
||||||
|
println!("cargo::rustc-check-cfg=cfg(cfg_true_for_tests)");
|
||||||
|
println!("cargo::rustc-cfg=cfg_true_for_tests");
|
||||||
let path = "visit_types.json";
|
let path = "visit_types.json";
|
||||||
println!("cargo::rerun-if-changed={path}");
|
println!("cargo::rerun-if-changed={path}");
|
||||||
println!("cargo::rerun-if-changed=build.rs");
|
println!("cargo::rerun-if-changed=build.rs");
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
// See Notices.txt for copyright information
|
// See Notices.txt for copyright information
|
||||||
//! ## `#[hdl] let` statements
|
//! ## `#[hdl] let` statements
|
||||||
|
|
||||||
|
pub mod destructuring;
|
||||||
pub mod inputs_outputs;
|
pub mod inputs_outputs;
|
||||||
pub mod instances;
|
pub mod instances;
|
||||||
pub mod memories;
|
pub mod memories;
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
|
// See Notices.txt for copyright information
|
||||||
|
//! ### Destructuring Let
|
||||||
|
//!
|
||||||
|
//! You can use `#[hdl] let` to destructure types, similarly to Rust `let` statements with non-trivial patterns.
|
||||||
|
//!
|
||||||
|
//! `#[hdl] let` statements can only match one level of struct/tuple pattern for now,
|
||||||
|
//! e.g. you can match with the pattern `MyStruct { a, b }`, but not `MyStruct { a, b: Struct2 { v } }`.
|
||||||
|
//!
|
||||||
|
//! ```
|
||||||
|
//! # use fayalite::prelude::*;
|
||||||
|
//! #[hdl]
|
||||||
|
//! struct MyStruct {
|
||||||
|
//! a: UInt<8>,
|
||||||
|
//! b: Bool,
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! #[hdl_module]
|
||||||
|
//! fn my_module() {
|
||||||
|
//! #[hdl]
|
||||||
|
//! let my_input: MyStruct = m.input();
|
||||||
|
//! #[hdl]
|
||||||
|
//! let my_output: UInt<8> = m.input();
|
||||||
|
//! #[hdl]
|
||||||
|
//! let MyStruct { a, b } = my_input;
|
||||||
|
//! #[hdl]
|
||||||
|
//! if b {
|
||||||
|
//! connect(my_output, a);
|
||||||
|
//! } else {
|
||||||
|
//! connect(my_output, 0_hdl_u8);
|
||||||
|
//! }
|
||||||
|
//! }
|
||||||
|
//! ```
|
|
@ -7,5 +7,5 @@
|
||||||
//!
|
//!
|
||||||
//! `#[hdl] match` statements' bodies must evaluate to type `()` for now.
|
//! `#[hdl] match` statements' bodies must evaluate to type `()` for now.
|
||||||
//!
|
//!
|
||||||
//! `#[hdl] match` statements can only match one level of struct/enum pattern for now,
|
//! `#[hdl] match` statements can only match one level of struct/tuple/enum pattern for now,
|
||||||
//! e.g. you can match with the pattern `HdlSome(v)`, but not `HdlSome(HdlSome(_))`.
|
//! e.g. you can match with the pattern `HdlSome(v)`, but not `HdlSome(HdlSome(_))`.
|
||||||
|
|
|
@ -2,8 +2,11 @@
|
||||||
// See Notices.txt for copyright information
|
// See Notices.txt for copyright information
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
expr::{ops::ArrayIndex, Expr, ToExpr},
|
expr::{
|
||||||
int::{DynSize, KnownSize, Size, SizeType, DYN_SIZE},
|
ops::{ArrayIndex, ArrayLiteral, ExprPartialEq},
|
||||||
|
CastToBits, Expr, HdlPartialEq, ReduceBits, ToExpr,
|
||||||
|
},
|
||||||
|
int::{Bool, DynSize, KnownSize, Size, SizeType, DYN_SIZE},
|
||||||
intern::{Intern, Interned, LazyInterned},
|
intern::{Intern, Interned, LazyInterned},
|
||||||
module::transform::visit::{Fold, Folder, Visit, Visitor},
|
module::transform::visit::{Fold, Folder, Visit, Visitor},
|
||||||
source_location::SourceLocation,
|
source_location::SourceLocation,
|
||||||
|
@ -218,3 +221,36 @@ impl<T: Type, L: SizeType> Index<L> for ArrayWithoutLen<T> {
|
||||||
Interned::into_inner(Intern::intern_sized(ArrayType::new(self.element, len)))
|
Interned::into_inner(Intern::intern_sized(ArrayType::new(self.element, len)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<Lhs: Type, Rhs: Type, Len: Size> ExprPartialEq<ArrayType<Rhs, Len>> for ArrayType<Lhs, Len>
|
||||||
|
where
|
||||||
|
Lhs: ExprPartialEq<Rhs>,
|
||||||
|
{
|
||||||
|
fn cmp_eq(lhs: Expr<Self>, rhs: Expr<ArrayType<Rhs, Len>>) -> Expr<Bool> {
|
||||||
|
let lhs_ty = Expr::ty(lhs);
|
||||||
|
let rhs_ty = Expr::ty(rhs);
|
||||||
|
assert_eq!(lhs_ty.len(), rhs_ty.len());
|
||||||
|
ArrayLiteral::<Bool, DynSize>::new(
|
||||||
|
Bool,
|
||||||
|
(0..lhs_ty.len())
|
||||||
|
.map(|i| Expr::canonical(lhs[i].cmp_eq(rhs[i])))
|
||||||
|
.collect(),
|
||||||
|
)
|
||||||
|
.cast_to_bits()
|
||||||
|
.all_one_bits()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cmp_ne(lhs: Expr<Self>, rhs: Expr<ArrayType<Rhs, Len>>) -> Expr<Bool> {
|
||||||
|
let lhs_ty = Expr::ty(lhs);
|
||||||
|
let rhs_ty = Expr::ty(rhs);
|
||||||
|
assert_eq!(lhs_ty.len(), rhs_ty.len());
|
||||||
|
ArrayLiteral::<Bool, DynSize>::new(
|
||||||
|
Bool,
|
||||||
|
(0..lhs_ty.len())
|
||||||
|
.map(|i| Expr::canonical(lhs[i].cmp_ne(rhs[i])))
|
||||||
|
.collect(),
|
||||||
|
)
|
||||||
|
.cast_to_bits()
|
||||||
|
.any_one_bits()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -2,14 +2,20 @@
|
||||||
// See Notices.txt for copyright information
|
// See Notices.txt for copyright information
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
expr::{ops::BundleLiteral, Expr, ToExpr},
|
expr::{
|
||||||
|
ops::{ArrayLiteral, BundleLiteral, ExprPartialEq},
|
||||||
|
CastToBits, Expr, ReduceBits, ToExpr,
|
||||||
|
},
|
||||||
|
int::{Bool, DynSize},
|
||||||
intern::{Intern, Interned},
|
intern::{Intern, Interned},
|
||||||
|
sim::{SimValue, ToSimValue},
|
||||||
source_location::SourceLocation,
|
source_location::SourceLocation,
|
||||||
ty::{
|
ty::{
|
||||||
impl_match_variant_as_self, CanonicalType, MatchVariantWithoutScope, StaticType, Type,
|
impl_match_variant_as_self, CanonicalType, MatchVariantWithoutScope, StaticType, Type,
|
||||||
TypeProperties, TypeWithDeref,
|
TypeProperties, TypeWithDeref,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
use bitvec::vec::BitVec;
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
use std::{fmt, marker::PhantomData};
|
use std::{fmt, marker::PhantomData};
|
||||||
|
|
||||||
|
@ -323,7 +329,19 @@ macro_rules! impl_tuple_builder_fields {
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! impl_tuples {
|
macro_rules! impl_tuples {
|
||||||
([$({#[num = $num:literal, field = $field:ident] $var:ident: $T:ident})*] []) => {
|
(
|
||||||
|
[$({
|
||||||
|
#[
|
||||||
|
num = $num:tt,
|
||||||
|
field = $field:ident,
|
||||||
|
ty = $ty_var:ident: $Ty:ident,
|
||||||
|
lhs = $lhs_var:ident: $Lhs:ident,
|
||||||
|
rhs = $rhs_var:ident: $Rhs:ident
|
||||||
|
]
|
||||||
|
$var:ident: $T:ident
|
||||||
|
})*]
|
||||||
|
[]
|
||||||
|
) => {
|
||||||
impl_tuple_builder_fields! {
|
impl_tuple_builder_fields! {
|
||||||
{}
|
{}
|
||||||
[$({
|
[$({
|
||||||
|
@ -423,6 +441,102 @@ macro_rules! impl_tuples {
|
||||||
BundleLiteral::new(ty, field_values[..].intern()).to_expr()
|
BundleLiteral::new(ty, field_values[..].intern()).to_expr()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl<$($T: ToSimValue<CanonicalType>,)*> ToSimValue<CanonicalType> for ($($T,)*) {
|
||||||
|
#[track_caller]
|
||||||
|
fn to_sim_value(&self, ty: CanonicalType) -> SimValue<CanonicalType> {
|
||||||
|
ToSimValue::<Bundle>::to_sim_value(self, Bundle::from_canonical(ty)).into_canonical()
|
||||||
|
}
|
||||||
|
#[track_caller]
|
||||||
|
fn into_sim_value(self, ty: CanonicalType) -> SimValue<CanonicalType>
|
||||||
|
{
|
||||||
|
ToSimValue::<Bundle>::into_sim_value(self, Bundle::from_canonical(ty)).into_canonical()
|
||||||
|
}
|
||||||
|
#[track_caller]
|
||||||
|
fn box_into_sim_value(self: Box<Self>, ty: CanonicalType) -> SimValue<CanonicalType> {
|
||||||
|
ToSimValue::<Bundle>::box_into_sim_value(self, Bundle::from_canonical(ty)).into_canonical()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<$($T: ToSimValue<CanonicalType>,)*> ToSimValue<Bundle> for ($($T,)*) {
|
||||||
|
#[track_caller]
|
||||||
|
fn to_sim_value(&self, ty: Bundle) -> SimValue<Bundle> {
|
||||||
|
let ($($var,)*) = self;
|
||||||
|
let [$($ty_var,)*] = *ty.fields() else {
|
||||||
|
panic!("bundle has wrong number of fields");
|
||||||
|
};
|
||||||
|
$(let $var = $var.to_sim_value($ty_var.ty);)*
|
||||||
|
ToSimValue::into_sim_value(($($var,)*), ty)
|
||||||
|
}
|
||||||
|
#[track_caller]
|
||||||
|
fn into_sim_value(self, ty: Bundle) -> SimValue<Bundle> {
|
||||||
|
#![allow(unused_mut)]
|
||||||
|
#![allow(clippy::unused_unit)]
|
||||||
|
let ($($var,)*) = self;
|
||||||
|
let [$($ty_var,)*] = *ty.fields() else {
|
||||||
|
panic!("bundle has wrong number of fields");
|
||||||
|
};
|
||||||
|
let mut bits: Option<BitVec> = None;
|
||||||
|
$(let $var = $var.into_sim_value($ty_var.ty);
|
||||||
|
assert_eq!($var.ty(), $ty_var.ty);
|
||||||
|
if !$var.bits().is_empty() {
|
||||||
|
if let Some(bits) = &mut bits {
|
||||||
|
bits.extend_from_bitslice($var.bits());
|
||||||
|
} else {
|
||||||
|
let mut $var = $var.into_bits();
|
||||||
|
$var.reserve(ty.type_properties().bit_width - $var.len());
|
||||||
|
bits = Some($var);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)*
|
||||||
|
bits.unwrap_or_else(BitVec::new).into_sim_value(ty)
|
||||||
|
}
|
||||||
|
#[track_caller]
|
||||||
|
fn box_into_sim_value(self: Box<Self>, ty: Bundle) -> SimValue<Bundle> {
|
||||||
|
Self::into_sim_value(*self, ty)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<$($T: ToSimValue<$Ty>, $Ty: Type,)*> ToSimValue<($($Ty,)*)> for ($($T,)*) {
|
||||||
|
#[track_caller]
|
||||||
|
fn to_sim_value(&self, ty: ($($Ty,)*)) -> SimValue<($($Ty,)*)> {
|
||||||
|
let ($($var,)*) = self;
|
||||||
|
let ($($ty_var,)*) = ty;
|
||||||
|
$(let $var = $var.to_sim_value($ty_var).into_canonical();)*
|
||||||
|
SimValue::from_canonical(ToSimValue::into_sim_value(($($var,)*), ty.canonical()))
|
||||||
|
}
|
||||||
|
#[track_caller]
|
||||||
|
fn into_sim_value(self, ty: ($($Ty,)*)) -> SimValue<($($Ty,)*)> {
|
||||||
|
let ($($var,)*) = self;
|
||||||
|
let ($($ty_var,)*) = ty;
|
||||||
|
$(let $var = $var.into_sim_value($ty_var).into_canonical();)*
|
||||||
|
SimValue::from_canonical(ToSimValue::into_sim_value(($($var,)*), ty.canonical()))
|
||||||
|
}
|
||||||
|
#[track_caller]
|
||||||
|
fn box_into_sim_value(self: Box<Self>, ty: ($($Ty,)*)) -> SimValue<($($Ty,)*)> {
|
||||||
|
Self::into_sim_value(*self, ty)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<$($Lhs: Type + ExprPartialEq<$Rhs>, $Rhs: Type,)*> ExprPartialEq<($($Rhs,)*)> for ($($Lhs,)*) {
|
||||||
|
fn cmp_eq(lhs: Expr<Self>, rhs: Expr<($($Rhs,)*)>) -> Expr<Bool> {
|
||||||
|
let ($($lhs_var,)*) = *lhs;
|
||||||
|
let ($($rhs_var,)*) = *rhs;
|
||||||
|
ArrayLiteral::<Bool, DynSize>::new(
|
||||||
|
Bool,
|
||||||
|
FromIterator::from_iter([$(Expr::canonical(ExprPartialEq::cmp_eq($lhs_var, $rhs_var)),)*]),
|
||||||
|
)
|
||||||
|
.cast_to_bits()
|
||||||
|
.all_one_bits()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cmp_ne(lhs: Expr<Self>, rhs: Expr<($($Rhs,)*)>) -> Expr<Bool> {
|
||||||
|
let ($($lhs_var,)*) = *lhs;
|
||||||
|
let ($($rhs_var,)*) = *rhs;
|
||||||
|
ArrayLiteral::<Bool, DynSize>::new(
|
||||||
|
Bool,
|
||||||
|
FromIterator::from_iter([$(Expr::canonical(ExprPartialEq::cmp_ne($lhs_var, $rhs_var)),)*]),
|
||||||
|
)
|
||||||
|
.cast_to_bits()
|
||||||
|
.any_one_bits()
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
([$($lhs:tt)*] [$rhs_first:tt $($rhs:tt)*]) => {
|
([$($lhs:tt)*] [$rhs_first:tt $($rhs:tt)*]) => {
|
||||||
impl_tuples!([$($lhs)*] []);
|
impl_tuples!([$($lhs)*] []);
|
||||||
|
@ -432,18 +546,18 @@ macro_rules! impl_tuples {
|
||||||
|
|
||||||
impl_tuples! {
|
impl_tuples! {
|
||||||
[] [
|
[] [
|
||||||
{#[num = 0, field = field_0] v0: T0}
|
{#[num = 0, field = field_0, ty = ty0: Ty0, lhs = lhs0: Lhs0, rhs = rhs0: Rhs0] v0: T0}
|
||||||
{#[num = 1, field = field_1] v1: T1}
|
{#[num = 1, field = field_1, ty = ty1: Ty1, lhs = lhs1: Lhs1, rhs = rhs1: Rhs1] v1: T1}
|
||||||
{#[num = 2, field = field_2] v2: T2}
|
{#[num = 2, field = field_2, ty = ty2: Ty2, lhs = lhs2: Lhs2, rhs = rhs2: Rhs2] v2: T2}
|
||||||
{#[num = 3, field = field_3] v3: T3}
|
{#[num = 3, field = field_3, ty = ty3: Ty3, lhs = lhs3: Lhs3, rhs = rhs3: Rhs3] v3: T3}
|
||||||
{#[num = 4, field = field_4] v4: T4}
|
{#[num = 4, field = field_4, ty = ty4: Ty4, lhs = lhs4: Lhs4, rhs = rhs4: Rhs4] v4: T4}
|
||||||
{#[num = 5, field = field_5] v5: T5}
|
{#[num = 5, field = field_5, ty = ty5: Ty5, lhs = lhs5: Lhs5, rhs = rhs5: Rhs5] v5: T5}
|
||||||
{#[num = 6, field = field_6] v6: T6}
|
{#[num = 6, field = field_6, ty = ty6: Ty6, lhs = lhs6: Lhs6, rhs = rhs6: Rhs6] v6: T6}
|
||||||
{#[num = 7, field = field_7] v7: T7}
|
{#[num = 7, field = field_7, ty = ty7: Ty7, lhs = lhs7: Lhs7, rhs = rhs7: Rhs7] v7: T7}
|
||||||
{#[num = 8, field = field_8] v8: T8}
|
{#[num = 8, field = field_8, ty = ty8: Ty8, lhs = lhs8: Lhs8, rhs = rhs8: Rhs8] v8: T8}
|
||||||
{#[num = 9, field = field_9] v9: T9}
|
{#[num = 9, field = field_9, ty = ty9: Ty9, lhs = lhs9: Lhs9, rhs = rhs9: Rhs9] v9: T9}
|
||||||
{#[num = 10, field = field_10] v10: T10}
|
{#[num = 10, field = field_10, ty = ty10: Ty10, lhs = lhs10: Lhs10, rhs = rhs10: Rhs10] v10: T10}
|
||||||
{#[num = 11, field = field_11] v11: T11}
|
{#[num = 11, field = field_11, ty = ty11: Ty11, lhs = lhs11: Lhs11, rhs = rhs11: Rhs11] v11: T11}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -528,3 +642,27 @@ impl<T: ?Sized + Send + Sync + 'static> ToExpr for PhantomData<T> {
|
||||||
BundleLiteral::new(PhantomData, Interned::default()).to_expr()
|
BundleLiteral::new(PhantomData, Interned::default()).to_expr()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T: ?Sized + Send + Sync + 'static> ToSimValue<Self> for PhantomData<T> {
|
||||||
|
#[track_caller]
|
||||||
|
fn to_sim_value(&self, ty: Self) -> SimValue<Self> {
|
||||||
|
ToSimValue::into_sim_value(BitVec::new(), ty)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: ?Sized> ToSimValue<Bundle> for PhantomData<T> {
|
||||||
|
#[track_caller]
|
||||||
|
fn to_sim_value(&self, ty: Bundle) -> SimValue<Bundle> {
|
||||||
|
assert!(ty.fields().is_empty());
|
||||||
|
ToSimValue::into_sim_value(BitVec::new(), ty)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: ?Sized> ToSimValue<CanonicalType> for PhantomData<T> {
|
||||||
|
#[track_caller]
|
||||||
|
fn to_sim_value(&self, ty: CanonicalType) -> SimValue<CanonicalType> {
|
||||||
|
let ty = Bundle::from_canonical(ty);
|
||||||
|
assert!(ty.fields().is_empty());
|
||||||
|
ToSimValue::into_sim_value(BitVec::new(), ty).into_canonical()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ use crate::{
|
||||||
expr::{Expr, ToExpr},
|
expr::{Expr, ToExpr},
|
||||||
hdl,
|
hdl,
|
||||||
int::Bool,
|
int::Bool,
|
||||||
reset::Reset,
|
reset::{Reset, ResetType},
|
||||||
source_location::SourceLocation,
|
source_location::SourceLocation,
|
||||||
ty::{impl_match_variant_as_self, CanonicalType, StaticType, Type, TypeProperties},
|
ty::{impl_match_variant_as_self, CanonicalType, StaticType, Type, TypeProperties},
|
||||||
};
|
};
|
||||||
|
@ -88,9 +88,9 @@ impl ToClock for Expr<Clock> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[hdl]
|
#[hdl]
|
||||||
pub struct ClockDomain {
|
pub struct ClockDomain<R: ResetType = Reset> {
|
||||||
pub clk: Clock,
|
pub clk: Clock,
|
||||||
pub rst: Reset,
|
pub rst: R,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToClock for bool {
|
impl ToClock for bool {
|
||||||
|
|
|
@ -2,7 +2,10 @@
|
||||||
// See Notices.txt for copyright information
|
// See Notices.txt for copyright information
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
expr::{ops::VariantAccess, Expr, ToExpr},
|
expr::{
|
||||||
|
ops::{ExprPartialEq, VariantAccess},
|
||||||
|
Expr, ToExpr,
|
||||||
|
},
|
||||||
hdl,
|
hdl,
|
||||||
int::Bool,
|
int::Bool,
|
||||||
intern::{Intern, Interned},
|
intern::{Intern, Interned},
|
||||||
|
@ -360,6 +363,60 @@ pub enum HdlOption<T: Type> {
|
||||||
HdlSome(T),
|
HdlSome(T),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<Lhs: Type + ExprPartialEq<Rhs>, Rhs: Type> ExprPartialEq<HdlOption<Rhs>> for HdlOption<Lhs> {
|
||||||
|
#[hdl]
|
||||||
|
fn cmp_eq(lhs: Expr<Self>, rhs: Expr<HdlOption<Rhs>>) -> Expr<Bool> {
|
||||||
|
#[hdl]
|
||||||
|
let cmp_eq = wire();
|
||||||
|
#[hdl]
|
||||||
|
match lhs {
|
||||||
|
HdlSome(lhs) =>
|
||||||
|
{
|
||||||
|
#[hdl]
|
||||||
|
match rhs {
|
||||||
|
HdlSome(rhs) => connect(cmp_eq, ExprPartialEq::cmp_eq(lhs, rhs)),
|
||||||
|
HdlNone => connect(cmp_eq, false),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
HdlNone =>
|
||||||
|
{
|
||||||
|
#[hdl]
|
||||||
|
match rhs {
|
||||||
|
HdlSome(_) => connect(cmp_eq, false),
|
||||||
|
HdlNone => connect(cmp_eq, true),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cmp_eq
|
||||||
|
}
|
||||||
|
|
||||||
|
#[hdl]
|
||||||
|
fn cmp_ne(lhs: Expr<Self>, rhs: Expr<HdlOption<Rhs>>) -> Expr<Bool> {
|
||||||
|
#[hdl]
|
||||||
|
let cmp_ne = wire();
|
||||||
|
#[hdl]
|
||||||
|
match lhs {
|
||||||
|
HdlSome(lhs) =>
|
||||||
|
{
|
||||||
|
#[hdl]
|
||||||
|
match rhs {
|
||||||
|
HdlSome(rhs) => connect(cmp_ne, ExprPartialEq::cmp_ne(lhs, rhs)),
|
||||||
|
HdlNone => connect(cmp_ne, true),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
HdlNone =>
|
||||||
|
{
|
||||||
|
#[hdl]
|
||||||
|
match rhs {
|
||||||
|
HdlSome(_) => connect(cmp_ne, true),
|
||||||
|
HdlNone => connect(cmp_ne, false),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cmp_ne
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
pub fn HdlNone<T: StaticType>() -> Expr<HdlOption<T>> {
|
pub fn HdlNone<T: StaticType>() -> Expr<HdlOption<T>> {
|
||||||
HdlOption[T::TYPE].HdlNone()
|
HdlOption[T::TYPE].HdlNone()
|
||||||
|
|
|
@ -17,6 +17,7 @@ use crate::{
|
||||||
Instance, ModuleIO,
|
Instance, ModuleIO,
|
||||||
},
|
},
|
||||||
reg::Reg,
|
reg::Reg,
|
||||||
|
reset::{AsyncReset, Reset, ResetType, ResetTypeDispatch, SyncReset},
|
||||||
ty::{CanonicalType, StaticType, Type, TypeWithDeref},
|
ty::{CanonicalType, StaticType, Type, TypeWithDeref},
|
||||||
wire::Wire,
|
wire::Wire,
|
||||||
};
|
};
|
||||||
|
@ -209,7 +210,9 @@ expr_enum! {
|
||||||
ModuleIO(ModuleIO<CanonicalType>),
|
ModuleIO(ModuleIO<CanonicalType>),
|
||||||
Instance(Instance<Bundle>),
|
Instance(Instance<Bundle>),
|
||||||
Wire(Wire<CanonicalType>),
|
Wire(Wire<CanonicalType>),
|
||||||
Reg(Reg<CanonicalType>),
|
Reg(Reg<CanonicalType, Reset>),
|
||||||
|
RegSync(Reg<CanonicalType, SyncReset>),
|
||||||
|
RegAsync(Reg<CanonicalType, AsyncReset>),
|
||||||
MemPort(MemPort<DynPortType>),
|
MemPort(MemPort<DynPortType>),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -593,25 +596,42 @@ impl<T: Type> GetTarget for Wire<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Type> ToExpr for Reg<T> {
|
impl<T: Type, R: ResetType> ToExpr for Reg<T, R> {
|
||||||
type Type = T;
|
type Type = T;
|
||||||
|
|
||||||
fn to_expr(&self) -> Expr<Self::Type> {
|
fn to_expr(&self) -> Expr<Self::Type> {
|
||||||
|
struct Dispatch;
|
||||||
|
impl ResetTypeDispatch for Dispatch {
|
||||||
|
type Input<T: ResetType> = Reg<CanonicalType, T>;
|
||||||
|
type Output<T: ResetType> = ExprEnum;
|
||||||
|
|
||||||
|
fn reset(self, input: Self::Input<Reset>) -> Self::Output<Reset> {
|
||||||
|
ExprEnum::Reg(input)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sync_reset(self, input: Self::Input<SyncReset>) -> Self::Output<SyncReset> {
|
||||||
|
ExprEnum::RegSync(input)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn async_reset(self, input: Self::Input<AsyncReset>) -> Self::Output<AsyncReset> {
|
||||||
|
ExprEnum::RegAsync(input)
|
||||||
|
}
|
||||||
|
}
|
||||||
Expr {
|
Expr {
|
||||||
__enum: ExprEnum::Reg(self.canonical()).intern_sized(),
|
__enum: R::dispatch(self.canonical(), Dispatch).intern_sized(),
|
||||||
__ty: self.ty(),
|
__ty: self.ty(),
|
||||||
__flow: self.flow(),
|
__flow: self.flow(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Type> ToLiteralBits for Reg<T> {
|
impl<T: Type, R: ResetType> ToLiteralBits for Reg<T, R> {
|
||||||
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, NotALiteralExpr> {
|
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, NotALiteralExpr> {
|
||||||
Err(NotALiteralExpr)
|
Err(NotALiteralExpr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Type> GetTarget for Reg<T> {
|
impl<T: Type, R: ResetType> GetTarget for Reg<T, R> {
|
||||||
fn target(&self) -> Option<Interned<Target>> {
|
fn target(&self) -> Option<Interned<Target>> {
|
||||||
Some(Intern::intern_sized(self.canonical().into()))
|
Some(Intern::intern_sized(self.canonical().into()))
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,10 @@ use crate::{
|
||||||
UIntType, UIntValue,
|
UIntType, UIntValue,
|
||||||
},
|
},
|
||||||
intern::{Intern, Interned},
|
intern::{Intern, Interned},
|
||||||
reset::{AsyncReset, Reset, SyncReset, ToAsyncReset, ToReset, ToSyncReset},
|
reset::{
|
||||||
|
AsyncReset, Reset, ResetType, ResetTypeDispatch, SyncReset, ToAsyncReset, ToReset,
|
||||||
|
ToSyncReset,
|
||||||
|
},
|
||||||
ty::{CanonicalType, StaticType, Type},
|
ty::{CanonicalType, StaticType, Type},
|
||||||
util::ConstUsize,
|
util::ConstUsize,
|
||||||
};
|
};
|
||||||
|
@ -262,7 +265,7 @@ impl Neg {
|
||||||
};
|
};
|
||||||
let result_ty = retval.ty();
|
let result_ty = retval.ty();
|
||||||
retval.literal_bits = arg.to_literal_bits().map(|bits| {
|
retval.literal_bits = arg.to_literal_bits().map(|bits| {
|
||||||
Intern::intern_owned(result_ty.bits_from_bigint_wrapping(-SInt::bits_to_bigint(&bits)))
|
Intern::intern_owned(result_ty.bits_from_bigint_wrapping(&-SInt::bits_to_bigint(&bits)))
|
||||||
});
|
});
|
||||||
retval
|
retval
|
||||||
}
|
}
|
||||||
|
@ -369,7 +372,7 @@ fn binary_op_literal_bits<ResultTy: BoolOrIntType, Lhs: BoolOrIntType, Rhs: Bool
|
||||||
let rhs = Rhs::bits_to_bigint(&rhs);
|
let rhs = Rhs::bits_to_bigint(&rhs);
|
||||||
let result = f(lhs, rhs)?;
|
let result = f(lhs, rhs)?;
|
||||||
Ok(Intern::intern_owned(
|
Ok(Intern::intern_owned(
|
||||||
result_ty.bits_from_bigint_wrapping(result),
|
result_ty.bits_from_bigint_wrapping(&result),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1344,7 +1347,7 @@ macro_rules! binary_op_fixed_shift {
|
||||||
literal_bits: Err(NotALiteralExpr),
|
literal_bits: Err(NotALiteralExpr),
|
||||||
};
|
};
|
||||||
retval.literal_bits = lhs.to_literal_bits().map(|bits| {
|
retval.literal_bits = lhs.to_literal_bits().map(|bits| {
|
||||||
Intern::intern_owned(retval.ty().bits_from_bigint_wrapping($Trait::$method(
|
Intern::intern_owned(retval.ty().bits_from_bigint_wrapping(&$Trait::$method(
|
||||||
$ty::bits_to_bigint(&bits),
|
$ty::bits_to_bigint(&bits),
|
||||||
rhs,
|
rhs,
|
||||||
)))
|
)))
|
||||||
|
@ -1621,7 +1624,7 @@ macro_rules! impl_cast_int_op {
|
||||||
ty,
|
ty,
|
||||||
literal_bits: arg.to_literal_bits().map(|bits| {
|
literal_bits: arg.to_literal_bits().map(|bits| {
|
||||||
Intern::intern_owned(
|
Intern::intern_owned(
|
||||||
ty.bits_from_bigint_wrapping($from::bits_to_bigint(&bits)),
|
ty.bits_from_bigint_wrapping(&$from::bits_to_bigint(&bits)),
|
||||||
)
|
)
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
|
@ -1773,11 +1776,11 @@ impl_cast_bit_op!(CastSIntToAsyncReset, SInt<1>, #[dyn] SInt, AsyncReset, #[trai
|
||||||
impl_cast_bit_op!(CastSyncResetToBool, SyncReset, Bool);
|
impl_cast_bit_op!(CastSyncResetToBool, SyncReset, Bool);
|
||||||
impl_cast_bit_op!(CastSyncResetToUInt, SyncReset, UInt<1>, #[dyn] UInt);
|
impl_cast_bit_op!(CastSyncResetToUInt, SyncReset, UInt<1>, #[dyn] UInt);
|
||||||
impl_cast_bit_op!(CastSyncResetToSInt, SyncReset, SInt<1>, #[dyn] SInt);
|
impl_cast_bit_op!(CastSyncResetToSInt, SyncReset, SInt<1>, #[dyn] SInt);
|
||||||
impl_cast_bit_op!(CastSyncResetToReset, SyncReset, Reset, #[trait] ToReset::to_reset);
|
impl_cast_bit_op!(CastSyncResetToReset, SyncReset, Reset);
|
||||||
impl_cast_bit_op!(CastAsyncResetToBool, AsyncReset, Bool);
|
impl_cast_bit_op!(CastAsyncResetToBool, AsyncReset, Bool);
|
||||||
impl_cast_bit_op!(CastAsyncResetToUInt, AsyncReset, UInt<1>, #[dyn] UInt);
|
impl_cast_bit_op!(CastAsyncResetToUInt, AsyncReset, UInt<1>, #[dyn] UInt);
|
||||||
impl_cast_bit_op!(CastAsyncResetToSInt, AsyncReset, SInt<1>, #[dyn] SInt);
|
impl_cast_bit_op!(CastAsyncResetToSInt, AsyncReset, SInt<1>, #[dyn] SInt);
|
||||||
impl_cast_bit_op!(CastAsyncResetToReset, AsyncReset, Reset, #[trait] ToReset::to_reset);
|
impl_cast_bit_op!(CastAsyncResetToReset, AsyncReset, Reset);
|
||||||
impl_cast_bit_op!(CastResetToBool, Reset, Bool);
|
impl_cast_bit_op!(CastResetToBool, Reset, Bool);
|
||||||
impl_cast_bit_op!(CastResetToUInt, Reset, UInt<1>, #[dyn] UInt);
|
impl_cast_bit_op!(CastResetToUInt, Reset, UInt<1>, #[dyn] UInt);
|
||||||
impl_cast_bit_op!(CastResetToSInt, Reset, SInt<1>, #[dyn] SInt);
|
impl_cast_bit_op!(CastResetToSInt, Reset, SInt<1>, #[dyn] SInt);
|
||||||
|
@ -1788,6 +1791,107 @@ impl_cast_bit_op!(CastClockToBool, Clock, Bool);
|
||||||
impl_cast_bit_op!(CastClockToUInt, Clock, UInt<1>, #[dyn] UInt);
|
impl_cast_bit_op!(CastClockToUInt, Clock, UInt<1>, #[dyn] UInt);
|
||||||
impl_cast_bit_op!(CastClockToSInt, Clock, SInt<1>, #[dyn] SInt);
|
impl_cast_bit_op!(CastClockToSInt, Clock, SInt<1>, #[dyn] SInt);
|
||||||
|
|
||||||
|
impl<T: ResetType> ToReset for Expr<T> {
|
||||||
|
fn to_reset(&self) -> Expr<Reset> {
|
||||||
|
struct Dispatch;
|
||||||
|
impl ResetTypeDispatch for Dispatch {
|
||||||
|
type Input<T: ResetType> = Expr<T>;
|
||||||
|
type Output<T: ResetType> = Expr<Reset>;
|
||||||
|
|
||||||
|
fn reset(self, input: Self::Input<Reset>) -> Self::Output<Reset> {
|
||||||
|
input
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sync_reset(self, input: Self::Input<SyncReset>) -> Self::Output<SyncReset> {
|
||||||
|
input.cast_to_static()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn async_reset(self, input: Self::Input<AsyncReset>) -> Self::Output<AsyncReset> {
|
||||||
|
input.cast_to_static()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
T::dispatch(*self, Dispatch)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ExprCastTo<AsyncReset> for AsyncReset {
|
||||||
|
fn cast_to(src: Expr<Self>, _to_type: AsyncReset) -> Expr<AsyncReset> {
|
||||||
|
src
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ExprCastTo<SyncReset> for AsyncReset {
|
||||||
|
fn cast_to(src: Expr<Self>, to_type: SyncReset) -> Expr<SyncReset> {
|
||||||
|
src.cast_to(Bool).cast_to(to_type)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ExprCastTo<Clock> for AsyncReset {
|
||||||
|
fn cast_to(src: Expr<Self>, to_type: Clock) -> Expr<Clock> {
|
||||||
|
src.cast_to(Bool).cast_to(to_type)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ExprCastTo<AsyncReset> for SyncReset {
|
||||||
|
fn cast_to(src: Expr<Self>, to_type: AsyncReset) -> Expr<AsyncReset> {
|
||||||
|
src.cast_to(Bool).cast_to(to_type)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ExprCastTo<SyncReset> for SyncReset {
|
||||||
|
fn cast_to(src: Expr<Self>, _to_type: SyncReset) -> Expr<SyncReset> {
|
||||||
|
src
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ExprCastTo<Clock> for SyncReset {
|
||||||
|
fn cast_to(src: Expr<Self>, to_type: Clock) -> Expr<Clock> {
|
||||||
|
src.cast_to(Bool).cast_to(to_type)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ExprCastTo<AsyncReset> for Reset {
|
||||||
|
fn cast_to(src: Expr<Self>, to_type: AsyncReset) -> Expr<AsyncReset> {
|
||||||
|
src.cast_to(Bool).cast_to(to_type)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ExprCastTo<SyncReset> for Reset {
|
||||||
|
fn cast_to(src: Expr<Self>, to_type: SyncReset) -> Expr<SyncReset> {
|
||||||
|
src.cast_to(Bool).cast_to(to_type)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ExprCastTo<Reset> for Reset {
|
||||||
|
fn cast_to(src: Expr<Self>, _to_type: Reset) -> Expr<Reset> {
|
||||||
|
src
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ExprCastTo<Clock> for Reset {
|
||||||
|
fn cast_to(src: Expr<Self>, to_type: Clock) -> Expr<Clock> {
|
||||||
|
src.cast_to(Bool).cast_to(to_type)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ExprCastTo<AsyncReset> for Clock {
|
||||||
|
fn cast_to(src: Expr<Self>, to_type: AsyncReset) -> Expr<AsyncReset> {
|
||||||
|
src.cast_to(Bool).cast_to(to_type)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ExprCastTo<SyncReset> for Clock {
|
||||||
|
fn cast_to(src: Expr<Self>, to_type: SyncReset) -> Expr<SyncReset> {
|
||||||
|
src.cast_to(Bool).cast_to(to_type)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ExprCastTo<Clock> for Clock {
|
||||||
|
fn cast_to(src: Expr<Self>, _to_type: Clock) -> Expr<Clock> {
|
||||||
|
src
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
|
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
pub struct FieldAccess<FieldType: Type = CanonicalType> {
|
pub struct FieldAccess<FieldType: Type = CanonicalType> {
|
||||||
base: Expr<Bundle>,
|
base: Expr<Bundle>,
|
||||||
|
|
|
@ -3,18 +3,19 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
array::Array,
|
array::Array,
|
||||||
bundle::{Bundle, BundleField},
|
bundle::{Bundle, BundleField},
|
||||||
expr::Flow,
|
expr::{Expr, Flow, ToExpr},
|
||||||
intern::{Intern, Interned},
|
intern::{Intern, Interned},
|
||||||
memory::{DynPortType, MemPort},
|
memory::{DynPortType, MemPort},
|
||||||
module::{Instance, ModuleIO, TargetName},
|
module::{Instance, ModuleIO, TargetName},
|
||||||
reg::Reg,
|
reg::Reg,
|
||||||
|
reset::{AsyncReset, Reset, ResetType, ResetTypeDispatch, SyncReset},
|
||||||
source_location::SourceLocation,
|
source_location::SourceLocation,
|
||||||
ty::{CanonicalType, Type},
|
ty::{CanonicalType, Type},
|
||||||
wire::Wire,
|
wire::Wire,
|
||||||
};
|
};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
pub struct TargetPathBundleField {
|
pub struct TargetPathBundleField {
|
||||||
pub name: Interned<str>,
|
pub name: Interned<str>,
|
||||||
}
|
}
|
||||||
|
@ -25,7 +26,7 @@ impl fmt::Display for TargetPathBundleField {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
pub struct TargetPathArrayElement {
|
pub struct TargetPathArrayElement {
|
||||||
pub index: usize,
|
pub index: usize,
|
||||||
}
|
}
|
||||||
|
@ -36,7 +37,7 @@ impl fmt::Display for TargetPathArrayElement {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
pub struct TargetPathDynArrayElement {}
|
pub struct TargetPathDynArrayElement {}
|
||||||
|
|
||||||
impl fmt::Display for TargetPathDynArrayElement {
|
impl fmt::Display for TargetPathDynArrayElement {
|
||||||
|
@ -45,7 +46,7 @@ impl fmt::Display for TargetPathDynArrayElement {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
pub enum TargetPathElement {
|
pub enum TargetPathElement {
|
||||||
BundleField(TargetPathBundleField),
|
BundleField(TargetPathBundleField),
|
||||||
ArrayElement(TargetPathArrayElement),
|
ArrayElement(TargetPathArrayElement),
|
||||||
|
@ -127,6 +128,7 @@ macro_rules! impl_target_base {
|
||||||
$(#[$enum_meta:meta])*
|
$(#[$enum_meta:meta])*
|
||||||
$enum_vis:vis enum $TargetBase:ident {
|
$enum_vis:vis enum $TargetBase:ident {
|
||||||
$(
|
$(
|
||||||
|
$(#[from = $from:ident])?
|
||||||
#[is = $is_fn:ident]
|
#[is = $is_fn:ident]
|
||||||
#[to = $to_fn:ident]
|
#[to = $to_fn:ident]
|
||||||
$(#[$variant_meta:meta])*
|
$(#[$variant_meta:meta])*
|
||||||
|
@ -150,19 +152,19 @@ macro_rules! impl_target_base {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$(
|
$($(
|
||||||
impl From<$VariantTy> for $TargetBase {
|
impl From<$VariantTy> for $TargetBase {
|
||||||
fn from(value: $VariantTy) -> Self {
|
fn $from(value: $VariantTy) -> Self {
|
||||||
Self::$Variant(value)
|
Self::$Variant(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<$VariantTy> for Target {
|
impl From<$VariantTy> for Target {
|
||||||
fn from(value: $VariantTy) -> Self {
|
fn $from(value: $VariantTy) -> Self {
|
||||||
$TargetBase::$Variant(value).into()
|
$TargetBase::$Variant(value).into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)*
|
)*)?
|
||||||
|
|
||||||
impl $TargetBase {
|
impl $TargetBase {
|
||||||
$(
|
$(
|
||||||
|
@ -193,30 +195,79 @@ macro_rules! impl_target_base {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ToExpr for $TargetBase {
|
||||||
|
type Type = CanonicalType;
|
||||||
|
|
||||||
|
fn to_expr(&self) -> Expr<Self::Type> {
|
||||||
|
match self {
|
||||||
|
$(Self::$Variant(v) => Expr::canonical(v.to_expr()),)*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_target_base! {
|
impl_target_base! {
|
||||||
#[derive(Clone, PartialEq, Eq, Hash)]
|
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
pub enum TargetBase {
|
pub enum TargetBase {
|
||||||
|
#[from = from]
|
||||||
#[is = is_module_io]
|
#[is = is_module_io]
|
||||||
#[to = module_io]
|
#[to = module_io]
|
||||||
ModuleIO(ModuleIO<CanonicalType>),
|
ModuleIO(ModuleIO<CanonicalType>),
|
||||||
|
#[from = from]
|
||||||
#[is = is_mem_port]
|
#[is = is_mem_port]
|
||||||
#[to = mem_port]
|
#[to = mem_port]
|
||||||
MemPort(MemPort<DynPortType>),
|
MemPort(MemPort<DynPortType>),
|
||||||
#[is = is_reg]
|
#[is = is_reg]
|
||||||
#[to = reg]
|
#[to = reg]
|
||||||
Reg(Reg<CanonicalType>),
|
Reg(Reg<CanonicalType, Reset>),
|
||||||
|
#[is = is_reg_sync]
|
||||||
|
#[to = reg_sync]
|
||||||
|
RegSync(Reg<CanonicalType, SyncReset>),
|
||||||
|
#[is = is_reg_async]
|
||||||
|
#[to = reg_async]
|
||||||
|
RegAsync(Reg<CanonicalType, AsyncReset>),
|
||||||
|
#[from = from]
|
||||||
#[is = is_wire]
|
#[is = is_wire]
|
||||||
#[to = wire]
|
#[to = wire]
|
||||||
Wire(Wire<CanonicalType>),
|
Wire(Wire<CanonicalType>),
|
||||||
|
#[from = from]
|
||||||
#[is = is_instance]
|
#[is = is_instance]
|
||||||
#[to = instance]
|
#[to = instance]
|
||||||
Instance(Instance<Bundle>),
|
Instance(Instance<Bundle>),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<R: ResetType> From<Reg<CanonicalType, R>> for TargetBase {
|
||||||
|
fn from(value: Reg<CanonicalType, R>) -> Self {
|
||||||
|
struct Dispatch;
|
||||||
|
impl ResetTypeDispatch for Dispatch {
|
||||||
|
type Input<T: ResetType> = Reg<CanonicalType, T>;
|
||||||
|
type Output<T: ResetType> = TargetBase;
|
||||||
|
|
||||||
|
fn reset(self, input: Self::Input<Reset>) -> Self::Output<Reset> {
|
||||||
|
TargetBase::Reg(input)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sync_reset(self, input: Self::Input<SyncReset>) -> Self::Output<SyncReset> {
|
||||||
|
TargetBase::RegSync(input)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn async_reset(self, input: Self::Input<AsyncReset>) -> Self::Output<AsyncReset> {
|
||||||
|
TargetBase::RegAsync(input)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
R::dispatch(value, Dispatch)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<R: ResetType> From<Reg<CanonicalType, R>> for Target {
|
||||||
|
fn from(value: Reg<CanonicalType, R>) -> Self {
|
||||||
|
TargetBase::from(value).into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl fmt::Display for TargetBase {
|
impl fmt::Display for TargetBase {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
write!(f, "{:?}", self.target_name())
|
write!(f, "{:?}", self.target_name())
|
||||||
|
@ -229,6 +280,8 @@ impl TargetBase {
|
||||||
TargetBase::ModuleIO(v) => TargetName(v.scoped_name(), None),
|
TargetBase::ModuleIO(v) => TargetName(v.scoped_name(), None),
|
||||||
TargetBase::MemPort(v) => TargetName(v.mem_name(), Some(v.port_name())),
|
TargetBase::MemPort(v) => TargetName(v.mem_name(), Some(v.port_name())),
|
||||||
TargetBase::Reg(v) => TargetName(v.scoped_name(), None),
|
TargetBase::Reg(v) => TargetName(v.scoped_name(), None),
|
||||||
|
TargetBase::RegSync(v) => TargetName(v.scoped_name(), None),
|
||||||
|
TargetBase::RegAsync(v) => TargetName(v.scoped_name(), None),
|
||||||
TargetBase::Wire(v) => TargetName(v.scoped_name(), None),
|
TargetBase::Wire(v) => TargetName(v.scoped_name(), None),
|
||||||
TargetBase::Instance(v) => TargetName(v.scoped_name(), None),
|
TargetBase::Instance(v) => TargetName(v.scoped_name(), None),
|
||||||
}
|
}
|
||||||
|
@ -238,6 +291,8 @@ impl TargetBase {
|
||||||
TargetBase::ModuleIO(v) => v.ty(),
|
TargetBase::ModuleIO(v) => v.ty(),
|
||||||
TargetBase::MemPort(v) => v.ty().canonical(),
|
TargetBase::MemPort(v) => v.ty().canonical(),
|
||||||
TargetBase::Reg(v) => v.ty(),
|
TargetBase::Reg(v) => v.ty(),
|
||||||
|
TargetBase::RegSync(v) => v.ty(),
|
||||||
|
TargetBase::RegAsync(v) => v.ty(),
|
||||||
TargetBase::Wire(v) => v.ty(),
|
TargetBase::Wire(v) => v.ty(),
|
||||||
TargetBase::Instance(v) => v.ty().canonical(),
|
TargetBase::Instance(v) => v.ty().canonical(),
|
||||||
}
|
}
|
||||||
|
@ -313,7 +368,7 @@ impl TargetChild {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq, Hash)]
|
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
pub enum Target {
|
pub enum Target {
|
||||||
Base(Interned<TargetBase>),
|
Base(Interned<TargetBase>),
|
||||||
Child(TargetChild),
|
Child(TargetChild),
|
||||||
|
|
|
@ -31,7 +31,7 @@ use crate::{
|
||||||
StmtConnect, StmtDeclaration, StmtFormal, StmtIf, StmtInstance, StmtMatch, StmtReg,
|
StmtConnect, StmtDeclaration, StmtFormal, StmtIf, StmtInstance, StmtMatch, StmtReg,
|
||||||
StmtWire,
|
StmtWire,
|
||||||
},
|
},
|
||||||
reset::{AsyncReset, Reset, SyncReset},
|
reset::{AsyncReset, Reset, ResetType, SyncReset},
|
||||||
source_location::SourceLocation,
|
source_location::SourceLocation,
|
||||||
ty::{CanonicalType, Type},
|
ty::{CanonicalType, Type},
|
||||||
util::{
|
util::{
|
||||||
|
@ -1739,6 +1739,14 @@ impl<'a> Exporter<'a> {
|
||||||
assert!(!const_ty, "not a constant");
|
assert!(!const_ty, "not a constant");
|
||||||
self.module.ns.get(expr.scoped_name().1).to_string()
|
self.module.ns.get(expr.scoped_name().1).to_string()
|
||||||
}
|
}
|
||||||
|
ExprEnum::RegSync(expr) => {
|
||||||
|
assert!(!const_ty, "not a constant");
|
||||||
|
self.module.ns.get(expr.scoped_name().1).to_string()
|
||||||
|
}
|
||||||
|
ExprEnum::RegAsync(expr) => {
|
||||||
|
assert!(!const_ty, "not a constant");
|
||||||
|
self.module.ns.get(expr.scoped_name().1).to_string()
|
||||||
|
}
|
||||||
ExprEnum::MemPort(expr) => {
|
ExprEnum::MemPort(expr) => {
|
||||||
assert!(!const_ty, "not a constant");
|
assert!(!const_ty, "not a constant");
|
||||||
let mem_name = self.module.ns.get(expr.mem_name().1);
|
let mem_name = self.module.ns.get(expr.mem_name().1);
|
||||||
|
@ -1848,6 +1856,8 @@ impl<'a> Exporter<'a> {
|
||||||
self.module.ns.get(v.mem_name().1)
|
self.module.ns.get(v.mem_name().1)
|
||||||
}
|
}
|
||||||
TargetBase::Reg(v) => self.module.ns.get(v.name_id()),
|
TargetBase::Reg(v) => self.module.ns.get(v.name_id()),
|
||||||
|
TargetBase::RegSync(v) => self.module.ns.get(v.name_id()),
|
||||||
|
TargetBase::RegAsync(v) => self.module.ns.get(v.name_id()),
|
||||||
TargetBase::Wire(v) => self.module.ns.get(v.name_id()),
|
TargetBase::Wire(v) => self.module.ns.get(v.name_id()),
|
||||||
TargetBase::Instance(v) => self.module.ns.get(v.name_id()),
|
TargetBase::Instance(v) => self.module.ns.get(v.name_id()),
|
||||||
};
|
};
|
||||||
|
@ -1956,6 +1966,37 @@ impl<'a> Exporter<'a> {
|
||||||
drop(memory_indent);
|
drop(memory_indent);
|
||||||
Ok(body)
|
Ok(body)
|
||||||
}
|
}
|
||||||
|
fn stmt_reg<R: ResetType>(
|
||||||
|
&mut self,
|
||||||
|
stmt_reg: StmtReg<R>,
|
||||||
|
module_name: Ident,
|
||||||
|
definitions: &RcDefinitions,
|
||||||
|
body: &mut String,
|
||||||
|
) {
|
||||||
|
let StmtReg { annotations, reg } = stmt_reg;
|
||||||
|
let indent = self.indent;
|
||||||
|
self.targeted_annotations(module_name, vec![], &annotations);
|
||||||
|
let name = self.module.ns.get(reg.name_id());
|
||||||
|
let ty = self.type_state.ty(reg.ty());
|
||||||
|
let clk = self.expr(Expr::canonical(reg.clock_domain().clk), definitions, false);
|
||||||
|
if let Some(init) = reg.init() {
|
||||||
|
let rst = self.expr(Expr::canonical(reg.clock_domain().rst), definitions, false);
|
||||||
|
let init = self.expr(init, definitions, false);
|
||||||
|
writeln!(
|
||||||
|
body,
|
||||||
|
"{indent}regreset {name}: {ty}, {clk}, {rst}, {init}{}",
|
||||||
|
FileInfo::new(reg.source_location()),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
} else {
|
||||||
|
writeln!(
|
||||||
|
body,
|
||||||
|
"{indent}reg {name}: {ty}, {clk}{}",
|
||||||
|
FileInfo::new(reg.source_location()),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
fn block(
|
fn block(
|
||||||
&mut self,
|
&mut self,
|
||||||
module: Interned<Module<Bundle>>,
|
module: Interned<Module<Bundle>>,
|
||||||
|
@ -2126,30 +2167,14 @@ impl<'a> Exporter<'a> {
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
Stmt::Declaration(StmtDeclaration::Reg(StmtReg { annotations, reg })) => {
|
Stmt::Declaration(StmtDeclaration::Reg(stmt_reg)) => {
|
||||||
self.targeted_annotations(module_name, vec![], &annotations);
|
self.stmt_reg(stmt_reg, module_name, &definitions, &mut body);
|
||||||
let name = self.module.ns.get(reg.name_id());
|
|
||||||
let ty = self.type_state.ty(reg.ty());
|
|
||||||
let clk =
|
|
||||||
self.expr(Expr::canonical(reg.clock_domain().clk), &definitions, false);
|
|
||||||
if let Some(init) = reg.init() {
|
|
||||||
let rst =
|
|
||||||
self.expr(Expr::canonical(reg.clock_domain().rst), &definitions, false);
|
|
||||||
let init = self.expr(init, &definitions, false);
|
|
||||||
writeln!(
|
|
||||||
body,
|
|
||||||
"{indent}regreset {name}: {ty}, {clk}, {rst}, {init}{}",
|
|
||||||
FileInfo::new(reg.source_location()),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
} else {
|
|
||||||
writeln!(
|
|
||||||
body,
|
|
||||||
"{indent}reg {name}: {ty}, {clk}{}",
|
|
||||||
FileInfo::new(reg.source_location()),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
}
|
}
|
||||||
|
Stmt::Declaration(StmtDeclaration::RegSync(stmt_reg)) => {
|
||||||
|
self.stmt_reg(stmt_reg, module_name, &definitions, &mut body);
|
||||||
|
}
|
||||||
|
Stmt::Declaration(StmtDeclaration::RegAsync(stmt_reg)) => {
|
||||||
|
self.stmt_reg(stmt_reg, module_name, &definitions, &mut body);
|
||||||
}
|
}
|
||||||
Stmt::Declaration(StmtDeclaration::Instance(StmtInstance {
|
Stmt::Declaration(StmtDeclaration::Instance(StmtInstance {
|
||||||
annotations,
|
annotations,
|
||||||
|
|
|
@ -202,17 +202,17 @@ macro_rules! impl_int {
|
||||||
bit_width: self.width(),
|
bit_width: self.width(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn bits_from_bigint_wrapping(self, v: BigInt) -> BitVec {
|
pub fn bits_from_bigint_wrapping(self, v: &BigInt) -> BitVec {
|
||||||
BoolOrIntType::bits_from_bigint_wrapping(self, v)
|
BoolOrIntType::bits_from_bigint_wrapping(self, v)
|
||||||
}
|
}
|
||||||
pub fn from_bigint_wrapping(self, v: BigInt) -> $value<Width> {
|
pub fn from_bigint_wrapping(self, v: &BigInt) -> $value<Width> {
|
||||||
$value {
|
$value {
|
||||||
bits: Arc::new(self.bits_from_bigint_wrapping(v)),
|
bits: Arc::new(self.bits_from_bigint_wrapping(v)),
|
||||||
_phantom: PhantomData,
|
_phantom: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn from_int_wrapping(self, v: impl Into<BigInt>) -> $value<Width> {
|
pub fn from_int_wrapping(self, v: impl Into<BigInt>) -> $value<Width> {
|
||||||
self.from_bigint_wrapping(v.into())
|
self.from_bigint_wrapping(&v.into())
|
||||||
}
|
}
|
||||||
pub fn zero(self) -> $value<Width> {
|
pub fn zero(self) -> $value<Width> {
|
||||||
self.from_int_wrapping(0u8)
|
self.from_int_wrapping(0u8)
|
||||||
|
@ -227,12 +227,29 @@ macro_rules! impl_int {
|
||||||
impl<Width: Size> BoolOrIntType for $name<Width> {
|
impl<Width: Size> BoolOrIntType for $name<Width> {
|
||||||
type Width = Width;
|
type Width = Width;
|
||||||
type Signed = ConstBool<$SIGNED>;
|
type Signed = ConstBool<$SIGNED>;
|
||||||
|
type Value = $value<Width>;
|
||||||
fn width(self) -> usize {
|
fn width(self) -> usize {
|
||||||
$name::width(self)
|
$name::width(self)
|
||||||
}
|
}
|
||||||
fn new(width: Width::SizeType) -> Self {
|
fn new(width: Width::SizeType) -> Self {
|
||||||
$name { width }
|
$name { width }
|
||||||
}
|
}
|
||||||
|
fn value_from_bigint_wrapping(self, v: &BigInt) -> Self::Value {
|
||||||
|
$value::<Width>::from_bigint_wrapping(self, v)
|
||||||
|
}
|
||||||
|
fn bits_to_value(bits: Cow<'_, BitSlice>) -> Self::Value {
|
||||||
|
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
|
||||||
|
struct MemoizeBitsToValue;
|
||||||
|
impl Memoize for MemoizeBitsToValue {
|
||||||
|
type Input = BitSlice;
|
||||||
|
type InputOwned = BitVec;
|
||||||
|
type Output = Arc<BitVec>;
|
||||||
|
fn inner(self, input: &Self::Input) -> Self::Output {
|
||||||
|
Arc::new(input.to_bitvec())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$value::new(MemoizeBitsToValue.get_cow(bits))
|
||||||
|
}
|
||||||
fn bits_to_expr(bits: Cow<'_, BitSlice>) -> Expr<Self> {
|
fn bits_to_expr(bits: Cow<'_, BitSlice>) -> Expr<Self> {
|
||||||
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
|
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
|
||||||
struct MemoizeBitsToExpr;
|
struct MemoizeBitsToExpr;
|
||||||
|
@ -334,6 +351,24 @@ macro_rules! impl_int {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<Width: Size> PartialOrd for $value<Width> {
|
||||||
|
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||||
|
Some(self.cmp(other))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Width: Size> Ord for $value<Width> {
|
||||||
|
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
||||||
|
self.to_bigint().cmp(&other.to_bigint())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Width: Size> From<$value<Width>> for BigInt {
|
||||||
|
fn from(v: $value<Width>) -> BigInt {
|
||||||
|
v.to_bigint()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<Width: Size> $value<Width> {
|
impl<Width: Size> $value<Width> {
|
||||||
pub fn width(&self) -> usize {
|
pub fn width(&self) -> usize {
|
||||||
if let Some(retval) = Width::KNOWN_VALUE {
|
if let Some(retval) = Width::KNOWN_VALUE {
|
||||||
|
@ -343,7 +378,7 @@ macro_rules! impl_int {
|
||||||
self.bits.len()
|
self.bits.len()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn from_bigint_wrapping(ty: $name<Width>, v: BigInt) -> $value<Width> {
|
pub fn from_bigint_wrapping(ty: $name<Width>, v: &BigInt) -> $value<Width> {
|
||||||
ty.from_bigint_wrapping(v)
|
ty.from_bigint_wrapping(v)
|
||||||
}
|
}
|
||||||
pub fn to_bigint(&self) -> BigInt {
|
pub fn to_bigint(&self) -> BigInt {
|
||||||
|
@ -485,6 +520,19 @@ macro_rules! impl_prim_int {
|
||||||
$(#[$meta:meta])*
|
$(#[$meta:meta])*
|
||||||
$prim_int:ident, $ty:ty
|
$prim_int:ident, $ty:ty
|
||||||
) => {
|
) => {
|
||||||
|
impl From<$prim_int> for <$ty as BoolOrIntType>::Value {
|
||||||
|
fn from(v: $prim_int) -> Self {
|
||||||
|
<$ty>::le_bytes_to_value_wrapping(
|
||||||
|
&v.to_le_bytes(),
|
||||||
|
<$ty as BoolOrIntType>::Width::VALUE,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl From<NonZero<$prim_int>> for <$ty as BoolOrIntType>::Value {
|
||||||
|
fn from(v: NonZero<$prim_int>) -> Self {
|
||||||
|
v.get().into()
|
||||||
|
}
|
||||||
|
}
|
||||||
$(#[$meta])*
|
$(#[$meta])*
|
||||||
impl ToExpr for $prim_int {
|
impl ToExpr for $prim_int {
|
||||||
type Type = $ty;
|
type Type = $ty;
|
||||||
|
@ -501,10 +549,7 @@ macro_rules! impl_prim_int {
|
||||||
type Type = $ty;
|
type Type = $ty;
|
||||||
|
|
||||||
fn to_expr(&self) -> Expr<Self::Type> {
|
fn to_expr(&self) -> Expr<Self::Type> {
|
||||||
<$ty>::le_bytes_to_expr_wrapping(
|
self.get().to_expr()
|
||||||
&self.get().to_le_bytes(),
|
|
||||||
<$ty as BoolOrIntType>::Width::VALUE,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -522,18 +567,27 @@ impl_prim_int!(i64, SInt<64>);
|
||||||
impl_prim_int!(i128, SInt<128>);
|
impl_prim_int!(i128, SInt<128>);
|
||||||
|
|
||||||
impl_prim_int!(
|
impl_prim_int!(
|
||||||
/// for portability reasons, [`usize`] always translates to [`UInt<64>`]
|
/// for portability reasons, [`usize`] always translates to [`UInt<64>`][type@UInt]
|
||||||
usize, UInt<64>
|
usize, UInt<64>
|
||||||
);
|
);
|
||||||
|
|
||||||
impl_prim_int!(
|
impl_prim_int!(
|
||||||
/// for portability reasons, [`isize`] always translates to [`SInt<64>`]
|
/// for portability reasons, [`isize`] always translates to [`SInt<64>`][type@SInt]
|
||||||
isize, SInt<64>
|
isize, SInt<64>
|
||||||
);
|
);
|
||||||
|
|
||||||
pub trait BoolOrIntType: Type + sealed::BoolOrIntTypeSealed {
|
pub trait BoolOrIntType: Type + sealed::BoolOrIntTypeSealed {
|
||||||
type Width: Size;
|
type Width: Size;
|
||||||
type Signed: GenericConstBool;
|
type Signed: GenericConstBool;
|
||||||
|
type Value: Clone
|
||||||
|
+ Ord
|
||||||
|
+ std::hash::Hash
|
||||||
|
+ fmt::Debug
|
||||||
|
+ Send
|
||||||
|
+ Sync
|
||||||
|
+ 'static
|
||||||
|
+ ToExpr<Type = Self>
|
||||||
|
+ Into<BigInt>;
|
||||||
fn width(self) -> usize;
|
fn width(self) -> usize;
|
||||||
fn new(width: <Self::Width as Size>::SizeType) -> Self;
|
fn new(width: <Self::Width as Size>::SizeType) -> Self;
|
||||||
fn new_static() -> Self
|
fn new_static() -> Self
|
||||||
|
@ -548,17 +602,24 @@ pub trait BoolOrIntType: Type + sealed::BoolOrIntTypeSealed {
|
||||||
fn as_same_width_uint(self) -> UIntType<Self::Width> {
|
fn as_same_width_uint(self) -> UIntType<Self::Width> {
|
||||||
UIntType::new(Self::Width::from_usize(self.width()))
|
UIntType::new(Self::Width::from_usize(self.width()))
|
||||||
}
|
}
|
||||||
fn bits_from_bigint_wrapping(self, v: BigInt) -> BitVec {
|
fn value_from_int_wrapping(self, v: impl Into<BigInt>) -> Self::Value {
|
||||||
let width = self.width();
|
self.value_from_bigint_wrapping(&v.into())
|
||||||
|
}
|
||||||
|
fn value_from_bigint_wrapping(self, v: &BigInt) -> Self::Value;
|
||||||
|
fn bits_from_bigint_wrapping(self, v: &BigInt) -> BitVec {
|
||||||
|
let mut bits = BitVec::repeat(false, self.width());
|
||||||
|
Self::copy_bits_from_bigint_wrapping(v, &mut bits);
|
||||||
|
bits
|
||||||
|
}
|
||||||
|
fn copy_bits_from_bigint_wrapping(v: &BigInt, bits: &mut BitSlice) {
|
||||||
|
let width = bits.len();
|
||||||
let mut bytes = v.to_signed_bytes_le();
|
let mut bytes = v.to_signed_bytes_le();
|
||||||
bytes.resize(
|
bytes.resize(
|
||||||
width.div_ceil(u8::BITS as usize),
|
width.div_ceil(u8::BITS as usize),
|
||||||
if v.is_negative() { 0xFF } else { 0 },
|
if v.is_negative() { 0xFF } else { 0 },
|
||||||
);
|
);
|
||||||
let bitslice = &BitSlice::<u8, Lsb0>::from_slice(&bytes)[..width];
|
let bitslice = &BitSlice::<u8, Lsb0>::from_slice(&bytes)[..width];
|
||||||
let mut bits = BitVec::new();
|
bits.clone_from_bitslice(bitslice);
|
||||||
bits.extend_from_bitslice(bitslice);
|
|
||||||
bits
|
|
||||||
}
|
}
|
||||||
fn bits_to_bigint(bits: &BitSlice) -> BigInt {
|
fn bits_to_bigint(bits: &BitSlice) -> BigInt {
|
||||||
let sign_byte = if Self::Signed::VALUE && bits.last().as_deref().copied().unwrap_or(false) {
|
let sign_byte = if Self::Signed::VALUE && bits.last().as_deref().copied().unwrap_or(false) {
|
||||||
|
@ -570,8 +631,9 @@ pub trait BoolOrIntType: Type + sealed::BoolOrIntTypeSealed {
|
||||||
BitSlice::<u8, Lsb0>::from_slice_mut(&mut bytes)[..bits.len()].clone_from_bitslice(bits);
|
BitSlice::<u8, Lsb0>::from_slice_mut(&mut bytes)[..bits.len()].clone_from_bitslice(bits);
|
||||||
BigInt::from_signed_bytes_le(&bytes)
|
BigInt::from_signed_bytes_le(&bytes)
|
||||||
}
|
}
|
||||||
|
fn bits_to_value(bits: Cow<'_, BitSlice>) -> Self::Value;
|
||||||
fn bits_to_expr(bits: Cow<'_, BitSlice>) -> Expr<Self>;
|
fn bits_to_expr(bits: Cow<'_, BitSlice>) -> Expr<Self>;
|
||||||
fn le_bytes_to_expr_wrapping(bytes: &[u8], bit_width: usize) -> Expr<Self> {
|
fn le_bytes_to_bits_wrapping(bytes: &[u8], bit_width: usize) -> BitVec {
|
||||||
let bitslice = BitSlice::<u8, Lsb0>::from_slice(bytes);
|
let bitslice = BitSlice::<u8, Lsb0>::from_slice(bytes);
|
||||||
let bitslice = &bitslice[..bit_width.min(bitslice.len())];
|
let bitslice = &bitslice[..bit_width.min(bitslice.len())];
|
||||||
let mut bits = BitVec::new();
|
let mut bits = BitVec::new();
|
||||||
|
@ -580,7 +642,17 @@ pub trait BoolOrIntType: Type + sealed::BoolOrIntTypeSealed {
|
||||||
bit_width,
|
bit_width,
|
||||||
Self::Signed::VALUE && bits.last().as_deref().copied().unwrap_or(false),
|
Self::Signed::VALUE && bits.last().as_deref().copied().unwrap_or(false),
|
||||||
);
|
);
|
||||||
Self::bits_to_expr(Cow::Owned(bits))
|
bits
|
||||||
|
}
|
||||||
|
fn le_bytes_to_expr_wrapping(bytes: &[u8], bit_width: usize) -> Expr<Self> {
|
||||||
|
Self::bits_to_expr(Cow::Owned(Self::le_bytes_to_bits_wrapping(
|
||||||
|
bytes, bit_width,
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
fn le_bytes_to_value_wrapping(bytes: &[u8], bit_width: usize) -> Self::Value {
|
||||||
|
Self::bits_to_value(Cow::Owned(Self::le_bytes_to_bits_wrapping(
|
||||||
|
bytes, bit_width,
|
||||||
|
)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -632,6 +704,7 @@ impl sealed::BoolOrIntTypeSealed for Bool {}
|
||||||
impl BoolOrIntType for Bool {
|
impl BoolOrIntType for Bool {
|
||||||
type Width = ConstUsize<1>;
|
type Width = ConstUsize<1>;
|
||||||
type Signed = ConstBool<false>;
|
type Signed = ConstBool<false>;
|
||||||
|
type Value = bool;
|
||||||
|
|
||||||
fn width(self) -> usize {
|
fn width(self) -> usize {
|
||||||
1
|
1
|
||||||
|
@ -642,10 +715,19 @@ impl BoolOrIntType for Bool {
|
||||||
Bool
|
Bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn value_from_bigint_wrapping(self, v: &BigInt) -> Self::Value {
|
||||||
|
v.bit(0)
|
||||||
|
}
|
||||||
|
|
||||||
fn bits_to_expr(bits: Cow<'_, BitSlice>) -> Expr<Self> {
|
fn bits_to_expr(bits: Cow<'_, BitSlice>) -> Expr<Self> {
|
||||||
assert_eq!(bits.len(), 1);
|
assert_eq!(bits.len(), 1);
|
||||||
bits[0].to_expr()
|
bits[0].to_expr()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn bits_to_value(bits: Cow<'_, BitSlice>) -> Self::Value {
|
||||||
|
assert_eq!(bits.len(), 1);
|
||||||
|
bits[0]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Bool {
|
impl Bool {
|
||||||
|
|
|
@ -11,6 +11,59 @@ extern crate self as fayalite;
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub use std as __std;
|
pub use std as __std;
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! __cfg_expansion_helper {
|
||||||
|
(
|
||||||
|
[
|
||||||
|
$($evaluated_cfgs:ident($($evaluated_exprs:tt)*) = $evaluated_results:ident,)*
|
||||||
|
]
|
||||||
|
[
|
||||||
|
$cfg:ident($($expr:tt)*),
|
||||||
|
$($unevaluated_cfgs:ident($($unevaluated_exprs:tt)*),)*
|
||||||
|
]
|
||||||
|
// pass as tt so we get right span for attribute
|
||||||
|
$after_evaluation_attr:tt $after_evaluation_body:tt
|
||||||
|
) => {
|
||||||
|
#[$cfg($($expr)*)]
|
||||||
|
$crate::__cfg_expansion_helper! {
|
||||||
|
[
|
||||||
|
$($evaluated_cfgs($($evaluated_exprs)*) = $evaluated_results,)*
|
||||||
|
$cfg($($expr)*) = true,
|
||||||
|
]
|
||||||
|
[
|
||||||
|
$($unevaluated_cfgs($($unevaluated_exprs)*),)*
|
||||||
|
]
|
||||||
|
$after_evaluation_attr $after_evaluation_body
|
||||||
|
}
|
||||||
|
#[$cfg(not($($expr)*))]
|
||||||
|
$crate::__cfg_expansion_helper! {
|
||||||
|
[
|
||||||
|
$($evaluated_cfgs($($evaluated_exprs)*) = $evaluated_results,)*
|
||||||
|
$cfg($($expr)*) = false,
|
||||||
|
]
|
||||||
|
[
|
||||||
|
$($unevaluated_cfgs($($unevaluated_exprs)*),)*
|
||||||
|
]
|
||||||
|
$after_evaluation_attr $after_evaluation_body
|
||||||
|
}
|
||||||
|
};
|
||||||
|
(
|
||||||
|
[
|
||||||
|
$($evaluated_cfgs:ident($($evaluated_exprs:tt)*) = $evaluated_results:ident,)*
|
||||||
|
]
|
||||||
|
[]
|
||||||
|
// don't use #[...] so we get right span for `#` and `[]` of attribute
|
||||||
|
{$($after_evaluation_attr:tt)*} {$($after_evaluation_body:tt)*}
|
||||||
|
) => {
|
||||||
|
$($after_evaluation_attr)*
|
||||||
|
#[__evaluated_cfgs([
|
||||||
|
$($evaluated_cfgs($($evaluated_exprs)*) = $evaluated_results,)*
|
||||||
|
])]
|
||||||
|
$($after_evaluation_body)*
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
#[doc(inline)]
|
#[doc(inline)]
|
||||||
/// The `#[hdl_module]` attribute is applied to a Rust function so that that function creates
|
/// The `#[hdl_module]` attribute is applied to a Rust function so that that function creates
|
||||||
/// a [`Module`][`::fayalite::module::Module`] when called.
|
/// a [`Module`][`::fayalite::module::Module`] when called.
|
||||||
|
@ -46,6 +99,7 @@ pub mod module;
|
||||||
pub mod prelude;
|
pub mod prelude;
|
||||||
pub mod reg;
|
pub mod reg;
|
||||||
pub mod reset;
|
pub mod reset;
|
||||||
|
pub mod sim;
|
||||||
pub mod source_location;
|
pub mod source_location;
|
||||||
pub mod testing;
|
pub mod testing;
|
||||||
pub mod ty;
|
pub mod ty;
|
||||||
|
|
|
@ -22,7 +22,7 @@ use std::{
|
||||||
fmt,
|
fmt,
|
||||||
hash::{Hash, Hasher},
|
hash::{Hash, Hasher},
|
||||||
marker::PhantomData,
|
marker::PhantomData,
|
||||||
num::NonZeroU32,
|
num::NonZeroUsize,
|
||||||
rc::Rc,
|
rc::Rc,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -478,7 +478,7 @@ struct MemImpl<Element: Type, Len: Size, P> {
|
||||||
initial_value: Option<Interned<BitSlice>>,
|
initial_value: Option<Interned<BitSlice>>,
|
||||||
ports: P,
|
ports: P,
|
||||||
read_latency: usize,
|
read_latency: usize,
|
||||||
write_latency: NonZeroU32,
|
write_latency: NonZeroUsize,
|
||||||
read_under_write: ReadUnderWrite,
|
read_under_write: ReadUnderWrite,
|
||||||
port_annotations: Interned<[TargetedAnnotation]>,
|
port_annotations: Interned<[TargetedAnnotation]>,
|
||||||
mem_annotations: Interned<[Annotation]>,
|
mem_annotations: Interned<[Annotation]>,
|
||||||
|
@ -519,7 +519,12 @@ impl<Element: Type, Len: Size> fmt::Debug for Mem<Element, Len> {
|
||||||
f.debug_struct("Mem")
|
f.debug_struct("Mem")
|
||||||
.field("name", scoped_name)
|
.field("name", scoped_name)
|
||||||
.field("array_type", array_type)
|
.field("array_type", array_type)
|
||||||
.field("initial_value", initial_value)
|
.field(
|
||||||
|
"initial_value",
|
||||||
|
&initial_value.as_ref().map(|initial_value| {
|
||||||
|
DebugMemoryData::from_bit_slice(*array_type, initial_value)
|
||||||
|
}),
|
||||||
|
)
|
||||||
.field("read_latency", read_latency)
|
.field("read_latency", read_latency)
|
||||||
.field("write_latency", write_latency)
|
.field("write_latency", write_latency)
|
||||||
.field("read_under_write", read_under_write)
|
.field("read_under_write", read_under_write)
|
||||||
|
@ -562,7 +567,7 @@ impl<Element: Type, Len: Size> Mem<Element, Len> {
|
||||||
initial_value: Option<Interned<BitSlice>>,
|
initial_value: Option<Interned<BitSlice>>,
|
||||||
ports: Interned<[MemPort<DynPortType>]>,
|
ports: Interned<[MemPort<DynPortType>]>,
|
||||||
read_latency: usize,
|
read_latency: usize,
|
||||||
write_latency: NonZeroU32,
|
write_latency: NonZeroUsize,
|
||||||
read_under_write: ReadUnderWrite,
|
read_under_write: ReadUnderWrite,
|
||||||
port_annotations: Interned<[TargetedAnnotation]>,
|
port_annotations: Interned<[TargetedAnnotation]>,
|
||||||
mem_annotations: Interned<[Annotation]>,
|
mem_annotations: Interned<[Annotation]>,
|
||||||
|
@ -645,7 +650,7 @@ impl<Element: Type, Len: Size> Mem<Element, Len> {
|
||||||
pub fn read_latency(self) -> usize {
|
pub fn read_latency(self) -> usize {
|
||||||
self.0.read_latency
|
self.0.read_latency
|
||||||
}
|
}
|
||||||
pub fn write_latency(self) -> NonZeroU32 {
|
pub fn write_latency(self) -> NonZeroUsize {
|
||||||
self.0.write_latency
|
self.0.write_latency
|
||||||
}
|
}
|
||||||
pub fn read_under_write(self) -> ReadUnderWrite {
|
pub fn read_under_write(self) -> ReadUnderWrite {
|
||||||
|
@ -707,7 +712,7 @@ pub(crate) struct MemBuilderTarget {
|
||||||
pub(crate) initial_value: Option<Interned<BitSlice>>,
|
pub(crate) initial_value: Option<Interned<BitSlice>>,
|
||||||
pub(crate) ports: Vec<MemPort<DynPortType>>,
|
pub(crate) ports: Vec<MemPort<DynPortType>>,
|
||||||
pub(crate) read_latency: usize,
|
pub(crate) read_latency: usize,
|
||||||
pub(crate) write_latency: NonZeroU32,
|
pub(crate) write_latency: NonZeroUsize,
|
||||||
pub(crate) read_under_write: ReadUnderWrite,
|
pub(crate) read_under_write: ReadUnderWrite,
|
||||||
pub(crate) port_annotations: Vec<TargetedAnnotation>,
|
pub(crate) port_annotations: Vec<TargetedAnnotation>,
|
||||||
pub(crate) mem_annotations: Vec<Annotation>,
|
pub(crate) mem_annotations: Vec<Annotation>,
|
||||||
|
@ -867,7 +872,7 @@ impl<Element: Type, Len: Size> MemBuilder<Element, Len> {
|
||||||
initial_value: None,
|
initial_value: None,
|
||||||
ports: vec![],
|
ports: vec![],
|
||||||
read_latency: 0,
|
read_latency: 0,
|
||||||
write_latency: NonZeroU32::new(1).unwrap(),
|
write_latency: NonZeroUsize::new(1).unwrap(),
|
||||||
read_under_write: ReadUnderWrite::Old,
|
read_under_write: ReadUnderWrite::Old,
|
||||||
port_annotations: vec![],
|
port_annotations: vec![],
|
||||||
mem_annotations: vec![],
|
mem_annotations: vec![],
|
||||||
|
@ -1030,10 +1035,10 @@ impl<Element: Type, Len: Size> MemBuilder<Element, Len> {
|
||||||
pub fn read_latency(&mut self, read_latency: usize) {
|
pub fn read_latency(&mut self, read_latency: usize) {
|
||||||
self.target.borrow_mut().read_latency = read_latency;
|
self.target.borrow_mut().read_latency = read_latency;
|
||||||
}
|
}
|
||||||
pub fn get_write_latency(&self) -> NonZeroU32 {
|
pub fn get_write_latency(&self) -> NonZeroUsize {
|
||||||
self.target.borrow().write_latency
|
self.target.borrow().write_latency
|
||||||
}
|
}
|
||||||
pub fn write_latency(&mut self, write_latency: NonZeroU32) {
|
pub fn write_latency(&mut self, write_latency: NonZeroUsize) {
|
||||||
self.target.borrow_mut().write_latency = write_latency;
|
self.target.borrow_mut().write_latency = write_latency;
|
||||||
}
|
}
|
||||||
pub fn get_read_under_write(&self) -> ReadUnderWrite {
|
pub fn get_read_under_write(&self) -> ReadUnderWrite {
|
||||||
|
@ -1079,3 +1084,61 @@ pub fn splat_mask<T: Type>(ty: T, value: Expr<Bool>) -> Expr<AsMask<T>> {
|
||||||
)),
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait DebugMemoryDataGetElement {
|
||||||
|
fn get_element(&self, element_index: usize, array_type: Array) -> &BitSlice;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, F: ?Sized + Fn(usize, Array) -> &'a BitSlice> DebugMemoryDataGetElement for &'a F {
|
||||||
|
fn get_element(&self, element_index: usize, array_type: Array) -> &BitSlice {
|
||||||
|
self(element_index, array_type)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct DebugMemoryData<GetElement: DebugMemoryDataGetElement> {
|
||||||
|
pub array_type: Array,
|
||||||
|
pub get_element: GetElement,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DebugMemoryDataGetElement for &'_ BitSlice {
|
||||||
|
fn get_element(&self, element_index: usize, array_type: Array) -> &BitSlice {
|
||||||
|
assert!(element_index < array_type.len());
|
||||||
|
let stride = array_type.element().bit_width();
|
||||||
|
let start = element_index
|
||||||
|
.checked_mul(stride)
|
||||||
|
.expect("memory is too big");
|
||||||
|
let end = start.checked_add(stride).expect("memory is too big");
|
||||||
|
&self[start..end]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> DebugMemoryData<&'a BitSlice> {
|
||||||
|
pub fn from_bit_slice<T: Type, Depth: Size>(
|
||||||
|
array_type: ArrayType<T, Depth>,
|
||||||
|
bit_slice: &'a BitSlice,
|
||||||
|
) -> Self {
|
||||||
|
let array_type = array_type.as_dyn_array();
|
||||||
|
assert_eq!(bit_slice.len(), array_type.type_properties().bit_width);
|
||||||
|
Self {
|
||||||
|
array_type,
|
||||||
|
get_element: bit_slice,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<GetElement: DebugMemoryDataGetElement> fmt::Debug for DebugMemoryData<GetElement> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
if self.array_type.len() == 0 {
|
||||||
|
return f.write_str("[]");
|
||||||
|
}
|
||||||
|
writeln!(f, "[\n // len = {:#x}", self.array_type.len())?;
|
||||||
|
for element_index in 0..self.array_type.len() {
|
||||||
|
let element = crate::util::BitSliceWriteWithBase(
|
||||||
|
self.get_element.get_element(element_index, self.array_type),
|
||||||
|
);
|
||||||
|
writeln!(f, " [{element_index:#x}]: {element:#x},")?;
|
||||||
|
}
|
||||||
|
f.write_str("]")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@ use crate::{
|
||||||
intern::{Intern, Interned},
|
intern::{Intern, Interned},
|
||||||
memory::{Mem, MemBuilder, MemBuilderTarget, PortName},
|
memory::{Mem, MemBuilder, MemBuilderTarget, PortName},
|
||||||
reg::Reg,
|
reg::Reg,
|
||||||
|
reset::{AsyncReset, Reset, ResetType, ResetTypeDispatch, SyncReset},
|
||||||
source_location::SourceLocation,
|
source_location::SourceLocation,
|
||||||
ty::{CanonicalType, Type},
|
ty::{CanonicalType, Type},
|
||||||
util::ScopedRef,
|
util::ScopedRef,
|
||||||
|
@ -180,7 +181,7 @@ impl Block {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq, Hash)]
|
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
pub struct StmtConnect {
|
pub struct StmtConnect {
|
||||||
pub lhs: Expr<CanonicalType>,
|
pub lhs: Expr<CanonicalType>,
|
||||||
pub rhs: Expr<CanonicalType>,
|
pub rhs: Expr<CanonicalType>,
|
||||||
|
@ -235,7 +236,7 @@ impl fmt::Debug for StmtConnect {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq, Hash)]
|
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
pub struct StmtFormal {
|
pub struct StmtFormal {
|
||||||
pub kind: FormalKind,
|
pub kind: FormalKind,
|
||||||
pub clk: Expr<Clock>,
|
pub clk: Expr<Clock>,
|
||||||
|
@ -284,6 +285,8 @@ pub struct StmtIf<S: ModuleBuildingStatus = ModuleBuilt> {
|
||||||
pub blocks: [S::Block; 2],
|
pub blocks: [S::Block; 2],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Copy for StmtIf {}
|
||||||
|
|
||||||
impl<S: ModuleBuildingStatus> StmtIf<S> {
|
impl<S: ModuleBuildingStatus> StmtIf<S> {
|
||||||
pub fn then_block(&self) -> S::Block {
|
pub fn then_block(&self) -> S::Block {
|
||||||
self.blocks[0]
|
self.blocks[0]
|
||||||
|
@ -315,6 +318,8 @@ pub struct StmtMatch<S: ModuleBuildingStatus = ModuleBuilt> {
|
||||||
pub blocks: Interned<[S::Block]>,
|
pub blocks: Interned<[S::Block]>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Copy for StmtMatch {}
|
||||||
|
|
||||||
impl StmtMatch {
|
impl StmtMatch {
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn assert_validity(&self) {
|
fn assert_validity(&self) {
|
||||||
|
@ -346,7 +351,7 @@ macro_rules! wrapper_enum {
|
||||||
$(#[$enum_meta:meta])*
|
$(#[$enum_meta:meta])*
|
||||||
$vis:vis enum $enum_name:ident<$T_enum:ident: $T_bound:ident = $T_enum_default:ident> {
|
$vis:vis enum $enum_name:ident<$T_enum:ident: $T_bound:ident = $T_enum_default:ident> {
|
||||||
$(
|
$(
|
||||||
#[is = $is_fn:ident, as_ref = $as_ref_fn:ident]
|
#[is = $is_fn:ident, as_ref = $as_ref_fn:ident $(, from = $from:ident)?]
|
||||||
$(#[$variant_meta:meta])*
|
$(#[$variant_meta:meta])*
|
||||||
$Variant:ident($VariantTy:ty),
|
$Variant:ident($VariantTy:ty),
|
||||||
)*
|
)*
|
||||||
|
@ -358,7 +363,7 @@ macro_rules! wrapper_enum {
|
||||||
$(#[$enum_meta])*
|
$(#[$enum_meta])*
|
||||||
$vis enum $enum_name<$T_enum: $T_bound = $T_enum_default> {
|
$vis enum $enum_name<$T_enum: $T_bound = $T_enum_default> {
|
||||||
$(
|
$(
|
||||||
#[is = $is_fn, as_ref = $as_ref_fn]
|
#[is = $is_fn, as_ref = $as_ref_fn $(, from = $from)?]
|
||||||
$(#[$variant_meta])*
|
$(#[$variant_meta])*
|
||||||
$Variant($VariantTy),
|
$Variant($VariantTy),
|
||||||
)*
|
)*
|
||||||
|
@ -385,7 +390,7 @@ macro_rules! wrapper_enum {
|
||||||
$(#[$enum_meta:meta])*
|
$(#[$enum_meta:meta])*
|
||||||
$vis:vis enum $enum_name:ident<$T_enum:ident: $T_bound:ident = $T_enum_default:ident> {
|
$vis:vis enum $enum_name:ident<$T_enum:ident: $T_bound:ident = $T_enum_default:ident> {
|
||||||
$(
|
$(
|
||||||
#[is = $is_fn:ident, as_ref = $as_ref_fn:ident]
|
#[is = $is_fn:ident, as_ref = $as_ref_fn:ident $(, from = $from:ident)?]
|
||||||
$(#[$variant_meta:meta])*
|
$(#[$variant_meta:meta])*
|
||||||
$Variant:ident($VariantTy:ty),
|
$Variant:ident($VariantTy:ty),
|
||||||
)*
|
)*
|
||||||
|
@ -397,22 +402,22 @@ macro_rules! wrapper_enum {
|
||||||
$(#[$enum_meta])*
|
$(#[$enum_meta])*
|
||||||
$vis enum $enum_name<$T_enum: $T_bound = $T_enum_default> {
|
$vis enum $enum_name<$T_enum: $T_bound = $T_enum_default> {
|
||||||
$(
|
$(
|
||||||
#[is = $is_fn, as_ref = $as_ref_fn]
|
#[is = $is_fn, as_ref = $as_ref_fn $(, from = $from)?]
|
||||||
$(#[$variant_meta])*
|
$(#[$variant_meta])*
|
||||||
$Variant($VariantTy),
|
$Variant($VariantTy),
|
||||||
)*
|
)*
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$(
|
$($(
|
||||||
wrapper_enum! {
|
wrapper_enum! {
|
||||||
impl $T_to From<$VariantTy> for $to_type {
|
impl $T_to From<$VariantTy> for $to_type {
|
||||||
fn from(value: $VariantTy) -> Self {
|
fn $from(value: $VariantTy) -> Self {
|
||||||
$enum_name::$Variant(value).into()
|
$enum_name::$Variant(value).into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)*
|
)?)*
|
||||||
};
|
};
|
||||||
(
|
(
|
||||||
#[impl()]
|
#[impl()]
|
||||||
|
@ -420,7 +425,7 @@ macro_rules! wrapper_enum {
|
||||||
$(#[$enum_meta:meta])*
|
$(#[$enum_meta:meta])*
|
||||||
$vis:vis enum $enum_name:ident<$T_enum:ident: $T_bound:ident = $T_enum_default:ident> {
|
$vis:vis enum $enum_name:ident<$T_enum:ident: $T_bound:ident = $T_enum_default:ident> {
|
||||||
$(
|
$(
|
||||||
#[is = $is_fn:ident, as_ref = $as_ref_fn:ident]
|
#[is = $is_fn:ident, as_ref = $as_ref_fn:ident $(, from = $from:ident)?]
|
||||||
$(#[$variant_meta:meta])*
|
$(#[$variant_meta:meta])*
|
||||||
$Variant:ident($VariantTy:ty),
|
$Variant:ident($VariantTy:ty),
|
||||||
)*
|
)*
|
||||||
|
@ -459,13 +464,15 @@ pub struct StmtWire<S: ModuleBuildingStatus = ModuleBuilt> {
|
||||||
pub wire: Wire<CanonicalType>,
|
pub wire: Wire<CanonicalType>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Copy for StmtWire {}
|
||||||
|
|
||||||
#[derive(Hash, Clone, PartialEq, Eq, Debug)]
|
#[derive(Hash, Clone, PartialEq, Eq, Debug)]
|
||||||
pub struct StmtReg<S: ModuleBuildingStatus = ModuleBuilt> {
|
pub struct StmtReg<R: ResetType, S: ModuleBuildingStatus = ModuleBuilt> {
|
||||||
pub annotations: S::StmtAnnotations,
|
pub annotations: S::StmtAnnotations,
|
||||||
pub reg: Reg<CanonicalType>,
|
pub reg: Reg<CanonicalType, R>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Copy for StmtReg {}
|
impl<R: ResetType> Copy for StmtReg<R> {}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
|
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
|
||||||
pub struct StmtInstance<S: ModuleBuildingStatus = ModuleBuilt> {
|
pub struct StmtInstance<S: ModuleBuildingStatus = ModuleBuilt> {
|
||||||
|
@ -473,6 +480,8 @@ pub struct StmtInstance<S: ModuleBuildingStatus = ModuleBuilt> {
|
||||||
pub instance: Instance<Bundle>,
|
pub instance: Instance<Bundle>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Copy for StmtInstance {}
|
||||||
|
|
||||||
wrapper_enum! {
|
wrapper_enum! {
|
||||||
#[impl(
|
#[impl(
|
||||||
(<S: ModuleBuildingStatus>) self: StmtDeclaration<S> = self,
|
(<S: ModuleBuildingStatus>) self: StmtDeclaration<S> = self,
|
||||||
|
@ -481,20 +490,57 @@ wrapper_enum! {
|
||||||
#[to((<S: ModuleBuildingStatus>) StmtDeclaration<S>, (<S: ModuleBuildingStatus>) Stmt<S>)]
|
#[to((<S: ModuleBuildingStatus>) StmtDeclaration<S>, (<S: ModuleBuildingStatus>) Stmt<S>)]
|
||||||
#[derive(Clone, PartialEq, Eq, Hash)]
|
#[derive(Clone, PartialEq, Eq, Hash)]
|
||||||
pub enum StmtDeclaration<S: ModuleBuildingStatus = ModuleBuilt> {
|
pub enum StmtDeclaration<S: ModuleBuildingStatus = ModuleBuilt> {
|
||||||
#[is = is_wire, as_ref = wire]
|
#[is = is_wire, as_ref = wire, from = from]
|
||||||
Wire(StmtWire<S>),
|
Wire(StmtWire<S>),
|
||||||
#[is = is_reg, as_ref = reg]
|
#[is = is_reg, as_ref = reg]
|
||||||
Reg(StmtReg<S>),
|
Reg(StmtReg<Reset, S>),
|
||||||
#[is = is_instance, as_ref = instance]
|
#[is = is_reg_sync, as_ref = reg_sync]
|
||||||
|
RegSync(StmtReg<SyncReset, S>),
|
||||||
|
#[is = is_reg_async, as_ref = reg_async]
|
||||||
|
RegAsync(StmtReg<AsyncReset, S>),
|
||||||
|
#[is = is_instance, as_ref = instance, from = from]
|
||||||
Instance(StmtInstance<S>),
|
Instance(StmtInstance<S>),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Copy for StmtDeclaration {}
|
||||||
|
|
||||||
|
impl<S: ModuleBuildingStatus, R: ResetType> From<StmtReg<R, S>> for Stmt<S> {
|
||||||
|
fn from(value: StmtReg<R, S>) -> Self {
|
||||||
|
StmtDeclaration::from(value).into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S: ModuleBuildingStatus, R: ResetType> From<StmtReg<R, S>> for StmtDeclaration<S> {
|
||||||
|
fn from(value: StmtReg<R, S>) -> Self {
|
||||||
|
struct Dispatch<S>(PhantomData<S>);
|
||||||
|
impl<S: ModuleBuildingStatus> ResetTypeDispatch for Dispatch<S> {
|
||||||
|
type Input<T: ResetType> = StmtReg<T, S>;
|
||||||
|
type Output<T: ResetType> = StmtDeclaration<S>;
|
||||||
|
|
||||||
|
fn reset(self, input: Self::Input<Reset>) -> Self::Output<Reset> {
|
||||||
|
StmtDeclaration::Reg(input)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sync_reset(self, input: Self::Input<SyncReset>) -> Self::Output<SyncReset> {
|
||||||
|
StmtDeclaration::RegSync(input)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn async_reset(self, input: Self::Input<AsyncReset>) -> Self::Output<AsyncReset> {
|
||||||
|
StmtDeclaration::RegAsync(input)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
R::dispatch(value, Dispatch(PhantomData))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<S: ModuleBuildingStatus> StmtDeclaration<S> {
|
impl<S: ModuleBuildingStatus> StmtDeclaration<S> {
|
||||||
pub fn annotations(&self) -> S::StmtAnnotations {
|
pub fn annotations(&self) -> S::StmtAnnotations {
|
||||||
match self {
|
match self {
|
||||||
StmtDeclaration::Wire(v) => v.annotations,
|
StmtDeclaration::Wire(v) => v.annotations,
|
||||||
StmtDeclaration::Reg(v) => v.annotations,
|
StmtDeclaration::Reg(v) => v.annotations,
|
||||||
|
StmtDeclaration::RegSync(v) => v.annotations,
|
||||||
|
StmtDeclaration::RegAsync(v) => v.annotations,
|
||||||
StmtDeclaration::Instance(v) => v.annotations,
|
StmtDeclaration::Instance(v) => v.annotations,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -502,6 +548,8 @@ impl<S: ModuleBuildingStatus> StmtDeclaration<S> {
|
||||||
match self {
|
match self {
|
||||||
StmtDeclaration::Wire(v) => v.wire.source_location(),
|
StmtDeclaration::Wire(v) => v.wire.source_location(),
|
||||||
StmtDeclaration::Reg(v) => v.reg.source_location(),
|
StmtDeclaration::Reg(v) => v.reg.source_location(),
|
||||||
|
StmtDeclaration::RegSync(v) => v.reg.source_location(),
|
||||||
|
StmtDeclaration::RegAsync(v) => v.reg.source_location(),
|
||||||
StmtDeclaration::Instance(v) => v.instance.source_location(),
|
StmtDeclaration::Instance(v) => v.instance.source_location(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -509,20 +557,26 @@ impl<S: ModuleBuildingStatus> StmtDeclaration<S> {
|
||||||
match self {
|
match self {
|
||||||
StmtDeclaration::Wire(v) => v.wire.scoped_name(),
|
StmtDeclaration::Wire(v) => v.wire.scoped_name(),
|
||||||
StmtDeclaration::Reg(v) => v.reg.scoped_name(),
|
StmtDeclaration::Reg(v) => v.reg.scoped_name(),
|
||||||
|
StmtDeclaration::RegSync(v) => v.reg.scoped_name(),
|
||||||
|
StmtDeclaration::RegAsync(v) => v.reg.scoped_name(),
|
||||||
StmtDeclaration::Instance(v) => v.instance.scoped_name(),
|
StmtDeclaration::Instance(v) => v.instance.scoped_name(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn sub_stmt_blocks(&self) -> &[S::Block] {
|
pub fn sub_stmt_blocks(&self) -> &[S::Block] {
|
||||||
match self {
|
match self {
|
||||||
StmtDeclaration::Wire(_) | StmtDeclaration::Reg(_) | StmtDeclaration::Instance(_) => {
|
StmtDeclaration::Wire(_)
|
||||||
&[]
|
| StmtDeclaration::Reg(_)
|
||||||
}
|
| StmtDeclaration::RegSync(_)
|
||||||
|
| StmtDeclaration::RegAsync(_)
|
||||||
|
| StmtDeclaration::Instance(_) => &[],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn canonical_ty(&self) -> CanonicalType {
|
pub fn canonical_ty(&self) -> CanonicalType {
|
||||||
match self {
|
match self {
|
||||||
StmtDeclaration::Wire(v) => v.wire.ty(),
|
StmtDeclaration::Wire(v) => v.wire.ty(),
|
||||||
StmtDeclaration::Reg(v) => v.reg.ty(),
|
StmtDeclaration::Reg(v) => v.reg.ty(),
|
||||||
|
StmtDeclaration::RegSync(v) => v.reg.ty(),
|
||||||
|
StmtDeclaration::RegAsync(v) => v.reg.ty(),
|
||||||
StmtDeclaration::Instance(v) => CanonicalType::Bundle(v.instance.ty()),
|
StmtDeclaration::Instance(v) => CanonicalType::Bundle(v.instance.ty()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -533,19 +587,21 @@ wrapper_enum! {
|
||||||
#[to((<S: ModuleBuildingStatus>) Stmt<S>)]
|
#[to((<S: ModuleBuildingStatus>) Stmt<S>)]
|
||||||
#[derive(Clone, PartialEq, Eq, Hash)]
|
#[derive(Clone, PartialEq, Eq, Hash)]
|
||||||
pub enum Stmt<S: ModuleBuildingStatus = ModuleBuilt> {
|
pub enum Stmt<S: ModuleBuildingStatus = ModuleBuilt> {
|
||||||
#[is = is_connect, as_ref = connect]
|
#[is = is_connect, as_ref = connect, from = from]
|
||||||
Connect(StmtConnect),
|
Connect(StmtConnect),
|
||||||
#[is = is_formal, as_ref = formal]
|
#[is = is_formal, as_ref = formal, from = from]
|
||||||
Formal(StmtFormal),
|
Formal(StmtFormal),
|
||||||
#[is = is_if, as_ref = if_]
|
#[is = is_if, as_ref = if_, from = from]
|
||||||
If(StmtIf<S>),
|
If(StmtIf<S>),
|
||||||
#[is = is_match, as_ref = match_]
|
#[is = is_match, as_ref = match_, from = from]
|
||||||
Match(StmtMatch<S>),
|
Match(StmtMatch<S>),
|
||||||
#[is = is_declaration, as_ref = declaration]
|
#[is = is_declaration, as_ref = declaration, from = from]
|
||||||
Declaration(StmtDeclaration<S>),
|
Declaration(StmtDeclaration<S>),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Copy for Stmt {}
|
||||||
|
|
||||||
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 {
|
||||||
|
@ -714,6 +770,18 @@ impl<T: BundleType> Instance<T> {
|
||||||
source_location,
|
source_location,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pub fn from_canonical(v: Instance<Bundle>) -> Self {
|
||||||
|
let Instance {
|
||||||
|
scoped_name,
|
||||||
|
instantiated,
|
||||||
|
source_location,
|
||||||
|
} = v;
|
||||||
|
Self {
|
||||||
|
scoped_name,
|
||||||
|
instantiated: Module::from_canonical(*instantiated).intern_sized(),
|
||||||
|
source_location,
|
||||||
|
}
|
||||||
|
}
|
||||||
pub fn containing_module_name(self) -> Interned<str> {
|
pub fn containing_module_name(self) -> Interned<str> {
|
||||||
self.containing_module_name_id().0
|
self.containing_module_name_id().0
|
||||||
}
|
}
|
||||||
|
@ -958,6 +1026,14 @@ impl From<NormalModuleBody<ModuleBuilding>> for NormalModuleBody {
|
||||||
annotations: (),
|
annotations: (),
|
||||||
reg,
|
reg,
|
||||||
}) => StmtReg { annotations, reg }.into(),
|
}) => StmtReg { annotations, reg }.into(),
|
||||||
|
StmtDeclaration::RegSync(StmtReg {
|
||||||
|
annotations: (),
|
||||||
|
reg,
|
||||||
|
}) => StmtReg { annotations, reg }.into(),
|
||||||
|
StmtDeclaration::RegAsync(StmtReg {
|
||||||
|
annotations: (),
|
||||||
|
reg,
|
||||||
|
}) => StmtReg { annotations, reg }.into(),
|
||||||
StmtDeclaration::Instance(StmtInstance {
|
StmtDeclaration::Instance(StmtInstance {
|
||||||
annotations: (),
|
annotations: (),
|
||||||
instance,
|
instance,
|
||||||
|
@ -1661,6 +1737,14 @@ impl AssertValidityState {
|
||||||
annotations: _,
|
annotations: _,
|
||||||
reg,
|
reg,
|
||||||
})) => self.insert_new_base(TargetBase::intern_sized(reg.into()), block),
|
})) => self.insert_new_base(TargetBase::intern_sized(reg.into()), block),
|
||||||
|
Stmt::Declaration(StmtDeclaration::RegSync(StmtReg {
|
||||||
|
annotations: _,
|
||||||
|
reg,
|
||||||
|
})) => self.insert_new_base(TargetBase::intern_sized(reg.into()), block),
|
||||||
|
Stmt::Declaration(StmtDeclaration::RegAsync(StmtReg {
|
||||||
|
annotations: _,
|
||||||
|
reg,
|
||||||
|
})) => self.insert_new_base(TargetBase::intern_sized(reg.into()), block),
|
||||||
Stmt::Declaration(StmtDeclaration::Instance(StmtInstance {
|
Stmt::Declaration(StmtDeclaration::Instance(StmtInstance {
|
||||||
annotations: _,
|
annotations: _,
|
||||||
instance,
|
instance,
|
||||||
|
@ -1842,10 +1926,10 @@ impl<CD> RegBuilder<CD, (), ()> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I, T: Type> RegBuilder<(), I, T> {
|
impl<I, T: Type> RegBuilder<(), I, T> {
|
||||||
pub fn clock_domain(
|
pub fn clock_domain<R: ResetType>(
|
||||||
self,
|
self,
|
||||||
clock_domain: impl ToExpr<Type = ClockDomain>,
|
clock_domain: impl ToExpr<Type = ClockDomain<R>>,
|
||||||
) -> RegBuilder<Expr<ClockDomain>, I, T> {
|
) -> RegBuilder<Expr<ClockDomain<R>>, I, T> {
|
||||||
let Self {
|
let Self {
|
||||||
name,
|
name,
|
||||||
source_location,
|
source_location,
|
||||||
|
@ -1863,7 +1947,7 @@ impl<I, T: Type> RegBuilder<(), I, T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Type> RegBuilder<Expr<ClockDomain>, Option<Expr<T>>, T> {
|
impl<T: Type, R: ResetType> RegBuilder<Expr<ClockDomain<R>>, Option<Expr<T>>, T> {
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
pub fn build(self) -> Expr<T> {
|
pub fn build(self) -> Expr<T> {
|
||||||
let Self {
|
let Self {
|
||||||
|
@ -2188,6 +2272,16 @@ pub fn annotate<T: Type>(target: Expr<T>, annotations: impl IntoAnnotations) {
|
||||||
reg,
|
reg,
|
||||||
}
|
}
|
||||||
.into(),
|
.into(),
|
||||||
|
TargetBase::RegSync(reg) => StmtReg {
|
||||||
|
annotations: (),
|
||||||
|
reg,
|
||||||
|
}
|
||||||
|
.into(),
|
||||||
|
TargetBase::RegAsync(reg) => StmtReg {
|
||||||
|
annotations: (),
|
||||||
|
reg,
|
||||||
|
}
|
||||||
|
.into(),
|
||||||
TargetBase::Wire(wire) => StmtWire {
|
TargetBase::Wire(wire) => StmtWire {
|
||||||
annotations: (),
|
annotations: (),
|
||||||
wire,
|
wire,
|
||||||
|
@ -2629,3 +2723,50 @@ impl<T: Type> ModuleIO<T> {
|
||||||
self.ty
|
self.ty
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Eq, Hash, Clone, Copy)]
|
||||||
|
pub enum InstantiatedModule {
|
||||||
|
Base(Interned<Module<Bundle>>),
|
||||||
|
Child {
|
||||||
|
parent: Interned<InstantiatedModule>,
|
||||||
|
instance: Interned<Instance<Bundle>>,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
impl InstantiatedModule {
|
||||||
|
pub fn leaf_module(self) -> Interned<Module<Bundle>> {
|
||||||
|
match self {
|
||||||
|
InstantiatedModule::Base(base) => base,
|
||||||
|
InstantiatedModule::Child { instance, .. } => instance.instantiated(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn write_path(self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
InstantiatedModule::Base(base) => fmt::Debug::fmt(&base.name_id(), f),
|
||||||
|
InstantiatedModule::Child { parent, instance } => {
|
||||||
|
parent.write_path(f)?;
|
||||||
|
write!(f, ".{}", instance.name_id())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for InstantiatedModule {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "InstantiatedModule(")?;
|
||||||
|
self.write_path(f)?;
|
||||||
|
write!(f, ": {})", self.leaf_module().name_id())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
|
||||||
|
pub struct TargetInInstantiatedModule {
|
||||||
|
pub instantiated_module: InstantiatedModule,
|
||||||
|
pub target: Target,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
|
||||||
|
pub struct ExprInInstantiatedModule<T: Type> {
|
||||||
|
pub instantiated_module: InstantiatedModule,
|
||||||
|
pub expr: Expr<T>,
|
||||||
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
// 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 mod deduce_resets;
|
||||||
pub mod simplify_enums;
|
pub mod simplify_enums;
|
||||||
pub mod simplify_memories;
|
pub mod simplify_memories;
|
||||||
pub mod visit;
|
pub mod visit;
|
||||||
|
|
2273
crates/fayalite/src/module/transform/deduce_resets.rs
Normal file
2273
crates/fayalite/src/module/transform/deduce_resets.rs
Normal file
File diff suppressed because it is too large
Load diff
|
@ -764,7 +764,9 @@ impl Folder for State {
|
||||||
| ExprEnum::ModuleIO(_)
|
| ExprEnum::ModuleIO(_)
|
||||||
| ExprEnum::Instance(_)
|
| ExprEnum::Instance(_)
|
||||||
| ExprEnum::Wire(_)
|
| ExprEnum::Wire(_)
|
||||||
| ExprEnum::Reg(_) => op.default_fold(self),
|
| ExprEnum::Reg(_)
|
||||||
|
| ExprEnum::RegSync(_)
|
||||||
|
| ExprEnum::RegAsync(_) => op.default_fold(self),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,7 @@ use crate::{
|
||||||
StmtInstance, StmtMatch, StmtReg, StmtWire,
|
StmtInstance, StmtMatch, StmtReg, StmtWire,
|
||||||
},
|
},
|
||||||
reg::Reg,
|
reg::Reg,
|
||||||
reset::{AsyncReset, Reset, SyncReset},
|
reset::{AsyncReset, Reset, ResetType, SyncReset},
|
||||||
source_location::SourceLocation,
|
source_location::SourceLocation,
|
||||||
ty::{CanonicalType, Type},
|
ty::{CanonicalType, Type},
|
||||||
wire::Wire,
|
wire::Wire,
|
||||||
|
|
|
@ -5,21 +5,22 @@ use crate::{
|
||||||
expr::{Expr, Flow},
|
expr::{Expr, Flow},
|
||||||
intern::Interned,
|
intern::Interned,
|
||||||
module::{NameId, ScopedNameId},
|
module::{NameId, ScopedNameId},
|
||||||
|
reset::{Reset, ResetType},
|
||||||
source_location::SourceLocation,
|
source_location::SourceLocation,
|
||||||
ty::{CanonicalType, Type},
|
ty::{CanonicalType, Type},
|
||||||
};
|
};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
|
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
|
||||||
pub struct Reg<T: Type> {
|
pub struct Reg<T: Type, R: ResetType = Reset> {
|
||||||
name: ScopedNameId,
|
name: ScopedNameId,
|
||||||
source_location: SourceLocation,
|
source_location: SourceLocation,
|
||||||
ty: T,
|
ty: T,
|
||||||
clock_domain: Expr<ClockDomain>,
|
clock_domain: Expr<ClockDomain<R>>,
|
||||||
init: Option<Expr<T>>,
|
init: Option<Expr<T>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Type + fmt::Debug> fmt::Debug for Reg<T> {
|
impl<T: Type + fmt::Debug, R: ResetType> fmt::Debug for Reg<T, R> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
let Self {
|
let Self {
|
||||||
name,
|
name,
|
||||||
|
@ -37,8 +38,8 @@ impl<T: Type + fmt::Debug> fmt::Debug for Reg<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Type> Reg<T> {
|
impl<T: Type, R: ResetType> Reg<T, R> {
|
||||||
pub fn canonical(&self) -> Reg<CanonicalType> {
|
pub fn canonical(&self) -> Reg<CanonicalType, R> {
|
||||||
let Self {
|
let Self {
|
||||||
name,
|
name,
|
||||||
source_location,
|
source_location,
|
||||||
|
@ -59,7 +60,7 @@ impl<T: Type> Reg<T> {
|
||||||
scoped_name: ScopedNameId,
|
scoped_name: ScopedNameId,
|
||||||
source_location: SourceLocation,
|
source_location: SourceLocation,
|
||||||
ty: T,
|
ty: T,
|
||||||
clock_domain: Expr<ClockDomain>,
|
clock_domain: Expr<ClockDomain<R>>,
|
||||||
init: Option<Expr<T>>,
|
init: Option<Expr<T>>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
assert!(
|
assert!(
|
||||||
|
@ -98,7 +99,7 @@ impl<T: Type> Reg<T> {
|
||||||
pub fn scoped_name(&self) -> ScopedNameId {
|
pub fn scoped_name(&self) -> ScopedNameId {
|
||||||
self.name
|
self.name
|
||||||
}
|
}
|
||||||
pub fn clock_domain(&self) -> Expr<ClockDomain> {
|
pub fn clock_domain(&self) -> Expr<ClockDomain<R>> {
|
||||||
self.clock_domain
|
self.clock_domain
|
||||||
}
|
}
|
||||||
pub fn init(&self) -> Option<Expr<T>> {
|
pub fn init(&self) -> Option<Expr<T>> {
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
// 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 crate::{
|
use crate::{
|
||||||
expr::{Expr, ToExpr},
|
clock::Clock,
|
||||||
int::Bool,
|
expr::{ops, Expr, ToExpr},
|
||||||
|
int::{Bool, SInt, UInt},
|
||||||
source_location::SourceLocation,
|
source_location::SourceLocation,
|
||||||
ty::{impl_match_variant_as_self, CanonicalType, StaticType, Type, TypeProperties},
|
ty::{impl_match_variant_as_self, CanonicalType, StaticType, Type, TypeProperties},
|
||||||
};
|
};
|
||||||
|
@ -11,10 +12,33 @@ mod sealed {
|
||||||
pub trait ResetTypeSealed {}
|
pub trait ResetTypeSealed {}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait ResetType: StaticType<MaskType = Bool> + sealed::ResetTypeSealed {}
|
pub trait ResetType:
|
||||||
|
StaticType<MaskType = Bool>
|
||||||
|
+ sealed::ResetTypeSealed
|
||||||
|
+ ops::ExprCastTo<Bool>
|
||||||
|
+ ops::ExprCastTo<Reset>
|
||||||
|
+ ops::ExprCastTo<SyncReset>
|
||||||
|
+ ops::ExprCastTo<AsyncReset>
|
||||||
|
+ ops::ExprCastTo<Clock>
|
||||||
|
+ ops::ExprCastTo<UInt<1>>
|
||||||
|
+ ops::ExprCastTo<SInt<1>>
|
||||||
|
+ ops::ExprCastTo<UInt>
|
||||||
|
+ ops::ExprCastTo<SInt>
|
||||||
|
{
|
||||||
|
fn dispatch<D: ResetTypeDispatch>(input: D::Input<Self>, dispatch: D) -> D::Output<Self>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait ResetTypeDispatch: Sized {
|
||||||
|
type Input<T: ResetType>;
|
||||||
|
type Output<T: ResetType>;
|
||||||
|
|
||||||
|
fn reset(self, input: Self::Input<Reset>) -> Self::Output<Reset>;
|
||||||
|
fn sync_reset(self, input: Self::Input<SyncReset>) -> Self::Output<SyncReset>;
|
||||||
|
fn async_reset(self, input: Self::Input<AsyncReset>) -> Self::Output<AsyncReset>;
|
||||||
|
}
|
||||||
|
|
||||||
macro_rules! reset_type {
|
macro_rules! reset_type {
|
||||||
($name:ident, $Trait:ident::$trait_fn:ident, $is_castable_from_bits:literal) => {
|
($name:ident, $(#[$impl_trait:ident])? $Trait:ident::$trait_fn:ident, $is_castable_from_bits:literal, $dispatch_fn:ident) => {
|
||||||
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Default)]
|
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Default)]
|
||||||
pub struct $name;
|
pub struct $name;
|
||||||
|
|
||||||
|
@ -67,7 +91,14 @@ macro_rules! reset_type {
|
||||||
|
|
||||||
impl sealed::ResetTypeSealed for $name {}
|
impl sealed::ResetTypeSealed for $name {}
|
||||||
|
|
||||||
impl ResetType for $name {}
|
impl ResetType for $name {
|
||||||
|
fn dispatch<D: ResetTypeDispatch>(
|
||||||
|
input: D::Input<Self>,
|
||||||
|
dispatch: D,
|
||||||
|
) -> D::Output<Self> {
|
||||||
|
dispatch.$dispatch_fn(input)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub trait $Trait {
|
pub trait $Trait {
|
||||||
fn $trait_fn(&self) -> Expr<$name>;
|
fn $trait_fn(&self) -> Expr<$name>;
|
||||||
|
@ -91,20 +122,21 @@ macro_rules! reset_type {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl $Trait for Expr<$name> {
|
$($impl_trait $Trait for Expr<$name> {
|
||||||
fn $trait_fn(&self) -> Expr<$name> {
|
fn $trait_fn(&self) -> Expr<$name> {
|
||||||
*self
|
*self
|
||||||
}
|
}
|
||||||
}
|
})?
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
reset_type!(AsyncReset, ToAsyncReset::to_async_reset, true);
|
reset_type!(AsyncReset, #[impl] ToAsyncReset::to_async_reset, true, async_reset);
|
||||||
reset_type!(SyncReset, ToSyncReset::to_sync_reset, true);
|
reset_type!(SyncReset, #[impl] ToSyncReset::to_sync_reset, true, sync_reset);
|
||||||
reset_type!(
|
reset_type!(
|
||||||
Reset,
|
Reset,
|
||||||
ToReset::to_reset,
|
ToReset::to_reset,
|
||||||
false // Reset is not castable from bits because we don't know if it's async or sync
|
false, // Reset is not castable from bits because we don't know if it's async or sync
|
||||||
|
reset
|
||||||
);
|
);
|
||||||
|
|
||||||
impl ToSyncReset for bool {
|
impl ToSyncReset for bool {
|
||||||
|
|
7356
crates/fayalite/src/sim.rs
Normal file
7356
crates/fayalite/src/sim.rs
Normal file
File diff suppressed because it is too large
Load diff
3185
crates/fayalite/src/sim/interpreter.rs
Normal file
3185
crates/fayalite/src/sim/interpreter.rs
Normal file
File diff suppressed because it is too large
Load diff
397
crates/fayalite/src/sim/time.rs
Normal file
397
crates/fayalite/src/sim/time.rs
Normal file
|
@ -0,0 +1,397 @@
|
||||||
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
|
// See Notices.txt for copyright information
|
||||||
|
use std::{
|
||||||
|
fmt,
|
||||||
|
ops::{Add, AddAssign, Sub, SubAssign},
|
||||||
|
time::Duration,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
|
||||||
|
pub struct SimInstant {
|
||||||
|
time_since_start: SimDuration,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SimInstant {
|
||||||
|
pub const fn checked_add(self, duration: SimDuration) -> Option<Self> {
|
||||||
|
let Some(time_since_start) = self.time_since_start.checked_add(duration) else {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
Some(SimInstant { time_since_start })
|
||||||
|
}
|
||||||
|
pub const fn checked_duration_since(self, earlier: Self) -> Option<SimDuration> {
|
||||||
|
self.time_since_start.checked_sub(earlier.time_since_start)
|
||||||
|
}
|
||||||
|
pub const fn checked_sub(self, duration: SimDuration) -> Option<Self> {
|
||||||
|
let Some(time_since_start) = self.time_since_start.checked_sub(duration) else {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
Some(SimInstant { time_since_start })
|
||||||
|
}
|
||||||
|
#[track_caller]
|
||||||
|
pub const fn duration_since(self, earlier: Self) -> SimDuration {
|
||||||
|
let Some(retval) = self.checked_duration_since(earlier) else {
|
||||||
|
panic!(
|
||||||
|
"tried to compute the duration since a later time -- durations can't be negative"
|
||||||
|
);
|
||||||
|
};
|
||||||
|
retval
|
||||||
|
}
|
||||||
|
pub const fn saturating_duration_since(self, earlier: Self) -> SimDuration {
|
||||||
|
let Some(retval) = self.checked_duration_since(earlier) else {
|
||||||
|
return SimDuration::ZERO;
|
||||||
|
};
|
||||||
|
retval
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Add<SimDuration> for SimInstant {
|
||||||
|
type Output = SimInstant;
|
||||||
|
|
||||||
|
#[track_caller]
|
||||||
|
fn add(mut self, rhs: SimDuration) -> Self::Output {
|
||||||
|
self += rhs;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AddAssign<SimDuration> for SimInstant {
|
||||||
|
#[track_caller]
|
||||||
|
fn add_assign(&mut self, rhs: SimDuration) {
|
||||||
|
self.time_since_start += rhs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Add<SimInstant> for SimDuration {
|
||||||
|
type Output = SimInstant;
|
||||||
|
|
||||||
|
#[track_caller]
|
||||||
|
fn add(self, rhs: SimInstant) -> Self::Output {
|
||||||
|
rhs.add(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Sub for SimInstant {
|
||||||
|
type Output = SimDuration;
|
||||||
|
|
||||||
|
#[track_caller]
|
||||||
|
fn sub(self, rhs: SimInstant) -> Self::Output {
|
||||||
|
self.duration_since(rhs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Sub<SimDuration> for SimInstant {
|
||||||
|
type Output = SimInstant;
|
||||||
|
|
||||||
|
#[track_caller]
|
||||||
|
fn sub(self, rhs: SimDuration) -> Self::Output {
|
||||||
|
let Some(retval) = self.checked_sub(rhs) else {
|
||||||
|
panic!("SimInstant underflow");
|
||||||
|
};
|
||||||
|
retval
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SubAssign<SimDuration> for SimInstant {
|
||||||
|
#[track_caller]
|
||||||
|
fn sub_assign(&mut self, rhs: SimDuration) {
|
||||||
|
*self = *self - rhs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SimInstant {
|
||||||
|
pub const START: SimInstant = SimInstant {
|
||||||
|
time_since_start: SimDuration::ZERO,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for SimInstant {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
self.time_since_start.fmt(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
|
||||||
|
pub struct SimDuration {
|
||||||
|
attos: u128,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AddAssign for SimDuration {
|
||||||
|
#[track_caller]
|
||||||
|
fn add_assign(&mut self, rhs: SimDuration) {
|
||||||
|
*self = *self + rhs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Add for SimDuration {
|
||||||
|
type Output = SimDuration;
|
||||||
|
|
||||||
|
#[track_caller]
|
||||||
|
fn add(self, rhs: SimDuration) -> Self::Output {
|
||||||
|
SimDuration {
|
||||||
|
attos: self
|
||||||
|
.attos
|
||||||
|
.checked_add(rhs.attos)
|
||||||
|
.expect("overflow adding durations"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Sub for SimDuration {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
#[track_caller]
|
||||||
|
fn sub(self, rhs: Self) -> Self::Output {
|
||||||
|
SimDuration {
|
||||||
|
attos: self
|
||||||
|
.attos
|
||||||
|
.checked_add(rhs.attos)
|
||||||
|
.expect("underflow subtracting durations -- durations can't be negative"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SubAssign for SimDuration {
|
||||||
|
#[track_caller]
|
||||||
|
fn sub_assign(&mut self, rhs: Self) {
|
||||||
|
*self = *self - rhs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Default)]
|
||||||
|
pub struct SimDurationParts {
|
||||||
|
pub attos: u16,
|
||||||
|
pub femtos: u16,
|
||||||
|
pub picos: u16,
|
||||||
|
pub nanos: u16,
|
||||||
|
pub micros: u16,
|
||||||
|
pub millis: u16,
|
||||||
|
pub secs: u128,
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! impl_duration_units {
|
||||||
|
(
|
||||||
|
$(
|
||||||
|
#[unit_const = $UNIT:ident, from_units = $from_units:ident, as_units = $as_units:ident, units = $units:ident, suffix = $suffix:literal]
|
||||||
|
const $log10_units_per_sec:ident: u32 = $log10_units_per_sec_value:expr;
|
||||||
|
)*
|
||||||
|
) => {
|
||||||
|
impl SimDuration {
|
||||||
|
$(
|
||||||
|
const $log10_units_per_sec: u32 = $log10_units_per_sec_value;
|
||||||
|
pub const fn $from_units($units: u128) -> Self {
|
||||||
|
Self::from_units_helper::<{ Self::$log10_units_per_sec }>($units)
|
||||||
|
}
|
||||||
|
pub const fn $as_units(self) -> u128 {
|
||||||
|
self.attos / const { 10u128.pow(Self::LOG10_ATTOS_PER_SEC - Self::$log10_units_per_sec) }
|
||||||
|
}
|
||||||
|
)*
|
||||||
|
pub const fn to_parts(mut self) -> SimDurationParts {
|
||||||
|
$(
|
||||||
|
let $units = self.attos / const { 10u128.pow(Self::LOG10_ATTOS_PER_SEC - Self::$log10_units_per_sec) };
|
||||||
|
self.attos %= const { 10u128.pow(Self::LOG10_ATTOS_PER_SEC - Self::$log10_units_per_sec) };
|
||||||
|
)*
|
||||||
|
SimDurationParts {
|
||||||
|
$($units: $units as _,)*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub const fn from_parts_checked(parts: SimDurationParts) -> Option<Self> {
|
||||||
|
let attos = 0u128;
|
||||||
|
$(
|
||||||
|
let Some(product) = const { 10u128.pow(Self::LOG10_ATTOS_PER_SEC - Self::$log10_units_per_sec) }.checked_mul(parts.$units as u128) else {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
let Some(attos) = attos.checked_add(product) else {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
)*
|
||||||
|
Some(Self {
|
||||||
|
attos,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for SimDuration {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
let ilog10_attos = match self.attos.checked_ilog10() {
|
||||||
|
Some(v) => v,
|
||||||
|
None => Self::LOG10_ATTOS_PER_SEC,
|
||||||
|
};
|
||||||
|
let (suffix, int, fraction, fraction_digits) =
|
||||||
|
match Self::LOG10_ATTOS_PER_SEC.saturating_sub(ilog10_attos) {
|
||||||
|
$(
|
||||||
|
..=Self::$log10_units_per_sec => {
|
||||||
|
let divisor = const { 10u128.pow(Self::LOG10_ATTOS_PER_SEC - Self::$log10_units_per_sec) };
|
||||||
|
(
|
||||||
|
$suffix,
|
||||||
|
self.attos / divisor,
|
||||||
|
self.attos % divisor,
|
||||||
|
(Self::LOG10_ATTOS_PER_SEC - Self::$log10_units_per_sec) as usize,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
)*
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
write!(f, "{int}")?;
|
||||||
|
if fraction != 0 {
|
||||||
|
write!(f, ".{fraction:0fraction_digits$}")?;
|
||||||
|
}
|
||||||
|
write!(f, " {suffix}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
#[test]
|
||||||
|
fn test_duration_debug() {
|
||||||
|
$(
|
||||||
|
assert_eq!(
|
||||||
|
format!("{:?}", SimDuration::$from_units(123)),
|
||||||
|
concat!("123 ", $suffix)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
format!("{:?}", SimDuration::$from_units(1)),
|
||||||
|
concat!("1 ", $suffix),
|
||||||
|
);
|
||||||
|
let mut v = SimDuration::$from_units(1);
|
||||||
|
if v.attos < 1 << 53 {
|
||||||
|
v.attos += 1;
|
||||||
|
assert_eq!(
|
||||||
|
format!("{v:?}"),
|
||||||
|
format!("{} {}", v.attos as f64 / 10.0f64.powf((SimDuration::LOG10_ATTOS_PER_SEC - SimDuration::$log10_units_per_sec) as f64), $suffix),
|
||||||
|
"1 {} + 1 as == {} as", $suffix, v.attos,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
)*
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_duration_units! {
|
||||||
|
#[unit_const = SECOND, from_units = from_secs, as_units = as_secs, units = secs, suffix = "s"]
|
||||||
|
const LOG10_SECS_PER_SEC: u32 = 0;
|
||||||
|
#[unit_const = MILLISECOND, from_units = from_millis, as_units = as_millis, units = millis, suffix = "ms"]
|
||||||
|
const LOG10_MILLIS_PER_SEC: u32 = 3;
|
||||||
|
#[unit_const = MICROSECOND, from_units = from_micros, as_units = as_micros, units = micros, suffix = "μs"]
|
||||||
|
const LOG10_MICROS_PER_SEC: u32 = 6;
|
||||||
|
#[unit_const = NANOSECOND, from_units = from_nanos, as_units = as_nanos, units = nanos, suffix = "ns"]
|
||||||
|
const LOG10_NANOS_PER_SEC: u32 = 9;
|
||||||
|
#[unit_const = PICOSECOND, from_units = from_picos, as_units = as_picos, units = picos, suffix = "ps"]
|
||||||
|
const LOG10_PICOS_PER_SEC: u32 = 12;
|
||||||
|
#[unit_const = FEMTOSECOND, from_units = from_femtos, as_units = as_femtos, units = femtos, suffix = "fs"]
|
||||||
|
const LOG10_FEMTOS_PER_SEC: u32 = 15;
|
||||||
|
#[unit_const = ATTOSECOND, from_units = from_attos, as_units = as_attos, units = attos, suffix = "as"]
|
||||||
|
const LOG10_ATTOS_PER_SEC: u32 = 18;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SimDuration {
|
||||||
|
const fn from_units_helper<const UNITS_PER_SEC: u32>(units: u128) -> Self {
|
||||||
|
let Some(attos) =
|
||||||
|
units.checked_mul(const { 10u128.pow(Self::LOG10_ATTOS_PER_SEC - UNITS_PER_SEC) })
|
||||||
|
else {
|
||||||
|
panic!("duration too big");
|
||||||
|
};
|
||||||
|
Self { attos }
|
||||||
|
}
|
||||||
|
pub const ZERO: SimDuration = SimDuration::from_secs(0);
|
||||||
|
pub const fn from_parts(parts: SimDurationParts) -> Self {
|
||||||
|
match Self::from_parts_checked(parts) {
|
||||||
|
Some(v) => v,
|
||||||
|
None => panic!("duration too big"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub const fn abs_diff(self, other: Self) -> Self {
|
||||||
|
Self {
|
||||||
|
attos: self.attos.abs_diff(other.attos),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub const fn checked_add(self, rhs: Self) -> Option<Self> {
|
||||||
|
let Some(attos) = self.attos.checked_add(rhs.attos) else {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
Some(Self { attos })
|
||||||
|
}
|
||||||
|
pub const fn checked_sub(self, rhs: Self) -> Option<Self> {
|
||||||
|
let Some(attos) = self.attos.checked_sub(rhs.attos) else {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
Some(Self { attos })
|
||||||
|
}
|
||||||
|
pub const fn is_zero(self) -> bool {
|
||||||
|
self.attos == 0
|
||||||
|
}
|
||||||
|
pub const fn saturating_add(self, rhs: Self) -> Self {
|
||||||
|
Self {
|
||||||
|
attos: self.attos.saturating_add(rhs.attos),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub const fn saturating_sub(self, rhs: Self) -> Self {
|
||||||
|
Self {
|
||||||
|
attos: self.attos.saturating_sub(rhs.attos),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub const fn checked_ilog10(self) -> Option<i32> {
|
||||||
|
let Some(ilog10_attos) = self.attos.checked_ilog10() else {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
Some(ilog10_attos as i32 - Self::LOG10_ATTOS_PER_SEC as i32)
|
||||||
|
}
|
||||||
|
#[track_caller]
|
||||||
|
pub const fn ilog10(self) -> i32 {
|
||||||
|
let Some(retval) = self.checked_ilog10() else {
|
||||||
|
panic!("tried to take the ilog10 of 0");
|
||||||
|
};
|
||||||
|
retval
|
||||||
|
}
|
||||||
|
pub const fn checked_pow10(log10: i32, underflow_is_zero: bool) -> Option<Self> {
|
||||||
|
let Some(log10) = Self::LOG10_ATTOS_PER_SEC.checked_add_signed(log10) else {
|
||||||
|
return if log10 < 0 && underflow_is_zero {
|
||||||
|
Some(Self::ZERO)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
};
|
||||||
|
let Some(attos) = 10u128.checked_pow(log10) else {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
Some(Self { attos })
|
||||||
|
}
|
||||||
|
#[track_caller]
|
||||||
|
pub const fn pow10(log10: i32) -> Self {
|
||||||
|
let Some(retval) = Self::checked_pow10(log10, true) else {
|
||||||
|
panic!("pow10 overflowed");
|
||||||
|
};
|
||||||
|
retval
|
||||||
|
}
|
||||||
|
pub const fn is_power_of_ten(self) -> bool {
|
||||||
|
const TEN: u128 = 10;
|
||||||
|
const NUMBER_OF_POWERS_OF_TEN: usize = {
|
||||||
|
let mut n = 0;
|
||||||
|
while let Some(_) = TEN.checked_pow(n as u32) {
|
||||||
|
n += 1;
|
||||||
|
}
|
||||||
|
n
|
||||||
|
};
|
||||||
|
const POWERS_OF_TEN: [u128; NUMBER_OF_POWERS_OF_TEN] = {
|
||||||
|
let mut retval = [0; NUMBER_OF_POWERS_OF_TEN];
|
||||||
|
let mut i = 0;
|
||||||
|
while i < NUMBER_OF_POWERS_OF_TEN {
|
||||||
|
retval[i] = TEN.pow(i as u32);
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
retval
|
||||||
|
};
|
||||||
|
let mut i = 0;
|
||||||
|
while i < NUMBER_OF_POWERS_OF_TEN {
|
||||||
|
if self.attos == POWERS_OF_TEN[i] {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Duration> for SimDuration {
|
||||||
|
fn from(duration: Duration) -> Self {
|
||||||
|
Self::from_nanos(duration.as_nanos())
|
||||||
|
}
|
||||||
|
}
|
1124
crates/fayalite/src/sim/vcd.rs
Normal file
1124
crates/fayalite/src/sim/vcd.rs
Normal file
File diff suppressed because it is too large
Load diff
|
@ -24,7 +24,8 @@ pub use scoped_ref::ScopedRef;
|
||||||
|
|
||||||
#[doc(inline)]
|
#[doc(inline)]
|
||||||
pub use misc::{
|
pub use misc::{
|
||||||
interned_bit, iter_eq_by, BitSliceWriteWithBase, DebugAsDisplay, DebugAsRawString, MakeMutSlice,
|
get_many_mut, interned_bit, iter_eq_by, BitSliceWriteWithBase, DebugAsDisplay,
|
||||||
|
DebugAsRawString, MakeMutSlice, RcWriter,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub mod job_server;
|
pub mod job_server;
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
use crate::intern::{Intern, Interned};
|
use crate::intern::{Intern, Interned};
|
||||||
use bitvec::{bits, order::Lsb0, slice::BitSlice, view::BitView};
|
use bitvec::{bits, order::Lsb0, slice::BitSlice, view::BitView};
|
||||||
use std::{
|
use std::{
|
||||||
|
cell::Cell,
|
||||||
fmt::{self, Debug, Write},
|
fmt::{self, Debug, Write},
|
||||||
rc::Rc,
|
rc::Rc,
|
||||||
sync::{Arc, OnceLock},
|
sync::{Arc, OnceLock},
|
||||||
|
@ -94,9 +95,15 @@ pub fn interned_bit(v: bool) -> Interned<BitSlice> {
|
||||||
RETVAL.get_or_init(|| [bits![0; 1].intern(), bits![1; 1].intern()])[v as usize]
|
RETVAL.get_or_init(|| [bits![0; 1].intern(), bits![1; 1].intern()])[v as usize]
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone)]
|
||||||
pub struct BitSliceWriteWithBase<'a>(pub &'a BitSlice);
|
pub struct BitSliceWriteWithBase<'a>(pub &'a BitSlice);
|
||||||
|
|
||||||
|
impl<'a> Debug for BitSliceWriteWithBase<'a> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "{self:#x}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl BitSliceWriteWithBase<'_> {
|
impl BitSliceWriteWithBase<'_> {
|
||||||
fn fmt_with_base<const BITS_PER_DIGIT: usize, const UPPER_CASE: bool>(
|
fn fmt_with_base<const BITS_PER_DIGIT: usize, const UPPER_CASE: bool>(
|
||||||
self,
|
self,
|
||||||
|
@ -155,3 +162,66 @@ impl fmt::UpperHex for BitSliceWriteWithBase<'_> {
|
||||||
self.fmt_with_base::<4, true>(f)
|
self.fmt_with_base::<4, true>(f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
#[track_caller]
|
||||||
|
pub fn get_many_mut<T, const N: usize>(slice: &mut [T], indexes: [usize; N]) -> [&mut T; N] {
|
||||||
|
for i in 0..N {
|
||||||
|
for j in 0..i {
|
||||||
|
assert!(indexes[i] != indexes[j], "duplicate index");
|
||||||
|
}
|
||||||
|
assert!(indexes[i] < slice.len(), "index out of bounds");
|
||||||
|
}
|
||||||
|
// Safety: checked that no indexes are duplicates and no indexes are out of bounds
|
||||||
|
unsafe {
|
||||||
|
let base = slice.as_mut_ptr(); // convert to a raw pointer before loop to avoid aliasing with &mut [T]
|
||||||
|
std::array::from_fn(|i| &mut *base.add(indexes[i]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Default)]
|
||||||
|
pub struct RcWriter(Rc<Cell<Vec<u8>>>);
|
||||||
|
|
||||||
|
impl Debug for RcWriter {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
self.borrow_impl(|buf| {
|
||||||
|
f.debug_tuple("RcWriter")
|
||||||
|
.field(&DebugAsDisplay(format_args!("b\"{}\"", buf.escape_ascii())))
|
||||||
|
.finish()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RcWriter {
|
||||||
|
fn borrow_impl<R>(&self, f: impl FnOnce(&mut Vec<u8>) -> R) -> R {
|
||||||
|
let buf = Cell::take(&self.0);
|
||||||
|
struct PutBackOnDrop<'a> {
|
||||||
|
buf: Vec<u8>,
|
||||||
|
this: &'a RcWriter,
|
||||||
|
}
|
||||||
|
impl Drop for PutBackOnDrop<'_> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.this.0.set(std::mem::take(&mut self.buf));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let mut buf = PutBackOnDrop { buf, this: self };
|
||||||
|
f(&mut buf.buf)
|
||||||
|
}
|
||||||
|
pub fn borrow<R>(&mut self, f: impl FnOnce(&mut Vec<u8>) -> R) -> R {
|
||||||
|
self.borrow_impl(f)
|
||||||
|
}
|
||||||
|
pub fn take(&mut self) -> Vec<u8> {
|
||||||
|
Cell::take(&self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::io::Write for RcWriter {
|
||||||
|
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
|
||||||
|
self.borrow(|v| v.extend_from_slice(buf));
|
||||||
|
Ok(buf.len())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn flush(&mut self) -> std::io::Result<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -49,6 +49,18 @@ impl<T: Type> ReadyValid<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// This debug port is only meant to assist the formal proof of the queue.
|
||||||
|
#[cfg(test)]
|
||||||
|
#[doc(hidden)]
|
||||||
|
#[hdl]
|
||||||
|
pub struct QueueDebugPort<Element, Index> {
|
||||||
|
#[hdl(flip)]
|
||||||
|
index_to_check: Index,
|
||||||
|
stored: Element,
|
||||||
|
inp_index: Index,
|
||||||
|
out_index: Index,
|
||||||
|
}
|
||||||
|
|
||||||
#[hdl_module]
|
#[hdl_module]
|
||||||
pub fn queue<T: Type>(
|
pub fn queue<T: Type>(
|
||||||
ty: T,
|
ty: T,
|
||||||
|
@ -178,6 +190,22 @@ pub fn queue<T: Type>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// These debug ports expose some internal state during the Induction phase
|
||||||
|
// of Formal Verification. They are not present in normal use.
|
||||||
|
#[cfg(test)]
|
||||||
|
{
|
||||||
|
#[hdl]
|
||||||
|
let dbg: QueueDebugPort<T, UInt> = m.output(QueueDebugPort[ty][index_ty]);
|
||||||
|
// read the memory word currently stored at some fixed index
|
||||||
|
let debug_port = mem.new_read_port();
|
||||||
|
connect(debug_port.addr, dbg.index_to_check);
|
||||||
|
connect(debug_port.en, true);
|
||||||
|
connect(debug_port.clk, cd.clk);
|
||||||
|
connect(dbg.stored, debug_port.data);
|
||||||
|
// also expose the current read and write indices
|
||||||
|
connect(dbg.inp_index, inp_index_reg);
|
||||||
|
connect(dbg.out_index, out_index_reg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -196,13 +224,23 @@ mod tests {
|
||||||
format_args!("test_queue_{capacity}_{inp_ready_is_comb}_{out_valid_is_comb}"),
|
format_args!("test_queue_{capacity}_{inp_ready_is_comb}_{out_valid_is_comb}"),
|
||||||
queue_test(capacity, inp_ready_is_comb, out_valid_is_comb),
|
queue_test(capacity, inp_ready_is_comb, out_valid_is_comb),
|
||||||
FormalMode::Prove,
|
FormalMode::Prove,
|
||||||
14,
|
2,
|
||||||
None,
|
None,
|
||||||
ExportOptions {
|
ExportOptions {
|
||||||
simplify_enums: Some(SimplifyEnumsKind::ReplaceWithBundleOfUInts),
|
simplify_enums: Some(SimplifyEnumsKind::ReplaceWithBundleOfUInts),
|
||||||
..ExportOptions::default()
|
..ExportOptions::default()
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
/// Formal verification of the FIFO queue
|
||||||
|
///
|
||||||
|
/// The strategy derives from the observation that, if we filter its
|
||||||
|
/// input and output streams to consider just one in every N reads and
|
||||||
|
/// writes (where N is the FIFO capacity), then the FIFO effectively
|
||||||
|
/// behaves as a one-entry FIFO.
|
||||||
|
///
|
||||||
|
/// In particular, any counterexample of the full FIFO behaving badly
|
||||||
|
/// will also be caught by one of the filtered versions (one which
|
||||||
|
/// happens to be in phase with the offending input or output).
|
||||||
#[hdl_module]
|
#[hdl_module]
|
||||||
fn queue_test(capacity: NonZeroUsize, inp_ready_is_comb: bool, out_valid_is_comb: bool) {
|
fn queue_test(capacity: NonZeroUsize, inp_ready_is_comb: bool, out_valid_is_comb: bool) {
|
||||||
#[hdl]
|
#[hdl]
|
||||||
|
@ -217,6 +255,8 @@ mod tests {
|
||||||
rst: formal_reset().to_reset(),
|
rst: formal_reset().to_reset(),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// random input data
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let inp_data: HdlOption<UInt<8>> = wire();
|
let inp_data: HdlOption<UInt<8>> = wire();
|
||||||
#[hdl]
|
#[hdl]
|
||||||
|
@ -225,16 +265,26 @@ mod tests {
|
||||||
} else {
|
} else {
|
||||||
connect(inp_data, HdlNone());
|
connect(inp_data, HdlNone());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// assert output ready at random
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let out_ready: Bool = wire();
|
let out_ready: Bool = wire();
|
||||||
connect(out_ready, any_seq(Bool));
|
connect(out_ready, any_seq(Bool));
|
||||||
let index_ty: UInt<32> = UInt::TYPE;
|
|
||||||
|
// The current number of elements in the FIFO ranges from zero to
|
||||||
|
// maximum capacity, inclusive.
|
||||||
|
let count_ty = UInt::range_inclusive(0..=capacity.get());
|
||||||
|
// type for counters that wrap around at the FIFO capacity
|
||||||
|
let index_ty = UInt::range(0..capacity.get());
|
||||||
|
|
||||||
|
// among all entries of the FIFO internal circular memory, choose
|
||||||
|
// one at random to check
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let index_to_check = wire();
|
let index_to_check = wire(index_ty);
|
||||||
connect(index_to_check, any_const(index_ty));
|
connect(index_to_check, any_const(index_ty));
|
||||||
let index_max = !index_ty.zero();
|
hdl_assume(clk, index_to_check.cmp_lt(capacity.get()), "");
|
||||||
// we saturate at index_max, so only check indexes where we properly maintain position
|
|
||||||
hdl_assume(clk, index_to_check.cmp_ne(index_max), "");
|
// instantiate and connect the queue
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let dut = instance(queue(
|
let dut = instance(queue(
|
||||||
UInt[ConstUsize::<8>],
|
UInt[ConstUsize::<8>],
|
||||||
|
@ -245,109 +295,172 @@ mod tests {
|
||||||
connect(dut.cd, cd);
|
connect(dut.cd, cd);
|
||||||
connect(dut.inp.data, inp_data);
|
connect(dut.inp.data, inp_data);
|
||||||
connect(dut.out.ready, out_ready);
|
connect(dut.out.ready, out_ready);
|
||||||
hdl_assume(
|
|
||||||
clk,
|
|
||||||
index_to_check.cmp_ne(!Expr::ty(index_to_check).zero()),
|
|
||||||
"",
|
|
||||||
);
|
|
||||||
|
|
||||||
|
// Keep an independent count of words in the FIFO. Ensure that
|
||||||
|
// it's always correct, and never overflows.
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let expected_count_reg = reg_builder().clock_domain(cd).reset(0u32);
|
let expected_count_reg = reg_builder().clock_domain(cd).reset(count_ty.zero());
|
||||||
#[hdl]
|
|
||||||
let next_expected_count = wire();
|
|
||||||
connect(next_expected_count, expected_count_reg);
|
|
||||||
connect(expected_count_reg, next_expected_count);
|
|
||||||
#[hdl]
|
#[hdl]
|
||||||
if ReadyValid::firing(dut.inp) & !ReadyValid::firing(dut.out) {
|
if ReadyValid::firing(dut.inp) & !ReadyValid::firing(dut.out) {
|
||||||
connect_any(next_expected_count, expected_count_reg + 1u8);
|
hdl_assert(clk, expected_count_reg.cmp_ne(capacity.get()), "");
|
||||||
|
connect_any(expected_count_reg, expected_count_reg + 1u8);
|
||||||
} else if !ReadyValid::firing(dut.inp) & ReadyValid::firing(dut.out) {
|
} else if !ReadyValid::firing(dut.inp) & ReadyValid::firing(dut.out) {
|
||||||
connect_any(next_expected_count, expected_count_reg - 1u8);
|
hdl_assert(clk, expected_count_reg.cmp_ne(count_ty.zero()), "");
|
||||||
|
connect_any(expected_count_reg, expected_count_reg - 1u8);
|
||||||
}
|
}
|
||||||
hdl_assert(cd.clk, expected_count_reg.cmp_eq(dut.count), "");
|
hdl_assert(clk, expected_count_reg.cmp_eq(dut.count), "");
|
||||||
|
|
||||||
#[hdl]
|
|
||||||
let prev_out_ready_reg = reg_builder().clock_domain(cd).reset(!0_hdl_u3);
|
|
||||||
connect_any(
|
|
||||||
prev_out_ready_reg,
|
|
||||||
(prev_out_ready_reg << 1) | out_ready.cast_to(UInt[1]),
|
|
||||||
);
|
|
||||||
#[hdl]
|
|
||||||
let prev_inp_valid_reg = reg_builder().clock_domain(cd).reset(!0_hdl_u3);
|
|
||||||
connect_any(
|
|
||||||
prev_inp_valid_reg,
|
|
||||||
(prev_inp_valid_reg << 1) | HdlOption::is_some(inp_data).cast_to(UInt[1]),
|
|
||||||
);
|
|
||||||
hdl_assume(
|
|
||||||
clk,
|
|
||||||
(prev_out_ready_reg & prev_inp_valid_reg).cmp_ne(0u8),
|
|
||||||
"",
|
|
||||||
);
|
|
||||||
|
|
||||||
|
// keep an independent write index into the FIFO's circular buffer
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let inp_index_reg = reg_builder().clock_domain(cd).reset(index_ty.zero());
|
let inp_index_reg = reg_builder().clock_domain(cd).reset(index_ty.zero());
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let stored_inp_data_reg = reg_builder().clock_domain(cd).reset(0u8);
|
if ReadyValid::firing(dut.inp) {
|
||||||
|
|
||||||
#[hdl]
|
#[hdl]
|
||||||
if let HdlSome(data) = ReadyValid::firing_data(dut.inp) {
|
if inp_index_reg.cmp_ne(capacity.get() - 1) {
|
||||||
#[hdl]
|
|
||||||
if inp_index_reg.cmp_lt(index_max) {
|
|
||||||
connect_any(inp_index_reg, inp_index_reg + 1u8);
|
connect_any(inp_index_reg, inp_index_reg + 1u8);
|
||||||
#[hdl]
|
} else {
|
||||||
if inp_index_reg.cmp_eq(index_to_check) {
|
connect_any(inp_index_reg, 0_hdl_u0);
|
||||||
connect(stored_inp_data_reg, data);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[hdl]
|
// keep an independent read index into the FIFO's circular buffer
|
||||||
if inp_index_reg.cmp_lt(index_to_check) {
|
|
||||||
hdl_assert(clk, stored_inp_data_reg.cmp_eq(0u8), "");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let out_index_reg = reg_builder().clock_domain(cd).reset(index_ty.zero());
|
let out_index_reg = reg_builder().clock_domain(cd).reset(index_ty.zero());
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let stored_out_data_reg = reg_builder().clock_domain(cd).reset(0u8);
|
if ReadyValid::firing(dut.out) {
|
||||||
|
|
||||||
#[hdl]
|
#[hdl]
|
||||||
if let HdlSome(data) = ReadyValid::firing_data(dut.out) {
|
if out_index_reg.cmp_ne(capacity.get() - 1) {
|
||||||
#[hdl]
|
|
||||||
if out_index_reg.cmp_lt(index_max) {
|
|
||||||
connect_any(out_index_reg, out_index_reg + 1u8);
|
connect_any(out_index_reg, out_index_reg + 1u8);
|
||||||
#[hdl]
|
|
||||||
if out_index_reg.cmp_eq(index_to_check) {
|
|
||||||
connect(stored_out_data_reg, data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[hdl]
|
|
||||||
if out_index_reg.cmp_lt(index_to_check) {
|
|
||||||
hdl_assert(clk, stored_out_data_reg.cmp_eq(0u8), "");
|
|
||||||
}
|
|
||||||
|
|
||||||
hdl_assert(clk, inp_index_reg.cmp_ge(out_index_reg), "");
|
|
||||||
|
|
||||||
#[hdl]
|
|
||||||
if inp_index_reg.cmp_lt(index_max) & out_index_reg.cmp_lt(index_max) {
|
|
||||||
hdl_assert(
|
|
||||||
clk,
|
|
||||||
expected_count_reg.cmp_eq(inp_index_reg - out_index_reg),
|
|
||||||
"",
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
hdl_assert(
|
connect_any(out_index_reg, 0_hdl_u0);
|
||||||
clk,
|
}
|
||||||
expected_count_reg.cmp_ge(inp_index_reg - out_index_reg),
|
|
||||||
"",
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// filter the input data stream, predicated by the read index
|
||||||
|
// matching the chosen position in the FIFO's circular buffer
|
||||||
#[hdl]
|
#[hdl]
|
||||||
if inp_index_reg.cmp_gt(index_to_check) & out_index_reg.cmp_gt(index_to_check) {
|
let inp_index_matches = wire();
|
||||||
hdl_assert(clk, stored_inp_data_reg.cmp_eq(stored_out_data_reg), "");
|
connect(inp_index_matches, inp_index_reg.cmp_eq(index_to_check));
|
||||||
|
#[hdl]
|
||||||
|
let inp_firing_data = wire();
|
||||||
|
connect(inp_firing_data, HdlNone());
|
||||||
|
#[hdl]
|
||||||
|
if inp_index_matches {
|
||||||
|
connect(inp_firing_data, ReadyValid::firing_data(dut.inp));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// filter the output data stream, predicated by the write index
|
||||||
|
// matching the chosen position in the FIFO's circular buffer
|
||||||
|
#[hdl]
|
||||||
|
let out_index_matches = wire();
|
||||||
|
connect(out_index_matches, out_index_reg.cmp_eq(index_to_check));
|
||||||
|
#[hdl]
|
||||||
|
let out_firing_data = wire();
|
||||||
|
connect(out_firing_data, HdlNone());
|
||||||
|
#[hdl]
|
||||||
|
if out_index_matches {
|
||||||
|
connect(out_firing_data, ReadyValid::firing_data(dut.out));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implement a one-entry FIFO and ensure its equivalence to the
|
||||||
|
// filtered FIFO.
|
||||||
|
//
|
||||||
|
// the holding register for our one-entry FIFO
|
||||||
|
#[hdl]
|
||||||
|
let stored_reg = reg_builder().clock_domain(cd).reset(HdlNone());
|
||||||
|
#[hdl]
|
||||||
|
match stored_reg {
|
||||||
|
// If the holding register is empty...
|
||||||
|
HdlNone => {
|
||||||
|
#[hdl]
|
||||||
|
match inp_firing_data {
|
||||||
|
// ... and we are not receiving data, then we must not
|
||||||
|
// transmit any data.
|
||||||
|
HdlNone => hdl_assert(clk, HdlOption::is_none(out_firing_data), ""),
|
||||||
|
// If we are indeed receiving some data...
|
||||||
|
HdlSome(data_in) => {
|
||||||
|
#[hdl]
|
||||||
|
match out_firing_data {
|
||||||
|
// ... and transmitting at the same time, we
|
||||||
|
// must be transmitting the input data itself,
|
||||||
|
// since the holding register is empty.
|
||||||
|
HdlSome(data_out) => hdl_assert(clk, data_out.cmp_eq(data_in), ""),
|
||||||
|
// If we are receiving, but not transmitting,
|
||||||
|
// store the received data in the holding
|
||||||
|
// register.
|
||||||
|
HdlNone => connect(stored_reg, HdlSome(data_in)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If there is some value stored in the holding register...
|
||||||
|
HdlSome(stored) => {
|
||||||
|
#[hdl]
|
||||||
|
match out_firing_data {
|
||||||
|
// ... and we are not transmitting it, we cannot
|
||||||
|
// receive any more data.
|
||||||
|
HdlNone => hdl_assert(clk, HdlOption::is_none(inp_firing_data), ""),
|
||||||
|
// If we are transmitting a previously stored value...
|
||||||
|
HdlSome(data_out) => {
|
||||||
|
// ... it must be the same data we stored earlier.
|
||||||
|
hdl_assert(clk, data_out.cmp_eq(stored), "");
|
||||||
|
// Also, accept new data, if any. Otherwise,
|
||||||
|
// let the holding register become empty.
|
||||||
|
connect(stored_reg, inp_firing_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// from now on, some extra assertions in order to pass induction
|
||||||
|
|
||||||
|
// sync the holding register, when it's occupied, to the
|
||||||
|
// corresponding entry in the FIFO's circular buffer
|
||||||
|
connect(dut.dbg.index_to_check, index_to_check);
|
||||||
|
#[hdl]
|
||||||
|
if let HdlSome(stored) = stored_reg {
|
||||||
|
hdl_assert(clk, stored.cmp_eq(dut.dbg.stored), "");
|
||||||
|
}
|
||||||
|
|
||||||
|
// sync the read and write indices
|
||||||
|
hdl_assert(clk, inp_index_reg.cmp_eq(dut.dbg.inp_index), "");
|
||||||
|
hdl_assert(clk, out_index_reg.cmp_eq(dut.dbg.out_index), "");
|
||||||
|
|
||||||
|
// the indices should never go past the capacity, but induction
|
||||||
|
// doesn't know that...
|
||||||
|
hdl_assert(clk, inp_index_reg.cmp_lt(capacity.get()), "");
|
||||||
|
hdl_assert(clk, out_index_reg.cmp_lt(capacity.get()), "");
|
||||||
|
|
||||||
|
// strongly constrain the state of the holding register
|
||||||
|
//
|
||||||
|
// The holding register is full if and only if the corresponding
|
||||||
|
// FIFO entry was written to and not yet read. In other words, if
|
||||||
|
// the number of pending reads until the chosen entry is read out
|
||||||
|
// is greater than the current FIFO count, then the entry couldn't
|
||||||
|
// be in the FIFO in the first place.
|
||||||
|
#[hdl]
|
||||||
|
let pending_reads: UInt = wire(index_ty);
|
||||||
|
// take care of wrap-around when subtracting indices, add the
|
||||||
|
// capacity amount to keep the result positive if necessary
|
||||||
|
#[hdl]
|
||||||
|
if index_to_check.cmp_ge(out_index_reg) {
|
||||||
|
connect(pending_reads, index_to_check - out_index_reg);
|
||||||
|
} else {
|
||||||
|
connect(
|
||||||
|
pending_reads,
|
||||||
|
index_to_check + capacity.get() - out_index_reg,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// check whether the chosen entry is in the FIFO
|
||||||
|
#[hdl]
|
||||||
|
let expected_stored: Bool = wire();
|
||||||
|
connect(expected_stored, pending_reads.cmp_lt(dut.count));
|
||||||
|
// sync with the state of the holding register
|
||||||
|
hdl_assert(
|
||||||
|
clk,
|
||||||
|
expected_stored.cmp_eq(HdlOption::is_some(stored_reg)),
|
||||||
|
"",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -430,4 +543,24 @@ mod tests {
|
||||||
fn test_4_true_true() {
|
fn test_4_true_true() {
|
||||||
test_queue(NonZero::new(4).unwrap(), true, true);
|
test_queue(NonZero::new(4).unwrap(), true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_many_false_false() {
|
||||||
|
test_queue(NonZero::new((2 << 16) - 5).unwrap(), false, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_many_false_true() {
|
||||||
|
test_queue(NonZero::new((2 << 16) - 5).unwrap(), false, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_many_true_false() {
|
||||||
|
test_queue(NonZero::new((2 << 16) - 5).unwrap(), true, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_many_true_true() {
|
||||||
|
test_queue(NonZero::new((2 << 16) - 5).unwrap(), true, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,6 +37,18 @@ impl<T: Type> Wire<T> {
|
||||||
ty: ty.canonical(),
|
ty: ty.canonical(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pub fn from_canonical(v: Wire<CanonicalType>) -> Self {
|
||||||
|
let Wire {
|
||||||
|
name,
|
||||||
|
source_location,
|
||||||
|
ty,
|
||||||
|
} = v;
|
||||||
|
Self {
|
||||||
|
name,
|
||||||
|
source_location,
|
||||||
|
ty: T::from_canonical(ty),
|
||||||
|
}
|
||||||
|
}
|
||||||
pub fn ty(&self) -> T {
|
pub fn ty(&self) -> T {
|
||||||
self.ty
|
self.ty
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
// See Notices.txt for copyright information
|
// See Notices.txt for copyright information
|
||||||
use fayalite::{
|
use fayalite::{
|
||||||
assert_export_firrtl, firrtl::ExportOptions, intern::Intern,
|
assert_export_firrtl, firrtl::ExportOptions, intern::Intern,
|
||||||
module::transform::simplify_enums::SimplifyEnumsKind, prelude::*, ty::StaticType,
|
module::transform::simplify_enums::SimplifyEnumsKind, prelude::*, reset::ResetType,
|
||||||
|
ty::StaticType,
|
||||||
};
|
};
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
|
|
||||||
|
@ -190,10 +191,14 @@ circuit check_array_repeat:
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait UnknownTrait {}
|
||||||
|
|
||||||
|
impl<T: ?Sized> UnknownTrait for T {}
|
||||||
|
|
||||||
#[hdl_module(outline_generated)]
|
#[hdl_module(outline_generated)]
|
||||||
pub fn check_skipped_generics<T, #[hdl(skip)] U, const N: usize, #[hdl(skip)] const M: usize>(v: U)
|
pub fn check_skipped_generics<T, #[hdl(skip)] U, const N: usize, #[hdl(skip)] const M: usize>(v: U)
|
||||||
where
|
where
|
||||||
T: StaticType,
|
T: StaticType + UnknownTrait,
|
||||||
ConstUsize<N>: KnownSize,
|
ConstUsize<N>: KnownSize,
|
||||||
U: std::fmt::Display,
|
U: std::fmt::Display,
|
||||||
{
|
{
|
||||||
|
@ -375,18 +380,18 @@ circuit check_written_inside_both_if_else:
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[hdl(outline_generated)]
|
#[hdl(outline_generated, cmp_eq)]
|
||||||
pub struct TestStruct<T> {
|
pub struct TestStruct<T> {
|
||||||
pub a: T,
|
pub a: T,
|
||||||
pub b: UInt<8>,
|
pub b: UInt<8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[hdl(outline_generated)]
|
#[hdl(outline_generated, cmp_eq)]
|
||||||
pub struct TestStruct2 {
|
pub struct TestStruct2 {
|
||||||
pub v: UInt<8>,
|
pub v: UInt<8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[hdl(outline_generated)]
|
#[hdl(outline_generated, cmp_eq)]
|
||||||
pub struct TestStruct3 {}
|
pub struct TestStruct3 {}
|
||||||
|
|
||||||
#[hdl_module(outline_generated)]
|
#[hdl_module(outline_generated)]
|
||||||
|
@ -4026,3 +4031,519 @@ circuit check_enum_connect_any:
|
||||||
",
|
",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[hdl_module(outline_generated)]
|
||||||
|
pub fn check_deduce_resets<T: ResetType>(ty: T) {
|
||||||
|
#[hdl]
|
||||||
|
let cd: ClockDomain<T> = m.input(ClockDomain[ty]);
|
||||||
|
#[hdl]
|
||||||
|
let my_reg = reg_builder().reset(0u8).clock_domain(cd);
|
||||||
|
#[hdl]
|
||||||
|
let u8_in: UInt<8> = m.input();
|
||||||
|
connect(my_reg, u8_in);
|
||||||
|
#[hdl]
|
||||||
|
let u8_out: UInt<8> = m.output();
|
||||||
|
connect(u8_out, my_reg);
|
||||||
|
#[hdl]
|
||||||
|
let enum_in: OneOfThree<Reset, AsyncReset, SyncReset> = m.input();
|
||||||
|
#[hdl]
|
||||||
|
let enum_out: OneOfThree<Reset, AsyncReset, SyncReset> = m.output();
|
||||||
|
#[hdl]
|
||||||
|
let reset_out: Reset = m.output();
|
||||||
|
connect(reset_out, cd.rst.to_reset());
|
||||||
|
#[hdl]
|
||||||
|
match enum_in {
|
||||||
|
OneOfThree::<_, _, _>::A(v) => {
|
||||||
|
connect(
|
||||||
|
enum_out,
|
||||||
|
OneOfThree[Reset][AsyncReset][SyncReset].A(cd.rst.to_reset()),
|
||||||
|
);
|
||||||
|
connect(reset_out, v);
|
||||||
|
}
|
||||||
|
OneOfThree::<_, _, _>::B(v) => {
|
||||||
|
connect(enum_out, OneOfThree[Reset][AsyncReset][SyncReset].B(v))
|
||||||
|
}
|
||||||
|
OneOfThree::<_, _, _>::C(v) => {
|
||||||
|
connect(enum_out, OneOfThree[Reset][AsyncReset][SyncReset].C(v))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_deduce_resets() {
|
||||||
|
let _n = SourceLocation::normalize_files_for_tests();
|
||||||
|
let m = check_deduce_resets(Reset);
|
||||||
|
dbg!(m);
|
||||||
|
#[rustfmt::skip] // work around https://github.com/rust-lang/rustfmt/issues/6161
|
||||||
|
assert_export_firrtl! {
|
||||||
|
m =>
|
||||||
|
options: ExportOptions {
|
||||||
|
simplify_enums: None,
|
||||||
|
..ExportOptions::default()
|
||||||
|
},
|
||||||
|
"/test/check_deduce_resets.fir": r"FIRRTL version 3.2.0
|
||||||
|
circuit check_deduce_resets:
|
||||||
|
type Ty0 = {clk: Clock, rst: Reset}
|
||||||
|
type Ty1 = {|A: Reset, B: AsyncReset, C: UInt<1>|}
|
||||||
|
module check_deduce_resets: @[module-XXXXXXXXXX.rs 1:1]
|
||||||
|
input cd: Ty0 @[module-XXXXXXXXXX.rs 2:1]
|
||||||
|
input u8_in: UInt<8> @[module-XXXXXXXXXX.rs 4:1]
|
||||||
|
output u8_out: UInt<8> @[module-XXXXXXXXXX.rs 6:1]
|
||||||
|
input enum_in: Ty1 @[module-XXXXXXXXXX.rs 8:1]
|
||||||
|
output enum_out: Ty1 @[module-XXXXXXXXXX.rs 9:1]
|
||||||
|
output reset_out: Reset @[module-XXXXXXXXXX.rs 10:1]
|
||||||
|
regreset my_reg: UInt<8>, cd.clk, cd.rst, UInt<8>(0h0) @[module-XXXXXXXXXX.rs 3:1]
|
||||||
|
connect my_reg, u8_in @[module-XXXXXXXXXX.rs 5:1]
|
||||||
|
connect u8_out, my_reg @[module-XXXXXXXXXX.rs 7:1]
|
||||||
|
connect reset_out, cd.rst @[module-XXXXXXXXXX.rs 11:1]
|
||||||
|
match enum_in: @[module-XXXXXXXXXX.rs 12:1]
|
||||||
|
A(_match_arm_value):
|
||||||
|
connect enum_out, {|A: Reset, B: AsyncReset, C: UInt<1>|}(A, cd.rst) @[module-XXXXXXXXXX.rs 13:1]
|
||||||
|
connect reset_out, _match_arm_value @[module-XXXXXXXXXX.rs 14:1]
|
||||||
|
B(_match_arm_value_1):
|
||||||
|
connect enum_out, {|A: Reset, B: AsyncReset, C: UInt<1>|}(B, _match_arm_value_1) @[module-XXXXXXXXXX.rs 15:1]
|
||||||
|
C(_match_arm_value_2):
|
||||||
|
connect enum_out, {|A: Reset, B: AsyncReset, C: UInt<1>|}(C, _match_arm_value_2) @[module-XXXXXXXXXX.rs 16:1]
|
||||||
|
",
|
||||||
|
};
|
||||||
|
fayalite::module::transform::deduce_resets::deduce_resets(m.canonical().intern_sized(), false)
|
||||||
|
.unwrap_err();
|
||||||
|
let m = fayalite::module::transform::deduce_resets::deduce_resets(
|
||||||
|
m.canonical().intern_sized(),
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
dbg!(m);
|
||||||
|
#[rustfmt::skip] // work around https://github.com/rust-lang/rustfmt/issues/6161
|
||||||
|
assert_export_firrtl! {
|
||||||
|
m =>
|
||||||
|
options: ExportOptions {
|
||||||
|
simplify_enums: None,
|
||||||
|
..ExportOptions::default()
|
||||||
|
},
|
||||||
|
"/test/check_deduce_resets.fir": r"FIRRTL version 3.2.0
|
||||||
|
circuit check_deduce_resets:
|
||||||
|
type Ty0 = {clk: Clock, rst: UInt<1>}
|
||||||
|
type Ty1 = {|A: UInt<1>, B: AsyncReset, C: UInt<1>|}
|
||||||
|
module check_deduce_resets: @[module-XXXXXXXXXX.rs 1:1]
|
||||||
|
input cd: Ty0 @[module-XXXXXXXXXX.rs 2:1]
|
||||||
|
input u8_in: UInt<8> @[module-XXXXXXXXXX.rs 4:1]
|
||||||
|
output u8_out: UInt<8> @[module-XXXXXXXXXX.rs 6:1]
|
||||||
|
input enum_in: Ty1 @[module-XXXXXXXXXX.rs 8:1]
|
||||||
|
output enum_out: Ty1 @[module-XXXXXXXXXX.rs 9:1]
|
||||||
|
output reset_out: UInt<1> @[module-XXXXXXXXXX.rs 10:1]
|
||||||
|
regreset my_reg: UInt<8>, cd.clk, cd.rst, UInt<8>(0h0) @[module-XXXXXXXXXX.rs 3:1]
|
||||||
|
connect my_reg, u8_in @[module-XXXXXXXXXX.rs 5:1]
|
||||||
|
connect u8_out, my_reg @[module-XXXXXXXXXX.rs 7:1]
|
||||||
|
connect reset_out, cd.rst @[module-XXXXXXXXXX.rs 11:1]
|
||||||
|
match enum_in: @[module-XXXXXXXXXX.rs 12:1]
|
||||||
|
A(_match_arm_value):
|
||||||
|
connect enum_out, {|A: UInt<1>, B: AsyncReset, C: UInt<1>|}(A, cd.rst) @[module-XXXXXXXXXX.rs 13:1]
|
||||||
|
connect reset_out, _match_arm_value @[module-XXXXXXXXXX.rs 14:1]
|
||||||
|
B(_match_arm_value_1):
|
||||||
|
connect enum_out, {|A: UInt<1>, B: AsyncReset, C: UInt<1>|}(B, _match_arm_value_1) @[module-XXXXXXXXXX.rs 15:1]
|
||||||
|
C(_match_arm_value_2):
|
||||||
|
connect enum_out, {|A: UInt<1>, B: AsyncReset, C: UInt<1>|}(C, _match_arm_value_2) @[module-XXXXXXXXXX.rs 16:1]
|
||||||
|
",
|
||||||
|
};
|
||||||
|
let m = check_deduce_resets(SyncReset);
|
||||||
|
dbg!(m);
|
||||||
|
#[rustfmt::skip] // work around https://github.com/rust-lang/rustfmt/issues/6161
|
||||||
|
assert_export_firrtl! {
|
||||||
|
m =>
|
||||||
|
options: ExportOptions {
|
||||||
|
simplify_enums: None,
|
||||||
|
..ExportOptions::default()
|
||||||
|
},
|
||||||
|
"/test/check_deduce_resets.fir": r"FIRRTL version 3.2.0
|
||||||
|
circuit check_deduce_resets:
|
||||||
|
type Ty0 = {clk: Clock, rst: UInt<1>}
|
||||||
|
type Ty1 = {|A: Reset, B: AsyncReset, C: UInt<1>|}
|
||||||
|
module check_deduce_resets: @[module-XXXXXXXXXX.rs 1:1]
|
||||||
|
input cd: Ty0 @[module-XXXXXXXXXX.rs 2:1]
|
||||||
|
input u8_in: UInt<8> @[module-XXXXXXXXXX.rs 4:1]
|
||||||
|
output u8_out: UInt<8> @[module-XXXXXXXXXX.rs 6:1]
|
||||||
|
input enum_in: Ty1 @[module-XXXXXXXXXX.rs 8:1]
|
||||||
|
output enum_out: Ty1 @[module-XXXXXXXXXX.rs 9:1]
|
||||||
|
output reset_out: Reset @[module-XXXXXXXXXX.rs 10:1]
|
||||||
|
regreset my_reg: UInt<8>, cd.clk, cd.rst, UInt<8>(0h0) @[module-XXXXXXXXXX.rs 3:1]
|
||||||
|
connect my_reg, u8_in @[module-XXXXXXXXXX.rs 5:1]
|
||||||
|
connect u8_out, my_reg @[module-XXXXXXXXXX.rs 7:1]
|
||||||
|
connect reset_out, cd.rst @[module-XXXXXXXXXX.rs 11:1]
|
||||||
|
match enum_in: @[module-XXXXXXXXXX.rs 12:1]
|
||||||
|
A(_match_arm_value):
|
||||||
|
connect enum_out, {|A: Reset, B: AsyncReset, C: UInt<1>|}(A, cd.rst) @[module-XXXXXXXXXX.rs 13:1]
|
||||||
|
connect reset_out, _match_arm_value @[module-XXXXXXXXXX.rs 14:1]
|
||||||
|
B(_match_arm_value_1):
|
||||||
|
connect enum_out, {|A: Reset, B: AsyncReset, C: UInt<1>|}(B, _match_arm_value_1) @[module-XXXXXXXXXX.rs 15:1]
|
||||||
|
C(_match_arm_value_2):
|
||||||
|
connect enum_out, {|A: Reset, B: AsyncReset, C: UInt<1>|}(C, _match_arm_value_2) @[module-XXXXXXXXXX.rs 16:1]
|
||||||
|
",
|
||||||
|
};
|
||||||
|
let m = fayalite::module::transform::deduce_resets::deduce_resets(
|
||||||
|
m.canonical().intern_sized(),
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
dbg!(m);
|
||||||
|
#[rustfmt::skip] // work around https://github.com/rust-lang/rustfmt/issues/6161
|
||||||
|
assert_export_firrtl! {
|
||||||
|
m =>
|
||||||
|
options: ExportOptions {
|
||||||
|
simplify_enums: None,
|
||||||
|
..ExportOptions::default()
|
||||||
|
},
|
||||||
|
"/test/check_deduce_resets.fir": r"FIRRTL version 3.2.0
|
||||||
|
circuit check_deduce_resets:
|
||||||
|
type Ty0 = {clk: Clock, rst: UInt<1>}
|
||||||
|
type Ty1 = {|A: UInt<1>, B: AsyncReset, C: UInt<1>|}
|
||||||
|
module check_deduce_resets: @[module-XXXXXXXXXX.rs 1:1]
|
||||||
|
input cd: Ty0 @[module-XXXXXXXXXX.rs 2:1]
|
||||||
|
input u8_in: UInt<8> @[module-XXXXXXXXXX.rs 4:1]
|
||||||
|
output u8_out: UInt<8> @[module-XXXXXXXXXX.rs 6:1]
|
||||||
|
input enum_in: Ty1 @[module-XXXXXXXXXX.rs 8:1]
|
||||||
|
output enum_out: Ty1 @[module-XXXXXXXXXX.rs 9:1]
|
||||||
|
output reset_out: UInt<1> @[module-XXXXXXXXXX.rs 10:1]
|
||||||
|
regreset my_reg: UInt<8>, cd.clk, cd.rst, UInt<8>(0h0) @[module-XXXXXXXXXX.rs 3:1]
|
||||||
|
connect my_reg, u8_in @[module-XXXXXXXXXX.rs 5:1]
|
||||||
|
connect u8_out, my_reg @[module-XXXXXXXXXX.rs 7:1]
|
||||||
|
connect reset_out, cd.rst @[module-XXXXXXXXXX.rs 11:1]
|
||||||
|
match enum_in: @[module-XXXXXXXXXX.rs 12:1]
|
||||||
|
A(_match_arm_value):
|
||||||
|
connect enum_out, {|A: UInt<1>, B: AsyncReset, C: UInt<1>|}(A, cd.rst) @[module-XXXXXXXXXX.rs 13:1]
|
||||||
|
connect reset_out, _match_arm_value @[module-XXXXXXXXXX.rs 14:1]
|
||||||
|
B(_match_arm_value_1):
|
||||||
|
connect enum_out, {|A: UInt<1>, B: AsyncReset, C: UInt<1>|}(B, _match_arm_value_1) @[module-XXXXXXXXXX.rs 15:1]
|
||||||
|
C(_match_arm_value_2):
|
||||||
|
connect enum_out, {|A: UInt<1>, B: AsyncReset, C: UInt<1>|}(C, _match_arm_value_2) @[module-XXXXXXXXXX.rs 16:1]
|
||||||
|
",
|
||||||
|
};
|
||||||
|
let m = check_deduce_resets(AsyncReset);
|
||||||
|
dbg!(m);
|
||||||
|
#[rustfmt::skip] // work around https://github.com/rust-lang/rustfmt/issues/6161
|
||||||
|
assert_export_firrtl! {
|
||||||
|
m =>
|
||||||
|
options: ExportOptions {
|
||||||
|
simplify_enums: None,
|
||||||
|
..ExportOptions::default()
|
||||||
|
},
|
||||||
|
"/test/check_deduce_resets.fir": r"FIRRTL version 3.2.0
|
||||||
|
circuit check_deduce_resets:
|
||||||
|
type Ty0 = {clk: Clock, rst: AsyncReset}
|
||||||
|
type Ty1 = {|A: Reset, B: AsyncReset, C: UInt<1>|}
|
||||||
|
module check_deduce_resets: @[module-XXXXXXXXXX.rs 1:1]
|
||||||
|
input cd: Ty0 @[module-XXXXXXXXXX.rs 2:1]
|
||||||
|
input u8_in: UInt<8> @[module-XXXXXXXXXX.rs 4:1]
|
||||||
|
output u8_out: UInt<8> @[module-XXXXXXXXXX.rs 6:1]
|
||||||
|
input enum_in: Ty1 @[module-XXXXXXXXXX.rs 8:1]
|
||||||
|
output enum_out: Ty1 @[module-XXXXXXXXXX.rs 9:1]
|
||||||
|
output reset_out: Reset @[module-XXXXXXXXXX.rs 10:1]
|
||||||
|
regreset my_reg: UInt<8>, cd.clk, cd.rst, UInt<8>(0h0) @[module-XXXXXXXXXX.rs 3:1]
|
||||||
|
connect my_reg, u8_in @[module-XXXXXXXXXX.rs 5:1]
|
||||||
|
connect u8_out, my_reg @[module-XXXXXXXXXX.rs 7:1]
|
||||||
|
connect reset_out, cd.rst @[module-XXXXXXXXXX.rs 11:1]
|
||||||
|
match enum_in: @[module-XXXXXXXXXX.rs 12:1]
|
||||||
|
A(_match_arm_value):
|
||||||
|
connect enum_out, {|A: Reset, B: AsyncReset, C: UInt<1>|}(A, cd.rst) @[module-XXXXXXXXXX.rs 13:1]
|
||||||
|
connect reset_out, _match_arm_value @[module-XXXXXXXXXX.rs 14:1]
|
||||||
|
B(_match_arm_value_1):
|
||||||
|
connect enum_out, {|A: Reset, B: AsyncReset, C: UInt<1>|}(B, _match_arm_value_1) @[module-XXXXXXXXXX.rs 15:1]
|
||||||
|
C(_match_arm_value_2):
|
||||||
|
connect enum_out, {|A: Reset, B: AsyncReset, C: UInt<1>|}(C, _match_arm_value_2) @[module-XXXXXXXXXX.rs 16:1]
|
||||||
|
",
|
||||||
|
};
|
||||||
|
let m = fayalite::module::transform::deduce_resets::deduce_resets(
|
||||||
|
m.canonical().intern_sized(),
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
dbg!(m);
|
||||||
|
#[rustfmt::skip] // work around https://github.com/rust-lang/rustfmt/issues/6161
|
||||||
|
assert_export_firrtl! {
|
||||||
|
m =>
|
||||||
|
options: ExportOptions {
|
||||||
|
simplify_enums: None,
|
||||||
|
..ExportOptions::default()
|
||||||
|
},
|
||||||
|
"/test/check_deduce_resets.fir": r"FIRRTL version 3.2.0
|
||||||
|
circuit check_deduce_resets:
|
||||||
|
type Ty0 = {clk: Clock, rst: AsyncReset}
|
||||||
|
type Ty1 = {|A: AsyncReset, B: AsyncReset, C: UInt<1>|}
|
||||||
|
module check_deduce_resets: @[module-XXXXXXXXXX.rs 1:1]
|
||||||
|
input cd: Ty0 @[module-XXXXXXXXXX.rs 2:1]
|
||||||
|
input u8_in: UInt<8> @[module-XXXXXXXXXX.rs 4:1]
|
||||||
|
output u8_out: UInt<8> @[module-XXXXXXXXXX.rs 6:1]
|
||||||
|
input enum_in: Ty1 @[module-XXXXXXXXXX.rs 8:1]
|
||||||
|
output enum_out: Ty1 @[module-XXXXXXXXXX.rs 9:1]
|
||||||
|
output reset_out: AsyncReset @[module-XXXXXXXXXX.rs 10:1]
|
||||||
|
regreset my_reg: UInt<8>, cd.clk, cd.rst, UInt<8>(0h0) @[module-XXXXXXXXXX.rs 3:1]
|
||||||
|
connect my_reg, u8_in @[module-XXXXXXXXXX.rs 5:1]
|
||||||
|
connect u8_out, my_reg @[module-XXXXXXXXXX.rs 7:1]
|
||||||
|
connect reset_out, cd.rst @[module-XXXXXXXXXX.rs 11:1]
|
||||||
|
match enum_in: @[module-XXXXXXXXXX.rs 12:1]
|
||||||
|
A(_match_arm_value):
|
||||||
|
connect enum_out, {|A: AsyncReset, B: AsyncReset, C: UInt<1>|}(A, cd.rst) @[module-XXXXXXXXXX.rs 13:1]
|
||||||
|
connect reset_out, _match_arm_value @[module-XXXXXXXXXX.rs 14:1]
|
||||||
|
B(_match_arm_value_1):
|
||||||
|
connect enum_out, {|A: AsyncReset, B: AsyncReset, C: UInt<1>|}(B, _match_arm_value_1) @[module-XXXXXXXXXX.rs 15:1]
|
||||||
|
C(_match_arm_value_2):
|
||||||
|
connect enum_out, {|A: AsyncReset, B: AsyncReset, C: UInt<1>|}(C, _match_arm_value_2) @[module-XXXXXXXXXX.rs 16:1]
|
||||||
|
",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// intentionally not outline_generated to ensure we get correct macro hygiene
|
||||||
|
#[hdl_module]
|
||||||
|
pub fn check_cfgs<#[cfg(cfg_false_for_tests)] A: Type, #[cfg(cfg_true_for_tests)] B: Type>(
|
||||||
|
#[cfg(cfg_false_for_tests)] a: A,
|
||||||
|
#[cfg(cfg_true_for_tests)] b: B,
|
||||||
|
) {
|
||||||
|
#[hdl]
|
||||||
|
struct S<#[cfg(cfg_false_for_tests)] A, #[cfg(cfg_true_for_tests)] B> {
|
||||||
|
#[cfg(cfg_false_for_tests)]
|
||||||
|
a: A,
|
||||||
|
#[cfg(cfg_true_for_tests)]
|
||||||
|
b: B,
|
||||||
|
}
|
||||||
|
#[hdl]
|
||||||
|
#[cfg(cfg_false_for_tests)]
|
||||||
|
let i_a: A = m.input(a);
|
||||||
|
#[hdl]
|
||||||
|
#[cfg(cfg_true_for_tests)]
|
||||||
|
let i_b: B = m.input(b);
|
||||||
|
#[hdl]
|
||||||
|
let w: S<UInt<8>> = wire();
|
||||||
|
#[cfg(cfg_false_for_tests)]
|
||||||
|
{
|
||||||
|
#[hdl]
|
||||||
|
let o_a: A = m.output(a);
|
||||||
|
connect(o_a, w.a.cast_bits_to(a));
|
||||||
|
connect_any(w.a, i_a.cast_to_bits());
|
||||||
|
}
|
||||||
|
#[cfg(cfg_true_for_tests)]
|
||||||
|
{
|
||||||
|
#[hdl]
|
||||||
|
let o_b: B = m.output(b);
|
||||||
|
connect(o_b, w.b.cast_bits_to(b));
|
||||||
|
connect_any(w.b, i_b.cast_to_bits());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_cfgs() {
|
||||||
|
let _n = SourceLocation::normalize_files_for_tests();
|
||||||
|
let m = check_cfgs(UInt[8]);
|
||||||
|
dbg!(m);
|
||||||
|
#[rustfmt::skip] // work around https://github.com/rust-lang/rustfmt/issues/6161
|
||||||
|
assert_export_firrtl! {
|
||||||
|
m =>
|
||||||
|
"/test/check_cfgs.fir": r"FIRRTL version 3.2.0
|
||||||
|
circuit check_cfgs:
|
||||||
|
type Ty0 = {b: UInt<8>}
|
||||||
|
module check_cfgs: @[the_test_file.rs 9962:1]
|
||||||
|
input i_b: UInt<8> @[the_test_file.rs 9979:20]
|
||||||
|
output o_b: UInt<8> @[the_test_file.rs 9992:24]
|
||||||
|
wire w: Ty0 @[the_test_file.rs 9981:25]
|
||||||
|
connect o_b, w.b @[the_test_file.rs 9993:9]
|
||||||
|
connect w.b, i_b @[the_test_file.rs 9994:9]
|
||||||
|
",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[hdl_module(outline_generated)]
|
||||||
|
pub fn check_let_patterns() {
|
||||||
|
#[hdl]
|
||||||
|
let tuple_in: (UInt<1>, SInt<1>, Bool) = m.input();
|
||||||
|
#[hdl]
|
||||||
|
let (tuple_0, tuple_1, tuple_2) = tuple_in;
|
||||||
|
#[hdl]
|
||||||
|
let tuple_0_out: UInt<1> = m.output();
|
||||||
|
connect(tuple_0_out, tuple_0);
|
||||||
|
#[hdl]
|
||||||
|
let tuple_1_out: SInt<1> = m.output();
|
||||||
|
connect(tuple_1_out, tuple_1);
|
||||||
|
#[hdl]
|
||||||
|
let tuple_2_out: Bool = m.output();
|
||||||
|
connect(tuple_2_out, tuple_2);
|
||||||
|
|
||||||
|
#[hdl]
|
||||||
|
let test_struct_in: TestStruct<SInt<8>> = m.input();
|
||||||
|
#[hdl]
|
||||||
|
let TestStruct::<_> { a, b } = test_struct_in;
|
||||||
|
#[hdl]
|
||||||
|
let test_struct_a_out: SInt<8> = m.output();
|
||||||
|
connect(test_struct_a_out, a);
|
||||||
|
#[hdl]
|
||||||
|
let test_struct_b_out: UInt<8> = m.output();
|
||||||
|
connect(test_struct_b_out, b);
|
||||||
|
|
||||||
|
#[hdl]
|
||||||
|
let test_struct_2_in: TestStruct2 = m.input();
|
||||||
|
#[hdl]
|
||||||
|
let TestStruct2 { v } = test_struct_2_in;
|
||||||
|
#[hdl]
|
||||||
|
let test_struct_2_v_out: UInt<8> = m.output();
|
||||||
|
connect(test_struct_2_v_out, v);
|
||||||
|
|
||||||
|
#[hdl]
|
||||||
|
let test_struct_3_in: TestStruct3 = m.input();
|
||||||
|
#[hdl]
|
||||||
|
let TestStruct3 {} = test_struct_3_in;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_let_patterns() {
|
||||||
|
let _n = SourceLocation::normalize_files_for_tests();
|
||||||
|
let m = check_let_patterns();
|
||||||
|
dbg!(m);
|
||||||
|
#[rustfmt::skip] // work around https://github.com/rust-lang/rustfmt/issues/6161
|
||||||
|
assert_export_firrtl! {
|
||||||
|
m =>
|
||||||
|
"/test/check_let_patterns.fir": r"FIRRTL version 3.2.0
|
||||||
|
circuit check_let_patterns:
|
||||||
|
type Ty0 = {`0`: UInt<1>, `1`: SInt<1>, `2`: UInt<1>}
|
||||||
|
type Ty1 = {a: SInt<8>, b: UInt<8>}
|
||||||
|
type Ty2 = {v: UInt<8>}
|
||||||
|
type Ty3 = {}
|
||||||
|
module check_let_patterns: @[module-XXXXXXXXXX.rs 1:1]
|
||||||
|
input tuple_in: Ty0 @[module-XXXXXXXXXX.rs 2:1]
|
||||||
|
output tuple_0_out: UInt<1> @[module-XXXXXXXXXX.rs 4:1]
|
||||||
|
output tuple_1_out: SInt<1> @[module-XXXXXXXXXX.rs 6:1]
|
||||||
|
output tuple_2_out: UInt<1> @[module-XXXXXXXXXX.rs 8:1]
|
||||||
|
input test_struct_in: Ty1 @[module-XXXXXXXXXX.rs 10:1]
|
||||||
|
output test_struct_a_out: SInt<8> @[module-XXXXXXXXXX.rs 12:1]
|
||||||
|
output test_struct_b_out: UInt<8> @[module-XXXXXXXXXX.rs 14:1]
|
||||||
|
input test_struct_2_in: Ty2 @[module-XXXXXXXXXX.rs 16:1]
|
||||||
|
output test_struct_2_v_out: UInt<8> @[module-XXXXXXXXXX.rs 18:1]
|
||||||
|
input test_struct_3_in: Ty3 @[module-XXXXXXXXXX.rs 20:1]
|
||||||
|
connect tuple_0_out, tuple_in.`0` @[module-XXXXXXXXXX.rs 5:1]
|
||||||
|
connect tuple_1_out, tuple_in.`1` @[module-XXXXXXXXXX.rs 7:1]
|
||||||
|
connect tuple_2_out, tuple_in.`2` @[module-XXXXXXXXXX.rs 9:1]
|
||||||
|
connect test_struct_a_out, test_struct_in.a @[module-XXXXXXXXXX.rs 13:1]
|
||||||
|
connect test_struct_b_out, test_struct_in.b @[module-XXXXXXXXXX.rs 15:1]
|
||||||
|
connect test_struct_2_v_out, test_struct_2_in.v @[module-XXXXXXXXXX.rs 19:1]
|
||||||
|
",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[hdl_module(outline_generated)]
|
||||||
|
pub fn check_struct_cmp_eq() {
|
||||||
|
#[hdl]
|
||||||
|
let tuple_lhs: (UInt<1>, SInt<1>, Bool) = m.input();
|
||||||
|
#[hdl]
|
||||||
|
let tuple_rhs: (UInt<1>, SInt<1>, Bool) = m.input();
|
||||||
|
#[hdl]
|
||||||
|
let tuple_cmp_eq: Bool = m.output();
|
||||||
|
connect(tuple_cmp_eq, tuple_lhs.cmp_eq(tuple_rhs));
|
||||||
|
#[hdl]
|
||||||
|
let tuple_cmp_ne: Bool = m.output();
|
||||||
|
connect(tuple_cmp_ne, tuple_lhs.cmp_ne(tuple_rhs));
|
||||||
|
|
||||||
|
#[hdl]
|
||||||
|
let test_struct_lhs: TestStruct<SInt<8>> = m.input();
|
||||||
|
#[hdl]
|
||||||
|
let test_struct_rhs: TestStruct<SInt<8>> = m.input();
|
||||||
|
#[hdl]
|
||||||
|
let test_struct_cmp_eq: Bool = m.output();
|
||||||
|
connect(test_struct_cmp_eq, test_struct_lhs.cmp_eq(test_struct_rhs));
|
||||||
|
#[hdl]
|
||||||
|
let test_struct_cmp_ne: Bool = m.output();
|
||||||
|
connect(test_struct_cmp_ne, test_struct_lhs.cmp_ne(test_struct_rhs));
|
||||||
|
|
||||||
|
#[hdl]
|
||||||
|
let test_struct_2_lhs: TestStruct2 = m.input();
|
||||||
|
#[hdl]
|
||||||
|
let test_struct_2_rhs: TestStruct2 = m.input();
|
||||||
|
#[hdl]
|
||||||
|
let test_struct_2_cmp_eq: Bool = m.output();
|
||||||
|
connect(
|
||||||
|
test_struct_2_cmp_eq,
|
||||||
|
test_struct_2_lhs.cmp_eq(test_struct_2_rhs),
|
||||||
|
);
|
||||||
|
#[hdl]
|
||||||
|
let test_struct_2_cmp_ne: Bool = m.output();
|
||||||
|
connect(
|
||||||
|
test_struct_2_cmp_ne,
|
||||||
|
test_struct_2_lhs.cmp_ne(test_struct_2_rhs),
|
||||||
|
);
|
||||||
|
|
||||||
|
#[hdl]
|
||||||
|
let test_struct_3_lhs: TestStruct3 = m.input();
|
||||||
|
#[hdl]
|
||||||
|
let test_struct_3_rhs: TestStruct3 = m.input();
|
||||||
|
#[hdl]
|
||||||
|
let test_struct_3_cmp_eq: Bool = m.output();
|
||||||
|
connect(
|
||||||
|
test_struct_3_cmp_eq,
|
||||||
|
test_struct_3_lhs.cmp_eq(test_struct_3_rhs),
|
||||||
|
);
|
||||||
|
#[hdl]
|
||||||
|
let test_struct_3_cmp_ne: Bool = m.output();
|
||||||
|
connect(
|
||||||
|
test_struct_3_cmp_ne,
|
||||||
|
test_struct_3_lhs.cmp_ne(test_struct_3_rhs),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_struct_cmp_eq() {
|
||||||
|
let _n = SourceLocation::normalize_files_for_tests();
|
||||||
|
let m = check_struct_cmp_eq();
|
||||||
|
dbg!(m);
|
||||||
|
#[rustfmt::skip] // work around https://github.com/rust-lang/rustfmt/issues/6161
|
||||||
|
assert_export_firrtl! {
|
||||||
|
m =>
|
||||||
|
"/test/check_struct_cmp_eq.fir": r"FIRRTL version 3.2.0
|
||||||
|
circuit check_struct_cmp_eq:
|
||||||
|
type Ty0 = {`0`: UInt<1>, `1`: SInt<1>, `2`: UInt<1>}
|
||||||
|
type Ty1 = {a: SInt<8>, b: UInt<8>}
|
||||||
|
type Ty2 = {v: UInt<8>}
|
||||||
|
type Ty3 = {}
|
||||||
|
module check_struct_cmp_eq: @[module-XXXXXXXXXX.rs 1:1]
|
||||||
|
input tuple_lhs: Ty0 @[module-XXXXXXXXXX.rs 2:1]
|
||||||
|
input tuple_rhs: Ty0 @[module-XXXXXXXXXX.rs 3:1]
|
||||||
|
output tuple_cmp_eq: UInt<1> @[module-XXXXXXXXXX.rs 4:1]
|
||||||
|
output tuple_cmp_ne: UInt<1> @[module-XXXXXXXXXX.rs 6:1]
|
||||||
|
input test_struct_lhs: Ty1 @[module-XXXXXXXXXX.rs 8:1]
|
||||||
|
input test_struct_rhs: Ty1 @[module-XXXXXXXXXX.rs 9:1]
|
||||||
|
output test_struct_cmp_eq: UInt<1> @[module-XXXXXXXXXX.rs 10:1]
|
||||||
|
output test_struct_cmp_ne: UInt<1> @[module-XXXXXXXXXX.rs 12:1]
|
||||||
|
input test_struct_2_lhs: Ty2 @[module-XXXXXXXXXX.rs 14:1]
|
||||||
|
input test_struct_2_rhs: Ty2 @[module-XXXXXXXXXX.rs 15:1]
|
||||||
|
output test_struct_2_cmp_eq: UInt<1> @[module-XXXXXXXXXX.rs 16:1]
|
||||||
|
output test_struct_2_cmp_ne: UInt<1> @[module-XXXXXXXXXX.rs 18:1]
|
||||||
|
input test_struct_3_lhs: Ty3 @[module-XXXXXXXXXX.rs 20:1]
|
||||||
|
input test_struct_3_rhs: Ty3 @[module-XXXXXXXXXX.rs 21:1]
|
||||||
|
output test_struct_3_cmp_eq: UInt<1> @[module-XXXXXXXXXX.rs 22:1]
|
||||||
|
output test_struct_3_cmp_ne: UInt<1> @[module-XXXXXXXXXX.rs 24:1]
|
||||||
|
wire _array_literal_expr: UInt<1>[3]
|
||||||
|
connect _array_literal_expr[0], eq(tuple_lhs.`0`, tuple_rhs.`0`)
|
||||||
|
connect _array_literal_expr[1], eq(tuple_lhs.`1`, tuple_rhs.`1`)
|
||||||
|
connect _array_literal_expr[2], eq(tuple_lhs.`2`, tuple_rhs.`2`)
|
||||||
|
wire _cast_array_to_bits_expr: UInt<1>[3]
|
||||||
|
connect _cast_array_to_bits_expr[0], _array_literal_expr[0]
|
||||||
|
connect _cast_array_to_bits_expr[1], _array_literal_expr[1]
|
||||||
|
connect _cast_array_to_bits_expr[2], _array_literal_expr[2]
|
||||||
|
wire _cast_to_bits_expr: UInt<3>
|
||||||
|
connect _cast_to_bits_expr, cat(_cast_array_to_bits_expr[2], cat(_cast_array_to_bits_expr[1], _cast_array_to_bits_expr[0]))
|
||||||
|
connect tuple_cmp_eq, andr(_cast_to_bits_expr) @[module-XXXXXXXXXX.rs 5:1]
|
||||||
|
wire _array_literal_expr_1: UInt<1>[3]
|
||||||
|
connect _array_literal_expr_1[0], neq(tuple_lhs.`0`, tuple_rhs.`0`)
|
||||||
|
connect _array_literal_expr_1[1], neq(tuple_lhs.`1`, tuple_rhs.`1`)
|
||||||
|
connect _array_literal_expr_1[2], neq(tuple_lhs.`2`, tuple_rhs.`2`)
|
||||||
|
wire _cast_array_to_bits_expr_1: UInt<1>[3]
|
||||||
|
connect _cast_array_to_bits_expr_1[0], _array_literal_expr_1[0]
|
||||||
|
connect _cast_array_to_bits_expr_1[1], _array_literal_expr_1[1]
|
||||||
|
connect _cast_array_to_bits_expr_1[2], _array_literal_expr_1[2]
|
||||||
|
wire _cast_to_bits_expr_1: UInt<3>
|
||||||
|
connect _cast_to_bits_expr_1, cat(_cast_array_to_bits_expr_1[2], cat(_cast_array_to_bits_expr_1[1], _cast_array_to_bits_expr_1[0]))
|
||||||
|
connect tuple_cmp_ne, orr(_cast_to_bits_expr_1) @[module-XXXXXXXXXX.rs 7:1]
|
||||||
|
connect test_struct_cmp_eq, and(eq(test_struct_lhs.a, test_struct_rhs.a), eq(test_struct_lhs.b, test_struct_rhs.b)) @[module-XXXXXXXXXX.rs 11:1]
|
||||||
|
connect test_struct_cmp_ne, or(neq(test_struct_lhs.a, test_struct_rhs.a), neq(test_struct_lhs.b, test_struct_rhs.b)) @[module-XXXXXXXXXX.rs 13:1]
|
||||||
|
connect test_struct_2_cmp_eq, eq(test_struct_2_lhs.v, test_struct_2_rhs.v) @[module-XXXXXXXXXX.rs 17:1]
|
||||||
|
connect test_struct_2_cmp_ne, neq(test_struct_2_lhs.v, test_struct_2_rhs.v) @[module-XXXXXXXXXX.rs 19:1]
|
||||||
|
connect test_struct_3_cmp_eq, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 23:1]
|
||||||
|
connect test_struct_3_cmp_ne, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 25:1]
|
||||||
|
",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
1445
crates/fayalite/tests/sim.rs
Normal file
1445
crates/fayalite/tests/sim.rs
Normal file
File diff suppressed because it is too large
Load diff
2859
crates/fayalite/tests/sim/expected/array_rw.txt
Normal file
2859
crates/fayalite/tests/sim/expected/array_rw.txt
Normal file
File diff suppressed because it is too large
Load diff
283
crates/fayalite/tests/sim/expected/array_rw.vcd
Normal file
283
crates/fayalite/tests/sim/expected/array_rw.vcd
Normal file
|
@ -0,0 +1,283 @@
|
||||||
|
$timescale 1 ps $end
|
||||||
|
$scope module array_rw $end
|
||||||
|
$scope struct array_in $end
|
||||||
|
$var wire 8 ! \[0] $end
|
||||||
|
$var wire 8 " \[1] $end
|
||||||
|
$var wire 8 # \[2] $end
|
||||||
|
$var wire 8 $ \[3] $end
|
||||||
|
$var wire 8 % \[4] $end
|
||||||
|
$var wire 8 & \[5] $end
|
||||||
|
$var wire 8 ' \[6] $end
|
||||||
|
$var wire 8 ( \[7] $end
|
||||||
|
$var wire 8 ) \[8] $end
|
||||||
|
$var wire 8 * \[9] $end
|
||||||
|
$var wire 8 + \[10] $end
|
||||||
|
$var wire 8 , \[11] $end
|
||||||
|
$var wire 8 - \[12] $end
|
||||||
|
$var wire 8 . \[13] $end
|
||||||
|
$var wire 8 / \[14] $end
|
||||||
|
$var wire 8 0 \[15] $end
|
||||||
|
$upscope $end
|
||||||
|
$scope struct array_out $end
|
||||||
|
$var wire 8 1 \[0] $end
|
||||||
|
$var wire 8 2 \[1] $end
|
||||||
|
$var wire 8 3 \[2] $end
|
||||||
|
$var wire 8 4 \[3] $end
|
||||||
|
$var wire 8 5 \[4] $end
|
||||||
|
$var wire 8 6 \[5] $end
|
||||||
|
$var wire 8 7 \[6] $end
|
||||||
|
$var wire 8 8 \[7] $end
|
||||||
|
$var wire 8 9 \[8] $end
|
||||||
|
$var wire 8 : \[9] $end
|
||||||
|
$var wire 8 ; \[10] $end
|
||||||
|
$var wire 8 < \[11] $end
|
||||||
|
$var wire 8 = \[12] $end
|
||||||
|
$var wire 8 > \[13] $end
|
||||||
|
$var wire 8 ? \[14] $end
|
||||||
|
$var wire 8 @ \[15] $end
|
||||||
|
$upscope $end
|
||||||
|
$var wire 8 A read_index $end
|
||||||
|
$var wire 8 B read_data $end
|
||||||
|
$var wire 8 C write_index $end
|
||||||
|
$var wire 8 D write_data $end
|
||||||
|
$var wire 1 E write_en $end
|
||||||
|
$scope struct array_wire $end
|
||||||
|
$var wire 8 F \[0] $end
|
||||||
|
$var wire 8 G \[1] $end
|
||||||
|
$var wire 8 H \[2] $end
|
||||||
|
$var wire 8 I \[3] $end
|
||||||
|
$var wire 8 J \[4] $end
|
||||||
|
$var wire 8 K \[5] $end
|
||||||
|
$var wire 8 L \[6] $end
|
||||||
|
$var wire 8 M \[7] $end
|
||||||
|
$var wire 8 N \[8] $end
|
||||||
|
$var wire 8 O \[9] $end
|
||||||
|
$var wire 8 P \[10] $end
|
||||||
|
$var wire 8 Q \[11] $end
|
||||||
|
$var wire 8 R \[12] $end
|
||||||
|
$var wire 8 S \[13] $end
|
||||||
|
$var wire 8 T \[14] $end
|
||||||
|
$var wire 8 U \[15] $end
|
||||||
|
$upscope $end
|
||||||
|
$upscope $end
|
||||||
|
$enddefinitions $end
|
||||||
|
$dumpvars
|
||||||
|
b11111111 !
|
||||||
|
b1111111 "
|
||||||
|
b111111 #
|
||||||
|
b11111 $
|
||||||
|
b1111 %
|
||||||
|
b111 &
|
||||||
|
b11 '
|
||||||
|
b1 (
|
||||||
|
b0 )
|
||||||
|
b10000000 *
|
||||||
|
b11000000 +
|
||||||
|
b11100000 ,
|
||||||
|
b11110000 -
|
||||||
|
b11111000 .
|
||||||
|
b11111100 /
|
||||||
|
b11111110 0
|
||||||
|
b11111111 1
|
||||||
|
b1111111 2
|
||||||
|
b111111 3
|
||||||
|
b11111 4
|
||||||
|
b1111 5
|
||||||
|
b111 6
|
||||||
|
b11 7
|
||||||
|
b1 8
|
||||||
|
b0 9
|
||||||
|
b10000000 :
|
||||||
|
b11000000 ;
|
||||||
|
b11100000 <
|
||||||
|
b11110000 =
|
||||||
|
b11111000 >
|
||||||
|
b11111100 ?
|
||||||
|
b11111110 @
|
||||||
|
b0 A
|
||||||
|
b11111111 B
|
||||||
|
b0 C
|
||||||
|
b0 D
|
||||||
|
0E
|
||||||
|
b11111111 F
|
||||||
|
b1111111 G
|
||||||
|
b111111 H
|
||||||
|
b11111 I
|
||||||
|
b1111 J
|
||||||
|
b111 K
|
||||||
|
b11 L
|
||||||
|
b1 M
|
||||||
|
b0 N
|
||||||
|
b10000000 O
|
||||||
|
b11000000 P
|
||||||
|
b11100000 Q
|
||||||
|
b11110000 R
|
||||||
|
b11111000 S
|
||||||
|
b11111100 T
|
||||||
|
b11111110 U
|
||||||
|
$end
|
||||||
|
#1000000
|
||||||
|
b1 A
|
||||||
|
b1111111 B
|
||||||
|
#2000000
|
||||||
|
b10 A
|
||||||
|
b111111 B
|
||||||
|
#3000000
|
||||||
|
b11 A
|
||||||
|
b11111 B
|
||||||
|
#4000000
|
||||||
|
b100 A
|
||||||
|
b1111 B
|
||||||
|
#5000000
|
||||||
|
b101 A
|
||||||
|
b111 B
|
||||||
|
#6000000
|
||||||
|
b110 A
|
||||||
|
b11 B
|
||||||
|
#7000000
|
||||||
|
b111 A
|
||||||
|
b1 B
|
||||||
|
#8000000
|
||||||
|
b1000 A
|
||||||
|
b0 B
|
||||||
|
#9000000
|
||||||
|
b1001 A
|
||||||
|
b10000000 B
|
||||||
|
#10000000
|
||||||
|
b1010 A
|
||||||
|
b11000000 B
|
||||||
|
#11000000
|
||||||
|
b1011 A
|
||||||
|
b11100000 B
|
||||||
|
#12000000
|
||||||
|
b1100 A
|
||||||
|
b11110000 B
|
||||||
|
#13000000
|
||||||
|
b1101 A
|
||||||
|
b11111000 B
|
||||||
|
#14000000
|
||||||
|
b1110 A
|
||||||
|
b11111100 B
|
||||||
|
#15000000
|
||||||
|
b1111 A
|
||||||
|
b11111110 B
|
||||||
|
#16000000
|
||||||
|
b10000 A
|
||||||
|
b0 B
|
||||||
|
#17000000
|
||||||
|
b0 1
|
||||||
|
b0 A
|
||||||
|
1E
|
||||||
|
b0 F
|
||||||
|
#18000000
|
||||||
|
b11111111 1
|
||||||
|
b1 2
|
||||||
|
b11111111 B
|
||||||
|
b1 C
|
||||||
|
b1 D
|
||||||
|
b11111111 F
|
||||||
|
b1 G
|
||||||
|
#19000000
|
||||||
|
b1111111 2
|
||||||
|
b100 3
|
||||||
|
b10 C
|
||||||
|
b100 D
|
||||||
|
b1111111 G
|
||||||
|
b100 H
|
||||||
|
#20000000
|
||||||
|
b111111 3
|
||||||
|
b1001 4
|
||||||
|
b11 C
|
||||||
|
b1001 D
|
||||||
|
b111111 H
|
||||||
|
b1001 I
|
||||||
|
#21000000
|
||||||
|
b11111 4
|
||||||
|
b10000 5
|
||||||
|
b100 C
|
||||||
|
b10000 D
|
||||||
|
b11111 I
|
||||||
|
b10000 J
|
||||||
|
#22000000
|
||||||
|
b1111 5
|
||||||
|
b11001 6
|
||||||
|
b101 C
|
||||||
|
b11001 D
|
||||||
|
b1111 J
|
||||||
|
b11001 K
|
||||||
|
#23000000
|
||||||
|
b111 6
|
||||||
|
b100100 7
|
||||||
|
b110 C
|
||||||
|
b100100 D
|
||||||
|
b111 K
|
||||||
|
b100100 L
|
||||||
|
#24000000
|
||||||
|
b11 7
|
||||||
|
b110001 8
|
||||||
|
b111 C
|
||||||
|
b110001 D
|
||||||
|
b11 L
|
||||||
|
b110001 M
|
||||||
|
#25000000
|
||||||
|
b1 8
|
||||||
|
b1000000 9
|
||||||
|
b1000 C
|
||||||
|
b1000000 D
|
||||||
|
b1 M
|
||||||
|
b1000000 N
|
||||||
|
#26000000
|
||||||
|
b0 9
|
||||||
|
b1010001 :
|
||||||
|
b1001 C
|
||||||
|
b1010001 D
|
||||||
|
b0 N
|
||||||
|
b1010001 O
|
||||||
|
#27000000
|
||||||
|
b10000000 :
|
||||||
|
b1100100 ;
|
||||||
|
b1010 C
|
||||||
|
b1100100 D
|
||||||
|
b10000000 O
|
||||||
|
b1100100 P
|
||||||
|
#28000000
|
||||||
|
b11000000 ;
|
||||||
|
b1111001 <
|
||||||
|
b1011 C
|
||||||
|
b1111001 D
|
||||||
|
b11000000 P
|
||||||
|
b1111001 Q
|
||||||
|
#29000000
|
||||||
|
b11100000 <
|
||||||
|
b10010000 =
|
||||||
|
b1100 C
|
||||||
|
b10010000 D
|
||||||
|
b11100000 Q
|
||||||
|
b10010000 R
|
||||||
|
#30000000
|
||||||
|
b11110000 =
|
||||||
|
b10101001 >
|
||||||
|
b1101 C
|
||||||
|
b10101001 D
|
||||||
|
b11110000 R
|
||||||
|
b10101001 S
|
||||||
|
#31000000
|
||||||
|
b11111000 >
|
||||||
|
b11000100 ?
|
||||||
|
b1110 C
|
||||||
|
b11000100 D
|
||||||
|
b11111000 S
|
||||||
|
b11000100 T
|
||||||
|
#32000000
|
||||||
|
b11111100 ?
|
||||||
|
b11100001 @
|
||||||
|
b1111 C
|
||||||
|
b11100001 D
|
||||||
|
b11111100 T
|
||||||
|
b11100001 U
|
||||||
|
#33000000
|
||||||
|
b11111110 @
|
||||||
|
b10000 C
|
||||||
|
b0 D
|
||||||
|
b11111110 U
|
||||||
|
#34000000
|
|
@ -0,0 +1,189 @@
|
||||||
|
Simulation {
|
||||||
|
state: State {
|
||||||
|
insns: Insns {
|
||||||
|
state_layout: StateLayout {
|
||||||
|
ty: TypeLayout {
|
||||||
|
small_slots: StatePartLayout<SmallSlots> {
|
||||||
|
len: 0,
|
||||||
|
debug_data: [],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
big_slots: StatePartLayout<BigSlots> {
|
||||||
|
len: 4,
|
||||||
|
debug_data: [
|
||||||
|
SlotDebugData {
|
||||||
|
name: "InstantiatedModule(conditional_assignment_last: conditional_assignment_last).conditional_assignment_last::i",
|
||||||
|
ty: Bool,
|
||||||
|
},
|
||||||
|
SlotDebugData {
|
||||||
|
name: "InstantiatedModule(conditional_assignment_last: conditional_assignment_last).conditional_assignment_last::w",
|
||||||
|
ty: Bool,
|
||||||
|
},
|
||||||
|
SlotDebugData {
|
||||||
|
name: "",
|
||||||
|
ty: Bool,
|
||||||
|
},
|
||||||
|
SlotDebugData {
|
||||||
|
name: "",
|
||||||
|
ty: Bool,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
},
|
||||||
|
memories: StatePartLayout<Memories> {
|
||||||
|
len: 0,
|
||||||
|
debug_data: [],
|
||||||
|
layout_data: [],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
},
|
||||||
|
insns: [
|
||||||
|
// at: module-XXXXXXXXXX.rs:1:1
|
||||||
|
0: Const {
|
||||||
|
dest: StatePartIndex<BigSlots>(3), // (0x0) SlotDebugData { name: "", ty: Bool },
|
||||||
|
value: 0x0,
|
||||||
|
},
|
||||||
|
1: Const {
|
||||||
|
dest: StatePartIndex<BigSlots>(2), // (0x1) SlotDebugData { name: "", ty: Bool },
|
||||||
|
value: 0x1,
|
||||||
|
},
|
||||||
|
// at: module-XXXXXXXXXX.rs:4:1
|
||||||
|
2: Copy {
|
||||||
|
dest: StatePartIndex<BigSlots>(1), // (0x0) SlotDebugData { name: "InstantiatedModule(conditional_assignment_last: conditional_assignment_last).conditional_assignment_last::w", ty: Bool },
|
||||||
|
src: StatePartIndex<BigSlots>(2), // (0x1) SlotDebugData { name: "", ty: Bool },
|
||||||
|
},
|
||||||
|
// at: module-XXXXXXXXXX.rs:5:1
|
||||||
|
3: BranchIfZero {
|
||||||
|
target: 5,
|
||||||
|
value: StatePartIndex<BigSlots>(0), // (0x1) SlotDebugData { name: "InstantiatedModule(conditional_assignment_last: conditional_assignment_last).conditional_assignment_last::i", ty: Bool },
|
||||||
|
},
|
||||||
|
// at: module-XXXXXXXXXX.rs:6:1
|
||||||
|
4: Copy {
|
||||||
|
dest: StatePartIndex<BigSlots>(1), // (0x0) SlotDebugData { name: "InstantiatedModule(conditional_assignment_last: conditional_assignment_last).conditional_assignment_last::w", ty: Bool },
|
||||||
|
src: StatePartIndex<BigSlots>(3), // (0x0) SlotDebugData { name: "", ty: Bool },
|
||||||
|
},
|
||||||
|
// at: module-XXXXXXXXXX.rs:1:1
|
||||||
|
5: Return,
|
||||||
|
],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
pc: 5,
|
||||||
|
memory_write_log: [],
|
||||||
|
memories: StatePart {
|
||||||
|
value: [],
|
||||||
|
},
|
||||||
|
small_slots: StatePart {
|
||||||
|
value: [],
|
||||||
|
},
|
||||||
|
big_slots: StatePart {
|
||||||
|
value: [
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
io: Instance {
|
||||||
|
name: <simulator>::conditional_assignment_last,
|
||||||
|
instantiated: Module {
|
||||||
|
name: conditional_assignment_last,
|
||||||
|
..
|
||||||
|
},
|
||||||
|
},
|
||||||
|
uninitialized_inputs: {},
|
||||||
|
io_targets: {
|
||||||
|
Instance {
|
||||||
|
name: <simulator>::conditional_assignment_last,
|
||||||
|
instantiated: Module {
|
||||||
|
name: conditional_assignment_last,
|
||||||
|
..
|
||||||
|
},
|
||||||
|
}.i: CompiledValue {
|
||||||
|
layout: CompiledTypeLayout {
|
||||||
|
ty: Bool,
|
||||||
|
layout: TypeLayout {
|
||||||
|
small_slots: StatePartLayout<SmallSlots> {
|
||||||
|
len: 0,
|
||||||
|
debug_data: [],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
big_slots: StatePartLayout<BigSlots> {
|
||||||
|
len: 1,
|
||||||
|
debug_data: [
|
||||||
|
SlotDebugData {
|
||||||
|
name: "InstantiatedModule(conditional_assignment_last: conditional_assignment_last).conditional_assignment_last::i",
|
||||||
|
ty: Bool,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
},
|
||||||
|
body: Scalar,
|
||||||
|
},
|
||||||
|
range: TypeIndexRange {
|
||||||
|
small_slots: StatePartIndexRange<SmallSlots> { start: 0, len: 0 },
|
||||||
|
big_slots: StatePartIndexRange<BigSlots> { start: 0, len: 1 },
|
||||||
|
},
|
||||||
|
write: None,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
made_initial_step: true,
|
||||||
|
needs_settle: false,
|
||||||
|
trace_decls: TraceModule {
|
||||||
|
name: "conditional_assignment_last",
|
||||||
|
children: [
|
||||||
|
TraceModuleIO {
|
||||||
|
name: "i",
|
||||||
|
child: TraceBool {
|
||||||
|
location: TraceScalarId(0),
|
||||||
|
name: "i",
|
||||||
|
flow: Source,
|
||||||
|
},
|
||||||
|
ty: Bool,
|
||||||
|
flow: Source,
|
||||||
|
},
|
||||||
|
TraceWire {
|
||||||
|
name: "w",
|
||||||
|
child: TraceBool {
|
||||||
|
location: TraceScalarId(1),
|
||||||
|
name: "w",
|
||||||
|
flow: Duplex,
|
||||||
|
},
|
||||||
|
ty: Bool,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
traces: [
|
||||||
|
SimTrace {
|
||||||
|
id: TraceScalarId(0),
|
||||||
|
kind: BigBool {
|
||||||
|
index: StatePartIndex<BigSlots>(0),
|
||||||
|
},
|
||||||
|
state: 0x1,
|
||||||
|
last_state: 0x0,
|
||||||
|
},
|
||||||
|
SimTrace {
|
||||||
|
id: TraceScalarId(1),
|
||||||
|
kind: BigBool {
|
||||||
|
index: StatePartIndex<BigSlots>(1),
|
||||||
|
},
|
||||||
|
state: 0x0,
|
||||||
|
last_state: 0x1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
trace_memories: {},
|
||||||
|
trace_writers: [
|
||||||
|
Running(
|
||||||
|
VcdWriter {
|
||||||
|
finished_init: true,
|
||||||
|
timescale: 1 ps,
|
||||||
|
..
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
instant: 2 μs,
|
||||||
|
clocks_triggered: [],
|
||||||
|
..
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
$timescale 1 ps $end
|
||||||
|
$scope module conditional_assignment_last $end
|
||||||
|
$var wire 1 ! i $end
|
||||||
|
$var wire 1 " w $end
|
||||||
|
$upscope $end
|
||||||
|
$enddefinitions $end
|
||||||
|
$dumpvars
|
||||||
|
0!
|
||||||
|
1"
|
||||||
|
$end
|
||||||
|
#1000000
|
||||||
|
1!
|
||||||
|
0"
|
||||||
|
#2000000
|
142
crates/fayalite/tests/sim/expected/connect_const.txt
Normal file
142
crates/fayalite/tests/sim/expected/connect_const.txt
Normal file
|
@ -0,0 +1,142 @@
|
||||||
|
Simulation {
|
||||||
|
state: State {
|
||||||
|
insns: Insns {
|
||||||
|
state_layout: StateLayout {
|
||||||
|
ty: TypeLayout {
|
||||||
|
small_slots: StatePartLayout<SmallSlots> {
|
||||||
|
len: 0,
|
||||||
|
debug_data: [],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
big_slots: StatePartLayout<BigSlots> {
|
||||||
|
len: 2,
|
||||||
|
debug_data: [
|
||||||
|
SlotDebugData {
|
||||||
|
name: "InstantiatedModule(connect_const: connect_const).connect_const::o",
|
||||||
|
ty: UInt<8>,
|
||||||
|
},
|
||||||
|
SlotDebugData {
|
||||||
|
name: "",
|
||||||
|
ty: UInt<8>,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
},
|
||||||
|
memories: StatePartLayout<Memories> {
|
||||||
|
len: 0,
|
||||||
|
debug_data: [],
|
||||||
|
layout_data: [],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
},
|
||||||
|
insns: [
|
||||||
|
// at: module-XXXXXXXXXX.rs:1:1
|
||||||
|
0: Const {
|
||||||
|
dest: StatePartIndex<BigSlots>(1), // (0x5) SlotDebugData { name: "", ty: UInt<8> },
|
||||||
|
value: 0x5,
|
||||||
|
},
|
||||||
|
// at: module-XXXXXXXXXX.rs:3:1
|
||||||
|
1: Copy {
|
||||||
|
dest: StatePartIndex<BigSlots>(0), // (0x5) SlotDebugData { name: "InstantiatedModule(connect_const: connect_const).connect_const::o", ty: UInt<8> },
|
||||||
|
src: StatePartIndex<BigSlots>(1), // (0x5) SlotDebugData { name: "", ty: UInt<8> },
|
||||||
|
},
|
||||||
|
// at: module-XXXXXXXXXX.rs:1:1
|
||||||
|
2: Return,
|
||||||
|
],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
pc: 2,
|
||||||
|
memory_write_log: [],
|
||||||
|
memories: StatePart {
|
||||||
|
value: [],
|
||||||
|
},
|
||||||
|
small_slots: StatePart {
|
||||||
|
value: [],
|
||||||
|
},
|
||||||
|
big_slots: StatePart {
|
||||||
|
value: [
|
||||||
|
5,
|
||||||
|
5,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
io: Instance {
|
||||||
|
name: <simulator>::connect_const,
|
||||||
|
instantiated: Module {
|
||||||
|
name: connect_const,
|
||||||
|
..
|
||||||
|
},
|
||||||
|
},
|
||||||
|
uninitialized_inputs: {},
|
||||||
|
io_targets: {
|
||||||
|
Instance {
|
||||||
|
name: <simulator>::connect_const,
|
||||||
|
instantiated: Module {
|
||||||
|
name: connect_const,
|
||||||
|
..
|
||||||
|
},
|
||||||
|
}.o: CompiledValue {
|
||||||
|
layout: CompiledTypeLayout {
|
||||||
|
ty: UInt<8>,
|
||||||
|
layout: TypeLayout {
|
||||||
|
small_slots: StatePartLayout<SmallSlots> {
|
||||||
|
len: 0,
|
||||||
|
debug_data: [],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
big_slots: StatePartLayout<BigSlots> {
|
||||||
|
len: 1,
|
||||||
|
debug_data: [
|
||||||
|
SlotDebugData {
|
||||||
|
name: "InstantiatedModule(connect_const: connect_const).connect_const::o",
|
||||||
|
ty: UInt<8>,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
},
|
||||||
|
body: Scalar,
|
||||||
|
},
|
||||||
|
range: TypeIndexRange {
|
||||||
|
small_slots: StatePartIndexRange<SmallSlots> { start: 0, len: 0 },
|
||||||
|
big_slots: StatePartIndexRange<BigSlots> { start: 0, len: 1 },
|
||||||
|
},
|
||||||
|
write: None,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
made_initial_step: true,
|
||||||
|
needs_settle: false,
|
||||||
|
trace_decls: TraceModule {
|
||||||
|
name: "connect_const",
|
||||||
|
children: [
|
||||||
|
TraceModuleIO {
|
||||||
|
name: "o",
|
||||||
|
child: TraceUInt {
|
||||||
|
location: TraceScalarId(0),
|
||||||
|
name: "o",
|
||||||
|
ty: UInt<8>,
|
||||||
|
flow: Sink,
|
||||||
|
},
|
||||||
|
ty: UInt<8>,
|
||||||
|
flow: Sink,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
traces: [
|
||||||
|
SimTrace {
|
||||||
|
id: TraceScalarId(0),
|
||||||
|
kind: BigUInt {
|
||||||
|
index: StatePartIndex<BigSlots>(0),
|
||||||
|
ty: UInt<8>,
|
||||||
|
},
|
||||||
|
state: 0x05,
|
||||||
|
last_state: 0x05,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
trace_memories: {},
|
||||||
|
trace_writers: [],
|
||||||
|
instant: 0 s,
|
||||||
|
clocks_triggered: [],
|
||||||
|
..
|
||||||
|
}
|
229
crates/fayalite/tests/sim/expected/connect_const_reset.txt
Normal file
229
crates/fayalite/tests/sim/expected/connect_const_reset.txt
Normal file
|
@ -0,0 +1,229 @@
|
||||||
|
Simulation {
|
||||||
|
state: State {
|
||||||
|
insns: Insns {
|
||||||
|
state_layout: StateLayout {
|
||||||
|
ty: TypeLayout {
|
||||||
|
small_slots: StatePartLayout<SmallSlots> {
|
||||||
|
len: 0,
|
||||||
|
debug_data: [],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
big_slots: StatePartLayout<BigSlots> {
|
||||||
|
len: 5,
|
||||||
|
debug_data: [
|
||||||
|
SlotDebugData {
|
||||||
|
name: "InstantiatedModule(connect_const_reset: connect_const_reset).connect_const_reset::reset_out",
|
||||||
|
ty: AsyncReset,
|
||||||
|
},
|
||||||
|
SlotDebugData {
|
||||||
|
name: "InstantiatedModule(connect_const_reset: connect_const_reset).connect_const_reset::bit_out",
|
||||||
|
ty: Bool,
|
||||||
|
},
|
||||||
|
SlotDebugData {
|
||||||
|
name: "",
|
||||||
|
ty: Bool,
|
||||||
|
},
|
||||||
|
SlotDebugData {
|
||||||
|
name: "",
|
||||||
|
ty: AsyncReset,
|
||||||
|
},
|
||||||
|
SlotDebugData {
|
||||||
|
name: "",
|
||||||
|
ty: Bool,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
},
|
||||||
|
memories: StatePartLayout<Memories> {
|
||||||
|
len: 0,
|
||||||
|
debug_data: [],
|
||||||
|
layout_data: [],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
},
|
||||||
|
insns: [
|
||||||
|
// at: module-XXXXXXXXXX.rs:1:1
|
||||||
|
0: Const {
|
||||||
|
dest: StatePartIndex<BigSlots>(2), // (0x1) SlotDebugData { name: "", ty: Bool },
|
||||||
|
value: 0x1,
|
||||||
|
},
|
||||||
|
1: Copy {
|
||||||
|
dest: StatePartIndex<BigSlots>(3), // (0x1) SlotDebugData { name: "", ty: AsyncReset },
|
||||||
|
src: StatePartIndex<BigSlots>(2), // (0x1) SlotDebugData { name: "", ty: Bool },
|
||||||
|
},
|
||||||
|
// at: module-XXXXXXXXXX.rs:4:1
|
||||||
|
2: Copy {
|
||||||
|
dest: StatePartIndex<BigSlots>(0), // (0x1) SlotDebugData { name: "InstantiatedModule(connect_const_reset: connect_const_reset).connect_const_reset::reset_out", ty: AsyncReset },
|
||||||
|
src: StatePartIndex<BigSlots>(3), // (0x1) SlotDebugData { name: "", ty: AsyncReset },
|
||||||
|
},
|
||||||
|
// at: module-XXXXXXXXXX.rs:1:1
|
||||||
|
3: Copy {
|
||||||
|
dest: StatePartIndex<BigSlots>(4), // (0x1) SlotDebugData { name: "", ty: Bool },
|
||||||
|
src: StatePartIndex<BigSlots>(0), // (0x1) SlotDebugData { name: "InstantiatedModule(connect_const_reset: connect_const_reset).connect_const_reset::reset_out", ty: AsyncReset },
|
||||||
|
},
|
||||||
|
// at: module-XXXXXXXXXX.rs:5:1
|
||||||
|
4: Copy {
|
||||||
|
dest: StatePartIndex<BigSlots>(1), // (0x1) SlotDebugData { name: "InstantiatedModule(connect_const_reset: connect_const_reset).connect_const_reset::bit_out", ty: Bool },
|
||||||
|
src: StatePartIndex<BigSlots>(4), // (0x1) SlotDebugData { name: "", ty: Bool },
|
||||||
|
},
|
||||||
|
// at: module-XXXXXXXXXX.rs:1:1
|
||||||
|
5: Return,
|
||||||
|
],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
pc: 5,
|
||||||
|
memory_write_log: [],
|
||||||
|
memories: StatePart {
|
||||||
|
value: [],
|
||||||
|
},
|
||||||
|
small_slots: StatePart {
|
||||||
|
value: [],
|
||||||
|
},
|
||||||
|
big_slots: StatePart {
|
||||||
|
value: [
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
io: Instance {
|
||||||
|
name: <simulator>::connect_const_reset,
|
||||||
|
instantiated: Module {
|
||||||
|
name: connect_const_reset,
|
||||||
|
..
|
||||||
|
},
|
||||||
|
},
|
||||||
|
uninitialized_inputs: {},
|
||||||
|
io_targets: {
|
||||||
|
Instance {
|
||||||
|
name: <simulator>::connect_const_reset,
|
||||||
|
instantiated: Module {
|
||||||
|
name: connect_const_reset,
|
||||||
|
..
|
||||||
|
},
|
||||||
|
}.bit_out: CompiledValue {
|
||||||
|
layout: CompiledTypeLayout {
|
||||||
|
ty: Bool,
|
||||||
|
layout: TypeLayout {
|
||||||
|
small_slots: StatePartLayout<SmallSlots> {
|
||||||
|
len: 0,
|
||||||
|
debug_data: [],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
big_slots: StatePartLayout<BigSlots> {
|
||||||
|
len: 1,
|
||||||
|
debug_data: [
|
||||||
|
SlotDebugData {
|
||||||
|
name: "InstantiatedModule(connect_const_reset: connect_const_reset).connect_const_reset::bit_out",
|
||||||
|
ty: Bool,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
},
|
||||||
|
body: Scalar,
|
||||||
|
},
|
||||||
|
range: TypeIndexRange {
|
||||||
|
small_slots: StatePartIndexRange<SmallSlots> { start: 0, len: 0 },
|
||||||
|
big_slots: StatePartIndexRange<BigSlots> { start: 1, len: 1 },
|
||||||
|
},
|
||||||
|
write: None,
|
||||||
|
},
|
||||||
|
Instance {
|
||||||
|
name: <simulator>::connect_const_reset,
|
||||||
|
instantiated: Module {
|
||||||
|
name: connect_const_reset,
|
||||||
|
..
|
||||||
|
},
|
||||||
|
}.reset_out: CompiledValue {
|
||||||
|
layout: CompiledTypeLayout {
|
||||||
|
ty: AsyncReset,
|
||||||
|
layout: TypeLayout {
|
||||||
|
small_slots: StatePartLayout<SmallSlots> {
|
||||||
|
len: 0,
|
||||||
|
debug_data: [],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
big_slots: StatePartLayout<BigSlots> {
|
||||||
|
len: 1,
|
||||||
|
debug_data: [
|
||||||
|
SlotDebugData {
|
||||||
|
name: "InstantiatedModule(connect_const_reset: connect_const_reset).connect_const_reset::reset_out",
|
||||||
|
ty: AsyncReset,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
},
|
||||||
|
body: Scalar,
|
||||||
|
},
|
||||||
|
range: TypeIndexRange {
|
||||||
|
small_slots: StatePartIndexRange<SmallSlots> { start: 0, len: 0 },
|
||||||
|
big_slots: StatePartIndexRange<BigSlots> { start: 0, len: 1 },
|
||||||
|
},
|
||||||
|
write: None,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
made_initial_step: true,
|
||||||
|
needs_settle: false,
|
||||||
|
trace_decls: TraceModule {
|
||||||
|
name: "connect_const_reset",
|
||||||
|
children: [
|
||||||
|
TraceModuleIO {
|
||||||
|
name: "reset_out",
|
||||||
|
child: TraceAsyncReset {
|
||||||
|
location: TraceScalarId(0),
|
||||||
|
name: "reset_out",
|
||||||
|
flow: Sink,
|
||||||
|
},
|
||||||
|
ty: AsyncReset,
|
||||||
|
flow: Sink,
|
||||||
|
},
|
||||||
|
TraceModuleIO {
|
||||||
|
name: "bit_out",
|
||||||
|
child: TraceBool {
|
||||||
|
location: TraceScalarId(1),
|
||||||
|
name: "bit_out",
|
||||||
|
flow: Sink,
|
||||||
|
},
|
||||||
|
ty: Bool,
|
||||||
|
flow: Sink,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
traces: [
|
||||||
|
SimTrace {
|
||||||
|
id: TraceScalarId(0),
|
||||||
|
kind: BigAsyncReset {
|
||||||
|
index: StatePartIndex<BigSlots>(0),
|
||||||
|
},
|
||||||
|
state: 0x1,
|
||||||
|
last_state: 0x1,
|
||||||
|
},
|
||||||
|
SimTrace {
|
||||||
|
id: TraceScalarId(1),
|
||||||
|
kind: BigBool {
|
||||||
|
index: StatePartIndex<BigSlots>(1),
|
||||||
|
},
|
||||||
|
state: 0x1,
|
||||||
|
last_state: 0x1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
trace_memories: {},
|
||||||
|
trace_writers: [
|
||||||
|
Running(
|
||||||
|
VcdWriter {
|
||||||
|
finished_init: true,
|
||||||
|
timescale: 1 ps,
|
||||||
|
..
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
instant: 1 μs,
|
||||||
|
clocks_triggered: [],
|
||||||
|
..
|
||||||
|
}
|
11
crates/fayalite/tests/sim/expected/connect_const_reset.vcd
Normal file
11
crates/fayalite/tests/sim/expected/connect_const_reset.vcd
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
$timescale 1 ps $end
|
||||||
|
$scope module connect_const_reset $end
|
||||||
|
$var wire 1 ! reset_out $end
|
||||||
|
$var wire 1 " bit_out $end
|
||||||
|
$upscope $end
|
||||||
|
$enddefinitions $end
|
||||||
|
$dumpvars
|
||||||
|
1!
|
||||||
|
1"
|
||||||
|
$end
|
||||||
|
#1000000
|
522
crates/fayalite/tests/sim/expected/counter_async.txt
Normal file
522
crates/fayalite/tests/sim/expected/counter_async.txt
Normal file
|
@ -0,0 +1,522 @@
|
||||||
|
Simulation {
|
||||||
|
state: State {
|
||||||
|
insns: Insns {
|
||||||
|
state_layout: StateLayout {
|
||||||
|
ty: TypeLayout {
|
||||||
|
small_slots: StatePartLayout<SmallSlots> {
|
||||||
|
len: 4,
|
||||||
|
debug_data: [
|
||||||
|
SlotDebugData {
|
||||||
|
name: "",
|
||||||
|
ty: Bool,
|
||||||
|
},
|
||||||
|
SlotDebugData {
|
||||||
|
name: "",
|
||||||
|
ty: Bool,
|
||||||
|
},
|
||||||
|
SlotDebugData {
|
||||||
|
name: "",
|
||||||
|
ty: Bool,
|
||||||
|
},
|
||||||
|
SlotDebugData {
|
||||||
|
name: "",
|
||||||
|
ty: Bool,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
big_slots: StatePartLayout<BigSlots> {
|
||||||
|
len: 10,
|
||||||
|
debug_data: [
|
||||||
|
SlotDebugData {
|
||||||
|
name: "InstantiatedModule(counter: counter).counter::cd.clk",
|
||||||
|
ty: Clock,
|
||||||
|
},
|
||||||
|
SlotDebugData {
|
||||||
|
name: "InstantiatedModule(counter: counter).counter::cd.rst",
|
||||||
|
ty: AsyncReset,
|
||||||
|
},
|
||||||
|
SlotDebugData {
|
||||||
|
name: "InstantiatedModule(counter: counter).counter::count",
|
||||||
|
ty: UInt<4>,
|
||||||
|
},
|
||||||
|
SlotDebugData {
|
||||||
|
name: "InstantiatedModule(counter: counter).counter::count_reg",
|
||||||
|
ty: UInt<4>,
|
||||||
|
},
|
||||||
|
SlotDebugData {
|
||||||
|
name: "InstantiatedModule(counter: counter).counter::count_reg$next",
|
||||||
|
ty: UInt<4>,
|
||||||
|
},
|
||||||
|
SlotDebugData {
|
||||||
|
name: "",
|
||||||
|
ty: UInt<4>,
|
||||||
|
},
|
||||||
|
SlotDebugData {
|
||||||
|
name: "",
|
||||||
|
ty: Bool,
|
||||||
|
},
|
||||||
|
SlotDebugData {
|
||||||
|
name: "",
|
||||||
|
ty: UInt<1>,
|
||||||
|
},
|
||||||
|
SlotDebugData {
|
||||||
|
name: "",
|
||||||
|
ty: UInt<5>,
|
||||||
|
},
|
||||||
|
SlotDebugData {
|
||||||
|
name: "",
|
||||||
|
ty: UInt<4>,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
},
|
||||||
|
memories: StatePartLayout<Memories> {
|
||||||
|
len: 0,
|
||||||
|
debug_data: [],
|
||||||
|
layout_data: [],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
},
|
||||||
|
insns: [
|
||||||
|
// at: module-XXXXXXXXXX.rs:1:1
|
||||||
|
0: Const {
|
||||||
|
dest: StatePartIndex<BigSlots>(7), // (0x1) SlotDebugData { name: "", ty: UInt<1> },
|
||||||
|
value: 0x1,
|
||||||
|
},
|
||||||
|
1: Copy {
|
||||||
|
dest: StatePartIndex<BigSlots>(6), // (0x0) SlotDebugData { name: "", ty: Bool },
|
||||||
|
src: StatePartIndex<BigSlots>(1), // (0x0) SlotDebugData { name: "InstantiatedModule(counter: counter).counter::cd.rst", ty: AsyncReset },
|
||||||
|
},
|
||||||
|
// at: module-XXXXXXXXXX.rs:3:1
|
||||||
|
2: IsNonZeroDestIsSmall {
|
||||||
|
dest: StatePartIndex<SmallSlots>(3), // (0x0 0) SlotDebugData { name: "", ty: Bool },
|
||||||
|
src: StatePartIndex<BigSlots>(1), // (0x0) SlotDebugData { name: "InstantiatedModule(counter: counter).counter::cd.rst", ty: AsyncReset },
|
||||||
|
},
|
||||||
|
// at: module-XXXXXXXXXX.rs:1:1
|
||||||
|
3: Const {
|
||||||
|
dest: StatePartIndex<BigSlots>(5), // (0x3) SlotDebugData { name: "", ty: UInt<4> },
|
||||||
|
value: 0x3,
|
||||||
|
},
|
||||||
|
// at: module-XXXXXXXXXX.rs:3:1
|
||||||
|
4: BranchIfZero {
|
||||||
|
target: 6,
|
||||||
|
value: StatePartIndex<BigSlots>(6), // (0x0) SlotDebugData { name: "", ty: Bool },
|
||||||
|
},
|
||||||
|
5: Copy {
|
||||||
|
dest: StatePartIndex<BigSlots>(3), // (0x3) SlotDebugData { name: "InstantiatedModule(counter: counter).counter::count_reg", ty: UInt<4> },
|
||||||
|
src: StatePartIndex<BigSlots>(5), // (0x3) SlotDebugData { name: "", ty: UInt<4> },
|
||||||
|
},
|
||||||
|
// at: module-XXXXXXXXXX.rs:1:1
|
||||||
|
6: Add {
|
||||||
|
dest: StatePartIndex<BigSlots>(8), // (0x4) SlotDebugData { name: "", ty: UInt<5> },
|
||||||
|
lhs: StatePartIndex<BigSlots>(3), // (0x3) SlotDebugData { name: "InstantiatedModule(counter: counter).counter::count_reg", ty: UInt<4> },
|
||||||
|
rhs: StatePartIndex<BigSlots>(7), // (0x1) SlotDebugData { name: "", ty: UInt<1> },
|
||||||
|
},
|
||||||
|
7: CastToUInt {
|
||||||
|
dest: StatePartIndex<BigSlots>(9), // (0x4) SlotDebugData { name: "", ty: UInt<4> },
|
||||||
|
src: StatePartIndex<BigSlots>(8), // (0x4) SlotDebugData { name: "", ty: UInt<5> },
|
||||||
|
dest_width: 4,
|
||||||
|
},
|
||||||
|
// at: module-XXXXXXXXXX.rs:4:1
|
||||||
|
8: Copy {
|
||||||
|
dest: StatePartIndex<BigSlots>(4), // (0x4) SlotDebugData { name: "InstantiatedModule(counter: counter).counter::count_reg$next", ty: UInt<4> },
|
||||||
|
src: StatePartIndex<BigSlots>(9), // (0x4) SlotDebugData { name: "", ty: UInt<4> },
|
||||||
|
},
|
||||||
|
// at: module-XXXXXXXXXX.rs:6:1
|
||||||
|
9: Copy {
|
||||||
|
dest: StatePartIndex<BigSlots>(2), // (0x3) SlotDebugData { name: "InstantiatedModule(counter: counter).counter::count", ty: UInt<4> },
|
||||||
|
src: StatePartIndex<BigSlots>(3), // (0x3) SlotDebugData { name: "InstantiatedModule(counter: counter).counter::count_reg", ty: UInt<4> },
|
||||||
|
},
|
||||||
|
// at: module-XXXXXXXXXX.rs:3:1
|
||||||
|
10: IsNonZeroDestIsSmall {
|
||||||
|
dest: StatePartIndex<SmallSlots>(2), // (0x1 1) SlotDebugData { name: "", ty: Bool },
|
||||||
|
src: StatePartIndex<BigSlots>(0), // (0x1) SlotDebugData { name: "InstantiatedModule(counter: counter).counter::cd.clk", ty: Clock },
|
||||||
|
},
|
||||||
|
11: AndSmall {
|
||||||
|
dest: StatePartIndex<SmallSlots>(1), // (0x0 0) SlotDebugData { name: "", ty: Bool },
|
||||||
|
lhs: StatePartIndex<SmallSlots>(2), // (0x1 1) SlotDebugData { name: "", ty: Bool },
|
||||||
|
rhs: StatePartIndex<SmallSlots>(0), // (0x0 0) SlotDebugData { name: "", ty: Bool },
|
||||||
|
},
|
||||||
|
12: BranchIfSmallNonZero {
|
||||||
|
target: 16,
|
||||||
|
value: StatePartIndex<SmallSlots>(3), // (0x0 0) SlotDebugData { name: "", ty: Bool },
|
||||||
|
},
|
||||||
|
13: BranchIfSmallZero {
|
||||||
|
target: 17,
|
||||||
|
value: StatePartIndex<SmallSlots>(1), // (0x0 0) SlotDebugData { name: "", ty: Bool },
|
||||||
|
},
|
||||||
|
14: Copy {
|
||||||
|
dest: StatePartIndex<BigSlots>(3), // (0x3) SlotDebugData { name: "InstantiatedModule(counter: counter).counter::count_reg", ty: UInt<4> },
|
||||||
|
src: StatePartIndex<BigSlots>(4), // (0x4) SlotDebugData { name: "InstantiatedModule(counter: counter).counter::count_reg$next", ty: UInt<4> },
|
||||||
|
},
|
||||||
|
15: Branch {
|
||||||
|
target: 17,
|
||||||
|
},
|
||||||
|
16: Copy {
|
||||||
|
dest: StatePartIndex<BigSlots>(3), // (0x3) SlotDebugData { name: "InstantiatedModule(counter: counter).counter::count_reg", ty: UInt<4> },
|
||||||
|
src: StatePartIndex<BigSlots>(5), // (0x3) SlotDebugData { name: "", ty: UInt<4> },
|
||||||
|
},
|
||||||
|
17: XorSmallImmediate {
|
||||||
|
dest: StatePartIndex<SmallSlots>(0), // (0x0 0) SlotDebugData { name: "", ty: Bool },
|
||||||
|
lhs: StatePartIndex<SmallSlots>(2), // (0x1 1) SlotDebugData { name: "", ty: Bool },
|
||||||
|
rhs: 0x1,
|
||||||
|
},
|
||||||
|
// at: module-XXXXXXXXXX.rs:1:1
|
||||||
|
18: Return,
|
||||||
|
],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
pc: 18,
|
||||||
|
memory_write_log: [],
|
||||||
|
memories: StatePart {
|
||||||
|
value: [],
|
||||||
|
},
|
||||||
|
small_slots: StatePart {
|
||||||
|
value: [
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
big_slots: StatePart {
|
||||||
|
value: [
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
3,
|
||||||
|
3,
|
||||||
|
4,
|
||||||
|
3,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
4,
|
||||||
|
4,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
io: Instance {
|
||||||
|
name: <simulator>::counter,
|
||||||
|
instantiated: Module {
|
||||||
|
name: counter,
|
||||||
|
..
|
||||||
|
},
|
||||||
|
},
|
||||||
|
uninitialized_inputs: {},
|
||||||
|
io_targets: {
|
||||||
|
Instance {
|
||||||
|
name: <simulator>::counter,
|
||||||
|
instantiated: Module {
|
||||||
|
name: counter,
|
||||||
|
..
|
||||||
|
},
|
||||||
|
}.cd: CompiledValue {
|
||||||
|
layout: CompiledTypeLayout {
|
||||||
|
ty: Bundle {
|
||||||
|
/* offset = 0 */
|
||||||
|
clk: Clock,
|
||||||
|
/* offset = 1 */
|
||||||
|
rst: AsyncReset,
|
||||||
|
},
|
||||||
|
layout: TypeLayout {
|
||||||
|
small_slots: StatePartLayout<SmallSlots> {
|
||||||
|
len: 0,
|
||||||
|
debug_data: [],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
big_slots: StatePartLayout<BigSlots> {
|
||||||
|
len: 2,
|
||||||
|
debug_data: [
|
||||||
|
SlotDebugData {
|
||||||
|
name: "InstantiatedModule(counter: counter).counter::cd.clk",
|
||||||
|
ty: Clock,
|
||||||
|
},
|
||||||
|
SlotDebugData {
|
||||||
|
name: "InstantiatedModule(counter: counter).counter::cd.rst",
|
||||||
|
ty: AsyncReset,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
},
|
||||||
|
body: Bundle {
|
||||||
|
fields: [
|
||||||
|
CompiledBundleField {
|
||||||
|
offset: TypeIndex {
|
||||||
|
small_slots: StatePartIndex<SmallSlots>(0),
|
||||||
|
big_slots: StatePartIndex<BigSlots>(0),
|
||||||
|
},
|
||||||
|
ty: CompiledTypeLayout {
|
||||||
|
ty: Clock,
|
||||||
|
layout: TypeLayout {
|
||||||
|
small_slots: StatePartLayout<SmallSlots> {
|
||||||
|
len: 0,
|
||||||
|
debug_data: [],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
big_slots: StatePartLayout<BigSlots> {
|
||||||
|
len: 1,
|
||||||
|
debug_data: [
|
||||||
|
SlotDebugData {
|
||||||
|
name: "",
|
||||||
|
ty: Clock,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
},
|
||||||
|
body: Scalar,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
CompiledBundleField {
|
||||||
|
offset: TypeIndex {
|
||||||
|
small_slots: StatePartIndex<SmallSlots>(0),
|
||||||
|
big_slots: StatePartIndex<BigSlots>(1),
|
||||||
|
},
|
||||||
|
ty: CompiledTypeLayout {
|
||||||
|
ty: AsyncReset,
|
||||||
|
layout: TypeLayout {
|
||||||
|
small_slots: StatePartLayout<SmallSlots> {
|
||||||
|
len: 0,
|
||||||
|
debug_data: [],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
big_slots: StatePartLayout<BigSlots> {
|
||||||
|
len: 1,
|
||||||
|
debug_data: [
|
||||||
|
SlotDebugData {
|
||||||
|
name: "",
|
||||||
|
ty: AsyncReset,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
},
|
||||||
|
body: Scalar,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
range: TypeIndexRange {
|
||||||
|
small_slots: StatePartIndexRange<SmallSlots> { start: 0, len: 0 },
|
||||||
|
big_slots: StatePartIndexRange<BigSlots> { start: 0, len: 2 },
|
||||||
|
},
|
||||||
|
write: None,
|
||||||
|
},
|
||||||
|
Instance {
|
||||||
|
name: <simulator>::counter,
|
||||||
|
instantiated: Module {
|
||||||
|
name: counter,
|
||||||
|
..
|
||||||
|
},
|
||||||
|
}.cd.clk: CompiledValue {
|
||||||
|
layout: CompiledTypeLayout {
|
||||||
|
ty: Clock,
|
||||||
|
layout: TypeLayout {
|
||||||
|
small_slots: StatePartLayout<SmallSlots> {
|
||||||
|
len: 0,
|
||||||
|
debug_data: [],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
big_slots: StatePartLayout<BigSlots> {
|
||||||
|
len: 1,
|
||||||
|
debug_data: [
|
||||||
|
SlotDebugData {
|
||||||
|
name: "",
|
||||||
|
ty: Clock,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
},
|
||||||
|
body: Scalar,
|
||||||
|
},
|
||||||
|
range: TypeIndexRange {
|
||||||
|
small_slots: StatePartIndexRange<SmallSlots> { start: 0, len: 0 },
|
||||||
|
big_slots: StatePartIndexRange<BigSlots> { start: 0, len: 1 },
|
||||||
|
},
|
||||||
|
write: None,
|
||||||
|
},
|
||||||
|
Instance {
|
||||||
|
name: <simulator>::counter,
|
||||||
|
instantiated: Module {
|
||||||
|
name: counter,
|
||||||
|
..
|
||||||
|
},
|
||||||
|
}.cd.rst: CompiledValue {
|
||||||
|
layout: CompiledTypeLayout {
|
||||||
|
ty: AsyncReset,
|
||||||
|
layout: TypeLayout {
|
||||||
|
small_slots: StatePartLayout<SmallSlots> {
|
||||||
|
len: 0,
|
||||||
|
debug_data: [],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
big_slots: StatePartLayout<BigSlots> {
|
||||||
|
len: 1,
|
||||||
|
debug_data: [
|
||||||
|
SlotDebugData {
|
||||||
|
name: "",
|
||||||
|
ty: AsyncReset,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
},
|
||||||
|
body: Scalar,
|
||||||
|
},
|
||||||
|
range: TypeIndexRange {
|
||||||
|
small_slots: StatePartIndexRange<SmallSlots> { start: 0, len: 0 },
|
||||||
|
big_slots: StatePartIndexRange<BigSlots> { start: 1, len: 1 },
|
||||||
|
},
|
||||||
|
write: None,
|
||||||
|
},
|
||||||
|
Instance {
|
||||||
|
name: <simulator>::counter,
|
||||||
|
instantiated: Module {
|
||||||
|
name: counter,
|
||||||
|
..
|
||||||
|
},
|
||||||
|
}.count: CompiledValue {
|
||||||
|
layout: CompiledTypeLayout {
|
||||||
|
ty: UInt<4>,
|
||||||
|
layout: TypeLayout {
|
||||||
|
small_slots: StatePartLayout<SmallSlots> {
|
||||||
|
len: 0,
|
||||||
|
debug_data: [],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
big_slots: StatePartLayout<BigSlots> {
|
||||||
|
len: 1,
|
||||||
|
debug_data: [
|
||||||
|
SlotDebugData {
|
||||||
|
name: "InstantiatedModule(counter: counter).counter::count",
|
||||||
|
ty: UInt<4>,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
},
|
||||||
|
body: Scalar,
|
||||||
|
},
|
||||||
|
range: TypeIndexRange {
|
||||||
|
small_slots: StatePartIndexRange<SmallSlots> { start: 0, len: 0 },
|
||||||
|
big_slots: StatePartIndexRange<BigSlots> { start: 2, len: 1 },
|
||||||
|
},
|
||||||
|
write: None,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
made_initial_step: true,
|
||||||
|
needs_settle: false,
|
||||||
|
trace_decls: TraceModule {
|
||||||
|
name: "counter",
|
||||||
|
children: [
|
||||||
|
TraceModuleIO {
|
||||||
|
name: "cd",
|
||||||
|
child: TraceBundle {
|
||||||
|
name: "cd",
|
||||||
|
fields: [
|
||||||
|
TraceClock {
|
||||||
|
location: TraceScalarId(0),
|
||||||
|
name: "clk",
|
||||||
|
flow: Source,
|
||||||
|
},
|
||||||
|
TraceAsyncReset {
|
||||||
|
location: TraceScalarId(1),
|
||||||
|
name: "rst",
|
||||||
|
flow: Source,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
ty: Bundle {
|
||||||
|
/* offset = 0 */
|
||||||
|
clk: Clock,
|
||||||
|
/* offset = 1 */
|
||||||
|
rst: AsyncReset,
|
||||||
|
},
|
||||||
|
flow: Source,
|
||||||
|
},
|
||||||
|
ty: Bundle {
|
||||||
|
/* offset = 0 */
|
||||||
|
clk: Clock,
|
||||||
|
/* offset = 1 */
|
||||||
|
rst: AsyncReset,
|
||||||
|
},
|
||||||
|
flow: Source,
|
||||||
|
},
|
||||||
|
TraceModuleIO {
|
||||||
|
name: "count",
|
||||||
|
child: TraceUInt {
|
||||||
|
location: TraceScalarId(2),
|
||||||
|
name: "count",
|
||||||
|
ty: UInt<4>,
|
||||||
|
flow: Sink,
|
||||||
|
},
|
||||||
|
ty: UInt<4>,
|
||||||
|
flow: Sink,
|
||||||
|
},
|
||||||
|
TraceReg {
|
||||||
|
name: "count_reg",
|
||||||
|
child: TraceUInt {
|
||||||
|
location: TraceScalarId(3),
|
||||||
|
name: "count_reg",
|
||||||
|
ty: UInt<4>,
|
||||||
|
flow: Duplex,
|
||||||
|
},
|
||||||
|
ty: UInt<4>,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
traces: [
|
||||||
|
SimTrace {
|
||||||
|
id: TraceScalarId(0),
|
||||||
|
kind: BigClock {
|
||||||
|
index: StatePartIndex<BigSlots>(0),
|
||||||
|
},
|
||||||
|
state: 0x1,
|
||||||
|
last_state: 0x1,
|
||||||
|
},
|
||||||
|
SimTrace {
|
||||||
|
id: TraceScalarId(1),
|
||||||
|
kind: BigAsyncReset {
|
||||||
|
index: StatePartIndex<BigSlots>(1),
|
||||||
|
},
|
||||||
|
state: 0x0,
|
||||||
|
last_state: 0x0,
|
||||||
|
},
|
||||||
|
SimTrace {
|
||||||
|
id: TraceScalarId(2),
|
||||||
|
kind: BigUInt {
|
||||||
|
index: StatePartIndex<BigSlots>(2),
|
||||||
|
ty: UInt<4>,
|
||||||
|
},
|
||||||
|
state: 0x3,
|
||||||
|
last_state: 0x2,
|
||||||
|
},
|
||||||
|
SimTrace {
|
||||||
|
id: TraceScalarId(3),
|
||||||
|
kind: BigUInt {
|
||||||
|
index: StatePartIndex<BigSlots>(3),
|
||||||
|
ty: UInt<4>,
|
||||||
|
},
|
||||||
|
state: 0x3,
|
||||||
|
last_state: 0x3,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
trace_memories: {},
|
||||||
|
trace_writers: [
|
||||||
|
Running(
|
||||||
|
VcdWriter {
|
||||||
|
finished_init: true,
|
||||||
|
timescale: 1 ps,
|
||||||
|
..
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
instant: 66 μs,
|
||||||
|
clocks_triggered: [
|
||||||
|
StatePartIndex<SmallSlots>(1),
|
||||||
|
],
|
||||||
|
..
|
||||||
|
}
|
217
crates/fayalite/tests/sim/expected/counter_async.vcd
Normal file
217
crates/fayalite/tests/sim/expected/counter_async.vcd
Normal file
|
@ -0,0 +1,217 @@
|
||||||
|
$timescale 1 ps $end
|
||||||
|
$scope module counter $end
|
||||||
|
$scope struct cd $end
|
||||||
|
$var wire 1 ! clk $end
|
||||||
|
$var wire 1 " rst $end
|
||||||
|
$upscope $end
|
||||||
|
$var wire 4 # count $end
|
||||||
|
$var reg 4 $ count_reg $end
|
||||||
|
$upscope $end
|
||||||
|
$enddefinitions $end
|
||||||
|
$dumpvars
|
||||||
|
0!
|
||||||
|
0"
|
||||||
|
b0 #
|
||||||
|
b0 $
|
||||||
|
$end
|
||||||
|
#500000
|
||||||
|
1"
|
||||||
|
b11 #
|
||||||
|
b11 $
|
||||||
|
#1000000
|
||||||
|
1!
|
||||||
|
#1500000
|
||||||
|
0"
|
||||||
|
#2000000
|
||||||
|
0!
|
||||||
|
#3000000
|
||||||
|
1!
|
||||||
|
b100 $
|
||||||
|
b100 #
|
||||||
|
#4000000
|
||||||
|
0!
|
||||||
|
#5000000
|
||||||
|
1!
|
||||||
|
b101 $
|
||||||
|
b101 #
|
||||||
|
#6000000
|
||||||
|
0!
|
||||||
|
#7000000
|
||||||
|
1!
|
||||||
|
b110 $
|
||||||
|
b110 #
|
||||||
|
#8000000
|
||||||
|
0!
|
||||||
|
#9000000
|
||||||
|
1!
|
||||||
|
b111 $
|
||||||
|
b111 #
|
||||||
|
#10000000
|
||||||
|
0!
|
||||||
|
#11000000
|
||||||
|
1!
|
||||||
|
b1000 $
|
||||||
|
b1000 #
|
||||||
|
#12000000
|
||||||
|
0!
|
||||||
|
#13000000
|
||||||
|
1!
|
||||||
|
b1001 $
|
||||||
|
b1001 #
|
||||||
|
#14000000
|
||||||
|
0!
|
||||||
|
#15000000
|
||||||
|
1!
|
||||||
|
b1010 $
|
||||||
|
b1010 #
|
||||||
|
#16000000
|
||||||
|
0!
|
||||||
|
#17000000
|
||||||
|
1!
|
||||||
|
b1011 $
|
||||||
|
b1011 #
|
||||||
|
#18000000
|
||||||
|
0!
|
||||||
|
#19000000
|
||||||
|
1!
|
||||||
|
b1100 $
|
||||||
|
b1100 #
|
||||||
|
#20000000
|
||||||
|
0!
|
||||||
|
#21000000
|
||||||
|
1!
|
||||||
|
b1101 $
|
||||||
|
b1101 #
|
||||||
|
#22000000
|
||||||
|
0!
|
||||||
|
#23000000
|
||||||
|
1!
|
||||||
|
b1110 $
|
||||||
|
b1110 #
|
||||||
|
#24000000
|
||||||
|
0!
|
||||||
|
#25000000
|
||||||
|
1!
|
||||||
|
b1111 $
|
||||||
|
b1111 #
|
||||||
|
#26000000
|
||||||
|
0!
|
||||||
|
#27000000
|
||||||
|
1!
|
||||||
|
b0 $
|
||||||
|
b0 #
|
||||||
|
#28000000
|
||||||
|
0!
|
||||||
|
#29000000
|
||||||
|
1!
|
||||||
|
b1 $
|
||||||
|
b1 #
|
||||||
|
#30000000
|
||||||
|
0!
|
||||||
|
#31000000
|
||||||
|
1!
|
||||||
|
b10 $
|
||||||
|
b10 #
|
||||||
|
#32000000
|
||||||
|
0!
|
||||||
|
#33000000
|
||||||
|
1!
|
||||||
|
b11 $
|
||||||
|
b11 #
|
||||||
|
#34000000
|
||||||
|
0!
|
||||||
|
#35000000
|
||||||
|
1!
|
||||||
|
b100 $
|
||||||
|
b100 #
|
||||||
|
#36000000
|
||||||
|
0!
|
||||||
|
#37000000
|
||||||
|
1!
|
||||||
|
b101 $
|
||||||
|
b101 #
|
||||||
|
#38000000
|
||||||
|
0!
|
||||||
|
#39000000
|
||||||
|
1!
|
||||||
|
b110 $
|
||||||
|
b110 #
|
||||||
|
#40000000
|
||||||
|
0!
|
||||||
|
#41000000
|
||||||
|
1!
|
||||||
|
b111 $
|
||||||
|
b111 #
|
||||||
|
#42000000
|
||||||
|
0!
|
||||||
|
#43000000
|
||||||
|
1!
|
||||||
|
b1000 $
|
||||||
|
b1000 #
|
||||||
|
#44000000
|
||||||
|
0!
|
||||||
|
#45000000
|
||||||
|
1!
|
||||||
|
b1001 $
|
||||||
|
b1001 #
|
||||||
|
#46000000
|
||||||
|
0!
|
||||||
|
#47000000
|
||||||
|
1!
|
||||||
|
b1010 $
|
||||||
|
b1010 #
|
||||||
|
#48000000
|
||||||
|
0!
|
||||||
|
#49000000
|
||||||
|
1!
|
||||||
|
b1011 $
|
||||||
|
b1011 #
|
||||||
|
#50000000
|
||||||
|
0!
|
||||||
|
#51000000
|
||||||
|
1!
|
||||||
|
b1100 $
|
||||||
|
b1100 #
|
||||||
|
#52000000
|
||||||
|
0!
|
||||||
|
#53000000
|
||||||
|
1!
|
||||||
|
b1101 $
|
||||||
|
b1101 #
|
||||||
|
#54000000
|
||||||
|
0!
|
||||||
|
#55000000
|
||||||
|
1!
|
||||||
|
b1110 $
|
||||||
|
b1110 #
|
||||||
|
#56000000
|
||||||
|
0!
|
||||||
|
#57000000
|
||||||
|
1!
|
||||||
|
b1111 $
|
||||||
|
b1111 #
|
||||||
|
#58000000
|
||||||
|
0!
|
||||||
|
#59000000
|
||||||
|
1!
|
||||||
|
b0 $
|
||||||
|
b0 #
|
||||||
|
#60000000
|
||||||
|
0!
|
||||||
|
#61000000
|
||||||
|
1!
|
||||||
|
b1 $
|
||||||
|
b1 #
|
||||||
|
#62000000
|
||||||
|
0!
|
||||||
|
#63000000
|
||||||
|
1!
|
||||||
|
b10 $
|
||||||
|
b10 #
|
||||||
|
#64000000
|
||||||
|
0!
|
||||||
|
#65000000
|
||||||
|
1!
|
||||||
|
b11 $
|
||||||
|
b11 #
|
||||||
|
#66000000
|
503
crates/fayalite/tests/sim/expected/counter_sync.txt
Normal file
503
crates/fayalite/tests/sim/expected/counter_sync.txt
Normal file
|
@ -0,0 +1,503 @@
|
||||||
|
Simulation {
|
||||||
|
state: State {
|
||||||
|
insns: Insns {
|
||||||
|
state_layout: StateLayout {
|
||||||
|
ty: TypeLayout {
|
||||||
|
small_slots: StatePartLayout<SmallSlots> {
|
||||||
|
len: 4,
|
||||||
|
debug_data: [
|
||||||
|
SlotDebugData {
|
||||||
|
name: "",
|
||||||
|
ty: Bool,
|
||||||
|
},
|
||||||
|
SlotDebugData {
|
||||||
|
name: "",
|
||||||
|
ty: Bool,
|
||||||
|
},
|
||||||
|
SlotDebugData {
|
||||||
|
name: "",
|
||||||
|
ty: Bool,
|
||||||
|
},
|
||||||
|
SlotDebugData {
|
||||||
|
name: "",
|
||||||
|
ty: Bool,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
big_slots: StatePartLayout<BigSlots> {
|
||||||
|
len: 9,
|
||||||
|
debug_data: [
|
||||||
|
SlotDebugData {
|
||||||
|
name: "InstantiatedModule(counter: counter).counter::cd.clk",
|
||||||
|
ty: Clock,
|
||||||
|
},
|
||||||
|
SlotDebugData {
|
||||||
|
name: "InstantiatedModule(counter: counter).counter::cd.rst",
|
||||||
|
ty: SyncReset,
|
||||||
|
},
|
||||||
|
SlotDebugData {
|
||||||
|
name: "InstantiatedModule(counter: counter).counter::count",
|
||||||
|
ty: UInt<4>,
|
||||||
|
},
|
||||||
|
SlotDebugData {
|
||||||
|
name: "InstantiatedModule(counter: counter).counter::count_reg",
|
||||||
|
ty: UInt<4>,
|
||||||
|
},
|
||||||
|
SlotDebugData {
|
||||||
|
name: "InstantiatedModule(counter: counter).counter::count_reg$next",
|
||||||
|
ty: UInt<4>,
|
||||||
|
},
|
||||||
|
SlotDebugData {
|
||||||
|
name: "",
|
||||||
|
ty: UInt<4>,
|
||||||
|
},
|
||||||
|
SlotDebugData {
|
||||||
|
name: "",
|
||||||
|
ty: UInt<1>,
|
||||||
|
},
|
||||||
|
SlotDebugData {
|
||||||
|
name: "",
|
||||||
|
ty: UInt<5>,
|
||||||
|
},
|
||||||
|
SlotDebugData {
|
||||||
|
name: "",
|
||||||
|
ty: UInt<4>,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
},
|
||||||
|
memories: StatePartLayout<Memories> {
|
||||||
|
len: 0,
|
||||||
|
debug_data: [],
|
||||||
|
layout_data: [],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
},
|
||||||
|
insns: [
|
||||||
|
// at: module-XXXXXXXXXX.rs:6:1
|
||||||
|
0: Copy {
|
||||||
|
dest: StatePartIndex<BigSlots>(2), // (0x3) SlotDebugData { name: "InstantiatedModule(counter: counter).counter::count", ty: UInt<4> },
|
||||||
|
src: StatePartIndex<BigSlots>(3), // (0x3) SlotDebugData { name: "InstantiatedModule(counter: counter).counter::count_reg", ty: UInt<4> },
|
||||||
|
},
|
||||||
|
// at: module-XXXXXXXXXX.rs:1:1
|
||||||
|
1: Const {
|
||||||
|
dest: StatePartIndex<BigSlots>(6), // (0x1) SlotDebugData { name: "", ty: UInt<1> },
|
||||||
|
value: 0x1,
|
||||||
|
},
|
||||||
|
2: Add {
|
||||||
|
dest: StatePartIndex<BigSlots>(7), // (0x4) SlotDebugData { name: "", ty: UInt<5> },
|
||||||
|
lhs: StatePartIndex<BigSlots>(3), // (0x3) SlotDebugData { name: "InstantiatedModule(counter: counter).counter::count_reg", ty: UInt<4> },
|
||||||
|
rhs: StatePartIndex<BigSlots>(6), // (0x1) SlotDebugData { name: "", ty: UInt<1> },
|
||||||
|
},
|
||||||
|
3: CastToUInt {
|
||||||
|
dest: StatePartIndex<BigSlots>(8), // (0x4) SlotDebugData { name: "", ty: UInt<4> },
|
||||||
|
src: StatePartIndex<BigSlots>(7), // (0x4) SlotDebugData { name: "", ty: UInt<5> },
|
||||||
|
dest_width: 4,
|
||||||
|
},
|
||||||
|
// at: module-XXXXXXXXXX.rs:4:1
|
||||||
|
4: Copy {
|
||||||
|
dest: StatePartIndex<BigSlots>(4), // (0x4) SlotDebugData { name: "InstantiatedModule(counter: counter).counter::count_reg$next", ty: UInt<4> },
|
||||||
|
src: StatePartIndex<BigSlots>(8), // (0x4) SlotDebugData { name: "", ty: UInt<4> },
|
||||||
|
},
|
||||||
|
// at: module-XXXXXXXXXX.rs:3:1
|
||||||
|
5: IsNonZeroDestIsSmall {
|
||||||
|
dest: StatePartIndex<SmallSlots>(3), // (0x0 0) SlotDebugData { name: "", ty: Bool },
|
||||||
|
src: StatePartIndex<BigSlots>(1), // (0x0) SlotDebugData { name: "InstantiatedModule(counter: counter).counter::cd.rst", ty: SyncReset },
|
||||||
|
},
|
||||||
|
// at: module-XXXXXXXXXX.rs:1:1
|
||||||
|
6: Const {
|
||||||
|
dest: StatePartIndex<BigSlots>(5), // (0x3) SlotDebugData { name: "", ty: UInt<4> },
|
||||||
|
value: 0x3,
|
||||||
|
},
|
||||||
|
// at: module-XXXXXXXXXX.rs:3:1
|
||||||
|
7: IsNonZeroDestIsSmall {
|
||||||
|
dest: StatePartIndex<SmallSlots>(2), // (0x1 1) SlotDebugData { name: "", ty: Bool },
|
||||||
|
src: StatePartIndex<BigSlots>(0), // (0x1) SlotDebugData { name: "InstantiatedModule(counter: counter).counter::cd.clk", ty: Clock },
|
||||||
|
},
|
||||||
|
8: AndSmall {
|
||||||
|
dest: StatePartIndex<SmallSlots>(1), // (0x0 0) SlotDebugData { name: "", ty: Bool },
|
||||||
|
lhs: StatePartIndex<SmallSlots>(2), // (0x1 1) SlotDebugData { name: "", ty: Bool },
|
||||||
|
rhs: StatePartIndex<SmallSlots>(0), // (0x0 0) SlotDebugData { name: "", ty: Bool },
|
||||||
|
},
|
||||||
|
9: BranchIfSmallZero {
|
||||||
|
target: 14,
|
||||||
|
value: StatePartIndex<SmallSlots>(1), // (0x0 0) SlotDebugData { name: "", ty: Bool },
|
||||||
|
},
|
||||||
|
10: BranchIfSmallNonZero {
|
||||||
|
target: 13,
|
||||||
|
value: StatePartIndex<SmallSlots>(3), // (0x0 0) SlotDebugData { name: "", ty: Bool },
|
||||||
|
},
|
||||||
|
11: Copy {
|
||||||
|
dest: StatePartIndex<BigSlots>(3), // (0x3) SlotDebugData { name: "InstantiatedModule(counter: counter).counter::count_reg", ty: UInt<4> },
|
||||||
|
src: StatePartIndex<BigSlots>(4), // (0x4) SlotDebugData { name: "InstantiatedModule(counter: counter).counter::count_reg$next", ty: UInt<4> },
|
||||||
|
},
|
||||||
|
12: Branch {
|
||||||
|
target: 14,
|
||||||
|
},
|
||||||
|
13: Copy {
|
||||||
|
dest: StatePartIndex<BigSlots>(3), // (0x3) SlotDebugData { name: "InstantiatedModule(counter: counter).counter::count_reg", ty: UInt<4> },
|
||||||
|
src: StatePartIndex<BigSlots>(5), // (0x3) SlotDebugData { name: "", ty: UInt<4> },
|
||||||
|
},
|
||||||
|
14: XorSmallImmediate {
|
||||||
|
dest: StatePartIndex<SmallSlots>(0), // (0x0 0) SlotDebugData { name: "", ty: Bool },
|
||||||
|
lhs: StatePartIndex<SmallSlots>(2), // (0x1 1) SlotDebugData { name: "", ty: Bool },
|
||||||
|
rhs: 0x1,
|
||||||
|
},
|
||||||
|
// at: module-XXXXXXXXXX.rs:1:1
|
||||||
|
15: Return,
|
||||||
|
],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
pc: 15,
|
||||||
|
memory_write_log: [],
|
||||||
|
memories: StatePart {
|
||||||
|
value: [],
|
||||||
|
},
|
||||||
|
small_slots: StatePart {
|
||||||
|
value: [
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
big_slots: StatePart {
|
||||||
|
value: [
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
3,
|
||||||
|
3,
|
||||||
|
4,
|
||||||
|
3,
|
||||||
|
1,
|
||||||
|
4,
|
||||||
|
4,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
io: Instance {
|
||||||
|
name: <simulator>::counter,
|
||||||
|
instantiated: Module {
|
||||||
|
name: counter,
|
||||||
|
..
|
||||||
|
},
|
||||||
|
},
|
||||||
|
uninitialized_inputs: {},
|
||||||
|
io_targets: {
|
||||||
|
Instance {
|
||||||
|
name: <simulator>::counter,
|
||||||
|
instantiated: Module {
|
||||||
|
name: counter,
|
||||||
|
..
|
||||||
|
},
|
||||||
|
}.cd: CompiledValue {
|
||||||
|
layout: CompiledTypeLayout {
|
||||||
|
ty: Bundle {
|
||||||
|
/* offset = 0 */
|
||||||
|
clk: Clock,
|
||||||
|
/* offset = 1 */
|
||||||
|
rst: SyncReset,
|
||||||
|
},
|
||||||
|
layout: TypeLayout {
|
||||||
|
small_slots: StatePartLayout<SmallSlots> {
|
||||||
|
len: 0,
|
||||||
|
debug_data: [],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
big_slots: StatePartLayout<BigSlots> {
|
||||||
|
len: 2,
|
||||||
|
debug_data: [
|
||||||
|
SlotDebugData {
|
||||||
|
name: "InstantiatedModule(counter: counter).counter::cd.clk",
|
||||||
|
ty: Clock,
|
||||||
|
},
|
||||||
|
SlotDebugData {
|
||||||
|
name: "InstantiatedModule(counter: counter).counter::cd.rst",
|
||||||
|
ty: SyncReset,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
},
|
||||||
|
body: Bundle {
|
||||||
|
fields: [
|
||||||
|
CompiledBundleField {
|
||||||
|
offset: TypeIndex {
|
||||||
|
small_slots: StatePartIndex<SmallSlots>(0),
|
||||||
|
big_slots: StatePartIndex<BigSlots>(0),
|
||||||
|
},
|
||||||
|
ty: CompiledTypeLayout {
|
||||||
|
ty: Clock,
|
||||||
|
layout: TypeLayout {
|
||||||
|
small_slots: StatePartLayout<SmallSlots> {
|
||||||
|
len: 0,
|
||||||
|
debug_data: [],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
big_slots: StatePartLayout<BigSlots> {
|
||||||
|
len: 1,
|
||||||
|
debug_data: [
|
||||||
|
SlotDebugData {
|
||||||
|
name: "",
|
||||||
|
ty: Clock,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
},
|
||||||
|
body: Scalar,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
CompiledBundleField {
|
||||||
|
offset: TypeIndex {
|
||||||
|
small_slots: StatePartIndex<SmallSlots>(0),
|
||||||
|
big_slots: StatePartIndex<BigSlots>(1),
|
||||||
|
},
|
||||||
|
ty: CompiledTypeLayout {
|
||||||
|
ty: SyncReset,
|
||||||
|
layout: TypeLayout {
|
||||||
|
small_slots: StatePartLayout<SmallSlots> {
|
||||||
|
len: 0,
|
||||||
|
debug_data: [],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
big_slots: StatePartLayout<BigSlots> {
|
||||||
|
len: 1,
|
||||||
|
debug_data: [
|
||||||
|
SlotDebugData {
|
||||||
|
name: "",
|
||||||
|
ty: SyncReset,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
},
|
||||||
|
body: Scalar,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
range: TypeIndexRange {
|
||||||
|
small_slots: StatePartIndexRange<SmallSlots> { start: 0, len: 0 },
|
||||||
|
big_slots: StatePartIndexRange<BigSlots> { start: 0, len: 2 },
|
||||||
|
},
|
||||||
|
write: None,
|
||||||
|
},
|
||||||
|
Instance {
|
||||||
|
name: <simulator>::counter,
|
||||||
|
instantiated: Module {
|
||||||
|
name: counter,
|
||||||
|
..
|
||||||
|
},
|
||||||
|
}.cd.clk: CompiledValue {
|
||||||
|
layout: CompiledTypeLayout {
|
||||||
|
ty: Clock,
|
||||||
|
layout: TypeLayout {
|
||||||
|
small_slots: StatePartLayout<SmallSlots> {
|
||||||
|
len: 0,
|
||||||
|
debug_data: [],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
big_slots: StatePartLayout<BigSlots> {
|
||||||
|
len: 1,
|
||||||
|
debug_data: [
|
||||||
|
SlotDebugData {
|
||||||
|
name: "",
|
||||||
|
ty: Clock,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
},
|
||||||
|
body: Scalar,
|
||||||
|
},
|
||||||
|
range: TypeIndexRange {
|
||||||
|
small_slots: StatePartIndexRange<SmallSlots> { start: 0, len: 0 },
|
||||||
|
big_slots: StatePartIndexRange<BigSlots> { start: 0, len: 1 },
|
||||||
|
},
|
||||||
|
write: None,
|
||||||
|
},
|
||||||
|
Instance {
|
||||||
|
name: <simulator>::counter,
|
||||||
|
instantiated: Module {
|
||||||
|
name: counter,
|
||||||
|
..
|
||||||
|
},
|
||||||
|
}.cd.rst: CompiledValue {
|
||||||
|
layout: CompiledTypeLayout {
|
||||||
|
ty: SyncReset,
|
||||||
|
layout: TypeLayout {
|
||||||
|
small_slots: StatePartLayout<SmallSlots> {
|
||||||
|
len: 0,
|
||||||
|
debug_data: [],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
big_slots: StatePartLayout<BigSlots> {
|
||||||
|
len: 1,
|
||||||
|
debug_data: [
|
||||||
|
SlotDebugData {
|
||||||
|
name: "",
|
||||||
|
ty: SyncReset,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
},
|
||||||
|
body: Scalar,
|
||||||
|
},
|
||||||
|
range: TypeIndexRange {
|
||||||
|
small_slots: StatePartIndexRange<SmallSlots> { start: 0, len: 0 },
|
||||||
|
big_slots: StatePartIndexRange<BigSlots> { start: 1, len: 1 },
|
||||||
|
},
|
||||||
|
write: None,
|
||||||
|
},
|
||||||
|
Instance {
|
||||||
|
name: <simulator>::counter,
|
||||||
|
instantiated: Module {
|
||||||
|
name: counter,
|
||||||
|
..
|
||||||
|
},
|
||||||
|
}.count: CompiledValue {
|
||||||
|
layout: CompiledTypeLayout {
|
||||||
|
ty: UInt<4>,
|
||||||
|
layout: TypeLayout {
|
||||||
|
small_slots: StatePartLayout<SmallSlots> {
|
||||||
|
len: 0,
|
||||||
|
debug_data: [],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
big_slots: StatePartLayout<BigSlots> {
|
||||||
|
len: 1,
|
||||||
|
debug_data: [
|
||||||
|
SlotDebugData {
|
||||||
|
name: "InstantiatedModule(counter: counter).counter::count",
|
||||||
|
ty: UInt<4>,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
},
|
||||||
|
body: Scalar,
|
||||||
|
},
|
||||||
|
range: TypeIndexRange {
|
||||||
|
small_slots: StatePartIndexRange<SmallSlots> { start: 0, len: 0 },
|
||||||
|
big_slots: StatePartIndexRange<BigSlots> { start: 2, len: 1 },
|
||||||
|
},
|
||||||
|
write: None,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
made_initial_step: true,
|
||||||
|
needs_settle: false,
|
||||||
|
trace_decls: TraceModule {
|
||||||
|
name: "counter",
|
||||||
|
children: [
|
||||||
|
TraceModuleIO {
|
||||||
|
name: "cd",
|
||||||
|
child: TraceBundle {
|
||||||
|
name: "cd",
|
||||||
|
fields: [
|
||||||
|
TraceClock {
|
||||||
|
location: TraceScalarId(0),
|
||||||
|
name: "clk",
|
||||||
|
flow: Source,
|
||||||
|
},
|
||||||
|
TraceSyncReset {
|
||||||
|
location: TraceScalarId(1),
|
||||||
|
name: "rst",
|
||||||
|
flow: Source,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
ty: Bundle {
|
||||||
|
/* offset = 0 */
|
||||||
|
clk: Clock,
|
||||||
|
/* offset = 1 */
|
||||||
|
rst: SyncReset,
|
||||||
|
},
|
||||||
|
flow: Source,
|
||||||
|
},
|
||||||
|
ty: Bundle {
|
||||||
|
/* offset = 0 */
|
||||||
|
clk: Clock,
|
||||||
|
/* offset = 1 */
|
||||||
|
rst: SyncReset,
|
||||||
|
},
|
||||||
|
flow: Source,
|
||||||
|
},
|
||||||
|
TraceModuleIO {
|
||||||
|
name: "count",
|
||||||
|
child: TraceUInt {
|
||||||
|
location: TraceScalarId(2),
|
||||||
|
name: "count",
|
||||||
|
ty: UInt<4>,
|
||||||
|
flow: Sink,
|
||||||
|
},
|
||||||
|
ty: UInt<4>,
|
||||||
|
flow: Sink,
|
||||||
|
},
|
||||||
|
TraceReg {
|
||||||
|
name: "count_reg",
|
||||||
|
child: TraceUInt {
|
||||||
|
location: TraceScalarId(3),
|
||||||
|
name: "count_reg",
|
||||||
|
ty: UInt<4>,
|
||||||
|
flow: Duplex,
|
||||||
|
},
|
||||||
|
ty: UInt<4>,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
traces: [
|
||||||
|
SimTrace {
|
||||||
|
id: TraceScalarId(0),
|
||||||
|
kind: BigClock {
|
||||||
|
index: StatePartIndex<BigSlots>(0),
|
||||||
|
},
|
||||||
|
state: 0x1,
|
||||||
|
last_state: 0x1,
|
||||||
|
},
|
||||||
|
SimTrace {
|
||||||
|
id: TraceScalarId(1),
|
||||||
|
kind: BigSyncReset {
|
||||||
|
index: StatePartIndex<BigSlots>(1),
|
||||||
|
},
|
||||||
|
state: 0x0,
|
||||||
|
last_state: 0x0,
|
||||||
|
},
|
||||||
|
SimTrace {
|
||||||
|
id: TraceScalarId(2),
|
||||||
|
kind: BigUInt {
|
||||||
|
index: StatePartIndex<BigSlots>(2),
|
||||||
|
ty: UInt<4>,
|
||||||
|
},
|
||||||
|
state: 0x3,
|
||||||
|
last_state: 0x2,
|
||||||
|
},
|
||||||
|
SimTrace {
|
||||||
|
id: TraceScalarId(3),
|
||||||
|
kind: BigUInt {
|
||||||
|
index: StatePartIndex<BigSlots>(3),
|
||||||
|
ty: UInt<4>,
|
||||||
|
},
|
||||||
|
state: 0x3,
|
||||||
|
last_state: 0x3,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
trace_memories: {},
|
||||||
|
trace_writers: [
|
||||||
|
Running(
|
||||||
|
VcdWriter {
|
||||||
|
finished_init: true,
|
||||||
|
timescale: 1 ps,
|
||||||
|
..
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
instant: 66 μs,
|
||||||
|
clocks_triggered: [
|
||||||
|
StatePartIndex<SmallSlots>(1),
|
||||||
|
],
|
||||||
|
..
|
||||||
|
}
|
214
crates/fayalite/tests/sim/expected/counter_sync.vcd
Normal file
214
crates/fayalite/tests/sim/expected/counter_sync.vcd
Normal file
|
@ -0,0 +1,214 @@
|
||||||
|
$timescale 1 ps $end
|
||||||
|
$scope module counter $end
|
||||||
|
$scope struct cd $end
|
||||||
|
$var wire 1 ! clk $end
|
||||||
|
$var wire 1 " rst $end
|
||||||
|
$upscope $end
|
||||||
|
$var wire 4 # count $end
|
||||||
|
$var reg 4 $ count_reg $end
|
||||||
|
$upscope $end
|
||||||
|
$enddefinitions $end
|
||||||
|
$dumpvars
|
||||||
|
0!
|
||||||
|
1"
|
||||||
|
b0 #
|
||||||
|
b0 $
|
||||||
|
$end
|
||||||
|
#1000000
|
||||||
|
1!
|
||||||
|
b11 $
|
||||||
|
b11 #
|
||||||
|
0"
|
||||||
|
#2000000
|
||||||
|
0!
|
||||||
|
#3000000
|
||||||
|
1!
|
||||||
|
b100 $
|
||||||
|
b100 #
|
||||||
|
#4000000
|
||||||
|
0!
|
||||||
|
#5000000
|
||||||
|
1!
|
||||||
|
b101 $
|
||||||
|
b101 #
|
||||||
|
#6000000
|
||||||
|
0!
|
||||||
|
#7000000
|
||||||
|
1!
|
||||||
|
b110 $
|
||||||
|
b110 #
|
||||||
|
#8000000
|
||||||
|
0!
|
||||||
|
#9000000
|
||||||
|
1!
|
||||||
|
b111 $
|
||||||
|
b111 #
|
||||||
|
#10000000
|
||||||
|
0!
|
||||||
|
#11000000
|
||||||
|
1!
|
||||||
|
b1000 $
|
||||||
|
b1000 #
|
||||||
|
#12000000
|
||||||
|
0!
|
||||||
|
#13000000
|
||||||
|
1!
|
||||||
|
b1001 $
|
||||||
|
b1001 #
|
||||||
|
#14000000
|
||||||
|
0!
|
||||||
|
#15000000
|
||||||
|
1!
|
||||||
|
b1010 $
|
||||||
|
b1010 #
|
||||||
|
#16000000
|
||||||
|
0!
|
||||||
|
#17000000
|
||||||
|
1!
|
||||||
|
b1011 $
|
||||||
|
b1011 #
|
||||||
|
#18000000
|
||||||
|
0!
|
||||||
|
#19000000
|
||||||
|
1!
|
||||||
|
b1100 $
|
||||||
|
b1100 #
|
||||||
|
#20000000
|
||||||
|
0!
|
||||||
|
#21000000
|
||||||
|
1!
|
||||||
|
b1101 $
|
||||||
|
b1101 #
|
||||||
|
#22000000
|
||||||
|
0!
|
||||||
|
#23000000
|
||||||
|
1!
|
||||||
|
b1110 $
|
||||||
|
b1110 #
|
||||||
|
#24000000
|
||||||
|
0!
|
||||||
|
#25000000
|
||||||
|
1!
|
||||||
|
b1111 $
|
||||||
|
b1111 #
|
||||||
|
#26000000
|
||||||
|
0!
|
||||||
|
#27000000
|
||||||
|
1!
|
||||||
|
b0 $
|
||||||
|
b0 #
|
||||||
|
#28000000
|
||||||
|
0!
|
||||||
|
#29000000
|
||||||
|
1!
|
||||||
|
b1 $
|
||||||
|
b1 #
|
||||||
|
#30000000
|
||||||
|
0!
|
||||||
|
#31000000
|
||||||
|
1!
|
||||||
|
b10 $
|
||||||
|
b10 #
|
||||||
|
#32000000
|
||||||
|
0!
|
||||||
|
#33000000
|
||||||
|
1!
|
||||||
|
b11 $
|
||||||
|
b11 #
|
||||||
|
#34000000
|
||||||
|
0!
|
||||||
|
#35000000
|
||||||
|
1!
|
||||||
|
b100 $
|
||||||
|
b100 #
|
||||||
|
#36000000
|
||||||
|
0!
|
||||||
|
#37000000
|
||||||
|
1!
|
||||||
|
b101 $
|
||||||
|
b101 #
|
||||||
|
#38000000
|
||||||
|
0!
|
||||||
|
#39000000
|
||||||
|
1!
|
||||||
|
b110 $
|
||||||
|
b110 #
|
||||||
|
#40000000
|
||||||
|
0!
|
||||||
|
#41000000
|
||||||
|
1!
|
||||||
|
b111 $
|
||||||
|
b111 #
|
||||||
|
#42000000
|
||||||
|
0!
|
||||||
|
#43000000
|
||||||
|
1!
|
||||||
|
b1000 $
|
||||||
|
b1000 #
|
||||||
|
#44000000
|
||||||
|
0!
|
||||||
|
#45000000
|
||||||
|
1!
|
||||||
|
b1001 $
|
||||||
|
b1001 #
|
||||||
|
#46000000
|
||||||
|
0!
|
||||||
|
#47000000
|
||||||
|
1!
|
||||||
|
b1010 $
|
||||||
|
b1010 #
|
||||||
|
#48000000
|
||||||
|
0!
|
||||||
|
#49000000
|
||||||
|
1!
|
||||||
|
b1011 $
|
||||||
|
b1011 #
|
||||||
|
#50000000
|
||||||
|
0!
|
||||||
|
#51000000
|
||||||
|
1!
|
||||||
|
b1100 $
|
||||||
|
b1100 #
|
||||||
|
#52000000
|
||||||
|
0!
|
||||||
|
#53000000
|
||||||
|
1!
|
||||||
|
b1101 $
|
||||||
|
b1101 #
|
||||||
|
#54000000
|
||||||
|
0!
|
||||||
|
#55000000
|
||||||
|
1!
|
||||||
|
b1110 $
|
||||||
|
b1110 #
|
||||||
|
#56000000
|
||||||
|
0!
|
||||||
|
#57000000
|
||||||
|
1!
|
||||||
|
b1111 $
|
||||||
|
b1111 #
|
||||||
|
#58000000
|
||||||
|
0!
|
||||||
|
#59000000
|
||||||
|
1!
|
||||||
|
b0 $
|
||||||
|
b0 #
|
||||||
|
#60000000
|
||||||
|
0!
|
||||||
|
#61000000
|
||||||
|
1!
|
||||||
|
b1 $
|
||||||
|
b1 #
|
||||||
|
#62000000
|
||||||
|
0!
|
||||||
|
#63000000
|
||||||
|
1!
|
||||||
|
b10 $
|
||||||
|
b10 #
|
||||||
|
#64000000
|
||||||
|
0!
|
||||||
|
#65000000
|
||||||
|
1!
|
||||||
|
b11 $
|
||||||
|
b11 #
|
||||||
|
#66000000
|
153
crates/fayalite/tests/sim/expected/duplicate_names.txt
Normal file
153
crates/fayalite/tests/sim/expected/duplicate_names.txt
Normal file
|
@ -0,0 +1,153 @@
|
||||||
|
Simulation {
|
||||||
|
state: State {
|
||||||
|
insns: Insns {
|
||||||
|
state_layout: StateLayout {
|
||||||
|
ty: TypeLayout {
|
||||||
|
small_slots: StatePartLayout<SmallSlots> {
|
||||||
|
len: 0,
|
||||||
|
debug_data: [],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
big_slots: StatePartLayout<BigSlots> {
|
||||||
|
len: 4,
|
||||||
|
debug_data: [
|
||||||
|
SlotDebugData {
|
||||||
|
name: "InstantiatedModule(duplicate_names: duplicate_names).duplicate_names::w",
|
||||||
|
ty: UInt<8>,
|
||||||
|
},
|
||||||
|
SlotDebugData {
|
||||||
|
name: "",
|
||||||
|
ty: UInt<8>,
|
||||||
|
},
|
||||||
|
SlotDebugData {
|
||||||
|
name: "InstantiatedModule(duplicate_names: duplicate_names).duplicate_names::w",
|
||||||
|
ty: UInt<8>,
|
||||||
|
},
|
||||||
|
SlotDebugData {
|
||||||
|
name: "",
|
||||||
|
ty: UInt<8>,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
},
|
||||||
|
memories: StatePartLayout<Memories> {
|
||||||
|
len: 0,
|
||||||
|
debug_data: [],
|
||||||
|
layout_data: [],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
},
|
||||||
|
insns: [
|
||||||
|
// at: module-XXXXXXXXXX.rs:1:1
|
||||||
|
0: Const {
|
||||||
|
dest: StatePartIndex<BigSlots>(3), // (0x6) SlotDebugData { name: "", ty: UInt<8> },
|
||||||
|
value: 0x6,
|
||||||
|
},
|
||||||
|
// at: module-XXXXXXXXXX.rs:5:1
|
||||||
|
1: Copy {
|
||||||
|
dest: StatePartIndex<BigSlots>(2), // (0x6) SlotDebugData { name: "InstantiatedModule(duplicate_names: duplicate_names).duplicate_names::w", ty: UInt<8> },
|
||||||
|
src: StatePartIndex<BigSlots>(3), // (0x6) SlotDebugData { name: "", ty: UInt<8> },
|
||||||
|
},
|
||||||
|
// at: module-XXXXXXXXXX.rs:1:1
|
||||||
|
2: Const {
|
||||||
|
dest: StatePartIndex<BigSlots>(1), // (0x5) SlotDebugData { name: "", ty: UInt<8> },
|
||||||
|
value: 0x5,
|
||||||
|
},
|
||||||
|
// at: module-XXXXXXXXXX.rs:3:1
|
||||||
|
3: Copy {
|
||||||
|
dest: StatePartIndex<BigSlots>(0), // (0x5) SlotDebugData { name: "InstantiatedModule(duplicate_names: duplicate_names).duplicate_names::w", ty: UInt<8> },
|
||||||
|
src: StatePartIndex<BigSlots>(1), // (0x5) SlotDebugData { name: "", ty: UInt<8> },
|
||||||
|
},
|
||||||
|
// at: module-XXXXXXXXXX.rs:1:1
|
||||||
|
4: Return,
|
||||||
|
],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
pc: 4,
|
||||||
|
memory_write_log: [],
|
||||||
|
memories: StatePart {
|
||||||
|
value: [],
|
||||||
|
},
|
||||||
|
small_slots: StatePart {
|
||||||
|
value: [],
|
||||||
|
},
|
||||||
|
big_slots: StatePart {
|
||||||
|
value: [
|
||||||
|
5,
|
||||||
|
5,
|
||||||
|
6,
|
||||||
|
6,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
io: Instance {
|
||||||
|
name: <simulator>::duplicate_names,
|
||||||
|
instantiated: Module {
|
||||||
|
name: duplicate_names,
|
||||||
|
..
|
||||||
|
},
|
||||||
|
},
|
||||||
|
uninitialized_inputs: {},
|
||||||
|
io_targets: {},
|
||||||
|
made_initial_step: true,
|
||||||
|
needs_settle: false,
|
||||||
|
trace_decls: TraceModule {
|
||||||
|
name: "duplicate_names",
|
||||||
|
children: [
|
||||||
|
TraceWire {
|
||||||
|
name: "w",
|
||||||
|
child: TraceUInt {
|
||||||
|
location: TraceScalarId(0),
|
||||||
|
name: "w",
|
||||||
|
ty: UInt<8>,
|
||||||
|
flow: Duplex,
|
||||||
|
},
|
||||||
|
ty: UInt<8>,
|
||||||
|
},
|
||||||
|
TraceWire {
|
||||||
|
name: "w",
|
||||||
|
child: TraceUInt {
|
||||||
|
location: TraceScalarId(1),
|
||||||
|
name: "w",
|
||||||
|
ty: UInt<8>,
|
||||||
|
flow: Duplex,
|
||||||
|
},
|
||||||
|
ty: UInt<8>,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
traces: [
|
||||||
|
SimTrace {
|
||||||
|
id: TraceScalarId(0),
|
||||||
|
kind: BigUInt {
|
||||||
|
index: StatePartIndex<BigSlots>(0),
|
||||||
|
ty: UInt<8>,
|
||||||
|
},
|
||||||
|
state: 0x05,
|
||||||
|
last_state: 0x05,
|
||||||
|
},
|
||||||
|
SimTrace {
|
||||||
|
id: TraceScalarId(1),
|
||||||
|
kind: BigUInt {
|
||||||
|
index: StatePartIndex<BigSlots>(2),
|
||||||
|
ty: UInt<8>,
|
||||||
|
},
|
||||||
|
state: 0x06,
|
||||||
|
last_state: 0x06,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
trace_memories: {},
|
||||||
|
trace_writers: [
|
||||||
|
Running(
|
||||||
|
VcdWriter {
|
||||||
|
finished_init: true,
|
||||||
|
timescale: 1 ps,
|
||||||
|
..
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
instant: 1 μs,
|
||||||
|
clocks_triggered: [],
|
||||||
|
..
|
||||||
|
}
|
11
crates/fayalite/tests/sim/expected/duplicate_names.vcd
Normal file
11
crates/fayalite/tests/sim/expected/duplicate_names.vcd
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
$timescale 1 ps $end
|
||||||
|
$scope module duplicate_names $end
|
||||||
|
$var wire 8 ! w $end
|
||||||
|
$var wire 8 " w_2 $end
|
||||||
|
$upscope $end
|
||||||
|
$enddefinitions $end
|
||||||
|
$dumpvars
|
||||||
|
b101 !
|
||||||
|
b110 "
|
||||||
|
$end
|
||||||
|
#1000000
|
1994
crates/fayalite/tests/sim/expected/enums.txt
Normal file
1994
crates/fayalite/tests/sim/expected/enums.txt
Normal file
File diff suppressed because it is too large
Load diff
110
crates/fayalite/tests/sim/expected/enums.vcd
Normal file
110
crates/fayalite/tests/sim/expected/enums.vcd
Normal file
|
@ -0,0 +1,110 @@
|
||||||
|
$timescale 1 ps $end
|
||||||
|
$scope module enums $end
|
||||||
|
$scope struct cd $end
|
||||||
|
$var wire 1 ! clk $end
|
||||||
|
$var wire 1 " rst $end
|
||||||
|
$upscope $end
|
||||||
|
$var wire 1 # en $end
|
||||||
|
$var wire 2 $ which_in $end
|
||||||
|
$var wire 4 % data_in $end
|
||||||
|
$var wire 2 & which_out $end
|
||||||
|
$var wire 4 ' data_out $end
|
||||||
|
$scope struct b_out $end
|
||||||
|
$var string 1 ( \$tag $end
|
||||||
|
$scope struct HdlSome $end
|
||||||
|
$var wire 1 ) \0 $end
|
||||||
|
$var wire 1 * \1 $end
|
||||||
|
$upscope $end
|
||||||
|
$upscope $end
|
||||||
|
$scope struct the_reg $end
|
||||||
|
$var string 1 + \$tag $end
|
||||||
|
$scope struct B $end
|
||||||
|
$var reg 1 , \0 $end
|
||||||
|
$var reg 1 - \1 $end
|
||||||
|
$upscope $end
|
||||||
|
$scope struct C $end
|
||||||
|
$scope struct a $end
|
||||||
|
$var reg 1 . \[0] $end
|
||||||
|
$var reg 1 / \[1] $end
|
||||||
|
$upscope $end
|
||||||
|
$var reg 2 0 b $end
|
||||||
|
$upscope $end
|
||||||
|
$upscope $end
|
||||||
|
$upscope $end
|
||||||
|
$enddefinitions $end
|
||||||
|
$dumpvars
|
||||||
|
0!
|
||||||
|
1"
|
||||||
|
0#
|
||||||
|
b0 $
|
||||||
|
b0 %
|
||||||
|
b0 &
|
||||||
|
b0 '
|
||||||
|
sHdlNone\x20(0) (
|
||||||
|
0)
|
||||||
|
0*
|
||||||
|
sA\x20(0) +
|
||||||
|
0,
|
||||||
|
0-
|
||||||
|
0.
|
||||||
|
0/
|
||||||
|
b0 0
|
||||||
|
$end
|
||||||
|
#1000000
|
||||||
|
1!
|
||||||
|
#1100000
|
||||||
|
0"
|
||||||
|
#2000000
|
||||||
|
0!
|
||||||
|
#3000000
|
||||||
|
1!
|
||||||
|
#4000000
|
||||||
|
1#
|
||||||
|
b1 $
|
||||||
|
0!
|
||||||
|
#5000000
|
||||||
|
1!
|
||||||
|
b1 &
|
||||||
|
sHdlSome\x20(1) (
|
||||||
|
sB\x20(1) +
|
||||||
|
#6000000
|
||||||
|
0#
|
||||||
|
b0 $
|
||||||
|
0!
|
||||||
|
#7000000
|
||||||
|
1!
|
||||||
|
#8000000
|
||||||
|
1#
|
||||||
|
b1 $
|
||||||
|
b1111 %
|
||||||
|
0!
|
||||||
|
#9000000
|
||||||
|
1!
|
||||||
|
b11 '
|
||||||
|
1)
|
||||||
|
1*
|
||||||
|
1,
|
||||||
|
1-
|
||||||
|
1.
|
||||||
|
1/
|
||||||
|
#10000000
|
||||||
|
0!
|
||||||
|
#11000000
|
||||||
|
1!
|
||||||
|
#12000000
|
||||||
|
b10 $
|
||||||
|
0!
|
||||||
|
#13000000
|
||||||
|
1!
|
||||||
|
b10 &
|
||||||
|
b1111 '
|
||||||
|
sHdlNone\x20(0) (
|
||||||
|
0)
|
||||||
|
0*
|
||||||
|
sC\x20(2) +
|
||||||
|
b11 0
|
||||||
|
#14000000
|
||||||
|
0!
|
||||||
|
#15000000
|
||||||
|
1!
|
||||||
|
#16000000
|
2776
crates/fayalite/tests/sim/expected/memories.txt
Normal file
2776
crates/fayalite/tests/sim/expected/memories.txt
Normal file
File diff suppressed because it is too large
Load diff
408
crates/fayalite/tests/sim/expected/memories.vcd
Normal file
408
crates/fayalite/tests/sim/expected/memories.vcd
Normal file
|
@ -0,0 +1,408 @@
|
||||||
|
$timescale 1 ps $end
|
||||||
|
$scope module memories $end
|
||||||
|
$scope struct r $end
|
||||||
|
$var wire 4 ! addr $end
|
||||||
|
$var wire 1 " en $end
|
||||||
|
$var wire 1 # clk $end
|
||||||
|
$scope struct data $end
|
||||||
|
$var wire 8 $ \0 $end
|
||||||
|
$var wire 8 % \1 $end
|
||||||
|
$upscope $end
|
||||||
|
$upscope $end
|
||||||
|
$scope struct w $end
|
||||||
|
$var wire 4 & addr $end
|
||||||
|
$var wire 1 ' en $end
|
||||||
|
$var wire 1 ( clk $end
|
||||||
|
$scope struct data $end
|
||||||
|
$var wire 8 ) \0 $end
|
||||||
|
$var wire 8 * \1 $end
|
||||||
|
$upscope $end
|
||||||
|
$scope struct mask $end
|
||||||
|
$var wire 1 + \0 $end
|
||||||
|
$var wire 1 , \1 $end
|
||||||
|
$upscope $end
|
||||||
|
$upscope $end
|
||||||
|
$scope struct mem $end
|
||||||
|
$scope struct contents $end
|
||||||
|
$scope struct \[0] $end
|
||||||
|
$scope struct mem $end
|
||||||
|
$var reg 8 9 \0 $end
|
||||||
|
$var reg 8 I \1 $end
|
||||||
|
$upscope $end
|
||||||
|
$upscope $end
|
||||||
|
$scope struct \[1] $end
|
||||||
|
$scope struct mem $end
|
||||||
|
$var reg 8 : \0 $end
|
||||||
|
$var reg 8 J \1 $end
|
||||||
|
$upscope $end
|
||||||
|
$upscope $end
|
||||||
|
$scope struct \[2] $end
|
||||||
|
$scope struct mem $end
|
||||||
|
$var reg 8 ; \0 $end
|
||||||
|
$var reg 8 K \1 $end
|
||||||
|
$upscope $end
|
||||||
|
$upscope $end
|
||||||
|
$scope struct \[3] $end
|
||||||
|
$scope struct mem $end
|
||||||
|
$var reg 8 < \0 $end
|
||||||
|
$var reg 8 L \1 $end
|
||||||
|
$upscope $end
|
||||||
|
$upscope $end
|
||||||
|
$scope struct \[4] $end
|
||||||
|
$scope struct mem $end
|
||||||
|
$var reg 8 = \0 $end
|
||||||
|
$var reg 8 M \1 $end
|
||||||
|
$upscope $end
|
||||||
|
$upscope $end
|
||||||
|
$scope struct \[5] $end
|
||||||
|
$scope struct mem $end
|
||||||
|
$var reg 8 > \0 $end
|
||||||
|
$var reg 8 N \1 $end
|
||||||
|
$upscope $end
|
||||||
|
$upscope $end
|
||||||
|
$scope struct \[6] $end
|
||||||
|
$scope struct mem $end
|
||||||
|
$var reg 8 ? \0 $end
|
||||||
|
$var reg 8 O \1 $end
|
||||||
|
$upscope $end
|
||||||
|
$upscope $end
|
||||||
|
$scope struct \[7] $end
|
||||||
|
$scope struct mem $end
|
||||||
|
$var reg 8 @ \0 $end
|
||||||
|
$var reg 8 P \1 $end
|
||||||
|
$upscope $end
|
||||||
|
$upscope $end
|
||||||
|
$scope struct \[8] $end
|
||||||
|
$scope struct mem $end
|
||||||
|
$var reg 8 A \0 $end
|
||||||
|
$var reg 8 Q \1 $end
|
||||||
|
$upscope $end
|
||||||
|
$upscope $end
|
||||||
|
$scope struct \[9] $end
|
||||||
|
$scope struct mem $end
|
||||||
|
$var reg 8 B \0 $end
|
||||||
|
$var reg 8 R \1 $end
|
||||||
|
$upscope $end
|
||||||
|
$upscope $end
|
||||||
|
$scope struct \[10] $end
|
||||||
|
$scope struct mem $end
|
||||||
|
$var reg 8 C \0 $end
|
||||||
|
$var reg 8 S \1 $end
|
||||||
|
$upscope $end
|
||||||
|
$upscope $end
|
||||||
|
$scope struct \[11] $end
|
||||||
|
$scope struct mem $end
|
||||||
|
$var reg 8 D \0 $end
|
||||||
|
$var reg 8 T \1 $end
|
||||||
|
$upscope $end
|
||||||
|
$upscope $end
|
||||||
|
$scope struct \[12] $end
|
||||||
|
$scope struct mem $end
|
||||||
|
$var reg 8 E \0 $end
|
||||||
|
$var reg 8 U \1 $end
|
||||||
|
$upscope $end
|
||||||
|
$upscope $end
|
||||||
|
$scope struct \[13] $end
|
||||||
|
$scope struct mem $end
|
||||||
|
$var reg 8 F \0 $end
|
||||||
|
$var reg 8 V \1 $end
|
||||||
|
$upscope $end
|
||||||
|
$upscope $end
|
||||||
|
$scope struct \[14] $end
|
||||||
|
$scope struct mem $end
|
||||||
|
$var reg 8 G \0 $end
|
||||||
|
$var reg 8 W \1 $end
|
||||||
|
$upscope $end
|
||||||
|
$upscope $end
|
||||||
|
$scope struct \[15] $end
|
||||||
|
$scope struct mem $end
|
||||||
|
$var reg 8 H \0 $end
|
||||||
|
$var reg 8 X \1 $end
|
||||||
|
$upscope $end
|
||||||
|
$upscope $end
|
||||||
|
$upscope $end
|
||||||
|
$scope struct r0 $end
|
||||||
|
$var wire 4 - addr $end
|
||||||
|
$var wire 1 . en $end
|
||||||
|
$var wire 1 / clk $end
|
||||||
|
$scope struct data $end
|
||||||
|
$var wire 8 0 \0 $end
|
||||||
|
$var wire 8 1 \1 $end
|
||||||
|
$upscope $end
|
||||||
|
$upscope $end
|
||||||
|
$scope struct w1 $end
|
||||||
|
$var wire 4 2 addr $end
|
||||||
|
$var wire 1 3 en $end
|
||||||
|
$var wire 1 4 clk $end
|
||||||
|
$scope struct data $end
|
||||||
|
$var wire 8 5 \0 $end
|
||||||
|
$var wire 8 6 \1 $end
|
||||||
|
$upscope $end
|
||||||
|
$scope struct mask $end
|
||||||
|
$var wire 1 7 \0 $end
|
||||||
|
$var wire 1 8 \1 $end
|
||||||
|
$upscope $end
|
||||||
|
$upscope $end
|
||||||
|
$upscope $end
|
||||||
|
$upscope $end
|
||||||
|
$enddefinitions $end
|
||||||
|
$dumpvars
|
||||||
|
b1 9
|
||||||
|
b100011 I
|
||||||
|
b1 :
|
||||||
|
b100011 J
|
||||||
|
b1 ;
|
||||||
|
b100011 K
|
||||||
|
b1 <
|
||||||
|
b100011 L
|
||||||
|
b1 =
|
||||||
|
b100011 M
|
||||||
|
b1 >
|
||||||
|
b100011 N
|
||||||
|
b1 ?
|
||||||
|
b100011 O
|
||||||
|
b1 @
|
||||||
|
b100011 P
|
||||||
|
b1 A
|
||||||
|
b100011 Q
|
||||||
|
b1 B
|
||||||
|
b100011 R
|
||||||
|
b1 C
|
||||||
|
b100011 S
|
||||||
|
b1 D
|
||||||
|
b100011 T
|
||||||
|
b1 E
|
||||||
|
b100011 U
|
||||||
|
b1 F
|
||||||
|
b100011 V
|
||||||
|
b1 G
|
||||||
|
b100011 W
|
||||||
|
b1 H
|
||||||
|
b100011 X
|
||||||
|
b0 !
|
||||||
|
0"
|
||||||
|
0#
|
||||||
|
b0 $
|
||||||
|
b0 %
|
||||||
|
b0 &
|
||||||
|
0'
|
||||||
|
0(
|
||||||
|
b0 )
|
||||||
|
b0 *
|
||||||
|
0+
|
||||||
|
0,
|
||||||
|
b0 -
|
||||||
|
0.
|
||||||
|
0/
|
||||||
|
b0 0
|
||||||
|
b0 1
|
||||||
|
b0 2
|
||||||
|
03
|
||||||
|
04
|
||||||
|
b0 5
|
||||||
|
b0 6
|
||||||
|
07
|
||||||
|
08
|
||||||
|
$end
|
||||||
|
#1000000
|
||||||
|
1#
|
||||||
|
1(
|
||||||
|
1/
|
||||||
|
14
|
||||||
|
#2000000
|
||||||
|
1"
|
||||||
|
0#
|
||||||
|
b1 $
|
||||||
|
b100011 %
|
||||||
|
1'
|
||||||
|
0(
|
||||||
|
b10000 )
|
||||||
|
b100000 *
|
||||||
|
1+
|
||||||
|
1,
|
||||||
|
1.
|
||||||
|
0/
|
||||||
|
b1 0
|
||||||
|
b100011 1
|
||||||
|
13
|
||||||
|
04
|
||||||
|
b10000 5
|
||||||
|
b100000 6
|
||||||
|
17
|
||||||
|
18
|
||||||
|
#3000000
|
||||||
|
b10000 9
|
||||||
|
b100000 I
|
||||||
|
1#
|
||||||
|
1(
|
||||||
|
1/
|
||||||
|
14
|
||||||
|
b10000 $
|
||||||
|
b100000 %
|
||||||
|
b10000 0
|
||||||
|
b100000 1
|
||||||
|
#4000000
|
||||||
|
0#
|
||||||
|
0(
|
||||||
|
b110000 )
|
||||||
|
b1000000 *
|
||||||
|
0+
|
||||||
|
0/
|
||||||
|
04
|
||||||
|
b110000 5
|
||||||
|
b1000000 6
|
||||||
|
07
|
||||||
|
#5000000
|
||||||
|
b10000 9
|
||||||
|
b1000000 I
|
||||||
|
1#
|
||||||
|
1(
|
||||||
|
1/
|
||||||
|
14
|
||||||
|
b1000000 %
|
||||||
|
b1000000 1
|
||||||
|
#6000000
|
||||||
|
0#
|
||||||
|
0(
|
||||||
|
b1010000 )
|
||||||
|
b1100000 *
|
||||||
|
1+
|
||||||
|
0,
|
||||||
|
0/
|
||||||
|
04
|
||||||
|
b1010000 5
|
||||||
|
b1100000 6
|
||||||
|
17
|
||||||
|
08
|
||||||
|
#7000000
|
||||||
|
b1010000 9
|
||||||
|
b1000000 I
|
||||||
|
1#
|
||||||
|
1(
|
||||||
|
1/
|
||||||
|
14
|
||||||
|
b1010000 $
|
||||||
|
b1010000 0
|
||||||
|
#8000000
|
||||||
|
0#
|
||||||
|
0(
|
||||||
|
b1110000 )
|
||||||
|
b10000000 *
|
||||||
|
0+
|
||||||
|
0/
|
||||||
|
04
|
||||||
|
b1110000 5
|
||||||
|
b10000000 6
|
||||||
|
07
|
||||||
|
#9000000
|
||||||
|
1#
|
||||||
|
1(
|
||||||
|
1/
|
||||||
|
14
|
||||||
|
#10000000
|
||||||
|
0#
|
||||||
|
0'
|
||||||
|
0(
|
||||||
|
b10010000 )
|
||||||
|
b10100000 *
|
||||||
|
0/
|
||||||
|
03
|
||||||
|
04
|
||||||
|
b10010000 5
|
||||||
|
b10100000 6
|
||||||
|
#11000000
|
||||||
|
1#
|
||||||
|
1(
|
||||||
|
1/
|
||||||
|
14
|
||||||
|
#12000000
|
||||||
|
0#
|
||||||
|
b1 &
|
||||||
|
1'
|
||||||
|
0(
|
||||||
|
1+
|
||||||
|
1,
|
||||||
|
0/
|
||||||
|
b1 2
|
||||||
|
13
|
||||||
|
04
|
||||||
|
17
|
||||||
|
18
|
||||||
|
#13000000
|
||||||
|
b10010000 :
|
||||||
|
b10100000 J
|
||||||
|
1#
|
||||||
|
1(
|
||||||
|
1/
|
||||||
|
14
|
||||||
|
#14000000
|
||||||
|
0#
|
||||||
|
b10 &
|
||||||
|
0(
|
||||||
|
b10110000 )
|
||||||
|
b11000000 *
|
||||||
|
0/
|
||||||
|
b10 2
|
||||||
|
04
|
||||||
|
b10110000 5
|
||||||
|
b11000000 6
|
||||||
|
#15000000
|
||||||
|
b10110000 ;
|
||||||
|
b11000000 K
|
||||||
|
1#
|
||||||
|
1(
|
||||||
|
1/
|
||||||
|
14
|
||||||
|
#16000000
|
||||||
|
0#
|
||||||
|
0'
|
||||||
|
0(
|
||||||
|
b11010000 )
|
||||||
|
b11100000 *
|
||||||
|
0/
|
||||||
|
03
|
||||||
|
04
|
||||||
|
b11010000 5
|
||||||
|
b11100000 6
|
||||||
|
#17000000
|
||||||
|
1#
|
||||||
|
1(
|
||||||
|
1/
|
||||||
|
14
|
||||||
|
#18000000
|
||||||
|
b1 !
|
||||||
|
0#
|
||||||
|
b10010000 $
|
||||||
|
b10100000 %
|
||||||
|
0(
|
||||||
|
b1 -
|
||||||
|
0/
|
||||||
|
b10010000 0
|
||||||
|
b10100000 1
|
||||||
|
04
|
||||||
|
#19000000
|
||||||
|
1#
|
||||||
|
1(
|
||||||
|
1/
|
||||||
|
14
|
||||||
|
#20000000
|
||||||
|
b10 !
|
||||||
|
0#
|
||||||
|
b10110000 $
|
||||||
|
b11000000 %
|
||||||
|
0(
|
||||||
|
b10 -
|
||||||
|
0/
|
||||||
|
b10110000 0
|
||||||
|
b11000000 1
|
||||||
|
04
|
||||||
|
#21000000
|
||||||
|
1#
|
||||||
|
1(
|
||||||
|
1/
|
||||||
|
14
|
||||||
|
#22000000
|
||||||
|
0#
|
||||||
|
0(
|
||||||
|
0/
|
||||||
|
04
|
1694
crates/fayalite/tests/sim/expected/memories2.txt
Normal file
1694
crates/fayalite/tests/sim/expected/memories2.txt
Normal file
File diff suppressed because it is too large
Load diff
363
crates/fayalite/tests/sim/expected/memories2.vcd
Normal file
363
crates/fayalite/tests/sim/expected/memories2.vcd
Normal file
|
@ -0,0 +1,363 @@
|
||||||
|
$timescale 1 ps $end
|
||||||
|
$scope module memories2 $end
|
||||||
|
$scope struct rw $end
|
||||||
|
$var wire 3 ! addr $end
|
||||||
|
$var wire 1 " en $end
|
||||||
|
$var wire 1 # clk $end
|
||||||
|
$var wire 2 $ rdata $end
|
||||||
|
$var wire 1 % wmode $end
|
||||||
|
$var wire 2 & wdata $end
|
||||||
|
$var wire 1 ' wmask $end
|
||||||
|
$upscope $end
|
||||||
|
$scope struct mem $end
|
||||||
|
$scope struct contents $end
|
||||||
|
$scope struct \[0] $end
|
||||||
|
$scope struct mem $end
|
||||||
|
$var string 1 1 \$tag $end
|
||||||
|
$var reg 1 6 HdlSome $end
|
||||||
|
$upscope $end
|
||||||
|
$upscope $end
|
||||||
|
$scope struct \[1] $end
|
||||||
|
$scope struct mem $end
|
||||||
|
$var string 1 2 \$tag $end
|
||||||
|
$var reg 1 7 HdlSome $end
|
||||||
|
$upscope $end
|
||||||
|
$upscope $end
|
||||||
|
$scope struct \[2] $end
|
||||||
|
$scope struct mem $end
|
||||||
|
$var string 1 3 \$tag $end
|
||||||
|
$var reg 1 8 HdlSome $end
|
||||||
|
$upscope $end
|
||||||
|
$upscope $end
|
||||||
|
$scope struct \[3] $end
|
||||||
|
$scope struct mem $end
|
||||||
|
$var string 1 4 \$tag $end
|
||||||
|
$var reg 1 9 HdlSome $end
|
||||||
|
$upscope $end
|
||||||
|
$upscope $end
|
||||||
|
$scope struct \[4] $end
|
||||||
|
$scope struct mem $end
|
||||||
|
$var string 1 5 \$tag $end
|
||||||
|
$var reg 1 : HdlSome $end
|
||||||
|
$upscope $end
|
||||||
|
$upscope $end
|
||||||
|
$upscope $end
|
||||||
|
$scope struct rw0 $end
|
||||||
|
$var wire 3 ( addr $end
|
||||||
|
$var wire 1 ) en $end
|
||||||
|
$var wire 1 * clk $end
|
||||||
|
$scope struct rdata $end
|
||||||
|
$var string 1 + \$tag $end
|
||||||
|
$var wire 1 , HdlSome $end
|
||||||
|
$upscope $end
|
||||||
|
$var wire 1 - wmode $end
|
||||||
|
$scope struct wdata $end
|
||||||
|
$var string 1 . \$tag $end
|
||||||
|
$var wire 1 / HdlSome $end
|
||||||
|
$upscope $end
|
||||||
|
$var wire 1 0 wmask $end
|
||||||
|
$upscope $end
|
||||||
|
$upscope $end
|
||||||
|
$upscope $end
|
||||||
|
$enddefinitions $end
|
||||||
|
$dumpvars
|
||||||
|
sHdlSome\x20(1) 1
|
||||||
|
16
|
||||||
|
sHdlSome\x20(1) 2
|
||||||
|
17
|
||||||
|
sHdlSome\x20(1) 3
|
||||||
|
18
|
||||||
|
sHdlSome\x20(1) 4
|
||||||
|
19
|
||||||
|
sHdlSome\x20(1) 5
|
||||||
|
1:
|
||||||
|
b0 !
|
||||||
|
0"
|
||||||
|
0#
|
||||||
|
b0 $
|
||||||
|
0%
|
||||||
|
b0 &
|
||||||
|
0'
|
||||||
|
b0 (
|
||||||
|
0)
|
||||||
|
0*
|
||||||
|
sHdlNone\x20(0) +
|
||||||
|
0,
|
||||||
|
0-
|
||||||
|
sHdlNone\x20(0) .
|
||||||
|
0/
|
||||||
|
00
|
||||||
|
$end
|
||||||
|
#250000
|
||||||
|
1#
|
||||||
|
1*
|
||||||
|
#500000
|
||||||
|
#750000
|
||||||
|
0#
|
||||||
|
0*
|
||||||
|
#1000000
|
||||||
|
1"
|
||||||
|
1)
|
||||||
|
#1250000
|
||||||
|
1#
|
||||||
|
1*
|
||||||
|
b11 $
|
||||||
|
sHdlSome\x20(1) +
|
||||||
|
1,
|
||||||
|
#1500000
|
||||||
|
#1750000
|
||||||
|
0#
|
||||||
|
0*
|
||||||
|
#2000000
|
||||||
|
0"
|
||||||
|
0)
|
||||||
|
#2250000
|
||||||
|
1#
|
||||||
|
1*
|
||||||
|
b0 $
|
||||||
|
sHdlNone\x20(0) +
|
||||||
|
0,
|
||||||
|
#2500000
|
||||||
|
#2750000
|
||||||
|
0#
|
||||||
|
0*
|
||||||
|
#3000000
|
||||||
|
1"
|
||||||
|
1%
|
||||||
|
1'
|
||||||
|
1)
|
||||||
|
1-
|
||||||
|
10
|
||||||
|
#3250000
|
||||||
|
sHdlNone\x20(0) 1
|
||||||
|
06
|
||||||
|
1#
|
||||||
|
1*
|
||||||
|
#3500000
|
||||||
|
#3750000
|
||||||
|
0#
|
||||||
|
0*
|
||||||
|
#4000000
|
||||||
|
0%
|
||||||
|
0'
|
||||||
|
0-
|
||||||
|
00
|
||||||
|
#4250000
|
||||||
|
1#
|
||||||
|
1*
|
||||||
|
#4500000
|
||||||
|
#4750000
|
||||||
|
0#
|
||||||
|
0*
|
||||||
|
#5000000
|
||||||
|
1%
|
||||||
|
b11 &
|
||||||
|
1-
|
||||||
|
sHdlSome\x20(1) .
|
||||||
|
1/
|
||||||
|
#5250000
|
||||||
|
1#
|
||||||
|
1*
|
||||||
|
#5500000
|
||||||
|
#5750000
|
||||||
|
0#
|
||||||
|
0*
|
||||||
|
#6000000
|
||||||
|
b1 !
|
||||||
|
b1 &
|
||||||
|
1'
|
||||||
|
b1 (
|
||||||
|
0/
|
||||||
|
10
|
||||||
|
#6250000
|
||||||
|
sHdlSome\x20(1) 2
|
||||||
|
07
|
||||||
|
1#
|
||||||
|
1*
|
||||||
|
#6500000
|
||||||
|
#6750000
|
||||||
|
0#
|
||||||
|
0*
|
||||||
|
#7000000
|
||||||
|
b10 !
|
||||||
|
b10 &
|
||||||
|
b10 (
|
||||||
|
sHdlNone\x20(0) .
|
||||||
|
#7250000
|
||||||
|
sHdlNone\x20(0) 3
|
||||||
|
08
|
||||||
|
1#
|
||||||
|
1*
|
||||||
|
#7500000
|
||||||
|
#7750000
|
||||||
|
0#
|
||||||
|
0*
|
||||||
|
#8000000
|
||||||
|
b11 !
|
||||||
|
b11 &
|
||||||
|
b11 (
|
||||||
|
sHdlSome\x20(1) .
|
||||||
|
1/
|
||||||
|
#8250000
|
||||||
|
sHdlSome\x20(1) 4
|
||||||
|
19
|
||||||
|
1#
|
||||||
|
1*
|
||||||
|
#8500000
|
||||||
|
#8750000
|
||||||
|
0#
|
||||||
|
0*
|
||||||
|
#9000000
|
||||||
|
b100 !
|
||||||
|
b10 &
|
||||||
|
b100 (
|
||||||
|
sHdlNone\x20(0) .
|
||||||
|
0/
|
||||||
|
#9250000
|
||||||
|
sHdlNone\x20(0) 5
|
||||||
|
0:
|
||||||
|
1#
|
||||||
|
1*
|
||||||
|
#9500000
|
||||||
|
#9750000
|
||||||
|
0#
|
||||||
|
0*
|
||||||
|
#10000000
|
||||||
|
b101 !
|
||||||
|
b1 &
|
||||||
|
b101 (
|
||||||
|
sHdlSome\x20(1) .
|
||||||
|
#10250000
|
||||||
|
1#
|
||||||
|
1*
|
||||||
|
#10500000
|
||||||
|
#10750000
|
||||||
|
0#
|
||||||
|
0*
|
||||||
|
#11000000
|
||||||
|
b110 !
|
||||||
|
b110 (
|
||||||
|
#11250000
|
||||||
|
1#
|
||||||
|
1*
|
||||||
|
#11500000
|
||||||
|
#11750000
|
||||||
|
0#
|
||||||
|
0*
|
||||||
|
#12000000
|
||||||
|
b111 !
|
||||||
|
b111 (
|
||||||
|
#12250000
|
||||||
|
1#
|
||||||
|
1*
|
||||||
|
#12500000
|
||||||
|
#12750000
|
||||||
|
0#
|
||||||
|
0*
|
||||||
|
#13000000
|
||||||
|
0%
|
||||||
|
b0 &
|
||||||
|
0'
|
||||||
|
0-
|
||||||
|
sHdlNone\x20(0) .
|
||||||
|
00
|
||||||
|
#13250000
|
||||||
|
1#
|
||||||
|
1*
|
||||||
|
#13500000
|
||||||
|
#13750000
|
||||||
|
0#
|
||||||
|
0*
|
||||||
|
#14000000
|
||||||
|
b110 !
|
||||||
|
b110 (
|
||||||
|
#14250000
|
||||||
|
1#
|
||||||
|
1*
|
||||||
|
#14500000
|
||||||
|
#14750000
|
||||||
|
0#
|
||||||
|
0*
|
||||||
|
#15000000
|
||||||
|
b101 !
|
||||||
|
b101 (
|
||||||
|
#15250000
|
||||||
|
1#
|
||||||
|
1*
|
||||||
|
#15500000
|
||||||
|
#15750000
|
||||||
|
0#
|
||||||
|
0*
|
||||||
|
#16000000
|
||||||
|
b100 !
|
||||||
|
b100 (
|
||||||
|
#16250000
|
||||||
|
1#
|
||||||
|
1*
|
||||||
|
#16500000
|
||||||
|
#16750000
|
||||||
|
0#
|
||||||
|
0*
|
||||||
|
#17000000
|
||||||
|
b11 !
|
||||||
|
b11 (
|
||||||
|
#17250000
|
||||||
|
1#
|
||||||
|
1*
|
||||||
|
b11 $
|
||||||
|
sHdlSome\x20(1) +
|
||||||
|
1,
|
||||||
|
#17500000
|
||||||
|
#17750000
|
||||||
|
0#
|
||||||
|
0*
|
||||||
|
#18000000
|
||||||
|
b10 !
|
||||||
|
b10 (
|
||||||
|
#18250000
|
||||||
|
1#
|
||||||
|
1*
|
||||||
|
b0 $
|
||||||
|
sHdlNone\x20(0) +
|
||||||
|
0,
|
||||||
|
#18500000
|
||||||
|
#18750000
|
||||||
|
0#
|
||||||
|
0*
|
||||||
|
#19000000
|
||||||
|
b0 !
|
||||||
|
b0 (
|
||||||
|
#19250000
|
||||||
|
1#
|
||||||
|
1*
|
||||||
|
#19500000
|
||||||
|
#19750000
|
||||||
|
0#
|
||||||
|
0*
|
||||||
|
#20000000
|
||||||
|
b1 !
|
||||||
|
b1 (
|
||||||
|
#20250000
|
||||||
|
1#
|
||||||
|
1*
|
||||||
|
b1 $
|
||||||
|
sHdlSome\x20(1) +
|
||||||
|
#20500000
|
||||||
|
#20750000
|
||||||
|
0#
|
||||||
|
0*
|
||||||
|
#21000000
|
||||||
|
b0 !
|
||||||
|
0"
|
||||||
|
b0 (
|
||||||
|
0)
|
||||||
|
#21250000
|
||||||
|
1#
|
||||||
|
1*
|
||||||
|
b0 $
|
||||||
|
sHdlNone\x20(0) +
|
||||||
|
#21500000
|
||||||
|
#21750000
|
||||||
|
0#
|
||||||
|
0*
|
||||||
|
#22000000
|
4882
crates/fayalite/tests/sim/expected/memories3.txt
Normal file
4882
crates/fayalite/tests/sim/expected/memories3.txt
Normal file
File diff suppressed because it is too large
Load diff
836
crates/fayalite/tests/sim/expected/memories3.vcd
Normal file
836
crates/fayalite/tests/sim/expected/memories3.vcd
Normal file
|
@ -0,0 +1,836 @@
|
||||||
|
$timescale 1 ps $end
|
||||||
|
$scope module memories3 $end
|
||||||
|
$scope struct r $end
|
||||||
|
$var wire 3 ! addr $end
|
||||||
|
$var wire 1 " en $end
|
||||||
|
$var wire 1 # clk $end
|
||||||
|
$scope struct data $end
|
||||||
|
$var wire 8 $ \[0] $end
|
||||||
|
$var wire 8 % \[1] $end
|
||||||
|
$var wire 8 & \[2] $end
|
||||||
|
$var wire 8 ' \[3] $end
|
||||||
|
$var wire 8 ( \[4] $end
|
||||||
|
$var wire 8 ) \[5] $end
|
||||||
|
$var wire 8 * \[6] $end
|
||||||
|
$var wire 8 + \[7] $end
|
||||||
|
$upscope $end
|
||||||
|
$upscope $end
|
||||||
|
$scope struct w $end
|
||||||
|
$var wire 3 , addr $end
|
||||||
|
$var wire 1 - en $end
|
||||||
|
$var wire 1 . clk $end
|
||||||
|
$scope struct data $end
|
||||||
|
$var wire 8 / \[0] $end
|
||||||
|
$var wire 8 0 \[1] $end
|
||||||
|
$var wire 8 1 \[2] $end
|
||||||
|
$var wire 8 2 \[3] $end
|
||||||
|
$var wire 8 3 \[4] $end
|
||||||
|
$var wire 8 4 \[5] $end
|
||||||
|
$var wire 8 5 \[6] $end
|
||||||
|
$var wire 8 6 \[7] $end
|
||||||
|
$upscope $end
|
||||||
|
$scope struct mask $end
|
||||||
|
$var wire 1 7 \[0] $end
|
||||||
|
$var wire 1 8 \[1] $end
|
||||||
|
$var wire 1 9 \[2] $end
|
||||||
|
$var wire 1 : \[3] $end
|
||||||
|
$var wire 1 ; \[4] $end
|
||||||
|
$var wire 1 < \[5] $end
|
||||||
|
$var wire 1 = \[6] $end
|
||||||
|
$var wire 1 > \[7] $end
|
||||||
|
$upscope $end
|
||||||
|
$upscope $end
|
||||||
|
$scope struct mem $end
|
||||||
|
$scope struct contents $end
|
||||||
|
$scope struct \[0] $end
|
||||||
|
$scope struct mem $end
|
||||||
|
$var reg 8 ] \[0] $end
|
||||||
|
$var reg 8 e \[1] $end
|
||||||
|
$var reg 8 m \[2] $end
|
||||||
|
$var reg 8 u \[3] $end
|
||||||
|
$var reg 8 } \[4] $end
|
||||||
|
$var reg 8 '" \[5] $end
|
||||||
|
$var reg 8 /" \[6] $end
|
||||||
|
$var reg 8 7" \[7] $end
|
||||||
|
$upscope $end
|
||||||
|
$upscope $end
|
||||||
|
$scope struct \[1] $end
|
||||||
|
$scope struct mem $end
|
||||||
|
$var reg 8 ^ \[0] $end
|
||||||
|
$var reg 8 f \[1] $end
|
||||||
|
$var reg 8 n \[2] $end
|
||||||
|
$var reg 8 v \[3] $end
|
||||||
|
$var reg 8 ~ \[4] $end
|
||||||
|
$var reg 8 (" \[5] $end
|
||||||
|
$var reg 8 0" \[6] $end
|
||||||
|
$var reg 8 8" \[7] $end
|
||||||
|
$upscope $end
|
||||||
|
$upscope $end
|
||||||
|
$scope struct \[2] $end
|
||||||
|
$scope struct mem $end
|
||||||
|
$var reg 8 _ \[0] $end
|
||||||
|
$var reg 8 g \[1] $end
|
||||||
|
$var reg 8 o \[2] $end
|
||||||
|
$var reg 8 w \[3] $end
|
||||||
|
$var reg 8 !" \[4] $end
|
||||||
|
$var reg 8 )" \[5] $end
|
||||||
|
$var reg 8 1" \[6] $end
|
||||||
|
$var reg 8 9" \[7] $end
|
||||||
|
$upscope $end
|
||||||
|
$upscope $end
|
||||||
|
$scope struct \[3] $end
|
||||||
|
$scope struct mem $end
|
||||||
|
$var reg 8 ` \[0] $end
|
||||||
|
$var reg 8 h \[1] $end
|
||||||
|
$var reg 8 p \[2] $end
|
||||||
|
$var reg 8 x \[3] $end
|
||||||
|
$var reg 8 "" \[4] $end
|
||||||
|
$var reg 8 *" \[5] $end
|
||||||
|
$var reg 8 2" \[6] $end
|
||||||
|
$var reg 8 :" \[7] $end
|
||||||
|
$upscope $end
|
||||||
|
$upscope $end
|
||||||
|
$scope struct \[4] $end
|
||||||
|
$scope struct mem $end
|
||||||
|
$var reg 8 a \[0] $end
|
||||||
|
$var reg 8 i \[1] $end
|
||||||
|
$var reg 8 q \[2] $end
|
||||||
|
$var reg 8 y \[3] $end
|
||||||
|
$var reg 8 #" \[4] $end
|
||||||
|
$var reg 8 +" \[5] $end
|
||||||
|
$var reg 8 3" \[6] $end
|
||||||
|
$var reg 8 ;" \[7] $end
|
||||||
|
$upscope $end
|
||||||
|
$upscope $end
|
||||||
|
$scope struct \[5] $end
|
||||||
|
$scope struct mem $end
|
||||||
|
$var reg 8 b \[0] $end
|
||||||
|
$var reg 8 j \[1] $end
|
||||||
|
$var reg 8 r \[2] $end
|
||||||
|
$var reg 8 z \[3] $end
|
||||||
|
$var reg 8 $" \[4] $end
|
||||||
|
$var reg 8 ," \[5] $end
|
||||||
|
$var reg 8 4" \[6] $end
|
||||||
|
$var reg 8 <" \[7] $end
|
||||||
|
$upscope $end
|
||||||
|
$upscope $end
|
||||||
|
$scope struct \[6] $end
|
||||||
|
$scope struct mem $end
|
||||||
|
$var reg 8 c \[0] $end
|
||||||
|
$var reg 8 k \[1] $end
|
||||||
|
$var reg 8 s \[2] $end
|
||||||
|
$var reg 8 { \[3] $end
|
||||||
|
$var reg 8 %" \[4] $end
|
||||||
|
$var reg 8 -" \[5] $end
|
||||||
|
$var reg 8 5" \[6] $end
|
||||||
|
$var reg 8 =" \[7] $end
|
||||||
|
$upscope $end
|
||||||
|
$upscope $end
|
||||||
|
$scope struct \[7] $end
|
||||||
|
$scope struct mem $end
|
||||||
|
$var reg 8 d \[0] $end
|
||||||
|
$var reg 8 l \[1] $end
|
||||||
|
$var reg 8 t \[2] $end
|
||||||
|
$var reg 8 | \[3] $end
|
||||||
|
$var reg 8 &" \[4] $end
|
||||||
|
$var reg 8 ." \[5] $end
|
||||||
|
$var reg 8 6" \[6] $end
|
||||||
|
$var reg 8 >" \[7] $end
|
||||||
|
$upscope $end
|
||||||
|
$upscope $end
|
||||||
|
$upscope $end
|
||||||
|
$scope struct r0 $end
|
||||||
|
$var wire 3 ? addr $end
|
||||||
|
$var wire 1 @ en $end
|
||||||
|
$var wire 1 A clk $end
|
||||||
|
$scope struct data $end
|
||||||
|
$var wire 8 B \[0] $end
|
||||||
|
$var wire 8 C \[1] $end
|
||||||
|
$var wire 8 D \[2] $end
|
||||||
|
$var wire 8 E \[3] $end
|
||||||
|
$var wire 8 F \[4] $end
|
||||||
|
$var wire 8 G \[5] $end
|
||||||
|
$var wire 8 H \[6] $end
|
||||||
|
$var wire 8 I \[7] $end
|
||||||
|
$upscope $end
|
||||||
|
$upscope $end
|
||||||
|
$scope struct w1 $end
|
||||||
|
$var wire 3 J addr $end
|
||||||
|
$var wire 1 K en $end
|
||||||
|
$var wire 1 L clk $end
|
||||||
|
$scope struct data $end
|
||||||
|
$var wire 8 M \[0] $end
|
||||||
|
$var wire 8 N \[1] $end
|
||||||
|
$var wire 8 O \[2] $end
|
||||||
|
$var wire 8 P \[3] $end
|
||||||
|
$var wire 8 Q \[4] $end
|
||||||
|
$var wire 8 R \[5] $end
|
||||||
|
$var wire 8 S \[6] $end
|
||||||
|
$var wire 8 T \[7] $end
|
||||||
|
$upscope $end
|
||||||
|
$scope struct mask $end
|
||||||
|
$var wire 1 U \[0] $end
|
||||||
|
$var wire 1 V \[1] $end
|
||||||
|
$var wire 1 W \[2] $end
|
||||||
|
$var wire 1 X \[3] $end
|
||||||
|
$var wire 1 Y \[4] $end
|
||||||
|
$var wire 1 Z \[5] $end
|
||||||
|
$var wire 1 [ \[6] $end
|
||||||
|
$var wire 1 \ \[7] $end
|
||||||
|
$upscope $end
|
||||||
|
$upscope $end
|
||||||
|
$upscope $end
|
||||||
|
$upscope $end
|
||||||
|
$enddefinitions $end
|
||||||
|
$dumpvars
|
||||||
|
b0 ]
|
||||||
|
b0 e
|
||||||
|
b0 m
|
||||||
|
b0 u
|
||||||
|
b0 }
|
||||||
|
b0 '"
|
||||||
|
b0 /"
|
||||||
|
b0 7"
|
||||||
|
b0 ^
|
||||||
|
b0 f
|
||||||
|
b0 n
|
||||||
|
b0 v
|
||||||
|
b0 ~
|
||||||
|
b0 ("
|
||||||
|
b0 0"
|
||||||
|
b0 8"
|
||||||
|
b0 _
|
||||||
|
b0 g
|
||||||
|
b0 o
|
||||||
|
b0 w
|
||||||
|
b0 !"
|
||||||
|
b0 )"
|
||||||
|
b0 1"
|
||||||
|
b0 9"
|
||||||
|
b0 `
|
||||||
|
b0 h
|
||||||
|
b0 p
|
||||||
|
b0 x
|
||||||
|
b0 ""
|
||||||
|
b0 *"
|
||||||
|
b0 2"
|
||||||
|
b0 :"
|
||||||
|
b0 a
|
||||||
|
b0 i
|
||||||
|
b0 q
|
||||||
|
b0 y
|
||||||
|
b0 #"
|
||||||
|
b0 +"
|
||||||
|
b0 3"
|
||||||
|
b0 ;"
|
||||||
|
b0 b
|
||||||
|
b0 j
|
||||||
|
b0 r
|
||||||
|
b0 z
|
||||||
|
b0 $"
|
||||||
|
b0 ,"
|
||||||
|
b0 4"
|
||||||
|
b0 <"
|
||||||
|
b0 c
|
||||||
|
b0 k
|
||||||
|
b0 s
|
||||||
|
b0 {
|
||||||
|
b0 %"
|
||||||
|
b0 -"
|
||||||
|
b0 5"
|
||||||
|
b0 ="
|
||||||
|
b0 d
|
||||||
|
b0 l
|
||||||
|
b0 t
|
||||||
|
b0 |
|
||||||
|
b0 &"
|
||||||
|
b0 ."
|
||||||
|
b0 6"
|
||||||
|
b0 >"
|
||||||
|
b0 !
|
||||||
|
0"
|
||||||
|
0#
|
||||||
|
b0 $
|
||||||
|
b0 %
|
||||||
|
b0 &
|
||||||
|
b0 '
|
||||||
|
b0 (
|
||||||
|
b0 )
|
||||||
|
b0 *
|
||||||
|
b0 +
|
||||||
|
b0 ,
|
||||||
|
1-
|
||||||
|
0.
|
||||||
|
b10010 /
|
||||||
|
b110100 0
|
||||||
|
b1010110 1
|
||||||
|
b1111000 2
|
||||||
|
b10011010 3
|
||||||
|
b10111100 4
|
||||||
|
b11011110 5
|
||||||
|
b11110000 6
|
||||||
|
07
|
||||||
|
18
|
||||||
|
09
|
||||||
|
1:
|
||||||
|
1;
|
||||||
|
0<
|
||||||
|
0=
|
||||||
|
1>
|
||||||
|
b0 ?
|
||||||
|
0@
|
||||||
|
0A
|
||||||
|
b0 B
|
||||||
|
b0 C
|
||||||
|
b0 D
|
||||||
|
b0 E
|
||||||
|
b0 F
|
||||||
|
b0 G
|
||||||
|
b0 H
|
||||||
|
b0 I
|
||||||
|
b0 J
|
||||||
|
1K
|
||||||
|
0L
|
||||||
|
b10010 M
|
||||||
|
b110100 N
|
||||||
|
b1010110 O
|
||||||
|
b1111000 P
|
||||||
|
b10011010 Q
|
||||||
|
b10111100 R
|
||||||
|
b11011110 S
|
||||||
|
b11110000 T
|
||||||
|
0U
|
||||||
|
1V
|
||||||
|
0W
|
||||||
|
1X
|
||||||
|
1Y
|
||||||
|
0Z
|
||||||
|
0[
|
||||||
|
1\
|
||||||
|
$end
|
||||||
|
#250000
|
||||||
|
1#
|
||||||
|
1.
|
||||||
|
1A
|
||||||
|
1L
|
||||||
|
#500000
|
||||||
|
#750000
|
||||||
|
0#
|
||||||
|
0.
|
||||||
|
0A
|
||||||
|
0L
|
||||||
|
#1000000
|
||||||
|
1"
|
||||||
|
b1 ,
|
||||||
|
0-
|
||||||
|
b0 /
|
||||||
|
b0 0
|
||||||
|
b0 1
|
||||||
|
b0 2
|
||||||
|
b0 3
|
||||||
|
b0 4
|
||||||
|
b0 5
|
||||||
|
b0 6
|
||||||
|
08
|
||||||
|
0:
|
||||||
|
0;
|
||||||
|
0>
|
||||||
|
1@
|
||||||
|
b1 J
|
||||||
|
0K
|
||||||
|
b0 M
|
||||||
|
b0 N
|
||||||
|
b0 O
|
||||||
|
b0 P
|
||||||
|
b0 Q
|
||||||
|
b0 R
|
||||||
|
b0 S
|
||||||
|
b0 T
|
||||||
|
0V
|
||||||
|
0X
|
||||||
|
0Y
|
||||||
|
0\
|
||||||
|
#1250000
|
||||||
|
b0 ]
|
||||||
|
b110100 e
|
||||||
|
b0 m
|
||||||
|
b1111000 u
|
||||||
|
b10011010 }
|
||||||
|
b0 '"
|
||||||
|
b0 /"
|
||||||
|
b11110000 7"
|
||||||
|
1#
|
||||||
|
1.
|
||||||
|
1A
|
||||||
|
1L
|
||||||
|
#1500000
|
||||||
|
#1750000
|
||||||
|
0#
|
||||||
|
0.
|
||||||
|
0A
|
||||||
|
0L
|
||||||
|
#2000000
|
||||||
|
#2250000
|
||||||
|
1#
|
||||||
|
1.
|
||||||
|
1A
|
||||||
|
1L
|
||||||
|
#2500000
|
||||||
|
#2750000
|
||||||
|
0#
|
||||||
|
0.
|
||||||
|
0A
|
||||||
|
0L
|
||||||
|
#3000000
|
||||||
|
b0 ,
|
||||||
|
1-
|
||||||
|
b11111110 /
|
||||||
|
b11011100 0
|
||||||
|
b10111010 1
|
||||||
|
b10011000 2
|
||||||
|
b1110110 3
|
||||||
|
b1010100 4
|
||||||
|
b110010 5
|
||||||
|
b10000 6
|
||||||
|
17
|
||||||
|
18
|
||||||
|
19
|
||||||
|
1:
|
||||||
|
1;
|
||||||
|
1<
|
||||||
|
1=
|
||||||
|
1>
|
||||||
|
b0 J
|
||||||
|
1K
|
||||||
|
b11111110 M
|
||||||
|
b11011100 N
|
||||||
|
b10111010 O
|
||||||
|
b10011000 P
|
||||||
|
b1110110 Q
|
||||||
|
b1010100 R
|
||||||
|
b110010 S
|
||||||
|
b10000 T
|
||||||
|
1U
|
||||||
|
1V
|
||||||
|
1W
|
||||||
|
1X
|
||||||
|
1Y
|
||||||
|
1Z
|
||||||
|
1[
|
||||||
|
1\
|
||||||
|
#3250000
|
||||||
|
1#
|
||||||
|
1.
|
||||||
|
1A
|
||||||
|
b110100 C
|
||||||
|
b1111000 E
|
||||||
|
b10011010 F
|
||||||
|
b11110000 I
|
||||||
|
1L
|
||||||
|
b110100 %
|
||||||
|
b1111000 '
|
||||||
|
b10011010 (
|
||||||
|
b11110000 +
|
||||||
|
#3500000
|
||||||
|
#3750000
|
||||||
|
0#
|
||||||
|
0.
|
||||||
|
0A
|
||||||
|
0L
|
||||||
|
#4000000
|
||||||
|
#4250000
|
||||||
|
b11111110 ]
|
||||||
|
b11011100 e
|
||||||
|
b10111010 m
|
||||||
|
b10011000 u
|
||||||
|
b1110110 }
|
||||||
|
b1010100 '"
|
||||||
|
b110010 /"
|
||||||
|
b10000 7"
|
||||||
|
1#
|
||||||
|
1.
|
||||||
|
1A
|
||||||
|
1L
|
||||||
|
#4500000
|
||||||
|
#4750000
|
||||||
|
0#
|
||||||
|
0.
|
||||||
|
0A
|
||||||
|
0L
|
||||||
|
#5000000
|
||||||
|
#5250000
|
||||||
|
b11111110 ]
|
||||||
|
b11011100 e
|
||||||
|
b10111010 m
|
||||||
|
b10011000 u
|
||||||
|
b1110110 }
|
||||||
|
b1010100 '"
|
||||||
|
b110010 /"
|
||||||
|
b10000 7"
|
||||||
|
1#
|
||||||
|
1.
|
||||||
|
1A
|
||||||
|
1L
|
||||||
|
#5500000
|
||||||
|
#5750000
|
||||||
|
0#
|
||||||
|
0.
|
||||||
|
0A
|
||||||
|
0L
|
||||||
|
#6000000
|
||||||
|
0"
|
||||||
|
b1 ,
|
||||||
|
b10011 /
|
||||||
|
b1010111 0
|
||||||
|
b10011011 1
|
||||||
|
b11011111 2
|
||||||
|
b10 3
|
||||||
|
b1000110 4
|
||||||
|
b10001010 5
|
||||||
|
b11001110 6
|
||||||
|
0@
|
||||||
|
b1 J
|
||||||
|
b10011 M
|
||||||
|
b1010111 N
|
||||||
|
b10011011 O
|
||||||
|
b11011111 P
|
||||||
|
b10 Q
|
||||||
|
b1000110 R
|
||||||
|
b10001010 S
|
||||||
|
b11001110 T
|
||||||
|
#6250000
|
||||||
|
b11111110 ]
|
||||||
|
b11011100 e
|
||||||
|
b10111010 m
|
||||||
|
b10011000 u
|
||||||
|
b1110110 }
|
||||||
|
b1010100 '"
|
||||||
|
b110010 /"
|
||||||
|
b10000 7"
|
||||||
|
1#
|
||||||
|
1.
|
||||||
|
1A
|
||||||
|
b11111110 B
|
||||||
|
b11011100 C
|
||||||
|
b10111010 D
|
||||||
|
b10011000 E
|
||||||
|
b1110110 F
|
||||||
|
b1010100 G
|
||||||
|
b110010 H
|
||||||
|
b10000 I
|
||||||
|
1L
|
||||||
|
b11111110 $
|
||||||
|
b11011100 %
|
||||||
|
b10111010 &
|
||||||
|
b10011000 '
|
||||||
|
b1110110 (
|
||||||
|
b1010100 )
|
||||||
|
b110010 *
|
||||||
|
b10000 +
|
||||||
|
#6500000
|
||||||
|
#6750000
|
||||||
|
0#
|
||||||
|
0.
|
||||||
|
0A
|
||||||
|
0L
|
||||||
|
#7000000
|
||||||
|
b10 ,
|
||||||
|
b1110100 /
|
||||||
|
b1100101 0
|
||||||
|
b1110011 1
|
||||||
|
b1110100 2
|
||||||
|
b1101001 3
|
||||||
|
b1101110 4
|
||||||
|
b1100111 5
|
||||||
|
b100001 6
|
||||||
|
b10 J
|
||||||
|
b1110100 M
|
||||||
|
b1100101 N
|
||||||
|
b1110011 O
|
||||||
|
b1110100 P
|
||||||
|
b1101001 Q
|
||||||
|
b1101110 R
|
||||||
|
b1100111 S
|
||||||
|
b100001 T
|
||||||
|
#7250000
|
||||||
|
b10011 ^
|
||||||
|
b1010111 f
|
||||||
|
b10011011 n
|
||||||
|
b11011111 v
|
||||||
|
b10 ~
|
||||||
|
b1000110 ("
|
||||||
|
b10001010 0"
|
||||||
|
b11001110 8"
|
||||||
|
1#
|
||||||
|
1.
|
||||||
|
1A
|
||||||
|
b0 B
|
||||||
|
b0 C
|
||||||
|
b0 D
|
||||||
|
b0 E
|
||||||
|
b0 F
|
||||||
|
b0 G
|
||||||
|
b0 H
|
||||||
|
b0 I
|
||||||
|
1L
|
||||||
|
b0 $
|
||||||
|
b0 %
|
||||||
|
b0 &
|
||||||
|
b0 '
|
||||||
|
b0 (
|
||||||
|
b0 )
|
||||||
|
b0 *
|
||||||
|
b0 +
|
||||||
|
#7500000
|
||||||
|
#7750000
|
||||||
|
0#
|
||||||
|
0.
|
||||||
|
0A
|
||||||
|
0L
|
||||||
|
#8000000
|
||||||
|
b11 ,
|
||||||
|
b1101101 /
|
||||||
|
b1101111 0
|
||||||
|
b1110010 1
|
||||||
|
b1100101 2
|
||||||
|
b100000 3
|
||||||
|
b1110100 4
|
||||||
|
b1110011 5
|
||||||
|
b1110100 6
|
||||||
|
b11 J
|
||||||
|
b1101101 M
|
||||||
|
b1101111 N
|
||||||
|
b1110010 O
|
||||||
|
b1100101 P
|
||||||
|
b100000 Q
|
||||||
|
b1110100 R
|
||||||
|
b1110011 S
|
||||||
|
b1110100 T
|
||||||
|
#8250000
|
||||||
|
b1110100 _
|
||||||
|
b1100101 g
|
||||||
|
b1110011 o
|
||||||
|
b1110100 w
|
||||||
|
b1101001 !"
|
||||||
|
b1101110 )"
|
||||||
|
b1100111 1"
|
||||||
|
b100001 9"
|
||||||
|
1#
|
||||||
|
1.
|
||||||
|
1A
|
||||||
|
1L
|
||||||
|
#8500000
|
||||||
|
#8750000
|
||||||
|
0#
|
||||||
|
0.
|
||||||
|
0A
|
||||||
|
0L
|
||||||
|
#9000000
|
||||||
|
1"
|
||||||
|
b0 ,
|
||||||
|
0-
|
||||||
|
b0 /
|
||||||
|
b0 0
|
||||||
|
b0 1
|
||||||
|
b0 2
|
||||||
|
b0 3
|
||||||
|
b0 4
|
||||||
|
b0 5
|
||||||
|
b0 6
|
||||||
|
07
|
||||||
|
08
|
||||||
|
09
|
||||||
|
0:
|
||||||
|
0;
|
||||||
|
0<
|
||||||
|
0=
|
||||||
|
0>
|
||||||
|
1@
|
||||||
|
b0 J
|
||||||
|
0K
|
||||||
|
b0 M
|
||||||
|
b0 N
|
||||||
|
b0 O
|
||||||
|
b0 P
|
||||||
|
b0 Q
|
||||||
|
b0 R
|
||||||
|
b0 S
|
||||||
|
b0 T
|
||||||
|
0U
|
||||||
|
0V
|
||||||
|
0W
|
||||||
|
0X
|
||||||
|
0Y
|
||||||
|
0Z
|
||||||
|
0[
|
||||||
|
0\
|
||||||
|
#9250000
|
||||||
|
b1101101 `
|
||||||
|
b1101111 h
|
||||||
|
b1110010 p
|
||||||
|
b1100101 x
|
||||||
|
b100000 ""
|
||||||
|
b1110100 *"
|
||||||
|
b1110011 2"
|
||||||
|
b1110100 :"
|
||||||
|
1#
|
||||||
|
1.
|
||||||
|
1A
|
||||||
|
1L
|
||||||
|
#9500000
|
||||||
|
#9750000
|
||||||
|
0#
|
||||||
|
0.
|
||||||
|
0A
|
||||||
|
0L
|
||||||
|
#10000000
|
||||||
|
b1 !
|
||||||
|
b1 ?
|
||||||
|
#10250000
|
||||||
|
1#
|
||||||
|
1.
|
||||||
|
1A
|
||||||
|
b11111110 B
|
||||||
|
b11011100 C
|
||||||
|
b10111010 D
|
||||||
|
b10011000 E
|
||||||
|
b1110110 F
|
||||||
|
b1010100 G
|
||||||
|
b110010 H
|
||||||
|
b10000 I
|
||||||
|
1L
|
||||||
|
b11111110 $
|
||||||
|
b11011100 %
|
||||||
|
b10111010 &
|
||||||
|
b10011000 '
|
||||||
|
b1110110 (
|
||||||
|
b1010100 )
|
||||||
|
b110010 *
|
||||||
|
b10000 +
|
||||||
|
#10500000
|
||||||
|
#10750000
|
||||||
|
0#
|
||||||
|
0.
|
||||||
|
0A
|
||||||
|
0L
|
||||||
|
#11000000
|
||||||
|
b10 !
|
||||||
|
b10 ?
|
||||||
|
#11250000
|
||||||
|
1#
|
||||||
|
1.
|
||||||
|
1A
|
||||||
|
b10011 B
|
||||||
|
b1010111 C
|
||||||
|
b10011011 D
|
||||||
|
b11011111 E
|
||||||
|
b10 F
|
||||||
|
b1000110 G
|
||||||
|
b10001010 H
|
||||||
|
b11001110 I
|
||||||
|
1L
|
||||||
|
b10011 $
|
||||||
|
b1010111 %
|
||||||
|
b10011011 &
|
||||||
|
b11011111 '
|
||||||
|
b10 (
|
||||||
|
b1000110 )
|
||||||
|
b10001010 *
|
||||||
|
b11001110 +
|
||||||
|
#11500000
|
||||||
|
#11750000
|
||||||
|
0#
|
||||||
|
0.
|
||||||
|
0A
|
||||||
|
0L
|
||||||
|
#12000000
|
||||||
|
b11 !
|
||||||
|
b11 ?
|
||||||
|
#12250000
|
||||||
|
1#
|
||||||
|
1.
|
||||||
|
1A
|
||||||
|
b1110100 B
|
||||||
|
b1100101 C
|
||||||
|
b1110011 D
|
||||||
|
b1110100 E
|
||||||
|
b1101001 F
|
||||||
|
b1101110 G
|
||||||
|
b1100111 H
|
||||||
|
b100001 I
|
||||||
|
1L
|
||||||
|
b1110100 $
|
||||||
|
b1100101 %
|
||||||
|
b1110011 &
|
||||||
|
b1110100 '
|
||||||
|
b1101001 (
|
||||||
|
b1101110 )
|
||||||
|
b1100111 *
|
||||||
|
b100001 +
|
||||||
|
#12500000
|
||||||
|
#12750000
|
||||||
|
0#
|
||||||
|
0.
|
||||||
|
0A
|
||||||
|
0L
|
||||||
|
#13000000
|
||||||
|
b0 !
|
||||||
|
0"
|
||||||
|
b0 ?
|
||||||
|
0@
|
||||||
|
#13250000
|
||||||
|
1#
|
||||||
|
1.
|
||||||
|
1A
|
||||||
|
b1101101 B
|
||||||
|
b1101111 C
|
||||||
|
b1110010 D
|
||||||
|
b1100101 E
|
||||||
|
b100000 F
|
||||||
|
b1110100 G
|
||||||
|
b1110011 H
|
||||||
|
b1110100 I
|
||||||
|
1L
|
||||||
|
b1101101 $
|
||||||
|
b1101111 %
|
||||||
|
b1110010 &
|
||||||
|
b1100101 '
|
||||||
|
b100000 (
|
||||||
|
b1110100 )
|
||||||
|
b1110011 *
|
||||||
|
b1110100 +
|
||||||
|
#13500000
|
||||||
|
#13750000
|
||||||
|
0#
|
||||||
|
0.
|
||||||
|
0A
|
||||||
|
0L
|
||||||
|
#14000000
|
||||||
|
#14250000
|
||||||
|
1#
|
||||||
|
1.
|
||||||
|
1A
|
||||||
|
b0 B
|
||||||
|
b0 C
|
||||||
|
b0 D
|
||||||
|
b0 E
|
||||||
|
b0 F
|
||||||
|
b0 G
|
||||||
|
b0 H
|
||||||
|
b0 I
|
||||||
|
1L
|
||||||
|
b0 $
|
||||||
|
b0 %
|
||||||
|
b0 &
|
||||||
|
b0 '
|
||||||
|
b0 (
|
||||||
|
b0 )
|
||||||
|
b0 *
|
||||||
|
b0 +
|
||||||
|
#14500000
|
||||||
|
#14750000
|
||||||
|
0#
|
||||||
|
0.
|
||||||
|
0A
|
||||||
|
0L
|
||||||
|
#15000000
|
810
crates/fayalite/tests/sim/expected/mod1.txt
Normal file
810
crates/fayalite/tests/sim/expected/mod1.txt
Normal file
|
@ -0,0 +1,810 @@
|
||||||
|
Simulation {
|
||||||
|
state: State {
|
||||||
|
insns: Insns {
|
||||||
|
state_layout: StateLayout {
|
||||||
|
ty: TypeLayout {
|
||||||
|
small_slots: StatePartLayout<SmallSlots> {
|
||||||
|
len: 0,
|
||||||
|
debug_data: [],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
big_slots: StatePartLayout<BigSlots> {
|
||||||
|
len: 17,
|
||||||
|
debug_data: [
|
||||||
|
SlotDebugData {
|
||||||
|
name: "InstantiatedModule(mod1: mod1).mod1::o.i",
|
||||||
|
ty: UInt<4>,
|
||||||
|
},
|
||||||
|
SlotDebugData {
|
||||||
|
name: "InstantiatedModule(mod1: mod1).mod1::o.o",
|
||||||
|
ty: SInt<2>,
|
||||||
|
},
|
||||||
|
SlotDebugData {
|
||||||
|
name: "InstantiatedModule(mod1: mod1).mod1::o.i2",
|
||||||
|
ty: SInt<2>,
|
||||||
|
},
|
||||||
|
SlotDebugData {
|
||||||
|
name: "InstantiatedModule(mod1: mod1).mod1::o.o2",
|
||||||
|
ty: UInt<4>,
|
||||||
|
},
|
||||||
|
SlotDebugData {
|
||||||
|
name: "InstantiatedModule(mod1: mod1).mod1::child.i",
|
||||||
|
ty: UInt<4>,
|
||||||
|
},
|
||||||
|
SlotDebugData {
|
||||||
|
name: "InstantiatedModule(mod1: mod1).mod1::child.o",
|
||||||
|
ty: SInt<2>,
|
||||||
|
},
|
||||||
|
SlotDebugData {
|
||||||
|
name: "InstantiatedModule(mod1: mod1).mod1::child.i2",
|
||||||
|
ty: SInt<2>,
|
||||||
|
},
|
||||||
|
SlotDebugData {
|
||||||
|
name: "InstantiatedModule(mod1: mod1).mod1::child.o2",
|
||||||
|
ty: UInt<4>,
|
||||||
|
},
|
||||||
|
SlotDebugData {
|
||||||
|
name: "InstantiatedModule(mod1.child: mod1_child).mod1_child::i",
|
||||||
|
ty: UInt<4>,
|
||||||
|
},
|
||||||
|
SlotDebugData {
|
||||||
|
name: "InstantiatedModule(mod1.child: mod1_child).mod1_child::o",
|
||||||
|
ty: SInt<2>,
|
||||||
|
},
|
||||||
|
SlotDebugData {
|
||||||
|
name: "InstantiatedModule(mod1.child: mod1_child).mod1_child::i2",
|
||||||
|
ty: SInt<2>,
|
||||||
|
},
|
||||||
|
SlotDebugData {
|
||||||
|
name: "InstantiatedModule(mod1.child: mod1_child).mod1_child::o2",
|
||||||
|
ty: UInt<4>,
|
||||||
|
},
|
||||||
|
SlotDebugData {
|
||||||
|
name: "",
|
||||||
|
ty: SInt<2>,
|
||||||
|
},
|
||||||
|
SlotDebugData {
|
||||||
|
name: "",
|
||||||
|
ty: UInt<4>,
|
||||||
|
},
|
||||||
|
SlotDebugData {
|
||||||
|
name: "",
|
||||||
|
ty: UInt<4>,
|
||||||
|
},
|
||||||
|
SlotDebugData {
|
||||||
|
name: "",
|
||||||
|
ty: Bool,
|
||||||
|
},
|
||||||
|
SlotDebugData {
|
||||||
|
name: "",
|
||||||
|
ty: UInt<4>,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
},
|
||||||
|
memories: StatePartLayout<Memories> {
|
||||||
|
len: 0,
|
||||||
|
debug_data: [],
|
||||||
|
layout_data: [],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
},
|
||||||
|
insns: [
|
||||||
|
// at: module-XXXXXXXXXX.rs:4:1
|
||||||
|
0: Copy {
|
||||||
|
dest: StatePartIndex<BigSlots>(6), // (-0x2) SlotDebugData { name: "InstantiatedModule(mod1: mod1).mod1::child.i2", ty: SInt<2> },
|
||||||
|
src: StatePartIndex<BigSlots>(2), // (-0x2) SlotDebugData { name: "InstantiatedModule(mod1: mod1).mod1::o.i2", ty: SInt<2> },
|
||||||
|
},
|
||||||
|
1: Copy {
|
||||||
|
dest: StatePartIndex<BigSlots>(4), // (0xa) SlotDebugData { name: "InstantiatedModule(mod1: mod1).mod1::child.i", ty: UInt<4> },
|
||||||
|
src: StatePartIndex<BigSlots>(0), // (0xa) SlotDebugData { name: "InstantiatedModule(mod1: mod1).mod1::o.i", ty: UInt<4> },
|
||||||
|
},
|
||||||
|
// at: module-XXXXXXXXXX.rs:2:1
|
||||||
|
2: Copy {
|
||||||
|
dest: StatePartIndex<BigSlots>(10), // (-0x2) SlotDebugData { name: "InstantiatedModule(mod1.child: mod1_child).mod1_child::i2", ty: SInt<2> },
|
||||||
|
src: StatePartIndex<BigSlots>(6), // (-0x2) SlotDebugData { name: "InstantiatedModule(mod1: mod1).mod1::child.i2", ty: SInt<2> },
|
||||||
|
},
|
||||||
|
3: Copy {
|
||||||
|
dest: StatePartIndex<BigSlots>(8), // (0xa) SlotDebugData { name: "InstantiatedModule(mod1.child: mod1_child).mod1_child::i", ty: UInt<4> },
|
||||||
|
src: StatePartIndex<BigSlots>(4), // (0xa) SlotDebugData { name: "InstantiatedModule(mod1: mod1).mod1::child.i", ty: UInt<4> },
|
||||||
|
},
|
||||||
|
// at: module-XXXXXXXXXX-2.rs:1:1
|
||||||
|
4: Const {
|
||||||
|
dest: StatePartIndex<BigSlots>(16), // (0xf) SlotDebugData { name: "", ty: UInt<4> },
|
||||||
|
value: 0xf,
|
||||||
|
},
|
||||||
|
5: Const {
|
||||||
|
dest: StatePartIndex<BigSlots>(14), // (0x5) SlotDebugData { name: "", ty: UInt<4> },
|
||||||
|
value: 0x5,
|
||||||
|
},
|
||||||
|
6: CmpLt {
|
||||||
|
dest: StatePartIndex<BigSlots>(15), // (0x1) SlotDebugData { name: "", ty: Bool },
|
||||||
|
lhs: StatePartIndex<BigSlots>(14), // (0x5) SlotDebugData { name: "", ty: UInt<4> },
|
||||||
|
rhs: StatePartIndex<BigSlots>(8), // (0xa) SlotDebugData { name: "InstantiatedModule(mod1.child: mod1_child).mod1_child::i", ty: UInt<4> },
|
||||||
|
},
|
||||||
|
7: CastToUInt {
|
||||||
|
dest: StatePartIndex<BigSlots>(13), // (0xe) SlotDebugData { name: "", ty: UInt<4> },
|
||||||
|
src: StatePartIndex<BigSlots>(10), // (-0x2) SlotDebugData { name: "InstantiatedModule(mod1.child: mod1_child).mod1_child::i2", ty: SInt<2> },
|
||||||
|
dest_width: 4,
|
||||||
|
},
|
||||||
|
// at: module-XXXXXXXXXX-2.rs:7:1
|
||||||
|
8: Copy {
|
||||||
|
dest: StatePartIndex<BigSlots>(11), // (0xf) SlotDebugData { name: "InstantiatedModule(mod1.child: mod1_child).mod1_child::o2", ty: UInt<4> },
|
||||||
|
src: StatePartIndex<BigSlots>(13), // (0xe) SlotDebugData { name: "", ty: UInt<4> },
|
||||||
|
},
|
||||||
|
// at: module-XXXXXXXXXX-2.rs:8:1
|
||||||
|
9: BranchIfZero {
|
||||||
|
target: 11,
|
||||||
|
value: StatePartIndex<BigSlots>(15), // (0x1) SlotDebugData { name: "", ty: Bool },
|
||||||
|
},
|
||||||
|
// at: module-XXXXXXXXXX-2.rs:9:1
|
||||||
|
10: Copy {
|
||||||
|
dest: StatePartIndex<BigSlots>(11), // (0xf) SlotDebugData { name: "InstantiatedModule(mod1.child: mod1_child).mod1_child::o2", ty: UInt<4> },
|
||||||
|
src: StatePartIndex<BigSlots>(16), // (0xf) SlotDebugData { name: "", ty: UInt<4> },
|
||||||
|
},
|
||||||
|
// at: module-XXXXXXXXXX.rs:2:1
|
||||||
|
11: Copy {
|
||||||
|
dest: StatePartIndex<BigSlots>(7), // (0xf) SlotDebugData { name: "InstantiatedModule(mod1: mod1).mod1::child.o2", ty: UInt<4> },
|
||||||
|
src: StatePartIndex<BigSlots>(11), // (0xf) SlotDebugData { name: "InstantiatedModule(mod1.child: mod1_child).mod1_child::o2", ty: UInt<4> },
|
||||||
|
},
|
||||||
|
// at: module-XXXXXXXXXX.rs:4:1
|
||||||
|
12: Copy {
|
||||||
|
dest: StatePartIndex<BigSlots>(3), // (0xf) SlotDebugData { name: "InstantiatedModule(mod1: mod1).mod1::o.o2", ty: UInt<4> },
|
||||||
|
src: StatePartIndex<BigSlots>(7), // (0xf) SlotDebugData { name: "InstantiatedModule(mod1: mod1).mod1::child.o2", ty: UInt<4> },
|
||||||
|
},
|
||||||
|
// at: module-XXXXXXXXXX-2.rs:1:1
|
||||||
|
13: CastToSInt {
|
||||||
|
dest: StatePartIndex<BigSlots>(12), // (-0x2) SlotDebugData { name: "", ty: SInt<2> },
|
||||||
|
src: StatePartIndex<BigSlots>(8), // (0xa) SlotDebugData { name: "InstantiatedModule(mod1.child: mod1_child).mod1_child::i", ty: UInt<4> },
|
||||||
|
dest_width: 2,
|
||||||
|
},
|
||||||
|
// at: module-XXXXXXXXXX-2.rs:6:1
|
||||||
|
14: Copy {
|
||||||
|
dest: StatePartIndex<BigSlots>(9), // (-0x2) SlotDebugData { name: "InstantiatedModule(mod1.child: mod1_child).mod1_child::o", ty: SInt<2> },
|
||||||
|
src: StatePartIndex<BigSlots>(12), // (-0x2) SlotDebugData { name: "", ty: SInt<2> },
|
||||||
|
},
|
||||||
|
// at: module-XXXXXXXXXX.rs:2:1
|
||||||
|
15: Copy {
|
||||||
|
dest: StatePartIndex<BigSlots>(5), // (-0x2) SlotDebugData { name: "InstantiatedModule(mod1: mod1).mod1::child.o", ty: SInt<2> },
|
||||||
|
src: StatePartIndex<BigSlots>(9), // (-0x2) SlotDebugData { name: "InstantiatedModule(mod1.child: mod1_child).mod1_child::o", ty: SInt<2> },
|
||||||
|
},
|
||||||
|
// at: module-XXXXXXXXXX.rs:4:1
|
||||||
|
16: Copy {
|
||||||
|
dest: StatePartIndex<BigSlots>(1), // (-0x2) SlotDebugData { name: "InstantiatedModule(mod1: mod1).mod1::o.o", ty: SInt<2> },
|
||||||
|
src: StatePartIndex<BigSlots>(5), // (-0x2) SlotDebugData { name: "InstantiatedModule(mod1: mod1).mod1::child.o", ty: SInt<2> },
|
||||||
|
},
|
||||||
|
// at: module-XXXXXXXXXX.rs:1:1
|
||||||
|
17: Return,
|
||||||
|
],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
pc: 17,
|
||||||
|
memory_write_log: [],
|
||||||
|
memories: StatePart {
|
||||||
|
value: [],
|
||||||
|
},
|
||||||
|
small_slots: StatePart {
|
||||||
|
value: [],
|
||||||
|
},
|
||||||
|
big_slots: StatePart {
|
||||||
|
value: [
|
||||||
|
10,
|
||||||
|
-2,
|
||||||
|
-2,
|
||||||
|
15,
|
||||||
|
10,
|
||||||
|
-2,
|
||||||
|
-2,
|
||||||
|
15,
|
||||||
|
10,
|
||||||
|
-2,
|
||||||
|
-2,
|
||||||
|
15,
|
||||||
|
-2,
|
||||||
|
14,
|
||||||
|
5,
|
||||||
|
1,
|
||||||
|
15,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
io: Instance {
|
||||||
|
name: <simulator>::mod1,
|
||||||
|
instantiated: Module {
|
||||||
|
name: mod1,
|
||||||
|
..
|
||||||
|
},
|
||||||
|
},
|
||||||
|
uninitialized_inputs: {},
|
||||||
|
io_targets: {
|
||||||
|
Instance {
|
||||||
|
name: <simulator>::mod1,
|
||||||
|
instantiated: Module {
|
||||||
|
name: mod1,
|
||||||
|
..
|
||||||
|
},
|
||||||
|
}.o: CompiledValue {
|
||||||
|
layout: CompiledTypeLayout {
|
||||||
|
ty: Bundle {
|
||||||
|
#[hdl(flip)] /* offset = 0 */
|
||||||
|
i: UInt<4>,
|
||||||
|
/* offset = 4 */
|
||||||
|
o: SInt<2>,
|
||||||
|
#[hdl(flip)] /* offset = 6 */
|
||||||
|
i2: SInt<2>,
|
||||||
|
/* offset = 8 */
|
||||||
|
o2: UInt<4>,
|
||||||
|
},
|
||||||
|
layout: TypeLayout {
|
||||||
|
small_slots: StatePartLayout<SmallSlots> {
|
||||||
|
len: 0,
|
||||||
|
debug_data: [],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
big_slots: StatePartLayout<BigSlots> {
|
||||||
|
len: 4,
|
||||||
|
debug_data: [
|
||||||
|
SlotDebugData {
|
||||||
|
name: "InstantiatedModule(mod1: mod1).mod1::o.i",
|
||||||
|
ty: UInt<4>,
|
||||||
|
},
|
||||||
|
SlotDebugData {
|
||||||
|
name: "InstantiatedModule(mod1: mod1).mod1::o.o",
|
||||||
|
ty: SInt<2>,
|
||||||
|
},
|
||||||
|
SlotDebugData {
|
||||||
|
name: "InstantiatedModule(mod1: mod1).mod1::o.i2",
|
||||||
|
ty: SInt<2>,
|
||||||
|
},
|
||||||
|
SlotDebugData {
|
||||||
|
name: "InstantiatedModule(mod1: mod1).mod1::o.o2",
|
||||||
|
ty: UInt<4>,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
},
|
||||||
|
body: Bundle {
|
||||||
|
fields: [
|
||||||
|
CompiledBundleField {
|
||||||
|
offset: TypeIndex {
|
||||||
|
small_slots: StatePartIndex<SmallSlots>(0),
|
||||||
|
big_slots: StatePartIndex<BigSlots>(0),
|
||||||
|
},
|
||||||
|
ty: CompiledTypeLayout {
|
||||||
|
ty: UInt<4>,
|
||||||
|
layout: TypeLayout {
|
||||||
|
small_slots: StatePartLayout<SmallSlots> {
|
||||||
|
len: 0,
|
||||||
|
debug_data: [],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
big_slots: StatePartLayout<BigSlots> {
|
||||||
|
len: 1,
|
||||||
|
debug_data: [
|
||||||
|
SlotDebugData {
|
||||||
|
name: "",
|
||||||
|
ty: UInt<4>,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
},
|
||||||
|
body: Scalar,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
CompiledBundleField {
|
||||||
|
offset: TypeIndex {
|
||||||
|
small_slots: StatePartIndex<SmallSlots>(0),
|
||||||
|
big_slots: StatePartIndex<BigSlots>(1),
|
||||||
|
},
|
||||||
|
ty: CompiledTypeLayout {
|
||||||
|
ty: SInt<2>,
|
||||||
|
layout: TypeLayout {
|
||||||
|
small_slots: StatePartLayout<SmallSlots> {
|
||||||
|
len: 0,
|
||||||
|
debug_data: [],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
big_slots: StatePartLayout<BigSlots> {
|
||||||
|
len: 1,
|
||||||
|
debug_data: [
|
||||||
|
SlotDebugData {
|
||||||
|
name: "",
|
||||||
|
ty: SInt<2>,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
},
|
||||||
|
body: Scalar,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
CompiledBundleField {
|
||||||
|
offset: TypeIndex {
|
||||||
|
small_slots: StatePartIndex<SmallSlots>(0),
|
||||||
|
big_slots: StatePartIndex<BigSlots>(2),
|
||||||
|
},
|
||||||
|
ty: CompiledTypeLayout {
|
||||||
|
ty: SInt<2>,
|
||||||
|
layout: TypeLayout {
|
||||||
|
small_slots: StatePartLayout<SmallSlots> {
|
||||||
|
len: 0,
|
||||||
|
debug_data: [],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
big_slots: StatePartLayout<BigSlots> {
|
||||||
|
len: 1,
|
||||||
|
debug_data: [
|
||||||
|
SlotDebugData {
|
||||||
|
name: "",
|
||||||
|
ty: SInt<2>,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
},
|
||||||
|
body: Scalar,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
CompiledBundleField {
|
||||||
|
offset: TypeIndex {
|
||||||
|
small_slots: StatePartIndex<SmallSlots>(0),
|
||||||
|
big_slots: StatePartIndex<BigSlots>(3),
|
||||||
|
},
|
||||||
|
ty: CompiledTypeLayout {
|
||||||
|
ty: UInt<4>,
|
||||||
|
layout: TypeLayout {
|
||||||
|
small_slots: StatePartLayout<SmallSlots> {
|
||||||
|
len: 0,
|
||||||
|
debug_data: [],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
big_slots: StatePartLayout<BigSlots> {
|
||||||
|
len: 1,
|
||||||
|
debug_data: [
|
||||||
|
SlotDebugData {
|
||||||
|
name: "",
|
||||||
|
ty: UInt<4>,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
},
|
||||||
|
body: Scalar,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
range: TypeIndexRange {
|
||||||
|
small_slots: StatePartIndexRange<SmallSlots> { start: 0, len: 0 },
|
||||||
|
big_slots: StatePartIndexRange<BigSlots> { start: 0, len: 4 },
|
||||||
|
},
|
||||||
|
write: None,
|
||||||
|
},
|
||||||
|
Instance {
|
||||||
|
name: <simulator>::mod1,
|
||||||
|
instantiated: Module {
|
||||||
|
name: mod1,
|
||||||
|
..
|
||||||
|
},
|
||||||
|
}.o.i: CompiledValue {
|
||||||
|
layout: CompiledTypeLayout {
|
||||||
|
ty: UInt<4>,
|
||||||
|
layout: TypeLayout {
|
||||||
|
small_slots: StatePartLayout<SmallSlots> {
|
||||||
|
len: 0,
|
||||||
|
debug_data: [],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
big_slots: StatePartLayout<BigSlots> {
|
||||||
|
len: 1,
|
||||||
|
debug_data: [
|
||||||
|
SlotDebugData {
|
||||||
|
name: "",
|
||||||
|
ty: UInt<4>,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
},
|
||||||
|
body: Scalar,
|
||||||
|
},
|
||||||
|
range: TypeIndexRange {
|
||||||
|
small_slots: StatePartIndexRange<SmallSlots> { start: 0, len: 0 },
|
||||||
|
big_slots: StatePartIndexRange<BigSlots> { start: 0, len: 1 },
|
||||||
|
},
|
||||||
|
write: None,
|
||||||
|
},
|
||||||
|
Instance {
|
||||||
|
name: <simulator>::mod1,
|
||||||
|
instantiated: Module {
|
||||||
|
name: mod1,
|
||||||
|
..
|
||||||
|
},
|
||||||
|
}.o.i2: CompiledValue {
|
||||||
|
layout: CompiledTypeLayout {
|
||||||
|
ty: SInt<2>,
|
||||||
|
layout: TypeLayout {
|
||||||
|
small_slots: StatePartLayout<SmallSlots> {
|
||||||
|
len: 0,
|
||||||
|
debug_data: [],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
big_slots: StatePartLayout<BigSlots> {
|
||||||
|
len: 1,
|
||||||
|
debug_data: [
|
||||||
|
SlotDebugData {
|
||||||
|
name: "",
|
||||||
|
ty: SInt<2>,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
},
|
||||||
|
body: Scalar,
|
||||||
|
},
|
||||||
|
range: TypeIndexRange {
|
||||||
|
small_slots: StatePartIndexRange<SmallSlots> { start: 0, len: 0 },
|
||||||
|
big_slots: StatePartIndexRange<BigSlots> { start: 2, len: 1 },
|
||||||
|
},
|
||||||
|
write: None,
|
||||||
|
},
|
||||||
|
Instance {
|
||||||
|
name: <simulator>::mod1,
|
||||||
|
instantiated: Module {
|
||||||
|
name: mod1,
|
||||||
|
..
|
||||||
|
},
|
||||||
|
}.o.o: CompiledValue {
|
||||||
|
layout: CompiledTypeLayout {
|
||||||
|
ty: SInt<2>,
|
||||||
|
layout: TypeLayout {
|
||||||
|
small_slots: StatePartLayout<SmallSlots> {
|
||||||
|
len: 0,
|
||||||
|
debug_data: [],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
big_slots: StatePartLayout<BigSlots> {
|
||||||
|
len: 1,
|
||||||
|
debug_data: [
|
||||||
|
SlotDebugData {
|
||||||
|
name: "",
|
||||||
|
ty: SInt<2>,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
},
|
||||||
|
body: Scalar,
|
||||||
|
},
|
||||||
|
range: TypeIndexRange {
|
||||||
|
small_slots: StatePartIndexRange<SmallSlots> { start: 0, len: 0 },
|
||||||
|
big_slots: StatePartIndexRange<BigSlots> { start: 1, len: 1 },
|
||||||
|
},
|
||||||
|
write: None,
|
||||||
|
},
|
||||||
|
Instance {
|
||||||
|
name: <simulator>::mod1,
|
||||||
|
instantiated: Module {
|
||||||
|
name: mod1,
|
||||||
|
..
|
||||||
|
},
|
||||||
|
}.o.o2: CompiledValue {
|
||||||
|
layout: CompiledTypeLayout {
|
||||||
|
ty: UInt<4>,
|
||||||
|
layout: TypeLayout {
|
||||||
|
small_slots: StatePartLayout<SmallSlots> {
|
||||||
|
len: 0,
|
||||||
|
debug_data: [],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
big_slots: StatePartLayout<BigSlots> {
|
||||||
|
len: 1,
|
||||||
|
debug_data: [
|
||||||
|
SlotDebugData {
|
||||||
|
name: "",
|
||||||
|
ty: UInt<4>,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
},
|
||||||
|
body: Scalar,
|
||||||
|
},
|
||||||
|
range: TypeIndexRange {
|
||||||
|
small_slots: StatePartIndexRange<SmallSlots> { start: 0, len: 0 },
|
||||||
|
big_slots: StatePartIndexRange<BigSlots> { start: 3, len: 1 },
|
||||||
|
},
|
||||||
|
write: None,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
made_initial_step: true,
|
||||||
|
needs_settle: false,
|
||||||
|
trace_decls: TraceModule {
|
||||||
|
name: "mod1",
|
||||||
|
children: [
|
||||||
|
TraceModuleIO {
|
||||||
|
name: "o",
|
||||||
|
child: TraceBundle {
|
||||||
|
name: "o",
|
||||||
|
fields: [
|
||||||
|
TraceUInt {
|
||||||
|
location: TraceScalarId(0),
|
||||||
|
name: "i",
|
||||||
|
ty: UInt<4>,
|
||||||
|
flow: Source,
|
||||||
|
},
|
||||||
|
TraceSInt {
|
||||||
|
location: TraceScalarId(1),
|
||||||
|
name: "o",
|
||||||
|
ty: SInt<2>,
|
||||||
|
flow: Sink,
|
||||||
|
},
|
||||||
|
TraceSInt {
|
||||||
|
location: TraceScalarId(2),
|
||||||
|
name: "i2",
|
||||||
|
ty: SInt<2>,
|
||||||
|
flow: Source,
|
||||||
|
},
|
||||||
|
TraceUInt {
|
||||||
|
location: TraceScalarId(3),
|
||||||
|
name: "o2",
|
||||||
|
ty: UInt<4>,
|
||||||
|
flow: Sink,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
ty: Bundle {
|
||||||
|
#[hdl(flip)] /* offset = 0 */
|
||||||
|
i: UInt<4>,
|
||||||
|
/* offset = 4 */
|
||||||
|
o: SInt<2>,
|
||||||
|
#[hdl(flip)] /* offset = 6 */
|
||||||
|
i2: SInt<2>,
|
||||||
|
/* offset = 8 */
|
||||||
|
o2: UInt<4>,
|
||||||
|
},
|
||||||
|
flow: Sink,
|
||||||
|
},
|
||||||
|
ty: Bundle {
|
||||||
|
#[hdl(flip)] /* offset = 0 */
|
||||||
|
i: UInt<4>,
|
||||||
|
/* offset = 4 */
|
||||||
|
o: SInt<2>,
|
||||||
|
#[hdl(flip)] /* offset = 6 */
|
||||||
|
i2: SInt<2>,
|
||||||
|
/* offset = 8 */
|
||||||
|
o2: UInt<4>,
|
||||||
|
},
|
||||||
|
flow: Sink,
|
||||||
|
},
|
||||||
|
TraceInstance {
|
||||||
|
name: "child",
|
||||||
|
instance_io: TraceBundle {
|
||||||
|
name: "child",
|
||||||
|
fields: [
|
||||||
|
TraceUInt {
|
||||||
|
location: TraceScalarId(8),
|
||||||
|
name: "i",
|
||||||
|
ty: UInt<4>,
|
||||||
|
flow: Sink,
|
||||||
|
},
|
||||||
|
TraceSInt {
|
||||||
|
location: TraceScalarId(9),
|
||||||
|
name: "o",
|
||||||
|
ty: SInt<2>,
|
||||||
|
flow: Source,
|
||||||
|
},
|
||||||
|
TraceSInt {
|
||||||
|
location: TraceScalarId(10),
|
||||||
|
name: "i2",
|
||||||
|
ty: SInt<2>,
|
||||||
|
flow: Sink,
|
||||||
|
},
|
||||||
|
TraceUInt {
|
||||||
|
location: TraceScalarId(11),
|
||||||
|
name: "o2",
|
||||||
|
ty: UInt<4>,
|
||||||
|
flow: Source,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
ty: Bundle {
|
||||||
|
#[hdl(flip)] /* offset = 0 */
|
||||||
|
i: UInt<4>,
|
||||||
|
/* offset = 4 */
|
||||||
|
o: SInt<2>,
|
||||||
|
#[hdl(flip)] /* offset = 6 */
|
||||||
|
i2: SInt<2>,
|
||||||
|
/* offset = 8 */
|
||||||
|
o2: UInt<4>,
|
||||||
|
},
|
||||||
|
flow: Source,
|
||||||
|
},
|
||||||
|
module: TraceModule {
|
||||||
|
name: "mod1_child",
|
||||||
|
children: [
|
||||||
|
TraceModuleIO {
|
||||||
|
name: "i",
|
||||||
|
child: TraceUInt {
|
||||||
|
location: TraceScalarId(4),
|
||||||
|
name: "i",
|
||||||
|
ty: UInt<4>,
|
||||||
|
flow: Source,
|
||||||
|
},
|
||||||
|
ty: UInt<4>,
|
||||||
|
flow: Source,
|
||||||
|
},
|
||||||
|
TraceModuleIO {
|
||||||
|
name: "o",
|
||||||
|
child: TraceSInt {
|
||||||
|
location: TraceScalarId(5),
|
||||||
|
name: "o",
|
||||||
|
ty: SInt<2>,
|
||||||
|
flow: Sink,
|
||||||
|
},
|
||||||
|
ty: SInt<2>,
|
||||||
|
flow: Sink,
|
||||||
|
},
|
||||||
|
TraceModuleIO {
|
||||||
|
name: "i2",
|
||||||
|
child: TraceSInt {
|
||||||
|
location: TraceScalarId(6),
|
||||||
|
name: "i2",
|
||||||
|
ty: SInt<2>,
|
||||||
|
flow: Source,
|
||||||
|
},
|
||||||
|
ty: SInt<2>,
|
||||||
|
flow: Source,
|
||||||
|
},
|
||||||
|
TraceModuleIO {
|
||||||
|
name: "o2",
|
||||||
|
child: TraceUInt {
|
||||||
|
location: TraceScalarId(7),
|
||||||
|
name: "o2",
|
||||||
|
ty: UInt<4>,
|
||||||
|
flow: Sink,
|
||||||
|
},
|
||||||
|
ty: UInt<4>,
|
||||||
|
flow: Sink,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
ty: Bundle {
|
||||||
|
#[hdl(flip)] /* offset = 0 */
|
||||||
|
i: UInt<4>,
|
||||||
|
/* offset = 4 */
|
||||||
|
o: SInt<2>,
|
||||||
|
#[hdl(flip)] /* offset = 6 */
|
||||||
|
i2: SInt<2>,
|
||||||
|
/* offset = 8 */
|
||||||
|
o2: UInt<4>,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
traces: [
|
||||||
|
SimTrace {
|
||||||
|
id: TraceScalarId(0),
|
||||||
|
kind: BigUInt {
|
||||||
|
index: StatePartIndex<BigSlots>(0),
|
||||||
|
ty: UInt<4>,
|
||||||
|
},
|
||||||
|
state: 0xa,
|
||||||
|
last_state: 0x3,
|
||||||
|
},
|
||||||
|
SimTrace {
|
||||||
|
id: TraceScalarId(1),
|
||||||
|
kind: BigSInt {
|
||||||
|
index: StatePartIndex<BigSlots>(1),
|
||||||
|
ty: SInt<2>,
|
||||||
|
},
|
||||||
|
state: 0x2,
|
||||||
|
last_state: 0x3,
|
||||||
|
},
|
||||||
|
SimTrace {
|
||||||
|
id: TraceScalarId(2),
|
||||||
|
kind: BigSInt {
|
||||||
|
index: StatePartIndex<BigSlots>(2),
|
||||||
|
ty: SInt<2>,
|
||||||
|
},
|
||||||
|
state: 0x2,
|
||||||
|
last_state: 0x2,
|
||||||
|
},
|
||||||
|
SimTrace {
|
||||||
|
id: TraceScalarId(3),
|
||||||
|
kind: BigUInt {
|
||||||
|
index: StatePartIndex<BigSlots>(3),
|
||||||
|
ty: UInt<4>,
|
||||||
|
},
|
||||||
|
state: 0xf,
|
||||||
|
last_state: 0xe,
|
||||||
|
},
|
||||||
|
SimTrace {
|
||||||
|
id: TraceScalarId(4),
|
||||||
|
kind: BigUInt {
|
||||||
|
index: StatePartIndex<BigSlots>(8),
|
||||||
|
ty: UInt<4>,
|
||||||
|
},
|
||||||
|
state: 0xa,
|
||||||
|
last_state: 0x3,
|
||||||
|
},
|
||||||
|
SimTrace {
|
||||||
|
id: TraceScalarId(5),
|
||||||
|
kind: BigSInt {
|
||||||
|
index: StatePartIndex<BigSlots>(9),
|
||||||
|
ty: SInt<2>,
|
||||||
|
},
|
||||||
|
state: 0x2,
|
||||||
|
last_state: 0x3,
|
||||||
|
},
|
||||||
|
SimTrace {
|
||||||
|
id: TraceScalarId(6),
|
||||||
|
kind: BigSInt {
|
||||||
|
index: StatePartIndex<BigSlots>(10),
|
||||||
|
ty: SInt<2>,
|
||||||
|
},
|
||||||
|
state: 0x2,
|
||||||
|
last_state: 0x2,
|
||||||
|
},
|
||||||
|
SimTrace {
|
||||||
|
id: TraceScalarId(7),
|
||||||
|
kind: BigUInt {
|
||||||
|
index: StatePartIndex<BigSlots>(11),
|
||||||
|
ty: UInt<4>,
|
||||||
|
},
|
||||||
|
state: 0xf,
|
||||||
|
last_state: 0xe,
|
||||||
|
},
|
||||||
|
SimTrace {
|
||||||
|
id: TraceScalarId(8),
|
||||||
|
kind: BigUInt {
|
||||||
|
index: StatePartIndex<BigSlots>(4),
|
||||||
|
ty: UInt<4>,
|
||||||
|
},
|
||||||
|
state: 0xa,
|
||||||
|
last_state: 0x3,
|
||||||
|
},
|
||||||
|
SimTrace {
|
||||||
|
id: TraceScalarId(9),
|
||||||
|
kind: BigSInt {
|
||||||
|
index: StatePartIndex<BigSlots>(5),
|
||||||
|
ty: SInt<2>,
|
||||||
|
},
|
||||||
|
state: 0x2,
|
||||||
|
last_state: 0x3,
|
||||||
|
},
|
||||||
|
SimTrace {
|
||||||
|
id: TraceScalarId(10),
|
||||||
|
kind: BigSInt {
|
||||||
|
index: StatePartIndex<BigSlots>(6),
|
||||||
|
ty: SInt<2>,
|
||||||
|
},
|
||||||
|
state: 0x2,
|
||||||
|
last_state: 0x2,
|
||||||
|
},
|
||||||
|
SimTrace {
|
||||||
|
id: TraceScalarId(11),
|
||||||
|
kind: BigUInt {
|
||||||
|
index: StatePartIndex<BigSlots>(7),
|
||||||
|
ty: UInt<4>,
|
||||||
|
},
|
||||||
|
state: 0xf,
|
||||||
|
last_state: 0xe,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
trace_memories: {},
|
||||||
|
trace_writers: [
|
||||||
|
Running(
|
||||||
|
VcdWriter {
|
||||||
|
finished_init: true,
|
||||||
|
timescale: 1 ps,
|
||||||
|
..
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
instant: 2 μs,
|
||||||
|
clocks_triggered: [],
|
||||||
|
..
|
||||||
|
}
|
47
crates/fayalite/tests/sim/expected/mod1.vcd
Normal file
47
crates/fayalite/tests/sim/expected/mod1.vcd
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
$timescale 1 ps $end
|
||||||
|
$scope module mod1 $end
|
||||||
|
$scope struct o $end
|
||||||
|
$var wire 4 ! i $end
|
||||||
|
$var wire 2 " o $end
|
||||||
|
$var wire 2 # i2 $end
|
||||||
|
$var wire 4 $ o2 $end
|
||||||
|
$upscope $end
|
||||||
|
$scope struct child $end
|
||||||
|
$var wire 4 ) i $end
|
||||||
|
$var wire 2 * o $end
|
||||||
|
$var wire 2 + i2 $end
|
||||||
|
$var wire 4 , o2 $end
|
||||||
|
$upscope $end
|
||||||
|
$scope module mod1_child $end
|
||||||
|
$var wire 4 % i $end
|
||||||
|
$var wire 2 & o $end
|
||||||
|
$var wire 2 ' i2 $end
|
||||||
|
$var wire 4 ( o2 $end
|
||||||
|
$upscope $end
|
||||||
|
$upscope $end
|
||||||
|
$enddefinitions $end
|
||||||
|
$dumpvars
|
||||||
|
b11 !
|
||||||
|
b11 "
|
||||||
|
b10 #
|
||||||
|
b1110 $
|
||||||
|
b11 %
|
||||||
|
b11 &
|
||||||
|
b10 '
|
||||||
|
b1110 (
|
||||||
|
b11 )
|
||||||
|
b11 *
|
||||||
|
b10 +
|
||||||
|
b1110 ,
|
||||||
|
$end
|
||||||
|
#1000000
|
||||||
|
b1010 !
|
||||||
|
b10 "
|
||||||
|
b1111 $
|
||||||
|
b1010 %
|
||||||
|
b10 &
|
||||||
|
b1111 (
|
||||||
|
b1010 )
|
||||||
|
b10 *
|
||||||
|
b1111 ,
|
||||||
|
#2000000
|
683
crates/fayalite/tests/sim/expected/shift_register.txt
Normal file
683
crates/fayalite/tests/sim/expected/shift_register.txt
Normal file
|
@ -0,0 +1,683 @@
|
||||||
|
Simulation {
|
||||||
|
state: State {
|
||||||
|
insns: Insns {
|
||||||
|
state_layout: StateLayout {
|
||||||
|
ty: TypeLayout {
|
||||||
|
small_slots: StatePartLayout<SmallSlots> {
|
||||||
|
len: 4,
|
||||||
|
debug_data: [
|
||||||
|
SlotDebugData {
|
||||||
|
name: "",
|
||||||
|
ty: Bool,
|
||||||
|
},
|
||||||
|
SlotDebugData {
|
||||||
|
name: "",
|
||||||
|
ty: Bool,
|
||||||
|
},
|
||||||
|
SlotDebugData {
|
||||||
|
name: "",
|
||||||
|
ty: Bool,
|
||||||
|
},
|
||||||
|
SlotDebugData {
|
||||||
|
name: "",
|
||||||
|
ty: Bool,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
big_slots: StatePartLayout<BigSlots> {
|
||||||
|
len: 13,
|
||||||
|
debug_data: [
|
||||||
|
SlotDebugData {
|
||||||
|
name: "InstantiatedModule(shift_register: shift_register).shift_register::cd.clk",
|
||||||
|
ty: Clock,
|
||||||
|
},
|
||||||
|
SlotDebugData {
|
||||||
|
name: "InstantiatedModule(shift_register: shift_register).shift_register::cd.rst",
|
||||||
|
ty: SyncReset,
|
||||||
|
},
|
||||||
|
SlotDebugData {
|
||||||
|
name: "InstantiatedModule(shift_register: shift_register).shift_register::d",
|
||||||
|
ty: Bool,
|
||||||
|
},
|
||||||
|
SlotDebugData {
|
||||||
|
name: "InstantiatedModule(shift_register: shift_register).shift_register::q",
|
||||||
|
ty: Bool,
|
||||||
|
},
|
||||||
|
SlotDebugData {
|
||||||
|
name: "InstantiatedModule(shift_register: shift_register).shift_register::reg0",
|
||||||
|
ty: Bool,
|
||||||
|
},
|
||||||
|
SlotDebugData {
|
||||||
|
name: "InstantiatedModule(shift_register: shift_register).shift_register::reg0$next",
|
||||||
|
ty: Bool,
|
||||||
|
},
|
||||||
|
SlotDebugData {
|
||||||
|
name: "",
|
||||||
|
ty: Bool,
|
||||||
|
},
|
||||||
|
SlotDebugData {
|
||||||
|
name: "InstantiatedModule(shift_register: shift_register).shift_register::reg1",
|
||||||
|
ty: Bool,
|
||||||
|
},
|
||||||
|
SlotDebugData {
|
||||||
|
name: "InstantiatedModule(shift_register: shift_register).shift_register::reg1$next",
|
||||||
|
ty: Bool,
|
||||||
|
},
|
||||||
|
SlotDebugData {
|
||||||
|
name: "InstantiatedModule(shift_register: shift_register).shift_register::reg2",
|
||||||
|
ty: Bool,
|
||||||
|
},
|
||||||
|
SlotDebugData {
|
||||||
|
name: "InstantiatedModule(shift_register: shift_register).shift_register::reg2$next",
|
||||||
|
ty: Bool,
|
||||||
|
},
|
||||||
|
SlotDebugData {
|
||||||
|
name: "InstantiatedModule(shift_register: shift_register).shift_register::reg3",
|
||||||
|
ty: Bool,
|
||||||
|
},
|
||||||
|
SlotDebugData {
|
||||||
|
name: "InstantiatedModule(shift_register: shift_register).shift_register::reg3$next",
|
||||||
|
ty: Bool,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
},
|
||||||
|
memories: StatePartLayout<Memories> {
|
||||||
|
len: 0,
|
||||||
|
debug_data: [],
|
||||||
|
layout_data: [],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
},
|
||||||
|
insns: [
|
||||||
|
// at: module-XXXXXXXXXX.rs:13:1
|
||||||
|
0: Copy {
|
||||||
|
dest: StatePartIndex<BigSlots>(3), // (0x0) SlotDebugData { name: "InstantiatedModule(shift_register: shift_register).shift_register::q", ty: Bool },
|
||||||
|
src: StatePartIndex<BigSlots>(11), // (0x0) SlotDebugData { name: "InstantiatedModule(shift_register: shift_register).shift_register::reg3", ty: Bool },
|
||||||
|
},
|
||||||
|
// at: module-XXXXXXXXXX.rs:12:1
|
||||||
|
1: Copy {
|
||||||
|
dest: StatePartIndex<BigSlots>(12), // (0x0) SlotDebugData { name: "InstantiatedModule(shift_register: shift_register).shift_register::reg3$next", ty: Bool },
|
||||||
|
src: StatePartIndex<BigSlots>(9), // (0x0) SlotDebugData { name: "InstantiatedModule(shift_register: shift_register).shift_register::reg2", ty: Bool },
|
||||||
|
},
|
||||||
|
// at: module-XXXXXXXXXX.rs:10:1
|
||||||
|
2: Copy {
|
||||||
|
dest: StatePartIndex<BigSlots>(10), // (0x0) SlotDebugData { name: "InstantiatedModule(shift_register: shift_register).shift_register::reg2$next", ty: Bool },
|
||||||
|
src: StatePartIndex<BigSlots>(7), // (0x0) SlotDebugData { name: "InstantiatedModule(shift_register: shift_register).shift_register::reg1", ty: Bool },
|
||||||
|
},
|
||||||
|
// at: module-XXXXXXXXXX.rs:8:1
|
||||||
|
3: Copy {
|
||||||
|
dest: StatePartIndex<BigSlots>(8), // (0x0) SlotDebugData { name: "InstantiatedModule(shift_register: shift_register).shift_register::reg1$next", ty: Bool },
|
||||||
|
src: StatePartIndex<BigSlots>(4), // (0x0) SlotDebugData { name: "InstantiatedModule(shift_register: shift_register).shift_register::reg0", ty: Bool },
|
||||||
|
},
|
||||||
|
// at: module-XXXXXXXXXX.rs:6:1
|
||||||
|
4: Copy {
|
||||||
|
dest: StatePartIndex<BigSlots>(5), // (0x0) SlotDebugData { name: "InstantiatedModule(shift_register: shift_register).shift_register::reg0$next", ty: Bool },
|
||||||
|
src: StatePartIndex<BigSlots>(2), // (0x0) SlotDebugData { name: "InstantiatedModule(shift_register: shift_register).shift_register::d", ty: Bool },
|
||||||
|
},
|
||||||
|
// at: module-XXXXXXXXXX.rs:5:1
|
||||||
|
5: IsNonZeroDestIsSmall {
|
||||||
|
dest: StatePartIndex<SmallSlots>(3), // (0x0 0) SlotDebugData { name: "", ty: Bool },
|
||||||
|
src: StatePartIndex<BigSlots>(1), // (0x0) SlotDebugData { name: "InstantiatedModule(shift_register: shift_register).shift_register::cd.rst", ty: SyncReset },
|
||||||
|
},
|
||||||
|
// at: module-XXXXXXXXXX.rs:1:1
|
||||||
|
6: Const {
|
||||||
|
dest: StatePartIndex<BigSlots>(6), // (0x0) SlotDebugData { name: "", ty: Bool },
|
||||||
|
value: 0x0,
|
||||||
|
},
|
||||||
|
// at: module-XXXXXXXXXX.rs:5:1
|
||||||
|
7: IsNonZeroDestIsSmall {
|
||||||
|
dest: StatePartIndex<SmallSlots>(2), // (0x1 1) SlotDebugData { name: "", ty: Bool },
|
||||||
|
src: StatePartIndex<BigSlots>(0), // (0x1) SlotDebugData { name: "InstantiatedModule(shift_register: shift_register).shift_register::cd.clk", ty: Clock },
|
||||||
|
},
|
||||||
|
8: AndSmall {
|
||||||
|
dest: StatePartIndex<SmallSlots>(1), // (0x0 0) SlotDebugData { name: "", ty: Bool },
|
||||||
|
lhs: StatePartIndex<SmallSlots>(2), // (0x1 1) SlotDebugData { name: "", ty: Bool },
|
||||||
|
rhs: StatePartIndex<SmallSlots>(0), // (0x0 0) SlotDebugData { name: "", ty: Bool },
|
||||||
|
},
|
||||||
|
9: BranchIfSmallZero {
|
||||||
|
target: 14,
|
||||||
|
value: StatePartIndex<SmallSlots>(1), // (0x0 0) SlotDebugData { name: "", ty: Bool },
|
||||||
|
},
|
||||||
|
10: BranchIfSmallNonZero {
|
||||||
|
target: 13,
|
||||||
|
value: StatePartIndex<SmallSlots>(3), // (0x0 0) SlotDebugData { name: "", ty: Bool },
|
||||||
|
},
|
||||||
|
11: Copy {
|
||||||
|
dest: StatePartIndex<BigSlots>(4), // (0x0) SlotDebugData { name: "InstantiatedModule(shift_register: shift_register).shift_register::reg0", ty: Bool },
|
||||||
|
src: StatePartIndex<BigSlots>(5), // (0x0) SlotDebugData { name: "InstantiatedModule(shift_register: shift_register).shift_register::reg0$next", ty: Bool },
|
||||||
|
},
|
||||||
|
12: Branch {
|
||||||
|
target: 14,
|
||||||
|
},
|
||||||
|
13: Copy {
|
||||||
|
dest: StatePartIndex<BigSlots>(4), // (0x0) SlotDebugData { name: "InstantiatedModule(shift_register: shift_register).shift_register::reg0", ty: Bool },
|
||||||
|
src: StatePartIndex<BigSlots>(6), // (0x0) SlotDebugData { name: "", ty: Bool },
|
||||||
|
},
|
||||||
|
// at: module-XXXXXXXXXX.rs:7:1
|
||||||
|
14: BranchIfSmallZero {
|
||||||
|
target: 19,
|
||||||
|
value: StatePartIndex<SmallSlots>(1), // (0x0 0) SlotDebugData { name: "", ty: Bool },
|
||||||
|
},
|
||||||
|
15: BranchIfSmallNonZero {
|
||||||
|
target: 18,
|
||||||
|
value: StatePartIndex<SmallSlots>(3), // (0x0 0) SlotDebugData { name: "", ty: Bool },
|
||||||
|
},
|
||||||
|
16: Copy {
|
||||||
|
dest: StatePartIndex<BigSlots>(7), // (0x0) SlotDebugData { name: "InstantiatedModule(shift_register: shift_register).shift_register::reg1", ty: Bool },
|
||||||
|
src: StatePartIndex<BigSlots>(8), // (0x0) SlotDebugData { name: "InstantiatedModule(shift_register: shift_register).shift_register::reg1$next", ty: Bool },
|
||||||
|
},
|
||||||
|
17: Branch {
|
||||||
|
target: 19,
|
||||||
|
},
|
||||||
|
18: Copy {
|
||||||
|
dest: StatePartIndex<BigSlots>(7), // (0x0) SlotDebugData { name: "InstantiatedModule(shift_register: shift_register).shift_register::reg1", ty: Bool },
|
||||||
|
src: StatePartIndex<BigSlots>(6), // (0x0) SlotDebugData { name: "", ty: Bool },
|
||||||
|
},
|
||||||
|
// at: module-XXXXXXXXXX.rs:9:1
|
||||||
|
19: BranchIfSmallZero {
|
||||||
|
target: 24,
|
||||||
|
value: StatePartIndex<SmallSlots>(1), // (0x0 0) SlotDebugData { name: "", ty: Bool },
|
||||||
|
},
|
||||||
|
20: BranchIfSmallNonZero {
|
||||||
|
target: 23,
|
||||||
|
value: StatePartIndex<SmallSlots>(3), // (0x0 0) SlotDebugData { name: "", ty: Bool },
|
||||||
|
},
|
||||||
|
21: Copy {
|
||||||
|
dest: StatePartIndex<BigSlots>(9), // (0x0) SlotDebugData { name: "InstantiatedModule(shift_register: shift_register).shift_register::reg2", ty: Bool },
|
||||||
|
src: StatePartIndex<BigSlots>(10), // (0x0) SlotDebugData { name: "InstantiatedModule(shift_register: shift_register).shift_register::reg2$next", ty: Bool },
|
||||||
|
},
|
||||||
|
22: Branch {
|
||||||
|
target: 24,
|
||||||
|
},
|
||||||
|
23: Copy {
|
||||||
|
dest: StatePartIndex<BigSlots>(9), // (0x0) SlotDebugData { name: "InstantiatedModule(shift_register: shift_register).shift_register::reg2", ty: Bool },
|
||||||
|
src: StatePartIndex<BigSlots>(6), // (0x0) SlotDebugData { name: "", ty: Bool },
|
||||||
|
},
|
||||||
|
// at: module-XXXXXXXXXX.rs:11:1
|
||||||
|
24: BranchIfSmallZero {
|
||||||
|
target: 29,
|
||||||
|
value: StatePartIndex<SmallSlots>(1), // (0x0 0) SlotDebugData { name: "", ty: Bool },
|
||||||
|
},
|
||||||
|
25: BranchIfSmallNonZero {
|
||||||
|
target: 28,
|
||||||
|
value: StatePartIndex<SmallSlots>(3), // (0x0 0) SlotDebugData { name: "", ty: Bool },
|
||||||
|
},
|
||||||
|
26: Copy {
|
||||||
|
dest: StatePartIndex<BigSlots>(11), // (0x0) SlotDebugData { name: "InstantiatedModule(shift_register: shift_register).shift_register::reg3", ty: Bool },
|
||||||
|
src: StatePartIndex<BigSlots>(12), // (0x0) SlotDebugData { name: "InstantiatedModule(shift_register: shift_register).shift_register::reg3$next", ty: Bool },
|
||||||
|
},
|
||||||
|
27: Branch {
|
||||||
|
target: 29,
|
||||||
|
},
|
||||||
|
28: Copy {
|
||||||
|
dest: StatePartIndex<BigSlots>(11), // (0x0) SlotDebugData { name: "InstantiatedModule(shift_register: shift_register).shift_register::reg3", ty: Bool },
|
||||||
|
src: StatePartIndex<BigSlots>(6), // (0x0) SlotDebugData { name: "", ty: Bool },
|
||||||
|
},
|
||||||
|
// at: module-XXXXXXXXXX.rs:5:1
|
||||||
|
29: XorSmallImmediate {
|
||||||
|
dest: StatePartIndex<SmallSlots>(0), // (0x0 0) SlotDebugData { name: "", ty: Bool },
|
||||||
|
lhs: StatePartIndex<SmallSlots>(2), // (0x1 1) SlotDebugData { name: "", ty: Bool },
|
||||||
|
rhs: 0x1,
|
||||||
|
},
|
||||||
|
// at: module-XXXXXXXXXX.rs:1:1
|
||||||
|
30: Return,
|
||||||
|
],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
pc: 30,
|
||||||
|
memory_write_log: [],
|
||||||
|
memories: StatePart {
|
||||||
|
value: [],
|
||||||
|
},
|
||||||
|
small_slots: StatePart {
|
||||||
|
value: [
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
big_slots: StatePart {
|
||||||
|
value: [
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
io: Instance {
|
||||||
|
name: <simulator>::shift_register,
|
||||||
|
instantiated: Module {
|
||||||
|
name: shift_register,
|
||||||
|
..
|
||||||
|
},
|
||||||
|
},
|
||||||
|
uninitialized_inputs: {},
|
||||||
|
io_targets: {
|
||||||
|
Instance {
|
||||||
|
name: <simulator>::shift_register,
|
||||||
|
instantiated: Module {
|
||||||
|
name: shift_register,
|
||||||
|
..
|
||||||
|
},
|
||||||
|
}.cd: CompiledValue {
|
||||||
|
layout: CompiledTypeLayout {
|
||||||
|
ty: Bundle {
|
||||||
|
/* offset = 0 */
|
||||||
|
clk: Clock,
|
||||||
|
/* offset = 1 */
|
||||||
|
rst: SyncReset,
|
||||||
|
},
|
||||||
|
layout: TypeLayout {
|
||||||
|
small_slots: StatePartLayout<SmallSlots> {
|
||||||
|
len: 0,
|
||||||
|
debug_data: [],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
big_slots: StatePartLayout<BigSlots> {
|
||||||
|
len: 2,
|
||||||
|
debug_data: [
|
||||||
|
SlotDebugData {
|
||||||
|
name: "InstantiatedModule(shift_register: shift_register).shift_register::cd.clk",
|
||||||
|
ty: Clock,
|
||||||
|
},
|
||||||
|
SlotDebugData {
|
||||||
|
name: "InstantiatedModule(shift_register: shift_register).shift_register::cd.rst",
|
||||||
|
ty: SyncReset,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
},
|
||||||
|
body: Bundle {
|
||||||
|
fields: [
|
||||||
|
CompiledBundleField {
|
||||||
|
offset: TypeIndex {
|
||||||
|
small_slots: StatePartIndex<SmallSlots>(0),
|
||||||
|
big_slots: StatePartIndex<BigSlots>(0),
|
||||||
|
},
|
||||||
|
ty: CompiledTypeLayout {
|
||||||
|
ty: Clock,
|
||||||
|
layout: TypeLayout {
|
||||||
|
small_slots: StatePartLayout<SmallSlots> {
|
||||||
|
len: 0,
|
||||||
|
debug_data: [],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
big_slots: StatePartLayout<BigSlots> {
|
||||||
|
len: 1,
|
||||||
|
debug_data: [
|
||||||
|
SlotDebugData {
|
||||||
|
name: "",
|
||||||
|
ty: Clock,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
},
|
||||||
|
body: Scalar,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
CompiledBundleField {
|
||||||
|
offset: TypeIndex {
|
||||||
|
small_slots: StatePartIndex<SmallSlots>(0),
|
||||||
|
big_slots: StatePartIndex<BigSlots>(1),
|
||||||
|
},
|
||||||
|
ty: CompiledTypeLayout {
|
||||||
|
ty: SyncReset,
|
||||||
|
layout: TypeLayout {
|
||||||
|
small_slots: StatePartLayout<SmallSlots> {
|
||||||
|
len: 0,
|
||||||
|
debug_data: [],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
big_slots: StatePartLayout<BigSlots> {
|
||||||
|
len: 1,
|
||||||
|
debug_data: [
|
||||||
|
SlotDebugData {
|
||||||
|
name: "",
|
||||||
|
ty: SyncReset,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
},
|
||||||
|
body: Scalar,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
range: TypeIndexRange {
|
||||||
|
small_slots: StatePartIndexRange<SmallSlots> { start: 0, len: 0 },
|
||||||
|
big_slots: StatePartIndexRange<BigSlots> { start: 0, len: 2 },
|
||||||
|
},
|
||||||
|
write: None,
|
||||||
|
},
|
||||||
|
Instance {
|
||||||
|
name: <simulator>::shift_register,
|
||||||
|
instantiated: Module {
|
||||||
|
name: shift_register,
|
||||||
|
..
|
||||||
|
},
|
||||||
|
}.cd.clk: CompiledValue {
|
||||||
|
layout: CompiledTypeLayout {
|
||||||
|
ty: Clock,
|
||||||
|
layout: TypeLayout {
|
||||||
|
small_slots: StatePartLayout<SmallSlots> {
|
||||||
|
len: 0,
|
||||||
|
debug_data: [],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
big_slots: StatePartLayout<BigSlots> {
|
||||||
|
len: 1,
|
||||||
|
debug_data: [
|
||||||
|
SlotDebugData {
|
||||||
|
name: "",
|
||||||
|
ty: Clock,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
},
|
||||||
|
body: Scalar,
|
||||||
|
},
|
||||||
|
range: TypeIndexRange {
|
||||||
|
small_slots: StatePartIndexRange<SmallSlots> { start: 0, len: 0 },
|
||||||
|
big_slots: StatePartIndexRange<BigSlots> { start: 0, len: 1 },
|
||||||
|
},
|
||||||
|
write: None,
|
||||||
|
},
|
||||||
|
Instance {
|
||||||
|
name: <simulator>::shift_register,
|
||||||
|
instantiated: Module {
|
||||||
|
name: shift_register,
|
||||||
|
..
|
||||||
|
},
|
||||||
|
}.cd.rst: CompiledValue {
|
||||||
|
layout: CompiledTypeLayout {
|
||||||
|
ty: SyncReset,
|
||||||
|
layout: TypeLayout {
|
||||||
|
small_slots: StatePartLayout<SmallSlots> {
|
||||||
|
len: 0,
|
||||||
|
debug_data: [],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
big_slots: StatePartLayout<BigSlots> {
|
||||||
|
len: 1,
|
||||||
|
debug_data: [
|
||||||
|
SlotDebugData {
|
||||||
|
name: "",
|
||||||
|
ty: SyncReset,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
},
|
||||||
|
body: Scalar,
|
||||||
|
},
|
||||||
|
range: TypeIndexRange {
|
||||||
|
small_slots: StatePartIndexRange<SmallSlots> { start: 0, len: 0 },
|
||||||
|
big_slots: StatePartIndexRange<BigSlots> { start: 1, len: 1 },
|
||||||
|
},
|
||||||
|
write: None,
|
||||||
|
},
|
||||||
|
Instance {
|
||||||
|
name: <simulator>::shift_register,
|
||||||
|
instantiated: Module {
|
||||||
|
name: shift_register,
|
||||||
|
..
|
||||||
|
},
|
||||||
|
}.d: CompiledValue {
|
||||||
|
layout: CompiledTypeLayout {
|
||||||
|
ty: Bool,
|
||||||
|
layout: TypeLayout {
|
||||||
|
small_slots: StatePartLayout<SmallSlots> {
|
||||||
|
len: 0,
|
||||||
|
debug_data: [],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
big_slots: StatePartLayout<BigSlots> {
|
||||||
|
len: 1,
|
||||||
|
debug_data: [
|
||||||
|
SlotDebugData {
|
||||||
|
name: "InstantiatedModule(shift_register: shift_register).shift_register::d",
|
||||||
|
ty: Bool,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
},
|
||||||
|
body: Scalar,
|
||||||
|
},
|
||||||
|
range: TypeIndexRange {
|
||||||
|
small_slots: StatePartIndexRange<SmallSlots> { start: 0, len: 0 },
|
||||||
|
big_slots: StatePartIndexRange<BigSlots> { start: 2, len: 1 },
|
||||||
|
},
|
||||||
|
write: None,
|
||||||
|
},
|
||||||
|
Instance {
|
||||||
|
name: <simulator>::shift_register,
|
||||||
|
instantiated: Module {
|
||||||
|
name: shift_register,
|
||||||
|
..
|
||||||
|
},
|
||||||
|
}.q: CompiledValue {
|
||||||
|
layout: CompiledTypeLayout {
|
||||||
|
ty: Bool,
|
||||||
|
layout: TypeLayout {
|
||||||
|
small_slots: StatePartLayout<SmallSlots> {
|
||||||
|
len: 0,
|
||||||
|
debug_data: [],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
big_slots: StatePartLayout<BigSlots> {
|
||||||
|
len: 1,
|
||||||
|
debug_data: [
|
||||||
|
SlotDebugData {
|
||||||
|
name: "InstantiatedModule(shift_register: shift_register).shift_register::q",
|
||||||
|
ty: Bool,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
..
|
||||||
|
},
|
||||||
|
},
|
||||||
|
body: Scalar,
|
||||||
|
},
|
||||||
|
range: TypeIndexRange {
|
||||||
|
small_slots: StatePartIndexRange<SmallSlots> { start: 0, len: 0 },
|
||||||
|
big_slots: StatePartIndexRange<BigSlots> { start: 3, len: 1 },
|
||||||
|
},
|
||||||
|
write: None,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
made_initial_step: true,
|
||||||
|
needs_settle: false,
|
||||||
|
trace_decls: TraceModule {
|
||||||
|
name: "shift_register",
|
||||||
|
children: [
|
||||||
|
TraceModuleIO {
|
||||||
|
name: "cd",
|
||||||
|
child: TraceBundle {
|
||||||
|
name: "cd",
|
||||||
|
fields: [
|
||||||
|
TraceClock {
|
||||||
|
location: TraceScalarId(0),
|
||||||
|
name: "clk",
|
||||||
|
flow: Source,
|
||||||
|
},
|
||||||
|
TraceSyncReset {
|
||||||
|
location: TraceScalarId(1),
|
||||||
|
name: "rst",
|
||||||
|
flow: Source,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
ty: Bundle {
|
||||||
|
/* offset = 0 */
|
||||||
|
clk: Clock,
|
||||||
|
/* offset = 1 */
|
||||||
|
rst: SyncReset,
|
||||||
|
},
|
||||||
|
flow: Source,
|
||||||
|
},
|
||||||
|
ty: Bundle {
|
||||||
|
/* offset = 0 */
|
||||||
|
clk: Clock,
|
||||||
|
/* offset = 1 */
|
||||||
|
rst: SyncReset,
|
||||||
|
},
|
||||||
|
flow: Source,
|
||||||
|
},
|
||||||
|
TraceModuleIO {
|
||||||
|
name: "d",
|
||||||
|
child: TraceBool {
|
||||||
|
location: TraceScalarId(2),
|
||||||
|
name: "d",
|
||||||
|
flow: Source,
|
||||||
|
},
|
||||||
|
ty: Bool,
|
||||||
|
flow: Source,
|
||||||
|
},
|
||||||
|
TraceModuleIO {
|
||||||
|
name: "q",
|
||||||
|
child: TraceBool {
|
||||||
|
location: TraceScalarId(3),
|
||||||
|
name: "q",
|
||||||
|
flow: Sink,
|
||||||
|
},
|
||||||
|
ty: Bool,
|
||||||
|
flow: Sink,
|
||||||
|
},
|
||||||
|
TraceReg {
|
||||||
|
name: "reg0",
|
||||||
|
child: TraceBool {
|
||||||
|
location: TraceScalarId(4),
|
||||||
|
name: "reg0",
|
||||||
|
flow: Duplex,
|
||||||
|
},
|
||||||
|
ty: Bool,
|
||||||
|
},
|
||||||
|
TraceReg {
|
||||||
|
name: "reg1",
|
||||||
|
child: TraceBool {
|
||||||
|
location: TraceScalarId(5),
|
||||||
|
name: "reg1",
|
||||||
|
flow: Duplex,
|
||||||
|
},
|
||||||
|
ty: Bool,
|
||||||
|
},
|
||||||
|
TraceReg {
|
||||||
|
name: "reg2",
|
||||||
|
child: TraceBool {
|
||||||
|
location: TraceScalarId(6),
|
||||||
|
name: "reg2",
|
||||||
|
flow: Duplex,
|
||||||
|
},
|
||||||
|
ty: Bool,
|
||||||
|
},
|
||||||
|
TraceReg {
|
||||||
|
name: "reg3",
|
||||||
|
child: TraceBool {
|
||||||
|
location: TraceScalarId(7),
|
||||||
|
name: "reg3",
|
||||||
|
flow: Duplex,
|
||||||
|
},
|
||||||
|
ty: Bool,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
traces: [
|
||||||
|
SimTrace {
|
||||||
|
id: TraceScalarId(0),
|
||||||
|
kind: BigClock {
|
||||||
|
index: StatePartIndex<BigSlots>(0),
|
||||||
|
},
|
||||||
|
state: 0x1,
|
||||||
|
last_state: 0x1,
|
||||||
|
},
|
||||||
|
SimTrace {
|
||||||
|
id: TraceScalarId(1),
|
||||||
|
kind: BigSyncReset {
|
||||||
|
index: StatePartIndex<BigSlots>(1),
|
||||||
|
},
|
||||||
|
state: 0x0,
|
||||||
|
last_state: 0x0,
|
||||||
|
},
|
||||||
|
SimTrace {
|
||||||
|
id: TraceScalarId(2),
|
||||||
|
kind: BigBool {
|
||||||
|
index: StatePartIndex<BigSlots>(2),
|
||||||
|
},
|
||||||
|
state: 0x0,
|
||||||
|
last_state: 0x0,
|
||||||
|
},
|
||||||
|
SimTrace {
|
||||||
|
id: TraceScalarId(3),
|
||||||
|
kind: BigBool {
|
||||||
|
index: StatePartIndex<BigSlots>(3),
|
||||||
|
},
|
||||||
|
state: 0x0,
|
||||||
|
last_state: 0x0,
|
||||||
|
},
|
||||||
|
SimTrace {
|
||||||
|
id: TraceScalarId(4),
|
||||||
|
kind: BigBool {
|
||||||
|
index: StatePartIndex<BigSlots>(4),
|
||||||
|
},
|
||||||
|
state: 0x0,
|
||||||
|
last_state: 0x0,
|
||||||
|
},
|
||||||
|
SimTrace {
|
||||||
|
id: TraceScalarId(5),
|
||||||
|
kind: BigBool {
|
||||||
|
index: StatePartIndex<BigSlots>(7),
|
||||||
|
},
|
||||||
|
state: 0x0,
|
||||||
|
last_state: 0x0,
|
||||||
|
},
|
||||||
|
SimTrace {
|
||||||
|
id: TraceScalarId(6),
|
||||||
|
kind: BigBool {
|
||||||
|
index: StatePartIndex<BigSlots>(9),
|
||||||
|
},
|
||||||
|
state: 0x0,
|
||||||
|
last_state: 0x0,
|
||||||
|
},
|
||||||
|
SimTrace {
|
||||||
|
id: TraceScalarId(7),
|
||||||
|
kind: BigBool {
|
||||||
|
index: StatePartIndex<BigSlots>(11),
|
||||||
|
},
|
||||||
|
state: 0x0,
|
||||||
|
last_state: 0x0,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
trace_memories: {},
|
||||||
|
trace_writers: [
|
||||||
|
Running(
|
||||||
|
VcdWriter {
|
||||||
|
finished_init: true,
|
||||||
|
timescale: 1 ps,
|
||||||
|
..
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
instant: 66 μs,
|
||||||
|
clocks_triggered: [
|
||||||
|
StatePartIndex<SmallSlots>(1),
|
||||||
|
],
|
||||||
|
..
|
||||||
|
}
|
193
crates/fayalite/tests/sim/expected/shift_register.vcd
Normal file
193
crates/fayalite/tests/sim/expected/shift_register.vcd
Normal file
|
@ -0,0 +1,193 @@
|
||||||
|
$timescale 1 ps $end
|
||||||
|
$scope module shift_register $end
|
||||||
|
$scope struct cd $end
|
||||||
|
$var wire 1 ! clk $end
|
||||||
|
$var wire 1 " rst $end
|
||||||
|
$upscope $end
|
||||||
|
$var wire 1 # d $end
|
||||||
|
$var wire 1 $ q $end
|
||||||
|
$var reg 1 % reg0 $end
|
||||||
|
$var reg 1 & reg1 $end
|
||||||
|
$var reg 1 ' reg2 $end
|
||||||
|
$var reg 1 ( reg3 $end
|
||||||
|
$upscope $end
|
||||||
|
$enddefinitions $end
|
||||||
|
$dumpvars
|
||||||
|
0!
|
||||||
|
1"
|
||||||
|
0#
|
||||||
|
0$
|
||||||
|
0%
|
||||||
|
0&
|
||||||
|
0'
|
||||||
|
0(
|
||||||
|
$end
|
||||||
|
#1000000
|
||||||
|
1!
|
||||||
|
#1100000
|
||||||
|
0"
|
||||||
|
#2000000
|
||||||
|
0!
|
||||||
|
#3000000
|
||||||
|
1!
|
||||||
|
#4000000
|
||||||
|
0!
|
||||||
|
1#
|
||||||
|
#5000000
|
||||||
|
1!
|
||||||
|
1%
|
||||||
|
#6000000
|
||||||
|
0!
|
||||||
|
#7000000
|
||||||
|
1!
|
||||||
|
1&
|
||||||
|
#8000000
|
||||||
|
0!
|
||||||
|
0#
|
||||||
|
#9000000
|
||||||
|
1!
|
||||||
|
0%
|
||||||
|
1'
|
||||||
|
#10000000
|
||||||
|
0!
|
||||||
|
#11000000
|
||||||
|
1!
|
||||||
|
0&
|
||||||
|
1(
|
||||||
|
1$
|
||||||
|
#12000000
|
||||||
|
0!
|
||||||
|
1#
|
||||||
|
#13000000
|
||||||
|
1!
|
||||||
|
1%
|
||||||
|
0'
|
||||||
|
#14000000
|
||||||
|
0!
|
||||||
|
0#
|
||||||
|
#15000000
|
||||||
|
1!
|
||||||
|
0%
|
||||||
|
1&
|
||||||
|
0(
|
||||||
|
0$
|
||||||
|
#16000000
|
||||||
|
0!
|
||||||
|
1#
|
||||||
|
#17000000
|
||||||
|
1!
|
||||||
|
1%
|
||||||
|
0&
|
||||||
|
1'
|
||||||
|
#18000000
|
||||||
|
0!
|
||||||
|
#19000000
|
||||||
|
1!
|
||||||
|
1&
|
||||||
|
0'
|
||||||
|
1(
|
||||||
|
1$
|
||||||
|
#20000000
|
||||||
|
0!
|
||||||
|
#21000000
|
||||||
|
1!
|
||||||
|
1'
|
||||||
|
0(
|
||||||
|
0$
|
||||||
|
#22000000
|
||||||
|
0!
|
||||||
|
#23000000
|
||||||
|
1!
|
||||||
|
1(
|
||||||
|
1$
|
||||||
|
#24000000
|
||||||
|
0!
|
||||||
|
0#
|
||||||
|
#25000000
|
||||||
|
1!
|
||||||
|
0%
|
||||||
|
#26000000
|
||||||
|
0!
|
||||||
|
#27000000
|
||||||
|
1!
|
||||||
|
0&
|
||||||
|
#28000000
|
||||||
|
0!
|
||||||
|
#29000000
|
||||||
|
1!
|
||||||
|
0'
|
||||||
|
#30000000
|
||||||
|
0!
|
||||||
|
#31000000
|
||||||
|
1!
|
||||||
|
0(
|
||||||
|
0$
|
||||||
|
#32000000
|
||||||
|
0!
|
||||||
|
#33000000
|
||||||
|
1!
|
||||||
|
#34000000
|
||||||
|
0!
|
||||||
|
#35000000
|
||||||
|
1!
|
||||||
|
#36000000
|
||||||
|
0!
|
||||||
|
#37000000
|
||||||
|
1!
|
||||||
|
#38000000
|
||||||
|
0!
|
||||||
|
#39000000
|
||||||
|
1!
|
||||||
|
#40000000
|
||||||
|
0!
|
||||||
|
#41000000
|
||||||
|
1!
|
||||||
|
#42000000
|
||||||
|
0!
|
||||||
|
#43000000
|
||||||
|
1!
|
||||||
|
#44000000
|
||||||
|
0!
|
||||||
|
#45000000
|
||||||
|
1!
|
||||||
|
#46000000
|
||||||
|
0!
|
||||||
|
#47000000
|
||||||
|
1!
|
||||||
|
#48000000
|
||||||
|
0!
|
||||||
|
#49000000
|
||||||
|
1!
|
||||||
|
#50000000
|
||||||
|
0!
|
||||||
|
#51000000
|
||||||
|
1!
|
||||||
|
#52000000
|
||||||
|
0!
|
||||||
|
#53000000
|
||||||
|
1!
|
||||||
|
#54000000
|
||||||
|
0!
|
||||||
|
#55000000
|
||||||
|
1!
|
||||||
|
#56000000
|
||||||
|
0!
|
||||||
|
#57000000
|
||||||
|
1!
|
||||||
|
#58000000
|
||||||
|
0!
|
||||||
|
#59000000
|
||||||
|
1!
|
||||||
|
#60000000
|
||||||
|
0!
|
||||||
|
#61000000
|
||||||
|
1!
|
||||||
|
#62000000
|
||||||
|
0!
|
||||||
|
#63000000
|
||||||
|
1!
|
||||||
|
#64000000
|
||||||
|
0!
|
||||||
|
#65000000
|
||||||
|
1!
|
||||||
|
#66000000
|
|
@ -1047,9 +1047,9 @@
|
||||||
"clock_domain()": "Visible",
|
"clock_domain()": "Visible",
|
||||||
"init()": "Visible"
|
"init()": "Visible"
|
||||||
},
|
},
|
||||||
"generics": "<T: Type>",
|
"generics": "<T: Type, R: ResetType>",
|
||||||
"fold_where": "T: Fold<State>",
|
"fold_where": "T: Fold<State>, R: Fold<State>",
|
||||||
"visit_where": "T: Visit<State>"
|
"visit_where": "T: Visit<State>, R: Visit<State>"
|
||||||
},
|
},
|
||||||
"Wire": {
|
"Wire": {
|
||||||
"data": {
|
"data": {
|
||||||
|
@ -1078,6 +1078,8 @@
|
||||||
"$kind": "Enum",
|
"$kind": "Enum",
|
||||||
"Wire": "Visible",
|
"Wire": "Visible",
|
||||||
"Reg": "Visible",
|
"Reg": "Visible",
|
||||||
|
"RegSync": "Visible",
|
||||||
|
"RegAsync": "Visible",
|
||||||
"Instance": "Visible"
|
"Instance": "Visible"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -1136,7 +1138,10 @@
|
||||||
"$kind": "Struct",
|
"$kind": "Struct",
|
||||||
"annotations": "Visible",
|
"annotations": "Visible",
|
||||||
"reg": "Visible"
|
"reg": "Visible"
|
||||||
}
|
},
|
||||||
|
"generics": "<R: ResetType>",
|
||||||
|
"fold_where": "R: Fold<State>",
|
||||||
|
"visit_where": "R: Visit<State>"
|
||||||
},
|
},
|
||||||
"StmtWire": {
|
"StmtWire": {
|
||||||
"data": {
|
"data": {
|
||||||
|
@ -1219,6 +1224,8 @@
|
||||||
"ModuleIO": "Visible",
|
"ModuleIO": "Visible",
|
||||||
"MemPort": "Visible",
|
"MemPort": "Visible",
|
||||||
"Reg": "Visible",
|
"Reg": "Visible",
|
||||||
|
"RegSync": "Visible",
|
||||||
|
"RegAsync": "Visible",
|
||||||
"Wire": "Visible",
|
"Wire": "Visible",
|
||||||
"Instance": "Visible"
|
"Instance": "Visible"
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,7 +46,7 @@ function main()
|
||||||
*/LICENSE.md|*/Notices.txt)
|
*/LICENSE.md|*/Notices.txt)
|
||||||
# copyright file
|
# copyright file
|
||||||
;;
|
;;
|
||||||
/crates/fayalite/tests/ui/*.stderr)
|
/crates/fayalite/tests/ui/*.stderr|/crates/fayalite/tests/sim/expected/*.vcd|/crates/fayalite/tests/sim/expected/*.txt)
|
||||||
# file that can't contain copyright header
|
# file that can't contain copyright header
|
||||||
;;
|
;;
|
||||||
/.forgejo/workflows/*.yml|*/.gitignore|*.toml)
|
/.forgejo/workflows/*.yml|*/.gitignore|*.toml)
|
||||||
|
|
Loading…
Reference in a new issue