;=====================================================================
;    MP/M-80 II Resident Extended Input/Output System, Version 1.0
;=====================================================================
;
; Copyright (C) 1981 ,by MICROCOSM.All rights reserved.No part may be
; reproduced,transmitted,transcribed ,stored in retrieval system,  or
; translated into any language or  computer language, in any form  or
; by any means,electronic,mechanical,magnetic,optical,chemical,manual
; or  otherwise,  without the prior written  permission of MICROCOSM,
; 3055 Waco St.,Simi Valley,California 93063.
;
;                           Disclaimer
;                           ==========
;
; MICROCOSM  makes no representation or warranties with respect to the
; contents herof and specifically disclaims any implied warranties  of
; merchantability  or  fitness for any particular purpose.   Further ,
; MICROCOSM  reserves the  right to  revise and to   make changes from
; time to  time in the  content hereof without obligation of MICROCOSM
; to notify any person of such revision or changes.
;
;
;
;
; THIS MODULE CONTAINS ALL THE INPUT/OUTPUT ROUTINES FOR THE MP/M-80 II SYSTEM
;
;
; CONSOLE PORT #0 I/O PARAMETER EQUATES
;
CCTRL	EQU	010H	; CONSOLE STATUS PORT 
CCTRL	EQU	010H	; CONSOLE COMMAND PORT 
CDATA	EQU	011H	; CONSOLE DATA PORT 
CRRDY	EQU	001H	; CONSOLE RECEIVER READY BIT
CTRDY	EQU	002H	; CONSOLE TRANSMITTER READY BIT
CNULL	EQU	000H	; CONSOLE NULL COUNT 
;
; CONSOLE PORT #1 I/O PARAMETER EQUATES
;
MCTRL	EQU	01AH	; MODEM CONTROL/STATUS PORT
MDATA	EQU	01BH	; MODEM DATA PORT
MRRDY	EQU	001H	; MODEM RECEIVER READY BIT
MTRDY	EQU	002H	; MODEM TRANSMITTER READY BIT
CARDET	EQU	004H	; DATA CARRIER DETECT MASK

ROMBOOT EQU	0F13DH	; ROM BOOT ENTRY ADDRESS

;
;  VECTOR INTERRUPT/REAL TIME CLOCK I/O PARAMETER EQUATES
; 
VICNTRL	EQU	0FEH	; 88-VI(RTC) CONTROL PORT
FLAGSET	EQU	133
DSPTCH	EQU	142
; 
;  VECTOR INTERRUPT/REAL TIME CLOCK VECTOR LEVEL EQUATES
; 
VEC1	EQU	0DDH	; VECTOR LEVEL 1 (RST 1), ADDRESS 0008 HEX
; 
;  DISK I/O PARAMETER EQUATES
; 
CNTRL	EQU	0C0H	; ICOM 3712 DISK CONTROL COMMAND PORT
DATAO	EQU	0C1H	; ICOM 3712 DISK DATA OUT PORT
DATAI	EQU	0C0H	; ICOM 3712 DISK DATA IN PORT
; 
;  LIST DEVICE I/O PARAMETER EQUATES
; 
LSTAT	EQU	002H	; LIST STATUS PORT
LCOM	EQU	002H	; LIST COMMAND PORT
LDATA	EQU	003H	; LIST DATA PORT
LRBIT	EQU	080H	; LISTER READY BIT 
LNULL	EQU	000H	; LIST NULL COUNT
LINCNT	EQU	66	; LINES PER PRINTER PAGE
; 
;  ASCII CHARACTER EQUATES
;
RUBOUT	EQU	7FH
SPACE	EQU	20H
;
TDISKS	EQU	2	; NUMBER OF AVAILABLE DISKS
;
NMBDEV	EQU	6	; NUMBER OF DEVICES IN POLL TABLE
;
NMBCNS	EQU	2	; NUMBER OF CONSOLES
;
POLL	EQU	131	; XDOS POLL FUNCTION
;
PLLPT	EQU	0	; POLL PRINTER
PLDSK	EQU	1	; POLL DISK
PLCO0	EQU	2	; POLL CONSOLE OUT #0
PLCO1	EQU	3	; POLL CONSOLE OUT #1 (MODEM)
PLCI0	EQU	4	; POLL CONSOLE IN #0
PLCI1	EQU	5	; POLL CONSOLE IN #1 (MODEM)
;
RTCNT	EQU	10	; RETRY COUNT 
;
IOBYTE	EQU	3	; ADDRESS OF I/O BYTE 
;
OFFSET	EQU	2	; NUMBER OF TRACKS USED BY MP/M-80 II

	ORG	00000H	; START OF REL-0 XIOS FOR MP/M-80 II
;
;		+++ I/O JUMP VECTOR +++
;
;
	JMP	COMMONBASE	; COMMON BASE, TERMINATE PROCESS
WBOOTE:	JMP	WBOOT		; WARM BOOT, TERMINATE PROCESS
	JMP	CONST		; CONSOLE STATUS
	JMP	CONIN		; CONSOLE CHARACTER IN
	JMP	CONOUT		; CONSOLE CHARACTER OUT
	JMP	LIST		; LIST CHARACTER OUT
	JMP	PUNCH		; PUNCH NOT IMPLEMENTED
	JMP	READER		; READER NOT IMPLEMENTED
	JMP	HOME		; MOVE HEAD TO HOME
	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
	JMP	POLLPT		; LIST STATUS
	JMP	SECTRAN		; SECTOR TRANSLATE
; 
;  EXTENDED I/O SYSTEM JUMP VECTOR
; 
	JMP	SELMEMORY	; SELECT MEMORY
	JMP	POLLDEVICE	; POLL DEVICE
	JMP	STARTCLOCK	; START CLOCK
	JMP	STOPCLOCK	; STOP CLOCK
	JMP	EXITREGION	; EXIT REGION
	JMP	MAXCONSOLE	; MAXIMUM CONSOLE NUMBER
	JMP	SYSTEMINIT	; SYSTEM INITIALIZATION
	DB	0,0,0		; IDLE PROCEDURE, NOT USED

;
COMMONBASE:			; TERMINATE PROCESS
;
	JMP	COLDSTART
SWTUSER:JMP	$-$
SWTSYS:	JMP	$-$
PDISP:	JMP	$-$
XDOS:	JMP	$-$
SYSDAT:	DW	$-$
;
COLDSTART:
WARMSTART:
;
	MVI	C,0		; SYETM RESET, TERMINATE PROCESS
	JMP	XDOS
;
;  MP/M-80 II   CONSOLE HANDLERS
;
CONST:			; CONSOLE STATUS
	CALL	PTBLJMP	; COMPUTE AND JUMP TO HANDLER
	DW	PT0ST	; CONSOLE #0 STATUS ROUTINE
	DW	PT1ST	; CONSOLE #1 (MODEM) STATUS RT

READER:			; READER NOT IMPLEMENTED
	MVI	D,0	; DEFAULT TO CONIN #0

CONIN:			; CONSOLE INPUT
	CALL	PTBLJMP	; COMPUTE AND JUMP TO HANDLER
	DW	PT0IN	; CONSOLE #0 INPUT
	DW	PT1IN	; CONSOLE #1 (MODEM) INPUT

PUNCH:			; PUNCH NOT IMPLEMENTED
	MVI	D,0	; DEFAULT TO CONOUT #0

CONOUT:			; CONSOLE OUTPUT
	CALL	PTBLJMP	; COMPUTE AND JUMP TO HANDLER
	DW	PT0OUT	; CONSOLE #0 OUTPUT
	DW	PT1OUT	; CONSOLE #1 (MODEM) OUTPUT

;
PTBLJMP:		; COMPUTE AND JUMP TO HANDLER
			; D = CONSOLE #
			; DO NOT DESTROY <D>
	MOV	A,D
	CPI	NMBCNS
	JC	TBLJMP
	POP	PSW	; THROW AWAY TABLE ADDRESS
RTNEMPTY:
	XRA	A
	RET
TBLJMP:			; COMPUTE AND JUMP TO HANDLER
			; A = TABLE INDEX
	ADD	A	; DOUBLE TABLE INDEX FOR ADR OFFST
	POP	H	; RETURN ADR POINTS TO JUMP TBL
	MOV	E,A
	MVI	D,0
	DAD	D	; ADD TABLE INDEX * 2 TO TBL BASE
	MOV	E,M	; GET HANDLER ADDRESS
	INX	H
	MOV	D,M
	XCHG
	PCHL		; JUMP TO COMPUTED CNS HANDLER
;
; CHECK CONSOLE INPUT STATUS
;
; POLL CONSOLE #0 INPUT

POLCI0:
PT0ST:			; RETURN 0FFH IF READY,
			;        000H IF NOT
	IN	CCTRL	; READ CONSOLE STATUS
	ANI	CRRDY	; LOOK AT RECEIVER READY BIT
	MVI	A,0	; SET A=0 FOR RETURN
	RZ		; NOT READY, WHEN 0
	MVI	A,0FFH	; IF READY A=FF
	RET		; RETURN FROM POLCI0
;
; READ A CHARACTER FROM CONSOLE.
;
; CONSOLE #0 INPUT
;
PT0IN:			; RETURN CHARACTER IN REG A
	MVI	C,POLL
	MVI	E,PLCI0
	CALL	XDOS	; POLL CONSOLE #0 INPUT
	IN	CDATA	; READ A CHARACTER 
	ANI	7FH	; MAKE MOST SIG. BIT = 0
	CPI	RUBOUT	; IS IT A RUBOUT?
	RNZ		; RETURN IF NOT
	MVI	A,0FFH	; SET NO PRINT FLAG
	STA	CONOTF
	MVI	A,7FH	; RESTORE RUBOUT
	RET		; RETURN FROM PT0IN
;
; WRITE A CHARACTER TO THE CONSOLE DEVICE
;
; CONSOLE #0 OUTPUT
;
PT0OUT:			; REG C = CHARACTER TO OUTPUT
	PUSH	B
	CALL	PT0WAIT	; POLL CONSOLE #0 OUTPUT
	POP	B
	MOV	A,C	; GET CHARACTER
	OUT	CDATA	; PRINT IT
	RET		; RETURN FROM PT0OUT
;
; WAIT FOR CONSOLE #0 OUTPUT READY
;
PT0WAIT:
	MVI	C,POLL
	MVI	E,PLCO0
	JMP	XDOS	; POLL CONSOLE #0 OUTPUT
;	RET

;
; POLL CONSOLE #0 OUTPUT
;
POLCO0:
			; RETURN 0FFH IF READY,
			;        000H IF NOT
	IN	CCTRL	; READ CONSOLE STATUS
	ANI	CTRDY	; IF NOT READY,
	MVI	A,0	; RETURN WITH ZERO'S
	RZ		; NOT READY, WHEN 0
	MVI	A,0FFH
	RET		; RETURN FROM POLCO0
;
; WRITE A CHARACTER ON LISTING DEVICE
;
LIST:			; LIST OUTPUT
	PUSH	B
	PUSH	D
	MVI	C, POLL
	MVI	E, PLLPT
	CALL	XDOS
	POP	D
	POP	B
	MOV	A,C	; GET DATA BYTE
	OUT	LDATA	; PRINT IT
	RET		; RETURN FROM LIST
; 
; RETURN LIST STATUS
;
LISTST:	XRA	A	; FLAG LISTER NOT READY
	RET

;
;  POLL PRINTER OUTPUT
;
POLLPT:
			; RETURN 0FFH IF READY,
			;        000H IF NOT
	IN	LSTAT	; READ LISTER STATUS.
	ANI	LRBIT	; LOOK AT READY BIT.
	MVI	A,0	; RETURN WITH ZERO'S IF NOT READY
	RNZ
	MVI	A,0FFH
	RET
;
;  POLL CONSOLE #1 (MODEM) INPUT
;
POLCI1:
PT1ST:
			; RETURN 0FFH IF READY,
			;        000H IF NOT
	IN	MCTRL	; GET MODEM STATUS
	ANI	CARDET	; DATA CARRIER DETECT ON?
	JNZ	RESTART	; EXIT, IF NO CARRIER
	IN	MCTRL	; GET MODEM STATUS
	ANI	MRRDY	; MASK MODEM RECEIVER READY
	MVI	A,0	; RETURN WITH ZERO'S
	RZ		; RETURN IF ZERO FLAG SET
	MVI	A,0FFH	; IF READY,A=FFH
	RET		; RETURN FROM POLCI1
;
;  CONSOLE #1 (MODEM) INPUT
;
PT1IN:
			; RETURN CHARACTER IN REG A
	IN	MCTRL	; GET MODEM STATUS
	ANI	CARDET	; DATA CARRIER DETECT ON?
	JNZ	RESTART	; EXIT, IF NO CARRIER
	MVI	C,POLL
	MVI	E,PLCI1
	CALL	XDOS	; POLL CONSOLE #1 INPUT
	IN	MDATA	; GET MODEM DATA BYTE
	ANI	07FH	; STRIP OFF MSB FOR ASCII
	RET		; RETURN FROM CONIN
; 
;  CONSOLE #1 (MODEM) OUTPUT
;
PT1OUT:
			; REG C = CHARACTER TO OUTPUT
	IN	MCTRL	; GET MODEM STATUS
	ANI	CARDET	; DATA CARRIER DETECT ON?
	JNZ	RESTART	; EXIT, IF NO CARRIER
	PUSH	B
	CALL	PT1WAIT
	POP	B
	MOV	A,C	; GET CHARACTER
	OUT	MDATA	; OUT TO MODEM
	RET		; RETURN FROM CONOUT

;  WAIT FOR CONSOLE #1 (MODEM) OUTPUT READY

PT1WAIT:
	MVI	C,POLL
	MVI	E,PLCO1
	JMP	XDOS		; POLL CONSOLE #1 OUTPUT
;	RET

;  POLL CONSOLE #1 (MODEM) OUTPUT

POLCO1:
			; RETURN 0FFH IF READY,
			;        000H IF NOT
	IN	MCTRL	; GET MODEM STATUS
	ANI	CARDET	; DATA CARRIER DETECT ON?
	JNZ	RESTART	; EXIT, IF NO CARRIER
	IN	MCTRL	; GET MODEM STATUS
	ANI	MTRDY	; MASK MODEM TRANSMITTER READY
	MVI	A,0	; RETURN WITH ZERO'S
	RZ
	MVI	A,0FFH	; IF READY,A=FFH
	RET		; RETURN FROM POLCO1
; 
;  WAIT FOR DATA CARRIER DETECT, THEN RESTART AT "BOOT"
; 
LIGHTS	EQU	0FFH	; IMSAI FRONT PANEL DATA LIGHTS
SWITCH	EQU	0FFH	; IMSAI FRONT PANEL DATA SWITCHES
; 
RESTART:MVI	B,10	; SET MAJOR DELAY LOOP
	XRA	A	; RESET FRON PANEL LIGHTS
	OUT	LIGHTS
DELAY:	LXI	H,0FFFFH; SET MINOR DELAY LOOP
DELAY1: DCX	H
	MOV	A,H
	ORA	L
	JNZ	DELAY1	; LOOP MINOR DELAY
	CMA		; SET FRONT PANEL LIGHTS
	OUT	LIGHTS
	DCR	B
	JNZ	DELAY	; LOOP MAJOR DELAY
	MVI	A,003H	; RESET MODEM 2SI/O PORT
	OUT	MCTRL
	MVI	A,011H	; SET 8 DATA BITS,2 STOP, NO PARITY
	OUT	MCTRL
CARWAIT:IN	MCTRL	; GET MODEM STATUS, AND WAIT FOR CARRIER
	ANI	CARDET	; DATA CARRIER DETECT ON?
	JNZ	RESTART	; LOOP HERE 'TILL IT IS
	JMP	ROMBOOT	; ROM BOOT WHEN READY
;
;	MP/M-80 II EXTENDED I/O SYSTEM
;
POLLDEVICE:
			; REG C = DEVICE # TO BE POLLED
			; RETURN 0FFH IF READY,
			;        000H IF NOT
	MOV	A,C
	CPI	NMBDEV
	JC	DEVOK
	MVI	A,NMBDEV; IF DEV # >= NMBDEV,
			; SET TO NMBDEV
DEVOK:
	CALL	TBLJMP	; JUMP TO DEV POLL CODE

	DW	POLLPT	; POLL PRINTER OUTPUT
	DW	POLDSK	; POLL DISK READY
	DW	POLCO0	; POLL CONSOLE #0 OUTPUT
	DW	POLCO1	; POLL CONSOLE #1 (MODEM) OUTPUT
	DW	POLCI0	; POLL CONSOLE #0 INPUT
	DW	POLCI1	; POLL CONSOLE #1 (MODEM) INPUT
	DW	RTNEMPTY; BAD DEVICE HANDLER


; SELECT / PROTECT MEMORY

SELMEMORY:
			; REG BC = ADR OF MEM DESCRIPTOR
			; BC ->  BASE   1 BYTE,
			;        SIZE   1 BYTE,
			;        ATTRIB 1 BYTE,
			;        BANK   1 BYTE.

; THIS HARDWARE DOES NOT HAVE MEMORY PROTECTION OR BANK SWITCHING

	RET


; START CLOCK

STARTCLOCK:
			; WILL CAUSE FLAG #1 TO BE SET
			;  AT EACH SYSTEM TIME UNIT TICK
	MVI	A,0FFH
	STA	TICKN
	RET

; STOP CLOCK

STOPCLOCK:
			; WILL STOP FLAG #1 SETTING AT
			;  SYSTEM TIME UNIT TICK
	XRA	A
	STA	TICKN
	RET

; EXIT REGION

EXITREGION:
			; EI IF NOT PREEMPTED
	LDA	PREEMP
	ORA	A
	RNZ
	EI
	RET

; MAXIMUM CONSOLE NUMBER

MAXCONSOLE:
	MVI	A,NMBCNS
	RET

;  SYSTEM INITIALIZATION

SYSTEMINIT:
;
	MVI	A,003H	; CONSOLE AND MODEM RESET
	OUT	CCTRL
	OUT	MCTRL
	MVI	A,011H	; NO INTERRUPTS,8 DATA BITS,NO PARITY,1 STOP BIT
	OUT	CCTRL
	OUT	MCTRL
;
;	CLEAR XIOS VARIABLE AREA
;
	MVI	C,ENDZ-STARTZ	; GET LENGTH OF ZERO AREA
	LXI	H,STARTZ	; POINT TO THE START OF ZERO AREA
CLEAR:	XRA	A	; MAKE ZERO
	MOV	M,A	; JAM INTO MEMORY
	INX	H	; BUMP POINTER
	DCR	C	; DE-BUMP LENGTH
	JNZ	CLEAR	; LOOP UNTIL ALL CLEARED
;
;	SETUP RESTART JUMP VECTORS
; 
	MVI	A,0C3H
	STA	1*8
	LXI	H,INT1HND
	SHLD	1*8+1	; JMP INT1HND AT RESTART 1
	MVI	A,0C9H	; RETURNS FOR ALL REMAINING INTERRUPT VECTORS
	STA	2*8
	STA	3*8
	STA	4*8
	STA	5*8
	STA	6*8
	MVI	A,0F0H	; ENABLE VI AND RTC, RESET INTERRUPT, CLEAR COUNTERS
	OUT	VICNTRL
	RET

;  MP/M-80 II   INTERRUPT HANDLERS

INT1HND:
			; INTERRUPT 1 HANDLER ENTRY POINT
			;  
			;  LOCATION 0008H CONTAINS A JMP
			;  TO INT1HND.
	PUSH	PSW
	MVI	A,VEC1	; SET VECTOR LEVEL 1 (RST 1), ADDRESS 0008 HEX
	OUT	VICNTRL
	LDA	SLICE
	DCR	A	; ONLY SERVICE EVERY 2ND SLICE
	STA	SLICE
	JZ	T40MS	; JUMP IF 40MS ELAPSED
	POP	PSW
	EI
	RET

T40MS:
	MVI	A,4
	STA	SLICE	; RESET SLICE COUNTER
	POP	PSW
	SHLD	SVDHL
	POP	H
	SHLD	SVDRET
	PUSH	PSW
	LXI	H,0
	DAD	SP
	SHLD	SVDSP		; SAVE USERS STK PTR
	LXI	SP,INTSTK+48	; LCL STK FOR INTR HNDL
	PUSH	D
	PUSH	B

	MVI	A,0FFH
	STA	PREEMP	; SET PREEMPTED FLAG

	LDA	TICKN
	ORA	A		; TEST TICKN, INDICATES
				;  DELAYED PROCESS(ES)
	JZ	NOTICKN
	MVI	C,FLAGSET
	MVI	E,1
	CALL	XDOS		; SET FLAG #1 EACH TICK
NOTICKN:
	LXI	H,CNT25
	DCR	M		; DEC 25 TICK CNTR
	JNZ	NOT1SEC
	MVI	M,25
	MVI	C,FLAGSET
	MVI	E,2
	CALL	XDOS		; SET FLAG #2 @ 1 SEC
NOT1SEC:
	XRA	A
	STA	PREEMP	; CLEAR PREEMPTED FLAG
	POP	B
	POP	D
	LHLD	SVDSP
	SPHL			; RESTORE STK PTR
	POP	PSW
	LHLD	SVDRET
	PUSH	H
	LHLD	SVDHL

; THE FOLLOWING DISPATCH CALL WILL FORCE ROUND ROBIN
; SCHEDULING OF PROCESSES EXECUTING AT THE SAME PRIORITY
; EVERY 40 MILLI-SECONDS.
;
; NOTE: INTERRUPTS ARE NOT ENABLED UNTIL THE DISPATCHER
; RESUMES THE NEXT PROCESS.  THIS PREVENTS INTERRUPT
; OVER-RUN OF THE STACKS WHEN STUCK OR HIGH FREQUENCY
; INTERRUPTS ARE ENCOUNTERED.

	JMP	PDISP		; MP/M DISPATCH
;
; FIXED DATA TABLES FOR TWO-DRIVE STANDARD IBM-COMPATIBLE 8" DISKS
;
	MACLIB DISKDEF	; DISK DEFINITION MACRO LIBRARY

	DISKS  2	; TWO DISK SYSTEM

	DISKDEF 0,1,26,6,1024,243,64,64,OFFSET,(0)
	DISKDEF 1,0
;
BOOT:
WBOOT:
	MVI	C,0
	JMP	XDOS

;
;  ROUTINE TO SELECT GIVEN BY REGISTER C
; 
SELDSK:	MOV	A,C	; GET NEW UNIT #
	LXI	H,0	; RETURN 0000 IN H&L REGS., IF ERROR
	CPI	TDISKS	; BIGGER THAN # OF DISKS AVAILABLE?
	RNC		; OOPS.....		
	STA	UNITNO	; VALID UNIT #, SAVE IT
	MOV	L,C	; L REG =DISK #
	DAD	H	; *2
	DAD	H	; *4
	DAD	H	; *8
	DAD	H	; *16
	LXI	D,DPBASE; D&E REGS =DISK PARAMETER BASE
	DAD	D	; H&L REGS =BIAS OFFSET INTO TABLE
	XRA	A	; SET A = 0 
	RET		; RETURN FROM SELDSK 
; 
;  MOVE DISK TO TRACK ZERO 
; 
HOME:	MVI	A,RTCNT	; GET RETRY COUNT
HRETRY: STA	SERCNT	; STORE IN SEEK ERROR COUNTER
	XRA	A	; SET TRKNO TO ZERO
	STA	TRKNO
	CALL	XMTUS	; XMIT UNIT/SECTOR #
	MVI	A,00DH	; SET SEEK TRACK ZERO COMMAND
	CALL	XMITW	; XMIT AND WAIT
	RZ		; RETURN FROM HOME, IF O.K. 
	CALL	CLRER	; CLEAR DISK ERROR
	PUSH	H	; SAVE CURRENT DMAADR
	LXI	H,SECNT	; GET SEEK ERR COUNT ADDRESS
	INR	M	; ONE MORE ERROR 
	POP	H	; RECOVER CURRENT DMAADR
	LDA	SERCNT	; GET SEEK ERROR COUNT 
	DCR	A	; DECREMENT COUNT 
	JNZ	HRETRY	; TRY TO HOME AGAIN 
	JMP	EREXIT	; OOPS...PERMANENT DISK I/O ERROR
; 
;  SET TRACK NUMBER TO WHATEVER IS IN REGISTER C 
;  ALSO PERFORM MOVE TO THE CORRECT TRACK (SEEK) 
; 
SETTRK:	MOV	A,C	; GET TRACK # INTO A REG 
	CPI	0	; TRACK ZERO REQUESTED?
	JZ	HOME	; DO SEEK TRACK ZERO, IF SO
	STA	TRKNO	; SAVE TRACK #
	MVI	A,RTCNT	; GET RETRY COUNT
SRETRY: STA	SERCNT	; STORE IN SEEK ERROR COUNTER
	CALL	XMTUS	; XMIT UNIT/SECTOR #
	CALL	XMTTK	; XMIT TRACK #
	MVI	A,009H	; SET SEEK TRACK COMMAND
	CALL	XMITW	; XMIT AND WAIT
	RZ		; RETURN FROM SETTRK, IF O.K. 
	CALL	CLRER	; CLEAR DISK ERROR
	PUSH	H	; SAVE CURRENT DMAADR
	LXI	H,SECNT	; GET ADDRESS OF SEEK ERROR COUNTER 
	INR	M	; ONE MORE SEEK ERROR 
	POP	H	; RECOVER CURRENT DMAADR
	LDA	SERCNT	; GET ERROR COUNT 
	DCR	A	; DECREMENT COUNT 
	JNZ	SRETRY	; RETRY SEEK 
	JMP	EREXIT	; ARGH.....

; 
;  TRANSLATE THE SECTOR GIVEN BY BC USING THE TRANSLATE TABLE GIVEN BY DE
; 
SECTRAN:MVI	B,0	; DOUBLE PRECISION SECTOR NUMBER
	XCHG		; TRANSLATE TABLE ADDRESS TO H&L REGS 
	DAD	B	; TRANSLATE SECTOR ADDRESS
	MOV	A,M	; TRANSLATE SECTOR # TO A REG 
	MOV	L,A	; RETURN SECTOR # IN L REG 
	RET		; RETURN FROM SECTRAN
; 
;  SET DISK SECTOR GIVEN BY REGISTER C 
; 
SETSEC: MOV	A,C	; GET SECTOR NUMBER
	STA	SECNO	; PUT AT SECT # ADDRESS
	RET		; RETURN FROM SETSEC
; 
;  SET DISK DMA ADDRESS GIVEN BY REGISTER PAIR B AND C 
; 
SETDMA: MOV	H,B	; MOVE B&C TO H&L
	MOV	L,C
	SHLD	DMAADR	; PUT AT DMA ADR ADDRESS
	RET		; RETURN FROM SETDMA
; 
;  READ THE SECTOR AT SECT, FROM THE PRESENT TRACK 
;  USE STARTING ADDRESS AT DMAADR 
; 
READ:	MVI	A,RTCNT	; GET RETRY COUNT 
RRETRY:	STA	ERCNT	; STORE IN ERROR CTR 
	CALL	XMTUS	; XMIT UNIT/SECTOR #
	MVI	A,003H	; SET READ SECTOR COMMAND
	CALL	XMITW	; XMIT AND WAIT
	JZ	READOK	; IF READ O.K.,GET DATA FROM BUFFER
	CALL	CLRER	; CLEAR DISK ERROR
	PUSH	H	; SAVE CURRENT DMAADR
	LXI	H,RECNT	; GET READ ERROR COUNT ADDRESS 
	INR	M	; ONE MORE ERROR 
	POP	H	; RECOVER CURRENT DMAADR
	LDA	ERCNT	; GET ERROR COUNT 
	DCR	A	; DECREMENT COUNT 
	JNZ	RRETRY	; TRY TO READ AGAIN 
EREXIT:	IN	DATAI	; GET DISK STATUS
	STA	IOERR	; SAVE ERROR STATUS
	MVI	A,1	; INFORM CP/M OF ERROR
	ORA	A	; SET FLAGS 
	RET

READOK:	LHLD	DMAADR	; GET STARTING ADDRESS 
	MVI	D,128	; SET BYTE COUNT
	MVI	A,040H	; SET READ BUFFER COMMAND
	CALL	XMT4X	; XMIT 04XH COMMAND
	INX	H	; BUMP POINTER
	DCR	D	; DE-BUMP BYTE COUNT
READL:	MVI	A,041H	; GET DATA BYTE FROM BUFFER
	CALL	XMT4X	; XMIT 04XH COMMAND
	INX	H	; BUMP POINTER
	DCR	D	; DE-BUMP BYTE COUNT
	JNZ	READL	; LOOP UNTIL ALL BYTES IN
	RET		; RETURN FROM READ
; 
;  WRITE THE SECTOR AT SECT, ON THE PRESENT TRACK 
;  USE STARTING ADDRESS AT DMAADR 
; 
WRITE:	MVI	A,RTCNT	; GET RETRY COUNT 
WRETRY:	STA	ERCNT	; STORE IN ERROR COUNTER 
	LHLD	DMAADR	; GET STARTING ADR 
	MVI	D,128	; SET BYTE COUNT
WRITEL:	MOV	A,M	; GET BYTE FROM DMAADR
	OUT	DATAO	; SEND TO CONTROLLER
	MVI	A,031H	; XMIT SHIFT WRITE BUFFER
	CALL	XMIT
	INX	H	; BUMP POINTER
	DCR	D	; DE-BUMP BYTE COUNT
	JNZ	WRITEL	; LOOP UNTIL ALL BYTES OUT
	CALL	XMTUS	; XMIT UNIT/SECTOR #
	MVI	A,005H	; SET WRITE COMMAND
	CALL	XMITW	; XMIT AND WAIT
	RZ		; RETURN FROM WRITE, IF O.K. 
	CALL	CLRER	; CLEAR DISK ERROR
	PUSH	H	; SAVE CURRENT DMAADR
	LXI	H,WECNT	; GET ADR OF WRITE ERR CTR 
	INR	M	; ONE MORE WRITE ERROR 
	POP	H	; RECOVER CURRENT DMAADR
	LDA	ERCNT	; GET ERROR COUNT 
	DCR	A	; DECREMENT COUNT 
	JNZ	WRETRY	; TRY TO WRITE AGAIN 
	JMP	EREXIT	; ARGH.....
; 
;  TRANSMIT UNIT AND SECTOR NUMBER
; 
XMTUS:	LDA	UNITNO	; GET UNIT NUMBER FOR DISK
	ANI	003H	; PRESERVE UNIT # ONLY
	RRC		; POSITION TO BITS 6&7 FOR 3712 CONTROLLER
	RRC
	MOV	B,A	; SAVE IN B REG 
	LDA	SECNO	; GET SECTOR NUMBER
	ORA	B	; MERGE UNIT NUMBER
	OUT	DATAO	; SEND DATA OUT
	MVI	A,021H	; XMIT UNIT/SECTOR NUMBER
	JMP	XMIT	
; 
;  TRANSMIT TRACK NUMBER
; 
XMTTK:	LDA	TRKNO	; GET TRACK NUMBER
	OUT	DATAO	; SEND DATA OUT
	MVI	A,011H	; XMIT TRACK NUMBER
XMIT:	PUSH	PSW	; SAVE COMMAND
DRCHK:	IN	DATAI	; GET DISK STATUS
	ANI	020H	; MASK FOR DRIVE NOT READY
	JNZ	DRCHK	; LOOP UNTILL DISK READY
	POP	PSW	; RECOVER COMMAND
	OUT	CNTRL	; SEND CONTROL
	XRA	A	; RESET CPU0 BIT
	OUT	CNTRL	; SEND CONTROL
	RET
; 
;  TRANSMIT "BUSY" TYPE COMMAND, AND WAIT FOR "NOT BUSY"
; 
XMITW:	CALL	XMIT	; XMIT COMMAND
BUSY:	IN	DATAI	; GET STATUS
	RAR		; SET BUSY FLAG
	JC	BUSY	; LOOP IF BUSY
	IN	DATAI	; GET DISK STATUS
	ANI	028H	; DISK NOT READY OR CRC ERROR?
	RET		; RETURN FROM XMITW WITH ERROR STATUS
; 
;  TRANSMIT "4X" (READ BUFFER OR SHIFT READ BUFFER) TYPE COMMAND
; 
XMT4X:	OUT	CNTRL	; SEND CONTROL
	IN	DATAI	; GET DATA BYTE
	MOV	M,A	; STUFF DATA BYTE INTO MEMORY
	XRA	A	; RESET CPU0 BIT
	OUT	CNTRL	; SEND CONTROL
	RET		; RETURN FROM XMT4X

CLRER:	MVI	A,00BH	; CLEAR ERROR FLAGS
	CALL	XMIT
	RET

;
; POLL DISK READY STATUS
;
POLDSK:
			; RETURN 0FFH IF READY,
			; 	000H IF NOT
	IN	DATAI	; GET DISK STATUS
	ANI	020H	; MASK FOR DISK NOT READY
	MVI	A,0	; SET A REG. TO ZERO FOR POSSIBLE NOT READY
	RNZ
	MVI	A,0FFH	; DISK IS READY
	RET
;
;  SCRATCH RAM AREA REQUIRED FOR XIOS VARIABLES
; 
;  NOTE:	AS THERE ARE ONLY SEVEN SECTORS
;  AVAILABLE FOR XIOS ON THE SECOND SYSTEM TRACK (1),
;  THE LAST ADDRESS BEFORE THIS POINT SHOULD BE NO
;  GREATER THAN THE XIOS STARTING ADDRESS + 0380 (HEX).
; 
; 
TRKNO:	DS	1	; CURRENT TRACK NUMBER 
SECNO:	DS	1	; CURRENT SECTOR NUMBER 
DMAADR:	DS	2	; DISK TRANSFER ADDRESS.
; 
;  THE NEXT SEVERAL BYTES, BETWEEN STARTZ AND
;  ENDZ, ARE SET TO ZERO AT COLD BOOT TIME.
; 
STARTZ:			; START OF ZEROED AREA.
UNITNO:	DS	1	; DISK NUMBER (TO MP/M) 
; 
;  THESE LOCATIONS KEEP TRACK OF THE NUMBER OF ERRORS THAT OCCUR DURING
;  READ, WRITE, OR SEEK OPERATIONS. THEY ARE INITIALIZED ONLY WHEN A
;  COLD START IS PERFORMED BY THE BOOT STRAP.
; 
IOERR:	DS	1	; DISK I/O ERROR TYPE
RECNT:	DS	1	; READ ERROR COUNTER
WECNT:	DS	1	; WRITE ERROR COUNTER
SECNT:	DS	1	; SEEK ERROR COUNTER
; 
;  SPECIAL FLAGS
; 
CONOTF:	DS	1	; NO PRINT FLAG (WHEN FF HEX)
;
ENDZ:			; END OF ZEROED AREA
;
NODSKS:	DS	1	; NUMBER OF DISKS
ERCNT:	DS	1	; ERROR COUNTER FOR DISK I/O RETRIES
SERCNT:	DS	1	; ERROR COUNTER FOR DISK SEEK RETRIES
TEMP:	DS	1	; TEMPORARY DISK UNIT NUMBER
;
SLICE:	DB	4	; 4 SLICES = 40MS = 1 TICK
CNT25:	DB	25	; 25 TICK CNTR = 1 SEC
INTSTK:	DS	48	; LOCAL INTRPT STK
SVDHL:	DW	0	; SAVED REGS HL DURING INTERRUPT
SVDSP:	DW	0	; SAVED SP DURING INTERRUPT
SVDRET:	DW	0	; SAVED RETURN DURING INTERRUPT
TICKN:	DB	0	; TICKING BOOLEAN,TRUE = DELAYED
PREEMP:	DB	0	; PREEMPTED BOOLEAN
;
	ENDEF
;
	DB	0	; FORCE OUT LAST BYTE IN HEX FIELD FOR RMAC
;
	END

