DataMuseum.dk

Presents historical artifacts from the history of:

CP/M

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about CP/M

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - download

⟦f047bafae⟧ TextFile

    Length: 54528 (0xd500)
    Types: TextFile
    Names: »BIOSKRNL.Z82«

Derivation

└─⟦8181fe295⟧ Bits:30005924 PolyPascal-80 V3.10 arbejdsdiskette 2
    └─ ⟦this⟧ »BIOSKRNL.Z82« 
└─⟦ee7c759f6⟧ Bits:30005973 System backup med COMPAS-80 V3.01, dBase II og WordStar
    └─ ⟦this⟧ »BIOSKRNL.Z82« 

TextFile

	TITLE	'BIOSKRNL.Z80   ROOT TO BIOS. CP/M 3.0'
;**********************************************************
;*      THE TOTAL SYSTEM CONSISTS OF:                     *
;*      BIOSKRNL.Z80    ROOT                              *
;*      BOOT.Z80        BOOT-MODULE                       *
;*      CHARIO.Z80      CHARACTER-I/O-MODULE              *
;*      DRIVES.Z80      DISK-DEFINITON-MODULE             *
;*      EXTMEM.Z80      EXTERNEL MEMORY-MODULE            *
;*      SCB.REL         SYSTEM VARIABLES                  *
;*      IOS.Z80         PORT ADDRESSES                    *
;**********************************************************
; LATEST CHANGE: 1984-02-29.  PSW.
; BIOSREVISION C.

TRUE	EQU	-1
FALSE	EQU	NOT TRUE
BIOSRV	EQU	8408H		; BIOS-REVISION.
BOTFLG	EQU	0C000H		; BOOT-FLAGG

	.Z80
DMA	EQU	18H		; DMA.
				; DMA-COMMANDS
DMRSET	EQU	0C3H		; SOFTWARE RESET
DMENAB	EQU	087H		; ENABLE DMA
DMDISA	EQU	083H		; DISABLE DMA

BNKMUX	EQU	1BH		; BANK-DMA-MULTIPLEXER
DMBK11	EQU	00000000B	; BANK1 --> BANK1
DMBK00	EQU	00001000B	; BANK0 --> BANK0
DMBK10	EQU	00010000B	; BANK1 --> BANK0
DMBK01	EQU	00011000B	; BANK0 --> BANK1
BANK1	EQU	00000000B	; BANK1 (64K FOR CPU)
BANK0	EQU	00100000B	; BANK0 (48K FOR CPU)

CR	EQU	13
LF	EQU	10
BELL	EQU	7
CTLQ	EQU	'Q'-'@'
CTLS	EQU	'S'-'@'

MB$XONXOFF	EQU	00010000B	; XON/XOFF PROTOCOLL ON.

JPOP	EQU	0C3H		; Z80 JUMP INSTRUCTION

CCP	EQU	100H		; LOAD ADDRESS FOR CCP
	PAGE
	; EXTERNAL VARIABELS
;	EXTRN	@COVEC,@CIVEC,@AOVEC	; I/O REDIRECTION VECTORS
;	EXTRN	@AIVEC,@LOVEC		;       - " -
;	EXTRN	@MXTPA			; MAX TPA IN USER BANK
;	EXTRN	@BNKBF			; COMMON 128 BYTE BUFFER

	; INIT
;	EXTRN	?PATCH,?INIT			; 
;	EXTRN	?LDCCP,?RLCCP		; LOAD & RELOAD CCP

	; USER DEFINED CHARACTER I/O ROUTINS
;	EXTRN	?CI,?CO,?CIST,?COST	; 
;	EXTRN	?CINIT,INISTM		; 
;	EXTRN	@CTBL			; 

	; DISK 
;	EXTRN	@DTBL			; POINTER TABLE
;	ENTRY	@ADRV,@RDRV,@TRK,@SECT	; DISKPARAMETERS
;	ENTRY	@DMA,@DBNK,@CNT		;     - " -	

	; MEMORY MODULE
;	ENTRY	@CBNK,BNKMSK		; CURRENT BANK

;	ENTRY	?PMSG   		; WRITES MESSAGES


	; EXTERNAL LABLES TO BIOS-CALLS
;	ENTRY	?BOOT,?WBOOT,?CONST,?CONIN,?CONO,?LIST,?AUXO,?AUXI
;	ENTRY	?HOME,?SLDSK,?STTRK,?STSEC,?STDMA,?READ,?WRITE
;	ENTRY	?LISTS,?SCTRN
;	ENTRY	?CONOS,?AUXIS,?AUXOS,?DVTBL,?DEVIN,?DRTBL
;	ENTRY	?MLTIO,?FLUSH,?MOV,?TIM,?BNKSL,?STBNK,?XMOV

	; EXTERNAL LABLE TO USERFUNCTION
;	EXTRN	?USERF

	; INTERRUPT-VECTORS
;	ENTRY	SIO1IV,SIO2IV,DMAIRV,CTCIRV,PIOIRV
;	ENTRY	INTVECT

	; INTERRUPT-DRIVEN ROUTINES
;	EXTRN	KBDIRQ,CLKIRQ,UNKINT
	PAGE
	CSEG
;**********************************************************
;*              BIOS: JUMP VECTORS                        *
;**********************************************************
	.PHASE	0F700H

?BOOT:	JP	BOOT		; 
?WBOOT:	JP	WBOOT		; 

?CONST:	JP	CONST		; 
?CONIN:	JP	CONIN		; 
?CONO:	JP	CONOUT		; 
?LIST:	JP	LIST		; 
?AUXO:	JP	AUXOUT		; 
?AUXI:	JP	AUXIN		; 

?HOME:	JP	HOME		; 
?SLDSK:	JP	SELDSK		; 
?STTRK:	JP	SETTRK		; 
?STSEC:	JP	SETSEC		; 
?STDMA:	JP	SETDMA		; 
?READ:	JP	READ		; 
?WRITE:	JP	WRITE		; 

?LISTS:	JP	LISTST		; 
?SCTRN:	JP	SECTRN		; 

?CONOS:	JP	CONOST		; 
?AUXIS:	JP	AUXIST		; 
?AUXOS:	JP	AUXOST		; 
?DVTBL:	JP	DEVTBL		; 
?DEVIN:	JP	?CINIT		; IN CHARIO.Z80

?DRTBL:	JP	GETDRV		; 
?MLTIO:	JP	MULTIO		; 
?FLUSH:	JP	FLUSH		; 

?MOV:	JP	?MOVE		; 
?TIM:	JP	RETURN		; NOT INSTALLED
?BNKSL:	JP	BNKSEL		; 
?STBNK:	JP	SETBNK		; 
?XMOV:	JP	?XMOVE		; 

	JP	?USERF		; IN EXTMEM.Z80
	JP	RETURN		; 
	JP	RETURN		; 
	NOP			; GIVE CORRECT START FOR INT.VECTORS.
	PAGE
;**********************************************************
;*		  INTERRUPT VECTORS			  *
;**********************************************************
INTVECT	EQU	$			; INTERRUPT VECTOR ADDRESS

PIOIRV	EQU	$			; PIO BASE INTERRUPT VECTOR
	DEFW	UNKINT
	DEFW	UNKINT			; PIO PORT B 

CTCIRV	EQU	$			; CTC BASE INTERRUPT VEKTOR
	DEFW	UNKINT			; 
	DEFW	UNKINT			; 
	DEFW	UNKINT			; 
	DEFW	CLKIRQ			; (10 Hz TICK)

SIO1IV	EQU	$			; SIO1 BASE INTERRUPT VECTOR
	DEFW	KBDIRQ			; KEYBOARD INT.
	DEFW	UNKINT			; 
	DEFW	UNKINT			; 
	DEFW	UNKINT			; 
	DEFW	UNKINT			; 
	DEFW	UNKINT			; 
	DEFW	UNKINT			; 
	DEFW	UNKINT			; 

SIO2IV	EQU	$			; SIO2 BASE INTERRUPT VECTOR
	DEFW	UNKINT			; 
	DEFW	UNKINT			; 
	DEFW	UNKINT			; 
	DEFW	UNKINT			; 
	DEFW	UNKINT			; 
	DEFW	UNKINT			; 
	DEFW	UNKINT			; 
	DEFW	UNKINT			; 

DMAIRV	EQU	$			; DMA BASE INTERRUPT VECTOR
	DEFW	UNKINT			; 
	DEFW	UNKINT			; 
	DEFW	UNKINT			; 
	DEFW	UNKINT			; 
	PAGE

;
	CSEG			; BANK 1.

BOOT$1:
	CALL	SET$JUMPS	; SET JUMPVECTORS
	CALL	?LDCCP		; READ CCP.COM FROM DISK
	JP	CCP		; 

	; WBOOT

WBOOT:
	LD	SP,BOOT$STACK
	CALL	SET$JUMPS	; INIT PAGE ZERO
	CALL	?RLCCP		; REREAD CCP.COM
	JP	CCP		; 

SET$JUMPS:
	LD	A,1		; SELECT BANK 1
	CALL	?BNKSL
	LD	A,JPOP		; Z80 JP OPCODE
	LD	HL,?WBOOT	; WARM BOOT ENTRY POINT
	LD	(0),A		; BIOS WARM START ENTRY
	LD	(1),HL
	LD	HL,(@MXTPA)	; BDOS ENTRY POINT
	LD	(5),A
	LD	(6),HL
RETURN:	RET			; 

	DS	64
BOOT$STACK	EQU	$

; DEVTBL --  RETURNS THE ADDRESS TO CHARACTER DEVICE TABLE

DEVTBL:	LD	HL,@CTBL
	RET

; GETDRV --  RETURNS THE ADDRESS TO DRIVE TABLE

GETDRV:	LD	HL,@DTBL
	RET
	PAGE
;**********************************************************
;*               CHARACTER I/O- ROUTINES                  *
;**********************************************************

; CONOUT -- CONSOLE OUTPUT.  SENDS CHAR IN (C) TO ALL
; 	    CHOOSEN DEVICES.

CONOUT:	LD	HL,(@COVEC)	; GET CONSOLE OUTPUT BIT VECTOR
	JR	OUT$SCAN


; AUXOUT --  AUXILLIARY OUTPUT.  SENS CHAR IN (C) TO ALL
; 	     CHOOSEN DEVICES.

AUXOUT:	LD	HL,(@AOVEC)	; GET AUX OUTPUT BIT VECTOR
	JR	OUT$SCAN


; LIST -- LIST OUTPUT.  SENDS CHAR IN (C) TO ALL
; 	  CHOOSEN DEVICES.

LIST:	LD	HL,(@LOVEC)	; GET LIST OUTPUT BIT VECTOR
				; AND DO OUT$SCAN

OUT$SCAN:
	LD	B,0		; START WITH DEVICE 0.
CO$NEXT:
	ADD	HL,HL		; SHIFT NEXT BIT BIT
	JR	NC,NO$OUT$DEV	; JUMP IF NO CARRY
	PUSH	HL		; SAVE THE VECTOR AND
	PUSH	BC		; COUNTER AND CHAR.
CO$OUT$RDY:
	CALL	COSTER
	OR	A		; READY ?
	JR	Z,CO$OUT$RDY	; NO...JUMP
	POP	BC		; B=COUNTER C=CHAR
	PUSH	BC		; SAVE
	CALL	?CO		; SEND CHAR IF DEVICE IS CHOOSEN
	POP	BC		; B=COUNTER C=CHAR
	POP	HL		; BIT VECTOR
NO$OUT$DEV:
	INC	B		; NEXT DEVICE #
	LD	A,H		; TEST IF ANY DEVICES LEFT
	OR	L
	JR	NZ,CO$NEXT	; YES...JUMP
	RET


; CONOST -- CONSOLE OUTPUT STATUS. RETURNS TRUE IF ALL
; 	    CHOOSEN CONSOLE OUTPUT DEVICES ARE READY.

CONOST:	LD	HL,(@COVEC)	; GET CONSOLE OUTPUT BIT VECTOR
	JR	OST$SCAN


; AUXOST -- AUXILIARY OUTPUT STATUS. RETURNS TRUE IF ALL
; 	    CHOOSEN AUX OUTPUT DEVICES ARE READY.

AUXOST:	LD	HL,(@AOVEC)	; GET AUX OUTPUT BIT VECTOR
	JR	OST$SCAN


; LISTST -- LIST OUTPUT STATUS. RETURNS TRUE IF ALL
; 	    CHOOSEN LIST OUTPUT DEVICES ARE READY.

LISTST:	LD	HL,(@LOVEC)	; GET LIST OUTPUT BIT VECTOR.


OST$SCAN:
	LD	B,0		; START WITH DEVICE 0
COS$NEXT:
	ADD	HL,HL		; SHIFT OUT NEXT BIT
	PUSH	HL		; SAVE THE VECTOR
	PUSH	BC		; B=COUNTER C=CHAR
	LD	A,-1		; SET DEVICE READY
	CALL	C,COSTER	; GET STATUS IF DEVICE CHOOSEN
	POP	BC		; B=COUNTER C=CHAR
	POP	HL		; HL=VECTOR
	OR	A		; TEST IF DEVICE READY.
	RET	Z		; IF ALL NOT READY, RETURN FALSE.
	INC	B		; NEXT DEVICE
	LD	A,H		; CHECK IF MORE CHOOSEN DEVICES
	OR	L
	JR	NZ,COS$NEXT	; YES...JUMP
	OR	0FFH		; ALL CHOOSEN DEVICES READY
	RET			; RETURN TRUE

; CHECK IF OUTPUT DEVICE READY (XON/XOFF SUPPORT).

COSTER:	LD	L,B		; CHANGE DEVICE # TO 16 BITS
	LD	H,0		; HL=DEV#
	PUSH	HL		; 
	ADD	HL,HL		; OFFSET IN DEVICE-TABLE
	ADD	HL,HL
	ADD	HL,HL		; HL=HL*8
	LD	DE,@CTBL+6	; DE= MODE BYTE FØR DEV 0
	ADD	HL,DE		; HL=RÆTT MODE BYTE
	LD	A,(HL)		; GET MODE BYTE
	AND	MB$XONXOFF	; XON/XOFF PROTOCOLL?
	POP	HL		; HL=DEVICE #
	JP	Z,?COST		; NO XON/XOFF...JUMP
	LD	DE,XOFFLIST
	ADD	HL,DE		; HL=PLACE IN XOFFLIST
	LD	C,0		; FLAGSTATUS FOR ^C, ^S, ^Q ONLY
	CALL	CISTL
	LD	A,(HL)
	CALL	NZ,CIL
	CP	CTLQ
	JR	NZ,NOT$Q
	LD	A,-1		; SET READY-FLAG
NOT$Q:	CP	CTLS		; CTL-S?
	JR	NZ,NOT$S	; NO...JUMP
	LD	A,0		; CLEAR FLAG
NOT$S:	LD	(HL),A		; SAVE FLAG
	CALL	COST1		; GET OUTPUT STATUS
	AND	(HL)		; AND MASK WITH XON/XOFF FLAG
	RET			; AND RETURN IT AS STATUS

CISTL:	PUSH	BC		; GET INPUT STATUS WITH (BC) & (HL)
	PUSH	HL
	CALL	?CIST
	POP	HL
	POP	BC
	OR	A
	RET

COST1:	PUSH	BC		; GET OUTPUT STATUS, SAVE (BC) & (HL)
	PUSH	HL
	CALL	?COST
	POP	HL
	POP	BC
	OR	A
	RET

CIL:	PUSH	BC		; GET INPUT AND SAVE (BC) & (HL)
	PUSH	HL
	CALL	?CI
	POP	HL
	POP	BC
	RET

; CONST -- CONSOLE INPUT STATUS. RETURNS TRUE IF ANY CHOOSEN
; 	   CONSOLE INPUT DEVICE HAS A CHAR AVAILABLE.

CONST:	LD	HL,(@CIVEC)	; GET CONSOLE INPUT BIT VECTOR
	JR	IST$SCAN

; AUXIST -- AUXILIARY INPUT STATUS. RETURNS TRUE IF ANY CHOOSEN
; 	    AUX INPUT DEVICE HAS A CHAR AVAILABLE.

AUXIST:	LD	HL,(@AIVEC)	; GET AUX INPUT BIT VECTOR

IST$SCAN:
	LD	BC,0		; START WITH DEVICE 0
				; CREG = 0 = FLAG, STATUS CALL ONLY
CIS$NEXT:
	XOR	A		; SET DEVICE NOT READY
	ADD	HL,HL		; SHIFT OUT ONE BIT
	CALL	C,CISTL		; CHECK STATUS ON THIS DEVICE
	OR	A		; IF ANY READY RETURN TRUE.
	RET	NZ
	INC	B		; NEXT DEVICE #
	LD	A,H		; CHECK IF ANY MORE DEV.
	OR	L
	JR	NZ,CIS$NEXT
	XOR	A		; ALL CHOOSEN NOT READY. FALSE
	RET

; CONIN -- CONSOLE INPUT. RETURNS  CHAR FROM FIRST READY
; 	   CONSOLE DEVICE.

CONIN:	LD	HL,(@CIVEC)	; GET CONSOLE BIT VECTOR
	JR	IN$SCAN

; AUXIN -- AUXILIARY INPUT. RETURNS CHAR FROM FIRST READY
; 	   AUX INPUT DEVICE.

AUXIN:	LD	HL,(@AIVEC)	; GET AUX BIT VECTOR

IN$SCAN:
	PUSH	HL		; SAVE BIT VECTOR
	LD	B,0		; START WITH DEVICE 0
	LD	C,-1		; CREG = FF = STATUS CALL FOR INPUT
CI$NEXT:
	XOR	A		; SET NO CHAR
	ADD	HL,HL		; SHIFT OUT ONE BIT
	CALL	C,CISTL		; CHECK IF DEVICE HAS A CHAR
	OR	A		; CHAR?
	JR	NZ,CI$RDY	; YES...JUMP
	INC	B		; TEST NEXT DEVICE
	LD	A,H
	OR	L
	JR	NZ,CI$NEXT	; 
	POP	HL		; HL=BIT VECTOR
	JR	IN$SCAN		; LOOP UNTIL GOT A CHAR
CI$RDY:	POP	HL		; HL=BIT VECTOR
	JP	?CI		; GET INPUT FROM DEVICE # IN B.
	PAGE
;**********************************************************
;*                    SUBROUTINES                         *
;**********************************************************

IPCHL:	JP	(HL)		; VECTOR-CALL

?PMSG:				; WRITES MESSAGE @(HL) DETERM.
				; WITH DEFB 0.
	LD	A,(HL)		; GET NEXT BYTE
	OR	A		; IS IT 0 ?
	RET	Z		; YES...RETURN
	PUSH	HL		; SAVE REGISTERS
	PUSH	DE
	PUSH	BC
	LD	C,A		; CHAR IN (C)
	CALL	?CONO		; WRITE
	POP	BC
	POP	DE
	POP	HL
	INC	HL		; HL-->NEXT BYTE
	JR	?PMSG		; START OVER AGAIN

; ?MOVE -- BLOCKMOVE MEMORY --> MEMORY
; IN:			HL = TO ADDRESS
;			DE = FROM ADDRES
;			BC = COUNTER.
; OUT:			HL & DE POINTING TO THE NEXT BYTES
;                               THAT FOLLOWS THE MOVE.

?MOVE:	LD	A,B		; IS IT ZERO-MOVE?
	OR	C
	RET	Z		; YES...QUIT
	LD	A,(BNKFLG)	; IS ?XMOVE INVOLVED?
	AND	A
	JR	NZ,MOVE1	; YES...JUMP
	EX	DE,HL		; EXCHANGE ADDRESSES TO FIT
	LDIR			; THIS INSTRUCTION.
	EX	DE,HL		; GET THEM BACK.
	RET
MOVE1:	XOR	A		; ZERO ?XMOVE-FLAG
	LD	(BNKFLG),A
	LD	(SRCADR),DE	; SET SOURCE-ADDRESS IN DMA-TABLE
	LD	(DSTADR),HL	; SET DEST-ADDRESS IN DMA-TABLE
	ADD	HL,BC		; HL= END-DEST-ADDRESS.
	PUSH	HL		;     SAVED.
	EX	DE,HL		;
	ADD	HL,BC		; HL= END-SOURCE-ADDRESS
	PUSH	HL		;      SAVED.
	DEC	BC		; REDUCE BLOCK LENGTH WITH 1
	LD	(LENGTH),BC	; CHECK FOR THE DMA COMMAND
	LD	A,B
	OR	C
	LD	A,11001101B	; IF NOT ONE BYTE SET BURST MODE
	JR	NZ,MOVE2
	LD	A,10001101B	; ELSE SET BYTE MODE.
MOVE2:	LD	(MODE),A	; SAVE THE MODE
	LD	HL,(DSTBNK)	;
	LD	A,H		; DEST-BANK IN A.
	RLA			; SHIFT OUT LEFT
	OR	L		; ADD ON SOURCE-BANK.
	AND	00000011B	; MASK ANY FAULTS.
	LD	L,A		; 
	LD	H,0		; PUT THE CODE I HL
	LD	DE,BNKTBL	; OFFSET IN THE TABLE
	ADD	HL,DE		; POINT TO THE RIGHT BYTE
	LD	A,(HL)		; GET IT.
	LD	HL,BNKMSK	; ADD ON BANKMASK
	OR	(HL)
	LD	HL,DMATBL	; POINT TO THE DMA-TABLE.
	DI			; SHUT UP FOR A MOMENT.
	OUT	(BNKMUX),A	; START THE DMA
	CALL	INISTM
	LD	A,B		;
	OR	C
	JR	Z,MOVE4
MOVE3:	IN	A,(DMA)		; READ STATUS
	AND	00100000B	; IS IT READY?
	JR	NZ,MOVE3
MOVE4:	LD	A,DMDISA	; DISABLE DMA
	OUT	(DMA),A
	EI			; SPEAK AGAIN
	POP	DE		; GET THE PARAMETERS BACK
	POP	HL
	LD	BC,0		; COUNTER=0
	RET

; ?XMOVE -- SETS CORRECT BANKS FOR DATA TRANSFERES.
; IN:			B = TO-BANK
;			C = FROM-BANK
; OUT:			NONE.
;

?XMOVE:
	LD	A,TRUE
	LD	(BNKFLG),A	; MARK ?XMOVE
	LD	(DSTBNK),BC	; GIVES (C) IN TO-BANK
				; AND (B) IN FROM-BANK.
	RET

; BNKSEL -- BANKSELECT.
; IN:			A = MEMORY BANK.
;
                                
BNKSEL:	LD	(@CBNK),A	; SAVE CURRENT BANK
	AND	1		; MASK 
	PUSH	HL		; SAVE 
	LD	HL,BNKMSK	; 
	LD	A,BANK0		; START WITH BANK 0.
	JR	Z,BNK1		; BANK0 ?  YES...JUMP
	LD	A,BANK1		; SET BANK 1.
BNK1:	DI			; NOTHING CRAZY MAY HAPPEN NOE
	LD	(HL),A
	OUT	(BNKMUX),A	; SEND TO BANK SELECT PORT
	POP	HL
	EI			; IT WORKED.
	RET
                                
       	PAGE

;********************************************************
;*                     VARIABLES                        *
;********************************************************
	.DEPHASE
	.PHASE		0F96FH	

	CSEG			; MUST BE IN BANK1

@ADRV:	DEFS	1		; SELECTED DISK DRIVE #
@RDRV:	DEFS	1		; CONTROLLER RELATIVE DISK DRIVE#
@TRK:	DEFS	2		; TRACK #
@SECT:	DEFS	2		; SECTOR #
@DMA:	DEFS	2		; DMA ADDRESS
@CNT:	DEFB	0		; RECORD COUNT FOR MULTISECTOR I/O
@DBNK:	DEFB	0		; BANK FOR DMA OPERATIONS
@CBNK:	DEFB	0		; BANK FOR PROCESSOR OPERATIONS
BNKMSK:	DEFB	BANK0		; MASK FOR PROC-/DMA-OPERATIONS.

BNKFLG:	DEFB	0		; FLAG FOR ?XMOV
DSTBNK:	DEFS	1		; DEST-BANK FOR ?XMOVE-?MOVE
SRCBNK:	DEFS	1		; SOURCE-BANK FOR ?XMOVE-?MOVE

BNKTBL:	DEFB	DMBK00		; BANK0 --> BANK0
	DEFB	DMBK10		; BANK1 --> BANK0
	DEFB	DMBK01		; BANK0 --> BANK1
	DEFB	DMBK11		; BANK1 --> BANK1

DMATBL:	DEFB	17,DMA		; 17 BYTES TO DMA
	DEFB	DMDISA		; DISABLE DMA
	DEFB	01111101B	; CR1A: BLOCKLENGTH LOW o. HI FOLLOWS,
				; PORT A START ADDRESS LOW  o. HI
				; FOLLOWS A->B, TRANSFER.
SRCADR:	DEFS	2		; SORCE-ADDRESS (PORT A)
LENGTH:	DEFS	2		; BLOCKLENGTH - 1.
	DEFB	00010100B	; CR1B: PORT ADDR. INC. PORT A-MEMORY.
	DEFB	00010000B	; CR1B: PORT ADDR. INC. PORT B-MEMORY
MODE:	DEFS	1		; CR2B:   BURST/BYTE-MODE
DSTADR:	DEFS	2		; DEST-ADDRESS (PORT B)
	DEFB	10000010B	; CR2A: STOP END-OF-BLOCK
	DEFB	11001111B	; CR2D: LOAD STARTADRESSES FOR BOTH
				; PORTS AND ZERO THE COUNTER.
	DEFB	10001011B	; CR2D: ZERO STATUS-BITS
	DEFB	10110011B	; CR2D: FORCE READY.
	DEFB	DMENAB		; ENABLE DMA
	DEFB	10111111B	; CR2D: SET NEXT READ STATUS.

	DEFB	0		; TABLE END.

XOFFLIST:	DEFB	-1,-1,-1,-1,-1,-1,-1,-1
		DEFB	-1,-1,-1,-1,-1,-1,-1,-1

;***************** BOOT **********************************
;
	CSEG			; BANK1
; ?LDCCP -- IS CALLED FROM BIOSKRNL.Z80 TO LOAD CCP FROM
;           THE FILE CCP.COM. IT WILL BE STORED IN A BUFFER
;           AREA IN BANK1 AND WHEN ?RLCCP IS CALLED IT WILL
;           BE RELOADED TO BANK1 FOR EXECUTION.
; NOTE:     WHEN ?RLCCP IS CALLED BANK1 IS ACTIVE.

?LDCCP:	XOR	A
	LD	(CCP$FCB+15),A
	LD	HL,0
	LD	(FCB$NR),HL
	LD	DE,CCP$FCB	; OPEN FILE 'CCP.COM'
	LD	C,15
	CALL	BDOS
	INC	A		; FILE OPEN?
	JR	NZ,CCPOPEN	; YES...JUMP
CCPERR:	LD	HL,ERRCCP
	LD	A,0		; SET BANK0
	CALL	?BNKSL
	CALL	?PMSG		; WRITE ERROR MESSAGE
	LD	A,1
	CALL	?BNKSL
	LD	C,1		; GET CONSOLE INPUT
	CALL	BDOS
	LD	HL,CRLF
	CALL	?PMSG		; NEW LINE.
	JR	?LDCCP		; TRY AGAIN.

; LOAD CCP FROM 'CCP.COM'

CCPOPEN:
	LD	DE,26		; UP TO 26 SECT. READ
	LD	C,44		; MULTI-SECTOR-COUNT
	CALL	BDOS
	LD	DE,BASE1	; ADDRESS IN BANK1.
	LD	C,26
	CALL	BDOS		; SET DMA ADDRESS
	LD	DE,CCP$FCB
	LD	C,20
	CALL	BDOS		; READ RECORDS.
	CP	1		; ANY ERRORS?
	JR	NZ,CCPERR	; YES...JUMP
CCPOP3:	LD	B,0		; DEST.-BANK
	LD	C,1		; SOURCE-BANK
	CALL	?XMOV
	LD	DE,BASE1	; SOURCE-ADDRESS
	LD	HL,BASE0	; DEST.-ADDRESS
	JR	RLOOP1

; ?RLCCP -- RELOADS CCP FROM BANK0 0000H - 0DFFH TO
;           BANK1 0100H -
;           ?LDCCP USES THE MAIN PART OF THIS ROUTINE
;           TO MOVE CCP FROM BANK1 TO BANK0 ON COLDBOOT.

?RLCCP:	LD	B,1		; DEST.-BANK
	LD	C,0		; SOURCE-BANK
	CALL	?XMOV
	LD	DE,BASE0	; SOURCE-ADDRESS
	LD	HL,BASE1	; DEST.-ADDRESS
RLOOP1:	LD	BC,13*256	; COUNT
	CALL	?MOV
	LD	A,1		; SET BANK1
	JP	?BNKSL

CCP$FCB:
	DEFB	1		; DRIVE A
	DEFB	'CCP     COM'
	DEFB	0		; EX
	DEFB	0		; S1
	DEFB	0		; S2
	DEFB	0		; RC
	DEFW	0,0,0,0		; D0 --
	DEFW	0,0,0,0		; --DN
FCB$NR:	DB	0
	DB	0,0,0
CRLF:	DEFB	CR,LF,0
 
;**************** CHARIO **********************************************
;
	TITLE	'CHARIO.Z80  I/O-HANDLER'

;**********************************************************
;* THIS MODULE TAKES CARE OF ALL CHAR I/O FUNCTIONS FOR   *
;* CP/M 3.0 .                                             *
;* A TABLE OF DEVICE-NAMES IS DEFINED TOGEATHER WITH A    *
;* DEVICE-HANDLER-TABLE WITH ADDRESSES AND ROUTINES.      *
;* THE INTERRUPT-DRIVEN KEYBOARD ROUTINE IS HERE.         *
;*                                                        *
;* THE GLOBAL SUBROUTINE 'INISTM' IS ALSO IN THIS MODULE. *
;**********************************************************
; LATEST CHANGE: 1984-02-29.  PSW.
; BIOSREVISION C.

	.Z80
; SPECIAL CHARACTERS AND CONSTANS:

EOF	EQU	1AH		; CP/M END OF FILE CHAR (^Z)
CTRLC	EQU	'C'-'@'
FALSE	EQU	0
TRUE	EQU	NOT FALSE

MB$INPUT	EQU	00000001B	; DEVICE HANDLES INPUT
MB$OUTPUT	EQU	00000010B	; DEVICE HANDLES OUTPUT
MB$IN$OUT	EQU	MB$INPUT+MB$OUTPUT
MB$SOFTBAUD	EQU	00000100B	; SOFTWARE SELECTABLE BAUD RATE
MB$SERIAL	EQU	00001000B	; DEVICE USES PROTOCOL
MB$XON$XOFF	EQU	00010000B	; XON/XOFF PROTOCOL ON

; PORT-ADDRESSES WITH COMMANDS.

SIO1AD	EQU	0		; MODEM/PRINTER - DATA
SIO1AC	EQU	SIO1AD+1	; MODEM/PRINTER - CONTROL/STATUS
SIO1BD	EQU	SIO1AD+2	; V24,TERMINAL - DATA
SIO1BC	EQU	SIO1AD+3	; V24,TERMINAL - CONTROL/STATUS

SIO2AD	EQU	4		; RS422/NETWORK - DATA
SIO2AC	EQU	SIO2AD+1	; RS422/NETWORK - CONTROL/STATUS
SIO2BD	EQU	SIO2AD+2	; 
SIO2BC	EQU	SIO2AD+3	; 

				; SUPPORTED WITH 1,228,800 Hz
CTC0	EQU	8		; CTC CHAN 0 - BAUDRATE SIO1A/TIMER
CTC1	EQU	CTC0+1		; CTC CHAN 1 - BAUDRATE SIO1B/TIMER
CTC2	EQU	CTC0+2		; CTC CHAN 2 - TIMER TO CTC3 (HALVED)
CTC3	EQU	CTC0+3		; CTC CHAN 3 - REALTIMECLOCK/COUNTER

PIOAD	EQU	0CH		; PIO A DATA - CENTRONICS DATA
PIOAC	EQU	PIOAD+1		; PIO A CONTROL (WRITE ONLY)
PIOBD 	EQU	PIOAD+2		; PIO B DATA - CENTRONICS CTRL
				;            + MODEM CTRL
				; BIT0 CEN. *BUSY
				; BIT1 CEN. *PAPER EMPTY
				; BIT2 CEN. *SELECT
				; BIT3 CEN. *FAULT
				; BIT4 CEN. *STROBE
				; BIT5 CEN. *ACK
				; BIT6 MODEM RING INDICATOR
				; BIT7 MODEM *DSR
PIOBC	EQU	PIOAD+3		; PIO B CONTROL (WRITE ONLY)

SWITCH	EQU	1CH		; READABLE SWITCH
				; BIT5: CONSOLE BAUDRATE
				; xx0xxxxx  9600 BAUD
				; xx1xxxxx 19200 BAUD
				; BIT6: CONSOLE HANDSHAKE
				; x0xxxxxx NO HANDSHAKE
				; x1xxxxxx HANSHAKE

;	ENTRY	?CINIT,?CI,?CO,?CIST,?COST
;	ENTRY	@CTBL
;	ENTRY	INISTM
;	ENTRY	KBDIRQ,UNKINT
;	ENTRY	C0BAUD,C1BAUD,SI1ATBL

;	EXTRN	SIO1IV,CTCIRV
;	EXTRN	@FX,@MXTPA
;	EXTRN	?PMSG
	PAGE
	CSEG			; BANK0
;**********************************************************
;*        NAME TABLE OF THE DEVICES IN THE SYSTEM.        *
;**********************************************************
@CTBL:
	DEFB	'CRT   '	; DEVICE 0, CRT OR CONSOLE
	DEFB	MB$IN$OUT+MB$SERIAL+MB$SOFTBAUD
C0BAUD:	DEFB	14		; 9600 BAUD. WILL BE PATCHED.

	DEFB	'LPT   '	; DEVICE 1, SERIAL LINE PRINTER
	DEFB	MB$IN$OUT+MB$SERIAL+MB$SOFTBAUD
C1BAUD:	DEFB	14		; 9600 BAUD. WILL BE PATCHED.

	DEFB	'CEN   '	; DEVICE 2, CENTRONICS PARALLEL
	DEFB	MB$OUTPUT	; OUTPUT ONLY.
	DEFB	0		; NO BAUDRATE

CTBLEND	EQU	$
	DB	0		; END TABLE

MAX$DEVICES	EQU	(CTBLEND-@CTBL)/8

BDTBL:
	DEFB	-1,0		; 0:  NONE
	DEFB	-1,0		; 1:    50
	DEFB	0,0C4H		; 2:    75
	DEFB	174,0C4H	; 3:   110
	DEFB	143,0C4H	; 4:   134.5
	DEFB	0,84H		; 5:   150
	DEFB	128,84H		; 6:   300
	DEFB	64,84H		; 7:   600
	DEFB	32,84H		; 8:  1200
	DEFB	-1,0		; 9:  1800
	DEFB	16,84H		;10:  2400
	DEFB	-1,0		;11:  3600
	DEFB	8,84H		;12:  4800
	DEFB	-1,0		;13:  7200
	DEFB	4,84H		;14:  9600
	DEFB	2,84H		;15: 19200

	DEFB	1,84H		;16: 38400
	DEFB	1,44H		;17: 76800

BTLKUP:
	AND	0FH		; MASK MAX 15.
	RLA			; *2 FOR TABLE-LOOKUP
	LD	E,A		; INDEX TABLE FOR CTC CONSTANS.
	LD	D,0		; (IF CTC CONST.=0FFH, NO BAUD RATE
	LD	HL,BDTBL
	ADD	HL,DE
	LD	A,(HL)
	CP	-1
	RET	Z		; CANNOT SET THIS BAUD RATE
	INC	HL		; GET SIO BYTE.
	LD	B,(HL)
	RET

	PAGE
; INISTM -- WRITES A NUMBER OF BYTE TO ONE OR MORE PORTS.
; IN:		     HL = TABLE-ADDRESS.
;                    TABLEVIEW (BYTE BY BYTE):
;                    NO OF BYTES, PORT#, BYTE1,...,
;                    NO OF BYTES, PORT#, BYTE1,...,
;                    0 (DETERMINATOR).

INISTM:	LD	A,(HL)		; LOAD BYTE
	OR	A		; IS IT ZERO?
	RET	Z		; YES...TERMINATE
	LD	B,A		; NO...THEN IT IS A BYTE COUNTER.
	INC	HL		; NEXT BYTE, WHICH IS THE PORT#
	LD	C,(HL)		; STORED IN C.
	INC	HL		; POINT TO DATA BYTE1
	OTIR			; SEND (B) BYTES TO PORT (C)
	JR	INISTM		; GO ON.
	PAGE
;********************************************************
;*							*
;*		CONSOLE AND LIST DEVICE I/O		*
;*							*
;********************************************************

; ?CINIT --
; IN:			C = LOGICAL UNIT #
;
; IF THERE IS A PHYSICAL UNIT IN @CTBL FOR THIS LOGICAL UNIT,
; IT WILL BE INITILIZED WITH WITH BAUD RATE BYTE IN THE TABLE.
?CINIT:
	LD	B,C
	INC	B		; MAKE DEVICE # (RELATIVE 1)
	DJNZ	INIT1		; TEST IF DEV# IS 0

; INIT DEVICE 0			; CRT
	LD	HL,SIO1IV	; SET SIOVECTOR
	LD	A,L
	LD	(SIOVEC),A
	LD	HL,CTCIRV	; SET CTCVECTOR
	LD	A,L
	LD	(CTCVEC),A
	IN	A,(SWITCH)	; READ SWITCH
	AND	00100000B	; BIT5 BAUDRATE
	JR	Z,INIT01
	LD	A,15		; 19200 BAUD
	LD	(C0BAUD),A
INIT01:	IN	A,(SWITCH)
	AND	01000000B	; BIT6 HANDSHAKE
	JR	Z,INIT02
	LD	A,11100001B	; Rx 8 BITS, AUTO ENABL., Rx ENABLE
	LD	(HANDSH),A
INIT02:	LD	A,(C0BAUD)
	CALL	BTLKUP
	RET	Z
	LD	(BAUDB),A
	LD	A,B
	LD	(CLKB),A
	LD	HL,SI1BTBL	; POINT TO INIT.TABLE
INSIO:	CALL	INISTM		; SEND TO THE PORT.
	DEC	C		; POINT TO THE DATA PORT
	IN	A,(C)		; CLEAR THE INPUT
	IN	A,(C)		; OF THE SIO.
	RET			; READY

INIT1:	DJNZ	INIT2		; JUMP IF NOT DEV #1.

; INIT DEV #1.			; LPT
	LD	A,(C1BAUD)	; GET CHAR DEVICE 1 BAUD BYTE.
				; CALC BAUD RATE BYTES
INIT1B:	CALL	BTLKUP		; CHECK IN BAUD TABLE
	RET	Z		; NOT COORECT...RETURN
	LD	(BAUDA),A	; SET CTC COUNTER CONSTANT
	LD	A,B		; GET SIO CONSTANT
	LD	(CLKA),A	; SET IT
	LD	HL,SI1ATBL	; POINT TO THE INIT. TABLE
	JR	INSIO		; DO

INIT2:	DJNZ	INIT3		; JUMP IF NOT DEV #2

; INIT DEVICE #2		; CEN
	LD	HL,PIOTBL	; POINT TO THE INIT. TABLE
	CALL	INISTM		; DO

INIT3:	RET			; NO MORE DEVICES.
	PAGE
; ?CI:
; CHAR INPUT FROM DEVICE # IN REGISTER (B).

?CI:
	INC	B		; DEVICE # (RELATIVE 1)
	DJNZ	CI1		; JUMP IF NOT DEVICE #0

; CONIN -- CONSOLE CHAR INPUT. DEVICE #0.
; IN:			NONE.
; OUT:			A = CHAR (PARITY BIT = 0).
;			AF,DE,HL,BC WILL BE CHANGED.
;CONIN:
TTYIN:
	LD	HL,RNGCNT	; POINT TO THE RING BUFFER COUNTER.
	XOR	A		;        ZERO 
CONIN1:	OR	(HL)		; GET IT.
	JR	Z,CONIN1	; LOOP FOR CHAR.
	DI
	DEC	(HL)		; COUNT DOWN
	LD	DE,(RNGOUT)	; GET THE OUTPUT-POINTER
	LD	A,(DE)		; A=OUTPUT CHAR (PARITY RESET).
	AND	07FH		; CLEAR BIT 7
	CP	03H		; CTRL C?
	JR	Z,CONIN2	; YES...JUMP
	CP	11H		; CTRL Q?
	JR	Z,CONIN2	; YES...JUMP
	CP	13H		; CTRL S?
	JR	NZ,CONIN3	; NO...JUMP
CONIN2:	INC	HL		; HL=^C-COUNTER
	DEC	(HL)
CONIN3:	AND	A		; CLEAR CARRY BIT
	LD	HL,RNGEND	; INC RING BUFFER-OUTPUT-POINTER
	SBC	HL,DE		; IS THE BUFFEREND?
	INC	DE		;        (INC)
	JR	NZ,CONIN4	; NO...JUMP
	LD	DE,RNGBEG	; SET BUFFER START
CONIN4:	LD	(RNGOUT),DE	; SAVE THE POINTER.
	EI
	RET

CI1:	DJNZ	CI2		; JUMP IF NOT DEVICE 1

; AUXIN -- GIVES INPUT FROM SIO1 A.
;
; IN:			NONE
; OUT:			A = CHAR.

;AUXIN:
MODIN:	CALL	MODIST		; CHAR IN SIO BUFFER?
	JR	Z,MODIN		; NO...WAIT
	IN	A,(SIO1AD)	; READ CHAR
	RET

CI2:
; CENTRONICS IS DEVICE 2, OUTPUT ONLY.

	LD	A,EOF		; END-OF-FILE-TOKEN.
	RET
	PAGE
; ?CO -- SEND A CHARACTER TO A CHOOSEN DEVICE.
; IN:			B = DEVICE #
;			C = CHAR.

?CO:
	INC	B		; MAKE DEVICE # (RELATIVE 1)
	DJNZ	CO1		; JUMP IF NOT DEVICE 0

; CONOUT -- SIO1B OUTPUT ROUTINE.
;
; IN:			C = CHAR --> SIO1B
; OUT:			A = WRITTEN CHAR.

;CONOUT:
TTYOUT:
	CALL	CNOST		; TEST OUTPUT STATUS
	JR	Z,TTYOUT	; WAIT FOR READY
	LD	A,C
	OUT	(SIO1BD),A
	RET	

CO1:	DJNZ	CO2		; JUMP IF NOT DEVICE 1

; AUXOUT --  SIO1A OUTPUT ROUTINE.
; IN:			C = CHAR --> SIO1A
; OUT:			A = WRITTEN CHAR

;AUXOUT:
MODOUT:
	CALL	MODOST		; TEST OUTPUT STATUS
	JR	Z,MODOUT	; WAIT FOR READY.
	LD	A,C
	OUT	(SIO1AD),A
	RET

CO2:	DJNZ	CO3		; JUMP IF NOT DEVICE 2

; LISTC --  CENTRONICS PARALLEL OUTPUT ROUTINE.
; IN:			C = CHAR --> PIOA
; OUT:			A = WRITTEN CHAR.

LISTC:	LD	A,10H		; STROBE HIGH
	OUT	(PIOBD),A
	
LISTC1:	CALL	LSTTST		; TESTA OUTPUT STATUS
	JR	Z,LISTC1	; VÆNTA TILLS KLAR.
	LD	A,C
	OUT	(PIOAD),A
	LD	A,0H		; STROBE
	OUT	(PIOBD),A
	LD	A,10H		; STROBE HIGH
	OUT	(PIOBD),A
CO3:	RET
	PAGE
; ?CIST -- CHAR INPUT STATUS FROM CHOOSEN DEVICE.
; IN:			B = DEVICE #

?CIST:
	INC	B		; MAKE DEVICE # (RELATIVE 1)
	DJNZ	CIS1		; JUMP IF NOT DEVICE 0.

; CONST -- CONSOLE INPUT STATUS CHECK.
; IN:			NONE
; OUT:			A = 0, Z = 1 IF NO CHAR AVAIL.
;			A = 0FFH, Z = 0 AT LEAST ONE CHAR AVAIL.

;CONST:
XCONST:
	LD	A,(RNGCNT)	; ANY CHAR IN THE BUFFER?
	OR	A
	RET	Z		; NO...RETURN
	OR	0FFH		; YES...SET FLAG
	RET 

CIS1:	DJNZ	CIS2		; JUMP IF NOT DEVICE 1.

; AUXIST -- AUXILIARY INPUT STATUS.
; IN:			NONE
; OUT:			A = 0, Z = 1 IF NOT READY
;			A = 0FFH, Z = 0 IF CHAR AVAIL.

;AUXIST:
MODIST:
	IN	A,(SIO1AC)	; READY STATUS.
	AND	00000001B	; MASK Rx CHAR AVAILABLE
	RET	Z		; NOT READY...RETURN
	OR	0FFH		; MARK CHAR AVAIL
	RET

CIS2:
; DEVICE 2 THE LAST ONE IN THE LIST. CENTRONICS DOES NOT
; HANDLE INPUT. RETURNS NOT READY.

	XOR	A		; NOT READY
	RET

	PAGE
; ?COST -- CHARACTER OUTPUT STATUS FROM CHOOSEN DEVICE.
; IN:			B = DEVICE #.

?COST:
	INC	B		; MAKE DEVICE # (RELATIVE 1)
	DJNZ	COS1		; JUMP IF NOT DEVICE 0.

; CNOST: -- CONSOLE OUTPUT STATUS CHECK.
; IN:			NONE
; OUT:			A = 0, Z = 1 IF NOT READY
;			A = 0FFH, Z = 0 IF READY FOR OUTPUT

CNOST:
	IN	A,(SIO1BC)	; READ STATUS.
	AND	00000100B	; MASK Tx BUFFER EMPTY
	RET	Z		; NOT READY...RETURN
	OR	0FFH		; SET FLAG FOR READY OUTPUT.
	RET

COS1:	DJNZ	COS2		; JUMP IF NOT DEVICE 1.

; AUXOST -- AUXILIARY OUTPUT STATUS.
; IN:			NONE
; OUT:			A = 0, Z = 1 IF NOT READY
;			A = 0FFH, Z = 0 IF READY FOR OUTPUT.

;AUXOST:
MODOST:
	IN	A,(SIO1AC)	; READ STATUS
	AND	00000100B	; MASK Tx BUFFER EMPTY
	RET	Z		; NOT READY...RETURN
	OR	0FFH		; SET FLAG FOR READY OUTPUT.
	RET

COS2:	DJNZ	COS3		; JUMP IF NOT DEVICE 2.

; LSTTST -- PARALLEL PORT TEST IF READY.
; IN:			NONE
; OUT: 			A = 0, Z = 1 IF NOT READY
;			A = 0FFH, Z = 0 IF READY FOR OUTPUT.

LSTTST:
	IN	A,(PIOBD)	; READ ACK AND BUSY.
	AND	00100001B
	CP	00100000B	; READY AND NOT BUSY
	LD	A,0FFH
	JR	Z,LSTT1		; YES...JUMP
	LD	A,0		; SET NOT READY
LSTT1:	AND	A
	RET

COS3:	XOR	A		; NOT READY. CAUSE NO
	RET			; MORE DEVICES.

	PAGE
; KBDIRQ -- CONSOLE KEYBOARD INTERRUPT SERVICE ROUTIN.
; USES LOCAL STACK IN ORDER NOT TO INTERFERE WITH THE
; USER PROGRAM STACK.

KBDIRQ:
	LD	(USRSK2),SP	; OWN STACK
	LD	SP,OWNSK2
	PUSH	AF		; SAVE REGISTERS.
	PUSH	DE
	PUSH	HL
	LD	HL,RNGCNT	; HL --> NO OF CHAR IN BUFFER
	LD	A,(HL)		; A = NO OF CHAR IN BUFFERT
	CP	RNGEND-RNGBEG	; IS BUFFER FULL?
	IN	A,(SIO1BD)	;         A = CHAR (CLR INTERRUPT)
	JR	Z,KBDIR3	; YES...JUST JUMP AND QUIT
	INC	(HL)		; INC CHAR-COUNTER 
	AND	07FH		; MASK PARITY
	CP	13H		; CTRL S?
	JR	Z,KBDIR4	; YES...JUMP
	JP	NC,KBDIR1	; CAN'T BE ^Q,^C...JUMP
	CP	11H		; CTRL Q?
	JR	Z,KBDIR4	; YES...JUMP
	CP	3		; CTRL C?
	JP	NZ,KBDIR1	; NO...JUMP
	LD	(HL),1		; ZERO BUFFER
	INC	HL
	LD	(HL),1
	LD	HL,RNGBEG
	LD	(RNGIN),HL
	LD	(RNGOUT),HL
	JR	KBDIR1
KBDIR4:	INC	HL		; HL --> ^C-COUTER
	INC	(HL)		; INC
	LD	HL,(RNGOUT)
	EX	DE,HL
	LD	HL,RNGBEG
	AND	A
	SBC	HL,DE
	DEC	DE
	JR	NZ,KBDIR7
	LD	DE,RNGEND
KBDIR7:	LD	(DE),A		; SAVE ^Q/S AT BUFFERSTART
	LD	(RNGOUT),DE
	JR	KBDIR3
KBDIR1:	LD	HL,(RNGIN)	; HL --> INPUT
	LD	(HL),A		; SPAR INPUT CHAR IN BUFFER.
	AND	A		; CLEAR CARRY BIT
	EX	DE,HL		; SAVE INPUT POINTER IN DE.
	LD	HL,RNGEND	; HL=BUFFEREND FOR TEST
	SBC	HL,DE		; POINTER AT END?
	INC	DE		;            INC
	JP	NZ,KBDIR2	; NO...JUMP
	LD	DE,RNGBEG	; SET POINTER TO BUFFERSTART
KBDIR2:	LD	(RNGIN),DE	; SAVE THE PEKAREN.
KBDIR3:	POP	HL		; USER REGS. BACK
	POP	DE
	POP	AF
	LD	SP,(USRSK2)	; AND USER STACK.

UNKINT:
	EI			; BACK FROM INTERRUPT.
	RETI

	PAGE
;**********************************************************
;*                    OTHER TABLES                        *
;**********************************************************
; NOTE: THE SIO1-TABLES ARE PATCHES FROM THE LOADER IN
;       BOOT.Z80-MODULE. 
;       IT VERY IMPORTANT THAT SIZE AND ORDER IN THIS
;       TABLES NOT ARE ALTERED.

SI1ATBL:			; MODEM/AUX/PRINTER.
	DEFB	3,CTC0		; 3 BYTES TO CTC CHAN 0
	DEFB	01000101B	; CTC0: INT. DIS, COUNTER MODE,
				; NEG. EDGE, TIME CONST. FOLLOWS,
				; COUNTING CONT.
BAUDA:	DEFB	4		; GIVES 307200 Hz TO SIO1A
CTCVEC:	DEFS	1		; CTCINTERRUPTVECTOR.

	DEFB	9,SIO1AC	; 9 BYTES TO SIO1 A/MODEM
	DEFB	18H		; RESET CHANNEL.
	DEFB	14H		; WR 4:
CLKA:	DEFB	10000100B	; x32 CLOCK, 1 STOP BIT, NO PARITY.
	DEFB	13H		; WR 3:
	DEFB	11100001B	; Rx 8 BITS, AUTO ENABL., Rx ENABLE.
	DEFB	15H		; WR 5:
	DEFB	11101010B	; DTR, Tx 8 BITS, Tx ENABLE, *RTS LOW.
	DEFB	01		; WR 1:
	DEFB	00000000B	; NO INTERRUPTS, UNMODIFIED INTERRUPT
				; VECTOR (BOTH CHANNELS).
	DEFB	0		; END TABLE.

SI1BTBL:
	DEFB	2,CTC1		; 2 BYTES TO CTC CHAN 1
	DEFB	01000101B	; CTC1: INT. DIS, COUNTER MODE,
				; NEG. EDGE, TIME CONST. FOLLOWS,
				; COUNTING CONT.
BAUDB:	DEFB	4		; GIVES 307200 Hz TO SIO1B.

	DEFB	11,SIO1BC	; 11 BYTES TO SIO1 B/TERMINAL
	DEFB	18H		; RESET CHANNEL
	DEFB	12H		; WR 2:
SIOVEC:	DEFS	1		; INTERRUPTVECTOR
	DEFB	14H		; WR 4:
CLKB:	DEFB	10000100B	; x32 CLOCK, 1 STOP BIT, NO PARITY
	DEFB	13H		; WR 3:
HANDSH:	DEFB	11000001B	; Rx 8 BITS, Rx ENABLE.
	DEFB	15H		; WR 5:
	DEFB	11101010B	; DTR, Tx 8 BITS, Tx ENABLE, *RTS LOW
	DEFB	01		; WR 1:
	DEFB	00011000B	; INT ON ALL Rx CHAR (PARITY DOES NOT
				; AFFECT VECTOR)
	DEFB	0		; END TABLE.

	PAGE

; PIO PORT A INIT TABLE

PIOTBL:	DEFB	2,PIOAC		; 2 BYTES TO PIO A CTLR-REG.
	DEFB	00001111B	; SELECT MODE 0 OPERATION
	DEFB	00000011B	; INTERUPT DISABLE.

; PIO PORT B INIT TABLE

	DEFB	4,PIOBC		; 4 BYTES TO PIO B CTRL-REG.
	DEFB	11001111B	; SELECT MODE 3 OPERATION
	DEFB	11101111B	; BIT4=OUTPUT ALL OTHERS INPUTS
	DEFB	00110111B	; INTERRUPT CONTROL WORD = DISABLED
	DEFB	00000001B	; MASK WORD, ONLY MONITOR BIT 0.

; REAL TIME CLOCK INITIALIZATION TABLE

	DEFB	2,CTC2		; 2 BYTES TO CTC CHAN 2
	DEFB	01000101B	; CTC2: INT. DIS, COUNTER MODE,
				; NEG. EDGE, TIME CONST. FOLLOWS,
				; COUNTING CONT.
	DEFB	0		; GIVES 4800 Hz TO CTC3.


	DEFB	2,CTC3		; 2 BYTES TO CTC CHAN 3.
	DEFB	11000101B	; INT. ENABLED, COUNTER MODE
				; NEG. EDGE, TIME CONST. FOLLOWS,
				; COUNTING CONT.
	DEFB	240		; GIVES 20 Hz, WHICH IS DIVIDED
				; BY 2 (HARDWARE).
				; INERRUPT 10 times/second.
	DEFB	0		; END TABLE.


	PAGE

USRSK2:	DEFS	2		; USER STACK SAVED HERE
	DEFS	10H		; LOCAL STACK.
OWNSK2	EQU	$



RNGCNT:	DEFB	0		; NO OF CHAR IN BUFFER
	DEFB	0		; NO OF ^C IN BUFFER

RNGIN:	DEFW	RNGBEG		; POINTS TO INPUT PLACE
RNGOUT:	DEFW	RNGBEG		; POINTS TO OUTPUT PLACE
				; IF EQU BUFFER IS EMPTY.
RNGBEG:	DEFS	82		; KEYBOARD RING BUFFER.
RNGEND	EQU	$-1

;
;*******************************************************************
	TITLE 'FDRIVES.Z80  TABLES FOR DISKETTES'
;*********************************************************
;*                                                       *
;*    DEFINITION MODULE FOR THE FLOPPIES IN THE SYSTEM   *
;*                                                       *
;*********************************************************
; LATEST CHANGE: 1984-02-29.  PSW
; BIOSREVISION C.

	.Z80
TRUE	EQU	0FFH
FALSE	EQU	0

;******************************************************************
;       What kind of floppy system do You want ?

VERIFY	EQU	TRUE		; Verify after write.

M8	EQU	TRUE		; A: 8" 2x77x8x1024, 256 ent. UNIT0
				; B: 8" 2x77x8x1024, 256 ent. UNIT1
				; C: 5" 2x80x5x1024, 128 ent. UNIT0
				; D: 8" 1x77x26x128,  64 ent. UNIT1

M5	EQU	FALSE		; A: 5" 2x77x8x1024, 256 ent. UNIT0
				; B: 5" 2x77x8x1024, 256 ent. UNIT1
				; C: 8" 2x77x8x1024, 256 ent. UNIT0
				; D: 8" 1x77x26x128,  64 ent. UNIT0

M596D	EQU	FALSE		; A: 5" 2x80x5x1024, 128 ent. UNIT0
				; B: 5" 2x80x5x1024, 128 ent. UNIT1
				; C: 8" 2x77x8x1024, 256 ent. UNIT0
				; D: 8" 1x77x26x128,  64 ent. UNIT0

M548D	EQU	FALSE		; A: 5" 2x40x5x1024, 128 ent. UNIT0
				; B: 5" 2x40x5x1024, 128 ent. UNIT1
				; C: 8" 2x77x8x1024, 256 ent. UNIT0
				; D: 8" 1x77x26x128,  64 ent. UNIT0

M548S	EQU	FALSE		; A: 5" 1x40x5x1024,  64 ent. UNIT0
				; B: 5" 1x40x5x1024,  64 ent. UNIT1
				; C: 8" 2x77x8x1024, 256 ent. UNIT0
				; D: 8" 1x77x26x128,  64 ent. UNIT0

; MARK CORRECT FLOPPY SYSTEM WITH TRUE. NOTE ONLY ONE TRUE.
;******************************************************************
	
	PAGE
RATE0	EQU	00000000B	; 3ms/6ms
RATE1	EQU	00000001B	; 6ms/12ms
RATE2	EQU	00000010B	; 10ms/20ms
RATE3	EQU	00000011B	; 15ms/30ms

DOUBLS	EQU	0FFH		; DOUBLE SIDED
SINGLS	EQU	0		; SINGLE SIDED

UNIT0	EQU	00000000B	; FYSISK ENHET 0
UNIT1	EQU	00000001B	; FYSISK ENHET 1
UNIT2	EQU	00000010B	; FYSISK ENHET 2
UNIT3	EQU	00000011B	; FYSISK ENHET 3

INCH5	EQU	00001000B	; 5"-FLOPPY
INCH8	EQU	11010100B	; 8"-FLOPPY

DOUBLD	EQU	00000000B	; DOUBLE DENSITY
SINGLD	EQU	00100000B	; SINGLE DENSITY

COMMON	EQU	0C0H		; COMMON AREA▶8a◀
	IF	M8
SIGN	EQU	'8'
	ELSE
SIGN	EQU	'5'
	ENDIF

;	EXTRN	FDREAD,FDWRIT,FDLGIN,FDINIT
;	ENTRY	@DTBL,?TITEL
;	ENTRY	@COMMO

	CSEG
@DTBL:	DEFW	FLA,FLB,FLC,FLD
	DEFW	0,0,0,0
	DEFW	0,0,0,0
	DEFW	0,0,0,0
@COMMO:	DEFB	COMMON

	PAGE

	CSEG
; DPB for 8" 2x77x8x1024, 256 entries.

F8D:	DEFW	64		; Number of logical sect/track
	DEFB	4,0FH		; BLOCK SKIFT and MASK
	DEFB	0		; EXTENT MASK
	DEFW	607		; MAX BLOCKNUMBER
	DEFW	256-1		; 256 DIR. ENTRIES
	DEFB	0F0H,0		; ALLOC VECTOR TO DIR
	DEFW	256/4		; CHECKSUMMA SIZE
	DEFW	2		; NUMBER OF OFFSET TRACKS
	DEFB	0		; PHYS. SECTOR SIZE
	DEFB	0		; PHYS. SECTOR SHIFT-MASK

	DEFB	0		; Floppy
	DEFB	8		; No. of log.sec./phys. sec.
	DEFB	22		; Read time out
	DEFB	19		; Write time out
	DEFB	0FFH		; Double sided
	DEFB	VERIFY		; Verify after write
	DEFB	RATE0		; Step rate
	DEFB	INCH8+DOUBLD	; Boot select
	DEFB	0,0,0,0,0,0	; Dummies


; DPB for 8" 1x77x26x128, 64 entries. (IBM)

F8S:	DEFW	26		; No. of logical sectors/track.
	DEFB	3,7		; BLOCK SKIFT AND MASK
	DEFB	0		; EXTENT MASK
	DEFW	242		; MAX BLOCKNUMBER
	DEFW	64-1		; 64 DIR. ENTRIES
	DEFB	0C0H,0		; ALLOC VECTOR TO DIR
	DEFW	64/4		; CHECKSUM SIZE
	DEFW	2		; OFFSET TRACK
	DEFB	0		; PHYS.SECTOR SIZE
	DEFB	0		; PHYS. SECTOR SHIFT-MASK

	DEFB	0		; Floppy
	DEFB	1		; No. of logical sectors/phys. sector.
	DEFB	22		; Read time out
	DEFB	19		; Write time out
	DEFB	0		; Single sided
	DEFB	VERIFY		; Verify after write
	DEFB	RATE0		; Step rate
	DEFB	INCH8+SINGLD	; Boot select
	DEFB	0,0,0,0,0,0	; Dummies

	PAGE
; DPB for 5.25" 2x77x8x1024, 256 entries.

F5MAX:	DEFW	64		; No. of logical sectors/track.
	DEFB	4,0FH		; BLOCK SKIFT AND MASK
	DEFB	0		; EXTENT MASK
	DEFW	607		; MAX BLOCKNUMBER
	DEFW	256-1		; 256 DIR. ENTRIES
	DEFB	0F0H,0		; ALLOC VECTOR TO DIR
	DEFW	256/4		; CHECKSUM SIZE
	DEFW	2		; OFFSET TRACKS
	DEFB	0		; PHYS. SECTOR SIZE
	DEFB	0		; PHYS. SECTOR SHIFT-MASK

	DEFB	0		; Floppy
	DEFB	8		; No. of logical sectors/phys. sector.
	DEFB	22		; Read time out
	DEFB	19		; Write time out
	DEFB	0FFH		; Double sided
	DEFB	VERIFY		; Verify after write
	DEFB	RATE0		; Step rate
	DEFB	INCH5+DOUBLD+11000000B	; Boot select
	DEFB	0,0,0,0,0,0	; Dummies


; DPB for 5.25" 2x80x5x1024, 128 entries.

F596D:	DEFW	40		; No. of logical sectors/track.
	DEFB	4,0FH		; BLOCK SKIFT AND MASK
	DEFB	0		; EXTENT MASK
	DEFW	394		; MAX BLOCKNUMBER
	DEFW	128-1		; 128 DIR. ENTRIES
	DEFB	0C0H,0		; ALLOC VECTOR TO DIR
	DEFW	128/4		; CHECKSUM SIZE
	DEFW	2		; OFFSET TRACKS
	DEFB	0		; PHYS. SECTOR SIZE
	DEFB	0		; PHYS. SECTOR SHIFT-MASK

	DEFB	0		; Floppy
	DEFB	8		; No. of logical sectors/phys. sector.
	DEFB	22		; Read time out
	DEFB	19		; Write time out
	DEFB	0FFH		; Double sided
	DEFB	VERIFY		; Verify after write
	DEFB	RATE0		; Step rate
	DEFB	INCH5+DOUBLD	; Boot select
	DEFB	0,0,0,0,0,0	; Dummies

	PAGE
; DPB for 5.25" 2x40x5x1024, 128 entries.

F548D:	DEFW	40		; No. of logical sectors/track.
	DEFB	4,0FH		; BLOCK SKIFT AND MASK
	DEFB	1		; EXTENT MASK
	DEFW	194		; MAX BLOCKNUMBER
	DEFW	128-1		; 128 DIR. ENTRIES
	DEFB	0C0H,0		; ALLOC VECTOR TO DIR
	DEFW	128/4		; CHECKSUM SIZE
	DEFW	2		; OFFSET TRACKS
	DEFB	0		; PHYS: SECTOR SIZE
	DEFB	0		; PHYS. SECTOR SHIFT-MASK

	DEFB	0		; Floppy
	DEFB	8		; No. of logical sectors/phys. sector
	DEFB	22		; Read time out
	DEFB	19		; Write time out
	DEFB	0FFH		; Double sided
	DEFB	VERIFY		; Verify after write
	DEFB	RATE0		; Step rate
	DEFB	INCH5+DOUBLD	; Boot select
	DEFB	0,0,0,0,0,0	; Dummies


; DPB for 5.25" 1x40x5x1024, 64 entries.

F548S:	DEFW	40		; No. of logical sectors/track.
	DEFB	3,7		; BLOCK SKIFT AND MASK
	DEFB	0		; EXTENT MASK
	DEFW	189		; MAX BLOCKNUMBER
	DEFW	64-1		; 64 DIR. ENTRIES
	DEFB	0C0H,0		; ALLOC VECTOR TILL DIR
	DEFW	64/4		; CHECKSUM SIZE
	DEFW	2		; OFFSET TRACKS
	DEFB	0		; PHYS. SECTOR SIZE
	DEFB	0		; PHYS. SECTOR SHIFT-MASK

	DEFB	0		; Floppy
	DEFB	8		; No. of logical sector/phys. sector
	DEFB	22		; Read time out
	DEFB	19		; Write time out
	DEFB	0		; Single sided
	DEFB	VERIFY		; Verify after write
	DEFB	RATE0		; Step rate
	DEFB	INCH5+DOUBLD	; Boot select
	DEFB	0,0,0,0,0,0	; Dummies

	PAGE
?TITEL:	DEFB	'80. '
	DEFB	SIGN,'"-floppy-version. '
	IF	M8
	DEFB	'2x1.2 MBytes.'
	ENDIF
	IF	M5
	DEFB	'2x1.2 MBytes.'
	ENDIF
	IF	M596D
	DEFB	'2x800 KBytes.'
	ENDIF
	IF	M548D
	DEFB	'2x400 KBytes.'
	ENDIF
	IF	M548S
	DEFB	'2x200 KBytes.'
	ENDIF
	DEFB	13,10,0	

TRANS:	DEFB	1,7,13,19,25▶8a◀	DEFB	5,11,17,23
	DEFB	3,9,15,21
	DEFB	2,8,14,20,26
	DEFB	6,12,18,24
	DEFB	4,10,16,22

	title 'System Control Block Definition for CP/M3 BIOS'

;	public @civec, @covec, @aivec, @aovec, @lovec, @bnkbf
;	public @crdma, @crdsk, @vinfo, @resel, @fx, @usrcd 
;       public @mltio, @ermde, @erdsk, @media, @bflgs
;	public @date, @hour, @min, @sec, ?erjmp, @mxtpa


scb$base equ    0F69CH          ; Base of the SCB

@CIVEC  equ     scb$base+22h    ; Console Input Redirection 
                                ; Vector (word, r/w)
@COVEC  equ     scb$base+24h    ; Console Output Redirection 
                                ; Vector (word, r/w)
@AIVEC  equ     scb$base+26h    ; Auxiliary Input Redirection 
                                ; Vector (word, r/w)
@AOVEC  equ     scb$base+28h    ; Auxiliary Output Redirection 
                                ; Vector (word, r/w)
@LOVEC  equ     scb$base+2Ah    ; List Output Redirection 
                                ; Vector (word, r/w)
@BNKBF  equ     scb$base+35h    ; Address of 128 Byte Buffer 
                                ; for Banked BIOS (word, r/o)
@CRDMA  equ     scb$base+3Ch    ; Current DMA Address 
                                ; (word, r/o)
@CRDSK  equ     scb$base+3Eh    ; Current Disk (byte, r/o)
@VINFO  equ     scb$base+3Fh    ; BDOS Variable "INFO" 
                                ; (word, r/o)
@RESEL  equ     scb$base+41h    ; FCB Flag (byte, r/o)
@FX     equ     scb$base+43h    ; BDOS Function for Error 
                                ; Messages (byte, r/o)
@USRCD  equ     scb$base+44h    ; Current User Code (byte, r/o)
@MLTIO	equ	scb$base+4Ah	; Current Multi-Sector Count
				; (byte,r/w)
@ERMDE  equ     scb$base+4Bh    ; BDOS Error Mode (byte, r/o)
@ERDSK	equ	scb$base+51h	; BDOS Error Disk (byte,r/o)
@MEDIA	equ	scb$base+54h	; Set by BIOS to indicate
				; open door (byte,r/w)
@BFLGS  equ     scb$base+57h    ; BDOS Message Size Flag (byte,r/o)  
@DATE   equ     scb$base+58h    ; Date in Days Since 1 Jan 78 
                                ; (word, r/w)
@HOUR   equ     scb$base+5Ah    ; Hour in BCD (byte, r/w)
@MIN    equ     scb$base+5Bh    ; Minute in BCD (byte, r/w)
@SEC    equ     scb$base+5Ch    ; Second in BCD (byte, r/w)
?ERJMP  equ     scb$base+5Fh    ; BDOS Error Message Jump
                                ; (word, r/w)
@MXTPA  equ     scb$base+62h    ; Top of User TPA 
                                ; (address at 6,7)(word, r/o)
;
	.DEPHASE
;
	.PHASE	0A700H
; BOOT
;	DSEG			;; CODE IN BANK0

BOOT:	LD	SP,BOOT$STACK
	CALL	?PATCH		;; PATCH IO-PART FROM LOADER.
	LD	C,0		;; INIT ALL 16 CHARACTER DEVICES
C$INIT$LOOP:
	PUSH	BC
	CALL	?CINIT		;; INIT CHARACTER DEV.
	POP	BC
	INC	C
	LD	A,C
	CP	16
	JR	NZ,C$INIT$LOOP
	CALL	?INIT		;; INIT THE OTHERS

	LD	A,(BOTFLG)	;; SHALL A: BE WINCHESTER ?
	AND	A
	JR	Z,GOON		;; NO...JUMP.
	LD	HL,(@DTBL+4)	;;  GET  C:
	LD	DE,(@DTBL+2)	;;       B:
	LD	BC,(@DTBL)	;;       A:
	LD	(@DTBL),DE	;; B: --> A:
	LD	(@DTBL+2),HL	;; C: --> B:
	LD	(@DTBL+4),BC	;; A: --> C:

; GO ON INIT 16 DISK UNITS.
 
GOON:	LD	BC,16*256+0	;; B=NUMBERS. C= LOG. DRIVE
	LD	HL,@DTBL	;; DRIVE-TABLE

D$IN$LOOP:
	PUSH	BC		;; SAVE NO. & DRIVE
	LD	E,(HL)
	INC	HL
	LD	D,(HL)		;; DE=ADDRESS TO DPH
	INC	HL
	LD	A,E		;; DOES DRIVE EXIST?
	OR	D
	JR	Z,D$IN$NEXT	;; NO...JUMP.
	PUSH	HL		;; SAVE HL 
	EX	DE,HL
	DEC	HL
	DEC	HL
	LD	A,(HL)		;; A=CONTROLLER RELATIVE ADDRESS
	LD	(@RDRV),A
	LD	A,C		;; LOGICAL ADDRESS.
	LD	(@ADRV),A
	DEC	HL
	LD	D,(HL)
	DEC	HL
	LD	E,(HL)		;; DE=INIT ADDRESS
	EX	DE,HL		;; 
	CALL	IPCHL		;; JUMP TO INIT.
	POP	HL		;; HL=DPH POINTER

D$IN$NEXT:
	POP	BC		;; B=NUMBERS. C=DRIVE
	INC	C		;; NEXT DRIVE #
	DJNZ	D$IN$LOOP	;; NEXT DPH-POINTER.
	JP	BOOT$1
;
;	DSEG			;; BANK 0.
;***********************************************************
;*	            DISK-DRIVE-ROUTINES                    *
;***********************************************************

; SELDSK -- SELECT DISK DRIVE. DOES THE LOGIN-PROCEDURE FOR 
;           THE DRIVE IF IT IS THE FIRST TIME SELECT.
; IN:			C = SELECTED DRIVE.
;			E = BIT0 IS 0 IF NOT SELECTED BEFORE
; OUT:			HL = 0 IF SELECTED DRIVE DOES NOT EXIST
;			HL = @DPH IF SELECTED DRIVE EXISTS

SELDSK:	LD	A,C
	LD	(@ADRV),A	;; SAVE #
	LD	L,C		;; CREATE INDEX
	LD	H,0
	ADD	HL,HL		;; HL=2*DRIVE #TO OFFSET
	LD	BC,@DTBL	;; POINT TO DRIVE-TABLE-HEAD
	ADD	HL,BC		;; HL=CORRECT VECTOR IN @DTBL
	LD	A,(HL)		;; GET DPH-POINTER
	INC	HL
	LD	H,(HL)
	LD	L,A		;; HL=DPH-POINTER
	OR	H		;; SET Z-FLAG AND
	RET	Z		;; RETURN IF NO DRIVE
	LD	A,E
	AND	1		;; FIRST SELECT?
	RET	NZ		;; NO...RETURN
	PUSH	HL		;; SAVE DPH-POINTER
	EX	DE,HL
	LD	HL,-2		;; GET (DPH-2)
	ADD	HL,DE
	LD	A,(HL)
	LD	(@RDRV),A	;; SAVE THE CONTROLLER RELATIVE DRIVE#
	LD	HL,-6		;; GET THE LOGIN-VECTOR
	ADD	HL,DE
	LD	A,(HL)
	INC	HL
	LD	H,(HL)
	LD	L,A
	CALL	IPCHL		;; DO LOGIN
	POP	HL		;; HL=DPH-POINTER
	RET
	PAGE
; HOME -- HOME SELECTED DRIVE.  DO SETTRK (0).

HOME:	LD	BC,0		;; TRACK=0

; SETTRK --  SET TRACK ADDRESS.
; IN:			BC = TRACK ADDRESS
; OUT:			@TRK = TRACK ADDRESS

SETTRK:	LD	(@TRK),BC	;; SAVE TRACK ADDRESS
	RET


; SETSEC -- SET SECTOR ADDRESS.
; IN:			BC = SECTOR ADDRESS
; OUT:			@SECT = SECTOR ADDRESS

SETSEC:	LD	(@SECT),BC	;; SAVE SECTOR ADDRESS
	RET

; SETDMA -- SET DIRECT MEMORY ACCESS DISK ADDRESS.
; IN:			BD = DMA ADDRESS
; OUT:			@DMA = DMA ADDRESS
;			@DBNK = @CBNK

SETDMA:	LD	(@DMA),BC	;; SET GLOBAL DMA ADDRESS
	LD	A,(@CBNK)	;; DEFAULT DMA BANK IS CURRENT BANK
				;; GET CURRENT BANK & DO SETBNK

; SETBNK -- SET DISK I/O MEMORY BANK.
; IN:			A = DISK BANK #
; OUT:			@DBNK = DISK BANK #

SETBNK:
	LD	(@DBNK),A	;; SET DISK DMA BANK
	RET

; SECTRN -- SECTOR TRANSLATE. TRANSLATE LOGICAL SECTOR NUMBER TO
; PHYSICAL SECTOR NUMBER.
; IN:			BC = LOGICAL SECTOR #
;			DE = POINTING TO TRANS TABLE
;			     (0 IF NONE)
; OUT:			HL = PHYSICAL SECTOR #.

SECTRN:	LD	L,C		;; 
	LD	H,B		;; HL=CP/M SECTOR # (RELATIVE 0)
	INC	HL		;; HL=   -"-        (RELATIVE 1)
	LD	A,D		;; IS DE=0
	OR	E
	RET	Z		;; YES...RETURN, NO TRANS TABLE
	DEC	HL		;; HL= CP/M SECTOR # (RELATIVE 0)
	ADD	HL,DE		;; HL=INDEX IN TRANS TABLE
	LD	L,(HL)		;; TRANSLATE TO SECTOR # FROM TABLE
	LD	H,0		;; 8 BITS VALUE
	RET

; READ -- READS PHYSICAL SECTOR FROM SELECTED DISK.
; IN:			NONE
; OUT:			A = 0 NO ERROR.
;			A = 1 IF ERROR.
;			A = 0FFH IF MEDIA CHANGE.

READ:	LD	DE,-8		;; INDEX OFFSET TO READ-ROUTINE
	PUSH	DE		;; ON THE STACK
	JR	RW$COMMON	;; READ-WRITE-GEMENSAM.


; WRITE -- WRITES PHYSICAL SECTOR ON SELECTED DISK.
; IN:			C = DEBLOCKING-CODE
; OUT:			A = 0 NO ERRORS.
;			A = 1 PHYSICAL ERROR.
;			A = 2 DISK READ-ONLY
;			A = 0FFH IF MEDIA CHANGE.

WRITE:	LD	DE,-10		;; INDEX OFFSET TO WRITE-ROUTINE
	PUSH	DE		;; ON THE STACK

RW$COMMON:
	LD	HL,(@ADRV)	;; GET DRIVE #
	LD	H,0
	ADD	HL,HL		;; HL=2*DRIVE#
	LD	DE,@DTBL
	ADD	HL,DE
	LD	A,(HL)
	INC	HL
	LD	H,(HL)
	LD	L,A		;; HL=DPH
	POP	DE		;; DE=READ/WRITE
	PUSH	HL		;; SAVE DPH-ADDRESS 
	ADD	HL,DE		;; HL=READ/WRITE IN DPH
	LD	A,(HL)
	INC	HL
	LD	H,(HL)
	LD	L,A		;; HL=READ/WRITE-VECTOR
	POP	DE		;; DE=DPH
	DEC	DE
	DEC	DE
	LD	A,(DE)
	LD	(@RDRV),A	;; A=CONTROLLER RELATIVE DRIVE#
	INC	DE		;; BACK TO DPH
	INC	DE
	JP	(HL)		;; DO THE ROUTINE IN EXTMEM.Z80

; MULTIO -- SET MULTIPLE SECTOR COUNT.
; IN:			A = SECTOR COUNT.
; OUT:			@CNT = MULTIPLE SECTOR COUNT

MULTIO:	LD	(@CNT),A	;; SAVE THE COUNTER.
	RET

; FLUSH --
; NOT INSTALLED.

FLUSH:	XOR	A		;; RETURN NO ERRORS.
	RET
	PAGE

;***************************************************************
;
	TITLE	'BOOT.Z80'

;***********************************************************
;*  THIS MODULE PATCHES THE IO-PARAMETERS FROM THE LOADER  *
;*  TO THE SCB.ASM AND CHARIO.Z80.                         *
;*  IT ALSO LOADS CCP.COM ON COLDBOOT TO A RESERVED AREA   *
;*  IN BANK0 0000H - 0DFFH, FROM WHERE IT WILL BE RELOADED *
;*  TO BANK1 ADDRESS 0100H ON WARMBOOT.                    *
;***********************************************************
; LATEST CHANGE: 1984-02-29.  PSW.
; BIOSREVSION C.

	.Z80
FALSE	EQU	0
TRUE	EQU	NOT FALSE

CR	EQU	13
LF	EQU	10
BDOS	EQU	5		; HOPP-VEKTOR TO CP/M 
BASE1	EQU	100H		; CCP I BANK 1
BASE0	EQU	000H		; CCP I BANK 0.

CIVC	EQU	20H		; IN LOADER
COVC	EQU	22H
LOVC	EQU	24H
AIVC	EQU	26H
AOVC	EQU	28H
C0BD	EQU	2AH		; BAUD DEV#0
C1BD	EQU	2BH		; BAUD DEV#1
S1STRT	EQU	30H		; SIO TABLES 
SILEN	EQU	23H		; LENGTH

;	EXTRN	INTVECT,?PMSG
;	EXTRN	?BNKSL,?MOV,?XMOV
;	EXTRN	@COVEC,@CIVEC,@LOVEC,@AOVEC,@AIVEC
;	EXTRN	C0BAUD,C1BAUD,SI1ATBL

;	ENTRY	?INIT,?PATCH,?LDCCP,?RLCCP

;	EXTRN	?TITEL

	PAGE
;	DSEG			;; BANK 0.
; ?PATCH -- THIS ROUTINE PATCHES THE IO-PARAMETERS 
;           FROM THE LOADER.

?PATCH:	LD	HL,(CIVC)	;; CONSOLE INPUT VECTOR
	LD	(@CIVEC),HL
	LD	HL,(COVC)	;; CONSOLE OUTPUT VECTOR
	LD	(@COVEC),HL
	LD	HL,(LOVC)	;; LIST OUTPUT VECTOR
	LD	(@LOVEC),HL
	LD	HL,(AIVC)	;; AUX INPUT VECTOR
	LD	(@AIVEC),HL
	LD	HL,(AOVC)	;; AUX OUTPUT VECTOR
	LD	(@AOVEC),HL
	LD	A,(C0BD)	;; BAUD DEV#0
	LD	(C0BAUD),A
	LD	A,(C1BD)	;; BAUD DEV#1
	LD	(C1BAUD),A
	LD	HL,S1STRT	;; MOVE SIO TABLES
	LD	DE,SI1ATBL
	LD	BC,SILEN
	LDIR
	RET

; ?INIT -- SET UP INTERRUP VECTOR ENABLE INTERRUPT AND
;          WRITE A PART OF SIGNON MESSAGE.

?INIT:	LD	HL,INTVECT
	LD	A,H		;; LADDA INTERRUPT VEKTOR PAGE
	LD	I,A		;; I Z80 REGISTER I.
	LD	HL,SIGNON	;; SKRIV 1/2 RAD 1 SIGNON.
	CALL	?PMSG
	LD	HL,?TITEL	;; SKRIV 1/2 RAD 1 SIGNON.
	CALL	?PMSG		;; FINNS I DRIVES.Z80
	EI			;; SLÅ PÅ INTERRUPTS 
	RET
;
;**************************** BOOT ********************************
;	DSEG

; MESSAGES IN BANK0.

ERRCCP:	DEFB	'CCP.COM-error. Press <RET> to retry',0
SIGNON:	DEFB	CR,LF
	DEFB	'CP/M Plus Version 3.0 - JET-',0

;
;	DSEG
	IF	M8
; Define 8" 2x77x8x1024, 256 entries. UNIT A:

	DEFW	FDWRIT
	DEFW	FDREAD
	DEFW	FDLGIN
	DEFW	FDINIT
	DEFB	INCH8+UNIT0+DOUBLD
				; $FDXSL
	DEFB	0		; 
FLA:	DEFW	0		; NO TRANS TABLE
	DEFB	0,0,0,0,0,0,0,0,0
	DEFB	0		; MEDIAFLAG
	DEFW	F8D		; ADDRESS T. DPB
	DEFW	0FFFEH		; CHECKSUM VECTOR SET BY GENCPM
	DEFW	0FFFEH		; ALLOC VECTOR SET BY GENCPM
	DEFW	0FFFEH,0FFFEH	; LET GENCPM SETUP
	DEFW	0FFFEH		; DIRBCB, DTABCB, HASH
	DEFB	0		; HASH BANK 


; Define 8" 2x77x8x1024, 256 entries. UNIT B:

	DEFW	FDWRIT
	DEFW	FDREAD
	DEFW	FDLGIN
	DEFW	FDINIT
	DEFB	INCH8+UNIT1+DOUBLD
				; $FDXSL
	DEFB	0		; 
FLB:	DEFW	0		; NO TRANS TABLE 
	DEFB	0,0,0,0,0,0,0,0,0
	DEFB	0		; MEDIAFLAG
	DEFW	F8D		; ADDRESS T. DPB
	DEFW	0FFFEH		; CHECKSUM VECTOR SET BY GENCPM▶8a◀	DEFW	0FFFEH		; ALLOC VECTOR SET BY GENCPM
	DEFW	0FFFEH,0FFFEH	; LET GENCPM SETUP
	DEFW	0FFFEH		; DIRBCB, DTABCB, HASH
	DEFB	0		; HASH BANK

	ENDIF
	PAGE
	IF	M5
; Define 5.25" 2x77x8x1024, 256 entries. UNIT A:

	DEFW	FDWRIT
	DEFW	FDREAD
	DEFW	FDLGIN
	DEFW	FDINIT
	DEFB	INCH5+UNIT0+DOUBLD+11000000B
				; $FDXSL 2 MHz 8" Mode
	DEFB	0		; 
FLA:	DEFW	0		; NO TRANS TABLE
	DEFB	0,0,0,0,0,0,0,0,0
	DEFB	0		; MEDIAFLAGG
	DEFW	F5MAX		; ADDRESS TO DPB
	DEFW	0FFFEH		; CHECKSUM VECTOR GEN BY GENCPM
	DEFW	0FFFEH		; ALLOC VECTOR GEN BY GENCPM
	DEFW	0FFFEH,0FFFEH	; LET GENCPM CALC
	DEFW	0FFFEH		; DIRBCB, DTABCB, HASH
	DEFB	0		; HASH BANK.


; Define 5.25" 2x77x8x1024, 256 entries. UNIT B:

	DEFW	FDWRIT
	DEFW	FDREAD
	DEFW	FDLGIN
	DEFW	FDINIT
	DEFB	INCH5+UNIT1+DOUBLD+11000000B
				; $FDXSL 2 MHz 8" Mode
	DEFB	0		; 
FLB:	DEFW	0		; NO TRANS TABLE
	DEFB	0,0,0,0,0,0,0,0,0
	DEFB	0		; MEDIAFLAGG
	DEFW	F5MAX		; ADDRESS TO DPB
	DEFW	0FFFEH		; CHECKSUM VECTOR GEN BY GENCPM
	DEFW	0FFFEH		; ALLOC VECTOR GEN BY GENCPM
	DEFW	0FFFEH,0FFFEH	; LET GENCPM CALC
	DEFW	0FFFEH		; DIRBCB, DTABCB, HASH
	DEFB	0		; HASH BANK.

	ENDIF

	PAGE
	IF	M596D
; Define 5.25" 2x80x5x1024, 128 entries. UNIT A:

	DEFW	FDWRIT
	DEFW	FDREAD
	DEFW	FDLGIN
	DEFW	FDINIT
	DEFB	INCH5+UNIT0+DOUBLD
				; $FDXSL
	DEFB	0		; 
FLA:	DEFW	0		; NO TRANS TABLE
	DEFB	0,0,0,0,0,0,0,0,0
	DEFB	0		; MEDIAFLAGG
	DEFW	F596D		; ADDRESS TO DPB
	DEFW	0FFFEH		; CHECKSUM VECTOR GEN BY GENCPM
	DEFW	0FFFEH		; ALLOC VECTOR GEN BY GENCPM
	DEFW	0FFFEH,0FFFEH	; LET GENCPM CALC
	DEFW	0FFFEH		; DIRBCB, DTABCB, HASH
	DEFB	0		; HASH BANK.


; Define 5.25" 2x80x5x1024, 128 entries. UNIT B:

	DEFW	FDWRIT
	DEFW	FDREAD
	DEFW	FDLGIN
	DEFW	FDINIT
	DEFB	INCH5+UNIT1+DOUBLD
				; $FDXSL
	DEFB	0		; 
FLB:	DEFW	0		; NO TRANS TABLE
	DEFB	0,0,0,0,0,0,0,0,0
	DEFB	0		; MEDIAFLAGG
	DEFW	F596D		; ADDRESS TO DPB
	DEFW	0FFFEH		; CHECKSUM VECTOR GEN BY GENCPM
	DEFW	0FFFEH		; ALLOC VECTOR GEN BY GENCPM
	DEFW	0FFFEH,0FFFEH	; LET GENCPM CALC
	DEFW	0FFFEH		; DIRBCB, DTABCB, HASH
	DEFB	0		; HASH BANK.

	ENDIF

	PAGE
	IF	M548D

; Define 5.25" 2x40x5x1024, 128 entries. UNIT A:

	DEFW	FDWRIT
	DEFW	FDREAD
	DEFW	FDLGIN
	DEFW	FDINIT
	DEFB	INCH5+UNIT0+DOUBLD
				; $FDXSL
	DEFB	0		; 
FLA:	DEFW	0		; NO TRANS TABLE 
	DEFB	0,0,0,0,0,0,0,0,0
	DEFB	0		; MEDIAFLAG
	DEFW	F548D		; ADDRESS T. DPB
	DEFW	0FFFEH		; CHECKSUM VECTOR SET BY GENCPM
	DEFW	0FFFEH		; ALLOC VECTOR SET BY GENCPM
	DEFW	0FFFEH,0FFFEH	; LET GENCPM SETUP
	DEFW	0FFFEH		; DIRBCB, DTABCB, HASH
	DEFB	0		; HASH BANK


; Define 5.25" 2x40x5x1024, 128 entries. UNIT B:

	DEFW	FDWRIT
	DEFW	FDREAD
	DEFW	FDLGIN
	DEFW	FDINIT
	DEFB	INCH5+UNIT1+DOUBLD
				; $FDXSL
	DEFB	0		; 
FLB:	DEFW	0		; NO TRANS TABLE 
	DEFB	0,0,0,0,0,0,0,0,0
	DEFB	0		; MEDIAFLAG
	DEFW	F548D		; ADDRESS T. DPB
	DEFW	0FFFEH		; CHECKSUM VECTOR SET BY GENCPM
	DEFW	0FFFEH		; ALLOC VECTOR SET BY GENCPM
	DEFW	0FFFEH,0FFFEH	; LET GENCPM SETUP
	DEFW	0FFFEH		; DIRBCB, DTABCB, HASH
	DEFB	0		; HASH BANK

	ENDIF

	PAGE
	IF	M548S

; Define 5.25" 1x40x5x1024, 64 entries. UNIT A:

	DEFW	FDWRIT▶8a◀	DEFW	FDREAD
	DEFW	FDLGIN
	DEFW	FDINIT
	DEFB	INCH5+UNIT0+DOUBLD
				; $FDXSL
	DEFB	0		; 
FLA:	DEFW	0		; NO TRANS TABLE 
	DEFB	0,0,0,0,0,0,0,0,0
	DEFB	0		; MEDIAFLAG
	DEFW	F548S		; ADDRESS T. DPB
	DEFW	0FFFEH		; CHECKSUM VECTOR SET BY GENCPM
	DEFW	0FFFEH		; ALLOC VECTOR SET BY GENCPM
	DEFW	0FFFEH,0FFFEH	; LET GENCPM SETUP
	DEFW	0FFFEH		; DIRBCB, DTABCB, HASH
	DEFB	0		; HASH BANK


; Define 5.25" 1x40x5x1024, 64 entries. UNIT B:

	DEFW	FDWRIT▶8a◀	DEFW	FDREAD
	DEFW	FDLGIN
	DEFW	FDINIT
	DEFB	INCH5+UNIT1+DOUBLD
				; $FDXSL
	DEFB	0		; 
FLB:	DEFW	0		; NO TRANS TABLE 
	DEFB	0,0,0,0,0,0,0,0,0
	DEFB	0		; MEDIAFLAG
	DEFW	F548S		; ADDRESS T. DPB
	DEFW	0FFFEH		; CHECKSUM VECTOR SET BY GENCPM
	DEFW	0FFFEH		; ALLOC VECTOR SET BY GENCPM
	DEFW	0FFFEH,0FFFEH	; LET GENCPM SETUP
	DEFW	0FFFEH		; DIRBCB, DTABCB, HASH
	DEFB	0		; HASH BANK

	ENDIF

	PAGE
; Define UNIT C:
; If M8 it is 5.25" 2x80x5x1024, 128 entries
;          else  8" 2x77x8x1024, 256 entries.

	DEFW	FDWRIT
	DEFW	FDREAD
	DEFW	FDLGIN
	DEFW	FDINIT
	IF	M8
	DEFB	INCH5+UNIT0+DOUBLD ; $FDXSL
	ELSE
	DEFB	INCH8+UNIT0+DOUBLD
	ENDIF
	DEFB	0		; 
FLC:	DEFW	0		; NO TRANS TABLE
	DEFB	0,0,0,0,0,0,0,0,0
	DEFB	0		; MEDIAFLAGG
	IF	M8
	DEFW	F596D		; ADDRESS TO DPB
	ELSE
	DEFW	F8D
	ENDIF
	DEFW	0FFFEH		; CHECKSUM VECTOR GEN BY GENCPM
	DEFW	0FFFEH		; ALLOC VECTOR GEN BY GENCPM
	DEFW	0FFFEH,0FFFEH	; LET GENCPM CALC
	DEFW	0FFFEH		; DIRBCB, DTABCB, HASH
	DEFB	0		; HASH BANK.

; Define 8" 1x77x26x128, 64 entries (IBM). UNIT D:

	DEFW	FDWRIT
	DEFW	FDREAD
	DEFW	FDLGIN
	DEFW	FDINIT
	IF	M8
	DEFB	INCH8+UNIT1+SINGLD ; $FDXSL
	ELSE
	DEFB	INCH8+UNIT0+SINGLD
	ENDIF
	DEFB	0		; 
FLD:	DEFW	TRANS		; TRANS TABLE
	DEFB	0,0,0,0,0,0,0,0,0
	DEFB	0		; MEDIAFLAGG
	DEFW	F8S		; ADDRESS TO DPB
	DEFW	0FFFEH		; CHECKSUM VECTOR GEN. BY GENCPM
	DEFW	0FFFEH		; ALLOC VECTOR GEN. BY GENCPM
	DEFW	0FFFEH,0FFFEH	; LET GENCPM CALC
	DEFW	0FFFEH		; DIRBCB, DTABCB, HASH
	DEFB	0		; HASH BANK.
	PAGE
;
;
«eof»