	title 'Character I/O handler for Tarbell based system'

; Copyright (c) 1983 Tarbell Electronics

; Version 1.0 4-12-83 ED SMITH
; Character I/O for the Modular CP/M 3 BIOS


	public	?cinit,?ci,?co,?cist,?cost
	public	@ctbl

	maclib	Z80		; define Z80 op codes
	maclib	modebaud	; define mode bits and baud euqates

data$port	set	0
status$port	set	1
in$mask		set	2
in$rdy$mask	set	3
out$mask	set	4
out$rdy$mask	set	5
initial		set	6

max$devices	equ 	2	; only crt & printer supported

	cseg

; this table shows each device for use by the DEVICE utility
 
@ctbl
	db	'CRT   '		; device 0, CRT port 0
	db	mb$in$out+mb$serial
	db	baud$none
	db	'LPT   '		; device 1, LPT port 0
	db	mb$output+mb$serial
	db	baud$none
	db 	0			; table terminator

; the following is a table of 8 bytes per device
; and defines the port #s status bytes ect. for use by
; the routines in this module

dev$tab:

; CRT PORT A OF TARBELL CPU CARD

	db	00h		; data port
	db	01h		; comand / status port
	db	02h		; input mask
	db	02h		; input ready mask
	db	01h		; output mask
	db	01h		; output ready mask
	db	04h		; init table 0 - 4 bytes long
	db	00h		; reserved

; PRINTER PORT B OF TARBELL CPU CARD

	db	02h		; data port
	db	03h		; comand / status port
	db	02h		; input mask
	db	02h		; input ready mask
	db	81h		; output mask
	db	81h		; output ready mask
	db	14h		; init table 1 - 4 bytes long
	db	00h		; reserved


; device initialization table - 1 to 8 bytes for each device
; if init for 2 or more devices is the same may use same table
; byte 6 of dev$tab upper nib = ini$tab # (0-f) lower nib =
; length of init string (1-8). If byte 6 is 00h then no init will be done

ini$tab:
	db	0aah,40h,0ceh,37h,0,0,0,0	;init for crt
	db	0aah,40h,0ceh,37h,0,0,0,0	;init for printer

; initialize device specified by register c
; regs used A,BC,DE,HL,IX none saved

?cinit:
	mov	a,c			;put device # in A
	cpi	max$devices
	rnc				; invalid device
	call	dev$idx			; setup index
	ldx	a,initial		; get init byte
	ora	a
	rz				;return if no init
	push	psw			;save init byte
	ani	0f0h			;mask upper nibble
	srlr	a			;a= table # * 8
	mov	e,a			;de = relative offset
	mvi	d,0
	lxi	h,ini$tab		;hl = beginning of table
	dad	d			;add offset
	pop	psw			;get init byte back
	ani	0fh			;mask count
	mov	b,a
	ldx	c,status$port		;get port # for init

;initialize device at port c with table at hl

	outir
	ret

; input character from device specified by B return with character
; in reg A with bit 7 cleared. do not return untill character is input
; regs used A,BC,IX none saved

?ci:	mov	a,b
	cpi	1
	jnc	null$input 		; can't read from printer
	call	dev$idx			; setup index
	ldx	c,status$port		; get status port
ci1:
	inp	a			; get status
	andx	in$mask			; mask status
	cmpx	in$rdy$mask		; test status
	jnz 	ci1			; wait for character ready
	ldx	c,data$port		; get data port
	inp	a			; get data
	ani	7Fh			; mask parity
	ret

null$input:
	mvi	a,1Ah			; return a ctl-Z for no device
	ret

; get input status of device specified by B
; return with A=0ffh if ready and A=0 if not ready
; regs used A,BC,IX none saved

?cist:	mov	a,b
	cpi	1
	jnc	null$status 		; can't read from printer
	call	dev$idx			; setup index
	ldx	c,status$port		; get port #
	inp	a			; get status
	andx	in$mask			; mask status
	cmpx	in$rdy$mask		; test status
	mvi	a,0
	rnz				; return not ready
	cma
	ret				; return ready

null$status:
	xra	a
	ret

; output character in C to device specified by B
; do not return untill done
; regs used A,BC,IX none saved

?co:	mov	a,b
	cpi	max$devices
	rnc				; return if no device
	push	b			; save character to output
	call	dev$idx			; setup index
	ldx	c,status$port		; get status port
co$spin:
	inp	a			; get status
	andx	out$mask		; mask status
	cmpx	out$rdy$mask		; test status
	jnz	co$spin			; wait for transmitter ready
	pop	b			; get character back
	mov	a,c
	ldx	c,data$port		; get data port
	outp	a			; send data
	ret

; get output status of device specified by B
; return with A=0ffh if ready and A=0 if not ready
; regs used A,BC,IX none saved

?cost:	mov	a,b
	cpi	max$devices		;test for no device
	jnc	null$status
	call	dev$idx			; setup index
	ldx	c,status$port		; get port #
	inp	a			; get status
	andx	out$mask		; mask status
	cmpx	out$rdy$mask		; test status
	mvi	a,0
	rnz				; return not ready
	cma
	ret				; return ready

; Setup index X to point to device table of device in A
; regs used IX,BC,A none saved

dev$idx:
	add	a			;* 2
	add	a			;* 4
	add	a			;* 8
	mov	c,a			;result in c
	mvi	b,0			;bc = relative offset
	lxix	dev$tab			;device table to index X
	dadx	bc			;add offset to index X
	ret


	end
