Compare commits

..

No commits in common. "master" and "fifo-proof" have entirely different histories.

96 changed files with 13781 additions and 28760 deletions

View file

@ -12,10 +12,10 @@ jobs:
outputs: outputs:
cache-primary-key: ${{ steps.restore-deps.outputs.cache-primary-key }} cache-primary-key: ${{ steps.restore-deps.outputs.cache-primary-key }}
steps: steps:
- uses: https://git.libre-chip.org/mirrors/checkout@v3 - uses: https://code.forgejo.org/actions/checkout@v3
with: with:
fetch-depth: 0 fetch-depth: 0
- uses: https://git.libre-chip.org/mirrors/cache/restore@v3 - uses: https://code.forgejo.org/actions/cache/restore@v3
id: restore-deps id: restore-deps
with: with:
path: deps path: deps
@ -58,19 +58,19 @@ jobs:
- name: Get SymbiYosys - name: Get SymbiYosys
if: steps.restore-deps.outputs.cache-hit != 'true' if: steps.restore-deps.outputs.cache-hit != 'true'
run: | run: |
git clone --depth=1 --branch=yosys-0.45 https://git.libre-chip.org/mirrors/sby deps/sby git clone --depth=1 --branch=yosys-0.45 https://github.com/YosysHQ/sby.git deps/sby
- name: Build Z3 - name: Build Z3
if: steps.restore-deps.outputs.cache-hit != 'true' if: steps.restore-deps.outputs.cache-hit != 'true'
run: | run: |
git clone --depth=1 --recursive --branch=z3-4.13.3 https://git.libre-chip.org/mirrors/z3 deps/z3 git clone --depth=1 --recursive --branch=z3-4.13.3 https://github.com/Z3Prover/z3.git deps/z3
(cd deps/z3; PYTHON=python3 ./configure --prefix=/usr/local) (cd deps/z3; PYTHON=python3 ./configure --prefix=/usr/local)
make -C deps/z3/build -j"$(nproc)" make -C deps/z3/build -j"$(nproc)"
- name: Build Yosys - name: Build Yosys
if: steps.restore-deps.outputs.cache-hit != 'true' if: steps.restore-deps.outputs.cache-hit != 'true'
run: | run: |
git clone --depth=1 --recursive --branch=0.45 https://git.libre-chip.org/mirrors/yosys deps/yosys git clone --depth=1 --recursive --branch=0.45 https://github.com/YosysHQ/yosys.git deps/yosys
make -C deps/yosys -j"$(nproc)" make -C deps/yosys -j"$(nproc)"
- uses: https://git.libre-chip.org/mirrors/cache/save@v3 - uses: https://code.forgejo.org/actions/cache/save@v3
if: steps.restore-deps.outputs.cache-hit != 'true' if: steps.restore-deps.outputs.cache-hit != 'true'
with: with:
path: deps path: deps

View file

@ -4,13 +4,12 @@ on: [push, pull_request]
jobs: jobs:
deps: deps:
runs-on: debian-12
uses: ./.forgejo/workflows/deps.yml uses: ./.forgejo/workflows/deps.yml
test: test:
runs-on: debian-12 runs-on: debian-12
needs: deps needs: deps
steps: steps:
- uses: https://git.libre-chip.org/mirrors/checkout@v3 - uses: https://code.forgejo.org/actions/checkout@v3
with: with:
fetch-depth: 0 fetch-depth: 0
- run: | - run: |
@ -39,11 +38,10 @@ 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.89.0 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"
rustup component add rust-src
echo "$PATH" >> "$GITHUB_PATH" echo "$PATH" >> "$GITHUB_PATH"
- uses: https://git.libre-chip.org/mirrors/cache/restore@v3 - uses: https://code.forgejo.org/actions/cache/restore@v3
with: with:
path: deps path: deps
key: ${{ needs.deps.outputs.cache-primary-key }} key: ${{ needs.deps.outputs.cache-primary-key }}
@ -54,11 +52,10 @@ jobs:
make -C deps/yosys install make -C deps/yosys install
export PATH="$(realpath deps/firtool/bin):$PATH" export PATH="$(realpath deps/firtool/bin):$PATH"
echo "$PATH" >> "$GITHUB_PATH" echo "$PATH" >> "$GITHUB_PATH"
- uses: https://git.libre-chip.org/mirrors/rust-cache@v2 - uses: https://github.com/Swatinem/rust-cache@v2
with: with:
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 test --doc --features=unstable-doc
- run: cargo doc --features=unstable-doc - run: cargo doc --features=unstable-doc
- run: FAYALITE_TEST_HASHER=always_zero cargo test --test=module --features=unstable-doc,unstable-test-hasher

56
Cargo.lock generated
View file

@ -2,6 +2,18 @@
# It is not intended for manual editing. # It is not intended for manual editing.
version = 3 version = 3
[[package]]
name = "ahash"
version = "0.8.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77c3a9648d43b9cd48db467b3f87fdd6e146bcc88ab0180006cef2179fe11d01"
dependencies = [
"cfg-if",
"once_cell",
"version_check",
"zerocopy",
]
[[package]] [[package]]
name = "allocator-api2" name = "allocator-api2"
version = "0.2.16" version = "0.2.16"
@ -353,12 +365,6 @@ version = "0.5.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99"
[[package]]
name = "foldhash"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
[[package]] [[package]]
name = "funty" name = "funty"
version = "2.0.0" version = "2.0.0"
@ -394,13 +400,12 @@ checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
[[package]] [[package]]
name = "hashbrown" name = "hashbrown"
version = "0.15.2" version = "0.14.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
dependencies = [ dependencies = [
"ahash",
"allocator-api2", "allocator-api2",
"equivalent",
"foldhash",
] ]
[[package]] [[package]]
@ -426,9 +431,9 @@ checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683"
[[package]] [[package]]
name = "indexmap" name = "indexmap"
version = "2.9.0" 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 = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5"
dependencies = [ dependencies = [
"equivalent", "equivalent",
"hashbrown", "hashbrown",
@ -519,14 +524,11 @@ dependencies = [
[[package]] [[package]]
name = "petgraph" name = "petgraph"
version = "0.8.1" version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "git+https://github.com/programmerjake/petgraph.git?rev=258ea8071209a924b73fe96f9f87a3b7b45cbc9f#258ea8071209a924b73fe96f9f87a3b7b45cbc9f"
checksum = "7a98c6720655620a521dcc722d0ad66cd8afd5d86e34a89ef691c50b7b24de06"
dependencies = [ dependencies = [
"fixedbitset", "fixedbitset",
"hashbrown",
"indexmap", "indexmap",
"serde",
] ]
[[package]] [[package]]
@ -891,3 +893,23 @@ checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed"
dependencies = [ dependencies = [
"tap", "tap",
] ]
[[package]]
name = "zerocopy"
version = "0.7.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be"
dependencies = [
"zerocopy-derive",
]
[[package]]
name = "zerocopy-derive"
version = "0.7.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6"
dependencies = [
"proc-macro2",
"quote",
"syn",
]

View file

@ -7,11 +7,11 @@ members = ["crates/*"]
[workspace.package] [workspace.package]
version = "0.3.0" version = "0.3.0"
license = "LGPL-3.0-or-later" license = "LGPL-3.0-or-later"
edition = "2024" 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.89.0" rust-version = "1.82.0"
[workspace.dependencies] [workspace.dependencies]
fayalite-proc-macros = { version = "=0.3.0", path = "crates/fayalite-proc-macros" } fayalite-proc-macros = { version = "=0.3.0", path = "crates/fayalite-proc-macros" }
@ -23,13 +23,14 @@ blake3 = { version = "1.5.4", features = ["serde"] }
clap = { version = "4.5.9", features = ["derive", "env", "string"] } 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.15.2" hashbrown = "0.14.3"
indexmap = { version = "2.5.0", features = ["serde"] } indexmap = { version = "2.5.0", features = ["serde"] }
jobslot = "0.2.19" jobslot = "0.2.19"
num-bigint = "0.4.6" 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"
petgraph = "0.8.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"

View file

@ -7,11 +7,3 @@ See Notices.txt for copyright information
Fayalite is a library for designing digital hardware -- a hardware description language (HDL) embedded in the Rust programming language. Fayalite's semantics are based on [FIRRTL] as interpreted by [LLVM CIRCT](https://circt.llvm.org/docs/Dialects/FIRRTL/FIRRTLAnnotations/). Fayalite is a library for designing digital hardware -- a hardware description language (HDL) embedded in the Rust programming language. Fayalite's semantics are based on [FIRRTL] as interpreted by [LLVM CIRCT](https://circt.llvm.org/docs/Dialects/FIRRTL/FIRRTLAnnotations/).
[FIRRTL]: https://github.com/chipsalliance/firrtl-spec [FIRRTL]: https://github.com/chipsalliance/firrtl-spec
# Funding
## NLnet Grants
* [Libre-Chip CPU with proof of No Spectre bugs](https://nlnet.nl/project/Libre-Chip-proof/) 2024-12-324 [(progress)](https://git.libre-chip.org/libre-chip/grant-tracking/src/branch/master/nlnet-2024-12-324/progress.md)
This project was funded through the [NGI0 Commons Fund](https://nlnet.nl/commonsfund), a fund established by [NLnet](https://nlnet.nl/) with financial support from the European Commission's [Next Generation Internet](https://ngi.eu) programme, under the aegis of [DG Communications Networks, Content and Technology](https://commission.europa.eu/about-european-commission/departments-and-executive-agencies/communications-networks-content-and-technology_en) under grant agreement № [101135429](https://cordis.europa.eu/project/id/101135429). Additional funding is made available by the [Swiss State Secretariat for Education, Research and Innovation](https://www.sbfi.admin.ch/sbfi/en/home.html) (SERI).

View file

@ -220,7 +220,6 @@ forward_fold!(syn::ExprArray => fold_expr_array);
forward_fold!(syn::ExprCall => fold_expr_call); forward_fold!(syn::ExprCall => fold_expr_call);
forward_fold!(syn::ExprIf => fold_expr_if); forward_fold!(syn::ExprIf => fold_expr_if);
forward_fold!(syn::ExprMatch => fold_expr_match); forward_fold!(syn::ExprMatch => fold_expr_match);
forward_fold!(syn::ExprMethodCall => fold_expr_method_call);
forward_fold!(syn::ExprPath => fold_expr_path); forward_fold!(syn::ExprPath => fold_expr_path);
forward_fold!(syn::ExprRepeat => fold_expr_repeat); forward_fold!(syn::ExprRepeat => fold_expr_repeat);
forward_fold!(syn::ExprStruct => fold_expr_struct); forward_fold!(syn::ExprStruct => fold_expr_struct);

View file

@ -1,22 +1,21 @@
// 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::{
Errors, HdlAttr, PairsIterExt,
hdl_type_common::{ hdl_type_common::{
ItemOptions, MakeHdlTypeExpr, MaybeParsed, ParsedField, ParsedFieldsNamed, ParsedGenerics, common_derives, get_target, ItemOptions, MakeHdlTypeExpr, MaybeParsed, ParsedField,
SplitForImpl, TypesParser, WrappedInConst, common_derives, get_target, ParsedFieldsNamed, ParsedGenerics, SplitForImpl, TypesParser, WrappedInConst,
}, },
kw, kw, Errors, HdlAttr, PairsIterExt,
}; };
use proc_macro2::TokenStream; use proc_macro2::TokenStream;
use quote::{ToTokens, format_ident, quote_spanned}; use quote::{format_ident, quote_spanned, ToTokens};
use syn::{ use syn::{
AngleBracketedGenericArguments, Attribute, Field, FieldMutability, Fields, FieldsNamed, parse_quote, parse_quote_spanned,
GenericParam, Generics, Ident, ItemStruct, Path, Token, Type, Visibility, parse_quote,
parse_quote_spanned,
punctuated::{Pair, Punctuated}, punctuated::{Pair, Punctuated},
spanned::Spanned, spanned::Spanned,
token::Brace, token::Brace,
AngleBracketedGenericArguments, Attribute, Field, FieldMutability, Fields, FieldsNamed,
GenericParam, Generics, Ident, ItemStruct, Path, Token, Type, Visibility,
}; };
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@ -31,9 +30,7 @@ pub(crate) struct ParsedBundle {
pub(crate) field_flips: Vec<Option<HdlAttr<kw::flip, kw::hdl>>>, pub(crate) field_flips: Vec<Option<HdlAttr<kw::flip, kw::hdl>>>,
pub(crate) mask_type_ident: Ident, pub(crate) mask_type_ident: Ident,
pub(crate) mask_type_match_variant_ident: Ident, pub(crate) mask_type_match_variant_ident: Ident,
pub(crate) mask_type_sim_value_ident: Ident,
pub(crate) match_variant_ident: Ident, pub(crate) match_variant_ident: Ident,
pub(crate) sim_value_ident: Ident,
pub(crate) builder_ident: Ident, pub(crate) builder_ident: Ident,
pub(crate) mask_type_builder_ident: Ident, pub(crate) mask_type_builder_ident: Ident,
} }
@ -86,7 +83,6 @@ 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,
@ -128,9 +124,7 @@ impl ParsedBundle {
field_flips, field_flips,
mask_type_ident: format_ident!("__{}__MaskType", ident), mask_type_ident: format_ident!("__{}__MaskType", ident),
mask_type_match_variant_ident: format_ident!("__{}__MaskType__MatchVariant", ident), mask_type_match_variant_ident: format_ident!("__{}__MaskType__MatchVariant", ident),
mask_type_sim_value_ident: format_ident!("__{}__MaskType__SimValue", ident),
match_variant_ident: format_ident!("__{}__MatchVariant", ident), match_variant_ident: format_ident!("__{}__MatchVariant", ident),
sim_value_ident: format_ident!("__{}__SimValue", ident),
mask_type_builder_ident: format_ident!("__{}__MaskType__Builder", ident), mask_type_builder_ident: format_ident!("__{}__MaskType__Builder", ident),
builder_ident: format_ident!("__{}__Builder", ident), builder_ident: format_ident!("__{}__Builder", ident),
ident, ident,
@ -432,9 +426,7 @@ impl ToTokens for ParsedBundle {
field_flips, field_flips,
mask_type_ident, mask_type_ident,
mask_type_match_variant_ident, mask_type_match_variant_ident,
mask_type_sim_value_ident,
match_variant_ident, match_variant_ident,
sim_value_ident,
builder_ident, builder_ident,
mask_type_builder_ident, mask_type_builder_ident,
} = self; } = self;
@ -445,7 +437,6 @@ 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();
@ -530,7 +521,7 @@ impl ToTokens for ParsedBundle {
semi_token: None, semi_token: None,
} }
.to_tokens(tokens); .to_tokens(tokens);
let mut mask_type_match_variant_fields = mask_type_fields.clone(); let mut mask_type_match_variant_fields = mask_type_fields;
for Field { ty, .. } in &mut mask_type_match_variant_fields.named { for Field { ty, .. } in &mut mask_type_match_variant_fields.named {
*ty = parse_quote_spanned! {span=> *ty = parse_quote_spanned! {span=>
::fayalite::expr::Expr<#ty> ::fayalite::expr::Expr<#ty>
@ -572,58 +563,6 @@ impl ToTokens for ParsedBundle {
semi_token: None, semi_token: None,
} }
.to_tokens(tokens); .to_tokens(tokens);
let mut mask_type_sim_value_fields = mask_type_fields;
for Field { ty, .. } in &mut mask_type_sim_value_fields.named {
*ty = parse_quote_spanned! {span=>
::fayalite::sim::value::SimValue<#ty>
};
}
ItemStruct {
attrs: vec![
parse_quote_spanned! {span=>
#[::fayalite::__std::prelude::v1::derive(
::fayalite::__std::fmt::Debug,
::fayalite::__std::clone::Clone,
)]
},
parse_quote_spanned! {span=>
#[allow(non_camel_case_types, dead_code)]
},
],
vis: vis.clone(),
struct_token: *struct_token,
ident: mask_type_sim_value_ident.clone(),
generics: generics.into(),
fields: Fields::Named(mask_type_sim_value_fields),
semi_token: None,
}
.to_tokens(tokens);
let mut sim_value_fields = FieldsNamed::from(fields.clone());
for Field { ty, .. } in &mut sim_value_fields.named {
*ty = parse_quote_spanned! {span=>
::fayalite::sim::value::SimValue<#ty>
};
}
ItemStruct {
attrs: vec![
parse_quote_spanned! {span=>
#[::fayalite::__std::prelude::v1::derive(
::fayalite::__std::fmt::Debug,
::fayalite::__std::clone::Clone,
)]
},
parse_quote_spanned! {span=>
#[allow(non_camel_case_types, dead_code)]
},
],
vis: vis.clone(),
struct_token: *struct_token,
ident: sim_value_ident.clone(),
generics: generics.into(),
fields: Fields::Named(sim_value_fields),
semi_token: None,
}
.to_tokens(tokens);
let this_token = Ident::new("__this", span); let this_token = Ident::new("__this", span);
let fields_token = Ident::new("__fields", span); let fields_token = Ident::new("__fields", span);
let self_token = Token![self](span); let self_token = Token![self](span);
@ -674,32 +613,6 @@ impl ToTokens for ParsedBundle {
} }
}, },
)); ));
let sim_value_from_opaque_fields =
Vec::from_iter(fields.named().into_iter().map(|field| {
let ident: &Ident = field.ident().as_ref().unwrap();
quote_spanned! {span=>
#ident: v.field_from_opaque(),
}
}));
let sim_value_clone_from_opaque_fields =
Vec::from_iter(fields.named().into_iter().map(|field| {
let ident: &Ident = field.ident().as_ref().unwrap();
quote_spanned! {span=>
v.field_clone_from_opaque(&mut value.#ident);
}
}));
let sim_value_to_opaque_fields = Vec::from_iter(fields.named().into_iter().map(|field| {
let ident: &Ident = field.ident().as_ref().unwrap();
quote_spanned! {span=>
v.field(&value.#ident);
}
}));
let to_sim_value_fields = Vec::from_iter(fields.named().into_iter().map(|field| {
let ident: &Ident = field.ident().as_ref().unwrap();
quote_spanned! {span=>
#ident: ::fayalite::sim::value::SimValue::ty(&self.#ident),
}
}));
let fields_len = fields.named().into_iter().len(); let fields_len = fields.named().into_iter().len();
quote_spanned! {span=> quote_spanned! {span=>
#[automatically_derived] #[automatically_derived]
@ -708,7 +621,6 @@ impl ToTokens for ParsedBundle {
{ {
type BaseType = ::fayalite::bundle::Bundle; type BaseType = ::fayalite::bundle::Bundle;
type MaskType = #mask_type_ident #type_generics; type MaskType = #mask_type_ident #type_generics;
type SimValue = #mask_type_sim_value_ident #type_generics;
type MatchVariant = #mask_type_match_variant_ident #type_generics; type MatchVariant = #mask_type_match_variant_ident #type_generics;
type MatchActiveScope = (); type MatchActiveScope = ();
type MatchVariantAndInactiveScope = ::fayalite::ty::MatchVariantWithoutScope< type MatchVariantAndInactiveScope = ::fayalite::ty::MatchVariantWithoutScope<
@ -746,35 +658,6 @@ impl ToTokens for ParsedBundle {
fn source_location() -> ::fayalite::source_location::SourceLocation { fn source_location() -> ::fayalite::source_location::SourceLocation {
::fayalite::source_location::SourceLocation::caller() ::fayalite::source_location::SourceLocation::caller()
} }
fn sim_value_from_opaque(
&self,
opaque: ::fayalite::ty::OpaqueSimValueSlice<'_>,
) -> <Self as ::fayalite::ty::Type>::SimValue {
#![allow(unused_mut, unused_variables)]
let mut v = ::fayalite::bundle::BundleSimValueFromOpaque::new(*self, opaque);
#mask_type_sim_value_ident {
#(#sim_value_from_opaque_fields)*
}
}
fn sim_value_clone_from_opaque(
&self,
value: &mut <Self as ::fayalite::ty::Type>::SimValue,
opaque: ::fayalite::ty::OpaqueSimValueSlice<'_>,
) {
#![allow(unused_mut, unused_variables)]
let mut v = ::fayalite::bundle::BundleSimValueFromOpaque::new(*self, opaque);
#(#sim_value_clone_from_opaque_fields)*
}
fn sim_value_to_opaque<'__w>(
&self,
value: &<Self as ::fayalite::ty::Type>::SimValue,
writer: ::fayalite::ty::OpaqueSimValueWriter<'__w>,
) -> ::fayalite::ty::OpaqueSimValueWritten<'__w> {
#![allow(unused_mut, unused_variables)]
let mut v = ::fayalite::bundle::BundleSimValueToOpaque::new(*self, writer);
#(#sim_value_to_opaque_fields)*
v.finish()
}
} }
#[automatically_derived] #[automatically_derived]
impl #impl_generics ::fayalite::bundle::BundleType for #mask_type_ident #type_generics impl #impl_generics ::fayalite::bundle::BundleType for #mask_type_ident #type_generics
@ -806,57 +689,11 @@ impl ToTokens for ParsedBundle {
} }
} }
#[automatically_derived] #[automatically_derived]
impl #impl_generics ::fayalite::sim::value::ToSimValue for #mask_type_sim_value_ident #type_generics
#where_clause
{
type Type = #mask_type_ident #type_generics;
fn to_sim_value(
&self,
) -> ::fayalite::sim::value::SimValue<
<Self as ::fayalite::sim::value::ToSimValue>::Type,
> {
let ty = #mask_type_ident {
#(#to_sim_value_fields)*
};
::fayalite::sim::value::SimValue::from_value(ty, ::fayalite::__std::clone::Clone::clone(self))
}
fn into_sim_value(
self,
) -> ::fayalite::sim::value::SimValue<
<Self as ::fayalite::sim::value::ToSimValue>::Type,
> {
let ty = #mask_type_ident {
#(#to_sim_value_fields)*
};
::fayalite::sim::value::SimValue::from_value(ty, self)
}
}
#[automatically_derived]
impl #impl_generics ::fayalite::sim::value::ToSimValueWithType<#mask_type_ident #type_generics>
for #mask_type_sim_value_ident #type_generics
#where_clause
{
fn to_sim_value_with_type(
&self,
ty: #mask_type_ident #type_generics,
) -> ::fayalite::sim::value::SimValue<#mask_type_ident #type_generics> {
::fayalite::sim::value::SimValue::from_value(ty, ::fayalite::__std::clone::Clone::clone(self))
}
fn into_sim_value_with_type(
self,
ty: #mask_type_ident #type_generics,
) -> ::fayalite::sim::value::SimValue<#mask_type_ident #type_generics> {
::fayalite::sim::value::SimValue::from_value(ty, self)
}
}
#[automatically_derived]
impl #impl_generics ::fayalite::ty::Type for #target #type_generics impl #impl_generics ::fayalite::ty::Type for #target #type_generics
#where_clause #where_clause
{ {
type BaseType = ::fayalite::bundle::Bundle; type BaseType = ::fayalite::bundle::Bundle;
type MaskType = #mask_type_ident #type_generics; type MaskType = #mask_type_ident #type_generics;
type SimValue = #sim_value_ident #type_generics;
type MatchVariant = #match_variant_ident #type_generics; type MatchVariant = #match_variant_ident #type_generics;
type MatchActiveScope = (); type MatchActiveScope = ();
type MatchVariantAndInactiveScope = ::fayalite::ty::MatchVariantWithoutScope< type MatchVariantAndInactiveScope = ::fayalite::ty::MatchVariantWithoutScope<
@ -896,35 +733,6 @@ impl ToTokens for ParsedBundle {
fn source_location() -> ::fayalite::source_location::SourceLocation { fn source_location() -> ::fayalite::source_location::SourceLocation {
::fayalite::source_location::SourceLocation::caller() ::fayalite::source_location::SourceLocation::caller()
} }
fn sim_value_from_opaque(
&self,
opaque: ::fayalite::ty::OpaqueSimValueSlice<'_>,
) -> <Self as ::fayalite::ty::Type>::SimValue {
#![allow(unused_mut, unused_variables)]
let mut v = ::fayalite::bundle::BundleSimValueFromOpaque::new(*self, opaque);
#sim_value_ident {
#(#sim_value_from_opaque_fields)*
}
}
fn sim_value_clone_from_opaque(
&self,
value: &mut <Self as ::fayalite::ty::Type>::SimValue,
opaque: ::fayalite::ty::OpaqueSimValueSlice<'_>,
) {
#![allow(unused_mut, unused_variables)]
let mut v = ::fayalite::bundle::BundleSimValueFromOpaque::new(*self, opaque);
#(#sim_value_clone_from_opaque_fields)*
}
fn sim_value_to_opaque<'__w>(
&self,
value: &<Self as ::fayalite::ty::Type>::SimValue,
writer: ::fayalite::ty::OpaqueSimValueWriter<'__w>,
) -> ::fayalite::ty::OpaqueSimValueWritten<'__w> {
#![allow(unused_mut, unused_variables)]
let mut v = ::fayalite::bundle::BundleSimValueToOpaque::new(*self, writer);
#(#sim_value_to_opaque_fields)*
v.finish()
}
} }
#[automatically_derived] #[automatically_derived]
impl #impl_generics ::fayalite::bundle::BundleType for #target #type_generics impl #impl_generics ::fayalite::bundle::BundleType for #target #type_generics
@ -955,144 +763,8 @@ impl ToTokens for ParsedBundle {
::fayalite::intern::Interned::into_inner(::fayalite::intern::Intern::intern_sized(__retval)) ::fayalite::intern::Interned::into_inner(::fayalite::intern::Intern::intern_sized(__retval))
} }
} }
#[automatically_derived]
impl #impl_generics ::fayalite::sim::value::ToSimValue for #sim_value_ident #type_generics
#where_clause
{
type Type = #target #type_generics;
fn to_sim_value(
&self,
) -> ::fayalite::sim::value::SimValue<
<Self as ::fayalite::sim::value::ToSimValue>::Type,
> {
let ty = #target {
#(#to_sim_value_fields)*
};
::fayalite::sim::value::SimValue::from_value(ty, ::fayalite::__std::clone::Clone::clone(self))
}
fn into_sim_value(
self,
) -> ::fayalite::sim::value::SimValue<
<Self as ::fayalite::sim::value::ToSimValue>::Type,
> {
let ty = #target {
#(#to_sim_value_fields)*
};
::fayalite::sim::value::SimValue::from_value(ty, self)
}
}
#[automatically_derived]
impl #impl_generics ::fayalite::sim::value::ToSimValueWithType<#target #type_generics>
for #sim_value_ident #type_generics
#where_clause
{
fn to_sim_value_with_type(
&self,
ty: #target #type_generics,
) -> ::fayalite::sim::value::SimValue<#target #type_generics> {
::fayalite::sim::value::SimValue::from_value(ty, ::fayalite::__std::clone::Clone::clone(self))
}
fn into_sim_value_with_type(
self,
ty: #target #type_generics,
) -> ::fayalite::sim::value::SimValue<#target #type_generics> {
::fayalite::sim::value::SimValue::from_value(ty, self)
}
}
} }
.to_tokens(tokens); .to_tokens(tokens);
if let Some((cmp_eq,)) = cmp_eq {
let mut expr_where_clause =
Generics::from(generics)
.where_clause
.unwrap_or_else(|| syn::WhereClause {
where_token: Token![where](span),
predicates: Punctuated::new(),
});
let mut sim_value_where_clause = expr_where_clause.clone();
let mut fields_sim_value_eq = vec![];
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();
expr_where_clause
.predicates
.push(parse_quote_spanned! {cmp_eq.span=>
#field_ty: ::fayalite::expr::ops::ExprPartialEq<#field_ty>
});
sim_value_where_clause
.predicates
.push(parse_quote_spanned! {cmp_eq.span=>
#field_ty: ::fayalite::sim::value::SimValuePartialEq<#field_ty>
});
fields_sim_value_eq.push(quote_spanned! {span=>
::fayalite::sim::value::SimValuePartialEq::sim_value_eq(&__lhs.#field_ident, &__rhs.#field_ident)
});
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 sim_value_eq_body;
let cmp_eq_body;
let cmp_ne_body;
if fields_len == 0 {
sim_value_eq_body = quote_spanned! {span=>
true
};
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 {
sim_value_eq_body = quote_spanned! {span=>
#(#fields_sim_value_eq)&&*
};
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
#expr_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
}
}
#[automatically_derived]
impl #impl_generics ::fayalite::sim::value::SimValuePartialEq<Self> for #target #type_generics
#sim_value_where_clause
{
fn sim_value_eq(
__lhs: &::fayalite::sim::value::SimValue<Self>,
__rhs: &::fayalite::sim::value::SimValue<Self>,
) -> bool {
#sim_value_eq_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) =
@ -1128,14 +800,6 @@ impl ToTokens for ParsedBundle {
} }
})); }));
quote_spanned! {span=> quote_spanned! {span=>
#[automatically_derived]
impl #static_impl_generics ::fayalite::__std::default::Default for #mask_type_ident #static_type_generics
#static_where_clause
{
fn default() -> Self {
<Self as ::fayalite::ty::StaticType>::TYPE
}
}
#[automatically_derived] #[automatically_derived]
impl #static_impl_generics ::fayalite::ty::StaticType for #mask_type_ident #static_type_generics impl #static_impl_generics ::fayalite::ty::StaticType for #mask_type_ident #static_type_generics
#static_where_clause #static_where_clause
@ -1158,15 +822,6 @@ impl ToTokens for ParsedBundle {
}; };
} }
#[automatically_derived] #[automatically_derived]
impl #static_impl_generics ::fayalite::__std::default::Default
for #target #static_type_generics
#static_where_clause
{
fn default() -> Self {
<Self as ::fayalite::ty::StaticType>::TYPE
}
}
#[automatically_derived]
impl #static_impl_generics ::fayalite::ty::StaticType for #target #static_type_generics impl #static_impl_generics ::fayalite::ty::StaticType for #target #static_type_generics
#static_where_clause #static_where_clause
{ {

View file

@ -1,20 +1,20 @@
// 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::{
Errors, HdlAttr, PairsIterExt,
hdl_type_common::{ hdl_type_common::{
ItemOptions, MakeHdlTypeExpr, MaybeParsed, ParsedGenerics, ParsedType, SplitForImpl, common_derives, get_target, ItemOptions, MakeHdlTypeExpr, MaybeParsed, ParsedGenerics,
TypesParser, WrappedInConst, common_derives, get_target, ParsedType, SplitForImpl, TypesParser, WrappedInConst,
}, },
kw, kw, Errors, HdlAttr, PairsIterExt,
}; };
use proc_macro2::TokenStream; use proc_macro2::TokenStream;
use quote::{ToTokens, format_ident, quote_spanned}; use quote::{format_ident, quote_spanned, ToTokens};
use syn::{ use syn::{
Attribute, Field, FieldMutability, Fields, FieldsNamed, FieldsUnnamed, Generics, Ident, parse_quote_spanned,
ItemEnum, ItemStruct, Token, Type, Variant, Visibility, parse_quote_spanned,
punctuated::{Pair, Punctuated}, punctuated::{Pair, Punctuated},
token::{Brace, Paren}, token::{Brace, Paren},
Attribute, Field, FieldMutability, Fields, FieldsNamed, FieldsUnnamed, Generics, Ident,
ItemEnum, ItemStruct, Token, Type, Variant, Visibility,
}; };
crate::options! { crate::options! {
@ -129,9 +129,6 @@ pub(crate) struct ParsedEnum {
pub(crate) brace_token: Brace, pub(crate) brace_token: Brace,
pub(crate) variants: Punctuated<ParsedVariant, Token![,]>, pub(crate) variants: Punctuated<ParsedVariant, Token![,]>,
pub(crate) match_variant_ident: Ident, pub(crate) match_variant_ident: Ident,
pub(crate) sim_value_ident: Ident,
pub(crate) sim_builder_ident: Ident,
pub(crate) sim_builder_ty_field_ident: Ident,
} }
impl ParsedEnum { impl ParsedEnum {
@ -158,11 +155,7 @@ 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");
@ -193,9 +186,6 @@ impl ParsedEnum {
brace_token, brace_token,
variants, variants,
match_variant_ident: format_ident!("__{}__MatchVariant", ident), match_variant_ident: format_ident!("__{}__MatchVariant", ident),
sim_value_ident: format_ident!("__{}__SimValue", ident),
sim_builder_ident: format_ident!("__{}__SimBuilder", ident),
sim_builder_ty_field_ident: format_ident!("__ty", span = ident.span()),
ident, ident,
}) })
} }
@ -213,9 +203,6 @@ impl ToTokens for ParsedEnum {
brace_token, brace_token,
variants, variants,
match_variant_ident, match_variant_ident,
sim_value_ident,
sim_builder_ident,
sim_builder_ty_field_ident,
} = self; } = self;
let span = ident.span(); let span = ident.span();
let ItemOptions { let ItemOptions {
@ -224,7 +211,6 @@ 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();
@ -418,133 +404,6 @@ impl ToTokens for ParsedEnum {
)), )),
} }
.to_tokens(tokens); .to_tokens(tokens);
let mut struct_attrs = attrs.clone();
struct_attrs.push(parse_quote_spanned! {span=>
#[allow(dead_code, non_camel_case_types)]
});
ItemStruct {
attrs: struct_attrs,
vis: vis.clone(),
struct_token: Token![struct](enum_token.span),
ident: sim_builder_ident.clone(),
generics: generics.into(),
fields: FieldsNamed {
brace_token: *brace_token,
named: Punctuated::from_iter([Field {
attrs: vec![],
vis: Visibility::Inherited,
mutability: FieldMutability::None,
ident: Some(sim_builder_ty_field_ident.clone()),
colon_token: Some(Token![:](span)),
ty: parse_quote_spanned! {span=>
#target #type_generics
},
}]),
}
.into(),
semi_token: None,
}
.to_tokens(tokens);
let mut enum_attrs = attrs.clone();
enum_attrs.push(parse_quote_spanned! {span=>
#[::fayalite::__std::prelude::v1::derive(
::fayalite::__std::fmt::Debug,
::fayalite::__std::clone::Clone,
)]
});
enum_attrs.push(parse_quote_spanned! {span=>
#[allow(dead_code, non_camel_case_types)]
});
let sim_value_has_unknown_variant = !variants.len().is_power_of_two();
let sim_value_unknown_variant_name = sim_value_has_unknown_variant.then(|| {
let mut name = String::new();
let unknown = "Unknown";
loop {
let orig_len = name.len();
name.push_str(unknown);
if variants.iter().all(|v| v.ident != name) {
break Ident::new(&name, span);
}
name.truncate(orig_len);
name.push('_');
}
});
let sim_value_unknown_variant =
sim_value_unknown_variant_name
.as_ref()
.map(|unknown_variant_name| {
Pair::End(parse_quote_spanned! {span=>
#unknown_variant_name(::fayalite::enum_::UnknownVariantSimValue)
})
});
ItemEnum {
attrs: enum_attrs,
vis: vis.clone(),
enum_token: *enum_token,
ident: sim_value_ident.clone(),
generics: generics.into(),
brace_token: *brace_token,
variants: Punctuated::from_iter(
variants
.pairs()
.map_pair_value_ref(
|ParsedVariant {
attrs,
options: _,
ident,
field,
}| Variant {
attrs: attrs.clone(),
ident: ident.clone(),
fields: match field {
Some(ParsedVariantField {
paren_token,
attrs,
options: _,
ty,
comma_token,
}) => Fields::Unnamed(FieldsUnnamed {
paren_token: *paren_token,
unnamed: Punctuated::from_iter([
Pair::new(
Field {
attrs: attrs.clone(),
vis: Visibility::Inherited,
mutability: FieldMutability::None,
ident: None,
colon_token: None,
ty: parse_quote_spanned! {span=>
::fayalite::sim::value::SimValue<#ty>
},
},
Some(comma_token.unwrap_or(Token![,](ident.span()))),
),
Pair::new(
Field {
attrs: vec![],
vis: Visibility::Inherited,
mutability: FieldMutability::None,
ident: None,
colon_token: None,
ty: parse_quote_spanned! {span=>
::fayalite::enum_::EnumPaddingSimValue
},
},
None,
),
]),
}),
None => Fields::Unnamed(parse_quote_spanned! {span=>
(::fayalite::enum_::EnumPaddingSimValue)
}),
},
discriminant: None,
},
)
.chain(sim_value_unknown_variant),
),
}
.to_tokens(tokens);
let self_token = Token![self](span); let self_token = Token![self](span);
for (index, ParsedVariant { ident, field, .. }) in variants.iter().enumerate() { for (index, ParsedVariant { ident, field, .. }) in variants.iter().enumerate() {
if let Some(ParsedVariantField { ty, .. }) = field { if let Some(ParsedVariantField { ty, .. }) = field {
@ -571,25 +430,6 @@ impl ToTokens for ParsedEnum {
) )
} }
} }
#[automatically_derived]
impl #impl_generics #sim_builder_ident #type_generics
#where_clause
{
#[allow(non_snake_case, dead_code)]
#vis fn #ident<__V: ::fayalite::sim::value::ToSimValueWithType<#ty>>(
#self_token,
v: __V,
) -> ::fayalite::sim::value::SimValue<#target #type_generics> {
let v = ::fayalite::sim::value::ToSimValueWithType::into_sim_value_with_type(
v,
#self_token.#sim_builder_ty_field_ident.#ident,
);
::fayalite::sim::value::SimValue::from_value(
#self_token.#sim_builder_ty_field_ident,
#sim_value_ident::#ident(v, ::fayalite::enum_::EnumPaddingSimValue::new()),
)
}
}
} }
} else { } else {
quote_spanned! {span=> quote_spanned! {span=>
@ -608,18 +448,6 @@ impl ToTokens for ParsedEnum {
) )
} }
} }
#[automatically_derived]
impl #impl_generics #sim_builder_ident #type_generics
#where_clause
{
#[allow(non_snake_case, dead_code)]
#vis fn #ident(#self_token) -> ::fayalite::sim::value::SimValue<#target #type_generics> {
::fayalite::sim::value::SimValue::from_value(
#self_token.#sim_builder_ty_field_ident,
#sim_value_ident::#ident(::fayalite::enum_::EnumPaddingSimValue::new()),
)
}
}
} }
} }
.to_tokens(tokens); .to_tokens(tokens);
@ -701,142 +529,6 @@ impl ToTokens for ParsedEnum {
} }
}, },
)); ));
let sim_value_from_opaque_unknown_match_arm = if let Some(sim_value_unknown_variant_name) =
&sim_value_unknown_variant_name
{
quote_spanned! {span=>
_ => #sim_value_ident::#sim_value_unknown_variant_name(v.unknown_variant_from_opaque()),
}
} else {
quote_spanned! {span=>
_ => ::fayalite::__std::unreachable!(),
}
};
let sim_value_from_opaque_match_arms = Vec::from_iter(
variants
.iter()
.enumerate()
.map(
|(
index,
ParsedVariant {
attrs: _,
options: _,
ident,
field,
},
)| {
if let Some(_) = field {
quote_spanned! {span=>
#index => {
let (field, padding) = v.variant_with_field_from_opaque();
#sim_value_ident::#ident(field, padding)
}
}
} else {
quote_spanned! {span=>
#index => #sim_value_ident::#ident(
v.variant_no_field_from_opaque(),
),
}
}
},
)
.chain([sim_value_from_opaque_unknown_match_arm]),
);
let sim_value_clone_from_opaque_unknown_match_arm =
if let Some(sim_value_unknown_variant_name) = &sim_value_unknown_variant_name {
quote_spanned! {span=>
_ => if let #sim_value_ident::#sim_value_unknown_variant_name(value) = value {
v.unknown_variant_clone_from_opaque(value);
} else {
*value = #sim_value_ident::#sim_value_unknown_variant_name(
v.unknown_variant_from_opaque(),
);
},
}
} else {
quote_spanned! {span=>
_ => ::fayalite::__std::unreachable!(),
}
};
let sim_value_clone_from_opaque_match_arms = Vec::from_iter(
variants
.iter()
.enumerate()
.map(
|(
index,
ParsedVariant {
attrs: _,
options: _,
ident,
field,
},
)| {
if let Some(_) = field {
quote_spanned! {span=>
#index => if let #sim_value_ident::#ident(field, padding) = value {
v.variant_with_field_clone_from_opaque(field, padding);
} else {
let (field, padding) = v.variant_with_field_from_opaque();
*value = #sim_value_ident::#ident(field, padding);
},
}
} else {
quote_spanned! {span=>
#index => if let #sim_value_ident::#ident(padding) = value {
v.variant_no_field_clone_from_opaque(padding);
} else {
*value = #sim_value_ident::#ident(
v.variant_no_field_from_opaque(),
);
},
}
}
},
)
.chain([sim_value_clone_from_opaque_unknown_match_arm]),
);
let sim_value_to_opaque_match_arms = Vec::from_iter(
variants
.iter()
.enumerate()
.map(
|(
index,
ParsedVariant {
attrs: _,
options: _,
ident,
field,
},
)| {
if let Some(_) = field {
quote_spanned! {span=>
#sim_value_ident::#ident(field, padding) => {
v.variant_with_field_to_opaque(#index, field, padding)
}
}
} else {
quote_spanned! {span=>
#sim_value_ident::#ident(padding) => {
v.variant_no_field_to_opaque(#index, padding)
}
}
}
},
)
.chain(sim_value_unknown_variant_name.as_ref().map(
|sim_value_unknown_variant_name| {
quote_spanned! {span=>
#sim_value_ident::#sim_value_unknown_variant_name(value) => {
v.unknown_variant_to_opaque(value)
}
}
},
)),
);
let variants_len = variants.len(); let variants_len = variants.len();
quote_spanned! {span=> quote_spanned! {span=>
#[automatically_derived] #[automatically_derived]
@ -845,7 +537,6 @@ impl ToTokens for ParsedEnum {
{ {
type BaseType = ::fayalite::enum_::Enum; type BaseType = ::fayalite::enum_::Enum;
type MaskType = ::fayalite::int::Bool; type MaskType = ::fayalite::int::Bool;
type SimValue = #sim_value_ident #type_generics;
type MatchVariant = #match_variant_ident #type_generics; type MatchVariant = #match_variant_ident #type_generics;
type MatchActiveScope = ::fayalite::module::Scope; type MatchActiveScope = ::fayalite::module::Scope;
type MatchVariantAndInactiveScope = ::fayalite::enum_::EnumMatchVariantAndInactiveScope<Self>; type MatchVariantAndInactiveScope = ::fayalite::enum_::EnumMatchVariantAndInactiveScope<Self>;
@ -878,41 +569,11 @@ impl ToTokens for ParsedEnum {
fn source_location() -> ::fayalite::source_location::SourceLocation { fn source_location() -> ::fayalite::source_location::SourceLocation {
::fayalite::source_location::SourceLocation::caller() ::fayalite::source_location::SourceLocation::caller()
} }
fn sim_value_from_opaque(
&self,
opaque: ::fayalite::ty::OpaqueSimValueSlice<'_>,
) -> <Self as ::fayalite::ty::Type>::SimValue {
let v = ::fayalite::enum_::EnumSimValueFromOpaque::new(*self, opaque);
match v.discriminant() {
#(#sim_value_from_opaque_match_arms)*
}
}
fn sim_value_clone_from_opaque(
&self,
value: &mut <Self as ::fayalite::ty::Type>::SimValue,
opaque: ::fayalite::ty::OpaqueSimValueSlice<'_>,
) {
let v = ::fayalite::enum_::EnumSimValueFromOpaque::new(*self, opaque);
match v.discriminant() {
#(#sim_value_clone_from_opaque_match_arms)*
}
}
fn sim_value_to_opaque<'__w>(
&self,
value: &<Self as ::fayalite::ty::Type>::SimValue,
writer: ::fayalite::ty::OpaqueSimValueWriter<'__w>,
) -> ::fayalite::ty::OpaqueSimValueWritten<'__w> {
let v = ::fayalite::enum_::EnumSimValueToOpaque::new(*self, writer);
match value {
#(#sim_value_to_opaque_match_arms)*
}
}
} }
#[automatically_derived] #[automatically_derived]
impl #impl_generics ::fayalite::enum_::EnumType for #target #type_generics impl #impl_generics ::fayalite::enum_::EnumType for #target #type_generics
#where_clause #where_clause
{ {
type SimBuilder = #sim_builder_ident #type_generics;
fn match_activate_scope( fn match_activate_scope(
v: <Self as ::fayalite::ty::Type>::MatchVariantAndInactiveScope, v: <Self as ::fayalite::ty::Type>::MatchVariantAndInactiveScope,
) -> (<Self as ::fayalite::ty::Type>::MatchVariant, <Self as ::fayalite::ty::Type>::MatchActiveScope) { ) -> (<Self as ::fayalite::ty::Type>::MatchVariant, <Self as ::fayalite::ty::Type>::MatchActiveScope) {
@ -931,33 +592,6 @@ impl ToTokens for ParsedEnum {
][..]) ][..])
} }
} }
#[automatically_derived]
impl #impl_generics ::fayalite::sim::value::ToSimValueWithType<#target #type_generics>
for #sim_value_ident #type_generics
#where_clause
{
fn to_sim_value_with_type(
&self,
ty: #target #type_generics,
) -> ::fayalite::sim::value::SimValue<#target #type_generics> {
::fayalite::sim::value::SimValue::from_value(ty, ::fayalite::__std::clone::Clone::clone(self))
}
fn into_sim_value_with_type(
self,
ty: #target #type_generics,
) -> ::fayalite::sim::value::SimValue<#target #type_generics> {
::fayalite::sim::value::SimValue::from_value(ty, self)
}
}
#[automatically_derived]
impl #impl_generics ::fayalite::__std::convert::From<#target #type_generics>
for #sim_builder_ident #type_generics
#where_clause
{
fn from(#sim_builder_ty_field_ident: #target #type_generics) -> Self {
Self { #sim_builder_ty_field_ident }
}
}
} }
.to_tokens(tokens); .to_tokens(tokens);
if let (None, MaybeParsed::Parsed(generics)) = (no_static, &self.generics) { if let (None, MaybeParsed::Parsed(generics)) = (no_static, &self.generics) {
@ -995,15 +629,6 @@ impl ToTokens for ParsedEnum {
} }
})); }));
quote_spanned! {span=> quote_spanned! {span=>
#[automatically_derived]
impl #static_impl_generics ::fayalite::__std::default::Default
for #target #static_type_generics
#static_where_clause
{
fn default() -> Self {
<Self as ::fayalite::ty::StaticType>::TYPE
}
}
#[automatically_derived] #[automatically_derived]
impl #static_impl_generics ::fayalite::ty::StaticType impl #static_impl_generics ::fayalite::ty::StaticType
for #target #static_type_generics for #target #static_type_generics
@ -1022,34 +647,6 @@ impl ToTokens for ParsedEnum {
const MASK_TYPE_PROPERTIES: ::fayalite::ty::TypeProperties = const MASK_TYPE_PROPERTIES: ::fayalite::ty::TypeProperties =
<::fayalite::int::Bool as ::fayalite::ty::StaticType>::TYPE_PROPERTIES; <::fayalite::int::Bool as ::fayalite::ty::StaticType>::TYPE_PROPERTIES;
} }
#[automatically_derived]
impl #static_impl_generics ::fayalite::sim::value::ToSimValue
for #sim_value_ident #static_type_generics
#static_where_clause
{
type Type = #target #static_type_generics;
fn to_sim_value(
&self,
) -> ::fayalite::sim::value::SimValue<
<Self as ::fayalite::sim::value::ToSimValue>::Type,
> {
::fayalite::sim::value::SimValue::from_value(
::fayalite::ty::StaticType::TYPE,
::fayalite::__std::clone::Clone::clone(self),
)
}
fn into_sim_value(
self,
) -> ::fayalite::sim::value::SimValue<
<Self as ::fayalite::sim::value::ToSimValue>::Type,
> {
::fayalite::sim::value::SimValue::from_value(
::fayalite::ty::StaticType::TYPE,
self,
)
}
}
} }
.to_tokens(tokens); .to_tokens(tokens);
} }

View file

@ -1,16 +1,15 @@
// 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::{
Errors, HdlAttr,
hdl_type_common::{ hdl_type_common::{
ItemOptions, MakeHdlTypeExpr, MaybeParsed, ParsedGenerics, ParsedType, TypesParser, get_target, ItemOptions, MakeHdlTypeExpr, MaybeParsed, ParsedGenerics, ParsedType,
get_target, TypesParser,
}, },
kw, kw, Errors, HdlAttr,
}; };
use proc_macro2::TokenStream; use proc_macro2::TokenStream;
use quote::ToTokens; use quote::ToTokens;
use syn::{Attribute, Generics, Ident, ItemType, Token, Type, Visibility, parse_quote_spanned}; use syn::{parse_quote_spanned, Attribute, Generics, Ident, ItemType, Token, Type, Visibility};
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub(crate) struct ParsedTypeAlias { pub(crate) struct ParsedTypeAlias {
@ -50,14 +49,10 @@ 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)) {
@ -100,7 +95,6 @@ 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();

View file

@ -1,21 +1,21 @@
// 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::{Errors, HdlAttr, PairsIterExt, fold::impl_fold, kw}; use crate::{fold::impl_fold, kw, Errors, HdlAttr, PairsIterExt};
use proc_macro2::{Span, TokenStream}; use proc_macro2::{Span, TokenStream};
use quote::{ToTokens, format_ident, quote_spanned}; use quote::{format_ident, quote_spanned, ToTokens};
use std::{collections::HashMap, fmt, mem}; use std::{collections::HashMap, fmt, mem};
use syn::{ use syn::{
parse::{Parse, ParseStream},
parse_quote, parse_quote_spanned,
punctuated::{Pair, Punctuated},
spanned::Spanned,
token::{Brace, Bracket, Paren},
AngleBracketedGenericArguments, Attribute, Block, ConstParam, Expr, ExprBlock, ExprGroup, AngleBracketedGenericArguments, Attribute, Block, ConstParam, Expr, ExprBlock, ExprGroup,
ExprIndex, ExprParen, ExprPath, ExprTuple, Field, FieldMutability, Fields, FieldsNamed, ExprIndex, ExprParen, ExprPath, ExprTuple, Field, FieldMutability, Fields, FieldsNamed,
FieldsUnnamed, GenericArgument, GenericParam, Generics, Ident, ImplGenerics, Index, ItemStruct, FieldsUnnamed, GenericArgument, GenericParam, Generics, Ident, ImplGenerics, Index, ItemStruct,
Path, PathArguments, PathSegment, PredicateType, QSelf, Stmt, Token, Turbofish, Type, Path, PathArguments, PathSegment, PredicateType, QSelf, Stmt, Token, Turbofish, Type,
TypeGenerics, TypeGroup, TypeParam, TypeParen, TypePath, TypeTuple, Visibility, WhereClause, TypeGenerics, TypeGroup, TypeParam, TypeParen, TypePath, TypeTuple, Visibility, WhereClause,
WherePredicate, WherePredicate,
parse::{Parse, ParseStream},
parse_quote, parse_quote_spanned,
punctuated::{Pair, Punctuated},
spanned::Spanned,
token::{Brace, Bracket, Paren},
}; };
crate::options! { crate::options! {
@ -26,7 +26,6 @@ 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),
} }
} }
@ -299,7 +298,7 @@ impl ParseTypes<Expr> for ParsedExpr {
return Ok(ParsedExpr::Delimited(ParsedExprDelimited { return Ok(ParsedExpr::Delimited(ParsedExprDelimited {
delim: ExprDelimiter::Group(*group_token), delim: ExprDelimiter::Group(*group_token),
expr: parser.parse(expr)?, expr: parser.parse(expr)?,
})); }))
} }
Expr::Paren(ExprParen { Expr::Paren(ExprParen {
attrs, attrs,
@ -309,7 +308,7 @@ impl ParseTypes<Expr> for ParsedExpr {
return Ok(ParsedExpr::Delimited(ParsedExprDelimited { return Ok(ParsedExpr::Delimited(ParsedExprDelimited {
delim: ExprDelimiter::Paren(*paren_token), delim: ExprDelimiter::Paren(*paren_token),
expr: parser.parse(expr)?, expr: parser.parse(expr)?,
})); }))
} }
Expr::Path(ExprPath { Expr::Path(ExprPath {
attrs, attrs,
@ -1902,8 +1901,8 @@ pub(crate) mod known_items {
use proc_macro2::{Ident, Span, TokenStream}; use proc_macro2::{Ident, Span, TokenStream};
use quote::ToTokens; use quote::ToTokens;
use syn::{ use syn::{
Path, PathArguments, PathSegment, Token,
parse::{Parse, ParseStream}, parse::{Parse, ParseStream},
Path, PathArguments, PathSegment, Token,
}; };
macro_rules! impl_known_item_body { macro_rules! impl_known_item_body {
@ -2070,16 +2069,11 @@ 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 {
@ -2092,54 +2086,28 @@ 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_type_param_bound(input.parse()?) Self::parse_path(Path::parse_mod_style(input)?).map_err(|path| {
.map_err(|type_param_bound| syn::Error::new_spanned( syn::Error::new_spanned(
type_param_bound, path,
format_args!("expected one of: {}", [$(stringify!($Variant)),*].join(", ")), format_args!("expected one of: {}", [$(stringify!($Variant)),*].join(", ")),
)) )
})
} }
} }
@ -2147,7 +2115,6 @@ 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 {
@ -2159,63 +2126,42 @@ 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)]
#[allow(non_snake_case)] $vis struct Iter($vis $struct_type);
$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 { Iter(self)
$($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.$Variant.take() { if let Some(value) = self.0.$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.$Variant.take() { if let Some(value) = self.0.$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
} }
} }
@ -2227,9 +2173,6 @@ 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);
})?
}); });
} }
} }
@ -2248,7 +2191,6 @@ 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);)*
}); });
} }
} }
@ -2302,8 +2244,6 @@ impl_bounds! {
Size, Size,
StaticType, StaticType,
Type, Type,
#[unknown]
Unknown,
} }
} }
@ -2317,8 +2257,6 @@ impl_bounds! {
ResetType, ResetType,
StaticType, StaticType,
Type, Type,
#[unknown]
Unknown,
} }
} }
@ -2332,7 +2270,6 @@ impl From<ParsedTypeBound> for ParsedBound {
ParsedTypeBound::ResetType(v) => ParsedBound::ResetType(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),
} }
} }
} }
@ -2347,7 +2284,6 @@ impl From<ParsedTypeBounds> for ParsedBounds {
ResetType, ResetType,
StaticType, StaticType,
Type, Type,
Unknown,
} = value; } = value;
Self { Self {
BoolOrIntType, BoolOrIntType,
@ -2359,7 +2295,6 @@ impl From<ParsedTypeBounds> for ParsedBounds {
Size: None, Size: None,
StaticType, StaticType,
Type, Type,
Unknown,
} }
} }
} }
@ -2395,7 +2330,6 @@ impl ParsedTypeBound {
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)]),
} }
} }
} }
@ -2430,7 +2364,6 @@ impl From<ParsedSizeTypeBounds> for ParsedBounds {
Size, Size,
StaticType: None, StaticType: None,
Type: None, Type: None,
Unknown: vec![],
} }
} }
} }
@ -2458,7 +2391,6 @@ 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
@ -2470,37 +2402,15 @@ 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, unknown_bounds.is_empty()) { match (type_bounds, size_type_bounds) {
(None, None, true) => ParsedBoundsCategory::Type(ParsedTypeBounds { (None, None) => ParsedBoundsCategory::Type(ParsedTypeBounds {
Type: Some(known_items::Type(span)), Type: Some(known_items::Type(span)),
..Default::default() ..Default::default()
}), }),
(None, None, false) => { (None, Some(bounds)) => ParsedBoundsCategory::SizeType(bounds),
errors.error( (Some(bounds), None) => ParsedBoundsCategory::Type(bounds),
unknown_bounds.remove(0), (Some(type_bounds), Some(size_type_bounds)) => {
"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
@ -2517,7 +2427,6 @@ 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 {
@ -2532,14 +2441,12 @@ impl ParsedBound {
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)]),
} }
} }
} }
@ -3418,7 +3325,7 @@ impl ParsedGenerics {
| ParsedTypeBound::EnumType(_) | ParsedTypeBound::EnumType(_)
| ParsedTypeBound::IntType(_) | ParsedTypeBound::IntType(_)
| ParsedTypeBound::ResetType(_) => { | ParsedTypeBound::ResetType(_) => {
errors.error(bound, "bounds on mask types are not implemented"); errors.error(bound, "bound on mask type not implemented");
} }
ParsedTypeBound::StaticType(bound) => { ParsedTypeBound::StaticType(bound) => {
if bounds.StaticType.is_none() { if bounds.StaticType.is_none() {
@ -3430,12 +3337,6 @@ 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();
@ -3761,10 +3662,7 @@ pub(crate) trait AsTurbofish {
} }
impl AsTurbofish for TypeGenerics<'_> { impl AsTurbofish for TypeGenerics<'_> {
type Turbofish<'a> type Turbofish<'a> = Turbofish<'a> where Self: 'a;
= Turbofish<'a>
where
Self: 'a;
fn as_turbofish(&self) -> Self::Turbofish<'_> { fn as_turbofish(&self) -> Self::Turbofish<'_> {
TypeGenerics::as_turbofish(self) TypeGenerics::as_turbofish(self)
@ -3772,8 +3670,7 @@ impl AsTurbofish for TypeGenerics<'_> {
} }
impl AsTurbofish for ParsedGenericsTypeGenerics<'_> { impl AsTurbofish for ParsedGenericsTypeGenerics<'_> {
type Turbofish<'a> type Turbofish<'a> = ParsedGenericsTurbofish<'a>
= ParsedGenericsTurbofish<'a>
where where
Self: 'a; Self: 'a;
@ -3824,18 +3721,15 @@ impl SplitForImpl for Generics {
} }
impl SplitForImpl for ParsedGenerics { impl SplitForImpl for ParsedGenerics {
type ImplGenerics<'a> type ImplGenerics<'a> = ParsedGenericsImplGenerics<'a>
= ParsedGenericsImplGenerics<'a>
where where
Self: 'a; Self: 'a;
type TypeGenerics<'a> type TypeGenerics<'a> = ParsedGenericsTypeGenerics<'a>
= ParsedGenericsTypeGenerics<'a>
where where
Self: 'a; Self: 'a;
type WhereClause<'a> type WhereClause<'a> = ParsedGenericsWhereClause<'a>
= ParsedGenericsWhereClause<'a>
where where
Self: 'a; Self: 'a;
@ -4052,8 +3946,7 @@ impl<P: ToTokens, U: ToTokens> ToTokens for MaybeParsed<P, U> {
} }
impl<P: AsTurbofish, U: AsTurbofish> AsTurbofish for MaybeParsed<P, U> { impl<P: AsTurbofish, U: AsTurbofish> AsTurbofish for MaybeParsed<P, U> {
type Turbofish<'a> type Turbofish<'a> = MaybeParsed<P::Turbofish<'a>, U::Turbofish<'a>>
= MaybeParsed<P::Turbofish<'a>, U::Turbofish<'a>>
where where
Self: 'a; Self: 'a;
@ -4066,16 +3959,13 @@ impl<P: AsTurbofish, U: AsTurbofish> AsTurbofish for MaybeParsed<P, U> {
} }
impl<P: SplitForImpl, U: SplitForImpl> SplitForImpl for MaybeParsed<P, U> { impl<P: SplitForImpl, U: SplitForImpl> SplitForImpl for MaybeParsed<P, U> {
type ImplGenerics<'a> type ImplGenerics<'a> = MaybeParsed<P::ImplGenerics<'a>, U::ImplGenerics<'a>>
= MaybeParsed<P::ImplGenerics<'a>, U::ImplGenerics<'a>>
where where
Self: 'a; Self: 'a;
type TypeGenerics<'a> type TypeGenerics<'a> = MaybeParsed<P::TypeGenerics<'a>, U::TypeGenerics<'a>>
= MaybeParsed<P::TypeGenerics<'a>, U::TypeGenerics<'a>>
where where
Self: 'a; Self: 'a;
type WhereClause<'a> type WhereClause<'a> = MaybeParsed<P::WhereClause<'a>, U::WhereClause<'a>>
= MaybeParsed<P::WhereClause<'a>, U::WhereClause<'a>>
where where
Self: 'a; Self: 'a;

View file

@ -2,13 +2,13 @@
// See Notices.txt for copyright information // See Notices.txt for copyright information
#![cfg_attr(test, recursion_limit = "512")] #![cfg_attr(test, recursion_limit = "512")]
use proc_macro2::{Span, TokenStream}; use proc_macro2::{Span, TokenStream};
use quote::{ToTokens, quote}; use quote::{quote, ToTokens};
use std::{ use std::{
collections::{HashMap, hash_map::Entry}, collections::{hash_map::Entry, HashMap},
io::{ErrorKind, Write}, io::{ErrorKind, Write},
}; };
use syn::{ use syn::{
AttrStyle, Attribute, Error, Ident, Item, ItemFn, LitBool, LitStr, Meta, Token, bracketed, bracketed,
ext::IdentExt, ext::IdentExt,
parenthesized, parenthesized,
parse::{Parse, ParseStream, Parser}, parse::{Parse, ParseStream, Parser},
@ -16,6 +16,7 @@ use syn::{
punctuated::{Pair, Punctuated}, punctuated::{Pair, Punctuated},
spanned::Spanned, spanned::Spanned,
token::{Bracket, Paren}, token::{Bracket, Paren},
AttrStyle, Attribute, Error, Ident, Item, ItemFn, LitBool, LitStr, Meta, Token,
}; };
mod fold; mod fold;
@ -71,14 +72,13 @@ mod kw {
custom_keyword!(cfg); custom_keyword!(cfg);
custom_keyword!(cfg_attr); 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!(incomplete_wire);
custom_keyword!(input); custom_keyword!(input);
custom_keyword!(incomplete_wire);
custom_keyword!(instance); custom_keyword!(instance);
custom_keyword!(m); custom_keyword!(m);
custom_keyword!(memory); custom_keyword!(memory);
@ -92,7 +92,6 @@ mod kw {
custom_keyword!(output); custom_keyword!(output);
custom_keyword!(reg_builder); custom_keyword!(reg_builder);
custom_keyword!(reset); custom_keyword!(reset);
custom_keyword!(sim);
custom_keyword!(skip); custom_keyword!(skip);
custom_keyword!(target); custom_keyword!(target);
custom_keyword!(wire); custom_keyword!(wire);

View file

@ -1,20 +1,19 @@
// 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::{
Errors, HdlAttr, PairsIterExt,
hdl_type_common::{ParsedGenerics, SplitForImpl}, hdl_type_common::{ParsedGenerics, SplitForImpl},
kw, kw,
module::transform_body::{HdlLet, HdlLetKindIO}, module::transform_body::{HdlLet, HdlLetKindIO},
options, options, Errors, HdlAttr, PairsIterExt,
}; };
use proc_macro2::TokenStream; use proc_macro2::TokenStream;
use quote::{ToTokens, format_ident, quote, quote_spanned}; use quote::{format_ident, quote, quote_spanned, ToTokens};
use std::collections::HashSet; use std::collections::HashSet;
use syn::{ use syn::{
parse_quote,
visit::{visit_pat, Visit},
Attribute, Block, ConstParam, Error, FnArg, GenericParam, Generics, Ident, ItemFn, ItemStruct, Attribute, Block, ConstParam, Error, FnArg, GenericParam, Generics, Ident, ItemFn, ItemStruct,
LifetimeParam, ReturnType, Signature, TypeParam, Visibility, WhereClause, WherePredicate, LifetimeParam, ReturnType, Signature, TypeParam, Visibility, WhereClause, WherePredicate,
parse_quote,
visit::{Visit, visit_pat},
}; };
mod transform_body; mod transform_body;
@ -378,7 +377,7 @@ impl ModuleFn {
module_kind, module_kind,
vis, vis,
sig, sig,
mut block, block,
struct_generics, struct_generics,
the_struct, the_struct,
} = match self.0 { } = match self.0 {
@ -440,12 +439,6 @@ impl ModuleFn {
body_sig body_sig
.inputs .inputs
.insert(0, parse_quote! { m: &::fayalite::module::ModuleBuilder }); .insert(0, parse_quote! { m: &::fayalite::module::ModuleBuilder });
block.stmts.insert(
0,
parse_quote! {
let _ = m;
},
);
let body_fn = ItemFn { let body_fn = ItemFn {
attrs: vec![], attrs: vec![],
vis: Visibility::Inherited, vis: Visibility::Inherited,

View file

@ -1,40 +1,32 @@
// 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::{
Errors, HdlAttr, fold::{impl_fold, DoFold},
fold::{DoFold, impl_fold},
hdl_type_common::{ hdl_type_common::{
ParseFailed, ParseTypes, ParsedGenerics, ParsedType, TypesParser, known_items, known_items, ParseFailed, ParseTypes, ParsedGenerics, ParsedType, TypesParser,
}, },
is_hdl_attr, kw, is_hdl_attr, kw,
module::{ModuleIO, ModuleIOKind, ModuleKind, check_name_conflicts_with_module_builder}, module::{check_name_conflicts_with_module_builder, ModuleIO, ModuleIOKind, ModuleKind},
options, options, Errors, HdlAttr,
}; };
use num_bigint::BigInt; use num_bigint::BigInt;
use proc_macro2::{Span, TokenStream}; use proc_macro2::{Span, TokenStream};
use quote::{ToTokens, quote, quote_spanned}; use quote::{quote, quote_spanned, ToTokens};
use std::{borrow::Borrow, convert::Infallible}; use std::{borrow::Borrow, convert::Infallible};
use syn::{ use syn::{
Attribute, Block, Error, Expr, ExprIf, ExprLet, ExprLit, ExprRepeat, ExprUnary, fold::{fold_expr, fold_expr_lit, fold_expr_unary, fold_local, fold_stmt, Fold},
GenericArgument, Ident, Item, Lit, LitStr, Local, LocalInit, Pat, Token, Type, UnOp,
fold::{Fold, fold_expr, fold_expr_lit, fold_expr_unary, fold_local, fold_stmt},
parenthesized, parenthesized,
parse::{Parse, ParseStream}, parse::{Nothing, Parse, ParseStream},
parse_quote, parse_quote_spanned, parse_quote, parse_quote_spanned,
spanned::Spanned, spanned::Spanned,
token::Paren, token::Paren,
Attribute, Block, Error, Expr, ExprIf, ExprLet, ExprLit, ExprRepeat, ExprUnary,
GenericArgument, Ident, Item, Lit, LitStr, Local, LocalInit, Pat, Token, Type, UnOp,
}; };
mod expand_aggregate_literals; mod expand_aggregate_literals;
mod expand_match; mod expand_match;
options! {
#[options = ExprOptions]
pub(crate) enum ExprOption {
Sim(sim),
}
}
options! { options! {
pub(crate) enum LetFnKind { pub(crate) enum LetFnKind {
Input(input), Input(input),
@ -960,7 +952,7 @@ with_debug_clone_and_fold! {
#[allow(dead_code)] #[allow(dead_code)]
pub(crate) struct HdlLet<Kind = HdlLetKind> { pub(crate) struct HdlLet<Kind = HdlLetKind> {
pub(crate) attrs: Vec<Attribute>, pub(crate) attrs: Vec<Attribute>,
pub(crate) hdl_attr: HdlAttr<syn::parse::Nothing, kw::hdl>, pub(crate) hdl_attr: HdlAttr<Nothing, kw::hdl>,
pub(crate) let_token: Token![let], pub(crate) let_token: Token![let],
pub(crate) mut_token: Option<Token![mut]>, pub(crate) mut_token: Option<Token![mut]>,
pub(crate) name: Ident, pub(crate) name: Ident,
@ -1117,7 +1109,7 @@ fn parse_quote_let_pat<T, R: ToTokens, C: Borrow<Token![:]>>(
} }
} }
pub(crate) fn wrap_ty_with_expr(ty: impl ToTokens) -> Type { 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>
} }
@ -1181,7 +1173,7 @@ impl Visitor<'_> {
Some(_) => {} Some(_) => {}
} }
} }
fn process_hdl_if(&mut self, hdl_attr: HdlAttr<ExprOptions, kw::hdl>, expr_if: ExprIf) -> Expr { fn process_hdl_if(&mut self, hdl_attr: HdlAttr<Nothing, kw::hdl>, expr_if: ExprIf) -> Expr {
let ExprIf { let ExprIf {
attrs, attrs,
if_token, if_token,
@ -1189,10 +1181,10 @@ impl Visitor<'_> {
then_branch, then_branch,
else_branch, else_branch,
} = expr_if; } = expr_if;
let (else_token, else_expr) = else_branch.unzip(); self.require_normal_module_or_fn(if_token);
let else_expr = else_expr.map(|else_expr| match *else_expr { let else_expr = else_branch.unzip().1.map(|else_expr| match *else_expr {
Expr::If(expr_if) => Box::new(self.process_hdl_if(hdl_attr.clone(), expr_if)), Expr::If(expr_if) => self.process_hdl_if(hdl_attr.clone(), expr_if),
_ => else_expr, expr => expr,
}); });
if let Expr::Let(ExprLet { if let Expr::Let(ExprLet {
attrs: let_attrs, attrs: let_attrs,
@ -1214,19 +1206,7 @@ impl Visitor<'_> {
}, },
); );
} }
let ExprOptions { sim } = hdl_attr.body; if let Some(else_expr) = else_expr {
if sim.is_some() {
ExprIf {
attrs,
if_token,
cond: parse_quote_spanned! {if_token.span=>
*::fayalite::sim::value::SimValue::<::fayalite::int::Bool>::value(&::fayalite::sim::value::ToSimValue::into_sim_value(#cond))
},
then_branch,
else_branch: else_token.zip(else_expr),
}
.into()
} else if let Some(else_expr) = else_expr {
parse_quote_spanned! {if_token.span=> parse_quote_spanned! {if_token.span=>
#(#attrs)* #(#attrs)*
{ {
@ -1606,7 +1586,7 @@ impl Visitor<'_> {
} }
} }
pub(crate) fn empty_let() -> Local { fn empty_let() -> Local {
Local { Local {
attrs: vec![], attrs: vec![],
let_token: Default::default(), let_token: Default::default(),
@ -1688,42 +1668,20 @@ impl Fold for Visitor<'_> {
Repeat => process_hdl_repeat, Repeat => process_hdl_repeat,
Struct => process_hdl_struct, Struct => process_hdl_struct,
Tuple => process_hdl_tuple, Tuple => process_hdl_tuple,
MethodCall => process_hdl_method_call,
Call => process_hdl_call,
} }
} }
} }
fn fold_local(&mut self, mut let_stmt: Local) -> Local { fn fold_local(&mut self, let_stmt: Local) -> Local {
match self match self
.errors .errors
.ok(HdlAttr::<ExprOptions, kw::hdl>::parse_and_leave_attr( .ok(HdlAttr::<Nothing, kw::hdl>::parse_and_leave_attr(
&let_stmt.attrs, &let_stmt.attrs,
)) { )) {
None => return empty_let(), None => return empty_let(),
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::<ExprOptions, 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();

View file

@ -1,102 +1,45 @@
// 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::{kw, module::transform_body::Visitor, HdlAttr};
use crate::{
HdlAttr, kw,
module::transform_body::{
ExprOptions, Visitor,
expand_match::{EnumPath, parse_enum_path},
},
};
use quote::{format_ident, quote_spanned}; use quote::{format_ident, quote_spanned};
use std::mem;
use syn::{ use syn::{
Expr, ExprArray, ExprCall, ExprGroup, ExprMethodCall, ExprParen, ExprPath, ExprRepeat, parse::Nothing, parse_quote, parse_quote_spanned, spanned::Spanned, Expr, ExprArray, ExprPath,
ExprStruct, ExprTuple, FieldValue, Token, TypePath, parse_quote_spanned, ExprRepeat, ExprStruct, ExprTuple, FieldValue, TypePath,
punctuated::Punctuated, spanned::Spanned, token::Paren,
}; };
impl Visitor<'_> { impl Visitor<'_> {
pub(crate) fn process_hdl_array( pub(crate) fn process_hdl_array(
&mut self, &mut self,
hdl_attr: HdlAttr<ExprOptions, kw::hdl>, hdl_attr: HdlAttr<Nothing, kw::hdl>,
mut expr_array: ExprArray, mut expr_array: ExprArray,
) -> Expr { ) -> Expr {
let ExprOptions { sim } = hdl_attr.body; self.require_normal_module_or_fn(hdl_attr);
let span = hdl_attr.kw.span;
if sim.is_some() {
for elem in &mut expr_array.elems {
*elem = parse_quote_spanned! {elem.span()=>
::fayalite::sim::value::ToSimValue::to_sim_value(&(#elem))
};
}
parse_quote_spanned! {span=>
::fayalite::sim::value::ToSimValue::into_sim_value(#expr_array)
}
} else {
for elem in &mut expr_array.elems { for elem in &mut expr_array.elems {
*elem = parse_quote_spanned! {elem.span()=> *elem = parse_quote_spanned! {elem.span()=>
::fayalite::expr::ToExpr::to_expr(&(#elem)) ::fayalite::expr::ToExpr::to_expr(&(#elem))
}; };
} }
parse_quote_spanned! {span=> parse_quote! {::fayalite::expr::ToExpr::to_expr(&#expr_array)}
::fayalite::expr::ToExpr::to_expr(&#expr_array)
}
}
} }
pub(crate) fn process_hdl_repeat( pub(crate) fn process_hdl_repeat(
&mut self, &mut self,
hdl_attr: HdlAttr<ExprOptions, kw::hdl>, hdl_attr: HdlAttr<Nothing, kw::hdl>,
mut expr_repeat: ExprRepeat, mut expr_repeat: ExprRepeat,
) -> Expr { ) -> Expr {
self.require_normal_module_or_fn(hdl_attr);
let repeated_value = &expr_repeat.expr; let repeated_value = &expr_repeat.expr;
let ExprOptions { sim } = hdl_attr.body;
let span = hdl_attr.kw.span;
if sim.is_some() {
*expr_repeat.expr = parse_quote_spanned! {repeated_value.span()=>
::fayalite::sim::value::ToSimValue::to_sim_value(&(#repeated_value))
};
parse_quote_spanned! {span=>
::fayalite::sim::value::ToSimValue::into_sim_value(#expr_repeat)
}
} else {
*expr_repeat.expr = parse_quote_spanned! {repeated_value.span()=> *expr_repeat.expr = parse_quote_spanned! {repeated_value.span()=>
::fayalite::expr::ToExpr::to_expr(&(#repeated_value)) ::fayalite::expr::ToExpr::to_expr(&(#repeated_value))
}; };
parse_quote_spanned! {span=> parse_quote! {::fayalite::expr::ToExpr::to_expr(&#expr_repeat)}
::fayalite::expr::ToExpr::to_expr(&#expr_repeat)
}
}
} }
pub(crate) fn process_hdl_struct( pub(crate) fn process_hdl_struct(
&mut self, &mut self,
hdl_attr: HdlAttr<ExprOptions, kw::hdl>, hdl_attr: HdlAttr<Nothing, kw::hdl>,
mut expr_struct: ExprStruct, expr_struct: ExprStruct,
) -> Expr { ) -> Expr {
self.require_normal_module_or_fn(&hdl_attr);
let name_span = expr_struct.path.segments.last().unwrap().ident.span(); let name_span = expr_struct.path.segments.last().unwrap().ident.span();
let ExprOptions { sim } = hdl_attr.body;
if sim.is_some() {
let ty_path = TypePath {
qself: expr_struct.qself.take(),
path: expr_struct.path,
};
expr_struct.path = parse_quote_spanned! {name_span=>
__SimValue::<#ty_path>
};
for field in &mut expr_struct.fields {
let expr = &field.expr;
field.expr = parse_quote_spanned! {field.member.span()=>
::fayalite::sim::value::ToSimValue::to_sim_value(&(#expr))
};
}
return parse_quote_spanned! {name_span=>
{
type __SimValue<T> = <T as ::fayalite::ty::Type>::SimValue;
let value: ::fayalite::sim::value::SimValue<#ty_path> = ::fayalite::sim::value::ToSimValue::into_sim_value(#expr_struct);
value
}
};
}
let builder_ident = format_ident!("__builder", span = name_span); let builder_ident = format_ident!("__builder", span = name_span);
let empty_builder = if expr_struct.qself.is_some() let empty_builder = if expr_struct.qself.is_some()
|| expr_struct || expr_struct
@ -148,126 +91,12 @@ impl Visitor<'_> {
} }
pub(crate) fn process_hdl_tuple( pub(crate) fn process_hdl_tuple(
&mut self, &mut self,
hdl_attr: HdlAttr<ExprOptions, kw::hdl>, hdl_attr: HdlAttr<Nothing, kw::hdl>,
mut expr_tuple: ExprTuple, expr_tuple: ExprTuple,
) -> Expr { ) -> Expr {
let ExprOptions { sim } = hdl_attr.body; self.require_normal_module_or_fn(hdl_attr);
if sim.is_some() {
for element in &mut expr_tuple.elems {
*element = parse_quote_spanned! {element.span()=>
&(#element)
};
}
parse_quote_spanned! {expr_tuple.span()=>
::fayalite::sim::value::ToSimValue::into_sim_value(#expr_tuple)
}
} else {
parse_quote_spanned! {expr_tuple.span()=> parse_quote_spanned! {expr_tuple.span()=>
::fayalite::expr::ToExpr::to_expr(&#expr_tuple) ::fayalite::expr::ToExpr::to_expr(&#expr_tuple)
} }
} }
} }
pub(crate) fn process_hdl_call(
&mut self,
hdl_attr: HdlAttr<ExprOptions, kw::hdl>,
mut expr_call: ExprCall,
) -> Expr {
let span = hdl_attr.kw.span;
let mut func = &mut *expr_call.func;
let EnumPath {
variant_path: _,
enum_path,
variant_name,
} = loop {
match func {
Expr::Group(ExprGroup { expr, .. }) | Expr::Paren(ExprParen { expr, .. }) => {
func = &mut **expr;
}
Expr::Path(_) => {
let Expr::Path(ExprPath { attrs, qself, path }) =
mem::replace(func, Expr::PLACEHOLDER)
else {
unreachable!();
};
match parse_enum_path(TypePath { qself, path }) {
Ok(path) => break path,
Err(path) => {
self.errors.error(&path, "unsupported enum variant path");
let TypePath { qself, path } = path;
*func = ExprPath { attrs, qself, path }.into();
return expr_call.into();
}
}
}
_ => {
self.errors.error(
&expr_call.func,
"#[hdl] function call -- function must be a possibly-parenthesized path",
);
return expr_call.into();
}
}
};
self.process_hdl_method_call(
hdl_attr,
ExprMethodCall {
attrs: expr_call.attrs,
receiver: parse_quote_spanned! {span=>
<#enum_path as ::fayalite::ty::StaticType>::TYPE
},
dot_token: Token![.](span),
method: variant_name,
turbofish: None,
paren_token: expr_call.paren_token,
args: expr_call.args,
},
)
}
pub(crate) fn process_hdl_method_call(
&mut self,
hdl_attr: HdlAttr<ExprOptions, kw::hdl>,
mut expr_method_call: ExprMethodCall,
) -> Expr {
let ExprOptions { sim } = hdl_attr.body;
let span = hdl_attr.kw.span;
// remove any number of groups and up to one paren
let mut receiver = &mut *expr_method_call.receiver;
let mut has_group = false;
let receiver = loop {
match receiver {
Expr::Group(ExprGroup { expr, .. }) => {
has_group = true;
receiver = expr;
}
Expr::Paren(ExprParen { expr, .. }) => break &mut **expr,
receiver @ Expr::Path(_) => break receiver,
_ => {
if !has_group {
self.errors.error(
&expr_method_call.receiver,
"#[hdl] on a method call needs parenthesized receiver",
);
}
break &mut *expr_method_call.receiver;
}
}
};
let func = if sim.is_some() {
parse_quote_spanned! {span=>
::fayalite::enum_::enum_type_to_sim_builder
}
} else {
parse_quote_spanned! {span=>
::fayalite::enum_::assert_is_enum_type
}
};
*expr_method_call.receiver = ExprCall {
attrs: vec![],
func,
paren_token: Paren(span),
args: Punctuated::from_iter([mem::replace(receiver, Expr::PLACEHOLDER)]),
}
.into();
expr_method_call.into()
}
}

View file

@ -1,121 +1,24 @@
// 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::{
Errors, HdlAttr, PairsIterExt, fold::{impl_fold, DoFold},
fold::{DoFold, impl_fold},
kw, kw,
module::transform_body::{ module::transform_body::{with_debug_clone_and_fold, Visitor},
ExprOptions, Visitor, empty_let, with_debug_clone_and_fold, wrap_ty_with_expr, Errors, HdlAttr, PairsIterExt,
},
}; };
use proc_macro2::{Span, TokenStream}; use proc_macro2::{Span, TokenStream};
use quote::{ToTokens, TokenStreamExt, format_ident, quote_spanned}; use quote::{format_ident, quote_spanned, ToTokens, TokenStreamExt};
use std::collections::BTreeSet;
use syn::{ use syn::{
Arm, Attribute, Expr, ExprMatch, FieldPat, Ident, Local, Member, Pat, PatIdent, PatOr, fold::{fold_arm, fold_expr_match, fold_pat, Fold},
PatParen, PatPath, PatRest, PatStruct, PatTuple, PatTupleStruct, PatWild, Path, PathSegment, parse::Nothing,
Token, TypePath,
fold::{Fold, fold_arm, fold_expr_match, fold_local, fold_pat},
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,
PatPath, PatRest, PatStruct, 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:_,
sim:_,
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,
@ -150,15 +53,6 @@ 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 {
@ -183,19 +77,6 @@ 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,
@ -278,29 +159,9 @@ 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,
sim: Option<(kw::sim,)>,
variant_path: Path, variant_path: Path,
enum_path: Path, enum_path: Path,
variant_name: Ident, variant_name: Ident,
@ -312,7 +173,6 @@ impl ToTokens for MatchPatEnumVariant {
fn to_tokens(&self, tokens: &mut TokenStream) { fn to_tokens(&self, tokens: &mut TokenStream) {
let Self { let Self {
match_span, match_span,
sim,
variant_path: _, variant_path: _,
enum_path, enum_path,
variant_name, variant_name,
@ -322,28 +182,7 @@ impl ToTokens for MatchPatEnumVariant {
__MatchTy::<#enum_path>::#variant_name __MatchTy::<#enum_path>::#variant_name
} }
.to_tokens(tokens); .to_tokens(tokens);
if sim.is_some() {
if let Some((paren_token, field)) = field { if let Some((paren_token, field)) = field {
paren_token.surround(tokens, |tokens| {
field.to_tokens(tokens);
match field {
MatchPatSimple::Paren(_)
| MatchPatSimple::Or(_)
| MatchPatSimple::Binding(_)
| MatchPatSimple::Wild(_) => quote_spanned! {*match_span=>
, _
}
.to_tokens(tokens),
MatchPatSimple::Rest(_) => {}
}
});
} else {
quote_spanned! {*match_span=>
(_)
}
.to_tokens(tokens);
}
} else if let Some((paren_token, field)) = field {
paren_token.surround(tokens, |tokens| field.to_tokens(tokens)); paren_token.surround(tokens, |tokens| field.to_tokens(tokens));
} }
} }
@ -355,7 +194,6 @@ enum MatchPatSimple {
Or(MatchPatOr<MatchPatSimple>), Or(MatchPatOr<MatchPatSimple>),
Binding(MatchPatBinding), Binding(MatchPatBinding),
Wild(MatchPatWild), Wild(MatchPatWild),
Rest(MatchPatRest),
} }
impl_fold! { impl_fold! {
@ -364,7 +202,6 @@ impl_fold! {
Or(MatchPatOr<MatchPatSimple>), Or(MatchPatOr<MatchPatSimple>),
Binding(MatchPatBinding), Binding(MatchPatBinding),
Wild(MatchPatWild), Wild(MatchPatWild),
Rest(MatchPatRest),
} }
} }
@ -375,18 +212,17 @@ 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),
} }
} }
} }
pub(crate) struct EnumPath { struct EnumPath {
pub(crate) variant_path: Path, variant_path: Path,
pub(crate) enum_path: Path, enum_path: Path,
pub(crate) variant_name: Ident, variant_name: Ident,
} }
pub(crate) fn parse_enum_path(variant_path: TypePath) -> Result<EnumPath, TypePath> { fn parse_enum_path(variant_path: TypePath) -> Result<EnumPath, TypePath> {
let TypePath { let TypePath {
qself: None, qself: None,
path: variant_path, path: variant_path,
@ -442,7 +278,6 @@ 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, ()> {
@ -478,7 +313,6 @@ trait ParseMatchPat: Sized {
state, state,
MatchPatEnumVariant { MatchPatEnumVariant {
match_span: state.match_span, match_span: state.match_span,
sim: state.sim,
variant_path, variant_path,
enum_path, enum_path,
variant_name, variant_name,
@ -525,7 +359,6 @@ trait ParseMatchPat: Sized {
state, state,
MatchPatEnumVariant { MatchPatEnumVariant {
match_span: state.match_span, match_span: state.match_span,
sim: state.sim,
variant_path, variant_path,
enum_path, enum_path,
variant_name, variant_name,
@ -610,7 +443,6 @@ trait ParseMatchPat: Sized {
state, state,
MatchPatEnumVariant { MatchPatEnumVariant {
match_span: state.match_span, match_span: state.match_span,
sim: state.sim,
variant_path, variant_path,
enum_path, enum_path,
variant_name, variant_name,
@ -630,34 +462,7 @@ trait ParseMatchPat: Sized {
}) => Ok(Self::simple(MatchPatSimple::Wild(MatchPatWild { }) => Ok(Self::simple(MatchPatSimple::Wild(MatchPatWild {
underscore_token, underscore_token,
}))), }))),
Pat::Tuple(PatTuple { Pat::Tuple(_) | Pat::Slice(_) | Pat::Const(_) | Pat::Lit(_) | Pat::Range(_) => {
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");
@ -692,14 +497,6 @@ 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,
@ -718,7 +515,6 @@ enum MatchPat {
Or(MatchPatOr<MatchPat>), Or(MatchPatOr<MatchPat>),
Paren(MatchPatParen<MatchPat>), Paren(MatchPatParen<MatchPat>),
Struct(MatchPatStruct), Struct(MatchPatStruct),
Tuple(MatchPatTuple),
EnumVariant(MatchPatEnumVariant), EnumVariant(MatchPatEnumVariant),
} }
@ -728,7 +524,6 @@ impl_fold! {
Or(MatchPatOr<MatchPat>), Or(MatchPatOr<MatchPat>),
Paren(MatchPatParen<MatchPat>), Paren(MatchPatParen<MatchPat>),
Struct(MatchPatStruct), Struct(MatchPatStruct),
Tuple(MatchPatTuple),
EnumVariant(MatchPatEnumVariant), EnumVariant(MatchPatEnumVariant),
} }
} }
@ -750,10 +545,6 @@ 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,
@ -769,7 +560,6 @@ 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),
} }
} }
@ -832,6 +622,10 @@ 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.member.span()));
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) {
@ -946,177 +740,17 @@ 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> {
sim: Option<(kw::sim,)>,
match_span: Span, match_span: Span,
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<ExprOptions, kw::hdl>,
mut let_stmt: Local,
) -> Local {
let span = let_stmt.let_token.span();
let ExprOptions { sim } = hdl_attr.body;
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;
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 {
sim,
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 = if sim.is_some() {
parse_quote_spanned! {span=>
let (#(#bindings,)*) = {
type __MatchTy<T> = <T as ::fayalite::ty::Type>::SimValue;
let __match_value = ::fayalite::sim::value::ToSimValue::to_sim_value(&(#expr));
#let_token #pat #eq_token ::fayalite::sim::value::SimValue::into_value(__match_value) #semi_token
(#(#bindings,)*)
};
}
} else {
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<ExprOptions, kw::hdl>, _hdl_attr: HdlAttr<Nothing, kw::hdl>,
expr_match: ExprMatch, expr_match: ExprMatch,
) -> Expr { ) -> Expr {
let span = expr_match.match_token.span(); let span = expr_match.match_token.span();
@ -1128,9 +762,8 @@ impl Visitor<'_> {
brace_token: _, brace_token: _,
arms, arms,
} = expr_match; } = expr_match;
let ExprOptions { sim } = hdl_attr.body; self.require_normal_module_or_fn(match_token);
let mut state = HdlMatchParseState { let mut state = HdlMatchParseState {
sim,
match_span: span, match_span: span,
errors: &mut self.errors, errors: &mut self.errors,
}; };
@ -1138,18 +771,7 @@ impl Visitor<'_> {
arms.into_iter() arms.into_iter()
.filter_map(|arm| MatchArm::parse(&mut state, arm).ok()), .filter_map(|arm| MatchArm::parse(&mut state, arm).ok()),
); );
let expr = if sim.is_some() { let expr = quote_spanned! {span=>
quote_spanned! {span=>
{
type __MatchTy<T> = <T as ::fayalite::ty::Type>::SimValue;
let __match_expr = ::fayalite::sim::value::ToSimValue::to_sim_value(&(#expr));
#match_token ::fayalite::sim::value::SimValue::into_value(__match_expr) {
#(#arms)*
}
}
}
} else {
quote_spanned! {span=>
{ {
type __MatchTy<T> = <T as ::fayalite::ty::Type>::MatchVariant; type __MatchTy<T> = <T as ::fayalite::ty::Type>::MatchVariant;
let __match_expr = ::fayalite::expr::ToExpr::to_expr(&(#expr)); let __match_expr = ::fayalite::expr::ToExpr::to_expr(&(#expr));
@ -1167,7 +789,6 @@ impl Visitor<'_> {
} }
} }
} }
}
}; };
syn::parse2(expr).unwrap() syn::parse2(expr).unwrap()
} }

View file

@ -5,8 +5,8 @@ use crate::{Cfg, CfgAttr, Cfgs, Errors};
use proc_macro2::Ident; use proc_macro2::Ident;
use std::{collections::VecDeque, marker::PhantomData}; use std::{collections::VecDeque, marker::PhantomData};
use syn::{ use syn::{
Token,
punctuated::{Pair, Punctuated}, punctuated::{Pair, Punctuated},
Token,
}; };
struct State<P: Phase> { struct State<P: Phase> {

View file

@ -1,7 +1,7 @@
// 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 proc_macro2::{Span, TokenStream}; use proc_macro2::{Span, TokenStream};
use quote::{ToTokens, format_ident, quote}; use quote::{format_ident, quote, ToTokens};
use std::{collections::BTreeMap, fs}; use std::{collections::BTreeMap, fs};
use syn::{fold::Fold, parse_quote}; use syn::{fold::Fold, parse_quote};

View file

@ -34,14 +34,12 @@ which.workspace = true
[dev-dependencies] [dev-dependencies]
trybuild.workspace = true trybuild.workspace = true
serde = { workspace = true, features = ["rc"] }
[build-dependencies] [build-dependencies]
fayalite-visit-gen.workspace = true fayalite-visit-gen.workspace = true
[features] [features]
unstable-doc = [] unstable-doc = []
unstable-test-hasher = []
[package.metadata.docs.rs] [package.metadata.docs.rs]
features = ["unstable-doc"] features = ["unstable-doc"]

View file

@ -2,7 +2,6 @@
// 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;

View file

@ -1,33 +0,0 @@
// 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);
//! }
//! }
//! ```

View file

@ -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/tuple/enum pattern for now, //! `#[hdl] match` statements can only match one level of struct/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(_))`.

View file

@ -12,7 +12,7 @@ use std::{
ops::Deref, ops::Deref,
}; };
#[derive(Clone, Debug)] #[derive(Clone)]
struct CustomFirrtlAnnotationFieldsImpl { struct CustomFirrtlAnnotationFieldsImpl {
value: serde_json::Map<String, serde_json::Value>, value: serde_json::Map<String, serde_json::Value>,
serialized: Interned<str>, serialized: Interned<str>,
@ -314,7 +314,9 @@ impl<T: Iterator<Item: IntoAnnotations>> Iterator for IterIntoAnnotations<T> {
} }
impl< impl<
T: FusedIterator<Item: IntoAnnotations<IntoAnnotations: IntoIterator<IntoIter: FusedIterator>>>, T: FusedIterator<
Item: IntoAnnotations<IntoAnnotations: IntoIterator<IntoIter: FusedIterator>>,
>,
> FusedIterator for IterIntoAnnotations<T> > FusedIterator for IterIntoAnnotations<T>
{ {
} }

View file

@ -2,24 +2,17 @@
// See Notices.txt for copyright information // See Notices.txt for copyright information
use crate::{ use crate::{
expr::{ expr::{ops::ArrayIndex, Expr, ToExpr},
CastToBits, Expr, HdlPartialEq, ReduceBits, ToExpr, int::{DynSize, KnownSize, Size, SizeType, DYN_SIZE},
ops::{ArrayLiteral, ExprFromIterator, ExprIntoIterator, ExprPartialEq},
},
int::{Bool, DYN_SIZE, DynSize, KnownSize, Size, SizeType},
intern::{Intern, Interned, LazyInterned}, intern::{Intern, Interned, LazyInterned},
module::transform::visit::{Fold, Folder, Visit, Visitor}, module::transform::visit::{Fold, Folder, Visit, Visitor},
sim::value::{SimValue, SimValuePartialEq},
source_location::SourceLocation, source_location::SourceLocation,
ty::{ ty::{
CanonicalType, MatchVariantWithoutScope, OpaqueSimValueSlice, OpaqueSimValueWriter, CanonicalType, MatchVariantWithoutScope, StaticType, Type, TypeProperties, TypeWithDeref,
OpaqueSimValueWritten, StaticType, Type, TypeProperties, TypeWithDeref,
serde_impls::SerdeCanonicalType,
}, },
util::ConstUsize, util::ConstUsize,
}; };
use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Error}; use std::ops::Index;
use std::{iter::FusedIterator, ops::Index};
#[derive(Copy, Clone, PartialEq, Eq, Hash)] #[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub struct ArrayType<T: Type = CanonicalType, Len: Size = DynSize> { pub struct ArrayType<T: Type = CanonicalType, Len: Size = DynSize> {
@ -48,20 +41,15 @@ impl<T: Type, Len: Size> ArrayType<T, Len> {
is_storable, is_storable,
is_castable_from_bits, is_castable_from_bits,
bit_width, bit_width,
sim_only_values_len,
} = element; } = element;
let Some(bit_width) = bit_width.checked_mul(len) else { let Some(bit_width) = bit_width.checked_mul(len) else {
panic!("array too big"); panic!("array too big");
}; };
let Some(sim_only_values_len) = sim_only_values_len.checked_mul(len) else {
panic!("array too big");
};
TypeProperties { TypeProperties {
is_passive, is_passive,
is_storable, is_storable,
is_castable_from_bits, is_castable_from_bits,
bit_width, bit_width,
sim_only_values_len,
} }
} }
pub fn new(element: T, len: Len::SizeType) -> Self { pub fn new(element: T, len: Len::SizeType) -> Self {
@ -103,12 +91,6 @@ impl<T: Type, Len: KnownSize + Size<SizeType = Len>> ArrayType<T, Len> {
} }
} }
impl<T: StaticType, Len: KnownSize> Default for ArrayType<T, Len> {
fn default() -> Self {
Self::TYPE
}
}
impl<T: StaticType, Len: KnownSize> StaticType for ArrayType<T, Len> { impl<T: StaticType, Len: KnownSize> StaticType for ArrayType<T, Len> {
const TYPE: Self = Self { const TYPE: Self = Self {
element: LazyInterned::new_lazy(&|| T::TYPE.intern_sized()), element: LazyInterned::new_lazy(&|| T::TYPE.intern_sized()),
@ -157,7 +139,6 @@ impl<T: Type + Visit<State>, Len: Size, State: Visitor + ?Sized> Visit<State>
impl<T: Type, Len: Size> Type for ArrayType<T, Len> { impl<T: Type, Len: Size> Type for ArrayType<T, Len> {
type BaseType = Array; type BaseType = Array;
type MaskType = ArrayType<T::MaskType, Len>; type MaskType = ArrayType<T::MaskType, Len>;
type SimValue = Len::ArraySimValue<T>;
type MatchVariant = Len::ArrayMatch<T>; type MatchVariant = Len::ArrayMatch<T>;
type MatchActiveScope = (); type MatchActiveScope = ();
type MatchVariantAndInactiveScope = MatchVariantWithoutScope<Len::ArrayMatch<T>>; type MatchVariantAndInactiveScope = MatchVariantWithoutScope<Len::ArrayMatch<T>>;
@ -167,8 +148,10 @@ impl<T: Type, Len: Size> Type for ArrayType<T, Len> {
this: Expr<Self>, this: Expr<Self>,
source_location: SourceLocation, source_location: SourceLocation,
) -> Self::MatchVariantsIter { ) -> Self::MatchVariantsIter {
let base = Expr::as_dyn_array(this);
let base_ty = Expr::ty(base);
let _ = source_location; let _ = source_location;
let retval = Vec::from_iter(this); let retval = Vec::from_iter((0..base_ty.len()).map(|i| ArrayIndex::new(base, i).to_expr()));
std::iter::once(MatchVariantWithoutScope( std::iter::once(MatchVariantWithoutScope(
Len::ArrayMatch::<T>::try_from(retval) Len::ArrayMatch::<T>::try_from(retval)
.ok() .ok()
@ -194,106 +177,16 @@ impl<T: Type, Len: Size> Type for ArrayType<T, Len> {
Len::from_usize(array.len()), Len::from_usize(array.len()),
) )
} }
fn source_location() -> SourceLocation { fn source_location() -> SourceLocation {
SourceLocation::builtin() SourceLocation::builtin()
} }
fn sim_value_from_opaque(&self, mut opaque: OpaqueSimValueSlice<'_>) -> Self::SimValue {
let element_ty = self.element();
let element_size = element_ty.canonical().size();
let mut value = Vec::with_capacity(self.len());
for _ in 0..self.len() {
let (element_opaque, rest) = opaque.split_at(element_size);
value.push(SimValue::from_opaque(element_ty, element_opaque.to_owned()));
opaque = rest;
}
value.try_into().ok().expect("used correct length")
}
fn sim_value_clone_from_opaque(
&self,
value: &mut Self::SimValue,
mut opaque: OpaqueSimValueSlice<'_>,
) {
let element_ty = self.element();
let element_size = element_ty.canonical().size();
let value = AsMut::<[SimValue<T>]>::as_mut(value);
assert_eq!(self.len(), value.len());
for element_value in value {
assert_eq!(SimValue::ty(element_value), element_ty);
let (element_opaque, rest) = opaque.split_at(element_size);
SimValue::opaque_mut(element_value).clone_from_slice(element_opaque);
opaque = rest;
}
}
fn sim_value_to_opaque<'w>(
&self,
value: &Self::SimValue,
mut writer: OpaqueSimValueWriter<'w>,
) -> OpaqueSimValueWritten<'w> {
let element_ty = self.element();
let element_size = element_ty.canonical().size();
let value = AsRef::<[SimValue<T>]>::as_ref(value);
assert_eq!(self.len(), value.len());
for element_value in value {
assert_eq!(SimValue::ty(element_value), element_ty);
writer.fill_prefix_with(element_size, |writer| {
writer.fill_cloned_from_slice(SimValue::opaque(element_value).as_slice())
});
}
writer.fill_cloned_from_slice(OpaqueSimValueSlice::empty())
}
}
impl<T: Type + Serialize, Len: Size> Serialize for ArrayType<T, Len> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
SerdeCanonicalType::<T>::Array {
element: self.element(),
len: self.len(),
}
.serialize(serializer)
}
}
impl<'de, T: Type + Deserialize<'de>, Len: Size> Deserialize<'de> for ArrayType<T, Len> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let name = |len| -> String {
if let Some(len) = len {
format!("an Array<_, {len}>")
} else {
"an Array<_>".to_string()
}
};
match SerdeCanonicalType::<T>::deserialize(deserializer)? {
SerdeCanonicalType::Array { element, len } => {
if let Some(len) = Len::try_from_usize(len) {
Ok(Self::new(element, len))
} else {
Err(Error::invalid_value(
serde::de::Unexpected::Other(&name(Some(len))),
&&*name(Len::KNOWN_VALUE),
))
}
}
ty => Err(Error::invalid_value(
serde::de::Unexpected::Other(ty.as_serde_unexpected_str()),
&&*name(Len::KNOWN_VALUE),
)),
}
}
} }
impl<T: Type, Len: Size> TypeWithDeref for ArrayType<T, Len> { impl<T: Type, Len: Size> TypeWithDeref for ArrayType<T, Len> {
fn expr_deref(this: &Expr<Self>) -> &Self::MatchVariant { fn expr_deref(this: &Expr<Self>) -> &Self::MatchVariant {
let retval = Vec::from_iter(*this); let base = Expr::as_dyn_array(*this);
let base_ty = Expr::ty(base);
let retval = Vec::from_iter((0..base_ty.len()).map(|i| ArrayIndex::new(base, i).to_expr()));
Interned::into_inner(Intern::intern_sized( Interned::into_inner(Intern::intern_sized(
Len::ArrayMatch::<T>::try_from(retval) Len::ArrayMatch::<T>::try_from(retval)
.ok() .ok()
@ -325,143 +218,3 @@ 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());
lhs.into_iter()
.zip(rhs)
.map(|(l, r)| l.cmp_eq(r))
.collect::<Expr<Array<Bool>>>()
.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());
lhs.into_iter()
.zip(rhs)
.map(|(l, r)| l.cmp_ne(r))
.collect::<Expr<Array<Bool>>>()
.cast_to_bits()
.any_one_bits()
}
}
impl<Lhs: Type, Rhs: Type, Len: Size> SimValuePartialEq<ArrayType<Rhs, Len>> for ArrayType<Lhs, Len>
where
Lhs: SimValuePartialEq<Rhs>,
{
fn sim_value_eq(this: &SimValue<Self>, other: &SimValue<ArrayType<Rhs, Len>>) -> bool {
AsRef::<[_]>::as_ref(&**this)
.iter()
.zip(AsRef::<[_]>::as_ref(&**other))
.all(|(l, r)| SimValuePartialEq::sim_value_eq(l, r))
}
}
impl<T: Type, Len: Size> ExprIntoIterator for ArrayType<T, Len> {
type Item = T;
type ExprIntoIter = ExprArrayIter<T, Len>;
fn expr_into_iter(e: Expr<Self>) -> Self::ExprIntoIter {
ExprArrayIter {
base: e,
indexes: 0..Expr::ty(e).len(),
}
}
}
#[derive(Clone, Debug)]
pub struct ExprArrayIter<T: Type, Len: Size> {
base: Expr<ArrayType<T, Len>>,
indexes: std::ops::Range<usize>,
}
impl<T: Type, Len: Size> ExprArrayIter<T, Len> {
pub fn base(&self) -> Expr<ArrayType<T, Len>> {
self.base
}
pub fn indexes(&self) -> std::ops::Range<usize> {
self.indexes.clone()
}
}
impl<T: Type, Len: Size> Iterator for ExprArrayIter<T, Len> {
type Item = Expr<T>;
fn next(&mut self) -> Option<Self::Item> {
self.indexes.next().map(|i| self.base[i])
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.indexes.size_hint()
}
fn count(self) -> usize {
self.indexes.count()
}
fn last(mut self) -> Option<Self::Item> {
self.next_back()
}
fn nth(&mut self, n: usize) -> Option<Self::Item> {
self.indexes.nth(n).map(|i| self.base[i])
}
fn fold<B, F>(self, init: B, mut f: F) -> B
where
F: FnMut(B, Self::Item) -> B,
{
self.indexes.fold(init, |b, i| f(b, self.base[i]))
}
}
impl<T: Type, Len: Size> DoubleEndedIterator for ExprArrayIter<T, Len> {
fn next_back(&mut self) -> Option<Self::Item> {
self.indexes.next_back().map(|i| self.base[i])
}
fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
self.indexes.nth_back(n).map(|i| self.base[i])
}
fn rfold<B, F>(self, init: B, mut f: F) -> B
where
F: FnMut(B, Self::Item) -> B,
{
self.indexes.rfold(init, |b, i| f(b, self.base[i]))
}
}
impl<T: Type, Len: Size> ExactSizeIterator for ExprArrayIter<T, Len> {
fn len(&self) -> usize {
self.indexes.len()
}
}
impl<T: Type, Len: Size> FusedIterator for ExprArrayIter<T, Len> {}
impl<A: StaticType> ExprFromIterator<Expr<A>> for Array<A> {
fn expr_from_iter<T: IntoIterator<Item = Expr<A>>>(iter: T) -> Expr<Self> {
ArrayLiteral::new(
A::TYPE,
iter.into_iter().map(|v| Expr::canonical(v)).collect(),
)
.to_expr()
}
}
impl<'a, A: StaticType> ExprFromIterator<&'a Expr<A>> for Array<A> {
fn expr_from_iter<T: IntoIterator<Item = &'a Expr<A>>>(iter: T) -> Expr<Self> {
iter.into_iter().copied().collect()
}
}

View file

@ -2,25 +2,20 @@
// See Notices.txt for copyright information // See Notices.txt for copyright information
use crate::{ use crate::{
expr::{ expr::{ops::BundleLiteral, Expr, ToExpr},
CastToBits, Expr, ReduceBits, ToExpr,
ops::{ArrayLiteral, BundleLiteral, ExprPartialEq},
},
int::{Bool, DynSize},
intern::{Intern, Interned}, intern::{Intern, Interned},
sim::value::{SimValue, SimValuePartialEq, ToSimValue, ToSimValueWithType}, sim::{SimValue, ToSimValue},
source_location::SourceLocation, source_location::SourceLocation,
ty::{ ty::{
CanonicalType, MatchVariantWithoutScope, OpaqueSimValue, OpaqueSimValueSize, impl_match_variant_as_self, CanonicalType, MatchVariantWithoutScope, StaticType, Type,
OpaqueSimValueSlice, OpaqueSimValueWriter, OpaqueSimValueWritten, StaticType, Type, TypeProperties, TypeWithDeref,
TypeProperties, TypeWithDeref, impl_match_variant_as_self,
}, },
util::HashMap,
}; };
use serde::{Deserialize, Serialize}; use bitvec::vec::BitVec;
use hashbrown::HashMap;
use std::{fmt, marker::PhantomData}; use std::{fmt, marker::PhantomData};
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
pub struct BundleField { pub struct BundleField {
pub name: Interned<str>, pub name: Interned<str>,
pub flipped: bool, pub flipped: bool,
@ -69,7 +64,7 @@ impl fmt::Display for FmtDebugInStruct {
struct BundleImpl { struct BundleImpl {
fields: Interned<[BundleField]>, fields: Interned<[BundleField]>,
name_indexes: HashMap<Interned<str>, usize>, name_indexes: HashMap<Interned<str>, usize>,
field_offsets: Interned<[OpaqueSimValueSize]>, field_offsets: Interned<[usize]>,
type_properties: TypeProperties, type_properties: TypeProperties,
} }
@ -89,9 +84,12 @@ impl std::fmt::Debug for BundleImpl {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str("Bundle ")?; f.write_str("Bundle ")?;
f.debug_set() f.debug_set()
.entries(self.fields.iter().enumerate().map(|(index, field)| { .entries(
field.fmt_debug_in_struct(self.field_offsets[index].bit_width) self.fields
})) .iter()
.enumerate()
.map(|(index, field)| field.fmt_debug_in_struct(self.field_offsets[index])),
)
.finish() .finish()
} }
} }
@ -116,7 +114,6 @@ impl BundleTypePropertiesBuilder {
is_storable: true, is_storable: true,
is_castable_from_bits: true, is_castable_from_bits: true,
bit_width: 0, bit_width: 0,
sim_only_values_len: 0,
}) })
} }
pub const fn clone(&self) -> Self { pub const fn clone(&self) -> Self {
@ -124,12 +121,8 @@ impl BundleTypePropertiesBuilder {
} }
#[must_use] #[must_use]
pub const fn field(self, flipped: bool, field_props: TypeProperties) -> Self { pub const fn field(self, flipped: bool, field_props: TypeProperties) -> Self {
let Some(OpaqueSimValueSize { let Some(bit_width) = self.0.bit_width.checked_add(field_props.bit_width) else {
bit_width, panic!("bundle is too big: bit-width overflowed");
sim_only_values_len,
}) = self.0.size().checked_add(field_props.size())
else {
panic!("bundle is too big: size overflowed");
}; };
if flipped { if flipped {
Self(TypeProperties { Self(TypeProperties {
@ -137,7 +130,6 @@ impl BundleTypePropertiesBuilder {
is_storable: false, is_storable: false,
is_castable_from_bits: false, is_castable_from_bits: false,
bit_width, bit_width,
sim_only_values_len,
}) })
} else { } else {
Self(TypeProperties { Self(TypeProperties {
@ -146,7 +138,6 @@ impl BundleTypePropertiesBuilder {
is_castable_from_bits: self.0.is_castable_from_bits is_castable_from_bits: self.0.is_castable_from_bits
& field_props.is_castable_from_bits, & field_props.is_castable_from_bits,
bit_width, bit_width,
sim_only_values_len,
}) })
} }
} }
@ -164,14 +155,14 @@ impl Default for BundleTypePropertiesBuilder {
impl Bundle { impl Bundle {
#[track_caller] #[track_caller]
pub fn new(fields: Interned<[BundleField]>) -> Self { pub fn new(fields: Interned<[BundleField]>) -> Self {
let mut name_indexes = HashMap::with_capacity_and_hasher(fields.len(), Default::default()); let mut name_indexes = HashMap::with_capacity(fields.len());
let mut field_offsets = Vec::with_capacity(fields.len()); let mut field_offsets = Vec::with_capacity(fields.len());
let mut type_props_builder = BundleTypePropertiesBuilder::new(); let mut type_props_builder = BundleTypePropertiesBuilder::new();
for (index, &BundleField { name, flipped, ty }) in fields.iter().enumerate() { for (index, &BundleField { name, flipped, ty }) in fields.iter().enumerate() {
if let Some(old_index) = name_indexes.insert(name, index) { if let Some(old_index) = name_indexes.insert(name, index) {
panic!("duplicate field name {name:?}: at both index {old_index} and {index}"); panic!("duplicate field name {name:?}: at both index {old_index} and {index}");
} }
field_offsets.push(type_props_builder.0.size()); field_offsets.push(type_props_builder.0.bit_width);
type_props_builder = type_props_builder.field(flipped, ty.type_properties()); type_props_builder = type_props_builder.field(flipped, ty.type_properties());
} }
Self(Intern::intern_sized(BundleImpl { Self(Intern::intern_sized(BundleImpl {
@ -187,7 +178,7 @@ impl Bundle {
pub fn field_by_name(&self, name: Interned<str>) -> Option<BundleField> { pub fn field_by_name(&self, name: Interned<str>) -> Option<BundleField> {
Some(self.0.fields[*self.0.name_indexes.get(&name)?]) Some(self.0.fields[*self.0.name_indexes.get(&name)?])
} }
pub fn field_offsets(self) -> Interned<[OpaqueSimValueSize]> { pub fn field_offsets(self) -> Interned<[usize]> {
self.0.field_offsets self.0.field_offsets
} }
pub fn type_properties(self) -> TypeProperties { pub fn type_properties(self) -> TypeProperties {
@ -221,7 +212,6 @@ impl Bundle {
impl Type for Bundle { impl Type for Bundle {
type BaseType = Bundle; type BaseType = Bundle;
type MaskType = Bundle; type MaskType = Bundle;
type SimValue = OpaqueSimValue;
impl_match_variant_as_self!(); impl_match_variant_as_self!();
fn mask_type(&self) -> Self::MaskType { fn mask_type(&self) -> Self::MaskType {
Self::new(Interned::from_iter(self.0.fields.into_iter().map( Self::new(Interned::from_iter(self.0.fields.into_iter().map(
@ -245,28 +235,6 @@ impl Type for Bundle {
fn source_location() -> SourceLocation { fn source_location() -> SourceLocation {
SourceLocation::builtin() SourceLocation::builtin()
} }
fn sim_value_from_opaque(&self, opaque: OpaqueSimValueSlice<'_>) -> Self::SimValue {
assert_eq!(self.type_properties().size(), opaque.size());
opaque.to_owned()
}
fn sim_value_clone_from_opaque(
&self,
value: &mut Self::SimValue,
opaque: OpaqueSimValueSlice<'_>,
) {
assert_eq!(self.type_properties().size(), opaque.size());
assert_eq!(value.size(), opaque.size());
value.clone_from_slice(opaque);
}
fn sim_value_to_opaque<'w>(
&self,
value: &Self::SimValue,
writer: OpaqueSimValueWriter<'w>,
) -> OpaqueSimValueWritten<'w> {
assert_eq!(self.type_properties().size(), writer.size());
assert_eq!(value.size(), writer.size());
writer.fill_cloned_from_slice(value.as_slice())
}
} }
pub trait BundleType: Type<BaseType = Bundle> { pub trait BundleType: Type<BaseType = Bundle> {
@ -275,102 +243,6 @@ pub trait BundleType: Type<BaseType = Bundle> {
fn fields(&self) -> Interned<[BundleField]>; fn fields(&self) -> Interned<[BundleField]>;
} }
pub struct BundleSimValueFromOpaque<'a> {
fields: std::slice::Iter<'static, BundleField>,
opaque: OpaqueSimValueSlice<'a>,
}
impl<'a> BundleSimValueFromOpaque<'a> {
#[track_caller]
pub fn new<T: BundleType>(bundle_ty: T, opaque: OpaqueSimValueSlice<'a>) -> Self {
let fields = bundle_ty.fields();
assert_eq!(
opaque.size(),
fields
.iter()
.map(|BundleField { ty, .. }| ty.size())
.sum::<OpaqueSimValueSize>()
);
Self {
fields: Interned::into_inner(fields).iter(),
opaque,
}
}
#[track_caller]
fn field_ty_and_opaque<T: Type>(&mut self) -> (T, OpaqueSimValueSlice<'a>) {
let Some(&BundleField {
name: _,
flipped: _,
ty,
}) = self.fields.next()
else {
panic!("tried to read too many fields from BundleSimValueFromBits");
};
let (field_opaque, rest) = self.opaque.split_at(ty.size());
self.opaque = rest;
(T::from_canonical(ty), field_opaque)
}
#[track_caller]
pub fn field_from_opaque<T: Type>(&mut self) -> SimValue<T> {
let (field_ty, field_opaque) = self.field_ty_and_opaque::<T>();
SimValue::from_opaque(field_ty, field_opaque.to_owned())
}
#[track_caller]
pub fn field_clone_from_opaque<T: Type>(&mut self, field_value: &mut SimValue<T>) {
let (field_ty, field_opaque) = self.field_ty_and_opaque::<T>();
assert_eq!(field_ty, SimValue::ty(field_value));
SimValue::opaque_mut(field_value).clone_from_slice(field_opaque);
}
}
pub struct BundleSimValueToOpaque<'a> {
fields: std::slice::Iter<'static, BundleField>,
writer: OpaqueSimValueWriter<'a>,
}
impl<'a> BundleSimValueToOpaque<'a> {
#[track_caller]
pub fn new<T: BundleType>(bundle_ty: T, writer: OpaqueSimValueWriter<'a>) -> Self {
let fields = bundle_ty.fields();
assert_eq!(
writer.size(),
fields
.iter()
.map(|BundleField { ty, .. }| ty.size())
.sum::<OpaqueSimValueSize>()
);
Self {
fields: Interned::into_inner(fields).iter(),
writer,
}
}
#[track_caller]
pub fn field<T: Type>(&mut self, field_value: &SimValue<T>) {
let Some(&BundleField {
name: _,
flipped: _,
ty,
}) = self.fields.next()
else {
panic!("tried to write too many fields with BundleSimValueToOpaque");
};
assert_eq!(T::from_canonical(ty), SimValue::ty(field_value));
self.writer.fill_prefix_with(ty.size(), |writer| {
writer.fill_cloned_from_slice(SimValue::opaque(field_value).as_slice())
});
}
#[track_caller]
pub fn finish(mut self) -> OpaqueSimValueWritten<'a> {
assert_eq!(
self.fields.next(),
None,
"wrote too few fields with BundleSimValueToOpaque"
);
self.writer
.fill_cloned_from_slice(OpaqueSimValueSlice::empty())
}
}
#[derive(Default)] #[derive(Default)]
pub struct NoBuilder; pub struct NoBuilder;
@ -453,19 +325,7 @@ macro_rules! impl_tuple_builder_fields {
} }
macro_rules! impl_tuples { macro_rules! impl_tuples {
( ([$({#[num = $num:literal, field = $field:ident, ty = $ty_var:ident: $Ty: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! {
{} {}
[$({ [$({
@ -477,7 +337,6 @@ macro_rules! impl_tuples {
impl<$($T: Type,)*> Type for ($($T,)*) { impl<$($T: Type,)*> Type for ($($T,)*) {
type BaseType = Bundle; type BaseType = Bundle;
type MaskType = ($($T::MaskType,)*); type MaskType = ($($T::MaskType,)*);
type SimValue = ($(SimValue<$T>,)*);
type MatchVariant = ($(Expr<$T>,)*); type MatchVariant = ($(Expr<$T>,)*);
type MatchActiveScope = (); type MatchActiveScope = ();
type MatchVariantAndInactiveScope = MatchVariantWithoutScope<Self::MatchVariant>; type MatchVariantAndInactiveScope = MatchVariantWithoutScope<Self::MatchVariant>;
@ -516,33 +375,6 @@ macro_rules! impl_tuples {
fn source_location() -> SourceLocation { fn source_location() -> SourceLocation {
SourceLocation::builtin() SourceLocation::builtin()
} }
fn sim_value_from_opaque(&self, opaque: OpaqueSimValueSlice<'_>) -> Self::SimValue {
#![allow(unused_mut, unused_variables)]
let mut v = BundleSimValueFromOpaque::new(*self, opaque);
$(let $var = v.field_from_opaque();)*
($($var,)*)
}
fn sim_value_clone_from_opaque(
&self,
value: &mut Self::SimValue,
opaque: OpaqueSimValueSlice<'_>,
) {
#![allow(unused_mut, unused_variables)]
let mut v = BundleSimValueFromOpaque::new(*self, opaque);
let ($($var,)*) = value;
$(v.field_clone_from_opaque($var);)*
}
fn sim_value_to_opaque<'w>(
&self,
value: &Self::SimValue,
writer: OpaqueSimValueWriter<'w>,
) -> OpaqueSimValueWritten<'w> {
#![allow(unused_mut, unused_variables)]
let mut v = BundleSimValueToOpaque::new(*self, writer);
let ($($var,)*) = value;
$(v.field($var);)*
v.finish()
}
} }
impl<$($T: Type,)*> BundleType for ($($T,)*) { impl<$($T: Type,)*> BundleType for ($($T,)*) {
type Builder = TupleBuilder<($(Unfilled<$T>,)*)>; type Builder = TupleBuilder<($(Unfilled<$T>,)*)>;
@ -593,104 +425,77 @@ macro_rules! impl_tuples {
BundleLiteral::new(ty, field_values[..].intern()).to_expr() BundleLiteral::new(ty, field_values[..].intern()).to_expr()
} }
} }
impl<$($T: ToSimValueWithType<CanonicalType>,)*> ToSimValueWithType<CanonicalType> for ($($T,)*) { impl<$($T: ToSimValue<CanonicalType>,)*> ToSimValue<CanonicalType> for ($($T,)*) {
#[track_caller] #[track_caller]
fn to_sim_value_with_type(&self, ty: CanonicalType) -> SimValue<CanonicalType> { fn to_sim_value(&self, ty: CanonicalType) -> SimValue<CanonicalType> {
SimValue::into_canonical(ToSimValueWithType::<Bundle>::to_sim_value_with_type(self, Bundle::from_canonical(ty))) ToSimValue::<Bundle>::to_sim_value(self, Bundle::from_canonical(ty)).into_canonical()
} }
#[track_caller] #[track_caller]
fn into_sim_value_with_type(self, ty: CanonicalType) -> SimValue<CanonicalType> fn into_sim_value(self, ty: CanonicalType) -> SimValue<CanonicalType>
{ {
SimValue::into_canonical(ToSimValueWithType::<Bundle>::into_sim_value_with_type(self, Bundle::from_canonical(ty))) ToSimValue::<Bundle>::into_sim_value(self, Bundle::from_canonical(ty)).into_canonical()
} }
}
impl<$($T: ToSimValueWithType<CanonicalType>,)*> ToSimValueWithType<Bundle> for ($($T,)*) {
#[track_caller] #[track_caller]
fn to_sim_value_with_type(&self, ty: Bundle) -> SimValue<Bundle> { 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 ($($var,)*) = self;
let [$($ty_var,)*] = *ty.fields() else { let [$($ty_var,)*] = *ty.fields() else {
panic!("bundle has wrong number of fields"); panic!("bundle has wrong number of fields");
}; };
$(let $var = $var.to_sim_value_with_type($ty_var.ty);)* $(let $var = $var.to_sim_value($ty_var.ty);)*
ToSimValueWithType::into_sim_value_with_type(($($var,)*), ty) ToSimValue::into_sim_value(($($var,)*), ty)
} }
#[track_caller] #[track_caller]
fn into_sim_value_with_type(self, ty: Bundle) -> SimValue<Bundle> { fn into_sim_value(self, ty: Bundle) -> SimValue<Bundle> {
#![allow(unused_mut)] #![allow(unused_mut)]
#![allow(clippy::unused_unit)] #![allow(clippy::unused_unit)]
let ($($var,)*) = self; let ($($var,)*) = self;
let [$($ty_var,)*] = *ty.fields() else { let [$($ty_var,)*] = *ty.fields() else {
panic!("bundle has wrong number of fields"); panic!("bundle has wrong number of fields");
}; };
let mut opaque = OpaqueSimValue::empty(); let mut bits: Option<BitVec> = None;
$(let $var = $var.into_sim_value_with_type($ty_var.ty); $(let $var = $var.into_sim_value($ty_var.ty);
assert_eq!(SimValue::ty(&$var), $ty_var.ty); assert_eq!($var.ty(), $ty_var.ty);
opaque.extend_from_slice(SimValue::opaque(&$var).as_slice()); 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);
}
}
)* )*
SimValue::from_opaque(ty, opaque) bits.unwrap_or_else(BitVec::new).into_sim_value(ty)
} }
}
impl<$($T: ToSimValueWithType<$Ty>, $Ty: Type,)*> ToSimValueWithType<($($Ty,)*)> for ($($T,)*) {
#[track_caller] #[track_caller]
fn to_sim_value_with_type(&self, ty: ($($Ty,)*)) -> SimValue<($($Ty,)*)> { 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 ($($var,)*) = self;
let ($($ty_var,)*) = ty; let ($($ty_var,)*) = ty;
$(let $var = $var.to_sim_value_with_type($ty_var);)* $(let $var = $var.to_sim_value($ty_var).into_canonical();)*
SimValue::from_value(ty, ($($var,)*)) SimValue::from_canonical(ToSimValue::into_sim_value(($($var,)*), ty.canonical()))
} }
#[track_caller] #[track_caller]
fn into_sim_value_with_type(self, ty: ($($Ty,)*)) -> SimValue<($($Ty,)*)> { fn into_sim_value(self, ty: ($($Ty,)*)) -> SimValue<($($Ty,)*)> {
let ($($var,)*) = self; let ($($var,)*) = self;
let ($($ty_var,)*) = ty; let ($($ty_var,)*) = ty;
$(let $var = $var.into_sim_value_with_type($ty_var);)* $(let $var = $var.into_sim_value($ty_var).into_canonical();)*
SimValue::from_value(ty, ($($var,)*)) SimValue::from_canonical(ToSimValue::into_sim_value(($($var,)*), ty.canonical()))
}
}
impl<$($T: ToSimValue,)*> ToSimValue for ($($T,)*) {
type Type = ($($T::Type,)*);
#[track_caller]
fn to_sim_value(&self) -> SimValue<Self::Type> {
let ($($var,)*) = self;
$(let $var = $var.to_sim_value();)*
SimValue::from_value(($(SimValue::ty(&$var),)*), ($($var,)*))
} }
#[track_caller] #[track_caller]
fn into_sim_value(self) -> SimValue<Self::Type> { fn box_into_sim_value(self: Box<Self>, ty: ($($Ty,)*)) -> SimValue<($($Ty,)*)> {
let ($($var,)*) = self; Self::into_sim_value(*self, ty)
$(let $var = $var.to_sim_value();)*
SimValue::from_value(($(SimValue::ty(&$var),)*), ($($var,)*))
}
}
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()
}
}
impl<$($Lhs: SimValuePartialEq<$Rhs>, $Rhs: Type,)*> SimValuePartialEq<($($Rhs,)*)> for ($($Lhs,)*) {
fn sim_value_eq(lhs: &SimValue<Self>, rhs: &SimValue<($($Rhs,)*)>) -> bool {
let ($($lhs_var,)*) = &**lhs;
let ($($rhs_var,)*) = &**rhs;
let retval = true;
$(let retval = retval && $lhs_var == $rhs_var;)*
retval
} }
} }
}; };
@ -702,25 +507,24 @@ macro_rules! impl_tuples {
impl_tuples! { impl_tuples! {
[] [ [] [
{#[num = 0, field = field_0, ty = ty0: Ty0, lhs = lhs0: Lhs0, rhs = rhs0: Rhs0] v0: T0} {#[num = 0, field = field_0, ty = ty0: Ty0] v0: T0}
{#[num = 1, field = field_1, ty = ty1: Ty1, lhs = lhs1: Lhs1, rhs = rhs1: Rhs1] v1: T1} {#[num = 1, field = field_1, ty = ty1: Ty1] v1: T1}
{#[num = 2, field = field_2, ty = ty2: Ty2, lhs = lhs2: Lhs2, rhs = rhs2: Rhs2] v2: T2} {#[num = 2, field = field_2, ty = ty2: Ty2] v2: T2}
{#[num = 3, field = field_3, ty = ty3: Ty3, lhs = lhs3: Lhs3, rhs = rhs3: Rhs3] v3: T3} {#[num = 3, field = field_3, ty = ty3: Ty3] v3: T3}
{#[num = 4, field = field_4, ty = ty4: Ty4, lhs = lhs4: Lhs4, rhs = rhs4: Rhs4] v4: T4} {#[num = 4, field = field_4, ty = ty4: Ty4] v4: T4}
{#[num = 5, field = field_5, ty = ty5: Ty5, lhs = lhs5: Lhs5, rhs = rhs5: Rhs5] v5: T5} {#[num = 5, field = field_5, ty = ty5: Ty5] v5: T5}
{#[num = 6, field = field_6, ty = ty6: Ty6, lhs = lhs6: Lhs6, rhs = rhs6: Rhs6] v6: T6} {#[num = 6, field = field_6, ty = ty6: Ty6] v6: T6}
{#[num = 7, field = field_7, ty = ty7: Ty7, lhs = lhs7: Lhs7, rhs = rhs7: Rhs7] v7: T7} {#[num = 7, field = field_7, ty = ty7: Ty7] v7: T7}
{#[num = 8, field = field_8, ty = ty8: Ty8, lhs = lhs8: Lhs8, rhs = rhs8: Rhs8] v8: T8} {#[num = 8, field = field_8, ty = ty8: Ty8] v8: T8}
{#[num = 9, field = field_9, ty = ty9: Ty9, lhs = lhs9: Lhs9, rhs = rhs9: Rhs9] v9: T9} {#[num = 9, field = field_9, ty = ty9: Ty9] v9: T9}
{#[num = 10, field = field_10, ty = ty10: Ty10, lhs = lhs10: Lhs10, rhs = rhs10: Rhs10] v10: T10} {#[num = 10, field = field_10, ty = ty10: Ty10] v10: T10}
{#[num = 11, field = field_11, ty = ty11: Ty11, lhs = lhs11: Lhs11, rhs = rhs11: Rhs11] v11: T11} {#[num = 11, field = field_11, ty = ty11: Ty11] v11: T11}
] ]
} }
impl<T: ?Sized + Send + Sync + 'static> Type for PhantomData<T> { impl<T: ?Sized + Send + Sync + 'static> Type for PhantomData<T> {
type BaseType = Bundle; type BaseType = Bundle;
type MaskType = (); type MaskType = ();
type SimValue = PhantomData<T>;
type MatchVariant = PhantomData<T>; type MatchVariant = PhantomData<T>;
type MatchActiveScope = (); type MatchActiveScope = ();
type MatchVariantAndInactiveScope = MatchVariantWithoutScope<Self::MatchVariant>; type MatchVariantAndInactiveScope = MatchVariantWithoutScope<Self::MatchVariant>;
@ -753,24 +557,6 @@ impl<T: ?Sized + Send + Sync + 'static> Type for PhantomData<T> {
fn source_location() -> SourceLocation { fn source_location() -> SourceLocation {
SourceLocation::builtin() SourceLocation::builtin()
} }
fn sim_value_from_opaque(&self, opaque: OpaqueSimValueSlice<'_>) -> Self::SimValue {
assert!(opaque.is_empty());
*self
}
fn sim_value_clone_from_opaque(
&self,
_value: &mut Self::SimValue,
opaque: OpaqueSimValueSlice<'_>,
) {
assert!(opaque.is_empty());
}
fn sim_value_to_opaque<'w>(
&self,
_value: &Self::SimValue,
writer: OpaqueSimValueWriter<'w>,
) -> OpaqueSimValueWritten<'w> {
writer.fill_cloned_from_slice(OpaqueSimValueSlice::empty())
}
} }
pub struct PhantomDataBuilder<T: ?Sized + Send + Sync + 'static>(PhantomData<T>); pub struct PhantomDataBuilder<T: ?Sized + Send + Sync + 'static>(PhantomData<T>);
@ -818,35 +604,26 @@ impl<T: ?Sized + Send + Sync + 'static> ToExpr for PhantomData<T> {
} }
} }
impl<T: ?Sized + Send + Sync + 'static> ToSimValue for PhantomData<T> { impl<T: ?Sized + Send + Sync + 'static> ToSimValue<Self> for PhantomData<T> {
type Type = PhantomData<T>;
#[track_caller] #[track_caller]
fn to_sim_value(&self) -> SimValue<Self> { fn to_sim_value(&self, ty: Self) -> SimValue<Self> {
SimValue::from_value(*self, *self) ToSimValue::into_sim_value(BitVec::new(), ty)
} }
} }
impl<T: ?Sized + Send + Sync + 'static> ToSimValueWithType<Self> for PhantomData<T> { impl<T: ?Sized> ToSimValue<Bundle> for PhantomData<T> {
#[track_caller] #[track_caller]
fn to_sim_value_with_type(&self, ty: Self) -> SimValue<Self> { fn to_sim_value(&self, ty: Bundle) -> SimValue<Bundle> {
SimValue::from_value(ty, *self)
}
}
impl<T: ?Sized> ToSimValueWithType<Bundle> for PhantomData<T> {
#[track_caller]
fn to_sim_value_with_type(&self, ty: Bundle) -> SimValue<Bundle> {
assert!(ty.fields().is_empty()); assert!(ty.fields().is_empty());
SimValue::from_opaque(ty, OpaqueSimValue::empty()) ToSimValue::into_sim_value(BitVec::new(), ty)
} }
} }
impl<T: ?Sized> ToSimValueWithType<CanonicalType> for PhantomData<T> { impl<T: ?Sized> ToSimValue<CanonicalType> for PhantomData<T> {
#[track_caller] #[track_caller]
fn to_sim_value_with_type(&self, canonical_ty: CanonicalType) -> SimValue<CanonicalType> { fn to_sim_value(&self, ty: CanonicalType) -> SimValue<CanonicalType> {
let ty = Bundle::from_canonical(canonical_ty); let ty = Bundle::from_canonical(ty);
assert!(ty.fields().is_empty()); assert!(ty.fields().is_empty());
SimValue::from_opaque(canonical_ty, OpaqueSimValue::empty()) ToSimValue::into_sim_value(BitVec::new(), ty).into_canonical()
} }
} }

View file

@ -8,10 +8,10 @@ use crate::{
util::{job_server::AcquiredJob, streaming_read_utf8::streaming_read_utf8}, util::{job_server::AcquiredJob, streaming_read_utf8::streaming_read_utf8},
}; };
use clap::{ use clap::{
Parser, Subcommand, ValueEnum, ValueHint,
builder::{OsStringValueParser, TypedValueParser}, builder::{OsStringValueParser, TypedValueParser},
Parser, Subcommand, ValueEnum, ValueHint,
}; };
use eyre::{Report, eyre}; use eyre::{eyre, Report};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::{ use std::{
error, error,
@ -258,7 +258,7 @@ pub struct VerilogArgs {
default_value = "firtool", default_value = "firtool",
env = "FIRTOOL", env = "FIRTOOL",
value_hint = ValueHint::CommandName, value_hint = ValueHint::CommandName,
value_parser = OsStringValueParser::new().try_map(which) value_parser = OsStringValueParser::new().try_map(which::which)
)] )]
pub firtool: PathBuf, pub firtool: PathBuf,
#[arg(long)] #[arg(long)]
@ -301,9 +301,7 @@ impl VerilogArgs {
input.split_once(file_separator_prefix) input.split_once(file_separator_prefix)
{ {
let Some((next_file_name, rest)) = rest.split_once(file_separator_suffix) else { let Some((next_file_name, rest)) = rest.split_once(file_separator_suffix) else {
return Err(CliError(eyre!( return Err(CliError(eyre!("parsing firtool's output failed: found {file_separator_prefix:?} but no {file_separator_suffix:?}")));
"parsing firtool's output failed: found {file_separator_prefix:?} but no {file_separator_suffix:?}"
)));
}; };
input = rest; input = rest;
(chunk, Some(next_file_name.as_ref())) (chunk, Some(next_file_name.as_ref()))
@ -430,13 +428,6 @@ impl clap::Args for FormalAdjustArgs {
} }
} }
fn which(v: std::ffi::OsString) -> which::Result<PathBuf> {
#[cfg(not(miri))]
return which::which(v);
#[cfg(miri)]
return Ok(Path::new("/").join(v));
}
#[derive(Parser, Clone)] #[derive(Parser, Clone)]
#[non_exhaustive] #[non_exhaustive]
pub struct FormalArgs { pub struct FormalArgs {
@ -447,7 +438,7 @@ pub struct FormalArgs {
default_value = "sby", default_value = "sby",
env = "SBY", env = "SBY",
value_hint = ValueHint::CommandName, value_hint = ValueHint::CommandName,
value_parser = OsStringValueParser::new().try_map(which) value_parser = OsStringValueParser::new().try_map(which::which)
)] )]
pub sby: PathBuf, pub sby: PathBuf,
#[arg(long)] #[arg(long)]

View file

@ -6,12 +6,8 @@ use crate::{
int::Bool, int::Bool,
reset::{Reset, ResetType}, reset::{Reset, ResetType},
source_location::SourceLocation, source_location::SourceLocation,
ty::{ ty::{impl_match_variant_as_self, CanonicalType, StaticType, Type, TypeProperties},
CanonicalType, OpaqueSimValueSize, OpaqueSimValueSlice, OpaqueSimValueWriter,
OpaqueSimValueWritten, StaticType, Type, TypeProperties, impl_match_variant_as_self,
},
}; };
use bitvec::{bits, order::Lsb0};
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Default)] #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Default)]
pub struct Clock; pub struct Clock;
@ -19,7 +15,6 @@ pub struct Clock;
impl Type for Clock { impl Type for Clock {
type BaseType = Clock; type BaseType = Clock;
type MaskType = Bool; type MaskType = Bool;
type SimValue = bool;
impl_match_variant_as_self!(); impl_match_variant_as_self!();
@ -41,31 +36,6 @@ impl Type for Clock {
}; };
retval retval
} }
fn sim_value_from_opaque(&self, opaque: OpaqueSimValueSlice<'_>) -> Self::SimValue {
assert_eq!(opaque.size(), OpaqueSimValueSize::from_bit_width(1));
opaque.bits()[0]
}
fn sim_value_clone_from_opaque(
&self,
value: &mut Self::SimValue,
opaque: OpaqueSimValueSlice<'_>,
) {
assert_eq!(opaque.size(), OpaqueSimValueSize::from_bit_width(1));
*value = opaque.bits()[0];
}
fn sim_value_to_opaque<'w>(
&self,
value: &Self::SimValue,
writer: OpaqueSimValueWriter<'w>,
) -> OpaqueSimValueWritten<'w> {
assert_eq!(writer.size(), OpaqueSimValueSize::from_bit_width(1));
writer.fill_cloned_from_slice(OpaqueSimValueSlice::from_bitslice(
[bits![0], bits![1]][*value as usize],
))
}
} }
impl Clock { impl Clock {
@ -85,7 +55,6 @@ impl StaticType for Clock {
is_storable: false, is_storable: false,
is_castable_from_bits: true, is_castable_from_bits: true,
bit_width: 1, bit_width: 1,
sim_only_values_len: 0,
}; };
const MASK_TYPE_PROPERTIES: TypeProperties = Bool::TYPE_PROPERTIES; const MASK_TYPE_PROPERTIES: TypeProperties = Bool::TYPE_PROPERTIES;
} }

View file

@ -2,31 +2,21 @@
// See Notices.txt for copyright information // See Notices.txt for copyright information
use crate::{ use crate::{
expr::{ expr::{ops::VariantAccess, Expr, ToExpr},
Expr, ToExpr,
ops::{ExprPartialEq, VariantAccess},
},
hdl, hdl,
int::{Bool, UIntValue}, int::Bool,
intern::{Intern, Interned}, intern::{Intern, Interned},
module::{ module::{
EnumMatchVariantAndInactiveScopeImpl, EnumMatchVariantsIterImpl, Scope, connect, connect, enum_match_variants_helper, incomplete_wire, wire,
enum_match_variants_helper, incomplete_wire, wire, EnumMatchVariantAndInactiveScopeImpl, EnumMatchVariantsIterImpl, Scope,
}, },
sim::value::{SimValue, SimValuePartialEq},
source_location::SourceLocation, source_location::SourceLocation,
ty::{ ty::{CanonicalType, MatchVariantAndInactiveScope, StaticType, Type, TypeProperties},
CanonicalType, MatchVariantAndInactiveScope, OpaqueSimValue, OpaqueSimValueSize,
OpaqueSimValueSlice, OpaqueSimValueWriter, OpaqueSimValueWritten, StaticType, Type,
TypeProperties,
},
util::HashMap,
}; };
use bitvec::{order::Lsb0, slice::BitSlice, view::BitView}; use hashbrown::HashMap;
use serde::{Deserialize, Serialize}; use std::{convert::Infallible, fmt, iter::FusedIterator};
use std::{convert::Infallible, fmt, iter::FusedIterator, sync::Arc};
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Serialize, Deserialize)] #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub struct EnumVariant { pub struct EnumVariant {
pub name: Interned<str>, pub name: Interned<str>,
pub ty: Option<CanonicalType>, pub ty: Option<CanonicalType>,
@ -121,7 +111,6 @@ impl EnumTypePropertiesBuilder {
is_storable: true, is_storable: true,
is_castable_from_bits: true, is_castable_from_bits: true,
bit_width: 0, bit_width: 0,
sim_only_values_len: 0,
}, },
variant_count: 0, variant_count: 0,
} }
@ -140,14 +129,9 @@ impl EnumTypePropertiesBuilder {
is_storable, is_storable,
is_castable_from_bits, is_castable_from_bits,
bit_width, bit_width,
sim_only_values_len,
}) = field_props }) = field_props
{ {
assert!(is_passive, "variant type must be a passive type"); assert!(is_passive, "variant type must be a passive type");
assert!(
sim_only_values_len == 0,
"can't have `SimOnlyValue`s in an Enum"
);
type_properties = TypeProperties { type_properties = TypeProperties {
is_passive: true, is_passive: true,
is_storable: type_properties.is_storable & is_storable, is_storable: type_properties.is_storable & is_storable,
@ -158,7 +142,6 @@ impl EnumTypePropertiesBuilder {
} else { } else {
type_properties.bit_width type_properties.bit_width
}, },
sim_only_values_len: 0,
}; };
} }
Self { Self {
@ -166,12 +149,6 @@ impl EnumTypePropertiesBuilder {
variant_count: variant_count + 1, variant_count: variant_count + 1,
} }
} }
#[must_use]
pub fn variants(self, variants: impl IntoIterator<Item = EnumVariant>) -> Self {
variants.into_iter().fold(self, |this, variant| {
this.variant(variant.ty.map(CanonicalType::type_properties))
})
}
pub const fn finish(self) -> TypeProperties { pub const fn finish(self) -> TypeProperties {
assert!( assert!(
self.variant_count != 0, self.variant_count != 0,
@ -201,8 +178,7 @@ impl Default for EnumTypePropertiesBuilder {
impl Enum { impl Enum {
#[track_caller] #[track_caller]
pub fn new(variants: Interned<[EnumVariant]>) -> Self { pub fn new(variants: Interned<[EnumVariant]>) -> Self {
let mut name_indexes = let mut name_indexes = HashMap::with_capacity(variants.len());
HashMap::with_capacity_and_hasher(variants.len(), Default::default());
let mut type_props_builder = EnumTypePropertiesBuilder::new(); let mut type_props_builder = EnumTypePropertiesBuilder::new();
for (index, EnumVariant { name, ty }) in variants.iter().enumerate() { for (index, EnumVariant { name, ty }) in variants.iter().enumerate() {
if let Some(old_index) = name_indexes.insert(*name, index) { if let Some(old_index) = name_indexes.insert(*name, index) {
@ -269,7 +245,6 @@ pub trait EnumType:
MatchVariantsIter = EnumMatchVariantsIter<Self>, MatchVariantsIter = EnumMatchVariantsIter<Self>,
> >
{ {
type SimBuilder: From<Self>;
fn variants(&self) -> Interned<[EnumVariant]>; fn variants(&self) -> Interned<[EnumVariant]>;
fn match_activate_scope( fn match_activate_scope(
v: Self::MatchVariantAndInactiveScope, v: Self::MatchVariantAndInactiveScope,
@ -332,18 +307,7 @@ impl<T: EnumType> DoubleEndedIterator for EnumMatchVariantsIter<T> {
} }
} }
pub struct NoBuilder {
_ty: Enum,
}
impl From<Enum> for NoBuilder {
fn from(_ty: Enum) -> Self {
Self { _ty }
}
}
impl EnumType for Enum { impl EnumType for Enum {
type SimBuilder = NoBuilder;
fn match_activate_scope( fn match_activate_scope(
v: Self::MatchVariantAndInactiveScope, v: Self::MatchVariantAndInactiveScope,
) -> (Self::MatchVariant, Self::MatchActiveScope) { ) -> (Self::MatchVariant, Self::MatchActiveScope) {
@ -358,7 +322,6 @@ impl EnumType for Enum {
impl Type for Enum { impl Type for Enum {
type BaseType = Enum; type BaseType = Enum;
type MaskType = Bool; type MaskType = Bool;
type SimValue = OpaqueSimValue;
type MatchVariant = Option<Expr<CanonicalType>>; type MatchVariant = Option<Expr<CanonicalType>>;
type MatchActiveScope = Scope; type MatchActiveScope = Scope;
type MatchVariantAndInactiveScope = EnumMatchVariantAndInactiveScope<Self>; type MatchVariantAndInactiveScope = EnumMatchVariantAndInactiveScope<Self>;
@ -389,341 +352,6 @@ impl Type for Enum {
fn source_location() -> SourceLocation { fn source_location() -> SourceLocation {
SourceLocation::builtin() SourceLocation::builtin()
} }
fn sim_value_from_opaque(&self, opaque: OpaqueSimValueSlice<'_>) -> Self::SimValue {
assert_eq!(self.type_properties().size(), opaque.size());
opaque.to_owned()
}
fn sim_value_clone_from_opaque(
&self,
value: &mut Self::SimValue,
opaque: OpaqueSimValueSlice<'_>,
) {
assert_eq!(self.type_properties().size(), opaque.size());
assert_eq!(value.size(), opaque.size());
value.clone_from_slice(opaque);
}
fn sim_value_to_opaque<'w>(
&self,
value: &Self::SimValue,
writer: OpaqueSimValueWriter<'w>,
) -> OpaqueSimValueWritten<'w> {
assert_eq!(self.type_properties().size(), writer.size());
assert_eq!(value.size(), writer.size());
writer.fill_cloned_from_slice(value.as_slice())
}
}
#[derive(Clone, PartialEq, Eq, Hash, Debug, Default)]
pub struct EnumPaddingSimValue {
bits: Option<UIntValue>,
}
impl EnumPaddingSimValue {
pub const fn new() -> Self {
Self { bits: None }
}
pub fn bit_width(&self) -> Option<usize> {
self.bits.as_ref().map(UIntValue::width)
}
pub fn bits(&self) -> &Option<UIntValue> {
&self.bits
}
pub fn bits_mut(&mut self) -> &mut Option<UIntValue> {
&mut self.bits
}
pub fn into_bits(self) -> Option<UIntValue> {
self.bits
}
pub fn from_bits(bits: Option<UIntValue>) -> Self {
Self { bits }
}
pub fn from_bitslice(v: &BitSlice) -> Self {
Self {
bits: Some(UIntValue::new(Arc::new(v.to_bitvec()))),
}
}
}
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub struct UnknownVariantSimValue {
discriminant: usize,
body_bits: UIntValue,
}
impl UnknownVariantSimValue {
pub fn discriminant(&self) -> usize {
self.discriminant
}
pub fn body_bits(&self) -> &UIntValue {
&self.body_bits
}
pub fn body_bits_mut(&mut self) -> &mut UIntValue {
&mut self.body_bits
}
pub fn into_body_bits(self) -> UIntValue {
self.body_bits
}
pub fn into_parts(self) -> (usize, UIntValue) {
(self.discriminant, self.body_bits)
}
pub fn new(discriminant: usize, body_bits: UIntValue) -> Self {
Self {
discriminant,
body_bits,
}
}
}
pub struct EnumSimValueFromOpaque<'a> {
variants: Interned<[EnumVariant]>,
discriminant: usize,
body_bits: &'a BitSlice,
}
impl<'a> EnumSimValueFromOpaque<'a> {
#[track_caller]
pub fn new<T: EnumType>(ty: T, opaque: OpaqueSimValueSlice<'a>) -> Self {
let variants = ty.variants();
let size = EnumTypePropertiesBuilder::new()
.variants(variants)
.finish()
.size();
assert!(size.only_bit_width().is_some());
assert_eq!(size, opaque.size());
let (discriminant_bits, body_bits) = opaque
.bits()
.split_at(discriminant_bit_width_impl(variants.len()));
let mut discriminant = 0usize;
discriminant.view_bits_mut::<Lsb0>()[..discriminant_bits.len()]
.copy_from_bitslice(discriminant_bits);
Self {
variants,
discriminant,
body_bits,
}
}
pub fn discriminant(&self) -> usize {
self.discriminant
}
#[track_caller]
#[cold]
fn usage_error(&self, clone: bool) -> ! {
let clone = if clone { "clone_" } else { "" };
match self.variants.get(self.discriminant) {
None => {
panic!("should have called EnumSimValueFromBits::unknown_variant_{clone}from_bits");
}
Some(EnumVariant { ty: None, .. }) => {
panic!(
"should have called EnumSimValueFromBits::variant_no_field_{clone}from_bits"
);
}
Some(EnumVariant { ty: Some(_), .. }) => {
panic!(
"should have called EnumSimValueFromBits::variant_with_field_{clone}from_bits"
);
}
}
}
#[track_caller]
fn known_variant(&self, clone: bool) -> (Option<CanonicalType>, &'a BitSlice, &'a BitSlice) {
let Some(EnumVariant { ty, .. }) = self.variants.get(self.discriminant) else {
self.usage_error(clone);
};
let variant_bit_width = ty.map_or(0, CanonicalType::bit_width);
let (variant_bits, padding_bits) = self.body_bits.split_at(variant_bit_width);
(*ty, variant_bits, padding_bits)
}
#[track_caller]
pub fn unknown_variant_from_opaque(self) -> UnknownVariantSimValue {
let None = self.variants.get(self.discriminant) else {
self.usage_error(false);
};
UnknownVariantSimValue::new(
self.discriminant,
UIntValue::new(Arc::new(self.body_bits.to_bitvec())),
)
}
#[track_caller]
pub fn unknown_variant_clone_from_opaque(self, value: &mut UnknownVariantSimValue) {
let None = self.variants.get(self.discriminant) else {
self.usage_error(true);
};
value.discriminant = self.discriminant;
assert_eq!(value.body_bits.width(), self.body_bits.len());
value
.body_bits
.bits_mut()
.copy_from_bitslice(self.body_bits);
}
#[track_caller]
pub fn variant_no_field_from_opaque(self) -> EnumPaddingSimValue {
let (None, _variant_bits, padding_bits) = self.known_variant(false) else {
self.usage_error(false);
};
EnumPaddingSimValue::from_bitslice(padding_bits)
}
#[track_caller]
pub fn variant_with_field_from_opaque<T: Type>(self) -> (SimValue<T>, EnumPaddingSimValue) {
let (Some(variant_ty), variant_bits, padding_bits) = self.known_variant(false) else {
self.usage_error(false);
};
(
SimValue::from_bitslice(T::from_canonical(variant_ty), variant_bits),
EnumPaddingSimValue::from_bitslice(padding_bits),
)
}
#[track_caller]
fn clone_padding_from_bits(padding: &mut EnumPaddingSimValue, padding_bits: &BitSlice) {
match padding.bits_mut() {
None => *padding = EnumPaddingSimValue::from_bitslice(padding_bits),
Some(padding) => {
assert_eq!(padding.width(), padding_bits.len());
padding.bits_mut().copy_from_bitslice(padding_bits);
}
}
}
#[track_caller]
pub fn variant_no_field_clone_from_opaque(self, padding: &mut EnumPaddingSimValue) {
let (None, _variant_bits, padding_bits) = self.known_variant(true) else {
self.usage_error(true);
};
Self::clone_padding_from_bits(padding, padding_bits);
}
#[track_caller]
pub fn variant_with_field_clone_from_opaque<T: Type>(
self,
value: &mut SimValue<T>,
padding: &mut EnumPaddingSimValue,
) {
let (Some(variant_ty), variant_bits, padding_bits) = self.known_variant(true) else {
self.usage_error(true);
};
assert_eq!(SimValue::ty(value), T::from_canonical(variant_ty));
SimValue::bits_mut(value)
.bits_mut()
.copy_from_bitslice(variant_bits);
Self::clone_padding_from_bits(padding, padding_bits);
}
}
pub struct EnumSimValueToOpaque<'a> {
variants: Interned<[EnumVariant]>,
bit_width: usize,
discriminant_bit_width: usize,
writer: OpaqueSimValueWriter<'a>,
}
impl<'a> EnumSimValueToOpaque<'a> {
#[track_caller]
pub fn new<T: EnumType>(ty: T, writer: OpaqueSimValueWriter<'a>) -> Self {
let variants = ty.variants();
let size = EnumTypePropertiesBuilder::new()
.variants(variants)
.finish()
.size();
assert_eq!(size, writer.size());
Self {
variants,
bit_width: size
.only_bit_width()
.expect("enums should only contain bits"),
discriminant_bit_width: discriminant_bit_width_impl(variants.len()),
writer,
}
}
#[track_caller]
fn write_discriminant(&mut self, mut discriminant: usize) {
let orig_discriminant = discriminant;
let discriminant_bits =
&mut discriminant.view_bits_mut::<Lsb0>()[..self.discriminant_bit_width];
self.writer.fill_prefix_with(
OpaqueSimValueSize::from_bit_width(self.discriminant_bit_width),
|writer| {
writer.fill_cloned_from_slice(OpaqueSimValueSlice::from_bitslice(discriminant_bits))
},
);
discriminant_bits.fill(false);
assert!(
discriminant == 0,
"{orig_discriminant:#x} is too big to fit in enum discriminant bits",
);
}
#[track_caller]
pub fn unknown_variant_to_opaque(
mut self,
value: &UnknownVariantSimValue,
) -> OpaqueSimValueWritten<'a> {
self.write_discriminant(value.discriminant);
let None = self.variants.get(value.discriminant) else {
panic!("can't use UnknownVariantSimValue to set known discriminant");
};
assert_eq!(
self.bit_width - self.discriminant_bit_width,
value.body_bits.width()
);
self.writer
.fill_cloned_from_slice(OpaqueSimValueSlice::from_bitslice(value.body_bits.bits()))
}
#[track_caller]
fn known_variant(
mut self,
discriminant: usize,
value: Option<&OpaqueSimValue>,
padding: &EnumPaddingSimValue,
) -> OpaqueSimValueWritten<'a> {
self.write_discriminant(discriminant);
let variant_ty = self.variants[discriminant].ty;
let variant_size = variant_ty.map_or(OpaqueSimValueSize::empty(), CanonicalType::size);
if let Some(value) = value {
if variant_ty.is_none() {
panic!("expected variant to have no field");
}
self.writer.fill_prefix_with(variant_size, |writer| {
writer.fill_cloned_from_slice(value.as_slice())
});
} else if variant_ty.is_some() {
panic!("expected variant to have a field");
}
if let Some(padding) = padding.bits() {
assert_eq!(padding.ty().type_properties().size(), self.writer.size());
self.writer
.fill_cloned_from_slice(OpaqueSimValueSlice::from_bitslice(padding.bits()))
} else {
self.writer.fill_with_zeros()
}
}
#[track_caller]
pub fn variant_no_field_to_opaque(
self,
discriminant: usize,
padding: &EnumPaddingSimValue,
) -> OpaqueSimValueWritten<'a> {
self.known_variant(discriminant, None, padding)
}
#[track_caller]
pub fn variant_with_field_to_opaque<T: Type>(
self,
discriminant: usize,
value: &SimValue<T>,
padding: &EnumPaddingSimValue,
) -> OpaqueSimValueWritten<'a> {
let Some(variant_ty) = self.variants[discriminant].ty else {
panic!("expected variant to have no field");
};
assert_eq!(SimValue::ty(value), T::from_canonical(variant_ty));
self.known_variant(discriminant, Some(SimValue::opaque(value)), padding)
}
}
#[doc(hidden)]
pub fn assert_is_enum_type<T: EnumType>(v: T) -> T {
v
}
#[doc(hidden)]
pub fn enum_type_to_sim_builder<T: EnumType>(v: T) -> T::SimBuilder {
v.into()
} }
#[hdl] #[hdl]
@ -732,79 +360,6 @@ 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
}
}
impl<Lhs: SimValuePartialEq<Rhs>, Rhs: Type> SimValuePartialEq<HdlOption<Rhs>> for HdlOption<Lhs> {
fn sim_value_eq(this: &SimValue<Self>, other: &SimValue<HdlOption<Rhs>>) -> bool {
type SimValueMatch<T> = <T as Type>::SimValue;
match (&**this, &**other) {
(SimValueMatch::<Self>::HdlNone(_), SimValueMatch::<HdlOption<Rhs>>::HdlNone(_)) => {
true
}
(SimValueMatch::<Self>::HdlSome(..), SimValueMatch::<HdlOption<Rhs>>::HdlNone(_))
| (SimValueMatch::<Self>::HdlNone(_), SimValueMatch::<HdlOption<Rhs>>::HdlSome(..)) => {
false
}
(
SimValueMatch::<Self>::HdlSome(l, _),
SimValueMatch::<HdlOption<Rhs>>::HdlSome(r, _),
) => l == r,
}
}
}
#[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()

View file

@ -13,10 +13,9 @@ use crate::{
intern::{Intern, Interned}, intern::{Intern, Interned},
memory::{DynPortType, MemPort, PortType}, memory::{DynPortType, MemPort, PortType},
module::{ module::{
Instance, ModuleIO,
transform::visit::{Fold, Folder, Visit, Visitor}, transform::visit::{Fold, Folder, Visit, Visitor},
Instance, ModuleIO,
}, },
phantom_const::PhantomConst,
reg::Reg, reg::Reg,
reset::{AsyncReset, Reset, ResetType, ResetTypeDispatch, SyncReset}, reset::{AsyncReset, Reset, ResetType, ResetTypeDispatch, SyncReset},
ty::{CanonicalType, StaticType, Type, TypeWithDeref}, ty::{CanonicalType, StaticType, Type, TypeWithDeref},
@ -110,7 +109,6 @@ expr_enum! {
UIntLiteral(Interned<UIntValue>), UIntLiteral(Interned<UIntValue>),
SIntLiteral(Interned<SIntValue>), SIntLiteral(Interned<SIntValue>),
BoolLiteral(bool), BoolLiteral(bool),
PhantomConst(PhantomConst),
BundleLiteral(ops::BundleLiteral), BundleLiteral(ops::BundleLiteral),
ArrayLiteral(ops::ArrayLiteral<CanonicalType, DynSize>), ArrayLiteral(ops::ArrayLiteral<CanonicalType, DynSize>),
EnumLiteral(ops::EnumLiteral), EnumLiteral(ops::EnumLiteral),
@ -274,20 +272,6 @@ pub struct Expr<T: Type> {
impl<T: Type + fmt::Debug> fmt::Debug for Expr<T> { impl<T: Type + fmt::Debug> fmt::Debug for Expr<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
#[cfg(debug_assertions)]
{
let Self {
__enum,
__ty,
__flow,
} = self;
let expr_ty = __ty.canonical();
let enum_ty = __enum.to_expr().__ty;
assert_eq!(
expr_ty, enum_ty,
"expr ty mismatch:\nExpr {{\n__enum: {__enum:?},\n__ty: {__ty:?},\n__flow: {__flow:?}\n}}"
);
}
self.__enum.fmt(f) self.__enum.fmt(f)
} }
} }
@ -532,7 +516,11 @@ impl Flow {
} }
} }
pub const fn flip_if(self, flipped: bool) -> Flow { pub const fn flip_if(self, flipped: bool) -> Flow {
if flipped { self.flip() } else { self } if flipped {
self.flip()
} else {
self
}
} }
} }
@ -710,7 +698,6 @@ impl<T: ToExpr + ?Sized> CastToBits for T {
} }
pub trait CastBitsTo { pub trait CastBitsTo {
#[track_caller]
fn cast_bits_to<T: Type>(&self, ty: T) -> Expr<T>; fn cast_bits_to<T: Type>(&self, ty: T) -> Expr<T>;
} }
@ -768,27 +755,3 @@ pub fn repeat<T: Type, L: SizeType>(
) )
.to_expr() .to_expr()
} }
impl<T: ?Sized + crate::phantom_const::PhantomConstValue> ToExpr for PhantomConst<T> {
type Type = Self;
fn to_expr(&self) -> Expr<Self::Type> {
Expr {
__enum: ExprEnum::PhantomConst(self.canonical_phantom_const()).intern_sized(),
__ty: *self,
__flow: Flow::Source,
}
}
}
impl<T: ?Sized + crate::phantom_const::PhantomConstValue> GetTarget for PhantomConst<T> {
fn target(&self) -> Option<Interned<Target>> {
None
}
}
impl<T: ?Sized + crate::phantom_const::PhantomConstValue> ToLiteralBits for PhantomConst<T> {
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, NotALiteralExpr> {
Ok(Interned::default())
}
}

View file

@ -7,19 +7,18 @@ use crate::{
clock::{Clock, ToClock}, clock::{Clock, ToClock},
enum_::{Enum, EnumType, EnumVariant}, enum_::{Enum, EnumType, EnumVariant},
expr::{ expr::{
CastBitsTo as _, CastTo, CastToBits as _, Expr, ExprEnum, Flow, HdlPartialEq,
HdlPartialOrd, NotALiteralExpr, ReduceBits, ToExpr, ToLiteralBits,
target::{ target::{
GetTarget, Target, TargetPathArrayElement, TargetPathBundleField, GetTarget, Target, TargetPathArrayElement, TargetPathBundleField,
TargetPathDynArrayElement, TargetPathElement, TargetPathDynArrayElement, TargetPathElement,
}, },
CastTo, Expr, ExprEnum, Flow, HdlPartialEq, HdlPartialOrd, NotALiteralExpr, ReduceBits,
ToExpr, ToLiteralBits,
}, },
int::{ int::{
Bool, BoolOrIntType, DynSize, IntType, KnownSize, SInt, SIntType, SIntValue, Size, UInt, Bool, BoolOrIntType, DynSize, IntType, KnownSize, SInt, SIntType, SIntValue, Size, UInt,
UIntType, UIntValue, UIntType, UIntValue,
}, },
intern::{Intern, Interned}, intern::{Intern, Interned},
phantom_const::{PhantomConst, PhantomConstValue},
reset::{ reset::{
AsyncReset, Reset, ResetType, ResetTypeDispatch, SyncReset, ToAsyncReset, ToReset, AsyncReset, Reset, ResetType, ResetTypeDispatch, SyncReset, ToAsyncReset, ToReset,
ToSyncReset, ToSyncReset,
@ -1893,26 +1892,6 @@ impl ExprCastTo<Clock> for Clock {
} }
} }
impl<T: ?Sized + PhantomConstValue> ExprCastTo<()> for PhantomConst<T> {
fn cast_to(src: Expr<Self>, to_type: ()) -> Expr<()> {
src.cast_to_bits().cast_bits_to(to_type)
}
}
impl<T: ?Sized + PhantomConstValue> ExprCastTo<PhantomConst<T>> for () {
fn cast_to(src: Expr<Self>, to_type: PhantomConst<T>) -> Expr<PhantomConst<T>> {
src.cast_to_bits().cast_bits_to(to_type)
}
}
impl<T: ?Sized + PhantomConstValue, U: ?Sized + PhantomConstValue> ExprCastTo<PhantomConst<T>>
for PhantomConst<U>
{
fn cast_to(src: Expr<Self>, to_type: PhantomConst<T>) -> Expr<PhantomConst<T>> {
src.cast_to_bits().cast_bits_to(to_type)
}
}
#[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>,
@ -1937,8 +1916,7 @@ impl<FieldType: Type> FieldAccess<FieldType> {
let field = Expr::ty(base).fields()[field_index]; let field = Expr::ty(base).fields()[field_index];
let field_type = FieldType::from_canonical(field.ty); let field_type = FieldType::from_canonical(field.ty);
let literal_bits = base.to_literal_bits().map(|bits| { let literal_bits = base.to_literal_bits().map(|bits| {
bits[Expr::ty(base).field_offsets()[field_index].bit_width..][..field.ty.bit_width()] bits[Expr::ty(base).field_offsets()[field_index]..][..field.ty.bit_width()].intern()
.intern()
}); });
let target = base.target().map(|base| { let target = base.target().map(|base| {
Intern::intern_sized(base.join(TargetPathElement::intern_sized( Intern::intern_sized(base.join(TargetPathElement::intern_sized(
@ -2730,47 +2708,3 @@ impl<T: Type> ToExpr for Uninit<T> {
} }
} }
} }
pub trait ExprIntoIterator: Type {
type Item: Type;
type ExprIntoIter: Iterator<Item = Expr<Self::Item>>;
fn expr_into_iter(e: Expr<Self>) -> Self::ExprIntoIter;
}
impl<T: ExprIntoIterator> IntoIterator for Expr<T> {
type Item = Expr<T::Item>;
type IntoIter = T::ExprIntoIter;
fn into_iter(self) -> Self::IntoIter {
T::expr_into_iter(self)
}
}
impl<T: ExprIntoIterator> IntoIterator for &'_ Expr<T> {
type Item = Expr<T::Item>;
type IntoIter = T::ExprIntoIter;
fn into_iter(self) -> Self::IntoIter {
T::expr_into_iter(*self)
}
}
impl<T: ExprIntoIterator> IntoIterator for &'_ mut Expr<T> {
type Item = Expr<T::Item>;
type IntoIter = T::ExprIntoIter;
fn into_iter(self) -> Self::IntoIter {
T::expr_into_iter(*self)
}
}
pub trait ExprFromIterator<A>: Type {
fn expr_from_iter<T: IntoIterator<Item = A>>(iter: T) -> Expr<Self>;
}
impl<This: ExprFromIterator<A>, A> FromIterator<A> for Expr<This> {
fn from_iter<T: IntoIterator<Item = A>>(iter: T) -> Self {
This::expr_from_iter(iter)
}
}

File diff suppressed because it is too large Load diff

View file

@ -2,55 +2,27 @@
// See Notices.txt for copyright information // See Notices.txt for copyright information
use crate::{ use crate::{
array::ArrayType,
expr::{ expr::{
Expr, NotALiteralExpr, ToExpr, ToLiteralBits,
target::{GetTarget, Target}, target::{GetTarget, Target},
Expr, NotALiteralExpr, ToExpr, ToLiteralBits,
}, },
hdl,
intern::{Intern, Interned, Memoize}, intern::{Intern, Interned, Memoize},
sim::value::{SimValue, ToSimValueWithType},
source_location::SourceLocation, source_location::SourceLocation,
ty::{ ty::{impl_match_variant_as_self, CanonicalType, StaticType, Type, TypeProperties},
CanonicalType, OpaqueSimValueSize, OpaqueSimValueSlice, OpaqueSimValueWriter, util::{interned_bit, ConstBool, ConstUsize, GenericConstBool, GenericConstUsize},
OpaqueSimValueWritten, StaticType, Type, TypeProperties, impl_match_variant_as_self,
},
util::{ConstBool, ConstUsize, GenericConstBool, GenericConstUsize, interned_bit, slice_range},
}; };
use bitvec::{bits, order::Lsb0, slice::BitSlice, vec::BitVec, view::BitView}; use bitvec::{order::Lsb0, slice::BitSlice, vec::BitVec};
use num_bigint::{BigInt, BigUint, Sign}; use num_bigint::{BigInt, BigUint, Sign};
use num_traits::{One, Signed, Zero}; use num_traits::{Signed, Zero};
use serde::{
Deserialize, Deserializer, Serialize, Serializer,
de::{DeserializeOwned, Error, Visitor},
};
use std::{ use std::{
borrow::{BorrowMut, Cow}, borrow::{BorrowMut, Cow},
fmt, fmt,
marker::PhantomData, marker::PhantomData,
num::NonZero, num::NonZero,
ops::{Index, Not, Range, RangeBounds, RangeInclusive}, ops::{Bound, Index, Not, Range, RangeBounds, RangeInclusive},
str::FromStr,
sync::Arc, sync::Arc,
}; };
mod uint_in_range;
#[hdl]
pub type UIntInRangeType<Start: Size, End: Size> = uint_in_range::UIntInRangeType<Start, End>;
#[hdl]
pub type UIntInRange<const START: usize, const END: usize> =
UIntInRangeType<ConstUsize<START>, ConstUsize<END>>;
#[hdl]
pub type UIntInRangeInclusiveType<Start: Size, End: Size> =
uint_in_range::UIntInRangeInclusiveType<Start, End>;
#[hdl]
pub type UIntInRangeInclusive<const START: usize, const END: usize> =
UIntInRangeInclusiveType<ConstUsize<START>, ConstUsize<END>>;
mod sealed { mod sealed {
pub trait BoolOrIntTypeSealed {} pub trait BoolOrIntTypeSealed {}
pub trait SizeSealed {} pub trait SizeSealed {}
@ -77,16 +49,6 @@ pub trait KnownSize:
+ IntoIterator<Item = Expr<Element>> + IntoIterator<Item = Expr<Element>>
+ TryFrom<Vec<Expr<Element>>> + TryFrom<Vec<Expr<Element>>>
+ Into<Vec<Expr<Element>>>; + Into<Vec<Expr<Element>>>;
type ArraySimValue<Element: Type>: AsRef<[SimValue<Element>]>
+ AsMut<[SimValue<Element>]>
+ BorrowMut<[SimValue<Element>]>
+ 'static
+ Clone
+ std::fmt::Debug
+ IntoIterator<Item = SimValue<Element>>
+ TryFrom<Vec<SimValue<Element>>>
+ Into<Vec<SimValue<Element>>>
+ ToSimValueWithType<ArrayType<Element, Self>>;
} }
macro_rules! known_widths { macro_rules! known_widths {
@ -98,7 +60,6 @@ macro_rules! known_widths {
}> { }> {
const SIZE: Self = Self; const SIZE: Self = Self;
type ArrayMatch<Element: Type> = [Expr<Element>; Self::VALUE]; type ArrayMatch<Element: Type> = [Expr<Element>; Self::VALUE];
type ArraySimValue<Element: Type> = [SimValue<Element>; Self::VALUE];
} }
}; };
([2 $($rest:tt)*] $($bits:literal)+) => { ([2 $($rest:tt)*] $($bits:literal)+) => {
@ -111,7 +72,6 @@ macro_rules! known_widths {
impl KnownSize for ConstUsize<{2 $(* $rest)*}> { impl KnownSize for ConstUsize<{2 $(* $rest)*}> {
const SIZE: Self = Self; const SIZE: Self = Self;
type ArrayMatch<Element: Type> = [Expr<Element>; Self::VALUE]; type ArrayMatch<Element: Type> = [Expr<Element>; Self::VALUE];
type ArraySimValue<Element: Type> = [SimValue<Element>; Self::VALUE];
} }
}; };
} }
@ -119,31 +79,13 @@ macro_rules! known_widths {
known_widths!([2 2 2 2 2 2 2 2 2]); known_widths!([2 2 2 2 2 2 2 2 2]);
pub trait SizeType: pub trait SizeType:
sealed::SizeTypeSealed sealed::SizeTypeSealed + Copy + Ord + std::hash::Hash + std::fmt::Debug + Send + Sync + 'static
+ Copy
+ Ord
+ std::hash::Hash
+ std::fmt::Debug
+ Send
+ Sync
+ 'static
+ Serialize
+ DeserializeOwned
{ {
type Size: Size<SizeType = Self>; type Size: Size<SizeType = Self>;
} }
pub trait Size: pub trait Size:
sealed::SizeSealed sealed::SizeSealed + Copy + Ord + std::hash::Hash + std::fmt::Debug + Send + Sync + 'static
+ Copy
+ Ord
+ std::hash::Hash
+ std::fmt::Debug
+ Send
+ Sync
+ 'static
+ Serialize
+ DeserializeOwned
{ {
type ArrayMatch<Element: Type>: AsRef<[Expr<Element>]> type ArrayMatch<Element: Type>: AsRef<[Expr<Element>]>
+ AsMut<[Expr<Element>]> + AsMut<[Expr<Element>]>
@ -158,16 +100,6 @@ pub trait Size:
+ IntoIterator<Item = Expr<Element>> + IntoIterator<Item = Expr<Element>>
+ TryFrom<Vec<Expr<Element>>> + TryFrom<Vec<Expr<Element>>>
+ Into<Vec<Expr<Element>>>; + Into<Vec<Expr<Element>>>;
type ArraySimValue<Element: Type>: AsRef<[SimValue<Element>]>
+ AsMut<[SimValue<Element>]>
+ BorrowMut<[SimValue<Element>]>
+ 'static
+ Clone
+ std::fmt::Debug
+ IntoIterator<Item = SimValue<Element>>
+ TryFrom<Vec<SimValue<Element>>>
+ Into<Vec<SimValue<Element>>>
+ ToSimValueWithType<ArrayType<Element, Self>>;
const KNOWN_VALUE: Option<usize>; const KNOWN_VALUE: Option<usize>;
type SizeType: SizeType<Size = Self> type SizeType: SizeType<Size = Self>
+ Copy + Copy
@ -193,7 +125,6 @@ impl SizeType for usize {
impl Size for DynSize { impl Size for DynSize {
type ArrayMatch<Element: Type> = Box<[Expr<Element>]>; type ArrayMatch<Element: Type> = Box<[Expr<Element>]>;
type ArraySimValue<Element: Type> = Box<[SimValue<Element>]>;
const KNOWN_VALUE: Option<usize> = None; const KNOWN_VALUE: Option<usize> = None;
type SizeType = usize; type SizeType = usize;
@ -216,7 +147,6 @@ impl<T: KnownSize> SizeType for T {
impl<T: KnownSize> Size for T { impl<T: KnownSize> Size for T {
type ArrayMatch<Element: Type> = <T as KnownSize>::ArrayMatch<Element>; type ArrayMatch<Element: Type> = <T as KnownSize>::ArrayMatch<Element>;
type ArraySimValue<Element: Type> = <T as KnownSize>::ArraySimValue<Element>;
const KNOWN_VALUE: Option<usize> = Some(T::VALUE); const KNOWN_VALUE: Option<usize> = Some(T::VALUE);
@ -227,307 +157,12 @@ impl<T: KnownSize> Size for T {
} }
fn try_from_usize(v: usize) -> Option<Self::SizeType> { fn try_from_usize(v: usize) -> Option<Self::SizeType> {
if v == T::VALUE { Some(T::SIZE) } else { None } if v == T::VALUE {
} Some(T::SIZE)
}
#[derive(Clone, PartialEq, Eq, Debug)]
pub enum ParseIntValueError {
Empty,
InvalidDigit,
MissingDigits,
InvalidRadix,
MissingType,
InvalidType,
TypeMismatch {
parsed_signed: bool,
parsed_width: usize,
expected_signed: bool,
expected_width: usize,
},
PosOverflow,
NegOverflow,
WidthOverflow,
MissingWidth,
}
impl std::error::Error for ParseIntValueError {}
impl fmt::Display for ParseIntValueError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(match self {
Self::Empty => "can't parse integer from empty string",
Self::InvalidDigit => "invalid digit",
Self::MissingDigits => "missing digits",
Self::InvalidRadix => "invalid radix",
Self::MissingType => "missing type",
Self::InvalidType => "invalid type",
Self::TypeMismatch {
parsed_signed,
parsed_width,
expected_signed,
expected_width,
} => {
return write!(
f,
"type mismatch: parsed type {parsed_signed_str}{parsed_width}, \
expected type {expected_signed_str}{expected_width}",
parsed_signed_str = if *parsed_signed { "i" } else { "u" },
expected_signed_str = if *expected_signed { "i" } else { "u" },
);
}
Self::PosOverflow => "value too large to fit in type",
Self::NegOverflow => "value too small to fit in type",
Self::WidthOverflow => "width is too large",
Self::MissingWidth => "missing width",
})
}
}
fn parse_int_value(
s: &str,
type_is_signed: bool,
type_width: Option<usize>,
parse_type: bool,
) -> Result<Arc<BitVec>, ParseIntValueError> {
if !parse_type && type_width.is_none() {
return Err(ParseIntValueError::MissingWidth);
}
let mut s = s.trim();
if s.is_empty() {
return Err(ParseIntValueError::Empty);
}
let negative = match s.bytes().next() {
Some(ch @ (b'+' | b'-')) => {
s = s[1..].trim_start();
ch == b'-'
}
_ => false,
};
let radix = match s.bytes().next() {
Some(b'0') => match s.bytes().nth(1) {
Some(b'x' | b'X') => {
s = &s[2..];
16
}
Some(b'b' | b'B') => {
s = &s[2..];
2
}
Some(b'o' | b'O') => {
s = &s[2..];
8
}
_ => 10,
},
Some(b'1'..=b'9') => 10,
_ => return Err(ParseIntValueError::InvalidDigit),
};
let mut any_digits = false;
let digits_end = s
.as_bytes()
.iter()
.position(|&ch| {
if ch == b'_' {
false
} else if (ch as char).to_digit(radix).is_some() {
any_digits = true;
false
} else { } else {
true None
}
})
.unwrap_or(s.len());
let digits = &s[..digits_end];
s = &s[digits_end..];
if !any_digits {
return Err(ParseIntValueError::MissingDigits);
}
let width = if parse_type {
const HDL_PREFIX: &[u8] = b"hdl_";
let mut missing_type = ParseIntValueError::MissingType;
if s.as_bytes()
.get(..HDL_PREFIX.len())
.is_some_and(|bytes| bytes.eq_ignore_ascii_case(HDL_PREFIX))
{
s = &s[HDL_PREFIX.len()..];
missing_type = ParseIntValueError::InvalidType;
}
let signed = match s.bytes().next() {
Some(b'u' | b'U') => false,
Some(b'i' | b'I') => true,
Some(_) => return Err(ParseIntValueError::InvalidType),
None => return Err(missing_type),
};
s = &s[1..];
let mut width = 0usize;
let mut any_digits = false;
for ch in s.bytes() {
let digit = (ch as char)
.to_digit(10)
.ok_or(ParseIntValueError::InvalidDigit)?;
any_digits = true;
width = width
.checked_mul(10)
.and_then(|v| v.checked_add(digit as usize))
.ok_or(ParseIntValueError::WidthOverflow)?;
}
if !any_digits {
return Err(ParseIntValueError::MissingDigits);
}
if width > <BitSlice>::MAX_BITS {
return Err(ParseIntValueError::WidthOverflow);
}
let expected_width = type_width.unwrap_or(width);
if type_is_signed != signed || expected_width != width {
let expected_width = type_width.unwrap_or(width);
return Err(ParseIntValueError::TypeMismatch {
parsed_signed: signed,
parsed_width: width,
expected_signed: type_is_signed,
expected_width,
});
}
width
} else {
if !s.is_empty() {
return Err(ParseIntValueError::InvalidDigit);
}
type_width.expect("checked earlier")
};
if !type_is_signed && negative {
return Err(ParseIntValueError::InvalidDigit);
}
if radix == 10 {
let mut value: BigInt = digits
.replace("_", "")
.parse()
.expect("checked that the digits are valid already");
if negative {
value = -value;
}
let uint_value: UIntValue = UInt::new(width).from_bigint_wrapping(&value);
if value.is_zero() {
Ok(uint_value.into_bits())
} else {
for i in 0..width {
value.set_bit(i as u64, type_is_signed && negative);
}
if value.is_zero() {
Ok(uint_value.into_bits())
} else if type_is_signed && negative {
if value.sign() == Sign::Minus && value.magnitude().is_one() {
Ok(uint_value.into_bits())
} else {
Err(ParseIntValueError::NegOverflow)
}
} else {
Err(ParseIntValueError::PosOverflow)
} }
} }
} else {
let mut value = BitVec::repeat(false, width);
let bits_per_digit = match radix {
2 => 1,
8 => 3,
16 => 4,
_ => unreachable!(),
};
let mut digits = digits
.bytes()
.rev()
.filter_map(|ch| (ch as char).to_digit(radix));
let overflow_error = if negative {
ParseIntValueError::NegOverflow
} else {
ParseIntValueError::PosOverflow
};
for chunk in value.chunks_mut(bits_per_digit) {
if let Some(mut digit) = digits.next() {
let digit_bits = &mut digit.view_bits_mut::<Lsb0>()[..chunk.len()];
chunk.clone_from_bitslice(digit_bits);
digit_bits.fill(false);
if digit != 0 {
return Err(overflow_error);
}
} else {
break;
}
}
for digit in digits {
if digit != 0 {
return Err(overflow_error);
}
}
let negative_zero = if negative {
// negating a value happens in three regions:
// * the least-significant zeros, which are left as zeros
// * the least-significant one bit, which is left as a one bit
// * all the most-significant bits, which are inverted
// e.g.:
const {
let inp = 0b1010_1_000_u8;
let out = 0b0101_1_000_u8;
assert!(inp.wrapping_neg() == out);
};
if let Some(first_one) = value.first_one() {
let most_significant_bits = &mut value[first_one + 1..];
// modifies in-place despite using `Not::not`
let _ = Not::not(most_significant_bits);
false
} else {
true
}
} else {
false
};
if !negative_zero && type_is_signed && negative != value[value.len() - 1] {
Err(overflow_error)
} else {
Ok(Arc::new(value))
}
}
}
fn deserialize_int_value<'de, D: Deserializer<'de>>(
deserializer: D,
type_is_signed: bool,
type_width: Option<usize>,
) -> Result<Arc<BitVec>, D::Error> {
struct IntValueVisitor {
type_is_signed: bool,
type_width: Option<usize>,
}
impl<'de> Visitor<'de> for IntValueVisitor {
type Value = Arc<BitVec>;
fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(if self.type_is_signed {
"SIntValue"
} else {
"UIntValue"
})?;
if let Some(type_width) = self.type_width {
write!(f, "<{type_width}>")?;
}
Ok(())
}
fn visit_str<E: Error>(self, v: &str) -> Result<Self::Value, E> {
parse_int_value(v, self.type_is_signed, self.type_width, true).map_err(E::custom)
}
fn visit_bytes<E: Error>(self, v: &[u8]) -> Result<Self::Value, E> {
match std::str::from_utf8(v) {
Ok(v) => self.visit_str(v),
Err(_) => Err(Error::invalid_value(serde::de::Unexpected::Bytes(v), &self)),
}
}
}
deserializer.deserialize_str(IntValueVisitor {
type_is_signed,
type_width,
})
} }
macro_rules! impl_int { macro_rules! impl_int {
@ -553,14 +188,19 @@ macro_rules! impl_int {
pub const $name: $generic_name = $generic_name; pub const $name: $generic_name = $generic_name;
impl<Width: Size> $name<Width> { impl<Width: Size> $name<Width> {
pub const fn new(width: Width::SizeType) -> Self { pub fn new(width: Width::SizeType) -> Self {
Self { width } Self { width }
} }
pub fn width(self) -> usize { pub fn width(self) -> usize {
Width::as_usize(self.width) Width::as_usize(self.width)
} }
pub fn type_properties(self) -> TypeProperties { pub fn type_properties(self) -> TypeProperties {
self.as_dyn_int().type_properties_dyn() TypeProperties {
is_passive: true,
is_storable: true,
is_castable_from_bits: true,
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)
@ -623,12 +263,6 @@ macro_rules! impl_int {
} }
Expr::from_dyn_int(MemoizeBitsToExpr.get_cow(bits)) Expr::from_dyn_int(MemoizeBitsToExpr.get_cow(bits))
} }
fn from_str_without_ty(
self,
s: &str,
) -> Result<Self::Value, <Self::Value as FromStr>::Err> {
parse_int_value(s, $SIGNED, Some(self.width()), false).map(Self::Value::new)
}
} }
impl<Width: Size> IntType for $name<Width> { impl<Width: Size> IntType for $name<Width> {
@ -636,21 +270,12 @@ macro_rules! impl_int {
} }
impl $name { impl $name {
pub const fn new_dyn(width: usize) -> Self { pub fn new_dyn(width: usize) -> Self {
Self { width } Self { width }
} }
pub fn bits_to_bigint(bits: &BitSlice) -> BigInt { pub fn bits_to_bigint(bits: &BitSlice) -> BigInt {
<Self as BoolOrIntType>::bits_to_bigint(bits) <Self as BoolOrIntType>::bits_to_bigint(bits)
} }
pub const fn type_properties_dyn(self) -> TypeProperties {
TypeProperties {
is_passive: true,
is_storable: true,
is_castable_from_bits: true,
bit_width: self.width,
sim_only_values_len: 0,
}
}
} }
impl<Width: KnownSize> $name<Width> { impl<Width: KnownSize> $name<Width> {
@ -662,7 +287,6 @@ macro_rules! impl_int {
impl<Width: Size> Type for $name<Width> { impl<Width: Size> Type for $name<Width> {
type BaseType = $pretty_name; type BaseType = $pretty_name;
type MaskType = Bool; type MaskType = Bool;
type SimValue = $value<Width>;
impl_match_variant_as_self!(); impl_match_variant_as_self!();
fn mask_type(&self) -> Self::MaskType { fn mask_type(&self) -> Self::MaskType {
Bool Bool
@ -673,7 +297,7 @@ macro_rules! impl_int {
#[track_caller] #[track_caller]
fn from_canonical(canonical_type: CanonicalType) -> Self { fn from_canonical(canonical_type: CanonicalType) -> Self {
let CanonicalType::$pretty_name(retval) = canonical_type else { let CanonicalType::$pretty_name(retval) = canonical_type else {
panic!("expected {}", stringify!($pretty_name)); panic!("expected {}", stringify!($name));
}; };
$name { $name {
width: Width::from_usize(retval.width), width: Width::from_usize(retval.width),
@ -682,93 +306,18 @@ macro_rules! impl_int {
fn source_location() -> SourceLocation { fn source_location() -> SourceLocation {
SourceLocation::builtin() SourceLocation::builtin()
} }
fn sim_value_from_opaque(&self, opaque: OpaqueSimValueSlice<'_>) -> Self::SimValue {
assert_eq!(
opaque.size(),
OpaqueSimValueSize::from_bit_width(self.width())
);
$value::new(Arc::new(opaque.bits().to_bitvec()))
}
fn sim_value_clone_from_opaque(
&self,
value: &mut Self::SimValue,
opaque: OpaqueSimValueSlice<'_>,
) {
assert_eq!(
opaque.size(),
OpaqueSimValueSize::from_bit_width(self.width())
);
assert_eq!(value.width(), self.width());
value.bits_mut().copy_from_bitslice(opaque.bits());
}
fn sim_value_to_opaque<'w>(
&self,
value: &Self::SimValue,
writer: OpaqueSimValueWriter<'w>,
) -> OpaqueSimValueWritten<'w> {
assert_eq!(
writer.size(),
OpaqueSimValueSize::from_bit_width(self.width())
);
assert_eq!(value.width(), self.width());
writer.fill_cloned_from_slice(OpaqueSimValueSlice::from_bitslice(value.bits()))
}
}
impl<Width: KnownSize> Default for $name<Width> {
fn default() -> Self {
Self::TYPE
}
} }
impl<Width: KnownSize> StaticType for $name<Width> { impl<Width: KnownSize> StaticType for $name<Width> {
const TYPE: Self = Self { width: Width::SIZE }; const TYPE: Self = Self { width: Width::SIZE };
const MASK_TYPE: Self::MaskType = Bool; const MASK_TYPE: Self::MaskType = Bool;
const TYPE_PROPERTIES: TypeProperties = $name { const TYPE_PROPERTIES: TypeProperties = TypeProperties {
width: Width::VALUE, is_passive: true,
} is_storable: true,
.type_properties_dyn(); is_castable_from_bits: true,
const MASK_TYPE_PROPERTIES: TypeProperties = Bool::TYPE_PROPERTIES; bit_width: Width::VALUE,
}
impl<Width: Size> Serialize for $name<Width> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
self.canonical().serialize(serializer)
}
}
impl<'de, Width: Size> Deserialize<'de> for $name<Width> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let name = |width| -> String {
if let Some(width) = width {
format!("a {}<{width}>", stringify!($pretty_name))
} else {
format!("a {}", stringify!($pretty_name))
}
}; };
match CanonicalType::deserialize(deserializer)? { const MASK_TYPE_PROPERTIES: TypeProperties = Bool::TYPE_PROPERTIES;
CanonicalType::$pretty_name(retval) => {
if let Some(width) = Width::try_from_usize(retval.width()) {
Ok($name { width })
} else {
Err(Error::invalid_value(
serde::de::Unexpected::Other(&name(Some(retval.width()))),
&&*name(Width::KNOWN_VALUE),
))
}
}
ty => Err(Error::invalid_value(
serde::de::Unexpected::Other(ty.as_serde_unexpected_str()),
&&*name(Width::KNOWN_VALUE),
)),
}
}
} }
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Default)] #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Default)]
@ -788,7 +337,7 @@ macro_rules! impl_int {
_phantom: PhantomData<Width>, _phantom: PhantomData<Width>,
} }
impl<Width: Size> fmt::Display for $value<Width> { impl<Width: Size> fmt::Debug for $value<Width> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let value = self.to_bigint(); let value = self.to_bigint();
let (sign, magnitude) = value.into_parts(); let (sign, magnitude) = value.into_parts();
@ -802,38 +351,15 @@ macro_rules! impl_int {
} }
} }
impl<Width: Size> fmt::Debug for $value<Width> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(self, f)
}
}
impl<Width: Size> std::str::FromStr for $value<Width> {
type Err = ParseIntValueError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
parse_int_value(s, $SIGNED, Width::KNOWN_VALUE, true).map(Self::new)
}
}
impl<Width: Size> Serialize for $value<Width> {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
self.to_string().serialize(serializer)
}
}
impl<'de, Width: Size> Deserialize<'de> for $value<Width> {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
deserialize_int_value(deserializer, $SIGNED, Width::KNOWN_VALUE).map(Self::new)
}
}
impl<Width: Size> PartialOrd for $value<Width> { impl<Width: Size> PartialOrd for $value<Width> {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> { fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
if self.width() != other.width() { Some(self.cmp(other))
return None;
} }
Some(self.to_bigint().cmp(&other.to_bigint())) }
impl<Width: Size> Ord for $value<Width> {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.to_bigint().cmp(&other.to_bigint())
} }
} }
@ -875,9 +401,6 @@ macro_rules! impl_int {
pub fn bits(&self) -> &Arc<BitVec> { pub fn bits(&self) -> &Arc<BitVec> {
&self.bits &self.bits
} }
pub fn bits_mut(&mut self) -> &mut BitSlice {
Arc::<BitVec>::make_mut(&mut self.bits)
}
} }
impl<Width: Size> ToLiteralBits for $value<Width> { impl<Width: Size> ToLiteralBits for $value<Width> {
@ -919,9 +442,6 @@ macro_rules! impl_int {
_phantom: PhantomData, _phantom: PhantomData,
} }
} }
pub fn bitvec_mut(&mut self) -> &mut BitVec {
Arc::make_mut(&mut self.bits)
}
} }
}; };
} }
@ -935,10 +455,6 @@ impl UInt {
let v: BigUint = v.into(); let v: BigUint = v.into();
Self::new(v.bits().try_into().expect("too big")) Self::new(v.bits().try_into().expect("too big"))
} }
/// gets the smallest `UInt` that fits `v` losslessly
pub const fn for_value_usize(v: usize) -> Self {
Self::new((usize::BITS - v.leading_zeros()) as usize)
}
/// gets the smallest `UInt` that fits `r` losslessly, panics if `r` is empty /// gets the smallest `UInt` that fits `r` losslessly, panics if `r` is empty
#[track_caller] #[track_caller]
pub fn range(r: Range<impl Into<BigUint>>) -> Self { pub fn range(r: Range<impl Into<BigUint>>) -> Self {
@ -949,12 +465,6 @@ impl UInt {
} }
/// gets the smallest `UInt` that fits `r` losslessly, panics if `r` is empty /// gets the smallest `UInt` that fits `r` losslessly, panics if `r` is empty
#[track_caller] #[track_caller]
pub const fn range_usize(r: Range<usize>) -> Self {
assert!(r.end != 0, "empty range");
Self::range_inclusive_usize(r.start..=(r.end - 1))
}
/// gets the smallest `UInt` that fits `r` losslessly, panics if `r` is empty
#[track_caller]
pub fn range_inclusive(r: RangeInclusive<impl Into<BigUint>>) -> Self { pub fn range_inclusive(r: RangeInclusive<impl Into<BigUint>>) -> Self {
let (start, end) = r.into_inner(); let (start, end) = r.into_inner();
let start: BigUint = start.into(); let start: BigUint = start.into();
@ -964,16 +474,6 @@ impl UInt {
// so must not take more bits than `end` // so must not take more bits than `end`
Self::for_value(end) Self::for_value(end)
} }
/// gets the smallest `UInt` that fits `r` losslessly, panics if `r` is empty
#[track_caller]
pub const fn range_inclusive_usize(r: RangeInclusive<usize>) -> Self {
let start = *r.start();
let end = *r.end();
assert!(start <= end, "empty range");
// no need to check `start`` since it's no larger than `end`
// so must not take more bits than `end`
Self::for_value_usize(end)
}
} }
impl SInt { impl SInt {
@ -1067,12 +567,12 @@ 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>`][type@UInt] /// for portability reasons, [`usize`] always translates to [`UInt<64>`]
usize, UInt<64> usize, UInt<64>
); );
impl_prim_int!( impl_prim_int!(
/// for portability reasons, [`isize`] always translates to [`SInt<64>`][type@SInt] /// for portability reasons, [`isize`] always translates to [`SInt<64>`]
isize, SInt<64> isize, SInt<64>
); );
@ -1080,17 +580,14 @@ pub trait BoolOrIntType: Type + sealed::BoolOrIntTypeSealed {
type Width: Size; type Width: Size;
type Signed: GenericConstBool; type Signed: GenericConstBool;
type Value: Clone type Value: Clone
+ PartialOrd + Ord
+ Eq
+ std::hash::Hash + std::hash::Hash
+ fmt::Debug + fmt::Debug
+ fmt::Display
+ Send + Send
+ Sync + Sync
+ 'static + 'static
+ ToExpr<Type = Self> + ToExpr<Type = Self>
+ Into<BigInt> + Into<BigInt>;
+ std::str::FromStr;
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
@ -1124,12 +621,6 @@ pub trait BoolOrIntType: Type + sealed::BoolOrIntTypeSealed {
let bitslice = &BitSlice::<u8, Lsb0>::from_slice(&bytes)[..width]; let bitslice = &BitSlice::<u8, Lsb0>::from_slice(&bytes)[..width];
bits.clone_from_bitslice(bitslice); bits.clone_from_bitslice(bitslice);
} }
fn bits_equal_bigint_wrapping(v: &BigInt, bits: &BitSlice) -> bool {
bits.iter()
.by_vals()
.enumerate()
.all(|(bit_index, bit): (usize, bool)| v.bit(bit_index as u64) == bit)
}
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) {
0xFF 0xFF
@ -1163,12 +654,9 @@ pub trait BoolOrIntType: Type + sealed::BoolOrIntTypeSealed {
bytes, bit_width, bytes, bit_width,
))) )))
} }
fn from_str_without_ty(self, s: &str) -> Result<Self::Value, <Self::Value as FromStr>::Err>;
} }
pub trait IntType: pub trait IntType: BoolOrIntType<BaseType = <Self as IntType>::Dyn> {
BoolOrIntType<BaseType = <Self as IntType>::Dyn, Value: FromStr<Err = ParseIntValueError>>
{
type Dyn: IntType<Dyn = Self::Dyn, Signed = Self::Signed, Width = DynSize>; type Dyn: IntType<Dyn = Self::Dyn, Signed = Self::Signed, Width = DynSize>;
fn as_dyn_int(self) -> Self::Dyn { fn as_dyn_int(self) -> Self::Dyn {
Self::new_dyn(self.width()) Self::new_dyn(self.width())
@ -1184,7 +672,19 @@ pub trait IntType:
Self::Dyn::new(width) Self::Dyn::new(width)
} }
fn slice_index_to_range<I: RangeBounds<usize>>(self, index: I) -> Range<usize> { fn slice_index_to_range<I: RangeBounds<usize>>(self, index: I) -> Range<usize> {
slice_range(index, self.width()) let width = self.width();
let start = match index.start_bound() {
Bound::Included(start) => *start,
Bound::Excluded(start) => *start + 1,
Bound::Unbounded => 0,
};
let end = match index.end_bound() {
Bound::Included(end) => *end + 1,
Bound::Excluded(end) => *end,
Bound::Unbounded => width,
};
assert!(start <= end && end <= width, "slice range out-of-range");
start..end
} }
fn slice_and_shift<I: RangeBounds<usize>>(self, index: I) -> (UInt, usize) { fn slice_and_shift<I: RangeBounds<usize>>(self, index: I) -> (UInt, usize) {
let range = self.slice_index_to_range(index); let range = self.slice_index_to_range(index);
@ -1196,7 +696,7 @@ pub trait IntType:
} }
} }
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Default)] #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub struct Bool; pub struct Bool;
impl sealed::BoolOrIntTypeSealed for Bool {} impl sealed::BoolOrIntTypeSealed for Bool {}
@ -1228,10 +728,6 @@ impl BoolOrIntType for Bool {
assert_eq!(bits.len(), 1); assert_eq!(bits.len(), 1);
bits[0] bits[0]
} }
fn from_str_without_ty(self, s: &str) -> Result<Self::Value, <Self::Value as FromStr>::Err> {
FromStr::from_str(s)
}
} }
impl Bool { impl Bool {
@ -1246,7 +742,6 @@ impl Bool {
impl Type for Bool { impl Type for Bool {
type BaseType = Bool; type BaseType = Bool;
type MaskType = Bool; type MaskType = Bool;
type SimValue = bool;
impl_match_variant_as_self!(); impl_match_variant_as_self!();
fn mask_type(&self) -> Self::MaskType { fn mask_type(&self) -> Self::MaskType {
Bool Bool
@ -1264,28 +759,6 @@ impl Type for Bool {
fn source_location() -> SourceLocation { fn source_location() -> SourceLocation {
SourceLocation::builtin() SourceLocation::builtin()
} }
fn sim_value_from_opaque(&self, opaque: OpaqueSimValueSlice<'_>) -> Self::SimValue {
assert_eq!(opaque.size(), OpaqueSimValueSize::from_bit_width(1));
opaque.bits()[0]
}
fn sim_value_clone_from_opaque(
&self,
value: &mut Self::SimValue,
opaque: OpaqueSimValueSlice<'_>,
) {
assert_eq!(opaque.size(), OpaqueSimValueSize::from_bit_width(1));
*value = opaque.bits()[0];
}
fn sim_value_to_opaque<'w>(
&self,
value: &Self::SimValue,
writer: OpaqueSimValueWriter<'w>,
) -> OpaqueSimValueWritten<'w> {
assert_eq!(writer.size(), OpaqueSimValueSize::from_bit_width(1));
writer.fill_cloned_from_slice(OpaqueSimValueSlice::from_bitslice(
[bits![0], bits![1]][*value as usize],
))
}
} }
impl StaticType for Bool { impl StaticType for Bool {
@ -1296,7 +769,6 @@ impl StaticType for Bool {
is_storable: true, is_storable: true,
is_castable_from_bits: true, is_castable_from_bits: true,
bit_width: 1, bit_width: 1,
sim_only_values_len: 0,
}; };
const MASK_TYPE_PROPERTIES: TypeProperties = Bool::TYPE_PROPERTIES; const MASK_TYPE_PROPERTIES: TypeProperties = Bool::TYPE_PROPERTIES;
} }
@ -1311,13 +783,6 @@ impl ToLiteralBits for bool {
mod tests { mod tests {
use super::*; use super::*;
#[test]
fn test_different_value_widths_compare_ne() {
// interning relies on [SU]IntValue with different `width` comparing not equal
assert_ne!(UInt[3].from_int_wrapping(0), UInt[4].from_int_wrapping(0));
assert_ne!(SInt[3].from_int_wrapping(0), SInt[4].from_int_wrapping(0));
}
#[test] #[test]
fn test_uint_for_value() { fn test_uint_for_value() {
assert_eq!(UInt::for_value(0u8).width, 0); assert_eq!(UInt::for_value(0u8).width, 0);
@ -1340,104 +805,4 @@ mod tests {
assert_eq!(SInt::for_value(3).width, 3); assert_eq!(SInt::for_value(3).width, 3);
assert_eq!(SInt::for_value(4).width, 4); assert_eq!(SInt::for_value(4).width, 4);
} }
#[test]
fn test_serde_round_trip() {
use serde_json::json;
#[track_caller]
fn check<T: Serialize + DeserializeOwned + PartialEq + fmt::Debug>(
value: T,
expected: serde_json::Value,
) {
assert_eq!(serde_json::to_value(&value).unwrap(), expected);
assert_eq!(value, T::deserialize(expected).unwrap());
}
check(UInt[0], json! { { "UInt": { "width": 0 } } });
check(UInt::<0>::TYPE, json! { { "UInt": { "width": 0 } } });
check(UInt::<35>::TYPE, json! { { "UInt": { "width": 35 } } });
check(SInt[0], json! { { "SInt": { "width": 0 } } });
check(SInt::<0>::TYPE, json! { { "SInt": { "width": 0 } } });
check(SInt::<35>::TYPE, json! { { "SInt": { "width": 35 } } });
check(Bool, json! { "Bool" });
check(UIntValue::from(0u8), json! { "0x0_u8" });
check(SIntValue::from(-128i8), json! { "-0x80_i8" });
check(UInt[3].from_int_wrapping(5), json! { "0x5_u3" });
check(UInt[12].from_int_wrapping(0x1123), json! { "0x123_u12" });
check(SInt[12].from_int_wrapping(0xFEE), json! { "-0x12_i12" });
check(SInt[12].from_int_wrapping(0x7EE), json! { "0x7EE_i12" });
}
#[test]
fn test_deserialize() {
use serde_json::json;
#[track_caller]
fn check<T: DeserializeOwned + fmt::Debug + PartialEq>(
expected: Result<T, &str>,
input: serde_json::Value,
) {
let mut error = String::new();
let value = T::deserialize(input).map_err(|e| -> &str {
error = e.to_string();
&error
});
assert_eq!(value, expected);
}
check::<UInt<0>>(
Err("invalid value: a UInt<2>, expected a UInt<0>"),
json! { { "UInt": { "width": 2 } } },
);
check::<UInt<0>>(
Err("invalid value: a Bool, expected a UInt<0>"),
json! { "Bool" },
);
check::<SInt<0>>(
Err("invalid value: a Bool, expected a SInt<0>"),
json! { "Bool" },
);
check::<UInt>(
Err("invalid value: a Bool, expected a UInt"),
json! { "Bool" },
);
check::<SInt>(
Err("invalid value: a Bool, expected a SInt"),
json! { "Bool" },
);
check::<UIntValue>(Err("value too large to fit in type"), json! { "2_u1" });
check::<UIntValue>(Err("value too large to fit in type"), json! { "10_u1" });
check::<UIntValue>(Err("value too large to fit in type"), json! { "0x2_u1" });
check::<UIntValue>(Err("value too large to fit in type"), json! { "0b10_u1" });
check::<UIntValue>(Err("value too large to fit in type"), json! { "0o2_u1" });
check::<SIntValue>(Err("value too large to fit in type"), json! { "0o377_i8" });
check::<SIntValue>(Err("value too large to fit in type"), json! { "0o200_i8" });
check(Ok(SInt[8].from_int_wrapping(i8::MAX)), json! { "0o177_i8" });
check::<SIntValue>(Err("value too small to fit in type"), json! { "-0o201_i8" });
check::<SIntValue>(Err("value too small to fit in type"), json! { "-0o377_i8" });
check::<SIntValue>(Err("value too small to fit in type"), json! { "-0o400_i8" });
check::<SIntValue>(
Err("value too small to fit in type"),
json! { "-0o4000_i8" },
);
check(Ok(UIntValue::from(0u8)), json! { "0_u8" });
check(Ok(UIntValue::from(0u8)), json! { "0b0_u8" });
check(Ok(UIntValue::from(0u8)), json! { "00_u8" });
check(Ok(UIntValue::from(0u8)), json! { "0x0_u8" });
check(Ok(UIntValue::from(0u8)), json! { "0o0_u8" });
check(Ok(SIntValue::from(-128i8)), json! { "-0x000_80_i8" });
check(Ok(SIntValue::from(-128i8)), json! { "-0o002_00_hdl_i8" });
check(Ok(SIntValue::from(-128i8)), json! { "-0b1__000_0000_i8" });
check(Ok(UInt[3].from_int_wrapping(5)), json! { " + 0x5_u3 " });
check(
Ok(UInt[12].from_int_wrapping(0x1123)),
json! { "0x1_2_3_hdl_u12" },
);
check(Ok(SInt[12].from_int_wrapping(0xFEE)), json! { "-0x12_i12" });
check(
Ok(SInt[12].from_int_wrapping(0x7EE)),
json! { " + \t0x7__E_e_i012\n" },
);
check(Ok(SInt[0].from_int_wrapping(0)), json! { "-0i0" });
check(Ok(SInt[1].from_int_wrapping(0)), json! { "-0i1" });
check(Ok(SInt[0].from_int_wrapping(0)), json! { "-0x0i0" });
check(Ok(SInt[1].from_int_wrapping(0)), json! { "-0x0i1" });
}
} }

View file

@ -1,643 +0,0 @@
// SPDX-License-Identifier: LGPL-3.0-or-later
// See Notices.txt for copyright information
use crate::{
bundle::{Bundle, BundleField, BundleType, BundleTypePropertiesBuilder, NoBuilder},
expr::{
CastBitsTo, CastTo, CastToBits, Expr, HdlPartialEq, HdlPartialOrd,
ops::{ExprCastTo, ExprPartialEq, ExprPartialOrd},
},
int::{Bool, DynSize, KnownSize, Size, SizeType, UInt, UIntType},
intern::{Intern, Interned},
phantom_const::PhantomConst,
sim::value::{SimValue, SimValuePartialEq, ToSimValueWithType},
source_location::SourceLocation,
ty::{
CanonicalType, OpaqueSimValueSlice, OpaqueSimValueWriter, OpaqueSimValueWritten,
StaticType, Type, TypeProperties, impl_match_variant_as_self,
},
};
use bitvec::{order::Lsb0, view::BitView};
use serde::{
Deserialize, Deserializer, Serialize, Serializer,
de::{Error, Visitor, value::UsizeDeserializer},
};
use std::{fmt, marker::PhantomData, ops::Index};
const UINT_IN_RANGE_TYPE_FIELD_NAMES: [&'static str; 2] = ["value", "range"];
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Default)]
pub struct UIntInRangeMaskType {
value: Bool,
range: PhantomConstRangeMaskType,
}
impl Type for UIntInRangeMaskType {
type BaseType = Bundle;
type MaskType = Self;
type SimValue = bool;
impl_match_variant_as_self!();
fn mask_type(&self) -> Self::MaskType {
*self
}
fn canonical(&self) -> CanonicalType {
CanonicalType::Bundle(Bundle::new(self.fields()))
}
fn from_canonical(canonical_type: CanonicalType) -> Self {
let fields = Bundle::from_canonical(canonical_type).fields();
let [
BundleField {
name: value_name,
flipped: false,
ty: value,
},
BundleField {
name: range_name,
flipped: false,
ty: range,
},
] = *fields
else {
panic!("expected UIntInRangeMaskType");
};
assert_eq!([&*value_name, &*range_name], UINT_IN_RANGE_TYPE_FIELD_NAMES);
let value = Bool::from_canonical(value);
let range = PhantomConstRangeMaskType::from_canonical(range);
Self { value, range }
}
fn source_location() -> SourceLocation {
SourceLocation::builtin()
}
fn sim_value_from_opaque(&self, opaque: OpaqueSimValueSlice<'_>) -> Self::SimValue {
Bool.sim_value_from_opaque(opaque)
}
fn sim_value_clone_from_opaque(
&self,
value: &mut Self::SimValue,
opaque: OpaqueSimValueSlice<'_>,
) {
Bool.sim_value_clone_from_opaque(value, opaque);
}
fn sim_value_to_opaque<'w>(
&self,
value: &Self::SimValue,
writer: OpaqueSimValueWriter<'w>,
) -> OpaqueSimValueWritten<'w> {
Bool.sim_value_to_opaque(value, writer)
}
}
impl BundleType for UIntInRangeMaskType {
type Builder = NoBuilder;
type FilledBuilder = Expr<UIntInRangeMaskType>;
fn fields(&self) -> Interned<[BundleField]> {
let [value_name, range_name] = UINT_IN_RANGE_TYPE_FIELD_NAMES;
let Self { value, range } = self;
[
BundleField {
name: value_name.intern(),
flipped: false,
ty: value.canonical(),
},
BundleField {
name: range_name.intern(),
flipped: false,
ty: range.canonical(),
},
][..]
.intern()
}
}
impl StaticType for UIntInRangeMaskType {
const TYPE: Self = Self {
value: Bool,
range: PhantomConstRangeMaskType::TYPE,
};
const MASK_TYPE: Self::MaskType = Self::TYPE;
const TYPE_PROPERTIES: TypeProperties = BundleTypePropertiesBuilder::new()
.field(false, Bool::TYPE_PROPERTIES)
.field(false, PhantomConstRangeMaskType::TYPE_PROPERTIES)
.finish();
const MASK_TYPE_PROPERTIES: TypeProperties = Self::TYPE_PROPERTIES;
}
impl ToSimValueWithType<UIntInRangeMaskType> for bool {
fn to_sim_value_with_type(&self, ty: UIntInRangeMaskType) -> SimValue<UIntInRangeMaskType> {
SimValue::from_value(ty, *self)
}
}
impl ExprCastTo<Bool> for UIntInRangeMaskType {
fn cast_to(src: Expr<Self>, to_type: Bool) -> Expr<Bool> {
src.cast_to_bits().cast_to(to_type)
}
}
impl ExprCastTo<UIntInRangeMaskType> for Bool {
fn cast_to(src: Expr<Self>, to_type: UIntInRangeMaskType) -> Expr<UIntInRangeMaskType> {
src.cast_to_static::<UInt<1>>().cast_bits_to(to_type)
}
}
impl ExprPartialEq<Self> for UIntInRangeMaskType {
fn cmp_eq(lhs: Expr<Self>, rhs: Expr<Self>) -> Expr<Bool> {
lhs.cast_to_bits().cmp_eq(rhs.cast_to_bits())
}
fn cmp_ne(lhs: Expr<Self>, rhs: Expr<Self>) -> Expr<Bool> {
lhs.cast_to_bits().cmp_ne(rhs.cast_to_bits())
}
}
impl SimValuePartialEq<Self> for UIntInRangeMaskType {
fn sim_value_eq(this: &SimValue<Self>, other: &SimValue<Self>) -> bool {
**this == **other
}
}
type PhantomConstRangeMaskType = <PhantomConst<SerdeRange<DynSize, DynSize>> as Type>::MaskType;
#[derive(Default, Copy, Clone, Debug)]
struct RangeParseError;
macro_rules! define_uint_in_range_type {
(
$UIntInRange:ident,
$UIntInRangeType:ident,
$UIntInRangeTypeWithoutGenerics:ident,
$UIntInRangeTypeWithStart:ident,
$SerdeRange:ident,
$range_operator_str:literal,
|$uint_range_usize_start:ident, $uint_range_usize_end:ident| $uint_range_usize:expr,
) => {
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
struct $SerdeRange<Start: Size, End: Size> {
start: Start::SizeType,
end: End::SizeType,
}
impl<Start: KnownSize, End: KnownSize> Default for $SerdeRange<Start, End> {
fn default() -> Self {
Self {
start: Start::SIZE,
end: End::SIZE,
}
}
}
impl std::str::FromStr for $SerdeRange<DynSize, DynSize> {
type Err = RangeParseError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let Some((start, end)) = s.split_once($range_operator_str) else {
return Err(RangeParseError);
};
if start.is_empty()
|| start.bytes().any(|b| !b.is_ascii_digit())
|| end.is_empty()
|| end.bytes().any(|b| !b.is_ascii_digit())
{
return Err(RangeParseError);
}
let start = start.parse().map_err(|_| RangeParseError)?;
let end = end.parse().map_err(|_| RangeParseError)?;
let retval = Self { start, end };
if retval.is_empty() {
Err(RangeParseError)
} else {
Ok(retval)
}
}
}
impl<Start: Size, End: Size> fmt::Display for $SerdeRange<Start, End> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let Self { start, end } = *self;
write!(
f,
"{}{}{}",
Start::as_usize(start),
$range_operator_str,
End::as_usize(end),
)
}
}
impl<Start: Size, End: Size> Serialize for $SerdeRange<Start, End> {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
serializer.collect_str(self)
}
}
impl<'de, Start: Size, End: Size> Deserialize<'de> for $SerdeRange<Start, End> {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
struct SerdeRangeVisitor<Start: Size, End: Size>(PhantomData<(Start, End)>);
impl<'de, Start: Size, End: Size> Visitor<'de> for SerdeRangeVisitor<Start, End> {
type Value = $SerdeRange<Start, End>;
fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("a string with format \"")?;
if let Some(start) = Start::KNOWN_VALUE {
write!(f, "{start}")?;
} else {
f.write_str("<int>")?;
};
f.write_str($range_operator_str)?;
if let Some(end) = End::KNOWN_VALUE {
write!(f, "{end}")?;
} else {
f.write_str("<int>")?;
};
f.write_str("\" that is a non-empty range")
}
fn visit_str<E: Error>(self, v: &str) -> Result<Self::Value, E> {
let $SerdeRange::<DynSize, DynSize> { start, end } =
v.parse().map_err(|_| {
Error::invalid_value(serde::de::Unexpected::Str(v), &self)
})?;
let start =
Start::SizeType::deserialize(UsizeDeserializer::<E>::new(start))?;
let end = End::SizeType::deserialize(UsizeDeserializer::<E>::new(end))?;
Ok($SerdeRange { start, end })
}
fn visit_bytes<E: Error>(self, v: &[u8]) -> Result<Self::Value, E> {
match std::str::from_utf8(v) {
Ok(v) => self.visit_str(v),
Err(_) => {
Err(Error::invalid_value(serde::de::Unexpected::Bytes(v), &self))
}
}
}
}
deserializer.deserialize_str(SerdeRangeVisitor(PhantomData))
}
}
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub struct $UIntInRangeType<Start: Size, End: Size> {
value: UInt,
range: PhantomConst<$SerdeRange<Start, End>>,
}
impl<Start: Size, End: Size> $UIntInRangeType<Start, End> {
fn from_phantom_const_range(range: PhantomConst<$SerdeRange<Start, End>>) -> Self {
let $SerdeRange { start, end } = *range.get();
let $uint_range_usize_start = Start::as_usize(start);
let $uint_range_usize_end = End::as_usize(end);
Self {
value: $uint_range_usize,
range,
}
}
pub fn new(start: Start::SizeType, end: End::SizeType) -> Self {
Self::from_phantom_const_range(PhantomConst::new(
$SerdeRange { start, end }.intern_sized(),
))
}
}
impl<Start: Size, End: Size> fmt::Debug for $UIntInRangeType<Start, End> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let Self { value, range } = self;
let $SerdeRange { start, end } = *range.get();
f.debug_struct(&format!(
"{}<{}, {}>",
stringify!($UIntInRange),
Start::as_usize(start),
End::as_usize(end),
))
.field("value", value)
.finish_non_exhaustive()
}
}
impl<Start: Size, End: Size> Type for $UIntInRangeType<Start, End> {
type BaseType = Bundle;
type MaskType = UIntInRangeMaskType;
type SimValue = usize;
impl_match_variant_as_self!();
fn mask_type(&self) -> Self::MaskType {
UIntInRangeMaskType::TYPE
}
fn canonical(&self) -> CanonicalType {
CanonicalType::Bundle(Bundle::new(self.fields()))
}
fn from_canonical(canonical_type: CanonicalType) -> Self {
let fields = Bundle::from_canonical(canonical_type).fields();
let [
BundleField {
name: value_name,
flipped: false,
ty: value,
},
BundleField {
name: range_name,
flipped: false,
ty: range,
},
] = *fields
else {
panic!("expected {}", stringify!($UIntInRange));
};
assert_eq!([&*value_name, &*range_name], UINT_IN_RANGE_TYPE_FIELD_NAMES);
let value = UInt::from_canonical(value);
let range = PhantomConst::<$SerdeRange<Start, End>>::from_canonical(range);
let retval = Self::from_phantom_const_range(range);
assert_eq!(retval, Self { value, range });
retval
}
fn source_location() -> SourceLocation {
SourceLocation::builtin()
}
fn sim_value_from_opaque(&self, opaque: OpaqueSimValueSlice<'_>) -> Self::SimValue {
assert_eq!(opaque.size(), self.value.type_properties().size());
let mut retval = 0usize;
retval.view_bits_mut::<Lsb0>()[..opaque.bit_width()]
.clone_from_bitslice(opaque.bits());
retval
}
fn sim_value_clone_from_opaque(
&self,
value: &mut Self::SimValue,
opaque: OpaqueSimValueSlice<'_>,
) {
*value = self.sim_value_from_opaque(opaque);
}
fn sim_value_to_opaque<'w>(
&self,
value: &Self::SimValue,
writer: OpaqueSimValueWriter<'w>,
) -> OpaqueSimValueWritten<'w> {
writer.fill_cloned_from_slice(OpaqueSimValueSlice::from_bitslice(
&value.view_bits::<Lsb0>()[..self.value.width()],
))
}
}
impl<Start: Size, End: Size> BundleType for $UIntInRangeType<Start, End> {
type Builder = NoBuilder;
type FilledBuilder = Expr<Self>;
fn fields(&self) -> Interned<[BundleField]> {
let [value_name, range_name] = UINT_IN_RANGE_TYPE_FIELD_NAMES;
let Self { value, range } = self;
[
BundleField {
name: value_name.intern(),
flipped: false,
ty: value.canonical(),
},
BundleField {
name: range_name.intern(),
flipped: false,
ty: range.canonical(),
},
][..]
.intern()
}
}
impl<Start: KnownSize, End: KnownSize> Default for $UIntInRangeType<Start, End> {
fn default() -> Self {
Self::TYPE
}
}
impl<Start: KnownSize, End: KnownSize> StaticType for $UIntInRangeType<Start, End> {
const TYPE: Self = {
let $uint_range_usize_start = Start::VALUE;
let $uint_range_usize_end = End::VALUE;
Self {
value: $uint_range_usize,
range: PhantomConst::<$SerdeRange<Start, End>>::TYPE,
}
};
const MASK_TYPE: Self::MaskType = UIntInRangeMaskType::TYPE;
const TYPE_PROPERTIES: TypeProperties = BundleTypePropertiesBuilder::new()
.field(false, Self::TYPE.value.type_properties_dyn())
.field(
false,
PhantomConst::<$SerdeRange<Start, End>>::TYPE_PROPERTIES,
)
.finish();
const MASK_TYPE_PROPERTIES: TypeProperties = UIntInRangeMaskType::TYPE_PROPERTIES;
}
impl<Start: Size, End: Size> ToSimValueWithType<$UIntInRangeType<Start, End>> for usize {
fn to_sim_value_with_type(
&self,
ty: $UIntInRangeType<Start, End>,
) -> SimValue<$UIntInRangeType<Start, End>> {
SimValue::from_value(ty, *self)
}
}
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Default)]
pub struct $UIntInRangeTypeWithoutGenerics;
#[allow(non_upper_case_globals)]
pub const $UIntInRangeType: $UIntInRangeTypeWithoutGenerics =
$UIntInRangeTypeWithoutGenerics;
impl<StartSize: SizeType> Index<StartSize> for $UIntInRangeTypeWithoutGenerics {
type Output = $UIntInRangeTypeWithStart<StartSize::Size>;
fn index(&self, start: StartSize) -> &Self::Output {
Interned::into_inner($UIntInRangeTypeWithStart(start).intern_sized())
}
}
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub struct $UIntInRangeTypeWithStart<Start: Size>(Start::SizeType);
impl<Start: Size, EndSize: SizeType<Size = End>, End: Size<SizeType = EndSize>>
Index<EndSize> for $UIntInRangeTypeWithStart<Start>
{
type Output = $UIntInRangeType<Start, End>;
fn index(&self, end: EndSize) -> &Self::Output {
Interned::into_inner($UIntInRangeType::new(self.0, end).intern_sized())
}
}
impl<Start: Size, End: Size> ExprCastTo<UInt> for $UIntInRangeType<Start, End> {
fn cast_to(src: Expr<Self>, to_type: UInt) -> Expr<UInt> {
src.cast_to_bits().cast_to(to_type)
}
}
impl<Start: Size, End: Size> ExprCastTo<$UIntInRangeType<Start, End>> for UInt {
fn cast_to(
src: Expr<Self>,
to_type: $UIntInRangeType<Start, End>,
) -> Expr<$UIntInRangeType<Start, End>> {
src.cast_bits_to(to_type)
}
}
impl<LhsStart: Size, LhsEnd: Size, RhsStart: Size, RhsEnd: Size>
ExprPartialEq<$UIntInRangeType<RhsStart, RhsEnd>>
for $UIntInRangeType<LhsStart, LhsEnd>
{
fn cmp_eq(
lhs: Expr<Self>,
rhs: Expr<$UIntInRangeType<RhsStart, RhsEnd>>,
) -> Expr<Bool> {
lhs.cast_to_bits().cmp_eq(rhs.cast_to_bits())
}
fn cmp_ne(
lhs: Expr<Self>,
rhs: Expr<$UIntInRangeType<RhsStart, RhsEnd>>,
) -> Expr<Bool> {
lhs.cast_to_bits().cmp_ne(rhs.cast_to_bits())
}
}
impl<LhsStart: Size, LhsEnd: Size, RhsStart: Size, RhsEnd: Size>
ExprPartialOrd<$UIntInRangeType<RhsStart, RhsEnd>>
for $UIntInRangeType<LhsStart, LhsEnd>
{
fn cmp_lt(
lhs: Expr<Self>,
rhs: Expr<$UIntInRangeType<RhsStart, RhsEnd>>,
) -> Expr<Bool> {
lhs.cast_to_bits().cmp_lt(rhs.cast_to_bits())
}
fn cmp_le(
lhs: Expr<Self>,
rhs: Expr<$UIntInRangeType<RhsStart, RhsEnd>>,
) -> Expr<Bool> {
lhs.cast_to_bits().cmp_le(rhs.cast_to_bits())
}
fn cmp_gt(
lhs: Expr<Self>,
rhs: Expr<$UIntInRangeType<RhsStart, RhsEnd>>,
) -> Expr<Bool> {
lhs.cast_to_bits().cmp_gt(rhs.cast_to_bits())
}
fn cmp_ge(
lhs: Expr<Self>,
rhs: Expr<$UIntInRangeType<RhsStart, RhsEnd>>,
) -> Expr<Bool> {
lhs.cast_to_bits().cmp_ge(rhs.cast_to_bits())
}
}
impl<LhsStart: Size, LhsEnd: Size, RhsStart: Size, RhsEnd: Size>
SimValuePartialEq<$UIntInRangeType<RhsStart, RhsEnd>>
for $UIntInRangeType<LhsStart, LhsEnd>
{
fn sim_value_eq(
this: &SimValue<Self>,
other: &SimValue<$UIntInRangeType<RhsStart, RhsEnd>>,
) -> bool {
**this == **other
}
}
impl<Start: Size, End: Size, Width: Size> ExprPartialEq<UIntType<Width>>
for $UIntInRangeType<Start, End>
{
fn cmp_eq(lhs: Expr<Self>, rhs: Expr<UIntType<Width>>) -> Expr<Bool> {
lhs.cast_to_bits().cmp_eq(rhs)
}
fn cmp_ne(lhs: Expr<Self>, rhs: Expr<UIntType<Width>>) -> Expr<Bool> {
lhs.cast_to_bits().cmp_ne(rhs)
}
}
impl<Start: Size, End: Size, Width: Size> ExprPartialEq<$UIntInRangeType<Start, End>>
for UIntType<Width>
{
fn cmp_eq(lhs: Expr<Self>, rhs: Expr<$UIntInRangeType<Start, End>>) -> Expr<Bool> {
lhs.cmp_eq(rhs.cast_to_bits())
}
fn cmp_ne(lhs: Expr<Self>, rhs: Expr<$UIntInRangeType<Start, End>>) -> Expr<Bool> {
lhs.cmp_ne(rhs.cast_to_bits())
}
}
impl<Start: Size, End: Size, Width: Size> ExprPartialOrd<UIntType<Width>>
for $UIntInRangeType<Start, End>
{
fn cmp_lt(lhs: Expr<Self>, rhs: Expr<UIntType<Width>>) -> Expr<Bool> {
lhs.cast_to_bits().cmp_lt(rhs)
}
fn cmp_le(lhs: Expr<Self>, rhs: Expr<UIntType<Width>>) -> Expr<Bool> {
lhs.cast_to_bits().cmp_le(rhs)
}
fn cmp_gt(lhs: Expr<Self>, rhs: Expr<UIntType<Width>>) -> Expr<Bool> {
lhs.cast_to_bits().cmp_gt(rhs)
}
fn cmp_ge(lhs: Expr<Self>, rhs: Expr<UIntType<Width>>) -> Expr<Bool> {
lhs.cast_to_bits().cmp_ge(rhs)
}
}
impl<Start: Size, End: Size, Width: Size> ExprPartialOrd<$UIntInRangeType<Start, End>>
for UIntType<Width>
{
fn cmp_lt(lhs: Expr<Self>, rhs: Expr<$UIntInRangeType<Start, End>>) -> Expr<Bool> {
lhs.cmp_lt(rhs.cast_to_bits())
}
fn cmp_le(lhs: Expr<Self>, rhs: Expr<$UIntInRangeType<Start, End>>) -> Expr<Bool> {
lhs.cmp_le(rhs.cast_to_bits())
}
fn cmp_gt(lhs: Expr<Self>, rhs: Expr<$UIntInRangeType<Start, End>>) -> Expr<Bool> {
lhs.cmp_gt(rhs.cast_to_bits())
}
fn cmp_ge(lhs: Expr<Self>, rhs: Expr<$UIntInRangeType<Start, End>>) -> Expr<Bool> {
lhs.cmp_ge(rhs.cast_to_bits())
}
}
};
}
define_uint_in_range_type! {
UIntInRange,
UIntInRangeType,
UIntInRangeTypeWithoutGenerics,
UIntInRangeTypeWithStart,
SerdeRange,
"..",
|start, end| UInt::range_usize(start..end),
}
define_uint_in_range_type! {
UIntInRangeInclusive,
UIntInRangeInclusiveType,
UIntInRangeInclusiveTypeWithoutGenerics,
UIntInRangeInclusiveTypeWithStart,
SerdeRangeInclusive,
"..=",
|start, end| UInt::range_inclusive_usize(start..=end),
}
impl SerdeRange<DynSize, DynSize> {
fn is_empty(self) -> bool {
self.start >= self.end
}
}
impl SerdeRangeInclusive<DynSize, DynSize> {
fn is_empty(self) -> bool {
self.start > self.end
}
}

View file

@ -1,9 +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
#![allow(clippy::type_complexity)] #![allow(clippy::type_complexity)]
use crate::{intern::type_map::TypeIdMap, util::DefaultBuildHasher}; use crate::intern::type_map::TypeIdMap;
use bitvec::{ptr::BitPtr, slice::BitSlice, vec::BitVec}; use bitvec::{ptr::BitPtr, slice::BitSlice, vec::BitVec};
use hashbrown::HashTable; use hashbrown::{hash_map::RawEntryMut, HashMap, HashTable};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::{ use std::{
any::{Any, TypeId}, any::{Any, TypeId},
@ -17,7 +17,7 @@ use std::{
sync::{Mutex, RwLock}, sync::{Mutex, RwLock},
}; };
mod type_map; pub mod type_map;
pub trait LazyInternedTrait<T: ?Sized + Send + Sync + 'static>: Send + Sync + Any { pub trait LazyInternedTrait<T: ?Sized + Send + Sync + 'static>: Send + Sync + Any {
fn get(&self) -> Interned<T>; fn get(&self) -> Interned<T>;
@ -316,13 +316,8 @@ pub trait Intern: Any + Send + Sync {
} }
} }
struct InternerState<T: ?Sized + 'static + Send + Sync> {
table: HashTable<&'static T>,
hasher: DefaultBuildHasher,
}
pub struct Interner<T: ?Sized + 'static + Send + Sync> { pub struct Interner<T: ?Sized + 'static + Send + Sync> {
state: Mutex<InternerState<T>>, map: Mutex<HashMap<&'static T, ()>>,
} }
impl<T: ?Sized + 'static + Send + Sync> Interner<T> { impl<T: ?Sized + 'static + Send + Sync> Interner<T> {
@ -335,10 +330,7 @@ impl<T: ?Sized + 'static + Send + Sync> Interner<T> {
impl<T: ?Sized + 'static + Send + Sync> Default for Interner<T> { impl<T: ?Sized + 'static + Send + Sync> Default for Interner<T> {
fn default() -> Self { fn default() -> Self {
Self { Self {
state: Mutex::new(InternerState { map: Default::default(),
table: HashTable::new(),
hasher: Default::default(),
}),
} }
} }
} }
@ -349,16 +341,17 @@ impl<T: ?Sized + 'static + Send + Sync + Hash + Eq + ToOwned> Interner<T> {
alloc: F, alloc: F,
value: Cow<'_, T>, value: Cow<'_, T>,
) -> Interned<T> { ) -> Interned<T> {
let mut state = self.state.lock().unwrap(); let mut map = self.map.lock().unwrap();
let InternerState { table, hasher } = &mut *state; let hasher = map.hasher().clone();
let inner = *table let hash = hasher.hash_one(&*value);
.entry( let inner = match map.raw_entry_mut().from_hash(hash, |k| **k == *value) {
hasher.hash_one(&*value), RawEntryMut::Occupied(entry) => *entry.key(),
|k| **k == *value, RawEntryMut::Vacant(entry) => {
|k| hasher.hash_one(&**k), *entry
) .insert_with_hasher(hash, alloc(value), (), |k| hasher.hash_one(&**k))
.or_insert_with(|| alloc(value)) .0
.get(); }
};
Interned { inner } Interned { inner }
} }
} }
@ -749,7 +742,7 @@ pub trait MemoizeGeneric: 'static + Send + Sync + Hash + Eq + Copy {
fn get_cow(self, input: Self::InputCow<'_>) -> Self::Output { fn get_cow(self, input: Self::InputCow<'_>) -> Self::Output {
static TYPE_ID_MAP: TypeIdMap = TypeIdMap::new(); static TYPE_ID_MAP: TypeIdMap = TypeIdMap::new();
let map: &RwLock<( let map: &RwLock<(
DefaultBuildHasher, hashbrown::hash_map::DefaultHashBuilder,
HashTable<(Self, Self::InputOwned, Self::Output)>, HashTable<(Self, Self::InputOwned, Self::Output)>,
)> = TYPE_ID_MAP.get_or_insert_default(); )> = TYPE_ID_MAP.get_or_insert_default();
fn hash_eq_key<'a, 'b, T: MemoizeGeneric>( fn hash_eq_key<'a, 'b, T: MemoizeGeneric>(

View file

@ -1,8 +1,10 @@
// 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 hashbrown::HashMap;
use std::{ use std::{
any::{Any, TypeId}, any::{Any, TypeId},
hash::{BuildHasher, Hasher}, hash::{BuildHasher, Hasher},
ptr::NonNull,
sync::RwLock, sync::RwLock,
}; };
@ -73,36 +75,59 @@ impl BuildHasher for TypeIdBuildHasher {
} }
} }
pub(crate) struct TypeIdMap( struct Value(NonNull<dyn Any + Send + Sync>);
RwLock<hashbrown::HashMap<TypeId, &'static (dyn Any + Send + Sync), TypeIdBuildHasher>>,
); impl Value {
unsafe fn get_transmute_lifetime<'b>(&self) -> &'b (dyn Any + Send + Sync) {
unsafe { &*self.0.as_ptr() }
}
fn new(v: Box<dyn Any + Send + Sync>) -> Self {
unsafe { Self(NonNull::new_unchecked(Box::into_raw(v))) }
}
}
unsafe impl Send for Value {}
unsafe impl Sync for Value {}
impl Drop for Value {
fn drop(&mut self) {
unsafe { std::ptr::drop_in_place(self.0.as_ptr()) }
}
}
pub struct TypeIdMap(RwLock<HashMap<TypeId, Value, TypeIdBuildHasher>>);
impl TypeIdMap { impl TypeIdMap {
pub(crate) const fn new() -> Self { pub const fn new() -> Self {
Self(RwLock::new(hashbrown::HashMap::with_hasher( Self(RwLock::new(HashMap::with_hasher(TypeIdBuildHasher)))
TypeIdBuildHasher,
)))
} }
#[cold] #[cold]
fn insert_slow( unsafe fn insert_slow(
&self, &self,
type_id: TypeId, type_id: TypeId,
make: fn() -> Box<dyn Any + Sync + Send>, make: fn() -> Box<dyn Any + Sync + Send>,
) -> &'static (dyn Any + Sync + Send) { ) -> &(dyn Any + Sync + Send) {
let value = Box::leak(make()); let value = Value::new(make());
let mut write_guard = self.0.write().unwrap(); let mut write_guard = self.0.write().unwrap();
*write_guard.entry(type_id).or_insert(value) unsafe {
write_guard
.entry(type_id)
.or_insert(value)
.get_transmute_lifetime()
} }
pub(crate) fn get_or_insert_default<T: Sized + Any + Send + Sync + Default>(&self) -> &T { }
pub fn get_or_insert_default<T: Sized + Any + Send + Sync + Default>(&self) -> &T {
let type_id = TypeId::of::<T>(); let type_id = TypeId::of::<T>();
let read_guard = self.0.read().unwrap(); let read_guard = self.0.read().unwrap();
let retval = read_guard.get(&type_id).map(|v| *v); let retval = read_guard
.get(&type_id)
.map(|v| unsafe { Value::get_transmute_lifetime(v) });
drop(read_guard); drop(read_guard);
let retval = match retval { let retval = match retval {
Some(retval) => retval, Some(retval) => retval,
None => self.insert_slow(type_id, move || Box::new(T::default())), None => unsafe { self.insert_slow(type_id, move || Box::new(T::default())) },
}; };
retval.downcast_ref().expect("known to have correct TypeId") unsafe { &*(retval as *const dyn Any as *const T) }
} }
} }

View file

@ -76,8 +76,6 @@ pub use fayalite_proc_macros::hdl_module;
#[doc(inline)] #[doc(inline)]
pub use fayalite_proc_macros::hdl; pub use fayalite_proc_macros::hdl;
pub use bitvec;
/// struct used as a placeholder when applying defaults /// struct used as a placeholder when applying defaults
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub struct __; pub struct __;
@ -98,7 +96,6 @@ pub mod int;
pub mod intern; pub mod intern;
pub mod memory; pub mod memory;
pub mod module; pub mod module;
pub mod phantom_const;
pub mod prelude; pub mod prelude;
pub mod reg; pub mod reg;
pub mod reset; pub mod reset;

View file

@ -7,7 +7,7 @@ use crate::{
array::{Array, ArrayType}, array::{Array, ArrayType},
bundle::{Bundle, BundleType}, bundle::{Bundle, BundleType},
clock::Clock, clock::Clock,
expr::{Expr, Flow, ToExpr, ToLiteralBits, ops::BundleLiteral, repeat}, expr::{ops::BundleLiteral, repeat, Expr, Flow, ToExpr, ToLiteralBits},
hdl, hdl,
int::{Bool, DynSize, Size, UInt, UIntType}, int::{Bool, DynSize, Size, UInt, UIntType},
intern::{Intern, Interned}, intern::{Intern, Interned},
@ -470,7 +470,7 @@ pub enum ReadUnderWrite {
Undefined, Undefined,
} }
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] #[derive(Copy, Clone, PartialEq, Eq, Hash)]
struct MemImpl<Element: Type, Len: Size, P> { struct MemImpl<Element: Type, Len: Size, P> {
scoped_name: ScopedNameId, scoped_name: ScopedNameId,
source_location: SourceLocation, source_location: SourceLocation,
@ -1066,8 +1066,7 @@ pub fn splat_mask<T: Type>(ty: T, value: Expr<Bool>) -> Expr<AsMask<T>> {
| CanonicalType::SyncReset(_) | CanonicalType::SyncReset(_)
| CanonicalType::Reset(_) | CanonicalType::Reset(_)
| CanonicalType::Clock(_) | CanonicalType::Clock(_)
| CanonicalType::Enum(_) | CanonicalType::Enum(_) => Expr::from_canonical(Expr::canonical(value)),
| CanonicalType::DynSimOnly(_) => Expr::from_canonical(Expr::canonical(value)),
CanonicalType::Array(array) => Expr::from_canonical(Expr::canonical(repeat( CanonicalType::Array(array) => Expr::from_canonical(Expr::canonical(repeat(
splat_mask(array.element(), value), splat_mask(array.element(), value),
array.len(), array.len(),
@ -1083,7 +1082,6 @@ pub fn splat_mask<T: Type>(ty: T, value: Expr<Bool>) -> Expr<AsMask<T>> {
) )
.to_expr(), .to_expr(),
)), )),
CanonicalType::PhantomConst(_) => Expr::from_canonical(Expr::canonical(().to_expr())),
} }
} }

View file

@ -8,12 +8,12 @@ use crate::{
clock::{Clock, ClockDomain}, clock::{Clock, ClockDomain},
enum_::{Enum, EnumMatchVariantsIter, EnumType}, enum_::{Enum, EnumMatchVariantsIter, EnumType},
expr::{ expr::{
Expr, Flow, ToExpr,
ops::VariantAccess, ops::VariantAccess,
target::{ target::{
GetTarget, Target, TargetBase, TargetPathArrayElement, TargetPathBundleField, GetTarget, Target, TargetBase, TargetPathArrayElement, TargetPathBundleField,
TargetPathElement, TargetPathElement,
}, },
Expr, Flow, ToExpr,
}, },
formal::FormalKind, formal::FormalKind,
int::{Bool, DynSize, Size}, int::{Bool, DynSize, Size},
@ -21,20 +21,18 @@ use crate::{
memory::{Mem, MemBuilder, MemBuilderTarget, PortName}, memory::{Mem, MemBuilder, MemBuilderTarget, PortName},
reg::Reg, reg::Reg,
reset::{AsyncReset, Reset, ResetType, ResetTypeDispatch, SyncReset}, reset::{AsyncReset, Reset, ResetType, ResetTypeDispatch, SyncReset},
sim::{ExternModuleSimGenerator, ExternModuleSimulation},
source_location::SourceLocation, source_location::SourceLocation,
ty::{CanonicalType, Type}, ty::{CanonicalType, Type},
util::{HashMap, HashSet, ScopedRef}, util::ScopedRef,
wire::{IncompleteWire, Wire}, wire::{IncompleteWire, Wire},
}; };
use hashbrown::hash_map::Entry; use hashbrown::{hash_map::Entry, HashMap, HashSet};
use num_bigint::BigInt; use num_bigint::BigInt;
use std::{ use std::{
cell::RefCell, cell::RefCell,
collections::{BTreeMap, VecDeque}, collections::VecDeque,
convert::Infallible, convert::Infallible,
fmt, fmt,
future::IntoFuture,
hash::{Hash, Hasher}, hash::{Hash, Hasher},
iter::FusedIterator, iter::FusedIterator,
marker::PhantomData, marker::PhantomData,
@ -1083,7 +1081,6 @@ pub struct ExternModuleBody<
> { > {
pub verilog_name: Interned<str>, pub verilog_name: Interned<str>,
pub parameters: P, pub parameters: P,
pub simulation: Option<ExternModuleSimulation>,
} }
impl From<ExternModuleBody<Vec<ExternModuleParameter>>> for ExternModuleBody { impl From<ExternModuleBody<Vec<ExternModuleParameter>>> for ExternModuleBody {
@ -1091,13 +1088,11 @@ impl From<ExternModuleBody<Vec<ExternModuleParameter>>> for ExternModuleBody {
let ExternModuleBody { let ExternModuleBody {
verilog_name, verilog_name,
parameters, parameters,
simulation,
} = value; } = value;
let parameters = Intern::intern_owned(parameters); let parameters = Intern::intern_owned(parameters);
Self { Self {
verilog_name, verilog_name,
parameters, parameters,
simulation,
} }
} }
} }
@ -1288,12 +1283,10 @@ impl<T: BundleType> fmt::Debug for DebugModuleBody<T> {
ModuleBody::Extern(ExternModuleBody { ModuleBody::Extern(ExternModuleBody {
verilog_name, verilog_name,
parameters, parameters,
simulation,
}) => { }) => {
debug_struct debug_struct
.field("verilog_name", verilog_name) .field("verilog_name", verilog_name)
.field("parameters", parameters) .field("parameters", parameters);
.field("simulation", simulation);
} }
} }
debug_struct.finish_non_exhaustive() debug_struct.finish_non_exhaustive()
@ -1459,9 +1452,7 @@ impl TargetState {
}) })
.reduce(TargetWritten::conditional_merge_written) .reduce(TargetWritten::conditional_merge_written)
else { else {
unreachable!( unreachable!("merge_conditional_sub_blocks_into_block must be called with at least one sub-block");
"merge_conditional_sub_blocks_into_block must be called with at least one sub-block"
);
}; };
let mut written_in_blocks = written_in_blocks.borrow_mut(); let mut written_in_blocks = written_in_blocks.borrow_mut();
if target_block >= written_in_blocks.len() { if target_block >= written_in_blocks.len() {
@ -1499,9 +1490,6 @@ impl TargetState {
}) })
.collect(), .collect(),
}, },
CanonicalType::PhantomConst(_) => TargetStateInner::Decomposed {
subtargets: HashMap::default(),
},
CanonicalType::Array(ty) => TargetStateInner::Decomposed { CanonicalType::Array(ty) => TargetStateInner::Decomposed {
subtargets: (0..ty.len()) subtargets: (0..ty.len())
.map(|index| { .map(|index| {
@ -1524,8 +1512,7 @@ impl TargetState {
| CanonicalType::Clock(_) | CanonicalType::Clock(_)
| CanonicalType::AsyncReset(_) | CanonicalType::AsyncReset(_)
| CanonicalType::SyncReset(_) | CanonicalType::SyncReset(_)
| CanonicalType::Reset(_) | CanonicalType::Reset(_) => TargetStateInner::Single {
| CanonicalType::DynSimOnly(_) => TargetStateInner::Single {
declared_in_block, declared_in_block,
written_in_blocks: RefCell::default(), written_in_blocks: RefCell::default(),
}, },
@ -1771,7 +1758,6 @@ impl AssertValidityState {
ModuleBody::Extern(ExternModuleBody { ModuleBody::Extern(ExternModuleBody {
verilog_name: _, verilog_name: _,
parameters: _, parameters: _,
simulation: _,
}) => {} }) => {}
ModuleBody::Normal(NormalModuleBody { body }) => { ModuleBody::Normal(NormalModuleBody { body }) => {
let body = self.make_block_index(body); let body = self.make_block_index(body);
@ -1793,49 +1779,12 @@ impl<T: BundleType> Module<T> {
pub fn new_unchecked( pub fn new_unchecked(
name_id: NameId, name_id: NameId,
source_location: SourceLocation, source_location: SourceLocation,
mut body: ModuleBody, body: ModuleBody,
module_io: impl IntoIterator<Item = AnnotatedModuleIO>, module_io: impl IntoIterator<Item = AnnotatedModuleIO>,
module_annotations: impl IntoAnnotations, module_annotations: impl IntoAnnotations,
) -> Module<T> { ) -> Module<T> {
let module_io: Interned<[_]> = module_io.into_iter().collect(); let module_io: Interned<[_]> = module_io.into_iter().collect();
let module_annotations = module_annotations.into_annotations().into_iter().collect(); let module_annotations = module_annotations.into_annotations().into_iter().collect();
match &mut body {
ModuleBody::Normal(_) => {}
ModuleBody::Extern(ExternModuleBody {
simulation: Some(simulation),
..
}) => {
if module_io.iter().any(|io| {
!simulation
.sim_io_to_generator_map
.contains_key(&io.module_io.intern())
}) {
let mut sim_io_to_generator_map =
BTreeMap::clone(&simulation.sim_io_to_generator_map);
for io in module_io.iter() {
let io = io.module_io.intern();
sim_io_to_generator_map.entry(io).or_insert(io);
}
simulation.sim_io_to_generator_map = sim_io_to_generator_map.intern_sized();
}
if simulation.sim_io_to_generator_map.len() > module_io.len() {
// if sim_io_to_generator_map is bigger, then there must be a key that's not in module_io
let module_io_set = HashSet::from_iter(module_io.iter().map(|v| v.module_io));
for (sim_io, generator_io) in simulation.sim_io_to_generator_map.iter() {
if !module_io_set.contains(&**sim_io) {
panic!(
"extern module has invalid `sim_io_to_generator_map`: key is not in containing module's `module_io`:\n\
key={sim_io:?}\nvalue={generator_io:?}\nmodule location: {source_location}"
);
}
}
unreachable!();
}
}
ModuleBody::Extern(ExternModuleBody {
simulation: None, ..
}) => {}
}
let retval = Module { let retval = Module {
name: name_id, name: name_id,
source_location, source_location,
@ -1904,7 +1853,7 @@ impl<T: BundleType> Module<T> {
AssertValidityState { AssertValidityState {
module: self.canonical(), module: self.canonical(),
blocks: vec![], blocks: vec![],
target_states: HashMap::with_capacity_and_hasher(64, Default::default()), target_states: HashMap::with_capacity(64),
} }
.assert_validity(); .assert_validity();
} }
@ -2156,7 +2105,6 @@ impl ModuleBuilder {
ModuleKind::Extern => ModuleBody::Extern(ExternModuleBody { ModuleKind::Extern => ModuleBody::Extern(ExternModuleBody {
verilog_name: name.0, verilog_name: name.0,
parameters: vec![], parameters: vec![],
simulation: None,
}), }),
ModuleKind::Normal => ModuleBody::Normal(NormalModuleBody { ModuleKind::Normal => ModuleBody::Normal(NormalModuleBody {
body: BuilderModuleBody { body: BuilderModuleBody {
@ -2165,8 +2113,8 @@ impl ModuleBuilder {
incomplete_declarations: vec![], incomplete_declarations: vec![],
stmts: vec![], stmts: vec![],
}], }],
annotations_map: HashMap::default(), annotations_map: HashMap::new(),
memory_map: HashMap::default(), memory_map: HashMap::new(),
}, },
}), }),
}; };
@ -2176,7 +2124,7 @@ impl ModuleBuilder {
impl_: RefCell::new(ModuleBuilderImpl { impl_: RefCell::new(ModuleBuilderImpl {
body, body,
io: vec![], io: vec![],
io_indexes: HashMap::default(), io_indexes: HashMap::new(),
module_annotations: vec![], module_annotations: vec![],
}), }),
}; };
@ -2223,7 +2171,6 @@ impl ModuleBuilder {
.builder_extern_body() .builder_extern_body()
.verilog_name = name.intern(); .verilog_name = name.intern();
} }
#[track_caller]
pub fn parameter(&self, name: impl AsRef<str>, value: ExternModuleParameterValue) { pub fn parameter(&self, name: impl AsRef<str>, value: ExternModuleParameterValue) {
let name = name.as_ref(); let name = name.as_ref();
self.impl_ self.impl_
@ -2236,7 +2183,6 @@ impl ModuleBuilder {
value, value,
}); });
} }
#[track_caller]
pub fn parameter_int(&self, name: impl AsRef<str>, value: impl Into<BigInt>) { pub fn parameter_int(&self, name: impl AsRef<str>, value: impl Into<BigInt>) {
let name = name.as_ref(); let name = name.as_ref();
let value = value.into(); let value = value.into();
@ -2250,7 +2196,6 @@ impl ModuleBuilder {
value: ExternModuleParameterValue::Integer(value), value: ExternModuleParameterValue::Integer(value),
}); });
} }
#[track_caller]
pub fn parameter_str(&self, name: impl AsRef<str>, value: impl AsRef<str>) { pub fn parameter_str(&self, name: impl AsRef<str>, value: impl AsRef<str>) {
let name = name.as_ref(); let name = name.as_ref();
let value = value.as_ref(); let value = value.as_ref();
@ -2264,7 +2209,6 @@ impl ModuleBuilder {
value: ExternModuleParameterValue::String(value.intern()), value: ExternModuleParameterValue::String(value.intern()),
}); });
} }
#[track_caller]
pub fn parameter_raw_verilog(&self, name: impl AsRef<str>, raw_verilog: impl AsRef<str>) { pub fn parameter_raw_verilog(&self, name: impl AsRef<str>, raw_verilog: impl AsRef<str>) {
let name = name.as_ref(); let name = name.as_ref();
let raw_verilog = raw_verilog.as_ref(); let raw_verilog = raw_verilog.as_ref();
@ -2278,26 +2222,6 @@ impl ModuleBuilder {
value: ExternModuleParameterValue::RawVerilog(raw_verilog.intern()), value: ExternModuleParameterValue::RawVerilog(raw_verilog.intern()),
}); });
} }
#[track_caller]
pub fn extern_module_simulation<G: ExternModuleSimGenerator>(&self, generator: G) {
let mut impl_ = self.impl_.borrow_mut();
let simulation = &mut impl_.body.builder_extern_body().simulation;
if simulation.is_some() {
panic!("already added an extern module simulation");
}
*simulation = Some(ExternModuleSimulation::new(generator));
}
#[track_caller]
pub fn extern_module_simulation_fn<
Args: fmt::Debug + Clone + Hash + Eq + Send + Sync + 'static,
Fut: IntoFuture<Output = ()> + 'static,
>(
&self,
args: Args,
f: fn(Args, crate::sim::ExternModuleSimulationState) -> Fut,
) {
self.extern_module_simulation(crate::sim::SimGeneratorFn { args, f });
}
} }
#[track_caller] #[track_caller]
@ -2330,12 +2254,14 @@ pub fn annotate<T: Type>(target: Expr<T>, annotations: impl IntoAnnotations) {
} }
TargetBase::MemPort(v) => { TargetBase::MemPort(v) => {
ModuleBuilder::with(|m| { ModuleBuilder::with(|m| {
RefCell::borrow_mut(unwrap!( RefCell::borrow_mut(unwrap!(unwrap!(m
unwrap!(m.impl_.borrow_mut().body.builder_normal_body_opt()) .impl_
.borrow_mut()
.body
.builder_normal_body_opt())
.body .body
.memory_map .memory_map
.get_mut(&v.mem_name()) .get_mut(&v.mem_name())))
))
.port_annotations .port_annotations
.extend(annotations) .extend(annotations)
}); });

View file

@ -6,32 +6,29 @@ use crate::{
bundle::{BundleField, BundleType}, bundle::{BundleField, BundleType},
enum_::{EnumType, EnumVariant}, enum_::{EnumType, EnumVariant},
expr::{ expr::{
ExprEnum,
ops::{self, ArrayLiteral}, ops::{self, ArrayLiteral},
target::{ target::{
Target, TargetBase, TargetChild, TargetPathArrayElement, TargetPathBundleField, Target, TargetBase, TargetChild, TargetPathArrayElement, TargetPathBundleField,
TargetPathDynArrayElement, TargetPathElement, TargetPathDynArrayElement, TargetPathElement,
}, },
ExprEnum,
}, },
formal::FormalKind, formal::FormalKind,
int::{SIntValue, UIntValue}, int::{SIntValue, UIntValue},
intern::{Intern, Interned, Memoize}, intern::{Intern, Interned, Memoize},
memory::{DynPortType, MemPort}, memory::{DynPortType, MemPort},
module::{ module::{
AnnotatedModuleIO, Block, ExprInInstantiatedModule, ExternModuleBody, AnnotatedModuleIO, Block, ExprInInstantiatedModule, ExternModuleBody, InstantiatedModule,
ExternModuleParameter, InstantiatedModule, ModuleBody, ModuleIO, NameId, NormalModuleBody, ModuleBody, ModuleIO, NameId, NormalModuleBody, Stmt, StmtConnect, StmtDeclaration,
Stmt, StmtConnect, StmtDeclaration, StmtFormal, StmtIf, StmtInstance, StmtMatch, StmtReg, StmtFormal, StmtIf, StmtInstance, StmtMatch, StmtReg, StmtWire,
StmtWire,
}, },
prelude::*, prelude::*,
reset::{ResetType, ResetTypeDispatch}, reset::{ResetType, ResetTypeDispatch},
sim::ExternModuleSimulation,
util::{HashMap, HashSet},
}; };
use hashbrown::hash_map::Entry; use hashbrown::{hash_map::Entry, HashMap, HashSet};
use num_bigint::BigInt; use num_bigint::BigInt;
use petgraph::unionfind::UnionFind; use petgraph::unionfind::UnionFind;
use std::{collections::BTreeMap, fmt, marker::PhantomData}; use std::{fmt, marker::PhantomData};
#[derive(Debug)] #[derive(Debug)]
pub enum DeduceResetsError { pub enum DeduceResetsError {
@ -43,16 +40,10 @@ impl fmt::Display for DeduceResetsError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self { match self {
DeduceResetsError::ResetIsNotDrivenByAsyncOrSync { source_location } => { DeduceResetsError::ResetIsNotDrivenByAsyncOrSync { source_location } => {
write!( write!(f, "deduce_reset failed: Reset signal is not driven by any AsyncReset or SyncReset signals: {source_location}")
f,
"deduce_reset failed: Reset signal is not driven by any AsyncReset or SyncReset signals: {source_location}"
)
} }
DeduceResetsError::ResetIsDrivenByBothAsyncAndSync { source_location } => { DeduceResetsError::ResetIsDrivenByBothAsyncAndSync { source_location } => {
write!( write!(f, "deduce_reset failed: Reset signal is driven by both AsyncReset and SyncReset signals: {source_location}")
f,
"deduce_reset failed: Reset signal is driven by both AsyncReset and SyncReset signals: {source_location}"
)
} }
} }
} }
@ -164,8 +155,6 @@ impl ResetsLayout {
CanonicalType::SyncReset(_) => ResetsLayout::SyncReset, CanonicalType::SyncReset(_) => ResetsLayout::SyncReset,
CanonicalType::Reset(_) => ResetsLayout::Reset, CanonicalType::Reset(_) => ResetsLayout::Reset,
CanonicalType::Clock(_) => ResetsLayout::NoResets, CanonicalType::Clock(_) => ResetsLayout::NoResets,
CanonicalType::PhantomConst(_) => ResetsLayout::NoResets,
CanonicalType::DynSimOnly(_) => ResetsLayout::NoResets,
} }
} }
} }
@ -418,9 +407,7 @@ impl Resets {
| CanonicalType::Bool(_) | CanonicalType::Bool(_)
| CanonicalType::AsyncReset(_) | CanonicalType::AsyncReset(_)
| CanonicalType::SyncReset(_) | CanonicalType::SyncReset(_)
| CanonicalType::Clock(_) | CanonicalType::Clock(_) => Ok(self.ty),
| CanonicalType::PhantomConst(_)
| CanonicalType::DynSimOnly(_) => Ok(self.ty),
CanonicalType::Array(ty) => Ok(CanonicalType::Array(Array::new_dyn( CanonicalType::Array(ty) => Ok(CanonicalType::Array(Array::new_dyn(
self.array_elements().substituted_type( self.array_elements().substituted_type(
reset_graph, reset_graph,
@ -1011,9 +998,7 @@ fn cast_bit_op<P: Pass, T: Type, A: Type>(
CanonicalType::Array(_) CanonicalType::Array(_)
| CanonicalType::Enum(_) | CanonicalType::Enum(_)
| CanonicalType::Bundle(_) | CanonicalType::Bundle(_)
| CanonicalType::Reset(_) | CanonicalType::Reset(_) => unreachable!(),
| CanonicalType::PhantomConst(_)
| CanonicalType::DynSimOnly(_) => unreachable!(),
$(CanonicalType::$Variant(ty) => Expr::expr_enum($arg.cast_to(ty)),)* $(CanonicalType::$Variant(ty) => Expr::expr_enum($arg.cast_to(ty)),)*
} }
}; };
@ -1025,8 +1010,6 @@ fn cast_bit_op<P: Pass, T: Type, A: Type>(
| CanonicalType::Enum(_) | CanonicalType::Enum(_)
| CanonicalType::Bundle(_) | CanonicalType::Bundle(_)
| CanonicalType::Reset(_) => unreachable!(), | CanonicalType::Reset(_) => unreachable!(),
CanonicalType::PhantomConst(_) |
CanonicalType::DynSimOnly(_) => Expr::expr_enum(arg),
$(CanonicalType::$Variant(_) => { $(CanonicalType::$Variant(_) => {
let arg = Expr::<$Variant>::from_canonical(arg); let arg = Expr::<$Variant>::from_canonical(arg);
match_expr_ty!(arg, UInt, SInt, Bool, AsyncReset, SyncReset, Clock) match_expr_ty!(arg, UInt, SInt, Bool, AsyncReset, SyncReset, Clock)
@ -1057,7 +1040,6 @@ impl<P: Pass> RunPass<P> for ExprEnum {
ExprEnum::UIntLiteral(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), ExprEnum::UIntLiteral(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)),
ExprEnum::SIntLiteral(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), ExprEnum::SIntLiteral(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)),
ExprEnum::BoolLiteral(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), ExprEnum::BoolLiteral(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)),
ExprEnum::PhantomConst(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)),
ExprEnum::BundleLiteral(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), ExprEnum::BundleLiteral(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)),
ExprEnum::ArrayLiteral(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), ExprEnum::ArrayLiteral(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)),
ExprEnum::EnumLiteral(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), ExprEnum::EnumLiteral(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)),
@ -1688,9 +1670,7 @@ impl RunPassDispatch for AnyReg {
| CanonicalType::Enum(_) | CanonicalType::Enum(_)
| CanonicalType::Bundle(_) | CanonicalType::Bundle(_)
| CanonicalType::Reset(_) | CanonicalType::Reset(_)
| CanonicalType::Clock(_) | CanonicalType::Clock(_) => unreachable!(),
| CanonicalType::PhantomConst(_)
| CanonicalType::DynSimOnly(_) => unreachable!(),
} }
}) })
} }
@ -1744,33 +1724,6 @@ impl RunPassDispatch for Instance<Bundle> {
} }
} }
impl<P: Pass> RunPass<P> for ExternModuleSimulation {
fn run_pass(
&self,
mut pass_args: PassArgs<'_, P>,
) -> Result<PassOutput<Self, P>, DeduceResetsError> {
let Self {
generator,
sim_io_to_generator_map,
source_location,
} = *self;
let sim_io_to_generator_map = Result::<PassOutput<BTreeMap<_, _>, P>, _>::from_iter(
sim_io_to_generator_map
.iter()
.map(|(sim_io, generator_io)| {
Ok(sim_io
.run_pass(pass_args.as_mut())?
.map(|v| (v, *generator_io)))
}),
)?;
Ok(sim_io_to_generator_map.map(|sim_io_to_generator_map| Self {
generator,
sim_io_to_generator_map: sim_io_to_generator_map.intern_sized(),
source_location,
}))
}
}
macro_rules! impl_run_pass_copy { macro_rules! impl_run_pass_copy {
([$($generics:tt)*] $ty:ty) => { ([$($generics:tt)*] $ty:ty) => {
impl<P: Pass, $($generics)*> RunPass<P> for $ty { impl<P: Pass, $($generics)*> RunPass<P> for $ty {
@ -1798,7 +1751,6 @@ macro_rules! impl_run_pass_clone {
} }
impl_run_pass_clone!([] BigInt); impl_run_pass_clone!([] BigInt);
impl_run_pass_clone!([] ExternModuleParameter);
impl_run_pass_clone!([] SIntValue); impl_run_pass_clone!([] SIntValue);
impl_run_pass_clone!([] std::ops::Range<usize>); impl_run_pass_clone!([] std::ops::Range<usize>);
impl_run_pass_clone!([] UIntValue); impl_run_pass_clone!([] UIntValue);
@ -1808,6 +1760,7 @@ impl_run_pass_copy!([] bool);
impl_run_pass_copy!([] CustomFirrtlAnnotation); impl_run_pass_copy!([] CustomFirrtlAnnotation);
impl_run_pass_copy!([] DocStringAnnotation); impl_run_pass_copy!([] DocStringAnnotation);
impl_run_pass_copy!([] DontTouchAnnotation); impl_run_pass_copy!([] DontTouchAnnotation);
impl_run_pass_copy!([] ExternModuleBody);
impl_run_pass_copy!([] Interned<str>); impl_run_pass_copy!([] Interned<str>);
impl_run_pass_copy!([] NameId); impl_run_pass_copy!([] NameId);
impl_run_pass_copy!([] SInt); impl_run_pass_copy!([] SInt);
@ -1816,7 +1769,6 @@ impl_run_pass_copy!([] SVAttributeAnnotation);
impl_run_pass_copy!([] UInt); impl_run_pass_copy!([] UInt);
impl_run_pass_copy!([] usize); impl_run_pass_copy!([] usize);
impl_run_pass_copy!([] FormalKind); impl_run_pass_copy!([] FormalKind);
impl_run_pass_copy!([] PhantomConst);
macro_rules! impl_run_pass_for_struct { macro_rules! impl_run_pass_for_struct {
( (
@ -2068,14 +2020,6 @@ impl_run_pass_for_struct! {
} }
} }
impl_run_pass_for_struct! {
impl[] RunPass for ExternModuleBody {
verilog_name: _,
parameters: _,
simulation: _,
}
}
impl_run_pass_copy!([] MemPort<DynPortType>); // Mem can't contain any `Reset` types impl_run_pass_copy!([] MemPort<DynPortType>); // Mem can't contain any `Reset` types
impl_run_pass_copy!([] Mem); // Mem can't contain any `Reset` types impl_run_pass_copy!([] Mem); // Mem can't contain any `Reset` types
@ -2147,7 +2091,7 @@ impl<P: Pass> RunPass<P> for StmtDeclaration {
) -> Result<PassOutput<Self, P>, DeduceResetsError> { ) -> Result<PassOutput<Self, P>, DeduceResetsError> {
let (annotations, reg) = match self { let (annotations, reg) = match self {
StmtDeclaration::Wire(v) => { StmtDeclaration::Wire(v) => {
return Ok(v.run_pass(pass_args)?.map(StmtDeclaration::Wire)); return Ok(v.run_pass(pass_args)?.map(StmtDeclaration::Wire))
} }
&StmtDeclaration::Reg(StmtReg { annotations, reg }) => (annotations, AnyReg::from(reg)), &StmtDeclaration::Reg(StmtReg { annotations, reg }) => (annotations, AnyReg::from(reg)),
&StmtDeclaration::RegSync(StmtReg { annotations, reg }) => { &StmtDeclaration::RegSync(StmtReg { annotations, reg }) => {
@ -2157,7 +2101,7 @@ impl<P: Pass> RunPass<P> for StmtDeclaration {
(annotations, AnyReg::from(reg)) (annotations, AnyReg::from(reg))
} }
StmtDeclaration::Instance(v) => { StmtDeclaration::Instance(v) => {
return Ok(v.run_pass(pass_args)?.map(StmtDeclaration::Instance)); return Ok(v.run_pass(pass_args)?.map(StmtDeclaration::Instance))
} }
}; };
let annotations = annotations.run_pass(pass_args.as_mut())?; let annotations = annotations.run_pass(pass_args.as_mut())?;
@ -2300,9 +2244,9 @@ pub fn deduce_resets(
fallback_to_sync_reset: bool, fallback_to_sync_reset: bool,
) -> Result<Interned<Module<Bundle>>, DeduceResetsError> { ) -> Result<Interned<Module<Bundle>>, DeduceResetsError> {
let mut state = State { let mut state = State {
modules_added_to_graph: HashSet::default(), modules_added_to_graph: HashSet::new(),
substituted_modules: HashMap::default(), substituted_modules: HashMap::new(),
expr_resets: HashMap::default(), expr_resets: HashMap::new(),
reset_graph: ResetGraph::default(), reset_graph: ResetGraph::default(),
fallback_to_sync_reset, fallback_to_sync_reset,
}; };

View file

@ -5,23 +5,23 @@ use crate::{
bundle::{Bundle, BundleField, BundleType}, bundle::{Bundle, BundleField, BundleType},
enum_::{Enum, EnumType, EnumVariant}, enum_::{Enum, EnumType, EnumVariant},
expr::{ expr::{
CastBitsTo, CastTo, CastToBits, Expr, ExprEnum, HdlPartialEq, ToExpr,
ops::{self, EnumLiteral}, ops::{self, EnumLiteral},
CastBitsTo, CastTo, CastToBits, Expr, ExprEnum, HdlPartialEq, ToExpr,
}, },
hdl, hdl,
int::UInt, int::UInt,
intern::{Intern, Interned, Memoize}, intern::{Intern, Interned, Memoize},
memory::{DynPortType, Mem, MemPort}, memory::{DynPortType, Mem, MemPort},
module::{ module::{
Block, Id, Module, NameId, ScopedNameId, Stmt, StmtConnect, StmtIf, StmtMatch, StmtWire,
transform::visit::{Fold, Folder}, transform::visit::{Fold, Folder},
Block, Id, Module, NameId, ScopedNameId, Stmt, StmtConnect, StmtIf, StmtMatch, StmtWire,
}, },
source_location::SourceLocation, source_location::SourceLocation,
ty::{CanonicalType, Type}, ty::{CanonicalType, Type},
util::HashMap,
wire::Wire, wire::Wire,
}; };
use core::fmt; use core::fmt;
use hashbrown::HashMap;
#[derive(Debug)] #[derive(Debug)]
pub enum SimplifyEnumsError { pub enum SimplifyEnumsError {
@ -69,9 +69,7 @@ fn contains_any_enum_types(ty: CanonicalType) -> bool {
| CanonicalType::AsyncReset(_) | CanonicalType::AsyncReset(_)
| CanonicalType::SyncReset(_) | CanonicalType::SyncReset(_)
| CanonicalType::Reset(_) | CanonicalType::Reset(_)
| CanonicalType::Clock(_) | CanonicalType::Clock(_) => false,
| CanonicalType::PhantomConst(_)
| CanonicalType::DynSimOnly(_) => false,
} }
} }
} }
@ -514,9 +512,7 @@ impl State {
| CanonicalType::AsyncReset(_) | CanonicalType::AsyncReset(_)
| CanonicalType::SyncReset(_) | CanonicalType::SyncReset(_)
| CanonicalType::Reset(_) | CanonicalType::Reset(_)
| CanonicalType::Clock(_) | CanonicalType::Clock(_) => unreachable!(),
| CanonicalType::PhantomConst(_)
| CanonicalType::DynSimOnly(_) => unreachable!(),
} }
} }
} }
@ -581,9 +577,7 @@ fn connect_port(
| (CanonicalType::Clock(_), _) | (CanonicalType::Clock(_), _)
| (CanonicalType::AsyncReset(_), _) | (CanonicalType::AsyncReset(_), _)
| (CanonicalType::SyncReset(_), _) | (CanonicalType::SyncReset(_), _)
| (CanonicalType::Reset(_), _) | (CanonicalType::Reset(_), _) => unreachable!(
| (CanonicalType::PhantomConst(_), _)
| (CanonicalType::DynSimOnly(_), _) => unreachable!(
"trying to connect memory ports:\n{:?}\n{:?}", "trying to connect memory ports:\n{:?}\n{:?}",
Expr::ty(lhs), Expr::ty(lhs),
Expr::ty(rhs), Expr::ty(rhs),
@ -671,7 +665,6 @@ impl Folder for State {
ExprEnum::UIntLiteral(_) ExprEnum::UIntLiteral(_)
| ExprEnum::SIntLiteral(_) | ExprEnum::SIntLiteral(_)
| ExprEnum::BoolLiteral(_) | ExprEnum::BoolLiteral(_)
| ExprEnum::PhantomConst(_)
| ExprEnum::BundleLiteral(_) | ExprEnum::BundleLiteral(_)
| ExprEnum::ArrayLiteral(_) | ExprEnum::ArrayLiteral(_)
| ExprEnum::Uninit(_) | ExprEnum::Uninit(_)
@ -930,9 +923,7 @@ impl Folder for State {
| CanonicalType::Clock(_) | CanonicalType::Clock(_)
| CanonicalType::AsyncReset(_) | CanonicalType::AsyncReset(_)
| CanonicalType::SyncReset(_) | CanonicalType::SyncReset(_)
| CanonicalType::Reset(_) | CanonicalType::Reset(_) => canonical_type.default_fold(self),
| CanonicalType::PhantomConst(_)
| CanonicalType::DynSimOnly(_) => canonical_type.default_fold(self),
} }
} }
@ -969,8 +960,8 @@ pub fn simplify_enums(
kind: SimplifyEnumsKind, kind: SimplifyEnumsKind,
) -> Result<Interned<Module<Bundle>>, SimplifyEnumsError> { ) -> Result<Interned<Module<Bundle>>, SimplifyEnumsError> {
module.fold(&mut State { module.fold(&mut State {
enum_types: HashMap::default(), enum_types: HashMap::new(),
replacement_mem_ports: HashMap::default(), replacement_mem_ports: HashMap::new(),
kind, kind,
module_state_stack: vec![], module_state_stack: vec![],
}) })

View file

@ -9,15 +9,16 @@ use crate::{
intern::{Intern, Interned}, intern::{Intern, Interned},
memory::{Mem, MemPort, PortType}, memory::{Mem, MemPort, PortType},
module::{ module::{
Block, Id, Module, NameId, ScopedNameId, Stmt, StmtConnect, StmtWire,
transform::visit::{Fold, Folder}, transform::visit::{Fold, Folder},
Block, Id, Module, NameId, ScopedNameId, Stmt, StmtConnect, StmtWire,
}, },
source_location::SourceLocation, source_location::SourceLocation,
ty::{CanonicalType, Type}, ty::{CanonicalType, Type},
util::{HashMap, MakeMutSlice}, util::MakeMutSlice,
wire::Wire, wire::Wire,
}; };
use bitvec::{slice::BitSlice, vec::BitVec}; use bitvec::{slice::BitSlice, vec::BitVec};
use hashbrown::HashMap;
use std::{ use std::{
convert::Infallible, convert::Infallible,
fmt::Write, fmt::Write,
@ -61,7 +62,6 @@ enum MemSplit {
Bundle { Bundle {
fields: Rc<[MemSplit]>, fields: Rc<[MemSplit]>,
}, },
PhantomConst,
Single { Single {
output_mem: Option<Mem>, output_mem: Option<Mem>,
element_type: SingleType, element_type: SingleType,
@ -76,7 +76,6 @@ impl MemSplit {
fn mark_changed_element_type(self) -> Self { fn mark_changed_element_type(self) -> Self {
match self { match self {
MemSplit::Bundle { fields: _ } => self, MemSplit::Bundle { fields: _ } => self,
MemSplit::PhantomConst => self,
MemSplit::Single { MemSplit::Single {
output_mem, output_mem,
element_type, element_type,
@ -98,7 +97,6 @@ impl MemSplit {
.map(|field| Self::new(field.ty).mark_changed_element_type()) .map(|field| Self::new(field.ty).mark_changed_element_type())
.collect(), .collect(),
}, },
CanonicalType::PhantomConst(_) => MemSplit::PhantomConst,
CanonicalType::Array(ty) => { CanonicalType::Array(ty) => {
let element = MemSplit::new(ty.element()); let element = MemSplit::new(ty.element());
if let Self::Single { if let Self::Single {
@ -194,7 +192,6 @@ impl MemSplit {
| CanonicalType::AsyncReset(_) | CanonicalType::AsyncReset(_)
| CanonicalType::SyncReset(_) | CanonicalType::SyncReset(_)
| CanonicalType::Reset(_) => unreachable!("memory element type is a storable type"), | CanonicalType::Reset(_) => unreachable!("memory element type is a storable type"),
CanonicalType::DynSimOnly(_) => todo!("memory containing sim-only values"),
} }
} }
} }
@ -324,9 +321,6 @@ impl SplitMemState<'_, '_> {
Expr::field(Expr::<Bundle>::from_canonical(e), &field.name) Expr::field(Expr::<Bundle>::from_canonical(e), &field.name)
}, },
|initial_value_element| { |initial_value_element| {
let Some(field_offset) = field_offset.only_bit_width() else {
todo!("memory containing sim-only values");
};
&initial_value_element[field_offset..][..field_ty_bit_width] &initial_value_element[field_offset..][..field_ty_bit_width]
}, },
); );
@ -345,7 +339,6 @@ impl SplitMemState<'_, '_> {
self.split_state_stack.pop(); self.split_state_stack.pop();
} }
} }
MemSplit::PhantomConst => {}
MemSplit::Single { MemSplit::Single {
output_mem, output_mem,
element_type: single_type, element_type: single_type,
@ -545,12 +538,7 @@ impl ModuleState {
}; };
loop { loop {
match input_element_type { match input_element_type {
CanonicalType::Bundle(_) => { CanonicalType::Bundle(_) => unreachable!("bundle types are always split"),
unreachable!("bundle types are always split")
}
CanonicalType::PhantomConst(_) => {
unreachable!("PhantomConst are always removed")
}
CanonicalType::Enum(_) CanonicalType::Enum(_)
if input_array_types if input_array_types
.first() .first()
@ -624,7 +612,6 @@ impl ModuleState {
| CanonicalType::AsyncReset(_) | CanonicalType::AsyncReset(_)
| CanonicalType::SyncReset(_) | CanonicalType::SyncReset(_)
| CanonicalType::Reset(_) => unreachable!("memory element type is a storable type"), | CanonicalType::Reset(_) => unreachable!("memory element type is a storable type"),
CanonicalType::DynSimOnly(_) => todo!("memory containing sim-only values"),
} }
break; break;
} }
@ -756,8 +743,7 @@ impl ModuleState {
.. ..
} }
| MemSplit::Bundle { .. } | MemSplit::Bundle { .. }
| MemSplit::Array { .. } | MemSplit::Array { .. } => {
| MemSplit::PhantomConst => {
let mut replacement_ports = Vec::with_capacity(input_mem.ports().len()); let mut replacement_ports = Vec::with_capacity(input_mem.ports().len());
let mut wire_port_rdata = Vec::with_capacity(input_mem.ports().len()); let mut wire_port_rdata = Vec::with_capacity(input_mem.ports().len());
let mut wire_port_wdata = Vec::with_capacity(input_mem.ports().len()); let mut wire_port_wdata = Vec::with_capacity(input_mem.ports().len());
@ -901,7 +887,7 @@ impl Folder for State {
module, module,
ModuleState { ModuleState {
output_module: None, output_module: None,
memories: HashMap::default(), memories: HashMap::new(),
}, },
); );
let mut this = PushedState::push_module(self, module); let mut this = PushedState::push_module(self, module);

View file

@ -11,11 +11,12 @@ use crate::{
clock::Clock, clock::Clock,
enum_::{Enum, EnumType, EnumVariant}, enum_::{Enum, EnumType, EnumVariant},
expr::{ expr::{
Expr, ExprEnum, ops, ops,
target::{ target::{
Target, TargetBase, TargetChild, TargetPathArrayElement, TargetPathBundleField, Target, TargetBase, TargetChild, TargetPathArrayElement, TargetPathBundleField,
TargetPathDynArrayElement, TargetPathElement, TargetPathDynArrayElement, TargetPathElement,
}, },
Expr, ExprEnum,
}, },
formal::FormalKind, formal::FormalKind,
int::{Bool, SIntType, SIntValue, Size, UIntType, UIntValue}, int::{Bool, SIntType, SIntValue, Size, UIntType, UIntValue},
@ -27,10 +28,8 @@ use crate::{
NormalModuleBody, ScopedNameId, Stmt, StmtConnect, StmtDeclaration, StmtFormal, StmtIf, NormalModuleBody, ScopedNameId, Stmt, StmtConnect, StmtDeclaration, StmtFormal, StmtIf,
StmtInstance, StmtMatch, StmtReg, StmtWire, StmtInstance, StmtMatch, StmtReg, StmtWire,
}, },
phantom_const::PhantomConst,
reg::Reg, reg::Reg,
reset::{AsyncReset, Reset, ResetType, SyncReset}, reset::{AsyncReset, Reset, ResetType, SyncReset},
sim::{ExternModuleSimulation, value::DynSimOnly},
source_location::SourceLocation, source_location::SourceLocation,
ty::{CanonicalType, Type}, ty::{CanonicalType, Type},
wire::Wire, wire::Wire,

View file

@ -1,417 +0,0 @@
// SPDX-License-Identifier: LGPL-3.0-or-later
// See Notices.txt for copyright information
use crate::{
expr::{
Expr, ToExpr,
ops::{ExprPartialEq, ExprPartialOrd},
},
int::Bool,
intern::{Intern, Interned, InternedCompare, LazyInterned, LazyInternedTrait, Memoize},
sim::value::{SimValue, SimValuePartialEq, ToSimValue, ToSimValueWithType},
source_location::SourceLocation,
ty::{
CanonicalType, OpaqueSimValueSlice, OpaqueSimValueWriter, OpaqueSimValueWritten,
StaticType, Type, TypeProperties, impl_match_variant_as_self,
serde_impls::{SerdeCanonicalType, SerdePhantomConst},
},
};
use serde::{
Deserialize, Deserializer, Serialize, Serializer,
de::{DeserializeOwned, Error},
};
use std::{
any::Any,
fmt,
hash::{Hash, Hasher},
marker::PhantomData,
ops::Index,
};
#[derive(Clone)]
pub struct PhantomConstCanonicalValue {
parsed: serde_json::Value,
serialized: Interned<str>,
}
impl PhantomConstCanonicalValue {
pub fn from_json_value(parsed: serde_json::Value) -> Self {
let serialized = Intern::intern_owned(
serde_json::to_string(&parsed)
.expect("conversion from json value to text shouldn't fail"),
);
Self { parsed, serialized }
}
pub fn as_json_value(&self) -> &serde_json::Value {
&self.parsed
}
pub fn as_str(&self) -> Interned<str> {
self.serialized
}
}
impl fmt::Debug for PhantomConstCanonicalValue {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(&self.serialized)
}
}
impl fmt::Display for PhantomConstCanonicalValue {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(&self.serialized)
}
}
impl PartialEq for PhantomConstCanonicalValue {
fn eq(&self, other: &Self) -> bool {
self.serialized == other.serialized
}
}
impl Eq for PhantomConstCanonicalValue {}
impl Hash for PhantomConstCanonicalValue {
fn hash<H: Hasher>(&self, state: &mut H) {
self.serialized.hash(state);
}
}
impl Serialize for PhantomConstCanonicalValue {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
self.parsed.serialize(serializer)
}
}
impl<'de> Deserialize<'de> for PhantomConstCanonicalValue {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
Ok(Self::from_json_value(serde_json::Value::deserialize(
deserializer,
)?))
}
}
pub trait PhantomConstValue: Intern + InternedCompare + Serialize + fmt::Debug {
fn deserialize_value<'de, D>(deserializer: D) -> Result<Interned<Self>, D::Error>
where
D: serde::Deserializer<'de>;
}
impl<T> PhantomConstValue for T
where
T: ?Sized + Intern + InternedCompare + Serialize + fmt::Debug,
Interned<T>: DeserializeOwned,
{
fn deserialize_value<'de, D>(deserializer: D) -> Result<Interned<Self>, D::Error>
where
D: serde::Deserializer<'de>,
{
<Interned<T> as Deserialize<'de>>::deserialize(deserializer)
}
}
/// Wrapper type that allows any Rust value to be smuggled as a HDL [`Type`].
/// This only works for values that can be [serialized][Serialize] to and [deserialized][Deserialize] from [JSON][serde_json].
pub struct PhantomConst<T: ?Sized + PhantomConstValue = PhantomConstCanonicalValue> {
value: LazyInterned<T>,
}
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Default)]
pub struct PhantomConstWithoutGenerics;
#[allow(non_upper_case_globals)]
pub const PhantomConst: PhantomConstWithoutGenerics = PhantomConstWithoutGenerics;
impl<T: Type + PhantomConstValue> Index<T> for PhantomConstWithoutGenerics {
type Output = PhantomConst<T>;
fn index(&self, value: T) -> &Self::Output {
Interned::into_inner(PhantomConst::new(value.intern()).intern_sized())
}
}
impl<T: ?Sized + PhantomConstValue> fmt::Debug for PhantomConst<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("PhantomConst").field(&self.get()).finish()
}
}
impl<T: ?Sized + PhantomConstValue> Clone for PhantomConst<T> {
fn clone(&self) -> Self {
*self
}
}
impl<T: ?Sized + PhantomConstValue> Copy for PhantomConst<T> {}
impl<T: ?Sized + PhantomConstValue> PartialEq for PhantomConst<T> {
fn eq(&self, other: &Self) -> bool {
self.get() == other.get()
}
}
impl<T: ?Sized + PhantomConstValue> Eq for PhantomConst<T> {}
impl<T: ?Sized + PhantomConstValue> Hash for PhantomConst<T> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.get().hash(state);
}
}
struct PhantomConstCanonicalMemoize<T: ?Sized, const IS_FROM_CANONICAL: bool>(PhantomData<T>);
impl<T: ?Sized, const IS_FROM_CANONICAL: bool> Copy
for PhantomConstCanonicalMemoize<T, IS_FROM_CANONICAL>
{
}
impl<T: ?Sized, const IS_FROM_CANONICAL: bool> Clone
for PhantomConstCanonicalMemoize<T, IS_FROM_CANONICAL>
{
fn clone(&self) -> Self {
*self
}
}
impl<T: ?Sized, const IS_FROM_CANONICAL: bool> Eq
for PhantomConstCanonicalMemoize<T, IS_FROM_CANONICAL>
{
}
impl<T: ?Sized, const IS_FROM_CANONICAL: bool> PartialEq
for PhantomConstCanonicalMemoize<T, IS_FROM_CANONICAL>
{
fn eq(&self, _other: &Self) -> bool {
true
}
}
impl<T: ?Sized, const IS_FROM_CANONICAL: bool> Hash
for PhantomConstCanonicalMemoize<T, IS_FROM_CANONICAL>
{
fn hash<H: Hasher>(&self, _state: &mut H) {}
}
impl<T: ?Sized + PhantomConstValue> Memoize for PhantomConstCanonicalMemoize<T, false> {
type Input = Interned<T>;
type InputOwned = Interned<T>;
type Output = Interned<PhantomConstCanonicalValue>;
fn inner(self, input: &Self::Input) -> Self::Output {
Intern::intern_sized(PhantomConstCanonicalValue::from_json_value(
serde_json::to_value(input)
.expect("serialization failed when constructing a canonical PhantomConst"),
))
}
}
impl<T: ?Sized + PhantomConstValue> Memoize for PhantomConstCanonicalMemoize<T, true> {
type Input = Interned<PhantomConstCanonicalValue>;
type InputOwned = Interned<PhantomConstCanonicalValue>;
type Output = Interned<T>;
fn inner(self, input: &Self::Input) -> Self::Output {
PhantomConstValue::deserialize_value(input.as_json_value())
.expect("deserialization failed ")
}
}
impl<T: ?Sized + PhantomConstValue> PhantomConst<T> {
pub fn new(value: Interned<T>) -> Self {
Self {
value: LazyInterned::Interned(value),
}
}
pub const fn new_lazy(v: &'static dyn LazyInternedTrait<T>) -> Self {
Self {
value: LazyInterned::new_lazy(v),
}
}
pub fn get(self) -> Interned<T> {
self.value.interned()
}
pub fn type_properties(self) -> TypeProperties {
<()>::TYPE_PROPERTIES
}
pub fn can_connect(self, other: Self) -> bool {
self == other
}
pub fn canonical_phantom_const(self) -> PhantomConst {
if let Some(&retval) = <dyn Any>::downcast_ref::<PhantomConst>(&self) {
return retval;
}
<PhantomConst>::new(
PhantomConstCanonicalMemoize::<T, false>(PhantomData).get_owned(self.get()),
)
}
pub fn from_canonical_phantom_const(canonical_type: PhantomConst) -> Self {
if let Some(&retval) = <dyn Any>::downcast_ref::<Self>(&canonical_type) {
return retval;
}
Self::new(
PhantomConstCanonicalMemoize::<T, true>(PhantomData).get_owned(canonical_type.get()),
)
}
}
impl<T: ?Sized + PhantomConstValue> Type for PhantomConst<T> {
type BaseType = PhantomConst;
type MaskType = ();
type SimValue = PhantomConst<T>;
impl_match_variant_as_self!();
fn mask_type(&self) -> Self::MaskType {
()
}
fn canonical(&self) -> CanonicalType {
CanonicalType::PhantomConst(self.canonical_phantom_const())
}
fn from_canonical(canonical_type: CanonicalType) -> Self {
let CanonicalType::PhantomConst(phantom_const) = canonical_type else {
panic!("expected PhantomConst");
};
Self::from_canonical_phantom_const(phantom_const)
}
fn source_location() -> SourceLocation {
SourceLocation::builtin()
}
fn sim_value_from_opaque(&self, opaque: OpaqueSimValueSlice<'_>) -> Self::SimValue {
assert!(opaque.is_empty());
*self
}
fn sim_value_clone_from_opaque(
&self,
value: &mut Self::SimValue,
opaque: OpaqueSimValueSlice<'_>,
) {
assert!(opaque.is_empty());
assert_eq!(*value, *self);
}
fn sim_value_to_opaque<'w>(
&self,
value: &Self::SimValue,
writer: OpaqueSimValueWriter<'w>,
) -> OpaqueSimValueWritten<'w> {
assert_eq!(*value, *self);
writer.fill_cloned_from_slice(OpaqueSimValueSlice::empty())
}
}
impl<T: ?Sized + PhantomConstValue> Default for PhantomConst<T>
where
Interned<T>: Default,
{
fn default() -> Self {
Self::TYPE
}
}
impl<T: ?Sized + PhantomConstValue> StaticType for PhantomConst<T>
where
Interned<T>: Default,
{
const TYPE: Self = PhantomConst {
value: LazyInterned::new_lazy(&Interned::<T>::default),
};
const MASK_TYPE: Self::MaskType = ();
const TYPE_PROPERTIES: TypeProperties = <()>::TYPE_PROPERTIES;
const MASK_TYPE_PROPERTIES: TypeProperties = <()>::TYPE_PROPERTIES;
}
type SerdeType<T> = SerdeCanonicalType<CanonicalType, SerdePhantomConst<Interned<T>>>;
impl<T: ?Sized + PhantomConstValue> Serialize for PhantomConst<T> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
SerdeType::<T>::PhantomConst(SerdePhantomConst(self.get())).serialize(serializer)
}
}
impl<'de, T: ?Sized + PhantomConstValue> Deserialize<'de> for PhantomConst<T> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
match SerdeType::<T>::deserialize(deserializer)? {
SerdeCanonicalType::PhantomConst(SerdePhantomConst(value)) => Ok(Self::new(value)),
ty => Err(Error::invalid_value(
serde::de::Unexpected::Other(ty.as_serde_unexpected_str()),
&"a PhantomConst",
)),
}
}
}
impl<T: ?Sized + PhantomConstValue> ExprPartialEq<Self> for PhantomConst<T> {
fn cmp_eq(lhs: Expr<Self>, rhs: Expr<Self>) -> Expr<Bool> {
assert_eq!(Expr::ty(lhs), Expr::ty(rhs));
true.to_expr()
}
fn cmp_ne(lhs: Expr<Self>, rhs: Expr<Self>) -> Expr<Bool> {
assert_eq!(Expr::ty(lhs), Expr::ty(rhs));
false.to_expr()
}
}
impl<T: ?Sized + PhantomConstValue> ExprPartialOrd<Self> for PhantomConst<T> {
fn cmp_lt(lhs: Expr<Self>, rhs: Expr<Self>) -> Expr<Bool> {
assert_eq!(Expr::ty(lhs), Expr::ty(rhs));
false.to_expr()
}
fn cmp_le(lhs: Expr<Self>, rhs: Expr<Self>) -> Expr<Bool> {
assert_eq!(Expr::ty(lhs), Expr::ty(rhs));
true.to_expr()
}
fn cmp_gt(lhs: Expr<Self>, rhs: Expr<Self>) -> Expr<Bool> {
assert_eq!(Expr::ty(lhs), Expr::ty(rhs));
false.to_expr()
}
fn cmp_ge(lhs: Expr<Self>, rhs: Expr<Self>) -> Expr<Bool> {
assert_eq!(Expr::ty(lhs), Expr::ty(rhs));
true.to_expr()
}
}
impl<T: ?Sized + PhantomConstValue> SimValuePartialEq<Self> for PhantomConst<T> {
fn sim_value_eq(this: &SimValue<Self>, other: &SimValue<Self>) -> bool {
assert_eq!(SimValue::ty(this), SimValue::ty(other));
true
}
}
impl<T: ?Sized + PhantomConstValue> ToSimValue for PhantomConst<T> {
type Type = PhantomConst<T>;
fn to_sim_value(&self) -> SimValue<Self::Type> {
SimValue::from_value(*self, *self)
}
}
impl<T: ?Sized + PhantomConstValue> ToSimValueWithType<PhantomConst<T>> for PhantomConst<T> {
fn to_sim_value_with_type(&self, ty: PhantomConst<T>) -> SimValue<PhantomConst<T>> {
SimValue::from_value(ty, *self)
}
}
impl<T: ?Sized + PhantomConstValue> ToSimValueWithType<CanonicalType> for PhantomConst<T> {
fn to_sim_value_with_type(&self, ty: CanonicalType) -> SimValue<CanonicalType> {
SimValue::into_canonical(SimValue::from_value(Self::from_canonical(ty), *self))
}
}

View file

@ -1,7 +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 use crate::{ pub use crate::{
__,
annotations::{ annotations::{
BlackBoxInlineAnnotation, BlackBoxPathAnnotation, CustomFirrtlAnnotation, BlackBoxInlineAnnotation, BlackBoxPathAnnotation, CustomFirrtlAnnotation,
DocStringAnnotation, DontTouchAnnotation, SVAttributeAnnotation, DocStringAnnotation, DontTouchAnnotation, SVAttributeAnnotation,
@ -12,32 +11,26 @@ pub use crate::{
clock::{Clock, ClockDomain, ToClock}, clock::{Clock, ClockDomain, ToClock},
enum_::{Enum, HdlNone, HdlOption, HdlSome}, enum_::{Enum, HdlNone, HdlOption, HdlSome},
expr::{ expr::{
CastBitsTo, CastTo, CastToBits, Expr, HdlPartialEq, HdlPartialOrd, MakeUninitExpr, repeat, CastBitsTo, CastTo, CastToBits, Expr, HdlPartialEq, HdlPartialOrd, MakeUninitExpr,
ReduceBits, ToExpr, repeat, ReduceBits, ToExpr,
}, },
formal::{ formal::{
MakeFormalExpr, all_const, all_seq, any_const, any_seq, formal_global_clock, formal_reset, all_const, all_seq, any_const, any_seq, formal_global_clock, formal_reset, hdl_assert,
hdl_assert, hdl_assert_with_enable, hdl_assume, hdl_assume_with_enable, hdl_cover, hdl_assert_with_enable, hdl_assume, hdl_assume_with_enable, hdl_cover,
hdl_cover_with_enable, hdl_cover_with_enable, MakeFormalExpr,
}, },
hdl, hdl_module, hdl, hdl_module,
int::{Bool, DynSize, KnownSize, SInt, SIntType, SIntValue, Size, UInt, UIntType, UIntValue}, int::{Bool, DynSize, KnownSize, SInt, SIntType, Size, UInt, UIntType},
memory::{Mem, MemBuilder, ReadUnderWrite}, memory::{Mem, MemBuilder, ReadUnderWrite},
module::{ module::{
Instance, Module, ModuleBuilder, annotate, connect, connect_any, incomplete_wire, instance, annotate, connect, connect_any, incomplete_wire, instance, memory, memory_array,
memory, memory_array, memory_with_init, reg_builder, wire, memory_with_init, reg_builder, wire, Instance, Module, ModuleBuilder,
}, },
phantom_const::PhantomConst,
reg::Reg, reg::Reg,
reset::{AsyncReset, Reset, SyncReset, ToAsyncReset, ToReset, ToSyncReset}, reset::{AsyncReset, Reset, SyncReset, ToAsyncReset, ToReset, ToSyncReset},
sim::{
ExternModuleSimulationState, Simulation,
time::{SimDuration, SimInstant},
value::{SimOnly, SimOnlyValue, SimValue, ToSimValue, ToSimValueWithType},
},
source_location::SourceLocation, source_location::SourceLocation,
ty::{AsMask, CanonicalType, Type}, ty::{AsMask, CanonicalType, Type},
util::{ConstUsize, GenericConstUsize}, util::{ConstUsize, GenericConstUsize},
wire::Wire, wire::Wire,
__,
}; };
pub use bitvec::{slice::BitSlice, vec::BitVec};

View file

@ -2,15 +2,11 @@
// See Notices.txt for copyright information // See Notices.txt for copyright information
use crate::{ use crate::{
clock::Clock, clock::Clock,
expr::{Expr, ToExpr, ops}, expr::{ops, Expr, ToExpr},
int::{Bool, SInt, UInt}, int::{Bool, SInt, UInt},
source_location::SourceLocation, source_location::SourceLocation,
ty::{ ty::{impl_match_variant_as_self, CanonicalType, StaticType, Type, TypeProperties},
CanonicalType, OpaqueSimValueSize, OpaqueSimValueSlice, OpaqueSimValueWriter,
OpaqueSimValueWritten, StaticType, Type, TypeProperties, impl_match_variant_as_self,
},
}; };
use bitvec::{bits, order::Lsb0};
mod sealed { mod sealed {
pub trait ResetTypeSealed {} pub trait ResetTypeSealed {}
@ -49,7 +45,6 @@ macro_rules! reset_type {
impl Type for $name { impl Type for $name {
type BaseType = $name; type BaseType = $name;
type MaskType = Bool; type MaskType = Bool;
type SimValue = bool;
impl_match_variant_as_self!(); impl_match_variant_as_self!();
@ -71,31 +66,6 @@ macro_rules! reset_type {
}; };
retval retval
} }
fn sim_value_from_opaque(&self, opaque: OpaqueSimValueSlice<'_>) -> Self::SimValue {
assert_eq!(opaque.size(), OpaqueSimValueSize::from_bit_width(1));
opaque.bits()[0]
}
fn sim_value_clone_from_opaque(
&self,
value: &mut Self::SimValue,
opaque: OpaqueSimValueSlice<'_>,
) {
assert_eq!(opaque.size(), OpaqueSimValueSize::from_bit_width(1));
*value = opaque.bits()[0];
}
fn sim_value_to_opaque<'w>(
&self,
value: &Self::SimValue,
writer: OpaqueSimValueWriter<'w>,
) -> OpaqueSimValueWritten<'w> {
assert_eq!(writer.size(), OpaqueSimValueSize::from_bit_width(1));
writer.fill_cloned_from_slice(OpaqueSimValueSlice::from_bitslice(
[bits![0], bits![1]][*value as usize],
))
}
} }
impl $name { impl $name {
@ -115,7 +85,6 @@ macro_rules! reset_type {
is_storable: false, is_storable: false,
is_castable_from_bits: $is_castable_from_bits, is_castable_from_bits: $is_castable_from_bits,
bit_width: 1, bit_width: 1,
sim_only_values_len: 0,
}; };
const MASK_TYPE_PROPERTIES: TypeProperties = Bool::TYPE_PROPERTIES; const MASK_TYPE_PROPERTIES: TypeProperties = Bool::TYPE_PROPERTIES;
} }

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,304 +0,0 @@
// SPDX-License-Identifier: LGPL-3.0-or-later
// See Notices.txt for copyright information
//! `unsafe` parts of [`DynSimOnlyValue`]
use serde::{Serialize, de::DeserializeOwned};
use std::{
any::{self, TypeId},
fmt,
hash::{Hash, Hasher},
marker::PhantomData,
mem::ManuallyDrop,
rc::Rc,
};
pub trait SimOnlyValueTrait:
'static + Eq + Hash + fmt::Debug + Serialize + DeserializeOwned + Clone + Default
{
}
impl<T: 'static + Eq + Hash + fmt::Debug + Serialize + DeserializeOwned + Clone + Default>
SimOnlyValueTrait for T
{
}
/// Safety: `type_id_dyn` must return `TypeId::of::<T>()` where `Self = SimOnly<T>`
unsafe trait DynSimOnlyTrait: 'static + Send + Sync {
fn type_id_dyn(&self) -> TypeId;
fn type_name(&self) -> &'static str;
fn default_value(&self) -> Rc<dyn DynSimOnlyValueTrait>;
fn deserialize_from_json_string(
&self,
json_str: &str,
) -> serde_json::Result<Rc<dyn DynSimOnlyValueTrait>>;
}
/// Safety: `type_id_dyn` is implemented correctly
unsafe impl<T: SimOnlyValueTrait> DynSimOnlyTrait for SimOnly<T> {
fn type_id_dyn(&self) -> TypeId {
TypeId::of::<T>()
}
fn type_name(&self) -> &'static str {
any::type_name::<T>()
}
fn default_value(&self) -> Rc<dyn DynSimOnlyValueTrait> {
Rc::new(T::default())
}
fn deserialize_from_json_string(
&self,
json_str: &str,
) -> serde_json::Result<Rc<dyn DynSimOnlyValueTrait>> {
Ok(Rc::<T>::new(serde_json::from_str(json_str)?))
}
}
/// Safety:
/// * `type_id_dyn()` must return `TypeId::of::<Self>()`.
/// * `ty().type_id()` must return `TypeId::of::<Self>()`.
unsafe trait DynSimOnlyValueTrait: 'static + fmt::Debug {
fn type_id_dyn(&self) -> TypeId;
fn ty(&self) -> DynSimOnly;
fn eq_dyn(&self, other: &dyn DynSimOnlyValueTrait) -> bool;
fn serialize_to_json_string(&self) -> serde_json::Result<String>;
fn hash_dyn(&self, state: &mut dyn Hasher);
}
impl dyn DynSimOnlyValueTrait {
fn is<T: SimOnlyValueTrait>(&self) -> bool {
Self::type_id_dyn(self) == TypeId::of::<T>()
}
fn downcast_ref<T: SimOnlyValueTrait>(&self) -> Option<&T> {
if Self::is::<T>(self) {
// Safety: checked that `Self` is really `T`
Some(unsafe { &*(self as *const Self as *const T) })
} else {
None
}
}
fn downcast_rc<T: SimOnlyValueTrait>(self: Rc<Self>) -> Result<Rc<T>, Rc<Self>> {
if Self::is::<T>(&*self) {
// Safety: checked that `Self` is really `T`
Ok(unsafe { Rc::from_raw(Rc::into_raw(self) as *const T) })
} else {
Err(self)
}
}
}
/// Safety:
/// * `type_id_dyn()` returns `TypeId::of::<Self>()`.
/// * `ty().type_id()` returns `TypeId::of::<Self>()`.
unsafe impl<T: SimOnlyValueTrait> DynSimOnlyValueTrait for T {
fn type_id_dyn(&self) -> TypeId {
TypeId::of::<T>()
}
fn ty(&self) -> DynSimOnly {
DynSimOnly::of::<T>()
}
fn eq_dyn(&self, other: &dyn DynSimOnlyValueTrait) -> bool {
other.downcast_ref::<T>().is_some_and(|other| self == other)
}
fn serialize_to_json_string(&self) -> serde_json::Result<String> {
serde_json::to_string(self)
}
fn hash_dyn(&self, mut state: &mut dyn Hasher) {
self.hash(&mut state);
}
}
#[derive(Copy, Clone)]
pub struct DynSimOnly {
ty: &'static dyn DynSimOnlyTrait,
}
impl DynSimOnly {
pub const fn of<T: SimOnlyValueTrait>() -> Self {
Self {
ty: &const { SimOnly::<T>::new() },
}
}
pub fn type_id(self) -> TypeId {
self.ty.type_id_dyn()
}
pub fn type_name(self) -> &'static str {
self.ty.type_name()
}
pub fn is<T: SimOnlyValueTrait>(self) -> bool {
self.type_id() == TypeId::of::<T>()
}
pub fn downcast<T: SimOnlyValueTrait>(self) -> Option<SimOnly<T>> {
self.is::<T>().then_some(SimOnly::default())
}
pub fn deserialize_from_json_string(
self,
json_str: &str,
) -> serde_json::Result<DynSimOnlyValue> {
self.ty
.deserialize_from_json_string(json_str)
.map(DynSimOnlyValue)
}
pub fn default_value(self) -> DynSimOnlyValue {
DynSimOnlyValue(self.ty.default_value())
}
}
impl PartialEq for DynSimOnly {
fn eq(&self, other: &Self) -> bool {
Self::type_id(*self) == Self::type_id(*other)
}
}
impl Eq for DynSimOnly {}
impl Hash for DynSimOnly {
fn hash<H: Hasher>(&self, state: &mut H) {
Self::type_id(*self).hash(state);
}
}
impl fmt::Debug for DynSimOnly {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "SimOnly<{}>", self.ty.type_name())
}
}
impl<T: SimOnlyValueTrait> From<SimOnly<T>> for DynSimOnly {
fn from(value: SimOnly<T>) -> Self {
let SimOnly(PhantomData) = value;
Self::of::<T>()
}
}
/// the [`Type`][Type] for a value that can only be used in a Fayalite simulation, it can't be converted to FIRRTL
///
/// [Type]: crate::ty::Type
#[derive(Clone, Eq, PartialEq, Hash)]
pub struct SimOnly<T: SimOnlyValueTrait>(PhantomData<fn(T) -> T>);
impl<T: SimOnlyValueTrait> fmt::Debug for SimOnly<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
DynSimOnly::of::<T>().fmt(f)
}
}
impl<T: SimOnlyValueTrait> SimOnly<T> {
pub const fn new() -> Self {
Self(PhantomData)
}
}
impl<T: SimOnlyValueTrait> Copy for SimOnly<T> {}
impl<T: SimOnlyValueTrait> Default for SimOnly<T> {
fn default() -> Self {
Self::new()
}
}
/// a value that can only be used in a Fayalite simulation, it can't be converted to FIRRTL
#[derive(Clone, Eq, PartialEq, Hash, Default, PartialOrd, Ord)]
pub struct SimOnlyValue<T: SimOnlyValueTrait>(Rc<T>);
impl<T: SimOnlyValueTrait> SimOnlyValue<T> {
pub fn with_dyn_ref<F: FnOnce(&DynSimOnlyValue) -> R, R>(&self, f: F) -> R {
// Safety: creating a copied `Rc<T>` is safe as long as the copy isn't dropped and isn't changed
// to point somewhere else, `f` can't change `dyn_ref` because it's only given a shared reference.
let dyn_ref =
unsafe { ManuallyDrop::new(DynSimOnlyValue(Rc::<T>::from_raw(Rc::as_ptr(&self.0)))) };
f(&dyn_ref)
}
pub fn from_rc(v: Rc<T>) -> Self {
Self(v)
}
pub fn new(v: T) -> Self {
Self(Rc::new(v))
}
pub fn into_inner(this: Self) -> Rc<T> {
this.0
}
pub fn inner_mut(this: &mut Self) -> &mut Rc<T> {
&mut this.0
}
pub fn inner(this: &Self) -> &Rc<T> {
&this.0
}
pub fn into_dyn(this: Self) -> DynSimOnlyValue {
DynSimOnlyValue::from(this)
}
}
impl<T: SimOnlyValueTrait> std::ops::Deref for SimOnlyValue<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<T: SimOnlyValueTrait> std::ops::DerefMut for SimOnlyValue<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
Rc::make_mut(&mut self.0)
}
}
#[derive(Clone)]
pub struct DynSimOnlyValue(Rc<dyn DynSimOnlyValueTrait>);
impl fmt::Debug for DynSimOnlyValue {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
<dyn DynSimOnlyValueTrait as fmt::Debug>::fmt(&*self.0, f)
}
}
impl PartialEq for DynSimOnlyValue {
fn eq(&self, other: &Self) -> bool {
DynSimOnlyValueTrait::eq_dyn(&*self.0, &*other.0)
}
}
impl Eq for DynSimOnlyValue {}
impl Hash for DynSimOnlyValue {
fn hash<H: Hasher>(&self, state: &mut H) {
DynSimOnlyValueTrait::hash_dyn(&*self.0, state);
}
}
impl<T: SimOnlyValueTrait> From<SimOnlyValue<T>> for DynSimOnlyValue {
fn from(value: SimOnlyValue<T>) -> Self {
Self(value.0)
}
}
impl DynSimOnlyValue {
pub fn ty(&self) -> DynSimOnly {
self.0.ty()
}
pub fn type_id(&self) -> TypeId {
self.0.type_id_dyn()
}
pub fn is<T: SimOnlyValueTrait>(&self) -> bool {
self.0.is::<T>()
}
pub fn downcast<T: SimOnlyValueTrait>(self) -> Result<SimOnlyValue<T>, DynSimOnlyValue> {
match <dyn DynSimOnlyValueTrait>::downcast_rc(self.0) {
Ok(v) => Ok(SimOnlyValue(v)),
Err(v) => Err(Self(v)),
}
}
pub fn downcast_ref<T: SimOnlyValueTrait>(&self) -> Option<&T> {
<dyn DynSimOnlyValueTrait>::downcast_ref(&*self.0)
}
pub fn serialize_to_json_string(&self) -> serde_json::Result<String> {
self.0.serialize_to_json_string()
}
}

View file

@ -5,86 +5,22 @@ use crate::{
enum_::{Enum, EnumType}, enum_::{Enum, EnumType},
expr::Flow, expr::Flow,
int::UInt, int::UInt,
intern::{Intern, Interned},
sim::{ sim::{
time::{SimDuration, SimInstant},
TraceArray, TraceAsyncReset, TraceBool, TraceBundle, TraceClock, TraceDecl, TraceArray, TraceAsyncReset, TraceBool, TraceBundle, TraceClock, TraceDecl,
TraceEnumDiscriminant, TraceEnumWithFields, TraceFieldlessEnum, TraceInstance, TraceEnumDiscriminant, TraceEnumWithFields, TraceFieldlessEnum, TraceInstance,
TraceLocation, TraceMem, TraceMemPort, TraceMemoryId, TraceMemoryLocation, TraceModule, TraceLocation, TraceMem, TraceMemPort, TraceMemoryId, TraceMemoryLocation, TraceModule,
TraceModuleIO, TraceReg, TraceSInt, TraceScalar, TraceScalarId, TraceScope, TraceSimOnly, TraceModuleIO, TraceReg, TraceSInt, TraceScalar, TraceScalarId, TraceScope, TraceSyncReset,
TraceSyncReset, TraceUInt, TraceWire, TraceWriter, TraceWriterDecls, TraceUInt, TraceWire, TraceWriter, TraceWriterDecls,
time::{SimDuration, SimInstant},
value::DynSimOnlyValue,
}, },
util::HashMap,
}; };
use bitvec::{order::Lsb0, slice::BitSlice}; use bitvec::{order::Lsb0, slice::BitSlice};
use hashbrown::hash_map::Entry;
use std::{ use std::{
fmt::{self, Write as _}, fmt,
io, mem, io::{self, Write},
mem,
}; };
#[derive(Default)]
struct Scope {
last_inserted: HashMap<Interned<str>, usize>,
}
#[derive(Copy, Clone)]
struct VerilogIdentifier {
unescaped_name: Interned<str>,
}
impl VerilogIdentifier {
fn needs_escape(self) -> bool {
// we only allow ascii, so we can just check bytes
let Some((&first, rest)) = self.unescaped_name.as_bytes().split_first() else {
unreachable!("Scope::new_identifier guarantees a non-empty name");
};
if !first.is_ascii_alphabetic() && first != b'_' {
true
} else {
rest.iter()
.any(|&ch| !ch.is_ascii_alphanumeric() && ch != b'_' && ch != b'$')
}
}
}
impl fmt::Display for VerilogIdentifier {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.needs_escape() {
f.write_str("\\")?;
}
write!(f, "{}", Escaped(self.unescaped_name))
}
}
impl Scope {
fn new_identifier(&mut self, unescaped_name: Interned<str>) -> VerilogIdentifier {
let next_disambiguator = match self.last_inserted.entry(unescaped_name) {
Entry::Vacant(entry) => {
entry.insert(1);
return VerilogIdentifier { unescaped_name };
}
Entry::Occupied(entry) => entry.get() + 1,
};
let mut disambiguated_name = String::from(&*unescaped_name);
for disambiguator in next_disambiguator.. {
disambiguated_name.truncate(unescaped_name.len());
write!(disambiguated_name, "_{disambiguator}").expect("can't fail");
if let Entry::Vacant(entry) = self.last_inserted.entry((*disambiguated_name).intern()) {
let retval = VerilogIdentifier {
unescaped_name: *entry.key(),
};
entry.insert(1);
// speed up future searches
self.last_inserted.insert(unescaped_name, disambiguator);
return retval;
}
}
panic!("too many names");
}
}
pub struct VcdWriterDecls<W: io::Write + 'static> { pub struct VcdWriterDecls<W: io::Write + 'static> {
writer: W, writer: W,
timescale: SimDuration, timescale: SimDuration,
@ -161,20 +97,14 @@ impl<W: io::Write> fmt::Debug for VcdWriterDecls<W> {
} }
} }
/// pass in scope to ensure it's not available in child scope
fn write_vcd_scope<W: io::Write, R>( fn write_vcd_scope<W: io::Write, R>(
writer: &mut W, writer: &mut W,
scope_type: &str, scope_type: &str,
scope_name: Interned<str>, scope_name: &str,
scope: &mut Scope, f: impl FnOnce(&mut W) -> io::Result<R>,
f: impl FnOnce(&mut W, &mut Scope) -> io::Result<R>,
) -> io::Result<R> { ) -> io::Result<R> {
writeln!( writeln!(writer, "$scope {scope_type} {scope_name} $end")?;
writer, let retval = f(writer)?;
"$scope {scope_type} {} $end",
scope.new_identifier(scope_name),
)?;
let retval = f(writer, &mut Scope::default())?;
writeln!(writer, "$upscope $end")?; writeln!(writer, "$upscope $end")?;
Ok(retval) Ok(retval)
} }
@ -213,28 +143,24 @@ trait_arg! {
struct ArgModule<'a> { struct ArgModule<'a> {
properties: &'a mut VcdWriterProperties, properties: &'a mut VcdWriterProperties,
scope: &'a mut Scope,
} }
impl<'a> ArgModule<'a> { impl<'a> ArgModule<'a> {
fn reborrow(&mut self) -> ArgModule<'_> { fn reborrow(&mut self) -> ArgModule<'_> {
ArgModule { ArgModule {
properties: self.properties, properties: self.properties,
scope: self.scope,
} }
} }
} }
struct ArgModuleBody<'a> { struct ArgModuleBody<'a> {
properties: &'a mut VcdWriterProperties, properties: &'a mut VcdWriterProperties,
scope: &'a mut Scope,
} }
impl<'a> ArgModuleBody<'a> { impl<'a> ArgModuleBody<'a> {
fn reborrow(&mut self) -> ArgModuleBody<'_> { fn reborrow(&mut self) -> ArgModuleBody<'_> {
ArgModuleBody { ArgModuleBody {
properties: self.properties, properties: self.properties,
scope: self.scope,
} }
} }
} }
@ -244,7 +170,6 @@ struct ArgInType<'a> {
sink_var_type: &'static str, sink_var_type: &'static str,
duplex_var_type: &'static str, duplex_var_type: &'static str,
properties: &'a mut VcdWriterProperties, properties: &'a mut VcdWriterProperties,
scope: &'a mut Scope,
} }
impl<'a> ArgInType<'a> { impl<'a> ArgInType<'a> {
@ -254,7 +179,6 @@ impl<'a> ArgInType<'a> {
sink_var_type: self.sink_var_type, sink_var_type: self.sink_var_type,
duplex_var_type: self.duplex_var_type, duplex_var_type: self.duplex_var_type,
properties: self.properties, properties: self.properties,
scope: self.scope,
} }
} }
} }
@ -283,7 +207,6 @@ impl WriteTrace for TraceScalar {
Self::Clock(v) => v.write_trace(writer, arg), Self::Clock(v) => v.write_trace(writer, arg),
Self::SyncReset(v) => v.write_trace(writer, arg), Self::SyncReset(v) => v.write_trace(writer, arg),
Self::AsyncReset(v) => v.write_trace(writer, arg), Self::AsyncReset(v) => v.write_trace(writer, arg),
Self::SimOnly(v) => v.write_trace(writer, arg),
} }
} }
} }
@ -303,42 +226,55 @@ fn write_vcd_id<W: io::Write>(writer: &mut W, mut id: usize) -> io::Result<()> {
Ok(()) Ok(())
} }
struct Escaped<T: fmt::Display>(T); fn write_escaped<W: io::Write>(writer: &mut W, value: impl fmt::Display) -> io::Result<()> {
impl<T: fmt::Display> fmt::Display for Escaped<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
// escaping rules from function GTKWave uses to decode VCD strings: // escaping rules from function GTKWave uses to decode VCD strings:
// https://github.com/gtkwave/gtkwave/blob/491f24d7e8619cfc1fcc65704ee5c967d1083c18/lib/libfst/fstapi.c#L7090 // https://github.com/gtkwave/gtkwave/blob/491f24d7e8619cfc1fcc65704ee5c967d1083c18/lib/libfst/fstapi.c#L7090
struct Wrapper<W>(W); struct Wrapper<W>(W);
impl<W: fmt::Write> fmt::Write for Wrapper<W> { impl<W: io::Write> io::Write for Wrapper<W> {
fn write_str(&mut self, s: &str) -> fmt::Result { fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
for byte in s.bytes() { if buf.is_empty() {
match byte { return self.0.write(buf);
b'\\' | b'\'' | b'"' | b'?' => {
self.0.write_str("\\")?;
self.0.write_char(byte as char)?;
} }
b'\n' => self.0.write_str(r"\n")?, let mut retval = 0;
b'\r' => self.0.write_str(r"\r")?, for &byte in buf {
b'\t' => self.0.write_str(r"\t")?, match byte {
0x7 => self.0.write_str(r"\a")?, b'\\' | b'\'' | b'"' | b'?' => self.0.write_all(&[b'\\', byte])?,
0x8 => self.0.write_str(r"\b")?, b'\n' => self.0.write_all(br"\n")?,
0xC => self.0.write_str(r"\f")?, b'\r' => self.0.write_all(br"\r")?,
0xB => self.0.write_str(r"\v")?, b'\t' => self.0.write_all(br"\t")?,
0x7 => self.0.write_all(br"\a")?,
0x8 => self.0.write_all(br"\b")?,
0xC => self.0.write_all(br"\f")?,
0xB => self.0.write_all(br"\v")?,
_ => { _ => {
if byte.is_ascii_graphic() { if byte.is_ascii_graphic() {
self.0.write_char(byte as char)?; self.0.write_all(&[byte])?;
} else { } else {
write!(self.0, r"\x{byte:02x}")?; write!(self.0, r"\x{byte:02x}")?;
} }
} }
} }
retval += 1;
} }
Ok(()) Ok(retval)
}
fn flush(&mut self) -> io::Result<()> {
self.0.flush()
} }
} }
write!(Wrapper(f), "{}", self.0) write!(Wrapper(writer), "{value}")
} }
fn is_unescaped_verilog_identifier(ident: &str) -> bool {
// we only allow ascii, so we can just check bytes
let Some((&first, rest)) = ident.as_bytes().split_first() else {
return false; // empty string is not an identifier
};
(first.is_ascii_alphabetic() || first == b'_')
&& rest
.iter()
.all(|&ch| ch.is_ascii_alphanumeric() || ch == b'_' || ch == b'$')
} }
fn write_vcd_var<W: io::Write>( fn write_vcd_var<W: io::Write>(
@ -348,7 +284,7 @@ fn write_vcd_var<W: io::Write>(
var_type: &str, var_type: &str,
size: usize, size: usize,
location: TraceLocation, location: TraceLocation,
name: VerilogIdentifier, name: &str,
) -> io::Result<()> { ) -> io::Result<()> {
let id = match location { let id = match location {
TraceLocation::Scalar(id) => id.as_usize(), TraceLocation::Scalar(id) => id.as_usize(),
@ -383,7 +319,12 @@ fn write_vcd_var<W: io::Write>(
}; };
write!(writer, "$var {var_type} {size} ")?; write!(writer, "$var {var_type} {size} ")?;
write_vcd_id(writer, id)?; write_vcd_id(writer, id)?;
writeln!(writer, " {name} $end") writer.write_all(b" ")?;
if !is_unescaped_verilog_identifier(name) {
writer.write_all(b"\\")?;
}
write_escaped(writer, name)?;
writer.write_all(b" $end\n")
} }
impl WriteTrace for TraceUInt { impl WriteTrace for TraceUInt {
@ -393,7 +334,6 @@ impl WriteTrace for TraceUInt {
sink_var_type, sink_var_type,
duplex_var_type, duplex_var_type,
properties, properties,
scope,
} = arg.in_type(); } = arg.in_type();
let Self { let Self {
location, location,
@ -416,7 +356,7 @@ impl WriteTrace for TraceUInt {
var_type, var_type,
ty.width(), ty.width(),
location, location,
scope.new_identifier(name), &name,
) )
} }
} }
@ -481,7 +421,6 @@ impl WriteTrace for TraceEnumDiscriminant {
sink_var_type: _, sink_var_type: _,
duplex_var_type: _, duplex_var_type: _,
properties, properties,
scope,
} = arg.in_type(); } = arg.in_type();
let Self { let Self {
location, location,
@ -496,7 +435,7 @@ impl WriteTrace for TraceEnumDiscriminant {
"string", "string",
1, 1,
location, location,
scope.new_identifier(name), &name,
) )
} }
} }
@ -549,33 +488,6 @@ impl WriteTrace for TraceAsyncReset {
} }
} }
impl WriteTrace for TraceSimOnly {
fn write_trace<W: io::Write, A: Arg>(self, writer: &mut W, mut arg: A) -> io::Result<()> {
let ArgInType {
source_var_type: _,
sink_var_type: _,
duplex_var_type: _,
properties,
scope,
} = arg.in_type();
let Self {
location,
name,
ty: _,
flow: _,
} = self;
write_vcd_var(
properties,
MemoryElementPartBody::Scalar,
writer,
"string",
1,
location,
scope.new_identifier(name),
)
}
}
impl WriteTrace for TraceScope { impl WriteTrace for TraceScope {
fn write_trace<W: io::Write, A: Arg>(self, writer: &mut W, arg: A) -> io::Result<()> { fn write_trace<W: io::Write, A: Arg>(self, writer: &mut W, arg: A) -> io::Result<()> {
match self { match self {
@ -595,11 +507,11 @@ impl WriteTrace for TraceScope {
impl WriteTrace for TraceModule { impl WriteTrace for TraceModule {
fn write_trace<W: io::Write, A: Arg>(self, writer: &mut W, mut arg: A) -> io::Result<()> { fn write_trace<W: io::Write, A: Arg>(self, writer: &mut W, mut arg: A) -> io::Result<()> {
let ArgModule { properties, scope } = arg.module(); let ArgModule { properties } = arg.module();
let Self { name, children } = self; let Self { name, children } = self;
write_vcd_scope(writer, "module", name, scope, |writer, scope| { write_vcd_scope(writer, "module", &name, |writer| {
for child in children { for child in children {
child.write_trace(writer, ArgModuleBody { properties, scope })?; child.write_trace(writer, ArgModuleBody { properties })?;
} }
Ok(()) Ok(())
}) })
@ -608,7 +520,7 @@ impl WriteTrace for TraceModule {
impl WriteTrace for TraceInstance { impl WriteTrace for TraceInstance {
fn write_trace<W: io::Write, A: Arg>(self, writer: &mut W, mut arg: A) -> io::Result<()> { fn write_trace<W: io::Write, A: Arg>(self, writer: &mut W, mut arg: A) -> io::Result<()> {
let ArgModuleBody { properties, scope } = arg.module_body(); let ArgModuleBody { properties } = arg.module_body();
let Self { let Self {
name: _, name: _,
instance_io, instance_io,
@ -622,16 +534,15 @@ impl WriteTrace for TraceInstance {
sink_var_type: "wire", sink_var_type: "wire",
duplex_var_type: "wire", duplex_var_type: "wire",
properties, properties,
scope,
}, },
)?; )?;
module.write_trace(writer, ArgModule { properties, scope }) module.write_trace(writer, ArgModule { properties })
} }
} }
impl WriteTrace for TraceMem { impl WriteTrace for TraceMem {
fn write_trace<W: io::Write, A: Arg>(self, writer: &mut W, mut arg: A) -> io::Result<()> { fn write_trace<W: io::Write, A: Arg>(self, writer: &mut W, mut arg: A) -> io::Result<()> {
let ArgModuleBody { properties, scope } = arg.module_body(); let ArgModuleBody { properties } = arg.module_body();
let Self { let Self {
id, id,
name, name,
@ -640,22 +551,11 @@ impl WriteTrace for TraceMem {
ports, ports,
array_type, array_type,
} = self; } = self;
write_vcd_scope(writer, "struct", name, scope, |writer, scope| { write_vcd_scope(writer, "struct", &*name, |writer| {
write_vcd_scope( write_vcd_scope(writer, "struct", "contents", |writer| {
writer,
"struct",
"contents".intern(),
scope,
|writer, scope| {
for element_index in 0..array_type.len() { for element_index in 0..array_type.len() {
write_vcd_scope( write_vcd_scope(writer, "struct", &format!("[{element_index}]"), |writer| {
writer, properties.memory_properties[id.as_usize()].element_index = element_index;
"struct",
Intern::intern_owned(format!("[{element_index}]")),
scope,
|writer, scope| {
properties.memory_properties[id.as_usize()].element_index =
element_index;
properties.memory_properties[id.as_usize()].element_part_index = 0; properties.memory_properties[id.as_usize()].element_part_index = 0;
element_type.write_trace( element_type.write_trace(
writer, writer,
@ -664,17 +564,14 @@ impl WriteTrace for TraceMem {
sink_var_type: "reg", sink_var_type: "reg",
duplex_var_type: "reg", duplex_var_type: "reg",
properties, properties,
scope,
}, },
) )
}, })?;
)?;
} }
Ok(()) Ok(())
}, })?;
)?;
for port in ports { for port in ports {
port.write_trace(writer, ArgModuleBody { properties, scope })?; port.write_trace(writer, ArgModuleBody { properties })?;
} }
Ok(()) Ok(())
}) })
@ -683,7 +580,7 @@ impl WriteTrace for TraceMem {
impl WriteTrace for TraceMemPort { impl WriteTrace for TraceMemPort {
fn write_trace<W: io::Write, A: Arg>(self, writer: &mut W, mut arg: A) -> io::Result<()> { fn write_trace<W: io::Write, A: Arg>(self, writer: &mut W, mut arg: A) -> io::Result<()> {
let ArgModuleBody { properties, scope } = arg.module_body(); let ArgModuleBody { properties } = arg.module_body();
let Self { let Self {
name: _, name: _,
bundle, bundle,
@ -696,7 +593,6 @@ impl WriteTrace for TraceMemPort {
sink_var_type: "wire", sink_var_type: "wire",
duplex_var_type: "wire", duplex_var_type: "wire",
properties, properties,
scope,
}, },
) )
} }
@ -704,7 +600,7 @@ impl WriteTrace for TraceMemPort {
impl WriteTrace for TraceWire { impl WriteTrace for TraceWire {
fn write_trace<W: io::Write, A: Arg>(self, writer: &mut W, mut arg: A) -> io::Result<()> { fn write_trace<W: io::Write, A: Arg>(self, writer: &mut W, mut arg: A) -> io::Result<()> {
let ArgModuleBody { properties, scope } = arg.module_body(); let ArgModuleBody { properties } = arg.module_body();
let Self { let Self {
name: _, name: _,
child, child,
@ -717,7 +613,6 @@ impl WriteTrace for TraceWire {
sink_var_type: "wire", sink_var_type: "wire",
duplex_var_type: "wire", duplex_var_type: "wire",
properties, properties,
scope,
}, },
) )
} }
@ -725,7 +620,7 @@ impl WriteTrace for TraceWire {
impl WriteTrace for TraceReg { impl WriteTrace for TraceReg {
fn write_trace<W: io::Write, A: Arg>(self, writer: &mut W, mut arg: A) -> io::Result<()> { fn write_trace<W: io::Write, A: Arg>(self, writer: &mut W, mut arg: A) -> io::Result<()> {
let ArgModuleBody { properties, scope } = arg.module_body(); let ArgModuleBody { properties } = arg.module_body();
let Self { let Self {
name: _, name: _,
child, child,
@ -738,7 +633,6 @@ impl WriteTrace for TraceReg {
sink_var_type: "reg", sink_var_type: "reg",
duplex_var_type: "reg", duplex_var_type: "reg",
properties, properties,
scope,
}, },
) )
} }
@ -746,7 +640,7 @@ impl WriteTrace for TraceReg {
impl WriteTrace for TraceModuleIO { impl WriteTrace for TraceModuleIO {
fn write_trace<W: io::Write, A: Arg>(self, writer: &mut W, mut arg: A) -> io::Result<()> { fn write_trace<W: io::Write, A: Arg>(self, writer: &mut W, mut arg: A) -> io::Result<()> {
let ArgModuleBody { properties, scope } = arg.module_body(); let ArgModuleBody { properties } = arg.module_body();
let Self { let Self {
name: _, name: _,
child, child,
@ -760,7 +654,6 @@ impl WriteTrace for TraceModuleIO {
sink_var_type: "wire", sink_var_type: "wire",
duplex_var_type: "wire", duplex_var_type: "wire",
properties, properties,
scope,
}, },
) )
} }
@ -768,31 +661,16 @@ impl WriteTrace for TraceModuleIO {
impl WriteTrace for TraceBundle { impl WriteTrace for TraceBundle {
fn write_trace<W: io::Write, A: Arg>(self, writer: &mut W, mut arg: A) -> io::Result<()> { fn write_trace<W: io::Write, A: Arg>(self, writer: &mut W, mut arg: A) -> io::Result<()> {
let ArgInType { let mut arg = arg.in_type();
source_var_type,
sink_var_type,
duplex_var_type,
properties,
scope,
} = arg.in_type();
let Self { let Self {
name, name,
fields, fields,
ty: _, ty: _,
flow: _, flow: _,
} = self; } = self;
write_vcd_scope(writer, "struct", name, scope, |writer, scope| { write_vcd_scope(writer, "struct", &name, |writer| {
for field in fields { for field in fields {
field.write_trace( field.write_trace(writer, arg.reborrow())?;
writer,
ArgInType {
source_var_type,
sink_var_type,
duplex_var_type,
properties,
scope,
},
)?;
} }
Ok(()) Ok(())
}) })
@ -801,31 +679,16 @@ impl WriteTrace for TraceBundle {
impl WriteTrace for TraceArray { impl WriteTrace for TraceArray {
fn write_trace<W: io::Write, A: Arg>(self, writer: &mut W, mut arg: A) -> io::Result<()> { fn write_trace<W: io::Write, A: Arg>(self, writer: &mut W, mut arg: A) -> io::Result<()> {
let ArgInType { let mut arg = arg.in_type();
source_var_type,
sink_var_type,
duplex_var_type,
properties,
scope,
} = arg.in_type();
let Self { let Self {
name, name,
elements, elements,
ty: _, ty: _,
flow: _, flow: _,
} = self; } = self;
write_vcd_scope(writer, "struct", name, scope, |writer, scope| { write_vcd_scope(writer, "struct", &name, |writer| {
for element in elements { for element in elements {
element.write_trace( element.write_trace(writer, arg.reborrow())?;
writer,
ArgInType {
source_var_type,
sink_var_type,
duplex_var_type,
properties,
scope,
},
)?;
} }
Ok(()) Ok(())
}) })
@ -834,13 +697,7 @@ impl WriteTrace for TraceArray {
impl WriteTrace for TraceEnumWithFields { impl WriteTrace for TraceEnumWithFields {
fn write_trace<W: io::Write, A: Arg>(self, writer: &mut W, mut arg: A) -> io::Result<()> { fn write_trace<W: io::Write, A: Arg>(self, writer: &mut W, mut arg: A) -> io::Result<()> {
let ArgInType { let mut arg = arg.in_type();
source_var_type,
sink_var_type,
duplex_var_type,
properties,
scope,
} = arg.in_type();
let Self { let Self {
name, name,
discriminant, discriminant,
@ -848,28 +705,10 @@ impl WriteTrace for TraceEnumWithFields {
ty: _, ty: _,
flow: _, flow: _,
} = self; } = self;
write_vcd_scope(writer, "struct", name, scope, |writer, scope| { write_vcd_scope(writer, "struct", &name, |writer| {
discriminant.write_trace( discriminant.write_trace(writer, arg.reborrow())?;
writer,
ArgInType {
source_var_type,
sink_var_type,
duplex_var_type,
properties,
scope,
},
)?;
for field in non_empty_fields { for field in non_empty_fields {
field.write_trace( field.write_trace(writer, arg.reborrow())?;
writer,
ArgInType {
source_var_type,
sink_var_type,
duplex_var_type,
properties,
scope,
},
)?;
} }
Ok(()) Ok(())
}) })
@ -905,7 +744,6 @@ impl<W: io::Write> TraceWriterDecls for VcdWriterDecls<W> {
&mut writer, &mut writer,
ArgModule { ArgModule {
properties: &mut properties, properties: &mut properties,
scope: &mut Scope::default(),
}, },
)?; )?;
writeln!(writer, "$enddefinitions $end")?; writeln!(writer, "$enddefinitions $end")?;
@ -960,7 +798,9 @@ fn write_string_value_change(
value: impl fmt::Display, value: impl fmt::Display,
id: usize, id: usize,
) -> io::Result<()> { ) -> io::Result<()> {
write!(writer, "s{} ", Escaped(value))?; writer.write_all(b"s")?;
write_escaped(writer, value)?;
writer.write_all(b" ")?;
write_vcd_id(writer, id)?; write_vcd_id(writer, id)?;
writer.write_all(b"\n") writer.write_all(b"\n")
} }
@ -1090,14 +930,6 @@ impl<W: io::Write> TraceWriter for VcdWriter<W> {
) -> Result<(), Self::Error> { ) -> Result<(), Self::Error> {
write_enum_discriminant_value_change(&mut self.writer, variant_index, ty, id.as_usize()) write_enum_discriminant_value_change(&mut self.writer, variant_index, ty, id.as_usize())
} }
fn set_signal_sim_only_value(
&mut self,
id: TraceScalarId,
value: &DynSimOnlyValue,
) -> Result<(), Self::Error> {
write_string_value_change(&mut self.writer, format_args!("{value:?}"), id.as_usize())
}
} }
impl<W: io::Write> fmt::Debug for VcdWriter<W> { impl<W: io::Write> fmt::Debug for VcdWriter<W> {
@ -1114,49 +946,3 @@ impl<W: io::Write> fmt::Debug for VcdWriter<W> {
.finish_non_exhaustive() .finish_non_exhaustive()
} }
} }
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_scope() {
let mut scope = Scope::default();
assert_eq!(&*scope.new_identifier("foo".intern()).unescaped_name, "foo");
assert_eq!(
&*scope.new_identifier("foo_0".intern()).unescaped_name,
"foo_0"
);
assert_eq!(
&*scope.new_identifier("foo_1".intern()).unescaped_name,
"foo_1"
);
assert_eq!(
&*scope.new_identifier("foo_3".intern()).unescaped_name,
"foo_3"
);
assert_eq!(
&*scope.new_identifier("foo".intern()).unescaped_name,
"foo_2"
);
assert_eq!(
&*scope.new_identifier("foo".intern()).unescaped_name,
"foo_4"
);
assert_eq!(
&*scope.new_identifier("foo_0".intern()).unescaped_name,
"foo_0_2"
);
assert_eq!(
&*scope.new_identifier("foo_1".intern()).unescaped_name,
"foo_1_2"
);
for i in 5..1000u64 {
// verify it actually picks the next available identifier with no skips or duplicates
assert_eq!(
*scope.new_identifier("foo".intern()).unescaped_name,
format!("foo_{i}"),
);
}
}
}

View file

@ -2,8 +2,9 @@
// See Notices.txt for copyright information // See Notices.txt for copyright information
use crate::{ use crate::{
intern::{Intern, Interned}, intern::{Intern, Interned},
util::{DebugAsDisplay, HashMap}, util::DebugAsDisplay,
}; };
use hashbrown::HashMap;
use std::{cell::RefCell, fmt, num::NonZeroUsize, panic, path::Path}; use std::{cell::RefCell, fmt, num::NonZeroUsize, panic, path::Path};
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
@ -96,7 +97,7 @@ impl NormalizeFilesForTestsState {
fn new() -> Self { fn new() -> Self {
Self { Self {
test_position: panic::Location::caller(), test_position: panic::Location::caller(),
file_pattern_matches: HashMap::default(), file_pattern_matches: HashMap::new(),
} }
} }
} }
@ -142,7 +143,7 @@ impl From<&'_ panic::Location<'_>> for SourceLocation {
map.entry_ref(file) map.entry_ref(file)
.or_insert_with(|| NormalizedFileForTestState { .or_insert_with(|| NormalizedFileForTestState {
file_name_id: NonZeroUsize::new(len + 1).unwrap(), file_name_id: NonZeroUsize::new(len + 1).unwrap(),
positions_map: HashMap::default(), positions_map: HashMap::new(),
}); });
file_str = m.generate_file_name(file_state.file_name_id); file_str = m.generate_file_name(file_state.file_name_id);
file = &file_str; file = &file_str;

View file

@ -3,9 +3,9 @@
use crate::{ use crate::{
cli::{FormalArgs, FormalMode, FormalOutput, RunPhase}, cli::{FormalArgs, FormalMode, FormalOutput, RunPhase},
firrtl::ExportOptions, firrtl::ExportOptions,
util::HashMap,
}; };
use clap::Parser; use clap::Parser;
use hashbrown::HashMap;
use serde::Deserialize; use serde::Deserialize;
use std::{ use std::{
fmt::Write, fmt::Write,
@ -87,7 +87,7 @@ fn get_assert_formal_target_path(test_name: &dyn std::fmt::Display) -> PathBuf {
let index = *DIRS let index = *DIRS
.lock() .lock()
.unwrap() .unwrap()
.get_or_insert_with(HashMap::default) .get_or_insert_with(HashMap::new)
.entry_ref(&dir) .entry_ref(&dir)
.and_modify(|v| *v += 1) .and_modify(|v| *v += 1)
.or_insert(0); .or_insert(0);

View file

@ -7,27 +7,12 @@ use crate::{
clock::Clock, clock::Clock,
enum_::Enum, enum_::Enum,
expr::Expr, expr::Expr,
int::{Bool, SInt, UInt, UIntValue}, int::{Bool, SInt, UInt},
intern::{Intern, Interned}, intern::{Intern, Interned},
phantom_const::PhantomConst,
reset::{AsyncReset, Reset, SyncReset}, reset::{AsyncReset, Reset, SyncReset},
sim::value::{DynSimOnlyValue, DynSimOnly, SimValue, ToSimValueWithType},
source_location::SourceLocation, source_location::SourceLocation,
util::{ConstUsize, slice_range, try_slice_range},
}; };
use bitvec::{slice::BitSlice, vec::BitVec}; use std::{fmt, hash::Hash, iter::FusedIterator, ops::Index};
use serde::{Deserialize, Deserializer, Serialize, Serializer, de::DeserializeOwned};
use std::{
fmt,
hash::Hash,
iter::{FusedIterator, Sum},
marker::PhantomData,
mem,
ops::{Add, AddAssign, Bound, Index, Mul, MulAssign, Range, Sub, SubAssign},
sync::Arc,
};
pub(crate) mod serde_impls;
#[derive(Copy, Clone, Hash, PartialEq, Eq, Debug)] #[derive(Copy, Clone, Hash, PartialEq, Eq, Debug)]
#[non_exhaustive] #[non_exhaustive]
@ -36,23 +21,6 @@ pub struct TypeProperties {
pub is_storable: bool, pub is_storable: bool,
pub is_castable_from_bits: bool, pub is_castable_from_bits: bool,
pub bit_width: usize, pub bit_width: usize,
pub sim_only_values_len: usize,
}
impl TypeProperties {
pub const fn size(self) -> OpaqueSimValueSize {
let Self {
is_passive: _,
is_storable: _,
is_castable_from_bits: _,
bit_width,
sim_only_values_len,
} = self;
OpaqueSimValueSize {
bit_width,
sim_only_values_len,
}
}
} }
#[derive(Copy, Clone, Hash, PartialEq, Eq)] #[derive(Copy, Clone, Hash, PartialEq, Eq)]
@ -67,8 +35,6 @@ pub enum CanonicalType {
SyncReset(SyncReset), SyncReset(SyncReset),
Reset(Reset), Reset(Reset),
Clock(Clock), Clock(Clock),
PhantomConst(PhantomConst),
DynSimOnly(DynSimOnly),
} }
impl fmt::Debug for CanonicalType { impl fmt::Debug for CanonicalType {
@ -84,30 +50,10 @@ impl fmt::Debug for CanonicalType {
Self::SyncReset(v) => v.fmt(f), Self::SyncReset(v) => v.fmt(f),
Self::Reset(v) => v.fmt(f), Self::Reset(v) => v.fmt(f),
Self::Clock(v) => v.fmt(f), Self::Clock(v) => v.fmt(f),
Self::PhantomConst(v) => v.fmt(f),
Self::DynSimOnly(v) => v.fmt(f),
} }
} }
} }
impl Serialize for CanonicalType {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serde_impls::SerdeCanonicalType::from(*self).serialize(serializer)
}
}
impl<'de> Deserialize<'de> for CanonicalType {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
Ok(serde_impls::SerdeCanonicalType::deserialize(deserializer)?.into())
}
}
impl CanonicalType { impl CanonicalType {
pub fn type_properties(self) -> TypeProperties { pub fn type_properties(self) -> TypeProperties {
match self { match self {
@ -121,8 +67,6 @@ impl CanonicalType {
CanonicalType::SyncReset(v) => v.type_properties(), CanonicalType::SyncReset(v) => v.type_properties(),
CanonicalType::Reset(v) => v.type_properties(), CanonicalType::Reset(v) => v.type_properties(),
CanonicalType::Clock(v) => v.type_properties(), CanonicalType::Clock(v) => v.type_properties(),
CanonicalType::PhantomConst(v) => v.type_properties(),
CanonicalType::DynSimOnly(v) => v.type_properties(),
} }
} }
pub fn is_passive(self) -> bool { pub fn is_passive(self) -> bool {
@ -137,12 +81,6 @@ impl CanonicalType {
pub fn bit_width(self) -> usize { pub fn bit_width(self) -> usize {
self.type_properties().bit_width self.type_properties().bit_width
} }
pub fn sim_only_values_len(self) -> usize {
self.type_properties().sim_only_values_len
}
pub fn size(self) -> OpaqueSimValueSize {
self.type_properties().size()
}
pub fn can_connect(self, rhs: Self) -> bool { pub fn can_connect(self, rhs: Self) -> bool {
match self { match self {
CanonicalType::UInt(lhs) => { CanonicalType::UInt(lhs) => {
@ -205,22 +143,7 @@ impl CanonicalType {
}; };
lhs.can_connect(rhs) lhs.can_connect(rhs)
} }
CanonicalType::PhantomConst(lhs) => {
let CanonicalType::PhantomConst(rhs) = rhs else {
return false;
};
lhs.can_connect(rhs)
} }
CanonicalType::DynSimOnly(lhs) => {
let CanonicalType::DynSimOnly(rhs) = rhs else {
return false;
};
lhs.can_connect(rhs)
}
}
}
pub(crate) fn as_serde_unexpected_str(self) -> &'static str {
serde_impls::SerdeCanonicalType::from(self).as_serde_unexpected_str()
} }
} }
@ -243,7 +166,7 @@ impl<T: 'static + Send + Sync> MatchVariantAndInactiveScope for MatchVariantWith
} }
pub trait FillInDefaultedGenerics { pub trait FillInDefaultedGenerics {
type Type; type Type: Type;
fn fill_in_defaulted_generics(self) -> Self::Type; fn fill_in_defaulted_generics(self) -> Self::Type;
} }
@ -255,22 +178,6 @@ impl<T: Type> FillInDefaultedGenerics for T {
} }
} }
impl FillInDefaultedGenerics for usize {
type Type = usize;
fn fill_in_defaulted_generics(self) -> Self::Type {
self
}
}
impl<const V: usize> FillInDefaultedGenerics for ConstUsize<V> {
type Type = ConstUsize<V>;
fn fill_in_defaulted_generics(self) -> Self::Type {
self
}
}
mod sealed { mod sealed {
pub trait TypeOrDefaultSealed {} pub trait TypeOrDefaultSealed {}
pub trait BaseTypeSealed {} pub trait BaseTypeSealed {}
@ -288,34 +195,6 @@ macro_rules! impl_base_type {
}; };
} }
macro_rules! impl_base_type_serde {
($name:ident, $expected:literal) => {
impl Serialize for $name {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
self.canonical().serialize(serializer)
}
}
impl<'de> Deserialize<'de> for $name {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
match CanonicalType::deserialize(deserializer)? {
CanonicalType::$name(retval) => Ok(retval),
ty => Err(serde::de::Error::invalid_value(
serde::de::Unexpected::Other(ty.as_serde_unexpected_str()),
&$expected,
)),
}
}
}
};
}
impl_base_type!(UInt); impl_base_type!(UInt);
impl_base_type!(SInt); impl_base_type!(SInt);
impl_base_type!(Bool); impl_base_type!(Bool);
@ -326,16 +205,6 @@ impl_base_type!(AsyncReset);
impl_base_type!(SyncReset); impl_base_type!(SyncReset);
impl_base_type!(Reset); impl_base_type!(Reset);
impl_base_type!(Clock); impl_base_type!(Clock);
impl_base_type!(PhantomConst);
impl_base_type!(DynSimOnly);
impl_base_type_serde!(Bool, "a Bool");
impl_base_type_serde!(Enum, "an Enum");
impl_base_type_serde!(Bundle, "a Bundle");
impl_base_type_serde!(AsyncReset, "an AsyncReset");
impl_base_type_serde!(SyncReset, "a SyncReset");
impl_base_type_serde!(Reset, "a Reset");
impl_base_type_serde!(Clock, "a Clock");
impl sealed::BaseTypeSealed for CanonicalType {} impl sealed::BaseTypeSealed for CanonicalType {}
@ -371,7 +240,6 @@ pub trait Type:
{ {
type BaseType: BaseType; type BaseType: BaseType;
type MaskType: Type<MaskType = Self::MaskType>; type MaskType: Type<MaskType = Self::MaskType>;
type SimValue: fmt::Debug + Clone + 'static + ToSimValueWithType<Self>;
type MatchVariant: 'static + Send + Sync; type MatchVariant: 'static + Send + Sync;
type MatchActiveScope; type MatchActiveScope;
type MatchVariantAndInactiveScope: MatchVariantAndInactiveScope< type MatchVariantAndInactiveScope: MatchVariantAndInactiveScope<
@ -389,30 +257,9 @@ pub trait Type:
fn canonical(&self) -> CanonicalType; fn canonical(&self) -> CanonicalType;
fn from_canonical(canonical_type: CanonicalType) -> Self; fn from_canonical(canonical_type: CanonicalType) -> Self;
fn source_location() -> SourceLocation; fn source_location() -> SourceLocation;
fn sim_value_from_opaque(&self, opaque: OpaqueSimValueSlice<'_>) -> Self::SimValue;
fn sim_value_clone_from_opaque(
&self,
value: &mut Self::SimValue,
opaque: OpaqueSimValueSlice<'_>,
);
fn sim_value_to_opaque<'w>(
&self,
value: &Self::SimValue,
writer: OpaqueSimValueWriter<'w>,
) -> OpaqueSimValueWritten<'w>;
} }
pub trait BaseType: pub trait BaseType: Type<BaseType = Self> + sealed::BaseTypeSealed + Into<CanonicalType> {}
Type<
BaseType = Self,
MaskType: Serialize + DeserializeOwned,
SimValue: Serialize + DeserializeOwned,
> + sealed::BaseTypeSealed
+ Into<CanonicalType>
+ Serialize
+ DeserializeOwned
{
}
macro_rules! impl_match_variant_as_self { macro_rules! impl_match_variant_as_self {
() => { () => {
@ -439,7 +286,6 @@ pub trait TypeWithDeref: Type {
impl Type for CanonicalType { impl Type for CanonicalType {
type BaseType = CanonicalType; type BaseType = CanonicalType;
type MaskType = CanonicalType; type MaskType = CanonicalType;
type SimValue = OpaqueSimValue;
impl_match_variant_as_self!(); impl_match_variant_as_self!();
fn mask_type(&self) -> Self::MaskType { fn mask_type(&self) -> Self::MaskType {
match self { match self {
@ -453,8 +299,6 @@ impl Type for CanonicalType {
CanonicalType::SyncReset(v) => v.mask_type().canonical(), CanonicalType::SyncReset(v) => v.mask_type().canonical(),
CanonicalType::Reset(v) => v.mask_type().canonical(), CanonicalType::Reset(v) => v.mask_type().canonical(),
CanonicalType::Clock(v) => v.mask_type().canonical(), CanonicalType::Clock(v) => v.mask_type().canonical(),
CanonicalType::PhantomConst(v) => v.mask_type().canonical(),
CanonicalType::DynSimOnly(v) => v.mask_type().canonical(),
} }
} }
fn canonical(&self) -> CanonicalType { fn canonical(&self) -> CanonicalType {
@ -466,636 +310,9 @@ impl Type for CanonicalType {
fn source_location() -> SourceLocation { fn source_location() -> SourceLocation {
SourceLocation::builtin() SourceLocation::builtin()
} }
fn sim_value_from_opaque(&self, opaque: OpaqueSimValueSlice<'_>) -> Self::SimValue {
assert_eq!(self.type_properties().size(), opaque.size());
opaque.to_owned()
}
fn sim_value_clone_from_opaque(
&self,
value: &mut Self::SimValue,
opaque: OpaqueSimValueSlice<'_>,
) {
assert_eq!(self.type_properties().size(), opaque.size());
assert_eq!(value.size(), opaque.size());
value.clone_from_slice(opaque);
}
fn sim_value_to_opaque<'w>(
&self,
value: &Self::SimValue,
writer: OpaqueSimValueWriter<'w>,
) -> OpaqueSimValueWritten<'w> {
assert_eq!(self.type_properties().size(), writer.size());
assert_eq!(value.size(), writer.size());
writer.fill_cloned_from_slice(value.as_slice())
}
} }
#[derive(Clone, PartialEq, Eq, Hash, Debug, Serialize, Deserialize, Default)] pub trait StaticType: Type {
#[non_exhaustive]
pub struct OpaqueSimValueSizeRange {
pub bit_width: Range<usize>,
pub sim_only_values_len: Range<usize>,
}
impl OpaqueSimValueSizeRange {
pub fn start(&self) -> OpaqueSimValueSize {
OpaqueSimValueSize {
bit_width: self.bit_width.start,
sim_only_values_len: self.sim_only_values_len.start,
}
}
pub fn end(&self) -> OpaqueSimValueSize {
OpaqueSimValueSize {
bit_width: self.bit_width.end,
sim_only_values_len: self.sim_only_values_len.end,
}
}
pub fn is_empty(&self) -> bool {
let Self {
bit_width,
sim_only_values_len,
} = self;
bit_width.is_empty() && sim_only_values_len.is_empty()
}
}
impl From<Range<OpaqueSimValueSize>> for OpaqueSimValueSizeRange {
fn from(value: Range<OpaqueSimValueSize>) -> Self {
Self {
bit_width: value.start.bit_width..value.end.bit_width,
sim_only_values_len: value.start.sim_only_values_len..value.end.sim_only_values_len,
}
}
}
impl From<OpaqueSimValueSizeRange> for Range<OpaqueSimValueSize> {
fn from(value: OpaqueSimValueSizeRange) -> Self {
value.start()..value.end()
}
}
pub trait OpaqueSimValueSizeRangeBounds {
fn start_bound(&self) -> Bound<OpaqueSimValueSize>;
fn end_bound(&self) -> Bound<OpaqueSimValueSize>;
}
impl OpaqueSimValueSizeRangeBounds for OpaqueSimValueSizeRange {
fn start_bound(&self) -> Bound<OpaqueSimValueSize> {
Bound::Included(self.start())
}
fn end_bound(&self) -> Bound<OpaqueSimValueSize> {
Bound::Excluded(self.end())
}
}
impl<T: ?Sized + std::ops::RangeBounds<OpaqueSimValueSize>> OpaqueSimValueSizeRangeBounds for T {
fn start_bound(&self) -> Bound<OpaqueSimValueSize> {
std::ops::RangeBounds::start_bound(self).cloned()
}
fn end_bound(&self) -> Bound<OpaqueSimValueSize> {
std::ops::RangeBounds::end_bound(self).cloned()
}
}
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Serialize, Deserialize, Default)]
#[non_exhaustive]
pub struct OpaqueSimValueSize {
pub bit_width: usize,
pub sim_only_values_len: usize,
}
impl OpaqueSimValueSize {
pub const fn from_bit_width(bit_width: usize) -> Self {
Self::from_bit_width_and_sim_only_values_len(bit_width, 0)
}
pub const fn from_bit_width_and_sim_only_values_len(
bit_width: usize,
sim_only_values_len: usize,
) -> Self {
Self {
bit_width,
sim_only_values_len,
}
}
pub const fn only_bit_width(self) -> Option<usize> {
if let Self {
bit_width,
sim_only_values_len: 0,
} = self
{
Some(bit_width)
} else {
None
}
}
pub const fn empty() -> Self {
Self {
bit_width: 0,
sim_only_values_len: 0,
}
}
pub const fn is_empty(self) -> bool {
let Self {
bit_width,
sim_only_values_len,
} = self;
bit_width == 0 && sim_only_values_len == 0
}
pub const fn checked_mul(self, factor: usize) -> Option<Self> {
let Some(bit_width) = self.bit_width.checked_mul(factor) else {
return None;
};
let Some(sim_only_values_len) = self.sim_only_values_len.checked_mul(factor) else {
return None;
};
Some(Self {
bit_width,
sim_only_values_len,
})
}
pub const fn checked_add(self, rhs: Self) -> Option<Self> {
let Some(bit_width) = self.bit_width.checked_add(rhs.bit_width) else {
return None;
};
let Some(sim_only_values_len) = self
.sim_only_values_len
.checked_add(rhs.sim_only_values_len)
else {
return None;
};
Some(Self {
bit_width,
sim_only_values_len,
})
}
pub const fn checked_sub(self, rhs: Self) -> Option<Self> {
let Some(bit_width) = self.bit_width.checked_sub(rhs.bit_width) else {
return None;
};
let Some(sim_only_values_len) = self
.sim_only_values_len
.checked_sub(rhs.sim_only_values_len)
else {
return None;
};
Some(Self {
bit_width,
sim_only_values_len,
})
}
pub fn try_slice_range<R: OpaqueSimValueSizeRangeBounds>(
self,
range: R,
) -> Option<OpaqueSimValueSizeRange> {
let start = range.start_bound();
let end = range.end_bound();
let bit_width = try_slice_range(
(start.map(|v| v.bit_width), end.map(|v| v.bit_width)),
self.bit_width,
)?;
let sim_only_values_len = try_slice_range(
(
start.map(|v| v.sim_only_values_len),
end.map(|v| v.sim_only_values_len),
),
self.sim_only_values_len,
)?;
Some(OpaqueSimValueSizeRange {
bit_width,
sim_only_values_len,
})
}
pub fn slice_range<R: OpaqueSimValueSizeRangeBounds>(
self,
range: R,
) -> OpaqueSimValueSizeRange {
self.try_slice_range(range).expect("range out of bounds")
}
}
impl Mul<usize> for OpaqueSimValueSize {
type Output = OpaqueSimValueSize;
fn mul(self, rhs: usize) -> Self::Output {
self.checked_mul(rhs).expect("multiplication overflowed")
}
}
impl Mul<OpaqueSimValueSize> for usize {
type Output = OpaqueSimValueSize;
fn mul(self, rhs: OpaqueSimValueSize) -> Self::Output {
rhs.checked_mul(self).expect("multiplication overflowed")
}
}
impl Add for OpaqueSimValueSize {
type Output = OpaqueSimValueSize;
fn add(self, rhs: OpaqueSimValueSize) -> Self::Output {
rhs.checked_add(self).expect("addition overflowed")
}
}
impl Sub for OpaqueSimValueSize {
type Output = OpaqueSimValueSize;
fn sub(self, rhs: OpaqueSimValueSize) -> Self::Output {
rhs.checked_sub(self).expect("subtraction underflowed")
}
}
impl MulAssign<usize> for OpaqueSimValueSize {
fn mul_assign(&mut self, rhs: usize) {
*self = *self * rhs;
}
}
impl AddAssign for OpaqueSimValueSize {
fn add_assign(&mut self, rhs: OpaqueSimValueSize) {
*self = *self + rhs;
}
}
impl SubAssign for OpaqueSimValueSize {
fn sub_assign(&mut self, rhs: OpaqueSimValueSize) {
*self = *self - rhs;
}
}
impl Sum for OpaqueSimValueSize {
fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
iter.fold(OpaqueSimValueSize::empty(), Add::add)
}
}
#[derive(Clone, PartialEq, Eq, Hash, Debug, Serialize, Deserialize)]
pub struct OpaqueSimValue {
bits: UIntValue,
#[serde(skip_serializing_if = "Vec::is_empty", default)]
sim_only_values: Vec<DynSimOnlyValue>,
}
impl OpaqueSimValue {
pub fn empty() -> Self {
Self {
bits: UIntValue::new(Default::default()),
sim_only_values: Vec::new(),
}
}
pub fn with_capacity(capacity: OpaqueSimValueSize) -> Self {
Self {
bits: UIntValue::new(Arc::new(BitVec::with_capacity(capacity.bit_width))),
sim_only_values: Vec::with_capacity(capacity.sim_only_values_len),
}
}
pub fn size(&self) -> OpaqueSimValueSize {
OpaqueSimValueSize {
bit_width: self.bits.width(),
sim_only_values_len: self.sim_only_values.len(),
}
}
pub fn is_empty(&self) -> bool {
self.size().is_empty()
}
pub fn bit_width(&self) -> usize {
self.bits.width()
}
pub fn bits(&self) -> &UIntValue {
&self.bits
}
pub fn bits_mut(&mut self) -> &mut UIntValue {
&mut self.bits
}
pub fn into_bits(self) -> UIntValue {
self.bits
}
pub fn from_bits(bits: UIntValue) -> Self {
Self {
bits,
sim_only_values: Vec::new(),
}
}
pub fn from_bitslice(v: &BitSlice) -> Self {
Self::from_bitslice_and_sim_only_values(v, Vec::new())
}
pub fn from_bitslice_and_sim_only_values(
bits: &BitSlice,
sim_only_values: Vec<DynSimOnlyValue>,
) -> Self {
Self {
bits: UIntValue::new(Arc::new(bits.to_bitvec())),
sim_only_values,
}
}
pub fn from_bits_and_sim_only_values(
bits: UIntValue,
sim_only_values: Vec<DynSimOnlyValue>,
) -> Self {
Self {
bits,
sim_only_values,
}
}
pub fn into_parts(self) -> (UIntValue, Vec<DynSimOnlyValue>) {
let Self {
bits,
sim_only_values,
} = self;
(bits, sim_only_values)
}
pub fn parts_mut(&mut self) -> (&mut UIntValue, &mut Vec<DynSimOnlyValue>) {
let Self {
bits,
sim_only_values,
} = self;
(bits, sim_only_values)
}
pub fn sim_only_values(&self) -> &[DynSimOnlyValue] {
&self.sim_only_values
}
pub fn sim_only_values_mut(&mut self) -> &mut Vec<DynSimOnlyValue> {
&mut self.sim_only_values
}
pub fn as_slice(&self) -> OpaqueSimValueSlice<'_> {
OpaqueSimValueSlice {
bits: self.bits.bits(),
sim_only_values: &self.sim_only_values,
}
}
pub fn slice<R: OpaqueSimValueSizeRangeBounds>(&self, range: R) -> OpaqueSimValueSlice<'_> {
self.as_slice().slice(range)
}
pub fn rewrite_with<F>(&mut self, target_size: OpaqueSimValueSize, f: F)
where
F: for<'b> FnOnce(OpaqueSimValueWriter<'b>) -> OpaqueSimValueWritten<'b>, // 'b is used as a brand
{
OpaqueSimValueWriter::rewrite_with(target_size, self, f);
}
pub fn clone_from_slice(&mut self, slice: OpaqueSimValueSlice<'_>) {
let OpaqueSimValueSlice {
bits,
sim_only_values,
} = slice;
self.bits.bits_mut().copy_from_bitslice(bits);
self.sim_only_values.clone_from_slice(sim_only_values);
}
pub fn extend_from_slice(&mut self, slice: OpaqueSimValueSlice<'_>) {
let OpaqueSimValueSlice {
bits,
sim_only_values,
} = slice;
self.bits.bitvec_mut().extend_from_bitslice(bits);
self.sim_only_values.extend_from_slice(sim_only_values);
}
}
impl<'a> Extend<OpaqueSimValueSlice<'a>> for OpaqueSimValue {
fn extend<T: IntoIterator<Item = OpaqueSimValueSlice<'a>>>(&mut self, iter: T) {
let Self {
bits,
sim_only_values,
} = self;
let bits = bits.bitvec_mut();
for slice in iter {
bits.extend_from_bitslice(slice.bits);
sim_only_values.extend_from_slice(slice.sim_only_values);
}
}
}
impl Extend<OpaqueSimValue> for OpaqueSimValue {
fn extend<T: IntoIterator<Item = OpaqueSimValue>>(&mut self, iter: T) {
let Self {
bits,
sim_only_values,
} = self;
let bits = bits.bitvec_mut();
for value in iter {
bits.extend_from_bitslice(value.bits().bits());
sim_only_values.extend_from_slice(value.sim_only_values());
}
}
}
impl<T: Type<SimValue = OpaqueSimValue>> ToSimValueWithType<T> for OpaqueSimValue {
fn to_sim_value_with_type(&self, ty: T) -> SimValue<T> {
SimValue::from_value(ty, self.clone())
}
fn into_sim_value_with_type(self, ty: T) -> SimValue<T> {
SimValue::from_value(ty, self)
}
}
#[derive(Copy, Clone, Debug)]
pub struct OpaqueSimValueSlice<'a> {
bits: &'a BitSlice,
sim_only_values: &'a [DynSimOnlyValue],
}
impl<'a> Default for OpaqueSimValueSlice<'a> {
fn default() -> Self {
Self::empty()
}
}
impl<'a> OpaqueSimValueSlice<'a> {
pub fn from_parts(bits: &'a BitSlice, sim_only_values: &'a [DynSimOnlyValue]) -> Self {
Self {
bits,
sim_only_values,
}
}
pub fn from_bitslice(bits: &'a BitSlice) -> Self {
Self::from_parts(bits, &[])
}
pub fn empty() -> Self {
Self {
bits: BitSlice::empty(),
sim_only_values: &[],
}
}
pub fn size(self) -> OpaqueSimValueSize {
OpaqueSimValueSize {
bit_width: self.bit_width(),
sim_only_values_len: self.sim_only_values_len(),
}
}
pub fn is_empty(self) -> bool {
self.size().is_empty()
}
pub fn bit_width(self) -> usize {
self.bits.len()
}
pub fn bits(self) -> &'a BitSlice {
self.bits
}
pub fn sim_only_values(self) -> &'a [DynSimOnlyValue] {
self.sim_only_values
}
pub fn sim_only_values_len(self) -> usize {
self.sim_only_values.len()
}
pub fn to_owned(self) -> OpaqueSimValue {
OpaqueSimValue::from_bitslice_and_sim_only_values(self.bits, self.sim_only_values.to_vec())
}
pub fn slice<R: OpaqueSimValueSizeRangeBounds>(self, range: R) -> OpaqueSimValueSlice<'a> {
let start = range.start_bound();
let end = range.end_bound();
let bits_range = slice_range(
(start.map(|v| v.bit_width), end.map(|v| v.bit_width)),
self.bit_width(),
);
let sim_only_values_range = slice_range(
(start.map(|v| v.bit_width), end.map(|v| v.bit_width)),
self.sim_only_values_len(),
);
Self {
bits: &self.bits[bits_range],
sim_only_values: &self.sim_only_values[sim_only_values_range],
}
}
pub fn split_at(self, index: OpaqueSimValueSize) -> (Self, Self) {
let bits = self.bits.split_at(index.bit_width);
let sim_only_values = self.sim_only_values.split_at(index.sim_only_values_len);
(
Self {
bits: bits.0,
sim_only_values: sim_only_values.0,
},
Self {
bits: bits.1,
sim_only_values: sim_only_values.1,
},
)
}
}
#[derive(Debug)]
pub struct OpaqueSimValueWriter<'a> {
bits: &'a mut BitSlice,
sim_only_values: &'a mut Vec<DynSimOnlyValue>,
sim_only_values_range: std::ops::Range<usize>,
}
#[derive(Debug)]
pub struct OpaqueSimValueWritten<'a> {
_phantom: PhantomData<&'a ()>,
}
impl<'a> OpaqueSimValueWriter<'a> {
pub fn sim_only_values_range(&self) -> std::ops::Range<usize> {
self.sim_only_values_range.clone()
}
pub fn rewrite_with<F>(target_size: OpaqueSimValueSize, value: &mut OpaqueSimValue, f: F)
where
F: for<'b> FnOnce(OpaqueSimValueWriter<'b>) -> OpaqueSimValueWritten<'b>, // 'b is used as a brand
{
let OpaqueSimValueWritten {
_phantom: PhantomData,
} = f(OpaqueSimValueWriter::rewrite_helper(target_size, value));
}
pub(crate) fn rewrite_helper(
target_size: OpaqueSimValueSize,
value: &'a mut OpaqueSimValue,
) -> Self {
let (bits, sim_only_values) = value.parts_mut();
let OpaqueSimValueSize {
bit_width,
sim_only_values_len,
} = target_size;
let bits = bits.bitvec_mut();
bits.resize(bit_width, false);
sim_only_values.truncate(sim_only_values_len);
sim_only_values.reserve_exact(sim_only_values_len - sim_only_values.len());
Self {
bits,
sim_only_values,
sim_only_values_range: 0..sim_only_values_len,
}
}
pub fn size(&self) -> OpaqueSimValueSize {
OpaqueSimValueSize {
bit_width: self.bit_width(),
sim_only_values_len: self.sim_only_values_len(),
}
}
pub fn bit_width(&self) -> usize {
self.bits.len()
}
pub fn sim_only_values_len(&self) -> usize {
self.sim_only_values_range.len()
}
pub fn is_empty(&self) -> bool {
self.size().is_empty()
}
pub fn fill_cloned_from_slice(
self,
slice: OpaqueSimValueSlice<'_>,
) -> OpaqueSimValueWritten<'a> {
assert_eq!(self.size(), slice.size());
let Self {
bits,
sim_only_values,
sim_only_values_range,
} = self;
bits.copy_from_bitslice(slice.bits);
let (clone_from_src, clone_src) = slice.sim_only_values.split_at(
(sim_only_values.len() - sim_only_values_range.start).min(slice.sim_only_values.len()),
);
sim_only_values[sim_only_values_range.start..][..clone_from_src.len()]
.clone_from_slice(clone_from_src);
sim_only_values.extend_from_slice(clone_src);
OpaqueSimValueWritten {
_phantom: PhantomData,
}
}
pub fn fill_with_bits_with<F: FnOnce(&mut BitSlice)>(self, f: F) -> OpaqueSimValueWritten<'a> {
assert!(self.size().only_bit_width().is_some());
let Self {
bits,
sim_only_values,
sim_only_values_range,
} = self;
f(bits);
assert_eq!(sim_only_values.len(), sim_only_values_range.end);
OpaqueSimValueWritten {
_phantom: PhantomData,
}
}
pub fn fill_with_zeros(self) -> OpaqueSimValueWritten<'a> {
assert!(
self.size().only_bit_width().is_some(),
"can't fill things other than bits with zeros",
);
self.fill_with_bits_with(|bits| bits.fill(false))
}
pub fn fill_prefix_with<F>(&mut self, prefix_size: OpaqueSimValueSize, f: F)
where
F: for<'b> FnOnce(OpaqueSimValueWriter<'b>) -> OpaqueSimValueWritten<'b>, // 'b is used as a brand
{
let OpaqueSimValueSize {
bit_width,
sim_only_values_len,
} = prefix_size;
assert!(bit_width <= self.bit_width());
assert!(sim_only_values_len <= self.sim_only_values_len());
let next_start = self.sim_only_values_range.start + sim_only_values_len;
let OpaqueSimValueWritten {
_phantom: PhantomData,
} = f(OpaqueSimValueWriter {
bits: &mut self.bits[..bit_width],
sim_only_values: self.sim_only_values,
sim_only_values_range: self.sim_only_values_range.start..next_start,
});
assert!(self.sim_only_values.len() >= next_start);
self.bits = &mut mem::take(&mut self.bits)[bit_width..];
self.sim_only_values_range.start = next_start;
}
}
pub trait StaticType: Type + Default {
const TYPE: Self; const TYPE: Self;
const MASK_TYPE: Self::MaskType; const MASK_TYPE: Self::MaskType;
const TYPE_PROPERTIES: TypeProperties; const TYPE_PROPERTIES: TypeProperties;

View file

@ -1,135 +0,0 @@
// SPDX-License-Identifier: LGPL-3.0-or-later
// See Notices.txt for copyright information
use crate::{
array::Array,
bundle::{Bundle, BundleType},
clock::Clock,
enum_::{Enum, EnumType},
int::{Bool, SInt, UInt},
intern::Interned,
phantom_const::{PhantomConstCanonicalValue, PhantomConstValue},
prelude::PhantomConst,
reset::{AsyncReset, Reset, SyncReset},
sim::value::DynSimOnly,
ty::{BaseType, CanonicalType},
};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
pub(crate) struct SerdePhantomConst<T>(pub T);
impl<T: ?Sized + PhantomConstValue> Serialize for SerdePhantomConst<Interned<T>> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
self.0.serialize(serializer)
}
}
impl<'de, T: ?Sized + PhantomConstValue> Deserialize<'de> for SerdePhantomConst<Interned<T>> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
T::deserialize_value(deserializer).map(Self)
}
}
#[derive(Serialize, Deserialize)]
#[serde(rename = "CanonicalType")]
pub(crate) enum SerdeCanonicalType<
ArrayElement = CanonicalType,
ThePhantomConst = SerdePhantomConst<Interned<PhantomConstCanonicalValue>>,
> {
UInt {
width: usize,
},
SInt {
width: usize,
},
Bool,
Array {
element: ArrayElement,
len: usize,
},
Enum {
variants: Interned<[crate::enum_::EnumVariant]>,
},
Bundle {
fields: Interned<[crate::bundle::BundleField]>,
},
AsyncReset,
SyncReset,
Reset,
Clock,
PhantomConst(ThePhantomConst),
DynSimOnly(DynSimOnly),
}
impl<ArrayElement, PhantomConstInner> SerdeCanonicalType<ArrayElement, PhantomConstInner> {
pub(crate) fn as_serde_unexpected_str(&self) -> &'static str {
match self {
Self::UInt { .. } => "a UInt",
Self::SInt { .. } => "a SInt",
Self::Bool => "a Bool",
Self::Array { .. } => "an Array",
Self::Enum { .. } => "an Enum",
Self::Bundle { .. } => "a Bundle",
Self::AsyncReset => "an AsyncReset",
Self::SyncReset => "a SyncReset",
Self::Reset => "a Reset",
Self::Clock => "a Clock",
Self::PhantomConst(_) => "a PhantomConst",
Self::DynSimOnly(_) => "a SimOnlyValue",
}
}
}
impl<T: BaseType> From<T> for SerdeCanonicalType {
fn from(ty: T) -> Self {
let ty: CanonicalType = ty.into();
match ty {
CanonicalType::UInt(ty) => Self::UInt { width: ty.width() },
CanonicalType::SInt(ty) => Self::SInt { width: ty.width() },
CanonicalType::Bool(Bool {}) => Self::Bool,
CanonicalType::Array(ty) => Self::Array {
element: ty.element(),
len: ty.len(),
},
CanonicalType::Enum(ty) => Self::Enum {
variants: ty.variants(),
},
CanonicalType::Bundle(ty) => Self::Bundle {
fields: ty.fields(),
},
CanonicalType::AsyncReset(AsyncReset {}) => Self::AsyncReset,
CanonicalType::SyncReset(SyncReset {}) => Self::SyncReset,
CanonicalType::Reset(Reset {}) => Self::Reset,
CanonicalType::Clock(Clock {}) => Self::Clock,
CanonicalType::PhantomConst(ty) => Self::PhantomConst(SerdePhantomConst(ty.get())),
CanonicalType::DynSimOnly(ty) => Self::DynSimOnly(ty),
}
}
}
impl From<SerdeCanonicalType> for CanonicalType {
fn from(ty: SerdeCanonicalType) -> Self {
match ty {
SerdeCanonicalType::UInt { width } => Self::UInt(UInt::new(width)),
SerdeCanonicalType::SInt { width } => Self::SInt(SInt::new(width)),
SerdeCanonicalType::Bool => Self::Bool(Bool),
SerdeCanonicalType::Array { element, len } => Self::Array(Array::new(element, len)),
SerdeCanonicalType::Enum { variants } => Self::Enum(Enum::new(variants)),
SerdeCanonicalType::Bundle { fields } => Self::Bundle(Bundle::new(fields)),
SerdeCanonicalType::AsyncReset => Self::AsyncReset(AsyncReset),
SerdeCanonicalType::SyncReset => Self::SyncReset(SyncReset),
SerdeCanonicalType::Reset => Self::Reset(Reset),
SerdeCanonicalType::Clock => Self::Clock(Clock),
SerdeCanonicalType::PhantomConst(value) => {
Self::PhantomConst(PhantomConst::new(value.0))
}
SerdeCanonicalType::DynSimOnly(value) => Self::DynSimOnly(value),
}
}
}

View file

@ -1,23 +1,12 @@
// 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(crate) mod alternating_cell;
mod const_bool; mod const_bool;
mod const_cmp; mod const_cmp;
mod const_usize; mod const_usize;
mod misc; mod misc;
mod scoped_ref; mod scoped_ref;
pub(crate) mod streaming_read_utf8; pub(crate) mod streaming_read_utf8;
mod test_hasher;
// allow easily switching the hasher crate-wide for testing
#[cfg(feature = "unstable-test-hasher")]
pub type DefaultBuildHasher = test_hasher::DefaultBuildHasher;
#[cfg(not(feature = "unstable-test-hasher"))]
pub(crate) type DefaultBuildHasher = hashbrown::DefaultHashBuilder;
pub(crate) type HashMap<K, V> = hashbrown::HashMap<K, V, DefaultBuildHasher>;
pub(crate) type HashSet<T> = hashbrown::HashSet<T, DefaultBuildHasher>;
#[doc(inline)] #[doc(inline)]
pub use const_bool::{ConstBool, ConstBoolDispatch, ConstBoolDispatchTag, GenericConstBool}; pub use const_bool::{ConstBool, ConstBoolDispatch, ConstBoolDispatchTag, GenericConstBool};
@ -33,13 +22,11 @@ pub use const_cmp::{
#[doc(inline)] #[doc(inline)]
pub use scoped_ref::ScopedRef; pub use scoped_ref::ScopedRef;
pub(crate) use misc::chain;
#[doc(inline)] #[doc(inline)]
pub use misc::{ pub use misc::{
BitSliceWriteWithBase, DebugAsDisplay, DebugAsRawString, MakeMutSlice, RcWriter, interned_bit, get_many_mut, interned_bit, iter_eq_by, BitSliceWriteWithBase, DebugAsDisplay,
iter_eq_by, slice_range, try_slice_range, DebugAsRawString, MakeMutSlice, RcWriter,
}; };
pub mod job_server; pub mod job_server;
pub mod prefix_sum;
pub mod ready_valid; pub mod ready_valid;

View file

@ -1,122 +0,0 @@
// SPDX-License-Identifier: LGPL-3.0-or-later
// See Notices.txt for copyright information
use crate::util::DebugAsDisplay;
use std::{
cell::{Cell, UnsafeCell},
fmt,
};
pub(crate) trait AlternatingCellMethods {
fn unique_to_shared(&mut self);
fn shared_to_unique(&mut self);
}
#[derive(Copy, Clone, Debug)]
enum State {
Unique,
Shared,
Locked,
}
pub(crate) struct AlternatingCell<T: ?Sized> {
state: Cell<State>,
value: UnsafeCell<T>,
}
impl<T: ?Sized + fmt::Debug + AlternatingCellMethods> fmt::Debug for AlternatingCell<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("AlternatingCell")
.field(
self.try_share()
.as_ref()
.map(|v| -> &dyn fmt::Debug { v })
.unwrap_or(&DebugAsDisplay("<...>")),
)
.finish()
}
}
impl<T: ?Sized> AlternatingCell<T> {
pub(crate) const fn new_shared(value: T) -> Self
where
T: Sized,
{
Self {
state: Cell::new(State::Shared),
value: UnsafeCell::new(value),
}
}
pub(crate) const fn new_unique(value: T) -> Self
where
T: Sized,
{
Self {
state: Cell::new(State::Unique),
value: UnsafeCell::new(value),
}
}
pub(crate) fn is_unique(&self) -> bool {
matches!(self.state.get(), State::Unique)
}
pub(crate) fn is_shared(&self) -> bool {
matches!(self.state.get(), State::Shared)
}
pub(crate) fn into_inner(self) -> T
where
T: Sized,
{
self.value.into_inner()
}
pub(crate) fn try_share(&self) -> Option<&T>
where
T: AlternatingCellMethods,
{
match self.state.get() {
State::Shared => {}
State::Unique => {
struct Locked<'a>(&'a Cell<State>);
impl Drop for Locked<'_> {
fn drop(&mut self) {
self.0.set(State::Shared);
}
}
self.state.set(State::Locked);
let lock = Locked(&self.state);
// Safety: state is Locked, so nothing else will
// access value while calling unique_to_shared.
unsafe { &mut *self.value.get() }.unique_to_shared();
drop(lock);
}
State::Locked => return None,
}
// Safety: state is Shared so nothing will create any mutable
// references until the returned reference's lifetime expires.
Some(unsafe { &*self.value.get() })
}
#[track_caller]
pub(crate) fn share(&self) -> &T
where
T: AlternatingCellMethods,
{
let Some(retval) = self.try_share() else {
panic!("`share` called recursively");
};
retval
}
pub(crate) fn unique(&mut self) -> &mut T
where
T: AlternatingCellMethods,
{
match self.state.get() {
State::Shared => {
self.state.set(State::Unique);
self.value.get_mut().shared_to_unique();
}
State::Unique => {}
State::Locked => unreachable!(),
}
self.value.get_mut()
}
}

View file

@ -1,9 +1,5 @@
// 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 serde::{
Deserialize, Deserializer, Serialize, Serializer,
de::{DeserializeOwned, Error, Unexpected},
};
use std::{fmt::Debug, hash::Hash, mem::ManuallyDrop, ptr}; use std::{fmt::Debug, hash::Hash, mem::ManuallyDrop, ptr};
mod sealed { mod sealed {
@ -13,17 +9,7 @@ mod sealed {
/// # Safety /// # Safety
/// the only implementation is `ConstBool<Self::VALUE>` /// the only implementation is `ConstBool<Self::VALUE>`
pub unsafe trait GenericConstBool: pub unsafe trait GenericConstBool:
sealed::Sealed sealed::Sealed + Copy + Ord + Hash + Default + Debug + 'static + Send + Sync
+ Copy
+ Ord
+ Hash
+ Default
+ Debug
+ 'static
+ Send
+ Sync
+ Serialize
+ DeserializeOwned
{ {
const VALUE: bool; const VALUE: bool;
} }
@ -44,32 +30,6 @@ unsafe impl<const VALUE: bool> GenericConstBool for ConstBool<VALUE> {
const VALUE: bool = VALUE; const VALUE: bool = VALUE;
} }
impl<const VALUE: bool> Serialize for ConstBool<VALUE> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
VALUE.serialize(serializer)
}
}
impl<'de, const VALUE: bool> Deserialize<'de> for ConstBool<VALUE> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let value = bool::deserialize(deserializer)?;
if value == VALUE {
Ok(ConstBool)
} else {
Err(D::Error::invalid_value(
Unexpected::Bool(value),
&if VALUE { "true" } else { "false" },
))
}
}
}
pub trait ConstBoolDispatchTag { pub trait ConstBoolDispatchTag {
type Type<Select: GenericConstBool>; type Type<Select: GenericConstBool>;
} }

View file

@ -1,9 +1,5 @@
// 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 serde::{
Deserialize, Deserializer, Serialize, Serializer,
de::{DeserializeOwned, Error, Unexpected},
};
use std::{fmt::Debug, hash::Hash}; use std::{fmt::Debug, hash::Hash};
mod sealed { mod sealed {
@ -12,17 +8,7 @@ mod sealed {
/// the only implementation is `ConstUsize<Self::VALUE>` /// the only implementation is `ConstUsize<Self::VALUE>`
pub trait GenericConstUsize: pub trait GenericConstUsize:
sealed::Sealed sealed::Sealed + Copy + Ord + Hash + Default + Debug + 'static + Send + Sync
+ Copy
+ Ord
+ Hash
+ Default
+ Debug
+ 'static
+ Send
+ Sync
+ Serialize
+ DeserializeOwned
{ {
const VALUE: usize; const VALUE: usize;
} }
@ -41,29 +27,3 @@ impl<const VALUE: usize> sealed::Sealed for ConstUsize<VALUE> {}
impl<const VALUE: usize> GenericConstUsize for ConstUsize<VALUE> { impl<const VALUE: usize> GenericConstUsize for ConstUsize<VALUE> {
const VALUE: usize = VALUE; const VALUE: usize = VALUE;
} }
impl<const VALUE: usize> Serialize for ConstUsize<VALUE> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
VALUE.serialize(serializer)
}
}
impl<'de, const VALUE: usize> Deserialize<'de> for ConstUsize<VALUE> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let value = usize::deserialize(deserializer)?;
if value == VALUE {
Ok(ConstUsize)
} else {
Err(D::Error::invalid_value(
Unexpected::Unsigned(value as u64),
&&*VALUE.to_string(),
))
}
}
}

View file

@ -5,7 +5,6 @@ use bitvec::{bits, order::Lsb0, slice::BitSlice, view::BitView};
use std::{ use std::{
cell::Cell, cell::Cell,
fmt::{self, Debug, Write}, fmt::{self, Debug, Write},
ops::{Bound, Range, RangeBounds},
rc::Rc, rc::Rc,
sync::{Arc, OnceLock}, sync::{Arc, OnceLock},
}; };
@ -164,6 +163,22 @@ impl fmt::UpperHex for BitSliceWriteWithBase<'_> {
} }
} }
#[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)] #[derive(Clone, Default)]
pub struct RcWriter(Rc<Cell<Vec<u8>>>); pub struct RcWriter(Rc<Cell<Vec<u8>>>);
@ -210,36 +225,3 @@ impl std::io::Write for RcWriter {
Ok(()) Ok(())
} }
} }
macro_rules! chain {
() => {
std::iter::empty()
};
($first:expr $(, $rest:expr)* $(,)?) => {
{
let retval = IntoIterator::into_iter($first);
$(let retval = Iterator::chain(retval, $rest);)*
retval
}
};
}
pub(crate) use chain;
pub fn try_slice_range<R: RangeBounds<usize>>(range: R, size: usize) -> Option<Range<usize>> {
let start = match range.start_bound() {
Bound::Included(start) => *start,
Bound::Excluded(start) => start.checked_add(1)?,
Bound::Unbounded => 0,
};
let end = match range.end_bound() {
Bound::Included(end) => end.checked_add(1)?,
Bound::Excluded(end) => *end,
Bound::Unbounded => size,
};
(start <= end && end <= size).then_some(start..end)
}
pub fn slice_range<R: RangeBounds<usize>>(range: R, size: usize) -> Range<usize> {
try_slice_range(range, size).expect("range out of bounds")
}

View file

@ -1,839 +0,0 @@
// SPDX-License-Identifier: LGPL-3.0-or-later
// See Notices.txt for copyright information
// code derived from:
// https://web.archive.org/web/20250303054010/https://git.libre-soc.org/?p=nmutil.git;a=blob;f=src/nmutil/prefix_sum.py;hb=effeb28e5848392adddcdad1f6e7a098f2a44c9c
use crate::intern::{Intern, Interned, Memoize};
use std::{borrow::Cow, num::NonZeroUsize};
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub struct PrefixSumOp {
pub lhs_index: usize,
pub rhs_and_dest_index: NonZeroUsize,
pub row: u32,
}
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
#[non_exhaustive]
pub struct DiagramConfig {
pub space: Cow<'static, str>,
pub vertical_bar: Cow<'static, str>,
pub plus: Cow<'static, str>,
pub slant: Cow<'static, str>,
pub connect: Cow<'static, str>,
pub no_connect: Cow<'static, str>,
pub padding: usize,
}
impl DiagramConfig {
pub const fn new() -> Self {
Self {
space: Cow::Borrowed(" "),
vertical_bar: Cow::Borrowed("|"),
plus: Cow::Borrowed("\u{2295}"), // ⊕
slant: Cow::Borrowed(r"\"),
connect: Cow::Borrowed("\u{25CF}"), // ●
no_connect: Cow::Borrowed("X"),
padding: 1,
}
}
pub fn draw(self, ops: impl IntoIterator<Item = PrefixSumOp>, item_count: usize) -> String {
#[derive(Copy, Clone, Debug)]
struct DiagramCell {
slant: bool,
plus: bool,
tee: bool,
}
let mut ops_by_row: Vec<Vec<PrefixSumOp>> = Vec::new();
let mut last_row = 0;
ops.into_iter().for_each(|op| {
assert!(
op.lhs_index < op.rhs_and_dest_index.get(),
"invalid PrefixSumOp! lhs_index must be less \
than rhs_and_dest_index: {op:?}",
);
assert!(
op.row >= last_row,
"invalid PrefixSumOp! row must \
not decrease (row last was: {last_row}): {op:?}",
);
let ops = if op.row > last_row || ops_by_row.is_empty() {
ops_by_row.push(vec![]);
ops_by_row.last_mut().expect("just pushed")
} else {
ops_by_row
.last_mut()
.expect("just checked if ops_by_row is empty")
};
if let Some(last) = ops.last() {
assert!(
op.rhs_and_dest_index < last.rhs_and_dest_index,
"invalid PrefixSumOp! rhs_and_dest_index must strictly \
decrease in a row:\nthis op: {op:?}\nlast op: {last:?}",
);
}
ops.push(op);
last_row = op.row;
});
let blank_row = || {
vec![
DiagramCell {
slant: false,
plus: false,
tee: false
};
item_count
]
};
let mut cells = vec![blank_row()];
for ops in ops_by_row {
let max_distance = ops
.iter()
.map(
|&PrefixSumOp {
lhs_index,
rhs_and_dest_index,
..
}| { rhs_and_dest_index.get() - lhs_index },
)
.max()
.expect("ops is known to be non-empty");
cells.extend((0..max_distance).map(|_| blank_row()));
for op in ops {
let mut y = cells.len() - 1;
assert!(
op.rhs_and_dest_index.get() < item_count,
"invalid PrefixSumOp! rhs_and_dest_index must be \
less than item_count ({item_count}): {op:?}",
);
let mut x = op.rhs_and_dest_index.get();
cells[y][x].plus = true;
x -= 1;
y -= 1;
while op.lhs_index < x {
cells[y][x].slant = true;
x -= 1;
y -= 1;
}
cells[y][x].tee = true;
}
}
let mut retval = String::new();
let mut row_text = vec![String::new(); 2 * self.padding + 1];
for cells_row in cells {
for cell in cells_row {
// top padding
for y in 0..self.padding {
// top left padding
for x in 0..self.padding {
row_text[y] += if x == y && (cell.plus || cell.slant) {
&self.slant
} else {
&self.space
};
}
// top vertical bar
row_text[y] += &self.vertical_bar;
// top right padding
for _ in 0..self.padding {
row_text[y] += &self.space;
}
}
// center left padding
for _ in 0..self.padding {
row_text[self.padding] += &self.space;
}
// center
row_text[self.padding] += if cell.plus {
&self.plus
} else if cell.tee {
&self.connect
} else if cell.slant {
&self.no_connect
} else {
&self.vertical_bar
};
// center right padding
for _ in 0..self.padding {
row_text[self.padding] += &self.space;
}
let bottom_padding_start = self.padding + 1;
let bottom_padding_last = self.padding * 2;
// bottom padding
for y in bottom_padding_start..=bottom_padding_last {
// bottom left padding
for _ in 0..self.padding {
row_text[y] += &self.space;
}
// bottom vertical bar
row_text[y] += &self.vertical_bar;
// bottom right padding
for x in bottom_padding_start..=bottom_padding_last {
row_text[y] += if x == y && (cell.tee || cell.slant) {
&self.slant
} else {
&self.space
};
}
}
}
for line in &mut row_text {
retval += line.trim_end();
retval += "\n";
line.clear();
}
}
retval
}
}
impl Default for DiagramConfig {
fn default() -> Self {
Self::new()
}
}
impl PrefixSumOp {
pub fn diagram(ops: impl IntoIterator<Item = Self>, item_count: usize) -> String {
Self::diagram_with_config(ops, item_count, DiagramConfig::new())
}
pub fn diagram_with_config(
ops: impl IntoIterator<Item = Self>,
item_count: usize,
config: DiagramConfig,
) -> String {
config.draw(ops, item_count)
}
}
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub enum PrefixSumAlgorithm {
/// Uses the algorithm from:
/// <https://en.wikipedia.org/wiki/Prefix_sum#Algorithm_1:_Shorter_span,_more_parallel>
LowLatency,
/// Uses the algorithm from:
/// <https://en.wikipedia.org/wiki/Prefix_sum#Algorithm_2:_Work-efficient>
WorkEfficient,
}
impl PrefixSumAlgorithm {
fn ops_impl(self, item_count: usize) -> Vec<PrefixSumOp> {
let mut retval = Vec::new();
let mut distance = 1;
let mut row = 0;
while distance < item_count {
let double_distance = distance
.checked_mul(2)
.expect("prefix-sum item_count is too big");
let (start, step) = match self {
Self::LowLatency => (distance, 1),
Self::WorkEfficient => (double_distance - 1, double_distance),
};
for rhs_and_dest_index in (start..item_count).step_by(step).rev() {
let Some(rhs_and_dest_index) = NonZeroUsize::new(rhs_and_dest_index) else {
unreachable!();
};
let lhs_index = rhs_and_dest_index.get() - distance;
retval.push(PrefixSumOp {
lhs_index,
rhs_and_dest_index,
row,
});
}
distance = double_distance;
row += 1;
}
match self {
Self::LowLatency => {}
Self::WorkEfficient => {
distance /= 2;
while distance >= 1 {
let start = distance
.checked_mul(3)
.expect("prefix-sum item_count is too big")
- 1;
for rhs_and_dest_index in (start..item_count).step_by(distance * 2).rev() {
let Some(rhs_and_dest_index) = NonZeroUsize::new(rhs_and_dest_index) else {
unreachable!();
};
let lhs_index = rhs_and_dest_index.get() - distance;
retval.push(PrefixSumOp {
lhs_index,
rhs_and_dest_index,
row,
});
}
row += 1;
distance /= 2;
}
}
}
retval
}
pub fn ops(self, item_count: usize) -> Interned<[PrefixSumOp]> {
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
struct MyMemoize(PrefixSumAlgorithm);
impl Memoize for MyMemoize {
type Input = usize;
type InputOwned = usize;
type Output = Interned<[PrefixSumOp]>;
fn inner(self, item_count: &Self::Input) -> Self::Output {
Intern::intern_owned(self.0.ops_impl(*item_count))
}
}
MyMemoize(self).get_owned(item_count)
}
pub fn run<T>(self, items: impl IntoIterator<Item = T>, f: impl FnMut(&T, &T) -> T) -> Vec<T> {
let mut items = Vec::from_iter(items);
self.run_on_slice(&mut items, f);
items
}
pub fn run_on_slice<T>(self, items: &mut [T], mut f: impl FnMut(&T, &T) -> T) -> &mut [T] {
self.ops(items.len()).into_iter().for_each(
|PrefixSumOp {
lhs_index,
rhs_and_dest_index,
row: _,
}| {
items[rhs_and_dest_index.get()] =
f(&items[lhs_index], &items[rhs_and_dest_index.get()]);
},
);
items
}
pub fn filtered_ops(
self,
item_live_out_flags: impl IntoIterator<Item = bool>,
) -> Vec<PrefixSumOp> {
let mut item_live_out_flags = Vec::from_iter(item_live_out_flags);
let prefix_sum_ops = self.ops(item_live_out_flags.len());
let mut ops_live_flags = vec![false; prefix_sum_ops.len()];
for (
op_index,
&PrefixSumOp {
lhs_index,
rhs_and_dest_index,
row: _,
},
) in prefix_sum_ops.iter().enumerate().rev()
{
let live = item_live_out_flags[rhs_and_dest_index.get()];
item_live_out_flags[lhs_index] |= live;
ops_live_flags[op_index] = live;
}
prefix_sum_ops
.into_iter()
.zip(ops_live_flags)
.filter_map(|(op, live)| live.then_some(op))
.collect()
}
pub fn reduce_ops(self, item_count: usize) -> Interned<[PrefixSumOp]> {
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
struct MyMemoize(PrefixSumAlgorithm);
impl Memoize for MyMemoize {
type Input = usize;
type InputOwned = usize;
type Output = Interned<[PrefixSumOp]>;
fn inner(self, item_count: &Self::Input) -> Self::Output {
let mut item_live_out_flags = vec![false; *item_count];
let Some(last_item_live_out_flag) = item_live_out_flags.last_mut() else {
return Interned::default();
};
*last_item_live_out_flag = true;
Intern::intern_owned(self.0.filtered_ops(item_live_out_flags))
}
}
MyMemoize(self).get_owned(item_count)
}
}
pub fn reduce_ops(item_count: usize) -> Interned<[PrefixSumOp]> {
PrefixSumAlgorithm::LowLatency.reduce_ops(item_count)
}
pub fn reduce<T>(items: impl IntoIterator<Item = T>, mut f: impl FnMut(T, T) -> T) -> Option<T> {
let mut items: Vec<_> = items.into_iter().map(Some).collect();
for op in reduce_ops(items.len()) {
let (Some(lhs), Some(rhs)) = (
items[op.lhs_index].take(),
items[op.rhs_and_dest_index.get()].take(),
) else {
unreachable!();
};
items[op.rhs_and_dest_index.get()] = Some(f(lhs, rhs));
}
items.last_mut().and_then(Option::take)
}
#[cfg(test)]
mod tests {
use super::*;
fn input_strings() -> [String; 9] {
std::array::from_fn(|i| String::from_utf8(vec![b'a' + i as u8]).unwrap())
}
#[test]
fn test_prefix_sum_strings() {
let input = input_strings();
let expected: Vec<String> = input
.iter()
.scan(String::new(), |l, r| {
*l += r;
Some(l.clone())
})
.collect();
println!("expected: {expected:?}");
assert_eq!(
*PrefixSumAlgorithm::WorkEfficient
.run_on_slice(&mut input.clone(), |l, r| l.to_string() + r),
*expected
);
assert_eq!(
*PrefixSumAlgorithm::LowLatency
.run_on_slice(&mut input.clone(), |l, r| l.to_string() + r),
*expected
);
}
#[test]
fn test_reduce_string() {
let input = input_strings();
let expected = input.clone().into_iter().reduce(|l, r| l + &r);
assert_eq!(reduce(input, |l, r| l + &r), expected);
}
fn op(lhs_index: usize, rhs_and_dest_index: usize, row: u32) -> PrefixSumOp {
PrefixSumOp {
lhs_index,
rhs_and_dest_index: NonZeroUsize::new(rhs_and_dest_index).expect("should be non-zero"),
row,
}
}
#[test]
fn test_reduce_ops_9() {
let expected = vec![
op(7, 8, 0),
op(5, 6, 0),
op(3, 4, 0),
op(1, 2, 0),
op(6, 8, 1),
op(2, 4, 1),
op(4, 8, 2),
op(0, 8, 3),
];
println!("expected: {expected:#?}");
let ops = reduce_ops(9);
println!("ops: {ops:#?}");
assert_eq!(*ops, *expected);
}
#[test]
fn test_reduce_ops_8() {
let expected = vec![
op(6, 7, 0),
op(4, 5, 0),
op(2, 3, 0),
op(0, 1, 0),
op(5, 7, 1),
op(1, 3, 1),
op(3, 7, 2),
];
println!("expected: {expected:#?}");
let ops = reduce_ops(8);
println!("ops: {ops:#?}");
assert_eq!(*ops, *expected);
}
#[test]
fn test_count_ones() {
for width in 0..=10u32 {
for v in 0..1u32 << width {
let expected = v.count_ones();
assert_eq!(
reduce((0..width).map(|i| (v >> i) & 1), |l, r| l + r).unwrap_or(0),
expected,
"v={v:#X}"
);
}
}
}
#[track_caller]
fn test_diagram(ops: impl IntoIterator<Item = PrefixSumOp>, item_count: usize, expected: &str) {
let text = PrefixSumOp::diagram_with_config(
ops,
item_count,
DiagramConfig {
plus: Cow::Borrowed("@"),
..Default::default()
},
);
println!("text:\n{text}\n");
assert_eq!(text, expected);
}
#[test]
fn test_work_efficient_diagram_16() {
let item_count = 16;
test_diagram(
PrefixSumAlgorithm::WorkEfficient.ops(item_count),
item_count,
&r"
| | | | | | | | | | | | | | | |
| | | | | | | |
|\ | |\ | |\ | |\ | |\ | |\ | |\ | |\ |
| \| | \| | \| | \| | \| | \| | \| | \|
| @ | @ | @ | @ | @ | @ | @ | @
| |\ | | | |\ | | | |\ | | | |\ | |
| | \| | | | \| | | | \| | | | \| |
| | X | | | X | | | X | | | X |
| | |\ | | | |\ | | | |\ | | | |\ |
| | | \| | | | \| | | | \| | | | \|
| | | @ | | | @ | | | @ | | | @
| | | |\ | | | | | | | |\ | | | |
| | | | \| | | | | | | | \| | | |
| | | | X | | | | | | | X | | |
| | | | |\ | | | | | | | |\ | | |
| | | | | \| | | | | | | | \| | |
| | | | | X | | | | | | | X | |
| | | | | |\ | | | | | | | |\ | |
| | | | | | \| | | | | | | | \| |
| | | | | | X | | | | | | | X |
| | | | | | |\ | | | | | | | |\ |
| | | | | | | \| | | | | | | | \|
| | | | | | | @ | | | | | | | @
| | | | | | | |\ | | | | | | | |
| | | | | | | | \| | | | | | | |
| | | | | | | | X | | | | | | |
| | | | | | | | |\ | | | | | | |
| | | | | | | | | \| | | | | | |
| | | | | | | | | X | | | | | |
| | | | | | | | | |\ | | | | | |
| | | | | | | | | | \| | | | | |
| | | | | | | | | | X | | | | |
| | | | | | | | | | |\ | | | | |
| | | | | | | | | | | \| | | | |
| | | | | | | | | | | X | | | |
| | | | | | | | | | | |\ | | | |
| | | | | | | | | | | | \| | | |
| | | | | | | | | | | | X | | |
| | | | | | | | | | | | |\ | | |
| | | | | | | | | | | | | \| | |
| | | | | | | | | | | | | X | |
| | | | | | | | | | | | | |\ | |
| | | | | | | | | | | | | | \| |
| | | | | | | | | | | | | | X |
| | | | | | | | | | | | | | |\ |
| | | | | | | | | | | | | | | \|
| | | | | | | | | | | | | | @
| | | | | | | |\ | | | | | | | |
| | | | | | | | \| | | | | | | |
| | | | | | | | X | | | | | | |
| | | | | | | | |\ | | | | | | |
| | | | | | | | | \| | | | | | |
| | | | | | | | | X | | | | | |
| | | | | | | | | |\ | | | | | |
| | | | | | | | | | \| | | | | |
| | | | | | | | | | X | | | | |
| | | | | | | | | | |\ | | | | |
| | | | | | | | | | | \| | | | |
| | | | | | | | | @ | | | |
| | | |\ | | | |\ | | | |\ | | | |
| | | | \| | | | \| | | | \| | | |
| | | | X | | | X | | | X | | |
| | | | |\ | | | |\ | | | |\ | | |
| | | | | \| | | | \| | | | \| | |
| | | @ | | @ | | @ | |
| |\ | |\ | |\ | |\ | |\ | |\ | |\ | |
| | \| | \| | \| | \| | \| | \| | \| |
| | @ | @ | @ | @ | @ | @ | @ |
| | | | | | | | | | | | | | | |
"[1..], // trim newline at start
);
}
#[test]
fn test_low_latency_diagram_16() {
let item_count = 16;
test_diagram(
PrefixSumAlgorithm::LowLatency.ops(item_count),
item_count,
&r"
| | | | | | | | | | | | | | | |
|
|\ |\ |\ |\ |\ |\ |\ |\ |\ |\ |\ |\ |\ |\ |\ |
| \| \| \| \| \| \| \| \| \| \| \| \| \| \| \|
@ @ @ @ @ @ @ @ @ @ @ @ @ @ @
|\ |\ |\ |\ |\ |\ |\ |\ |\ |\ |\ |\ |\ |\ | |
| \| \| \| \| \| \| \| \| \| \| \| \| \| \| |
| X X X X X X X X X X X X X X |
| |\ |\ |\ |\ |\ |\ |\ |\ |\ |\ |\ |\ |\ |\ |
| | \| \| \| \| \| \| \| \| \| \| \| \| \| \|
@ @ @ @ @ @ @ @ @ @ @ @ @ @
|\ |\ |\ |\ |\ |\ |\ |\ |\ |\ |\ |\ | | | |
| \| \| \| \| \| \| \| \| \| \| \| \| | | |
| X X X X X X X X X X X X | | |
| |\ |\ |\ |\ |\ |\ |\ |\ |\ |\ |\ |\ | | |
| | \| \| \| \| \| \| \| \| \| \| \| \| | |
| | X X X X X X X X X X X X | |
| | |\ |\ |\ |\ |\ |\ |\ |\ |\ |\ |\ |\ | |
| | | \| \| \| \| \| \| \| \| \| \| \| \| |
| | | X X X X X X X X X X X X |
| | | |\ |\ |\ |\ |\ |\ |\ |\ |\ |\ |\ |\ |
| | | | \| \| \| \| \| \| \| \| \| \| \| \|
@ @ @ @ @ @ @ @ @ @ @ @
|\ |\ |\ |\ |\ |\ |\ |\ | | | | | | | |
| \| \| \| \| \| \| \| \| | | | | | | |
| X X X X X X X X | | | | | | |
| |\ |\ |\ |\ |\ |\ |\ |\ | | | | | | |
| | \| \| \| \| \| \| \| \| | | | | | |
| | X X X X X X X X | | | | | |
| | |\ |\ |\ |\ |\ |\ |\ |\ | | | | | |
| | | \| \| \| \| \| \| \| \| | | | | |
| | | X X X X X X X X | | | | |
| | | |\ |\ |\ |\ |\ |\ |\ |\ | | | | |
| | | | \| \| \| \| \| \| \| \| | | | |
| | | | X X X X X X X X | | | |
| | | | |\ |\ |\ |\ |\ |\ |\ |\ | | | |
| | | | | \| \| \| \| \| \| \| \| | | |
| | | | | X X X X X X X X | | |
| | | | | |\ |\ |\ |\ |\ |\ |\ |\ | | |
| | | | | | \| \| \| \| \| \| \| \| | |
| | | | | | X X X X X X X X | |
| | | | | | |\ |\ |\ |\ |\ |\ |\ |\ | |
| | | | | | | \| \| \| \| \| \| \| \| |
| | | | | | | X X X X X X X X |
| | | | | | | |\ |\ |\ |\ |\ |\ |\ |\ |
| | | | | | | | \| \| \| \| \| \| \| \|
| | | | | | | | @ @ @ @ @ @ @ @
| | | | | | | | | | | | | | | |
"[1..], // trim newline at start
);
}
#[test]
fn test_work_efficient_diagram_9() {
let item_count = 9;
test_diagram(
PrefixSumAlgorithm::WorkEfficient.ops(item_count),
item_count,
&r"
| | | | | | | | |
| | | | |
|\ | |\ | |\ | |\ | |
| \| | \| | \| | \| |
| @ | @ | @ | @ |
| |\ | | | |\ | | |
| | \| | | | \| | |
| | X | | | X | |
| | |\ | | | |\ | |
| | | \| | | | \| |
| | | @ | | | @ |
| | | |\ | | | | |
| | | | \| | | | |
| | | | X | | | |
| | | | |\ | | | |
| | | | | \| | | |
| | | | | X | | |
| | | | | |\ | | |
| | | | | | \| | |
| | | | | | X | |
| | | | | | |\ | |
| | | | | | | \| |
| | | | | | @ |
| | | |\ | | | | |
| | | | \| | | | |
| | | | X | | | |
| | | | |\ | | | |
| | | | | \| | | |
| | | @ | |
| |\ | |\ | |\ | |\ |
| | \| | \| | \| | \|
| | @ | @ | @ | @
| | | | | | | | |
"[1..], // trim newline at start
);
}
#[test]
fn test_low_latency_diagram_9() {
let item_count = 9;
test_diagram(
PrefixSumAlgorithm::LowLatency.ops(item_count),
item_count,
&r"
| | | | | | | | |
|
|\ |\ |\ |\ |\ |\ |\ |\ |
| \| \| \| \| \| \| \| \|
@ @ @ @ @ @ @ @
|\ |\ |\ |\ |\ |\ |\ | |
| \| \| \| \| \| \| \| |
| X X X X X X X |
| |\ |\ |\ |\ |\ |\ |\ |
| | \| \| \| \| \| \| \|
@ @ @ @ @ @ @
|\ |\ |\ |\ |\ | | | |
| \| \| \| \| \| | | |
| X X X X X | | |
| |\ |\ |\ |\ |\ | | |
| | \| \| \| \| \| | |
| | X X X X X | |
| | |\ |\ |\ |\ |\ | |
| | | \| \| \| \| \| |
| | | X X X X X |
| | | |\ |\ |\ |\ |\ |
| | | | \| \| \| \| \|
| | | @ @ @ @ @
|\ | | | | | | | |
| \| | | | | | | |
| X | | | | | | |
| |\ | | | | | | |
| | \| | | | | | |
| | X | | | | | |
| | |\ | | | | | |
| | | \| | | | | |
| | | X | | | | |
| | | |\ | | | | |
| | | | \| | | | |
| | | | X | | | |
| | | | |\ | | | |
| | | | | \| | | |
| | | | | X | | |
| | | | | |\ | | |
| | | | | | \| | |
| | | | | | X | |
| | | | | | |\ | |
| | | | | | | \| |
| | | | | | | X |
| | | | | | | |\ |
| | | | | | | | \|
| | | | | | | | @
| | | | | | | | |
"[1..], // trim newline at start
);
}
#[test]
fn test_reduce_diagram_16() {
let item_count = 16;
test_diagram(
reduce_ops(item_count),
item_count,
&r"
| | | | | | | | | | | | | | | |
| | | | | | | |
|\ | |\ | |\ | |\ | |\ | |\ | |\ | |\ |
| \| | \| | \| | \| | \| | \| | \| | \|
| @ | @ | @ | @ | @ | @ | @ | @
| |\ | | | |\ | | | |\ | | | |\ | |
| | \| | | | \| | | | \| | | | \| |
| | X | | | X | | | X | | | X |
| | |\ | | | |\ | | | |\ | | | |\ |
| | | \| | | | \| | | | \| | | | \|
| | | @ | | | @ | | | @ | | | @
| | | |\ | | | | | | | |\ | | | |
| | | | \| | | | | | | | \| | | |
| | | | X | | | | | | | X | | |
| | | | |\ | | | | | | | |\ | | |
| | | | | \| | | | | | | | \| | |
| | | | | X | | | | | | | X | |
| | | | | |\ | | | | | | | |\ | |
| | | | | | \| | | | | | | | \| |
| | | | | | X | | | | | | | X |
| | | | | | |\ | | | | | | | |\ |
| | | | | | | \| | | | | | | | \|
| | | | | | | @ | | | | | | | @
| | | | | | | |\ | | | | | | | |
| | | | | | | | \| | | | | | | |
| | | | | | | | X | | | | | | |
| | | | | | | | |\ | | | | | | |
| | | | | | | | | \| | | | | | |
| | | | | | | | | X | | | | | |
| | | | | | | | | |\ | | | | | |
| | | | | | | | | | \| | | | | |
| | | | | | | | | | X | | | | |
| | | | | | | | | | |\ | | | | |
| | | | | | | | | | | \| | | | |
| | | | | | | | | | | X | | | |
| | | | | | | | | | | |\ | | | |
| | | | | | | | | | | | \| | | |
| | | | | | | | | | | | X | | |
| | | | | | | | | | | | |\ | | |
| | | | | | | | | | | | | \| | |
| | | | | | | | | | | | | X | |
| | | | | | | | | | | | | |\ | |
| | | | | | | | | | | | | | \| |
| | | | | | | | | | | | | | X |
| | | | | | | | | | | | | | |\ |
| | | | | | | | | | | | | | | \|
| | | | | | | | | | | | | | | @
| | | | | | | | | | | | | | | |
"[1..], // trim newline at start
);
}
#[test]
fn test_reduce_diagram_9() {
let item_count = 9;
test_diagram(
reduce_ops(item_count),
item_count,
&r"
| | | | | | | | |
| | | | |
| |\ | |\ | |\ | |\ |
| | \| | \| | \| | \|
| | @ | @ | @ | @
| | |\ | | | |\ | |
| | | \| | | | \| |
| | | X | | | X |
| | | |\ | | | |\ |
| | | | \| | | | \|
| | | | @ | | | @
| | | | |\ | | | |
| | | | | \| | | |
| | | | | X | | |
| | | | | |\ | | |
| | | | | | \| | |
| | | | | | X | |
| | | | | | |\ | |
| | | | | | | \| |
| | | | | | | X |
| | | | | | | |\ |
| | | | | | | | \|
| | | | | | | @
|\ | | | | | | | |
| \| | | | | | | |
| X | | | | | | |
| |\ | | | | | | |
| | \| | | | | | |
| | X | | | | | |
| | |\ | | | | | |
| | | \| | | | | |
| | | X | | | | |
| | | |\ | | | | |
| | | | \| | | | |
| | | | X | | | |
| | | | |\ | | | |
| | | | | \| | | |
| | | | | X | | |
| | | | | |\ | | |
| | | | | | \| | |
| | | | | | X | |
| | | | | | |\ | |
| | | | | | | \| |
| | | | | | | X |
| | | | | | | |\ |
| | | | | | | | \|
| | | | | | | | @
| | | | | | | | |
"[1..], // trim newline at start
);
}
}

View file

@ -1,240 +0,0 @@
// SPDX-License-Identifier: LGPL-3.0-or-later
// See Notices.txt for copyright information
#![cfg(feature = "unstable-test-hasher")]
use std::{
fmt::Write as _,
hash::{BuildHasher, Hash, Hasher},
io::Write as _,
marker::PhantomData,
sync::LazyLock,
};
type BoxDynHasher = Box<dyn Hasher + Send + Sync>;
type BoxDynBuildHasher = Box<dyn DynBuildHasherTrait + Send + Sync>;
type BoxDynMakeBuildHasher = Box<dyn Fn() -> BoxDynBuildHasher + Send + Sync>;
trait TryGetDynBuildHasher: Copy {
type Type;
fn try_get_make_build_hasher(self) -> Option<BoxDynMakeBuildHasher>;
}
impl<T> TryGetDynBuildHasher for PhantomData<T> {
type Type = T;
fn try_get_make_build_hasher(self) -> Option<BoxDynMakeBuildHasher> {
None
}
}
impl<T: Default + BuildHasher<Hasher: Send + Sync + 'static> + Send + Sync + 'static + Clone>
TryGetDynBuildHasher for &'_ PhantomData<T>
{
type Type = T;
fn try_get_make_build_hasher(self) -> Option<BoxDynMakeBuildHasher> {
Some(Box::new(|| Box::<DynBuildHasher<T>>::default()))
}
}
#[derive(Default, Clone)]
struct DynBuildHasher<T>(T);
trait DynBuildHasherTrait: BuildHasher<Hasher = BoxDynHasher> {
fn clone_dyn_build_hasher(&self) -> BoxDynBuildHasher;
}
impl<BH: BuildHasher<Hasher: Send + Sync + 'static>> BuildHasher for DynBuildHasher<BH> {
type Hasher = BoxDynHasher;
fn build_hasher(&self) -> Self::Hasher {
Box::new(self.0.build_hasher())
}
fn hash_one<T: Hash>(&self, x: T) -> u64 {
self.0.hash_one(x)
}
}
impl<BH> DynBuildHasherTrait for DynBuildHasher<BH>
where
Self: Clone + BuildHasher<Hasher = BoxDynHasher> + Send + Sync + 'static,
{
fn clone_dyn_build_hasher(&self) -> BoxDynBuildHasher {
Box::new(self.clone())
}
}
pub struct DefaultBuildHasher(BoxDynBuildHasher);
impl Clone for DefaultBuildHasher {
fn clone(&self) -> Self {
DefaultBuildHasher(self.0.clone_dyn_build_hasher())
}
}
const ENV_VAR_NAME: &'static str = "FAYALITE_TEST_HASHER";
struct EnvVarValue {
key: &'static str,
try_get_make_build_hasher: fn() -> Option<BoxDynMakeBuildHasher>,
description: &'static str,
}
macro_rules! env_var_value {
(
key: $key:literal,
build_hasher: $build_hasher:ty,
description: $description:literal,
) => {
EnvVarValue {
key: $key,
try_get_make_build_hasher: || {
// use rust method resolution to detect if $build_hasher is usable
// (e.g. hashbrown's hasher won't be usable without the right feature enabled)
(&PhantomData::<DynBuildHasher<$build_hasher>>).try_get_make_build_hasher()
},
description: $description,
}
};
}
#[derive(Default)]
struct AlwaysZeroHasher;
impl Hasher for AlwaysZeroHasher {
fn write(&mut self, _bytes: &[u8]) {}
fn finish(&self) -> u64 {
0
}
}
const ENV_VAR_VALUES: &'static [EnvVarValue] = &[
env_var_value! {
key: "std",
build_hasher: std::hash::RandomState,
description: "use std::hash::RandomState",
},
env_var_value! {
key: "hashbrown",
build_hasher: hashbrown::DefaultHashBuilder,
description: "use hashbrown's DefaultHashBuilder",
},
env_var_value! {
key: "always_zero",
build_hasher: std::hash::BuildHasherDefault<AlwaysZeroHasher>,
description: "use a hasher that always returns 0 for all hashes,\n \
this is useful for checking that PartialEq impls are correct",
},
];
fn report_bad_env_var(msg: impl std::fmt::Display) -> ! {
let mut msg = format!("{ENV_VAR_NAME}: {msg}\n");
for &EnvVarValue {
key,
try_get_make_build_hasher,
description,
} in ENV_VAR_VALUES
{
let availability = match try_get_make_build_hasher() {
Some(_) => "available",
None => "unavailable",
};
writeln!(msg, "{key}: ({availability})\n {description}").expect("can't fail");
}
std::io::stderr()
.write_all(msg.as_bytes())
.expect("should be able to write to stderr");
std::process::abort();
}
impl Default for DefaultBuildHasher {
fn default() -> Self {
static DEFAULT_FN: LazyLock<BoxDynMakeBuildHasher> = LazyLock::new(|| {
let var = std::env::var_os(ENV_VAR_NAME);
let var = var.as_deref().unwrap_or("std".as_ref());
for &EnvVarValue {
key,
try_get_make_build_hasher,
description: _,
} in ENV_VAR_VALUES
{
if var.as_encoded_bytes().eq_ignore_ascii_case(key.as_bytes()) {
return try_get_make_build_hasher().unwrap_or_else(|| {
report_bad_env_var(format_args!(
"unavailable hasher: {key} (is the appropriate feature enabled?)"
));
});
}
}
report_bad_env_var(format_args!("unrecognized hasher: {var:?}"));
});
Self(DEFAULT_FN())
}
}
pub struct DefaultHasher(BoxDynHasher);
impl BuildHasher for DefaultBuildHasher {
type Hasher = DefaultHasher;
fn build_hasher(&self) -> Self::Hasher {
DefaultHasher(self.0.build_hasher())
}
}
impl Hasher for DefaultHasher {
fn finish(&self) -> u64 {
self.0.finish()
}
fn write(&mut self, bytes: &[u8]) {
self.0.write(bytes)
}
fn write_u8(&mut self, i: u8) {
self.0.write_u8(i)
}
fn write_u16(&mut self, i: u16) {
self.0.write_u16(i)
}
fn write_u32(&mut self, i: u32) {
self.0.write_u32(i)
}
fn write_u64(&mut self, i: u64) {
self.0.write_u64(i)
}
fn write_u128(&mut self, i: u128) {
self.0.write_u128(i)
}
fn write_usize(&mut self, i: usize) {
self.0.write_usize(i)
}
fn write_i8(&mut self, i: i8) {
self.0.write_i8(i)
}
fn write_i16(&mut self, i: i16) {
self.0.write_i16(i)
}
fn write_i32(&mut self, i: i32) {
self.0.write_i32(i)
}
fn write_i64(&mut self, i: i64) {
self.0.write_i64(i)
}
fn write_i128(&mut self, i: i128) {
self.0.write_i128(i)
}
fn write_isize(&mut self, i: isize) {
self.0.write_isize(i)
}
}

View file

@ -4,17 +4,11 @@ use fayalite::{
bundle::BundleType, bundle::BundleType,
enum_::EnumType, enum_::EnumType,
int::{BoolOrIntType, IntType}, int::{BoolOrIntType, IntType},
phantom_const::PhantomConst,
prelude::*, prelude::*,
ty::StaticType, ty::StaticType,
}; };
use std::marker::PhantomData; use std::marker::PhantomData;
#[hdl(outline_generated)]
pub struct MyConstSize<V: Size> {
pub size: PhantomConst<UIntType<V>>,
}
#[hdl(outline_generated)] #[hdl(outline_generated)]
pub struct S<T, Len: Size, T2> { pub struct S<T, Len: Size, T2> {
pub a: T, pub a: T,

View file

@ -1,13 +1,8 @@
// 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 fayalite::{ use fayalite::{
assert_export_firrtl, assert_export_firrtl, firrtl::ExportOptions, intern::Intern,
firrtl::ExportOptions, module::transform::simplify_enums::SimplifyEnumsKind, prelude::*, reset::ResetType,
int::{UIntInRange, UIntInRangeInclusive},
intern::Intern,
module::transform::simplify_enums::SimplifyEnumsKind,
prelude::*,
reset::ResetType,
ty::StaticType, ty::StaticType,
}; };
use serde_json::json; use serde_json::json;
@ -196,14 +191,10 @@ 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 + UnknownTrait, T: StaticType,
ConstUsize<N>: KnownSize, ConstUsize<N>: KnownSize,
U: std::fmt::Display, U: std::fmt::Display,
{ {
@ -385,18 +376,18 @@ circuit check_written_inside_both_if_else:
}; };
} }
#[hdl(outline_generated, cmp_eq)] #[hdl(outline_generated)]
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, cmp_eq)] #[hdl(outline_generated)]
pub struct TestStruct2 { pub struct TestStruct2 {
pub v: UInt<8>, pub v: UInt<8>,
} }
#[hdl(outline_generated, cmp_eq)] #[hdl(outline_generated)]
pub struct TestStruct3 {} pub struct TestStruct3 {}
#[hdl_module(outline_generated)] #[hdl_module(outline_generated)]
@ -4354,280 +4345,3 @@ circuit check_cfgs:
", ",
}; };
} }
#[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]
",
};
}
#[hdl_module(outline_generated)]
pub fn check_uint_in_range() {
#[hdl]
let i_0_to_1: UIntInRange<0, 1> = m.input();
#[hdl]
let i_0_to_2: UIntInRange<0, 2> = m.input();
#[hdl]
let i_0_to_3: UIntInRange<0, 3> = m.input();
#[hdl]
let i_0_to_4: UIntInRange<0, 4> = m.input();
#[hdl]
let i_0_to_7: UIntInRange<0, 7> = m.input();
#[hdl]
let i_0_to_8: UIntInRange<0, 8> = m.input();
#[hdl]
let i_0_to_9: UIntInRange<0, 9> = m.input();
#[hdl]
let i_0_through_0: UIntInRangeInclusive<0, 0> = m.input();
#[hdl]
let i_0_through_1: UIntInRangeInclusive<0, 1> = m.input();
#[hdl]
let i_0_through_2: UIntInRangeInclusive<0, 2> = m.input();
#[hdl]
let i_0_through_3: UIntInRangeInclusive<0, 3> = m.input();
#[hdl]
let i_0_through_4: UIntInRangeInclusive<0, 4> = m.input();
#[hdl]
let i_0_through_7: UIntInRangeInclusive<0, 7> = m.input();
#[hdl]
let i_0_through_8: UIntInRangeInclusive<0, 8> = m.input();
#[hdl]
let i_0_through_9: UIntInRangeInclusive<0, 9> = m.input();
}
#[test]
fn test_uint_in_range() {
let _n = SourceLocation::normalize_files_for_tests();
let m = check_uint_in_range();
dbg!(m);
#[rustfmt::skip] // work around https://github.com/rust-lang/rustfmt/issues/6161
assert_export_firrtl! {
m =>
"/test/check_uint_in_range.fir": r"FIRRTL version 3.2.0
circuit check_uint_in_range:
type Ty0 = {value: UInt<0>, range: {}}
type Ty1 = {value: UInt<1>, range: {}}
type Ty2 = {value: UInt<2>, range: {}}
type Ty3 = {value: UInt<2>, range: {}}
type Ty4 = {value: UInt<3>, range: {}}
type Ty5 = {value: UInt<3>, range: {}}
type Ty6 = {value: UInt<4>, range: {}}
type Ty7 = {value: UInt<0>, range: {}}
type Ty8 = {value: UInt<1>, range: {}}
type Ty9 = {value: UInt<2>, range: {}}
type Ty10 = {value: UInt<2>, range: {}}
type Ty11 = {value: UInt<3>, range: {}}
type Ty12 = {value: UInt<3>, range: {}}
type Ty13 = {value: UInt<4>, range: {}}
type Ty14 = {value: UInt<4>, range: {}}
module check_uint_in_range: @[module-XXXXXXXXXX.rs 1:1]
input i_0_to_1: Ty0 @[module-XXXXXXXXXX.rs 2:1]
input i_0_to_2: Ty1 @[module-XXXXXXXXXX.rs 3:1]
input i_0_to_3: Ty2 @[module-XXXXXXXXXX.rs 4:1]
input i_0_to_4: Ty3 @[module-XXXXXXXXXX.rs 5:1]
input i_0_to_7: Ty4 @[module-XXXXXXXXXX.rs 6:1]
input i_0_to_8: Ty5 @[module-XXXXXXXXXX.rs 7:1]
input i_0_to_9: Ty6 @[module-XXXXXXXXXX.rs 8:1]
input i_0_through_0: Ty7 @[module-XXXXXXXXXX.rs 9:1]
input i_0_through_1: Ty8 @[module-XXXXXXXXXX.rs 10:1]
input i_0_through_2: Ty9 @[module-XXXXXXXXXX.rs 11:1]
input i_0_through_3: Ty10 @[module-XXXXXXXXXX.rs 12:1]
input i_0_through_4: Ty11 @[module-XXXXXXXXXX.rs 13:1]
input i_0_through_7: Ty12 @[module-XXXXXXXXXX.rs 14:1]
input i_0_through_8: Ty13 @[module-XXXXXXXXXX.rs 15:1]
input i_0_through_9: Ty14 @[module-XXXXXXXXXX.rs 16:1]
",
};
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,283 +0,0 @@
$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

View file

@ -1,183 +0,0 @@
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,
},
],
..
},
sim_only_slots: StatePartLayout<SimOnlySlots> {
len: 0,
debug_data: [],
layout_data: [],
..
},
},
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,
],
},
sim_only_slots: StatePart {
value: [],
},
},
io: Instance {
name: <simulator>::conditional_assignment_last,
instantiated: Module {
name: conditional_assignment_last,
..
},
},
main_module: SimulationModuleState {
base_targets: [
Instance {
name: <simulator>::conditional_assignment_last,
instantiated: Module {
name: conditional_assignment_last,
..
},
}.i,
],
uninitialized_ios: {},
io_targets: {
Instance {
name: <simulator>::conditional_assignment_last,
instantiated: Module {
name: conditional_assignment_last,
..
},
}.i,
},
did_initial_settle: true,
},
extern_modules: [],
state_ready_to_run: 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: [],
..
}

View file

@ -1,14 +0,0 @@
$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

View file

@ -22,12 +22,6 @@ Simulation {
], ],
.. ..
}, },
sim_only_slots: StatePartLayout<SimOnlySlots> {
len: 0,
debug_data: [],
layout_data: [],
..
},
}, },
memories: StatePartLayout<Memories> { memories: StatePartLayout<Memories> {
len: 0, len: 0,
@ -66,9 +60,6 @@ Simulation {
5, 5,
], ],
}, },
sim_only_slots: StatePart {
value: [],
},
}, },
io: Instance { io: Instance {
name: <simulator>::connect_const, name: <simulator>::connect_const,
@ -77,17 +68,7 @@ Simulation {
.. ..
}, },
}, },
main_module: SimulationModuleState { uninitialized_inputs: {},
base_targets: [
Instance {
name: <simulator>::connect_const,
instantiated: Module {
name: connect_const,
..
},
}.o,
],
uninitialized_ios: {},
io_targets: { io_targets: {
Instance { Instance {
name: <simulator>::connect_const, name: <simulator>::connect_const,
@ -95,12 +76,37 @@ Simulation {
name: connect_const, name: connect_const,
.. ..
}, },
}.o, }.o: CompiledValue {
layout: CompiledTypeLayout {
ty: UInt<8>,
layout: TypeLayout {
small_slots: StatePartLayout<SmallSlots> {
len: 0,
debug_data: [],
..
}, },
did_initial_settle: true, big_slots: StatePartLayout<BigSlots> {
len: 1,
debug_data: [
SlotDebugData {
name: "InstantiatedModule(connect_const: connect_const).connect_const::o",
ty: UInt<8>,
}, },
extern_modules: [], ],
state_ready_to_run: false, ..
},
},
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 { trace_decls: TraceModule {
name: "connect_const", name: "connect_const",
children: [ children: [

View file

@ -34,12 +34,6 @@ Simulation {
], ],
.. ..
}, },
sim_only_slots: StatePartLayout<SimOnlySlots> {
len: 0,
debug_data: [],
layout_data: [],
..
},
}, },
memories: StatePartLayout<Memories> { memories: StatePartLayout<Memories> {
len: 0, len: 0,
@ -95,9 +89,6 @@ Simulation {
1, 1,
], ],
}, },
sim_only_slots: StatePart {
value: [],
},
}, },
io: Instance { io: Instance {
name: <simulator>::connect_const_reset, name: <simulator>::connect_const_reset,
@ -106,24 +97,7 @@ Simulation {
.. ..
}, },
}, },
main_module: SimulationModuleState { uninitialized_inputs: {},
base_targets: [
Instance {
name: <simulator>::connect_const_reset,
instantiated: Module {
name: connect_const_reset,
..
},
}.reset_out,
Instance {
name: <simulator>::connect_const_reset,
instantiated: Module {
name: connect_const_reset,
..
},
}.bit_out,
],
uninitialized_ios: {},
io_targets: { io_targets: {
Instance { Instance {
name: <simulator>::connect_const_reset, name: <simulator>::connect_const_reset,
@ -131,19 +105,71 @@ Simulation {
name: connect_const_reset, name: connect_const_reset,
.. ..
}, },
}.bit_out, }.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 { Instance {
name: <simulator>::connect_const_reset, name: <simulator>::connect_const_reset,
instantiated: Module { instantiated: Module {
name: connect_const_reset, name: connect_const_reset,
.. ..
}, },
}.reset_out, }.reset_out: CompiledValue {
layout: CompiledTypeLayout {
ty: AsyncReset,
layout: TypeLayout {
small_slots: StatePartLayout<SmallSlots> {
len: 0,
debug_data: [],
..
}, },
did_initial_settle: true, big_slots: StatePartLayout<BigSlots> {
len: 1,
debug_data: [
SlotDebugData {
name: "InstantiatedModule(connect_const_reset: connect_const_reset).connect_const_reset::reset_out",
ty: AsyncReset,
}, },
extern_modules: [], ],
state_ready_to_run: false, ..
},
},
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 { trace_decls: TraceModule {
name: "connect_const_reset", name: "connect_const_reset",
children: [ children: [

View file

@ -71,12 +71,6 @@ Simulation {
], ],
.. ..
}, },
sim_only_slots: StatePartLayout<SimOnlySlots> {
len: 0,
debug_data: [],
layout_data: [],
..
},
}, },
memories: StatePartLayout<Memories> { memories: StatePartLayout<Memories> {
len: 0, len: 0,
@ -201,9 +195,6 @@ Simulation {
4, 4,
], ],
}, },
sim_only_slots: StatePart {
value: [],
},
}, },
io: Instance { io: Instance {
name: <simulator>::counter, name: <simulator>::counter,
@ -212,24 +203,7 @@ Simulation {
.. ..
}, },
}, },
main_module: SimulationModuleState { uninitialized_inputs: {},
base_targets: [
Instance {
name: <simulator>::counter,
instantiated: Module {
name: counter,
..
},
}.cd,
Instance {
name: <simulator>::counter,
instantiated: Module {
name: counter,
..
},
}.count,
],
uninitialized_ios: {},
io_targets: { io_targets: {
Instance { Instance {
name: <simulator>::counter, name: <simulator>::counter,
@ -237,33 +211,205 @@ Simulation {
name: counter, name: counter,
.. ..
}, },
}.cd, }.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 { Instance {
name: <simulator>::counter, name: <simulator>::counter,
instantiated: Module { instantiated: Module {
name: counter, name: counter,
.. ..
}, },
}.cd.clk, }.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 { Instance {
name: <simulator>::counter, name: <simulator>::counter,
instantiated: Module { instantiated: Module {
name: counter, name: counter,
.. ..
}, },
}.cd.rst, }.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 { Instance {
name: <simulator>::counter, name: <simulator>::counter,
instantiated: Module { instantiated: Module {
name: counter, name: counter,
.. ..
}, },
}.count, }.count: CompiledValue {
layout: CompiledTypeLayout {
ty: UInt<4>,
layout: TypeLayout {
small_slots: StatePartLayout<SmallSlots> {
len: 0,
debug_data: [],
..
}, },
did_initial_settle: true, big_slots: StatePartLayout<BigSlots> {
len: 1,
debug_data: [
SlotDebugData {
name: "InstantiatedModule(counter: counter).counter::count",
ty: UInt<4>,
}, },
extern_modules: [], ],
state_ready_to_run: false, ..
},
},
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 { trace_decls: TraceModule {
name: "counter", name: "counter",
children: [ children: [

View file

@ -67,12 +67,6 @@ Simulation {
], ],
.. ..
}, },
sim_only_slots: StatePartLayout<SimOnlySlots> {
len: 0,
debug_data: [],
layout_data: [],
..
},
}, },
memories: StatePartLayout<Memories> { memories: StatePartLayout<Memories> {
len: 0, len: 0,
@ -182,9 +176,6 @@ Simulation {
4, 4,
], ],
}, },
sim_only_slots: StatePart {
value: [],
},
}, },
io: Instance { io: Instance {
name: <simulator>::counter, name: <simulator>::counter,
@ -193,24 +184,7 @@ Simulation {
.. ..
}, },
}, },
main_module: SimulationModuleState { uninitialized_inputs: {},
base_targets: [
Instance {
name: <simulator>::counter,
instantiated: Module {
name: counter,
..
},
}.cd,
Instance {
name: <simulator>::counter,
instantiated: Module {
name: counter,
..
},
}.count,
],
uninitialized_ios: {},
io_targets: { io_targets: {
Instance { Instance {
name: <simulator>::counter, name: <simulator>::counter,
@ -218,33 +192,205 @@ Simulation {
name: counter, name: counter,
.. ..
}, },
}.cd, }.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 { Instance {
name: <simulator>::counter, name: <simulator>::counter,
instantiated: Module { instantiated: Module {
name: counter, name: counter,
.. ..
}, },
}.cd.clk, }.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 { Instance {
name: <simulator>::counter, name: <simulator>::counter,
instantiated: Module { instantiated: Module {
name: counter, name: counter,
.. ..
}, },
}.cd.rst, }.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 { Instance {
name: <simulator>::counter, name: <simulator>::counter,
instantiated: Module { instantiated: Module {
name: counter, name: counter,
.. ..
}, },
}.count, }.count: CompiledValue {
layout: CompiledTypeLayout {
ty: UInt<4>,
layout: TypeLayout {
small_slots: StatePartLayout<SmallSlots> {
len: 0,
debug_data: [],
..
}, },
did_initial_settle: true, big_slots: StatePartLayout<BigSlots> {
len: 1,
debug_data: [
SlotDebugData {
name: "InstantiatedModule(counter: counter).counter::count",
ty: UInt<4>,
}, },
extern_modules: [], ],
state_ready_to_run: false, ..
},
},
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 { trace_decls: TraceModule {
name: "counter", name: "counter",
children: [ children: [

View file

@ -1,166 +0,0 @@
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>,
},
],
..
},
sim_only_slots: StatePartLayout<SimOnlySlots> {
len: 0,
debug_data: [],
layout_data: [],
..
},
},
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,
],
},
sim_only_slots: StatePart {
value: [],
},
},
io: Instance {
name: <simulator>::duplicate_names,
instantiated: Module {
name: duplicate_names,
..
},
},
main_module: SimulationModuleState {
base_targets: [],
uninitialized_ios: {},
io_targets: {},
did_initial_settle: true,
},
extern_modules: [],
state_ready_to_run: 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: [],
..
}

View file

@ -1,11 +0,0 @@
$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

File diff suppressed because it is too large Load diff

View file

@ -16,25 +16,18 @@ $var wire 1 ) \0 $end
$var wire 1 * \1 $end $var wire 1 * \1 $end
$upscope $end $upscope $end
$upscope $end $upscope $end
$scope struct b2_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 $scope struct the_reg $end
$var string 1 . \$tag $end $var string 1 + \$tag $end
$scope struct B $end $scope struct B $end
$var reg 1 / \0 $end $var reg 1 , \0 $end
$var reg 1 0 \1 $end $var reg 1 - \1 $end
$upscope $end $upscope $end
$scope struct C $end $scope struct C $end
$scope struct a $end $scope struct a $end
$var reg 1 1 \[0] $end $var reg 1 . \[0] $end
$var reg 1 2 \[1] $end $var reg 1 / \[1] $end
$upscope $end $upscope $end
$var reg 2 3 b $end $var reg 2 0 b $end
$upscope $end $upscope $end
$upscope $end $upscope $end
$upscope $end $upscope $end
@ -50,15 +43,12 @@ b0 '
sHdlNone\x20(0) ( sHdlNone\x20(0) (
0) 0)
0* 0*
sHdlNone\x20(0) + sA\x20(0) +
0, 0,
0- 0-
sA\x20(0) . 0.
0/ 0/
00 b0 0
01
02
b0 3
$end $end
#1000000 #1000000
1! 1!
@ -76,8 +66,7 @@ b1 $
1! 1!
b1 & b1 &
sHdlSome\x20(1) ( sHdlSome\x20(1) (
sHdlSome\x20(1) + sB\x20(1) +
sB\x20(1) .
#6000000 #6000000
0# 0#
b0 $ b0 $
@ -96,10 +85,8 @@ b11 '
1* 1*
1, 1,
1- 1-
1.
1/ 1/
10
11
12
#10000000 #10000000
0! 0!
#11000000 #11000000
@ -114,11 +101,8 @@ b1111 '
sHdlNone\x20(0) ( sHdlNone\x20(0) (
0) 0)
0* 0*
sHdlNone\x20(0) + sC\x20(2) +
0, b11 0
0-
sC\x20(2) .
b11 3
#14000000 #14000000
0! 0!
#15000000 #15000000

View file

@ -1,253 +0,0 @@
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(extern_module: extern_module).extern_module::i",
ty: Bool,
},
SlotDebugData {
name: "InstantiatedModule(extern_module: extern_module).extern_module::o",
ty: Bool,
},
],
..
},
sim_only_slots: StatePartLayout<SimOnlySlots> {
len: 0,
debug_data: [],
layout_data: [],
..
},
},
memories: StatePartLayout<Memories> {
len: 0,
debug_data: [],
layout_data: [],
..
},
},
insns: [
// at: module-XXXXXXXXXX.rs:1:1
0: Return,
],
..
},
pc: 0,
memory_write_log: [],
memories: StatePart {
value: [],
},
small_slots: StatePart {
value: [],
},
big_slots: StatePart {
value: [
1,
1,
],
},
sim_only_slots: StatePart {
value: [],
},
},
io: Instance {
name: <simulator>::extern_module,
instantiated: Module {
name: extern_module,
..
},
},
main_module: SimulationModuleState {
base_targets: [
Instance {
name: <simulator>::extern_module,
instantiated: Module {
name: extern_module,
..
},
}.i,
Instance {
name: <simulator>::extern_module,
instantiated: Module {
name: extern_module,
..
},
}.o,
],
uninitialized_ios: {},
io_targets: {
Instance {
name: <simulator>::extern_module,
instantiated: Module {
name: extern_module,
..
},
}.i,
Instance {
name: <simulator>::extern_module,
instantiated: Module {
name: extern_module,
..
},
}.o,
},
did_initial_settle: true,
},
extern_modules: [
SimulationExternModuleState {
module_state: SimulationModuleState {
base_targets: [
ModuleIO {
name: extern_module::i,
is_input: true,
ty: Bool,
..
},
ModuleIO {
name: extern_module::o,
is_input: false,
ty: Bool,
..
},
],
uninitialized_ios: {},
io_targets: {
ModuleIO {
name: extern_module::i,
is_input: true,
ty: Bool,
..
},
ModuleIO {
name: extern_module::o,
is_input: false,
ty: Bool,
..
},
},
did_initial_settle: true,
},
sim: ExternModuleSimulation {
generator: SimGeneratorFn {
args: (
ModuleIO {
name: extern_module::i,
is_input: true,
ty: Bool,
..
},
ModuleIO {
name: extern_module::o,
is_input: false,
ty: Bool,
..
},
),
f: ...,
},
sim_io_to_generator_map: {
ModuleIO {
name: extern_module::i,
is_input: true,
ty: Bool,
..
}: ModuleIO {
name: extern_module::i,
is_input: true,
ty: Bool,
..
},
ModuleIO {
name: extern_module::o,
is_input: false,
ty: Bool,
..
}: ModuleIO {
name: extern_module::o,
is_input: false,
ty: Bool,
..
},
},
source_location: SourceLocation(
module-XXXXXXXXXX.rs:4:1,
),
},
running_generator: Some(
...,
),
wait_targets: {
Instant(
20.500000000000 μs,
),
},
},
],
state_ready_to_run: false,
trace_decls: TraceModule {
name: "extern_module",
children: [
TraceModuleIO {
name: "i",
child: TraceBool {
location: TraceScalarId(0),
name: "i",
flow: Source,
},
ty: Bool,
flow: Source,
},
TraceModuleIO {
name: "o",
child: TraceBool {
location: TraceScalarId(1),
name: "o",
flow: Sink,
},
ty: Bool,
flow: Sink,
},
],
},
traces: [
SimTrace {
id: TraceScalarId(0),
kind: BigBool {
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: 20 μs,
clocks_triggered: [],
..
}

View file

@ -1,51 +0,0 @@
$timescale 1 ps $end
$scope module extern_module $end
$var wire 1 ! i $end
$var wire 1 " o $end
$upscope $end
$enddefinitions $end
$dumpvars
0!
1"
$end
#500000
#1500000
0"
#2500000
1"
#3500000
0"
#4500000
1"
#5500000
0"
#6500000
1"
#7500000
0"
#8500000
1"
#9500000
0"
#10000000
1!
#10500000
#11500000
1"
#12500000
0"
#13500000
1"
#14500000
0"
#15500000
1"
#16500000
0"
#17500000
1"
#18500000
0"
#19500000
1"
#20000000

View file

@ -1,362 +0,0 @@
Simulation {
state: State {
insns: Insns {
state_layout: StateLayout {
ty: TypeLayout {
small_slots: StatePartLayout<SmallSlots> {
len: 0,
debug_data: [],
..
},
big_slots: StatePartLayout<BigSlots> {
len: 3,
debug_data: [
SlotDebugData {
name: "InstantiatedModule(extern_module2: extern_module2).extern_module2::en",
ty: Bool,
},
SlotDebugData {
name: "InstantiatedModule(extern_module2: extern_module2).extern_module2::clk",
ty: Clock,
},
SlotDebugData {
name: "InstantiatedModule(extern_module2: extern_module2).extern_module2::o",
ty: UInt<8>,
},
],
..
},
sim_only_slots: StatePartLayout<SimOnlySlots> {
len: 0,
debug_data: [],
layout_data: [],
..
},
},
memories: StatePartLayout<Memories> {
len: 0,
debug_data: [],
layout_data: [],
..
},
},
insns: [
// at: module-XXXXXXXXXX.rs:1:1
0: Return,
],
..
},
pc: 0,
memory_write_log: [],
memories: StatePart {
value: [],
},
small_slots: StatePart {
value: [],
},
big_slots: StatePart {
value: [
0,
1,
101,
],
},
sim_only_slots: StatePart {
value: [],
},
},
io: Instance {
name: <simulator>::extern_module2,
instantiated: Module {
name: extern_module2,
..
},
},
main_module: SimulationModuleState {
base_targets: [
Instance {
name: <simulator>::extern_module2,
instantiated: Module {
name: extern_module2,
..
},
}.en,
Instance {
name: <simulator>::extern_module2,
instantiated: Module {
name: extern_module2,
..
},
}.clk,
Instance {
name: <simulator>::extern_module2,
instantiated: Module {
name: extern_module2,
..
},
}.o,
],
uninitialized_ios: {},
io_targets: {
Instance {
name: <simulator>::extern_module2,
instantiated: Module {
name: extern_module2,
..
},
}.clk,
Instance {
name: <simulator>::extern_module2,
instantiated: Module {
name: extern_module2,
..
},
}.en,
Instance {
name: <simulator>::extern_module2,
instantiated: Module {
name: extern_module2,
..
},
}.o,
},
did_initial_settle: true,
},
extern_modules: [
SimulationExternModuleState {
module_state: SimulationModuleState {
base_targets: [
ModuleIO {
name: extern_module2::en,
is_input: true,
ty: Bool,
..
},
ModuleIO {
name: extern_module2::clk,
is_input: true,
ty: Clock,
..
},
ModuleIO {
name: extern_module2::o,
is_input: false,
ty: UInt<8>,
..
},
],
uninitialized_ios: {},
io_targets: {
ModuleIO {
name: extern_module2::clk,
is_input: true,
ty: Clock,
..
},
ModuleIO {
name: extern_module2::en,
is_input: true,
ty: Bool,
..
},
ModuleIO {
name: extern_module2::o,
is_input: false,
ty: UInt<8>,
..
},
},
did_initial_settle: true,
},
sim: ExternModuleSimulation {
generator: SimGeneratorFn {
args: (
ModuleIO {
name: extern_module2::en,
is_input: true,
ty: Bool,
..
},
ModuleIO {
name: extern_module2::clk,
is_input: true,
ty: Clock,
..
},
ModuleIO {
name: extern_module2::o,
is_input: false,
ty: UInt<8>,
..
},
),
f: ...,
},
sim_io_to_generator_map: {
ModuleIO {
name: extern_module2::clk,
is_input: true,
ty: Clock,
..
}: ModuleIO {
name: extern_module2::clk,
is_input: true,
ty: Clock,
..
},
ModuleIO {
name: extern_module2::en,
is_input: true,
ty: Bool,
..
}: ModuleIO {
name: extern_module2::en,
is_input: true,
ty: Bool,
..
},
ModuleIO {
name: extern_module2::o,
is_input: false,
ty: UInt<8>,
..
}: ModuleIO {
name: extern_module2::o,
is_input: false,
ty: UInt<8>,
..
},
},
source_location: SourceLocation(
module-XXXXXXXXXX.rs:5:1,
),
},
running_generator: Some(
...,
),
wait_targets: {
Change {
key: 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: "InstantiatedModule(extern_module2: extern_module2).extern_module2::clk",
ty: Clock,
},
],
..
},
sim_only_slots: StatePartLayout<SimOnlySlots> {
len: 0,
debug_data: [],
layout_data: [],
..
},
},
body: Scalar,
},
range: TypeIndexRange {
small_slots: StatePartIndexRange<SmallSlots> { start: 0, len: 0 },
big_slots: StatePartIndexRange<BigSlots> { start: 1, len: 1 },
sim_only_slots: StatePartIndexRange<SimOnlySlots> { start: 0, len: 0 },
},
write: None,
},
value: SimValue {
ty: Clock,
value: OpaqueSimValue {
bits: 0x1_u1,
sim_only_values: [],
},
},
},
},
},
],
state_ready_to_run: false,
trace_decls: TraceModule {
name: "extern_module2",
children: [
TraceModuleIO {
name: "en",
child: TraceBool {
location: TraceScalarId(0),
name: "en",
flow: Source,
},
ty: Bool,
flow: Source,
},
TraceModuleIO {
name: "clk",
child: TraceClock {
location: TraceScalarId(1),
name: "clk",
flow: Source,
},
ty: Clock,
flow: Source,
},
TraceModuleIO {
name: "o",
child: TraceUInt {
location: TraceScalarId(2),
name: "o",
ty: UInt<8>,
flow: Sink,
},
ty: UInt<8>,
flow: Sink,
},
],
},
traces: [
SimTrace {
id: TraceScalarId(0),
kind: BigBool {
index: StatePartIndex<BigSlots>(0),
},
state: 0x0,
last_state: 0x0,
},
SimTrace {
id: TraceScalarId(1),
kind: BigClock {
index: StatePartIndex<BigSlots>(1),
},
state: 0x1,
last_state: 0x1,
},
SimTrace {
id: TraceScalarId(2),
kind: BigUInt {
index: StatePartIndex<BigSlots>(2),
ty: UInt<8>,
},
state: 0x65,
last_state: 0x65,
},
],
trace_memories: {},
trace_writers: [
Running(
VcdWriter {
finished_init: true,
timescale: 1 ps,
..
},
),
],
instant: 60 μs,
clocks_triggered: [],
..
}

View file

@ -1,150 +0,0 @@
$timescale 1 ps $end
$scope module extern_module2 $end
$var wire 1 ! en $end
$var wire 1 " clk $end
$var wire 8 # o $end
$upscope $end
$enddefinitions $end
$dumpvars
1!
0"
b1001000 #
$end
#1000000
1"
b1100101 #
#2000000
0"
#3000000
1"
b1101100 #
#4000000
0"
#5000000
1"
#6000000
0"
#7000000
1"
b1101111 #
#8000000
0"
#9000000
1"
b101100 #
#10000000
0!
0"
#11000000
1"
#12000000
0"
#13000000
1"
#14000000
0"
#15000000
1"
#16000000
0"
#17000000
1"
#18000000
0"
#19000000
1"
#20000000
1!
0"
#21000000
1"
b100000 #
#22000000
0"
#23000000
1"
b1010111 #
#24000000
0"
#25000000
1"
b1101111 #
#26000000
0"
#27000000
1"
b1110010 #
#28000000
0"
#29000000
1"
b1101100 #
#30000000
0!
0"
#31000000
1"
#32000000
0"
#33000000
1"
#34000000
0"
#35000000
1"
#36000000
0"
#37000000
1"
#38000000
0"
#39000000
1"
#40000000
1!
0"
#41000000
1"
b1100100 #
#42000000
0"
#43000000
1"
b100001 #
#44000000
0"
#45000000
1"
b1010 #
#46000000
0"
#47000000
1"
b1001000 #
#48000000
0"
#49000000
1"
b1100101 #
#50000000
0!
0"
#51000000
1"
#52000000
0"
#53000000
1"
#54000000
0"
#55000000
1"
#56000000
0"
#57000000
1"
#58000000
0"
#59000000
1"
#60000000

File diff suppressed because it is too large Load diff

View file

@ -24,97 +24,97 @@ $upscope $end
$upscope $end $upscope $end
$scope struct mem $end $scope struct mem $end
$scope struct contents $end $scope struct contents $end
$scope struct \[0] $end $scope struct [0] $end
$scope struct mem $end $scope struct mem $end
$var reg 8 9 \0 $end $var reg 8 9 \0 $end
$var reg 8 I \1 $end $var reg 8 I \1 $end
$upscope $end $upscope $end
$upscope $end $upscope $end
$scope struct \[1] $end $scope struct [1] $end
$scope struct mem $end $scope struct mem $end
$var reg 8 : \0 $end $var reg 8 : \0 $end
$var reg 8 J \1 $end $var reg 8 J \1 $end
$upscope $end $upscope $end
$upscope $end $upscope $end
$scope struct \[2] $end $scope struct [2] $end
$scope struct mem $end $scope struct mem $end
$var reg 8 ; \0 $end $var reg 8 ; \0 $end
$var reg 8 K \1 $end $var reg 8 K \1 $end
$upscope $end $upscope $end
$upscope $end $upscope $end
$scope struct \[3] $end $scope struct [3] $end
$scope struct mem $end $scope struct mem $end
$var reg 8 < \0 $end $var reg 8 < \0 $end
$var reg 8 L \1 $end $var reg 8 L \1 $end
$upscope $end $upscope $end
$upscope $end $upscope $end
$scope struct \[4] $end $scope struct [4] $end
$scope struct mem $end $scope struct mem $end
$var reg 8 = \0 $end $var reg 8 = \0 $end
$var reg 8 M \1 $end $var reg 8 M \1 $end
$upscope $end $upscope $end
$upscope $end $upscope $end
$scope struct \[5] $end $scope struct [5] $end
$scope struct mem $end $scope struct mem $end
$var reg 8 > \0 $end $var reg 8 > \0 $end
$var reg 8 N \1 $end $var reg 8 N \1 $end
$upscope $end $upscope $end
$upscope $end $upscope $end
$scope struct \[6] $end $scope struct [6] $end
$scope struct mem $end $scope struct mem $end
$var reg 8 ? \0 $end $var reg 8 ? \0 $end
$var reg 8 O \1 $end $var reg 8 O \1 $end
$upscope $end $upscope $end
$upscope $end $upscope $end
$scope struct \[7] $end $scope struct [7] $end
$scope struct mem $end $scope struct mem $end
$var reg 8 @ \0 $end $var reg 8 @ \0 $end
$var reg 8 P \1 $end $var reg 8 P \1 $end
$upscope $end $upscope $end
$upscope $end $upscope $end
$scope struct \[8] $end $scope struct [8] $end
$scope struct mem $end $scope struct mem $end
$var reg 8 A \0 $end $var reg 8 A \0 $end
$var reg 8 Q \1 $end $var reg 8 Q \1 $end
$upscope $end $upscope $end
$upscope $end $upscope $end
$scope struct \[9] $end $scope struct [9] $end
$scope struct mem $end $scope struct mem $end
$var reg 8 B \0 $end $var reg 8 B \0 $end
$var reg 8 R \1 $end $var reg 8 R \1 $end
$upscope $end $upscope $end
$upscope $end $upscope $end
$scope struct \[10] $end $scope struct [10] $end
$scope struct mem $end $scope struct mem $end
$var reg 8 C \0 $end $var reg 8 C \0 $end
$var reg 8 S \1 $end $var reg 8 S \1 $end
$upscope $end $upscope $end
$upscope $end $upscope $end
$scope struct \[11] $end $scope struct [11] $end
$scope struct mem $end $scope struct mem $end
$var reg 8 D \0 $end $var reg 8 D \0 $end
$var reg 8 T \1 $end $var reg 8 T \1 $end
$upscope $end $upscope $end
$upscope $end $upscope $end
$scope struct \[12] $end $scope struct [12] $end
$scope struct mem $end $scope struct mem $end
$var reg 8 E \0 $end $var reg 8 E \0 $end
$var reg 8 U \1 $end $var reg 8 U \1 $end
$upscope $end $upscope $end
$upscope $end $upscope $end
$scope struct \[13] $end $scope struct [13] $end
$scope struct mem $end $scope struct mem $end
$var reg 8 F \0 $end $var reg 8 F \0 $end
$var reg 8 V \1 $end $var reg 8 V \1 $end
$upscope $end $upscope $end
$upscope $end $upscope $end
$scope struct \[14] $end $scope struct [14] $end
$scope struct mem $end $scope struct mem $end
$var reg 8 G \0 $end $var reg 8 G \0 $end
$var reg 8 W \1 $end $var reg 8 W \1 $end
$upscope $end $upscope $end
$upscope $end $upscope $end
$scope struct \[15] $end $scope struct [15] $end
$scope struct mem $end $scope struct mem $end
$var reg 8 H \0 $end $var reg 8 H \0 $end
$var reg 8 X \1 $end $var reg 8 X \1 $end

View file

@ -224,12 +224,6 @@ Simulation {
], ],
.. ..
}, },
sim_only_slots: StatePartLayout<SimOnlySlots> {
len: 0,
debug_data: [],
layout_data: [],
..
},
}, },
memories: StatePartLayout<Memories> { memories: StatePartLayout<Memories> {
len: 1, len: 1,
@ -596,9 +590,6 @@ Simulation {
1, 1,
], ],
}, },
sim_only_slots: StatePart {
value: [],
},
}, },
io: Instance { io: Instance {
name: <simulator>::memories2, name: <simulator>::memories2,
@ -607,17 +598,7 @@ Simulation {
.. ..
}, },
}, },
main_module: SimulationModuleState { uninitialized_inputs: {},
base_targets: [
Instance {
name: <simulator>::memories2,
instantiated: Module {
name: memories2,
..
},
}.rw,
],
uninitialized_ios: {},
io_targets: { io_targets: {
Instance { Instance {
name: <simulator>::memories2, name: <simulator>::memories2,
@ -625,61 +606,506 @@ Simulation {
name: memories2, name: memories2,
.. ..
}, },
}.rw, }.rw: CompiledValue {
layout: CompiledTypeLayout {
ty: Bundle {
/* offset = 0 */
addr: UInt<3>,
/* offset = 3 */
en: Bool,
/* offset = 4 */
clk: Clock,
#[hdl(flip)] /* offset = 5 */
rdata: UInt<2>,
/* offset = 7 */
wmode: Bool,
/* offset = 8 */
wdata: UInt<2>,
/* offset = 10 */
wmask: Bool,
},
layout: TypeLayout {
small_slots: StatePartLayout<SmallSlots> {
len: 0,
debug_data: [],
..
},
big_slots: StatePartLayout<BigSlots> {
len: 7,
debug_data: [
SlotDebugData {
name: "InstantiatedModule(memories2: memories2).memories2::rw.addr",
ty: UInt<3>,
},
SlotDebugData {
name: "InstantiatedModule(memories2: memories2).memories2::rw.en",
ty: Bool,
},
SlotDebugData {
name: "InstantiatedModule(memories2: memories2).memories2::rw.clk",
ty: Clock,
},
SlotDebugData {
name: "InstantiatedModule(memories2: memories2).memories2::rw.rdata",
ty: UInt<2>,
},
SlotDebugData {
name: "InstantiatedModule(memories2: memories2).memories2::rw.wmode",
ty: Bool,
},
SlotDebugData {
name: "InstantiatedModule(memories2: memories2).memories2::rw.wdata",
ty: UInt<2>,
},
SlotDebugData {
name: "InstantiatedModule(memories2: memories2).memories2::rw.wmask",
ty: Bool,
},
],
..
},
},
body: Bundle {
fields: [
CompiledBundleField {
offset: TypeIndex {
small_slots: StatePartIndex<SmallSlots>(0),
big_slots: StatePartIndex<BigSlots>(0),
},
ty: CompiledTypeLayout {
ty: UInt<3>,
layout: TypeLayout {
small_slots: StatePartLayout<SmallSlots> {
len: 0,
debug_data: [],
..
},
big_slots: StatePartLayout<BigSlots> {
len: 1,
debug_data: [
SlotDebugData {
name: "",
ty: UInt<3>,
},
],
..
},
},
body: Scalar,
},
},
CompiledBundleField {
offset: TypeIndex {
small_slots: StatePartIndex<SmallSlots>(0),
big_slots: StatePartIndex<BigSlots>(1),
},
ty: CompiledTypeLayout {
ty: Bool,
layout: TypeLayout {
small_slots: StatePartLayout<SmallSlots> {
len: 0,
debug_data: [],
..
},
big_slots: StatePartLayout<BigSlots> {
len: 1,
debug_data: [
SlotDebugData {
name: "",
ty: Bool,
},
],
..
},
},
body: Scalar,
},
},
CompiledBundleField {
offset: TypeIndex {
small_slots: StatePartIndex<SmallSlots>(0),
big_slots: StatePartIndex<BigSlots>(2),
},
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>(3),
},
ty: CompiledTypeLayout {
ty: UInt<2>,
layout: TypeLayout {
small_slots: StatePartLayout<SmallSlots> {
len: 0,
debug_data: [],
..
},
big_slots: StatePartLayout<BigSlots> {
len: 1,
debug_data: [
SlotDebugData {
name: "",
ty: UInt<2>,
},
],
..
},
},
body: Scalar,
},
},
CompiledBundleField {
offset: TypeIndex {
small_slots: StatePartIndex<SmallSlots>(0),
big_slots: StatePartIndex<BigSlots>(4),
},
ty: CompiledTypeLayout {
ty: Bool,
layout: TypeLayout {
small_slots: StatePartLayout<SmallSlots> {
len: 0,
debug_data: [],
..
},
big_slots: StatePartLayout<BigSlots> {
len: 1,
debug_data: [
SlotDebugData {
name: "",
ty: Bool,
},
],
..
},
},
body: Scalar,
},
},
CompiledBundleField {
offset: TypeIndex {
small_slots: StatePartIndex<SmallSlots>(0),
big_slots: StatePartIndex<BigSlots>(5),
},
ty: CompiledTypeLayout {
ty: UInt<2>,
layout: TypeLayout {
small_slots: StatePartLayout<SmallSlots> {
len: 0,
debug_data: [],
..
},
big_slots: StatePartLayout<BigSlots> {
len: 1,
debug_data: [
SlotDebugData {
name: "",
ty: UInt<2>,
},
],
..
},
},
body: Scalar,
},
},
CompiledBundleField {
offset: TypeIndex {
small_slots: StatePartIndex<SmallSlots>(0),
big_slots: StatePartIndex<BigSlots>(6),
},
ty: CompiledTypeLayout {
ty: Bool,
layout: TypeLayout {
small_slots: StatePartLayout<SmallSlots> {
len: 0,
debug_data: [],
..
},
big_slots: StatePartLayout<BigSlots> {
len: 1,
debug_data: [
SlotDebugData {
name: "",
ty: Bool,
},
],
..
},
},
body: Scalar,
},
},
],
},
},
range: TypeIndexRange {
small_slots: StatePartIndexRange<SmallSlots> { start: 0, len: 0 },
big_slots: StatePartIndexRange<BigSlots> { start: 0, len: 7 },
},
write: None,
},
Instance { Instance {
name: <simulator>::memories2, name: <simulator>::memories2,
instantiated: Module { instantiated: Module {
name: memories2, name: memories2,
.. ..
}, },
}.rw.addr, }.rw.addr: CompiledValue {
layout: CompiledTypeLayout {
ty: UInt<3>,
layout: TypeLayout {
small_slots: StatePartLayout<SmallSlots> {
len: 0,
debug_data: [],
..
},
big_slots: StatePartLayout<BigSlots> {
len: 1,
debug_data: [
SlotDebugData {
name: "",
ty: UInt<3>,
},
],
..
},
},
body: Scalar,
},
range: TypeIndexRange {
small_slots: StatePartIndexRange<SmallSlots> { start: 0, len: 0 },
big_slots: StatePartIndexRange<BigSlots> { start: 0, len: 1 },
},
write: None,
},
Instance { Instance {
name: <simulator>::memories2, name: <simulator>::memories2,
instantiated: Module { instantiated: Module {
name: memories2, name: memories2,
.. ..
}, },
}.rw.clk, }.rw.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: 2, len: 1 },
},
write: None,
},
Instance { Instance {
name: <simulator>::memories2, name: <simulator>::memories2,
instantiated: Module { instantiated: Module {
name: memories2, name: memories2,
.. ..
}, },
}.rw.en, }.rw.en: 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: "",
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 { Instance {
name: <simulator>::memories2, name: <simulator>::memories2,
instantiated: Module { instantiated: Module {
name: memories2, name: memories2,
.. ..
}, },
}.rw.rdata, }.rw.rdata: CompiledValue {
layout: CompiledTypeLayout {
ty: UInt<2>,
layout: TypeLayout {
small_slots: StatePartLayout<SmallSlots> {
len: 0,
debug_data: [],
..
},
big_slots: StatePartLayout<BigSlots> {
len: 1,
debug_data: [
SlotDebugData {
name: "",
ty: UInt<2>,
},
],
..
},
},
body: Scalar,
},
range: TypeIndexRange {
small_slots: StatePartIndexRange<SmallSlots> { start: 0, len: 0 },
big_slots: StatePartIndexRange<BigSlots> { start: 3, len: 1 },
},
write: None,
},
Instance { Instance {
name: <simulator>::memories2, name: <simulator>::memories2,
instantiated: Module { instantiated: Module {
name: memories2, name: memories2,
.. ..
}, },
}.rw.wdata, }.rw.wdata: CompiledValue {
layout: CompiledTypeLayout {
ty: UInt<2>,
layout: TypeLayout {
small_slots: StatePartLayout<SmallSlots> {
len: 0,
debug_data: [],
..
},
big_slots: StatePartLayout<BigSlots> {
len: 1,
debug_data: [
SlotDebugData {
name: "",
ty: UInt<2>,
},
],
..
},
},
body: Scalar,
},
range: TypeIndexRange {
small_slots: StatePartIndexRange<SmallSlots> { start: 0, len: 0 },
big_slots: StatePartIndexRange<BigSlots> { start: 5, len: 1 },
},
write: None,
},
Instance { Instance {
name: <simulator>::memories2, name: <simulator>::memories2,
instantiated: Module { instantiated: Module {
name: memories2, name: memories2,
.. ..
}, },
}.rw.wmask, }.rw.wmask: 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: "",
ty: Bool,
},
],
..
},
},
body: Scalar,
},
range: TypeIndexRange {
small_slots: StatePartIndexRange<SmallSlots> { start: 0, len: 0 },
big_slots: StatePartIndexRange<BigSlots> { start: 6, len: 1 },
},
write: None,
},
Instance { Instance {
name: <simulator>::memories2, name: <simulator>::memories2,
instantiated: Module { instantiated: Module {
name: memories2, name: memories2,
.. ..
}, },
}.rw.wmode, }.rw.wmode: CompiledValue {
layout: CompiledTypeLayout {
ty: Bool,
layout: TypeLayout {
small_slots: StatePartLayout<SmallSlots> {
len: 0,
debug_data: [],
..
}, },
did_initial_settle: true, big_slots: StatePartLayout<BigSlots> {
len: 1,
debug_data: [
SlotDebugData {
name: "",
ty: Bool,
}, },
extern_modules: [], ],
state_ready_to_run: false, ..
},
},
body: Scalar,
},
range: TypeIndexRange {
small_slots: StatePartIndexRange<SmallSlots> { start: 0, len: 0 },
big_slots: StatePartIndexRange<BigSlots> { start: 4, len: 1 },
},
write: None,
},
},
made_initial_step: true,
needs_settle: false,
trace_decls: TraceModule { trace_decls: TraceModule {
name: "memories2", name: "memories2",
children: [ children: [

View file

@ -11,31 +11,31 @@ $var wire 1 ' wmask $end
$upscope $end $upscope $end
$scope struct mem $end $scope struct mem $end
$scope struct contents $end $scope struct contents $end
$scope struct \[0] $end $scope struct [0] $end
$scope struct mem $end $scope struct mem $end
$var string 1 1 \$tag $end $var string 1 1 \$tag $end
$var reg 1 6 HdlSome $end $var reg 1 6 HdlSome $end
$upscope $end $upscope $end
$upscope $end $upscope $end
$scope struct \[1] $end $scope struct [1] $end
$scope struct mem $end $scope struct mem $end
$var string 1 2 \$tag $end $var string 1 2 \$tag $end
$var reg 1 7 HdlSome $end $var reg 1 7 HdlSome $end
$upscope $end $upscope $end
$upscope $end $upscope $end
$scope struct \[2] $end $scope struct [2] $end
$scope struct mem $end $scope struct mem $end
$var string 1 3 \$tag $end $var string 1 3 \$tag $end
$var reg 1 8 HdlSome $end $var reg 1 8 HdlSome $end
$upscope $end $upscope $end
$upscope $end $upscope $end
$scope struct \[3] $end $scope struct [3] $end
$scope struct mem $end $scope struct mem $end
$var string 1 4 \$tag $end $var string 1 4 \$tag $end
$var reg 1 9 HdlSome $end $var reg 1 9 HdlSome $end
$upscope $end $upscope $end
$upscope $end $upscope $end
$scope struct \[4] $end $scope struct [4] $end
$scope struct mem $end $scope struct mem $end
$var string 1 5 \$tag $end $var string 1 5 \$tag $end
$var reg 1 : HdlSome $end $var reg 1 : HdlSome $end

File diff suppressed because it is too large Load diff

View file

@ -42,7 +42,7 @@ $upscope $end
$upscope $end $upscope $end
$scope struct mem $end $scope struct mem $end
$scope struct contents $end $scope struct contents $end
$scope struct \[0] $end $scope struct [0] $end
$scope struct mem $end $scope struct mem $end
$var reg 8 ] \[0] $end $var reg 8 ] \[0] $end
$var reg 8 e \[1] $end $var reg 8 e \[1] $end
@ -54,7 +54,7 @@ $var reg 8 /" \[6] $end
$var reg 8 7" \[7] $end $var reg 8 7" \[7] $end
$upscope $end $upscope $end
$upscope $end $upscope $end
$scope struct \[1] $end $scope struct [1] $end
$scope struct mem $end $scope struct mem $end
$var reg 8 ^ \[0] $end $var reg 8 ^ \[0] $end
$var reg 8 f \[1] $end $var reg 8 f \[1] $end
@ -66,7 +66,7 @@ $var reg 8 0" \[6] $end
$var reg 8 8" \[7] $end $var reg 8 8" \[7] $end
$upscope $end $upscope $end
$upscope $end $upscope $end
$scope struct \[2] $end $scope struct [2] $end
$scope struct mem $end $scope struct mem $end
$var reg 8 _ \[0] $end $var reg 8 _ \[0] $end
$var reg 8 g \[1] $end $var reg 8 g \[1] $end
@ -78,7 +78,7 @@ $var reg 8 1" \[6] $end
$var reg 8 9" \[7] $end $var reg 8 9" \[7] $end
$upscope $end $upscope $end
$upscope $end $upscope $end
$scope struct \[3] $end $scope struct [3] $end
$scope struct mem $end $scope struct mem $end
$var reg 8 ` \[0] $end $var reg 8 ` \[0] $end
$var reg 8 h \[1] $end $var reg 8 h \[1] $end
@ -90,7 +90,7 @@ $var reg 8 2" \[6] $end
$var reg 8 :" \[7] $end $var reg 8 :" \[7] $end
$upscope $end $upscope $end
$upscope $end $upscope $end
$scope struct \[4] $end $scope struct [4] $end
$scope struct mem $end $scope struct mem $end
$var reg 8 a \[0] $end $var reg 8 a \[0] $end
$var reg 8 i \[1] $end $var reg 8 i \[1] $end
@ -102,7 +102,7 @@ $var reg 8 3" \[6] $end
$var reg 8 ;" \[7] $end $var reg 8 ;" \[7] $end
$upscope $end $upscope $end
$upscope $end $upscope $end
$scope struct \[5] $end $scope struct [5] $end
$scope struct mem $end $scope struct mem $end
$var reg 8 b \[0] $end $var reg 8 b \[0] $end
$var reg 8 j \[1] $end $var reg 8 j \[1] $end
@ -114,7 +114,7 @@ $var reg 8 4" \[6] $end
$var reg 8 <" \[7] $end $var reg 8 <" \[7] $end
$upscope $end $upscope $end
$upscope $end $upscope $end
$scope struct \[6] $end $scope struct [6] $end
$scope struct mem $end $scope struct mem $end
$var reg 8 c \[0] $end $var reg 8 c \[0] $end
$var reg 8 k \[1] $end $var reg 8 k \[1] $end
@ -126,7 +126,7 @@ $var reg 8 5" \[6] $end
$var reg 8 =" \[7] $end $var reg 8 =" \[7] $end
$upscope $end $upscope $end
$upscope $end $upscope $end
$scope struct \[7] $end $scope struct [7] $end
$scope struct mem $end $scope struct mem $end
$var reg 8 d \[0] $end $var reg 8 d \[0] $end
$var reg 8 l \[1] $end $var reg 8 l \[1] $end

View file

@ -82,12 +82,6 @@ Simulation {
], ],
.. ..
}, },
sim_only_slots: StatePartLayout<SimOnlySlots> {
len: 0,
debug_data: [],
layout_data: [],
..
},
}, },
memories: StatePartLayout<Memories> { memories: StatePartLayout<Memories> {
len: 0, len: 0,
@ -214,9 +208,6 @@ Simulation {
15, 15,
], ],
}, },
sim_only_slots: StatePart {
value: [],
},
}, },
io: Instance { io: Instance {
name: <simulator>::mod1, name: <simulator>::mod1,
@ -225,17 +216,7 @@ Simulation {
.. ..
}, },
}, },
main_module: SimulationModuleState { uninitialized_inputs: {},
base_targets: [
Instance {
name: <simulator>::mod1,
instantiated: Module {
name: mod1,
..
},
}.o,
],
uninitialized_ios: {},
io_targets: { io_targets: {
Instance { Instance {
name: <simulator>::mod1, name: <simulator>::mod1,
@ -243,40 +224,305 @@ Simulation {
name: mod1, name: mod1,
.. ..
}, },
}.o, }.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 { Instance {
name: <simulator>::mod1, name: <simulator>::mod1,
instantiated: Module { instantiated: Module {
name: mod1, name: mod1,
.. ..
}, },
}.o.i, }.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 { Instance {
name: <simulator>::mod1, name: <simulator>::mod1,
instantiated: Module { instantiated: Module {
name: mod1, name: mod1,
.. ..
}, },
}.o.i2, }.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 { Instance {
name: <simulator>::mod1, name: <simulator>::mod1,
instantiated: Module { instantiated: Module {
name: mod1, name: mod1,
.. ..
}, },
}.o.o, }.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 { Instance {
name: <simulator>::mod1, name: <simulator>::mod1,
instantiated: Module { instantiated: Module {
name: mod1, name: mod1,
.. ..
}, },
}.o.o2, }.o.o2: CompiledValue {
layout: CompiledTypeLayout {
ty: UInt<4>,
layout: TypeLayout {
small_slots: StatePartLayout<SmallSlots> {
len: 0,
debug_data: [],
..
}, },
did_initial_settle: true, big_slots: StatePartLayout<BigSlots> {
len: 1,
debug_data: [
SlotDebugData {
name: "",
ty: UInt<4>,
}, },
extern_modules: [], ],
state_ready_to_run: false, ..
},
},
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 { trace_decls: TraceModule {
name: "mod1", name: "mod1",
children: [ children: [

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -83,12 +83,6 @@ Simulation {
], ],
.. ..
}, },
sim_only_slots: StatePartLayout<SimOnlySlots> {
len: 0,
debug_data: [],
layout_data: [],
..
},
}, },
memories: StatePartLayout<Memories> { memories: StatePartLayout<Memories> {
len: 0, len: 0,
@ -263,9 +257,6 @@ Simulation {
0, 0,
], ],
}, },
sim_only_slots: StatePart {
value: [],
},
}, },
io: Instance { io: Instance {
name: <simulator>::shift_register, name: <simulator>::shift_register,
@ -274,31 +265,7 @@ Simulation {
.. ..
}, },
}, },
main_module: SimulationModuleState { uninitialized_inputs: {},
base_targets: [
Instance {
name: <simulator>::shift_register,
instantiated: Module {
name: shift_register,
..
},
}.cd,
Instance {
name: <simulator>::shift_register,
instantiated: Module {
name: shift_register,
..
},
}.d,
Instance {
name: <simulator>::shift_register,
instantiated: Module {
name: shift_register,
..
},
}.q,
],
uninitialized_ios: {},
io_targets: { io_targets: {
Instance { Instance {
name: <simulator>::shift_register, name: <simulator>::shift_register,
@ -306,40 +273,239 @@ Simulation {
name: shift_register, name: shift_register,
.. ..
}, },
}.cd, }.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 { Instance {
name: <simulator>::shift_register, name: <simulator>::shift_register,
instantiated: Module { instantiated: Module {
name: shift_register, name: shift_register,
.. ..
}, },
}.cd.clk, }.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 { Instance {
name: <simulator>::shift_register, name: <simulator>::shift_register,
instantiated: Module { instantiated: Module {
name: shift_register, name: shift_register,
.. ..
}, },
}.cd.rst, }.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 { Instance {
name: <simulator>::shift_register, name: <simulator>::shift_register,
instantiated: Module { instantiated: Module {
name: shift_register, name: shift_register,
.. ..
}, },
}.d, }.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 { Instance {
name: <simulator>::shift_register, name: <simulator>::shift_register,
instantiated: Module { instantiated: Module {
name: shift_register, name: shift_register,
.. ..
}, },
}.q, }.q: CompiledValue {
layout: CompiledTypeLayout {
ty: Bool,
layout: TypeLayout {
small_slots: StatePartLayout<SmallSlots> {
len: 0,
debug_data: [],
..
}, },
did_initial_settle: true, big_slots: StatePartLayout<BigSlots> {
len: 1,
debug_data: [
SlotDebugData {
name: "InstantiatedModule(shift_register: shift_register).shift_register::q",
ty: Bool,
}, },
extern_modules: [], ],
state_ready_to_run: false, ..
},
},
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 { trace_decls: TraceModule {
name: "shift_register", name: "shift_register",
children: [ children: [

File diff suppressed because it is too large Load diff

View file

@ -1,185 +0,0 @@
$timescale 1 ps $end
$scope module sim_only_connects $end
$scope struct cd $end
$var wire 1 ! clk $end
$var wire 1 " rst $end
$upscope $end
$var string 1 # inp $end
$var string 1 $ out1 $end
$var string 1 % out2 $end
$var string 1 & out3 $end
$scope struct helper1 $end
$scope struct cd $end
$var wire 1 + clk $end
$var wire 1 , rst $end
$upscope $end
$var string 1 - inp $end
$var string 1 . out $end
$upscope $end
$scope module sim_only_connects_helper $end
$scope struct cd $end
$var wire 1 ' clk $end
$var wire 1 ( rst $end
$upscope $end
$var string 1 ) inp $end
$var string 1 * out $end
$upscope $end
$var string 1 / delay1 $end
$var reg 1 0 delay1_empty $end
$scope struct helper2 $end
$scope struct cd $end
$var wire 1 5 clk $end
$var wire 1 6 rst $end
$upscope $end
$var string 1 7 inp $end
$var string 1 8 out $end
$upscope $end
$scope module sim_only_connects_helper_2 $end
$scope struct cd $end
$var wire 1 1 clk $end
$var wire 1 2 rst $end
$upscope $end
$var string 1 3 inp $end
$var string 1 4 out $end
$upscope $end
$upscope $end
$enddefinitions $end
$dumpvars
0!
1"
s{\"extra\":\x20\"value\"} #
s{} $
s{} %
s{} &
0'
1(
s{} )
s{} *
0+
1,
s{} -
s{} .
s{} /
00
01
12
s{} 3
s{} 4
05
16
s{} 7
s{} 8
$end
#1000000
1!
1'
1+
10
11
15
s{\"extra\":\x20\"value\"} $
s{\"extra\":\x20\"value\"} )
s{\"extra\":\x20\"value\"} -
s{\"bar\":\x20\"\",\x20\"extra\":\x20\"value\",\x20\"foo\":\x20\"baz\"} *
s{\"bar\":\x20\"\",\x20\"foo\":\x20\"baz\"} 4
s{\"bar\":\x20\"\",\x20\"extra\":\x20\"value\",\x20\"foo\":\x20\"baz\"} %
s{\"bar\":\x20\"\",\x20\"foo\":\x20\"baz\"} &
s{\"bar\":\x20\"\",\x20\"extra\":\x20\"value\",\x20\"foo\":\x20\"baz\"} .
s{\"bar\":\x20\"\",\x20\"extra\":\x20\"value\",\x20\"foo\":\x20\"baz\"} 3
s{\"bar\":\x20\"\",\x20\"extra\":\x20\"value\",\x20\"foo\":\x20\"baz\"} 7
s{\"bar\":\x20\"\",\x20\"foo\":\x20\"baz\"} 8
#2000000
0!
0"
0'
0(
0+
0,
01
02
05
06
#3000000
1!
1'
1+
s{\"extra\":\x20\"value\"} /
00
11
15
s{\"bar\":\x20\"baz\",\x20\"extra\":\x20\"value\",\x20\"foo\":\x20\"baz\"} 4
s{\"bar\":\x20\"baz\",\x20\"extra\":\x20\"value\",\x20\"foo\":\x20\"baz\"} &
s{\"bar\":\x20\"baz\",\x20\"extra\":\x20\"value\",\x20\"foo\":\x20\"baz\"} 8
#4000000
0!
0'
0+
01
05
#5000000
1!
1'
1+
11
15
#6000000
0!
0'
0+
01
05
#7000000
1!
1'
1+
11
15
#8000000
0!
0'
0+
01
05
#9000000
1!
1'
1+
11
15
#10000000
0!
0'
0+
01
05
#11000000
1!
1'
1+
11
15
#12000000
0!
0'
0+
01
05
#13000000
1!
1'
1+
11
15
#14000000
0!
0'
0+
01
05
#15000000
1!
1'
1+
11
15
#16000000

View file

@ -1,15 +0,0 @@
// SPDX-License-Identifier: LGPL-3.0-or-later
// See Notices.txt for copyright information
//! check that SimValue can't be interned, since equality may ignore types
use fayalite::{
intern::{Intern, Interned},
sim::value::SimValue,
};
fn f(v: SimValue<()>) -> Interned<SimValue<()>> {
Intern::intern_sized(v)
}
fn main() {}

View file

@ -1,369 +0,0 @@
error[E0277]: `Cell<util::alternating_cell::State>` cannot be shared between threads safely
--> tests/ui/simvalue_is_not_internable.rs:11:26
|
11 | fn f(v: SimValue<()>) -> Interned<SimValue<()>> {
| ^^^^^^^^^^^^^^^^^^^^^^ `Cell<util::alternating_cell::State>` cannot be shared between threads safely
|
= help: within `SimValue<()>`, the trait `Sync` is not implemented for `Cell<util::alternating_cell::State>`
= note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock`
note: required because it appears within the type `util::alternating_cell::AlternatingCell<value::SimValueInner<()>>`
--> src/util/alternating_cell.rs
|
| pub(crate) struct AlternatingCell<T: ?Sized> {
| ^^^^^^^^^^^^^^^
note: required because it appears within the type `SimValue<()>`
--> src/sim/value.rs
|
| pub struct SimValue<T: Type> {
| ^^^^^^^^
note: required by a bound in `fayalite::intern::Interned`
--> src/intern.rs
|
| pub struct Interned<T: ?Sized + 'static + Send + Sync> {
| ^^^^ required by this bound in `Interned`
error[E0277]: `UnsafeCell<value::SimValueInner<()>>` cannot be shared between threads safely
--> tests/ui/simvalue_is_not_internable.rs:11:26
|
11 | fn f(v: SimValue<()>) -> Interned<SimValue<()>> {
| ^^^^^^^^^^^^^^^^^^^^^^ `UnsafeCell<value::SimValueInner<()>>` cannot be shared between threads safely
|
= help: within `SimValue<()>`, the trait `Sync` is not implemented for `UnsafeCell<value::SimValueInner<()>>`
note: required because it appears within the type `util::alternating_cell::AlternatingCell<value::SimValueInner<()>>`
--> src/util/alternating_cell.rs
|
| pub(crate) struct AlternatingCell<T: ?Sized> {
| ^^^^^^^^^^^^^^^
note: required because it appears within the type `SimValue<()>`
--> src/sim/value.rs
|
| pub struct SimValue<T: Type> {
| ^^^^^^^^
note: required by a bound in `fayalite::intern::Interned`
--> src/intern.rs
|
| pub struct Interned<T: ?Sized + 'static + Send + Sync> {
| ^^^^ required by this bound in `Interned`
error[E0277]: `Rc<(dyn value::sim_only_value_unsafe::DynSimOnlyValueTrait + 'static)>` cannot be sent between threads safely
--> tests/ui/simvalue_is_not_internable.rs:11:26
|
11 | fn f(v: SimValue<()>) -> Interned<SimValue<()>> {
| ^^^^^^^^^^^^^^^^^^^^^^ `Rc<(dyn value::sim_only_value_unsafe::DynSimOnlyValueTrait + 'static)>` cannot be sent between threads safely
|
= help: within `SimValue<()>`, the trait `Send` is not implemented for `Rc<(dyn value::sim_only_value_unsafe::DynSimOnlyValueTrait + 'static)>`
note: required because it appears within the type `DynSimOnlyValue`
--> src/sim/value/sim_only_value_unsafe.rs
|
| pub struct DynSimOnlyValue(Rc<dyn DynSimOnlyValueTrait>);
| ^^^^^^^^^^^^^^^
note: required because it appears within the type `PhantomData<DynSimOnlyValue>`
--> $RUST/core/src/marker.rs
|
| pub struct PhantomData<T: PointeeSized>;
| ^^^^^^^^^^^
note: required because it appears within the type `alloc::raw_vec::RawVec<DynSimOnlyValue>`
--> $RUST/alloc/src/raw_vec/mod.rs
|
| pub(crate) struct RawVec<T, A: Allocator = Global> {
| ^^^^^^
note: required because it appears within the type `Vec<DynSimOnlyValue>`
--> $RUST/alloc/src/vec/mod.rs
|
| pub struct Vec<T, #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global> {
| ^^^
note: required because it appears within the type `OpaqueSimValue`
--> src/ty.rs
|
| pub struct OpaqueSimValue {
| ^^^^^^^^^^^^^^
note: required because it appears within the type `value::SimValueInner<()>`
--> src/sim/value.rs
|
| struct SimValueInner<T: Type> {
| ^^^^^^^^^^^^^
note: required because it appears within the type `UnsafeCell<value::SimValueInner<()>>`
--> $RUST/core/src/cell.rs
|
| pub struct UnsafeCell<T: ?Sized> {
| ^^^^^^^^^^
note: required because it appears within the type `util::alternating_cell::AlternatingCell<value::SimValueInner<()>>`
--> src/util/alternating_cell.rs
|
| pub(crate) struct AlternatingCell<T: ?Sized> {
| ^^^^^^^^^^^^^^^
note: required because it appears within the type `SimValue<()>`
--> src/sim/value.rs
|
| pub struct SimValue<T: Type> {
| ^^^^^^^^
note: required by a bound in `fayalite::intern::Interned`
--> src/intern.rs
|
| pub struct Interned<T: ?Sized + 'static + Send + Sync> {
| ^^^^ required by this bound in `Interned`
error[E0277]: the trait bound `SimValue<()>: Intern` is not satisfied
--> tests/ui/simvalue_is_not_internable.rs:12:26
|
12 | Intern::intern_sized(v)
| -------------------- ^ the trait `Hash` is not implemented for `SimValue<()>`
| |
| required by a bound introduced by this call
|
= note: required for `SimValue<()>` to implement `Intern`
help: consider dereferencing here
|
12 | Intern::intern_sized(*v)
| +
error[E0277]: the trait bound `SimValue<()>: Intern` is not satisfied
--> tests/ui/simvalue_is_not_internable.rs:12:26
|
12 | Intern::intern_sized(v)
| -------------------- ^ the trait `std::cmp::Eq` is not implemented for `SimValue<()>`
| |
| required by a bound introduced by this call
|
= note: required for `SimValue<()>` to implement `Intern`
help: consider dereferencing here
|
12 | Intern::intern_sized(*v)
| +
error[E0277]: `Cell<util::alternating_cell::State>` cannot be shared between threads safely
--> tests/ui/simvalue_is_not_internable.rs:12:26
|
12 | Intern::intern_sized(v)
| -------------------- ^ `Cell<util::alternating_cell::State>` cannot be shared between threads safely
| |
| required by a bound introduced by this call
|
= help: within `SimValue<()>`, the trait `Sync` is not implemented for `Cell<util::alternating_cell::State>`
= note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock`
note: required because it appears within the type `util::alternating_cell::AlternatingCell<value::SimValueInner<()>>`
--> src/util/alternating_cell.rs
|
| pub(crate) struct AlternatingCell<T: ?Sized> {
| ^^^^^^^^^^^^^^^
note: required because it appears within the type `SimValue<()>`
--> src/sim/value.rs
|
| pub struct SimValue<T: Type> {
| ^^^^^^^^
note: required by a bound in `intern_sized`
--> src/intern.rs
|
| pub trait Intern: Any + Send + Sync {
| ^^^^ required by this bound in `Intern::intern_sized`
| fn intern(&self) -> Interned<Self>;
| fn intern_sized(self) -> Interned<Self>
| ------------ required by a bound in this associated function
help: consider dereferencing here
|
12 | Intern::intern_sized(*v)
| +
error[E0277]: `UnsafeCell<value::SimValueInner<()>>` cannot be shared between threads safely
--> tests/ui/simvalue_is_not_internable.rs:12:26
|
12 | Intern::intern_sized(v)
| -------------------- ^ `UnsafeCell<value::SimValueInner<()>>` cannot be shared between threads safely
| |
| required by a bound introduced by this call
|
= help: within `SimValue<()>`, the trait `Sync` is not implemented for `UnsafeCell<value::SimValueInner<()>>`
note: required because it appears within the type `util::alternating_cell::AlternatingCell<value::SimValueInner<()>>`
--> src/util/alternating_cell.rs
|
| pub(crate) struct AlternatingCell<T: ?Sized> {
| ^^^^^^^^^^^^^^^
note: required because it appears within the type `SimValue<()>`
--> src/sim/value.rs
|
| pub struct SimValue<T: Type> {
| ^^^^^^^^
note: required by a bound in `intern_sized`
--> src/intern.rs
|
| pub trait Intern: Any + Send + Sync {
| ^^^^ required by this bound in `Intern::intern_sized`
| fn intern(&self) -> Interned<Self>;
| fn intern_sized(self) -> Interned<Self>
| ------------ required by a bound in this associated function
help: consider dereferencing here
|
12 | Intern::intern_sized(*v)
| +
error[E0277]: `Rc<(dyn value::sim_only_value_unsafe::DynSimOnlyValueTrait + 'static)>` cannot be sent between threads safely
--> tests/ui/simvalue_is_not_internable.rs:12:26
|
12 | Intern::intern_sized(v)
| -------------------- ^ `Rc<(dyn value::sim_only_value_unsafe::DynSimOnlyValueTrait + 'static)>` cannot be sent between threads safely
| |
| required by a bound introduced by this call
|
= help: within `SimValue<()>`, the trait `Send` is not implemented for `Rc<(dyn value::sim_only_value_unsafe::DynSimOnlyValueTrait + 'static)>`
note: required because it appears within the type `DynSimOnlyValue`
--> src/sim/value/sim_only_value_unsafe.rs
|
| pub struct DynSimOnlyValue(Rc<dyn DynSimOnlyValueTrait>);
| ^^^^^^^^^^^^^^^
note: required because it appears within the type `PhantomData<DynSimOnlyValue>`
--> $RUST/core/src/marker.rs
|
| pub struct PhantomData<T: PointeeSized>;
| ^^^^^^^^^^^
note: required because it appears within the type `alloc::raw_vec::RawVec<DynSimOnlyValue>`
--> $RUST/alloc/src/raw_vec/mod.rs
|
| pub(crate) struct RawVec<T, A: Allocator = Global> {
| ^^^^^^
note: required because it appears within the type `Vec<DynSimOnlyValue>`
--> $RUST/alloc/src/vec/mod.rs
|
| pub struct Vec<T, #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global> {
| ^^^
note: required because it appears within the type `OpaqueSimValue`
--> src/ty.rs
|
| pub struct OpaqueSimValue {
| ^^^^^^^^^^^^^^
note: required because it appears within the type `value::SimValueInner<()>`
--> src/sim/value.rs
|
| struct SimValueInner<T: Type> {
| ^^^^^^^^^^^^^
note: required because it appears within the type `UnsafeCell<value::SimValueInner<()>>`
--> $RUST/core/src/cell.rs
|
| pub struct UnsafeCell<T: ?Sized> {
| ^^^^^^^^^^
note: required because it appears within the type `util::alternating_cell::AlternatingCell<value::SimValueInner<()>>`
--> src/util/alternating_cell.rs
|
| pub(crate) struct AlternatingCell<T: ?Sized> {
| ^^^^^^^^^^^^^^^
note: required because it appears within the type `SimValue<()>`
--> src/sim/value.rs
|
| pub struct SimValue<T: Type> {
| ^^^^^^^^
note: required by a bound in `intern_sized`
--> src/intern.rs
|
| pub trait Intern: Any + Send + Sync {
| ^^^^ required by this bound in `Intern::intern_sized`
| fn intern(&self) -> Interned<Self>;
| fn intern_sized(self) -> Interned<Self>
| ------------ required by a bound in this associated function
help: consider dereferencing here
|
12 | Intern::intern_sized(*v)
| +
error[E0277]: `Cell<util::alternating_cell::State>` cannot be shared between threads safely
--> tests/ui/simvalue_is_not_internable.rs:12:5
|
12 | Intern::intern_sized(v)
| ^^^^^^^^^^^^^^^^^^^^^^^ `Cell<util::alternating_cell::State>` cannot be shared between threads safely
|
= help: within `SimValue<()>`, the trait `Sync` is not implemented for `Cell<util::alternating_cell::State>`
= note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock`
note: required because it appears within the type `util::alternating_cell::AlternatingCell<value::SimValueInner<()>>`
--> src/util/alternating_cell.rs
|
| pub(crate) struct AlternatingCell<T: ?Sized> {
| ^^^^^^^^^^^^^^^
note: required because it appears within the type `SimValue<()>`
--> src/sim/value.rs
|
| pub struct SimValue<T: Type> {
| ^^^^^^^^
note: required by a bound in `fayalite::intern::Interned`
--> src/intern.rs
|
| pub struct Interned<T: ?Sized + 'static + Send + Sync> {
| ^^^^ required by this bound in `Interned`
error[E0277]: `UnsafeCell<value::SimValueInner<()>>` cannot be shared between threads safely
--> tests/ui/simvalue_is_not_internable.rs:12:5
|
12 | Intern::intern_sized(v)
| ^^^^^^^^^^^^^^^^^^^^^^^ `UnsafeCell<value::SimValueInner<()>>` cannot be shared between threads safely
|
= help: within `SimValue<()>`, the trait `Sync` is not implemented for `UnsafeCell<value::SimValueInner<()>>`
note: required because it appears within the type `util::alternating_cell::AlternatingCell<value::SimValueInner<()>>`
--> src/util/alternating_cell.rs
|
| pub(crate) struct AlternatingCell<T: ?Sized> {
| ^^^^^^^^^^^^^^^
note: required because it appears within the type `SimValue<()>`
--> src/sim/value.rs
|
| pub struct SimValue<T: Type> {
| ^^^^^^^^
note: required by a bound in `fayalite::intern::Interned`
--> src/intern.rs
|
| pub struct Interned<T: ?Sized + 'static + Send + Sync> {
| ^^^^ required by this bound in `Interned`
error[E0277]: `Rc<(dyn value::sim_only_value_unsafe::DynSimOnlyValueTrait + 'static)>` cannot be sent between threads safely
--> tests/ui/simvalue_is_not_internable.rs:12:5
|
12 | Intern::intern_sized(v)
| ^^^^^^^^^^^^^^^^^^^^^^^ `Rc<(dyn value::sim_only_value_unsafe::DynSimOnlyValueTrait + 'static)>` cannot be sent between threads safely
|
= help: within `SimValue<()>`, the trait `Send` is not implemented for `Rc<(dyn value::sim_only_value_unsafe::DynSimOnlyValueTrait + 'static)>`
note: required because it appears within the type `DynSimOnlyValue`
--> src/sim/value/sim_only_value_unsafe.rs
|
| pub struct DynSimOnlyValue(Rc<dyn DynSimOnlyValueTrait>);
| ^^^^^^^^^^^^^^^
note: required because it appears within the type `PhantomData<DynSimOnlyValue>`
--> $RUST/core/src/marker.rs
|
| pub struct PhantomData<T: PointeeSized>;
| ^^^^^^^^^^^
note: required because it appears within the type `alloc::raw_vec::RawVec<DynSimOnlyValue>`
--> $RUST/alloc/src/raw_vec/mod.rs
|
| pub(crate) struct RawVec<T, A: Allocator = Global> {
| ^^^^^^
note: required because it appears within the type `Vec<DynSimOnlyValue>`
--> $RUST/alloc/src/vec/mod.rs
|
| pub struct Vec<T, #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global> {
| ^^^
note: required because it appears within the type `OpaqueSimValue`
--> src/ty.rs
|
| pub struct OpaqueSimValue {
| ^^^^^^^^^^^^^^
note: required because it appears within the type `value::SimValueInner<()>`
--> src/sim/value.rs
|
| struct SimValueInner<T: Type> {
| ^^^^^^^^^^^^^
note: required because it appears within the type `UnsafeCell<value::SimValueInner<()>>`
--> $RUST/core/src/cell.rs
|
| pub struct UnsafeCell<T: ?Sized> {
| ^^^^^^^^^^
note: required because it appears within the type `util::alternating_cell::AlternatingCell<value::SimValueInner<()>>`
--> src/util/alternating_cell.rs
|
| pub(crate) struct AlternatingCell<T: ?Sized> {
| ^^^^^^^^^^^^^^^
note: required because it appears within the type `SimValue<()>`
--> src/sim/value.rs
|
| pub struct SimValue<T: Type> {
| ^^^^^^^^
note: required by a bound in `fayalite::intern::Interned`
--> src/intern.rs
|
| pub struct Interned<T: ?Sized + 'static + Send + Sync> {
| ^^^^ required by this bound in `Interned`

View file

@ -49,9 +49,7 @@
"AsyncReset": "Visible", "AsyncReset": "Visible",
"SyncReset": "Visible", "SyncReset": "Visible",
"Reset": "Visible", "Reset": "Visible",
"Clock": "Visible", "Clock": "Visible"
"PhantomConst": "Visible",
"DynSimOnly": "Visible"
} }
}, },
"Bundle": { "Bundle": {
@ -161,8 +159,7 @@
"data": { "data": {
"$kind": "Struct", "$kind": "Struct",
"verilog_name": "Visible", "verilog_name": "Visible",
"parameters": "Visible", "parameters": "Visible"
"simulation": "Visible"
} }
}, },
"ExternModuleParameter": { "ExternModuleParameter": {
@ -1265,22 +1262,6 @@
"ArrayElement": "Visible", "ArrayElement": "Visible",
"DynArrayElement": "Visible" "DynArrayElement": "Visible"
} }
},
"PhantomConst": {
"data": {
"$kind": "Opaque"
},
"generics": "<T: ?Sized + crate::phantom_const::PhantomConstValue>"
},
"DynSimOnly": {
"data": {
"$kind": "Opaque"
}
},
"ExternModuleSimulation": {
"data": {
"$kind": "ManualImpl"
}
} }
} }
} }