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.1KB

  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. push ix ; --> lvl 1
  80. ld ix, IO_INCLUDE_BLK
  81. call _blkGetB
  82. pop ix ; <-- lvl 1
  83. jr nz, .includeEOF
  84. cp 0x0a ; newline
  85. ret nz ; not newline? nothing to do
  86. ; We have newline. Increase lineno and return (the rest of the
  87. ; processing below isn't needed.
  88. push hl
  89. ld hl, (IO_INC_LINENO)
  90. inc hl
  91. ld (IO_INC_LINENO), hl
  92. pop hl
  93. ret
  94. .includeEOF:
  95. ; We reached EOF. What we do depends on whether we're in Local Pass
  96. ; mode. Yes, I know, a bit hackish. Normally, we *should* be
  97. ; transparently getting of include mode and avoid meddling with global
  98. ; states, but here, we need to tell main.asm that the local scope if
  99. ; over *before* we get off include mode, otherwise, our IO_SAVED_POS
  100. ; will be wrong (an include IO_SAVED_POS used in global IN stream).
  101. call zasmIsLocalPass
  102. ld a, 0 ; doesn't affect Z flag
  103. ret z ; local pass? return EOF
  104. ; regular pass (first or second)? transparently get off include mode.
  105. ld (IO_IN_INCLUDE), a ; A already 0
  106. ld (IO_INC_LINENO), a
  107. ld (IO_INC_LINENO+1), a
  108. ; continue on to "normal" reading. We don't want to return our zero
  109. .normalmode:
  110. ; normal mode, read from IN stream
  111. push ix ; --> lvl 1
  112. ld ix, IO_IN_BLK
  113. call _blkGetB
  114. pop ix ; <-- lvl 1
  115. cp LF ; newline
  116. ret nz ; not newline? return
  117. ; inc current lineno
  118. push hl
  119. ld hl, IO_LINENO
  120. inc (hl)
  121. pop hl
  122. cp a ; ensure Z
  123. ret
  124. .getback:
  125. push af
  126. xor a
  127. ld (IO_PUTBACK_BUF), a
  128. pop af
  129. ret
  130. ; Put back non-zero character A into the "ioGetB stack". The next ioGetB call,
  131. ; instead of reading from IO_IN_BLK, will return that character. That's the
  132. ; easiest way I found to handle the readWord/gotoNextLine problem.
  133. ioPutBack:
  134. ld (IO_PUTBACK_BUF), a
  135. ret
  136. ioPutB:
  137. push hl ; --> lvl 1
  138. ld hl, (IO_PC)
  139. inc hl
  140. ld (IO_PC), hl
  141. pop hl ; <-- lvl 1
  142. push af ; --> lvl 1
  143. call zasmIsFirstPass
  144. jr z, .skip
  145. pop af ; <-- lvl 1
  146. push ix ; --> lvl 1
  147. ld ix, IO_OUT_BLK
  148. call _blkPutB
  149. pop ix ; <-- lvl 1
  150. ret
  151. .skip:
  152. pop af ; <-- lvl 1
  153. cp a ; ensure Z
  154. ret
  155. ioSavePos:
  156. ld hl, (IO_LINENO)
  157. call ioInInclude
  158. jr z, .skip
  159. ld hl, (IO_INC_LINENO)
  160. .skip:
  161. ld (IO_SAVED_LINENO), hl
  162. call _ioTell
  163. ld (IO_SAVED_POS), hl
  164. ret
  165. ioRecallPos:
  166. ld hl, (IO_SAVED_LINENO)
  167. call ioInInclude
  168. jr nz, .include
  169. ld (IO_LINENO), hl
  170. jr .recallpos
  171. .include:
  172. ld (IO_INC_LINENO), hl
  173. .recallpos:
  174. ld hl, (IO_SAVED_POS)
  175. jr _ioSeek
  176. ioRewind:
  177. call ioResetCounters ; sets HL to 0
  178. jr _ioSeek
  179. ioResetCounters:
  180. ld hl, 0
  181. ld (IO_PC), hl
  182. ld (IO_LINENO), hl
  183. ld (IO_SAVED_LINENO), hl
  184. ret
  185. ; always in absolute mode (A = 0)
  186. _ioSeek:
  187. call ioInInclude
  188. ld a, 0 ; don't alter flags
  189. jr nz, .include
  190. ; normal mode, seek in IN stream
  191. ld ix, IO_IN_BLK
  192. jp _blkSeek
  193. .include:
  194. ; We're in "include mode", seek in FS
  195. ld ix, IO_INCLUDE_BLK
  196. jp _blkSeek ; returns
  197. _ioTell:
  198. call ioInInclude
  199. jp nz, .include
  200. ; normal mode, seek in IN stream
  201. ld ix, IO_IN_BLK
  202. jp _blkTell
  203. .include:
  204. ; We're in "include mode", tell from FS
  205. ld ix, IO_INCLUDE_BLK
  206. jp _blkTell ; returns
  207. ; Sets Z according to whether we're inside an include
  208. ; Z is set when we're *not* in includes. A bit weird, I know...
  209. ioInInclude:
  210. ld a, (IO_IN_INCLUDE)
  211. or a ; cp 0
  212. ret
  213. ; Open include file name specified in (HL).
  214. ; Sets Z on success, unset on error.
  215. ioOpenInclude:
  216. call ioPrintLN
  217. call fsFindFN
  218. ret nz
  219. ld ix, IO_INCLUDE_HDL
  220. call fsOpen
  221. ld a, 1
  222. ld (IO_IN_INCLUDE), a
  223. ld hl, 0
  224. ld (IO_INC_LINENO), hl
  225. xor a
  226. ld ix, IO_INCLUDE_BLK
  227. call _blkSeek
  228. cp a ; ensure Z
  229. ret
  230. ; Open file specified in (HL) and spit its contents through ioPutB
  231. ; Sets Z on success.
  232. ioSpitBin:
  233. call fsFindFN
  234. ret nz
  235. push hl ; --> lvl 1
  236. ld ix, IO_BIN_HDL
  237. call fsOpen
  238. ld hl, 0
  239. .loop:
  240. ld ix, IO_BIN_HDL
  241. call fsGetB
  242. jr nz, .loopend
  243. call ioPutB
  244. inc hl
  245. jr .loop
  246. .loopend:
  247. pop hl ; <-- lvl 1
  248. cp a ; ensure Z
  249. ret
  250. ; Return current lineno in HL and, if in an include, its lineno in DE.
  251. ; If not in an include, DE is set to 0
  252. ioLineNo:
  253. push af
  254. ld hl, (IO_LINENO)
  255. ld de, 0
  256. call ioInInclude
  257. jr z, .end
  258. ld de, (IO_INC_LINENO)
  259. .end:
  260. pop af
  261. ret
  262. _ioIncGetB:
  263. ld ix, IO_INCLUDE_HDL
  264. jp fsGetB
  265. _ioIncBlk:
  266. .dw _ioIncGetB, unsetZ
  267. ; call printstr followed by newline
  268. ioPrintLN:
  269. push hl
  270. call printstr
  271. ld hl, .sCRLF
  272. call printstr
  273. pop hl
  274. ret
  275. .sCRLF:
  276. .db 0x0a, 0x0d, 0