TITLE	'BANKED WINCHESTER BIOS FOR CPM 3'
	VER EQU  280

; MEMORY MAP OF BANK 0:
;		0000H TO 0100H:	INTERRUPT VECTOR TABLE
;		0100H TO 0E00H:	COPY OF CCP.COM FOR WARM BOOTS
;		0E00H TO WHATEVER:	BUFFER SPACE
;
;	Version of 8/5/91: Set up for year 1991.
;
;	Version of 4/10/90: Does less retries during floppy r/w.
;
;	Version 0f 1/8/90:  Checks real-time clock for rollover
;	when reading time.  Also set year to 1990.
;
;	Version 1.1 has cache on, burst mode used, DMA
;	for disk reads and writes.
	
;	Version 1.0 initialized from hbw8.azm  5/9/89 
;

MACLIB	Z80
MACLIB	Z280
MACLIB	CPM3

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


PUBLIC	BOOT
PUBLIC	WBOOT
PUBLIC	CONST
PUBLIC	CONIN
PUBLIC	CONOUT
PUBLIC	LIST
PUBLIC	AUXOUT
PUBLIC	AUXIN
PUBLIC	HOME
PUBLIC	SELDSK
PUBLIC	SETTRK
PUBLIC	SETSEC
PUBLIC	SETDMA
PUBLIC	READ
PUBLIC	WRITE
PUBLIC	LISTST
PUBLIC	SECTRAN
PUBLIC	CONOST
PUBLIC	DUMMY
PUBLIC	DRVTBL
PUBLIC	MOVE

PUBLIC @DTBL
PUBLIC ?DRTBL


;
;THE CODE BEGINS HERE:
;THIS IS THE JUMP VECTOR TABLE:
;
CSEG

BIOS:
;
	JMP	BOOT
?WBOOT:	JMP	WBOOT
	JMP	CONST
	JMP	CONIN
	JMP	CONOUT
	JMP	LIST
	JMP	AUXOUT
	JMP	AUXIN
	JMP	HOME
	JMP	SELDSK
	JMP	SETTRK
	JMP	SETSEC
	JMP	SETDMA
	JMP	READ
	JMP	WRITE
	JMP	LISTST
	JMP	SECTRAN
	JMP	CONOST
	JMP	AUXIST
	JMP	AUXOST
	JMP	DEVTBL
	JMP	DEVINI
?DRTBL:	JMP	DRVTBL
	JMP	MULTIO
	JMP	FLUSH
	JMP	MOVE
	JMP	TIME
	JMP	SELMEM
	JMP	SETBNK
	JMP	XMOVE
	JMP	DUMMY
	JMP	DUMMY
	JMP	DUMMY
;
;
FLETTER EQU  'C'
FLOPPY EQU 	FLETTER - 'A'
;
@DTBL:
	DTBL	<WDPH0, WDPH1, FDPH, WDPH2, WDPH3, WDPH4>



FDPH:	DPH	FTRANS,FDPB

	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	0FFFEH		;CHECKSUM VECTOR
	DW	0FFFEH		;ALLOCATION VECTOR
	DW	0FFFEH		;DIR BUFFER CONTROL BLOCK (NOT ALLOCATED)
	DW	0FFFFH		;DATA BUFFER CONTROL BLOCK (NONE)
	DW	0FFFEH		;HASH TABLE (NOT ALLOCATED)
	DB	0		;HASH BANK

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

FDPB:	DPB	128,26,77,1024,64,2	;STANDARD SSSD DISK PARAMETER BLOCK


WDPH0:	DPH	0000H, WDPB0, 0
WDPB0:	DPB	512, 16, 303+2, 2048, 640, 2, 8000H

WDPH1:	DPH	0000H, WDPB1, 0
WDPB1:	DPB	512, 16, 303+305, 2048, 640, 305, 8000H

WDPH2:	DPH	0000H, WDPB2, 0
WDPB2:	DPB	512, 16, 303+608, 2048, 640, 608, 8000H

WDPH3:	DPH	0000H, WDPB3, 0
WDPB3:	DPB	512, 16, 303+911, 2048, 640, 911, 8000H

WDPH4:	DPH	0000H, WDPB4, 0
WDPB4:	DPB	512, 16, 303+1214, 2048, 640, 1214, 8000H



DUMMY:	RET


;
BOOT:	
	DI
	LXI	SP,TEMPSTACK

;SET DMA MASTER CONTROL REGISTER TO TURN ON
;SOFTWARE READY FOR DMA0  (USED BY MOVE ROUTINE)

	CALL	IOPGFF

	MVI	C,1FH
	LXI	H,0020H
	OUTW

;COPY COMMON MEMORY IN 80000H AREA TO C00000H AREA SO COMMON MEMORY
;WILL BE PHYSICALLY CONTIGIOUS.

	LXI	H,CPPROG
	MVI	C,0		;OUTPUT PROGRAM TO DMA 0
	MVI	B,6
?CLOOP:	OUTIW
	INR	C
	INR	B
	DCR	B
	JNZ	?CLOOP

; WAIT FOR THE DMA TO COMPLETE
C2LOOP:	MVI	C,05
	INW
	MOV	A,L
	ANI	10H	;TEST TRANSFER COMPLETE BIT
	JZ	C2LOOP

; Load the MMU PDR pointer (at I/O address FFxxF1h) to 1Eh
	mvi	a, 1Eh
	out	0f1h
; Do output to port FFxxF4h to fill descriptors 1e-1fh
	mvi	c, 0f4h
	LHLD	MMTAB0+28
	OUTW
	LHLD	MMTAB0+30
	OUTW

	CALL	IOPG00

	XRA	A		; TURN OFF THE CLOCK INTERRUPT
	OUT	0F1H
	IN	0F0H

	MVI	A,0		;INITIALIZE CONSOLE INPUT BUFFER
	STA	BUFCNT

	MVI	A,98H
	OUT	87H		;INITIALIZE PARALLEL PRINTER PORT
	MVI	A,0FFH
	OUT	86H
	OUT	85H		;MAKE OUTPUT LINES HIGH

;	CALL	WRESET		;RESET WINCHESTER CONTOLLER


; Initialize the trap/vector table entry for interrupt line A
	
	LXI	H, 0000
	SHLD	0008H
	LXI	H, INTRES
	SHLD	000AH

; Set the interrupt/trap vector table pointer to 0000h (logical)
	LXI	H,8000H    ;800000H physical  EQU  0000H logical
	MVI	C,6
	LDCTL

	IM3

	MVI	A,91H	;TURN ON UART RX INTERRUPTS
	OUT	70H
	EI		;TURN ON INTERRUPT FOR CONSOLE INPUT

; Turn off refresh
	CALL	IOPGFF
	MVI	A,60
	OUT	0E8H	;TURN OFF REFRESH
	CALL	IOPG00


; Turn on the cache
	PCACHE
	LXI	H,0028H	;Turn on cache for code only with burst on upper 8mb
	MVI	C,12H
	LDCTL


	LXI	H,SIGNON
	CALL	PRMSG	;PRINT SIGN-ON

	XRA	A
	STA	DIFBNK
	MVI	A,1
	CALL	SELMEM

	MVI	A,1
	STA	SEKCNT
	STA	REMCNT		;INITIALIZE MULTIO VARIABLES

	CALL	SETJUMPS
	CALL	LOADCCP		;GET CCP FROM DISK, AND COPY TO BANK 0
	JMP	0100H
;
SIGNON: DB  'CP/M 3 BANKED BIOS FOR Z280 VERSION OF 8/5/91', 0DH, 0AH, 0
;


CPPROG:
	DW	0000H
	DW	0C0E0H
	DW	0000H
	DW	080E0H
	DW	02000H
	DW	8100H	;SPECIFIES CONTINOUS MEMORY-MEMORY BYTE TRANSACTION

;
WBOOT:
	LXI	SP,TEMPSTACK
	MVI	A,1
	CALL	SELMEM
	CALL	SETJUMPS
	CALL	RLCCP		;COPY THE CCP FROM BANK 0 TO BANK 1
	JMP	0100H

DRVTBL:
	LXI	H,@DTBL
	RET

XMOVE:
	MOV	A,C
	STA	SRCBNK
	MOV	A,B
	STA	DSTBNK
	MVI	A,1
	STA	DIFBNK
	RET


MOVE:	
	PUSH	B	;SAVE COUNT
	PUSH	D	;SAVE SOURCE
			;HL HAS DEST
	LDA	DIFBNK
	ANA	A
	JNZ	BNKDIF

	LDA	CURBNK	;IF NO XMOVE, SET SRC AND DEST TO CURRENT BANK
	STA	SRCBNK
	STA	DSTBNK
BNKDIF:
	XRA	A
	STA	DIFBNK	;CLEAR XMOVE FLAG

	SHLD	MVDST
	LDA	DSTBNK
	CALL	PHYADR
	SHLD	MVDST+2

	POP	H	;GET SOURCE
	SHLD	MVSRC
	LDA	SRCBNK
	CALL	PHYADR
	SHLD	MVSRC+2

	POP	H	;GET COUNT
	SHLD	MVCNT

	;SEND PROGRAM TO DMA CONTROLLER
	MVI	A,00	;USE DMA CONTROLLER 0
	LXI	H, MVPROG
	CALL	DODMA

	LBCD	MVCNT		;SET DE AND HL TO REQUIRED EXIT VALUES
	LHLD	MVSRC
	DAD	B
	XCHG			;LOAD DE WITH NEXT SRC ADDRESS
	LHLD	MVDST
	DAD	B		;LOAD HL WITH NEXT DST ADDRESS

	RET


MVPROG:
MVDST:	DW	0000H
	DW	0000H
MVSRC:	DW	0000
	DW	0000
MVCNT:	DW	0000
	DW	8100H	;SPECIFIES CONTINOUS MEMORY-MEMORY BYTE TRANSACTION



MULTIO:
	MOV	A,C
	STA	SEKCNT
	STA	REMCNT
	RET

FLUSH:
	XRA	A
	RET

RESMEM:
	LDA	CURBNK
	JMP	SELMM2

SELMEM:
	STA	CURBNK
SELMM2:
	PUSH	H
	PUSH	B
	PUSH	D
	PUSH	PSW

; Set the I/O page register to ffh
	CALL	IOPGFF

; Load the MMU PDR pointer (at I/O address FFxxF1h) to 10h
	mvi	a, 10h
	out	0f1h

	POP	PSW
	MOV	E,A
	MVI	D,0
	LXI	H,PTABLST
	DAD	D
	DAD	D
	LDHLM		;LOAD HL WITH ADDRESS OF PAGE TABLE OF BANK IN A

; Do block output to port FFxxF4h to fill descriptors 10-1dh
	mvi	c, 0f4h
	mvi	b, 14
	otirw

; Set the I/O page register back to 00h
	CALL	IOPG00

	POP	D
	POP	B
	POP	H
	RET


PTABLST:
	DW	MMTAB0
	DW	MMTAB1


; This is the inital table of values to be loaded into the MMU.
; it maps the lower 14 of 16 pages to RAM at 800000h.
; THE LAST TWO PAGES ARE ALWAYS IN THE C00000 AREA. They
; are copied there from the 800000 area at boot time.

MMTAB0:
	DW	800ah
	DW	801ah
	DW	802ah
	DW	803ah
	DW	804ah
	DW	805ah
	DW	806ah
	DW	807ah
	DW	808ah
	DW	809ah
	DW	80aah
	DW	80bah
	DW	80cah
	DW	80dah
	DW	0C0eah
	DW	0C0fah


; This is the map for bank 1, It maps the lower 56K to; physical memory at
; C00000H.  The last 8K, common memory, is also in this area.

MMTAB1:
	DW	0C00ah
	DW	0C01ah
	DW	0C02ah
	DW	0C03ah
	DW	0C04ah
	DW	0C05ah
	DW	0C06ah
	DW	0C07ah
	DW	0C08ah
	DW	0C09ah
	DW	0C0aah
	DW	0C0bah
	DW	0C0cah
	DW	0C0dah
	DW	0C0eah
	dw	0C0fah	

SETBNK:
	STA	SEKBNK
	RET


; THIS ROUTINE FIGURES OUT THE TOP 12 BITS OF THE PHYSICAL ADDRESS
; FOR THE BANK IN A AND THE LOGICAL ADDRESS IN HL.

PHYADR:
	PUSH	H
	MOV	E,A
	MVI	D,0
	LXI	H,PTABLST
	DAD	D
	DAD	D
	LDHLM		;LOAD HL WITH ADDRESS OF PAGE TABLE OF BANK IN A
	POP	D
	MOV	A,D
	RRC
	RRC
	RRC
	ANI	1EH	;GET HI-ORDER 4 BITS OF ADDRESS INTO RANGE OF 0-31
	MOV	E,A
	MVI	D,0
	DAD	D
	LDHLM		;LOAD HL WITH CONTENTS OF PAGE TABLE FOR THE ADDRESS
	RET



EXTRN	@MXTPA
SETJUMPS:
	MVI	A,JMP
	STA	0
	STA	5
	LXI	H,?WBOOT
	SHLD	0001
	LHLD	@MXTPA
	SHLD	0006
	RET


;THIS LOADS THE CCP FROM A:CCP.COM

LOADCCP:
	MVI	A,1
	CALL	SELMEM
	XRA	A
	STA	CCPFCB+15
	LXI	H,0
	SHLD	FCBNR
	LXI	D,CCPFCB
	MVI	C,15
	CALL	0005	;OPEN FILE
	INR	A
	JZ	NOCCP
	LXI	D,0100H
	MVI	C,26
	CALL	0005	;SETDMA
	LXI	D,128
	MVI	C,44
	CALL	0005	;SETMULTI
	LXI	D,CCPFCB
	MVI	C,20
	CALL	0005	;READ FILE
	;ASSUME READ OK

	;COPY THE CCP TO BANK 0 FOR RELOADS
	XRA	A
	STA	DSTBNK
	MVI	A,1
	STA	SRCBNK
	STA	DIFBNK
	JMP	MVCCP

NOCCP:
	LXI	H,CCPMSG
	CALL	PRMSG
	CALL	CONIN
	JMP	LOADCCP	;LOOP; RETRYING

CCPMSG:
	DB	'CANNOT READ A:CCP.COM', 0DH, 0AH, 0

CCPFCB:
	DB	1, 'CCP     ', 'COM', 0,0,0,0
	DS	16
FCBNR:	DB	0,0,0


;THIS COPIES THE CCP FROM BANK 0 TO BANK 1 FOR WARM BOOTS
RLCCP:
	XRA	A
	STA	SRCBNK
	MVI	A,1
	STA	DSTBNK
	STA	DIFBNK
MVCCP:	LXI	D,0100H
	LXI	H,0100H
	LXI	B,0C80H
	CALL	MOVE
	RET


;
;THIS IS THE INTERRUPT RESPONSE ROUTINE FOR THE CONSOLE INPUT
;

INTRES:	PUSH	PSW	;SAVE REGISTERS
	PUSH	B
	PUSH	D
	PUSH	H
	CALL	PSHIOP
	CALL	IOPG00	;MAKE SURE WE ARE AT I/O PAGE 0
;	
	IN	72H	;SEE IF IT'S FROM UART
	ANI	81H	;CHECK INTERRUPT AND RX FULL BITS
	CPI	81H
	JNZ	?1END	;RETURN IF NOT FROM UART RECEIVER
;
	IN	73H	;GET CHARACTER
	ANI	7FH	;CLEAR BIT SEVEN 
;
	MOV	B,A	;SAVE CHAR
	LDA	BUFCNT
	CPI	BUFMAX
	JNZ	?1A	;IF BUFFER IS FULL, BEEP AND DUMP CHAR
	MVI	C,07
	CALL	CONOUT
	JMP	?1END
;
?1A:	INR	A
	STA	BUFCNT	;INCREMENT BUFFER COUNT
;
	LXI	H,CONBUF-1
	ADD	L
	MOV	L,A
	JNC	?1C
	INR	H	;ADD ACCUM TO HL TO GET ADDRESS OF 
			;TOP OF BUFFER
?1C:	MOV	M,B	;BUT CHAR IN BUFFER
;
?1END:	
	CALL	POPIOP
	POP	H
	POP	D
	POP	B
	POP	PSW	;RESTORE REGISTERS
	INX	SP
	INX	SP	; Pop off "reason code"
	RETIL		; Return from interrupt long
			; (restores previous interrupt enable state) 
;
;
CONST:

	LDA	BUFCNT
	ANA	A	;SEE IF BUFFER COUNT IS ZERO
	RZ		;RETURN WITH ACC = 0 IF SO
	MVI	A,0FFH
	RET		;ELSE 0FFH MEANS SOMETHING IN BUFFER
;
;
CONIN:	CALL	CONST
	ORA	A
	JZ	CONIN	;WAIT FOR A CHARACTER TO ARRIVE
;
	LXI	H,CONBUF
	LXI	D,BUFHED
	LXI	B,BUFMAX  ;SET UP TO SHIFT BUFFER DOWN
	DI		;ENTER CRITICAL SECTION
;
	LDIR		;SHIFT BUFFER
	LXI	H,BUFCNT
	DCR	M	;DECREMENT BUFFER COUNT
	LDA	BUFHED	;GET CHARACTER
;
	EI		;LEAVE CRITICAL SECTION
	RET
;
;
BUFMAX	EQU	32		;LENGTH OF BUFFER
;
BUFCNT:	DB	0	;# OF CHARS IN BUFFER
BUFHED:	DB	0	;PLACE TO SHIFT BUFFER HEAD
CONBUF:	DS	BUFMAX	;INPUT BUFFER



;
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
;
;
; THIS LIST HAS NORMAL LIST AS CENTRONICS 
;
LIST:
	JMP	CENLST

LISTST:
	JMP	CENST

;
; VERSION OF LIST AND LISTST FOR CENTRONICS PORT
;
CENST:	IN	84H
	ANI	02H
	MVI	A,0FFH
	RZ
	INR	A
	RET
;
;
CENLST:			;VERSION FOR CENTRONICS PRINTER
	IN	84H
	ANI	02H	;TEST BUSY BIT
	JRNZ	LIST	;LOOP UNTIL READY
	MOV	A,C
	OUT	85H	;PLACE DATA ON OUTPUT
	MVI	A,0FEH
	OUT	86H	;MAKE STROBE LOW
	INR	A
	OUT	86H	;AND RETURN HIGH
	OUT	85H	;MAKE DATA LINES HIGH
	RET



; Z280 UART register addresses (in page FE)

CFREG	equ	10h
TCREG	equ	12h
RCREG	equ	14h
RDREG	equ	16h
TDREG	equ	18h


AUXIST:
	CALL	IOPGFE
	IN	RCREG
	CALL	IOPG00
	ANI	10H
	MVI	A,0
	RZ
	DCR	A
	RET		;RETURN WITH FFH IN A IF CHAR IS READY


AUXIN:
	CALL	IOPGFE
AUXINL:
	IN	RCREG
	ANI	10H 		;bit to test for rcv ready
	JZ	AUXINL
	IN	RDREG

	CALL	IOPG00
	RET


AUXOST:
	CALL	IOPGFE
	IN	TCREG
	CALL	IOPG00
	ANI	01H
	MVI	A,0
	RZ
	DCR	A
	RET		;RETURN WITH FFH IN A IF XMTR IS READY


AUXOUT:
	PUSH	B
	CALL	IOPGFE
AUXOTL:
	IN	TCREG
	ANI	01H 		;bit to test for rcv ready
	JZ	AUXOTL
	POP	B
	MOV	A,C
	OUT	TDREG

	CALL	IOPG00
	RET



;THIS TABLE GIVES TIMER CONSTANTS FOR BAUD RATE GENERATION
; THEY ASSUME A 10MHZ CLOCK AND X16 IN THE UART.

BAUDNO:
	DW	0
	DW	3124	;50 BPS
	DW	2082	;75
	DW	1419	;110
	DW	1161	;134.5
	DW	1041	;150
	DW	520	;300
	DW	259	;600
	DW	129	;1200
	DW	86	;1800
	DW	64	;2400
	DW	42	;3600
	DW	32	;4800
	DW	21	;7200
	DW	15	;9600
	DW	7	;19200


MB$INPUT	EQU	01H
MB$OUTPUT	EQU	02H
MB$IN$OUT	EQU	03H
MB$SOFT$BAUD	EQU	04H
MB$SERIAL	EQU	08H
MB$XON$XOFF	EQU	10H


CHRTBL:
	DB	'ACIA  '	;6850 ACIA SERIAL CHIP
	DB	MB$IN$OUT+MB$SERIAL+MB$SOFT$BAUD
	DB	14		;9600 BPS

	DB	'UART  '	;Z280 UART
	DB	MB$IN$OUT+MB$SERIAL+MB$SOFT$BAUD
	DB	14		;9600 BPS

	DB	'LPR   '	;CENTRONICS PORT
	DB	MB$OUTPUT
	DB	0

	DB	0


DEVTBL:
	LXI	H,CHRTBL
	RET


DEVINI:
	PUSH	B	;SAVE DEVICE NUM

	MOV	A,C
	ADD	A
	ADD	A
	ADD	A
	ADI	7	; A := 8*A + 7
	MOV	C,A
	MVI	B,0	
	LXI	H,CHRTBL
	DAD	B	; HL := &(CHRTBL[C].BAUDRATE)

	MOV	C,M
	MVI	B,0	; BC := BAUD RATE INDEX OF DEVICE  (1-15)

	LXI	H,BAUDNO
	DAD	B
	DAD	B
	LDHLM		; HL := BAUDNO[C]

	PUSH	H
	CALL	IOPGFE

	POP	H	;H IS COUNTER VALUE
	POP	B
	MOV	A,C	;GET ORIGINAL DEVICE NUMBER
	
	MVI	C,0FAH	;ADDRESS OF COUNT REGISTER FOR ACIA BAUD RATE
	ANA	A	;SEE IF DEVICE 0
	JZ	WRBAUD
	MVI	C,0EAH	;ADDRESS FOR Z280 UART BAUD RATE REGISTER
WRBAUD:
	OUTW		;WRITE

	CALL	IOPG00

	RET


	

EXTRN	@SEC, @MIN, @HOUR, @DATE

TIME:
	MOV	A,C
	ANA	A
	JNZ	STTIME

	; GET THE HOUR, MINUTES, AND SECONDS
	
	IN	0F4H	;RESET ROLLOVER DETECTOR

RTLOOP:
	IN	0E2H
	STA	@SEC
	IN	0E3H
	STA	@MIN
	IN	0E4H
	STA	@HOUR

	IN	0F4H
	ANA	A
	JNZ	RTLOOP	;TRY AGAIN IF CLOCK ROLLED OVER WHILE BEING READ

	;GET THE MONTH, CONVERT IT TO BINARY FROM BCD,
	;AND USE IT TO INDEX INTO THE MONTH TABLE
	
	IN	0E7H
	CALL	BCDBIN	;NOW HAVE 1-12
	DCR	A
	MOV	E,A
	MVI	D,0
	LXI	H,MONTHS
	DAD	D
	DAD	D	;INDEX INTO MONTHS[0-11]
	MOV	A,M
	INX	H
	MOV	H,M
	MOV	L,A	;GET # OF DAYS TO BEGINNING OF MONTH
	
	IN	0E6H	;GET DAY OF MONTH
	CALL	BCDBIN
	MOV	E,A
	MVI	D,0
	DAD	D	;ADD TO BEGINNING-OF-MONTH
	SHLD	@DATE

	RET


;THESE TWO DEFINES MUST BE UPDATED EVERY YEAR
LEAP	EQU	0	;NO LEAP YEAR THIS YEAR
JAN	EQU	4748	;DAYS FROM JAN 1, 1978 TO BEGINNING OF THIS YEAR - 1
			;VALUE OF 4018 IS FOR 1989
			;4383 for 1990
			;4748 for 1991

FEB	EQU	JAN+31
MAR	EQU	FEB+28+LEAP
APR	EQU	MAR+31
MAY	EQU	APR+30
JUN	EQU	MAY+31
JUL	EQU	JUN+30
AUG	EQU	JUL+31
SEP	EQU	AUG+31
OCT	EQU	SEP+30
NOV	EQU	OCT+31
DEC	EQU	NOV+30


MONTHS:
	DW	JAN
	DW	FEB
	DW	MAR
	DW	APR
	DW	MAY
	DW	JUN
	DW	JUL
	DW	AUG
	DW	SEP
	DW	OCT
	DW	NOV
	DW	DEC


STTIME:
	; SET THE HOUR, MINUTES, AND SECONDS
	
	LDA	@SEC
	OUT	0E2H
	LDA	@MIN
	OUT	0E3H
	LDA	@HOUR
	OUT	0E4H

	;SKIP THE DAYS FOR NOW
	RET



BCDBIN:		;CONVERT BCD IN A TO BINARY 0-99
	MOV	C,A
	ANI	0FH	;MASK OUT ONE'S
	MOV	B,A	;STORE IN B
	MOV	A,C
	ANI	0F0H
	RRC
	MOV	C,A	;SAVE 8 TIMES TEN'S
	RRC
	RRC		;GET 2 TIMES TENS
	ADD	C	;ADD 2X AND 8X TO GET 10X
	ADD	B	;ADD IN ONES
	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
;
;

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


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

IOPGFE:	MVI	L,0FEH
	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


;
;
HOME:	LXI	H,0
	SHLD	SEKTRK
	RET
;
;
SELDSK:	
	MOV	A,C
	STA	SEKDSK
	MVI	B,0	;BC HAS DRIVE NUMBER
	LXI	H,@DTBL
	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
;
;
SECTRAN:
	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:	
	XRA	A
	STA	ERFLAG
	LDA	SEKDSK
	CPI	FLOPPY
	JZ	FREAD

	LDA	SEKCNT
	LXI	H,REMCNT
	CMP	M
	CZ	HREAD	;DO READ IF FIRST CALL AFTER MULTIO
	LXI	H,REMCNT
	DCR	M
	JNZ	RDMULT
	MVI	A,1
	STA	SEKCNT	;AFTER LAST SKIPPED MULTIO READ, RESET COUNTERS TO 1
	STA	REMCNT
RDMULT:
	LDA	ERFLAG
	RET


WRITE:
	XRA	A
	STA	ERFLAG
	LDA	SEKDSK
	CPI	FLOPPY
	JZ	FWRITE

	LDA	SEKCNT
	LXI	H,REMCNT
	CMP	M
	CZ	HWRITE	;DO WRITE IF FIRST CALL AFTER MULTIO
	LXI	H,REMCNT
	DCR	M
	JNZ	WRMULT
	MVI	A,1
	STA	SEKCNT	;AFTER LAST SKIPPED MULTIO WRITE, RESET COUNTERS TO 1
	STA	REMCNT
WRMULT:
	LDA	ERFLAG
	RET


;
;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:
	MVI	A,1
	STA	SEKCNT
	STA	REMCNT	;DISABLE MULTIO FOR FLOPPY
	LDA	SEKBNK
	CALL	SELMM2	;TEMPORARILY SET BANK TO I/O BANK
	CALL	FREAD2
	LDA	ERFLAG
	ANA	A	;SET FLAGS
	JZ	FRDONE	;READ WAS OK
	CALL	FHOME
	CALL	FREAD2
FRDONE:
	CALL	RESMEM	;RESTORE ORIGINAL BANK
	LDA	ERFLAG
	RET
;
FREAD2:	CALL	FWAIT
	LDA	SEKSEC
	OUT	SECTOR
	CALL	FTKSET
	MVI	A,3
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
;
;THIS IS THE FLOPPY WRITE ROUTINE. IT CALLS
;THE ACTUAL WRITING SUBROUTINE, AND IF IT
;WAS UNSUCCESSFUL, RESETS THE HEAD AND
;TRIES AGAIN.
;
FWRITE: 
	MVI	A,1
	STA	SEKCNT
	STA	REMCNT	;DISABLE MULTIO FOR FLOPPY
	LDA	SEKBNK
	CALL	SELMM2	;TEMPORARILY SET BANK TO I/O BANK
	CALL	FWR2
	LDA	ERFLAG
	ANA	A	;SET FLAGS
	JZ	FWDONE	;WRITE WAS OK
	CALL	FHOME
	CALL	FWR2
FWDONE:
	CALL	RESMEM	;RESTORE ORIGINAL BANK
	LDA	ERFLAG
	RET

;
FWR2:	CALL	FWAIT
	LDA	SEKSEC
	OUT	SECTOR
	CALL    FTKSET
FWR4:	MVI	A,3
FWR3:	STA	TRYNUM
	CALL	FWAIT
	LHLD	DMAADR
	MVI	C,DATA
	MVI	B,128
	MVI	D,01
	MVI	A,WRITEC
	DI		;ENTERING CRITICAL SECTION
	OUT	COMAND
?3A:	IN	STATUS
	ANI	01
	JZ	?3A
?3B:	IN 	STATUS
	ANI	02
	JNZ	?2LOOP
	IN	STATUS
	ANI	01
	JZ	??ERROR
	JMP	?3B
?2LOOP:	IN	STATUS
	XRA	D
	JZ	?2LOOP
	OUTI
	JNZ	?2LOOP
	EI		;LEAVING CRITICAL SECTION
	CALL	FWAIT
	IN	STATUS
	ANI	WRMASK
	JRZ	FW2END
??ERROR: LDA	TRYNUM
	DCR	A
	JNZ	FWR3
	MVI	A,1
FW2END:	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
;


;
;
;THESE ARE THE HARD DISK READ AND WRITE ROUTINES.
;
;
WREAD EQU  08H
WWRITE EQU 0AH
;
HREAD:
	MVI	A,WREAD
	CALL	COMCODE
	RET
;
HWRITE:
	MVI	A,WWRITE
	CALL	COMCODE
	RET

;
; COMMON CODE FOR WINCHESTER READ OR WRITE
;
COMCODE:
	STA	CMDBLK+0	;STORE OPCODE
	MVI	A,0
	STA	CMDBLK+1	;SELECT LUN
	XRA	A
	STA	CMDBLK+5
	LDA	SEKCNT
	STA	CMDBLK+4	;TRANSFER COUNT

	LHLD	SEKTRK
	DAD	H
	DAD	H
	DAD	H
	DAD	H	;MULTIPLY HSTTRK 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
;
	LXI	H,CMDBLK
	SHLD	CPTR

	LHLD	DMAADR
	SHLD	DPTR

	LDA	SEKBNK
	STA	DBNK

	LDA	SEKCNT
	MOV	H,A
	MVI	L,0
	DAD	H	;MULT SEKCNT BY 512 FOR BYTE COUNT
	SHLD	DLEN

	MVI	A,1
	STA	BUSID

	CALL	SCSIOP

;CHECK ERROR HERE
	MOV	A,L
	ANI	11B
	STA	ERFLAG

	RET

;
CMDBLK:	DB	0,0,0,0,0,0
;
;



; /* The following is generic SCSI driver code, also used by devmt.c */

; char *dptr;
; unsigned dlen;
; char *cptr;
; int busid;

DPTR:	DW	0
DBNK:	DB	0
DLEN:	DW	0
CPTR:	DW	0
BUSID:	DB	0

;
SDATA	EQU	0D8H
SCMD	EQU	0D9H
;
SCSIOP:
;
	PUSH	B
;
	CALL	SWAIT
	JZ	HUNG	;ABORT IF PENDING TRANSACTION

	LDA	BUSID	;OUTPUT SCSI BUS ADDRESS
	OUT	SDATA
	MVI	A,1	;SELECT CONTROLLER
	OUT	SCMD	;ASSERT SELECT
SLA2:	IN	SCMD	;WAIT FOR BSY TO BE ASSERTED
	ANI	01
	JNZ	SLA2
	XRA	A
	OUT	SCMD	;DEASSERT IT
;
	LHLD	CPTR
SLA3:	CALL	SWAIT	;WAIT FOR REQ
	JNZ	LOST
	IN	SCMD
	ANI	1FH
	CPI	01100B	;CONTINUE AS LONG AS IT WANTS COMMANDS
	JNZ	ECMD
	ANI	00100B
	JZ	SEQ	;ABORT IF IT HAS A MESSAGE
	MOV	A,M		;TRANSMIT COMMAND
	OUT	SDATA
	INX	H
	JMP	SLA3
;	
ECMD:	LHLD	DLEN
	MOV	A,H
	ORA	L
	JZ	EDATA	;SKIP DATA I/O IF NECESSARY
	CALL	SWAIT	
	JNZ	LOST
	IN	SCMD	;SEE IF IT REALLY WANTS DATA
	ANI	10H
	JZ	EDATA
	IN	SCMD
	ANI	08H	;CHECK FOR DATA READ OR WRITE
	JNZ	WIO
	
	; FILL IN THE DMA PROGRAM WITH THE CORRECT ADDRESS AND LENGTH
	LHLD	DPTR
	SHLD	RDADR
	LDA	DBNK
	CALL	PHYADR
	SHLD	RDADR+2
	LHLD	DLEN
	SHLD	RDCNT
;
	;SEND PROGRAM TO DMA CONTROLLER
	MVI	A,08
	LXI	H, RDBLK
	CALL	DODMA
	JMP	EDATA
;
WIO:
	LHLD	DPTR
	SHLD	WRADR
	LDA	DBNK
	CALL	PHYADR
	SHLD	WRADR+2
	LHLD	DLEN
	SHLD	WRCNT
;
	;SEND PROGRAM TO DMA CONTROLLER
	MVI	A,08
	LXI	H,WRBLK
	CALL	DODMA	
	JMP	EDATA


;
EDATA:
	CALL	SWAIT	;WAIT UNTIL THE CONTROLLER WANTS TO SEND NON-DATA
	JNZ	LOST
	IN	SCMD
	ANI	10H
	JNZ	EDATA
;
;GET STATUS AND SHUT DOWN
;

	IN	SCMD
	ANI	1FH
	CPI	00100B
	JNZ	SEQ	;JUMP IF IT DOESN'T WANT TO SEND STATUS
;
	IN	SDATA
	MOV	L,A
	MVI	H,0
	CALL	SWAIT
	JNZ	LOST
	IN	SCMD
	ANI	1FH
	CPI	00000B
	JNZ	SEQ
	IN	SDATA	;READ FINAL MESSAGE BYTE
;
DONE:	POP	B
	MOV	A,H
	ORA	L
	RET
;
;
LOST:	LXI	H,-1
	JMP	DONE
;
SEQ:	CALL	SWAIT
	LXI	H,-2
	JNZ	DONE
	IN	SDATA	;EAT EXTRA DATA
	JMP	SEQ
;
HUNG:
	CALL	SRESET
	LXI	H,-3
	JMP	DONE
;
; THIS WAITS FOR REQ TO BE ASSERTED OR FOR THE CONNECTION TO BE LOST.
;A NON-ZERO RETURN MEANS CONNECTION WAS LOST
;
SWAIT:
	IN	SCMD
	ANI	01
	RNZ		;RETURN IF NOT EVEN BUSY
	IN	SCMD
	ANI	22H	;MASK OUT REQ AND MAKE SURE ACK FROM LAST CYCLE IS GONE
	JNZ	SWAIT
	RET
;
SRESET:
	MVI	A,2
	OUT	SCMD
	XTHL
	XTHL
	XTHL
	XTHL
	XRA	A
	OUT	SCMD
	RET
;	
;
; THESE ARE THE DMA PROGRAMS FOR READ/WRITE
;
RDBLK:	
RDADR:	DW	000
	DW	000
	DW	SDATA
	DW	0000
RDCNT:	DW	000
	DW	0E080H

WRBLK:
	DW	SDATA
	DW	0000
WRADR:	DW	000	
	DW	000	
WRCNT:	DW	000	
	DW	0808CH

;



;
;
; 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
;
;
;
TRYNUM:	DS	1
;
SEKDSK: DS   1
SEKTRK:	DS	2	
SEKSEC:	DS	1	
SEKCNT	DS	1
REMCNT	DS	1
;
ERFLAG:	DS	1	;DISK ERROR FLAG
DMAADR:	DS	2
;
CURBNK:	DS	1	;CURRENT MEMORY BANK (NOT NECESSARILY THE
			;BANK DISK I/O IS BEING DONE TO)
SRCBNK:	DS	1
DSTBNK:	DS	1	;SOURCE AND DEST BANKS FOR MEMORY-MEMORY MOVE
DIFBNK:	DS	1	;TRUE IF XMOVE HAS BEEN CALLED

SEKBNK:	DS	1	;THE BANK TO DO DISK I/O TO


; TEMPORARY STACK FOR WARM AND COLD BOOT
	DS	64
TEMPSTACK EQU     $


BIOSIZ EQU 	$ - BIOS
;
END
