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;
                 }
             }