; From Dr. Dobb's Journal, Number 73, November 1982, pp. 6

; A letter from Oscar Goldman, extracted from
; CP/M EXCHANGE by Gene Head 

; Dear Gene,
;    This scheme is based on intercepting calls to the BDOS.  The
; only visible entry point into the BDOS is the jump instruction
; at the absolute memory address of 5.  WHile it might seem a
; simple matter to change the address at 6 and 7 in order to
; effect the interception, many applications programs (e.g., DDT)
; determine memory size from the information contained there.
; Therefore, it would seem prudent to leave the content of 6 and
; 7 alone.  Fortunately, for our purpose, the instruction jumped
; to from 5 is also a jump instruction.  This observation is the
; key to the interception process.
;    Here is an outline of the modifications to be made in the
; BIOS.  (If necessary, change the identifiers to avoid
; duplication.)
;    Add the following two equates:

; MAXFUN	EQU	49	; Last of the standard BDOS function numbers
; EXTRA	EQU	?	; Replace the "?" with the actual number
			; of new BDOS calls.  The new function
			; numbers will start from 50.

; Toward the end of the warm boot, there is a routine called
; "gocpm".  (This name is used by Digital Research in the listing
; of the skeletal CBIOS.)  Somewhere in there will be found the
; two lines:

;	LXI	H,BDOS
;	SHLD	6

; Immediately after these, insert the following 4 lines:

; 	LHLD	BDOS+1
;	SHLD	NORMAL+1
;	LXI	H,DIVERT
;	SHLD	BDOS+1

; and finish with the rest of "gocpm".
;     At a convenient point in the BIOS, add the following:

NORMAL:	EQU	JMP	0	; The 0 will be replaced during
				; the warm boot.
DIVERT:
	; This point is reached with the function number in C
	; and the BDOS call information in DE.
	MVI	A,MAXFUN
	CMP	C		; Is it an old or new call?
	JNC	NORMAL		; Old ones are diverted to NORMAL.
	ADI	EXTRA
	CMP	C		; Are we exceeding the number of
				; allowed calls?
	JNC	OKAY		; Continue if not.
	LXI	H,0		; Protocol requires these registers
				; to be zeroed for out-of-range calls.
	RET
;
OKAY:
	; Here we handle the new functions
	LXI	H,0		; HL is lost.
	DAD	SP
	SHLD	SAVSTK		; Save the stack pointer for later return,
	LXI	SP,SAVSTK	; and set up a local stack.
	XCHG
	SHLD	NTRPAR		; Save the entry parameters.
	LXI	D,FIN
	PUSH	D		; A place to return to when done.
	MOV	A,c
	SBI	MAXFUN+1	; Start counting from 0.
	ADD	A		; Double it
	MOV	E,A
	MVI	D,0
	LXI	D,TABLE
	DAD	D		; HL points to the revelent table entry.
	MOV	E,M		; Get the address
	INX	H		; contained there,
	MOV	D,M		; and move it
	XCHG			; into HL.
	PCHL			; Go do it.
;
FIN:
	; Return to here when done.
	LHLD	SAVSTK
	SPHL			; Restore old stack pointer.
	LHLD	XITPAR		; Get the result of the routine.
	MOV	A,L
	MOV	B,H		; As per CP/M protocol.
	RET			; All done.
;
TABLE:
	; Jump table for the various new BDOS calls.
	; There should be one entry for each of "EXTRA" items.
NEW0:	DW	DONEW0
NEW1:	DW	DONEW1
	...
	...
;
NITPAR:	DS	2		; Save the entry value of DE.
XITPAR:	DS	2		; Save the result of the BDOS call.
	DS	40		; Ample local stack -
				; change this if necessary.
SAVSTK:	DS	2		; Save the stack pointer on entry.
;
; Each of the following routines must end with a RET instruction.
; If the routine returns a value, then it should be stored in XITPAR.
;
DONEW0:				; Actual routine #0.

DONEW1:				; Actual routine #1.

	etc.
