stage1_assembler-2.s 14 KB

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