backend.c 73 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531
  1. /*
  2. Copyright (c) 2021-2022, b4rt-dev
  3. Copyright (c) 2012-2015, Alexey Frunze
  4. All rights reserved.
  5. Redistribution and use in source and binary forms, with or without
  6. modification, are permitted provided that the following conditions are met:
  7. 1. Redistributions of source code must retain the above copyright notice, this
  8. list of conditions and the following disclaimer.
  9. 2. Redistributions in binary form must reproduce the above copyright notice,
  10. this list of conditions and the following disclaimer in the documentation
  11. and/or other materials provided with the distribution.
  12. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  13. ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  14. WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  15. DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
  16. ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  17. (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  18. LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  19. ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  20. (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  21. SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  22. */
  23. /*****************************************************************************/
  24. /* */
  25. /* BCC (B32P C Compiler) */
  26. /* */
  27. /* C compiler for B32P */
  28. /* */
  29. /* Based on SmallerC: */
  30. /* A simple and small single-pass C compiler */
  31. /* */
  32. /* B32P code generator */
  33. /* Modified from the MIPS code generator */
  34. /* */
  35. /*****************************************************************************/
  36. // NOTE: Pretty inefficient generated code, because of the direct-ish translation from MIPS to B32P
  37. /* MAIN TODOs:
  38. - Improve using new B32P instructions
  39. - Remove all MIPS code leftovers
  40. - Do optimizations (like size stuff)
  41. */
  42. /* WORDSIZE issue tags (to look into if I will ever try to fix it)
  43. //WORDSIZE
  44. //CurFxnLocalOfs (gcc.c)
  45. */
  46. STATIC
  47. void GenInit(void)
  48. {
  49. // initialization of target-specific code generator
  50. // Assembler should move all .data and .rdata parts away from the code
  51. SizeOfWord = 4;
  52. OutputFormat = FormatSegmented;
  53. CodeHeaderFooter[0] = ".code";
  54. DataHeaderFooter[0] = ".data";
  55. RoDataHeaderFooter[0] = ".rdata";
  56. BssHeaderFooter[0] = ".bss"; // object data
  57. UseLeadingUnderscores = 0;
  58. }
  59. STATIC
  60. int GenInitParams(int argc, char** argv, int* idx)
  61. {
  62. return 0;
  63. }
  64. STATIC
  65. void GenInitFinalize(void)
  66. {
  67. // finalization of initialization of target-specific code generator
  68. // Put all C specific wrapper code (start) here
  69. if (compileUserBDOS)
  70. {
  71. printf2(
  72. ".code\n"
  73. "; Setup stack and return function before jumping to Main of BDOS user program\n"
  74. "; BDOS user programs have their stack to keep the other stacks intact\n"
  75. "Main:\n"
  76. " load32 0 r14 ; initialize base pointer address\n"
  77. " load32 0x73FFFF r13 ; initialize user main stack address\n"
  78. " addr2reg Return_BDOS r1 ; get address of return function\n"
  79. " or r0 r1 r15 ; copy return addr to r15\n"
  80. " jump main ; jump to main of C program\n"
  81. " halt ; should not get here\n"
  82. "\n"
  83. "; Function that is called after Main of C user program has returned\n"
  84. "; Here we do some post processing before jumping back to BDOS\n"
  85. "; Its adrress should be on top of the hardware stack\n"
  86. "Return_BDOS:\n"
  87. " ; notify program has ended\n"
  88. " load32 0x100300 r1\n"
  89. " write 0 r1 r0\n"
  90. "\n"
  91. " pop r1\n"
  92. " jumpr 3 r1\n"
  93. " halt ; should not get here\n"
  94. "\n"
  95. "; COMPILED C CODE HERE\n");
  96. }
  97. else
  98. {
  99. printf2(
  100. ".code\n"
  101. "; Setup stack and return function before jumping to Main of C program\n"
  102. "Main:\n"
  103. " load32 0 r14 ; initialize base pointer address\n"
  104. " load32 0x77FFFF r13 ; initialize main stack address\n"
  105. " addr2reg Return_UART r1 ; get address of return function\n"
  106. " or r0 r1 r15 ; copy return addr to r15\n"
  107. " jump main ; jump to main of C program\n"
  108. " ; should return to the address in r15\n"
  109. " halt ; should not get here\n"
  110. "\n"
  111. "; Function that is called after Main of C program has returned\n"
  112. "; Return value should be in R1\n"
  113. "; Send it over UART and halt afterwards\n"
  114. "Return_UART:\n"
  115. " load32 0xC02723 r1 ; r1 = 0xC02723 | UART tx\n"
  116. " write 0 r1 r2 ; write r2 over UART\n"
  117. " halt ; halt\n"
  118. "\n"
  119. "; COMPILED C CODE HERE\n");
  120. }
  121. }
  122. STATIC
  123. void GenStartCommentLine(void)
  124. {
  125. printf2(" ; ");
  126. }
  127. // No alignment needed on B32P
  128. STATIC
  129. void GenWordAlignment(int bss)
  130. {
  131. (void)bss;
  132. printf2("; .align 2\n");
  133. }
  134. STATIC
  135. void GenLabel(char* Label, int Static)
  136. {
  137. {
  138. if (!Static && GenExterns)
  139. printf2("; .globl %s\n", Label);
  140. printf2("%s:\n", Label);
  141. }
  142. }
  143. STATIC
  144. void GenPrintLabel(char* Label)
  145. {
  146. {
  147. if (isdigit(*Label))
  148. printf2("Label_%s", Label);
  149. else
  150. printf2("%s", Label);
  151. }
  152. }
  153. STATIC
  154. void GenNumLabel(int Label)
  155. {
  156. printf2("Label_%d:\n", Label);
  157. }
  158. STATIC
  159. void GenPrintNumLabel(int label)
  160. {
  161. printf2("Label_%d", label);
  162. }
  163. STATIC
  164. void GenZeroData(unsigned Size, int bss)
  165. {
  166. (void)bss;
  167. printf2("; .space %u\n", truncUint(Size));
  168. // B32P implementation of .space:
  169. if (Size > 0)
  170. {
  171. printf2(".dw");
  172. int i;
  173. for (i = 0; i < Size; i++)
  174. {
  175. printf2(" 0");
  176. }
  177. printf2("\n");
  178. }
  179. }
  180. STATIC
  181. void GenIntData(int Size, int Val)
  182. {
  183. Val = truncInt(Val);
  184. // Print multiple times, since the compiler does not know yet B32P is word addressable
  185. if (Size == 1)
  186. printf2(" .dw %d\n", Val);
  187. else if (Size == 2)
  188. printf2(" .dw %d %d\n", Val, Val);
  189. else if (Size == 4)
  190. printf2(" .dw %d %d %d %d\n", Val, Val, Val, Val);
  191. }
  192. STATIC
  193. void GenStartAsciiString(void)
  194. {
  195. printf2(".dw "); // String should be converted into 1 character per word
  196. }
  197. STATIC
  198. void GenAddrData(int Size, char* Label, int ofs)
  199. {
  200. ofs = truncInt(ofs);
  201. int i;
  202. for (i = 0; i < 4; i++) // label is 4 "bytes", hotfix since the compiler does not know yet B32P is word addressable
  203. {
  204. printf2(".dl ");
  205. GenPrintLabel(Label);
  206. // Still not sure if this ever gets called (and probably will not work until an Assembler update)
  207. if (ofs)
  208. printf2(" %+d", ofs);
  209. puts2("");
  210. }
  211. }
  212. STATIC
  213. int GenFxnSizeNeeded(void)
  214. {
  215. return 0;
  216. }
  217. STATIC
  218. void GenRecordFxnSize(char* startLabelName, int endLabelNo)
  219. {
  220. (void)startLabelName;
  221. (void)endLabelNo;
  222. }
  223. #define B32PInstrHalt 0x30
  224. #define B32PInstrRead 0x31
  225. #define B32PInstrWrite 0x32
  226. #define B32PInstrIntID 0x33
  227. #define B32PInstrPush 0x34
  228. #define B32PInstrPop 0x35
  229. #define B32PInstrJump 0x36
  230. #define B32PInstrJumpo 0x37
  231. #define B32PInstrJumpr 0x38
  232. #define B32PInstrJumpro 0x39
  233. #define B32PInstrBEQ 0x3A
  234. #define B32PInstrBGT 0x3B
  235. #define B32PInstrBGTS 0x3C
  236. #define B32PInstrBGE 0x3D
  237. #define B32PInstrBGES 0x3E
  238. #define B32PInstrBNE 0x3F
  239. #define B32PInstrBLT 0x40
  240. #define B32PInstrBLTS 0x41
  241. #define B32PInstrBLE 0x42
  242. #define B32PInstrBLES 0x43
  243. #define B32PInstrSavPC 0x44
  244. #define B32PInstrReti 0x45
  245. #define B32PInstrOR 0x46
  246. #define B32PInstrAND 0x47
  247. #define B32PInstrXOR 0x48
  248. #define B32PInstrADD 0x49
  249. #define B32PInstrSUB 0x4A
  250. #define B32PInstrSHIFTL 0x4B
  251. #define B32PInstrSHIFTR 0x4C
  252. #define B32PInstrNOT 0x4D
  253. #define B32PInstrMULTS 0x4E
  254. #define B32PInstrMULTU 0x4F
  255. #define B32PInstrSLT 0x50
  256. #define B32PInstrSLTU 0x51
  257. #define B32PInstrLoad 0x52
  258. #define B32PInstrLoadHi 0x53
  259. #define B32PInstrAddr2reg 0x54
  260. #define B32PInstrLoad32 0x55
  261. #define B32PInstrNOP 0x56
  262. STATIC
  263. void GenPrintInstr(int instr, int val)
  264. {
  265. char* p = "";
  266. (void)val;
  267. switch (instr)
  268. {
  269. case B32PInstrHalt : p = "halt"; break;
  270. case B32PInstrRead : p = "read"; break;
  271. case B32PInstrWrite : p = "write"; break;
  272. case B32PInstrIntID : p = "readintid"; break;
  273. case B32PInstrPush : p = "push"; break;
  274. case B32PInstrPop : p = "pop"; break;
  275. case B32PInstrJump : p = "jump"; break;
  276. case B32PInstrJumpo : p = "jumpo"; break;
  277. case B32PInstrJumpr : p = "jumpr"; break;
  278. case B32PInstrJumpro : p = "jumpro"; break;
  279. case B32PInstrBEQ : p = "beq"; break;
  280. case B32PInstrBGT : p = "bgts"; break; // HACK: Default signed comparison, because of MIPS
  281. case B32PInstrBGTS : p = "bgts"; break;
  282. case B32PInstrBGE : p = "bges"; break; // HACK: Default signed comparison, because of MIPS
  283. case B32PInstrBGES : p = "bges"; break;
  284. case B32PInstrBNE : p = "bne"; break;
  285. case B32PInstrBLT : p = "blts"; break; // HACK: Default signed comparison, because of MIPS
  286. case B32PInstrBLTS : p = "blts"; break;
  287. case B32PInstrBLE : p = "bles"; break; // HACK: Default signed comparison, because of MIPS
  288. case B32PInstrBLES : p = "bles"; break;
  289. case B32PInstrSavPC : p = "savpc"; break;
  290. case B32PInstrReti : p = "reti"; break;
  291. case B32PInstrOR : p = "or"; break;
  292. case B32PInstrAND : p = "and"; break;
  293. case B32PInstrXOR : p = "xor"; break;
  294. case B32PInstrADD : p = "add"; break;
  295. case B32PInstrSUB : p = "sub"; break;
  296. case B32PInstrSHIFTL : p = "shiftl"; break;
  297. case B32PInstrSHIFTR : p = "shiftr"; break;
  298. case B32PInstrNOT : p = "not"; break;
  299. case B32PInstrMULTS : p = "mults"; break;
  300. case B32PInstrMULTU : p = "multu"; break;
  301. case B32PInstrSLT : p = "slt"; break;
  302. case B32PInstrSLTU : p = "sltu"; break;
  303. case B32PInstrLoad : p = "load32"; break;
  304. case B32PInstrLoadHi : p = "loadhi"; break;
  305. case B32PInstrAddr2reg : p = "addr2reg"; break;
  306. case B32PInstrLoad32 : p = "load32"; break;
  307. }
  308. printf2(" %s ", p);
  309. }
  310. #define B32POpRegZero 0x00 //0 0
  311. #define B32POpRegAt 0x01 //1 at
  312. #define B32POpRegV0 0x02 //2 ret0
  313. #define B32POpRegV1 0x03 //3 ret1
  314. #define B32POpRegA0 0x04 //4 arg0
  315. #define B32POpRegA1 0x05 //5 arg1
  316. #define B32POpRegA2 0x06 //6 arg2
  317. #define B32POpRegA3 0x07 //7 arg3
  318. #define B32POpRegT0 0x08 //8 gp0
  319. #define B32POpRegT1 0x09 //9 gp1
  320. #define B32POpRegT2 0x0A //10 gp2
  321. #define B32POpRegT8 0x0B //11 tempa
  322. #define B32POpRegT9 0x0C //12 tempb
  323. #define B32POpRegSp 0x0D //13 sp
  324. #define B32POpRegFp 0x0E //14 fp
  325. #define B32POpRegRa 0x0F //15 retaddr
  326. #define B32POpIndRegZero 0x20
  327. #define B32POpIndRegAt 0x21
  328. #define B32POpIndRegV0 0x22
  329. #define B32POpIndRegV1 0x23
  330. #define B32POpIndRegA0 0x24
  331. #define B32POpIndRegA1 0x25
  332. #define B32POpIndRegA2 0x26
  333. #define B32POpIndRegA3 0x27
  334. #define B32POpIndRegT0 0x28
  335. #define B32POpIndRegT1 0x29
  336. #define B32POpIndRegSp 0x2D
  337. #define B32POpIndRegFp 0x2E
  338. #define B32POpIndRegRa 0x2F
  339. #define B32POpConst 0x80
  340. #define B32POpLabel 0x81
  341. #define B32POpNumLabel 0x82
  342. #define B32POpLabelLo 0x83
  343. #define B32POpIndLocal B32POpIndRegFp
  344. #define MAX_TEMP_REGS 3 // this many temp registers used beginning with T0 to hold subexpression results
  345. #define TEMP_REG_A B32POpRegT8 // two temporary registers used for momentary operations, similarly to the AT register
  346. #define TEMP_REG_B B32POpRegT9
  347. STATIC
  348. void GenPrintOperand(int op, int val)
  349. {
  350. if (op >= B32POpRegZero && op <= B32POpRegRa)
  351. {
  352. printf2("r%d", op);
  353. }
  354. else if (op >= B32POpIndRegZero && op <= B32POpIndRegRa)
  355. {
  356. printf2("%d r%d", truncInt(val), op - B32POpIndRegZero);
  357. }
  358. else
  359. {
  360. switch (op)
  361. {
  362. case B32POpConst: printf2("%d", truncInt(val)); break;
  363. case B32POpLabelLo:
  364. printf2("%%lo(");
  365. GenPrintLabel(IdentTable + val);
  366. printf2(")(r1)");
  367. break;
  368. case B32POpLabel: GenPrintLabel(IdentTable + val); break;
  369. case B32POpNumLabel: GenPrintNumLabel(val); break;
  370. default:
  371. errorInternal(100);
  372. break;
  373. }
  374. }
  375. }
  376. STATIC
  377. void GenPrintOperandSeparator(void)
  378. {
  379. printf2(" ");
  380. }
  381. STATIC
  382. void GenPrintNewLine(void)
  383. {
  384. puts2("");
  385. }
  386. STATIC
  387. void GenPrintInstr1Operand(int instr, int instrval, int operand, int operandval)
  388. {
  389. GenPrintInstr(instr, instrval);
  390. GenPrintOperand(operand, operandval);
  391. GenPrintNewLine();
  392. }
  393. STATIC
  394. void GenPrintInstr2Operands(int instr, int instrval, int operand1, int operand1val, int operand2, int operand2val)
  395. {
  396. // TODO: figure out if this ever happens because ADD and SUB need 3 args
  397. if (operand2 == B32POpConst && operand2val == 0 &&
  398. (instr == B32PInstrADD || instr == B32PInstrSUB))
  399. return;
  400. GenPrintInstr(instr, instrval);
  401. GenPrintOperand(operand1, operand1val);
  402. GenPrintOperandSeparator();
  403. GenPrintOperand(operand2, operand2val);
  404. GenPrintNewLine();
  405. }
  406. STATIC
  407. void GenPrintInstr3Operands(int instr, int instrval,
  408. int operand1, int operand1val,
  409. int operand2, int operand2val,
  410. int operand3, int operand3val)
  411. {
  412. if (operand3 == B32POpConst && operand3val == 0 &&
  413. (instr == B32PInstrADD || instr == B32PInstrSUB) &&
  414. operand1 == operand2)
  415. return;
  416. // If constant is negative, swap B32PInstrADD for B32PInstrSUB and vice versa
  417. // and flip sign of constant
  418. if (operand2 == B32POpConst && operand2val < 0)
  419. {
  420. if (instr == B32PInstrADD)
  421. {
  422. instr = B32PInstrSUB;
  423. operand2val = -operand2val;
  424. }
  425. else if (instr == B32PInstrSUB)
  426. {
  427. instr = B32PInstrADD;
  428. operand2val = -operand2val;
  429. }
  430. }
  431. GenPrintInstr(instr, instrval);
  432. GenPrintOperand(operand1, operand1val);
  433. GenPrintOperandSeparator();
  434. GenPrintOperand(operand2, operand2val);
  435. GenPrintOperandSeparator();
  436. GenPrintOperand(operand3, operand3val);
  437. GenPrintNewLine();
  438. }
  439. // Currently we do not want to "extend" any reg
  440. STATIC
  441. void GenExtendRegIfNeeded(int reg, int opSz)
  442. {
  443. }
  444. STATIC
  445. void GenJumpUncond(int label)
  446. {
  447. GenPrintInstr1Operand(B32PInstrJump, 0,
  448. B32POpNumLabel, label);
  449. }
  450. extern int GenWreg; // GenWreg is defined below
  451. STATIC
  452. void GenJumpIfEqual(int val, int label)
  453. {
  454. GenPrintInstr2Operands(B32PInstrLoad, 0,
  455. B32POpConst, val,
  456. TEMP_REG_B, 0);
  457. /*
  458. GenPrintInstr3Operands(MipsInstrBEQ, 0,
  459. GenWreg, 0,
  460. TEMP_REG_B, 0,
  461. B32POpNumLabel, label);
  462. */
  463. GenPrintInstr3Operands(B32PInstrBNE, 0,
  464. GenWreg, 0,
  465. TEMP_REG_B, 0,
  466. B32POpConst, 2);
  467. GenPrintInstr1Operand(B32PInstrJump, 0,
  468. B32POpNumLabel, label);
  469. }
  470. STATIC
  471. void GenJumpIfZero(int label)
  472. {
  473. #ifndef NO_ANNOTATIONS
  474. printf2(" ; JumpIfZero\n");
  475. #endif
  476. /* if Wreg == 0, jump to label
  477. GenPrintInstr3Operands(MipsInstrBEQ, 0,
  478. GenWreg, 0,
  479. B32POpRegZero, 0,
  480. B32POpNumLabel, label);
  481. */
  482. GenPrintInstr3Operands(B32PInstrBNE, 0,
  483. GenWreg, 0,
  484. B32POpRegZero, 0,
  485. B32POpConst, 2);
  486. GenPrintInstr1Operand(B32PInstrJump, 0,
  487. B32POpNumLabel, label);
  488. }
  489. STATIC
  490. void GenJumpIfNotZero(int label)
  491. {
  492. #ifndef NO_ANNOTATIONS
  493. printf2(" ; JumpIfNotZero\n");
  494. #endif
  495. /* if Wreg != 0, jump to label
  496. GenPrintInstr3Operands(MipsInstrBNE, 0,
  497. GenWreg, 0,
  498. B32POpRegZero, 0,
  499. B32POpNumLabel, label);
  500. */
  501. GenPrintInstr3Operands(B32PInstrBEQ, 0,
  502. GenWreg, 0,
  503. B32POpRegZero, 0,
  504. B32POpConst, 2);
  505. GenPrintInstr1Operand(B32PInstrJump, 0,
  506. B32POpNumLabel, label);
  507. }
  508. fpos_t GenPrologPos;
  509. int GenLeaf;
  510. STATIC
  511. void GenWriteFrameSize(void) //WORDSIZE
  512. {
  513. unsigned size = 8/*RA + FP*/ - CurFxnMinLocalOfs;
  514. //printf2(" subu r13, r13, %10u\n", size); // 10 chars are enough for 32-bit unsigned ints
  515. printf2(" sub r13 %10u r13\n", size); // r13 = r13 - size
  516. //printf2(" sw r14, %10u r13\n", size - 8);
  517. printf2(" write %10u r13 r14\n", size - 8); // write r14 to memory[r13+(size-8)]
  518. //printf2(" addu r14, r13, %10u\n", size - 8);
  519. printf2(" add r13 %10u r14\n", size - 8); // r14 = r13 + (size-8)
  520. //printf2(" %csw r15, 4 r14\n", GenLeaf ? ';' : ' ');
  521. printf2(" %c write 4 r14 r15\n", GenLeaf ? ';' : ' '); // write r15 to memory[r14+4]
  522. }
  523. STATIC
  524. void GenUpdateFrameSize(void)
  525. {
  526. fpos_t pos;
  527. fgetpos(OutFile, &pos);
  528. fsetpos(OutFile, &GenPrologPos);
  529. GenWriteFrameSize();
  530. fsetpos(OutFile, &pos);
  531. }
  532. STATIC
  533. void GenFxnProlog(void)
  534. {
  535. if (CurFxnParamCntMin && CurFxnParamCntMax)
  536. {
  537. int i, cnt = CurFxnParamCntMax;
  538. if (cnt > 4)
  539. cnt = 4; //WORDSIZE?
  540. // TBD!!! for structure passing use the cumulative parameter size
  541. // instead of the number of parameters. Currently this bug is masked
  542. // by the subroutine that pushes structures on the stack (it copies
  543. // all words except the first to the stack). But passing structures
  544. // in registers from assembly code won't always work.
  545. for (i = 0; i < cnt; i++)
  546. GenPrintInstr2Operands(B32PInstrWrite, 0,
  547. B32POpIndRegSp, 4 * i, //WORDSIZE
  548. B32POpRegA0 + i, 0);
  549. }
  550. GenLeaf = 1; // will be reset to 0 if a call is generated
  551. fgetpos(OutFile, &GenPrologPos);
  552. GenWriteFrameSize();
  553. }
  554. STATIC
  555. void GenGrowStack(int size) //WORDSIZE
  556. {
  557. if (!size)
  558. return;
  559. if (size > 0)
  560. {
  561. GenPrintInstr3Operands(B32PInstrSUB, 0,
  562. B32POpRegSp, 0,
  563. B32POpConst, size,
  564. B32POpRegSp, 0);
  565. }
  566. else
  567. {
  568. GenPrintInstr3Operands(B32PInstrADD, 0,
  569. B32POpRegSp, 0,
  570. B32POpConst, -size,
  571. B32POpRegSp, 0);
  572. }
  573. }
  574. STATIC
  575. void GenFxnEpilog(void)
  576. {
  577. GenUpdateFrameSize();
  578. if (!GenLeaf)
  579. GenPrintInstr2Operands(B32PInstrRead, 0,
  580. B32POpIndRegFp, 4, //WORDSIZE
  581. B32POpRegRa, 0);
  582. GenPrintInstr2Operands(B32PInstrRead, 0,
  583. B32POpIndRegFp, 0,
  584. B32POpRegFp, 0);
  585. GenPrintInstr3Operands(B32PInstrADD, 0,
  586. B32POpRegSp, 0,
  587. B32POpConst, 8/*RA + FP*/ - CurFxnMinLocalOfs, //WORDSIZE
  588. B32POpRegSp, 0);
  589. GenPrintInstr2Operands(B32PInstrJumpr, 0,
  590. B32POpConst, 0,
  591. B32POpRegRa, 0);
  592. }
  593. STATIC
  594. int GenMaxLocalsSize(void)
  595. {
  596. return 0x7FFFFFFF;
  597. }
  598. STATIC
  599. int GenGetBinaryOperatorInstr(int tok)
  600. {
  601. switch (tok)
  602. {
  603. case tokPostAdd:
  604. case tokAssignAdd:
  605. case '+':
  606. return B32PInstrADD;
  607. case tokPostSub:
  608. case tokAssignSub:
  609. case '-':
  610. return B32PInstrSUB;
  611. case '&':
  612. case tokAssignAnd:
  613. return B32PInstrAND;
  614. case '^':
  615. case tokAssignXor:
  616. return B32PInstrXOR;
  617. case '|':
  618. case tokAssignOr:
  619. return B32PInstrOR;
  620. case '<':
  621. case '>':
  622. case tokLEQ:
  623. case tokGEQ:
  624. case tokEQ:
  625. case tokNEQ:
  626. case tokULess:
  627. case tokUGreater:
  628. case tokULEQ:
  629. case tokUGEQ:
  630. return B32PInstrNOP;
  631. case '*':
  632. case tokAssignMul:
  633. return B32PInstrMULTS;
  634. case '/':
  635. case '%':
  636. case tokAssignDiv:
  637. case tokAssignMod:
  638. printf("DIVISION/MOD is not supported!\n");
  639. return B32PInstrHalt;
  640. case tokUDiv:
  641. case tokUMod:
  642. case tokAssignUDiv:
  643. case tokAssignUMod:
  644. printf("DIVISION/MOD is not supported!\n");
  645. return B32PInstrHalt;
  646. case tokLShift:
  647. case tokAssignLSh:
  648. return B32PInstrSHIFTL;
  649. case tokRShift:
  650. case tokAssignRSh:
  651. return B32PInstrSHIFTR; // B32P does not know about signed, so normal shiftr is done instead
  652. case tokURShift:
  653. case tokAssignURSh:
  654. return B32PInstrSHIFTR;
  655. default:
  656. //error("Error: Invalid operator\n");
  657. errorInternal(101);
  658. return 0;
  659. }
  660. }
  661. // Should not be needed, AT register is not used by B32P assembler
  662. // Although the lui instruction probably should stay?
  663. STATIC
  664. void GenPreIdentAccess(int label)
  665. {
  666. printf2("; .set noat\n lui r1, %%hi(");
  667. GenPrintLabel(IdentTable + label);
  668. puts2(")");
  669. }
  670. // Should not be needed, AT register is not used by B32P assembler
  671. STATIC
  672. void GenPostIdentAccess(void)
  673. {
  674. puts2("; .set at");
  675. }
  676. STATIC
  677. void GenReadIdent(int regDst, int opSz, int label)
  678. {
  679. GenPrintInstr2Operands(B32PInstrAddr2reg, 0,
  680. B32POpLabel, label,
  681. B32POpRegAt, 0);
  682. GenPrintInstr3Operands(B32PInstrRead, 0,
  683. B32POpConst, 0,
  684. B32POpRegAt, 0,
  685. regDst, 0);
  686. }
  687. STATIC
  688. void GenReadLocal(int regDst, int opSz, int ofs)
  689. {
  690. int instr = B32PInstrRead;
  691. GenPrintInstr2Operands(instr, 0,
  692. B32POpIndRegFp, ofs,
  693. regDst, 0);
  694. }
  695. STATIC
  696. void GenReadIndirect(int regDst, int regSrc, int opSz)
  697. {
  698. int instr = B32PInstrRead;
  699. GenPrintInstr2Operands(instr, 0,
  700. regSrc + B32POpIndRegZero, 0,
  701. regDst, 0);
  702. }
  703. STATIC
  704. void GenWriteIdent(int regSrc, int opSz, int label)
  705. {
  706. GenPrintInstr2Operands(B32PInstrAddr2reg, 0,
  707. B32POpLabel, label,
  708. B32POpRegAt, 0);
  709. GenPrintInstr3Operands(B32PInstrWrite, 0,
  710. B32POpConst, 0,
  711. B32POpRegAt, 0,
  712. regSrc, 0);
  713. }
  714. STATIC
  715. void GenWriteLocal(int regSrc, int opSz, int ofs)
  716. {
  717. int instr = B32PInstrWrite;
  718. GenPrintInstr2Operands(instr, 0,
  719. B32POpIndRegFp, ofs,
  720. regSrc, 0);
  721. }
  722. STATIC
  723. void GenWriteIndirect(int regDst, int regSrc, int opSz)
  724. {
  725. int instr = B32PInstrWrite;
  726. GenPrintInstr2Operands(instr, 0,
  727. regDst + B32POpIndRegZero, 0,
  728. regSrc, 0);
  729. }
  730. STATIC
  731. void GenIncDecIdent(int regDst, int opSz, int label, int tok)
  732. {
  733. int instr = B32PInstrADD;
  734. if (tok != tokInc)
  735. instr = B32PInstrSUB;
  736. GenReadIdent(regDst, opSz, label);
  737. GenPrintInstr3Operands(instr, 0,
  738. regDst, 0,
  739. B32POpConst, 1,
  740. regDst, 0);
  741. GenWriteIdent(regDst, opSz, label);
  742. GenExtendRegIfNeeded(regDst, opSz);
  743. }
  744. STATIC
  745. void GenIncDecLocal(int regDst, int opSz, int ofs, int tok)
  746. {
  747. int instr = B32PInstrADD;
  748. if (tok != tokInc)
  749. instr = B32PInstrSUB;
  750. GenReadLocal(regDst, opSz, ofs);
  751. GenPrintInstr3Operands(instr, 0,
  752. regDst, 0,
  753. B32POpConst, 1,
  754. regDst, 0);
  755. GenWriteLocal(regDst, opSz, ofs);
  756. GenExtendRegIfNeeded(regDst, opSz);
  757. }
  758. STATIC
  759. void GenIncDecIndirect(int regDst, int regSrc, int opSz, int tok)
  760. {
  761. int instr = B32PInstrADD;
  762. if (tok != tokInc)
  763. instr = B32PInstrSUB;
  764. GenReadIndirect(regDst, regSrc, opSz);
  765. GenPrintInstr3Operands(instr, 0,
  766. regDst, 0,
  767. B32POpConst, 1,
  768. regDst, 0);
  769. GenWriteIndirect(regSrc, regDst, opSz);
  770. GenExtendRegIfNeeded(regDst, opSz);
  771. }
  772. STATIC
  773. void GenPostIncDecIdent(int regDst, int opSz, int label, int tok)
  774. {
  775. int instr = B32PInstrADD;
  776. if (tok != tokPostInc)
  777. instr = B32PInstrSUB;
  778. GenReadIdent(regDst, opSz, label);
  779. GenPrintInstr3Operands(instr, 0,
  780. regDst, 0,
  781. B32POpConst, 1,
  782. regDst, 0);
  783. GenWriteIdent(regDst, opSz, label);
  784. GenPrintInstr3Operands(instr, 0,
  785. regDst, 0,
  786. B32POpConst, -1,
  787. regDst, 0);
  788. GenExtendRegIfNeeded(regDst, opSz);
  789. }
  790. STATIC
  791. void GenPostIncDecLocal(int regDst, int opSz, int ofs, int tok)
  792. {
  793. int instr = B32PInstrADD;
  794. if (tok != tokPostInc)
  795. instr = B32PInstrSUB;
  796. GenReadLocal(regDst, opSz, ofs);
  797. GenPrintInstr3Operands(instr, 0,
  798. regDst, 0,
  799. B32POpConst, 1,
  800. regDst, 0);
  801. GenWriteLocal(regDst, opSz, ofs);
  802. GenPrintInstr3Operands(instr, 0,
  803. regDst, 0,
  804. B32POpConst, -1,
  805. regDst, 0);
  806. GenExtendRegIfNeeded(regDst, opSz);
  807. }
  808. STATIC
  809. void GenPostIncDecIndirect(int regDst, int regSrc, int opSz, int tok)
  810. {
  811. int instr = B32PInstrADD;
  812. if (tok != tokPostInc)
  813. instr = B32PInstrSUB;
  814. GenReadIndirect(regDst, regSrc, opSz);
  815. GenPrintInstr3Operands(instr, 0,
  816. regDst, 0,
  817. B32POpConst, 1,
  818. regDst, 0);
  819. GenWriteIndirect(regSrc, regDst, opSz);
  820. GenPrintInstr3Operands(instr, 0,
  821. regDst, 0,
  822. B32POpConst, -1,
  823. regDst, 0);
  824. GenExtendRegIfNeeded(regDst, opSz);
  825. }
  826. int CanUseTempRegs;
  827. int TempsUsed;
  828. int GenWreg = B32POpRegV0; // current working register (V0 or Tn or An)
  829. int GenLreg, GenRreg; // left operand register and right operand register after GenPopReg()
  830. /*
  831. General idea behind GenWreg, GenLreg, GenRreg:
  832. - In expressions w/o function calls:
  833. Subexpressions are evaluated in V0, T0, T1, ..., T<MAX_TEMP_REGS-1>. If those registers
  834. aren't enough, the stack is used additionally.
  835. The expression result ends up in V0, which is handy for returning from
  836. functions.
  837. In the process, GenWreg is the current working register and is one of: V0, T0, T1, ... .
  838. All unary operators are evaluated in the current working register.
  839. GenPushReg() and GenPopReg() advance GenWreg as needed when handling binary operators.
  840. GenPopReg() sets GenWreg, GenLreg and GenRreg. GenLreg and GenRreg are the registers
  841. where the left and right operands of a binary operator are.
  842. When the exression runs out of the temporary registers, the stack is used. While it is being
  843. used, GenWreg remains equal to the last temporary register, and GenPopReg() sets GenLreg = TEMP_REG_A.
  844. Hence, after GenPopReg() the operands of the binary operator are always in registers and can be
  845. directly manipulated with.
  846. Following GenPopReg(), binary operator evaluation must take the left and right operands from
  847. GenLreg and GenRreg and write the evaluated result into GenWreg. Care must be taken as GenWreg
  848. will be the same as either GenLreg (when the popped operand comes from T0-T<MAX_TEMP_REGS-1>)
  849. or GenRreg (when the popped operand comes from the stack in TEMP_REG_A).
  850. - In expressions with function calls:
  851. GenWreg is always V0 in subexpressions that aren't function parameters. These subexpressions
  852. get automatically pushed onto the stack as necessary.
  853. GenWreg is always V0 in expressions, where return values from function calls are used as parameters
  854. into other called functions. IOW, this is the case when the function call depth is greater than 1.
  855. Subexpressions in such expressions get automatically pushed onto the stack as necessary.
  856. GenWreg is A0-A3 in subexpressions that are function parameters when the function call depth is 1.
  857. Basically, while a function parameter is evaluated, it's evaluated in the register from where
  858. the called function will take it. This avoids some of unnecessary register copies and stack
  859. manipulations in the most simple and very common cases of function calls.
  860. */
  861. STATIC
  862. void GenWregInc(int inc)
  863. {
  864. if (inc > 0)
  865. {
  866. // Advance the current working register to the next available temporary register
  867. if (GenWreg == B32POpRegV0)
  868. GenWreg = B32POpRegT0;
  869. else
  870. GenWreg++;
  871. }
  872. else
  873. {
  874. // Return to the previous current working register
  875. if (GenWreg == B32POpRegT0)
  876. GenWreg = B32POpRegV0;
  877. else
  878. GenWreg--;
  879. }
  880. }
  881. STATIC
  882. void GenPushReg(void)
  883. {
  884. if (CanUseTempRegs && TempsUsed < MAX_TEMP_REGS)
  885. {
  886. GenWregInc(1);
  887. TempsUsed++;
  888. return;
  889. }
  890. GenPrintInstr3Operands(B32PInstrSUB, 0,
  891. B32POpRegSp, 0,
  892. B32POpConst, 4, //WORDSIZE
  893. B32POpRegSp, 0);
  894. GenPrintInstr2Operands(B32PInstrWrite, 0,
  895. B32POpIndRegSp, 0,
  896. GenWreg, 0);
  897. TempsUsed++;
  898. }
  899. STATIC
  900. void GenPopReg(void)
  901. {
  902. TempsUsed--;
  903. if (CanUseTempRegs && TempsUsed < MAX_TEMP_REGS)
  904. {
  905. GenRreg = GenWreg;
  906. GenWregInc(-1);
  907. GenLreg = GenWreg;
  908. return;
  909. }
  910. GenPrintInstr2Operands(B32PInstrRead, 0,
  911. B32POpIndRegSp, 0,
  912. TEMP_REG_A, 0);
  913. GenPrintInstr3Operands(B32PInstrADD, 0,
  914. B32POpRegSp, 0,
  915. B32POpConst, 4, //WORDSIZE
  916. B32POpRegSp, 0);
  917. GenLreg = TEMP_REG_A;
  918. GenRreg = GenWreg;
  919. }
  920. #define tokRevIdent 0x100
  921. #define tokRevLocalOfs 0x101
  922. #define tokAssign0 0x102
  923. #define tokNum0 0x103
  924. STATIC
  925. void GenPrep(int* idx)
  926. {
  927. int tok;
  928. int oldIdxRight, oldIdxLeft, t0, t1;
  929. if (*idx < 0)
  930. //error("GenFuse(): idx < 0\n");
  931. errorInternal(100);
  932. tok = stack[*idx][0];
  933. oldIdxRight = --*idx;
  934. switch (tok)
  935. {
  936. case tokUDiv:
  937. case tokUMod:
  938. case tokAssignUDiv:
  939. case tokAssignUMod:
  940. if (stack[oldIdxRight][0] == tokNumInt || stack[oldIdxRight][0] == tokNumUint)
  941. {
  942. // Change unsigned division to right shift and unsigned modulo to bitwise and
  943. unsigned m = truncUint(stack[oldIdxRight][1]);
  944. if (m && !(m & (m - 1)))
  945. {
  946. if (tok == tokUMod || tok == tokAssignUMod)
  947. {
  948. stack[oldIdxRight][1] = (int)(m - 1);
  949. tok = (tok == tokUMod) ? '&' : tokAssignAnd;
  950. }
  951. else
  952. {
  953. t1 = 0;
  954. while (m >>= 1) t1++;
  955. stack[oldIdxRight][1] = t1;
  956. tok = (tok == tokUDiv) ? tokURShift : tokAssignURSh;
  957. }
  958. stack[oldIdxRight + 1][0] = tok;
  959. }
  960. }
  961. }
  962. switch (tok)
  963. {
  964. case tokNumUint:
  965. stack[oldIdxRight + 1][0] = tokNumInt; // reduce the number of cases since tokNumInt and tokNumUint are handled the same way
  966. // fallthrough
  967. case tokNumInt:
  968. case tokNum0:
  969. case tokIdent:
  970. case tokLocalOfs:
  971. break;
  972. case tokPostAdd:
  973. case tokPostSub:
  974. case '-':
  975. case '/':
  976. case '%':
  977. case tokUDiv:
  978. case tokUMod:
  979. case tokLShift:
  980. case tokRShift:
  981. case tokURShift:
  982. case tokLogAnd:
  983. case tokLogOr:
  984. case tokComma:
  985. GenPrep(idx);
  986. // fallthrough
  987. case tokShortCirc:
  988. case tokGoto:
  989. case tokUnaryStar:
  990. case tokInc:
  991. case tokDec:
  992. case tokPostInc:
  993. case tokPostDec:
  994. case '~':
  995. case tokUnaryPlus:
  996. case tokUnaryMinus:
  997. case tok_Bool:
  998. case tokVoid:
  999. case tokUChar:
  1000. case tokSChar:
  1001. case tokShort:
  1002. case tokUShort:
  1003. GenPrep(idx);
  1004. break;
  1005. case '=':
  1006. if (oldIdxRight + 1 == sp - 1 &&
  1007. (stack[oldIdxRight][0] == tokNumInt || stack[oldIdxRight][0] == tokNumUint) &&
  1008. truncUint(stack[oldIdxRight][1]) == 0)
  1009. {
  1010. // Special case for assigning 0 while throwing away the expression result value
  1011. // TBD??? ,
  1012. stack[oldIdxRight][0] = tokNum0; // this zero constant will not be loaded into a register
  1013. stack[oldIdxRight + 1][0] = tokAssign0; // change '=' to tokAssign0
  1014. }
  1015. // fallthrough
  1016. case tokAssignAdd:
  1017. case tokAssignSub:
  1018. case tokAssignMul:
  1019. case tokAssignDiv:
  1020. case tokAssignUDiv:
  1021. case tokAssignMod:
  1022. case tokAssignUMod:
  1023. case tokAssignLSh:
  1024. case tokAssignRSh:
  1025. case tokAssignURSh:
  1026. case tokAssignAnd:
  1027. case tokAssignXor:
  1028. case tokAssignOr:
  1029. GenPrep(idx);
  1030. oldIdxLeft = *idx;
  1031. GenPrep(idx);
  1032. // If the left operand is an identifier (with static or auto storage), swap it with the right operand
  1033. // and mark it specially, so it can be used directly
  1034. if ((t0 = stack[oldIdxLeft][0]) == tokIdent || t0 == tokLocalOfs)
  1035. {
  1036. t1 = stack[oldIdxLeft][1];
  1037. memmove(stack[oldIdxLeft], stack[oldIdxLeft + 1], (oldIdxRight - oldIdxLeft) * sizeof(stack[0]));
  1038. stack[oldIdxRight][0] = (t0 == tokIdent) ? tokRevIdent : tokRevLocalOfs;
  1039. stack[oldIdxRight][1] = t1;
  1040. }
  1041. break;
  1042. case '+':
  1043. case '*':
  1044. case '&':
  1045. case '^':
  1046. case '|':
  1047. case tokEQ:
  1048. case tokNEQ:
  1049. case '<':
  1050. case '>':
  1051. case tokLEQ:
  1052. case tokGEQ:
  1053. case tokULess:
  1054. case tokUGreater:
  1055. case tokULEQ:
  1056. case tokUGEQ:
  1057. GenPrep(idx);
  1058. oldIdxLeft = *idx;
  1059. GenPrep(idx);
  1060. // If the right operand isn't a constant, but the left operand is, swap the operands
  1061. // so the constant can become an immediate right operand in the instruction
  1062. t1 = stack[oldIdxRight][0];
  1063. t0 = stack[oldIdxLeft][0];
  1064. if (t1 != tokNumInt && t0 == tokNumInt)
  1065. {
  1066. int xor;
  1067. t1 = stack[oldIdxLeft][1];
  1068. memmove(stack[oldIdxLeft], stack[oldIdxLeft + 1], (oldIdxRight - oldIdxLeft) * sizeof(stack[0]));
  1069. stack[oldIdxRight][0] = t0;
  1070. stack[oldIdxRight][1] = t1;
  1071. switch (tok)
  1072. {
  1073. case '<':
  1074. case '>':
  1075. xor = '<' ^ '>'; break;
  1076. case tokLEQ:
  1077. case tokGEQ:
  1078. xor = tokLEQ ^ tokGEQ; break;
  1079. case tokULess:
  1080. case tokUGreater:
  1081. xor = tokULess ^ tokUGreater; break;
  1082. case tokULEQ:
  1083. case tokUGEQ:
  1084. xor = tokULEQ ^ tokUGEQ; break;
  1085. default:
  1086. xor = 0; break;
  1087. }
  1088. tok ^= xor;
  1089. }
  1090. // Handle a few special cases and transform the instruction
  1091. if (stack[oldIdxRight][0] == tokNumInt)
  1092. {
  1093. unsigned m = truncUint(stack[oldIdxRight][1]);
  1094. switch (tok)
  1095. {
  1096. case '*':
  1097. // Change multiplication to left shift, this helps indexing arrays of ints/pointers/etc
  1098. if (m && !(m & (m - 1)))
  1099. {
  1100. t1 = 0;
  1101. while (m >>= 1) t1++;
  1102. stack[oldIdxRight][1] = t1;
  1103. tok = tokLShift;
  1104. }
  1105. break;
  1106. case tokLEQ:
  1107. // left <= const will later change to left < const+1, but const+1 must be <=0x7FFFFFFF
  1108. if (m == 0x7FFFFFFF)
  1109. {
  1110. // left <= 0x7FFFFFFF is always true, change to the equivalent left >= 0u
  1111. stack[oldIdxRight][1] = 0;
  1112. tok = tokUGEQ;
  1113. }
  1114. break;
  1115. case tokULEQ:
  1116. // left <= const will later change to left < const+1, but const+1 must be <=0xFFFFFFFFu
  1117. if (m == 0xFFFFFFFF)
  1118. {
  1119. // left <= 0xFFFFFFFFu is always true, change to the equivalent left >= 0u
  1120. stack[oldIdxRight][1] = 0;
  1121. tok = tokUGEQ;
  1122. }
  1123. break;
  1124. case '>':
  1125. // left > const will later change to !(left < const+1), but const+1 must be <=0x7FFFFFFF
  1126. if (m == 0x7FFFFFFF)
  1127. {
  1128. // left > 0x7FFFFFFF is always false, change to the equivalent left & 0
  1129. stack[oldIdxRight][1] = 0;
  1130. tok = '&';
  1131. }
  1132. break;
  1133. case tokUGreater:
  1134. // left > const will later change to !(left < const+1), but const+1 must be <=0xFFFFFFFFu
  1135. if (m == 0xFFFFFFFF)
  1136. {
  1137. // left > 0xFFFFFFFFu is always false, change to the equivalent left & 0
  1138. stack[oldIdxRight][1] = 0;
  1139. tok = '&';
  1140. }
  1141. break;
  1142. }
  1143. }
  1144. stack[oldIdxRight + 1][0] = tok;
  1145. break;
  1146. case ')':
  1147. while (stack[*idx][0] != '(')
  1148. {
  1149. GenPrep(idx);
  1150. if (stack[*idx][0] == ',')
  1151. --*idx;
  1152. }
  1153. --*idx;
  1154. break;
  1155. default:
  1156. //error("GenPrep: unexpected token %s\n", GetTokenName(tok));
  1157. errorInternal(101);
  1158. }
  1159. }
  1160. /*
  1161. ; l <[u] 0 // slt[u] w, w, 0 "k"
  1162. l <[u] const // slt[u] w, w, const "m"
  1163. l <[u] r // slt[u] w, l, r "i"
  1164. * if (l < 0) // bgez w, Lskip "f"
  1165. if (l <[u] const) // slt[u] w, w, const; beq w, r0, Lskip "mc"
  1166. if (l <[u] r) // slt[u] w, l, r; beq w, r0, Lskip "ic"
  1167. ; l <=[u] 0 // slt[u] w, w, 1 "l"
  1168. l <=[u] const // slt[u] w, w, const + 1 "n"
  1169. l <=[u] r // slt[u] w, r, l; xor w, w, 1 "js"
  1170. * if (l <= 0) // bgtz w, Lskip "g"
  1171. if (l <=[u] const) // slt[u] w, w, const + 1; beq w, r0, Lskip "nc"
  1172. if (l <=[u] r) // slt[u] w, r, l; bne w, r0, Lskip "jd"
  1173. l >[u] 0 // slt[u] w, r0, w "o"
  1174. l >[u] const // slt[u] w, w, const + 1; xor w, w, 1 "ns"
  1175. l >[u] r // slt[u] w, r, l "j"
  1176. * if (l > 0) // blez w, Lskip "h"
  1177. **if (l >u 0) // beq w, r0, Lskip
  1178. if (l >[u] const) // slt[u] w, w, const + 1; bne w, r0, Lskip "nd"
  1179. if (l >[u] r) // slt[u] w, r, l; beq w, r0, Lskip "jc"
  1180. ; l >=[u] 0 // slt[u] w, w, 0; xor w, w, 1 "ks"
  1181. l >=[u] const // slt[u] w, w, const; xor w, w, 1 "ms"
  1182. l >=[u] r // slt[u] w, l, r; xor w, w, 1 "is"
  1183. * if (l >= 0) // bltz w, Lskip "e"
  1184. if (l >=[u] const) // slt[u] w, w, const; bne w, r0, Lskip "md"
  1185. if (l >=[u] r) // slt[u] w, l, r; bne w, r0, Lskip "id"
  1186. l == 0 // sltu w, w, 1 "q"
  1187. l == const // xor w, w, const; sltu w, w, 1 "tq"
  1188. l == r // xor w, l, r; sltu w, w, 1 "rq"
  1189. if (l == 0) // bne w, r0, Lskip "d"
  1190. if (l == const) // xor w, w, const; bne w, r0, Lskip "td"
  1191. if (l == r) // bne l, r, Lskip "b"
  1192. l != 0 // sltu w, r0, w "p"
  1193. l != const // xor w, w, const; sltu w, r0, w "tp"
  1194. l != r // xor w, l, r; sltu w, r0, w "rp"
  1195. if (l != 0) // beq w, r0, Lskip "c"
  1196. if (l != const) // xor w, w, const; beq w, r0, Lskip "tc"
  1197. if (l != r) // beq l, r, Lskip "a"
  1198. */
  1199. char CmpBlocks[6/*op*/][2/*condbranch*/][3/*constness*/][2] =
  1200. {
  1201. {
  1202. { "k", "m", "i" },
  1203. { "f", "mc", "ic" }
  1204. },
  1205. {
  1206. { "l", "n", "js" },
  1207. { "g", "nc", "jd" }
  1208. },
  1209. {
  1210. { "o", "ns", "j" },
  1211. { "h", "nd", "jc" }
  1212. },
  1213. {
  1214. { "ks", "ms", "is" },
  1215. { "e", "md", "id" }
  1216. },
  1217. {
  1218. { "q", "tq", "rq" },
  1219. { "d", "td", "b" }
  1220. },
  1221. {
  1222. { "p", "tp", "rp" },
  1223. { "c", "tc", "a" }
  1224. }
  1225. };
  1226. STATIC
  1227. void GenCmp(int* idx, int op)
  1228. {
  1229. // TODO:
  1230. /*
  1231. For B322 (not B32P!): direct conversion from MIPS to B322 is very inefficient, these notes help:
  1232. MIPS:
  1233. slt reg, s < t (reg := 1, else reg := 0)
  1234. B322 equivalent:
  1235. bge s >= t 2
  1236. load 1 reg
  1237. load 0 reg
  1238. */
  1239. /*
  1240. Inverses:
  1241. BEQ a b BNE a b
  1242. BNE a b BEQ a b
  1243. BLTZ a (a < 0) BGE a r0 (a >= 0)
  1244. BGEZ a (a >=0) BGT r0 a (a < 0) == (0 > a)
  1245. BGTZ a (a > 0) BGE r0 a (a <= 0) == (0 >= a)
  1246. BLEZ a (a <=0) BGT a r0 (a > 0)
  1247. */
  1248. // constness: 0 = zero const, 1 = non-zero const, 2 = non-const
  1249. int constness = (stack[*idx - 1][0] == tokNumInt) ? (stack[*idx - 1][1] != 0) : 2;
  1250. int constval = (constness == 1) ? truncInt(stack[*idx - 1][1]) : 0;
  1251. // condbranch: 0 = no conditional branch, 1 = branch if true, 2 = branch if false
  1252. int condbranch = (*idx + 1 < sp) ? (stack[*idx + 1][0] == tokIf) + (stack[*idx + 1][0] == tokIfNot) * 2 : 0;
  1253. int unsign = op >> 4;
  1254. int slt = unsign ? B32PInstrSLTU : B32PInstrSLT;
  1255. int label = condbranch ? stack[*idx + 1][1] : 0;
  1256. char* p;
  1257. int i;
  1258. op &= 0xF;
  1259. if (constness == 2)
  1260. GenPopReg();
  1261. // bltz, blez, bgez, bgtz are for signed comparison with 0 only,
  1262. // so for conditional branches on <0u, <=0u, >0u, >=0u use the general method instead
  1263. if (condbranch && op < 4 && constness == 0 && unsign)
  1264. {
  1265. // Except, >0u is more optimal as !=0
  1266. if (op == 2)
  1267. op = 5;
  1268. else
  1269. constness = 1;
  1270. }
  1271. p = CmpBlocks[op][condbranch != 0][constness];
  1272. for (i = 0; i < 2; i++)
  1273. {
  1274. switch (p[i])
  1275. {
  1276. case 'a':
  1277. condbranch ^= 3;
  1278. // fallthrough
  1279. case 'b':
  1280. GenPrintInstr3Operands((condbranch == 1) ? B32PInstrBNE : B32PInstrBEQ, 0,
  1281. GenLreg, 0,
  1282. GenRreg, 0,
  1283. B32POpConst, 2);
  1284. GenPrintInstr1Operand(B32PInstrJump, 0,
  1285. B32POpNumLabel, label);
  1286. break;
  1287. case 'c':
  1288. condbranch ^= 3;
  1289. // fallthrough
  1290. case 'd':
  1291. GenPrintInstr3Operands((condbranch == 1) ? B32PInstrBNE : B32PInstrBEQ, 0,
  1292. GenWreg, 0,
  1293. B32POpRegZero, 0,
  1294. B32POpConst, 2);
  1295. GenPrintInstr1Operand(B32PInstrJump, 0,
  1296. B32POpNumLabel, label);
  1297. break;
  1298. case 'e':
  1299. condbranch ^= 3;
  1300. // fallthrough
  1301. case 'f':
  1302. /*
  1303. BLTZ a (a < 0) BGE a r0 (a >= 0)
  1304. BGEZ a (a >=0) BGT r0 a (a < 0) == (0 > a)
  1305. */
  1306. if (condbranch == 1)
  1307. {
  1308. GenPrintInstr3Operands(B32PInstrBGE, 0,
  1309. GenWreg, 0,
  1310. B32POpRegZero, 0,
  1311. B32POpConst, 2);
  1312. }
  1313. else
  1314. {
  1315. GenPrintInstr3Operands(B32PInstrBGT, 0,
  1316. B32POpRegZero, 0,
  1317. GenWreg, 0,
  1318. B32POpConst, 2);
  1319. }
  1320. GenPrintInstr1Operand(B32PInstrJump, 0,
  1321. B32POpNumLabel, label);
  1322. break;
  1323. case 'g':
  1324. condbranch ^= 3;
  1325. // fallthrough
  1326. case 'h':
  1327. /*
  1328. BGTZ a (a > 0) BGE r0 a (a <= 0) == (0 >= a)
  1329. BLEZ a (a <=0) BGT a r0 (a > 0)
  1330. */
  1331. if (condbranch == 1)
  1332. {
  1333. GenPrintInstr3Operands(B32PInstrBGE, 0,
  1334. B32POpRegZero, 0,
  1335. GenWreg, 0,
  1336. B32POpConst, 2);
  1337. }
  1338. else
  1339. {
  1340. GenPrintInstr3Operands(B32PInstrBGT, 0,
  1341. GenWreg, 0,
  1342. B32POpRegZero, 0,
  1343. B32POpConst, 2);
  1344. }
  1345. GenPrintInstr1Operand(B32PInstrJump, 0,
  1346. B32POpNumLabel, label);
  1347. break;
  1348. case 'i':
  1349. GenPrintInstr3Operands(slt, 0,
  1350. GenLreg, 0,
  1351. GenRreg, 0,
  1352. GenWreg, 0);
  1353. break;
  1354. case 'j':
  1355. GenPrintInstr3Operands(slt, 0,
  1356. GenRreg, 0,
  1357. GenLreg, 0,
  1358. GenWreg, 0);
  1359. break;
  1360. case 'k':
  1361. GenPrintInstr3Operands(slt, 0,
  1362. GenWreg, 0,
  1363. B32POpRegZero, 0,
  1364. GenWreg, 0);
  1365. break;
  1366. case 'l':
  1367. GenPrintInstr3Operands(slt, 0,
  1368. GenWreg, 0,
  1369. B32POpConst, 1,
  1370. GenWreg, 0);
  1371. break;
  1372. case 'n':
  1373. constval++;
  1374. // fallthrough
  1375. case 'm':
  1376. if (constval < 0x8000)
  1377. {
  1378. GenPrintInstr3Operands(slt, 0,
  1379. GenWreg, 0,
  1380. B32POpConst, constval,
  1381. GenWreg, 0);
  1382. }
  1383. else
  1384. {
  1385. GenPrintInstr2Operands(B32PInstrLoad, 0,
  1386. B32POpConst, constval,
  1387. TEMP_REG_A, 0);
  1388. GenPrintInstr3Operands(slt, 0,
  1389. GenWreg, 0,
  1390. TEMP_REG_A, 0,
  1391. GenWreg, 0);
  1392. }
  1393. break;
  1394. case 'o':
  1395. GenPrintInstr3Operands(slt, 0,
  1396. B32POpRegZero, 0,
  1397. GenWreg, 0,
  1398. GenWreg, 0);
  1399. break;
  1400. case 'p':
  1401. GenPrintInstr3Operands(B32PInstrSLTU, 0,
  1402. B32POpRegZero, 0,
  1403. GenWreg, 0,
  1404. GenWreg, 0);
  1405. break;
  1406. case 'q':
  1407. GenPrintInstr3Operands(B32PInstrSLTU, 0,
  1408. GenWreg, 0,
  1409. B32POpConst, 1,
  1410. GenWreg, 0);
  1411. break;
  1412. case 'r':
  1413. GenPrintInstr3Operands(B32PInstrXOR, 0,
  1414. GenLreg, 0,
  1415. GenRreg, 0,
  1416. GenWreg, 0);
  1417. break;
  1418. case 's':
  1419. GenPrintInstr3Operands(B32PInstrXOR, 0,
  1420. GenWreg, 0,
  1421. B32POpConst, 1,
  1422. GenWreg, 0);
  1423. break;
  1424. case 't':
  1425. if (constval < 0x8000)
  1426. {
  1427. GenPrintInstr3Operands(B32PInstrXOR, 0,
  1428. GenWreg, 0,
  1429. B32POpConst, constval,
  1430. GenWreg, 0);
  1431. }
  1432. else
  1433. {
  1434. GenPrintInstr2Operands(B32PInstrLoad, 0,
  1435. B32POpConst, constval,
  1436. TEMP_REG_A, 0);
  1437. GenPrintInstr3Operands(B32PInstrXOR, 0,
  1438. GenWreg, 0,
  1439. TEMP_REG_A, 0,
  1440. GenWreg, 0);
  1441. }
  1442. break;
  1443. }
  1444. }
  1445. *idx += condbranch != 0;
  1446. }
  1447. STATIC
  1448. int GenIsCmp(int t)
  1449. {
  1450. return
  1451. t == '<' ||
  1452. t == '>' ||
  1453. t == tokGEQ ||
  1454. t == tokLEQ ||
  1455. t == tokULess ||
  1456. t == tokUGreater ||
  1457. t == tokUGEQ ||
  1458. t == tokULEQ ||
  1459. t == tokEQ ||
  1460. t == tokNEQ;
  1461. }
  1462. // Improved register/stack-based code generator
  1463. // DONE: test 32-bit code generation
  1464. STATIC
  1465. void GenExpr0(void)
  1466. {
  1467. int i;
  1468. int gotUnary = 0;
  1469. int maxCallDepth = 0;
  1470. int callDepth = 0;
  1471. int paramOfs = 0;
  1472. int t = sp - 1;
  1473. if (stack[t][0] == tokIf || stack[t][0] == tokIfNot || stack[t][0] == tokReturn)
  1474. t--;
  1475. GenPrep(&t);
  1476. for (i = 0; i < sp; i++)
  1477. if (stack[i][0] == '(')
  1478. {
  1479. if (++callDepth > maxCallDepth)
  1480. maxCallDepth = callDepth;
  1481. }
  1482. else if (stack[i][0] == ')')
  1483. {
  1484. callDepth--;
  1485. }
  1486. CanUseTempRegs = maxCallDepth == 0;
  1487. TempsUsed = 0;
  1488. if (GenWreg != B32POpRegV0)
  1489. errorInternal(102);
  1490. for (i = 0; i < sp; i++)
  1491. {
  1492. int tok = stack[i][0];
  1493. int v = stack[i][1];
  1494. #ifndef NO_ANNOTATIONS
  1495. switch (tok)
  1496. {
  1497. case tokNumInt: printf2(" ; %d\n", truncInt(v)); break;
  1498. //case tokNumUint: printf2(" ; %uu\n", truncUint(v)); break;
  1499. case tokIdent: case tokRevIdent: printf2(" ; %s\n", IdentTable + v); break;
  1500. case tokLocalOfs: case tokRevLocalOfs: printf2(" ; local ofs\n"); break;
  1501. case ')': printf2(" ; ) fxn call\n"); break;
  1502. case tokUnaryStar: printf2(" ; * (read dereference)\n"); break;
  1503. case '=': printf2(" ; = (write dereference)\n"); break;
  1504. case tokShortCirc: printf2(" ; short-circuit "); break;
  1505. case tokGoto: printf2(" ; sh-circ-goto "); break;
  1506. case tokLogAnd: printf2(" ; short-circuit && target\n"); break;
  1507. case tokLogOr: printf2(" ; short-circuit || target\n"); break;
  1508. case tokIf: case tokIfNot: case tokReturn: break;
  1509. case tokNum0: printf2(" ; 0\n"); break;
  1510. case tokAssign0: printf2(" ; =\n"); break;
  1511. default: printf2(" ; %s\n", GetTokenName(tok)); break;
  1512. }
  1513. #endif
  1514. switch (tok)
  1515. {
  1516. case tokNumInt:
  1517. if (!(i + 1 < sp && ((t = stack[i + 1][0]) == '+' ||
  1518. t == '-' ||
  1519. t == '&' ||
  1520. t == '^' ||
  1521. t == '|' ||
  1522. t == tokLShift ||
  1523. t == tokRShift ||
  1524. t == tokURShift ||
  1525. GenIsCmp(t))))
  1526. {
  1527. if (gotUnary)
  1528. GenPushReg();
  1529. GenPrintInstr2Operands(B32PInstrLoad, 0,
  1530. B32POpConst, v,
  1531. GenWreg, 0);
  1532. }
  1533. gotUnary = 1;
  1534. break;
  1535. case tokIdent:
  1536. if (gotUnary)
  1537. GenPushReg();
  1538. if (!(i + 1 < sp && ((t = stack[i + 1][0]) == ')' ||
  1539. t == tokUnaryStar ||
  1540. t == tokInc ||
  1541. t == tokDec ||
  1542. t == tokPostInc ||
  1543. t == tokPostDec)))
  1544. {
  1545. GenPrintInstr2Operands(B32PInstrAddr2reg, 0,
  1546. B32POpLabel, v,
  1547. GenWreg, 0);
  1548. }
  1549. gotUnary = 1;
  1550. break;
  1551. case tokLocalOfs:
  1552. if (gotUnary)
  1553. GenPushReg();
  1554. if (!(i + 1 < sp && ((t = stack[i + 1][0]) == tokUnaryStar ||
  1555. t == tokInc ||
  1556. t == tokDec ||
  1557. t == tokPostInc ||
  1558. t == tokPostDec)))
  1559. {
  1560. GenPrintInstr3Operands(B32PInstrADD, 0,
  1561. B32POpRegFp, 0,
  1562. B32POpConst, v,
  1563. GenWreg, 0);
  1564. }
  1565. gotUnary = 1;
  1566. break;
  1567. case '(':
  1568. if (gotUnary)
  1569. GenPushReg();
  1570. gotUnary = 0;
  1571. if (maxCallDepth != 1 && v < 16)
  1572. GenGrowStack(16 - v);
  1573. paramOfs = v - 4;
  1574. if (maxCallDepth == 1 && paramOfs >= 0 && paramOfs <= 12)
  1575. {
  1576. // Work directly in A0-A3 instead of working in V0 and avoid copying V0 to A0-A3
  1577. GenWreg = B32POpRegA0 + division(paramOfs, 4); //(paramOfs >> 2); //division(paramOfs, 4);
  1578. }
  1579. break;
  1580. case ',':
  1581. if (maxCallDepth == 1)
  1582. {
  1583. if (paramOfs == 16)
  1584. {
  1585. // Got the last on-stack parameter, the rest will go in A0-A3
  1586. GenPushReg();
  1587. gotUnary = 0;
  1588. GenWreg = B32POpRegA3;
  1589. }
  1590. if (paramOfs >= 0 && paramOfs <= 12)
  1591. {
  1592. // Advance to the next An reg or revert to V0
  1593. if (paramOfs)
  1594. GenWreg--;
  1595. else
  1596. GenWreg = B32POpRegV0;
  1597. gotUnary = 0;
  1598. }
  1599. paramOfs -= 4;
  1600. }
  1601. break;
  1602. case ')':
  1603. GenLeaf = 0;
  1604. if (maxCallDepth != 1)
  1605. {
  1606. if (v >= 4)
  1607. GenPrintInstr2Operands(B32PInstrRead, 0,
  1608. B32POpIndRegSp, 0,
  1609. B32POpRegA0, 0);
  1610. if (v >= 8)
  1611. GenPrintInstr2Operands(B32PInstrRead, 0,
  1612. B32POpIndRegSp, 4,
  1613. B32POpRegA1, 0);
  1614. if (v >= 12)
  1615. GenPrintInstr2Operands(B32PInstrRead, 0,
  1616. B32POpIndRegSp, 8,
  1617. B32POpRegA2, 0);
  1618. if (v >= 16)
  1619. GenPrintInstr2Operands(B32PInstrRead, 0,
  1620. B32POpIndRegSp, 12,
  1621. B32POpRegA3, 0);
  1622. }
  1623. else
  1624. {
  1625. GenGrowStack(16);
  1626. }
  1627. if (stack[i - 1][0] == tokIdent)
  1628. {
  1629. GenPrintInstr1Operand(B32PInstrSavPC, 0,
  1630. B32POpRegRa, 0);
  1631. GenPrintInstr3Operands(B32PInstrADD, 0,
  1632. B32POpRegRa, 0,
  1633. B32POpConst, 3,
  1634. B32POpRegRa, 0);
  1635. GenPrintInstr1Operand(B32PInstrJump, 0,
  1636. B32POpLabel, stack[i - 1][1]);
  1637. }
  1638. else
  1639. {
  1640. GenPrintInstr1Operand(B32PInstrSavPC, 0,
  1641. B32POpRegRa, 0);
  1642. GenPrintInstr3Operands(B32PInstrADD, 0,
  1643. B32POpRegRa, 0,
  1644. B32POpConst, 3,
  1645. B32POpRegRa, 0);
  1646. GenPrintInstr2Operands(B32PInstrJumpr, 0,
  1647. B32POpConst, 0,
  1648. GenWreg, 0);
  1649. }
  1650. if (v < 16)
  1651. v = 16;
  1652. GenGrowStack(-v);
  1653. break;
  1654. case tokUnaryStar:
  1655. if (stack[i - 1][0] == tokIdent)
  1656. GenReadIdent(GenWreg, v, stack[i - 1][1]);
  1657. else if (stack[i - 1][0] == tokLocalOfs)
  1658. GenReadLocal(GenWreg, v, stack[i - 1][1]);
  1659. else
  1660. GenReadIndirect(GenWreg, GenWreg, v);
  1661. break;
  1662. case tokUnaryPlus:
  1663. break;
  1664. case '~': //nor
  1665. GenPrintInstr3Operands(B32PInstrOR, 0,
  1666. GenWreg, 0,
  1667. GenWreg, 0,
  1668. GenWreg, 0);
  1669. GenPrintInstr2Operands(B32PInstrNOT, 0,
  1670. GenWreg, 0,
  1671. GenWreg, 0);
  1672. break;
  1673. case tokUnaryMinus:
  1674. GenPrintInstr3Operands(B32PInstrSUB, 0,
  1675. B32POpRegZero, 0,
  1676. GenWreg, 0,
  1677. GenWreg, 0);
  1678. break;
  1679. case '+':
  1680. case '-':
  1681. case '*':
  1682. case '&':
  1683. case '^':
  1684. case '|':
  1685. case tokLShift:
  1686. case tokRShift:
  1687. case tokURShift:
  1688. if (stack[i - 1][0] == tokNumInt && tok != '*')
  1689. {
  1690. int instr = GenGetBinaryOperatorInstr(tok);
  1691. GenPrintInstr3Operands(instr, 0,
  1692. GenWreg, 0,
  1693. B32POpConst, stack[i - 1][1],
  1694. GenWreg, 0);
  1695. }
  1696. else
  1697. {
  1698. int instr = GenGetBinaryOperatorInstr(tok);
  1699. GenPopReg();
  1700. GenPrintInstr3Operands(instr, 0,
  1701. GenLreg, 0,
  1702. GenRreg, 0,
  1703. GenWreg, 0);
  1704. }
  1705. break;
  1706. case '/':
  1707. case tokUDiv:
  1708. case '%':
  1709. case tokUMod:
  1710. {
  1711. printf("DIVISION/MOD is not supported!\n");
  1712. /*
  1713. GenPopReg();
  1714. if (tok == '/' || tok == '%')
  1715. GenPrintInstr3Operands(MipsInstrDiv, 0,
  1716. B32POpRegZero, 0,
  1717. GenLreg, 0,
  1718. GenRreg, 0);
  1719. else
  1720. GenPrintInstr3Operands(MipsInstrDivU, 0,
  1721. B32POpRegZero, 0,
  1722. GenLreg, 0,
  1723. GenRreg, 0);
  1724. if (tok == '%' || tok == tokUMod)
  1725. GenPrintInstr1Operand(MipsInstrMfHi, 0,
  1726. GenWreg, 0);
  1727. else
  1728. GenPrintInstr1Operand(MipsInstrMfLo, 0,
  1729. GenWreg, 0);
  1730. */
  1731. }
  1732. break;
  1733. case tokInc:
  1734. case tokDec:
  1735. if (stack[i - 1][0] == tokIdent)
  1736. {
  1737. GenIncDecIdent(GenWreg, v, stack[i - 1][1], tok);
  1738. }
  1739. else if (stack[i - 1][0] == tokLocalOfs)
  1740. {
  1741. GenIncDecLocal(GenWreg, v, stack[i - 1][1], tok);
  1742. }
  1743. else
  1744. {
  1745. GenPrintInstr3Operands(B32PInstrOR, 0,
  1746. B32POpRegZero, 0,
  1747. GenWreg, 0,
  1748. TEMP_REG_A, 0);
  1749. GenIncDecIndirect(GenWreg, TEMP_REG_A, v, tok);
  1750. }
  1751. break;
  1752. case tokPostInc:
  1753. case tokPostDec:
  1754. if (stack[i - 1][0] == tokIdent)
  1755. {
  1756. GenPostIncDecIdent(GenWreg, v, stack[i - 1][1], tok);
  1757. }
  1758. else if (stack[i - 1][0] == tokLocalOfs)
  1759. {
  1760. GenPostIncDecLocal(GenWreg, v, stack[i - 1][1], tok);
  1761. }
  1762. else
  1763. {
  1764. GenPrintInstr3Operands(B32PInstrOR, 0,
  1765. B32POpRegZero, 0,
  1766. GenWreg, 0,
  1767. TEMP_REG_A, 0);
  1768. GenPostIncDecIndirect(GenWreg, TEMP_REG_A, v, tok);
  1769. }
  1770. break;
  1771. case tokPostAdd:
  1772. case tokPostSub:
  1773. {
  1774. int instr = GenGetBinaryOperatorInstr(tok);
  1775. GenPopReg();
  1776. if (GenWreg == GenLreg)
  1777. {
  1778. GenPrintInstr3Operands(B32PInstrOR, 0,
  1779. B32POpRegZero, 0,
  1780. GenLreg, 0,
  1781. TEMP_REG_B, 0);
  1782. GenReadIndirect(GenWreg, TEMP_REG_B, v);
  1783. GenPrintInstr3Operands(instr, 0,
  1784. GenWreg, 0,
  1785. GenRreg, 0,
  1786. TEMP_REG_A, 0);
  1787. GenWriteIndirect(TEMP_REG_B, TEMP_REG_A, v);
  1788. }
  1789. else
  1790. {
  1791. // GenWreg == GenRreg here
  1792. GenPrintInstr3Operands(B32PInstrOR, 0,
  1793. B32POpRegZero, 0,
  1794. GenRreg, 0,
  1795. TEMP_REG_B, 0);
  1796. GenReadIndirect(GenWreg, GenLreg, v);
  1797. GenPrintInstr3Operands(instr, 0,
  1798. GenWreg, 0,
  1799. TEMP_REG_B, 0,
  1800. TEMP_REG_B, 0);
  1801. GenWriteIndirect(GenLreg, TEMP_REG_B, v);
  1802. }
  1803. }
  1804. break;
  1805. case tokAssignAdd:
  1806. case tokAssignSub:
  1807. case tokAssignMul:
  1808. case tokAssignAnd:
  1809. case tokAssignXor:
  1810. case tokAssignOr:
  1811. case tokAssignLSh:
  1812. case tokAssignRSh:
  1813. case tokAssignURSh:
  1814. if (stack[i - 1][0] == tokRevLocalOfs || stack[i - 1][0] == tokRevIdent)
  1815. {
  1816. int instr = GenGetBinaryOperatorInstr(tok);
  1817. if (stack[i - 1][0] == tokRevLocalOfs)
  1818. GenReadLocal(TEMP_REG_B, v, stack[i - 1][1]);
  1819. else
  1820. GenReadIdent(TEMP_REG_B, v, stack[i - 1][1]);
  1821. GenPrintInstr3Operands(instr, 0,
  1822. TEMP_REG_B, 0,
  1823. GenWreg, 0,
  1824. GenWreg, 0);
  1825. if (stack[i - 1][0] == tokRevLocalOfs)
  1826. GenWriteLocal(GenWreg, v, stack[i - 1][1]);
  1827. else
  1828. GenWriteIdent(GenWreg, v, stack[i - 1][1]);
  1829. }
  1830. else
  1831. {
  1832. int instr = GenGetBinaryOperatorInstr(tok);
  1833. int lsaved, rsaved;
  1834. GenPopReg();
  1835. if (GenWreg == GenLreg)
  1836. {
  1837. GenPrintInstr3Operands(B32PInstrOR, 0,
  1838. B32POpRegZero, 0,
  1839. GenLreg, 0,
  1840. TEMP_REG_B, 0);
  1841. lsaved = TEMP_REG_B;
  1842. rsaved = GenRreg;
  1843. }
  1844. else
  1845. {
  1846. // GenWreg == GenRreg here
  1847. GenPrintInstr3Operands(B32PInstrOR, 0,
  1848. B32POpRegZero, 0,
  1849. GenRreg, 0,
  1850. TEMP_REG_B, 0);
  1851. rsaved = TEMP_REG_B;
  1852. lsaved = GenLreg;
  1853. }
  1854. GenReadIndirect(GenWreg, GenLreg, v); // destroys either GenLreg or GenRreg because GenWreg coincides with one of them
  1855. GenPrintInstr3Operands(instr, 0,
  1856. GenWreg, 0,
  1857. rsaved, 0,
  1858. GenWreg, 0);
  1859. GenWriteIndirect(lsaved, GenWreg, v);
  1860. }
  1861. GenExtendRegIfNeeded(GenWreg, v);
  1862. break;
  1863. case tokAssignDiv:
  1864. case tokAssignUDiv:
  1865. case tokAssignMod:
  1866. case tokAssignUMod:
  1867. if (stack[i - 1][0] == tokRevLocalOfs || stack[i - 1][0] == tokRevIdent)
  1868. {
  1869. if (stack[i - 1][0] == tokRevLocalOfs)
  1870. GenReadLocal(TEMP_REG_B, v, stack[i - 1][1]);
  1871. else
  1872. GenReadIdent(TEMP_REG_B, v, stack[i - 1][1]);
  1873. if (tok == tokAssignDiv || tok == tokAssignMod)
  1874. {
  1875. printf("DIVISION/MOD is not supported!\n");
  1876. /*
  1877. GenPrintInstr3Operands(MipsInstrDiv, 0,
  1878. B32POpRegZero, 0,
  1879. TEMP_REG_B, 0,
  1880. GenWreg, 0);*/
  1881. }
  1882. else
  1883. {
  1884. printf("DIVISION/MOD is not supported!\n");
  1885. /*
  1886. GenPrintInstr3Operands(MipsInstrDivU, 0,
  1887. B32POpRegZero, 0,
  1888. TEMP_REG_B, 0,
  1889. GenWreg, 0);*/
  1890. }
  1891. if (tok == tokAssignMod || tok == tokAssignUMod)
  1892. {
  1893. printf("DIVISION/MOD is not supported!\n");
  1894. /*
  1895. GenPrintInstr1Operand(MipsInstrMfHi, 0,
  1896. GenWreg, 0);*/
  1897. }
  1898. else
  1899. {
  1900. printf("DIVISION/MOD is not supported!\n");
  1901. /*
  1902. GenPrintInstr1Operand(MipsInstrMfLo, 0,
  1903. GenWreg, 0);*/
  1904. }
  1905. if (stack[i - 1][0] == tokRevLocalOfs)
  1906. GenWriteLocal(GenWreg, v, stack[i - 1][1]);
  1907. else
  1908. GenWriteIdent(GenWreg, v, stack[i - 1][1]);
  1909. }
  1910. else
  1911. {
  1912. int lsaved, rsaved;
  1913. GenPopReg();
  1914. if (GenWreg == GenLreg)
  1915. {
  1916. GenPrintInstr3Operands(B32PInstrOR, 0,
  1917. B32POpRegZero, 0,
  1918. GenLreg, 0,
  1919. TEMP_REG_B, 0);
  1920. lsaved = TEMP_REG_B;
  1921. rsaved = GenRreg;
  1922. }
  1923. else
  1924. {
  1925. // GenWreg == GenRreg here
  1926. GenPrintInstr3Operands(B32PInstrOR, 0,
  1927. B32POpRegZero, 0,
  1928. GenRreg, 0,
  1929. TEMP_REG_B, 0);
  1930. rsaved = TEMP_REG_B;
  1931. lsaved = GenLreg;
  1932. }
  1933. GenReadIndirect(GenWreg, GenLreg, v); // destroys either GenLreg or GenRreg because GenWreg coincides with one of them
  1934. if (tok == tokAssignDiv || tok == tokAssignMod)
  1935. {
  1936. printf("DIVISION/MOD is not supported!\n");
  1937. /*
  1938. GenPrintInstr3Operands(MipsInstrDiv, 0,
  1939. B32POpRegZero, 0,
  1940. GenWreg, 0,
  1941. rsaved, 0);*/
  1942. }
  1943. else
  1944. {
  1945. printf("DIVISION/MOD is not supported!\n");
  1946. /*
  1947. GenPrintInstr3Operands(MipsInstrDivU, 0,
  1948. B32POpRegZero, 0,
  1949. GenWreg, 0,
  1950. rsaved, 0);*/
  1951. }
  1952. if (tok == tokAssignMod || tok == tokAssignUMod)
  1953. {
  1954. printf("DIVISION/MOD is not supported!\n");
  1955. /*
  1956. GenPrintInstr1Operand(MipsInstrMfHi, 0,
  1957. GenWreg, 0);*/
  1958. }
  1959. else
  1960. {
  1961. printf("DIVISION/MOD is not supported!\n");
  1962. /*
  1963. GenPrintInstr1Operand(MipsInstrMfLo, 0,
  1964. GenWreg, 0);*/
  1965. }
  1966. GenWriteIndirect(lsaved, GenWreg, v);
  1967. }
  1968. GenExtendRegIfNeeded(GenWreg, v);
  1969. break;
  1970. case '=':
  1971. if (stack[i - 1][0] == tokRevLocalOfs)
  1972. {
  1973. GenWriteLocal(GenWreg, v, stack[i - 1][1]);
  1974. }
  1975. else if (stack[i - 1][0] == tokRevIdent)
  1976. {
  1977. GenWriteIdent(GenWreg, v, stack[i - 1][1]);
  1978. }
  1979. else
  1980. {
  1981. GenPopReg();
  1982. GenWriteIndirect(GenLreg, GenRreg, v);
  1983. if (GenWreg != GenRreg)
  1984. GenPrintInstr3Operands(B32PInstrOR, 0,
  1985. B32POpRegZero, 0,
  1986. GenRreg, 0,
  1987. GenWreg, 0);
  1988. }
  1989. GenExtendRegIfNeeded(GenWreg, v);
  1990. break;
  1991. case tokAssign0: // assignment of 0, while throwing away the expression result value
  1992. if (stack[i - 1][0] == tokRevLocalOfs)
  1993. {
  1994. GenWriteLocal(B32POpRegZero, v, stack[i - 1][1]);
  1995. }
  1996. else if (stack[i - 1][0] == tokRevIdent)
  1997. {
  1998. GenWriteIdent(B32POpRegZero, v, stack[i - 1][1]);
  1999. }
  2000. else
  2001. {
  2002. GenWriteIndirect(GenWreg, B32POpRegZero, v);
  2003. }
  2004. break;
  2005. case '<': GenCmp(&i, 0x00); break;
  2006. case tokLEQ: GenCmp(&i, 0x01); break;
  2007. case '>': GenCmp(&i, 0x02); break;
  2008. case tokGEQ: GenCmp(&i, 0x03); break;
  2009. case tokULess: GenCmp(&i, 0x10); break;
  2010. case tokULEQ: GenCmp(&i, 0x11); break;
  2011. case tokUGreater: GenCmp(&i, 0x12); break;
  2012. case tokUGEQ: GenCmp(&i, 0x13); break;
  2013. case tokEQ: GenCmp(&i, 0x04); break;
  2014. case tokNEQ: GenCmp(&i, 0x05); break;
  2015. case tok_Bool:
  2016. /* if 0 < wreg (if wreg > 0)
  2017. wreg = 1
  2018. else
  2019. wreg = 0
  2020. GenPrintInstr3Operands(MipsInstrSLTU, 0,
  2021. GenWreg, 0,
  2022. B32POpRegZero, 0,
  2023. GenWreg, 0);
  2024. */
  2025. GenPrintInstr3Operands(B32PInstrSLTU, 0,
  2026. B32POpRegZero, 0,
  2027. GenWreg, 0,
  2028. GenWreg, 0);
  2029. break;
  2030. case tokSChar:
  2031. /* just use as an int for now
  2032. GenPrintInstr3Operands(B32PInstrSHIFTL, 0,
  2033. GenWreg, 0,
  2034. B32POpConst, 24,
  2035. GenWreg, 0);
  2036. GenPrintInstr3Operands(B32PInstrSHIFTR, 0, //TODO this should have also replicated the sign bit (SRA)
  2037. GenWreg, 0,
  2038. B32POpConst, 24,
  2039. GenWreg, 0);
  2040. */
  2041. break;
  2042. case tokUChar:
  2043. /* just use as an int for now
  2044. GenPrintInstr3Operands(B32PInstrAND, 0,
  2045. GenWreg, 0,
  2046. B32POpConst, 0xFF,
  2047. GenWreg, 0);
  2048. */
  2049. break;
  2050. case tokShort:
  2051. /* just use as an int for now
  2052. GenPrintInstr3Operands(B32PInstrSHIFTL, 0,
  2053. GenWreg, 0,
  2054. B32POpConst, 16,
  2055. GenWreg, 0);
  2056. GenPrintInstr3Operands(B32PInstrSHIFTR, 0, //TODO this should have also replicated the sign bit (SRA)
  2057. GenWreg, 0,
  2058. B32POpConst, 16,
  2059. GenWreg, 0);
  2060. */
  2061. break;
  2062. case tokUShort:
  2063. /*
  2064. GenPrintInstr3Operands(MipsInstrAnd, 0,
  2065. GenWreg, 0,
  2066. GenWreg, 0,
  2067. B32POpConst, 0xFFFF);*/
  2068. /* just use as an int for now
  2069. GenPrintInstr3Operands(B32PInstrSHIFTL, 0,
  2070. GenWreg, 0,
  2071. B32POpConst, 16,
  2072. GenWreg, 0);
  2073. GenPrintInstr3Operands(B32PInstrSHIFTR, 0,
  2074. GenWreg, 0,
  2075. B32POpConst, 16,
  2076. GenWreg, 0);
  2077. */
  2078. break;
  2079. case tokShortCirc:
  2080. #ifndef NO_ANNOTATIONS
  2081. if (v >= 0)
  2082. printf2("&&\n");
  2083. else
  2084. printf2("||\n");
  2085. #endif
  2086. if (v >= 0)
  2087. GenJumpIfZero(v); // &&
  2088. else
  2089. GenJumpIfNotZero(-v); // ||
  2090. gotUnary = 0;
  2091. break;
  2092. case tokGoto:
  2093. #ifndef NO_ANNOTATIONS
  2094. printf2("goto\n");
  2095. #endif
  2096. GenJumpUncond(v);
  2097. gotUnary = 0;
  2098. break;
  2099. case tokLogAnd:
  2100. case tokLogOr:
  2101. GenNumLabel(v);
  2102. break;
  2103. case tokVoid:
  2104. gotUnary = 0;
  2105. break;
  2106. case tokRevIdent:
  2107. case tokRevLocalOfs:
  2108. case tokComma:
  2109. case tokReturn:
  2110. case tokNum0:
  2111. break;
  2112. case tokIf:
  2113. GenJumpIfNotZero(stack[i][1]);
  2114. break;
  2115. case tokIfNot:
  2116. GenJumpIfZero(stack[i][1]);
  2117. break;
  2118. default:
  2119. //error("Error: Internal Error: GenExpr0(): unexpected token %s\n", GetTokenName(tok));
  2120. errorInternal(103);
  2121. break;
  2122. }
  2123. }
  2124. if (GenWreg != B32POpRegV0)
  2125. errorInternal(104);
  2126. }
  2127. STATIC
  2128. void GenDumpChar(int ch)
  2129. {
  2130. if (ch < 0)
  2131. {
  2132. if (TokenStringLen)
  2133. printf2("\n");
  2134. return;
  2135. }
  2136. if (TokenStringLen == 0)
  2137. {
  2138. GenStartAsciiString();
  2139. //printf2("\"");
  2140. }
  2141. // Just print as ascii value
  2142. printf2("%d ", ch);
  2143. }
  2144. STATIC
  2145. void GenExpr(void)
  2146. {
  2147. GenExpr0();
  2148. }
  2149. STATIC
  2150. void GenFin(void)
  2151. {
  2152. // No idea what this does (something with structs??), so I just literally converted it to B32P asm
  2153. if (StructCpyLabel)
  2154. {
  2155. int lbl = LabelCnt++;
  2156. puts2(CodeHeaderFooter[0]);
  2157. GenNumLabel(StructCpyLabel);
  2158. //puts2(" move r2, r6\n" //r2 := r6
  2159. // " move r3, r6"); //r3 := r3
  2160. puts2(" or r0 r6 r2\n"
  2161. " or r0 r6 r3");
  2162. GenNumLabel(lbl);
  2163. //puts2(" lbu r6, 0 r5\n" // r6:=mem[r5]
  2164. // " addiu r5, r5, 1\n" // r5:= r5+1
  2165. // " addiu r4, r4, -1\n" // r4:= r4-1
  2166. // " sb r6, 0 r3\n" // mem[r3]:=r6
  2167. // " addiu r3, r3, 1"); // r3:= r3+1
  2168. puts2(" read 0 r5 r6\n"
  2169. " add r5 1 r5\n"
  2170. " sub r4 1 r4\n"
  2171. " write 0 r3 r6\n"
  2172. " add r3 1 r3");
  2173. //printf2(" bne r4, r0, "); GenPrintNumLabel(lbl); // if r4 != 0, jump to lbl
  2174. printf2("beq r4 r0 2\n");
  2175. printf2("jump ");GenPrintNumLabel(lbl);
  2176. puts2("");
  2177. puts2(" jumpr 0 r15");
  2178. puts2(CodeHeaderFooter[1]);
  2179. }
  2180. // Put all ending C specific wrapper code here
  2181. if (compileUserBDOS)
  2182. {
  2183. printf2(
  2184. ".code\n"
  2185. "; END OF COMPILED C CODE\n"
  2186. "\n"
  2187. "; Interrupt handlers for BDOS user program\n"
  2188. "; Has some administration before jumping to Label_int[ID]\n"
  2189. "; To prevent interfering with other stacks, they have their own stack\n"
  2190. "; Because this is a BDOS user program, the interrupts are called from the BDOS interrupt handlers\n"
  2191. "; Therefore, it should return to that interrupt handler and not use reti\n"
  2192. "\n"
  2193. "Int:\n"
  2194. "\n"
  2195. " load32 0x7BFFFF r13 ; initialize user int stack address\n"
  2196. " load32 0 r14 ; initialize base pointer address\n"
  2197. " addr2reg Return_Interrupt r1 ; get address of return function\n"
  2198. " or r0 r1 r15 ; copy return addr to r15\n"
  2199. " jump interrupt ; jump to interrupt handler of C program\n"
  2200. " ; should return to the address we just put on the stack\n"
  2201. " halt ; should not get here\n"
  2202. "\n"
  2203. "\n"
  2204. "; Function that is called after any interrupt handler from C has returned\n"
  2205. "; Rreturns to BDOS interrupt handler\n"
  2206. "Return_Interrupt:\n"
  2207. "\n"
  2208. " ; RETURN\n"
  2209. " pop r1\n"
  2210. " jumpr 3 r1\n"
  2211. "\n"
  2212. " halt ; should not get here\n"
  2213. );
  2214. }
  2215. else
  2216. {
  2217. printf2(
  2218. ".code\n"
  2219. "; END OF COMPILED C CODE\n"
  2220. "\n"
  2221. "; Interrupt handlers\n"
  2222. "; Has some administration before jumping to Label_int[ID]\n"
  2223. "; To prevent interfering with other stacks, they have their own stack\n"
  2224. "; Also, all registers have to be backed up and restored to hardware stack\n"
  2225. "; A return function has to be put on the stack as wel that the C code interrupt handler\n"
  2226. "; will jump to when it is done\n"
  2227. "\n"
  2228. "Int:\n"
  2229. " push r1\n"
  2230. " push r2\n"
  2231. " push r3\n"
  2232. " push r4\n"
  2233. " push r5\n"
  2234. " push r6\n"
  2235. " push r7\n"
  2236. " push r8\n"
  2237. " push r9\n"
  2238. " push r10\n"
  2239. " push r11\n"
  2240. " push r12\n"
  2241. " push r13\n"
  2242. " push r14\n"
  2243. " push r15\n"
  2244. "\n"
  2245. " load32 0x7FFFFF r13 ; initialize (BDOS) int stack address\n"
  2246. " load32 0 r14 ; initialize base pointer address\n"
  2247. " addr2reg Return_Interrupt r1 ; get address of return function\n"
  2248. " or r0 r1 r15 ; copy return addr to r15\n"
  2249. " jump interrupt ; jump to interrupt handler of C program\n"
  2250. " ; should return to the address we just put on the stack\n"
  2251. " halt ; should not get here\n"
  2252. "\n"
  2253. "\n"
  2254. "; Function that is called after any interrupt handler from C has returned\n"
  2255. "; Restores all registers and issues RETI instruction to continue from original code\n"
  2256. "Return_Interrupt:\n"
  2257. " pop r15\n"
  2258. " pop r14\n"
  2259. " pop r13\n"
  2260. " pop r12\n"
  2261. " pop r11\n"
  2262. " pop r10\n"
  2263. " pop r9\n"
  2264. " pop r8\n"
  2265. " pop r7\n"
  2266. " pop r6\n"
  2267. " pop r5\n"
  2268. " pop r4\n"
  2269. " pop r3\n"
  2270. " pop r2\n"
  2271. " pop r1\n"
  2272. "\n"
  2273. " reti ; return from interrrupt\n"
  2274. "\n"
  2275. " halt ; should not get here\n");
  2276. }
  2277. if (compileOS)
  2278. {
  2279. printf2(
  2280. ".code\n"
  2281. "\n; Syscall handler for OS\n"
  2282. "; Because this is not called during an interrupt, we use a different stack\n"
  2283. "; located at the end of BDOS heap\n"
  2284. "\n"
  2285. "Syscall:\n"
  2286. " load32 0x3FFFFF r13 ; initialize syscall stack address\n"
  2287. " load32 0 r14 ; initialize base pointer address\n"
  2288. " addr2reg Return_Syscall r1 ; get address of return function\n"
  2289. " or r0 r1 r15 ; copy return addr to r15\n"
  2290. " jump syscall ; jump to syscall handler of C program\n"
  2291. " ; should return to the address we just put on the stack\n"
  2292. " halt ; should not get here\n"
  2293. "\n"
  2294. "Return_Syscall:\n"
  2295. " pop r1\n"
  2296. " jumpr 3 r1\n"
  2297. "\n"
  2298. " halt ; should not get here\n"
  2299. );
  2300. }
  2301. }