FC00 OPT P*3+4 FC00 ; Tube Client Startup FC00 ; =================== FC00 .STARTUP FC00 F3 DI FC01 31 00 FC LD SP,STARTUP ; Set up initial stack below code FC04 3E 13 LD A,TxInit FC06 D3 00 OUT (TxStatus),A ; Initialise I/O hardware FC08 3E 15 LD A,RxInit FC0A D3 00 OUT (RxStatus),A ; Initialise I/O hardware FC0C CD BF FF CALL INITERR FC0F CD B3 FF CALL PRTEXT ; Print startup banner FC12 .StartupMessage FC12 0A DEFB 10 FC13 53 65 72 69 61 6C 20 54 55 42 45 20 5A 38 30 20 36 34 4B 20 30 2E 31 30 DEFM "Serial TUBE Z80 64K "+ver$ FC2B 0A DEFB 10 FC2C 0A DEFB 10 FC2D .StartupCR FC2D 0D DEFB 13 FC2E 00 DEFB 0 FC2F AF XOR A FC30 32 80 FF LD (ESCFLG),A ; Clear Escape flag FC33 CD EE FF CALL OSWRCH ; Send terminating zero byte FC36 CD 31 FF CALL WaitEnterCode ; Wait for ack and enter code if needed FC39 ; Fall through to command prompt if nothing entered FC39 .z% FC39 ; Minimal Command prompt FC39 ; ====================== FC39 .CmdOSLoop FC39 ED 7B 8A FF LD SP,(MEMTOP) ; Clear stack FC3D 21 4D FC LD HL,ErrorHandler ; Claim error handler FC40 22 FA FF LD (BRKV),HL FC43 3E 2A LD A,ASC"*" FC45 CD EE FF CALL OSWRCH ; Print '*' prompt FC48 21 67 FC LD HL,CmdOSCtrl FC4B AF XOR A FC4C CD F1 FF CALL OSWORD ; Read line to INPBUF FC4F 38 08 JR C,CmdOSEscape FC51 21 3F FF LD HL,INPBUF FC54 CD F7 FF CALL OS_CLI ; Execute command FC57 18 E0 JR CmdOSLoop ; and loop back for another command FC59 .CmdOSEscape FC59 3E 7E LD A,&7E FC5B CD F4 FF CALL OSBYTE ; Acknowledge Escape state FC5E FF RST &38 FC5F 11 DEFB 17 FC60 45 73 63 61 70 65 DEFM "Escape" FC66 00 NOP FC67 ; Control block for command prompt input FC67 ; -------------------------------------- FC67 .CmdOSCtrl FC67 3F FF DEFW INPBUF ; Input text to INPBUF FC69 41 DEFB INPBUFEND-INPBUF ; Size of INPBUF FC6A 20 DEFB &20 FC6B FF DEFB &FF ; Min=&20, Max=&FF FC39 OPT P*3+4 FC39 ; Error handlers FC39 ; ============== FC39 .InitErr FC39 3E C3 LD A,&C3 FC3B 32 38 00 LD (&38),A ; Put 'JP' opcode at &38 FC3E 2A BD FF LD HL,(ERRJMP+1) ; Get destination of ERRJMP FC41 22 39 00 LD (&39),HL FC44 C9 RET ; RST &38 generates an error FC45 .RestartHandler FC45 E1 POP HL FC46 22 82 FF LD (FAULT),HL ; Get address after RST &38 FC49 2A FA FF LD HL,(BRKV) FC4C E9 JP (HL) ; Vector via BRKV FC4D .ErrorHandler FC4D CD 53 FC CALL Report FC50 C3 BC FF JP CLICOM ; Report error and enter command prompt FC53 ; Printout routines FC53 ; ================= FC53 .Report FC53 CD E7 FF CALL OSNEWL FC56 2A 82 FF LD HL,(FAULT) ; Get error pointer FC59 23 INC HL FC5A CD 60 FC CALL PrString ; Print text after error number FC5D C3 E7 FF JP OSNEWL ; Print final NL FC60 ; Print string at HL FC60 ; ------------------ FC60 .PrString FC60 7E LD A,(HL) FC61 23 INC HL ; Get character FC62 A7 AND A FC63 C8 RET Z ; Return if zero byte FC64 CD E3 FF CALL OSASCI FC67 18 F7 JR PrString ; Print current character and loop back FC69 ; Print embedded string FC69 ; --------------------- FC69 .PrText FC69 E3 EX (SP),HL FC6A CD 60 FC CALL PrString ; Print from address on stack FC6D E3 EX (SP),HL ; Return updated address to stack FC6E .EventHandler FC6E .InterruptHandler FC6E .osFSC FC6E C9 RET FC6F ; MOS INTERFACE FC6F ; ============= FC6F ; FC6F ; FC6F ; OSRDCH - Wait for character from input stream FC6F ; ============================================= FC6F ; On exit, A =char, Cy=Escape flag FC6F ; FC6F .osRDCH FC6F C5 PUSH BC FC70 CD 83 FE CALL WaitByte ; Wait for character FC73 47 LD B,A ; Save character FC74 3A 80 FF LD A,(ESCFLG) FC77 87 ADD A,A ; Get Escape flag to Carry FC78 78 LD A,B FC79 C1 POP BC FC7A C9 RET ; Get character to A FC7B ; OSRDCH_IO - Request character via Tube FC7B ; ====================================== FC7B ; On exit, A =char, Cy=carry FC7B ; FC7B ; Tube data &00 -- Carry Char FC7B ; FC7B .osRDCH_IO FC7B AF XOR A FC7C CD 70 FE CALL SendCommand ; Send command &00 - OSRDCH FC7F .WaitCarryChar FC7F CD 83 FE CALL WaitByte FC82 87 ADD A,A ; Wait for Carry FC83 C3 83 FE JP WaitByte ; Wait for Char FC86 ; OSCLI - Send command line to host FC86 ; ================================= FC86 ; On entry, HL=>command string FC86 ; On exit, A, HL corrupted FC86 ; FC86 ; Tube data &02 string &0D -- &7F or &80 FC86 ; FC86 ; Should use a temporary stack in case command causes a FC86 ; data transfer that overwrites current stack. Needs to FC86 ; be able to cope with OSCLI calling code that then calls FC86 ; another OSCLI and be able to return recusively. FC86 ; FC86 .osCLI FC86 3E 02 LD A,&02 FC88 CD 70 FE CALL SendCommand ; Send command &02 - OSCLI FC8B CD 38 FE CALL SendString ; Send command string FC8E .CLIAck FC8E C5 PUSH BC FC8F D5 PUSH DE FC90 E5 PUSH HL ; Save registers FC91 2A 92 FF LD HL,(PROG) FC94 E5 PUSH HL ; Save current program FC95 CD 31 FF CALL WaitEnterCode ; Wait for ack and enter code if needed FC98 E1 POP HL FC99 22 92 FF LD (PROG),HL ; Restore current program FC9C E1 POP HL FC9D D1 POP DE FC9E C1 POP BC FC9F C9 RET ; Restore registers and return FCA0 ; OSBYTE - Byte MOS functions FCA0 ; =========================== FCA0 ; On entry, A, HL=OSBYTE parameters FCA0 ; On exit, A preserved FCA0 ; If A<&80, L=returned value FCA0 ; If A>&7F, HL, Carry=returned values FCA0 ; FCA0 .osBYTE FCA0 FE 80 CP &80 FCA2 30 15 JR NC,ByteHigh ; Jump for long OSBYTEs FCA4 ; FCA4 ; BYTELO FCA4 ; Tube data &04 X A -- X FCA4 ; FCA4 F5 PUSH AF FCA5 3E 04 LD A,&04 FCA7 CD 70 FE CALL SendCommand ; Send command &04 - OSBYTELO FCAA 7D LD A,L FCAB CD 60 FE CALL SendByte ; Send single parameter FCAE F1 POP AF FCAF F5 PUSH AF FCB0 CD 60 FE CALL SendByte ; Send function FCB3 CD 83 FE CALL WaitByte FCB6 6F LD L,A ; Get return value FCB7 F1 POP AF FCB8 C9 RET FCB9 ; FCB9 .ByteHigh FCB9 FE 82 CP &82 FCBB 28 32 JR Z,Byte82 ; Read memory high word FCBD FE 83 CP &83 FCBF 28 32 JR Z,Byte83 ; Read bottom of memory FCC1 FE 84 CP &84 FCC3 28 32 JR Z,Byte84 ; Read top of memory FCC5 ; FCC5 ; BYTEHI FCC5 ; Tube data &06 X Y A -- Cy Y X FCC5 ; FCC5 F5 PUSH AF FCC6 3E 06 LD A,&06 FCC8 CD 70 FE CALL SendCommand ; Send command &06 - OSBYTEHI FCCB 7D LD A,L FCCC CD 60 FE CALL SendByte ; Send parameter 1 FCCF 7C LD A,H FCD0 CD 60 FE CALL SendByte ; Send parameter 2 FCD3 F1 POP AF FCD4 CD 60 FE CALL SendByte ; Send function FCD7 FE 9D CP &9D FCD9 C8 RET Z ; Fast return with 'Fast BPUT' FCDA FE 8E CP &8E FCDC 28 B0 JR Z,CLIAck ; Check acknowledge with 'Enter language' FCDE C5 PUSH BC FCDF 47 LD B,A ; Save function FCE0 CD 83 FE CALL WaitByte FCE3 87 ADD A,A ; Wait for Carry FCE4 CD 83 FE CALL WaitByte FCE7 67 LD H,A ; Wait for return high byte FCE8 CD 83 FE CALL WaitByte FCEB 6F LD L,A ; Wait for return low byte FCEC 78 LD A,B FCED C1 POP BC FCEE C9 RET ; Restore function, BC FCEF .Byte82 FCEF 21 00 00 LD HL,&0000 FCF2 C9 RET ; Read memory high word FCF3 .Byte83 FCF3 2A 88 FF LD HL,(MEMBOT) FCF6 C9 RET ; Read bottom of memory FCF7 .Byte84 FCF7 2A 8A FF LD HL,(MEMTOP) FCFA C9 RET ; Read top of memory FCFB ; OSWORD - Various functions FCFB ; ========================== FCFB ; On entry, A =function FCFB ; HL=>control block FCFB ; FCFB .osWORD FCFB A7 AND A FCFC 28 62 JR Z,RDLINE ; OSWORD 0, jump to read line of text FCFE ; FCFE ; Tube data &08 A in_length block out_length -- block FCFE ; FCFE F5 PUSH AF ; Save function FCFF 3E 08 LD A,&08 FD01 CD 70 FE CALL SendCommand ; Send command &08 - OSWORD FD04 F1 POP AF FD05 F5 PUSH AF FD06 CD 60 FE CALL SendByte ; Send function FD09 C5 PUSH BC FD0A E5 PUSH HL ; Save BC, save control block address FD0B 87 ADD A,A FD0C 38 0E JR C,WordIndex ; If &80+, use control block entries FD0E 01 10 10 LD BC,&1010 FD11 FE 2A CP 42 FD13 30 0A JR NC,WordSend ; If 21..127, use 16 both ways FD15 21 38 FD LD HL,WordLengths FD18 06 00 LD B,0 FD1A 4F LD C,A FD1B 09 ADD HL,BC ; If 1..20, index into length table FD1C .WordIndex FD1C 46 LD B,(HL) FD1D 23 INC HL FD1E 4E LD C,(HL) ; B=send length, C=receive length FD1F .WordSend FD1F E1 POP HL FD20 E5 PUSH HL FD21 C5 PUSH BC ; Get control block address back, save lengths FD22 78 LD A,B FD23 CD 60 FE CALL SendByte ; Send send length FD26 48 LD C,B FD27 CD 42 FE CALL SendBlockC ; Send control block FD2A C1 POP BC FD2B E1 POP HL FD2C E5 PUSH HL ; Get lengths and control block address back FD2D 79 LD A,C FD2E CD 60 FE CALL SendByte ; Send receive length FD31 CD 51 FE CALL WaitBlockC ; Wait for returned control block FD34 E1 POP HL FD35 C1 POP BC FD36 F1 POP AF FD37 C9 RET ; Restore registers and return FD38 ; OSWORD control block lengths FD38 ; ---------------------------- FD38 .WordLengths FD38 00 DEFB &00 FD39 05 DEFB &05 ; &01 =TIME FD3A 05 DEFB &05 FD3B 00 DEFB &00 ; &02 TIME= FD3C 00 DEFB &00 FD3D 05 DEFB &05 ; &03 =Timer FD3E 05 DEFB &05 FD3F 00 DEFB &00 ; &04 Timer= FD40 04 DEFB &04 FD41 05 DEFB &05 ; &05 =IO FD42 05 DEFB &05 FD43 00 DEFB &00 ; &06 IO= FD44 08 DEFB &08 FD45 00 DEFB &00 ; &07 SOUND FD46 0E DEFB &0E FD47 00 DEFB &00 ; &08 ENVELOPE FD48 04 DEFB &04 FD49 05 DEFB &05 ; &09 =LOADLOMEM FD4A 01 DEFB &01 FD4B 09 DEFB &09 ; &0A =CHR$ FD4C 01 DEFB &01 FD4D 05 DEFB &05 ; &0B =Palette FD4E 05 DEFB &05 FD4F 00 DEFB &00 ; &0C Palette= FD50 00 DEFB &00 FD51 08 DEFB &08 ; &0D =Coord FD52 10 DEFB &10 FD53 19 DEFB &19 ; &0E =TIME$ FD54 19 DEFB &19 FD55 10 DEFB &10 ; &0F TIME$= FD56 10 DEFB &10 FD57 01 DEFB &01 ; &10 Net_Tx FD58 0D DEFB &0D FD59 0D DEFB &0D ; &11 Net_Args FD5A 00 DEFB &00 FD5B 80 DEFB &80 ; &12 Net_Rx FD5C 08 DEFB &08 FD5D 08 DEFB &08 ; &13 NetFS_Info FD5E 80 DEFB &80 FD5F 80 DEFB &80 ; &14 NetFS_Op FD60 ; RDLINE - Read a line of text FD60 ; ============================ FD60 ; On entry, A =0 FD60 ; HL=>control block FD60 ; On exit, A =undefined FD60 ; H =length of returned string FD60 ; Cy=0 ok, Cy=1 Escape FD60 ; FD60 ; Tube data &0A block -- &FF or &7F string &0D FD60 ; FD60 .RDLINE FD60 3E 0A LD A,&0A FD62 CD 70 FE CALL SendCommand ; Send command &0A - RDLINE FD65 23 INC HL FD66 23 INC HL FD67 0E 03 LD C,3 FD69 CD 45 FE CALL SendBlock ; Send control block FD6C 3E 07 LD A,&07 FD6E CD 60 FE CALL SendByte FD71 AF XOR A FD72 CD 60 FE CALL SendByte ; Send &0700 FD75 CD 83 FE CALL WaitByte FD78 87 ADD A,A ; Wait for response FD79 38 18 JR C,RdLineEscape FD7B 2B DEC HL FD7C 7E LD A,(HL) FD7D 2B DEC HL FD7E 6E LD L,(HL) FD7F 67 LD H,A ; Get address of text buffer FD80 C5 PUSH BC FD81 01 00 FF LD BC,&FF00 ; Save BC, initialise counter FD84 .RdLineLp FD84 CD 83 FE CALL WaitByte FD87 77 LD (HL),A ; Wait for a byte FD88 23 INC HL FD89 04 INC B ; Inc. pointer and count FD8A FE 0D CP 13 FD8C 20 F6 JR NZ,RdLineLp ; Loop until FD8E C5 PUSH BC FD8F E1 POP HL FD90 C1 POP BC ; Copy counter to H, restore BC FD91 AF XOR A FD92 C9 RET ; Return A=0, Cy=0 FD93 .RdLineEscape FD93 21 FF 00 LD HL,&00FF ; Return count=0 FD96 AF XOR A FD97 37 SCF FD98 C9 RET ; Return A=0, Cy=1 FD99 ; OSARGS - Read info on open file FD99 ; =============================== FD99 ; On entry, A =function FD99 ; HL=>control block FD99 ; E =handle FD99 ; On exit, A =returned value FD99 ; HL preserved FD99 ; E preserved FD99 ; FD99 ; Tube data &0C handle block function -- result block FD99 ; FD99 .osARGS FD99 C5 PUSH BC FD9A F5 PUSH AF ; Save BC, function FD9B 3E 0C LD A,&0C FD9D CD 70 FE CALL SendCommand ; Send command &0C - OSARGS FDA0 7B LD A,E FDA1 CD 60 FE CALL SendByte ; Send handle FDA4 0E 04 LD C,4 FDA6 CD 45 FE CALL SendBlock ; Send data FDA9 F1 POP AF FDAA CD 60 FE CALL SendByte ; Send function FDAD CD 83 FE CALL WaitByte FDB0 F5 PUSH AF ; Wait for result FDB1 0E 04 LD C,4 FDB3 CD 54 FE CALL WaitBlock ; Wait for data FDB6 F1 POP AF FDB7 C1 POP BC FDB8 C9 RET ; Get result, restore BC FDB9 ; OSBGET - Get a byte from open file FDB9 ; ================================== FDB9 ; On entry, H =handle FDB9 ; On exit, A =byte Read FDB9 ; H =preserved FDB9 ; Cy set if EOF FDB9 ; FDB9 ; Tube data &0E handle -- Carry byte FDB9 ; FDB9 .osBGET FDB9 3E 0E LD A,&0E FDBB CD 70 FE CALL SendCommand ; Send command &0E - OSBGET FDBE 7C LD A,H FDBF CD 60 FE CALL SendByte ; Send handle FDC2 C3 7F FC JP WaitCarryChar ; Wait for Carry and byte FDC5 ; OSBPUT - Put a byte to an open file FDC5 ; =================================== FDC5 ; On entry, A =byte to write FDC5 ; H =handle FDC5 ; On exit, A =preserved FDC5 ; H =preserved FDC5 ; FDC5 ; Tube data &10 handle byte -- &7F FDC5 ; FDC5 .osBPUT FDC5 F5 PUSH AF ; Save byte FDC6 3E 10 LD A,&10 FDC8 CD 70 FE CALL SendCommand ; Send command &10 - OSBPUT FDCB 7C LD A,H FDCC CD 60 FE CALL SendByte ; Send handle FDCF F1 POP AF FDD0 CD 60 FE CALL SendByte ; Send byte FDD3 F5 PUSH AF FDD4 CD 83 FE CALL WaitByte ; Wait for acknowledge FDD7 F1 POP AF FDD8 C9 RET ; Restore A, return FDD9 ; OSFIND - Open or Close a file FDD9 ; ============================= FDD9 ; On entry, A =function FDD9 ; H =handle or HL=>filename FDD9 ; On exit, A =zero or handle FDD9 ; FDD9 ; Tube data &12 function string &0D -- handle FDD9 ; &12 &00 handle -- &7F FDD9 ; FDD9 .osFIND FDD9 F5 PUSH AF ; Save function FDDA 3E 12 LD A,&12 FDDC CD 70 FE CALL SendCommand ; Send command &12 - OSFIND FDDF F1 POP AF FDE0 CD 60 FE CALL SendByte ; Send function FDE3 A7 AND A FDE4 20 09 JR NZ,OPEN ; If A<>0, jump to do OPEN FDE6 ; CLOSE FDE6 7C LD A,H FDE7 CD 60 FE CALL SendByte ; Send handle FDEA CD 83 FE CALL WaitByte ; Wait for acknowledgement FDED AF XOR A FDEE C9 RET ; Restore function FDEF .OPEN FDEF CD 38 FE CALL SendString ; Send pathname FDF2 C3 83 FE JP WaitByte ; Wait for and return handle FDF5 ; OSFILE - Operate on whole files FDF5 ; =============================== FDF5 ; On entry, A =function FDF5 ; HL=>control block FDF5 ; On exit, A =result FDF5 ; control block updated FDF5 ; FDF5 ; Tube data &14 block string function -- result block FDF5 ; FDF5 .osFILE FDF5 C5 PUSH BC FDF6 F5 PUSH AF ; Save BC and function FDF7 3E 14 LD A,&14 FDF9 CD 70 FE CALL SendCommand ; Send command &14 - OSFILE FDFC 23 INC HL FDFD 23 INC HL FDFE E5 PUSH HL ; Point to control block contents FDFF 0E 10 LD C,16 FE01 CD 45 FE CALL SendBlock ; Send 16-byte control block FE04 2B DEC HL FE05 7E LD A,(HL) FE06 2B DEC HL FE07 6E LD L,(HL) FE08 67 LD H,A ; Get pointer to pathname FE09 CD 38 FE CALL SendString ; Send pathname FE0C E1 POP HL ; Get control block address back FE0D F1 POP AF FE0E CD 60 FE CALL SendByte ; Send function FE11 CD 83 FE CALL WaitByte FE14 F5 PUSH AF ; Wait for result FE15 0E 10 LD C,16 FE17 CD 54 FE CALL WaitBlock ; Wait for 16-byte control block FE1A 2B DEC HL FE1B 2B DEC HL ; Restore HL FE1C F1 POP AF FE1D C1 POP BC ; Get result back, restore BC FE1E C9 RET FE1F ; OSGBPB - Multiple byte Read and write FE1F ; ===================================== FE1F ; On entry, A =function FE1F ; HL=>control block FE1F ; On exit, A =returned value FE1F ; control block updated FE1F ; FE1F ; Tube data &16 block function -- block Carry result FE1F ; FE1F .osGBPB FE1F C5 PUSH BC FE20 F5 PUSH AF ; Save BC and function FE21 3E 16 LD A,&16 FE23 CD 70 FE CALL SendCommand ; Send command &16 - OSGBPB FE26 0E 0D LD C,13 FE28 CD 45 FE CALL SendBlock ; Send 13-byte control block FE2B F1 POP AF FE2C CD 60 FE CALL SendByte ; Send function FE2F 0E 0D LD C,13 FE31 CD 54 FE CALL WaitBlock ; Wait for 13-byte control block FE34 C1 POP BC FE35 C3 7F FC JP WaitCarryChar ; Jump to get Carry and A FE38 ; Tube I/O routines FE38 ; ================= FE38 ; Send a string FE38 ; ------------- FE38 .SendString FE38 7E LD A,(HL) FE39 CD 60 FE CALL SendByte ; Send a character FE3C 23 INC HL ; Move to next character FE3D FE 0D CP 13 FE3F 20 F7 JR NZ,SendString ; Loop until sent FE41 C9 RET FE42 ; Send a block of data FE42 ; -------------------- FE42 .SendBlockC FE42 0D DEC C FE43 F8 RET M FE44 0C INC C ; Don't send if &81..&FF or &00 FE45 .SendBlock FE45 06 00 LD B,0 FE47 09 ADD HL,BC ; Point to end of data block FE48 .SendBlockLp FE48 2B DEC HL ; Move downwards through data FE49 7E LD A,(HL) FE4A CD 60 FE CALL SendByte ; Send a byte FE4D 0D DEC C FE4E 20 F8 JR NZ,SendBlockLp ; Loop for whole block FE50 C9 RET FE51 ; Wait for a block of data FE51 ; ------------------------ FE51 .WaitBlockC FE51 0D DEC C FE52 F8 RET M FE53 0C INC C ; Don't wait if &81..&FF or &00 FE54 .WaitBlock FE54 06 00 LD B,0 FE56 09 ADD HL,BC ; Point to end of data block FE57 .WaitBlockLp FE57 2B DEC HL ; Move downwards through data FE58 CD 83 FE CALL WaitByte FE5B 77 LD (HL),A ; Wait for a byte FE5C 0D DEC C FE5D 20 F8 JR NZ,WaitBlockLp ; Loop for whole block FE5F C9 RET FE60 ; OSWRCH - Send character to output stream FE60 ; ======================================== FE60 ; On entry, A =character FE60 ; On exit, A =preserved FE60 ; FE60 ; Tube data character -- FE60 ; FE60 .osWRCH ; WRCH is simply SendByte FE60 ; Tube Core I/O Routines FE60 ; ====================== FE60 ; Characters and commands are sent over the same single port FE60 ; Outward commands are escaped, and inward responses are escaped FE60 ; FE60 ; Outward FE60 ; x VDU x FE60 ; esc,esc VDU esc FE60 ; esc,n MOS function, control block follows FE60 ; FE60 ; Inward FE60 ; x char/byte x FE60 ; esc,esc char/byte esc FE60 ; esc,&00 BRK, error number+text+null follows FE60 ; esc,<&80 read returned control block set length FE60 ; esc,&8n Escape change, b0=new state FE60 ; esc,&9x,Y,X,A Event FE60 ; esc,&Ax reserved for networking FE60 ; esc,&Bx end transfer FE60 ; esc,&Cx,addr set address FE60 ; esc,&Dx,addr execute address FE60 ; esc,&Ex,addr start load from address FE60 ; esc,&Fx,addr start save from address FE60 ; All commands are data inward, except esc,&Fx which is data outward FE60 ; Send a byte, escaping it if needed FE60 ; ---------------------------------- FE60 ; On entry, A=byte to send FE60 ; On exit, A preserved, F corrupted FE60 ; FE60 .SendByte FE60 FE 7F CP esc FE62 CC 65 FE CALL Z,SendData ; If esc, prefix it with another esc FE65 .SendData FE65 F5 PUSH AF FE66 .SendWait FE66 DB 00 IN A,(TxStatus) FE68 E6 02 AND TxRDY FE6A 28 FA JR Z,SendWait ; Wait until data can be sent FE6C F1 POP AF FE6D D3 01 OUT (TxData),A ; Send data FE6F C9 RET FE70 ; Send an escaped command FE70 ; ----------------------- FE70 ; On entry, A=command FE70 ; On exit, All registers preserved FE70 .SendCommand FE70 F5 PUSH AF ; Save command byte FE71 .SendCmdLp FE71 CD 7E FE CALL ReadByte FE74 20 FB JR NZ,SendCmdLp ; Flush input FE76 3E 7F LD A,esc FE78 CD 65 FE CALL SendData ; Send esc prefix FE7B F1 POP AF FE7C 18 E7 JR SendData ; Send command byte FE7E ; Check if a byte is waiting, and read it if there FE7E ; ------------------------------------------------ FE7E ; On exit, F=Z - nothing waiting FE7E ; F=NZ - byte waiting, returned in A FE7E ; FE7E .ReadByte FE7E DB 00 IN A,(RxStatus) FE80 E6 01 AND RxRDY FE82 C8 RET Z ; Nothing waiting FE83 ; Continue into WaitByte FE83 ; Wait for a byte, decoding escaped data FE83 ; -------------------------------------- FE83 ; On exit, A =byte FE83 ; F =preserved FE83 ; FE83 .WaitByte FE83 C5 PUSH BC FE84 F5 PUSH AF ; Save BC and flags FE85 .WaitByteLp FE85 CD 9D FE CALL WaitData FE88 20 0E JR NZ,WaitByteOk ; Not esc, return it FE8A CD 9D FE CALL WaitData FE8D 28 09 JR Z,WaitByteOk ; esc,esc, return as esc FE8F E5 PUSH HL FE90 D5 PUSH DE FE91 CD A8 FE CALL WaitCommand ; Decode escaped command FE94 D1 POP DE FE95 E1 POP HL FE96 18 ED JR WaitByteLp ; Loop back to wait for a byte FE98 .WaitByteOk FE98 47 LD B,A FE99 F1 POP AF ; Save byte, get flags back FE9A 78 LD A,B FE9B C1 POP BC ; Put byte in A, restore BC FE9C C9 RET FE9D ; Wait for raw byte of data FE9D ; ------------------------- FE9D ; On exit, A =byte FE9D ; F =Z byte=esc, NZ byte<>esc FE9D ; FE9D .WaitData FE9D DB 00 IN A,(RxStatus) FE9F E6 01 AND RxRDY FEA1 28 FA JR Z,WaitData ; Wait until data present FEA3 DB 01 IN A,(RxData) FEA5 FE 7F CP esc FEA7 C9 RET ; Fetch data FEA8 ; Decode escaped command FEA8 ; ---------------------- FEA8 ; On entry, A=command FEA8 ; AF, BC, DE, HL can be trashed FEA8 ; FEA8 .WaitCommand FEA8 A7 AND A FEA9 28 13 JR Z,WaitError ; esc,&00 - error FEAB FA DC FE JP M,WaitTransfer ; esc,>&7F - data transfer FEAE ; esc,1..127 - read a control block FEAE ; --------------------------------- FEAE 4F LD C,A FEAF 06 00 LD B,0 ; Move count to BC FEB1 2A 90 FF LD HL,(CTRL) FEB4 09 ADD HL,BC ; Point to end of control block FEB5 .WaitLength FEB5 CD 83 FE CALL WaitByte FEB8 2B DEC HL ; Wait for a byte FEB9 77 LD (HL),A ; Store it FEBA 0D DEC C FEBB 20 F8 JR NZ,WaitLength ; Loop back FEBD C9 RET ; Return to WaitByte FEBE ; esc,&00 - error FEBE ; --------------- FEBE .WaitError FEBE 21 3F FF LD HL,ERRBUF ; Point to error buffer FEC1 36 FF LD (HL),&FF FEC3 23 INC HL FEC4 E5 PUSH HL ; Store error RST FEC5 CD 83 FE CALL WaitByte FEC8 77 LD (HL),A FEC9 23 INC HL ; Store error number FECA .WaitErrorLp FECA CD 83 FE CALL WaitByte FECD 77 LD (HL),A FECE 23 INC HL ; Store error character FECF A7 AND A FED0 20 F8 JR NZ,WaitErrorLp ; Loop until final &00 FED2 E1 POP HL FED3 7E LD A,(HL) ; Get error number FED4 23 INC HL FED5 B6 OR (HL) FED6 CA 00 FC JP Z,STARTUP ; If error 0,"" do a RESET FED9 C3 BC FF JP ERRJMP ; Enter error handler, no return FEDC ; esc,&8n - Escape change FEDC ; ----------------------- FEDC .WaitTransfer FEDC FE C0 CP &C0 FEDE 30 27 JR NC,WaitStart FEE0 FE A0 CP &A0 FEE2 30 1A JR NC,WaitEnd FEE4 FE 90 CP &90 FEE6 30 05 JR NC,WaitEvent FEE8 0F RRCA FEE9 32 80 FF LD (ESCFLG),A FEEC C9 RET ; Set error flag from b0 FEED ; esc,&9x - Event FEED ; --------------- FEED .WaitEvent FEED CD 83 FE CALL WaitByte FEF0 67 LD H,A ; Fetch event Y parameter FEF1 CD 83 FE CALL WaitByte FEF4 6F LD L,A ; Fetch event X parameter FEF5 CD 83 FE CALL WaitByte ; Fetch event A parameter FEF8 E5 PUSH HL FEF9 2A FC FF LD HL,(EVENTV) ; Get event vector FEFC E3 EX (SP),HL FEFD C9 RET ; Dispatch and return FEFE ; esc,&Ax - Reserved FEFE ; ------------------ FEFE .WaitEnd FEFE FE B0 CP &B0 FF00 D8 RET C ; Return to WaitByte FF01 ; esc,&Bx - End transfer FF01 ; ---------------------- FF01 E1 POP HL FF02 E1 POP HL FF03 E1 POP HL ; Drop data from stack to fall FF04 E1 POP HL FF05 E1 POP HL ; out of WaitSave/WaitLoad loop FF06 C9 RET ; Return to WaitByte FF07 ; esc,&C0+ - Start transfer FF07 ; ------------------------- FF07 .WaitStart FF07 F5 PUSH AF FF08 21 8C FF LD HL,ADDR ; Save command, point to ADDR FF0B 0E 04 LD C,4 FF0D CD 54 FE CALL WaitBlock ; Wait for 4-byte data address FF10 2A 8C FF LD HL,(ADDR) FF13 F1 POP AF ; Get address to HL FF14 FE D0 CP &D0 FF16 D8 RET C ; esc,&Cx - set address for later execution FF17 FE E0 CP &E0 FF19 DA 3E FF JP C,CallCode ; esc,&Dx - enter code immediately FF1C FE F0 CP &F0 FF1E 30 07 JR NC,WaitSave ; esc,&Fx - save data FF20 .WaitLoad FF20 CD 83 FE CALL WaitByte FF23 77 LD (HL),A ; esc,&Ex - load data FF24 23 INC HL FF25 18 F9 JR WaitLoad ; Loop until terminated by esc,&Bx FF27 .WaitSave FF27 7E LD A,(HL) FF28 CD 60 FE CALL SendByte ; esc,&Fx - save data FF2B 23 INC HL FF2C CD 7E FE CALL ReadByte ; Poll input for termination FF2F 18 F6 JR WaitSave ; Loop until terminated by esc,&Bx FF31 ; Wait for acknowledge and enter code if >&7F FF31 ; ------------------------------------------- FF31 .WaitEnterCode FF31 CD 83 FE CALL WaitByte FF34 87 ADD A,A FF35 D0 RET NC ; Wait for ack, exit if <&80 FF36 2A 8C FF LD HL,(ADDR) ; Fetch transfer address FF39 ; EnterCode - Enter code at HL FF39 ; ---------------------------- FF39 ; All registers trashable FF39 ; FF39 .EnterCode FF39 22 92 FF LD (PROG),HL ; Set as current program FF3C .z% FF3C E5 PUSH HL FF3D 11 06 00 LD DE,6 FF40 19 ADD HL,DE ; HL+1=>Offset to copyright message FF41 7E LD A,(HL) FF42 23 INC HL FF43 5E LD E,(HL) ; A=ROM type, DE=Offset to copyright message FF44 E1 POP HL FF45 E5 PUSH HL FF46 19 ADD HL,DE ; HL=>Copyright message FF47 22 82 FF LD (FAULT),HL FF4A 5F LD E,A ; Set previous error, save ROM type in E FF4B 7E LD A,(HL) FF4C A7 AND A FF4D 20 4E JR NZ,EnterRunCode ; Look for &00,"(C)" FF4F 23 INC HL FF50 7E LD A,(HL) FF51 FE 28 CP ASC"(" FF53 20 48 JR NZ,EnterRunCode FF55 23 INC HL FF56 7E LD A,(HL) FF57 FE 43 CP ASC"C" FF59 20 42 JR NZ,EnterRunCode FF5B 23 INC HL FF5C 7E LD A,(HL) FF5D FE 29 CP ASC")" FF5F 20 3C JR NZ,EnterRunCode FF61 ; &00,"(C)" exists, check ROM type byte FF61 ; ------------------------------------- FF61 7B LD A,E FF62 7E LD A,(HL) FF63 E6 4F AND &4F ; Keep Language and CPU bits FF65 FE 40 CP &40 FF67 38 1B JR C,errNotLanguage ; <&40, no language bit set FF69 FE 48 CP &48 FF6B 28 30 JR Z,EnterRunCode ; CPU=8, Z80 code FF6D .errNotZ80Code FF6D FF RST &38 FF6E 00 DEFB 0 FF6F 54 68 69 73 20 69 73 20 6E 6F 74 20 5A 38 30 20 63 6F 64 65 DEFM "This is not Z80 code" FF83 00 DEFB 0 FF84 .errNotLanguage FF84 FF RST &38 FF85 00 DEFB 0 FF86 54 68 69 73 20 69 73 20 6E 6F 74 20 61 20 6C 61 6E 67 75 61 67 65 DEFM "This is not a language" FF9C 00 DEFB 0 FF9D .EnterRunCode FF9D E1 POP HL FF3C OPT P*3+4 FF3C 3E 01 LD A,1 FF3E .CallCode FF3E E9 JP (HL) FF3F DEFM STRING$((&FC00-P%)AND(P%<&FC00),CHR$&FF) FF3F DEFM STRING$((&FC80-P%)AND(P%<&FC80),CHR$&FF) FF3F DEFM STRING$((&FD00-P%)AND(P%<&FD00),CHR$&FF) FF3F DEFM STRING$((&FD80-P%)AND(P%<&FD80),CHR$&FF) FF3F DEFM STRING$((&FE00-P%)AND(P%<&FE00),CHR$&FF) FF3F DEFM STRING$((&FE80-P%)AND(P%<&FE80),CHR$&FF) FF3F DEFM STRING$((&FF20-P%)AND(P%<&FF00),CHR$&FF) FF3F .ERRBUF ; About 40 bytes for error strings/system stack FF3F .INPBUF ; Also use for input buffer FF3F 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 DEFM STRING$(&FF80-P%,CHR$&00) FF80 .INPBUFEND FF80 .SystemStack ; Stack grows down from here FF80 ; &FF80 FF80 .ESCFLG FF80 00 DEFB &00 ; Escape flag FF81 ; &FF81 FF81 .FF81 FF81 00 DEFB &00 ; TempA FF82 ; &FF82 FF82 .FAULT FF82 12 FC DEFW StartupMessage ; Fault pointer FF84 ; &FF84 FF84 .ERRDEF FF84 4D FC DEFW ErrorHandler ; Default error handler FF86 ; &FF86 FF86 .LPTR FF86 2D FC DEFW StartupCR ; Command line tail pointer FF88 ; &FF88 FF88 .MEMBOT FF88 00 01 DEFW &0100 ; Bottom of available memory FF8A ; &FF8A FF8A .MEMTOP FF8A 00 FC DEFW STARTUP ; Top of available memory FF8C ; &FF8C FF8C .ADDR FF8C 00 00 DEFW &0000 FF8E 00 00 DEFW &0000 ; Transfer address FF90 ; &FF90 FF90 .CTRL FF90 3F FF DEFW ERRBUF ; Control block FF92 ; &FF92 FF92 .PROG FF92 00 FC DEFW STARTUP ; Current program FF94 ; &FF94 FF94 .LFF94 FF94 00 NOP FF95 ; &FF95 FF95 .LFF95 FF95 C9 RET FF96 C9 RET FF97 C9 RET FF98 ; &FF98 FF98 .LFF98 FF98 C9 RET FF99 C9 RET FF9A C9 RET FF9B ; &FF9B FF9B .LFF9B FF9B C9 RET FF9C C9 RET FF9D C9 RET FF9E ; &FF9E FF9E .LFF9E FF9E C9 RET FF9F C9 RET FFA0 C9 RET FFA1 ; &FFA1 FFA1 .RDDEC FFA1 C9 RET FFA2 C9 RET FFA3 C9 RET FFA4 ; &FFA4 FFA4 .RDHEX FFA4 C9 RET FFA5 C9 RET FFA6 C9 RET FFA7 ; &FFA7 FFA7 .OSQUIT FFA7 C9 RET FFA8 C9 RET FFA9 C9 RET FFAA ; &FFAA FFAA .PRHEX FFAA C9 RET FFAB C9 RET FFAC C9 RET FFAD ; &FFAD FFAD .PR2HEX FFAD C9 RET FFAE C9 RET FFAF C9 RET FFB0 ; &FFB0 FFB0 .USERINT FFB0 C9 RET FFB1 C9 RET FFB2 C9 RET FFB3 ; &FFB3 FFB3 .PRTEXT FFB3 C3 69 FC JP PrText FFB6 ; &FFB6 FFB6 .SPARE1 FFB6 C9 RET FFB7 C9 RET FFB8 C9 RET FFB9 ; &FFB9 FFB9 .CLICOM FFB9 C3 B9 FF JP CLICOM FFBC OPT P*3+4 FFBC ; &FFB9 FFBC .CLICOM FFBC C3 39 FC JP CmdOSLoop FFBC OPT P*3+4 FFBC ; &FFBC FFBC .ERRJMP FFBC C3 45 FC JP RestartHandler FFBF ; &FFBF FFBF .INITERR FFBF C3 39 FC JP InitErr FFC2 ; &FFC2 FFC2 .SPARE2 FFC2 C9 RET FFC3 C9 RET FFC4 C9 RET FFC5 ; &FFC5 FFC5 .SPARE3 FFC5 C9 RET FFC6 C9 RET FFC7 C9 RET FFC8 ; &FFC8 FFC8 .SPARE4 FFC8 C9 RET FFC9 C9 RET FFCA C9 RET FFCB ; FILE I/O ENTRIES FFCB ; ================ FFCB ; &FFCB FFCB .OSFSC FFCB C3 6E FC JP osFSC FFCE ; &FFCE FFCE .OSFIND FFCE C3 D9 FD JP osFIND FFD1 ; &FFD1 FFD1 .OSGBPB FFD1 C3 1F FE JP osGBPB FFD4 ; &FFD4 FFD4 .OSBPUT FFD4 C3 C5 FD JP osBPUT FFD7 ; &FFD7 FFD7 .OSBGET FFD7 C3 B9 FD JP osBGET FFDA ; &FFDA FFDA .OSARGS FFDA C3 99 FD JP osARGS FFDD ; &FFDD FFDD .OSFILE FFDD C3 F5 FD JP osFILE FFE0 ; CHARACTER I/O ENTRIES FFE0 ; ===================== FFE0 ; &FFE0 FFE0 .OSRDCH FFE0 C3 6F FC JP osRDCH FFE3 ; &FFE3 FFE3 .OSASCI FFE3 FE 0D CP 13 FFE5 20 07 JR NZ,OSWRCH FFE7 ; &FFE7 FFE7 .OSNEWL FFE7 3E 0A LD A,10 FFE9 CD EE FF CALL OSWRCH FFEC ; &FFEC FFEC .OSWRCR FFEC 3E 0D LD A,13 FFEE ; &FFEE FFEE .OSWRCH FFEE C3 60 FE JP osWRCH FFF1 ; MOS ENTRIES FFF1 ; =========== FFF1 ; &FFF1 FFF1 .OSWORD FFF1 C3 FB FC JP osWORD FFF4 ; &FFF4 FFF4 .OSBYTE FFF4 C3 A0 FC JP osBYTE FFF7 ; &FFF7 FFF7 .OS_CLI FFF7 C3 86 FC JP osCLI FFFA ; SYSTEM VECTORS FFFA ; ============== FFFA ; &FFFA FFFA .BRKV FFFA 4D FC DEFW ErrorHandler FFFC ; &FFFC FFFC .EVENTV FFFC 6E FC DEFW EventHandler FFFE ; &FFFE FFFE .IRQV FFFE 6E FC DEFW InterruptHandler