.SBTTL XDISPA - task scheduler and dispatcher ; this section contains the dispatcher. it distributes cpu ; time among the tasks on a "non-preemptive" basis. ; that is, a task must deliberately relinquish control by ; calling "wait" before another task can get control. ; ; in addition, the once-per-clock-tick subroutines are called ; from here, as are the once-per-second subroutines. ; ; if a task takes too much time, the clock tick interrupt will ; issue a stopcode, so each task calls "wait" after only ; a little processing. .REPT 0 COPYRIGHT (c) 1982,1981,1980, 1979 DIGITAL EQUIPMENT CORPORATION, maynard, mass. THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED AND COPIED ONLY IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE AND WITH THE INCLUSION OF THE ABOVE COPYRIGHT NOTICE. THIS SOFTWARE OR ANY OTHER COPIES THEREOF MAY NOT BE PROVIDED OR OTHERWISE MADE AVAILABLE TO ANY OTHER PERSON. NO TITLE TO AND OWNERSHIP OF THE SOFTWARE IS HEREBY TRANSFERRED. THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE WITHOUT NOTICE AND SHOULD NOT BE CONSTRUED AS A COMMITMENT BY DIGITAL EQUIPMENT CORPORATION. DIGITAL ASSUMES NO RESPONSIBILITY FOR THE USE OR RELIABILITY OF ITS SOFTWARE ON EQUIPMENT WHICH IS NOT SUPPLIED BY DIGITAL. .ENDR ; REVISION HISTORY ; 4(001) BS ADD VERSION NUMBER ; ; 4(002) RLS MOVE LOOP CHECK FROM DSPIDL TO WAIT OTHERWISE IT REQUIRES ; ALL TASKS TO BE SIMULTANEOUSLY IDLE AT LEAST ONCE PER SECOND!! ; 4(003) RLS 25-Feb-81 remove task timer checking from DSPIDL and make ; function TSKTIK - called from CLKINT. ; Move calls to once/tick routines(DSPDQT,DSPDLT) from ; DSPIDL to CLKINT - made necessary by task timer change ; above. Of course, it should have been this way anyhow. ; make DSPUDC check if task waiting for timer whenever ; TCTIM is zero. ; 4(004) RLS 05-OCT-81 Move call to DSPDLS from dspidl to CLKINT. VDISPT=004 VEDIT=VEDIT+VDISPT .SBTTL SKED - the moby hyber function ISKD: ;schedule a task interrupt ;2(SP)/interrupting task ;trace caller,interrupting task,previous interrupting task,current task TRACE TRCINT!TRCDSP,<(SP),4(SP),SKDWRD,DSPTCB> CMP 2(SP),DSPTCB ;check if interrupting self BEQ 20$ SAVE R0 MOV 4(SP),R0 ;get the interrupting task tcb CMPB TCPS(R0),SKDP ;compare priorities BLOS 15$ ;this one higher - schedule it MOV R0,SKDWRD ;set reeskd flag MOV TCPS(R0),SKDP BISB #37,SKDP ;set up priority for comparing 15$: RESTOR R0 ;let the previous one ride 20$: MOV (SP)+,(SP) ;clean up stack and exit RETURN ;all interrupts return through this function .ENABL LSB SKDCHK: TST SKDWRD ;check if scheduler pass required BNE 10$ ;yes - go check interrupt level 5$: RTI ;no - just depart 10$: TSTB 2(SP) ;identify interrupted task by priority level BMI 5$ ;must be an interrupt process(BR4=200) TST DSPTCB ;not an interrupt process - check if task BNE 15$ MOV #SKDINI,(SP) ;no - just the scheduler MOV #BR7,2(SP) ;shut off the interrupts long enough to init RTI ;force scheduler to restart 15$: ;yes - fall thru as though task volunteered TRACE TRCLIN!TRCDSP, REESKD: MOV 2(SP),-(SP) ;move wake loc and ps down on stack MOV 2(SP),-(SP) CLR 4(SP) ;stash args as if task were gentlemenly CLR 6(SP) ;task is immediately runnable .DSABL LSB ; SUBROUTINE TO WAIT UNTIL THE CONDITION SPECIFIED IN THE ; TCB HAS BEEN SATISFIED. ;EMT traps to here ; stack: wake location ; ps of caller ; wakeup time limit ; wake conditions - low byte ;interrupts are disabled SKED: CMP R5,DSPTCB ;basic integrity check BEQ 10$ STOPCD BUG ;can't allow this 10$: MOV (SP)+,TCPC(R5) ;SAVE PROGRAM COUNTER MOV (SP)+,TCPS(R5) ;save the task ps MOV (SP)+,TCTIM(R5) ;set wakeup time limit BEQ 15$ BISB #EBTIME,(SP) ;set timer wakeup if non-zero time 15$: MOVB (SP)+,(R5) ;set wakeup events BICB #EBTIME,TCEV(R5) ;task timer's always reset TRACE TRCDSP, ;trace hyber call and wakeup condtions KGSAVE -(SP) ;save KG11 state SAVE ;save the task registers MOV SP,TCSP(R5) ;SAVE STACK POINTER ;task state preserved now SKDINI: ;enter here to init scheduler CLR DSPTCB ;NO LONGER RUNNING A TASK CLR SKDWRD ;note scheduler pass not needed CLR SKDP ;allow any tasks to interrupt MOV #PDL,SP ;SWITCH TO DISPATCHER STACK CLR -(SP) ;SET UP STACK AS THOUGH FROM AN INTERRUPT MOV #DISPATCH,-(SP) ;SO WE CAN CLEAR THE "T" BIT 20$: RTI ;DISMISS THE "INTERRUPT", I.E., ; BRANCH TO DISPATCHER ; THIS IS THE MAIN ENTRY POINT AND THE RECYCLE POINT. DISPATCH: MOV TCBP1,R5 ;GET HIGHEST PRIORITY TASKS CALL DISP MOV TCBP2,R5 ;GET MEDIUM PRIORITY TCBS CALL DISP MOV TCBP3,R5 ;GET LOWEST PRIORITY TCBS CALL DISP JSR PC,DSPIDL ;DO IDLE TIME CODE BR DISPATCH ; AND CHECK ALL TCBS AGAIN. ; SUBROUTINE TO TEST A TCB TO SEE IF THE TASK IS DISPATCHABLE. ; IF THE TASK IS DISPATCHABLE WE DISPATCH TO IT, OTHERWISE ; WE RETURN. ; ; R5/ptr to a tcb DISP: TST R5 ;check for empty list 5$: BNE 6$ ;more to check RETURN 6$: CLR R0 ;get the wakeup conditions BISB TCWK(R5),R0 BEQ 15$ ;none => runnable MOVB TCEV(R5),R1 ;get signalled events COM R1 BIC #177400,R1 BIC R1,R0 ;flush those which haven't happened BNE 10$ ;anything left have happened and cause wakeup MOV TCHAIN(R5),R5 ;check rest of tasks on this chain BR 5$ 10$: MTPS #BR7 ;shut off world long enough to check current events MOV R0,TCWKEV(R5) ;task is runnable BICB R0,TCEV(R5) ;these events are now ancient history BR 20$ ;special case - do not mung task's last wake events in case he hasn't had a ; chance to check them yet! 15$: MTPS #BR7 20$: MOV R5,DSPTCB ; REMEMBER THE TCB MOV TCPS(R5),SKDP BIS #37,SKDP ;set task priority up for schedluer interrupts TRACE TRCDSP,;trace dispatch of task and reasons MOV TCSP(R5),SP ;LOAD THE TASK'S STACK RESTOR ;restore task regs KGLOAD (SP)+ ;restore KG11 status MOV TCPS(R5),-(SP) ; AT TASK'S PRIORITY LEVEL MOV TCPC(R5),-(SP) ;CREATE A PSEUDO-INTERRUPT RTI ;GO RUN THE TASK. ; SUBROUTINE CALLED BY THE DISPATCHER WHEN ALL TASKS ARE WAITING. DSPIDL: CMP DSPCLK,JIFCLK ;IS THE DISPATCHER CLOCK UP TO DATE? BEQ 17$ ;NO - NUTHIN TODO ; HERE WHEN THE CLOCK HAS TICKED. 12$: MOV JIFCLK,R0 ;catch up to real time SUB DSPCLK,R0 MOV JIFCLK,DSPCLK ADD R0,DSPSEC CMP R0,BSYMAX ;track max busy time between idle loop BLE 13$ MOV R0,BSYMAX 13$: CMP DSPSEC,#JIFSEC ;REACHED ONE SECOND? BLT 17$ ;NO. SUB #JIFSEC,DSPSEC ;YES, CLEAR SECONDS COUNTER INC DSPUPT ;INCREMENT UP TIME BNE 14$ INC DSPUPT+2 ;ADD CARRY TO HIGH-ORDER WORD 14$: CMP DLGONE,#-6 ;CHECK FOR TEN DOWN TOO LONG BGT 16$ ;NOT 5 SECONDS, JUST UPDATE STATUS ; HERE ONCE A SECOND AFTER THE 10 HAS BEEN GONE FOR A WHILE. CALL INITDL ;TRY TO INITIALIZE THE DL10 ; HERE ONCE A SECOND ANYHOW 16$: 17$: RETURN ; SUBROUTINE TO UPDATE THE CLOCKS IN A LIST OF TASKS TSKTIK: ;update all task timers - called from CLKINT MOV TCBP1,R5 ;GET HIGH PRIORITY TASKS JSR PC,DSPUDC ;UPDATE THEIR CLOCKS MOV TCBP2,R5 ;GET MEDIUM PRIORITY TASKS JSR PC,DSPUDC ;UPDATE THEIR CLOCKS MOV TCBP3,R5 ;GET LOW PRIORITY TASKS CALL DSPUDC MOV #NLINES,R0 ;check line timers MOV #LINTBL,R1 10$: MOV (R1)+,R4 ;get an lcb BEQ 15$ ;not created TST LB.ALR(R4) BEQ 15$ ;alarm not enabled BIT #LS.ENB,(R4) BEQ 14$ ;line not enabled DEC LB.ALR(R4) ;count down alarm BGT 15$ ;not expired yet 14$: CLR LB.ALR(R4) ;set alarm expired MOV LB.TC1(R4),R5 ;get BSC task BEQ 15$ ;none??? SIGNAL R5,EBALR ;signal alarm event 15$: SOB R0,10$ RETURN DSPUDC: ;update all timers on R5/list of tasks TST R5 ;ANY TASKS? 11$: BNE 12$ ;YES. RTS PC ;NO, DONE WITH THIS LIST 12$: TST TCTIM(R5) ;HAS THIS TASK A TIMER? BEQ 14$ ;NO. DEC TCTIM(R5) ;YES, DECREMENT IT. BNE 13$ ;BRANCH IF TIME NOT YET UP 14$: BIT #EBTIME,(R5) ;IS TASK WAITING FOR TIMER? BEQ 13$ ;NO, IGNORE IT. SIGNAL R5,EBTIME ;signal task timer expired 13$: MOV TCHAIN(R5),R5 ;GET NEXT TCB BR 11$ ; AND TEST IT.