1
0

asm.c 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925
  1. /*****************************************************************************/
  2. /* */
  3. /* ASM (B322 Assembler) */
  4. /* */
  5. /* Assembler for B322 */
  6. /* Specifically made to assemble the output of BCC on FPGC */
  7. /* Assembles for userBDOS specifically */
  8. /* */
  9. /* Main file */
  10. /* */
  11. /*****************************************************************************/
  12. /* Notes:
  13. - everything after the last \n is ignored, should not be a problem because wrapper
  14. - does not support includes or other things that are not used when using BCC
  15. - does not support asm defines, because of performance reasons
  16. - also does not keep track of line numbers for errors and does less checks for errors
  17. since the input is from BCC and therefore has some kind of standard
  18. */
  19. #define word char
  20. #define STDIO_FBUF_ADDR 0x440000
  21. #include "lib/math.c"
  22. #include "lib/sys.c"
  23. #include "lib/stdlib.c"
  24. #include "lib/fs.c"
  25. #include "lib/stdio.c"
  26. #define USERBDOS_OFFSET 0x400000 // applied offset to all labels
  27. #define OUTFILE_DATA_ADDR 0x500000
  28. #define OUTFILE_CODE_ADDR 0x540000
  29. #define OUTFILE_PASS1_ADDR 0x580000
  30. #define OUTFILE_PASS2_ADDR 0x600000
  31. #define LABELLISTLINENR_ADDR 0x65F000
  32. #define LABELLIST_ADDR 0x660000
  33. #define LINEBUFFER_ADDR 0x4C0000
  34. char infilename[96];
  35. char *lineBuffer = (char*) LINEBUFFER_ADDR;
  36. word memCursor = 0; // cursor for readMemLine
  37. word globalLineCursor = 0; // to keep track of the line number for labels
  38. #define LABELLIST_SIZE 2048 // expecting a lot of labels! as of writing, BDOS has ~1000 TODO: 2048 when done
  39. #define LABEL_NAME_SIZE 32 // max length of a label (therefore of a function name)
  40. char (*labelListName)[LABEL_NAME_SIZE] = (char (*)[LABEL_NAME_SIZE]) LABELLIST_ADDR; // 2d array containing all lines of the input file
  41. //char labelListName[LABELLIST_SIZE][LABEL_NAME_SIZE]; // old version, makes binary too large
  42. word* labelListLineNumber = (word*) LABELLISTLINENR_ADDR;
  43. //word labelListLineNumber[LABELLIST_SIZE]; // value should be the line number of the corresponding label name
  44. word labelListIndex = 0; // current index in the label list
  45. word prevLinesWereLabels = 0; // allows the current line to know how many labels are pointing to it
  46. // reads a line from the input file, tries to remove all extra characters
  47. word readFileLine()
  48. {
  49. word foundStart = 0;
  50. word foundComment = 0;
  51. word outputi = 0;
  52. char c = fgetc();
  53. char cprev = c;
  54. // stop on EOF or newline
  55. while (c != EOF && c != '\n')
  56. {
  57. // if we have found a comment, ignore everything after
  58. if (c == ';')
  59. {
  60. foundComment = 1;
  61. }
  62. if (!foundComment)
  63. {
  64. // if we have not found the first non-space yet, ignore until a non-space
  65. if (!foundStart)
  66. {
  67. if (c == ' ')
  68. {
  69. // do nothing until we find a non-space
  70. }
  71. else
  72. {
  73. foundStart = 1;
  74. lineBuffer[outputi] = c;
  75. outputi++;
  76. }
  77. }
  78. else
  79. {
  80. if (cprev == ' ' && c == ' ')
  81. {
  82. // ignore double space
  83. }
  84. else
  85. {
  86. lineBuffer[outputi] = c;
  87. outputi++;
  88. }
  89. }
  90. }
  91. cprev = c;
  92. c = fgetc();
  93. }
  94. lineBuffer[outputi] = 0; // terminate
  95. if (c == EOF)
  96. {
  97. if (lineBuffer[0] != 0)
  98. {
  99. // all code after the last \n is ignored!
  100. BDOS_PrintConsole("Skipped: ");
  101. BDOS_PrintConsole(lineBuffer);
  102. BDOS_PrintConsole("\n");
  103. }
  104. return EOF;
  105. }
  106. // if empty line, read next line
  107. if (outputi == 0)
  108. {
  109. return readFileLine();
  110. }
  111. else if (lineBuffer[outputi-1] == ' ')
  112. {
  113. // remove trailing space
  114. lineBuffer[outputi-1] = 0;
  115. }
  116. return 0;
  117. }
  118. // Reads a line from memory
  119. // Assumes all extra characters are already processed
  120. word readMemLine(char* memAddr)
  121. {
  122. word outputi = 0;
  123. char c = memAddr[memCursor];
  124. memCursor++;
  125. while (c != 0 && c != '\n')
  126. {
  127. lineBuffer[outputi] = c;
  128. outputi++;
  129. c = memAddr[memCursor];
  130. memCursor++;
  131. }
  132. lineBuffer[outputi] = 0; // terminate
  133. // memory ends with a 0
  134. if (c == 0)
  135. {
  136. return EOF;
  137. }
  138. // if empty line, read next line
  139. if (outputi == 0)
  140. {
  141. BDOS_PrintConsole("Empty string in readMemLine!!!\n");
  142. return EOF;
  143. }
  144. return 0;
  145. }
  146. // Fills bufOut with argi in linebuffer
  147. void getArgPos(word argi, char* bufOut)
  148. {
  149. word linei = 0;
  150. char c = 0;
  151. word lineLength = strlen(lineBuffer);
  152. while(argi > 0 && linei < lineLength)
  153. {
  154. c = lineBuffer[linei];
  155. if (c == ' ')
  156. {
  157. argi--;
  158. }
  159. linei++;
  160. }
  161. if (linei == 0)
  162. {
  163. BDOS_PrintConsole("getArgPos error");
  164. exit(1);
  165. }
  166. // copy until space or \n
  167. word i = 0;
  168. c = lineBuffer[linei];
  169. while (c != ' ' && c != 0)
  170. {
  171. bufOut[i] = c;
  172. linei++;
  173. i++;
  174. c = lineBuffer[linei];
  175. }
  176. bufOut[i] = 0; // terminate
  177. }
  178. // parses the number at argument i in linebuffer
  179. // can be hex or decimal or binary
  180. word getNumberAtArg(word argi)
  181. {
  182. word linei = 0;
  183. char c = 0;
  184. word lineLength = strlen(lineBuffer);
  185. while(argi > 0 && linei < lineLength)
  186. {
  187. c = lineBuffer[linei];
  188. if (c == ' ')
  189. {
  190. argi--;
  191. }
  192. linei++;
  193. }
  194. if (linei == 0)
  195. {
  196. BDOS_PrintConsole("NumberAtArg error");
  197. exit(1);
  198. }
  199. // linei is now at the start of the number string
  200. // copy until space or \n
  201. char strNumberBuf[36];
  202. word i = 0;
  203. c = lineBuffer[linei];
  204. while (c != ' ' && c != 0)
  205. {
  206. strNumberBuf[i] = c;
  207. linei++;
  208. i++;
  209. c = lineBuffer[linei];
  210. }
  211. strNumberBuf[i] = 0; // terminate
  212. word valueToReturn = 0;
  213. if (strNumberBuf[1] == 'x' || strNumberBuf[1] == 'X')
  214. {
  215. // hex number
  216. valueToReturn = hexToInt(strNumberBuf);
  217. }
  218. else if (strNumberBuf[1] == 'b' || strNumberBuf[1] == 'B')
  219. {
  220. // binary number
  221. valueToReturn = binToInt(strNumberBuf);
  222. }
  223. else
  224. {
  225. // dec number
  226. valueToReturn = decToInt(strNumberBuf);
  227. }
  228. return valueToReturn;
  229. }
  230. // returns 1 if the current line is a label
  231. word isLabel()
  232. {
  233. // loop until \0 or space
  234. word i = 0;
  235. while(lineBuffer[i] != 0 && lineBuffer[i] != ' ')
  236. {
  237. i++;
  238. }
  239. // empty line
  240. if (i == 0)
  241. {
  242. return 0;
  243. }
  244. // label if ends with :
  245. if (lineBuffer[i-1] == ':')
  246. {
  247. return 1;
  248. }
  249. return 0;
  250. }
  251. void Pass1StoreLabel()
  252. {
  253. // loop until \0 or space
  254. word labelStrLen = 0;
  255. while(lineBuffer[labelStrLen] != 0 && lineBuffer[labelStrLen] != ' ')
  256. {
  257. labelStrLen++;
  258. }
  259. // store label name minus the :
  260. memcpy(labelListName[labelListIndex], lineBuffer, labelStrLen-1);
  261. // terminate
  262. labelListName[labelListIndex][labelStrLen-1] = 0;
  263. labelListIndex++;
  264. // labelListLineNumber will be set when the next instruction is found
  265. // notify next line that it has a label
  266. prevLinesWereLabels++;
  267. }
  268. void Pass1StoreDefine()
  269. {
  270. // defines are not supported right now, so they are skipped
  271. }
  272. // Create two lines with the same args:
  273. // loadLabelLow
  274. // loadLabelHigh
  275. // returns the number of lines added
  276. word Pass1Addr2reg(char* outputAddr, char* outputCursor)
  277. {
  278. word lineBufArgsLen = strlen(lineBuffer) - 9; // minus addr2len and space
  279. // copy name of instruction
  280. memcpy((outputAddr + *outputCursor), "loadLabelLow ", 13);
  281. (*outputCursor) += 13;
  282. // copy args
  283. memcpy((outputAddr + *outputCursor), (lineBuffer+9), lineBufArgsLen);
  284. (*outputCursor) += lineBufArgsLen;
  285. // add a newline
  286. *(outputAddr + *outputCursor) = '\n';
  287. (*outputCursor)++;
  288. // copy name of instruction
  289. memcpy((outputAddr + *outputCursor), "loadLabelHigh ", 14);
  290. (*outputCursor) += 14;
  291. // copy args
  292. memcpy((outputAddr + *outputCursor), (lineBuffer+9), lineBufArgsLen);
  293. (*outputCursor) += lineBufArgsLen;
  294. // add a newline
  295. *(outputAddr + *outputCursor) = '\n';
  296. (*outputCursor)++;
  297. return 2;
  298. }
  299. // Converts into load and loadhi
  300. // skips loadhi if the value fits in 32bits
  301. // returns the number of lines added
  302. word Pass1Load32(char* outputAddr, char* outputCursor)
  303. {
  304. // get the destination register
  305. char dstRegBuf[16];
  306. getArgPos(2, dstRegBuf);
  307. word dstRegBufLen = strlen(dstRegBuf);
  308. // get and parse the value that is being loaded
  309. word load32Value = getNumberAtArg(1);
  310. // split into 16 bit unsigned values
  311. word mask16Bit = 0xFFFF;
  312. word lowVal = load32Value & mask16Bit;
  313. word highVal = ((unsigned) load32Value >> 16) & mask16Bit;
  314. // add lowval
  315. char buf[16];
  316. itoa(lowVal, buf);
  317. word buflen = strlen(buf);
  318. // copy name of instruction
  319. memcpy((outputAddr + *outputCursor), "load ", 5);
  320. (*outputCursor) += 5;
  321. // copy value
  322. memcpy((outputAddr + *outputCursor), buf, buflen);
  323. (*outputCursor) += buflen;
  324. // add a space
  325. *(outputAddr + *outputCursor) = ' ';
  326. (*outputCursor)++;
  327. // copy destination register
  328. memcpy((outputAddr + *outputCursor), dstRegBuf, dstRegBufLen);
  329. (*outputCursor) += dstRegBufLen;
  330. // add a newline
  331. *(outputAddr + *outputCursor) = '\n';
  332. (*outputCursor)++;
  333. // add highval
  334. if (highVal) // skip if 0
  335. {
  336. itoa(highVal, buf);
  337. word buflen = strlen(buf);
  338. // copy name of instruction
  339. memcpy((outputAddr + *outputCursor), "loadhi ", 7);
  340. (*outputCursor) += 7;
  341. // copy value
  342. memcpy((outputAddr + *outputCursor), buf, buflen);
  343. (*outputCursor) += buflen;
  344. // add a space
  345. *(outputAddr + *outputCursor) = ' ';
  346. (*outputCursor)++;
  347. // copy destination register
  348. memcpy((outputAddr + *outputCursor), dstRegBuf, dstRegBufLen);
  349. (*outputCursor) += dstRegBufLen;
  350. // add a newline
  351. *(outputAddr + *outputCursor) = '\n';
  352. (*outputCursor)++;
  353. return 2;
  354. }
  355. return 1;
  356. }
  357. // Creates a single .dw line using numBuf as value
  358. void addSingleDwLine(char* outputAddr, char* outputCursor, char* numBuf)
  359. {
  360. word numBufLen = strlen(numBuf);
  361. // copy name of instruction
  362. memcpy((outputAddr + *outputCursor), ".dw ", 4);
  363. (*outputCursor) += 4;
  364. // copy value
  365. memcpy((outputAddr + *outputCursor), numBuf, numBufLen);
  366. (*outputCursor) += numBufLen;
  367. // add a newline
  368. *(outputAddr + *outputCursor) = '\n';
  369. (*outputCursor)++;
  370. }
  371. // Puts each value after .dw on its own line with its own .dw prefix
  372. // returns the number of lines added
  373. word Pass1Dw(char* outputAddr, char* outputCursor)
  374. {
  375. word numberOfLinesAdded = 0;
  376. char numBuf[36]; // buffer to store each space separated number in
  377. word i = 0;
  378. word linei = 4; // index of linebuffer, start after .dw
  379. char c = lineBuffer[linei];
  380. while (c != 0)
  381. {
  382. if (c == ' ')
  383. {
  384. numBuf[i] = 0; // terminate
  385. addSingleDwLine(outputAddr, outputCursor, numBuf); // process number
  386. numberOfLinesAdded++;
  387. i = 0; // reset numBuf index
  388. }
  389. else
  390. {
  391. numBuf[i] = c;
  392. i++;
  393. }
  394. linei++;
  395. c = lineBuffer[linei];
  396. }
  397. numBuf[i] = 0; // terminate
  398. addSingleDwLine(outputAddr, outputCursor, numBuf); // process the final number
  399. numberOfLinesAdded++;
  400. return numberOfLinesAdded;
  401. }
  402. void Pass1Db(char* outputAddr, char* outputCursor)
  403. {
  404. BDOS_PrintConsole(".db is not yet implemented!\n");
  405. exit(1);
  406. }
  407. // Convert each line into the number of lines equal to the number of words in binary
  408. // Also reads defines and processes labels
  409. void LinePass1(char* outputAddr, char* outputCursor)
  410. {
  411. // non-instructions
  412. if (memcmp(lineBuffer, "define ", 7))
  413. {
  414. Pass1StoreDefine();
  415. }
  416. else if (isLabel())
  417. {
  418. Pass1StoreLabel();
  419. }
  420. else
  421. {
  422. // all instructions that can end up in multiple lines
  423. // set values to the labels (while loop, since multiple labels can point to the same addr)
  424. while(prevLinesWereLabels > 0)
  425. {
  426. labelListLineNumber[labelListIndex - prevLinesWereLabels] = globalLineCursor;
  427. prevLinesWereLabels--;
  428. }
  429. if (memcmp(lineBuffer, "addr2reg ", 9))
  430. {
  431. globalLineCursor += Pass1Addr2reg(outputAddr, outputCursor);
  432. }
  433. else if (memcmp(lineBuffer, "load32 ", 7))
  434. {
  435. globalLineCursor += Pass1Load32(outputAddr, outputCursor);
  436. }
  437. else if (memcmp(lineBuffer, ".dw ", 4))
  438. {
  439. globalLineCursor += Pass1Dw(outputAddr, outputCursor);
  440. }
  441. else if (memcmp(lineBuffer, ".db ", 4))
  442. {
  443. Pass1Db(outputAddr, outputCursor);
  444. }
  445. else
  446. {
  447. // just copy the line
  448. word lineBufLen = strlen(lineBuffer);
  449. memcpy((outputAddr + *outputCursor), lineBuffer, lineBufLen);
  450. (*outputCursor) += lineBufLen;
  451. // add a newline
  452. *(outputAddr + *outputCursor) = '\n';
  453. (*outputCursor)++;
  454. globalLineCursor++;
  455. }
  456. }
  457. }
  458. void doPass1()
  459. {
  460. BDOS_PrintConsole("Doing pass 1\n");
  461. memCursor = 0; // reset cursor for readMemLine
  462. globalLineCursor = 0; // keep track of the line number for the labels
  463. char* outfileCodeAddr = (char*) OUTFILE_CODE_ADDR; // read from
  464. char* outfilePass1Addr = (char*) OUTFILE_PASS1_ADDR; // write to
  465. word filePass1Cursor = 0;
  466. // add userBDOS header instructions
  467. memcpy(outfilePass1Addr, "jump Main\njump Int\njump Main\njump Main\n", 39);
  468. filePass1Cursor += 39;
  469. globalLineCursor += 5;
  470. while (readMemLine(outfileCodeAddr) != EOF)
  471. {
  472. LinePass1(outfilePass1Addr, &filePass1Cursor);
  473. }
  474. outfilePass1Addr[*(&filePass1Cursor)] = 0; // terminate
  475. }
  476. #include "pass2.c"
  477. void LinePass2(char* outputAddr, char* outputCursor)
  478. {
  479. // Go through all possible instructions:
  480. if (memcmp(lineBuffer, "halt", 4))
  481. pass2Halt(outputAddr, outputCursor);
  482. else if (memcmp(lineBuffer, "read ", 5))
  483. pass2Read(outputAddr, outputCursor);
  484. else if (memcmp(lineBuffer, "write ", 6))
  485. pass2Write(outputAddr, outputCursor);
  486. else if (memcmp(lineBuffer, "readintid ", 10))
  487. pass2Readintid(outputAddr, outputCursor);
  488. else if (memcmp(lineBuffer, "push ", 5))
  489. pass2Push(outputAddr, outputCursor);
  490. else if (memcmp(lineBuffer, "pop ", 4))
  491. pass2Pop(outputAddr, outputCursor);
  492. else if (memcmp(lineBuffer, "jump ", 5))
  493. pass2Jump(outputAddr, outputCursor);
  494. else if (memcmp(lineBuffer, "jumpo ", 6))
  495. pass2Jumpo(outputAddr, outputCursor);
  496. else if (memcmp(lineBuffer, "jumpr ", 6))
  497. pass2Jumpr(outputAddr, outputCursor);
  498. else if (memcmp(lineBuffer, "jumpro ", 7))
  499. pass2Jumpr(outputAddr, outputCursor);
  500. else if (memcmp(lineBuffer, "beq ", 4))
  501. pass2Beq(outputAddr, outputCursor);
  502. else if (memcmp(lineBuffer, "bgt ", 4))
  503. pass2Bgt(outputAddr, outputCursor);
  504. else if (memcmp(lineBuffer, "bgts ", 5))
  505. pass2Bgts(outputAddr, outputCursor);
  506. else if (memcmp(lineBuffer, "bge ", 4))
  507. pass2Bge(outputAddr, outputCursor);
  508. else if (memcmp(lineBuffer, "bges ", 5))
  509. pass2Bges(outputAddr, outputCursor);
  510. else if (memcmp(lineBuffer, "bne ", 4))
  511. pass2Bne(outputAddr, outputCursor);
  512. else if (memcmp(lineBuffer, "blt ", 4))
  513. pass2Blt(outputAddr, outputCursor);
  514. else if (memcmp(lineBuffer, "blts ", 5))
  515. pass2Blts(outputAddr, outputCursor);
  516. else if (memcmp(lineBuffer, "ble ", 4))
  517. pass2Ble(outputAddr, outputCursor);
  518. else if (memcmp(lineBuffer, "bles ", 5))
  519. pass2Bles(outputAddr, outputCursor);
  520. else if (memcmp(lineBuffer, "savpc ", 6))
  521. pass2Savpc(outputAddr, outputCursor);
  522. else if (memcmp(lineBuffer, "reti", 4))
  523. pass2Reti(outputAddr, outputCursor);
  524. else if (memcmp(lineBuffer, "or ", 3))
  525. pass2Or(outputAddr, outputCursor);
  526. else if (memcmp(lineBuffer, "and ", 4))
  527. pass2And(outputAddr, outputCursor);
  528. else if (memcmp(lineBuffer, "xor ", 4))
  529. pass2Xor(outputAddr, outputCursor);
  530. else if (memcmp(lineBuffer, "add ", 4))
  531. pass2Add(outputAddr, outputCursor);
  532. else if (memcmp(lineBuffer, "sub ", 4))
  533. pass2Sub(outputAddr, outputCursor);
  534. else if (memcmp(lineBuffer, "shiftl ", 7))
  535. pass2Shiftl(outputAddr, outputCursor);
  536. else if (memcmp(lineBuffer, "shiftr ", 7))
  537. pass2Shiftr(outputAddr, outputCursor);
  538. else if (memcmp(lineBuffer, "shiftrs ", 8))
  539. pass2Shiftrs(outputAddr, outputCursor);
  540. else if (memcmp(lineBuffer, "not ", 4))
  541. pass2Not(outputAddr, outputCursor);
  542. else if (memcmp(lineBuffer, "mults ", 6))
  543. pass2Mults(outputAddr, outputCursor);
  544. else if (memcmp(lineBuffer, "multu ", 6))
  545. pass2Multu(outputAddr, outputCursor);
  546. else if (memcmp(lineBuffer, "slt ", 4))
  547. pass2Slt(outputAddr, outputCursor);
  548. else if (memcmp(lineBuffer, "sltu ", 5))
  549. pass2Sltu(outputAddr, outputCursor);
  550. else if (memcmp(lineBuffer, "load ", 5))
  551. pass2Load(outputAddr, outputCursor);
  552. else if (memcmp(lineBuffer, "loadhi ", 7))
  553. pass2Loadhi(outputAddr, outputCursor);
  554. else if (memcmp(lineBuffer, "loadLabelLow ", 13))
  555. pass2LoadLabelLow(outputAddr, outputCursor);
  556. else if (memcmp(lineBuffer, "loadLabelHigh ", 14))
  557. pass2LoadLabelHigh(outputAddr, outputCursor);
  558. else if (memcmp(lineBuffer, "nop", 3))
  559. pass2Nop(outputAddr, outputCursor);
  560. else if (memcmp(lineBuffer, ".dw ", 4))
  561. pass2Dw(outputAddr, outputCursor);
  562. else if (memcmp(lineBuffer, ".dl ", 4))
  563. pass2Dl(outputAddr, outputCursor);
  564. else
  565. {
  566. BDOS_PrintConsole("Unknown instruction!\n");
  567. BDOS_PrintConsole(lineBuffer);
  568. BDOS_PrintConsole("\n");
  569. exit(1);
  570. }
  571. }
  572. // returns the length of the binary
  573. word doPass2()
  574. {
  575. BDOS_PrintConsole("Doing pass 2\n");
  576. memCursor = 0; // reset cursor for readMemLine
  577. char* outfilePass1Addr = (char*) OUTFILE_PASS1_ADDR; // read from
  578. char* outfilePass2Addr = (char*) OUTFILE_PASS2_ADDR; // write to
  579. word filePass2Cursor = 0;
  580. while (readMemLine(outfilePass1Addr) != EOF)
  581. {
  582. LinePass2(outfilePass2Addr, &filePass2Cursor);
  583. }
  584. return filePass2Cursor;
  585. }
  586. void moveDataDown()
  587. {
  588. char* outfileDataAddr = (char*) OUTFILE_DATA_ADDR;
  589. *outfileDataAddr = 0; // initialize to 0
  590. word fileDataCursor = 0;
  591. char* outfileCodeAddr = (char*) OUTFILE_CODE_ADDR;
  592. *outfileCodeAddr = 0; // initialize to 0
  593. word fileCodeCursor = 0;
  594. BDOS_PrintConsole("Looking for .data and .code sections\n");
  595. // .data, also do pass one on the code
  596. word inDataSection = 0;
  597. word inCodeSection = 0;
  598. while (readFileLine() != EOF)
  599. {
  600. if (memcmp(lineBuffer, ".data", 5))
  601. {
  602. inDataSection = 1;
  603. inCodeSection = 0;
  604. continue; // skip this line
  605. }
  606. if (memcmp(lineBuffer, ".rdata", 6))
  607. {
  608. inDataSection = 0;
  609. inCodeSection = 0;
  610. continue; // skip this line
  611. }
  612. if (memcmp(lineBuffer, ".code", 5))
  613. {
  614. inDataSection = 0;
  615. inCodeSection = 1;
  616. continue; // skip this line
  617. }
  618. if (memcmp(lineBuffer, ".bss", 4))
  619. {
  620. inDataSection = 0;
  621. inCodeSection = 0;
  622. continue; // skip this line
  623. }
  624. if (inDataSection)
  625. {
  626. // copy to data section
  627. word lineBufLen = strlen(lineBuffer);
  628. memcpy((outfileDataAddr + fileDataCursor), lineBuffer, lineBufLen);
  629. fileDataCursor += lineBufLen;
  630. // add a newline
  631. *(outfileDataAddr + fileDataCursor) = '\n';
  632. fileDataCursor++;
  633. }
  634. if (inCodeSection)
  635. {
  636. // copy to code section
  637. word lineBufLen = strlen(lineBuffer);
  638. memcpy((outfileCodeAddr + fileCodeCursor), lineBuffer, lineBufLen);
  639. fileCodeCursor += lineBufLen;
  640. // add a newline
  641. *(outfileCodeAddr + fileCodeCursor) = '\n';
  642. fileCodeCursor++;
  643. }
  644. }
  645. *(outfileCodeAddr+fileCodeCursor) = 0; // terminate code section
  646. // do not increment the codeCursor, because we will append the data section
  647. BDOS_PrintConsole("Looking for .rdata and .bss sections\n");
  648. // reopen file to reiterate
  649. fclose();
  650. fopenRead(infilename);
  651. //.rdata and .bss at the same time
  652. inDataSection = 0;
  653. while (readFileLine() != EOF)
  654. {
  655. if (memcmp(lineBuffer, ".data", 5))
  656. {
  657. inDataSection = 0;
  658. continue; // skip this line
  659. }
  660. if (memcmp(lineBuffer, ".rdata", 6))
  661. {
  662. inDataSection = 1;
  663. continue; // skip this line
  664. }
  665. if (memcmp(lineBuffer, ".code", 5))
  666. {
  667. inDataSection = 0;
  668. continue; // skip this line
  669. }
  670. if (memcmp(lineBuffer, ".bss", 4))
  671. {
  672. inDataSection = 1;
  673. continue; // skip this line
  674. }
  675. if (inDataSection)
  676. {
  677. // copy to data section
  678. word lineBufLen = strlen(lineBuffer);
  679. memcpy((outfileDataAddr + fileDataCursor), lineBuffer, lineBufLen);
  680. fileDataCursor += lineBufLen;
  681. // add a newline
  682. *(outfileDataAddr + fileDataCursor) = '\n';
  683. fileDataCursor++;
  684. }
  685. }
  686. *(outfileDataAddr+fileDataCursor) = 0; // terminate data section
  687. fileDataCursor++;
  688. BDOS_PrintConsole("Appending all to .code section\n");
  689. // append data section to code section, including \0
  690. memcpy((outfileCodeAddr+fileCodeCursor), outfileDataAddr, fileDataCursor);
  691. }
  692. int main()
  693. {
  694. BDOS_PrintConsole("B322 Assembler\n");
  695. // output file
  696. char outfilename[96];
  697. BDOS_GetArgN(2, outfilename);
  698. // Default to a.out
  699. if (outfilename[0] == 0)
  700. {
  701. strcat(outfilename, BDOS_GetPath());
  702. if (outfilename[strlen(outfilename)-1] != '/')
  703. {
  704. strcat(outfilename, "/");
  705. }
  706. strcat(outfilename, "A.OUT");
  707. }
  708. // Make full path if it is not already
  709. if (outfilename[0] != '/')
  710. {
  711. char bothPath[96];
  712. bothPath[0] = 0;
  713. strcat(bothPath, BDOS_GetPath());
  714. if (bothPath[strlen(bothPath)-1] != '/')
  715. {
  716. strcat(bothPath, "/");
  717. }
  718. strcat(bothPath, outfilename);
  719. strcpy(outfilename, bothPath);
  720. }
  721. // create output file, test if it can be created/opened
  722. if (!fopenWrite(outfilename))
  723. {
  724. BDOS_PrintConsole("Could not open outfile\n");
  725. return 0;
  726. }
  727. fclose();
  728. // input file
  729. BDOS_GetArgN(1, infilename);
  730. // Default to out.asm
  731. if (infilename[0] == 0)
  732. {
  733. strcat(infilename, BDOS_GetPath());
  734. if (infilename[strlen(infilename)-1] != '/')
  735. {
  736. strcat(infilename, "/");
  737. }
  738. strcat(infilename, "OUT.ASM");
  739. }
  740. // Make full path if it is not already
  741. if (infilename[0] != '/')
  742. {
  743. char bothPath[96];
  744. bothPath[0] = 0;
  745. strcat(bothPath, BDOS_GetPath());
  746. if (bothPath[strlen(bothPath)-1] != '/')
  747. {
  748. strcat(bothPath, "/");
  749. }
  750. strcat(bothPath, infilename);
  751. strcpy(infilename, bothPath);
  752. }
  753. // Open the input file
  754. if (!fopenRead(infilename))
  755. {
  756. BDOS_PrintConsole("Cannot open input file\n");
  757. return 1;
  758. }
  759. moveDataDown(); // move all data sections below the code sections
  760. fclose(); // done reading file, everything else can be done in memory
  761. doPass1();
  762. word pass2Length = doPass2();
  763. BDOS_PrintConsole("Writing to file\n");
  764. // write binary to output file
  765. if (!fopenWrite(outfilename))
  766. {
  767. BDOS_PrintConsole("Could not open outfile\n");
  768. return 0;
  769. }
  770. char* outfilePass2Addr = (char*) OUTFILE_PASS2_ADDR;
  771. fputData(outfilePass2Addr, pass2Length-1);
  772. fclose();
  773. return 0;
  774. }
  775. void interrupt()
  776. {
  777. // handle all interrupts
  778. word i = getIntID();
  779. switch(i)
  780. {
  781. case INTID_TIMER1:
  782. timer1Value = 1; // notify ending of timer1
  783. break;
  784. case INTID_TIMER2:
  785. break;
  786. case INTID_UART0:
  787. break;
  788. case INTID_GPU:
  789. break;
  790. case INTID_TIMER3:
  791. break;
  792. case INTID_PS2:
  793. break;
  794. case INTID_UART1:
  795. break;
  796. case INTID_UART2:
  797. break;
  798. }
  799. }