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.

268 lines
6.3KB

  1. ; blockdev
  2. ;
  3. ; A block device is an abstraction over something we can read from, write to.
  4. ;
  5. ; A device that fits this abstraction puts the properly hook into itself, and
  6. ; then the glue code assigns a blockdev ID to that device. It then becomes easy
  7. ; to access arbitrary devices in a convenient manner.
  8. ;
  9. ; This part exposes a new "bsel" command to select the currently active block
  10. ; device.
  11. ;
  12. ; *** Blockdev routines ***
  13. ;
  14. ; There are 4 blockdev routines that can be defined by would-be block devices
  15. ; and they follow these specifications:
  16. ;
  17. ; GetC:
  18. ; Reads one character from selected device and returns its value in A.
  19. ; Sets Z according to whether read was successful: Set if successful, unset
  20. ; if not.
  21. ;
  22. ; A successful GetC should advance the "pointer" of the device (if there is one)
  23. ; by one byte so that a subsequent GetC will read the next char. Unsuccessful
  24. ; reads generally mean that we reached EOF.
  25. ;
  26. ;
  27. ; PutC:
  28. ; Writes character in A in current position in the selected device. Sets Z
  29. ; according to whether the operation was successful.
  30. ;
  31. ; A successful PutC should advance the "pointer" of the device (if there is one)
  32. ; by one byte so that the next PutC places the next char next to this one.
  33. ; Unsuccessful writes generally mean that we reached EOF.
  34. ;
  35. ; Seek:
  36. ; Place device "pointer" at position dictated by HL (low 16 bits) and DE (high
  37. ; 16 bits).
  38. ;
  39. ; Tell:
  40. ; Return the position of the "pointer" in HL (low 16 bits) and DE (high 16
  41. ; bits).
  42. ;
  43. ; All routines are expected to preserve unused registers.
  44. ; *** DEFINES ***
  45. ; BLOCKDEV_COUNT: The number of devices we manage.
  46. ; *** CONSTS ***
  47. .equ BLOCKDEV_ERR_OUT_OF_BOUNDS 0x03
  48. .equ BLOCKDEV_ERR_UNSUPPORTED 0x04
  49. .equ BLOCKDEV_SEEK_ABSOLUTE 0
  50. .equ BLOCKDEV_SEEK_FORWARD 1
  51. .equ BLOCKDEV_SEEK_BACKWARD 2
  52. .equ BLOCKDEV_SEEK_BEGINNING 3
  53. .equ BLOCKDEV_SEEK_END 4
  54. ; *** VARIABLES ***
  55. ; Pointer to the selected block device. A block device is a 8 bytes block of
  56. ; memory with pointers to GetC, PutC, Seek and Tell routines, in that order.
  57. ; 0 means unsupported.
  58. .equ BLOCKDEV_GETC BLOCKDEV_RAMSTART
  59. .equ BLOCKDEV_PUTC BLOCKDEV_GETC+2
  60. .equ BLOCKDEV_SEEK BLOCKDEV_PUTC+2
  61. .equ BLOCKDEV_TELL BLOCKDEV_SEEK+2
  62. .equ BLOCKDEV_RAMEND BLOCKDEV_TELL+2
  63. ; *** CODE ***
  64. ; Select block index specified in A and place them in routine pointers at (DE).
  65. ; For example, for a "regular" blkSel, you will want to set DE to BLOCKDEV_GETC.
  66. blkSel:
  67. push af
  68. push de
  69. push hl
  70. ld hl, blkDevTbl
  71. or a ; cp 0
  72. jr z, .afterloop ; index is zero? don't loop
  73. push bc
  74. ld b, a
  75. .loop:
  76. ld a, 8
  77. call addHL
  78. djnz .loop
  79. pop bc
  80. .afterloop:
  81. push hl
  82. call intoHL
  83. call writeHLinDE
  84. inc de
  85. inc de
  86. pop hl
  87. inc hl
  88. inc hl
  89. push hl
  90. call intoHL
  91. call writeHLinDE
  92. inc de
  93. inc de
  94. pop hl
  95. inc hl
  96. inc hl
  97. push hl
  98. call intoHL
  99. call writeHLinDE
  100. inc de
  101. inc de
  102. pop hl
  103. inc hl
  104. inc hl
  105. call intoHL
  106. call writeHLinDE
  107. pop hl
  108. pop de
  109. pop af
  110. ret
  111. ; call IX unless it's zero
  112. _blkCall:
  113. ; Before we call... is IX zero? We don't want to call a zero.
  114. push af
  115. xor a
  116. push hl
  117. push ix \ pop hl
  118. cp h
  119. jr nz, .ok ; not zero, ok
  120. cp l
  121. jr z, .error ; zero, error
  122. .ok:
  123. pop hl
  124. pop af
  125. call callIX
  126. ret
  127. .error:
  128. pop hl
  129. pop af
  130. ld a, BLOCKDEV_ERR_UNSUPPORTED
  131. ret
  132. ; Reads one character from selected device and returns its value in A.
  133. ; Sets Z according to whether read was successful: Set if successful, unset
  134. ; if not.
  135. blkGetC:
  136. ld ix, (BLOCKDEV_GETC)
  137. jr _blkCall
  138. ; Reads B chars from blkGetC and copy them in (HL).
  139. ; Sets Z if successful, unset Z if there was an error.
  140. blkRead:
  141. ld ix, (BLOCKDEV_GETC)
  142. _blkRead:
  143. push hl
  144. push bc
  145. .loop:
  146. call _blkCall
  147. jr nz, .end ; Z already unset
  148. ld (hl), a
  149. inc hl
  150. djnz .loop
  151. cp a ; ensure Z
  152. .end:
  153. pop bc
  154. pop hl
  155. ret
  156. ; Writes character in A in current position in the selected device. Sets Z
  157. ; according to whether the operation was successful.
  158. blkPutC:
  159. ld ix, (BLOCKDEV_PUTC)
  160. jr _blkCall
  161. ; Writes B chars to blkPutC from (HL).
  162. ; Sets Z if successful, unset Z if there was an error.
  163. blkWrite:
  164. ld ix, (BLOCKDEV_PUTC)
  165. _blkWrite:
  166. push hl
  167. push bc
  168. .loop:
  169. ld a, (hl)
  170. call _blkCall
  171. jr nz, .end ; Z already unset
  172. inc hl
  173. djnz .loop
  174. cp a ; ensure Z
  175. .end:
  176. pop bc
  177. pop hl
  178. ret
  179. ; Seeks the block device in one of 5 modes, which is the A argument:
  180. ; 0 : Move exactly to X, X being the HL/DE argument.
  181. ; 1 : Move forward by X bytes, X being the HL argument (no DE)
  182. ; 2 : Move backwards by X bytes, X being the HL argument (no DE)
  183. ; 3 : Move to the end
  184. ; 4 : Move to the beginning
  185. ; Set position of selected device to the value specified in HL (low) and DE
  186. ; (high). DE is only used for mode 0.
  187. ;
  188. ; When seeking to an out-of-bounds position, the resulting position will be
  189. ; one position ahead of the last valid position. Therefore, GetC after a seek
  190. ; to end would always fail.
  191. ;
  192. ; If the device is "growable", it's possible that seeking to end when calling
  193. ; PutC doesn't necessarily result in a failure.
  194. blkSeek:
  195. ld ix, (BLOCKDEV_SEEK)
  196. ld iy, (BLOCKDEV_TELL)
  197. _blkSeek:
  198. ; we preserve DE so that it's possible to call blkSeek in mode != 0
  199. ; while not discarding our current DE value.
  200. push de
  201. cp BLOCKDEV_SEEK_FORWARD
  202. jr z, .forward
  203. cp BLOCKDEV_SEEK_BACKWARD
  204. jr z, .backward
  205. cp BLOCKDEV_SEEK_BEGINNING
  206. jr z, .beginning
  207. cp BLOCKDEV_SEEK_END
  208. jr z, .end
  209. ; all other modes are considered absolute
  210. jr .seek ; for absolute mode, HL and DE are already
  211. ; correct
  212. .forward:
  213. push bc
  214. push hl
  215. ; We want to be able to plug our own TELL function, which is why we
  216. ; don't call blkTell directly here.
  217. ; Calling TELL
  218. ld de, 0 ; in case out Tell routine doesn't return DE
  219. call callIY ; HL/DE now have our curpos
  220. pop bc ; pop HL into BC
  221. add hl, bc
  222. pop bc ; pop orig BC back
  223. jr nc, .seek ; no carry? let's seek.
  224. ; carry, adjust DE
  225. inc de
  226. jr .seek
  227. .backward:
  228. ; TODO - subtraction are more complicated...
  229. jr .seek
  230. .beginning:
  231. ld hl, 0
  232. ld de, 0
  233. jr .seek
  234. .end:
  235. ld hl, 0xffff
  236. ld de, 0xffff
  237. .seek:
  238. call _blkCall
  239. pop de
  240. ret
  241. ; Returns the current position of the selected device in HL (low) and DE (high).
  242. blkTell:
  243. ld de, 0 ; in case device ignores DE.
  244. ld ix, (BLOCKDEV_TELL)
  245. jp _blkCall
  246. ; This label is at the end of the file on purpose: the glue file should include
  247. ; a list of device routine table entries just after the include. Each line
  248. ; has 4 word addresses: GetC, PutC and Seek, Tell. An entry could look like:
  249. ; .dw mmapGetC, mmapPutC, mmapSeek, mmapTell
  250. blkDevTbl: