	title	'Boot loader module for PROF-80 CP/M 3.0'

	; Letzte Aenderung am:
	; 24.11.1984 (Joachim)

true equ -1
false equ not true

banked	equ true

	public	?init,?ldccp,?rlccp,?time,binit
	extrn	?pmsg,?conin,?cono,?const,?wboot
	extrn	@civec,@covec,@aivec,@aovec,@lovec
	extrn 	@cbnk,?bnksl,?pmsg,?bank,@ctbl
	extrn	@date,@hour,@min,@sec
	extrn	monon,monoff,intser

	maclib	cdef
;
	maclib	monvec
;
	maclib	z80
;
	maclib	syspage
;
	maclib	modebaud

bdos	equ 5

	if banked
tpa$bank	equ 1
	else
tpa$bank	equ 0
	endif

	dseg	; init done from banked memory

?init:
	xra	a ! sta epromz				;
	mvi	a,com$page ! sta common$page		;
	mvi	a,0c3h ! sta 38h			; interuppt in
	lxi	h,intser ! shld 39h			; bank 0

	lxi h,xwboot ! shld umleit$getcm + 1		; setze umleit
	lxi h,xconst ! shld umleit$const + 1		; vektoren
	lxi h,xconin ! shld umleit$conin + 1		;
	lxi h,xcono ! shld umleit$conout + 1		;

	lda	io$jumperbyte		; waehle richtige Voreinstellung
	cpi	4 ! jrz io4		; der Geraetetreiber
	cpi	3 ! jrz io3		; in Abhaengigkeit des IO Jumpers
	cpi	2 ! jrz io2
	cpi	1 ! jrz io1

io0:	lxi h,00800h ! lxi d,00400h ! lxi b,08000h ! jr ioset	; j4 kein jumper 
io1:	lxi h,08000h ! lxi d,04000h ! lxi b,08000h ! jr ioset	; j4/1-3
io2:	lxi h,02000h ! lxi d,04000h ! lxi b,08000h ! jr ioset	; j4/2-4
io3:	lxi h,01000h ! lxi d,04000h ! lxi b,08000h ! jr ioset	; j4/3-5
io4:	lxi h,00800h ! lxi d,00400h ! lxi b,08000h		; j4/4-6

ioset:	shld @civec ! shld @covec
	sded @lovec
	sbcd @aivec
	sbcd @aovec


	lda bank$err$byte	;sind beide RAM banks ok?
	ora a ! jrz twobank	;sprung wenn ja

	lxi h,ramtext ! call ?pmsg	;sonst fehlermeldung
ramfail	jr ramfail


ramtext	db 13,10,'error, CP/M 3 needs 128k RAM on PROF-80',13,10,0

twobank	lxi h,signon$msg ! call ?pmsg			; print signon message
	ret

signon$msg:	db	13,10,13,10
		db	'PROF-80 CP/M Version 3, sample BIOS  '
		db	'(C) 24.11.1984  Digital Research & Conitec'
		db	13,10,0


binit:
	lda	baud$jumperbyte		; setze duplex baudrate
	mov	l,a ! mvi h,0		; entsprechend j4
	lxi	d,j4baudlist ! dad d	;
	mov	a,m ! sta @ctbl+7	;
	ret				;

j4baudlist:
	db	baud$9600
	db	baud$4800
	db	baud$2400
	db	baud$1200
	db	baud$300


	cseg
	
	; diese Routinen werden vom EPROM benutzt

xwboot:
	mvi a,1 ! sta epromz
	call monoff ! jmp ?wboot

xconst:
	push b ! push d ! push h
	call ?const
	pop h ! pop d ! pop b ! ret

xconin:
	push b ! push d ! push h
	call ?conin
	pop h ! pop d ! pop b ! ret

xcono:
	push b ! push d ! push h
	call ?cono
	pop h ! pop d ! pop b ! ret

	
	; Laden des CCP.COM von Drive A:

?ldccp:
	mvi	a,0c3h ! sta 38h	;setze interuppt vektor
	lxi	h,intser ! shld 39h	;in bank 1

	; First time, load the A:CCP.COM file into TPA
	xra a ! sta ccp$fcb+15		; zero extent
	lxi h,0 ! shld fcb$nr		; start at beginning of file
	lxi d,ccp$fcb ! call open	; open file containing CCP
	inr a ! jz no$CCP		; error if no file...
	lxi d,0100h ! call setdma	; start of TPA
	lxi d,128 ! call setmulti	; allow up to 16k bytes
	lxi d,ccp$fcb ! call read	; load the thing
					;
	lxi b,070h*256+p$ram$table	; schalte bank1 f000h
	mvi a,0bh ! outp a		; nach 7000h
	lxi h,0100h ! lxi d,07000h	; und kopiere
	lxi b,0c80h ! ldir		;
	lxi b,070h*256+p$ram$table	;
	mvi a,2 ! outp a		;
					;
	ret

no$CCP:			; here if we couldn't find the file
	lxi h,ccp$msg ! call ?pmsg	; report this...
	call ?conin			; get a response
	jmp ?ldccp			; and try again


?rlccp:	mvi	a,0c3h ! sta 38h	;setze interrupt sprung
	lxi	h,intser ! shld 39h	;in bank 1 neu

	lxi b,070h*256+p$ram$table	; 
	mvi a,0bh ! outp a		;
	lxi d,0100h ! lxi h,07000h	; kopiere
	lxi b,0c80h ! ldir		; ccp
	lxi b,070h*256+p$ram$table	;
	mvi a,2 ! outp a		;
	ret

	dseg
?time:
	push	h
	push	d
	mov	a,c	;lesen oder setzen
	ora	a	;seze flags
	jz	set$scb	;setze scb neu
			;setze zeit neu
	;berechne aus der absolutem zahl das datum
	lhld	@date	;lese datumszahl aus scb
	lxi	d,730	;setze auf 1 jan. 1980
	jc	time$ret;zeit vor 1980, keine aenderung
	stc ! cmc	;loesche carry bit
	dsbc	d	;subtrahiere
	mvi	c,0	;zaehler fuer jahreszahl nach 1980
year$loop:
	lxi	d,366	;ziehe schaltjahr ab
	call	sub$end	;
	lxi	d,365	;ziehe drei normale jahre ab
	call	sub$end	;
	call	sub$end	;
	call	sub$end	;
	jr	year$loop	;beginne wieder von vorn

sub$end:
	stc ! cmc	;loesche  carry bit
	dsbc	d	;ziehe de von hl ab
	jrc	sub$end1
	inr	c	;jahr  zaehler um eins weiter
	ret

sub$end1:		;ok jahreszahl ist berrechnet
	inx	sp	;setze stack richtig
	inx	sp	;
	dad	d	;in hl jetzt die tage des verbleibenden jahres
	mov	a,c	;speichere jahr ab
	sta	jahr	;
	call	set$feb	;setze februar bei schaltjahr auf 29 sonst 28
			;berechne monat
	lxi	d,monat$list
	mvi	b,0	;
monat$loop:
	ldax	d	;lade monats anzahl
	mov	c,a	;setze de
	stc ! cmc	;loesche carry
	dsbc	b	;ziehe monat ab
	jrc	monat$loop$end	;wenn carry, monat erreicht
	inx	d	;zeige auf naechsten monat
	jr	monat$loop
monat$loop$end:
	dad	b	;monat wieder dazu
	mov	a,l	;speichere tag ab
	sta	tag	;
	xchg		;berrechne monatszahl aus d
	lxi	d,monat$list
	stc ! cmc
	dsbc	d	;in l steht jetzt monat ab 0
	mov	a,l
	inr	a	;speichere monat ab. jan=1,.. dez=0ch
	sta	monat	;
			;ok, datum ist berrechnet
	rlc		;bringe monat in die oberen 4 bit
	rlc
	rlc
	rlc
	ani	0f0h
	sta	phys$time+4	;lege monat ab
	lda	tag		;lege tag ab
	call	bindez		;wandle in bcd zahl
	sta	phys$time+3
	lda	@hour		;lege sunde ab
	sta	phys$time+2
	lda	@min		;lege minute ab
	sta	phys$time+1
	lda	@sec		;lege sekunde ab
	sta	phys$time
	
	call	set$phys$time	;setze zeit, und lese shiftreg aus

	lda	jahr		;speichere jahr im shiftregister
	ani	01fh		;nur fuenf bits vom jahr
	mov	b,a
	lda	shift$cont+4	;rette ober 3 bits dieser zelle
	ani	0e0h
	ora	b		;packe jahr dazu
	sta	shift$cont+4
	
	call	set$shift	;lade shiftregister zurueck

time$ret:
	pop	d
	pop	h
	ret

set$scb:
		; setze das datum und die uhrzeit im
		; system control block
		;
	call	read$phys$time	;lese die uhr aus
	lda	shift$cont+4	;lese jahres offset
	call	set$feb		;setze februar entspr.
		; berechne absolute tageszahl
	lxi	h,0
	lda	phys$time+3	;lese tag ein
set$scb1:			;und wandle in binaerzahl
	inx	h		;erhoehe h um eins
	dcr	a		;akku eins dezimal weniger
	daa
	jrnz	set$scb1
				;in hl steht jetzt der tag
	lda	phys$time+4	;lade monat
	rrc			;schieb 4 bit nach rechts
	rrc
	rrc
	rrc
	ani	0fh		;monat steht in den untern 4 bit
	lxi	d,monat$list	;zeiger auf die liste mit den monatstagen
	mvi	b,0
set$scb2:
	dcr	a		;ende der monats addition?
	jrz	set$scb3
	push	psw		;rette akku
	ldax	d
	mov	c,a
	pop	psw
	dad	b		;monat zu hl
	inx	d		;zeiger auf naechsten monat
	jr	set$scb2
set$scb3:			;die tage des laufenden jahres sind in hl
	lda	shift$cont+4	;lade jahres offset zu 1980
	ani	1fh		;nur die untern 5 bits fuer jahres offset
	lxi	d,365		;fuer jedes jahr 365 tage
	mov	b,a		;b dient als zaehler
	ora	a
	jrz	set$scb6	;wenn jahreszahl=0
set$scb4:
	mov	a,b		;wenn schaltjahr, ein tag mehr
	ani	3		;schaltjahr wenn untere 2 bits 01
	cpi	1		;
	jrnz	set$scb5	;sprung wenn kein schaltjahr
	inx	h		;ein tag mehr
set$scb5:
	dad	d		;365 tage dazu
	djnz	set$scb4	;addiere fuer alle jahre
set$scb6:			;in hl jetzt offset ab 1 jan 1980
	lxi	d,730		;berechene offset ab 1 jan 1978
	dad	d		;ok
	shld	@date		;ab, in scb
				;
				;uebertrage noch uhrzeit
	lda	phys$time	;sekunden
	sta	@sec		;
	lda	phys$time+1	;minuten
	sta	@min		;
	lda	phys$time+2	;stunden
	sta	@hour		;
	jmp	time$ret	;alles ok



bindez:	;binaer dezimalwandlung im akku
	ora	a	;akku=0
	rz		;alles ok
	push	b	;rette bc
	mov	b,a	;b=zaehler
	xra	a	;akku=0
bindez1	inr	a	;akku=akku+1
	daa		;dez. korr.
	djnz	bindez1
	pop	b
	ret

set$feb:
	;pruefe ob in akku schaltjahr
	;dann setze tage im februar auf 29
	;sonst auf 28
	ani	3	;untere 2 bits null
	mvi	a,29
	jrz	set$feb1
	mvi	a,28	;kein schaltjahr, 28 tage
set$feb1:
	sta	monat$list+1	;speichere im februar ab
	ret

monat$list:
	; liste der tage im monat
	; erster eintrag fuer jan. dann feb usw.
	db	31,28,31,30,31,30
	db	31,31,30,31,30,31


; routinen zum ein und auslesen der uhrzeit
; fuer den upd 1990


set$phys$time:
	call	monon
	call	mset$phys$time
	call	monoff
	ret

read$phys$time:
	call	monon
	call	mread$phys$time
	call	monoff
	ret

set$shift:
	call	monon
	call	mset$shift
	call	monoff
	ret

jahr	ds	1
monat	ds	1
tag	ds	1


	cseg

	; CP/M BDOS Function Interfaces

open:
	mvi c,15 ! jmp bdos		; open file control block

setdma:
	mvi c,26 ! jmp bdos		; set data transfer address

setmulti:
	mvi c,44 ! jmp bdos		; set record count

read:
	mvi c,20 ! jmp bdos		; read records


ccp$msg		db	13,10,'BIOS Err on A: No CCP.COM file',0


ccp$fcb		db	1,'CCP     ','COM',0,0,0,0
		ds	16
fcb$nr		db	0,0,0


	end
