stage1_assembler-2.s 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493
  1. ; Copyright (C) 2016 Jeremiah Orians
  2. ; This file is part of stage0.
  3. ;
  4. ; stage0 is free software: you can redistribute it and/or modify
  5. ; it under the terms of the GNU General Public License as published by
  6. ; the Free Software Foundation, either version 3 of the License, or
  7. ; (at your option) any later version.
  8. ;
  9. ; stage0 is distributed in the hope that it will be useful,
  10. ; but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. ; GNU General Public License for more details.
  13. ;
  14. ; You should have received a copy of the GNU General Public License
  15. ; along with stage0. If not, see <http://www.gnu.org/licenses/>.
  16. ;; Node format:
  17. ;; PREV->pointer (register size)
  18. ;; Address (register size)
  19. ;; NULL terminated string (strln + 1)
  20. :start
  21. ;; R1 is reserved for reading/writing bytes (don't touch)
  22. ;; We will be using R8 for our malloc pointer
  23. ;; We will be using R9 for our header size in bytes
  24. ;; We will be using R10 for our toggle
  25. ;; We will be using R11 for our PC counter
  26. ;; We will be using R12 for holding our nybble
  27. ;; We will be using R13 for our register size in bytes
  28. ;; We will be using R14 for our head-node
  29. LOADUI R15 $stack ; We will be using R15 for our stack
  30. ;; Main program functionality
  31. ;; Reads in Tape_01 and writes out results onto Tape_02
  32. ;; Accepts no arguments and HALTS when done
  33. :main
  34. ;; Initialize header info
  35. READSCID R0 ; Get process capabilities
  36. ANDI R1 R0 0xF ; We only care about size nybble
  37. LOADUI R0 1 ; Assume we are 8bit
  38. SL0 R13 R0 R1 ; Let size nybble correct answer
  39. COPY R9 R13 ; Prepare Header size
  40. SL0I R9 1 ; Double to make proper size
  41. ;; Prep TAPE_01
  42. LOADUI R0 0x1100
  43. FOPEN_READ
  44. ;; Intialize environment
  45. LOADUI R1 0x1100 ; Read from tape_01
  46. FALSE R12 ; Set holder to zero
  47. FALSE R11 ; Set PC counter to zero
  48. FALSE R10 ; Our toggle
  49. LOADUI R8 0x700 ; Where we want our heap to start
  50. ;; Perform first pass
  51. CALLI R15 @first_pass
  52. ;; We need to rewind tape_01 to perform our second pass
  53. LOADUI R0 0x1100
  54. REWIND
  55. ;; Reintialize environment
  56. FALSE R12 ; Set holder to zero
  57. FALSE R11 ; Set PC counter to zero
  58. FALSE R10 ; Our toggle
  59. ;; Prep TAPE_02
  60. LOADUI R0 0x1101
  61. FOPEN_WRITE
  62. CALLI R15 @second_pass
  63. ;; Close up as we are done
  64. LOADUI R0 0x1100 ; Close TAPE_01
  65. FCLOSE
  66. LOADUI R0 0x1101 ; Close TAPE_02
  67. FCLOSE
  68. HALT
  69. ;; First pass function
  70. ;; Reads Tape_01 and creates our label table
  71. ;; Will Overwrite R0 R10 R11
  72. ;; Returns to Main function when done
  73. :first_pass
  74. FGETC ; Read a Char
  75. ;; Check for EOF
  76. CMPSKIPI.GE R0 0
  77. RET R15
  78. ;; Check for and deal with label (:)
  79. CMPSKIPI.NE R0 58
  80. JUMP @storeLabel
  81. ;; Check for and deal with pointers to labels
  82. ;; Starting with (@)
  83. CMPSKIPI.NE R0 64
  84. JUMP @ThrowAwayPointer
  85. ;; Then dealing with ($)
  86. CMPSKIPI.NE R0 36
  87. JUMP @ThrowAwayPointer
  88. ;; Now check for absolute addresses (&)
  89. CMPSKIPI.NE R0 38
  90. JUMP @ThrowAwayAddress
  91. ;; Otherwise attempt to process
  92. CALLI R15 @hex ; Convert it
  93. JUMP.NP R0 @first_pass ; Don't record, nonhex values
  94. ;; Flip the toggle
  95. NOT R10 R10
  96. JUMP.Z R10 @first_pass ; Jump if toggled
  97. ;; Deal with case of second half of byte
  98. ADDUI R11 R11 1 ; increment PC now that that we have a full byte
  99. JUMP @first_pass
  100. ;; Second pass function
  101. ;; Reads from Tape_01 and uses the values in the table
  102. ;; To write desired contents onto Tape_02
  103. ;; Will Overwrite R0 R10 R11
  104. ;; Returns to Main function when done
  105. :second_pass
  106. FGETC ; Read a Char
  107. ;; Check for EOF
  108. CMPSKIPI.GE R0 0
  109. RET R15
  110. ;; Check for and deal with label
  111. CMPSKIPI.NE R0 58
  112. JUMP @ThrowAwayLabel
  113. ;; Check for and deal with Pointers to labels
  114. CMPSKIPI.NE R0 64 ; @ for relative
  115. JUMP @StoreRelativePointer
  116. CMPSKIPI.NE R0 36 ; $ for absolute
  117. JUMP @StoreAbsolutePointer
  118. CMPSKIPI.NE R0 38 ; & for address
  119. JUMP @StoreAbsoluteAddress
  120. ;; Process everything else
  121. CALLI R15 @hex ; Attempt to Convert it
  122. CMPSKIPI.GE R0 0 ; Don't record, nonhex values
  123. JUMP @second_pass ; Move onto Next char
  124. ;; Determine if we got a full byte
  125. NOT R10 R10
  126. JUMP.Z R10 @second_pass_0 ; Jump if toggled
  127. ;; Deal with case of first half of byte
  128. ANDI R12 R0 0x0F ; Store our first nibble
  129. JUMP @second_pass
  130. :second_pass_0
  131. ;; Deal with case of second half of byte
  132. SL0I R12 4 ; Shift our first nybble
  133. ANDI R0 R0 0x0F ; Mask out top
  134. ADD R0 R0 R12 ; Combine nybbles
  135. LOADUI R1 0x1101 ; Write the combined byte
  136. FPUTC ; To TAPE_02
  137. LOADUI R1 0x1100 ; Read from tape_01
  138. ADDUI R11 R11 1 ; increment PC now that that we have a full byte
  139. JUMP @second_pass
  140. ;; Store Label function
  141. ;; Writes out the token and the current PC value
  142. ;; Its static variable for storing the next index to be used
  143. ;; Will overwrite R0
  144. ;; Returns to first pass when done
  145. :storeLabel
  146. COPY R0 R8 ; get current malloc
  147. ADD R8 R8 R9 ; update malloc
  148. ;; Add node info
  149. STOREX R11 R0 R13 ; Store the PC of the label
  150. STORE R14 R0 0 ; Store the Previous Head
  151. MOVE R14 R0 ; Update Head
  152. ;; Store the name of the Label
  153. CALLI R15 @writeout_token
  154. ;; And be done
  155. JUMP @first_pass
  156. ;; StoreRelativepointer function
  157. ;; Deals with the special case of relative pointers
  158. ;; Stores string
  159. ;; Finds match in Table
  160. ;; Writes out the offset
  161. ;; Modifies R0 R11
  162. ;; Jumps back into Pass2
  163. :StoreRelativePointer
  164. ;; Correct the PC to reflect the size of the pointer
  165. ADDUI R11 R11 2 ; Exactly 2 bytes
  166. CALLI R15 @Match_string ; Find the Match
  167. SUB R0 R0 R11 ; Determine the difference
  168. CALLI R15 @ProcessImmediate ; Write out the value
  169. JUMP @second_pass
  170. ;; StoreAbsolutepointer function
  171. ;; Deals with the special case of absolute pointers
  172. ;; Stores string
  173. ;; Finds match in Table
  174. ;; Writes out the absolute address of match
  175. ;; Modifies R0 R11
  176. ;; Jumps back into Pass2
  177. :StoreAbsolutePointer
  178. ;; Correct the PC to reflect the size of the pointer
  179. ADDUI R11 R11 2 ; Exactly 2 bytes
  180. CALLI R15 @Match_string ; Find the Match
  181. CALLI R15 @ProcessImmediate ; Write out the value
  182. JUMP @second_pass
  183. ;; StoreAbsoluteAddress function
  184. ;; Deal with the special case of absolute Addresses
  185. ;; Stores string
  186. ;; Finds match in Table
  187. ;; Writes out the full absolute address [32 bit machine]
  188. ;; Modifies R0 R11
  189. ;; Jumpbacs back into Pass2
  190. :StoreAbsoluteAddress
  191. ;; COrrect the PC to reflect the size of the address
  192. ADDUI R11 R11 4 ; 4 Bytes on 32bit machines
  193. CALLI R15 @Match_string ; Find the Match
  194. ANDI R2 R0 0xFFFF ; Save bottom half for next function
  195. SARI R0 16 ; Drop bottom 16 bits
  196. CALLI R15 @ProcessImmediate ; Write out top 2 bytes
  197. MOVE R0 R2 ; Use the saved 16bits
  198. CALLI R15 @ProcessImmediate ; Write out bottom 2 bytes
  199. JUMP @second_pass
  200. ;; Writeout Token Function
  201. ;; Writes the Token [minus first char] to the address
  202. ;; given by malloc and updates malloc pointer
  203. ;; Returns starting address of string
  204. :writeout_token
  205. ;; Preserve registers
  206. PUSHR R1 R15
  207. PUSHR R2 R15
  208. ;; Initialize
  209. COPY R2 R8 ; Get current malloc pointer
  210. ;; Our core loop
  211. :writeout_token_0
  212. FGETC ; Get another byte
  213. ;; Deal with termination cases
  214. CMPSKIPI.NE R0 32 ; Finished if space
  215. JUMP @writeout_token_done
  216. CMPSKIPI.NE R0 9 ; Finished if tab
  217. JUMP @writeout_token_done
  218. CMPSKIPI.NE R0 10 ; Finished if newline
  219. JUMP @writeout_token_done
  220. CMPSKIPI.NE R0 -1 ; Finished if EOF
  221. JUMP @writeout_token_done
  222. ;; Deal with valid input
  223. STORE8 R0 R8 0 ; Write out the byte
  224. ADDUI R8 R8 1 ; Increment
  225. JUMP @writeout_token_0 ; Keep looping
  226. ;; Clean up now that we are done
  227. :writeout_token_done
  228. ;; Fix malloc
  229. ADDUI R8 R8 1
  230. ;; Prepare for return
  231. MOVE R0 R2
  232. ;; Restore registers
  233. POPR R2 R15
  234. POPR R1 R15
  235. ;; And be done
  236. RET R15
  237. ;; Match string function
  238. ;; Walks down list until match is found or returns -1
  239. ;; Reads a token
  240. ;; Then returns address of match in R0
  241. ;; Returns to whatever called it
  242. :Match_string
  243. ;; Preserve registers
  244. PUSHR R1 R15
  245. PUSHR R2 R15
  246. ;; Initialize for Loop
  247. CALLI R15 @writeout_token ; Get our desired string
  248. MOVE R1 R0 ; Position our desired string
  249. COPY R2 R14 ; Begin at our head node
  250. ;; Loop until we find a match
  251. :Match_string_0
  252. ADD R0 R2 R9 ; Where the string is located
  253. CALLI R15 @strcmp
  254. JUMP.E R0 @Match_string_1 ; It is a match!
  255. ;; Prepare for next loop
  256. LOAD R2 R2 0 ; Move to next node
  257. JUMP.NZ R2 @Match_string_0 ; Keep looping
  258. TRUE R2 ; Set result to -1 if not found
  259. :Match_string_1
  260. ;; Store the correct answer
  261. CMPSKIPI.E R2 -1 ; Otherwise get the value
  262. LOADX R0 R2 R13 ; Get the value we care about
  263. ;; Restore registers
  264. POPR R2 R15
  265. POPR R1 R15
  266. RET R15
  267. ;; Our simple string compare function
  268. ;; Recieves two pointers in R0 and R1
  269. ;; Returns the difference between the strings in R0
  270. ;; Returns to whatever called it
  271. :strcmp
  272. ;; Preserve registers
  273. PUSHR R1 R15
  274. PUSHR R2 R15
  275. PUSHR R3 R15
  276. PUSHR R4 R15
  277. ;; Setup registers
  278. MOVE R2 R0
  279. MOVE R3 R1
  280. LOADUI R4 0
  281. :cmpbyte
  282. LOADXU8 R0 R2 R4 ; Get a byte of our first string
  283. LOADXU8 R1 R3 R4 ; Get a byte of our second string
  284. ADDUI R4 R4 1 ; Prep for next loop
  285. CMP R1 R0 R1 ; Compare the bytes
  286. CMPSKIPI.E R0 0 ; Stop if byte is NULL
  287. JUMP.E R1 @cmpbyte ; Loop if bytes are equal
  288. ;; Done
  289. MOVE R0 R1 ; Prepare for return
  290. ;; Restore registers
  291. POPR R4 R15
  292. POPR R3 R15
  293. POPR R2 R15
  294. POPR R1 R15
  295. RET R15
  296. ;; Processimmediate Function
  297. ;; Recieves an integer value in R0
  298. ;; Writes out the values to Tape_02
  299. ;; Doesn't modify registers
  300. ;; Returns to whatever called it
  301. :ProcessImmediate
  302. ;; Preserve registers
  303. PUSHR R0 R15
  304. PUSHR R1 R15
  305. PUSHR R2 R15
  306. ;; Break up Immediate
  307. ANDI R2 R0 0xFF ; Put lower byte in R2
  308. SARI R0 8 ; Drop Bottom byte from R0
  309. ANDI R0 R0 0xFF ; Maskout everything outside of top byte
  310. ;; Write out Top Byte
  311. LOADUI R1 0x1101 ; Write the byte
  312. FPUTC ; To TAPE_02
  313. ;; Write out bottom Byte
  314. MOVE R0 R2 ; Put Lower byte in R0
  315. FPUTC ; To TAPE_02
  316. ;; Restore registers
  317. POPR R2 R15
  318. POPR R1 R15
  319. POPR R0 R15
  320. ;; Be Done
  321. RET R15
  322. ;; ThrowAwaypointer function
  323. ;; Handle the special case of a generic problem
  324. ;; for Pass1, Will update R11 and modify R0
  325. ;; Will return to the start of first_pass
  326. ;; Never call this function, only jump to it
  327. :ThrowAwayPointer
  328. ADDUI R11 R11 2 ; Pointers always take up 2 bytes
  329. CALLI R15 @throwAwayToken ; Get rid of rest of token
  330. JUMP @first_pass ; Then return to the proper place
  331. ;; ThrowAwayAddress function
  332. ;; Handle the case of a 32bit absolute address storage
  333. ;; for Pass1, Will update R11 and modify R0
  334. ;; Will return to the start of first_pass
  335. ;; Never call this function, conly jump to it
  336. :ThrowAwayAddress
  337. ADDUI R11 R11 4 ; Addresses on 32bit systems take up 4 bytes
  338. CALLI R15 @throwAwayToken ; Get rid of rest of token
  339. JUMP @first_pass ; Then return to the proper place
  340. ;; ThrowAwaylabel function
  341. ;; Handle the special case of a generic problem
  342. ;; for Pass2, Will update R11 and modify R0
  343. ;; Will return to the start of second_pass
  344. ;; Never call this function, only jump to it
  345. :ThrowAwayLabel
  346. CALLI R15 @throwAwayToken ; Get rid of rest of token
  347. JUMP @second_pass
  348. ;; Throw away token function
  349. ;; Deals with the general case of not wanting
  350. ;; The rest of the characters in a token
  351. ;; This Will alter the values of R0 R1
  352. ;; Returns back to whatever called it
  353. :throwAwayToken
  354. FGETC ; Read a Char
  355. ;; Stop looping if space
  356. CMPSKIPI.NE R0 32
  357. RET R15
  358. ;; Stop looping if tab
  359. CMPSKIPI.NE R0 9
  360. RET R15
  361. ;; Stop looping if newline
  362. CMPSKIPI.NE R0 10
  363. RET R15
  364. ;; Stop looping if EOF
  365. CMPSKIPI.NE R0 -1
  366. RET R15
  367. ;; Otherwise keep looping
  368. JUMP @throwAwayToken
  369. ;; Hex function
  370. ;; This function is serving three purposes:
  371. ;; Identifying hex characters
  372. ;; Purging line comments
  373. ;; Returning the converted value of a hex character
  374. ;; This function will alter the values of R0
  375. ;; Returns back to whatever called it
  376. :hex
  377. ;; Deal with line comments starting with #
  378. CMPSKIPI.NE R0 35
  379. JUMP @ascii_comment
  380. ;; Deal with line comments starting with ;
  381. CMPSKIPI.NE R0 59
  382. JUMP @ascii_comment
  383. ;; Deal with all ascii less than '0'
  384. CMPSKIPI.GE R0 48
  385. JUMP @ascii_other
  386. ;; Deal with '0'-'9'
  387. CMPSKIPI.G R0 57
  388. JUMP @ascii_num
  389. ;; Deal with all ascii less than 'A'
  390. CMPSKIPI.GE R0 65
  391. JUMP @ascii_other
  392. ;; Unset high bit to set everything into uppercase
  393. ANDI R0 R0 0xDF
  394. ;; Deal with 'A'-'F'
  395. CMPSKIPI.G R0 70
  396. JUMP @ascii_high
  397. ;; Ignore the rest
  398. JUMP @ascii_other
  399. :ascii_num
  400. SUBUI R0 R0 48
  401. RET R15
  402. :ascii_high
  403. SUBUI R0 R0 55
  404. RET R15
  405. :ascii_comment
  406. FGETC ; Read another char
  407. JUMP.NP R0 @ascii_other ; Stop with EOF
  408. CMPSKIPI.E R0 10 ; Stop at the end of line
  409. JUMP @ascii_comment ; Otherwise keep looping
  410. :ascii_other
  411. TRUE R0
  412. RET R15
  413. ;; Where we will putting our stack
  414. :stack