st010_op.cpp 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  1. #ifdef ST010_CPP
  2. //ST-010 emulation code - Copyright (C) 2003 The Dumper, Matthew Kendora, Overload, Feather
  3. //bsnes port - Copyright (C) 2007 byuu
  4. void ST010::op_01(int16 x0, int16 y0, int16 &x1, int16 &y1, int16 &quadrant, int16 &theta) {
  5. if((x0 < 0) && (y0 < 0)) {
  6. x1 = -x0;
  7. y1 = -y0;
  8. quadrant = -0x8000;
  9. } else if(x0 < 0) {
  10. x1 = y0;
  11. y1 = -x0;
  12. quadrant = -0x4000;
  13. } else if(y0 < 0) {
  14. x1 = -y0;
  15. y1 = x0;
  16. quadrant = 0x4000;
  17. } else {
  18. x1 = x0;
  19. y1 = y0;
  20. quadrant = 0x0000;
  21. }
  22. while((x1 > 0x1f) || (y1 > 0x1f)) {
  23. if(x1 > 1) { x1 >>= 1; }
  24. if(y1 > 1) { y1 >>= 1; }
  25. }
  26. if(y1 == 0) { quadrant += 0x4000; }
  27. theta = (arctan[y1][x1] << 8) ^ quadrant;
  28. }
  29. //
  30. void ST010::op_01() {
  31. int16 x0 = readw(0x0000);
  32. int16 y0 = readw(0x0002);
  33. int16 x1, y1, quadrant, theta;
  34. op_01(x0, y0, x1, y1, quadrant, theta);
  35. writew(0x0000, x1);
  36. writew(0x0002, y1);
  37. writew(0x0004, quadrant);
  38. //writew(0x0006, y0); //Overload's docs note this write occurs, SNES9x disagrees
  39. writew(0x0010, theta);
  40. }
  41. void ST010::op_02() {
  42. int16 positions = readw(0x0024);
  43. uint16 *places = (uint16*)(ram + 0x0040);
  44. uint16 *drivers = (uint16*)(ram + 0x0080);
  45. bool sorted;
  46. uint16 temp;
  47. if(positions > 1) {
  48. do {
  49. sorted = true;
  50. for(int i = 0; i < positions - 1; i++) {
  51. if(places[i] < places[i + 1]) {
  52. temp = places[i + 1];
  53. places[i + 1] = places[i];
  54. places[i] = temp;
  55. temp = drivers[i + 1];
  56. drivers[i + 1] = drivers[i];
  57. drivers[i] = temp;
  58. sorted = false;
  59. }
  60. }
  61. positions--;
  62. } while(!sorted);
  63. }
  64. }
  65. void ST010::op_03() {
  66. int16 x0 = readw(0x0000);
  67. int16 y0 = readw(0x0002);
  68. int16 multiplier = readw(0x0004);
  69. int32 x1, y1;
  70. x1 = x0 * multiplier << 1;
  71. y1 = y0 * multiplier << 1;
  72. writed(0x0010, x1);
  73. writed(0x0014, y1);
  74. }
  75. void ST010::op_04() {
  76. int16 x = readw(0x0000);
  77. int16 y = readw(0x0002);
  78. int16 square;
  79. //calculate the vector length of (x,y)
  80. square = (int16)sqrt((double)(y * y + x * x));
  81. writew(0x0010, square);
  82. }
  83. void ST010::op_05() {
  84. int32 dx, dy;
  85. int16 a1, b1, c1;
  86. uint16 o1;
  87. bool wrap = false;
  88. //target (x,y) coordinates
  89. int16 ypos_max = readw(0x00c0);
  90. int16 xpos_max = readw(0x00c2);
  91. //current coordinates and direction
  92. int32 ypos = readd(0x00c4);
  93. int32 xpos = readd(0x00c8);
  94. uint16 rot = readw(0x00cc);
  95. //physics
  96. uint16 speed = readw(0x00d4);
  97. uint16 accel = readw(0x00d6);
  98. uint16 speed_max = readw(0x00d8);
  99. //special condition acknowledgement
  100. int16 system = readw(0x00da);
  101. int16 flags = readw(0x00dc);
  102. //new target coordinates
  103. int16 ypos_new = readw(0x00de);
  104. int16 xpos_new = readw(0x00e0);
  105. //mask upper bit
  106. xpos_new &= 0x7fff;
  107. //get the current distance
  108. dx = xpos_max - (xpos >> 16);
  109. dy = ypos_max - (ypos >> 16);
  110. //quirk: clear and move in9
  111. writew(0x00d2, 0xffff);
  112. writew(0x00da, 0x0000);
  113. //grab the target angle
  114. op_01(dy, dx, a1, b1, c1, (int16&)o1);
  115. //check for wrapping
  116. if(abs(o1 - rot) > 0x8000) {
  117. o1 += 0x8000;
  118. rot += 0x8000;
  119. wrap = true;
  120. }
  121. uint16 old_speed = speed;
  122. //special case
  123. if(abs(o1 - rot) == 0x8000) {
  124. speed = 0x100;
  125. }
  126. //slow down for sharp curves
  127. else if(abs(o1 - rot) >= 0x1000) {
  128. uint32 slow = abs(o1 - rot);
  129. slow >>= 4; //scaling
  130. speed -= slow;
  131. }
  132. //otherwise accelerate
  133. else {
  134. speed += accel;
  135. if(speed > speed_max) {
  136. speed = speed_max; //clip speed
  137. }
  138. }
  139. //prevent negative/positive overflow
  140. if(abs(old_speed - speed) > 0x8000) {
  141. if(old_speed < speed) { speed = 0; }
  142. else speed = 0xff00;
  143. }
  144. //adjust direction by so many degrees
  145. //be careful of negative adjustments
  146. if((o1 > rot && (o1 - rot) > 0x80) || (o1 < rot && (rot - o1) >= 0x80)) {
  147. if(o1 < rot) { rot -= 0x280; }
  148. else if(o1 > rot) { rot += 0x280; }
  149. }
  150. //turn of wrapping
  151. if(wrap) { rot -= 0x8000; }
  152. //now check the distances (store for later)
  153. dx = (xpos_max << 16) - xpos;
  154. dy = (ypos_max << 16) - ypos;
  155. dx >>= 16;
  156. dy >>= 16;
  157. //if we're in so many units of the target, signal it
  158. if((system && (dy <= 6 && dy >= -8) && (dx <= 126 && dx >= -128)) || (!system && (dx <= 6 && dx >= -8) && (dy <= 126 && dy >= -128))) {
  159. //announce our new destination and flag it
  160. xpos_max = xpos_new & 0x7fff;
  161. ypos_max = ypos_new;
  162. flags |= 0x08;
  163. }
  164. //update position
  165. xpos -= (cos(rot) * 0x400 >> 15) * (speed >> 8) << 1;
  166. ypos -= (sin(rot) * 0x400 >> 15) * (speed >> 8) << 1;
  167. //quirk: mask upper byte
  168. xpos &= 0x1fffffff;
  169. ypos &= 0x1fffffff;
  170. writew(0x00c0, ypos_max);
  171. writew(0x00c2, xpos_max);
  172. writed(0x00c4, ypos);
  173. writed(0x00c8, xpos);
  174. writew(0x00cc, rot);
  175. writew(0x00d4, speed);
  176. writew(0x00dc, flags);
  177. }
  178. void ST010::op_06() {
  179. int16 multiplicand = readw(0x0000);
  180. int16 multiplier = readw(0x0002);
  181. int32 product;
  182. product = multiplicand * multiplier << 1;
  183. writed(0x0010, product);
  184. }
  185. void ST010::op_07() {
  186. int16 theta = readw(0x0000);
  187. int16 data;
  188. for(int i = 0, offset = 0; i < 176; i++) {
  189. data = mode7_scale[i] * cos(theta) >> 15;
  190. writew(0x00f0 + offset, data);
  191. writew(0x0510 + offset, data);
  192. data = mode7_scale[i] * sin(theta) >> 15;
  193. writew(0x0250 + offset, data);
  194. if(data) { data = ~data; }
  195. writew(0x03b0 + offset, data);
  196. offset += 2;
  197. }
  198. }
  199. void ST010::op_08() {
  200. int16 x0 = readw(0x0000);
  201. int16 y0 = readw(0x0002);
  202. int16 theta = readw(0x0004);
  203. int16 x1, y1;
  204. x1 = (y0 * sin(theta) >> 15) + (x0 * cos(theta) >> 15);
  205. y1 = (y0 * cos(theta) >> 15) - (x0 * sin(theta) >> 15);
  206. writew(0x0010, x1);
  207. writew(0x0012, y1);
  208. }
  209. #endif