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 reg; | ||||
| pub mod reset; | ||||
| pub mod sim; | ||||
| pub mod source_location; | ||||
| pub mod testing; | ||||
| 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