Browse Source

PROPIO Driver Refactoring

pull/3/head
Wayne Warthen 10 years ago
parent
commit
df74f73d5b
  1. 1
      BuildCommon.cmd
  2. 1
      Clean.cmd
  3. 4
      Hardware/Build.cmd
  4. 5
      Hardware/Clean.cmd
  5. BIN
      Hardware/ParPortProp/ParPortProp.eeprom
  6. 920
      Hardware/ParPortProp/Spin/safe_spi.spin
  7. BIN
      Hardware/ParPortProp/TstPPP.com
  8. 18
      Hardware/Prop/Build.cmd
  9. 6
      Hardware/Prop/Clean.cmd
  10. 0
      Hardware/Prop/Spin/E555_SPKEngine.spin
  11. 0
      Hardware/Prop/Spin/FullDuplexSerial.spin
  12. 0
      Hardware/Prop/Spin/FullDuplexSerialNull.spin
  13. 0
      Hardware/Prop/Spin/Keyboard.spin
  14. BIN
      Hardware/Prop/Spin/ParPortProp.spin
  15. 0
      Hardware/Prop/Spin/Parallax Serial Terminal Null.spin
  16. 0
      Hardware/Prop/Spin/Parallax Serial Terminal.spin
  17. BIN
      Hardware/Prop/Spin/PropIO.spin
  18. BIN
      Hardware/Prop/Spin/PropIO2.spin
  19. 14
      Hardware/Prop/Spin/VGA_1024.spin
  20. 0
      Hardware/Prop/Spin/VGA_HiRes_Text.spin
  21. 73
      Hardware/Prop/Spin/safe_spi.spin
  22. BIN
      Hardware/PropIO/PropIO.eeprom
  23. BIN
      Hardware/PropIO/Spin/Keyboard.spin
  24. BIN
      Hardware/PropIO/Spin/Parallax Serial Terminal.spin
  25. 704
      Hardware/PropIO/Spin/VGA_1024.spin
  26. BIN
      Hardware/PropIO/Spin/VGA_HiRes_Text.spin
  27. 920
      Hardware/PropIO/Spin/safe_spi.spin
  28. BIN
      Hardware/PropIO2/PropIO2.eeprom
  29. 1
      Hardware/PropIO2/Spin/E555_SPKEngine.spin
  30. BIN
      Hardware/PropIO2/Spin/Keyboard.spin
  31. BIN
      Hardware/PropIO2/Spin/Parallax Serial Terminal.spin
  32. 704
      Hardware/PropIO2/Spin/VGA_1024.spin
  33. BIN
      Hardware/PropIO2/Spin/VGA_HiRes_Text.spin
  34. 8
      Hardware/ReadMe.txt
  35. 2
      Source/HBIOS/Config/mk4_std.asm
  36. 71
      Source/HBIOS/fd.asm
  37. 21
      Source/HBIOS/ide.asm
  38. 51
      Source/HBIOS/md.asm
  39. 25
      Source/HBIOS/ppide.asm
  40. 28
      Source/HBIOS/ppp.asm
  41. 870
      Source/HBIOS/prp.asm
  42. 8
      Source/HBIOS/sd.asm

1
BuildCommon.cmd

@ -2,3 +2,4 @@
setlocal
pushd Source && call BuildCommon && popd
pushd Hardware && call Build && popd

1
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

4
Hardware/Build.cmd

@ -0,0 +1,4 @@
@echo off
setlocal
pushd Prop && call Build && popd

5
Hardware/Clean.cmd

@ -0,0 +1,5 @@
@echo off
setlocal
pushd Prop && call Clean && popd

BIN
Hardware/ParPortProp/ParPortProp.eeprom

Binary file not shown.

920
Hardware/ParPortProp/Spin/safe_spi.spin

@ -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 | (|<pinCLK) | maskDI
dira |= maskAll
' get the card in a ready state: set DI and CS high, send => 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<n> is the command sequense of CMD55-CMD<n>
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<<pin), and is controlled directly
maskAll long 0
adrShift long 9 ' will be 0 for SDHC, 9 for MMC & SD
bufAdr long 0 ' where in Hub RAM is the buffer to copy to/from?
sdAdr long 0 ' where on the SD card does it read/write?
writeMode long 0 ' the counter setup in NCO single ended, clocking data out on pinDI
'clockOutMode long 0 ' the counter setup in NCO single ended, driving the clock line on pinCLK
N_in8_500ms long 1_000_000 ' used for timeout checking in PASM
'readMode long 0
clockLineMode long 0
clockXferMode long %11111 << 26
const512 long 512
const1024 long 1024
incDest4 long 4 << 9
decDestNminus1 long (512 / 4 - 1) << 9
{=== Initialized PASM Variables ===}
seconds long 0
dtime long 0
idle_time long 0
idle_limit long 0
{=== Multiblock State Machine ===}
lastIndexPlus long -1 ' state handler will check against lastIndexPlus, which will not have been -1
lastCommand long 0 ' this will never be the last command.
{=== Debug Logging Pointers ===}
{
dbg_ptr long 0
dbg_end long 0
'}
{=== Assembly Scratch Variables ===}
ops_left res 1 ' used as a counter for bytes, words, longs, whatever (start w/ # byte clocks out)
readback res 1 ' all reading from the card goes through here
tmp1 res 1 ' this may get used in all subroutines...don't use except in lowest
user_request res 1 ' the main command variable, read in from Hub: "r"-read single, "w"-write single
user_cmd res 1 ' used internally to handle actual commands to be executed
user_idx res 1 ' the pointer to the Hub RAM where the data block is/goes
block_cmd res 1 ' one of the SD/MMC command codes, no app-specific allowed
buf_ptr res 1 ' moving pointer to the Hub RAM buffer
last_time res 1 ' tracking the timestamp
{{
496 longs is my total available space in the cog,
and I want 128 longs for eventual use as one 512-
byte buffer. This gives me a total of 368 longs
to use for umount, and a readblock and writeblock
for both Hub RAM and Cog buffers.
}}
speed_buf res 128 ' 512 bytes to be used for read-ahead / write-behind
'fit 467
FIT 496
'' 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.
}}

BIN
Hardware/ParPortProp/TstPPP.com

Binary file not shown.

18
Hardware/Prop/Build.cmd

@ -0,0 +1,18 @@
@echo off
setlocal
set TOOLS=../../Tools
set PATH=%TOOLS%\bst;%PATH%
call :bstc PropIO || goto :eof
call :bstc PropIO2 || goto :eof
call :bstc ParPortProp || goto :eof
goto :eof
:bstc
echo.
echo Building %1...
bstc Spin\%1 -e -l
goto :eof

6
Hardware/Prop/Clean.cmd

@ -0,0 +1,6 @@
@echo off
setlocal
if exist *.eeprom del *.eeprom /Q
if exist *.list del *.list /Q

0
Hardware/ParPortProp/Spin/E555_SPKEngine.spin → Hardware/Prop/Spin/E555_SPKEngine.spin

0
Hardware/ParPortProp/Spin/FullDuplexSerial.spin → Hardware/Prop/Spin/FullDuplexSerial.spin

0
Hardware/ParPortProp/Spin/FullDuplexSerialNull.spin → Hardware/Prop/Spin/FullDuplexSerialNull.spin

0
Hardware/ParPortProp/Spin/Keyboard.spin → Hardware/Prop/Spin/Keyboard.spin

BIN
Hardware/ParPortProp/Spin/ParPortProp.spin → Hardware/Prop/Spin/ParPortProp.spin

Binary file not shown.

0
Hardware/ParPortProp/Spin/Parallax Serial Terminal Null.spin → Hardware/Prop/Spin/Parallax Serial Terminal Null.spin

0
Hardware/ParPortProp/Spin/Parallax Serial Terminal.spin → Hardware/Prop/Spin/Parallax Serial Terminal.spin

BIN
Hardware/PropIO/Spin/PropIO.spin → Hardware/Prop/Spin/PropIO.spin

Binary file not shown.

BIN
Hardware/PropIO2/Spin/PropIO2.spin → Hardware/Prop/Spin/PropIO2.spin

Binary file not shown.

14
Hardware/ParPortProp/Spin/VGA_1024.spin → Hardware/Prop/Spin/VGA_1024.spin

@ -122,19 +122,19 @@ 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
PUB cls1(VerStr) | i
longfill(@screen[0], $20202020, chars / 4)
clrbtm(TURQUOISE)
inverse := 1
statprint(36,0, string(" N8VEM ParPortProp | RomWBW v0.92"))
'statprint(36,0, string(" N8VEM PropIO V2 | RomWBW v0.95"))
statprint(36, 0, VerStr)
inverse := 0
repeat i from 37 to (rows - 1)
statprint(37,0, string(" "))
statprint(38,0, string(" "))
statprint(39,0, string(" "))
{{
@ -152,7 +152,7 @@ PUB cls1(c,screencolor,pcport,ascii,CR) | i,x,y
yloc :=36
loc := xloc + yloc*cols
inverse := 1
str(string(" propIO V 0.91 "))
str(string(" "))
inverse := 0
str(string("Baud Rate: "))
i:= BR[6]
@ -215,7 +215,7 @@ PUB clsupdate(c,screencolor,PCPORT,ascii,CR) | i,x,y,locold
yloc :=36
loc := xloc + yloc*cols
inverse := 1
str(string(" propIO V 0.81 "))
str(string(" "))
inverse := 0
xloc := 0
yloc :=37

0
Hardware/ParPortProp/Spin/VGA_HiRes_Text.spin → Hardware/Prop/Spin/VGA_HiRes_Text.spin

73
Hardware/PropIO2/Spin/safe_spi.spin → Hardware/Prop/Spin/safe_spi.spin

@ -25,6 +25,9 @@ CON
ERR_3v3_NOT_SUPPORTED = -2
ERR_OCR_FAILED = -3
ERR_BLOCK_NOT_LONG_ALIGNED = -4
ERR_CRC_ONOFF_FAILED = -5
ERR_STATUS_FAILED = -6
ERR_CSD_FAILED = -7
'...
' These errors are for the assembly engine...they are negated inside, and need to be <= 511
ERR_ASM_NO_READ_TOKEN = 100
@ -58,14 +61,17 @@ CON
' 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
'}
'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

BIN
Hardware/PropIO/PropIO.eeprom

Binary file not shown.

BIN
Hardware/PropIO/Spin/Keyboard.spin

Binary file not shown.

BIN
Hardware/PropIO/Spin/Parallax Serial Terminal.spin

Binary file not shown.

704
Hardware/PropIO/Spin/VGA_1024.spin

@ -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

BIN
Hardware/PropIO/Spin/VGA_HiRes_Text.spin

Binary file not shown.

920
Hardware/PropIO/Spin/safe_spi.spin

@ -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 | (|<pinCLK) | maskDI
dira |= maskAll
' get the card in a ready state: set DI and CS high, send => 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<n> is the command sequense of CMD55-CMD<n>
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<<pin), and is controlled directly
maskAll long 0
adrShift long 9 ' will be 0 for SDHC, 9 for MMC & SD
bufAdr long 0 ' where in Hub RAM is the buffer to copy to/from?
sdAdr long 0 ' where on the SD card does it read/write?
writeMode long 0 ' the counter setup in NCO single ended, clocking data out on pinDI
'clockOutMode long 0 ' the counter setup in NCO single ended, driving the clock line on pinCLK
N_in8_500ms long 1_000_000 ' used for timeout checking in PASM
'readMode long 0
clockLineMode long 0
clockXferMode long %11111 << 26
const512 long 512
const1024 long 1024
incDest4 long 4 << 9
decDestNminus1 long (512 / 4 - 1) << 9
{=== Initialized PASM Variables ===}
seconds long 0
dtime long 0
idle_time long 0
idle_limit long 0
{=== Multiblock State Machine ===}
lastIndexPlus long -1 ' state handler will check against lastIndexPlus, which will not have been -1
lastCommand long 0 ' this will never be the last command.
{=== Debug Logging Pointers ===}
{
dbg_ptr long 0
dbg_end long 0
'}
{=== Assembly Scratch Variables ===}
ops_left res 1 ' used as a counter for bytes, words, longs, whatever (start w/ # byte clocks out)
readback res 1 ' all reading from the card goes through here
tmp1 res 1 ' this may get used in all subroutines...don't use except in lowest
user_request res 1 ' the main command variable, read in from Hub: "r"-read single, "w"-write single
user_cmd res 1 ' used internally to handle actual commands to be executed
user_idx res 1 ' the pointer to the Hub RAM where the data block is/goes
block_cmd res 1 ' one of the SD/MMC command codes, no app-specific allowed
buf_ptr res 1 ' moving pointer to the Hub RAM buffer
last_time res 1 ' tracking the timestamp
{{
496 longs is my total available space in the cog,
and I want 128 longs for eventual use as one 512-
byte buffer. This gives me a total of 368 longs
to use for umount, and a readblock and writeblock
for both Hub RAM and Cog buffers.
}}
speed_buf res 128 ' 512 bytes to be used for read-ahead / write-behind
'fit 467
FIT 496
'' 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.
}}

BIN
Hardware/PropIO2/PropIO2.eeprom

Binary file not shown.

1
Hardware/PropIO2/Spin/E555_SPKEngine.spin

@ -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. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// }}

BIN
Hardware/PropIO2/Spin/Keyboard.spin

Binary file not shown.

BIN
Hardware/PropIO2/Spin/Parallax Serial Terminal.spin

Binary file not shown.

704
Hardware/PropIO2/Spin/VGA_1024.spin

@ -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

BIN
Hardware/PropIO2/Spin/VGA_HiRes_Text.spin

Binary file not shown.

8
Hardware/ReadMe.txt

@ -7,8 +7,6 @@ Contents
VDU\vdu.rom: ROM image for VDU onboard EPROM
PropIO\PropIO.eeprom: PropIO firmware for use with RomWBW
PropIO2\PropIO2.eeprom: PropIO V2 firmware for use with RomWBW
ParPortProp\ParPortProp.eeprom: ParPortProp firmware for use with RomWBW
Prop\PropIO.eeprom: PropIO firmware for use with RomWBW
Prop\PropIO2.eeprom: PropIO V2 firmware for use with RomWBW
Prop\ParPortProp.eeprom: ParPortProp firmware for use with RomWBW

2
Source/HBIOS/Config/mk4_std.asm

@ -60,7 +60,7 @@ PPIDESLOW .EQU FALSE ; ADD DELAYS TO HELP PROBLEMATIC HARDWARE (TRY THIS IF PPI
;
SDENABLE .EQU TRUE ; TRUE FOR SD SUPPORT
SDMODE .EQU SDMODE_MK4 ; SDMODE_JUHA, SDMODE_CSIO, SDMODE_UART, SDMODE_PPI, SDMODE_DSD, SDMODE_MK4
SDTRACE .EQU 2 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF IDEENABLE = TRUE)
SDTRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF IDEENABLE = TRUE)
SDCSIOFAST .EQU TRUE ; TABLE-DRIVEN BIT INVERTER
;
PRPENABLE .EQU FALSE ; TRUE FOR PROPIO SD SUPPORT (FOR N8VEM PROPIO ONLY!)

71
Source/HBIOS/fd.asm

@ -372,24 +372,19 @@ FCT_COUNT .EQU (($ - FCT) / FCT_ENTSIZ) ; # ENTRIES IN TABLE
FD_DISPATCH:
LD A,B ; GET REQUESTED FUNCTION
AND $0F
JR Z,FD_RD
JP Z,FD_READ
DEC A
JR Z,FD_WR
JP Z,FD_WRITE
DEC A
JR Z,FD_ST
JP Z,FD_STATUS
DEC A
JR Z,FD_MED
JP Z,FD_MEDIA
DEC A
JP Z,FD_CAP
DEC A
JP Z,FD_GEOM
CALL PANIC
;
FD_RD:
JP FD_READ
FD_WR:
JP FD_WRITE
FD_ST:
JP FD_STATUS
FD_MED:
JP FD_MEDIA
;
; FD_MEDIA
;
FD_MEDIA:
@ -468,6 +463,56 @@ FD_MEDIA3:
#ENDIF
RET
;
;
;
FD_CAP:
CALL FD_GEOM ; GET GEOMETRY
; HL=TRACKS, D=HEADS, E=SECTORS
PUSH HL ; SAVE TRACK COUNT
LD H,D ; HEADS COUNT TO H
RES 7,H ; MAKE SURE LBA CAPABILITY BIT IS CLEARED
CALL MULT8 ; HL := H * E FOR SECTORS / CYL
POP DE ; RECOVER TRACKS, E == TRACK COUNT
LD H,L ; MOVE WORKING COUNT L --> H
CALL MULT8 ; HL := H * E FOR TOTAL SECTORS
LD DE,0 ; HI WORD ALWAYS ZERO
XOR A ; SIGNAL SUCCESS
RET ; DONE
;
;
;
FD_GEOM:
LD A,C ; GET DEVICE/UNIT
OR $0F ; ISOLATE UNIT
JR Z,FD_GEOM0 ; UNIT 0
DEC A ; NOPE, TRY UNIT 1
JR Z,FD_GEOM1 ; UNIT 1
CALL PANIC ; INVALID UNIT
FD_GEOM0:
LD A,(FCD_U0MEDIA)
JR FD_GEOM2
FD_GEOM1:
LD A,(FCD_U1MEDIA)
FD_GEOM2:
RLCA ; TABLE IS 4 BYTE ENTRIES
RLCA ; A = A * 4
LD HL,FCD_TBL ; HL = START OF TABLE
LD D,0 ; SET DE TO TABLE OFFSET
LD E,A
ADD HL,DE ; OFFSET BASED ON DESIRED MEDIA
CALL JPHL ; CALL THE TABLE ENTRY (SEE FCD_TBL)
; HL NOW POINTS TO START OF DESIRED MEDIA INFO
LD A,(HL) ; GET TRACKS
INC HL ; POINT TO HEADS
LD D,(HL) ; GET HEADS
;SET 7,D ; SET LBA CAPABILITY BIT (FUTURE)
INC HL ; POINT TO SECTORS
LD E,(HL) ; GET SECTORS
LD L,A ; L := TRACKS
LD H,0 ; HI WORD OF TRACKS IS ALWAYS ZERO
XOR A ; SIGNAL SUCCESS
RET ; DONE
;
; FD_INIT
;
FD_INIT:

21
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:

51
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)

25
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:

28
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)

870
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 PRPSD_INIT ; SD CARD INITIALIZATION
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
@ -72,6 +173,8 @@ PRPCON_OUT:
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,84 +190,127 @@ 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
@ -184,15 +330,24 @@ 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
@ -203,6 +358,10 @@ PRPSD_WRITE:
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_PRTPREFIX:
CALL NEWLINE
PRTS("PRPSD0:$")
RET
;
; 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

8
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

Loading…
Cancel
Save