370 lines
11 KiB
Plaintext
370 lines
11 KiB
Plaintext
{
|
|
_clkfreq = 96_000_000 ' Hybrid
|
|
_clkmode = xtal1 + pll16x
|
|
|
|
tvPins = 24
|
|
kbPins = 12
|
|
sdPins = 8
|
|
}
|
|
_clkfreq = 80_000_000 ' Hydra
|
|
_clkmode = xtal1 + pll8x
|
|
|
|
tvPins = 24
|
|
kbPins = 13
|
|
sdPins = 16
|
|
{
|
|
Simple command line
|
|
|
|
2009
|
|
April
|
|
15 Adding file transfer to/from PC via serial
|
|
16 0.02
|
|
SendFile bugfix (while blksize == 1024)
|
|
Tries to run .bin before .eep now.
|
|
June
|
|
4 Changing name from cl to sphinx. Converting to use sxfs, sxtv.
|
|
15 sxkb; adding c and cl commands
|
|
23 Corrected clock mode calculation.
|
|
2010
|
|
Feb
|
|
25 New version number
|
|
}
|
|
|
|
obj
|
|
kb: "sxkb"
|
|
term: "sxtv"
|
|
sxfs: "sxfs"
|
|
f: "sxfile"
|
|
ser: "fdserial"
|
|
|
|
con
|
|
SXTVRENDEZVOUS = $8000 - 4
|
|
SXKBRENDEZVOUS = SXTVRENDEZVOUS - 4
|
|
SDSPIRENDEZVOUS = SXKBRENDEZVOUS - 3 * 4
|
|
SXFS2RENDEZVOUS = SDSPIRENDEZVOUS - 4 * 4 ' four rendezvous variables
|
|
SXFSRENDEZVOUS = SXFS2RENDEZVOUS - 4 * 4 ' four rendezvous variables
|
|
METADATABUFFER = SXFSRENDEZVOUS - 512
|
|
|
|
_free = ($8000 - METADATABUFFER) / 4
|
|
|
|
pub Main | err, p
|
|
if term.start( tvPins, SXTVRENDEZVOUS )
|
|
term.str( string("============= Sphinx 100225 ============", 13) )
|
|
term.str( string("video @ pin ") )
|
|
term.dec( tvPins )
|
|
term.str( string(13, "keyboard @ pin ") )
|
|
term.dec( kbPins )
|
|
term.str( string(13, "SD @ pin ") )
|
|
term.dec( sdPins )
|
|
term.out( 13 )
|
|
sxfs.start( sdPins )
|
|
kb.start( kbPins )
|
|
|
|
repeat
|
|
if ina[31] ' USB cable connected?
|
|
ser.start( 31, 30, %0000, 19200 )
|
|
f.Close
|
|
err := \DoIt
|
|
if err
|
|
if err > 0
|
|
term.str( err )
|
|
else
|
|
term.str( string("Error ") )
|
|
term.dec( err )
|
|
term.out( 13 )
|
|
else
|
|
term.str( string("Normal exit") ) ' This never happens
|
|
|
|
pri DoIt | ch
|
|
term.out( ">" )
|
|
term.out( "_" )
|
|
term.out( 8 )
|
|
repeat
|
|
if kb.peekkey
|
|
EditCmdLine
|
|
Execute
|
|
term.out( ">" )
|
|
term.out( "_" )
|
|
term.out( 8 )
|
|
if (ch := ser.rxcheck) <> -1
|
|
term.out( 8 )
|
|
FileTransfer( ch )
|
|
term.out( ">" )
|
|
term.out( "_" )
|
|
term.out( 8 )
|
|
|
|
con
|
|
MAXCMDLINELENGTH = 78 ' some arbitray limit.
|
|
CR = $0d
|
|
BKSP = $c8
|
|
|
|
var
|
|
byte cmdLine[MAXCMDLINELENGTH+1] ' +1 for null terminator
|
|
long cmdLineLength
|
|
|
|
pri EditCmdLine | key
|
|
cmdLineLength~ ' cursor is always at end of command line
|
|
|
|
repeat
|
|
case key := kb.key
|
|
$20..$7f:
|
|
if cmdLineLength < MAXCMDLINELENGTH
|
|
cmdLine[ cmdLineLength++ ] := key
|
|
term.out( key )
|
|
term.out( "_" )
|
|
term.out( 8 )
|
|
CR:
|
|
term.out( " " )
|
|
term.out( 13 )
|
|
cmdLine[ cmdLineLength ]~
|
|
return true
|
|
BKSP:
|
|
if cmdLineLength
|
|
--cmdLineLength
|
|
term.out( " " )
|
|
term.out( 8 )
|
|
term.out( 8 )
|
|
term.out( "_" )
|
|
term.out( 8 )
|
|
|
|
pri FileTransfer( cmd ) | ch, i
|
|
if cmd <> "G" and cmd <> "P"
|
|
term.out( cmd )
|
|
abort string(" -- unrecognized command from PC")
|
|
i~
|
|
repeat
|
|
ch := RxSerByte
|
|
if i => FILENAMEBUFFERSIZE
|
|
abort string("Filename too long")
|
|
filename[i++] := ch
|
|
while ch
|
|
|
|
if cmd == "G"
|
|
term.str( string("sending ") )
|
|
term.str( @filename )
|
|
term.out( 13 )
|
|
SendFileToPC
|
|
else
|
|
term.str( string("receiving ") )
|
|
term.str( @filename )
|
|
term.out( 13 )
|
|
ReceiveFileFromPC
|
|
|
|
pri SendFileToPC | blksize, i, chksum, b, n
|
|
if f.Open( @filename, "R" ) <> 0
|
|
term.str( @filename )
|
|
abort string(" -- can't open file for reading")
|
|
TxSerByte( "A" ) ' ack
|
|
|
|
n~
|
|
repeat
|
|
blksize := f.Read( @buffer, 1024 )
|
|
if blksize == -1
|
|
blksize~
|
|
TxSerByte( blksize.byte[0] )
|
|
TxSerByte( blksize.byte[1] )
|
|
i~
|
|
chksum~
|
|
repeat blksize
|
|
b := buffer[i++]
|
|
chksum += b
|
|
TxSerByte( b )
|
|
n += blksize
|
|
if chksum & $ff <> RxSerByte
|
|
abort string("Checksum error")
|
|
while blksize == 1024
|
|
f.Close
|
|
term.dec( n )
|
|
term.str( string(" bytes sent", 13) )
|
|
|
|
pri ReceiveFileFromPC | blksize, i, chksum, b, n
|
|
if f.Open( @filename, "W" ) <> 0
|
|
term.str( @filename )
|
|
abort string(" -- can't open file for writing")
|
|
TxSerByte( "A" ) ' ack
|
|
|
|
n~
|
|
repeat
|
|
blksize~
|
|
blksize.byte[0] := RxSerByte
|
|
blksize.byte[1] := RxSerByte
|
|
if blksize > 1024
|
|
abort string("Block size > 1024")
|
|
i~
|
|
chksum~
|
|
repeat blksize
|
|
b := RxSerByte
|
|
buffer[i++] := b
|
|
chksum += b
|
|
n += blksize
|
|
f.Write( @buffer, blksize )
|
|
TxSerByte( chksum )
|
|
while blksize == 1024
|
|
f.Close
|
|
term.dec( n )
|
|
term.str( string(" bytes received", 13) )
|
|
|
|
pri RxSerByte : b
|
|
' ser.rx with timeout
|
|
b := ser.rxtime( TIMEOUT )
|
|
if b == -1
|
|
abort string("RxSerByte timed out")
|
|
|
|
pri TxSerByte( b )
|
|
' just for symmetry with RxSerByte
|
|
ser.tx( b )
|
|
|
|
con
|
|
TIMEOUT = 500
|
|
|
|
var
|
|
byte buffer[1024]
|
|
|
|
pri Execute | n, p, q, run, c
|
|
c~
|
|
ifnot n := ParseCmdLine
|
|
return
|
|
p := @cmdLine
|
|
ToUpper(p)
|
|
|
|
if run := strcomp( @cmdLine, string("RUN") )
|
|
--n
|
|
p += strsize(p) + 1
|
|
elseif strcomp( @cmdLine, string("C") )
|
|
c := 1
|
|
--n
|
|
p += strsize(p) + 1 ' command arg1 arg2...
|
|
elseif strcomp( @cmdLine, string("CL") ) ' run command arg1 arg2...
|
|
c := 2 ' c arg1 arg2...
|
|
--n ' cl arg1 arg2...
|
|
p += strsize(p) + 1
|
|
|
|
ifnot n
|
|
abort string("No file specified")
|
|
|
|
f.Open( string("args.d8a"), "W" ) ' write args
|
|
if c == 0
|
|
q := p + strsize(p) + 1 ' for run and plain command, skip first arg (command name)
|
|
--n
|
|
f.Write( @n, 1 )
|
|
repeat n
|
|
f.Write( q, strsize(q) + 1 )
|
|
q += strsize(q) + 1
|
|
else ' for c and cl,
|
|
++n ' add extra arg (/c or /l)
|
|
f.Write( @n, 1 )
|
|
repeat n-1
|
|
f.Write( p, strsize(p) + 1 )
|
|
p += strsize(p) + 1
|
|
if c == 1
|
|
f.Write( string("/c"), 3 )
|
|
else
|
|
f.Write( string("/l"), 3 )
|
|
|
|
n~
|
|
f.Write( @n, 1 ) ' final terminating null
|
|
f.Close
|
|
|
|
if c
|
|
if f.Open( string("lex.bin"), "R" ) <> 0
|
|
abort string("lex.bin not found")
|
|
ser.stop
|
|
f.Execute( 0 )
|
|
|
|
|
|
if EndsWith( p, string(".BIN") ) or EndsWith( p, string(".EEP") )
|
|
if f.Open( p, "R" ) <> 0
|
|
term.str( p )
|
|
abort string(" -- not found")
|
|
else
|
|
if strsize(p) > MAXFILENAMELENGTH - 4
|
|
term.str( p )
|
|
abort string(" -- filename too long")
|
|
bytemove( @filename, p, strsize(p) + 1 )
|
|
bytemove( @filename + strsize(p), string(".BIN"), 5 )
|
|
if f.Open( @filename, "R" ) <> 0
|
|
bytemove( @filename + strsize(p), string(".EEP"), 5 )
|
|
if f.Open( @filename, "R" ) <> 0
|
|
term.str( p )
|
|
abort string(" -- no .bin or .eep found")
|
|
ser.stop
|
|
f.Execute( run )
|
|
|
|
pri ToUpper( p )
|
|
repeat while byte[p]
|
|
if "a" =< byte[p] and byte[p] =< "z"
|
|
byte[p] += "A" - "a"
|
|
++p
|
|
|
|
pri EndsWith( p, s )
|
|
if strsize(p) < strsize(s)
|
|
return false
|
|
p += strsize(p) - strsize(s)
|
|
repeat while byte[p]
|
|
if byte[p++] <> byte[s++]
|
|
return false
|
|
return true
|
|
|
|
con
|
|
MAXFILENAMELENGTH = 12 ' 8 + . + 3
|
|
FILENAMEBUFFERSIZE = MAXFILENAMELENGTH + 1 ' 8 + . + 3 + null
|
|
CMDNAMEBUFFERSIZE = 9 ' 8 + null
|
|
|
|
var
|
|
byte filename[MAXFILENAMELENGTH+1] ' 8 + . + 3 + null
|
|
|
|
pri ParseCmdLine : n | pSrc, pDst, state
|
|
{{
|
|
Converts cmdLine from " ab de fg \" to "ab\de\fg\" ('\' = null).
|
|
Returns # of "words".
|
|
}}
|
|
{
|
|
state whitespace null other char
|
|
0 ++pSrc; append \0; quit append char; => 1
|
|
1 append \0; ++n; => 0 append \0; ++n; quit append char;
|
|
}
|
|
pSrc := @cmdLine
|
|
pDst := @cmdLine
|
|
state~
|
|
repeat
|
|
if state == 0
|
|
if byte[pSrc] == " "
|
|
++pSrc
|
|
elseif byte[pSrc] == 0
|
|
byte[pDst++]~
|
|
quit
|
|
else
|
|
byte[pDst++] := byte[pSrc++]
|
|
state := 1
|
|
elseif state == 1
|
|
if byte[pSrc] == " "
|
|
++pSrc
|
|
byte[pDst++]~
|
|
++n
|
|
state~
|
|
elseif byte[pSrc] == 0
|
|
byte[pDst++]~
|
|
++n
|
|
quit
|
|
else
|
|
byte[pDst++] := byte[pSrc++]
|
|
|
|
{{
|
|
Copyright (c) 2009 Michael Park
|
|
+------------------------------------------------------------------------------------------------------------------------------+
|
|
| 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. |
|
|
+------------------------------------------------------------------------------------------------------------------------------+
|
|
}}
|
|
|