forked from libre-chip/fayalite
		
	WIP adding simulator
This commit is contained in:
		
							parent
							
								
									3ea0d98924
								
							
						
					
					
						commit
						6f904148c4
					
				
					 3 changed files with 671 additions and 0 deletions
				
			
		|  | @ -46,6 +46,7 @@ pub mod module; | ||||||
| pub mod prelude; | pub mod prelude; | ||||||
| pub mod reg; | pub mod reg; | ||||||
| pub mod reset; | pub mod reset; | ||||||
|  | pub mod sim; | ||||||
| pub mod source_location; | pub mod source_location; | ||||||
| pub mod testing; | pub mod testing; | ||||||
| pub mod ty; | pub mod ty; | ||||||
|  |  | ||||||
							
								
								
									
										206
									
								
								crates/fayalite/src/sim.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										206
									
								
								crates/fayalite/src/sim.rs
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,206 @@ | ||||||
|  | //! Fayalite Simulation
 | ||||||
|  | 
 | ||||||
|  | use crate::{ | ||||||
|  |     bundle::{Bundle, BundleType}, | ||||||
|  |     enum_::Enum, | ||||||
|  |     expr::Expr, | ||||||
|  |     int::Bool, | ||||||
|  |     intern::{Intern, Interned}, | ||||||
|  |     module::{ | ||||||
|  |         Block, Module, ModuleBody, NormalModuleBody, Stmt, StmtConnect, StmtFormal, StmtIf, | ||||||
|  |         StmtMatch, | ||||||
|  |     }, | ||||||
|  |     sim::interpreter::{Insn, Insns, InsnsBuilding}, | ||||||
|  |     source_location::SourceLocation, | ||||||
|  | }; | ||||||
|  | use hashbrown::HashMap; | ||||||
|  | use std::{cell::RefCell, rc::Rc}; | ||||||
|  | 
 | ||||||
|  | mod interpreter; | ||||||
|  | 
 | ||||||
|  | #[derive(Debug)] | ||||||
|  | struct CompilingModule { | ||||||
|  |     compiled_module: Option<CompiledModule>, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] | ||||||
|  | enum CondStack { | ||||||
|  |     Always, | ||||||
|  |     IfTrue { | ||||||
|  |         parent: Interned<CondStack>, | ||||||
|  |         cond: Expr<Bool>, | ||||||
|  |         source_location: SourceLocation, | ||||||
|  |     }, | ||||||
|  |     IfFalse { | ||||||
|  |         parent: Interned<CondStack>, | ||||||
|  |         cond: Expr<Bool>, | ||||||
|  |         source_location: SourceLocation, | ||||||
|  |     }, | ||||||
|  |     MatchArm { | ||||||
|  |         parent: Interned<CondStack>, | ||||||
|  |         enum_expr: Expr<Enum>, | ||||||
|  |         variant_index: usize, | ||||||
|  |         source_location: SourceLocation, | ||||||
|  |     }, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[derive(Debug)] | ||||||
|  | pub struct Compiler { | ||||||
|  |     insns: Insns<InsnsBuilding>, | ||||||
|  |     modules: HashMap<Interned<Module<Bundle>>, Rc<RefCell<CompilingModule>>>, | ||||||
|  |     module_queue: Vec<Interned<Module<Bundle>>>, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl Compiler { | ||||||
|  |     pub fn new() -> Self { | ||||||
|  |         Self { | ||||||
|  |             insns: Insns::new(), | ||||||
|  |             modules: HashMap::new(), | ||||||
|  |             module_queue: Vec::new(), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     pub fn add_module(&mut self, module: Interned<Module<Bundle>>) { | ||||||
|  |         self.modules.entry(module).or_insert_with(|| { | ||||||
|  |             self.module_queue.push(module); | ||||||
|  |             Rc::new(RefCell::new(CompilingModule { | ||||||
|  |                 compiled_module: None, | ||||||
|  |             })) | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  |     fn compile_block( | ||||||
|  |         &mut self, | ||||||
|  |         module: Interned<Module<Bundle>>, | ||||||
|  |         block: Block, | ||||||
|  |         cond_stack: Interned<CondStack>, | ||||||
|  |     ) { | ||||||
|  |         let Block { memories, stmts } = block; | ||||||
|  |         for memory in memories { | ||||||
|  |             todo!("implement memory"); | ||||||
|  |         } | ||||||
|  |         for stmt in stmts { | ||||||
|  |             match stmt { | ||||||
|  |                 Stmt::Connect(StmtConnect { | ||||||
|  |                     lhs, | ||||||
|  |                     rhs, | ||||||
|  |                     source_location, | ||||||
|  |                 }) => todo!(), | ||||||
|  |                 Stmt::Formal(StmtFormal { | ||||||
|  |                     kind, | ||||||
|  |                     clk, | ||||||
|  |                     pred, | ||||||
|  |                     en, | ||||||
|  |                     text, | ||||||
|  |                     source_location, | ||||||
|  |                 }) => todo!("implement simulating formal statements"), | ||||||
|  |                 Stmt::If(StmtIf { | ||||||
|  |                     cond, | ||||||
|  |                     source_location, | ||||||
|  |                     blocks: [then_block, else_block], | ||||||
|  |                 }) => { | ||||||
|  |                     self.compile_block( | ||||||
|  |                         module, | ||||||
|  |                         then_block, | ||||||
|  |                         CondStack::IfTrue { | ||||||
|  |                             parent: cond_stack, | ||||||
|  |                             cond, | ||||||
|  |                             source_location, | ||||||
|  |                         } | ||||||
|  |                         .intern_sized(), | ||||||
|  |                     ); | ||||||
|  |                     self.compile_block( | ||||||
|  |                         module, | ||||||
|  |                         else_block, | ||||||
|  |                         CondStack::IfFalse { | ||||||
|  |                             parent: cond_stack, | ||||||
|  |                             cond, | ||||||
|  |                             source_location, | ||||||
|  |                         } | ||||||
|  |                         .intern_sized(), | ||||||
|  |                     ); | ||||||
|  |                 } | ||||||
|  |                 Stmt::Match(StmtMatch { | ||||||
|  |                     expr, | ||||||
|  |                     source_location, | ||||||
|  |                     blocks, | ||||||
|  |                 }) => { | ||||||
|  |                     for (variant_index, block) in blocks.into_iter().enumerate() { | ||||||
|  |                         self.compile_block( | ||||||
|  |                             module, | ||||||
|  |                             block, | ||||||
|  |                             CondStack::MatchArm { | ||||||
|  |                                 parent: cond_stack, | ||||||
|  |                                 enum_expr: expr, | ||||||
|  |                                 variant_index, | ||||||
|  |                                 source_location, | ||||||
|  |                             } | ||||||
|  |                             .intern_sized(), | ||||||
|  |                         ); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |                 Stmt::Declaration(stmt_declaration) => todo!(), | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     fn compile_module(&mut self, module: Interned<Module<Bundle>>) -> CompiledModule { | ||||||
|  |         let step_entry_pc = self.insns.next_insn_pc(); | ||||||
|  |         match module.body() { | ||||||
|  |             ModuleBody::Normal(NormalModuleBody { body }) => { | ||||||
|  |                 self.compile_block(module, body, CondStack::Always.intern_sized()) | ||||||
|  |             } | ||||||
|  |             ModuleBody::Extern(_extern_module_body) => { | ||||||
|  |                 todo!("simulating extern module: {}", module.name_id()); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         self.insns.push(Insn::Return, module.source_location()); | ||||||
|  |         CompiledModule { step_entry_pc } | ||||||
|  |     } | ||||||
|  |     pub fn run(mut self) -> Compiled { | ||||||
|  |         while let Some(module) = self.module_queue.pop() { | ||||||
|  |             let compiling_module = self.modules[&module].clone(); | ||||||
|  |             let mut compiling_module = compiling_module.borrow_mut(); | ||||||
|  |             let CompilingModule { compiled_module } = &mut *compiling_module; | ||||||
|  |             assert!(compiled_module.is_none()); | ||||||
|  |             *compiled_module = Some(self.compile_module(module)); | ||||||
|  |         } | ||||||
|  |         Compiled { | ||||||
|  |             insns: Insns::from(self.insns).intern_sized(), | ||||||
|  |             modules: self | ||||||
|  |                 .modules | ||||||
|  |                 .into_iter() | ||||||
|  |                 .map(|(module, compiling_module)| { | ||||||
|  |                     ( | ||||||
|  |                         module, | ||||||
|  |                         Rc::into_inner(compiling_module) | ||||||
|  |                             .expect("only reference is Compiler::modules") | ||||||
|  |                             .into_inner() | ||||||
|  |                             .compiled_module | ||||||
|  |                             .expect("module is compiled by Compiler::run"), | ||||||
|  |                     ) | ||||||
|  |                 }) | ||||||
|  |                 .collect(), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[derive(Debug)] | ||||||
|  | struct CompiledModule { | ||||||
|  |     step_entry_pc: usize, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[derive(Debug)] | ||||||
|  | pub struct Compiled { | ||||||
|  |     insns: Interned<Insns>, | ||||||
|  |     modules: HashMap<Interned<Module<Bundle>>, CompiledModule>, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl Compiled { | ||||||
|  |     pub fn new<T: BundleType>(module: Module<T>) -> Self { | ||||||
|  |         let mut compiler = Compiler::new(); | ||||||
|  |         compiler.add_module(module.canonical().intern()); | ||||||
|  |         compiler.run() | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | pub struct Simulation { | ||||||
|  |     state: interpreter::State, | ||||||
|  | } | ||||||
							
								
								
									
										464
									
								
								crates/fayalite/src/sim/interpreter.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										464
									
								
								crates/fayalite/src/sim/interpreter.rs
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,464 @@ | ||||||
|  | use crate::{ | ||||||
|  |     intern::{Intern, Interned}, | ||||||
|  |     source_location::SourceLocation, | ||||||
|  | }; | ||||||
|  | use num_bigint::BigInt; | ||||||
|  | use std::{convert::Infallible, fmt, hash::Hash}; | ||||||
|  | 
 | ||||||
|  | pub(crate) type SmallUInt = u64; | ||||||
|  | pub(crate) type SmallSInt = i64; | ||||||
|  | 
 | ||||||
|  | macro_rules! impl_insns { | ||||||
|  |     ( | ||||||
|  |         #[next_macro = $next_macro:ident, branch_macro = $branch_macro:ident] | ||||||
|  |         $vis:vis fn $State:ident::$run:ident(&mut $self:ident, $insns:ident: &[$Insn:ident]) -> $run_ret_ty:ty { | ||||||
|  |             #[pc] | ||||||
|  |             let mut $pc:ident: usize = $pc_init:expr; | ||||||
|  |             setup! { | ||||||
|  |                 $($setup:tt)* | ||||||
|  |             } | ||||||
|  |             $(let mut $local:ident = $local_init:expr;)* | ||||||
|  |             main_loop!(); | ||||||
|  |             cleanup! { | ||||||
|  |                 $($cleanup:tt)* | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         $( | ||||||
|  |             $(#[$insn_meta:meta])* | ||||||
|  |             $insn_name:ident $({ | ||||||
|  |                 $( | ||||||
|  |                     $(#[$field_meta:meta])* | ||||||
|  |                     $field_name:ident: $field_ty:ty, | ||||||
|  |                 )* | ||||||
|  |             })? => $block:block | ||||||
|  |         )+ | ||||||
|  |     ) => { | ||||||
|  |         #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] | ||||||
|  |         $vis enum $Insn { | ||||||
|  |             $( | ||||||
|  |                 $(#[$insn_meta])* | ||||||
|  |                 $insn_name $({ | ||||||
|  |                     $( | ||||||
|  |                         $(#[$field_meta])* | ||||||
|  |                         $field_name: $field_ty, | ||||||
|  |                     )* | ||||||
|  |                 })?, | ||||||
|  |             )+ | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         impl $State { | ||||||
|  |             $vis fn $run(&mut $self, $insns: &[$Insn]) -> $run_ret_ty { | ||||||
|  |                 let mut $pc: usize = $pc_init; | ||||||
|  |                 $($setup)* | ||||||
|  |                 let mut insn = $insns[$pc]; | ||||||
|  |                 let retval = 'main_loop: loop { | ||||||
|  |                     macro_rules! $next_macro { | ||||||
|  |                         () => { | ||||||
|  |                             $pc += 1; | ||||||
|  |                             insn = $insns[$pc]; | ||||||
|  |                             continue 'main_loop; | ||||||
|  |                         }; | ||||||
|  |                     } | ||||||
|  |                     macro_rules! $branch_macro { | ||||||
|  |                         ($next_pc:expr) => { | ||||||
|  |                             $pc = $next_pc; | ||||||
|  |                             insn = $insns[$pc]; | ||||||
|  |                             continue 'main_loop; | ||||||
|  |                         }; | ||||||
|  |                     } | ||||||
|  |                     let _: Infallible = match insn { | ||||||
|  |                         $( | ||||||
|  |                             $Insn::$insn_name $({ | ||||||
|  |                                 $( | ||||||
|  |                                     $field_name, | ||||||
|  |                                 )* | ||||||
|  |                             })? => { | ||||||
|  |                                 $block | ||||||
|  |                             } | ||||||
|  |                         )+ | ||||||
|  |                     }; | ||||||
|  |                 }; | ||||||
|  |                 $($cleanup)* | ||||||
|  |                 retval | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     }; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | pub(crate) trait InsnsBuildingKind: Copy + Eq + fmt::Debug + Hash + Default { | ||||||
|  |     type BoxedSlice<T: fmt::Debug + Clone + Eq + Hash + Send + Sync + 'static>: fmt::Debug | ||||||
|  |         + Clone | ||||||
|  |         + Eq | ||||||
|  |         + std::ops::Deref<Target = [T]>; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Default)] | ||||||
|  | pub(crate) struct InsnsBuildingDone; | ||||||
|  | 
 | ||||||
|  | impl InsnsBuildingKind for InsnsBuildingDone { | ||||||
|  |     type BoxedSlice<T: fmt::Debug + Clone + Eq + Hash + Send + Sync + 'static> = Interned<[T]>; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Default)] | ||||||
|  | pub(crate) struct InsnsBuilding; | ||||||
|  | 
 | ||||||
|  | impl InsnsBuildingKind for InsnsBuilding { | ||||||
|  |     type BoxedSlice<T: fmt::Debug + Clone + Eq + Hash + Send + Sync + 'static> = Vec<T>; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[derive(Clone, PartialEq, Eq, Hash)] | ||||||
|  | pub(crate) struct Insns<BK: InsnsBuildingKind = InsnsBuildingDone> { | ||||||
|  |     insns: BK::BoxedSlice<Insn>, | ||||||
|  |     small_stack_size: usize, | ||||||
|  |     big_stack_size: usize, | ||||||
|  |     small_state_debug_names: BK::BoxedSlice<Interned<str>>, | ||||||
|  |     big_state_debug_names: BK::BoxedSlice<Interned<str>>, | ||||||
|  |     insn_source_locations: BK::BoxedSlice<SourceLocation>, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | struct InsnsDebug<'a> { | ||||||
|  |     insns: &'a [Insn], | ||||||
|  |     insn_source_locations: &'a [SourceLocation], | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<'a> fmt::Debug for InsnsDebug<'a> { | ||||||
|  |     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||||||
|  |         let mut debug_list = f.debug_list(); | ||||||
|  |         let mut last_source_location = None; | ||||||
|  |         for (insn, source_location) in self.insns.iter().zip(self.insn_source_locations) { | ||||||
|  |             if Some(source_location) != last_source_location { | ||||||
|  |                 debug_list.entry(&format_args!("// at: {source_location}\n{insn:?}")); | ||||||
|  |             } else { | ||||||
|  |                 debug_list.entry(insn); | ||||||
|  |             } | ||||||
|  |             last_source_location = Some(source_location); | ||||||
|  |         } | ||||||
|  |         debug_list.finish() | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<BK: InsnsBuildingKind> fmt::Debug for Insns<BK> { | ||||||
|  |     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||||||
|  |         let Self { | ||||||
|  |             insns, | ||||||
|  |             small_stack_size, | ||||||
|  |             big_stack_size, | ||||||
|  |             small_state_debug_names, | ||||||
|  |             big_state_debug_names, | ||||||
|  |             insn_source_locations, | ||||||
|  |         } = self; | ||||||
|  |         f.debug_struct("Insns") | ||||||
|  |             .field("small_stack_size", small_stack_size) | ||||||
|  |             .field("big_stack_size", big_stack_size) | ||||||
|  |             .field("small_state_debug_names", small_state_debug_names) | ||||||
|  |             .field("big_state_debug_names", big_state_debug_names) | ||||||
|  |             .field( | ||||||
|  |                 "insns", | ||||||
|  |                 &InsnsDebug { | ||||||
|  |                     insns, | ||||||
|  |                     insn_source_locations, | ||||||
|  |                 }, | ||||||
|  |             ) | ||||||
|  |             .finish_non_exhaustive() | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl Insns<InsnsBuilding> { | ||||||
|  |     pub(crate) fn new() -> Self { | ||||||
|  |         Self { | ||||||
|  |             insns: Vec::new(), | ||||||
|  |             small_stack_size: 0, | ||||||
|  |             big_stack_size: 0, | ||||||
|  |             small_state_debug_names: Vec::new(), | ||||||
|  |             big_state_debug_names: Vec::new(), | ||||||
|  |             insn_source_locations: Vec::new(), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     pub(crate) fn last_insn_pc(&self) -> usize { | ||||||
|  |         self.insns | ||||||
|  |             .len() | ||||||
|  |             .checked_sub(1) | ||||||
|  |             .expect("no last instruction") | ||||||
|  |     } | ||||||
|  |     pub(crate) fn next_insn_pc(&self) -> usize { | ||||||
|  |         self.insns.len() | ||||||
|  |     } | ||||||
|  |     pub(crate) fn push(&mut self, insn: Insn, source_location: SourceLocation) { | ||||||
|  |         self.insns.push(insn); | ||||||
|  |         self.insn_source_locations.push(source_location); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl From<Insns<InsnsBuilding>> for Insns { | ||||||
|  |     fn from(input: Insns<InsnsBuilding>) -> Self { | ||||||
|  |         let Insns { | ||||||
|  |             insns, | ||||||
|  |             small_stack_size, | ||||||
|  |             big_stack_size, | ||||||
|  |             small_state_debug_names, | ||||||
|  |             big_state_debug_names, | ||||||
|  |             insn_source_locations, | ||||||
|  |         } = input; | ||||||
|  |         Insns { | ||||||
|  |             insns: Intern::intern_owned(insns), | ||||||
|  |             small_stack_size, | ||||||
|  |             big_stack_size, | ||||||
|  |             small_state_debug_names: Intern::intern_owned(small_state_debug_names), | ||||||
|  |             big_state_debug_names: Intern::intern_owned(big_state_debug_names), | ||||||
|  |             insn_source_locations: Intern::intern_owned(insn_source_locations), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[derive(Debug)] | ||||||
|  | pub(crate) struct State { | ||||||
|  |     pub(crate) insns: Interned<Insns>, | ||||||
|  |     pub(crate) pc: usize, | ||||||
|  |     pub(crate) small_stack: Box<[SmallUInt]>, | ||||||
|  |     pub(crate) small_stack_top: usize, | ||||||
|  |     pub(crate) small_states: Box<[SmallUInt]>, | ||||||
|  |     pub(crate) big_stack: Box<[BigInt]>, | ||||||
|  |     pub(crate) big_stack_top: usize, | ||||||
|  |     pub(crate) big_states: Box<[BigInt]>, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl State { | ||||||
|  |     pub(crate) fn setup_call(&mut self, entry_pc: usize) { | ||||||
|  |         let Self { | ||||||
|  |             insns: _, | ||||||
|  |             pc, | ||||||
|  |             small_stack: _, | ||||||
|  |             small_stack_top, | ||||||
|  |             small_states: _, | ||||||
|  |             big_stack: _, | ||||||
|  |             big_stack_top, | ||||||
|  |             big_states: _, | ||||||
|  |         } = self; | ||||||
|  |         *pc = entry_pc; | ||||||
|  |         *small_stack_top = 0; | ||||||
|  |         *big_stack_top = 0; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl_insns! { | ||||||
|  |     #[next_macro = next, branch_macro = branch] | ||||||
|  |     pub(crate) fn State::run(&mut self, insns: &[Insn]) -> () { | ||||||
|  |         #[pc] | ||||||
|  |         let mut pc: usize = self.pc; | ||||||
|  |         setup! { | ||||||
|  |             let small_states = &mut *self.small_states; | ||||||
|  |             let small_stack = &mut *self.small_stack; | ||||||
|  |             let mut small_stack_top = self.small_stack_top; | ||||||
|  |             macro_rules! small_stack_push { | ||||||
|  |                 ($v:expr) => { | ||||||
|  |                     { | ||||||
|  |                         small_stack[small_stack_top] = $v; | ||||||
|  |                         small_stack_top += 1; | ||||||
|  |                     } | ||||||
|  |                 }; | ||||||
|  |             } | ||||||
|  |             macro_rules! small_stack_pop { | ||||||
|  |                 () => { | ||||||
|  |                     { | ||||||
|  |                         small_stack_top -= 1; | ||||||
|  |                         small_stack[small_stack_top] | ||||||
|  |                     } | ||||||
|  |                 }; | ||||||
|  |             } | ||||||
|  |             let big_states = &mut *self.big_states; | ||||||
|  |             let big_stack = &mut *self.big_stack; | ||||||
|  |             let mut big_stack_top = self.big_stack_top; | ||||||
|  |             macro_rules! big_stack_push { | ||||||
|  |                 ($v:expr) => { | ||||||
|  |                     { | ||||||
|  |                         big_stack[big_stack_top] = $v; | ||||||
|  |                         big_stack_top += 1; | ||||||
|  |                     } | ||||||
|  |                 }; | ||||||
|  |             } | ||||||
|  |             macro_rules! big_stack_pop { | ||||||
|  |                 () => { | ||||||
|  |                     { | ||||||
|  |                         big_stack_top -= 1; | ||||||
|  |                         big_stack[big_stack_top] | ||||||
|  |                     } | ||||||
|  |                 }; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         main_loop!(); | ||||||
|  |         cleanup! { | ||||||
|  |             self.pc = pc; | ||||||
|  |             self.small_stack_top = small_stack_top; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     ReadSmall { | ||||||
|  |         index: u32, | ||||||
|  |     } => { | ||||||
|  |         small_stack_push!(small_states[index as usize]); | ||||||
|  |         next!(); | ||||||
|  |     } | ||||||
|  |     SExtSmall { | ||||||
|  |         /// number of bits in a [`SmallSInt`] that aren't used
 | ||||||
|  |         unused_bit_count: u8, | ||||||
|  |     } => { | ||||||
|  |         let mut value = small_stack_pop!() as SmallSInt; | ||||||
|  |         value <<= unused_bit_count; | ||||||
|  |         value >>= unused_bit_count; | ||||||
|  |         small_stack_push!(value as SmallUInt); | ||||||
|  |         next!(); | ||||||
|  |     } | ||||||
|  |     ZExtSmall { | ||||||
|  |         /// number of bits in a [`SmallUInt`] that aren't used
 | ||||||
|  |         unused_bit_count: u8, | ||||||
|  |     } => { | ||||||
|  |         let mut value = small_stack_pop!(); | ||||||
|  |         value <<= unused_bit_count; | ||||||
|  |         value >>= unused_bit_count; | ||||||
|  |         small_stack_push!(value); | ||||||
|  |         next!(); | ||||||
|  |     } | ||||||
|  |     AndSmall => { | ||||||
|  |         let rhs = small_stack_pop!(); | ||||||
|  |         let lhs = small_stack_pop!(); | ||||||
|  |         let value = lhs & rhs; | ||||||
|  |         small_stack_push!(value); | ||||||
|  |         next!(); | ||||||
|  |     } | ||||||
|  |     OrSmall => { | ||||||
|  |         let rhs = small_stack_pop!(); | ||||||
|  |         let lhs = small_stack_pop!(); | ||||||
|  |         let value = lhs | rhs; | ||||||
|  |         small_stack_push!(value); | ||||||
|  |         next!(); | ||||||
|  |     } | ||||||
|  |     XorSmall => { | ||||||
|  |         let rhs = small_stack_pop!(); | ||||||
|  |         let lhs = small_stack_pop!(); | ||||||
|  |         let value = lhs ^ rhs; | ||||||
|  |         small_stack_push!(value); | ||||||
|  |         next!(); | ||||||
|  |     } | ||||||
|  |     NotSmall => { | ||||||
|  |         let value = small_stack_pop!(); | ||||||
|  |         small_stack_push!(!value); | ||||||
|  |         next!(); | ||||||
|  |     } | ||||||
|  |     CmpEqSmall => { | ||||||
|  |         let rhs = small_stack_pop!(); | ||||||
|  |         let lhs = small_stack_pop!(); | ||||||
|  |         let value = (lhs == rhs) as SmallUInt; | ||||||
|  |         small_stack_push!(value); | ||||||
|  |         next!(); | ||||||
|  |     } | ||||||
|  |     CmpNeSmall => { | ||||||
|  |         let rhs = small_stack_pop!(); | ||||||
|  |         let lhs = small_stack_pop!(); | ||||||
|  |         let value = (lhs != rhs) as SmallUInt; | ||||||
|  |         small_stack_push!(value); | ||||||
|  |         next!(); | ||||||
|  |     } | ||||||
|  |     CmpLTSmallUInt => { | ||||||
|  |         let rhs = small_stack_pop!(); | ||||||
|  |         let lhs = small_stack_pop!(); | ||||||
|  |         let value = (lhs < rhs) as SmallUInt; | ||||||
|  |         small_stack_push!(value); | ||||||
|  |         next!(); | ||||||
|  |     } | ||||||
|  |     CmpLESmallUInt => { | ||||||
|  |         let rhs = small_stack_pop!(); | ||||||
|  |         let lhs = small_stack_pop!(); | ||||||
|  |         let value = (lhs <= rhs) as SmallUInt; | ||||||
|  |         small_stack_push!(value); | ||||||
|  |         next!(); | ||||||
|  |     } | ||||||
|  |     CmpGTSmallUInt => { | ||||||
|  |         let rhs = small_stack_pop!(); | ||||||
|  |         let lhs = small_stack_pop!(); | ||||||
|  |         let value = (lhs > rhs) as SmallUInt; | ||||||
|  |         small_stack_push!(value); | ||||||
|  |         next!(); | ||||||
|  |     } | ||||||
|  |     CmpGESmallUInt => { | ||||||
|  |         let rhs = small_stack_pop!(); | ||||||
|  |         let lhs = small_stack_pop!(); | ||||||
|  |         let value = (lhs >= rhs) as SmallUInt; | ||||||
|  |         small_stack_push!(value); | ||||||
|  |         next!(); | ||||||
|  |     } | ||||||
|  |     CmpLTSmallSInt => { | ||||||
|  |         let rhs = small_stack_pop!() as SmallSInt; | ||||||
|  |         let lhs = small_stack_pop!() as SmallSInt; | ||||||
|  |         let value = (lhs < rhs) as SmallUInt; | ||||||
|  |         small_stack_push!(value); | ||||||
|  |         next!(); | ||||||
|  |     } | ||||||
|  |     CmpLESmallSInt => { | ||||||
|  |         let rhs = small_stack_pop!() as SmallSInt; | ||||||
|  |         let lhs = small_stack_pop!() as SmallSInt; | ||||||
|  |         let value = (lhs <= rhs) as SmallUInt; | ||||||
|  |         small_stack_push!(value); | ||||||
|  |         next!(); | ||||||
|  |     } | ||||||
|  |     CmpGTSmallSInt => { | ||||||
|  |         let rhs = small_stack_pop!() as SmallSInt; | ||||||
|  |         let lhs = small_stack_pop!() as SmallSInt; | ||||||
|  |         let value = (lhs > rhs) as SmallUInt; | ||||||
|  |         small_stack_push!(value); | ||||||
|  |         next!(); | ||||||
|  |     } | ||||||
|  |     CmpGESmallSInt => { | ||||||
|  |         let rhs = small_stack_pop!() as SmallSInt; | ||||||
|  |         let lhs = small_stack_pop!() as SmallSInt; | ||||||
|  |         let value = (lhs >= rhs) as SmallUInt; | ||||||
|  |         small_stack_push!(value); | ||||||
|  |         next!(); | ||||||
|  |     } | ||||||
|  |     AddSmall => { | ||||||
|  |         let rhs = small_stack_pop!(); | ||||||
|  |         let lhs = small_stack_pop!(); | ||||||
|  |         let value = lhs.wrapping_add(rhs); | ||||||
|  |         small_stack_push!(value); | ||||||
|  |         next!(); | ||||||
|  |     } | ||||||
|  |     SubSmall => { | ||||||
|  |         let rhs = small_stack_pop!(); | ||||||
|  |         let lhs = small_stack_pop!(); | ||||||
|  |         let value = lhs.wrapping_sub(rhs); | ||||||
|  |         small_stack_push!(value); | ||||||
|  |         next!(); | ||||||
|  |     } | ||||||
|  |     NegSmall => { | ||||||
|  |         let value = small_stack_pop!(); | ||||||
|  |         let value = value.wrapping_neg(); | ||||||
|  |         small_stack_push!(value); | ||||||
|  |         next!(); | ||||||
|  |     } | ||||||
|  |     MulSmall => { | ||||||
|  |         let rhs = small_stack_pop!(); | ||||||
|  |         let lhs = small_stack_pop!(); | ||||||
|  |         let value = lhs.wrapping_mul(rhs); | ||||||
|  |         small_stack_push!(value); | ||||||
|  |         next!(); | ||||||
|  |     } | ||||||
|  |     ConstU32Small { | ||||||
|  |         value: u32, | ||||||
|  |     } => { | ||||||
|  |         small_stack_push!(value as SmallUInt); | ||||||
|  |         next!(); | ||||||
|  |     } | ||||||
|  |     ConstS32Small { | ||||||
|  |         value: i32, | ||||||
|  |     } => { | ||||||
|  |         small_stack_push!(value as SmallUInt); | ||||||
|  |         next!(); | ||||||
|  |     } | ||||||
|  |     WriteSmall { | ||||||
|  |         index: u32, | ||||||
|  |     } => { | ||||||
|  |         small_states[index as usize] = small_stack_pop!(); | ||||||
|  |         next!(); | ||||||
|  |     } | ||||||
|  |     Return => { | ||||||
|  |         break; | ||||||
|  |     } | ||||||
|  | } | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue