;
; ---- MODEM REMOTE CONSOLE PROGRAM ----
;	     VERSION 1.1
;  ----- TRS-80 MODEL III EQUATES -----
;             (ORIGINAL)
;   (--- VERSION FOR OSBORNE O-1 ---)
;	       BY BRK
;
; revised by Jim Woolley, FOG Disk Librarian, 11/82
;
;***** MODIFIED by Garry Pribble 02/12/85 *****
;++++++Modified by Steven A. Bland 2/13/85++++++
;
; THIS PROGRAM ATTACHES A REMOTE CONSOLE, TYPICALLY
; THRU A MODEM CHANNEL, IN PARALLEL WITH THE USUAL
; CP/M CONSOLE DEVICE.	IN THIS MODE, CHARACTERS TYPED
; ON EITHER CONSOLE ARE ECHOED TO BOTH.  THIS ALLOWS
; A REMOTE USER TO CONTROL THE COMPUTER ... TO RUN
; DIAGNOSTICS... OR TO GIVE INSTRUCTION ON HOW TO
; PERFORM CERTAIN OPERATIONS.
;
; THE PROGRAM IS INITIATED BY THE COMMAND:
;
;	A>REMOTE
; OR
;	A>REMOTE  XXXX
;			WHERE XXXX IS A HEX MEMORY ADDRESS
;
; IN THE FIRST CASE, THE MODEM DRIVERS WILL BE RELOCATED AND
; COPIED JUST UNDER THE  CCP ( OR JUST UNDER WHATEVER PROGRAM
; IS ALREADY PROTECTED UNDER THE CCP ). IN THIS MODE, WARM BOOTS
; ARE DISABLED.  IN THE SECOND CASE, WHEN A HEX MEMORY ADDRESS
; IS SPECIFIED, THE MODEM DRIVERS ARE RELOCATED AND COPIED TO THIS
; ADDRESS (ASSUMED TO BE "ABOVE" THE BIOS).
;
; THE DRIVERS MAY BE DETACHED BY RUNNING THE PROGRAM AGAIN.  IT WILL
; LOAD AND IF IT FINDS MODEM DRIVERS ALREADY ATTACHED, IT WILL ASK
; IF YOU WANT THEM DISCONNECTED.
;
; ---- CP/M EQUATES ----
;
BDOS	EQU	5	; FUNCTION CALL ENTRY POINT
FCB	EQU	5CH	; DEFAULT FCB LOCATION
CDISC	EQU	4	; BUFFER FOR LOGGED ON DRIVE #
CHOUT	EQU	2	; BDOS COMMAND FOR CONSOLE OUTPUT
LST	EQU	9	; BDOS COMMAND TO PRINT A STRING
DIO	EQU	6	; BDOS COMMAND FOR DIRECT I/O ( CP/M 2.X )
;
CR	EQU	0DH	; CARRIAGE RETURN

LF	EQU	0AH	; LINE FEED
;
;
	ORG	100H
;
	JMP	START	; JUMP OVER MSG
	DB	'REMOTE CONSOLE PGM V1.1, (C) 1982 BY BRK',1AH
;
START:	POP	H	; GET RETURN ADDRESS FROM STACK
	LXI	SP,STACK ; SET NEW STACK
	PUSH	H	; PUT RETURN ADDRESS ON NEW STACK
;
	LXI	D,STMSG	; POINT TO STARTUP MESSAGE
	CALL	PTMSG	; ANNOUNCE PRESENCE
;
	XRA	A
	STA	ABOVE	; INIT ABOVE FLAG TO "BELOW" STATUS
;
	LHLD	1	; GET POINTER TO  BIOS+3
	SHLD	BIOS3	; SET INTO PROGRAM MODULE
	LXI	D,-1600H
	DAD	D	; COMPUTE ADDRESS OF CCP+3 (CP/M 2.X)
	SHLD	CCP3	; SAVE IN PROGRAM MODULE
	LXI	D,1621H	; OFFSET TO BIOS SETDMA LOCATION
	DAD	D
	SHLD	STDMA	; SET IN PROGRAM MODULE
;
	LHLD	6
	SHLD	BDJ+1	; SAVE BDOS ENTRY ADDRESS
;
	LHLD	1
	LXI	D,4
	DAD	D	; POINT TO BIOS+7
	MOV	E,M	; GET  ADDRESS OF CONSOLE STATUS ROUTINE
	INX	H
	MOV	D,M
	XCHG
	LXI	D,-10	; LENGTH OF POSSIBLE TEST STRING+POINTER
	DAD	D	; POINT TO POSSIBLE START OF STRING
	LXI	D,TMSG	; POINT TO TEST STRING
	MVI	C,8	; SET COMPARISON LENGTH
	CALL	COMPARE	; COMPARE THEM
	SHLD	CDPTR	; SAVE POSSIBLE POINTER
	JNZ	INSTALL	; IF NOT EQUAL, ASSUME NO MODEM DRIVER IS
;			;    ATTACHED ALREADY
	LXI	D,ALMSG	; IF DRIVER IS ATTACHED, ASK TO DETACH
	CALL	PTMSG
	CALL	YES
	RNZ		; IF "NO", JUST RETURN
;
	LXI	D,DTMSG
	CALL	PTMSG	; NOTIFY OF DETACHMENT
;
	LHLD	CDPTR
	CALL	GTDE	; GET POINTER TO OLD JUMP TABLE IN MODULE
	LHLD	1	; GET POINTER TO STD JUMP TABLE
	XCHG
	LXI	B,12	; LENGTH OF TABLE
	CALL	MOVE	; DETACH MODULE
	JMP	EXIT	; DO WARM BOOT TO RE-INIT BASE PAGE JUMPS
;
INSTALL: LXI	H,FCB+1	; POINT TO STD CP/M FCB LOCATION
	SHLD	CHPTR	; SAVE FOR HEX ROUTINE
	MOV	A,M	; GET FIRST CHAR.
	CALL	THEX	; CHECK IF VALID HEX #
	JC	BELOW	; IF NOT, PUT MODULE "BELOW"
	CALL	GTHEX	; IF VALID, TRY TO EXTRACT HEX NUMBER
	SHLD	LDADDR	; SAVE IT
	MVI	A,1
	STA	ABOVE	; SET ABOVE MODE
	JC	INST1	; IF GOOD HEX VALUE
	LXI	D,EMSG1
	JMP	EXMG	; EXIT WITH ERROR MESSAGE
;
INST1:	PUSH	H
	LHLD	1	; GET BIOS+3
	LXI	D,40H	; ASSUME JUMP TABLE AT LEAST
	DAD	D
	POP	D
	CALL	COMPDE	; IS # REALLY ABOVE THE BIOS
	JC	INSTA	; IF IT LOOKS OK
;
	LXI	D,EMSG2
	JMP	EXMG	; " ABOVE ADDRESS IS TOO SMALL"
			;  AND EXIT BACK TO CP/M
;
BELOW:	LHLD	CCP3	; GET ADDRESS OF CCP+3
	XCHG
	LHLD	BDOS+1	; GET BDOS ENTRY JUMP ADDRESS
	CALL	COMPDE	; COMPARE THEM
	JC	INST2	; IF CCP+3>BDOS ENTRY
	XCHG
INST2:	LXI	D,-LENC-10
	DAD	D	; ALLOW ROOM BELOW FOR CODE
	MVI	L,6	; MAKE START ADDRESS LIKE BDOS ENTRY
	SHLD	LDADDR	; SAVE ADDRESS TO COPY MODULE TO
;
INSTA:	LHLD	1	; POINT TO PART OF BIOS JUMP TABLE
	LXI	D,OWBOOT ; POINT TO DESTINATION IN MODULE
	LXI	B,12	; LENGTH OF TABLE
	CALL	MOVE	; COPY INTO MODULE
;
	LXI	D,BDJ	; POINT TO START OF MODULE
	LHLD	LDADDR	; POINT TO CODE DESTINATION
	CALL	SUBDE
	SHLD	OFFSET	; SAVE RELOCATION OFFSET
	CALL	RELOC	; RELOCATE CODE IN MODULE
;
	LHLD	LDADDR	; SET DESTINATION ADDRESS
	XCHG
	LXI	H,BDJ	; SET SOURCE ADDRESS
	LXI	B,LENC+1; SET LENGTH OF CODE IN MODULE
	CALL	MOVE	; COPY MODULE TO DESTINATION
;
	LHLD	1
	XCHG		; GET BIOS+3 IN (D,E)
;
	LXI	H,NWBOOT ; POINT TO NEW JUMP TABLE
	LXI	B,12	; LENGTH OF TABLE
	LDA	ABOVE
	ORA	A	; TEST IF "ABOVE" MODE
	JZ	INST3	; NO, SO DO MOVE
	INX	D	; YES, SO DO NOT COPY OVER WARM BOOT JUMP
	INX	D
	INX	D
	LXI	H,NWBOOT+3
	LXI	B,9
INST3:	CALL	MOVE	; LINK IN MODULE BY SWITCHING IN JUMP TABLE
;	CALL	MXINIT	; INIT REMOTE DRIVERS  deleted, jw
	LXI	D,ATMSG
	CALL	PTMSG
	LHLD	LDADDR	; GET LOAD ADDRESS
	CALL	HEXW	; PRINT IT OUT
	LXI	D,ATMSG1
	JMP	EXMG	; LET WARM BOOT CORRECT BASE PAGE JUMPS
;
; ------ SUBROUTINES ------
;
; --- COMPARE STRINGS AT (H,L) AND (D,E) FOR (C) BYTES ---
;
COMPARE: LDAX	D
	CMP	M
	RNZ		; IF NO MATCH
	INX	H
	INX	D
	DCR	C	; COUNT DOWN
	JNZ	COMPARE	; LOOP UNTIL ERROR OR DONE
	RET
;
; --- COMPARE (H,L) & (D,E) BY SUBTRACTION (H,L)-(D,E) ---
;
COMPDE:	MOV	A,L
	SUB	E
	MOV	A,H
	SBB	D
	RET
;
; --- SUBTRACT: (H,L)=(H,L)-(D,E) ---
;
SUBDE:	MOV	A,L
	SUB	E
	MOV	L,A
	MOV	A,H
	SBB	D
	MOV	H,A
	RET
;
; --- COPY CODE FROM (H,L) TO (D,E) FOR (B,C) BYTES ---
;
MOVE:	MOV	A,M
	STAX	D
	INX	H
	INX	D
	DCX	B
	MOV	A,B
	ORA	C
	JNZ	MOVE
	RET
;
; --- TEST & CONVERT CHAR. IF VALID HEX # ---
;
THEX:	SUI	'0'	; REMOVE ASCII BIAS
	RC		; IF ERROR
	CPI	'G'-'0'
	CMC
	RC		; IF ERROR
	CPI	10	; IS IT 0-9?
	CMC
	RNC		; YES, SO RETURN
	SUI	7
	CPI	10	; IF NOT A-F, SET CARRY
	RET
;
; --- GET 16 BIT WORD POINTED TO BY (H,L) INTO (D,E) ---
;
GTDE:	MOV	E,M
	INX	H
	MOV	D,M
	INX	H
	RET
;
; --- PUT 16 BIT WORD FROM (D,E) INTO MEMORY AT (H,L) ---
;
PTDE:	MOV	M,E
	INX	H
	MOV	M,D
	INX	H
	RET
;
;
;  --- HEX INPUT ROUTINE ----
;
GTHEX:	LXI	H,0	; CLEAR CONVERSION REGISTER
H1:	CALL	GTCHR	; GET CHAR.
	CPI	CR	; IS IT A CR
	RZ		; YES, SO RETURN
HEX2:	CALL	THEX	; TEST CHAR. AND REMOVE ASCII BIAS
	RC		; IF ERROR
HEX1:	DAD	H	; SHIFT 16 BIT REGISTER OVER 4 PLACES
	DAD	H
	DAD	H
	DAD	H
	ADD	L	; ADD IN NEW NIBBLE
	MOV	L,A
	JMP	H1
;
GTCHR:	PUSH	H
	LHLD	CHPTR	; POINT TO CHAR.
	MOV	A,M	; GET IT
	INX	H
	SHLD	CHPTR	; POINT TO NEXT ONE
	POP	H
	RET
;
; --- OUTPUT BYTE IN ACC IN HEX ---
;
HEXOT:	PUSH	PSW	; SAVE BYTE
	RRC		; SHIFT UPPER NIBBLE DOWN
	RRC
	RRC
	RRC
	CALL	HEXB	; OUTPUT UPPER NIBBLE IN HEX
	POP	PSW	; GET BYTE BACK
HEXB:	ANI	0FH	; MASK OFF UPPER NIBBLE
	ADI	'0'	; ADD ASCII BIAS
	CPI	'9'+1	; TEST IF NUMERIC
	JC	PRT	; YES, SO DO IT
	ADI	7	; NO, SO ADD BIAS FOR A-F
PRT:	MOV	C,A	; SETUP FOR OUTPUT
COUT:	PUSH	PSW
	PUSH	H	; BUFFERED CONSOLE OUTPUT
	PUSH	D
	PUSH	B
	MOV	E,C
	MVI	C,CHOUT	; BDOS CHAR. OUTPUT COMMAND
	CALL	BDOS
	POP	B
	POP	D
	POP	H
	POP	PSW
	RET
;
; --- OUTPUT (H,L) IN HEX ---
;
HEXW:	PUSH	H
	MOV	A,H
	CALL	HEXOT	; PRINT OUT UPPER BYTE
	POP	H
	MOV	A,L
	JMP	HEXOT	; PRINT OUT LOWER BYTE
;
; --- PRINT STRING POINTED TO BY (D,E) ---
;
PTMSG:	MVI	C,LST
	JMP	BDOS
;
;
; -- YES FUNCTION --
;
YES:	CALL	CONNC	; GET CONSOLE CHAR.
	CPI	'Y'	; IS IT A  Y?
	JZ	YES1
	CPI	'N'	; IS IT A  N?
	JNZ	YES	; IF NEITHER, KEEP TRYING
	INR	A	; SET  N  STATUS
YES1:	PUSH	PSW	; SAVE FLAGS
	CALL	COUT	; OUTPUT TO CONSOLE
	POP	PSW	; RESTORE FLAGS
	RET
CONNC:	CALL	CONIN	; GET CHAR. FROM CONSOLE
	MOV	C,A	; SAVE FOR ECHO
	CPI	60H	; IS IT LOWER CASE?
	JC	CON1	; NO, SO CONTINUE
	ANI	5FH	; YES, SO MASK TO UPPER CASE
CON1:	CPI	'C'-40H	; IS IT A CONTROL-C?
	RNZ		; NO, SO RETURN
CTC:	LXI	D,CMSG	; POINT TO CONTROL-C MESSAGE
EXMG:	CALL	PTMSG		; ISSUE MESSAGE 
EXIT:	LXI	D,CRLF
	CALL	PTMSG		; ISSUE A CRLF
	JMP	0
;
CONIN:	MVI	E,0FFH
	MVI	C,DIO
	CALL	BDOS
	ORA	A
	JZ	CONIN
	RET
;
; --- RELOCATE ADDRESSES POINTED TO BY ADDRESS TABLE ---
;
RELOC:	LXI	H,RELTAB	; POINT TO ADDRESS TABLE
REL1:	CALL	GTDE		; GET POINTER INTO (D,E)
	MOV	A,D
	ORA	E		; TEST IF ADDRESS IS ZERO
	RZ			; RETURN (DONE) IF IT IS
	PUSH	H		; SAVE TABLE POINTER
	XCHG			; GET ADDRESS INTO (H,L)
	PUSH	H		; SAVE POINTER
	CALL	GTDE		; GET REFERENCED ADDRESS WORD
	LHLD	OFFSET		; GET OFFSET
	DAD	D		; COMPUTE RELOCATED ADDRESS
	XCHG
	POP	H
	CALL	PTDE		; UPDATE ADDRESS WORD IN CODE
	POP	H		; GET TABLE ADDRESS POINTER BACK
	JMP	REL1		; LOOP UNTIL DONE
;
; --- RELOCATION ADDRESS TABLE ---
;
RELTAB	EQU	$
	DW	NWBOOT+1
	DW	NWBOOT+4
	DW	NWBOOT+7
	DW	NWBOOT+10
	DW	PTX00
	DW	PTX0+1
	DW	MCNST+1
	DW	MCNIN+1
	DW	PTX1+1
	DW	PTX2+1
	DW	PTX3+1
	DW	PTX4+1
	DW	PTX41+1
	DW	PTX5+1
	DW	PTX6+1
	DW	PTX7+1
	DW	DVX1+1
	DW	MXIN+1
	DW	DVX2+1
	DW	DVX3+1
	DW	DVX4+1
	DW	0		; TABLE TERMINATOR
;
; --- MESSAGES -----
;
STMSG:	DB CR,LF
	DB CR,LF,' --- REMOTE CONSOLE ATTACHMENT PROGRAM ---'
	DB CR,LF,'		 VERS. 1.2'
	DB CR,LF,'	  FOR TRS-80 III RS-232 PORT'
	DB CR,LF,'  by BRK (TRS-80 3 by Garry Pribble and)'
        DB CR,LF,'            Steven A. Bland'
        DB CR,LF,'$'
;
ALMSG:	DB	CR,LF,07,' REMOTE CONSOLE IS ALREADY ATTACHED'
	DB	   CR,LF,' ---------------->  DETACH IT (Y/N) ?$'
;
DTMSG:	DB	CR,LF
	DB	CR,LF,' --> REMOTE CONSOLE DRIVERS ARE DETACHED !!'
CRLF:	DB	CR,LF,'$'
;
EMSG1:	DB	CR,LF,07,' *** INVALID "ABOVE" ADDRESS SPECIFIED ***'
	DB	CR,LF,'$'
;
EMSG2:	DB	CR,LF,07,' *** "ABOVE" ADDRESS IS TOO SMALL ***'
	DB	CR,LF,'$'
;
ATMSG:	DB	CR,LF,' --- REMOTE CONSOLE DRIVERS ATTACHED AT $'
;
ATMSG1:	DB	'H ---',CR,LF,'$'
;
CMSG:	DB	' ^C',CR,LF,'$'
;
; --- BUFFERS ---
;
CHPTR:	DS	2	; BUFFER POINTER FOR HEXIN ROUTINE
LDADDR:	DS	2	; BUFFER FOR SAVING DRIVER LOAD ADDRESS
OFFSET:	DS	2	; BUFFER FOR SAVING ADDRESS OFFSET
CDPTR:	DS	2	; BUFFER FOR POINTER TO JUMP TABLE IN DRIVER
ABOVE:	DS	1	; FLAG FOR "ABOVE" OR "BELOW" MODE
;
; ---------------------------------------------------------------
; ---- REMOTE CONSOLE DRIVERS ----
;
;  THIS SECTION GETS RELOCATED AND COPIED UP TO THE "TOP"
;  OF AVAILABLE MEMORY. ANY ADDRESSES IN THIS CODE THAT
;  NEED RELOCATION MUST BE REFERENCED IN THE RELOCATION TABLE.
;
BDJ:	JMP	$-$	; THIS GETS PATCHED
;
; --- COPY OF ORIGINAL CP/M JUMP TABLE
;
OWBOOT:	JMP	$-$	; COPY OF OLD WARM BOOT
OCNST:	JMP	$-$
OCNIN:	JMP	$-$
OCNOUT:	JMP	$-$
;
; --- NEW JUMP TABLE TO BE COPIED INTO CP/M JUMP TABLE ---
;
NWBOOT:	JMP	WBOOT
NCNST:	JMP	MCNST
	JMP	MCNIN
	JMP	MCNOUT
;
; --- FAKE WARM BOOT ROUTINE USED IN "BELOW" MODE ---
;
WBOOT:	LXI	SP,0FFH
	MVI	A,(JMP)
	STA	0	; SET JUMP OPCODE AT 0000H
BIOS3	EQU	$+1
	LXI	H,$-$	
	SHLD	1	; SET BIOS+3 WARM BOOT ADDRESS
	STA	5
PTX0:	LXI	H,BDJ
	SHLD	6
	LXI	B,80H	; SET DEFAULT DMA ADDRESS
STDMA	EQU	$+1
	CALL	$-$
	LDA	CDISC	; GET DEFAULT DRIVE #
	MOV	C,A
CCP3	EQU	$+1
	JMP	$-$	; RE-ENTER CCP AT CCP+3
;
; THE FOLLOWING 10 BYTES MUST NOT BE CHANGED OR MOVED
;
TMSG:	DB	'REMOTE C' ; IDENTIFIER STRING
PTX00:	DW	OWBOOT	; POINT TO SAVED OLD JUMP TABLE
;
; --- NEW CONSOLE STATUS ROUTINE ---
;
MCNST:	CALL	OCNST	; SEE IF STD CONSOLE HAS A CHAR.
	ORA	A
	RNZ		; RETURN IF IT DOES
PTX1:	JMP	MXISTAT ; OTHERWISE, CHECK MODEM DRIVER
;
; --- NEW CONSOLE INPUT ROUTINE ---
;
MCNIN:	CALL	OCNST	; IS CHAR. AVAIL. FROM STD CONSOLE?
	ORA	A
PTX2:	JNZ	OCNIN	; YES, SO GO GET IT
PTX3:	CALL	MXISTAT	; NO, SO TRY MODEM
	ORA	A
PTX4:	JZ	MCNIN	; IF NO CHAR., KEEP LOOKING
PTX41:	CALL	MXIN	; GET CHAR.
	ORA	A	; IS IT A NULL?
PTX5:	JZ	MCNIN	; YES, IGNORE IT
	ANI	7FH	; MASK PARITY
	RET
;
; --- NEW CONSOLE OUTPUT ROUTINE ---
;
MCNOUT:	PUSH	B	; SAVE OUTPUT CHAR.
PTX6:	CALL	OCNOUT	; SEND IT TO STD CONSOLE
	POP	B
PTX7:	JMP	MXOUT	; SEND IT TO REMOTE CONSOLE ALSO
;
; ----- HARDWARE DEPENDENT I/O DRIVER ----
;      -------------------------------------
;       THE ORIGINAL VERSION FOR THE OSBORNE
;	IS COMPLICATED BY A DESIGN FLAW
;	IN THE RS232 PORT HARDWARE.  WHEN
;	NO CONNECTIONS ARE MADE, UART IS
;	BEING GIVEN NULLS.
;      -------------------------------------
;
MODCTLP	EQU	00EAH	;PUT YOUR MODEM CONTROL PORT HERE
MODSNDB	EQU	40H	;YOUR BIT TO TEST FOR SEND
MODSNDR	EQU	40H	;YOUR VALUE WHEN READY
MODRCVB	EQU	80H	;YOUR BIT TO TEST FOR RECEIVE
MODRCVR	EQU	80H	;YOUR VALUE WHEN READY
MODDATP	EQU	00EBH	;YOUR MODEM DATA PORT
; these are setup for TRS-80 III serial WD TR1602 UART+  (G.P. & S.B.)
;     Running Under Holmes Engineering VID-80 (tm)(c) CP/M 2.22J
;
; --- ALL OF THE MODEM ROUTINES MAY ONLY CHANGE ---
;	THE A-REGISTER AND THE FLAGS.  NO OTHER
;	REGISTERS MAY BE CHANGED.
;
; --- INPUT DATA FROM MODEM ---
;
MXIN:	LXI	H,CHRSAV	; POINT TO CHAR. BUFFER
	MOV	A,M		; GET CHAR.
	MVI	M,0		; INDICATE CHAR. RECEIVED
	RET
;
; --- OUTPUT DATA TO MODEM ---
;
MXOUT	DI
	IN 	MODCTLP
	EI
	ANI	MODSNDB
	CPI	MODSNDR
DVX1:	JNZ	MXOUT
	MOV	A,C              
	DI
	OUT	MODDATP
	EI
	RET
;
; --- TEST IF DATA IS AVAILABLE FROM MODEM ---
;
;
MXISTAT: DI
	IN 	MODCTLP
	EI
	ANI	MODRCVB
	CPI	MODRCVR	
;
DVX2:	LDA	CHRSAV	; GET POSSIBLE SAVE CHAR.
DVX3:	JNZ	MXI1	; IF NO CHAR., TEST BUFFER FOR ONE
;
	DI		; IF CHAR., GET IT
	IN 	MODDATP	; GET DATA
	EI
;
DVX4:	STA	CHRSAV	; SAVE IT
MXI1:	ORA	A	; WAS IT A NULL?
	RZ		; YES, SO RETURN NOT READY STATUS
        MVI	A,0FFH	; SET READY STATUS
	RET
;
CHRSAV:	DB	0	; BUFFER FOR ONE CHAR.
;
; --- INIT MODEM ROUTINES (NOT HARDWARE) ---
;	THIS ROUTINE NEED NOT PRESERVE ANY
;	OF THE REGISTERS.
;
;MXINIT	EQU	$	;deleted following code, jw
;
;	MVI	C,56H	; USE 56H FOR 300 BAUD, 55H FOR 1200
;	LHLD	1
;	MVI	L,3CH	; SETUP SPECIAL OSBORNE JUMP
;	PCHL
;
LENC	EQU	$-BDJ	; LENGTH OF CODE MODULE TO COPY UP
; ------------------------------------------------------
;
	DS	80
STACK	EQU	$
	END