diff --git a/BuildCommon.cmd b/BuildCommon.cmd index 54811f78..9d537ff5 100644 --- a/BuildCommon.cmd +++ b/BuildCommon.cmd @@ -1,4 +1,5 @@ @echo off setlocal -pushd Source && call BuildCommon && popd \ No newline at end of file +pushd Source && call BuildCommon && popd +pushd Hardware && call Build && popd \ No newline at end of file diff --git a/Clean.cmd b/Clean.cmd index 6c86e1aa..561798bb 100644 --- a/Clean.cmd +++ b/Clean.cmd @@ -4,6 +4,7 @@ setlocal pushd Source && call Clean && popd pushd Images && call Clean && popd +pushd Hardware && call Clean && popd if exist *.img del *.img /Q if exist *.log del *.log /Q diff --git a/Hardware/Build.cmd b/Hardware/Build.cmd new file mode 100644 index 00000000..b810657c --- /dev/null +++ b/Hardware/Build.cmd @@ -0,0 +1,4 @@ +@echo off +setlocal + +pushd Prop && call Build && popd \ No newline at end of file diff --git a/Hardware/Clean.cmd b/Hardware/Clean.cmd new file mode 100644 index 00000000..d112a6bd --- /dev/null +++ b/Hardware/Clean.cmd @@ -0,0 +1,5 @@ +@echo off + +setlocal + +pushd Prop && call Clean && popd \ No newline at end of file diff --git a/Hardware/ParPortProp/ParPortProp.eeprom b/Hardware/ParPortProp/ParPortProp.eeprom deleted file mode 100644 index 2d1b8ea4..00000000 Binary files a/Hardware/ParPortProp/ParPortProp.eeprom and /dev/null differ diff --git a/Hardware/ParPortProp/Spin/safe_spi.spin b/Hardware/ParPortProp/Spin/safe_spi.spin deleted file mode 100644 index a63cb229..00000000 --- a/Hardware/ParPortProp/Spin/safe_spi.spin +++ /dev/null @@ -1,920 +0,0 @@ -{{ - SPI interface routines for SD & SDHC & MMC cards - - Jonathan "lonesock" Dummer - version 0.3.0 2009 July 19 - - Using multiblock SPI mode exclusively. - - This is the "SAFE" version...uses - * 1 instruction per bit writes - * 2 instructions per bit reads - - For the fsrw project: - fsrw.sf.net -}} - -CON - ' possible card types - type_MMC = 1 - type_SD = 2 - type_SDHC = 3 - - ' Error codes - ERR_CARD_NOT_RESET = -1 - ERR_3v3_NOT_SUPPORTED = -2 - ERR_OCR_FAILED = -3 - ERR_BLOCK_NOT_LONG_ALIGNED = -4 - '... - ' These errors are for the assembly engine...they are negated inside, and need to be <= 511 - ERR_ASM_NO_READ_TOKEN = 100 - ERR_ASM_BLOCK_NOT_WRITTEN = 101 - ' NOTE: errors -128 to -255 are reserved for reporting R1 response errors - '... - ERR_SPI_ENGINE_NOT_RUNNING = -999 - ERR_CARD_BUSY_TIMEOUT = -1000 - - ' SDHC/SD/MMC command set for SPI - CMD0 = $40+0 ' GO_IDLE_STATE - CMD1 = $40+1 ' SEND_OP_COND (MMC) - ACMD41 = $C0+41 ' SEND_OP_COND (SDC) - CMD8 = $40+8 ' SEND_IF_COND - CMD9 = $40+9 ' SEND_CSD - CMD10 = $40+10 ' SEND_CID - CMD12 = $40+12 ' STOP_TRANSMISSION - CMD13 = $40+13 ' SEND_STATUS - ACMD13 = $C0+13 ' SD_STATUS (SDC) - CMD16 = $40+16 ' SET_BLOCKLEN - CMD17 = $40+17 ' READ_SINGLE_BLOCK - CMD18 = $40+18 ' READ_MULTIPLE_BLOCK - CMD23 = $40+23 ' SET_BLOCK_COUNT (MMC) - ACMD23 = $C0+23 ' SET_WR_BLK_ERASE_COUNT (SDC) - CMD24 = $40+24 ' WRITE_BLOCK - CMD25 = $40+25 ' WRITE_MULTIPLE_BLOCK - CMD55 = $40+55 ' APP_CMD - CMD58 = $40+58 ' READ_OCR - CMD59 = $40+59 ' CRC_ON_OFF - - ' buffer size for my debug cmd log - 'LOG_SIZE = 256<<1 - -{ -VAR - long SPI_engine_cog - ' these are used for interfacing with the assembly engine | temporary initialization usage - long SPI_command ' "t", "r", "w", 0 =>done, <0 => error | pin mask - long SPI_block_index ' which 512-byte block to read/write | cnt at init - long SPI_buffer_address ' where to get/put the data in Hub RAM | unused -'} -DAT -'' I'm placing these variables in a DAT section to make this driver a singleton. -'' If for some reason you really need more than one driver (e.g. if you have more -'' than a single SD socket), move these back into VAR. -SPI_engine_cog long 0 -' these are used for interfacing with the assembly engine | temporary initialization usage -SPI_command long 0 ' "t", "r", "w", 0 =>done, <0 => error | unused -SPI_block_index long 0 ' which 512-byte block to read/write | cnt at init -SPI_buffer_address long 0 ' where to get/put the data in Hub RAM | unused - -{ -VAR - ' for debug ONLY - byte log_cmd_resp[LOG_SIZE+1] -PUB get_log_pointer - return @log_cmd_resp -'} - -PUB start( basepin ) -{{ - This is a compatibility wrapper, and requires that the pins be - both consecutive, and in the order DO CLK DI CS. -}} - return start_explicit( basepin, basepin+1, basepin+2, basepin+3 ) - -PUB readblock( block_index, buffer_address ) - if SPI_engine_cog == 0 - abort ERR_SPI_ENGINE_NOT_RUNNING - if (buffer_address & 3) - abort ERR_BLOCK_NOT_LONG_ALIGNED - SPI_block_index := block_index - SPI_buffer_address := buffer_address - SPI_command := "r" - repeat while SPI_command == "r" - if SPI_command < 0 - abort SPI_command - -PUB writeblock( block_index, buffer_address ) - if SPI_engine_cog == 0 - abort ERR_SPI_ENGINE_NOT_RUNNING - if (buffer_address & 3) - abort ERR_BLOCK_NOT_LONG_ALIGNED - SPI_block_index := block_index - SPI_buffer_address := buffer_address - SPI_command := "w" - repeat while SPI_command == "w" - if SPI_command < 0 - abort SPI_command - -PUB get_seconds - if SPI_engine_cog == 0 - abort ERR_SPI_ENGINE_NOT_RUNNING - SPI_command := "t" - repeat while SPI_command == "t" - ' secods are in SPI_block_index, remainder is in SPI_buffer_address - return SPI_block_index - -PUB get_milliseconds : ms - if SPI_engine_cog == 0 - abort ERR_SPI_ENGINE_NOT_RUNNING - SPI_command := "t" - repeat while SPI_command == "t" - ' secods are in SPI_block_index, remainder is in SPI_buffer_address - ms := SPI_block_index * 1000 - ms += SPI_buffer_address * 1000 / clkfreq - -PUB start_explicit( DO, CLK, DI, CS ) : card_type | tmp, i -{{ - Do all of the card initialization in SPIN, then hand off the pin - information to the assembly cog for hot SPI block R/W action! -}} - ' Start from scratch - stop - ' clear my log buffer - { - bytefill( @log_cmd_resp, 0, LOG_SIZE+1 ) - dbg_ptr := @log_cmd_resp - dbg_end := dbg_ptr + LOG_SIZE - '} - ' wait ~4 milliseconds - waitcnt( 500 + (clkfreq>>8) + cnt ) - ' (start with cog variables, _BEFORE_ loading the cog) - pinDO := DO - maskDO := |< DO - pinCLK := CLK - pinDI := DI - maskDI := |< DI - maskCS := |< CS - adrShift := 9 ' block = 512 * index, and 512 = 1<<9 - ' pass the output pin mask via the command register - maskAll := maskCS | (| 74 clocks - outa |= maskAll - repeat 4096 - outa[CLK]~~ - outa[CLK]~ - ' time-hack - SPI_block_index := cnt - ' reset the card - tmp~ - repeat i from 0 to 9 - if tmp <> 1 - tmp := send_cmd_slow( CMD0, 0, $95 ) - if (tmp & 4) - ' the card said CMD0 ("go idle") was invalid, so we're possibly stuck in read or write mode - if i & 1 - ' exit multiblock read mode - repeat 4 - read_32_slow ' these extra clocks are required for some MMC cards - send_slow( $FD, 8 ) ' stop token - read_32_slow - repeat while read_slow <> $FF - else - ' exit multiblock read mode - send_cmd_slow( CMD12, 0, $61 ) - if tmp <> 1 - ' the reset command failed! - crash( ERR_CARD_NOT_RESET ) - ' Is this a SD type 2 card? - if send_cmd_slow( CMD8, $1AA, $87 ) == 1 - ' Type2 SD, check to see if it's a SDHC card - tmp := read_32_slow - ' check the supported voltage - if (tmp & $1FF) <> $1AA - crash( ERR_3v3_NOT_SUPPORTED ) - ' try to initialize the type 2 card with the High Capacity bit - repeat while send_cmd_slow( ACMD41, |<30, $77 ) - ' the card is initialized, let's read back the High Capacity bit - if send_cmd_slow( CMD58, 0, $FD ) <> 0 - crash( ERR_OCR_FAILED ) - ' get back the data - tmp := read_32_slow - ' check the bit - if tmp & |<30 - card_type := type_SDHC - adrShift := 0 - else - card_type := type_SD - else - ' Either a type 1 SD card, or it's MMC, try SD 1st - if send_cmd_slow( ACMD41, 0, $E5 ) < 2 - ' this is a type 1 SD card (1 means busy, 0 means done initializing) - card_type := type_SD - repeat while send_cmd_slow( ACMD41, 0, $E5 ) - else - ' mark that it's MMC, and try to initialize - card_type := type_MMC - repeat while send_cmd_slow( CMD1, 0, $F9 ) - ' some SD or MMC cards may have the wrong block size, set it here - send_cmd_slow( CMD16, 512, $15 ) - ' card is mounted, make sure the CRC is turned off - send_cmd_slow( CMD59, 0, $91 ) - ' check the status - 'send_cmd_slow( CMD13, 0, $0D ) - ' done with the SPI bus for now - outa |= maskCS - ' set my counter modes for super fast SPI operation - ' writing: NCO single-ended mode, output on DI - writeMode := (%00100 << 26) | (DI << 0) - ' reading - 'readMode := (%11000 << 26) | (DO << 0) | (CLK << 9) - ' clock - 'clockLineMode := (%00110 << 26) | (CLK << 0) ' DUTY, 25% duty cycle - ' clock - clockLineMode := (%00100 << 26) | (CLK << 0) ' NCO, 50% duty cycle - ' how many bytes (8 clocks, >>3) fit into 1/2 of a second (>>1), 4 clocks per instruction (>>2)? - N_in8_500ms := clkfreq >> constant(1+2+3) - ' how long should we wait before auto-exiting any multiblock mode? - idle_limit := 125 ' ms, NEVER make this > 1000 - idle_limit := clkfreq / (1000 / idle_limit) ' convert to counts - ' Hand off control to the assembly engine's cog - bufAdr := @SPI_buffer_address - sdAdr := @SPI_block_index - SPI_command := 0 ' just make sure it's not 1 - ' start my driver cog and wait till I hear back that it's done - SPI_engine_cog := cognew( @SPI_engine_entry, @SPI_command ) + 1 - if( SPI_engine_cog == 0 ) - crash( ERR_SPI_ENGINE_NOT_RUNNING ) - repeat while SPI_command <> -1 - ' and we no longer need to control any pins from here - dira &= !maskAll - ' the return variable is card_type - -PUB release -{{ - I do not want to abort if the cog is not - running, as this is called from stop, which - is called from start/ [8^) -}} - if SPI_engine_cog - SPI_command := "z" - repeat while SPI_command == "z" - -PUB stop -{{ - kill the assembly driver cog. -}} - release - if SPI_engine_cog - cogstop( SPI_engine_cog~ - 1 ) - -PRI crash( abort_code ) -{{ - In case of Bad Things(TM) happening, - exit as gracefully as possible. -}} - ' and we no longer need to control any pins from here - dira &= !maskAll - ' and report our error - abort abort_code - -PRI send_cmd_slow( cmd, val, crc ) : reply | time_stamp -{{ - Send down a command and return the reply. - Note: slow is an understatement! - Note: this uses the assembly DAT variables for pin IDs, - which means that if you run this multiple times (say for - multiple SD cards), these values will change for each one. - But this is OK as all of these functions will be called - during the initialization only, before the PASM engine is - running. -}} - ' if this is an application specific command, handle it - if (cmd & $80) - ' ACMD is the command sequense of CMD55-CMD - cmd &= $7F - reply := send_cmd_slow( CMD55, 0, $65 ) - if (reply > 1) - return reply - ' the CS line needs to go low during this operation - outa |= maskCS - outa &= !maskCS - ' give the card a few cocks to finish whatever it was doing - read_32_slow - ' send the command byte - send_slow( cmd, 8 ) - ' send the value long - send_slow( val, 32 ) - ' send the CRC byte - send_slow( crc, 8 ) - ' is this a CMD12?, if so, stuff byte - if cmd == CMD12 - read_slow - ' read back the response (spec declares 1-8 reads max for SD, MMC is 0-8) - time_stamp := 9 - repeat - reply := read_slow - while( reply & $80 ) and ( time_stamp-- ) - ' done, and 'reply' is already pre-loaded - { - if dbg_ptr < (dbg_end-1) - byte[dbg_ptr++] := cmd - byte[dbg_ptr++] := reply - if (cmd&63) == 13 - ' get the second byte - byte[dbg_ptr++] := cmd - byte[dbg_ptr++] := read_slow - '} - -PRI send_slow( value, bits_to_send ) - value ><= bits_to_send - repeat bits_to_send - outa[pinCLK]~ - outa[pinDI] := value - value >>= 1 - outa[pinCLK]~~ - -PRI read_32_slow : r - repeat 4 - r <<= 8 - r |= read_slow - -PRI read_slow : r -{{ - Read back 8 bits from the card -}} - ' we need the DI line high so a read can occur - outa[pinDI]~~ - ' get 8 bits (remember, r is initialized to 0 by SPIN) - repeat 8 - outa[pinCLK]~ - outa[pinCLK]~~ - r += r + ina[pinDO] - ' error check - if( (cnt - SPI_block_index) > (clkfreq << 2) ) - crash( ERR_CARD_BUSY_TIMEOUT ) - -DAT -{{ - This is the assembly engine for doing fast block - reads and writes. This is *ALL* it does! -}} -ORG 0 -SPI_engine_entry - ' Counter A drives data out - mov ctra,writeMode - ' Counter B will always drive my clock line - mov ctrb,clockLineMode - ' set our output pins to match the pin mask - mov dira,maskAll - ' handshake that we now control the pins - neg user_request,#1 - wrlong user_request,par - ' start my seconds' counter here - mov last_time,cnt - -waiting_for_command - ' update my seconds counter, but also track the idle - ' time so we can to release the card after timeout. - call #handle_time - ' read the command, and make sure it's from the user (> 0) - rdlong user_request,par - cmps user_request,#0 wz,wc -if_be jmp #waiting_for_command - ' handle our card based commands - cmp user_request,#"r" wz -if_z jmp #read_ahead - cmp user_request,#"w" wz -if_z jmp #write_behind - cmp user_request,#"z" wz -if_z jmp #release_card - ' time requests are handled differently - cmp user_request,#"t" wz ' time -if_z wrlong seconds,sdAdr ' seconds goes into the SD index register -if_z wrlong dtime,bufAdr ' the remainder goes into the buffer address register - ' in all other cases, clear the user's request - mov user_request,#0 - wrlong user_request,par - jmp #waiting_for_command - - -release_card - mov user_cmd,#"z" ' request a release - neg lastIndexPlus,#1 ' reset the last block index - neg user_idx,#1 ' and make this match it - call #handle_command - mov user_request,user_cmd - wrlong user_request,par - jmp #waiting_for_command - -read_ahead - rdlong user_idx,sdAdr - ' if the correct block is not already loaded, load it - mov tmp1,user_idx - add tmp1,#1 - cmp tmp1,lastIndexPlus wz -if_z cmp lastCommand,#"r" wz -if_z jmp #:get_on_with_it - mov user_cmd,#"r" - call #handle_command -:get_on_with_it - ' copy the data up into Hub RAM - movi transfer_long,#%000010_000 'set to wrlong - call #hub_cog_transfer - ' signify that the data is ready, Spin can continue - mov user_request,user_cmd - wrlong user_request,par - ' request the next block - mov user_cmd,#"r" - add user_idx,#1 - call #handle_command - ' done - jmp #waiting_for_command - -write_behind - rdlong user_idx,sdAdr - ' copy data in from Hub RAM - movi transfer_long,#%000010_001 'set to rdlong - call #hub_cog_transfer - ' signify that we have the data, Spin can continue - mov user_request,user_cmd - wrlong user_request,par - ' write out the block - mov user_cmd,#"w" - call #handle_command - ' done - jmp #waiting_for_command - -{{ - Set user_cmd and user_idx before calling this -}} -handle_command - ' Can we stay in the old mode? (address = old_address+1) && (old mode == new_mode) - cmp lastIndexPlus,user_idx wz -if_z cmp user_cmd,lastCommand wz -if_z jmp #:execute_block_command - ' we fell through, must exit the old mode! (except if the old mode was "release") - cmp lastCommand,#"w" wz -if_z call #stop_mb_write - cmp lastCommand,#"r" wz -if_z call #stop_mb_read - ' and start up the new mode! - cmp user_cmd,#"w" wz -if_z call #start_mb_write - cmp user_cmd,#"r" wz -if_z call #start_mb_read - cmp user_cmd,#"z" wz -if_z call #release_DO -:execute_block_command - ' track the (new) last index and command - mov lastIndexPlus,user_idx - add lastIndexPlus,#1 - mov lastCommand,user_cmd - ' do the block read or write or terminate! - cmp user_cmd,#"w" wz -if_z call #write_single_block - cmp user_cmd,#"r" wz -if_z call #read_single_block - cmp user_cmd,#"z" wz -if_z mov user_cmd,#0 - ' done -handle_command_ret - ret - -{=== these PASM functions get me in and out of multiblock mode ===} -release_DO - ' we're already out of multiblock mode, so - ' deselect the card and send out some clocks - or outa,maskCS - call #in8 - call #in8 - ' if you are using pull-up resistors, and need all - ' lines tristated, then uncomment the following line. - ' for Cluso99 - 'mov dira,#0 -release_DO_ret - ret - -start_mb_read - movi block_cmd,#CMD18<<1 - call #send_SPI_command_fast -start_mb_read_ret - ret - -stop_mb_read - movi block_cmd,#CMD12<<1 - call #send_SPI_command_fast - call #busy_fast -stop_mb_read_ret - ret - -start_mb_write - movi block_cmd,#CMD25<<1 - call #send_SPI_command_fast -start_mb_write_ret - ret - -stop_mb_write - call #busy_fast - ' only some cards need these extra clocks - mov tmp1,#16 -:loopity - call #in8 - djnz tmp1,#:loopity - ' done with hack - movi phsa,#$FD<<1 - call #out8 - call #in8 ' stuff byte - call #busy_fast -stop_mb_write_ret - ret - -send_SPI_command_fast - ' make sure we have control of the output lines - mov dira,maskAll - ' make sure the CS line transitions low - or outa,maskCS - andn outa,maskCS - ' 8 clocks - call #in8 - ' send the data - mov phsa,block_cmd ' do which ever block command this is (already in the top 8 bits) - call #out8 ' write the byte - mov phsa,user_idx ' read in the desired block index - shl phsa,adrShift ' this will multiply by 512 (bytes/sector) for MMC and SD - call #out8 ' move out the 1st MSB ' - rol phsa,#1 - call #out8 ' move out the 1st MSB ' - rol phsa,#1 - call #out8 ' move out the 1st MSB ' - rol phsa,#1 - call #out8 ' move out the 1st MSB ' - ' bogus CRC value - call #in8 ' in8 looks like out8 with $FF - ' CMD12 requires a stuff byte - shr block_cmd,#24 - cmp block_cmd,#CMD12 wz -if_z call #in8 ' 8 clocks - ' get the response - mov tmp1,#9 -:cmd_response - call #in8 - test readback,#$80 wc,wz -if_c djnz tmp1,#:cmd_response -if_nz neg user_cmd,readback - ' done -send_SPI_command_fast_ret - ret - - -busy_fast - mov tmp1,N_in8_500ms -:still_busy - call #in8 - cmp readback,#$FF wz -if_nz djnz tmp1,#:still_busy -busy_fast_ret - ret - - -out8 - andn outa,maskDI - 'movi phsb,#%11_0000000 - mov phsb,#0 - movi frqb,#%01_0000000 - rol phsa,#1 - rol phsa,#1 - rol phsa,#1 - rol phsa,#1 - rol phsa,#1 - rol phsa,#1 - rol phsa,#1 - mov frqb,#0 - ' don't shift out the final bit...already sent, but be aware - ' of this when sending consecutive bytes (send_cmd, for e.g.) -out8_ret - ret - -{ -in8 - or outa,maskDI - mov ctra,readMode - ' Start my clock - mov frqa,#1<<7 - mov phsa,#0 - movi phsb,#%11_0000000 - movi frqb,#%01_0000000 - ' keep reading in my value, one bit at a time! (Kuneko - "Wh) - shr frqa,#1 - shr frqa,#1 - shr frqa,#1 - shr frqa,#1 - shr frqa,#1 - shr frqa,#1 - shr frqa,#1 - mov frqb,#0 ' stop the clock - mov readback,phsa - mov frqa,#0 - mov ctra,writeMode -in8_ret - ret -} -in8 - neg phsa,#1' DI high - mov readback,#0 - ' set up my clock, and start it - movi phsb,#%011_000000 - movi frqb,#%001_000000 - ' keep reading in my value - test maskDO,ina wc - rcl readback,#1 - test maskDO,ina wc - rcl readback,#1 - test maskDO,ina wc - rcl readback,#1 - test maskDO,ina wc - rcl readback,#1 - test maskDO,ina wc - rcl readback,#1 - test maskDO,ina wc - rcl readback,#1 - test maskDO,ina wc - rcl readback,#1 - test maskDO,ina wc - mov frqb,#0 ' stop the clock - rcl readback,#1 - mov phsa,#0 'DI low -in8_ret - ret - - -' this is called more frequently than 1 Hz, and -' is only called when the user command is 0. -handle_time - mov tmp1,cnt ' get the current timestamp - add idle_time,tmp1 ' add the current time to my idle time counter - sub idle_time,last_time ' subtract the last time from my idle counter (hence delta) - add dtime,tmp1 ' add to my accumulator, - sub dtime,last_time ' and subtract the old (adding delta) - mov last_time,tmp1 ' update my "last timestamp" - rdlong tmp1,#0 ' what is the clock frequency? - cmpsub dtime,tmp1 wc ' if I have more than a second in my accumulator - addx seconds,#0 ' then add it to "seconds" - ' this part is to auto-release the card after a timeout - cmp idle_time,idle_limit wz,wc -if_b jmp #handle_time_ret ' don't clear if we haven't hit the limit - mov user_cmd,#"z" ' we can't overdo it, the command handler makes sure - neg lastIndexPlus,#1 ' reset the last block index - neg user_idx,#1 ' and make this match it - call #handle_command ' release the card, but don't mess with the user's request register -handle_time_ret - ret - -hub_cog_transfer -' setup for all 4 passes - mov ctrb,clockXferMode - mov frqb,#1 - rdlong buf_ptr,bufAdr - mov ops_left,#4 - movd transfer_long,#speed_buf -four_transfer_passes - ' sync to the Hub RAM access - rdlong tmp1,tmp1 - ' how many long to move on this pass? (512 bytes / 4)longs / 4 passes - mov tmp1,#(512 / 4 / 4) - ' get my starting address right (phsb is incremented 1 per clock, so 16 each Hub access) - mov phsb,buf_ptr - ' write the longs, stride 4...low 2 bits of phsb are ignored -transfer_long - rdlong 0-0,phsb - add transfer_long,incDest4 - djnz tmp1,#transfer_long - ' go back to where I started, but advanced 1 long - sub transfer_long,decDestNminus1 - ' offset my Hub pointer by one long per pass - add buf_ptr,#4 - ' do all 4 passes - djnz ops_left,#four_transfer_passes - ' restore the counter mode - mov frqb,#0 - mov phsb,#0 - mov ctrb,clockLineMode -hub_cog_transfer_ret - ret - - -read_single_block - ' where am I sending the data? - movd :store_read_long,#speed_buf - mov ops_left,#128 - ' wait until the card is ready - mov tmp1,N_in8_500ms -:get_resp - call #in8 - cmp readback,#$FE wz -if_nz djnz tmp1,#:get_resp -if_nz neg user_cmd,#ERR_ASM_NO_READ_TOKEN -if_nz jmp #read_single_block_ret - ' set DI high - neg phsa,#1 - ' read the data - mov ops_left,#128 -:read_loop - mov tmp1,#4 - movi phsb,#%011_000000 -:in_byte - ' Start my clock - movi frqb,#%001_000000 - ' keep reading in my value, BACKWARDS! (Brilliant idea by Tom Rokicki!) - test maskDO,ina wc - rcl readback,#8 - test maskDO,ina wc - muxc readback,#2 - test maskDO,ina wc - muxc readback,#4 - test maskDO,ina wc - muxc readback,#8 - test maskDO,ina wc - muxc readback,#16 - test maskDO,ina wc - muxc readback,#32 - test maskDO,ina wc - muxc readback,#64 - test maskDO,ina wc - mov frqb,#0 ' stop the clock - muxc readback,#128 - ' go back for more - djnz tmp1,#:in_byte - ' make it...NOT backwards [8^) - rev readback,#0 -:store_read_long - mov 0-0,readback ' due to some counter weirdness, we need this mov - add :store_read_long,const512 - djnz ops_left,#:read_loop - - ' set DI low - mov phsa,#0 - - ' now read 2 trailing bytes (CRC) - call #in8 ' out8 is 2x faster than in8 - call #in8 ' and I'm not using the CRC anyway - ' give an extra 8 clocks in case we pause for a long time - call #in8 ' in8 looks like out8($FF) - - ' all done successfully - mov idle_time,#0 - mov user_cmd,#0 -read_single_block_ret - ret - -write_single_block - ' where am I getting the data? (all 512 bytes / 128 longs of it?) - movs :write_loop,#speed_buf - ' read in 512 bytes (128 longs) from Hub RAM and write it to the card - mov ops_left,#128 - ' just hold your horses - call #busy_fast - ' $FC for multiblock, $FE for single block - movi phsa,#$FC<<1 - call #out8 - mov phsb,#0 ' make sure my clock accumulator is right - 'movi phsb,#%11_0000000 -:write_loop - ' read 4 bytes - mov phsa,speed_buf - add :write_loop,#1 - ' a long in LE order is DCBA - rol phsa,#24 ' move A7 into position, so I can do the swizzled version - movi frqb,#%010000000 ' start the clock (remember A7 is already in place) - rol phsa,#1 ' A7 is going out, at the end of this instr, A6 is in place - rol phsa,#1 ' A5 - rol phsa,#1 ' A4 - rol phsa,#1 ' A3 - rol phsa,#1 ' A2 - rol phsa,#1 ' A1 - rol phsa,#1 ' A0 - rol phsa,#17 ' B7 - rol phsa,#1 ' B6 - rol phsa,#1 ' B5 - rol phsa,#1 ' B4 - rol phsa,#1 ' B3 - rol phsa,#1 ' B2 - rol phsa,#1 ' B1 - rol phsa,#1 ' B0 - rol phsa,#17 ' C7 - rol phsa,#1 ' C6 - rol phsa,#1 ' C5 - rol phsa,#1 ' C4 - rol phsa,#1 ' C3 - rol phsa,#1 ' C2 - rol phsa,#1 ' C1 - rol phsa,#1 ' C0 - rol phsa,#17 ' D7 - rol phsa,#1 ' D6 - rol phsa,#1 ' D5 - rol phsa,#1 ' D4 - rol phsa,#1 ' D3 - rol phsa,#1 ' D2 - rol phsa,#1 ' D1 - rol phsa,#1 ' D0 will be in place _after_ this instruction - mov frqb,#0 ' shuts the clock off, _after_ this instruction - djnz ops_left,#:write_loop - ' write out my two (bogus, using $FF) CRC bytes - call #in8 - call #in8 - ' now read response (I need this response, so can't spoof using out8) - call #in8 - and readback,#$1F - cmp readback,#5 wz -if_z mov user_cmd,#0 ' great -if_nz neg user_cmd,#ERR_ASM_BLOCK_NOT_WRITTEN ' oops - ' send out another 8 clocks - call #in8 - ' all done - mov idle_time,#0 -write_single_block_ret - ret - - -{=== Assembly Interface Variables ===} -pinDO long 0 ' pin is controlled by a counter -pinCLK long 0 ' pin is controlled by a counter -pinDI long 0 ' pin is controlled by a counter -maskDO long 0 ' mask for reading the DO line from the card -maskDI long 0 ' mask for setting the pin high while reading -maskCS long 0 ' mask = (1<done, <0 => error | pin mask - long SPI_block_index ' which 512-byte block to read/write | cnt at init - long SPI_buffer_address ' where to get/put the data in Hub RAM | unused -'} + 'long SPI_engine_cog + '' these are used for interfacing with the assembly engine | temporary initialization usage + 'long SPI_command ' "t", "r", "w", 0 =>done, <0 => error | pin mask + 'long SPI_block_index ' which 512-byte block to read/write | cnt at init + 'long SPI_buffer_address ' where to get/put the data in Hub RAM | unused + + 'long SPI_capacity + 'byte SPI_csdbuf[16] + DAT '' I'm placing these variables in a DAT section to make this driver a singleton. '' If for some reason you really need more than one driver (e.g. if you have more @@ -76,6 +82,9 @@ SPI_command long 0 ' "t", "r", "w", 0 =>done, <0 => error SPI_block_index long 0 ' which 512-byte block to read/write | cnt at init SPI_buffer_address long 0 ' where to get/put the data in Hub RAM | unused +SPI_capacity long 0 +SPI_csdbuf byte 0 [16] + { VAR ' for debug ONLY @@ -115,6 +124,12 @@ PUB writeblock( block_index, buffer_address ) if SPI_command < 0 abort SPI_command +PUB getcapacity + Result := SPI_capacity + +PUB getcsd( buffer_address ) + bytemove(buffer_address, @SPI_csdbuf, 16) + PUB get_seconds if SPI_engine_cog == 0 abort ERR_SPI_ENGINE_NOT_RUNNING @@ -217,10 +232,48 @@ PUB start_explicit( DO, CLK, DI, CS ) : card_type | tmp, i repeat while send_cmd_slow( CMD1, 0, $F9 ) ' some SD or MMC cards may have the wrong block size, set it here send_cmd_slow( CMD16, 512, $15 ) + ' card is mounted, make sure the CRC is turned off - send_cmd_slow( CMD59, 0, $91 ) - ' check the status - 'send_cmd_slow( CMD13, 0, $0D ) + if send_cmd_slow( CMD59, 0, $91 ) <> 0 + crash( ERR_CRC_ONOFF_FAILED ) + + ' check card status + if send_cmd_slow ( CMD13, 0, $FF) <> 0 + crash( ERR_STATUS_FAILED ) + read_slow ' swallow second byte of status + + ' get card capacity + if send_cmd_slow ( CMD9, 0, $FF) <> 0 + crash( ERR_CSD_FAILED ) + i := 32 ' arbitrary timeout + repeat while (read_slow <> $FE) + if i == 0 + crash( ERR_CSD_FAILED ) + repeat i from 0 to 15 ' 16 bytes of CSD data + SPI_csdbuf[i] := read_slow + read_slow ' discard CRC - first byte + read_slow ' discard CRC - second byte + + case (card_type) + type_MMC, type_SD: + tmp := SPI_csdbuf[9] + tmp := (tmp << 8) | SPI_csdbuf[10] + i := ((tmp >> 7) & $07) ' c_size_mult + tmp := SPI_csdbuf[5] + i += tmp & $0F ' mask out read_bl_len and add to c_size_mult + tmp := SPI_csdbuf[6] & $03 + tmp := (tmp << 8) | SPI_csdbuf[7] + tmp := (tmp << 8) | SPI_csdbuf[8] + tmp := (tmp >> 6) ' c_size + SPI_capacity := ((tmp + 1) << (2 + i)) >> 9 + type_SDHC: + tmp := SPI_csdbuf[7] & $3F + tmp := (tmp << 8) | SPI_csdbuf[8] + tmp := (tmp << 8) | SPI_csdbuf[9] + SPI_capacity := (tmp + 1) * 1024 + other: + SPI_capacity := 0 + ' done with the SPI bus for now outa |= maskCS ' set my counter modes for super fast SPI operation diff --git a/Hardware/PropIO/PropIO.eeprom b/Hardware/PropIO/PropIO.eeprom deleted file mode 100644 index af54217b..00000000 Binary files a/Hardware/PropIO/PropIO.eeprom and /dev/null differ diff --git a/Hardware/PropIO/Spin/Keyboard.spin b/Hardware/PropIO/Spin/Keyboard.spin deleted file mode 100644 index 29025a99..00000000 Binary files a/Hardware/PropIO/Spin/Keyboard.spin and /dev/null differ diff --git a/Hardware/PropIO/Spin/Parallax Serial Terminal.spin b/Hardware/PropIO/Spin/Parallax Serial Terminal.spin deleted file mode 100644 index a525a4be..00000000 Binary files a/Hardware/PropIO/Spin/Parallax Serial Terminal.spin and /dev/null differ diff --git a/Hardware/PropIO/Spin/VGA_1024.spin b/Hardware/PropIO/Spin/VGA_1024.spin deleted file mode 100644 index 82d12261..00000000 --- a/Hardware/PropIO/Spin/VGA_1024.spin +++ /dev/null @@ -1,704 +0,0 @@ -'' VGA_1024.spin -'' -'' MODIFIED BY VINCE BRIEL FOR POCKETERM FEATURES -'' MODIIFED BY JEFF LEDGER / AKA OLDBITCOLLECTOR -'' - -CON - cols = 80 '128 ' number of screen columns - lcols = cols / 4 ' number of long in columns - rows = 40 '64 ' number of screen rows - chars = rows*cols ' number of screen characters - esc = $CB ' keyboard esc char - rowsnow = 36 ' adjusted for split screen effect - maxChars = rowsnow*cols ' adjusted value for split screen effect - lastChar = maxChars / 4 ' last screen position in longs adjusted for split - lastLine = (rowsnow - 1) * cols ' character position of last row - cols1 = 81 ' adjusted value for 80th character - TURQUOISE = $29 - -OBJ - vga : "vga_Hires_Text" - -VAR - byte screen[chars] ' screen character buffer - byte tmpl[cols] ' temporary line buffer - word colors[rows] ' color specs for each screen row (see ColorPtr description above) - byte cursor[6] ' cursor info array (see CursorPtr description above) - long sync, loc, xloc, yloc ' sync used by VGA routine, others are local screen pointers - long kbdreq ' global val of kbdflag - long BR[8] - long Brate - byte inverse - byte invs - byte state ' Current state of state machine - word pos ' Current Position on the screen - word oldpos ' Previous location of cursor before update - word regionTop, regionBot ' Scroll region top/bottom - long arg0 ' First argument of escape sequence - long arg1 ' Second argument of escape sequence - byte lastc ' Last displayed char - word statpos - long vgabasepin - -PUB start(BasePin) | i, char - vgabasepin := BasePin - -''init screen colors to gold on blue - repeat i from 0 to rows - 1 - colors[i] := $08F0 '$2804 (if you want cyan on blue) - -''init cursor attributes - cursor[2] := %110 ' init cursor to underscore with slow blink - BR[0]:=300 - BR[1]:=1200 - BR[2]:=2400 - BR[3]:=4800 - BR[4]:=9600 - BR[5]:=19200 - BR[6]:=38400 - BR[7]:=57600 - BR[8]:=115200 - xloc := cursor[0] := 0 - yloc := cursor[1] := 0 - loc := xloc + yloc*cols - - pos := 0 - regionTop := 0 - regionBot := 35 * cols - state := 0 - statpos := 37 * cols - -PUB vidon - if (!vga.start(vgabasepin, @screen, @colors, @cursor, @sync)) - return false - - waitcnt(clkfreq * 1 + cnt) 'wait 1 second for cogs to start - - -PUB vidoff - vga.stop - - -PUB inv(c) - inverse:=c - -PUB color(colorVal) | i - repeat i from 0 to rows - 1 - colors[i] := $0000 | colorVal - -PUB cursorset(c) | i - i:=%000 - if c == 1 - i:= %001 - if c == 2 - i:= %010 - if c == 3 - i:= %011 - if c == 4 - i:= %101 - if c == 5 - i:= %110 - if c == 6 - i:= %111 - if c == 7 - i:= %000 - cursor[2] := i - -PUB bin(value, digits) - -'' Print a binary number, specify number of digits - - repeat while digits > 32 - outc("0") - digits-- - - value <<= 32 - digits - - repeat digits - outc((value <-= 1) & 1 + "0") - - -PUB clrbtm(ColorVal) | i - repeat i from 36 to rows - 1 'was 35 - colors[i] := $0000 + ColorVal - -PUB cls1(c,screencolor,pcport,ascii,CR) | i,x,y - - longfill(@screen[0], $20202020, chars / 4) - - clrbtm(TURQUOISE) - - inverse := 1 - - statprint(36,0, string(" N8VEM PropIO | RomWBW v0.94")) - inverse := 0 - statprint(37,0, string(" ")) - statprint(38,0, string(" ")) - statprint(39,0, string(" ")) - - -{{ - x :=xloc - y := yloc - invs := inverse - ''clrbtm(TURQUOISE) - longfill(@screen, $20202020, chars/4) - xloc := 0 - yloc :=0 - loc := xloc + yloc*cols - repeat 80 - outc(32) - xloc := 0 - yloc :=36 - loc := xloc + yloc*cols - inverse := 1 - str(string(" propIO V 0.91 ")) - inverse := 0 - str(string("Baud Rate: ")) - i:= BR[6] - dec(i) - str(string(" ")) - xloc := 18 - loc := xloc + yloc*cols - str(string("Color ")) - str(string("PC Port: ")) - if pcport == 1 - str(string("OFF ")) - if pcport == 0 - str(string("ON ")) - str(string(" Force 7 bit: ")) - if ascii == 0 - str(string("NO ")) - if ascii == 1 - str(string("YES ")) - str(string(" Cursor CR W/LF: ")) - if CR == 1 - str(string("YES")) - if CR == 0 - str(string("NO ")) - outc(13) - outc(10) - - inverse:=1 - xloc := 6 - loc := xloc + yloc*cols - str(string("F1")) - xloc := 19 - loc := xloc + yloc*cols - str(string("F2")) - xloc := 30 - loc := xloc + yloc*cols - str(string("F3")) - xloc := 46 - loc := xloc + yloc*cols - str(string("F4")) - xloc := 58 - loc := xloc + yloc*cols - str(string("F5")) - xloc := 70 - loc := xloc + yloc*cols - str(string("F6")) - inverse := invs - xloc := cursor[0] := x 'right & left was 0 - yloc := cursor[1] := y 'from top was 1 - loc := xloc + yloc*cols -}} - -PUB clsupdate(c,screencolor,PCPORT,ascii,CR) | i,x,y,locold - - invs := inverse - locold := loc - x := xloc - y := yloc - ''(TURQUOISE) - xloc := 0 - yloc :=36 - loc := xloc + yloc*cols - inverse := 1 - str(string(" propIO V 0.81 ")) - inverse := 0 - xloc := 0 - yloc :=37 - loc := xloc + yloc*cols - str(string("Baud Rate: ")) - i:= BR[6] - dec(i) - str(string(" ")) - xloc := 18 - loc := xloc + yloc*cols - - str(string("Color ")) - str(string("PC Port: ")) - if pcport == 1 - str(string("OFF ")) - if pcport == 0 - str(string("ON ")) - str(string(" Force 7 bit: ")) - if ascii == 0 - str(string("NO ")) - if ascii == 1 - str(string("YES ")) - str(string(" Cursor CR W/LF: ")) - if CR == 1 - str(string("YES")) - if CR == 0 - str(string("NO ")) - xloc := 0 - yloc :=38 - loc := xloc + yloc*cols - inverse:=1 - xloc := 6 - loc := xloc + yloc*cols - str(string("F1")) - xloc := 19 - loc := xloc + yloc*cols - str(string("F2")) - xloc := 30 - loc := xloc + yloc*cols - str(string("F3")) - xloc := 46 - loc := xloc + yloc*cols - str(string("F4")) - xloc := 58 - loc := xloc + yloc*cols - str(string("F5")) - xloc := 70 - loc := xloc + yloc*cols - str(string("F6")) - inverse := invs - xloc := cursor[0] := x - yloc := cursor[1] := y -' loc := xloc + yloc*cols - loc := locold - -PUB dec(value) | i - -'' Print a decimal number - - if value < 0 - -value - outc("-") - - i := 1_000_000_000 - - repeat 10 - if value => i - outc(value/i + "0") - value //= i - result~~ - elseif result or i == 1 - outc("0") - i /= 10 - -PUB hex(value, digits) - -'' Print a hexadecimal number, specify number of digits - - repeat while digits > 8 - outc("0") - digits-- - - value <<= (8 - digits) << 2 - - repeat digits - outc(lookupz((value <-= 4) & $f : "0".."9", "A".."F")) - - -PUB str(string_ptr) - -'' Print a zero terminated string - - repeat strsize(string_ptr) - process_char(byte[string_ptr++]) - -PUB statprint(r, c, str1) | x, ptr - - ptr := r * cols + c - repeat x from 0 to STRSIZE(str1) - 1 - putc(ptr++, BYTE[str1 + x]) - -PUB statnum(r, c, num1) | i, ptr - - ptr := r * cols + c - - if num1 < 0 - -num1 - putc(ptr++,"-") - - i := 1_000_000_000 - - repeat 10 - if num1 => i - putc(ptr++, (num1/i +"0")) - num1 //= i - result~~ - elseif result or i == 1 - putc(ptr++, "0") - i /= 10 - -PUB putc(position, c) - if inverse - c |= $80 - screen[position] := c - -PUB cls - longfill (@screen, $20202020, lastChar) - -PUB fullcls - longfill(@screen, $20202020, 800) - -PUB setInverse(val) - inverse := val - -PUB setInv(c) - if c == 7 - setInverse(1) - else - setInverse(0) - -PUB clEOL(position) | count - count := cols - (position // cols) - bytefill(@screen + position, $20, count) - -PUB clBOL(position) | count - count := position // cols - bytefill(@screen + position - count, $20, count) - -PUB delLine(position) | src, count - position -= position // cols - - src := position + cols - - count := (maxChars - src) / 4 - - if count > 0 - longmove(@screen + position, @screen + src, count) - - longfill(@screen + lastLine, $20202020, lcols) - -PUB clEOS(position) - cleol(position) - position += cols - (position // cols) - repeat while position < maxChars - longfill(@screen + position, $20202020, lcols) - pos += cols - -PUB setCursorPos(position) - cursor[0] := position // cols - cursor[1] := position / cols - -PUB insLine(position) | base, nxt - base := position - (position // cols) - position := lastLine - repeat while position > base - nxt := position - cols - longmove(@screen + position, @screen + nxt, lcols) - position := nxt - clEOL(base) - -PUB insChar(position) | count - count := (cols - (position // cols)) - 1 - bytemove(@tmpl, @screen + position, count) - screen[position] := " " - bytemove(@screen + position + 1, @tmpl, count) - -PUB delChar(position) | count - count := (cols - (position // cols)) - 1 - bytemove(@screen + position, @screen + position + 1, count) - screen[position + count] := " " - -PRI inRegion : answer - answer := (pos => regionTop) AND (pos < regionBot) - -PRI scrollUp - delLine(regionTop) - if regionBot < maxChars - insLine(regionBot) - -PRI scrollDown - if regionBot < maxChars - delLine(regionBot) - insLine(regionTop) - -PRI ansi(c) | x, defVal - - state := 0 - - if (c <> "r") AND (c <> "J") AND (c <> "m") AND (c <> "K") - if arg0 == -1 - arg0 := 1 - if arg1 == -1 - arg1 := 1 - - case c - "@": - repeat while arg0-- > 0 - insChar(pos) - - "b": - repeat while arg0-- > 0 - outc(lastc) - - "d": - if (arg0 < 1) OR (arg0 > rows) - arg0 := rows - pos := ((arg0 - 1) * cols) + (pos // cols) - - "m": - setInv(arg0) - if arg1 <> -1 - setInv(arg1) - - "r": - if arg0 < 1 - arg0 := 1 - elseif arg0 > cols - arg0 := cols - if arg1 < 1 - arg1 := 1 - elseif arg1 > cols - arg1 := cols - if arg1 < arg0 - arg1 := arg0 - - regionTop := (arg0 - 1) * cols - regionBot := arg1 * cols - pos := 0 - - "A": - repeat while arg0-- > 0 - pos -= cols - if pos < 0 - pos += cols - return - - "B": - repeat while arg0-- > 0 - pos += cols - if pos => maxChars - pos -= cols - return - - "C": - repeat while arg0-- > 0 - pos += 1 - if pos => maxChars - pos -= 1 - return - - "D": - repeat while arg0-- > 0 - pos -= 1 - if pos < 0 - pos := 0 - return - - "G": - if (arg0 < 1) OR (arg0 > cols) - arg0 := cols - pos := (pos - (pos // cols)) + (arg0 - 1) - - "H", "f": - if arg0 =< 0 - arg0 := 1 - if arg1 =< 0 - arg1 := 1 - pos := (cols * (arg0 - 1)) + (arg1 - 1) - if pos < 0 - pos := 0 - if pos => maxChars - pos := maxChars - 1 - - "J": - if arg0 == 1 - clBOL(pos) - x := pos - cols - x -= x // cols - repeat while x => 0 - clEOL(x) - x -= cols - return - - if arg0 == 2 - pos := 0 - - clEOL(pos) - x := pos + cols - x -= (x // cols) - repeat while x < maxChars - clEOL(x) - x += cols - - "K": - if arg0 == -1 - clEOL(pos) - elseif arg0 == 1 - clBOL(pos) - else - clEOL(pos - (pos // cols)) - - "L": - if inRegion - repeat while arg0-- > 0 - if regionBot < maxChars - delLine(regionBot) - insLine(pos) - - "M": - if inRegion - repeat while arg0-- > 0 - delLine(pos) - if regionBot < maxChars - insLine(regionBot) - - "P": - repeat while arg0-- - delChar(pos) - -PRI outc(c) - - putc(pos++, lastc := c) - if pos == regionBot - scrollUp - pos -= cols - elseif pos == maxChars - pos := lastLine - -PUB process_char(c) - - case state - - 0: - if c > 127 - c := $20 - - if c => $20 - outc(c) - setCursorPos(pos) - return - - if c == $1B - state := 1 - return - - if c == $0D - pos := pos - (pos // cols) - setCursorPos(pos) - return - - if c == $0A - if inRegion - pos += cols - if pos => regionBot - scrollUp - pos -= cols - else - pos += cols - if pos => maxChars - pos -= cols - setCursorPos(pos) - return - - if c == 9 - pos += (8 - (pos // 8)) - - if pos => maxChars - pos := lastLine - delLine(0) - - setCursorPos(pos) - return - - if c == 8 - if pos > 0 - pos -= 1 - setCursorPos(pos) - return - - 1: - case c - "[": - arg0 := arg1 := -1 - state := 2 - return - - "P": - pos += cols - if pos => maxChars - pos -= cols - - "K": - if pos > 0 - pos -= 1 - - "H": - pos -= cols - if pos < 0 - pos += cols - - "D": - if inRegion - scrollUp - - "M": - if inRegion - scrollDown - - "G": - pos := 0 - - "(": - state := 5 - return - - state := 0 - return - - 2: - if (c => "0") AND (c =< "9") - if arg0 == -1 - arg0 := c - "0" - else - arg0 := (arg0 * 10) + (c - "0") - return - - if c == ";" - state := 3 - return - - ansi(c) - setCursorPos(pos) - return - - 3: - if (c => "0") AND (c =< "9") - if arg1 == -1 - arg1 := c - "0" - else - arg1 := (arg1 * 10) + (c - "0") - return - - if c == ";" - state := 4 - return - - ansi(c) - setCursorPos(pos) - return - - 4: - if (c => "0") AND (c =< "9") - return - - if c == ";" - return - ansi(c) - setCursorPos(pos) - return - - 5: - state := 0 - return - - return \ No newline at end of file diff --git a/Hardware/PropIO/Spin/VGA_HiRes_Text.spin b/Hardware/PropIO/Spin/VGA_HiRes_Text.spin deleted file mode 100644 index 5b892316..00000000 Binary files a/Hardware/PropIO/Spin/VGA_HiRes_Text.spin and /dev/null differ diff --git a/Hardware/PropIO/Spin/safe_spi.spin b/Hardware/PropIO/Spin/safe_spi.spin deleted file mode 100644 index a63cb229..00000000 --- a/Hardware/PropIO/Spin/safe_spi.spin +++ /dev/null @@ -1,920 +0,0 @@ -{{ - SPI interface routines for SD & SDHC & MMC cards - - Jonathan "lonesock" Dummer - version 0.3.0 2009 July 19 - - Using multiblock SPI mode exclusively. - - This is the "SAFE" version...uses - * 1 instruction per bit writes - * 2 instructions per bit reads - - For the fsrw project: - fsrw.sf.net -}} - -CON - ' possible card types - type_MMC = 1 - type_SD = 2 - type_SDHC = 3 - - ' Error codes - ERR_CARD_NOT_RESET = -1 - ERR_3v3_NOT_SUPPORTED = -2 - ERR_OCR_FAILED = -3 - ERR_BLOCK_NOT_LONG_ALIGNED = -4 - '... - ' These errors are for the assembly engine...they are negated inside, and need to be <= 511 - ERR_ASM_NO_READ_TOKEN = 100 - ERR_ASM_BLOCK_NOT_WRITTEN = 101 - ' NOTE: errors -128 to -255 are reserved for reporting R1 response errors - '... - ERR_SPI_ENGINE_NOT_RUNNING = -999 - ERR_CARD_BUSY_TIMEOUT = -1000 - - ' SDHC/SD/MMC command set for SPI - CMD0 = $40+0 ' GO_IDLE_STATE - CMD1 = $40+1 ' SEND_OP_COND (MMC) - ACMD41 = $C0+41 ' SEND_OP_COND (SDC) - CMD8 = $40+8 ' SEND_IF_COND - CMD9 = $40+9 ' SEND_CSD - CMD10 = $40+10 ' SEND_CID - CMD12 = $40+12 ' STOP_TRANSMISSION - CMD13 = $40+13 ' SEND_STATUS - ACMD13 = $C0+13 ' SD_STATUS (SDC) - CMD16 = $40+16 ' SET_BLOCKLEN - CMD17 = $40+17 ' READ_SINGLE_BLOCK - CMD18 = $40+18 ' READ_MULTIPLE_BLOCK - CMD23 = $40+23 ' SET_BLOCK_COUNT (MMC) - ACMD23 = $C0+23 ' SET_WR_BLK_ERASE_COUNT (SDC) - CMD24 = $40+24 ' WRITE_BLOCK - CMD25 = $40+25 ' WRITE_MULTIPLE_BLOCK - CMD55 = $40+55 ' APP_CMD - CMD58 = $40+58 ' READ_OCR - CMD59 = $40+59 ' CRC_ON_OFF - - ' buffer size for my debug cmd log - 'LOG_SIZE = 256<<1 - -{ -VAR - long SPI_engine_cog - ' these are used for interfacing with the assembly engine | temporary initialization usage - long SPI_command ' "t", "r", "w", 0 =>done, <0 => error | pin mask - long SPI_block_index ' which 512-byte block to read/write | cnt at init - long SPI_buffer_address ' where to get/put the data in Hub RAM | unused -'} -DAT -'' I'm placing these variables in a DAT section to make this driver a singleton. -'' If for some reason you really need more than one driver (e.g. if you have more -'' than a single SD socket), move these back into VAR. -SPI_engine_cog long 0 -' these are used for interfacing with the assembly engine | temporary initialization usage -SPI_command long 0 ' "t", "r", "w", 0 =>done, <0 => error | unused -SPI_block_index long 0 ' which 512-byte block to read/write | cnt at init -SPI_buffer_address long 0 ' where to get/put the data in Hub RAM | unused - -{ -VAR - ' for debug ONLY - byte log_cmd_resp[LOG_SIZE+1] -PUB get_log_pointer - return @log_cmd_resp -'} - -PUB start( basepin ) -{{ - This is a compatibility wrapper, and requires that the pins be - both consecutive, and in the order DO CLK DI CS. -}} - return start_explicit( basepin, basepin+1, basepin+2, basepin+3 ) - -PUB readblock( block_index, buffer_address ) - if SPI_engine_cog == 0 - abort ERR_SPI_ENGINE_NOT_RUNNING - if (buffer_address & 3) - abort ERR_BLOCK_NOT_LONG_ALIGNED - SPI_block_index := block_index - SPI_buffer_address := buffer_address - SPI_command := "r" - repeat while SPI_command == "r" - if SPI_command < 0 - abort SPI_command - -PUB writeblock( block_index, buffer_address ) - if SPI_engine_cog == 0 - abort ERR_SPI_ENGINE_NOT_RUNNING - if (buffer_address & 3) - abort ERR_BLOCK_NOT_LONG_ALIGNED - SPI_block_index := block_index - SPI_buffer_address := buffer_address - SPI_command := "w" - repeat while SPI_command == "w" - if SPI_command < 0 - abort SPI_command - -PUB get_seconds - if SPI_engine_cog == 0 - abort ERR_SPI_ENGINE_NOT_RUNNING - SPI_command := "t" - repeat while SPI_command == "t" - ' secods are in SPI_block_index, remainder is in SPI_buffer_address - return SPI_block_index - -PUB get_milliseconds : ms - if SPI_engine_cog == 0 - abort ERR_SPI_ENGINE_NOT_RUNNING - SPI_command := "t" - repeat while SPI_command == "t" - ' secods are in SPI_block_index, remainder is in SPI_buffer_address - ms := SPI_block_index * 1000 - ms += SPI_buffer_address * 1000 / clkfreq - -PUB start_explicit( DO, CLK, DI, CS ) : card_type | tmp, i -{{ - Do all of the card initialization in SPIN, then hand off the pin - information to the assembly cog for hot SPI block R/W action! -}} - ' Start from scratch - stop - ' clear my log buffer - { - bytefill( @log_cmd_resp, 0, LOG_SIZE+1 ) - dbg_ptr := @log_cmd_resp - dbg_end := dbg_ptr + LOG_SIZE - '} - ' wait ~4 milliseconds - waitcnt( 500 + (clkfreq>>8) + cnt ) - ' (start with cog variables, _BEFORE_ loading the cog) - pinDO := DO - maskDO := |< DO - pinCLK := CLK - pinDI := DI - maskDI := |< DI - maskCS := |< CS - adrShift := 9 ' block = 512 * index, and 512 = 1<<9 - ' pass the output pin mask via the command register - maskAll := maskCS | (| 74 clocks - outa |= maskAll - repeat 4096 - outa[CLK]~~ - outa[CLK]~ - ' time-hack - SPI_block_index := cnt - ' reset the card - tmp~ - repeat i from 0 to 9 - if tmp <> 1 - tmp := send_cmd_slow( CMD0, 0, $95 ) - if (tmp & 4) - ' the card said CMD0 ("go idle") was invalid, so we're possibly stuck in read or write mode - if i & 1 - ' exit multiblock read mode - repeat 4 - read_32_slow ' these extra clocks are required for some MMC cards - send_slow( $FD, 8 ) ' stop token - read_32_slow - repeat while read_slow <> $FF - else - ' exit multiblock read mode - send_cmd_slow( CMD12, 0, $61 ) - if tmp <> 1 - ' the reset command failed! - crash( ERR_CARD_NOT_RESET ) - ' Is this a SD type 2 card? - if send_cmd_slow( CMD8, $1AA, $87 ) == 1 - ' Type2 SD, check to see if it's a SDHC card - tmp := read_32_slow - ' check the supported voltage - if (tmp & $1FF) <> $1AA - crash( ERR_3v3_NOT_SUPPORTED ) - ' try to initialize the type 2 card with the High Capacity bit - repeat while send_cmd_slow( ACMD41, |<30, $77 ) - ' the card is initialized, let's read back the High Capacity bit - if send_cmd_slow( CMD58, 0, $FD ) <> 0 - crash( ERR_OCR_FAILED ) - ' get back the data - tmp := read_32_slow - ' check the bit - if tmp & |<30 - card_type := type_SDHC - adrShift := 0 - else - card_type := type_SD - else - ' Either a type 1 SD card, or it's MMC, try SD 1st - if send_cmd_slow( ACMD41, 0, $E5 ) < 2 - ' this is a type 1 SD card (1 means busy, 0 means done initializing) - card_type := type_SD - repeat while send_cmd_slow( ACMD41, 0, $E5 ) - else - ' mark that it's MMC, and try to initialize - card_type := type_MMC - repeat while send_cmd_slow( CMD1, 0, $F9 ) - ' some SD or MMC cards may have the wrong block size, set it here - send_cmd_slow( CMD16, 512, $15 ) - ' card is mounted, make sure the CRC is turned off - send_cmd_slow( CMD59, 0, $91 ) - ' check the status - 'send_cmd_slow( CMD13, 0, $0D ) - ' done with the SPI bus for now - outa |= maskCS - ' set my counter modes for super fast SPI operation - ' writing: NCO single-ended mode, output on DI - writeMode := (%00100 << 26) | (DI << 0) - ' reading - 'readMode := (%11000 << 26) | (DO << 0) | (CLK << 9) - ' clock - 'clockLineMode := (%00110 << 26) | (CLK << 0) ' DUTY, 25% duty cycle - ' clock - clockLineMode := (%00100 << 26) | (CLK << 0) ' NCO, 50% duty cycle - ' how many bytes (8 clocks, >>3) fit into 1/2 of a second (>>1), 4 clocks per instruction (>>2)? - N_in8_500ms := clkfreq >> constant(1+2+3) - ' how long should we wait before auto-exiting any multiblock mode? - idle_limit := 125 ' ms, NEVER make this > 1000 - idle_limit := clkfreq / (1000 / idle_limit) ' convert to counts - ' Hand off control to the assembly engine's cog - bufAdr := @SPI_buffer_address - sdAdr := @SPI_block_index - SPI_command := 0 ' just make sure it's not 1 - ' start my driver cog and wait till I hear back that it's done - SPI_engine_cog := cognew( @SPI_engine_entry, @SPI_command ) + 1 - if( SPI_engine_cog == 0 ) - crash( ERR_SPI_ENGINE_NOT_RUNNING ) - repeat while SPI_command <> -1 - ' and we no longer need to control any pins from here - dira &= !maskAll - ' the return variable is card_type - -PUB release -{{ - I do not want to abort if the cog is not - running, as this is called from stop, which - is called from start/ [8^) -}} - if SPI_engine_cog - SPI_command := "z" - repeat while SPI_command == "z" - -PUB stop -{{ - kill the assembly driver cog. -}} - release - if SPI_engine_cog - cogstop( SPI_engine_cog~ - 1 ) - -PRI crash( abort_code ) -{{ - In case of Bad Things(TM) happening, - exit as gracefully as possible. -}} - ' and we no longer need to control any pins from here - dira &= !maskAll - ' and report our error - abort abort_code - -PRI send_cmd_slow( cmd, val, crc ) : reply | time_stamp -{{ - Send down a command and return the reply. - Note: slow is an understatement! - Note: this uses the assembly DAT variables for pin IDs, - which means that if you run this multiple times (say for - multiple SD cards), these values will change for each one. - But this is OK as all of these functions will be called - during the initialization only, before the PASM engine is - running. -}} - ' if this is an application specific command, handle it - if (cmd & $80) - ' ACMD is the command sequense of CMD55-CMD - cmd &= $7F - reply := send_cmd_slow( CMD55, 0, $65 ) - if (reply > 1) - return reply - ' the CS line needs to go low during this operation - outa |= maskCS - outa &= !maskCS - ' give the card a few cocks to finish whatever it was doing - read_32_slow - ' send the command byte - send_slow( cmd, 8 ) - ' send the value long - send_slow( val, 32 ) - ' send the CRC byte - send_slow( crc, 8 ) - ' is this a CMD12?, if so, stuff byte - if cmd == CMD12 - read_slow - ' read back the response (spec declares 1-8 reads max for SD, MMC is 0-8) - time_stamp := 9 - repeat - reply := read_slow - while( reply & $80 ) and ( time_stamp-- ) - ' done, and 'reply' is already pre-loaded - { - if dbg_ptr < (dbg_end-1) - byte[dbg_ptr++] := cmd - byte[dbg_ptr++] := reply - if (cmd&63) == 13 - ' get the second byte - byte[dbg_ptr++] := cmd - byte[dbg_ptr++] := read_slow - '} - -PRI send_slow( value, bits_to_send ) - value ><= bits_to_send - repeat bits_to_send - outa[pinCLK]~ - outa[pinDI] := value - value >>= 1 - outa[pinCLK]~~ - -PRI read_32_slow : r - repeat 4 - r <<= 8 - r |= read_slow - -PRI read_slow : r -{{ - Read back 8 bits from the card -}} - ' we need the DI line high so a read can occur - outa[pinDI]~~ - ' get 8 bits (remember, r is initialized to 0 by SPIN) - repeat 8 - outa[pinCLK]~ - outa[pinCLK]~~ - r += r + ina[pinDO] - ' error check - if( (cnt - SPI_block_index) > (clkfreq << 2) ) - crash( ERR_CARD_BUSY_TIMEOUT ) - -DAT -{{ - This is the assembly engine for doing fast block - reads and writes. This is *ALL* it does! -}} -ORG 0 -SPI_engine_entry - ' Counter A drives data out - mov ctra,writeMode - ' Counter B will always drive my clock line - mov ctrb,clockLineMode - ' set our output pins to match the pin mask - mov dira,maskAll - ' handshake that we now control the pins - neg user_request,#1 - wrlong user_request,par - ' start my seconds' counter here - mov last_time,cnt - -waiting_for_command - ' update my seconds counter, but also track the idle - ' time so we can to release the card after timeout. - call #handle_time - ' read the command, and make sure it's from the user (> 0) - rdlong user_request,par - cmps user_request,#0 wz,wc -if_be jmp #waiting_for_command - ' handle our card based commands - cmp user_request,#"r" wz -if_z jmp #read_ahead - cmp user_request,#"w" wz -if_z jmp #write_behind - cmp user_request,#"z" wz -if_z jmp #release_card - ' time requests are handled differently - cmp user_request,#"t" wz ' time -if_z wrlong seconds,sdAdr ' seconds goes into the SD index register -if_z wrlong dtime,bufAdr ' the remainder goes into the buffer address register - ' in all other cases, clear the user's request - mov user_request,#0 - wrlong user_request,par - jmp #waiting_for_command - - -release_card - mov user_cmd,#"z" ' request a release - neg lastIndexPlus,#1 ' reset the last block index - neg user_idx,#1 ' and make this match it - call #handle_command - mov user_request,user_cmd - wrlong user_request,par - jmp #waiting_for_command - -read_ahead - rdlong user_idx,sdAdr - ' if the correct block is not already loaded, load it - mov tmp1,user_idx - add tmp1,#1 - cmp tmp1,lastIndexPlus wz -if_z cmp lastCommand,#"r" wz -if_z jmp #:get_on_with_it - mov user_cmd,#"r" - call #handle_command -:get_on_with_it - ' copy the data up into Hub RAM - movi transfer_long,#%000010_000 'set to wrlong - call #hub_cog_transfer - ' signify that the data is ready, Spin can continue - mov user_request,user_cmd - wrlong user_request,par - ' request the next block - mov user_cmd,#"r" - add user_idx,#1 - call #handle_command - ' done - jmp #waiting_for_command - -write_behind - rdlong user_idx,sdAdr - ' copy data in from Hub RAM - movi transfer_long,#%000010_001 'set to rdlong - call #hub_cog_transfer - ' signify that we have the data, Spin can continue - mov user_request,user_cmd - wrlong user_request,par - ' write out the block - mov user_cmd,#"w" - call #handle_command - ' done - jmp #waiting_for_command - -{{ - Set user_cmd and user_idx before calling this -}} -handle_command - ' Can we stay in the old mode? (address = old_address+1) && (old mode == new_mode) - cmp lastIndexPlus,user_idx wz -if_z cmp user_cmd,lastCommand wz -if_z jmp #:execute_block_command - ' we fell through, must exit the old mode! (except if the old mode was "release") - cmp lastCommand,#"w" wz -if_z call #stop_mb_write - cmp lastCommand,#"r" wz -if_z call #stop_mb_read - ' and start up the new mode! - cmp user_cmd,#"w" wz -if_z call #start_mb_write - cmp user_cmd,#"r" wz -if_z call #start_mb_read - cmp user_cmd,#"z" wz -if_z call #release_DO -:execute_block_command - ' track the (new) last index and command - mov lastIndexPlus,user_idx - add lastIndexPlus,#1 - mov lastCommand,user_cmd - ' do the block read or write or terminate! - cmp user_cmd,#"w" wz -if_z call #write_single_block - cmp user_cmd,#"r" wz -if_z call #read_single_block - cmp user_cmd,#"z" wz -if_z mov user_cmd,#0 - ' done -handle_command_ret - ret - -{=== these PASM functions get me in and out of multiblock mode ===} -release_DO - ' we're already out of multiblock mode, so - ' deselect the card and send out some clocks - or outa,maskCS - call #in8 - call #in8 - ' if you are using pull-up resistors, and need all - ' lines tristated, then uncomment the following line. - ' for Cluso99 - 'mov dira,#0 -release_DO_ret - ret - -start_mb_read - movi block_cmd,#CMD18<<1 - call #send_SPI_command_fast -start_mb_read_ret - ret - -stop_mb_read - movi block_cmd,#CMD12<<1 - call #send_SPI_command_fast - call #busy_fast -stop_mb_read_ret - ret - -start_mb_write - movi block_cmd,#CMD25<<1 - call #send_SPI_command_fast -start_mb_write_ret - ret - -stop_mb_write - call #busy_fast - ' only some cards need these extra clocks - mov tmp1,#16 -:loopity - call #in8 - djnz tmp1,#:loopity - ' done with hack - movi phsa,#$FD<<1 - call #out8 - call #in8 ' stuff byte - call #busy_fast -stop_mb_write_ret - ret - -send_SPI_command_fast - ' make sure we have control of the output lines - mov dira,maskAll - ' make sure the CS line transitions low - or outa,maskCS - andn outa,maskCS - ' 8 clocks - call #in8 - ' send the data - mov phsa,block_cmd ' do which ever block command this is (already in the top 8 bits) - call #out8 ' write the byte - mov phsa,user_idx ' read in the desired block index - shl phsa,adrShift ' this will multiply by 512 (bytes/sector) for MMC and SD - call #out8 ' move out the 1st MSB ' - rol phsa,#1 - call #out8 ' move out the 1st MSB ' - rol phsa,#1 - call #out8 ' move out the 1st MSB ' - rol phsa,#1 - call #out8 ' move out the 1st MSB ' - ' bogus CRC value - call #in8 ' in8 looks like out8 with $FF - ' CMD12 requires a stuff byte - shr block_cmd,#24 - cmp block_cmd,#CMD12 wz -if_z call #in8 ' 8 clocks - ' get the response - mov tmp1,#9 -:cmd_response - call #in8 - test readback,#$80 wc,wz -if_c djnz tmp1,#:cmd_response -if_nz neg user_cmd,readback - ' done -send_SPI_command_fast_ret - ret - - -busy_fast - mov tmp1,N_in8_500ms -:still_busy - call #in8 - cmp readback,#$FF wz -if_nz djnz tmp1,#:still_busy -busy_fast_ret - ret - - -out8 - andn outa,maskDI - 'movi phsb,#%11_0000000 - mov phsb,#0 - movi frqb,#%01_0000000 - rol phsa,#1 - rol phsa,#1 - rol phsa,#1 - rol phsa,#1 - rol phsa,#1 - rol phsa,#1 - rol phsa,#1 - mov frqb,#0 - ' don't shift out the final bit...already sent, but be aware - ' of this when sending consecutive bytes (send_cmd, for e.g.) -out8_ret - ret - -{ -in8 - or outa,maskDI - mov ctra,readMode - ' Start my clock - mov frqa,#1<<7 - mov phsa,#0 - movi phsb,#%11_0000000 - movi frqb,#%01_0000000 - ' keep reading in my value, one bit at a time! (Kuneko - "Wh) - shr frqa,#1 - shr frqa,#1 - shr frqa,#1 - shr frqa,#1 - shr frqa,#1 - shr frqa,#1 - shr frqa,#1 - mov frqb,#0 ' stop the clock - mov readback,phsa - mov frqa,#0 - mov ctra,writeMode -in8_ret - ret -} -in8 - neg phsa,#1' DI high - mov readback,#0 - ' set up my clock, and start it - movi phsb,#%011_000000 - movi frqb,#%001_000000 - ' keep reading in my value - test maskDO,ina wc - rcl readback,#1 - test maskDO,ina wc - rcl readback,#1 - test maskDO,ina wc - rcl readback,#1 - test maskDO,ina wc - rcl readback,#1 - test maskDO,ina wc - rcl readback,#1 - test maskDO,ina wc - rcl readback,#1 - test maskDO,ina wc - rcl readback,#1 - test maskDO,ina wc - mov frqb,#0 ' stop the clock - rcl readback,#1 - mov phsa,#0 'DI low -in8_ret - ret - - -' this is called more frequently than 1 Hz, and -' is only called when the user command is 0. -handle_time - mov tmp1,cnt ' get the current timestamp - add idle_time,tmp1 ' add the current time to my idle time counter - sub idle_time,last_time ' subtract the last time from my idle counter (hence delta) - add dtime,tmp1 ' add to my accumulator, - sub dtime,last_time ' and subtract the old (adding delta) - mov last_time,tmp1 ' update my "last timestamp" - rdlong tmp1,#0 ' what is the clock frequency? - cmpsub dtime,tmp1 wc ' if I have more than a second in my accumulator - addx seconds,#0 ' then add it to "seconds" - ' this part is to auto-release the card after a timeout - cmp idle_time,idle_limit wz,wc -if_b jmp #handle_time_ret ' don't clear if we haven't hit the limit - mov user_cmd,#"z" ' we can't overdo it, the command handler makes sure - neg lastIndexPlus,#1 ' reset the last block index - neg user_idx,#1 ' and make this match it - call #handle_command ' release the card, but don't mess with the user's request register -handle_time_ret - ret - -hub_cog_transfer -' setup for all 4 passes - mov ctrb,clockXferMode - mov frqb,#1 - rdlong buf_ptr,bufAdr - mov ops_left,#4 - movd transfer_long,#speed_buf -four_transfer_passes - ' sync to the Hub RAM access - rdlong tmp1,tmp1 - ' how many long to move on this pass? (512 bytes / 4)longs / 4 passes - mov tmp1,#(512 / 4 / 4) - ' get my starting address right (phsb is incremented 1 per clock, so 16 each Hub access) - mov phsb,buf_ptr - ' write the longs, stride 4...low 2 bits of phsb are ignored -transfer_long - rdlong 0-0,phsb - add transfer_long,incDest4 - djnz tmp1,#transfer_long - ' go back to where I started, but advanced 1 long - sub transfer_long,decDestNminus1 - ' offset my Hub pointer by one long per pass - add buf_ptr,#4 - ' do all 4 passes - djnz ops_left,#four_transfer_passes - ' restore the counter mode - mov frqb,#0 - mov phsb,#0 - mov ctrb,clockLineMode -hub_cog_transfer_ret - ret - - -read_single_block - ' where am I sending the data? - movd :store_read_long,#speed_buf - mov ops_left,#128 - ' wait until the card is ready - mov tmp1,N_in8_500ms -:get_resp - call #in8 - cmp readback,#$FE wz -if_nz djnz tmp1,#:get_resp -if_nz neg user_cmd,#ERR_ASM_NO_READ_TOKEN -if_nz jmp #read_single_block_ret - ' set DI high - neg phsa,#1 - ' read the data - mov ops_left,#128 -:read_loop - mov tmp1,#4 - movi phsb,#%011_000000 -:in_byte - ' Start my clock - movi frqb,#%001_000000 - ' keep reading in my value, BACKWARDS! (Brilliant idea by Tom Rokicki!) - test maskDO,ina wc - rcl readback,#8 - test maskDO,ina wc - muxc readback,#2 - test maskDO,ina wc - muxc readback,#4 - test maskDO,ina wc - muxc readback,#8 - test maskDO,ina wc - muxc readback,#16 - test maskDO,ina wc - muxc readback,#32 - test maskDO,ina wc - muxc readback,#64 - test maskDO,ina wc - mov frqb,#0 ' stop the clock - muxc readback,#128 - ' go back for more - djnz tmp1,#:in_byte - ' make it...NOT backwards [8^) - rev readback,#0 -:store_read_long - mov 0-0,readback ' due to some counter weirdness, we need this mov - add :store_read_long,const512 - djnz ops_left,#:read_loop - - ' set DI low - mov phsa,#0 - - ' now read 2 trailing bytes (CRC) - call #in8 ' out8 is 2x faster than in8 - call #in8 ' and I'm not using the CRC anyway - ' give an extra 8 clocks in case we pause for a long time - call #in8 ' in8 looks like out8($FF) - - ' all done successfully - mov idle_time,#0 - mov user_cmd,#0 -read_single_block_ret - ret - -write_single_block - ' where am I getting the data? (all 512 bytes / 128 longs of it?) - movs :write_loop,#speed_buf - ' read in 512 bytes (128 longs) from Hub RAM and write it to the card - mov ops_left,#128 - ' just hold your horses - call #busy_fast - ' $FC for multiblock, $FE for single block - movi phsa,#$FC<<1 - call #out8 - mov phsb,#0 ' make sure my clock accumulator is right - 'movi phsb,#%11_0000000 -:write_loop - ' read 4 bytes - mov phsa,speed_buf - add :write_loop,#1 - ' a long in LE order is DCBA - rol phsa,#24 ' move A7 into position, so I can do the swizzled version - movi frqb,#%010000000 ' start the clock (remember A7 is already in place) - rol phsa,#1 ' A7 is going out, at the end of this instr, A6 is in place - rol phsa,#1 ' A5 - rol phsa,#1 ' A4 - rol phsa,#1 ' A3 - rol phsa,#1 ' A2 - rol phsa,#1 ' A1 - rol phsa,#1 ' A0 - rol phsa,#17 ' B7 - rol phsa,#1 ' B6 - rol phsa,#1 ' B5 - rol phsa,#1 ' B4 - rol phsa,#1 ' B3 - rol phsa,#1 ' B2 - rol phsa,#1 ' B1 - rol phsa,#1 ' B0 - rol phsa,#17 ' C7 - rol phsa,#1 ' C6 - rol phsa,#1 ' C5 - rol phsa,#1 ' C4 - rol phsa,#1 ' C3 - rol phsa,#1 ' C2 - rol phsa,#1 ' C1 - rol phsa,#1 ' C0 - rol phsa,#17 ' D7 - rol phsa,#1 ' D6 - rol phsa,#1 ' D5 - rol phsa,#1 ' D4 - rol phsa,#1 ' D3 - rol phsa,#1 ' D2 - rol phsa,#1 ' D1 - rol phsa,#1 ' D0 will be in place _after_ this instruction - mov frqb,#0 ' shuts the clock off, _after_ this instruction - djnz ops_left,#:write_loop - ' write out my two (bogus, using $FF) CRC bytes - call #in8 - call #in8 - ' now read response (I need this response, so can't spoof using out8) - call #in8 - and readback,#$1F - cmp readback,#5 wz -if_z mov user_cmd,#0 ' great -if_nz neg user_cmd,#ERR_ASM_BLOCK_NOT_WRITTEN ' oops - ' send out another 8 clocks - call #in8 - ' all done - mov idle_time,#0 -write_single_block_ret - ret - - -{=== Assembly Interface Variables ===} -pinDO long 0 ' pin is controlled by a counter -pinCLK long 0 ' pin is controlled by a counter -pinDI long 0 ' pin is controlled by a counter -maskDO long 0 ' mask for reading the DO line from the card -maskDI long 0 ' mask for setting the pin high while reading -maskCS long 0 ' mask = (1< -1), speakerPinNumber) newFrequency := ((newFrequency <# clkfreq) #> 0) result := 1 repeat 32 newFrequency <<= 1 result <-= 1 if(newFrequency => clkfreq) newFrequency -= clkfreq result += 1 frqa := result~ phsb := 0 PUB speakerVolume(newVolume, speakerPinNumber) '' 10 Stack Longs '' //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// '' // Changes the speaker volume using the SPIN interpreter's counter modules. '' // '' // NewVolume - The new volume. Between 0% and 100%. -1 to reset the pin and counter modules. '' // SpeakerPinNumber - Pin to use to drive the speaker circuit. Between 0 and 31. '' //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// speakerSetup((newVolume <> -1), speakerPinNumber) frqb := (((100 - ((newVolume <# 100) #> 0)) * constant(posx / 50)) | $7) PRI speakerSetup(activeOrInactive, speakerPinNumber) ' 5 Stack Longs speakerPinNumber := ((speakerPinNumber <# 31) #> 0) dira[speakerPinNumber] := activeOrInactive outa[speakerPinNumber] := false ctra := ((constant(%0_0100 << 26) + speakerPinNumber) & activeOrInactive) ctrb := ((constant(%0_0110 << 26) + speakerPinNumber) & activeOrInactive) {{ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // TERMS OF USE: MIT License /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation // files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, // modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the // Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE // WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// }} \ No newline at end of file diff --git a/Hardware/PropIO2/Spin/Keyboard.spin b/Hardware/PropIO2/Spin/Keyboard.spin deleted file mode 100644 index 29025a99..00000000 Binary files a/Hardware/PropIO2/Spin/Keyboard.spin and /dev/null differ diff --git a/Hardware/PropIO2/Spin/Parallax Serial Terminal.spin b/Hardware/PropIO2/Spin/Parallax Serial Terminal.spin deleted file mode 100644 index a525a4be..00000000 Binary files a/Hardware/PropIO2/Spin/Parallax Serial Terminal.spin and /dev/null differ diff --git a/Hardware/PropIO2/Spin/VGA_1024.spin b/Hardware/PropIO2/Spin/VGA_1024.spin deleted file mode 100644 index 9f3c2851..00000000 --- a/Hardware/PropIO2/Spin/VGA_1024.spin +++ /dev/null @@ -1,704 +0,0 @@ -'' VGA_1024.spin -'' -'' MODIFIED BY VINCE BRIEL FOR POCKETERM FEATURES -'' MODIIFED BY JEFF LEDGER / AKA OLDBITCOLLECTOR -'' - -CON - cols = 80 '128 ' number of screen columns - lcols = cols / 4 ' number of long in columns - rows = 40 '64 ' number of screen rows - chars = rows*cols ' number of screen characters - esc = $CB ' keyboard esc char - rowsnow = 36 ' adjusted for split screen effect - maxChars = rowsnow*cols ' adjusted value for split screen effect - lastChar = maxChars / 4 ' last screen position in longs adjusted for split - lastLine = (rowsnow - 1) * cols ' character position of last row - cols1 = 81 ' adjusted value for 80th character - TURQUOISE = $29 - -OBJ - vga : "vga_Hires_Text" - -VAR - byte screen[chars] ' screen character buffer - byte tmpl[cols] ' temporary line buffer - word colors[rows] ' color specs for each screen row (see ColorPtr description above) - byte cursor[6] ' cursor info array (see CursorPtr description above) - long sync, loc, xloc, yloc ' sync used by VGA routine, others are local screen pointers - long kbdreq ' global val of kbdflag - long BR[8] - long Brate - byte inverse - byte invs - byte state ' Current state of state machine - word pos ' Current Position on the screen - word oldpos ' Previous location of cursor before update - word regionTop, regionBot ' Scroll region top/bottom - long arg0 ' First argument of escape sequence - long arg1 ' Second argument of escape sequence - byte lastc ' Last displayed char - word statpos - long vgabasepin - -PUB start(BasePin) | i, char - vgabasepin := BasePin - -''init screen colors to gold on blue - repeat i from 0 to rows - 1 - colors[i] := $08F0 '$2804 (if you want cyan on blue) - -''init cursor attributes - cursor[2] := %110 ' init cursor to underscore with slow blink - BR[0]:=300 - BR[1]:=1200 - BR[2]:=2400 - BR[3]:=4800 - BR[4]:=9600 - BR[5]:=19200 - BR[6]:=38400 - BR[7]:=57600 - BR[8]:=115200 - xloc := cursor[0] := 0 - yloc := cursor[1] := 0 - loc := xloc + yloc*cols - - pos := 0 - regionTop := 0 - regionBot := 35 * cols - state := 0 - statpos := 37 * cols - -PUB vidon - if (!vga.start(vgabasepin, @screen, @colors, @cursor, @sync)) - return false - - waitcnt(clkfreq * 1 + cnt) 'wait 1 second for cogs to start - - -PUB vidoff - vga.stop - - -PUB inv(c) - inverse:=c - -PUB color(colorVal) | i - repeat i from 0 to rows - 1 - colors[i] := $0000 | colorVal - -PUB cursorset(c) | i - i:=%000 - if c == 1 - i:= %001 - if c == 2 - i:= %010 - if c == 3 - i:= %011 - if c == 4 - i:= %101 - if c == 5 - i:= %110 - if c == 6 - i:= %111 - if c == 7 - i:= %000 - cursor[2] := i - -PUB bin(value, digits) - -'' Print a binary number, specify number of digits - - repeat while digits > 32 - outc("0") - digits-- - - value <<= 32 - digits - - repeat digits - outc((value <-= 1) & 1 + "0") - - -PUB clrbtm(ColorVal) | i - repeat i from 36 to rows - 1 'was 35 - colors[i] := $0000 + ColorVal - -PUB cls1(c,screencolor,pcport,ascii,CR) | i,x,y - - longfill(@screen[0], $20202020, chars / 4) - - clrbtm(TURQUOISE) - - inverse := 1 - - statprint(36,0, string(" N8VEM PropIO V2 | RomWBW v0.94")) - inverse := 0 - statprint(37,0, string(" ")) - statprint(38,0, string(" ")) - statprint(39,0, string(" ")) - - -{{ - x :=xloc - y := yloc - invs := inverse - ''clrbtm(TURQUOISE) - longfill(@screen, $20202020, chars/4) - xloc := 0 - yloc :=0 - loc := xloc + yloc*cols - repeat 80 - outc(32) - xloc := 0 - yloc :=36 - loc := xloc + yloc*cols - inverse := 1 - str(string(" propIO V 0.91 ")) - inverse := 0 - str(string("Baud Rate: ")) - i:= BR[6] - dec(i) - str(string(" ")) - xloc := 18 - loc := xloc + yloc*cols - str(string("Color ")) - str(string("PC Port: ")) - if pcport == 1 - str(string("OFF ")) - if pcport == 0 - str(string("ON ")) - str(string(" Force 7 bit: ")) - if ascii == 0 - str(string("NO ")) - if ascii == 1 - str(string("YES ")) - str(string(" Cursor CR W/LF: ")) - if CR == 1 - str(string("YES")) - if CR == 0 - str(string("NO ")) - outc(13) - outc(10) - - inverse:=1 - xloc := 6 - loc := xloc + yloc*cols - str(string("F1")) - xloc := 19 - loc := xloc + yloc*cols - str(string("F2")) - xloc := 30 - loc := xloc + yloc*cols - str(string("F3")) - xloc := 46 - loc := xloc + yloc*cols - str(string("F4")) - xloc := 58 - loc := xloc + yloc*cols - str(string("F5")) - xloc := 70 - loc := xloc + yloc*cols - str(string("F6")) - inverse := invs - xloc := cursor[0] := x 'right & left was 0 - yloc := cursor[1] := y 'from top was 1 - loc := xloc + yloc*cols -}} - -PUB clsupdate(c,screencolor,PCPORT,ascii,CR) | i,x,y,locold - - invs := inverse - locold := loc - x := xloc - y := yloc - ''(TURQUOISE) - xloc := 0 - yloc :=36 - loc := xloc + yloc*cols - inverse := 1 - str(string(" propIO V 0.81 ")) - inverse := 0 - xloc := 0 - yloc :=37 - loc := xloc + yloc*cols - str(string("Baud Rate: ")) - i:= BR[6] - dec(i) - str(string(" ")) - xloc := 18 - loc := xloc + yloc*cols - - str(string("Color ")) - str(string("PC Port: ")) - if pcport == 1 - str(string("OFF ")) - if pcport == 0 - str(string("ON ")) - str(string(" Force 7 bit: ")) - if ascii == 0 - str(string("NO ")) - if ascii == 1 - str(string("YES ")) - str(string(" Cursor CR W/LF: ")) - if CR == 1 - str(string("YES")) - if CR == 0 - str(string("NO ")) - xloc := 0 - yloc :=38 - loc := xloc + yloc*cols - inverse:=1 - xloc := 6 - loc := xloc + yloc*cols - str(string("F1")) - xloc := 19 - loc := xloc + yloc*cols - str(string("F2")) - xloc := 30 - loc := xloc + yloc*cols - str(string("F3")) - xloc := 46 - loc := xloc + yloc*cols - str(string("F4")) - xloc := 58 - loc := xloc + yloc*cols - str(string("F5")) - xloc := 70 - loc := xloc + yloc*cols - str(string("F6")) - inverse := invs - xloc := cursor[0] := x - yloc := cursor[1] := y -' loc := xloc + yloc*cols - loc := locold - -PUB dec(value) | i - -'' Print a decimal number - - if value < 0 - -value - outc("-") - - i := 1_000_000_000 - - repeat 10 - if value => i - outc(value/i + "0") - value //= i - result~~ - elseif result or i == 1 - outc("0") - i /= 10 - -PUB hex(value, digits) - -'' Print a hexadecimal number, specify number of digits - - repeat while digits > 8 - outc("0") - digits-- - - value <<= (8 - digits) << 2 - - repeat digits - outc(lookupz((value <-= 4) & $f : "0".."9", "A".."F")) - - -PUB str(string_ptr) - -'' Print a zero terminated string - - repeat strsize(string_ptr) - process_char(byte[string_ptr++]) - -PUB statprint(r, c, str1) | x, ptr - - ptr := r * cols + c - repeat x from 0 to STRSIZE(str1) - 1 - putc(ptr++, BYTE[str1 + x]) - -PUB statnum(r, c, num1) | i, ptr - - ptr := r * cols + c - - if num1 < 0 - -num1 - putc(ptr++,"-") - - i := 1_000_000_000 - - repeat 10 - if num1 => i - putc(ptr++, (num1/i +"0")) - num1 //= i - result~~ - elseif result or i == 1 - putc(ptr++, "0") - i /= 10 - -PUB putc(position, c) - if inverse - c |= $80 - screen[position] := c - -PUB cls - longfill (@screen, $20202020, lastChar) - -PUB fullcls - longfill(@screen, $20202020, 800) - -PUB setInverse(val) - inverse := val - -PUB setInv(c) - if c == 7 - setInverse(1) - else - setInverse(0) - -PUB clEOL(position) | count - count := cols - (position // cols) - bytefill(@screen + position, $20, count) - -PUB clBOL(position) | count - count := position // cols - bytefill(@screen + position - count, $20, count) - -PUB delLine(position) | src, count - position -= position // cols - - src := position + cols - - count := (maxChars - src) / 4 - - if count > 0 - longmove(@screen + position, @screen + src, count) - - longfill(@screen + lastLine, $20202020, lcols) - -PUB clEOS(position) - cleol(position) - position += cols - (position // cols) - repeat while position < maxChars - longfill(@screen + position, $20202020, lcols) - pos += cols - -PUB setCursorPos(position) - cursor[0] := position // cols - cursor[1] := position / cols - -PUB insLine(position) | base, nxt - base := position - (position // cols) - position := lastLine - repeat while position > base - nxt := position - cols - longmove(@screen + position, @screen + nxt, lcols) - position := nxt - clEOL(base) - -PUB insChar(position) | count - count := (cols - (position // cols)) - 1 - bytemove(@tmpl, @screen + position, count) - screen[position] := " " - bytemove(@screen + position + 1, @tmpl, count) - -PUB delChar(position) | count - count := (cols - (position // cols)) - 1 - bytemove(@screen + position, @screen + position + 1, count) - screen[position + count] := " " - -PRI inRegion : answer - answer := (pos => regionTop) AND (pos < regionBot) - -PRI scrollUp - delLine(regionTop) - if regionBot < maxChars - insLine(regionBot) - -PRI scrollDown - if regionBot < maxChars - delLine(regionBot) - insLine(regionTop) - -PRI ansi(c) | x, defVal - - state := 0 - - if (c <> "r") AND (c <> "J") AND (c <> "m") AND (c <> "K") - if arg0 == -1 - arg0 := 1 - if arg1 == -1 - arg1 := 1 - - case c - "@": - repeat while arg0-- > 0 - insChar(pos) - - "b": - repeat while arg0-- > 0 - outc(lastc) - - "d": - if (arg0 < 1) OR (arg0 > rows) - arg0 := rows - pos := ((arg0 - 1) * cols) + (pos // cols) - - "m": - setInv(arg0) - if arg1 <> -1 - setInv(arg1) - - "r": - if arg0 < 1 - arg0 := 1 - elseif arg0 > cols - arg0 := cols - if arg1 < 1 - arg1 := 1 - elseif arg1 > cols - arg1 := cols - if arg1 < arg0 - arg1 := arg0 - - regionTop := (arg0 - 1) * cols - regionBot := arg1 * cols - pos := 0 - - "A": - repeat while arg0-- > 0 - pos -= cols - if pos < 0 - pos += cols - return - - "B": - repeat while arg0-- > 0 - pos += cols - if pos => maxChars - pos -= cols - return - - "C": - repeat while arg0-- > 0 - pos += 1 - if pos => maxChars - pos -= 1 - return - - "D": - repeat while arg0-- > 0 - pos -= 1 - if pos < 0 - pos := 0 - return - - "G": - if (arg0 < 1) OR (arg0 > cols) - arg0 := cols - pos := (pos - (pos // cols)) + (arg0 - 1) - - "H", "f": - if arg0 =< 0 - arg0 := 1 - if arg1 =< 0 - arg1 := 1 - pos := (cols * (arg0 - 1)) + (arg1 - 1) - if pos < 0 - pos := 0 - if pos => maxChars - pos := maxChars - 1 - - "J": - if arg0 == 1 - clBOL(pos) - x := pos - cols - x -= x // cols - repeat while x => 0 - clEOL(x) - x -= cols - return - - if arg0 == 2 - pos := 0 - - clEOL(pos) - x := pos + cols - x -= (x // cols) - repeat while x < maxChars - clEOL(x) - x += cols - - "K": - if arg0 == -1 - clEOL(pos) - elseif arg0 == 1 - clBOL(pos) - else - clEOL(pos - (pos // cols)) - - "L": - if inRegion - repeat while arg0-- > 0 - if regionBot < maxChars - delLine(regionBot) - insLine(pos) - - "M": - if inRegion - repeat while arg0-- > 0 - delLine(pos) - if regionBot < maxChars - insLine(regionBot) - - "P": - repeat while arg0-- - delChar(pos) - -PRI outc(c) - - putc(pos++, lastc := c) - if pos == regionBot - scrollUp - pos -= cols - elseif pos == maxChars - pos := lastLine - -PUB process_char(c) - - case state - - 0: - if c > 127 - c := $20 - - if c => $20 - outc(c) - setCursorPos(pos) - return - - if c == $1B - state := 1 - return - - if c == $0D - pos := pos - (pos // cols) - setCursorPos(pos) - return - - if c == $0A - if inRegion - pos += cols - if pos => regionBot - scrollUp - pos -= cols - else - pos += cols - if pos => maxChars - pos -= cols - setCursorPos(pos) - return - - if c == 9 - pos += (8 - (pos // 8)) - - if pos => maxChars - pos := lastLine - delLine(0) - - setCursorPos(pos) - return - - if c == 8 - if pos > 0 - pos -= 1 - setCursorPos(pos) - return - - 1: - case c - "[": - arg0 := arg1 := -1 - state := 2 - return - - "P": - pos += cols - if pos => maxChars - pos -= cols - - "K": - if pos > 0 - pos -= 1 - - "H": - pos -= cols - if pos < 0 - pos += cols - - "D": - if inRegion - scrollUp - - "M": - if inRegion - scrollDown - - "G": - pos := 0 - - "(": - state := 5 - return - - state := 0 - return - - 2: - if (c => "0") AND (c =< "9") - if arg0 == -1 - arg0 := c - "0" - else - arg0 := (arg0 * 10) + (c - "0") - return - - if c == ";" - state := 3 - return - - ansi(c) - setCursorPos(pos) - return - - 3: - if (c => "0") AND (c =< "9") - if arg1 == -1 - arg1 := c - "0" - else - arg1 := (arg1 * 10) + (c - "0") - return - - if c == ";" - state := 4 - return - - ansi(c) - setCursorPos(pos) - return - - 4: - if (c => "0") AND (c =< "9") - return - - if c == ";" - return - ansi(c) - setCursorPos(pos) - return - - 5: - state := 0 - return - - return \ No newline at end of file diff --git a/Hardware/PropIO2/Spin/VGA_HiRes_Text.spin b/Hardware/PropIO2/Spin/VGA_HiRes_Text.spin deleted file mode 100644 index 5b892316..00000000 Binary files a/Hardware/PropIO2/Spin/VGA_HiRes_Text.spin and /dev/null differ diff --git a/Hardware/ReadMe.txt b/Hardware/ReadMe.txt index 86ce8545..95395120 100644 --- a/Hardware/ReadMe.txt +++ b/Hardware/ReadMe.txt @@ -7,8 +7,6 @@ Contents VDU\vdu.rom: ROM image for VDU onboard EPROM -PropIO\PropIO.eeprom: PropIO firmware for use with RomWBW - -PropIO2\PropIO2.eeprom: PropIO V2 firmware for use with RomWBW - -ParPortProp\ParPortProp.eeprom: ParPortProp firmware for use with RomWBW +Prop\PropIO.eeprom: PropIO firmware for use with RomWBW +Prop\PropIO2.eeprom: PropIO V2 firmware for use with RomWBW +Prop\ParPortProp.eeprom: ParPortProp firmware for use with RomWBW diff --git a/Source/HBIOS/Config/mk4_std.asm b/Source/HBIOS/Config/mk4_std.asm index 970b8838..85a6a1a4 100644 --- a/Source/HBIOS/Config/mk4_std.asm +++ b/Source/HBIOS/Config/mk4_std.asm @@ -60,7 +60,7 @@ PPIDESLOW .EQU FALSE ; ADD DELAYS TO HELP PROBLEMATIC HARDWARE (TRY THIS IF PPI ; SDENABLE .EQU TRUE ; TRUE FOR SD SUPPORT SDMODE .EQU SDMODE_MK4 ; SDMODE_JUHA, SDMODE_CSIO, SDMODE_UART, SDMODE_PPI, SDMODE_DSD, SDMODE_MK4 -SDTRACE .EQU 2 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF IDEENABLE = TRUE) +SDTRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF IDEENABLE = TRUE) SDCSIOFAST .EQU TRUE ; TABLE-DRIVEN BIT INVERTER ; PRPENABLE .EQU FALSE ; TRUE FOR PROPIO SD SUPPORT (FOR N8VEM PROPIO ONLY!) diff --git a/Source/HBIOS/fd.asm b/Source/HBIOS/fd.asm index a0fe98ee..803663ff 100644 --- a/Source/HBIOS/fd.asm +++ b/Source/HBIOS/fd.asm @@ -372,24 +372,19 @@ FCT_COUNT .EQU (($ - FCT) / FCT_ENTSIZ) ; # ENTRIES IN TABLE FD_DISPATCH: LD A,B ; GET REQUESTED FUNCTION AND $0F - JR Z,FD_RD + JP Z,FD_READ DEC A - JR Z,FD_WR + JP Z,FD_WRITE DEC A - JR Z,FD_ST + JP Z,FD_STATUS DEC A - JR Z,FD_MED + JP Z,FD_MEDIA + DEC A + JP Z,FD_CAP + DEC A + JP Z,FD_GEOM CALL PANIC ; -FD_RD: - JP FD_READ -FD_WR: - JP FD_WRITE -FD_ST: - JP FD_STATUS -FD_MED: - JP FD_MEDIA -; ; FD_MEDIA ; FD_MEDIA: @@ -468,6 +463,56 @@ FD_MEDIA3: #ENDIF RET ; +; +; +FD_CAP: + CALL FD_GEOM ; GET GEOMETRY + ; HL=TRACKS, D=HEADS, E=SECTORS + PUSH HL ; SAVE TRACK COUNT + LD H,D ; HEADS COUNT TO H + RES 7,H ; MAKE SURE LBA CAPABILITY BIT IS CLEARED + CALL MULT8 ; HL := H * E FOR SECTORS / CYL + POP DE ; RECOVER TRACKS, E == TRACK COUNT + LD H,L ; MOVE WORKING COUNT L --> H + CALL MULT8 ; HL := H * E FOR TOTAL SECTORS + LD DE,0 ; HI WORD ALWAYS ZERO + XOR A ; SIGNAL SUCCESS + RET ; DONE +; +; +; +FD_GEOM: + LD A,C ; GET DEVICE/UNIT + OR $0F ; ISOLATE UNIT + JR Z,FD_GEOM0 ; UNIT 0 + DEC A ; NOPE, TRY UNIT 1 + JR Z,FD_GEOM1 ; UNIT 1 + CALL PANIC ; INVALID UNIT +FD_GEOM0: + LD A,(FCD_U0MEDIA) + JR FD_GEOM2 +FD_GEOM1: + LD A,(FCD_U1MEDIA) +FD_GEOM2: + RLCA ; TABLE IS 4 BYTE ENTRIES + RLCA ; A = A * 4 + LD HL,FCD_TBL ; HL = START OF TABLE + LD D,0 ; SET DE TO TABLE OFFSET + LD E,A + ADD HL,DE ; OFFSET BASED ON DESIRED MEDIA + CALL JPHL ; CALL THE TABLE ENTRY (SEE FCD_TBL) + ; HL NOW POINTS TO START OF DESIRED MEDIA INFO + LD A,(HL) ; GET TRACKS + INC HL ; POINT TO HEADS + LD D,(HL) ; GET HEADS + ;SET 7,D ; SET LBA CAPABILITY BIT (FUTURE) + INC HL ; POINT TO SECTORS + LD E,(HL) ; GET SECTORS + LD L,A ; L := TRACKS + LD H,0 ; HI WORD OF TRACKS IS ALWAYS ZERO + XOR A ; SIGNAL SUCCESS + RET ; DONE +; ; FD_INIT ; FD_INIT: diff --git a/Source/HBIOS/ide.asm b/Source/HBIOS/ide.asm index 3c21a0e2..2619eee3 100644 --- a/Source/HBIOS/ide.asm +++ b/Source/HBIOS/ide.asm @@ -236,9 +236,6 @@ IDE_INIT1: LD A,C ; UNIT NUM TO ACCUM PUSH BC ; SAVE LOOP CONTROL CALL IDE_INIT2 ; DISPLAY UNIT INFO -#IF (IDETRACE < 2) - CALL NZ,IDE_PRTSTAT ; IF ERROR, NOTIFY USER IF NOT DONE PREVIOUSLY -#ENDIF POP BC ; RESTORE LOOP CONTROL INC C ; INCREMENT UNIT INDEX DJNZ IDE_INIT1 ; LOOP UNTIL DONE @@ -315,11 +312,19 @@ IDE_DISPATCH: ; ; IDE_READ: +#IF (IDETRACE == 1) + LD HL,IDE_PRTERR ; SET UP IDE_PRTERR + PUSH HL ; ... TO FILTER ALL EXITS +#ENDIF JP IDE_RDSEC ; ; ; IDE_WRITE: +#IF (IDETRACE == 1) + LD HL,IDE_PRTERR ; SET UP IDE_PRTERR + PUSH HL ; ... TO FILTER ALL EXITS +#ENDIF JP IDE_WRSEC ; ; @@ -339,9 +344,13 @@ IDE_MEDIA: CALL IDE_RESET ; RESET ALL DEVICES ON BUS POP AF ; RECOVER UNIT SELECTION CALL IDE_SELUNIT ; RESELECT DESIRED UNIT +; IDE_DPTR(IDE_STAT) ; POINT TO UNIT STATUS LD A,(HL) ; GET STATUS OR A ; SET FLAGS +#IF (IDETRACE == 1) + CALL IDE_PRTERR ; PRINT ANY ERRORS +#ENDIF LD A,MID_HD ; ASSUME WE ARE OK RET Z ; RETURN IF GOOD INIT LD A,MID_NONE ; SIGNAL NO MEDA @@ -922,6 +931,12 @@ IDE_ERR2: OR A ; SET FLAGS RET ; +; +; +IDE_PRTERR: + RET Z ; DONE IF NO ERRORS + ; FALL THRU TO IDE_PRTSTAT +; ; PRINT STATUS STRING (STATUS NUM IN A) ; IDE_PRTSTAT: diff --git a/Source/HBIOS/md.asm b/Source/HBIOS/md.asm index b160c533..d1a0f7f5 100644 --- a/Source/HBIOS/md.asm +++ b/Source/HBIOS/md.asm @@ -6,13 +6,17 @@ MD_DISPATCH: LD A,B ; GET REQUESTED FUNCTION AND $0F - JR Z,MD_READ + JP Z,MD_READ DEC A - JR Z,MD_WRITE + JP Z,MD_WRITE DEC A - JR Z,MD_STATUS + JP Z,MD_STATUS DEC A - JR Z,MD_MEDIA + JP Z,MD_MEDIA + DEC A + JP Z,MD_CAP + DEC A + JP Z,MD_GEOM CALL PANIC ; ; @@ -47,6 +51,45 @@ MD_STATUS: ; ; ; +MD_CAP: + LD A,C ; DEVICE/UNIT IS IN C + AND $0F ; ISOLATE UNIT NUM + JR Z,MD_CAP0 ; UNIT 0 + DEC A ; TRY UNIT 1 + JR Z,MD_CAP1 ; UNIT 1 + CALL PANIC ; PANIC ON INVALID UNIT +MD_CAP0: + LD HL,(HCB + HCB_ROMBANKS) ; POINT TO ROM BANK COUNT + JR MD_CAP2 +MD_CAP1: + LD HL,(HCB + HCB_RAMBANKS) ; POINT TO RAM BANK COUNT +MD_CAP2: + LD H,(HL) ; H := # BANKS + LD E,64 ; # 512 BYTE BLOCKS / BANK + CALL MULT8 ; HL := TOTAL # 512 BYTE BLOCKS + LD DE,0 ; NEVER EXCEEDS 64K, ZERO HIGH WORD + XOR A + RET +; +; +; +MD_GEOM: + ; RAM/ROM DISKS ALLOW CHS STYLE ACCESS BY EMULATING + ; A DISK DEVICE WITH 1 HEAD AND 16 SECTORS / TRACK. + CALL MD_CAP ; HL := CAPACITY IN BLOCKS + EX DE,HL ; SWAP + LD D,1 | $80 ; HEADS / CYL := 1 BY DEFINITION, SET LBA CAPABILITY BIT + LD E,16 ; SECTORS / TRACK := 16 BY DEFINTION + LD B,4 ; PREPARE TO DIVIDE BY 16 +MD_GEOM1: + SRL H ; SHIFT H + RR L ; SHIFT L + DJNZ MD_GEOM1 ; DO 4 BITS TO DIVIDE BY 16 + XOR A ; SIGNAL SUCCESS + RET ; DONE +; +; +; MD_READ: CALL MD_IOSETUP ; SETUP FOR MEMORY COPY #IF (MDTRACE >= 2) diff --git a/Source/HBIOS/ppide.asm b/Source/HBIOS/ppide.asm index b0d418b0..83c1f0f9 100644 --- a/Source/HBIOS/ppide.asm +++ b/Source/HBIOS/ppide.asm @@ -227,9 +227,6 @@ PPIDE_INIT1: LD A,C ; UNIT NUM TO ACCUM PUSH BC ; SAVE LOOP CONTROL CALL PPIDE_INIT2 ; DISPLAY UNIT INFO -#IF (IDETRACE < 2) - CALL NZ,PPIDE_PRTSTAT ; IF ERROR, NOTIFY USER IF NOT DONE PREVIOUSLY -#ENDIF POP BC ; RESTORE LOOP CONTROL INC C ; INCREMENT UNIT INDEX DJNZ PPIDE_INIT1 ; LOOP UNTIL DONE @@ -306,11 +303,19 @@ PPIDE_DISPATCH: ; ; PPIDE_READ: +#IF (PPIDETRACE == 1) + LD HL,PPIDE_PRTERR ; SET UP PPIDE_PRTERR + PUSH HL ; ... TO FILTER ALL EXITS +#ENDIF JP PPIDE_RDSEC ; ; ; PPIDE_WRITE: +#IF (PPIDETRACE == 1) + LD HL,PPIDE_PRTERR ; SET UP PPIDE_PRTERR + PUSH HL ; ... TO FILTER ALL EXITS +#ENDIF JP PPIDE_WRSEC ; ; @@ -325,14 +330,22 @@ PPIDE_STATUS: ; PPIDE_MEDIA ; PPIDE_MEDIA: + ; THE ONLY WAY TO RESET AN IDE DEVICE IS TO RESET + ; THE ENTIRE INTERFACE. SO, TO HANDLE POSSIBLE HOT + ; SWAP WE DO THAT, THEN RESELECT THE DESIRED UNIT AND + ; CONTINUE. LD A,(PPIDE_UNIT) ; GET UNIT SELECTION PUSH AF ; SAVE UNIT SELECTION CALL PPIDE_RESET ; RESET ALL DEVICES ON BUS POP AF ; RECOVER UNIT SELECTION CALL PPIDE_SELUNIT ; RESELECT DESIRED UNIT +; PPIDE_DPTR(PPIDE_STAT) ; POINT TO UNIT STATUS LD A,(HL) ; GET STATUS OR A ; SET FLAGS +#IF (PPIDETRACE == 1) + CALL PPIDE_PRTERR ; PRINT ANY ERRORS +#ENDIF LD A,MID_HD ; ASSUME WE ARE OK RET Z ; RETURN IF GOOD INIT LD A,MID_NONE ; SIGNAL NO MEDA @@ -1030,6 +1043,12 @@ PPIDE_ERR2: OR A ; SET FLAGS RET ; +; +; +PPIDE_PRTERR: + RET Z ; DONE IF NO ERRORS + ; FALL THRU TO PPIDE_PRTSTAT +; ; PRINT STATUS STRING (STATUS NUM IN A) ; PPIDE_PRTSTAT: @@ -1131,7 +1150,7 @@ PPIDE_DSKY: IN A,(PPIDE_REG_CYLLO) ; GET DRIVE/HEAD LD (HL),A ; SAVE IN BUFFER INC HL ; INCREMENT BUFFER POINTER - IN A,(PPIDE_REG_SECT) ; GET DRIVE/HEAD + IN A,(PPIDE_REG_SECT) ; GET DRIVE/HEAD LD (HL),A ; SAVE IN BUFFER CALL DSKY_HEXOUT ; SEND IT TO DSKY RET diff --git a/Source/HBIOS/ppp.asm b/Source/HBIOS/ppp.asm index efa333cf..93b1a0c8 100644 --- a/Source/HBIOS/ppp.asm +++ b/Source/HBIOS/ppp.asm @@ -180,6 +180,10 @@ PPPSD_DISPATCH: JP Z,PPPSD_STATUS ; STATUS DEC A JP Z,PPPSD_MEDIA ; MEDIA ID + DEC A + JP Z,PPPSD_CAP + DEC A + JP Z,PPPSD_GEOM CALL PANIC ; ; SETUP FOR SUBSEQUENT ACCESS @@ -195,6 +199,28 @@ PPPSD_MEDIA: LD A,MID_HD ; SET MEDIA ID RET ; +; +; +PPPSD_CAP: + LD HL,PPPSD_BLKCNT ; GET BLOCK COUNT + CALL LD32 ; GET THE CURRENT CAPACITY DO DE:HL + LD BC,512 ; 512 BYTES PER BLOCK + XOR A ; SIGNAL SUCCESS + RET ; AND DONE +; +; +; +PPPSD_GEOM: + ; FOR LBA, WE SIMULATE CHS ACCESS USING 16 HEADS AND 16 SECTORS + ; RETURN HS:CC -> DE:HL, SET HIGH BIT OF D TO INDICATE LBA CAPABLE + CALL PPPSD_CAP ; GET TOTAL BLOCKS IN DE:HL, BLOCK SIZE TO BC + LD L,H ; DIVIDE BY 256 FOR # TRACKS + LD H,E ; ... HIGH BYTE DISCARDED, RESULT IN HL + LD D,16 | $80 ; HEADS / CYL = 16, SET LBA CAPABILITY BIT + LD E,16 ; SECTORS / TRACK = 16 + XOR A ; SIGNAL SUCCESS + RET +; ; SD CARD INITIALIZATION ; PPPSD_INIT: @@ -482,3 +508,5 @@ SENDCMD1: RET ; PPPSTR_TIMEOUT .TEXT "ParPortProp not responding!$" +; +PPPSD_BLKCNT .DB $00, $00, $20, $00 ; ASSUME 1GB (LITTLE ENDIAN DWORD) diff --git a/Source/HBIOS/prp.asm b/Source/HBIOS/prp.asm index 5dbb66d1..7a646d8e 100644 --- a/Source/HBIOS/prp.asm +++ b/Source/HBIOS/prp.asm @@ -3,17 +3,109 @@ ; PROPIO DRIVER ;================================================================================================== ; +; TODO: +; 1) ADD SUPPORT FOR DSKY +; ; GLOBAL PARPORTPROP INITIALIZATION ; PRP_INIT: +; PRTS("PRP: IO=0x$") LD A,PRPIOB CALL PRTHEXBYTE ; + CALL PRP_DETECT + LD DE,PRP_STR_NOXFC + JP NZ,WRITESTR + +; JR Z,PRP_INIT1 +; CALL WRITESTR +; OR $FF +; RET +; +;PRP_INIT1: +; + ; RESET INTERFACE, RETURN WITH NZ ON FAILURE +#IF (PRPSDTRACE >= 3) + CALL PRPSD_PRTPREFIX + PRTS(" RESET$") +#ENDIF +; + ; REQUEST INTERFACE RESET, RESULT IN A, Z/NZ SET + LD A,PRPSD_CMDRESET ; CLEAR ANY ERRORS ON PROPIO + CALL PRPSD_SNDCMD + RET NZ ; NZ SET, A HAS RESULT CODE +; + CALL PRPSD_GETVER + RET NZ +; + PRTS(" F/W=$") + LD HL,PRP_FWVER + CALL LD32 + LD A,D + CALL PRTHEXBYTE + CALL PC_PERIOD + LD A,E + CALL PRTHEXBYTE + CALL PC_PERIOD + LD B,H + LD C,L + CALL PRTHEXWORD +; + LD HL,PRP_FWVER + CALL LD32 + XOR A + CP D + JR NZ,PRP_INIT2 + CP E + JR NZ,PRP_INIT2 + LD DE,PRPSTR_UPGRADE + CALL WRITESTR +; +PRP_INIT2: + CALL PRPCON_INIT ; CONSOLE INITIALIZATION CALL PRPSD_INIT ; SD CARD INITIALIZATION - +; + RET +; +; +; +PRP_DETECT: + LD HL,(PRPSD_TIMEOUT) + PUSH HL + LD HL,$0100 + LD (PRPSD_TIMEOUT),HL + CALL PRP_DETECT1 + POP HL + LD (PRPSD_TIMEOUT),HL RET ; +PRP_DETECT1: + CALL PRPSD_WAITBSY + ;RET NZ ; IGNORE CURRENT RESULT + LD A,PRPSD_CMDRESET + OUT (PRPSD_DSKCMD),A + CALL PRPSD_WAITBSY + RET NZ + LD A,$A5 + OUT (PRPSD_DSKIO),A + LD A,$5A + OUT (PRPSD_DSKIO),A + LD A,PRPSD_CMDNOP + OUT (PRPSD_DSKCMD),A + CALL PRPSD_WAITBSY + RET NZ + IN A,(PRPSD_DSKIO) + CP $A5 + RET NZ + IN A,(PRPSD_DSKIO) + CP $5A + RET +; +; +; +PRP_STR_NOXFC .TEXT " NOT PRESENT$" +; ;================================================================================================== ; PROPIO CONSOLE DRIVER ;================================================================================================== @@ -29,6 +121,15 @@ PRPCON_DSPRDY .EQU $10 ; BIT SET WHEN DISPLAY BUF IS READY FOR A BYTE (BUF EMPT ; ; ; +PRPCON_INIT: +; + CALL NEWLINE + PRTS("PRPCON:$") +; + RET +; +; +; PRPCON_DISPATCH: LD A,B ; GET REQUESTED FUNCTION AND $0F ; ISOLATE SUB-FUNCTION @@ -69,9 +170,11 @@ PRPCON_OUT: CALL PRPCON_OST ; CHECK FOR OUTPUT READY JR Z,PRPCON_OUT ; WAIT IF NECESSARY LD A,E ; RECOVER THE CHAR TO WRITE - OUT (PRPCON_DATA),A ; WRITE THE CHAR TO PROPIO + OUT (PRPCON_DATA),A ; WRITE THE CHAR TO PROPIO RET ; +; +; PRPCON_OST: IN A,(PRPCON_STATUS) ; READ LINE STATUS REGISTER AND PRPCON_DSPRDY | PRPCON_BUSY ; ISOLATE DSPRDY AND BUSY @@ -87,87 +190,130 @@ PRPCON_OST1: ; PRPSD DISK DRIVER ;================================================================================================== ; +PRPSD_UNITCNT .EQU 1 +; ; IO PORT ADDRESSES ; PRPSD_DSKCMD .EQU PRPIOB + 2 PRPSD_DSKST .EQU PRPIOB + 2 PRPSD_DSKIO .EQU PRPIOB + 3 ; -PRPSD_CMDRESET .EQU 10H -PRPSD_CMDINIT .EQU 20H -PRPSD_CMDREAD .EQU 30H -PRPSD_CMDPREP .EQU 40H -PRPSD_CMDWRITE .EQU 50H +PRPSD_CMDNOP .EQU $00 +PRPSD_CMDSTAT .EQU $01 +PRPSD_CMDTYPE .EQU $02 +PRPSD_CMDCAP .EQU $03 +PRPSD_CMDCSD .EQU $04 +PRPSD_CMDRESET .EQU $10 +PRPSD_CMDINIT .EQU $20 +PRPSD_CMDREAD .EQU $30 +PRPSD_CMDPREP .EQU $40 +PRPSD_CMDWRITE .EQU $50 ; -PRPSD_STBUSY .EQU 80H -PRPSD_STERR .EQU 40H -PRPSD_STOVR .EQU 20H -PRPSD_STTO .EQU 10H +PRPSD_CMDVER .EQU $F0 ; +PRPSD_DSKSTBSY .EQU $80 +PRPSD_DSKSTERR .EQU $40 +PRPSD_DSKSTOVR .EQU $20 +PRPSD_DSKSTTO .EQU $10 ; +; SD CARD TYPE ; -PRPSD_DISPATCH: - LD A,B ; GET REQUESTED FUNCTION - AND $0F - JR Z,PRPSD_RD - DEC A - JR Z,PRPSD_WR - DEC A - JR Z,PRPSD_ST - DEC A - JR Z,PRPSD_MED - CALL PANIC +PRPSD_TYPEUNK .EQU 0 ; CARD TYPE UNKNOWN/UNDETERMINED +PRPSD_TYPEMMC .EQU 1 ; MULTIMEDIA CARD (MMC STANDARD) +PRPSD_TYPESDSC .EQU 2 ; SDSC CARD (V1) +PRPSD_TYPESDHC .EQU 3 ; SDHC CARD (V2) +PRPSD_TYPESDXC .EQU 4 ; SDXC CARD (V3) ; -PRPSD_RD: - JP PRPSD_READ -PRPSD_WR: - JP PRPSD_WRITE -PRPSD_ST: - JP PRPSD_STATUS -PRPSD_MED: - JP PRPSD_MEDIA +; SD CARD STATUS (PRPSD_STAT) ; -; PRPSD_MEDIA +PRPSD_STOK .EQU 0 ; OK +PRPSD_STINVUNIT .EQU -1 ; INVALID UNIT +PRPSD_STRDYTO .EQU -2 ; TIMEOUT WAITING FOR CARD TO BE READY +PRPSD_STINITTO .EQU -3 ; INITIALIZATOIN TIMEOUT +PRPSD_STCMDTO .EQU -4 ; TIMEOUT WAITING FOR COMMAND RESPONSE +PRPSD_STCMDERR .EQU -5 ; COMMAND ERROR OCCURRED (REF SD_RC) +PRPSD_STDATAERR .EQU -6 ; DATA ERROR OCCURRED (REF SD_TOK) +PRPSD_STDATATO .EQU -7 ; DATA TRANSFER TIMEOUT +PRPSD_STCRCERR .EQU -8 ; CRC ERROR ON RECEIVED DATA PACKET +PRPSD_STNOMEDIA .EQU -9 ; NO MEDIA IN CONNECTOR +PRPSD_STWRTPROT .EQU -10 ; ATTEMPT TO WRITE TO WRITE PROTECTED MEDIA ; -PRPSD_MEDIA: +; +; +PRPSD_INIT: ; REINITIALIZE THE CARD HERE CALL PRPSD_INITCARD - LD A,MID_NONE ; ASSUME FAILURE RET NZ - - ; ALL IS WELL, RETURN MEDIA IDENTIFIER - LD A,MID_HD ; SET MEDIA ID - RET ; + CALL PRPSD_PRTPREFIX ; + ; PRINT CARD TYPE + PRTS(" TYPE=$") + CALL PRPSD_PRTTYPE +; + ; PRINT STORAGE CAPACITY (BLOCK COUNT) + PRTS(" BLOCKS=0x$") ; PRINT FIELD LABEL + LD HL,PRPSD_BLKCNT ; POINT TO BLOCK COUNT + CALL LD32 ; GET THE CAPACITY VALUE + CALL PRTHEX32 ; PRINT HEX VALUE +; + ; PRINT STORAGE SIZE IN MB + PRTS(" SIZE=$") ; PRINT FIELD LABEL + LD B,11 ; 11 BIT SHIFT TO CONVERT BLOCKS --> MB + CALL SRL32 ; RIGHT SHIFT + CALL PRTDEC ; PRINT LOW WORD IN DECIMAL (HIGH WORD DISCARDED) + PRTS("MB$") ; PRINT SUFFIX ; -PRPSD_INIT: - ; MARK DRIVE NOT READY - ; HARDWARE INIT DEFERRED UNTIL DRIVE SELECT - XOR A - DEC A - LD (PRPSD_STAT),A RET ; ; ; -PRPSD_STATUS: - LD A,(PRPSD_STAT) ; GET THE CURRENT READY STATUS - OR A - RET +PRPSD_DISPATCH: + LD A,C ; DEVICE/UNIT TO A + AND $0F ; REMOVE DEVICE BITS LEAVING JUST UNIT ID + CALL PRPSD_SELUNIT ; SELECT DESIRED UNIT + RET NZ ; ABORT ON ERROR + LD A,B ; GET REQUESTED FUNCTION + AND $0F ; ISOLATE SUB-FUNCTION BITS + JP Z,PRPSD_READ + DEC A + JP Z,PRPSD_WRITE + DEC A + JP Z,PRPSD_STATUS + DEC A + JP Z,PRPSD_MEDIA + DEC A + JP Z,PRPSD_CAP + DEC A + JP Z,PRPSD_GEOM + CALL PANIC ; ; ; PRPSD_READ: +#IF (PRPSDTRACE == 1) + LD HL,PRPSD_PRTERR ; SET UP SD_PRTERR + PUSH HL ; ... TO FILTER ALL EXITS +#ENDIF + CALL PRPSD_CHKCARD ; CHECK / REINIT CARD AS NEEDED RET NZ ; BAIL OUT ON ERROR - - LD A,PRPSD_CMDRESET - CALL PRPSD_SNDCMD - RET NZ ; RETURN ON FAILURE, A = STATUS - + +#IF (PRPSDTRACE >= 3) + CALL PRPSD_PRTPREFIX +#ENDIF + +#IF (PRPSDTRACE >= 3) + PRTS(" READ$") +#ENDIF + + ;LD DE,$FFFF + ;LD HL,$FFFF + ;LD BC,HSTLBA + ;CALL ST32 + CALL PRPSD_SETBLK - + LD A,PRPSD_CMDREAD CALL PRPSD_SNDCMD RET NZ ; RETURN ON FAILURE, A = STATUS @@ -184,25 +330,38 @@ PRPSD_READ: ; ; PRPSD_WRITE: +#IF (PRPSDTRACE == 1) + LD HL,PRPSD_PRTERR ; SET UP SD_PRTERR + PUSH HL ; ... TO FILTER ALL EXITS +#ENDIF + CALL PRPSD_CHKCARD ; CHECK / REINIT CARD AS NEEDED RET NZ ; BAIL OUT ON ERROR - - LD A,PRPSD_CMDRESET - CALL PRPSD_SNDCMD - RET NZ ; RETURN ON FAILURE, A = STATUS - + +#IF (PRPSDTRACE >= 3) + CALL PRPSD_PRTPREFIX +#ENDIF + CALL PRPSD_SETBLK +#IF (PRPSDTRACE >= 3) + PRTS(" PREP$") +#ENDIF + LD A,PRPSD_CMDPREP CALL PRPSD_SNDCMD RET NZ ; RETURN ON FAILURE, A = STATUS - + LD C,PRPSD_DSKIO LD B,0 LD HL,(DIOBUF) OTIR OTIR +#IF (PRPSDTRACE >= 3) + PRTS(" WRITE$") +#ENDIF + LD A,PRPSD_CMDWRITE CALL PRPSD_SNDCMD RET NZ ; RETURN ON FAILURE, A = STATUS @@ -212,159 +371,542 @@ PRPSD_WRITE: ; ; ; +PRPSD_STATUS: + LD A,(PRPSD_STAT) ; GET THE CURRENT STATUS + OR A + RET +; +; PRPSD_MEDIA +; +PRPSD_MEDIA: + ; REINITIALIZE THE CARD HERE + CALL PRPSD_INITCARD +#IF (PRPSDTRACE == 1) + CALL PRPSD_PRTERR ; PRINT ANY ERRORS +#ENDIF + LD A,MID_HD ; ASSUME SUCCESS, SETUP MEDIA ID + RET Z ; RETURN IF GOOD INIT + LD A,MID_NONE ; SIGNAL NO MEDA + OR A ; SET FLAGS + RET ; AND RETURN +; +; +; +PRPSD_CAP: + LD HL,PRPSD_BLKCNT ; POINT TO BLOCK COUNT + CALL LD32 ; GET THE CURRENT CAPACITY TO DE:HL + LD BC,512 ; 512 BYTES PER BLOCK + XOR A ; SIGNAL SUCCESS + RET ; AND DONE +; +; +; +PRPSD_GEOM: + ; FOR LBA, WE SIMULATE CHS ACCESS USING 16 HEADS AND 16 SECTORS + ; RETURN HS:CC -> DE:HL, SET HIGH BIT OF D TO INDICATE LBA CAPABLE + CALL PRPSD_CAP ; GET TOTAL BLOCKS IN DE:HL, BLOCK SIZE TO BC + LD L,H ; DIVIDE BY 256 FOR # TRACKS + LD H,E ; ... HIGH BYTE DISCARDED, RESULT IN HL + LD D,16 | $80 ; HEADS / CYL = 16, SET LBA CAPABILITY BIT + LD E,16 ; SECTORS / TRACK = 16 + XOR A ; SIGNAL SUCCESS + RET +; +; +; +PRPSD_GETVER: +#IF (PRPSDTRACE >= 3) + CALL PRPSD_PRTPREFIX +#ENDIF +; +#IF (PRPSDTRACE >= 3) + PRTS(" PREP$") +#ENDIF +; + ; ZEROES BUFFER IN CASE F/W DOES NOT KNOW VER COMMAND + LD A,PRPSD_CMDPREP + CALL PRPSD_SNDCMD + RET NZ ; RETURN ON FAILURE, A = STATUS +; +#IF (PRPSDTRACE >= 3) + PRTS(" VER$") +#ENDIF + LD A,PRPSD_CMDVER + CALL PRPSD_SNDCMD + RET NZ + + LD C,PRPSD_DSKIO ; FROM PROPIO DISK PORT + LD B,4 ; 4 BYTES + LD HL,PRP_FWVER ; TO PRP_FWVER + INIR + +#IF (PRPSDTRACE >= 3) + CALL PC_SPACE + LD HL,PRP_FWVER + CALL LD32 + CALL PRTHEX32 +#ENDIF + XOR A + RET +; +; +; +PRPSD_GETTYPE: +#IF (PRPSDTRACE >= 3) + CALL PRPSD_PRTPREFIX +#ENDIF + +#IF (PRPSDTRACE >= 3) + PRTS(" TYPE$") +#ENDIF + LD A,PRPSD_CMDTYPE + CALL PRPSD_SNDCMD + RET NZ + + IN A,(PRPSD_DSKIO) + LD (PRPSD_CARDTYPE),A + +#IF (PRPSDTRACE >= 3) + CALL PC_SPACE + CALL PRTHEXBYTE +#ENDIF + + XOR A + RET +; +; +; +PRPSD_GETCAP: +#IF (PRPSDTRACE >= 3) + CALL PRPSD_PRTPREFIX +#ENDIF + +#IF (PRPSDTRACE >= 3) + PRTS(" CAP$") +#ENDIF + LD A,PRPSD_CMDCAP + CALL PRPSD_SNDCMD + RET NZ + + LD C,PRPSD_DSKIO ; FROM PROPIO DISK PORT + LD B,4 ; 4 BYTES + LD HL,PRPSD_BLKCNT ; TO PRPSD_BLKCNT + INIR + +#IF (PRPSDTRACE >= 3) + CALL PC_SPACE + LD HL,PRPSD_BLKCNT + CALL LD32 + CALL PRTHEX32 +#ENDIF + + XOR A + RET +; +; +; +PRPSD_GETCSD: +#IF (PRPSDTRACE >= 3) + CALL PRPSD_PRTPREFIX +#ENDIF + +#IF (PRPSDTRACE >= 3) + PRTS(" CSD$") +#ENDIF + LD A,PRPSD_CMDCSD + CALL PRPSD_SNDCMD + RET NZ + + LD C,PRPSD_DSKIO + LD B,16 + LD HL,PRPSD_CSDBUF + INIR + +#IF (PRPSDTRACE >= 3) + CALL PC_SPACE + LD DE,PRPSD_CSDBUF + LD A,16 + CALL PRTHEXBUF +#ENDIF + + XOR A + RET +; +; +; PRPSD_SNDCMD: - LD (PRPSD_CMD),A - OUT (PRPSD_DSKCMD),A - NOP ; SETTLE - NOP ; SETTLE - LD BC,0 -PRPSD_SNDCMD1: - IN A,(PRPSD_DSKST) - BIT 7,A - JR Z,PRPSD_SNDCMD2 ; RET WITH A = STATUS - LD E,A ; SAVE STATUS + LD (PRPSD_CMD),A ; SAVE INCOMING COMMAND + CALL PRPSD_WAITBSY ; WAIT FOR BUSY TO BE CLEAR + LD (PRPSD_DSKSTAT),A ; SAVE STATUS +#IF (PRPSDTRACE >= 3) + CALL PC_SPACE + CALL PRTHEXBYTE +#ENDIF + BIT 7,A ; STILL BUSY + JP NZ,PRPSD_ERRRDYTO ; HANDLE TIMEOUT + ;CALL PC_PERIOD + LD A,(PRPSD_CMD) ; RECOVER INCOMING COMMAND + OUT (PRPSD_DSKCMD),A ; SEND THE COMMAND + CALL PRPSD_WAITBSY ; WAIT FOR BUSY TO CLEAR (CMD COMPLETE) + LD (PRPSD_DSKSTAT),A ; SAVE STATUS +#IF (PRPSDTRACE >= 3) + CALL PC_SPACE + CALL PRTHEXBYTE +#ENDIF + OR A ; SET FLAGS + RET Z ; RETURN W/ NO ERRORS +; + BIT 7,A ; STILL BUSY + JP NZ,PRPSD_ERRRDYTO ; HANDLE TIMEOUT +; + ; ASSUMES A COMMAND ERROR AT THIS POINT + ; GET DETAIL ERROR CODE + LD C,PRPSD_DSKIO ; FROM PROPIO DISK PORT + LD B,4 ; 4 BYTES + LD HL,PRPSD_ERRCODE ; TO PRPSD_ERRCODE + INIR +#IF (PRPSDTRACE >= 3) + CALL PC_SPACE + LD HL,PRPSD_ERRCODE + CALL LD32 + CALL PRTHEX32 +#ENDIF + JP PRPSD_ERRCMD ; RETURN VIA ERROR HANDLER +; +; +; +PRPSD_WAITBSY: + LD BC,(PRPSD_TIMEOUT) +PRPSD_WAITBSY1: + IN A,(PRPSD_DSKST) ; GET STATUS + LD E,A ; SAVE IT IN E + BIT 7,A ; ISLOATE BUSY BIT + JR Z,PRPSD_WAITBSY2 ; DONE, JUMP TO HAPPY EXIT + CALL DELAY CALL DELAY DEC BC LD A,B OR C - JR NZ,PRPSD_SNDCMD1 - LD A,E ; RECOVER STATUS - OR PRPSD_STTO ; SET TIMEOUT BIT -PRPSD_SNDCMD2: - LD (PRPSD_STAT),A - JR PRPSD_PRT ; RET WITH A = STATUS + JR NZ,PRPSD_WAITBSY1 + ; TIMEOUT RETURN + LD A,E ; RECOVER LAST STATUS + OR A ; SET FLAGS + RET +; +PRPSD_WAITBSY2: +#IF (PRPSDTRACE >= 3) + ; DUMP LOOP COUNT + PUSH AF + CALL PC_SPACE + CALL PC_LBKT + OR A ; CLEAR CARRY + LD HL,(PRPSD_TIMEOUT) + SBC HL,BC + LD B,H + LD C,L + CALL PRTHEXWORD + CALL PC_RBKT + POP AF +#ENDIF + OR A ; SET FLAGS + RET ; AND RETURN WITH STATUS IN A +; +; TAKE ANY ACTIONS REQUIRED TO SELECT DESIRED PHYSICAL UNIT +; UNIT IS SPECIFIED IN A +; +PRPSD_SELUNIT: + CP PRPSD_UNITCNT ; CHECK VALIDITY (EXCEED UNIT COUNT?) + JP NC,PRPSD_INVUNIT ; HANDLE INVALID UNIT + XOR A ; SIGNAL SUCCESS + RET ; DONE ; ; ; PRPSD_INITCARD: + ; CLEAR ALL STATUS DATA + LD HL,PRPSD_UNITDATA + LD BC,PRPSD_UNITDATALEN + XOR A + CALL FILL +; ; RESET INTERFACE, RETURN WITH NZ ON FAILURE - LD A,PRPSD_CMDRESET +#IF (PRPSDTRACE >= 3) + CALL PRPSD_PRTPREFIX + PRTS(" RESET$") +#ENDIF + + ; REQUEST INTERFACE RESET, RESULT IN A, Z/NZ SET + LD A,PRPSD_CMDRESET ; CLEAR ANY ERRORS ON PROPIO CALL PRPSD_SNDCMD - RET NZ ; NZ SET, A HAS ERROR CODE - + RET NZ ; NZ SET, A HAS RESULT CODE +; + ; (RE)INITIALIZE THE CARD, RETURN WITH NZ ON FAILURE +#IF (PRPSDTRACE >= 3) + CALL PRPSD_PRTPREFIX + PRTS(" INIT$") +#ENDIF + ; REQUEST HARDWARE INIT, RESULT IN A, Z/NZ SET LD A,PRPSD_CMDINIT CALL PRPSD_SNDCMD - RET ; Z/NZ SET, A HAS RESULT CODE + RET NZ ; NZ SET, A HAS RESULT CODE + +#IF (PRPSDTRACE >= 3) + ; GET CSD IF DEBUGGING + CALL PRPSD_GETCSD + RET NZ +#ENDIF + + ; GET CARD TYPE + CALL PRPSD_GETTYPE + RET NZ + + ; GET CAPACITY + CALL PRPSD_GETCAP + RET NZ + + RET ; N/NZ SET, A HAS RESULT CODE ; ; CHECK THE SD CARD, ATTEMPT TO REINITIALIZE IF NEEDED ; PRPSD_CHKCARD: LD A,(PRPSD_STAT) ; GET STATUS OR A ; SET FLAGS - CALL NZ,PRPSD_INITCARD ; INIT CARD IF NOT READY - RET ; RETURN WITH STATUS IN A + RET Z ; IF ALL GOOD, DONE + JP NZ,PRPSD_INITCARD ; OTHERWISE, REINIT ; -; SEND INDEX OF BLOCK TO READ FROM SD CARD +; SEND INDEX OF BLOCK TO READ/WRITE FROM SD CARD ; 32 BIT VALUE (4 BYTES) -; NOTE THAT BYTES ARE SENT REVERSED, PROPELLER IS LITTLE ENDIAN ; PRPSD_SETBLK: - LD DE,PRPSD_BLK + 3 -; LD A,(HSTSEC) ; A = LSB OF OS SECTOR -; CALL PRPSD_SETBLK1 -; LD HL,(HSTTRK) ; GET OS TRACK VALUE -; LD A,L ; EXTRACT LSB -; CALL PRPSD_SETBLK1 -; LD A,H ; EXTRACT MSB -; CALL PRPSD_SETBLK1 -; XOR A ; A = 0, NOT USED -; CALL PRPSD_SETBLK1 - LD A,(HSTLBALO) ; LBA LOW LSB - CALL PRPSD_SETBLK1 - LD A,(HSTLBALO + 1) ; LBA LOW MSB - CALL PRPSD_SETBLK1 - LD A,(HSTLBAHI) ; LBA HIGH LSB - CALL PRPSD_SETBLK1 - LD A,(HSTLBAHI + 1) ; LBA HIGH MSB - CALL PRPSD_SETBLK1 - RET -PRPSD_SETBLK1: - OUT (PRPSD_DSKIO),A ; SEND IT - LD (DE),A - DEC DE - RET - -PRPSD_PRT: - BIT 6,A -#IF (PRPSDTRACE == 0) - RET -#ELSE -#IF (PRPSDTRACE == 1) - RET Z +#IF (PRPSDTRACE >= 3) + PRTS(" BLK$") #ENDIF - PUSH AF - CALL NEWLINE - CALL PC_LBKT - CALL PRTHEXWORD - CALL PC_RBKT - CALL PC_SPACE - LD DE,PRPSTR_PREFIX - CALL WRITESTR - CALL PC_SPACE - LD DE,PRPSTR_CMD - CALL WRITESTR - LD A,(PRPSD_CMD) - CALL PRTHEXBYTE - CP PRPSD_CMDREAD - CALL Z,PRPSD_PRTBLK - CP PRPSD_CMDWRITE - CALL Z,PRPSD_PRTBLK - CALL PC_SPACE - LD DE,PRPSTR_ARROW - CALL WRITESTR - CALL PC_SPACE - POP AF - PUSH AF - CALL PRTHEXBYTE - BIT 6,A - CALL NZ,PRPSD_PRTERR - POP AF - RET ; RET WITH A = STATUS -PRPSD_PRTBLK: + ; A NOP COMMAND IS A QUICK WAY TO ENSURE THE DISK BUFFER + ; POINTER ON THE PROPIO IS RESET TO ZERO + LD A,PRPSD_CMDNOP + OUT (PRPSD_DSKCMD),A ; SEND THE COMMAND (NO WAIT) + +#IF (PRPSDTRACE >= 3) CALL PC_SPACE - LD HL,PRPSD_BLK - LD B,4 -PRPSD_PRTBLK1: - LD A,(HL) - CALL PRTHEXBYTE - INC HL - DJNZ PRPSD_PRTBLK1 + LD HL,HSTLBA + CALL LD32 + CALL PRTHEX32 +#ENDIF + LD C,PRPSD_DSKIO ; SEND TO DISK I/O PORT + LD B,4 ; 4 BYTES + LD HL,HSTLBA ; OF LBA + OTIR + RET +; +;============================================================================= +; ERROR HANDLING AND DIAGNOSTICS +;============================================================================= +; +; ERROR HANDLERS +; +PRPSD_INVUNIT: + LD A,PRPSD_STINVUNIT + JR PRPSD_ERR2 ; SPECIAL CASE FOR INVALID UNIT +; +PRPSD_ERRRDYTO: + LD A,PRPSD_STRDYTO + JR PRPSD_ERR +; +PRPSD_ERRINITTO: + LD A,PRPSD_STINITTO + JR PRPSD_ERR +; +PRPSD_ERRCMDTO: + LD A,PRPSD_STCMDTO + JR PRPSD_ERR +; +PRPSD_ERRCMD: + LD A,PRPSD_STCMDERR + JR PRPSD_ERR +; +PRPSD_ERRDATA: + LD A,PRPSD_STDATAERR + JR PRPSD_ERR +; +PRPSD_ERRDATATO: + LD A,PRPSD_STDATATO + JR PRPSD_ERR +; +PRPSD_ERRCRC: + LD A,PRPSD_STCRCERR + JR PRPSD_ERR +; +PRPSD_NOMEDIA: + LD A,PRPSD_STNOMEDIA + JR PRPSD_ERR +; +PRPSD_WRTPROT: + LD A,PRPSD_STWRTPROT + JR PRPSD_ERR2 ; DO NOT UPDATE UNIT STATUS! +; +PRPSD_ERR: + LD (PRPSD_STAT),A ; UPDATE STATUS +PRPSD_ERR2: +#IF (PRPSDTRACE >= 2) + CALL PRPSD_PRTSTAT +#ENDIF + OR A ; SET FLAGS RET - +; +; +; PRPSD_PRTERR: - LD B,4 -PRPSD_PRTERR1: - IN A,(PRPSD_DSKIO) + RET Z ; DONE IF NO ERRORS + ; FALL THRU TO PRPSD_PRTSTAT +; +; PRINT STATUS STRING +; +PRPSD_PRTSTAT: PUSH AF - DJNZ PRPSD_PRTERR1 - CALL PC_SPACE - LD DE,PRPSTR_ERR + PUSH DE + PUSH HL + OR A + LD DE,PRPSD_STR_STOK + JR Z,PRPSD_PRTSTAT1 + INC A + LD DE,PRPSD_STR_STINVUNIT + JR Z,PRPSD_PRTSTAT1 ; INVALID UNIT IS SPECIAL CASE + INC A + LD DE,PRPSD_STR_STRDYTO + JR Z,PRPSD_PRTSTAT1 + INC A + LD DE,PRPSD_STR_STINITTO + JR Z,PRPSD_PRTSTAT1 + INC A + LD DE,PRPSD_STR_STCMDTO + JR Z,PRPSD_PRTSTAT1 + INC A + LD DE,PRPSD_STR_STCMDERR + JR Z,PRPSD_PRTSTAT1 + INC A + LD DE,PRPSD_STR_STDATAERR + JR Z,PRPSD_PRTSTAT1 + INC A + LD DE,PRPSD_STR_STDATATO + JR Z,PRPSD_PRTSTAT1 + INC A + LD DE,PRPSD_STR_STCRCERR + JR Z,PRPSD_PRTSTAT1 + INC A + LD DE,PRPSD_STR_STNOMEDIA + JR Z,PRPSD_PRTSTAT1 + INC A + LD DE,PRPSD_STR_STWRTPROT + JR Z,PRPSD_PRTSTAT1 + LD DE,PRPSD_STR_STUNK +PRPSD_PRTSTAT1: + CALL PRPSD_PRTPREFIX ; PRINT UNIT PREFIX + CALL PC_SPACE ; FORMATTING CALL WRITESTR - LD B,4 -PRPSD_PRTERR2: + LD A,(PRPSD_STAT) + CP PRPSD_STCMDERR + CALL Z,PRPSD_PRTSTAT2 + POP HL + POP DE POP AF + RET +PRPSD_PRTSTAT2: + CALL PC_SPACE + LD A,(PRPSD_DSKSTAT) CALL PRTHEXBYTE - DJNZ PRPSD_PRTERR2 + CALL PC_SPACE + JP PRPSD_PRTERRCODE RET -#ENDIF + ; ; ; -PRPSTR_PREFIX .TEXT "PRPDSK:$" -PRPSTR_CMD .TEXT "CMD=$" -;PRPSTR_RC .TEXT "RC=$" -PRPSTR_ARROW .TEXT "-->$" -PRPSTR_ERR .TEXT "ERR=$" -;PRPSTR_RCOK .TEXT "OK$" -;PRPSTR_RCRDYTO .TEXT "READY TIMEOUT$" +PRPSD_PRTERRCODE: + PUSH HL + PUSH DE + LD HL,PRPSD_ERRCODE + CALL LD32 + CALL PRTHEX32 + POP DE + POP HL + RET ; -;================================================================================================== -; PRPSD DISK DRIVER - DATA -;================================================================================================== +; PRINT DIAGNONSTIC PREFIX ; -PRPSD_STAT .DB 0 +PRPSD_PRTPREFIX: + CALL NEWLINE + PRTS("PRPSD0:$") + RET ; -PRPSD_CMD .DB 0 -PRPSD_BLK .DB 0, 0, 0, 0 +; PRINT THE CARD TYPE +; +PRPSD_PRTTYPE: + LD A,(PRPSD_CARDTYPE) + LD DE,PRPSD_STR_TYPEMMC + CP PRPSD_TYPEMMC + JR Z,PRPSD_INIT1 + LD DE,PRPSD_STR_TYPESDSC + CP PRPSD_TYPESDSC + JR Z,PRPSD_INIT1 + LD DE,PRPSD_STR_TYPESDHC + CP PRPSD_TYPESDHC + JR Z,PRPSD_INIT1 + LD DE,PRPSD_STR_TYPESDXC + CP PRPSD_TYPESDXC + JR Z,PRPSD_INIT1 + LD DE,PRPSD_STR_TYPEUNK +PRPSD_INIT1: + JP WRITESTR +; +;============================================================================= +; STRING DATA +;============================================================================= +; +PRPSD_STR_ARROW .TEXT " -->$" +PRPSD_STR_RC .TEXT " RC=$" +PRPSD_STR_TOK .TEXT " TOK=$" +PRPSD_STR_CSD .TEXT " CSD =$" +PRPSD_STR_CID .TEXT " CID =$" +PRPSD_STR_SCR .TEXT " SCR =$" +PRPSD_STR_SDTYPE .TEXT " SD CARD TYPE ID=$" +; +PRPSD_STR_STOK .TEXT "OK$" +PRPSD_STR_STINVUNIT .TEXT "INVALID UNIT$" +PRPSD_STR_STRDYTO .TEXT "READY TIMEOUT$" +PRPSD_STR_STINITTO .TEXT "INITIALIZATION TIMEOUT$" +PRPSD_STR_STCMDTO .TEXT "COMMAND TIMEOUT$" +PRPSD_STR_STCMDERR .TEXT "COMMAND ERROR$" +PRPSD_STR_STDATAERR .TEXT "DATA ERROR$" +PRPSD_STR_STDATATO .TEXT "DATA TIMEOUT$" +PRPSD_STR_STCRCERR .TEXT "CRC ERROR$" +PRPSD_STR_STNOMEDIA .TEXT "NO MEDIA$" +PRPSD_STR_STWRTPROT .TEXT "WRITE PROTECTED$" +PRPSD_STR_STUNK .TEXT "UNKNOWN$" +PRPSD_STR_TYPEUNK .TEXT "UNK$" +PRPSD_STR_TYPEMMC .TEXT "MMC$" +PRPSD_STR_TYPESDSC .TEXT "SDSC$" +PRPSD_STR_TYPESDHC .TEXT "SDHC$" +PRPSD_STR_TYPESDXC .TEXT "SDXC$" +PRPSTR_UPGRADE .TEXT " !!!UPGRADE REQUIRED!!!$" +; +;============================================================================= +; DATA STORAGE +;============================================================================= +; +PRPSD_UNITDATA: +PRPSD_STAT .DB 0 +PRPSD_DSKSTAT .DB 0 +PRPSD_ERRCODE .DB $00, $00, $00, $00 +PRPSD_CARDTYPE .DB 0 +PRPSD_BLKCNT .DB $00, $00, $00, $00 ; ASSUME 1GB (LITTLE ENDIAN DWORD) +PRPSD_CSDBUF .FILL 16,0 +PRPSD_UNITDATALEN .EQU $ - PRPSD_UNITDATA +; +PRPSD_CMD .DB 0 +PRPSD_BLK .DB 0, 0, 0, 0 +; +PRP_FWVER .DB $00, $00, $00, $00 ; MMNNBBB (M=MAJOR, N=MINOR, B=BUILD) +; +PRPSD_TIMEOUT .DW $0000 ; FIX: MAKE THIS CPU SPEED RELATIVE diff --git a/Source/HBIOS/sd.asm b/Source/HBIOS/sd.asm index b02eb868..f10f6e2d 100644 --- a/Source/HBIOS/sd.asm +++ b/Source/HBIOS/sd.asm @@ -453,6 +453,9 @@ SD_STATUS: SD_MEDIA: ; RE-INITIALIZE THE SD CARD TO ACCOMMODATE HOT SWAPPING CALL SD_INITCARD ; RE-INIT SELECTED UNIT +#IF (SDTRACE == 1) + CALL SD_PRTERR ; PRINT ANY ERRORS +#ENDIF LD A,MID_HD ; ASSUME SUCCESS, SETUP MEDIA ID RET Z ; RETURN IF GOOD INIT LD A,MID_NONE ; SIGNAL NO MEDA @@ -693,7 +696,7 @@ SD_INITCARD5: JP NC,SD_INITCARD8 ; HANDLE SDHC (V2) OR BETTER JR SD_INITCARD6 ; HANDLE MMC OR SDSC ; -; CAPACITY CALCULATION FOR MMC OR SDSD (V1) CARDS: +; CAPACITY CALCULATION FOR MMC OR SDSC (V1) CARDS: ; BYTES = (C_SIZE + 1) * 2^(2+C_SIZE_MULT+READ_BL_LEN) = (C_SIZE+1) << (2+C_SIZE_MULT+READ_BL_LEN) ; BLOCKS = BYTES / 512 = BYTES >> 9 ; @@ -815,6 +818,9 @@ SD_SECTIO3: ; CHECK THE SD CARD, ATTEMPT TO REINITIALIZE IF NEEDED ; SD_CHKCARD: + ; FIX: NEED TO CHECK FOR CARD DETECT HERE AND + ; HANDLE AS ERROR. + ; SD_DPTR(SD_STAT) ; HL = ADR OF STATUS, AF TRASHED LD A,(HL) ; GET CURRENT STATUS OR A ; SET FLAGS