; LAST UPDATED:		15 JUN 83
; REASON FOR UPDATE:	Reorganized structure of BOOT and BIOS routines so that
;		a portion of the cold boot initialization takes place in the
;		boot loader.  This facilitates modification of Input/Output
;		initialization by placing the most common tables in a smaller
;		program and at fixed locations.				aep
;
; PROGRAM NAME:		xxxFBOOT.ASM, where "xxx" identifies the relationship
;		of the revision level to it's corresponding BIOS source.
;
; PURPOSE:	Floppy Disk (either 8 inch or 5 1/4 inch drives) boot loader
;		for CP/M or MP/M.
;
;	==========================	Copyright 1982, CompuPro Corporation,
;	||			||	A division of Godbout Electronics.
;	||  FLOPPY BOOT LOADER	||	Oakland Airport,	Oakland, CA
;	||			||
;	==========================
;
;	This product is a copyright program product of CompuPro and is
;	supplied for use with the CompuPro Disk controllers.
;
; LIBRARY CONSTANTS:
	MACLIB	COMPUPRO ;Disk and Serial/Parallel interface constants
	MACLIB	ACTIVE	;Flags directing construction for the various
;
; EQUATED CONSTANTS:
;
    if BOOT5X		;If 5 1/4 inch drive used during cold boot 
FDPORT	EQU	FD5PORT	;Normal controller port is 5 1/4 inch
FDXPORT	EQU	FD8PORT	;Auxiliary controller port is 8 inch
    else
FDPORT	EQU	FD8PORT	;Defaults to using 8 inch controller to boot
FDXPORT	EQU	FD5PORT	;Auxiliary controller port is 5 1/4 inch
    endif
;
; PROGRAM:
    ASEG
	ORG	100h		;Base address of bootstrap load
;
;********************************************************
;*	CHARACTER INPUT / OUTPUT INITIALIZATION		*
;********************************************************
;
;Entry:	C = Board switches from ROM (0 .. 3)
;
START:	LXI	SP,100h		;Initialize top of stack
	MOV	A,C		;Save board options (boot switch selected)
	STA	BOOTSW		;In CBIOS reserved area at low memory
	ADD	A		;Get Boot Switch value times 2
	LXI	H,BIOTBL	;Add to I/O vector initialization table
	ADD L!	MOV L,A		;To get offset entry from it
	MOV A,M!  STA IOBYTE	;Set I/O BYTE as in table
	INX	H		;Set I/O Control as well
	MOV A,M!  STA IOCNTL
;
; This routine performs the initialization required by the system
;	Input/Output support chips (UARTs).
;
IOINIT:	LXI	H,INISEQ	;Point to initialization sequence string
IOINIT1:MOV A,M!  INX H		;Get the port to xmit to, point to next value
	STA	INIPORT+1	;Store in code sequence for transmission
	INR	A		;See if highest address port
	JZ	IOINIT2		;Clear console input ports if so
	MOV A,M!  INX H		;Get value to xmit in "A", point to next value
INIPORT:OUT	0		;Send data to correct port
	JMP	IOINIT1		;Loop until all ports initialized
;
IOINIT2:IN	SS1UD		;Flush System Support I UART of any input data
	IN	IF3UD		;as well as USER 7 on the Interfacer 3 or 4
;
;************************************************
;*	BOOTSTRAP LOAD FROM FLOPPY DISK		*
;************************************************
;
; Load Specify Command for boot controller (usually 8 inch) floppy drives.
SPECIFY:LXI	H,SPEC		;Start of specification table
	MVI	B,3		;3 Byte length in "B"
	CALL	PUTDATA		;Put specification in boot controller
;
; Load Specify Command for auxiliary drive controller.
;	 (does nothing if other DISK 1 is absent)
	MVI	B,3		;3 Byte length in "B"
SPEC2:	IN	FDXPORT+FDCS	;See if ready to accept next byte
	ORA	A
	JP	SPEC2		;Wait if not ready
	MOV	A,M		;Load command byte
	OUT 	FDXPORT+FDCD	;to controller command port
	INX	H		;Point to next byte
	DCR	B		;Bump count until all loaded
	JNZ	SPEC2		;Loop if more to do
;
; The drive is already known to be positioned on track 0 (done to load this
; routine), and therefore a seek is not necessary.  The routine will loop on
; error back to this point.
;
RETRY:	LXI	H,DATA		;DMA data pointer
	CALL	READ$DISK	;Read in remainder of track at CBIOS position
	JNZ	RETRY		;Loop on error to re-issue command
	CALL	READ$DISK	;Re-read sector 2 into the 8088's highest RAM
	JNZ	RETRY		;Loop on error to re-issue both read commands
	LHLD	ENTRY		;Get CBIOS entry address (cold boot vector)
	MOV	D,H		;Exchange bytes to correct for reverse order
	MOV	H,L
	MOV	L,D
	PCHL			;Enter CBIOS by direct vector in "H,L"
;
	PAGE
;****************************************************************
;*	LOAD DMA REGISTERS AND EXECUTE FLOPPY READ COMMAND	*
;****************************************************************
;
READ$DISK:  ; Output beginning DMA address.
	MVI	B,3		;3 Bytes of DMA data
ADDR:	MOV	A,M		;Get byte of extended address
	OUT	FDPORT+FDMA	;Send to DMA port of DISK 1
	INX	H		;Next byte to xfer
	DCR	B		;Bump count
	JNZ	ADDR		;Loop until all 3 bytes loaded
;
; Read the remainder of track 0 in as the CBIOS to execute the cold boot.
	MVI	B,9		;Load "B" with command length (9 Bytes)
	CALL	PUTDATA		;Wait until controller ready to accept data
READ1:	IN	FDPORT+INTS	;See if interrupt active (command complete)
	ORA	A
	JP	READ1		;Loop until so
	CALL	GETDATA		;Get a result status byte from controller
	XRI	40h		;Test for "abnormal ending" status bit only
	MOV	E,A		;Put result in "E"
	CALL	GETDATA		;Get second result status byte from controller
	XRI	FD$EOC		;Flip status of "End Of Cylinder" bit
	MOV	D,A		;Put result in "D"
	MVI	B,7-2		;Count of remaining status bytes (ignored)
READ2:	CALL	GETDATA		;Get next result status byte from controller
	DCR	B		;Bump remaining count
	JNZ	READ2		;Wait until all done
	MOV A,E!  ORA D		;Combine the two significant status bytes
	RET			;Return with zero if successful read operation
;
;
; Routine to load controller with command and data bytes.
PUTDATA:IN	FDPORT+FDCS	;Get controller status
	ORA	A
	JP	PUTDATA		;Wait until controller ready for another byte
	MOV	A,M		;load command byte
	OUT 	FDPORT+FDCD	; to controller
	INX	H		;Point to next byte to load
	DCR	B		;Bump command load count
	JNZ	PUTDATA		;Loop if more bytes to load
	RET			;Return if all data loaded in controller
;
; Routine to get a command result status byte from controller.
GETDATA:IN	FDPORT+FDCS	;See if ready to read status
	ORA	A
	JP	GETDATA		;Wait if not
	IN	FDPORT+FDCD	;Get resulting status of read operation
	RET
;
	PAGE
;************************************************
;*	FIXED STORAGE FOR DISK SPECIFICATIONS	*
;************************************************
SPEC:	;	FLOPPY Specification sequences (loaded only once).
    if BOOT5X
	DB  FD$SPEC		;5 1/4 inch drive specifications
	DB  (SRT5 SHL 4) + HUT5
	DB  HDLT5 SHL 1
	DB	FD$SPEC		;8 inch drive specifications
	DB	(SRT8 SHL 4) + HUT8
	DB	HDLT8 SHL 1
    else
	DB	FD$SPEC		;8 inch drive specifications
	DB	(SRT8 SHL 4) + HUT8
	DB	HDLT8 SHL 1
	DB  FD$SPEC		;5 1/4 inch drive specifications
	DB  (SRT5 SHL 4) + HUT5
	DB  HDLT5 SHL 1
    endif
;
;************************************************
;*	FIXED STORAGE FOR DISK READ OPERATIONS	*
;************************************************
;
; Function data for controller to boot.
DATA:	DB	0		;Extended Address
ENTRY:	DB	high BIOS	;Base address of CBIOS
	DB	low BIOS
READ:	DB	FD$RDAT		;Read sector(s) command for 8272 controller
	DB	0		;Head select, Drive select = 0
	DB	0		;Cylinder #0
	DB	0		;Head #0
	DB	3		;Starting Record (sector)
	DB	0		;"N" parameter (128 byte sectors)
	DB	26		;Read to end of track
	DB	7		;GPL (Gap length)
	DB	128		;DTL (Data length)
;
; Re-read this sector into the memory at 0FFF80h to place the 8088 code for
; a long jump back to 400h, the default run address of the GO86 prom.
;
READ88:	DB	00Fh,0FFh,080h	;3 bytes of the DMA to setup for 8088
	DB	FD$RDAT		;Read sector(s) command for 8272 controller
	DB	0		;Head select, Drive select = 0
	DB	0		;Cylinder #0
	DB	0		;Head #0
	DB	2		;Starting Record (sector)
	DB	0		;"N" parameter (128 byte sectors)
	DB	2		;Read just a single sector
	DB	7		;GPL (Gap length)
	DB	128		;DTL (Data length)
;
	PAGE
;****************************************************************
;*	INPUT/OUTPUT DEVICE INITIALIZATION SEQUENCE TABLE	*
;****************************************************************
INISEQ:	;Port,	Value to transmit sequence until Port = 0FFh.
;
; Interfacer 3,4 UART initialization.
   DB	IF3UX,	4	;Select Uart 4
   DB	IF3UM,01011010b ;Async, 16x, 7 bits, odd parity, 1 stop
   DB	IF3UM,01111110b ; 9600 baud
   DB	IF3UC,00100111b	;Trans. on, DTR low, rec. on, no break/ reset, RTS low
;
   DB	IF3UX,	5	;Select Uart 5
   DB	IF3UM,01011010b ;Async, 16x, 7 bits, odd parity, 1 stop
   DB	IF3UM,01111110b ; 9600 baud
   DB	IF3UC,00100111b	;Trans. on, DTR low, rec. on, no break/ reset, RTS low
;
   DB	IF3UX,	6	;Select Uart 6
   DB	IF3UM,01011110b ;Async, 16x, 8 bits, odd parity, 1 stop
   DB	IF3UM,01111110b ; 9600 baud
   DB	IF3UC,00100111b	;Trans. on, DTR low, rec. on, no break/ reset, RTS low
;
   DB	IF3UX,	7	;Select Uart 7
   DB	IF3UM,01011010b ;Async, 16x, 7 bits, odd parity, 1 stop
   DB	IF3UM,01111110b ; 9600 baud
   DB	IF3UC,00100111b	;Trans. on, DTR low, rec. on, no break/ reset, RTS low
;
; System Support I UART initialization.
   DB	SS1UM,01011010b	;Async, 16x, 7 bits, odd parity, 1 stop
   DB	SS1UM,01111111b	;19200 baud
   DB	SS1UC,00100111b	;Xmit on, DTR low, rec. on, no break, run, RTS low
;
   DB	0FFh		;End of I/O port initialization string
;
;************************************************
;*	STORAGE "LONG JUMP" FOR 8088		*
;************************************************
	ORG	1F0h		;Place in the last 16 bytes of last sector
	DB	0EAh		;Long jump instruction
	DW	0400h,0000h	;Segment at 0 hex, offset 400h (000400h)
	DB	90h,90h,90h	;Fill out remainder with 8088 NOP instructions
;
	PAGE
;********************************************************
;*	INPUT/OUTPUT DEVICE INITIAL SELECT TABLE	*
;********************************************************
;
BIOTBL:		;I/O byte (IOBYTE) value, Aux I/O control byte (IOCNTL) value
; Switch = 0
   DB	10$00$00$01b	;LST:=LPT:, PUN:=TTY:, RDR:=TTY:, CON:=CRT:
   DB	01$00$00$10b	;LPT:=Interfacer I UART 1, CRT:=Interfacer I UART 0
; Switch = 1
   DB	10$00$00$01b	;LST:=LPT:, PUN:=TTY:, RDR:=TTY:, CON:=CRT:
   DB	00$00$01$00b	;LPT:=Interfacer 3 USER 4 xon/xoff, CRT:=USER 0
; Switch = 2
   DB	10$00$00$01b	;LST:=LPT:, PUN:=TTY:, RDR:=TTY:, CON:=CRT:
   DB	00$00$01$01b	;LPT:=Interfacer 3,4 USER 4, CRT:=System Support I
; Switch = 3
   DB	00$00$00$11b	;LST:=TTY:, PUN:=TTY:, RDR:=TTY:, CON:=UC1:
   DB	00$00$01$01b	;LPT:=Interfacer 3,4 USER 4, CRT:=System Support I
;
; IOBYTE value is the first entry for each switch selection, and --
; IOCNTL =	ww$xx$yy$zzb	selects the following:
;(second byte	ww xx yy 00	CRT:=Interfacer 3 USER 0.
;of each entry	ww xx yy 01	CRT:=System Support I.
;in BIOTBL).	ww xx yy 10	CRT:=Interfacer 1,2 UART 0.
;		   xx yy 11	CRT:=Interfacer 1,2 UART 1 (Custom Routine).
;		00 xx yy --	LPT:=Interfacer 3,4 USER 4.
;		01 xx yy --	LPT:=Interfacer 1,2 UART 1.
;		10 xx yy --	LPT:=Interfacer 1,2 UART 2 (Custom Routine).
;		11 xx yy --	LPT:=	"	"	"	"	"
;		-- xx -- --	Interfacer 3,4 USER 5 list routine select,
;		-- -- yy --	Interfacer 3,4 USER 4 list routine select,
;Where xx and/or yy = 00	Straight output, no software protocol.
;		      01	XON/XOFF software protocol active.
;		      10	ETX/ACK software protocol active.
; And (always):
;		UC1:= Interfacer 3,4 USER 7
;		TTY:= Interfacer 3,4 USER 6
;		UL1:= Interfacer 3,4 USER 5 at all times.
;
;<=========  If CON:=BAT: then --
;/==|	BAT:=	RDR:= Interfacer 3,4 USER 3 when RDR:=UR2: on input.
;\==|__	BAT:=	PUN:=	"		" 3 when PUN:=UP2: on output.
;/==|	BAT:=	RDR:= Interfacer 3,4 USER 2 when RDR:=UR1: on input.
;\==|__	BAT:=	PUN:=	"		" 2 when PUN:=UP2: on output.
;/==|	BAT:=	RDR:= Interfacer 3,4 USER 1 when RDR:=PTR: on input.
;\==|__	BAT:=	PUN:=	"		" 1 when PUN:=PTP: on output.
;x /--|	BAT:=	----- Interfacer 3,4 USER 0 when RDR:=TTY: on input.
;x \--|	BAT:=	-----	"		" 0 when PUN:=TTY: on output.
; and for reader/punch vectors only --
;x --	------	RDR:= Interfacer 3,4 USER 6 when RDR:=TTY: on input.
;x --	------	PUN:=	"		" 6 when PUN:=TTY: on output.
;
	END
