



;
	title	'C128 BIOS, main I/O and sys functions     28 Apr 86'

;
;	This module contains CXIO,CXINIT,CXMOVE and CXTIME.
;
	maclib	cpm3

	maclib	z80

	maclib	cxequ

	maclib	modebaud


	public	?init,?ldccp,?rlccp

	public	?user,?di$int

	extrn	?sysint

bdos	equ	5	

	extrn	@civec,@covec,@aivec,@aovec,@lovec
	extrn 	?bnksl

	public	?cinit,?ci,?co,?cist,?cost,?kbin,?kbstat
	public	?out$RS232,?out$st$RS232,?in$RS232,?in$st$RS232
	public	?init$RS232
	public	@ctbl
	extrn	?kyscn

; Utility routines in standard BIOS
	extrn	?wboot		; warm boot vector
	extrn	?pmsg		; print message @<HL> up to 00
				; saves <BC> & <DE>
	extrn	?pdec		; print binary number in <A> from 0 to 99.
	extrn	?pderr		; print BIOS disk error header
	extrn	?conin,?cono	; con in and out
	extrn	?const		; get console status

	extrn	@hour,@min,@sec,@date,?bnksl

;       public	bios$stack

	public	?time

	page
;
;	keyboard scanning routine 
;
	extrn	?get$key,?int$cia
	extrn	Fx$V$tbl
;
;	links to 80 column display
;
	extrn	?out80,?int80,start$checking
	extrn	?out40,?int40

	extrn	?pt$i$1101,?pt$o$1,?pt$o$2
	extrn	?convt,?cnvt$none
	extrn	?pt$s$1,?pt$s$2

;
;	bios8502 function routines
;
	public	?fun65

;
;
;
	public	?intbd
	extrn	?int65,?in65,?ins65,?out65,?outs65

;	cseg
;trace:
;	xthl			; save hl on stack
;	push	psw
;	call	?pmsg		; DE and BC saved by ?pmsg
;	pop	psw
;	xthl
;	ret
;
;	CSEG
;disp$A:
;	push	psw		;;;test
;	ani	0fh		;;;test
;	adi	90h		;;;test
;	daa			;;;test
;	aci	40h		;;;test
;	daa			;;;test
;	sta	low$test	;;;test
;	pop	psw		;;;test
;	rar			;;;test
;	rar			;;;test
;	rar			;;;test
;	rar			;;;test
;	ani	0fh		;;;test
;	adi	90h		;;;test
;	daa			;;;test
;	aci	40h		;;;test
;	daa			;;;test
;	sta	hi$test		;;;test
;	call	trace		;;;test
;hi$test:			;;;test
;	db	31		;;;test
;low$test:			;;;test
;	db	31		;;;test
;	db	' '		;;;test
;	db	0		;;;test
;	ret			;;;test
;
	page

	DSEG
?fun65:
	sta	vic$cmd			; save the command passed in A
	call	?di$int                 ; cleanly disable int
	lda	force$map		; get current MMU configuration
	push	psw			; save it
	sta	io$0			; make I/O 0 current

	lxi	d,1			; D=0,  E=1
   if	use$fast
	lxi	b,VIC$speed
	inp	a
	sta	sys$speed
	outp	d			; set slow mode (1 2 MHz Z80)
   endif
	lxi	b,page$1$h
	outp	d
	dcr	c
	outp	e			; page 1, 0-1
	dcr	c
	outp	d
	dcr	c
	outp	d			; page 0, 0-0
	call	enable$6502+6		; go run the 8502
	mvi	c,low(page$1$h)
	outp	e
	dcr	c
	outp	e			; page 1, 1-1
	dcr	c
	outp	e
	dcr	c
	outp	d			; page 0, 1-0
   if	use$fast
	lxi	b,VIC$speed
	lda	sys$speed		; get desired system speed
	outp	a			; set speed (2 or 4 MHz Z80)
   endif
	pop	psw			; recover the MMU config.
	sta	force$map		; restore it
	ei				; turn interrupts back on
	lda	vic$data		; get command results
	ora	a			; set the zero flag if A=0
	ret

?di$int:
   if	not use$6551
	push	psw
di$int$1:
	lda	RS232$status		; character to Xmit or currently
	ani	11000010b		; ..transmitting or receiving ?
	jrnz	di$int$1		; yes, wait for int to clean up
	pop	psw
   endif
	di
	ret

	page
;
;	set up the MMU for CP/M Plus
;
	DSEG			; init done from banked memory
?init:
	mvi	a,3eh			; force MMU into I/O space
	sta	force$map		;
	lxi	h,mmu$table+11-1	; table of 11 values
	lxi	b,mmu$start+11-1	; to to MMU registers
	mvi	d,11			; move all 11 bytes to the MMU

init$mmu$loop:
	mov	a,m
	outp	a
	dcx	h
	dcx	b
	dcr	d
	jrnz	init$mmu$loop

	xra	a			; disable track and sector status
	sta	stat$enable		; on the status line
	inr	a			; no parity, 8 bits, 1 stop bit
	sta	XxD$config
;
   if	use$6551
	lxi	h,int$6551
   else
	lxi	h,usart
   endif
	shld	usart$adr

	lxi	h,?cnvt$none
	shld	prt$conv$1
	lxi	h,?convt
	shld	prt$conv$2

	lxi	h,Fx$V$tbl
	shld	key$FX$function
;
; install I/O assignments
;
	lxi	h,start$checking
	shld	parm$area$80
	shld	parm$area$40
	lxi	h,4000h+2000h 		; 80 and 40 column drivers
	shld	@covec
	mvi	h,80h
	shld	@civec			; assign console input to keys
	mvi	h,10h
	shld	@lovec			; assign printer to LPT:
    if	use$6551                        ; assign 6551 or RS232 to rdr/pun
	mvi	h,04h
    else
	mvi	h,02h
    endif
	shld	@aivec
	shld	@aovec                 

	page
;
; print sign on message
;
	mov	c,l                     ; (C=0)
	call	?out40
	call	prt$msg			; print signon message
	db	'Z'-'@'			; initialize screen pointers
	db	esc,esc,esc
	db	lt$grey+50h             ; set character color
	db	esc,esc,esc
	db	blue+60h                ; set background (BG) color
	db	esc,esc,esc
	db	black+70h               ; set border color
	db	'Z'-'@'			; home and clear screen (to BG color)

;	db	lf,lf,lf
    if	use$fast
	db	'Fast '
    endif

    if	use$6551
	db	'/w 6551 '
    endif

	db	esc,'=',2+20h,8+20h,'CP/M 3       Version 3.0'
    if	not banked
	db	' Non-Banked'
    endif
;	db	' on the Commodore 128  '
;	date
	warning
	db	cr,lf,lf,lf,0
;	db	'          ',0

;
;	set CONOUT driver to correct screen
;
	lxi	h,2000h			; 40 column screen vector
	call	read$d505
	ral
	jrc	set$screen
;	mvi	a,'8'
;	sta	screen$num
	mvi     h,40h			; 80 column screen vector

set$screen:
;	call	prt$msg			; HL saved
screen$num:
;	db	'40 column display',cr,lf,lf,lf,lf,0
	shld	@covec			; assign console output to CRT: (40/80)

	page

;
;
	mvi	a,-1			; set block move to NORMAL mode
	sta	source$bnk
;
;	install mode 2 page vectors
;
	mvi	a,JMP
	sta	INT$vector		; install a JMP at vector location
	lxi	h,?sysint
	shld	INT$vector+1		; install int$handler adr
;
; A software fix is  required for the lack of hardware to force the
; LSB of the INT vector to 0. If the bus floats INT VECT could be
; read as 0FFh; thus ADRh=I (I=0FCh) ADRl=FF for first read, and
; ADRh=I+1 ADRl=00 for second, to ensure that control is retained
; 0FD00h will also have FDh in it.
;
	lxi	h,int$block		; FC00h
	lxi	d,int$block+1		; FC01h
	lxi	b,256-1+1		; interrupt pointer block
	mvi	m,INT$vector/256	; high and low are equal (FD)
	ldir
	mvi	a,INT$block/256
	stai				; set interrupt page pointer
	im2				; enable mode 2 interrupts

	page
;
;
	mvi	a,vicinit		; null command just to setup BIOS8502
	call	?fun65
;
;
;
	lda	sys$freq		; 0=60Hz 0FFh=50Hz
	ani	80h			; 0=60Hz 080h=50Hz
	mov	l,a			; save in L
	lxi	b,cia$1+0eh		; point to CRA
	inp	a			; get old config
	ani	7fh			; clear freq bit
	ora	l			; add in new freq bit
	outp	a			; set new config

	mvi	c,8			; start RTC
	outp	a

	lxi	h,date$hex
	shld	@date			; set date to system data

;
;	setup the sound variables
;
	lhld	key$tbl
	lxi	d,58*4
	dad	d
	mov	e,m
	inx	h
	mov	d,m
	inx	h
	sded	sound1			; H=SID reg 24, L=SID reg 5
	mov	e,m
	inx	h
	mov	d,m
	sded	sound2			; H=SID reg 6, L=SID reg 1
	lxi	d,9
	dad	d
	mov	e,m
	inx	h
	mov	d,m
	sded	sound3			; H=SID reg 4 then L=SID reg 4 
;
;	set-up key click sound registers
;
	lxi	b,sid+7
	lxi	h,0040h
	outp	l			; (sid+7)=40h
	inr	c
	outp	l			; (sid+8)=40h
	mvi	c,low(sid+12)
	outp	h			; (sid+12)=0  Attack=2ms, Decay=6ms
	inr	c
	outp	h			; (sid+13)=0  Sustain=0,  Release=6ms
	mvi	a,6
	sta	tick$vol		; set keyclick volumn level
;
;	set up interrupts for key scan (not software usart)
;
   if	use$6551
	lxi	d,2273			; int at 150 BAUD rate
	lxi	b,CIA1+timer$b$low	;
	outp	e			;
	inr	c			; point to timer$b$high
	outp	d			;

	mvi	a,11h			;
	mvi	c,CIA$ctrl$b		; turn on timer B
	outp	a			;

	lxi	b,CIA2+data$b		; setup user port for RS232
	inp	a			; get old data
	ori	6			; set CTS and DTR
	outp	a			; update it
   endif
 	ret


mmu$table:
	mmu$tbl$M

	page
;
;
;
	CSEG
prt$msg:
	xthl
	call	?pmsg
	xthl
	ret


;
;	placed in common memory to keep IO from stepping on this code
;		always called from bank 0
;
	CSEG
read$d505:
	sta	io$0			; enable MMU (not RAM)
	lxi	b,0d505h
	inp	a			; read 40/80 column screen
	ral
	jrc	end$d505
	push	psw
	push	b
	lxi	b,0d011h		; blank 40 col screen if 80 col
	inp	a
	ani	0efh
	outp	a
	pop	b
	pop	psw
end$d505:
	rar
	sta	bank$0			; re-enable RAM
	ret

	page
;
;
;
	DSEG
   if	not use$6551
?init$RS232:
	di

	xra	a
	sta	RS232$status
	lxi	h,RxD$buf$count		; clear the count
	mvi	m,0
	inr	l			; point to RxD$buf$put
	mvi	m,low(RxD$buffer)
	inr	l			; point to RxD$buf$get
	mvi	m,low(RxD$buffer)

	lxi	h,NTSC$baud$table
	lda	sys$freq
	ora	a
	jrz	use$NTSC
	lxi	h,PAL$baud$table
use$NTSC:
	lda	RS232$baud
	cpi	baud$1200		; baud rate less then 1200 baud
	jrc	baud$ok			; yes, go set it
	mvi	a,baud$1200		; no, 1200 baud is the max
	sta	RS232$baud		; (change to 1200 baud)

baud$ok:
	mov	e,a
	mvi	d,0
	dad	d			; +1X
	dad	d			; +1X
	dad	d			; +1X = +3X
	mov	e,m
	inx	h
	mov	d,m
	inx	h			;
	mov	a,m			; get rate #
	sta	int$rate		;
	lxi	b,CIA1+timer$b$low	;
	outp	e			;
	inr	c			; point to timer$b$high
	outp	d			;

	mvi	a,11h			;
	mvi	c,CIA$ctrl$b		; turn on timer B
	outp	a			;

	lxi	b,CIA2+data$b		; setup user port for RS232
	inp	a			; get old data
	ori	6			; set CTS and DTR
	outp	a			; update it
	ei
	ret

	page
;
;	NTSC rates (1.02273 MHz)
;
NTSC$baud$table:
	dw	6818			; no baud rate	 (6666.47)
	db	1
	dw	6818			; 50	6666.7us (6666.47)
	db	1
	dw	4545			; 75	4444.4us (4443.99)
	db	1
	dw	3099			; 110	3030.3us (3030.13)
	db	1
	dw	2544			; 134	2487.6us (2487.46)
	db	1
	dw	2273			; 150	2222.2us (2222.48)
	db	1
	dw	1136			; 300	1111.1us (1110.75)
	db	3
	dw	568			; 600	 555.6us ( 555.38)
	db	6
	dw	284			; 1200	 277.8us ( 277.69)
	db	12

;
;	PAL rates (0.98525 MHz)
;
PAL$baud$table:
	dw	6568			; no baud rate	  (6666.32)
	db	1
	dw	6568			; 50	 6666.7us (6666.32)
	db	1
	dw	4379			; 75	 4444.4us (4444.56)
	db	1
	dw	2986			; 110	 3030.3us (3030.70)
	db	1
	dw	2451			; 134	 2487.6us (2487.69)
	db	1
	dw	2189			; 150	 2222.2us (2221.77)
	db	1
	dw	1095			; 300	 1111.1us (1111.39)  300*3
	db	3
	dw	547			; 600	  555.6us ( 555.19)  600*3
	db	6
	dw	274			; 1200    277.8us ( 278.10) 1200*3
	db	12

	page
;
;
;
?out$RS232:
	call	?out$st$RS232
	jrz	?out$RS232
	mov	a,c
	sta	xmit$data		; get character to send in A
	lxi	h,RS232$status
	setb	7,m			; set Xmit request bit
	ret

;
;
;
?out$st$RS232:
	lda	RS232$status
	ani	80h			; bit 8 set if busy
	xri	80h			; A cleared if busy (=80h if not)
	rz
	ori	0ffh			; A=ff if ready (not busy)
	ret

;
;
;
?in$RS232:
	call	?in$st$RS232
	jrz	?in$RS232
	lda	recv$data
	lxi	h,RS232$status
	res	0,m
	ret

;
;
;
?in$st$RS232:
	lda	RS232$status
	ani	1
	rz
	ori	0ffh			; set data ready (-1)
	ret
   endif
	page
;
;	this routine is used to provide the user with a method
;	of interfacing with low level system functions
;
	CSEG
;
;	input:
;		all registers except HL and A are passed to function
;
;	output:
;		all resisters from function are preserved
;
?user:
	shld	user$hl$temp
	sded	de$temp			; save DE for called function

	mov	e,a			; place function number in E
	mvi	a,num$user$fun-1	; last legal function number

	call	vector			; function
usr$tb:	dw	read$mem$0		; 0
	dw	write$mem$0		; 1
	dw	?kyscn			; 2
	dw	do$rom$fun		; 3  (L=function #) 	
	dw	do$6502$fun		; 4  (L=function #)
	dw	read$d505		; 5  returns MMU reg in A
	dw	code$error		; not 0 to 5 ret version number in HL

num$user$fun	equ	($-usr$tb)/2

	page
;
;	address in DE is read and returned in C
;	A=0 if no error
;
	DSEG
read$mem$0:
	ldax	d			; read location addressed by DE
	mov	c,a			; value returned in C
	xra	a			; clear error flag
	ret

;
;	address in DE is written to with value in C
;	A=0 if no errors
;
write$mem$0:
	mvi	a,-1			; get error flag and 0ffh value
	cmp	d			; do not allow write from FF00 to FFFF
					;   this is 8502 space, MMU direct reg.
	rz
	mov	a,d
	cpi	10h			; do not allow write from 0000 to 0FFF
					;   this is ROM space
	mvi	a,-1			; get error flag
	rc				; return if 00h to 0fh
	mov	a,c
	stax	d
	xra	a			; clear error flag 
	ret

	page
;
;	This is the function code entry point for direct execution
;	of driver functions. If the MSB of the function number is
;	set, the 40 column driver is used; else the 80 column drive 
;	is used.
;
do$rom$fun:
	lhld	user$hl$temp		; get HL (L=fun #)

	mvi	a,7eh			; only allow even functions
	ana	l
	cpi	79h
	jrc	no$hl$req
	lhld	@dma			; HL will be passed in @dma by
	push	h			; ..the user
no$hl$req:
	mov	l,a
	rst	5			; call rom function (RCALL) L=fun #
	ret

;	mvi	a,7eh			; only allow even functions
;	ana	l
;	sta	no$hl$req+1
;	cpi	79h
;	jrc	no$hl$req
;	lhld	@dma			; HL will be passed in @dma by
;	push	h			; ..the user
;no$hl$req:
;	will be changed to RCALL xx   RET for next release (ROM FN 7A, 7C
;		and 7E will not function with current code, they expect
;		a return address on the stack
;
;	RJMP	5Eh			; unused function, real fun# installed
					; ..above

do$6502$fun:
	lhld	user$hl$temp
	mov	a,l
	jmp	?fun65
;
;
;
code$error:
	lxi	h,date$hex
	mvi	a,-1
	ret

	page
;
;
;
	CSEG
?rlccp:

	lxi	d,0100h
	lxi	h,ccp$buffer
trans$ccp:
	sta	io$1
	lxi	b,ram$reg
	mvi	a,common$4K
	outp	a
	lxi	b,0c80h
	ldir
	lxi	b,ram$reg
	mvi	a,common$8K
	outp	a
	sta	bank$1
	ret

;	lxi	h,ccp$buffer
;	lxi	b,0c80h

;load$ccp:
;	sta	bank$0
;	mov	a,m
;	sta	bank$1
;	lxi	d,-ccp$buffer+100h
;	dad	d
;	mov	m,a
;	lxi	d,ccp$buffer-100h+1
;	dad	d
;	dcx	b
;	mov	a,b
;	ora	c
;	jrnz	load$ccp
;	ret

	page
;
;
;
	CSEG
?ldccp:
	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
	jrz	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

	lxi	h,0100h
	lxi	d,ccp$buffer
	jr	trans$ccp

;
;
save$ccp:
;	sta	bank$1
;	mov	a,m
;	sta	bank$0
;	lxi	d,ccp$buffer-100h
;	dad	d
;	mov	m,a
;	lxi	d,-ccp$buffer+100h+1
;	dad	d
;	dcx	b
;	mov	a,b
;	ora	c
;	jrnz	save$ccp

;	pop	psw
;	sta	force$map
;	ret

	page 
;
;	The following code does not work with the NEW MMU
;
;?ldccp:
;	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
;
;;	trace	jz below should be jrz
;	jz	no$CCP		; error if no file...
;
;	lda	fcb$rc		; get the record count
;	sta	ccp$count	; save for later
;	lxi	d,0100h
;	call	setdma		; start of TPA
;	lxi	d,128
;	call	setmulti	; allow up to 16K bytes
;	lxi	d,ccp$fcb
;	call	read
;
;	lxi	d,1f0h		; point to buffer
;				; bank 1, page F0
;;	lxi	h,101h		; point to CCP (in TPA)
;				; bank 1, page 01
;	mov	h,d
;	mov	l,d
;	jr	save$ccp
;
;
;
;
;?rlccp:
;	lda	ccp$count	;
;	sui	30		; we can only save 30 records
;	jp	?ldccp
;
;	lxi	h,1F0h		; point to buffer
;				; bank 1, page F0
;;	lxi	d,101h		; point to TPA space
;				; bank 1, page 01
;	mov	d,h
;	mov	e,h
;
;save$ccp:
;	mvi	b,15		; number of pages in buffer
;ccp$move$loop:
;	push	h
;	push	d
;	push	b
;	call	do$move$0$to$1
;	pop	b
;	pop	d
;	pop	h
;	inx	h
;	inx	d
;	djnz	ccp$move$loop
;
;	ret
;
;
;do$move$0$to$1:
;	call	set$0$and$1
;	call	move$0$to$1
;	lxi	h,100h		; bank 1 page 0
;;	lxi	d,101h		; bank 1 page 1
;	mov	d,h
;	mov	e,h
;;
;;
;;
;set$0$and$1:
;	lda	force$map	; get current map
;	sta	io		; force to i/o in bank 0
;	lxi	b,page$0$l	; point to 1st page register
;	outp	l		; set page 0 low
;	inr	c
;	outp	h		; set page 0 high
;	inr	c
;	outp	e		; set page 1 low
;	inr	c
;	outp	d		; set page 1 high
;	sta	force$map
;	ret
;
;;
;;
;;
;move$0$to$1: 
;	lda	force$map
;	sta	bank$1		; force bank 1 memory
;	lxi	h,000h		; source
;	lxi	d,100h		; dest.
;;	lxi	b,100h
;	mov	b,d
;	mov	c,e		; count
;	ldir
;	sta	force$map
;	ret
;
	page
;
;
;
no$CCP:				; here if we couldn't find the file
	call	prtmsg		; report this...
	db	cr,lf,'BIOS Err on A: No CCP.COM file',0
	call	?conin		; get a response
	jr	?ldccp		; and try again

;
; CP/M BDOS Function Interfaces
;
	CSEG
open:
	mvi	c,15		; open file control block

	db	21h		; lxi h,(mvi c,26)
setdma:
	mvi	c,26		; set data transfer address

	db	21h		; lxi h,(mvi c,44)	
setmulti:
	mvi	c,44		; set record count

	db	21h		; lxi h,(mvi c,20)
read:
	mvi	c,20		; read records
	jmp	bdos

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


	page
;
;	CXIO.ASM and CXEM.ASM
;
;==========================================================
;		ROUITINE TO VECTOR TO HANDLER
;==========================================================
;	CP/M IO routines	b=device : c=output char : a=input char
;
	CSEG
;
;
;
?cinit:				; initialize usarts
	mov	b,c
	call	vector$io	; jump with table adr on stack
number$drivers:
	dw	?int$cia	; keys
	dw	?int80		; 80col
	dw	?int40		; 40col
	dw	?pt$i$1101	; prt1
	dw	?pt$i$1101	; prt2
	dw	?int65		; 6551
   if	not use$6551
	dw	?init$RS232	; software RS232
   endif
	dw	rret		;
max$devices	equ	(($-number$drivers)/2)-1

;
;
;
?ci				; character input
	call	vector$io	; jump with table adr on stack
	dw	?kbin		; keys
	dw	rret		; 80col
	dw	rret		; 40col
	dw	rret		; ptr1
	dw	rret		; prt2
	dw	?in65		; 6551
   if	not use$6551
	dw	?in$RS232	; software RS232
   endif
	dw	null$input

;
;
;
?cist:				; character input status
	call	vector$io	; jump with table adr on stack
	dw	?kbstat		; keys
	dw	rret		; 80col
	dw	rret		; 40col
	dw	rret		; prt1
	dw	rret		; prt2
	dw	?ins65		; 6551
   if	not use$6551
	dw	?in$st$RS232	; software RS232
   endif
	dw	rret

;
;
;
?co:				; character output
	call	vector$io	; jump with table adr on stack
	dw	rret		; keys
	dw	?out80		; 80col
	dw	?out40		; 40col
	dw	?pt$o$1		; prt1
	dw	?pt$o$2		; prt2
	dw	?out65		; 6551
   if	not use$6551
	dw	?out$RS232	; software RS232
   endif
	dw	rret

;
;
;
?cost:				; character output status
	call	vector$io	; jump with table adr on stack
	dw	rret		; keys
	dw	ret$true	; 80col
	dw	ret$true	; 40col
	dw	?pt$s$1		; prt1
	dw	?pt$s$2		; prt2
	dw	?outs65		; 6551
   if	not use$6551
	dw	?out$st$RS232	; software RS232
   endif
	dw	ret$true

	page
;
;	This entry does not care about values of DE
;
vector$io:
	mvi	a,max$devices	; check for device # to high
	mov	e,b		; get devive # in E
;
;
;	INPUT:
;		Vector # in E, Max device in A
;		passes value in DE$TEMP in DE
;		HL has routine's address in it on entering routine
;
;	OUTPUT:
;		ALL registers of returning routine are passed
;
vector:
	pop	h		; get address vector list
	mvi	d,0		; zero out the MSB
	cmp	e		; is it too high?
	jrnc	exist		; no, go get the handler address

	mov	e,a		; yes, set to max$dev$handler(last one) 
exist:
	dad	d		; 
	dad	d		; point into table

 	mov	a,m
	inx	h
	mov	h,m
	mov	l,a		; get routine adr in HL

    if	banked
	shld	hl$temp		; save exec adr
	lxi	h,0
	dad	sp
	lxi	sp,bios$stack
	push	h		; save old stack

	lded	de$temp
	lhld	hl$temp		; recover exec adr

	lda	force$map	; get current bank
	push	psw		; save on stack
	sta	bank$0		; set bank 0 as current

	call	ipchl

	sta	a$temp		; save value to return
	pop	psw
	sta	force$map	; set old bank back
	lda	a$temp		; recover value to return

	shld	hl$temp
	pop	h		; recover old stack
	sphl			; set new stack
	lhld	hl$temp
	ret

ipchl:
	pchl			; jmp to handler

;	ds	30h		; our own stack
;bios$stack:

    else
	lda	a$temp
	lded	de$temp
	pchl
    endif

	page
;==========================================================
;		CHARACTER INPUT ROUTINES
;==========================================================

	DSEG
;
;
;
?kbin
	lda	key$buf
	ora	a
	jnz	kbin$cont
kbin$again:
	call	?get$key
	jrz	kbin$again   
kbin$cont:
	mov	c,a		; save
	xra	a		; clear key 
	sta	key$buf
;
;**	the tracking of the display should be able to be turned off
;**	this could be done with one of the keyboard's Fx codes
;	lda	stat$enable
;	bit	6,a
;	jrnz	no$update
;	lda	char$col$40
;	mov	b,a
;	lda	@off40
;	cmp	b
;	jrnc	do$update
;	adi	39-1
;	cmp	b
;	jrnc	no$update
do$update:
;	mvi	a,80h 
;	sta	old$offset	; store 80h to demand update
no$update:
	mov	a,c		; recover current key
rret:
	ret

;
;
;
null$input:		; return a ctl-Z for no device
	mvi	a,1Ah
	ret


	page

;==========================================================
;	CHARACTER DEVICE INPUT STATUS
;==========================================================

	DSEG
;
;
;
?kbstat:
	lda	key$buf
	ora	a
	jrnz	ret$true

	call	?get$key
	ora	a		; =0 if none
	rz			; return character not advailable

	sta	key$buf		; was one, save in key buffer

ret$true:
	ori	0ffh		; and return true
	ret

	page

	cseg
@ctbl
	db	'KEYS  '	; device 0, internal keyboard
	db	mb$input
	db	baud$none

	db	'80COL '	; device 1, 80 column display
	db	mb$output
	db	baud$none

	db	'40COL '	; device 2, 40 column display
	db	mb$output
	db	baud$none

	db	'PRT1  '	; device 3, serial bus printer (device 4)
	db	mb$output
	db	baud$none

	db	'PRT2  '	; device 4, serial bus printer (device 5)
	db	mb$output
	db	baud$none

	db	'6551  '	; device 5, EXT CRT
	db	mb$in$out+mb$serial+mb$softbaud+mb$xonxoff
?intbd:
	db	baud$1200
   if	not use$6551
	db	'RS232 '	; device 6, software RS232 device
	db	mb$in$out+mb$serial+mb$xonxoff+mb$softbaud
RS232$baud:
	db	baud$110
   endif
	db	0		; mark end of table

	page
;
;	TIME.ASM
;
	cseg
;
;	HL and DE must be presevered
;
?time:
	inr	c
	lxi	b,cia$hours
	jrz	set$time
;
;	update SCB time  (READ THE TIME)
;
	inp	a			; read HR (sets sign flag)
	jp	is$am			; jmp if AM (positive)
	ani	7fh
	adi	12h			; noon=24(PM), midnight=12(AM)
	daa
	cpi	24h			; check for noon (12+12 PM)
	jrnz	set$hr
	mvi	a,12h
	jr	set$hr

is$am:
	cpi	12h			; check for midnight (AM)
	jrnz	set$hr
	xra	a			; becomes 00:00
set$hr:
	sta	@hour
	mov	b,a
	lda	old$hr
	mov	c,a
	mov	a,b
	sta	old$hr
	cmp	c			; if @hour<old$hr
	jrnc	same$day
 
	push	h
	lhld	@date
	inx	h
	shld	@date
	pop	h

same$day:
	lxi	b,cia$hours-1
	inp	a			; read MIN
	sta	@min

	dcr	c
	inp	a			; read SEC
	sta	@sec

	dcr	c
	inp	a			; read 1/10 of SEC (a must to free
	ret				; the holding register)

old$hr:
	ds	1

	page
;
;
;
set$time
	lda	@hour
	sta	old$hr
	cpi	12h			; test for noon
	jrz	set$as$is
	ana	a			; test for 00:xx
	jrnz	not$zero$hundred
	mvi	a,80h+12h			; set to midnight
	jr	set$as$is

not$zero$hundred:
 	cpi	11h+1			; test for 1 to 11 AM
	jrc	set$as$is
	sui	12h
	daa				; decimal adjust
set$msb:
	ori	80h			; set PM

set$as$is:
	outp	a
	dcr	c
	lda	@min
	outp	a
	dcr	c
	lda	@sec
	outp	a
	dcr	c
	xra	a
	outp	a
	ret

	page
;
; CXMOVE.ASM
;
	public ?move,?xmove,?bank

;
;	Move a block of data from DE to HL
;	count is in BC (within current bank)
;
;
	cseg			; place code in common
?move:
	xchg			;*
	lda	source$bnk	; =FFh if normal block move 
	inr	a		; 
	jrnz	inter$bank$move

	LDIR			;* do block move	
	xchg			;*
	ret


;
;
;
?xmove:				; can be in bank 0	
	mov	a,c
	sta	source$bnk
	mov	a,b
	sta	dest$bnk
	ret			;*

	page
;
;
;
inter$bank$move:
	shld	@buffer		; save HL TEMP
	lxi	h,0
	dad	sp
	lxi	sp,bios$stack
	push	h		; save old stack  ;**1
	lhld	@buffer

inter$bank$move$1:
	mov	a,b		; get msb of count
	ora	a
	jrz	count$less$than$256
	push	b		; save the count  ;**2
	push	d		; save the dest   ;**3
	lxi	d,@buffer	; make buffer the dest
	lxi	b,256		; move 256 bytes
	lda	source$bnk
	call	?bank
	ldir			; move source to buffer

	pop	d		; recover dest    ;**2
	push	h		; save updated source ;**3
	lxi	h,@buffer	; make the buffer the source
	lxi	b,256		; move 256 bytes
	lda	dest$bnk
	call	?bank
	ldir			; move buffer to dest
 
	pop	h		; recover updated source ;**2
	pop	b		; recover count          ;**1
	dcr	b		; subtract 256 from count
	jr	inter$bank$move$1

	page
;
;
;
count$less$than$256:
	ora	c		; BC=0  [A (0) or'ed with C]
 	jrz	exit$move

	push	d		; save count for 2nd half  ;**2
	push	b		; save dest adr            ;**3
	lxi	d,@buffer
	lda	source$bnk
	call	?bank
	ldir			; move source to buffer

	pop	b		; recover count		  ;**2
	pop	d		; recover dest		  ;**1
	push	h		; save updated dest	  ;**2
	lxi	h,@buffer
	lda	dest$bnk
	call	?bank
	ldir			; move buffer to dest
	pop	h	 				   ;**1
;
;
;
exit$move:
	xchg
	mvi	a,-1
	sta	source$bnk	; set MOVE back to normal
	lda	@cbnk

	shld	@buffer
	pop	h		; recover old stack	;**0
	sphl
	lhld	@buffer

; call	?bank		; set current bank
; ret

	page
;
;	switch bank to bank number in A
;
	cseg			; (must be in common)
?bank:				
   if	banked
	ora	a		; bank 0 ?
	jrnz	not$bank$0	; go check for bank 1

	sta	bank$0		; set bank 0
	ret

;
;
not$bank$0:
	dcr	a		; bank 1 ?
	rnz			; if not a valid bank just return
	sta	bank$1		; set bank 1
   endif
	ret

	end
