M.MMP=0;THIS IS A MULTIPROCESSOR MONITOR! ;STAND ALONE VERSION OF MXTRAP IS CONDITIONED BY ; $$DOS AND NODOS BOTH DEFINED. .IF DF,$$DOS .IF DF,NODOS SAXCL=0 ;STAND-ALONE DUAL MODE CONDITION IF DEFINED .ENDC KAPR0=172340 .ENDC .TITLE MXTRAP V004 MSX TRAP (DIRECTIVE) HANDLER ;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 DF,M$GE ;IF MEMORY MANAGING MSX IS TO BE DONE .GLOBL A.PRSV,A.PRRS .GLOBL MAPPER,MAPOFF TCBAP1=14 ;USE TCB CELL FOR INITIAL APR 1 CONTENTS. OTHERS UNDEFINED. 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 .IF DF,SAXCL .IIF DF,TP$ALL,AL$APR=0 .PSECT AABVEC,RW,D,GBL,OVR,ABS ZERMEM: ;LOW MEMORY VECTOR AREA FOR MSX0 SYSTEM .WORD 137,MX.BGN ;ZERO START .WORD MX.FTL,340 ;ODD ADDRESS, PRI 7 .WORD MX.FTL,340 ;ILLEGAL INSTRUCTION, PRI 7 .IF NDF,TP$ALL .WORD MX.IOT,340 ;BPT INITIALLY LIKE IOT .WORD MX.IOT,340 ;IOT TRAP .WORD MX.KIL,340 ;POWERFAIL TRAP TO MX.KIL .WORD MXEMT,340 ;EMT VECTOR TO QUICK RUN/XIT .WORD MX.TRP,340 ;TRAP INSTRUCTION TO MX.TRP .IFF .WORD TKBPT,340 ;BPT INTERCEPTOR .WORD TKIOT,340 ;IOT INTERCEPTOR .WORD MX.KIL,340 ;POWERFAIL TRAP TO RESTART ADDRESS... .WORD TKEMT,340 ;EMT INTERCEPTOR .WORD TKTRP,340 ;TRAP INTERCEPTOR .ENDC .=ZERMEM+40 ;SYSTEM VECTORS .WORD MX.TBL ;SYSTEM TASK LIST POINTER, 40 .IF DF,VARPRI .WORD MX.PRL ;PRIO LIST POINTER, 42 .IFF .WORD 0 .ENDC .WORD S.RSAV ;REG SAVE/RESTORE AS IN DOS, 44 .WORD S.RRES ; 46 .WORD S.BFA ;BUFFER ALLOCATE .WORD S.BRL ;BUFFER RELEASE, 52 .WORD MX.NSZ ;SYSTEM NODE POOL CONTROL AREA, 54 .WORD 0 ;(RESERVED FOR MEM MANAGEMENT AREA MAP CONTROL), 56 .=ZERMEM+60 ;KEYBOARD VECTORS .WORD MX.KBL,340 ;INPUT INTERRUPT .WORD KBOINT,340 ;OUTPUT INTERRUPT .GLOBL MX.KBL,KBOINT .=ZERMEM+100 ;CLOCK VECTORS .IF DF,MX$CLK .GLOBL CLKINT .WORD CLKINT,340,CLKINT,340 ;KW11P OR KW11L .ENDC .=ZERMEM+214 ;DECTAPE VECTOR .WORD DTINT ;DECTAPE INTERRUPT .WORD 340 ;PRI7 .=ZERMEM+200 ;LP VECTOR .WORD LPINT,340 .=ZERMEM+350 ;MEM. MGT. TRAP .WORD MX.FTL,340 ;ACT LIKE ODD ADDR... .=ZERMEM+1000 .WORD 0,0 ;FENCE ABOVE INT. VECTORS FOR RANDOM STUFF .PSECT ; .ENDC ; ; TRAP INTERCEPTORS ; ; THESE SECTIONS OF CODE ALLOW MSX-11 TASKS TO CONTAIN THEIR OWN ;TRAPS AND EMT'S AND PRESUME THAT MSX-11 CALLS ARE NOT DONE BY SEPARATE ;TRAPS BUT ARE DONE BY THE SINGLE TRAP CALL "TRAP 375", FOLLOWED BY THE ;CODE THAT WOULD FORMERLY HAVE BEEN THE TRAP CODE. ALL OTHER TRAPS WILL ;BE PASSED, IF A TASK WAS ACTIVE, TO THE TASK IF IT HAS SPECIFIED A ;TRAP LOCATION IN ITS INITIAL APR BLOCK. OTHERWISE, THE TRAPS WILL BE ;FORWARDED VIA A SYSTEM TABLE "TKSYST". ; ; ; ;TRAP CALLS ARE OF FORM (FOR MSX CALLS) ; (PUSH ARGS ONTO STACK) ; TRAP 375 ;CALL MSX11 ; .WORD CODE ;SPECIFY WHAT TO DO... ; ; .IF DF,TP$ALL .GLOBL TKIOT,TKBPT,TKEMT,TKTRP,TKREMT,TKRTRP TKTRP: MOV (SP),-(SP) ;COPY CALLING PC SUB #2,(SP) ;GET CALL ADDRESS .IF DF,SAXCL MFPI @(SP)+ ;GET TRAPPING INSTRUCTION .IFF MOV @(SP)+,-(SP) .ENDC CMP (SP)+,(PC)+ ;COMPARE TO MSX SYSTEM CALL TRAP 375 ;(*** LITERAL FOR MSX SYSTEM CALL***) BNE TKTRP2 ;IF NOT SAME, SEE IF TASK WANTS THE TRAP ADD #2,(SP) ;IF NOT, POINT RETURN PC PAST CODE WORD JMP MX.TRP ;AND APPEAR TO BE DOING A NORMAL TRAP TKIOT: MOV #2,-(SP) ;PUSH CODE FOR IOT (2ND) BR TKCMN TKBPT: CLR -(SP) ;PUSH A 0 BR TKCMN TKTRP2: MOV #6,-(SP) ;PUSH A 6 = OFFSET TO TRAP SAVED VECTOR BR TKCMN TKEMT: MOV #4,-(SP) ;PUSH OFFSET TO EMT SVC AREA BR TKCMN TKREMT: TST (SP)+ ;FLUSH EXTRA RSX STACK WORD BR TKEMT TKRTRP: TST (SP)+ ;FLUSH EXTRA RSX STACK WORD BR TKTRP TKCMN: MOV MX.TCB,-(SP) ;GET TCB OF ACTIVE TASK BEQ TKER2 ;IF NONE, USE SYSTEM TRAP LIST .IF DF,SAXCL BIT #140000,4(SP) ;SEE IF WE CAME FROM KERNEL MODE BEQ TKER2 ;IF SO, HAVE TO SAY NOT FROM TASK... .ENDC ADD #TCBAP1,(SP) ;FORM ADDRESS OF TCBAP1 TABLE ADDRESS MOV @(SP)+,-(SP) ;NOW GET THE ADDRESS ITSELF .IF DF,SAXCL ADD #16.,(SP) ;PASS SAVED APR'S .IFF ;OTHERWISE, RSX VERSION WITH 6 APR'S .IIF DF,M$GE, ADD #12.,(SP) .ENDC ;NOW ADD THE SAVED OFFSET TO THE TRAP VECTOR IN THE TABLE ;THESE ARE IN THE ORDER ; BPT ; IOT ; EMT ; TRAP (I.E., JUST AS IN REAL CORE). ; ; THESE TRAP VECTORS ARE SET UP BY THE MSX TRAP CALL THAT SETS UP ;OR MODIFIES SYSTEM INFORMATION OR READS IT. ; THEY MAY BE SET UP INITIALLY ALSO IF THE TCB IS SET UP ;STATICALLY IN THAT WAY. ONLY VECTORS, NOT PSW'S, ARE SET UP ;OR USED. ; ADD (SP)+,(SP) ;NOW WE POINT AT THE TASK TRAP VECTOR MOV @(SP)+,-(SP) ;GRAB THE TRAP VECTOR ADDRESS ;ALLOW MSX TO HANDLE THE CASE OF TASKS USING THE TRAP INSTRUCTION DIRECTLY ;TO DO DIRECTIVES BY PASSING CONTROL TRANSPARENTLY WHEREVER MSX HAS NO ;TASK TRAPS DECLARED (OR NONE FOR THIS CASE...). NOTE THAT FOR SECURITY, ;MSX SHOULD CHECK THE ADDRESSES, BUT FOR NOW IT DOES SO NOWHERE VERY ;MUCH. .IF DF,TP$FTL BEQ TKERR ;IF ZERO, NONE THERE SO TREAT AS FATAL .IFF ;DEFAULT AND USUAL CONDITION- ALLOW COMPATIBLE TRAPS WITH OLD BSX SYSTEM. BEQ TKER2 ;IF ZERO, USE SYSTEM TRAPS FOR COMPATIBILITY .ENDC BIT #1,(SP) ;IF ODD, ALSO IGNORE BNE TKERR ;(AN ODD TRAP ADDRESS IS FATAL!!) .IF DF,SAXCL MOV R0,-(SP) ;NEED A REGISTER MFPI SP ;GET USER SP ADD #4,(SP) MOV (SP),R0 ;POINT R0 AT USER SP MTPI SP ;UPDATE USER MODE STACK POINTER ;NOW FILL IN PS,PC ON USER STACK TO ALLOW RTI FROM THERE. MOV 4(SP),-(SP) ;GET PRE-TRAP PC MTPI (R0)+ ;FILL INTO USER MODE MOV 6(SP),-(SP) ;GET OLD PS TOO MTPI @R0 MOV (SP)+,R0 MOV (SP)+,(SP) ;REPLACE OUR RETURN WITH TASK TRAP ADDRESS .IFF MOV (SP),-(SP) ;OTHERWISE SET UP A NEW RETURN PC MOV 4(SP),2(SP) ;AND COPY PS .ENDC RTI ;THEN GO TO TASK ROUTINE TKERR: TST (SP)+ ;FLUSH EXTRA STACKED WORD ON STACK JMP MX.FTL ;AND TREAT ERROR AS FATAL TO TASK ;FOR TRAPS WITH NO TASK, USE SYSTEM TRAP TABLES TKER2: TST (SP)+ ;FLUSH PUSHED TCBADDR=0 ADD #TKSYST,(SP) ;GET ADDRESS OF SYSTEM'S TRAP HANDLER JMP @(SP)+ ;GO THERE ; ;SYSTEM TRAP TABLE ADDRESSES: ; TKSYST: .WORD MX.FTL ;BPT .IF DF,$$DOS .WORD MX.IOT ;IOT HANDLER (STD ALONE) .IFF .WORD MX.QUE ;IOT (RSX) .ENDC .IF DF,SAXCL .WORD MXEMT .IFF .WORD MX.FTL .ENDC .WORD MX.TRP ;TRAP HANDLER .ENDC ; ; MX.IOG ;START I/O FROM KERNEL MODE BY FAKING UP A "TASK CONTEXT" ; ; THIS ENTRY WILL EFFECT A QTRAN AND WAIT SEQUENCE FROM KERNEL MODE ; BY FAKING OUT THE REST OF THE SYSTEM. IT SETS UP A FAKE "TCB" ; FOR KERNEL MODE AND A FAKE EVENT VARIABLE, AND SETS MX.ATL TO POINT ; TO THIS TCB, WHICH MUST IMMEDIATELY PRECEDE MX.TBL. ; .IF DF,SAXCL ;(THIS IS NEEDED IN STANDALONE ONLY) .GLOBL KNLTCB ;KNLTCB IS SPECIAL FAKED UP TCB ;N.B. ALL WE NEED DO IS SET UP MX.ATL AND REMEMBER THAT KNLTCB ;IS OF TASK NAMED "$$$". HOWEVER, NAME SEARCH STARTS AT MX.TBL SO ;WILL NEVER FIND IT (OR GET CONFUSED BY IT). .GLOBL KNLQIO ;KNLQIO WILL START I/O UP VIA NORMAL-LIKE OPERATIONS, THEN ;WAIT FOR I/O. ON ENTRY, EXPECT: ; R1 = ADDRESS OF EV ; R2 = ADDRESS OF QTRAN BLOCK ; R3 = LUN NUMBER ; CALL VIA JSR PC,KNLQIO ; KNLQIO: JSR PC,U.RSAV ;SAVE ANY OLD CONTEXT IF NOT DONE NOW MOV #30340,@#PS ;TO PRI 7 AWHILE... MOV MX.TCB,R0 ;GET OLD TSK BEQ 101$ ;SKIP BLOCK IF NO TASK BISB #200,TCBST(R0) ;BLOCK IT FROM EXECUTING WHILE WE DO I/O 101$: MOV MX.TCB,TCBSAV ;SAVE OLD MX.TCB LOCALLY FOR RESTORE MOV #KNLQIO,MX.TCB MOV #KNLQIO,MX.ATL ; NOW SET UP KNLTCB AS SAME AS KERNEL MODE MOV #KNLTCB,R0 ;POINTER THE TCB WITH R0 MOV TCBISP(R0),TCBDSP(R0) MOVB #4,TCBST(R0) ;SET RUNNING STATUS MOV #KAPR0,R4 ;POINT AT KNL APR0 ADD #34,R0 ;POINT AT TCB UAPR0 SAVE MOV #8.,R5 1$: MOV (R4)+,(R0)+ ;SAVE AN APR DEC R5 BGT 1$ ;DO ALL 8 FROM KNL SPACE MOV #KNLTCB,R0 ;POINT R0 AT KNL TCB AGAIN JSR PC,U.LDR ;MAP USER SPACE TO TCB SPACE NOW (=KNL) ;NOW USER AND KERNEL MAPPINGS ARE ALIKE, SO WE CAN CHANGE MODE TO USER ;WITHOUT CLOBBERING OURSELVES. MOV #KNLTCB,R0 MOV TCBISP(R0),TCBDSP(R0) MOV TCBISP(R0),-(SP) MTPI SP ;SET USER SP UP MOV #140340,@#PS ;SO GO TO USER MODE ; NOTE SPECIAL STACK FOR THIS TASK IS RIGHT HERE! .GLOBL KNLSTK ;NOTICE WE LEFT R1,R2, AND R3 ALONE. ASSUME THEY ARE SET UP ;OK AND ISSUE THE TRAPS MOV R1,-(SP) ;EV ADDRESS MOV R2,-(SP) ;QTRAN BLOCK MOV R3,-(SP) ;LUN NUMBER TRAP 10 ;DO THE QTRAN MOV R1,-(SP) ;EV ADDRESS TRAP 0 ;WAIT. FOR EV NONZERO ;NOW SHOULD BE OK TO RESUME OLD STUFF SINCE QTRAN GOT DONE... ; ; RESTORE TO OLD STATE MOV #30340,@#PS ;BACK TO KNL MODE MOV #MX.TBL,MX.ATL MOV TCBSAV,MX.TCB ;RESTORE OLD CONTEXT MOV MX.TCB,R0 BEQ 100$ ;IF NO TASK, NO NEED TO RESTORE THINGS BICB #200,TCBST(R0) ;IF SO UNBLOCK TASK 100$: MOV #30000,@#PS ;BACK TO PRI0 JSR PC,U.RRES TCBSAV: .WORD 0 ;SAVE AREA FOR OLD MX.TCB .BLKW 4 .BLKW 60. KNLSTK: .WORD 0,0,0,0,0,0,0 .ENDC ;ALLOW EMT + TSK NUMBER AS FAST REQUEST FOR TASK NUMBERED ;AND EMT WITH CODE 377 AS FAST EXIT... ; ; MXEMT ; ; THIS ENTRY HANDLES EMT INSTRUCTIONS IN THE STANDALONE MSX CONFIGURATION. ; ; AN ENTRY HERE IS AN ALTERNATE METHOD OF TASK ACTIVATION. ; ; TO ACTIVATE TASK NUMBER N (N BETWEEN 0 AND THE HIGHEST NUMBERED ; TASK IN THE SYSTEM (THE NUMBER OF STL ENTRIES), USE THE ; CODE ; EMT N ; ; ; N.B. IF THE C BIT IS CLEAR AT THE TIME OF THE EMT, THE REQUEST IS ; "NORMAL", THAT IS, IT WILL BE PRIORITY ARBITRATED. ; IF THE C BIT IS SET AT THE TIME OF THE EMT, THE ; REQUEST WILL BE HONORED IMMEDIATELY AND WITH NO PRIORITY ; ARBITRATION (THOUGH IT WILL OCCUR ON EXIT). ; ; IF AN EMT CODE OF OVER THE MAXIMUM IS SEEN (OR A NEGATIVE ; CODE), THE EMT WILL BE TREATED AS AN EXIT CALL. ; ; NOTE THAT NEITHER OF THESE METHODS ALLOW ARGUMENTS ; TO BE PASSED. TO PASS EV ARGUMENTS, THE TRAP FORMS OF MSX ; DIRECTIVES MUST BE USED. ; .IF DF,SAXCL .GLOBL MXEMT EM.CD: .WORD 0 ;EMT CODE (SAVED/USED AT PRIO 7) MXEMT: MOV (SP),-(SP) ;MAKE COPY OF EMT PC+2 SUB #2,(SP) ;BACK IT UP TO EMT PC MFPI @(SP)+ ;GET THE EMT INSTRUCTION NOW MOV (SP),EM.CD ;SAVE THE CODE CMPB (SP)+,#</MX.TBS> ;SEE IF TASK NUMBER LEGAL BHI EMXIT ;IF NOT MUST BE EXIT. LEAVE. JSR PC,U.RSAV ;IF SO MUST SAVE TASK STATUS MOV EM.CD,R1 ;THEN GET EMT CODE. ; THE ABOVE CODE ALLOWS EMT TO WORK FROM EITHER KERNEL OR USER ;SPACE, WHEREVER ACTUALLY ISSUED. ;LOOKS LIKE A REQUEST FOR A TASK. EMT CODE IS TASK NUMBER TO START UP. ASH #MX.CNT,R1 ;SHIFT TSK N# UP FOR OFFSET MOV #MX.TBL,R0 ;GET BASE ADD R1,R0 ;R0 NOW IS ADDR OF DESIRED TCB .IF DF,M.MMP .IIF DF,CMNTCB,JSR PC,TCBGET ;RESERVE THE TCB IF COMMON MEM. TST TCBDSP(R0) ;IS TASK ACTIVE (ANYWHERE?) BEQ 20$ ;NO, CAN START IT HERE IN ALL CASES CMPB MX.CPU,TCBCPU(R0) ;IF EXECUTING IS IT ON THIS CPU? BEQ 20$ ;YEAH, ALL SEEMS WELL; LET IT GO ON JSR PC,U.RRES ;NO, ERROR. IGNORE THE EMT. BR EMXIT ;BY RESTORING & GOING AWAY 20$: .ENDC ; ;IF THE C BIT WAS SET AT EMT TIME DO QUICK REQUEST. ;OTHERWISE DO NORMAL BIT #1,2(SP) ;TEST CALLER'S C BIT BEQ 1$ ;IF OFF, NORMAL REQ JMP MX.RQS ;IF ON, FAST VERSION W/O ARBITRATION 1$: MOVB #4,TCBST(R0) ;EN-READY THE TASK (END SUSPENDS, ETC.) ;*** NOTE: WE MAY NEED TO LOCK THIS ACCESS TO THE STL ;*** IN ORDER TO PREVENT RACE CONDITIONS... MOVB MX.CPU,TCBCPU(R0) ;FILL IN THIS CPU PENDING ARBITRATION CLR R2 ;NOTHING ON STACK TO ADJUST JMP SETSEV ;SO GO DO IT. .ENDC EMXIT: ; HERE DO AN EXIT. MOV MX.TCB,R0 ;GET DESIRED TCB BNE 1$ ;IF 0, IGNORE EMT CLRB @#PS ;ENSURE INTS BACK ON RTI 1$: CLR TCBDSP(R0) ;REMOVE DYNAMIC STACK CLRB TCBST(R0) ;SET EXITED STATE .IIF DF,PRLVLS, JSR PC,MX.DNU CMP R0,MX.HGH ;MAINTAIN HIGHEST ACTIVE BNE 2$ MOV #-1,MX.HGH .IF NDF,M.MMP 2$: JMP MX.SCN ;NOW FIND MORE WORK. .IFF .GLOBL REABRT 2$: JMP REABRT ;CLEAN UP & GO .ENDC .IF DF,PRLVLS .GLOBL MX.UPU,MX.DNU .ENDC ; .IF DF,CMNTCB ;ACQUIRE OR RELEASE A TCB. TCB ADDRESS IN R0. .GLOBL TCBGET,TCBFRE TCBGET: MOV R0,-(SP) SUB #MX.TBL,R0 ;FORM AN OFFSET TO TCB TABLE ASH #<-MX.CNT>,R0 ;FORM BYTE ADDRESS ADD #TCBFGS,R0 ;POINT AT BYTE TBL OF TCB'S 1$: ASRB @R0 ;SHIFT LO BIT TO CARRY BCC 2$ ;IF IT WAS 0 WE HAVE IT. ADD #,R0 ;POINT AT OWNER CPU NO. CMPB MX.CPU,@R0 ;SEE IF WE HAD IT ALREADY BEQ 2$ ;IF SO DON'T WAIT TO GET TCB AGAIN SUB #,R0 ;ELSE ADJUST R0 BACK .IF DF,$$DOS WAIT ;ELSE WAIT AND RETRY .IFF .MCALL WSIG$S WSIG$S .ENDC BR 1$ 2$: ADD #,R0 MOVB MX.CPU,@R0 ;SAY WE GOT THE TCB MOV (SP)+,R0 RTS PC TCBFRE: MOV R0,-(SP) SUB #MX.TBL,R0 ;MAKE OFFSET, THEN... ASH #<-MX.CNT>,R0 ;MAKE TSK NO. ADD #TCBFGS,R0 ;POINT AT TASK'S BYTE 1$: MOVB #376,@R0 ;FREE THE TCB (OK EVEN IF MULTIPLY CALLED) ADD #,R0 CLRB @R0 ;SAY NOBODY HAS TCB NOW 2$: MOV (SP)+,R0 RTS PC .ENDC ; .PSECT ; ; THIS HANDLER PROCESSES ALL TRAP INSTURCTIONS GIVEN ; BY THE SYSTEM'S TASKS. IT THEN PERFORMS THE ; NECESSARY ACTION. MOST TRAPS WILL RESULT IN A ; SCAN, SO A SPECIAL EXIT (COMMON TO ALL) IS USED ; TO MAKE ENTRY TO MSXSCN AT THE APPROPRIATE PLACE. ; THE STATUS WORD ON THE STACK WILL BE SET TO THE NUMBER ; OF STACK ENTRIES TO BE DELETED WHEN THE TASK IS ; RESTARTED. THIS IS NOT DONE UNTIL THE TASK IS BEING ; ACTIVATED BY SCAN. LEAVES SOME WORDS FLOATING AROUND ; WHICH ARE NOT ABSOLUTELY NECESSARY, BUT IS USEFULL ; FOR DEBUGGING AND IS FASTER. ; ; N.B. THE STACK IS CLEANED UP HERE IMMEDIATELY FOR THE STANDALONE ; DUAL MODE VERSION OF MSX, SINCE IT IS HERE EASIER AND FASTER ; THAN AT TASK STARTUP. ; DEFINE REGS R0=%0 R1=%1 R2=%2 R3=%3 R4=%4 R5=%5 SP=%6 PC=%7 ; DEFINE OFFSETS WITHIN TCB TCBID=0 ; TASK ID TCBPR=2 ; PRI TCBST=3 ; STATE TCBSA=4 ; START ADDR TCBISP=6 ; INITIAL STACK PTR TCBDSP=10 ; DYNAMIC POINTER TCBCSP=12 ; STACK CHECK WORD TCBEVA=16 ; EVENT VARIABLE ADDR TCBREG=20 ; DEFINE OUR GLOBAL SYMBOLS. .GLOBL MX.TRP,MX.SCN,MX.SVE .IF DF,$$DOS .GLOBL MX.LUT ; SYSTM LOGICAL UNIT TABLE .ENDC LNKQHD=12 LNKQTL=14 .GLOBL MX.ATL,MX.TCB,MX.SEV .GLOBL S.RSAV,S.RRES ;PS=177776 ; ENTRY FROM TRAP INTERRUPT WITH PRI = 7 ; WE ASSUME SOMEONE HAS PLUGGED THE TRAP VECTOR. .IF NDF,$$DOS ;FOR THE RSX VERSION, WE WILL DECLARE A SET OF SST VECTORS ;HERE AND ON TRAP SERVICE WILL COME IN WITH CODE ON TOP OF STACK. ;WE HAVE TO POP TRAP CODE OFF TO BE COMPATIBLE... SO ;ENTER AT RX.TRP WITH SST AND POP EXTRA WORD. ;FOR SPEED, DEFINE A JSR PC TYPE ENTRY OF FORM ; JSR PC,MX.SVC ; .WORD TRAP CODE ; ; DEFINE A SECOND JSR PC TYPE ENTRY FOR GREATER SPEED. IT IS ;IDENTICAL TO MX.SVC BUT THE TRAP CODE MUST BE DOUBLED. NO CHECK ;ON EVENNESS IS DONE! ; .IIF DF,SVCCC, .GLOBL MX.SVC .GLOBL RX.TRP .GLOBL MX.SV2,MX.PRR MX.SV2:: ;ENTRY POINT WITH TRAP CODE * 2 FOR NO ASL NEEDED... MOV (SP),-(SP) ;COPY TO RETURN ADDRESS CLR 2(SP) ;AND LOOK LIKE 0 PSW ON RETURN. ;ADD CODE TO SPEED THINGS UP IN RSX USE ;ADD INLINE CODE FOR SPEED... MOVB #340,@#PS ;PREVENT INTERRUPTS... MOV R5,-(SP) ;FAKE UP S.RSAV CALL EFFECTS MOV R4,-(SP) MOV R3,-(SP) MOV R2,-(SP) MOV R1,-(SP) MOV R0,-(SP) .IIF DF,M$GE,JSR PC,A.PRSV ;SAVE APR 1-6 MOV MX.TCB,R0 ; NO CHECK...THIS BETTER BE RIGHT OR WE LOSE...REQUEST VIA TRAP BUT NO ; TASK ACTIVE IS AN ILLOGICAL CONDITION. ; BEQ CRASH ;GET TCB OR FAIL AND DIE... .IF NDF,SAXCL MOV SP,TCBDSP(R0) ;SAVE DYNAMIC SP WITH OTHER THINGS .ENDC MOV SP,R1 ADD #20+A$PROF,R1 ;GET TOP OF USER STACK ADDR MOV @14+A$PROF(SP),R2 ;GET CODE WORD ADD #2,14+A$PROF(SP) ;PASS CODE ON RETURN BR MX.VC2 ;THEN GO TO TRAP SCANNER. .IF DF,SVCCC MX.SVC:; ADD #2,(SP) ;POINT RETURN ADDRESS PAST ARGUMENT MOV (SP),-(SP) ;COPY TO RETURN ADDRESS CLR 2(SP) ;AND LOOK LIKE 0 PSW ON RETURN. ;ADD CODE TO SPEED THINGS UP IN RSX USE ;ADD INLINE CODE FOR SPEED... MOVB #340,@#PS ;PREVENT INTERRUPTS... MOV R5,-(SP) ;FAKE UP S.RSAV CALL EFFECTS MOV R4,-(SP) MOV R3,-(SP) MOV R2,-(SP) MOV R1,-(SP) MOV R0,-(SP) .IIF DF,M$GE,JSR PC,A.PRSV ;SAVE APR 1-6 MOV MX.TCB,R0 BEQ CRASH ;GET TCB OR FAIL AND DIE... .IF NDF,SAXCL MOV SP,TCBDSP(R0) ;SAVE DYNAMIC SP WITH OTHER THINGS .ENDC MOV SP,R1 ADD #20+A$PROF,R1 ;GET TOP OF USER STACK ADDR MOV @14+A$PROF(SP),R2 ;GET CODE WORD ADD #2,14+A$PROF(SP) ;PASS CODE ON RETURN BR MX.VCT ;THEN GO TO TRAP SCANNER. .ENDC RX.TRP: ;RSX SST ENTRY HERE. TST (SP)+ ;POP EXTRA RSX GARBAGE OFF STACK .ENDC MX.TRP: ; ENTRY POINT WITH PRI = 7 FROM TRAP INST. .IIF NDF,$$DOS,MOVB #340,@#PS .IF NDF,SAXCL JSR R5,S.RSAV ; SAVE USER REGS .IIF DF,M$GE,JSR PC,A.PRSV ;SAVE APR 1-6 .IFF .GLOBL U.RSAV,U.RRES JSR PC,U.RSAV ;SAVE REGS AND APRS .ENDC MOV MX.TCB,R0 ; SET R0 WITH TCB ADDR .IF NDF,SAXCL BEQ 24$ MOV SP,TCBDSP(R0) ;SAVE DYNAMIC SP WITH OTHER THINGS 24$: .ENDC ; BEQ CRASH ; CRASH IF NOTHING HERE ; WHEN WE GO OFF TO TRAP HANDLERS, R0 HAS CURRENT ; MX.TCB VALUE, R1 POINTS TO TOP OF USER STACK ; AT TIME OF TRAP THE REST OF ROUTINES ASSUME THIS ; USEFULL CRAP .. .IF NDF,SAXCL MOV SP,R1 ; MOVE CURRENT STACK VALUE ADD #20+A$PROF,R1 ; LEAVE R1 POINTING TO PARAMS MOV -4(R1),R2 ; MOVE PC VLAE TO R2 MOV -(R2),R2 ; AND FETCH INSTRUCTION .IFF ;STAND ALONE DUAL MODE VERSION MFPI SP MOV (SP)+,R1 ; POINT AT USER PARAMS (IN HIS SPACE) BIT #140000,2(SP) ;(SEE IF PREV MODE WAS KNL) BNE 1$ ;IF NOT, R1 OK NOW ADD #4,R1 ;ELSE ADJUST R1 FOR TOP OF STACK 1$: MOV @SP,R2 ; GET TRAP PC MFPI -(R2) ; GET INSTRUCTION MOV (SP)+,R2 ; FROM USER .ENDC BIC #177400,R2 ; MASK OFF USELESS MX.VCT: ASL R2 ; MAKE IT FULL WORDS MX.DMX=40*2 ;MAXIMUM LEGAL DIRECTIVE OFFSET CMP R2,#MX.DMX ;BE SURE DIRECTIVE IS VALID BHI MX.DCL MX.VC2: .IF DF,PR.VS ;IF PRIVILEGES ARE IMPLEMENTED ;THE PRIV. MASK IS AT SCB+20, SCB+22 AND IS A DOUBLEWORD ;WITH BITS SET TO PROHIBIT DIRECTIVES. NOTE THAT DIRECTIVES ;0,2,6,7, AND 14 ARE LEGAL ALWAYS. MASK MIN.P ENFORCES THIS. MIN.P=10305 ;BITS FOR DIRECTIVES 0,2,6,7, AND 14 (OCTAL). CLR R5 ;LO MASK CLR R4 ;HI MASK FOR ASHC MOV R2,-(SP) ;SAVE OFFSET ASR R2 ;MAKE A BIT NUMBER MOV R2,R3 ;SAVE BIT NO. INC R2 ;STARTING WITH 1 SEC ;GUARANTEE WE SHIFT A 1 INTO PLACE ASHC R2,R4 ;SHIFT THE 1 INTO THE MASK MOV TCBSCB(R0),R2 ;NOW GET THE MASKS ADD #20,R2 ;POINT AT THE MASK AREA BIC #MIN.P,@R2 ;GUARANTEE MINIMUM DIRECTIVES ARE LEGAL BIT R5,(R2)+ ;IS OP ILLEGAL? BNE 1$ ;YES, BRANCH BIT R4,(R2) ;IS OP ILLEGAL? BEQ 2$ ;NO, BRANCH ;1$: MOV #MX.DMX,(SP) ;ILLEGAL OP. MAKE IT A DECLARE. (TASK MUST ;CLEAN ITS OWN STACK) 1$: TST (SP)+ ;ILLEGAL OP. MOVB MP.TB(R3),R2 ;GET STACK OFFSET TO POP JMP TRPSCN ;THEN POP THEM AND EXIT THE DIRECTIVE. 2$: MOV (SP)+,R2 ;RESTORE THE OFFSET TO PROCESS. .ENDC JMP @MX.XVX(R2) ; AND OFF TO ROUTINES ; TRANSFER VECTOR PLUGGED WITH PROPER VALUES. ;TRANSFER ADDRESSES FOR SYSTEM TRAPS. MX.XVX: ;CODE 0 .WORD WAIT. ;WAIT FOR EVENT VARIABLE TO GO NONZERO ;CODE 1 .WORD PRIREQ ;REQUEST TASK W/O PRIO ARBITRATION ;CODE 2 .WORD ORWAIT ;WAIT FOR ANY OF LIST OF VARIABLES TO BE NONZERO ;CODE 3 .WORD SUSPND ;SUSPEND EXECUTION OF TASK UNTIL RESUMED ;CODE 4 .WORD RESUME ;RESUME EXECUTION OF TASK [AT OPTIONAL ADDRESS] ;CODE 5 .WORD REQEST ;START UP A TASK, NO HIERARCHY. ;CODE 6 .WORD EXIT ;END EXECUTION OF TASK (FROM THE TASK) ;CODE 7 .WORD DECLAR ;DECLARE SIGNIFICANT EVENT ;CODE 10 .WORD QTRAN ;QUEUED I/O TRANSFER ;CODE 11 .WORD SPAWN ;START UP A TASK, RECORD CALLER AND CALLED RELATIONS ;CODE 12 .WORD MSGOUT ;SEND MESSAGE TASK-TO-TASK ;CODE 13 .WORD MSGIN ;READ MESSAGE RECEIVED, IF ANY ;CODE 14 .WORD WSIG ;WAIT FOR NEXT SIGNIFICANT EVENT ;CODE 15 .WORD ABORT ;ABORT EXECUTION OF A TASK (FROM ANOTHER TASK). TELL CALLER ;CODE 16 .WORD ALTGBL ;CHANGE EVENT VARIABLE ANYWHERE ;CODE 17 .WORD MODSTT ;READ OR WRITE STATUS IN SYSTEM TABLES FOR ANY TASK ;CODE 20 .WORD LOCK ;LOCK THE MSX SCANNER (INHIBITS TASK SWITCHING) ;CODE 21 .WORD UNLOCK ;UNLOCK MSX SCANNER (RE-ALLOWS TASK SWITCHING) ;CODE 22 .WORD PWAIT ;WAIT UNTIL AN EVENT VARIABLE BECOMES 0 OR + ;CODE 23 .WORD ASTXIT ;EXIT MESSAGE-IN MSX ASYNCH SYSTEM TRAP ;CODE 24 .WORD KWAIT ;WAIT UNTIL AN EVENT VARIABLE IN KERNEL SPACE IS NON-0 ;CODE 25 .WORD MSGFRE ;FREE A MESSAGE DATA AREA WHEN DONE WITH IT ;CODE 26 .WORD XASTX ;EXIT A "CALLED-TASK-EXITED" AST ;CODE 27 .IF DF,VARPRI .WORD ALTP ;ALTER A TASK'S PRIORITY .IFF .WORD WSIG ;(OTHERWISE WAIT FOR SIG EVENT) .ENDC ;CODE 30 .WORD KPWAIT ;PWAIT ON EVENT VARIABLE IN KNL SPACE ;(USED AS MARKTIME SETUP ALSO...) ;CODE 31 .WORD ORGWAT ;ORWAIT FOR ANY EV GREATER THAN 0 IN LIST OF EV. ;CODE 32 .WORD TWAIT ;WAIT UNTIL EV IS SET OR TASK EXITS ;CODES 33 UP TO 40 .WORD DECLAR,DECLAR,DECLAR,DECLAR,DECLAR,DECLAR ;SPARES .WORD DECLAR,DECLAR MX.DCL: JMP DECLAR ;DEFAULT TOO-HIGH DIRECTIVE JUST DOES A SCAN .IF DF,PR.VS MP.TB:; .BLKB 40 ;STACK OFFSETS PER DIRECTIVE .BYTE 2,6,2,0,6,6,2,0 ;NO. BYTES TO POP OFF STACK FOR EACH DIRECTIVE .BYTE 6,6,2,6,0,2,6,12 .BYTE 0,0,2,6,2,4,6,4 .BYTE 2,2,2,0,0,0,0,0 .EVEN .ENDC .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 .MACRO KMOV SRC,DEST .IF DF,SAXCL MFPI SRC MOV (SP)+,DEST .IFF MOV SRC,DEST .ENDC .ENDM .IF NDF,$$DOS MX.PRR: ;PRIORITY REQUEST SPECIAL ENTRY ; CALL: ; CLR -(SP) ;FAKE PS ; JSR PC,MX.PRR ;CALL PRIO REQUEST WITH USUAL REQ STUFF ON STACK ; ; AS FOR NORMAL REQUEST... MOVB #340,@#PS ;NO INTERRUPTS MOV R5,-(SP) ;SAVE REGS MOV R4,-(SP) MOV R3,-(SP) MOV R2,-(SP) MOV R1,-(SP) MOV R0,-(SP) .IIF DF,M$GE,JSR PC,A.PRSV ;SAVE APR 1-6 MOV SP,R1 ;GET POINTER TO ADD #20+A$PROF,R1 ;TOP OF CALLER STACK IN R1 MOV MX.TCB,R0 ;POINTER THE ACTIVE TASK BNE 2$ ;SKIP SAVING SP IF NO ACTIVE TASK JMP PRIRE3 ; SKIP SAVING SP IF NO TASK ACTIVE... 2$: JMP PRIRE2 ;GO TO REQUEST ROUTINE DIRECT .ENDC ;-------- CRASH: ;HALT ; ERROR HALT .IIF NDF,$$DOS,CLRB @#PS CCP: BR CCP ;XASTX - EXIT AST EXIT CALL. CALL=TRAP 26 ; XASTX: MOVB #340,@#PS MOV TCBDSP(R0),R1 ;GET DYNAMIC SP BNE 1$ ;0 ILLEGAL JMP EMXIT ;SO EXIT TASK IF 0 1$: JMP XASTQ ;IF NOT, MERGE IN COMMON AST EXIT CODE ; ; SPAWN -- FUNCTIONS AS REQUEST, BUT MAINTAINS TASK HIERARCHY. EXIT OF ; SPAWNED TASKS QUEUES ASTS TO THE CALLER IF AN ENTRY IS SPECIFIED ; AND BUMPS AN EVENT VARIABLE IN CALLER ALSO. IF A TASK EXITS OR ; IS ABORTED, ANY ACTIVE SPAWNED TASKS ARE ALSO ABORTED. UP TO ; 15. TASKS MAY BE KEPT TRACK OF; THE NUMBER THAT MAY SIGNAL THE ; CALLER IS UNLIMITED. ; CALL ARGUMENTS ARE AS FOR REQUEST, BUT THE "PRIORITY" ; WORD IS THE ADDRESS OF AN EV IN THE CALLER TO BUMP WHEN ; THAT TASK EXITS. NOTE THE ADDRESS IS IN THE CALLED TASK'S TCB. SPAWN: KMOV @R1,R3 ;GET CALLED TASK NAME/NUMBER JSR PC,ATLOOK ;HUNT FOR IT .GLOBL ATLOOK .IF DF,DY$MEM BNE 20$ ;GOT ONE. JSR PC,NAMSRV ;IF NOT, SEE ABOUT GETTING A TASK OFF DISK BCS CRR ;IF WE CANNOT, SAY ERROR .IFF BEQ CRR ;IF NOT THERE, LEAVE QUIET-LIKE .ENDC ;FOUND THE CALLED TASK. SAVE THE NAME IF A SPOT IS AVAILABLE. ;FIRST CHECK IT IS NOT THERE ALREADY... 20$: MOV TCBSPW(R0),R4 ;SPAWN TBL TST (R4)+ ;PASS OUR CALLER'S NAME IF ANY MOV R4,-(SP) ;SAVE THIS MOV #15.,R5 ;15 TASKS MAX IN TBL 1$: CMP (R4)+,R3 ;LOOK FOR SAME TASK BEQ 2$ ;IF FOUND, NO INSERT SOB R5,1$ ;GO ON MOV (SP)+,R4 ;RESTORE R4, LOOK FOR EMPTY SLOT NEXT MOV #15.,R5 3$: TST (R4)+ ;SEE IF ZERO BEQ 4$ ;IF SO, GOT A SLOT SOB R5,3$ ;LOOK THRU ALL BR 5$ 4$: MOV R3,-2(R4) ;FILL IN CALLED TASK NAME 5$: MOV @R0,@TCBSPW(R2) ;FILL OUR TASK NAME AS CALLER KMOV 2(R1),TCBKEV(R2) ;NOTE ACTIV8 USES THESE IN TASK START MESSAGES BR SETRDY ;START THE TASK 2$: TST (SP)+ ;FIX STACK IF NO EMPTY SLOTS BR 5$ ;THEN GO AHEAD ; ;TWAIT - WAIT FOR EVENT VARIABLE OR TASK EXIT. ; ;CALL: ; MOV #TBL,-(SP) ;POINT TO TABLE IN TASK SPACE ; TRAP 32 ;CALL THE SERVICE ; TWAIT 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. TWAIT: MOV #15,R2 ;STATE 15 IS THE TWAIT STATUS BR WAITC ;THEN DO COMMON WAITS STUFF... ; ;PWAIT - AWAIT EVENT VARIABLE GOING POSITIVE PWAIT: MOV #7,R2 ;SET STATE 7 BR WAITC ;TO COMMON WAIT CODE ; ;KWAIT - WAIT FOR NONZERO EVENT VARIABLE IN KERNEL SPACE ; KWAIT: MOV #6,R2 ;STATE 6 = WAITING FOR KNL EV BR WAITC ;TO COMMON NOW ; ;LOCK - LOCK THE BSX SCANNER (FROM POSSIBLY ANOTHER SPACE) ; LOCK: INCB MX.LOK ;LOCK UP NORG: CLR R2 BR TRPSCN ;GO TO SCANNER ; ;UNLOCK - CLEAR LOCK OF LOCK CALL ; UNLOCK: MOVB #-1,MX.LOK ;FREE SCANNER BR NORG ;GO AWAY ; ; ;WSIG - WAIT FOR SIGNIFICANT EVENT (FOR 1 SCAN) WSIG: MOVB #5,TCBST(R0) ;SET INTO SIG EVENT WAIT STATE ;FALL THROUGH TO DECLARE ; DECLARE COMES HERE DECLAR: CLR R2 ; SET FOR NO PARAMS SETSEV: CLRB MX.SEV ; SET SIG EVENT VAR ;--------- ; NOW FALL THRU ;----- ;------- TRPSCN: ; COMMON EXT TO MERGE WITH MX.SCN ; WE ASSUME THAT R2 HAS THE VALUE TO BE USIED IN RESTORING ; STACK AND THAT R0, R1 HAVE PROPER STUFF IN THEM AS DEFINED ; ABOVE... .IIF NDF,SAXCL, MOVB R2,-(R1) ; INSERT STACK POP VALUE .IIF DF,SAXCL, ADD R2,TCBDSP(R0) ;ADJUST STACK FOR USER JMP MX.SVE ; SAVE EAE ENTRY ; WAIT/ORWAIT ;------- ; WAIT ; TOP OF STACK CONTINAS THE EVA WAIT.: MOV #2,R2 ; SET FOR NORMAL WAIT ; FALL THRU FOR BUSY WORK IN COMMON ;------- WAITC: .IF NDF,SAXCL MOV (R1),-(SP) ;GET THE EV ADDRESS .IFF MFPI (R1) ;GET THE EV ADDRESS .ENDC .IIF DF,CK.AD., JSR PC,CK.MAP ;VALIDATE ADDRESS AS IN THE TASK SPACE BIT #1,@SP ;IS ADDRESS OK LOOKING? BNE 1$ ;IF NOT, BUZZ OFF MOV (SP)+,TCBEVA(R0) ;IF SO, MOVE IN THE WAIT EV ADDRESS MOVB R2,TCBST(R0) ;MOVE IN THE NEW STATE OF TASK BR 2$ ;THEN SET POP OF STACKED DATA 1$: TST (SP)+ ;INVALID ARGS ==> NO ACTION 2$: MOV #2,R2 ;SET 2 BYTE POP OF SP BR TRPSCN ;AND USE COMMON EXIT. ;------- ; ORWAIT ; TOP OF STACK HAS POINTER TO OR LIST (WE HPE) ;(FOR ORGWAT (=WAIT UNTIL ANY WORD OF LIST IS GT 0) USE DIFFERENT TRAP.) ORWAIT: MOVB #3,R2 ; SET FOR ORWAIT BR WAITC ; AND USE COMMON ORGWAT: MOVB #14,R2 ;SET FOR WAIT FOR ANY EV GREATER THAN 0 BR WAITC ; REQUEST/EXIT ;------- ; REQUEST ; STACK HAS TASK, PR, EV ; NOTE: REQUEST AND RESUME WANT RAD50 NAME ON STACK, NOT ADDR OF NAME REQEST: .IF NDF,SAXCL MOV (R1),R3 ; MOVE NAME TO R3 .IFF MFPI (R1) MOV (SP)+,R3 .ENDC JSR PC,ATLOOK ; LOOK IT UP .IF NDF,DY$MEM BEQ CRR .IFF BNE 20$ JSR PC,NAMSRV ;TRY TO FIND ON DISK BCS CRR ;RETURN CS IF NOT THERE 20$: .ENDC ; BEQ CRASH ; ERROR .IIF DF,$TST.,TSTB TCBST(R2) ; IS THS IT ? .IIF DF,$TST.,BNE CRASH ; ERROR ; (*** ALLOW TO GO THRU EVEN IF TASK ALREADY ACTIVE...) .IIF DF,PRLVLS, JSR PC,MX.UPU ;BUMP PRIO COUNT SETRDY: ; COMMON BETWEEN REQUEST AND RESUME .GLOBL MX.HGH ; CMP R2,MX.HGH ;HIGHEST PRIO SO FAR IS THIS NEW ONE? ; BHI 10$ ;NO, HIGHER ONE THERE AND NOT EXITED. ; MOV R2,MX.HGH ;YES, SAVE TCB ADDR FOR LATER TESTS ;10$: SETRD2: .IF NDF,SAXCL MOV 4(R1),R5 ;GET EV ADDR OR 0 FROM STACK BEQ 1$ ;IF 0, NO BUMP ADRCHK R5 BIT #1,R5 ;SEE IF VALID ADDRESS BNE 1$ ;IF ODD, IGNORE BUMP. INC @R5 ;ELSE BUMP THE THING. 1$: .IFF MFPI 4(R1) ;GET EV ADDR MOV (SP)+,R5 BEQ 1$ ADRCHK R5 BIT #1,R5 ;SEE IF VALID ADDRESS BNE 1$ ;IF ODD, IGNORE BUMP. MOV #1,-(SP) ;IF IT IS THERE PUT 1 IN MTPI @R5 1$: .ENDC .IF DF,M.MMP ;OK TO DO THIS STUFF IF TASK MAY BE IN ANOTHER CPU. .ENDC .IF DF,CMNTCB MOV R0,-(SP) MOV R2,R0 JSR PC,TCBGET ;ACQUIRE UNIQUE TCB ACCESS .ENDC TST TCBDSP(R2) ;SEE IF TASK IS ACTIVE BNE 5$ ;IF SO, NO ACTION MORE MOVB MX.CPU,TCBCPU(R2); IF SO, SET ACTIVE HERE PENDING ARBITRATION MOVB #4,TCBST(R2) ; SET READY STATE 5$: .IF DF,CMNTCB JSR PC,TCBFRE ;ACQUIRE UNIQUE TCB ACCESS MOV (SP)+,R0 .ENDC BR CRX CRR: .IF DF,DY$MEM KMOV 4(R1),R2 ;GET CALLER EV ADDRESS BEQ CRX ;NO EV MEANS NO BUMPING EV ADRCHK R2 BIT #1,R2 ;SEE IF EV IS LEGAL BNE CRX ;IF NOT, NO MESSING WITH IT. MOVK #-5,@4(R1) ;FILL IN CALLER EV WITH NO ROOM STATUS .ENDC CRX: MOV #6,R2 ; SET UP EXIT REGS BR SETSEV ; DO A NEW SCAN ;------- ; .IF NDF,$$DOS ;MX.PRX EXIT QUICK ROUTINE ENTRY (GO STRAIGHT TO EXIT TRAP) ; .GLOBL MX.PRX MX.PRX: MOVB #340,@#PS ;NO INTERRUPTS MOV MX.TCB,R0 ;POINTER THE ACTIVE TASK .IF NDF,SAXCL MOV SP,R1 ;GET POINTER TO ADD #4,R1 ;TOP OF CALLER STACK IN R1 .IFF MFPI SP MOV (SP)+,R1 ADD #4,R1 ;POINTER TOP OF CALLER STACK .ENDC ; BR MX.XIT .ENDC ; EXIT .GLOBL MX.XIT ; EXIT ENTRY MX.XIT: ; ENTRY FOR EXIT OF TASK EXIT: CLR TCBDSP(R0) ; RESET STACK PTR CLRB TCBST(R0) ; AND STATE .IIF DF,CMNTCB,JSR PC,TCBFRE ;ENSURE THE TCB IS FREE .IIF DF,PRLVLS, JSR PC,MX.DNU CMP R0,MX.HGH ;HIGHEST PRIO TASK EXITING? BNE 10$ ;NO, LEAVE FLAG ALONE MOV #-1,MX.HGH ;YES, CLEAR OUT ADDR 10$: .IF NDF,SAXCL MOV (R1),R5 ;WAS THERE AN EV? BEQ 1$ ;NO, SKIP ADRCHK R5 BIT #1,R5 ;SEE IF VALID ADDRESS BNE 1$ ;IF ODD, IGNORE BUMP. INC @R5 ;YES, BUMP IT. 1$: .IFF MFPI @R1 MOV (SP)+,R5 BEQ 1$ ADRCHK R5 BIT #1,R5 ;SEE IF VALID ADDRESS BNE 1$ ;IF ODD, IGNORE BUMP. MOV #1,-(SP) ;IF AN EV THERE, BUMP IT MTPI @R5 1$: .ENDC .IF DF,M.MMP MOV #1,TCBSTT(R0) ; FILL IN 1 AS TASK NORMAL EXIT STATUS JMP REABRT ; FINISH CLEANUP AND DO A SCAN .IFF JMP MX.SCN ; PERFORM ONLY A SCAN .ENDC ; PRIORITY REQUEST ; STARTS UP A TASK, WITHOUT USING SIG. EVENT INDICATOR, AND ; GOES DIRECTLY TO IT. IT WILL HOWEVER SET THE MX.SEV FLAG FOR ; POSSIBLE LATER USE. PRIREQ: CLRB MX.SEV ;SET UP SIG EVENT AFTER DONE PRIRE2: .IF NDF,SAXCL MOV SP,TCBDSP(R0) ;SAVE STACK POINTER OF CURRENT TASK .IFF ;U.RSAV SAVED DYNAMIC SP SO DON'T BOTHER HERE... .ENDC ; (ON ENTRY R0 IS TCB ADDR) MOV #PS,R5 PRIRE3: .IF NDF,SAXCL MOV @R1,R3 ;GET TASK NAME .IFF MFPI @R1 MOV (SP)+,R3 ;GET TSK NAME OR NUMBER .ENDC JSR PC,ATLOOK ;FIND THE TASK (BY NUMBER IS FASTEST) .IIF DF,$$CHK,BEQ CRASH ; CRASH IF CANNOT FIND TASK. (CONDITIONAL) .IIF DF,PRLVLS, JSR PC,MX.UPU ;COUNT ACTIVATED TASKS CMP R2,MX.HGH ;THIS TASK ADDR LATER THAN HIGHEST PRIO? BHI SETRD2 ;YES, SO DO NORMAL REQUEST TO ARBITRATE PRIO ; MOV R2,MX.HGH ;ELSE SAVE HIGHEST PRIO CURRENTLY NONXIT TSK .IF NDF,SAXCL MOV 4(R1),R0 ;SEE IF EV ADDR IS ON STACK BEQ 1$ ;IF NOT FORGET BUMPING IT INC @R0 ;IF SO BUMP IT. 1$:; CLRB MX.SEV ;SET SIG. EVENT FOR LATER USE .IFF MFPI 4(R1) ; SEE IF EV ADDR ON STACK MOV (SP)+,R0 BEQ 1$ MOV #1,-(SP) ;IF SO PUT 1 INTO IT MTPI @R0 1$: .ENDC .IF DF,CMNTCB ; MOV R0,-(SP) MOV R2,R0 JSR PC,TCBGET ;ACQUIRE UNIQUE TCB ACCESS ; MOV (SP)+,R0 .ENDC TST TCBDSP(R2) ;TSK ACTIVE ALREADY? BNE 4$ MOVB MX.CPU,TCBCPU(R2) MOVB #4,TCBST(R2) ;SET READY TO RUN STATUS 4$: MOV R2,R0 ;POINT R0 AT TCB .IF NDF,SAXCL MOVB #6,-(R1) ;SAVE STACK POP VALUE .IFF ADD #6,TCBDSP(R2) ;ADJUST STACK .ENDC .GLOBL MX.RNS ;READY STATUS ENTRY JMP MX.RNS ;THEN START UP THE TASK... ; AST EXIT (MESSAGE AST ENTRY) ;EXPECTS STACK TO CONTAIN STATUS,MSG ADDR,MSG LENGTH, PS,PC ; ASTXIT: MOVB #340,@#PS ;NO INTS THIS CPU PLEASE. MOVB TCBST(R0),R1 ;GET DISABLED BIT BIC #^C200,R1 ;LEAVE IT ONLY BIS #11,R1 ;SET IN AST QUEUED STATUS MOVB R1,TCBST(R0) ;SET AST QUEUED STATE ;AST QUEUED STATE ALLOWS LATER CHECK THAT TASK REALLY HAS NO ;MORE AST'S QUEUED MOV TCBDSP(R0),R1 ;GET TASK SP BNE 1$ ;IF OK, LET IT FLY JMP EMXIT ;IF NOT, TASK EXITS RIGHT NOW! ;NOTE STACK HAS REGS AND MAYBE APR'S SAVED ALREADY, PLUS THE TRAP STUFF. 1$: JSR PC,FREDAT ;FREE DATA AREA POINTED TO BY STUFF ON STACK XASTQ: ;COMMON ENTRY FOR AST EXITS .IF DF,SAXCL ;STANDALONE HAS APR'S IN TCB; ONLY ADJUST STACK ADD #12,TCBDSP(R0) ;REMOVE 5 WORDS JUNK KMOV (R1)+,TCBDPC(R0);SAVE DYNAMIC PC OFF STACK KMOV (R1)+,TCBDPS(R0);AND PS JMP DECLAR ;GO ISSUE SIG EVENT .IFF ;RSX/DOS MSX. NOTE THAT HERE APR'S AND REGS ARE SAVED ON TASK STACK AND ;REQUIRE STACK TO BE JUGGLED. MOV #<10+>,R2 ;NO. ENTRIES MOV R1,R3 ;COPY "TASK STACK" .IF DF,M$GE MFPI 20+A$PROF(R1) MTPI 14+A$PROF(R1) ;COPY PC MFPI 22+A$PROF(R1) MTPI 16+A$PROF(R1) ;COPY PS .IFF MOV 20+A$PROF(R1),14+A$PROF(R1) ;COPY PC MOV 22+A$PROF(R1),16+A$PROF(R1) ;COPY PS .ENDC ADD #30+A$PROF,R1 ;POINT R1 AT NEW TOP OF STACK ADD #16+A$PROF,R3 ;POINT R3 AT OLD TOS .IF DF,M$GE 2$: MFPI -(R3) MTPI -(R1) .IFF 2$: MOV -(R3),-(R1) .ENDC SOB R2,2$ ;COPY STACK UP ADD #10.,TCBDSP(R0) ;BUMP SP IN TCB ADD #10.,SP ;AND REAL STACK JMP DECLAR ;GO TO IT .ENDC ; ; MODSTT ; MODIFY TASK STATUS. ; THIS CALL ALLOWS A TASK TO MODIFY ITS TCB (OR ANOTHER TCB) BY ;NAME WITHIN ITS CPU. (NAMES ARE SMALL INTEGERS THAT HAPPEN TO BE ;OFFSETS WITHIN THE TCB). TCB DATA MAY BE EITHER READ OR WRITTEN, ;1 WORD AT A TIME. THE CALL FORMAT IS: ; MOV TASKNAME,-(SP) ;PUSH TASK NAME OR NUMBER ;(-1 MEANS SELF) ; MOV #ID1,-(SP) ;PUSH MAJOR ID (TCB OFFSET IN BYTES) ; MOV #ID2,-(SP) ;PUSH MINOR ID (TABLE OFFSET IF TCB IS A TBL ;ADDRESS) ; MOV #VALADR,-(SP) ;PUSH ADDRESS OF AREA WITH DATA. DATA READ ;GOES HERE; DATA WRITTEN COMES FROM HERE. ; MOV #CODE,-(SP) ;PUSH CODE. CODE=0 IF READ, =1 IF WRITE. ; TRAP 17 ;TRAP 15. ; ; RESULT IS READ INTO VALADR OR WRITTEN FROM VALADR MODSTT: KMOV 10(R1),R3 ;GET TASK NAME CMP R3,#-1 ;NAME = -1 MEANS KERNEL (EVERYONE) BEQ 1$ ;IF KNL GO OFF JSR PC,ATLOOK ;FIND TASK BNE 2$ ;IF OK GO ON 1$: MOV R0,R2 ;NO TASK MEANS SELF 2$: KMOV 6(R1),R4 ;GET ID1 CMPB R4,#MODMAX ;CRUDE RANGE CHECK BHI MODXIT ;LEAVE IF BAD ; MOVB MODOF(R4),R4 ;(MAP ARGS IF TABLES CHANGE) MOV R4,R3 ;COPY TO SAVE POINTER ADD R2,R4 ;GET ADDR IN R4 TO TABLE BITB #1,MODFLG(R3) ;IS THIS ENTRY ANOTHER TABLE? BEQ 3$ ;IF 0 NO KMOV 4(R1),R5 ;IF 1 YES CMP R5,#TBLMX ;CRUDE RANGE CHECK BHI MODXIT ; MOVB MODOF2(R5),R5 ;(MAP ARGS IF TABLES CHANGE) MOV @R4,R4 ;GET TBL ADDRESS ADD R5,R4 ;MAKE R4 POINT TO DESIRED NUMBER 3$: KMOV (R1),R5 ;GET CODE (READ/WRITE = 0/1) CMP R5,#1 ;IF CODE = 1 THEN WRITE ELSE READ BEQ 4$ ;TO WRITE BRANCH KMOV 2(R1),R5 ;GET ADDR TO USE ADRCHK R5 ;BE SURE ADDR LEGAL IN THIS TASK. BIT #1,R5 ;BE SURE EVEN BNE MODXIT ;IF NOT, IGNORE THE OPERATION. TSTB MODFLG(R3) ;SEE IF BYTE QUANTITY BPL 5$ ;IF +, A WORD MOVB @R4,R2 ;GET WORD KMOV R2,@R5 ;SAVE IT IN TASK'S SPACE BR 6$ 5$: BIC #1,R4 ;BE SURE R4 EVEN MOV @R4,R2 ;GET WORD KMOV R2,@R5 ;STASH BR 6$ ;ENDS READ 4$: KMOV 2(R1),R5 ;ADDR KMOV @R5,R5 ;GET DATA OUT OF TASK TSTB MODFLG(R3) ;SEE IF BYTE OPERAND BPL 7$ MOVB R5,@R4 ; BR 6$ 7$: BIC #1,R4 ;EVENIZE R4 MOV R5,@R4 ;SAVE DATA IN KNL AREA 6$: MODXIT: MOV #12,R2 ;GO WITH BIG FLUSH OFF STACK SETSVJ: JMP SETSEV ;TO SCANNER NOW... ; ;MSGOUT - EMIT MESSAGE TO ANOTHER TASK. FORMAT OF CALL: ; ; MOV #MSGHDR,-(SP) ; TRAP 12 ; ; MSGHDR IS THE MESSAGE HEADER. THE TASK MUST FILL IN THE FOLLOWING: ; ; MSGHDR: .WORD 0 ; .WORD 0 ; .WORD PRIO (FILL IN PRIORITY. 1 BYTE) (HI BYTE NONZERO ; MEANS MESSAGE ADDRESS FOLLOWS HDR INSTEAD ; OF MSG DATA). ; .RAD50 /NAM/ NAME OF CALLED TASK ; .WORD MSGLEN LENGTH OF MESSAGE DATA AREA (<257 WORDS) ; .WORD EVA EVENT VARIABLE TO BUMP ON RECEIPT OF MSG ; .BLKB MSGLEN DATA AREA. NOT OVER 256. WORDS LONG (512.BYTES) ; ;THE WHOLE MESSAGE GETS COPIED TO M.MSG INTERNALLY IF THE CALLED AND CALLER ;TASKS ARE IN THE SAME CPU. REPLY IS DONE VIA ANOTHER MESSAGE AND THAT BUMPS ;THE EVENT VARIABLE. EV GETS +1 IF ALL SEEMS WELL, -1 IF A LENGTH ERROR ;OCCURS (OR OTHER PROBLEMS...) MSGOUT: KMOV (R1),R4 ;GET MESSAGE HEADER ADRCHK R4 BIT #1,R4 ;BE SURE MSG HDR LEGAL BNE MGXIT ;IF NOT, EXIT THE DIRECTIVE NOW. MOVK #1,@R4 ;GUARANTEE TYPE 1 MESSAGE MOVK @R0,2(R4) ;FILL IN CALLER TASK AS CURRENT ONE ;MESSAGE HEADER NOW HAS CORRECT FIELDS AS FAR AS WE CAN TELL. SEND IT TO ;ITS DESTINATION. KMOV 6(R4),R3 ;GET CALLED TASK NAME JSR PC,ATLOOK ;LOOK FOR ITS TCB BEQ MGXIT ;IF WE FAIL, CANNOT ROUTE MESSAGE SO FORGET IT ;TEST THAT THE TASK IS ACTIVE. IF NOT, RETURN AN ERROR IMMEDIATELY ;TO THE REQUESTOR. TST TCBDSP(R2) ;IS THE CALLED TASK ACTIVE? BNE 4$ ;YES, CAN PROCEED ;CALLED TASK IS NOT ACTIVE...THE HECK WITH IT. KMOV 12(R4),R3 ;GET THE EV ADDRESS TO NOTIFY IN REQUESTOR BEQ MGXIT ;IF NONE EXIT IMMEDIATELY... DONE MOVK #-5,(R3) ;FILL IN A -5 IN THE EV IF TASK NOT ACTIVE BR MGXIT ;THEN FINISH THE DIRECTIVE OFF. 4$: CMPB MX.CPU,TCBCPU(R2);THIS TASK IN OUR CPU? BNE MGSND ;NO, HAVE TO SEND A MESSAGE ;BOTH TASKS IN SAME CPU. JUST COPY MESSAGE TO A HOLDING AREA AND ;STUFF IT INTO CALLED TASK. MOV #1,MX.ERR ;PRESET SUCCESS CODE KMOV 10(R4),R5 ;DATA LENGTH CMP R5,#310.*2 ;DATA TOO LONG? BHI MGXIT ;IF SO, NO MESSAGE AND LEAVE DIRECTIVE. MOV #M.MSG,R0 ;OUTPUT MSG ADDR ADD #<14+1>,R5 ;ADD HEADER LENGTH AND ROUND UP BY EXTRA 1 ASR R5 ;MAKE WORD COUNT (FOR MFPI/MTPI) MOV R4,-(SP) MOV R5,-(SP) ;SAVE ORIG. SIZE MOV #6,R5 ;GET HEADER SIZE, WORDS 2$: KMOV (R4)+,(R0)+ ;COPY THE MESSAGE SOB R5,2$ ;A WORD AT A TIME MOV (SP)+,R5 ;GET LENGTH SUB #6,R5 ;GET DATA LENGTH ONLY BLE 22$ ;IF 0, DONE TSTB -11(R0) ;SEE IF ADDRESS WAS FLAGGED BEQ 21$ ;IF NOT, JUST DATA KMOV @R4,R4 ;IF SO, GET DATA'S ADDRESS IN TASK CLRB -11(R0) ;AND REMOVE THE FLAG ADRCHK R4 ;BE SURE NEW ADDR IS LEGAL BIT #1,R4 ;AND NOT ODD BNE 22$ ;IF ODD, NO COPY OF DATA! 21$: KMOV (R4)+,(R0)+ ;COPY THE DATA TO INTERNAL MSG SOB R5,21$ ;DO ALL 22$: MOV (SP)+,R4 MOV #M.MSG+2,R0 ;POINT R0 AT MSG JSR R5,S.RSAV ;SAVE REGS JSR PC,CPUDO ;GO QUEUE MESSAGE IN IN.RTN==. ;DEFINE THIS IN CASE CPUDO MUST CHECK TO BE SURE IT REALLY ;HAS TO COPY THE MESSAGE INTERNALLY (AS OPPOSED TO DMA SETUP ;TYPE THINGS IF IT IS ALTERED!) ;IF MSG FAILED WE HAVE TO NOTIFY CALLER. DO SO HERE. CMP MX.ERR,#1 ;IS MX.ERR STILL OK (NOTICE WHEN CALLED TASK ;DEQUEUES IN THAT CASE) BEQ 12$ ;YES, ALL IS OK NOW ;RATS! WE HAVE TO TELL THE CHARACTER! ; SINCE APRS MAY BE MAPPED FOR CALLED TSK, REMAP THEM. MOV 4(SP),R0 ;SET R0 FOR CALLED TASK .IIF DF,SAXCL, JSR PC,U.LDR ;MAP APRS .IIF DF,M$GE, JSR PC,U.ALD ;MAP APRS MOV M.MSG+12,R4 ;GET EV ADDRESS ADRCHK R4 ;BE SURE EV LEGALLY ADDRESSED. ;(NOTE: NORMALLY ALL TASKS WILL HAVE THE SAME MAPPING, WITH AT MOST SOME ;OVERLAPPED STORAGE.) BIT #1,R4 BNE 12$ ;IF INVALID, NO BUMP MOVK MX.ERR,(R4) ;FILL ERROR RETURN IN 12$: JSR R5,S.RRES ;RESTORE REGS MGXIT: MOV #2,R2 ;1 ARG JMP SETSEV ;THEN GO MGSND: KMOV 10(R4),R5 ;HERE HAVE TO SEND A MESSAGE ADD #14,R5 ;ADJUST LENGTH SO R5 = LENGTH NOW MOVB TCBBUS(R2),R3 ;R3 = BUS NUMBER JSR PC,ROUTE ;FIND ROUTE TO GET TO BUS OF TASK ;NOTE WE CALL MGXMT INSTEAD OF MGXMTR HERE BECAUSE THE MESSAGE IS NOT ;IN THE SYSTEM NODE POOL, SO WE DON'T DELETE ANY NODE. IT IS IN THE ;TASK'S SPACE. JSR PC,MGXMT ;SEND THE MESSAGE AND ERASE THE NODE BR MGXIT ;THEN DONE AT LAST. ;ALTGBL - ALTER GLOBAL EVENT VARIABLE. FORMAT OF CALL: ; ; MOV #VALUE,-(SP) ;NO. TO ADD TO EV (0 IMPLIES ADD 1) ; MOV TASKNAM,-(SP) ;TASK NAME OF TASK WITH EV ; MOV #EVA,-(SP) ;EV ADDR WITHIN TASK (TASK =-1 ==>KNL) ; TRAP 16 ;CALL IT ; ALTGBL: KMOV 2(R1),R3 ;GET TASK NAME KMOV @R1,R5 ;GET EVA BEQ 2$ ADRCHK R5 BIT #1,R5 ;EVA LEGAL? BNE 2$ ;IF NO, BRANCH. KMOV 4(R1),R4 ;GET VALUE ; KMOV @4(R1),R4 ;GET VALUE BNE 3$ INC R4 3$: CMP R3,#-1 ;KERNEL SPACE? (IMPLIES BROADCAST TOO) BEQ 11$ ;YES, DO IT JSR PC,ATLOOK ;FIND TASK BEQ 2$ ;NO TASK MEANS IGNORE REQUEST CMPB TCBCPU(R2),MX.CPU ;THIS OUR CPU? BNE 1$ ;NO, HAVE TO BROADCAST A MESSAGE ;MESSAGE GOES TO THIS CPU MOV R0,-(SP) ;SAVE CURRENT R0 = TCB PTR MOV R2,R0 ;ALLOW MAP TO CALLED TSK .IF DF,SAXCL JSR PC,U.LDR MFPI @R5 ADD R4,@SP MTPI @R5 ;ADD VALUE TO EV .IFF .IF DF,M$GE JSR PC,U.ALD ;MAP IN CALLED TSK MFPI @R5 ADD R4,@SP MTPI @R5 ;ADD VALUE TO EV .IFF ADD R4,@R5 .ENDC .ENDC MOV (SP)+,R0 ; BR 2$ ;DONE HERE 11$: ADD R4,@R5 ;KNL SPACE NEEDS NOTHING FANCY 1$: JSR PC,GETNOD ;GET NODE IN R1 FOR MSG MOV #5,(R1)+ ;TYPE 5 MSG=EV MOD MOV R3,(R1)+ ;TASK NAME (OR KNL) MOV TCBCPU(R2),(R1)+;CPU/BUS (NOTE WORD ALIGNED!!****) MOV R5,(R1)+ ;ADDRESS OF EV MOV MX.CON,(R1)+ ;NET CONNECTIVITY CLR @R1 ;PREPARE NODE MOVB TCBCPU(R2),(R1) ;CPU (AGAIN) TST (R1)+ ;PASS IT ALREADY! MOV R4,(R1)+ ;VALUE TO ADD (GUARANTEED NONZERO!) SUB #16,R1 ;RESTORE R1 TO FRONT OF MSG JSR R5,S.RSAV ;PRESERVE REGS MOV R1,R4 ;R4 <- ADDR MOV #16,R5 ;R5 <--BYTECOUNT MOVB TCBBUS(R2),R3 ;R3 = BUS NO. JSR PC,ROUTE ;FIND ROUTE TO TASK JSR PC,MGXMTR ;SEND MSG AND FREE NODE WHEN DONE JSR R5,S.RRES ;RESTORE REGS NOW 2$: MOV #6,R2 ;3 ARGS JMP TRPSCN ;DO SCAN, BUT NO SIG EVENT. ; ;MSGIN - READ IN MESSAGE (AND REPLY WITH EV NOTICE) BUT DO NOT FREE ; BUFFER. (NEED MSGFRE CALL TO DO THAT). NOTE THAT MSGFRE IS ; NOT NEEDED IN AST ROUTINES BUT FREDAT SUB HAS TO CHECK THAT ; THE MESSAGE BEING FREED IS NOT ON THE FREE LIST ALREADY. ;CALL FORMAT: ; MOV #MSGSTT,-(SP) ;STATUS ADDR (REQUIRED) ; MOV #MSGADR,-(SP) ;AREA TO SAVE MSG DATA ADDR ; MOV #MSGLEN,-(SP) ;AREA FOR MSG SIZE IN BYTES ; TRAP 13 ; MSGIN: JSR PC,DQMSGI ;DEQUEUE INPUT MSG BCS NOMIN ;IF NONE IGNORE CALL .IF DF,SAXCL MFPI 4(R1) .IFF MOV 4(R1),-(SP) .ENDC .IIF DF,CK.AD., JSR PC,CK.MAP BIT #1,(SP)+ ;IS EVA LEGAL? BNE 1$ ;IF NO, SKIP INC MOVK #1,@4(R1) ;PRESET SUCCESS 1$: MOV R5,-(SP) ;SAVE EV ADDR TO TELL OF DEQUEUE .IF NDF,SAXCL MOV 2(R1),-(SP) .IFF MFPI 2(R1) .ENDC .IIF DF,CK.AD., JSR PC,CK.MAP BIT #1,(SP)+ ;CALLER'S DATA ADDR ADDR LOOK OK? BNE 12$ ;NO, SKIP THE GIVING OF IT. MOVK R3,@2(R1) ;GIVE CALLER DATA ADDR 12$: .IF DF,SAXCL MFPI @R1 .IFF MOV @R1,-(SP) .ENDC .IIF DF,CK.AD., JSR PC,CK.MAP BIT #1,(SP)+ ;LENGTH ADDR LOOK OK? BNE 4$ ;IF NO, SKIP GIVING THE INFO. MOVK R4,@0(R1) ;GIVE CALLER BYTE COUNT 4$: JSR PC,EVNFY ;TELL OTHERS IF NECC. ADD #4,SP NOMIN: MOV #6,R2 JMP TRPSCN ;LEAVE ; ;MSGFRE - FREE UP MESSAGE AREA (ADD TO FREE QUEUE) ;FORMAT OF CALL: ; MOV #MSGADR,-(SP) ; MOV #MSGLEN,-(SP) ;PUSH ADDR, LENGTH OF MSG DATA AREA ; TRAP 25 ; ; FREES MESSAGE AREA. NEEDED WHEREVER MESSAGES ARE READ BY MSGIN. MSGFRE: KMOV (R1),R4 ;GET MSG LENGTH KMOV 2(R1),R5 ;GET MSG ADDR MOV R1,-(SP) ;MUST PRESERVE R1 ACROSS CALL. CLR -(SP) ;FAKE STATUS MOV R5,-(SP) ;MSG DATA AREA LENGTH MOV R4,-(SP) ;MSG ADDR (DATA AREA) CLR -(SP) ;FAKE PS CLR -(SP) ;FAKE PC MOV TCBDSP(R0),R1 ;TASK SP (BETTER BE THERE!!!) BEQ 1$ ;MAKE THE STACK LOOK LIKE THE STUFF JUST STASHED IS FROM THE TRAP. .IF DF,SAXCL SUB #14,SP ;FAKE REGISTER SAVE .IFF SUB #14+A$PROF,SP ;FAKE REGISTER AND APR SAVE HERE .ENDC JSR PC,FREDAT ;FREE AREA AFTER ENSURING NOT ALREADY FREE .IF DF,SAXCL ADD #14,SP ;FAKE REGISTER RESTORE .IFF ADD #14+A$PROF,SP ;FAKE REGISTER AND APR RESTORE .ENDC ADD #12,SP ;FLUSH RUBBISH OFF STACK MOV (SP)+,R1 ;GET BACK REAL OLD R1. 1$: MOV #4,R2 ;2 ARGS TO REMOVE JMP TRPSCN ; ;ABORT ; THE ABORT ENTRY ABORTS A TASK (AND ALL SUCCESSORS) ;CALL: ; MOV TASK,-(SP) ;PUSH TASK NAME (OR NUMBER) ; TRAP 15 ;DO IT! ; ABORT: KMOV (R1),R3 ;GET TASK NAME JSR PC,ATLOOK ;IF WE CAN FIND IT BEQ ABTX ;IF UNFINDABLE JUST FORGET IT. CMPB MX.CPU,TCBCPU(R2);TASK ON THIS CPU? BNE 1$ ;IF NOT BRANCH ;TASK IS HERE! CAN QUEUE ABORT THEN. MOVB #10,TCBST(R2) ;SET ABORT QUEUED STATUS MOV #-2,TCBSTT(R2) ;SET TASK ABORT AS STATUS OF TASK (BY REQ) JSR PC,AQUER ;SEE IF WE CAN ALSO QUEUE EXIT STATUS AST TO ;CALLER BR ABTX ;TASK IS SOMEWHERE ELSE. HOWEVER, IF CALLER IS HERE WE HAVE TO GENERATE ;THE EXIT NOTIFICATION TO THE CALLER SINCE OUR EXIT BROADCAST WILL NOT ;LEAD TO ANY EXIT NOTIFICATION FURTHER; THE OTHERS ON THE NET WILL ;SIMPLY MARK THE TASK ABORTED AND FLAG THE CALLER, WHEREVER IT IS. 1$: JSR PC,AQUER ;CHECK IF WE CAN TELL CALLER... JSR R5,S.RSAV ;SAVE REGS NOW JSR PC,GETNOD ;GET NODE TO USE FOR MSG IN R1 MOV #3,(R1)+ ;CREATE AN ABORT MESSAGE MOV @R2,(R1)+ ;COPY TASK NAME MOV TCBCPU(R2),(R1)+;CPU/BUS (NOTE WORD ALIGNED ****) MOV TCBKEV(R2),(R1)+;EV TO BUMP ON EXIT MOV MX.CON,(R1)+ ;NET CONNECTIVITY COUNTER CLR @R1 ;PREPARE HIGH BYTE MOVB TCBCPU(R2),(R1) ;FILL IN CPU AGAIN TST (R1)+ ;PASS CPU TO LOOK AT IN MSG MOV #-2,(R1) ;FILL IN ABORT-BY-REQUEST STATUS ;NOTE THAT XNOTFY WILL SEND THIS STATUS AND PUT INTO EXIT MSG TOO ;16 OCTAL BYTES LONG SUB #14,R1 ;BACK R1 TO START (DIDN'T BUMP R1 LAST TIME) MOV R1,R4 ;R4 GETS ADDR MOV #16,R5 ;R5 HAS SIZE MOVB TCBBUS(R2),R3 ;R3 HAS BUS NO. JSR PC,MGXMTR ;SEND MSG AND FREE NODE WHEN OUT JSR R5,S.RRES ABTX: MOV #2,R2 ;1 ARG ONLY JMP SETSEV ;AND THIS IS A SIG EVENT! ;AQUER - CHECK IF WE CAN QUEUE AN EXIT AST TO THE CALLER OF A TASK WITH ; TCB ADDR IN R2 AQUER: JSR R5,S.RSAV ;SAVE ALL REGS MOV @TCBSPW(R2),R3 ;GET CALLER NAME MOV R2,R0 ;POINT R0 AT CALLED TCB JSR PC,ATLOOK ;FROM CALLER NAME BEQ 7$ ;IF NONE FORGET IT CMPB MX.CPU,TCBCPU(R2);IS CALLER ON THIS CPU? BNE 7$ ;IF NOT SKIP IT TOO JSR PC,QXTAST ;IF SO QUEUE EXIT AST TO CALLER TO NOTIFY ;HIM OF EXIT OF THIS TASK ;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 ;WAS OLD STATUS DISABLED? (MAYBE NOT LOADED?) BPL 7$ ;IF NOT, AST QUEUED STAT OK NOW BISB #200,TCBST(R2) ;IF SO, DISABLE AGAIN. ;NOTE: ANY LOAD OPERATION SHOULD RESET THE DISABLED BITS IN THE SAVED ;STATUSES AS WELL AS THE TCB CURRENT STATUS TO MARK THE TASK READY TO GO. 7$: JSR R5,S.RRES ;GET BACK REGS RTS PC ;THEN GO BACK TO WHOEVER... ; SUSPEND/RESUME ;------- ; SUSPEND ; STACK HAS (NULL) SUSPND: MOVB #1,TCBST(R0) ; SET UP TO SHOW SESPENDED CLR R2 ; SET UP FOR NO POP JMP TRPSCN ; AND OFF TO SCANNER ;------- ; RESUME ; STACK HAS TASK, RA, EV RESUME: .IF NDF,SAXCL MOV (R1),R3 ; MOVE NAME TO CALL REG .IFF MFPI @R1 MOV (SP)+,R3 ; GET TASK NAME .ENDC .IF DF,SAXCL MFPI 4(R1) ;SEE IF HE HAS AN EV BNE 20$ ;IF SO, TEST IT TST (SP)+ ;ELSE FIX STACK AND GO BR 21$ 20$: .IIF DF,CK.AD., JSR PC,CK.MAP ;VALIDATE EVA BIT #1,(SP)+ ;EVA OK? BNE SETRYJ ;IF NOT, IGNORE DIRECTIVE. CLR -(SP) ;ZERO HIS EV FIRST MTPI @4(R1) .IFF TST 4(R1) ;ANY EV? BEQ 21$ ;NO, GO ON MOV 4(R1),-(SP) .IIF DF,CK.AD., JSR PC,CK.MAP BIT #1,(SP)+ ;ADDR OK? BNE SETRYJ ;IF NO, IGNORE DIRECTIVE CLR @4(R1) ;IF SO, ZERO THE EV. .ENDC 21$: JSR PC,ATLOOK ; LOOK FOR IT BNE 12$ ; IF OK, BRANCH MOV #-4,-(SP) MTPI @4(R1) ; IF NOT, FILL IN EV AS -4 TO FLAG IT.. BR SETRYJ ; THEN GO BACK TO HIM ; JMP CRASH ; ERROR -- CAN'T DO IT. TASK CRASHES. 12$: .IF NDF,SAXCL MOV 2(R1),R4 ; GET RA (IF ANY) .IFF MFPI 2(R1) ; GET RA OR 0 MOV (SP)+,R4 .ENDC BEQ SETRYJ ; NONE, SKIP ADRCHK R4 ;BE SURE R4 IS VALID ADDRESS IN TASK BIT #1,R4 ;SEE IF ODD? BNE SETRYJ ;IF ODD, SKIP IT. ;ARRANGE NEW TASK MAPPING, OLD TASK ALREADY SAVED BY TRAP. MOV R2,R0 .IIF DF,M$GE, JSR PC,U.ALD ;MAP IN NEW TASK APR'S .IIF DF,SAXCL, JSR PC,U.LDR ;MAP IN NEW TASK'S APR'S MOV TCBDSP(R0),R3 ; FETCH STACK POINTER OF TASK TO RESUME BEQ SETRYJ ;IF NO DSP FORGET IT .IF NDF,SAXCL .IF NDF,REL$SP MOV R4,22+A$PROF(R3) ; AND INSERT NEW PC .IFF .IIF DF,CMNTCB, JSR PC,TCBGET CMPB MX.CPU,TCBCPU(R0) ;TASK HERE (AND GOING?) BEQ 1$ ;YES, UPDATE REAL DYNAMIC PC MOV R4,@TCBDSP(R0) ;NO, SAVE IN DYNAMIC = INITIAL STACK BR 2$ ;SKIP LOCAL SAVE 1$: MOV R4,22+A$PROF(R3) ; AND INSERT NEW PC 2$: .IIF DF,CMNTCB, JSR PC,TCBFRE .ENDC .IFF MOV R4,54(R0) ; SAVE NEW PC IN DYNAMIC PC OF TCB .ENDC .IIF DF,M.MMP, JSR PC,ACTIV ; TELL OTHER CPU'S OF THE RESUME ;NOTE: ACTIV SENDS OUT A MESSAGE THAT RESETS THE START ADDRESS ;IN THE RECEIVING TASK. ACTIV8 SIMPLY REQUESTS. (OPTIONAL START ;ADDR SET TO 0 IN ACTIV8; HERE ACTIV SENDS IT OUT.) SETRYJ: JMP SETRDY ; USE COMMON ; QTRAN QUEUED IO PROCESSOR .IF DF,$$DOS .GLOBL MX.FSL ; FREE SPACE LIST .ENDC ;------- QTRAN: ; ENTRY FROM DISPATCHER ABOVE ;------- QIO: ; COMMON TO MAKE P QUEUES .IF DF,$$DOS ;FOR DOS VERSION USE OLD CODE .IF NDF,NODOS MOVB (R1),R3 ; FETCH UNIT VALUE .IFF MFPI (R1) MOVB (SP)+,R3 .ENDC BLE QCRASH ; BAD VALUE CMP R3,MX.LUT ; CORRECT RANGE? BGT QCRASH ; NO, SIGNAL ERROR ASL R3 ; GET AS WORD VALUE MOV MX.LUT(R3),R3 ; MOVE TO TABLE BEQ QCRASH ; NOTHER HERE .IF NDF,NODOS TST (R3) ; IS IT INITED ? BEQ QCRASH ; NO, ERROR .ENDC MOV R3,R5 ; SAVE LINK BLOCK ADDRESS FOR LATER... MOV MX.FSL,R2 ; MOVE TH BEQ QCRASH ; ALL GONE, DIE MOV (R2),MX.FSL ; UPDATE FREE QUEUE QIO0: ; MERGE HERE MOV LNKQTL(R3),R4 ; MOVE LAST DDB PTR BNE QIO1 ; SKIP OF ALREADY ONE TER MOV R2,LNKQHD(R3) ; PLASCE AT HED THEN BR QIO2 ; AND SKIP QIO1: MOV R2,(R4) ; MAKE LAST ENTRY QIO2: MOV R2,LNKQTL(R3) ; AND MAKE AS LAST IN HER CLR (R2)+ ; CLRE LAST ENTRY NEXT PTR .IF NDF,SAXCL MOV 4(R1),(R2) ; SET INTO QUEUE NOE CLR @(R2)+ ; SET WAIT ZERO MOV 2(R1),R3 ; GET FROM MOV (R3)+,(R2)+ ; MVOE WORDS MOV (R3)+,(R2)+ MOV (R3)+,(R2) ; WORD COUNT NEG (R2)+ ; FIX FOR IO MOV (R3)+,(R2) BISB 1(R1),1(R2) ; ADD IN UNIT (FROM SUB-UNIT) .IFF ;STAND ALONE VERSION MFPI 4(R1) MOV (SP)+,@R2 ; EV ADDR .IF DF,SAXCL ;STD ALN VERSION SAVES TCB MOV @R2,R3 ;HERE GET AND SAVE TASK TO CALL ON COMPLETION MFPI -2(R3) ;WHICH IS BEFORE EV MOV (SP)+,R3 ;(SAVES A MAPPING ON I/O DONE) MOV R3,14(R2) ;STASH IN I/O QUEUE. ; ;I/O QUEUE HERE HAS FORMAT: ; QUEUE: FWD POINTER ; EV ADDR ; DEVICE BLK # ; MEMORY ADDR ; WORD COUNT (POSITIVE) ; FUNCTION/UNIT WORD (AS DDB) ; TCB ADDR OF TASK ; TASK NUMBER TO CALL ON DONE (OR 0) ; .ENDC CLR -(SP) ;HERE ALLOW OPERATION BY DEFINING 74 AS A DEFAULT EV TO LET SYSTEM ;FORCE WAITS ON TASKS AT QTRAN. MFPI @R2 ; GET USER'S EV .IIF DF,CK.AD., JSR PC,CK.MAP ;VALIDATE ADDRESS RANGE BIT #1,(SP)+ ; ODD ADDRESSES OF EV ARE ILLEGAL BEQ 41$ ; SO LEAVE THEM BE IF EVEN MOV #74,-(SP) ; BUT MAKE EVA = 74 IF IT WAS ODD. MTPI @R2 ; (IN USER SPACE) 41$: MTPI @(R2)+ ; SET WAIT VARIABLE 0 FOR USER MFPI 2(R1) ; GET QTRAN BLOCK (LIKE DOS TRAN BLOCK) MOV (SP)+,R3 ; R3 INDEXES IT .REPT 3 MFPI (R3)+ ; GET WORDS, WC, ETC MOV (SP)+,(R2)+ .ENDR NEG -2(R2) ; FIX WORD COUNT FOR I/O MFPI (R3)+ MOV (SP)+,(R2) MFPI (R1) BISB 1(SP),1(R2) ;SET UP UNIT NUMBER FROM SUBUNIT TST (SP)+ ;RESTORE STACK MOV R0,2(R2) ;SAVE TCB ADDR FOR LATER RELOCATION ; ; LINK NOW CONTAINS: ; DEV BLK # ; MEM. ADDR -- USER VIRTUAL ; NEG. WC TO DO FOR XFER ; R2: FUNCT. CODE ; TCB ADDRESS (SEE MXIOHT FOR ITS USE) OR 0 IF KNL ; ; ; A DDB HAS THE FORMAT (PARTIAL) ; ; .WORD 0,0,0 ;DOS LINKS ; .WORD DRIVER ADDR ;DDB: .WORD USER CALL ADDR (BUSY DDB FLAG) ; .WORD SPEC FUNCT CODE OR USER LINE ADDR ; .WORD DEV. BLK # ; .WORD MEM. BLK ADDR ; .WORD WC (2 COMPL.) ; .WORD TRANSFER FUNCT ; .WORD COMPLETION RETURN ; .WORD DRIVER RESID. WC RETURN ; ;TRANSFER FUNCT: ;BITS MEANING ;15 PARITY ERR ;14 EOF/EOD ;13,12 RESERVED ;11 DECTAPE REVERSE ;10,9,8 UNIT # ;7 OPEN/CLOSED ;6,5,4 RESERVED ;3 TT ECHO CONTROL ;2 TRANSFER IN ;1 TRANSFER OUT ;0 ASCII(0)/BINARY(1) ; ;ON DRIVER CALL, R0 POINTS TO DDB; CALL VIA JSR PC,DRIVERSUB ; ;ON INT. RETURN TO @DDB+14 ; ;STACK SHOULD BE: ; INT PS ; INT PC ; INT R5 ; INT R4 ; INT R3 ; INT R2 ; INT R1 ; INT R0 .IF DF,SAXCL MOV R5,R0 ;POINT R0 AT LINKBLK JSR PC,MX.IOH ;TRY TO START UP I/O .ENDC ; .ENDC .IFF ;NEXT THE RSX VERSION ;NOTE: ;FOR RSX11 TO USE THE QTRAN MACRO, THE FOLLOWING CHANGES ARE ;DEFINED: ; 1. THE DEVICE ARGUMENT AND LUN NUMBERS MAY BE EITHER OF ; THEM 0, IN WHICH CASE VALUES IN DB WILL BE USED ; 2. THE QBOCK IS A QIO$ DPB (OR ANY OTHER RSX DPB...) ; 3. THE EVENT VARIABLE IS THE I/O STATUS BLOCK; RESERVE 2 WORDS. ; NOTE: THE WORD BEFORE THE I/O STATUS BLOCK WILL BE USED ; TO DETERMINE A TASK TO CALL ON I/O COMPLETION VIA A ; PRIREQ REQUEST. IF THE LUN ARGUMENT IS SPECIFIED AND ; CONTAINS A NONZERO HIGH BYTE, THE WORD AHEAD OF THE ; I/O STATUS BLOCK IS ASSUMED TO HAVE A TASK NUMBER ; (EXCEPT THAT 0 IS ILLEGAL) FROM 1 TO THE MAX. NO. OF ; TASKS. THIS WORD WILL BE CLEARED IF THE LUN ARGUMENT ; HIGH BYTE IS SPECIFIED AND ZERO. IF THE EV ADDR AND ; THE LUN ARGUMENT ARE BOTH OMITTED, THE CALL MAY TAKE ; PLACE IF THE WORD AHEAD OF THE I/O STAT. BLK IS IN A ; LEGAL RANGE, THOUGH THE FIRST WORD OF THE I/O STATUS ; BLOCK WILL BE CLEARED ONLY BY RSX. RACE CONDITIONS ARE ; UNLIKELY BUT SHOULD BE CONSIDERED. (ESP. IF QQIO IS DEFINED). ; 4. AN AST WILL BE ADDED TO THE DB IF A QIO$ AND WILL OINT BACK ; TO A ROUTINE TO RESTART THE MSX SCHEDULER AT I/O COMLETION. .MCALL DIR$,EXIT$S MOV 2(R1),R3 ;GET QBLOCK ADDRESS (SHOULD BE DPB ADDR) CMPB @R3,#1 ;QIO$? BNE 100$ ;NO, NO MODS TO DPB TST 4(R1) ;WAS AN IOSB (EVENT FLAG) SPECIFIED? BEQ 2$ ;IF 0, ASSUME NOT ; IF WORD AHEAD OF I/O STATUS BLOCK IS IN RANGE 1-MAX TASK NO, ; ALLOW AST RETURN TO TASK NO. (N) WHERE N IS CONTENTS OF THAT ; WORD. NOTE WE AVOID 0 SINCE IT IS TOO EASY FOR THAT TO APPEAR BY ; ACCIDENT. THIS WILL BE DONE IF HIGH BYTE OF LUN REQUEST HAS NONZERO ; CONTENTS. ONLY FILL IN LOW BYTE OF LUN FIELD OF DPB; ASSUME ; HIGH BYTE IS 0 INITIALLY AND REMAINS SO. MOV 4(R1),R2 ;GET I/O STAT BLK ADDR MOV R2,Q.IOSB(R3) ;STASH I/O STAT BLK ADDR IN DPB CLR @R2 ;ZERO EV ALSO ON DIRECTIVE TSTB 1(R1) ;NOW IS COMPLETION REQUEST FLAG SET? BNE 123$ ;IF SO SKIP OVER THE NEXT INSTRUCTION CLR -2(R2) ;IF NOT PREVENT IT FROM LOOKING LIKE IT WAS 123$: 2$: TSTB (R1) ;WAS LUN NUMBER FILLED IN? BEQ 1$ ;NO MOVB @R1,Q.IOLU(R3) ;YES; FILL IN LUN FIELD (WORD) IN DPB ;NOTE Q.IOLU+1(R3) UNCHANGED, ASSUMED ZERO ;NOW FILL IN OUR AST ADDRESS MOV #MX.IAS,Q.IOAE(R3) ;FILL IN I/O AST WHEN IT FINISHES. ;NOTE THAT RSX ONLY DOES AN IMPLIED SUSPEND IF 2 I/O REQUESTS ; ARE OUTSTANDING ON A LUN IF THE TASK IS CHECKPOINTABLE. THUS IF ; THE TASK IS TO BE NONCHECKPOINTABLE (PROBABLY THE USUAL CASE) WE ; CAN LET RSX WORRY ABOUT THE QUEUES. HENCE IF THE PARAMETER ; QQIO IS UNDEFINED, MSX WILL NOT QUEUE REQUESTS INTERNALLY. OTHERWISE ; IT WILL. .IF DF,QQIO MOV Q.IOLU(R3),R2 ;GET LUN NUMBER INC R2 ;BUMP LUN # BY 1 ASL R2 ;ADD 2 TO MAKE AN ADDRESS ADD R2,Q.IOAE(R3) ;AND OFFSET AST BY LUN NO. .ENDC ;QQIO ;NOW ISSUE THE CALL TO RSX. ; 1$: .GLOBL MX.IAS ;N.B.-- THE I/O THAT IS QUEUED BY RSX WILL SUSPEND A TASK IF 2 SUCCESSIVE ;QIO REQUESTS OCCUR TO A SINGLE LUN. THEREFORE, FOR QIO$ REQUESTS, GENERATE ;AN INTERNAL QUEUE THAT IS SERVICED BY AST ROUTINES TO DE-QUEUE THE NEXT ;REQUEST. THIS WILL ALLOW EACH SUBTASK TO ISSUE QIO REQUESTS WITHOUT ALLOWING ;RSX TO SUSPEND THE ENTIRE SYSTEM AND WITHOUT NEED FOR FURTHER COMPLEX ;INTERNAL SYNCHRONIZATION. FOR NORMAL OTHER RSX REQUESTS, JUST ISSUE THE ;DIRECTIVE. ; ;PERFORM QUEUE OPS ON A PER-LUN BASIS MOVB Q.IOLU(R3),R2 ;OBTAIN THE LUN NUMBER CMP R2,#NLUNS ;IS THE LUN A QUEUE-ABLE ONE? BHI 100$ ;NO, JUST DO THE QIO$ CMP Q.IOFN(R3),#IO.WLB ;IS IT IO.WLB TO THIS LUN? BNE 154$ ;NO, SKIP MOV #IO.WVB,Q.IOFN(R3) ;YES, MAKE IT IO.WVB 154$: CMP Q.IOFN(R3),#IO.RLB ;IS IT IO.RLB? BNE 155$ ;NO, PROBABLY OK MOV #IO.RVB,Q.IOFN(R3) ;YES, MAKE IT IO.RVB 155$: .IF DF,QQIO ASL R2 ;MAKE AN OFFSET 120$: MOV QIN(R2),R4 ;GET INPUT POS. REL TO TABLE MOV R4,R5 ADD QUEUE(R2),R4 ;ADD TABLE START TO GET ADDR TST @R4 ;SEE IF I/O IN PROGRESS NOW THERE (ELSE 0) BEQ 4$ ;IF 0, START A QIO NOW. ;NOT POSSIBLE TO DO QIO$ NOW; SEE IF WE CAN QUEUE IT FOR LATER. ;LOCK OUT INTERRUPTS FIRST FOR TABLE MANIPULATIONS MOVB #340,@#PS ;SET TO PRI 7 MOV QOUT(R2),R4 ;GET OUTPUT POSITION TO CHECK WE DON'T PASS ADD #2,R5 ;NEW INPUT POSITION CMP R5,#QSIZE ;SEE IF PAST END... BLO 5$ ;IF NOT, OK NOW CLR R5 ;IF SO RESET BACK TO 0. 5$: CMP R5,R4 ;SEE IF ABOUT TO USE CURRENT OUTPUT LOC BNE 6$ ;IF NOT, ALL OK. .MCALL SPND$S ;IF SO, WE HAVE NO MORE SPACE SO SUSPEND CLRB @#PS ;BACK TO PRI 0 SPND$S ;AWAIT SOMETHING GOOD... BR 120$ ;THEN TRY AGAIN 6$: MOV R5,QIN(R2) ;UPDATE INPUT POINTER ADD QUEUE(R2),R5 ;NOW POINT AT QUEUE ELEMENT MOV R3,@R5 ;AND SAVE THE DPB ADDRESS CLRB @#PS ;BACK TO PRI 0. BR 101$ 4$: ;HERE, OK TO DO THE QIO$ NOW. MOVB #340,@#PS ;SET TO PRI 7 MOV R5,QIN(R2) ;UPDATE INPUT POINTER ADD QUEUE(R2),R5 ;NOW POINT AT QUEUE ELEMENT MOV R3,@R5 ;AND SAVE THE DPB ADDRESS CLRB @#PS ;BACK TO PRI 0. .ENDC ;QQIO 100$: CLRB @#PS ;BACK TO PRI 0. MOV #1,MX.ARC ;FLAG AST RECOGNITION INHIBITED .MCALL DSAR$S DSAR$S ;DISABLE AST RECOGNITION DIR$ R3 ;ISSUE THE CALL. 101$: .ENDC QTX3: MOV #6,R2 ; SET POP VALUE JMP SETSEV ; AND USE COMMON EXIT ; NOTE, THIS EXIT FORCES A SCAN. THIS IS NEEDED!!!! ;-- ERRORS DETECTED ABOVE COME HERE FOR QTRAN QCRASH: ;HALT .IF NDF,SAXCL ; BR . TST 4(R1) ;ANY EV THERE BEQ QTX3 ;IF NOT, NO BUMP MOVK #1,@4(R1) ;IF SO, PUT -1 IN EV TO SIGNL ERR BR QTX3 ;IF SO, EXIT AFTER FLAGGING ERR .IFF ;IF I/O QUEUE FAILS SEND USER A -1 AS HIS EV TO TELL HIM TO RETRY MOV #-1,-(SP) ;(HE'LL BE MAPPED IN...) MTPI @4(R1) ;SO SEND HIM THE EV ; MOV #6,R2 ;FAKE UP RETURN ; JMP SETSEV ;LET HIM KNOW... BR QTX3 ;NOW LEAVE .ENDC .IF NDF,$$DOS QSIZE=40 ;NUMBER OF BYTES IN QUEUES NLUNS=2 ;NUMBER OF LUNS TO DO QUEUES FOR... .IF DF,QQIO ;NO NEED FOR QUEUE DATABASE IF NO QUEUES QIN: .BLKW NLUNS .WORD 0,0,0,0,0 ;SAFETY QOUT: .BLKW NLUNS .BLKW 5 ;SAFETY QUEUE: $$$$=IOQUE NNN=NLUNS+3 .REPT NNN .WORD $$$$ $$$$=$$$$+QSIZE .ENDR IOQUE: .REPT NNN .BLKB QSIZE ;SPACE FOR I/O QUEUES .ENDR ;ROUTINE TO DO THE CLEARING OF I/O QUEUES. CALLABLE FROM COMPLETION ;AST AT END TO ISSUE THE NEXT QIO. .GLOBL MX.QNX ;NEXT QIO$ ; JSR PC,MX.QNX AFTER POSTING INTERRUPT AND ;BEFORE RETURN FROM AST. ; EXPECTS CALLER R0 TO BE LUN NUMBER MX.QNX: ASL R0 ;MAKE OFFSET OF LUN MOV R1,-(SP) MOV R2,-(SP) MOV QOUT(R0),R1 ;OUTPUT QUEUE LOC ;N.B. AST RECOGNITION DISABLED HERE SO NO BOTHER TO GO TO PRI0 7 MOV R1,R2 ADD QUEUE(R0),R1 ;POINT AT OUTPUT QUEUE USED CLR @R1 ;FLAG DONE WITH IT CMP R2,QIN(R0) ;OUTPUT AND INPUT ELEMENTS ALIKE? BEQ 100$ ;YES, I/O DONE FINALLY ADD #2,R2 ;NEXT OUTPUT LOC CMP R2,#QSIZE ;TOO BIG BLO 1$ ;NO, OK CLR R2 ;YES, CIRCULAR BUFFER IT BACK 1$: TST 2(R1) ;ANYTHING TO DO AT NEXT LOC? BEQ 100$ ;NO, SKIP IT. MOV R2,QOUT(R0) ;POINT AT NEXT OUTPUT LOC ADD QUEUE(R0),R2 ;POINT AT CORE LOC NOW TST @R2 ;ANYTHING TO DO HERE? BEQ 100$ ;NO, NO RSX CALL. .MCALL DIR$ DIR$ R2 ;ISSUE THE NEXT QIO$ 100$: ;FALL THRU TO HERE IF NO MORE TO DO MOV (SP)+,R2 MOV (SP)+,R1 RTS PC .ENDC ;QQIO .ENDC .IF DF,VARPRI ;ALTP - ALLOW TASKS TO ALTER THEIR PRIORITY IF NOT TASK 0. ;CALL: ; MOV TASKNAME,-(SP) ;0 IMPLIES THIS TASK ; MOV #NEWPRIO,-(SP) ;NEW PRIO, BUT NOT OVER 249. ; TRAP 27 ALTP: KMOV (R1),R5 ;NEW PRIORITY CMP R5,#250. ;SEE THAT ITS RANGE IS OK BHIS ALTPX ;IF NOT, HE LOSES. KMOV 2(R1),R3 ;GET TASK NAME OR NUMBER BNE 10$ ;(BETTER NOT BE 0) MOV @R0,R3 ;IF IT'S 0 USE THIS TASK'S NAME 10$: JSR PC,ATLOOK ;HUNT UP THE TASK BEQ ALTPX ;IF CAN'T FIND IT, IGNORE DIRECTIVE CMP R2,#MX.TBL ;ALSO DISALLOW MODS TO TASK 0 BEQ ALTPX ;LOOKS LIKE IT'S OK TO CHANGE THIS TASK'S PRIORITY SO DO SO. ;NOTE: TABLES ARE IN EACH CPU AND A TASK MAY HAVE DIFFERENT ;PRIORITIES IN DIFFERENT CPUS. MOVB #340,@#PS ;NO INTERRUPTS ALLOWED HERE! JSR R5,S.RSAV ;ALSO LEAVE OTHER REGS ALONE SUB #MX.TBL,R2 ;MAKE OFFSET ASH #<3-MX.CNT>,R2 ;TO MX.PRL TO FIND LOCATION THERE ADD #MX.PRL,R2 ;POINT AT THIS TASK'S PRIO LIST ;FIRST REMOVE THE TASK BEING ALTERED FROM THE QUEUE MOV 2(R2),R3 ;SAVE LAST POINTER MOV (R2),R4 ;AND NEXT POINTER MOV R4,(R3) ;OUR NEXT IS LAST'S NEXT MOV R3,2(R4) ;AND OUR LAST IS NEXT'S LAST ;ENTRY POINTED AT BY R2 IS NOW REMOVED FROM THE QUEUE. JUST GO DOWN ;THE QUEUE NOW AND LOOK FOR THE FIRST PRIORITY LOWER THAN THE ONE ;THE USER WANTS. MOV #MX.PRL,R0 ;POINT AT LIST HEAD MOV 2(R0),R1 ;AND AT LIST TAIL 1$: MOV (R0),R0 ;GET NEXT LIST ELEMENT CMP R0,R1 ;ARE WE AT END? IF SO PUT ELEMENT AS NEW LAST BEQ 20$ CMP 6(R0),R5 ;IS THIS PRIORITY LESS THAN THE ONE DESIRED? BGT 1$ ;IF NOT, LOOK FURTHER DOWN ;NOTE THAT WE DIDN'T INSPECT THE FIRST LIST ELEMENT; IT MUST NOT CHANGE. ;NOW WE CAN INSERT THE ELEMENT AHEAD OF THE ONE NOW POINTED TO BY R0. ;THIS CANNOT BE THE FIRST LIST ELEMENT!!! 25$: MOV 2(R0),R3 ;GET LAST ELEMENT MOV R0,(R2) ;THIS ONE IS INSERTED ELEMENT'S NEXT MOV R3,2(R2) ;THIS ONE'S LAST BECOMES INSERTED'S LAST MOV R2,(R3) ;INSERTED ONE BECOMES LAST ONE'S NEXT MOV R2,2(R0) ;AND INSERTED IS THIS ONE'S LAST ;NEW LIST ELEMENT IS NOW INSERTED. BR 30$ ;GO CLEAN UP 20$: MOV (R0),R0 ;TO INSERT AFTER LAST, GO AHEAD BY ONE AND ;INSERT BEFORE IT (MERGE TO SAVE CODE) BR 25$ ;USE COMMON INSERTION CODE ;CLEAN UP AFTER INSERTIONS. 30$: JSR R5,S.RRES ;RESTORE REGS BASHED ALTPX: MOV #4,R2 ;SET 2 ARGS TO REMOVE JMP SETSEV ;THIS DIRECTIVE CAUSES A SIG EVENT ;RETURN WILL EVENTUALLY REALLOW INTS. .ENDC ; KPWAIT SET TASK WAITING FOR EV IN KNL SPACE TO GO 0 OR + ; (EV MAY BE ANYWHERE IN KERNEL SPACE (EVEN THE I/O PAGE)) ; (TOO BAD IF IT GETS ERROR AND CLOBBERS TASK...TASK'S PROBLEM) ;CALL: ; MOV #VALUE,-(SP) ;VALUE TO PUT IN EV. ; MOV #ADDR,-(SP) ;ADDR OF EV IN KNL SPACE. 0 IMPLIES TIMER EV ; TRAP 25. ;ISSUE CALL ; ;DIRECTIVE IGNORED IF ERRORS SEEN. ; KPWAIT: KMOV (R1),R2 ;GET ADDRESS TO EXAMINE BNE 1$ ;IF NON 0, USE ADDRESS MOV TCBSCB(R0),R2 ;GET SCB ADDRESS BEQ 2$ ;IF 0, IGNORE CALL ;N.B. SCB SHOULD ALWAYS BE OK...ONLY SCREWUP IF USER CHANGED HIS SCB ADD #10,R2 ;OK, SO ADJUST TO SPARE WORD 1$: BIT #1,R2 ;ENSURE SCB ADDRESS IS VALID CRUDELY BNE 2$ ;IF NOT FORGET IT MOV R2,TCBEVA(R0) ;SET THIS EV TO WAIT FOR MOVB #13,TCBST(R0) ;SET KPWAIT STATE 13 TOO 2$: MOV #4,R2 ;SET TO FLUSH 2 ARGS JMP TRPSCN ;SCAN W/O SIG EVENT (CLOCK GIVES THAT) ; ; ; ATLOOK LOOKUP OF SPECIFIC TASK BY NAME ;------- .GLOBL ATLOOK ; ATLOOK ; R3 HAS NAME TO BE SEARCHED ATLOOK: MOV #MX.TBL,R2 ; MOVE ADDRES OF TCB ; MOV MX.ATL,R2 ;GET TCB ADDR ; BNE 11$ ; JMP CRASH ;REALLY BAD--SHOULDN'T HAPPEN ;11$: .GLOBL MX.TBE,MX.TBL TST R3 ;EXCEPTION TO TASK NUMBERS- 0 IS ILLEGAL BEQ MISSED ;SO IF HE GIVES 0, SAY NO TASK. CMP R3,#</MX.TBS> ;SEE IF R3 IS TASK NUMBER BHI ATLOOP ;IF NOT MUST BE RAD50 NAME ASH #MX.CNT,R3 ;MAKE TBL ADDR .GLOBL MX.CNT ADD R3,R2 ;BY ADDING OFFSET BR FOUND ;AND DECLARE WE HAVE IT! ATLOOP: TST (R2) ; IS THIS LAST ONE ? BEQ MISSED ; YES, NOT PRESENT CMP (R2),R3 ; IS THIS IT ? BEQ FOUND ; YES, REJOICE .GLOBL MX.TBS ADD #MX.TBS,R2 ; NO, KEEP LOOKING BR ATLOOP MISSED: CLR R2 ; RESET PTR TO SHOW MISSED FOUND: TST R2 ; CHECK ON WHETER NULL RTS PC ; TO MAKE IT EASY FOR CALLER .IF NDF,$$DOS ;FOR RSX VERSION... ;DEFINE I/O AST POINT FOR QTRAN I/O DONE OPERATIONS .IF DF,QQIO QGO: MOV R0,-(SP) ;SAVE R0 MOV 2(SP),R0 ;CALL ADDR SUB #MX.IAS,R0 ;MINUS START ASR R0 ;MAKE A LUN NO. OF IT DEC R0 BLE MX.IA2 ;BE SURE LEGAL RANGE JSR PC,MX.QNX ;MAKE NEXT QIO GO OUT MOV (SP)+,R0 ;GET BACK R0 TST (SP)+ ;FLUSH RETURN FROM JSR BR MX.IA2 ;AND GO TO MAIN LINE AGAIN .ENDC ; ; MX.IAS ; THIS ROUTINE IS ENTERED FROM I/O AST SERVICING AFTER ANY QTRAN I/O. ; IT LOOKS AT THE I/O STATUS BLOCK AND ITS PRECEDING WORD TO SEE IF ANY TASK ; SHOULD BE REQUESTED ON I/O DONE. IF THIS SHOULD BE SO, THE STACK IS ; MODIFIED TO GO TO MX.RQQ TO START UP THE NEW TASK. ; IF NO NEW TASK IS NEEDED, THE MAINLINE IS RESUMED AND THE MX.PST ; ROUTINE IS CALLED TO POST THE INTERRUPT WITH AST RECOGNITION DISABLED. ; THE SCANNER WILL TURN IT BACK ON WHERE IT IS NORMALLY INTERRUPTABLE. ; THIS IS DONE BY MOVING THE TOP ENTRIES OF THE STACK DOWN PRIOR TO ; ASTX$S CALL AND PUTTING APPROPRIATE INFORMATION ON TOP OF THE STACK. ; THE ORIGINAL ENTRY IS SAVED ON THE AST STACK. ; MX.IAS: .IF DF,QQIO JSR PC,QGO ;SET UP QIO FOR NEXT QUEUED ELEMENT JSR PC,QGO ;SET UP QIO FOR NEXT QUEUED ELEMENT JSR PC,QGO ;SET UP QIO FOR NEXT QUEUED ELEMENT JSR PC,QGO ;SET UP QIO FOR NEXT QUEUED ELEMENT JSR PC,QGO ;SET UP QIO FOR NEXT QUEUED ELEMENT JSR PC,QGO ;SET UP QIO FOR NEXT QUEUED ELEMENT JSR PC,QGO ;SET UP QIO FOR NEXT QUEUED ELEMENT JSR PC,QGO ;SET UP QIO FOR NEXT QUEUED ELEMENT JSR PC,QGO ;SET UP QIO FOR NEXT QUEUED ELEMENT JSR PC,QGO ;SET UP QIO FOR NEXT QUEUED ELEMENT JSR PC,QGO ;SET UP QIO FOR NEXT QUEUED ELEMENT JSR PC,QGO ;SET UP QIO FOR NEXT QUEUED ELEMENT JSR PC,QGO ;SET UP QIO FOR NEXT QUEUED ELEMENT JSR PC,QGO ;SET UP QIO FOR NEXT QUEUED ELEMENT JSR PC,QGO ;SET UP QIO FOR NEXT QUEUED ELEMENT JSR PC,QGO ;SET UP QIO FOR NEXT QUEUED ELEMENT ;NOTE-- MUST HAVE AT LEAST ENOUGH QGO CALLS TO HANDLE NO. LUNS USED. .ENDC ;QQIO .MCALL ASTX$S MX.IA2: .MCALL RSUM$S ;DO SOME FANCY STACK JUGGLING HERE TO GET THE MAINLINE TO ACT AS THOUGH ;IT GOT AN INTERRUPT AND WENT TO MX.AS1 TO POST THE INTERRUPT AND ;DO A TASK SCAN. .GLOBL MX.AS1 ;STACK NOW CONTAINS: ; DSW OF TASK PRIOR TO AST ; PC OF TASK PRIOR TO AST ; PS OF TASK PRIOR TO AST ; EVENT FLAG MASK ; EVENT FLAG MASK ; EVENT FLAG MASK ; EVENT FLAG MASK ; ; MOVE THE STACK DOWN 2 WORDS AND HAVE THE AST RETURN TO THE ; TASK AT MX.AS1 TO POST THE INTERRUPT FOR YOU ; SET UP FOR DIRECT CALL TO TASK. DEFAULT IS NOT TO, SO ALLOW ; NORMAL RETURN VIA MX.PST AND MX.AS1. THIS IS NOT ESPECIALLY ; CLEAN BUT IS NON-INTERRUPTABLE AND CANNOT BE REENTRANT ANYWAY, ; SO ITS SELF MODIFICATION IS NOT REALLY BAD PRACTICE. MOV #MX.AS1,MX.ASV ;MX.AS1 RETURN ; NOTE I/O STAT BLK ADDR STILL ON STACK HERE. MOV R0,-(SP) ;MAKE STACK CELL & SAVE R0 .IF DF,RQAST ;COMPLETION TASKS ONLY IF THIS IS DEFINED MOV 2(SP),R0 ;NEED I/O STAT BLK ADDR MOV -2(R0),R0 ;AND HAVE TO GET 0 OR TASK NO. ; THE REASON FOR THIS SQUEAMISHNESS IS NOT TO HAVE TO SAVE/RESTORE ANY ; MORE REGISTERS HERE THAN REALLY NECESSARY... BEQ 2$ ;0 IMPILES NO TASK... CMP R0,#</>; LEGAL TASK NUMBER? BHI 2$ ;NO, SKIP IT... ; NOTE: MX.RQQ REQUEST IS NOT REALLY QUITE REGULAR SINCE WE COULD BE ;ON MX.STK AT THE TIME OF THE I/O AST, BUT IT WON'T CHECK AND WE'LL SIMPLY ;SET THINGS UP SO THEY SHOULD BE OK ANYWAY. ON RETURN, THE STACK LOOKS LIKE ;A REQUEST CALL HAS BEEN MADE, SO THE RETURN WILL JUST GO TO IT... .GLOBL MX.RQQ .GLOBL RQ.R0 ASH #MX.TBS,R0 ADD #MX.TBL,R0 ;MAKE TCB ADDRESS MOV R0,RQ.R0 ;SET FOR R0 "RESTORE" AFTER INT. 1$: MOV #MX.RQQ,MX.ASV ;RETURN TO FAKED UP REQUEST ; ;NOTE THAT AFTER THE AST WE EITHER GO TO MX.AS1 TO POST THE INTERRUPT, ;OR TO MX.RQQ TO REQUEST ANOTHER TASK. IF ANOTHER TASK STARTS UP, THE ;TASK EXIT WILL CLEAN UP AFTER US. HOWEVER, WE WILL SET A SIGNIFICANT ;EVENT HERE TO BE EFFECTIVE AFTER THAT TASK EXITS CLRB MX.SEV ;(VOILA!) ;TO BE SURE THAT THE INTERRUPT IS NOT LOST. BR 15$ ;SKIP AST INHIBIT BUSINESS FOR NOW .ENDC ;RQAST ; 2$: MOV #1,MX.ARC ;NOW HAVE TO DISABLE ANY MORE AST'S UNTIL ;THE SCANNER GETS DONE WITH THIS ONE. DO SO ;AND FLAG IT... .MCALL DSAR$S DSAR$S ;OK, NO MORE AST'S NOW... ; ;(MAY WANT TO DO THIS BY BASHING RSX EVENTUALLY) ; 15$: MOV @SP,R0 ;GET R0 W/O RESTORE... ;NOTE THAT TOP OF STACK WAS I/O STAT BLK ADDR WHICH HAS TO BE POPPED ;PRIOR TO THE ASTX$S CALL SINCE THIS IS A QIO$ COMPLETION ROUTINE. MOV 4(SP),(SP) 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 MX.ASV,2(SP) ;MAKE RETURN GO TO MX.AS1 AS THOUGH FROM ;INTERRUPT CLR 4(SP) ;AT PRIO 0 TO KEEP RSX HAPPY ;NOW THE AST WILL RETURN AND IT WILL APPEAR THAT AN INTERRUPT OCCURRED ;TO MX.AS1. WE POST IT AND DISABLE AST RECOGNITION UNTIL RETURN ;TO GUARANTEE THE MSX REG SAVE/POST SEQ WILL NOT BE INTERRUPTED... ; NOTE NO DISABLE/ENABLE AST'S SINCE MX.PST PROTECTS ITSELF AGAINST ; INTERRUPTS BY BASHING PSW DURING STACK SWITCHES. ;EVENTUALLY FLAG SUSPENDED LOCALLY AND ALLOW THIS TO BE AVOIDED ;IF TASK NOT SUSPENDED MX.AXX:; RSUM$S ;RESUME MAINLINE IF SUSPENDED ;NO-OP RESUME SINCE WAIT LOOP USES WSIG$ NOW RATHER THAN SUSPEND... ASTX$S ;EXIT THE AST MX.ASV: .WORD 0 ;WHERE TO GO AFTER RETURN... MX.AS1: JSR R5,MX.PST ;ENTRY HERE FOR PSEUDO-INTERRUPT .WORD 0 ;PRI 0, NO REG SAVES RTI ;THEN BUZZ OFF. LET MSX DO ITS THING. .ENDC .END ; THATS IT