P2 ROM SERIAL ROUTINES - ROM version

Hello,
does anyone know how I can query the Rx status if a character is ready to be fetched?
And how do I fetch a single character.
Both functions must not block the process.
The code is from the Z80 emulator.
'+-----------------------------------------------------------------------------+
_bitper = (_clkfreq / _baudx) << 16 + 7 ' xxx baud, 8 bits
_txmode = %0000_0000_000_0000000000000_01_11110_0 'async tx mode, output enabled for smart output
_rxmode = %0000_0000_000_0000000000000_00_11111_0 'async rx mode, input enabled for smart input
'+-----------------------------------------------------------------------------+
rx_pin = 63 'pin serial receiver
tx_pin = 62 'pin serial transmitter
'+-----------------------------------------------------------------------------+
'+============[ COG VARIABLES $1E0-$1EF - ROM MONITOR]=========================+
'+-------[ LMM parameters, etc ]-----------------------------------------------+
lmm_x = $1e0 ' parameter passed to/from LMM routine (typically a value)
lmm_f = $1e1 ' parameter passed to LMM routine (function options; returns unchanged)
lmm_p = $1e2 ' parameter passed to/from LMM routine (typically a hub/cog ptr/addr)
lmm_p2 = $1e3 ' parameter passed to/from LMM routine (typically a 2nd hub/cog address)
lmm_c = $1e4 ' parameter passed to/from LMM routine (typically a count)
'+-------[ LMM additional workareas ]------------------------------------------+
lmm_w = $1e5 ' workarea (never saved - short term use between calls, except _HubTx)
lmm_tx = $1e6 ' _HubTx
lmm_hx = $1e7 ' _HubHex/_HubString
lmm_hx2 = $1e8 ' _HubHex
lmm_hc = $1e9 ' "
lmm_lx = $1ea ' _HubList
lmm_lf = $1eb ' "
lmm_lp = $1ec ' "
lmm_lp2 = $1ed ' "
lmm_lc = $1ee ' "
lmm_bufad = $1ef ' _HubRxString
'+-------[ ASCII equates ]-----------------------------------------------------+
_CLS_ = $0C
_BS_ = $08
_LF_ = $0A
_CR_ = $0D
_TAQOZ_ = $1B ' <esc> goto TAQOZ
'+-------[ LMM DEBUGGER - CALL Modes...(not all modes supported) ]-------------+
_MODE = $F << 5 ' mode bits defining the call b8..b5 (b4..b0 are modifier options)
_SHIFT = 5 ' shr # to extract mode bits
_HEX_ = 2 << 5 ' hex...
_REV_ = 1 << 4 ' - reverse byte order
_SP = 1 << 3 ' - space between hex output pairs
'_DIGITS = 7..0 where 8->0 ' - no. of digits to display
_LIST = 3 << 5 ' LIST memory line (1/4 longs) from cog/hub
_ADDR2 = 1 << 4 ' 1= use lmm_p2 as to-address
_LONG_ = 1 << 1 ' 1=display longs xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx
_TXSTRING = 4 << 5 ' tx string (nul terminated) from hub
_RXSTRING = 5 << 5 ' rx string
_ECHO_ = 1 << 4 ' - echo char
_PROMPT = 1 << 3 ' - prompt (lmm_x)
_ADDR = 1 << 2 ' - addr of string buffer supplied
_NOLF = 1 << 1 ' - strip <lf>
_MONITOR = 7 << 5 ' goto rom monitor
'+-------[ P2 ROM SERIAL ROUTINES (HUBEXEC) - ROM version ]--------------------+
_SerialInit = $fcab8 ' Serial Initialise (lmm_x & lmm_bufad must be set first)
_hubTxCR = $fcae4 ' Sends <cr><lf> (overwrites lmm_x)
_hubTxRev = $fcaec ' Sends lmm_x with bytes reversed
_hubTx = $fcaf0 ' Sends lmm_x (can be up to 4 bytes)
_hubHexRev = $fcb24 ' Sends lmm_x with bytes reversed as Hex char(s) as defined in lmm_f
_hubHex8 = $fcb28 ' Sends lmm_x as Hex char(s) after setting lmm_f as 8 hex chars
_hubHex = $fcb2c ' Sends lmm_x as Hex char(s) as defined in lmm_f
_hubTxStrVer = $fcb9c ' Sends $0 terminated string at lmm_p address after setting lmm_p=##_str_vers
_hubTxString = $fcba4 '\ Sends $0 terminated string at lmm_p address
_hubTxStr = $fcba4 '/ Sends $0 terminated string at lmm_p address
_hubListA2H = $fcbc4 ' List/Dump line(s) from lmm_p address to lmm_p2 address after setting lmm_f=#_LIST+_ADDR2
_hubList = $fcbc8 ' List/Dump line(s) from lmm_p address to lmm_p2 address according to lmm_f
_hubRx = $fcb10 ' Recv char into lmm_x
_hubRxStrMon = $fccc4 ' Recv string into lmm_bufad address after setting prompt=lmm_x=#"*" & params=lmm_f=#_RXSTRING+_ECHO_+_PROMPT
_hubRxString = $fcccc ' Recv string into lmm_p/lmm_bufad address according to params in lmm_f
_hubMonitor = $fcd78 ' Calls the Monitor; uses lmm_bufad as the input buffer address
_RdLongCogHub = $fcf34 ' read cog/lut/hub long from lmm_p address into lmm_x, then lmm_p++
_str_vers = $fd014 ' locn of hub string, $0 terminated
'+-------[ HUB ADDRESSES ]-----------------------------------------------------+
_HUB_ROM = $FC000 ' ROM $FC000
_HUB_SERBUF = $FC000 '[80] Serial receive buffer (overwrites ROM Booter)
_HUB_SERSIZE = 80 ' Serial receive buffer size
'+-----------------------------------------------------------------------------+
'+-------[ Start Serial for P2xxxx ]-------------------------------------------+
mov lmm_bufad, ##_HUB_SERBUF ' locn of hub buffer for serial routine
mov lmm_x, ##_BITPER ' sets serial baud
call #\_SerialInit ' initialise serial
'+-----------------------------------------------------------------------------+
waitx ##_STARTUP_DELAY ' delay to get terminal running
'+-----------------------------------------------------------------------------+
'+-----------------------------------------------------------------------------+
TX_DATA
mov lmm_x, Tx_Data
call #\_hubTx
ret
'+-----------------------------------------------------------------------------+
RX_STATUS
call #\_hubRxStat?????
mov Rx_Stat, lmm_x
ret
'+-----------------------------------------------------------------------------+
RX_DATA
call #\_hubRx
mov Rx_Data, lmm_x
ret
'+-----------------------------------------------------------------------------+
Smartpinn is easier with single characters.
Comments
Hello,
I would like to ask again if there is a way to determine whether a new character was received or their number.
CP/M often asks the status and I don't want to block the whole system.
Thank you.
I would think that the RX_STATUS code below that is near the end of the code you posted would do that. Not 100% sure of that since the code it calls is not listed here.
'+-----------------------------------------------------------------------------+
RX_STATUS
call #_hubRxStat?????
mov Rx_Stat, lmm_x
ret
No, the routine is only a guess, as _hubRxStat is not defined in the constants.
Sorry i am away and on my iphone.
I created a thread about using the P2 ROM Serial routines. IIRC there is a routine that does a rxline that places any received chars into a buffer.
Yesterday I wrote something for my RPi Zero based contraption. A P2 uses a serial port to receive messages from it via a serial port. This is done without any ROM procedures, instead I read the pin status to determine if the serial port received a byte. Then I put this byte into a circular buffer. Without this buffer there were missed bytes as they can arrive faster than the main program process them.
Maybe something from this code can help. It opens 2 serial ports, one for a RPi (keyboard/mouse interface), one for MIDI and then receicves and processes this data.
https://github.com/pik33/P2-retromachine/blob/main/Propeller/retrocog.spin2
' A retromachine cog ' The purpose: to read/send and process data from RPi and Midi Shield ' v. 0.01 pik33@o2.pl ' con _clkfreq=320_000_000 rxpin=32 txpin=33 midiin=29 midiout=30 baudrate=1920000 mbaudrate=31250 var long kbdfront,kbdtail long mousefront,mousetail long midifront,miditail long kbdbuf[32] long mousebuf[128] long midibuf[32] long serialstack[36] pub dummy() repeat 'this is the object and not a program pub start :cog cog:=cogspin(16,serialcog(),@serialstack) return cog pub serialcog()| rr, mrr, b, mb, midireport, kbmreport 'start serial and midi serial_start(rxpin, txpin, baudrate) serial_start(midiin,midiout,mbaudrate) mb:=(-1) b:=(-1) mousefront:=0 mousetail:=0 kbdfront:=0 kbdtail:=0 midifront:=0 miditail:=0 long[$30]:=0 long[$34]:=0 long[$38]:=0 repeat repeat rr:=rxcheck(rxpin) mrr:=rxcheck(midiin) until rr>=0 || mrr>=0 ' midi. Must be >= $80 for a command '$80-$8F - 3 bytes note off. note, velocity '$90-$9F - 3 bytes note on, note, velocity '$A0-$AF - 3 bytes poly aftertouch. note, value '$B0-$BF - 3 bytes control change, controller-value, '$C0-$CF - 2 bytes program change '$D0-$DF - 2 bytes mono aftertouch '$E0-$EF - 3 bytes pitch bend, $2000 - center '$F0-$FF - 1 byte if ((mrr>=$80) && (mrr<=$BF)) || ((mrr>=$E0) && (mrr<=$EF)) mb:=2 midireport:=mrr<<24 if (mrr>=$C0) && (mrr<=$DF) mb:=1 midireport:=mrr<<24 if (mrr>=$F0) 'TODO: do something with SYSEX, now a workaround for Novation Impulse mb:=4 midireport:=mrr<<24 if (mrr<$80) && (mb>0) mb-- if mb<3 midireport+=mrr<<(mb<<3) if mb==0 if midifront<>((miditail-1) //32) midibuf[midifront]:=midireport midifront+=1 midifront:=midifront // 32 mb:=(-1) 'Keyboard and mouse if (rr>=$80) && (rr<>$FF) b:=3 kbmreport:=rr<<24 if (rr<$80) && (b>0) b-- kbmreport+=rr<<(b<<3) if (rr==$FF) b:=0 if b==0 if (kbmreport +>= $80000000) && (kbmreport +< $87000000) 'mouse if mousefront<>((mousetail-1) //128) mousebuf[mousefront]:=kbmreport mousefront+=1 mousefront:=mousefront // 128 b:=(-1) if (kbmreport +>= $87000000) && (kbmreport +< $8a000000) 'keyboard if kbdfront<>((kbdtail-1) //32) kbdbuf[kbdfront]:=kbmreport kbdfront+=1 kbdfront:=kbdfront // 32 b:=(-1) if long[$30]==0 if kbdfront<>kbdtail long[$30]:=kbdbuf[kbdtail] kbdtail++ kbdtail:= kbdtail // 32 if long[$34]==0 if mousefront<>mousetail long[$34]:=mousebuf[mousetail] mousetail++ mousetail:= mousetail // 128 if long[$38]==0 if midifront<>miditail long[$38]:=midibuf[miditail] miditail++ miditail:= miditail // 32 ''---------------------- Serial functions from jm_serial.spin2, modified pub serial_start(rxpin, txpin, baud) | bitmode bitmode := muldiv64(clkfreq, $1_0000, baud) & $FFFFFC00 ' set bit timing bitmode |= 7 ' set bits (8) pinstart(rxpin,P_HIGH_15K|P_ASYNC_RX,bitmode,0) pinstart(txpin,P_ASYNC_TX|P_OE,bitmode,0) pinhigh(rxpin) pub rxcheck(pin) : rxbyte | check '' Check for serial input '' -- returns -1 if nothing available rxbyte := -1 check := pinr(pin) if (check) rxbyte := rdpin(pin) >> 24 pub tx(pin,b) '' Emit byte wypin(pin, b) txflush(pin) pub txflush(pin) | check '' Wait until last byte has finished repeat check := pinr(pin) while (check == 0)
Pic33, that looks good.
I just have to see how I do it with PASM.
I will leave the (lmm) part in for debugging.
I will use a new interface for the console in/out of the CP/M bios.
I added today the standard serial pin p63 as 4th input source to the code (and removed a bug) - I wanted to do this in PASM first, but the spin is fast enough. Maybe this code will be rewritten in Pasm as I want more input sources to receive data (I want to connect analog and digital joystick to the P2)
I pulled out the important part and this is what comes out:
''============================================================================== '' Echo ''============================================================================== CON _clkfreq = 256_000_000 srxpin=32 stxpin=31 sbaudrate=1000000 pub start()| srr serial_start(srxpin,stxpin,sbaudrate) repeat if srr>=rxcheck(srxpin) tx(stxpin,srr) PRI serial_start(rxpin, txpin, baud) | bitmode bitmode := muldiv64(clkfreq, $1_0000, baud) & $FFFFFC00 '' set bit timing bitmode |= 7 '' set bits (8) pinstart(rxpin,P_HIGH_15K|P_ASYNC_RX,bitmode,0) pinstart(txpin,P_ASYNC_TX|P_OE,bitmode,0) pinhigh(rxpin) ''activate PRI rxcheck(pin) : rxbyte '' Check for serial input, returns -1 if nothing available rxbyte := -1 if pinr(pin) rxbyte := rdpin(pin) >> 24 PRI tx(pin,b) '' Send a byte and Wait until last byte has finished wypin(pin, b) repeat while (pinr(pin) == 0)
Now I still have to test it and convert it into PASM.
{{ %0000_0000_000_0000000000000_00_11110_0 P_ASYNC_TX Asynchronous serial transmit %0000_0000_000_0000000000000_01_00000_0 P_OE Enable output in smart pin mode %0000_0000_000_0000000000000_00_11111_0 P_ASYNC_RX Asynchronous serial receive %0000_0000_000_0000000010000_00_00000_0 P_HIGH_15K Drive high 15k }} CON _clkfreq = 256_000_000 CON TX_PIN = 31 '' P31 serial input RX_PIN = 32 '' P32 serial out txmode = P_ASYNC_TX | P_OE '' async tx mode rxmode = P_ASYNC_RX | P_HIGH_15K '' async rx mode sclk = ( _clkfreq / 1_000_000 ) '' bit rate 1MBit bitper = (( sclk << 16 ) & $FFFFFC00 ) + ( 32 - 1 ) '' bit rate & bits DAT org 0 asmclk wrpin ##rxmode, #RX_PIN '' Smart Pin async receive mode wxpin ##bitper, #RX_PIN '' receive period for 8 bits dirh #RX_PIN '' enable Smart Pin rcvr wrpin ##txmode, #TX_PIN '' Smart Pin async transmit mode wxpin ##bitper, #TX_PIN '' transmit period for 32 bits dirh #TX_PIN '' enable Smart Pin tx nop .next .rcvr '' wait for data testp #RX_PIN wc '' test flag if_nc jmp #.rcvr '' no flag, no data rdpin data_1, #RX_PIN '' RX .tcvr '' wait for ready testp #TX_PIN wc '' test flag if_c jmp #.tcvr '' is flag, no ready wypin data_1, #TX_PIN '' TX jmp #.next data_1 long 0 '' data saved here
I hope I have the TX status query right.
I don't have a P2 at hand, so it's all theory.
Remember to enable output for TX (the or P_OE bit in spin, there is a particular bit# to set)
The input pin (RX) is normally floating. If the signal source is on the same board, it is OK, but if there is a long cable between the source and P2, trash happens. This is why there is this P_HIGH_15K and pinhigh in my code. This enables 15k pullup which magically removed these interferences.
pic33,
i have adjusted the code in #10 a little.
Thanks
Sending and receiving works.
I want to check whether the smart pin has sent the old byte before sending.
But that doesn't work somehow.
I don't want to wait after each byte until the byte has been sent.
.tcvr '' wait for ready rdpin tmp,#TX_PIN wc '' test flag if_c jmp #.tcvr '' is flag, no ready wypin data_1, #TX_PIN '' TX