;----------------------------------------------------------------
; USERALT.ASM
;
; USER AREA for CP/M 2.2b (Single Density North Star Controller)
;
;  This file provides I/O routines for CP/M using the serial
;  port on the Processor Technology 3P+S board.
;  
;  1.0   02-23-19   Mike Douglas
;
;  USER area location (180h bytes long)
;	0500h from start of BIOS
;	1B00h from start of CP/M
;	2500h in memory after loading or running MOVCPM
;	1C00h offset in the disk image file
;			
;  IOBYTE location: 1Dh from start of USER area
;
;  To install this patch:
;    1) Set MSIZE immediately below and assemble this file.
;    2) Run MOVCPM and save the image to a file (e.g., CPM.COM)
;       as prompted.
;    3) Use DDT to install the patch in the CP/M image:
;       A>DDT CPM.COM
;       -IUSERALT.HEX
;       -R7200		(replace 7200 with value of "OFFSET" below)
;       -G0		(G zero, not "oh", or type ctrl-c)
;       A>SYSGEN	(hit return at source prompt to use
;		 	 image in memory, then follow remaining
;			 prompts).
;----------------------------------------------------------------

; Change MSIZE to the desired CP/M memory size in K.

MSIZE	equ	48		;Distribution size

; BIOS and USER area equates

BIOSLEN	equ	1200h		;length of the BIOS
USROFF	equ	0500h		;offset of USER area in BIOS
USRAREA	equ	MSIZE*1024 - BIOSLEN + USROFF

OFFSET	equ	2500h-USRAREA	;offset to overlay SYSGEN image

; Serial port on 3P+S board

CSRA	equ	00h		;serial port ontrol/status register
DRA	equ	01h		;serial port data register

RDRF	equ	40h		;receive data bit mask
TDRE	equ	80h		;transmit ready bit mask

; Misc equates

IOBYTE	equ	3		;location of CP/M IOBYTE

;----------------------------------------------------------------
; Jump Table
;    The BIOS accesses the user I/O routines through this jump
;    table. The table must remain at the start of the user area
;    and in the same order.
;----------------------------------------------------------------
	org	USRAREA

ucoldst	jmp	coldIni		;cold start init
uwarmst	jmp	warmIni		;warm start init
uconst	jmp	conStat		;BIOS console status call
uconin	jmp	conInp		;BIOS console input call
uconout	jmp	conOut		;BIOS console output call
ulist	jmp	conOut		;BIOS list output call
upunch	jmp	conOut		;BIOS punch output call
ureader	jmp	conInp		;BIOS reader input call
ulistst	jmp	lstStat		;BIOS list status call

; The next 8 bytes may be accessed externally and must remain in the
;     same order and immediately follow the jump table

usrLen	dw	USREND-USRAREA	;Length of USER AREA
defIob	db	00h		;LST = TTY (2SIO port A)
				;PUN = TTY (2SIO port A)
				;RDR = TTY (2SIO port A)
				;CON = TTY (2SIO port A)
	db	0,0,0,0,0	;reserved

;-----------------------------------------------------------------------
; coldIni - cold start initialization
;   This entry is called during cold boot.
;-----------------------------------------------------------------------
coldIni	lda	defIob		;store default IOBYTE for CP/M
	sta	IOBYTE
	ret

;-----------------------------------------------------------------------
; warmIni - warm start initialization
;   This entry is called during each warm boot.
;-----------------------------------------------------------------------
warmIni	ret

;-----------------------------------------------------------------------
; conStat - console status check
;-----------------------------------------------------------------------
conStat	lda	IOBYTE		;select device based on IOBYTE 1:0
	call	devSel

	dw	statusA		;TTY
	dw	statusA		;CRT
	dw	statusA		;BAT
	dw	statusA		;UC1

;-----------------------------------------------------------------------
; conInp - console input
;-----------------------------------------------------------------------
conInp	lda	IOBYTE		;select device based on IOBYTE 1:0
	call	devSel

	dw	inputA		;TTY
	dw	inputA		;CRT
	dw	inputA		;BAT
	dw	inputA		;UC1

;-----------------------------------------------------------------------
; conOut - console output
;-----------------------------------------------------------------------
conOut	lda	IOBYTE		;select device based on IOBYTE 1:0
	call	devSel

	dw	outputA		;TTY
	dw	outputA		;CRT
	dw	outputA		;BAT
	dw	outputA		;UC1

;-----------------------------------------------------------------------
; lstStat - list status not supported. Return zero per CP/M spec.
;-----------------------------------------------------------------------
lstStat	xra	a
	ret

;-----------------------------------------------------------------------
; devSel - jump to proper I/O routine based on device in A
;-----------------------------------------------------------------------
devSel	xthl			;hl->table, old hl saved on stack
	push	d		;de and hl saved on stack

	ani	3		;get 2 bit device selection alone
	rlc			;two bytes per table entry
	mov	e,a		;de=offset into table
	mvi	d,0
	dad	d		;hl->table[device]

	mov	e,m		;load routine address into de
	inx	h
	mov	d,m		;de->address of I/O routine 

	xchg			;hl->address of I/O routine
	pop	d		;restore de
	xthl			;jump address on stack, restore HL
	ret			;jump to address specified in table

;-----------------------------------------------------------------------
; statusA - return status of 3P+S serial port.
;    Return 0FFh if character ready, zero if not
;-----------------------------------------------------------------------
statusA	in	CSRA		;a=port a status
	ani	RDRF		;read data present?
	rz			;no, exit with zero status

	mvi	a,0FFh		;character is ready
	ret

;-----------------------------------------------------------------------
; inputA - input character from 3P+S serial port.
;-----------------------------------------------------------------------
inputA	in	CSRA		;a=port a status
	ani	RDRF		;read data present?
	jz	inputA		;no

	in	DRA		;a=data from serial port
	ani	07Fh		;strip parity
	ret


;-----------------------------------------------------------------------
; outputA - output character in C through 3P+S serial port.
;-----------------------------------------------------------------------
outputA	in	CSRA		;a=port a status
	ani	TDRE		;transmit ready?
	jz	outputA		;no

	mov	a,c		;a=byte to send
	ani	07Fh		;strip parity bit
	out	DRA		;send character

	ret


USREND	equ	$		;end of user area
