WIP adding simulator
This commit is contained in:
parent
3d5d8c54b6
commit
56ff69ba52
|
@ -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…
Reference in a new issue