;RESCOD.68K	FEB-25-89	(ALSO SEE NULLSTR)
;APEX MEMORY-RESIDENT MODULE
;WRITTEN BY LOREN BLANEY FOR DFM ENGINEERING
;THIS IS BASED ON 6502 CODE WRITTEN BY P.J.R. BOYLE.
;
;REVISION HISTORY:
;FEB-28-86, ORIGINAL
;SEP-DEC-86, CHANGED TO ASM68K CONVENTIONS AND MODIFIED FOR NEW MEMORY
; MAP.
;APR-28-88, MODIFIED FOR MAC II.
;JUN-88, FIXED ERROR ROUTINE WHICH DIDN'T LOOK FOR THE CORRECT STRING
; TERMINATION, MADE SWAP SIZE VERY SMALL (TO FIX WRITE-PROTECTED RAM
; DISK), FIXED UNINSTALLED DEBUGGER BUG, REMOVED FASAVE, OPEN DISK ONLY
; AT BOOT UP.
;FEB-25-89, ADDED CONDITIONAL ASSEMBLY FLAG TO HANDLE AMIGA-1000'S NEED
; FOR A SMALL SWAP SIZE REQUIRED WITH WRITE-PROTECTED KICKSTART RAM.
;
;WARNINGS:
; IF THIS MODULE IS INSTALLED THEN ALL HANDLERS MUST BE REINSTALLED.
;
;NOTES:
; SCRATCH.SYS is nomally big enough to contain all the memory that Apex
; uses. This is essential for a swapping operating system. However,
; because of a special problem with the Amiga's RAM disk (it is write
; protected), SCRATCH.SYS has been made very small. With the 68000's
; relatively large amounts of memory, the swapping feature is unimpor-
; tant. Only two blocks are swapped. The first contains SYSPAG; the
; second is only used to avoid a possible bug where writting zero blocks
; writes many blocks.

	NOLIST
	INCLUDE	SYSPAG		;GET SYSTEM PAGE DEFINITIONS
	LIST

;SYSTEM DEFINITIONS:
	IF	A1000
SWPLOC	EQU	MEMTOP -$4100	;BASE ADDRESS OF SWAPPED MEMORY (1 BLOCK
	ELSE			; FOR SAFETY)
SWPLOC	EQU	MEMTOP -$B800	;BASE ADDRESS OF SWAPPED MEMORY
	ENDIF
SWPEND	EQU	MEMTOP -$4000	;END OF SWAPPED MEMORY +1
SWPSIZ	EQU	[SWPEND-SWPLOC]/$100 ;SIZE OF SWAPPED MEMORY (BLOCKS)
DIRBUF	EQU	MEMTOP -$B800	;LOC FSCAN USES FOR THE DIRECTORY (1K)

XDIRBLK	EQU	1		;BLOCK WHERE EXTENDED DIRECTORY BEGINS
DIRBLK	EQU	9		;BLOCK WHERE THE MAIN DIRECTORY BEGINS

MAXFL	EQU	47		;MAX NO. OF FILES (-1) ON ONE DIRECTORY
EXTPAT	EQU	$A5		;PATTERN INDICATING VALID EXTENDED DIR

COMPAG	ORG	MEMTOP -$3000	;APEX'S COPY OF SYSPAG
	ORG	@ +$100
START	EQU	@		;MARK START OF THIS MODULE

;=======================================================================
;ENTRY POINTS:
;
; *** KLUDGE TO INITIALIZE RAM DISK UNIT 2. ***
; APEX SHOULD BE FIXED SO THAT "SY N" REALLY ENTERS HERE. AND THAT UNIT
; "N" IS OPENED. FOR NOW IT IS KLUDGED.
;
OPENUNT2
	LEA	MEMTOP.L,SP	;SET STACK
	CLR.L	ERRLOC		;INDICATE NO ERRORS

	CLR.B	UNIT		;INITIALIZE THE DISK DRIVER
	MOVEA.W	#0,A6		;OPEN(0)
	BSR	UNTHAN

	MOVE.B	#2,UNIT		;INITIALIZE THE DISK DRIVER
	BSR	UNTHAN		;OPEN(0)

;RELOAD APEX FROM THE SYSTEM UNIT AND START IT.
; THIS IS THE FIRST-TIME, BOOT-UP ENTRY POINT.
;
RELOAD	LEA	MEMTOP.L,SP	;SET STACK
	MOVE.B	#$FC,SYSENF	;INDICATE A "RELOAD" ENTRY
	CLR.L	ERRLOC		;INDICATE NO ERRORS
	CLR.B	CMDMOD		;TURN OFF EXEC MODE (COMMAND FILES)

	CLR.B	DEVICE		;INITIALIZE THE CONSOLE
	MOVEA.W	#0,A6		;OPENI(0)
	BSR	DEVHAN
	MOVEA.W	#4,A6		;OPENO(0)
	BSR	DEVHAN

;	MOVE.B	SYSUNT,UNIT	;INITIALIZE THE DISK DRIVER
;	MOVEA.W	#0,A6		;OPEN(0)
;	BSR	UNTHAN
;	BSR	SHOWERR		;SHOW ERROR IF ANY

	MOVE.B	SYSUNT,UNIT	;SCAN FOR "SYSTEM.SYS" ON SYSTEM UNIT
	LEA	SYSFIL-@-2(PC),A6
	BSR	FSCAN
	BSR	SHOWERR		;GO HANDLE FILE NOT FOUND ERROR, IF ANY
	MOVE.L	BLKNO,SYSBLK	;SAVE SYSTEM.SYS BLOCK NUMBER FOR LATER
	BRA	FRUN		;START THE SYSTEM

SYSFIL	ASCII	'SYSTEM  SYS '	;SYSTEM FILE NAME
	DC.B	0
SWPFIL	ASCII	'SCRATCH SYS '	;SWAP (SCRATCH) FILE NAME
	DC.B	0

;-----------------------------------------------------------------------
;RE-ENTER APEX BUT RELOAD IT ONLY IF THE "SYBOMB" FLAG IS SET.
; THIS IS THE NORMAL ENTRY POINT TAKEN AFTER A PROGRAM FINISHES OR WHEN
; A CTRL-C IS PRESSED.
; NOTE THAT ALL .SAV FILES BOMB SYSPAG. SO APEX'S SYSPAG IS SAVED IN
; COMPAG TO AVOID HAVING TO REREAD IT FROM DISK, WHICH SPEEDS THINGS UP
; A LITTLE.
;
; THE STATE OF THE "SYBOMB" FLAG IS USED TO DETERMINE THE FOLLOWING:
;	00	SYSTEM IS NOT BOMBED, JUST SYSPAG
;	55	SYSTEM IS NOT BOMBED, AND SYSPAG IS OK
;	OTHER	RELOAD APEX
;
RENTER	LEA	MEMTOP.L,SP	;SET STACK
	MOVE.B	#$FD,SYSENF	;INDICATE A "REENTER" ENTRY
	CLR.L	ERRLOC		;INDICATE NO ERRORS

RENTERX	TST.B	SYBOMB		;ATTEMPT TO GET APEX'S SYSTEM PAGE
	BNE.S	REN20		; FROM COMPAG
	MOVEQ	#63,D0		;GET 64 LONG WORDS = 256 BYTES
	LEA	COMPAG-@-2(PC),A5 ;SET UP POINTERS
	LEA	SYSPAG,A6
REN10	MOVE.L	(A5)+,(A6)+	;MOVE COMPAG INTO SYSPAG
	DBF	D0,REN10
REN20
	CMPI.B	#$55,SYBOMB	;VALID SYSPAG?
	BEQ	FRUNX		;BRANCH IF SO -- APEX IS IN MEMORY
				;(FSAVE ENTRY MUST BE INDICATED EVEN IF
				; APEX IS RELOADED)

	MOVE.B	SYSUNT,UNIT	;SCAN FOR "SYSTEM.SYS" ON SYSTEM UNIT
	LEA	SYSFIL-@-2(PC),A6
	BSR	FSCAN
	BSR	SHOWERR		;GO HANDLE FILE NOT FOUND ERROR, IF ANY
	MOVE.L	BLKNO,SYSBLK	;SAVE SYSTEM.SYS BLOCK NUMBER FOR LATER
	BRA	FRUN		;START THE SYSTEM

;-----------------------------------------------------------------------
;SAVE THE PART OF THE MEMORY IMAGE THAT WILL BE BOMBED BY APEX, THEN
; RELOAD AND RESTART APEX.
; THIS IS THE NORMAL ENTRY POINT FOR A CTRL-P.
;
SAVER	LEA	MEMTOP.L,SP	;SET STACK
	MOVE.B	#$FE,SYSENF	;INDICATE A "SAVER" ENTRY
	CLR.L	ERRLOC		;INDICATE NO ERRORS

	MOVE.B	SYSUNT,UNIT	;LOOK FOR "SCRATCH.SYS" ON SYSTEM UNIT
	LEA	SWPFIL-@-2(PC),A6
	BSR	FSCAN
	BSR	SHOWERR		;HANDLE "FILE NOT FOUND" ERROR, IF ANY
	MOVE.L	BLKNO,SWPBLK	;SAVE "SCRATCH.SYS" BLOCK NO. FOR LATER

	MOVE.L	#SWPLOC,DSKMEM	;WRITE THE PART OF THE MEMORY IMAGE THAT
	MOVE.L	#SWPSIZ,DSKSIZ	; WILL BE BOMBED BY "SYSTEM.SYS" INTO
	BSR	SAVE		; "SCRATCH.SYS"

	BRA	RENTERX		;GO RESTART APEX

;=======================================================================
;SPECIAL INTRINSICS FOR APEX:
; (NOTE THAT THESE "INTRINSICS" ARE NOT CALLED DIRECTLY BY XPL CODE, BUT
; THROUGH THE REAL INTRINSICS IN INT32.68K)
;
;RUN THE MEMORY IMAGE (.SAV FILE) WHICH BEGINS AT "BLKNO" ON "UNIT".
; THE LOAD LOCATION (DSKMEM) AND THE NUMBER OF BLOCKS TO LOAD (DSKSIZ)
; ARE GOTTEN FROM "SYSPAG" WHICH IS SAVED AS THE FIRST BLOCK OF THE FILE
;
; FRUN(UNIT, BLKNO)
;
; (THE READ INTRINSIC IS NOT SUFFICIENT BECAUSE THE LOADED PROGRAM MAY
; BOMB THE SYSTEM AND PREVENT IT FROM STARTING THE LOADED PROGRAM.)
;
FRUN	LEA	MEMTOP.L,SP	;SET STACK (FOR SWAP AREA)
	BSR	SAVPAG		;SAVE APEX'S SYSTEM-PAGE PARAMETERS
	BSR	GET		;LOAD THE MEMORY IMAGE (THE PROGRAM)
FRUNX	CLR.B	RERUNF		;CLEAR THE RERUN FLAG
	CLR.L	ERRLOC		;INDICATE NO ERRORS
	MOVEA.L	STACK,A7	;SET THE STACK POINTER
	MOVEA.L	HEAP,A5		;SET THE HEAP POINTER
	JSR	VSTART		;CALL THE LOADED PROGRAM
	BSR	SHOWERR		;DISPLAY ANY ERRORS
	JMP	VEXIT		;TAKE THE PROGRAM'S EXIT VECTOR

;-----------------------------------------------------------------------
;GET THE MEMORY IMAGE (.SAV FILE) WHICH BEGINS AT "BLKNO" ON "UNIT"
; AND START THE DEBUGGER. SAME AS FRUN, BUT IT STARTS THE DEBUGGER
; INSTEAD OF THE LOADED PROGRAM.
; FGET(UNIT,BLKNO)
;
FGET	LEA	MEMTOP.L,SP	;SET STACK (FOR SWAP AREA)
	BSR	SAVPAG		;SAVE APEX'S SYSTEM-PAGE PARAMETERS
	BSR	GET		;LOAD THE MEMORY IMAGE
	CLR.B	RERUNF		;CLEAR THE RERUN FLAG
	CLR.L	ERRLOC		;INDICATE NO ERRORS
	MOVEA.L	STACK,A7	;SET THE STACK POINTER
	MOVEA.L	HEAP,A5		;SET THE HEAP POINTER
	JMP	VBUG		;CALL THE DEBUGGER

;-----------------------------------------------------------------------
;SAVE A MEMORY IMAGE FOR A .SAV FILE (CMDSAV)
; FSAVE(UNIT,BLKNO)
; IN ADDITION TO THE "UNIT" AND "BLKNO" INPUTS, THE MEMORY ADDRESS
; (USRMEM) AND THE SIZE IN PAGES (PROSIZ) ARE GIVEN. THESE ARE SET UP
; BY THE USER'S PROGRAM OR THE APEX SAVE COMMAND (FROG=$400,$9000) AND
; ARE IN THE SAVED PORTION OF THE SYSTEM PAGE.
;
; THIS INTRINSIC IS REQUIRED BECAUSE THE USER'S PROGRAM MAY USE (BOMB)
; APEX'S MEMORY SPACE. THE RESIDENT CODE MUST BE ABLE TO LOAD THE USER'S
; PROGRAM BACK INTO MEMORY [FROM SCRATCH.SYS], THEN WRITE THE ENTIRE
; IMAGE INTO A .SAV FILE.
;
FSAVE	LEA	MEMTOP.L,SP	;SET STACK (FOR SWAP AREA)
	MOVE.B	UNIT,-(SP)	;SAVE THE .SAV FILE'S UNIT AND
	MOVE.L	BLKNO,-(SP)	; STARTING BLOCK NUMBER

	MOVE.B	SYSUNT,UNIT	;LOAD "SCRATCH.SYS" (IN CASE THE .SAV
	MOVE.L	SWPBLK,BLKNO	; FILE BOMBED APEX)
	BSR	SAVPAG		;SAVE APEX'S SYSTEM-PAGE PARAMETERS
	BSR	GET

	MOVE.L	(SP)+,BLKNO	;GET THE .SAV FILE'S PARAMETERS
	MOVE.B	(SP)+,UNIT
	MOVE.L	PROSIZ,DSKSIZ	;SET UP THE SYSTEM PAGE PARAMETERS SO WE
	MOVE.L	USRMEM,DSKMEM	; KNOW HOW BIG IT IS AND WHERE IT STARTS
	BSR	SAVE		;SAVE THE MEMORY IMAGE ON THE GIVEN UNIT
				; AND BLOCK NUMBER
	MOVE.B	#$FF,SYSENF	;INDICATE A "FSAVE" RE-ENTRY CONDITION
	BRA	RENTERX		;GO RE-ENTER APEX

;-----------------------------------------------------------------------
;THIS INTRINSIC WRITES THE CURRENT MEMORY IMAGE TO DISK. RIGHT NOW, IT
; IS ONLY USED TO WRITE THE SYSTEM MEMORY IMAGE INTO "SYSTEM.SYS" (WS).
; THIS IS A CONVENIENCE FOR SYSTEM HACKERS WHICH IS NOT NORMALLY USED.
; FASAVE(UNIT,BLKNO)
;
; IN ADDITION TO THE "UNIT" AND "BLKNO" INPUTS, THE MEMORY ADDRESS
; (USRMEM) AND THE SIZE IN PAGES (PROSIZ) ARE GIVEN. THESE ARE SET UP
; BY APEX.XPL AND ARE IN THE SAVED PORTION OF THE SYSTEM PAGE.
;
;FASAVE	MOVE.L	USRMEM,DSKMEM	;GET THE BASE ADDRESS
;	MOVE.L	PROSIZ,DSKSIZ	;GET THE NUMBER OF BLOCKS
;	BSR	SAVE		;SAVE (WRITE) THE MEMORY IMAGE
;
;	MOVE.B	#$F0,SYSENF	;INDICATE A "FASAVE" RE-ENTRY CONDITION
;	BRA	RENTERX		;GO REENTER APEX
;
;-----------------------------------------------------------------------
;SCAN THE DIRECTORY FOR A FILE NAME
; SCAN(UNIT, BLOCKS, FILENAME)
;
; INPUTS: UNIT - UNIT TO SCAN
;	A6 - CONTAINS THE ADDRESS OF THE FILE NAME
; OUTPUTS: BLKNO - THE STARTING BLOCK NUMBER OF THE FILE (IF FOUND)
;	ENDBLK - THE LAST BLOCK OF THE FILE (IF FOUND)
;
;	ERRLOC - "XXXXXXXX.XXX" NOT FOUND ERROR MESSAGE
;
; REGISTER USAGE:
;	D0 - SCRATCH, BYTE COUNTER
;	D1 - FILE COUNTER
;	A0 - INDEX FOR DIRECTORY NAMES (11-BYTE)
;	A1 - INDEX FOR STATUS ARRAY IN THE DIRECTORY (BYTE)
;	A2 - INDEX FOR FILE BLOCKS IN THE DIRECTORY (WORD)
;	A3 - SCRATCH POINTER TO THE FILE NAME BEING LOOKED UP
;	A4 - SCRATCH POINTER TO THE FILE NAME IN THE DIRECTORY
;	A6 - POINTER TO THE FILE NAME BEING LOOKED UP
;
; NOTE: THE DIRECTORY CONSISTS OF TWO PARTS, EACH OF WHICH MAY HOLD UP
; TO 48 FILES. THE PRIMARY DIRECTORY IS SCANNED FIRST. IF THE FILE NAME
; IS NOT FOUND, THE EXTENDED DIRECTORY IS READ IN AND SCANNED.
;
STATUS	EQU	528		;OFFSET TO STATUS ARRAY IN DIRECTORY
FIRBLK	EQU	576		;OFFSET TO FIRST BLOCK ARRAY
LASBLK	EQU	672		;OFFSET TO LAST BLOCK ARRAY

FSCAN	MOVEM.L	D0/D1/A0-A4,-(SP)	;SAVE REGISTERS

	MOVE.L	#DIRBLK,BLKNO	;GET THE PRIMARY DIRECTORY

FS05	MOVEA.L	A6,A3		;SAVE THE FILE NAME ADDRESS
	MOVE.L	#DIRBUF,FADDR	;READ A DIRECTORY
	MOVE.L	#4,NBLKS
	MOVEA.W	#8,A6		;SET FUNCTION CODE FOR "READ"
	BSR	UNTHAN
	MOVEA.L	A3,A6		;RESTORE A6 WITH THE FILE NAME
	TST.L	ERRLOC		;DID WE GET AN ERROR?
	BNE	FS90		;RETURN IF WE DID

	MOVEA.L	#DIRBUF,A0	;POINT TO FILE NAMES IN THE DIRECTORY
	MOVEA.L	A0,A1		;INITIALIZE THE FILE INDEX FOR BYTES
	MOVEA.L	A0,A2		;INITIALIZE THE FILE INDEX FOR WORDS
	MOVEQ	#MAXFL,D1	;INITIALIZE THE FILE COUNTER (0-47)

FS10	TST.B	STATUS(A1)	;CHECK THE STATUS BYTE FOR FILE
	BLE.S	FS30		;BRANCH IF FILE IS NOT VALID (ACTIVE)

	MOVEA.L	A6,A3		;DOES THIS FILE NAME MATCH OURS (A6)?
	MOVEA.L	A0,A4		;INITIALIZE SCRATCH POINTERS
	MOVEQ	#10,D0		;COMPARE 11 BYTES (0-10)
FS20	CMPM.B	(A3)+,(A4)+
	DBNE	D0,FS20		;EXIT LOOP IF NOT EQUAL OR WHEN D0 = -1
	BEQ.S	FS70		;BRANCH IF THE NAMES MATCH

FS30	ADDA.L	#11,A0		;POINT TO NEXT FILE NAME IN DIRECTORY
	ADDQ.L	#1,A1		;BUMP INDEX TO NEXT STATUS BYTE
	ADDQ.L	#2,A2		;BUMP INDEX TO NEXT WORD
	DBF	D1,FS10		;LOOP FOR ALL FILES

	CMPI.B	#EXTPAT,DIRBUF+1023.L	;IS THERE AN EXTENDED DIRECTORY?
	BNE.S	FS60		;BRANCH IF NOT
	CMPI.L	#XDIRBLK,BLKNO	;BRANCH IF WE HAVE ALREADY SEARCHED THE
	BEQ.S	FS60		; EXTENDED DIRECTORY
	MOVE.L	#XDIRBLK,BLKNO	;GO BACK AND SEARCH THE EXTENDED DIR
	BRA.S	FS05

;COME HERE IF THE FILE WAS NOT FOUND
FS60	MOVEQ	#10,D0		;INSERT FILE NAME INTO THE ERROR MESSAGE
	MOVEA.L	A6,A3		;MOVE 11 BYTES FROM (A6) INTTO FS66+6
	MOVEA.L	#FS66+6,A4	;WARNING: SELF-MODIFYING CODE (NOT
FS63	MOVE.B	(A3)+,(A4)+	; ROMMABLE AND NOT RE-ENTRANT)
	CMPI.W	#3,D0		;INSERT A DOT AFTER THE 8TH CHARACTER
	BNE	FS65		;(NOTE THAT THERE IS NO DOT IN THE FILE
	MOVE.B	#'.',(A4)+	; NAME IN THE DIRECTORY)
FS65	DBF	D0,FS63

	BSR	ERROR		;REPORT THE ERROR
FS66	ASCII	'22 - "XXXXXXXX.XXX" NOT FOUND'
	DC.B	0
	BRA.S	FS90		;EXIT

FS70	CLR.L	D0		;???
	MOVE.W	FIRBLK(A2),D0	;WE FOUND THE FILE NAME		????
	ROL.W	#8,D0		; SO RETURN ITS FIRST AND LAST BLOCKS???
	MOVE.L	D0,BLKNO	;SWAP THE BYTE ORDER TO CONFORM TO 68000
	MOVE.W	LASBLK(A2),D0	; STANDARDS   ????
	ROL.W	#8,D0		;????
	MOVE.L	D0,ENDBLK

FS90	MOVEM.L	(SP)+,D0/D1/A0-A4	;RESTORE REGISTERS
	RTS

;=======================================================================
;SUBROUTINES:
;
;GET THE MEMORY IMAGE (.SAV FILE) WHICH BEGINS AT "BLKNO" ON "UNIT"
;
GET	MOVE.L	#SYSPAG,FADDR	;READ IN THE SYSTEM PAGE
	MOVE.L	#1,NBLKS	; THIS LOADS IN "DSKMEM" AND "DSKSIZ"
	BSR.S	READER		; SO WE CAN...

	ADDQ.L	#1,BLKNO	;POINT TO NEXT BLOCK ON UNIT
	MOVE.L	DSKMEM,FADDR	;READ IN THE MAIN BODY
	MOVE.L	DSKSIZ,NBLKS
	BSR.S	READER
	RTS

;-----------------------------------------------------------------------
;WRITE THE MEMORY IMAGE AT "DSKMEM" AND "DSKSIZ" ONTO "UNIT" BEGINNING
; AT "BLKNO".
;
SAVE	MOVE.L	#SYSPAG,FADDR	;WRITE THE SYSTEM PAGE
	MOVE.L	#1,NBLKS
	BSR.S	WRITER

	ADDQ.L	#1,BLKNO	;POINT TO NEXT BLOCK ON UNIT
	MOVE.L	DSKMEM,FADDR	;WRITE THE MAIN BODY
	MOVE.L	DSKSIZ,NBLKS
	BSR.S	WRITER
	RTS

;-----------------------------------------------------------------------
;SAVE THE SYSTEM PAGE IN "COMPAG"
; THIS IS DONE TO SAVE APEX'S SYSTEM PAGE SO WE DON'T HAVE TO RELOAD IT
; FROM DISK IF THE SYSTEM IS NOT BOMBED BY THE USER PROGRAM. THIS JUST
; MAKES APEX RUN A LITTLE FASTER.
;
SAVPAG	MOVEM.L	D0/A5/A6,-(SP)	;SAVE REGISTERS

	MOVEQ	#63,D0		;SAVE 64 LONG WORDS = 256 BYTES
	LEA	COMPAG-@-2(PC),A5 ;SET UP POINTERS
	LEA	SYSPAG,A6

SPP10	MOVE.L	(A6)+,(A5)+	;MOVE SYSPAG INTO COMPAG
	DBF	D0,SPP10

	MOVEM.L	(SP)+,D0/A5/A6	;RESTORE REGISTERS
	RTS

;-----------------------------------------------------------------------
;READ A FILE FROM DISK AND HANDLE ERRORS IF ANY
; INPUTS: UNIT, BLKNO, FADDR, NBLKS.
;
READER	MOVEM.L	D0/A6,-(SP)	;SAVE REGISTERS

	MOVEA.W	#8,A6		;SET FUNCTION CODE FOR "READ"
	BSR	UNTHAN
	BSR	SHOWERR		;REPORT ANY ERROR

	MOVEM.L	(SP)+,D0/A6	;RESTORE REGISTERS
	RTS

;-----------------------------------------------------------------------
;WRITE A FILE TO DISK AND HANDLE ERRORS IF ANY
;
WRITER	MOVEM.L	D0/A6,-(SP)	;SAVE REGISTERS

	MOVEA.W	#12,A6		;SET FUNCTION CODE FOR "WRITE"
	BSR	UNTHAN
	BSR	SHOWERR		;REPORT ANY ERROR

	MOVEM.L	(SP)+,D0/A6	;RESTORE REGISTERS
	RTS

;=======================================================================
;UNIT AND DEVICE DISPATCHERS
;
;MAIN UNIT HANDLER
; DISPATCH TO A ROUTINE TO HANDLE THE FUNCTION CODE FOR A UNIT.
;    INPUTS:
;	UNIT = THE UNIT NUMBER (0-7)
;	A6 = FUNCTION CODE:
;		0 = OPEN
;		4 = OPEN
;		8 = READ
;		12 = WRITE
;		16 = CLOSE
;		20 = GET INFO
;		24... OTHER SPECIAL CODES ARE ALLOWED (BEWARE OF
;		     SUBSTITUTING UNITS WITHOUT THESE FUNCTIONS)
;	BLKNO =	BLOCK ON THE DISK TO START READ/WRITE
;	FADDR =	ADDRESS IN MEMORY TO WRITE/READ (LONG WORD)
;	NBLKS =	NUMBER OF BLOCKS TO READ/WRITE
;	OFFTBL = PHYSICAL BASE BLOCK ADDED TO GET TO SUB-DIRECTORY
;	MAXTBL = LAST PHYSICAL BLOCK + 1 OF SUB-DIRECTORY
;	UNTTBL = ENTRY POINTS TO UNIT HANDLERS
;
;    OUTPUTS:
;	BLKNOX = SUB-DIRECTORY OFFSET IS ADDED
;	D0 = OUTPUT DATA (IF ANY)
;
UNTHAN	MOVE.W	A6,-(SP)	;SAVE A6, THE FUNCTION CODE

	MOVEA.W	UNIT-1,A6	;GET THE UNIT NUMBER (NO MOVEA.B)
	CMPA.W	#8,A6		;CHECK FOR LEGAL UNIT NO.
	BLO.S	UHAN10		;BRANCH IF IT'S OK
	BSR	ERROR
	ASCII	'6 - ILLEGAL UNIT NUMBER'
	DC.B	0
	BRA	UHAN90		;EXIT

UHAN10	ADDA.W	A6,A6		;BLKNOX := BLKNO + OFFTBL(UNIT)
	ADDA.W	A6,A6		;TIMES 4 FOR LONG ENTRIES
	MOVE.L	OFFTBL(A6),D0
	ADD.L	BLKNO,D0

	CMP.L	MAXTBL(A6),D0	;IF BLKNO >= MAXTBL(UNIT) THEN
	BLO.S	UHAN20		;IF WE'RE DOING A READ (8) OR WRITE (12)
	CMPI.W	#8,(SP)		; THEN FLAG ERROR
	BEQ.S	UHAN17
	CMPI.W	#12,(SP)
	BNE.S	UHAN20
UHAN17	BSR	ERROR
	ASCII	'5 - ACCESS BEYOND END OF UNIT'
	DC.B	0
	BRA.S	UHAN90		;EXIT

UHAN20	MOVE.L	D0,BLKNOX
	MOVEA.L	UNTTBL(A6),A6	;GET THE ADDRESS OF THE UNIT HANDLER

	ADDA.W	(SP),A6		;ADD THE FUNCTION CODE OFFSET
	MOVEA.L	(A6),A6		;GET THE ENTRY ADDRESS FROM THE TABLE
	JSR	(A6)		;CALL THIS HANDLER

UHAN90	MOVEA.W	(SP)+,A6	;RESTORE A6
	RTS

;-----------------------------------------------------------------------
;MAIN DEVICE HANDLER
; DISPATCH TO A ROUTINE TO HANDLE THE FUNCTION CODE FOR AN I/O DEVICE.
;    INPUTS:	DEVICE = THE CURRENT DEVICE NUMBER (0-7)
;		D0 = INPUT DATA (IF ANY)
;		A6 = FUNCTION CODE:
;			0 = OPENI
;			4 = OPENO
;			8 = CHIN
;			12 = CHOUT
;			16 = CLOSE
;			20 = GET INFO
;			24... OTHER SPECIAL CODES ARE ALLOWED (BEWARE OF
;			   SUBSTITUTING DEVICES WITHOUT THESE FUNCTIONS)
;
DEVHAN	MOVE.W	A6,-(SP)	;SAVE A6, THE FUNCTION CODE

	MOVEA.W	DEVICE-1,A6	;GET THE DEVICE NUMBER (NO MOVEA.B)
	CMPA.W	#8,A6		;CHECK FOR LEGAL DEVICE NO.
	BLO.S	DHAN10		;BRANCH IF IT'S OK
	BSR	ERROR
	ASCII	'1 - ILLEGAL DEVICE NUMBER'
	DC.B	0
	BRA	DHAN90		;EXIT

DHAN10	ADDA.W	A6,A6		;GET ADDRESS OF HANDLER FROM "DEVTBL"
	ADDA.W	A6,A6		; (TIMES 4 FOR LONG ENTRIES)
	MOVEA.L	DEVTBL(A6),A6

	ADDA.W	(SP),A6		;ADD THE FUNCTION CODE OFFSET
	MOVEA.L	(A6),A6		;GET THE ENTRY ADDRESS FROM THE TABLE
	JSR	(A6)		;CALL THIS HANDLER

DHAN90	MOVEA.W	(SP)+,A6	;RESTORE A6
	RTS

;-----------------------------------------------------------------------
;NULL DEVICE HANDLER
;
NULLHAN	DC.L	NULL90		;0 = OPENI
	DC.L	NULL90		;1 = OPENO
	DC.L	NULL10		;2 = CHIN
	DC.L	NULL90		;3 = CHOUT
	DC.L	NULL90		;4 = CLOSE
	DC.L	GETINFO		;5 = GET INFO
	DC.L	NULL90		;6 = SPARE
	DC.L	NULL90		;7 = SPARE

NULL10	MOVEQ	#EOF,D0		;RETURN "EOF"
NULL90	RTS

GETINFO	MOVE.L	#INFO,D0
	RTS

INFO	DC.L	START		;STARTING ADDRESS OF RESCOD
	DC.L	END		;ENDING ADDRESS OF RESCOD
	DC.L	NULLSTR		;DESCRIPTION
NULLSTR	ASCII	'RESCOD    FEB-25-89  Null device handler'
	DC.B	0
NULLEND	EQU	@

;-----------------------------------------------------------------------
;"HANDLER" FOR AN UNINSTALLED HANDLER (EITHER A DEVICE OR A UNIT)
;
BADHAN	DC.L	BADHAN1		;0 = OPENI
	DC.L	BADHAN1		;1 = OPENO
	DC.L	BADHAN1		;2 = CHIN
	DC.L	BADHAN1		;3 = CHOUT
	DC.L	BADHAN1		;4 = CLOSE
	DC.L	BADHAN2		;5 = GET INFO
	DC.L	BADHAN1		;6 = SPARE
	DC.L	BADHAN1		;7 = SPARE

BADHAN1	BSR.S	ERROR
	ASCII	'2 - UNINSTALLED HANDLER'
	DC.B	0
	RTS

BADHAN2	MOVE.L	#BADINFO,D0	;RETURN ADDRESS OF INFO ARRAY
	RTS

BADINFO	DC.L	0		;STARTING ADDRESS
	DC.L	0		;ENDING ADDRESS
	DC.L	BADSTR		;DESCRIPTION
BADSTR	ASCII	'(Uninstalled)'
	DC.B	0

;=======================================================================
;ERROR HANDLER
; RECORD THE ADDRESS OF THE ERROR MESSAGE UNLESS AN ERROR IS ALREADY
; RECORDED.
;
ERROR	MOVEM.L	D0/A0,-(SP)	;SAVE REGISTERS

	MOVEA.L	8(SP),A0	;GET THE "RETURN ADDRESS" WHICH POINTS
	MOVE.L	A0,D0		; TO ERROR MESSAGE STRING, & SAVE A COPY
ERR10	TST.B	(A0)+		;SCAN FOR THE END OF THE STRING
	BNE.S	ERR10		;LOOP UNITL THE TERMINATOR IS FOUND

	ADDQ.L	#1,A0		;SET THE REAL RETURN ADDRESS
	MOVE.L	A0,8(SP)	;MAKE SURE IT IS ON THE WORD BOUNDARY
	ANDI.B	#$FE,11(SP)	; FOLLOWING THE STRING

	TST.L	ERRLOC		;DO WE ALREADY HAVE AN ERROR RECORDED?
	BNE.S	ERR80		;BRANCH IF WE DO
	MOVE.L	D0,ERRLOC	;RECORD THE ADDRESS OF THE ERROR MESSAGE
	MOVE.B	UNIT,ERRUNT	;RECORD THE CURRENT UNIT NUMBER
	MOVE.B	DEVICE,ERRDEV	;RECORD THE CURRENT DEVICE NUMBER

ERR80	TST.B	ERRTRAP		;ARE WE TRAPPING ERRORS?
	BEQ.S	ERR90		;BRANCH IF NOT
	BSR.S	SHOWERR		;DISPLAY ERROR MESSAGE
	BRA	RELOAD		;RESTART APEX

ERR90	MOVEM.L	(SP)+,D0/A0	;RESTORE REGISTERS
	RTS

;-----------------------------------------------------------------------
;SHOW ERROR MESSAGE (IF ANY) ON THE CONSOLE.
; E.G:	ERROR 10 - OUTPUT FILE NOT OPEN
;	UNIT: 2   DEVICE: 3   ADDRESS: $0456
;	FIX IT, THEN PRESS "RETURN"
; INPUTS: ERRLOC, ERRUNT, ERRDEV
; OUTPUTS:
;	ERRLOC IS RESET TO ZERO
;
;ALSO HANDLE ERRORS ON SYSTEM UNIT (MUST WAIT FOR RETURN KEY)
;
SHOWERR	TST.L	ERRLOC		;DO WE HAVE AN ERROR RECORDED?
	BEQ	SER99		;EXIT IF NOT
	MOVEM.L	D0/A6,-(SP)	;SAVE REGISTERS

	CLR.B	DEVICE		;INITIALIZE THE CONSOLE OUTPUT
	MOVEA.W	#4,A6		;OPENO(0)
	BSR	DEVHAN		;(WE MIGHT HAVE HAD A GRAPHIC SCREEN)

	LEA	SERM10-@-2(PC),A6 ;"ERROR "
	BSR	TEXT
	MOVEA.L	ERRLOC,A6	;DISPLAY ERROR STRING
	BSR	TEXT
	MOVEQ	#CR,D0
	MOVEA.W	#12,A6		;SET "OUTPUT" FUNCTION CODE
	BSR	DEVHAN

	LEA	SERM30-@-2(PC),A6 ;UNIT:
	BSR	TEXT
	MOVE.B	ERRUNT,D0
	BSR	NYBOUT
	LEA	SERM40-@-2(PC),A6 ;DEVICE:
	BSR	TEXT
	MOVE.B	ERRDEV,D0
	BSR	NYBOUT
	LEA	SERM50-@-2(PC),A6 ;ADDRESS:
	BSR	TEXT
	MOVE.L	ERRLOC,D0
	BSR	HEXOUT
	MOVEQ	#CR,D0
	MOVEA.W	#12,A6		;SET "OUTPUT" FUNCTION CODE
	BSR	DEVHAN

	MOVE.B	ERRUNT,D0	;IS THE ERROR ON THE SYSTEM UNIT?
	CMP.B	SYSUNT,D0
	BNE.S	SER80		;BRANCH IF NOT
;*** This should also check to see if the error was actually caused by
; a disk drive ***
	LEA	SERM60-@-2(PC),A6 ;FIX IT, THEN PRESS "RETURN"
	BSR	TEXT
	MOVEA.W	#0,A6		;OPENI(0)
	BSR	DEVHAN
	MOVEA.W	#8,A6		;CHIN(0), I.E. WAIT FOR RETURN KEY
	BSR	DEVHAN
	BRA	RELOAD		;RELOAD APEX & START FROM THE BEGINNING

SER80	CLR.L	ERRLOC		;CLEAR REPORTED ERROR

	MOVEM.L	(SP)+,D0/A6	;RESTORE REGISTERS
SER99	RTS

SERM10	DC.B	CR
	DC.B	BEL
	ASCII	'ERROR '
	DC.B	0
SERM30	ASCII	'UNIT: '
	DC.B	0
SERM40	ASCII	'   DEVICE: '
	DC.B	0
SERM50	ASCII	'   ADDRESS: $'
	DC.B	0
SERM60	ASCII	'FIX IT, THEN PRESS "RETURN"'
	DC.B	0

;======================================================================
;SUBROUTINES
; ALTHOUGH THESE SUBROUTINES ARE IN INT32.68K, THEY ARE REPRODUCED HERE
; TO MAKE RESCOD.68K INDEPENDENT.
;
;-----------------------------------------------------------------------
;OUTPUT THE TEXT STRING POINTED TO BY A6 TO "DEVICE"
;
TEXT	MOVEM.L	D0/A0/A6,-(SP)	;SAVE REGISTERS

	MOVEA.L	A6,A0		;GET SET UP STRING POINTER IN A0
	MOVEA.W	#12,A6		;SET FUNCTION CODE FOR "CHOUT"
	BRA.S	TXT20		;ENTER THE LOOP

TXT10	BSR	DEVHAN		;OUTPUT CHARACTER TO "DEVICE"
TXT20	MOVE.B	(A0)+,D0	;GET CHARACTER AT POINTER
	BNE.S	TXT10		;LOOP UNTIL TERMINATOR (0)

	MOVEM.L	(SP)+,D0/A0/A6	;RESTORE REGISTERS
	RTS

;-----------------------------------------------------------------------
;OUTPUT D0 IN ASCII HEX (8 DIGITS) TO "DEVICE"
;
HEXOUT	SWAP	D0		;GET HIGH WORD
	BSR.S	WRDOUT		;OUTPUT IT
	SWAP	D0		;(PFALL) RESTORE D0 & OUTPUT LOW WORD

;-----------------------------------------------------------------------
;OUTPUT D0 IN ASCII HEX (4 DIGITS) TO "DEVICE"
;
WRDOUT	MOVE.W	D0,-(SP)	;SAVE LOW BYTE
	ASR.W	#8,D0		;MOVE HIGH BYTE DOWN
	BSR.S	BYTOUT		;OUTPUT IT
	MOVE.W	(SP)+,D0	;(PFALL) GET LOW BYTE AND OUTPUT IT

;-----------------------------------------------------------------------
;OUTPUT D0 IN ASCII HEX (2 DIGITS) TO "DEVICE"
;
BYTOUT	MOVE.W	D0,-(SP)	;SAVE LOW NYBBLE
	ASR.W	#4,D0		;MOVE HIGH NYBBLE DOWN
	BSR.S	NYBOUT		;OUTPUT IT
	MOVE.W	(SP)+,D0	;(PFALL) GET LOW NYBBLE AND OUTPUT IT

;-----------------------------------------------------------------------
;OUTPUT D0 IN ASCII HEX (1 DIGIT) TO "DEVICE"
;
NYBOUT	MOVEM.L	D0/A6,-(SP)	;SAVE REGISTERS
	ANDI.W	#$F,D0		;WORK WITH LOW NYBBLE ONLY
	CMPI.W	#10,D0
	BLO.S	NO10
	ADDQ.W	#7,D0
NO10	ADDI.W	#'0',D0		;CONVERT TO ASCII
	MOVEA.W	#12,A6		;SET THE FUNCTION CODE TO "CHOUT"
	BSR	DEVHAN		;OUTPUT D0
	MOVEM.L	(SP)+,D0/A6	;RESTORE REGISTERS
	RTS

END	EQU	@-1		;MARK END OF MODULE

	IF	@ > MEMTOP-$2900
	ERROR -- FILE IS TOO LONG
	ENDIF

;-----------------------------------------------------------------------
;
;HOOK HANDLERS INTO UNIT AND DEVICE HANDLER TABLES
	ORG	UNTTBL
	DC.L	BADHAN		;0
	DC.L	BADHAN		;1
	DC.L	BADHAN		;2
	DC.L	BADHAN		;3
	DC.L	BADHAN		;4
	DC.L	BADHAN		;5
	DC.L	BADHAN		;6
	DC.L	BADHAN		;7

	ORG	DEVTBL
	DC.L	BADHAN		;0
	DC.L	BADHAN		;1
	DC.L	BADHAN		;2
	DC.L	BADHAN		;3
	DC.L	BADHAN		;4
	DC.L	BADHAN		;5
	DC.L	BADHAN		;6
	DC.L	NULLHAN		;7

;-----------------------------------------------------------------------
;INITIALIZE SYSTEM PAGE PARAMETERS

	ORG	VSTART
	JMP	OPENUNT2.L	;APEX START ENTRY POINT
	JMP	RELOAD.L	;APEX RESTART ENTRY POINT
	JMP	VRENTR.L	;PROGRAM NORMAL EXIT ADDRESS (CTRL-C)
	JMP	VRENTR.L	;PROGRAM ERROR EXIT ADDRESS
	JMP	VSAVER.L	;PROGRAM ABORT EXIT ADDRESS (CTRL-P)

	ORG	SYSUNT
	DC.B	0

	ORG	VALUNT
	DC.B	0

	ORG	LOKMSK
	DC.B	0

	ORG	DEVICE-1
	DC.W	0

	ORG	UNIT-1
	DC.W	0

;SET UP LINK VECTORS
	ORG	VBUG
	JMP	BADHAN1.L	;(Must install Debugger to set this)
	JMP	RELOAD.L
	JMP	RENTER.L
	JMP	SAVER.L
	JMP	FRUN.L
	JMP	FGET.L
	JMP	FSAVE.L
	JMP	BADHAN1.L	;FASAVE.L (OBSOLETE)
	JMP	FSCAN.L
	JMP	UNTHAN.L
	JMP	DEVHAN.L
	JMP	SHOWERR.L
	JMP	ERROR.L

	END
SAVE.L
	JMP	B