;**************************************************************
;		MICRO RESOURCES CP/M RAM DISK ADDON MODULE
;**************************************************************
;
;
;	THIS PROGRAM IS A SMALL TRANSIENT PROGRAM BASED BIOS SUBSTITURE
;	THAT ALLOWS FILE TRANSFER UTILITY BETWEEN THE NORMAL CP/M SYSTEM
;	DISKS AND AN MEMORY RESIDENT "RAM DISK". THIS TRANSIENT PROGRAM IS
;	SETUP FOR ANY VERSION 2.2 CP/M SYSTEM.
;
;	THIS PROGRAM PRESENTS A SMALL DISK DEMONSTRATION VERSION THAT USES
;	20 K BYTES OF THE HOST SYSTEM TPA TO DEMONSTRATE THE "RAM DISK"
;	ADDON MODULE TECHNIQUE. THE DEMO VERSION USES 1K BYTE ALLOCATION
;	GROUPS (BLOCKS) AND ALLOWS FOR A TOTAL OF 32 DIRECTORY ENTRIES AS
;	DEFINED BY THE DISKDEF MACRO CALLS. PLEASE NOTE THAT WHILE THIS MAY
;	NOT APPEAR TO BE A VERY PRACTICAL IMPLEMENTATION OF A RAM DISK
;	IT DOES DEMONSTRATE THE FRIVER TECHNIQUES. A GREATLY EXPANDED VERSION
;	WOULD USE ADDITIONAL BANK SWITCHED RAM BOARDS TO STORE THE DISK DATA
;	SUCH THAT THE DISK STORAGE AREA COULD EASILY BE EXPANDED TO AS MUCH
;	AS A MEGABYTE OF MORE.
;
;	THE SUPPORTED RAM DISK FORMAT IS AS FOLLOWS:
;
;		10 TRACKS MAPPED INTO RAM
;		8 PHYSICAL SECTORS FER TRACK
;		256 BYTES/PER SECTOR
;		SECTORS ACCESSED FROM RAM THROUGH THE STANDARD BEBLOCKING
;			TECHNIQUES. RAM RESIDENT "HOST SECTORS" MAPPED TO
;			256 BYTES IN SIZE SO EXPANSION OF THIS PROGRAM TO
;			BANK SWITCHED MEMORY CAN BE MADE EASILY.
;
;	PROGRAM ACCESS TO THE RAM DRIVE IS DONE IN 256 BYTE SECTORS
;	THAT ARE DEBLOCKED WITHIN A BUFFER CONTAINED INSIDE OF THIS SOFTWARE
;	PACKAGE. THE INITIAL LOADING OF THIS SOFTWARE SWAPS OUT THE NORMAL
;	CP/M DISK I/O ENTERY POINTS TO THE BIOS WITH A NEW SET OF ENTRY POINTS
;	TO THIS MODULE. THIS MODULE THEN CHECKS ALL SELECT DISK ACCESSES FOR
;	LOGICAL UNIT P: AND WILL STEER I/O REQUESTS FOR THIS DRIVE THROUGH
;	DRIVERS CONTAINED WITHIN THIS PROGRAM. NOTE THAT THIS PROGRAM STILL
;	DEPENDS UPON THE HOST CP/M SYSTEM BDOS AS THE FILE INTERFACE MEDIUM.
;
;	OPERATION OF THE PROGRAM IS DONE TO MOVE THE MODULE UP TO A WORKSPACE
;	BELOW THE MEMORY RESIDENT CCP. THE WARM BOOT VECTOR AT THE SYSTEM
;	WARM BOOT ENTRY POINT IS SWAPPED TO A NEW ENTRY POINT WITHIN THE
;	RELOCATED I/O	MODULE. THE NEW WARMBOOT FUNCTION SIMPLY RE-ENTERS
;	THE ALREADY PRESENT CCP FOR FURTHER OPERATOR COMMAND PROCESSING.
;	THE BDOS ENTRY VECTOR IS ALSO MODIFIED TO PERMIT THE DYNAMIC
;	MODIFICATION OF THE USER PROGRAM AREA SIZE SUCH THAT THE CCP AND
;	THE RELOCATED I/O MODULE DO NOT GET OVERLAYED BY THE TRANSIENT
;	PROGRAM AREA'S BUFFER SPACES. THE UTILITY, WHEN LOADED PERFORMS
;	A CHECK TO VERIFY WHETHER A RELOCATED MODULE IS ALREADY PRESENT
;	IN MEMORY. THE ALREADY PRESENT CHECK IS DONE VIA A SPECIALLY DEFINED
;	BDOS CALL THAT REQUESTS THE OPENING OF A FILE WITH THE SPECIALLY
;	DEFINED NAME SEQUENCE OF "A,,,,,,,,.,,," AS THE FILE NAME WHARE (A)
;	IS A REQUEST NUMBER FOR PRESENCE CHECKING. AS THIS CHARACTER SEQUENCE
;	IS AN ILLEGAL FILE NAME SEQUENCE, THE CHECK PROGRAM WILL TRAP THE NAME
;	AND RETURN A ZERO BYTE IN THE (A) REGISTER IF THE MODULE IS PRESENT.
;	IF THE ADDRESS BYTE IN THE FIRST BYTE OF THE FCB IS NOT RECOGNIZED,
;	THEN THE MODULE PASSES THE OPEN FILE REQUEST ON TO THE NEXT HIGHER
;	LEVEL BDOS CALL. IN ANY CASE THE NON PRESENCE OF A FILE BY THE NAME
;	OF "A,,,,,,,.,,," IS VIRTUALLY ASSURED TO CAUSE THE BDOS TO RETURN
;	A NOT FOUND "0FFH" ERROR CODE IN THE (A) REGISTER. THIS WOULD INDICATE
;	THE ABSENSE OF THE MODULE BEING CHECKED FOR.
;
;
;	THIS RAM DISK DRIVER PACKAGE
;	PROGRAM IS COPYRIGHT PROTECTED BY:
;
;	COPYRIGHT (C) 1982
;
;	MICRO RESOURCES
;	2468 HANSEN COURT
;	SIMI VALLEY, CALIFORNIA 93065
;	(805) 527-7922
;
;*****************************************************************************
;
;
;
;DEFINE TRUE AND FALSE ASSEMBLY PARAMETERS
;
TRUE	EQU	-1		;DEFINE TRUE
FALSE	EQU	NOT TRUE	;DEFINE FALSE
;
;
;DEFINE RAMSISK MODULE SELECT ADDRESS AS SPECIAL VALUE
;
MODADDR	EQU	08AH		;ADDRESS OF THIS MODULE
;
;
;CP/M BDOS INTERFACE EQUATES
;
	ASEG
BOOT	EQU	0000H		;FIXED BOOT ADDRESS
BDOS	EQU	0005H		;FIXED BDOS ADDRESS
DEFFCB	EQU	005CH		;DEFAULT FCB LOCATION
DEFBUF	EQU	0080H		;DEFAULT SYSTEM BUFFER
RESET	EQU	13		;RESET DISK SYSTEM
OPEN	EQU	15		;OPEN FILE
STDMA	EQU	26		;SET DMA ADDRESS
;
;
;ASCII CHARACTER DEFINITIONS
;
LF	EQU	00AH		;ASCII LINE FEED CHARACTER
CR	EQU	00DH		;ASCII	CARRIAGE RETURN CHARAVTER
;
;
;SECTOR DEBLOCKING ALGORITHMS FOR CP/M 2.2
;
	MACLIB	DISKDEF
;
SMASK	MACRO	HBLK		;UTILITY MACRO TO COMPUTE SECTOR MASK
;
;	COMPUTE LOG2(HBLK), RETURN @X AS RESULT
;	(2 ** @X = HBLK ON RETURN)
;
@Y	SET	HBLK
@X	SET	0
;
;	COUNT RIGHT SHIFTS OF @Y UNTIL = 1
;
	REPT	8
	IF	@Y = 1
	EXITM
	ENDIF
;
;	@Y IS NOT 1, SHIFT RIGHT ONE POSITION
;
@Y	SET	@Y SHR 1
@X	SET	@X + 1
	ENDM
	ENDM
;
;
;BDOS CONSTANTS ON ENTRY TO "WRITE"
;
WRALL	EQU	0		;WRITE TO ALLOCATED BLOCK
WRDIR	EQU	1		;WRITE TO DIRECTORY
WRUAL	EQU	2		;WRITE TO UNALLOCATED BLOCK
;
;
;
;CP/M 2.2 TO HOST DISK CONSTANTS
;
BLKSIZ	EQU	2048		;CP/M ALLOCATION SIZE
HSTSIZ	EQU	256		;HOST DISK SECTOR SIZE
;
HDSPT	EQU	32		;HOST HARD DISK 256 BYTE SECTORS/TRACK
HSTBLK	EQU	HSTSIZ/128	;CP/M SECTS/HOST BUFF
;
SECMSK	EQU	HSTBLK-1	;SECTOR MASK
	SMASK	HSTBLK		;COMPUTE SECTOR MASK
SECSHF	EQU	@X		;LOG2(HSTBLK)
;
;SECTOR SKEW INTERLACE FACTOR
;
SKEW	EQU	00		;SECTOR SKEW FACTOR
;
SECSIZ	EQU	256		;NUMBER OF BYTES IN DISK RECORD
;
;
;****************************************************************************
;
;
	CSEG			;SET ORIGIN TO ZERO FOR RELOCATABLE
				;ASSEMBLY BY RMAC
;
;
;SETUP STORAGE FOR THE RAM DISK DRIVE DATA BUFFER BELOW THE RELOCATED
;ADDON MODULE.
;
RAMBUF	EQU	$-(10*8*SECSIZ)	;SIZE SET AT 10 TRACKS OF EIGHT 256
				;BYTE SECTORS PER TRACK
BUFSIZ	EQU	$-RAMBUF	;SIZE OF FUFFER FOR INIT CLEAR
;
;
;FIRST TIME START UP ENTRY POINT FOR THE RAM DISK AUTO RELOCATING
;I/O MODULE. ENTRY HERE ASSURES PRESENSE OF CP/M 2.2.
;
	JMP	CHKPRES		;GO CHECK IF A MODULE OF
				;SAME FUNCTION ADDRESS IS PRESENT
				;IN SYSTEM
;
;
;SUBSTITURE BDOS ENTRY POINT. EXECUTION ADDRESS IS PLACED HERE
;FROM LOCATION 6 & 7 BY THE START UP MODULE PROVIDED THIS
;MODULE IS DETERMINED TO NOT ALREADY PR
DEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEOEO;T"A,,,,,,,.,,,"
	LXI	D,CHKFCB	;POINT AT THE CHECK FCB
	CALL	BDOS		;CALL NORMAL BDOS ADDRESS
	ORA	A
	JNZ	NOT$PRES	;NON ZERO RETURN MOFULE IS NOT
				;..PRESENT
	LXI	D,PRESMSG	;POINT TO PRESENT MESSAGE
	MVI	C,9		;PRINT FUNCTION CODE
	CALL	BDOS		;PRINT ALREADY PRESENT MESSAGE
	RET			;SIMPLE RETURN TO THE CCP
;
CHKFCB:
	DB	0,MODADDR,',,,,,,,,,,',0,0,0,0
	DS	16
	DB	0
;
PRESMSG:
	DB	CR,LF,'Micro Resources Ram Disk Already Active','$'
;
;
;HERE IF THIS RELOCATED MODULE IS NOT PRESENT IN MEMORY
;
NOT$PRES:
	POP	H		;COMPUTE CCP RE-ENTRY POINT
	PUSH	H		; WITH STANDARD CPM 2.2
	LXI	D,075CH		;NEGATIVE OFFSET TO CCP ENTRY
;
; FOR USE WITH ZCPR CPM OR USE 0765H ABOVE
;
	LXI	D,0806H-003H	;LOAD OFFSET OF CCP TO BDOS
	LHLD	006H		;GET BDOS ENTRY POINT
;
;END OF ZCPR
;
	MOV	A,L
	SUB	E
	MOV	L,A
	MOV	A,H
	SBB	D
	MOV	H,A
	LDA	BDOS+2
	SUI	8
	MOV	H,A
	MVI	L,3
	SHLD	CCP$ENT		;SAVE THAT ENTRY ADDRESS
;
	LHLD	BDOS+1		;GET PREVIOUS BDOS ADDRESS
	SHLD	TO$BDOS+1	;SET TO LOCAL REFERENCE VECTOR
;
;
;COMPUTE THE NEW RAM TOP OF TPA TO SET IN A JUMP ONE PAGE BELOW
;FOR PLACEMENT OF BASE OF THE RAM DISK DRIVE FOR BDOS REFERENCE
;
	LXI	H,RAMBUF
	DCR	H		;ONE PAGE DOWN
	MVI	L,06H		;AT CP/M'S BDOS LOOK ALIKE
	SHLD	BDOS+1		;BASE+6
	LXI	D,BDOS$SCAN
	MVI	M,0C3H		;SET A JUMP AT TPA TOP
	INX	H
	MOV	M,E		;LOW BYTE OF ENTRY POINT
	INX	H
	MOV	M,D		;HIGH BYTE OF ENTRY POINT
;
;
;INITIALIZE ALL ITEMS FOR USE IN THIS I/O HANDLER
;
	MVI	B,ENDZ-STARTZ	;ZERO DATA AREA IN PARAMETER TABLE
	LXI	H,STARTZ
ZLP:
	MVI	M,00H		;PUT IN A ZERO PARM BYTE
	INX	H		;POINT TO NEXT BYTE TO BE ZEROED
	DCR	B		;CHECK BYTE COUNT TO SEE IF DONE
	JNZ	ZLP
;
;
;INITIALIZE THE RAM BUFFER TO LOOK LIKE FRESH FORMATTED DRIVE
;
	LXI	B,BUFSIZ	;RAM DRIVE SIZE
	LXI	H,RAMBUF	;DRIVE BASE ADDRESS
E5LP:
	MVI	M,0E5H		;STORE AN E5 BYTE
	INX	H		;BUMP POINTER
	DCX	B		;DEC BYTE COUNT
	MOV	A,B
	ORA	C
	JNZ	E5LP
;
	LXI	H,RAMSEL	;DISABLE DRIVE SELECT FOR RAM DISK
	MVI	M,00H
;
	CALL	MOVDN		;MOVE DOWN THE BIOS VECTOR TABLE
	LXI	H,BOOTENT	;SET MOVED DOWN TABLE TO LOCAL BOOT HANDLER
	SHLD	BWBOOT+1
;
	CALL	PRTMSG		;PRINT SIGNON MESSAGE
;
	DB	CR,LF,'Micro Resources RAM Disk Demonstration'
	DB	CR,LF,'Add-on Access Module Version 1.0 6/14/82'
	DB	CR,LF,'Copyright (C) 1982 Micro Resources'
	DB	CR,LF,0
;
;
;
;HAVE THIS UTILITY QUEUE BOTH BIOS AND THIS DRIVER TO THE SAME
;CP/M DATA BUFFER ADDRESS
;
	LXI	D,DEFBUF	;USE DEFAULT BUFFER
	MVI	C,STDMA		;SET DMA	CODE
	CALL	TO$BDOS
;
;
;RETURN TO CCP VIA THE OLD DEFINED REENTRY POINT
;
CCPGO:
	LXI	H,RAMBUF
	DCR	H		;ONE PAGE DOWN
	MVI	L,06H		;AT CP/M'S BDOS LOOK ALIKE
	SHLD	BDOS+1		;BASE+6
	LHLD	CCP$ENT		;GET THE CCP ENTRY POINT
	LDA	004H		;GET CURRENTLY LODDED DRIVE
	MOV	C,A
	PCHL
;
;
;NEW WARM BOOT ENTRY LOCATION THAT RESETS THE DISK SYSTEM
;AND TRANSFERS CONTROL BACK TO THE ALREADY PRESENT CCP
;
BOOTENT:
	JMP	CCPGO		;NO GO BACK TO THE CCP
;
;
;HERE FROM A BDOS ENTRY TO TRAP FILE OPEN I/O TO CHECK FOR
;MODULE PRESENT CHECK.
;
BDOS$SCAN:
	PUSH	D		;SAVE CALLERS PARAMETERS
	PUSH	B
	MOV	A,C		;GET FUNCTION CODE TO A
	CPI	OPEN		;SEE IF THIS IS AN OPEN FUNCTION
	JNZ	CHKFAIL
	INX	D		;POINT TO FCB CHECK BYTE
	LXI	H,10		;SET SCAN COUNTER TO FAKE FILE NAME END
	DAD	D
	MVI	B,10		;NUMBER OF "," TO CHECK FOR
SCAN$LOOP:
	MOV	A,M		;GET FILE NAME CHARACTER
	CPI	','
	JNZ	CHKFAIL		;PASS ON IF CHECK FAIL
	DCX	H		;DECREASE BUFFER POINTER
	DCR	B
	JNZ	SCAN$LOOP	;CHECKED ALL PASSIBLE CHARS YET
	MOV	A,M		;CHECK IF ADDRESS BYTE IS OURS
	CPI	MODADDR
	JNZ	CHKFAIL		;BALE OUT IF NOT
	XRA	A		;RETURN ZERO BYTE IF ALL CHECK VALID
	POP	B
	POP	D
	RET			;BACK TO PRESENT CHECKER
;
CHKFAIL:
	POP	B		;PROPER OPEN CHECK FAIL
	POP	D
	JMP	TO$BDOS		;OFF TO THE NORMAL BDOS ROUTINE
;
;
;
XFRTAB:
;
;SUBSTITURE BIOS VECTOR TABLE. THIS JUMP TABLE VECTORS ALL CP/M
;DISK I/O TO THIS TRANSIENT MODULE FIRST. TABLE IS PUT INTO THE
;BIOS VECTOR TABLE POSITION BY A CALL TO THE SUBROUTINE "MOVDN"
;
;
	JMP	BCBOOT		;TO NORMAL BIOS COLD BOOT ROUTINE
	JMP	BOOTENT		;TO LOCAL WARM BOOT HANDLER
	JMP	BCSTAT		;TO NORMAL BIOS CONSOLE STATUS CHECK
	JMP	BCIN		;TO NORMAL BIOS CONSOLE INPUT
	JMP	BCOUT		;TO NORMAL BIOS CONSOLE OUTPUT
	JMP	BLOUT		;TO NORMAL BIOS LPT OUTPUT
	JMP	BPUN		;TO NORMAL BIOS PUNCH OUTPUT
	JMP	BRDR		;TO NORMAL BIOS READER INPUT
	JMP	HOME		;MOVE DISK TO TRACK ZERO
	JMP	SELDSK		;SELECT DISK DRIVE
	JMP	SETTRK		;SEEK TO TRACK IN REG A
	JMP	SETSEC		;SET SECTOR NUMBER
	JMP	SETDMA		;SET DISK STARTING ADR
	JMP	READ		;READ SELECTED SECTOR
	JMP	WRITE		;WRITE SELECTED SECTOR
	JMP	BLSTST		;GO RIGHT TO NORMAL BIOS FOR THIS I/O
	JMP	SECTRAN		;SECTOR TRANSLATE
;
;
LOCTAB:
;
;LOCAL COPY OF THE ORIGINAL BIOS DISK I/O VECTOR TABLE
;INITIALIZED BY CALLING THE "MOVDN" SUBROUTINE.
;
BCBOOT:
	JMP	$-$		;TO BIOS COLD BOOT ROUTINE
BWBOOT:
	JMP	$-$		;TO BIOS WARM BOOT ROUTINE
BCSTAT:
	JMP	$-$		;TO BIOS CONSOLE STATUS CHECK
BCIN:
	JMP	$-$		;TO BIOS CONSOLE INPUT
BCOUT:
	JMP	$-$		;TO BIOS CONSOLE OUTPUT
BLOUT:
	JMP	$-$		;TO BIOS LPT OUTPUT
BPUN:
	JMP	$-$		;TO BIOS PUNCH OUTPUT
BRDR:
	JMP	$-$		;TO BIOS READER INPUT
BHOME:
	JMP	$-$		;TO BIOS HOME DISK ROUTINE
BSELDSK:
	JMP	$-$		;TO BIOS SELECT DISK ROUTINE
BSETTRK:
	JMP	$-$		;TO BIOS SET TRACK ROUTINE
BSETSEC:
	JMP	$-$		;TO BIOS SET SECTOR ROUTINE
BSETDMA:
	JMP	$-$		;TO BIOS SET DMA ROUTINE
BREAD:
	JMP	$-$		;TO BIOS SECTOR RAD ROUTINE
BWRITE:
	JMP	$-$		;TO BIOS SECTOR WRITE ROUTINE
BLSTST:
	JMP	$-$		;TO BIOS LIST STATUS ROUTINE
BSTRAN:
	JMP	$-$		;TO BIOS SECTOR TRANSLATE ROUTINE
;
;
;SUBROUTINE TO INTERCHANGE BIOS DISK I/O VECTOR TABLE ENTRIES WITH
;THOSE CONTAINED LOCALLY.
;
TABSIZ	EQU	17*3		;TABLE SIZE TO INITIALIZE WITH 17 JMP'S
;
;
MOVDN:
	LHLD	BOOT+1		;GET ORIGINAL WARM BOOT VECTOR POINTER
	DCX	H		;ADJUST TO BASE OF COLD BOOT VECTOR
	DCX	H
	DCX	H
	MVI	A,TABSIZ	;SET BYTE COUNT TO MOVE
	STA 	BYTCNT
	LXI	D,LOCTAB	;POINT TO LOCAL TABLE FILL FROM ABOVE
	LXI	B,XFRTAB	;POINT TO TABLE TO MOVE UP
MDLP:
	MOV	A,M		;GET A BIOS TABLE BYTE
	STAX	D		;PUT IN LOCAL COPY TABLE
	LDAX	B		;GET BYTE OF PATCH TABLE
	MOV	M,A		;PUT PATCH BYTE INTO BIOS POSITION
	INX	H		;MOVE UP TO NEXT BYTE
	INX	D
	INX	B
	LDA	BYTCNT		;SEE IF DONE YET
	DCR	A
	STA	BYTCNT
	JNZ	MDLP		;CONTINUE IF NOT DONE YET
	RET
;
BYTCNT:
	DB	0		;LOCAL MOVE BYTE COUNTER
;
;
;***************************************************************************
;
;PARAMETER TABLE FOR TPA REASIDEN RAM DRIVER
;
	DISKS	1		;ONE LOGICAL DRIVES SUPPORTED
	DISKDEF	0,1,16,,1024,20,32,0,0	;P: RAM DRIVE
;
SELDSK:
	MOV	A,C		;GET NEW UNIT NUMBER
	CPI	'D'-041H	;IS THIS OUR DRIVE?
	JZ	SDSK1		;IF SO THEN GIVE THEM A PARAMETER POINTER
;
	XRA	A		;IF NOT CLEAR THE ZOBEX DRIVE SELECT FLAG
	STA	RAMSEL
	JMP	BSELDSK		;IF NOT FOR US THEN LET BIOS HAVE SELECT
;
;
;HERE IF DRIVE SELECT WAS FOR THIS PIECE OF SOFTWARE
;
SDSK1:
	SUI	'D'-041H	;SET SEKDSK TO THE HEAD SELECT CODE FOR
	STA	SEKDSK		;..RAM DISK DRIVE
;
	PUSH	PSW
	MVI	A,0FFH		;SET THE RAM DRIVE SELECT FLAG
	STA	RAMSEL
	POP	PSW
;
	LXI	H,DPBASE	;PASS BACK DISK PARAMETER BASE
	XRA	A		;SET A REG. = 00
	RET			;RETURN FROM SELDSK
;
;
;DO DIGITAL RESEARCH BUFFER PURGE IF NEED BE AND BALE OUT
;NO RESTORE MEMORY IS RANDOM ACCESS
;
HOME:
	LDA	RAMSEL		;SEE IF RESTORE FOR US
	ORA	A
	JZ	BHOME		;NO MUST BE FOR BIOS DRIVE
;
	LDA	HSTWRT		;CHECK HOST ACTIVE WRITE FLAG
	ORA	A
	JNZ	HOMEIT
	STA	HSTACT
HOMEIT:
	RET
;
;
;SET TRACK NUMBER SPECIFIED BY B&C REGS.
;
SETTRK:
	LDA	RAMSEL		;SEE IF TRACK FOR US
	ORA	A
	JZ	BSETTRK		;TO PROM IF NOT LOCAL
;
	MOV	H,B
	MOV	L,C
	SHLD	SEKTRK		;TRACK TO EMULATE
	RET
;
;
;
;TRANSLATE THE SECTOR GIVEN BY B&C REGS.
;
;	NO TRANSLATE DONE AT THIS TIME. WE WILL NOT NEED TO TRANSLATE
;	RAM DISK SECTOR BECAUSE RAM HAS NO ROTATIONAL LATENCY
;
SECTRAN:
	LDA	RAMSEL		;SEE IF SECTRAN FOR US
	ORA	A
	JZ	BSTRAN		;TO BIOS IF NOT LOCAL
;
	MOV	H,B
	MOV	L,C
	RET			;RETURN FROM SECTRAN
;
;
;SET DISK SECTOR NUMBER
;
SETSEC:
	LDA	RAMSEL		;SEE IF SECTOR FOR US
	ORA	A
	JZ	BSETSEC		;TO PROM IF NOT LOCAL
;
	MOV	A,C		;GET SECTOR NUMBER
	STA	SEKSEC		;SECTOR TO EMULATE
	RET			;RETURN FROM SETSEC
;
;
;SET DISK DMA ADDRESS
;
SETDMA:
	PUSH	H
	MOV	H,B		;MOVE B&C TO H&L
	MOV	L,C
	SHLD	DMAADR		;PUT AT DMA ADR ADDRESS
	POP	H
	JMP	BSETDMA		;TELL BIOS DMA ADDRESS
;
;
;READ THE SELECTED CP/M 2.2 SECTOR
;
READ:
	LDA	RAMSEL		;SEE IF OPERATION FOR US
	ORA	A
	JZ	BREAD		;GO READ IN BIOS IF NOT FOR US LOCAL
;
	XRA	A		;CLEAR UNALLOCATED COUNT
	STA	UNACNT
	MVI	A,1
	STA	READOP		;READ OPERATION
	STA	RSFLAG		;MUST READ DATA
	MVI	A,WRUAL
	STA	WRTYPE		;TREAT AS UNALLOCCATED
	JMP	RWOPER		;TO PERFORM THE READ
;
;
;WRITE THE SELECTED CP/M 2.2 SECTOR
;
WRITE:
	LDA	RAMSEL		;IS THIS WRITE FOR HERE
	ORA	A
	JZ	BWRITE		;TO BIAS IF NOT SO
;
	XRA	A		;0 TO A REG.
	STA	READOP		;NOT A READ OPERATION
	MOV	A,C		;WRITE TYPE IN C
	STA	WRTYPE
	CPI	WRUAL		;WRITE UNALLACATED?
	JNZ	CHKUNA		;CHECK FOR UNALLOCATED
;
;
;WRITE TO UNALLOCATED, SET PARAMETERS
;
	MVI	A,BLKSIZ/128	;NEXT UNALLOCATED RECORDS
	STA	UNACNT
	LDA	SEKDSK		;DISK TO SEEK
	STA	UNADSK		;UNADSK = SEKDSK
	LHLD	SEKTRK
	SHLD	UNATRK		;UNATRK = SECTRK
	LDA	SEKSEC
	STA	UNASEC		;UNASEC = SEKSEC
;
;
;CHECK FOR WRITE TO UNALLOCATED SECTOR
;
CHKUNA:
	LDA	UNACNT		;ANY UNALLOCATED REMAINING?
	ORA	A
	JZ	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?
	JNZ	ALLOC		;SKIP IF NOT
;
;
;DISKS ARE THE SAME
;
	LXI	H,UNATRK
	CALL	SEKTRKCMP	;SEKTRK = UNATRK?
	JNZ	ALLOC		;SKIP IF NOT
;
;
;TRACKS ARE THE SAME
;
	LDA	SEKSEC		;SAME SECTOR?
	LXI	H,UNASEC
	CMP	M		;SEKSEC = UNASEC?
	JNZ	ALLOC		;SKIP IF NOT
;
;
;MATCH, MOVE TO NEXT SECTOR FOR FUTURE REFERENCE
;
	INR	M		;UNASEC = UNASEC+1
	MOV	A,M		;END OF TRACK?
	PUSH	B
	MVI	B,HDSPT		;USE HARD DISK SPT
	CMP	H
	POP	B
	JC	NOOVF		;SKIP IF NO OVERFLOW
;
;
;OVERLFOW TO NEXT TRACK
;
	MVI	M,0		;UNASEC = 0
	LHLD	UNATRK
	INX	H
	SHLD	UNATRK		;UNATRK = UNATRK+
;
;
;MATCH FOUND, MARK AS UNNECESSARY READ
;
NOOVF:
	XRA	A		;0 TO A REG.
	STA	RSFLAG		;REFLAG = 0
	JMP	RWOPER		;TO PERFORM THE WRITE
;
;
;NOT AN UNALLOCATED RECORD, REQUIRES PRE-READ
;
ALLOC:
	XRA	A		;0 TO A REG.
	STA	UNACNT		;UNACNT = 0
	INR	A		;1 TO A REG.
	STA	RSFLAG		;RSFLAG = 1
;
;
;COMMON CODE FOR READ AND WRITE FOLLOWS:
;
RWOPER:				;ENTER HERE TO PERFORM THE READ/WRITE
	XRA	A		;ZERO TO A REG.
	STA	ERFLAG		;NO ERRORS (YET)
	LDA	SEKSEC		;COMPUTE HOST SECTOR
;
	REPT	SECSHF
	ORA	A		;CARRY = 0
	RAR			;SHIFT RIGHT
	ENDM
;
;
;LET BIOS PRETEND THAT SECTORS ARE NUMBERED FROM 1 TO AVOID
;OTHER PROBLEMS IN THE "SEKHST" SECTOR NUMBER VALUE.
;
	INR	A
	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?
	JZ	FILHST		;FILL HOST IF NOT
;
;
;HOST BUFFER ACTIVE, SAME AS SEEK BUFFER?
;
	LDA	SEKDSK
	LXI	H,HSTDSK	;SAME DISK?
	CMP	M		;SEKDSK = HSTDSK?
	JNZ	NOMATCH
;
;
;SAME DISK, SAME TRACK?
;
	LXI	H,HSTTRK
	CALL	SEKTRKCMP	;SEKTRK = HSTTRK?
	JNZ	NOMATCH
;
;
;SAME DISK, SAME TRACK, SAME BUFFER?
;
	LDA	SEKHST
	LXI	H,HSTSEC	;SEKHST = HSTSEC?
	CMP	M
	JZ	MATCH		;SKIP IF MATCH
;
;
;PROPER DISK, BUT NOT CORRECT SECTOR
;
NOMATCH:
	LDA	HSTWRT		;HST WRITTEN?
	ORA	A
	CNZ	WRITEHST	;CLEAR HAST BUFF
;
;
;MAY HAVE TO FILL THE HOST BUFFER
;
FILHST:
	LDA	SEKDSK
	STA 	HSTDSK
	LHLD	SEKTRK
	SHLD	HSTTRK
	LDA	SEKHST
	STA	HSTSEC
	LDA	RSFLAG		;NEED TO READ?
	ORA	A
	CNZ	READHST		;YES, IF 1
	XRA	A		;0 TO A REG.
	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
;
	REPT	7		;SHIFT LEFT 7
	DAD	H
	ENDM
;
;
;HL HAS RELATIVE HOST BUFFER ADDRESS
;
	LXI	D,HSTBUF
	DAD	D		;HL = HOST ADDRESS
	XCHG			;NOW IN DE
	LHLD	DMAADR		;GET/PUT CP/M DATA
	MVI	C,128		;LENGTH OF MOVE; CP/M SECTOR SIZE
	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/DESTINATION SWAP
;
;
;C INITIALLY 128, DE IS SOURCE, HL IS DESTINATION
;
RWMOVE:
	LDAX	D		;SOURCE CHARACTER
	INX	D
	MOV	M,A		;TO DESTINATION
	INX	H
	DCR	C		;LOOP 128 TIMES
	JNZ	RWMOVE
;
;
;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 A REG.
	STA	HSTWRT		;BUFFER WRITTEN
	CALL	WRITEHST
	LDA	ERFLAG
	RET
;
;
;UTILITY SUBROUTINE FOR 16-BIT COMPARE
;
SEKTRKCMP:			;HL = .UNATRK OR .HSTTRK, COMPARE
				;..WITH SEKTRK
	XCHG
	LXI	H,SEKTRK
	LDAX	D		;LOW BYTE COMPARE
	CMP	M		;SAME?
	RNZ			;RETURN IF NOT
;
;
;LOW BYTES EQUAL, TEST HIGH FIRST
;
	INX	D
	INX	H
	LDAX	D
	CMP	M		;SETS FLAGS
	RET
;
;
WRITEHST:			;PERFORMS THE PHYSICAL WRITE
				;TO THE HST DISK
;
;HSTDSK = HOST DISK NUMBER, HSTTRK = HOST TRACK NUMBER,
;HSTSEC = HOST SECT NUMBER. WRITE "HSTSIZ" BYTES
;FROM HSTBUF AND RETURN ERROR FLAG IN ERFLAG.
;RETURN ERFLAG NON-ZERO IF ERROR
;
WRTSEC:
	CALL	RIOPB		;SETUP RAM DISK IOPB
				;..FROM BIOS VARIABLES
	CALL	RWRITE		;GO WRITE RAM DISK SECTOR
	XRA	A
	STA	ERFLAG		;RESET ERROR FLAG
	RET			;RETURN FROM "WRITEHST", IF O.K.
;
;
READHST:			;PERFORMS THE PHYSICAL READ FROM
				;.. THE HOST DISK
;
;HSTDSK = HOST DISK NUMBER, HSTTRK = HOST TRACK NUMBER,
;HSTSEC = HOST SECT NUMBER. READ "HSTSIZ" BYTES
;INTO HSTBUF AND RETURN ERROR FLAG IN ERFLAG.
;
READSEC:
	CALL	RIOPB		;SET RAM DISK IOPB
	CALL	RREAD		;GO READ SECTOR
	XRA	A
	STA	ERFLAG
	RET
;
;
;ROUTINE TO SETUP THE RAM DISK SOFTWARE ADDRESS VALUES. VALUES
;BASED UPON THE CP/M LOGICAL VALUES
;
RIOPB:
	LXI	H,HSTBUF	;POINT TO HOST BUFFER ADDRESS
	SHLD	XFRPNT
	LDA	HSTTRK		;CONVERT CP/M TRACK AND SECTOR TO
	ADD	A		;  256 BYTE RAM PAGE ADDRESS INDEX
	ADD	A
	ADD	A		;TRACK BOUNDARY INDEX
	MOV	B,A		;SAVE TO GET SECTOR
	LDA	HSTSEC
	DCR	A		;HOST BIOS ABOVE THINKS SECTORS START AT 1
	ADD	B		;SECTOR 256 BYTE INDEX TO RAM DISK
	MOV	D,A
	MVI	E,00H
	LXI	H,RAMBUF	;POINT TO RAM BUFFER FOR DISK
	DAD	D		;(HL) IS RAM ADDRESS FOR MOVE
	SHLD	RAMADDR
	RET
;
;
;INLINE PRINT OF MESSAGE TILL A ZERO
;
PRTMSG:
	XTHL			;SAVE HL, GET MSG POINTER
;
PRTMLP:
	MOV	C,M		;GET CHARACTER
	INX	H		;INCREMENT POINTER TO HEXT CHAR
				;.. OR RETURN ADDRESS
	MOV	A,C		;CHECK IF ZERO END
	ORA	A
	JZ	PMXIT		;EXIT IF ZERO
;
	CALL	CTYPE		;OUTPUT IT
	JMP	PRTMLP		;GO CHECK/DO NEXT CHAR
;

CTYPE:
;	PUSH	PSW
	PUSH	B
	PUSH	D
	PUSH	H
	CALL	BCOUT
	POP	H
	POP	D
	POP	B
;	POP	PSW
	RET
;
;
;
PMXIT:
	XTHL			;RESTORE HL, RET ADDR
	RET			;RET PAST MSG
;
;
;***************************************************************************
;***************************************************************************
;
;	MICRO RESOURCES TPA RESIDENT RAM DRIVE I/O ROUTINES
;
;***************************************************************************
;***************************************************************************
;
;
;WRITE ON 256 BYTE RECORD FROM THE HSTBUF TO THE RAM DRIVE
;
RWRITE:
	LHLD	RAMADDR		;POINT AT THE RAM DRIVE ADDRESS
	XCHG			;TO (DE) AS "TO" ADDRESS
	LHLD	XFRPNT		;GET (HL) AS "FROM" ADDRESS
	LXI	B,SECSIZ	;PHYSICAL HOST SECTOR SIZE
;
RWXFR:
	MOV	A,M		;GET A DATA BYTE
	STAX	D		;PUT AT DESTINATION
	INX	H		;BUMP	POINTERS
	INX	D
	DCX	B		;DECREMENT BUFFER SIZE COUNTER
	MOV	A,B
	ORA	C		;CHECK IF ALL MOVED YET
	JNZ	RWXFR
	RET			;DONE WITH READ ALREADY
;
;
;READ ONE 256 BYTE RECORD FROM THE RAM DRIVE TO THE HOST BUFFER
;
RREAD:
	LHLD	XFRPNT		;POINT AT THE HOST BUFFER AS
	XCHG			;..(DE) AS "TO" ADDRESS
	LHLD	RAMADDR		;GET (HL) READ ADDRESS AS "FROM" ADDRESS
	LXI	B,SECSIZ	;BYTES PER SECTOR COUNTER
	JMP	RWXFR		;GO DO THE TRANSTER
;
;
;***************************************************************************
;
;	STORAGE AREA FOR VARIABLES BEGINS HERE..
;
;
;RELOCATION POINTER STORAGE AREA
;
CCP$ENT
	DS	2		;STORE CCP RE-ENTRY POINTER HERE
				;TABLE POINTER HERE
;
;
;RAM DISK DRIVE ACCESS PARAMETER BLOCK
;
RAMADDR:
	DS	2		;RAM DRIVE POINTER ADDRESS
XFRPNT:
	DS	2		;READ/WRITE ROUTINE DATA BUFFER POINTER
;
;
;THE NEXT SEVERAL BYTES, BETWEEN STARTZ AND
;ENDZ, ARE SET TO ZERO AT MODULE INITIALIZATION
;
STARTZ	EQU	$		;START OF ZEROED AREA
;
;
;HOST DISK BLOCKING/DE-BLOCKING DATA AREA
;
SEKDSK:
	DS	1		;SEEK DISK NUMBER
SEKTRK:
	DS	2		;SEEK TRACK NUMBER
SEKSEC:
	DS	1		;SEEK SECTOR NUMBER
HSTDSK:
	DS	1		;HOST DISK NUMBER
HSTTRK:
	DS	2		;HOST TRACK NUMBER
HSTSEC:
	DS	1		;HOST SECTOR NUMBER
SEKHST:
	DS	1		;SEEK SHR SECSHF
HSTACT:
	DS	1		;HOST ACTIVE FLAG
HSTWRT:
	DS	1		;HOST WRITTEN FLAG
UNACNT:
	DS	1		;UNALLOCATED RECORD COUNT
UNADSK:
	DS	1		;LAST UNALLOCATED DISK
UNATRK:
	DS	2		;LAST UNALLOCATED TRACK
UNASEC:
	DS	1		;LAST UNALLOCATED SECTOR
ERFLAG:
	DS	1		;ERROR REPORTING
RSFLAG:
	DS	1		;READ SECTOR FLAG
READOP:
	DS	1		;1 IF READ OPERATION
WRTYPE:
	DS	1		;WRITE OPERATION TYPE
DMAADR:
	DS	2		;DISK DMA TRANSFER ADDRESS
RAMSEL:
	DS	1		;LOCAL DISK SELECTED FLAG
;
ENDZ	EQU	$		;END OF ZEROED AREA
;
;
;HOST DATA BUFFER MEMORY AREA
;
;
HSTBUF:
	DS	HSTSIZ		;HOST BUFFER
;
;
;
;
;SCRATCH RAM AREA FOR BDOS USE
;
	ENDEF			;LET DISKDEF FIXUP BDOS BUFFERS
;
	END
;
;
;+++...END OF FILE
				;.. THE HOST DISK
;
;HSTDSK = HOST DISK NUMBER, HSTTRK = HOST TRACK NUMBER,
;HSTSE