This commit is contained in:
parent
def406ab52
commit
3f5dd61e46
10 changed files with 1468 additions and 218 deletions
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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,
|
||||||
};
|
};
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
1146
crates/fayalite/src/platform.rs
Normal file
1146
crates/fayalite/src/platform.rs
Normal file
File diff suppressed because it is too large
Load diff
|
@ -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()
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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]
|
||||||
|
",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
|
@ -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() {}
|
||||||
|
|
|
@ -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);
|
||||||
|
| ^^^^^^^^^^^^^^^
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue