backend.c 73 KB

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