Mirror of CollapseOS
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

233 lines
5.5KB

  1. ; *** Variables ***
  2. ; A bool flag indicating that we're on first pass. When we are, we don't care
  3. ; about actual output, but only about the length of each upcode. This means
  4. ; that when we parse instructions and directive that error out because of a
  5. ; missing symbol, we don't error out and just write down a dummy value.
  6. .equ ZASM_FIRST_PASS ZASM_RAMSTART
  7. ; whether we're in "local pass", that is, in local label scanning mode. During
  8. ; this special pass, ZASM_FIRST_PASS will also be set so that the rest of the
  9. ; code behaves as is we were in the first pass.
  10. .equ ZASM_LOCAL_PASS ZASM_FIRST_PASS+1
  11. ; What IO_PC was when we started our context
  12. .equ ZASM_CTX_PC ZASM_LOCAL_PASS+1
  13. ; current ".org" offset, that is, what we must offset all our label by.
  14. .equ ZASM_ORG ZASM_CTX_PC+2
  15. .equ ZASM_RAMEND ZASM_ORG+2
  16. ; Takes 2 byte arguments, blkdev in and blkdev out, expressed as IDs.
  17. ; Read file through blkdev in and outputs its upcodes through blkdev out.
  18. ; HL is set to the last lineno to be read.
  19. ; Sets Z on success, unset on error. On error, A contains an error code (ERR_*)
  20. zasmMain:
  21. ; Parse args. HL points to string already
  22. ; We don't allocate memory just to hold this. Because this happens
  23. ; before initialization, we don't really care where those args are
  24. ; parsed.
  25. ld de, .argspecs
  26. ld ix, ZASM_RAMSTART
  27. call parseArgs
  28. jr z, .goodargs
  29. ; bad args
  30. ld hl, 0
  31. ld de, 0
  32. ld a, SHELL_ERR_BAD_ARGS
  33. ret
  34. .goodargs:
  35. ; HL now points to parsed args
  36. ; Init I/O
  37. ld a, (ZASM_RAMSTART) ; blkdev in ID
  38. ld de, IO_IN_BLK
  39. call blkSel
  40. ld a, (ZASM_RAMSTART+1) ; blkdev out ID
  41. ld de, IO_OUT_BLK
  42. call blkSel
  43. ; Init modules
  44. xor a
  45. ld (ZASM_LOCAL_PASS), a
  46. ld (ZASM_ORG), a
  47. ld (ZASM_ORG+1), a
  48. call ioInit
  49. call symInit
  50. ; First pass
  51. ld hl, .sFirstPass
  52. call ioPrintLN
  53. ld a, 1
  54. ld (ZASM_FIRST_PASS), a
  55. call zasmParseFile
  56. jr nz, .end
  57. ; Second pass
  58. ld hl, .sSecondPass
  59. call ioPrintLN
  60. xor a
  61. ld (ZASM_FIRST_PASS), a
  62. ; before parsing the file for the second pass, let's clear the const
  63. ; registry. See comment in handleEQU.
  64. ld ix, SYM_CONST_REGISTRY
  65. call symClear
  66. call zasmParseFile
  67. .end:
  68. jp ioLineNo ; --> HL, --> DE, returns
  69. .argspecs:
  70. .db 0b001, 0b001, 0
  71. .sFirstPass:
  72. .db "First pass", 0
  73. .sSecondPass:
  74. .db "Second pass", 0
  75. ; Sets Z according to whether we're in first pass.
  76. zasmIsFirstPass:
  77. ld a, (ZASM_FIRST_PASS)
  78. cp 1
  79. ret
  80. ; Sets Z according to whether we're in local pass.
  81. zasmIsLocalPass:
  82. ld a, (ZASM_LOCAL_PASS)
  83. cp 1
  84. ret
  85. ; Set ZASM_ORG to specified number in HL
  86. zasmSetOrg:
  87. ld (ZASM_ORG), hl
  88. ret
  89. ; Return current PC (properly .org offsetted) in HL
  90. zasmGetPC:
  91. push de
  92. ld hl, (ZASM_ORG)
  93. ld de, (IO_PC)
  94. add hl, de
  95. pop de
  96. ret
  97. ; Repeatedly reads lines from IO, assemble them and spit the binary code in
  98. ; IO. Z is set on success, unset on error. DE contains the last line number to
  99. ; be read (first line is 1).
  100. zasmParseFile:
  101. call ioRewind
  102. .loop:
  103. call parseLine
  104. ret nz ; error
  105. ld a, b ; TOK_*
  106. cp TOK_EOF
  107. jr z, .eof
  108. jr .loop
  109. .eof:
  110. call zasmIsLocalPass
  111. jr nz, .end ; EOF and not local pass
  112. ; we're in local pass and EOF. Unwind this
  113. call _endLocalPass
  114. jr .loop
  115. .end:
  116. cp a ; ensure Z
  117. ret
  118. ; Parse next token and accompanying args (when relevant) in I/O, write the
  119. ; resulting opcode(s) through ioPutB and increases (IO_PC) by the number of
  120. ; bytes written. BC is set to the result of the call to tokenize.
  121. ; Sets Z if parse was successful, unset if there was an error. EOF is not an
  122. ; error. If there is an error, A is set to the corresponding error code (ERR_*).
  123. parseLine:
  124. call tokenize
  125. ld a, b ; TOK_*
  126. cp TOK_INSTR
  127. jp z, _parseInstr
  128. cp TOK_DIRECTIVE
  129. jp z, _parseDirec
  130. cp TOK_LABEL
  131. jr z, _parseLabel
  132. cp TOK_EOF
  133. ret z ; We're finished, no error.
  134. ; Bad token
  135. ld a, ERR_UNKNOWN
  136. jp unsetZ ; return with Z unset
  137. _parseInstr:
  138. ld a, c ; I_*
  139. jp parseInstruction
  140. _parseDirec:
  141. ld a, c ; D_*
  142. jp parseDirective
  143. _parseLabel:
  144. ; The string in (scratchpad) is a label with its trailing ':' removed.
  145. ld hl, scratchpad
  146. call zasmIsLocalPass
  147. jr z, .processLocalPass
  148. ; Is this a local label? If yes, we don't process it in the context of
  149. ; parseLine, whether it's first or second pass. Local labels are only
  150. ; parsed during the Local Pass
  151. call symIsLabelLocal
  152. jr z, .success ; local? don't do anything.
  153. ld ix, SYM_GLOBAL_REGISTRY
  154. call zasmIsFirstPass
  155. jr z, .registerLabel ; When we encounter a label in the first
  156. ; pass, we register it in the symbol
  157. ; list
  158. ; At this point, we're in second pass, we've encountered a global label
  159. ; and we'll soon continue processing our file. However, before we do
  160. ; that, we should process our local labels.
  161. call _beginLocalPass
  162. jr .success
  163. .processLocalPass:
  164. ld ix, SYM_LOCAL_REGISTRY
  165. call symIsLabelLocal
  166. jr z, .registerLabel ; local label? all good, register it
  167. ; normally
  168. ; not a local label? Then we need to end local pass
  169. call _endLocalPass
  170. jr .success
  171. .registerLabel:
  172. push hl
  173. call zasmGetPC
  174. ex de, hl
  175. pop hl
  176. call symRegister
  177. jr nz, .error
  178. ; continue to .success
  179. .success:
  180. xor a ; ensure Z
  181. ret
  182. .error:
  183. call unsetZ
  184. ret
  185. _beginLocalPass:
  186. ; remember were I/O was
  187. call ioSavePos
  188. ; Remember where PC was
  189. ld hl, (IO_PC)
  190. ld (ZASM_CTX_PC), hl
  191. ; Fake first pass
  192. ld a, 1
  193. ld (ZASM_FIRST_PASS), a
  194. ; Set local pass
  195. ld (ZASM_LOCAL_PASS), a
  196. ; Empty local label registry
  197. ld ix, SYM_LOCAL_REGISTRY
  198. jp symClear
  199. _endLocalPass:
  200. ; recall I/O pos
  201. call ioRecallPos
  202. ; recall PC
  203. ld hl, (ZASM_CTX_PC)
  204. ld (IO_PC), hl
  205. ; unfake first pass
  206. xor a
  207. ld (ZASM_FIRST_PASS), a
  208. ; Unset local pass
  209. ld (ZASM_LOCAL_PASS), a
  210. cp a ; ensure Z
  211. ret