;	MP/M 2 XIOS for Z80-Simulator
;
;	Copyright (C) 1989-2006 by Udo Munk
;
; This XIOS is a patch for z80pack versions 1.8 and 1.9, banking doesn't
; work correct with the XIOS included in that versions. For all later
; versions don't use this, the problem is fixed already.
;
	.Z80
	CSEG
;
;	i/o ports
;
CONSTA	EQU	0		;console status port
CONDAT	EQU	1		;console data port
PRTSTA	EQU	2		;printer status port
PRTDAT	EQU	3		;printer data port
AUXSTA	EQU	4		;auxilary status port
AUXDAT	EQU	5		;auxilary data port
FDCD	EQU	10		;fdc-port: # of drive
FDCT	EQU	11		;fdc-port: # of track
FDCS	EQU	12		;fdc-port: # of sector
FDCOP	EQU	13		;fdc-port: command
FDCST	EQU	14		;fdc-port: status
DMAL	EQU	15		;dma-port: dma address low
DMAH	EQU	16		;dma-port: dma address high
MMUINI	EQU	20		;initialize mmu
MMUSEL	EQU	21		;bank select mmu
TIMER	EQU	27		;interrupt timer
;
POLL	EQU	131		;xdos poll function
PLCI0	EQU	0		;poll console in #0
FLAGSET	EQU	133		;xdos flag set function
;
;	jump vector for individual subroutines
;
	JP	COMMONBASE	;commonbase
	JP	WARMSTART	;warm start
	JP	CONST		;console status
	JP	CONIN		;console character in
	JP	CONOUT		;console character out
	JP	LIST		;list character out
	JP	PUNCH		;not used by MP/M 2
	JP	READER		;not used by MP/M 2
	JP	HOME		;move head to home
	JP	SELDSK		;select disk
	JP	SETTRK		;set track numer
	JP	SETSEC		;set sector number
	JP	SETDMA		;set dma address
	JP	READ		;read disk
	JP	WRITE		;write disk
	JP	LISTST		;not used by MP/M 2
	JP	SECTRAN		;sector translate
	JP	SELMEMORY	;select memory
	JP	POLLDEVICE	;poll device
	JP	STARTCLOCK	;start clock
	JP	STOPCLOCK	;stop clock
	JP	EXITREGION	;exit region
	JP	MAXCONSOLE	;maximum console number
	JP	SYSTEMINIT	;system initialization
	JP	IDLE		;idle prozedure
;
COMMONBASE:
	JP	COLDSTART
SWTUSER:
	JP	$-$
SWTSYS:	JP	$-$
PDISP:	JP	$-$
XDOS:	JP	$-$
SYSDAT:	DEFW	$-$
;
COLDSTART:
WARMSTART:
	LD	C,0
	JP	XDOS		;system reset, terminate prozess
;
;	MP/M II V2.0 Console Bios
;
CONST:
	CALL	PTBLJMP		;compute and jump to handler
	DW	PTSTI0
;
CONIN:
	CALL	PTBLJMP		;compute and jump to handle
	DW	PTIN0
;
CONOUT:
	CALL	PTBLJMP		;compute and jump to handler
	DW	PTOUT0
;
PTSTI0:	IN	A,(CONSTA)	;console 0 input
	RET
;
PTIN0:	LD	C,POLL		;poll console 0 status in
	LD	E,PLCI0
	CALL	XDOS		;poll console 0
	IN	A,(CONDAT)	;read character
	AND	7FH		;strip parity
	RET
;
PTOUT0:	LD	A,C		;console 0 output
	OUT	(CONDAT),A
	RET
;
PTBLJMP:			;compute and jump to handler
	LD	A,D
	ADD	A,A		;double table index for adress offset
	POP	HL		;return adress of jump table
	LD	E,A
	LD	D,0
	ADD	HL,DE		;table index * 2 + table base
	LD	E,(HL)		;get handler address
	INC	HL
	LD	D,(HL)
	EX	DE,HL
	JP	(HL)		;jump to computed handler
;
LIST:
	LD	A,C
	OUT	(PRTDAT),A
	RET
;
;	not used by MP/M 2
PUNCH:
READER:
LISTST:
	RET
;
;	MP/M II V2.0 Xios
;
;	select/protect memory
;		BC = address of memory descriptor
SELMEMORY:
	LD	HL,3		;offset memory bank in memory descriptor
	ADD	HL,BC
	LD	A,(HL)		;get bank
	OUT	(MMUSEL),A	;and select it
	RET
;
;	poll character devices
;
POLLDEVICE:
	JP	PTSTI0		;poll console 0 status in
;
;	start clock
;
STARTCLOCK:
	LD	A,0FFH
	LD	(TICKN),A
	RET
;
;	stop clock
;
STOPCLOCK:
	XOR	A
	LD	(TICKN),A
	RET
;
;	exit region:
;	enable interrupt if not preempted or in dispatcher
;
EXITREGION:
	LD	A,(PREEMP)
	OR	A
	RET	NZ
	EI
	RET
;
;	maximum console number
;
MAXCONSOLE:
	LD	A,1
	RET
;
;	system initialization
;		C	MP/M debugger restart #
;		DE	MP/M entry point for debugger
;		HL	BIOS jump table address
;
SYSTEMINIT:
;
	LD	A,8		;initialize banked memory
	OUT	(MMUINI),A
	LD	B,A
;
SYS1:	DEC	B
	LD	A,B
	OUT	(MMUSEL),A	;select every bank and initialize
	LD	A,0C3H		;jp instruction
	LD	(0),A
	LD	(38H),A
	LD	(1),HL
	PUSH	HL
	LD	HL,INTHND
	LD	(39H),HL
	POP	HL
	JP	NZ,SYS1
;
	LD	HL,SIGNON	;print message
SYS2:	LD	A,(HL)
	OR	A
	JP	Z,SYS3
	OUT	(CONDAT),A
	INC	HL
	JP	SYS2
;
SYS3:	IM	1
	LD	A,1		;enable 20ms interrupt timer
	OUT	(TIMER),A
	EI
	RET
;
;	idle
;
IDLE:	EI
	HALT
	RET
;
;	interrupt handler
;
INTHND:	LD	(SVDHL),HL	;save registers
	POP	HL
	LD	(SVDRET),HL
	PUSH	AF
	LD	HL,0
	ADD	HL,SP
	LD	(SVDSP),HL
	LD	SP,INTSTK
	PUSH	DE
	PUSH	BC
	LD	A,0FFH		;set preempted flag
	LD	(PREEMP),A
	LD	A,(TICKN)
	OR	A		;test tick, indicates delayed process
	JP	Z,INTHND1
	LD	C,FLAGSET	;set flag #1 each tick
	LD	E,1
	CALL	XDOS
INTHND1:
	LD	HL,CNT50	;decrement tick counter
	DEC	(HL)
	JP	NZ,INTDONE
	LD	(HL),50		;set flag #2 each second
	LD	C,FLAGSET
	LD	E,2
	CALL	XDOS
INTDONE:
	XOR	A		;clear preempted flag
	LD	(PREEMP),A
	POP	BC		;restore registers
	POP	DE
	LD	HL,(SVDSP)
	LD	SP,HL
	POP	AF
	LD	HL,(SVDRET)
	PUSH	HL
	LD	HL,(PDISP+1)	;dispatch processes
	PUSH	HL
	LD	HL,(SVDHL)
	RETI
;
;	i/o drivers for disks
;
;	move to the track 00 position of current drive
;	translate this call into a settrk call with parameter 00
;
HOME:	LD	C,0		;select track 0
	JP	SETTRK		;we will move to 00 on first read/write
;
;	select disk given by register C
;
SELDSK: LD	HL,0000H	;error return code
	LD	A,C
	CP	4		;must be between 0 and 3
	JR	NC,SELHD	;no carry if 4,5,...
;	disk number is in the proper range
;	compute proper disk parameter header address
	OUT	(FDCD),A	;selekt disk drive
	LD	L,A		;L=disk number 0,1,2,3
	ADD	HL,HL		;*2
	ADD	HL,HL		;*4
	ADD	HL,HL		;*8
	ADD	HL,HL		;*16 (size of each header)
	LD	DE,DPBASE
	ADD	HL,DE		;HL=.dpbase(diskno*16)
	RET
SELHD:	CP	8		;select the harddisk?
	RET	NZ		;no, error
	OUT	(FDCD),A	;select disk drive
	LD	HL,HDBASE	;HL=hdbase for harddisk
	RET
;
;	set track given by register c
;
SETTRK: LD	A,C
	OUT	(FDCT),A
	RET
;
;	set sector given by register c
;
SETSEC: LD	A,C
	OUT	(FDCS),A
	RET
;
;	translate the sector given by BC using the
;	translate table given by DE
;
SECTRAN:
	EX	DE,HL		;HL=.trans
	ADD	HL,BC		;HL=.trans(sector)
	LD	L,(HL)		;L = trans(sector)
	LD	H,0		;HL= trans(sector)
	RET			;with value in HL
;
;	set dma address given by registers b and c
;
SETDMA: LD	A,C		;low order address
	OUT	(DMAL),A
	LD	A,B		;high order address
	OUT	(DMAH),A	;in dma
	RET
;
;	perform read operation
;
READ:	XOR	A		;read command -> A
	JP	WAITIO		;to perform the actual i/o
;
;	perform a write operation
;
WRITE:	LD	A,1		;write command -> A
;
;	enter here from read and write to perform the actual i/o
;	operation.  return a 00h in register a if the operation completes
;	properly, and 01h if an error occurs during the read or write
;
;	in this case, we have saved the disk number in 'diskno' (0-3)
;			the track number in 'track' (0-76)
;			the sector number in 'sector' (1-26)
;			the dma address in 'dmaad' (0-65535)
;
WAITIO:	PUSH	AF
	CALL	SWTUSER		;switch to user page
	POP	AF
	OUT	(FDCOP),A	;start i/o operation
	IN	A,(FDCST)	;status of i/o operation -> A
	PUSH	AF
	CALL	SWTSYS		;switch back to system page
	POP	AF
	RET
;
;	XIOS data segment
;
SIGNON:	DEFB	13,10
	DEFM	'MP/M 2 XIOS V1.2 for Z80SIM, '
	DEFM	'Copyright 1989-2006 by Udo Munk'
	DEFB	13,10,0
;
TICKN:	DEFB	0		;flag for tick
PREEMP:	DEFB	0		;preempted flag
TOD:	DEFS	4		;time of day
SVDHL:	DEFS	2		;save hl during interrupt
SVDRET:	DEFS	2		;save return address during interrupt
SVDSP:	DEFS	2		;save sp during interrupt
CNT50:	DEFB	50		;50 ticks a 20ms = 1 second
				;interrupt stack
	DEFW	0C7C7H,0C7C7H,0C7C7H,0C7C7H
	DEFW	0C7C7H,0C7C7H,0C7C7H,0C7C7H
	DEFW	0C7C7H,0C7C7H,0C7C7H,0C7C7H
	DEFW	0C7C7H,0C7C7H,0C7C7H,0C7C7H
INTSTK:
;
;	fixed data tables for four-drive standard
;	IBM-compatible 8" disks
;
;	disk parameter header for disk 00
DPBASE:	DEFW	TRANS,0000H
	DEFW	0000H,0000H
	DEFW	DIRBF,DPBLK
	DEFW	CHK00,ALL00
;	disk parameter header for disk 01
	DEFW	TRANS,0000H
	DEFW	0000H,0000H
	DEFW	DIRBF,DPBLK
	DEFW	CHK01,ALL01
;	disk parameter header for disk 02
	DEFW	TRANS,0000H
	DEFW	0000H,0000H
	DEFW	DIRBF,DPBLK
	DEFW	CHK02,ALL02
;	disk parameter header for disk 03
	DEFW	TRANS,0000H
	DEFW	0000H,0000H
	DEFW	DIRBF,DPBLK
	DEFW	CHK03,ALL03
;
;	sector translate vector for the IBM 8" disks
;
TRANS:	DEFB	1,7,13,19	;sectors 1,2,3,4
	DEFB	25,5,11,17	;sectors 5,6,7,8
	DEFB	23,3,9,15	;sectors 9,10,11,12
	DEFB	21,2,8,14	;sectors 13,14,15,16
	DEFB	20,26,6,12	;sectors 17,18,19,20
	DEFB	18,24,4,10	;sectors 21,22,23,24
	DEFB	16,22		;sectors 25,26
;
;	disk parameter block, common to all IBM 8" disks
;
DPBLK:  DEFW	26		;sectors per track
	DEFB	3		;block shift factor
	DEFB	7		;block mask
	DEFB	0		;extent mask
	DEFW	242		;disk size-1
	DEFW	63		;directory max
	DEFB	192		;alloc 0
	DEFB	0		;alloc 1
	DEFW	16		;check size
	DEFW	2		;track offset
;
;	fixed data tables for 4MB harddisk
;
;	disk parameter header
HDBASE:	DEFW	HDTRA,0000H
	DEFW	0000H,0000H
	DEFW	DIRBF,HDBLK
	DEFW	CHKHD,ALLHD
;
;	sector translate vector for the hardisk
;
HDTRA:	DEFB	1,2,3,4,5,6,7,8,9,10
	DEFB	11,12,13,14,15,16,17,18,19,20
	DEFB	21,22,23,24,25,26,27,28,29,30
	DEFB	31,32,33,34,35,36,37,38,39,40
	DEFB	41,42,43,44,45,46,47,48,49,50
	DEFB	51,52,53,54,55,56,57,58,59,60
	DEFB	61,62,63,64,65,66,67,68,69,70
	DEFB	71,72,73,74,75,76,77,78,79,80
	DEFB	81,82,83,84,85,86,87,88,89,90
	DEFB	91,92,93,94,95,96,97,98,99,100
	DEFB	101,102,103,104,105,106,107,108,109,110
	DEFB	111,112,113,114,115,116,117,118,119,120
	DEFB	121,122,123,124,125,126,127,128
;
;       disk parameter block for harddisk
;
HDBLK:  DEFW    128		;sectors per track
	DEFB    4		;block shift factor
	DEFB    15		;block mask
	DEFB    0		;extent mask
	DEFW    2039		;disk size-1
	DEFW    1023		;directory max
	DEFB    255		;alloc 0
	DEFB    255		;alloc 1
	DEFW    0		;check size
	DEFW    0		;track offset
;
DIRBF:	DEFS	128		;scratch directory area
ALL00:	DEFS	31		;allocation vector 0
ALL01:	DEFS	31		;allocation vector 1
ALL02:	DEFS	31		;allocation vector 2
ALL03:	DEFS	31		;allocation vector 3
ALLHD:	DEFS	255		;allocation vector harddisk
CHK00:	DEFS	16		;check vector 0
CHK01:	DEFS	16		;check vector 1
CHK02:	DEFS	16		;check vector 2
CHK03:	DEFS	16		;check vector 3
CHKHD:	DEFS	0		;check vector harddisk
;
	END
