Mercurial > touhou
changeset 696:7ae576a418ff
ecl_vm: implement Call, Return, and the call stack thingy.
author | Emmanuel Gil Peyrot <linkmauve@linkmauve.fr> |
---|---|
date | Fri, 23 Aug 2019 02:31:08 +0200 |
parents | f5b34a1c2707 |
children | 600eb0a69b25 |
files | examples/eclrenderer.rs src/th06/ecl.rs src/th06/ecl_vm.rs |
diffstat | 3 files changed, 103 insertions(+), 81 deletions(-) [+] |
line wrap: on
line diff
--- a/examples/eclrenderer.rs +++ b/examples/eclrenderer.rs @@ -99,7 +99,7 @@ fn main() { let anm_filename = &args[2]; let png_filename = &args[3]; let rank: Rank = args[4].parse().expect("rank"); - let sub: u8 = args[5].parse().expect("number"); + let sub: u16 = args[5].parse().expect("number"); // Open the ECL file. let file = File::open(ecl_filename).unwrap();
--- a/src/th06/ecl.rs +++ b/src/th06/ecl.rs @@ -58,6 +58,18 @@ pub struct CallSub { pub instr: SubInstruction, } +impl CallSub { + /// Create a new instruction call. + pub fn new(time: i32, rank_mask: Rank, instr: SubInstruction) -> CallSub { + CallSub { + time, + rank_mask, + param_mask: 0, + instr, + } + } +} + /// Script driving an animation. #[derive(Debug, Clone)] pub struct Sub {
--- a/src/th06/ecl_vm.rs +++ b/src/th06/ecl_vm.rs @@ -24,43 +24,50 @@ macro_rules! gen_SetBulletAttributes { }}; } -type Variables = ([i32; 4], [f32; 4], [i32; 4]); +#[derive(Clone, Default)] +struct StackFrame { + frame: i32, + ip: i32, + //ins122_callback: Option<Box<FnMut(Enemy)>>, + ints1: [i32; 4], + floats: [f32; 4], + ints2: [i32; 4], + comparison_reg: i32, + sub: u16, +} /// Interpreter for enemy scripts. #[derive(Default)] pub struct EclRunner { enemy: Rc<RefCell<Enemy>>, ecl: Option<Ecl>, - sub: u8, /// XXX pub running: bool, - /// XXX - pub frame: i32, - ip: i32, - variables: Variables, - comparison_reg: i8, - stack: Vec<Variables>, + frame: StackFrame, + // TODO: there are only 8 of these. + stack: Vec<StackFrame>, } impl EclRunner { /// Create a new ECL runner. - pub fn new(ecl: &Ecl, enemy: Rc<RefCell<Enemy>>, sub: u8) -> EclRunner { - EclRunner { + pub fn new(ecl: &Ecl, enemy: Rc<RefCell<Enemy>>, sub: u16) -> EclRunner { + let mut ecl_runner = EclRunner { enemy, // XXX: no clone. ecl: Some(ecl.clone()), - sub, running: true, ..Default::default() - } + }; + ecl_runner.frame.sub = sub; + ecl_runner } /// Advance the ECL of a single frame. pub fn run_frame(&mut self) { while self.running { let ecl = self.ecl.clone().unwrap(); - let sub = &ecl.subs[self.sub as usize]; - let call = match sub.instructions.get(self.ip as usize) { + let sub = &ecl.subs[self.frame.sub as usize]; + let call = match sub.instructions.get(self.frame.ip as usize) { Some(call) => call, None => { self.running = false; @@ -68,38 +75,38 @@ impl EclRunner { } }; - if call.time > self.frame { + if call.time > self.frame.frame { break; } - self.ip += 1; + self.frame.ip += 1; let rank = self.enemy.borrow().get_rank(); if (call.rank_mask & rank).is_empty() { continue; } - if call.time == self.frame { + if call.time == self.frame.frame { self.run_instruction(call.instr.clone()); } } - self.frame += 1; + self.frame.frame += 1; } fn get_i32(&self, var: i32) -> i32 { let enemy = self.enemy.borrow(); match var { - -10001 => self.variables.0[0], - -10002 => self.variables.0[1], - -10003 => self.variables.0[2], - -10004 => self.variables.0[3], - -10005 => self.variables.1[0] as i32, - -10006 => self.variables.1[1] as i32, - -10007 => self.variables.1[2] as i32, - -10008 => self.variables.1[3] as i32, - -10009 => self.variables.2[0], - -10010 => self.variables.2[1], - -10011 => self.variables.2[2], - -10012 => self.variables.2[3], + -10001 => self.frame.ints1[0], + -10002 => self.frame.ints1[1], + -10003 => self.frame.ints1[2], + -10004 => self.frame.ints1[3], + -10005 => self.frame.floats[0] as i32, + -10006 => self.frame.floats[1] as i32, + -10007 => self.frame.floats[2] as i32, + -10008 => self.frame.floats[3] as i32, + -10009 => self.frame.ints2[0], + -10010 => self.frame.ints2[1], + -10011 => self.frame.ints2[2], + -10012 => self.frame.ints2[3], -10013 => enemy.get_rank().bits() as i32, -10014 => enemy.get_difficulty(), -10015 => enemy.pos.x as i32, @@ -120,18 +127,18 @@ impl EclRunner { fn get_f32(&self, var: f32) -> f32 { let enemy = self.enemy.borrow(); match var { - -10001.0 => self.variables.0[0] as f32, - -10002.0 => self.variables.0[1] as f32, - -10003.0 => self.variables.0[2] as f32, - -10004.0 => self.variables.0[3] as f32, - -10005.0 => self.variables.1[0], - -10006.0 => self.variables.1[1], - -10007.0 => self.variables.1[2], - -10008.0 => self.variables.1[3], - -10009.0 => self.variables.2[0] as f32, - -10010.0 => self.variables.2[1] as f32, - -10011.0 => self.variables.2[2] as f32, - -10012.0 => self.variables.2[3] as f32, + -10001.0 => self.frame.ints1[0] as f32, + -10002.0 => self.frame.ints1[1] as f32, + -10003.0 => self.frame.ints1[2] as f32, + -10004.0 => self.frame.ints1[3] as f32, + -10005.0 => self.frame.floats[0], + -10006.0 => self.frame.floats[1], + -10007.0 => self.frame.floats[2], + -10008.0 => self.frame.floats[3], + -10009.0 => self.frame.ints2[0] as f32, + -10010.0 => self.frame.ints2[1] as f32, + -10011.0 => self.frame.ints2[2] as f32, + -10012.0 => self.frame.ints2[3] as f32, -10013.0 => enemy.get_rank().bits() as f32, -10014.0 => enemy.get_difficulty() as f32, -10015.0 => enemy.pos.x, @@ -152,18 +159,18 @@ impl EclRunner { fn set_i32(&mut self, var: i32, value: i32) { let mut enemy = self.enemy.borrow_mut(); match var { - -10001 => self.variables.0[0] = value, - -10002 => self.variables.0[1] = value, - -10003 => self.variables.0[2] = value, - -10004 => self.variables.0[3] = value, + -10001 => self.frame.ints1[0] = value, + -10002 => self.frame.ints1[1] = value, + -10003 => self.frame.ints1[2] = value, + -10004 => self.frame.ints1[3] = value, -10005 => unimplemented!(), -10006 => unimplemented!(), -10007 => unimplemented!(), -10008 => unimplemented!(), - -10009 => self.variables.2[0] = value, - -10010 => self.variables.2[1] = value, - -10011 => self.variables.2[2] = value, - -10012 => self.variables.2[3] = value, + -10009 => self.frame.ints2[0] = value, + -10010 => self.frame.ints2[1] = value, + -10011 => self.frame.ints2[2] = value, + -10012 => self.frame.ints2[3] = value, -10013 => unreachable!(), -10014 => unreachable!(), -10015 => unimplemented!(), @@ -188,10 +195,10 @@ impl EclRunner { -10002.0 => unimplemented!(), -10003.0 => unimplemented!(), -10004.0 => unimplemented!(), - -10005.0 => self.variables.1[0] = value, - -10006.0 => self.variables.1[1] = value, - -10007.0 => self.variables.1[2] = value, - -10008.0 => self.variables.1[3] = value, + -10005.0 => self.frame.floats[0] = value, + -10006.0 => self.frame.floats[1] = value, + -10007.0 => self.frame.floats[2] = value, + -10008.0 => self.frame.floats[3] = value, -10009.0 => unimplemented!(), -10010.0 => unimplemented!(), -10011.0 => unimplemented!(), @@ -231,9 +238,9 @@ impl EclRunner { } // 2 SubInstruction::RelativeJump(frame, ip) => { - self.frame = frame; + self.frame.frame = frame; // ip = ip + flag in th06 - self.ip = ip; + self.frame.ip = ip; // we jump back to the main of the interpreter } // 3 @@ -375,110 +382,113 @@ impl EclRunner { let a = self.get_i32(a); let b = self.get_i32(b); if a < b { - self.comparison_reg = -1; + self.frame.comparison_reg = -1; } else if a == b { - self.comparison_reg = 0; + self.frame.comparison_reg = 0; } else { - self.comparison_reg = 1; + self.frame.comparison_reg = 1; } } SubInstruction::CompareFloats(a, b) => { let a = self.get_f32(a); let b = self.get_f32(b); if a < b { - self.comparison_reg = -1; + self.frame.comparison_reg = -1; } else if a == b { - self.comparison_reg = 0; + self.frame.comparison_reg = 0; } else { - self.comparison_reg = 1; + self.frame.comparison_reg = 1; } } // 29 SubInstruction::RelativeJumpIfLowerThan(frame, ip) => { - if self.comparison_reg == -1 { + if self.frame.comparison_reg == -1 { SubInstruction::RelativeJump(frame, ip); } } // 30 SubInstruction::RelativeJumpIfLowerOrEqual(frame, ip) => { - if self.comparison_reg != 1 { + if self.frame.comparison_reg != 1 { SubInstruction::RelativeJump(frame, ip); } } // 31 SubInstruction::RelativeJumpIfEqual(frame, ip) => { - if self.comparison_reg == 0 { + if self.frame.comparison_reg == 0 { SubInstruction::RelativeJump(frame, ip); } } // 32 SubInstruction::RelativeJumpIfGreaterThan(frame, ip) => { - if self.comparison_reg == 1 { + if self.frame.comparison_reg == 1 { SubInstruction::RelativeJump(frame, ip); } } // 33 SubInstruction::RelativeJumpIfGreaterOrEqual(frame, ip) => { - if self.comparison_reg != -1 { + if self.frame.comparison_reg != -1 { SubInstruction::RelativeJump(frame, ip); } } // 34 SubInstruction::RelativeJumpIfNotEqual(frame, ip) => { - if self.comparison_reg != 0 { + if self.frame.comparison_reg != 0 { SubInstruction::RelativeJump(frame, ip); } } // 35 SubInstruction::Call(sub, param1, param2) => { - // does insane stuff with the stack, not implemented - unimplemented!() + self.stack.push(self.frame.clone()); + self.frame.sub = sub as u16; + self.frame.ints1[0] = param1; + self.frame.floats[0] = param2; + self.frame.frame = 0; + self.frame.ip = 0; } // 36 SubInstruction::Return() => { - // does insane stuff with the stack, not implemented - unimplemented!() + self.frame = self.stack.pop().unwrap(); } // 37 SubInstruction::CallIfSuperior(sub, param1, param2, a, b) => { if self.get_i32(a) < self.get_i32(b) { - SubInstruction::Call(sub, param1, param2); + self.run_instruction(SubInstruction::Call(sub, param1, param2)); } } // 38 SubInstruction::CallIfSuperiorOrEqual(sub, param1, param2, a, b) => { if self.get_i32(a) <= self.get_i32(b) { - SubInstruction::Call(sub, param1, param2); + self.run_instruction(SubInstruction::Call(sub, param1, param2)); } } // 39 SubInstruction::CallIfEqual(sub, param1, param2, a, b) => { if self.get_i32(a) == self.get_i32(b) { - SubInstruction::Call(sub, param1, param2); + self.run_instruction(SubInstruction::Call(sub, param1, param2)); } } // 40 SubInstruction::CallIfInferior(sub, param1, param2, a, b) => { if self.get_i32(b) < self.get_i32(a) { - SubInstruction::Call(sub, param1, param2); + self.run_instruction(SubInstruction::Call(sub, param1, param2)); } } // 41 SubInstruction::CallIfInferiorOrEqual(sub, param1, param2, a, b) => { if self.get_i32(b) <= self.get_i32(a) { - SubInstruction::Call(sub, param1, param2); + self.run_instruction(SubInstruction::Call(sub, param1, param2)); } } //42 SubInstruction::CallIfNotEqual(sub, param1, param2, a, b) => { if self.get_i32(a) != self.get_i32(b) { - SubInstruction::Call(sub, param1, param2); + self.run_instruction(SubInstruction::Call(sub, param1, param2)); } } @@ -729,10 +739,10 @@ impl EclRunner { // 1/100000 chance to continue, otherwise crash if enemy.laser_by_id.contains_key(&laser_id) { // let's assume we gud - self.comparison_reg = 1; + self.frame.comparison_reg = 1; } else{ - self.comparison_reg = 0; + self.frame.comparison_reg = 0; } }