; M X S C A N ; ;TASK SCANNER MODULE AND STATE TESTER FOR MSX-11 SYSTEM. ; THIS ROUTINE GAINS CONTROL AFTER ALL TRAPS, INTERUPTS, ;ETC. AND IS CALLED TO LOOK FOR WORK. IT ALSO CONTAINS THE MAIN ;INPUT MESSAGE SERVICE ENTRIES TO HANDLE THE STATE TRANSITIONS ;FORCED BY MESSAGES FROM OTHER PARTS OF THE SYSTEM. ; M.MMP=0;THIS IS A MULTIPROCESSOR MONITOR! ;THIS VERSION OF MXSCAN IS FOR USE IN STAND-ALONE SYSTEMS ;PROVIDED THE ASSEMBLY CONDITIONAL $$DOS AND THE CONDITIONAL NODOS ;ARE BOTH DEFINED. ;MAPPED SYSTEMS .TITLE MXSCAN V004 MSX SCANNER .PSECT ; NULL CSECT .MACRO KMOV SRC,DEST .IF DF,SAXCL MFPI SRC MOV (SP)+,DEST .IFF MOV SRC,DEST .ENDC .ENDM .IF DF,$$DOS .IF DF,NODOS SAXCL=0 ;EXCLUDE CODE ON STANDALONE IF DEFINED .ENDC .ENDC UPAR7=177656 KAPR6=172354 .GLOBL UPAR7,KAPR6 ; DEFINE OUR REGISTERS R0=%0 R1=%1 R2=%2 R3=%3 R4=%4 R5=%5 SP=%6 PC=%7 ;PS=177776 ; PROCESSOR STATUS REG ; EAE REGS THAT REQUIRE SAVING EAEAC=177302 EAEMQ=177304 EAECSR=177310 ;EAE=0 ; SET FOR EAE SAVE/RESTORE ; OFFSETS OF MSX TABLE ENTRIES TCBID=0 ; TASK IDENTIFICATION FOR REQUEST AND RESUME TCBPR=2 ; PRIORITY (IGNORED BY MSX0) TCBST=3 ; CURRENT TASK STATE TCBSA=4 ; STARTING ADDRESS WHEN REQUESTING TCBISP=6 ; INITIAL STACK POINTER .GLOBL TCBDSP TCBDSP=10 ; DYNAMIC STACK POINTER TCBCSP=12 ; STACK CHECK WORD .IF DF,M$GE ;IF MEMORY MANAGING MSX IS TO BE DONE .IFTF TCBAP1=14 ;USE TCB CELL FOR INITIAL APR 1 CONTENTS. OTHERS UNDEFINED. .IFT A$PROF == 16 ;STACK OFFSET FOR 6 SAVED APR'S PLUS PC FOR JSR PC,A.PRSV CALL .IFF ;NO MEMORY MANAGEMENT A$PROF == 0 ;IF NO MANAGEMENT, NO STACK OFFSET .ENDC TCBEVA=16 ; EVENT VARAIBLE ADDRESS .IF DF,$$DOS .IF DF,NODOS TCBREG=20 ;OFFSET TO KEEP REGS AND APR'S IN FOR U.RSAV/U.RRES .ENDC .ENDC ; NOW DEFINE GLOBAL SYMBOLS USED BY SCAN .GLOBL MX.IAC,MX.SEV,MX.LOK,MX.ATL,MX.TCB,MX.STK .GLOBL MX.OSP,MX.EMT,MX.XIT,MX.TRP,MX.IOT .IF DF,$$DOS .GLOBL MX.IVS .ENDC .GLOBL S.RSAV,S.RRES ; .IF DF,$$DOS .IF DF,NODOS SAXCL=0 ;STAND ALONE OPS .GLOBL U.RSAV,U.RRES .ENDC .ENDC DE.BUG=0 ;NO SVDB$ ;(REMOVE THIS DEFINITION TO USE DEBUG VECTORS FOR ;MSX TRAP SERVICE (SLIGHTLY FASTER UNDER RSX11M...)) .IF NDF,$$DOS ;QTRAN HANDLES I/O VIA QIO$ TO FILES IT PRE-OPENS ON UP TO "NLUSN" ;FILES. THESE I/O REQUESTS ARE TO BLOCKS OF THE FILES RELATIVE ;TO THEIR STARTS, AND THE FILES ARE OPENED FOR UPDATE AT STARTUP ;AND PRESUMED PREALLOCATED. THE ENTIRE SET OF FILE-STRUCTURED OPENS ;MAY BE NO-OPPED BY CONDITIONAL ASSEMBLY TO REGAIN ROUGHLY 3K OF ;SPACE (PLUS AN AMOUNT VARYING WITH THE NUMBER OF LUNS) FROM THE ;SYSTEM, BUT ONE MUST THEN USE THE NORMAL RSX11M I/O MECHANISM. ;THE STANDALONE MSX HAS ITS OWN SCHEMES AND THESE PARAMETERS DO NOT ;APPLY THERE. NLUNS==7 ;NUMBER OF LUNS SUPPORTED BY QTRAN MAXLUN==7 .ENDC ; MX.BGN MSX ENTRY POINT FOR START OF MSX PROGRAM ; WE SET UP OUR TRAP VECTOR AND GO OFF ; TO START SCANNING ;--- ;DEFINE TRAP ENTRIES FOR RSX BASED SYSTEMS... .IF NDF,$$DOS .IIF DF,TP$ALL,AL$APR=0 .IF NDF,TP$ALL VECT:: .WORD MX.FTL ;ODD ADDR .WORD MX.KIL ;MEM PROT VIOL. STACK BAD SO KILL AT ONCE .WORD MX.QUE ;BPT -- QUESTIONABLE,NONFATAL .WORD MX.FTL ;IOT .WORD MX.FTL ;RESERVED INST .WORD MX.QUE ;NON-RSX EMT - NONFATAL .WORD RX.TRP ;TRAP INST .WORD 0 ;FLOATING POINT EXCEPTION ??? .IFF VECT:: .WORD MX.FTL,MX.KIL .WORD TKBPT,TKIOT,MX.FTL .WORD TKREMT,TKRTRP,0 ;VECTORS IF TASK IS ALLOWED TO ; HAVE EMT, TRAP, BPT, IOT VECTORS OF ITS OWN... .ENDC .MCALL SVTK$S BGNS:: .IF DF,RSTSTT ;IF RESET AT BEGINNING WANTED MX.BGN: ; ENTRY POINT HERE FOR NORMAL MODE .ENDC NOP NOP .IFF BGNS:: .IF DF,RSTSTT ;IF RESET AT BEGINNING WANTED MX.BGN: ; ENTRY POINT HERE FOR NORMAL MODE .ENDC RESET ; EXECUTE THIS IF USER SETS BEGIN ADDRESS NOP ; ALLOW USER PATCHES BEFORE STARTING .ENDC .GLOBL BGNS .GLOBL MX.BGN .IF NDF,RSTSTT ;IF NO RESET AT START WANTED MX.BGN: ; ENTRY POINT HERE FOR NORMAL MODE .ENDC .IF DF,$FPP$ MOV #2,@#246 ;SET UP FLOATING INTERRUPT VECTOR MOV #246,@#244 LDFPS #40000 ;AND DISABLE MOST FLOATING INTERRUPTS .ENDC MOV SP,MX.OSP ; SAVE ORIGINAL STACK POINTER MOV #MX.STK,SP ; SET UP STACK POINTER MOV #-1,MX.HGH ;SET LOW PRIO "HIGHEST PRIO" TASK .IF DF,$$DOS .IF DF,NODOS ;SET UP 18 BIT MAPPING HERE BY LOADING ALL REGISTERS, THEN TURNING THE ;MAPPING BOX ON. THE SYSTEM AS STANDALONE IS THE ONLY PLACE THIS HAPPENS, ;AND 22 BIT MODE CAN BE HANDLED PROVIDED DMA DEVICE DRIVERS ARE MODIFIED ;TO ACCEPT IT. THE DMA DEVICE DRIVERS ARE THE ONLY PLACE IN THE SYSTEM ;NEEDING MODS...EVERYTHING ELSE CAN HANDLE 22 BIT MODE JUST FINE AS IT ;IS. MOV #77406,R0 ;SET UP ALL PDR'S MOV #KPDR0,R1 ;POINTER KNL PDR 0 MOV #UPDR0,R2 ;SET UP USER AND KERNEL MODES MOV #10,R3 ;8 OF THEM ;NOTE THAT ALL PDR'S ARE SET TO 4K READ/WRITE ACCESS. A PROTECTING SYSTEM ;WOULD SET UP PDR'S FOR EACH TASK AND PROTECT READ/ONLY AREAS, BUT ONE ;HAS TO START SOMEWHERE... ; ... GCE 1$: MOV R0,(R1)+ MOV R0,(R2)+ ;SET UP A PDR DEC R3 ;COUNT DOWN BGT 1$ ;UNTIL ALL DONE ; ;NOW SET UP KERNEL APR'S TO BOTTOM OF PHYSICAL MEMORY ; MOV #KPAR0,R0 ;WHERE CLR R1 ;WHAT TO PUT IN MOV #UPAR0,R3 ;SET UP USER SPACE ALSO AT FIRST MOV #7,R2 ;HOW MANY TO DO 3$: MOV R1,(R0)+ ;SET UP THE PDR MOV R1,(R3)+ ;SET UP USER APR TOO ADD #200,R1 ;POINT AT NEXT DEC R2 BGT 3$ ;SET UP APR 0 - 6 ;START OFF BOTH KERNEL AND USER APR7 TO THE I/O PAGE. NOTE THAT ONLY ;THE KERNEL MODE WOULD BE SO SET UP IF PROTECTING THE SYSTEM, AND ;USER MODE PROCESSES WOULD NORMALLLY START UP WITH PREVIOUS ;USER MODE TOO, TO PREVENT MTPI/MFPI FROM BASHING ANYTHING ELSE. MOV #177600,(R0) ;POINT AT I/O PAGE WITH APR 7 MOV #177600,@#UPAR7 ;ALSO SET UP USER MODE APR7 TO I/O PAGE KPDR0=172300 UPDR0=177600 KPAR0=172340 KPAR7=172356 UPAR7=177656 UPAR0=177640 MMSR0=177572 ;MEM. MANAGEMENT STATUS REG 0 ; ; START MEMORY MANAGEMENT UNIT ; MOV #1,@#MMSR0 ;ENABLE 18-BIT MAP ;(NOTE: UMR'S NOT ALLOCATED HERE... ; MUST DO SO ON 11/44 OR 11/70 IF OVER 124K MEMORY...) ;(THIS FURTHER PRESUMES SOME ALLOCATING MECHANISM, ALSO NOT SET UP...) JSR PC,MX.MAP ;SET UP INITIAL MAPPINGS ALL TSKS .ENDC .ENDC .IF NDF,$$DOS .MCALL SVDB$S,EXIT$S .MCALL WSIG$S .IF NDF,DE.BUG SVDB$S #VECT,#7 .ENDC ;TELL RSX WE WANT TRAP SERVICES AT THE LOCATIONS DEFINED IN TABLE VECT ABOVE. SVTK$S #VECT,#7 ;ALLOW SST VIA EITHER...FOR DDT USE ;NOW VECTORS ALL SET. MX.IOT IS ERROR CATCHER... ;NEXT OPEN ALL FILES WE ARE USING FOR QTRAN ACCESS... JSR PC,OPNALL ;OPEN FILES ON LUNS 1-NLUNS .IF DF,M$GE ;IF USING MEM. MANAGEMENT UNDER MSX JSR PC,MX.MAP ;LOAD ALL SEGMENTS INTO MEMORY ;NOTE THAT SEGMENT NAMES ARE ; XXXTSK ; WHERE MSX TASK NAMES ARE THE "XXX" IN EACH CASE. IT IS ; EXPECTED THAT EACH TASK HAS A SEGMENT AT TCB+14 (CURRENTLY UNUSED) ; AND THAT ITS NAME IS NORMALLY THE SAME AS THE TASK, THOUGH IT NEED ; NOT BE. ; JSR PC,WNDSET ;INITIALIZE DATA FOR ADDR MAPPING ;(THE WNDSET CALL ALSO ALLOCATES A DYNAMIC STORAGE REGION...) .IIF DF,MX.IV, JSR PC,SPRING ;SPRING INTERRUPT VECTOR .ENDC .ENDC .IF DF,M.MMP ; MULTIPROCESSOR STARTUP SPECIAL ITEMS. ; ;CLEAR INITIAL BITMAP OF AST NODES MOV #PX.NSZ,R0 ;PERM. NODEPOOL COPY MOV #MX.NSZ,R1 ;WORKING NODEPOOL CTLL COPY PX.WDS=7 MOV #PX.WDS,R2 ;SIZE OF NODEPOOL CTL 130$: MOV (R0)+,(R1)+ ;RESET WORKING SYS NODEPOOL COPY SOB R2,130$ MOV #MX.BMP,R0 ;BITMAP START MOV #MX.MPE,R1 ;BITMAP END 131$: CLR (R0)+ ;ZERO MAP OUT CMP R0,R1 ;SEE IF AT END YET BLO 131$ ;IF NOT CLEAR NEXT WORD ;SETUSG MUST HAVE A SPECIAL STARTUP TABLE GIVING WHICH TASKS ARE ACTIVE AT ;SYSTEM START IN THIS CPU. IT CANNOT USE MX.TBL FOR IT SINCE MX.TBL ;MAY BE SHARED... JSR PC,SETUSG ;SET UP CPU NUMBER AND TASK USAGE FROM STL ;ALSO AT THIS POINT CLEAN MSG AREAS OF ALL ACTIVE TASKS ;GO OVER WHOLE OF MX.TBL ;THIS GUARANTEES ALL SYSTEM QUEUES ARE OK... MOV #MX.TBL,R0 ;START UP 101$: ;**** ALLOW NON LOADING TASKS TO INIT THEIR MAPS ETC. TSTB TCBCPU(R0) ;IS TASK NOWHERE (SET IT UP TEMPORARILY) BEQ 122$ ;YES CMPB MX.CPU,TCBCPU(R0);IS TASK IN OUR CPU? BNE 102$ ;NO, LOOK AT NEXT 122$: ; ;NOTE: ALLOW INACTIVE TASKS TO BE INITIALIZED BY COMMENTING OUT THE 2 ;LINES FOLLOWING: ; TSTB TCBST(R0) ;TASK NOT EXITED? ; BEQ 102$ ;NO, INACTIVE SO IGNORE ;ADD MORE TESTS ON CODES FOR STATUS AS NEEDED HERE. MUST BE SURE TASK ;IS ACTIVE ON THIS CPU AND IN MEMORY. LET 100 BIT (OCTAL) BE OUT-OF-MEM ;BIT AND WE GET ; BITB #100,TCBST(R0) ;OUT OF MEMORY? ; BNE 102$ ;YES. (WOULD SET 100 AND 200 BITS TOGETHER) ;IF WE GET HERE, TASK WAS ACTIVE SOMEHOW SO CLEAR IT UP. ;SCB SIZE IS 7 WORDS LONG. ;SCB POINTER IS TO PERM. DATA IN USER TASK WHICH WE MUST ENSURE IS MAPPED. ;NOTE POINTERS ARE CORRECT FOR WORKING COPY OF BITMAP CTL AREA ADDR ; ;ENSURE NO TASK IS SET AS ALREADY BEGUN... (MAY NEED MORE LATER) CLR TCBDSP(R0) ;CLEAR DYNAMIC SP = TASK ACTIVE & STARTED FLG ; ;RESET SCRATCH AREA FOR EACH TASK, WHICH HAS MESSAGES' DATA ;... ZERO BITMAP TOO. JSR PC,MQSET ;COMMON SUB CLEARS BITMAP AND ;REGENERATES QUEUES. 111$: ; 102$: ADD #MX.TBS,R0 ;POINT AT NEXT TST @R0 ;DONE? BNE 101$ ;NO, STILL MORE TASKS TO DO JSR PC,DQRCV ;START I/O FOR INPUT MESSAGES (EACH INTERRUPT ;ISSUES ANOTHER READIN. WRITES NOT A PROBLEM. ; ; NOTE: MESSAGE READIN SHOULD BE STARTED WITH EACH BUS TO WHICH THE ; CPU IS ATTACHED (IF ANY). SETUSG WILL HAVE TO INITIALIZE INTERRUPT ; VECTORS OR ASTs AS APPROPRIATE FOR THE DETAILED HARDWARE CONFIGURATION ; .ENDC .IF DF,MX$CLK ;FOR CASES WHERE THERE IS A CLOCK .IF DF,SAXCL ;FOR STAND-ALONE VERSION, SET UP THE CLOCK .IF DF,KW11P ;IF CLOCK IS PROGRAMMABLE... MOV #340,@#106 ;SET NEW PSW MOV #CLKINT,@#104 ;AND CLK INT VECTOR MOV #-60.,@#172542 ;SET 60 TICKS PER INTERRUPT MOV #105,@#172540 ;AND SET LINE FREQ. OPERATION. .IFF ;IF CLOCK IS LINE CLOCK... MOV #-60.,MX.TPI ;INITIALIZE SOFTWARE COUNTER MOV #340,@#102 ;PRI 7 MOV #CLKINT,@#100 ;INT GOES TO HANDLER MOV #105,@#177546 ;SET FIRST INTERRUPT. .ENDC .IFF ;IF RSX VERSIONS... .MCALL MRKT$S,DSAR$S ;SET 1 SECOND MARKTIME UP WITH AST ;1 SEC. IS TO REDUCE SYSTEM OVERHEAD. OTHERWISE A RESCHEDULING IS DONE ;EVERY TICK, WHICH IS NOT QUITE WHAT WE NEED FOR A RESPONSIVE SYSTEM. MOV #1,MX.ARC ;FLAG AST'S DISABLED DSAR$S ;THEN DISABLE THEM MRKT$S ,#1,#2,#CLKINT ;AST ENTRY AT CLKINT. 1 SECOND. .MCALL ASTX$S ;THIS ALLOWS EXIT .ENDC .ENDC .IF DF,$$DOS MOV SP,MX.OSP ; SAVE ORIGINAL STACK POINTER MOV #MX.STK,SP ; SET UP STACK POINTER ; NOW SET UP TRAP VECTOR MOV #MX.TRP,R2 ; NEW PC VALUE MOV #34,R1 ; IV LOC JSR PC,MX.IVS ; AND SET IT MOV #MX.IOT,R2 ; NEW PC FOR IOT MOV #20,R1 ; IV LOC JSR PC,MX.IVS ; AND SAVE IT ; ;RELINK FREE LISTS IN MXTBLS... ;FREE SPACE LIST IS REALLY THE ONLY ONE... MOV #MX.FSL,R0 ;START OF LIST MXFSE=21. MOV #MXFSE,R1 ;NUMBER OF FREE SPACE ELEMENTS ;**** MUST CHANGE NO. ELEMENTS IF MXTBLS CHANGES!!!! MOV R0,R2 ADD #2,R2 ;SET UP FIRST NODE RIGHT AFTER HEADER MOV R2,@R0 ADD #2,R0 ;THEN SKIP LISTHEADER 133$: MOV R0,R2 MXFSZ=20. ;SIZE OF A FREE SPACE LIST ELEMENT (BYTES) ADD #MXFSZ+2,R2 ;POINT AT NEXT ELEMENT MOV R2,@R0 ;SET ELEMENT POINTING AT NEXT MOV R2,R0 ;COPY TO NEXT ELEMENT ADDRESS SOB R1,133$ ;DO ALL ELEMENTS CLR @R0 ;ZERO THE LAST LINK ;NOW TRY TO FREE UP ALL DRIVERS, ETC. IF STANDALONE VERSION RUNNING. .IF DF,SAXCL MOV #MX.LUT,R0 ;LUN TABLE HAS DRIVERS... MOV (R0)+,R1 ;R1 = MAX NO. DRIVERS BIC #-20,R1 ;(NO REAL BIG NUMBERS...) 134$: MOV (R0)+,R2 ;GET DDB ADDRESS OR 0 BEQ 135$ ;IF 0, NO DDB SO NO DRIVER ;GOT A DDB SO FREE IT AND DRIVER CLR @R2 ;FREE THE DDB CLR @-2(R2) ;FREE THE DRIVER TOO... ;THIS DOES WHAT WE CAN DO TO FREE UP THE I/O SYSTEM IN THE STAND-ALONE CASE. ;IT MAY NOT BE ENOUGH, BUT SHOULD WORK MOST OF THE TIME... 135$: DEC R1 BGT 134$ ;DO ALL DRIVERS TILL DONE .ENDC .ENDC BR MX.SCN ; AND START UP A SCAN .MACRO MOVK SRC,DEST .IF DF,SAXCL .IF DIF,SRC,#0 MOV SRC,-(SP) .IFF CLR -(SP) .ENDC MTPI DEST .IFF ;NOTE RSX VERSIONS ARE ONE-SPACE VERSIONS, SO ONLY NORMAL MOV NEEDED. .IF DIF,SRC,#0 MOV SRC,DEST .IFF CLR DEST .ENDC .ENDC .ENDM .GLOBL TKIOT,TKEMT,TKTRP,TKEMT,TKRTRP,TKREMT ; MX.RTI AND MX.ETI ;----- ; THESE ENTRIES PROVIDE SERVICE FOR TWO SPECIAL AND VERY ; IMPROTANT THINGS HAPPENING IN THE COURSE OF EXECUTION. ; THE FIRST IS THE RTI FROM THE FIRST (OF A POSSIBLE NEST) ; OF INTERRUPTS. THE DUMMY RTI ENTRY ON OUR SYSTEM STACK ; GETS US HERE WITH PRI=7. WE THEN LOOK TO SEE IF A SCAN ; SHOULD BE PERFORME. ; IF NOT, WE USE THE TCB POINTER TO RESTORE REGS AND EXIT. ; IF SO, WE GO TO THE SCANNER CONTAINED HEREIN. ; ; THE SECOND IS AN EMT RTI FROM THE FIRST (OF A POSSIBLE NEST) ; EMT ENCOUNTERED.IN THIS CASE, WE UNLOK AND PERFORM RTI ; FROM SAVE EMT INFO. .GLOBL MX.RTI,MX.ETI ;---- MX.RTI ENTRY SEE IF A SCAN SLHOULD BE DONE MX.RTI: ; ENTRY FROM RTI .IF NDF,$$DOS MOVB #340,@#PS .ENDC ; THE FIRST THING WE DO IS SET STACK POINTER TO USER TASK ; IF ANY BECAUSE WE WILL EITHER RTI TO HIM, OR HAVE TO SAVE THE ; REGS. IN ANY CASE, WE NEED SP SET. .IF DF,$$DOS .IF DF,NODOS SAXCL=0 ;EXCLUDE CODE ON STANDALONE IF DEFINED .ENDC .ENDC .IF NDF,SAXCL MOV R0,MXRTI0+2 ; WE NEED A REG MOV MX.TCB,R0 ; FETCH ADR BEQ MXRTI0 ; NONE, FORGET SWITCH MOV TCBDSP(R0),SP ; PRESENT, SWITCH STACK MXRTI0: MOV #0,R0 ; RESTORE REG .ENDC ; NOW WE CAN DO MORE MOVB #-1,MX.IAC ; RESET FLAG TSTB MX.SEV ; SEV (TRY SCAN)? BMI MXRTI ; NO, DO JUNK CMP #-1,MX.LOK ; LOCK SET ? BEQ MX.SAV ; IF NOT LOCKED, ATTEMPT A SCAN ;NOTE: IF RTI IN USER MODE RETURNS BUT DOES NOT LOWER PRIO BACK TO ;PRIORITY 0, THEN WE MUST LOWER IT BY HAND HERE. MXRTI: .IF NDF,$$DOS CLRB @#PS .ENDC ; .IIF DF,SAXCL, BIC #30000,2(SP) ;PREV KNL MODE IN USER MODE RTI ; AND EXIT/ + 0 ; ROOM FOR EMT INSTRUCTION ;--- MX.ETI ENTRY PERFORM A RTI TO USERS CODE MX.ETI: ; ENTRY CLR -(SP) MOVB @#PS,(SP) ; SUMMY PS TO USERS MOVB #340,@#PS ; SAVE A POSSIBLE INTERRUPT MOV MX.EMT,-(SP) ; SET UP PC VALUE MOVB #-1,MX.LOK+1 ; OK, RESET LOCK WORD ; *** NOTE JUGGLING WITH PSW HERE, NOT CONDITIONED BY "$$DOS" .IF NDF,$$DOS CLRB @#PS .ENDC RTI ; AND EXIT TO CALLERS ROUTINES .IF NDF,$$DOS .MACRO ENBL .IF DF,RX.CHK .MCALL ENAR$S ENAR$S .IFF CLRB @#PS .ENDC .ENDM .MACRO DSBL .IF DF,RX.CHK .MCALL DSAR$S DSAR$S .IFF BISB #340,@#PS .ENDC .ENDM .ENDC ; SCANNER LOOP AND ITS ENTRIES .GLOBL MX.SAV,MX.SVE,MX.SCN ; MX.SAV IS ENTRY FOR WHEN NO REGISTERS ARE CURRENTLY ; SAVED ; MX.SVE IS ENTRY FOR WHEN ALL BUT EAE REGS ARE SAVED ;(ADD FPU REGS AS NEEDED...) ; MX.SCN ASSUMES THAT ALL REGS ARE SAVED. ; ; IN ANY CASE, ASSCAN WILL BE DONE FROM BEGINNING ONLY ; IF SEV IS SET. IF NOT, THE TASK TABLE IS SCANNED FROM ; CURRENT SPOT DOWN. ;----- ; ;THE FOLLOWING ASSUMES THAT THE VARIABLE-PRIO OPTION IS NOT SELECTED ;FOR MSX. IT WILL WORK BADLY IF TASKS ARE NOT IN THE SAME ORDER OF ;PRIORITY AS THE TCB ORDER. .IF DF,VARPRI .IF DF,PRLVLS .PRINT ;WARNING *** VARIABLE PRIO AND PRIO LEVEL CODE CONFLICT *** .ENDC .ENDC ; ; NOTE: THE FOLLOWING LOGIC IS USED WHERE THERE ARE TO BE SEVERAL ; PRIORITY LEVELS TO BE CHECKED TOGETHER. THE ASSUMPTION WILL ; BE THAT EACH LEVEL IS A GROUP OF 16 TASKS (SOME OF WHICH MAY ; BE NULL FILLERS) AND THAT A COUNT OF TASKS, INITIALLY ZERO, ; THAT IS REQUESTED AND NOT EXITED IN EACH GROUP IS MAINTAINED. ; THE COUNT IS BUMPED ON STARTUP AND CLEARED ON TERMINATION ; AND SHOULD BE INITIALIZED TO CORRESPOND WITH THE INITIAL ; STATES IN THE STL. THE SETTING HERE WILL ASSUME ONE ; INITIALLY ACTIVE TASK IN THE LAST GROUP DEFINED. THE TABLE ; SHOULD BE MADE AS LONG AS NEEDED TO COVER THE STL. .IF DF,PRLVLS ;ONE ENTRY WILL LOCATE THE VALUE TO PUT IN FOR MX.TCB+2 IF ; A SIG. EVENT HAS OCCURRED AND INSERT IT. ; ;ANOTHER WILL BUMP THE RIGHT COUNT UP ; ;ANOTHER WILL DECREMENT A COUNT. .GLOBL MX.USG BITS: .WORD 100000,40000,20000,10000,4000,2000,1000,400,200,100 .WORD 40,20,10,4,2,1 ;ALL BITS IN WORD ;MX.USG: .WORD 1 ;USAGE COUNT FOR SHORT TABLE ; .WORD 0,0,0,0,0,0,0,0,0 ;SPARES FOR SAFETY .GLOBL MX.LKP,MX.UPU,MX.DNU ; ;MX.LKP LOOK UP USE COUNT OF 1ST NONZERO GROUP AND SET MX.TCB+2 IF ; MX.SEV NOT NEGATIVE ; CALL IS JSR PC,MX.LKP. MX.LKP: TSTB MX.SEV ;SIG EVENT SEEN? BMI 1$ ;NO, SCRAM MOV #<1+</>>,R5 ;NO. GROUPS MOV #MX.USG,R0 ;GET USE TABLE 2$: MOV (R0)+,R4 ;ANY TASKS ACTIVE THERE? BNE 3$ ;YES, STASH SOB R5,2$ ;NO, COUNT DOWN MOV #MX.TBE,R0 ;SET END TABLE IF FAIL BR 5$ 3$: SUB #MX.USG+2,R0 ;GET OFFSET TO ENTRY SEEN ASH #<3+MX.CNT>,R0 ;MAKE OFFSET TO MX.TBL MOV #BITS,R3 ;GET MASK ADDR 6$: BIT (R3)+,R4 ;SEE IF GOT BIT BEQ 6$ ;NO, KEEP TRYING (NONZERO SO MUST WIN!) 7$: SUB #,R3 ;GET INDEX TO BITS SEEN ASH #,R3 ;MAKE OFFSET FROM TABLE ADD R3,R0 ADD #MX.TBL,R0 ;MAKE ADDRESS 5$: 1$: RTS PC ; ; MX.UPU COUNT UP MX.USG ENTRY ; ENTER WITH R2 = TCB ADDR OF TASK BEING STARTED. ALL REGS SAVED. MX.UPU: MOV R2,-(SP) ;LET US MOD R2 SUB #MX.TBL,R2 ;MAKE OFFSET. NOTE TCB IS PWR OF 2 LONG ASH #-,R2 ;DIVIDE TO WORD OFFSET FROM TBL MOV R2,R3 ;COPY WORD INDEX BIC #-40,R3 ;ZOT OUT BITS ASH #-5,R2 ;REMOVE MULTIPLE OF 16 NOW ASL R2 ;BE SURE EVEN VIA EXTRA SHIFT BIS BITS(R3),MX.USG(R2) ;COUNT UP USAGE MOV (SP)+,R2 ;GET BACK OUR TCB RTS PC ; ; MX.DNU COUNT DOWN MX.USG ENTRY ; ENTER WITH R0 = TCB ADDR OF TASK ; MX.DNU: SUB #MX.TBL,R0 ;MAKE OFFSET. NOTE TCB IS PWR OF 2 LONG ASH #-,R0 ;DIVIDE TO WORD OFFSET FROM TBL MOV R0,R3 ;COPY WORD INDEX BIC #-40,R3 ;ZOT OUT BITS ASH #-5,R0 ;REMOVE MULTIPLE OF 16 NOW ASL R0 ;BE SURE EVEN BIC BITS(R3),MX.USG(R0) ;COUNT DOWN USAGE RTS PC .ENDC MX.SAV: ; ENTRY FOR SAVING ALL REGISTERS ; AT THIS POINT, WE MAY HAVE SWITCHED STACKS BACK TO USER OR ; BE RUNNING ON MX.STK. THE WAY WE TELL IS BY LOOKING AT WHETHER ; MX.TCB HAS A POINTER OR IS NULL. IF NULL, WE WERE IN A SCAN ; AND HENCE. DON'T GO THRU THE TROUBLE OF SAVING REGS... TST MX.TCB ; WAS THERE A TASK ? BEQ SCAN ; NO, SKIP AROUND THIS STUFF ; HERE WE SAVE THE USERS REGS AND CLEAN UP ; NOTE THAT SP SHOULD BE SET TO USER STACK .IF NDF,SAXCL JSR R5,S.RSAV ; SAVE THEM .IFF ;STANDALONE JSR PC,U.RSAV ;SAVE REGS AND APR'S (AND USER SP) .ENDC .IIF DF,M$GE,JSR PC,A.PRSV ;SAVE APR 1-6 TOO ;--- ENTRY FOR MX.SVE MX.SVE: ; NOTA BENE !!!!! ; PRIORITY MAY BE SET TO 7 ON ENTRY HERE! MUST BE LOWERED AGAIN FOR RSX ;NOTE -- EAE SAVE/RESTORE SUPPORTED ONLY FOR DOS OR RSX VERSIONS, ;NOT STANDALONE DUAL MODE...!!! .IF DF,EAE MOV @#EAEAC,-(SP) MOV @#EAEMQ,-(SP) MOV @#EAECSR,-(SP) .ENDC MOV MX.TCB,R0 ; GET TCB PTR .IIF NDF,SAXCL, MOV SP,TCBDSP(R0) ; SAVE SP ;--- MERGE PATHFOR SCANNER ENTRIES MX.SCN: CLR MX.TCB ; AND SHOW NO TASK ; NOW MERGE WITH REST OF SHOW SCAN: ; ENTRY FROM ALL OVER (AT PRI7) MOV #MX.STK,SP ; SET TO MY STACK CMP MX.LOK,#-1 ; ARE WE LOCKED ? BNE SCANN ; YES, DON'T DO ANYTHING MOV MX.TCB+2,R0 ; LOOK AT LAST SCAN ENTRY BEQ SCANA ; NOT PRESENT, USE ATL ENTRY ; NOTE THE PARTIAL SCAN LOGIC USED HERE... ; UNLESS A SIGNIFICANT EVENT HAS OCCURRED, WE DO NOT GO BACK TO THE ; START OF THE ATL, BUT SCAN TO THE END FROM WHERE WE ARE (THE ATL ; IS ORDERED BY (FIXED) PRIORITY IN MSX0). SINCE MX.SEV IS ; GLOBALLY AVAILABLE IT IS POSSIBLE TO JUST DO AN INCB MX.SEV PRIOR ; TO A DIRECTIVE TO CAUSE A FULL SCAN. IF MX.ATL IS FILLED IN WITH THE ; ATL ADDRESS OF A TASK, THE SCANNER WILL PRESUME THAT WAS THE ACTIVE ; TASK. HOWEVER, THE STACK SHOULD BE SET TO THAT TASK TO COMPLETE ; THE SWITCH. THE SCANNER DOES THIS AT HIGH PRIORITY TO AVOID HAVING ; THE CONTEXT SETUP SEQUENCE INTERRUPTED. TSTB MX.SEV ; SIGNIFICANT EVENT? BMI SCANX ; NO, LETS USE CURRENT THEN SCANA: MOV MX.ATL,R0 ; START FROM BEGINNING OF TABLE SCANX: .IF DF,PRLVLS JSR PC,MX.LKP ; LOOK UP WHERE WE SHOULD START SCAN .ENDC MOVB #-1,MX.SEV ; SET TO SHOW SCANNING .IIF DF,$$DOS,CLR R5 ; USE R5 FOR PS PTR .IIF NDF,$$DOS,MOV #PS,R5 .IIF DF,$$DOS,CLR -(R5) ; RESET INTERRUPTS .IF NDF,$$DOS CLRB (R5) .ENDC ; FROM HERE ON, INTERRUPTS ARE POSSIBLE. .IF NDF,$$DOS .MCALL ENAR$S ;ALLOW AST'S FOR RSX VERSION AT THIS POINT... TST MX.ARC ;AST INHIBITING NOW? BEQ SCANLP ;NO, SKIP IT CLR MX.ARC ;YES, FLAG ASTS ALLOWED ENAR$S ;AND ALLOW THEM .ENDC SCANLP: ; SCAN LOOP STARTS HERE TST (R0) ; LASTE ENTRY ? .GLOBL MX.RNS ; RUN STATE PROCESSING BEQ WAIT ; YES, PERFORM WAIT ;;; .GLOBL SCNVCT ;FOR DIRECT ENTRY TO TASK BY PRIQ REQUEST SCNVCT: MOVB TCBST(R0),R1 ; MOVE STATE TO R1 ;NOTE: 200 BIT IS THE DISABLE BIT. IF SET, THE CODE WILL BE ; NEGATIVE. ALSO WE HAVE TO CHECK CPU NUMBER IF THIS IS A MULTI- ; CPU SYSTEM. BLE SCNEXT ; LOOK AT NEXT ONE .IF DF,M.MMP CMPB MX.CPU,TCBCPU(R0) ;THIS CPU THE SAME AS THE ONE RUNNING? BNE SCNEXT ;NO, SKIP TASK. (MESSAGE HANDLER WILL TAKE CARE ;OF SETTING STARTED/EXITED STATES AND NO ;OTHERS MATTER IF IN ANOTHER CPU. .ENDC ASL R1 ; CONVERT TO WORD INDEX BIC #-40,R1 ; BE SURE STATE IS LEGAL IN RANGE (SHOULD BE ; PERMANENTLY SAFE, BUT DOUBLE CHECK HERE) JMP @MX.XVC(R1) ; TRANSFER VECTOR MX.XVC: .WORD SCNEXT ;STATE 0 - EXITED .WORD STATE1 ;STATE 1 - SUSPENDED .WORD STATE2 ;STATE 2 - WAITING FOR EV (IN TASK SPACE) .WORD STATE3 ;STATE 3 - ORWAITING .WORD STATE4 ;STATE 4 - RUNNING (OR INTERRUPTED...) .WORD STATE5 ;STATE 5 - WAITING FOR SIG EVENT .WORD STATE6 ;STATE 6 - WAITING FOR EV IN KERNEL SPACE .WORD STATE2 ;STATE 7 - PWAITING (MERGED WITH STATE 2) .WORD STAT10 ;STATE 10- ABORT QUEUED FOR TASK .WORD STAT11 ;STATE 11- MESSAGE-IN AST QUEUED (OR MESSAGE RCV) .WORD STAT12 ;STATE 12- EXIT OF SPAWNED TASK (W/STATUS) .WORD STAT13 ;STATE 13- PWAIT ON KERNEL EVENT VRBL (FOR TIMER) .WORD STAT14 ;STATE 14- ORWAIT UNTIL ANY EV BECOMES > 0 ;NOTE: STATE 15 IS FOR GENERAL WAITS WHERE AN EVENT VARIABLE IS TO BE SET DUE ;TO THE ACTION OF ANOTHER TASK. THE WAIT IDENTIFIES THE OTHER TASK AND IS ;GUARANTEED TO FALL THROUGH IF THE OTHER TASK EXITS. SHOULD THAT HAPPEN, THE ;EVENT VARIABLE WILL NOT BE TOUCHED AND MAY BE TESTED TO DETERMINE THE FALL- ;THROUGH OCCURRED DUE TO TASK EXIT. THE SYSTEM CAN THEN AVOID DEADLOCKS. THIS ;FORM OF WAIT USES A TABLE OF INFORMATION IN TASK ADDRESS SPACE FOR ITS ;OPERATION AND PERMITS TYPES OF WAITING NOT PERMITTED BY OTHER DIRECTIVES. ;THE TABLE HAS THE FORMAT: ; TABLE: .WORD EV_ADDRESS ; .WORD TASKNAME (OR TASK NUMBER) ; .WORD MASK (USED TO MASK THE PART OF THE EV TO TEST) ; .WORD CONDITION (DETERMINES TYPE OF WAIT. ; COND=0 = NORMAL WAIT FOR NONZERO EV ; COND=-1= WAIT UNTIL EV < 0 ; COND=+1= WAIT UNTIL EV > 0 ; COND=OTHER MEANS WAIT UNTIL EV IS = 0. ; .WORD STAT15 ;STATE 15- WAIT UNTIL EV. IS SET OR TASK EXITS .WORD SCNEXT ;FILL IN STATE UP TO 16. (=20 OCTAL) .WORD SCNEXT ;FILL IN STATE UP TO 16. (=20 OCTAL) .WORD SCNEXT ;FILL IN STATE UP TO 16. (=20 OCTAL) .WORD SCNEXT ;FILL IN STATE UP TO 16. (=20 OCTAL) ;------- ; WAIT SYSTEM (MSX0) WAIT LOOP .IF DF,$$DOS WAIT: CLRB @#PS ;ENSURE INTS OK WAIT ; THIS IS IT .IFF WAIT: CLRB @#PS ;ENSURE INTS OK WSIG$S ;SUSPEND US UNTIL INTERRUPT TURNS TASK ON AGAIN .ENDC BR SCAN ; AND KEEP WAINTG .GLOBL MX.TBS ;SIZE OF AN STL ENTRY SCNEXT: CLR MX.TCB ;BE SURE TCB MARKED EMPTY, THEN... CLRB @#PS ;BE SURE PRIO 0 HERE .IF NDF,VARPRI ADD #MX.TBS,R0 ; POINT TO NEXT ONE IN LINE BR SCANLP ; AND LOOP .IFF CMP R0,#KNLTCB ;SPECIAL DUMMY TCB? BNE 1$ ;NO ADD #MX.TBS,R0 ;YES, JUST BUMP R0 BR SCANLP ;AND GO 1$: ;HERE WE HAVE TO FIND THE NEXT TASK WHERE SCAN IS NORMAL. NOTE ;THAT FIRST TASK BY CONVENTION IS NOT ALTERABLE (IT IS ALWAYS FIRST). ;THE TABLE MX.PRL IS ORDERED LIKE THE STL SO FIND IT AND INDEX ALONG ;IT TO LOCATE THE NEXT TCB... SUB #MX.TBL,R0 ;FORM MX.TBL OFFSET ASH #<3-MX.CNT>,R0 ;MAKE OFFSET FROM MX.PRL ADD #MX.PRL,R0 ;POINT AT IT MOV (R0),R0 ;POINT AT NEXT ENTRY NOW MOV 4(R0),R0 ;AND POINT TO TCB VIA POINTER THERE. JMP SCANLP ; AND LOOP .ENDC ; HERE WE HAVE ENCOUNTERED LOCK, SET FOR THIS CURRENT USER SCANN: CLR R2 ; SET FOR NON-WAIIT MOV MX.TCB+2,R0 ; POINT TO LAST ONE BNE SETUP ; AND OUT IF THERE IS ONE ; NOTE: THERE IS A LOGICAL ERROR IF NO TASK WAS RUNNING BUT ; WE ARE LOCKED. HALT AND ALLOW RESET OF LOCK . ; .IIF DF,$$DOS,HALT ;(HALTING SEEMS LIKE A BAD IDEA...JUST RECOVER) MOV #-1,MX.LOK BR SCANA ; ACTUAL SCANNER ACTION PROCESSORS. CONTROL RECEIVED BY ; TRANSFER VECTOR JUMP. ; STATE1 SUSPENDED, LOOP OVER TO NEXT ENTRY STATE1: BR SCNEXT ; OFF TO NEXT ONE ; STATE2 WAITING FOR EVENT VARIABLE ; STATE7 WAITING FOR EVENT VARIABLE 0 OR POSITIVE ;STATE7: STATE2: ; HERE MUST SET UP MAPPING TO THE TASK POINTED AT TO ALLOW ;READY CHECK. THIS CAN BE EXPECTED TO BE RATHER SLOW BUT CANNOT ;REALLY BE HELPED... .IF DF,SAXCL ; IN DUAL MODE SYSTEMS WE NEED TO REMAP ALWAYS...WE ARE DEALING WITH ; USER SPACE, NOT SAME AS MSX IN THOSE CASES. TOO BAD. JSR PC,U.LDR MFPI @TCBEVA(R0) ; MOVE TO WORD REG MOV (SP)+,R2 ; GET FROM OLD SPACE CMPB #7,TCBST(R0) ;THIS STATE 7 (PWAIT) OR JUST WAIT? BEQ 10$ ;JUST WAIT TST R2 BEQ SCNEXT ;SINCE WAIT DO THE TEST BR 11$ ;THEN SKIP PWAIT LOGIC 10$: TST R2 ;IF PWAIT DO THE TEST ALSO BMI SCNEXT ;AND SKIP IF NEGATIVE BUT GO ON IF 0 OR + 11$: .IFF .IF DF,M$GE ; CHECK FOR APR 0 SINCE REMAPPING TAKES PRECIOUS TIME AND SHOULD BE ; DONE ONLY IF NECESSARY. CMP TCBEVA(R2),#20000 ;MAPPED BY APR 0 (ALWAYS THERE...)? BLO 1$ ;YES, DON'T NEED TO REMAP JSR PC,U.ALD ;NO, MUST MAP AGAIN TO LOOK AT EV 1$: .ENDC MOV @TCBEVA(R0),R2 CMPB #7,TCBST(R0) ;THIS A PWAIT OR A WAIT? BEQ 10$ ;WAIT ONLY TST R2 ;CHECK EV VALUE BEQ SCNEXT ;UNSATISIFED... LOSE BR 11$ ;SKIP PWAIT LOGIC 10$: TST R2 ;ON PWAIT THE PROGRAM CONTINUES IF EV IS 0 OR + BMI SCNEXT ;TEST FAILS IF EV IS NEGATIVE 11$: .ENDC ; WAIT IS SATISFIED HERE WATDUN: .IF DF,$$DOS .IF NDF,NODOS MOVB #340,(R5) ; INHIBIT INTERRUPTS HERE .IFF MOV #30340,(R5) ;SET PRI7 PREV USER MODE FOR TSK START .ENDC .IFF ; .IF DF,RX.CHK MOVB #340,@R5 ; DSBL ;PREVENT INTERRUPTIONS... ; .ENDC .ENDC BR SETUP ; AND MERGE ; STATE3 ORWAITING ; STATE14 ORWAITING FOR EVENT VARIIABLE GREATER THAN 0 STATE3: STAT14: MOV TCBEVA(R0),R1 ; MOVE TO INDEX REG BEQ SCNEXT ; IF NULL, SKIP THIS ;ADDRESS CHECK AN ARGUMENT. SETS THE ARG ODD IF INVALID FOR THE CURRENT ;TASK. (INITIALLY NOOPPED...) .MACRO ADRCHK ARG .IF DF,CK.AD. MOV ARG,-(SP) JSR PC,CK.MAP ;SET (SP) ODD IF ILLEGAL MOV (SP)+,ARG .ENDC .ENDM .IF NDF,SAXCL .IIF DF,M$GE, JSR PC,U.ALD ;MAP TASK TO LOOK AT EV LIST ORLOOP: TST (R1) ; IS THIS LAST ONE ? BEQ SCNEXT ; YES, SKIP OUT ADRCHK (R1) ;RANGE CHECK THE ADDRESS BIT #1,(R1) ;IS IT ODD? BNE SCNEXT ;IF SO, DONE TESTS. MOV @(R1)+,R2 ; MOVE VALUE FOR LATER CMPB TCBST(R0),#3 ;NORMAL ORWAIT? BEQ 5$ ;YES, TEST R2 AND ACT... TST R2 ;NO. CHECK IF EV IS GREATER THAN 0 BGT WATDUN BR ORLOOP ;IF LESS THAN OR EQUAL 0, KEEP LOOKING 5$: TST R2 BNE WATDUN ; YES, START UP BR ORLOOP ; IF NOT, LOOK FOR MORE .IFF JSR PC,U.LDR ;SET UP TASK'S USER SPACE ORLOOP: MFPI (R1) .IIF DF,CK.AD., JSR PC,CK.MAP BIT #1,(SP) ;SEE IF ARG LOOKS VALID BEQ 1$ ;IF SO, GO ON CLR @SP ;IF NOT, MAKE IT THE END OF SCAN 1$: TST (SP)+ ; SEE IF THIS IS THE LAST ONE BEQ SCNEXT ; YES, SKIP OUT MFPI @(R1)+ ; GET NEXT VALUE OUT FOR LATER MOV (SP)+,R2 ; GRAB VALUE CMPB TCBST(R0),#3 ;NORMAL ORWAIT? BEQ 5$ ;YES, TEST R2 AND ACT... TST R2 ;NO. CHECK IF EV IS GREATER THAN 0 BGT WATDUN BR ORLOOP ;IF LESS THAN OR EQUAL 0, KEEP LOOKING 5$: TST R2 BNE WATDUN ; IF OK, ALL SET BR ORLOOP .ENDC ; STATE4 READY, START IT UP MX.RNS: STATE4: .IF DF,$$DOS .IF NDF,NODOS MOV #340,(R5) .IFF MOV #34340,(R5) ;SET PREV USER FOR U.RRES .ENDC .ENDC .IF NDF,$$DOS MOVB #340,@R5 ; DSBL ;NO INTERRUPTS PLEASE .ENDC CLR R2 ; SET UP FOR NON-WAIT SETUP: ; COMMON POINT FOR WAITS/READY MOV R0,MX.TCB ; SAVE THIS TCB ADDRESS MOV R0,MX.TCB+2 ; SAVE FOR LATER MOVB #4,TCBST(R0) ; SET UP TO SHOW READY CMP R0,MX.HGH ; IS THIS TASK HIGHER PRIO THAN MAX ONE? BHI 15$ ; IF NOT (LATER IN TBL) NO ACTION MOV R0,MX.HGH ; IF SO, SAVE PRIO OF MAX 15$: .IF NDF,SAXCL ; **NON STANDALONE TST TCBDSP(R0) ;SEE IF THERE IS A DYNAMIC STACK BEQ NEWONE ;IF NOT, MAKE ONE AT INITIAL SP MOV TCBDSP(R0),SP ; SET STACK POINTER BEQ NEWONE ; IF NOT SET, MUST BE NEW .IFDF EAE ; RESTORE EAE REGS HERE MOV (SP)+,@#EAECSR ; IN PROPER ORDER MOV (SP)+,@#EAEMQ MOV (SP)+,@#EAEAC .ENDC ; NOW CHECK IF WE ARE TO SET UP PS BITS .IF DF,PSSET ; IF THIS CODE IS INCLUDED, RETURNS AFTER WAIT SET COND CODES ; ACCORDING TO EV VALUE. OMIT FOR SPEED... TST R2 ; IF NON-ZERO, WAS FROM WAIT BEQ POPSTK ; NO, MERGE ; SET UP PSW CONDITION CODES WITH RESULT OF EVA MOV @#PS,R1 ; GET OUR CODES BIC #177760,R1 ; MASK COND CODES MOV 16+A$PROF(SP),R2 ; GET HIS PSW BIC #177437,R2 ; MASK STATUS BIS R1,R2 ; ORIN THE CODES MOVB R2,16+A$PROF(SP) ; AND STASH IT .ENDC ;------- ; THIS IS THE POINT OF DEPARTURE FOR MSX0. ; WE RESTORE REGS AND POP ANY WORDS OFF STACK ; ACCORDING TO VALUE IN UPPER BYTE OF WAHT WAS ; STATUS REG AT TIME OF RTI. POPSTK: ; COMMON FOR POP OF USER STACK PARAMS MOVB 17+A$PROF(SP),STKFIX ; MOVE TO ADDER BEQ RESTOR ; NO OTHER NONSENSE ; HERE WE MOVE UP THE RTI INFO TO PROPER STACK LOC MOV STKFIX,R1 ; MOVE VALUE MOV SP,R2 ; NOW CURRENT FALUE ADD R2,R1 ; ADD IN NEW OFFSET ADD #16+A$PROF,R1 ; ADJUST VALUE ADD #16+A$PROF,R2 CLR (R1) ; CLEAR WHOLE STATUS MOVB (R2),(R1) ; MOVE ONLY ONE BYTE MOV -(R2),-(R1) ; AND PC VAUE RESTOR: .IIF DF,M$GE,JSR PC,A.PRRS ;RESTORE APR 6-1 ; HERE WE RESTORE REGS AND EXIT JSR R5,S.RRES ; RESTORE USERS REGS ADD STKFIX,SP ; ADD IN OFFEET VALUE BR NEW.RT ;START UP VIA RTI ; RTI ; AND OFF TO USER CODE ;------- ; NEWONE ; WE HAVE A NEW TASK, STE UP FOR SA NEWONE: MOV TCBISP(R0),SP ; SET UP INITIAL MOV #MX.XIT,(SP) ; SET UP FOR RETURN TO XIT MOV TCBISP(R0),TCBDSP(R0) ;FLAG ACTIVE ALSO UNIFORMLY CLR -(SP) ; RUNNING ON PRIORITY 0 MOV TCBSA(R0),-(SP) ; SET UP DUMMY RTI .IF DF,M$GE ; WE ALWAYS GET HERE FOR NEW TASKS...GET ALL APRS IF WANTED .IF NDF,AL$APR ;IF ONLY 1 APR AT START IS GUARANTEED MOV TCBAP1(R0),R1 ;NEW APR 1 (REL. TO BASE) MOV #2,R0 ;MAP APR 1 .GLOBL MAPOF2 JSR PC,MAPOF2 ;MAP APR 1 FOR US AND RSX. .IFF MOV #UPAR1,R2 ;POINTER FIRST PAR TO LOAD MOV TCBAP1(R0),R1 ;GET TBL OF VALUES MOV #6,R3 ;NUMBER OF THEM TO DO CLR R4 ;SET APR 0 FIRST 1$: MOV (R1)+,R5 ;GET AN APR ADD #2,R4 ;POINT AT NEXT APR (RSX USES 1 TO 6) JSR R5,S.RSAV ;(NEED ALL REGS) MOV R5,R1 ;NEW APR CONTENTS MOV R4,R0 ;AND APR INDEX ;USE MAP ROUTINE FOR ALL OPS TO KEEP RSX HAPPY AND ALLOW STANDARD OPERATIONS. JSR PC,MAPCMN ;SET UP APR FOR US AND RSX JSR R5,S.RRES ;RESTORE REGS WE SAVED NEXT SOB R3,1$ ;DO ALL .ENDC .ENDC ;(REG STATE INITIALLY FOR TSK NOT IMPORTANT) .IF DF,M.MMP ;MULTI-CPU SYSTEM ; SET UP CPU NUMBER IN TCB AND CLEAR OLD STATUS WORD (EV ADDR FOR MSG) MOV #1,TCBSTT(R0) ;SET THE STATUS TO OK INITIALLY. BICB #^C2,TCBPR(R0) ;ZERO EXTRA BYTE STATUS FLAGS TOO IF LEFT OVER MOVB MX.CPU,TCBCPU(R0) ;SET EXECUTING IN THIS CPU (ACTIV8 MAY MOD) MOVB MX.BUS,TCBBUS(R0) ;SET THIS CPU'S BUS (ONE OF THEM AT LEAST) ;ALLOCATE MEMORY INSIDE ACTIV8 SEQUENCE IF MSX IS DOING SO, ONCE ACTIV8 ;DECIDES THAT THIS CPU IS TO BE USED. IF MEMORY ALLOCATING IS DONE, MARK TASK ;WAITING FOR KERNEL EVENT VARIABLE IN TCB SOMEWHERE, THEN GENERATE A REQUEST ;TO A LOADER TASK (VIA A MESSAGE) TO LOAD THE TASK CODE UP AND BUMP THE ;VARIABLE WHEN DONE. THIS MEANS THAT IF ACTIV8 RETURNS WITH THE TASK STATE ;SET TO 6 (AWAIT EV IN KNL SPACE), DO NOT JUMP INTO THE TASK... .IIF DF,DY$MEM, LDR$=0 .IF NDF,LDR$ ;IF NO LOADABLE TASKS, TEST HERE ;IF TASKS MAY BE LOADED BY ACTIV8 ARBITRATION, ACTIV8 MUST NOT ;SEND A MESSAGE BUT MUST DO CORE ALLOCATION THINGS. BITB #2,TCBPR(R0) ;SEE IF THIS IS AN EXTERNAL REQUEST BNE 44$ ;IF SO, NO ACTIV8 CALL .ENDC JSR PC,ACTIV8 ;SEND MSG TO ALL TASKS AND ARBITRATE PRIO ;NOTE: ACTIV8 MAY ALTER THE CPU NUMBER AND/OR STATE DEPENDING ;ON ITS PRIORITY ARBITRATION. IT ASSUMES R0 POINTS TO THE ;TCB ENTRY OF THE TASK TO BE ACTIVATED AND THAT THE STATE ;AND CPU FIELDS ARE INITIALIZED. IT ALSO EMITS MESSAGES ;TO ALL CPUS IF A BUS SYSTEM IS PRESENT, AND RETURNS ONLY ;AFTER ARBITRATION IS DONE. IF THE TASK IS NOT ACTIVATED, ;THE C BIT WILL BE SET AND CONDITIONS ESTABLISHED FOR ;THE TASK TO RUN ELSEWHERE. BCC 44$ ;SKIP AROUND JUMP IF ALL IS OK ;ACTIV8 MOVED THE TASK TO ANOTHER CPU, SO WE MUST NOT ACTIVATE IT FURTHER ;HERE. SKIP BACK TO SCAN (SCNEXT) 47$: CLR -(SP) MOVB TCBCPU(R0),(SP) ;GET CPU WHERE TASK IS TO GO DEC @SP ASL @SP ADD #CPU.PR,@SP INC @(SP)+ ;COUNT TASK UP 49$: BICB #2,TCBPR(R0) ;SAY NOT EXTERNALLY REQUESTED ANY MORE .IIF DF,CMNTCB,JSR PC,TCBFRE JMP SCNEXT 44$: BICB #2,TCBPR(R0) ;SAY NOT EXTERNALLY REQUESTED ANY MORE ;IF "REL$SP" IS DEFINED, PERMIT STACKS TO BE DYNAMICALLY ALLOCATED ;AND THE TASK POINTED TO THE DYNAMIC STACK. IT WILL BE CLEARED AT ;TASK EXIT. NOTE THE ISP MUST POINT TO A FEW WORDS TO USE FOR ;SAVING RESUME ADDRESSES, AND THE WORD ABOVE THE INITIAL SP WILL ;BE USED FOR THE POINTER TO THE DYNAMICALLY ALLOCATED STACK TO ;PERMIT ITS DEALLOCATION. THE CORE ALLOCATION FOR THE TASK MAY BE ;DONE IN SPRELO ALSO IF DESIRED. .IIF DF,REL$SP, JSR PC,SPRELO ;RELOCATE STACK ON NEW RUN .IF DF,DY$MEM JSR PC,MEMLNK ;FIND MEMORY FOR THE TASK CMPB #10,TCBST(R0) ;DID IT FAIL? (ABORT SET UP) BEQ 49$ ;YES, BEST FORGET IT. .ENDC .IIF DF,CMNTCB,JSR PC,TCBFRE MOVB MX.CPU,-(SP) CLRB 1(SP) ;LEAVE ONLY 1 BYTE OF CPU NUMBER DEC @SP ASL @SP ;GET CPU NUMBER ADD #CPU.PR,@SP ;FORM ADDRESS OF CPU INC @(SP)+ ;COUNT UP TASKS ACTIVE ON THIS CPU MOV TCBSPW(R0),R1 ;GET SPAWN TBL TO CLEAR SPAWNED TASKS LIST MOV #15.,R2 ;MAX SPAWNED TASKS IN TBL TST (R1)+ ;PASS CALLER TASK CELL 15$: CLR (R1)+ ;REMOVE ALL CALLED TASKS IN CASE LEFT OVER SOB R2,15$ ;DO ALL CELLS ;BE SURE NOT WAITING FOR LOAD... CMPB #206,TCBST(R0) ;WAIT ON KNL EV? (DISABLED...) BEQ 47$ ;YES, MUST IGNORE FOR NOW... BITB #200,TCBST(R0) ;DISABLED? BNE 47$ ;YES, MUST IGNORE FOR NOW... .ENDC NEW.RT: .IIF DF,CMNTCB,JSR PC,TCBFRE .IF NDF,$$DOS ENBL ;ALLOW INTERRUPTS. (MUST DO EXPLICITLY...) .ENDC RTI ; AND DO IMMEDIATE RTI STKFIX: .WORD 0 ;AMOUNT TO ADD TO STACK ON RETURN .IFF ; ** STAND ALONE VERSION SACM: TST TCBDSP(R0) ;ANY DYNAMIC STACK? BNE CMNGO ;MERGE WITH COMMON TASK STARTUP NEWONE: MOV TCBISP(R0),TCBDSP(R0) ;SET UP START SP MOV TCBSA(R0),TCBDPC(R0) ;SET UP START ADDRESS TCBDPC=54 ;OFFSET OF SAVED PC IN TCB. (PS SAVED AT 56) .IF NDF,AL$APR ;IF ONLY 1 APR GUARANTEED MOV TCBAP1(R0),TCBREG+14(R0) ;SET INITIAL APR 0 AS IN START WORD .IFF MOV TCBAP1(R0),R1 ;GET APR TBL IF RESTORING ALL MOV #TCBREG+14,R2 ;GET OFFSET TO REGS ADD R0,R2 ;MAKE ADDRESS SO R2 IS NOW TCB APR AREA MOV #8.,R3 ;8 APRS IN ALL 1$: MOV (R1)+,(R2)+ ;COPY ALL IN SOB R3,1$ .ENDC .IF DF,M.MMP ;MULTI-CPU SYSTEM ; SET UP CPU NUMBER IN TCB AND CLEAR OLD STATUS WORD (EV ADDR FOR MSG) MOV #1,TCBSTT(R0) ;SET THE STATUS TO OK INITIALLY. BICB #^C2,TCBPR(R0) ;ZERO EXTRA BYTE STATUS FLAGS TOO IF LEFT OVER MOVB MX.CPU,TCBCPU(R0) ;SET EXECUTING IN THIS CPU (ACTIV8 MAY MOD) MOVB MX.BUS,TCBBUS(R0) ;SET THIS CPU'S BUS (ONE OF THEM AT LEAST) ;ALLOCATE MEMORY INSIDE ACTIV8 SEQUENCE IF MSX IS DOING SO, ONCE ACTIV8 ;DECIDES THAT THIS CPU IS TO BE USED. IF MEMORY ALLOCATING IS DONE, MARK TASK ;WAITING FOR KERNEL EVENT VARIABLE IN TCB SOMEWHERE, THEN GENERATE A REQUEST ;TO A LOADER TASK (VIA A MESSAGE) TO LOAD THE TASK CODE UP AND BUMP THE ;VARIABLE WHEN DONE. THIS MEANS THAT IF ACTIV8 RETURNS WITH THE TASK STATE ;SET TO 6 (AWAIT EV IN KNL SPACE), DO NOT JUMP INTO THE TASK... .IF NDF,LDR$ ;IF NO LOADABLE TASKS, TEST HERE ;IF TASKS MAY BE LOADED BY ACTIV8 ARBITRATION, ACTIV8 MUST NOT ;SEND A MESSAGE BUT MUST DO CORE ALLOCATION THINGS. BITB #2,TCBPR(R0) ;SEE IF THIS IS AN EXTERNAL REQUEST BNE 44$ ;IF SO, NO ACTIV8 CALL .ENDC JSR PC,ACTIV8 ;SEND MSG TO ALL TASKS AND ARBITRATE PRIO ;NOTE: ACTIV8 MAY ALTER THE CPU NUMBER AND/OR STATE DEPENDING ;ON ITS PRIORITY ARBITRATION. IT ASSUMES R0 POINTS TO THE ;TCB ENTRY OF THE TASK TO BE ACTIVATED AND THAT THE STATE ;AND CPU FIELDS ARE INITIALIZED. IT ALSO EMITS MESSAGES ;TO ALL CPUS IF A BUS SYSTEM IS PRESENT, AND RETURNS ONLY ;AFTER ARBITRATION IS DONE. IF THE TASK IS NOT ACTIVATED, ;THE C BIT WILL BE SET AND CONDITIONS ESTABLISHED FOR ;THE TASK TO RUN ELSEWHERE. BCC 44$ ;SKIP AROUND JUMP IF ALL IS OK ;ACTIV8 MOVED THE TASK TO ANOTHER CPU, SO WE MUST NOT ACTIVATE IT FURTHER ;HERE. SKIP BACK TO SCAN (SCNEXT) 47$: CLR -(SP) MOVB TCBCPU(R0),(SP) ;GET CPU WHERE TASK IS TO GO DEC @SP ASL @SP ADD #CPU.PR,@SP INC @(SP)+ ;COUNT TASK UP 49$: BICB #2,TCBPR(R0) ;SAY NOT EXTERNAL REQUEST ANY MORE .IIF DF,CMNTCB,JSR PC,TCBFRE JMP SCNEXT 44$: BICB #2,TCBPR(R0) ;SAY NOT EXTERNAL REQUEST ANY MORE ;IF "REL$SP" IS DEFINED, PERMIT STACKS TO BE DYNAMICALLY ALLOCATED ;AND THE TASK POINTED TO THE DYNAMIC STACK. IT WILL BE CLEARED AT ;TASK EXIT. NOTE THE ISP MUST POINT TO A FEW WORDS TO USE FOR ;SAVING RESUME ADDRESSES, AND THE WORD ABOVE THE INITIAL SP WILL ;BE USED FOR THE POINTER TO THE DYNAMICALLY ALLOCATED STACK TO ;PERMIT ITS DEALLOCATION. THE CORE ALLOCATION FOR THE TASK MAY BE ;DONE IN SPRELO ALSO IF DESIRED. .IIF DF,REL$SP, JSR PC,SPRELO ;RELOCATE STACK ON NEW RUN .IF DF,DY$MEM JSR PC,MEMLNK ;FIND MEMORY FOR THE TASK CMPB #10,TCBST(R0) ;DID IT FAIL? (ABORT SET UP) BEQ 49$ ;YES, BEST FORGET IT. .ENDC .IIF DF,CMNTCB,JSR PC,TCBFRE MOVB MX.CPU,-(SP) CLRB 1(SP) ;LEAVE ONLY 1 BYTE OF CPU NUMBER DEC @SP ASL @SP ;GET CPU NUMBER ADD #CPU.PR,@SP ;FORM ADDRESS OF CPU INC @(SP)+ ;COUNT UP TASKS ACTIVE ON THIS CPU MOV TCBSPW(R0),R1 ;GET SPAWN TBL TO CLEAR SPAWNED TASKS LIST MOV #15.,R2 ;MAX SPAWNED TASKS IN TBL TST (R1)+ ;PASS CALLER TASK CELL 15$: CLR (R1)+ ;REMOVE ALL CALLED TASKS IN CASE LEFT OVER SOB R2,15$ ;DO ALL CELLS CMPB #6,TCBST(R0) ;DID WE RETURN WAITING ON KNL EV (LOADING TSK) BEQ 47$ ;IF SO,JUMP TO NEXT TASK... BITB #200,TCBST(R0) ;DISABLED? BNE 47$ ;YES, MUST IGNORE FOR NOW... .ENDC ;NOW COMMON TASK STARTUP VIA APR AND REG RESTORE CMNGO: .IF DF,M.MMP ;MULTI-CPU SYSTEM ;BE DOUBLY SURE THAT NO TASK STARTS IF ON WRONG CPU NOW. ;THIS IS NEESED IN CASE SOMEONE JUMPS HERE FROM ELSEWHERE. FALLTHROUGH ;IS ALREADY PROTECTED. .IIF DF,CMNTCB, JSR PC,TCBGET ;ALLOCATE THE TCB TST TCBDSP(R0) ;IS TASK RUNNING? BEQ 5$ ;NO, LOOKS OK TO START HERE CMPB MX.CPU,TCBCPU(R0) ;IF RUNNING, IS IT ON OUR CPU? BEQ 5$ ;YES, OK TO ACTIVATE THIS WAY ;TASK IS RUNNING SOMEWHERE ELSE...CANNOT JUMP INTO IT. GO DO A SCAN. .IIF DF,CMNTCB,JSR PC,TCBFRE JMP MX.SCN ;OUGHT TO DO IT... 5$: .ENDC .IIF DF,CMNTCB,JSR PC,TCBFRE JSR PC,U.RRES ;GET BACK OUR APR'S PMODE=60 ;PREVIOUS USER MODE BITS. SET 0 FOR PREV KNL MODE IN TASKS. MOVB #300+PMODE,3(SP) ;SET UP USER MODE, PREVIOUS KERNEL MODE RTI ;GO TO IT, GUY! .ENDC ;SAXCL ; ; MX.RQU ;REQUEST TASK DIRECTLY (AS FROM INTERRUPT) ; ; MX.RQU IS PROVIDED AS A GLOBAL ENTRY TO ALLOW FAST CALLS ; OF A MSX0 TASK, E.G. ON INTERRUPTS. ; IT PRESUMES R0 IS SET TO POINT TO THE TCB ENTRY OF THE ; DESIRED TASK ON CALL AND THAT A FAKE PSW IS PUSHED ONTO ; THE STACK. THE CALL, THEN, FOR TASK NUMBER "N" WOULD BE ; (IN MACRO): ; ; MOV #>,R0 ;POINT R0 AT TCB ENTRY ; CLR -(SP) ;MAKE FAKE PSW (APPEAR TO BE INT.) ; JSR PC,MX.RQU ;CALL THE REQUEST ROUTINE ; (RETURNS HERE...) .GLOBL MX.RQU .IF NDF,SAXCL .GLOBL RQ.R0 RQ.R0: .WORD 0 ;SAVE AREA (AT PRI7) FOR R0 ACROSS A.PRSV CALL .ENDC .IF NDF,$$DOS ;MX.RQQ ... ENTRY FOR QRUN AFTER AST. .GLOBL MX.RQQ MX.RQQ: .IIF NDF,$$DOS, MOVB #340,@#PS ;PRIO 7 .IF DF,M$GE JSR R5,S.RSAV ;SAVE THE REGISTERS ON CALL BR RQ.DOO ;SAVE APR'S AND LOAD DESIRED "R0" .ENDC .ENDC ; MX.RQU: ; .IIF DF,$$DOS, MOV #30340,@#PS ;PRI 7 PREV USER .IIF NDF,$$DOS, MOVB #340,@#PS ;PRIO 7 .IF NDF,SAXCL MOV R5,-(SP) ;SAVE REGS FOR OLD TASK MOV R4,-(SP) MOV R3,-(SP) MOV R2,-(SP) MOV R1,-(SP) MOV R0,-(SP) .IF NDF,SAXCL MOV R0,RQ.R0 ; A.PRSV BASHES R0 -- HAVE TO SAVE ACROSS CALL... .IIF NDF,$$DOS, .GLOBL RQ.DOO,RQ.R0 RQ.DOO: .IIF DF,M$GE, JSR PC,A.PRSV ;SAVE APR'S IF DOING MEM MGMT. MOV RQ.R0,R0 ;GET BACK BASHED R0 .ENDC MOV MX.TCB,R1 ;GET CURRENT TASK TCB BEQ 1$ ;IF NONE IGNORE SP SAVE MOV SP,TCBDSP(R1) ;BUT IF ONE IS THERE SAVE SP VALUE 1$: MOV R0,MX.TCB ;POINT SCAN AT NEW TASK BUT LEAVE OLD SCAN ;POSITION ALONE (MX.TCB+2) .IIF DF,CMNTCB, JSR PC,TCBGET ;ALLOCATE THE TCB .IF DF,M.MMP ;MULTI-CPU SYSTEM TST TCBDSP(R0) ;IS TASK RUNNING? BEQ 5$ ;NO, OK TO ACTIVATE HERE CMPB MX.CPU,TCBCPU(R0) ;IF RUNNING, IS IT ON OUR CPU? BEQ 5$ ;YES, OK TO ACTIVATE THIS WAY ;TASK IS RUNNING SOMEWHERE ELSE...CANNOT JUMP INTO IT. GO DO A SCAN. .IIF DF,CMNTCB, JSR PC,TCBFRE ;FREE THE TCB AGAIN JMP MX.SCN ;OUGHT TO DO IT... 5$: .ENDC ;MX.RQS IS AN INTERNAL ENTRY POINT FOR STARTING A TASK IN MSX. ; IT PRESUMES THE EXISTING TASK CONTEXT HAS BEEN SAVED ; AND THAT R0 POINTS TO THE TCB ENTRY OF THE TASK TO BE ; STARTED. IT WILL START THE TASK CORRECTLY (EVEN IF ; IT IS NEW). THE STACK IS PRESUMED TO HAVE THE ; OLD PS,PC OF THE OLD TASK AND THE OLD TCB MUST HAVE ; ITS DYNAMIC REGISTERS AND POSSIBLY APRS ON IT AS WELL ; AS THE DYNAMIC STACK POINTER SAVED. THERE IS NO PRESUMED ; OTHER DATA ON THE STACK (SUCH AS THE ARGUMENTS OF A ; REQUEST OR SPAWN DIRECTIVE IN THE NORMAL SITUATION). THIS ; ENTRY IS USED WHERE TASKS ARE CALLED AT I/O COMPLETION AND ; WHERE THEY ARE STARTED FROM REMOTE REQUESTS (AND MAYBE OTHER ; PLACES). .GLOBL MX.RQS MX.RQS: BISB #340,@#PS ;GUARANTEE NO INTERRUPTS!!!! .IIF DF,CMNTCB, JSR PC,TCBGET ;ALLOCATE THE TCB MOV R0,MX.TCB ;SAVE WHERE WE ARE MOVB #4,TCBST(R0) ;SET RUNNING STATUS TST TCBDSP(R0) ;SEE IF THERE IS A DYNAMIC STACK BEQ NEWONE ;IF NOT, MAKE ONE AT INITIAL SP MOV TCBDSP(R0),SP ;GET DYNAMIC STACK POINTER .IIF DF,CMNTCB, JSR PC,TCBFRE ;DEALLOCATE THE TCB .IIF DF,M$GE,JSR PC,A.PRRS ;RESTORE APR'S IF APPROPRIATE MOV (SP)+,R0 ;RESTORE GENERAL REGS TOO MOV (SP)+,R1 MOV (SP)+,R2 MOV (SP)+,R3 MOV (SP)+,R4 MOV (SP)+,R5 ;NOTE NO EVENT FLAG OR STACK ARGS HERE... .IIF NDF,$$DOS,CLRB @#PS ;PRIO 0 FOR RSX RTI ;GO TO USER PROGRAM AGAIN IF HE WAS ACTIVE BEFORE... .IFF JSR PC,U.RSAV ;SAVE STATE OF TASK NOW ACTIVE .GLOBL MX.RQS MX.RQS: .IIF DF,CMNTCB, JSR PC,TCBGET ;ALLOCATE THE TCB MOV R0,MX.TCB ;SET CALLER R0 TO TCB OF NEW TASK TST TCBDSP(R0) ;RUNNING NOW? BNE 3$ ;IF SO, RESTART IT AS IS... MOVB MX.CPU,TCBCPU(R0) 3$: MOVB #4,TCBST(R0) ;SET IT RUNNING STATUS (NO WAITS,SUSPEND,ETC) BR SACM ;GO START THE THING UP .ENDC .IF DF,M$GE ; ; ;U.ALD -- LOAD APRS OF TASK WITH TCB ENTRY ADDR IN R0. USED FOR WAIT AND ; ORWAIT WHEREVER EV ADDR NOT IN PAR 0 WITH MSX EXEC TO ALLOW EV ; TO BE ANYWHERE IN A TASK'S SPACE. ; U.ALD: MOV TCBDSP(R0),R1 ;REMAP TO TASK POINTED TO BY R0 IF ACTIVE BEQ 2$ ;CHECK THAT IS ACTIVE MOV @#PS,-(SP) ;SAVE PSW MOVB #340,@#PS ;GO TO PRI7 TO LOCK OUT INTERRUPTS JSR R5,S.RSAV MOV SP,U.SVSP ;SAVE CURRENT SP A FEW INSTRUCTIONS MOV R1,SP ;SET UP TO TASK SP JSR PC,A.PRRS ;PARASITE CALL TO RESTORE USER APRS MOV U.SVSP,SP ;BACK TO OUR STACK JSR R5,S.RRES MOV (SP)+,@#PS ;BACK TO OUR OLD PRIO 2$: RTS PC ;RETURN TO CALLER U.SVSP: .WORD 0 .ENDC .IF DF,REL$SP ;SUBSIDIARY STACK RELOCATION ROUTINES ; ;NOTE GETSTK OR FRESTK MAY GET STACK FROM A POOL (RSX VERSIONS) OR ;FROM THE TASK'S SPACE (STAND-ALONE VERSIONS). THEY WILL BE DIFFERENT ;SINCE RSX STACKS SHOULD BE IN THE MSX EXEC AREA AND IN OTHER VERSIONS ;(S/A) SHOULD BE WITH THE STACK. (HOWEVER, THEY CAN BE WITH THE ;STACK IN EITHER CASE AS MSX MAPS ALL APR'S TO THE TASK PRIOR TO ;REFERENCES TO IT IN MAPPED CONFIGURATIONS.) ; ;SPRELO - ALLOCATE STACK FRAME AND POINT TASK TO IT. SPRELO: JSR R5,S.RSAV ;SAVE CALLER'S REGS JSR PC,GETSTK ;THEN GET A STACK FRAME POINTED TO BY R1 CMP R1,#4 ;IS R1 VALID? BLOS SREXIT ;NO, DON'T SET DYNAMIC STACK MOV R1,TCBDSP(R0) ;SAVE ADDRESS AS TASK'S DYNAMIC SP MOV TCBISP(R0),R2 ;NOW POINT AT INITIAL SP AREA MOV R1,-2(R2) ;SAVE STACK FRAME START THERE SREXIT: JSR R5,S.RRES ;GIVE BACK USER REGS RTS PC ;AND GO BACK TO HIM ;N.B. -- THERE MUST BE ENOUGH STACK SPACE!!! ; ;SPRMOV - REMOVE STACK FRAME AND MARK IT GONE FROM TASK SPRMOV: JSR R5,S.RSAV ;SAVE CALLER'S REGS MOV TCBISP(R0),R2 ;GET STACK FRAME ADDRESS MOV -2(R2),R1 ;INTO R1 BEQ SREXIT ;FORGET IT IF NONE JSR PC,FRESTK ;RELEASE THE CORE CLR -2(R2) ;MARK IT FREED BR SREXIT ;THEN GO AWAY .ENDC ; ; STATE5 - WAITING FOR SIGNIFICANT EVENT (JUST SKIPS A SCAN) STATE5: MOVB #4,TCBST(R0) ;SET RUNNING STATE FOR NEXT SCAN SCNXTJ: JMP SCNEXT ;THEN GO TO NEXT SCAN STEP ; ; STATE6 - WAITING FOR NONZERO EV IN KERNEL SPACE STATE6: TST @TCBEVA(R0) ;IS THE EV NONZERO YET? BEQ SCNXTJ ;NO, LOOK AT THE NEXT TASK JMP WATDUN ;YES, FLAG WAITING OVER. ; ; STAT10 - ABORT QUEUED ; ;NOTE THAT THIS STATE IS ENTERED WHERE A TASK'S SPAWNED TASKS ARE ABORTED ;AND LEADS TO CALLING AN ABORT ROUTINE IN THE TASK. A TASK WILL BE ABORTED ;AND THEN ITS SPAWNED TASKS, BUT IT WILL HAVE A CHANCE TO RUN. IT IS ;EXPECTED THE ABORT ROUTINE ENDS WITH AN EXIT DIRECTIVE. TWO ABORTS ;ON A TASK WILL CAUSE IT TO EXIT REGARDLESS OF THE ABORT ROUTINE'S ;EXECUTION; THE ABORT ROUTINE IS ENTERED AS AN AST (A MSX AST, NOT AN ;RSX AST) AND CAN DO WHAT IT LIKES TO CLEAN UP. ; STAT10: MOVB #340,@R5 ;SET PRI 7 FOR NO INTS NOW BITB #1,TCBPR(R0) ;DID WE SET THIS ONCE YET? BNE REABRT ;YES, CANNOT ENTER CLEANUP ENTRY TWICE. BISB #1,TCBPR(R0) ;NOTE STARTUP ZEROES THIS BYTE TST TCBABO(R0) ;DID TASK HAVE AN ABORT ENTRY? BEQ REABRT ;NO, JUST DO OUR CLEANUP AND GO. ;NOW SET UP THE AST ENTRY MOV TCBSTT(R0),-(SP) ;SAVE STATUS WORD TO SEND CALLER MOV R0,-(SP) ;SAVE TCB ADDRESS OF TASK MOVB TCBCPU(R0),-(SP) ;SAVE CPU NUMBER OF TASK MOV TCBABO(R0),R1 ;GET AST ENTRY JSR PC,ENTAST ;SET UP TASK TO START UP AGAIN AT ADDR IN R1 ;WITH STACK CONTAINING: ; ; STATUS WORD ; TCB ADDRESS ; TASK CPU ; OLD TASK PSW ; SP: OLD TASK PC ; SINCE TASKS IN OTHER CPUS HAVE STATES 0 OR 4 ONLY, NO BROADCAST NEEDED SETUPJ: JMP SETUP ;NOW GO START THE TASK (AT ITS NEW LOC) .GLOBL REABRT ;CLEANUP ENTRY TO FINALLY GET RID OF THE TASK. HERE ALL TASK ACTIVITY IS ;ENDED AND THE EXIT BROADCAST IS FINALLY SENT. THIS ENTRY IS CALLED FROM ;MXTRAP. ; ; R0 MUST POINT AT THE TCB ENTRY OF THE TASK ON ENTRY ; REABRT: MOVB #340,@#PS ;ENSURE PRIORITY 7 .IIF DF,CMNTCB, JSR PC,TCBGET BICB #1,TCBPR(R0) ;REMOVE EXIT FLAG ;GET MESSAGE QUEUE. MESSAGE INPUT AST'S ARE QUEUED UP IN A SYSTEM POOL ;AND ALL SUCH MUST BE DRAINED AND THE TASK'S MESSAGE QUEUE DRAINED AND ;ITS FREE SPACE LIST REBUILT. CLR TCBDSP(R0) ;SAY NO DYNAMIC STACK (EXITED FLAG TOO...) .IIF DF,REL$SP, JSR PC,SPRMOV ;FREE STACK FRAME IF ANY MOV TCBMQB(R0),R1 ;R1 POINTS TO MSG QUEUE BLOCK MOVB MX.CPU,-(SP) ;MAINTAIN INFORMATION ON CPU USE CLRB 1(SP) ;LEAVE ONLY 1 BYTE OF CPU NUMBER DEC @SP ASL @SP ;GET CPU NUMBER ADD #CPU.PR,@SP ;FORM ADDRESS OF CPU DEC @(SP)+ ;COUNT DOWN TASKS ACTIVE ON THIS CPU JSR PC,MQDRAN ;DRAIN QUEUE AND REBUILD FREE SPACE LIST MOV TCBSCB(R0),R1 ;NOW GET SCRATCH AREA CONTROL BEQ 1$ ;IF NONE, NO PROBLEM ; MOV @R1,4(R1) ;FREE ALL SPACE THERE ;SCB SIZE IS 7 WORDS LONG. ;SCB POINTER IS TO PERM. DATA IN USER TASK WHICH WE MUST ENSURE IS MAPPED. ;NOTE POINTERS ARE CORRECT FOR WORKING COPY OF BITMAP CTL AREA ADDR .IF DF,SAXCL JSR PC,U.LDR ;MAP TASK IN .IFF .IF DF,M$GE JSR PC,U.ALD ;MAP TASK IN .ENDC .ENDC MOV @R1,R2 ;ADDR OF PERM. MAP MOV 2(R1),R3 ;ADDR WORKING MAP MOV #7.,R4 ;SIZE OF AREAS (SEE MXSUBS) 34$: MOV (R2)+,(R3)+ ;COPY PERM. TO WORKING SOB R4,34$ ;NOW ZERO BITMAP TOO. MOV @R1,R2 ;POINT AT PERM DATA AGAIN MOV 10(R2),R3 ;BITMAP START ADDR MOV R3,R4 ;COPY FOR LENGTH SUB 12(R2),R4 ;LENGTH OF MAP IN BYTES NOW BLT 1$ ;MUST NOT BE NEGATIVE...ERROR THEN ASR R4 ;ENWORD LENGTH 35$: MOVK #0,(R3)+ ;ZERO BITMAP IN TASK SPACE SOB R4,35$ ;(ALL OF IT) 1$: MOV TCBSPW(R0),R1 ;GET SPAWN TABLE ADDRESS MOV (R1)+,R3 ;SET UP NOTIFY OF CALLER CLR -2(R1) ;(NOW DON'T NEED THE CALLER NAME) JSR PC,ATLOOK ;FIND CALLER TCB IF IT EXISTS MOV #15.,R4 ;UP TO 15. SPAWNED TASKS (MORE ARE JUST RQST) 2$: MOV (R1)+,R3 ;GET A CALLED TASK TCB ADDRESS BEQ 3$ ;IF 0, NOTHING TO DO MOV R2,-(SP) JSR PC,ATLOOK ;FIND TCB FROM TASK NAME IN TABLE MOV R2,R3 ;POINT R3 AT THE TCB MOV (SP)+,R2 TST R3 ;SEE IF THERE IS A TCB BEQ 3$ ;IF NOT, NO ACTION CMPB TCBCPU(R3),MX.CPU ; CHECK WHICH CPU THEY ARE ON BNE 3$ ;IF NOT THIS CPU DON'T PUT IN STATE 10 MOVB #10,TCBST(R3) ;IF NOT, SET IT AS ABORT QUEUED CLR -2(R1) ;THEN ZERO THE ENTRY FOR NEXT TIME 3$: SOB R4,2$ ;DO ALL THE TASKS THERE BITB #2,TCBPR(R0) ;HAS AN EXIT MSG ALREADY BEEN SEEN? BNE 41$ ;IF SO, DON'T REPLICATE IT JSR PC,XNOTFY ;LET CALLER KNOW OF EXIT BY BROADCAST OF ;EXIT MESSAGE WITH STATUS SET. 41$: ; BICB #2,TCBPR(R0) ;REMOVE MSG-SEEN FLAG CLRB TCBCPU(R0) ;SET NO CPU NOW (LEGAL CPU NUMBERS ;ARE NONZERO (1,2,3,4,...).) TST TCBKEV(R0) ;ANY KNL EVENT VARIABLE TO BUMP FOR ;CALLER ON EXIT WITH STATUS? BEQ 25$ ;NO, ALL RIGHT FOR NOW TST R2 ;IS THE CALLER TCB THERE? BEQ 25$ ;IF NOT, CANNOT TELL HIM ANYTHING EITHER MOV TCBKEV(R0),R5 ;GET EV ADDR TO TELL CALLER ABOUT EXIT IF NEED JSR R5,S.RSAV ;SAVE REGS MOV R5,R1 ;COPY EVA .IF DF,CHKNFY ;(SHOULDN'T NEED THIS CODE) MOV @R2,-(SP) ;PUSH TSK NAME MOV R1,-(SP) ;PUSH EVA TO BUMP ;EVNFY BUMPS THE CALLER'S EVENT VARIABLE USING EITHER LOCAL LOGIC OR A ;TYPE 5 (GLOBAL BUMP) MESSAGE. THE CALLED TASK IS ASSUMED IN THIS CPU. ;R2 IS TCB OF CALLER. R0 IS TCB OF ABORTING TASK. JSR PC,EVNFY ;NOTIFY OTHER TASKS OF EXIT VIA EV BUMP ADD #4,SP ;FIXUP STACK .ENDC JSR PC,ACK ;QUEUE EXIT AST TO TASK IF IN THIS CPU JSR R5,S.RRES ;RESTORE REGS 25$: ;BIT 2 IS FLAG THAT THE WORLD (OTHER CPUS) KNOWS OF THE EXIT. ;BIT 4 IS A FLAG THAT THE CALLER HAS HAD AN EXIT QUEUED HIS WAY. ; QXTAST SETS BIT 4 AND IGNORES ALL CALLS UNTIL IT IS CLEARED. .IIF DF,DY$MEM, JSR PC,MULADD ;ALLOW MEMORY RECLAIMING LATER BICB #6,TCBPR(R0) ;REMOVE MSG-SEEN FLAG AND CALLER-TOLD FLAG .IIF DF,CMNTCB, JSR PC,TCBFRE JMP MX.SCN ;GO DO A SCAN ;ACK - CHECK THAT CALLER NOT IN CPU AND QUEUE EXIT AST IF IT IS ACK: CMPB MX.CPU,TCBCPU(R2) BNE 7$ ;IF NOT IN THIS CPU FORGET THE QUEUE ;TEST THAT THE CALLED TASK WAS NOT SEEN IN A MSG. IF SO, AST ALREADY WAS ;QUEUED AND IS NOT NEEDED HERE. BITB #2,TCBPR(R0) ;WAS CALLER ENDED VIA EXTERNAL MSG? BNE 7$ ;YES, NO SECOND EXIT AST. ;NOTE R0 STILL POINTS AT CALLED TASK TCB JSR PC,QXTAST ;IF SO QUEUE AN EXIT AST. R2 = TCB ADDR ;NOW SET CALLER'S STATUS AS HAVING EXIT AST QUEUED AFTER SAVING ;OLD STATUS... MOV TCBSCB(R2),R5 ;GRAB SCB ADDR HERE ADD #14,R5 ;POINT AT OLD STATUS BYTE ;IF OLD STATUS NONZERO, LEAVE IT ALONE. ELSE FILL IN FROM CURRENT. TSTB @R5 ;ANYBODY HOME? BNE 37$ ;YEP. BEST LEAVE HIM BE... MOVB TCBST(R2),@R5 ;NO. SAVE THE OLD STATUS HERE FOR LATER. 37$: MOVB #12,TCBST(R2) ;AND SET AST QUEUED STATUS UP TSTB @R5 ;SEE IF OLD STATUS WAS DISABLED BPL 7$ ;IF NOT, NO DISABLE NOW BISB #200,TCBST(R2) ;IF SO, DISABLE AGAIN. 7$: RTS PC ; ; ; STAT11 - MESSAGE-IN AST QUEUED ; STAT11: MOVB #340,@R5 ;TO PRI 7 TO PREVENT INTS TST @TCBAQB(R0) ;SEE THAT AN AST ADDRESS EXISTS BEQ SETPJJ ;IF NOT DON'T DEQUEUE ANY ASTS. JSR PC,DQMSGI ;GET A MSG IN. IF NONE, RETURNS WITH C BIT SET ;NOTE THAT ON RETURN WE EXPECT ; R5= EV ADDR TO NOTIFY OF RECEIPT ; R2= STATUS ; R3= ADDRESS OF DATA ; R4= BYTE COUNT ; TOP OF STACK= TASK NAME OR NUMBER FROM WHOM MSG CAME ; DQMSGI MUST ALSO UPDATE THE FREE AREA, FREE THE NODE FOR AST AND UPDATE ; MESSAGE COUNTS (IN KNL AND TASK SPACE) BCS SETPJJ ;IF FAIL, GO START PGM AGAIN MOV R5,-(SP) ;SAVE R5 FROM ENTAST MOV R2,-(SP) ;PUSH STATUS MOV R3,-(SP) ;PUSH ADDR MOV R4,-(SP) ;PUSH BYTE COUNT MOV @TCBAQB(R0),R1 ;MSG AST INPUT ADDRESS (0 IF NONE) ;ALWAYS HAVE AST ENTRY HERE JSR PC,ENTAST ;IF SOME, THEN ENTER AND DO THE STUFF. JSR PC,EVNFY ;FLAG EV IN CALLER IF NEEDED ADD #4,SP ;FIX SP JMP SETUP ;GO RUN THE AST NOW. .GLOBL EVNFY EVNFY: ;NOW BUMP THE EV IF SPECIFIED MOV 4(SP),R3 ;TASK # OR NAME JSR PC,ATLOOK ;FIND IT MOV 2(SP),R1 ;EV ADDRESS BEQ 11$ ;IF NO EV, NO BUMP TST R2 ;NOW, IS THERE A TASK FOR THE EV? BEQ 11$ ;NO, DON'T BUMP IT. ;GENERATE A REPLY MSG CMPB TCBCPU(R2),MX.CPU ;TASK HERE? BEQ 12$ ;YES, NO MSG NEEDED MOV R1,R5 ;MUST SAVE EV ADDR JSR PC,GETNOD ;GET A NODE ADDR IN R1 MOV R1,R4 ;COPY/SAVE MOV #5,(R1)+ ;TYPE 1 MSG MOV R3,(R1)+ ;TSK NAME=CALLER'S MOV TCBCPU(R2),(R1)+ ; CPU/BUS # OF TASK MOV R5,(R1)+ ;EV IS THE ONE WE WANT MOV MX.CON,(R1)+ ;NET CONNECTIVITY=RE-XMIT COUNT CLR (R1) MOVB TCBCPU(R2),@R1 ;CPU TO GET MSG TST (R1)+ ;PASS IT MOV TCBSTT(R2),@R1 ;SAVE EXIT STATUS BNE 7$ MOV MX.ERR,@R1 ;SEND MX.ERR AS VALUE TO BUMP BY 7$: MOV R0,-(SP) MOV R2,R0 ;TASK TO=TASK FROM MOV #16,R5 ;7 WORDS TO SEND MOVB TCBBUS(R0),R3 ;BUS IS TASK'S ;ALLOW ROUTING TO THE TASK IF NOT DIRECT-CONNECTED JSR PC,ROUTE ;FIND BUS TO SEND ON JSR PC,MGXMTR ;TRANSMIT, THEN DELETE, THE NODE (AUTO FREEUP) MOV (SP)+,R0 ;FIX R0 AGAIN BR 11$ 12$: ;NOTIFY A TASK IN THIS CPU MOV R0,-(SP) ;YES. SAVE R0 MOV R2,R0 ;AND SET UP CALLER AS R0 POINTED .IF DF,SAXCL JSR PC,U.LDR ;MAP EV MFPI @R1 INC @SP MTPI @R1 .IFF .IF DF,M$GE JSR PC,U.ALD ;MAP EV .ENDC INC @R1 ;(ONLY ONE SPACE IN RSX VERSIONS OR DOS) .ENDC MOV (SP)+,R0 ;RESTORE TCB POINTER 11$: RTS PC ;GO SET THE TASK UP TO RUN NOW. SETPJJ: ; GO TO START UP TASK IF OLD STATUS WAS 0 OR 4, ELSE SCAN TO NEXT MOV #15,R1 ;POINT AT SAVED STATUS IF ANY SCCP: ADD TCBSCB(R0),R1 ;GET SCRATCH AREA MOVB @R1,R5 ;GET OLD STATUS CLRB @R1 ;AND ZERO SAVED ONE ; TSTB R5 ;R5=0 ==>NO SAVED STATUS? ; BEQ 1$ ;IF NOT, JUST START NOW ;*** RESET OLD STATUS. SHOULD ALWAYS BE SAVED PRIOR TO SETUP OF AST-QUEUED ;*** STATUS. MOVB R5,TCBST(R0) ;IF NOT, RESET OLD STATUS. CMPB R5,#4 ;RUN STATUS? BEQ 1$ CLRB @#PS ;ENSURE INTS OK JMP SCANLP ;THEN RETEST TASK. 1$: JMP SETUP ;IF RUN OK, DO IT. SETQJJ: MOV #14,R1 ;STATUS SAVE FOR EXIT AST'S BR SCCP ; ; STAT12 - EXIT-WITH-STATUS AST QUEUED STAT12: MOVB #340,@R5 ;TO PRI 7 JSR PC,DQXST ;GET AN EXIT AST NODE OR FAIL WITH CS BCS SETQJJ ;IF FAIL, GO TO START UP THE TASK ;SET UP THE AST ENTRY TO THE TASK'S EXIT AST ENTRY ; MOV R5,-(SP) ;EV ADDR MOV R2,-(SP) ;SAVE STATUS OF TASK MOV R3,-(SP) ;SAVE TSK NAME MOV R4,-(SP) ;SAVE CPU NO. MOV TCBAQB(R0),R1 ;GET AST CTL BLK MOV TCBSPW(R0),R2 ;GET SPAWN TBL TO CLEAR SPAWNED TASKS LIST MOV #15.,R4 ;MAX SPAWNED TASKS IN TBL TST (R2)+ ;PASS CALLER TASK CELL ;TRY TO CLEAR OUT THE CALLED TASK ENTRY IN SPWN TBL 15$: CMP (R2)+,R3 ;SEE IF CALLED TASK IN TBL NOW BNE 16$ CLR -2(R2) ;IF WE FIND IT, ZERO IT BR 17$ 16$: SOB R4,15$ 17$: MOV 10(R1),R1 ;GET EXIT AST ENTRY BEQ 1$ ;IF NONE, NO EXIT AST JSR PC,ENTAST ;IF ONE, MAKE TASK HAVE AN AST 2$: JMP SETUP 1$: ADD #6,SP ;REPAIR STACK ; IF NO AST WAS SPECIFIED, CLEAR SAVED STATUS FOR THE NEXT TIME. BR SETQJJ ;GO START OR TEST TASK ; ;STAT13 - PWAIT ON KERNEL EVENT VRBL. ; STAT13: MOV @TCBEVA(R0),R2 ;LOOK AT EV. IN KNL SPACE BPL 1$ ;IF POSITIVE WAIT IS DONE JMP SCNEXT ;IF NEG., WAIT MORE 1$: INC R2 ;FORCE R2 NONZERO JMP WATDUN ;IF 0 OR +, WAIT IS OVER, START UP. ; ; ;STAT15 - GENERALIZED WAIT UNTIL EITHER EV IS SET AS SPECIFIED IN USER ; TABLE OR TASK SETTING EV EXITS STAT15: MOV TCBEVA(R0),R1 ;GET USER TABLE ADDRESS. (SEE ABOVE FOR FORMAT) .IIF DF,SAXCL, JSR PC,U.LDR ;MAP TASK'S APR'S IN .IIF DF,M$GE, JSR PC,U.ALD ;MAP TASK'S APR'S IN S15LUK: KMOV 2(R1),R3 ;SEE WHICH TASK IS TO BE WAITED FOR JSR PC,ATLOOK ;FIND IT IN STL BNE 1$ ;IF NE WE FOUND ONE 2$: JMP WATDUN ;IF NOT, END THE WAIT...NO TASK NOW. ;(TASKS MAY BE TRANSIENT IF INSTALL/RUN/REMOVE TASKS RUN THEM...) 1$: TSTB TCBST(R2) ;SEE IF THE TASK HAS EXITED BEQ 2$ ;IF SO, WAIT ENDS RIGHT NOW. KMOV (R1),R3 ;IF NOT, LOOK AT USER'S EV ADDRESS ADRCHK R3 ;VERIFY ADDR LEGALITY OR MAKE IT ODD BIT #1,R3 ;IF ODD ADDRESS BNE 2$ ;SKIP OUT. KMOV (R3),R3 ;AND GET HIS EVENT VARIABLE KMOV 4(R1),R2 ;GET MASK ADDRESS (TEST EV ANDED WITH MASK) BNE 15$ 14$: MOV #-1,R2 ;ALL BITS ON... BR 16$ 15$: ADRCHK R2 BIT #1,R2 ;SEE IF ADDR IS VALID BNE 14$ ;IF NOT, USE -1 MASK. KMOV (R2),R2 ;GET MASK IF ONE IS THERE BEQ 14$ ;IF 0, ERROR SO ACCEPT ALL BITS 16$: COM R2 ;MAKE MASK FOR ANDS BIC R2,R3 ;MASK THE EV. VARIABLE KMOV 6(R1),R2 ;GET TYPE OF WAIT ; KMOV (R2),R2 ;(ADD THIS IF ADDRESS, NOT LITERAL, IN TABLE) TST R2 ;SEE IF TYPE=0 (NORMAL WAIT) BEQ 4$ ;YES, DO NORMAL WAIT CMP R2,#-1 ;SEE IF TYPE=-1 (TEST EV .LT. 0) BEQ 5$ ;YES, WAIT TILL EV IS STRICTLY NEGATIVE CMP R2,#1 ;SEE IF TYPE=+1 (TEST EV .GT. 0) BEQ 6$ ;YES, WAIT TILL EV IS STRICTLY POSITIVE ;WAIT TILL EV IS 0 AS FALL-THROUGH TST R3 ;IS EV.AND.MASK ZERO? BEQ 2$ ;YES, WAITING DONE 10$: .IF DF,MULT15 ;IF THIS IS DEFINED, TBL MAY HAVE SEVERAL ;ENTRIES DELIMITED BY A 0,0,0,0 ENTRY. ADD #4,R1 ;POINT AT NEXT TABLE ENTRY OR 0 DELIMITER KMOV @R1,R3 ;GET NEXT EV ADDRESS (OR 0 IF END) BEQ 25$ ;IF NONE, END LOOKING BIT #1,R3 ;ODD EV ADDRESSES ARE A NO-NO TOO BEQ S15LUK ;IF LOOKS OK, CHECK NEXT TBL ENTRY 25$: .ENDC JMP SCNEXT ;NO, KEEP WAITING 4$: TST R3 ;IS EV NONZERO? (NORMAL WAIT) BNE 2$ ;NONZERO SO DONE BR 10$ ;ELSE WAIT MORE 5$: TST R3 ;EV.AND.MASK STRICTLY NEGATIVE? BLT 2$ ;IF SO DONE BR 10$ 6$: TST R3 ;IS EV STRICTLY POSITIVE? BGT 2$ ;IF SO, DONE NOW BR 10$ ;IF NOT, GO ON WAITING. ; .IF DF,MX$CLK ; ;CLOCK INTERRUPT VECTOR ENTRY. ; SYSTEM TIMING WILL USE THE SPARE WORD AT SCB (SCRATCH CTL BLK)+6 ;AND INCREMENT THE ENTRY FOR EACH TASK EVERY SECOND. MX.TPI WILL BE SET ;TO NO. TICKS LEFT IF LINE CLOCK. THIS GIVES 1 SIG EVENT/SEC. .GLOBL CLKINT ;ENTRY HERE FOLKS .IIF DF,SAXCL, MX.TPI: .WORD 60. ;NO. TICKS TO COUNT DOWN (R/W) CLKINT: .IF DF,SAXCL .IF DF,KW11P ;PROG. CLOCK MOV #105,@#172540 ;SET NEXT INT. GOING .IFF ;LINE CLOCK MOV #105,@#177546 ;SET NEXT INT. DEC MX.TPI ;COUNT DOWN TICKS TO DO BLE 1$ ;IF NEG OR 0 ALL SET UP RTI ;IF NOT NEG OR 0 JUST RETURN 1$: MOV #60.,MX.TPI ;SET FOR NEXT SECOND .ENDC JSR R5,MX.PST ;POST INT. .BYTE 340,1 ;SAVING REGISTERS TOO ;RETURN HERE WITH PRI=7 STILL BUT REGS SAVED MOV #MX.TBL,R0 ;POINT AT TASK CONTROL TABLE 2$: TST (R0) ;AT END OF TABLE? BEQ 3$ ;IF SO, DONE WITH INT. CMPB TCBCPU(R0),MX.CPU ;THIS TASK OURS? BNE 4$ ;NO, IGNORE MOV TCBSCB(R0),R1 ;GET SCRATCH CONTROL BLK ADDR BEQ 4$ ;IF ZERO (NO SCB), NO TIMING! BIT #1,R1 ;TEST ADDR NOT ODD BNE 4$ ;ILLEGAL ADDRESSES IGNORED TOO INC 10(R1) ;BUMP SPARE WORD OF SCB ;ALLOW THIS ROUTINE TO TIME OUT TASKS IF THE WORD NEXT IN SCB IS ;NONZERO. IF ZERO, NO TIME LIMIT ON RUNTIME. TST 12(R1) ;WORD AFTER SCB TIME EV NONZERO? BEQ 4$ ;NO, JUST GO ON CMP 10(R1),12(R1) ;IF SO, ARE WE AT ABORT TIME YET? BNE 4$ ;NO, LEAVE STATUS ALONE ;AT THE TASK TIMEOUT, MARK IT FOR ABORT. MOVB #10,TCBST(R0) ;MARK TASK FOR ABORT NEXT SCAN. 4$: ADD #MX.TBS,R0 ;GO TO NEXT TASK BR 2$ ;CHECK IT FOR LEGALITY NEXT 3$: ;NOW ALL DONE. ;ALLOW OPTIONAL ROUTINE TO DO HANDLER TIMEOUT BY CALLING AN EXTRA ;ROUTINE TO TIME ALL DATA TRANSFERS. (REQUIRES HANDLER MODS). ;NOTE THIS IS A NOOP FOR RSX VERSIONS. .IF DF,SAXCL .IIF DF,DEVTMR, JSR PC,DEVTMO ;TIME OUT DEVICES. .ENDC JSR R5,S.RRES ;RESTORE USER'S REGS RTI .IFF ;RSX VERSIONS MOV R0,-(SP) ;ONLY NEED A COUPLE OF REGS HERE MOV R1,-(SP) MOV #MX.TBL,R0 ;POINT AT TASK CONTROL TABLE 2$: TST (R0) ;AT END OF TABLE? BEQ 3$ ;IF SO, DONE WITH INT. CMPB TCBCPU(R0),MX.CPU ;THIS TASK OURS? BNE 4$ ;NO, IGNORE MOV TCBSCB(R0),R1 ;GET SCRATCH CONTROL BLK ADDR ;NOTE SCRATCH CONTROL BLOCKS MUST BE IN LOCAL STORAGE! BEQ 4$ ;IF ZERO (NO SCB), NO TIMING! BIT #1,R1 ;TEST ADDR NOT ODD BNE 4$ ;ILLEGAL ADDRESSES IGNORED TOO INC 10(R1) ;BUMP SPARE WORD OF SCB 4$: ADD #MX.TBS,R0 ;GO TO NEXT TASK BR 2$ ;CHECK IT FOR LEGALITY NEXT 3$: ;NOW ALL DONE. MOV (SP)+,R1 MOV (SP)+,R0 ;RESTORE REGS CLR -(SP) ;MAKE EXTRA CELL ON STACK. NOTE THAT ;EVENT FLAG NO. ON TOP OF STACK THERE ALREADY SO 2 NEW CELLS THERE NOW. ;ADJUST STACK AND MAKE IT LOOK LIKE A NORMAL INT OCCURRED TO CLKIDM MOV 4(SP),(SP) ;MOVE STACK DOWN INTO NEW CELLS MOV 6(SP),2(SP) MOV 10(SP),4(SP) MOV 12(SP),6(SP) ;COPY THE TOP OF STACK MOV 14(SP),10(SP) ;COPY REST OF EF WORDS MOV 16(SP),12(SP) MOV 20(SP),14(SP) MOV 2(SP),16(SP) ;COPY OLD PC MOV 4(SP),20(SP) ;COPY OLD PS MOV #CLKIDM,2(SP) ;MAKE RETURN GO TO MX.AS1 AS THOUGH FROM ;INTERRUPT CLR 4(SP) ;AT PRIO 0 TO KEEP RSX HAPPY MOV #1,MX.ARC ;FLAG AST'S DISABLED .MCALL DSAR$S DSAR$S ;AND DISABLE THEM CLRB MX.SEV ;SET SIG EVENT FOR SCANNER TOO. ;NOW MAKE MSX AWARE OF WHAT HAPPENED. MRKT$S ,#1,#2,#CLKINT ;SET NEXT INT ASTX$S ;CLKIDM - DUMMY CLOCK INTERRUPT ENTRY TO POST INTERRUPT AND GO TO MXSCAN CLKIDM: JSR R5,MX.PST ;POST INTERRUPT .WORD 0 ;PRI 0, NO REG SAVE RTI ;THEN OFF TO SCANNER .ENDC .ENDC ; .IF DF,M.MMP ; INTERPROCESSOR MESSAGES ARE STARTED AT THE BEGINNING OF THE ; SYSTEM'S OPERATION AND THEREAFTER CONTINUED FROM THIS INTERRUPT ; ENTRY POINT. THE SYSTEM WILL ATTEMPT AT ALL TIMES (AND FOR EACH ; BUS, FOR WHICH THIS SECTION SHOULD BE DUPLICATED) TO KEEP THE ; INPUT GOING ON. THE PRESUMPTION WILL BE MADE THAT THIS LOOKS ; LIKE AN INTERRUPT HANDLER WITH THE ENTERING PSW CONTAINING ; A CODE IN THE RANGE 0-17 CONTAINING THE BUS NUMBER. FOR SYSTEMS ; WITH MORE BUSSES, THE CODE MAY BE DUPLICATED. ; ; THERE ARE 5 MESSAGE TYPES THAT MAY BE SEEN: ; 1. INPUT MESSAGES. FORMAT: ; TYPE OF MSG=1 ; CALLER TASK NAME OR NUMBER ; MESSAGE PRIORITY ; TASK NAME OR NUMBER TO RECEIVE THE MSG ; MESSAGE LENGTH ; EV ADDRESS TO BUMP IN CALLER TASK WHEN MSG IS RECEIVED BY ; CALLED TASK ; DATA. TOTAL LENGTH NOT OVER 512. BYTES. (BECAUSE BUFFERED HERE) ; ; 2. TASK-REQUEST BROADCASTS; FORMAT: ; TYPE OF MSG=2 ; CALLER CPU NUMBER ; TASK NAME OR NUMBER REQUESTED ; TASK PRIORITY/PRIORITY EXPECTED ADDRESSED CPU CAN ACCEPT ; NUMBER OF TIMES TO RETRANSMIT MESSAGE ; CPU NO. TO GET MESSAGE (OR 0 IF ALL) ; ADDRESS TO RESUME TASK OR 0 (NON-0 IF A RESUME MSG) ; CALLER TASK NO. OR -1 (FOR SPAWNS) (TSK NAME OK TOO) ; EXIT EV ADDR FOR CALLER TASK ON TASK EXIT ; ; 3. TASK-ABORT BROADCASTS; FORMAT: ; TYPE OF MSG=3 ; TASK NAME OR NUMBER ; CPU#/BUS# OF TASK ; EV ADDRESS FOR CALLER (WHERE TO SIGNAL CALLER OF ABORT) ; NUMBER OF TIMES TO RETRANSMIT MESSAGE ; CPU NO. TO GET MESSAGE (OR 0 IF ALL) ; TASK STATUS (REASON FOR ABORT, CODED) ; ; 4. TASK EXIT BROADCASTS; FORMAT: ; TYPE OF MSG=4 ; TASK NAME OR NUMBER ; CPU#/BUS# OF TASK ; EV ADDRESS FOR CALLER ; NUMBER OF TIMES TO RETRANSMIT MESSAGE ; CPU NO. TO GET MESSAGE (OR 0 IF ALL) ; ; 5. BUMP GLOBAL EVENT VARIABLE; FORMAT: ; TYPE OF MSG=5 ; TASK # OF TASK WITH EV (-1 IMPLIES KERNEL) ; CPU#/BUS# OF TASK ; ADDRESS OF EV TO BUMP (BUMP=ADD 1) ; NUMBER OF TIMES TO RETRANSMIT MESSAGE ; CPU NO. TO GET MESSAGE (OR 0 IF ALL) ; VALUE TO ADD (0 IMPLIES JUST INCREMENT) .GLOBL INMSGI INMSGI: MOV @#PS,CCSAVE JSR R5,MX.PST ;POST THE INTERRUPT .BYTE 340,1 ;SAVING REGISTERS MOV #MSGDT,R0 ;POINT AT MSG DATA AREA MOV (R0)+,R1 ;GET MSG TYPE MAXTYP=5 ;HIGHEST LEGAL MESSAGE TYPE DEC R1 ;MAP 1-5 TO 0-4 ASL R1 CMP R1,#<2*> ;IS THE MESSAGE IN A LEGAL RANGE? BHI INTXXX ;NO, TRY ANOTHER. CAN'T FIGURE THIS ONE OUT JMP @INTYP(R1) INTYP: .WORD MGRCV,TSKINI,TSKABT,TSKXIT,GINCEV INTXXX: JSR PC,RDMSG ;READ NEXT MESSAGE JSR R5,S.RRES RTI ;RETURN TO SCANNER NOW (AS MX.PST ENSURES) ; ; RECEIVED MESSAGE MGRCV: MOV 4(R0),R3 ;FIRST BE SURE WE HAVE RIGHT TASK JSR PC,ATLOOK ;FIND TASK TCB ADDRESS (CAN'T EXPECT OTHER CPU ;TO KNOW OUR TCB LOC) BEQ INTXXX ;IF ZERO, TASK NOT HERE ;BE SURE WE HAVE THE RIGHT CPU CMPB TCBCPU(R2),MX.CPU ;CHECK WE HAVE RIGHT CPU BEQ CPUOK ;IF IT'S FOR US, OK NOW... ;NOT FOR THIS CPU, BUT THE MESSAGE MAY HAVE TO BE ROUTED HERE TO GET TO ;WHERE IT HAS TO GO. FIRST CHECK THAT THE MESSAGE IS FOR A TASK ON ;A BUS OTHER THAN THE ONE WE GOT THIS MESSAGE ON (POSSIBLY A REDUNDANT ;OPERATION IF THE HARDWARE IS DONE RIGHT) TO BE SURE THE DESTINATION ;DIDN'T GET THE RESULT YET. IF SO, JUST LEAVE. OTHERWISE, FORWARD MESSAGE MOV CCSAVE,R3 ;GET ENTRY CC WHICH ENCODES COND CODES BIC #^C17,R3 ;MASK OFF COND CODES CMPB TCBBUS(R2),R3 ;IS THE TASK ON THE SAME BUS? BEQ INTXXX ;YES, JUST LEAVE...THAT CPU SHOULD GET MSG ;HAVE TO ROUTE THE MESSAGE TO ITS DESTINATION. ASSUME WE HAVE ROUTING ;TABLES (WHICH WILL BE MAINTAINED BY WATCHDOG TASKS RUNNING AS MSX TASKS ;SENDING MESSAGES TO EACH OTHER) AND THAT A SUBROUTINE CAN LOOK UP THE ;SHORTEST ROUTE BUS. ROUTINE ROUTE RETURNS DESIRED BUS VIA R3 WHICH ;REXMIT USES: JSR PC,ROUTE ;FIND ROUTE TO TASK WHOSE TCB IS POINTED ;AT BY R2. R3 GETS BUS NO. RETURN ;C BIT SET IF NO POSSIBLE ROUTE. BCC 1$ JMP OTHXIT ;IF NO ROUTE TO TASK MARK IT EXITED... ;RETRANSMIT THE MESSAGE ON THE NEEDED BUS 1$: JSR PC,REXMIT JMP INTXXX ;GO GET NEXT MSG CPUOK: .GLOBL CPUDO ;TASK RECEIVE SUB BROKEN OFF SO DIRECTIVE ;PROCESSOR CAN CALL---AVOID DUPLICATE CODE JSR PC,CPUDO ;CALL COMMON. R0 POINTS AT BUFFER+2. JMP INTXXX CPUDO: JSR R5,S.RSAV ;LOOKS LIKE OUR TASK CAN RECEIVE THE MESSAGE. QUEUE IT UP AND COPY DATA ;INTO TASK SPACE, AND THEN SET THE TASK INTO MESSAGE AST QUEUED STATE FOR ;LATER DEQUEUE. TSTB TCBST(R2) ;FIRST HOWEVER CHECK THE TASK STATUS ;(IF IT IS NOT THERE, CAN'T GET MSG)... BEQ 32$ ;IF NO SCRATCH AREA CAN'T RECEIVE MSG MOV TCBSCB(R2),R1 ;GET SCR AREA BEQ 32$ ;IF NO SCRATCH AREA CAN'T RECEIVE MSG MOV 6(R0),R3 ;DATA LENGTH ;NOTE: HEADER HAS 3 WORDS MORE THAN OTHERWISE NOTED: ; SIZE IN BLOCKS OF THE ALLOCATED NODE, AND ; LIST FWD, BACK POINTERS. HENCE 20=6+12=SIZE TO ADD ADD #20,R3 ;ADJUST DATA LENGTH FOR HEADER ; ; HERE ALLOCATE THE NODE IN THE TASK'S SPACE. THIS NODE IS ; MANAGED BY THE SAME BITMAP LOGIC AS THE SYSTEM'S NODES, ; BUT WILL RESIDE (WITH THE BITMAP) IN THE TASK'S SPACE. ;SCRATCH CONTROL BLOCK FORMAT: ; SCRTBL: ADDRESS OF PERMANENT COPY OF BITMAP CONTROL AREA ; ADDRESS OF WORKING COPY OF BITMAP CTL AREA ; START NODE ADDRESS (LISTHEAD A) ; END NODE ADDRESS (LISTHEAD B) ;NOTE THAT ALLOCATION FAILURE GIVES R5=0; OTHERWISE R5=NODE ADDRESS JSR PC,MNDALO ;ALLOCATE MESSAGE NODE TST R5 ;DID WE FIND ONE? BNE 1$ ;YES, ALL WAS WELL. ;DATA TOO LONG FOR AVAILABLE SPACE...SEND BACK A COMPLAINT! 32$: JSR R5,S.RRES ;ALLOCATION FAILED...RESTORE REGS 40$: ;HERE IF NO AST NODE AVAILABLE MOV #-1,MX.ERR ;FLAG ERROR FOR CALLER IF NEEDED JSR PC,MSGERR ;SEND THE ERROR MESSAGE RTS PC 1$: MOV TCBMQB(R2),R4 ;MSG QUEUE AREA JSR PC,NODCHN ;CHAIN NODE INTO MESSAGE CHAIN BY PRIORITY MOV R0,-(SP) ;SAVE R0 ;MAINTAIN COUNT OF MESSAGES IN IN TASK SPACE MOV R2,R0 ;LET U.LDR ETC WORK .IF DF,SAXCL JSR PC,U.LDR ;MAP COUNNTER MFPI 14(R4) ;GET ADDR OR 0 TST (SP)+ ;IF 0 NO BUMP BEQ 2$ MFPI @14(R4) ;BUMP COUNTER INC @SP MTPI @14(R4) 2$: .IFF .IF DF,M$GE JSR PC,U.ALD ;NOTE IN RSX CURRENT=PREV=USER MODE MFPI 14(R4) ;GET ADDR OR 0 TST (SP)+ ;IF 0 NO BUMP BEQ 2$ MFPI @14(R4) ;BUMP COUNTER INC @SP MTPI @14(R4) 2$: .IFF TST 14(R4) ;SEE IF ADDR THERE BEQ 2$ ;IF NOT, SKIP INCREMENT INC @14(R4) ;IF SO BUMP EV 2$: .ENDC .ENDC MOV (SP)+,R0 ;RESTORE ORIGINAL R0 NOW JSR R5,S.RSAV ;PRESERVE ALL REGS JSR PC,GETNOD ;FIND AN AST NODE IN R1 (USE BITMAP) TST R1 ;DID WE FIND A NODE? BNE 10$ ;YES, ADDR IN R1 NONZERRO JSR R5,S.RRES ;NO. FIX UP REGS ;RESTORE REGS TO GET R5 BACK (= POINTER TO NODE ALLOCATED) JSR PC,NODFRE ;THEN FREE THE MESSAGE NODE ALLOCATED BY ;MNDALO AND REMOVE IT FROM THE MSG QUEUE ;(NOT IN THAT ORDER...) ;DECREASE TASK COPY OF MESSAGE COUNTER IF WE INCREASED IT ABOVE. .IF DF,SAXCL MFPI 14(R4) ;GET ADDR OR 0 TST (SP)+ ;IF 0 NO BUMP BEQ 52$ MFPI @14(R4) ;BUMP COUNTER DEC @SP MTPI @14(R4) 52$: .IFF .IF DF,M$GE.. MFPI 14(R4) ;GET ADDR OR 0 TST (SP)+ ;IF 0 NO BUMP BEQ 52$ MFPI @14(R4) ;BUMP COUNTER DEC @SP MTPI @14(R4) 52$: .IFF TST 14(R4) ;SEE IF ADDR THERE BEQ 52$ ;IF NOT, SKIP INCREMENT DEC @14(R4) ;IF SO BUMP EV 52$: .ENDC .ENDC BR 32$ ;THEN COMPLAIN TO CALLER CAN'T DO IT. 10$: MOV R1,2(SP) ;KEEP R1 AFTER RESTORE JSR R5,S.RRES ;COUNT THE NUMBER OF MESSAGES IN... INC @R4 ;COUNT UP MSG IN ;INSERT THE NODE JUST FOUND IN THE AST QUEUE FOR THE TASK MOV TCBAQB(R2),R3 ;QUEUE HEAD MOV #6,R4 ;OFFSET IN NODE TO PRIORITY MOV 2(R0),R0 ;PRIORITY OF THIS MESSAGE ;R1 HAS NODE ADDRESS JSR PC,P.INS ;INSERT NODE INTO QUEUE AT CORRECT PRIO. MOV R5,12(SP) ;KEEP R5 AFTER RESTORE MOV R1,2(SP) ;SAVE R1 ACROSS REG RESTORE (=NODE POINTER) JSR R5,S.RRES JSR R5,S.RSAV ;RESTORE ALL OTHER REGS AND FREE THEM AGAIN ;FILL IN THE NODE JUST FOUND WITH THE NEEDED INFORMATION FROM THE MESSAGE MOV 10(R0),(R1) ;FILL IN EVA OR 0 MOV R5,2(R1) ;MESSAGE ADDRESS MOV 6(R0),4(R1) ;MESSAGE (DATA) SIZE IN BYTES ADD #12,2(R1) ;ADD IN HEADER SIZE TO MSG TO POINT TO DATA MOV 2(R0),6(R1) ;STORE PRIORITY MOV R5,10(R1) ;POINT AT MESSAGE BUFFER (R5 STILL FROM PRILOC) MOV 6(R0),R4 ;MSG SIZE AGAIN NOW (DATA AREA) ;PREPARE TO COPY DATA INTO TASK SPACE ;NOTE THAT MSG HEADER RECEIVED IS 12 LONG (BASE 8) AND NODE IN TSK SPACE IS ;14 LONG SINCE TYPE OF MESSAGE WORD IS NOT NEEDED NOW. ADD #<12+1>,R4 ;NO. BYTES TO COPY (ROUND UP BY ADDING 1) ;NOTE: ALLOC ROUTINE PASSES HEADERS ALREADY... ASR R4 ;ENWORD (MTPI/MFPI ARE WORD INSTS) X.XX=0 .IIF DF,SAXCL,X.XX=1 ;.IIF DF,M$GE,X.XX=1 ;SEE IF MEM MGT NEEDED .IF NE,X.XX 3$: MOV (R0)+,-(SP) ;MOVE A WORD FROM OUR BUFFER MTPI (R5)+ ;TO TSK SPACE (U.LDR OR U.ALD ABOVE DONE) .IFF 3$: MOV (R0)+,(R5)+ ;COPY A WORD .ENDC SOB R4,3$ ;DO ALL WORDS ;COUNT UP MESSAGE-IN AST'S IN AST QUEUE BLOCK. MOV TCBAQB(R2),R5 INC 2(R5) ;COUNT ANOTHER PENDING MESSAGE IN MOV TCBSCB(R2),R5 ;POINT AT SCRATCH CONTROL TO SEE ABOUT OLD STS ;NOTE-- 14(R5) IS STATUS FOR EXIT AST; 15(R5) FOR MSG AST TSTB 15(R5) ;LOOK AT OLD STATUS WORD ;IF OLD STAT SAVED, LEAVE ALONE. BNE 17$ ;IF NOT, SAVE OLD STATUS NOW... ;SAVE OLD STATUS TILL ALL AST'S DONE. MOVB TCBST(R2),15(R5);IN SCRATCH TBL ;17$: MOVB #11,TCBST(R2) ;SET AST-QUEUED STATUS TSTB 15(R5) ;WAS OLD STATUS DISABLED? BPL 18$ ;IF NOT, NO MODIFICATION NEEDED BISB #200,TCBST(R0) ;IF SO, DISABLE 17$: ;COME HERE SO AN AST WILL NOT BE INTERUPTED 18$: JSR R5,S.RRES ;RESTORE REGS BEFORE LEAVING... RTS PC ; ;TASK EXIT OR TASK ABORT MESSAGES... GINTXX: JMP INTXXX TSKXIT: JSR PC,REBRDC ;REBROADCAST MESSAGE IF NEEDED BCS GINTXX ;IF CS, THIS CPU SHOULD IGNORE MSG MOV (R0),R3 ;GET TASK NAME JSR PC,ATLOOK ;FIND IT (IF POSSIBLE) BEQ GINTXX ;IF FAIL, GO ;CHECK THAT THE EXIT SEEN IS IN THE CPU WE THINK IT'S IN. ;IF NOT, COULD BE A PHANTOM FROM FAR OFF IN NET AND SHOULD BE IGNORED. CMPB MX.CPU,TCBCPU(R2) ;TASK HERE? BEQ GINTXX ;YES, CAN'T HAPPEN SO IGNORE (DUE TO NET ;ROUTING LOOPS). CMPB TCBCPU(R2),2(R0);MSG IN CPU WE HAVE SAID? BNE GINTXX ;IF NOT, IGNORE. NOT REALLY EXIT/ABORT .IF DF,CMNTCB MOV R0,-(SP) MOV R2,R0 JSR PC,TCBGET ;ACQUIRE TCB ACCESS RIGHTS MOV (SP)+,R0 .ENDC MOVB #1,TCBPR(R2) ;IF SUCCEED, SET ALREADY DONE ERR ROUTINE ;THIS IS A KLUDGE TO ALLOW THE ABORT STATUS TO REMOVE THE TASK MOV #1,12(R0) ;FILL IN TASK EXIT STATUS BR TX.CM TSKABT: JSR PC,REBRDC ;REBROADCAST MESSAGE IF NEEDED ;NOTE REBRDC DECREMENTS COUNT OF RETRANSMITS. IF >0, TRANSMITS EITHER ;TO ALL CPU'S ON BUSSES OTHER THAN THE ONE IT WAS RECEIVED ON, OR TO ;THE CPU TO LOOK AT MSG. IF THE LATTER, IT RETURNS WITH C BIT SET. BCS GINTXX ;IF CS, THIS CPU SHOULD IGNORE MSG MOV (R0),R3 ;GET TASK NAME JSR PC,ATLOOK BEQ GINTXX ;IF NOT THERE, LEAVE ;CHECK THAT THE EXIT SEEN IS IN THE CPU WE THINK IT'S IN. ;IF NOT, COULD BE A PHANTOM FROM FAR OFF IN NET AND SHOULD BE IGNORED. CMPB TCBCPU(R2),2(R0);TASK IN CPU MSG HAS SAID? BNE GINTXX ;IF NOT, IGNORE. NOT REALLY EXIT/ABORT .IF DF,CMNTCB MOV R0,-(SP) MOV R2,R0 JSR PC,TCBGET ;ACQUIRE TCB ACCESS RIGHTS MOV (SP)+,R0 .ENDC TX.CM: ;NOTE: WE MUST PERMIT EXIT MESSAGES WHERE THE TASK BEING ABORTED IS ;IN ANOTHER CPU BUT THE CALLER IS IN THIS CPU TO NOTIFY THE CALLER. ;THUS, ALLOW THE CHECK OF THE CALLER HERE ALWAYS. CMPB MX.CPU,TCBCPU(R2) ;THIS CPU? BEQ 8$ ;IF SO, NO NEED TO FILL STATUS IN ;PRESUME THAT A MESSAGE HAS THE CORRECT EXIT STATUS AND EV TO BUMP ;FROM WHEREVER THE TASK EXITED. HOWEVER, IF THE TASK IS HERE, OUR INFO ;SHOULD BE THE BEST AVAILABLE SO USE IT. .IF DF,CMNTCB MOV R0,-(SP) MOV R2,R0 JSR PC,TCBGET ;ACQUIRE TCB ACCESS RIGHTS MOV (SP)+,R0 .ENDC MOV 12(R0),TCBSTT(R2) ;FILL IN ERROR STATUS MOV 4(R0),TCBKEV(R2) ;FILL IN CALLER EV TO BUMP .IF DF,CMNTCB MOV R0,-(SP) MOV R2,R0 JSR PC,TCBFRE MOV (SP)+,R0 .ENDC 8$: JSR R5,S.RSAV ;SAVE REGS MOV @TCBSPW(R2),R3 ;GET SPAWN TASK TABLE TCB ADDRESS MOV R2,R0 ;POINT R0 AT CALLED TCB (THE ONE EXITING) JSR PC,ATLOOK ;FROM NAME BEQ 7$ ;IF NONE IGNORE CMPB TCBCPU(R2),MX.CPU ;CALLER HERE? BNE 7$ ;NO, HANDLE VIA MSG JSR PC,QXTAST ;YES. QUEUE HIM AN EXIT AST ;NOW SET CALLER'S STATUS AS HAVING EXIT AST QUEUED AFTER SAVING ;OLD STATUS... MOV TCBSCB(R2),R5 ;GRAB SCB ADDR HERE ADD #14,R5 ;POINT AT OLD STATUS BYTE ;IF OLD STATUS NONZERO, LEAVE IT ALONE. ELSE FILL IN FROM CURRENT. TSTB @R5 ;ANYBODY HOME? BNE 37$ ;YEP. BEST LEAVE HIM BE... MOVB TCBST(R2),@R5 ;NO. SAVE THE OLD STATUS HERE FOR LATER. ;37$: MOVB #12,TCBST(R2) ;AND SET AST QUEUED STATUS UP TSTB @R5 ;WERE WE DISABLED? BPL 7$ ;NO, SKIP BISB #200,TCBST(R2) ;YES, DISABLE NOW TOO... 37$: ;COME HERE SO AST'S WILL NOT BE INTERRUPTED BY OTHER AST'S 7$: JSR R5,S.RRES ;RESTORE REGS CMPB MX.CPU,TCBCPU(R2) ;OUR CPU? BEQ X1$ ;YES, ALL IS WELL ;MAINTAIN STATISTICS ALSO ;ENTRY TO DECLARE A TASK EXITED IF NO ROUTE TO IT, OR IF JUST EXIT BROADCAST OTHXIT: .IF DF,CMNTCB MOV R0,-(SP) MOV R2,R0 JSR PC,TCBGET ;ACQUIRE TCB ACCESS RIGHTS MOV (SP)+,R0 .ENDC MOVB TCBCPU(R2),R3 ;GET CPU NUMBER CLRB TCBBUS(R2) CLRB TCBCPU(R2) DEC R3 ASL R3 DEC CPU.PR(R3) ;COUNT DOWN CPU USE CLRB TCBST(R2) ;NO, SET EXITED STATUS NOW CLRB TCBPR(R2) ;ALSO ABORT DONE CLR TCBDSP(R2) ;ALSO NO DYNAM. SP. CLR TCBKEV(R2) ;ALSO KNL EV (JUST IN CASE...) CLR TCBSTT(R2) ;ALSO STATUS WORD .IF DF,CMNTCB MOV R0,-(SP) MOV R2,R0 JSR PC,TCBFRE ;GIVE UP TCB ACCESS RIGHTS MOV (SP)+,R0 .ENDC BR INTXXJ ;THEN GO X1$: MOVB #10,TCBST(R2) ;OUR CPU; FLAG ABORT QUEUED BISB #2,TCBPR(R0) ;FLAG NO MORE MESSAGES BY XNOTFY MOV 4(R0),TCBKEV(R2);SET EV TO BUMP TOO. .IF DF,CMNTCB MOV R0,-(SP) MOV R2,R0 JSR PC,TCBFRE ;GIVE UP TCB ACCESS RIGHTS MOV (SP)+,R0 .ENDC INTXXJ: JMP INTXXX ;THEN LEAVE ; ;INCREMENT (OR ADD CONST TO) GLOBAL EVENT VARIABLE GINCEV: JSR PC,REBRDC BCS INTXXJ ;HANDLE MESSAGE RETRANSMISSION ON A POSSIBLE NET ;NOTE 1-BUS SYSTEMS ALWAYS HAVE XMIT COUNT 1 (IN GENERAL IT IS THE ; GREATEST DISTANCE ON THE NET) SO THE REBRDC ALWAYS ACTS AS A NOOP MOV 12(R0),R5 ;GET NUMBER TO ADD BNE 2$ ;IF NONZERO OK NOW INC R5 ;IF ZERO MAKE IT 1 2$: MOV 4(R0),R4 ;ADDR TO BUMP BEQ INTXXJ ;ZERO IS ILLEGAL BIT #1,R4 ;BE SURE EVEN TOO BNE INTXXJ CMP #-1,@R0 ;SEE IF ITS FOR KERNEL BNE 1$ ;IF NOT IT'S FOR TASK ADD R5,@R4 ;IF SO ITS FOR KERNEL BR INTXXJ ;SO DO IT AND GO 1$: MOV (R0)+,R3 ;TASK NAME OR NUMBER JSR PC,ATLOOK ;FIND TCB ENTRY BEQ INTXXJ ;IF NONE, IGNORE MSG MOV R2,R0 ;ADDRESS TCB WITH R0 (U.LDR OR U.ALD EXPECT) .IF DF,SAXCL ;S/A SYS JSR PC,U.LDR MOV @#PS,-(SP) BISB #340,@#PS ;NO INTS MFPI @R4 ;GET EV IN TSK SPACE ADD R5,@SP ;MODIFY IT MTPI @R4 ;STORE MOV (SP)+,@#PS .IFF .IF DF,M$GE ;RSX MAPPED SYS JSR PC,U.ALD MOV @#PS,-(SP) BISB #340,@#PS ;NO INTS MFPI @R4 ;GET EV IN TSK SPACE ADD R5,@SP ;MODIFY IT MTPI @R4 ;STORE MOV (SP)+,@#PS .IFF ADD R5,@R4 ;RSX UNMAPPED OR DOS .ENDC .ENDC INTXJJ: JMP INTXXX ;FINISH UP ; ;TASK INITIATE MESSAGE -- INDICATES TASK TO START UP (FROM A REQUEST) ; TSKINI: JSR PC,REBRDC ;RE-EMIT MSG IF NEEDED BCS INTXXJ BISB #340,@#PS ;TO PRI 7 (MUSTN'T INTERRUPT TASK STARTUP) MOV 2(R0),R3 ;CALLED TASK NUMBER OR NAME JSR PC,ATLOOK ;HUNT UP THE TCB ADDR HERE .IF NDF,DY$MEM BEQ INTXXJ ;IF NONE, CAN'T HACK IT...GO AWAY .IFF BNE 40$ ;IF WE GOT IT ALL IS WELL JSR PC,NAMSRV ;SEE IF WE CAN GET A NAME FROM DISK BCC 41$ ;IF ALL IS WELL R2 HAS A TCB NOW ;NOTIFY CALLER WE CANNOT RUN HIS TASK VIA AN EXIT BROADCAST! CMPB 10(R0),MX.CPU ;ONLY TELL CALLER IF WE SHOULD HAVE RUN IT BNE INTXJJ ;IF FOR ELSEWHERE, OK NOT TO KNOW HERE. ;DRAT! WE HAD TO RUN IT! MAKE UP AN EXIT B/C TO FAKE IT OUT. JSR PC,GETNOD ;GET A SPACE CMP R1,#4 BLOS INTXJJ ;IF NO ROOM FOR B/C, FORGET IT. MOV R1,R4 ;COPY IT MOV #3,(R1)+ ;ABORT B/C MOV 2(R0),(R1)+ ;ABORTED TSK NAME MOVB MX.CPU,(R1)+ MOVB MX.BUS,(R1)+ ;CPU/BUS MOV 14(R0),(R1)+ ;EV FOR CALLER MOV MX.CON,(R1)+ ;NET RE-XMIT COUNT CLR (R1)+ ;MSG IS FOR ALL MOV #-5,(R1)+ ;STATUS -5 = NO ROOM! MOV MX.BUS,R3 JSR PC,ROUTE JSR PC,MGXMTR ;SEND/REMOVE A MESSAGE BR INTXJJ ;THEN DONE HERE. 41$: CLR TCBDSP(R2) ;BE SURE TASK NOT MARKED GOING NOW 40$: .ENDC CMPB 10(R0),MX.CPU ;THIS REQUEST FOR THIS CPU OR NOTICE ONLY? BNE 11$ ;JUST NOTICE...DON'T START TASK UP .IF DF,CMNTCB MOV R0,-(SP) MOV R2,R0 JSR PC,TCBGET ;ACQUIRE TCB ACCESS RIGHTS MOV (SP)+,R0 .ENDC ; ;NOW TEST THAT THE TASK IS NOT ALREADY ACTIVE HERE. IF SO AND IF ;NOT A RESUME (MSG RESUME ADDRESS=0), IGNORE THE MESSAGE. TST 12(R0) ;IS RESUME ADDRESS NONZERO? BNE 30$ ;YES, BRANCH AND DO THE STARTUP THERE ;TEST THAT WE THINK THE TASK IS HERE NOW... CMPB TCBCPU(R2),10(R0) ;TASK IN THIS CPU NOW? BNE 30$ ;NO, MAKE IT BECOME ACTIVE HERE. ;TASK MARKED AS HERE AND WE WANT TO ACTIVATE IT. START IT HERE IF NOT NOW ON. TST TCBDSP(R2) ;IS THE TASK ACTIVE HERE NOW? BNE INTXXJ ;YES, IGNORE THE MESSAGE 30$: ;HERE HAVE TO START A TASK IN THIS CPU. NEEDS A LITTLE FAKERY... ; HAVE TO GET BACK REGS ; SAVE SOME INFO ACROSS THIS... ADD #6,R0 MOV 4(R0),CALRSA ;SAVE RESUME ADDR IF ANY MOV 6(R0),SPNOWN ;SAVE OWNER TASK NAME (MUST STILL LOOK UP TCB) MOV 10(R0),CALEVA ;SAVE CALLER TASK EV ADDRESS MOV R2,TCBPTR ;SAVE THIS TASK TCB ADDRESS ;START NEXT MESSAGE IN NOW. JSR PC,RDMSG ;START A NEW MESSAGE IN JSR R5,S.RRES ;GET BACK TASK REGS ;NOW LOOKS LIKE AFTER A TRAP .IF DF,SAXCL JSR PC,U.RSAV .IFF JSR R5,S.RSAV ;SAVE REGS FIRST .IF DF,M$GE JSR PC,A.PRSV ;SAVE APR'S .ENDC ;U.RSAV SAVES DYNAMIC SP BUT A.PRSV DOES NOT ;SAVE IT HERE MOV MX.TCB,R1 ;GET THIS TASK TCB NAME BEQ 2$ ;IF NONE, DON'T BOTHER MOV SP,TCBDSP(R1) ;SAVE DYNAMIC SP IF ONE IS THERE 2$: .ENDC MOV TCBPTR,R0 ;POINT AT OUR TCB MOV SPNOWN,R3 ;GET CALLER NAME JSR PC,ATLOOK ;HUNT UP TCB ADDR HERE ;R2 RETURNS AS 0 IF NO TASK HERE... MOV R3,@TCBSPW(R0) ;SAVE AS CALLER TASK MOV CALEVA,TCBKEV(R0) ;SAVE CALLER TASK EV ADDR ;HANDLE ANY RESUME ADDRESS IF TASK ACTIVE... MOV CALRSA,R1 ;GET RESUME ADDRESS BEQ 1$ ;ZERO MEANS NONE BIT #1,R1 ;ODD ALSO MEANS NONE BNE 1$ .IF NDF,SAXCL MOV TCBDSP(R0),R3 ;GET SP BEQ 1$ ;IF NONE, CAN'T RESUME INACTIVE TSK .IF NDF,REL$SP MOV R1,22+A$PROF(R3);SAVE NEW PC AS WHERE TASK WILL GO ON .IFF .IIF DF,CMNTCB, JSR PC,TCBGET CMPB MX.CPU,TCBCPU(R0) ;TASK HERE? BEQ 4$ ;IF SO, LOCAL UPDATE MOV R1,@R3 ;REMOTE UPDATE CHANGES @TCBISP(R0) BR 5$ 4$: MOV R1,22+A$PROF(R3);SAVE NEW PC AS WHERE TASK WILL GO ON 5$: .IIF DF,CMNTCB, JSR PC,TCBFRE .ENDC .IFF ;STANDALONE HAS PC IN TCB MOV R1,54(R0) ;OVERWRITE DYNAMIC PC .ENDC 1$: ;FLAG THE TASK STARTER THAT THIS IS AN EXTERNAL REQUEST BY ;SETTING A BIT (BIT 2) IN TCBPR TO INHIBIT THE ACTIV8 CALL ;SINCE THAT CALL SHOULD HAVE BEEN ACTED ON BY THIS MESSAGE ;IN ALL OTHER CPU'S. CMPB MX.CPU,TCBCPU(R0) ;THIS TASK IN THIS CPU ALREADY? BEQ 24$ ;YES, NO NEED TO MARK ANOTHER STARTUP CLR TCBDSP(R0) ;NO, FLAG START CLEAN BISB #2,TCBPR(R0) ;FLAG AN EXTERNAL REQUEST 24$: ; .IIF DF,CMNTCB, JSR PC,TCBFRE ;GIVE UP TCB ACCESS RIGHTS JMP MX.RQS ;GO FINISH STARTING THE TASK 11$: ;START A TASK ON ANOTHER CPU...JUST MARK IT ACTIVE FOR US ;HANDLE RACE CONDITION OF TASK ACTIVE HERE AND BEING STARTED ALSO ;SOMEWHERE ELSE BY FLAGGING THE TASK FOR ABORT HERE. THIS CAN HAPPEN ;WHERE 2 CPU'S REQUEST A TASK SIMULTANEOUSLY IN DIFFERENT PLACES ;AND ONE STARTS BEFORE THE SIGNAL OF THE OTHER'S REQUEST ARRIVES. .IF DF,CMNTCB MOV R0,-(SP) MOV R2,R0 JSR PC,TCBGET ;ACQUIRE TCB ACCESS RIGHTS MOV (SP)+,R0 .ENDC CMPB MX.CPU,TCBCPU(R2) ;TASK NOW IN THIS CPU? BNE 15$ ;NO, OK TO SIMPLY NOTICE WHERE ;IT IS. TST TCBDSP(R2) ;TASK REALLY ACTIVE NOW? BEQ 15$ ;NO, IGNORE. MOVB #10,TCBST(R2) ;YES, FLAG TASK FOR ABORT MOV #4,TCBSTT(R2) ;STATUS=4=NET ERROR BR 12$ ;THEN SKIP THE REST. ;(THIS SHOULD BE OK SINCE BOTH CPU'S WILL EVENTUALLY EXIT AND SEND MESSAGES ;ALLLOWING THE TASK TO BE MARKED EXITED EVEN THOUGH WE DON'T KNOW WHICH ;CPU THE TASK WILL BE MARKED AS IN; THE EXIT SHOULD ARRIVE AFTER THE ;ACTIVATION AND THE EXTRA EXIT SHOULD BE IGNORED.) ;**** ;IF THE TASK EXIT ARRIVES BEFORE THE TASK REQUEST, WE CAN GET INTO TROUBLE ;HERE, BUT I CAN'T SEE HOW THAT COULD HAPPEN. ;**** 15$: MOVB 10(R0),TCBCPU(R2) MOVB 11(R0),TCBBUS(R2) ;FILL IN TASK CPU AND BUS MOV 14(R0),@TCBSPW(R2) ;FILL IN CALLER TASK MOV 16(R0),TCBKEV(R2) ;SAVE CALLER EV ;NOTE: IF THE TCB IS SHARED, ONE SHOULD NOT SEND THESE MESSAGES AND ;ACTIV8 WILL NOT GENERATE CALLS HERE. FOR HYBRID SYSTEMS THIS PRESUMES ;THIS ROUTINE (AND ITS TCB MODS) ARE DONE ONLY IN SEPARATE SECTIONS OF ;CODE; THEY ARE NOT INTERLOCKED AGAINST MULTI-CPU ACCESS IN SHARED ;MEMORY... CLR TCBSTT(R2) CLRB TCBPR(R2) ;CLEAR ANY LEFTOVER STATUSES MOVB #4,TCBST(R2) ;SET RUNNING STATUS (BUT ANOTHER CPU) MOV TCBDSP(R2),R3 ;GET DYNAMIC SP BNE 12$ ;ALREADY NONZERO...ALLOW TO STAY THAT WAY ;DYNAMIC SP WAS ZERO, SO SET NONZERO AS A FLAG FOR LATER MOV TCBISP(R2),TCBDSP(R2) ;(VALUE MUST BE NON-0, BUT SHOULD BE ;LEGAL SO RESUMES WILL WORK FOR RSX VERSION) MOVB 10(R0),R1 ;GET CPU NUMBER ASL R1 ;ENWORD INC CPU.PR-2(R1) ;COUNT UP CPU USAGE OF THAT TASK'S CPU 12$: .IF DF,CMNTCB MOV R0,-(SP) MOV R2,R0 JSR PC,TCBFRE ;GIVE UP TCB ACCESS RIGHTS MOV (SP)+,R0 .ENDC JMP INTXXX ;CONTINUE THE MESSAGES IN... ; .PSECT MSGIDT,RW,D CALRSA: .WORD 0 ;RESUME ADDR TCBPTR: .WORD 0 ;TASK TCB ADDR SPNOWN: .WORD 0 ;CALLER TASK (FOR SPAWN) CALEVA: .WORD 0 ;CALLER TASK EV ADDR (INC ON SPWN TSK EXIT) CCSAVE: .WORD 0 ;SAVE FOR PSW ON INTERRUPT ;N.B. - THIS BUFFER'S SIZE IS THE LIMIT ON MESSAGE SIZE. MAKE SOMEWHAT ;LARGER THAN A DISK BLOCK TO PERMIT PROTOCOL INFORMATION TO BE PREFIXED ;TO THE DATA. .GLOBL MSGDT ;USED IN MXCONN MSGDT: .BLKW 340. ;AREA FOR INPUT DATA INCLUDING PREFIX ; .ENDC ; ;-- THATS IT FOLKS .END MX.BGN ; THIS IS PROGRAM'S ENTRY