mirror of https://github.com/wwarthen/RomWBW.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
809 lines
47 KiB
809 lines
47 KiB
{{
|
|
|
|
************************************
|
|
* ParPortProp for RomWBW *
|
|
* Interface to N8VEM ParPortProp *
|
|
* Version 0.92 *
|
|
* August 10, 2012 *
|
|
************************************
|
|
|
|
Wayne Warthen
|
|
wwarthen@gmail.com
|
|
|
|
Substantially derived from work by:
|
|
|
|
David Mehaffy (yoda)
|
|
|
|
Credits:
|
|
|
|
Andrew Lynch (lynchaj) for creating the N8VEM
|
|
Vince Briel (vbriel) for the PockeTerm with which a lot of code is shared here
|
|
Jeff Ledger (oldbitcollector) for base terminal code
|
|
Ray Rodrick (cluso99) for the TriBladeProp that shares some of these ideas
|
|
for using the CPM to SD
|
|
|
|
ToDo:
|
|
|
|
Updates:
|
|
|
|
}}
|
|
|
|
CON
|
|
_CLKMODE = XTAL1 + PLL16X
|
|
_XINFREQ = 5_000_000
|
|
|
|
SLEEP = 60 * 5 ' Screen saver timeout in seconds
|
|
|
|
SPK_VOL = 75
|
|
|
|
SPK_MAXFRQ = 1_200
|
|
SPK_MINFRQ = 200
|
|
|
|
VGA_BASE = 16 ' VGA Video pins 16-23 (??)
|
|
KBD_BASE = 14 ' PS/2 Keyboard pins 14-15 (DATA, CLK)
|
|
SD_BASE = 24 ' SD Card pins 24-27 (DO, CLK, DI, CS)
|
|
SPK_BASE = 13 ' Speaker pin
|
|
|
|
'' Terminal Colors
|
|
TURQUOISE = $29
|
|
BLUE = $27
|
|
BABYBLUE = $95
|
|
RED = $C1
|
|
GREEN = $99
|
|
GOLDBROWN = $A2
|
|
AMBERDARK = $E2
|
|
LAVENDER = $A5
|
|
WHITE = $FF
|
|
HOTPINK = $C9
|
|
GOLD = $D9
|
|
PINK = $C5
|
|
|
|
PPI_CMD = $0100 ' pin 8, PC0, active ???
|
|
PPI_STB = $0200 ' pin 9, PC4, active low
|
|
PPI_IBF = $0400 ' pin 10, PC5, active high
|
|
PPI_ACK = $0800 ' pin 11, PC6, active low
|
|
PPI_OBF = $1000 ' pin 12, PC7, active low
|
|
|
|
PPI_DIRRD = PPI_STB + PPI_ACK
|
|
PPI_DIRWR = PPI_STB + PPI_ACK + $FF
|
|
|
|
FUNC_PUTBYTE = $10 ' Buf[0] -> PPI (one byte)
|
|
FUNC_GETBYTE = $11 ' PPI -> Buf[0] (one byte)
|
|
FUNC_PUTBUF = $20 ' Buf -> PPI (arbitrary buffer)
|
|
FUNC_GETBUF = $21 ' PPI -> Buf (arbitrary buffer)
|
|
|
|
CMD_NOP = $00 ' Do nothing
|
|
CMD_ECHOBYTE = $01 ' Receive a byte, invert it, send it back
|
|
CMD_ECHOBUF = $02 ' Receive 512 byte buffer, send it back
|
|
|
|
CMD_DSKRES = $10 ' Restart SD card support
|
|
CMD_DSKSTAT = $11 ' Send last SD card status (4 bytes)
|
|
CMD_DSKPUT = $12 ' PPI -> sector buffer -> PPP
|
|
CMD_DSKGET = $13 ' PPP -> sector buffer -> PPI
|
|
CMD_DSKRD = $14 ' Read sctor from SD card into PPP buffer, return 1 byte status
|
|
CMD_DSKWR = $15 ' Write sector to SD card from PPP buffer, return 1 byte status
|
|
|
|
CMD_VIDOUT = $20 ' Write a byte to the terminal emulator
|
|
|
|
CMD_KBDSTAT = $30 ' Return a byte with number of characters in buffer
|
|
CMD_KBDRD = $31 ' Return a character, wait if necessary
|
|
|
|
CMD_SPKTONE = $40 ' Emit speaker tone at specified frequency and duration
|
|
|
|
CMD_SIOINIT = $50 ' Reset serial port and establish a new baud rate (4 byte baud rate)
|
|
CMD_SIORX = $51 ' Receive a byte in from serial port
|
|
CMD_SIOTX = $52 ' Transmit a byte out of the serial port
|
|
CMD_SIORXST = $53 ' Serial port receive status (returns # bytes of rx buffer used)
|
|
CMD_SIOTXST = $54 ' Serial port transmit status (returns # bytes of tx buffer space available)
|
|
CMD_SIORXFL = $55 ' Serial port receive buffer flush
|
|
CMD_SIOTXFL = $56 ' Serial port transmit buffer flush (not implemented)
|
|
|
|
CMD_RESET = $F0 ' Soft reset Propeller
|
|
|
|
OBJ
|
|
dsp : "VGA_1024" ' VGA Terminal Driver
|
|
kbd : "Keyboard" ' PS/2 Keyboard Driver
|
|
sdc : "safe_spi" ' SD Card Driver
|
|
'dbg : "Parallax Serial Terminal" ' Serial Port Driver (debug output)
|
|
dbg : "Parallax Serial Terminal Null" ' Do nothing for debug output
|
|
spk : "E555_SPKEngine" ' Speaker Driver
|
|
sio : "FullDuplexSerial" ' Serial I/O
|
|
'sio : "FullDuplexSerialNull" ' Dummy driver to use when debugging
|
|
|
|
VAR
|
|
long tmp
|
|
long Cmd
|
|
long Func
|
|
byte ByteVal
|
|
long BufPtr
|
|
long BufSize
|
|
|
|
long DskBuf[128] ' 512 byte, declared as long's to ensure long-aligned
|
|
long DskStat
|
|
long DskBlock
|
|
|
|
long FuncTmp
|
|
|
|
long Cnt10ms
|
|
|
|
long TimerStack[16]
|
|
long TimerCount
|
|
|
|
PUB main
|
|
dbg.Start(115200)
|
|
|
|
MsgStr(string("Starting ParPortProp..."))
|
|
MsgNewLine
|
|
|
|
MsgStr(string("Initializing Video..."))
|
|
Result := dsp.Start(VGA_BASE)
|
|
if (Result < 0)
|
|
MsgStr(string(" Failed! Error: "))
|
|
MsgDec(Result)
|
|
else
|
|
MsgStr(string(" OK"))
|
|
dsp.Color(GOLDBROWN)
|
|
dsp.Cls1(9600, 5, 1, 0, 0)
|
|
dsp.Inv(0)
|
|
dsp.CursorSet(5)
|
|
MsgNewLine
|
|
|
|
TimerCount := SLEEP
|
|
dsp.VidOn
|
|
|
|
MsgStr(string("Initializing ParPortProp..."))
|
|
|
|
Cmd := 0
|
|
Func := 0
|
|
ByteVal := 0
|
|
BufPtr := @DskBuf
|
|
DskStat := 0
|
|
DskBlock := 0
|
|
|
|
CmdAdr := @Cmd
|
|
FuncAdr := @Func
|
|
ByteValAdr := @ByteVal
|
|
BufPtrAdr := @BufPtr
|
|
BufSizeAdr := @BufSize
|
|
|
|
MsgStr(string(" OK"))
|
|
MsgNewLine
|
|
|
|
MsgStr(string("Initializing Keyboard..."))
|
|
Result := kbd.Start(KBD_BASE, KBD_BASE + 1)
|
|
if (Result < 0)
|
|
MsgStr(string(" Failed! Error: "))
|
|
MsgDec(Result)
|
|
else
|
|
MsgStr(string(" OK"))
|
|
MsgNewLine
|
|
|
|
MsgStr(string("Initializing SD Card..."))
|
|
Result := \sdc.Start(SD_BASE)
|
|
if (Result < 0)
|
|
MsgStr(string(" Failed! Error: "))
|
|
MsgDec(Result)
|
|
else
|
|
MsgStr(string(" OK"))
|
|
MsgNewLine
|
|
|
|
MsgStr(string("Initializing Serial Port..."))
|
|
Result := sio.Start(31, 30, 0, 9600)
|
|
if (Result < 0)
|
|
MsgStr(string(" Failed! Error: "))
|
|
MsgDec(Result)
|
|
else
|
|
MsgStr(string(" OK"))
|
|
MsgNewLine
|
|
|
|
MsgStr(string("Starting Timer..."))
|
|
Result := cognew(Timer, @TimerStack)
|
|
if (Result < 0)
|
|
MsgStr(string(" Failed! Error: "))
|
|
MsgDec(Result)
|
|
else
|
|
MsgStr(string(" OK"))
|
|
MsgNewLine
|
|
|
|
MsgStr(string("Starting PortIO cog..."))
|
|
Result := cognew(@Entry, 0) + 1
|
|
if (Result < 0)
|
|
MsgStr(string(" Failed! Error: "))
|
|
MsgDec(Result)
|
|
else
|
|
MsgStr(string(" OK"))
|
|
MsgNewLine
|
|
|
|
spk.speakerFrequency(1000, SPK_BASE)
|
|
waitcnt((clkfreq >> 4) + cnt)
|
|
spk.speakerFrequency(-1, SPK_BASE)
|
|
|
|
MsgStr(string("ParPortProp Ready!"))
|
|
MsgNewLine
|
|
|
|
'repeat
|
|
' dbg.NewLine
|
|
' dbg.Hex(ina, 8)
|
|
' waitcnt((clkfreq / 2) + cnt)
|
|
|
|
repeat
|
|
tmp := Cmd
|
|
'dbg.Str(String("Cmd="))
|
|
'dbg.Hex(Cmd, 8)
|
|
'dbg.NewLine
|
|
if (tmp <> 0)
|
|
dbg.Str(string("Command: "))
|
|
dbg.Hex(tmp, 8)
|
|
dbg.NewLine
|
|
|
|
case tmp
|
|
CMD_NOP:
|
|
|
|
CMD_ECHOBYTE:
|
|
EchoByte
|
|
|
|
CMD_ECHOBUF:
|
|
EchoBuf
|
|
|
|
CMD_DSKRES:
|
|
DiskReset
|
|
|
|
CMD_DSKSTAT:
|
|
DiskStatus
|
|
|
|
CMD_DSKPUT:
|
|
DiskPutBuf
|
|
|
|
CMD_DSKGET:
|
|
DiskGetBuf
|
|
|
|
CMD_DSKRD:
|
|
DiskRead
|
|
|
|
CMD_DSKWR:
|
|
DiskWrite
|
|
|
|
CMD_VIDOUT:
|
|
VideoOut
|
|
|
|
CMD_KBDSTAT:
|
|
KeyboardStatus
|
|
|
|
CMD_KBDRD:
|
|
KeyboardRead
|
|
|
|
CMD_SPKTONE:
|
|
SpeakerTone
|
|
|
|
CMD_SIOINIT:
|
|
SerialInit
|
|
|
|
CMD_SIORX:
|
|
SerialRx
|
|
|
|
CMD_SIOTX:
|
|
SerialTx
|
|
|
|
CMD_SIORXST:
|
|
SerialRxStat
|
|
|
|
CMD_SIOTXST:
|
|
SerialTxStat
|
|
|
|
CMD_SIORXFL:
|
|
SerialRxFlush
|
|
|
|
CMD_SIOTXFL:
|
|
SerialTxFlush
|
|
|
|
CMD_RESET:
|
|
Reboot
|
|
|
|
Cmd := 0
|
|
dbg.Str(string("*End of Command*"))
|
|
dbg.NewLine
|
|
|
|
MsgNewLine
|
|
MsgStr(string("ParPortProp Shutdown!"))
|
|
MsgNewLine
|
|
|
|
PRI EchoByte
|
|
|
|
ExecFunction(FUNC_GETBYTE)
|
|
!ByteVal
|
|
ExecFunction(FUNC_PUTBYTE)
|
|
|
|
return
|
|
|
|
PRI EchoBuf
|
|
|
|
BufPtr := @DskBuf
|
|
BufSize := 512
|
|
|
|
bytefill(BufPtr, $FF, BufSize)
|
|
'DumpBuffer(@DskBuf)
|
|
|
|
ExecFunction(FUNC_GETBUF)
|
|
'DumpBuffer(@DskBuf)
|
|
|
|
ExecFunction(FUNC_PUTBUF)
|
|
|
|
return
|
|
|
|
PRI DiskReset
|
|
|
|
dbg.Str(string("sdc.Start:"))
|
|
DskStat := \sdc.Start(SD_BASE)
|
|
Result := DskStat
|
|
dbg.Dec(DskStat)
|
|
dbg.NewLine
|
|
|
|
ByteVal := (DskStat < 0)
|
|
ExecFunction(FUNC_PUTBYTE)
|
|
|
|
return
|
|
|
|
PRI DiskStatus | Stat
|
|
|
|
dbg.Str(string("Disk Status:"))
|
|
dbg.Dec(DskStat)
|
|
dbg.NewLine
|
|
|
|
BufPtr := @DskStat
|
|
BufSize := 4
|
|
ExecFunction(FUNC_PUTBUF)
|
|
|
|
return
|
|
|
|
PRI DiskPutBuf
|
|
|
|
BufPtr := @DskBuf
|
|
BufSize := 512
|
|
|
|
bytefill(BufPtr, $00, BufSize)
|
|
|
|
ExecFunction(FUNC_GETBUF)
|
|
|
|
'DumpBuffer(@DskBuf)
|
|
|
|
return
|
|
|
|
PRI DiskGetBuf
|
|
|
|
BufPtr := @DskBuf
|
|
BufSize := 512
|
|
|
|
ExecFunction(FUNC_PUTBUF)
|
|
|
|
return
|
|
|
|
PRI DiskRead
|
|
|
|
BufPtr := @DskBlock
|
|
BufSize := 4
|
|
|
|
ExecFunction(FUNC_GETBUF)
|
|
|
|
dbg.Str(string("sdc.ReadBlock("))
|
|
dbg.Hex(DskBlock, 8)
|
|
dbg.Str(string("): "))
|
|
DskStat := \sdc.ReadBlock(DskBlock, @DskBuf)
|
|
Result := DskStat
|
|
dbg.Dec(DskStat)
|
|
dbg.NewLine
|
|
|
|
ByteVal := (DskStat <> 0)
|
|
ExecFunction(FUNC_PUTBYTE)
|
|
|
|
'DumpBuffer(@DskBuf)
|
|
|
|
return
|
|
|
|
PRI DiskWrite
|
|
|
|
'DumpBuffer(@DskBuf)
|
|
|
|
BufPtr := @DskBlock
|
|
BufSize := 4
|
|
|
|
ExecFunction(FUNC_GETBUF)
|
|
|
|
dbg.Str(string("sdc.WriteBlock("))
|
|
dbg.Hex(DskBlock, 8)
|
|
dbg.Str(string("): "))
|
|
DskStat := \sdc.WriteBlock(DskBlock, @DskBuf)
|
|
Result := DskStat
|
|
dbg.Dec(DskStat)
|
|
dbg.NewLine
|
|
|
|
ByteVal := (DskStat <> 0)
|
|
ExecFunction(FUNC_PUTBYTE)
|
|
|
|
return
|
|
|
|
PRI VideoOut
|
|
|
|
ExecFunction(FUNC_GETBYTE)
|
|
|
|
dbg.Str(string("VideoOut: "))
|
|
dbg.Hex(ByteVal, 2)
|
|
|
|
dsp.Process_Char(ByteVal)
|
|
|
|
dbg.Str(string(" <done>"))
|
|
dbg.NewLine
|
|
|
|
Activity
|
|
|
|
return
|
|
|
|
PRI KeyboardStatus
|
|
|
|
dbg.Str(string("KeyboardStatus: "))
|
|
|
|
ByteVal := kbd.GotKey
|
|
|
|
if (ByteVal)
|
|
Activity
|
|
|
|
dbg.Hex(ByteVal, 2)
|
|
dbg.Str(string(" <done>"))
|
|
|
|
ExecFunction(FUNC_PUTBYTE)
|
|
|
|
return
|
|
|
|
PRI KeyboardRead
|
|
|
|
repeat until kbd.GotKey
|
|
|
|
ByteVal := kbd.GetKey
|
|
|
|
ExecFunction(FUNC_PUTBYTE)
|
|
|
|
Activity
|
|
|
|
return
|
|
|
|
PRI SpeakerTone | Freq, Duration
|
|
|
|
ExecFunction(FUNC_GETBYTE) ' tone
|
|
Freq := (ByteVal * 10)
|
|
|
|
ExecFunction(FUNC_GETBYTE) ' duration
|
|
Duration := ((CLKFREQ >> 8) * ByteVal)
|
|
|
|
dbg.Str(String("Speaker Tone: "))
|
|
dbg.Dec(Freq)
|
|
dbg.Str(String("Hz, "))
|
|
tmp := (CLKFREQ / 1000)
|
|
dbg.Dec(Duration / tmp)
|
|
dbg.Str(String("ms"))
|
|
dbg.NewLine
|
|
|
|
spk.speakerFrequency(Freq, SPK_BASE)
|
|
waitcnt(Duration + cnt)
|
|
spk.speakerFrequency(-1, SPK_BASE)
|
|
|
|
return
|
|
|
|
PRI SerialInit | Baudrate
|
|
|
|
BufPtr := @Baudrate
|
|
BufSize := 4
|
|
|
|
ExecFunction(FUNC_GETBUF)
|
|
|
|
sio.Start(31, 30, 0, Baudrate)
|
|
|
|
return
|
|
|
|
PRI SerialRx
|
|
|
|
ByteVal := sio.rx
|
|
ExecFunction(FUNC_PUTBYTE)
|
|
|
|
return
|
|
|
|
PRI SerialTx
|
|
|
|
ExecFunction(FUNC_GETBYTE)
|
|
sio.tx(ByteVal)
|
|
|
|
return
|
|
|
|
PRI SerialRxStat
|
|
|
|
ByteVal := sio.rxcount
|
|
ExecFunction(FUNC_PUTBYTE)
|
|
|
|
PRI SerialTxStat
|
|
|
|
ByteVal := sio.txcount
|
|
ExecFunction(FUNC_PUTBYTE)
|
|
|
|
PRI SerialRxFlush
|
|
|
|
sio.rxflush
|
|
|
|
return
|
|
|
|
PRI SerialTxFlush
|
|
|
|
' not implemented by serial driver...
|
|
|
|
return
|
|
|
|
PRI ExecFunction (Function)
|
|
|
|
dbg.Str(string("Function: "))
|
|
dbg.Hex(Function, 8)
|
|
|
|
if (Cmd < 0)
|
|
dbg.Str(string(" <bypassed>"))
|
|
dbg.NewLine
|
|
return
|
|
|
|
Func := Function
|
|
|
|
repeat until (Func =< 0)
|
|
|
|
' FIX: use 'abort' below instead of setting Cmd := -1
|
|
|
|
if (Func < 0)
|
|
dbg.Str(string(" <aborted>"))
|
|
Cmd := -1
|
|
else
|
|
dbg.Str(string(" <done>"))
|
|
|
|
dbg.NewLine
|
|
|
|
return
|
|
|
|
PRI MsgNewLine
|
|
dbg.NewLine
|
|
dsp.process_char(13)
|
|
dsp.process_char(10)
|
|
|
|
PRI MsgStr(StrPtr)
|
|
dbg.Str(StrPtr)
|
|
dsp.Str(StrPtr)
|
|
|
|
PRI MsgDec(Val)
|
|
dbg.Dec(Val)
|
|
dsp.Dec(Val)
|
|
|
|
PRI MsgHex(Val, Digits)
|
|
dbg.Hex(Val, Digits)
|
|
dsp.Hex(Val, Digits)
|
|
|
|
PRI DumpBuffer(Buffer) | i, j
|
|
|
|
repeat i from 0 to 31
|
|
dbg.Hex(i * 16, 4)
|
|
dbg.Str(string(": "))
|
|
repeat j from 0 to 15
|
|
dbg.Hex((byte[Buffer][((i * 16) + j)]), 2)
|
|
dbg.Str(string(" "))
|
|
dbg.NewLine
|
|
|
|
PRI Reverse(Val) | i
|
|
|
|
repeat i from 0 to 3
|
|
Result.byte[i] := Val.byte[3 - i]
|
|
|
|
PRI Timer
|
|
TimerCount := SLEEP
|
|
repeat
|
|
waitcnt(clkfreq * 1 + cnt)
|
|
if (TimerCount > 0)
|
|
if (TimerCount == 1)
|
|
dsp.VidOff
|
|
TimerCount--
|
|
|
|
PRI Activity
|
|
if (TimerCount == 0)
|
|
dsp.VidOn
|
|
TimerCount := SLEEP
|
|
|
|
DAT
|
|
|
|
|
|
org 0
|
|
|
|
Entry mov outa, xppi_idle ' set ack and strobe to inactive state
|
|
mov dira, xppi_dirrd ' pin direction to default (read)
|
|
|
|
' Notify host we are ready with $AA
|
|
'waitpeq Zero, xppi_ibf ' wait for IBF to be inactive (low)
|
|
or outa, #$AA
|
|
mov dira, xppi_dirwr ' configure data bits for output
|
|
andn outa, xppi_stb ' assert strobe (low)
|
|
nop ' time for PPI to see strobe
|
|
or outa, xppi_stb ' deassert strobe (high)
|
|
mov dira, xppi_dirrd ' configure data bits for input
|
|
|
|
'' Second part of notification is $55
|
|
'waitpeq Zero, xppi_ibf ' wait for IBF to be inactive (low)
|
|
'mov outa, xppi_idle ' clear out old data bits
|
|
'or outa, #$55 ' set new data bits
|
|
'mov dira, xppi_dirwr ' configure data bits for output
|
|
'andn outa, xppi_stb ' assert strobe (low)
|
|
'nop ' time for PPI to see strobe
|
|
'or outa, xppi_stb ' deassert strobe (high)
|
|
'mov dira, xppi_dirrd ' configure data bits for input
|
|
|
|
DoCmd ' Discard incoming bytes until we see cmd signal
|
|
|
|
mov xtmp, ina ' get pins
|
|
test xtmp, xppi_cmd wz ' is command ready?
|
|
if_nz jmp #DoCmd1 ' yes, handle it now
|
|
test xtmp, xppi_obf wz ' is bogus data pending?
|
|
if_nz jmp #DoCmd ' nope, loop
|
|
andn outa, xppi_ack ' assert ack (low)
|
|
waitpeq xppi_obf, xppi_obf ' wait for OBF to be inactive (high)
|
|
or outa, xppi_ack ' deassert ack (high)
|
|
jmp #DoCmd ' bad byte swallowed, loop
|
|
|
|
'waitpeq xppi_cmd, xppi_cmd ' wait for command signal
|
|
|
|
DoCmd1 ' Receive incoming commands
|
|
waitpeq Zero, xppi_obf ' wait for it to show up (OBF low)
|
|
andn outa, xppi_ack ' assert ack (low)
|
|
waitpeq xppi_obf, xppi_obf ' wait for OBF to be inactive (high)
|
|
mov xtmp, ina ' now we can get the data bits
|
|
or outa, xppi_ack ' deassert ack (high)
|
|
|
|
waitpeq Zero, xppi_cmd ' wait for command signal to clear
|
|
|
|
and xtmp, #$FF ' isolate data bits
|
|
wrlong xtmp, CmdAdr ' Record it
|
|
|
|
DoFunc ' Function processing loop
|
|
|
|
rdlong xtmp, FuncAdr
|
|
cmp xtmp, #FUNC_PUTBYTE wz
|
|
if_e jmp #PutByte
|
|
cmp xtmp, #FUNC_GETBYTE wz
|
|
if_e jmp #GetByte
|
|
cmp xtmp, #FUNC_PUTBUF wz
|
|
if_e jmp #PutBuf
|
|
cmp xtmp, #FUNC_GETBUF wz
|
|
if_e jmp #GetBuf
|
|
|
|
' Check for a new command to be pending???
|
|
|
|
' Check Cmd, loop until it is zero (idle)
|
|
|
|
rdlong xtmp, CmdAdr
|
|
cmp xtmp, Zero wz
|
|
if_e jmp #DoCmd
|
|
jmp #DoFunc
|
|
|
|
PutByte ' Parm -> PPI
|
|
|
|
andn outa, #$FF ' clear old data bits
|
|
rdbyte xtmp, ByteValAdr ' get byte value into xtmp
|
|
and xtmp, #$FF ' careful to ensure only data bits set
|
|
or outa, xtmp ' set new data bits
|
|
|
|
waitpne xppi_ibf, xppi_ibfcmd ' wait for IBF empty or CMD flag
|
|
mov xtmp, ina ' read the pins
|
|
test xtmp, xppi_cmd wz ' CMD pending?
|
|
if_nz jmp #AbortCmd ' Yes, clear out
|
|
|
|
mov dira, xppi_dirwr ' configure data bits for output
|
|
andn outa, xppi_stb ' assert strobe (low)
|
|
nop ' time for PPI to see strobe
|
|
or outa, xppi_stb ' deassert strobe (high)
|
|
mov dira, xppi_dirrd ' configure data bits for input
|
|
|
|
wrlong Zero, FuncAdr ' clear out original function request
|
|
jmp #DoFunc ' and return
|
|
|
|
GetByte ' PPI -> Parm
|
|
|
|
waitpne xppi_obf, xppi_obfcmd ' wait for OBF empty or CMD flag
|
|
mov xtmp, ina ' read the pins
|
|
test xtmp, xppi_cmd wz ' CMD pending?
|
|
if_nz jmp #AbortCmd ' Yes, clear out
|
|
|
|
andn outa, xppi_ack ' assert ack (low)
|
|
waitpeq xppi_obf, xppi_obf ' wait for OBF to be inactive (high)
|
|
mov xtmp, ina ' now we can get the data bits
|
|
or outa, xppi_ack ' deassert ack (high)
|
|
|
|
wrbyte xtmp, ByteValAdr ' Save it in main memory
|
|
|
|
wrlong Zero, FuncAdr ' clear out original function request
|
|
jmp #DoFunc ' and return
|
|
|
|
PutBuf ' Buf -> PPI
|
|
|
|
rdlong TempAdr, BufPtrAdr ' get buffer pointer
|
|
rdlong TempCnt,BufSizeAdr ' get the buffer size for operation
|
|
|
|
PutBuf1 andn outa, #$FF ' clear old data bits
|
|
rdbyte xtmp, TempAdr ' get value into xtmp
|
|
and xtmp, #$FF ' careful to ensure only data bits set
|
|
or outa, xtmp ' set new data bits
|
|
|
|
waitpne xppi_ibf, xppi_ibfcmd ' wait for IBF empty or CMD flag
|
|
mov xtmp, ina ' read the pins
|
|
test xtmp, xppi_cmd wz ' CMD pending?
|
|
if_nz jmp #AbortCmd ' Yes, clear out
|
|
|
|
' FIX: move setting of dir outside of loop
|
|
|
|
mov dira, xppi_dirwr ' configure data bits for output
|
|
andn outa, xppi_stb ' assert strobe (low)
|
|
nop ' delay for PPI to see strobe
|
|
or outa, xppi_stb ' deassert strobe (high)
|
|
mov dira, xppi_dirrd ' configure data bits for input
|
|
|
|
sub TempCnt, #1
|
|
add TempAdr, #1
|
|
cmp TempCnt, Zero wz
|
|
if_ne jmp #PutBuf1
|
|
|
|
wrlong Zero, FuncAdr ' clear out original function request
|
|
jmp #DoFunc ' and return
|
|
|
|
GetBuf ' PPI -> Buf
|
|
|
|
rdlong TempAdr, BufPtrAdr ' get buffer pointer
|
|
rdlong TempCnt,BufSizeAdr ' get the buffer size for operation
|
|
|
|
GetBuf1 waitpne xppi_obf, xppi_obfcmd ' wait for OBF empty or CMD flag
|
|
mov xtmp, ina ' read the pins
|
|
test xtmp, xppi_cmd wz ' CMD pending?
|
|
if_nz jmp #AbortCmd ' Yes, clear out
|
|
|
|
andn outa, xppi_ack ' assert ack (low)
|
|
waitpeq xppi_obf, xppi_obf ' wait for OBF to be inactive (high)
|
|
mov xtmp, ina ' now we can get the data bits
|
|
or outa, xppi_ack ' deassert ack (high)
|
|
|
|
wrbyte xtmp, TempAdr
|
|
|
|
sub TempCnt, #1
|
|
add TempAdr, #1
|
|
cmp TempCnt, Zero wz
|
|
if_ne jmp #GetBuf1
|
|
|
|
wrlong Zero, FuncAdr ' clear out original function request
|
|
jmp #DoFunc ' and return
|
|
|
|
AbortCmd mov dira, xppi_dirrd ' configure data bits for input
|
|
wrlong NegOne, FuncAdr ' abort any active function
|
|
jmp #DoFunc ' handle pending command
|
|
|
|
CmdAdr long 0
|
|
FuncAdr long 0
|
|
ByteValAdr long 0
|
|
BufPtrAdr long 0
|
|
BufSizeAdr long 0
|
|
|
|
Zero long 0
|
|
NegOne long -1
|
|
|
|
xppi_cmd long PPI_CMD ' pin 8, active high
|
|
xppi_stb long PPI_STB ' pin 9, active low
|
|
xppi_ibf long PPI_IBF ' pin 10, active high
|
|
xppi_ack long PPI_ACK ' pin 11, active low
|
|
xppi_obf long PPI_OBF ' pin 12, active low
|
|
|
|
xppi_idle long PPI_STB + PPI_ACK
|
|
xppi_ibfcmd long PPI_IBF + PPI_CMD
|
|
xppi_obfcmd long PPI_OBF + PPI_CMD
|
|
|
|
xppi_dirrd long PPI_STB + PPI_ACK
|
|
xppi_dirwr long PPI_STB + PPI_ACK + $FF
|
|
|
|
xtmp long $FFFF
|
|
|
|
TempVal res 1
|
|
TempAdr res 1
|
|
TempCnt res 1
|
|
|
|
fit
|