backend.c 73 KB

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