WIP adding Platform
All checks were successful
/ test (pull_request) Successful in 4m28s

This commit is contained in:
Jacob Lifshay 2025-10-17 05:52:56 -07:00
parent def406ab52
commit 3f5dd61e46
Signed by: programmerjake
SSH key fingerprint: SHA256:HnFTLGpSm4Q4Fj502oCFisjZSoakwEuTsJJMSke63RQ
10 changed files with 1468 additions and 218 deletions

View file

@ -66,6 +66,7 @@ mod kw {
} }
custom_keyword!(__evaluated_cfgs); custom_keyword!(__evaluated_cfgs);
custom_keyword!(add_platform_io);
custom_keyword!(all); custom_keyword!(all);
custom_keyword!(any); custom_keyword!(any);
custom_keyword!(cfg); custom_keyword!(cfg);

View file

@ -4,7 +4,7 @@ use crate::{
Errors, HdlAttr, PairsIterExt, 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, ModuleIOOrAddPlatformIO},
options, options,
}; };
use proc_macro2::TokenStream; use proc_macro2::TokenStream;
@ -39,7 +39,7 @@ pub(crate) fn check_name_conflicts_with_module_builder(name: &Ident) -> syn::Res
if name == "m" { if name == "m" {
Err(Error::new_spanned( Err(Error::new_spanned(
name, name,
"name conflicts with implicit `m: &mut ModuleBuilder<_>`", "name conflicts with implicit `m: &ModuleBuilder`",
)) ))
} else { } else {
Ok(()) Ok(())
@ -67,7 +67,7 @@ struct ModuleFnModule {
vis: Visibility, vis: Visibility,
sig: Signature, sig: Signature,
block: Box<Block>, block: Box<Block>,
struct_generics: ParsedGenerics, struct_generics: Option<ParsedGenerics>,
the_struct: TokenStream, the_struct: TokenStream,
} }
@ -290,7 +290,7 @@ impl ModuleFn {
paren_token, paren_token,
body, body,
} => { } => {
debug_assert!(io.is_empty()); debug_assert!(matches!(io, ModuleIOOrAddPlatformIO::ModuleIO(v) if v.is_empty()));
return Ok(Self(ModuleFnImpl::Fn { return Ok(Self(ModuleFnImpl::Fn {
attrs, attrs,
config_options: HdlAttr { config_options: HdlAttr {
@ -322,6 +322,21 @@ impl ModuleFn {
body, body,
}, },
}; };
let io = match io {
ModuleIOOrAddPlatformIO::ModuleIO(io) => io,
ModuleIOOrAddPlatformIO::AddPlatformIO => {
return Ok(Self(ModuleFnImpl::Module(ModuleFnModule {
attrs,
config_options,
module_kind: module_kind.unwrap(),
vis,
sig,
block,
struct_generics: None,
the_struct: TokenStream::new(),
})));
}
};
let (_struct_impl_generics, _struct_type_generics, struct_where_clause) = let (_struct_impl_generics, _struct_type_generics, struct_where_clause) =
struct_generics.split_for_impl(); struct_generics.split_for_impl();
let struct_where_clause: Option<WhereClause> = parse_quote! { #struct_where_clause }; let struct_where_clause: Option<WhereClause> = parse_quote! { #struct_where_clause };
@ -364,7 +379,7 @@ impl ModuleFn {
vis, vis,
sig, sig,
block, block,
struct_generics, struct_generics: Some(struct_generics),
the_struct, the_struct,
}))) })))
} }
@ -433,9 +448,14 @@ impl ModuleFn {
ModuleKind::Normal => quote! { ::fayalite::module::ModuleKind::Normal }, ModuleKind::Normal => quote! { ::fayalite::module::ModuleKind::Normal },
}; };
let fn_name = &outer_sig.ident; let fn_name = &outer_sig.ident;
let (_struct_impl_generics, struct_type_generics, _struct_where_clause) = let struct_ty = match struct_generics {
struct_generics.split_for_impl(); Some(struct_generics) => {
let struct_ty = quote! {#fn_name #struct_type_generics}; let (_struct_impl_generics, struct_type_generics, _struct_where_clause) =
struct_generics.split_for_impl();
quote! {#fn_name #struct_type_generics}
}
None => quote! {::fayalite::bundle::Bundle},
};
body_sig.ident = parse_quote! {__body}; body_sig.ident = parse_quote! {__body};
body_sig body_sig
.inputs .inputs

View file

@ -39,6 +39,7 @@ options! {
pub(crate) enum LetFnKind { pub(crate) enum LetFnKind {
Input(input), Input(input),
Output(output), Output(output),
AddPlatformIO(add_platform_io),
Instance(instance), Instance(instance),
RegBuilder(reg_builder), RegBuilder(reg_builder),
Wire(wire), Wire(wire),
@ -216,6 +217,49 @@ impl HdlLetKindToTokens for HdlLetKindInstance {
} }
} }
#[derive(Clone, Debug)]
pub(crate) struct HdlLetKindAddPlatformIO {
pub(crate) m: kw::m,
pub(crate) dot_token: Token![.],
pub(crate) add_platform_io: kw::add_platform_io,
pub(crate) paren: Paren,
pub(crate) platform_io_builder: Box<Expr>,
}
impl ParseTypes<Self> for HdlLetKindAddPlatformIO {
fn parse_types(input: &mut Self, _parser: &mut TypesParser<'_>) -> Result<Self, ParseFailed> {
Ok(input.clone())
}
}
impl_fold! {
struct HdlLetKindAddPlatformIO<> {
m: kw::m,
dot_token: Token![.],
add_platform_io: kw::add_platform_io,
paren: Paren,
platform_io_builder: Box<Expr>,
}
}
impl HdlLetKindToTokens for HdlLetKindAddPlatformIO {
fn ty_to_tokens(&self, _tokens: &mut TokenStream) {}
fn expr_to_tokens(&self, tokens: &mut TokenStream) {
let Self {
m,
dot_token,
add_platform_io,
paren,
platform_io_builder,
} = self;
m.to_tokens(tokens);
dot_token.to_tokens(tokens);
add_platform_io.to_tokens(tokens);
paren.surround(tokens, |tokens| platform_io_builder.to_tokens(tokens));
}
}
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub(crate) struct RegBuilderClockDomain { pub(crate) struct RegBuilderClockDomain {
pub(crate) dot_token: Token![.], pub(crate) dot_token: Token![.],
@ -711,6 +755,7 @@ impl HdlLetKindMemory {
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub(crate) enum HdlLetKind<IOType = ParsedType> { pub(crate) enum HdlLetKind<IOType = ParsedType> {
IO(HdlLetKindIO<ModuleIOKind, IOType>), IO(HdlLetKindIO<ModuleIOKind, IOType>),
AddPlatformIO(HdlLetKindAddPlatformIO),
Incomplete(HdlLetKindIncomplete), Incomplete(HdlLetKindIncomplete),
Instance(HdlLetKindInstance), Instance(HdlLetKindInstance),
RegBuilder(HdlLetKindRegBuilder), RegBuilder(HdlLetKindRegBuilder),
@ -721,6 +766,7 @@ pub(crate) enum HdlLetKind<IOType = ParsedType> {
impl_fold! { impl_fold! {
enum HdlLetKind<IOType,> { enum HdlLetKind<IOType,> {
IO(HdlLetKindIO<ModuleIOKind, IOType>), IO(HdlLetKindIO<ModuleIOKind, IOType>),
AddPlatformIO(HdlLetKindAddPlatformIO),
Incomplete(HdlLetKindIncomplete), Incomplete(HdlLetKindIncomplete),
Instance(HdlLetKindInstance), Instance(HdlLetKindInstance),
RegBuilder(HdlLetKindRegBuilder), RegBuilder(HdlLetKindRegBuilder),
@ -736,6 +782,9 @@ impl<T: ParseTypes<I>, I> ParseTypes<HdlLetKind<I>> for HdlLetKind<T> {
) -> Result<Self, ParseFailed> { ) -> Result<Self, ParseFailed> {
match input { match input {
HdlLetKind::IO(input) => ParseTypes::parse_types(input, parser).map(HdlLetKind::IO), HdlLetKind::IO(input) => ParseTypes::parse_types(input, parser).map(HdlLetKind::IO),
HdlLetKind::AddPlatformIO(input) => {
ParseTypes::parse_types(input, parser).map(HdlLetKind::AddPlatformIO)
}
HdlLetKind::Incomplete(input) => { HdlLetKind::Incomplete(input) => {
ParseTypes::parse_types(input, parser).map(HdlLetKind::Incomplete) ParseTypes::parse_types(input, parser).map(HdlLetKind::Incomplete)
} }
@ -861,6 +910,23 @@ impl HdlLetKindParse for HdlLetKind<Type> {
ModuleIOKind::Output(output), ModuleIOKind::Output(output),
) )
.map(Self::IO), .map(Self::IO),
LetFnKind::AddPlatformIO((add_platform_io,)) => {
if let Some(parsed_ty) = parsed_ty {
return Err(Error::new_spanned(
parsed_ty.1,
"type annotation not allowed for instance",
));
}
let (m, dot_token) = unwrap_m_dot(m_dot, kind)?;
let paren_contents;
Ok(Self::AddPlatformIO(HdlLetKindAddPlatformIO {
m,
dot_token,
add_platform_io,
paren: parenthesized!(paren_contents in input),
platform_io_builder: paren_contents.call(parse_single_fn_arg)?,
}))
}
LetFnKind::Instance((instance,)) => { LetFnKind::Instance((instance,)) => {
if let Some(parsed_ty) = parsed_ty { if let Some(parsed_ty) = parsed_ty {
return Err(Error::new_spanned( return Err(Error::new_spanned(
@ -936,6 +1002,7 @@ impl HdlLetKindToTokens for HdlLetKind {
fn ty_to_tokens(&self, tokens: &mut TokenStream) { fn ty_to_tokens(&self, tokens: &mut TokenStream) {
match self { match self {
HdlLetKind::IO(v) => v.ty_to_tokens(tokens), HdlLetKind::IO(v) => v.ty_to_tokens(tokens),
HdlLetKind::AddPlatformIO(v) => v.ty_to_tokens(tokens),
HdlLetKind::Incomplete(v) => v.ty_to_tokens(tokens), HdlLetKind::Incomplete(v) => v.ty_to_tokens(tokens),
HdlLetKind::Instance(v) => v.ty_to_tokens(tokens), HdlLetKind::Instance(v) => v.ty_to_tokens(tokens),
HdlLetKind::RegBuilder(v) => v.ty_to_tokens(tokens), HdlLetKind::RegBuilder(v) => v.ty_to_tokens(tokens),
@ -947,6 +1014,7 @@ impl HdlLetKindToTokens for HdlLetKind {
fn expr_to_tokens(&self, tokens: &mut TokenStream) { fn expr_to_tokens(&self, tokens: &mut TokenStream) {
match self { match self {
HdlLetKind::IO(v) => v.expr_to_tokens(tokens), HdlLetKind::IO(v) => v.expr_to_tokens(tokens),
HdlLetKind::AddPlatformIO(v) => v.expr_to_tokens(tokens),
HdlLetKind::Incomplete(v) => v.expr_to_tokens(tokens), HdlLetKind::Incomplete(v) => v.expr_to_tokens(tokens),
HdlLetKind::Instance(v) => v.expr_to_tokens(tokens), HdlLetKind::Instance(v) => v.expr_to_tokens(tokens),
HdlLetKind::RegBuilder(v) => v.expr_to_tokens(tokens), HdlLetKind::RegBuilder(v) => v.expr_to_tokens(tokens),
@ -1149,7 +1217,7 @@ impl<T: ToString> ToTokens for ImplicitName<T> {
struct Visitor<'a> { struct Visitor<'a> {
module_kind: Option<ModuleKind>, module_kind: Option<ModuleKind>,
errors: Errors, errors: Errors,
io: Vec<ModuleIO>, io: ModuleIOOrAddPlatformIO,
block_depth: usize, block_depth: usize,
parsed_generics: &'a ParsedGenerics, parsed_generics: &'a ParsedGenerics,
} }
@ -1289,7 +1357,81 @@ impl Visitor<'_> {
}), }),
semi_token: hdl_let.semi_token, semi_token: hdl_let.semi_token,
}; };
self.io.push(hdl_let); match &mut self.io {
ModuleIOOrAddPlatformIO::ModuleIO(io) => io.push(hdl_let),
ModuleIOOrAddPlatformIO::AddPlatformIO => {
self.errors.error(
kind,
"can't have other inputs/outputs in a module using m.add_platform_io()",
);
}
}
let_stmt
}
fn process_hdl_let_add_platform_io(
&mut self,
hdl_let: HdlLet<HdlLetKindAddPlatformIO>,
) -> Local {
let HdlLet {
mut attrs,
hdl_attr: _,
let_token,
mut_token,
ref name,
eq_token,
kind:
HdlLetKindAddPlatformIO {
m,
dot_token,
add_platform_io,
paren,
platform_io_builder,
},
semi_token,
} = hdl_let;
let mut expr = quote! {#m #dot_token #add_platform_io};
paren.surround(&mut expr, |expr| {
let name_str = ImplicitName {
name,
span: name.span(),
};
quote_spanned! {name.span()=>
#name_str, #platform_io_builder
}
.to_tokens(expr);
});
self.require_module(add_platform_io);
attrs.push(parse_quote_spanned! {let_token.span=>
#[allow(unused_variables)]
});
let let_stmt = Local {
attrs,
let_token,
pat: parse_quote! { #mut_token #name },
init: Some(LocalInit {
eq_token,
expr: parse_quote! { #expr },
diverge: None,
}),
semi_token,
};
match &mut self.io {
ModuleIOOrAddPlatformIO::ModuleIO(io) => {
for io in io {
self.errors.error(
io.kind.kind,
"can't have other inputs/outputs in a module using m.add_platform_io()",
);
}
}
ModuleIOOrAddPlatformIO::AddPlatformIO => {
self.errors.error(
add_platform_io,
"can't use m.add_platform_io() more than once in a single module",
);
}
}
self.io = ModuleIOOrAddPlatformIO::AddPlatformIO;
let_stmt let_stmt
} }
fn process_hdl_let_instance(&mut self, hdl_let: HdlLet<HdlLetKindInstance>) -> Local { fn process_hdl_let_instance(&mut self, hdl_let: HdlLet<HdlLetKindInstance>) -> Local {
@ -1510,6 +1652,7 @@ impl Visitor<'_> {
} }
the_match! { the_match! {
IO => process_hdl_let_io, IO => process_hdl_let_io,
AddPlatformIO => process_hdl_let_add_platform_io,
Incomplete => process_hdl_let_incomplete, Incomplete => process_hdl_let_incomplete,
Instance => process_hdl_let_instance, Instance => process_hdl_let_instance,
RegBuilder => process_hdl_let_reg_builder, RegBuilder => process_hdl_let_reg_builder,
@ -1753,15 +1896,20 @@ impl Fold for Visitor<'_> {
} }
} }
pub(crate) enum ModuleIOOrAddPlatformIO {
ModuleIO(Vec<ModuleIO>),
AddPlatformIO,
}
pub(crate) fn transform_body( pub(crate) fn transform_body(
module_kind: Option<ModuleKind>, module_kind: Option<ModuleKind>,
mut body: Box<Block>, mut body: Box<Block>,
parsed_generics: &ParsedGenerics, parsed_generics: &ParsedGenerics,
) -> syn::Result<(Box<Block>, Vec<ModuleIO>)> { ) -> syn::Result<(Box<Block>, ModuleIOOrAddPlatformIO)> {
let mut visitor = Visitor { let mut visitor = Visitor {
module_kind, module_kind,
errors: Errors::new(), errors: Errors::new(),
io: vec![], io: ModuleIOOrAddPlatformIO::ModuleIO(vec![]),
block_depth: 0, block_depth: 0,
parsed_generics, parsed_generics,
}; };

View file

@ -99,12 +99,12 @@ pub mod intern;
pub mod memory; pub mod memory;
pub mod module; pub mod module;
pub mod phantom_const; pub mod phantom_const;
pub mod platform;
pub mod prelude; pub mod prelude;
pub mod reg; pub mod reg;
pub mod reset; pub mod reset;
pub mod sim; pub mod sim;
pub mod source_location; pub mod source_location;
pub mod target;
pub mod testing; pub mod testing;
pub mod ty; pub mod ty;
pub mod util; pub mod util;

View file

@ -19,6 +19,7 @@ use crate::{
int::{Bool, DynSize, Size}, int::{Bool, DynSize, Size},
intern::{Intern, Interned}, intern::{Intern, Interned},
memory::{Mem, MemBuilder, MemBuilderTarget, PortName}, memory::{Mem, MemBuilder, MemBuilderTarget, PortName},
platform::PlatformIOBuilder,
reg::Reg, reg::Reg,
reset::{AsyncReset, Reset, ResetType, ResetTypeDispatch, SyncReset}, reset::{AsyncReset, Reset, ResetType, ResetTypeDispatch, SyncReset},
sim::{ExternModuleSimGenerator, ExternModuleSimulation}, sim::{ExternModuleSimGenerator, ExternModuleSimulation},
@ -2119,6 +2120,27 @@ impl ModuleBuilder {
self.output_with_loc(implicit_name.0, SourceLocation::caller(), ty) self.output_with_loc(implicit_name.0, SourceLocation::caller(), ty)
} }
#[track_caller] #[track_caller]
pub fn add_platform_io_with_loc(
&self,
name: &str,
source_location: SourceLocation,
platform_io_builder: PlatformIOBuilder<'_>,
) -> Expr<Bundle> {
platform_io_builder.add_platform_io(name, source_location, self)
}
#[track_caller]
pub fn add_platform_io(
&self,
implicit_name: ImplicitName<'_>,
platform_io_builder: PlatformIOBuilder<'_>,
) -> Expr<Bundle> {
self.add_platform_io_with_loc(
implicit_name.0,
SourceLocation::caller(),
platform_io_builder,
)
}
#[track_caller]
pub fn run<T: BundleType>( pub fn run<T: BundleType>(
name: &str, name: &str,
module_kind: ModuleKind, module_kind: ModuleKind,
@ -2743,6 +2765,22 @@ impl<T: Type> ModuleIO<T> {
source_location, source_location,
} }
} }
pub fn from_canonical(canonical_module_io: ModuleIO<CanonicalType>) -> Self {
let ModuleIO {
containing_module_name,
bundle_field,
id,
ty,
source_location,
} = canonical_module_io;
Self {
containing_module_name,
bundle_field,
id,
ty: T::from_canonical(ty),
source_location,
}
}
pub fn bundle_field(&self) -> BundleField { pub fn bundle_field(&self) -> BundleField {
self.bundle_field self.bundle_field
} }

File diff suppressed because it is too large Load diff

View file

@ -1,202 +0,0 @@
// SPDX-License-Identifier: LGPL-3.0-or-later
// See Notices.txt for copyright information
use crate::{intern::Interned, util::job_server::AcquiredJob};
use std::{
any::Any,
fmt,
iter::FusedIterator,
sync::{Arc, Mutex},
};
pub trait Peripheral: Any + Send + Sync + fmt::Debug {}
pub trait Tool: Any + Send + Sync + fmt::Debug {
fn name(&self) -> Interned<str>;
fn run(&self, acquired_job: &mut AcquiredJob);
}
pub trait Target: Any + Send + Sync + fmt::Debug {
fn name(&self) -> Interned<str>;
fn peripherals(&self) -> Interned<[Interned<dyn Peripheral>]>;
}
#[derive(Clone)]
struct TargetsMap(Vec<(Interned<str>, Interned<dyn Target>)>);
impl TargetsMap {
fn sort(&mut self) {
self.0.sort_by(|(k1, _), (k2, _)| str::cmp(k1, k2));
self.0.dedup_by_key(|(k, _)| *k);
}
fn from_unsorted_vec(unsorted_vec: Vec<(Interned<str>, Interned<dyn Target>)>) -> Self {
let mut retval = Self(unsorted_vec);
retval.sort();
retval
}
fn extend_from_unsorted_slice(&mut self, additional: &[(Interned<str>, Interned<dyn Target>)]) {
self.0.extend_from_slice(additional);
self.sort();
}
}
impl Default for TargetsMap {
fn default() -> Self {
Self::from_unsorted_vec(vec![
// TODO: add default targets here
])
}
}
fn access_targets<F: FnOnce(&mut Option<Arc<TargetsMap>>) -> R, R>(f: F) -> R {
static TARGETS: Mutex<Option<Arc<TargetsMap>>> = Mutex::new(None);
let mut targets_lock = TARGETS.lock().expect("shouldn't be poisoned");
f(&mut targets_lock)
}
pub fn add_targets<I: IntoIterator<Item = Interned<dyn Target>>>(additional: I) {
// run iterator and target methods outside of lock
let additional = Vec::from_iter(additional.into_iter().map(|v| (v.name(), v)));
access_targets(|targets| {
Arc::make_mut(targets.get_or_insert_default()).extend_from_unsorted_slice(&additional);
});
}
pub fn targets() -> TargetsSnapshot {
access_targets(|targets| match targets {
Some(targets) => TargetsSnapshot {
targets: targets.clone(),
},
None => {
let new_targets = Arc::<TargetsMap>::default();
*targets = Some(new_targets.clone());
TargetsSnapshot {
targets: new_targets,
}
}
})
}
#[derive(Clone)]
pub struct TargetsSnapshot {
targets: Arc<TargetsMap>,
}
impl TargetsSnapshot {
pub fn get(&self, key: &str) -> Option<Interned<dyn Target>> {
let index = self
.targets
.0
.binary_search_by_key(&key, |(k, _v)| k)
.ok()?;
Some(self.targets.0[index].1)
}
pub fn iter(&self) -> TargetsIter {
self.into_iter()
}
pub fn len(&self) -> usize {
self.targets.0.len()
}
}
impl fmt::Debug for TargetsSnapshot {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("TargetsSnapshot ")?;
f.debug_map().entries(self).finish()
}
}
impl IntoIterator for &'_ mut TargetsSnapshot {
type Item = (Interned<str>, Interned<dyn Target>);
type IntoIter = TargetsIter;
fn into_iter(self) -> Self::IntoIter {
self.clone().into_iter()
}
}
impl IntoIterator for &'_ TargetsSnapshot {
type Item = (Interned<str>, Interned<dyn Target>);
type IntoIter = TargetsIter;
fn into_iter(self) -> Self::IntoIter {
self.clone().into_iter()
}
}
impl IntoIterator for TargetsSnapshot {
type Item = (Interned<str>, Interned<dyn Target>);
type IntoIter = TargetsIter;
fn into_iter(self) -> Self::IntoIter {
TargetsIter {
indexes: 0..self.targets.0.len(),
targets: self.targets,
}
}
}
#[derive(Clone)]
pub struct TargetsIter {
targets: Arc<TargetsMap>,
indexes: std::ops::Range<usize>,
}
impl fmt::Debug for TargetsIter {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("TargetsIter ")?;
f.debug_map().entries(self.clone()).finish()
}
}
impl Iterator for TargetsIter {
type Item = (Interned<str>, Interned<dyn Target>);
fn next(&mut self) -> Option<Self::Item> {
Some(self.targets.0[self.indexes.next()?])
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.indexes.size_hint()
}
fn count(self) -> usize {
self.indexes.len()
}
fn last(mut self) -> Option<Self::Item> {
self.next_back()
}
fn nth(&mut self, n: usize) -> Option<Self::Item> {
Some(self.targets.0[self.indexes.nth(n)?])
}
fn fold<B, F: FnMut(B, Self::Item) -> B>(self, init: B, mut f: F) -> B {
self.indexes
.fold(init, move |retval, index| f(retval, self.targets.0[index]))
}
}
impl FusedIterator for TargetsIter {}
impl DoubleEndedIterator for TargetsIter {
fn next_back(&mut self) -> Option<Self::Item> {
Some(self.targets.0[self.indexes.next_back()?])
}
fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
Some(self.targets.0[self.indexes.nth_back(n)?])
}
fn rfold<B, F: FnMut(B, Self::Item) -> B>(self, init: B, mut f: F) -> B {
self.indexes
.rfold(init, move |retval, index| f(retval, self.targets.0[index]))
}
}
impl ExactSizeIterator for TargetsIter {
fn len(&self) -> usize {
self.indexes.len()
}
}

View file

@ -6,6 +6,7 @@ use fayalite::{
int::{UIntInRange, UIntInRangeInclusive}, int::{UIntInRange, UIntInRangeInclusive},
intern::Intern, intern::Intern,
module::transform::simplify_enums::SimplifyEnumsKind, module::transform::simplify_enums::SimplifyEnumsKind,
platform::PlatformIOBuilder,
prelude::*, prelude::*,
reset::ResetType, reset::ResetType,
ty::StaticType, ty::StaticType,
@ -4631,3 +4632,55 @@ circuit check_uint_in_range:
", ",
}; };
} }
#[hdl_module(outline_generated)]
pub fn check_platform_io(platform_io_builder: PlatformIOBuilder<'_>) {
#[hdl]
let io = m.add_platform_io(platform_io_builder);
}
#[cfg(todo)]
#[test]
fn test_platform_io() {
let _n = SourceLocation::normalize_files_for_tests();
let m = check_platform_io(todo!());
dbg!(m);
#[rustfmt::skip] // work around https://github.com/rust-lang/rustfmt/issues/6161
assert_export_firrtl! {
m =>
"/test/check_platform_io.fir": r"FIRRTL version 3.2.0
circuit check_platform_io:
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_platform_io: @[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]
",
};
}

View file

@ -11,4 +11,20 @@ pub fn my_module(a: i32, m: u32, (m, _): (i32, u32)) {
let o: UInt<8> = m.output(); let o: UInt<8> = m.output();
} }
#[hdl_module]
pub fn my_module2(platform_io_builder: PlatformIOBuilder<'_>) {
#[hdl]
let a: UInt<8> = m.input();
#[hdl]
let b: UInt<8> = m.output();
#[hdl]
let io = m.add_platform_io(platform_io_builder);
#[hdl]
let c: UInt<8> = m.input();
#[hdl]
let d: UInt<8> = m.output();
#[hdl]
let io = m.add_platform_io(platform_io_builder);
}
fn main() {} fn main() {}

View file

@ -1,17 +1,47 @@
error: name conflicts with implicit `m: &mut ModuleBuilder<_>` error: name conflicts with implicit `m: &ModuleBuilder`
--> tests/ui/module.rs:7:26 --> tests/ui/module.rs:7:26
| |
7 | pub fn my_module(a: i32, m: u32, (m, _): (i32, u32)) { 7 | pub fn my_module(a: i32, m: u32, (m, _): (i32, u32)) {
| ^ | ^
error: name conflicts with implicit `m: &mut ModuleBuilder<_>` error: name conflicts with implicit `m: &ModuleBuilder`
--> tests/ui/module.rs:7:35 --> tests/ui/module.rs:7:35
| |
7 | pub fn my_module(a: i32, m: u32, (m, _): (i32, u32)) { 7 | pub fn my_module(a: i32, m: u32, (m, _): (i32, u32)) {
| ^ | ^
error: name conflicts with implicit `m: &mut ModuleBuilder<_>` error: name conflicts with implicit `m: &ModuleBuilder`
--> tests/ui/module.rs:9:9 --> tests/ui/module.rs:9:9
| |
9 | let m: UInt<8> = m.input(); 9 | let m: UInt<8> = m.input();
| ^ | ^
error: can't have other inputs/outputs in a module using m.add_platform_io()
--> tests/ui/module.rs:17:24
|
17 | let a: UInt<8> = m.input();
| ^^^^^
error: can't have other inputs/outputs in a module using m.add_platform_io()
--> tests/ui/module.rs:19:24
|
19 | let b: UInt<8> = m.output();
| ^^^^^^
error: can't have other inputs/outputs in a module using m.add_platform_io()
--> tests/ui/module.rs:23:24
|
23 | let c: UInt<8> = m.input();
| ^^^^^
error: can't have other inputs/outputs in a module using m.add_platform_io()
--> tests/ui/module.rs:25:24
|
25 | let d: UInt<8> = m.output();
| ^^^^^^
error: can't use m.add_platform_io() more than once in a single module
--> tests/ui/module.rs:27:16
|
27 | let io = m.add_platform_io(platform_io_builder);
| ^^^^^^^^^^^^^^^