/4 RTS-8  SMALL REAL TIME SYSTEM V2B
	XLIST	1	/COPYRIGHT ALSO IS IN PARAM.PA
/
/
/
/
/
/
/
/
/
/COPYRIGHT  (C)  1974,1975,1976 BY DIGITAL EQUIPMENT CORPORATION
/
/
/
/
/
/
/
/
/
/
/THE INFORMATION IN THIS DOCUMENT IS SUBJECT TO CHANGE WITHOUT NOTICE
/AND SHOULD NOT BE CONSTRUED AS A COMMITMENT BY DIGITAL EQUIPMENT
/CORPORATION.  DIGITAL EQUIPMENT CORPORATION ASSUMES NO RESPONSIBILITY
/FOR ANY ERRORS THAT MAY APPEAR IN THIS DOCUMENT.
/
/THE SOFTWARE DESCRIBED IN THIS DOCUMENT IS FURNISHED TO THE PURCHASER
/UNDER A LICENSE FOR USE ON A SINGLE COMPUTER SYSTEM AND CAN BE COPIED
/(WITH INCLUSION OF DIGITAL'S COPYRIGHT NOTICE) ONLY FOR USE IN SUCH
/SYSTEM, EXCEPT AS MAY OTHERWISE BE PROVIDED IN WRITING BY DIGITAL.
/
/DIGITAL EQUIPMENT CORPORATION ASSUMES NO RESPONSIBILITY FOR THE USE
/OR RELIABILITY OF ITS SOFTWARE ON EQUIPMENT THAT IS NOT SUPPLIED BY
/DIGITAL.
/
/
/
/
/
/
/
/
/
/
	XLIST	0	/LIST EXEC
/EDIT HISTORY:
/RICHARD LARY		LAST EDITED AUG 18, 1974
/SHAWN SPILLMAN EDITED THIS ON 14-SEP-74.
/STANLEY RABINOWITZ EDITED THIS ON 5-APR-75
/	ADDED PDP-12 SUPPORT
/	FIXED ANGLE BRACKET BUG OF SHWANS
/RICHARD LARY EDITED THIS ON 20-NOV-75
/	ADDED KL8A SUPPORT AND RESCHED FUNCTION
/RICHARD LARY EDITED THIS ON 28-DEC-75
/	ADDED FREE-PARTITION OPTION TO WAITM, FIXING BUG
/	FIXED NON-RESIDENT TASK BUG IN FREEJ AND STOPJ
/STANLEY RABINOWITZ EDITED THIS DURING SEP, OCT 1976 (V2B)
/	REMOVED KL8A SUPPORT (NOW IN KL8ASR.PA)
/	ADDED HELPER STUFF FOR KL8A INTERRUPT SKIP CHAIN
/	ADDED WAITX ER
/	ALLOWED RECEIVE TO FALL THROUGH IF NO MSG AND AC NEGATIVE
/	ZERO CERTAIN DECNET TABLES
/	FIXED RACE CONDITION IN SCHEDULER

/BASED ON      T-O-Y    JUNE 5, 1973

/IOT'S FOR OPTIONAL HARDWARE:

	*200

	IFNDEF PDP12	<PDP12=0>	/IF NOT SURE, YOU'RE NOT A PDP-12
	IFZERO PDP8E <
		IFZERO PDP12	<CAFHLT=HLT>	/HALT TO LET USER CLEAR FLAGS
		IFNZRO PDP12	<CAFHLT=JMS IOPRST>  /ISSUE I/O PRESET ON PDP-12
	>
	IFNZRO	PDP8E	<CAFHLT=CAF>	/MACHINE WILL CLEAR FLAGS

SINT=	6254		/SKIP ON USER INTERRUPT
SUF=	6274		/SET USER MODE FLAG
SPL=	6102		/SKIP ON POWER LOW
LINC=	6141		/ENTER LINC MODE
PDP=	2		/ENTER PDP-8/I MODE
ESF=	4		/ENABLE SPECIAL FUNCTIONS
/PAGE 0 OF FIELD 0

	*0		/INTERRUPT "VECTOR"
	0		/SET TO  JMP I 3  ON POWER FAILURE
	JMP I	.+1
	INTRPT
	IFNZRO	PWRFAL	<
PFLADR,	PFLRTN		/CHANGED BY POWER FAIL TASK
	>

	*17
XR,	0		/INDEX REGISTER USED BY EXEC
LOC20,	0		/MONITOR CALL LOCATION ** MUST BE AT 20 **
DCDF,	CDF 0
CALIOF,	IOF
	JMP I	CALEXC
	DSPOST		/** MUST BE AT LOC 24 **
	XWAITM		/** MUST BE AT LOC 25 **
CALEXC,	EXEC		/** MUST BE 400 **
ACARG,	0		/HOLDS AC ARG ON EXEC CALLS
MPTR,	ION		/POINTS TO FIRST WORD OF MESSAGE Q POINTER
MPT2,	JMP I	ACARG	/"      "  SECOND "   "
TASKX,	0		/CURRENT TASK NUMBER
INTT,	0		/INTERRUPT-LEVEL TEMPORARY

SVSFLG,	-1		/SAVE STATE FLAG -
			/-1 MEANS CPU STATE COUNTS & SHOULD BE SAVED,
			/0 MEANS CPU STATE IS UNIMPORTANT.
TSWFLG,	1		/TASK SWITCHING INHIBITED FLAG -
			/ 1 = TASK SWITCHING ALLOWED
			/ 0 = TASK SWITCHING INHIBITED
			/-1 = TASK SWITCHING INHIBITED, RESCAN ASAP

TODL,	0		/TIME-OF-DAY LOW ORDER
TODH,	0		/TIME-OF-DAY HIGH ORDER
DATE,	TSTCLK		/DATE WORD - USED TO INIT CLOCK HANDLER
MCREF,	0		/MCR STARTUP EVENT FLAG
T,	0		/NON-INTERRUPT LEVEL TEMPORARY
	IFDEF	SWAPPER	<
COMMAND, ACARG		/SWAPPER OVERWRITES WITH INITIAL ENTRY
			/HOLDS FREE-PARTITION FLAG IN SIGN BIT
SWPENT,	WIPCAL		/SWAPPER OVERWRITES WITH FREEPAR ENTRY
	>
	*45
	IFNZRO KL8A <
KL8LOC,	MSABAD		/POINTS TO FIRST FREE LOC FOR KL8A IN SKIP CHAIN
	>
	ZBLOCK	50-.	/RESERVED FOR FUTURE EXPANSION
/SET UP EXEC LINKAGE IN FIELDS 1-7

	IFZERO	HGHFLD-10&4000	<
	FIELD 1
	*21
	CDF 10
	CIF 0
	JMP	CALIOF
	DSPOST
	XWAITM
	>
	IFZERO	HGHFLD-20&4000	<
	FIELD 2
	*21
	CDF 20
	CIF 0
	JMP	CALIOF
	DSPOST
	XWAITM
	>
	IFZERO	HGHFLD-30&4000	<
	FIELD 3
	*21
	CDF 30
	CIF 0
	JMP	CALIOF
	DSPOST
	XWAITM
	>
	IFZERO	HGHFLD-40&4000	<
	FIELD 4
	*21
	CDF 40
	CIF 0
	JMP	CALIOF
	DSPOST
	XWAITM
	>
	IFZERO	HGHFLD-50&4000	<
	FIELD 5
	*21
	CDF 50
	CIF 0
	JMP	CALIOF
	DSPOST
	XWAITM
	>
	IFZERO	HGHFLD-60&4000	<
	FIELD 6
	*21
	CDF 60
	CIF 0
	JMP	CALIOF
	DSPOST
	XWAITM
	>
	IFZERO	HGHFLD-70&4000	<
	FIELD 7
	*21
	CDF 70
	CIF 0
	JMP	CALIOF
	DSPOST
	XWAITM
	>

	FIELD 0
/INTERRUPT ROUTINE

	*200

TS8LOC,	CAFHLT		/SO WE CAN START AT 200
	IFNZRO TS8LOC-200 <SYSERR,_ERROR_>	/OS8SUP NEEDS THIS HERE
	IFDEF	SWAPPER	<
NEWTSK,	JMS I	COMMAND	/DO SWAPPER INITIALIZATION
	>		/(SEE SWAP TASK FOR DETAILS)
	IFNDEF	SWAPPER	<
NEWTSK,	ION
	>
INTFGS,	JMP I	.+1	/GO AND FIND THE FIRST
INTAC,	FINDJ		/TASK TO RUN

INTRPT,
	IFDEF	OS8	<
	SINT		/MUST BE FIRST SKIP IN INTERRUPT CHAIN!
	SKP
	JMP I	TS8LOC
	>
	DCA	INTAC	/SAVE AC
	IFNZRO	PDP8E	<GTF>
	IFZERO	PDP8E	<
	RAR		/COMBINE LINK, IF AND DF INTO ONE WORD
	RIB
	>
	DCA	INTFGS
USERSK,			/VERY HIGH PRIORITY USER FLAG TESTS GO HERE
	IFNZRO	KL8A	<MSABAD, NOP >	/KL8A INTERRUPT DISPATCHER
	IFZERO	KL8A-2	<NOP>	/NOP IS FASTER THAN '0'
	IFZERO	KL8A-3	<NOP;NOP>
	IFNZRO	PWRFAL	<SPL>	/SKIP ON POWER LOW
	JMP	TSTCLK	/NO MORE H.P. SKIPS - GO TO SKIP CHAIN
	IFNZRO	PWRFAL	<
	TAD	0
	DCA	INTT	/SAVE LOCATION ZERO
	TAD	(JMP I PFLADR
	DCA	0	/SET UP 0 FOR RESTART
	HLT		/DON'T TRY ANYTHING FANCY

PWFLEF,	0		/POWER FAILURE EVENT FLAG
PFLRTN,	TAD	INTT	/** MUST BE AT PWFLEF+1 **
	DCA	0	/RESTORE LOCATION OF POWER LOW INTERRUPT
	TAD	(PWFLEF	/POST THE POWER-FAIL INTERRUPT
	POSTDS		/TO EXECUTE THE POWER-FAIL TASK (IF ANY)
	>
BSKCHN,	DISMIS		/BEGINNING OF SKIP CHAIN LIST
TSTCLK,	CDF CIF 0	/ADDRESS FOLLOWED BY CDF CIF FIELD
	NOP		/SET TO CLSK BY CLOCK ROUTINE
	JMP I	BSKCHN
DCDIF0,	CDF CIF 0	/CLOCK HANDLER ALWAYS IN FLD 0
	JMP I	.+1
	DISMIS		/CHANGED BY CLOCK HANDLER (IF ANY)
/SUBROUTINE TO POST AN EVENT FLAG AND DISMISS FROM INTERRUPTS
/ENTER WITH IOF, DF=D.F. OF EVENT FLAG, AC=ADDRESS OF EVENT FLAG

DSPOST,	SNA
	JMP	DISMIS	/NO EVENT FLAG - JUST DISMISS
	DCA	INTT
	AC4000
	TAD I	INTT	/LINK=1 IF EVENT FLAG.LT.0, 0 IF.GT.0
	DCA	NEWTSK	/SAVE OLD VALUE OF EVENT FLAG
	DCA I	INTT	/ZERO EVENT FLAG TO INDICATE EVENT COMPLETION
	TAD	NEWTSK
	SPA		/** LINK MUST BE 0 HERE IF AC IS NEGATIVE **
	JMP	.+3	/IF E.F. .LT. 0, TASK WAS WAITING FOR EVENT
	JMS I	(FREEJ	/SO CLEAR "EVENT WAIT" BIT IN FLAG WORD.
	EFWT!EORMWT	/IF THE TASK WHICH WAS WAITING ON THIS
	SNL CLA		/EVENT FLAG IS HIGHER PRIORITY THAN THE TASK
	JMP	DISMIS	/CURRENTLY RUNNING, SUSPEND THE CURRENT TASK
	TAD	0	/UNLESS WE ARE IN A NON-INTERRUPTABLE ZONE
	IFDEF OS8 <RIB>	/(NAMELY LOCS 0-77 OF A FIELD
	AND	(7700	/NOT USED BY OS/8 BACKGROUND)
	SZA CLA		/OR TASK SWITCHING HAS BEEN SPECIFICALLY
	TAD	TSWFLG	/INHIBITED BY THE SOFTWARE
	SMA SZA CLA	/(BY MAKING TSWFLG LE 0)
	JMP	STOPJ
	STA		/IF TASK SWITCHING IS INHIBITED,
	DCA	TSWFLG	/SET FLAG TO INSURE A RESCAN OF THE TASK LIST
	JMP	DISMIS	/WHEN WE UNINHIBIT IT, THEN DISMISS NORMALLY.

STOPJ,	ISZ	SVSFLG	/IS THE STATE OF THE CURRENT TASK WORTH SAVING?
	JMP	NOSVST	/NO - FORGET IT.
	TAD	TASKX
	CLL RTL
	TAD	(TSTABL-1
	DCA	XR	/SAVE THE CURRENT TASK'S STATE
	TAD	INTFGS
	DCA I	XR
	TAD	0
	DCA I	XR
	TAD	INTAC
	DCA I	XR
	IFNZRO	EAE	<
	MQA
	DCA I	XR	/SAVE THE MQ
	>
NOSVST,	TAD	NEWTSK	/SET THE CURRENT PRIORITY TO THAT OF THE
	DCA	TASKX	/HIGHER PRIORITY TASK AND ATTEMPT TO START IT.
	ION		/ENABLE INTERRUPTS WITH THE "DON'T SAVE STATE"
			/FLAG ON TO ALLOW FURTHER RESCHEDULING

	IFDEF	SWAPPER	<
/	TAD	NEWTSK	/FORM A POINTER TO THE TASK FLAGS WORD
/	TAD	(TFTABL	/OF THE NEW TASK
/	DCA	INTT	/AND STORE IT IN INTT
			/(ACTUALLY "FREEJ" DID IT FOR US)

/**NOTE** IF YOU ENABLE THE PRECEDING 3 LINES, DON'T USE INTT!
	TAD I	INTT	/GET TASK FLAGS WORD
			/(INTERRUPTS COME ON  N O W !)
	SZA CLA		/IF ITS 0 (RUNNABLE) THEN RUN IT
	JMP I	(FINDJ	/IF ITS 4000 THEN GO SCHEDULE SWAPPER
	>

/THIS MEANS THAT IF ANYBODY WITH HIGHER PRIORITY THAN "NEWTSK"
/GETS AN EVENT-FLAG-SETTING INTERRUPT NOW, WE'LL JUST DASH OFF
/AND START HIM INSTEAD.

/CODE TO START UP A TASK
/ENTER WITH TASK# IN "TASK", DF=0, ION, NO STATE (SVSFLG=0)

STARTJ,	IFZERO	HGHFLD	<ION>	/INTERRUPTS ALREADY ON IF CIF WORKS
	TAD	TASKX
	CLL RTL
	TAD	(TSTABL-1	/FORM POINTER INTO TASK STATE TABLE
	DCA	XR
	STA
	IOF		/OK, THINGS ARE GETTING SENSITIVE - TURN INTS OFF
	DCA	SVSFLG	/AND RESET SAVE-STATE FLAG TO "YES"
	TAD I	XR
	DCA	INTFGS
	TAD I	XR
	DCA	0	/SIMULATE AN INTERRUPT FROM THE TASK
	TAD I	XR
	DCA	INTAC	/AND DISMISS IT
	IFNZRO	EAE	<
	TAD I	XR
	MQL		/RESTORE MQ
	>		/*** CAUSES ERRORS IF MACHINE HAS NO EAE

/** NOW FALL INTO "DISMIS" ON NEXT PAGE **
/INTERRUPT DISMISS ROUTINE - ALSO USED TO START TASKS

DISMIS,	IFNZRO	PDP8E	<
	SRQ		/ANY OTHER INTERRUPTS PENDING?
	SKP		/NO
	JMP	USERSK	/YES - SKIP PREAMBLE STUFF FOR EXTRA SPEED
	>
	TAD	INTFGS
	IFNZRO	PDP8E	<
	IFNZRO	HGHFLD	<RTF>
	IFZERO	HGHFLD	<RAL>	/RTF DOESN'T WORK RIGHT ON 4K 8E'S
	CLA
	>
	IFZERO	PDP8E	<
	IFDEF	OS8	<
	TAD	(700	/PROPAGATE USER-MODE BIT FROM BIT 5 TO BIT 2
	>
	CLL RTL
	RAL		/USER-MODE BIT NOW IN LINK
	AND	(70	/FAKE AN RTF IF NOT ON A PDP8E
	TAD	DCDF
	DCA	DISCDF
	IFDEF	OS8	<
	SZL		/IF USER MODE WAS ON WHEN WE INTERRUPTED,
	SUF		/TURN IT ON WHEN WE DISMISS
	>
	AC4000
	TAD	INTFGS
	AND	(70	/NOTE THAT THE LINK IS NOW RESTORED
	TAD	DCDIF0
	DCA	DISCIF
DISCIF,	0
DISCDF,	0
	>
	TAD	INTAC
	IFZERO	-PDP8E&HGHFLD	<ION>	/FOR PRE 8E OR 4K 8E MACHINES
	JMP I	0

	IFNZRO PDP12 <
IOPRST,	0
	TAD (20		/   I/O PRESET BIT IN SPECIAL FUNCTIONS REGISTER
	LINC		/ENTER LINC MODE
	ESF		/ENABLE SPECIAL FUNCTION
	PDP		/BACK TO 8-MODE
	CLA
	JMP I IOPRST
	>
	PAGE
/RTS-8 EXECUTIVE - PROCESSES USER REQUESTS

/CALLED BY:	JMS 20	/IN ANY FIELD
/		ARGS
/
/CODE AT LOC 20 TURNS IOF, DOES CDF CUR AND CIF 0 AND JUMPS HERE

EXEC,	DCA	ACARG	/SAVE POSSIBLE AC ARGUMENT
	TAD	TSWFLG	/TSWFLG=1 HERE UNLESS WE WERE INTERRUPTED
	SMA CLA		/WHEN WE WERE IN THE PAGE 0 CODE, IN WHICH CASE
	DCA	TSWFLG	/ITS -1  -  ZERO IT IF IT WAS 1
	ION		/IT IS NOW OK TO TURN INTERRUPTS BACK ON
	RDF
	TAD	ECDIF0
	DCA	EXRET	/SAVE RETURN FIELD
	TAD I	(LOC20	/GET LOC 20 OF THE CALLING FIELD
	DCA	LOC20	/SAVE IT IN FIELD 0
	IFDEF	SWAPPER	<
	TAD I	LOC20	/SAVE A COPY OF THE COMMAND FOR LATER
	DCA	COMMAND	/IN CASE HE WANTS TO "FREE"
	>
	AC3777
	AND I	LOC20	/GET COMMAND MINUS WAIT BIT
	ISZ	LOC20
	TAD	CMDJMP
	DCA	.+1	/TURN COMMAND INTO DISPATCH JUMP
	HLT

CMDJMP,	JMP I	.+1
	XSEND		/SEND MESSAGE TO A TASK
	XRECEIV		/GET A MESSAGE FROM THE MESSAGE QUEUE
	XWAITE		/WAIT FOR AN EVENT FLAG TO BE POSTED
	XRUN		/RUN A TASK (IF NOT BEING RUN)
	XSUSPND		/SUSPEND EXECUTION OF A TASK
	XPOST		/POST AN EVENT FLAG
	XSKPINS		/INSERT SKIP INTO INTERRUPT CHAIN
	XDERAL		/DERAIL A TASK
	XBLKARG		/BLOCK TASK FOR REASON SPECIFIED BY ARG
	XSENDW		/SEND MESSAGE AND WAIT FOR COMPLETION
	XUNBARG		/UNBLOCK TASK FOR REASON SPECIFIED BY ARG
	XTSTOP		/FORCE A RESCHEDULE
	XWAITX		/WAIT FOR EXACTLY THIS EVENT FLAG
/ROUTINE TO DERAIL A TASK'S EXECUTION INTO A SUBROUTINE

XDERAL,	TAD I	LOC20
	ISZ	LOC20
	DCA	T	/SAVE ADDR OF DERAIL SUBR
	TAD	ACARG
	CLL RTL
	TAD	(TSTABL	/GET POINTER INTO TASK STATE TABLE
	DCA	MPTR
	CDF 0
	TAD I	MPTR
	AND	(70	/GET INSTRUCTION FIELD
	TAD	DCDF
	DCA	DRLCDF
	ISZ	MPTR
	TAD I	MPTR	/GET CURRENT TASK PC
DRLCDF,	HLT		/CDF TO TASK FIELD
	DCA I	T	/STORE PC IN SUBR HEADER
	CDF 0
	TAD	T
	IAC
	DCA I	MPTR	/SET PC TO SUBR HEADER + 1
	JMP	EXRET	/RETURN TO CALLING TASK


/SUBROUTINE TO WAIT FOR MULTIPLE EVENTS
/CALLED VIA JMS I 25 WITH INTERRUPTS OFF.
/THIS ROUTINE SHOULD BE CALLED AFTER SCANNING THE MULTIPLE EVENT FLAGS
/(WITH INTERRUPTS OFF) TO AVOID TURNING INTERRUPTS ON BEFORE THE
/WAIT MASK IS PLACED IN TFTABL.  THE "BLKARG" CALL TO THE RTS EXEC
/WOULD TURN INTERRUPTS ON (IN THE EXEC), THUS INVITING
/RACE CONDITIONS.

XWAITM,	0
	IFDEF	SWAPPER	<	/THE "FREE PARTITION" FLAG
	DCA	COMMAND		/IS IN THE SIGN BIT OF THE AC
	>
	CLA CLL		/CLEAR AC (IN CASE SWAPPER NOT PRESENT)
			/AND LINK (SO TSWAIT WILL ZERO THE TASK AC)
	TAD	XWAITM
	DCA	LOC20	/FAKE A CALL TO EXEC (IN CASE WE MUST WAIT)
	RDF
	TAD	ECDIF0
	DCA	EXRET
	DCA	TSWFLG	/THIS IS STILL PART OF THE FAKE CALL
	TAD I	LOC20	/GET THE WAIT MASK
	ISZ	LOC20
	JMP I	(TSWAIT	/GO WAIT ON MASK
/INSERT A DEVICE SKIP INTO THE INTERRUPT CHAIN

XSKPINS,TAD I	LOC20	/GET THE ADDRESS OF THE SKIP - 2
	ISZ	LOC20
	DCA	T
	TAD I	T
	SZA CLA		/IF ARGUMENT LOC IS NON-ZERO,
	JMP	EXRET	/IT IS ALREADY IN THE SKIP CHAIN - IGNORE
	TAD	(DISMIS	/CHAIN IT TO THE END OF THE CHAIN
	DCA I	T
	ISZ	T
	TAD	ECDIF0
	DCA I	T
	IFNZRO	HGHFLD	<
	TAD	EXRET	/GET CDF TO NEW "LAST SKIP"
INTCDF,	CDF CIF 0	/CDF TO FLD OF OLD "LAST SKIP" AND INH INTS
			/**NOTE:  THE IF IS NOW GARBAGE
			/DO NOT JUMP ANYWHERE!
	DCA	INTCDF	/UPDATE "LAST SKIP" FIELD TO NEW ONE
	>
	TAD	T
	DCA I	INTEND	/CHAIN OLD SKIP TO NEW ONE
	ISZ	INTEND
	IFNZRO	HGHFLD	<
	TAD	INTCDF
	>
	DCA I	INTEND
	STA
	TAD	T
	DCA	INTEND	/UPDATE POINTER TO END OF SKIP CHAIN
			/FALLING INTO EXRET FIXES INSTRUCTION FIELD
EXRET,	HLT		/CDF CIF RETURN FIELD (ALSO INHIBIT INTERRUPTS)
	IFZERO	HGHFLD	<IOF>	/INTERRUPTS OFF FOR ISZ!
	ISZ	TSWFLG	/ALLOW TASK SWITCHING (SKIPS IF RESCAN NECESSARY)
	IFZERO	HGHFLD	<
	JMP	.+3	/NO RESCAN NECESSARY
	ION		/TASK SWITCHING STILL INHIBITED, TURN ION AND
	JMP	ECDIF0	/STOP CURRENT JOB AND GO TO RESCAN
	ION		/NOW ITS SAFE TO TURN INTERRUPTS BACK ON
	>
	JMP I	LOC20	/RETURN TO CALLING TASK
ECDIF0,	CDF CIF 0	/OOPS - WE MUST TASK SWITCH IMMEDIATELY!
	JMP I	(TSTOP	/GO STOP THIS TASK AND RUN SOMEONE ELSE

INTEND,	BSKCHN
	IFNDEF	SWAPPER	<
/RTS-8 SCHEDULER - SCANS TASK FLAGS TABLE TO DETERMINE HIGHEST
/PRIORITY RUNNABLE TASK - RUNS WITH INTERRUPTS ON (SOMETIMES)
/AND IS STATELESS.

FINDJ,	CLA CLL IAC	/CODE TO FIND FIRST RUNNABLE TASK
	DCA	TASKX	/INITIALIZE TASK NUMBER
	DCA	SVSFLG	/THE MACHINE STATE IS NOW UNIMPORTANT
	CLA IAC		/AND WE SHOULD RE-ENABLE TASK SWITCHING
	DCA	TSWFLG	/SO THAT IF A TASK BECOMES RUNNABLE
	TAD	(TFTABL	/AFTER WE SCAN IT, IT WILL INTERRUPT
	DCA	XR	/THE SCAN LOOP AND RUN.
FINDJL,	IFNZRO	HGHFLD	<CIF 0>	/AS WE SEARCH A TASK'S ENTRY IN THE LIST,
	IFZERO	HGHFLD	<IOF>
	TAD I	XR	/WE ASSUME THAT TASK'S PRIORITY
	SNA CLA		/LOOK FOR FIRST TABLE ENTRY OF 0
	JMP I	(STARTJ	/(THERE HAS TO BE ONE - NAMELY THE NULL TASK)
	IFZERO	HGHFLD	<ION>
	ISZ	TASKX	/BUMP THE TASK NUMBER (AND PRIORITY)
			/ALLOW INTERRUPTS FOR ONE CYCLE SINCE
	JMP	FINDJL	/"TASKX" IS BIGGER THAN CURRENT REJECTED TASK
	>
	IFDEF	SWAPPER	<
/RTS-8 SCHEDULER - SCANS TASK FLAGS TABLE TO DETERMINE HIGHEST
/PRIORITY RUNNABLE TASK - RUNS WITH INTERRUPTS ON (SOMETIMES)
/AND IS STATELESS.
/THIS SCHEDULER, USED WITH THE SWAPPER, IS SLIGHTLY
/SLOWER THAT THE PREVIOUS SCHEDULER, USED WITHOUT THE SWAPPER.

/NOTE: THIS ROUTINE IS VERY PRONE TO RACE CONDITIONS.
/DO NOT MODIFY IT UNLESS YOU VERY CAREFULLY CHECK OUT WHAT
/MIGHT HAPPEN IF AN INTERRUPT OCCURS AFTER EACH STATEMENT

ACTION,	SNL		/IS HE NONRESIDENT?
	JMP I	(STARTJ	/NO: START HIM UP
	IFNZRO	EXEC-SWPWT	<SYSERR,_ERROR_>	/CALEXC.NE.SWPWT
	TAD	CALEXC	/AC='SWPWT'
	DCA I	NXR	/PUT HIM IN SWAP WAIT
	TAD	(-RUNWT-1
	AND I	(SWAPPER+TFTABL
	DCA I	(SWAPPER+TFTABL	/TAKE SWAPPER OUT OF RUN WAIT
			/GO FIND SOMEONE ELSE; HOPEFULLY SWAPPER
			/** NOTE: AC MAY BE NON-ZERO ON ENTRY **
FINDJ,	CLA IAC		/CODE TO FIND FIRST RUNNABLE TASK
	DCA	TASKX	/INITIALIZE TASK NUMBER
	DCA	SVSFLG	/THE MACHINE STATE IS NOW UNIMPORTANT
			/IN CASE WE ARE TASK-SWITCHED OUT OF THE SCAN LOOP
			/WE WILL NOT SAVE STATE
	CLA IAC		/NOW (NOT EARLIER) WE CAN RE-ENABLE TASK SWITCHING
	DCA	TSWFLG	/SO THAT IF A TASK BECOMES RUNNABLE
	TAD	(TFTABL	/AFTER WE SCAN IT, IT WILL INTERRUPT
	DCA	NXR	/THIS SCAN LOOP AND RUN
FINDJL,	IFNZRO	HGHFLD	<CIF 0>	/AS WE SEARCH A TASK'S ENTRY IN THE LIST
	IFZERO	HGHFLD	<IOF>
	ISZ	NXR	/(BUMPING TO NEXT ENTRY)
	TAD I	NXR	/WE ASSUME THAT TASK'S PRIORITY
	CLL RAL		/PUT NON-RESIDENT BIT INTO LINK
	SNA CLA		/LOOK FOR THE FIRST TABLE ENTRY OF 0
	JMP	ACTION	/FOUND ONE, START HIM UP
	IFZERO	HGHFLD	<ION>
	ISZ	TASKX	/BUMP THE TASK NUMBER (AND OUR PRIORITY)
	JMP	FINDJL	/ALLOW INTERRUPTS FOR ONE CYCLE SINCE
			/'TASK' IS BIGGER THAN CURRENT REJECTED TASK
			/WE MAY RESCHEDULE OUT OF HERE
NXR,	0
	>
	PAGE
/SEND A MESSAGE TO A TASK

/	*****  N O   L I T E R A L S   O N   T H I S    P A G E  !

XSENDW,	STA		/SET OR
XSEND,	DCA	SWTFLG	/CLEAR WAIT FLAG
	TAD I	LOC20
	ISZ	LOC20	/GET THE
	DCA	ACARG	/TASK NUMBER FROM THE ARGUMENT LIST
	TAD I	LOC20	/GET THE ADDRESS OF THE MESSAGE
	DCA	MSGADR
	TAD I	MSGADR
	SNA CLA		/IS THE MESSAGE ALREADY IN A QUEUE?
	JMP	MSGFRE	/NO
	AC7775
	TAD	LOC20
	DCA	LOC20	/BUMP PC BACK TO DO CALL AGAIN
MSEFWT,	TAD	MSGADR
	JMP I	PWAITS	/WAIT FOR MESSAGE TO BE FREE
MSGFRE,	ISZ	LOC20
	TAD	ACARG	/GET THE ADDRESS OF THE TARGET TASKS'
	JMS	SRCOMN	/MESSAGE QUEUE POINTER
	DCA	MSGCDF	/SAVE CDF TO NEW MESSAGE'S FIELD
	TAD	DCDF
ADDTOQ,	DCA	MPTCDF	/SAVE CDF TO FIELD OF CURRENT QUEUE POINTER
	CLA IAC
	TAD	MPTR
	DCA	MPT2	/GET POINTER TO SECOND WORD OF POINTER
	TAD I	MPT2
	DCA	T	/SAVE ADDRESS OF NEXT QUEUE ENTRY
	TAD I	MPTR	/FIRST WORD IS A CDF
	SNA		/ZERO TERMINATES THE QUEUE
	JMP	ENDOFQ
	DCA	NXTCDF	/SAVE CDF
RCVPTR,
NXTCDF,	HLT
	AC3777
	AND I	T	/FIRST WORD OF MESSAGE HEADER IS TASK#
	CIA CLL		/COMPARE TO NUMBER OF SENDING TASK
	TAD	TASKX	/IF NUMBER IS LOWER WE INSERT
	SNL CLA		/THE MESSAGE BEFORE THIS ONE
	JMP	ENDOFQ
	CLA IAC
	TAD	T
	DCA	MPTR	/OTHERWISE GO ON TO THE NEXT
	TAD	NXTCDF	/QUEUE ENTRY
	JMP	ADDTOQ
/COME HERE WHEN WE HAVE FOUND THE PLACE TO INSERT THE MESSAGE

ENDOFQ,
MPTCDF,	HLT		/SET DF TO FIELD OF PREVIOUS POINTER
	TAD I	MPTR
	DCA	MPTCDF	/SAVE PREVIOUS CDF
	TAD	MSGCDF	/LINK THE NEW MESSAGE BETWEEN TWO
	DCA I	MPTR	/EXISTING MESSAGES ON THE QUEUE
	TAD	MSGADR
	DCA I	MPT2	/OK - HALF THE LINKAGE IS DONE
	IOF		/MUST TURN INTERRUPTS OFF TO CALL FREEJ!
	TAD	ACARG
	JMS I	PFREEJ	/CLEAR MESSAGE WAIT BIT FOR RECEIVER
	MSGWT!EORMWT	/(DO IT NOW SO DF WILL BE CORRECT LATER)
	TAD	TASKX	/*** CODE IN THIS RANGE MUST NOT TOUCH LINK ***
MSGCDF,	HLT		/* NOW GO TO THE MESSAGE'S DATA FIELD
	ION		/* WE'RE SAFE - TURN INTERRUPTS ON
	DCA I	MSGADR	/* STORE THE SENDING TASK NUMBER
	ISZ	MSGADR	/*
	TAD	MPTCDF	/*
	DCA I	MSGADR	/* STORE CDF TO NEXT MESSAGE IN Q
	ISZ	MSGADR	/*
	TAD	T	/*
	DCA I	MSGADR	/* STORE ADDRESS OF NEXT MESSAGE IN Q
	ISZ	SWTFLG	/* SHOULD WE WAIT ON THIS MESSAGE?
	JMP I	PPOSTEX	/* NO - RUN RECEIVER IF ITS
			/* HIGHER PRIORITY, ELSE EXIT
	AC7776		/DON'T WORRY ABOUT RECEIVER -
			/WAITING WILL FORCE RESCAN OF TASK LIST -
	JMP	MSEFWT	/GO WAIT ON MESSAGE EVENT FLAG
			/** DF MUST BE SET TO CALLER'S FIELD HERE **

SRCOMN,	0		/SUBROUTINE USED BY SEND AND RECEIVE
	CLL RAL		/GET POINTER TO A TASK'S
	TAD	PMSGTBL	/MESSAGE QUEUE POINTER
	DCA	MPTR
	CDF 0
	AC7776
	TAD I	PEXRET
	JMP I	SRCOMN
/RECEIVE A MESSAGE FROM THE TASK'S MESSAGE QUEUE

XRECEIV,TAD	TASKX
	JMS	SRCOMN	/GET THE MESSAGE QUEUE PTR FOR THIS TASK
	DCA	STOCDF	/SAVE CDF TO CALLING FIELD
	TAD	DCDF
RCVLP,	DCA	PRVCDF	/SAVE PREVIOUS Q ENTRIES' FIELD
	TAD I	MPTR	/GET MESSAGE QUEUE POINTER
	SNA		/IF ZERO, THERE ARE NO MESSAGES IN THE Q
	JMP	NOMSG	/SO HANG THE TASK
	DCA	CHNCDF
	CLA IAC
	TAD	MPTR
	DCA	MPT2	/GET POINTER TO SECOND WORD OF Q POINTER
	TAD I	MPT2
	DCA	RCVPTR
SWTFLG,
CHNCDF,	HLT		/CDF TO FIELD OF Q ENTRY
	AC3777		/IGNORE SIGN BIT
	AND	ACARG	/ACARG CONTAINS TASK DEDICATION (IF ANY)
	CIA
	SZA		/IS RECEIVER DEDICATED TO ANYONE?
	TAD I	RCVPTR	/YES - CHECK ORIGIN OF THIS MESSAGE
	ISZ	RCVPTR
	CLL RAL		/HIGH-ORDER BIT (WAIT BIT) IRRELEVANT
	SNA CLA		/CAN THIS MESSAGE BE RECEIVED?
	JMP	RCVOK	/YES - PASS IT ON
	TAD	RCVPTR	/NO - CHAIN TO NEXT MESSAGE IN Q
	DCA	MPTR
	TAD	CHNCDF
	JMP	RCVLP

RCVOK,	TAD I	RCVPTR	/GET FIRST WORD OF ENTRY
	DCA	T
	ISZ	RCVPTR
	TAD I	RCVPTR
PRVCDF,	HLT		/SET FIELD OF PREVIOUS Q ENTRY
	DCA I	MPT2	/SET PREV Q ENTRIES' POINTER (BOTH WORDS)
	TAD	T	/TO THE CONTENTS OF THIS Q ENTRIES'
	DCA I	MPTR	/POINTER, REMOVING THIS ENTRY FROM THE Q
	CLA IAC		/FORM A POINTER TO THE FIRST WORD OF
	TAD	RCVPTR	/INFORMATION IN THE REMOVED MESSAGE
MSGADR,
STOCDF,	HLT
	DCA I	LOC20	/AND STORE IT IN THE FIRST ARGUMENT
	TAD	CHNCDF	/RETURN WITH CDF TO MESSAGE IN AC
STOCD2,	ISZ	LOC20	/SKIP ARG
	JMP I	PEXRET

/LITERALS:

PWAITS,	WAITS
PFREEJ,	FREEJ
PPOSTEX,POSTEX
PMSGTBL,MSGTBL
PEXRET,	EXRET

NOMSG,	TAD	ACARG	/LOOK AT AC AGAIN
	SPA CLA		/DID USER WANT TO WAIT IF NO MESSAGE?
	JMP	STOCD2	/NO
			/YES, FLOW INTO WAITM3
	IFNZRO	.&1000	<SYSERR,_ERROR_>	/PAGE TOO BIG
/WAIT FOR MESSAGE

WAITM3,	AC7776
	TAD	LOC20
	DCA	LOC20	/MOVE PC BACK TO "JMS 20"
	STL		/SET LINK TO PRESERVE AC ACROSS "TSTOP"
	TAD	(MSGWT	/BLOCK TASK ON MESSAGE WAIT

/COME HERE WITH BLOCKING BITS IN AC.
/TASK AC WILL BE CLEARED IF LINK IS 0, PRESERVED IF LINK IS 1

TSWAIT,	DCA	BLKMSK	/ENTER HERE WITH BLOCKING BITS IN AC

TSWATX,	TAD	TASKX	/ENTER HERE WITH BLOCKING BITS IN "BLKMSK"
	TAD	(TFTABL	/GET INDEX INTO JOB FLAGS TABLE.
	DCA	T
	TAD	BLKMSK	/GET BLOCKING BITS
	CDF 0
	DCA I	T	/NO NEED TO OR THEM IN - WORD WAS ZERO BEFORE.
	ION		/(IN CASE WE CAME FROM "WAITE" OR "WAITM")
	SNL		/SHOULD WE CLEAR TASK AC?

TSTOP,	DCA	ACARG	/ENTER HERE WITH TASK AC IN AC
XTSTOP,	TAD	TASKX	/TO STOP THE CURRENT TASK BUT NOT BLOCK IT.
	CLL RTL		/GET A POINTER INTO THE TASK'S STATE TABLE ENTRY
	TAD	(TSTABL-1
	DCA	XR
	CDF 0
	IFNZRO	HGHFLD	<
	TAD I	(EXRET
	CLL RAR
	RTR
	TAD I	(EXRET
	TAD	(-5023	/5023 = 6203 + (6203 SHIFTED RIGHT 3)
	>
	DCA I	XR	/STORE RETURN IF AND DF=IF
	TAD	LOC20
	DCA I	XR	/STORE RETURN PC
	TAD	ACARG
	DCA I	XR	/STORE RETURN AC
	IFNZRO	EAE	<
	MQA		/EVEN PRESERVE THE MQ OVER MONITOR CALLS
	DCA I	XR	/(WHAT THE HECK, ITS ONLY 2 INSTRUCTIONS)
	>
	IFDEF	SWAPPER	<
	TAD	COMMAND
	SPA CLA		/FREE THE PARTITION?
WIPCAL,	JMS I	SWPENT>	/YES: LET SWAPPER CODE DO IT
	JMP I	(FINDJ	/NO: FIND NEXT TASK TO RUN
/SCHEDULE A TASK TO BE RUN

XRUN,	TAD	(RUNWT
	JMP	UNBLOK

XUNBARG,TAD I	LOC20		/UNBLOCKING CODE IN ARGUMENT
	ISZ	LOC20

UNBLOK,	DCA	UNBMSK	/AC CONTAINS REASON FOR UNBLOCKING TASK "ACARG"
	TAD	ACARG
	IOF		/FREEJ IS AN INTERRUPT-LEVEL ROUTINE!
	JMS	FREEJ	/REMOVE THE GIVEN BLOCKING BIT
UNBMSK,	0
	ION
POSTEX,	SNL CLA		/SHOULD THE NEW TASK BE RUN NOW?
	JMP I	(EXRET	/NO
	JMP	TSTOP	/YES-PUT TASK TO SLEEP WITHOUT BLOCKING IT


/SUSPEND EXECUTION OF A TASK

XSUSPND,TAD	(RUNWT
	JMP	BLOK

XBLKARG,TAD I	LOC20	/BLOCKING CODE IN ARGUMENT
	ISZ	LOC20
BLOK,	DCA	BLKMSK	/SAVE BLOCKING CODE
	TAD	ACARG	/GET TASK TO BE BLOCKED
	SNA
	JMP	TSWATX	/0 MEANS CURRENT TASK!

/	^		NOTE THE LINK IS RANDOM HERE BUT SINCE ACARG=0
/			IT DOESN'T MATTER IF WE CLEAR IT OR NOT

	CDF 0
	TAD	(TFTABL
	DCA	T
	TAD	BLKMSK	/GET THE BLOCKING FLAG(S)
	CMA
	AND I	T
	TAD	BLKMSK	/OR THEM INTO THE TASK FLAG WORD
	DCA I	T
	JMP I	(EXRET	/THIS DOESN'T AFFECT US - JUST RETURN
/ROUTINE TO UNBLOCK A TASK'S EXECUTION
/ENTER WITH TASK# IN AC, INTERRUPTS OFF, UNBLOCKING BIT IN CALL+1

FREEJ,	0
	CDF 0
	TAD	(TFTABL
	DCA	INTT
	TAD I	FREEJ	/GET UNBLOCKING BIT
	ISZ	FREEJ	/BUMP RETURN POINTER
	CMA
	AND I	INTT
	DCA I	INTT	/REMOVE THE FLAG FROM THE TASK FLAG WORD
	TAD I	INTT
	IFDEF	SWAPPER	<
	CLL RAL		/IGNORING NON-RESIDENT WAIT,
	>
	SNA CLA		/IF THE TASK IS NOW RUNNABLE
	TAD	TASKX	/AND HAS A HIGHER PRIORITY THAN THE CURRENTLY
	TAD	(TFTABL	/RUNNING TASK, RETURN WITH THE LINK ON.
	CIA STL
	TAD	INTT
	CLA		/OTHERWISE RETURN WITH THE LINK OFF.
	JMP I	FREEJ
/WAIT FOR EVENT FLAG

XWAITX,	STA		/USE 'ACARG' AS FLAG (-1 INDICATES WAITX)
XWAITE,	DCA	ACARG
	TAD I	LOC20	/GET ADDRESS OF EVENT FLAG
	ISZ	LOC20	/SEND HAS ACARG RANDOM BUT NOT -1
WAITS,	DCA	T	/ENTER HERE FROM SEND
	IFZERO	HGHFLD	<IOF>	/INHIBIT INTERRUPTS
	IFNZRO	HGHFLD	<CIF 0>	/WHILE TESTING FLAG!
	TAD I	T	/EVENT FLAG IS IN SAME FIELD AS CALL
	SNA CLA		/ZERO MEANS EVENT COMPLETED
	JMP I	(EXRET	/SO EXIT IMMEDIATELY
	IFNZRO HGHFLD <IOF>	/INTERRUPTS MUST BE OFF BETWEEN SETTING EF
			/AND SETTING EF WAIT!
	AC4000		/SET EVENT FLAG TO TASK NUMBER
	TAD	TASKX	/WITH HIGH-ORDER BIT ON TO INDICATE
	DCA I	T	/THAT TASK IS WAITING FOR EVENT COMPLETION
	TAD	(EFWT
	ISZ	ACARG	/WAS THIS A WAITE OR WAITX?
	JMP	TSWAIT	/WAITE; AND BLOCK CURRENT TASK ON EVENT WAIT
			/** NOTE LINK=0 SO ACARG WILL BE CLEARED **
	AC7775		/WAITX
	TAD	LOC20	/BUMP PC BACK TO CAL
	DCA	LOC20	/ALSO CLEAR LINK
	TAD	(EORMWT
	JMP	TSWAIT

/POST AN EVENT FLAG

XPOST,	TAD I	LOC20	/GET DATA FIELD OF EVENT FLAG
	ISZ	LOC20
	DCA	.+1
BLKMSK,	HLT		/CDF TO IT
	AC4000
	TAD I	ACARG	/ADDRESS WAS IN AC AT CALL
	DCA	T
	DCA I	ACARG	/ZERO EVENT FLAG
	SNL		/WAS A TASK WAITING ON EVENT FLAG?
	JMP I	(EXRET	/NO - WE'RE DONE
	TAD	T	/YES - LOW ORDER BITS ARE TASK NUMBER
	DCA	ACARG
	TAD	(EFWT!EORMWT
	JMP	UNBLOK	/UNBLOCK THIS TASK FROM EVENT FLAG WAIT
	PAGE
/DUMMY TABLE ENTRIES (EACH TASK OVERLAYS ITS ENTRY WHEN IT LOADS):

MSGTBX,	ZBLOCK	NTASKS^2
	0;0		/MESSAGES FOR NULL TASK
TSTABX,	ZBLOCK	NTASKS^4
	0
	.+1		/FIELDS, PC, AC FOR NULL TASK
	DCA	SVSFLG	/NULL TASK RUNS STATELESS
	JMP	.

TFTABX,	IFNZRO	NTASKS&40 <
	1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1>
	IFNZRO	NTASKS&20 <
	1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1>
	IFNZRO	NTASKS&10 <
	1;1;1;1;1;1;1;1>
	IFNZRO	NTASKS&4 <1;1;1;1>
	IFNZRO	NTASKS&2 <1;1>
	IFNZRO	NTASKS&1 <1>

	0		/NULL TASK ALWAYS RUNNABLE

	IFNZRO	TFTABX-TFTABL-1	<TBLERR,_ERROR_>
	IFDEF	SWAPPER	<
	*RESTBL
	ZBLOCK	NTASKS-SWAPPER^2
	*PARTBL
	ZBLOCK	PARTNS^4
	>

	IFNZRO	KL8A	<
	*KL8ACT
KL8ACT,	0
	HLT		/SAFETY HALT IN CASE USER
	JMP	.	/FORGETS TO ASSEMBLE KL8ASR.PA
	>
	IFDEF	DDCMP	<
	FIELD	DDCFLD%10
	*LCBTAB
	ZBLOCK	MAXLIN^LCBSIZ
	>
	IFDEF	NSP	<
	FIELD	NSPFLD%10
	*CCBTAB
	ZBLOCK	MAXCCB^2
	>
	FIELD	0

