Mirror of CollapseOS
Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

760 lines
19KB

  1. ; sdc
  2. ;
  3. ; Manages the initialization of a SD card and implement a block device to read
  4. ; and write from/to it, in SPI mode.
  5. ;
  6. ; Note that SPI can't really be used directly from the z80, so this part
  7. ; assumes that you have a device that handles SPI communication on behalf of
  8. ; the z80. This device is assumed to work in a particular way. See the
  9. ; "rc2014/sdcard" recipe for details.
  10. ;
  11. ; That device has 3 ports. One write-only port to make CS high, one to make CS
  12. ; low (data sent is irrelevant), and one read/write port to send and receive
  13. ; bytes with the card through the SPI protocol. The device acts as a SPI master
  14. ; and writing to that port initiates a byte exchange. Data from the slave is
  15. ; then placed on a buffer that can be read by reading the same port.
  16. ;
  17. ; It's through that kind of device that this code below is supposed to work.
  18. ;
  19. ; *** SDC buffers ***
  20. ;
  21. ; SD card's lowest common denominator in terms of block size is 512 bytes, so
  22. ; that's what we deal with. To avoid wastefully reading entire blocks from the
  23. ; card for one byte read ops, we buffer the last read block. If a GetB or PutB
  24. ; operation is within that buffer, then no interaction with the SD card is
  25. ; necessary.
  26. ;
  27. ; As soon as a GetB or PutB operation is made that is outside the current
  28. ; buffer, we load a new block.
  29. ;
  30. ; When we PutB, we flag the buffer as "dirty". On the next buffer change (during
  31. ; an out-of-buffer request or during an explicit "flush" operation), bytes
  32. ; currently in the buffer will be written to the SD card.
  33. ;
  34. ; We hold 2 buffers in memory, each targeting a different sector and with its
  35. ; own dirty flag. We do that to avoid wasteful block writing in the case where
  36. ; we read data from a file in the SD card, process it and write the result
  37. ; right away, in another file on the same card (zasm), on a different sector.
  38. ;
  39. ; If we only have one buffer in this scenario, we'll end up loading a new sector
  40. ; at each GetB/PutB operation and, more importantly, writing a whole block for
  41. ; a few bytes each time. This will wear the card prematurely (and be very slow).
  42. ;
  43. ; With 2 buffers, we solve the problem. Whenever GetB/PutB is called, we first
  44. ; look if one of the buffer holds our sector. If not, we see if one of the
  45. ; buffer is clean (not dirty). If yes, we use this one. If both are dirty or
  46. ; clean, we use any. This way, as long as writing isn't made to random
  47. ; addresses, we ensure that we don't write wastefully because read operations,
  48. ; even if random, will always use the one buffer that isn't dirty.
  49. ; *** Defines ***
  50. ; SDC_PORT_CSHIGH: Port number to make CS high
  51. ; SDC_PORT_CSLOW: Port number to make CS low
  52. ; SDC_PORT_SPI: Port number to send/receive SPI data
  53. ; *** Consts ***
  54. .equ SDC_BLKSIZE 512
  55. .equ SDC_MAXTRIES 8
  56. ; *** Variables ***
  57. ; This is a pointer to the currently selected buffer. This points to the BUFSEC
  58. ; part, that is, two bytes before actual content begins.
  59. .equ SDC_BUFPTR SDC_RAMSTART
  60. ; Count the number of times we tried a particular read or write operation. When
  61. ; CRC check fail, we retry. After SDC_MAXTRIES failures, we stop.
  62. .equ SDC_RETRYCNT SDC_BUFPTR+2
  63. ; Sector number currently in SDC_BUF1. Little endian like any other z80 word.
  64. .equ SDC_BUFSEC1 SDC_RETRYCNT+1
  65. ; Whether the buffer has been written to. 0 means clean. 1 means dirty.
  66. .equ SDC_BUFDIRTY1 SDC_BUFSEC1+2
  67. ; The contents of the buffer.
  68. .equ SDC_BUF1 SDC_BUFDIRTY1+1
  69. ; CRC bytes for the buffer. They're placed after the contents because that makes
  70. ; things easier processing-wise. Because the SD card sends them right after the
  71. ; contents, all we need to do is read SDC_BLKSIZE+2.
  72. ; IMPORTANT NOTE: This is big endian. The SD card sends the MSB first, so we
  73. ; keep it in memory this way.
  74. .equ SDC_CRC1 SDC_BUF1+SDC_BLKSIZE
  75. ; second buffer has the same structure as the first.
  76. .equ SDC_BUFSEC2 SDC_CRC1+2
  77. .equ SDC_BUFDIRTY2 SDC_BUFSEC2+2
  78. .equ SDC_BUF2 SDC_BUFDIRTY2+1
  79. .equ SDC_CRC2 SDC_BUF2+SDC_BLKSIZE
  80. .equ SDC_RAMEND SDC_CRC2+2
  81. ; *** Code ***
  82. ; Wake the SD card up. After power up, a SD card has to receive at least 74
  83. ; dummy clocks with CS and DI high. We send 80.
  84. sdcWakeUp:
  85. out (SDC_PORT_CSHIGH), a
  86. ld b, 10 ; 10 * 8 == 80
  87. ld a, 0xff
  88. .loop:
  89. out (SDC_PORT_SPI), a
  90. nop
  91. djnz .loop
  92. ret
  93. ; Initiate SPI exchange with the SD card. A is the data to send. Received data
  94. ; is placed in A.
  95. sdcSendRecv:
  96. out (SDC_PORT_SPI), a
  97. nop
  98. nop
  99. in a, (SDC_PORT_SPI)
  100. nop
  101. nop
  102. ret
  103. sdcIdle:
  104. ld a, 0xff
  105. jp sdcSendRecv
  106. ; sdcSendRecv 0xff until the response is something else than 0xff for a maximum
  107. ; of 20 times. Returns 0xff if no response.
  108. sdcWaitResp:
  109. push bc
  110. ld b, 20
  111. .loop:
  112. call sdcIdle
  113. inc a ; if 0xff, it's going to become zero
  114. jr nz, .end ; not zero? good, that's our command
  115. djnz .loop
  116. .end:
  117. ; whether we had a success or failure, we return the result.
  118. ; But first, let's bring it back to its original value.
  119. dec a
  120. pop bc
  121. ret
  122. ; The opposite of sdcWaitResp: we wait until response if 0xff. After a
  123. ; successful read or write operation, the card will be busy for a while. We need
  124. ; to give it time before interacting with it again. Technically, we could
  125. ; continue processing on our side while the card it busy, and maybe we will one
  126. ; day, but at the moment, I'm having random write errors if I don't do this
  127. ; right after a write, so I prefer to stay cautious for now.
  128. ; This has no error condition and preserves A
  129. sdcWaitReady:
  130. push af
  131. ; for now, we have no timeout for waiting. It means that broken SD
  132. ; cards can cause infinite loops.
  133. .loop:
  134. call sdcIdle
  135. inc a ; if 0xff, it's going to become zero
  136. jr nz, .loop ; not zero? still busy. loop
  137. pop af
  138. ret
  139. ; Sends a command to the SD card, along with arguments and specified CRC fields.
  140. ; (CRC is only needed in initial commands though).
  141. ; A: Command to send
  142. ; H: Arg 1 (MSB)
  143. ; L: Arg 2
  144. ; D: Arg 3
  145. ; E: Arg 4 (LSB)
  146. ;
  147. ; Returns R1 response in A.
  148. ;
  149. ; This does *not* handle CS. You have to select/deselect the card outside this
  150. ; routine.
  151. sdcCmd:
  152. push bc
  153. ; Wait until ready to receive commands
  154. push af
  155. call sdcWaitResp
  156. pop af
  157. ld c, 0 ; init CRC
  158. call .crc7
  159. call sdcSendRecv
  160. ; Arguments
  161. ld a, h
  162. call .crc7
  163. call sdcSendRecv
  164. ld a, l
  165. call .crc7
  166. call sdcSendRecv
  167. ld a, d
  168. call .crc7
  169. call sdcSendRecv
  170. ld a, e
  171. call .crc7
  172. call sdcSendRecv
  173. ; send CRC
  174. ld a, c
  175. or 0x01 ; ensure stop bit is set
  176. call sdcSendRecv
  177. ; And now we just have to wait for a valid response...
  178. call sdcWaitResp
  179. pop bc
  180. ret
  181. ; push A into C and compute CRC7 with 0x09 polynomial
  182. ; Note that the result is "left aligned", that is, that 8th bit to the "right"
  183. ; is insignificant (will be stop bit).
  184. .crc7:
  185. push af
  186. xor c
  187. ld b, 8
  188. .loop:
  189. sla a
  190. jr nc, .noCRC
  191. ; msb was set, apply polynomial
  192. xor 0x12 ; 0x09 << 1. We apply CRC on high 7 bits
  193. .noCRC:
  194. djnz .loop
  195. ld c, a
  196. pop af
  197. ret
  198. ; Send a command that expects a R1 response, handling CS.
  199. sdcCmdR1:
  200. out (SDC_PORT_CSLOW), a
  201. call sdcCmd
  202. out (SDC_PORT_CSHIGH), a
  203. ret
  204. ; Send a command that expects a R7 response, handling CS. A R7 is a R1 followed
  205. ; by 4 bytes. Those 4 bytes are returned in HL/DE in the same order as in
  206. ; sdcCmd.
  207. sdcCmdR7:
  208. out (SDC_PORT_CSLOW), a
  209. call sdcCmd
  210. ; We have our R1 response in A. Let's try reading the next 4 bytes in
  211. ; case we have a R3.
  212. push af
  213. call sdcIdle
  214. ld h, a
  215. call sdcIdle
  216. ld l, a
  217. call sdcIdle
  218. ld d, a
  219. call sdcIdle
  220. ld e, a
  221. pop af
  222. out (SDC_PORT_CSHIGH), a
  223. ret
  224. ; Initialize a SD card. This should be called at least 1ms after the powering
  225. ; up of the card. Sets result code in A. Zero means success, non-zero means
  226. ; error.
  227. sdcInitialize:
  228. push hl
  229. push de
  230. push bc
  231. call sdcWakeUp
  232. ; Call CMD0 and expect a 0x01 response (card idle)
  233. ; This should be called multiple times. We're actually expected to.
  234. ; Let's call this for a maximum of 10 times.
  235. ld b, 10
  236. .loop1:
  237. ld a, 0b01000000 ; CMD0
  238. ld hl, 0
  239. ld de, 0
  240. call sdcCmdR1
  241. cp 0x01
  242. jp z, .cmd0ok
  243. djnz .loop1
  244. ; Nothing? error
  245. jr .error
  246. .cmd0ok:
  247. ; Then comes the CMD8. We send it with a 0x01aa argument and expect
  248. ; a 0x01aa argument back, along with a 0x01 R1 response.
  249. ld a, 0b01001000 ; CMD8
  250. ld hl, 0
  251. ld de, 0x01aa
  252. call sdcCmdR7
  253. cp 0x01
  254. jr nz, .error
  255. xor a
  256. cp h ; H is zero
  257. jr nz, .error
  258. cp l ; L is zero
  259. jr nz, .error
  260. ld a, d
  261. cp 0x01
  262. jp nz, .error
  263. ld a, e
  264. cp 0xaa
  265. jr nz, .error
  266. ; Now we need to repeatedly run CMD55+CMD41 (0x40000000) until we
  267. ; the card goes out of idle mode, that is, when it stops sending us
  268. ; 0x01 response and send us 0x00 instead. Any other response means that
  269. ; initialization failed.
  270. .loop2:
  271. ld a, 0b01110111 ; CMD55
  272. ld hl, 0
  273. ld de, 0
  274. call sdcCmdR1
  275. cp 0x01
  276. jr nz, .error
  277. ld a, 0b01101001 ; CMD41 (0x40000000)
  278. ld hl, 0x4000
  279. ld de, 0x0000
  280. call sdcCmdR1
  281. cp 0x01
  282. jr z, .loop2
  283. or a ; cp 0
  284. jr nz, .error
  285. ; Success! out of idle mode!
  286. jr .end
  287. .error:
  288. ld a, 0x01
  289. .end:
  290. pop bc
  291. pop de
  292. pop hl
  293. ret
  294. ; Read block index specified in DE and place the contents in buffer pointed to
  295. ; by (SDC_BUFPTR).
  296. ; If the operation is a success, updates buffer's sector to the value of DE.
  297. ; After a block read, check that CRC given by the card matches the content. If
  298. ; it doesn't, retries up to SDC_MAXTRIES times.
  299. ; Returns 0 in A if success, non-zero if error.
  300. sdcReadBlk:
  301. xor a
  302. ld (SDC_RETRYCNT), a
  303. push bc
  304. push hl
  305. out (SDC_PORT_CSLOW), a
  306. .retry:
  307. ld hl, 0
  308. ; DE already has the correct value
  309. ld a, 0b01010001 ; CMD17
  310. call sdcCmd
  311. or a ; cp 0
  312. jr nz, .error
  313. ; Command sent, no error, now let's wait for our data response.
  314. ld b, 20
  315. .loop1:
  316. call sdcWaitResp
  317. ; 0xfe is the expected data token for CMD17
  318. cp 0xfe
  319. jr z, .loop1end
  320. cp 0xff
  321. jr nz, .error
  322. djnz .loop1
  323. jr .error ; timeout. error out
  324. .loop1end:
  325. ; We received our data token!
  326. ; Data packets follow immediately, we have 512+CRC of them to read
  327. ld bc, SDC_BLKSIZE+2
  328. ld hl, (SDC_BUFPTR) ; HL --> active buffer's sector
  329. ; It sounds a bit wrong to set bufsec and dirty flag before we get our
  330. ; actual data, but at this point, we don't have any error conditions
  331. ; left, success is guaranteed. To avoid needlesssly INCing hl, let's
  332. ; set sector and dirty along the way
  333. ld (hl), e ; sector number LSB
  334. inc hl
  335. ld (hl), d ; sector number MSB
  336. inc hl ; dirty flag
  337. xor a ; unset
  338. ld (hl), a
  339. inc hl ; actual contents
  340. .loop2:
  341. call sdcIdle
  342. ld (hl), a
  343. cpi ; a trick to inc HL and dec BC at the same time.
  344. ; P/V indicates whether BC reached 0
  345. jp pe, .loop2 ; BC is not zero, loop
  346. ; Success! while the card is busy, let's get busy too: let's check and
  347. ; see if the CRC matches.
  348. push de ; <|
  349. call sdcCRC ; |
  350. ; before we check the CRC r|esults, let's wait until card is ready
  351. call sdcWaitReady ; |
  352. ; check CRC results |
  353. ld a, (hl) ; |
  354. cp d ; |
  355. jr nz, .crcMismatch ; |
  356. inc hl ; |
  357. ld a, (hl) ; |
  358. cp e ; |
  359. jr nz, .crcMismatch ; |
  360. pop de ; <|
  361. ; Everything is fine and dandy!
  362. xor a ; success
  363. jr .end
  364. .crcMismatch:
  365. ; CRC of the buffer's content doesn't match the CRC reported by the
  366. ; card. Let's retry.
  367. pop de ; from the push right before call sdcCRC
  368. ld a, (SDC_RETRYCNT)
  369. inc a
  370. ld (SDC_RETRYCNT), a
  371. cp SDC_MAXTRIES
  372. jr nz, .retry ; we jump inside our main stack push. No need
  373. ; to pop it.
  374. ; Continue to error condition. Even if we went through many retries,
  375. ; our stack is still the same as it was at the first call. We can return
  376. ; normally (but in error condition).
  377. .error:
  378. ; try to preserve error code
  379. or a ; cp 0
  380. jr nz, .end ; already non-zero
  381. inc a ; zero, adjust
  382. .end:
  383. out (SDC_PORT_CSHIGH), a
  384. pop hl
  385. pop bc
  386. ret
  387. ; Write the contents of buffer where (SDC_BUFPTR) points to in sector associated
  388. ; to it. Unsets the the buffer's dirty flag on success.
  389. ; Before writing the block, update the buffer's CRC field so that the correct
  390. ; CRC is sent.
  391. ; A returns 0 in A on success (with Z set), non-zero (with Z unset) on error.
  392. sdcWriteBlk:
  393. push ix
  394. ld ix, (SDC_BUFPTR) ; IX points to sector LSB
  395. xor a
  396. cp (ix+2) ; dirty flag
  397. pop ix
  398. ret z ; don't write if dirty flag is zero
  399. push bc
  400. push de
  401. push hl
  402. call sdcCRC ; DE -> new CRC. HL -> pointer to buf CRC
  403. ld (hl), d ; write computed CRC
  404. inc hl
  405. ld (hl), e
  406. out (SDC_PORT_CSLOW), a
  407. ld hl, (SDC_BUFPTR) ; sector LSB
  408. ld e, (hl) ; sector LSB
  409. inc hl
  410. ld d, (hl) ; sector MSB
  411. ld hl, 0 ; high addr word always zero, DE already set
  412. ld a, 0b01011000 ; CMD24
  413. call sdcCmd
  414. or a ; cp 0
  415. jr nz, .error
  416. ; Before sending the data packet, we need to send at least one empty
  417. ; byte.
  418. call sdcIdle
  419. ; data packet token for CMD24
  420. ld a, 0xfe
  421. call sdcSendRecv
  422. ; Sending our data token!
  423. ld bc, SDC_BLKSIZE+2 ; +2 for CRC. (as of now, however, that
  424. ; CRC isn't properly updated. Because
  425. ; CMD59 isn't enabled, it doesn't
  426. ; matter)
  427. ld hl, (SDC_BUFPTR)
  428. inc hl ; sector MSB
  429. inc hl ; dirty flag
  430. inc hl ; beginning of contents
  431. .loop:
  432. ld a, (hl)
  433. call sdcSendRecv
  434. cpi ; a trick to inc HL and dec BC at the same time.
  435. ; P/V indicates whether BC reached 0
  436. jp pe, .loop ; BC is not zero, loop
  437. ; Let's see what response we have
  438. call sdcWaitResp
  439. and 0b00011111 ; We ignore the first 3 bits of the response.
  440. cp 0b00000101 ; A valid response is "010" in bits 3:1 flanked
  441. ; by 0 on its left and 1 on its right.
  442. jr nz, .error
  443. ; good! Now, we need to let the card process this data. It will return
  444. ; 0xff when it's not busy any more.
  445. call sdcWaitResp
  446. ; Success! Now let's unset the dirty flag
  447. ld hl, (SDC_BUFPTR)
  448. inc hl ; sector MSB
  449. inc hl ; dirty flag
  450. xor a
  451. ld (hl), a
  452. ; Before returning, wait until card is ready
  453. call sdcWaitReady
  454. xor a
  455. jr .end
  456. .error:
  457. ; try to preserve error code
  458. or a ; cp 0
  459. jr nz, .end ; already non-zero
  460. inc a ; zero, adjust
  461. .end:
  462. out (SDC_PORT_CSHIGH), a
  463. pop hl
  464. pop de
  465. pop bc
  466. ret
  467. ; Considering the first 15 bits of EHL, select the most appropriate of our two
  468. ; buffers and, if necessary, sync that buffer with the SD card. If the selected
  469. ; buffer doesn't have the same sector as what EHL asks, load that buffer from
  470. ; the SD card.
  471. ; If the dirty flag is set, we write the content of the in-memory buffer to the
  472. ; SD card before we read a new sector.
  473. ; Returns Z on success, not-Z on error (with the error code from either
  474. ; sdcReadBlk or sdcWriteBlk)
  475. sdcSync:
  476. push de
  477. ; Given a 24-bit address in EHL, extracts the 15-bit sector from it and
  478. ; place it in DE.
  479. ; We need to shift both E and H right by one bit
  480. srl e ; sets Carry
  481. ld d, e
  482. ld a, h
  483. rra ; takes Carry
  484. ld e, a
  485. ; Let's first see if our first buffer has our sector
  486. ld a, (SDC_BUFSEC1) ; sector LSB
  487. cp e
  488. jr nz, .notBuf1
  489. ld a, (SDC_BUFSEC1+1) ; sector MSB
  490. cp d
  491. jr z, .buf1Ok
  492. .notBuf1:
  493. ; Ok, let's check for buf2 then
  494. ld a, (SDC_BUFSEC2) ; sector LSB
  495. cp e
  496. jr nz, .notBuf2
  497. ld a, (SDC_BUFSEC2+1) ; sector MSB
  498. cp d
  499. jr z, .buf2Ok
  500. .notBuf2:
  501. ; None of our two buffers have the sector we need, we'll need to load
  502. ; a new one.
  503. ; We select our buffer depending on which is dirty. If both are on the
  504. ; same status of dirtiness, we pick any (the first in our case). If one
  505. ; of them is dirty, we pick the clean one.
  506. push de ; <|
  507. ld de, SDC_BUFSEC1 ; |
  508. ld a, (SDC_BUFDIRTY1) ; |
  509. or a ; | is buf1 dirty?
  510. jr z, .ready ; | no? good, that's our buffer
  511. ; yes? then buf2 is our buffer. ; |
  512. ld de, SDC_BUFSEC2 ; |
  513. ; |
  514. .ready: ; |
  515. ; At this point, DE points to one o|f our two buffers, the good one.
  516. ; Let's save it to SDC_BUFPTR |
  517. ld (SDC_BUFPTR), de ; |
  518. ; |
  519. pop de ; <|
  520. ; We have to read a new sector, but first, let's write the current one
  521. ; if needed.
  522. call sdcWriteBlk
  523. jr nz, .end ; error
  524. ; Let's read our new sector in DE
  525. call sdcReadBlk
  526. jr .end
  527. .buf1Ok:
  528. ld de, SDC_BUFSEC1
  529. ld (SDC_BUFPTR), de
  530. ; Z already set
  531. jr .end
  532. .buf2Ok:
  533. ld de, SDC_BUFSEC2
  534. ld (SDC_BUFPTR), de
  535. ; Z already set
  536. ; to .end
  537. .end:
  538. pop de
  539. ret
  540. ; Computes the CRC-16, with polynomial 0x1021 of buffer at (SDC_BUFPTR) and
  541. ; returns its value in DE. Also, make HL point to the first byte of the CRC
  542. ; associated to (SDC_BUFPTR).
  543. sdcCRC:
  544. push af
  545. push bc
  546. ld hl, (SDC_BUFPTR)
  547. inc hl \ inc hl \ inc hl ; HL points to contents
  548. ld bc, SDC_BLKSIZE
  549. ld de, 0
  550. .loop:
  551. push bc ; <|
  552. ld b, 8 ; |
  553. ld a, (hl) ; |
  554. xor d ; |
  555. ld d, a ; |
  556. .inner: ; |
  557. sla e ; | Sets Carry
  558. rl d ; | Takes and sets carry
  559. jr nc, .noCRC ; |
  560. ; msb was set, apply polyno|mial
  561. ld a, d ; |
  562. xor 0x10 ; |
  563. ld d, a ; |
  564. ld a, e ; |
  565. xor 0x21 ; |
  566. ld e, a ; |
  567. .noCRC: ; |
  568. djnz .inner ; |
  569. pop bc ; <|
  570. cpi ; inc HL, dec BC, sets P/V on BC=0
  571. jp pe, .loop ; BC is not zero, loop
  572. ; At this point, HL points to the right place: the first byte of the
  573. ; recorded CRC.
  574. pop bc
  575. pop af
  576. ret
  577. sdcInitializeCmd:
  578. call sdcInitialize
  579. ret nz
  580. call .setBlkSize
  581. ret nz
  582. call .enableCRC
  583. ret nz
  584. ; At this point, our buffers are unnitialized. We could have some logic
  585. ; that determines whether a buffer is initialized in appropriate SDC
  586. ; routines and act appropriately, but why bother when we could, instead,
  587. ; just buffer the first two sectors of the card on initialization? This
  588. ; way, no need for special conditions.
  589. ; initialize variables
  590. ld hl, SDC_BUFSEC1
  591. ld (SDC_BUFPTR), hl
  592. ld de, 0
  593. call sdcReadBlk ; read sector 0 in buf1
  594. ret nz
  595. ld hl, SDC_BUFSEC2
  596. ld (SDC_BUFPTR), hl
  597. inc de
  598. jp sdcReadBlk ; read sector 1 in buf2, returns
  599. ; Send a command to set block size to SDC_BLKSIZE to the SD card.
  600. ; Returns zero in A if a success, non-zero otherwise
  601. .setBlkSize:
  602. push hl
  603. push de
  604. ld a, 0b01010000 ; CMD16
  605. ld hl, 0
  606. ld de, SDC_BLKSIZE
  607. call sdcCmdR1
  608. ; Since we're out of idle mode, we expect a 0 response
  609. ; We need no further processing: A is already the correct value.
  610. pop de
  611. pop hl
  612. ret
  613. ; Enable CRC checks through CMD59
  614. .enableCRC:
  615. push hl
  616. push de
  617. ld a, 0b01111011 ; CMD59
  618. ld hl, 0
  619. ld de, 1 ; 1 means CRC enabled
  620. call sdcCmdR1
  621. pop de
  622. pop hl
  623. ret
  624. ; Flush the current SDC buffer if dirty
  625. sdcFlushCmd:
  626. ld hl, SDC_BUFSEC1
  627. ld (SDC_BUFPTR), hl
  628. call sdcWriteBlk
  629. ret nz
  630. ld hl, SDC_BUFSEC2
  631. ld (SDC_BUFPTR), hl
  632. jp sdcWriteBlk ; returns
  633. ; *** blkdev routines ***
  634. ; Make HL point to its proper place in SDC_BUF.
  635. ; EHL currently is a 24-bit offset to read in the SD card. E=high byte,
  636. ; HL=low word. Load the proper sector in memory and make HL point to the
  637. ; correct data in the memory buffer.
  638. _sdcPlaceBuf:
  639. call sdcSync
  640. ret nz ; error
  641. ; At this point, we have the proper buffer in place and synced in
  642. ; (SDC_BUFPTR). Only the 9 low bits of HL are important.
  643. push de
  644. ld de, (SDC_BUFPTR)
  645. inc de ; sector MSB
  646. inc de ; dirty flag
  647. inc de ; contents
  648. ld a, h ; high byte
  649. and 0x01 ; is first bit set?
  650. jr z, .read ; first bit reset? we're in the "lowbuf" zone.
  651. ; DE already points to the right place.
  652. ; We're in the highbuf zone, let's inc DE by 0x100, which, as it turns
  653. ; out, is quite easy.
  654. inc d
  655. .read:
  656. ; DE is now placed either on the lower or higher half of the active
  657. ; buffer and all we need is to increase DE the lower half of HL.
  658. ld a, l
  659. call addDE
  660. ex de, hl
  661. pop de
  662. ; Now, HL points exactly at the right byte in the active buffer.
  663. xor a ; ensure Z
  664. ret
  665. sdcGetB:
  666. push hl
  667. call _sdcPlaceBuf
  668. jr nz, .end ; NZ already set
  669. ; This is it!
  670. ld a, (hl)
  671. cp a ; ensure Z
  672. .end:
  673. pop hl
  674. ret
  675. sdcPutB:
  676. push hl
  677. push af ; let's remember the char we put, _sdcPlaceBuf
  678. ; destroys A.
  679. call _sdcPlaceBuf
  680. jr nz, .error
  681. ; HL points to our dest. Recall A and write
  682. pop af
  683. ld (hl), a
  684. ; Now, let's set the dirty flag
  685. ld a, 1
  686. ld hl, (SDC_BUFPTR)
  687. inc hl ; sector MSB
  688. inc hl ; point to dirty flag
  689. ld (hl), a ; set dirty flag
  690. xor a ; ensure Z
  691. jr .end
  692. .error:
  693. ; preserve error code
  694. ex af, af'
  695. pop af
  696. ex af, af'
  697. call unsetZ
  698. .end:
  699. pop hl
  700. ret