vm_ppc_new.c 66 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120
  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. #define DEBUG_VM 0
  23. #if DEBUG_VM
  24. static char *opnames[256] = {
  25. "OP_UNDEF",
  26. "OP_IGNORE",
  27. "OP_BREAK",
  28. "OP_ENTER",
  29. "OP_LEAVE",
  30. "OP_CALL",
  31. "OP_PUSH",
  32. "OP_POP",
  33. "OP_CONST",
  34. "OP_LOCAL",
  35. "OP_JUMP",
  36. //-------------------
  37. "OP_EQ",
  38. "OP_NE",
  39. "OP_LTI",
  40. "OP_LEI",
  41. "OP_GTI",
  42. "OP_GEI",
  43. "OP_LTU",
  44. "OP_LEU",
  45. "OP_GTU",
  46. "OP_GEU",
  47. "OP_EQF",
  48. "OP_NEF",
  49. "OP_LTF",
  50. "OP_LEF",
  51. "OP_GTF",
  52. "OP_GEF",
  53. //-------------------
  54. "OP_LOAD1",
  55. "OP_LOAD2",
  56. "OP_LOAD4",
  57. "OP_STORE1",
  58. "OP_STORE2",
  59. "OP_STORE4",
  60. "OP_ARG",
  61. "OP_BLOCK_COPY",
  62. //-------------------
  63. "OP_SEX8",
  64. "OP_SEX16",
  65. "OP_NEGI",
  66. "OP_ADD",
  67. "OP_SUB",
  68. "OP_DIVI",
  69. "OP_DIVU",
  70. "OP_MODI",
  71. "OP_MODU",
  72. "OP_MULI",
  73. "OP_MULU",
  74. "OP_BAND",
  75. "OP_BOR",
  76. "OP_BXOR",
  77. "OP_BCOM",
  78. "OP_LSH",
  79. "OP_RSHI",
  80. "OP_RSHU",
  81. "OP_NEGF",
  82. "OP_ADDF",
  83. "OP_SUBF",
  84. "OP_DIVF",
  85. "OP_MULF",
  86. "OP_CVIF",
  87. "OP_CVFI"
  88. };
  89. #endif
  90. typedef enum {
  91. R_REAL_STACK = 1,
  92. // registers 3-11 are the parameter passing registers
  93. // state
  94. R_STACK = 3, // local
  95. R_OPSTACK, // global
  96. // constants
  97. R_MEMBASE, // global
  98. R_MEMMASK,
  99. R_ASMCALL, // global
  100. R_INSTRUCTIONS, // global
  101. R_NUM_INSTRUCTIONS, // global
  102. R_CVM, // currentVM
  103. // temps
  104. R_TOP = 11,
  105. R_SECOND = 12,
  106. R_EA = 2 // effective address calculation
  107. } regNums_t;
  108. #define RG_REAL_STACK r1
  109. #define RG_STACK r3
  110. #define RG_OPSTACK r4
  111. #define RG_MEMBASE r5
  112. #define RG_MEMMASK r6
  113. #define RG_ASMCALL r7
  114. #define RG_INSTRUCTIONS r8
  115. #define RG_NUM_INSTRUCTIONS r9
  116. #define RG_CVM r10
  117. #define RG_TOP r12
  118. #define RG_SECOND r13
  119. #define RG_EA r14
  120. // The deepest value I saw in the Quake3 games was 9.
  121. #define OP_STACK_MAX_DEPTH 12
  122. // These are all volatile and thus must be saved
  123. // upon entry to the VM code.
  124. static int opStackIntRegisters[OP_STACK_MAX_DEPTH] =
  125. {
  126. 16, 17, 18, 19,
  127. 20, 21, 22, 23,
  128. 24, 25, 26, 27
  129. };
  130. static unsigned int *opStackLoadInstructionAddr[OP_STACK_MAX_DEPTH];
  131. // We use different registers for the floating point
  132. // operand stack (these are volatile in the PPC ABI)
  133. static int opStackFloatRegisters[OP_STACK_MAX_DEPTH] =
  134. {
  135. 0, 1, 2, 3,
  136. 4, 5, 6, 7,
  137. 8, 9, 10, 11
  138. };
  139. static int opStackRegType[OP_STACK_MAX_DEPTH] =
  140. {
  141. 0, 0, 0, 0,
  142. 0, 0, 0, 0,
  143. 0, 0, 0, 0
  144. };
  145. // this doesn't have the low order bits set for instructions i'm not using...
  146. typedef enum {
  147. PPC_TDI = 0x08000000,
  148. PPC_TWI = 0x0c000000,
  149. PPC_MULLI = 0x1c000000,
  150. PPC_SUBFIC = 0x20000000,
  151. PPC_CMPI = 0x28000000,
  152. PPC_CMPLI = 0x2c000000,
  153. PPC_ADDIC = 0x30000000,
  154. PPC_ADDIC_ = 0x34000000,
  155. PPC_ADDI = 0x38000000,
  156. PPC_ADDIS = 0x3c000000,
  157. PPC_BC = 0x40000000,
  158. PPC_SC = 0x44000000,
  159. PPC_B = 0x48000000,
  160. PPC_MCRF = 0x4c000000,
  161. PPC_BCLR = 0x4c000020,
  162. PPC_RFID = 0x4c000000,
  163. PPC_CRNOR = 0x4c000000,
  164. PPC_RFI = 0x4c000000,
  165. PPC_CRANDC = 0x4c000000,
  166. PPC_ISYNC = 0x4c000000,
  167. PPC_CRXOR = 0x4c000000,
  168. PPC_CRNAND = 0x4c000000,
  169. PPC_CREQV = 0x4c000000,
  170. PPC_CRORC = 0x4c000000,
  171. PPC_CROR = 0x4c000000,
  172. //------------
  173. PPC_BCCTR = 0x4c000420,
  174. PPC_RLWIMI = 0x50000000,
  175. PPC_RLWINM = 0x54000000,
  176. PPC_RLWNM = 0x5c000000,
  177. PPC_ORI = 0x60000000,
  178. PPC_ORIS = 0x64000000,
  179. PPC_XORI = 0x68000000,
  180. PPC_XORIS = 0x6c000000,
  181. PPC_ANDI_ = 0x70000000,
  182. PPC_ANDIS_ = 0x74000000,
  183. PPC_RLDICL = 0x78000000,
  184. PPC_RLDICR = 0x78000000,
  185. PPC_RLDIC = 0x78000000,
  186. PPC_RLDIMI = 0x78000000,
  187. PPC_RLDCL = 0x78000000,
  188. PPC_RLDCR = 0x78000000,
  189. PPC_CMP = 0x7c000000,
  190. PPC_TW = 0x7c000000,
  191. PPC_SUBFC = 0x7c000010,
  192. PPC_MULHDU = 0x7c000000,
  193. PPC_ADDC = 0x7c000014,
  194. PPC_MULHWU = 0x7c000000,
  195. PPC_MFCR = 0x7c000000,
  196. PPC_LWAR = 0x7c000000,
  197. PPC_LDX = 0x7c000000,
  198. PPC_LWZX = 0x7c00002e,
  199. PPC_SLW = 0x7c000030,
  200. PPC_CNTLZW = 0x7c000000,
  201. PPC_SLD = 0x7c000000,
  202. PPC_AND = 0x7c000038,
  203. PPC_CMPL = 0x7c000040,
  204. PPC_SUBF = 0x7c000050,
  205. PPC_LDUX = 0x7c000000,
  206. //------------
  207. PPC_DCBST = 0x7c000000,
  208. PPC_LWZUX = 0x7c00006c,
  209. PPC_CNTLZD = 0x7c000000,
  210. PPC_ANDC = 0x7c000000,
  211. PPC_TD = 0x7c000000,
  212. PPC_MULHD = 0x7c000000,
  213. PPC_MULHW = 0x7c000000,
  214. PPC_MTSRD = 0x7c000000,
  215. PPC_MFMSR = 0x7c000000,
  216. PPC_LDARX = 0x7c000000,
  217. PPC_DCBF = 0x7c000000,
  218. PPC_LBZX = 0x7c0000ae,
  219. PPC_NEG = 0x7c000000,
  220. PPC_MTSRDIN = 0x7c000000,
  221. PPC_LBZUX = 0x7c000000,
  222. PPC_NOR = 0x7c0000f8,
  223. PPC_SUBFE = 0x7c000000,
  224. PPC_ADDE = 0x7c000000,
  225. PPC_MTCRF = 0x7c000000,
  226. PPC_MTMSR = 0x7c000000,
  227. PPC_STDX = 0x7c000000,
  228. PPC_STWCX_ = 0x7c000000,
  229. PPC_STWX = 0x7c00012e,
  230. PPC_MTMSRD = 0x7c000000,
  231. PPC_STDUX = 0x7c000000,
  232. PPC_STWUX = 0x7c00016e,
  233. PPC_SUBFZE = 0x7c000000,
  234. PPC_ADDZE = 0x7c000000,
  235. PPC_MTSR = 0x7c000000,
  236. PPC_STDCX_ = 0x7c000000,
  237. PPC_STBX = 0x7c0001ae,
  238. PPC_SUBFME = 0x7c000000,
  239. PPC_MULLD = 0x7c000000,
  240. //------------
  241. PPC_ADDME = 0x7c000000,
  242. PPC_MULLW = 0x7c0001d6,
  243. PPC_MTSRIN = 0x7c000000,
  244. PPC_DCBTST = 0x7c000000,
  245. PPC_STBUX = 0x7c000000,
  246. PPC_ADD = 0x7c000214,
  247. PPC_DCBT = 0x7c000000,
  248. PPC_LHZX = 0x7c00022e,
  249. PPC_EQV = 0x7c000000,
  250. PPC_TLBIE = 0x7c000000,
  251. PPC_ECIWX = 0x7c000000,
  252. PPC_LHZUX = 0x7c000000,
  253. PPC_XOR = 0x7c000278,
  254. PPC_MFSPR = 0x7c0002a6,
  255. PPC_LWAX = 0x7c000000,
  256. PPC_LHAX = 0x7c000000,
  257. PPC_TLBIA = 0x7c000000,
  258. PPC_MFTB = 0x7c000000,
  259. PPC_LWAUX = 0x7c000000,
  260. PPC_LHAUX = 0x7c000000,
  261. PPC_STHX = 0x7c00032e,
  262. PPC_ORC = 0x7c000338,
  263. PPC_SRADI = 0x7c000000,
  264. PPC_SLBIE = 0x7c000000,
  265. PPC_ECOWX = 0x7c000000,
  266. PPC_STHUX = 0x7c000000,
  267. PPC_OR = 0x7c000378,
  268. PPC_DIVDU = 0x7c000000,
  269. PPC_DIVWU = 0x7c000396,
  270. PPC_MTSPR = 0x7c0003a6,
  271. PPC_DCBI = 0x7c000000,
  272. PPC_NAND = 0x7c000000,
  273. PPC_DIVD = 0x7c000000,
  274. //------------
  275. PPC_DIVW = 0x7c0003d6,
  276. PPC_SLBIA = 0x7c000000,
  277. PPC_MCRXR = 0x7c000000,
  278. PPC_LSWX = 0x7c000000,
  279. PPC_LWBRX = 0x7c000000,
  280. PPC_LFSX = 0x7c00042e,
  281. PPC_SRW = 0x7c000430,
  282. PPC_SRD = 0x7c000000,
  283. PPC_TLBSYNC = 0x7c000000,
  284. PPC_LFSUX = 0x7c000000,
  285. PPC_MFSR = 0x7c000000,
  286. PPC_LSWI = 0x7c000000,
  287. PPC_SYNC = 0x7c000000,
  288. PPC_LFDX = 0x7c000000,
  289. PPC_LFDUX = 0x7c000000,
  290. PPC_MFSRIN = 0x7c000000,
  291. PPC_STSWX = 0x7c000000,
  292. PPC_STWBRX = 0x7c000000,
  293. PPC_STFSX = 0x7c00052e,
  294. PPC_STFSUX = 0x7c000000,
  295. PPC_STSWI = 0x7c000000,
  296. PPC_STFDX = 0x7c000000,
  297. PPC_DCBA = 0x7c000000,
  298. PPC_STFDUX = 0x7c000000,
  299. PPC_LHBRX = 0x7c000000,
  300. PPC_SRAW = 0x7c000630,
  301. PPC_SRAD = 0x7c000000,
  302. PPC_SRAWI = 0x7c000000,
  303. PPC_EIEIO = 0x7c000000,
  304. PPC_STHBRX = 0x7c000000,
  305. PPC_EXTSH = 0x7c000734,
  306. PPC_EXTSB = 0x7c000774,
  307. PPC_ICBI = 0x7c000000,
  308. //------------
  309. PPC_STFIWX = 0x7c0007ae,
  310. PPC_EXTSW = 0x7c000000,
  311. PPC_DCBZ = 0x7c000000,
  312. PPC_LWZ = 0x80000000,
  313. PPC_LWZU = 0x84000000,
  314. PPC_LBZ = 0x88000000,
  315. PPC_LBZU = 0x8c000000,
  316. PPC_STW = 0x90000000,
  317. PPC_STWU = 0x94000000,
  318. PPC_STB = 0x98000000,
  319. PPC_STBU = 0x9c000000,
  320. PPC_LHZ = 0xa0000000,
  321. PPC_LHZU = 0xa4000000,
  322. PPC_LHA = 0xa8000000,
  323. PPC_LHAU = 0xac000000,
  324. PPC_STH = 0xb0000000,
  325. PPC_STHU = 0xb4000000,
  326. PPC_LMW = 0xb8000000,
  327. PPC_STMW = 0xbc000000,
  328. PPC_LFS = 0xc0000000,
  329. PPC_LFSU = 0xc4000000,
  330. PPC_LFD = 0xc8000000,
  331. PPC_LFDU = 0xcc000000,
  332. PPC_STFS = 0xd0000000,
  333. PPC_STFSU = 0xd4000000,
  334. PPC_STFD = 0xd8000000,
  335. PPC_STFDU = 0xdc000000,
  336. PPC_LD = 0xe8000000,
  337. PPC_LDU = 0xe8000001,
  338. PPC_LWA = 0xe8000002,
  339. PPC_FDIVS = 0xec000024,
  340. PPC_FSUBS = 0xec000028,
  341. PPC_FADDS = 0xec00002a,
  342. //------------
  343. PPC_FSQRTS = 0xec000000,
  344. PPC_FRES = 0xec000000,
  345. PPC_FMULS = 0xec000032,
  346. PPC_FMSUBS = 0xec000000,
  347. PPC_FMADDS = 0xec000000,
  348. PPC_FNMSUBS = 0xec000000,
  349. PPC_FNMADDS = 0xec000000,
  350. PPC_STD = 0xf8000000,
  351. PPC_STDU = 0xf8000001,
  352. PPC_FCMPU = 0xfc000000,
  353. PPC_FRSP = 0xfc000018,
  354. PPC_FCTIW = 0xfc000000,
  355. PPC_FCTIWZ = 0xfc00001e,
  356. PPC_FDIV = 0xfc000000,
  357. PPC_FSUB = 0xfc000028,
  358. PPC_FADD = 0xfc000000,
  359. PPC_FSQRT = 0xfc000000,
  360. PPC_FSEL = 0xfc000000,
  361. PPC_FMUL = 0xfc000000,
  362. PPC_FRSQRTE = 0xfc000000,
  363. PPC_FMSUB = 0xfc000000,
  364. PPC_FMADD = 0xfc000000,
  365. PPC_FNMSUB = 0xfc000000,
  366. PPC_FNMADD = 0xfc000000,
  367. PPC_FCMPO = 0xfc000000,
  368. PPC_MTFSB1 = 0xfc000000,
  369. PPC_FNEG = 0xfc000050,
  370. PPC_MCRFS = 0xfc000000,
  371. PPC_MTFSB0 = 0xfc000000,
  372. PPC_FMR = 0xfc000000,
  373. PPC_MTFSFI = 0xfc000000,
  374. PPC_FNABS = 0xfc000000,
  375. PPC_FABS = 0xfc000000,
  376. //------------
  377. PPC_MFFS = 0xfc000000,
  378. PPC_MTFSF = 0xfc000000,
  379. PPC_FCTID = 0xfc000000,
  380. PPC_FCTIDZ = 0xfc000000,
  381. PPC_FCFID = 0xfc000000
  382. } ppcOpcodes_t;
  383. // the newly generated code
  384. static unsigned *buf;
  385. static int compiledOfs; // in dwords
  386. static int pass;
  387. // fromt the original bytecode
  388. static byte *code;
  389. static int pc;
  390. void AsmCall( void );
  391. double itofConvert[2];
  392. static int Constant4( void ) {
  393. int v;
  394. v = code[pc] | (code[pc+1]<<8) | (code[pc+2]<<16) | (code[pc+3]<<24);
  395. pc += 4;
  396. return v;
  397. }
  398. static int Constant1( void ) {
  399. int v;
  400. v = code[pc];
  401. pc += 1;
  402. return v;
  403. }
  404. static void Emit4( char *opname, int i ) {
  405. #if DEBUG_VM
  406. if(pass == 1)
  407. printf("\t\t\t%p %s\t%08lx\n",&buf[compiledOfs],opname,i&0x3ffffff);
  408. #endif
  409. buf[ compiledOfs ] = i;
  410. compiledOfs++;
  411. }
  412. static void Inst( char *opname, int opcode, int destReg, int aReg, int bReg ) {
  413. unsigned r;
  414. #if DEBUG_VM
  415. if(pass == 1)
  416. printf("\t\t\t%p %s\tr%d,r%d,r%d\n",&buf[compiledOfs],opname,destReg,aReg,bReg);
  417. #endif
  418. r = opcode | ( destReg << 21 ) | ( aReg << 16 ) | ( bReg << 11 ) ;
  419. buf[ compiledOfs ] = r;
  420. compiledOfs++;
  421. }
  422. static void Inst4( char *opname, int opcode, int destReg, int aReg, int bReg, int cReg ) {
  423. unsigned r;
  424. #if DEBUG_VM
  425. if(pass == 1)
  426. printf("\t\t\t%p %s\tr%d,r%d,r%d,r%d\n",&buf[compiledOfs],opname,destReg,aReg,bReg,cReg);
  427. #endif
  428. r = opcode | ( destReg << 21 ) | ( aReg << 16 ) | ( bReg << 11 ) | ( cReg << 6 );
  429. buf[ compiledOfs ] = r;
  430. compiledOfs++;
  431. }
  432. static void InstImm( char *opname, int opcode, int destReg, int aReg, int immediate ) {
  433. unsigned r;
  434. if ( immediate > 32767 || immediate < -32768 ) {
  435. Com_Error( ERR_FATAL, "VM_Compile: immediate value %i out of range, opcode %x,%d,%d", immediate, opcode, destReg, aReg );
  436. }
  437. #if DEBUG_VM
  438. if(pass == 1)
  439. printf("\t\t\t%p %s\tr%d,r%d,0x%x\n",&buf[compiledOfs],opname,destReg,aReg,immediate);
  440. #endif
  441. r = opcode | ( destReg << 21 ) | ( aReg << 16 ) | ( immediate & 0xffff );
  442. buf[ compiledOfs ] = r;
  443. compiledOfs++;
  444. }
  445. static void InstImmU( char *opname, int opcode, int destReg, int aReg, int immediate ) {
  446. unsigned r;
  447. if ( immediate > 0xffff || immediate < 0 ) {
  448. Com_Error( ERR_FATAL, "VM_Compile: immediate value %i out of range", immediate );
  449. }
  450. #if DEBUG_VM
  451. if(pass == 1)
  452. printf("\t\t\t%p %s\tr%d,r%d,0x%x\n",&buf[compiledOfs],opname,destReg,aReg,immediate);
  453. #endif
  454. r = opcode | ( destReg << 21 ) | ( aReg << 16 ) | ( immediate & 0xffff );
  455. buf[ compiledOfs ] = r;
  456. compiledOfs++;
  457. }
  458. static int pop0, pop1, oc0, oc1;
  459. static vm_t *tvm;
  460. static int instruction;
  461. static byte *jused;
  462. static void ltop() {
  463. // if (rtopped == qfalse) {
  464. // InstImm( PPC_LWZ, R_TOP, R_OPSTACK, 0 ); // get value from opstack
  465. // }
  466. }
  467. static void ltopandsecond() {
  468. #if 0
  469. if (pass>=0 && buf[compiledOfs-1] == (PPC_STWU | R_TOP<<21 | R_OPSTACK<<16 | 4 ) && jused[instruction]==0 ) {
  470. compiledOfs--;
  471. if (!pass) {
  472. tvm->instructionPointers[instruction] = compiledOfs * 4;
  473. }
  474. InstImm( PPC_LWZ, R_SECOND, R_OPSTACK, 0 ); // get value from opstack
  475. InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, -4 );
  476. } else if (pass>=0 && buf[compiledOfs-1] == (PPC_STW | R_TOP<<21 | R_OPSTACK<<16 | 0 ) && jused[instruction]==0 ) {
  477. compiledOfs--;
  478. if (!pass) {
  479. tvm->instructionPointers[instruction] = compiledOfs * 4;
  480. }
  481. InstImm( PPC_LWZ, R_SECOND, R_OPSTACK, -4 ); // get value from opstack
  482. InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, -8 );
  483. } else {
  484. ltop(); // get value from opstack
  485. InstImm( PPC_LWZ, R_SECOND, R_OPSTACK, -4 ); // get value from opstack
  486. InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, -8 );
  487. }
  488. rtopped = qfalse;
  489. #endif
  490. }
  491. static void spillOpStack(int depth)
  492. {
  493. // Store out each register on the operand stack to it's correct location.
  494. int i;
  495. for(i = 0; i < depth; i++)
  496. {
  497. assert(opStackRegType[i]);
  498. assert(opStackRegType[i] == 1);
  499. switch(opStackRegType[i])
  500. {
  501. case 1: // Integer register
  502. InstImm( "stw", PPC_STW, opStackIntRegisters[i], R_OPSTACK, i*4+4);
  503. break;
  504. case 2: // Float register
  505. InstImm( "stfs", PPC_STFS, opStackFloatRegisters[i], R_OPSTACK, i*4+4);
  506. break;
  507. }
  508. opStackRegType[i] = 0;
  509. }
  510. }
  511. static void loadOpStack(int depth)
  512. {
  513. // Back off operand stack pointer and reload all operands.
  514. // InstImm( "addi", PPC_ADDI, R_OPSTACK, R_OPSTACK, -(depth)*4 );
  515. int i;
  516. for(i = 0; i < depth; i++)
  517. {
  518. assert(opStackRegType[i] == 0);
  519. // For now we're stuck reloading everything as an integer.
  520. opStackLoadInstructionAddr[i] = &buf[compiledOfs];
  521. InstImm( "lwz", PPC_LWZ, opStackIntRegisters[i], R_OPSTACK, i*4+4);
  522. opStackRegType[i] = 1;
  523. }
  524. }
  525. static void makeInteger(int depth)
  526. {
  527. // This should really never be necessary...
  528. assert(opStackRegType[depth] == 1);
  529. //assert(opStackRegType[depth] == 2);
  530. if(opStackRegType[depth] == 2)
  531. {
  532. unsigned instruction;
  533. assert(opStackLoadInstructionAddr[depth]);
  534. printf("patching float load at %p to int load\n",opStackLoadInstructionAddr[depth]);
  535. // Repatch load instruction to use LFS instead of LWZ
  536. instruction = *opStackLoadInstructionAddr[depth];
  537. instruction &= ~PPC_LFSX;
  538. instruction |= PPC_LWZX;
  539. *opStackLoadInstructionAddr[depth] = instruction;
  540. opStackLoadInstructionAddr[depth] = 0;
  541. opStackRegType[depth] = 1;
  542. #if 0
  543. InstImm( "stfs", PPC_STFS, opStackFloatRegisters[depth], R_OPSTACK, depth*4+4);
  544. // For XXX make sure we force enough NOPs to get the load into
  545. // another dispatch group to avoid pipeline flush.
  546. Inst( "ori", PPC_ORI, 0, 0, 0 );
  547. Inst( "ori", PPC_ORI, 0, 0, 0 );
  548. Inst( "ori", PPC_ORI, 0, 0, 0 );
  549. Inst( "ori", PPC_ORI, 0, 0, 0 );
  550. InstImm( "lwz", PPC_LWZ, opStackIntRegisters[depth], R_OPSTACK, depth*4+4);
  551. opStackRegType[depth] = 1;
  552. #endif
  553. }
  554. }
  555. static void makeFloat(int depth)
  556. {
  557. //assert(opStackRegType[depth] == 1);
  558. if(opStackRegType[depth] == 1)
  559. {
  560. unsigned instruction;
  561. unsigned destReg, aReg, bReg, imm;
  562. if(opStackLoadInstructionAddr[depth])
  563. {
  564. // Repatch load instruction to use LFS instead of LWZ
  565. instruction = *opStackLoadInstructionAddr[depth];
  566. // Figure out if it's LWZ or LWZX
  567. if((instruction & 0xfc000000) == PPC_LWZ)
  568. {
  569. //printf("patching LWZ at %p to LFS at depth %ld\n",opStackLoadInstructionAddr[depth],depth);
  570. //printf("old instruction: %08lx\n",instruction);
  571. // Extract registers
  572. destReg = (instruction >> 21) & 31;
  573. aReg = (instruction >> 16) & 31;
  574. imm = instruction & 0xffff;
  575. // Calculate correct FP register to use.
  576. // THIS ASSUMES REGISTER USAGE FOR THE STACK IS n, n+1, n+2, etc!
  577. //printf("old dest: %ld\n",destReg);
  578. destReg = (destReg - opStackIntRegisters[0]) + opStackFloatRegisters[0];
  579. instruction = PPC_LFS | ( destReg << 21 ) | ( aReg << 16 ) | imm ;
  580. //printf("new dest: %ld\n",destReg);
  581. //printf("new instruction: %08lx\n",instruction);
  582. }
  583. else
  584. {
  585. //printf("patching LWZX at %p to LFSX at depth %ld\n",opStackLoadInstructionAddr[depth],depth);
  586. //printf("old instruction: %08lx\n",instruction);
  587. // Extract registers
  588. destReg = (instruction >> 21) & 31;
  589. aReg = (instruction >> 16) & 31;
  590. bReg = (instruction >> 11) & 31;
  591. // Calculate correct FP register to use.
  592. // THIS ASSUMES REGISTER USAGE FOR THE STACK IS n, n+1, n+2, etc!
  593. //printf("old dest: %ld\n",destReg);
  594. destReg = (destReg - opStackIntRegisters[0]) + opStackFloatRegisters[0];
  595. instruction = PPC_LFSX | ( destReg << 21 ) | ( aReg << 16 ) | ( bReg << 11 ) ;
  596. //printf("new dest: %ld\n",destReg);
  597. //printf("new instruction: %08lx\n",instruction);
  598. }
  599. *opStackLoadInstructionAddr[depth] = instruction;
  600. opStackLoadInstructionAddr[depth] = 0;
  601. }
  602. else
  603. {
  604. //printf("doing float constant load at %p for depth %ld\n",&buf[compiledOfs],depth);
  605. // It was likely loaded as a constant so we have to save/load it. A more
  606. // interesting implementation might be to generate code to do a "PC relative"
  607. // load from the VM code region.
  608. InstImm( "stw", PPC_STW, opStackIntRegisters[depth], R_OPSTACK, depth*4+4);
  609. // For XXX make sure we force enough NOPs to get the load into
  610. // another dispatch group to avoid pipeline flush.
  611. Inst( "ori", PPC_ORI, 0, 0, 0 );
  612. Inst( "ori", PPC_ORI, 0, 0, 0 );
  613. Inst( "ori", PPC_ORI, 0, 0, 0 );
  614. Inst( "ori", PPC_ORI, 0, 0, 0 );
  615. InstImm( "lfs", PPC_LFS, opStackFloatRegisters[depth], R_OPSTACK, depth*4+4);
  616. }
  617. opStackRegType[depth] = 2;
  618. }
  619. }
  620. // TJW: Unused
  621. #if 0
  622. static void fltop() {
  623. if (rtopped == qfalse) {
  624. InstImm( PPC_LFS, R_TOP, R_OPSTACK, 0 ); // get value from opstack
  625. }
  626. }
  627. #endif
  628. #if 0
  629. static void fltopandsecond() {
  630. InstImm( PPC_LFS, R_TOP, R_OPSTACK, 0 ); // get value from opstack
  631. InstImm( PPC_LFS, R_SECOND, R_OPSTACK, -4 ); // get value from opstack
  632. InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, -8 );
  633. rtopped = qfalse;
  634. return;
  635. }
  636. #endif
  637. #define assertInteger(depth) assert(opStackRegType[depth] == 1)
  638. /*
  639. =================
  640. VM_Compile
  641. =================
  642. */
  643. void VM_Compile( vm_t *vm, vmHeader_t *header ) {
  644. int op;
  645. int maxLength;
  646. int v;
  647. int i;
  648. int opStackDepth;
  649. int mainFunction;
  650. // set up the into-to-float variables
  651. ((int *)itofConvert)[0] = 0x43300000;
  652. ((int *)itofConvert)[1] = 0x80000000;
  653. ((int *)itofConvert)[2] = 0x43300000;
  654. // allocate a very large temp buffer, we will shrink it later
  655. maxLength = header->codeLength * 8;
  656. buf = Z_Malloc( maxLength );
  657. jused = Z_Malloc(header->instructionCount + 2);
  658. Com_Memset(jused, 0, header->instructionCount+2);
  659. // compile everything twice, so the second pass will have valid instruction
  660. // pointers for branches
  661. for ( pass = -1 ; pass < 2 ; pass++ ) {
  662. // translate all instructions
  663. pc = 0;
  664. mainFunction = 0;
  665. opStackDepth = 0;
  666. pop0 = 343545;
  667. pop1 = 2443545;
  668. oc0 = -2343535;
  669. oc1 = 24353454;
  670. tvm = vm;
  671. code = (byte *)header + header->codeOffset;
  672. compiledOfs = 0;
  673. #ifndef __GNUC__
  674. // metrowerks seems to require this header in front of functions
  675. Emit4( (int)(buf+2) );
  676. Emit4( 0 );
  677. #endif
  678. for ( instruction = 0 ; instruction < header->instructionCount ; instruction++ ) {
  679. if ( compiledOfs*4 > maxLength - 16 ) {
  680. Com_Error( ERR_DROP, "VM_Compile: maxLength exceeded" );
  681. }
  682. op = code[ pc ];
  683. if ( !pass ) {
  684. vm->instructionPointers[ instruction ] = compiledOfs * 4;
  685. }
  686. pc++;
  687. switch ( op ) {
  688. case 0:
  689. break;
  690. case OP_BREAK:
  691. #if DEBUG_VM
  692. if(pass == 1)
  693. printf("%08lx BREAK\n",instruction);
  694. #endif
  695. InstImmU( "addi", PPC_ADDI, R_TOP, 0, 0 );
  696. InstImm( "lwz", PPC_LWZ, R_TOP, R_TOP, 0 ); // *(int *)0 to crash to debugger
  697. break;
  698. case OP_ENTER:
  699. opStackDepth = 0;
  700. v = Constant4();
  701. #if DEBUG_VM
  702. if(pass == 1)
  703. printf("%08x ENTER\t%04x\n",instruction,v);
  704. #endif
  705. opStackRegType[opStackDepth] = 0;
  706. mainFunction++;
  707. if(mainFunction == 1)
  708. {
  709. // Main VM entry point is the first thing we compile, so save off operand stack
  710. // registers here. This avoids issues with trying to trick the native compiler
  711. // into doing it, and properly matches the PowerPC ABI
  712. InstImm( "addi", PPC_ADDI, R_REAL_STACK, R_REAL_STACK, -OP_STACK_MAX_DEPTH*4 ); // sub R_STACK, R_STACK, imm
  713. for(i = 0; i < OP_STACK_MAX_DEPTH; i++)
  714. InstImm( "stw", PPC_STW, opStackIntRegisters[i], R_REAL_STACK, i*4);
  715. }
  716. InstImm( "addi", PPC_ADDI, R_STACK, R_STACK, -v ); // sub R_STACK, R_STACK, imm
  717. break;
  718. case OP_CONST:
  719. v = Constant4();
  720. #if DEBUG_VM
  721. if(pass == 1)
  722. printf("%08x CONST\t%08x\n",instruction,v);
  723. #endif
  724. opStackLoadInstructionAddr[opStackDepth] = 0;
  725. if ( v < 32768 && v >= -32768 ) {
  726. InstImmU( "addi", PPC_ADDI, opStackIntRegisters[opStackDepth], 0, v & 0xffff );
  727. } else {
  728. InstImmU( "addis", PPC_ADDIS, opStackIntRegisters[opStackDepth], 0, (v >> 16)&0xffff );
  729. if ( v & 0xffff ) {
  730. InstImmU( "ori", PPC_ORI, opStackIntRegisters[opStackDepth], opStackIntRegisters[opStackDepth], v & 0xffff );
  731. }
  732. }
  733. opStackRegType[opStackDepth] = 1;
  734. opStackDepth += 1;
  735. if (code[pc] == OP_JUMP) {
  736. jused[v] = 1;
  737. }
  738. break;
  739. case OP_LOCAL:
  740. oc1 = Constant4();
  741. #if DEBUG_VM
  742. if(pass == 1)
  743. printf("%08x LOCAL\t%08x\n",instruction,oc1);
  744. #endif
  745. if (code[pc] == OP_LOAD4 || code[pc] == OP_LOAD2 || code[pc] == OP_LOAD1) {
  746. oc1 &= vm->dataMask;
  747. }
  748. InstImm( "addi", PPC_ADDI, opStackIntRegisters[opStackDepth], R_STACK, oc1 );
  749. opStackRegType[opStackDepth] = 1;
  750. opStackLoadInstructionAddr[opStackDepth] = 0;
  751. opStackDepth += 1;
  752. break;
  753. case OP_ARG:
  754. v = Constant1();
  755. #if DEBUG_VM
  756. if(pass == 1)
  757. printf("%08x ARG \t%08x\n",instruction,v);
  758. #endif
  759. InstImm( "addi", PPC_ADDI, R_EA, R_STACK, v ); // location to put it
  760. if(opStackRegType[opStackDepth-1] == 1)
  761. Inst( "stwx", PPC_STWX, opStackIntRegisters[opStackDepth-1], R_EA, R_MEMBASE );
  762. else
  763. Inst( "stfsx", PPC_STFSX, opStackFloatRegisters[opStackDepth-1], R_EA, R_MEMBASE );
  764. opStackRegType[opStackDepth-1] = 0;
  765. opStackLoadInstructionAddr[opStackDepth-1] = 0;
  766. opStackDepth -= 1;
  767. break;
  768. case OP_CALL:
  769. #if DEBUG_VM
  770. if(pass == 1)
  771. printf("%08x CALL\n",instruction);
  772. #endif
  773. assertInteger(opStackDepth-1);
  774. assert(opStackDepth > 0);
  775. Inst( "mflr", PPC_MFSPR, R_SECOND, 8, 0 ); // move from link register
  776. InstImm( "stwu", PPC_STWU, R_SECOND, R_REAL_STACK, -16 ); // save off the old return address
  777. // Spill operand stack registers.
  778. spillOpStack(opStackDepth);
  779. // We need to leave R_OPSTACK pointing to the top entry on the stack, which is the call address.
  780. // It will be consumed (and R4 decremented) by the AsmCall code.
  781. InstImm( "addi", PPC_ADDI, R_OPSTACK, R_OPSTACK, opStackDepth*4);
  782. Inst( "mtctr", PPC_MTSPR, R_ASMCALL, 9, 0 ); // move to count register
  783. Inst( "bctrl", PPC_BCCTR | 1, 20, 0, 0 ); // jump and link to the count register
  784. // R4 now points to the top of the operand stack, which has the return value in it. We want to
  785. // back off the pointer to point to the base of our local operand stack and then reload the stack.
  786. InstImm("addi", PPC_ADDI, R_OPSTACK, R_OPSTACK, -opStackDepth*4);
  787. // Reload operand stack.
  788. loadOpStack(opStackDepth);
  789. InstImm( "lwz", PPC_LWZ, R_SECOND, R_REAL_STACK, 0 ); // fetch the old return address
  790. InstImm( "addi", PPC_ADDI, R_REAL_STACK, R_REAL_STACK, 16 );
  791. Inst( "mtlr", PPC_MTSPR, R_SECOND, 8, 0 ); // move to link register
  792. break;
  793. case OP_PUSH:
  794. #if DEBUG_VM
  795. if(pass == 1)
  796. printf("%08x PUSH\n",instruction);
  797. #endif
  798. opStackRegType[opStackDepth] = 1; // Garbage int value.
  799. opStackDepth += 1;
  800. break;
  801. case OP_POP:
  802. #if DEBUG_VM
  803. if(pass == 1)
  804. printf("%08x POP\n",instruction);
  805. #endif
  806. opStackDepth -= 1;
  807. opStackRegType[opStackDepth] = 0; // ??
  808. opStackLoadInstructionAddr[opStackDepth-1] = 0;
  809. break;
  810. case OP_LEAVE:
  811. #if DEBUG_VM
  812. if(pass == 1)
  813. printf("%08x LEAVE\n",instruction);
  814. #endif
  815. assert(opStackDepth == 1);
  816. assert(opStackRegType[0] != 0);
  817. // Save return value onto top of op stack. We also have to increment R_OPSTACK
  818. switch(opStackRegType[0])
  819. {
  820. case 1: // Integer register
  821. InstImm( "stw", PPC_STWU, opStackIntRegisters[0], R_OPSTACK, 4);
  822. break;
  823. case 2: // Float register
  824. InstImm( "stfs", PPC_STFSU, opStackFloatRegisters[0], R_OPSTACK, 4);
  825. break;
  826. }
  827. InstImm( "addi", PPC_ADDI, R_STACK, R_STACK, Constant4() ); // add R_STACK, R_STACK, imm
  828. if(mainFunction == 1)
  829. {
  830. for(i = 0; i < OP_STACK_MAX_DEPTH; i++)
  831. InstImm( "lwz", PPC_LWZ, opStackIntRegisters[i], R_REAL_STACK, i*4);
  832. InstImm( "addi", PPC_ADDI, R_REAL_STACK, R_REAL_STACK, OP_STACK_MAX_DEPTH*4 );
  833. }
  834. opStackDepth--;
  835. opStackRegType[opStackDepth] = 0;
  836. opStackLoadInstructionAddr[opStackDepth] = 0;
  837. Inst( "blr", PPC_BCLR, 20, 0, 0 ); // branch unconditionally to link register
  838. break;
  839. case OP_LOAD4:
  840. #if DEBUG_VM
  841. if(pass == 1)
  842. printf("%08x LOAD4\n",instruction);
  843. #endif
  844. // We should try to figure out whether to use LWZX or LFSX based
  845. // on some kind of code analysis after subsequent passes. I think what
  846. // we could do is store the compiled load instruction address along with
  847. // the register type. When we hit the first mismatched operator, we go back
  848. // and patch the load. Since LCC's operand stack should be at 0 depth by the
  849. // time we hit a branch, this should work fairly well. FIXME FIXME FIXME.
  850. assertInteger(opStackDepth-1);
  851. opStackLoadInstructionAddr[opStackDepth-1] = &buf[ compiledOfs ];
  852. Inst( "lwzx", PPC_LWZX, opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1], R_MEMBASE );// load from memory base
  853. opStackRegType[opStackDepth-1] = 1;
  854. break;
  855. case OP_LOAD2:
  856. #if DEBUG_VM
  857. if(pass == 1)
  858. printf("%08x LOAD2\n",instruction);
  859. #endif
  860. assertInteger(opStackDepth-1);
  861. opStackLoadInstructionAddr[opStackDepth-1] = 0;
  862. Inst( "lhzx", PPC_LHZX, opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1], R_MEMBASE );// load from memory base
  863. opStackRegType[opStackDepth-1] = 1;
  864. break;
  865. case OP_LOAD1:
  866. #if DEBUG_VM
  867. if(pass == 1)
  868. printf("%08x LOAD1\n",instruction);
  869. #endif
  870. assertInteger(opStackDepth-1);
  871. opStackLoadInstructionAddr[opStackDepth-1] = 0;
  872. Inst( "lbzx", PPC_LBZX, opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1], R_MEMBASE );// load from memory base
  873. opStackRegType[opStackDepth-1] = 1;
  874. break;
  875. case OP_STORE4:
  876. #if DEBUG_VM
  877. if(pass == 1)
  878. printf("%08x STORE4\n",instruction);
  879. #endif
  880. assertInteger(opStackDepth-2);
  881. if(opStackRegType[opStackDepth-1] == 1)
  882. Inst( "stwx", PPC_STWX, opStackIntRegisters[opStackDepth-1],
  883. opStackIntRegisters[opStackDepth-2], R_MEMBASE ); // store from memory base
  884. else
  885. Inst( "stfsx", PPC_STFSX, opStackFloatRegisters[opStackDepth-1],
  886. opStackIntRegisters[opStackDepth-2], R_MEMBASE ); // store from memory base
  887. opStackRegType[opStackDepth-1] = 0;
  888. opStackRegType[opStackDepth-2] = 0;
  889. opStackLoadInstructionAddr[opStackDepth-1] = 0;
  890. opStackLoadInstructionAddr[opStackDepth-2] = 0;
  891. opStackDepth -= 2;
  892. break;
  893. case OP_STORE2:
  894. #if DEBUG_VM
  895. if(pass == 1)
  896. printf("%08x STORE2\n",instruction);
  897. #endif
  898. assertInteger(opStackDepth-1);
  899. assertInteger(opStackDepth-2);
  900. Inst( "sthx", PPC_STHX, opStackIntRegisters[opStackDepth-1],
  901. opStackIntRegisters[opStackDepth-2], R_MEMBASE ); // store from memory base
  902. opStackRegType[opStackDepth-1] = 0;
  903. opStackRegType[opStackDepth-2] = 0;
  904. opStackLoadInstructionAddr[opStackDepth-1] = 0;
  905. opStackLoadInstructionAddr[opStackDepth-2] = 0;
  906. opStackDepth -= 2;
  907. break;
  908. case OP_STORE1:
  909. #if DEBUG_VM
  910. if(pass == 1)
  911. printf("%08x STORE1\n",instruction);
  912. #endif
  913. assertInteger(opStackDepth-1);
  914. assertInteger(opStackDepth-2);
  915. Inst( "stbx", PPC_STBX, opStackIntRegisters[opStackDepth-1],
  916. opStackIntRegisters[opStackDepth-2], R_MEMBASE ); // store from memory base
  917. opStackRegType[opStackDepth-1] = 0;
  918. opStackRegType[opStackDepth-2] = 0;
  919. opStackLoadInstructionAddr[opStackDepth-1] = 0;
  920. opStackLoadInstructionAddr[opStackDepth-2] = 0;
  921. opStackDepth -= 2;
  922. break;
  923. case OP_EQ:
  924. #if DEBUG_VM
  925. if(pass == 1)
  926. printf("%08x EQ\n",instruction);
  927. #endif
  928. assertInteger(opStackDepth-1);
  929. assertInteger(opStackDepth-2);
  930. Inst( "cmp", PPC_CMP, 0, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
  931. opStackRegType[opStackDepth-1] = 0;
  932. opStackRegType[opStackDepth-2] = 0;
  933. opStackLoadInstructionAddr[opStackDepth-1] = 0;
  934. opStackLoadInstructionAddr[opStackDepth-2] = 0;
  935. opStackDepth -= 2;
  936. i = Constant4();
  937. jused[i] = 1;
  938. InstImm( "bc", PPC_BC, 4, 2, 8 );
  939. if ( pass==1 ) {
  940. v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
  941. } else {
  942. v = 0;
  943. }
  944. Emit4("b", PPC_B | (v&0x3ffffff) );
  945. break;
  946. case OP_NE:
  947. #if DEBUG_VM
  948. if(pass == 1)
  949. printf("%08x NE\n",instruction);
  950. #endif
  951. assertInteger(opStackDepth-1);
  952. assertInteger(opStackDepth-2);
  953. Inst( "cmp", PPC_CMP, 0, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
  954. opStackRegType[opStackDepth-1] = 0;
  955. opStackRegType[opStackDepth-2] = 0;
  956. opStackLoadInstructionAddr[opStackDepth-1] = 0;
  957. opStackLoadInstructionAddr[opStackDepth-2] = 0;
  958. opStackDepth -= 2;
  959. i = Constant4();
  960. jused[i] = 1;
  961. InstImm( "bc", PPC_BC, 12, 2, 8 );
  962. if ( pass==1 ) {
  963. v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
  964. } else {
  965. v = 0;
  966. }
  967. Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) );
  968. // InstImm( "bc", PPC_BC, 4, 2, v );
  969. break;
  970. case OP_LTI:
  971. #if DEBUG_VM
  972. if(pass == 1)
  973. printf("%08x LTI\n",instruction);
  974. #endif
  975. assertInteger(opStackDepth-1);
  976. assertInteger(opStackDepth-2);
  977. Inst( "cmp", PPC_CMP, 0, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
  978. opStackRegType[opStackDepth-1] = 0;
  979. opStackRegType[opStackDepth-2] = 0;
  980. opStackLoadInstructionAddr[opStackDepth-1] = 0;
  981. opStackLoadInstructionAddr[opStackDepth-2] = 0;
  982. opStackDepth -= 2;
  983. i = Constant4();
  984. jused[i] = 1;
  985. InstImm( "bc", PPC_BC, 4, 0, 8 );
  986. if ( pass==1 ) {
  987. v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
  988. } else {
  989. v = 0;
  990. }
  991. Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) );
  992. // InstImm( "bc", PPC_BC, 12, 0, v );
  993. break;
  994. case OP_LEI:
  995. #if DEBUG_VM
  996. if(pass == 1)
  997. printf("%08x LEI\n",instruction);
  998. #endif
  999. assertInteger(opStackDepth-1);
  1000. assertInteger(opStackDepth-2);
  1001. Inst( "cmp", PPC_CMP, 0, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
  1002. opStackRegType[opStackDepth-1] = 0;
  1003. opStackRegType[opStackDepth-2] = 0;
  1004. opStackLoadInstructionAddr[opStackDepth-1] = 0;
  1005. opStackLoadInstructionAddr[opStackDepth-2] = 0;
  1006. opStackDepth -= 2;
  1007. i = Constant4();
  1008. jused[i] = 1;
  1009. InstImm( "bc", PPC_BC, 12, 1, 8 );
  1010. if ( pass==1 ) {
  1011. v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
  1012. } else {
  1013. v = 0;
  1014. }
  1015. Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) );
  1016. // InstImm( "bc", PPC_BC, 4, 1, v );
  1017. break;
  1018. case OP_GTI:
  1019. #if DEBUG_VM
  1020. if(pass == 1)
  1021. printf("%08x GTI\n",instruction);
  1022. #endif
  1023. assertInteger(opStackDepth-1);
  1024. assertInteger(opStackDepth-2);
  1025. Inst( "cmp", PPC_CMP, 0, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
  1026. opStackRegType[opStackDepth-1] = 0;
  1027. opStackRegType[opStackDepth-2] = 0;
  1028. opStackLoadInstructionAddr[opStackDepth-1] = 0;
  1029. opStackLoadInstructionAddr[opStackDepth-2] = 0;
  1030. opStackDepth -= 2;
  1031. i = Constant4();
  1032. jused[i] = 1;
  1033. InstImm( "bc", PPC_BC, 4, 1, 8 );
  1034. if ( pass==1 ) {
  1035. v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
  1036. } else {
  1037. v = 0;
  1038. }
  1039. Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) );
  1040. // InstImm( "bc", PPC_BC, 12, 1, v );
  1041. break;
  1042. case OP_GEI:
  1043. #if DEBUG_VM
  1044. if(pass == 1)
  1045. printf("%08x GEI\n",instruction);
  1046. #endif
  1047. assertInteger(opStackDepth-1);
  1048. assertInteger(opStackDepth-2);
  1049. Inst( "cmp", PPC_CMP, 0, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
  1050. opStackRegType[opStackDepth-1] = 0;
  1051. opStackRegType[opStackDepth-2] = 0;
  1052. opStackLoadInstructionAddr[opStackDepth-1] = 0;
  1053. opStackLoadInstructionAddr[opStackDepth-2] = 0;
  1054. opStackDepth -= 2;
  1055. i = Constant4();
  1056. jused[i] = 1;
  1057. InstImm( "bc", PPC_BC, 12, 0, 8 );
  1058. if ( pass==1 ) {
  1059. v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
  1060. } else {
  1061. v = 0;
  1062. }
  1063. Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) );
  1064. // InstImm( "bc", PPC_BC, 4, 0, v );
  1065. break;
  1066. case OP_LTU:
  1067. #if DEBUG_VM
  1068. if(pass == 1)
  1069. printf("%08x LTU\n",instruction);
  1070. #endif
  1071. assertInteger(opStackDepth-1);
  1072. assertInteger(opStackDepth-2);
  1073. Inst( "cmp", PPC_CMP, 0, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
  1074. opStackRegType[opStackDepth-1] = 0;
  1075. opStackRegType[opStackDepth-2] = 0;
  1076. opStackLoadInstructionAddr[opStackDepth-1] = 0;
  1077. opStackLoadInstructionAddr[opStackDepth-2] = 0;
  1078. opStackDepth -= 2;
  1079. i = Constant4();
  1080. jused[i] = 1;
  1081. InstImm( "bc", PPC_BC, 4, 0, 8 );
  1082. if ( pass==1 ) {
  1083. v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
  1084. } else {
  1085. v = 0;
  1086. }
  1087. Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) );
  1088. // InstImm( "bc", PPC_BC, 12, 0, v );
  1089. break;
  1090. case OP_LEU:
  1091. #if DEBUG_VM
  1092. if(pass == 1)
  1093. printf("%08x LEU\n",instruction);
  1094. #endif
  1095. assertInteger(opStackDepth-1);
  1096. assertInteger(opStackDepth-2);
  1097. Inst( "cmp", PPC_CMP, 0, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
  1098. opStackRegType[opStackDepth-1] = 0;
  1099. opStackRegType[opStackDepth-2] = 0;
  1100. opStackLoadInstructionAddr[opStackDepth-1] = 0;
  1101. opStackLoadInstructionAddr[opStackDepth-2] = 0;
  1102. opStackDepth -= 2;
  1103. i = Constant4();
  1104. jused[i] = 1;
  1105. InstImm( "bc", PPC_BC, 12, 1, 8 );
  1106. if ( pass==1 ) {
  1107. v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
  1108. } else {
  1109. v = 0;
  1110. }
  1111. Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) );
  1112. // InstImm( "bc", PPC_BC, 4, 1, v );
  1113. break;
  1114. case OP_GTU:
  1115. #if DEBUG_VM
  1116. if(pass == 1)
  1117. printf("%08x GTU\n",instruction);
  1118. #endif
  1119. assertInteger(opStackDepth-1);
  1120. assertInteger(opStackDepth-2);
  1121. Inst( "cmp", PPC_CMP, 0, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
  1122. opStackRegType[opStackDepth-1] = 0;
  1123. opStackRegType[opStackDepth-2] = 0;
  1124. opStackLoadInstructionAddr[opStackDepth-1] = 0;
  1125. opStackLoadInstructionAddr[opStackDepth-2] = 0;
  1126. opStackDepth -= 2;
  1127. i = Constant4();
  1128. jused[i] = 1;
  1129. InstImm( "bc", PPC_BC, 4, 1, 8 );
  1130. if ( pass==1 ) {
  1131. v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
  1132. } else {
  1133. v = 0;
  1134. }
  1135. Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) );
  1136. // InstImm( "bc", PPC_BC, 12, 1, v );
  1137. break;
  1138. case OP_GEU:
  1139. #if DEBUG_VM
  1140. if(pass == 1)
  1141. printf("%08x GEU\n",instruction);
  1142. #endif
  1143. assertInteger(opStackDepth-1);
  1144. assertInteger(opStackDepth-2);
  1145. Inst( "cmp", PPC_CMP, 0, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
  1146. opStackRegType[opStackDepth-1] = 0;
  1147. opStackRegType[opStackDepth-2] = 0;
  1148. opStackLoadInstructionAddr[opStackDepth-1] = 0;
  1149. opStackLoadInstructionAddr[opStackDepth-2] = 0;
  1150. opStackDepth -= 2;
  1151. i = Constant4();
  1152. jused[i] = 1;
  1153. InstImm( "bc", PPC_BC, 12, 0, 8 );
  1154. if ( pass==1 ) {
  1155. v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
  1156. } else {
  1157. v = 0;
  1158. }
  1159. Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) );
  1160. // InstImm( "bc", PPC_BC, 4, 0, v );
  1161. break;
  1162. case OP_EQF:
  1163. #if DEBUG_VM
  1164. if(pass == 1)
  1165. printf("%08x EQF\n",instruction);
  1166. #endif
  1167. makeFloat(opStackDepth-1);
  1168. makeFloat(opStackDepth-2);
  1169. Inst( "fcmpu", PPC_FCMPU, 0, opStackFloatRegisters[opStackDepth-2], opStackFloatRegisters[opStackDepth-1] );
  1170. opStackRegType[opStackDepth-1] = 0;
  1171. opStackRegType[opStackDepth-2] = 0;
  1172. opStackLoadInstructionAddr[opStackDepth-1] = 0;
  1173. opStackLoadInstructionAddr[opStackDepth-2] = 0;
  1174. opStackDepth -= 2;
  1175. i = Constant4();
  1176. jused[i] = 1;
  1177. InstImm( "bc", PPC_BC, 4, 2, 8 );
  1178. if ( pass==1 ) {
  1179. v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
  1180. } else {
  1181. v = 0;
  1182. }
  1183. Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) );
  1184. // InstImm( "bc", PPC_BC, 12, 2, v );
  1185. break;
  1186. case OP_NEF:
  1187. #if DEBUG_VM
  1188. if(pass == 1)
  1189. printf("%08x NEF\n",instruction);
  1190. #endif
  1191. makeFloat(opStackDepth-1);
  1192. makeFloat(opStackDepth-2);
  1193. Inst( "fcmpu", PPC_FCMPU, 0, opStackFloatRegisters[opStackDepth-2], opStackFloatRegisters[opStackDepth-1] );
  1194. opStackRegType[opStackDepth-1] = 0;
  1195. opStackRegType[opStackDepth-2] = 0;
  1196. opStackLoadInstructionAddr[opStackDepth-1] = 0;
  1197. opStackLoadInstructionAddr[opStackDepth-2] = 0;
  1198. opStackDepth -= 2;
  1199. i = Constant4();
  1200. jused[i] = 1;
  1201. InstImm( "bc", PPC_BC, 12, 2, 8 );
  1202. if ( pass==1 ) {
  1203. v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
  1204. } else {
  1205. v = 0;
  1206. }
  1207. Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) );
  1208. // InstImm( "bc", PPC_BC, 4, 2, v );
  1209. break;
  1210. case OP_LTF:
  1211. #if DEBUG_VM
  1212. if(pass == 1)
  1213. printf("%08x LTF\n",instruction);
  1214. #endif
  1215. makeFloat(opStackDepth-1);
  1216. makeFloat(opStackDepth-2);
  1217. Inst( "fcmpu", PPC_FCMPU, 0, opStackFloatRegisters[opStackDepth-2], opStackFloatRegisters[opStackDepth-1] );
  1218. opStackRegType[opStackDepth-1] = 0;
  1219. opStackRegType[opStackDepth-2] = 0;
  1220. opStackLoadInstructionAddr[opStackDepth-1] = 0;
  1221. opStackLoadInstructionAddr[opStackDepth-2] = 0;
  1222. opStackDepth -= 2;
  1223. i = Constant4();
  1224. jused[i] = 1;
  1225. InstImm( "bc", PPC_BC, 4, 0, 8 );
  1226. if ( pass==1 ) {
  1227. v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
  1228. } else {
  1229. v = 0;
  1230. }
  1231. Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) );
  1232. // InstImm( "bc", PPC_BC, 12, 0, v );
  1233. break;
  1234. case OP_LEF:
  1235. #if DEBUG_VM
  1236. if(pass == 1)
  1237. printf("%08x LEF\n",instruction);
  1238. #endif
  1239. makeFloat(opStackDepth-1);
  1240. makeFloat(opStackDepth-2);
  1241. Inst( "fcmpu", PPC_FCMPU, 0, opStackFloatRegisters[opStackDepth-2], opStackFloatRegisters[opStackDepth-1] );
  1242. opStackRegType[opStackDepth-1] = 0;
  1243. opStackRegType[opStackDepth-2] = 0;
  1244. opStackLoadInstructionAddr[opStackDepth-1] = 0;
  1245. opStackLoadInstructionAddr[opStackDepth-2] = 0;
  1246. opStackDepth -= 2;
  1247. i = Constant4();
  1248. jused[i] = 1;
  1249. InstImm( "bc", PPC_BC, 12, 1, 8 );
  1250. if ( pass==1 ) {
  1251. v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
  1252. } else {
  1253. v = 0;
  1254. }
  1255. Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) );
  1256. // InstImm( "bc", PPC_BC, 4, 1, v );
  1257. break;
  1258. case OP_GTF:
  1259. #if DEBUG_VM
  1260. if(pass == 1)
  1261. printf("%08x GTF\n",instruction);
  1262. #endif
  1263. makeFloat(opStackDepth-1);
  1264. makeFloat(opStackDepth-2);
  1265. Inst( "fcmpu", PPC_FCMPU, 0, opStackFloatRegisters[opStackDepth-2], opStackFloatRegisters[opStackDepth-1] );
  1266. opStackRegType[opStackDepth-1] = 0;
  1267. opStackRegType[opStackDepth-2] = 0;
  1268. opStackLoadInstructionAddr[opStackDepth-1] = 0;
  1269. opStackLoadInstructionAddr[opStackDepth-2] = 0;
  1270. opStackDepth -= 2;
  1271. i = Constant4();
  1272. jused[i] = 1;
  1273. InstImm( "bc", PPC_BC, 4, 1, 8 );
  1274. if ( pass==1 ) {
  1275. v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
  1276. } else {
  1277. v = 0;
  1278. }
  1279. Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) );
  1280. // InstImm( "bc", PPC_BC, 12, 1, v );
  1281. break;
  1282. case OP_GEF:
  1283. #if DEBUG_VM
  1284. if(pass == 1)
  1285. printf("%08x GEF\n",instruction);
  1286. #endif
  1287. makeFloat(opStackDepth-1);
  1288. makeFloat(opStackDepth-2);
  1289. Inst( "fcmpu", PPC_FCMPU, 0, opStackFloatRegisters[opStackDepth-2], opStackFloatRegisters[opStackDepth-1] );
  1290. opStackRegType[opStackDepth-1] = 0;
  1291. opStackRegType[opStackDepth-2] = 0;
  1292. opStackLoadInstructionAddr[opStackDepth-1] = 0;
  1293. opStackLoadInstructionAddr[opStackDepth-2] = 0;
  1294. opStackDepth -= 2;
  1295. i = Constant4();
  1296. jused[i] = 1;
  1297. InstImm( "bc", PPC_BC, 12, 0, 8 );
  1298. if ( pass==1 ) {
  1299. v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
  1300. } else {
  1301. v = 0;
  1302. }
  1303. Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) );
  1304. // InstImm( "bc", PPC_BC, 4, 0, v );
  1305. break;
  1306. case OP_NEGI:
  1307. #if DEBUG_VM
  1308. if(pass == 1)
  1309. printf("%08x NEGI\n",instruction);
  1310. #endif
  1311. assertInteger(opStackDepth-1);
  1312. InstImm( "subfic", PPC_SUBFIC, opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1], 0 );
  1313. opStackLoadInstructionAddr[opStackDepth-1] = 0;
  1314. break;
  1315. case OP_ADD:
  1316. #if DEBUG_VM
  1317. if(pass == 1)
  1318. printf("%08x ADD\n",instruction);
  1319. #endif
  1320. assertInteger(opStackDepth-1);
  1321. assertInteger(opStackDepth-2);
  1322. Inst( "add", PPC_ADD, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-2] );
  1323. opStackRegType[opStackDepth-1] = 0;
  1324. opStackLoadInstructionAddr[opStackDepth-1] = 0;
  1325. opStackDepth -= 1;
  1326. break;
  1327. case OP_SUB:
  1328. #if DEBUG_VM
  1329. if(pass == 1)
  1330. printf("%08x SUB\n",instruction);
  1331. #endif
  1332. assertInteger(opStackDepth-1);
  1333. assertInteger(opStackDepth-2);
  1334. Inst( "subf", PPC_SUBF, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-2] );
  1335. opStackRegType[opStackDepth-1] = 0;
  1336. opStackLoadInstructionAddr[opStackDepth-1] = 0;
  1337. opStackDepth -= 1;
  1338. break;
  1339. case OP_DIVI:
  1340. #if DEBUG_VM
  1341. if(pass == 1)
  1342. printf("%08x DIVI\n",instruction);
  1343. #endif
  1344. assertInteger(opStackDepth-1);
  1345. assertInteger(opStackDepth-2);
  1346. Inst( "divw", PPC_DIVW, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
  1347. opStackRegType[opStackDepth-1] = 0;
  1348. opStackLoadInstructionAddr[opStackDepth-1] = 0;
  1349. opStackDepth -= 1;
  1350. break;
  1351. case OP_DIVU:
  1352. #if DEBUG_VM
  1353. if(pass == 1)
  1354. printf("%08x DIVU\n",instruction);
  1355. #endif
  1356. assertInteger(opStackDepth-1);
  1357. assertInteger(opStackDepth-2);
  1358. Inst( "divwu", PPC_DIVWU, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
  1359. opStackRegType[opStackDepth-1] = 0;
  1360. opStackLoadInstructionAddr[opStackDepth-1] = 0;
  1361. opStackDepth -= 1;
  1362. break;
  1363. case OP_MODI:
  1364. #if DEBUG_VM
  1365. if(pass == 1)
  1366. printf("%08x MODI\n",instruction);
  1367. #endif
  1368. assertInteger(opStackDepth-1);
  1369. assertInteger(opStackDepth-2);
  1370. Inst( "divw", PPC_DIVW, R_EA, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
  1371. Inst( "mullw", PPC_MULLW, R_EA, opStackIntRegisters[opStackDepth-1], R_EA );
  1372. Inst( "subf", PPC_SUBF, opStackIntRegisters[opStackDepth-2], R_EA, opStackIntRegisters[opStackDepth-2] );
  1373. opStackRegType[opStackDepth-1] = 0;
  1374. opStackLoadInstructionAddr[opStackDepth-1] = 0;
  1375. opStackDepth -= 1;
  1376. break;
  1377. case OP_MODU:
  1378. #if DEBUG_VM
  1379. if(pass == 1)
  1380. printf("%08x MODU\n",instruction);
  1381. #endif
  1382. assertInteger(opStackDepth-1);
  1383. assertInteger(opStackDepth-2);
  1384. Inst( "divwu", PPC_DIVWU, R_EA, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
  1385. Inst( "mullw", PPC_MULLW, R_EA, opStackIntRegisters[opStackDepth-1], R_EA );
  1386. Inst( "subf", PPC_SUBF, opStackIntRegisters[opStackDepth-2], R_EA, opStackIntRegisters[opStackDepth-2] );
  1387. opStackRegType[opStackDepth-1] = 0;
  1388. opStackLoadInstructionAddr[opStackDepth-1] = 0;
  1389. opStackDepth -= 1;
  1390. break;
  1391. case OP_MULI:
  1392. case OP_MULU:
  1393. #if DEBUG_VM
  1394. if(pass == 1)
  1395. printf("%08x MULI\n",instruction);
  1396. #endif
  1397. assertInteger(opStackDepth-1);
  1398. assertInteger(opStackDepth-2);
  1399. Inst( "mullw", PPC_MULLW, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-2] );
  1400. opStackRegType[opStackDepth-1] = 0;
  1401. opStackLoadInstructionAddr[opStackDepth-1] = 0;
  1402. opStackDepth -= 1;
  1403. break;
  1404. case OP_BAND:
  1405. #if DEBUG_VM
  1406. if(pass == 1)
  1407. printf("%08x BAND\n",instruction);
  1408. #endif
  1409. assertInteger(opStackDepth-1);
  1410. assertInteger(opStackDepth-2);
  1411. Inst( "and", PPC_AND, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
  1412. opStackRegType[opStackDepth-1] = 0;
  1413. opStackLoadInstructionAddr[opStackDepth-1] = 0;
  1414. opStackDepth -= 1;
  1415. break;
  1416. case OP_BOR:
  1417. #if DEBUG_VM
  1418. if(pass == 1)
  1419. printf("%08x BOR\n",instruction);
  1420. #endif
  1421. assertInteger(opStackDepth-1);
  1422. assertInteger(opStackDepth-2);
  1423. Inst( "or", PPC_OR, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
  1424. opStackRegType[opStackDepth-1] = 0;
  1425. opStackLoadInstructionAddr[opStackDepth-1] = 0;
  1426. opStackDepth -= 1;
  1427. break;
  1428. case OP_BXOR:
  1429. #if DEBUG_VM
  1430. if(pass == 1)
  1431. printf("%08x BXOR\n",instruction);
  1432. #endif
  1433. assertInteger(opStackDepth-1);
  1434. assertInteger(opStackDepth-2);
  1435. Inst( "xor", PPC_XOR, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
  1436. opStackRegType[opStackDepth-1] = 0;
  1437. opStackLoadInstructionAddr[opStackDepth-1] = 0;
  1438. opStackDepth -= 1;
  1439. break;
  1440. case OP_BCOM:
  1441. #if DEBUG_VM
  1442. if(pass == 1)
  1443. printf("%08x BCOM\n",instruction);
  1444. #endif
  1445. assertInteger(opStackDepth-1);
  1446. Inst( "nor", PPC_NOR, opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1] );
  1447. opStackLoadInstructionAddr[opStackDepth-1] = 0;
  1448. break;
  1449. case OP_LSH:
  1450. #if DEBUG_VM
  1451. if(pass == 1)
  1452. printf("%08x LSH\n",instruction);
  1453. #endif
  1454. assertInteger(opStackDepth-1);
  1455. assertInteger(opStackDepth-2);
  1456. Inst( "slw", PPC_SLW, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
  1457. opStackRegType[opStackDepth-1] = 0;
  1458. opStackLoadInstructionAddr[opStackDepth-1] = 0;
  1459. opStackDepth -= 1;
  1460. break;
  1461. case OP_RSHI:
  1462. #if DEBUG_VM
  1463. if(pass == 1)
  1464. printf("%08x RSHI\n",instruction);
  1465. #endif
  1466. assertInteger(opStackDepth-1);
  1467. assertInteger(opStackDepth-2);
  1468. Inst( "sraw", PPC_SRAW, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
  1469. opStackRegType[opStackDepth-1] = 0;
  1470. opStackLoadInstructionAddr[opStackDepth-1] = 0;
  1471. opStackDepth -= 1;
  1472. break;
  1473. case OP_RSHU:
  1474. #if DEBUG_VM
  1475. if(pass == 1)
  1476. printf("%08x RSHU\n",instruction);
  1477. #endif
  1478. assertInteger(opStackDepth-1);
  1479. assertInteger(opStackDepth-2);
  1480. Inst( "srw", PPC_SRW, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
  1481. opStackRegType[opStackDepth-1] = 0;
  1482. opStackLoadInstructionAddr[opStackDepth-1] = 0;
  1483. opStackDepth -= 1;
  1484. break;
  1485. case OP_NEGF:
  1486. #if DEBUG_VM
  1487. if(pass == 1)
  1488. printf("%08x NEGF\n",instruction);
  1489. #endif
  1490. makeFloat(opStackDepth-1);
  1491. Inst( "fneg", PPC_FNEG, opStackFloatRegisters[opStackDepth-1], 0, opStackFloatRegisters[opStackDepth-1] );
  1492. opStackLoadInstructionAddr[opStackDepth-1] = 0;
  1493. break;
  1494. case OP_ADDF:
  1495. #if DEBUG_VM
  1496. if(pass == 1)
  1497. printf("%08x ADDF\n",instruction);
  1498. #endif
  1499. makeFloat(opStackDepth-1);
  1500. makeFloat(opStackDepth-2);
  1501. Inst( "fadds", PPC_FADDS, opStackFloatRegisters[opStackDepth-2], opStackFloatRegisters[opStackDepth-2], opStackFloatRegisters[opStackDepth-1] );
  1502. opStackRegType[opStackDepth-1] = 0;
  1503. opStackLoadInstructionAddr[opStackDepth-1] = 0;
  1504. opStackDepth -= 1;
  1505. break;
  1506. case OP_SUBF:
  1507. #if DEBUG_VM
  1508. if(pass == 1)
  1509. printf("%08x SUBF\n",instruction);
  1510. #endif
  1511. makeFloat(opStackDepth-1);
  1512. makeFloat(opStackDepth-2);
  1513. Inst( "fsubs", PPC_FSUBS, opStackFloatRegisters[opStackDepth-2], opStackFloatRegisters[opStackDepth-2], opStackFloatRegisters[opStackDepth-1] );
  1514. opStackRegType[opStackDepth-1] = 0;
  1515. opStackLoadInstructionAddr[opStackDepth-1] = 0;
  1516. opStackDepth -= 1;
  1517. break;
  1518. case OP_DIVF:
  1519. #if DEBUG_VM
  1520. if(pass == 1)
  1521. printf("%08x DIVF\n",instruction);
  1522. #endif
  1523. makeFloat(opStackDepth-1);
  1524. makeFloat(opStackDepth-2);
  1525. Inst( "fdivs", PPC_FDIVS, opStackFloatRegisters[opStackDepth-2], opStackFloatRegisters[opStackDepth-2], opStackFloatRegisters[opStackDepth-1] );
  1526. opStackRegType[opStackDepth-1] = 0;
  1527. opStackLoadInstructionAddr[opStackDepth-1] = 0;
  1528. opStackDepth -= 1;
  1529. break;
  1530. case OP_MULF:
  1531. #if DEBUG_VM
  1532. if(pass == 1)
  1533. printf("%08x MULF\n",instruction);
  1534. #endif
  1535. makeFloat(opStackDepth-1);
  1536. makeFloat(opStackDepth-2);
  1537. Inst4( "fmuls", PPC_FMULS, opStackFloatRegisters[opStackDepth-2], opStackFloatRegisters[opStackDepth-2], 0, opStackFloatRegisters[opStackDepth-1] );
  1538. opStackRegType[opStackDepth-1] = 0;
  1539. opStackLoadInstructionAddr[opStackDepth-1] = 0;
  1540. opStackDepth -= 1;
  1541. break;
  1542. case OP_CVIF:
  1543. #if DEBUG_VM
  1544. if(pass == 1)
  1545. printf("%08x CVIF\n",instruction);
  1546. #endif
  1547. assertInteger(opStackDepth-1);
  1548. //makeInteger(opStackDepth-1);
  1549. v = (int)&itofConvert;
  1550. InstImmU( "addis", PPC_ADDIS, R_EA, 0, (v >> 16)&0xffff );
  1551. InstImmU( "ori", PPC_ORI, R_EA, R_EA, v & 0xffff );
  1552. InstImmU( "xoris", PPC_XORIS, opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1], 0x8000 );
  1553. InstImm( "stw", PPC_STW, opStackIntRegisters[opStackDepth-1], R_EA, 12 );
  1554. InstImm( "lfd", PPC_LFD, opStackFloatRegisters[opStackDepth-1], R_EA, 0 );
  1555. Inst( "ori", PPC_ORI, 0, 0, 0);
  1556. Inst( "ori", PPC_ORI, 0, 0, 0);
  1557. Inst( "ori", PPC_ORI, 0, 0, 0);
  1558. InstImm( "lfd", PPC_LFD, 13, R_EA, 8 );
  1559. Inst( "fsub", PPC_FSUB, opStackFloatRegisters[opStackDepth-1], 13, opStackFloatRegisters[opStackDepth-1] );
  1560. opStackRegType[opStackDepth-1] = 2;
  1561. opStackLoadInstructionAddr[opStackDepth-1] = 0;
  1562. // Inst( PPC_FRSP, R_TOP, 0, R_TOP );
  1563. break;
  1564. case OP_CVFI:
  1565. #if DEBUG_VM
  1566. if(pass == 1)
  1567. printf("%08x CVFI\n",instruction);
  1568. #endif
  1569. makeFloat(opStackDepth-1);
  1570. InstImm( "addi", PPC_ADDI, R_OPSTACK, R_OPSTACK, opStackDepth*4);
  1571. Inst( "fctiwz", PPC_FCTIWZ, opStackFloatRegisters[opStackDepth-1], 0, opStackFloatRegisters[opStackDepth-1] );
  1572. Inst( "stfiwx", PPC_STFIWX, opStackFloatRegisters[opStackDepth-1], 0, R_OPSTACK ); // save value to opstack (dummy area now)
  1573. Inst( "ori", PPC_ORI, 0, 0, 0);
  1574. Inst( "ori", PPC_ORI, 0, 0, 0);
  1575. Inst( "ori", PPC_ORI, 0, 0, 0);
  1576. Inst( "ori", PPC_ORI, 0, 0, 0);
  1577. InstImm( "lwz", PPC_LWZ, opStackIntRegisters[opStackDepth-1], R_OPSTACK, 0 );
  1578. InstImm( "addi", PPC_ADDI, R_OPSTACK, R_OPSTACK, -opStackDepth*4);
  1579. opStackRegType[opStackDepth-1] = 1;
  1580. opStackLoadInstructionAddr[opStackDepth-1] = 0;
  1581. break;
  1582. case OP_SEX8:
  1583. #if DEBUG_VM
  1584. if(pass == 1)
  1585. printf("%08x SEX8\n",instruction);
  1586. #endif
  1587. assertInteger(opStackDepth-1);
  1588. Inst( "extsb", PPC_EXTSB, opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1], 0 );
  1589. opStackLoadInstructionAddr[opStackDepth-1] = 0;
  1590. break;
  1591. case OP_SEX16:
  1592. #if DEBUG_VM
  1593. if(pass == 1)
  1594. printf("%08x SEX16\n",instruction);
  1595. #endif
  1596. assertInteger(opStackDepth-1);
  1597. Inst( "extsh", PPC_EXTSH, opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1], 0 );
  1598. opStackLoadInstructionAddr[opStackDepth-1] = 0;
  1599. break;
  1600. case OP_BLOCK_COPY:
  1601. v = Constant4() >> 2;
  1602. #if DEBUG_VM
  1603. if(pass == 1)
  1604. printf("%08x BLOCK_COPY\t%08lx\n",instruction,v<<2);
  1605. #endif
  1606. assert(opStackDepth >= 2);
  1607. assertInteger(opStackDepth-1);
  1608. assertInteger(opStackDepth-2);
  1609. InstImmU( "addi", PPC_ADDI, R_EA, 0, v ); // count
  1610. // FIXME: range check
  1611. Inst( "mtctr", PPC_MTSPR, R_EA, 9, 0 ); // move to count register
  1612. Inst( "add", PPC_ADD, opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1], R_MEMBASE );
  1613. InstImm( "addi", PPC_ADDI, opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1], -4 );
  1614. Inst( "add", PPC_ADD, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-2], R_MEMBASE );
  1615. InstImm( "addi", PPC_ADDI, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-2], -4 );
  1616. InstImm( "lwzu", PPC_LWZU, R_EA, opStackIntRegisters[opStackDepth-1], 4 ); // source
  1617. InstImm( "stwu", PPC_STWU, R_EA, opStackIntRegisters[opStackDepth-2], 4 ); // dest
  1618. Inst( "b", PPC_BC | 0xfff8 , 16, 0, 0 ); // loop
  1619. opStackRegType[opStackDepth-1] = 0;
  1620. opStackRegType[opStackDepth-2] = 0;
  1621. opStackLoadInstructionAddr[opStackDepth-1] = 0;
  1622. opStackLoadInstructionAddr[opStackDepth-2] = 0;
  1623. opStackDepth -= 2;
  1624. break;
  1625. case OP_JUMP:
  1626. #if DEBUG_VM
  1627. if(pass == 1)
  1628. printf("%08x JUMP\n",instruction);
  1629. #endif
  1630. assert(opStackDepth == 1);
  1631. assertInteger(opStackDepth-1);
  1632. Inst( "rlwinm", PPC_RLWINM | ( 29 << 1 ), opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1], 2 );
  1633. // FIXME: range check
  1634. Inst( "lwzx", PPC_LWZX, opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1], R_INSTRUCTIONS );
  1635. Inst( "mtctr", PPC_MTSPR, opStackIntRegisters[opStackDepth-1], 9, 0 ); // move to count register
  1636. Inst( "bctr", PPC_BCCTR, 20, 0, 0 ); // jump to the count register
  1637. opStackRegType[opStackDepth-1] = 0;
  1638. opStackLoadInstructionAddr[opStackDepth-1] = 0;
  1639. opStackDepth -= 1;
  1640. break;
  1641. default:
  1642. Com_Error( ERR_DROP, "VM_CompilePPC: bad opcode %i at instruction %i, offset %i", op, instruction, pc );
  1643. }
  1644. pop0 = pop1;
  1645. pop1 = op;
  1646. assert(opStackDepth >= 0);
  1647. assert(opStackDepth < OP_STACK_MAX_DEPTH);
  1648. //printf("%4d\t%s\n",opStackDepth,opnames[op]);
  1649. }
  1650. Com_Printf( "VM file %s pass %d compiled to %i bytes of code\n", vm->name, (pass+1), compiledOfs*4 );
  1651. if ( pass == 0 ) {
  1652. // copy to an exact size buffer on the hunk
  1653. vm->codeLength = compiledOfs * 4;
  1654. vm->codeBase = Hunk_Alloc( vm->codeLength, h_low );
  1655. Com_Memcpy( vm->codeBase, buf, vm->codeLength );
  1656. //printf("codeBase: %p\n",vm->codeBase);
  1657. Z_Free( buf );
  1658. // offset all the instruction pointers for the new location
  1659. for ( i = 0 ; i < header->instructionCount ; i++ ) {
  1660. vm->instructionPointers[i] += (int)vm->codeBase;
  1661. //printf("%08x %08lx\n",i,vm->instructionPointers[i]);
  1662. }
  1663. // go back over it in place now to fixup reletive jump targets
  1664. buf = (unsigned *)vm->codeBase;
  1665. }
  1666. }
  1667. if(0)
  1668. {
  1669. char buf[256];
  1670. printf("wait..\n");
  1671. gets(buf);
  1672. }
  1673. Z_Free( jused );
  1674. }
  1675. /*
  1676. ==============
  1677. VM_CallCompiled
  1678. This function is called directly by the generated code
  1679. ==============
  1680. */
  1681. int VM_CallCompiled( vm_t *vm, int *args ) {
  1682. int stack[1024];
  1683. int programStack;
  1684. int stackOnEntry;
  1685. byte *image;
  1686. currentVM = vm;
  1687. //printf("VM_CallCompiled: %p %08lx %08lx %08lx\n",
  1688. // vm, args[0],args[1],args[2]);
  1689. // interpret the code
  1690. vm->currentlyInterpreting = qtrue;
  1691. // we might be called recursively, so this might not be the very top
  1692. programStack = vm->programStack;
  1693. stackOnEntry = programStack;
  1694. image = vm->dataBase;
  1695. // set up the stack frame
  1696. programStack -= 48;
  1697. *(int *)&image[ programStack + 44] = args[9];
  1698. *(int *)&image[ programStack + 40] = args[8];
  1699. *(int *)&image[ programStack + 36] = args[7];
  1700. *(int *)&image[ programStack + 32] = args[6];
  1701. *(int *)&image[ programStack + 28] = args[5];
  1702. *(int *)&image[ programStack + 24] = args[4];
  1703. *(int *)&image[ programStack + 20] = args[3];
  1704. *(int *)&image[ programStack + 16] = args[2];
  1705. *(int *)&image[ programStack + 12] = args[1];
  1706. *(int *)&image[ programStack + 8 ] = args[0];
  1707. *(int *)&image[ programStack + 4 ] = 0; // return stack
  1708. *(int *)&image[ programStack ] = -1; // will terminate the loop on return
  1709. // Cheesy... manually save registers used by VM call...
  1710. // off we go into generated code...
  1711. // the PPC calling standard says the parms will all go into R3 - R11, so
  1712. // no special asm code is needed here
  1713. #ifdef __GNUC__
  1714. ((void(*)(int, int, int, int, int, int, int, int))(vm->codeBase))(
  1715. programStack, (int)&stack,
  1716. (int)image, vm->dataMask, (int)&AsmCall,
  1717. (int)vm->instructionPointers, vm->instructionPointersLength,
  1718. (int)vm );
  1719. #else
  1720. ((void(*)(int, int, int, int, int, int, int, int))(vm->codeBase))(
  1721. programStack, (int)&stack,
  1722. (int)image, vm->dataMask, *(int *)&AsmCall /* skip function pointer header */,
  1723. (int)vm->instructionPointers, vm->instructionPointersLength,
  1724. (int)vm );
  1725. #endif
  1726. vm->programStack = stackOnEntry;
  1727. vm->currentlyInterpreting = qfalse;
  1728. return stack[1];
  1729. }
  1730. /*
  1731. ==================
  1732. AsmCall
  1733. Put this at end of file because gcc messes up debug line numbers
  1734. ==================
  1735. */
  1736. #ifdef __GNUC__
  1737. void AsmCall( void ) {
  1738. asm (
  1739. // pop off the destination instruction
  1740. " lwz r12,0(r4) \n" // RG_TOP, 0(RG_OPSTACK)
  1741. " addi r4,r4,-4 \n" // RG_OPSTACK, RG_OPSTACK, -4 \n"
  1742. // see if it is a system trap
  1743. " cmpwi r12,0 \n" // RG_TOP, 0 \n"
  1744. " bc 12,0, systemTrap \n"
  1745. // calling another VM function, so lookup in instructionPointers
  1746. " slwi r12,r12,2 \n" // RG_TOP,RG_TOP,2
  1747. // FIXME: range check
  1748. " lwzx r12, r8, r12 \n" // RG_TOP, RG_INSTRUCTIONS(RG_TOP)
  1749. " mtctr r12 \n" // RG_TOP
  1750. );
  1751. #if defined(MACOS_X) && defined(__OPTIMIZE__)
  1752. // On Mac OS X, gcc doesn't push a frame when we are optimized, so trying to tear it down results in grave disorder.
  1753. #warning Mac OS X optimization on, not popping GCC AsmCall frame
  1754. #else
  1755. // Mac OS X Server and unoptimized compiles include a GCC AsmCall frame
  1756. asm (
  1757. " lwz r1,0(r1) \n" // pop off the GCC AsmCall frame
  1758. " lmw r30,-8(r1) \n"
  1759. );
  1760. #endif
  1761. asm (
  1762. " bcctr 20,0 \n" // when it hits a leave, it will branch to the current link register
  1763. // calling a system trap
  1764. "systemTrap: \n"
  1765. // convert to positive system call number
  1766. " subfic r12,r12,-1 \n"
  1767. // save all our registers, including the current link register
  1768. " mflr r13 \n" // RG_SECOND // copy off our link register
  1769. " addi r1,r1,-92 \n" // required 24 byets of linkage, 32 bytes of parameter, plus our saves
  1770. " stw r3,56(r1) \n" // RG_STACK, -36(REAL_STACK)
  1771. " stw r4,60(r1) \n" // RG_OPSTACK, 4(RG_REAL_STACK)
  1772. " stw r5,64(r1) \n" // RG_MEMBASE, 8(RG_REAL_STACK)
  1773. " stw r6,68(r1) \n" // RG_MEMMASK, 12(RG_REAL_STACK)
  1774. " stw r7,72(r1) \n" // RG_ASMCALL, 16(RG_REAL_STACK)
  1775. " stw r8,76(r1) \n" // RG_INSTRUCTIONS, 20(RG_REAL_STACK)
  1776. " stw r9,80(r1) \n" // RG_NUM_INSTRUCTIONS, 24(RG_REAL_STACK)
  1777. " stw r10,84(r1) \n" // RG_VM, 28(RG_REAL_STACK)
  1778. " stw r13,88(r1) \n" // RG_SECOND, 32(RG_REAL_STACK) // link register
  1779. // save the vm stack position to allow recursive VM entry
  1780. " addi r13,r3,-4 \n" // RG_TOP, RG_STACK, -4
  1781. " stw r13,0(r10) \n" //RG_TOP, VM_OFFSET_PROGRAM_STACK(RG_VM)
  1782. // save the system call number as the 0th parameter
  1783. " add r3,r3,r5 \n" // r3, RG_STACK, RG_MEMBASE // r3 is the first parameter to vm->systemCalls
  1784. " stwu r12,4(r3) \n" // RG_TOP, 4(r3)
  1785. // make the system call with the address of all the VM parms as a parameter
  1786. // vm->systemCalls( &parms )
  1787. " lwz r12,4(r10) \n" // RG_TOP, VM_OFFSET_SYSTEM_CALL(RG_VM)
  1788. " mtctr r12 \n" // RG_TOP
  1789. " bcctrl 20,0 \n"
  1790. " mr r12,r3 \n" // RG_TOP, r3
  1791. // pop our saved registers
  1792. " lwz r3,56(r1) \n" // RG_STACK, 0(RG_REAL_STACK)
  1793. " lwz r4,60(r1) \n" // RG_OPSTACK, 4(RG_REAL_STACK)
  1794. " lwz r5,64(r1) \n" // RG_MEMBASE, 8(RG_REAL_STACK)
  1795. " lwz r6,68(r1) \n" // RG_MEMMASK, 12(RG_REAL_STACK)
  1796. " lwz r7,72(r1) \n" // RG_ASMCALL, 16(RG_REAL_STACK)
  1797. " lwz r8,76(r1) \n" // RG_INSTRUCTIONS, 20(RG_REAL_STACK)
  1798. " lwz r9,80(r1) \n" // RG_NUM_INSTRUCTIONS, 24(RG_REAL_STACK)
  1799. " lwz r10,84(r1) \n" // RG_VM, 28(RG_REAL_STACK)
  1800. " lwz r13,88(r1) \n" // RG_SECOND, 32(RG_REAL_STACK)
  1801. " addi r1,r1,92 \n" // RG_REAL_STACK, RG_REAL_STACK, 36
  1802. // restore the old link register
  1803. " mtlr r13 \n" // RG_SECOND
  1804. // save off the return value
  1805. " stwu r12,4(r4) \n" // RG_TOP, 0(RG_OPSTACK)
  1806. // GCC adds its own prolog / epliog code
  1807. );
  1808. }
  1809. #else
  1810. // codewarrior version
  1811. void asm AsmCall( void ) {
  1812. // pop off the destination instruction
  1813. lwz r12,0(r4) // RG_TOP, 0(RG_OPSTACK)
  1814. addi r4,r4,-4 // RG_OPSTACK, RG_OPSTACK, -4
  1815. // see if it is a system trap
  1816. cmpwi r12,0 // RG_TOP, 0
  1817. bc 12,0, systemTrap
  1818. // calling another VM function, so lookup in instructionPointers
  1819. slwi r12,r12,2 // RG_TOP,RG_TOP,2
  1820. // FIXME: range check
  1821. lwzx r12, r8, r12 // RG_TOP, RG_INSTRUCTIONS(RG_TOP)
  1822. mtctr r12 // RG_TOP
  1823. bcctr 20,0 // when it hits a leave, it will branch to the current link register
  1824. // calling a system trap
  1825. systemTrap:
  1826. // convert to positive system call number
  1827. subfic r12,r12,-1
  1828. // save all our registers, including the current link register
  1829. mflr r13 // RG_SECOND // copy off our link register
  1830. addi r1,r1,-92 // required 24 byets of linkage, 32 bytes of parameter, plus our saves
  1831. stw r3,56(r1) // RG_STACK, -36(REAL_STACK)
  1832. stw r4,60(r1) // RG_OPSTACK, 4(RG_REAL_STACK)
  1833. stw r5,64(r1) // RG_MEMBASE, 8(RG_REAL_STACK)
  1834. stw r6,68(r1) // RG_MEMMASK, 12(RG_REAL_STACK)
  1835. stw r7,72(r1) // RG_ASMCALL, 16(RG_REAL_STACK)
  1836. stw r8,76(r1) // RG_INSTRUCTIONS, 20(RG_REAL_STACK)
  1837. stw r9,80(r1) // RG_NUM_INSTRUCTIONS, 24(RG_REAL_STACK)
  1838. stw r10,84(r1) // RG_VM, 28(RG_REAL_STACK)
  1839. stw r13,88(r1) // RG_SECOND, 32(RG_REAL_STACK) // link register
  1840. // save the vm stack position to allow recursive VM entry
  1841. addi r13,r3,-4 // RG_TOP, RG_STACK, -4
  1842. stw r13,0(r10) //RG_TOP, VM_OFFSET_PROGRAM_STACK(RG_VM)
  1843. // save the system call number as the 0th parameter
  1844. add r3,r3,r5 // r3, RG_STACK, RG_MEMBASE // r3 is the first parameter to vm->systemCalls
  1845. stwu r12,4(r3) // RG_TOP, 4(r3)
  1846. // make the system call with the address of all the VM parms as a parameter
  1847. // vm->systemCalls( &parms )
  1848. lwz r12,4(r10) // RG_TOP, VM_OFFSET_SYSTEM_CALL(RG_VM)
  1849. // perform macos cross fragment fixup crap
  1850. lwz r9,0(r12)
  1851. stw r2,52(r1) // save old TOC
  1852. lwz r2,4(r12)
  1853. mtctr r9 // RG_TOP
  1854. bcctrl 20,0
  1855. lwz r2,52(r1) // restore TOC
  1856. mr r12,r3 // RG_TOP, r3
  1857. // pop our saved registers
  1858. lwz r3,56(r1) // RG_STACK, 0(RG_REAL_STACK)
  1859. lwz r4,60(r1) // RG_OPSTACK, 4(RG_REAL_STACK)
  1860. lwz r5,64(r1) // RG_MEMBASE, 8(RG_REAL_STACK)
  1861. lwz r6,68(r1) // RG_MEMMASK, 12(RG_REAL_STACK)
  1862. lwz r7,72(r1) // RG_ASMCALL, 16(RG_REAL_STACK)
  1863. lwz r8,76(r1) // RG_INSTRUCTIONS, 20(RG_REAL_STACK)
  1864. lwz r9,80(r1) // RG_NUM_INSTRUCTIONS, 24(RG_REAL_STACK)
  1865. lwz r10,84(r1) // RG_VM, 28(RG_REAL_STACK)
  1866. lwz r13,88(r1) // RG_SECOND, 32(RG_REAL_STACK)
  1867. addi r1,r1,92 // RG_REAL_STACK, RG_REAL_STACK, 36
  1868. // restore the old link register
  1869. mtlr r13 // RG_SECOND
  1870. // save off the return value
  1871. stwu r12,4(r4) // RG_TOP, 0(RG_OPSTACK)
  1872. blr
  1873. }
  1874. #endif