DataMuseum.dk

Presents historical artifacts from the history of:

Jet Computer Jet80

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

See our Wiki for more about Jet Computer Jet80

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - download

⟦40b3ed475⟧ TextFile

    Length: 29056 (0x7180)
    Types: TextFile
    Names: »BIOSKRNL.Z80«

Derivation

└─⟦21f5a1bd4⟧ Bits:30003500 CP/M Plus (tm) Version 3.0 BIOS Revision F
    └─ ⟦this⟧ »BIOSKRNL.Z80« 
└─⟦67f37b9ce⟧ Bits:30003503 JET80/W20FT systemdisk
    └─ ⟦this⟧ »BIOSKRNL.Z80« 

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.Asm	Disk defintion module                ;
;			Fdrives.Asm for floppy systems       ;
;			Wdrives.Asm for winchester systems   ;
;	Extmem.Rel	External memory module               ;
;			ExtmemF.Rel for floppy systems       ;
;			ExtmemA.Rel for winchester Adaptec   ;
;			ExtmemX.Rel for winchester Xebec     ;
;	Cntrlr.Rel	Controller commands for Adaptec      ;
;	Scb.Asm		System variables                     ;
;------------------------------------------------------------;
; Latest update: 1985-11-15. PSW
; Bios revision: F

	.Z80
True		Equ	-1
False		Equ	Not True
BotFlg		Equ	0C000h		; Boot flag address
NetWork		Equ	False
WrkStn		Equ	False
	Page	66
; External variables:

	Extrn	@CoVec,@CiVec,@AoVec	; I/O REDIRECTION VECTORS
	Extrn	@AiVec,@LoVec		;       - " -
	Extrn	@MxTpa			; MAX TPA IN USER BANK
	Extrn	@BnkBf			; COMMON 128 BYTE BUFFER

	Extrn	Bank0Call

; Init

	Extrn	?Patch,?Init		; 
	Extrn	?LdCcp,?RlCcp		; LOAD & RELOAD CCP

; User defined character I/O routines:

	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,MuxByte	; CURRENT BANK
	Entry	DmaFlg
	Entry	?PMsg   		; WRITES MESSAGES

; Global 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

; Global lable to userfunction:

	Extrn	?UserF

; Interrupt vectors:

	Entry	Sio1Iv,CtcIrv
	Entry	PioIrv
	Entry	IntVect

; Interrupt driven routines:

	Extrn	KbdIrq,UnkInt,LptIrq,ClkIrq
	If	Not WrkStn
	 Extrn	PioGaI,PioGbI
	Endif
	Extrn	KbdErRq,LptErRq,SetLptBuff
	Page	
; Port address:

					; Dma-COMMANDS
DmRSet		Equ	0C3h		; SOFTWARE RESET
DmEnab		Equ	087h		; ENABLE Dma
DmDisa		Equ	083h		; DISABLE Dma

	If	Not WrkStn
Dma		Equ	18h		; 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)
	Else
Dma		Equ	0F0h		; Dma

BnkMux		Equ	0F4h		; Bank-Dma-MULTIPLEXER
DmBk11		Equ	00000100b	; Bank1 --> Bank1
DmBk00		Equ	00000000b	; Bank0 --> Bank0
DmBk10		Equ	00000110b	; Bank1 --> Bank0
DmBk01		Equ	00000010b	; Bank0 --> Bank1
Bank1		Equ	00100000b	; Bank1 (64K FOR CPU)
Bank0		Equ	00100001b	; Bank0 (48K FOR CPU)
	Endif

CtlQ		Equ	'Q'-'@'
CtlS		Equ	'S'-'@'

MbXonXoff	Equ	00010000B	; XON/XOFF PROTOCOLL ON.

JpOp		Equ	0C3H		; Z80 JUMP INSTRUCTION

Ccp		Equ	100H		; LOAD ADDRESS FOR Ccp
	Page
	Cseg
;------------------------------------------------------------;
;                    Bios Jump Vectors                       ;
;------------------------------------------------------------;

?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
	If	Not WrkStn
	Dw	PioGaI			; GRAPHIC SCREEN READY
	Dw	PioGbI			; GRAPHIC KEY BOARD 
	Else
	Dw	UnkInt			;
	Dw	UnkInt			;
	Endif

CtcIrv	Equ	$			; CTC BASE INTERRUPT VEKTOR
	Dw	UnkInt			; 
	Dw	UnkInt			; 
	Dw	UnkInt			; 
	Dw	ClkIrq			; (10 Hz TICK)

Sio1Iv	Equ	$			; SIO1 BASE INTERRUPT VECTOR
	Dw	KbdIrq			; KEYBOARD INT.
	Dw	KbdIrq			; 
	Dw	KbdIrq			; 
	Dw	KbdErRq			; 
	Dw	LptIrq			; 
	Dw	LptIrq			; 
	Dw	LptIrq			; 
	Dw	LptErRq			; 

	Db	'This area is used as stack by CCP but You '
	Db	'can use it for interrupt vectors when'
	Db	' CCP not in ram  '
Boot$Stack	Equ	$
	Page
;------------------------------------------------------------;
; Boot -- Cold start init. routunes.                         ;
;------------------------------------------------------------;

	Dseg				;; Code in Bank0.

Boot:	Di				;;
	Ld	Sp,Boot$Stack		;;
	Call	?Patch			;; Patch loader parameters
	Ld	Bc,16*256+0		;; B=Counter, C=Dev#.
C_Init_Loop:				;;
	Push	Bc			;;
	Call	?CInit			;; Init char. dev.
	Pop	Bc			;;
	Inc	C			;;
	Djnz	C_Init_Loop		;;
	Call	?Init			;; Init the rest.

	If	Not NetWork

	Ld	A,(BotFlg)		;; Winchester boot?
	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:

	Endif

; Go on init 16 logical disk units.
 
GoOn:	Ld	Bc,16*256+0		;; B=Counter, C=Log. drive#
	Ld	Hl,@DTbl		;; drive table.

D_In_Loop:				;;
	Push	Bc			;; save # and drive.
	Ld	E,(Hl)			;; get DPH-vector
	Inc	Hl			;;
	Ld	D,(Hl)			;; in De.
	Inc	Hl			;;
	Ld	A,E			;; does drive exist ?
	Or	D			;;
	Jr	Z,D_In_Next		;; No...next
	Push	Hl			;; save vector pointer 
	Ex	De,Hl			;;
	Dec	Hl			;; .media byte
	Dec	Hl			;; .controller rel. address
	Ld	A,(Hl)			;; get it
	Ld	(@RDrv),A		;; and save it
	Ld	A,C			;; And save
	Ld	(@ADrv),A		;; logical drive#.
	Dec	Hl			;; Get init-vector
	Ld	D,(Hl)			;;
	Dec	Hl			;;
	Ld	E,(Hl)			;; into De.
	Ex	De,Hl			;; 
	Call	IPcHl			;; execute init.
	Pop	Hl			;; Restore vector pointer.

D_In_Next:				;;
	Pop	Bc			;; Restore counter, drive
	Inc	C			;; Next drive
	Djnz	D_In_Loop		;; Loop...
	Jp	Boot$1			;; Take the last part in Bank1.

	Cseg				; Bank 1.

Boot$1:
	Call	SetJumps		; Set jump vectors
	Call	?LdCcp			; Read Ccp.Com from disk
	Jp	Ccp			; 

;------------------------------------------------------------;
; WBoot -- Warm boot routine.                                ;
;------------------------------------------------------------;

WBoot:
	Ld	Sp,Boot$Stack		;

	Ld	Hl,0			;
	Ld	C,5			; Reset Lpt interrupt buffer
	Call	?UserF			;


	Ld	C,2			;
	Call	?UserF			; Flush floppy/winchester buffers

	Call	SetJumps		; Init page zero
	Call	?RlCcp			; Reread Ccp.Com
	Jp	Ccp			; 

SetJumps:
	Ld	A,1			; Select Bank1
	Call	?BnkSl			;
	Ld	A,JpOp			; Z80 Jp opcode
	Ld	Hl,?WBoot		; Warm Boot entry point
	Ld	(0),A			; 
	Ld	(1),Hl			;
	Ld	Hl,(@MxTpa)		; Bdos entry point
	Ld	(5),A			;
	Ld	(6),Hl			;
Return:	Ret				; 

;------------------------------------------------------------;
; 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 a charcter in (C) to all   ;
;           choosen devices.                                 ;
;------------------------------------------------------------;

ConOut:
	Ld	Hl,ConOutB0		;
	Jp	Bank0Call		;

	Dseg

ConOutB0:				;;
	Ld	Hl,(@CoVec)		;; Get console oputput bit vector
	Jr	OutScan			;;

	Cseg
;------------------------------------------------------------;
; AuxOut -- Auxilliary output. Sends a character in (C) to   ;
;           all choosen devices.                             ;
;------------------------------------------------------------;

AuxOut:
	Ld	Hl,AuxOutB0		;
	Jp	Bank0Call		;

	Dseg

AuxOutB0:				;;
	Ld	Hl,(@AoVec)		;; Get aux output bit vector
	Jr	OutScan			;;

	Cseg
;------------------------------------------------------------;
; List -- List output. Sends a character in (C) to all       ;
;         choosen devices.                                   ;
;------------------------------------------------------------;

List:
	Ld	Hl,ListB0		;
	Jp	Bank0Call		;

	Dseg

ListB0:					;;
	Ld	Hl,(@LoVec)		;; Get list output bit vector
					;; and do OutScan
OutScan:				;;
	Ld	B,0			;; Start with device 0.
CoNext:
	Add	Hl,Hl			;; Shift next device bit
	Jr	NC,NoOutDev		;; Jump...if not set
	Push	Hl			;; Save bit vector
	Push	Bc			;; device and char.
CoOutRdy:				;;
	Call	Coster			;;
	Or	A			;; Ready ? ?
	Jr	Z,CoOutRdy		;; No...jump
	Pop	Bc			;; B=device# C=Char
	Push	Bc			;; save
	Call	?Co			;; Send char
	Pop	Bc			;; Restore
	Pop	Hl			;; 
NoOutDev:				;;
	Inc	B			;; Next device#
	Ld	A,H			;; Any bits left in bit vector
	Or	L			;;
	Jr	Nz,CoNext		;; Yes...loop
	Ret				;;

	Cseg
;------------------------------------------------------------;
; ConoSt -- Console output status. Returns true if all       ;
;           choosen console output devices are ready.        ;
;------------------------------------------------------------;

ConoSt:					;
	Ld	Hl,ConoStB0		;
	Jp	Bank0Call		;

	Dseg

ConoStB0:				;;
	Ld	Hl,(@CoVec)		;; Get console output bit vector
	Jr	OStScan			;;

	Cseg
;------------------------------------------------------------;
; AuxOSt -- Auxiliary output status. Returns true if all     ;
;           choosen aux output devices are ready.            ;
;------------------------------------------------------------;

AuxOSt:					;
	Ld	Hl,AuxOStB0		;
	Jp	Bank0Call		;

	Dseg

AuxOStB0:				;;
	Ld	Hl,(@AoVec)		;; Get aux output bit vector
	Jr	OStScan			;;

	Cseg
;------------------------------------------------------------;
; ListSt -- List output status. Returns true if all choosen  ;
;           list output devices are ready.                   ;
;------------------------------------------------------------;

ListSt:					;
	Ld	Hl,LstStoStB0		;
	Jp	Bank0Call		;

	Dseg

LstStoStB0:				;;
	Ld	Hl,(@LoVec)		;; Get list output bit vector.

OStScan:				;;
	Ld	B,0			;; Start with device #0.
CosNext:				;;
	Add	Hl,Hl			;; Shift next device bit
	Push	Hl			;; save bit vector
	Push	Bc			;; B=dev#, C=Char.
	Ld	A,-1			;; Set dev. ready
	Call	C,Coster		;; Get status if choosen
	Pop	Bc			;; Restore
	Pop	Hl			;; 
	Or	A			;; Ready ?
	Ret	Z			;; No...Return false.
	Inc	B			;; Next device
	Ld	A,H			;; Any more devs. ?
	Or	L			;;
	Jr	Nz,CosNext		;; Yes...loop
	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	MbXonXoff		;; 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,NotQ			;;
	Ld	A,-1			;; SET READY-FLAG
NotQ:	Cp	CtlS			;; CTL-S?
	Jr	Nz,NotS			;; NO...JUMP
	Xor	A			;; CLEAR FLAG
NotS:	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				;;

	Cseg
;------------------------------------------------------------;
; ConSt -- Console input status. Returns true if any choosen ;
;          console input device has a character available.   ;
;------------------------------------------------------------;

ConSt:					;
	Ld	Hl,ConStB0		;
	Jp	Bank0Call		;

	Dseg

ConStB0:				;;
	Ld	Hl,(@CiVec)		;; Get console input bit vector
	Jr	IstScan			;;

	Cseg
;------------------------------------------------------------;
; AuxISt -- Auxialiary input status. Returns true if any     ;
;           Choosen aux input device has a character avail.  ;
;------------------------------------------------------------;

AuxISt:					;
	Ld	Hl,AuxIStB0		;
	Jp	Bank0Call		;

	Dseg

AuxIStB0:				;;
	Ld	Hl,(@AiVec)		;; Get aux input bit vector

IstScan:				;;
	Ld	Bc,0			;; START WITH DEVICE 0
					;; CREG = 0 = FLAG, STATUS Call ONLY
CisNext:				;;
	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,CisNext		;;
	Xor	A			;; ALL CHOOSEN NOT READY. FALSE
	Ret				;;

	Cseg
;------------------------------------------------------------;
; ConIn -- Console input. Returns a character from first     ;
;          ready console device.                             ;
;------------------------------------------------------------;

ConIn:					;
	Ld	Hl,ConInB0		;
	Jp	Bank0Call		;

	Dseg

ConInB0:				;;
	Ld	Hl,(@CiVec)		;; Get console input bit vector
	Call	InScan			;;
	And	7FH			;; strip off parity bit.
	Ret				;;

	Cseg
;------------------------------------------------------------;
; AuxIn -- Auxialiary input. Returns a character from first  ;
;          ready aux input device.                           ;
;------------------------------------------------------------;

AuxIn:					;
	Ld	Hl,AuxInB0		;
	Jp	Bank0Call		;

	Dseg

AuxInB0:				;;
	Ld	Hl,(@AiVec)		;; Get aux input bit vector

InScan:					;;
	Push	Hl			;; SAVE BIT VECTOR
	Ld	B,0			;; START WITH DEVICE 0
	Ld	C,-1			;; CREG = FF = STATUS Call FOR INPUT
CiNext:					;;
	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,CiRdy		;; YES...JUMP
	Inc	B			;; TEST NEXT DEVICE
	Ld	A,H			;;
	Or	L			;;
	Jr	Nz,CiNext		;; 
	Pop	Hl			;; Hl=BIT VECTOR
	Jr	InScan			;; LOOP UNTIL GOT A CHAR
CiRdy:	Pop	Hl			;; Hl=BIT VECTOR
	Jp	?Ci			;; GET INPUT FROM DEVICE # IN B.
	Page
	Cseg
;------------------------------------------------------------;
;                       Subroutines                          ;
;------------------------------------------------------------;

IPcHl:	Jp	(Hl)			; VECTOR-Call

?PMsg:					; Prints a message @(Hl) terminated
					; with Db 0.
	Ld	A,(Hl)			; Get next char
	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			; print it
	Pop	Bc			; Restore
	Pop	De			;
	Pop	Hl			;
	Inc	Hl			; Next byte
	Jr	?PMsg			; Loop...

;------------------------------------------------------------;
; ?Move -- Blockmove: Memory to memory.                      ;
;                                                            ;
; At entry:	Hl = Destination address.                    ;
;		De = Source address.                         ;
;		Bc = Counter.                                ;
; At exit:	Hl & De pointing to the next bytes           ;
;			that follows the move.               ;
;------------------------------------------------------------;

?Move:	Ld	A,B			; Is it a zero-move ?
	Or	C			;
	Ret	Z			; Yes...quit
	Ld	A,(BnkFlg)		; Is ?XMove involved ?
	And	A			;
	Jr	Nz,Move1		; Yes...
	Ex	De,Hl			; Exchange addresses to fit
	Ldir				; this instruction
	Ex	De,Hl			; and get them back.
	Ret				;
Move1:	Di				; Shut up for a moment
	Call	WaitDma			; Wait for Dma
	Xor	A			; Zero ?XMove-flag
	Ld	(BnkFlg),A		;
	Ld	(SrcAdr),De		; Set source address in Dmatable
	Ld	(DstAdr),Hl		; Set destination address in Dmatable
	Add	Hl,Bc			; Hl= End dest.address
	Push	Hl			;     Saved.
	Ex	De,Hl			;
	Add	Hl,Bc			; Hl= End sourceaddress
	Push	Hl			;      saved.
	Dec	Bc			; Reduce blocklength with 1
	Ld	(Length),Bc		; Check for the Dma command
	Ld	A,B			;
	Or	C			;
	Ld	A,11001101b		; If not 1 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 garbidge.
	Ld	L,A			; Will give index
	Ld	H,0			; in table.
	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 Dmatable.
	Out	(BnkMux),A		; Start dma
	Ld	(MuxByte),A		; 
	Push	Bc			; Save counter
	Call	IniStm			;
	Pop	Bc			; Restore counter
	Ld	A,B			;
	Or	C			;
	Jr	Z,Move4			;
Move3:	In	A,(Dma)			; Read status
	And	00100000b		; ready ?
	Jr	Nz,Move3		; No...
Move4:	Ld	A,DmDisa		; Disable Dma
	Out	(Dma),A			;
	Xor	A			; Free Dma
	Ld	(DmaFlg),A
	Ei				; Speak again
	Pop	De			; Restore parameters 
	Pop	Hl			;
	Ld	Bc,0			; COUNTER=0
	Ret				;

;------------------------------------------------------------;
; WaitDma -- Wait until Dma is free, then mark it busy.      ;
;------------------------------------------------------------;

WaitDma:				;
	Ld	A,(DmaFlg)		;
	And	A			;
	Jr	Nz,WaitDma		;
	Inc	A			;
	Ld	(DmaFlg),A		;
	Ret				;

;------------------------------------------------------------;
; ?XMove -- Sets correct banks for data transferes.          ;
;                                                            ;
; At entry:	B = Destination bank.                        ;
;		C = Source bank.                             ;
;------------------------------------------------------------;

?XMove:					;
	Ld	A,True			;
	Ld	(BnkFlg),A		; Mark ?XMove
	Ld	(DstBnk),Bc		; Gives (C) in dest.bank
					; and (B) in source bank.
	Ret				;

;------------------------------------------------------------;
; BnkSel -- Select bank.                                     ;
;                                                            ;
; At entry:	A = Memory Bank.                             ;
;------------------------------------------------------------;
                                
BnkSel:					;
	Di				; Nothing crazy may happen now
	Ld	(@CBnk),A		; Save current bank
	And	1			; mask 
	Ld	A,Bank0			; Start with Bank0.
	Jr	Z,Bnk1			; Bank0 ?  Yes...
	Ld	A,Bank1			; Else set Bank1.
Bnk1:					;
	Ld	(BnkMsk),A		;
	Out	(BnkMux),A		; Send it to Bank select port.
	Ld	(MuxByte),A		;
	Ei				; It worked.
	Ret				;
                                
       	Page
;------------------------------------------------------------;
;	             Disk Drive Routines                     ;
;------------------------------------------------------------;

	Dseg				;; Bank 0.

;------------------------------------------------------------;
; SelDsk -- Select disk drive. Executes the login procedure  ;
;           for the drive if it is the first time select.    ;
;                                                            ;
; At entry:	C = Selected drive.                          ;
;		E = Bit0 reset if not slected before.        ;
; At exit:	Hl = 0 if drives does not exist.             ;
;		Hl = @DPH if 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				;;

;------------------------------------------------------------;
; Home -- Home selected drive. Do SetTrk (0).                ;
;                                                            ;
; SetTrk -- Set track address.                               ;
;                                                            ;
; At entry:	Bc = Track address                           ;
; At exit:	(@Trk) = Track address.                      ;
;------------------------------------------------------------;

Home:	Ld	Bc,0			;; Track=0

SetTrk:	Ld	(@Trk),Bc		;; Save track address
	Ret				;;

;------------------------------------------------------------;
; SetSec -- Set sector address.                              ;
;                                                            ;
; At entry:	Bc = Sector address                          ;
; At exit:	(@Sect) = Sector address.                    ;
;------------------------------------------------------------;

SetSec:	Ld	(@Sect),Bc		;; Save sector address
	Ret				;;

;------------------------------------------------------------;
; SetDma -- Set Direct Memory Access disk address.           ;
;                                                            ;
; At entry:	Bc = Dma address                             ;
; At exit:	(@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.                        ;
;                                                            ;
; At entry:	A = Disk Bank #                              ;
; At exit:	(@DBnk) = Disk Bank #                        ;
;------------------------------------------------------------;

SetBnk:	Ld	(@DBnk),A		;; Set Disk Dma Bank
	Ret				;;

;------------------------------------------------------------;
; SecTrn -- Sector translate. Translate logical sector number;
;           to physical sector number.                       ;
;                                                            ;
; At entry:	Bc = Logical sector #                        ;
;		De = Pointing to TransTable. (0 if none).    ;
; At exit:	Hl = Physical sector #.                      ;
;------------------------------------------------------------;

SecTrn:	Ld	L,C			;; 
	Ld	H,B			;; Hl=CP/M sector # (relative 0)
	Inc	Hl			;; Hl=   -"-        (relative 1)
	Ld	A,D			;; Test De=0
	Or	E			;;
	Ret	Z			;; Yes...Return, no TransTable
	Dec	Hl			;; Hl= CP/M sector # (relative 0)
	Add	Hl,De			;; Hl=Index in table 
	Ld	L,(Hl)			;; Translate to sector # from table
	Ld	H,0			;; 8 bits value
	Ret				;;

;------------------------------------------------------------;
; Read -- Reads physical sector from selected disk to current;
;         @Dma address.                                      ;
;                                                            ;
; At entry:	None                                         ;
; At exit:	A = 0 Ok.                                    ;
;		A = 1 if error.                              ;
;		A =-1 if media change.                       ;
;------------------------------------------------------------;

Read:	Ld	De,-8			;; Index offset to Readroutine
	Push	De			;; on the stack
	Jr	RWCommon		;; Read-Write-Common-Routine

;------------------------------------------------------------;
; Write -- Writes physical sector on selected disk from      ;
;          current @Dma address.                             ;
;                                                            ;
; At entry:	C = Deblocking code.                         ;
; At exit:	A = 0 If Ok.                                 ;
;		A = 1 Physical error.                        ;
;		A = 2 Disk is R/O.                           ;
;		A =-1 If media change.                       ;
;------------------------------------------------------------;

Write:	Ld	De,-10			;; Index offset to Writeroutine
	Push	De			;; on the stack

RWCommon:				;;
	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.                       ;
;                                                            ;
; At entry:	A = Sector count.                            ;
; At exit:	(@Cnt) = Multiple sector count.              ;
;------------------------------------------------------------;

MultIO:	Ld	(@Cnt),A		;; Save the counter.
	Ret				;;

;------------------------------------------------------------;
; Flush -- Flush all disk buffers.                           ;
;------------------------------------------------------------;

Flush:	Ld	C,2			;;
	Call	?UserF			;;
	Xor	A			;; Return no error.
	Ret				;;
	Page
;------------------------------------------------------------;
;                        Variables                           ;
;------------------------------------------------------------;

	Cseg				; MUST BE IN Bank1

@ADrv:		Db	0		; SELECTED DISK DRIVE #
@RDrv:		Db	0		; CONTROLLER RELATIVE DISK DRIVE#
@Trk:		Dw	0		; TRACK #
@Sect:		Dw	0		; SECTOR #
@Dma:		Dw	0		; Dma ADDRESS
@Cnt:		Db	0		; RECORD COUNT FOR MULTISECTOR I/O
@DBnk:		Db	0		; Bank FOR Dma OPERATIONS
@CBnk:		Db	0		; Bank FOR PROCESSOR OPERATIONS
BnkMsk:		Db	Bank0		; MASK FOR PROC-/Dma-OPERATIONS.
MuxByte:	Db	0		; 
DmaFlg:		Db	0		; Dma busy flag
BnkFlg:		Db	0		; FLAG FOR ?XMov
DstBnk:		Db	0		; DEST-Bank FOR ?XMove-?Move
SrcBnk:		Db	0		; SOURCE-Bank FOR ?XMove-?Move

BnkTbl:		Db	DmBk00		; Bank0 --> Bank0
		Db	DmBk10		; Bank1 --> Bank0
		Db	DmBk01		; Bank0 --> Bank1
		Db	DmBk11		; Bank1 --> Bank1

DmaTbl:		Db	23,Dma		; 23 Bytes to Dma
		Db	DmDisa		; DISABLE Dma
		Db	DmRset
		Db	DmRset
		Db	DmRset
		Db	DmRset
		Db	DmRset
		Db	DmRset
		Db	01111101B	; CR1A: BLOCKLENGTH LOW o. HI FOLLOWS,
					; PORT A START ADDRESS LOW  o. HI
					; FOLLOWS A->B, TRANSFER.
SrcAdr:		Dw	0		; SORCE-ADDRESS (PORT A)
Length:		Dw	0		; BLOCKLENGTH - 1.
		Db	00010100B	; CR1B: PORT ADDR. Inc. PORT A-MEMORY.
		Db	00010000B	; CR1B: PORT ADDR. Inc. PORT B-MEMORY
Mode:		Db	0		; CR2B:   BURST/BYTE-Mode
DstAdr:		Dw	0		; DEST-ADDRESS (PORT B)
		Db	10000010B	; CR2A: STOP END-OF-BLOCK
		Db	11001111B	; CR2D: LOAD STARTADRESSES FOR BOTH
					; PORTS And ZERO THE COUNTER.
		Db	10001011B	; CR2D: ZERO STATUS-BITS
		Db	10110011B	; CR2D: FORCE READY.
		Db	DmEnab		; ENABLE Dma
		Db	10111111B	; CR2D: SET NEXT READ STATUS.

		Db	0		; TABLE END.

	Dseg				;; Bank0

XoffList:	Db	-1,-1,-1,-1,-1,-1,-1,-1
		Db	-1,-1,-1,-1,-1,-1,-1,-1

	End
«eof»