	TITLE	'MP/M II V2.1 xios 10-19-82 L.R.U. Ver.'
;
;deblocked xios for tarbell cpu board, tarbell double
;density board, and mp/m II ver 2.1 operating system.
;this code is written in z-80 and supports only tarbell
;electronics products. all other hardware situations
;must be added by the user of this xios package.
;
;********************************************************
;code modification notice:				*
;							*
;04-28-81 added queued consoles.			*
;05-03-81 reduced amount of interrupt stack declared	*
;05-03-81 changed labels to stop zasm errors.		*
;05-05-81 added 4th console routine			*
;05-06-81 added 4th drive				*
;05-23-81 changed xios for version 2.0 mp/m.		*
;06-23-81 adjusted for banked xios operation.		*
;06-24-81 added conditional for number of consoles	*
;09-15-81 corrected problem on allocation		*
;09-15-81 moved dsklog pointers to storage at end	*
;09-17-81 put conditionals around trtest routine	*
;09-17-81 moved floppy buff rd/rw above commonbase	*
;09-21-81 block move disk variables (deblock storage)	*
;09-22-81 removed push/pops in rd/wr logical routines	*
;10-06-81 added hardisk routines (33 megabyte drive)	*
;10-08-81 increased dir. entries on h/d to 2048		*
;10-22-81 increased 512 doub sided to 170 dir. entries	*
;10-22-81 increased 512 doub sided to 1208 Kbytes/drv	*
;01-29-82 corrected seek to same trk to unload head on	*
;	  new drive select for floppies			*
;04-27-82 added L.R.U. algorithm			*
;08-31-82 FIXED BUG IN SEL$MEMORY ROUTINE E.E.S.	*
;09-10-82 FIXED BUG IN FLUSH IN IDLE PROCESS E.E.S.	*
;10-01-82 MOVED HARD DISK BUFFER TO FC00H AND SETUP	*
;	  TO USE ENABLE/DISABLE EES			*
;10-01-82 ADDED TWO PRINTER SUPPORT E.E.S.		*
;10-19-82 FIXED MULTI-DEF IN PRINTER ROUTINES E.E.S.	*
;********************************************************
;
TRUE	EQU	-1	;define true
FALSE	EQU	00	;define false
;
	MACLIB	Z80
;
;------------------------------------------------------------
;          this is the area you change for
;		your situation
;*** YOU CANNOT USE LRU AND HARD DISK TOGETHER ***
;------------------------------------------------------------
;
DEBUG	EQU	FALSE
TARBELL	EQU	TRUE	;true if using tarbell cpu board
LRU	EQU	FALSE	;true if using L.R.U. Algorithm
NHITSC	EQU	128	;number of sectors in L.R.U. buffer
FLHDLY	EQU	001	;delay count for "idle l.r.u. flush"
LRUBNK	EQU	2	;EXTENDED MEMORY BANK FOR LRU BUFFERS
HD10	EQU	FALSE	;true if using 10 mbyte hardisk
HD33	EQU	FALSE	;TRUE IF USING 33 MBYTE HARDISK
HDS33	EQU	FALSE	;TRUE IF USING 33 MBYTE AS 1 DISK
HD66	EQU	FALSE	;TRUE IF USING 66 MBYTE HARDISK
HDS66	EQU	FALSE	;TRUE IF USING 66 MBYTE AS 1 DISK
HARDSK	EQU	HD10 OR HD33 OR HD66 OR HDS33 OR HDS66
PS100B	EQU	0FC00H	;hardisk buffer address
ADSPRT	EQU	080H	;HARD DISK BUFFER ENABLE/DISABLE PORT
QUECON	EQU	FALSE	;true if using queued consoles
;
;if you are using 3 consoles, set consol1 and consol2 to true
;etc.....note: console # 0 always active
;
CONSL1	EQU	FALSE	;true if using console #1
CONSL2	EQU	FALSE	;true if using console #2
CONSL3	EQU	FALSE	;true if using console #3
PRNTR1	EQU	FALSE	;TRUE IF USING TWO PRINTERS
VECT	EQU	1	;restart vector number
INTERVL	EQU	33333	;this = 16.6666 ms (60 hz period)
TINTRVL	EQU	060	;this = 1 second
DMACNTL	EQU	TRUE	;true if using dma control
STPRAT	EQU	0	;0=3ms,1=6ms,2=10ms,3=15ms(drv stp rate)
PERSCI	EQU	FALSE	;true if using 270/277 drive
HLAB	EQU	8	;0=no head load at beginning of seek
ERCNT	EQU	10	;error retry count
;
;i/o equates
;
	IF	TARBELL
IOBAS0	EQU	0	;tarbell i/o base (00 or 10 hex)
IOBAS1	EQU	10H	;if using tarbell 4 port board
	ELSE
IOBAS0	EQU	10H	;using vdb-8024 board
IOBAS1	EQU	40H	;i/o base address of tarbell 4 port
	ENDIF		;board.
;
;----------
;console #0
;----------
	IF	TARBELL
CSTAT0	EQU	IOBAS0+1	;i/o base for channel 0 status
CDATA0	EQU	IOBAS0+0	;i/o base for channel 0 data
	ELSE
VSTAT0	EQU	00H		;if using vdb-8024
VDATA0	EQU	01H		;  "
	ENDIF
;
;----------
;console #1
;----------
	IF	TARBELL
CSTAT1	EQU	IOBAS1+1	;channel 1 status port
CDATA1	EQU	IOBAS1+0	;channel 1 data port
	ELSE
CSTAT1	EQU	IOBAS0+1
CDATA1	EQU	IOBAS0+0
	ENDIF
;
;----------
;console #2
;----------
CSTAT2	EQU	IOBAS1+3	;channel 2 status port
CDATA2	EQU	IOBAS1+2	;channel 2 data port
;
;----------
;console #3
;----------
CSTAT3	EQU	IOBAS1+5	;channel 3 status port
CDATA3	EQU	IOBAS1+4	;channel 3 data port
;
;mask values for 8251 usarts
;
;
CIMASK	EQU	00000010B	;input mask value
COMASK	EQU	00000001B	;output mask value
;
VIMASK	EQU	00000010B	;input mask for vdb-8024
VOMASK	EQU	00000100B	;output mask for vdb-8024
;
;------------
;printer port
;------------
;
; NOTE : PRINTER 0 PORT IS ON THE TARBELL CPU CARD
; WHILE PRINTER 1 PORT IS ON THE TARBELL 4S-2P CARD
;
LSTAT0	EQU	IOBAS0+3	;list status port
LDATA0	EQU	IOBAS0+2	;list data port
LMASK	EQU	10000001B	;output mask value
LSTAT1	EQU	IOBAS1+7	;LIST STATUS PORT
LDATA1	EQU	IOBAS1+6	;LIST DATA PORT
;--------------------------------------------------------------
;		end of modification area
;--------------------------------------------------------------
;
	IF	HD10
	MACLIB	MPM10
	ENDIF
	IF	HD33
	MACLIB	MPM33
	ENDIF
	IF	HDS33
	MACLIB	SMPM33
	ENDIF
	IF	HD66
	MACLIB	MPM66
	ENDIF
	IF	HDS66
	MACLIB	SMPM66
	ENDIF
;
MEMMAG	EQU	IOBAS0+20H 	;memory management on cpu
;
	IF	HD10 OR HDS33 OR HDS66
NHARD	EQU	1		;1 HARD DISK
	ENDIF
	IF	HD33
NHARD	EQU	4		;4 HARD ON 33 MBYTE
	ENDIF
	IF	HD66
NHARD	EQU	8		;8 HARD ON 66 MBYTE
	ENDIF
	IF	HARDSK
NDISK	EQU	4+NHARD		;4 FLOPPIES AND N HARDISKS
	ELSE
NDISK	EQU	4		;number of FLOPPIE drives
	ENDIF
;
DMAP	EQU	0E0H		;dma port base address
ADR0	EQU	DMAP+0		;dma address register
WCT0	EQU	DMAP+1		;dma word count register
CMND	EQU	DMAP+8		;dma command register
DADR	EQU	0F8H		;disk address
DCOM	EQU	DADR		;disk command port
DSTAT	EQU	DADR		;disk status port
TRACK	EQU	DADR+1		;disk track register
SECTP	EQU	DADR+2		;disk sector register
DDATA	EQU	DADR+3		;disk data register
WAIT	EQU	DADR+4		;wait for data-interrupt
DMACHK	EQU	DADR+5		;non-wait status port
DMAR	EQU	01000000B	;dma read command
DMAW	EQU	10000000B	;dma write command
FREAD	EQU	10000000B	;floppy read command
FWRIT	EQU	10100000B	;floppy write command
RDID	EQU	11000000B	;read id command
B128	EQU	128		;sgl / dbl den. sect size
B512	EQU	512		;deblock sector size
;
; timer equates
;
TCH0	EQU	IOBAS0+4	;timer chan 0 address
TCH1	EQU	IOBAS0+5	;timer chan 1 address
TCH2	EQU	IOBAS0+6	;timer chan 2 address
TCMND	EQU	IOBAS0+7	;timer command port
IMASK	EQU	IOBAS0+8	;interrupt masking port
CNTR0	EQU	00000000B	;counter 0
CNTR1	EQU	01000000B	;counter 1
CNTR2	EQU	10000000B	;counter 2
RLWORD	EQU	00110000B	;read/load lsb 1st, msb 2nd.
RLHBYTE	EQU	00100000B	;read/load msb only.
RLLBYTE	EQU	00010000B	;read/load lsb only.
CNTRLT	EQU	00000000B	;counter latching operation.
BINARY	EQU	00000000B	;select binary operation.
BCD	EQU	00000001B	;select bcd operation.
MODE0	EQU	00000000B	;interrupt on terminal count.
MODE1	EQU	00000010B	;programmable one-shot.
MODE2	EQU	00000100B	;rate generator.
MODE3	EQU	00000110B	;square wave rate generator.
MODE4	EQU	00001000B	;software triggered strobe.
MODE5	EQU	00001010B	;hardware triggered strobe.
;
;cp/m to host disk constants
;
BLKSIZ	EQU	2048		;cp/m allocation size
HSTSIZ	EQU	512		;host disk sector size
HSTSPT	EQU	16		;host disk sectors/trk
HSTBLK	EQU	HSTSIZ/128	;cp/m sects/host buff
CPMSPT	EQU	HSTBLK * HSTSPT	;cp/m sectors/track
SECMSK	EQU	HSTBLK-1	;sector mask
SECSHF	EQU	2		;log2(hstblk)
;
	IF	HARDSK
WRCMD	EQU	60H		;hardisk write command
RDCMD	EQU	58H		;hardisk read command
	IF	HD10
HRDSPT	EQU	22		;10 MBYTE SECTORS/TRACK
CPMHRD	EQU	352		;LOGICAL 10 MBYTE SECTORS/TRACK
	ELSE
HRDSPT	EQU	36		;physical hardisk sector/track
CPMHRD	EQU	432		;logical cpm sectors/track
	ENDIF
PRAMS	EQU	PS100B+512	;command register
STAT	EQU	PRAMS+8		;status register
HARDBUF	EQU	PS100B		;HARD DISK BUFFER
	ENDIF
;
;bdos constants on entry to write
;
WRDIR	EQU	1		;write to directory
WRUAL	EQU	2		;write to unallocated
;
ABSMREQ	EQU	128		;xdos abs memory request
RELMREQ	EQU	129		;xdos rel memory request
MEMFREE	EQU	130		;xdos memory free function
POLL	EQU	131		;xdos poll function
FLGWAIT	EQU	132		;xdos flagwait function
FLAGSET	EQU	133		;xdos flag set function
MAKEQUE	EQU	134		;xdos make queue function
OPENQUE	EQU	135		;xdos open queue function
DELTQUE	EQU	136		;xdos delete que function
READQUE	EQU	137		;xdos read queue function
CONRQUE	EQU	138		;xdos conditional read queue
WRITQUE	EQU	139		;xdos write queue function
CONWQUE	EQU	140		;xdos conditional write queue
DELAY	EQU	141		;xdos delay for ticks function
DSPTCH	EQU	142		;xdos dispatch function
TERMIN	EQU	143		;xdos terminate process
CREATE	EQU	144		;xdos create process function
SYSDTA	EQU	154		;xdos return system data page
;
PLLPT0	EQU	0		;poll printer 0
	IF	PRNTR1
PLLPT1	EQU	1		;POLL PRINTER 1
	ELSE
PLLPT1	EQU	0
	ENDIF
	IF	HARDSK
HRDPOL	EQU	PLLPT1+1	;poll hardisk device
	ELSE
HRDPOL	EQU	PLLPT1
	ENDIF
DMAPOL	EQU	HRDPOL+1	;poll dma device
PLDSK	EQU	HRDPOL+2	;poll disk
PLCO0	EQU	HRDPOL+3	;poll console # 0 out
PLCO1	EQU	HRDPOL+4	;poll console # 1 out
PLCO2	EQU	HRDPOL+5	;poll console # 2 out
PLCO3	EQU	HRDPOL+6	;poll console # 3 out
PLCI0	EQU	HRDPOL+7	;poll console # 0 input
PLCI1	EQU	HRDPOL+8	;poll console # 1 input
PLCI2	EQU	HRDPOL+9	;poll console # 2 input
PLCI3	EQU	HRDPOL+10	;poll console # 3 input
;
	CSEG
	ORG	0000H		;base address
;
;	jump vector for individual subroutines
;
START:	JMP	COMMONBASE	;cold start
	JMP	WBOOT		;warm start
	JMP	CONST		;console status
	JMP	CONIN		;console character in
	JMP	CONOUT		;console character out
	JMP	LIST		;list character out
	JMP	RTNEMPTY	;punch character out
	JMP	RTNEMPTY	;reader character out
	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	LISTST		;return list status
	JMP	SECTRA		;sector translate
;
;extended i/o system jump vectors
;
	JMP	SEL$MEMORY	;select memory
	JMP	POLL$DEVICE	;poll device
	JMP	START$CLOCK	;start clock
	JMP	STOP$CLOCK	;stop clock
	JMP	EXIT$REGION	;exit region
	JMP	MAX$CONSOLE	;max number of consoles
	JMP	SYSINT		;system initialization
	JMP	IDLE		;idle procedure
;
	IF	LRU
	DW	HITLST		;for l.r.u. display program
	DW	DRVLST
	DW	NHITSC
	ENDIF
;
;6 table entries will allow for 8 user banks
;of 48k + the mp/m system in bank 0.
; *** DON'T MESS WITH BANK 0 ***
;
MEM$BYT$TBL:
;
	DB	00H,01H,02H,03H,04H,05H,06H,07H
	DB	08H,09H,0AH,0BH,0CH,0DH,0EH,0FH	;bank 0
;
	DB	10H,11H,12H,13H,14H,15H,16H,17H
	DB	18H,19H,1AH,1BH,0CH,0DH,0EH,0FH	;bank 1
;
	DB	20H,21H,22H,23H,24H,25H,26H,27H
	DB	28H,29H,2AH,2BH,0CH,0DH,0EH,0FH	;bank 2
;
	DB	30H,31H,32H,33H,34H,35H,36H,37H
	DB	38H,39H,3AH,3BH,0CH,0DH,0EH,0FH	;bank 3
;
	DB	1CH,1DH,1EH,1FH,2CH,2DH,2EH,2FH
	DB	3CH,3DH,3EH,3FH,0CH,0DH,0EH,0FH	;bank 4
;
	DB	50H,51H,52H,53H,54H,55H,56H,57H
	DB	58H,59H,5AH,5BH,0CH,0DH,0EH,0FH	;bank 5
;
	DB	60H,61H,62H,63H,64H,65H,66H,67H
	DB	68H,69H,6AH,6BH,0CH,0DH,0EH,0FH	;bank 6
;
; translate the sector given by bc using the
; translate table given by de
;
SECTRA:	MOV	L,C		;double density part
	MOV	H,B
;
	IF	HARDSK
	LDA	SEKDSK		;check for hardisk
	CPI	4
	RNC			;return if using hardisk
	ENDIF
;
	LDA	DISKHF
	CPI	3		;sector 0-63 for format 3
	RNC
	INR	L		;just increment 0-51 to 1-52
	CPI	2
	RZ
	XCHG			;single density xlat
	DAD	B
	MOV	L,M
	MVI	H,0
	RET
;
;home - restore to track 0 with head loaded
;
HOME:	LDA	HSTWRT		;check for pending write
	ORA	A
	JRNZ	HOME1
	STA	HSTACT		;host inactive
HOME1:	LXI	B,0		;restore
;
;settrk - select track 0 - 76
;
SETTRK:	SBCD	SEKTRK
	RET
;
;seldsk
;always done prior to settrk,setsec
;
SELDSK:	MOV	A,C
	CPI	NDISK		;number of defined drives
	LXI	H,0
	RNC			;return with hl=0 on error
	STA	SEKDSK
	LDA	OLDDSK		;get a copy of last select
	CMP	C		;same drive?
	MVI	A,0		;0=same disk, 1=new disk
	JRZ	SAMDSK		;jump if same
	INR	A		;disk is different
SAMDSK:	STA	CHNGFL		;set the change flag
	MOV	A,C		;else, not the same drive
	STA	OLDDSK		; so update the last used.
;
	IF	HARDSK
	HSEL
	ENDIF
;
	BIT	0,E		;if bit 0 = 0, 1st time select
	JRNZ	NOT1ST		;= 1, drive selected before
;
	IF	LRU
	PUSH	B		;save drive select code
	LXI	H,DRVLST	;point to drive list
	MVI	B,NHITSC	;get the number of sectors in lru
CLRDRV:	MOV	A,M		;get the drive byte
	ANI	00001111B	;mask off write bit
	CMP	C		;is this drive being reset?
	JRNZ	NOTRST		;jump if not
	MVI	M,00001111B	;else, force mismatch on this drv
NOTRST:	INX	H		;bump pointer
	DJNZ	CLRDRV		;loop till all checked/cleared.
	POP	B		;recover drive select code
	ENDIF
;
	MOV	A,C		;get select code
	LXI	H,DSKINX	;point to disk constants
	JMP	TBLJP1		;use common routine
;
DSKINX:	DW	DSK1		;disk 1 routine
	DW	DSK2		;disk 2 routine
	DW	DSK3		;disk 3 routine
	DW	DSK4		;disk 4 routine
;
DSK1:	LXI	H,0000H
	SHLD	DSKLG		;reset dsk 0
	JMPR	CLRDB		;set buffer inactive
;
DSK2:	LXI	H,1000H
	SHLD	DSKLG1		;reset dsk 1
	JMPR	CLRDB
;
DSK3:	LXI	H,2000H
	SHLD	DSKLG2		;reset dsk 2
	JMPR	CLRDB
;
DSK4:	LXI	H,3000H
	SHLD	DSKLG3		;reset dsk 3
CLRDB:	LXI	H,TRKTAB	;point to track table
	MVI	B,0		;b,c = index value
	DAD	B		;point to drive track byte
	MOV	M,B		;zero the byte
	MOV	A,B		;get a zero to reg a
	STA	HSTACT		;clear to inactive
	STA	UNACNT		;clear unalloc count
;
NOT1ST:	MOV	A,C		;recover selected disk value
	ADD	A		;double for indexing
	MOV	C,A		;put into reg c
	MVI	B,0		;clear reg b
	LXI	H,DSKLG		;point to disk log vector
	DAD	B		;get logon location
	MOV	A,M		;get format
;
;store format flag
;
	STA	DISKHF		;save it for system reference
;
; 0 = unlogged
; 1 = single density
; 2 = double density (51 secs - 128 b)
; 3 = double density (16 secs - 512 b)
;
;example:
;for double density 512x16:
;
;	lxi	h,3 * 256 + 8
;
;3 = use deblock part of bios (reg h)
;8 = set bit 3 to a '1' for doub density ( reg l )
;
;for double density 512x16 doub sided:
;
;	lxi	h,3 * 256 + 48h
;
;3 = use deblock part of bios (reg h)
;48h = set bit 3 '1' for doub den
;      set bit 6 '1' for doub sided ( reg l)
;
	INX	H		;get disk pointer address
	ORA	A		;logged on?
	MOV	A,M
	STA	DISKHS		;store selected disk wait port
	JNZ	LOGGED
	PUSH	H
	OUT	WAIT		;at single density
	MVI	A,STPRAT+HLAB	;restore drive
	CALL	EXECC1		;restore to track 0
	MVI	A,1
	OUT	SECTP		;address sector 1
	LXI	H,BUFFER	;trk 0 sect 1 buffer for id.
	CALL	READLS		;read a logical sector
	LDA	BUFFER+7EH	;get density id byte

	CPI	0DEH		;512 x 16 single sided?
	JRZ	DD64

	CPI	0DCH		;512 x 16 doub sided?
	JRZ	DD642

	CPI	0DFH		;128 x 51 doub sided?
	JRZ	DD52

	CPI	0DDH		;128 x 51 single sided?
	JRZ	DD51

	LXI	H,1*256 + 0	;must be single density disk
	LXI	D,DPBLK1	;single density parm block
SD2A:	LXI	B,TRANS		;sector translate table
	JMPR	PUT
;
DD642:	LXI	H,3*256 + 48H
	LXI	D,DPBLK6
	JMPR	PUT1
;
DD52:	LXI	H,2*256 + 48H
	LXI	D,DPBLK5
	JMPR	PUT1
;
DD51:	LXI	H,2*256 + 8	;as above for 51 secs ddens
	LXI	D,DPBLK2
	JMPR	PUT1

DD64:	LXI	H,3*256 + 8	; 64 logical secs (16 by 512)
	LXI	D,DPBLK3
PUT1:	LXI	B,0
PUT:	MOV	A,L		;disk density mask
	XTHL			; pointer to disk hardware
	ORA	M		;add in density mask
	MOV	M,A		;and save
	STA	DISKHS		; (value for selected disk)
	DCX	H		;back up to format address
	XTHL
	MOV	A,H		;format type
	POP	H
	MOV	M,A		;save type (0, 1, 2, 3)
	STA	DISKHF
	PUSH	B
	LDA	SEKDSK		;fix up dpbase tables
	ADD	A
	ADD	A
	ADD	A
	ADD	A	
	MOV	C,A
	MVI	B,0
	LXI	H,DPBASE	; reference table for this disk
	DAD	B
	POP	B
	MOV	M,C		;copy translate table address
	INX	H
	MOV	M,B
	LXI	B,9
	DAD	B
	MOV	M,E		;copy parameter block address
	INX	H
	MOV	M,D

LOGGED:	LDA	DISKHS
	ANI	0B0H		;eliminate density from address
	MOV	E,A
	MVI	D,0
	LXI	H,DPBASE
	DAD	D
	RET
;
;read - read a sector
;
READ:
	IF	HARDSK
	HCOND	SEKDSK,READB
	ENDIF
;
	LDA	SEKTRK		;bypass format 3 if track 0
	ORA	A
	JRZ	READ1
	LDA	DISKHF		;if format 3 then deblock
	CPI	3
	JZ	READB
READ1:	LDA	SEKSEC
	MOV	D,A
	LDA	DISKHS
	MOV	B,A
	LDA	SEKTRK
	CALL	SEEKLS
	JMP	READ3
;
;write - write a sector from dmaadr
;
WRITE:
	IF	HARDSK
	HCOND	SEKDSK,WRITEB
	ENDIF
;
	LDA	SEKTRK		;bypass format 3 if track 0
	ORA	A		;track = 0?
	JRZ	WRIT1		;if = must be track 0
	LDA	DISKHF		;if format 3 then deblock
	CPI	3
	JZ	WRITEB
;
;use a common buffer for single density
;
WRIT1:	CALL	WRIT2		;use commonbase routine
	LDA	SEKSEC
	MOV	D,A
	LDA	DISKHS
	MOV	B,A
	LDA	SEKTRK
	CALL	SEEKLS
	LXI	H,BUFFER
;
	IF	NOT DMACNTL
	CALL	WRTEST
	ENDIF
;
	JMP	WRITEL		;write logical sector
;
;setsec - set sector from reg c
;
SETSEC:	SBCD	SEKSEC
	RET
;
;setdma - set dma address from bc
;check for need to flush buffer.
;
SETDMA:	SBCD	DMAADR		;bc to dmaadr
	INX	B		;check for flush buffer
	MOV	A,B		;check for b,c = 0
	ORA	C
	RNZ			;return if flush no needed
	LXI	H,HSTWRT	;point to host write flag
	MOV	A,M		;check for pending write
	MVI	M,0		;reset, we are writing it out
	ORA	A		;is it pending write?
	RZ			;return if not
	CALL	WRITEHST	;else,..flush to disk
	ORA	A		;any errors?
	RZ			;return if not
	POP	H		;error found
	RET
;
	IF	NOT DMACNTL
RDTEST:	CALL	TRTEST		;see if phantom track
	RNC
	LXI	B,127
	MOV	D,H
	MOV	E,L
	INX	D
	MVI	M,0
	LDIR
	JMP	TESTDN
;
WRTEST:	CALL	TRTEST		;see if phantom track
	RNC
TESTDN:	POP	B		;scrap 1 subroutine
	XRA	A
	RET
;
TRTEST:	IN	TRACK		;test track
	CPI	1
	RNC
	IN	SECTP
	ORA	A
	JRZ	TSTC
	IN	TRACK
	DCR	A
	JRZ	TRK1
	IN	SECTP
	CPI	27
	CMC
	RET
TRK1:	IN	SECTP
	CPI	52
TSTC:	CMA
	RET
	ENDIF
;
; -read logical sector-
;hl is dma address
;
	IF	DMACNTL		;if using dma
READLS:	MVI	A,ERCNT		;retry count
RRTRY:	STA	RTCNT		;save it
	LXI	B,FREAD SHL 8 OR WCT0
	LDA	DISKHF		;check if deblocking
	CPI	3		;if = 3, deblocking
	LXI	D,DMAR SHL 8 OR (B512-1)
	JRNC	RSET		;we are deblocking
	LXI	D,DMAR SHL 8 OR (B128-1)
RSET:	PUSH	H		;save dma address
	CALL	DMARW		;use common read/write
	CALL	DMA$XFER$POL
	POP	H		;recover dma address
	ANI	9DH		;check for errors during read
	RZ			;return if no errors
	LDA	RTCNT		;get retry count
	DCR	A		;decrement it
	JRNZ	RRTRY		;retry again
COMEXT:	MVI	A,1		;error retry exausted
	ORA	A		;set flags
	RET			;return error code

	ELSE

READLS:	DI			;disable interrupts
	PUSH	B		;save	bc, de
	PUSH	D
	LXI	B,ERCNT*256 + WAIT
RRTRY:	MVI	A,80H
	OUT	DCOM		;read a block
	PUSH	H
	XCHG
	LXI	H,RLOOP		;set up for fast transfer
RLOOP:	INP	A		;read port c and set status
	JP	RDONE
	IN	DDATA		;read byte
	STAX	D
	INX	D
	PCHL
;
RDONE:	IN	DSTAT
	ANI	9DH
	JRZ	REXIT		;return on good read
	POP	H
	DJNZ	RRTRY
	MVI	A,1
	ORA	A		;set status
	JMP	REXIT1
;
REXIT:	XCHG			;put next address in hl
REXIT2:	POP	D		;throw away orig. dma
REXIT1:	POP	D		;restore de
	POP	B		;restore bc
	EI
	RET
	ENDIF
;
;-write logical sector-
;hl is dma address
;
	IF	DMACNTL		;if using dma
WRITEL:	MVI	A,ERCNT		;retry count
WRTRY:	STA	RTCNT		;save retry count
	LXI	B,FWRIT SHL 8 OR WCT0
	LDA	DISKHF		;check if deblocking
	CPI	3		;if = 3, deblocking
	LXI	D,DMAW SHL 8 OR (B512-1)
	JRNC	WSET		;we are deblocking
	LXI	D,DMAW SHL 8 OR (B128-1)
WSET:	PUSH	H		;save dma address
	CALL	DMARW		;use common read/write
	CALL	DMA$XFER$POL
	POP	H		;recover dma address
	ANI	0FDH		;check for errors during read
	RZ			;return if no errors
	LDA	RTCNT		;get retry count
	DCR	A		;decrement it
	JRNZ	WRTRY		;retry again
	JMPR	COMEXT		;error detected, send error code

	ELSE

WRITEL:	DI			;disable interrupts
	PUSH	B		;save	bc, de
	PUSH	D
	LXI	B,ERCNT*256 + WAIT
WRTRY:	MVI	A,0A0H
	OUT	DCOM		;write a block
	PUSH	H
	XCHG
	LXI	H,WLOOP		;set up for fast transfer
WLOOP:	INP	A		;read port c and set status
	JP	WDONE
	LDAX	D
	OUT	DDATA		;write a byte
	INX	D
	PCHL

WDONE:	IN	DSTAT
	ANI	0FDH
	JRZ	REXIT		;return on good write
	POP	H
	DJNZ	WRTRY
	MVI	A,1
	ORA	A		;set status
	JMP	REXIT1		;clean up routine
	ENDIF
;
;logical sector seek
;
;a=track, b=hardware and density for fdc
;d=sector (for future read)
;
SEEKLS:	PUSH	PSW
	MVI	A,10		;retrys
	STA	SEEKRTY		;save it
	PUSH	B
	CALL	TRKINDX		;compute table index.
;
	IF	PERSCI
	ANI	0EH		;strip bit 0
	ENDIF
;
;compute index into track table
;
	MOV	C,A		;put disk number into reg e.
	MVI	B,0
	LXI	H,TRKTAB	;point to start of trk table
	DAD	B		;get correct drive byte
	POP	B
	MOV	A,M		;get track value
	OUT	TRACK		;force into 1793 track reg.
	POP	PSW		;restore track value
LSSEEK:	CPI	1
	MOV	C,A		;save track in reg c
	MOV	A,B		;get copy of drive and density
	JRNC	SEEKOK		;we are > than track 1?
	ANI	30H		;clear density & side bit
	JMP	SEEK2		;going to trk < 1
;
SEEKOK:	BIT	6,B		;doing doub sided?
	JRZ	SEEK1		;< > 1, doing single sided
	RRCR	C		;divide track by 2
	JRC	SEEKK1		;side bit set,doing odd trk
	RES	6,B		;reset side bit, doing even trk
SEEKK1:	RES	7,C		;clear msb of track value
SEEK1:	MOV	A,B		;get drive select code
SEEK2:	OUT	WAIT		;select disk and density
	PUSH	B
	PUSH	D
	CALL	DLYSEL		;check for new drive change
	POP	D
	POP	B
	MOV	A,D		;get sector number
	OUT	SECTP		;tell the controoller chip
	IN	TRACK		;read 1793 track register
	CMP	C		;is track the same?
	JRZ	SAVTRK		;save track value for next time.
	MOV	A,C		;not same, get new track number
	OUT	DDATA		;seek to track with head load
;
;execute seek command
;
EXECC:	MVI	A,14H+STPRAT+HLAB	;seek command
EXECC1:
	IF	NOT DMACNTL
	DI
	ENDIF
;
	OUT	DCOM		;output disk command
;
	IF	LRU
	LDA	LRUSEK		;get seek flag
	ORA	A		;0=use polled seek
	JRZ	POLSEK		;1=use no polling through xdos
LRULOP:	IN	DMACHK		;check for seek done
	RLC
	JRC	LRULOP
	JMPR	LRUSTS
POLSEK:
	ENDIF

	IF	DMACNTL
	CALL	SLOOP		;use common polling
	ELSE
	IN	WAIT		;use wait port
	ENDIF
;
LRUSTS:	IN	DSTAT		;check disk status
	ANI	10010000B	;mask out junk bits
	JRZ	SAVTRK		;save track for next time
;
;we have an seek error,
;save primary registers
;and execute a read id.
;
RIDCOM:	EXX			;save regs

	IF	DMACNTL
	LXI	H,BUFF1		;buffer area for read id
	LXI	B,RDID SHL 8 OR WCT0
	LXI	D,04005H	;dma read, length - 1
	CALL	DMARW		;read the id marks
	CALL	DMA$XFER$POL

	ELSE

	MVI	A,RDID		;read id command
	OUT	DCOM		;send it
RIDLOP:	IN	WAIT		;stall cpu
	ORA	A		;set flags
	JP	RIDDON		;read status if done
	IN	DDATA		;get a byte from floppy
	JMP	RIDLOP		;loop till done
RIDDON:	IN	DSTAT		;read floppy status
	ENDIF

	ANI	9DH		;any errors in reading?
	JRZ	DENOK		;no, density is correct.
	EXX			;yes, incorrect density
	MOV	A,B		;get density and drive byte
	RES	3,A		;set single density for retry
	OUT	WAIT		;on read id.
	JMP	RIDCOM		;switch registers and retry.
;
DENOK:	IN	SECTP		;get track byte
	OUT	TRACK		;place value into trk reg.
	LDA	SEEKRTY		;get retry count
	DCR	A
	STA	SEEKRTY
	EXX			;restore registers
	JRNZ	SEEK1		;reseek to track
	MVI	A,1		;error code
	RET
;
;check for new drive select
;
DLYSEL:	LDA	CHNGFL		;get drv change flag
	ORA	A		;change to new drive?
	RZ			;return if no
	XRA	A		;get a zero
	STA	CHNGFL		;clear 1st time flag
;
;drives are different, so get the
;present track number and seek to
;it to unload the head.
;
	IN	TRACK		;get the present track number
	OUT	DDATA		;place it in data register
	MVI	A,10H + STPRAT	;get seek command
	JMP	SLOOP		;do the seek and return
;
SAVTRK:	CALL	TRKINDX		;get correct index value
;
	IF	PERSCI
	ANI	0EH		;strip bit 0
	ENDIF
;
	MOV	C,A
	MVI	B,0
	LXI	H,TRKTAB	;point to track table
	DAD	B		;add offset
	IN	TRACK		;get 1793 track
	MOV	M,A		;save in table
;
	IF	NOT DMACNTL
	EI
	ENDIF
;
	RET
;
;get drive select code from reg b
;and shift it right 4 places for
;use as an index into track table
;
TRKINDX:MOV	A,B
	ANI	30H		;strip side and density
	JMP	SHIFTR		;use common routine
;
;dma read / write routine
;
	IF	DMACNTL
DMARW:	XRA	A		;clear accum
	OUT	CMND		;clear dma chip
	MVI	A,0D0H		;force intrp cmnd (1793)
	OUT	DCOM
	OUTP	E
	OUTP	D		;read/write with length
	DCR	C		;reg -> adr0 port now
	OUTP	L
	OUTP	H		;address for dma set up
	MVI	A,41H		;request chan 0 operation
	OUT	CMND		;tell dma chip
	CALL	HDLD		;check head load bit
	ORA	B		;add in command for floppy
	OUT	DCOM		;send it to floppy
	RET
;
DMA$XFER$POL:
	MVI	C,POLL		;place on poll list
	MVI	E,DMAPOL
	CALL	XDOS
	IN	DSTAT		;get disk status
	RET
;
SLOOP:	EXAF			;save accum and psw
	EXX			;save primary regs
	MVI	C,POLL		;place on poll list
	MVI	E,PLDSK		;use poll disk routine
	CALL	XDOS
	EXX			;restore primary registers
	EXAF			;restore accum and psw
	RET
;
;check for head load bit on in 1793
;
HDLD:	IN	DSTAT		;get status from 1793
	BIT	5,A		;check head load bit
	MVI	A,4		;get head load set bit
	RZ			;return if not loaded
	XRA	A		;get a zero
	RET			;head is load already
	ENDIF
;
;start of deblock routines
;
;================================
;deblock read routine
;read the selected cp/m sector
;
READB:	MVI	A,1
	STA	READOP		;read operation
	MVI	A,WRUAL
	STA	WRTYPE		;treat as unalloc
	JMP	ALLOC		;to perform the read
;
;deblock write routine
;write the selected cp/m sector
;
WRITEB:	XRA	A		;0 to accumulator
	STA	READOP		;not a read operation
	MOV	A,C		;write type in c
	STA	WRTYPE
	ANI	WRUAL		;write unallocated?
	JRZ	CHKUNA		;check for unalloc
;
;write to unallocated, set parameters
;
	IF	HARDSK
	ALLCHK1	BLKSET
	ENDIF
;
	LDA	DISKHS		;check for double sided
	BIT	6,A		;check for 2048 alloc size
	MVI	A,BLKSIZ/128	;next unalloc recs
	JRZ	BLKSET		;doing single sided
	ADD	A		;*2 = 4096 alloc size
BLKSET:	STA	UNACNT		;save the alloc size
	LXI	H,SEKSEC
	LXI	D,UNASEC
	LXI	B,5		;block move count
	LDIR
;
;check for write to unallocated sector
;
CHKUNA:	LDA	UNACNT		;any unalloc remain?
	ORA	A
	JRZ	ALLOC		;skip if not
;
;more unallocated records remain
;
	DCR	A		;unacnt = unacnt-1
	STA	UNACNT
	LDA	SEKDSK		;same disk?
	LXI	H,UNADSK
	CMP	M		;sekdsk = unadsk?
	JRNZ	ALLOC		;skip if not
;
;disks are the same
;
	ORA	A		;clear cy flag
	LDED	UNATRK
	LHLD	SEKTRK		;sektrk = unatrk?
	DSBB	D
	JRNZ	ALLOC		;skip if not
;
;tracks are the same
;
	ORA	A		;clear cy flag
	LDED	SEKSEC		;same sector?
	LHLD	UNASEC
	DSBB	D		;seksec = unasec?
	JRNZ	ALLOC		;skip if not
;
;match, move to next sector for future ref
;
	IF	HARDSK
	HALLOC	SEKDSK,NOHRD
	ENDIF
;
	LXI	B,CPMSPT	;get the # of floppy sectors
NOHRD:	LHLD	UNASEC
	INX	H
	SHLD	UNASEC
	ORA	A
	DSBB	B
	JRNZ	NOOVF
	LXI	H,0
	SHLD	UNASEC
;
;overflow to next track
;
	LHLD	UNATRK
	INX	H
	SHLD	UNATRK		;unatrk = unatrk+1
;
;match found, mark as unnecessary read
;
NOOVF:	XRA	A		;0 to accumulator
	STA	RSFLAG		;rsflag = 0
	JMPR	RWOPER		;to perform the write
;
;not an unallocated record, requires pre-read
;
ALLOC:	XRA	A		;0 to accum
	STA	UNACNT		;unacnt = 0
	INR	A		;1 to accum
	STA	RSFLAG		;rsflag = 1
;
;common code for read and write follows
;enter here to perform the read/write
;
RWOPER:	XRA	A		;zero to accum
	STA	ERFLAG		;no errors (yet)
	LHLD	SEKSEC		;compute host sector
	MOV	A,H
	RRC			;shift right
	MOV	A,L
	RAR
	STC
	CMC
	RAR			;shift right
	STA	SEKHST		;host sector to seek
;
;active host sector?
;
	LXI	H,HSTACT	;host active flag
	MOV	A,M
	MVI	M,1		;always becomes 1
	ORA	A		;was it already?
	JRZ	FILHST		;fill host if not
;
;host buffer active, same as seek buffer?
;
	LDA	SEKDSK
	LXI	H,HSTDSK	;same disk?
	CMP	M		;sekdsk = hstdsk?
	JRNZ	NOMATCH
;
;same disk, same track?
;
	ORA	A		;clear cy flag
	LDED	HSTTRK
	LHLD	SEKTRK		;sektrk = hsttrk?
	DSBB	D
	JRNZ	NOMATCH
;
;same disk, same track, same buffer?
;
	LDA	SEKHST
	LXI	H,HSTSEC	;sekhst = hstsec?
	CMP	M
	JRZ	MATCH		;skip if match
;
;proper disk, but not correct sector
;
NOMATCH:LDA	HSTWRT		;host written?
	ORA	A
	CNZ	WRITEHST	;clear host buff
;
;may have to fill the host buffer
;
FILHST:	LXI	H,SEKDSK	;point to sekdsk storage
	LXI	D,HSTDSK	;point to hstdsk storage
	LXI	B,4		;block move count
	LDIR			;move the storage values
	LDA	RSFLAG		;need to read?
	ORA	A
	CNZ	READHST		;yes, if 1
	XRA	A		;0 to accum
	STA	HSTWRT		;no pending write
;
;copy data to or from buffer
;
MATCH:	LDA	SEKSEC		;mask buffer number
	ANI	SECMSK		;least signif bits
	MOV	L,A		;ready to shift
	MVI	H,0		;double count
	MVI	B,7		;count = 7
MTCH1:	DAD	H
	DJNZ	MTCH1
;
;hl has relative host buffer address
;
	IF	LRU
;
	SHLD	RELHST		;save relative host buffer index
	LDA	READOP		;are we doing a write operation
	ORA	A		;if yes, read in proper sector 1st
	CZ	READHST		; so we can save data in correct sect.
;
	ELSE
	IF	HARDSK
	LDA	SEKDSK
	CPI	4		;CHECK IF HARD DISK SELECTED
	LXI	D,HARDBUF	;HARD DISK BUFFER ADDRESS
	JRNC	MTCH2		;JUMP IF HARD DISK
	ENDIF
	LXI	D,HSTBUF	;FLOPPY DEBLOCK BUFFER
MTCH2:	DAD	D		;hl = host address
	LDED	DMAADR		;get/put cp/m data
	LDA	READOP		;which way?
	ORA	A
	JNZ	RWMOVE		;skip if read
;
;write operation, mark and switch direction
;
	MVI	A,1
	STA	HSTWRT		;hstwrt = 1
	XCHG			;source/dest swap
	ENDIF
;
	JMP	RWMOVE
;
;writehst performs the physical
;write to the host disk.
;hstdsk = host disk #, hsttrk = host track #,
;hstsec = host sect #. write "hstsiz" bytes
;from hstbuf and return error flag in erflag.
;return erflag non-zero if error
;
	IF	NOT LRU
WRITEHST:
	CALL	SETIO		;set up to do write block
;
	IF	HARDSK
	JNC	WRTHST
	ENDIF
;
	CALL	WRITEL		;do it
	JMPR	XITIO
;
;readhst reads the physical disk.
;hstdsk = host disk #, hsttrk = host track #,
;hstsec = host sect #. read "hstsiz" bytes
;into hstbuf and return error flag in erflag.
;
READHST:CALL	SETIO
;
	IF	HARDSK
	JNC	RDHST
	ENDIF
;
	CALL	READLS
XITIO:	MVI	A,0
	STA	ERFLAG
	RZ
	CMA
	STA	ERFLAG
	RET
;
SETIO:	LXI	H,DSKLG			;get hardware port
	LDA	HSTDSK
;
	IF	HARDSK
	RWCON
	ENDIF
;
	ADD	A
	MOV	E,A
	MVI	D,0
	DAD	D
	INX	H
	MOV	B,M			;disk sel stuff in b
	LDA	HSTSEC
	INR	A			;sector on disk is 1-16
	MOV	D,A
	LDA	HSTTRK
	CALL	SEEKLS
	LXI	H,HSTBUF
;
	IF	HARDSK
	XRA	A
	CMC
	ENDIF
;
	RET
	ENDIF			;end of IF NOT LRU
;
;entry:	none (hsttrk,hstsec,hstdsk are setup already)
;exit:	sector data returned to cp/m
;
	IF	LRU
WRITEHST:
READHST:
	CALL	HITTRK		;check for this trk in buffer
	JNZ	GETLRU		;get l.r.u. if trk not in buffer
	MOV	A,C		;get relative buffer position
	STA	NXTLRU		;save it for rohl routine
	JMP	ROHL		;reorder hit list and ret
;
;subroutine to check for track in trklst area
;
;entry:	none
;reg usage:	reg  b = number of sectors buffered
;		reg  c = counter for index into seclst and drvlst
;		reg de = track to search for (hsttrk value)
;		reg hl = trklst table pointer
;exit:	z flag set = track found
;	z flag reset = track not found (find l.r.u. for substitution)
;
HITTRK:	LXI	B,NHITSC SHL 8 OR 0	;get the number sectors buffered
	LDED	HSTTRK			;get track to search for
	LXI	H,TRKLST		;point to track storage table
TRKLOP:	MOV	A,M			;get track table value
	INX	H			;bump to next
	CMP	E			;match?
	JRNZ	DONXTT			;do next byte if not
	MOV	A,M			;match found, check next byte
	CMP	D			;match?
DONXTT:	INX	H			;bump in case no match found
	PUSH	H			;save track list pointer
	PUSH	B			;save index value
	CZ	HITSEC			;found trk, check for sector
	POP	B			;recover index value
	POP	H			;recover track list pointer
	JRZ	FNDTRK			;return if match is found
	INR	C			;else, no match,, bump counter
	DJNZ	TRKLOP			;and try for next match if not done
	MVI	B,0			;clear reg b
	MVI	A,1			;else, this track not in table
	DCR	C			;adjust counter = actual value
	ORA	A			;set flags
	RET				;return to caller
;
FNDTRK:	MVI	B,0			;clear reg b
	RET
;
;subroutine to check for sector in buffer
;
;entry:	reg  c = relative index to sector position
;exit:	z flag set if correct sector this track
;	else, z flag reset if not correct sector
;
HITSEC:	LDA	HSTSEC		;get host sector needed
	LXI	H,SECLST	;point to start of sector buffer
	MVI	B,0		;clear reg b
	DAD	B		;index to correct sector
	CMP	M		;do they match
	RNZ			;return if no match
;
;subroutine to check if this drive is correct unit
;
;entry:	reg bc = relative index to drive byte
;exit:	z flag set if correct drive
;	else, z flag reset if not correct drive
;
HITDRV:	LXI	H,DRVLST	;point to drive buffer start
	DAD	B		;index into drive position in buffer
	MOV	A,M		;get the drive select code
	ANI	00001111B	;strip down to actual drv #
	LXI	H,HSTDSK	;point to requested drive number
	CMP	M		;is this the right drive?
	RET			;return flag back to caller
;
;get l.r.u. position (last in table)
;use as an index into trk,sec,drv buffer
;check for pending write of this buffer 1st.
;
;entry:	reg bc = bottom of l.r.u. list
;exit:	none
;
GETLRU:	LXI	H,HITLST	;point to l.r.u. table
	PUSH	B		;save index on stack
	LXI	B,NHITSC-1	;index value ot bottom of l.r.u. list
	DAD	B		;point to end of table (l.r.u.)
	MOV	A,M		;get l.r.u. number
	STA	NXTLRU		;save for rohl routine
	MOV	C,M		;get the l.r.u. buffer position
	LXI	H,DRVLST	;point to drive buffer list
	DAD	B		;point to l.r.u. drive byte
	BIT	7,M		;check for pending write
	CNZ	NDFLSH		;flush first if needed
;
;else, save new trk, sector, drive info in l.r.u. buffers
;
	LXI	H,TRKLST	;point to track buffer
	DAD	B		;get index into proper
	DAD	B		; track position in buffer
	LDED	HSTTRK		;get hsttrk value
	MOV	M,E		;save in track buffer
	INX	H
	MOV	M,D		;save in track buffer
;
;save new sector value in l.r.u. buffers
;
	LXI	H,SECLST	;point to start of sector buffer
	DAD	B		;point to new entry location
	LDA	HSTSEC		;get host sector value
	MOV	M,A		;save it in sector buffer
;
;save drive in drv buffer
;
	LXI	H,DRVLST	;point to drive buffer
	DAD	B		;point to new entry location
	LDA	HSTDSK		;get hstdsk value
	ANI	00001111B	;strip to binary drive value
	MOV	M,A		;save in table (read operation only)
	CALL	BNKRED		;read the new sector into memory
	POP	B		;recover index from stack
;
;reorder hit list - subroutine (rohl) 4-13-82
;
;entry:	none
;	 a = next l.r.u. number to search for
;exit:	hit list reordered for l.r.u. sector
;	hl = top of list
;
ROHL:	LXI	H,HITLST	;point to hit list start
;
;search hit list for m.r.u.
;
	LDA	NXTLRU		;get relative index value
	LXI	B,0		;clear counter
SRCHL:	CMP	M		;is this it?
	JRZ	MRUFD		;m.r.u. found
	INX	B		;bump count
	INX	H
	JMPR	SRCHL		;keep looking
;		
;now re-order the list
;
MRUFD:	EXAF			;save in alternate accum
	MOV	A,B		;check for list top
	ORA	C		;bc= 0 if top of list
	JRZ	ROHLEX		;exit if top of list
	MOV	E,L
	MOV	D,H		;d,e --> start position
	DCX	D		;d,e --> start - 1
	XCHG			;flip source/destination
	LDDR			;block move in reverse order
	EXAF			;recover m.r.u. byte
	INX	H		;point to top of list
	MOV	M,A		;save m.r.u. sector in table
	RET			;return top of list addr in h,l
				;and sector position in reg b
ROHLEX:	EXAF			;restore alt accum and flags
	RET			;ret to caller
;
NDFLSH:	PUSH	B		;save index value
	CALL	SPLIO		;use special i/o for l.r.u.
	CALL	WRTEXT		;common read/write extension
	MVI	A,LRUBNK	;set extended dma latch
	OUT	DMACHK
	LXI	B,FWRIT SHL 8 OR WCT0
	LXI	D,DMAW SHL 8 OR (B512-1)
	CALL	DMARW		;use dma routine
	CALL	DMADON		;check for dma xfer completed
	POP	B		;recover index value
	RET
;
GETBNK:	MVI	C,MEMMAG+1	;use page 1
	MOV	A,H		;get buffer page address
	ANI	0F0H		;strip to ext page number
	RRC			;shift
	RRC			;right
	RRC			;4
	RRC			;places
	MOV	B,A		;save a copy
	LDA	BNKNUM		;get extended bank address
	ADD	B		;add it in
	CMA			;flip for m/m chips
	OUTP	A		;swap out main page with sector page
	RET
;
RSTBNK:	MVI	C,MEMMAG+1	;reset page 1
	MVI	A,0FEH		;page to restore (inverted for m/m chip)
	OUTP	A
	RET
;
SPLIO:	LXI	H,DRVLST	;point to drive list
	DAD	B		;point to requested drive
	MOV	A,M		;get it
	ANI	0FH		;strip to just drive number
	ADD	A		;double it
	LXI	H,DSKLG		;point to physical drive log bytes
	MOV	E,A
	MVI	D,0		;reg de = index
	DAD	D
	INX	H		;point to drive select & density code
	MOV	E,M		;get it
	LXI	H,SECLST	;point to sector list
	DAD	B		;point to requested sector
	MOV	D,M		;save in reg d for seekls routine
	INR	D		;make physical sector number
	LXI	H,TRKLST	;point to track list
	DAD	B		;point to requested track number
	DAD	B
	MOV	A,M		;get it
	MOV	B,E		;get disk select and density code
	JMP	SEEKLS		;do seek and return to caller
;
;this subroutine computes the sector in sector buffer
;
;entry:	hl = base address of page start
;
WRTEXT:	LXI	H,0		;clear hl
	LDA	NXTLRU		;get index value
	MOV	B,A		;place in reg b as counter value
	LXI	D,512		;length of each sector
	INR	B		;check for 0 count
NXTSC:	DCR	B		;if = 0 , will just return
	RZ
	DAD	D		;else, index to next sector location
	JMPR	NXTSC		;any more counts left?
;
;this subroutine is used to read a sector of data
;into an extended bank of memory.
;
BNKRED:	CALL	SPLIO		;seek to correct track sector
	CALL	WRTEXT		;compute index into read sector loc.
	MVI	A,LRUBNK	;write using extended dma latch
	OUT	DMACHK
	LXI	D,DMAR SHL 8 OR (B512-1)
	LXI	B,FREAD SHL 8 OR WCT0
	CALL	DMARW		;use dma routine
DMADON:	IN	DMACHK		;get dma status
	RLC			;still busy
	JRC	DMADON		;loop if still busy
	XRA	A		;restore bank 0 
	OUT	DMACHK
	OUT	CMND		;clear dma chip
	IN	DSTAT		;clear floppy chip
	RET
;
GETSEC:	CALL	WRTEXT		;compute sector position
	CALL	GETBNK		;swap code with sector buffer
	MOV	A,H		;convert to relative buffer number
	ANI	0FH		; by stripping page nibble off
	MOV	H,A		;restore to h,l again
	LXI	D,1000H		;get absolute buffer start address
	LBCD	RELHST		;get relative record number
	DAD	D		;compute sector start in the buffer
	DAD	B		;hl --> actual 128 byte record to move
	RET
	ENDIF
;
	IF	HARDSK
	HARDISK
	ENDIF
;
;l.r.u. tables
;
	IF	LRU
TRKLST:	DS	NHITSC * 2	;track table for l.r.u.
SECLST:	DS	NHITSC		;sector table for l.r.u.
DRVLST:	DS	NHITSC		;drive table for l.r.u.
HITLST:	DS	NHITSC		;hit list table for l.r.u.
	ENDIF
;
BEGDAT	EQU	$
;
;ram storage area
;
;disk log tables
;
DSKLG:	DS	2		;disk 0 log flag/den
DSKLG1:	DS	2		;disk 1 "
DSKLG2:	DS	2		;disk 2 "
DSKLG3:	DS	2		;disk 3 "
;
DISKHF:	DS	1		;disk hardware format (1, 2, 3)
DISKHS:	DS	1		;disk/density setting = hardware
TRKTAB:	DS	4		;track table for 4 drives
ALL00:	DS	38		;allocation vector 0
ALL01:	DS	38		;allocation vector 1
ALL02:	DS	38		;allocation vector 2
ALL03:	DS	38		;allocation vector 3
CHK00:	DS	42		;check vector 0
CHK01:	DS	42		;check vector 1
CHK02:	DS	42		;check vector 2
CHK03:	DS	42		;check vector 3
;
	IF	HARDSK
	ALLCHK
	ENDIF
;
OLDDSK:	DS	1		;last drive select save
SEKSEC:	DS	2		;seek sector number
SEKDSK:	DS	1		;seek disk number
SEKTRK:	DS	2		;seek track number
SEKHST:	DS	1		;seek shr secshf
HSTDSK:	DS	1		;host disk number
HSTTRK:	DS	2		;host track number
HSTSEC:	DS	1		;host sector number
HSTACT:	DS	1		;host active flag
HSTWRT:	DS	1		;host written flag
UNACNT:	DS	1		;unalloc rec cnt
UNASEC:	DS	2		;last unalloc sector
UNADSK:	DS	1		;last unalloc disk
UNATRK:	DS	2		;last unalloc track
RTCNT:	DS	1		;disk retry counter
SEEKRTY:DS	1		;seek retry counter
ERFLAG:	DS	1		;error reporting
RSFLAG:	DS	1		;read sector flag
READOP:	DS	1		;1 if read operation
WRTYPE:	DS	1		;write operation type
CHNGFL:	DS	1		;1st time flag
BUFF1:	DS	6		;read id buffer
;
;
;warm boot - not used in mp/m
;
COMMONBASE:
	JMP	BOOT		;not used
;
;the following routines are filled in by gensys
;
SWTUSER:JMP	$-$		;switch common memory routine
SWTSYS:	JMP	$-$		;switch system routine
PDISP:	JMP	$-$		;dispatcher entry point
XDOS:	JMP	$-$		;xdos entry point
SYSDAT:	DW	$-$		;pointer to system data page
;
;this dw added for computation of xios jump table length.
;this way, digital research can add all the jumps they
;want, and the selmemory routine will always know where
;the mem$byt$tbl starts in the xiosjmp.tbl area.
;
MEM$TBL$PNTR:
	DW	MEM$BYT$TBL-START	;length of jump tbl
;
;idle procedure
;
IDLE:	CALL	TIMINT		;set up timer operation
;
	IF	LRU
	LDA	LRUWRT		;did we write any sectors?
	ORA	A
	JRZ	NOLRUWT		;skip and do dispatch
	LXI	H,LRUCNT	;point to lru count down register
	DCR	M		;decrease it
	JRNZ	NOLRUWT
	MVI	M,FLHDLY	;else, reset the counter and do flush
	CALL	LRUFLH		;flush 1 buffer out to disk
;
NOLRUWT	EQU	$
	ENDIF
;
	MVI	C,DSPTCH	;clock now running
	JMP	XDOS		;jump and dispatch mp/m now
;
	IF	LRU
LRUFLH:
	LXI	D,FLSQCB	;point to flush queue control block
	MVI	C,OPENQUE	;open function
	CALL	XDOS		;open it
	INR	A		;is it there?
	RZ			;return if not
	LXI	D,FLSQCB	;test for queue available
	MVI	C,CONRQUE	;do a conditional test
	CALL	XDOS		;and test for free queue
	INR	A		;check if busy
	RZ			;return, MXdisk is busy
;
	DI			;stop intrps
	MVI	A,1		;set the lru seek flag
	STA	LRUSEK
	MVI	A,0FFH		;kill intrps
	OUT	IMASK
	IN	IMASK		;CLEAR ANY PENDING INTERRUPT
	CALL	SWTSYS		;GET SYSTEM FOR FLUSH LRU BUFFERS
	DI			;DISABLE INTERRUPTS AGAIN
FLHLOP:	LBCD	FLSHNX		;get next check number
	MVI	A,NHITSC	;get the number of checks to do
	CMP	C		;are we done?
	JRZ	FLSHDN		;reset counters and flag
	LXIX	DRVLST		;point to crive list
	DADX	B		;index to correct drive byte
	BITX	7,0		;did we write this drive?
	JRZ	FLSH2		;leave if not
	RESX	7,0		;else, reset the flag bit
	LDA	NXTLRU		;save the current record number
	PUSH	PSW		; on the stack
	MOV	A,C		;get the flush index number
	STA	NXTLRU		;save for flush routine
	CALL	NDFLSH		;do the flush to disk
	POP	PSW		;restore o.s. current lru number
	STA	NXTLRU
FLSH2:	LXI	H,FLSHNX	;get index number
	INR	M		;bump to next
	JMPR	CLOSQU
;
FLSHDN:	LXI	H,FLSHNX
	XRA	A		;clear accum
	MOV	M,A		;reset flush counter/index
	STA	LRUWRT		;clear the write flag
;
CLOSQU:	LXI	D,FLSQCB	;point to queue control block
	MVI	C,CONWQUE	;conditional write queue
	CALL	XDOS		;close the queue and return
	INR	A
	JRZ	CLOSQU
	XRA	A
	STA	LRUSEK		;kill lru seek flag
	MVI	A,0FDH		;MASK ALL BUT VI1
	OUT	IMASK
	EI			;allow intrps again
	RET
;
FLSQCB:	DS	2		;pointer, filled in by open queue
	DW	0		;buffer pointer, not used here
	DB	'MXDisk  '	;queue name, padded to 8 chars.
	ENDIF
;
;
TICK:	DS	1		;tick counter
	REPT	3
	DW	0C7C7H,0C7C7H,0C7C7H,0C7C7H,0C7C7H ;local stack
	ENDM
NEWSTK	EQU	$		;local interrupt stack
TICKN:	DS	1		;clock tick flag storage
PREEMP:	DS	1		;pre-emp flag
HLSAVE:	DS	2		;user h,l save
RTSAVE:	DS	2		;return address save
OLDSTK:	DS	2		;mpm stack pointer
DMAADR:	DS	2		;dma address
;
;
BOOT:	EQU	$
WBOOT:	MVI	C,0		;force termination
	JMP	XDOS		;and got to xdos.
;
;shift right routine
;
SHIFTR:	RAR			;shift
	RAR			;right
	RAR			;four
	RAR			;times
	ANI	0FH		;strip junk bits
	RET
;
;common base read buffer move routine
;move data from buffer for disk read
;
READ3:	LXI	H,BUFFER	;point to transfer buffer
	PUSH	H		;save buffer address
;
	IF	NOT DMACNTL
	CALL	RDTEST		;track 0,1 test
	ENDIF
;
	CALL	READLS		;read logical sector
	STA	ERFLAG		;save the error byte
	LDED	DMAADR		;destination address
	PUSH	D		;save destination address
RWCOMM:	CALL	SWTUSER		;switch to user memory
	POP	D		;restore d,e
	POP	H		;restore buffer address
	LXI	B,128		;count
	LDIR			;block move
	CALL	SWTSYS		;restore system back and ret
	LDA	ERFLAG		;return error flag
	RET
;
;commonbase write buffer move routine
;move data to buffer for disk write
;
WRIT2:	LHLD	DMAADR
	LXI	D,BUFFER
	PUSH	H
	PUSH	D
	JMPR	RWCOMM		;use common routine
;
;read/write move routine.
;de is source, hl is dest
;must be in common base memory.
;
RWMOVE:
	IF	LRU
	MVI	A,0FFH		;mask interrupts
	OUT	IMASK		;set intrp disable
	IN	IMASK		;kill pending intrp for now
;
	LDA	READOP		;which way is xfer?
	ORA	A
	JRNZ	RMOVE		;jump if read move
;
;write operation, switch direction
;
	MVI	A,1		;write operation is needed
	STA	HSTWRT		;mark as write operation
	STA	LRUWRT		;set write flag
	LDA	NXTLRU		;get index value
	MOV	C,A		;ready for index
	MVI	B,0
	LXIX	DRVLST		;point to drive list
	DADX	B		;point to correct drive byte
	SETX	7,0		;set bit 7 on = write this drive
	CALL	SWTUSER		;get user segment
	LXI	D,BUFFER	;xfer destination
	LHLD	DMAADR		;user tpa source
	LXI	B,128
	LDIR
	CALL	SWTSYS		;restore system
	CALL	GETSEC		;get the sector we need
	XCHG			;flip
	LXI	H,BUFFER
	LXI	B,128
	LDIR
	CALL	RSTBNK		;restore bank
	JMPR	RWEXIT		;exit
;
RMOVE:	CALL	GETSEC		;get the sector we need
	LXI	D,BUFFER	;xfer data to buffer 1st
	LXI	B,128		;move count
	LDIR
	CALL	RSTBNK		;restore bank number
	CALL	SWTUSER		;switch to user memory segment
	LDED	DMAADR		;tpa destination
	LXI	H,BUFFER	;source
	LXI	B,128		;move size
	LDIR			;fast z-80 block move
	CALL	SWTSYS		;switch system back, enable intrps again
;
RWEXIT:	MVI	A,0FDH		;clear intrp mask latch
	OUT	IMASK		;allow intrps again
	ELSE
;
	EXX
	IF	HARDSK
	LDA	SEKDSK
	PUSH	PSW		;SAVE DISK NUMBER
	CALL	SWTUSER
	POP	PSW
	CPI	4		;CHECK IF HARD DISK
	JRC	RWNHRD		;NOT HARD
	DI			;DISABLE INTERRUPTS
	XRA	A
	OUT	ADSPRT		;ENABLE HARD DISK BUFFER
RWNHRD:
	EXX
	LXI	B,128		;COUNT
	LDIR
	MVI	A,0FFH
	OUT	ADSPRT		;DISABLE HARD DISK BUFFER
	ELSE
	CALL	SWTUSER		;switch to common base
	EXX
	LXI	B,128		;COUNT
	LDIR			;fast z-80 block move
	ENDIF
	CALL	SWTSYS		;switch system back
	ENDIF
;
;data has been moved to/from host buffer
;
	LDA	WRTYPE		;write type
	ANI	WRDIR		;to directory?
	JRZ	DBEND		;no
	LDA	ERFLAG		;in case of errors
	ORA	A		;any errors?
	JRNZ	DBEND		;jump if yes
;
;clear host buffer for directory write
;
	XRA	A		;0 to accum
	STA	HSTWRT		;buffer written
	CALL	WRITEHST	;up-date directory if needed
DBEND:	LDA	ERFLAG		;recover error flag
	ORA	A		;any errors?
	RZ			;return if not
	LXI	H,HSTDSK	;point to host disk
	MVI	M,0FFH		;force a mis-match
	RET			;return error status
;
;fixed data tables for three-drive standard
;ibm-compatible 8" disks
;disk parameter header for disk 00
;
DPBASE:	DW	TRANS,0000H
	DW	0000H,0000H
	DW	DIRBF,DPBLK1
	DW	CHK00,ALL00
;
;	disk parameter header for disk 01
;
	DW	TRANS,0000H
	DW	0000H,0000H
	DW	DIRBF,DPBLK1
	DW	CHK01,ALL01
;
;	disk parameter header for disk 02
;
	DW	TRANS,0000H
	DW	0000H,0000H
	DW	DIRBF,DPBLK1
	DW	CHK02,ALL02
;
;	disk parameter header for disk 03
;
	DW	TRANS,0000H
	DW	0000H,0000H
	DW	DIRBF,DPBLK1
	DW	CHK03,ALL03
;
;	sector translate vector
;
TRANS:	DB	1,7,13,19	;sectors 1,2,3,4
	DB	25,5,11,17	;sectors 5,6,7,8
	DB	23,3,9,15	;sectors 9,10,11,12
	DB	21,2,8,14	;sectors 13,14,15,16
	DB	20,26,6,12	;sectors 17,18,19,20
	DB	18,24,4,10	;sectors 21,22,23,24
	DB	16,22		;sectors 25,26
;
;	disk parameter block, single density
;
DPBLK1:	DW	26		;sectors per track
	DB	3		;block shift factor
	DB	7		;block mask
	DB	0		;null mask
	DW	242		;disk size-1
	DW	63		;directory max
	DB	192		;alloc 0
	DB	0		;alloc 1
	DW	16		;check size
	DW	2		;track offset
;
;	double density disk parameter block
;
DPBLK2:	DW	51		;sectors per track
	DB	4		;block shift factor
	DB	15		;block mask
	DB	0		;extent mask
	DW	237		;disk size-1
	DW	127		;directory max
	DB	192		;alloc 0
	DB	0		;alloc 1
	DW	32		;check size
	DW	2		;track offset
;
;	double density disk parameter block
;
DPBLK3:	DW	64		;sectors per track
	DB	4		;block shift factor
	DB	15		;block mask
	DB	0		;null mask
	DW	299		;disk size-1
	DW	127		;directory max
	DB	11000000B	;alloc 0
	DB	0		;alloc 1
	DW	32		;check size
	DW	2		;track offset
;
;defines a double density / double side 51 x 128
;
DPBLK5:	DW	51		;sectors / track
	DB	5		;block shift factor
	DB	31		;block mask
	DB	0		;extent mask
	DW	237		;disk size - 1
	DW	95		;max number of directorys
	DB	11000000B	;alloc 0
	DB	0		;alloc 1
	DW	24		;check size
	DW	2		;track offset
;
;defines a double density / double side 512 x 16
;
DPBLK6:	DW	64		;sectors / track
	DB	5		;block shift factor
	DB	31		;block mask
	DB	0		;extent mask
	DW	303		;disk size - 1
	DW	169		;max number of directorys
	DB	11000000B	;alloc 0
	DB	0		;alloc 1
	DW	42		;check size
	DW	2		;reserved tracks
;
	IF	HARDSK
	HDHEDER
	HDPBLK
	ENDIF
;
;	end of fixed tables
;
;io test and vector routines
;
;list status port check
;
LISTST:
	IF	PRNTR1
	MOV	A,D		;TEST IF PRINTER 0 OR 1
	ORA	A
	JRNZ	POLPT1		;GO TEST PRINTER 1
	ENDIF
POLPT0:
	IN	LSTAT0		;check printer 0 status
	IF	PRNTR1
	JR	POLPTX
POLPT1:
	IN	LSTAT1		;check printer 1 status
POLPTX:
	ENDIF
	ANI	LMASK		;mask
	XRI	LMASK		; values
	MVI	A,0		;return status activity
	RNZ			;return if not ready
	CMA			;flip and...
	RET			;return ready
;
; write a character on listing device.
;
LIST:	CALL	LISTST			;check printer status
	MOV	E,C			;SAVE CHARACTER IN E
	JRZ	LPRDY			;jump if not busy
	PUSH	D			;SAVE PRINTER # AND CHARACTER
	MVI	C,POLL			;place on poll list
	IF	PRNTR1
	MOV	A,D
	ANI	1			;MASK 0 & 1 ONLY
	MOV	E,A			;line printer number
	ELSE
	MVI	E,0
	ENDIF
	CALL	XDOS			;call xdos for poll
	POP	D			;RECOVER PRINTER # AND CHARACTER
LPRDY:	IF	PRNTR1
	MOV	A,D			;TEST FOR PRINTER #
	ORA	A
	ENDIF
	MOV	A,E			;get cpm character
	IF	PRNTR1
	JRNZ	LPRN1			;PRINT IT ON PRINTER 1
	ENDIF
	OUT	LDATA0			;send to printer 0
	RET
	IF	PRNTR1
LPRN1:	OUT	LDATA1			;SEND TO PRINTER 1
	RET
	ENDIF
;
;check console status
;
CONST:
	CALL	PTBLJMP		;get address of routine to serv
CONS:	DW	CONST0		;pointer for console 0

	IF	CONSL1
	DW	CONST1		;   "     "     "    1
	ENDIF
	IF	CONSL2
	DW	CONST2		;   "     "     "    2
	ENDIF
	IF	CONSL3
	DW	CONST3		;   "     "     "    3
	ENDIF
;
CONS1:	DS	0
;
NMBCNS	EQU	(CONS1-CONS)/2	;number of consoles defined
;
;console # 0 input status routine
;
	IF	NOT QUECON
POLCI0:	EQU	$
CONST0:	EQU	$
	ENDIF
;
	IF	TARBELL AND NOT QUECON
	IN	CSTAT0		;console status
	ANI	CIMASK		;check data ready
	ENDIF
;
	IF	NOT TARBELL AND NOT QUECON
	IN	VSTAT0		;using a vdb-8024
	ANI	VIMASK		;  "        "
	ENDIF
;
	IF	NOT QUECON
	JMP	CONSTC		;use common routine
	ENDIF
;
;console # 1 input status routine
;
POLCI1:	EQU	$
CONST1:	EQU	$
	IF	QUECON AND CONSL1
	LDA	C1INMSGCNT	;key pushed
	ORA	A		;check for a 0 byte
	RZ			;return if not ready
	MVI	A,0FFH		;else, return its ready
	RET
	ENDIF

	IF	NOT QUECON AND CONSL1
	IN	CSTAT1		;console status
	ANI	CIMASK		;check data ready
	JMP	CONSTC
	ENDIF
;
;console #2 input status routine
;
POLCI2:	EQU	$
CONST2:	EQU	$
	IF	QUECON AND CONSL2
	LDA	C2INMSGCNT	;key pushed
	ORA	A		;check for a 0
	RZ			;return if not ready
	MVI	A,0FFH		;else, return its ready
	RET
	ENDIF

	IF	NOT QUECON AND CONSL2
	IN	CSTAT2		;console status
	ANI	CIMASK		;check data ready
	JMP	CONSTC		;use common routine
	ENDIF
;
;console #3 input status routine
;
POLCI3:	EQU	$
CONST3:	EQU	$
	IF	QUECON AND CONSL3
	LDA	C3INMSGCNT	;key pushed
	ORA	A		;check for a 0
	RZ			;return if not ready
	MVI	A,0FFH		;else, return its ready
	RET
	ENDIF

	IF	NOT QUECON AND CONSL3
	IN	CSTAT3		;console status
	ANI	CIMASK		;check data ready
	JMP	CONSTC		;use common routine
	ENDIF
;
;poll console # 0 output
;
POLCO0:	EQU	$
	IF	TARBELL
	IN	CSTAT0		;console status
	ANI	COMASK		;check data ready
	ELSE
	IN	VSTAT0
	ANI	VOMASK
	ENDIF
;
	JMP	CONSTC		;use common routine
;
;poll console #1 output
;
	IF	CONSL1
POLCO1:	IN	CSTAT1		;console status
	ANI	COMASK		;check data ready
	JMP	CONSTC
	ENDIF
;
;poll console # 2 output
;
	IF	CONSL2
POLCO2:	IN	CSTAT2		;console status
	ANI	COMASK		;check data ready
	JMP	CONSTC		;use common routine
	ENDIF
;
;poll console # 3 output
;
	IF	CONSL3
POLCO3:	IN	CSTAT3		;console status
	ANI	COMASK		;check data ready
	ENDIF
CONSTC:	RZ			;return if not ready
	MVI	A,0FFH		;else, return its ready
	RET
;
;read a character from the console
;
CONIN:	CALL	PTBLJMP
	DW	CONIN0		;console input 0

	IF	CONSL1
	DW	CONIN1		;   "      "   1
	ENDIF
	IF	CONSL2
	DW	CONIN2		;   "      "   2
	ENDIF
	IF	CONSL3
	DW	CONIN3		;   "      "   3
	ENDIF
;
;console #0 input routine
;
CONIN0:	EQU	$
	IF	QUECON
	MVI	C,READQUE	;read queue function
	LXI	D,C0INUQCB	;point to queue structure
	CALL	XDOS		;call xdos for char
	LDA	CHAR0IN		;get char from buffer
	ANI	7FH		;strip parity
	RET
	ENDIF
;
C0INPD:	EQU	$
	IF	QUECON AND CONSL1
	DW	C1INPD		;pl
	ENDIF

	IF	QUECON AND NOT CONSL1
	DW	0		;pl
	ENDIF

	IF	QUECON
	DB	0		;status
	DB	32		;priority
	DW	C0INSTK+38	;stack pointer
	DB	'C0IN    '	;name of function
	DB	0		;console
	DB	0FFH		;memseg
	DS	36
C0INSTK:DW	0C7C7H,0C7C7H,0C7C7H
	DW	0C7C7H,0C7C7H,0C7C7H
	DW	0C7C7H,0C7C7H,0C7C7H
	DB	'FACBEDLHXIYIFACBEDLH'
	DW	C0INP		;starting address
C0INQ:	DW	0		;ql
	DB	'C0INQUE '	;name
	DW	1		;msglen
	DW	4		;nmbmsgs
	DS	8
C0INMSGCNT:
	DS	2		;message count
	DS	4		;buffer
C0INQCB:DW	C0INQ		;pointer
	DW	CH0IN		;msg addr.
CH0IN:	DB	0
C0INUQCB:
	DW	C0INQ		;pointer
	DW	CHAR0IN		;msg addr.
CHAR0IN:DB	0		;char buffer
;
;
POLCI0:	EQU	$		;return ff if ready	
CONST0:	EQU	$		;else, 00 if not
	LDA	C0INMSGCNT	;any key pushed
	ORA	A		;check for a 0
	RZ			;return if not ready
	MVI	A,0FFH		;else, return its ready
	RET
;
C0INP:	MVI	C,MAKEQUE	;make queue function
	LXI	D,C0INQ		;point to queue
	CALL	XDOS		;call xdos for makeing queue
C0LOOP:	MVI	C,FLGWAIT	;set flagwait for char
	MVI	E,6		;flag value
	CALL	XDOS		;wait till co in intrp flag
	MVI	C,WRITQUE	;now write the queue
	LXI	D,C0INQCB	;point to the buffer area
	CALL	XDOS		;wait till char comes ready
	JMP	C0LOOP		;loop till it does.
;
	ELSE
;
	MVI	C,POLL		;poll function
	MVI	E,PLCI0		;chan 0 poll code
	CALL	XDOS
	ENDIF
;
	IF	TARBELL AND NOT QUECON
	IN	CDATA0		;get the key
	ENDIF
;
	IF	NOT TARBELL AND NOT QUECON
	IN	VDATA0
	ENDIF
;
	IF	NOT QUECON
	ANI	7FH		;strip parity bit
	RET
	ENDIF
;
;console #1 input routine
;
CONIN1:	EQU	$
	IF	QUECON AND CONSL1
	MVI	C,READQUE
	LXI	D,C1INUQCB
	CALL	XDOS
	LDA	CHAR1IN
	ANI	7FH
	RET
	ENDIF
;
C1INPD:	EQU	$
	IF	QUECON AND CONSL2
	DW	C2INPD		;pl
	ENDIF

	IF	QUECON AND NOT CONSL2
	DW	0		;pl
	ENDIF

	IF	QUECON AND CONSL1
	DB	0		;status
	DB	33		;priority
	DW	C1INSTK+38	;stack pointer
	DB	'C1IN    '	;name of function
	DB	1		;console
	DB	0FFH		;memseg
	DS	36
C1INSTK:DW	0C7C7H,0C7C7H,0C7C7H
	DW	0C7C7H,0C7C7H,0C7C7H
	DW	0C7C7H,0C7C7H,0C7C7H
	DB	'FACBEDLHXIYIFACBEDLH'
	DW	C1INP		;starting address
C1INQ:	DW	0		;ql
	DB	'C1INQUE '	;name
	DW	1		;msglen
	DW	4		;nmbmsgs
	DS	8
C1INMSGCNT:
	DS	2		;message count
	DS	4		;buffer
C1INQCB:DW	C1INQ		;pointer
	DW	CH1IN		;msg addr.
CH1IN:	DB	0
C1INUQCB:
	DW	C1INQ		;pointer
	DW	CHAR1IN		;msg addr.
CHAR1IN:DB	0
C1INP:	MVI	C,MAKEQUE	;make queue function
	LXI	D,C1INQ
	CALL	XDOS
C1LOOP:	MVI	C,FLGWAIT
	MVI	E,7
	CALL	XDOS		;wait till co in intrp flag
	MVI	C,WRITQUE
	LXI	D,C1INQCB
	CALL	XDOS
	JMP	C1LOOP
	ENDIF

	IF	NOT QUECON AND CONSL1
	MVI	C,POLL
	MVI	E,PLCI1
	CALL	XDOS
	IN	CDATA1		;get the key
	ANI	7FH		;strip parity bit
	RET
	ENDIF
;
;console #2 input routine
;
CONIN2:	EQU	$
	IF	QUECON AND CONSL2
	MVI	C,READQUE
	LXI	D,C2INUQCB
	CALL	XDOS
	LDA	CHAR2IN
	ANI	7FH
	RET
	ENDIF
;
C2INPD:	EQU	$
	IF	QUECON AND CONSL3
	DW	C3INPD		;pl
	ENDIF

	IF	QUECON AND NOT CONSL3
	DW	0		;pl
	ENDIF

	IF	QUECON AND CONSL2
	DB	0		;status
	DB	34		;priority
	DW	C2INSTK+38	;stack pointer
	DB	'C2IN    '	;name of function
	DB	2		;console
	DB	0FFH		;memseg
	DS	36
C2INSTK:DW	0C7C7H,0C7C7H,0C7C7H
	DW	0C7C7H,0C7C7H,0C7C7H
	DW	0C7C7H,0C7C7H,0C7C7H
	DB	'FACBEDLHXIYIFACBEDLH'
	DW	C2INP		;starting address
C2INQ:	DW	0		;ql
	DB	'C2INQUE '	;name
	DW	1		;msglen
	DW	4		;nmbmsgs
	DS	8
C2INMSGCNT:
	DS	2		;message count
	DS	4		;buffer
C2INQCB:DW	C2INQ		;pointer
	DW	CH2IN		;msg addr.
CH2IN:	DB	0
C2INUQCB:
	DW	C2INQ		;pointer
	DW	CHAR2IN		;msg addr.
CHAR2IN:DB	0
C2INP:	MVI	C,MAKEQUE	;make queue function
	LXI	D,C2INQ
	CALL	XDOS
C2LOOP:	MVI	C,FLGWAIT
	MVI	E,8
	CALL	XDOS		;wait till co in intrp flag
	MVI	C,WRITQUE
	LXI	D,C2INQCB
	CALL	XDOS
	JMP	C2LOOP
	ENDIF

	IF	NOT QUECON AND CONSL2
	MVI	C,POLL
	MVI	E,PLCI2
	CALL	XDOS
	IN	CDATA2		;get the key
	ANI	7FH		;strip parity bit
	RET
	ENDIF
;
;console #3 input routine
;
CONIN3:	EQU	$
	IF	QUECON AND CONSL3
	MVI	C,READQUE
	LXI	D,C3INUQCB
	CALL	XDOS
	LDA	CHAR3IN
	ANI	7FH
	RET
;
C3INPD:	DW	00		;pl
	DB	0		;status
	DB	35		;priority
	DW	C3INSTK+38	;stack pointer
	DB	'C3IN    '	;name of function
	DB	3		;console
	DB	0FFH		;memseg
	DS	36
C3INSTK:DW	0C7C7H,0C7C7H,0C7C7H
	DW	0C7C7H,0C7C7H,0C7C7H
	DW	0C7C7H,0C7C7H,0C7C7H
	DB	'FACBEDLHXIYIFACBEDLH'
	DW	C3INP		;starting address
C3INQ:	DW	0		;ql
	DB	'C3INQUE '	;name
	DW	1		;msglen
	DW	4		;nmbmsgs
	DS	8
C3INMSGCNT:
	DS	2		;message count
	DS	4		;buffer
C3INQCB:DW	C3INQ		;pointer
	DW	CH3IN		;msg addr.
CH3IN:	DB	0
C3INUQCB:
	DW	C3INQ		;pointer
	DW	CHAR3IN		;msg addr.
CHAR3IN:DB	0
C3INP:	MVI	C,MAKEQUE	;make queue function
	LXI	D,C3INQ
	CALL	XDOS
C3LOOP:	MVI	C,FLGWAIT
	MVI	E,9
	CALL	XDOS		;wait till co in intrp flag
	MVI	C,WRITQUE
	LXI	D,C3INQCB
	CALL	XDOS
	JMP	C2LOOP
	ENDIF

	IF	NOT QUECON AND CONSL3
	MVI	C,POLL
	MVI	E,PLCI3
	CALL	XDOS
	IN	CDATA3		;get the key
	ANI	7FH		;strip parity bit
	RET
	ENDIF
;
;character out to console
;
CONOUT:	CALL	PTBLJMP
	DW	CONOT0		;console # 0 output

	IF	CONSL1
	DW	CONOT1		;   "    # 1   "
	ENDIF
	IF	CONSL2
	DW	CONOT2		;   "    # 2   "
	ENDIF
	IF	CONSL3
	DW	CONOT3		;console # 3 output
	ENDIF
;
;console # 0 output handler
;
CONOT0:	CALL	POLCO0		;use common status routine
	ORA	A		;need service?
	JRNZ	CO0RDY		;jump if so
	PUSH	B		;else, place on poll list
	MVI	C,POLL		;poll function
	MVI	E,PLCO0		;device number to poll
	CALL	XDOS
	POP	B		;recover char
CO0RDY:	MOV	A,C		;get char
;
	IF	TARBELL
	OUT	CDATA0		;send it
	ELSE
	OUT	VDATA0
	ENDIF
;
	RET
;
;console # 1 output handler
;
	IF	CONSL1
CONOT1:	CALL	POLCO1		;use common routine
	ORA	A
	JRNZ	CO1RDY
	PUSH	B
	MVI	C,POLL		;poll function
	MVI	E,PLCO1		;device number to poll
	CALL	XDOS
	POP	B		;recover char
CO1RDY:	MOV	A,C		;get char
	OUT	CDATA1		;send it
	RET
	ENDIF
;
;console # 2 output handler
;
	IF	CONSL2
CONOT2:	CALL	POLCO2
	ORA	A
	JRNZ	CO2RDY
	PUSH	B
	MVI	C,POLL		;poll function
	MVI	E,PLCO2		;device number to poll
	CALL	XDOS
	POP	B		;recover char
CO2RDY:	MOV	A,C		;get char
	OUT	CDATA2		;send it
	RET
	ENDIF
;
;console # 3 output handler
;
	IF	CONSL3
CONOT3:	CALL	POLCO3
	ORA	A
	JRNZ	CO3RDY
	PUSH	B
	MVI	C,POLL		;poll function
	MVI	E,PLCO3		;device number to poll
	CALL	XDOS
	POP	B		;recover char
CO3RDY:	MOV	A,C		;get char
	OUT	CDATA3		;send it
	RET
	ENDIF
;
;poll i/o device index routine
;
PTBLJMP:MOV	A,D		;get device number
	CPI	NMBCNS		;check for number of devices
	JRC	TBLJMP		;if <= , we are ok.
	POP	PSW		;waste table address
;
RTNEMPTY:
	XRA	A		;return error code
	RET
;
TBLJMP:	POP	H		;recover pointer to jump table
TBLJP1:	ADD	A		;device number * 2
	MOV	E,A		;set reg e
	MVI	D,0		;set reg d = 0
	DAD	D		;add index
	MOV	E,M		;get low byte
	INX	H		;bump pointer
	MOV	D,M		;get high byte
	XCHG			;put into h,l
	PCHL			;go to device handler
;
;mpm poll table list
;
;reg c = devicce # to be polled
;return ffh if ready, else a 00
;
POLL$DEVICE:
	MOV	A,C		;get device number
	CPI	NMBDEV		;compare for number of devices
	JRC	DEVOK		;if < = , we are ok
	MVI	A,NMBDEV	;else, set for max only.
DEVOK:	CALL	TBLJMP		;use index routine
;
DEVOK1:	DW	POLPT0		;poll printer device 0
;
	IF	PRNTR1
	DW	POLPT1		;POLL PRINTER DEVICE 1
	ENDIF
;
	IF	HARDSK
	DW	POLHRD
	ENDIF
;
	IF	DMACNTL
	DW	POLDMA		;poll dma device
	DW	POLDSK		;poll disk device
	ELSE
	DW	RTNEMPTY	;not used
	DW	RTNEMPTY	;not used
	ENDIF

	DW	POLCO0		;poll console #0 output

	IF	CONSL1
	DW	POLCO1		; # 1 output
	ELSE
	DW	RTNEMPTY
	ENDIF

	IF	CONSL2
	DW	POLCO2		; # 2 output
	ELSE
	DW	RTNEMPTY
	ENDIF

	IF	CONSL3
	DW	POLCO3		; # 3 output
	ELSE
	DW	RTNEMPTY
	ENDIF

	DW	POLCI0		;poll consloe # 0 input

	IF	CONSL1
	DW	POLCI1		; # 1 input
	ELSE
	DW	RTNEMPTY
	ENDIF

	IF	CONSL2
	DW	POLCI2		; # 2 input
	ELSE
	DW	RTNEMPTY
	ENDIF

	IF	CONSL3
	DW	POLCI3		; # 3 input
	ELSE
	DW	RTNEMPTY
	ENDIF

DEVOK2:	EQU	$
NMBDEV	EQU	(DEVOK2-DEVOK1)/2 ;number of devices
	DW	RTNEMPTY	;bad device called
;
;start clock routine
;
START$CLOCK:
	MVI	A,0FFH		;set flag # 1
TICKNS:	STA	TICKN		;set clock going
	RET
;
;stop clock routine
;
STOP$CLOCK:
	XRA	A		;set flag # 1 = 0
	JMPR	TICKNS		;stop the clock
;
;exit region
;
EXIT$REGION:
	LDA	PREEMP
	ORA	A
	RNZ
	EI
	RET
;
;max console number
;
MAX$CONSOLE:
	MVI	A,NMBCNS	;number of consoles defined
	RET
;
;interrupt handler routine
;
INTLHND:
	SHLD	HLSAVE		;save h,l
	POP	H		;get return address from stack
	SHLD	RTSAVE		;save return address
	PUSH	PSW		;save mp/m accum and psw
	SSPD	OLDSTK		;save system stack pointer
	LXI	SP,NEWSTK	;set local stack for interrupts
	PUSH	D
	PUSH	B
	MVI	A,0FFH		;set preemp flag
	STA	PREEMP
;
	IF	TARBELL AND QUECON
	IN	CSTAT0		;get status of chan 0
	ANI	CIMASK		;check for ready
	ENDIF
;
	IF	NOT TARBELL AND QUECON
	IN	VSTAT0
	ANI	VIMASK
	ENDIF
;
	IF	QUECON AND CONSL1
	JRZ	CONS11		;if not ready, check next con:
	ENDIF
;
	IF	TARBELL AND QUECON
	IN	CDATA0		;get console 0 data
	ENDIF
;
	IF	NOT TARBELL AND QUECON
	IN	VDATA0
	ENDIF
;
	IF	QUECON
	STA	CH0IN		;save con: 0 data
	MVI	C,FLAGSET	;set flag for ready
	MVI	E,6
	CALL	XDOS
	ENDIF
CONS11:	EQU	$
	IF	QUECON AND CONSL1
	IN	CSTAT1		;test console #1
	ANI	CIMASK
	JRZ	CONS2
	IN	CDATA1
	STA	CH1IN
	MVI	C,FLAGSET
	MVI	E,7
	CALL	XDOS
CONS2:	EQU	$
	ENDIF

	IF	QUECON AND CONSL2
	IN	CSTAT2		;test console #2
	ANI	CIMASK
	JRZ	CONS3
	IN	CDATA2
	STA	CH2IN
	MVI	C,FLAGSET
	MVI	E,8
	CALL	XDOS
CONS3:	EQU	$
	ENDIF

	IF	QUECON AND CONSL3
	IN	CSTAT3		;test console # 3
	ANI	CIMASK
	JRZ	CONS4
	IN	CDATA3
	STA	CH3IN
	MVI	C,FLAGSET
	MVI	E,9
	CALL	XDOS
CONS4:	EQU	$
	ENDIF

	LDA	TICKN		;get tickn flag
	ORA	A		;test tickn flag
	JRZ	NOTTICK		;jump if = 0
	MVI	C,FLAGSET	;else,
	MVI	E,1		;set flag #1 tick
	CALL	XDOS		;through xdos
NOTTICK:LXI	H,TICK		;point to tick counter
	DCR	M		;decrease by 1
	JRNZ	NOT1SEC		;= 1 second yet
	MVI	M,TINTRVL	;1 sec elapsed, reset counter
	MVI	C,FLAGSET
	MVI	E,2		;set flag #2 at 1 second
	CALL	XDOS
;
;other interrupt handlers go here
;
NOT1SEC:EQU	$
	XRA	A		;clear preemp flag
	STA	PREEMP		;and save it
	POP	B
	POP	D
	LSPD	OLDSTK		;recover system stack
	LHLD	RTSAVE		;recover return save address
	IN	IMASK		;clear interrupt latch.
	POP	PSW		;recover psw
	PUSH	H		;put on top of stack
;
;note:	the following dispatch will force round-robin
;	scheduling of processes executing at the same
;	priority at each system tick { 16.666 ms }
;
	LHLD	HLSAVE		;recover user h,l
	JMP	PDISP		;mp/m dispatch
;
POLDSK:	IN	DSTAT		;check disk status
	MOV	E,A		;save a copy
	ANI	80H		;drive ready
	MVI	A,0		;0 = not ready
	RNZ
	MOV	A,E
	RRC			;disk busy?
	MVI	A,0
	RC			;yes, return a 00 hex
	CMA			;flip to = ff hex, ready
	RET
;
;general purpose wait routine
;
POLDMA:	IN	DMACHK		;check bit 7
	RLC			;and rotate it left
	MVI	A,0		;complete?
	RC
	OUT	CMND		;reset dma chip
	CMA			;flip = ready
	RET			; and return it to caller
;
	IF	HARDSK
	ADSPOL			;hardisk poll routine
	ENDIF
;
;select memory routine
;
;bank descriptor:  base - size - attrib - bank
;
SEL$MEMORY:
;
	IF	NOT DEBUG
	LDAX	B		;get base address
	CALL	SHIFTR		;shift right
	MOV	E,A		;save base address start
	ADI	MEMMAG		;add in memory management port
	MOV	D,A		;save in reg e
	INX	B		;bump to bank size
	LDAX	B		;get it
	ORA	A		;is it = 0
	RZ			;return if so
	CALL	SHIFTR		;else, shift bank size right
	INR	A		;BUMP TO GET ANY ODD STUFF
	EXAF			;save in alternate accum.
	INX	B		;bump to attrib byte
	INX	B		;point to bank port byte
	LDAX	B		;get bank port byte
	ADD	A		;*2
	ADD	A		;*4
	ADD	A		;*8
	ADD	A		;*16
	MOV	C,A		;memory bank table start
	MVI	B,0		;index value now ready
	PUSH	D		;save d,e
	LXI	D,7		;base pointer -> xiosjmp.tbl
	LHLD	SYSDAT		;get pointer to system.dat
	DAD	D
	MOV	E,D		;get a zero to reg e
	MOV	D,M		;get base of xiosjmp.tbl
	XCHG			;h,l-> xiosjmp.tbl start
	LDED	MEM$TBL$PNTR	;offset from xiosjmp.tbl start
	DAD	D		;h,l-> memory byte table start
	DAD	B		;h,l-> bank byte table start
	POP	D		;recover d,e
	MOV	C,E		;reg c = position to start
	DAD	B		;h,l-> start within byte table
	EXAF			;recover size byte
	MOV	B,A		;reg b = count
	MOV	C,D		;reg d = m/m port start
	LDA	MAXSIZ		;GET MAX MEMMAG PORT
	MOV	D,A		;PUT IN D FOR FAST COMPARE
MEMSEL:	MOV	A,M		;get a byte from table
	CMA			;flip for cpu memory
	OUTP	A		;use reg c as i/o port address
	INX	H		;bump to next byte
	INR	C		;bump i/o port address
	MOV	A,C		;CHECK FOR OVERLAP
	CMP	D
	RZ			;RETURN IF UP TO COMMONBASE
	DJNZ	MEMSEL		;loop till all init is done
	ENDIF

	RET			;return to caller
MAXSIZ	DS	1		;MAX MEMMAG PORT #
;
	IF	LRU
NXTLRU:	DS	1		;save area for next l.r.u.
RELHST:	DS	2		;relative host buffer record number
LRUWRT:	DS	1		;write flag for lru use
FLSHNX:	DS	2		;flush index counter
BNKNUM:	DS	1		;extended bank number for lru
LRUCNT:	DS	1		;time counter for lru flush
LRUSEK:	DS	1		;lru flush seek flag 0= use poll routine
	ENDIF			;		     1= use no polling
;

;system initialization routines
;
SYSINT	EQU	$
;
	IF	LRU
BUFFER:	DS	128		;single density transfer buffer
DIRBF:	DS	128		;scratch directory area
	ELSE
HSTBUF	EQU	$		;claim for host buffer
	ENDIF
;
;clear un-initialized area at
;end of xios
;the area from hstbuf to hststp will be
;claimed as the host sector buffer after
;mp/m is running.
;
	EXX			;save primary regs
	LXI	H,BEGDAT	;clear scratch area
	LXI	D,BEGDAT+1	;block transfer dest.
	LXI	B,BUFF1-BEGDAT+1	;count
	XRA	A
	MOV	M,A		;set first loc. = 0
	LDIR			;use block move to clear
;
	IF	LRU
	LXI	H,TRKLST	;point to track list
	LXI	D,TRKLST+1
	LXI	B,NHITSC*3	;get the number of sectors in l.r.u.
	MVI	M,0FFH		;force track, sector mis-match on start up
	LDIR			;block fill it
	LXI	H,DRVLST	;fill drive list with 0Fh
	MVI	B,NHITSC
	MVI	A,0FH
DRVINT:	MOV	M,A
	INX	H
	DJNZ	DRVINT
	LXI	H,HITLST
	LXI	B,NHITSC SHL 8 OR 00H	;setup hit list
HITINT:	MOV	M,C		;place byte into table
	INX	H		;bump pointer
	INR	C		;bump to next byte
	DJNZ	HITINT		;loop till all filled
	XRA	A		;get a zero
	STA	LRUWRT		;clear lru write flag
	LXI	H,0
	SHLD	FLSHNX		;clear flush index counter
	LXI	H,FLHDLY	;flush delay count
	SHLD	LRUCNT
	ENDIF
;
	LXI	H,0		;clear h,l
	SHLD	DSKLG		;clear disk logs
	MVI	H,10H
	SHLD	DSKLG1
	MVI	H,20H
	SHLD	DSKLG2
	MVI	H,30H
	SHLD	DSKLG3
	EXX			;restore
;
	SHLD	BIOSAD
	SDED	DEBUGA
	MOV	A,C
	RAL
	RAL
	RAL
	MVI	H,0
	MOV	L,A
	SHLD	DEBUGR
;
	IF	QUECON
	MVI	C,CREATE	;create process
	LXI	D,C0INPD	;point to process discriptor
	CALL	XDOS
	ENDIF
;
;initialize each bank but the first 1.
;the first bank is the mp/m-80 system.
;this routine assumes that the memory
;management circuit has been initialized
;by the bootstrap loader program.
;
	IF	NOT DEBUG
	LHLD	SYSDAT		;GET START OF SYSTEM DATA PAGE
	LXI	D,124		;OFFSET TO COMMONBASE PAGE
	DAD	D
	MOV	A,M		;GET COMMONBASE PAGE
	CALL	SHIFTR
	ADI	MEMMAG		;ADD MEMORY MAMAG BASE PORT
	STA	MAXSIZ		;MAXIMUM PORT # FOR SEL$MEMORY
	LHLD	SYSDAT		;get start of system.dat
	LXI	D,15		;offset to memory segs
	DAD	D		;h,l -> seg count
	MOV	B,M		;get count of segs to do
;
	IF	LRU
	MVI	A,LRUBNK	;LRU BANK NUMBER
	RLC
	RLC
	RLC
	RLC
	STA	BNKNUM		;save m/m bank number
	ENDIF
;
	INX	H		;point to main bank
	SHLD	MAINBK		;save main bank select pointer
	DCR	B		;skip first page
	LXI	D,4		;point to next segment byte
	DAD	D		;h,l-> next seg byte.
INIT3:	SHLD	CNTLSG		;save control seg pointer
	SBCD	INITCT		;save init counter
	LBCD	CNTLSG		;get memory pointer
	LDAX	B		;check for non-zero base start
	ORA	A		;= 0?
	JRNZ	INIT4		;don't init if < > 0
	CALL	SEL$MEMORY	;select this bank
	ENDIF

	CALL	SETUP		;init selected bank low memory

	IF	DEBUG
	RET
	ENDIF

	IF	NOT DEBUG
INIT4:	LHLD	CNTLSG		;get control segment pointer
	LXI	D,4		;offset to next memory discrp.
	DAD	D		;add to h,l
	LBCD	INITCT		;get counter value
	DJNZ	INIT3		;loop till all banks are inited
	LBCD	MAINBK		;b,c -> main bank select
	JMP	SEL$MEMORY	;select bank 0 and run mp/m
	ENDIF
;
;setup restart jump vectors
;
SETUP:	MVI	A,0C3H		;jump inst.
	STA	VECT*8		;rst vector # * 8
	STA	0
	LHLD	DEBUGR
	MOV	M,A
	INX	H
	LDED	DEBUGA
	MOV	M,E
	INX	H
	MOV	M,D
	LHLD	BIOSAD
	SHLD	1
	LXI	H,INTLHND	;point to interrupt handler
	SHLD	VECT*8+1	;jump inst. complete
	RET
;
;set up timer and interrupt controller
;this routine is called once
;
TIMINT:	XRA	A
	MOV	H,A
	MOV	L,A
	STA	IDLE		;clear call to this routine
	SHLD	IDLE+1		;to nop bytes (nulls)
	MVI	A,CNTR2+RLWORD+MODE2+BINARY
	LXI	B,INTERVL	;timer interval
	OUT	TCMND		;send init byte
	MOV	A,C		;get low byte of count
	OUT	TCH2		;send it
	MOV	A,B		;get high byte of count
	OUT	TCH2		;send it
	MVI	A,0FDH		;MASK ALL BUT VI1
	OUT	IMASK		;clear intrp mask bits
	RET			;back to caller
;
;
BIOSAD:	DS	2		;bios address save
DEBUGA:	DS	2		;debugger address save
DEBUGR:	DS	2		;debugger restart save
MAINBK:	DS	2		;main bank save area for init
INITCT:	DS	2		;counter loop value for init
CNTLSG:	DS	2		;memory bank being initialized
;
	IF	NOT LRU
HSTSTP:	DS	HSTSIZ-($-SYSINT) ;end of host buffer storage.
BUFFER:	DS	128		;SINGLE DENSITY TRANSFER BUFFER
DIRBF:	DS	128		;SCRATCH DIRECTORY AREA
	ENDIF
	DB	0		;force eof on hex file
