forked from libre-chip/fayalite
		
	Compare commits
	
		
			11 commits
		
	
	
		
			903ca1bf30
			...
			c16726cee6
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| c16726cee6 | |||
| b63676d0ca | |||
| 7005fa3330 | |||
| 2ab8428062 | |||
| 9b06019bf5 | |||
| 36bad52978 | |||
| 21c73051ec | |||
| 304d8da0e8 | |||
| 2af38de900 | |||
| c756aeec70 | |||
|  | 2e7d685dc7 | 
					 17 changed files with 13276 additions and 513 deletions
				
			
		
							
								
								
									
										8
									
								
								Cargo.lock
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										8
									
								
								Cargo.lock
									
										
									
										generated
									
									
									
								
							|  | @ -543,9 +543,9 @@ dependencies = [ | ||||||
| 
 | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "proc-macro2" | name = "proc-macro2" | ||||||
| version = "1.0.83" | version = "1.0.92" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "0b33eb56c327dec362a9e55b3ad14f9d2f0904fb5a5b03b513ab5465399e9f43" | checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" | ||||||
| dependencies = [ | dependencies = [ | ||||||
|  "unicode-ident", |  "unicode-ident", | ||||||
| ] | ] | ||||||
|  | @ -647,9 +647,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" | ||||||
| 
 | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "syn" | name = "syn" | ||||||
| version = "2.0.66" | version = "2.0.93" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" | checksum = "9c786062daee0d6db1132800e623df74274a0a87322d8e183338e01b3d98d058" | ||||||
| dependencies = [ | dependencies = [ | ||||||
|  "proc-macro2", |  "proc-macro2", | ||||||
|  "quote", |  "quote", | ||||||
|  |  | ||||||
|  | @ -37,7 +37,7 @@ quote = "1.0.36" | ||||||
| serde = { version = "1.0.202", features = ["derive"] } | serde = { version = "1.0.202", features = ["derive"] } | ||||||
| serde_json = { version = "1.0.117", features = ["preserve_order"] } | serde_json = { version = "1.0.117", features = ["preserve_order"] } | ||||||
| sha2 = "0.10.8" | sha2 = "0.10.8" | ||||||
| syn = { version = "2.0.66", features = ["full", "fold", "visit", "extra-traits"] } | syn = { version = "2.0.93", features = ["full", "fold", "visit", "extra-traits"] } | ||||||
| tempfile = "3.10.1" | tempfile = "3.10.1" | ||||||
| thiserror = "1.0.61" | thiserror = "1.0.61" | ||||||
| trybuild = "1.0" | trybuild = "1.0" | ||||||
|  |  | ||||||
|  | @ -3,14 +3,20 @@ | ||||||
| #![cfg_attr(test, recursion_limit = "512")] | #![cfg_attr(test, recursion_limit = "512")] | ||||||
| use proc_macro2::{Span, TokenStream}; | use proc_macro2::{Span, TokenStream}; | ||||||
| use quote::{quote, ToTokens}; | use quote::{quote, ToTokens}; | ||||||
| use std::io::{ErrorKind, Write}; | use std::{ | ||||||
|  |     collections::{hash_map::Entry, HashMap}, | ||||||
|  |     io::{ErrorKind, Write}, | ||||||
|  | }; | ||||||
| use syn::{ | use syn::{ | ||||||
|     bracketed, parenthesized, |     bracketed, | ||||||
|  |     ext::IdentExt, | ||||||
|  |     parenthesized, | ||||||
|     parse::{Parse, ParseStream, Parser}, |     parse::{Parse, ParseStream, Parser}, | ||||||
|     parse_quote, |     parse_quote, | ||||||
|     punctuated::Pair, |     punctuated::{Pair, Punctuated}, | ||||||
|     spanned::Spanned, |     spanned::Spanned, | ||||||
|     AttrStyle, Attribute, Error, Item, ItemFn, Token, |     token::{Bracket, Paren}, | ||||||
|  |     AttrStyle, Attribute, Error, Ident, Item, ItemFn, LitBool, LitStr, Meta, Token, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| mod fold; | mod fold; | ||||||
|  | @ -19,6 +25,7 @@ mod hdl_enum; | ||||||
| mod hdl_type_alias; | mod hdl_type_alias; | ||||||
| mod hdl_type_common; | mod hdl_type_common; | ||||||
| mod module; | mod module; | ||||||
|  | mod process_cfg; | ||||||
| 
 | 
 | ||||||
| pub(crate) trait CustomToken: | pub(crate) trait CustomToken: | ||||||
|     Copy |     Copy | ||||||
|  | @ -59,6 +66,11 @@ mod kw { | ||||||
|         }; |         }; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     custom_keyword!(__evaluated_cfgs); | ||||||
|  |     custom_keyword!(all); | ||||||
|  |     custom_keyword!(any); | ||||||
|  |     custom_keyword!(cfg); | ||||||
|  |     custom_keyword!(cfg_attr); | ||||||
|     custom_keyword!(clock_domain); |     custom_keyword!(clock_domain); | ||||||
|     custom_keyword!(connect_inexact); |     custom_keyword!(connect_inexact); | ||||||
|     custom_keyword!(custom_bounds); |     custom_keyword!(custom_bounds); | ||||||
|  | @ -75,6 +87,7 @@ mod kw { | ||||||
|     custom_keyword!(no_reset); |     custom_keyword!(no_reset); | ||||||
|     custom_keyword!(no_runtime_generics); |     custom_keyword!(no_runtime_generics); | ||||||
|     custom_keyword!(no_static); |     custom_keyword!(no_static); | ||||||
|  |     custom_keyword!(not); | ||||||
|     custom_keyword!(outline_generated); |     custom_keyword!(outline_generated); | ||||||
|     custom_keyword!(output); |     custom_keyword!(output); | ||||||
|     custom_keyword!(reg_builder); |     custom_keyword!(reg_builder); | ||||||
|  | @ -901,15 +914,346 @@ fn hdl_module_impl(item: ItemFn) -> syn::Result<TokenStream> { | ||||||
|     Ok(contents) |     Ok(contents) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub fn hdl_module(attr: TokenStream, item: TokenStream) -> syn::Result<TokenStream> { | #[derive(Clone, PartialEq, Eq, Hash, Debug)] | ||||||
|     let kw = kw::hdl_module::default(); | pub(crate) enum CfgExpr { | ||||||
|     hdl_module_impl(syn::parse2(quote! { #[#kw(#attr)] #item })?) |     Option { | ||||||
|  |         ident: Ident, | ||||||
|  |         value: Option<(Token![=], LitStr)>, | ||||||
|  |     }, | ||||||
|  |     All { | ||||||
|  |         all: kw::all, | ||||||
|  |         paren: Paren, | ||||||
|  |         exprs: Punctuated<CfgExpr, Token![,]>, | ||||||
|  |     }, | ||||||
|  |     Any { | ||||||
|  |         any: kw::any, | ||||||
|  |         paren: Paren, | ||||||
|  |         exprs: Punctuated<CfgExpr, Token![,]>, | ||||||
|  |     }, | ||||||
|  |     Not { | ||||||
|  |         not: kw::not, | ||||||
|  |         paren: Paren, | ||||||
|  |         expr: Box<CfgExpr>, | ||||||
|  |         trailing_comma: Option<Token![,]>, | ||||||
|  |     }, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub fn hdl_attr(attr: TokenStream, item: TokenStream) -> syn::Result<TokenStream> { | impl Parse for CfgExpr { | ||||||
|     let kw = kw::hdl::default(); |     fn parse(input: ParseStream) -> syn::Result<Self> { | ||||||
|     let item = quote! { #[#kw(#attr)] #item }; |         match input.cursor().ident() { | ||||||
|     let item = syn::parse2::<Item>(item)?; |             Some((_, cursor)) if cursor.eof() => { | ||||||
|  |                 return Ok(CfgExpr::Option { | ||||||
|  |                     ident: input.call(Ident::parse_any)?, | ||||||
|  |                     value: None, | ||||||
|  |                 }); | ||||||
|  |             } | ||||||
|  |             _ => {} | ||||||
|  |         } | ||||||
|  |         if input.peek(Ident::peek_any) && input.peek2(Token![=]) { | ||||||
|  |             return Ok(CfgExpr::Option { | ||||||
|  |                 ident: input.call(Ident::parse_any)?, | ||||||
|  |                 value: Some((input.parse()?, input.parse()?)), | ||||||
|  |             }); | ||||||
|  |         } | ||||||
|  |         let contents; | ||||||
|  |         if input.peek(kw::all) { | ||||||
|  |             Ok(CfgExpr::All { | ||||||
|  |                 all: input.parse()?, | ||||||
|  |                 paren: parenthesized!(contents in input), | ||||||
|  |                 exprs: contents.call(Punctuated::parse_terminated)?, | ||||||
|  |             }) | ||||||
|  |         } else if input.peek(kw::any) { | ||||||
|  |             Ok(CfgExpr::Any { | ||||||
|  |                 any: input.parse()?, | ||||||
|  |                 paren: parenthesized!(contents in input), | ||||||
|  |                 exprs: contents.call(Punctuated::parse_terminated)?, | ||||||
|  |             }) | ||||||
|  |         } else if input.peek(kw::not) { | ||||||
|  |             Ok(CfgExpr::Not { | ||||||
|  |                 not: input.parse()?, | ||||||
|  |                 paren: parenthesized!(contents in input), | ||||||
|  |                 expr: contents.parse()?, | ||||||
|  |                 trailing_comma: contents.parse()?, | ||||||
|  |             }) | ||||||
|  |         } else { | ||||||
|  |             Err(input.error("expected cfg-pattern")) | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl ToTokens for CfgExpr { | ||||||
|  |     fn to_tokens(&self, tokens: &mut TokenStream) { | ||||||
|  |         match self { | ||||||
|  |             CfgExpr::Option { ident, value } => { | ||||||
|  |                 ident.to_tokens(tokens); | ||||||
|  |                 if let Some((eq, value)) = value { | ||||||
|  |                     eq.to_tokens(tokens); | ||||||
|  |                     value.to_tokens(tokens); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             CfgExpr::All { all, paren, exprs } => { | ||||||
|  |                 all.to_tokens(tokens); | ||||||
|  |                 paren.surround(tokens, |tokens| exprs.to_tokens(tokens)); | ||||||
|  |             } | ||||||
|  |             CfgExpr::Any { any, paren, exprs } => { | ||||||
|  |                 any.to_tokens(tokens); | ||||||
|  |                 paren.surround(tokens, |tokens| exprs.to_tokens(tokens)); | ||||||
|  |             } | ||||||
|  |             CfgExpr::Not { | ||||||
|  |                 not, | ||||||
|  |                 paren, | ||||||
|  |                 expr, | ||||||
|  |                 trailing_comma, | ||||||
|  |             } => { | ||||||
|  |                 not.to_tokens(tokens); | ||||||
|  |                 paren.surround(tokens, |tokens| { | ||||||
|  |                     expr.to_tokens(tokens); | ||||||
|  |                     trailing_comma.to_tokens(tokens); | ||||||
|  |                 }); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[derive(Clone, PartialEq, Eq, Hash, Debug)] | ||||||
|  | pub(crate) struct Cfg { | ||||||
|  |     cfg: kw::cfg, | ||||||
|  |     paren: Paren, | ||||||
|  |     expr: CfgExpr, | ||||||
|  |     trailing_comma: Option<Token![,]>, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl Cfg { | ||||||
|  |     fn parse_meta(meta: &Meta) -> syn::Result<Self> { | ||||||
|  |         syn::parse2(meta.to_token_stream()) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl ToTokens for Cfg { | ||||||
|  |     fn to_tokens(&self, tokens: &mut TokenStream) { | ||||||
|  |         let Self { | ||||||
|  |             cfg, | ||||||
|  |             paren, | ||||||
|  |             expr, | ||||||
|  |             trailing_comma, | ||||||
|  |         } = self; | ||||||
|  |         cfg.to_tokens(tokens); | ||||||
|  |         paren.surround(tokens, |tokens| { | ||||||
|  |             expr.to_tokens(tokens); | ||||||
|  |             trailing_comma.to_tokens(tokens); | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl Parse for Cfg { | ||||||
|  |     fn parse(input: ParseStream) -> syn::Result<Self> { | ||||||
|  |         let contents; | ||||||
|  |         Ok(Self { | ||||||
|  |             cfg: input.parse()?, | ||||||
|  |             paren: parenthesized!(contents in input), | ||||||
|  |             expr: contents.parse()?, | ||||||
|  |             trailing_comma: contents.parse()?, | ||||||
|  |         }) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[derive(Clone, PartialEq, Eq, Hash, Debug)] | ||||||
|  | pub(crate) struct CfgAttr { | ||||||
|  |     cfg_attr: kw::cfg_attr, | ||||||
|  |     paren: Paren, | ||||||
|  |     expr: CfgExpr, | ||||||
|  |     comma: Token![,], | ||||||
|  |     attrs: Punctuated<Meta, Token![,]>, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl CfgAttr { | ||||||
|  |     pub(crate) fn to_cfg(&self) -> Cfg { | ||||||
|  |         Cfg { | ||||||
|  |             cfg: kw::cfg(self.cfg_attr.span), | ||||||
|  |             paren: self.paren, | ||||||
|  |             expr: self.expr.clone(), | ||||||
|  |             trailing_comma: None, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     fn parse_meta(meta: &Meta) -> syn::Result<Self> { | ||||||
|  |         syn::parse2(meta.to_token_stream()) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl Parse for CfgAttr { | ||||||
|  |     fn parse(input: ParseStream) -> syn::Result<Self> { | ||||||
|  |         let contents; | ||||||
|  |         Ok(Self { | ||||||
|  |             cfg_attr: input.parse()?, | ||||||
|  |             paren: parenthesized!(contents in input), | ||||||
|  |             expr: contents.parse()?, | ||||||
|  |             comma: contents.parse()?, | ||||||
|  |             attrs: contents.call(Punctuated::parse_terminated)?, | ||||||
|  |         }) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | pub(crate) struct CfgAndValue { | ||||||
|  |     cfg: Cfg, | ||||||
|  |     eq_token: Token![=], | ||||||
|  |     value: LitBool, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl Parse for CfgAndValue { | ||||||
|  |     fn parse(input: ParseStream) -> syn::Result<Self> { | ||||||
|  |         Ok(Self { | ||||||
|  |             cfg: input.parse()?, | ||||||
|  |             eq_token: input.parse()?, | ||||||
|  |             value: input.parse()?, | ||||||
|  |         }) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | pub(crate) struct Cfgs<T> { | ||||||
|  |     pub(crate) bracket: Bracket, | ||||||
|  |     pub(crate) cfgs_map: HashMap<Cfg, T>, | ||||||
|  |     pub(crate) cfgs_list: Vec<Cfg>, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<T> Default for Cfgs<T> { | ||||||
|  |     fn default() -> Self { | ||||||
|  |         Self { | ||||||
|  |             bracket: Default::default(), | ||||||
|  |             cfgs_map: Default::default(), | ||||||
|  |             cfgs_list: Default::default(), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<T> Cfgs<T> { | ||||||
|  |     fn insert_cfg(&mut self, cfg: Cfg, value: T) { | ||||||
|  |         match self.cfgs_map.entry(cfg) { | ||||||
|  |             Entry::Occupied(_) => {} | ||||||
|  |             Entry::Vacant(entry) => { | ||||||
|  |                 self.cfgs_list.push(entry.key().clone()); | ||||||
|  |                 entry.insert(value); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl Parse for Cfgs<bool> { | ||||||
|  |     fn parse(input: ParseStream) -> syn::Result<Self> { | ||||||
|  |         let contents; | ||||||
|  |         let bracket = bracketed!(contents in input); | ||||||
|  |         let mut cfgs_map = HashMap::new(); | ||||||
|  |         let mut cfgs_list = Vec::new(); | ||||||
|  |         for CfgAndValue { | ||||||
|  |             cfg, | ||||||
|  |             eq_token, | ||||||
|  |             value, | ||||||
|  |         } in contents.call(Punctuated::<CfgAndValue, Token![,]>::parse_terminated)? | ||||||
|  |         { | ||||||
|  |             let _ = eq_token; | ||||||
|  |             match cfgs_map.entry(cfg) { | ||||||
|  |                 Entry::Occupied(_) => {} | ||||||
|  |                 Entry::Vacant(entry) => { | ||||||
|  |                     cfgs_list.push(entry.key().clone()); | ||||||
|  |                     entry.insert(value.value); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         Ok(Self { | ||||||
|  |             bracket, | ||||||
|  |             cfgs_map, | ||||||
|  |             cfgs_list, | ||||||
|  |         }) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl Parse for Cfgs<()> { | ||||||
|  |     fn parse(input: ParseStream) -> syn::Result<Self> { | ||||||
|  |         let contents; | ||||||
|  |         let bracket = bracketed!(contents in input); | ||||||
|  |         let mut cfgs_map = HashMap::new(); | ||||||
|  |         let mut cfgs_list = Vec::new(); | ||||||
|  |         for cfg in contents.call(Punctuated::<Cfg, Token![,]>::parse_terminated)? { | ||||||
|  |             match cfgs_map.entry(cfg) { | ||||||
|  |                 Entry::Occupied(_) => {} | ||||||
|  |                 Entry::Vacant(entry) => { | ||||||
|  |                     cfgs_list.push(entry.key().clone()); | ||||||
|  |                     entry.insert(()); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         Ok(Self { | ||||||
|  |             bracket, | ||||||
|  |             cfgs_map, | ||||||
|  |             cfgs_list, | ||||||
|  |         }) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl ToTokens for Cfgs<()> { | ||||||
|  |     fn to_tokens(&self, tokens: &mut TokenStream) { | ||||||
|  |         let Self { | ||||||
|  |             bracket, | ||||||
|  |             cfgs_map: _, | ||||||
|  |             cfgs_list, | ||||||
|  |         } = self; | ||||||
|  |         bracket.surround(tokens, |tokens| { | ||||||
|  |             for cfg in cfgs_list { | ||||||
|  |                 cfg.to_tokens(tokens); | ||||||
|  |                 <Token![,]>::default().to_tokens(tokens); | ||||||
|  |             } | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn hdl_main( | ||||||
|  |     kw: impl CustomToken, | ||||||
|  |     attr: TokenStream, | ||||||
|  |     item: TokenStream, | ||||||
|  | ) -> syn::Result<TokenStream> { | ||||||
|  |     fn parse_evaluated_cfgs_attr<R>( | ||||||
|  |         input: ParseStream, | ||||||
|  |         parse_inner: impl FnOnce(ParseStream) -> syn::Result<R>, | ||||||
|  |     ) -> syn::Result<R> { | ||||||
|  |         let _: Token![#] = input.parse()?; | ||||||
|  |         let bracket_content; | ||||||
|  |         bracketed!(bracket_content in input); | ||||||
|  |         let _: kw::__evaluated_cfgs = bracket_content.parse()?; | ||||||
|  |         let paren_content; | ||||||
|  |         parenthesized!(paren_content in bracket_content); | ||||||
|  |         parse_inner(&paren_content) | ||||||
|  |     } | ||||||
|  |     let (evaluated_cfgs, item): (_, TokenStream) = Parser::parse2( | ||||||
|  |         |input: ParseStream| { | ||||||
|  |             let peek = input.fork(); | ||||||
|  |             if parse_evaluated_cfgs_attr(&peek, |_| Ok(())).is_ok() { | ||||||
|  |                 let evaluated_cfgs = parse_evaluated_cfgs_attr(input, Cfgs::<bool>::parse)?; | ||||||
|  |                 Ok((Some(evaluated_cfgs), input.parse()?)) | ||||||
|  |             } else { | ||||||
|  |                 Ok((None, input.parse()?)) | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|  |         item, | ||||||
|  |     )?; | ||||||
|  |     let cfgs = if let Some(cfgs) = evaluated_cfgs { | ||||||
|  |         cfgs | ||||||
|  |     } else { | ||||||
|  |         let cfgs = process_cfg::collect_cfgs(syn::parse2(item.clone())?)?; | ||||||
|  |         if cfgs.cfgs_list.is_empty() { | ||||||
|  |             Cfgs::default() | ||||||
|  |         } else { | ||||||
|  |             return Ok(quote! { | ||||||
|  |                 ::fayalite::__cfg_expansion_helper! { | ||||||
|  |                     [] | ||||||
|  |                     #cfgs | ||||||
|  |                     {#[::fayalite::#kw(#attr)]} { #item } | ||||||
|  |                 } | ||||||
|  |             }); | ||||||
|  |         } | ||||||
|  |     }; | ||||||
|  |     let item = syn::parse2(quote! { #[#kw(#attr)] #item })?; | ||||||
|  |     let Some(item) = process_cfg::process_cfgs(item, cfgs)? else { | ||||||
|  |         return Ok(TokenStream::new()); | ||||||
|  |     }; | ||||||
|     match item { |     match item { | ||||||
|         Item::Enum(item) => hdl_enum::hdl_enum(item), |         Item::Enum(item) => hdl_enum::hdl_enum(item), | ||||||
|         Item::Struct(item) => hdl_bundle::hdl_bundle(item), |         Item::Struct(item) => hdl_bundle::hdl_bundle(item), | ||||||
|  | @ -921,3 +1265,11 @@ pub fn hdl_attr(attr: TokenStream, item: TokenStream) -> syn::Result<TokenStream | ||||||
|         )), |         )), | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | pub fn hdl_module(attr: TokenStream, item: TokenStream) -> syn::Result<TokenStream> { | ||||||
|  |     hdl_main(kw::hdl_module::default(), attr, item) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | pub fn hdl_attr(attr: TokenStream, item: TokenStream) -> syn::Result<TokenStream> { | ||||||
|  |     hdl_main(kw::hdl::default(), attr, item) | ||||||
|  | } | ||||||
|  |  | ||||||
							
								
								
									
										2527
									
								
								crates/fayalite-proc-macros-impl/src/process_cfg.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										2527
									
								
								crates/fayalite-proc-macros-impl/src/process_cfg.rs
									
										
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							|  | @ -5,6 +5,9 @@ use std::{env, fs, path::Path}; | ||||||
| 
 | 
 | ||||||
| fn main() { | fn main() { | ||||||
|     println!("cargo::rustc-check-cfg=cfg(todo)"); |     println!("cargo::rustc-check-cfg=cfg(todo)"); | ||||||
|  |     println!("cargo::rustc-check-cfg=cfg(cfg_false_for_tests)"); | ||||||
|  |     println!("cargo::rustc-check-cfg=cfg(cfg_true_for_tests)"); | ||||||
|  |     println!("cargo::rustc-cfg=cfg_true_for_tests"); | ||||||
|     let path = "visit_types.json"; |     let path = "visit_types.json"; | ||||||
|     println!("cargo::rerun-if-changed={path}"); |     println!("cargo::rerun-if-changed={path}"); | ||||||
|     println!("cargo::rerun-if-changed=build.rs"); |     println!("cargo::rerun-if-changed=build.rs"); | ||||||
|  |  | ||||||
|  | @ -4,12 +4,14 @@ | ||||||
| use crate::{ | use crate::{ | ||||||
|     expr::{ops::BundleLiteral, Expr, ToExpr}, |     expr::{ops::BundleLiteral, Expr, ToExpr}, | ||||||
|     intern::{Intern, Interned}, |     intern::{Intern, Interned}, | ||||||
|  |     sim::{SimValue, ToSimValue}, | ||||||
|     source_location::SourceLocation, |     source_location::SourceLocation, | ||||||
|     ty::{ |     ty::{ | ||||||
|         impl_match_variant_as_self, CanonicalType, MatchVariantWithoutScope, StaticType, Type, |         impl_match_variant_as_self, CanonicalType, MatchVariantWithoutScope, StaticType, Type, | ||||||
|         TypeProperties, TypeWithDeref, |         TypeProperties, TypeWithDeref, | ||||||
|     }, |     }, | ||||||
| }; | }; | ||||||
|  | use bitvec::vec::BitVec; | ||||||
| use hashbrown::HashMap; | use hashbrown::HashMap; | ||||||
| use std::{fmt, marker::PhantomData}; | use std::{fmt, marker::PhantomData}; | ||||||
| 
 | 
 | ||||||
|  | @ -323,7 +325,7 @@ macro_rules! impl_tuple_builder_fields { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| macro_rules! impl_tuples { | macro_rules! impl_tuples { | ||||||
|     ([$({#[num = $num:literal, field = $field:ident] $var:ident: $T:ident})*] []) => { |     ([$({#[num = $num:literal, field = $field:ident, ty = $ty_var:ident: $Ty:ident] $var:ident: $T:ident})*] []) => { | ||||||
|         impl_tuple_builder_fields! { |         impl_tuple_builder_fields! { | ||||||
|             {} |             {} | ||||||
|             [$({ |             [$({ | ||||||
|  | @ -423,6 +425,79 @@ macro_rules! impl_tuples { | ||||||
|                 BundleLiteral::new(ty, field_values[..].intern()).to_expr() |                 BundleLiteral::new(ty, field_values[..].intern()).to_expr() | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |         impl<$($T: ToSimValue<CanonicalType>,)*> ToSimValue<CanonicalType> for ($($T,)*) { | ||||||
|  |             #[track_caller] | ||||||
|  |             fn to_sim_value(&self, ty: CanonicalType) -> SimValue<CanonicalType> { | ||||||
|  |                 ToSimValue::<Bundle>::to_sim_value(self, Bundle::from_canonical(ty)).into_canonical() | ||||||
|  |             } | ||||||
|  |             #[track_caller] | ||||||
|  |             fn into_sim_value(self, ty: CanonicalType) -> SimValue<CanonicalType> | ||||||
|  |             { | ||||||
|  |                 ToSimValue::<Bundle>::into_sim_value(self, Bundle::from_canonical(ty)).into_canonical() | ||||||
|  |             } | ||||||
|  |             #[track_caller] | ||||||
|  |             fn box_into_sim_value(self: Box<Self>, ty: CanonicalType) -> SimValue<CanonicalType> { | ||||||
|  |                 ToSimValue::<Bundle>::box_into_sim_value(self, Bundle::from_canonical(ty)).into_canonical() | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         impl<$($T: ToSimValue<CanonicalType>,)*> ToSimValue<Bundle> for ($($T,)*) { | ||||||
|  |             #[track_caller] | ||||||
|  |             fn to_sim_value(&self, ty: Bundle) -> SimValue<Bundle> { | ||||||
|  |                 let ($($var,)*) = self; | ||||||
|  |                 let [$($ty_var,)*] = *ty.fields() else { | ||||||
|  |                     panic!("bundle has wrong number of fields"); | ||||||
|  |                 }; | ||||||
|  |                 $(let $var = $var.to_sim_value($ty_var.ty);)* | ||||||
|  |                 ToSimValue::into_sim_value(($($var,)*), ty) | ||||||
|  |             } | ||||||
|  |             #[track_caller] | ||||||
|  |             fn into_sim_value(self, ty: Bundle) -> SimValue<Bundle> { | ||||||
|  |                 #![allow(unused_mut)] | ||||||
|  |                 #![allow(clippy::unused_unit)] | ||||||
|  |                 let ($($var,)*) = self; | ||||||
|  |                 let [$($ty_var,)*] = *ty.fields() else { | ||||||
|  |                     panic!("bundle has wrong number of fields"); | ||||||
|  |                 }; | ||||||
|  |                 let mut bits: Option<BitVec> = None; | ||||||
|  |                 $(let $var = $var.into_sim_value($ty_var.ty); | ||||||
|  |                 assert_eq!($var.ty(), $ty_var.ty); | ||||||
|  |                 if !$var.bits().is_empty() { | ||||||
|  |                     if let Some(bits) = &mut bits { | ||||||
|  |                         bits.extend_from_bitslice($var.bits()); | ||||||
|  |                     } else { | ||||||
|  |                         let mut $var = $var.into_bits(); | ||||||
|  |                         $var.reserve(ty.type_properties().bit_width - $var.len()); | ||||||
|  |                         bits = Some($var); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |                 )* | ||||||
|  |                 bits.unwrap_or_else(BitVec::new).into_sim_value(ty) | ||||||
|  |             } | ||||||
|  |             #[track_caller] | ||||||
|  |             fn box_into_sim_value(self: Box<Self>, ty: Bundle) -> SimValue<Bundle> { | ||||||
|  |                 Self::into_sim_value(*self, ty) | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         impl<$($T: ToSimValue<$Ty>, $Ty: Type,)*> ToSimValue<($($Ty,)*)> for ($($T,)*) { | ||||||
|  |             #[track_caller] | ||||||
|  |             fn to_sim_value(&self, ty: ($($Ty,)*)) -> SimValue<($($Ty,)*)> { | ||||||
|  |                 let ($($var,)*) = self; | ||||||
|  |                 let ($($ty_var,)*) = ty; | ||||||
|  |                 $(let $var = $var.to_sim_value($ty_var).into_canonical();)* | ||||||
|  |                 SimValue::from_canonical(ToSimValue::into_sim_value(($($var,)*), ty.canonical())) | ||||||
|  |             } | ||||||
|  |             #[track_caller] | ||||||
|  |             fn into_sim_value(self, ty: ($($Ty,)*)) -> SimValue<($($Ty,)*)> { | ||||||
|  |                 let ($($var,)*) = self; | ||||||
|  |                 let ($($ty_var,)*) = ty; | ||||||
|  |                 $(let $var = $var.into_sim_value($ty_var).into_canonical();)* | ||||||
|  |                 SimValue::from_canonical(ToSimValue::into_sim_value(($($var,)*), ty.canonical())) | ||||||
|  |             } | ||||||
|  |             #[track_caller] | ||||||
|  |             fn box_into_sim_value(self: Box<Self>, ty: ($($Ty,)*)) -> SimValue<($($Ty,)*)> { | ||||||
|  |                 Self::into_sim_value(*self, ty) | ||||||
|  |             } | ||||||
|  |         } | ||||||
|     }; |     }; | ||||||
|     ([$($lhs:tt)*] [$rhs_first:tt $($rhs:tt)*]) => { |     ([$($lhs:tt)*] [$rhs_first:tt $($rhs:tt)*]) => { | ||||||
|         impl_tuples!([$($lhs)*] []); |         impl_tuples!([$($lhs)*] []); | ||||||
|  | @ -432,18 +507,18 @@ macro_rules! impl_tuples { | ||||||
| 
 | 
 | ||||||
| impl_tuples! { | impl_tuples! { | ||||||
|     [] [ |     [] [ | ||||||
|         {#[num = 0, field = field_0] v0: T0} |         {#[num = 0, field = field_0, ty = ty0: Ty0] v0: T0} | ||||||
|         {#[num = 1, field = field_1] v1: T1} |         {#[num = 1, field = field_1, ty = ty1: Ty1] v1: T1} | ||||||
|         {#[num = 2, field = field_2] v2: T2} |         {#[num = 2, field = field_2, ty = ty2: Ty2] v2: T2} | ||||||
|         {#[num = 3, field = field_3] v3: T3} |         {#[num = 3, field = field_3, ty = ty3: Ty3] v3: T3} | ||||||
|         {#[num = 4, field = field_4] v4: T4} |         {#[num = 4, field = field_4, ty = ty4: Ty4] v4: T4} | ||||||
|         {#[num = 5, field = field_5] v5: T5} |         {#[num = 5, field = field_5, ty = ty5: Ty5] v5: T5} | ||||||
|         {#[num = 6, field = field_6] v6: T6} |         {#[num = 6, field = field_6, ty = ty6: Ty6] v6: T6} | ||||||
|         {#[num = 7, field = field_7] v7: T7} |         {#[num = 7, field = field_7, ty = ty7: Ty7] v7: T7} | ||||||
|         {#[num = 8, field = field_8] v8: T8} |         {#[num = 8, field = field_8, ty = ty8: Ty8] v8: T8} | ||||||
|         {#[num = 9, field = field_9] v9: T9} |         {#[num = 9, field = field_9, ty = ty9: Ty9] v9: T9} | ||||||
|         {#[num = 10, field = field_10] v10: T10} |         {#[num = 10, field = field_10, ty = ty10: Ty10] v10: T10} | ||||||
|         {#[num = 11, field = field_11] v11: T11} |         {#[num = 11, field = field_11, ty = ty11: Ty11] v11: T11} | ||||||
|     ] |     ] | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -528,3 +603,27 @@ impl<T: ?Sized + Send + Sync + 'static> ToExpr for PhantomData<T> { | ||||||
|         BundleLiteral::new(PhantomData, Interned::default()).to_expr() |         BundleLiteral::new(PhantomData, Interned::default()).to_expr() | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | impl<T: ?Sized + Send + Sync + 'static> ToSimValue<Self> for PhantomData<T> { | ||||||
|  |     #[track_caller] | ||||||
|  |     fn to_sim_value(&self, ty: Self) -> SimValue<Self> { | ||||||
|  |         ToSimValue::into_sim_value(BitVec::new(), ty) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<T: ?Sized> ToSimValue<Bundle> for PhantomData<T> { | ||||||
|  |     #[track_caller] | ||||||
|  |     fn to_sim_value(&self, ty: Bundle) -> SimValue<Bundle> { | ||||||
|  |         assert!(ty.fields().is_empty()); | ||||||
|  |         ToSimValue::into_sim_value(BitVec::new(), ty) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<T: ?Sized> ToSimValue<CanonicalType> for PhantomData<T> { | ||||||
|  |     #[track_caller] | ||||||
|  |     fn to_sim_value(&self, ty: CanonicalType) -> SimValue<CanonicalType> { | ||||||
|  |         let ty = Bundle::from_canonical(ty); | ||||||
|  |         assert!(ty.fields().is_empty()); | ||||||
|  |         ToSimValue::into_sim_value(BitVec::new(), ty).into_canonical() | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -11,6 +11,59 @@ extern crate self as fayalite; | ||||||
| #[doc(hidden)] | #[doc(hidden)] | ||||||
| pub use std as __std; | pub use std as __std; | ||||||
| 
 | 
 | ||||||
|  | #[doc(hidden)] | ||||||
|  | #[macro_export] | ||||||
|  | macro_rules! __cfg_expansion_helper { | ||||||
|  |     ( | ||||||
|  |         [ | ||||||
|  |             $($evaluated_cfgs:ident($($evaluated_exprs:tt)*) = $evaluated_results:ident,)* | ||||||
|  |         ] | ||||||
|  |         [ | ||||||
|  |             $cfg:ident($($expr:tt)*), | ||||||
|  |             $($unevaluated_cfgs:ident($($unevaluated_exprs:tt)*),)* | ||||||
|  |         ] | ||||||
|  |         // pass as tt so we get right span for attribute
 | ||||||
|  |         $after_evaluation_attr:tt $after_evaluation_body:tt | ||||||
|  |     ) => { | ||||||
|  |         #[$cfg($($expr)*)] | ||||||
|  |         $crate::__cfg_expansion_helper! { | ||||||
|  |             [ | ||||||
|  |                 $($evaluated_cfgs($($evaluated_exprs)*) = $evaluated_results,)* | ||||||
|  |                 $cfg($($expr)*) = true, | ||||||
|  |             ] | ||||||
|  |             [ | ||||||
|  |                 $($unevaluated_cfgs($($unevaluated_exprs)*),)* | ||||||
|  |             ] | ||||||
|  |             $after_evaluation_attr $after_evaluation_body | ||||||
|  |         } | ||||||
|  |         #[$cfg(not($($expr)*))] | ||||||
|  |         $crate::__cfg_expansion_helper! { | ||||||
|  |             [ | ||||||
|  |                 $($evaluated_cfgs($($evaluated_exprs)*) = $evaluated_results,)* | ||||||
|  |                 $cfg($($expr)*) = false, | ||||||
|  |             ] | ||||||
|  |             [ | ||||||
|  |                 $($unevaluated_cfgs($($unevaluated_exprs)*),)* | ||||||
|  |             ] | ||||||
|  |             $after_evaluation_attr $after_evaluation_body | ||||||
|  |         } | ||||||
|  |     }; | ||||||
|  |     ( | ||||||
|  |         [ | ||||||
|  |             $($evaluated_cfgs:ident($($evaluated_exprs:tt)*) = $evaluated_results:ident,)* | ||||||
|  |         ] | ||||||
|  |         [] | ||||||
|  |         // don't use #[...] so we get right span for `#` and `[]` of attribute
 | ||||||
|  |         {$($after_evaluation_attr:tt)*} {$($after_evaluation_body:tt)*} | ||||||
|  |     ) => { | ||||||
|  |         $($after_evaluation_attr)* | ||||||
|  |         #[__evaluated_cfgs([ | ||||||
|  |             $($evaluated_cfgs($($evaluated_exprs)*) = $evaluated_results,)* | ||||||
|  |         ])] | ||||||
|  |         $($after_evaluation_body)* | ||||||
|  |     }; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| #[doc(inline)] | #[doc(inline)] | ||||||
| /// The `#[hdl_module]` attribute is applied to a Rust function so that that function creates
 | /// The `#[hdl_module]` attribute is applied to a Rust function so that that function creates
 | ||||||
| /// a [`Module`][`::fayalite::module::Module`] when called.
 | /// a [`Module`][`::fayalite::module::Module`] when called.
 | ||||||
|  |  | ||||||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							|  | @ -7,12 +7,13 @@ use fayalite::{ | ||||||
|     clock::{Clock, ClockDomain}, |     clock::{Clock, ClockDomain}, | ||||||
|     expr::{CastTo, HdlPartialEq}, |     expr::{CastTo, HdlPartialEq}, | ||||||
|     firrtl::ExportOptions, |     firrtl::ExportOptions, | ||||||
|     formal::{any_seq, formal_reset, hdl_assert, hdl_assume}, |     formal::{any_const, any_seq, formal_reset, hdl_assert, hdl_assume}, | ||||||
|     hdl_module, |     hdl, hdl_module, | ||||||
|     int::{Bool, UInt}, |     int::{Bool, DynSize, Size, UInt, UIntType}, | ||||||
|     module::{connect, connect_any, reg_builder, wire}, |     module::{connect, connect_any, instance, memory, reg_builder, wire}, | ||||||
|     reset::ToReset, |     reset::ToReset, | ||||||
|     testing::assert_formal, |     testing::assert_formal, | ||||||
|  |     ty::StaticType, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /// Test hidden state
 | /// Test hidden state
 | ||||||
|  | @ -131,3 +132,164 @@ mod hidden_state { | ||||||
|         ); |         ); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | /// Formal verification of designs containing memories
 | ||||||
|  | ///
 | ||||||
|  | /// There is a trick for memories, described in the [Zipcpu blog].
 | ||||||
|  | /// First, select a fixed but arbitrary memory address, monitoring all reads
 | ||||||
|  | /// and writes made to it. Then, assert that anything read from that location
 | ||||||
|  | /// matches the last stored value.
 | ||||||
|  | ///
 | ||||||
|  | /// A difficulty for induction is that the memory represents [hidden_state]. A
 | ||||||
|  | /// solution is to include an additional read port to the memory and assert
 | ||||||
|  | /// that the memory location effectively contains the last stored value.
 | ||||||
|  | /// This additional debug port is present only to assist the proof and is
 | ||||||
|  | /// unused (optimized out) in actual use.
 | ||||||
|  | ///
 | ||||||
|  | /// [Zipcpu blog]: <https://zipcpu.com/zipcpu/2018/07/13/memories.html>
 | ||||||
|  | mod memory { | ||||||
|  |     use super::*; | ||||||
|  | 
 | ||||||
|  |     /// Test a simple 8-bit SRAM model
 | ||||||
|  |     #[test] | ||||||
|  |     fn test_sram() { | ||||||
|  |         #[hdl] | ||||||
|  |         struct WritePort<AddrWidth: Size> { | ||||||
|  |             addr: UIntType<AddrWidth>, | ||||||
|  |             data: UInt<8>, | ||||||
|  |             en: Bool, | ||||||
|  |         } | ||||||
|  |         #[hdl] | ||||||
|  |         struct ReadPort<AddrWidth: Size> { | ||||||
|  |             addr: UIntType<AddrWidth>, | ||||||
|  |             #[hdl(flip)] | ||||||
|  |             data: UInt<8>, | ||||||
|  |         } | ||||||
|  |         /// This debug port is only meant to assist the proof.
 | ||||||
|  |         /// For normal use in a design, a wrapper could be provided,
 | ||||||
|  |         /// omitting this port.
 | ||||||
|  |         /// The implementation is forbidden to use any information
 | ||||||
|  |         /// provided on this port in its internal workings.
 | ||||||
|  |         #[hdl] | ||||||
|  |         struct DebugPort<AddrWidth: Size> { | ||||||
|  |             selected: UIntType<AddrWidth>, | ||||||
|  |             stored: UInt<8>, | ||||||
|  |             wrote: Bool, | ||||||
|  |         } | ||||||
|  |         /// simple 1R1W SRAM model (one asynchronous read port and one
 | ||||||
|  |         /// independent write port) with `n`-bit address width
 | ||||||
|  |         #[hdl_module] | ||||||
|  |         fn example_sram(n: usize) { | ||||||
|  |             #[hdl] | ||||||
|  |             let wr: WritePort<DynSize> = m.input(WritePort[n]); | ||||||
|  |             #[hdl] | ||||||
|  |             let rd: ReadPort<DynSize> = m.input(ReadPort[n]); | ||||||
|  |             #[hdl] | ||||||
|  |             let cd: ClockDomain = m.input(); | ||||||
|  | 
 | ||||||
|  |             // declare and connect the backing memory
 | ||||||
|  |             #[hdl] | ||||||
|  |             let mut mem = memory(); | ||||||
|  |             mem.depth(1 << n); | ||||||
|  |             let read_port = mem.new_read_port(); | ||||||
|  |             let write_port = mem.new_write_port(); | ||||||
|  |             connect(write_port.clk, cd.clk); | ||||||
|  |             connect(write_port.addr, wr.addr); | ||||||
|  |             connect(write_port.en, wr.en); | ||||||
|  |             connect(write_port.data, wr.data); | ||||||
|  |             connect(write_port.mask, true); | ||||||
|  |             connect(read_port.clk, cd.clk); | ||||||
|  |             connect(read_port.addr, rd.addr); | ||||||
|  |             connect(read_port.en, true); | ||||||
|  |             connect(rd.data, read_port.data); | ||||||
|  | 
 | ||||||
|  |             // To assist with induction, ensure that the chosen memory location
 | ||||||
|  |             // really contains, always, the last value written to it.
 | ||||||
|  |             #[hdl] | ||||||
|  |             let dbg: DebugPort<DynSize> = m.input(DebugPort[n]); | ||||||
|  |             let debug_port = mem.new_read_port(); | ||||||
|  |             connect(debug_port.en, true); | ||||||
|  |             connect(debug_port.clk, cd.clk); | ||||||
|  |             connect(debug_port.addr, dbg.selected); | ||||||
|  |             #[hdl] | ||||||
|  |             if dbg.wrote { | ||||||
|  |                 hdl_assert(cd.clk, debug_port.data.cmp_eq(dbg.stored), ""); | ||||||
|  |                 // Try commenting out the assert above, induction will fail.
 | ||||||
|  |                 // Opening the trace, it can be seen that the memory contents
 | ||||||
|  |                 // and the stored value don't match, which is an unreachable
 | ||||||
|  |                 // state. By asserting the above, it will become invalid
 | ||||||
|  |                 // as well, so induction will skip this kind of situation.
 | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         /// formal verification of the SRAM module, parametrized by the
 | ||||||
|  |         /// address bit-width
 | ||||||
|  |         #[hdl_module] | ||||||
|  |         fn test_module(n: usize) { | ||||||
|  |             #[hdl] | ||||||
|  |             let clk: Clock = m.input(); | ||||||
|  |             let cd = #[hdl] | ||||||
|  |             ClockDomain { | ||||||
|  |                 clk, | ||||||
|  |                 rst: formal_reset().to_reset(), | ||||||
|  |             }; | ||||||
|  | 
 | ||||||
|  |             // instantiate the SRAM model, connecting its inputs to
 | ||||||
|  |             // a random sequence
 | ||||||
|  |             #[hdl] | ||||||
|  |             let rd: ReadPort<DynSize> = wire(ReadPort[n]); | ||||||
|  |             connect(rd.addr, any_seq(UInt[n])); | ||||||
|  |             #[hdl] | ||||||
|  |             let wr: WritePort<DynSize> = wire(WritePort[n]); | ||||||
|  |             connect(wr.addr, any_seq(UInt[n])); | ||||||
|  |             connect(wr.data, any_seq(UInt::<8>::TYPE)); | ||||||
|  |             connect(wr.en, any_seq(Bool)); | ||||||
|  |             #[hdl] | ||||||
|  |             let dut = instance(example_sram(n)); | ||||||
|  |             connect(dut.cd, cd); | ||||||
|  |             connect(dut.rd, rd); | ||||||
|  |             connect(dut.wr, wr); | ||||||
|  | 
 | ||||||
|  |             // select a fixed but arbitrary test address
 | ||||||
|  |             #[hdl] | ||||||
|  |             let selected = wire(UInt[n]); | ||||||
|  |             connect(selected, any_const(UInt[n])); | ||||||
|  |             // store the last value written to that address
 | ||||||
|  |             #[hdl] | ||||||
|  |             let stored: UInt<8> = reg_builder().clock_domain(cd).reset(0u8); | ||||||
|  |             // since memories are not initialized, track whether we wrote to the
 | ||||||
|  |             // memory at least once
 | ||||||
|  |             #[hdl] | ||||||
|  |             let wrote: Bool = reg_builder().clock_domain(cd).reset(false); | ||||||
|  |             // on a write, capture the last written value
 | ||||||
|  |             #[hdl] | ||||||
|  |             if wr.en & wr.addr.cmp_eq(selected) { | ||||||
|  |                 connect(stored, wr.data); | ||||||
|  |                 connect(wrote, true); | ||||||
|  |             } | ||||||
|  |             // on a read, assert that the read value is the same which was stored
 | ||||||
|  |             #[hdl] | ||||||
|  |             if rd.addr.cmp_eq(selected) & wrote { | ||||||
|  |                 hdl_assert(clk, rd.data.cmp_eq(stored), ""); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             // to assist induction, pass our state to the underlying instance
 | ||||||
|  |             let dbg = #[hdl] | ||||||
|  |             DebugPort { | ||||||
|  |                 selected, | ||||||
|  |                 stored, | ||||||
|  |                 wrote, | ||||||
|  |             }; | ||||||
|  |             connect(dut.dbg, dbg); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         assert_formal( | ||||||
|  |             "sram", | ||||||
|  |             test_module(8), | ||||||
|  |             FormalMode::Prove, | ||||||
|  |             2, | ||||||
|  |             None, | ||||||
|  |             ExportOptions::default(), | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -4287,3 +4287,61 @@ circuit check_deduce_resets: | ||||||
| ",
 | ",
 | ||||||
|     }; |     }; | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | // intentionally not outline_generated to ensure we get correct macro hygiene
 | ||||||
|  | #[hdl_module] | ||||||
|  | pub fn check_cfgs<#[cfg(cfg_false_for_tests)] A: Type, #[cfg(cfg_true_for_tests)] B: Type>( | ||||||
|  |     #[cfg(cfg_false_for_tests)] a: A, | ||||||
|  |     #[cfg(cfg_true_for_tests)] b: B, | ||||||
|  | ) { | ||||||
|  |     #[hdl] | ||||||
|  |     struct S<#[cfg(cfg_false_for_tests)] A, #[cfg(cfg_true_for_tests)] B> { | ||||||
|  |         #[cfg(cfg_false_for_tests)] | ||||||
|  |         a: A, | ||||||
|  |         #[cfg(cfg_true_for_tests)] | ||||||
|  |         b: B, | ||||||
|  |     } | ||||||
|  |     #[hdl] | ||||||
|  |     #[cfg(cfg_false_for_tests)] | ||||||
|  |     let i_a: A = m.input(a); | ||||||
|  |     #[hdl] | ||||||
|  |     #[cfg(cfg_true_for_tests)] | ||||||
|  |     let i_b: B = m.input(b); | ||||||
|  |     #[hdl] | ||||||
|  |     let w: S<UInt<8>> = wire(); | ||||||
|  |     #[cfg(cfg_false_for_tests)] | ||||||
|  |     { | ||||||
|  |         #[hdl] | ||||||
|  |         let o_a: A = m.output(a); | ||||||
|  |         connect(o_a, w.a.cast_bits_to(a)); | ||||||
|  |         connect_any(w.a, i_a.cast_to_bits()); | ||||||
|  |     } | ||||||
|  |     #[cfg(cfg_true_for_tests)] | ||||||
|  |     { | ||||||
|  |         #[hdl] | ||||||
|  |         let o_b: B = m.output(b); | ||||||
|  |         connect(o_b, w.b.cast_bits_to(b)); | ||||||
|  |         connect_any(w.b, i_b.cast_to_bits()); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[test] | ||||||
|  | fn test_cfgs() { | ||||||
|  |     let _n = SourceLocation::normalize_files_for_tests(); | ||||||
|  |     let m = check_cfgs(UInt[8]); | ||||||
|  |     dbg!(m); | ||||||
|  |     #[rustfmt::skip] // work around https://github.com/rust-lang/rustfmt/issues/6161
 | ||||||
|  |     assert_export_firrtl! { | ||||||
|  |         m => | ||||||
|  |         "/test/check_cfgs.fir": r"FIRRTL version 3.2.0
 | ||||||
|  | circuit check_cfgs: | ||||||
|  |     type Ty0 = {b: UInt<8>} | ||||||
|  |     module check_cfgs: @[the_test_file.rs 9962:1] | ||||||
|  |         input i_b: UInt<8> @[the_test_file.rs 9979:20] | ||||||
|  |         output o_b: UInt<8> @[the_test_file.rs 9992:24] | ||||||
|  |         wire w: Ty0 @[the_test_file.rs 9981:25] | ||||||
|  |         connect o_b, w.b @[the_test_file.rs 9993:9] | ||||||
|  |         connect w.b, i_b @[the_test_file.rs 9994:9] | ||||||
|  | ",
 | ||||||
|  |     }; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -5,7 +5,8 @@ use fayalite::{ | ||||||
|     int::UIntValue, |     int::UIntValue, | ||||||
|     prelude::*, |     prelude::*, | ||||||
|     reset::ResetType, |     reset::ResetType, | ||||||
|     sim::{time::SimDuration, vcd::VcdWriterDecls, Simulation}, |     sim::{time::SimDuration, vcd::VcdWriterDecls, Simulation, ToSimValue}, | ||||||
|  |     ty::StaticType, | ||||||
|     util::RcWriter, |     util::RcWriter, | ||||||
| }; | }; | ||||||
| use std::num::NonZeroUsize; | use std::num::NonZeroUsize; | ||||||
|  | @ -254,8 +255,14 @@ fn test_shift_register() { | ||||||
|     let mut sim = Simulation::new(shift_register()); |     let mut sim = Simulation::new(shift_register()); | ||||||
|     let mut writer = RcWriter::default(); |     let mut writer = RcWriter::default(); | ||||||
|     sim.add_trace_writer(VcdWriterDecls::new(writer.clone())); |     sim.add_trace_writer(VcdWriterDecls::new(writer.clone())); | ||||||
|     sim.write_clock(sim.io().cd.clk, false); |     sim.write( | ||||||
|     sim.write_reset(sim.io().cd.rst, true); |         sim.io().cd, | ||||||
|  |         #[hdl] | ||||||
|  |         ClockDomain { | ||||||
|  |             clk: false.to_clock(), | ||||||
|  |             rst: true.to_sync_reset(), | ||||||
|  |         }, | ||||||
|  |     ); | ||||||
|     sim.write_bool(sim.io().d, false); |     sim.write_bool(sim.io().d, false); | ||||||
|     sim.advance_time(SimDuration::from_micros(1)); |     sim.advance_time(SimDuration::from_micros(1)); | ||||||
|     sim.write_clock(sim.io().cd.clk, true); |     sim.write_clock(sim.io().cd.clk, true); | ||||||
|  | @ -271,7 +278,7 @@ fn test_shift_register() { | ||||||
|                 assert_eq!( |                 assert_eq!( | ||||||
|                     *expected, |                     *expected, | ||||||
|                     sim.read_bool(sim.io().q), |                     sim.read_bool(sim.io().q), | ||||||
|                     "cycle: {cycle}\nvcd:\n{}", |                     "vcd:\n{}\ncycle: {cycle}", | ||||||
|                     String::from_utf8(writer.take()).unwrap(), |                     String::from_utf8(writer.take()).unwrap(), | ||||||
|                 ); |                 ); | ||||||
|             } |             } | ||||||
|  | @ -309,6 +316,8 @@ pub fn enums() { | ||||||
|     let which_out: UInt<2> = m.output(); |     let which_out: UInt<2> = m.output(); | ||||||
|     #[hdl] |     #[hdl] | ||||||
|     let data_out: UInt<4> = m.output(); |     let data_out: UInt<4> = m.output(); | ||||||
|  |     #[hdl] | ||||||
|  |     let b_out: HdlOption<(UInt<1>, Bool)> = m.output(); | ||||||
| 
 | 
 | ||||||
|     #[hdl] |     #[hdl] | ||||||
|     struct MyStruct<T> { |     struct MyStruct<T> { | ||||||
|  | @ -348,6 +357,8 @@ pub fn enums() { | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     connect(b_out, HdlNone()); | ||||||
|  | 
 | ||||||
|     #[hdl] |     #[hdl] | ||||||
|     match the_reg { |     match the_reg { | ||||||
|         MyEnum::A => { |         MyEnum::A => { | ||||||
|  | @ -357,6 +368,7 @@ pub fn enums() { | ||||||
|         MyEnum::B(v) => { |         MyEnum::B(v) => { | ||||||
|             connect(which_out, 1_hdl_u2); |             connect(which_out, 1_hdl_u2); | ||||||
|             connect_any(data_out, v.0 | (v.1.cast_to_static::<UInt<1>>() << 1)); |             connect_any(data_out, v.0 | (v.1.cast_to_static::<UInt<1>>() << 1)); | ||||||
|  |             connect(b_out, HdlSome(v)); | ||||||
|         } |         } | ||||||
|         MyEnum::C(v) => { |         MyEnum::C(v) => { | ||||||
|             connect(which_out, 2_hdl_u2); |             connect(which_out, 2_hdl_u2); | ||||||
|  | @ -382,13 +394,33 @@ fn test_enums() { | ||||||
|     sim.advance_time(SimDuration::from_nanos(100)); |     sim.advance_time(SimDuration::from_nanos(100)); | ||||||
|     sim.write_reset(sim.io().cd.rst, false); |     sim.write_reset(sim.io().cd.rst, false); | ||||||
|     sim.advance_time(SimDuration::from_nanos(900)); |     sim.advance_time(SimDuration::from_nanos(900)); | ||||||
|     #[derive(Debug, PartialEq, Eq)] |     type BOutTy = HdlOption<(UInt<1>, Bool)>; | ||||||
|  |     #[derive(Debug)] | ||||||
|     struct IO { |     struct IO { | ||||||
|         en: bool, |         en: bool, | ||||||
|         which_in: u8, |         which_in: u8, | ||||||
|         data_in: u8, |         data_in: u8, | ||||||
|         which_out: u8, |         which_out: u8, | ||||||
|         data_out: u8, |         data_out: u8, | ||||||
|  |         b_out: Expr<BOutTy>, | ||||||
|  |     } | ||||||
|  |     impl PartialEq for IO { | ||||||
|  |         fn eq(&self, other: &Self) -> bool { | ||||||
|  |             let Self { | ||||||
|  |                 en, | ||||||
|  |                 which_in, | ||||||
|  |                 data_in, | ||||||
|  |                 which_out, | ||||||
|  |                 data_out, | ||||||
|  |                 b_out, | ||||||
|  |             } = *self; | ||||||
|  |             en == other.en | ||||||
|  |                 && which_in == other.which_in | ||||||
|  |                 && data_in == other.data_in | ||||||
|  |                 && which_out == other.which_out | ||||||
|  |                 && data_out == other.data_out | ||||||
|  |                 && b_out.to_sim_value(BOutTy::TYPE) == other.b_out.to_sim_value(BOutTy::TYPE) | ||||||
|  |         } | ||||||
|     } |     } | ||||||
|     let io_cycles = [ |     let io_cycles = [ | ||||||
|         IO { |         IO { | ||||||
|  | @ -397,6 +429,7 @@ fn test_enums() { | ||||||
|             data_in: 0, |             data_in: 0, | ||||||
|             which_out: 0, |             which_out: 0, | ||||||
|             data_out: 0, |             data_out: 0, | ||||||
|  |             b_out: HdlNone(), | ||||||
|         }, |         }, | ||||||
|         IO { |         IO { | ||||||
|             en: true, |             en: true, | ||||||
|  | @ -404,6 +437,7 @@ fn test_enums() { | ||||||
|             data_in: 0, |             data_in: 0, | ||||||
|             which_out: 0, |             which_out: 0, | ||||||
|             data_out: 0, |             data_out: 0, | ||||||
|  |             b_out: HdlNone(), | ||||||
|         }, |         }, | ||||||
|         IO { |         IO { | ||||||
|             en: false, |             en: false, | ||||||
|  | @ -411,6 +445,7 @@ fn test_enums() { | ||||||
|             data_in: 0, |             data_in: 0, | ||||||
|             which_out: 1, |             which_out: 1, | ||||||
|             data_out: 0, |             data_out: 0, | ||||||
|  |             b_out: HdlSome((0_hdl_u1, false)), | ||||||
|         }, |         }, | ||||||
|         IO { |         IO { | ||||||
|             en: true, |             en: true, | ||||||
|  | @ -418,6 +453,7 @@ fn test_enums() { | ||||||
|             data_in: 0xF, |             data_in: 0xF, | ||||||
|             which_out: 1, |             which_out: 1, | ||||||
|             data_out: 0, |             data_out: 0, | ||||||
|  |             b_out: HdlSome((0_hdl_u1, false)), | ||||||
|         }, |         }, | ||||||
|         IO { |         IO { | ||||||
|             en: true, |             en: true, | ||||||
|  | @ -425,6 +461,7 @@ fn test_enums() { | ||||||
|             data_in: 0xF, |             data_in: 0xF, | ||||||
|             which_out: 1, |             which_out: 1, | ||||||
|             data_out: 0x3, |             data_out: 0x3, | ||||||
|  |             b_out: HdlSome((1_hdl_u1, true)), | ||||||
|         }, |         }, | ||||||
|         IO { |         IO { | ||||||
|             en: true, |             en: true, | ||||||
|  | @ -432,6 +469,7 @@ fn test_enums() { | ||||||
|             data_in: 0xF, |             data_in: 0xF, | ||||||
|             which_out: 1, |             which_out: 1, | ||||||
|             data_out: 0x3, |             data_out: 0x3, | ||||||
|  |             b_out: HdlSome((1_hdl_u1, true)), | ||||||
|         }, |         }, | ||||||
|         IO { |         IO { | ||||||
|             en: true, |             en: true, | ||||||
|  | @ -439,6 +477,7 @@ fn test_enums() { | ||||||
|             data_in: 0xF, |             data_in: 0xF, | ||||||
|             which_out: 2, |             which_out: 2, | ||||||
|             data_out: 0xF, |             data_out: 0xF, | ||||||
|  |             b_out: HdlNone(), | ||||||
|         }, |         }, | ||||||
|     ]; |     ]; | ||||||
|     for ( |     for ( | ||||||
|  | @ -449,6 +488,7 @@ fn test_enums() { | ||||||
|             data_in, |             data_in, | ||||||
|             which_out: _, |             which_out: _, | ||||||
|             data_out: _, |             data_out: _, | ||||||
|  |             b_out: _, | ||||||
|         }, |         }, | ||||||
|     ) in io_cycles.into_iter().enumerate() |     ) in io_cycles.into_iter().enumerate() | ||||||
|     { |     { | ||||||
|  | @ -469,11 +509,12 @@ fn test_enums() { | ||||||
|                 .to_bigint() |                 .to_bigint() | ||||||
|                 .try_into() |                 .try_into() | ||||||
|                 .expect("known to be in range"), |                 .expect("known to be in range"), | ||||||
|  |             b_out: sim.read(sim.io().b_out).to_expr(), | ||||||
|         }; |         }; | ||||||
|         assert_eq!( |         assert_eq!( | ||||||
|             expected, |             expected, | ||||||
|             io, |             io, | ||||||
|             "cycle: {cycle}\nvcd:\n{}", |             "vcd:\n{}\ncycle: {cycle}", | ||||||
|             String::from_utf8(writer.take()).unwrap(), |             String::from_utf8(writer.take()).unwrap(), | ||||||
|         ); |         ); | ||||||
|         sim.write_clock(sim.io().cd.clk, false); |         sim.write_clock(sim.io().cd.clk, false); | ||||||
|  | @ -671,7 +712,7 @@ fn test_memories() { | ||||||
|         assert_eq!( |         assert_eq!( | ||||||
|             expected, |             expected, | ||||||
|             io, |             io, | ||||||
|             "cycle: {cycle}\nvcd:\n{}", |             "vcd:\n{}\ncycle: {cycle}", | ||||||
|             String::from_utf8(writer.take()).unwrap(), |             String::from_utf8(writer.take()).unwrap(), | ||||||
|         ); |         ); | ||||||
|         sim.advance_time(SimDuration::from_micros(1)); |         sim.advance_time(SimDuration::from_micros(1)); | ||||||
|  | @ -694,4 +735,514 @@ fn test_memories() { | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // TODO: add more tests for memories
 | #[hdl_module(outline_generated)] | ||||||
|  | pub fn memories2() { | ||||||
|  |     #[hdl] | ||||||
|  |     let rw: fayalite::memory::ReadWriteStruct<UInt<2>, ConstUsize<3>> = m.input(); | ||||||
|  |     #[hdl] | ||||||
|  |     let mut mem = memory_with_init([HdlSome(true); 5]); | ||||||
|  |     mem.read_latency(1); | ||||||
|  |     mem.write_latency(NonZeroUsize::new(1).unwrap()); | ||||||
|  |     mem.read_under_write(ReadUnderWrite::New); | ||||||
|  |     let rw_port = mem.new_rw_port(); | ||||||
|  |     connect_any(rw_port.addr, rw.addr); | ||||||
|  |     connect(rw_port.en, rw.en); | ||||||
|  |     connect(rw_port.clk, rw.clk); | ||||||
|  |     connect_any(rw.rdata, rw_port.rdata.cast_to_bits()); | ||||||
|  |     connect(rw_port.wmode, rw.wmode); | ||||||
|  |     connect(rw_port.wdata, HdlNone()); | ||||||
|  |     #[hdl] | ||||||
|  |     if rw.wdata[0] { | ||||||
|  |         connect(rw_port.wdata, HdlSome(rw.wdata[1])); | ||||||
|  |     } | ||||||
|  |     connect(rw_port.wmask, rw.wmask); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[hdl] | ||||||
|  | #[test] | ||||||
|  | fn test_memories2() { | ||||||
|  |     let _n = SourceLocation::normalize_files_for_tests(); | ||||||
|  |     let mut sim = Simulation::new(memories2()); | ||||||
|  |     let mut writer = RcWriter::default(); | ||||||
|  |     sim.add_trace_writer(VcdWriterDecls::new(writer.clone())); | ||||||
|  |     sim.write_clock(sim.io().rw.clk, false); | ||||||
|  |     #[derive(Debug, PartialEq, Eq)] | ||||||
|  |     struct IO { | ||||||
|  |         addr: u8, | ||||||
|  |         en: bool, | ||||||
|  |         rdata: u8, | ||||||
|  |         wmode: bool, | ||||||
|  |         wdata: u8, | ||||||
|  |         wmask: bool, | ||||||
|  |     } | ||||||
|  |     let io_cycles = [ | ||||||
|  |         IO { | ||||||
|  |             addr: 0, | ||||||
|  |             en: false, | ||||||
|  |             rdata: 0, | ||||||
|  |             wmode: false, | ||||||
|  |             wdata: 0, | ||||||
|  |             wmask: false, | ||||||
|  |         }, | ||||||
|  |         IO { | ||||||
|  |             addr: 0, | ||||||
|  |             en: true, | ||||||
|  |             rdata: 0x3, | ||||||
|  |             wmode: false, | ||||||
|  |             wdata: 0, | ||||||
|  |             wmask: false, | ||||||
|  |         }, | ||||||
|  |         IO { | ||||||
|  |             addr: 0, | ||||||
|  |             en: false, | ||||||
|  |             rdata: 0, | ||||||
|  |             wmode: false, | ||||||
|  |             wdata: 0, | ||||||
|  |             wmask: false, | ||||||
|  |         }, | ||||||
|  |         IO { | ||||||
|  |             addr: 0, | ||||||
|  |             en: true, | ||||||
|  |             rdata: 0, | ||||||
|  |             wmode: true, | ||||||
|  |             wdata: 0, | ||||||
|  |             wmask: true, | ||||||
|  |         }, | ||||||
|  |         IO { | ||||||
|  |             addr: 0, | ||||||
|  |             en: true, | ||||||
|  |             rdata: 0, | ||||||
|  |             wmode: false, | ||||||
|  |             wdata: 0, | ||||||
|  |             wmask: false, | ||||||
|  |         }, | ||||||
|  |         IO { | ||||||
|  |             addr: 0, | ||||||
|  |             en: true, | ||||||
|  |             rdata: 0, | ||||||
|  |             wmode: true, | ||||||
|  |             wdata: 3, | ||||||
|  |             wmask: false, | ||||||
|  |         }, | ||||||
|  |         IO { | ||||||
|  |             addr: 1, | ||||||
|  |             en: true, | ||||||
|  |             rdata: 0, | ||||||
|  |             wmode: true, | ||||||
|  |             wdata: 1, | ||||||
|  |             wmask: true, | ||||||
|  |         }, | ||||||
|  |         IO { | ||||||
|  |             addr: 2, | ||||||
|  |             en: true, | ||||||
|  |             rdata: 0, | ||||||
|  |             wmode: true, | ||||||
|  |             wdata: 2, | ||||||
|  |             wmask: true, | ||||||
|  |         }, | ||||||
|  |         IO { | ||||||
|  |             addr: 3, | ||||||
|  |             en: true, | ||||||
|  |             rdata: 0, | ||||||
|  |             wmode: true, | ||||||
|  |             wdata: 3, | ||||||
|  |             wmask: true, | ||||||
|  |         }, | ||||||
|  |         IO { | ||||||
|  |             addr: 4, | ||||||
|  |             en: true, | ||||||
|  |             rdata: 0, | ||||||
|  |             wmode: true, | ||||||
|  |             wdata: 2, | ||||||
|  |             wmask: true, | ||||||
|  |         }, | ||||||
|  |         IO { | ||||||
|  |             addr: 5, | ||||||
|  |             en: true, | ||||||
|  |             rdata: 0, | ||||||
|  |             wmode: true, | ||||||
|  |             wdata: 1, | ||||||
|  |             wmask: true, | ||||||
|  |         }, | ||||||
|  |         IO { | ||||||
|  |             addr: 6, | ||||||
|  |             en: true, | ||||||
|  |             rdata: 0, | ||||||
|  |             wmode: true, | ||||||
|  |             wdata: 1, | ||||||
|  |             wmask: true, | ||||||
|  |         }, | ||||||
|  |         IO { | ||||||
|  |             addr: 7, | ||||||
|  |             en: true, | ||||||
|  |             rdata: 0, | ||||||
|  |             wmode: true, | ||||||
|  |             wdata: 1, | ||||||
|  |             wmask: true, | ||||||
|  |         }, | ||||||
|  |         IO { | ||||||
|  |             addr: 7, | ||||||
|  |             en: true, | ||||||
|  |             rdata: 0, | ||||||
|  |             wmode: false, | ||||||
|  |             wdata: 0, | ||||||
|  |             wmask: false, | ||||||
|  |         }, | ||||||
|  |         IO { | ||||||
|  |             addr: 6, | ||||||
|  |             en: true, | ||||||
|  |             rdata: 0, | ||||||
|  |             wmode: false, | ||||||
|  |             wdata: 0, | ||||||
|  |             wmask: false, | ||||||
|  |         }, | ||||||
|  |         IO { | ||||||
|  |             addr: 5, | ||||||
|  |             en: true, | ||||||
|  |             rdata: 0, | ||||||
|  |             wmode: false, | ||||||
|  |             wdata: 0, | ||||||
|  |             wmask: false, | ||||||
|  |         }, | ||||||
|  |         IO { | ||||||
|  |             addr: 4, | ||||||
|  |             en: true, | ||||||
|  |             rdata: 0, | ||||||
|  |             wmode: false, | ||||||
|  |             wdata: 0, | ||||||
|  |             wmask: false, | ||||||
|  |         }, | ||||||
|  |         IO { | ||||||
|  |             addr: 3, | ||||||
|  |             en: true, | ||||||
|  |             rdata: 3, | ||||||
|  |             wmode: false, | ||||||
|  |             wdata: 0, | ||||||
|  |             wmask: false, | ||||||
|  |         }, | ||||||
|  |         IO { | ||||||
|  |             addr: 2, | ||||||
|  |             en: true, | ||||||
|  |             rdata: 0, | ||||||
|  |             wmode: false, | ||||||
|  |             wdata: 0, | ||||||
|  |             wmask: false, | ||||||
|  |         }, | ||||||
|  |         IO { | ||||||
|  |             addr: 0, | ||||||
|  |             en: true, | ||||||
|  |             rdata: 0, | ||||||
|  |             wmode: false, | ||||||
|  |             wdata: 0, | ||||||
|  |             wmask: false, | ||||||
|  |         }, | ||||||
|  |         IO { | ||||||
|  |             addr: 1, | ||||||
|  |             en: true, | ||||||
|  |             rdata: 1, | ||||||
|  |             wmode: false, | ||||||
|  |             wdata: 0, | ||||||
|  |             wmask: false, | ||||||
|  |         }, | ||||||
|  |         IO { | ||||||
|  |             addr: 0, | ||||||
|  |             en: false, | ||||||
|  |             rdata: 0, | ||||||
|  |             wmode: false, | ||||||
|  |             wdata: 0, | ||||||
|  |             wmask: false, | ||||||
|  |         }, | ||||||
|  |     ]; | ||||||
|  |     for ( | ||||||
|  |         cycle, | ||||||
|  |         expected @ IO { | ||||||
|  |             addr, | ||||||
|  |             en, | ||||||
|  |             rdata: _, | ||||||
|  |             wmode, | ||||||
|  |             wdata, | ||||||
|  |             wmask, | ||||||
|  |         }, | ||||||
|  |     ) in io_cycles.into_iter().enumerate() | ||||||
|  |     { | ||||||
|  |         sim.write_bool_or_int(sim.io().rw.addr, addr.cast_to_static()); | ||||||
|  |         sim.write_bool(sim.io().rw.en, en); | ||||||
|  |         sim.write_bool(sim.io().rw.wmode, wmode); | ||||||
|  |         sim.write_bool_or_int(sim.io().rw.wdata, wdata.cast_to_static()); | ||||||
|  |         sim.write_bool(sim.io().rw.wmask, wmask); | ||||||
|  |         sim.advance_time(SimDuration::from_nanos(250)); | ||||||
|  |         sim.write_clock(sim.io().rw.clk, true); | ||||||
|  |         sim.advance_time(SimDuration::from_nanos(250)); | ||||||
|  |         let io = IO { | ||||||
|  |             addr, | ||||||
|  |             en, | ||||||
|  |             rdata: sim | ||||||
|  |                 .read_bool_or_int(sim.io().rw.rdata) | ||||||
|  |                 .to_bigint() | ||||||
|  |                 .try_into() | ||||||
|  |                 .expect("known to be in range"), | ||||||
|  |             wmode, | ||||||
|  |             wdata, | ||||||
|  |             wmask, | ||||||
|  |         }; | ||||||
|  |         assert_eq!( | ||||||
|  |             expected, | ||||||
|  |             io, | ||||||
|  |             "vcd:\n{}\ncycle: {cycle}", | ||||||
|  |             String::from_utf8(writer.take()).unwrap(), | ||||||
|  |         ); | ||||||
|  |         sim.advance_time(SimDuration::from_nanos(250)); | ||||||
|  |         sim.write_clock(sim.io().rw.clk, false); | ||||||
|  |         sim.advance_time(SimDuration::from_nanos(250)); | ||||||
|  |     } | ||||||
|  |     sim.flush_traces().unwrap(); | ||||||
|  |     let vcd = String::from_utf8(writer.take()).unwrap(); | ||||||
|  |     println!("####### VCD:\n{vcd}\n#######"); | ||||||
|  |     if vcd != include_str!("sim/expected/memories2.vcd") { | ||||||
|  |         panic!(); | ||||||
|  |     } | ||||||
|  |     let sim_debug = format!("{sim:#?}"); | ||||||
|  |     println!("#######\n{sim_debug}\n#######"); | ||||||
|  |     if sim_debug != include_str!("sim/expected/memories2.txt") { | ||||||
|  |         panic!(); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[hdl_module(outline_generated)] | ||||||
|  | pub fn memories3() { | ||||||
|  |     #[hdl] | ||||||
|  |     let r: fayalite::memory::ReadStruct<Array<UInt<8>, 8>, ConstUsize<3>> = m.input(); | ||||||
|  |     #[hdl] | ||||||
|  |     let w: fayalite::memory::WriteStruct<Array<UInt<8>, 8>, ConstUsize<3>> = m.input(); | ||||||
|  |     #[hdl] | ||||||
|  |     let mut mem: MemBuilder<Array<UInt<8>, 8>> = memory(); | ||||||
|  |     mem.depth(8); | ||||||
|  |     mem.read_latency(2); | ||||||
|  |     mem.write_latency(NonZeroUsize::new(2).unwrap()); | ||||||
|  |     mem.read_under_write(ReadUnderWrite::Old); | ||||||
|  |     connect_any(mem.new_read_port(), r); | ||||||
|  |     connect_any(mem.new_write_port(), w); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[hdl] | ||||||
|  | #[test] | ||||||
|  | fn test_memories3() { | ||||||
|  |     let _n = SourceLocation::normalize_files_for_tests(); | ||||||
|  |     let mut sim = Simulation::new(memories3()); | ||||||
|  |     let mut writer = RcWriter::default(); | ||||||
|  |     sim.add_trace_writer(VcdWriterDecls::new(writer.clone())); | ||||||
|  |     sim.write_clock(sim.io().r.clk, false); | ||||||
|  |     sim.write_clock(sim.io().w.clk, false); | ||||||
|  |     #[derive(Debug, PartialEq, Eq, Clone, Copy)] | ||||||
|  |     struct IO { | ||||||
|  |         r_addr: u8, | ||||||
|  |         r_en: bool, | ||||||
|  |         r_data: [u8; 8], | ||||||
|  |         w_addr: u8, | ||||||
|  |         w_en: bool, | ||||||
|  |         w_data: [u8; 8], | ||||||
|  |         w_mask: [bool; 8], | ||||||
|  |     } | ||||||
|  |     let io_cycles = [ | ||||||
|  |         IO { | ||||||
|  |             r_addr: 0, | ||||||
|  |             r_en: false, | ||||||
|  |             r_data: [0; 8], | ||||||
|  |             w_addr: 0, | ||||||
|  |             w_en: true, | ||||||
|  |             w_data: [0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0], | ||||||
|  |             w_mask: [false, true, false, true, true, false, false, true], | ||||||
|  |         }, | ||||||
|  |         IO { | ||||||
|  |             r_addr: 0, | ||||||
|  |             r_en: true, | ||||||
|  |             r_data: [0; 8], | ||||||
|  |             w_addr: 1, | ||||||
|  |             w_en: false, | ||||||
|  |             w_data: [0; 8], | ||||||
|  |             w_mask: [false; 8], | ||||||
|  |         }, | ||||||
|  |         IO { | ||||||
|  |             r_addr: 0, | ||||||
|  |             r_en: true, | ||||||
|  |             r_data: [0, 0x34, 0, 0x78, 0x9A, 0, 0, 0xF0], | ||||||
|  |             w_addr: 1, | ||||||
|  |             w_en: false, | ||||||
|  |             w_data: [0; 8], | ||||||
|  |             w_mask: [false; 8], | ||||||
|  |         }, | ||||||
|  |         IO { | ||||||
|  |             r_addr: 0, | ||||||
|  |             r_en: true, | ||||||
|  |             r_data: [0, 0x34, 0, 0x78, 0x9A, 0, 0, 0xF0], | ||||||
|  |             w_addr: 0, | ||||||
|  |             w_en: true, | ||||||
|  |             w_data: [0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10], | ||||||
|  |             w_mask: [true; 8], | ||||||
|  |         }, | ||||||
|  |         IO { | ||||||
|  |             r_addr: 0, | ||||||
|  |             r_en: true, | ||||||
|  |             r_data: [0, 0x34, 0, 0x78, 0x9A, 0, 0, 0xF0], | ||||||
|  |             w_addr: 0, | ||||||
|  |             w_en: true, | ||||||
|  |             w_data: [0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10], | ||||||
|  |             w_mask: [true; 8], | ||||||
|  |         }, | ||||||
|  |         IO { | ||||||
|  |             r_addr: 0, | ||||||
|  |             r_en: true, | ||||||
|  |             r_data: [0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10], | ||||||
|  |             w_addr: 0, | ||||||
|  |             w_en: true, | ||||||
|  |             w_data: [0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10], | ||||||
|  |             w_mask: [true; 8], | ||||||
|  |         }, | ||||||
|  |         IO { | ||||||
|  |             r_addr: 0, | ||||||
|  |             r_en: false, | ||||||
|  |             r_data: [0; 8], | ||||||
|  |             w_addr: 1, | ||||||
|  |             w_en: true, | ||||||
|  |             w_data: [0x13, 0x57, 0x9B, 0xDF, 0x02, 0x46, 0x8A, 0xCE], | ||||||
|  |             w_mask: [true; 8], | ||||||
|  |         }, | ||||||
|  |         IO { | ||||||
|  |             r_addr: 0, | ||||||
|  |             r_en: false, | ||||||
|  |             r_data: [0; 8], | ||||||
|  |             w_addr: 2, | ||||||
|  |             w_en: true, | ||||||
|  |             w_data: *b"testing!", | ||||||
|  |             w_mask: [true; 8], | ||||||
|  |         }, | ||||||
|  |         IO { | ||||||
|  |             r_addr: 0, | ||||||
|  |             r_en: false, | ||||||
|  |             r_data: [0; 8], | ||||||
|  |             w_addr: 3, | ||||||
|  |             w_en: true, | ||||||
|  |             w_data: *b"more tst", | ||||||
|  |             w_mask: [true; 8], | ||||||
|  |         }, | ||||||
|  |         IO { | ||||||
|  |             r_addr: 0, | ||||||
|  |             r_en: true, | ||||||
|  |             r_data: [0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10], | ||||||
|  |             w_addr: 0, | ||||||
|  |             w_en: false, | ||||||
|  |             w_data: [0; 8], | ||||||
|  |             w_mask: [false; 8], | ||||||
|  |         }, | ||||||
|  |         IO { | ||||||
|  |             r_addr: 1, | ||||||
|  |             r_en: true, | ||||||
|  |             r_data: [0x13, 0x57, 0x9B, 0xDF, 0x02, 0x46, 0x8A, 0xCE], | ||||||
|  |             w_addr: 0, | ||||||
|  |             w_en: false, | ||||||
|  |             w_data: [0; 8], | ||||||
|  |             w_mask: [false; 8], | ||||||
|  |         }, | ||||||
|  |         IO { | ||||||
|  |             r_addr: 2, | ||||||
|  |             r_en: true, | ||||||
|  |             r_data: *b"testing!", | ||||||
|  |             w_addr: 0, | ||||||
|  |             w_en: false, | ||||||
|  |             w_data: [0; 8], | ||||||
|  |             w_mask: [false; 8], | ||||||
|  |         }, | ||||||
|  |         IO { | ||||||
|  |             r_addr: 3, | ||||||
|  |             r_en: true, | ||||||
|  |             r_data: *b"more tst", | ||||||
|  |             w_addr: 0, | ||||||
|  |             w_en: false, | ||||||
|  |             w_data: [0; 8], | ||||||
|  |             w_mask: [false; 8], | ||||||
|  |         }, | ||||||
|  |     ]; | ||||||
|  |     for cycle in 0..io_cycles.len() + 2 { | ||||||
|  |         { | ||||||
|  |             let IO { | ||||||
|  |                 r_addr, | ||||||
|  |                 r_en, | ||||||
|  |                 r_data: _, | ||||||
|  |                 w_addr, | ||||||
|  |                 w_en, | ||||||
|  |                 w_data, | ||||||
|  |                 w_mask, | ||||||
|  |             } = io_cycles.get(cycle).copied().unwrap_or(IO { | ||||||
|  |                 r_addr: 0, | ||||||
|  |                 r_en: false, | ||||||
|  |                 r_data: [0; 8], | ||||||
|  |                 w_addr: 0, | ||||||
|  |                 w_en: false, | ||||||
|  |                 w_data: [0; 8], | ||||||
|  |                 w_mask: [false; 8], | ||||||
|  |             }); | ||||||
|  |             sim.write_bool_or_int(sim.io().r.addr, r_addr.cast_to_static()); | ||||||
|  |             sim.write_bool(sim.io().r.en, r_en); | ||||||
|  |             sim.write_bool_or_int(sim.io().w.addr, w_addr.cast_to_static()); | ||||||
|  |             sim.write_bool(sim.io().w.en, w_en); | ||||||
|  |             for (i, v) in w_data.into_iter().enumerate() { | ||||||
|  |                 sim.write_bool_or_int(sim.io().w.data[i], v); | ||||||
|  |             } | ||||||
|  |             for (i, v) in w_mask.into_iter().enumerate() { | ||||||
|  |                 sim.write_bool_or_int(sim.io().w.mask[i], v); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         sim.advance_time(SimDuration::from_nanos(250)); | ||||||
|  |         sim.write_clock(sim.io().r.clk, true); | ||||||
|  |         sim.write_clock(sim.io().w.clk, true); | ||||||
|  |         sim.advance_time(SimDuration::from_nanos(250)); | ||||||
|  |         if let Some( | ||||||
|  |             expected @ IO { | ||||||
|  |                 r_addr, | ||||||
|  |                 r_en, | ||||||
|  |                 r_data: _, | ||||||
|  |                 w_addr, | ||||||
|  |                 w_en, | ||||||
|  |                 w_data, | ||||||
|  |                 w_mask, | ||||||
|  |             }, | ||||||
|  |         ) = cycle.checked_sub(1).and_then(|i| io_cycles.get(i).copied()) | ||||||
|  |         { | ||||||
|  |             let io = IO { | ||||||
|  |                 r_addr, | ||||||
|  |                 r_en, | ||||||
|  |                 r_data: std::array::from_fn(|i| { | ||||||
|  |                     sim.read_bool_or_int(sim.io().r.data[i]) | ||||||
|  |                         .to_bigint() | ||||||
|  |                         .try_into() | ||||||
|  |                         .expect("known to be in range") | ||||||
|  |                 }), | ||||||
|  |                 w_addr, | ||||||
|  |                 w_en, | ||||||
|  |                 w_data, | ||||||
|  |                 w_mask, | ||||||
|  |             }; | ||||||
|  |             assert_eq!( | ||||||
|  |                 expected, | ||||||
|  |                 io, | ||||||
|  |                 "vcd:\n{}\ncycle: {cycle}", | ||||||
|  |                 String::from_utf8(writer.take()).unwrap(), | ||||||
|  |             ); | ||||||
|  |         } | ||||||
|  |         sim.advance_time(SimDuration::from_nanos(250)); | ||||||
|  |         sim.write_clock(sim.io().r.clk, false); | ||||||
|  |         sim.write_clock(sim.io().w.clk, false); | ||||||
|  |         sim.advance_time(SimDuration::from_nanos(250)); | ||||||
|  |     } | ||||||
|  |     sim.flush_traces().unwrap(); | ||||||
|  |     let vcd = String::from_utf8(writer.take()).unwrap(); | ||||||
|  |     println!("####### VCD:\n{vcd}\n#######"); | ||||||
|  |     if vcd != include_str!("sim/expected/memories3.vcd") { | ||||||
|  |         panic!(); | ||||||
|  |     } | ||||||
|  |     let sim_debug = format!("{sim:#?}"); | ||||||
|  |     println!("#######\n{sim_debug}\n#######"); | ||||||
|  |     if sim_debug != include_str!("sim/expected/memories3.txt") { | ||||||
|  |         panic!(); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							|  | @ -9,18 +9,25 @@ $var wire 2 $ which_in $end | ||||||
| $var wire 4 % data_in $end | $var wire 4 % data_in $end | ||||||
| $var wire 2 & which_out $end | $var wire 2 & which_out $end | ||||||
| $var wire 4 ' data_out $end | $var wire 4 ' data_out $end | ||||||
| $scope struct the_reg $end | $scope struct b_out $end | ||||||
| $var string 1 ( \$tag $end | $var string 1 ( \$tag $end | ||||||
|  | $scope struct HdlSome $end | ||||||
|  | $var wire 1 ) \0 $end | ||||||
|  | $var wire 1 * \1 $end | ||||||
|  | $upscope $end | ||||||
|  | $upscope $end | ||||||
|  | $scope struct the_reg $end | ||||||
|  | $var string 1 + \$tag $end | ||||||
| $scope struct B $end | $scope struct B $end | ||||||
| $var reg 1 ) \0 $end | $var reg 1 , \0 $end | ||||||
| $var reg 1 * \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 + \[0] $end | $var reg 1 . \[0] $end | ||||||
| $var reg 1 , \[1] $end | $var reg 1 / \[1] $end | ||||||
| $upscope $end | $upscope $end | ||||||
| $var reg 2 - b $end | $var reg 2 0 b $end | ||||||
| $upscope $end | $upscope $end | ||||||
| $upscope $end | $upscope $end | ||||||
| $upscope $end | $upscope $end | ||||||
|  | @ -33,12 +40,15 @@ b0 $ | ||||||
| b0 % | b0 % | ||||||
| b0 & | b0 & | ||||||
| b0 ' | b0 ' | ||||||
| sA\x20(0) ( | sHdlNone\x20(0) ( | ||||||
| 0) | 0) | ||||||
| 0* | 0* | ||||||
| 0+ | sA\x20(0) + | ||||||
| 0, | 0, | ||||||
| b0 - | 0- | ||||||
|  | 0. | ||||||
|  | 0/ | ||||||
|  | b0 0 | ||||||
| $end | $end | ||||||
| #1000000 | #1000000 | ||||||
| 1! | 1! | ||||||
|  | @ -55,7 +65,8 @@ b1 $ | ||||||
| #5000000 | #5000000 | ||||||
| 1! | 1! | ||||||
| b1 & | b1 & | ||||||
| sB\x20(1) ( | sHdlSome\x20(1) ( | ||||||
|  | sB\x20(1) + | ||||||
| #6000000 | #6000000 | ||||||
| 0# | 0# | ||||||
| b0 $ | b0 $ | ||||||
|  | @ -72,8 +83,10 @@ b1111 % | ||||||
| b11 ' | b11 ' | ||||||
| 1) | 1) | ||||||
| 1* | 1* | ||||||
| 1+ |  | ||||||
| 1, | 1, | ||||||
|  | 1- | ||||||
|  | 1. | ||||||
|  | 1/ | ||||||
| #10000000 | #10000000 | ||||||
| 0! | 0! | ||||||
| #11000000 | #11000000 | ||||||
|  | @ -85,8 +98,11 @@ b10 $ | ||||||
| 1! | 1! | ||||||
| b10 & | b10 & | ||||||
| b1111 ' | b1111 ' | ||||||
| sC\x20(2) ( | sHdlNone\x20(0) ( | ||||||
| b11 - | 0) | ||||||
|  | 0* | ||||||
|  | sC\x20(2) + | ||||||
|  | b11 0 | ||||||
| #14000000 | #14000000 | ||||||
| 0! | 0! | ||||||
| #15000000 | #15000000 | ||||||
|  |  | ||||||
							
								
								
									
										1694
									
								
								crates/fayalite/tests/sim/expected/memories2.txt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1694
									
								
								crates/fayalite/tests/sim/expected/memories2.txt
									
										
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										363
									
								
								crates/fayalite/tests/sim/expected/memories2.vcd
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										363
									
								
								crates/fayalite/tests/sim/expected/memories2.vcd
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,363 @@ | ||||||
|  | $timescale 1 ps $end | ||||||
|  | $scope module memories2 $end | ||||||
|  | $scope struct rw $end | ||||||
|  | $var wire 3 ! addr $end | ||||||
|  | $var wire 1 " en $end | ||||||
|  | $var wire 1 # clk $end | ||||||
|  | $var wire 2 $ rdata $end | ||||||
|  | $var wire 1 % wmode $end | ||||||
|  | $var wire 2 & wdata $end | ||||||
|  | $var wire 1 ' wmask $end | ||||||
|  | $upscope $end | ||||||
|  | $scope struct mem $end | ||||||
|  | $scope struct contents $end | ||||||
|  | $scope struct [0] $end | ||||||
|  | $scope struct mem $end | ||||||
|  | $var string 1 1 \$tag $end | ||||||
|  | $var reg 1 6 HdlSome $end | ||||||
|  | $upscope $end | ||||||
|  | $upscope $end | ||||||
|  | $scope struct [1] $end | ||||||
|  | $scope struct mem $end | ||||||
|  | $var string 1 2 \$tag $end | ||||||
|  | $var reg 1 7 HdlSome $end | ||||||
|  | $upscope $end | ||||||
|  | $upscope $end | ||||||
|  | $scope struct [2] $end | ||||||
|  | $scope struct mem $end | ||||||
|  | $var string 1 3 \$tag $end | ||||||
|  | $var reg 1 8 HdlSome $end | ||||||
|  | $upscope $end | ||||||
|  | $upscope $end | ||||||
|  | $scope struct [3] $end | ||||||
|  | $scope struct mem $end | ||||||
|  | $var string 1 4 \$tag $end | ||||||
|  | $var reg 1 9 HdlSome $end | ||||||
|  | $upscope $end | ||||||
|  | $upscope $end | ||||||
|  | $scope struct [4] $end | ||||||
|  | $scope struct mem $end | ||||||
|  | $var string 1 5 \$tag $end | ||||||
|  | $var reg 1 : HdlSome $end | ||||||
|  | $upscope $end | ||||||
|  | $upscope $end | ||||||
|  | $upscope $end | ||||||
|  | $scope struct rw0 $end | ||||||
|  | $var wire 3 ( addr $end | ||||||
|  | $var wire 1 ) en $end | ||||||
|  | $var wire 1 * clk $end | ||||||
|  | $scope struct rdata $end | ||||||
|  | $var string 1 + \$tag $end | ||||||
|  | $var wire 1 , HdlSome $end | ||||||
|  | $upscope $end | ||||||
|  | $var wire 1 - wmode $end | ||||||
|  | $scope struct wdata $end | ||||||
|  | $var string 1 . \$tag $end | ||||||
|  | $var wire 1 / HdlSome $end | ||||||
|  | $upscope $end | ||||||
|  | $var wire 1 0 wmask $end | ||||||
|  | $upscope $end | ||||||
|  | $upscope $end | ||||||
|  | $upscope $end | ||||||
|  | $enddefinitions $end | ||||||
|  | $dumpvars | ||||||
|  | sHdlSome\x20(1) 1 | ||||||
|  | 16 | ||||||
|  | sHdlSome\x20(1) 2 | ||||||
|  | 17 | ||||||
|  | sHdlSome\x20(1) 3 | ||||||
|  | 18 | ||||||
|  | sHdlSome\x20(1) 4 | ||||||
|  | 19 | ||||||
|  | sHdlSome\x20(1) 5 | ||||||
|  | 1: | ||||||
|  | b0 ! | ||||||
|  | 0" | ||||||
|  | 0# | ||||||
|  | b0 $ | ||||||
|  | 0% | ||||||
|  | b0 & | ||||||
|  | 0' | ||||||
|  | b0 ( | ||||||
|  | 0) | ||||||
|  | 0* | ||||||
|  | sHdlNone\x20(0) + | ||||||
|  | 0, | ||||||
|  | 0- | ||||||
|  | sHdlNone\x20(0) . | ||||||
|  | 0/ | ||||||
|  | 00 | ||||||
|  | $end | ||||||
|  | #250000 | ||||||
|  | 1# | ||||||
|  | 1* | ||||||
|  | #500000 | ||||||
|  | #750000 | ||||||
|  | 0# | ||||||
|  | 0* | ||||||
|  | #1000000 | ||||||
|  | 1" | ||||||
|  | 1) | ||||||
|  | #1250000 | ||||||
|  | 1# | ||||||
|  | 1* | ||||||
|  | b11 $ | ||||||
|  | sHdlSome\x20(1) + | ||||||
|  | 1, | ||||||
|  | #1500000 | ||||||
|  | #1750000 | ||||||
|  | 0# | ||||||
|  | 0* | ||||||
|  | #2000000 | ||||||
|  | 0" | ||||||
|  | 0) | ||||||
|  | #2250000 | ||||||
|  | 1# | ||||||
|  | 1* | ||||||
|  | b0 $ | ||||||
|  | sHdlNone\x20(0) + | ||||||
|  | 0, | ||||||
|  | #2500000 | ||||||
|  | #2750000 | ||||||
|  | 0# | ||||||
|  | 0* | ||||||
|  | #3000000 | ||||||
|  | 1" | ||||||
|  | 1% | ||||||
|  | 1' | ||||||
|  | 1) | ||||||
|  | 1- | ||||||
|  | 10 | ||||||
|  | #3250000 | ||||||
|  | sHdlNone\x20(0) 1 | ||||||
|  | 06 | ||||||
|  | 1# | ||||||
|  | 1* | ||||||
|  | #3500000 | ||||||
|  | #3750000 | ||||||
|  | 0# | ||||||
|  | 0* | ||||||
|  | #4000000 | ||||||
|  | 0% | ||||||
|  | 0' | ||||||
|  | 0- | ||||||
|  | 00 | ||||||
|  | #4250000 | ||||||
|  | 1# | ||||||
|  | 1* | ||||||
|  | #4500000 | ||||||
|  | #4750000 | ||||||
|  | 0# | ||||||
|  | 0* | ||||||
|  | #5000000 | ||||||
|  | 1% | ||||||
|  | b11 & | ||||||
|  | 1- | ||||||
|  | sHdlSome\x20(1) . | ||||||
|  | 1/ | ||||||
|  | #5250000 | ||||||
|  | 1# | ||||||
|  | 1* | ||||||
|  | #5500000 | ||||||
|  | #5750000 | ||||||
|  | 0# | ||||||
|  | 0* | ||||||
|  | #6000000 | ||||||
|  | b1 ! | ||||||
|  | b1 & | ||||||
|  | 1' | ||||||
|  | b1 ( | ||||||
|  | 0/ | ||||||
|  | 10 | ||||||
|  | #6250000 | ||||||
|  | sHdlSome\x20(1) 2 | ||||||
|  | 07 | ||||||
|  | 1# | ||||||
|  | 1* | ||||||
|  | #6500000 | ||||||
|  | #6750000 | ||||||
|  | 0# | ||||||
|  | 0* | ||||||
|  | #7000000 | ||||||
|  | b10 ! | ||||||
|  | b10 & | ||||||
|  | b10 ( | ||||||
|  | sHdlNone\x20(0) . | ||||||
|  | #7250000 | ||||||
|  | sHdlNone\x20(0) 3 | ||||||
|  | 08 | ||||||
|  | 1# | ||||||
|  | 1* | ||||||
|  | #7500000 | ||||||
|  | #7750000 | ||||||
|  | 0# | ||||||
|  | 0* | ||||||
|  | #8000000 | ||||||
|  | b11 ! | ||||||
|  | b11 & | ||||||
|  | b11 ( | ||||||
|  | sHdlSome\x20(1) . | ||||||
|  | 1/ | ||||||
|  | #8250000 | ||||||
|  | sHdlSome\x20(1) 4 | ||||||
|  | 19 | ||||||
|  | 1# | ||||||
|  | 1* | ||||||
|  | #8500000 | ||||||
|  | #8750000 | ||||||
|  | 0# | ||||||
|  | 0* | ||||||
|  | #9000000 | ||||||
|  | b100 ! | ||||||
|  | b10 & | ||||||
|  | b100 ( | ||||||
|  | sHdlNone\x20(0) . | ||||||
|  | 0/ | ||||||
|  | #9250000 | ||||||
|  | sHdlNone\x20(0) 5 | ||||||
|  | 0: | ||||||
|  | 1# | ||||||
|  | 1* | ||||||
|  | #9500000 | ||||||
|  | #9750000 | ||||||
|  | 0# | ||||||
|  | 0* | ||||||
|  | #10000000 | ||||||
|  | b101 ! | ||||||
|  | b1 & | ||||||
|  | b101 ( | ||||||
|  | sHdlSome\x20(1) . | ||||||
|  | #10250000 | ||||||
|  | 1# | ||||||
|  | 1* | ||||||
|  | #10500000 | ||||||
|  | #10750000 | ||||||
|  | 0# | ||||||
|  | 0* | ||||||
|  | #11000000 | ||||||
|  | b110 ! | ||||||
|  | b110 ( | ||||||
|  | #11250000 | ||||||
|  | 1# | ||||||
|  | 1* | ||||||
|  | #11500000 | ||||||
|  | #11750000 | ||||||
|  | 0# | ||||||
|  | 0* | ||||||
|  | #12000000 | ||||||
|  | b111 ! | ||||||
|  | b111 ( | ||||||
|  | #12250000 | ||||||
|  | 1# | ||||||
|  | 1* | ||||||
|  | #12500000 | ||||||
|  | #12750000 | ||||||
|  | 0# | ||||||
|  | 0* | ||||||
|  | #13000000 | ||||||
|  | 0% | ||||||
|  | b0 & | ||||||
|  | 0' | ||||||
|  | 0- | ||||||
|  | sHdlNone\x20(0) . | ||||||
|  | 00 | ||||||
|  | #13250000 | ||||||
|  | 1# | ||||||
|  | 1* | ||||||
|  | #13500000 | ||||||
|  | #13750000 | ||||||
|  | 0# | ||||||
|  | 0* | ||||||
|  | #14000000 | ||||||
|  | b110 ! | ||||||
|  | b110 ( | ||||||
|  | #14250000 | ||||||
|  | 1# | ||||||
|  | 1* | ||||||
|  | #14500000 | ||||||
|  | #14750000 | ||||||
|  | 0# | ||||||
|  | 0* | ||||||
|  | #15000000 | ||||||
|  | b101 ! | ||||||
|  | b101 ( | ||||||
|  | #15250000 | ||||||
|  | 1# | ||||||
|  | 1* | ||||||
|  | #15500000 | ||||||
|  | #15750000 | ||||||
|  | 0# | ||||||
|  | 0* | ||||||
|  | #16000000 | ||||||
|  | b100 ! | ||||||
|  | b100 ( | ||||||
|  | #16250000 | ||||||
|  | 1# | ||||||
|  | 1* | ||||||
|  | #16500000 | ||||||
|  | #16750000 | ||||||
|  | 0# | ||||||
|  | 0* | ||||||
|  | #17000000 | ||||||
|  | b11 ! | ||||||
|  | b11 ( | ||||||
|  | #17250000 | ||||||
|  | 1# | ||||||
|  | 1* | ||||||
|  | b11 $ | ||||||
|  | sHdlSome\x20(1) + | ||||||
|  | 1, | ||||||
|  | #17500000 | ||||||
|  | #17750000 | ||||||
|  | 0# | ||||||
|  | 0* | ||||||
|  | #18000000 | ||||||
|  | b10 ! | ||||||
|  | b10 ( | ||||||
|  | #18250000 | ||||||
|  | 1# | ||||||
|  | 1* | ||||||
|  | b0 $ | ||||||
|  | sHdlNone\x20(0) + | ||||||
|  | 0, | ||||||
|  | #18500000 | ||||||
|  | #18750000 | ||||||
|  | 0# | ||||||
|  | 0* | ||||||
|  | #19000000 | ||||||
|  | b0 ! | ||||||
|  | b0 ( | ||||||
|  | #19250000 | ||||||
|  | 1# | ||||||
|  | 1* | ||||||
|  | #19500000 | ||||||
|  | #19750000 | ||||||
|  | 0# | ||||||
|  | 0* | ||||||
|  | #20000000 | ||||||
|  | b1 ! | ||||||
|  | b1 ( | ||||||
|  | #20250000 | ||||||
|  | 1# | ||||||
|  | 1* | ||||||
|  | b1 $ | ||||||
|  | sHdlSome\x20(1) + | ||||||
|  | #20500000 | ||||||
|  | #20750000 | ||||||
|  | 0# | ||||||
|  | 0* | ||||||
|  | #21000000 | ||||||
|  | b0 ! | ||||||
|  | 0" | ||||||
|  | b0 ( | ||||||
|  | 0) | ||||||
|  | #21250000 | ||||||
|  | 1# | ||||||
|  | 1* | ||||||
|  | b0 $ | ||||||
|  | sHdlNone\x20(0) + | ||||||
|  | #21500000 | ||||||
|  | #21750000 | ||||||
|  | 0# | ||||||
|  | 0* | ||||||
|  | #22000000 | ||||||
							
								
								
									
										4882
									
								
								crates/fayalite/tests/sim/expected/memories3.txt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										4882
									
								
								crates/fayalite/tests/sim/expected/memories3.txt
									
										
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										836
									
								
								crates/fayalite/tests/sim/expected/memories3.vcd
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										836
									
								
								crates/fayalite/tests/sim/expected/memories3.vcd
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,836 @@ | ||||||
|  | $timescale 1 ps $end | ||||||
|  | $scope module memories3 $end | ||||||
|  | $scope struct r $end | ||||||
|  | $var wire 3 ! addr $end | ||||||
|  | $var wire 1 " en $end | ||||||
|  | $var wire 1 # clk $end | ||||||
|  | $scope struct data $end | ||||||
|  | $var wire 8 $ \[0] $end | ||||||
|  | $var wire 8 % \[1] $end | ||||||
|  | $var wire 8 & \[2] $end | ||||||
|  | $var wire 8 ' \[3] $end | ||||||
|  | $var wire 8 ( \[4] $end | ||||||
|  | $var wire 8 ) \[5] $end | ||||||
|  | $var wire 8 * \[6] $end | ||||||
|  | $var wire 8 + \[7] $end | ||||||
|  | $upscope $end | ||||||
|  | $upscope $end | ||||||
|  | $scope struct w $end | ||||||
|  | $var wire 3 , addr $end | ||||||
|  | $var wire 1 - en $end | ||||||
|  | $var wire 1 . clk $end | ||||||
|  | $scope struct data $end | ||||||
|  | $var wire 8 / \[0] $end | ||||||
|  | $var wire 8 0 \[1] $end | ||||||
|  | $var wire 8 1 \[2] $end | ||||||
|  | $var wire 8 2 \[3] $end | ||||||
|  | $var wire 8 3 \[4] $end | ||||||
|  | $var wire 8 4 \[5] $end | ||||||
|  | $var wire 8 5 \[6] $end | ||||||
|  | $var wire 8 6 \[7] $end | ||||||
|  | $upscope $end | ||||||
|  | $scope struct mask $end | ||||||
|  | $var wire 1 7 \[0] $end | ||||||
|  | $var wire 1 8 \[1] $end | ||||||
|  | $var wire 1 9 \[2] $end | ||||||
|  | $var wire 1 : \[3] $end | ||||||
|  | $var wire 1 ; \[4] $end | ||||||
|  | $var wire 1 < \[5] $end | ||||||
|  | $var wire 1 = \[6] $end | ||||||
|  | $var wire 1 > \[7] $end | ||||||
|  | $upscope $end | ||||||
|  | $upscope $end | ||||||
|  | $scope struct mem $end | ||||||
|  | $scope struct contents $end | ||||||
|  | $scope struct [0] $end | ||||||
|  | $scope struct mem $end | ||||||
|  | $var reg 8 ] \[0] $end | ||||||
|  | $var reg 8 e \[1] $end | ||||||
|  | $var reg 8 m \[2] $end | ||||||
|  | $var reg 8 u \[3] $end | ||||||
|  | $var reg 8 } \[4] $end | ||||||
|  | $var reg 8 '" \[5] $end | ||||||
|  | $var reg 8 /" \[6] $end | ||||||
|  | $var reg 8 7" \[7] $end | ||||||
|  | $upscope $end | ||||||
|  | $upscope $end | ||||||
|  | $scope struct [1] $end | ||||||
|  | $scope struct mem $end | ||||||
|  | $var reg 8 ^ \[0] $end | ||||||
|  | $var reg 8 f \[1] $end | ||||||
|  | $var reg 8 n \[2] $end | ||||||
|  | $var reg 8 v \[3] $end | ||||||
|  | $var reg 8 ~ \[4] $end | ||||||
|  | $var reg 8 (" \[5] $end | ||||||
|  | $var reg 8 0" \[6] $end | ||||||
|  | $var reg 8 8" \[7] $end | ||||||
|  | $upscope $end | ||||||
|  | $upscope $end | ||||||
|  | $scope struct [2] $end | ||||||
|  | $scope struct mem $end | ||||||
|  | $var reg 8 _ \[0] $end | ||||||
|  | $var reg 8 g \[1] $end | ||||||
|  | $var reg 8 o \[2] $end | ||||||
|  | $var reg 8 w \[3] $end | ||||||
|  | $var reg 8 !" \[4] $end | ||||||
|  | $var reg 8 )" \[5] $end | ||||||
|  | $var reg 8 1" \[6] $end | ||||||
|  | $var reg 8 9" \[7] $end | ||||||
|  | $upscope $end | ||||||
|  | $upscope $end | ||||||
|  | $scope struct [3] $end | ||||||
|  | $scope struct mem $end | ||||||
|  | $var reg 8 ` \[0] $end | ||||||
|  | $var reg 8 h \[1] $end | ||||||
|  | $var reg 8 p \[2] $end | ||||||
|  | $var reg 8 x \[3] $end | ||||||
|  | $var reg 8 "" \[4] $end | ||||||
|  | $var reg 8 *" \[5] $end | ||||||
|  | $var reg 8 2" \[6] $end | ||||||
|  | $var reg 8 :" \[7] $end | ||||||
|  | $upscope $end | ||||||
|  | $upscope $end | ||||||
|  | $scope struct [4] $end | ||||||
|  | $scope struct mem $end | ||||||
|  | $var reg 8 a \[0] $end | ||||||
|  | $var reg 8 i \[1] $end | ||||||
|  | $var reg 8 q \[2] $end | ||||||
|  | $var reg 8 y \[3] $end | ||||||
|  | $var reg 8 #" \[4] $end | ||||||
|  | $var reg 8 +" \[5] $end | ||||||
|  | $var reg 8 3" \[6] $end | ||||||
|  | $var reg 8 ;" \[7] $end | ||||||
|  | $upscope $end | ||||||
|  | $upscope $end | ||||||
|  | $scope struct [5] $end | ||||||
|  | $scope struct mem $end | ||||||
|  | $var reg 8 b \[0] $end | ||||||
|  | $var reg 8 j \[1] $end | ||||||
|  | $var reg 8 r \[2] $end | ||||||
|  | $var reg 8 z \[3] $end | ||||||
|  | $var reg 8 $" \[4] $end | ||||||
|  | $var reg 8 ," \[5] $end | ||||||
|  | $var reg 8 4" \[6] $end | ||||||
|  | $var reg 8 <" \[7] $end | ||||||
|  | $upscope $end | ||||||
|  | $upscope $end | ||||||
|  | $scope struct [6] $end | ||||||
|  | $scope struct mem $end | ||||||
|  | $var reg 8 c \[0] $end | ||||||
|  | $var reg 8 k \[1] $end | ||||||
|  | $var reg 8 s \[2] $end | ||||||
|  | $var reg 8 { \[3] $end | ||||||
|  | $var reg 8 %" \[4] $end | ||||||
|  | $var reg 8 -" \[5] $end | ||||||
|  | $var reg 8 5" \[6] $end | ||||||
|  | $var reg 8 =" \[7] $end | ||||||
|  | $upscope $end | ||||||
|  | $upscope $end | ||||||
|  | $scope struct [7] $end | ||||||
|  | $scope struct mem $end | ||||||
|  | $var reg 8 d \[0] $end | ||||||
|  | $var reg 8 l \[1] $end | ||||||
|  | $var reg 8 t \[2] $end | ||||||
|  | $var reg 8 | \[3] $end | ||||||
|  | $var reg 8 &" \[4] $end | ||||||
|  | $var reg 8 ." \[5] $end | ||||||
|  | $var reg 8 6" \[6] $end | ||||||
|  | $var reg 8 >" \[7] $end | ||||||
|  | $upscope $end | ||||||
|  | $upscope $end | ||||||
|  | $upscope $end | ||||||
|  | $scope struct r0 $end | ||||||
|  | $var wire 3 ? addr $end | ||||||
|  | $var wire 1 @ en $end | ||||||
|  | $var wire 1 A clk $end | ||||||
|  | $scope struct data $end | ||||||
|  | $var wire 8 B \[0] $end | ||||||
|  | $var wire 8 C \[1] $end | ||||||
|  | $var wire 8 D \[2] $end | ||||||
|  | $var wire 8 E \[3] $end | ||||||
|  | $var wire 8 F \[4] $end | ||||||
|  | $var wire 8 G \[5] $end | ||||||
|  | $var wire 8 H \[6] $end | ||||||
|  | $var wire 8 I \[7] $end | ||||||
|  | $upscope $end | ||||||
|  | $upscope $end | ||||||
|  | $scope struct w1 $end | ||||||
|  | $var wire 3 J addr $end | ||||||
|  | $var wire 1 K en $end | ||||||
|  | $var wire 1 L clk $end | ||||||
|  | $scope struct data $end | ||||||
|  | $var wire 8 M \[0] $end | ||||||
|  | $var wire 8 N \[1] $end | ||||||
|  | $var wire 8 O \[2] $end | ||||||
|  | $var wire 8 P \[3] $end | ||||||
|  | $var wire 8 Q \[4] $end | ||||||
|  | $var wire 8 R \[5] $end | ||||||
|  | $var wire 8 S \[6] $end | ||||||
|  | $var wire 8 T \[7] $end | ||||||
|  | $upscope $end | ||||||
|  | $scope struct mask $end | ||||||
|  | $var wire 1 U \[0] $end | ||||||
|  | $var wire 1 V \[1] $end | ||||||
|  | $var wire 1 W \[2] $end | ||||||
|  | $var wire 1 X \[3] $end | ||||||
|  | $var wire 1 Y \[4] $end | ||||||
|  | $var wire 1 Z \[5] $end | ||||||
|  | $var wire 1 [ \[6] $end | ||||||
|  | $var wire 1 \ \[7] $end | ||||||
|  | $upscope $end | ||||||
|  | $upscope $end | ||||||
|  | $upscope $end | ||||||
|  | $upscope $end | ||||||
|  | $enddefinitions $end | ||||||
|  | $dumpvars | ||||||
|  | b0 ] | ||||||
|  | b0 e | ||||||
|  | b0 m | ||||||
|  | b0 u | ||||||
|  | b0 } | ||||||
|  | b0 '" | ||||||
|  | b0 /" | ||||||
|  | b0 7" | ||||||
|  | b0 ^ | ||||||
|  | b0 f | ||||||
|  | b0 n | ||||||
|  | b0 v | ||||||
|  | b0 ~ | ||||||
|  | b0 (" | ||||||
|  | b0 0" | ||||||
|  | b0 8" | ||||||
|  | b0 _ | ||||||
|  | b0 g | ||||||
|  | b0 o | ||||||
|  | b0 w | ||||||
|  | b0 !" | ||||||
|  | b0 )" | ||||||
|  | b0 1" | ||||||
|  | b0 9" | ||||||
|  | b0 ` | ||||||
|  | b0 h | ||||||
|  | b0 p | ||||||
|  | b0 x | ||||||
|  | b0 "" | ||||||
|  | b0 *" | ||||||
|  | b0 2" | ||||||
|  | b0 :" | ||||||
|  | b0 a | ||||||
|  | b0 i | ||||||
|  | b0 q | ||||||
|  | b0 y | ||||||
|  | b0 #" | ||||||
|  | b0 +" | ||||||
|  | b0 3" | ||||||
|  | b0 ;" | ||||||
|  | b0 b | ||||||
|  | b0 j | ||||||
|  | b0 r | ||||||
|  | b0 z | ||||||
|  | b0 $" | ||||||
|  | b0 ," | ||||||
|  | b0 4" | ||||||
|  | b0 <" | ||||||
|  | b0 c | ||||||
|  | b0 k | ||||||
|  | b0 s | ||||||
|  | b0 { | ||||||
|  | b0 %" | ||||||
|  | b0 -" | ||||||
|  | b0 5" | ||||||
|  | b0 =" | ||||||
|  | b0 d | ||||||
|  | b0 l | ||||||
|  | b0 t | ||||||
|  | b0 | | ||||||
|  | b0 &" | ||||||
|  | b0 ." | ||||||
|  | b0 6" | ||||||
|  | b0 >" | ||||||
|  | b0 ! | ||||||
|  | 0" | ||||||
|  | 0# | ||||||
|  | b0 $ | ||||||
|  | b0 % | ||||||
|  | b0 & | ||||||
|  | b0 ' | ||||||
|  | b0 ( | ||||||
|  | b0 ) | ||||||
|  | b0 * | ||||||
|  | b0 + | ||||||
|  | b0 , | ||||||
|  | 1- | ||||||
|  | 0. | ||||||
|  | b10010 / | ||||||
|  | b110100 0 | ||||||
|  | b1010110 1 | ||||||
|  | b1111000 2 | ||||||
|  | b10011010 3 | ||||||
|  | b10111100 4 | ||||||
|  | b11011110 5 | ||||||
|  | b11110000 6 | ||||||
|  | 07 | ||||||
|  | 18 | ||||||
|  | 09 | ||||||
|  | 1: | ||||||
|  | 1; | ||||||
|  | 0< | ||||||
|  | 0= | ||||||
|  | 1> | ||||||
|  | b0 ? | ||||||
|  | 0@ | ||||||
|  | 0A | ||||||
|  | b0 B | ||||||
|  | b0 C | ||||||
|  | b0 D | ||||||
|  | b0 E | ||||||
|  | b0 F | ||||||
|  | b0 G | ||||||
|  | b0 H | ||||||
|  | b0 I | ||||||
|  | b0 J | ||||||
|  | 1K | ||||||
|  | 0L | ||||||
|  | b10010 M | ||||||
|  | b110100 N | ||||||
|  | b1010110 O | ||||||
|  | b1111000 P | ||||||
|  | b10011010 Q | ||||||
|  | b10111100 R | ||||||
|  | b11011110 S | ||||||
|  | b11110000 T | ||||||
|  | 0U | ||||||
|  | 1V | ||||||
|  | 0W | ||||||
|  | 1X | ||||||
|  | 1Y | ||||||
|  | 0Z | ||||||
|  | 0[ | ||||||
|  | 1\ | ||||||
|  | $end | ||||||
|  | #250000 | ||||||
|  | 1# | ||||||
|  | 1. | ||||||
|  | 1A | ||||||
|  | 1L | ||||||
|  | #500000 | ||||||
|  | #750000 | ||||||
|  | 0# | ||||||
|  | 0. | ||||||
|  | 0A | ||||||
|  | 0L | ||||||
|  | #1000000 | ||||||
|  | 1" | ||||||
|  | b1 , | ||||||
|  | 0- | ||||||
|  | b0 / | ||||||
|  | b0 0 | ||||||
|  | b0 1 | ||||||
|  | b0 2 | ||||||
|  | b0 3 | ||||||
|  | b0 4 | ||||||
|  | b0 5 | ||||||
|  | b0 6 | ||||||
|  | 08 | ||||||
|  | 0: | ||||||
|  | 0; | ||||||
|  | 0> | ||||||
|  | 1@ | ||||||
|  | b1 J | ||||||
|  | 0K | ||||||
|  | b0 M | ||||||
|  | b0 N | ||||||
|  | b0 O | ||||||
|  | b0 P | ||||||
|  | b0 Q | ||||||
|  | b0 R | ||||||
|  | b0 S | ||||||
|  | b0 T | ||||||
|  | 0V | ||||||
|  | 0X | ||||||
|  | 0Y | ||||||
|  | 0\ | ||||||
|  | #1250000 | ||||||
|  | b0 ] | ||||||
|  | b110100 e | ||||||
|  | b0 m | ||||||
|  | b1111000 u | ||||||
|  | b10011010 } | ||||||
|  | b0 '" | ||||||
|  | b0 /" | ||||||
|  | b11110000 7" | ||||||
|  | 1# | ||||||
|  | 1. | ||||||
|  | 1A | ||||||
|  | 1L | ||||||
|  | #1500000 | ||||||
|  | #1750000 | ||||||
|  | 0# | ||||||
|  | 0. | ||||||
|  | 0A | ||||||
|  | 0L | ||||||
|  | #2000000 | ||||||
|  | #2250000 | ||||||
|  | 1# | ||||||
|  | 1. | ||||||
|  | 1A | ||||||
|  | 1L | ||||||
|  | #2500000 | ||||||
|  | #2750000 | ||||||
|  | 0# | ||||||
|  | 0. | ||||||
|  | 0A | ||||||
|  | 0L | ||||||
|  | #3000000 | ||||||
|  | b0 , | ||||||
|  | 1- | ||||||
|  | b11111110 / | ||||||
|  | b11011100 0 | ||||||
|  | b10111010 1 | ||||||
|  | b10011000 2 | ||||||
|  | b1110110 3 | ||||||
|  | b1010100 4 | ||||||
|  | b110010 5 | ||||||
|  | b10000 6 | ||||||
|  | 17 | ||||||
|  | 18 | ||||||
|  | 19 | ||||||
|  | 1: | ||||||
|  | 1; | ||||||
|  | 1< | ||||||
|  | 1= | ||||||
|  | 1> | ||||||
|  | b0 J | ||||||
|  | 1K | ||||||
|  | b11111110 M | ||||||
|  | b11011100 N | ||||||
|  | b10111010 O | ||||||
|  | b10011000 P | ||||||
|  | b1110110 Q | ||||||
|  | b1010100 R | ||||||
|  | b110010 S | ||||||
|  | b10000 T | ||||||
|  | 1U | ||||||
|  | 1V | ||||||
|  | 1W | ||||||
|  | 1X | ||||||
|  | 1Y | ||||||
|  | 1Z | ||||||
|  | 1[ | ||||||
|  | 1\ | ||||||
|  | #3250000 | ||||||
|  | 1# | ||||||
|  | 1. | ||||||
|  | 1A | ||||||
|  | b110100 C | ||||||
|  | b1111000 E | ||||||
|  | b10011010 F | ||||||
|  | b11110000 I | ||||||
|  | 1L | ||||||
|  | b110100 % | ||||||
|  | b1111000 ' | ||||||
|  | b10011010 ( | ||||||
|  | b11110000 + | ||||||
|  | #3500000 | ||||||
|  | #3750000 | ||||||
|  | 0# | ||||||
|  | 0. | ||||||
|  | 0A | ||||||
|  | 0L | ||||||
|  | #4000000 | ||||||
|  | #4250000 | ||||||
|  | b11111110 ] | ||||||
|  | b11011100 e | ||||||
|  | b10111010 m | ||||||
|  | b10011000 u | ||||||
|  | b1110110 } | ||||||
|  | b1010100 '" | ||||||
|  | b110010 /" | ||||||
|  | b10000 7" | ||||||
|  | 1# | ||||||
|  | 1. | ||||||
|  | 1A | ||||||
|  | 1L | ||||||
|  | #4500000 | ||||||
|  | #4750000 | ||||||
|  | 0# | ||||||
|  | 0. | ||||||
|  | 0A | ||||||
|  | 0L | ||||||
|  | #5000000 | ||||||
|  | #5250000 | ||||||
|  | b11111110 ] | ||||||
|  | b11011100 e | ||||||
|  | b10111010 m | ||||||
|  | b10011000 u | ||||||
|  | b1110110 } | ||||||
|  | b1010100 '" | ||||||
|  | b110010 /" | ||||||
|  | b10000 7" | ||||||
|  | 1# | ||||||
|  | 1. | ||||||
|  | 1A | ||||||
|  | 1L | ||||||
|  | #5500000 | ||||||
|  | #5750000 | ||||||
|  | 0# | ||||||
|  | 0. | ||||||
|  | 0A | ||||||
|  | 0L | ||||||
|  | #6000000 | ||||||
|  | 0" | ||||||
|  | b1 , | ||||||
|  | b10011 / | ||||||
|  | b1010111 0 | ||||||
|  | b10011011 1 | ||||||
|  | b11011111 2 | ||||||
|  | b10 3 | ||||||
|  | b1000110 4 | ||||||
|  | b10001010 5 | ||||||
|  | b11001110 6 | ||||||
|  | 0@ | ||||||
|  | b1 J | ||||||
|  | b10011 M | ||||||
|  | b1010111 N | ||||||
|  | b10011011 O | ||||||
|  | b11011111 P | ||||||
|  | b10 Q | ||||||
|  | b1000110 R | ||||||
|  | b10001010 S | ||||||
|  | b11001110 T | ||||||
|  | #6250000 | ||||||
|  | b11111110 ] | ||||||
|  | b11011100 e | ||||||
|  | b10111010 m | ||||||
|  | b10011000 u | ||||||
|  | b1110110 } | ||||||
|  | b1010100 '" | ||||||
|  | b110010 /" | ||||||
|  | b10000 7" | ||||||
|  | 1# | ||||||
|  | 1. | ||||||
|  | 1A | ||||||
|  | b11111110 B | ||||||
|  | b11011100 C | ||||||
|  | b10111010 D | ||||||
|  | b10011000 E | ||||||
|  | b1110110 F | ||||||
|  | b1010100 G | ||||||
|  | b110010 H | ||||||
|  | b10000 I | ||||||
|  | 1L | ||||||
|  | b11111110 $ | ||||||
|  | b11011100 % | ||||||
|  | b10111010 & | ||||||
|  | b10011000 ' | ||||||
|  | b1110110 ( | ||||||
|  | b1010100 ) | ||||||
|  | b110010 * | ||||||
|  | b10000 + | ||||||
|  | #6500000 | ||||||
|  | #6750000 | ||||||
|  | 0# | ||||||
|  | 0. | ||||||
|  | 0A | ||||||
|  | 0L | ||||||
|  | #7000000 | ||||||
|  | b10 , | ||||||
|  | b1110100 / | ||||||
|  | b1100101 0 | ||||||
|  | b1110011 1 | ||||||
|  | b1110100 2 | ||||||
|  | b1101001 3 | ||||||
|  | b1101110 4 | ||||||
|  | b1100111 5 | ||||||
|  | b100001 6 | ||||||
|  | b10 J | ||||||
|  | b1110100 M | ||||||
|  | b1100101 N | ||||||
|  | b1110011 O | ||||||
|  | b1110100 P | ||||||
|  | b1101001 Q | ||||||
|  | b1101110 R | ||||||
|  | b1100111 S | ||||||
|  | b100001 T | ||||||
|  | #7250000 | ||||||
|  | b10011 ^ | ||||||
|  | b1010111 f | ||||||
|  | b10011011 n | ||||||
|  | b11011111 v | ||||||
|  | b10 ~ | ||||||
|  | b1000110 (" | ||||||
|  | b10001010 0" | ||||||
|  | b11001110 8" | ||||||
|  | 1# | ||||||
|  | 1. | ||||||
|  | 1A | ||||||
|  | b0 B | ||||||
|  | b0 C | ||||||
|  | b0 D | ||||||
|  | b0 E | ||||||
|  | b0 F | ||||||
|  | b0 G | ||||||
|  | b0 H | ||||||
|  | b0 I | ||||||
|  | 1L | ||||||
|  | b0 $ | ||||||
|  | b0 % | ||||||
|  | b0 & | ||||||
|  | b0 ' | ||||||
|  | b0 ( | ||||||
|  | b0 ) | ||||||
|  | b0 * | ||||||
|  | b0 + | ||||||
|  | #7500000 | ||||||
|  | #7750000 | ||||||
|  | 0# | ||||||
|  | 0. | ||||||
|  | 0A | ||||||
|  | 0L | ||||||
|  | #8000000 | ||||||
|  | b11 , | ||||||
|  | b1101101 / | ||||||
|  | b1101111 0 | ||||||
|  | b1110010 1 | ||||||
|  | b1100101 2 | ||||||
|  | b100000 3 | ||||||
|  | b1110100 4 | ||||||
|  | b1110011 5 | ||||||
|  | b1110100 6 | ||||||
|  | b11 J | ||||||
|  | b1101101 M | ||||||
|  | b1101111 N | ||||||
|  | b1110010 O | ||||||
|  | b1100101 P | ||||||
|  | b100000 Q | ||||||
|  | b1110100 R | ||||||
|  | b1110011 S | ||||||
|  | b1110100 T | ||||||
|  | #8250000 | ||||||
|  | b1110100 _ | ||||||
|  | b1100101 g | ||||||
|  | b1110011 o | ||||||
|  | b1110100 w | ||||||
|  | b1101001 !" | ||||||
|  | b1101110 )" | ||||||
|  | b1100111 1" | ||||||
|  | b100001 9" | ||||||
|  | 1# | ||||||
|  | 1. | ||||||
|  | 1A | ||||||
|  | 1L | ||||||
|  | #8500000 | ||||||
|  | #8750000 | ||||||
|  | 0# | ||||||
|  | 0. | ||||||
|  | 0A | ||||||
|  | 0L | ||||||
|  | #9000000 | ||||||
|  | 1" | ||||||
|  | b0 , | ||||||
|  | 0- | ||||||
|  | b0 / | ||||||
|  | b0 0 | ||||||
|  | b0 1 | ||||||
|  | b0 2 | ||||||
|  | b0 3 | ||||||
|  | b0 4 | ||||||
|  | b0 5 | ||||||
|  | b0 6 | ||||||
|  | 07 | ||||||
|  | 08 | ||||||
|  | 09 | ||||||
|  | 0: | ||||||
|  | 0; | ||||||
|  | 0< | ||||||
|  | 0= | ||||||
|  | 0> | ||||||
|  | 1@ | ||||||
|  | b0 J | ||||||
|  | 0K | ||||||
|  | b0 M | ||||||
|  | b0 N | ||||||
|  | b0 O | ||||||
|  | b0 P | ||||||
|  | b0 Q | ||||||
|  | b0 R | ||||||
|  | b0 S | ||||||
|  | b0 T | ||||||
|  | 0U | ||||||
|  | 0V | ||||||
|  | 0W | ||||||
|  | 0X | ||||||
|  | 0Y | ||||||
|  | 0Z | ||||||
|  | 0[ | ||||||
|  | 0\ | ||||||
|  | #9250000 | ||||||
|  | b1101101 ` | ||||||
|  | b1101111 h | ||||||
|  | b1110010 p | ||||||
|  | b1100101 x | ||||||
|  | b100000 "" | ||||||
|  | b1110100 *" | ||||||
|  | b1110011 2" | ||||||
|  | b1110100 :" | ||||||
|  | 1# | ||||||
|  | 1. | ||||||
|  | 1A | ||||||
|  | 1L | ||||||
|  | #9500000 | ||||||
|  | #9750000 | ||||||
|  | 0# | ||||||
|  | 0. | ||||||
|  | 0A | ||||||
|  | 0L | ||||||
|  | #10000000 | ||||||
|  | b1 ! | ||||||
|  | b1 ? | ||||||
|  | #10250000 | ||||||
|  | 1# | ||||||
|  | 1. | ||||||
|  | 1A | ||||||
|  | b11111110 B | ||||||
|  | b11011100 C | ||||||
|  | b10111010 D | ||||||
|  | b10011000 E | ||||||
|  | b1110110 F | ||||||
|  | b1010100 G | ||||||
|  | b110010 H | ||||||
|  | b10000 I | ||||||
|  | 1L | ||||||
|  | b11111110 $ | ||||||
|  | b11011100 % | ||||||
|  | b10111010 & | ||||||
|  | b10011000 ' | ||||||
|  | b1110110 ( | ||||||
|  | b1010100 ) | ||||||
|  | b110010 * | ||||||
|  | b10000 + | ||||||
|  | #10500000 | ||||||
|  | #10750000 | ||||||
|  | 0# | ||||||
|  | 0. | ||||||
|  | 0A | ||||||
|  | 0L | ||||||
|  | #11000000 | ||||||
|  | b10 ! | ||||||
|  | b10 ? | ||||||
|  | #11250000 | ||||||
|  | 1# | ||||||
|  | 1. | ||||||
|  | 1A | ||||||
|  | b10011 B | ||||||
|  | b1010111 C | ||||||
|  | b10011011 D | ||||||
|  | b11011111 E | ||||||
|  | b10 F | ||||||
|  | b1000110 G | ||||||
|  | b10001010 H | ||||||
|  | b11001110 I | ||||||
|  | 1L | ||||||
|  | b10011 $ | ||||||
|  | b1010111 % | ||||||
|  | b10011011 & | ||||||
|  | b11011111 ' | ||||||
|  | b10 ( | ||||||
|  | b1000110 ) | ||||||
|  | b10001010 * | ||||||
|  | b11001110 + | ||||||
|  | #11500000 | ||||||
|  | #11750000 | ||||||
|  | 0# | ||||||
|  | 0. | ||||||
|  | 0A | ||||||
|  | 0L | ||||||
|  | #12000000 | ||||||
|  | b11 ! | ||||||
|  | b11 ? | ||||||
|  | #12250000 | ||||||
|  | 1# | ||||||
|  | 1. | ||||||
|  | 1A | ||||||
|  | b1110100 B | ||||||
|  | b1100101 C | ||||||
|  | b1110011 D | ||||||
|  | b1110100 E | ||||||
|  | b1101001 F | ||||||
|  | b1101110 G | ||||||
|  | b1100111 H | ||||||
|  | b100001 I | ||||||
|  | 1L | ||||||
|  | b1110100 $ | ||||||
|  | b1100101 % | ||||||
|  | b1110011 & | ||||||
|  | b1110100 ' | ||||||
|  | b1101001 ( | ||||||
|  | b1101110 ) | ||||||
|  | b1100111 * | ||||||
|  | b100001 + | ||||||
|  | #12500000 | ||||||
|  | #12750000 | ||||||
|  | 0# | ||||||
|  | 0. | ||||||
|  | 0A | ||||||
|  | 0L | ||||||
|  | #13000000 | ||||||
|  | b0 ! | ||||||
|  | 0" | ||||||
|  | b0 ? | ||||||
|  | 0@ | ||||||
|  | #13250000 | ||||||
|  | 1# | ||||||
|  | 1. | ||||||
|  | 1A | ||||||
|  | b1101101 B | ||||||
|  | b1101111 C | ||||||
|  | b1110010 D | ||||||
|  | b1100101 E | ||||||
|  | b100000 F | ||||||
|  | b1110100 G | ||||||
|  | b1110011 H | ||||||
|  | b1110100 I | ||||||
|  | 1L | ||||||
|  | b1101101 $ | ||||||
|  | b1101111 % | ||||||
|  | b1110010 & | ||||||
|  | b1100101 ' | ||||||
|  | b100000 ( | ||||||
|  | b1110100 ) | ||||||
|  | b1110011 * | ||||||
|  | b1110100 + | ||||||
|  | #13500000 | ||||||
|  | #13750000 | ||||||
|  | 0# | ||||||
|  | 0. | ||||||
|  | 0A | ||||||
|  | 0L | ||||||
|  | #14000000 | ||||||
|  | #14250000 | ||||||
|  | 1# | ||||||
|  | 1. | ||||||
|  | 1A | ||||||
|  | b0 B | ||||||
|  | b0 C | ||||||
|  | b0 D | ||||||
|  | b0 E | ||||||
|  | b0 F | ||||||
|  | b0 G | ||||||
|  | b0 H | ||||||
|  | b0 I | ||||||
|  | 1L | ||||||
|  | b0 $ | ||||||
|  | b0 % | ||||||
|  | b0 & | ||||||
|  | b0 ' | ||||||
|  | b0 ( | ||||||
|  | b0 ) | ||||||
|  | b0 * | ||||||
|  | b0 + | ||||||
|  | #14500000 | ||||||
|  | #14750000 | ||||||
|  | 0# | ||||||
|  | 0. | ||||||
|  | 0A | ||||||
|  | 0L | ||||||
|  | #15000000 | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue