TCBISP=6 .MCALL ASTX$S,MRKT$S,ENAR$S,DSAR$S,WSIG$S ;THIS MODULE SHOULD BE ASSEMBLED TWICE, ONCE WITH "GBLDAT" DEFINED ;TO GET GLOBAL DATA, ONCE WITHOUT TO GET THE CONNECTION ROUTINES. .IF DF,GBLDAT .PSECT MAILBX,RW,CON,D ;INPUT DATA AREAS FOR EACH CPU. ASSUMES "NCPU" DEFINED OR DEFAULTS ;TO 3. THE SYSTEM USES INFUL SET NONZERO AS A VIRTUAL "INTERPROCESSOR ;INTERRUPT" TO FLAG DATA PRESENT. CLOCKS ARE USED TO GIVE THE SYSTEM ;A CHANCE TO SAMPLE INFUL. .IIF NDF,NCPU,NCPU=3 ;DEFAUTL 3 CPU SYSTEM ..$$=0 .GLOBL INBOX,INFUL ;FORCE ACCESS TO DATA VIA INBOX POINTERS ;INDEXED BY CPU # -1. INBOX: .REPT NCPU .WORD MBDAT+..$$ ..$$=..$$+324.+324. .ENDR MBDAT: .BLKW 324.*NCPU INFUL: .BLKW NCPU ;FULL FLAGS. (NOTE IAS/RSX WILL MAKE THEM ZERO ;INITIALLY. ALSO SETUP MUST. .IFF .IIF DF,MLTCPU, .GLOBL MINAST .TITLE MXCONN ;MSX-11 CONNECTION SPECIFICATION ROUTINES ; ; THESE ROUTINES SPECIFY THE MSX-11 SYSTEM ;INTERCONNECTIONS AND ARE LINKED WITH AN MSX SYSTEM TO ;PROVIDE A COMPLETE MULTIPROCESSING SYSTEM. ; ; ENTRY POINT NAMES: .GLOBL SETUSG,DQRCV,ACTIV8,ACTIV .GLOBL XNOTFY,ROUTE,MGXMT,MGXMTR .GLOBL RDMSG,MSGERR,REXMIT,REBRDC ; ;SETUSG -- INITIAL SETUP OF CPU NUMBER FOR ALL TASKS, SETTING ; UP WHICH CPU IS RUNNING WHICH TASKS AT SYSTEM INITIAL ; START. ALSO MUST SET UP THE INITIAL ROUTING TABLE, INTERRUPT ; VECTORS FOR COMM. HARDWARE, AST'S, AND USAGE TABLES USED ; FOR LOAD BALANCING (INCLUDING CPU.PR TABLE). SETUSG: ;SET UP THE TASK USAGE JSR R5,S.RSAV .IF DF,DY$MEM ;CLEAR MEM. BITMAP MOV #MX.MMP,R0 MOVB #17,(R0)+ 43$: CLRB (R0)+ CMPB R0,#MX.MME BLOS 43$ ;CLEAR MEM BITMAP MOV #MX.MUH,MX.MUH ;ALSO INIT MUL LISTHEAD MOV #MX.MUH,MX.MUH+2 MOV #4,MX.MAV ;INIT MEM AVAIL. COUNTER .ENDC MOV #MX.TBL,R0 1$: MOVB #0,TCBCPU(R0) ;SET UP NO CPU FOR ALL MOVB MX.BUS,TCBBUS(R0) ;ALSO THIS BUS MOV @R0,R4 ;GET TASK NAME BIC #17,R4 ;SEE IF IT BEGINS WITH 42420 (KBn) CMP R4,#42420 ;KBn (N IS A FUNCTION OF CPU NUMBER? BNE 16$ ;NO, NORMAL PROCESSING MOV @R0,R5 ;FIND WHERE IT SHOULD BE ACTIVE BIC #^C17,R5 ;FROM LOW BITS OF NAME MOVB R5,TCBCPU(R0) ;AND FILL IN WHERE THE CONSOLE TASK IS RUNNING ADD MX.CPU,R4 ;SEE IF IT IS OUR CONSOLE ; CLRB TCBST(R0) ;SET INACTIVE (*** NO-OPPED***) ;NOTE THE CONSOLE TASK NAME IS .RAD50 /KB/ + CPU NUMBER, HENCE /KBA/, /KBB/ ; /KBC/, ETC. CHECK NAME TO SEE WHOSE CONSOLE TASK IT IS. CMP R4,@R0 ;IF IT IS NOT OUR CONSOLE LEAVE IT INACTIVE BNE 15$ MOVB #4,TCBST(R0) ;OTHERWISE START IT AS ACTIVE (OUR CONSOLE) BR 16$ ;IF ELSEWHERE MAKE IT APPEAR REALLY ACTIVE 15$: MOV TCBISP(R0),TCBDSP(R0) ;WE HAVE TO MAKE THESE TASKS KNOWN TO PERMIT NOTIFICATION TO THEM OF ;SPAWNED TASK EXITS. MOVB #4,TCBST(R0) ;"ACTIVE ELSEWHERE" DEC R5 BLT 16$ ;MAKE OFFSET OUT OF CPU NUMBER ASL R5 INC CPU.PR(R5) ;FLAG COUNT OF TASKS ACTIVE ELSEWHERE 16$: ADD #MX.TBS,R0 CMP R0,#MX.TBE ;AT END OF TABLE? BLO 1$ ;IF NOT SET UP OTHER TASKS. JSR R5,S.RRES RTS PC ; ; ;DQRCV -- START I/O RECEPTION ON ALL BUSSES TO WHICH THE CPU IS ; CONNECTED. DQRCV: ;I/O INPUT STARTUP .IF DF,MLTCPU MOV #INFUL,R0 MOV #NCPU,R1 ;CLEAR FULL MAILBOX FLAGS 1$: CLR (R0)+ DEC R1 BGT 1$ ;PROTECT AGAINST ERRANT SOB LOOP CLRB @#PS ;ENSURE INTS OK FOR RSX MRKT$S ,#2,#2,#MINAST ;GET AST TO START SAMPLING FULL .ENDC ; ;FOR SIMPLY CONNECTED (1 BUS) SYSTEM SIMULATION, SET UP AN AST FOR ;RECEIVE BY REFERENCE. AT THE AST, DISABLE AST RECOGNITION AND FLAG ;BY SETTING MX.ARC TO MX.ARC+1, THEN COPY DATA TO MESSAGE AREA. THEN ;CALL ASTSET TO FAKE AN INTERRUPT TO MXSCNS' ENTRY INMSGI. CLC RTS PC ; ; ;ACTIV AND ACTIV8 -- SET UP ACTIVE-TASK NOTIFICATION ; ;1. ARBITRATE PRIORITY (POSSIBLY USING CPU.PR TABLE) TO FIND WHICH CPU ;TO RUN A TASK IN. ON ENTRY, R0=TCB OF TASK TO BE STARTED, MARKED FOR ;STARTUP IN LOCAL CPU. ;2. SET UP THE TCB TO REFLECT THE CPU TO ACTUALLY BE USED. ;3. EMIT A MESSAGE TO ALL CPU'S THAT THIS TASK IS TO BE RUN WHERE DECIDED ;IN 1. ABOVE (AND FOR THAT CPU TO REALLY START THE TASK) ;4. RETURNS CARRY BIT CLEAR IF STARTING THE TASK "HERE", SET IF STARTING ;IN ANOTHER CPU. ;;;N.B. -- ALL ACCESS TO TCB MUST BE INTERLOCKED AGAINST OTHER CPU'S ;;;BY THIS ROUTINE IF SHARED MEMORY IS USED!!!!! ;5. SET STATE TO 200 OR 206 IF AWAITING A LOAD AND SET UP AN INPUT TO A ;LOADER TASK TO FILL CORE. IT MUST CLEAR THE SUSPEND BIT IN TCBST AND ;IN THE SCRATCH CONTROL BLOCK. THIS ROUTINE MUST ALLOCATE THE MEMORY AND ;BE SURE THAT TASK'S MESSAGE SPACE IS RESERVED SINCE IT WILL BE USABLE ;EVEN BEFORE THE TASK IS LOADED TO DEQUEUE THE MESSAGES. THE LOADER TASK ;MUST CLEAR THE SUSPEND BIT IN ALL PLACES. THIS ROUTINE MUST SET UP THE ;APR'S ALSO IF A TASK IS TO BE LOADED, AND OTHER ADDRESS TABLES MUST ;BE SET UP ALSO. ; ;ACTIV8 JUST STARTS THE TASK AT ITS NORMAL START. ACTIV STARTS IT (WHERE ;ALREADY GOING ONLY) AT AN OPTIONAL START (FOR RESUME) WHICH IS IN THE ;TCB OR STACK LOCATION FOR THE DYNAMIC PC. ACTIV DOES NOT HAVE TO DO ALL ;OF THE ARBITRATION SINCE THE TASK SHOULD BE ACTIVE, BUT SHOULD CALL ACTIV8 ;IF THE TASK IS NOT ALREADY STARTED. IN BOTH, R0=TCB AT CALL. .IF NDF,MLTCPU ACTIV: TST TCBDSP(R0) ;TASK GOING? BNE 1$ ;YES, RETURN (1-CPU CASE..MUST NOTIFY ;RUNNER CPU IF GOING ELSEWHERE) JSR PC,ACTIV8 ;NO, START IT UP 1$: CLC RTS PC ACTIV8: ;IF THIS CPU HAS FEWER TASKS THAN OTHERS, LEAVE TASK HERE AND RETURN ;WITH C CLEAR. ELSE FIND BEST CPU, ;GET A NODE, FILL IN A TASK ACTIVATE MESSAGE AND SEND VIA MGXMTR. ;RETURN WITH C SET IN THAT CASE. CLC ;SAY HERE IS OK RTS PC .IFF ACTIV: JSR R5,S.RSAV ;SAVE CALLER'S REGS ;CHECK THAT THE TASK BEING RESUMED IS REALLY ELSEWHERE. IF IT IS ;HERE, WE NEED ONLY LET IT GO THROUGH. CMPB TCBCPU(R0),MX.CPU ;RUNNING HERE? BEQ AC0$ ;YES, LET IT GO ON. JSR PC,GETNOD ;GET A SYSTEM NODE POINTED TO BY R1 CMP R1,#4 ;4 OR LESS MEANS NO NODE BHI AC1$ ;ELSE OK AC0$: JSR R5,S.RRES ;FAILURE...RETURN FROM CALL CLC ;(SAY RUN THE TASK HERE...) RTS PC AC1$: MOV R4,14(R1) ;R4 IS RESUME ADDRESS. (ONLY CALL FROM RESUME) BR ACTCMN ;DO COMMON WITH ACTIV8 ACTIV8: JSR R5,S.RSAV ;SAVE CALLER'S REGS MOV #42420,-(SP) ;FORM OUR CONSOLE'S NAME ADD MX.CPU,(SP) ;USING CPU NUMBER AND RAD50 FOR "KB" CMP (SP)+,@R0 ;IF IT IS OUR CONSOLE, DO NOT NOTIFY ALL. BEQ AC0$ ;IF IT IS TASK "KBT", LET IT STAY WHERE IT IS. JSR PC,GETNOD ;GET THE NODE CMP R1,#4 BLOS AC0$ ;IF WE FAIL, RETURN AND RUN HERE CLR 14(R1) ;SAY NO RESUME ADDRESS ACTCMN: MOV R1,R4 ;SAVE NODE ADDRESS MOV #2,(R1)+ ;SET REQUEST BROADCAST TYPE MOV MX.CPU,(R1)+ ;REQUESTED BY US MOV @R0,(R1)+ ;SEND TASK NAME CLR (R1)+ ;(EVERYONE SHOULD GET IT) MOV MX.CON,(R1)+ ;RE-XMIT COUNT IS NET CONNECTIVITY ;NOW FIGURE OUT WHERE THE TASK OUGHT TO RUN 1$: CLR R2 ;R2=INDEX OF LEAST-USED CPU MOV #-1,R3 ;R3= # TASKS ON LEAST-USED CPU (UNSIGNED) MOV R4,-(SP) ;SAVE R4 FOR NODE ADDRESS TOO MOV #CPU.PR,R4 ;R4 POINTS AT LIST OF ACTIVE TASKS 4$: CMP @R4,R3 ;THIS CPU LESS ACTIVE THAN CURRENT LEAST? BHI 3$ ;NO, MORE ACTIVE MOV R4,R2 ;YES, UPDATE INDEX SUB #CPU.PR,R2 ;(MAKE IT A REAL INDEX) MOV @R4,R3 ;AND SAVE VALUE 3$: TST (R4)+ ;PASS THIS CPU CMP R4,#> ;PAST LAST CPU? BLO 4$ ;IF NOT, LOOK AT ONE MORE ;NOW HAVE INDEX OF LEAST ACTIVE CPU. START THE TASK THERE. MOV (SP)+,R4 ;GET BACK THE NODE ADDRESS ASR R2 ;MAKE A CPU NUMBER OUT OF THE INDEX INC R2 ;LIKE THIS MOV R2,(R1)+ ;FILL IN DESIRED CPU IN MESSAGE MOVB R2,TCBCPU(R0) ;AND SET INTO THE TCB ENTRY TOO. 2$: TST (R1)+ ;PASS RESUME ADDRESS (ALREADY THERE) MOV TCBSPW(R0),R3 ;FIND OUT WHO CALLED US MOV @R3,(R1)+ ;FILL IN CALLER NAME, OR 0. MOV TCBKEV(R0),(R1)+ ;FILL IN EV ADDR FOR CALLER MLS$D=0 .IF DF,SE$K MLS$D=14. ;NO BYTES EXTRA TO SEND MLS STUFF ACROSS IN JSR PC,MLSFIL ;FILL IN MLS DATA FOR TASK CLEARANCE... .ENDC MOV MX.BUS,R3 ;GET BUS NO. (CURRENTLY UNUSED...) MOV #22+MLS$D,R5 ;MSG=22 BYTES LONG (OCTAL) CLR R2 ;SET BROADCAST JSR PC,MGXMTR ;SEND MESSAGE AND DELETE THE NODE JSR R5,S.RRES ;GIVE THE USER BACK HIS REGS CMPB MX.CPU,TCBCPU(R0) ;SEE IF WE STAYED HERE BNE 27$ ;IF NOT RETURN CARRY SET CLC RTS PC 27$: SEC ;RETURN CARRY SET = TASK MOVES RTS PC .ENDC ; ; ; ;XNOTFY - TELL ALL CPU'S THAT A TASK HAS EXITED. ; INPUT R0 HAS TCB ADDRESS. XNOTFY MUST BROADCAST AN EXIT-NOTIFY ;MESSAGE. XNOTFY: ;GET A NODE, FILL IN AN EXIT MESSAGE, AND EMIT VIA MGXMTR .IF DF,MLTCPU JSR R5,S.RSAV JSR PC,GETNOD ;GET A NODE FOR THHE EXIT MESSAGE CMP R1,#4 BLOS 1$ ;IF NONE, RETURN MOV R1,R4 ;SAVE NODE ADDRESS MOV #3,(R1)+ ;SEND THE MESSAGE MOV @R0,(R1)+ ;TASK NAME MOV TCBCPU(R0),(R1)+ ;CPU/BUS NO. MOV TCBKEV(R0),(R1)+ ;WHERE TO TELL CALLER MOV MX.CON,(R1)+ ;NET CONNECTIVITY CLR (R1)+ ;TELL ALL MOV TCBSTT(R0),(R1)+ ;EXIT STATUS MOV MX.BUS,R3 ;SET UP BUS NO. MOV #16,R5 ;MESSAGE LENGTH CLR R2 ;SET THIS AS A BROADCAST JSR PC,MGXMTR ;SEND IT AND ERASE NODE 1$: JSR R5,S.RRES CLC RTS PC .IFF CLC RTS PC .ENDC ; ; ;ROUTE -- FIND THE BUS TO USE TO ROUTE A MESSAGE TO THE TASK ;WHOSE TCB ADDRESS IS IN R2. ; FINDS A ROUTE AND CLEARS CARRY IF R3 CONTAINS A VALID BUS ;TO SEND A MESSAGE TO TASK ON. IF NO ROUTE IS AVAILABLE, SETS CARRY. ;BUS NUMBERS ARE 1-255. (1-377 OCTAL). NOTE THAT A CARRY SET RETURN ;WILL CAUSE THE TASK TO BE MARKED EXITED. ROUTE: MOVB MX.BUS,R3 ;GET OUR BUS FOR 1-CPU/BUS CASE ;(FOR 1 BUS SYSTEMS THIS IS OK) CLC RTS PC ; ; ;MGXMT AND MGXMTR -- SEND MESSAGE (POSSIBLY DELETING NODE) ; ;MGXMT AND MGXMTR SEND A MESSAGE. THE NODE IS ADDRESSED BY R4, R5= ;NUMBER OF WORDS TO SEND, R3=BUS NUMBER TO USE, R2= CALLED TASK TCB ADDR ; ;(THE NODE WILL HAVE SOME EXTRA WORDS). NODES ARE FROM THE SYSTEM POOL, ;AND ARE DELETED AFTER TRANNSMISSION BY MGXMTR, THOUGH NOT BY MGXMT. ;MGXMT IS CALLED WHERE THE MESSAGE IS IN THE TASK'S SPACE CURRENTLY ;MAPPED; MGXMTR ASSUMES THE MESSAGE IS IN A SYSTEM NODE AND THUS ;HAS TO ERASE THE NODE. MGXMT: .IF DF,MLTCPU JSR R5,S.RSAV ;PRESERVE CALLER'S REGISTERS TST R2 ;R2=0 IF BROADCAST TO ALL (EXCEPT US) BEQ 24$ MOVB TCBCPU(R2),R0 ;FIND WHERE CALLED TASK IS 24$: DEC R0 ;MAKE AN INDEX BLT 1$ ;IF IT WAS 0, ERROR SO IGNORE MSG ASL R0 ;ENWORD TIMOUT=150. ;TIMEOUT FOR MESSAGE SEND MOV #TIMOUT,R3 ;DON'T HANG HERE FOREVVER 3$: TST INFUL(R0) ;IS THE MAILBOX EMPTY? BEQ 2$ ;NO, GO USE IT. ;NOTE THAT FOR REALLY SEPARATE CPU'S WE WOULD NEED A BUSY AND A ;FULL SIGNAL, AS THE TCB GETTING CODE USES. WING IT HERE...NOT REALLY ;GOING TO HAVE A TEST-AND-SET JUST NOW. CLRB @#PS ;ENSURE INTS OK FOR RSX WSIG$S ;WAIT A BIT DEC R3 ;HAVE WE WAITED TOO LONG? BLE 20$ ;IF SO, RETURN BR 3$ ;OR WAIT SOME MORE 2$: COM INFUL(R0) ;FLAG DATA AREA OCCUPIED, NOT READY MOV INBOX(R0),R1 ;GET DATA AREA INC R5 ;ROUND UP TO WORD COUNT IN R5 CLC ROR R5 ;HALVE THE BYTECOUNT CMP 14(SP),#MGXMTR ;IN MGXMTR ROUTINE BLO 6$ ;NO, SKIP TO 6$ CMP 14(SP),#MGSV ;COME FROM MGXMTR? BHI 6$ ;NO, USE MTPI/MFPI 7$: MOV (R4)+,(R1)+ ;COPY DATA TO MAILBOX DEC R5 BGT 7$ ;(DO ALL WE NEED TO) BR 5$ 6$: ; .MACRO KMOV SRC,DST .IF DF,SAXCL MFPI SRC ;(NO I/D SPACE IN MSX!) MOV (SP)+,DST .IFF MOV SRC,DST .ENDC .ENDM 4$: ;ALLOW GATHER-WRITES SO THAT A MSG HEADER NEED NOT PRECEDE THE MESSAGE ;DIRECTLY IN A TASK. NOTE THAT THE NORMAL (1 BLOCK OF DATA) METHOD WAS ;CHOSEN TO MAKE IT EASIER TO DO DMA TRANSFERS FROM ONE CPU TO ANOTHER. ;HOWEVER, TO MAKE INPUT EASIER, 2 TRANSFERS WOULD BE PREFERABLE FOR ;INTERTASK MESSAGES. THE FIRST WOULD BE THE HEADER (AS FOR ALL MESSAGES) AND ;POSSIBLY SOMETIMES A LITTLE DATA. THE 2ND WOULD BE THE DATA, INTO THE AREA ;ALLOCATED IN THE TASK. THE INTERRUPT ROUTINE IN MXSCNS WOULD HAVE TO ;BE ALTERED TO SET UP THE SECOND AND ARRANGE FOR THE NEXT INTERRUPT ;(WHICH WOULD HAVE TO BE GUARANTEED AS THE NEXT ONE) TO COME BACK ;INTO THE MESSAGE-INPUT HANDLING LOGIC. PERHAPS SOME OTHER SWITCHING ;SCHEME THAT WOULD RESIST ERRORS IF THE NEXT INTERRUPT WERE ANOTHER MESSAGE ;WOULD BE BETTER. HOWEVER, THE COMPLETION OF THE DMA OF DATA WOULD THEN ;FINISH OFF THE MESSAGE. THIS WOULD REPLACE THE PRESENT LOGIC ;OF COPYING THE DATA INTO THE TASK'S SPACE FROM THE SYSTEM COMMON INPUT ;BUFFER. MOV R5,-(SP) ;SAVE COUNT TO DO MOV #6,R5 ;HDR HAS 6 WORDS FOR INTERTASK MESSAGES 41$: KMOV (R4)+,(R1)+ ;COPY THE DATA SOB R5,41$ ;DO ALL 6 WORDS MOV (SP)+,R5 ;GET BACK TOTAL LENGTH SUB #6,R5 ;MAKE IT DATA LENGTH BLE 42$ ;(GUARD AGAINST NULLS) TSTB -7(R1) ;SEE IF HIGH PRIO BYTE WAS NONZERO BEQ 43$ ;IF ZERO, DATA FOLLOWS IMMEDIATELY CLRB -7(R1) ;IF NOT, REMOVE THE FLAG KMOV @R4,R4 ;NOW POINT AT THE DATA .IF DF,CK.AD. MOV R4,-(SP) ;ADDRESS CHECK THE DATA JSR PC,CK.MAP MOV (SP)+,R4 .ENDC BIT #1,R4 ;BE SURE ADDR NOT ODD BNE 42$ ;IF ODD, NOT REAL 43$: KMOV (R4)+,(R1)+ DEC R5 ;NOW DO THE DATA BGT 43$ ;COPY TO MSG BUFFER 42$: 5$: MOV #1,INFUL(R0) ;FLAG DATA PRESENT JSR R5,S.RRES CLC ;NORMAL ALL-OK EXIT RTS PC 1$: 20$: JSR R5,S.RRES ;ERROR EXIT, CARRY SET ON RETURN SEC .ENDC RTS PC MGXMTR: .IF DF,MLTCPU ;JIGGER WITH NODE TO FLAG INT. HANDLER TO DELETE NODE... TST R2 ;IF R2=0, BROADCAST TO ALL BNE 24$ ;ELSE SEND TO ONE ONLY MOV #1,R0 ;START AT CPU #1 23$: CMP R0,MX.CPU ;DON'T SEND TO OURSELVES BEQ 26$ JSR PC,MGXMT 26$: INC R0 ;GO TO NEXT CPU CMP R0,#NCPU ;SEE IF AT END BLOS 23$ ;IF NOT AT END, DO ANOTHER SEND BR MGSV 24$: .ENDC JSR PC,MGXMT ;SEND TO THE ONE CPU ;ALLOCATE A REGION, FILL THE MESSAGE IN TO IT, SEND BY REFERENCE TO ;OTHER "CPU'S", AND FREE THE NODE CONTAINING THE MESSAGE ONCE IT IS ;COPIED TO THE REGION. ALSO DETACH THE REGION. MGSV: .IF DF,MLTCPU JSR R5,S.RSAV MOV R4,R5 ;POINT AT THE NODE WITH R5 SUB #4,R5 ;POINT AT POINTER FIELDS AHEAD OF DATA JSR PC,FRENOD ;FREE THE NODE JSR R5,S.RRES ;RESTORE REGS CHANGED .ENDC CLC RTS PC ; ; ;RDMSG -- READ IN THE NEXT MESSAGE INTO THE SYSTEM'S INPUT MESSAGE ;BUFFER ; RDMSG: ;ALLOW ANY ACTION NEEDED TO CONTINUE RECEIPT OF MORE RECEIVE-BY-REFERENCE ASTS .IF DF,MLTCPU CLRB @#PS ;ENSURE INTS OK FOR RSX MRKT$S ,#50.,#1,#MINAST ;ALLOW 50 TICK AST TO TRY AGAIN .ENDC CLC RTS PC .IF DF,MLTCPU ; ;MINAST - AST TO TEST WHETHER A MESSAGE MUST BE PROCESSED. MINAST: CLR @SP ;REMOVE EVENT FLG # MOVB MX.CPU,@SP DEC @SP ;CHANGE RANGE TO 0 --> NCPU-1 ASL @SP ;GET INDEX ADD #INFUL,@SP TST @(SP)+ ;SEE IF BUFFER WAS FULL BGT 1$ ;IF SO, BRANCH AND PROCESS (IF -, NOT USABLE NOW) JSR PC,RDMSG ;ELSE CAUSE ANOTHER AST LATER CLRB @#PS ;ENSURE INTS OK FOR RSX ASTX$S 1$: JSR R5,S.RSAV ;SAVE REGS FOR OUR JIGGERY-POKERY MOV #1,MX.ARC CLRB @#PS ;ENSURE INTS OK FOR RSX DSAR$S ;DISABLE AST RECOGNITION MOVB MX.CPU,R0 ;FIND OUT WHO WE ARE DEC R0 ASL R0 ;MAKE AN INDEX MOV #MSGDT,R1 ;GET INTERNAL INPUT BUFFER ;COPY DATA FROM MAILBOX TO OUR INTERNAL BUFFER AND FREE MAILBOX MOV #324.,R2 ;COPY ALL OF IT TO AVOID HAVING TO ANALYZE SIZE MOV INBOX(R0),R3 ;POINT AT MAILBOX 2$: MOV (R3)+,(R1)+ SOB R2,2$ ;DO ALL OF BUFFER CLR INFUL(R0) ;NOW MARK MAILBOX FREE AGAIN JSR R5,S.RRES MOV #INMSGI,-(SP) ;NOW HANDLE "INTERRUPT" AT INMSGI JMP ASTSET ;AFTER ASTSET EXITS THE AST. .ENDC ; ; ;MSGERR -- FLAG ERROR IN MESSAGE RECEIVED TO SENDER AND RESEND. ; ; ON ENTRY, 4(R0)=CALLED TSK NAME, R2=TCB ADDR, @R0=CALLER TASK ;NAME. MODIFY THE MESSAGE TO REPLY THAT SOMETHING WENT WRONG...MX.ERR=CODE ;AND SEND MESSAGE BACK TO CALLER AS ERROR NOTICE. ; MSGERR: ;FILL IN AN ERROR MESSAGE AND SEND VIA MGXMTR .IF DF,MLTCPU JSR R5,S.RSAV MOV (R0),R3 ;GET TASK NAME JSR PC,ATLOOK ;FIND HIS TCB BEQ 1$ ;IF NONE, FORGET IT. CMPB TCBCPU(R2),MX.CPU ;TASK HERE? BEQ 1$ ;IF SO, NO ACTION NEEDED. JSR PC,GETNOD ;GET A MSG NODE CMP R1,#4 ;DID THAT WORK? BLOS 1$ ;NO, SKIP THE REST MOV R1,R4 ;SAVE NODE ADDRESS MOV #5,(R1)+ ;FILL IN MODIFY-GLOBAL-EVENT VARIABLE TYPE MOV TCBCPU(R2),(R1)+ ;CALLER'S CPU/BUS MOV 10(R0),(R1)+ ;CALLER'S EV ADDRESS CLR @R1 ;PRESET FOR CPU ONLY MOVB TCBCPU(R2),@R1 ;FILL IN CPU NO. TST (R1)+ ;PASS CPU NO. MOV MX.ERR,(R1)+ ;RETURN MX.ERR TO CALLER MOV #16,R5 ;MESSAGE LENGTH JSR PC,MGXMTR ;SEND THE MESSAGE 1$: JSR R5,S.RRES .ENDC RTS PC ; ; ;REXMIT -- RETRANSMIT MESSAGE ON BUS FOUND BY ROUTE ; ;REXMIT RESENDS THE MESSAGE JUST RECEIVED ON THE BUS FOUND BY ROUTE AND ;WHOSE NUMBER IS IN R3. USED ON NETS. ; REXMIT: ;(FOR SINGLE BUS OR SHARED MEM SYSTEMS, THIS IS OK AS IS, I.E., DUMMIED) CLC ;SAY NO ERRORS RTS PC ; ; ;REBRDC -- REBROADCAST MESSAGE ; ;REBRDC REBROADCASTS A MESSAGE JUST RECEIVED IF IT SHOULD BE. DECREMENTS ;REBROADCAST COUNTER AND DOES NOT SEND IF IT GOES 0 OR NEGATIVE. SENDS ;ON ALL BUSSES EXCEPT WHERE RECEIVED. RETURNS CARRY CLEAR IF THIS CPU ;NEEDS TO EXAMINE MESSAGE, SET IF NOT. (SEE MESSAGE FORMATS). ; REBRDC: ;(FOR SINGLE BUS OR SHARED MEM SYSTEMS, THIS IS OK AS IS, I.E., DUMMIED) CLC ;SAY NO ERRORS RTS PC ; .ENDC ;"GBLDAT" .END