

# Exidy Sorcerer - SS/DD, ie: 8" - 256 x 16
# 77 tracks, 1 sides, 16 sectors/track, 256 bytes/sector
# Bytes on the media = 1*77*16*256 = 315392
#
# EXI2  Exidy Sorcerer - SSDD 48 tpi 8" - 256 x 16
diskdef exi2
  seclen 256
  tracks 77
  sectrk 16
  blocksize 2048
  maxdir 64
  datarate HD
  fm YES 
  skew 5
# offset 8192       # 0x2000 = 8192
  boottrk 2
  os 2.2
end



cpmls -f exi2 -D disk1.raw
     Name    Bytes   Recs  Attr     update             create
------------ ------ ------ ---- -----------------  -----------------
ADMIN1  .WPF     2K      5    
ASM     .COM    10K     65    
BASCNVRT.COM     4K     17    
BASIC   .COM     2K     11    
BASIC1  .COM    10K     73    
BASIC2  .COM    10K     67    
BIOS    .ASM    12K     92    
BIOS    .WPF    12K     92    
CALENDAR.COM     6K     35    
CBIOS   .ASM     8K     55    
CHESS   .COM    10K     71    
COPYCAT .COM     2K      9    
DBS1    .WPF     4K     19    
DDT     .COM     6K     38    
DEVCNVRT.COM     2K     11    
DISKBAS .COM     4K     19    
DISKCOPY.COM     4K     21    
DUMP    .ASM     6K     35    
DUMP    .COM     2K      4    
ED      .COM     8K     49    
EXASM   .COM    12K     95    
EXBASIC .COM    24K    190    
EXLINK  .COM     6K     45    
FILECOPY.COM     2K      6    
FORMAT  .COM     4K     19    
INVADERS.COM     6K     42    
LIBINDEX.COM     4K     27    
LOAD    .COM     2K     15    
MAZE    .COM     6K     35    
MBASIC  .COM    24K    189    
MOVCPM  .COM    14K    102    
OBASIC  .COM    20K    145    
PATTERN .BAS     2K      2    
PIP     .COM     8K     57    
PRINT   .WPF     2K     11    
RAY1    .WPF     2K      6    
STAT    .COM     4K     24    
SUBMIT  .COM     2K     11    
SYSGEN  .COM     2K     10    
TOUCH   .COM     6K     33    
WP      .COM     2K      4    
WP9     .COM     6K     35    
   42 Files occupying    284K,      14K Free.


cpmcp -f exi2 disk1.raw 0:*.asm .


$ls -alt *.asm
-rw-r--r-- 1 larry larry 11776 Aug 11 21:36 bios.asm
-rw-r--r-- 1 larry larry  7040 Aug 11 21:36 cbios.asm
-rw-r--r-- 1 larry larry  4480 Aug 11 21:36 dump.asm


;	SKELETAL CBIOS FOR FIRST LEVEL OF CP/M ALTERATION
;
;	NOTE :  MSIZE DETERMINES WHERE THIS CBIOS IS LOCATED
MSIZE	EQU	16	;CP/M VERSION MEMORY SIZE IN KILOBYTES
PATCH	EQU	MSIZE*1024-2*256	;START OF THE CBIOS PATCH
IOBYTE	EQU	0003H	;INTEL I/O BYTE
CDISK	EQU	0004H	;CURRENT DISK NUMBER (0=A, ..., 3=D)
;
;	WE WILL USE THE AREA RESERVED STARTING AT LOCATION
;	40H IN PAGE 0 FOR HOLDING THE VALUES OF:
;		TRACK   =  LAST SELECTED TRACK
;		SECTOR  =  LAST SELECTED SECTOR
;		DMAAD   =  LAST SELECTED DMA ADDRESS
;		DISKNO  =  LAST SELECTED DISK NUMBER
;	(NOTE THAT ALL ARE BYTE VALUES EXCEPT FOR DMAAD)
;
SCRAT	EQU	40H		;BASE OF SCRATCH AREA (FROM 40H TO 4FH)
TRACK	EQU	SCRAT		;CURRENTLY SELECTED TRACK
SECTOR	EQU	SCRAT+1		;CURRENTLY SELECTED SECTOR
DMAAD	EQU	SCRAT+2		;CURRENT DMA ADDRESS
DISKNO	EQU	SCRAT+4	;CURRENT DISK NUMBER
;
;
	ORG	PATCH	;ORGIN OF THIS PROGRAM
CBASE	EQU	(MSIZE-16)*1024	;BIAS FOR SYSTEMS LARGER THAN 16K
CPMB	EQU	CBASE+2900H	;BASE OF CP/M (= BASE OF CCP)
BDOS	EQU	CBASE+3106H	;BASE OF RESIDENT PORTION OF CP/M
CPML	EQU	$-CPMB		;LENGTH OF THE CP/M SYSTEM IN BYTES
NSECTS	EQU	CPML/128	;NUMBER OF SECTORS TO LOAD ON WARM START
;
;	JUMP VECTOR FOR INDIVIDUAL SUBROUTINES
	JMP	BOOT		;COLD START
WBOOTE:
	JMP	WBOOT		;WARM START
	JMP	CONST		;CONSOLE STATUS
	JMP	CONIN		;CONSOLE CHARACTER IN
	JMP	CONOUT		;CONSOLE CHARACTER OUT
	JMP	LIST		;LIST CHARACTER OUT
	JMP	PUNCH		;PUNCH CHARACTER OUT
	JMP	READER		;READER CHARACTER OUT
	JMP	HOME		;MOVE HEAD TO HOME POSITION
	JMP	SELDSK		;SELECT DISK
	JMP	SETTRK		;SET TRACK NUMBER
	JMP	SETSEC		;SET SECTOR NUMBER
	JMP	SETDMA		;SET DMA ADDRESS
	JMP	READ		;READ DISK
	JMP	WRITE		;WRITE DISK
;
;
;	INDIVIDUAL SUBROUTINES TO PERFORM EACH FUNCTION
BOOT:	;SIMPLEST CASE IS TO JUST PERFORM PARAMETER INITIALIZATION
	XRA	A		;ZERO IN THE ACCUM
	STA	IOBYTE		;CLEAR THE IOBYTE
	STA	CDISK		;SELECT DISK ZERO
	JMP	GOCPM		;INITIALIZE AND GO TO CP/M
;
WBOOT:	;SIMPLEST CASE IS TO READ THE DISK UNTIL ALL SECTORS LOADED
	LXI	SP,80H		;USE SPACE BELOW BUFFER FOR STACK
	MVI	C,0		;SELECT DISK 0
	CALL	SELDSK
	CALL	HOME		;GO TO TRACK 00
;
	MVI	B,NSECTS	;B COUNTS THE NUMBER OF SECTORS TO LOAD
	MVI	C,0		;C HAS THE CURRENT TRACK NUMBER
	MVI	D,2		;D HAS THE NEXT SECTOR TO READ
;	NOTE THAT WE BEGIN BY READING TRACK 0, SECTOR 2 SINCE SECTOR 1
;	CONTAINS THE COLD START LOADER, WHICH IS SKIPPED IN A WARM START
	LXI	H,CPMB		;BASE OF CP/M (INITIAL LOAD POINT)
LOAD1:	;LOAD ONE MORE SECTOR
	PUSH	B	;SAVE SECTOR COUNT, CURRENT TRACK
	PUSH	D	;SAVE NEXT SECTOR TO READ
	PUSH	H	;SAVE DMA ADDRESS
	MOV	C,D	;GET SECTOR ADDRESS TO REGISTER C
	CALL	SETSEC	;SET SECTOR ADDRESS FROM REGISTER C
	POP	B	;RECALL DMA ADDRESS TO B,C
	PUSH	B	;REPLACE ON STACK FOR LATER RECALL
	CALL	SETDMA	;SET DMA ADDRESS FROM B,C
;
;	DRIVE SET TO 0, TRACK SET, SECTOR SET, DMA ADDRESS SET
	CALL	READ
	CPI	00H	;ANY ERRORS?
	JNZ	WBOOT	;RETRY THE ENTIRE BOOT IF AN ERROR OCCURS
;
;	NO ERROR, MOVE TO NEXT SECTOR
	POP	H	;RECALL DMA ADDRESS
	LXI	D,128	;DMA=DMA+128
	DAD	D	;NEW DMA ADDRESS IS IN H,L
	POP	D	;RECALL SECTOR ADDRESS
	POP	B	;RECALL NUMBER OF SECTORS REMAINING, AND CURRENT TRK
	DCR	B	;SECTORS=SECTORS-1
	JZ	GOCPM	;TRANSFER TO CP/M IF ALL HAVE BEEN LOADED
;
;	MORE SECTORS REMAIN TO LOAD, CHECK FOR TRACK CHANGE
	INR	D
	MOV	A,D	;SECTOR=27?, IF SO, CHANGE TRACKS
	CPI	27
	JC	LOAD1	;CARRY GENERATED IF SECTOR<27
;
;	END OF CURRENT TRACK, GO TO NEXT TRACK
	MVI	D,1	;BEGIN WITH FIRST SECTOR OF NEXT TRACK
	INR	C	;TRACK=TRACK+1
;
;	SAVE REGISTER STATE, AND CHANGE TRACKS
	PUSH	B
	PUSH	D
	PUSH	H
	CALL	SETTRK	;TRACK ADDRESS SET FROM REGISTER C
	POP	H
	POP	D
	POP	B
	JMP	LOAD1	;FOR ANOTHER SECTOR
;
;	END OF LOAD OPERATION, SET PARAMETERS AND GO TO CP/M
GOCPM:
	MVI	A,0C3H	;C3 IS A JMP INSTRUCTION
	STA	0	;FOR JMP TO WBOOT
	LXI	H,WBOOTE	;WBOOT ENTRY POINT
	SHLD	1	;SET ADDRESS FIELD FOR JMP AT 0
;
	STA	5	;FOR JMP TO BDOS
	LXI	H,BDOS	;BDOS ENTRY POINT
	SHLD	6	;ADDRESS FIELD OF JUMP AT 5 TO BDOS
;
	LXI	B,80H	;DEFAULT DMA ADDRESS IS 80H
	CALL	SETDMA
;
	EI		;ENABLE THE INTERRUPT SYSTEM
	LDA	CDISK	;GET CURRENT DISK NUMBER
	MOV	C,A	;SEND TO THE CCP
	JMP	CPMB	;GO TO CP/M FOR FURTHER PROCESSING
;
;
;	SIMPLE I/O HANDLERS (MUST BE FILLED IN BY USER)
;	IN EACH CASE, THE ENTRY POINT IS PROVIDED, WITH SPACE RESERVED
;	TO INSERT YOUR OWN CODE
;
CONST:	;CONSOLE STATUS, RETURN 0FFH IF CHARACTER READY, 00H IF NOT
	DS	10H	;SPACE FOR STATUS SUBROUTINE
	MVI	A,00H
	RET
;
CONIN:	;CONSOLE CHARACTER INTO REGISTER A
	DS	10H	;SPACE FOR INPUT ROUTINE
	ANI	7FH	;STRIP PARITY BIT
	RET
;
CONOUT: ;CONSOLE CHARACTER OUTPUT FROM REGISTER C
	MOV	A,C	;GET TO ACCUMULATOR
	DS	10H	;SPACE FOR OUTPUT ROUTINE
	RET
;
LIST:	;LIST CHARACTER FROM REGISTER C
	MOV	A,C	;CHARACTER TO REGISTER A
	RET		;NULL SUBROUTINE
;
PUNCH:	;PUNCH CHARACTER FROM REGISTER C
	MOV	A,C	;CHARACTER TO REGISTER A
	RET		;NULL SUBROUTINE
;
;
READER: ;READ CHARACTER INTO REGISTER A FROM READER DEVICE
	MVI	A,1AH	;ENTER END OF FILE FOR NOW (REPLACE LATER)
	ANI	7FH	;REMEMBER TO STRIP PARITY BIT
	RET
;
;
;	I/O DRIVERS FOR THE DISK FOLLOW
;	FOR NOW, WE WILL SIMPLY STORE THE PARAMETERS AWAY FOR USE
;	IN THE READ AND WRITE SUBROUTINES
;
HOME:	;MOVE TO THE TRACK 00 POSITION OF CURRENT DRIVE
;	TRANSLATE THIS CALL INTO A SETTRK CALL WITH PARAMETER 00
	MVI	C,0	;SELECT TRACK 0
	CALL	SETTRK
	RET		;WE WILL MOVE TO 00 ON FIRST READ/WRITE
;
SELDSK:	;SELECT DISK GIVEN BY REGISTER C
	MOV	A,C
	STA	DISKNO
	DS	10H	;SPACE FOR DISK SELECTION ROUTINE
	RET
;
SETTRK:	;SET TRACK GIVEN BY REGISTER C
	MOV	A,C
	STA	TRACK
	DS	10H	;SPACE FOR TRACK SELECT
	RET
;
SETSEC:	;SET SECTOR GIVEN BY REGISTER C
	MOV	A,C
	STA	SECTOR
	DS	10H	;SPACE FOR SECTOR SELECT
	RET
;
SETDMA:	;SET DMA ADDRESS GIVEN BY REGISTERS B AND C
	MOV	L,C	;LOW ORDER ADDRESS
	MOV	H,B	;HIGH ORDER ADDRESS
	SHLD	DMAAD	;SAVE THE ADDRESS
	DS	10H	;SPACE FOR SETTING THE DMA ADDRESS
	RET
;
READ:	;PERFORM READ OPERATION (USUALLY THIS IS SIMILAR TO WRITE
;	SO WE WILL ALLOW SPACE TO SET UP READ COMMAND, THEN USE
;	COMMON CODE IN WRITE)
	DS	10H	;SET UP READ COMMAND
	JMP	WAITIO	;TO PERFORM THE ACTUAL I/O
;
WRITE:	;PERFORM A WRITE OPERATION
	DS	10H	;SET UP WRITE COMMAND
;
WAITIO:	;ENTER HERE FROM READ AND WRITE TO PERFORM THE ACTUAL I/O 
;	OPERATION.  RETURN A 00H IN REGISTER A IF THE OPERATION COMPLETES
;	PROPERLY, AND 01H IF AN ERROR OCCURS DURING THE READ OR WRITE
;
;	IN THIS CASE, WE HAVE SAVED THE DISK NUMBER IN 'DISKNO' (0,1)
;				THE TRACK NUMBER IN 'TRACK' (0-76)
;				THE SECTOR NUMBER IN 'SECTOR' (1-26)
;				THE DMA ADDRESS IN 'DMAAD' (0-65535)
;	ALL REMAINING SPACE FROM $ THROUGH MSIZE*1024-1 IS AVAILABLE:
LEFT	EQU	(MSIZE*1024-1)-$	;SPACE REMAINING IN CBIOS
;
	MVI	A,1	;ERROR CONDITION
	RET		;REPLACED WHEN FILLED-IN
	END




;	MDS I/O DRIVERS FOR CP/M
;	(FOUR DRIVE SINGLE DENSITY VERSION)
;	VERSION 1.4 JANUARY, 1978
;
VERS	EQU	14	;VERSION 1.4
;
;	COPYRIGHT (C) 1978
;	DIGITAL RESEARCH
;	BOX 579, PACIFIC GROVE
;	CALIFORNIA, 93950
;
;
TRUE	EQU	0FFFFH	;VALUE OF "TRUE"
FALSE	EQU	NOT TRUE	;"FALSE"
SAMPLE	EQU	FALSE	;TRUE IF SAMPLE BIOS
;
	IF	SAMPLE
BIAS	EQU	2900H	;SAMPLE PROGRAM IN 16K SYSTEM
	ENDIF
	IF	NOT SAMPLE
BIAS	EQU	0000H	;GENERATE RELOCATABLE CP/M SYSTEM
	ENDIF
;
PATCH	EQU	1500H+BIAS
;
	ORG	PATCH
CPMB	EQU	000H+BIAS	;BASE OF CPM CONSOLE PROCESSOR
BDOS	EQU	806H+BIAS	;BASIC DOS (RESIDENT PORTION)
CPML	EQU	$-CPMB	;LENGTH (IN BYTES) OF CPM SYSTEM
NSECTS	EQU	CPML/128	;NUMBER OF SECTORS TO LOAD
OFFSET	EQU	2	;NUMBER OF DISK TRACKS USED BY CP/M
CDISK	EQU	0004H	;ADDRESS OF LAST LOGGED DISK ON WARM START
BUFF	EQU	0080H	;DEFAULT BUFFER ADDRESS
RETRY	EQU	10	;MAX RETRIES ON DISK I/O BEFORE ERROR
;
;	PERFORM FOLLOWING FUNCTIONS
;	BOOT	COLD START
;	WBOOT	WARM START (SAVE I/O BYTE)
;	(BOOT AND WBOOT ARE THE SAME FOR MDS)
;	CONST	CONSOLE STATUS
;		REG-A = 00 IF NO CHARACTER READY
;		REG-A = FF IF CHARACTER READY
;	CONIN	CONSOLE CHARACTER IN (RESULT IN REG-A)
;	CONOUT	CONSOLE CHARACTER OUT (CHAR IN REG-C)
;	LIST	LIST OUT (CHAR IN REG-C)
;	PUNCH	PUNCH OUT (CHAR IN REG-C)
;	READER	PAPER TAPE READER IN (RESULT TO REG-A)
;	HOME	MOVE TO TRACK 00
;
;	(THE FOLLOWING CALLS SET-UP THE IO PARAMETER BLOCK FOR THE
;	MDS, WHICH IS USED TO PERFORM SUBSEQUENT READS AND WRITES)
;	SELDSK	SELECT DISK GIVEN BY REG-C (0,1,2...)
;	SETTRK	SET TRACK ADDRESS (0,...76) FOR SUBSEQUENT READ/WRITE
;	SETSEC	SET SECTOR ADDRESS (1,...,26) FOR SUBSEQUENT READ/WRITE
;	SETDMA	SET SUBSEQUENT DMA ADDRESS (INITIALLY 80H)
;
;	(READ AND WRITE ASSUME PREVIOUS CALLS TO SET UP THE IO PARAMETERS)
;	READ	READ TRACK/SECTOR TO PRESET DMA ADDRESS
;	WRITE	WRITE TRACK/SECTOR FROM PRESET DMA ADDRESS
;
;	JUMP VECTOR FOR INDIVIUAL ROUTINES
	JMP	BOOT
WBOOTE:	JMP	WBOOT
	JMP	CONST
	JMP	CONIN
	JMP	CONOUT
	JMP	LIST
	JMP	PUNCH
	JMP	READER
	JMP	HOME
	JMP	SELDSK
	JMP	SETTRK
	JMP	SETSEC
	JMP	SETDMA
	JMP	READ
	JMP	WRITE
;
;
;	END OF CONTROLLER - INDEPENDENT CODE, THE REMAINING SUBROUTINES
;	ARE TAILORED TO THE PARTICULAR OPERATING ENVIRONMENT, AND MUST
;	BE ALTERED FOR ANY SYSTEM WHICH DIFFERS FROM THE INTEL MDS.
;
;	THE FOLLOWING CODE ASSUMES THE MDS MONITOR EXISTS AT 0F800H
;	AND USES THE I/O SUBROUTINES WITHIN THE MONITOR
;
;	WE ALSO ASSUME THE MDS SYSTEM HAS FOUR DISK DRIVES
NDISKS	EQU	4	;NUMBER OF DRIVES AVAILABLE
REVRT	EQU	0FDH	;INTERRUPT REVERT PORT
INTC	EQU	0FCH	;INTERRUPT MASK PORT
ICON	EQU	0F3H	;INTERRUPT CONTROL PORT
INTE	EQU	0111$1110B	;ENABLE RST 0(WARM BOOT), RST 7 (MONITOR)
;
;	MDS MONITOR EQUATES
MON80	EQU	0F800H	;MDS MONITOR
RMON80	EQU	0FF0FH	;RESTART MON80 (BOOT ERROR)
CI	EQU	0F803H	;CONSOLE CHARACTER TO REG-A
RI	EQU	0F806H	;READER IN TO REG-A
CO	EQU	0F809H	;CONSOLE CHAR FROM C TO CONSOLE OUT
PO	EQU	0F80CH	;PUNCH CHAR FROM C TO PUNCH DEVICE
LO	EQU	0F80FH	;LIST FROM C TO LIST DEVICE
CSTS	EQU	0F812H	;CONSOLE STATUS 00/FF TO REGISTER A
;
;	DISK PORTS AND COMMANDS
BASE	EQU	78H	;BASE OF DISK COMMAND IO PORTS
DSTAT	EQU	BASE	;DISK STATUS (INPUT)
RTYPE	EQU	BASE+1	;RESULT TYPE (INPUT)
RBYTE	EQU	BASE+3	;RESULT BYTE (INPUT)
;
ILOW	EQU	BASE+1	;IOPB LOW ADDRESS (OUTPUT)
IHIGH	EQU	BASE+2	;IOPB HIGH ADDRESS (OUTPUT)
;
READF	EQU	4H	;READ FUNCTION
WRITF	EQU	6H	;WRITE FUNCTION
RECAL	EQU	3H	;RECALIBRATE DRIVE
IORDY	EQU	4H	;I/O FINISHED MASK
CR	EQU	0DH	;CARRIAGE RETURN
LF	EQU	0AH	;LINE FEED
;
SIGNON:	;SIGNON MESSAGE: XXK CP/M VERS Y.Y
	DB	CR,LF,LF
	IF	SAMPLE
	DB	'16'	;16K EXAMPLE BIOS
	ENDIF
	IF	NOT SAMPLE
	DB	'00'	;MEMORY SIZE FILLED BY RELOCATOR
	ENDIF
	DB	'K CP/M VERS '
	DB	VERS/10+'0','.',VERS MOD 10+'0'
	DB	CR,LF,0
;
BOOT:	;PRINT SIGNON MESSAGE AND GO TO CCP
;	(NOTE: MDS BOOT INITIALIZED IOBYTE AT 0003H)
	LXI	SP,BUFF+80H
	LXI	H,SIGNON
	CALL	PRMSG	;PRINT MESSAGE
	XRA	A	;CLEAR ACCUMULATOR
	STA	CDISK	;SET INITIALLY TO DISK A
	JMP	GOCPM	;GO TO CP/M
;
;
WBOOT:;	LOADER ON TRACK 0, SECTOR 1, WHICH WILL BE SKIPPED FOR WARM 
;	READ CP/M FROM DISK - ASSUMING THERE IS A 128 BYTE COLD START
;	START.
;
	LXI	SP,BUFF	;USING DMA - THUS 80 THRU FF AVAILABLE FOR STACK
;
	MVI	C,RETRY	;MAX RETRIES
	PUSH	B
WBOOT0:	;ENTER HERE ON ERROR RETRIES
	LXI	B,CPMB	;SET DMA ADDRESS TO START OF DISK SYSTEM
	CALL	SETDMA
	MVI	C,0	;BOOT FROM DRIVE 0
	CALL	SELDSK
	MVI	C,0
	CALL	SETTRK	;START WITH TRACK 0
	MVI	C,2	;START READING SECTOR 2
	CALL	SETSEC
;
;	READ SECTORS, COUNT NSECTS TO ZERO
	POP	B	;10-ERROR COUNT
	MVI	B,NSECTS
RDSEC:	;READ NEXT SECTOR
	PUSH	B	;SAVE SECTOR COUNT
	CALL	READ
	JNZ	BOOTERR	;RETRY IF ERRORS OCCUR
	LHLD	IOD	;INCREMENT DMA ADDRESS
	LXI	D,128	;SECTOR SIZE
	DAD	D	;INCREMENTED DMA ADDRESS IN HL
	MOV	B,H
	MOV	C,L	;READY FOR CALL TO SET DMA
	CALL	SETDMA
	LDA	IOS	;SECTOR NUMBER JUST READ
	CPI	26	;READ LAST SECTOR?
	JC	RD1
;	MUST BE SECTOR 26, ZERO AND GO TO NEXT TRACK
	LDA	IOT	;GET TRACK TO REGISTER A
	INR	A
	MOV	C,A	;READY FOR CALL
	CALL	SETTRK
	XRA	A	;CLEAR SECTOR NUMBER
RD1:	INR	A	;TO NEXT SECTOR
	MOV	C,A	;READY FOR CALL
	CALL	SETSEC
	POP	B	;RECALL SECTOR COUNT
	DCR	B	;DONE?
	JNZ	RDSEC
;
;	DONE WITH THE LOAD, RESET DEFAULT BUFFER ADDRESS
GOCPM:	;(ENTER HERE FROM COLD START BOOT)
;	ENABLE RST0 AND RST7
	DI
	MVI	A,12H	;INITIALIZE COMMAND
	OUT	REVRT
	XRA	A
	OUT	INTC	;CLEARED
	MVI	A,INTE	;RST0 AND RST7 BITS ON
	OUT	INTC
	XRA	A
	OUT	ICON	;INTERRUPT CONTROL
;
;	SET DEFAULT BUFFER ADDRESS TO 80H
	LXI	B,BUFF
	CALL	SETDMA
;
;	RESET MONITOR ENTRY POINTS
	MVI	A,JMP
	STA	0
	LXI	H,WBOOTE
	SHLD	1	;JMP WBOOT AT LOCATION 00
	STA	5
	LXI	H,BDOS
	SHLD	6	;JMP BDOS AT LOCATION 5
	STA	7*8	;JMP TO MON80 (MAY HAVE BEEN CHANGED BY DDT)
	LXI	H,MON80
	SHLD	7*8+1
;	LEAVE IOBYTE SET
;	PREVIOUSLY SELECTED DISK WAS B, SEND PARAMETER TO CPM
	LDA	CDISK	;LAST LOGGED DISK NUMBER
	MOV	C,A	;SEND TO CCP TO LOG IT IN
	EI
	JMP	CPMB
;
;	ERROR CONDITION OCCURRED, PRINT MESSAGE AND RETRY
BOOTERR:
	POP	B	;RECALL COUNTS
	DCR	C
	JZ	BOOTER0
;	TRY AGAIN
	PUSH	B
	JMP	WBOOT0
;
BOOTER0:
;	OTHERWISE TOO MANY RETRIES
	LXI	H,BOOTMSG
	CALL	PRMSG
	JMP	RMON80	;MDS HARDWARE MONITOR
;
BOOTMSG:
	DB	'?BOOT',0
;
;
CONST:	;CONSOLE STATUS TO REG-A
;	(EXACTLY THE SAME AS MDS CALL)
	JMP	CSTS
;
CONIN:	;CONSOLE CHARACTER TO REG-A
	CALL	CI
	ANI	7FH	;REMOVE PARITY BIT
	RET
;
CONOUT:	;CONSOLE CHARACTER FROM C TO CONSOLE OUT
	JMP	CO
;
LIST:	;LIST DEVICE OUT
;	(EXACTLY THE SAME AS MDS CALL)
	JMP	LO
;
PUNCH:	;PUNCH DEVICE OUT
;	(EXACTLY THE SAME AS MDS CALL)
	JMP	PO
;
READER:	;READER CHARACTER IN TO REG-A
;	(EXACTLY THE SAME AS MDS CALL)
	JMP	RI
;
HOME:	;MOVE TO HOME POSITION
;	TREAT AS TRACK 00 SEEK
	MVI	C,0
	JMP	SETTRK
;
SELDSK:	;SELECT DISK GIVEN BY REGISTER C
;	CP/M HAS CHECKED FOR DISK SELECT 0 - 3, BUT WE MAY HAVE 
;	A SMALLER MDS SYSTEM, SO CHECK AGAIN AND GIVE ERROR
;	BY CALLING MON80
	MOV	A,C
	CPI	NDISKS	;TOO LARGE?
	CNC	RMON80	;GIVES #ADDR MESSAGE AT CONSOLE
;
	ANI	10B	;00 00 FOR DRIVE 0,1 AND 10 10 FOR DRIVE 2,3
	STA	DBANK	;TO SELECT DRIVE BANK
	MOV	A,C	;00, 01, 10, 11
	ANI	1B	;MDS HAS 0,1 AT 78, 2,3 AT 88
	ORA	A	;RESULT 00?
	JZ	SETDRIVE
	MVI	A,00110000B	;SELECTS DRIVE 1 IN BANK
SETDRIVE:
	MOV	C,A	;SAVE THE FUNCTION
	LXI	H,IOF	;IO FUNCTION
	MOV	A,M
	ANI	11001111B	;MASK OUT DISK NUMBER
	ORA	C	;MASK IN NEW DISK NUMBER
	MOV	M,A	;SAVE IT IN IOPB
	RET
;
;
SETTRK:	;SET TRACK ADDRESS GIVEN BY C
	LXI	H,IOT
	MOV	M,C
	RET
;
SETSEC:	;SET SECTOR NUMBER GIVEN BY C
	MOV	A,C	;SECTOR NUMBER TO ACCUM
	STA	IOS	;STORE SECTOR NUMBER TO IOPB
	RET
;
SETDMA:	;SET DMA ADDRESS GIVEN BY REGS B,C
	MOV	L,C
	MOV	H,B
	SHLD	IOD
	RET
;
READ:	;READ NEXT DISK RECORD (ASSUMING DISK/TRK/SEC/DMA SET)
	MVI	C,READF	;SET TO READ FUNCTION
	CALL	SETFUNC
	CALL	WAITIO	;PERFORM READ FUNCTION
	RET		;MAY HAVE ERROR SET IN REG-A
;
;
WRITE:	;DISK WRITE FUNCTION
	MVI	C,WRITF
	CALL	SETFUNC	;SET TO WRITE FUNCTION
	CALL	WAITIO
	RET		;MAY HAVE ERROR SET
;
;
;	UTILITY SUBROUTINES
PRMSG:	;PRINT MESSAGE AT H,L TO 0
	MOV	A,M
	ORA	A	;ZERO?
	RZ
;	MORE TO PRINT
	PUSH	H
	MOV	C,A
	CALL	CONOUT
	POP	H
	INX	H
	JMP	PRMSG
;
SETFUNC:
;	SET FUNCTION FOR NEXT I/O (COMMAND IN REG-C)
	LXI	H,IOF	;IO FUNCTION ADDRESS
	MOV	A,M	;GET IT TO ACCUMULATOR FOR MASKING
	ANI	11111000B	;REMOVE PREVIOUS COMMAND
	ORA	C	;SET TO NEW COMMAND
	MOV	M,A	;REPLACED IN IOPB
;	THE MDS-800 CONTROLLER REQUIRES DISK BANK BIT IN SECTOR BYTE
;	MASK THE BIT FROM THE CURRENT I/O FUNCTION
	ANI	00100000B	;MASK THE DISK SELECT BIT
	LXI	H,IOS		;ADDRESS THE SECTOR SELECT BYTE
	ORA	M		;SELECT PROPER DISK BANK
	MOV	M,A		;SET DISK SELECT BIT ON/OFF
	RET
;
WAITIO:
	MVI	C,RETRY	;MAX RETRIES BEFORE PERM ERROR
REWAIT:
;	START THE I/O FUNCTION AND WAIT FOR COMPLETION
	CALL	INTYPE	;IN RTYPE
	CALL	INBYTE	;CLEARS THE CONTROLLER
;
	LDA	DBANK		;SET BANK FLAGS
	ORA	A		;ZERO IF DRIVE 0,1 AND NZ IF 2,3
	MVI	A,IOPB AND 0FFH	;LOW ADDRESS FOR IOPB
	MVI	B,IOPB SHR 8	;HIGH ADDRESS FOR IOPB
	JNZ	IODR1	;DRIVE BANK 1?
	OUT	ILOW		;LOW ADDRESS TO CONTROLLER
	MOV	A,B
	OUT	IHIGH	;HIGH ADDRESS
	JMP	WAIT0		;TO WAIT FOR COMPLETE
;
IODR1:	;DRIVE BANK 1
	OUT	ILOW+10H	;88 FOR DRIVE BANK 10
	MOV	A,B
	OUT	IHIGH+10H
;
WAIT0:	CALL	INSTAT		;WAIT FOR COMPLETION
	ANI	IORDY		;READY?
	JZ	WAIT0
;
;	CHECK IO COMPLETION OK
	CALL	INTYPE		;MUST BE IO COMPLETE (00) UNLINKED
;	00 UNLINKED I/O COMPLETE,    01 LINKED I/O COMPLETE (NOT USED)
;	10 DISK STATUS CHANGED       11 (NOT USED)
	CPI	10B		;READY STATUS CHANGE?
	JZ	WREADY
;
;	MUST BE 00 IN THE ACCUMULATOR
	ORA	A
	JNZ	WERROR		;SOME OTHER CONDITION, RETRY
;
;	CHECK I/O ERROR BITS
	CALL	INBYTE
	RAL
	JC	WREADY		;UNIT NOT READY
	RAR
	ANI	11111110B	;ANY OTHER ERRORS?  (DELETED DATA OK)
	JNZ	WERROR
;
;	READ OR WRITE IS OK, ACCUMULATOR CONTAINS ZERO
	RET
;
WREADY:	;NOT READY, TREAT AS ERROR FOR NOW
	CALL	INBYTE		;CLEAR RESULT BYTE
	JMP	TRYCOUNT
;
WERROR:	;RETURN HARDWARE MALFUNCTION (CRC, TRACK, SEEK, ETC.)
;	THE MDS CONTROLLER HAS RETURNED A BIT IN EACH POSITION
;	OF THE ACCUMULATOR, CORRESPONDING TO THE CONDITIONS:
;	0	- DELETED DATA (ACCEPTED AS OK ABOVE)
;	1	- CRC ERROR
;	2	- SEEK ERROR
;	3	- ADDRESS ERROR (HARDWARE MALFUNCTION)
;	4	- DATA OVER/UNDER FLOW (HARDWARE MALFUNCTION)
;	5	- WRITE PROTECT (TREATED AS NOT READY)
;	6	- WRITE ERROR (HARDWARE MALFUNCTION)
;	7	- NOT READY
;	(ACCUMULATOR BITS ARE NUMBERED 7 6 5 4 3 2 1 0)
;
;	IT MAY BE USEFUL TO FILTER OUT THE VARIOUS CONDITIONS,
;	BUT WE WILL GET A PERMANENT ERROR MESSAGE IF IT IS NOT
;	RECOVERABLE.  IN ANY CASE, THE NOT READY CONDITION IS
;	TREATED AS A SEPARATE CONDITION FOR LATER IMPROVEMENT
TRYCOUNT:
;	REGISTER C CONTAINS RETRY COUNT, DECREMENT 'TIL ZERO
	DCR	C
	JNZ	REWAIT	;FOR ANOTHER TRY
;
;	CANNOT RECOVER FROM ERROR
	MVI	A,1	;ERROR CODE
	RET
;
;	INTYPE, INBYTE, INSTAT READ DRIVE BANK 00 OR 10
INTYPE:	LDA	DBANK
	ORA	A
	JNZ	INTYP1	;SKIP TO BANK 10
	IN	RTYPE
	RET
INTYP1:	IN	RTYPE+10H	;78 FOR 0,1  88 FOR 2,3
	RET
;
INBYTE:	LDA	DBANK
	ORA	A
	JNZ	INBYT1
	IN	RBYTE
	RET
INBYT1:	IN	RBYTE+10H
	RET
;
INSTAT:	LDA	DBANK
	ORA	A
	JNZ	INSTA1
	IN	DSTAT
	RET
INSTA1:	IN	DSTAT+10H
	RET
;
;
;
;	DATA AREAS (MUST BE IN RAM)
DBANK:	DB	0	;DISK BANK 00 IF DRIVE 0,1
			;	   10 IF DRIVE 2,3
IOPB:	;IO PARAMETER BLOCK
	DB	80H	;NORMAL I/O OPERATION
IOF:	DB	READF	;IO FUNCTION, INITIAL READ
ION:	DB	1	;NUMBER OF SECTORS TO READ
IOT:	DB	OFFSET	;TRACK NUMBER
IOS:	DB	1	;SECTOR NUMBER
IOD:	DW	BUFF	;IO ADDRESS
;
;
	END

