From df74f73d5b0d0d34349627c47b058723ee4227a0 Mon Sep 17 00:00:00 2001 From: Wayne Warthen Date: Sat, 21 Nov 2015 13:16:23 -0800 Subject: [PATCH] PROPIO Driver Refactoring --- BuildCommon.cmd | 3 +- Clean.cmd | 1 + Hardware/Build.cmd | 4 + Hardware/Clean.cmd | 5 + Hardware/ParPortProp/ParPortProp.eeprom | Bin 32768 -> 0 bytes Hardware/ParPortProp/Spin/safe_spi.spin | 920 ------------------ Hardware/ParPortProp/TstPPP.com | Bin 2903 -> 0 bytes Hardware/Prop/Build.cmd | 18 + Hardware/Prop/Clean.cmd | 6 + .../Spin/E555_SPKEngine.spin | 0 .../Spin/FullDuplexSerial.spin | Bin .../Spin/FullDuplexSerialNull.spin | Bin .../{ParPortProp => Prop}/Spin/Keyboard.spin | Bin .../Spin/ParPortProp.spin | Bin 47384 -> 47682 bytes .../Spin/Parallax Serial Terminal Null.spin | Bin .../Spin/Parallax Serial Terminal.spin | Bin Hardware/{PropIO => Prop}/Spin/PropIO.spin | Bin 30874 -> 31130 bytes Hardware/{PropIO2 => Prop}/Spin/PropIO2.spin | Bin 30028 -> 32276 bytes .../{ParPortProp => Prop}/Spin/VGA_1024.spin | 16 +- .../Spin/VGA_HiRes_Text.spin | Bin Hardware/{PropIO2 => Prop}/Spin/safe_spi.spin | 73 +- Hardware/PropIO/PropIO.eeprom | Bin 32768 -> 0 bytes Hardware/PropIO/Spin/Keyboard.spin | Bin 60850 -> 0 bytes .../PropIO/Spin/Parallax Serial Terminal.spin | Bin 39544 -> 0 bytes Hardware/PropIO/Spin/VGA_1024.spin | 704 -------------- Hardware/PropIO/Spin/VGA_HiRes_Text.spin | Bin 54408 -> 0 bytes Hardware/PropIO/Spin/safe_spi.spin | 920 ------------------ Hardware/PropIO2/PropIO2.eeprom | Bin 32768 -> 0 bytes Hardware/PropIO2/Spin/E555_SPKEngine.spin | 1 - Hardware/PropIO2/Spin/Keyboard.spin | Bin 60850 -> 0 bytes .../Spin/Parallax Serial Terminal.spin | Bin 39544 -> 0 bytes Hardware/PropIO2/Spin/VGA_1024.spin | 704 -------------- Hardware/PropIO2/Spin/VGA_HiRes_Text.spin | Bin 54408 -> 0 bytes Hardware/ReadMe.txt | 8 +- Source/HBIOS/Config/mk4_std.asm | 2 +- Source/HBIOS/fd.asm | 71 +- Source/HBIOS/ide.asm | 21 +- Source/HBIOS/md.asm | 51 +- Source/HBIOS/ppide.asm | 27 +- Source/HBIOS/ppp.asm | 28 + Source/HBIOS/prp.asm | 892 +++++++++++++---- Source/HBIOS/sd.asm | 8 +- 42 files changed, 1009 insertions(+), 3474 deletions(-) create mode 100644 Hardware/Build.cmd create mode 100644 Hardware/Clean.cmd delete mode 100644 Hardware/ParPortProp/ParPortProp.eeprom delete mode 100644 Hardware/ParPortProp/Spin/safe_spi.spin delete mode 100644 Hardware/ParPortProp/TstPPP.com create mode 100644 Hardware/Prop/Build.cmd create mode 100644 Hardware/Prop/Clean.cmd rename Hardware/{ParPortProp => Prop}/Spin/E555_SPKEngine.spin (100%) rename Hardware/{ParPortProp => Prop}/Spin/FullDuplexSerial.spin (100%) rename Hardware/{ParPortProp => Prop}/Spin/FullDuplexSerialNull.spin (100%) rename Hardware/{ParPortProp => Prop}/Spin/Keyboard.spin (100%) rename Hardware/{ParPortProp => Prop}/Spin/ParPortProp.spin (96%) rename Hardware/{ParPortProp => Prop}/Spin/Parallax Serial Terminal Null.spin (100%) rename Hardware/{ParPortProp => Prop}/Spin/Parallax Serial Terminal.spin (100%) rename Hardware/{PropIO => Prop}/Spin/PropIO.spin (98%) rename Hardware/{PropIO2 => Prop}/Spin/PropIO2.spin (90%) rename Hardware/{ParPortProp => Prop}/Spin/VGA_1024.spin (91%) rename Hardware/{ParPortProp => Prop}/Spin/VGA_HiRes_Text.spin (100%) rename Hardware/{PropIO2 => Prop}/Spin/safe_spi.spin (90%) delete mode 100644 Hardware/PropIO/PropIO.eeprom delete mode 100644 Hardware/PropIO/Spin/Keyboard.spin delete mode 100644 Hardware/PropIO/Spin/Parallax Serial Terminal.spin delete mode 100644 Hardware/PropIO/Spin/VGA_1024.spin delete mode 100644 Hardware/PropIO/Spin/VGA_HiRes_Text.spin delete mode 100644 Hardware/PropIO/Spin/safe_spi.spin delete mode 100644 Hardware/PropIO2/PropIO2.eeprom delete mode 100644 Hardware/PropIO2/Spin/E555_SPKEngine.spin delete mode 100644 Hardware/PropIO2/Spin/Keyboard.spin delete mode 100644 Hardware/PropIO2/Spin/Parallax Serial Terminal.spin delete mode 100644 Hardware/PropIO2/Spin/VGA_1024.spin delete mode 100644 Hardware/PropIO2/Spin/VGA_HiRes_Text.spin 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 2d1b8ea4c162dece918948789554a46dcbe6d16c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 32768 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 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<cA)dcg6qjxl@g$AUF`^G<0caGokcX~}ZLa!n6}h|kEz08z z0>?SV@AFwOw0AOvhg4NxACKa+xQ%` zkD+CD+{S02Ekav^_Ehk;&12$ZD8jvG;b5SSc<`k5_xnoZuBV0{A?gm;7U#zms{Rsj z?;-^}*KGa|uCRrZAQ}eI$i2^tfkV9S0$u`nE&$@Vhs6^t{$2oolf^Fw@HA`teSw(o zg0;}8faW@EYH2*+fyB^ErvuIeZ2nVXj@u1-{P+AIgvSG%k7%8wU38SF+KRS4;GJpl zwp{!V(T6_{qJ1R(j%%Ta1>s&#T&3{atg@cCLgA~yI%>DT)jHZww)m%(e90+?GfoCp zgX@DIP_vMP8npGnYb_cw;)Ku(1kVuxE{uN>{}yCr;zu9NLT{cXSiJB_z=aHANc!MCs8|AgW4 zB%K#2k$xZ1p0#bppp^EyTs0_4705d5#pYgeLBNoQkt%zhx=w~>@H)xxgV`k;V&E97 zE!rFpWb7J+FHtj{+d7+TCyQ68g--ml?H%wgUgw-LbL-d2j%BDx50KmCBPsn2pz}I?{_L3__nieq1-bnKW*gRa7*lrV8Z=RMjh0U`duLCy}Zb zCY~NKOI00^qooO*2oLJDaid^P0GXfG3nz7xP`U}WP>yICGK}f*Lhu6Osr%L6*sV@{Lm}DP0)0jp_V52hyQ%6T3 zk`sk$35=b2ruSf&1>Na#rD~oo60p)AW)bQ^AT((frciE+j+s*R#8#kJ*QZTm$`t?| zI>aoWL*YbEcTQuC{?S4;t5nhM-NMA z%7A1WCL#&U<)7|r1;ph|m<9x^Xq3x(v5KZk|_G$R!im6I>g%10?8?mk`o#tiay>Dd!yfI zi2c#_hWOp+!wvEKQMMt5qf|p=qdxp|X2ZtwG(Jn)jb;7{i?7q7u$vHJ=H`ao@GjpC z`@v+P>~7m2(3a_H-JS)FHE4Fz_t6gK zFx+Y#aI3XN{&`~;d1Cor5=(YRQ}`YD(sm=vtSws&euM#(KSlaFzDV;gx2Q8MYQ9CC z^{5*@AE_Ks6j2KDJLFbq1 z{noJn|8KiF5jQs=P|Dh{m!vhO1w&y1TpGGnYx{Gm@4#f+WpdNy?d{#ZmXkCvmHo11Rmvun%$Kd^R3$znXHa}Nm6FxZ zaY>sd^N8H3L$W3(QBM!bZeFMPO)rU8P;lv?VYqc+U4+OtD>lOMWDLrvn~bzy*; z1yr@xO?+~ml?pdpA5d(vl`WDv7p-jJ=I~p)BFXRu$OH9COzyH4fUB5o?F?t%x3)zw wSJuW7g&%HX3w3>XxIEBLa+5FEaKUxowsD2C6>Z(&>`Yr{WK%Y;wau;u05J$xX8-^I delta 214 zcmX@~g=xkorVVn8j7F0WDrs)^V0@)6ZOLH9U;u5R7pu@~EdWZ#2HYdd!! YJ3mT(a+ICK5c6j1bI$Y&^HNM*=nNCJ{Y3)3@JdE3d9Nw!3-`y zGMOO}Xak53Vif>!GD9Xq2}31NqzI_80O*z?AU~5Kk0G6bmw^k6YZ+?cY-a}l&Fk6s z3Qu-X5}H_|Fgbx=jXwaWCm*O+fx(kOpTU1}AiphV8PM%|K!2D{F0>S#>}SETd6D#w F7yzT_G710y delta 108 zcmbRBnQ_)f#s!RwCX+w1$WK;a6p(jgNM%T3C}JpONCc9V3UKe diff --git a/Hardware/PropIO2/Spin/PropIO2.spin b/Hardware/Prop/Spin/PropIO2.spin similarity index 90% rename from Hardware/PropIO2/Spin/PropIO2.spin rename to Hardware/Prop/Spin/PropIO2.spin index 9c180f14171e8678943bfb2fb632f91869809971..172203706d9e1e83cba8792bf76f73308b0f255d 100644 GIT binary patch delta 1393 zcma)6OHUI~82yGflopD>P>On?2qL9S3ylGbB2O`h4O9$jx?pW;w@G7;S zG@^B$M)8fI2dAGE62C9a zd-+hXNG&VyL!nvB2K;VC|h<%t!+5f2u;HYyZhzsfE@%M|E$?3`Cb11BQ4eb+KcqHzKCBdJ_Auc5Dkvh zGJoW3G8t^bW~Ysh)#e?BHz!y}XV?!4rO7Auq8Kcta~wCIz$osEi#nk~G$yw32I(2< zTv!fVId*)CH>+A_X;wT*&8Xv=w!lB*R27SF$ibZ8OFau)!e{~q=gKeK-)sl>wrdl< zQ&-84J>~qYwD9y`JQQtU-v!;5mul2WC!nzta9^2F3((V z=B>dY4qeRPH^cd+a_Yb*=pH@bcZ0|65!`?fj2eZC@mD8=);vaLc(JQAeF|y}0;@fA zݺky-GG`nh21K{)l?)0D77RK-(ul!;!H~gZ zvLK^0P#w?aHbx(|$#xuan@@2ZVx64F|75a)5ZmN)`fQVr38ifQCa{ZZ@+N7$$&aLE zHkZkCF-co8m;p^N0GnkBCJn(PP-JqWk?`bqavYma$)_=IUZQ-Di(7%A254syLoq|a z=0?4E#>o?OSSBavvP>>8w3+N@AjS%onp|$64`n@+6`y>;pajZGbdv@=>WwMMu*Je4ZC!CwbT=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 af54217bc7a4742ff765134124f5cc42397d5b20..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 32768 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 G;C}-sqkG~2 diff --git a/Hardware/PropIO/Spin/Keyboard.spin b/Hardware/PropIO/Spin/Keyboard.spin deleted file mode 100644 index 29025a99689e5fc04d794a2e281e42ace8c1d4b4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 60850 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 PuT_ueUsCUa{ayYK!)rep 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 5b892316533d01d855cf1bf08be8a9513fc1775b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 54408 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, <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<%M>9TeoWUK4I{A3o*}`9P=L<^(i|`YUkUX9z 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 diff --git a/Hardware/PropIO2/Spin/E555_SPKEngine.spin b/Hardware/PropIO2/Spin/E555_SPKEngine.spin deleted file mode 100644 index 02e55e87..00000000 --- a/Hardware/PropIO2/Spin/E555_SPKEngine.spin +++ /dev/null @@ -1 +0,0 @@ -{{ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // E555 Speaker Engine // // Author: Kwabena W. Agyeman // Updated: 7/27/2010 // Designed For: P8X32A // Version: 1.1 // // Copyright (c) 2010 Kwabena W. Agyeman // See end of file for terms of use. // // Update History: // // v1.0 - Original release - 8/26/2009. // v1.1 - Added support for variable pin assignments - 7/27/2010. // // For each included copy of this object only one spin interpreter should access it at a time. // // Nyamekye, /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Speaker Circuit: // // SpeakerPinNumber --- Speaker Driver (Active High). // /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// }} PUB speakerFrequency(newFrequency, speakerPinNumber) '' 10 Stack Longs '' //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// '' // Changes the speaker frequency using the SPIN interpreter's counter modules. '' // '' // NewFrequency - The new frequency. Between 0 Hz and 80MHz @ 80MHz. -1 to reset the pin and counter modules. '' // SpeakerPinNumber - Pin to use to drive the speaker circuit. Between 0 and 31. '' //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// speakerSetup((newFrequency <> -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 29025a99689e5fc04d794a2e281e42ace8c1d4b4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 60850 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 PuT_ueUsCUa{ayYK!)rep 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 5b892316533d01d855cf1bf08be8a9513fc1775b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 54408 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 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