Serial Tube Protocol ==================== Serial Tube is a method of using the Tube protocol to communicate over a single communication channel, such as a serial port, a parallel port, or even a single Tube register. The Tube protocol has four transfer phases: Character Output, Command/ Response, Transfer Initialise, Transfer Data. These are usually sent via four seperate communication channels, such as the four Tube registers. Sending them via a single channel requires a method of combining and seperating all four. This is done by making the communication channel a simple text channel - as though a simple text terminal - and escaping out from the outward character stream to start a command request, and escaping out from the inward character stream to perform the data transfer actions. As with any client system, any functionality is entirely and utterly what the *Host* system provides. The client *must* *not* impose its own expectations of what functionality the host has. Client-to-Host transfers ------------------------ Sent data Returned data OSWRCH char or esc,esc OSRDCH char OSRDCHIO esc &00 Cy A OSCLI esc &02 string &0D &7F or &80 OSBYTELO esc &04 X A X OSBYTEHI esc &06 X Y A Cy Y X OSWORD esc &08 A in_length block out_length block OSWORD0 esc &0A block &FF or &7F string &0D OSARGS esc &0C Y block A A block OSBGET esc &0E Y Cy A OSBPUT esc &10 Y A &7F OSFIND esc &12 &00 Y &7F OSFIND esc &12 A string &0D A OSFILE esc &14 block string &0D A A block OSGBPB esc &16 block A block Cy A OSFSC esc &18 X Y A &FF Y X or &7F OSFSC reply &7F: string &0D &80 or &40 string &00 or &00 RESET string &00 &7F or &80 A X Y are the 8-bit register parameters. Cy is the Carry flag, &00 or &80. With responses of &FF, &80, &40 and &7F only the relevant bit should be tested. b0 and b7 of the transmitted command byte must always be zero. b5 and b6 are used to indicate what sort of filing system the host should 'look like': b6 b5 0 0 BBC: directory.filename/extension 0 1 Unix: directory/filename.extension 1 0 Win/DOS: directory\filename.extension 1 1 Native: whatever the host system is running on Host-to-Client transfers ------------------------ Incoming data x char/byte x esc esc char/byte esc esc &00 err string &00 Error esc <&80 ... Read returned control block of specified length esc &8n Escape state change, b0=new state esc &9x Y X A Event esc &Ax Reserved for networking esc &Bx End transfer esc &Cx addr Set address esc &Dx addr Execute address esc &Ex addr Start load from address esc &Fx addr Start save from address b0-b3 of the incoming transfer byte are reserved and should be ignored (other than b0 of &8n which holds the new Escape state). All addresses and control blocks are transfered high byte to low byte. All strings and data are transfered low byte to high byte. The Carry flag is transfered in b7 of a byte. An escape byte must be chosen so as not to conflict an outward command byte or an inward transfer byte. Almost any odd numbered byte can be used, but using &7F allows the greatest flexibility. In particular, it allows inward esc <&80 to transfer any control block from 1 to 126 bytes long. All outward and inward data is protected by the escape byte. An escape byte is transfered by prefixing it with another escape byte, even within command and response sequences. So, for example, an OSARGS call on channel &7F with address &17F (eg PTR#&7F=&17F) would send the following raw data: Sends: esc 0C Y block=&0000017F A +----+----+-------+----+----+----+-------+----+ | 7F | 0C | 7F 7F | 00 | 00 | 01 | 7F 7F | 01 | +----+----+-------+----+----+----+-------+----+ Reply: A block=&0000017F +----+----+----+----+-------+ | 01 | 00 | 00 | 01 | 7F 7F | +----+----+----+----+-------+ Notes on OSCLI -------------- OSCLI sends a string to the Host and wait for a command execution response byte. If b7 is clear, then OSCLI just returns. If b7 is set, then the data transfer address should be called. When code is called in response to a command execution response byte with b7 set, the Client should save the address of the current program, make any checks on the code such as checking for a valid ROM header, and then call the code. If the code then returns, the Client should then restore the current program address. Notes on RESET -------------- If the Client and the Host share a hardware RESET, then both the Client and the Host will be in the same state at reset. In order for the Client to determine what to do next, the reset sequence is to send a text string, terminated with a zero byte, and then wait for an OSCLI acknowledge. If b7 is set, then the data transfer address should be called, otherwise the current local program should be re-entered. If the Client and Host do not share a hardware RESET, such as with a simple serial connection, then the Client and Host will not neccessarily be in the same state at reset, and the text startup string is seen as just the same as any text string, there is no acknowledgement to wait for. In this case, the Client can send an OSFSC &FF call to tell the Host it has restarted. The response to to this will be an OSCLI acknowlege, with b7 set if the code at the data transfer address is to be called. The Host can tell the Client to restart by sending a Restart data transfer command. Notes on OSFSC -------------- Adding OSFSC to the Tube protocol commands allows a Serial Tube Client to be used as a BBC filing system. In a normal Client it would not be used, all FSC functions are performed by calling other entries, usually OSCLI. The protocol also adds the OSFSC &FF,x,y call for the Client to tell the Host it has restarted. This is used to implement Shift-Break when Serial Tube is used to implement the HostFS filing system. X should be 0 on entry, Y=0 indicates a boot requested, Y<>0 indicated no boot is to be performed. OSFSC sends its command sequence and then receives either a byte with b7 set or clear. If b7 is set, it is an OSFSC byte command and the returned Y and X values follow. If b7 is clear, it is an OSFSC string command and the Client should send the string pointed to by the OSFSC entry parameters. The response to this is then a command execution response byte as with the response to OSCLI. If b7 is set, then the transfer address should be called as the current Client program. If b6 is set, then a stream of characters will be send which should be displayed to OSWRCH, this will be terminated with a &00 byte which should not be printed. If the received execution byte is zero, then the OSFSC call should just exit. b5-b0 of the returned byte are reserved and should be ignored. Data Transfer ------------- All data transfers are initiated by a command sequence being sent from the Client. While the Client is waiting for a response the Host can escape from the byte stream to perform a data transfer. These data transfers can occur at any time that the Client is waiting for inward-coming data, even within another data transfer. From the point of view of the waiting Client command the data transfer takes place in the background. esc &00 err string &00 Error esc &00 &00 &00 Restart The received error byte and string is copied to the Client's error buffer and the Client's error handler entered. An extension is that esc &00 &00 &00 to causes the Client to reset. This is a fatal error (error number zero) with a null error string. esc <&80 ... Read returned control block The transfer byte specfies a number of bytes to read to the Client's command control block set up by the calling command sequence. esc &8n Escape state change, b0=new state The Client's Escape flag is set to the received flag in b0, and any local Escape handler called. esc &9x Y X A Event The Client's primary, secondary and tertiary registers are set to the recieved A, X and Y byte values, and then the local Event handler is called. esc &Ax Reserved for networking This sequence is reserved for networking over a serial link. esc &Bx End transfer Sufficient data and return addresses are popped from the stack to abandon the current sata transfer, and then a return is made as though returning from the data transfer call. esc &Cx addr Set address esc &Dx addr Execute address esc &Ex addr Start load from address esc &Fx addr Start save from address These all set the Client's data transfer address, high byte to low byte, from the received information. Set Address then simply returns, leaving the address to be used by the waiting command action (usually OSCLI) as the entry point of code to be exectuted. Execute Address calls the specified address directly from within the transfer routine without checking it. Start Load continues by receiving data, storing it at incrementing memory locations from the transfer address. Start Save continues by sending data from incrementing memory locations in the Client. Start Load and Start Save transfers are both terminated by an End Transfer packet. Note that if received data is read by polling the data input port, then data transfer actions can only happen while waiting for data. In particular, the Escape state cannot change in the background while a foreground program is running if the foreground program never makes any system calls. If data is received via interupts then the Escape state can change in the background with no system calls being made. Hardware -------- The only hardware required to form a Serial Tube link is an 8-bit input port with 1-bit Ready status bit, and an 8-bit output port with 1-bit Ready status bit. The TxRdy bit must indicate that a byte may be transmitted, the RxRdy bit must indicate that a byte has been received and is available for collection, and the other end is waiting for it to be collected. Simple Client code for the code send and receive functions would be the following: \ 6502 code \ Z80 code .SendData .SendData PHA PUSH AF .SendWait .SendWait LDA TxStatus IN A,(TxStatus) :\ Get Status AND #TxRDY AND TxRDY BEQ SendWait JR Z,SendWait :\ Wait until data can be sent PLA POP AF STA TxData OUT (TxData),A :\ Send data RTS RET .ReadData .ReadData LDA RxStatus IN A,(RxStatus) :\ Get Status CLC:AND #RxRDY AND RxRDY BEQ ReadDataOk RET Z :\ Exit if nothing waiting LDA RxData IN A,(RxData) :\ Read data CMP #esc CP esc :\ Check if esc character SEC SCF :\ Carry=Data fetched .ReadDataOk :\ Equal=Byte is esc char RTS RET Most one-byte communication ports (such as an RS232 link) do not automatically tell the remote end to stop transmitting when there is a received byte waiting to be read, so that must be performed by the reception code by raising/lowering a signal such as RTS. \ 6502 code \ Z80 code .ReadData .ReadData PHP:SEI :\ Disable IRQs TYA:PHA :\ Save Y LDY #RxCont LDA RxCont STY RxStatus OUT (RxStatus),A :\ Lower RTS to allow input LDY #RxStop LDA RxStatus IN A,(RxStatus) :\ Get RxStatus AND #RxRDY AND RxRDY BNE ReadDataOk JR NZ,ReadDataOk :\ Data present PLA LD A,RxStop STY RxStatus OUT (RxStatus),A :\ Raise RTS to stop input TAY:PLP :\ Restore Y, IRQs CLC:RTS RET :\ No Carry=No data present .ReadDataOk .ReadDataOk PLA LD A,RxStop STY RxStatus OUT (RxStatus),A :\ Raise RTS to stop input TAY:PLP :\ Restore Y, IRQs LDA RxData IN A,(RxData) :\ Fetch data CMP #esc CP esc :\ Check if esc character SEC SCF :\ Carry=Data fetched RTS RET :\ Equal=Byte is esc char All other Client code calls these two basic functions for all communication. More detailed information ------------------------- The source for the 6502 and Z80 Clients can be examined for more detailed information and should be regarded as the definitive specification. If documentation disagrees with the working released code, the code is the superior reference unless otherwise stated. History ------- 09-Apr-1995 v0.10 Z80 Serial Tube Client written. 15-May-1995 v0.10 6502 Serial Tube Client written. 12-Jun-2010 v0.10 6809 Serial Tube Client written.