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.

317 lines
6.4KB

  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 proper hook into itself, and then
  6. ; the glue code assigns a blockdev ID to that device. It then becomes easy to
  7. ; access arbitrary devices in a convenient manner.
  8. ;
  9. ; This module exposes a seek/tell/getb/putb API that is then re-routed to
  10. ; underlying drivers. There will eventually be more than one driver type, but
  11. ; for now we sit on only one type of driver: random access driver.
  12. ;
  13. ; *** Random access drivers ***
  14. ;
  15. ; Random access drivers are expected to supply two routines: GetB and PutB.
  16. ;
  17. ; GetB:
  18. ; Reads one byte at address specified in DE/HL and returns its value in A.
  19. ; Sets Z according to whether read was successful: Set if successful, unset
  20. ; if not.
  21. ;
  22. ; Unsuccessful reads generally mean that requested addr is out of bounds (we
  23. ; reached EOF).
  24. ;
  25. ; PutB:
  26. ; Writes byte in A at address specified in DE/HL. Sets Z according to whether
  27. ; the operation was successful.
  28. ;
  29. ; Unsuccessful writes generally mean that we're out of bounds for writing.
  30. ;
  31. ; All routines are expected to preserve unused registers except IX which is
  32. ; explicitly protected during GetB/PutB calls. This makes quick "handle+jump"
  33. ; definitions possible.
  34. ; *** DEFINES ***
  35. ; BLOCKDEV_COUNT: The number of devices we manage.
  36. ; *** CONSTS ***
  37. ; *** VARIABLES ***
  38. ; Pointer to the selected block device. A block device is a 8 bytes block of
  39. ; memory with pointers to GetB, PutB, and a 32-bit counter, in that order.
  40. .equ BLOCKDEV_SEL BLOCKDEV_RAMSTART
  41. .equ BLOCKDEV_RAMEND @+BLOCKDEV_SIZE
  42. ; *** CODE ***
  43. ; Put the pointer to the "regular" blkdev selection in DE
  44. blkSelPtr:
  45. ld de, BLOCKDEV_SEL
  46. ; Select block index specified in A and place them in routine pointers at (DE).
  47. ; For example, for a "regular" blkSel, you will want to set DE to BLOCKDEV_SEL.
  48. ; Sets Z on success, reset on error.
  49. ; If A >= BLOCKDEV_COUNT, it's an error.
  50. blkSel:
  51. cp BLOCKDEV_COUNT
  52. jp nc, unsetZ ; if selection >= device count, error
  53. push af
  54. push de
  55. push hl
  56. ld hl, blkDevTbl
  57. or a ; cp 0
  58. jr z, .end ; index is zero? don't loop
  59. push bc ; <|
  60. ld b, a ; |
  61. .loop: ; |
  62. ld a, 4 ; |
  63. call addHL ; |
  64. djnz .loop ; |
  65. pop bc ; <|
  66. .end:
  67. call blkSet
  68. pop hl
  69. pop de
  70. pop af
  71. cp a ; ensure Z
  72. ret
  73. ; Setup blkdev handle in (DE) using routines at (HL).
  74. blkSet:
  75. push af
  76. push de
  77. push hl
  78. ; Write GETC
  79. push hl ; <|
  80. call intoHL ; |
  81. call writeHLinDE ; |
  82. inc de ; |
  83. inc de ; |
  84. pop hl ; <|
  85. inc hl
  86. inc hl
  87. ; Write PUTC
  88. call intoHL
  89. call writeHLinDE
  90. inc de
  91. inc de
  92. ; Initialize pos
  93. xor a
  94. ld (de), a
  95. inc de
  96. ld (de), a
  97. inc de
  98. ld (de), a
  99. inc de
  100. ld (de), a
  101. pop hl
  102. pop de
  103. pop af
  104. ret
  105. _blkInc:
  106. ret nz ; don't advance when in error condition
  107. push af
  108. push hl
  109. ld a, BLOCKDEV_SEEK_FORWARD
  110. ld hl, 1
  111. call _blkSeek
  112. pop hl
  113. pop af
  114. ret
  115. ; Reads one byte from selected device and returns its value in A.
  116. ; Sets Z according to whether read was successful: Set if successful, unset
  117. ; if not.
  118. blkGetB:
  119. push ix
  120. ld ix, BLOCKDEV_SEL
  121. call _blkGetB
  122. pop ix
  123. ret
  124. _blkGetB:
  125. push hl
  126. push de
  127. call _blkTell
  128. call callIXI
  129. pop de
  130. pop hl
  131. jr _blkInc ; advance and return
  132. ; Writes byte in A in current position in the selected device. Sets Z according
  133. ; to whether the operation was successful.
  134. blkPutB:
  135. push ix
  136. ld ix, BLOCKDEV_SEL
  137. call _blkPutB
  138. pop ix
  139. ret
  140. _blkPutB:
  141. push ix
  142. push hl
  143. push de
  144. call _blkTell
  145. inc ix ; make IX point to PutB
  146. inc ix
  147. call callIXI
  148. pop de
  149. pop hl
  150. pop ix
  151. jr _blkInc ; advance and return
  152. ; Reads B chars from blkGetB and copy them in (HL).
  153. ; Sets Z if successful, unset Z if there was an error.
  154. blkRead:
  155. push ix
  156. ld ix, BLOCKDEV_SEL
  157. call _blkRead
  158. pop ix
  159. ret
  160. _blkRead:
  161. push hl
  162. push bc
  163. .loop:
  164. call _blkGetB
  165. jr nz, .end ; Z already unset
  166. ld (hl), a
  167. inc hl
  168. djnz .loop
  169. cp a ; ensure Z
  170. .end:
  171. pop bc
  172. pop hl
  173. ret
  174. ; Writes B chars to blkPutB from (HL).
  175. ; Sets Z if successful, unset Z if there was an error.
  176. blkWrite:
  177. push ix
  178. ld ix, BLOCKDEV_SEL
  179. call _blkWrite
  180. pop ix
  181. ret
  182. _blkWrite:
  183. push hl
  184. push bc
  185. .loop:
  186. ld a, (hl)
  187. call _blkPutB
  188. jr nz, .end ; Z already unset
  189. inc hl
  190. djnz .loop
  191. cp a ; ensure Z
  192. .end:
  193. pop bc
  194. pop hl
  195. ret
  196. ; Seeks the block device in one of 5 modes, which is the A argument:
  197. ; 0 : Move exactly to X, X being the HL/DE argument.
  198. ; 1 : Move forward by X bytes, X being the HL argument (no DE)
  199. ; 2 : Move backwards by X bytes, X being the HL argument (no DE)
  200. ; 3 : Move to the end
  201. ; 4 : Move to the beginning
  202. ; Set position of selected device to the value specified in HL (low) and DE
  203. ; (high). DE is only used for mode 0.
  204. ;
  205. ; When seeking to an out-of-bounds position, the resulting position will be
  206. ; one position ahead of the last valid position. Therefore, GetB after a seek
  207. ; to end would always fail.
  208. ;
  209. ; If the device is "growable", it's possible that seeking to end when calling
  210. ; PutB doesn't necessarily result in a failure.
  211. blkSeek:
  212. push ix
  213. ld ix, BLOCKDEV_SEL
  214. call _blkSeek
  215. pop ix
  216. ret
  217. _blkSeek:
  218. cp BLOCKDEV_SEEK_FORWARD
  219. jr z, .forward
  220. cp BLOCKDEV_SEEK_BACKWARD
  221. jr z, .backward
  222. cp BLOCKDEV_SEEK_BEGINNING
  223. jr z, .beginning
  224. cp BLOCKDEV_SEEK_END
  225. jr z, .end
  226. ; all other modes are considered absolute
  227. ld (ix+4), e
  228. ld (ix+5), d
  229. ld (ix+6), l
  230. ld (ix+7), h
  231. ret
  232. .forward:
  233. push bc ; <-|
  234. push hl ; <||
  235. ld l, (ix+6) ; || low byte
  236. ld h, (ix+7) ; ||
  237. pop bc ; <||
  238. add hl, bc ; |
  239. pop bc ; <-|
  240. ld (ix+6), l
  241. ld (ix+7), h
  242. ret nc ; no carry? no need to adjust high byte
  243. ; carry, adjust high byte
  244. inc (ix+4)
  245. ret nz
  246. inc (ix+5)
  247. ret
  248. .backward:
  249. and a ; clear carry
  250. push bc ; <-|
  251. push hl ; <||
  252. ld l, (ix+6) ; || low byte
  253. ld h, (ix+7) ; ||
  254. pop bc ; <||
  255. sbc hl, bc ; |
  256. pop bc ; <-|
  257. ld (ix+6), l
  258. ld (ix+7), h
  259. ret nc ; no carry? no need to adjust high byte
  260. ld a, 0xff
  261. dec (ix+4)
  262. cp (ix+4)
  263. ret nz
  264. ; we decremented from 0
  265. dec (ix+5)
  266. ret
  267. .beginning:
  268. xor a
  269. ld (ix+4), a
  270. ld (ix+5), a
  271. ld (ix+6), a
  272. ld (ix+7), a
  273. ret
  274. .end:
  275. ld a, 0xff
  276. ld (ix+4), a
  277. ld (ix+5), a
  278. ld (ix+6), a
  279. ld (ix+7), a
  280. ret
  281. ; Returns the current position of the selected device in HL (low) and DE (high).
  282. blkTell:
  283. push ix
  284. ld ix, BLOCKDEV_SEL
  285. call _blkTell
  286. pop ix
  287. ret
  288. _blkTell:
  289. ld e, (ix+4)
  290. ld d, (ix+5)
  291. ld l, (ix+6)
  292. ld h, (ix+7)
  293. ret
  294. ; This label is at the end of the file on purpose: the glue file should include
  295. ; a list of device routine table entries just after the include. Each line
  296. ; has 2 word addresses: GetB and PutB. An entry could look like:
  297. ; .dw mmapGetB, mmapPutB
  298. blkDevTbl: