This commit is contained in:
lampmerchant 2022-04-24 11:32:03 -06:00
parent 70cf1e5b88
commit a49b5b2f1e

View File

@ -90,8 +90,8 @@ IWMCNT0 equ 0 ; "
M_FAIL equ 7 ;Set when there's been a failure on the MMC interface M_FAIL equ 7 ;Set when there's been a failure on the MMC interface
M_CMDLR equ 6 ;Set when R3 or R7 is expected (5 bytes), not R1 M_CMDLR equ 6 ;Set when R3 or R7 is expected (5 bytes), not R1
M_CMDRB equ 5 ;Set when an R1b is expected (busy signal after reply) M_CMDRB equ 5 ;Set when an R1b is expected (busy signal after reply)
M_MBRD equ 4 ;Set when a multiblock read is in progress M_RDCMD equ 4 ;Set when state machine should do a read command
M_MBWR equ 3 ;Set when a multiblock write is in progress M_ONGWR equ 3 ;Set when state machine shouldn't stop tran on a write
M_BKADR equ 2 ;Set when block (rather than byte) addressing is in use M_BKADR equ 2 ;Set when block (rather than byte) addressing is in use
M_CDVER equ 1 ;Set when dealing with a V2.0+ card, clear for 1.0 M_CDVER equ 1 ;Set when dealing with a V2.0+ card, clear for 1.0
@ -127,7 +127,7 @@ M_CDVER equ 1 ;Set when dealing with a V2.0+ card, clear for 1.0
M_ADR0 ;Fourth (low) byte of the address, last byte of R3/R7 response M_ADR0 ;Fourth (low) byte of the address, last byte of R3/R7 response
M_CRCH ;CRC16 high byte M_CRCH ;CRC16 high byte
M_CRCL ;CRC16 low byte M_CRCL ;CRC16 low byte
X6 ;Various purposes M_STATE ;State of card state machine
X5 ;Various purposes X5 ;Various purposes
X4 ;Various purposes X4 ;Various purposes
X3 ;Various purposes X3 ;Various purposes
@ -526,11 +526,9 @@ Unselected
tris 7 ; done this already, but.. belt and suspenders) tris 7 ; done this already, but.. belt and suspenders)
movlb 3 ;Deassert !HSHK movlb 3 ;Deassert !HSHK
clrf TXREG ; " clrf TXREG ; "
movlb 0 ;Deassert !CS and next !ENBL (the interrupt movlb 0 ;Deassert next !ENBL (the interrupt handler
movlw B'00111111' ; handler will have deasserted next !ENBL movlw B'00111111' ; will have deasserted next !ENBL already,
movwf PORTC ; already, but.. belt and suspenders) movwf PORTA ; but.. belt and suspenders)
movlw B'00111111' ; "
movwf PORTA ; "
clrf DEVNUM ;Reset selected device number to zero clrf DEVNUM ;Reset selected device number to zero
btfsc EN_PORT,EN_PIN ;Wait for Mac to drive !ENBL low btfsc EN_PORT,EN_PIN ;Wait for Mac to drive !ENBL low
bra $-1 ; " bra $-1 ; "
@ -862,6 +860,16 @@ SysIni6 addfsr FSR0,16 ;Move pop pointer ahead to next entry
;;; Receiver ;;; ;;; Receiver ;;;
Receiver Receiver
movlw 4 ;Spend about 262.144 ms waiting for the state
movwf X1 ; machine to try and get the card back to
Receiv0 clrf TMR1H ; waiting for a command or a write token, which
clrf TMR1L ; is about how long we have before Mac tires of
movlw MSSWrEtTok - MSS; waiting for us to acknowledge a command (we
btfss M_FLAGS,M_ONGWR ; actually have ~350 ms, but be cautious);
movlw MSSWaitCmd - MSS; hopefully this will be enough, spec says that
call MmcWaitState ; writes may take up to 200 ms
decfsz X1,F ; "
bra Receiv0 ; "
movlb 3 ;Assert !HSHK to signal to Mac that we're movlb 3 ;Assert !HSHK to signal to Mac that we're
btfss TXSTA,TRMT ; ready to receive btfss TXSTA,TRMT ; ready to receive
bra $-1 ; " bra $-1 ; "
@ -1022,25 +1030,22 @@ BadChk1 movlp 0 ;Return to the idle loop
goto IdleLoop ; " goto IdleLoop ; "
CmdRead CmdRead
call MmcStopOngoing ;Make sure any ongoing write is stopped
movlw ERRCODE ;Ready an error code in case we need to jump movlw ERRCODE ;Ready an error code in case we need to jump
movwf RESPERR ; into the placeholder response routine movwf RESPERR ; into the placeholder response routine
call SetupCmdAddr ;Set up the card address for this command call SetupCmdAddr ;Set up the card address for this command
btfsc STATUS,C ;If the read is out of bounds, send an error btfsc STATUS,C ;If the read is out of bounds, send an error
goto CmdPlaceholder ; response goto CmdPlaceholder ; response
CmdRea0 movlw 0x51 ;Set up a read command for the card (R1-type CmdRea0 bsf M_FLAGS,M_RDCMD ;Set the state machine to do a read for us
movwf M_CMDN ; response) bcf M_FLAGS,M_ONGWR ;Cancel any ongoing write
bcf M_FLAGS,M_CMDLR ; " movlw 4 ;Spend about 262.144 ms waiting for the state
bcf M_FLAGS,M_CMDRB ; " movwf X1 ; machine to prepare the card to read out the
bcf CS_PORT,CS_PIN ;Assert !CS CmdRea5 clrf TMR1H ; data, which is about how long we have before
call MmcCmd ;Send the read command clrf TMR1L ; Mac tires of waiting for a response from us
movf M_CMDN,W ;Treat any error flag as a failed command movlw MSSRdData - MSS ; (we actually have ~350 ms, but be cautious)
andlw B'11111110' ; " call MmcWaitState ; "
btfss STATUS,Z ; " decfsz X1,F ; "
bsf M_FLAGS,M_FAIL ; " bra CmdRea5 ; "
btfss M_FLAGS,M_FAIL ;If no failures up to this point, prepare the btfsc PIR1,TMR1IF ;If there was any failure, respond with a
call MmcGetData ; card to read out data
btfsc M_FLAGS,M_FAIL ;If there was any failure, respond with a
goto CmdPlaceholder ; placeholder with an error code goto CmdPlaceholder ; placeholder with an error code
clrf M_CRCH ;Clear the CRC registers for our read of the clrf M_CRCH ;Clear the CRC registers for our read of the
clrf M_CRCL ; block clrf M_CRCL ; block
@ -1082,6 +1087,8 @@ CmdRea2 moviw FSR0++ ;Pick up the next byte to write from the queue
bra CmdRea2 ; " bra CmdRea2 ; "
decfsz X3,F ; " decfsz X3,F ; "
bra CmdRea2 ; " bra CmdRea2 ; "
movlw MSSWaitCmd - MSS;Finished with read, so set state back to
movwf M_STATE ; WaitCmd
movf M_CRCH,W ;Feeding the CRC through the CRC registers movf M_CRCH,W ;Feeding the CRC through the CRC registers
iorwf M_CRCL,W ; should leave it at zero if the CRC is right; iorwf M_CRCL,W ; should leave it at zero if the CRC is right;
btfss STATUS,Z ; if it's not, send the wrong checksum so Mac btfss STATUS,Z ; if it's not, send the wrong checksum so Mac
@ -1104,7 +1111,6 @@ CmdRea4 comf CHKSUM,W ;CRC failed, so write what we know is the wrong
bra CmdRea3 bra CmdRea3
CmdStatus CmdStatus
call MmcStopOngoing ;Make sure any ongoing write is stopped
movlw 0x21 ;Point to the partition information block for movlw 0x21 ;Point to the partition information block for
movwf FSR0H ; the selected device movwf FSR0H ; the selected device
swapf DEVNUM,W ; " swapf DEVNUM,W ; "
@ -1115,26 +1121,24 @@ CmdStatus
xorlw 0xAF ; built-in icon, not one loaded from the card, xorlw 0xAF ; built-in icon, not one loaded from the card,
btfsc STATUS,Z ; so skip setting up the read btfsc STATUS,Z ; so skip setting up the read
bra CmdSta0 ; " bra CmdSta0 ; "
movlw 0x51 ;Set up a read command for the card (R1-type bsf M_FLAGS,M_RDCMD ;Set the state machine to do a read for us
movwf M_CMDN ; response) bcf M_FLAGS,M_ONGWR ;Cancel any ongoing write
bcf M_FLAGS,M_CMDLR ; "
bcf M_FLAGS,M_CMDRB ; "
clrf M_ADR3 ;Point to the address of the icon to be loaded clrf M_ADR3 ;Point to the address of the icon to be loaded
clrf M_ADR2 ; " clrf M_ADR2 ; "
clrf M_ADR1 ; " clrf M_ADR1 ; "
moviw 4[FSR0] ; " moviw 4[FSR0] ; "
movwf M_ADR0 ; " movwf M_ADR0 ; "
bcf CS_PORT,CS_PIN ;Assert !CS
call MmcConvAddr ;Convert address to bytes if necessary call MmcConvAddr ;Convert address to bytes if necessary
btfss M_FLAGS,M_FAIL ;If the address conversion didn't fail, send movlw 4 ;Spend about 262.144 ms waiting for the state
call MmcCmd ; the read command movwf X1 ; machine to prepare the card to read out the
movf M_CMDN,W ;Treat any error flag as a failed command CmdSta8 clrf TMR1H ; icon, which is about how long we have before
andlw B'11111110' ; " clrf TMR1L ; Mac tires of waiting for a response from us
btfss STATUS,Z ; " movlw MSSRdData - MSS ; (we actually have ~350 ms, but be cautious)
bsf M_FLAGS,M_FAIL ; " call MmcWaitState ; "
btfsc M_FLAGS,M_FAIL ;If the operation failed, use the built-in icon decfsz X1,F ; "
bra CmdSta0 ; instead bra CmdSta8 ; "
call MmcGetData ;Get the card ready to read out data btfsc PIR1,TMR1IF ;If it timed out, use the built in icon instead
bra CmdSta0 ; "
movlw 0x22 ;Point the push pointer off into space and movlw 0x22 ;Point the push pointer off into space and
movwf FSR1H ; read and throw away the first 256 bytes of movwf FSR1H ; read and throw away the first 256 bytes of
movlw 0 ; the icon sector movlw 0 ; the icon sector
@ -1187,7 +1191,7 @@ CmdSta3 movlw 0 ; area (52 bytes), all as zeroes
moviw 4[FSR0] ;If the partition type is 0xAF or we had a fail moviw 4[FSR0] ;If the partition type is 0xAF or we had a fail
xorlw 0xAF ; while reading from the card, we're using the xorlw 0xAF ; while reading from the card, we're using the
btfss STATUS,Z ; built-in icon, so skip ahead to do that btfss STATUS,Z ; built-in icon, so skip ahead to do that
btfsc M_FLAGS,M_FAIL ; " btfsc PIR1,TMR1IF ; "
bra CmdSta4 ; " bra CmdSta4 ; "
movlw 0 ;Copy 256 bytes from the card to the Mac movlw 0 ;Copy 256 bytes from the card to the Mac
call MmcCopyData ; " call MmcCopyData ; "
@ -1232,8 +1236,12 @@ CmdSta7 movlw 0 ; area (52 bytes), all as zeroes
movf CHKSUM,W ;Finish the block off with the checksum movf CHKSUM,W ;Finish the block off with the checksum
call WriteByte ; " call WriteByte ; "
btfss X2,0 ;If we didn't use the built-in icon, finish up btfss X2,0 ;If we didn't use the built-in icon, finish up
call MmcCheckCrc ; with the card by ignoring the CRC call MmcCheckCrc ; with the card by ignoring the CRC and setting
bsf CS_PORT,CS_PIN ;Deassert !CS movlw MSSWaitCmd - MSS; the state back to WaitCmd and deasserting !CS
btfss X2,0 ; "
movwf M_STATE ; "
btfss X2,0 ; "
bsf CS_PORT,CS_PIN ; "
call ReturnToIdle ;Return to the idle state call ReturnToIdle ;Return to the idle state
movlp 0 ;Return to the idle loop movlp 0 ;Return to the idle loop
goto IdleLoop ; " goto IdleLoop ; "
@ -1244,8 +1252,12 @@ CmdWrite
call SetupCmdAddr ;Set up the card address for this command call SetupCmdAddr ;Set up the card address for this command
btfsc STATUS,C ;If the write is out of bounds, send an error btfsc STATUS,C ;If the write is out of bounds, send an error
goto WaitToFinish ; response after we've received the command goto WaitToFinish ; response after we've received the command
btfsc M_FLAGS,M_MBWR ;If we're starting a new write even though a movf M_STATE,W ;If we're not in the await-command state, we
bra CmdWri7 ; multiblock write is ongoing, handle it xorlw MSSWaitCmd - MSS; won't be able to do this write, so send an
btfss STATUS,Z ; error response
goto WaitToFinish ; "
btfsc M_FLAGS,M_ONGWR ;If we're starting a new write even though a
bra CmdWri6 ; multiblock write is ongoing, handle it
movlw 0x59 ;Set up a multiblock write command for the card movlw 0x59 ;Set up a multiblock write command for the card
movwf M_CMDN ; (R1-type reply) movwf M_CMDN ; (R1-type reply)
bcf M_FLAGS,M_CMDLR ; " bcf M_FLAGS,M_CMDLR ; "
@ -1258,7 +1270,7 @@ CmdWrite
bsf M_FLAGS,M_FAIL ; " bsf M_FLAGS,M_FAIL ; "
btfsc M_FLAGS,M_FAIL ;If there was any failure, respond with a btfsc M_FLAGS,M_FAIL ;If there was any failure, respond with a
goto WaitToFinish ; placeholder with an error code goto WaitToFinish ; placeholder with an error code
bsf M_FLAGS,M_MBWR ;Flag that a multiblock write is in progress bsf M_FLAGS,M_ONGWR ;Flag that a multiblock write is in progress
CmdWri0 movlb 4 ;Clock a dummy byte while keeping MOSI high CmdWri0 movlb 4 ;Clock a dummy byte while keeping MOSI high
movlw 0xFF ; " movlw 0xFF ; "
movwf SSP1BUF ; " movwf SSP1BUF ; "
@ -1339,37 +1351,54 @@ CmdWri4 movlb 4 ;Clock the byte out to the card
bra $-1 ; " bra $-1 ; "
movf SSP1BUF,W ;Save data response to check later movf SSP1BUF,W ;Save data response to check later
movwf X2 ; " movwf X2 ; "
call MmcWaitBusy ;Wait for the card not to be busy anymore movlw 0xFF ;Start clocking the first is-still-busy? byte
movlb 0 ;If the data response byte indicated that the movwf SSP1BUF ; "
movf X2,W ; write succeeded, skip ahead movlb 0 ; "
bcf PIR1,SSP1IF ;Clear SSP int flag so it knows when not busy
movlw MSSWrBusy - MSS ;Set the card state to WrBusy so state machine
movwf M_STATE ; knows
decf CMDCNT,W ;If this was the last block, clear the ongoing
btfsc STATUS,Z ; write flag so state machine knows not to stop
bcf M_FLAGS,M_ONGWR ; waiting on a write or stop tran token
movf X2,W ;Check if the write succeeded
andlw B'00011111' ; " andlw B'00011111' ; "
xorlw B'00000101' ; " xorlw B'00000101' ; "
btfsc STATUS,Z ; " btfsc STATUS,Z ;If it did, clear the error flag so we send a
bra CmdWri6 ; " clrf RESPERR ; success response
CmdWri5 call MmcStopOngoing ;Stop the ongoing write btfss STATUS,Z ;If it didn't, clear the ongoing write flag so
btfss IWMFLAG,IWMOVER ;Wait until the Mac's transmission is over bcf M_FLAGS,M_ONGWR ; the write ends here
CmdWri5 btfss IWMFLAG,IWMOVER ;Wait until the Mac's transmission is over
bra $-1 ; " bra $-1 ; "
call ReturnToIdle ;If the checksum was wrong, send a NAK, if it movf CHKSUM,W ;If the checksum didn't match, clear the
movf CHKSUM,W ; was right, send an error btfss STATUS,Z ; ongoing write flag because the write stops
btfss STATUS,Z ; " bcf M_FLAGS,M_ONGWR ; here
goto BadChecksum ; " clrf TMR1H ;Spend about 65.536 ms, which is about how long
clrf TMR1L ; we have before Mac timeouts waiting for us to
movlw MSSWrEtTok - MSS; return to idle, waiting for the state machine
btfss M_FLAGS,M_ONGWR ; to try and get the card back to waiting for
movlw MSSWaitCmd - MSS; a command or a write token (we actually have
call MmcWaitState ; ~90 ms, but let's be cautious)
call ReturnToIdle ;That's long enough, return us to idle
movf CHKSUM,W ;If the checksum was wrong, send a NAK, else
btfss STATUS,Z ; send either a failure or success depending
goto BadChecksum ; on RESPERR
goto CmdPlaceholder ; " goto CmdPlaceholder ; "
CmdWri6 decf CMDCNT,W ;If this was the last block in the write, stop CmdWri6 movlw 1 ;In the unlikely event Mac tried to start a new
btfsc STATUS,Z ; the ongoing write
call MmcStopOngoing ; "
clrf RESPERR ;Send a success response
call ReturnToIdle ; "
goto CmdPlaceholder ; "
CmdWri7 movlw 1 ;In the unlikely event Mac tried to start a new
movwf CHKSUM ; write while one was ongoing, pretend there movwf CHKSUM ; write while one was ongoing, pretend there
bra CmdWri5 ; was a bad checksum so it tries again bra CmdWri5 ; was a bad checksum so it tries again
CmdWriteCont CmdWriteCont
movlw ERRCODE ;Ready an error code in case we need to jump movlw ERRCODE ;Ready an error code in case we need to jump
movwf RESPERR ; into the placeholder response routine movwf RESPERR ; into the placeholder response routine
btfsc M_FLAGS,M_MBWR ;If a multibyte write is already ongoing, as it btfss M_FLAGS,M_ONGWR ;If a write isn't ongoing as it should be,
bra CmdWri0 ; should be, jump into the middle of CmdWrite, bra CmdWrC0 ; handle this
goto WaitToFinish ; otherwise send an error response movf M_STATE,W ;If we're not in the await-token state, we
xorlw MSSWrEtTok - MSS; won't be able to do this write, handle this
btfss STATUS,Z ; "
bra CmdWrC0 ; "
bra CmdWri0 ;Else jump into the middle of CmdWrite
CmdWrC0 bcf M_FLAGS,M_ONGWR ;If something went wrong, end the ongoing write
goto WaitToFinish ; and send an error response
;;; Subprograms ;;; ;;; Subprograms ;;;
@ -1398,21 +1427,21 @@ SetupCmdAddr
movlw 0 ; " movlw 0 ; "
addwfc CMDHIGH,W ; " addwfc CMDHIGH,W ; "
movwf M_ADR2 ; " movwf M_ADR2 ; "
moviw 5[FSR0] ;If the partition size is less than or equal to moviw 7[FSR0] ;If the partition size is less than or equal to
subwf M_ADR0,W ; the maximum block number accessed, return subwf M_ADR0,W ; the maximum block number accessed, return
moviw 6[FSR0] ; with carry set moviw 6[FSR0] ; with carry set
subwfb M_ADR1,W ; " subwfb M_ADR1,W ; "
moviw 7[FSR0] ; " moviw 5[FSR0] ; "
subwfb M_ADR2,W ; " subwfb M_ADR2,W ; "
btfsc STATUS,C ; " btfsc STATUS,C ; "
bra SetCmA0 ; " bra SetCmA0 ; "
movf INDF0,W ;Move the starting block of the partition into movf INDF0,W ;Move the starting block of the partition into
movwf M_ADR3 ; the card address registers movwf M_ADR3 ; the card address registers
moviw 1[INDF0] ; " moviw 1[FSR0] ; "
movwf M_ADR2 ; " movwf M_ADR2 ; "
moviw 2[INDF0] ; " moviw 2[FSR0] ; "
movwf M_ADR1 ; " movwf M_ADR1 ; "
moviw 3[INDF0] ; " moviw 3[FSR0] ; "
addwf CMDLOW,W ;Add the block address from the command to it addwf CMDLOW,W ;Add the block address from the command to it
movwf M_ADR0 ; " movwf M_ADR0 ; "
movf CMDMED,W ; " movf CMDMED,W ; "
@ -1587,6 +1616,7 @@ ReqSnd1 bsf STATUS,Z ;We've successfully requested to send, set the
;Initialize MMC card. Sets M_FAIL on fail. Trashes X0 through X3. ;Initialize MMC card. Sets M_FAIL on fail. Trashes X0 through X3.
MmcInit MmcInit
clrf M_FLAGS ;Make sure flags are all clear to begin with clrf M_FLAGS ;Make sure flags are all clear to begin with
clrf M_STATE ;Make sure state starts at awaiting command
call MmcIni0 ;Call into the function below call MmcIni0 ;Call into the function below
bsf CS_PORT,CS_PIN ;Always deassert !CS bsf CS_PORT,CS_PIN ;Always deassert !CS
movf WREG,W ;If the init function returned a code other movf WREG,W ;If the init function returned a code other
@ -2055,40 +2085,206 @@ MmcChe0 movlw 0xFF ;Clock the low CRC byte out of the card
movlb 0 ; return movlb 0 ; return
return ; " return ; "
;Stop a multiblock read or write, if one is ongoing, and deassert !CS. Sets ;Try to advance to the state requested in W, timing out if Timer1 overflows.
; M_FAIL on fail. Trashes X0 and X1. ; Trashes X0.
MmcStopOngoing MmcWaitState
bcf M_FLAGS,M_FAIL ;Assume no failure to start with movwf X0 ;Save the state caller wants to get to
btfsc M_FLAGS,M_MBWR ;If there's an ongoing write operation, make it movlw B'00110001' ;Turn on Timer1
bra MmcSto0 ; stop movwf T1CON ; "
btfss M_FLAGS,M_MBRD ;If there's not an ongoing read operation, this bcf PIR1,TMR1IF ;Clear the Timer1 interrupt flag if it was set
return ; function was called needlessly, return movf M_STATE,W ;If we're already in the state caller wants to
movlw 0x4C ;Send a CMD12 to stop the ongoing read, R1b xorwf X0,W ; be in, skip ahead
movwf M_CMDN ; reply type btfsc STATUS,Z ; "
clrf M_ADR3 ; " bra MmcWaS1 ; "
clrf M_ADR2 ; " MmcWaS0 call MmcStepState ;Step the state
clrf M_ADR1 ; " movf M_STATE,W ;If we're now in the state caller wants to be
clrf M_ADR0 ; " xorwf X0,W ; in, skip ahead
bcf M_FLAGS,M_CMDLR ; " btfsc STATUS,Z ; "
bsf M_FLAGS,M_CMDRB ; " bra MmcWaS1 ; "
call MmcCmd ; " btfsc PIR1,TMR1IF ;If Timer1 overflowed, skip ahead
bcf M_FLAGS,M_MBRD ;Clear the ongoing multiblock read flag bra MmcWaS2 ; "
bsf CS_PORT,CS_PIN ;Deassert !CS bra MmcWaS0 ;Loop until something happens
return MmcWaS1 bcf T1CON,TMR1ON ;Stop Timer1 and clear its interrupt flag so
MmcSto0 movlb 4 ;Switch to the bank with the SSP registers bcf PIR1,TMR1IF ; caller knows we're in the state requested and
movlw 0xFD ;Clock the end-of-data token into the MMC card return ; did not time out
MmcWaS2 bcf T1CON,TMR1ON ;Stop Timer1 and leave its interrupt flag set
return ; so caller knows a timeout occurred
;State machine to ensure that the card stays in a good state.
MmcStepState
btfss PIR1,SSP1IF ;If the SSP is busy, we can't do anything, so
return ; return
movlb 4 ;Switch depending on the current state
movf M_STATE,W ; "
call MSSCall ; "
movwf M_STATE ;Save the returned value in W as the new state
movlb 0 ; and return
movlp 8 ; "
return ; "
MSSCall brw
MSS
MSSWaitCmd
btfss M_FLAGS,M_RDCMD ;If we're not set to do a read command, cycle
retlw MSSWaitCmd - MSS; back to this state doing nothing
movlb 0 ;Assert !CS
bcf CS_PORT,CS_PIN ; "
movlb 4 ; "
movlw 0x51 ;Clock out the command byte for a read
movwf SSP1BUF ; " movwf SSP1BUF ; "
btfss SSP1STAT,BF ; " movlw 0xE8 ;Set up the CRC register with the CRC7 of the
bra $-1 ; " movwf M_CRCL ; read command byte
movlw 0xFF ;Clock a dummy byte while keeping MOSI high movlb 0 ;Clear the SSP interrupt flag because it's in
bcf PIR1,SSP1IF ; use now
retlw MSSRdCmd1 - MSS ;Transition to the next read command state
MSSRdCmd1
movf M_ADR3,W ;Clock out the high byte of the address
movwf SSP1BUF ; " movwf SSP1BUF ; "
btfss SSP1STAT,BF ; " movlp high LutCrc7 ;Update the CRC for the command
bra $-1 ; " xorwf M_CRCL,W ; "
call MmcWaitBusy ;Wait for the card to not be busy anymore callw ; "
movlb 0 ;Return to the default bank movwf M_CRCL ; "
bcf M_FLAGS,M_MBWR ;Clear the ongoing multiblock write flag movlb 0 ;Clear the SSP interrupt flag because it's in
bsf CS_PORT,CS_PIN ;Deassert !CS bcf PIR1,SSP1IF ; use now
return retlw MSSRdCmd2 - MSS ;Transition to the next read command state
MSSRdCmd2
movf M_ADR2,W ;Clock out the next byte of the address
movwf SSP1BUF ; "
movlp high LutCrc7 ;Update the CRC for the command
xorwf M_CRCL,W ; "
callw ; "
movwf M_CRCL ; "
movlb 0 ;Clear the SSP interrupt flag because it's in
bcf PIR1,SSP1IF ; use now
retlw MSSRdCmd3 - MSS ;Transition to the next read command state
MSSRdCmd3
movf M_ADR1,W ;Clock out the next byte of the address
movwf SSP1BUF ; "
movlp high LutCrc7 ;Update the CRC for the command
xorwf M_CRCL,W ; "
callw ; "
movwf M_CRCL ; "
movlb 0 ;Clear the SSP interrupt flag because it's in
bcf PIR1,SSP1IF ; use now
retlw MSSRdCmd4 - MSS ;Transition to the next read command state
MSSRdCmd4
movf M_ADR0,W ;Clock out the low byte of the address
movwf SSP1BUF ; "
movlp high LutCrc7 ;Update the CRC for the command
xorwf M_CRCL,W ; "
callw ; "
movwf M_CRCL ; "
movlb 0 ;Clear the SSP interrupt flag because it's in
bcf PIR1,SSP1IF ; use now
retlw MSSRdCmd5 - MSS ;Transition to the next read command state
MSSRdCmd5
movf M_CRCL,W ;Clock out the CRC for the command
movwf SSP1BUF ; "
bcf M_FLAGS,M_RDCMD ;Read command complete, M_ADR* are free
movlb 0 ;Clear the SSP interrupt flag because it's in
bcf PIR1,SSP1IF ; use now
retlw MSSRdCmd6 - MSS ;Transition to the next read command state
MSSRdCmd6
movlw 0xFF ;Clock first is-still-busy? byte out of the
movwf SSP1BUF ; card
movlb 0 ;Clear the SSP interrupt flag because it's in
bcf PIR1,SSP1IF ; use now
retlw MSSRdCmd7 - MSS ; "
MSSRdCmd7
btfss SSP1BUF,7 ;If MSB is set, this isn't an R1 response byte,
bra $+6 ; so clock out another byte and try again
movlw 0xFF ; "
movwf SSP1BUF ; "
movlb 0 ; "
bcf PIR1,SSP1IF ; "
retlw MSSRdCmd7 - MSS ; "
movf SSP1BUF,W ;If MSB is clear but an error bit is set, the
andlw B'11111110' ; command was not processed, so go back to the
btfsc STATUS,Z ; WaitCmd state after deasserting !CS
bra $+4 ; "
movlb 0 ; "
bsf CS_PORT,CS_PIN ; "
retlw MSSWaitCmd - MSS; "
movlw 0xFF ;If all error bits are clear in the response
movwf SSP1BUF ; byte, clock out the first is-read-token? byte
movlb 0 ; "
bcf PIR1,SSP1IF ; "
retlw MSSRdTok - MSS ; "
MSSRdTok
movf SSP1BUF,W ;Check if the byte read from the card is the
xorlw 0xFE ; read token
btfsc STATUS,Z ;If the byte read was not the read token, start
bra $+6 ; the next byte clocking out and remain in this
movlw 0xFF ; state for next call
movwf SSP1BUF ; "
movlb 0 ; "
bcf PIR1,SSP1IF ; "
retlw MSSRdTok - MSS ; "
movlw 0xFD ;If byte read was the read token, transition
movwf M_CRCH ; to RdData using CRC register as an up counter
movwf M_CRCL ; set to -515 (512 bytes + 2 CRC bytes + 1),
retlw MSSRdData - MSS ; assuming we have to throw away the read data
MSSRdData
incf M_CRCL,F ;Step the up counter
btfsc STATUS,Z ; "
incf M_CRCH,F ; "
btfss STATUS,Z ;If the up counter overflowed, deassert !CS
bra $+4 ; and reset the state to WaitCmd without
movlb 0 ; starting a byte clocking
bsf CS_PORT,CS_PIN ; "
retlw MSSWaitCmd - MSS; "
movlw 0xFF ;Start the next byte to read clocking out and
movwf SSP1BUF ; stay in this state for next time
movlb 0 ; "
bcf PIR1,SSP1IF ; "
retlw MSSRdData - MSS ; "
MSSWrEtTok
btfsc M_FLAGS,M_ONGWR ;If there's an ongoing write, don't proceed in
retlw MSSWrEtTok - MSS; sending an end tran token
movlw 0xFD ;Start an end tran token clocking
movwf SSP1BUF ; "
movlb 0 ;Clear the SSP interrupt flag because it's in
bcf PIR1,SSP1IF ; use now
retlw MSSEtJnk1 - MSS ;Transition to EtJnk1
MSSEtJnk1
movlw 0xFF ;Byte we got in when we clocked out the end
movwf SSP1BUF ; tran token is junk, so is the next one
movlb 0 ;Clear the SSP interrupt flag because it's in
bcf PIR1,SSP1IF ; use now
retlw MSSEtJnk2 - MSS ;Transition to EtJnk2
MSSEtJnk2
movlw 0xFF ;Byte we got in from previous state is junk,
movwf SSP1BUF ; the one we're clocking now is legit
movlb 0 ;Clear the SSP interrupt flag because it's in
bcf PIR1,SSP1IF ; use now
retlw MSSEtBusy - MSS ;Transition to EtBusy
MSSEtBusy
movf SSP1BUF,W ;If the byte we read out of the card is not all
btfsc STATUS,Z ; zeroes, deassert !CS and transition to
bra $+4 ; WaitCmd
movlb 0 ; "
bsf CS_PORT,CS_PIN ; "
retlw MSSWaitCmd - MSS; "
movlw 0xFF ;If the byte we read out of the card is all
movwf SSP1BUF ; zeroes, clock the next one out while keeping
movlb 0 ; MOSI high and stay in this state
bcf PIR1,SSP1IF ; "
retlw MSSEtBusy - MSS ; "
MSSWrBusy
movf SSP1BUF,W ;If the byte clocked in is 0x00, clock another
btfss STATUS,Z ; byte out and return to this state
bra $+6 ; "
movlw 0xFF ; "
movwf SSP1BUF ; "
movlb 0 ; "
bcf PIR1,SSP1IF ; "
retlw MSSWrBusy - MSS ; "
btfsc M_FLAGS,M_ONGWR ;If there's an ongoing write, transition to let
retlw MSSWrEtTok - MSS; the caller send a data token if it wants to
movlw 0xFD ;Else, start an end tran token clocking
movwf SSP1BUF ; "
movlb 0 ;Clear the SSP interrupt flag because it's in
bcf PIR1,SSP1IF ; use now
retlw MSSEtJnk1 - MSS ;Transition to EtJnk1
;;; End of Program ;;; ;;; End of Program ;;;