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.

298 lines
7.0KB

  1. ; I/Os in zasm
  2. ;
  3. ; As a general rule, I/O in zasm is pretty straightforward. We receive, as a
  4. ; parameter, two blockdevs: One that we can read and seek and one that we can
  5. ; write to (we never seek into it).
  6. ;
  7. ; This unit also has the responsibility of counting the number of written bytes,
  8. ; maintaining IO_PC and of properly disabling output on first pass.
  9. ;
  10. ; On top of that, this unit has the responsibility of keeping track of the
  11. ; current lineno. Whenever GetB is called, we check if the fetched byte is a
  12. ; newline. If it is, we increase our lineno. This unit is the best place to
  13. ; keep track of this because we have to handle ioRecallPos.
  14. ;
  15. ; zasm doesn't buffers its reads during tokenization, which simplifies its
  16. ; process. However, it also means that it needs, in certain cases, a "putback"
  17. ; mechanism, that is, a way to say "you see that character I've just read? that
  18. ; was out of my bounds. Could you make it as if I had never read it?". That
  19. ; buffer is one character big and is made with the expectation that ioPutBack
  20. ; is always called right after a ioGetB (when it's called).
  21. ;
  22. ; ioPutBack will mess up seek and tell offsets, so thath "put back" should be
  23. ; consumed before having to seek and tell.
  24. ;
  25. ; That's for the general rules.
  26. ;
  27. ; Now, let's enter includes. To simplify processing, we make include mostly
  28. ; transparent to all other units. They always read from ioGetB and a include
  29. ; directive should have the exact same effect as copy/pasting the contents of
  30. ; the included file in the caller.
  31. ;
  32. ; By the way: we don't support multiple level of inclusion. Only top level files
  33. ; can include.
  34. ;
  35. ; When we include, all we do here is open the file with fsOpen and set a flag
  36. ; indicating that we're inside an include. When that flag is on, GetB, Seek and
  37. ; Tell are transparently redirected to their fs* counterpart.
  38. ;
  39. ; When we reach EOF in an included file, we transparently unset the "in include"
  40. ; flag and continue on the general IN stream.
  41. ; *** Variables ***
  42. .equ IO_IN_BLK IO_RAMSTART
  43. .equ IO_OUT_BLK IO_IN_BLK+BLOCKDEV_SIZE
  44. ; Save pos for ioSavePos and ioRecallPos
  45. .equ IO_SAVED_POS IO_OUT_BLK+BLOCKDEV_SIZE
  46. ; File handle for included source
  47. .equ IO_INCLUDE_HDL IO_SAVED_POS+2
  48. ; blkdev for include file
  49. .equ IO_INCLUDE_BLK IO_INCLUDE_HDL+FS_HANDLE_SIZE
  50. ; see ioPutBack below
  51. .equ IO_PUTBACK_BUF IO_INCLUDE_BLK+BLOCKDEV_SIZE
  52. .equ IO_IN_INCLUDE IO_PUTBACK_BUF+1
  53. .equ IO_PC IO_IN_INCLUDE+1
  54. ; Current lineno in top-level file
  55. .equ IO_LINENO IO_PC+2
  56. ; Current lineno in include file
  57. .equ IO_INC_LINENO IO_LINENO+2
  58. ; Line number (can be top-level or include) when ioSavePos was last called.
  59. .equ IO_SAVED_LINENO IO_INC_LINENO+2
  60. ; Handle for the ioSpitBin
  61. .equ IO_BIN_HDL IO_SAVED_LINENO+2
  62. .equ IO_RAMEND IO_BIN_HDL+FS_HANDLE_SIZE
  63. ; *** Code ***
  64. ioInit:
  65. xor a
  66. ld (IO_PUTBACK_BUF), a
  67. ld (IO_IN_INCLUDE), a
  68. ld de, IO_INCLUDE_BLK
  69. ld hl, _ioIncBlk
  70. call blkSet
  71. jp ioResetCounters
  72. ioGetB:
  73. ld a, (IO_PUTBACK_BUF)
  74. or a ; cp 0
  75. jr nz, .getback
  76. call ioInInclude
  77. jr z, .normalmode
  78. ; We're in "include mode", read from FS
  79. ld ix, IO_INCLUDE_BLK
  80. call _blkGetB
  81. jr nz, .includeEOF
  82. cp 0x0a ; newline
  83. ret nz ; not newline? nothing to do
  84. ; We have newline. Increase lineno and return (the rest of the
  85. ; processing below isn't needed.
  86. push hl
  87. ld hl, (IO_INC_LINENO)
  88. inc hl
  89. ld (IO_INC_LINENO), hl
  90. pop hl
  91. ret
  92. .includeEOF:
  93. ; We reached EOF. What we do depends on whether we're in Local Pass
  94. ; mode. Yes, I know, a bit hackish. Normally, we *should* be
  95. ; transparently getting of include mode and avoid meddling with global
  96. ; states, but here, we need to tell main.asm that the local scope if
  97. ; over *before* we get off include mode, otherwise, our IO_SAVED_POS
  98. ; will be wrong (an include IO_SAVED_POS used in global IN stream).
  99. call zasmIsLocalPass
  100. ld a, 0 ; doesn't affect Z flag
  101. ret z ; local pass? return EOF
  102. ; regular pass (first or second)? transparently get off include mode.
  103. ld (IO_IN_INCLUDE), a ; A already 0
  104. ld (IO_INC_LINENO), a
  105. ld (IO_INC_LINENO+1), a
  106. ; continue on to "normal" reading. We don't want to return our zero
  107. .normalmode:
  108. ; normal mode, read from IN stream
  109. ld ix, IO_IN_BLK
  110. call _blkGetB
  111. cp 0x0a ; newline
  112. ret nz ; not newline? return
  113. ; inc current lineno
  114. push hl
  115. ld hl, IO_LINENO
  116. inc (hl)
  117. pop hl
  118. cp a ; ensure Z
  119. ret
  120. .getback:
  121. push af
  122. xor a
  123. ld (IO_PUTBACK_BUF), a
  124. pop af
  125. ret
  126. _callIX:
  127. jp (ix)
  128. ret
  129. ; Put back non-zero character A into the "ioGetB stack". The next ioGetB call,
  130. ; instead of reading from IO_IN_BLK, will return that character. That's the
  131. ; easiest way I found to handle the readWord/gotoNextLine problem.
  132. ioPutBack:
  133. ld (IO_PUTBACK_BUF), a
  134. ret
  135. ioPutB:
  136. push hl ; --> lvl 1
  137. ld hl, (IO_PC)
  138. inc hl
  139. ld (IO_PC), hl
  140. pop hl ; <-- lvl 1
  141. push af ; --> lvl 1
  142. call zasmIsFirstPass
  143. jr z, .skip
  144. pop af ; <-- lvl 1
  145. push ix ; --> lvl 1
  146. ld ix, IO_OUT_BLK
  147. call _blkPutB
  148. pop ix ; <-- lvl 1
  149. ret
  150. .skip:
  151. pop af ; <-- lvl 1
  152. cp a ; ensure Z
  153. ret
  154. ioSavePos:
  155. ld hl, (IO_LINENO)
  156. call ioInInclude
  157. jr z, .skip
  158. ld hl, (IO_INC_LINENO)
  159. .skip:
  160. ld (IO_SAVED_LINENO), hl
  161. call _ioTell
  162. ld (IO_SAVED_POS), hl
  163. ret
  164. ioRecallPos:
  165. ld hl, (IO_SAVED_LINENO)
  166. call ioInInclude
  167. jr nz, .include
  168. ld (IO_LINENO), hl
  169. jr .recallpos
  170. .include:
  171. ld (IO_INC_LINENO), hl
  172. .recallpos:
  173. ld hl, (IO_SAVED_POS)
  174. jr _ioSeek
  175. ioRewind:
  176. call ioResetCounters ; sets HL to 0
  177. jr _ioSeek
  178. ioResetCounters:
  179. ld hl, 0
  180. ld (IO_PC), hl
  181. ld (IO_LINENO), hl
  182. ld (IO_SAVED_LINENO), hl
  183. ret
  184. ; always in absolute mode (A = 0)
  185. _ioSeek:
  186. call ioInInclude
  187. ld a, 0 ; don't alter flags
  188. jr nz, .include
  189. ; normal mode, seek in IN stream
  190. ld ix, IO_IN_BLK
  191. jp _blkSeek
  192. .include:
  193. ; We're in "include mode", seek in FS
  194. ld ix, IO_INCLUDE_BLK
  195. jp _blkSeek ; returns
  196. _ioTell:
  197. call ioInInclude
  198. jp nz, .include
  199. ; normal mode, seek in IN stream
  200. ld ix, IO_IN_BLK
  201. jp _blkTell
  202. .include:
  203. ; We're in "include mode", tell from FS
  204. ld ix, IO_INCLUDE_BLK
  205. jp _blkTell ; returns
  206. ; Sets Z according to whether we're inside an include
  207. ; Z is set when we're *not* in includes. A bit weird, I know...
  208. ioInInclude:
  209. ld a, (IO_IN_INCLUDE)
  210. or a ; cp 0
  211. ret
  212. ; Open include file name specified in (HL).
  213. ; Sets Z on success, unset on error.
  214. ioOpenInclude:
  215. call ioPrintLN
  216. call fsFindFN
  217. ret nz
  218. ld ix, IO_INCLUDE_HDL
  219. call fsOpen
  220. ld a, 1
  221. ld (IO_IN_INCLUDE), a
  222. ld hl, 0
  223. ld (IO_INC_LINENO), hl
  224. xor a
  225. ld ix, IO_INCLUDE_BLK
  226. call _blkSeek
  227. cp a ; ensure Z
  228. ret
  229. ; Open file specified in (HL) and spit its contents through ioPutB
  230. ; Sets Z on success.
  231. ioSpitBin:
  232. call fsFindFN
  233. ret nz
  234. push hl ; --> lvl 1
  235. ld ix, IO_BIN_HDL
  236. call fsOpen
  237. ld hl, 0
  238. .loop:
  239. ld ix, IO_BIN_HDL
  240. call fsGetB
  241. jr nz, .loopend
  242. call ioPutB
  243. inc hl
  244. jr .loop
  245. .loopend:
  246. pop hl ; <-- lvl 1
  247. cp a ; ensure Z
  248. ret
  249. ; Return current lineno in HL and, if in an include, its lineno in DE.
  250. ; If not in an include, DE is set to 0
  251. ioLineNo:
  252. push af
  253. ld hl, (IO_LINENO)
  254. ld de, 0
  255. call ioInInclude
  256. jr z, .end
  257. ld de, (IO_INC_LINENO)
  258. .end:
  259. pop af
  260. ret
  261. _ioIncGetB:
  262. ld ix, IO_INCLUDE_HDL
  263. jp fsGetB
  264. _ioIncBlk:
  265. .dw _ioIncGetB, unsetZ
  266. ; call printstr followed by newline
  267. ioPrintLN:
  268. push hl
  269. call printstr
  270. ld hl, .sCRLF
  271. call printstr
  272. pop hl
  273. ret
  274. .sCRLF:
  275. .db 0x0a, 0x0d, 0