	TITLE	'Deblocked Bios of 3-21-83 L.R.U. ver'
;
; Deblocked Bios for Tarbell Double Density Controller Board.
;     With Morrow Winchester disk support.
; ADES (priam) hardisk version g.w.mulchin  10-1-81
; increased 512x16 to 170 dir entries, & 1208 Kbytes 10-22-81
; added seek to same trk to unload head on new drv select 01-28-81
; added 10 megabyte hooks for priam drive  10-29-81
; added Least Recently Used Algorithm (LRU) 4-19-82
;  BEGINNING OF MODS BY ED SMITH
; MOVED ADES BUFFER ADDRESS TO FC00 AND ADDED
; BUFFER ENABLE DISABLE 8-10-82
; ADDED CPM PAGE SIZING OPTION 8-13-82
; ADDED SIZE CHECK 8-17-82
; CORRECTED ZASM ERRORS 9-7-82
; ADDED CODE TO DISABLE TIMER AT BOOT 9-7-82
; ADDED CODE TO ENABLE USE OF LRU WITH HARD DISK 10-5-82
; ADDED CONSOLE INPUT TYPE AHEAD WITH INTERRUPT 10-13-82
; FIXED PROBLEM WITH TRACK TABLE 10-18-82
; ADDED WINCHESTER DISKS 12-9-82
; DELETED "TRANS" MOD CODE IN SELDSK ROUTINE 12-10-82
; FIXED CONINT GLITCH AND NON DEBLOCKED LRU PROBLEM 12-30-81
; ADDED 9 MEG TANDON DRIVE 1-6-83
; ADDED 33 MEG ATASI DRIVE 1-31-83
; SETUP FOR WARM BOOT FROM WINCHESTER DISK , REMAPPED LOGICAL
; DISK NOS. , AND DELETED ADES HARD DISK SUPPORT 2-17-83
; ADDED 19 MEGABYTE CMI 5619 WINCHESTER 3-21-83
; CHANGED DISPLAY DATE BECAUSE OF NEW WINCHESTER LIBRARY 3-23-83
; EDWIN E. SMITH
;=============================================================
;	** Note **
;	   ----
;    If you want to use the Ades Interface with this bios,
; you must set both mac and ades to TRUE. You must also
; have MAC to assemble this bios with the L.R.U option or the
; ades macro library. Any other combination will not work!!
;============================================================
;
TRUE	EQU	-1
FALSE	EQU	0
;
;------------------------------------------------------------
;          this is the area you change for
;		your situation
;------------------------------------------------------------
; To locate cpm on a page boundry instead of a kbyte
; boundry set PGS EQU to 1,2 or 3 for example a 61.5
; kbyte cp/m would have MSIZE EQU to 61 and PGS EQU
; to 2 . (see digital research AN-9, 9/29/81)
;
; The MSIZE, and PGS equates in the DBBIOS and DMABOOT source
; files, and the DDS equate in the DMABOOT source file have
; certain maximum values depending on your particular situation.
; The following table shows the values for a few common setups.
;
;			      MSIZE    PGS     DDS
;  DEBLOCK BIOS			63	0	9
;      WITH CONINT		62	3	10
;  DEBLOCK W/LRU		62	1	11
;      WITH CONINT		62	0	11
;  DEBLOCK W/RMS12		61	1	13
;  DEBLOCK W/CMI5619		61	1	13
;  DEBLOCK W/MINISCRIBE 20	61	1	13
;  DEBLOCK W/DISCTRON D526	61	0	13
;  DEBLOCK W/ATASI 33		60	3	14
;
; If an MSIZE which is less than the above values is used, the
; address (FC00H) of the ADES controller may have to be lowered
; in order to bring the initialization routines within range of
; the bootstrap loader.
;
; Use this formula to determine the last address that the bootstrap
; will load for any configuration.
;
; (MSIZE-20)*1024+PGS*256+16511+DDS*512
;
MSIZE	EQU	61	;cp/m memory size in kilobytes
PGS	EQU	1	;additional cp/m pages
;
MAC	EQU	TRUE	;true if macro assembler
CRSDRV	EQU	TRUE	;true if using cross drive auto select
LRU	EQU	FALSE	;true if using l.r.u. algorithm
NHITSC	EQU	128	;buffer up this amount of sectors
BNKNUM	EQU	10H	;extended bank address for l.r.u. buffers
TARBELL	EQU	TRUE	;true if using tarbell cpu/io
TIMER	EQU	FALSE	;true if using timer on tarbell cpu/io
MW12	EQU	FALSE	;TRUE IF USING 12 MEGABYTE WINCHESTER
MW19	EQU	TRUE	;TRUE IF USING 19 MEGABYTE WINCHESTER
MW20	EQU	FALSE	;TRUE IF USING 20 MEGABYTE WINCHESTER
MW26	EQU	FALSE	;TRUE IF USING 26 MEGABYTE WINCHESTER
MW33	EQU	FALSE	;TRUE IF USING 33 MEGABYTE WINCHESTER
DMACNTL	EQU	TRUE	;true if using dma control
LSTPAG	EQU	FALSE	;true if using list paging option
LINCNT	EQU	66	;if lstpag true, = # of lines/page
LSTNUL	EQU	FALSE	;true if printer needs nulls
LNULL	EQU	0	;number of lister nulls to do
STPRAT	EQU	0	;0=3ms,1=6ms,2=15ms,3=20ms(stp rate)
HLAB	EQU	8	;0=no head load at beginning of seek
DUAL	EQU	FALSE	;true if using a persci drive
ERCNT	EQU	10	;error retry count
CONINT	EQU	FALSE	;TRUE IF USING CONSOLE TYPE AHEAD
NFLOP	EQU	1	;NUMBER OF FLOPPY DRIVES
;
MINWIN	EQU	MW12 OR MW19 OR MW20 OR MW26 OR MW33
;
	IF	MAC
	MACLIB	Z80	;use macro library
	ENDIF
;
	IF	MW12 AND MAC
	MACLIB	MW12	;USE WINCHESTER LIBRARY
	ENDIF
;
	IF	MW19 AND MAC
	MACLIB	MW19	;USE WINCHESTER LIBRARY
	ENDIF
;
	IF	MW20 AND MAC
	MACLIB	MW20	;USE WINCHESTER LIBRARY
	ENDIF
;
	IF	MW26 AND MAC
	MACLIB	MW26	;USE WINCHESTER LIBRARY
	ENDIF
;
	IF	MW33 AND MAC
	MACLIB	MW33	;USE WINCHESTER LIBRARY
	ENDIF
;
;i/o equates
;
	IF	TARBELL		;if using tarbell cpu/io
IOBASE	EQU	00H		;i/o base on tarbell (00 or 10 hex)
MEMMAG	EQU	IOBASE+20H	;base of mem/mang address
;
CCOM	EQU	IOBASE+1	;console command port
CSTAT	EQU	IOBASE+1	;console status port
CDATA	EQU	IOBASE+0	;console data port
CIMASK	EQU	00000010B	;keyboard ready mask
COMASK	EQU	00000001B	;output ready mask
;
LCOM	EQU	IOBASE+3	;list command port
LSTAT	EQU	IOBASE+3	;list status port
LDATA	EQU	IOBASE+2	;list data port
LMASK	EQU	10000001B	;list output ready mask
;
	ELSE
;
;*** note ***
;define your own routine if not using the tarbell cpu/io
;
CCOM	EQU	0		;init port for console
CSTAT	EQU	0		;console status port
CDATA	EQU	1		;console data port
CIMASK	EQU	00000010B	;input mask value
COMASK	EQU	00000100B	;output mask value
LCOM	EQU	13H		;init port for lister
LSTAT	EQU	13H		;list status port
LDATA	EQU	12H		;list data port
LMASK	EQU	10000001B	;output mask value
	ENDIF
;
;-------------------------------------------------------------
;timer equates
;
	IF	TIMER AND TARBELL
TCH0	EQU	IOBASE+4	;timer chan 0
TCH1	EQU	IOBASE+5	;timer chan 1
TCH2	EQU	IOBASE+6	;timer chan 2 (use for intrps)
TCMND	EQU	IOBASE+7	;command port
IMASK	EQU	IOBASE+8	;interrupt mask port
;
CNTR0	EQU	00000000B	;counter 0
CNTR1	EQU	01000000B	;counter 1
CNTR2	EQU	10000000B	;counter 2
RLWORD	EQU	00110000B	;read/load lsb,msb
RLHBYT	EQU	00100000B	;read/load msb only
RLLBYT	EQU	00010000B	;read/load lsb only
CNTRLT	EQU	00000000B	;counter latching operation
BINARY	EQU	00000000B	;binary count select
BCD	EQU	00000001B	;bcd counter select
MODE0	EQU	00000000B	;interrupt on terminal count
MODE1	EQU	00000010B	;programmable one-shot
MODE2	EQU	00000100B	;rate generator
MODE3	EQU	00000110B	;square wave generator
MODE4	EQU	00001000B	;software triggered strobe
MODE5	EQU	00001010B	;hardware triggered strobe
	ENDIF
;
BIAS	EQU	((MSIZE-20)*1024)+PGS*256
CCP	EQU	3400H+BIAS	;base of ccp
BDOS	EQU	CCP+806H	;base of bdos
BIOS	EQU	CCP+1600H	;base of bios
NSECTS	EQU	17		;warm start sector count
IOBYTE	EQU	3		;intel i/o byte
;
DMAP	EQU	0E0H		;dma port base address
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
;
	IF	MINWIN AND MAC
	HDCONST			;define hard disk constants
	ELSE
NHARD	EQU	0		;NO HARD DISK
	ENDIF
;
NDISK	EQU	NFLOP+NHARD	;NUMBER OF LOGICAL DISKS
;
DMAR	EQU	01000000B	;dma read command
DMAW	EQU	10000000B	;dma write command
FREAD	EQU	10000000B	;floppy read command
FWRIT	EQU	10100000B	;floppy write command
FWRITD	EQU	10100100B	;floppy write with 15ms delay
RDID	EQU	11000000B	;read id command
B128	EQU	128		;sgl / dbl den. sect size
B512	EQU	512		;deblock sector size
;
;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
;
;bdos constants on entry to write
;
WRDIR	EQU	1		;write to directory
WRUAL	EQU	2		;write to unallocated
;
;auto drive default search routine
;
	IF	CRSDRV		;if using cross drive select
	ORG	CCP+0D7H
	JMP	AUTSEL
	ENDIF
;
;patch cpm 2.2 with overlay for deblock operation
;
	ORG	CCP+12D2H
	NOP
	NOP
	LXI	H,0
;
;start of bios
;
	ORG	BIOS		;origin of this program
;
;	jump vector for individual subroutines
;
DMAENT:	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
	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
;
;	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
;
	IF	MINWIN AND MAC
	HDHEDER			;define additional h/d header
	ENDIF
;
;	sector translate vector floppy disk
;
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 single density double sided disk
;
DPBLK4:	DW	26
	DB	4
	DB	15
	DB	0
	DW	242
	DW	95
	DB	11000000B
	DB	0
	DW	24
	DW	2
;
;defines a double density / double side 51 x 128
;
DPBLK5:	DW	51
	DB	5
	DB	31
	DB	0
	DW	237
	DW	95
	DB	11000000B
	DB	0
	DW	24
	DW	2
;
;defines a double density / double side 512 x 16
;
DPBLK6:	DW	64
	DB	5
	DB	31
	DB	0
	DW	303
	DW	169
	DB	11000000B
	DB	0
	DW	42
	DW	2
;
	IF	MINWIN AND MAC
	HDPBLK
	ENDIF
;
;	end of fixed tables
;
;auto cross drive select routine
;
	IF	CRSDRV		;if using auto cross drive
AUTSEL:	PUSH	D
	CALL	CCP+0CBH
	POP	D
	RNZ
	MVI	A,1
	STAX	D
	JMP	CCP+0CBH
	ENDIF
;
;print message until zero terminator
;
PMSG:	MOV	A,M		;get a byte
	INX	H		;bump pointer
	ORA	A		;zero?
	RZ			;yes
	MOV	C,A		;no, print it
	CALL	CONOUT		; on crt
	JMPR	PMSG		;loop till done.
;
;warm boot
;
WBOOT:	LXI	SP,80H		;set boot stack
	LDA	HSTWRT		;check for pending dir write
	ORA	A		;is buffer active
	CNZ	WRITEHST	;write it out if yes
;
	IF	LRU AND MAC
WBTFLS:	LDA	LRUWRT		;did we do any writes?
	ORA	A
	JRZ	NOFLSH
	CALL	CHKFLH
	JMPR	WBTFLS
;
NOFLSH:	LXI	H,SECLST
	LXI	D,SECLST+1
	LXI	B,NHITSC-1
	MVI	M,0FFH		;force drives to re-log
	LDIR
	ENDIF

	LXI	H,0		;drive a select code
	SHLD	TRKTAB		;clear track table
	SHLD	TRKTAB+2
	SHLD	DSKLOG		;clear log in vector
	MVI	H,10H		;drive b select code
	SHLD	DSKLOG+2
	MVI	H,20H		;drive c select code
	SHLD	DSKLOG+4
	MVI	H,30H		;drive d select code
	SHLD	DSKLOG+6
	XRA	A
	STA	HSTACT		;host buffer inactive
	STA	UNACNT		;clear unallocated count

	IF	MINWIN AND MAC
	STA	LOGREG		;RESET CURRENTLY LOGGED DRIVES
	LXI	H,BADMAP	;GET POINTER TO BADMAP
	SHLD	BADPTR		;INITIALIZE
	ENDIF

	IF	LSTPAG		;if using list pageing
	STA	LFCNT		;clear linefeed counter
	ENDIF

	IF	MINWIN AND MAC
	MWBOOT			;WARM BOOT FROM WINCHESTER

	ELSE

	MVI	C,0
	CALL	SELDSK		;select drive 0	
	XRA	A
	OUT	WAIT
	OUT	DDATA		;seek to track 0
	MVI	A,STPRAT+HLAB
	CALL	EXECC1
	MVI	C,2		;starting sector
	LXI	H,CCP		;cpm base
	MVI	B,NSECTS	;sectors to load

RDBLK:	MOV	A,C
	OUT	SECTP		;set sector

	IF	DMACNTL		;if using dma control
	PUSH	B		;save sectors to load
	LXI	B,FREAD SHL 8 OR WCT0
	LXI	D,DMAR SHL 8 OR (B128-1)
	CALL	DMARW		;use dma routine
	LXI	B,128		;adjust dma address
	DAD	B		;+128 bytes
	POP	B		;restore sectors to load

	ELSE

	CALL	READLS
	ENDIF

	INR	C		;next sector
	DJNZ	RDBLK
	ENDIF

GOCPM:	MVI	A,0C3H		;init jmp loc in page 0
	STA	0
	LXI	H,WBOOTE	;get warmboot entry
	SHLD	1		;save it
	STA	5		;save jump inst.
	LXI	H,BDOS		;point to bdos entry
	SHLD	6		;save it
	LXI	H,80H		;set dma address
	SHLD	DMAADR
	IF	CONINT
	STA	10H		;SETUP CONSOLE INTERRUPT VECTOR
	LXI	H,VECTOR2	;INTERRUPT SERVICE ROUTINE
	SHLD	11H		;RESTART 2 INTERRUPT
	MVI	A,0FBH		;UNMASK VECTOR 2
	OUT	IOBASE+9	;INTERRUPT MASK PORT
	EI			;ENABLE INTERRUPTS
	ELSE
	MVI	A,0FFH		;MASK EM ALL
	OUT	IOBASE+9	;INTERRUPT MASK PORT
	ENDIF
	LDA	4		;restore user # and disk #
	MOV	C,A		;drive in c
	JMP	CCP		;jump to ccp
;
;io test and vector routines
;
LISTST:	CALL	LISSTAT		;check printer status
	MVI	A,0		;return status activity
	RNZ
	CMA
	RET
;
;list status port check
;
LISSTAT:IN	LSTAT		;check printer status
	ANI	LMASK		;mask
	XRI	LMASK		; values
	RET
;
; write a character on listing device.
;
LIST:
	IF	LSTNUL  		;if nulls or paging,
	MVI	A,0DH			;if it's a cr,
	CMP	C			;then hop out to
	JRZ	LINUL			;null routine.
	ENDIF
;
	IF	LSTPAG			;if paging
	MVI	A,0AH			;get a linefeed
	CMP	C			;does it match?
	JRZ	LINUL3
	MOV	A,C
	CPI	0CH
	RZ
	ENDIF
;
LTBSY:	CALL	LISSTAT			;check printer status
	JRNZ	LTBSY			;loop if busy
	MOV	A,C			;get cpm character
	OUT	LDATA			;send to printer
	RET
;
	IF	LSTNUL			;if list nulls
LINUL:	PUSH	B			;save b&c.
	MVI	B,(LNULL AND 0FFH)+1	;get null count
LINUL1:	CALL	LTBSY			;print (cr first).
	MVI	C,0			;get null char.
	DJNZ	LINUL1			;do next null.
	JMPR	LINUL2			;exit the routine.
	ENDIF
;
	IF	LSTPAG			;if list dev. paging,
LINUL3:	PUSH	B			;save b,c pair
	LDA	LFCNT			;get line-feed count.
	INR	A			;increment it.
	STA	LFCNT			;save it back.
	CPI	LINCNT-(LINCNT/11)	;end of page?
	MVI	B,1			;set up for 1 lf.
	JRNZ	NOTEOP			;hop if not end.
	XRA	A			;set lf count = 0.
	STA	LFCNT
	MVI	B,(LINCNT/11)+1		;between pages.
NOTEOP:	MVI	C,0AH			;get line-feed code.
LSTPA1:	CALL	LTBSY			;print line-feed.
	DJNZ	LSTPA1			;do next line feed?
	ENDIF
;
	IF	LSTNUL OR LSTPAG	;if nulls or paging,
LINUL2:	POP	B			;restore b&c.
	MOV	A,C			;restore a.
	RET				;return from list.
	ENDIF
;
;punch and reader not supported
;
READER:	MVI	A,1AH		;not supported return code
PUNCH:	RET
;
;check console status
;
CONST:
	IF	CONINT
	LDA	CHRCT		;CHECK CHARACTER COUNT
	ORA	A
	RZ			;RETURN IF BUFFER EMPTY
	MVI	A,0FFH
	RET
	ELSE
	IN	CSTAT		;console status
	ANI	CIMASK		;check data ready
	RZ
	MVI	A,0FFH
	RET
	ENDIF
;
;read a character from the console
;
CONIN:
	IF	LRU AND MAC
	LDA	LRUWRT		;check if flush needed
	ORA	A		;0 = NO
	CNZ	CHKFLH		;else, check which buffer to flush
	ENDIF
;
	IF	CONINT
	CALL	CONST		;GHECK FOR CHARACTER IN BUFFER
	JRZ	CONIN		;LOOP UNTIL WE GET ONE
	LXI	H,CHRCT
	DCR	M		;DECREMENT CHARACTER COUNT
	LHLD	INPPTR		;GET POINTER TO CHARACTER
	MOV	C,M		;PUT CHARACTER IN C
	CALL	BMPPTR		;BUMP POINTER TO NEXT CHARACTER
	SHLD	INPPTR		;STORE POINTER FOR NEXT TIME
	MOV	A,C		;PUT CHARACTER IN A
	ANI	7FH		;CLEAR PARITY BIT
	RET			;RETURN TO CP/M
BMPPTR:
	LXI	D,BUFEND	;GET END OF BUFFER
	INX	H		;INCREMENT BUFFER POINTER
	MOV	A,L
	CMP	E		;CHECK LOW BYTE FOR OVERFLOW
	RNZ			;RETURN IF NO OVERFLOW
	MOV	A,H
	CMP	D		;CHECK HIGH BYTE FOR OVERFLOW
	RNZ			;RETURN IF NO OVERFLOW
	LXI	H,BUFFER	;RESET BUFFER POINTER
	RET
VECTOR2:
	SSPD	CPMSTK		;SAVE STACK POINTER
	LXI	SP,INTSTK	;USE INTERRUPT STACK
	PUSH	PSW		;SERVICE CONSOLE INTERRUPT
	PUSH	B
	PUSH	D
	PUSH	H
	LXI	H,CHRCT		;GET THE CHARACTER COUNT
	MOV	A,M
	CPI	BUFEND-BUFFER	;CHECK FOR OVERFLOW
	JRZ	FULL
	INR	M		;BUMP THE POINTER
	LHLD	INTPTR		;GET INPUT POINTER
	IN	CDATA		;GET CONSOLE DATA
	MOV	M,A		;STORE THE CHARACTER
	CALL	BMPPTR		;INCREMENT THE BUFFER
	SHLD	INTPTR		;SAVE THE NEW POINTER
RETINT:	POP	H
	POP	D		;RESTORE THE REGISTERS
	POP	B
	POP	PSW
	LSPD	CPMSTK		;RESTORE STACK POINTER
	EI			;ENABLE INTERRUPTS LAST
	RET
FULL:	MVI	C,7		;RING THE BELL IF FULL
	CALL	CONOUT
	IN	CDATA		;CLEAR THE INTERRUPT
	JMPR	RETINT		;RETURN FROM INTERRUPT
BUFFER:	DS	10		;10 CHARACTER BUFFER
BUFEND:	EQU	$		;END OF BUFFER
INPPTR:	DW	BUFFER		;POINTER TO NEXT BUFFER OUTPUT
INTPTR:	DW	BUFFER		;POINTER TO NEXT BUFFER INPUT
CHRCT:	DB	0		;CHARACTER COUNT
CPMSTK:	DW	0		;CPM STACK SAVE
	DS	10		;10 BYTES
INTSTK	DB	0		;LOCAL STACK
	ELSE
	CALL	CONST		;check keyboard
	JRZ	CONIN		;loop till ready
	IN	CDATA		;get the key
	ANI	7FH		;strip parity bit
	RET
	ENDIF
;
	IF	LRU AND MAC
CHKFLH:	LBCD	FLSHNX		;get relative buffer number
	MVI	A,NHITSC	;check for end of list
	CMP	C		;is it?
	JRC	FLSHDN		;exit if yes
	LXIX	DRVLST		;point ix reg at drive list
	DADX	B		;point to correct drive byte
	BITX	7,0		;was a write done on this drive?
	JRZ	FLSH2		;if not, bump relative buf # to next.
	RESX	7,0		;else, reset the write flag bit
	LDA	DISKHF		;GET DISKHF
	PUSH	PSW		;SAVE CURRENT FORMAT
	MVI	A,3		;SET DISKHF TO DEBLOCKED
	STA	DISKHF		;MODE 3
	LDA	NXTLRU		;get the current o.s. index number
	PUSH	PSW		;save on the stack
	MOV	A,C		;get flush index number
	STA	NXTLRU		;save for flush routine
	CALL	NDFLSH		;flush this track,sector to drive
	POP	PSW		;recover o.s. index number
	STA	NXTLRU		;save for any pending o.s.read/writes
	POP	PSW		;RESTORE DISKHF
	STA	DISKHF		;
FLSH2:	LHLD	FLSHNX		;load the flush index number
	INX	H		;bump to next one
	SHLD	FLSHNX		;save for next flush check
	RET
;
FLSHDN:	LXI	H,0		;clear h,l
	SHLD	FLSHNX		;and reset flush index counter
	MOV	A,L		;get a zero
	STA	LRUWRT		;clear the lru write flag
	RET
	ENDIF
;
;character out to console
;
CONOUT:	IN	CSTAT		;check output status
	ANI	COMASK		;mask
	JRZ	CONOUT		;loop till not busy
	MOV	A,C		;get cpm character
	OUT	CDATA		;send to console
	RET
;
; translate the sector given by bc using the
; translate table given by de
;
SECTRA:	MOV	L,C		;double density part
	MOV	H,B
;
	MOV	A,E		;CHECK FOR NO XLAT
	ORA	D
	RZ			;RETURN IF NO XLAT
;
	LDA	DISKHF
	CPI	3		;sector 0-63 for format 3
	RZ
;
	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 - set up for home of drive to track 0
;
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		;system disk select save
	LDA	OLDDSK		;get last drive accessed
	CMP	C		;are they the same drive
	MVI	A,0		;0=same disk as last
	JRZ	SAMDSK		;jump if they are the same
	INR	A		;1=not same disk as last
SAMDSK:	STA	CHNGFL		;save the change flag
	MOV	A,C		;else, not the same, so update
	STA	OLDDSK		; for next select change
;
	IF	MINWIN AND MAC
	HSEL
	ENDIF
;
	ADD	A		;double for indexing
	MOV	C,A		;put into reg c
	MVI	B,0		;clear reg b
	LXI	H,DSKLOG	;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		;save disk pointer address
	OUT	WAIT		;at single density
	CALL	RDYDRV		;check for drive ready
	LDA	DISKHS
	MOV	B,A		;GET SELECTED DISK #
	MVI	A,STPRAT+HLAB	;restore drive
	CALL	EXECC1		;restore to track 0
	MVI	A,1
	OUT	SECTP		;address sector 1
	LXI	H,DIRBF
	CALL	READLS		;read a logical sector
	LDA	DIRBF+7EH
;
	CPI	0DEH		;double density 16 secs of 512?
	JRZ	DD64
;
	CPI	0DCH		;512 x 16 doub sided?
	JRZ	DD642
;
	CPI	0DFH		;128 x 51 doub sided?
	JRZ	DD52
;
	CPI	0DDH		;double density 51 secs?
	JRZ	DD51
;
	CPI	0E7H		;doub sided single density
	JRZ	SD2
;
	LXI	H,1*256 + 0	;format flag and density mask
	LXI	D,DPBLK1	;single density parm block
	JMPR	PUT
;
SD2:	LXI	H,1*256 + 40H
	LXI	D,DPBLK4
	JMPR	PUT
;
DD642:	LXI	H,3*256 + 48H
	LXI	D,DPBLK6
	JMPR	PUT
;
DD52:	LXI	H,2*256 + 48H
	LXI	D,DPBLK5
	JMPR	PUT
;
DD51:	LXI	H,2*256 + 8	;as above for 51 secs ddens
	LXI	D,DPBLK2
	JMPR	PUT
;
DD64:	LXI	H,3*256 + 8	; 64 logical secs (16 by 512)
	LXI	D,DPBLK3
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
	LDA	SEKDSK		;fix up dpbase tables
	IF	MINWIN AND MAC
	SUI	NHARD		;REMOVE BIAS
	ENDIF
	ADD	A
	ADD	A
	ADD	A		;GET INDEX FOR DRIVE
	ADD	A	
	ADI	10		;INDEX TO DPBLK ADDRESS
	MOV	C,A
	MVI	B,0
	LXI	H,DPBASE	; reference table for this disk
	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
;
;setsec - set sector from reg b,c
;
SETSEC:	SBCD	SEKSEC		;save the sector
	RET
;
;setdma - set dma address from bc
;
SETDMA:	SBCD	DMAADR		;bc to dmaadr
	RET
;
;read - read a sector
;
READ:	EQU	$
;
	IF	MINWIN AND MAC
	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
	LHLD	DMAADR
;
	IF	NOT DMACNTL
	CALL	RDTEST		;track 0,1 test
	ENDIF
;
	JMP	READLS		;read logical sector
;
;write - write a sector from dmaadr
;
WRITE:	EQU	$
;
	IF	MINWIN AND MAC
	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
WRIT1:	LDA	SEKSEC
	MOV	D,A
	LDA	DISKHS
	MOV	B,A
	LDA	SEKTRK
	CALL	SEEKLS
	LHLD	DMAADR
;
	IF	NOT DMACNTL
	CALL	WRTEST
	ENDIF
;
	JMP	WRITEL		;write logical sector
;
	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
	JMPR	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			; carry set if < track 2
	IN	SECTP		;if sector zero, also phantom
	ORA	A
	JRZ	TSTC
	IN	TRACK		;track 1 limit is sector 51
	DCR	A
	JRZ	TRK1
	IN	SECTP
	CPI	27		;track 0 limit is sector 26
	CMC
	RET
TRK1:	IN	SECTP
	CPI	52
TSTC:	CMC
	RET
	ENDIF
;
; -read logical sector-
;hl is dma address
;
READLS:	CALL	RDYDRV		;check for drive ready
;
	IF	DMACNTL		;if using dma
	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
	POP	H
	ANI	9DH		;check for errors during read
	RZ			;return if no read errors
	LDA	RTCNT		;get retry count
	DCR	A		;decrement it
	JRNZ	RRTRY		;retry again
	LXI	H,RDERR		;retry exausted, print message
COMEXT:	CALL	PMSG
	MVI	A,1		;error return code
	STA	ERFLAG		;set the error flag
	ORA	A		;set flags
	RET

	ELSE

	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
	LXI	H,RDERR
	CALL	PMSG		;read error message
	MVI	A,1
	ORA	A		;set status
	JMPR	REXIT1
;
REXIT:	XCHG			;put next address in hl
REXIT2:	POP	D		;throw away orig. dma
REXIT1:	POP	D		;restore de
	POP	B		;restore bc
	RET
	ENDIF
;
;-write logical sector-
;hl is dma address
;
WRITEL:	CALL	RDYDRV		;check for drive ready
;
	IF	DMACNTL		;if using dma
	MVI	A,ERCNT		;retry count
WRTRY:	STA	RTCNT		;save it
	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
	POP	H
	ANI	0FDH		;check for errors during read
	RZ			;return if no write errors
	LDA	RTCNT		;get retry count
	DCR	A		;decrement it
	JRNZ	WRTRY		;retry again
	LXI	H,WERR		;retry exausted, print message
	JMPR	COMEXT		;use common exit routine

	ELSE

	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
	LXI	H,WERR		;write error message
	CALL	PMSG
	MVI	A,1
	ORA	A		;set status
	JMPR	REXIT1		;clean up routine
	ENDIF
;
;check to see if selected drive is ready
;routine is also good for slim line drives.
;
RDYDRV:	CALL	STATCK		;check for drive ready
	RZ			;return if ready
	MVI	B,50		;50 * 16ms = 800 ms
RDYDV1:	CALL	DLYLOP
	CALL	STATCK		;check drive status
	RZ			;return if ready
	DJNZ	RDYDV1		;loop for 800 ms for slim line drives
	EXX
	LDA	SEKDSK
	ADI	'A'		;ascii adjust
	STA	DRV		;save for message
	LXI	H,READY		;point to ready message
	CALL	PMSG		;print it
	CALL	CONIN		;WAIT FOR CHARACTER
	EXX
	JMP	RDYDRV		;WAIT FOR READY
;
;selected drive is ready now
;
STATCK:	IN	DSTAT		;get drive status
	BIT	7,A		;check ready bit
	RET
;
DLYLOP:	MVI	A,16		;16 ms count value
DLYLP1:	MVI	C,210		;1 ms time constant
WEXITL:	NOP
	DCR	C
	JNZ	WEXITL
	DCR	A
	JNZ	DLYLP1
	RET
;
;logical sector seek
;
;a=track, b=hardware and density for fdc
;d=sector (for future read)
;
SEEKLS:	PUSH	PSW		;save track
	MVI	A,10		;retrys
	STA	SEEKRTY		;save it
	PUSH	B
	CALL	TRKINDX		;compute table index.
;
;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
	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
	JMPR	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
	CALL	RDYDRV		;check for drive ready
	POP	B
	CALL	DLYSEL		;delay on selects
	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
;
	MVI	A,14H+STPRAT+HLAB
EXECC1:	OUT	DCOM		;output disk command

	IF	DMACNTL
	CALL	SLOOP		;use common polling
	ELSE
	IN	WAIT		;use wait port
	IN	DSTAT		;check disk status
	ENDIF

	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
	LXI	H,BIOS-6	;buffer area for read id

	IF	DMACNTL
	LXI	B,RDID SHL 8 OR WCT0
	LXI	D,04006H	;dma read, length
	CALL	DMARW		;read the id marks

	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
	JMPR	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.
	JMPR	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
;
	LXI	H,SEEKER	;print error
	CALL	PMSG		;print it
SEEKR:	CALL	CONIN		;get a key
	CPI	03
	JRNZ	SEEKR		;try again
	JMP	WBOOT
;
;delay on new drive select
;
DLYSEL:	LDA	CHNGFL		;get drive change flag
	ORA	A		;was there a change to new drv?
	RZ			;return if not, else
	XRA	A		;reset the drv chng flag
	STA	CHNGFL
;
;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 into data register
	MVI	A,10H + STPRAT	;get seek command
	OUT	DCOM		;send seek command
;
	IF	DMACNTL
	JMP	SLOOP		;wait till done
	ELSE
	IN	WAIT
	IN	DSTAT
	RET
	ENDIF
;
SAVTRK:	CALL	TRKINDX		;get correct index value
	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
	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
	RAR			;shift
	RAR			;right
	RAR			;four
	RAR			;times

	IF	DUAL
	ANI	OEH		;strip lsb
	ELSE
	ANI	0FH		;strip junk bits
	ENDIF

	RET
;
;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
;
;general purpose wait routine
;
SLOOP:	IN	DMACHK		;check bit 7
	RLC			;and rotate it left
	JRC	SLOOP		;and loop if carry
	XRA	A		;get a zero
	OUT	CMND		;clear dma chip
	IN	DSTAT		;get status of disk
	RET			; and return it to caller
;
;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
;
;data tables
;
RDERR:	DB	0DH,0AH,'Read',0
WERR:	DB	0DH,0AH,'Write',0
SEEKER:	DB	0DH,0AH,'Seek',0
READY:	DB	0DH,0AH,7,'Drive '
DRV:	DB	' : not ready , type any key when ready',0
;
;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
	CPI	WRUAL		;write unallocated?
	JRNZ	CHKUNA		;check for unalloc
;
;write to unallocated, set parameters
;
	IF	MINWIN AND MAC
	ALLCHK1	BLKSET
	ENDIF
;
	LDA	DISKHS		;check for double sided
	BIT	6,A		;if set, doing double sided
	MVI	A,BLKSIZ/128	;block size = 2048
	JRZ	BLKSET		;jump if single sided
	ADD	A		;block size = 4096
BLKSET:	STA	UNACNT		;save the alloc size
	LXI	H,SEKDSK	;source for move
	LXI	D,UNADSK	;destination for move
	LXI	B,5		;number of bytes to move
	LDIR
;
;check for write to unallocated sector
;
CHKUNA:	LDA	UNACNT		;any }nalloc 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 flags
	LDED	UNATRK
	LHLD	SEKTRK
	DSBB	D		;sektrk = unatrk?
	JRNZ	ALLOC		;skip if not
;
;tracks are the same
;
	ORA	A		;clear flags
	LDED	SEKSEC		;same sector?
	LHLD	UNASEC
	DSBB	D		;seksec = unasec?
	JRNZ	ALLOC		;skip if not
;
;match, move to next sector for future ref
;
	IF	MINWIN AND MAC
	HALLOC	SEKDSK,NOHRD
	ENDIF
;
	LXI	B,CPMSPT	;get the number of cpm sectors
NOHRD:	LHLD	UNASEC		;get the sector
	INX	H		;increment it
	SHLD	UNASEC		;save it
	ORA	A		;clear flags
	DSBB	B		;have we exceeded the # of sects?
	JRNZ	NOOVF		;jump if not
	LXI	H,0		;else, max +1 has been reached
	SHLD	UNASEC		;reset the unalloc sectors
;
;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
;WATCH OUT FOR SEKSEC > 1020
;
RWOPER:	XRA	A		;zero to accum
	STA	ERFLAG		;no errors (yet)
	LHLD	SEKSEC
	MOV	A,H		;rotate h,l right 2 places
	RAR			;move lsb of h into carry
	MOV	H,A		;BACK TO H
	MOV	A,L
	RAR
	MOV	L,A		;BACK TO L
	MOV	A,H		;GET H AGAIN
	RAR
	MOV	A,L		;GET L AGAIN
	RAR
	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 flags
	LDED	HSTTRK
	LHLD	SEKTRK
	DSBB	D		;sektrk = hsttrk?
	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,SEKHST	;source for move
	LXI	D,HSTSEC	;destination for move
	LXI	B,4		;count for move
	LDIR			;block move the data
	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		;reg b = loop count
MTCH1:	DAD	H		;shift h,l by b counts
	DJNZ	MTCH1
;
;hl has relative host buffer address
;
	IF	LRU AND MAC	;if using l.r.u. algorithm
	SHLD	RELHST		;save the relative record number
	LDA	READOP		;are we doing a write operation
	ORA	A		;if yes, read in the proper sector
	CZ	READHST		;so we can save the data in correct sect.
	SSPD	OLDSTK		;save cp/m stack
	LXI	SP,NEWSTK	;set a local stack
	CALL	GETSEC		;swap in the sector we need 1st
	ELSE			;if not using l.r.u.
	LXI	D,HSTBUF
	DAD	D		;hl = host address
	ENDIF
;
;
	LDED	DMAADR		;get/put cp/m data
	LDA	READOP		;which way?
	ORA	A
	JRNZ	RWMOVE		;skip if read
;
;write operation, mark and switch direction
;
	MVI	A,1
	STA	HSTWRT		;hstwrt = 1
	XCHG			;source/dest swap
;
	IF	LRU AND MAC
	STA	LRUWRT		;set the lru write flag
EXTWRT:	LDA	NXTLRU		;get index number
	MOV	C,A		;ready for index
	MVI	B,0
	LXIX	DRVLST		;point ix reg at drive list
	DADX	B
	SETX	7,0		;set bit 7 on to show write op.
	ENDIF
;
;c initially 128, de is source, hl is dest
;
RWMOVE:	LXI	B,128		;count
;
;
BUFF1:	LDIR			;fast z-80 block move
;
;
	IF	LRU AND MAC
	CALL	RSTBNK		;restore bdos page
	LSPD	OLDSTK		;recover cp/m stack
	ENDIF
;
;data has been moved to/from host buffer
;
	LDA	WRTYPE		;write type
	CPI	WRDIR		;to directory?
	LDA	ERFLAG		;in case of errors
	RNZ			;no further processing
;
;clear host buffer for directory write
;
	ORA	A		;errors?
	RNZ			;skip if so
	XRA	A		;0 to accum
	STA	HSTWRT		;buffer written
	CALL	WRITEHST
	LDA	ERFLAG
	RET
;
;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	MINWIN AND MAC
	JC	WRTHST		;write hardisk
	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		;get the selected disk parms
;
	IF	MINWIN AND MAC
	JC	RDHST		;read hardisk
	ENDIF
;
	CALL	READLS		;read the selected disk
;
XITIO:	MVI	A,0		;0 = no error
	STA	ERFLAG		;save it
	RZ			;return if no errors
	CMA			;else,, we have an error
	STA	ERFLAG		;save the error flag byte
	RET

SETIO:	LXI	H,DSKLOG	;point to disk log table
	LDA	HSTDSK		;get selected disk
;
	IF	MINWIN AND MAC
	RWCON
	ENDIF
;
	ADD	A		;double for index
	MOV	E,A		;move into reg e
	MVI	D,0		;clear reg d
	DAD	D		;add to h,l
	INX	H		;bump to disk select code
	MOV	B,M		;disk sel stuff in b
	LDA	HSTSEC		;get the sector to do
	INR	A		;sector on disk is 1-16
	MOV	D,A		;save in reg d for seek
	LDA	HSTTRK		;get the track to do
	CALL	SEEKLS		;seek to track in reg a
	LXI	H,HSTBUF	;point to host buffer
;
	IF	MINWIN AND MAC
	XRA	A		;CLEAR CARRY TO SHOW NOT HARD
	ENDIF
;
	RET			;return to caller
	ENDIF
;
;this routine replaces the readhst: routine
;in the deblocked bios.
;
;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
RDHST1:	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	7		;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
	JMP	RDHST1		;update hit list and ret sector data
;
;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
	ENDIF
	IF	LRU AND MINWIN
	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
	CPI	4		;TEST FOR HARD DISK
	JNC	WRTHARD		;GO WRITE HARD DISK
	ENDIF
	IF	LRU
	CALL	SPLIO		;use special i/o for l.r.u.
	LXI	H,0		;write from ext bnk 1, based at 0
	CALL	WRTEXT		;common read/write extension
	MVI	A,1		;set extended dma latch
	OUT	DMACHK
	CALL	WRITEL		;use logical write routine
	XRA	A		;reset extended dma latch to bnk 0
	OUT	DMACHK
	POP	B		;recover index value
	RET
	ENDIF
	IF	LRU AND MINWIN
WRTHARD:
	SBCD	LRUINDX		;SAVE LRU INDEX
	STA	HRDDRV		;SAVE DRIVE #
	LXI	H,0		;SETUP TO FIND BUFFER TO WRITE
	CALL	WRTEXT		;GET ADDRESS
	CALL	WRTHST		;WRITE 512 BYTES FROM HL TO HARD DISK
	POP	B
	RET
	ENDIF
;
	IF	LRU
CHKLIM:	PUSH	H		;save hl
	LHLD	DMAADR		;check for xfer into tpa > xfer buff.
	LXI	D,(BDOS AND 0F000H)-127
	ORA	A		;clear flags
	DSBB	D		;subtract the two
	POP	H		;restore hl
	JRNC	BELOSB		;jump if >=
	LXI	D,(BDOS AND 0F000H)	;compute the start of buffer
	SDED	PAGOVR		;save it
	JMPR	SHFTB
;
BELOSB:	LXI	D,(BDOS AND 0F000H) - 2000H ;move buffer down 8k bytes
	SDED	PAGOVR
SHFTB:	MOV	A,D		;get page number
	RRC
	RRC
	RRC
	RRC
	ADI	MEMMAG
	STA	MMPAGN		;save the memory management page addr.
	RET
;
GETBNK:	CALL	CHKLIM		;which buffer do we need?
	LDA	MMPAGN		;get page address
	MOV	C,A		;place into reg c
	MOV	A,H		;get buffer page address
	ANI	0F0H		;strip to ext page number
	RRC			;shift
	RRC			;right
	RRC			;4
	RRC			;places
	ADI	BNKNUM		;add in extended bank address
	CMA			;flip for m/m chips
	OUTP	A		;swap out main page with sector page
	RET
;
RSTBNK:	LDA	MMPAGN		;get last bank number used
	MOV	C,A		;place into reg c
	ANI	0FH		;strip off extended page nibble
	CMA			;flip for m/m chips
	OUTP	A		;restore main page back
	RET
	ENDIF
;
SPLIO:	IF	LRU AND NOT MINWIN
	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
	ENDIF
	IF	LRU
	ADD	A		;double it
	LXI	H,DSKLOG	;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:	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?
	ENDIF
;
;this subroutine is used to read a sector of data
;into an extended bank of memory.
;
BNKRED:	IF	LRU AND MINWIN
	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
	CPI	4		;TEST FOR HARD DISK
	JNC	RDHARD		;GO READ HARD DISK
	ENDIF
	IF	LRU
	CALL	SPLIO		;seek to correct track sector
	LXI	H,0		;read data into bnk 1 based at 0
	CALL	WRTEXT		;compute index into read sector loc.
	MVI	A,1		;write using extended dma latch
	OUT	DMACHK
	CALL	READLS		;read in the new sector into memory
	XRA	A		;restore bank 0 
	OUT	DMACHK
	RET
	ENDIF
	IF	LRU AND MINWIN
RDHARD:
	SBCD	LRUINDX		;SAVE LRU INDEX
	STA	HRDDRV		;SAVE DRIVE #
	LXI	H,0		;SETUP TO FIND BUFFER TO READ
	CALL	WRTEXT		;GET ADDRESS
	JMP	RDHST		;GO READ HARD DISK
	ENDIF
;
	IF	LRU
GETSEC:	LXI	H,0		;hl = relative buffer start address
	CALL	WRTEXT		;compute sector position
	CALL	GETBNK		;swap bdos 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
	LDED	PAGOVR		;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
;
DSKLOG:	DW	0000H		;disk 0 log flag/den
	DW	1000H		;disk 1 "
	DW	2000H		;disk 2 "
	DW	3000H		;disk 3 "
;
	IF	MINWIN AND MAC
	HARDISK
	ENDIF
;
	IF	MINWIN AND MAC
;
HSTSEC:	DS	1		;host sector number
HSTDSK:	DS	1		;host disk number
HSTTRK:	DS	2		;host track number
;
	ALLCHK			;alloc & check for hard disk
;
	ENDIF
;
;storage area for l.r.u. function
;
	IF	LRU AND MAC
NXTLRU:	DS	1		;save area for next l.r.u.
;
;l.r.u. tables
;
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.
	DS	10		;local stack for l.r.u. use
NEWSTK:	DS	1
OLDSTK:	DS	2		;cpm stack save
RELHST:	DS	2		;relative host buffer record number
PAGOVR:	DS	2		;relative page to use as overlay
MMPAGN:	DS	1		;m/m page number
LRUWRT:	DS	1		;write flag for lru use
FLSHNX:	DS	2		;flush index counter
	ENDIF
;
;the following area is claimed as the
;host buffer after system is running
;
HSTBUF	EQU	$
;
;hide system init in this area. we only
;use this stuff once
;
; NOTE: IF YOU ARE USING THE PGS OPTION AND YOU WISH
; THE TRUE SIZE TO DISPLAY AT BOOT THEN YOU MUST USE MAC
; OR INCLUDE A DB STATEMENT BELOW.
;
SIGNON:	DB	0DH,0AH,'Tarbell Electronics '
	DB	MSIZE/10+'0',MSIZE MOD 10+'0'
	IF	MAC
	IF	PGS = 1
	DB	'.25'
	ENDIF
	ENDIF
	IF	MAC
	IF	PGS = 2
	DB	'.5'
	ENDIF
	ENDIF
	IF	MAC
	IF	PGS = 3
	DB	'.75'
	ENDIF
	ENDIF
	DB	'K CP/M 2.2 version.'
	DB	0DH,0AH,'Dated 03-23-83'
	DB	0DH,0AH,'Deblocked Bios'
;
	IF	LRU AND MAC
	DB	0DH,0AH,' With L.R.U. Sector cache.'
	ENDIF
;
	IF	CONINT
	DB	0DH,0AH
	ENDIF
	IF	LRU AND CONINT
	DB	'and '
	ENDIF
	IF	CONINT
	DB	'Buffered Console Input'
	ENDIF
;
	IF	MW12 AND MAC
	DB	0DH,0AH,'12 Megabyte winchester disk.'
	ENDIF
;
	IF	MW19 AND MAC
	DB	0DH,0AH,'19 Megabyte winchester disk.'
	ENDIF
;
	IF	MW20 AND MAC
	DB	0DH,0AH,'20 Megabyte winchester disk.'
	ENDIF
;
	IF	MW26 AND MAC
	DB	0DH,0AH,'26 Megabyte winchester disk.'
	ENDIF
;
	IF	MW33 AND MAC
	DB	0DH,0AH,'33 Megabyte winchester disk.'
	ENDIF
;
	DB	0
;
;boot - cold start cp/m load
;initialize crt and printer ports
;
;8251 init table
;
INITT:	DB	0AAH,040H,0CEH,037H
INITE:	DS	0
;
BOOT:	IF	TARBELL
	MVI	A,0B4H		;INITIALIZE TIMER
	OUT	IOBASE+7	;SETUP COUNT MODE
	MVI	A,1		;COUNT OF 1 TO DISABLE
	OUT	IOBASE+6
	MVI	A,0		;MSB OF COUNT
	OUT	IOBASE+6
	IN	IOBASE+8	;CLEAR INTERRUPT LATCH
	ENDIF
	LXI	H,INITT		;point to init table
	MVI	B,INITE-INITT	;length
BLOOP:	MOV	A,M		;get a byte
	INX	H		;bump pointer
	OUT	CCOM		;init console port
	OUT	LCOM		;init printer port
	DJNZ	BLOOP		;loop till done
;
	XRA	A		;clear a
	MOV	L,A		;clear l
	MOV	H,A		;clear h
	SHLD	IOBYTE		;clear i/o byte and disk num.
	LXI	H,BEGDAT	;clear scratch area
	LXI	D,BEGDAT+1	;block transfer dest.
	LXI	B,DMAADR-BEGDAT+1	;count
	MOV	M,A		;set first loc. = 0
	LDIR			;use block move to clear

	IF	LRU AND MAC
	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 03h
	MVI	B,NHITSC
	MVI	A,03H
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,TRKLST
	SHLD	10H
	LXI	H,SECLST
	SHLD	12H
	LXI	H,DRVLST
	SHLD	14H
	MVI	A,NHITSC
	STA	16H
	ENDIF

	LXI	H,SIGNON	;signon message
	CALL	PMSG		;print it

	IF	DMACNTL
	LXI	H,WBOOT		;point to warm boot routine
	SHLD	DMAENT+1	;modify 'jmp  boot' entry point
	ENDIF
;
	JMP	GOCPM		;set up low memory
;
; PAD DOWN TO END OF HOST BUFFER
	DS	HSTSIZ-($-HSTBUF)
;
;ram storage area
;
;
BEGDAT	EQU	$		;beginning of data area
;
DISKHF:	DS	1		;disk hardware format (1, 2, 3)
DISKHS:	DS	1		;disk/density setting = hardware
TRKTAB:	DS	4		;track table for 4 drives
;
DIRBF:	DS	128		;scratch directory area
;
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
;
;
SEKHST:	DS	1		;seek shr secshf
SEKDSK:	DS	1		;seek disk number
SEKTRK:	DS	2		;seek track number
SEKSEC:	DS	2		;seek sector number
;
UNADSK:	DS	1		;last unalloc disk
UNATRK:	DS	2		;last unalloc track
UNASEC:	DS	2		;last unalloc sector
;
	IF	NOT MINWIN
HSTSEC:	DS	1		;host sector number
HSTDSK:	DS	1		;host disk number
HSTTRK:	DS	2		;host track number
	ENDIF
;
HSTACT:	DS	1		;host active flag
HSTWRT:	DS	1		;host written flag
UNACNT:	DS	1		;unalloc rec cnt
;
	IF	LSTPAG
LFCNT:	DS	1		;linefeed counter for paging
	ENDIF
;
RTCNT:	DS	1		;disk retry counter
CHNGFL:	DS	1		;drv change flag
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
OLDDSK:	DS	1		;last drive select save
DMAADR:	DS	2		;dma address
;
	IF	MINWIN
	DB	0		;force eof on hex file
	ENDIF
;
	END
