Mercurial > touhou
comparison src/th06/ecl_vm.rs @ 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 |
comparison
equal
deleted
inserted
replaced
695:f5b34a1c2707 | 696:7ae576a418ff |
---|---|
22 enemy.set_bullet_attributes($opcode, $anim, sprite_index_offset, bullets_per_shot, | 22 enemy.set_bullet_attributes($opcode, $anim, sprite_index_offset, bullets_per_shot, |
23 number_of_shots, speed, speed2, launch_angle, angle, $flags); | 23 number_of_shots, speed, speed2, launch_angle, angle, $flags); |
24 }}; | 24 }}; |
25 } | 25 } |
26 | 26 |
27 type Variables = ([i32; 4], [f32; 4], [i32; 4]); | 27 #[derive(Clone, Default)] |
28 struct StackFrame { | |
29 frame: i32, | |
30 ip: i32, | |
31 //ins122_callback: Option<Box<FnMut(Enemy)>>, | |
32 ints1: [i32; 4], | |
33 floats: [f32; 4], | |
34 ints2: [i32; 4], | |
35 comparison_reg: i32, | |
36 sub: u16, | |
37 } | |
28 | 38 |
29 /// Interpreter for enemy scripts. | 39 /// Interpreter for enemy scripts. |
30 #[derive(Default)] | 40 #[derive(Default)] |
31 pub struct EclRunner { | 41 pub struct EclRunner { |
32 enemy: Rc<RefCell<Enemy>>, | 42 enemy: Rc<RefCell<Enemy>>, |
33 ecl: Option<Ecl>, | 43 ecl: Option<Ecl>, |
34 sub: u8, | |
35 /// XXX | 44 /// XXX |
36 pub running: bool, | 45 pub running: bool, |
37 /// XXX | 46 frame: StackFrame, |
38 pub frame: i32, | 47 // TODO: there are only 8 of these. |
39 ip: i32, | 48 stack: Vec<StackFrame>, |
40 variables: Variables, | |
41 comparison_reg: i8, | |
42 stack: Vec<Variables>, | |
43 } | 49 } |
44 | 50 |
45 impl EclRunner { | 51 impl EclRunner { |
46 /// Create a new ECL runner. | 52 /// Create a new ECL runner. |
47 pub fn new(ecl: &Ecl, enemy: Rc<RefCell<Enemy>>, sub: u8) -> EclRunner { | 53 pub fn new(ecl: &Ecl, enemy: Rc<RefCell<Enemy>>, sub: u16) -> EclRunner { |
48 EclRunner { | 54 let mut ecl_runner = EclRunner { |
49 enemy, | 55 enemy, |
50 // XXX: no clone. | 56 // XXX: no clone. |
51 ecl: Some(ecl.clone()), | 57 ecl: Some(ecl.clone()), |
52 sub, | |
53 running: true, | 58 running: true, |
54 ..Default::default() | 59 ..Default::default() |
55 } | 60 }; |
61 ecl_runner.frame.sub = sub; | |
62 ecl_runner | |
56 } | 63 } |
57 | 64 |
58 /// Advance the ECL of a single frame. | 65 /// Advance the ECL of a single frame. |
59 pub fn run_frame(&mut self) { | 66 pub fn run_frame(&mut self) { |
60 while self.running { | 67 while self.running { |
61 let ecl = self.ecl.clone().unwrap(); | 68 let ecl = self.ecl.clone().unwrap(); |
62 let sub = &ecl.subs[self.sub as usize]; | 69 let sub = &ecl.subs[self.frame.sub as usize]; |
63 let call = match sub.instructions.get(self.ip as usize) { | 70 let call = match sub.instructions.get(self.frame.ip as usize) { |
64 Some(call) => call, | 71 Some(call) => call, |
65 None => { | 72 None => { |
66 self.running = false; | 73 self.running = false; |
67 break; | 74 break; |
68 } | 75 } |
69 }; | 76 }; |
70 | 77 |
71 if call.time > self.frame { | 78 if call.time > self.frame.frame { |
72 break; | 79 break; |
73 } | 80 } |
74 self.ip += 1; | 81 self.frame.ip += 1; |
75 | 82 |
76 let rank = self.enemy.borrow().get_rank(); | 83 let rank = self.enemy.borrow().get_rank(); |
77 if (call.rank_mask & rank).is_empty() { | 84 if (call.rank_mask & rank).is_empty() { |
78 continue; | 85 continue; |
79 } | 86 } |
80 | 87 |
81 if call.time == self.frame { | 88 if call.time == self.frame.frame { |
82 self.run_instruction(call.instr.clone()); | 89 self.run_instruction(call.instr.clone()); |
83 } | 90 } |
84 } | 91 } |
85 self.frame += 1; | 92 self.frame.frame += 1; |
86 } | 93 } |
87 | 94 |
88 fn get_i32(&self, var: i32) -> i32 { | 95 fn get_i32(&self, var: i32) -> i32 { |
89 let enemy = self.enemy.borrow(); | 96 let enemy = self.enemy.borrow(); |
90 match var { | 97 match var { |
91 -10001 => self.variables.0[0], | 98 -10001 => self.frame.ints1[0], |
92 -10002 => self.variables.0[1], | 99 -10002 => self.frame.ints1[1], |
93 -10003 => self.variables.0[2], | 100 -10003 => self.frame.ints1[2], |
94 -10004 => self.variables.0[3], | 101 -10004 => self.frame.ints1[3], |
95 -10005 => self.variables.1[0] as i32, | 102 -10005 => self.frame.floats[0] as i32, |
96 -10006 => self.variables.1[1] as i32, | 103 -10006 => self.frame.floats[1] as i32, |
97 -10007 => self.variables.1[2] as i32, | 104 -10007 => self.frame.floats[2] as i32, |
98 -10008 => self.variables.1[3] as i32, | 105 -10008 => self.frame.floats[3] as i32, |
99 -10009 => self.variables.2[0], | 106 -10009 => self.frame.ints2[0], |
100 -10010 => self.variables.2[1], | 107 -10010 => self.frame.ints2[1], |
101 -10011 => self.variables.2[2], | 108 -10011 => self.frame.ints2[2], |
102 -10012 => self.variables.2[3], | 109 -10012 => self.frame.ints2[3], |
103 -10013 => enemy.get_rank().bits() as i32, | 110 -10013 => enemy.get_rank().bits() as i32, |
104 -10014 => enemy.get_difficulty(), | 111 -10014 => enemy.get_difficulty(), |
105 -10015 => enemy.pos.x as i32, | 112 -10015 => enemy.pos.x as i32, |
106 -10016 => enemy.pos.y as i32, | 113 -10016 => enemy.pos.y as i32, |
107 -10017 => enemy.z as i32, | 114 -10017 => enemy.z as i32, |
118 } | 125 } |
119 | 126 |
120 fn get_f32(&self, var: f32) -> f32 { | 127 fn get_f32(&self, var: f32) -> f32 { |
121 let enemy = self.enemy.borrow(); | 128 let enemy = self.enemy.borrow(); |
122 match var { | 129 match var { |
123 -10001.0 => self.variables.0[0] as f32, | 130 -10001.0 => self.frame.ints1[0] as f32, |
124 -10002.0 => self.variables.0[1] as f32, | 131 -10002.0 => self.frame.ints1[1] as f32, |
125 -10003.0 => self.variables.0[2] as f32, | 132 -10003.0 => self.frame.ints1[2] as f32, |
126 -10004.0 => self.variables.0[3] as f32, | 133 -10004.0 => self.frame.ints1[3] as f32, |
127 -10005.0 => self.variables.1[0], | 134 -10005.0 => self.frame.floats[0], |
128 -10006.0 => self.variables.1[1], | 135 -10006.0 => self.frame.floats[1], |
129 -10007.0 => self.variables.1[2], | 136 -10007.0 => self.frame.floats[2], |
130 -10008.0 => self.variables.1[3], | 137 -10008.0 => self.frame.floats[3], |
131 -10009.0 => self.variables.2[0] as f32, | 138 -10009.0 => self.frame.ints2[0] as f32, |
132 -10010.0 => self.variables.2[1] as f32, | 139 -10010.0 => self.frame.ints2[1] as f32, |
133 -10011.0 => self.variables.2[2] as f32, | 140 -10011.0 => self.frame.ints2[2] as f32, |
134 -10012.0 => self.variables.2[3] as f32, | 141 -10012.0 => self.frame.ints2[3] as f32, |
135 -10013.0 => enemy.get_rank().bits() as f32, | 142 -10013.0 => enemy.get_rank().bits() as f32, |
136 -10014.0 => enemy.get_difficulty() as f32, | 143 -10014.0 => enemy.get_difficulty() as f32, |
137 -10015.0 => enemy.pos.x, | 144 -10015.0 => enemy.pos.x, |
138 -10016.0 => enemy.pos.y, | 145 -10016.0 => enemy.pos.y, |
139 -10017.0 => enemy.z, | 146 -10017.0 => enemy.z, |
150 } | 157 } |
151 | 158 |
152 fn set_i32(&mut self, var: i32, value: i32) { | 159 fn set_i32(&mut self, var: i32, value: i32) { |
153 let mut enemy = self.enemy.borrow_mut(); | 160 let mut enemy = self.enemy.borrow_mut(); |
154 match var { | 161 match var { |
155 -10001 => self.variables.0[0] = value, | 162 -10001 => self.frame.ints1[0] = value, |
156 -10002 => self.variables.0[1] = value, | 163 -10002 => self.frame.ints1[1] = value, |
157 -10003 => self.variables.0[2] = value, | 164 -10003 => self.frame.ints1[2] = value, |
158 -10004 => self.variables.0[3] = value, | 165 -10004 => self.frame.ints1[3] = value, |
159 -10005 => unimplemented!(), | 166 -10005 => unimplemented!(), |
160 -10006 => unimplemented!(), | 167 -10006 => unimplemented!(), |
161 -10007 => unimplemented!(), | 168 -10007 => unimplemented!(), |
162 -10008 => unimplemented!(), | 169 -10008 => unimplemented!(), |
163 -10009 => self.variables.2[0] = value, | 170 -10009 => self.frame.ints2[0] = value, |
164 -10010 => self.variables.2[1] = value, | 171 -10010 => self.frame.ints2[1] = value, |
165 -10011 => self.variables.2[2] = value, | 172 -10011 => self.frame.ints2[2] = value, |
166 -10012 => self.variables.2[3] = value, | 173 -10012 => self.frame.ints2[3] = value, |
167 -10013 => unreachable!(), | 174 -10013 => unreachable!(), |
168 -10014 => unreachable!(), | 175 -10014 => unreachable!(), |
169 -10015 => unimplemented!(), | 176 -10015 => unimplemented!(), |
170 -10016 => unimplemented!(), | 177 -10016 => unimplemented!(), |
171 -10017 => unimplemented!(), | 178 -10017 => unimplemented!(), |
186 match var { | 193 match var { |
187 -10001.0 => unimplemented!(), | 194 -10001.0 => unimplemented!(), |
188 -10002.0 => unimplemented!(), | 195 -10002.0 => unimplemented!(), |
189 -10003.0 => unimplemented!(), | 196 -10003.0 => unimplemented!(), |
190 -10004.0 => unimplemented!(), | 197 -10004.0 => unimplemented!(), |
191 -10005.0 => self.variables.1[0] = value, | 198 -10005.0 => self.frame.floats[0] = value, |
192 -10006.0 => self.variables.1[1] = value, | 199 -10006.0 => self.frame.floats[1] = value, |
193 -10007.0 => self.variables.1[2] = value, | 200 -10007.0 => self.frame.floats[2] = value, |
194 -10008.0 => self.variables.1[3] = value, | 201 -10008.0 => self.frame.floats[3] = value, |
195 -10009.0 => unimplemented!(), | 202 -10009.0 => unimplemented!(), |
196 -10010.0 => unimplemented!(), | 203 -10010.0 => unimplemented!(), |
197 -10011.0 => unimplemented!(), | 204 -10011.0 => unimplemented!(), |
198 -10012.0 => unimplemented!(), | 205 -10012.0 => unimplemented!(), |
199 -10013.0 => unreachable!(), | 206 -10013.0 => unreachable!(), |
229 let mut enemy = self.enemy.borrow_mut(); | 236 let mut enemy = self.enemy.borrow_mut(); |
230 enemy.removed = true; | 237 enemy.removed = true; |
231 } | 238 } |
232 // 2 | 239 // 2 |
233 SubInstruction::RelativeJump(frame, ip) => { | 240 SubInstruction::RelativeJump(frame, ip) => { |
234 self.frame = frame; | 241 self.frame.frame = frame; |
235 // ip = ip + flag in th06 | 242 // ip = ip + flag in th06 |
236 self.ip = ip; | 243 self.frame.ip = ip; |
237 // we jump back to the main of the interpreter | 244 // we jump back to the main of the interpreter |
238 } | 245 } |
239 // 3 | 246 // 3 |
240 // GHIDRA SAYS THERE IS A COMPARISON_REG BUFFER BUT THERE IS NOT!!! | 247 // GHIDRA SAYS THERE IS A COMPARISON_REG BUFFER BUT THERE IS NOT!!! |
241 // | 248 // |
373 // 27(int), 28(float) | 380 // 27(int), 28(float) |
374 SubInstruction::CompareInts(a, b) => { | 381 SubInstruction::CompareInts(a, b) => { |
375 let a = self.get_i32(a); | 382 let a = self.get_i32(a); |
376 let b = self.get_i32(b); | 383 let b = self.get_i32(b); |
377 if a < b { | 384 if a < b { |
378 self.comparison_reg = -1; | 385 self.frame.comparison_reg = -1; |
379 } | 386 } |
380 else if a == b { | 387 else if a == b { |
381 self.comparison_reg = 0; | 388 self.frame.comparison_reg = 0; |
382 } | 389 } |
383 else { | 390 else { |
384 self.comparison_reg = 1; | 391 self.frame.comparison_reg = 1; |
385 } | 392 } |
386 } | 393 } |
387 SubInstruction::CompareFloats(a, b) => { | 394 SubInstruction::CompareFloats(a, b) => { |
388 let a = self.get_f32(a); | 395 let a = self.get_f32(a); |
389 let b = self.get_f32(b); | 396 let b = self.get_f32(b); |
390 if a < b { | 397 if a < b { |
391 self.comparison_reg = -1; | 398 self.frame.comparison_reg = -1; |
392 } | 399 } |
393 else if a == b { | 400 else if a == b { |
394 self.comparison_reg = 0; | 401 self.frame.comparison_reg = 0; |
395 } | 402 } |
396 else { | 403 else { |
397 self.comparison_reg = 1; | 404 self.frame.comparison_reg = 1; |
398 } | 405 } |
399 } | 406 } |
400 // 29 | 407 // 29 |
401 SubInstruction::RelativeJumpIfLowerThan(frame, ip) => { | 408 SubInstruction::RelativeJumpIfLowerThan(frame, ip) => { |
402 if self.comparison_reg == -1 { | 409 if self.frame.comparison_reg == -1 { |
403 SubInstruction::RelativeJump(frame, ip); | 410 SubInstruction::RelativeJump(frame, ip); |
404 } | 411 } |
405 } | 412 } |
406 // 30 | 413 // 30 |
407 SubInstruction::RelativeJumpIfLowerOrEqual(frame, ip) => { | 414 SubInstruction::RelativeJumpIfLowerOrEqual(frame, ip) => { |
408 if self.comparison_reg != 1 { | 415 if self.frame.comparison_reg != 1 { |
409 SubInstruction::RelativeJump(frame, ip); | 416 SubInstruction::RelativeJump(frame, ip); |
410 } | 417 } |
411 } | 418 } |
412 // 31 | 419 // 31 |
413 SubInstruction::RelativeJumpIfEqual(frame, ip) => { | 420 SubInstruction::RelativeJumpIfEqual(frame, ip) => { |
414 if self.comparison_reg == 0 { | 421 if self.frame.comparison_reg == 0 { |
415 SubInstruction::RelativeJump(frame, ip); | 422 SubInstruction::RelativeJump(frame, ip); |
416 } | 423 } |
417 } | 424 } |
418 // 32 | 425 // 32 |
419 SubInstruction::RelativeJumpIfGreaterThan(frame, ip) => { | 426 SubInstruction::RelativeJumpIfGreaterThan(frame, ip) => { |
420 if self.comparison_reg == 1 { | 427 if self.frame.comparison_reg == 1 { |
421 SubInstruction::RelativeJump(frame, ip); | 428 SubInstruction::RelativeJump(frame, ip); |
422 } | 429 } |
423 } | 430 } |
424 // 33 | 431 // 33 |
425 SubInstruction::RelativeJumpIfGreaterOrEqual(frame, ip) => { | 432 SubInstruction::RelativeJumpIfGreaterOrEqual(frame, ip) => { |
426 if self.comparison_reg != -1 { | 433 if self.frame.comparison_reg != -1 { |
427 SubInstruction::RelativeJump(frame, ip); | 434 SubInstruction::RelativeJump(frame, ip); |
428 } | 435 } |
429 } | 436 } |
430 // 34 | 437 // 34 |
431 SubInstruction::RelativeJumpIfNotEqual(frame, ip) => { | 438 SubInstruction::RelativeJumpIfNotEqual(frame, ip) => { |
432 if self.comparison_reg != 0 { | 439 if self.frame.comparison_reg != 0 { |
433 SubInstruction::RelativeJump(frame, ip); | 440 SubInstruction::RelativeJump(frame, ip); |
434 } | 441 } |
435 } | 442 } |
436 // 35 | 443 // 35 |
437 SubInstruction::Call(sub, param1, param2) => { | 444 SubInstruction::Call(sub, param1, param2) => { |
438 // does insane stuff with the stack, not implemented | 445 self.stack.push(self.frame.clone()); |
439 unimplemented!() | 446 self.frame.sub = sub as u16; |
447 self.frame.ints1[0] = param1; | |
448 self.frame.floats[0] = param2; | |
449 self.frame.frame = 0; | |
450 self.frame.ip = 0; | |
440 } | 451 } |
441 | 452 |
442 // 36 | 453 // 36 |
443 SubInstruction::Return() => { | 454 SubInstruction::Return() => { |
444 // does insane stuff with the stack, not implemented | 455 self.frame = self.stack.pop().unwrap(); |
445 unimplemented!() | |
446 } | 456 } |
447 // 37 | 457 // 37 |
448 SubInstruction::CallIfSuperior(sub, param1, param2, a, b) => { | 458 SubInstruction::CallIfSuperior(sub, param1, param2, a, b) => { |
449 if self.get_i32(a) < self.get_i32(b) { | 459 if self.get_i32(a) < self.get_i32(b) { |
450 SubInstruction::Call(sub, param1, param2); | 460 self.run_instruction(SubInstruction::Call(sub, param1, param2)); |
451 } | 461 } |
452 } | 462 } |
453 // 38 | 463 // 38 |
454 SubInstruction::CallIfSuperiorOrEqual(sub, param1, param2, a, b) => { | 464 SubInstruction::CallIfSuperiorOrEqual(sub, param1, param2, a, b) => { |
455 if self.get_i32(a) <= self.get_i32(b) { | 465 if self.get_i32(a) <= self.get_i32(b) { |
456 SubInstruction::Call(sub, param1, param2); | 466 self.run_instruction(SubInstruction::Call(sub, param1, param2)); |
457 } | 467 } |
458 } | 468 } |
459 // 39 | 469 // 39 |
460 SubInstruction::CallIfEqual(sub, param1, param2, a, b) => { | 470 SubInstruction::CallIfEqual(sub, param1, param2, a, b) => { |
461 if self.get_i32(a) == self.get_i32(b) { | 471 if self.get_i32(a) == self.get_i32(b) { |
462 SubInstruction::Call(sub, param1, param2); | 472 self.run_instruction(SubInstruction::Call(sub, param1, param2)); |
463 } | 473 } |
464 } | 474 } |
465 // 40 | 475 // 40 |
466 SubInstruction::CallIfInferior(sub, param1, param2, a, b) => { | 476 SubInstruction::CallIfInferior(sub, param1, param2, a, b) => { |
467 if self.get_i32(b) < self.get_i32(a) { | 477 if self.get_i32(b) < self.get_i32(a) { |
468 SubInstruction::Call(sub, param1, param2); | 478 self.run_instruction(SubInstruction::Call(sub, param1, param2)); |
469 } | 479 } |
470 } | 480 } |
471 | 481 |
472 // 41 | 482 // 41 |
473 SubInstruction::CallIfInferiorOrEqual(sub, param1, param2, a, b) => { | 483 SubInstruction::CallIfInferiorOrEqual(sub, param1, param2, a, b) => { |
474 if self.get_i32(b) <= self.get_i32(a) { | 484 if self.get_i32(b) <= self.get_i32(a) { |
475 SubInstruction::Call(sub, param1, param2); | 485 self.run_instruction(SubInstruction::Call(sub, param1, param2)); |
476 } | 486 } |
477 } | 487 } |
478 //42 | 488 //42 |
479 SubInstruction::CallIfNotEqual(sub, param1, param2, a, b) => { | 489 SubInstruction::CallIfNotEqual(sub, param1, param2, a, b) => { |
480 if self.get_i32(a) != self.get_i32(b) { | 490 if self.get_i32(a) != self.get_i32(b) { |
481 SubInstruction::Call(sub, param1, param2); | 491 self.run_instruction(SubInstruction::Call(sub, param1, param2)); |
482 } | 492 } |
483 } | 493 } |
484 | 494 |
485 // 43 | 495 // 43 |
486 SubInstruction::SetPosition(x, y, z) => { | 496 SubInstruction::SetPosition(x, y, z) => { |
727 // which, uhhhh, we are not going to reimplement for obvious reasons | 737 // which, uhhhh, we are not going to reimplement for obvious reasons |
728 // the correct implementation would be: if this laser does not exist have a | 738 // the correct implementation would be: if this laser does not exist have a |
729 // 1/100000 chance to continue, otherwise crash | 739 // 1/100000 chance to continue, otherwise crash |
730 if enemy.laser_by_id.contains_key(&laser_id) { | 740 if enemy.laser_by_id.contains_key(&laser_id) { |
731 // let's assume we gud | 741 // let's assume we gud |
732 self.comparison_reg = 1; | 742 self.frame.comparison_reg = 1; |
733 } | 743 } |
734 else{ | 744 else{ |
735 self.comparison_reg = 0; | 745 self.frame.comparison_reg = 0; |
736 } | 746 } |
737 } | 747 } |
738 | 748 |
739 // 92 | 749 // 92 |
740 /* | 750 /* |