709 lines
20 KiB
Text
709 lines
20 KiB
Text
//------------------------------------------------------------------------
|
|
// MMC64 ReadWrite Library
|
|
//
|
|
// Author: Mattias Hansson
|
|
// Copyright (c) : 2005 Mattias Hansson
|
|
// License: GNU GPL 2
|
|
// Language: 65CM v0.4+
|
|
// Dependencies:
|
|
// ZP usage: $fb-$fc (pointer to buffer)
|
|
// Target: Commodore 64 with MMC64 interface
|
|
//
|
|
// functions:
|
|
// ( MMC cartridge level )
|
|
// lib_mmc64_enable
|
|
// lib_mmc64_status
|
|
// ( MMC-card or SD-card level )
|
|
// lib_mmc64_cardinit
|
|
// lib_mmc64_readsector
|
|
//
|
|
// External compiler directive support:
|
|
// __LIB_MMC64_OPTIMIZE_SIZE - define this to build lib smaller
|
|
// but slower (default UNDEFINED)
|
|
// __LIB_MMC64_READONLY - define this to build the lib to support
|
|
// only read operations (decreasing it's size)
|
|
// (default UNDEFINED)
|
|
//
|
|
// Note: Some of the code is copied from Olivers Achtens democode.
|
|
// I havent removed any comments or anything and it's very clear to
|
|
// see, what comes from his paper caller "mmc64prog.txt". These
|
|
// parts of the code are, if I understand it right, in the public domain
|
|
// as just code-snippets to demonstrate how the MMC64 can be accessed.
|
|
// Just want to clarify everything, and give credit where credit due.
|
|
//
|
|
// Note2: Communication with MMC/SD in this lib is implemented to always
|
|
// Align with sectorsizes i.e. $200. i.e. AccessAddress % $200 is always
|
|
// zero(!). Every single read or write access is always $200 long.
|
|
// (Reason: This seams to keep all MMC/SD iv'e tried happy and provides
|
|
// realiable communications.)
|
|
//
|
|
// Mattias Hansson
|
|
//------------------------------------------------------------------------
|
|
|
|
#IFNDEF __LIB_MMC64
|
|
#DEFINE __LIB_MMC64 = 1
|
|
|
|
//Define __LIB_MMC64_OPTIMIZE_SIZE externally to optimize for size instead of speed.
|
|
#IFNDEF __LIB_MMC64_OPTIMIZE_SIZE
|
|
#DEFINE __LIB_MMC64_OPTIMIZE_SPEED = 1
|
|
#IFEND
|
|
|
|
//This define is needed to include the code needed for writesupport.
|
|
#IFNDEF __LIB_MMC64_READONLY
|
|
#PRINT Write access in mmc65lib.c65 is experimental!!!
|
|
#DEFINE __LIB_MMC64_WRITESUPPORT = 1
|
|
#IFEND
|
|
|
|
GOTO lib_mmc64_skip
|
|
|
|
|
|
//------------------------------------------------------------------------
|
|
// buffer pointer zeropage variable used for data transfer function
|
|
//------------------------------------------------------------------------
|
|
WORD lib_mmc64_buffer_ptr @ $fb
|
|
|
|
//------------------------------------------------------------------------
|
|
// MMC64 reader status constants
|
|
//
|
|
// Everything except LIB_MMC64_R_OK
|
|
// is an error.
|
|
// Constants in order of importance.
|
|
//------------------------------------------------------------------------
|
|
|
|
BYTE CONST LIB_MMC64_R_OK = 0
|
|
BYTE CONST LIB_MMC64_R_BUSY = 1
|
|
BYTE CONST LIB_MMC64_R_NOCARD = 2
|
|
BYTE CONST LIB_MMC64_R_FLASH_ENABLED = 3
|
|
|
|
|
|
//------------------------------------------------------------------------
|
|
// lib_mmc64_enable
|
|
//
|
|
// Purpose: Enables the MMC64 cartridge
|
|
// Params: none.
|
|
// Preparation: none.
|
|
//------------------------------------------------------------------------
|
|
FUNC lib_mmc64_enable
|
|
ASM
|
|
;(re)enable MMC64
|
|
lda #$0A
|
|
sta $df13
|
|
lda #$1C
|
|
sta $df13
|
|
|
|
;enable MMC64 with initial settings
|
|
lda $df11 ;get contents of MMC64 control register
|
|
and #%10111011 ;set 250khz & write trigger mode
|
|
ora #%00000010 ;disable card select
|
|
sta $df11 ;update control register
|
|
ENDASM
|
|
FEND
|
|
|
|
|
|
//------------------------------------------------------------------------
|
|
// lib_mmc64_status
|
|
//
|
|
// Purpose:
|
|
// To get actual status codes from the reader controller.
|
|
// Parameters:
|
|
// out:lib_mmc64_st_value - Value of one of the
|
|
// "MMC64 reader status constants" defined
|
|
// above.
|
|
//
|
|
// Preparation: lib_mmc64_enable
|
|
//
|
|
//------------------------------------------------------------------------
|
|
|
|
BYTE lib_mmc64_st_value
|
|
FUNC lib_mmc64_status ( out:lib_mmc64_st_value )
|
|
ASM
|
|
lda $df12
|
|
and #%00111001
|
|
asl
|
|
asl
|
|
asl ; flash jumper enabled bit. true if set!
|
|
bcc lib_mmc64_rstatus_l1 ; if NOT flash jumper is set
|
|
|
|
;flash jumper is set!
|
|
lda #3
|
|
sta lib_mmc64_st_value
|
|
rts
|
|
|
|
lib_mmc64_rstatus_l1
|
|
asl
|
|
asl ; card inserted bit. card NOT inserted if set
|
|
bcc lib_mmc64_rstatus_l2 ; if card IS inserted
|
|
|
|
; no card inserted!
|
|
lda #2
|
|
sta lib_mmc64_st_value
|
|
rts
|
|
|
|
lib_mmc64_rstatus_l2
|
|
and #%00100000 ; the current position of the busy-bit after ASL's above
|
|
beq lib_mmc64_rstatus_l3 ; after the and-operation we have a 0-value if all is ok, so we store it!
|
|
|
|
lda #1 ; card is busy
|
|
lib_mmc64_rstatus_l3
|
|
sta lib_mmc64_st_value
|
|
ENDASM
|
|
FEND
|
|
|
|
//------------------------------------------------------------------------
|
|
// lib_mmc64_set512blocks
|
|
//
|
|
// Send CMD16 to MMC/SD to set the blocksize to $200 (512) which is the
|
|
// only transfer size used in this lib.
|
|
// This size is the defaut when doing read operations, but must be
|
|
// exclusivly set when attempting writes to the MMC/SD
|
|
//------------------------------------------------------------------------
|
|
|
|
#IFDEF __LIB_MMC64_WRITESUPPORT
|
|
|
|
FUNC lib_mmc64_set512blocks
|
|
|
|
ASM
|
|
ldy #$09
|
|
lib_mmc64_s5_l1
|
|
lda lib_mmc64_s5_cmd16-1,y
|
|
sta $df10
|
|
dey
|
|
bne lib_mmc64_s5_l1
|
|
ENDASM
|
|
FEND
|
|
|
|
ASM
|
|
lib_mmc64_s5_cmd16
|
|
!8 $ff,$ff,$ff,$00,$02,$00,$00,$50,$ff ;CMD16
|
|
ENDASM
|
|
|
|
#IFEND
|
|
|
|
//------------------------------------------------------------------------
|
|
// lib_mmc64_cardinit
|
|
//
|
|
// Purpose: Reset the SD||MMC card and set it up in SPI mode
|
|
// Params: none.
|
|
// Preparation: lib_mmc64_enable,
|
|
// (lib_mmc64_status
|
|
// to know that there is a working card in the slot)
|
|
//
|
|
//------------------------------------------------------------------------
|
|
|
|
FUNC lib_mmc64_cardinit
|
|
ASM
|
|
|
|
lib_mmc64_reset
|
|
ldx #$0a ;initialize counter (10*8 pulses)
|
|
ldy #$ff ;initialize value to be written (bits must be all high)
|
|
lib_mmc64_reset_l1
|
|
sty $df10 ;send 8 pulses to the card
|
|
lib_mmc64_reset_l2
|
|
lda $df12 ;we catch the status register
|
|
and #$01 ;all bits shiftet out?
|
|
bne lib_mmc64_reset_l2 ;nope, so wait
|
|
dex ;decrement counter
|
|
bne lib_mmc64_reset_l1 ;until 80 pulses sent
|
|
lda $df11 ;pull card chip select line down for SPI communication
|
|
and #%11111101
|
|
sta $df11
|
|
|
|
lib_mmc64_reset_l6
|
|
ldy #$09 ;we send 8 command bytes to the card
|
|
lib_mmc64_reset_l3
|
|
lda lib_mmc64_reset_cmdtxt0-1,y ;grab command byte
|
|
sta $df10 ;and fire it to the card
|
|
lib_mmc64_reset_l4
|
|
lda $df12 ;we check the busy bit
|
|
and #$01 ;to ensure that the transfer is safe
|
|
bne lib_mmc64_reset_l4
|
|
dey ;decrease command counter
|
|
bne lib_mmc64_reset_l3 ;until the entire command has been sent
|
|
lda $df10 ;now we check the card response
|
|
and #$01 ;did it accept the command ?
|
|
bne lib_mmc64_reset_l5 ;ok, everything is fine !
|
|
lda $df12 ;is there a card at all ?
|
|
and #$08
|
|
beq lib_mmc64_reset_l6 ;yup, so we just resend the command
|
|
lib_mmc64_reset_l5
|
|
|
|
lib_mmc64_reset_l7
|
|
ldy #$09 ;we send 8 command bytes to the card
|
|
lib_mmc64_reset_l8
|
|
lda lib_mmc64_reset_cmdtxt1-1,y ;grab command byte
|
|
sta $df10 ;and fire it to the card
|
|
lib_mmc64_reset_l9
|
|
lda $df12 ;we check the busy bit
|
|
and #$01 ;to ensure that the transfer is safe
|
|
bne lib_mmc64_reset_l9
|
|
dey ;decrease command counter
|
|
bne lib_mmc64_reset_l8 ;until entire command has been sent
|
|
lda $df10 ;did the card left its init state?
|
|
and #$01
|
|
bne lib_mmc64_reset_l7 ;no, so we resend the command to check it again
|
|
|
|
;Enable 8Mhz mode
|
|
lda $df11
|
|
ora #%00000100
|
|
sta $df11
|
|
|
|
ENDASM
|
|
#IFDEF __LIB_MMC64_WRITESUPPORT
|
|
CALL lib_mmc64_set512blocks
|
|
#IFEND
|
|
|
|
FEND
|
|
|
|
ASM
|
|
|
|
lib_mmc64_reset_cmdtxt0
|
|
!8 $ff,$ff,$95,$00,$00,$00,$00,$40,$ff ;CMD0
|
|
lib_mmc64_reset_cmdtxt1
|
|
!8 $ff,$ff,$ff,$00,$00,$00,$00,$41,$ff ;CMD1
|
|
|
|
ENDASM
|
|
|
|
//------------------------------------------------------------------------
|
|
// lib_mmc64_readsector
|
|
//
|
|
// Purpose: To read a sector specified by the 24-bit number sent in.
|
|
// (65CM does not support larger types than 16-bit so we have
|
|
// to use two.) and put the data where the buffer pointer points.
|
|
//
|
|
// lib_mmc64_readsector_part
|
|
//
|
|
// Purpose: Like above but optionally be able to choose what part of the
|
|
// sector caller wants to read. This call was implemented to
|
|
// allow FAT16 to:
|
|
// 1. Read files to their real end (not the end of the last sector of a file)
|
|
// 2. fgetc()
|
|
//
|
|
// Params:
|
|
// lib_mmc64_rs_sectornr_lo = the two lowest bytes of the 24-bit sector#
|
|
// lib_mmc64_rs_sectornr_hi = the highest byte of the 24-bit sector#
|
|
// lib_mmc64_buffer_ptr = the address where to put the read data
|
|
// lib_mmc64_rs_status = after a completed operation the caller can
|
|
// check if it went OK. 0=OK. !0=fail!
|
|
//
|
|
// Params (extended for "lib_mmc64_readsector_part"):
|
|
// WORD first_pos - first byte in the sector to write to memory
|
|
// WORD read_count - how many bytes to write to target memory
|
|
//
|
|
// Preparation: lib_mmc64_cardinit
|
|
//------------------------------------------------------------------------
|
|
|
|
WORD lib_mmc64_rs_sectornr_lo
|
|
BYTE lib_mmc64_rs_sectornr_hi
|
|
BYTE lib_mmc64_rs_status
|
|
|
|
FUNC lib_mmc64_readsector ( lib_mmc64_rs_sectornr_lo lib_mmc64_rs_sectornr_hi lib_mmc64_buffer_ptr out:lib_mmc64_rs_status )
|
|
|
|
WORD first_pos // in bytes
|
|
WORD read_count
|
|
|
|
LET first_pos = 0
|
|
LET read_count = 512
|
|
|
|
FUNC lib_mmc64_readsector_part ( lib_mmc64_rs_sectornr_lo lib_mmc64_rs_sectornr_hi lib_mmc64_buffer_ptr first_pos read_count out:lib_mmc64_rs_status )
|
|
|
|
WORD totalread
|
|
BYTE readbyte
|
|
|
|
LET lib_mmc64_rs_status = 1
|
|
|
|
// If what we are reading up is to the internal buffer
|
|
// We compare the sector# sent in with the last sector#
|
|
// read there. We don't need to read it up if it's equal.
|
|
// Note: this code relies on lib_fat16. Not nice, but
|
|
// It'll do for now.
|
|
// Note2: this is not neccessary for normal operation
|
|
// but will certainly speed up continous read-speed when
|
|
// used on a non-fragmented file, a whole lot.
|
|
// (without optimization it reads up a sector from the
|
|
// FAT everytime we change cluster, as it's unaware of
|
|
// whats in the fat_buffer for the moment)
|
|
// Therefore it's only included if compiled with speed
|
|
// optimization.
|
|
#IFDEF __LIB_MMC64_OPTIMIZE_SPEED
|
|
ASM
|
|
lda lib_mmc64_buffer_ptr
|
|
cmp #<lib_fat16_fatbuffer
|
|
bne lib_mmc64_rs_buffnotequal_skip
|
|
lda lib_mmc64_buffer_ptr+1
|
|
cmp #>lib_fat16_fatbuffer
|
|
bne lib_mmc64_rs_buffnotequal_skip
|
|
; here we know that the pointer sent in is indeed the internal FAT buffer.
|
|
|
|
lda lib_mmc64_rs_sectornr_lo
|
|
cmp lib_mmc64_rs_oldsector
|
|
bne lib_mmc64_rs_storenewbuffsector
|
|
lda lib_mmc64_rs_sectornr_lo+1
|
|
cmp lib_mmc64_rs_oldsector+1
|
|
bne lib_mmc64_rs_storenewbuffsector
|
|
lda lib_mmc64_rs_sectornr_hi
|
|
cmp lib_mmc64_rs_oldsector+2
|
|
bne lib_mmc64_rs_storenewbuffsector
|
|
|
|
lda #0
|
|
sta lib_mmc64_rs_status
|
|
rts ; if everything matched we just saved the caller the whole readup
|
|
; of the sector in question.
|
|
lib_mmc64_rs_storenewbuffsector
|
|
lda lib_mmc64_rs_sectornr_lo
|
|
sta lib_mmc64_rs_oldsector
|
|
lda lib_mmc64_rs_sectornr_lo+1
|
|
sta lib_mmc64_rs_oldsector+1
|
|
lda lib_mmc64_rs_sectornr_hi
|
|
sta lib_mmc64_rs_oldsector+2
|
|
|
|
jmp lib_mmc64_rs_buffnotequal_skip
|
|
lib_mmc64_rs_oldsector
|
|
!24 $ffffff
|
|
|
|
lib_mmc64_rs_buffnotequal_skip
|
|
ENDASM
|
|
#IFEND //__LIB_MMC64_OPTIMIZE_SPEED
|
|
|
|
ASM
|
|
|
|
;first we recalc the sector nr to byte nr (that the card requires)
|
|
;since a sector of a MMC or SD card is 512 bytes it's "shift left 9"
|
|
;shift left 8 is done by just shifting the bytes (naturally) which
|
|
;leaves us 1 shift left to do.
|
|
|
|
clc
|
|
rol lib_mmc64_rs_sectornr_lo
|
|
rol lib_mmc64_rs_sectornr_lo+1
|
|
rol lib_mmc64_rs_sectornr_hi
|
|
|
|
lda #0
|
|
sta lib_mmc64_rs_bytenr
|
|
lda lib_mmc64_rs_sectornr_lo
|
|
sta lib_mmc64_rs_bytenr+1
|
|
lda lib_mmc64_rs_sectornr_lo+1
|
|
sta lib_mmc64_rs_bytenr+2
|
|
lda lib_mmc64_rs_sectornr_hi
|
|
sta lib_mmc64_rs_bytenr+3
|
|
|
|
ldy #$09
|
|
lib_mmc64_rs_l1
|
|
lda lib_mmc64_rs_cmd17-1,y
|
|
sta $df10
|
|
dey
|
|
bne lib_mmc64_rs_l1
|
|
|
|
lib_mmc64_rs_l2
|
|
lda #$ff
|
|
sta $df10 ;write all high bits
|
|
lda $df10 ;to give the possibility to respond
|
|
cmp #$fe ;has it started?
|
|
beq lib_mmc64_rs_l4 ; start receive
|
|
cmp #0
|
|
beq lib_mmc64_rs_l2 ; still waiting for card to answer
|
|
cmp #$ff
|
|
beq lib_mmc64_rs_l2 ; still waiting for card to answer
|
|
|
|
jmp lib_mmc64_rs_error_exit ; Serious error - sector could not be read.
|
|
; (normaly this is because we've called the
|
|
; blockread CMD17 with a wrong param!)
|
|
|
|
|
|
lib_mmc64_rs_l4 ; start receive
|
|
|
|
lda $df11 ;set MMC64 into read trigger mode
|
|
ora #%01000000 ;which means every read triggers a SPI transfer
|
|
sta $df11
|
|
|
|
lda $df10 ;we have to start with one dummy read here
|
|
|
|
ENDASM
|
|
|
|
#IFDEF __LIB_MMC64_OPTIMIZE_SPEED
|
|
|
|
//If we're about to read the whole sector we use this routine!
|
|
//It's faster than the one below, 'coz it does not check for
|
|
//anything except the $200 (512) limit.
|
|
IF first_pos == 0
|
|
IF read_count == 512
|
|
ASM
|
|
ldx #$02 ;set up counters
|
|
ldy #$00
|
|
lib_mmc64_rs_l3
|
|
lda $df10 ;get data byte from card
|
|
sta (lib_mmc64_buffer_ptr),y ;store it into memory ( memptr has to be initialized)
|
|
iny ;have we copied 256 bytes ?
|
|
bne lib_mmc64_rs_l3 ;nope, so go on!
|
|
inc lib_mmc64_buffer_ptr+1 ;increase memory pointer for next 256 bytes
|
|
dex ;have we copied 512 bytes ?
|
|
bne lib_mmc64_rs_l3
|
|
|
|
ENDASM
|
|
GOTO lib_mmc64_rs_skipelse1
|
|
ENDIF
|
|
ENDIF
|
|
|
|
#IFEND //__LIB_MMC64_OPTIMIZE_SPEED
|
|
|
|
//ELSE - we want to read just a part of the sector. so this routine is used instead
|
|
|
|
LET totalread = 0
|
|
WHILE totalread < 512
|
|
IF first_pos == 0
|
|
IF read_count == 0
|
|
GOTO lib_mmc64_rs_dummyread
|
|
ENDIF
|
|
PEEK $df10 -> readbyte
|
|
POKE lib_mmc64_buffer_ptr , readbyte
|
|
INC lib_mmc64_buffer_ptr
|
|
DEC read_count
|
|
ELSE //prepare for first position
|
|
DEC first_pos
|
|
LABEL lib_mmc64_rs_dummyread
|
|
ASM
|
|
lda $df10 ; dummyread a byte (to move forward for the desired offset)
|
|
ENDASM
|
|
ENDIF
|
|
INC totalread
|
|
WEND
|
|
|
|
|
|
LABEL lib_mmc64_rs_skipelse1
|
|
ASM
|
|
lda $df10 ;we have to end the data transfer with one dummy read
|
|
|
|
lda $df11 ;now we put the hardware back into write trigger mode again
|
|
and #%10111111
|
|
sta $df11
|
|
|
|
ENDASM
|
|
|
|
LET lib_mmc64_rs_status = 0 // if we got this far it's a successful read!
|
|
|
|
LABEL lib_mmc64_rs_error_exit
|
|
|
|
|
|
FEND
|
|
|
|
|
|
|
|
ASM
|
|
;!pet "debugtxt>"
|
|
|
|
lib_mmc64_rs_cmd17
|
|
;Outline of the command (read sector 0)
|
|
;!8 $ff,$ff,$ff,$00,$00,$00,$00,$51,$ff ;CMD17
|
|
; ^^^^^^^^^^^^^^^ <- 32 bit byte offset where we want to read
|
|
; In this lib we always send in byte-offsets corresponding to a sector start.i (i.e. $200*sectornr)
|
|
;
|
|
;Start of command
|
|
!8 $ff,$ff,$ff
|
|
lib_mmc64_rs_bytenr
|
|
!32 0
|
|
!8 $51,$ff ;CMD17
|
|
|
|
ENDASM
|
|
|
|
//------------------------------------------------------------------------
|
|
// lib_mmc64_writesector
|
|
//
|
|
// Purpose: To write a sector specified by the 24-bit number sent in.
|
|
// (65CM does not support larger types than 16-bit so we have
|
|
// to use two.) data for the write is taken from where
|
|
// lib_mmc64_buffer_ptr points and onwards $200(512) bytes.
|
|
//
|
|
// lib_mmc64_writesector_part
|
|
//
|
|
// Purpose: Like above but optionally be able to choose what part of the
|
|
// sector caller wants to write. This call was implemented to
|
|
// allow FAT16 to write just the part of the sector that represents
|
|
// the actual EOF in the file. (rest will be zero-filled)
|
|
//
|
|
// Note: Mem-pointer points to the actual area to be written.
|
|
// I.e. first_pos equals byte @ lib_mmc64_buffer_ptr
|
|
//
|
|
// Params:
|
|
// lib_mmc64_ws_sectornr_lo = the two lowest bytes of the 24-bit sector#
|
|
// lib_mmc64_ws_sectornr_hi = the highest byte of the 24-bit sector#
|
|
// lib_mmc64_buffer_ptr = the address where to read data for writing
|
|
// lib_mmc64_ws_status = after a completed operation the caller can
|
|
// check if it went OK. 0=OK. !0=fail!
|
|
//
|
|
// Params (extended for "lib_mmc64_readsector_part"):
|
|
// WORD first_pos - first byte in the sector to write to memory
|
|
// WORD read_count - how many bytes to write to target memory
|
|
//
|
|
// Preparation: lib_mmc64_cardinit
|
|
//------------------------------------------------------------------------
|
|
|
|
#IFDEF __LIB_MMC64_WRITESUPPORT
|
|
|
|
//Block write command - set up a 512 byte transfer to the SD Card from $00000100 to $000002ff
|
|
|
|
WORD lib_mmc64_ws_sectornr_lo
|
|
BYTE lib_mmc64_ws_sectornr_hi
|
|
BYTE lib_mmc64_ws_status
|
|
|
|
FUNC lib_mmc64_writesector ( lib_mmc64_ws_sectornr_lo lib_mmc64_ws_sectornr_hi lib_mmc64_buffer_ptr out:lib_mmc64_ws_status )
|
|
|
|
WORD first_pos // in bytes
|
|
WORD read_count
|
|
|
|
LET first_pos = 0
|
|
LET read_count = 512
|
|
|
|
FUNC lib_mmc64_writesector_part ( lib_mmc64_ws_sectornr_lo lib_mmc64_ws_sectornr_hi lib_mmc64_buffer_ptr first_pos read_count out:lib_mmc64_ws_status )
|
|
|
|
WORD totalwritten
|
|
BYTE writebyte
|
|
|
|
LET lib_mmc64_ws_status = 1
|
|
|
|
|
|
//To make writesector compatible with the internal
|
|
//buffer-caching done in readsector we must update
|
|
//the pointers to the "oldsector". A write will
|
|
//always be issued though
|
|
#IFDEF __LIB_MMC64_OPTIMIZE_SPEED
|
|
ASM
|
|
lda lib_mmc64_buffer_ptr
|
|
cmp #<lib_fat16_fatbuffer
|
|
bne lib_mmc64_ws_buffnotequal_skip
|
|
lda lib_mmc64_buffer_ptr+1
|
|
cmp #>lib_fat16_fatbuffer
|
|
bne lib_mmc64_ws_buffnotequal_skip
|
|
; here we know that the pointer sent in is indeed the internal FAT buffer.
|
|
|
|
;here we write down (for eventual future caller request)
|
|
;what sector the data in the buffer will represent after we write it
|
|
lda lib_mmc64_ws_sectornr_lo
|
|
sta lib_mmc64_rs_oldsector
|
|
lda lib_mmc64_ws_sectornr_lo+1
|
|
sta lib_mmc64_rs_oldsector+1
|
|
lda lib_mmc64_ws_sectornr_hi
|
|
sta lib_mmc64_rs_oldsector+2
|
|
|
|
lib_mmc64_ws_buffnotequal_skip
|
|
ENDASM
|
|
#IFEND //__LIB_MMC64_OPTIMIZE_SPEED
|
|
|
|
ASM
|
|
|
|
;first we recalc the sector nr to byte nr (that the card requires)
|
|
;since a sector of a MMC or SD card is 512 bytes it's "shift left 9"
|
|
;shift left 8 is done by just shifting the bytes (naturally) which
|
|
;leaves us 1 shift left to do.
|
|
|
|
clc
|
|
rol lib_mmc64_ws_sectornr_lo
|
|
rol lib_mmc64_ws_sectornr_lo+1
|
|
rol lib_mmc64_ws_sectornr_hi
|
|
|
|
lda #0
|
|
sta lib_mmc64_ws_bytenr
|
|
lda lib_mmc64_ws_sectornr_lo
|
|
sta lib_mmc64_ws_bytenr+1
|
|
lda lib_mmc64_ws_sectornr_lo+1
|
|
sta lib_mmc64_ws_bytenr+2
|
|
lda lib_mmc64_ws_sectornr_hi
|
|
sta lib_mmc64_ws_bytenr+3
|
|
ENDASM
|
|
|
|
//Now we send CMD24 (Write single sector command) to MMC/SD
|
|
ASM
|
|
ldy #$09
|
|
lib_mmc64_ws_l1
|
|
lda lib_mmc64_ws_cmd24-1,y
|
|
sta $df10
|
|
dey
|
|
bne lib_mmc64_ws_l1
|
|
|
|
ldx #$ff ;we send the sequence $ff,$ff,$fe to start the transfer
|
|
stx $df10
|
|
stx $df10
|
|
dex
|
|
stx $df10
|
|
|
|
ENDASM
|
|
|
|
//If we're about to write the whole sector we use this routine
|
|
//just like the write routine
|
|
IF first_pos == 0
|
|
IF read_count == 512
|
|
ASM
|
|
;And now we can write the data to the card:
|
|
|
|
ldx #$02 ;set up counters
|
|
ldy #$00
|
|
lib_mmc64_ws_l2
|
|
lda (lib_mmc64_buffer_ptr),y ;get byte from C64 memory
|
|
sta $df10 ;give it to the card
|
|
|
|
iny ;have we copied 256 bytes ?
|
|
bne lib_mmc64_ws_l2
|
|
inc lib_mmc64_buffer_ptr+1 ;increase memory pointer for next 256 bytes
|
|
dex ;have we copied 512 bytes ?
|
|
bne lib_mmc64_ws_l2
|
|
ENDASM
|
|
GOTO lib_mmc64_ws_skipelse1
|
|
ENDIF
|
|
ENDIF
|
|
|
|
//ELSE - we want to write just a part of the sector. so this routine is used instead
|
|
LET totalwritten = 0
|
|
WHILE totalwritten < 512
|
|
IF first_pos == 0
|
|
IF read_count == 0
|
|
GOTO lib_mmc64_ws_dummywrite
|
|
ENDIF
|
|
PEEK lib_mmc64_buffer_ptr -> writebyte
|
|
POKE $df10 , writebyte
|
|
INC lib_mmc64_buffer_ptr
|
|
DEC read_count
|
|
GOTO lib_mmc64_ws_skipelse2
|
|
ENDIF
|
|
//ELSE prepare for first position
|
|
|
|
DEC first_pos
|
|
LABEL lib_mmc64_ws_dummywrite
|
|
ASM
|
|
lda #0
|
|
sta $df10 ; dummywrite NULL to rest of the sector.
|
|
ENDASM
|
|
|
|
LABEL lib_mmc64_ws_skipelse2
|
|
INC totalwritten
|
|
WEND
|
|
|
|
ASM
|
|
|
|
lib_mmc64_ws_skipelse1
|
|
|
|
lda #$ff ;send 2 sync bytes
|
|
sta $df10
|
|
sta $df10
|
|
lib_mmc64_ws_l3
|
|
sta $df10 ;wait until card has left busy state
|
|
ldx $df10
|
|
cpx #$ff
|
|
bne lib_mmc64_ws_l3
|
|
|
|
ENDASM
|
|
|
|
LET lib_mmc64_ws_status = 0
|
|
|
|
FEND
|
|
|
|
|
|
ASM
|
|
lib_mmc64_ws_cmd24
|
|
!8 $ff,$ff,$ff
|
|
lib_mmc64_ws_bytenr
|
|
!32 0 ; byte offset on card to write
|
|
!8 $58,$ff ;CMD24
|
|
ENDASM
|
|
|
|
#IFEND
|
|
|
|
LABEL lib_mmc64_skip
|
|
|
|
#IFEND
|