vm_ppc.c 47 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480
  1. /*
  2. ===========================================================================
  3. Copyright (C) 1999-2005 Id Software, Inc.
  4. This file is part of Quake III Arena source code.
  5. Quake III Arena source code is free software; you can redistribute it
  6. and/or modify it under the terms of the GNU General Public License as
  7. published by the Free Software Foundation; either version 2 of the License,
  8. or (at your option) any later version.
  9. Quake III Arena source code is distributed in the hope that it will be
  10. useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with Foobar; if not, write to the Free Software
  15. Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  16. ===========================================================================
  17. */
  18. // vm_ppc.c
  19. // ppc dynamic compiler
  20. #include "vm_local.h"
  21. #pragma opt_pointer_analysis off
  22. typedef enum {
  23. R_REAL_STACK = 1,
  24. // registers 3-11 are the parameter passing registers
  25. // state
  26. R_STACK = 3, // local
  27. R_OPSTACK, // global
  28. // constants
  29. R_MEMBASE, // global
  30. R_MEMMASK,
  31. R_ASMCALL, // global
  32. R_INSTRUCTIONS, // global
  33. R_NUM_INSTRUCTIONS, // global
  34. R_CVM, // currentVM
  35. // temps
  36. R_TOP = 11,
  37. R_SECOND = 12,
  38. R_EA = 2 // effective address calculation
  39. } regNums_t;
  40. #define RG_REAL_STACK r1
  41. #define RG_STACK r3
  42. #define RG_OPSTACK r4
  43. #define RG_MEMBASE r5
  44. #define RG_MEMMASK r6
  45. #define RG_ASMCALL r7
  46. #define RG_INSTRUCTIONS r8
  47. #define RG_NUM_INSTRUCTIONS r9
  48. #define RG_CVM r10
  49. #define RG_TOP r12
  50. #define RG_SECOND r13
  51. #define RG_EA r14
  52. // this doesn't have the low order bits set for instructions i'm not using...
  53. typedef enum {
  54. PPC_TDI = 0x08000000,
  55. PPC_TWI = 0x0c000000,
  56. PPC_MULLI = 0x1c000000,
  57. PPC_SUBFIC = 0x20000000,
  58. PPC_CMPI = 0x28000000,
  59. PPC_CMPLI = 0x2c000000,
  60. PPC_ADDIC = 0x30000000,
  61. PPC_ADDIC_ = 0x34000000,
  62. PPC_ADDI = 0x38000000,
  63. PPC_ADDIS = 0x3c000000,
  64. PPC_BC = 0x40000000,
  65. PPC_SC = 0x44000000,
  66. PPC_B = 0x48000000,
  67. PPC_MCRF = 0x4c000000,
  68. PPC_BCLR = 0x4c000020,
  69. PPC_RFID = 0x4c000000,
  70. PPC_CRNOR = 0x4c000000,
  71. PPC_RFI = 0x4c000000,
  72. PPC_CRANDC = 0x4c000000,
  73. PPC_ISYNC = 0x4c000000,
  74. PPC_CRXOR = 0x4c000000,
  75. PPC_CRNAND = 0x4c000000,
  76. PPC_CREQV = 0x4c000000,
  77. PPC_CRORC = 0x4c000000,
  78. PPC_CROR = 0x4c000000,
  79. //------------
  80. PPC_BCCTR = 0x4c000420,
  81. PPC_RLWIMI = 0x50000000,
  82. PPC_RLWINM = 0x54000000,
  83. PPC_RLWNM = 0x5c000000,
  84. PPC_ORI = 0x60000000,
  85. PPC_ORIS = 0x64000000,
  86. PPC_XORI = 0x68000000,
  87. PPC_XORIS = 0x6c000000,
  88. PPC_ANDI_ = 0x70000000,
  89. PPC_ANDIS_ = 0x74000000,
  90. PPC_RLDICL = 0x78000000,
  91. PPC_RLDICR = 0x78000000,
  92. PPC_RLDIC = 0x78000000,
  93. PPC_RLDIMI = 0x78000000,
  94. PPC_RLDCL = 0x78000000,
  95. PPC_RLDCR = 0x78000000,
  96. PPC_CMP = 0x7c000000,
  97. PPC_TW = 0x7c000000,
  98. PPC_SUBFC = 0x7c000010,
  99. PPC_MULHDU = 0x7c000000,
  100. PPC_ADDC = 0x7c000014,
  101. PPC_MULHWU = 0x7c000000,
  102. PPC_MFCR = 0x7c000000,
  103. PPC_LWAR = 0x7c000000,
  104. PPC_LDX = 0x7c000000,
  105. PPC_LWZX = 0x7c00002e,
  106. PPC_SLW = 0x7c000030,
  107. PPC_CNTLZW = 0x7c000000,
  108. PPC_SLD = 0x7c000000,
  109. PPC_AND = 0x7c000038,
  110. PPC_CMPL = 0x7c000040,
  111. PPC_SUBF = 0x7c000050,
  112. PPC_LDUX = 0x7c000000,
  113. //------------
  114. PPC_DCBST = 0x7c000000,
  115. PPC_LWZUX = 0x7c00006c,
  116. PPC_CNTLZD = 0x7c000000,
  117. PPC_ANDC = 0x7c000000,
  118. PPC_TD = 0x7c000000,
  119. PPC_MULHD = 0x7c000000,
  120. PPC_MULHW = 0x7c000000,
  121. PPC_MTSRD = 0x7c000000,
  122. PPC_MFMSR = 0x7c000000,
  123. PPC_LDARX = 0x7c000000,
  124. PPC_DCBF = 0x7c000000,
  125. PPC_LBZX = 0x7c0000ae,
  126. PPC_NEG = 0x7c000000,
  127. PPC_MTSRDIN = 0x7c000000,
  128. PPC_LBZUX = 0x7c000000,
  129. PPC_NOR = 0x7c0000f8,
  130. PPC_SUBFE = 0x7c000000,
  131. PPC_ADDE = 0x7c000000,
  132. PPC_MTCRF = 0x7c000000,
  133. PPC_MTMSR = 0x7c000000,
  134. PPC_STDX = 0x7c000000,
  135. PPC_STWCX_ = 0x7c000000,
  136. PPC_STWX = 0x7c00012e,
  137. PPC_MTMSRD = 0x7c000000,
  138. PPC_STDUX = 0x7c000000,
  139. PPC_STWUX = 0x7c00016e,
  140. PPC_SUBFZE = 0x7c000000,
  141. PPC_ADDZE = 0x7c000000,
  142. PPC_MTSR = 0x7c000000,
  143. PPC_STDCX_ = 0x7c000000,
  144. PPC_STBX = 0x7c0001ae,
  145. PPC_SUBFME = 0x7c000000,
  146. PPC_MULLD = 0x7c000000,
  147. //------------
  148. PPC_ADDME = 0x7c000000,
  149. PPC_MULLW = 0x7c0001d6,
  150. PPC_MTSRIN = 0x7c000000,
  151. PPC_DCBTST = 0x7c000000,
  152. PPC_STBUX = 0x7c000000,
  153. PPC_ADD = 0x7c000214,
  154. PPC_DCBT = 0x7c000000,
  155. PPC_LHZX = 0x7c00022e,
  156. PPC_EQV = 0x7c000000,
  157. PPC_TLBIE = 0x7c000000,
  158. PPC_ECIWX = 0x7c000000,
  159. PPC_LHZUX = 0x7c000000,
  160. PPC_XOR = 0x7c000278,
  161. PPC_MFSPR = 0x7c0002a6,
  162. PPC_LWAX = 0x7c000000,
  163. PPC_LHAX = 0x7c000000,
  164. PPC_TLBIA = 0x7c000000,
  165. PPC_MFTB = 0x7c000000,
  166. PPC_LWAUX = 0x7c000000,
  167. PPC_LHAUX = 0x7c000000,
  168. PPC_STHX = 0x7c00032e,
  169. PPC_ORC = 0x7c000338,
  170. PPC_SRADI = 0x7c000000,
  171. PPC_SLBIE = 0x7c000000,
  172. PPC_ECOWX = 0x7c000000,
  173. PPC_STHUX = 0x7c000000,
  174. PPC_OR = 0x7c000378,
  175. PPC_DIVDU = 0x7c000000,
  176. PPC_DIVWU = 0x7c000396,
  177. PPC_MTSPR = 0x7c0003a6,
  178. PPC_DCBI = 0x7c000000,
  179. PPC_NAND = 0x7c000000,
  180. PPC_DIVD = 0x7c000000,
  181. //------------
  182. PPC_DIVW = 0x7c0003d6,
  183. PPC_SLBIA = 0x7c000000,
  184. PPC_MCRXR = 0x7c000000,
  185. PPC_LSWX = 0x7c000000,
  186. PPC_LWBRX = 0x7c000000,
  187. PPC_LFSX = 0x7c000000,
  188. PPC_SRW = 0x7c000430,
  189. PPC_SRD = 0x7c000000,
  190. PPC_TLBSYNC = 0x7c000000,
  191. PPC_LFSUX = 0x7c000000,
  192. PPC_MFSR = 0x7c000000,
  193. PPC_LSWI = 0x7c000000,
  194. PPC_SYNC = 0x7c000000,
  195. PPC_LFDX = 0x7c000000,
  196. PPC_LFDUX = 0x7c000000,
  197. PPC_MFSRIN = 0x7c000000,
  198. PPC_STSWX = 0x7c000000,
  199. PPC_STWBRX = 0x7c000000,
  200. PPC_STFSX = 0x7c000000,
  201. PPC_STFSUX = 0x7c000000,
  202. PPC_STSWI = 0x7c000000,
  203. PPC_STFDX = 0x7c000000,
  204. PPC_DCBA = 0x7c000000,
  205. PPC_STFDUX = 0x7c000000,
  206. PPC_LHBRX = 0x7c000000,
  207. PPC_SRAW = 0x7c000630,
  208. PPC_SRAD = 0x7c000000,
  209. PPC_SRAWI = 0x7c000000,
  210. PPC_EIEIO = 0x7c000000,
  211. PPC_STHBRX = 0x7c000000,
  212. PPC_EXTSH = 0x7c000734,
  213. PPC_EXTSB = 0x7c000774,
  214. PPC_ICBI = 0x7c000000,
  215. //------------
  216. PPC_STFIWX = 0x7c0007ae,
  217. PPC_EXTSW = 0x7c000000,
  218. PPC_DCBZ = 0x7c000000,
  219. PPC_LWZ = 0x80000000,
  220. PPC_LWZU = 0x84000000,
  221. PPC_LBZ = 0x88000000,
  222. PPC_LBZU = 0x8c000000,
  223. PPC_STW = 0x90000000,
  224. PPC_STWU = 0x94000000,
  225. PPC_STB = 0x98000000,
  226. PPC_STBU = 0x9c000000,
  227. PPC_LHZ = 0xa0000000,
  228. PPC_LHZU = 0xa4000000,
  229. PPC_LHA = 0xa8000000,
  230. PPC_LHAU = 0xac000000,
  231. PPC_STH = 0xb0000000,
  232. PPC_STHU = 0xb4000000,
  233. PPC_LMW = 0xb8000000,
  234. PPC_STMW = 0xbc000000,
  235. PPC_LFS = 0xc0000000,
  236. PPC_LFSU = 0xc4000000,
  237. PPC_LFD = 0xc8000000,
  238. PPC_LFDU = 0xcc000000,
  239. PPC_STFS = 0xd0000000,
  240. PPC_STFSU = 0xd4000000,
  241. PPC_STFD = 0xd8000000,
  242. PPC_STFDU = 0xdc000000,
  243. PPC_LD = 0xe8000000,
  244. PPC_LDU = 0xe8000001,
  245. PPC_LWA = 0xe8000002,
  246. PPC_FDIVS = 0xec000024,
  247. PPC_FSUBS = 0xec000028,
  248. PPC_FADDS = 0xec00002a,
  249. //------------
  250. PPC_FSQRTS = 0xec000000,
  251. PPC_FRES = 0xec000000,
  252. PPC_FMULS = 0xec000032,
  253. PPC_FMSUBS = 0xec000000,
  254. PPC_FMADDS = 0xec000000,
  255. PPC_FNMSUBS = 0xec000000,
  256. PPC_FNMADDS = 0xec000000,
  257. PPC_STD = 0xf8000000,
  258. PPC_STDU = 0xf8000001,
  259. PPC_FCMPU = 0xfc000000,
  260. PPC_FRSP = 0xfc000018,
  261. PPC_FCTIW = 0xfc000000,
  262. PPC_FCTIWZ = 0xfc00001e,
  263. PPC_FDIV = 0xfc000000,
  264. PPC_FSUB = 0xfc000028,
  265. PPC_FADD = 0xfc000000,
  266. PPC_FSQRT = 0xfc000000,
  267. PPC_FSEL = 0xfc000000,
  268. PPC_FMUL = 0xfc000000,
  269. PPC_FRSQRTE = 0xfc000000,
  270. PPC_FMSUB = 0xfc000000,
  271. PPC_FMADD = 0xfc000000,
  272. PPC_FNMSUB = 0xfc000000,
  273. PPC_FNMADD = 0xfc000000,
  274. PPC_FCMPO = 0xfc000000,
  275. PPC_MTFSB1 = 0xfc000000,
  276. PPC_FNEG = 0xfc000050,
  277. PPC_MCRFS = 0xfc000000,
  278. PPC_MTFSB0 = 0xfc000000,
  279. PPC_FMR = 0xfc000000,
  280. PPC_MTFSFI = 0xfc000000,
  281. PPC_FNABS = 0xfc000000,
  282. PPC_FABS = 0xfc000000,
  283. //------------
  284. PPC_MFFS = 0xfc000000,
  285. PPC_MTFSF = 0xfc000000,
  286. PPC_FCTID = 0xfc000000,
  287. PPC_FCTIDZ = 0xfc000000,
  288. PPC_FCFID = 0xfc000000
  289. } ppcOpcodes_t;
  290. // the newly generated code
  291. static unsigned *buf;
  292. static int compiledOfs; // in dwords
  293. // fromt the original bytecode
  294. static byte *code;
  295. static int pc;
  296. void AsmCall( void );
  297. double itofConvert[2];
  298. static int Constant4( void ) {
  299. int v;
  300. v = code[pc] | (code[pc+1]<<8) | (code[pc+2]<<16) | (code[pc+3]<<24);
  301. pc += 4;
  302. return v;
  303. }
  304. static int Constant1( void ) {
  305. int v;
  306. v = code[pc];
  307. pc += 1;
  308. return v;
  309. }
  310. static void Emit4( int i ) {
  311. buf[ compiledOfs ] = i;
  312. compiledOfs++;
  313. }
  314. static void Inst( int opcode, int destReg, int aReg, int bReg ) {
  315. unsigned r;
  316. r = opcode | ( destReg << 21 ) | ( aReg << 16 ) | ( bReg << 11 ) ;
  317. buf[ compiledOfs ] = r;
  318. compiledOfs++;
  319. }
  320. static void Inst4( int opcode, int destReg, int aReg, int bReg, int cReg ) {
  321. unsigned r;
  322. r = opcode | ( destReg << 21 ) | ( aReg << 16 ) | ( bReg << 11 ) | ( cReg << 6 );
  323. buf[ compiledOfs ] = r;
  324. compiledOfs++;
  325. }
  326. static void InstImm( int opcode, int destReg, int aReg, int immediate ) {
  327. unsigned r;
  328. if ( immediate > 32767 || immediate < -32768 ) {
  329. Com_Error( ERR_FATAL, "VM_Compile: immediate value %i out of range, opcode %x,%d,%d", immediate, opcode, destReg, aReg );
  330. }
  331. r = opcode | ( destReg << 21 ) | ( aReg << 16 ) | ( immediate & 0xffff );
  332. buf[ compiledOfs ] = r;
  333. compiledOfs++;
  334. }
  335. static void InstImmU( int opcode, int destReg, int aReg, int immediate ) {
  336. unsigned r;
  337. if ( immediate > 0xffff || immediate < 0 ) {
  338. Com_Error( ERR_FATAL, "VM_Compile: immediate value %i out of range", immediate );
  339. }
  340. r = opcode | ( destReg << 21 ) | ( aReg << 16 ) | ( immediate & 0xffff );
  341. buf[ compiledOfs ] = r;
  342. compiledOfs++;
  343. }
  344. static qboolean rtopped;
  345. static int pop0, pop1, oc0, oc1;
  346. static vm_t *tvm;
  347. static int instruction;
  348. static byte *jused;
  349. static int pass;
  350. static void ltop() {
  351. if (rtopped == qfalse) {
  352. InstImm( PPC_LWZ, R_TOP, R_OPSTACK, 0 ); // get value from opstack
  353. }
  354. }
  355. static void ltopandsecond() {
  356. if (pass>=0 && buf[compiledOfs-1] == (PPC_STWU | R_TOP<<21 | R_OPSTACK<<16 | 4 ) && jused[instruction]==0 ) {
  357. compiledOfs--;
  358. if (!pass) {
  359. tvm->instructionPointers[instruction] = compiledOfs * 4;
  360. }
  361. InstImm( PPC_LWZ, R_SECOND, R_OPSTACK, 0 ); // get value from opstack
  362. InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, -4 );
  363. } else if (pass>=0 && buf[compiledOfs-1] == (PPC_STW | R_TOP<<21 | R_OPSTACK<<16 | 0 ) && jused[instruction]==0 ) {
  364. compiledOfs--;
  365. if (!pass) {
  366. tvm->instructionPointers[instruction] = compiledOfs * 4;
  367. }
  368. InstImm( PPC_LWZ, R_SECOND, R_OPSTACK, -4 ); // get value from opstack
  369. InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, -8 );
  370. } else {
  371. ltop(); // get value from opstack
  372. InstImm( PPC_LWZ, R_SECOND, R_OPSTACK, -4 ); // get value from opstack
  373. InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, -8 );
  374. }
  375. rtopped = qfalse;
  376. }
  377. // TJW: Unused
  378. #if 0
  379. static void fltop() {
  380. if (rtopped == qfalse) {
  381. InstImm( PPC_LFS, R_TOP, R_OPSTACK, 0 ); // get value from opstack
  382. }
  383. }
  384. #endif
  385. static void fltopandsecond() {
  386. InstImm( PPC_LFS, R_TOP, R_OPSTACK, 0 ); // get value from opstack
  387. InstImm( PPC_LFS, R_SECOND, R_OPSTACK, -4 ); // get value from opstack
  388. InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, -8 );
  389. rtopped = qfalse;
  390. return;
  391. }
  392. /*
  393. =================
  394. VM_Compile
  395. =================
  396. */
  397. void VM_Compile( vm_t *vm, vmHeader_t *header ) {
  398. int op;
  399. int maxLength;
  400. int v;
  401. int i;
  402. // set up the into-to-float variables
  403. ((int *)itofConvert)[0] = 0x43300000;
  404. ((int *)itofConvert)[1] = 0x80000000;
  405. ((int *)itofConvert)[2] = 0x43300000;
  406. // allocate a very large temp buffer, we will shrink it later
  407. maxLength = header->codeLength * 8;
  408. buf = Z_Malloc( maxLength );
  409. jused = Z_Malloc(header->instructionCount + 2);
  410. Com_Memset(jused, 0, header->instructionCount+2);
  411. // compile everything twice, so the second pass will have valid instruction
  412. // pointers for branches
  413. for ( pass = -1 ; pass < 2 ; pass++ ) {
  414. rtopped = qfalse;
  415. // translate all instructions
  416. pc = 0;
  417. pop0 = 343545;
  418. pop1 = 2443545;
  419. oc0 = -2343535;
  420. oc1 = 24353454;
  421. tvm = vm;
  422. code = (byte *)header + header->codeOffset;
  423. compiledOfs = 0;
  424. #ifndef __GNUC__
  425. // metrowerks seems to require this header in front of functions
  426. Emit4( (int)(buf+2) );
  427. Emit4( 0 );
  428. #endif
  429. for ( instruction = 0 ; instruction < header->instructionCount ; instruction++ ) {
  430. if ( compiledOfs*4 > maxLength - 16 ) {
  431. Com_Error( ERR_DROP, "VM_Compile: maxLength exceeded" );
  432. }
  433. op = code[ pc ];
  434. if ( !pass ) {
  435. vm->instructionPointers[ instruction ] = compiledOfs * 4;
  436. }
  437. pc++;
  438. switch ( op ) {
  439. case 0:
  440. break;
  441. case OP_BREAK:
  442. InstImmU( PPC_ADDI, R_TOP, 0, 0 );
  443. InstImm( PPC_LWZ, R_TOP, R_TOP, 0 ); // *(int *)0 to crash to debugger
  444. rtopped = qfalse;
  445. break;
  446. case OP_ENTER:
  447. InstImm( PPC_ADDI, R_STACK, R_STACK, -Constant4() ); // sub R_STACK, R_STACK, imm
  448. rtopped = qfalse;
  449. break;
  450. case OP_CONST:
  451. v = Constant4();
  452. if (code[pc] == OP_LOAD4 || code[pc] == OP_LOAD2 || code[pc] == OP_LOAD1) {
  453. v &= vm->dataMask;
  454. }
  455. if ( v < 32768 && v >= -32768 ) {
  456. InstImmU( PPC_ADDI, R_TOP, 0, v & 0xffff );
  457. } else {
  458. InstImmU( PPC_ADDIS, R_TOP, 0, (v >> 16)&0xffff );
  459. if ( v & 0xffff ) {
  460. InstImmU( PPC_ORI, R_TOP, R_TOP, v & 0xffff );
  461. }
  462. }
  463. if (code[pc] == OP_LOAD4) {
  464. Inst( PPC_LWZX, R_TOP, R_TOP, R_MEMBASE ); // load from memory base
  465. pc++;
  466. instruction++;
  467. } else if (code[pc] == OP_LOAD2) {
  468. Inst( PPC_LHZX, R_TOP, R_TOP, R_MEMBASE ); // load from memory base
  469. pc++;
  470. instruction++;
  471. } else if (code[pc] == OP_LOAD1) {
  472. Inst( PPC_LBZX, R_TOP, R_TOP, R_MEMBASE ); // load from memory base
  473. pc++;
  474. instruction++;
  475. }
  476. if (code[pc] == OP_STORE4) {
  477. InstImm( PPC_LWZ, R_SECOND, R_OPSTACK, 0 ); // get value from opstack
  478. InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, -4 );
  479. //Inst( PPC_AND, R_MEMMASK, R_SECOND, R_SECOND ); // mask it
  480. Inst( PPC_STWX, R_TOP, R_SECOND, R_MEMBASE ); // store from memory base
  481. pc++;
  482. instruction++;
  483. rtopped = qfalse;
  484. break;
  485. } else if (code[pc] == OP_STORE2) {
  486. InstImm( PPC_LWZ, R_SECOND, R_OPSTACK, 0 ); // get value from opstack
  487. InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, -4 );
  488. //Inst( PPC_AND, R_MEMMASK, R_SECOND, R_SECOND ); // mask it
  489. Inst( PPC_STHX, R_TOP, R_SECOND, R_MEMBASE ); // store from memory base
  490. pc++;
  491. instruction++;
  492. rtopped = qfalse;
  493. break;
  494. } else if (code[pc] == OP_STORE1) {
  495. InstImm( PPC_LWZ, R_SECOND, R_OPSTACK, 0 ); // get value from opstack
  496. InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, -4 );
  497. //Inst( PPC_AND, R_MEMMASK, R_SECOND, R_SECOND ); // mask it
  498. Inst( PPC_STBX, R_TOP, R_SECOND, R_MEMBASE ); // store from memory base
  499. pc++;
  500. instruction++;
  501. rtopped = qfalse;
  502. break;
  503. }
  504. if (code[pc] == OP_JUMP) {
  505. jused[v] = 1;
  506. }
  507. InstImm( PPC_STWU, R_TOP, R_OPSTACK, 4 );
  508. rtopped = qtrue;
  509. break;
  510. case OP_LOCAL:
  511. oc0 = oc1;
  512. oc1 = Constant4();
  513. if (code[pc] == OP_LOAD4 || code[pc] == OP_LOAD2 || code[pc] == OP_LOAD1) {
  514. oc1 &= vm->dataMask;
  515. }
  516. InstImm( PPC_ADDI, R_TOP, R_STACK, oc1 );
  517. if (code[pc] == OP_LOAD4) {
  518. Inst( PPC_LWZX, R_TOP, R_TOP, R_MEMBASE ); // load from memory base
  519. pc++;
  520. instruction++;
  521. } else if (code[pc] == OP_LOAD2) {
  522. Inst( PPC_LHZX, R_TOP, R_TOP, R_MEMBASE ); // load from memory base
  523. pc++;
  524. instruction++;
  525. } else if (code[pc] == OP_LOAD1) {
  526. Inst( PPC_LBZX, R_TOP, R_TOP, R_MEMBASE ); // load from memory base
  527. pc++;
  528. instruction++;
  529. }
  530. if (code[pc] == OP_STORE4) {
  531. InstImm( PPC_LWZ, R_SECOND, R_OPSTACK, 0 ); // get value from opstack
  532. InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, -4 );
  533. //Inst( PPC_AND, R_MEMMASK, R_SECOND, R_SECOND ); // mask it
  534. Inst( PPC_STWX, R_TOP, R_SECOND, R_MEMBASE ); // store from memory base
  535. pc++;
  536. instruction++;
  537. rtopped = qfalse;
  538. break;
  539. } else if (code[pc] == OP_STORE2) {
  540. InstImm( PPC_LWZ, R_SECOND, R_OPSTACK, 0 ); // get value from opstack
  541. InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, -4 );
  542. //Inst( PPC_AND, R_MEMMASK, R_SECOND, R_SECOND ); // mask it
  543. Inst( PPC_STHX, R_TOP, R_SECOND, R_MEMBASE ); // store from memory base
  544. pc++;
  545. instruction++;
  546. rtopped = qfalse;
  547. break;
  548. } else if (code[pc] == OP_STORE1) {
  549. InstImm( PPC_LWZ, R_SECOND, R_OPSTACK, 0 ); // get value from opstack
  550. InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, -4 );
  551. //Inst( PPC_AND, R_MEMMASK, R_SECOND, R_SECOND ); // mask it
  552. Inst( PPC_STBX, R_TOP, R_SECOND, R_MEMBASE ); // store from memory base
  553. pc++;
  554. instruction++;
  555. rtopped = qfalse;
  556. break;
  557. }
  558. InstImm( PPC_STWU, R_TOP, R_OPSTACK, 4 );
  559. rtopped = qtrue;
  560. break;
  561. case OP_ARG:
  562. ltop(); // get value from opstack
  563. InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, -4 );
  564. InstImm( PPC_ADDI, R_EA, R_STACK, Constant1() ); // location to put it
  565. Inst( PPC_STWX, R_TOP, R_EA, R_MEMBASE );
  566. rtopped = qfalse;
  567. break;
  568. case OP_CALL:
  569. Inst( PPC_MFSPR, R_SECOND, 8, 0 ); // move from link register
  570. InstImm( PPC_STWU, R_SECOND, R_REAL_STACK, -16 ); // save off the old return address
  571. Inst( PPC_MTSPR, R_ASMCALL, 9, 0 ); // move to count register
  572. Inst( PPC_BCCTR | 1, 20, 0, 0 ); // jump and link to the count register
  573. InstImm( PPC_LWZ, R_SECOND, R_REAL_STACK, 0 ); // fetch the old return address
  574. InstImm( PPC_ADDI, R_REAL_STACK, R_REAL_STACK, 16 );
  575. Inst( PPC_MTSPR, R_SECOND, 8, 0 ); // move to link register
  576. rtopped = qfalse;
  577. break;
  578. case OP_PUSH:
  579. InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, 4 );
  580. rtopped = qfalse;
  581. break;
  582. case OP_POP:
  583. InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, -4 );
  584. rtopped = qfalse;
  585. break;
  586. case OP_LEAVE:
  587. InstImm( PPC_ADDI, R_STACK, R_STACK, Constant4() ); // add R_STACK, R_STACK, imm
  588. Inst( PPC_BCLR, 20, 0, 0 ); // branch unconditionally to link register
  589. rtopped = qfalse;
  590. break;
  591. case OP_LOAD4:
  592. ltop(); // get value from opstack
  593. //Inst( PPC_AND, R_MEMMASK, R_TOP, R_TOP ); // mask it
  594. Inst( PPC_LWZX, R_TOP, R_TOP, R_MEMBASE ); // load from memory base
  595. InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 );
  596. rtopped = qtrue;
  597. break;
  598. case OP_LOAD2:
  599. ltop(); // get value from opstack
  600. //Inst( PPC_AND, R_MEMMASK, R_TOP, R_TOP ); // mask it
  601. Inst( PPC_LHZX, R_TOP, R_TOP, R_MEMBASE ); // load from memory base
  602. InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 );
  603. rtopped = qtrue;
  604. break;
  605. case OP_LOAD1:
  606. ltop(); // get value from opstack
  607. //Inst( PPC_AND, R_MEMMASK, R_TOP, R_TOP ); // mask it
  608. Inst( PPC_LBZX, R_TOP, R_TOP, R_MEMBASE ); // load from memory base
  609. InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 );
  610. rtopped = qtrue;
  611. break;
  612. case OP_STORE4:
  613. ltopandsecond(); // get value from opstack
  614. //Inst( PPC_AND, R_MEMMASK, R_SECOND, R_SECOND ); // mask it
  615. Inst( PPC_STWX, R_TOP, R_SECOND, R_MEMBASE ); // store from memory base
  616. rtopped = qfalse;
  617. break;
  618. case OP_STORE2:
  619. ltopandsecond(); // get value from opstack
  620. //Inst( PPC_AND, R_MEMMASK, R_SECOND, R_SECOND ); // mask it
  621. Inst( PPC_STHX, R_TOP, R_SECOND, R_MEMBASE ); // store from memory base
  622. rtopped = qfalse;
  623. break;
  624. case OP_STORE1:
  625. ltopandsecond(); // get value from opstack
  626. //Inst( PPC_AND, R_MEMMASK, R_SECOND, R_SECOND ); // mask it
  627. Inst( PPC_STBX, R_TOP, R_SECOND, R_MEMBASE ); // store from memory base
  628. rtopped = qfalse;
  629. break;
  630. case OP_EQ:
  631. ltopandsecond(); // get value from opstack
  632. Inst( PPC_CMP, 0, R_SECOND, R_TOP );
  633. i = Constant4();
  634. jused[i] = 1;
  635. InstImm( PPC_BC, 4, 2, 8 );
  636. if ( pass==1 ) {
  637. v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
  638. } else {
  639. v = 0;
  640. }
  641. Emit4(PPC_B | (v&0x3ffffff) );
  642. rtopped = qfalse;
  643. break;
  644. case OP_NE:
  645. ltopandsecond(); // get value from opstack
  646. Inst( PPC_CMP, 0, R_SECOND, R_TOP );
  647. i = Constant4();
  648. jused[i] = 1;
  649. InstImm( PPC_BC, 12, 2, 8 );
  650. if ( pass==1 ) {
  651. v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
  652. } else {
  653. v = 0;
  654. }
  655. Emit4(PPC_B | (unsigned int)(v&0x3ffffff) );
  656. // InstImm( PPC_BC, 4, 2, v );
  657. rtopped = qfalse;
  658. break;
  659. case OP_LTI:
  660. ltopandsecond(); // get value from opstack
  661. Inst( PPC_CMP, 0, R_SECOND, R_TOP );
  662. i = Constant4();
  663. jused[i] = 1;
  664. InstImm( PPC_BC, 4, 0, 8 );
  665. if ( pass==1 ) {
  666. v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
  667. } else {
  668. v = 0;
  669. }
  670. Emit4(PPC_B | (unsigned int)(v&0x3ffffff) );
  671. // InstImm( PPC_BC, 12, 0, v );
  672. rtopped = qfalse;
  673. break;
  674. case OP_LEI:
  675. ltopandsecond(); // get value from opstack
  676. Inst( PPC_CMP, 0, R_SECOND, R_TOP );
  677. i = Constant4();
  678. jused[i] = 1;
  679. InstImm( PPC_BC, 12, 1, 8 );
  680. if ( pass==1 ) {
  681. v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
  682. } else {
  683. v = 0;
  684. }
  685. Emit4(PPC_B | (unsigned int)(v&0x3ffffff) );
  686. // InstImm( PPC_BC, 4, 1, v );
  687. rtopped = qfalse;
  688. break;
  689. case OP_GTI:
  690. ltopandsecond(); // get value from opstack
  691. Inst( PPC_CMP, 0, R_SECOND, R_TOP );
  692. i = Constant4();
  693. jused[i] = 1;
  694. InstImm( PPC_BC, 4, 1, 8 );
  695. if ( pass==1 ) {
  696. v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
  697. } else {
  698. v = 0;
  699. }
  700. Emit4(PPC_B | (unsigned int)(v&0x3ffffff) );
  701. // InstImm( PPC_BC, 12, 1, v );
  702. rtopped = qfalse;
  703. break;
  704. case OP_GEI:
  705. ltopandsecond(); // get value from opstack
  706. Inst( PPC_CMP, 0, R_SECOND, R_TOP );
  707. i = Constant4();
  708. jused[i] = 1;
  709. InstImm( PPC_BC, 12, 0, 8 );
  710. if ( pass==1 ) {
  711. v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
  712. } else {
  713. v = 0;
  714. }
  715. Emit4(PPC_B | (unsigned int)(v&0x3ffffff) );
  716. // InstImm( PPC_BC, 4, 0, v );
  717. rtopped = qfalse;
  718. break;
  719. case OP_LTU:
  720. ltopandsecond(); // get value from opstack
  721. Inst( PPC_CMPL, 0, R_SECOND, R_TOP );
  722. i = Constant4();
  723. jused[i] = 1;
  724. InstImm( PPC_BC, 4, 0, 8 );
  725. if ( pass==1 ) {
  726. v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
  727. } else {
  728. v = 0;
  729. }
  730. Emit4(PPC_B | (unsigned int)(v&0x3ffffff) );
  731. // InstImm( PPC_BC, 12, 0, v );
  732. rtopped = qfalse;
  733. break;
  734. case OP_LEU:
  735. ltopandsecond(); // get value from opstack
  736. Inst( PPC_CMPL, 0, R_SECOND, R_TOP );
  737. i = Constant4();
  738. jused[i] = 1;
  739. InstImm( PPC_BC, 12, 1, 8 );
  740. if ( pass==1 ) {
  741. v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
  742. } else {
  743. v = 0;
  744. }
  745. Emit4(PPC_B | (unsigned int)(v&0x3ffffff) );
  746. // InstImm( PPC_BC, 4, 1, v );
  747. rtopped = qfalse;
  748. break;
  749. case OP_GTU:
  750. ltopandsecond(); // get value from opstack
  751. Inst( PPC_CMPL, 0, R_SECOND, R_TOP );
  752. i = Constant4();
  753. jused[i] = 1;
  754. InstImm( PPC_BC, 4, 1, 8 );
  755. if ( pass==1 ) {
  756. v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
  757. } else {
  758. v = 0;
  759. }
  760. Emit4(PPC_B | (unsigned int)(v&0x3ffffff) );
  761. // InstImm( PPC_BC, 12, 1, v );
  762. rtopped = qfalse;
  763. break;
  764. case OP_GEU:
  765. ltopandsecond(); // get value from opstack
  766. Inst( PPC_CMPL, 0, R_SECOND, R_TOP );
  767. i = Constant4();
  768. jused[i] = 1;
  769. InstImm( PPC_BC, 12, 0, 8 );
  770. if ( pass==1 ) {
  771. v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
  772. } else {
  773. v = 0;
  774. }
  775. Emit4(PPC_B | (unsigned int)(v&0x3ffffff) );
  776. // InstImm( PPC_BC, 4, 0, v );
  777. rtopped = qfalse;
  778. break;
  779. case OP_EQF:
  780. fltopandsecond(); // get value from opstack
  781. Inst( PPC_FCMPU, 0, R_TOP, R_SECOND );
  782. i = Constant4();
  783. jused[i] = 1;
  784. InstImm( PPC_BC, 4, 2, 8 );
  785. if ( pass==1 ) {
  786. v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
  787. } else {
  788. v = 0;
  789. }
  790. Emit4(PPC_B | (unsigned int)(v&0x3ffffff) );
  791. // InstImm( PPC_BC, 12, 2, v );
  792. rtopped = qfalse;
  793. break;
  794. case OP_NEF:
  795. fltopandsecond(); // get value from opstack
  796. Inst( PPC_FCMPU, 0, R_TOP, R_SECOND );
  797. i = Constant4();
  798. jused[i] = 1;
  799. InstImm( PPC_BC, 12, 2, 8 );
  800. if ( pass==1 ) {
  801. v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
  802. } else {
  803. v = 0;
  804. }
  805. Emit4(PPC_B | (unsigned int)(v&0x3ffffff) );
  806. // InstImm( PPC_BC, 4, 2, v );
  807. rtopped = qfalse;
  808. break;
  809. case OP_LTF:
  810. fltopandsecond(); // get value from opstack
  811. Inst( PPC_FCMPU, 0, R_SECOND, R_TOP );
  812. i = Constant4();
  813. jused[i] = 1;
  814. InstImm( PPC_BC, 4, 0, 8 );
  815. if ( pass==1 ) {
  816. v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
  817. } else {
  818. v = 0;
  819. }
  820. Emit4(PPC_B | (unsigned int)(v&0x3ffffff) );
  821. // InstImm( PPC_BC, 12, 0, v );
  822. rtopped = qfalse;
  823. break;
  824. case OP_LEF:
  825. fltopandsecond(); // get value from opstack
  826. Inst( PPC_FCMPU, 0, R_SECOND, R_TOP );
  827. i = Constant4();
  828. jused[i] = 1;
  829. InstImm( PPC_BC, 12, 1, 8 );
  830. if ( pass==1 ) {
  831. v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
  832. } else {
  833. v = 0;
  834. }
  835. Emit4(PPC_B | (unsigned int)(v&0x3ffffff) );
  836. // InstImm( PPC_BC, 4, 1, v );
  837. rtopped = qfalse;
  838. break;
  839. case OP_GTF:
  840. fltopandsecond(); // get value from opstack
  841. Inst( PPC_FCMPU, 0, R_SECOND, R_TOP );
  842. i = Constant4();
  843. jused[i] = 1;
  844. InstImm( PPC_BC, 4, 1, 8 );
  845. if ( pass==1 ) {
  846. v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
  847. } else {
  848. v = 0;
  849. }
  850. Emit4(PPC_B | (unsigned int)(v&0x3ffffff) );
  851. // InstImm( PPC_BC, 12, 1, v );
  852. rtopped = qfalse;
  853. break;
  854. case OP_GEF:
  855. fltopandsecond(); // get value from opstack
  856. Inst( PPC_FCMPU, 0, R_SECOND, R_TOP );
  857. i = Constant4();
  858. jused[i] = 1;
  859. InstImm( PPC_BC, 12, 0, 8 );
  860. if ( pass==1 ) {
  861. v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
  862. } else {
  863. v = 0;
  864. }
  865. Emit4(PPC_B | (unsigned int)(v&0x3ffffff) );
  866. // InstImm( PPC_BC, 4, 0, v );
  867. rtopped = qfalse;
  868. break;
  869. case OP_NEGI:
  870. ltop(); // get value from opstack
  871. InstImm( PPC_SUBFIC, R_TOP, R_TOP, 0 );
  872. InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 ); // save value to opstack
  873. rtopped = qtrue;
  874. break;
  875. case OP_ADD:
  876. ltop(); // get value from opstack
  877. InstImm( PPC_LWZU, R_SECOND, R_OPSTACK, -4 ); // get value from opstack
  878. Inst( PPC_ADD, R_TOP, R_TOP, R_SECOND );
  879. InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 ); // save value to opstack
  880. rtopped = qtrue;
  881. break;
  882. case OP_SUB:
  883. ltop(); // get value from opstack
  884. InstImm( PPC_LWZU, R_SECOND, R_OPSTACK, -4 ); // get value from opstack
  885. Inst( PPC_SUBF, R_TOP, R_TOP, R_SECOND );
  886. InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 ); // save value to opstack
  887. rtopped = qtrue;
  888. break;
  889. case OP_DIVI:
  890. ltop(); // get value from opstack
  891. InstImm( PPC_LWZU, R_SECOND, R_OPSTACK, -4 ); // get value from opstack
  892. Inst( PPC_DIVW, R_TOP, R_SECOND, R_TOP );
  893. InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 ); // save value to opstack
  894. rtopped = qtrue;
  895. break;
  896. case OP_DIVU:
  897. ltop(); // get value from opstack
  898. InstImm( PPC_LWZU, R_SECOND, R_OPSTACK, -4 ); // get value from opstack
  899. Inst( PPC_DIVWU, R_TOP, R_SECOND, R_TOP );
  900. InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 ); // save value to opstack
  901. rtopped = qtrue;
  902. break;
  903. case OP_MODI:
  904. ltop(); // get value from opstack
  905. InstImm( PPC_LWZU, R_SECOND, R_OPSTACK, -4 ); // get value from opstack
  906. Inst( PPC_DIVW, R_EA, R_SECOND, R_TOP );
  907. Inst( PPC_MULLW, R_EA, R_TOP, R_EA );
  908. Inst( PPC_SUBF, R_TOP, R_EA, R_SECOND );
  909. InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 ); // save value to opstack
  910. rtopped = qtrue;
  911. break;
  912. case OP_MODU:
  913. ltop(); // get value from opstack
  914. InstImm( PPC_LWZU, R_SECOND, R_OPSTACK, -4 ); // get value from opstack
  915. Inst( PPC_DIVWU, R_EA, R_SECOND, R_TOP );
  916. Inst( PPC_MULLW, R_EA, R_TOP, R_EA );
  917. Inst( PPC_SUBF, R_TOP, R_EA, R_SECOND );
  918. InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 ); // save value to opstack
  919. rtopped = qtrue;
  920. break;
  921. case OP_MULI:
  922. case OP_MULU:
  923. ltop(); // get value from opstack
  924. InstImm( PPC_LWZU, R_SECOND, R_OPSTACK, -4 ); // get value from opstack
  925. Inst( PPC_MULLW, R_TOP, R_SECOND, R_TOP );
  926. InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 ); // save value to opstack
  927. rtopped = qtrue;
  928. break;
  929. case OP_BAND:
  930. ltop(); // get value from opstack
  931. InstImm( PPC_LWZU, R_SECOND, R_OPSTACK, -4 ); // get value from opstack
  932. Inst( PPC_AND, R_SECOND, R_TOP, R_TOP );
  933. InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 ); // save value to opstack
  934. rtopped = qtrue;
  935. break;
  936. case OP_BOR:
  937. ltop(); // get value from opstack
  938. InstImm( PPC_LWZU, R_SECOND, R_OPSTACK, -4 ); // get value from opstack
  939. Inst( PPC_OR, R_SECOND, R_TOP, R_TOP );
  940. InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 ); // save value to opstack
  941. rtopped = qtrue;
  942. break;
  943. case OP_BXOR:
  944. ltop(); // get value from opstack
  945. InstImm( PPC_LWZU, R_SECOND, R_OPSTACK, -4 ); // get value from opstack
  946. Inst( PPC_XOR, R_SECOND, R_TOP, R_TOP );
  947. InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 ); // save value to opstack
  948. rtopped = qtrue;
  949. break;
  950. case OP_BCOM:
  951. ltop(); // get value from opstack
  952. Inst( PPC_NOR, R_TOP, R_TOP, R_TOP );
  953. InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 ); // save value to opstack
  954. rtopped = qtrue;
  955. break;
  956. case OP_LSH:
  957. ltop(); // get value from opstack
  958. InstImm( PPC_LWZU, R_SECOND, R_OPSTACK, -4 ); // get value from opstack
  959. Inst( PPC_SLW, R_SECOND, R_TOP, R_TOP );
  960. InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 ); // save value to opstack
  961. rtopped = qtrue;
  962. break;
  963. case OP_RSHI:
  964. ltop(); // get value from opstack
  965. InstImm( PPC_LWZU, R_SECOND, R_OPSTACK, -4 ); // get value from opstack
  966. Inst( PPC_SRAW, R_SECOND, R_TOP, R_TOP );
  967. InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 ); // save value to opstack
  968. rtopped = qtrue;
  969. break;
  970. case OP_RSHU:
  971. ltop(); // get value from opstack
  972. InstImm( PPC_LWZU, R_SECOND, R_OPSTACK, -4 ); // get value from opstack
  973. Inst( PPC_SRW, R_SECOND, R_TOP, R_TOP );
  974. InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 ); // save value to opstack
  975. rtopped = qtrue;
  976. break;
  977. case OP_NEGF:
  978. InstImm( PPC_LFS, R_TOP, R_OPSTACK, 0 ); // get value from opstack
  979. Inst( PPC_FNEG, R_TOP, 0, R_TOP );
  980. InstImm( PPC_STFS, R_TOP, R_OPSTACK, 0 ); // save value to opstack
  981. rtopped = qfalse;
  982. break;
  983. case OP_ADDF:
  984. InstImm( PPC_LFS, R_TOP, R_OPSTACK, 0 ); // get value from opstack
  985. InstImm( PPC_LFSU, R_SECOND, R_OPSTACK, -4 ); // get value from opstack
  986. Inst( PPC_FADDS, R_TOP, R_SECOND, R_TOP );
  987. InstImm( PPC_STFS, R_TOP, R_OPSTACK, 0 ); // save value to opstack
  988. rtopped = qfalse;
  989. break;
  990. case OP_SUBF:
  991. InstImm( PPC_LFS, R_TOP, R_OPSTACK, 0 ); // get value from opstack
  992. InstImm( PPC_LFSU, R_SECOND, R_OPSTACK, -4 ); // get value from opstack
  993. Inst( PPC_FSUBS, R_TOP, R_SECOND, R_TOP );
  994. InstImm( PPC_STFS, R_TOP, R_OPSTACK, 0 ); // save value to opstack
  995. rtopped = qfalse;
  996. break;
  997. case OP_DIVF:
  998. InstImm( PPC_LFS, R_TOP, R_OPSTACK, 0 ); // get value from opstack
  999. InstImm( PPC_LFSU, R_SECOND, R_OPSTACK, -4 ); // get value from opstack
  1000. Inst( PPC_FDIVS, R_TOP, R_SECOND, R_TOP );
  1001. InstImm( PPC_STFS, R_TOP, R_OPSTACK, 0 ); // save value to opstack
  1002. rtopped = qfalse;
  1003. break;
  1004. case OP_MULF:
  1005. InstImm( PPC_LFS, R_TOP, R_OPSTACK, 0 ); // get value from opstack
  1006. InstImm( PPC_LFSU, R_SECOND, R_OPSTACK, -4 ); // get value from opstack
  1007. Inst4( PPC_FMULS, R_TOP, R_SECOND, 0, R_TOP );
  1008. InstImm( PPC_STFS, R_TOP, R_OPSTACK, 0 ); // save value to opstack
  1009. rtopped = qfalse;
  1010. break;
  1011. case OP_CVIF:
  1012. v = (int)&itofConvert;
  1013. InstImmU( PPC_ADDIS, R_EA, 0, (v >> 16)&0xffff );
  1014. InstImmU( PPC_ORI, R_EA, R_EA, v & 0xffff );
  1015. InstImm( PPC_LWZ, R_TOP, R_OPSTACK, 0 ); // get value from opstack
  1016. InstImmU( PPC_XORIS, R_TOP, R_TOP, 0x8000 );
  1017. InstImm( PPC_STW, R_TOP, R_EA, 12 );
  1018. InstImm( PPC_LFD, R_TOP, R_EA, 0 );
  1019. InstImm( PPC_LFD, R_SECOND, R_EA, 8 );
  1020. Inst( PPC_FSUB, R_TOP, R_SECOND, R_TOP );
  1021. // Inst( PPC_FRSP, R_TOP, 0, R_TOP );
  1022. InstImm( PPC_STFS, R_TOP, R_OPSTACK, 0 ); // save value to opstack
  1023. rtopped = qfalse;
  1024. break;
  1025. case OP_CVFI:
  1026. InstImm( PPC_LFS, R_TOP, R_OPSTACK, 0 ); // get value from opstack
  1027. Inst( PPC_FCTIWZ, R_TOP, 0, R_TOP );
  1028. Inst( PPC_STFIWX, R_TOP, 0, R_OPSTACK ); // save value to opstack
  1029. rtopped = qfalse;
  1030. break;
  1031. case OP_SEX8:
  1032. ltop(); // get value from opstack
  1033. Inst( PPC_EXTSB, R_TOP, R_TOP, 0 );
  1034. InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 );
  1035. rtopped = qtrue;
  1036. break;
  1037. case OP_SEX16:
  1038. ltop(); // get value from opstack
  1039. Inst( PPC_EXTSH, R_TOP, R_TOP, 0 );
  1040. InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 );
  1041. rtopped = qtrue;
  1042. break;
  1043. case OP_BLOCK_COPY:
  1044. v = Constant4() >> 2;
  1045. ltop(); // source
  1046. InstImm( PPC_LWZ, R_SECOND, R_OPSTACK, -4 ); // dest
  1047. InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, -8 );
  1048. InstImmU( PPC_ADDI, R_EA, 0, v ); // count
  1049. // FIXME: range check
  1050. Inst( PPC_MTSPR, R_EA, 9, 0 ); // move to count register
  1051. Inst( PPC_ADD, R_TOP, R_TOP, R_MEMBASE );
  1052. InstImm( PPC_ADDI, R_TOP, R_TOP, -4 );
  1053. Inst( PPC_ADD, R_SECOND, R_SECOND, R_MEMBASE );
  1054. InstImm( PPC_ADDI, R_SECOND, R_SECOND, -4 );
  1055. InstImm( PPC_LWZU, R_EA, R_TOP, 4 ); // source
  1056. InstImm( PPC_STWU, R_EA, R_SECOND, 4 ); // dest
  1057. Inst( PPC_BC | 0xfff8 , 16, 0, 0 ); // loop
  1058. rtopped = qfalse;
  1059. break;
  1060. case OP_JUMP:
  1061. ltop(); // get value from opstack
  1062. InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, -4 );
  1063. Inst( PPC_RLWINM | ( 29 << 1 ), R_TOP, R_TOP, 2 );
  1064. // FIXME: range check
  1065. Inst( PPC_LWZX, R_TOP, R_TOP, R_INSTRUCTIONS );
  1066. Inst( PPC_MTSPR, R_TOP, 9, 0 ); // move to count register
  1067. Inst( PPC_BCCTR, 20, 0, 0 ); // jump to the count register
  1068. rtopped = qfalse;
  1069. break;
  1070. default:
  1071. Com_Error( ERR_DROP, "VM_CompilePPC: bad opcode %i at instruction %i, offset %i", op, instruction, pc );
  1072. }
  1073. pop0 = pop1;
  1074. pop1 = op;
  1075. }
  1076. Com_Printf( "VM file %s pass %d compiled to %i bytes of code\n", vm->name, (pass+1), compiledOfs*4 );
  1077. if ( pass == 0 ) {
  1078. // copy to an exact size buffer on the hunk
  1079. vm->codeLength = compiledOfs * 4;
  1080. vm->codeBase = Hunk_Alloc( vm->codeLength, h_low );
  1081. Com_Memcpy( vm->codeBase, buf, vm->codeLength );
  1082. Z_Free( buf );
  1083. // offset all the instruction pointers for the new location
  1084. for ( i = 0 ; i < header->instructionCount ; i++ ) {
  1085. vm->instructionPointers[i] += (int)vm->codeBase;
  1086. }
  1087. // go back over it in place now to fixup reletive jump targets
  1088. buf = (unsigned *)vm->codeBase;
  1089. }
  1090. }
  1091. Z_Free( jused );
  1092. }
  1093. /*
  1094. ==============
  1095. VM_CallCompiled
  1096. This function is called directly by the generated code
  1097. ==============
  1098. */
  1099. int VM_CallCompiled( vm_t *vm, int *args ) {
  1100. int stack[1024];
  1101. int programStack;
  1102. int stackOnEntry;
  1103. byte *image;
  1104. currentVM = vm;
  1105. // interpret the code
  1106. vm->currentlyInterpreting = qtrue;
  1107. // we might be called recursively, so this might not be the very top
  1108. programStack = vm->programStack;
  1109. stackOnEntry = programStack;
  1110. image = vm->dataBase;
  1111. // set up the stack frame
  1112. programStack -= 48;
  1113. *(int *)&image[ programStack + 44] = args[9];
  1114. *(int *)&image[ programStack + 40] = args[8];
  1115. *(int *)&image[ programStack + 36] = args[7];
  1116. *(int *)&image[ programStack + 32] = args[6];
  1117. *(int *)&image[ programStack + 28] = args[5];
  1118. *(int *)&image[ programStack + 24] = args[4];
  1119. *(int *)&image[ programStack + 20] = args[3];
  1120. *(int *)&image[ programStack + 16] = args[2];
  1121. *(int *)&image[ programStack + 12] = args[1];
  1122. *(int *)&image[ programStack + 8 ] = args[0];
  1123. *(int *)&image[ programStack + 4 ] = 0; // return stack
  1124. *(int *)&image[ programStack ] = -1; // will terminate the loop on return
  1125. // off we go into generated code...
  1126. // the PPC calling standard says the parms will all go into R3 - R11, so
  1127. // no special asm code is needed here
  1128. #ifdef __GNUC__
  1129. ((void(*)(int, int, int, int, int, int, int, int))(vm->codeBase))(
  1130. programStack, (int)&stack,
  1131. (int)image, vm->dataMask, (int)&AsmCall,
  1132. (int)vm->instructionPointers, vm->instructionPointersLength,
  1133. (int)vm );
  1134. #else
  1135. ((void(*)(int, int, int, int, int, int, int, int))(vm->codeBase))(
  1136. programStack, (int)&stack,
  1137. (int)image, vm->dataMask, *(int *)&AsmCall /* skip function pointer header */,
  1138. (int)vm->instructionPointers, vm->instructionPointersLength,
  1139. (int)vm );
  1140. #endif
  1141. vm->programStack = stackOnEntry;
  1142. vm->currentlyInterpreting = qfalse;
  1143. return stack[1];
  1144. }
  1145. /*
  1146. ==================
  1147. AsmCall
  1148. Put this at end of file because gcc messes up debug line numbers
  1149. ==================
  1150. */
  1151. #ifdef __GNUC__
  1152. void AsmCall( void ) {
  1153. asm (
  1154. // pop off the destination instruction
  1155. " lwz r12,0(r4) \n" // RG_TOP, 0(RG_OPSTACK)
  1156. " addi r4,r4,-4 \n" // RG_OPSTACK, RG_OPSTACK, -4 \n"
  1157. // see if it is a system trap
  1158. " cmpwi r12,0 \n" // RG_TOP, 0 \n"
  1159. " bc 12,0, systemTrap \n"
  1160. // calling another VM function, so lookup in instructionPointers
  1161. " slwi r12,r12,2 \n" // RG_TOP,RG_TOP,2
  1162. // FIXME: range check
  1163. " lwzx r12, r8, r12 \n" // RG_TOP, RG_INSTRUCTIONS(RG_TOP)
  1164. " mtctr r12 \n" // RG_TOP
  1165. );
  1166. #if defined(MACOS_X) && defined(__OPTIMIZE__)
  1167. // On Mac OS X, gcc doesn't push a frame when we are optimized, so trying to tear it down results in grave disorder.
  1168. #warning Mac OS X optimization on, not popping GCC AsmCall frame
  1169. #else
  1170. // Mac OS X Server and unoptimized compiles include a GCC AsmCall frame
  1171. asm (
  1172. " lwz r1,0(r1) \n" // pop off the GCC AsmCall frame
  1173. " lmw r30,-8(r1) \n"
  1174. );
  1175. #endif
  1176. asm (
  1177. " bcctr 20,0 \n" // when it hits a leave, it will branch to the current link register
  1178. // calling a system trap
  1179. "systemTrap: \n"
  1180. // convert to positive system call number
  1181. " subfic r12,r12,-1 \n"
  1182. // save all our registers, including the current link register
  1183. " mflr r13 \n" // RG_SECOND // copy off our link register
  1184. " addi r1,r1,-92 \n" // required 24 byets of linkage, 32 bytes of parameter, plus our saves
  1185. " stw r3,56(r1) \n" // RG_STACK, -36(REAL_STACK)
  1186. " stw r4,60(r1) \n" // RG_OPSTACK, 4(RG_REAL_STACK)
  1187. " stw r5,64(r1) \n" // RG_MEMBASE, 8(RG_REAL_STACK)
  1188. " stw r6,68(r1) \n" // RG_MEMMASK, 12(RG_REAL_STACK)
  1189. " stw r7,72(r1) \n" // RG_ASMCALL, 16(RG_REAL_STACK)
  1190. " stw r8,76(r1) \n" // RG_INSTRUCTIONS, 20(RG_REAL_STACK)
  1191. " stw r9,80(r1) \n" // RG_NUM_INSTRUCTIONS, 24(RG_REAL_STACK)
  1192. " stw r10,84(r1) \n" // RG_VM, 28(RG_REAL_STACK)
  1193. " stw r13,88(r1) \n" // RG_SECOND, 32(RG_REAL_STACK) // link register
  1194. // save the vm stack position to allow recursive VM entry
  1195. " addi r13,r3,-4 \n" // RG_TOP, RG_STACK, -4
  1196. " stw r13,0(r10) \n" //RG_TOP, VM_OFFSET_PROGRAM_STACK(RG_VM)
  1197. // save the system call number as the 0th parameter
  1198. " add r3,r3,r5 \n" // r3, RG_STACK, RG_MEMBASE // r3 is the first parameter to vm->systemCalls
  1199. " stwu r12,4(r3) \n" // RG_TOP, 4(r3)
  1200. // make the system call with the address of all the VM parms as a parameter
  1201. // vm->systemCalls( &parms )
  1202. " lwz r12,4(r10) \n" // RG_TOP, VM_OFFSET_SYSTEM_CALL(RG_VM)
  1203. " mtctr r12 \n" // RG_TOP
  1204. " bcctrl 20,0 \n"
  1205. " mr r12,r3 \n" // RG_TOP, r3
  1206. // pop our saved registers
  1207. " lwz r3,56(r1) \n" // RG_STACK, 0(RG_REAL_STACK)
  1208. " lwz r4,60(r1) \n" // RG_OPSTACK, 4(RG_REAL_STACK)
  1209. " lwz r5,64(r1) \n" // RG_MEMBASE, 8(RG_REAL_STACK)
  1210. " lwz r6,68(r1) \n" // RG_MEMMASK, 12(RG_REAL_STACK)
  1211. " lwz r7,72(r1) \n" // RG_ASMCALL, 16(RG_REAL_STACK)
  1212. " lwz r8,76(r1) \n" // RG_INSTRUCTIONS, 20(RG_REAL_STACK)
  1213. " lwz r9,80(r1) \n" // RG_NUM_INSTRUCTIONS, 24(RG_REAL_STACK)
  1214. " lwz r10,84(r1) \n" // RG_VM, 28(RG_REAL_STACK)
  1215. " lwz r13,88(r1) \n" // RG_SECOND, 32(RG_REAL_STACK)
  1216. " addi r1,r1,92 \n" // RG_REAL_STACK, RG_REAL_STACK, 36
  1217. // restore the old link register
  1218. " mtlr r13 \n" // RG_SECOND
  1219. // save off the return value
  1220. " stwu r12,4(r4) \n" // RG_TOP, 0(RG_OPSTACK)
  1221. // GCC adds its own prolog / epilog code
  1222. );
  1223. }
  1224. #else
  1225. // codewarrior version
  1226. void asm AsmCall( void ) {
  1227. // pop off the destination instruction
  1228. lwz r12,0(r4) // RG_TOP, 0(RG_OPSTACK)
  1229. addi r4,r4,-4 // RG_OPSTACK, RG_OPSTACK, -4
  1230. // see if it is a system trap
  1231. cmpwi r12,0 // RG_TOP, 0
  1232. bc 12,0, systemTrap
  1233. // calling another VM function, so lookup in instructionPointers
  1234. slwi r12,r12,2 // RG_TOP,RG_TOP,2
  1235. // FIXME: range check
  1236. lwzx r12, r8, r12 // RG_TOP, RG_INSTRUCTIONS(RG_TOP)
  1237. mtctr r12 // RG_TOP
  1238. bcctr 20,0 // when it hits a leave, it will branch to the current link register
  1239. // calling a system trap
  1240. systemTrap:
  1241. // convert to positive system call number
  1242. subfic r12,r12,-1
  1243. // save all our registers, including the current link register
  1244. mflr r13 // RG_SECOND // copy off our link register
  1245. addi r1,r1,-92 // required 24 byets of linkage, 32 bytes of parameter, plus our saves
  1246. stw r3,56(r1) // RG_STACK, -36(REAL_STACK)
  1247. stw r4,60(r1) // RG_OPSTACK, 4(RG_REAL_STACK)
  1248. stw r5,64(r1) // RG_MEMBASE, 8(RG_REAL_STACK)
  1249. stw r6,68(r1) // RG_MEMMASK, 12(RG_REAL_STACK)
  1250. stw r7,72(r1) // RG_ASMCALL, 16(RG_REAL_STACK)
  1251. stw r8,76(r1) // RG_INSTRUCTIONS, 20(RG_REAL_STACK)
  1252. stw r9,80(r1) // RG_NUM_INSTRUCTIONS, 24(RG_REAL_STACK)
  1253. stw r10,84(r1) // RG_VM, 28(RG_REAL_STACK)
  1254. stw r13,88(r1) // RG_SECOND, 32(RG_REAL_STACK) // link register
  1255. // save the vm stack position to allow recursive VM entry
  1256. addi r13,r3,-4 // RG_TOP, RG_STACK, -4
  1257. stw r13,0(r10) //RG_TOP, VM_OFFSET_PROGRAM_STACK(RG_VM)
  1258. // save the system call number as the 0th parameter
  1259. add r3,r3,r5 // r3, RG_STACK, RG_MEMBASE // r3 is the first parameter to vm->systemCalls
  1260. stwu r12,4(r3) // RG_TOP, 4(r3)
  1261. // make the system call with the address of all the VM parms as a parameter
  1262. // vm->systemCalls( &parms )
  1263. lwz r12,4(r10) // RG_TOP, VM_OFFSET_SYSTEM_CALL(RG_VM)
  1264. // perform macos cross fragment fixup crap
  1265. lwz r9,0(r12)
  1266. stw r2,52(r1) // save old TOC
  1267. lwz r2,4(r12)
  1268. mtctr r9 // RG_TOP
  1269. bcctrl 20,0
  1270. lwz r2,52(r1) // restore TOC
  1271. mr r12,r3 // RG_TOP, r3
  1272. // pop our saved registers
  1273. lwz r3,56(r1) // RG_STACK, 0(RG_REAL_STACK)
  1274. lwz r4,60(r1) // RG_OPSTACK, 4(RG_REAL_STACK)
  1275. lwz r5,64(r1) // RG_MEMBASE, 8(RG_REAL_STACK)
  1276. lwz r6,68(r1) // RG_MEMMASK, 12(RG_REAL_STACK)
  1277. lwz r7,72(r1) // RG_ASMCALL, 16(RG_REAL_STACK)
  1278. lwz r8,76(r1) // RG_INSTRUCTIONS, 20(RG_REAL_STACK)
  1279. lwz r9,80(r1) // RG_NUM_INSTRUCTIONS, 24(RG_REAL_STACK)
  1280. lwz r10,84(r1) // RG_VM, 28(RG_REAL_STACK)
  1281. lwz r13,88(r1) // RG_SECOND, 32(RG_REAL_STACK)
  1282. addi r1,r1,92 // RG_REAL_STACK, RG_REAL_STACK, 36
  1283. // restore the old link register
  1284. mtlr r13 // RG_SECOND
  1285. // save off the return value
  1286. stwu r12,4(r4) // RG_TOP, 0(RG_OPSTACK)
  1287. blr
  1288. }
  1289. #endif