TITLE	'CPM 3 LDRBIOS'

; INITIALIZED FROM HBW208.AZM OF 8/89
;

MACLIB	Z80
MACLIB	Z280
MACLIB	CPM3

; ###############################################


PUBLIC	BOOT
PUBLIC	WBOOT
PUBLIC	CONST
PUBLIC	CONIN
PUBLIC	CONOUT
PUBLIC	LIST
PUBLIC	PUNCH
PUBLIC	READER
PUBLIC	HOME
PUBLIC	SELDSK
PUBLIC	SETTRK
PUBLIC	SETSEC
PUBLIC	SETDMA
PUBLIC	READ
PUBLIC	LISTST
PUBLIC	SECTRN
PUBLIC	CONOST
PUBLIC	DUMMY
PUBLIC	DRVTBL
PUBLIC	MOVE


;
;THE CODE BEGINS HERE:
;THIS IS THE JUMP VECTOR TABLE:
;
BIOS:
;
	JMP	BOOT
	JMP	WBOOT
	JMP	CONST
	JMP	CONIN
	JMP	CONOUT
	JMP	LIST
	JMP	PUNCH
	JMP	READER
	JMP	HOME
	JMP	SELDSK
	JMP	SETTRK
	JMP	SETSEC
	JMP	SETDMA
	JMP	READ
	JMP	DUMMY
	JMP	LISTST
	JMP	SECTRN
	JMP	CONOST
	JMP	DUMMY
	JMP	DUMMY
	JMP	DUMMY
	JMP	DUMMY
	JMP	DRVTBL
	JMP	DUMMY
	JMP	DUMMY
	JMP	MOVE
	JMP	DUMMY
	JMP	DUMMY
	JMP	DUMMY
	JMP	DUMMY
	JMP	DUMMY
	JMP	DUMMY
	JMP	DUMMY
;
;
FLETTER EQU  'B'	;FLOPPY IS B:
;
FLOPPY EQU 	FLETTER - 'A'
;
DRIVETABLE:
	DTBL	<WDPH0, FDPH>


FDPH:	DW	FTRANS		;FLOPPY DISK PARAMETER HEADER
	DB	0,0,0,0,0,0,0,0,0
	DB	0		;MEDIA FLAG
	DW	FDPB		;DISK PARAMETER BLOCK
	DW	0000		;CHECKSUM VECTOR
	DW	FALV		;ALLOCATION VECTOR
	DW	FDIRBCB		;DIRECTORY BUFFER CONTROL BLOCK
	DW	0FFFFH		;DATA BUFFER CONTROL BLOCK (NONE)
	DW	0FFFFH		;NO HASH
	DB	0		;HASH BANK

FTRANS:	SKEW	26,6,1		;STANDARD SSSD FLOPPY SKEW

FDPB:	DPB	128,26,77,1024,64,2,8000H ;STANDARD SSSD DISK PARAMETER BLOCK
						;WITHOUT CHECKSUM VECTOR

FDIRBCB:
	DB	0FFH
	DB	0,0,0
	DB	0
	DB	0
	DW	0
	DW	0
	DW	FDIRBUF
	DB	0
	DW	0


WDPH0:
	DW	0000		;HARD DISK PARAMETER HEADER
	DB	0,0,0,0,0,0,0,0,0
	DB	0		;MEDIA FLAG
	DW	WDPB0		;DISK PARAMETER BLOCK
	DW	0000		;CHECKSUM VECTOR
	DW	WALV0		;ALLOCATION VECTOR
	DW	WDIRBCB0	;DIRECTORY BUFFER CONTROL BLOCK
	DW	WDTABCB0	;DATA BUFFER CONTROL BLOCK
	DW	0FFFFH		;NO HASH
	DB	0		;HASH BANK

;
;

WDPB0:	DW	64	;HARD DISK PARAMETER BLOCK
	DB	4,15,0
	DW	1211,511   ;THERE ARE 384 DIR ENTRIES, BUT SPACE
	DB	0FFH,0C0H	;RESERVED FOR 640
	DW	8000H,2
	DB	2,3		;512 BYTE PHYSICAL SECTORS
;
WDIRBCB0:
	DB	0FFH
	DB	0,0,0
	DB	0
	DB	0
	DW	0
	DW	0
	DW	WDIRBUF0
	DB	0
	DW	0
;
WDTABCB0:
	DB	0FFH
	DB	0,0,0
	DB	0
	DB	0
	DW	0
	DW	0
	DW	WDTABUF0
	DB	0
	DW	0



DUMMY:	RET


;
BOOT:	
	RET
;
;
;
WBOOT:	RET



DRVTBL:
	LXI	H,DRIVETABLE
	RET

MOVE:	XCHG
	LDIR
	XCHG
	RET

;
;
CONST:
	RET		;ELSE 0FFH MEANS SOMETHING IN BUFFER
;
;
CONIN:	
	RET
;
;
CONOST:
	IN	70H
	ANI	02H
	RZ
	MVI	A,0FFH
	RET
;
CONOUT:	IN	70H
	ANI	02H
	JZ	CONOUT
	MOV	A,C
	OUT	71H
; THIS ADDS TWO PAD CHARS AFTER LF'S
	CPI	0AH
	RNZ
	MVI	C,00H	;NULL
	CALL	CONOUT	;RECURSIVE
	CALL	CONOUT
	RET
;
;
LIST:
	RET
;
LISTST:
	RET
PUNCH:
;	RET
READER:
	RET
;
;
;
;THIS IS USED IN SEVERAL PLACES. IT GIVES
; ( .5 * HL ) MILLISECONDS OF DELAY.
;
DELAY:	MVI	B,154
DELAY1:	DJNZ	DELAY1	;.5 MS DELAY
	DCX	H
	MOV	A,H
	ORA	L
	JNZ	DELAY	;LOOP HL TIMES
	RET
;
;
;
HOME:	LXI	H,0
	SHLD	SEKTRK

	RET
;
;
SELDSK:	
	; DO THIS HERE INSTEAD OF IN BOOT SO IT WILL NOT BE
	; SCROLLED OFF THE SCREEN
	PUSH	B
	LXI	H,SIGNON
	CALL	PRMSG	;PRINT SIGN-ON
	POP	B

	MOV	A,C
	STA	SEKDSK
	MVI	B,0	;BC HAS DRIVE NUMBER
	LXI	H,DRIVETABLE
	DAD	B
	DAD	B	;INDEX TO POINTER IN DRIVE TABLE FOR DISK
	MOV	A,M
	INX	H
	MOV	H,M
	MOV	L,A

	RET

;
;
SETTRK:	SBCD	SEKTRK
	RET
;
;
SETSEC:	MOV	A,C
	STA	SEKSEC
	RET
;
;
SECTRN:
	MOV	L,C
	MOV	H,B
	MOV	A,D
	ORA	E
	RZ
	XCHG		;FLOPPY ROUTINE
	DAD	B
	MOV	L,M
	MVI	H,0
	RET
;
;
SETDMA:	SBCD	DMAADR
	RET
;
;
READ:
	LDA	SEKDSK
	CPI	FLOPPY
	JZ	FREAD
	JMP	HREAD

;
;THESE ARE 1771 FLOPPY DISK CONTROLLER COMMANDS,
;I/O PORT ADDRESSES, AND FLAG MASKS:
;
RESTOR EQU 	08H	;6MS STEP,LOAD HEAD
SEEK EQU 	18H	;6MS STEP,LOAD HEAD
READC EQU 	88H	;NO HEAD LOAD
WRITEC EQU 	0A8H	;NO HEAD LOAD
RESET EQU 	0D0H	;RESET STATUS COMMAND
STATUS EQU 	80H
COMAND EQU 	80H
TRACK EQU 	81H
SECTOR EQU 	82H
DATA EQU 	83H
BUSY EQU 	01
RDMASK EQU 	10011111B
WRMASK EQU 	0FFH
;
;
;THIS FLOPPY READ ROUTINE CALLS FREAD2. IF THE
;READ IS UNSUCCESSFUL, THE DRIVE IS HOMED,
;AND THE READ IS RETRIED.
;
FREAD:	CALL	FREAD2
	LDA	ERFLAG
	ANA	A	;SET FLAGS
	RZ		;READ WAS OK
	CALL	FHOME
	CALL	FREAD2
	LDA	ERFLAG
	RET
;
FREAD2:	CALL	FWAIT
	LDA	SEKSEC
	OUT	SECTOR
	CALL	FTKSET
	MVI	A,11
FREAD3:	STA 	TRYNUM
	CALL	FWAIT
	LHLD	DMAADR
	MVI	C,DATA
	MVI	B,128
	MVI	D,03
	MVI	A,READC
	DI		;ENTERING CRITICAL SECTION
	OUT	COMAND
	XTHL	;SHORT DELAY
	XTHL
	XTHL
	XTHL	
	XTHL
	XTHL
	XTHL
	XTHL
?1LOOP:	IN	STATUS
	ANA	D
	DCR	A
	JZ	?1LOOP
	INI
	JNZ	?1LOOP
	EI		;LEAVING CRITICAL SECTION
	CALL	FWAIT
	IN	STATUS
	ANI	RDMASK
	JRZ	FR1END
	LDA	TRYNUM
	DCR	A
	JNZ	FREAD3
	MVI	A,1
FR1END:	STA	ERFLAG
	RET
;
;
;THESE 3 SUBROUTINES ARE USED BY THE FREAD2 AND
;FWR2 ROUTINES:
;
FTKSET:	CALL	FWAIT
	LDA	SEKTRK
	OUT	DATA
	XTHL	
	XTHL
	XTHL
	XTHL
	MVI	A,SEEK
	OUT	COMAND
	XTHL	
	XTHL
	XTHL
	XTHL
	XTHL	
	XTHL
	XTHL
	XTHL
	RET
;
FWAIT:	IN	STATUS
	XTHL	
	XTHL
	XTHL
	XTHL
	ANI	10000001B
	JNZ	FWAIT
	RET
;
FHOME:	CALL	FWAIT
	MVI	A,RESTOR
	OUT	COMAND
	XTHL	
	XTHL
	XTHL
	XTHL
	RET
;
;
;


DODMA:
	PUSH	H
	DI
	CALL	IOPGFF
	POP	H
	MOV	C,A
	MVI	B,6
?3LOOP:	OUTIW
	INR	C
	INR	B
	DCR	B
	JNZ	?3LOOP
	CALL	IOPG00
	EI
	RET


; THIS PUTS INTO HL THE HI-ORDER 12 BITS OF THE PHYSICAL ADDRESS SPECIFIED
; BY DMAADR

GETPAD:
	lhld	DMAADR
	mov	a,h
	ani	0f0h
	mov	l,a
	MVI	H,80H		;ALL MEMORY IS MAPPED TO 800000H PHYSICAL
	RET


IOPGFF:	MVI	L,0FFH
	MVI	C,08
	LDCTL            
	RET

IOPG00:	MVI	L,00
	MVI	C,08
	LDCTL
	RET


; THIS PUSHES THE I/O PAGE NUMBER ONTO THE STACK
PSHIOP:
	MVI	C,08
	RDCTL		;GET I/O PAGE #
	XTHL		;EXCHANGE WITH RETURN ADDRESS ON STACK 
	PCHL		;RETURN TO RETURN ADDRESS

POPIOP:
	POP	H	;GET RETURN ADDRESS
	XTHL		;EXCHANGE WITH I/O PAGE VALUE ON STACK
	MVI	C,08
	LDCTL
	RET



RDPROG:
RDADR:	DW	0000H
	DW	0000H
	DW	WDATA
	DW	0000
RDCNT:	DW	0000
	DW	0E080H


;
;
;THESE ARE THE HARD DISK READ ROUTINES.
;THEY READ A 512 BYTE SECTOR TO AND
;FROM THE BUFFER.
;
;
WDATA EQU 	0D8H
WCMD EQU 	0D9H
WREAD EQU   08H
;
HREAD:
	MVI	A,WREAD
	CALL	COMCODE
;
;SETUP DMA CONTROLLER

	; FILL IN THE DMA PROGRAM WITH THE CORRECT ADDRESS AND LENGTH
	LHLD	DMAADR
	mov	a,h
	ani	0fh
	mov	h,a
	SHLD	RDADR
	CALL	GETPAD	;GET HI-ORDER PHYSICAL ADDRESS
	SHLD	RDADR+2
	LHLD	DLEN
	SHLD	RDCNT
;
	;SEND PROGRAM TO DMA CONTROLLER
	MVI	A,08
	LXI	H, RDPROG
	CALL	DODMA

;
	JMP	WCHECK

;
;

;
; COMMON CODE FOR WINCHESTER READ OR WRITE
;
COMCODE:
	STA	CMDBLK+0	;STORE OPCODE
;	LDA	SEKDSK		;USE LUN 0 FOR A,B,D,E
;	CPI	5
	MVI	A,0
;	JC	?1CCA
;	ORI	20H		;USE LUN 1 FOR F AND G
?1CCA:	STA	CMDBLK+1	;SELECT LUN
	XRA	A
	STA	CMDBLK+5
	MVI	A,1		;USE 512 BYTE SECTORS FOR F AND G ON LUN 1
	STA	CMDBLK+4	;TRANSFER COUNT
	CALL	WFREE

	LHLD	SEKTRK
	DAD	H
	DAD	H
	DAD	H
	DAD	H	;MULTIPLY SEKTRK BY 16
;
	LDA	SEKSEC
	MOV	E,A
	MVI	D,0
	DAD	D	;ADD IN SECTOR TO GET BLOCK # (FOR 512 BYTE BLOCKS)
;
	MOV	A,H	;PLACE IN COMMAND BLOCK
	STA	CMDBLK+2
	MOV	A,L
	STA	CMDBLK+3
;
	CALL	SELECT	;SELECT CONTROLLER
	LXI	H,CMDBLK
	MVI	B,6
?5LOOP:	CALL	WWAIT
	MOV	A,M
	OUT	WDATA
	INX	H
	DCR	B
	JNZ	?5LOOP
;	
	CALL	WWAIT	
	IN	WCMD	;SEE IF IT REALLY WANTS DATA
	ANI	10H
	RNZ
	MVI	A,1
	STA	ERFLAG
	LXI	H,SEQMSG
	CALL	PRMSG
        CALL	WCHECK	;EAT STATUS BYTES
	POP	H	;EAT RETURN ADDRESS
	CALL	NLINE
	RET		;RETURN FROM READHST OR WRITEHST	
;
CMDBLK:	DB	0,0,0,0,1,0
;
;
; THIS SELECTS THE CONTROLLER
;
SELECT:	MVI	A,1
	OUT	WDATA
	OUT	WCMD	;ASSERT SELECT
?5A:	IN	WCMD	;WAIT FOR BSY TO BE ASSERTED
	ANI	01
	JNZ	?5A
	XRA	A
	OUT	WCMD	;DEASSERT IT
	CALL	WWAIT	;WAIT FOR REQ
	RET
;
;
; THIS DOES A REQUEST SENSE COMMAND
RDERR:
?6A:	IN	WCMD	;WAIT FOR BSY TO BE DEASSERTED
	ANI	01
	JNZ	?5B
	IN	WDATA
	JMP	?6A
?5B:
	CALL	SELECT
	LXI	H,ERRBLK
;
	LDA	SEKDSK		;USE LUN 0 FOR A,B,D,E
	CPI	5
	MVI	A,0
	JC	?1REA
	ORI	20H		;USE LUN 1 FOR F AND G
?1REA:	STA	ERRBLK+1	;SELECT LUN
;
	MVI	B,6
?7LOOP:
	CALL	WWAIT
	MOV	A,M
	OUT	WDATA
	INX	H
	DCR	B
	JNZ	?7LOOP
; READ IN 4 SENSE BYTES PLUS STATUS AND MESSAGE
	LXI	H,ERSTAT
	MVI	B,6
?1L2:
	CALL	WWAIT
	IN	WDATA
	MOV	M,A
	INX	H
	DCR	B
	JNZ	?1L2
	LDA	ERSTAT
	CPI	98H	;SEE IF CORRECTABLE ERROR
	RNZ
	LXI	H,CORMSG
	CALL	PRMSG
	XRA	A
	STA	ERFLAG	;FORGET ABOUT ERROR
	RET
;
CORMSG:	DB	'CORRECTED ', 0
;
;
ERRBLK:	DB	3,0,0,0,4,0
ERSTAT	 EQU  0FFFAH	;ERROR STAT IN LAST 6 BYTES OF MEMORY
;
; THIS READS IN THE STATUS AND MESSAGE BYTES
;
WCHECK:
?8LOOP:
	CALL	WWAIT	;WAIT UNTIL THE CONTROLLER WANTS TO SEND STATUS
	IN	WCMD
	ANI	00011000B
	JNZ	?8LOOP
;
	; TODO ;TURN OFF DMA CONTROLLER
	CALL	WWAIT
	IN	WCMD
	ANI	00011011B
	JZ	?1OK
	LXI	H,DMSG
	CALL	PRMSG
	MVI	A,1
	STA	ERFLAG
	JMP	?7B
?1OK:	IN	WDATA
	ANA	A
	JRZ	?9A
	MVI	A,1
	STA	ERFLAG
	LXI	H,STATMSG
	CALL	PRMSG
?9A:
	CALL	WWAIT
	IN	WDATA	;READ FINAL MESSAGE BYTE
;
?7B:	LDA	ERFLAG
	ANA	A
	RZ
	CALL	RDERR
	CALL	NLINE
	RET
;
SEQMSG:	DB	'DOESNT WANT DATA ', 0
STATMSG: DB	'BAD RETURN STATUS ', 0
DMSG:	DB	'DOESNT HAVE STATUS ', 0
;
; THIS WAITS FOR REQ TO BE ASSERTED:
;
WWAIT:
	IN	WCMD
	ANI	01
	JNZ	?AA	;JUMP IF NOT EVEN BUSY
	IN	WCMD
	ANI	22H   ;MASK OUT REQ AND MAKE SURE ACK FROM LAST CYCLE IS GONE
	JNZ	WWAIT
	RET
?AA:	
	LXI	H,BSYMSG
	CALL	PRMSG
	MVI	A,1
	STA	ERFLAG
	RET
;
BSYMSG:	DB	'CONTROLLER SHUT OFF ', 0
;
WRESET:
	MVI	A,2
	OUT	WCMD
	XTHL
	XTHL
	XTHL
	XTHL
	XRA	A
	OUT	WCMD
	RET
;	
WFREE:	IN	WCMD
	ANI	1FH
	CPI	1FH
	JNZ	WFREE
	RET
;
;
;
; THIS PRINTS A TEXT STRING TERMINATED BY 00H:
;
PRMSG:	MOV	A,M
	ORA	A
	RZ
	PUSH	H
	MOV	C,A
	CALL	CONOUT
	POP	H
	INX	H
	JR	PRMSG
NLINE:
	LXI	H,NLMSG
	JR	PRMSG
;
NLMSG:	DB	0DH,0AH,0
;
;
;THESE ARE VARIOUS MESSAGES:
;
SIGNON: DB  'CP/M 3 LDRBIOS FOR Z280', 0DH, 0AH, 0
;
;
;
;
;
TRYNUM:	DS	1
;
SEKDSK: DS   1
SEKTRK:	DS	2	
SEKSEC:	DS	1	
DLEN:	DW	512	;512 BYTE SECTORS FOR HARD DISK
;
ERFLAG:	DS	1	;DISK ERROR FLAG
DMAADR:	DS	2
;
;
FDIRBUF:	DS	128
FALV:		DS	62	;WAS 31

WALV0:		DS	306	;WAS 153
WDIRBUF0:	DS	512
WDTABUF0:	DS	512
;
BIOSIZ EQU 	$ - BIOS
;
END
