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.

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