;*****************************************************
;*                                                   *
;*      SECTOR DEBLOCKING ALGORITHMS FOR CP/M 2.0    *
;*                                                   *
;*****************************************************
;	REVISIONS:
;
; 1.0 -	
;	ORIGINAL
;
; 1.1 -	3 MAR 87   GRH
;	CP/M 2.X deblocking based on CP/M 3.x Data structures (dynamic).
;
;****************************************************************************


;=====================================================
;*                                                   *
;*         CP/M TO HOST DISK CONSTANTS               *
;*                                                   *
;=====================================================
;BLKSIZ		;CP/M ALLOCATION BLOCK SIZE (IN BYTES, 1K,2K,4K,8K,16K)
;	CALCULATE FROM: 0400H SHL (CUR_DPB.DPBBSH - 3)
;
;HSTSIZ		;PHYSICAL DISK SECTOR SIZE
;	CALCULATE FROM: 0080H SHL CUR_DPB.DPBPSH 
;
;HSTSPT	EQU	64		;PHYSICAL DISK SECTORS/TRK
;	CALCULATE FROM: 
;
;HSTBLK	EQU	HSTSIZ/128	;CP/M SECTORS IN SECTOR BUFFER
;	CALCULATE FROM: CUR_DPB.DPBPHM + 1
;
;CPMSPT	EQU	HSTBLK * HSTSPT	;CP/M SECTORS/TRACK
;	CALCULATE FROM: CUR_DPB.DPBSPT
;
;SECMSK	EQU	HSTBLK-1	;SECTOR MASK
;	CALCULATE FROM: CUR_DPB.DPBPHM
;
;SECSHF	EQU	@X		;LOG2(HSTBLK)
;	CALCULATE FROM: CUR_DPB.DPBPSH


;=====================================================
;*                                                   *
;*        BDOS CONSTANTS ON ENTRY TO WRITE           *
;*                                                   *
;=====================================================
WRALL	EQU	0		;WRITE TO ALLOCATED
WRDIR	EQU	1		;WRITE TO DIRECTORY
WRUAL	EQU	2		;WRITE TO UNALLOCATED


;*****************************************************
;*                                                   *
;*	THE BDOS ENTRY POINTS GIVEN BELOW SHOW THE   *
;*      CODE WHICH IS RELEVANT TO DEBLOCKING ONLY.   *
;*                                                   *
;*****************************************************


;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;   ENTER HERE ON SYSTEM BOOT TO INITIALIZE
;
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
BOOT:
WBOOT:
;
;   ASSUME NO DATA IN BUFFER
;
	XOR	A,A
	LD	(HSTACT),A
;
;   CLEAR UNALLOCATED SECTOR COUNT
;
	LD	(UNACNT),A
	RET


;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;   SELECT DISK
;	ENTRY-	C= DISK #
;
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SELDSK:
;
;   SAVE DISK # AS REQUESTED DISK
;
	LD	A,C
	LD	(SEKDSK),A
;
;   LOOK UP DISK PTR IN TABLE
;
	LD	HL,DRV_TBL	;BASE
	ADD	A,A		;WORD PTRS
	ADD	A,L
	LD	L,A
	LD	A,0
	ADC	A,H
	LD	H,A
	LD	A,(HL)		;FETCH PTR
	INC	HL
	LD	H,(HL)
	LD	L,A
	LD	(CUR_DPH),HL
;
;   FETCH DPB PTR
;
	PUSH	IX		;SAVE IX 1ST
	PUSH	HL
	POP	IX
;
	LD	L,(IX+DPHDPBO)
	LD	H,(IX+DPHDPBO + 1)
	LD	(CUR_DPB),HL
;
;   FETCH CURRENT BUFFER CONTROL BLOCK PTR
;
	LD	L,(IX+ DPHDTABO)
	LD	H,(IX+ DPHDTABO + 1)
	LD	(CUR_BCB),HL
;
;   RESTORE & RETURN DPH PTR
;
	POP	IX
;
	LD	HL,(CUR_DPH)
	RET


;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;   HOME THE SELECTED DISK
;
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
HOME:
;
;   IF PENDING WRITE (BUFFER DIRTY) THEN IGNORE
;
	LD	A,(HSTWRT)
	OR	A,A
	RET	NZ
;
;   ELSE PURGE BUFFER
;
	LD	(HSTACT),A	;A= 0 AT THIS POINT
	RET


;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;   SET TRACK GIVEN BY REGISTERS BC
;
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SETTRK:
;
;   STORE TRACK #
;
	LD	(SEKTRK),BC
	RET


;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;   SET SECTOR GIVEN BY REGISTER BC 
;
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SETSEC:
	LD	(SEKSEC),BC		;SECTOR TO SEEK
	RET


;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;   SET DMA ADDRESS GIVEN BY BC
;
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SETDMA:
	LD	(DMAADR),BC
;
;   ASSUME BANK 0 FOR NOW
;
	XOR	A,A
	LD	(DMABNK),A
	RET


;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;   TRANSLATE SECTOR NUMBER BC
;	ENTRY- BC= LOGICAL SECTOR
;	EXIT - HL= PHYSICAL SECTOR
;
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SECTRAN:
	LD	H,B
	LD	L,C
	INC	HL
	RET



;*****************************************************
;*                                                   *
;*	THE READ ENTRY POINT TAKES THE PLACE OF      *
;*	THE PREVIOUS BIOS DEFINTION FOR READ.        *
;*                                                   *
;*   READ THE SELECTED CP/M SECTOR		     *
;*****************************************************
READ:
;
;   SET UP DATA TABLE PTR
;
	PUSH	IX
	LD	IX,(CUR_DPB)
;
;   READ_OPERATION_FLAG = TRUE (1)
;
	LD	A,1
	LD	(READOP),A
;
;   PRE-READ_OF_DATA_FLAG = TRUE
;
	LD	(RSFLAG),A
;
;   TREAT AS UNALLOCATED BLOCK
;
	LD	A,WRUAL
	LD	(WRTYPE),A
;
	JP	RWOPER		;TO PERFORM THE READ


;****************************************************************************
;
;	THE WRITE ENTRY POINT TAKES THE PLACE OF THE PREVIOUS BIOS DEFINTION
; FOR WRITE.
;	ENTRY- C= WRITE TYPE:
;			0: WRITE TO ALLOCATED BLOCK (UPDATE)
;			1: WRITE TO DIRECTORY BLOCK (ALLWAYS WRITE)
;			2: WRITE TO UNALLOCATED BLOCK (NO NEED TO PRE-READ)
;
;****************************************************************************
WRITE:
;
;   SET PTR TO DISK DATA
;
	PUSH	IX
	LD	IX,(CUR_DPB)
;
;   READ_OP_FLAG = FALSE
;
	XOR	A,A
	LD	(READOP),A
;
;   SAVE WRITE TYPE
;
	LD	A,C
	LD	(WRTYPE),A
;
;   IF 1ST WRITE TO UNALLOCATED (NEW, UNUSED) BLOCK THEN SET PARAMETERS
;
	CP	A,WRUAL
	JP	NZ,CHKUNA
;
;   COUNT = NUMBER_OF_SECTORS_IN_BLOCK
;
	LD	A,(IX+ DPBBLM)	;CUR_DPB.DPBBLM + 1 ::= (BLKSIZ/128)
	INC	A
	LD	(UNACNT),A
;
;   SET DISK TO SEEK
;
	LD	A,(SEKDSK)
	LD	(UNADSK),A
;
;   SET TRACK TO SEEK
;
	LD	HL,(SEKTRK)
	LD	(UNATRK),HL
;
;   SET SECTOR TO SEEK
;
	LD	HL,(SEKSEC)
	LD	(UNASEC),HL
;
;   IF NO UNALLOCATED SECTORS REMAIN THEN PREREAD
;
CHKUNA:	LD	A,(UNACNT)
	OR	A,A
	JP	Z,ALLOC
;
;   ELSE MORE UNALLOCATED RECORDS REMAIN, COUNT--
;
	DEC	A
	LD	(UNACNT),A
;
;   IF REQUESTED SECTOR != UNALLOCATED SECTOR THEN PURGE
;
	LD	A,(SEKDSK)	;SAME DISK?
	LD	HL,UNADSK
	CP	A,(HL)
	JP	NZ,ALLOC
;
	LD	HL,(UNATRK)	;SAME TRACK?
	LD	DE,(SECTRK)
	SBC	HL,DE
	JP	NZ,ALLOC
;
	LD	HL,(SEKSEC)
	LD	DE,(UNASEC)
	SBC	HL,DE
	JP	NZ,ALLOC
;
;   MATCH, MOVE TO NEXT SECTOR FOR FUTURE REF
;
	INC	HL		;UNASEC = UNASEC+1
	LD	(UNASEC),HL
;
;   IF PAST LAST SECTOR ON TRACK THEN USE 1ST SECTOR OF NEXT TRACK
;
	LD	E,(IX+ DPBSPT)
	LD	D,(IX+ DPBSPT +1)
	INC	DE
	SBC	HL,DE
	JP	C,NOOVF
;
	LD	HL,1		;SECTOR = 1
	LD	(UNASEC),HL
;
	LD	HL,(UNATRK)	;TRACK++
	INC	HL
	LD	(UNATRK),HL
;
NOOVF:
;
;   MATCH FOUND, MARK AS UNNECESSARY READ
;
	XOR	A,A		;PREREAD FLAG = FALSE
	LD	(RSFLAG),A
	JP	RWOPER
;
;
;   NOT AN UNALLOCATED RECORD, REQUIRES PRE-READ
;
ALLOC:
	XOR	A,A		;COUNT = 0
	LD	(UNACNT),A
;
	INC	A		;PREREAD FLAG = TRUE
	LD	(RSFLAG),A
;
;
;
;   COMMON CODE FOR READ AND WRITE FOLLOWS
;
RWOPER:
;
;   ASSUME NO ERRORS
;
	XOR	A,A
	LD	(ERFLAG),A
;
;   COMPUTE BUFFER SECTOR
;
	LD	BC,(SEKSEC)
	DEC	BC			;CONVERT PHYSICAL SECTOR TO LOGICAL
;
	LD	A,(IX+ DPBPSH)		;USE PHYSICAL SHIFT FACTOR (CP/M 3.X)
	OR	A,A			;IF ALREADY 0 THEN SECTOR SIZE IS 128
	JR	Z,NOSECSHF
;
SECSHFLP:
	SRL	B			;ELSE SHIFT OVER TO PHYSICAL SECTOR
	RR	C
	DEC	A
	JR	NZ,SECSHFLP
;
NOSECSHF:
	INC	BC		;SET BACK TO PHYSICAL SECTOR
	LD	(SEKHST),BC	;BUFFER SECTOR TO SEEK
;
;   IF BUFFER EMPTY THEN READ THE PHYSICAL SECTOR
;
	LD	HL,HSTACT
	LD	A,(HL)
;
	LD	(HL),1		;BUFFER FULL IN ANY CASE
;
	OR	A,A
	JP	Z,FILHST
;
;   HOST BUFFER ACTIVE, SAME AS SEEK BUFFER?
;
	LD	A,(SEKDSK)
	LD	HL,HSTDSK	;SAME DISK?
	CP	A,(HL)
	JP	NZ,NOMATCH
;
	LD	HL,(HSTTRK)	;SAME TRACK?
	LD	DE,(SEKTRK)
	SBC	HL,DE
	JP	NZ,NOMATCH
;
	LD	DE,(SEKHST)	;SAME SECTOR?
	LD	HL,(HSTSEC)
	SBC	HL,DE
	JP	Z,MATCH		;SKIP IF MATCH
;
NOMATCH:
;
;   IF CURRENT BUFFER DIRTY THEN WRITE IT OUT BEFORE READING NEW ONE
;
	LD	A,(HSTWRT)
	OR	A,A
	CALL	NZ,WRITEHST	;CLEAR HOST BUFF
;
FILHST:
;
;   READ THE SECTOR BUFFER
;
	LD	A,(SEKDSK)	;BUFFER SECTOR = PHYSICAL SECTOR
	LD	(HSTDSK),A
;
	LD	HL,(SEKTRK)
	LD	(HSTTRK),HL
;
	LD	HL,(SEKHST)
	LD	(HSTSEC),HL
;
;   IF REQUIRED TO READ THEN READ
;
	LD	A,(RSFLAG)		;NEED TO READ?
	OR	A,A
	CALL	NZ,READHST		;YES, IF 1
;
;   BUFFER = CLEAN
;
	XOR	A,A
	LD	(HSTWRT),A
;
MATCH:
;
;   COPY DATA TO OR FROM BUFFER
;
	LD	HL,(SEKSEC)	;CALCULATE INDEX INTO BUFFER
	DEC	HL		;CONVERT TO LOGICAL SECTOR (0..N-1)
	LD	A,L
;
	AND	A,(IX+ DPBPHM)	;USE PHYSICAL RECORD MASK DATA (CP/M 3.X)
;
	RRA			;BITS <7..1> -> BITS <14..8>
	LD	H,A
;
	LD	A,0		;BIT 0 -> BIT 7
	RRA
	LD	L,A
;
;   HL HAS RELATIVE HOST BUFFER ADDRESS
;
	LD	DE,HSTBUF
	ADD	HL,DE		;HL = HOST ADDRESS
;
	LD	DE,(DMAADR)	;GET/PUT CP/M DATA
	LD	BC,128		;LENGTH OF MOVE
;
	LD	A,(READOP)	;WHICH WAY?
	OR	A,A
	JP	NZ,RWMOVE	;SKIP IF READ
;
;   WRITE OPERATION, MARK AND SWITCH DIRECTION
;
	LD	A,1		;BUFFER = DIRTY
	LD	(HSTWRT),A
;
	EX	DE,HL		;SOURCE/DEST SWAP
;
RWMOVE:
;
;   BC INITIALLY 128, DE IS SOURCE, HL IS DEST
;
	LDIR
;
;   DATA HAS BEEN MOVED TO/FROM HOST BUFFER, IF NOT DIRECTORY THEN DELAY WRITE
;
	LD	A,(WRTYPE)	;IF NOT DIRECTORY THEN DELAY WRITE
	CP	A,WRDIR
	LD	A,(ERFLAG)	;RETURN ANY ERRORS ANYWAY
	JR	NZ,RW_RET
;
;   IF ERROR THEN ABORT
;
	OR	A,A
	RET	NZ
;
;   NO ERROR/DIRECTORY WRITE
;
	XOR	A,A		;BUFFER = CLEAN
	LD	(HSTWRT),A
;
	CALL	WRITEHST	;WRITE TO DISK
;
	LD	A,(ERFLAG)	;RETURN ANY ERRORS
;
;   DONE, RESTORE & RETURN
;
RW_RET:
	POP	IX
;
	RET


;****************************************************************************
;
;	WRITEHST PERFORMS THE PHYSICAL WRITE FROM HSTBUF TO THE HOST DISK.
;	ENTRY-	(HSTDSK)= DISK # TO WRITE TO
;		(HSTTRK)= TRACK # TO WRITE TO
;		(HSTSEC)= SECTOR # TO WRITE TO
;	EXIT -	(ERFLAG)= 0: OK, /0: ERROR
;
;****************************************************************************
WRITEHST:
;
	RET


;****************************************************************************
;
;	READHST PERFORMS THE PHYSICAL READ FROM THE HOST DISK INTO HSTBUF.
;	ENTRY-	(HSTDSK)= DISK # TO READ FROM
;		(HSTTRK)= TRACK # TO READ FROM
;		(HSTSEC)= SECTOR # TO READ FROM
;	EXIT -	(ERFLAG)= 0: OK, /0: ERROR
;
;****************************************************************************
READHST:
;
	RET


;****************************************************************************
;
;	UNITIALIZED RAM DATA AREAS
;
;****************************************************************************
;
;   THE FOLLOWING ITEMS ARE SET BY THE BIOS FUNCTIONS
;
SEKDSK:	DS	1		;LOGICAL DRIVE
SEKTRK:	DS	2		;LOGICAL TRACK NUMBER
SEKSEC:	DS	2		;LOGICAL SECTOR NUMBER
;
;   THE FOLLOWING ARE SET BY THE BUFFER READ/WRITE
;
HSTDSK:	DS	1		;BUFFER DISK NUMBER
HSTTRK:	DS	2		;BUFFER TRACK NUMBER
HSTSEC:	DS	2		;BUFFER SECTOR NUMBER
;
;
SEKHST:	DS	2		;PHYSICAL SECTOR TO XFER
;
HSTACT:	DS	1		;0: BUFFER FLUSHED, /0: DATA IN BUFFER
HSTWRT:	DS	1		;0: BUFFER CLEAN, /0: BUFFER DIRTY (MODIFIED)
;
;   THE FOLLOWING USED BY THE UNALLOCATED BLOCK ALGORITHMS
;
UNACNT:	DS	1		;# SECTORS REMAINING IN BLOCK (CLUSTER)
UNADSK:	DS	1		;LAST UNALLOC DISK
UNATRK:	DS	2		;LAST UNALLOC TRACK
UNASEC:	DS	2		;LAST UNALLOC SECTOR
;
;
ERFLAG:	DS	1		;ERROR REPORTING 0: OK, /0: ERROR
RSFLAG:	DS	1		;0: NO PREREAD REQ'D, /0: PREREAD REQ'D
READOP:	DS	1		;0: WRITE OPERATION, 1: READ OPERATION
WRTYPE:	DS	1		;WRITE OPERATION TYPE FROM BDOS:
;				 0: WRITE TO ALLOCATED (USED) BLOCK (PREREAD)
;				 1: WRITE TO DIRECTORY (PREREAD & WRITE)
;				 2: WRITE TO UNALLOCATED (UNUSED) BLOCK (NO
;					PREREAD REQ'D)
DMAADR:	DS	2		;LAST DMA ADDRESS
DMABNK	DS	1		;LAST DMA BANK
;
HSTBUF:	DS	1024		;HOST BUFFER
