mescc_m1.g 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629
  1. # This file is part of asmc, a bootstrapping OS with minimal seed
  2. # Copyright (C) 2018 Giovanni Mascellani <gio@debian.org>
  3. # https://gitlab.com/giomasce/asmc
  4. # This file was ported from M1-macro.c, distributed with mescc-tools,
  5. # which has the following copyright notices:
  6. # Copyright (C) 2016 Jeremiah Orians
  7. # Copyright (C) 2017 Jan Nieuwenhuizen <janneke@gnu.org>
  8. # This program is free software: you can redistribute it and/or modify
  9. # it under the terms of the GNU General Public License as published by
  10. # the Free Software Foundation, either version 3 of the License, or
  11. # (at your option) any later version.
  12. # This program is distributed in the hope that it will be useful,
  13. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. # GNU General Public License for more details.
  16. # You should have received a copy of the GNU General Public License
  17. # along with this program. If not, see <https://www.gnu.org/licenses/>.
  18. const M1_MAX_STRING 4096
  19. const M1TOKEN_TYPE_MACRO 1
  20. const M1TOKEN_TYPE_STR 2
  21. const M1TOKEN_NEXT 0
  22. const M1TOKEN_TYPE 4
  23. const M1TOKEN_TEXT 8
  24. const M1TOKEN_EXPR 12
  25. const SIZEOF_M1TOKEN 16
  26. const M1CTX_SOURCE_FD 0
  27. const M1CTX_DEST_FD 4
  28. const SIZEOF_M1CTX 8
  29. fun m1_new_token 0 {
  30. $p
  31. @p SIZEOF_M1TOKEN 1 calloc = ;
  32. p ret ;
  33. }
  34. fun m1_reverse_list 1 {
  35. $head
  36. @head 0 param = ;
  37. $root
  38. @root 0 = ;
  39. while head 0 != {
  40. $next
  41. @next head M1TOKEN_NEXT take = ;
  42. head M1TOKEN_NEXT take_addr root = ;
  43. @root head = ;
  44. @head next = ;
  45. }
  46. root ret ;
  47. }
  48. fun m1_purge_line_comment 1 {
  49. $ctx
  50. @ctx 0 param = ;
  51. $fd
  52. @fd ctx M1CTX_SOURCE_FD take = ;
  53. $c
  54. @c fd vfs_read = ;
  55. while c '\n' != c '\r' != && {
  56. @c fd vfs_read = ;
  57. }
  58. }
  59. fun m1_store_atom 2 {
  60. $ctx
  61. $c
  62. @ctx 1 param = ;
  63. @c 0 param = ;
  64. $fd
  65. @fd ctx M1CTX_SOURCE_FD take = ;
  66. $store
  67. @store 1 M1_MAX_STRING 1 + calloc = ;
  68. $ch
  69. @ch c = ;
  70. $i
  71. @i 0 = ;
  72. $cont
  73. @cont 1 = ;
  74. while cont {
  75. store i + ch =c ;
  76. @ch fd vfs_read = ;
  77. @i i 1 + = ;
  78. @cont ch 9 != ch 10 != && ch 32 != && i M1_MAX_STRING <= && = ;
  79. }
  80. store ret ;
  81. }
  82. fun m1_store_string 2 {
  83. $ctx
  84. $c
  85. @ctx 1 param = ;
  86. @c 0 param = ;
  87. $fd
  88. @fd ctx M1CTX_SOURCE_FD take = ;
  89. $store
  90. @store 1 M1_MAX_STRING 1 + calloc = ;
  91. $ch
  92. @ch c = ;
  93. $i
  94. @i 0 = ;
  95. $cont
  96. @cont 1 = ;
  97. while cont {
  98. store i + ch =c ;
  99. @i i 1 + = ;
  100. @ch fd vfs_read = ;
  101. ch 0xffffffff != "m1_store_string: unmatched !" assert_msg ;
  102. M1_MAX_STRING i != "m1_store_string: max string size exceeded" assert_msg ;
  103. @cont c ch != = ;
  104. }
  105. store ret ;
  106. }
  107. fun m1_tokenize_line 2 {
  108. $ctx
  109. $head
  110. @ctx 1 param = ;
  111. @head 0 param = ;
  112. $fd
  113. @fd ctx M1CTX_SOURCE_FD take = ;
  114. $c
  115. $p
  116. while 1 {
  117. @c fd vfs_read = ;
  118. if 35 c == 59 c == || {
  119. ctx m1_purge_line_comment ;
  120. } else {
  121. if 9 c == 10 c == || 32 c == || ! {
  122. if 0xffffffff c == {
  123. head ret ;
  124. }
  125. @p m1_new_token = ;
  126. if 34 c == 39 c == || {
  127. p M1TOKEN_TEXT take_addr ctx c m1_store_string = ;
  128. p M1TOKEN_TYPE take_addr M1TOKEN_TYPE_STR = ;
  129. } else {
  130. p M1TOKEN_TEXT take_addr ctx c m1_store_atom = ;
  131. }
  132. p M1TOKEN_NEXT take_addr head = ;
  133. @head p = ;
  134. }
  135. }
  136. }
  137. }
  138. fun m1_set_expression 4 {
  139. $ctx
  140. $p
  141. $c
  142. $exp
  143. @ctx 3 param = ;
  144. @p 2 param = ;
  145. @c 1 param = ;
  146. @exp 0 param = ;
  147. $i
  148. @i p = ;
  149. while i 0 != {
  150. if i M1TOKEN_TYPE take M1TOKEN_TYPE_MACRO & ! {
  151. if i M1TOKEN_TEXT take c strcmp 0 == {
  152. i M1TOKEN_EXPR take_addr exp = ;
  153. }
  154. }
  155. @i i M1TOKEN_NEXT take = ;
  156. }
  157. }
  158. fun m1_identify_macros 2 {
  159. $ctx
  160. $p
  161. @ctx 1 param = ;
  162. @p 0 param = ;
  163. $i
  164. @i p = ;
  165. while i 0 != {
  166. if i M1TOKEN_TEXT take "DEFINE" strcmp 0 == {
  167. i M1TOKEN_TYPE take_addr M1TOKEN_TYPE_MACRO = ;
  168. i M1TOKEN_TEXT take_addr i M1TOKEN_NEXT take M1TOKEN_TEXT take = ;
  169. if i M1TOKEN_NEXT take M1TOKEN_NEXT take M1TOKEN_TYPE take M1TOKEN_TYPE_STR & {
  170. i M1TOKEN_EXPR take_addr i M1TOKEN_NEXT take M1TOKEN_NEXT take M1TOKEN_TEXT take 1 + = ;
  171. } else {
  172. i M1TOKEN_EXPR take_addr i M1TOKEN_NEXT take M1TOKEN_NEXT take M1TOKEN_TEXT take = ;
  173. }
  174. i M1TOKEN_NEXT take_addr i M1TOKEN_NEXT take M1TOKEN_NEXT take M1TOKEN_NEXT take = ;
  175. }
  176. @i i M1TOKEN_NEXT take = ;
  177. }
  178. }
  179. fun m1_line_macro 2 {
  180. $ctx
  181. $p
  182. @ctx 1 param = ;
  183. @p 0 param = ;
  184. $i
  185. @i p = ;
  186. while i 0 != {
  187. if i M1TOKEN_TYPE take M1TOKEN_TYPE_MACRO & {
  188. ctx i M1TOKEN_NEXT take i M1TOKEN_TEXT take i M1TOKEN_EXPR take m1_set_expression ;
  189. }
  190. @i i M1TOKEN_NEXT take = ;
  191. }
  192. }
  193. fun m1_hexify_string 2 {
  194. $ctx
  195. $p
  196. @ctx 1 param = ;
  197. @p 0 param = ;
  198. $table
  199. @table "0123456789ABCDEF" = ;
  200. $i
  201. @i p M1TOKEN_TEXT take 1 + strlen 4 / 1 + 8 * = ;
  202. $d
  203. @d 1 M1_MAX_STRING calloc = ;
  204. p M1TOKEN_EXPR take_addr d = ;
  205. while 0 i < {
  206. @i i 1 - = ;
  207. d i + 0x30 =c ;
  208. }
  209. while i M1_MAX_STRING < {
  210. if 0 p M1TOKEN_TEXT take i + 1 + **c == {
  211. @i M1_MAX_STRING = ;
  212. } else {
  213. d 2 i * + table p M1TOKEN_TEXT take i 1 + + **c 16 / + **c =c ;
  214. d 2 i * 1 + + table p M1TOKEN_TEXT take i 1 + + **c 16 % + **c =c ;
  215. @i i 1 + = ;
  216. }
  217. }
  218. }
  219. fun m1_process_string 2 {
  220. $ctx
  221. $p
  222. @ctx 1 param = ;
  223. @p 0 param = ;
  224. $i
  225. @i p = ;
  226. while i 0 != {
  227. if i M1TOKEN_TYPE take M1TOKEN_TYPE_STR & {
  228. if '\'' i M1TOKEN_TEXT take **c == {
  229. i M1TOKEN_EXPR take_addr i M1TOKEN_TEXT take 1 + = ;
  230. } else {
  231. if '\"' i M1TOKEN_TEXT take **c == {
  232. ctx i m1_hexify_string ;
  233. }
  234. }
  235. }
  236. @i i M1TOKEN_NEXT take = ;
  237. }
  238. }
  239. fun m1_preserve_other 2 {
  240. $ctx
  241. $p
  242. @ctx 1 param = ;
  243. @p 0 param = ;
  244. $i
  245. @i p = ;
  246. while i 0 != {
  247. if i M1TOKEN_EXPR take 0 == i M1TOKEN_TYPE take M1TOKEN_TYPE_MACRO & ! && {
  248. $c
  249. @c i M1TOKEN_TEXT take **c = ;
  250. if c '!' == c '@' == || c '$' == || c '%' == || c '&' == || c ':' == || {
  251. i M1TOKEN_EXPR take_addr i M1TOKEN_TEXT take = ;
  252. } else {
  253. 0 "m1_preserve_other: invalid other" assert_msg ;
  254. }
  255. }
  256. @i i M1TOKEN_NEXT take = ;
  257. }
  258. }
  259. fun m1_bound_values 4 {
  260. $disp
  261. $num
  262. $low
  263. $high
  264. @disp 3 param = ;
  265. @num 2 param = ;
  266. @low 1 param = ;
  267. @high 0 param = ;
  268. high disp < disp low < || ! "m1_bound_values: displacement does not fit" assert_msg ;
  269. }
  270. fun m1_range_check 2 {
  271. $disp
  272. $num
  273. @disp 1 param = ;
  274. @num 0 param = ;
  275. if 4 num == {
  276. ret ;
  277. }
  278. if 3 num == {
  279. disp num 0 8388608 - 16777216 m1_bound_values ;
  280. ret ;
  281. }
  282. if 2 num == {
  283. disp num 0 32768 - 65535 m1_bound_values ;
  284. ret ;
  285. }
  286. if 1 num == {
  287. disp num 0 128 - 255 m1_bound_values ;
  288. ret ;
  289. }
  290. 0 "m1_range_check: invalid byte number" assert_msg ;
  291. }
  292. fun m1_reverse_bit_order 1 {
  293. $c
  294. @c 0 param = ;
  295. if c 0 == {
  296. ret ;
  297. }
  298. if c 1 + **c 0 == {
  299. ret ;
  300. }
  301. $hold
  302. @hold c **c = ;
  303. c c 1 + **c =c ;
  304. c 1 + hold =c ;
  305. c 2 + m1_reverse_bit_order ;
  306. }
  307. fun m1_little_endian 1 {
  308. $start
  309. @start 0 param = ;
  310. $end
  311. @end start = ;
  312. $c
  313. @c start = ;
  314. while 0 end **c != {
  315. @end end 1 + = ;
  316. }
  317. $hold
  318. @end end 1 - = ;
  319. while start end < {
  320. @hold start **c = ;
  321. start end **c =c ;
  322. end hold =c ;
  323. @end end 1 - = ;
  324. @start start 1 + = ;
  325. }
  326. c m1_reverse_bit_order ;
  327. }
  328. fun m1_hex2char 1 {
  329. $c
  330. @c 0 param = ;
  331. if c 0 >= c 9 <= && {
  332. c 48 + ret ;
  333. }
  334. if c 10 >= c 15 <= && {
  335. c 55 + ret ;
  336. }
  337. 0 1 - ret ;
  338. }
  339. fun m1_char2hex 1 {
  340. $c
  341. @c 0 param = ;
  342. if c '0' >= c '9' <= && {
  343. c 48 - ret ;
  344. }
  345. if c 'a' >= c 'f' <= && {
  346. c 87 - ret ;
  347. }
  348. if c 'A' >= c 'F' <= && {
  349. c 55 - ret ;
  350. }
  351. 0 1 - ret ;
  352. }
  353. fun m1_char2dec 1 {
  354. $c
  355. @c 0 param = ;
  356. if c '0' >= c '9' <= && {
  357. c 48 - ret ;
  358. }
  359. 0 1 - ret ;
  360. }
  361. fun m1_stringify 5 {
  362. $s
  363. $digits
  364. $divisor
  365. $value
  366. $shift
  367. @s 4 param = ;
  368. @digits 3 param = ;
  369. @divisor 2 param = ;
  370. @value 1 param = ;
  371. @shift 0 param = ;
  372. $i
  373. @i value = ;
  374. if digits 1 > {
  375. @i s 1 + digits 1 - divisor value shift m1_stringify = ;
  376. }
  377. s i divisor 1 - & m1_hex2char =c ;
  378. i shift >> ret ;
  379. }
  380. fun m1_express_number 2 {
  381. $value
  382. $c
  383. @value 1 param = ;
  384. @c 0 param = ;
  385. $ch
  386. @ch 42 1 calloc = ;
  387. $size
  388. $num
  389. $shift
  390. $processed
  391. @processed 0 = ;
  392. if '!' c == {
  393. @num 1 = ;
  394. @value value 0xff & = ;
  395. @processed 1 = ;
  396. }
  397. if '@' c == {
  398. @num 2 = ;
  399. @value value 0xffff & = ;
  400. @processed 1 = ;
  401. }
  402. if '%' c == {
  403. @num 4 = ;
  404. @value value 0xffffffff & = ;
  405. @processed 1 = ;
  406. }
  407. processed "m1_express_number: invalid character" assert_msg ;
  408. value num m1_range_check ;
  409. @size num 2 * = ;
  410. @shift 4 = ;
  411. ch size 16 value shift m1_stringify ;
  412. ch m1_little_endian ;
  413. ch ret ;
  414. }
  415. fun m1_numerate_string 1 {
  416. $a
  417. @a 0 param = ;
  418. $count
  419. @count 0 = ;
  420. $index
  421. $negative
  422. if 0 a **c == {
  423. 0 ret ;
  424. }
  425. if a **c '0' == a 1 + **c 'x' == && {
  426. if a 2 + **c '-' == {
  427. @negative 1 = ;
  428. @index 3 = ;
  429. } else {
  430. @negative 0 = ;
  431. @index 2 = ;
  432. }
  433. while 0 a index + **c != {
  434. if a index + **c m1_char2hex 0 1 - == {
  435. 0 ret ;
  436. }
  437. @count count 16 * a index + **c m1_char2hex + = ;
  438. @index index 1 + = ;
  439. }
  440. } else {
  441. if a **c '-' == {
  442. @negative 1 = ;
  443. @index 1 = ;
  444. } else {
  445. @negative 0 = ;
  446. @index 0 = ;
  447. }
  448. while 0 a index + **c != {
  449. if a index + **c m1_char2dec 0 1 - == {
  450. 0 ret ;
  451. }
  452. @count count 10 * a index + **c m1_char2dec + = ;
  453. @index index 1 + = ;
  454. }
  455. }
  456. if negative {
  457. @count 0 count - = ;
  458. }
  459. count ret ;
  460. }
  461. fun m1_eval_immediates 1 {
  462. $p
  463. @p 0 param = ;
  464. $i
  465. @i p = ;
  466. while i 0 != {
  467. if i M1TOKEN_EXPR take 0 == i M1TOKEN_TYPE take M1TOKEN_TYPE_MACRO & ! && {
  468. $value
  469. @value i M1TOKEN_TEXT take 1 + m1_numerate_string = ;
  470. if '0' i M1TOKEN_TEXT take 1 + **c == 0 value != || {
  471. i M1TOKEN_EXPR take_addr value i M1TOKEN_TEXT take **c m1_express_number = ;
  472. }
  473. }
  474. @i i M1TOKEN_NEXT take = ;
  475. }
  476. }
  477. fun m1_print_hex 2 {
  478. $ctx
  479. $p
  480. @ctx 1 param = ;
  481. @p 0 param = ;
  482. $i
  483. @i p = ;
  484. while i 0 != {
  485. if i M1TOKEN_TYPE take M1TOKEN_TYPE_MACRO ^ {
  486. ctx M1CTX_DEST_FD take '\n' vfs_write ;
  487. ctx M1CTX_DEST_FD take i M1TOKEN_EXPR take vfs_write_string ;
  488. }
  489. @i i M1TOKEN_NEXT take = ;
  490. }
  491. ctx M1CTX_DEST_FD take '\n' vfs_write ;
  492. }
  493. fun m1_dealloc_list 1 {
  494. $head
  495. @head 0 param = ;
  496. $ptrs
  497. @ptrs 4 vector_init = ;
  498. $i
  499. @i head = ;
  500. while i 0 != {
  501. $tok
  502. @tok i = ;
  503. @i i M1TOKEN_NEXT take = ;
  504. $ptr
  505. @ptr tok M1TOKEN_TEXT take = ;
  506. if ptrs ptr vector_has ! {
  507. ptrs ptr vector_push_back ;
  508. ptr free ;
  509. }
  510. @ptr tok M1TOKEN_EXPR take = ;
  511. if ptrs ptr vector_has ! {
  512. ptrs ptr vector_push_back ;
  513. ptr free ;
  514. }
  515. tok free ;
  516. }
  517. ptrs vector_destroy ;
  518. }
  519. fun m1_assemble 2 {
  520. $files
  521. $outfile
  522. @files 1 param = ;
  523. @outfile 0 param = ;
  524. $ctx
  525. @ctx SIZEOF_M1CTX malloc = ;
  526. $head
  527. @head 0 = ;
  528. ctx M1CTX_DEST_FD take_addr outfile vfs_open = ;
  529. ctx M1CTX_DEST_FD take vfs_truncate ;
  530. $i
  531. @i 0 = ;
  532. while i files vector_size < {
  533. $name
  534. @name files i vector_at = ;
  535. ctx M1CTX_SOURCE_FD take_addr name vfs_open = ;
  536. @head ctx head m1_tokenize_line = ;
  537. ctx M1CTX_SOURCE_FD take vfs_close ;
  538. @i i 1 + = ;
  539. }
  540. head 0 != "m1_assemble: empty content" assert_msg ;
  541. @head head m1_reverse_list = ;
  542. ctx head m1_identify_macros ;
  543. ctx head m1_line_macro ;
  544. ctx head m1_process_string ;
  545. head m1_eval_immediates ;
  546. ctx head m1_preserve_other ;
  547. ctx head m1_print_hex ;
  548. ctx M1CTX_DEST_FD take vfs_close ;
  549. head m1_dealloc_list ;
  550. ctx free ;
  551. #"Assembled dump:\n" log ;
  552. #outfile dump_file ;
  553. #"\n" log ;
  554. }
  555. fun m1_test 0 {
  556. $files
  557. @files 4 vector_init = ;
  558. files "/disk1/test/test.m1" strdup vector_push_back ;
  559. files "/ram/assembled" m1_assemble ;
  560. files free_vect_of_ptrs ;
  561. }