;-----------------------------------------------------------
;
;   SWSPUZ.A86 : 8088 Portion of switch code
;
;-----------------------------------------------------------
	page

	org	100h

start:	cld
;
	LD	CL,#s_getcn		;Find out which console wants us
	INT	S_INT			;Go call S_INT
; For now slaves start at console 1 ***DEBUG*****
;	DEC	AL
;**********************************
	MOV	CL,AL			;Save console number
	MOV	AH,AL			;Put in AH to make segment
	SHL AH ! SHL AH			;Put in upper nibble
	SHL AH ! SHL AH
	ADD	AH,#0C0H		;Turn into page number
	XOR	AL,AL
	MOV	ES,AX			;Put into es for moves
	MOV	DX,AX			;And into dx for later
;Really want to MX here to be sure slave is free
	$ES ! STOB CL,[NUMCON]		;Save CONSOLE number for later
	$ES ! STOB #ZJMP,[NMIVECT]	;Set jump to Z80 wait loop
	$ES ! STO #ZWAIT,[NMIVECT+1]	;At Z80 NMI vector
	LD	AL,#1			;Set low bit in al 
	SHL	AL,CL			;Set bit corresponding to this slave 
	OUT	ZCNTRL,AL		;Send to contorl port
	XOR	AL,AL			;Now clear AL
	OUT	ZCNTRL,AL		;To clear NMI line
;
	ld	si,#cs_80		;Move Z80 code
	ld	di,#cd_80
	ld	cx,#cl_80/2
	rep
	movs

	ld	si,#cs_88		;Move 8088 data
	ld	di,#cd_88
	ld	cx,#cl_88/2
	rep	
	movs


	push	es
	push	dx		;Save 64K block segment
	ld	cl,#s_getpd	;Return PD address
	int	S_INT
	$es
	ld	ax,[bx+10h]	;Pick up UDA address
	push	ax		;Save UDA address
	ld	si,#5dh		;Start at name part of fcb	
	add	bx,#8		;Offset into name part of PD
	mov	di,bx		;Put start of name in (di)
	ld	cx,#8		;Command name of 8 bytes
	repz
	movsb
	pop	ax
	pop	dx
	pop	es

	ld	si,#0		;Move base page here to give Z80 time to pass
	ld	di,#0		;NMI vector
	ld	cx,#100h/2
	rep
	movs			

	mov	ds,dx	
	push	es
	ld	cl,#s_dma_base	;Set new DMA segment
	int	S_INT

	ld	cl,#s_cur_disk	;Setup default disk number
	int	S_INT
	sto	al,[x_drive]
	pop	es

	stob	#0,[x_bytes]	;Initialize # of I/O calls in char buffer to 0
	stob	#10,[x_cs]	;Do 10 console status checks befor switch 
	stob	#0c3h,[bdose]	; JMP BDOS vector
	stob	#(bd and 0ffh),[bdose+1]
	stob	#(bd / 100h), [bdose+2]

	

cpskp7:	ld	cl,#s_userno		;Ask MP/M what our current user number is
	ld	dl,#0ffh
	call	inesys
	sto	al,[x_user]		;Save it for Z80

;-------------------------
;
;  Read Program File
;
;-------------------------

	ld	si,#@com	; Set file type to COM
	ld	di,#s_fcb0+fcb_typ
	ld	cx,#3
	rep
	movsb

	ld	ax,#0		; Clear all of fcb1 to 0
	ld	di,#s_fcb1
	ld	cx,#8
	rep !   stosb	

	ld	dx,#s_fcb0	; open "com" file given in fcb0
	call	open
	cmp	al,#0FFh
	jne	@100		; open ok
	ld	dx,#e_nocmd	; Else open was not OK so print error message
	call	error		;and quit	
@100:
	;*** read program loop
	ld	dx,#100h	;Put "com" at 100h for Z80

@110:	push	dx		;Save current DMA location
	ld	cl,#s_dma
	call	inesys
	ld	cl,#s_read	;Go read a sector of the "com" file 
	ld	dx,#s_fcb0
	call	inesys
	pop	dx
	add	dx,#80h		;Point to spot for next sector
	cmp	al,#1		;See if End Of File reached
	je	@120		;Program read in OK if reached EOF
	cmp	al,#0		;See if last sector read OK with no EOF 
	je	@110		; Loop back to read next sector if so 
	ld	cl,#s_userno	;If error,Set user back to original user number
	ld	dl,x_user	; OPEN routine may have changed user number
	call	inesys
	ld	dx,#e_read	;Show read error message
	call	error
@120:
	ld	cl,#s_close	; *** close input if read OK or error
	ld	dx,#s_fcb0
	call	inesys
	ld	cl,#s_dma	;Reset DMA address back to CP/M 80 default
	ld	dx,#80h
	call	inesys
	ld	cl,#s_userno	;Set orginal user number back (OPEN may have changed it)
	ld	dl,x_user
	call	inesys

	page

;-------------------------------
;
;  parse command line, finish fill of page 0
;
;-------------------------------
				; *** parse to skip program name
	sto	#81h,pfcb	;Set start address of line for MP/M to parse
	ld	cl,#s_parse	;In MP/M parse buffer block
	ld	dx,#pfcb	;Get address of parse buffer block
	call	inesys
	cmp	ax,#0		;See if line parsed oK
	jne	@210
	ld	al,80h		;Get length of command line typed in
	ld	ah,#0
	add	ax,#80h
@210:
	inc	ax
	mov	bl,al		;Save pointer past program name
	sub	bl,#81h		;Determine length of program name
	ld	cl,[80h]	;Get total length of command line
	sub	cl,bl		;Determine length of remainder of command line
	sto	cl,[80h]	;Store new command line length

				; move command tail over program name
	mov	si,ax		;Turn Command tail into an 8 bit command line
	ld	di,#82h		;Ie. take out "com" file name  
	ld	ch,#0
	rep
	movsb

	xor	al,al		;Clear out remainder of command line
	mov	cl,bl		; by filling with zero's 
@215:	REP !	STOSB
				;*** clear fcb0 area
	ld	DI,#s_fcb0	;Since "com" file was there
	ld	cx,#16
@220:	REP !	STOSB
				;*** parse fcb0 for program
	ld	cl,#s_parse	;Parse file user gave to 8 bit program
	ld	dx,#pfcb
	call	inesys
	cmp	ax,#0
	jne	@230		; not eol
	ld	ax,#e_cr
@230:	sto	ax,[pfcb]	;Move file user gave to 8 bit program to 
	ld	si,#fcb		;     FCB0, Parse left new FCB at "fcb"
	ld	di,#s_fcb0
	ld	cx,#8		;Only move name
	rep
	movs
	cmp	ax,#0FFFFh
	je	@280
	page


				;*** parse fcb1 for program
	ld	cl,#s_parse
	ld	dx,#pfcb
	call	inesys
@280:	ld	si,#fcb
	ld	di,#s_fcb1
	ld	cx,#8
	rep
	movs
@290:
	sto	#0h,x_p		;Set Z80 registers upon entry to 8 bit program
	sto	#100h,x_p-2
	sto	#x_p-2,x_sp
	ld	ax,#0		;Set all working registers to 0
	sto	ax,x_psw
	sto	ax,x_bc
	sto	ax,x_de
	sto	ax,x_hl
				;*** setup page 0 8085 code
	ld	si,#x_page0	;Move "JMP BIOS", "JMP BDOS", curuser & curdrive 
	ld	di,#0		;To page 0
	ld	cx,#x_pl
	rep
	movsb
	ld	cl,#2dh		; Set error mode so MP/M only errors come back 
	ld	dl,#0feh	; to us and are not printed to the user
	call	inesys

@1012	
	jmp	go_z80		;Enter resident 8088 code

inesys	push	es
	int	S_INT
	pop	es
	ret

open:
;------------------------------------------------------
;
;  call open
;
;  Open a disk file for current user number or user 0,
;  drive A.
;
;  ENTRY	DX	Address of fcb
;
;  EXIT		AL	System error code (0FFh for open failed)
;------------------------------------------------------

	proc
	push	dx
	ld	cl,#s_open
	call	inesys
	pop	dx
	cmp	al,#0FFh
	jne	:900		; open ok

				;*** try open from user 0, drive A
	mov	bx,dx
	ld	bl,[bx+fcb_drive]
	and	bl,#0fh
	jnz	:900

	sto	dx,[Sysfcb]
	push	dx
	ld	cl,#s_userno
	ld	dl,#0
	call	inesys
	pop	dx
	mov	bx,dx
	stob	#1,[bx+fcb_drive]
	ld	cl,#s_open
	call	inesys
:900	ret
	page

error:
;-----------------------------------------------------
;
;  jmp error
;
;  Print error message and terminate.
;
;  ENTRY	DX	Address of string for print function.
;
;  EXIT			Never returns
;------------------------------------------------------

	ld	cl,#s_print
	int	S_INT
	ld	cl,#s_exit
	ld	dl,#0
	int	S_INT
	page

go_z80:
;--------------------------------
;
;  Switch to SLAVE
;
;--------------------------------
@300:	LD	AL,#0FFH		;Tell Z80 system call is done
	STOB	AL,[INTBYT]		;Or to begin execution
;
	LD	CL,#s_flgwt		;Call mpm to wait for flag
	LD	DL,[NUMCON]		;Get current console number
	ADD	DL,#F_ZSLV		;Add base flag number to console number
	CALL	ESYS			;Call system to wait for interrupt flag
;
@500:				;*** issue system call
	ld	cx,x_bc		;Get Z80's registers
	ld	dx,x_de		;For system call
	ld	ch,#0
	call	flush
	cmp	cl,#S_FLUSH
	je	go_z80		;Dumb...
	cmp	cl,#36		;See if function is a CP/M 2.2 call and prehaps
	jbe	@501		;Specially handled
    	jmp	@506		;Otherwise just do an INT call

flush:
	push	cx		;Save function number
	push	dx		; and parameter
	ld	dl,[x_bytes]	;Get number
	ld	bx,#x_chars	;Get start of I/O call buffer
flush1	cmp	dl,#0		;See if any I/O call pending
	je	flush2		;done if none pending
	push	dx		;Save count and pointer in buffer
	push	bx
	ld	dl,[bx]		;Pick up character
	inc	bx
	ld	cl,[bx]		;Pick up call type
	int	S_INT		;Perform I/O call
	pop	bx
	pop	dx
	add	bx,#2		;Point to next entry
	dec	dl		;Count entry just done
	jmp	flush1

flush2	stob	#0,[x_bytes]	;All I/O call done so clear count
	pop	dx
	pop	cx
	ret

@501:
	mov	bx,cx		;Get function number in BX
	shl	bx		;*2 for word pointers 	
	$cs
	jmp	[bx+CallAddr]	;Jump to vector in table

CallAddr:	
	dw	@exit		; 0 = System reset
	dw	cpmin		; 1 = Console input
	dw	@504		; 2 = Console output
 	dw	@504		; 3 = Raw console input
	dw	@504		; 4 = Raw console output
	dw	@504		; 5 = List output
	dw	@905		; 6 = Direct console I/O
	dw	@504		; 7 = Get I/O byte
	dw	@504		; 8 = Set I/I byte
	dw	@504		; 9 = Print string
	dw	@504		;10 = Read console buffer
	dw	@504		;11 = Console status
	dw	@530		;12 = Return version number
	dw	go_z80		;13 = Reset disks
	dw	@506		;14 = Select disk
	dw	@540		;15 = Open file
	dw	@550		;16 = Close file
	dw	@506		;17 = Search for first
	dw	@506		;18 = Search for next
	dw	@506		;19 = Delete file
	dw	@560		;20 = Read sequential
	dw	@560		;21 = Write sequential
	dw	@540		;22 = Create file
	dw	@506		;23 = Rename file
	dw	@506		;24 = Return login vector
	dw	@506		;25 = Return current default disk
	dw	@506		;26 = Set DMA address
	dw	@510		;27 = Return ALV
	dw	@506		;28 = Write protect disk
	dw	@506		;29 = Get R/O vector
	dw	@506		;30 = Set file attributes
	dw	@520		;31 = Return DPB
	dw	@506		;32 = Get/Set user code
	dw	@560		;33 = Read random
	dw	@560		;34 = Write random
	dw	@506		;35 = Compute file size
	dw	@506		;36 = Set random record

	page

cpmin	call	newin		;Go get a char from MP/M
	cmp	al,#'S'-64	;Check for CTRL-S
	jne	nots		;
qwait:	call	newin		;If CTRL-S was typed, wait for a CTRL-Q to  
	cmp	al,#'Q'-64	; be typed before proceeding
	je	cpmin
	ld	cl,#4		;If any other character is typed, print a bell
	ld	dl,#'G'-64	; to the console until the user types a CTRL-Q
	int	S_INT
	jmp	qwait		;Wait for ever if necassary

nots	push	ax		;Save the Character we just got
	mov	dl,al		;Echo it for the 8 bit program 
	and	dl,07fh		;
	ld	cl,#2		; With MP/M console output routine
	int	S_INT
	pop	ax		;Recover Character
	jmp	@505		;And go give  it to the Z80

@exit	ld	dl,#0		;Exit to the system and release any resources 
	int	S_INT		; This never returns

@905	call	newin		;Here for direct console I/O
	jmp	@505
newin:	cmp	dl,#0fdh	;See if I/O call is input only
	jne	@907
@906	ld	dl,#0ffh	;Else check input status and come right back
	ld	cl,#6
	int	S_INT
	cmp	al,#0		;See if a character was ready
	je	@906		;Try again if no character was ready
	ret			;Else return now

@907	int	S_INT
	ret

@504:
@506:
	int	S_INT		; int for console I/O

@505:	sto	al,x_psw+1
	sto	ax,x_hl
	sto	bx,x_bc
	jmp	go_z80

@510:				;*** get ALV request
	int	S_INT
	cmp	ax,#0FFFFh
	je	@505		; error
	ld	cx,#80h		;Move 80h bytes of ALV to Z80 space
	mov	si,ax		;Source is returned in AX	
	ld	ax,#x_alv	;Destination in Z80 space in AX for CP/M return
	mov	di,ax		;And into DI for MOV
	mov	bx,ds		;Swap DS and ES registers for move             
	mov	dx,es
	mov	ds,dx
	mov	es,bx
	rep
	movs
	mov	ds,bx		;Restore DS register
	jmp	@505		;Go back to Z80
	page
@520:				;*** get DPB request
	int	S_INT
	cmp	ax,#0FFFFh
	je	@505		; error
	ld	cx,#15		;Move 15 bytes of DPB to Z80 space            
	mov	si,ax           ;Offset of DPB is returned in AX	               
	ld	ax,#x_dpb       ;Destination in Z80 space in AX for CP/M return
	mov	di,ax           ;And into DI for MOV                           
	mov	bx,ds           ;Swap DS and ES registers for move             
	mov	dx,es
	mov	ds,dx
	mov	es,bx
	rep
	movsb
	mov	ds,bx		;Restore DS register
	jmp	@505		;And go back to Z80

@530:					;*** version
;	ld	ax,#0022h		; look like CP/M 2.2
	LD	AX,#1130		; look like MP/M 2.1
	jmp	@505

@540:					;*** open a file
	mov	bx,dx
	stob	#0,[bx+fcb_cr]
	int	S_INT
	jmp	@505

@550:					;*** close a file
	int	S_INT
	jmp	@505

	page

@560:					;*** disk read/write
	push	cx
	push	dx
	int	S_INT
	pop	dx
	pop	cx
	cmp	al,#10			; fcb checksum error
	je	@562
	cmp	al,#9			; invalid fcb
	je	@562
	jmp	@505
@562:					; try to reopen file and redo I/O
	push	bx
	push	cx
	push	dx
	ld	cl,#s_open
	int	S_INT
	pop	dx
	pop	cx
	pop	bx
	or	al,al
	jz	@566			; open OK
	ld	al,#10
	jmp	@505
@566:
	int	S_INT			; reissue I/O
	jmp	@505

	proc

esys:
;-----------------------------------------------------
;
;  call esys
;
;  Issue system call interrupt
;-----------------------------------------------------
	push	es
	int	S_INT
	pop	es
	ret
sys:
;-----------------------------------------------------
;
;  call sys
;
;  Issue system call interrupt
;-----------------------------------------------------
	int	S_INT
	ret
	page

;-----------------------------------------------------
;
;  Data Area
;
;-----------------------------------------------------
cs_88:
	loc	cd_88
@com	db	'COM'
e_cr	db	cr
e_nocmd	db	'Program file cannot be opened',cr,lf,'$'
e_read	db	'SW: Disk read error',cr,lf,'$'

fcb	ds	36
pfcb	dw	0,fcb
Sysfcb	dw	0
	
NUMCON	DB	0		;Console number is kept here

cl_88	equ	$-cd_88		;Length of 8088 data

	end



