REM > Client/src REM Source for Z80 Tube Client : A%=0:X%=1:os%=(USR&FFF4 AND &FF00)DIV256:IFos%=6 AND PAGE>&8000:PRINT"Running Z80...":SYS "OS_GetEnv" TO A$:OSCLI"TextToBas "+MID$(A$,INSTR(A$," ",1+INSTR(A$," ")))+" -crunch *Z80":END : load%=&F000:DIM mcode% &1100 : FOR P=0 TO 1 P%=load%:O%=mcode% [OPT P*3+4 ; Z80 Tube Client Source Code ; =========================== ; Commentary Copyright (C) J.G.Harston ; See mdfs.net/Software/Tube .RESET ; On RESET, ROM is paged into low memory. ROM is paged out by an ; instruction fetch from an address in the top 32K of memory. DI LD DE,RESET:LD HL,&0000 ; Copy code from low memory to LD BC,&1000:LDIR ; high memory JP STARTUP ; Enter code in high memory DEFM "Copyright Acorn Computers Ltd. 1984":DEFB 13 ; Unused data ; ----------- DEFB &48:DEFB &3A:DEFB &7D:DEFB &3C DEFB &B7:DEFB &C4:DEFB &C0:DEFB &2C:DEFB &3A:DEFB &22:DEFB &3A:DEFB &B7 DEFB &C4:DEFB &F1:DEFB &2C:DEFB &F1:DEFB &21:DEFB &1B:DEFB &3A:DEFB &34 DEFB &7E:DEFB &3D:DEFB &C2:DEFB &AB:DEFB &2B:DEFB &21:DEFB &EC:DEFB &3B DEFB &7E:DEFB &B7:DEFB &C2:DEFB &34:DEFB &2B:DEFB &21:DEFB &4A:DEFB &3B DEFB &7E:DEFB &B7:DEFB &C2:DEFB &34:DEFB &2B:DEFB &21:DEFB &58:DEFB &3D DEFB &23:DEFB &01:DEFB &06:DEFB &00:DEFB &11:DEFB &EC:DEFB &3B ; NMI code, paged in when NMI occurs ; ---------------------------------- .LF066 JP LFC61 ; Jump to NMI handler in high memory ; Acknowledgments ; --------------- DEFM "The Business Systems Group would like to thank" DEFM "Mike Bolley,Mike & Allen Boothroyd,Richard Clayton," DEFM "Andrew Gordon,Chris Hall,Kim Spence-Jones,Paul Overell," DEFM "David Parkinson,John Tuten and Eric the half TUBE" DEFM "The BSG is Big Arthur The Toucan,J Mark Carrington," DEFM "Howard Fisher,Ian G Jack,Neil Robinson,Simon Woodward," DEFM "John Corrall,Toby Cross,Ian Miller,Boris Southears" ; Unused data ; ----------- DEFM "ror(s)":DEFB &00 DEFM " Warning(s)":DEFB &00 DEFB &0E:DEFB &00:DEFB &3A:DEFB &00:DEFB &3B:DEFB &47:DEFB &CD:DEFB &48 DEFB &1A:DEFB &C3:DEFB &6B:DEFB &2B:DEFB &CD:DEFB &16:DEFB &2D:DEFB &21 DEFB &CF:DEFB &2C:DEFB &CD:DEFB &19:DEFB &2D:DEFB &CD:DEFB &CA:DEFB &19 DEFB &C3:DEFB &FD:DEFB &2C DEFM "REPT/IRP/IRPC/MACRO":DEFB 0 DEFM "Unterminated ":DEFB 0 DEFB &CD:DEFB &16:DEFB &2D DEFB &21:DEFB &26:DEFB &2D:DEFB &CD:DEFB &19:DEFB &2D:DEFB &CD:DEFB &CA DEFB &19:DEFB &3E:DEFB &0D:DEFB &CD:DEFB &FC:DEFB &18:DEFB &3E:DEFB &0A DEFB &CD:DEFB &FC:DEFB &18:DEFB &3A:DEFB &37:DEFB &3D:DEFB &3C:DEFB &C8 DEFB &3E:DEFB &0D:DEFB &CD:DEFB &4E:DEFB &47:DEFB &3E:DEFB &0A:DEFB &C3 DEFB &4E:DEFB &47:DEFB &21:DEFB &E3:DEFB &2C:DEFB &E5:DEFB &CD:DEFB &77 DEFB &19:DEFB &E1:DEFB &3A:DEFB &37:DEFB &3D:DEFB &3C:DEFB &C8:DEFB &C3 DEFB &4F:DEFB &43 DEFM "Conditional":DEFB 0 DEFM "Symbols:":DEFB 13:DEFB 10:DEFB 0 DEFM "Macros:":DEFB 13:DEFB 10:DEFB 0 DEFB &21:DEFB &E2:DEFB &FF:DEFB &39:DEFB &EB DEFB &2A:DEFB &AC:DEFB &3C:DEFB &CD:DEFB &82:DEFB &0D:DEFB &D2:DEFB &5D ; STARTUP - Startup routine ; ========================= ; Tube data via R1, string &00 -- via R2, &7F or &80 ; .STARTUP LD SP,SysStack ; Initialise a stack CALL InitErr ; Initialise RST &38 error call LD A,&FF:LD I,A:IM 2:EI ; Set interrupts to vector via &FFFE CALL PrText ; Print banner DEFB 22:DEFB 8 ; MODE 8, usually gives MODE 0 DEFB 13:DEFM "Acorn TUBE Z80 64K 1.20" DEFB 13:DEFB 13:DEFB 0 ; NEWL, NEWL CALL WaitR2 ; Wait for response from TubeR2 ; Response is ignored CALL InitFF ; Set up OSWORD &FF code LD A,&FD:LD HL,&FF00:CALL osBYTE ; Fetch BREAK type LD A,L:OR A:JP Z,CLIPrompt ; If a soft BREAK, enter CLI Prompt LD A,&0F:LD HL,&0001:CALL osBYTE ; Clear buffers JP EnterCode ; Try to enter current program or boot CPM .LF2CB CALL OSNEWL ; Minimal Command prompt ; ====================== .CLIPrompt ; Default language LD SP,SysStack ; Set up a stack .LF2D1 LD A,(ESCFLG):BIT 7,A:JR Z,LF2E0 ; Skip if no pending Escape .LF2D8 LD A,&7E:LD HL,&0000:CALL osBYTE ; Acknowledge Escape .LF2E0 LD A,&2A:CALL osWRCH ; Print '*' prompt LD HL,LFC9D:XOR A:CALL osWORD ; Read a line JP C,LF2FA ; Jump if Escape pressed LD HL,LFCB0:CALL osCLI ; Pass line to OSCLI JR CLIPrompt ; Loop back for another .LF2F7 CALL OSNEWL .LF2FA LD A,&7E:CALL osBYTE ; Ack. escape condition RST &38:DEFB 0:DEFM "Escape":DEFB 0; Generate error ; *GO - call or enter machine code ; ======================================= .LF308 INC DE:LD A,(DE) ; Fetch next character AND &DF:CP ASC"O":JP NZ,LF7CC ; Not '*GO', jump to pass to Tube CALL SkipSpace1:LD B,&00 ; Skip past any spaces CALL ScanHex:CALL SkipSpaces ; Read hex value and move past spaces CP &0D:JP NZ,LF7CC ; More parameters, pass to Tube to deal with LD A,(ADDR+0):LD (PROG+0),A ; Set program start to address read LD A,(ADDR+1):LD (PROG+1),A JP LF7DF ; Jump to execute in non-CPM mode ; *S - set memory ; ======================== .LF330 CALL SkipSpace1:LD B,&00 ; Skip past any spaces CALL ScanHex:CALL SkipSpaces ; Read hex value and move past spaces CP &0D:JP NZ,LF7CC ; More parameters, pass to Tube to deal with LD A,&04:LD HL,&0001:CALL OSBYTE ; Cursor keys return characters LD A,L:LD (OLDFX4),A ; Save old cursor key setting LD HL,(ADDR) ; Get initial address .LF34F CALL OSNEWL CALL Pr2Hex:CALL LF41D ; Print address, then space .LF358 LD A,(HL):CALL LF40D ; Get byte, print character or dot CALL LF41D:LD A,(HL) ; Print a space, get byte again CALL PrHex:PUSH HL ; Print byte as hex, save address LD B,&01:LD HL,&0000 ; B=fetch 1 digit, HL=accumulator CALL OSRDCH:CALL LF440 ; Get key, add hex digit to accumulator LD B,&00:LD E,L:POP HL ; E=hex digit, restore address CP &8A:JR Z,LF39E ; If up, jump to move back CP &8B:JR Z,LF39B ; If down, jump to move forward CP &01:JP NZ,LF3A1 ; If not a valid digit, jump to exit LD A,(HL) ; Get current byte SLA A:SLA A:SLA A:SLA A ; Multiply by 16 ADD A,E:LD (HL),A ; Add entered digit and store LD A,&08 ; Move back 4 chars to overwrite CALL osWRCH:CALL osWRCH CALL osWRCH:CALL osWRCH JR LF358 ; Loop back for another keypress .LF39B INC HL:JR LF34F ; Increment address, jump to display .LF39E DEC HL:JR LF34F ; Decrement address, jump to display ; ; Exit from *S ; ------------ .LF3A1 LD A,(OLDFX4):LD L,A ; Get old cursor key status LD H,&00:LD A,&04:CALL OSBYTE ; Restore cursor key state CALL OSNEWL POP DE:POP BC:POP AF:RET ; Restore registers and return ; *D () - dump memory ; ================================ .LF3B3 CALL SkipSpace1:LD B,&00 ; Skip past any spaces CALL ScanHex ; Read hex value CP &0D:JR Z,LF3CF ; No more parameters, jump to dump CP &20:JP NZ,LF7CC ; Wasn't a hex number, jump to pass to Tube LD HL,(ADDR) ; Get first address for start address CALL SkipSpaces:CALL ScanHex ; Skip spaces and read hex value for end address JR LF3D2 ; Jump to dump between addresses ; ; *D ; --------- .LF3CF LD HL,(ADDR) .LF3D2 LD DE,(ADDR) .LF3D6 LD A,(ESCFLG) BIT 7,A:JP NZ,LF2F7 ; If Escape set, jump to exit CALL OSNEWL:CALL Pr2Hex ; Print address LD B,&08:PUSH HL ; B=8 for eight bytes, save address .LF3E7 CALL LF41D:LD A,(HL):CALL PrHex ; Print space, the hex byte INC HL:DJNZ LF3E7 ; Loop to print 8 bytes LD B,&08:POP HL ; B=8 for eight bytes, get address back CALL LF41D ; Print another space .LF3F7 LD A,(HL):CALL LF40D ; Print byte as a character INC HL:DJNZ LF3F7 ; Loop to print 8 characters CALL LF423:JP NC,LF406 ; Check address, jump to exit if at end JR LF3D6 ; Loop back to dump another 8 bytes ; ; Exit *D ; ------- .LF406 CALL OSNEWL POP DE:POP BC:POP AF:RET ; Restore registers and return ; ; Print character or dot ; ====================== .LF40D CP &20:JR C,LF417 ; Control character, print a dot CP &7F:JR NC,LF417 ; DEL or topbit set, print a dot JR LF419 ; Jump to print character .LF417 LD A,ASC"." ; Print a dot if not SPC-'~' .LF419 CALL osWRCH:RET ; .LF41D LD A,&20:CALL osWRCH:RET ; Print a space ; ; Check address against end ; ------------------------- .LF423 PUSH HL:LD BC,&0008 CP A:SBC HL,BC ; HL=ADDR-8 JR NC,LF432 ; If ADDR-8>0, jump to check end LD HL,&0000 ; ADDR-8<0, replace with &0000 CP A:JR LF434 ; Clear carry, jump to check end .LF432 POP HL:PUSH HL ; Get address back .LF434 DEC HL:SBC HL,DE ; Check against end address in DE POP HL:RET ; Restore address, C=not at end ; Scan hex value from line ; ======================== ; On entry, DE=>first hex character to scan ; B=1, scan one digit ; B<>1, scan all digits ; On exit, DE=>first nonhex character ; BC,HL preserved ; A=first nonhex character .ScanHex LD (CTRL),HL:LD HL,&0000 ; Save HL, clear accumulator .LF43F LD A,(DE) ; Get current character ; ; Check A for hex digit ; --------------------- .LF440 BIT 6,A:JR Z,LF446 ; If lower case, skip past AND &DF ; Convert lower case to upper .LF446 CP &30:JP M,LF46D ; If <'0', exit CP &47:JP P,LF46D ; If >'G', exit CP &3A:JR C,LF45B ; If '0'..'9', add to accumulator CP &41:JP M,LF46D ; If >'9', <'A', exit ADD A,&09 ; Convert letter .LF45B AND &0F ; Keep bottom nybble ADD HL,HL:ADD HL,HL ; *16 ADD HL,HL:ADD HL,HL OR L:LD L,A ; Add in current digit LD A,&01:CP B:RET Z ; If B=1, return single digit INC DE ; Step to next character LD (ADDR),HL:JR LF43F ; Store value and loop for next digit .LF46D LD HL,(CTRL):RET ; Return HL and return ; Pr2Hex - Print HL as hex string ; =============================== .Pr2Hex LD A,H:CALL PrHex:LD A,L ; Prhex - Print a as hex string ; ============================= .PrHex PUSH AF RRCA:RRCA:RRCA:RRCA CALL LF47F:POP AF .LF47F AND &0F:ADD A,&30 CP &3A:JP M,osWRCH ADD A,&07:JP osWRCH ; *CPM - boot CPM ; =============== .LF48D INC DE:LD A,(DE):AND &DF ; Get next character in upper case CP ASC"P":JP NZ,LF7CC ; Not '*CP', jump to pass to Tube INC DE:LD A,(DE):AND &DF ; Get next character in upper case CP ASC"M":JP NZ,LF7CC ; Not '*CPM', jump to pass to Tube CALL SkipSpace1 ; Skip any spaces CP &0D:JP NZ,LF7CC ; More characters, jump to pass to Tube JR LF4CF ; Jump to boot CPM .LF4A9 CALL PrText ; Print in-line text DEFM "Insert CP/M System disc in drive A":DEFB 0 ; Boot CPM - Load BIOS, BDOS and CCP ; ================================== .LF4CF LD A,&E5:LD HL,&0001:CALL osBYTE ; Disable Escape LD HL,LF582:CALL LF54A ; Load BIOS code from sectors 0-7 LD HL,&EB00:LD DE,&EAF0 ; Move code down over DFS names LD BC,&00F0:LDIR LD HL,&EBF0:LD DE,&EBE0 ; Move code down over DFS addresses LD BC,&0600:LDIR CALL LoadCCP ; Load CCP and BDOS from sectors 8-29 LD A,(&D400) ; Get first byte from CCP CP &C3:JP Z,LF522 ; If it is 'JP opcode, jump to enter BDOS LD A,&E5:LD HL,&0000:CALL osBYTE ; Enable Escape CALL OSNEWL ; Print newline ; Generate error RST &38:DEFB 0:DEFM "Not a CP/M System disc":DEFB 0 ; .LF522 LD HL,DefaultError:LD (BRKV),HL ; Set up default error handler LD A,&90:LD (LFCA3),A ; Set flag LD HL,&0100:CALL osBYTE ; Do *TV 0,1 CALL PrText:DEFB &16:DEFB 0 ; Do MODE 0 JP &EA00 ; Enter BDOS ; Load CCP - also loads BDOS ; ========================== .LoadCCP LD HL,LF58D:CALL LF54A ; Load CCP from sectors 8-9 LD HL,LF598:CALL LF54A ; Load CCP and BDOS from sectors 10-19 LD HL,LF5A3 ; Load BDOS from sectors 20-29 .LF54A CALL DiskAccess ; Read data from disk OR A ; Check returned status RET Z ; Return if no error RST &38:DEFB &C7:DEFM "Disc fault":DEFB 0 ; Generate error ; Load from FM disk using control block pointed to by HL ; ====================================================== .DiskAccess LD B,&04 ; We're going to do four main passes, .LF55E LD C,B ; and in each pass we try ten times LD B,&0A ; before reseeking track zero .LF561 LD A,&7F ; OSWORD &7F - DiskOpFM CALL osWORD ; Call WORD code LD DE,&000A EX DE,HL ; Save pointer in DE .LF56A ADD HL,DE ; Point to result byte LD A,(HL) ; Fetch it LD (RESULT),A ; Store it in main result store EX DE,HL ; Get pointer back to HL CP &12 ; DskFM_ReadOnly? RET Z ; Return if so OR A ; DskFM_Ok? RET Z ; Return is so DJNZ LF561 ; Loop back up to ten times to retry LD A,(HL) ; Get drive number from control block CALL Seek0 ; Seek track 0 on this drive LD B,C DJNZ LF55E ; Loop back up to 4 times LD A,(RESULT) ; Get result byte. By here it will be RET ; a error other than ReadOnly .LF582 ; Load BIOS code DEFB &00 ; Drive 0 DEFW &E9F0:DEFW &0000 ; Load to &0000E9F0 DEFB &03:DEFB &53 ; Command=Load DEFB &00 ; Track 0 DEFB &00 ; Sector 0 DEFB &28 ; 8 sectors DEFB &FF ; .LF58D ; Load start of CCP code DEFB &00 ; Drive 0 DEFW &D400:DEFW &0000 ; Load to &0000D400 DEFB &03:DEFB &53 ; Command=Load DEFB &00 ; Track 0 DEFB &08 ; Sector 8 DEFB &22 ; 2 sectors DEFB &FF ; .LF598 ; Load CCP and BDOS code DEFB &00 ; Drive 0 DEFW &D600:DEFW &0000 ; Load to &0000D600 DEFB &03:DEFB &53 ; Command=Load DEFB &01 ; Track 1 DEFB &00 ; Sector 0 DEFB &2A ; 10 sectors DEFB &FF ; .LF5A3 ; Load end of BDOS code DEFB &00 ; Drive 0 DEFW &E000:DEFW &0000 ; Load to &0000E000 DEFB &03:DEFB &53 ; Command=Load DEFB &02 ; Track 2 DEFB &00 ; Sector 0 DEFB &2A ; 10 sectors DEFB &FF ; Initialise OSWORD &FF code in the I/O processor ; =============================================== ; Copies the code over, copies USERV to the code, and then sets ; USERV to call the code. ; .InitFF DI ; Disable interrupts while copying code LD HL,&2500 ; Copy to &2500 in i/o processor LD DE,LFD30 ; from &FD30 in Z80 processor LD B,&AA ; 170 bytes CALL LF5F3 ; Copy OSWORD &FF code over LD HL,&0200 ; Copy from &0200 in i/o processor .LF5BD LD DE,LFDDC ; to &FDDC in Z80 processor LD B,&02 ; 2 bytes CALL LF5DD ; Fetch USERV LD HL,&2503 ; Copy to &2503 in i/o processor LD DE,LFDDC ; from &FDDC in Z80 processor LD B,&02 ; 2 bytes CALL LF5F3 ; Set oldUSERV in OSWORD &FF code LD HL,&0200 ; Copy to &0200 in i/o processor LD DE,LFDDA ; from &FDDA in Z80 processor LD B,&02 ; 2 bytes CALL LF5F3 ; Set USERV to point to OSWORD &FF code EI ; Turn interrupts back on RET ; .LF5DD LD (LF609),HL PUSH HL LD HL,LF609 LD A,&05 CALL OSWORD LD A,(LF60D) LD (DE),A INC DE POP HL INC HL DJNZ LF5DD RET ; .LF5F3 LD (LF609),HL LD A,(DE) LD (LF60D),A PUSH HL LD HL,LF609 LD A,&06 CALL OSWORD INC DE POP HL INC HL DJNZ LF5F3 RET ; .LF609 ; Control block for I/O memory read/write DEFB &00:DEFB &00:DEFB &00:DEFB &00 .LF60D DEFB &00 .PrText EX (SP),HL PUSH AF .LF610 LD A,(HL) CALL OSASCI INC HL OR A JR NZ,LF610 POP AF EX (SP),HL RET ; ; Seek to track zero on drive supplied in A ; .Seek0 PUSH AF PUSH HL LD (LF636),A LD HL,LF636 LD A,&7F LD (DISKSP),SP LD SP,SysStack CALL osWORD LD SP,(DISKSP) POP HL POP AF RET ; .LF636 DEFB &00 DEFB &00 DEFB &00 DEFB &00 DEFB &00 DEFB &01 DEFB &69 DEFB &00 DEFB &00 .KeyTest PUSH HL LD HL,&FFFF LD A,&80 CALL osBYTE LD A,L OR A JR Z,LF64E JR LF65A .LF64E LD A,&D8 LD HL,&FF00 CALL osBYTE LD A,L OR A JR Z,LF65C .LF65A LD A,&FF .LF65C POP HL RET ; .InitErr PUSH BC:PUSH DE:PUSH HL LD HL,RST38:LD DE,&0038 LD BC,&0003:LDIR POP HL:POP DE:POP BC:RET .EventHandler RET ; MOS INTERFACE ; ============= ; ; ; OSWRCH - Send character to output stream ; ======================================== ; On entry, A =character ; On exit, A =preserved ; ; Tube data character -- ; .osWRCH PUSH AF ; Save character .LF672 IN A,(&00) ; Read Tube R1 status BIT 6,A:JR Z,LF672 ; Loop until b6 set POP AF:OUT (&01),A ; Send character to Tube R1 RET ; Wait for byte in R1 while allowing requests via R4 ; ================================================== .LF67C IN A,(&00) ; Check R1 status BIT 7,A:JR NZ,LF68D ; Data present, fetch it IN A,(&06) ; Check R4 status BIT 7,A:JR Z,LF67C ; No data, loop back to check R1 CALL LFB0B ; Process R4 interrupt JR LF67C ; Jump back to wait for R1 .LF68D IN A,(&01) ; Read byte from R1 RET ; OSRDCH - Wait for character from input stream ; ============================================= ; On exit, A =char, Cy=Escape flag ; ; Tube data &00 -- Carry Char ; .osRDCH LD A,&00:CALL SendR2 ; Send command &00 - OSRDCH .WaitCarryChar ; Wait for Cy and A CALL WaitR2:SLA A .WaitR2 IN A,(&02) BIT 7,A:JR Z,WaitR2 IN A,(&03) RET ; .SendR2 PUSH AF .LF6A4 IN A,(&02) BIT 6,A:JR Z,LF6A4 POP AF:OUT (&03),A RET ; ; Wait for byte in R4 ; =================== .LF6AE IN A,(&06) BIT 7,A:JR Z,LF6AE IN A,(&07) RET ; OSCLI - Execute command ; ======================= ; On entry, HL=>command string ; On exit, HL= corrupted ; .osCLI PUSH AF:PUSH BC:PUSH DE LD D,H:LD E,L .LF6BC CALL SkipStars:CALL SkipSpaces CP ASC"*":JR Z,LF6BC AND &DF CP ASC"H":JR Z,LF6EC ; Check for '*HELP' LD C,A:LD A,(LFCA3) OR A:LD A,C:JP NZ,LF7CC ; Pass to host CP ASC"G":JP Z,LF308 ; Check for '*GO' CP ASC"D":JP Z,LF3B3 ; Check for '*Dump' CP ASC"S":JP Z,LF330 ; Check for '*Set' CP ASC"C":JP Z,LF48D ; Check for '*CPM' JP LF7CC ; Pass to host ; .LF6EC INC DE:LD A,(DE):CP ASC".":JR Z,LF720 AND &DF:CP ASC"E":JP NZ,LF7CC INC DE:LD A,(DE):CP ASC".":JR Z,LF720 AND &DF:CP ASC"L":JP NZ,LF7CC INC DE:LD A,(DE):CP ASC".":JR Z,LF720 AND &DF:CP ASC"P":JP NZ,LF7CC INC DE:LD A,(DE):CALL LF86D JP NC,LF7CC CALL SkipSpaces:JR LF723 ; .LF720 CALL SkipSpace1 .LF723 CALL PRTEXT DEFB 13:DEFM "Z80 TUBE 1.20":DEFB 13 DEFB 0 ; LD C,A:LD A,(LFCA3) OR A:LD A,C:JP NZ,LF7CC CP &0D:JR Z,LF76C .LF743 AND &DF:CP ASC"M":JR Z,LF752 CP &0D:JP Z,LF7CC .LF74E INC DE:LD A,(DE):JR LF743 .LF752 INC DE:LD A,(DE):AND &DF CP ASC"O":JR NZ,LF74E .LF75A INC DE:LD A,(DE):AND &DF CP ASC"N":JR NZ,LF74E .LF762 INC DE:LD A,(DE):CALL LF86D JP NC,LF74E:JR LF778 .LF76C CALL PrText ; Print inline text DEFM " MON":DEFB 13:DEFB 0 JR LF7CC .LF778 CALL PrText ; Print inline text DEFM " CPM":DEFB 13 DEFM " Dump ":DEFB 13 DEFM " GO
":DEFB 13 DEFM " Set ":DEFB 13 DEFB 0 ; OSCLI - Send command line to host ; ================================= ; On entry, HL=>command string ; ; Tube data &02 string &0D -- &7F or &80 ; .LF7CC LD A,&02:CALL SendR2 ; Send command &02 - OSCLI CALL SendR2String ; Send command string CALL WaitR2 ; Wait for response CP &80:JR Z,LF7DF ; Jump if code to be entered POP DE:POP BC:POP AF:RET ; Restore registers and return .LF7DF LD A,&01:LD (REBOOT),A ; Set 'not RESET' CALL EnterCode ; Enter code POP DE:POP BC:POP AF:RET ; Restore registers and return ; Attempt to enter current program, or boot CPM ; --------------------------------------------- ; REBOOT=&00 if called from RESET, <>&00 if called from OSCLI ; .EnterCode LD HL,(PROG) ; Fetch program address LD DE,&0007:ADD HL,DE ; Point to copyright message PUSH HL:LD A,(HL) LD HL,(PROG):LD E,A ADD HL,DE:LD (FAULT),HL ; Point FAULT to (C) string LD A,(HL) CP &00:JR NZ,LF826 ; No ROM header, enter as raw code INC HL:LD A,(HL) CP ASC"(":JR NZ,LF826 ; No ROM header, enter as raw code INC HL:LD A,(HL) CP ASC"C":JR NZ,LF826 ; No ROM header, enter as raw code INC HL:LD A,(HL) CP ASC")":JR NZ,LF826 ; No ROM header, enter as raw code POP HL:DEC HL ; Point to ROM type LD A,(REBOOT) ; Get RESET/OSCLI flag OR A:JR NZ,LF82A ; Jump to non-booting test if called from OSCLI LD A,(HL) ; Get ROM type BIT 6,A:JP Z,LF4A9 ; If not a language try boot CPM BIT 3,A:JP Z,LF4A9 ; If not Z80 code try boot CPM .LF826 LD HL,(PROG) ; Fetch program address JP (HL) ; And enter it ; .LF82A XOR A:LD (REBOOT),A ; Set flag to reboot to CPM LD A,(HL) ; Get ROM type BIT 6,A:JR Z,LF83D ; If not a language, give error BIT 3,A:JR Z,LF856 ; If not Z80 code, give error LD A,&01 ; Set 'starting language' LD HL,(PROG) ; Fetch program address JP (HL) ; And enter it with A=&01 ; .LF83D RST &38:DEFB 0:DEFM "This is not a language":DEFB 0 ; .LF856 RST &38:DEFB 0:DEFM "This is not Z80 code":DEFB 0 ; .LF86D AND &DF:CP &41:RET C CP &5B:CCF:RET ; Skip spaces ; ----------- .SkipSpace1 INC DE .SkipSpaces LD A,(DE):CP ASC" ":JR Z,SkipSpace1:RET ; Skip stars ; ---------- .SkipStar1 INC DE .SkipStars LD A,(DE):CP ASC"*":JR Z,SkipStar1:RET ; Send string to Tube R2 ; ---------------------- .SendR2String LD A,(HL):CALL SendR2:INC HL CP &0D:JR NZ,SendR2String:RET ; OSBYTE - Byte MOS functions ; =========================== ; On entry, A, HL=OSBYTE parameters ; On exit, A preserved ; If A<&80, L=returned value ; If A>&7F, HL, Carry=returned values ; .osBYTE CP &80:JR NC,ByteHigh ; Jump for long OSBYTEs ; ; Tube data &04 X A -- X ; PUSH AF LD A,&04:CALL SendR2 ; Send command &04 - OSBYTELO LD A,L:CALL SendR2 ; Send single parameter POP AF:PUSH AF:CALL SendR2 ; Send function CALL WaitR2:LD L,A ; Get return value POP AF:RET ; .ByteHigh CP &82:JR Z,Byte82 ; Read memory high word CP &83:JR Z,Byte83 ; Read bottom of memory CP &84:JR Z,Byte84 ; Read top of memory ; ; Tube data &06 X Y A -- Cy Y X ; PUSH AF LD A,&06:CALL SendR2 ; Send command &06 - OSBYTEHI LD A,L:CALL SendR2 ; Send parameter 1 LD A,H:CALL SendR2 ; Send parameter 2 POP AF:PUSH AF:CALL SendR2 ; Send function CP &9D:JR Z,LF8DA ; Fast return with OSBYTE &9D CALL WaitR2:LD L,A ; Wait for returned Carry POP AF:SLA L:PUSH AF ; Copy into Carry flag CALL WaitR2:LD H,A ; Wait for return high byte CALL WaitR2:LD L,A ; Wait for return low byte .LF8DA POP AF:RET ; .Byte82:LD HL,&0000:RET ; Read memory high word .Byte83:LD HL,&3B03:RET ; Read bottom of memory ; LD HL,&0100 ; Bottom of TPA is bottom of memory .Byte84:LD HL,&DC00:RET ; Read top of memory ; LD HL,(&0006) ; Read top of memory from JP BDOS ; OSWORD_DE - Call OSWORD ; ======================= ; On entry, A =function ; HL=>control block ; DE=>returned control block ; .osWORD_DE PUSH AF:LD A,&01 ; Signal to return OSWORD data at DE LD (WORDDE),A:POP AF ; Continue into OSWORD ; OSWORD - Various functions ; ========================== ; On entry, A =function ; HL=>control block ; .osWORD OR A:JR Z,RDLINE ; OSWORD 0, jump to read line PUSH BC:PUSH HL PUSH IX:PUSH AF LD A,&08:CALL SendR2 ; Send command &08 - OSWORD POP AF:PUSH AF:CALL SendR2 ; Send function LD B,&00 LD C,A CP &80 JR C,LF90E LD B,(HL) INC HL LD C,(HL) DEC HL JR LF923 ; .LF90E CP &15 JR C,LF917 LD BC,&1010 JR LF923 ; .LF917 LD IX,LFC75 ADD IX,BC LD B,(IX-1) LD C,(IX+19) .LF923 PUSH HL PUSH BC LD C,B LD B,&00 ADD HL,BC POP BC LD A,B CALL SendR2 OR A JR Z,LF938 .LF931 DEC HL LD A,(HL) CALL SendR2 DJNZ LF931 .LF938 LD A,C CALL SendR2 POP HL PUSH AF LD A,(WORDDE) OR A:JR Z,LF94A LD H,D:LD L,E XOR A:LD (WORDDE),A .LF94A POP AF OR A JR Z,LF957 ADD HL,BC LD B,C .LF950 DEC HL CALL WaitR2 LD (HL),A DJNZ LF950 .LF957 POP AF POP IX POP HL POP BC RET ; RDLINE - Read a line of text ; ============================ ; On entry, A =0 ; HL=>control block ; On exit, A =undefined ; H =length of returned string ; Cy=0 ok, Cy=1 Escape ; ; Tube data &0A block -- &FF or &7F string &0D ; .RDLINE PUSH BC:PUSH AF LD A,&0A:CALL SendR2 ; Send command &0A - RDLINE INC HL:INC HL:INC HL:INC HL ; Point to end of control block LD B,&03 ; Three bytes to send from block .LF96A LD A,(HL):CALL SendR2 ; Send byte from control block DEC HL:DJNZ LF96A LD A,&07:CALL SendR2 SUB A:CALL SendR2 ; Send &0700 CALL WaitR2:RLCA ; Wait for response JR C,RdLineEscape LD A,(HL):DEC HL LD L,(HL):LD H,A ; Get address of text buffer LD B,&FF ; Initialise counter .RdLineLp CALL WaitR2:LD (HL),A ; Wait for a byte INC HL:INC B ; Inc. pointer and counter CP &0D:JR NZ,RdLineLp ; Loop until LD L,&00:LD H,B ; Copy counter to H POP AF:POP BC ; Restore registers SCF:CCF:RET ; Return A=0, Cy=0, H=length, L=0 ; .RdLineEscape LD HL,&00FF ; Return count=0 POP AF:POP BC ; Restore registers SCF:RET ; Return A=0, Cy=1, H=0, L=&FF ; OSARGS - Read info on open file ; =============================== ; On entry, A =function ; HL=>control block ; E =handle ; On exit, A =returned value ; HL preserved ; E preserved ; ; Tube data &0C handle block function -- result block ; .osARGS PUSH HL:PUSH DE PUSH BC:PUSH AF ; Save registers LD A,&0C:CALL SendR2 ; Send command &0C - OSARGS LD A,E:CALL SendR2 ; Send handle INC HL:INC HL:INC HL ; Point to end of data word LD B,&04 ; Four bytes to send .LF9B1 LD A,(HL):CALL SendR2 ; Send a byte of data word DEC HL:DJNZ LF9B1 INC HL ; Point HL back to data word POP AF:CALL SendR2 ; Send function CALL WaitR2:PUSH AF ; Wait for result INC HL:INC HL:INC HL ; Point to end of data word LD B,&04 ; Four bytes to receive .LF9C6 CALL WaitR2:LD (HL),A ; Get a byte of data word DEC HL:DJNZ LF9C6 POP AF:POP BC ; Restore registers POP DE:POP HL:RET ; OSFIND - Open of Close a file ; ============================= ; On entry, A =function ; H =handle or HL=>filename ; On exit, A =zero or handle ; ; Tube data &12 function string &0D -- handle ; &12 &00 handle -- &7F ; .osFIND PUSH AF ; Save function LD A,&12:CALL SendR2 ; Send command &12 - OSFIND POP AF:CALL SendR2 ; Send function CP &00:JR NZ,OPEN ; If <>0, jump to do OPEN ; CLOSE PUSH AF:LD A,H:CALL SendR2 ; Send handle CALL WaitR2:POP AF:RET ; Wait for response, restore registers .OPEN CALL SendR2String ; Send pathname JP WaitR2 ; Wait for and return handle ; OSBGet - Get a byte from open file ; ================================== ; On entry, H =handle ; On exit, A =byte Read ; H =preserved ; Cy set if EOF ; ; Tube data &0E handle -- Carry byte ; .osBGET LD A,&0E:CALL SendR2 ; Send command &0E - OSBGET LD A,H:CALL SendR2 ; Send handle JP WaitCarryChar ; Jump to wait for Carry and byte ; OSBPut - Put a byte to an open file ; =================================== ; On entry, A =byte to write ; H =handle ; On exit, A =preserved ; H =preserved ; ; Tube data &10 handle byte -- &7F ; .osBPUT PUSH AF ; Save byte LD A,&10:CALL SendR2 ; Send command &10 - OSBPUT LD A,H:CALL SendR2 ; Send handle POP AF:CALL SendR2 ; Send byte PUSH AF:CALL WaitR2 ; Wait for acknowledge POP AF:RET ; Restore A, return ; OSFILE - Operate on whole files ; =============================== ; On entry, A =function ; HL=>control block ; On exit, A =result ; control block updated ; ; Tube data &14 block string function -- result block ; .osFILE PUSH BC:PUSH AF ; Save BC and function LD (CTRL),HL ; Save address of control block LD A,&14:CALL SendR2 ; Send command &14 - OSFILE LD BC,&0011:ADD HL,BC ; Point to end of control block LD B,&10 ; Sixteen bytes to send .LFA20 LD A,(HL):CALL SendR2 ; Send control block DEC HL:DJNZ LFA20 LD A,(HL):DEC HL LD L,(HL):LD H,A ; Get address of pathname CALL SendR2String ; Send pathname POP AF:CALL SendR2 ; Send function CALL WaitR2:AND &7F ; Wait for result (Lose b7 - why?) PUSH AF LD HL,(CTRL) ; Get control block address back LD BC,&0011:ADD HL,BC ; Point to end of control block LD B,&10 ; Sixteen bytes to receive .LFA41 CALL WaitR2:LD (HL),A ; Get control block DEC HL:DJNZ LFA41 LD HL,(CTRL) ; Get control block address to restore HL POP AF:POP BC:RET ; Get result, restore BC ; OSGBPB - Multiple byte Read and write ; ===================================== ; On entry, A =function ; HL=>control block ; On exit, A =returned value ; control block updated ; ; Tube data &16 block function -- block Carry result ; .osGBPB PUSH BC:PUSH AF ; Save BC and function LD (CTRL),HL ; Save address of control block LD A,&16:CALL SendR2 ; Send command &16 - OSGBPB LD BC,&000C:ADD HL,BC ; Point to end of control block LD B,&0D ; Thirteen bytes to send .LFA5E LD A,(HL):CALL SendR2 ; Send control block DEC HL:DJNZ LFA5E POP AF:CALL SendR2 ; Send function LD HL,(CTRL) ; Get control block address LD BC,&000C:ADD HL,BC ; Point to end of control block LD B,&0D ; Thirteen bytes to receive .LFA72 CALL WaitR2:LD (HL),A ; Get control block DEC HL:DJNZ LFA72 LD HL,(CTRL) ; Get control block address to restore HL POP BC:JP WaitCarryChar ; Restore BC, jump to wait for Cy and A ; Interrupt SP store ; ================== .LFA80 DEFW &0000 ; ; Interupt handler ; ================ .InterruptHandler LD (LFA80),SP ; Save SP LD SP,TempStack ; Point to temporary stack CALL LFA93 ; Process interrupt LD SP,(LFA80) ; Restore SP EI:RETI ; Enable INTs and return from INT handler ; ; Interrupt handler subcode ; ------------------------- .LFA93 PUSH AF IN A,(&06) ; Check R4 status BIT 7,A:JR NZ,LFB0B ; Jump to process errors and transfers IN A,(&00) ; Check R1 status BIT 7,A:JR NZ,LFAD9 ; Jump to process Escape and events POP AF:JP USERINT ; Continue into INT2 vector ; .RestartHandler ; Enter here from CALL ERRJMP or RST &38 POP HL LD (FAULT),HL LD HL,(BRKV) JP (HL) ; .ErrorHandler ; Default error handler CALL LFAC6 ; Print error message JP LF2CB ; Jump to CliCom ; .DefaultError LD A,&03:LD L,&00:CALL osBYTE LD A,&02:LD L,&02:CALL osBYTE CALL LFAC6 JP &0000 ; .LFAC6 LD HL,(FAULT) LD A,&0D CALL osWRCH LD A,&0A .LFAD0 CALL osWRCH INC HL LD A,(HL) OR A JR NZ,LFAD0 RET ; .LFAD9 ; Interupt generated by data in R1 ; -------------------------------- IN A,(&01) ; Get byte from TubeR1 BIT 7,A:JR NZ,LFB04 ; Bit 7 set, jump to set Escape state LD A,&01:LD (INEVENT),A ; Set flag to indicate within ; event handler PUSH HL:PUSH IX ; Save registers CALL LF67C ; Wait for byte via R1 LD H,A ; 6502 Y passed to H CALL LF67C ; Wait for byte via R1 LD L,A ; 6502 X passed to L CALL LF67C ; Wait for byte via R1 in A CALL LFAFE ; Call event vector XOR A ; Clear flag, indicate not within LD (INEVENT),A ; event handler POP IX ; Restore registers POP HL POP AF .Null RET ; Return ; .LFAFE LD IX,(EVENTV) ; Get EVENTV contents JP (IX) ; Jump to it ; .LFB04 ; Set Escape state ; ---------------- SLA A ; Move escape flag to b7 LD (ESCFLG),A ; Store in Escape flag POP AF ; Restore A RET ; Return ; .LFB0B ; Interupt generated by data in R4 ; -------------------------------- IN A,(&07) ; Get byte from R4 BIT 7,A JR Z,LFB56 ; b7=0, jump for data transfer .LFB11 IN A,(&02) ; Get R2 status BIT 7,A JR Z,LFB11 ; Loop until data present IN A,(&03) ; Get (unused) byte from R2 EI ; Enable INTs LD HL,LFCB0 ; Point to error buffer LD (HL),&CD ; Put CALL opcode in INC HL LD A,(RST38+1) ; Call destination of default LD (HL),A ; error handler INC HL LD A,(RST38+2) LD (HL),A INC HL CALL WaitR2 ; Wait for byte from R2 LD (HL),A ; Store as ERR in error buffer OR A ; Was it error zero? JR NZ,LFB4B ; No, get rest of error block ; *BUG* Test for error zero should happen *after* collecting error block. ; This results in the client hanging as command transfer is now out of sequence. ; Change the above branch to JR LFB4B to fix this CALL PrText ; Print inline text ; DEFB 13 ; NEWL DEFM "Fatal error" DEFB 0 ; LD A,(LFCA3) OR A JP NZ,&0000 JP LF2CB ; .LFB4B INC HL CALL WaitR2 ; Wait for byte from R2 LD (HL),A ; Store in error buffer OR A JR NZ,LFB4B ; Loop until final zero byte JP LFCB0 ; Jump to error block to generate ; .LFB56 ; Data transfer initiated by INT via R4 ; ------------------------------------- PUSH BC PUSH DE PUSH HL PUSH AF ; Save transfer type RLCA LD E,A RLCA RLCA ADD A,E RLCA LD E,A LD D,&00 LD HL,LFBC1 ADD HL,DE LD DE,LFC61 LD BC,&0014 LDIR CALL LF6AE ; Wait for caller ID in R4 POP AF ; Get transfer type back CP &05 ; Is it 'release'? JR Z,LFBAA ; Yes, exit PUSH AF ; Save transfer type again CALL LF6AE ; Wait for byte in R4 CALL LF6AE ; Wait for byte in R4 CALL LF6AE ; Wait for byte in R4 LD H,A ; High byte of address CALL LF6AE ; Wait for byte in R4 LD L,A ; Low byte of address LD (PROG),HL; Set data address LD C,&05 ; Set C to R3 port address LD B,&00 ; Set B for 256 bytes to transfer CALL LF6AE ; Wait for sync byte in R4 POP AF ; Get transfer type back CP &06 JR C,LFBAA ; Jump if not 256-byte transfers JR NZ,LFBB4 ; Jump with 256-byte read ; .LFB97 ; Send 256 bytes to Tube via R3 ; ----------------------------- IN A,(&04) ; Check R3 status OR A JP P,LFB97 ; Loop until port free OUTI ; Send byte from (HL), increment HL JP NZ,LFB97 ; Loop until 256 bytes done .LFBA2 IN A,(&04) ; Check R3 status OR A JP P,LFBA2 ; Loop until port free OUT (&05),A ; Send final sync byte ; .LFBAA POP HL:POP DE:POP BC LD A,(INEVENT) ; Are we in the event handler? OR A:RET NZ POP AF RET ; .LFBB4 ; Read 256 bytes from Tube via R3 ; ------------------------------- IN A,(&04) ; Get R3 status OR A JP P,LFBB4 ; Loop until data present INI ; Get a byte and increment HL JP NZ,LFBB4 ; Loop for 256 bytes JR LFBAA ; Jump to restore and exit ; ; ; NMI data transfer routines ; ========================== ; .LFBC1 ; Transfer 0 - Single byte write to host ; -------------------------------------- PUSH HL PUSH AF LD HL,(PROG) ; Get data address LD A,(HL) ; Get byte from memory OUT (&05),A ; Send to R3 INC HL ; Increment data address LD (PROG),HL POP AF POP HL RETN ; LD A,(&3B12) OR A ; ; Transfer 1 - Single byte read from host ; --------------------------------------- PUSH HL PUSH AF IN A,(&05) LD HL,(PROG) LD (HL),A INC HL LD (PROG),HL POP AF POP HL RETN ; LD BC,&EB3B DEFB &CD ; ; Transfer 2 - Double byte write to host ; -------------------------------------- PUSH HL PUSH AF LD HL,(PROG) LD A,(HL) OUT (&05),A INC HL LD A,(HL) OUT (&05),A INC HL LD (PROG),HL POP AF POP HL RETN ; ; Transfer 3 - Double byte read from host ; --------------------------------------- PUSH HL PUSH AF IN A,(&05) LD HL,(PROG) LD (HL),A INC HL IN A,(&05) LD (HL),A INC HL LD (PROG),HL POP AF POP HL RETN ; ; Transfer 4 - Execute code ; ------------------------- OUT (&05),A RETN ; Code jumped to later ; INC HL LD D,(HL) DEC HL RET ; LD HL,(&3CA0) ADD HL,DE INC HL INC HL LD E,(HL) INC HL LD D,(HL) DEC HL RET DEFB &2A ; ; Transfer 5 - Release Tube ; ------------------------- OUT (&05),A RETN ; JP Z,&370D EX DE,HL PUSH DE CALL &36ED EX DE,HL LD (&3CA4),HL POP DE JP &3739 ; ; Transfer 6 - 256-byte transfer ; ------------------------------ OUT (&05),A ; Write to R3 RETN ; JR NZ,LFC3F .LFC3F EX DE,HL ADD HL,DE LD (&3CA2),HL PUSH DE EX DE,HL LD HL,(&3CAC) CALL &0D82 POP DE ; ; Transfer 7 - 256-byte transfer ; ------------------------------ OUT (&05),A ; Write to R3 RETN ; LD A,E INC A DEC H LD A,(&3C7D) OR A CALL &0D82 JP C,&3887 LD HL,(&3CA0) ; ; Current data transfer NMI code copied to here ; ============================================= .LFC61 OUT (&05),A ; Write to R3 RETN ; PUSH DE CALL &36E4 EX DE,HL LD HL,(&3CA8) EX DE,HL LD A,E AND &E0 LD E,A LD A,E OR D DEFB &C2 ; ; OSWORD control block lengths ; ============================ .LFC75 DEFB &00:DEFB &05:DEFB &00:DEFB &05 ; =TIME, TIME=, =Timer, Timer= DEFB &04:DEFB &05:DEFB &08:DEFB &0E ; =IO, IO=, SOUND, ENVELOPE DEFB &04:DEFB &01:DEFB &01:DEFB &05 ; =POINT, =CHR$, =Palette, Palette= DEFB &00:DEFB &10:DEFB &19:DEFB &10 ; =Coords, =TIME$, TIME$=, Net_Tx DEFB &0D:DEFB &00:DEFB &08:DEFB &80 ; Net_Rx, Net_Args, NetFS_Info, NetFS_Op ; Original code has =IO sending &02, should be &04 ; Original code has TIME$= sending &10, should be &20 DEFB &05:DEFB &00:DEFB &05:DEFB &00 ; =TIME, TIME=, =Timer, Timer= DEFB &05:DEFB &00:DEFB &00:DEFB &00 ; =IO, IO=, SOUND, ENVELOPE DEFB &05:DEFB &09:DEFB &05:DEFB &00 ; =POINT, =CHR$, =Palette, Palette= DEFB &08:DEFB &19:DEFB &10:DEFB &01 ; =Coords, =TIME$, TIME$=, Net_Tx DEFB &0D:DEFB &80:DEFB &08:DEFB &80 ; Net_Rx, Net_Args, NetFS_Info, NetFS_Op ; Original code has =TIME$ receiving &10, it should be &19 ; CLI Prompt input control block .LFC9D DEFW LFCB0 ; Input buffer DEFB &80 ; Maximum length DEFB &20:DEFB &FF ; Min char, max char ; Variables ; ========= .INEVENT :DEFB &00 ; Is code within the event handler? .LFCA3 :DEFB &00 .WORDDE :DEFB &00 .DISKSP :DEFW &F5D5 ; Saved SP within disk access code .RESULT :DEFB &2A ; Result of disk access .PROG :DEFW PROG ; Current program start address .ADDR :DEFW &0000 ; Temporary store .CTRL :DEFW LFCB0 ; Line pointer .OLDFX4 :DEFB &00 ; Previous fx4 state .REBOOT :DEFB &00 ; Reboot flag 0=CPM, <>0=Not CPM ; .LFCB0 ; Input and error buffer ; Contains leftover code from somewhere ; DEFB &36:DEFB &2A:DEFB &A0:DEFB &3C:DEFB &19:DEFB &F1 DEFB &F5:DEFB &77:DEFB &7B:DEFB &E6:DEFB &1F:DEFB &FE DEFB &1F:DEFB &CA:DEFB &95:DEFB &37:DEFB &13 CALL Z,&379F:EX DE,HL LD (&3CA8),HL POP AF:POP DE:RET LD A,E:AND &E0 .LFCCE LD E,A:CALL &36ED LD A,D:OR E:JP Z,&36F8 INC DE:INC DE:INC DE:INC DE RET ; PUSH DE:EX DE,HL LD HL,(&3CA0) EX DE,HL:LD A,L:AND &1F .LFCE5 JP NZ,&37C0:LD A,L .LFCE9 OR &04 .LFCEB LD L,A:EX DE,HL ADD HL,DE:LD A,(HL) EX DE,HL:POP DE RET ; .LFCF2 CALL &37B0:PUSH AF PUSH DE:EX DE,HL LD A,E:AND &1F:CP &1F .LFCFD JP Z,&37D5:INC DE:CALL Z,&379F EX DE,HL:POP DE:POP AF RET ; .LFD08 EX DE,HL:LD A,E:AND &E0 LD E,A:PUSH DE .LFD0E CALL &36ED:LD A,E:OR D POP BC:RET Z:XOR A LD (HL),A:INC HL .LFD18 LD (HL),A:LD HL,(&3CA0) ADD HL,DE .LFD1D LD (HL),E:INC HL:LD (HL),D .LFD20 PUSH BC:CALL &36D2 POP BC:LD HL,(&3CA6) EX DE,HL:CALL &36E4 LD (HL),C .LFD2D INC HL:LD (HL),B RET ; ; 6502 code for OSWORD &FF ; ------------------------ .LFD30 DEFB &4C:DEFB &05:DEFB &25 ; JMP &2505 .L2503 DEFB &10:DEFB &E3 ; Old WORDV .L2505 DEFB &C9:DEFB &FF ; CMP #&FF DEFB &F0:DEFB &03 ; BEQ L250C DEFB &6C:DEFB &03:DEFB &25 ; JMP (L2503) .L250C DEFB &86:DEFB &70 ; STX &70 DEFB &84:DEFB &71 ; STY &71 DEFB &85:DEFB &72 ; STA &72 DEFB &A0:DEFB &02 ; LDY #2 DEFB &B1:DEFB &70 ; LDA (&70),Y DEFB &85:DEFB &74 ; STA &74 DEFB &C8 ; INY DEFB &B1:DEFB &70 ; LDA (&70),Y DEFB &85:DEFB &75 ; STA &75 DEFB &20:DEFB &9C DEFB &25 DEFB &A0 DEFB &0C DEFB &B1 DEFB &70 DEFB &48 DEFB &A5 DEFB &70 DEFB &18:DEFB &69 DEFB &06:DEFB &AA DEFB &A9 DEFB &00 DEFB &65 DEFB &71 DEFB &A8 DEFB &68 DEFB &48 DEFB &20:DEFB &06 DEFB &04 DEFB &A0 DEFB &0A DEFB &B1 .LFD68 DEFB &70 DEFB &AA .LFD6A DEFB &C8 DEFB &B1 DEFB &70 DEFB &85 DEFB &76 DEFB &D0 DEFB &03 DEFB &8A DEFB &F0 DEFB &4E DEFB &8A DEFB &F0 DEFB &02 DEFB &E6:DEFB &76 DEFB &68 DEFB &6A DEFB &B0 DEFB &28:DEFB &20 DEFB &9B DEFB &25 DEFB &20:DEFB &9B DEFB &25 DEFB &20:DEFB &9B DEFB &25 DEFB &A0 DEFB &00 DEFB &AD DEFB &E5 DEFB &FE:DEFB &91 DEFB &74 DEFB &20:DEFB &9B DEFB &25 DEFB &20:DEFB &9B DEFB &25 DEFB &20:DEFB &9B DEFB &25 DEFB &E6:DEFB &74 DEFB &D0 DEFB &02 DEFB &E6:DEFB &75 DEFB &CA:DEFB &D0:DEFB &E9 DEFB &C6:DEFB &76 DEFB &D0 DEFB &E5 DEFB &F0 DEFB &1D DEFB &A0 DEFB &00 DEFB &B1 DEFB &74 DEFB &8D DEFB &E5 DEFB &FE:DEFB &20 DEFB &9B DEFB &25 DEFB &20:DEFB &9B DEFB &25 DEFB &20:DEFB &9B DEFB &25 DEFB &E6:DEFB &74 DEFB &D0 DEFB &02 DEFB &E6:DEFB &75 DEFB &CA:DEFB &D0:DEFB &E9 DEFB &C6:DEFB &76 DEFB &D0 .LFDC1 PUSH HL .LFDC2 JR NZ,LFD68 DEC H AND (HL) LD (HL),B AND H LD (HL),C AND L LD (HL),D LD H,B XOR C RST &00 JR NZ,LFDD6 INC B SUB B LD SP,HL LD H,B XOR C ADD A,A .LFDD6 JR NZ,Terminal INC B LD H,B .LFDDA DEFB 0 DEC H .LFDDC DEFB &36:DEFB &42 ; .Terminal ; Set/Read terminal destination CP &02 JR NC,LFE04 PUSH AF LD A,(TERMFLG) AND &01 LD (ADDR),A POP AF LD (TERMFLG),A OR A JR NZ,LFDFA LD HL,osWRCH LD (PROUT+1),HL JR LFE00 .LFDFA LD HL,LFE0D LD (PROUT+1),HL .LFE00 LD A,(ADDR) RET ; .LFE04 CP &FF RET NZ LD A,(TERMFLG) AND &01 RET ; .LFE0D LD C,A .TermOut LD A,(TERMFLG) BIT 7,A JR NZ,LFE27 LD A,C CP &1B JR Z,LFE1E CALL osWRCH RET ; .LFE1E LD A,(TERMFLG) SET 7,A LD (TERMFLG),A RET ; .LFE27 BIT 6,A JP NZ,LFEA6 BIT 5,A JP NZ,LFED9 LD A,C CP &3D JR Z,LFE4B CP &3E JR Z,LFE54 CP &3F JR Z,LFE5D CP &40 JR Z,LFE80 .LFE42 LD A,(TERMFLG) RES 7,A LD (TERMFLG),A RET ; .LFE4B LD A,(TERMFLG) SET 6,A LD (TERMFLG),A RET ; .LFE54 LD A,(TERMFLG) SET 5,A LD (TERMFLG),A RET ; .LFE5D CALL LFEEC JR Z,LFE6A CP &00 JR NZ,LFE42 LD A,&1F JR LFE6C ; .LFE6A LD A,&18 .LFE6C LD (LFF18),A CALL LFEF5 LD B,&10 LD HL,LFF10 .LFE77 LD A,(HL) CALL osWRCH INC HL DJNZ LFE77 JR LFE42 ; .LFE80 CALL LFEEC JR Z,LFE89 CP &00 JR NZ,LFE42 .LFE89 CALL LFEF5 LD B,&06 LD HL,LFF10 .LFE91 LD A,(HL) CALL osWRCH INC HL DJNZ LFE91 LD B,&05 LD HL,LFF1B .LFE9D LD A,(HL) CALL osWRCH INC HL DJNZ LFE9D JR LFE42 ; .LFEA6 BIT 4,A JR NZ,LFEB9 LD A,C SUB &20 LD (LFF21),A LD A,(TERMFLG) SET 4,A LD (TERMFLG),A RET ; .LFEB9 LD A,C:SUB &20 LD (LFF20),A LD A,&1F:CALL osWRCH LD A,(LFF20):CALL osWRCH LD A,(LFF21):CALL osWRCH LD A,(TERMFLG):AND &01 LD (TERMFLG),A:RET ; .LFED9 LD A,C:OR A:JR Z,LFEE3 SUB &20:CALL osWRCH:RET ; .LFEE3 LD A,(TERMFLG):AND &01 LD (TERMFLG),A:RET ; .LFEEC LD A,&87:CALL osBYTE LD A,H:CP &03:RET ; .LFEF5 LD A,&86:CALL osBYTE LD A,L:LD (LFF11),A:LD (LFF1E),A LD A,H:LD (LFF12),A:LD (LFF14),A LD (LFF1F),A:INC A:LD (LFF1A),A RET ; .LFF10:INC E .LFF11:DEFB &C4 .LFF12:DEFB &48:DEFB &4F .LFF14:POP BC INC C:INC E DEFB 0 .LFF18:RRA:LD C,A .LFF1A:LD C,B .LFF1B:INC C LD A,(DE):RRA .LFF1E:DEFB &22 .LFF1F:DEFB &28 .LFF20:DEFB &00 .LFF21:DEFB 0 LD L,E:RLA LD HL,(&3B28) LD (HL),&00 LD HL,&3B2A JP &1977 PUSH BC:PUSH HL LD A,(HL):AND &03 LD B,A:LD C,&06 INC HL:LD E,(HL) INC HL:LD D,(HL) CALL &1A48 POP HL:POP BC:RET LD D,E:DEFW 0:DEFW 0:DEFB 0 LD (BC),A:DEFW 0:DEFW 0 LD A,(BC):DEFW 0:DEFW 0 DEFW 0:DEFW 0:DEFW 0 DEFW 0:DEFW 0:DEFW 0 DEFW 0:DEFB 0 .TempStack ; Interrupt stack descends from here DEFW 0:DEFW 0:DEFW 0:DEFW 0:DEFW 0 DEFW 0:DEFW 0:DEFW 0:DEFW 0:DEFW 0 DEFW 0:DEFW 0:DEFW 0:DEFW 0:DEFW 0 DEFW 0 .SysStack ; System stack descends from here ; .ESCFLG: ; &FF80 : DEFB &00 ; Bit 7 is set on escape. .TERMFLG: ; &FF81 : DEFB &00 ; TERM flag .FAULT .FAULT: ; &FF82 : DEFW &0100 ; Fault pointer .ERRDEF: ; &FF84 : DEFW DefaultError ; Default error handler ; DEFB &02:DEFB &14:DEFB &95:DEFB &00 DEFB &01:DEFB &00:DEFB &00:DEFB &3C DEFB &1A:DEFB &FF:DEFB &FF:DEFB &01 DEFB &00:DEFB &00:DEFB &00:DEFB &00 DEFB &00:DEFB &00:DEFB &00:DEFB &00 DEFB &74:DEFB &4C:DEFB &D6:DEFB &5E ; .PROUT: ; &FF9E : JP osWRCH .INITFF: ; &FFA1 : JP InitFF .DISKACC: ; &FFA4 : JP DiskAccess .LDCCP: ; &FFA7 : JP LoadCCP .PRHEX: ; &FFAA : JP PrHex .PR2HEX: ; &FFAD : JP Pr2Hex .USERINT: ; &FFB0 : JP Null .PRTEXT: ; &FFB3 : JP PrText .PRNTC: ; &FFB6 : JP TermOut .CLICOM: ; &FFB9 : JP CLIPrompt .RST38: ; &FFBC : JP RestartHandler .INITERR: ; &FFBF : JP InitErr .SEEK0: ; &FFC2 : JP Seek0 .KBDTST: ; &FFC5 : JP KeyTest .TERM: ; &FFC8 : JP Terminal .OSWORDDE: ; &FFCB : JP osWORD_DE ; .OSFIND: ; &FFCE : JP osFIND .OSGBPB: ; &FFD1 : JP osGBPB .OSBPUT: ; &FFD4 : JP osBPUT .OSBGET: ; &FFD7 : JP osBGET .OSARGS: ; &FFDA : JP osARGS .OSFILE: ; &FFDD : JP osFILE ; .OSRDCH: ; &FFE0 : JP osRDCH .OSASCI: ; &FFE3 : CP &0D:JR NZ,OSWRCH .OSNEWL: ; &FFE7 : LD A,&0A:CALL OSWRCH .OSWRCR: ; &FFEC : LD A,&0D .OSWRCH: ; &FFEE : JP osWRCH .OSWORD: ; &FFF1 : JP osWORD .OSBYTE: ; &FFF4 : JP osBYTE .OS_CLI: ; &FFF7 : JP osCLI .BRKV: ; &FFFA : DEFW ErrorHandler ; Error vector .EVENTV: ; &FFFC : DEFW EventHandler ; Event vector .IRQV: ; &FFFE : DEFW InterruptHandler ; Interrupt vector ]NEXT OS."Save Client "+STR$~mcode%+" "+STR$~O%+" "+STR$~load%+" "+STR$~load% *Quit