asm.c 25 KB

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