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

⟦4c516c2a3⟧ TextFile

    Length: 11648 (0x2d80)
    Types: TextFile
    Names: »LDRBIOS.ASM«

Derivation

└─⟦b445f10af⟧ Bits:30004389 CP/M Plus Source files
    └─ ⟦this⟧ »LDRBIOS.ASM« 

TextFile


	TITLE	'LOADER  MODULE FOR CP/M 3.0 BIOS - DATE:831107'
	PAGE 43

	EXTRN	?XMOVE,?MOVE,?BANK,MA3MIR
	Extrn	@DTBL

	PUBLIC	@ADRV,@RDRV,@TRK,@SECT,@DMA,@DBNK,@CNT,@CBNK
	PUBLIC	?PMSG,?PDERR,?PDEC	;
	PUBLIC	@ERMDE
	PUBLIC	DSKTMR,MONCNT

	MACLIB	PORTS			;

	MACLIB	Z80			;

	MACLIB	CPM3			;

	if banked
	ERROR : banked must be equal false
	endif


;EXTERNAL NAMES FOR BIOS ENTRY POINTS

	PUBLIC	?BOOT,?WBOOT,?CONST,?CONIN,?CONO,?LIST,?AUXO,?AUXI
	PUBLIC	?HOME,?SLDSK,?STTRK,?STSEC,?STDMA,?READ,?WRITE
	PUBLIC	?LISTS,?SCTRN
	PUBLIC	?CONOS,?AUXIS,?AUXOS,?DVTBL,?DEVIN,?DRTBL
	PUBLIC	?MLTIO,?FLUSH,?MOV,?TIM,?BNKSL,?STBNK,?XMOV

;BIOS JUMP VECTOR

?BOOT:	JMP	BOOT
?WBOOT:	JMP		DUMMY
?CONST:	JMP		DUMMY
?CONIN:	JMP		DUMMY	
?CONO:	JMP	CONOUT
?LIST:	JMP		DUMMY
?AUXO:	JMP		DUMMY
?AUXI:	JMP		DUMMY
?HOME:	JMP	HOME
?SLDSK:	JMP	SELDSK
?STTRK:	JMP	SETTRK
?STSEC:	JMP	SETSEC
?STDMA:	JMP	SETDMA
?READ:	JMP	READ
?WRITE:	JMP		DUMMY
?LISTS:	JMP		DUMMY
?SCTRN:	JMP	SECTRN
?CONOS:	JMP		DUMMY
?AUXIS:	JMP		DUMMY
?AUXOS:	JMP		DUMMY
?DVTBL:	JMP	DEVTBL
?DEVIN:	JMP		DUMMY
?DRTBL:	JMP	GETDRV
?MLTIO:	JMP	MULTIO
?FLUSH:	JMP	FLUSH
?MOV:	JMP	?MOVE
?TIM:	JMP		DUMMY
?BNKSL:	JMP		DUMMY
?STBNK:	JMP	SETBNK
?XMOV:	JMP		DUMMY

	JMP	0
	JMP	0
	JMP	0

BOOT:
;---
	SSPD	BDOS$SP
	LXI	SP,BOOT$STACK
	CALL	?INIT
	LXI	B,16*256+0
	LXI	H,@DTBL
D$INIT$LOOP:
	PUSH	B
	MOV	E,M ! INX H ! MOV D,M ! INX H
	MOV	A,E 
	ORA	D
	JZ	D$INIT$NEXT
	PUSH	H
	XCHG

	DCX	H   !	DCX	H
	MOV	A,M
	STA	@RDRV
	MOV	A,C
	STA	@ADRV
	DCX	H ! MOV	D,M ! DCX H ! MOV E,M
	XCHG
	CALL	IPCHL
	POP	H
D$INIT$NEXT:
	POP	B
	INR	C
	DCR	B
	JNZ	D$INIT$LOOP
	LSPD	BDOS$SP
	RET

BDOS$SP:	DW	00H

		DS	64
BOOT$STACK:	EQU	$

;***********************************************************************
;	INTERRUPT VECTOR TABLE
;***********************************************************************
	DS	1
CTCINT:
	DW	DMYINT
	DW	DMYINT
	DW	TIMER
	DW	DMYINT

;***********************************************************************

	; DEVTBL	Return address of character device table

devtbl:
	lxi h,@ctbl ! ret

	; GETDRV	Return address of drive table

getdrv:
	lxi h,@dtbl ! ret

	; CONOUT	Console Output.  Send character in <C>
	;			to all selected devices

conout:	

	lhld @covec	; fetch console output bit vector
	jmp out$scan

out$scan:
	mvi b,0		; start with device 0
co$next:
	dad h		; shift out next bit
	jnc not$out$device
	push h		; save the vector
	push b		; save the count and character
not$out$ready:
	call coster ! ora a ! jz not$out$ready
	pop b ! push b	; restore and resave the character and device
	call ?co	; if device selected, print it
	pop b		; recover count and character
	pop h		; recover the rest of the vector
not$out$device:
	inr b		; next device number
	mov a,h ! ora l	; see if any devices left
	jnz co$next	; and go find them...
	ret

coster:		; check for output device ready

	mov l,b ! mvi h,0	; make device code 16 bits
	jmp ?cost		; not a xon device, go get output status direct

;	Utility Subroutines

ipchl:		; vectored CALL point
	pchl

?pmsg:		; print message @<HL> up to a null
		; saves <BC> & <DE>
	push b
	push d
pmsg$loop:
	mov a,m ! ora a ! jz pmsg$exit
	mov c,a ! push h
	call ?cono ! pop h
	inx h ! jmp pmsg$loop
pmsg$exit:
	pop d
	pop b
	ret

?pdec:	; print binary number 0-65535 from <HL>
	lxi b,table10! lxi d,-10000
next:
	mvi a,'0'-1
pdecl:
	push h! inr a! dad d! jnc stoploop
	inx sp! inx sp! jmp pdecl
stoploop:
	push d! push b
	mov c,a! call ?cono
	pop b! pop d
nextdigit:
	pop h
	ldax b! mov e,a! inx b
	ldax b! mov d,a! inx b
	mov a,e! ora d! jnz next
	ret

table10:
	dw	-1000,-100,-10,-1,0

?pderr:
	lxi h,drive$msg ! call ?pmsg			; error header
	lda @adrv ! adi 'A' ! mov c,a ! call ?cono	; drive code
	lxi h,track$msg ! call ?pmsg			; track header
	lhld @trk ! call ?pdec				; track number
	lxi h,sector$msg ! call ?pmsg			; sector header
	lhld @sect ! call ?pdec				; sector number
	ret

;	Disk I/O interface routines

	; SELDSK	Select Disk Drive.  Drive code in <C>.
	;		Invoke login procedure for drive
	;		if this is first select.  Return
	;		address of disk parameter header
	;		in <HL>

seldsk:
	mov a,c ! sta @adrv			; save drive select code
	mov l,c ! mvi h,0 ! dad h		; create index from drive code
	lxi b,@dtbl ! dad b			; get pointer to dispatch table
	mov a,m ! inx h ! mov h,m ! mov l,a	; point at disk descriptor
	ora h ! rz 				; if no entry in table, no disk
	mov a,e ! ani 1 ! jnz not$first$select	; examine login bit
	push h ! xchg				; put pointer in stack & <DE>
	lxi h,-2 ! dad d ! mov a,m ! sta @RDRV	; get relative drive
	lxi h,-6 ! dad d			; find LOGIN addr
	mov a,m ! inx h ! mov h,m ! mov l,a	; get address of LOGIN routine
	call ipchl				; call LOGIN
	pop h					; recover DPH pointer
not$first$select:
	ret

	; HOME		Home selected drive.  Treated as SETTRK(0).

home:
	lxi b,0		; same as set track zero


	; SETTRK	Set Track. Saves track address from <BC> 
	;		in @TRK for further operations.

settrk:
	mov l,c ! mov h,b
	shld @trk
	ret


	; SETSEC	Set Sector.  Saves sector number from <BC>
	;		in @sect for further operations.

setsec:
	mov l,c ! mov h,b
	shld @sect
	ret

	; SETDMA	Set Disk Memory Address.  Saves DMA address
	;		from <BC> in @DMA and sets @DBNK to @CBNK
	;		so that further disk operations take place
	;		in current bank.

setdma:
	mov l,c ! mov h,b
	shld @dma
	lda @cbnk	; default DMA bank is current bank
			; fall through to set DMA bank

	; SETBNK	Set Disk Memory Bank.  Saves bank number
	;		in @DBNK for future disk data
	;		transfers.

setbnk:
	sta @dbnk
	ret

	; SECTRN	Sector Translate.  Indexes skew table in <DE>
	;		with sector in <BC>.  Returns physical sector
	;		in <HL>.  If no skew table (<DE>=0) then
	;		returns physical=logical.

sectrn:
	mov l,c ! mov h,b
	mov a,d ! ora e ! rz
	xchg ! dad b ! mov l,m ! mvi h,0
	ret

	; READ		Read physical record from currently selected drive.
	;		Finds address of proper read routine from
	;		extended disk parameter header (XDPH).

read:
	lhld @adrv ! mvi h,0 ! dad h	; get drive code and double it
	lxi d,@dtbl ! dad d		; make address of table entry
	mov a,m ! inx h ! mov h,m ! mov l,a	; fetch table entry
	push h				; save address of table
	lxi d,-8 ! dad d		; point to read routine address
	jmp rw$common			; use common code

rw$common:
	mov a,m ! inx h ! mov h,m ! mov l,a	; get address of routine
	pop d				; recover address of table
	dcx d ! dcx d			; point to relative drive
	ldax d ! sta @rdrv		; get relative drive code and post it
	inx d ! inx d			; point to DPH again
	pchl				; leap to driver

	; MULTIO	Set multiple sector count. Saves passed count in
	;		@CNT

multio:
	sta @cnt ! ret

	; FLUSH		BIOS deblocking buffer flush.  Not implemented.

flush:
	xra a ! ret		; return with no error

DUMMY:
	RET

	; error message components
drive$msg	db	cr,lf,bell,'BIOS Error on ',0
track$msg	db	': T-',0
sector$msg	db	', S-',0

    ; disk communication data items

@adrv	ds	1		; currently selected disk drive
@rdrv	ds	1		; controller relative disk drive
@trk	ds	2		; current track number
@sect	ds	2		; current sector number
@dma	ds	2		; current DMA address
@cnt	db	1		; record count for multisector transfer
@dbnk	db	1		; bank for DMA operations
@cbnk	db	1		; bank for processor operations

@COVEC  DW	0		; Console Output Redirection 
                                ; Vector (word, r/w)
@ERMDE  DW	0		; BDOS Error Mode (byte, r/o)

;=========================================================================

?INIT:	LXI	H,8000H		;ASSIGN CONSOLE TO CRT
	SHLD	@COVEC		;

	LXI	H,0C200H
	MOV	A,L
	STA	0FFFEH+0AH
	MOV	A,H
	STA	0FFFEH+0AH+1H

	LXI	H,INIT$TABLE	;SET UP MISC. HARDWARE
	CALL	OUT$BLOCKS	;

	CALL	HW$INIT
	RET			;

OUT$BLOCKS:
	MOV	A,M		;GET COUNT VALUE
	ORA	A		;
	RZ			;
	MOV	B,A		;GET COUNT VALUE INTO <B>
	INX	H		;
	MOV	C,M		;GET PORT ADDRESS INTO <C>
	INX	H		;<HL> POINTER TO  OUTPUT VALUE 
	OUTIR			;
	JMP	OUT$BLOCKS	;

INIT$TABLE:
	DB	1,P$DMA$CLEAR,0			;CLEAR DMA
	DB	1,P$DMA$STAT,C$DMA$BYTE		;SET HARDWARE ATTRIBUTES
	DB	4,P$DMA$MODE,88H,85H,82H,83H	;SET CH.0-3 MODE REG.
	DB	00H				;TABLE TERMINATOR

;*************************************************************************
;	I/O AND HARDWARE INITIALIZATION ROUTINE
;***********************************************************************

HW$INIT:

	MVI	A,0FFH		;DELAY 1/4 SECOND FOR ANY
				;UART CHAR IN PROGRESS
	CALL	SDLY
	DI
;
;INIT TIMER

	MVI	A,03H		;INIT ALSO SOFTWARE TIMER
	OUT	P$DMA$INT	;CH0 RESET
	OUT	P$MFD$INT	;CH1 RESET
	OUT	P$SCI$INT	;CH3 RESET
	LXI	H,CTCINT	;
	MOV	A,L		;
	OUT	P$CTC		;
	MVI	A,0A5H		;
	OUT	P$TIM$INT	;CH2 USED AS SOFTWARE TIMER
	MVI	A,195		;...AND BUS TIMER
	OUT	P$TIM$INT	;INTERRUPT EVERY 12.5 MILLISECONDS

;INIT CPU

	MOV	A,H		;CTC INTERRUPT VECTOR TABLE ADDRESS
	STAI			;MOV I,A	INITIALIZE CPU PART OF
	IM2			;IM 2		INTERRUPT LOGIC

	EI			;
	RET			;FINALLY DONE WITH ALL THAT

;***********************************************************************
;	12.5 MSEC. TIMER INTERRUPT SERVICE ROUTINE
;***********************************************************************

MONCNT:	DB	0
DSKTMR:	DB	0

TIMER:
	EXAF
MOTCHK:
	LDA	MA3MIR		;CHECK IF MOTORS IS OFF
	ANI	080H		;MOTENB
	JZ	TIMER1		;
	LDA	DSKTMR		;TEST IF 2 SEC HAS ELAPSED
	ANA	A		;	WITHOUT DISK ACCESS
	JNZ	TIMER1		;
	LDA	MONCNT		;
	INR	A		;
	STA	MONCNT		;
	CPI	03H		;HAVE WE BEEN AT THIS FOR SIX SEC YET
	JNZ	NEXT2		;
	LDA	MA3MIR		;IF SIX SEC HAS ELAPSED
	ANI	0FH		;
	STA	MA3MIR		;
	OUT	P$MAP3		;SHUT OFF MINI MOTOR
	JMP	TIMER1		;
NEXT2:
	MVI	A,160		;160*12.5 mSEC = 2 SEC
	STA	DSKTMR		;SET ANOTHER 2 SEC DELAY

TIMER1:
	LDA	DSKTMR		;GET MINI FLOPPY MOTOR ON COUNTER
	ANA	A
	JZ	TEXIT		;IF NOT TIMED OUT
	DCR	A		;COUNT DOWN
	STA	DSKTMR		;OPDATE MEMORY IMAGE
TEXIT:
	EXAF
DMYINT:				;DUMMY INTERRUPTS CAN ENTER HERE
	EI
	RETI

;----------------------------------------------------------------------

SDLY:
	MVI	L,070H
	DCR	L
	JNZ	$-1
	DCR	A
	JNZ	SDLY
	RET

;=========================================================================

MAX$DEVICE$NO	EQU	01H		;DEVICE 0

?COST:	MOV	A,B		;GET DEVICE NUMBER
	CPI	MAX$DEVICE$NO	;
	JNC	NULL$STATUS	;
	MOV	L,B		;MAKE DEVICE NUMBER 16 BITS
	MVI	H,0		;
	PUSH	H		;
	LXI	D,STAT$PORTS	;
	DAD	D		;MAKE POINTER TO PORT ADDRESS
	MOV	C,M		;
	MVI	A,10H		;RESET EXTERNAL STATUS
	OUTP	A		;
	INP	A		;GET STATUS
	POP	H		;GET DEVICE NUMBER
	PUSH	H		;
	LXI	D,OUT$STAT$MASK	;
	DAD	D		;MAKE POINTER TO MASK
	MOV	C,M		;
	ANA	C		;
	POP	H		;
	LXI	D,OUT$STAT$VALUE;
	DAD	D		;MAKE POINTER TO VALUE
	MOV	C,M		;
	CMP	C		;
	JNZ	NULL$STATUS	;
	ORI	0FFH		;
	RET			;

?CO:	MOV	A,B		;GET DEVICE NUMBER
	CPI	MAX$DEVICE$NO	;
	JNC	NULL$OUTPUT	;
	MOV	A,C		;GET OUTPUT CHARACTER
	PUSH	PSW		;SAVE CHARACTER
	PUSH	B		;
COL:	CALL	?COST		;
	JZ	COL		;
	POP	B		;
	MOV	L,B		;
	MVI	H,0		;MAKE DEVICE NUMBER 16 BITS
	LXI	D,DATA$PORTS	;
	DAD	D		;MAKE POINTER TO PORT ADDRESS
	MOV	C,M		;
	POP	PSW		;GET CHARACTER
	ANI	7FH		;MASK PARITY BIT
	OUTP	A		;
NULL$OUTPUT:
	RET

NULL$STATUS:
	XRA	A
	RET

DATA$PORTS:
	DB	P$CRT$DATA	;
STAT$PORTS:
	DB	P$CRT$STAT	;
OUT$STAT$MASK:
	DB	M$CRT$OUT	;
OUT$STAT$VALUE:
	DB	V$CRT$OUT	;

@CTBL:	DB	'CRT   '	;DEVICE 0
	DB	MB$IN$OUT+MB$SERIAL+MB$SOFT$BAUD
	DB	BAUD$9600	;
				;
	DB	0		;TABLE TERMINATOR

	END
«eof»