; dosrtck/asm
;
; real time clock service routines (188H bytes long)
; IX, IY, HL, DE, BC, AF already saved
;
; outside support
MASK	EQU	5		;video mask (ix+mask)
LOCDCB	EQU	$		;locate DCB
PDCB#	EQU	2		;printer DCB number
DDCB#	EQU	1		;display DCB number
FLAGK1	EQU	$		;system flag #1
FLAGK2	EQU	$		;system flag #2
DATAK1	EQU	$		;data area #1
DATAK2	EQU	$		;data area #2
DATAK6	EQU	$		;data area #6
TIME$	EQU	$		;real time clock
PRMAX	EQU	5		;max *PR chars/interrupt
; following is the real time clock printer spooler serv.
;
PRTASK	LD	B,PRMAX		;max chars/interrupt
	LD	A,PDCB#		;printer DCB number
	CALL	LOCDCB		;find the DCB
PRAGAIN	CALL	BUFFTAKE	;see if anything
	RET	Z		;return if empty
	CALL	PRIN		;get status byte
	RET	NZ		;not ready to go
	LD	A,(HL)		;get the character
	CALL	PROUT		;send the character
	DJNZ	PRAGAIN		;go for max chars
	RET			;else return
;
; common subroutine to position buffer pointers
;
; BUFFTAKE
; ENTRY:  IX => DCB
; EXIT:   Z  = no chars available
;         NZ = char available
;         HL => take location
;         counter decremented
;         offset incremented
;
BUFFTAKE LD	E,(IX+13)	;get counter
	LD	D,(IX+14)
	LD	A,D		;see if anything
	OR	E
	RET	Z		;Z = nil
	DEC	DE		;else reduce it
	LD	(IX+13),E	;update counter
	LD	(IX+14),D
	LD	L,(IX+9)	;get buffer pointer
	LD	H,(IX+10)
	LD	E,(IX+17)	;get taker offset
	LD	D,(IX+18)
	ADD	HL,DE		;HL => buff posit
	CALL	INCBUFF		;bump buffer pointer
	LD	(IX+17),E	;update pointer
	LD	(IX+18),D
	OR	-1		;set NZ flag for OK
	RET
;
; BUFFADD
; ENTRY:  IX => DCB
; EXIT:   C  = no room to add
;         NC = OK
;         HL => add location
;         counter incremented
;         offset incremented
;
BUFFADD	LD	L,(IX+11)	;get length
	LD	H,(IX+12)
	LD	E,(IX+13)	;get counter
	LD	D,(IX+14)
	INC	DE		;for this character
	OR	A		;clear carry flag
	SBC	HL,DE		;compare
	RET	C		;no more room
	LD	(IX+13),E	;update counter
	LD	(IX+14),D
	LD	L,(IX+9)	;get buffer start
	LD	H,(IX+10)
	LD	E,(IX+15)	;get adder offset
	LD	D,(IX+16)
	ADD	HL,DE		;HL => buff posit
	CALL	INCBUFF		;bump ring pointer
	LD	(IX+15),E	;update pointer
	LD	(IX+16),D
	OR	A		;clear carry
	RET			;done, HL => buffer
;
; routine to increment ring buffer pointer
;
INCBUFF	INC	DE		;bump pointer
	PUSH	HL		;save from test
	LD	L,(IX+11)	;get max length
	LD	H,(IX+12)
	DEC	HL		;adjust for compare
	OR	A		;clear carry
	SBC	HL,DE		;see if at end
	POP	HL		;restore pointer
	RET	NC		;not at end
	LD	DE,0		;else start over
	RET
;
; routine to send a char to printer
; ENTRY:  IX => DCB
;         A  = character
; EXIT:   character sent directly to the device
;
PROUT	BIT	7,(IX+5)	;serial?
	JR	NZ,PROUTS	;go if yes
	OUT	(0E1H),A	;send parallel
	RET			;done
PROUTS	OUT	(0F5H),A	;send character
	RET
;
; routine to fetch printer status
; ENTRY:  IX => DCB
; EXIT:   Z  = printer can accept char
;         NZ = not ready
;
PRIN	BIT	7,(IX+5)	;serial?
	JR	NZ,PRINS	;go if yes
	IN	A,(0E0H)	;get parallel status
	AND	0F0H		;top 4 bits only
	CP	30H		;7,6 reset / 5,4 set
	RET			;Z = ready
PRINS	LD	A,10H		;reset
	OUT	(0F7H),A	;channel B command
	IN	A,(0F7H)	;get status
	CPL			;reverse bits
	AND	4		;TX buffer empty?
	RET			;Z = yes
;
; user timer service
;
TMRTASK	LD	HL,FLAGK1	;system flag #1
	BIT	3,(HL)		;timer on?
	RET	Z		;nope
	LD	HL,(DATAK1)	;get second counter
	DEC	HL		;less 1 second
	LD	(DATAK1),HL	;update counter
	LD	A,H		;see if time
	OR	L
	RET	NZ		;not time
	LD	HL,FLAGK1	;system #1
	RES	3,(HL)		;turn it off
	LD	HL,(DATAK2)	;get vector
	JP	(HL)		;go!
;
; break key processor
;
BRKTASK	LD	HL,FLAGK1	;system flag #1
	BIT	6,(HL)		;break in buffer
	RET	Z		;nope
	RES	6,(HL)		;reset it
	BIT	2,(HL)		;debug on?
	JR	NZ,BRKDBG	;go if yes
	BIT	7,(HL)		;user break vector?
	RET	Z		;nope
	LD	HL,(DATAK6)	;get break vector
	JP	(HL)		;go!
BRKDBG	SET	1,(HL)		;set debug trigger
	RET			;done, go after RETN
;
; normal vector for BREAK processor
;
BRKVEC	RST	0		;back to DOS
;
; normal vector for TIMER vector
;
TMRVEC	RET		;nil for now
;
; real time clock to display processor
;
CLKTASK	LD	HL,FLAGK2	;system flag #2
	BIT	7,(HL)		;on?
	RET	Z		;nope
	LD	A,DDCB#		;video DCB number
	CALL	LOCDCB		;find it
	LD	A,(IX+MASK)	;video mask byte
	PUSH	AF		;save mask
	OR	80H		;video enable
	OUT	(0FFH),A	;turn it on
	LD	HL,0F800H+69	;display position
	LD	DE,TIME$+3	;point to hour
	LD	B,3		;3 loops
	JR	CLK2		;go!
CLK1	LD	(HL),':'	;time separator
	INC	HL		;next video slot
CLK2	LD	A,(DE)		;get time byte
	DEC	DE		;point to next
	CALL	CLKASC		;quick ascii
	LD	(HL),C		;put MSB
	INC	HL		;bump pointer
	LD	(HL),A		;put LSB ascii
	INC	HL		;next
	DJNZ	CLK1		;more?
	POP	AF		;get video mask back
	OUT	(0FFH),A	;put it back
	RET			;done
CLKASC	LD	C,'0'		;start for MSB
CLKA1	SUB	10		;less 10
	JR	C,CLKA2		;go if done
	INC	C		;bump ascii digit
	JR	CLKA1		;go again
CLKA2	ADD	A,3AH		;make it ascii
	RET			;done, CA = ascii
;
; real time trace to display processor
;
TRCTASK	LD	HL,FLAGK2	;system flag #2
	BIT	6,(HL)		;trace on?
	RET	Z		;nope
	LD	A,DDCB#		;video DCB number
	CALL	LOCDCB		;find it
	LD	A,(IX+MASK)	;get video mask
	PUSH	AF		;save for restore
	OR	80H		;set 7, enable
	OUT	(0FFH),A	;enable video ram
	LD	HL,0F800H+64	;video location
	LD	DE,0		;get trace address
TRADD	EQU	$-2		;set from NMI service
	LD	A,D		;get MSB
	CALL	TRHEX		;quick hex convert
	LD	A,E		;get LSB
	CALL	TRHEX		;put on video
	POP	AF		;restore video mask
	OUT	(0FFH),A	;put it back
	RET			;done
TRHEX	LD	C,A		;save byte
	RRCA			;move top bits down
	RRCA
	RRCA
	RRCA
	AND	0FH		;mask it off
	CALL	TRHEXA		;make it ascii
	LD	(HL),A		;MSB to video
	INC	HL		;bump pointer
	LD	A,C		;get again
	AND	0FH		;low 4 bits
	CALL	TRHEXA		;make it ascii
	LD	(HL),A		;LSB to video
	INC	HL		;bump video
	RET			;done
TRHEXA	ADD	A,'0'		;add ascii to it
	CP	3AH		;0-9?
	RET	C		;yes, go
	ADD	A,7		;adjust for A-F
	RET			;done, A = hex digit
;
; real time alive to video processor
;
ALVTASK	LD	HL,FLAGK2	;system flag #2
	BIT	5,(HL)		;alive on?
	RET	Z		;nope
	LD	A,DDCB#		;video DCB number
	CALL	LOCDCB		;find it
	LD	A,(IX+MASK)	;get video mask
	PUSH	AF		;save it
	OR	80H		;enable video ram
	OUT	(0FFH),A	;send it
	LD	HL,0F800H+78	;video location
	LD	E,99H		;byte sequence
	LD	BC,9A9EH	;EBC
	CALL	ALIVE		;put on video
	INC	L		;next video
	LD	E,9CH		;2'nd one
	LD	BC,9D9EH
	CALL	ALIVE		;to video
	POP	AF		;get video mask
	OUT	(0FFH),A	;put it back
	RET			;done
ALIVE	LD	A,(HL)		;get the current byte
	CP	E		;this one?
	JR	Z,ALIV1		;go if yes
	CP	B		;this one?
	JR	Z,ALIV2		;go if yes
	LD	(HL),E		;reset it
	RET			;done
ALIV1	LD	(HL),B		;next one
	RET
ALIV2	LD	(HL),C
	RET
*EJECT
;
