|
|
DataMuseum.dkPresents historical artifacts from the history of: Bogika Butler |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about Bogika Butler Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - download
Length: 156288 (0x26280)
Types: TextFile
Names: »SC.SA«
└─⟦1ed910a99⟧ Bits:30009789/_.ft.Ibm2.50006596.imd Mogens Pelles Zilog 80,000 / EOS projekt
└─⟦this⟧ »SC.SA«
└─⟦798d317aa⟧ Bits:30009789/_.ft.Ibm2.50006626.imd Mogens Pelles Zilog 80,000 / EOS projekt
└─⟦798d317aa⟧ Bits:30009789/_.ft.Ibm2.50006628.imd Mogens Pelles Zilog 80,000 / EOS projekt
└─⟦this⟧ »SC.SA«
***********************************************************************
* Copyright 1984 by *
* NCR Corporation *
* Dayton, Ohio U.S.A. *
* All Rights Reserved *
***********************************************************************
* EOS Software produced by: *
* NCR Systems Engineering - Co enhagen *
* Copenhagen *
* DENMARK *
***********************************************************************
SCHEDULE IDNT 1,0 SCHEDULER FACILITIES
OPT FRS FORWARD REFERENCE SHORT.
NOLIST
INCLUDE COMDEF.SA
LIST
* WRITTEN BY VILHELM ROSENQVIST
*
* THE FACILITIES OF THE SCHEDULER ARE:
* CENTRAL SCHEDULING ALGORITHMS (ROUND ROBIN ETC)
* CLOCK MANAGEMENT (TIME_OUT)
* SYNCHRONIZATION
* DRIVER AND INTERRUPT MANAGEMENT.
*
* THE FUNCTIONS APPEAR AS
* - SERVICE PROCEDURES FOR OTHER PARTS OF THE KERNEL (E.G. KNELWAIT)
* - KERNEL OPERATIONS (E.G. IO_BEGIN)
* - INITIAL OBJECT FUNCTIONS (E.G. NEW_COND)
* - PRIVILEGED OBJECT FUNCTIONS (E.G. DECL_GATE)
* - GENERAL OBJECT FUNCTIONS (E.G. NEW_SCHED)
*
* INITIALLY THREE SCHEDULER OBJECTS ARE PRESENT (GENERAL OBJECTS)
* 1: THE INITIAL SCHEDULER
* 2: A NORMAL SCHEDULER
* 3: AN INTERRUPT SCHEDULER
* THE STUB OBJECT GETS A REFERENCE (LOCAL-4 AND 5) TO THE
* NORMAL SCHEDULER AND TO THE INTERRUPT SCHEDULER
* THE INITIAL SCHEDULER CAN ONLY BE CALLED BY INTERRUPT SCHEDULERS.
* THE INITIAL SCHEDULER OWNS SUPERVISOR STACK EXTENSIONS (NOT IMPLEMENTED)
* PRIVILEGED OBJECT FUNCTIONS ARE CALLED BY THE SCHEDULERS USING
* A REFERENCE TO THE INITIAL "DECL_DIV" OBJECT.
* "DECL_DIV" IS THE ONLY KERNEL DEFINED OBJECT WITH OB_KIN=OB_SCHE.
*
* THE SCHEDULER OBJECTS MAY CREATE OTHER SCHEDULER OBJECTS AND
* PROCESSES, GATES, CONDITIONS AND CHANNELS (DRIVERS).
PAGE
* SCHEDULER DEFINITIONS
A_FORMAL EQU 0<<14 DIRECT ADDRESS OF FORMAL POINTER
A_LOCAL EQU 2<<14 DIRECT ADDRESS OF LOCAL POINTER
A_TEMP EQU 1<<14 DIRECT ADDRESS OF TEMP POINTER
ACT_SIZ EQU AR_SIZ SIZE OF ACTUAL ARG/SUBSEGM ARG/VOID VALUE ARG
XREF.S 9:RTEDUMMY DUMMY INTERRUPT PROCEDURE IN PREFACE
* USE PTMCHIP ADDRESS OF CLOCK DEVICE
* USE TIMER2 SINGLE SHOT TIMER
* USE TIMER3 FREE RUNNING COUNTER
* USE STATCON2 CLOCK STATUS
XREF.S 7:ALLOCOBJ ALLOCATE OBJECT ?
XREF 11:GETSTUBE GET ADDRESS OF STUB ENVELOPE
XREF 9:SIMPLEPT CREATE SIMPLE POINTER TO OBJECT
XREF 11:MAKESEGM CREATE A SEGMENT OBJECT
XREF 9:INIT_ENV INITIALIZE ENVELOPE OF INITIAL OBJECT
XREF 9:INITGEIN INITIALIZE INITIAL GENERAL OBJECT
XREF 9:MM_PUSHK,MM_POPO,MM_PUSHO
XREF 9:INITKNEL INITIALIZES A KERNEL PART AS AN OPEN OBJECT
XREF 9:TOP_RUNK TOP OF KERNEL RUNTIME SECTION (ROUNDED BELOW)
XREF.S 7:KV_INVEC EXCEPTION VECTOR (NORMALLY PLACED AT ADDRESS ZERO)
XREF.S 7:SUPV_STK CONTAINS THE ADDRESS OF THE LAST+1 BYTE OF SUPV. STACK
XREF.S 7:F_SUPVS CONTAINS THE ADDRESS OF THE FIRST BYTE OF SUPV. STACK
* PROCEDURES FROM KNELOP:
XREF 9:RET_FAST,C_PT,C_SUB,INT_EXC,PREP_RET,LOAD_MMU,C_ENTRES,CLR_SMP
XREF 9:TR_SPEED
XREF 11:I_KNELOP INITIALIZE KNELKOP
XDEF START_PROC,NEXT_PROC,DECLBOOT,DRIV_TAB,STAK_TAB,KNELSIGN,KNELWAIT
XDEF KV_CTX,RUNNING,TIMCHECK,I_SCHED,INT_CTX,SCHEDOBJ,GATE_OBJ,COND_OBJ
XDEF SAVE_STK,RSTO_STK,KV_SPSAVE,SAVE_SR,SAVE_PC,EOSBEGIN,FORCE_OPEN
XDEF TINTRUPT,RTCNT,INCRDECR,TERMDRIV,TERMGATE,TERMCOND,PROPSPED
XDEF NIOBEGIN,IIOBEGIN,RIOBEGIN,NIO_END,IIO_END,RIO_END,INT_SIGN
XDEF NABSADDR,IABSADDR,RABSADDR,KV_PROC,CONVADDR,GET_TIME
PAGE
SECTION.S 7 = KNEL_VAR. KERNEL VARIABLES OF THE SCHEDULER.
*
DRIV_TAB DS.L 256 ONE ENTRY FOR EACH CHANNEL (INTERRUPT SOURCE)
STAK_TAB DS.L 256 ONE ENTRY FOR EACH CHANNEL.
* BOTH ENTRIES ARE ZERO FOR AN UNUSED CHANNEL AND
* -1 FOR A PERMANTLY RESERVED CHANNEL.
* AFTER A DRIVER FOR A CHANNEL IS INSTALLED, DRIV_TAB(CHANNEL) CONTAINS
* THE ADDRESS OF THE FIELD "ENV.ENSTK" OF THE DRIVER ENVELOPE (<>0) AND
* STACK_TAB(CHANNEL) CONTAINS INT_STK <<16 + LEVEL (<>0).
* INT_STK TELLS THE MAX NUMBER OF BYTES USED DURING PROCESSING
* OF A CHANNEL INTERRUPT. LEVEL GIVES THE INTERRUPT LEVEL OF THE
* ASSOCIATED INTERRUPT SOURCE. THE INTERRUPT VECTOR OF A USED
* CHANNEL POINTS TO THE INTERRUPT PROCEDURE OF THE CHANNEL.
*
TIMER DS.W CHAIN PROCESSES WAITING FOR TIME_OUT
* PROC=RUNNING_CURRENT OR PROC.STATE=WAIT=2 OR =D_WAIT=4
RUNNING DS.W CHAIN PROCESSES EXECUTING NORMAL CONTEXTS.
* PROC.STATE=RUN=0
DRIVING DS.W CHAIN PROCESSES EXECUTING RESIDENT CONTEXTS
* PROC.STATE=RUN=0 OR =D_WAIT=4
KV_CTX DS.L 1 TOP CONTEXT OF CURRENT PROCESS.
* ZERO WHEN DUMMY PROCESS IS RUNNING
KV_PROC DS.L 1 CURRENT PROCESS, USED TO IDENTIFY THE PROCESS THAT CALLED
* THE KERNEL.
* UNDEF WHEN DUMMY PROCESS IS RUNNING
KV_SPSAVE DS.L 1 CURRENT SUPERVISOR STACK POINTER. CHANGES WHEN A RECURSION
* OF THE SCHEDULER IS CREATED OR REMOVED (SE TR_TR8 FF).
* POINTS TO SAVED A4,A5,A6,SR,PC IN THE STACK
SAVE_PC DS.L 1 USED BY SCHEDULER TO SAVE PC AND SR
SAVE_SR DS.W 1 OF CURRENT PROCESS
RTCNT DS.L 2 64 BIT REAL TIME COUNTER
* INITIALLY ZERO, COUNTS THE ELAPSED TIME IN MICRO SECONDS
*
* INITIAL OBJECTS
*
SCHEDSIZ EQU GE_SIZ+SP_SIZ+EN_SIZ+(PT_SIZ*6) SIZE OF GENERAL SCHEDULER OBJ.
*
INIT_SCH DS.B SCHEDSIZ INITIAL SCHEDULER OBJECT
*
NORM_SCH DS.B SCHEDSIZ NORMAL SCHEDULER OBJECT
*
INTR_SCH DS.B SCHEDSIZ INTERRUPT SCHEDULER OBJECT
*
DDIV_SCH DS.B OB_SIZ+SP_SIZ DECL_DIV OBJECT
*
SCH_CODE DS.B SE_SIZ+SP_SIZ SEGMENT OBJECT HOLDING CODE OF SCHED
INT_CTX DS.B ST_SIZ+2 ST_FIELDS+CT_TOPT ARE PRESENT IN THE INTERRUPT_CTX.
* THE CONTEXT IS "CURRENT CONTEXT" WHEN AN
* INTERRUPT PROCEDURE CALLS THE KERNEL.
DS.B ACT_SIZ*3 ROOM FOR THREE ACTUALS
SCHD_ARG EQU * USED WHEN A GATE CREATES A COND BY CALLING SCHEDULER OBJ.
PAGE
SECTION 11 = INITIALIZE INITIALIZE SCHEDULER
I_SCHED EQU * ENTRY TO INIT PART OF SCHEDULER
* THE SCHEDULER INITIALIZATION GETS CONTROL AFTER MM_PROC HAS INITIALIZED.
* THE FOLLOWING STEPS ARE CARRIED OUT:
* 1) INITIALIZE SIMPLE GLOBAL VARIABLES
* 2) INITIALIZE INITIAL OBJECTS
* 3) INITIALIZE STUB OBJECT
* 4) INITIALIZE TRAP#8 = INTERRUPT_END
* INITIALIZE SIMPLE VARIABLES
INIT_HEAD TIMER,A0 TIMERQUEUE IS EMPTY;
INIT_HEAD RUNNING,A0 RUNNING QUEUE:=EMPTY;
INIT_HEAD DRIVING,A0 DRIVING QUEUE:=EMPTY;
LEA RTCNT,A0 A0:=REAL TIME COUNTER; "64BITS"
CLR.L (A0)+ REAL TIME COUNTER:=0
CLR.L (A0) .
* INITIALIZE INTERRUPT CONTEXT AND SCHEDULER OBJECTS
* INT_CTX
LEA INT_CTX,A0 A0:=INT_CTX;
LEA 4-OB_SPA(A0),A1 A1:="EVALUATES" 4(A0)
MOVE.L A1,CT_OBJ(A0) INT_CTX.EXECUTES:="EVALUATES" 4(A0)
LEA 0-(SP_ENV+4)(A0),A1 A1:="EVALUATES" 0(A0)
MOVE.L A1,4(A0) 4(A0):="EVALUATES" 0(A0)
* AN ENVELOPE ADDRESS MAY NOW BE ASSIGNED TO 0(A0); THE POINTERS
* OF THE ENVELOPE WILL BE LOCAL POINTERS OF INT_CTX;
* "EVALUATES" ARE DEFINED ACCORDING TO THE ALGORITHM IN "C_PT"
* (LOCAL POINTER ARGUMENT).
* THE INT_CTX IS ALSO USED AS A DUMMY CONTEXT WHEN THE
* INITIAL CONTEXT OF THE BOOT PROCESS IS CREATED. THE VALUES INITIALIZED
* BELOW ARE USED BY "CRE_CTX"
MOVE.B #3,CT_MODE(A0) CTX.PROPAGATION_MODE:=SAME;
CLR.B CT_SPE(A0) CTX.SPEED_UP_STATUS:=NORMAL;
PRT_MEM INT_CTX,(A0),ST_SIZ+2 ********
* CODE SEGMENT FOR SCHEDULER OBJECTS
* THE CODE SEGMENT DESCRIBES SECTION 7+9 OF THE KERNEL CODE IN THIS RAM-VERSION
* OF THE KERNEL. IN A ROM-VERSION THIS SHOULD BE CHANGED TO SECTION 9+11.
LEA SCH_CODE,A0 A0:=CODE SEGMENT OBJECT;
MOVEQ.L #0,D2 D2:=FIRST BYTE OF SECTION 7 := 0;
TST.B D2 TEST_PAGE
IF <NE> THEN.S
ERROR 30 ERROR(30)
ENDI
MOVE.L #TOP_RUNK,D1 D1:=TOP_BYTE OF SECTION 9;
ADDI.W #255,D1 ROUND
CLR.B D1 UP;
SUB.L D2,D1 D1:=LENGTH OF CODE;
MOVE.L D2,A1 A1:=FIRST BYTE OF CODE;
MOVE.L #SE_SIZ+SP_SIZ,D0 D0:=SIZE OF SEGMENT OBJECT;
BSR.L INITKNEL INITKNEL(A0=OBJ,D0=SIZ);
BSR.L MAKESEGM MAKESEGM(A0=OBJ,A1=FIRST BYTE,D1=LENGTH);
LEA SCHEDENT,A2 A2:=ADDRESS OF SCHEDULER ENTRY
SUB.L D2,A2 A2:=ENTRY POINT OFFSET INTO CODE SEGM
* :=ENTRY ADDRESS - FIRST BYTE OF CODE;
PAGE
* DECL_DIV OBJECT (A2 MUST NOT BE DESTROYED)
*
LEA DDIV_SCH,A0 A0:=DECL_DIV OBJECT
MOVE.L #OB_SIZ+SP_SIZ,D0 D0:=SIZE OF DECL_DIV OBJECT
BSR.L INITKNEL INITKNEL(A0=OBJ,D0=SIZE);
MOVE.B #OB_SCHE,OB_KIN(A0) OBJECT.KIND:=DECL_DIV;
MOVE.B #1<<OB_REEN,OB_STA(A0) OBJECT.STATE:=REENTRANT OBJECT;
PRT_MEM DDIV_SCH,(A0),OB_SIZ+SP_SIZ ********
*
* GENERAL SCHEDULER OBJECTS; A2=ENTRY POINT
*
CLR.L -(A7) PUSH "END_OF_LIST"
PEA INIT_SCH PUSH ADDRESS OF INITIAL SCHEDULER
PEA NORM_SCH PUSH ADDRESS OF NORMAL SCHEDULER
LEA INTR_SCH,A0 A0:=ADDRESS OF INTERRUPT SCHEDULER
REPEAT REPEAT "A0=OBJECT"
MOVE.L #SCHEDSIZ,D0 D0:=SIZE OF OBJECT
BSR.L INITKNEL INITKNEL(A0=OBJ,D0=SIZE);
CLR.W OB_OFF(A0) INITIAL OWNER POINTER IS THE OWNER;
MOVE.L A2,A1 A1:=ENTRY POINT
BSR.L INITGEIN INIT_GENERAL(A0=OBJ,A1=ENTRY,A1:=UNDEF);
MOVE.L #EN_SIZ+(PT_SIZ*6),D0 D0:=SIZE OF PRIMARY ENVELOPE
BSR.L MM_PUSHK A3:=ENVELOPE,A6:=SPACE DESC;
BSR.L INIT_ENV INIT_ENV(A3=ENV,D0=SIZE,A6=SPACE DESC)
LEA EN_SIZ(A3),A0 A0:=LOCAL-1 OF ENVELOPE
LEA SCH_CODE,A4 A4:=CODE_SEGMENT;
BSR.L SIMPLEPT LOCAL-1 BECOMES POINTER TO CODE_SEGMENT
LEA PT_SIZ*2(A0),A0 A0:=LOCAL-3:=NEXT NEXT TO LOCAL-1
LEA ALLOCOBJ,A4 A4:=ALLOCOBJ;
BSR.L SIMPLEPT LOCAL-3 BECOMES POINTER TO ALLOC
LEA PT_SIZ(A0),A0 A0:=LOCAL-4:=NEXT TO LOCAL-3;
LEA DDIV_SCH,A4 A4:=DECL_DIV OBJECT
BSR.L SIMPLEPT LOCAL-4 BECOMES POINTER TO DECL_DIV;
PRT_MEM GEN_SCHED,(A3),SCHEDSIZ-GE_SIZ ********
MOVE.L (A7)+,A0 A0:=NEXT SCHEDULER OBJECT;
UNTIL.W A0 <EQ> #0 UNTIL NO MORE SCHEDULER OBJECTS
* AT EXIT A3=ENVELOPE OF INITIAL SCHEDULER
* FIND LOCAL-5 OF INTERRUPT SCHEDULER, CREATE A REF ENVELOPE TO
* INITIAL SCHEDULER IN LOCAL-5
LEA INTR_SCH,A0 A0:=OBJ;
MOVE.L OB_SPA(A0),A0 A0:=SPACE DESCR OF OBJ;
MOVE.L SP_ENV+4(A0),A0 A0:=TOP ENV OF OBJ;
LEA EN_SIZ-EN_STK+PT_SIZ*4(A0),A0 A0:=LOCAL-5 OF ENV;
MOVE.L A3,PT_REF(A0) LOCAL-5.REFERENCE:=ENVELOPE;
MOVE.B #PT_ENV,PT_KIN(A0) LOCAL-5.KIND:=REF_ENV;
LEA EN_REF(A3),A3 A3:=REF_ENV CHAIN
INS_ELEM A3,A0,A6,A3/A6 CHAIN LOCAL-5 TO ENVELOPE;
PAGE
* FINALIZE THE STUB OBJECT, LOCAL 4,5,7,8 AND 9
*
BSR.L GETSTUBE A3:=ENVELOPE OF STUB OBJECT
LEA EN_SIZ+PT_SIZ*3(A3),A0 A0:=LOCAL-4 OF STUB;
LEA NORM_SCH,A4 A4:=NORMAL SCHEDULER
BSR.L SIMPLEPT LET LOCAL-4 POINT TO NORMAL SCHEDULER
LEA PT_SIZ(A0),A0 A0:=LOCAL-5:=NEXT TO LOCAL-4
LEA INTR_SCH,A4 A4:=INTERRUPT SCHEDULER
BSR.L SIMPLEPT LET LOCAL-5 POINT TO INTERRUPT SCHEDULER
LEA PT_SIZ<<1(A0),A0 A0:=LOCAL-7:=NEXT NEXT TO LOCAL-5
* LOCAL-7 POINTS TO DEFVIRT OBJECT, REMAINS NIL
LEA PT_SIZ(A0),A0 A0:=LOCAL-8:=NEXT TO LOCAL-7
MOVE.L EN_OBJ(A3),A4 A4:=STUB OBJECT
BSR.L SIMPLEPT LET LOCAL-8 POINT TO THE STUB OBJECT
LEA PT_SIZ(A0),A0 A0:=LOCAL-9:=NEXT TO LOCAL-8;
MOVE.L A3,PT_REF(A0) LOCAL-9.REFERENCE:=STUB ENVELOPE
MOVE.B #PT_ENV,PT_KIN(A0) LOCAL-9.KIND:=REF_ENVELOPE;
LEA EN_REF(A3),A3 A3:=REF_ENV CHAIN
INS_ELEM A3,A0,A6,A3/A6 CHAIN LOCAL-9 TO ENVELOPE;
* LOCAL-9 HOLDS A REF_ENV TO THE STUBS OWN PRIMARY ENVELOPE.
* INITIALIZE TRAP#8
LEA KV_INVEC,A0 A0:= EXCEPTION VECTOR; "NORMALLY ZERO"
LEA DRIV_TAB,A2 A2:= DRIVER_TABLE;
LEA STAK_TAB,A3 A3:= STACK_TABLE;
MOVE.W #(32+8)<<2,D0 D0:= INDEX TO TRAP#8
MOVE.L #TR_TR8,(A0,D0.W) EXCEPT_ADDR(TRAP#8):= TR_TR8;"=INT_END"
MOVEQ.L #-1,D1 D1:= CHANNEL RESERVED:= -1;
MOVE.L D1,(A2,D0.W) DRIVER_TABLE(TRAP#8):= CHANNEL RESERVED;
MOVE.L D1,(A3,D0.W) STACK_TABLE(TRAP#8):= CHANNEL RESERVED;
PRT_MEM END_OF_SC_ETC.,TIMER,INIT_SCH-TIMER ********
BRA.L I_KNELOP GOTO INIT KNELOP;
* END OF INITIALIZE SECTION IN SCHEDULER;
PAGE
SECTION 9 = RUN_TIME
* RUNTIME SECTION OF SCHEDULER
TINTRUPT EQU * INTERRUPT PROCEDURE FOR THE PTMCHIP
* THE INTERRUPT PROCEDURE UPDATES THE REAL TIME COUNTER (RTCNT).
* IF A REQUESTED TIME OUT INTERRUPT OCCURED, THE TIME_OUT PROCEDURE
* OF THE SCHEDULER WILL BE CALLED AND TRAP #8 MAY BE CALLED TOO.
*
MOVEM.L D0-D7/A0-A6,-(A7) SAVE REGISTERS;
MOVE.W SR,D5 SAVE SR IN D5;
CLR.B D5 SAVED CCR:=0 => <NE>;
MOVE #$2700,SR PREVENT INTERRUPTS;
BSR.L RT_UPDAT D2/D3:=RTCNT; A4=TIMER CHIP
* D4:=TIMER STATUS
BTST.L #1,D4
IF <NE> THEN.S IF TIMER2-INTRPT IN TIME_STATUS THEN
MOVEP.W TIMER_2(A4),D4 CLEAR TIMER2-INTERPT;
* ENDI ENDI; THIS LINE IS A TEST LINE(SE TWO DOWN)
BSR.S TIME_OUT TIME_OUT(D2/D3=NOW,D5.W.B:=CCR);
ENDI ENDI; THIS LINE IS THE REAL LINE(SE TWO UP)
MOVE.W D5,SR RESTORE SR WITH UPDATED CCR FROM D5;
MOVEM.L (A7)+,D0-D7/A0-A6 RESTORE REGISTERS;
IF <EQ> THEN.S IF A WAITING DRIVER TIMED OUT THEN
TRAP #8 GOTO INTERRUPT_END;"
ENDI ENDI;
RTE RETURN;
TWAIT EQU * WAIT FOR TIMEOUT
* CALL: RETURN
* D0/D1 #USEC UNDEF
* A1 PROCESS SAME
* SPOILED D2/D3/D4/D5/A4/A5/A6
* THE PROCESS IS QUEUED IN THE TIMER QUEUE, AND WILL BE TIMED OUT AT:(NOW+USEC)
*
BSR.L RT_UPDAT D2/D3:=UPDATE REAL TIME COUNTER; A4/D4:=?
ADD.L D1,D3 D2/D3:=TIME_OUT_POINT:=
ADDX.L D0,D2 #USEC+REAL TIME COUNTER;
MOVEM.L D2/D3,PR_TIMO(A1) PROC.TIME_OUT:=TIME_OUT_POINT;
LEA TIMER,A4 A4:=TIMER QUEUE
MOVE.L (A4),A5 A5:=AFTER:=TIMER.FIRST;
WHILE.L A5 <NE> A4 DO.S WHILE AFTER <> TIMER DO "SCAN TIM_Q"
MOVEM.L PR_TIMO-PR_MAIN(A5),D4/D5 D4/D5:=AFTER.TIME_OUT;
SUB.L D3,D5 D4/D5:=AFTER.TIME_OUT-TIME_OUT_POINT;
SUBX.L D2,D4 .
IF <GE> THEN.S IF AFTER.TIME_OUT >= TIME_OUT_POINT THEN
BRA.S TWAITEXI GOTO POSITION_FOUND;
ENDI ENDI;
MOVE.L (A5),A5 A5=AFTER:=AFTER.NEXT
ENDW ENDW;
TWAITEXI EQU * POSITION_FOUND:
* A1 SHOULD BE CHAINED PRIOR TO A5 (=AFTER).
LEA PR_MAIN(A1),A4 A4:=SCHEDULER CHAIN ELEMENT;
INS_ELEM A5,A4,A6,A5/A6 INSERT A4 PRIOR TO A5; A6:=PROC.PREV;
IF.L A6 <NE> #TIMER THEN.S IF PROC IS NOT INSERTED FIRST_IN_QUEUE THEN
RTS RETURN;
ENDI ENDI;
BRA.L TO_UPDAT GOTO UPDATE TIME_OUT_COUNTER(D0/D1)
PAGE
TIME_OUT EQU * TIME_OUT CALL FROM DRIVER
* CALL: RETURN
* D2/D3 RTCNT=NOW UNDEF
* D5 SAVED SR WITH CCR=0 CCR.Z_BIT SET IF A DRIVER TIMES OUT
* OTHER EXCEPT A7 UNDEF
*
* SCAN THE TIMER QUEUE AND PERFORM THE PROPER TIME OUT ACTION
* FOR PROCESSES THAT HAVE TIMED OUT.
*
LEA TIMER,A0 A0:=TIMER_QUEUE
MOVE.L (A0),A1 A1:=PROC:=TIMER_QUEUE.FIRST
WHILE.L A1 <NE> A0 DO.L WHILE PROC <> END_OF_TIMER_QUEUE DO
MOVEM.L PR_TIMO-PR_MAIN(A1),D0/D1 D0/D1:=TIME_OUT_POINT
SUB.L D3,D1 D0/D1:=REST # USEC:=
SUBX.L D2,D0 TIME_OUT_POINT - NOW;
IF <GT> THEN.S IF REST # USEC > 0 THEN
BRA.L TO_UPDAT RETURN THRU "UPDATE_TIMEOUT_COUNTER"
ENDI ENDI;
* TIME_OUT HAS ACTUALLY OCCURED
PRT_MEM TIME_OUT_PROC,-PR_MAIN(A1),PR_SIZ ********
* REMOVE PROC FROM TIMER_QUEUE; PROC IS ALWAYS THE FIRST IN THE TIMER_QUEUE
MOVE.L (A1),A4 A4:=NEXT PROC IN TIMER_QUEUE;
MOVE.L A0,4(A4) NEXT.PREV:=TIMER_QUEUE;
MOVE.L A4,(A0) TIMER_QUEUE.FIRST:=NEXT;
MOVE.L A1,(A1) PROC.MAIN
MOVE.L A1,4(A1) := EMPTY;
* ENSURE THAT SCHEDULER WILL BE CALLED LATER:
BSR.L EN_STOPR ENSURE_STOP_RUNNING_PROCESS(D7/A4:=?);
PAGE
TST.B PR_STA-PR_MAIN(A1) TEST PROC STATE
IF <NE> THEN.S IF PROC STATE <> RUN THEN
* A1=PROC.MAIN. A COND.WAIT HAS TIMED OUT.
MOVE.W #ECRTIME,PR_SYN-PR_MAIN(A1) PROC.SYNC_RESULT:=REJECTED,TIMEOU
MOVE.L PR_CON-PR_MAIN(A1),A3 A3:=THE CONDITION THAT WAS "WAITED";
MOVE.L CO_GA(A3),A3 A3:=THE MANAGING GATE; "CANNOT BE ZERO"
MOVE.B GA_LEV(A3),D7 D7:=GATE.LEVEL
TAS.B GA_STA(A3) TEST FOR OPEN, AND LOCK THE GATE;
IF <EQ> THEN.S IF GATE WAS OPEN THEN
TST.B D7 TEST LEVEL
IF <EQ> THEN.S IF NORMAL GATE WAS OPEN THEN
LEA RUNNING,A3 A3:=RUNNING QUEUE;
LEA PR_AUX-PR_MAIN(A1),A4 A4:= PROC.AUX;
REM_ELEM (A4),A5,A6,A5/A6 REMOVE PROC.AUX FROM CONDITION;
INS_ELEM A3,A4,A6,A3/A6 INSERT PROC.AUX IN RUNNING;
CLR.B PR_STA-PR_AUX(A4) PROC.STATE:=RUN:=0;
ELSE.S ELSE "DEVICE GATE WAS OPEN"
BRA.S ASLOCKED GOTO ASLOCKED; "SAME PROCEDURE"
ENDI ENDI;
ELSE.S ELSE "GATE WAS LOCKED"
TST.B D7 TEST LEVEL
IF <EQ> THEN.S IF NORMAL GATE WAS LOCKED THEN
LEA GA_SPLOK(A3),A3 A3:=SPEED RELOCKING QUEUE;
INS_ELEM A3,A1,A6,A3/A6 INSERT PROC.MAIN IN RELOCKING;
ELSE.S ELSE "DEVICE GATE WAS LOCKED/OPEN"
ASLOCKED EQU * ASLOCKED:
LSL.B #4,D7 D7:=PRIO:=LEVEL<<4+0;
BSR.L QDRIV QUEUE PROC ACCORDING TO PRIO (A3/A6:=?);
* A DRIVER HAS TIMED OUT, PROC.STATE OF DRIVING PROC IS UNCHANGED (=D_WAIT=4).
BSET.L #2,D5 Z-BIT:= 1; <EQ> BECOMES TRUE;
ENDI ENDI; "DEVICE GATE"
ENDI ENDI; "GATE WAS LOCKED"
ENDI ENDI; "A COND.WAIT TIMED OUT"
MOVE.L (A0),A1 A1:=FIRST PROC IN TIMER QUEUE
ENDW ENDW;
* EXIT HERE SIGNALS THAT TIMER QUEUE IS EMPTY;
* NO NEW TIME_OUT INTERRUPT IS REQUESTED;
RTS RETURN;
PAGE
TO_UPDAT EQU * UPDATE TIME OUT COUNTER
* CALL RETURN:
* D0/D1 #USEC UNDEF
* A4 ANY UNDEF
*
* THE NEXT TIME_OUT INTERRUPT IS REQUESTED WITHIN #USEC (APROX).
* IF #USEC >=2**16, THE NEXT INTERRUPT IS REQUESTED
* WITHIN 2**16 USEC.
TST.L D0
IF <NE> THEN.S IF #USEC > 2**32 THEN
MOVE.W #$FFFF,D1 D1:=TOC:=2**16 -1
ELSE.S ELSE
SWAP.W D1
TST.W D1
IF <EQ> THEN.S IF #USEC < 2**16 THEN
SWAP.W D1 D1:=TOC:=#USEC;
ELSE.S ELSE
MOVE.W #$FFFF,D1 D1:=TOC:=2**16 -1
ENDI ENDI;
ENDI ENDI;
* D1.W = NEXT TIME_OUT PERIOD; SET UP TIMER2.
LEA PTMCHIP,A4
* PRT_REG TO_UPDAT_D1 TEST PRT CANNOT BE ACTIVE WHEN THE REAL TIMER IS ON
MOVEP.W D1,TIMER_2(A4)
RTS
RT_UPDAT EQU * UPDATE REAL TIME COUNTER (RTCNT)
* CALL: RETURN
* D2/D3 ANY UPDATED VALUE OF RTCNT
* D4.B ANY TIMER STATUS;
* A4 ANY TIMER CHIP ADDRESS
*
*
MOVEM.L RTCNT,D2/D3 D2/D3:=OLD RTCNT;
LEA PTMCHIP,A4 A4:=TIMER CHIP ADDRESS
MOVEP.W TIMER_3(A4),D3 RTCNT(0..15):=TIMER3;
MOVE.B STATCON2(A4),D4 D4:=TIMER STATUS;
BTST.L #2,D4 TEST CARRY(=INTERRUPT) OF TIMER3
IF <NE> THEN.S IF CARRY THEN "CARRY=1"
ADD.L #$10000,D3 RTCNT(16..31):=...+CARRY;
IF <CS> THEN.S IF CARRY THEN
ADDQ.L #1,D2 RTCNT(32..63):=...+CARRY;
ENDI ENDI;
MOVEP.W TIMER_3(A4),D3 RTCNT(0..15):=TIMER3; CLEAR INTERRUPT;
ENDI ENDI;
MOVEM.L D2/D3,RTCNT SAVE NEW RTCNT;
RTS RETURN;
GET_TIME EQU * KERNEL OPERATION #34; MAY ALSO BE CALLED FROM RESIDENT CTX.
* CALL: RETURN:
* A0 - CALLING PROCESS
* A2 CUR_CTX SAME
* D0/D1 - CPU TIME USED BY CALLING PROCESS
* D2/D3 - RTCNT
* D4/A4 - UNDEF
* D7 - OK-RESULT
* THE ADDRESSES USED BELOW ARE ALSO VALID WHEN CALLED FROM RESIDENT CTX
*
MOVE.L CT_HOLD(A2),A0 A0:= OBJECT HOLDING CTX;
MOVE.L EX_PR(A0),A0 A0:= PROCESS OF HOLDING OBJECT;
MOVEM.L PR_CPU(A0),D0/D1 D0/D1:= CPU_TIME OF PROCESS;
*IGET_TIME EQU * GET_TIME CALLED FROM INTERRUPT PROCEDURE COULD ENTER HERE
BSR.S RT_UPDAT D2/D3:= RTCNT;
MOVEQ.L #0,D7 RESULT:=OK;
BRA RET_FAST RETURN TO CALLER;
PAGE
*MEGADIV EQU * CONVERT D2/D3 FROM USECS TO SECS/USECS. D4-D7 SPOILED.
* A DIVISION BY 1000000 IS PERFORMED THROUGH TO DIVISIONS BY 1000.
*
* MOVE.W #1000,D7 D7:= 1000; D2/D3 = MICROSECS
* BSR.S KILODIV D4/D5:=MILLISECS:= MICROSECS DIV 1000;
* MOVE.W D2,D6 D6:=D0:=MICRO:= MICROSECS MOD 1000;
* MOVE.L D5,D3 D2/D3:=MILLISECS;
* MOVE.L D4,D2 (D4)/D5:= SECONDS:=MILLISECS DIV 1000;
* BSR.S KILODIV D0:= MILLI:=MILLISECS MOD 1000;
* MOVE.W D6,D3 D1:= USECS:=MILLI
* MULU D7,D3 * 1000
* ADD.L D2,D3 + MICRO;
* MOVE.L D5,D2 D2:= SECONDS;
* RTS
*KILODIV EQU * D4/D5:= D2/D3 DIV 1000; D2:= D2/D3 MOD 1000 D3:= UNDEF;
* DIFFICULT TO IMPLEMENT WITH 16 BITS ARITHMETIC.
PAGE
CONVADDR EQU * CONVERT ADDRESS FROM USER SPACE TO SUPERVISOR SPACE
* CALL: RETURN:
* D3 USER ADDR SUPV ADDR
* D5 - MMU_OFSET
* CCR ANY <NE>:OK, <EQ>:NOT_OK
* USED BY TRAP #8
MOVEM.L D3/D4/A0/A1,-(A7)
BTST.L #0,D3
IF <NE> THEN.S IF ODD ADDRESS THEN
MOVEQ.L #0,D5 CCR:=<EQ> = NOT OK;
BRA.S RET_CONV GOTO RETURN;
ENDI ENDI;
MOVE.L KV_CTX,A0 A0:= CURRENT CONTEXT
MOVEQ.L #0,D4 D4:= TABLE_INDEX:=0;
ROR.L #8,D3 D3.LOW:= ADDRESS.BITS(23..8)
REPEAT
MOVE.W MMU_TAB(PC,D4.W),D5 D5:= OFFSET TO NEXT MMU_DESC IN CTX
BEQ.S RET_CONV IF NO NEXT THEN RETURN WITH CCR=<EQ>
LEA MM_REG(A0,D5.W),A1 A1:= ADDRESS OF NEXT MMU LIMIT IN CTX
CMP.W (A1)+,D3 IF ADDR >= MMU.FIRST "UNSIGNED"
IF <CC> THEN.S AND
CMP.W (A1)+,D3 ADDR <= MMU.LAST "UNSIGNED"
IF <LS> THEN.S AND
BTST.B #0,3(A1) MMU ENABLED
IF <NE> THEN.S THEN
ADD.W (A1),D3 D3:= SUPV ADDR := USER ADDRESS + DIFF
ROL.L #8,D3 LOW ORDER BITS ARE UNCHANGED
MOVE.L D3,(A7) SAVED_D3:= SUPV ADDR; CCR:= <NE>;
RET_CONV EQU *
PRT_REG CONVADDR ********
MOVEM.L (A7)+,D3/D4/A0/A1
RTS
ENDI ENDI; MMU NOT ENABLED
ENDI ENDI; ADDR <= LAST
ENDI ENDI; ADDR >= FIRST
ADDQ.W #2,D4 D0:= NEXT INDEX
UNTIL <EQ> UNTIL FOREVER;
MMU_TAB DC.W CT_MM1,CT_MM0,CT_MM2,CT_MM3,0 OFFSETS TO MMU_DESC IN CTX
PAGE
* THE SCHEDULER IMPLEMENTS PROCESS SWITCHING.
* THE PROCESSES OF THE SYSTEM ARE:
*
* ØØPROCESS !
* ØØ PRIO ! ! !
* KIND ØØ ! ZERO PRIORITY ! DRIVER PRIORITY (>0) !
* OF PROCESS ØØ! ! !
* -------------!-------------------!----------------------!
* ! ! !
* REAL PROCS ! RUNNING PROCESSES ! DRIVING PROCESSES !
* ! ! !
* -------------!-------------------!----------------------!
* ! ! !
* FANTOM PROCS ! DUMMY PROCESS ! INTERRUPT PROCEDURES !
* ! ! !
* -------------!-------------------!----------------------!
*
*
* ALTHOUGH ALL RUNNING PROCESSES HAVE THE SAME LOW PRIORITY, THEY MAY HAVE
* DIFFERENT REQUIREMENTS TO RESPONSE TIME AND CPU-LOAD. AT PRESENT NOTHING
* IS DONE TO MEET SUCH INDIVIDUAL REQUIREMENTS, BUT NO PROCESS ARE ALLOWED
* TO USE THE CPU CONTINUEOUSLY FOR MORE THAN A FIXED PERIOD OF TIME.
*
* A DRIVING PROCESS HAS AN ABSOLUT PRIORITY IN THE RANGE 1 TO 6.
* AN INTERRUPT PROCEDURE HAS AN ABSOLUT PRIORITY IN THE RANGE 1 TO 7.
* HAVING AN ABSOLUT PRIORITY P MEANS THAT NO PROCESS WITH A PRIORITY N<P
* IS SCHEDULED AS LONG AS THE P-PROCESS IS READY TO RUN.
*
* A HIGH PRIORITY CORRESPONDES TO A SHORT RESPONSE TIME REQUIREMENT AND
* A LOW CPU-LOAD.
* NO SWITCHING TAKES PLACE BETWEEN PROCESSES AT THE SAME DRIVER LEVEL
* (SWITCHING TO A HIGER LEVEL MAY OCCUR), BECAUSE THE "QUEUE" OF INTERRUPT
* PROCEDURES ARE INVISIBLE TO THE SCHEDULER, AND BECAUSE NO IMPROVEMENTS IN
* PERFORMANCE (RESPONSE TIME) SEEMS TO FOLLOW:
* THE RESPONSE TIME EXPECTED AT A GIVEN LEVEL MAY BE CORRUPTED IF PROCESSES
* AT THE SAME OR HIGHER LEVELS ENFORCES A TOO BIG CPU-LOAD; BUT IMPLEMENTING
* A SWITCHING POLICY BETWEEN PROCESSES AT THE SAME LEVEL CANNOT REMOVE A BIG
* CPU-LOAD FROM PROCESSES AT HIGHER LEVELS.
* CONSEQUENTLY: DRIVER PRIORIOTY MUST BE USED CAREFULL.
*
* THE SCHEDULER IS A RECURSIVE ALGORITHM. A NEW LEVEL OF RECURSION IS
* INTRODUCED WHEN AN INTERRUPT PROCEDURE TERMINATES THROUGH 'INTERRUPT_END'
* (TRAP #8) TO ACTIVATE SIGNALED DRIVING PROCESSES. THE LEVEL OF RECURSION
* (CALLED PREVPRIO) IS IDENTIFIED BY THE PRIORITY LEVEL OF THE PROCESS
* (REAL OR FANTOM) THAT WAS INTERRUPTED.
* THE ALGORITHM SCHEDULES ALL PROCESSES HAVING A PRIORITY ABOVE PREVPRIO
* BEFORE IT RETURNS TO THE INTERRUPTED PROCESS WHICH WAS SCHEDULED BY A
* "LOWER_LEVEL INCARNATION" OF THE SCHEDULER ALGORITHM. IN THE "LOWEST"
* INCARNATION PREVPRIO EQUALS -1. THIS INCARNATION WILL NEVER RETURN, BUT
* SCHEDULE THE DUMMY PROCESS WHEN NO OTHER PROCESSES ARE FOUND.
*
* REAL PROCESSES ARE SELECTED EXPLICITLY FROM THE DRIVING QUEUE OR FROM
* THE RUNNING QUEUE. INTERRUPT PROCEDURES ARE SELECTED IMPLICITLY WHEN THE
* INTERRUPT MASK OF THE PROCESSOR IS DECREASED. THE DUMMY PROCESS IS SELECTED
* WHEN NO OTHER PROCESSES APPEAR.
*
PAGE
EN_STOPR EQU * ENSURE THAT RUNNING CURRENT PROCESS WILL BE STOPPPED.
* CALL: RETURN:
* D7/A4 ANY UNDEF
* SR 27XX 27XX
* CALLED FROM TIME_OUT, WHEN A PROCESS IN THE TIMER QUEUE ACTUALLY TIMES
* OUT.
*
MOVE.L SUPV_STK,A4 A4:= BOTTOM OF STACK;
SUBQ.L #8,A4 A4:= BOTTOM SR; "-1,PC,SR"
PRT_MEM EN_STOPR,(A4),8+4+4 ********
MOVEQ.L #$27,D7
AND.B (A4),D7 TEST SUPERVISOR BYTE OF BOTTOM SR
IF <EQ> THEN.S IF LEVEL=0 AND MODE=USER THEN
* A RUNNING PROCESS SHOULD BE STOPPED
MOVE.W (A4)+,SAVE_SR SAVE SR OF RUNNING CURRENT PROCESS
MOVE.L (A4),SAVE_PC SAVE PC OF RUNNING CURRENT PROCESS
MOVE.L #DO_STOPR,(A4) PC:= STOP RUNNING PROCESS
MOVE.W #$2000,-(A4) SR:= SUPERVISOR MODE/RUNNING PROCESS;
ENDI ENDI;
RTS RETURN, BUT CONTINUE LATER IN 'DO_STOPR' BELOW.
* THE PROCESS MAY STOP ITSELF(CALL SUSPEND),IF IT EXECUTES
* IN THE KERNEL. IN THIS CASE 'DO_STOPR' IS NOT ENTERED.
DO_STOPR EQU * STOP RUNNING CURRENT PROCESS FOR A WHILE
*
* ALL REGISTERS WILL BE UNCHANGED WHEN THE PROCESS IS RESUMED.
*
* THE STACK CONTAINS PREVPRIO OF THE BOTTOM SCHEDULER (=-1)
* AND THE SPECIAL VALUES FOR SR AND PC ASSIGNED BY EN_STOPR,
* BUT A7 POINTS TO PREVPRIO (RTE HAS BEEN EXECUTED).
*
MOVE.W #$2700,SR PREVENT INTERRUPTS IN THE SCHEDULER
SUBQ.L #6,A7 ALLOCATE SR,PC WHICH ARE STILL ON STACK
MOVEM.L A4-A6,-(A7) SAVE A4-A6 ON STACK
MOVE.L KV_PROC,A4 A4:= CURRENT PROCESS
REM_ELEM PR_MAIN(A4),A5,A6,A5/A6 REMOVE PROC FROM TIMER QUEUE
INIT_HEAD PR_MAIN(A4),A5 NOTE: PROC MAY HAVE BEEN REMOVE ALREADY
MOVEM.L D0-D7/A0-A3,PR_D0.A3(A4) SAVE REGS IN PROC DESCRIPTION
LEA PR_AUX(A4),A4 A4:= PROC.AUX_QUEUE;
REM_ELEM (A4),A0,A1,A0/A1 REMOVE PROC FROM RUNNING; A1:=RUNNING QUE
INS_ELEM A1,A4,A5,A1/A5 INSERT PROC AS LAST PROC IN RUNNING QUEUE
MOVE.L KV_CTX,A2 A2:= CURRENT CONTEXT
BSR.L SUSPEND SUSPEND EGO (A0/A1/A2/A3:=!,OTHER:=?)
START_PROC EQU * INITIAL RESUME POINT FOR INITIAL CTX IN CREATED PROCESSES.
* STACK AND USP IS UNCHANGED. CHECK FOR ABORT AND RESTORE MMU:
BSR.L PREP_RET PREPARE RETURN(A3=CTX,A4:=?,CCR:=SP_EXC);
MOVEM.L PR_D0.A3(A1),D0-D7/A0-A3 RESTORE REGS FROM PROC DESCR.CCR UNCHANG.
MOVEM.L (A7)+,A4-A6 RESTORE A4-A6 FROM STACK. CCR UNCHANGED.
BLT.L TR_SPEED IF SP_EXC THEN GOTO SPEEDUP EXCEPTION;
RTE RETURN TO USER MODE
PAGE
TR_TR8 EQU * INTERRUPT_END IS CALLED (TRAP #8)
* INTERUPT END IS CALLED FROM AN INTERRUPT PROCEDURE IN ORDER TO ACTIVATE
* SIGNALED PROCESSES. A NEW INSTANCE OF THE SCHEDULER IS CREATED. THE STATE
* OF THE INTERRUPTED LEVEL IS SAVED ON THE STACK.
*
PRT_REG TR_TR8 ********
MOVE.W #$2700,SR PREVENT INTERRUPTS
MOVE.W D3,-(A7) SAVE D3.W ON STACK
MOVE.B #$27,D3 D3:= MODE AND LEVEL OF CALLER
AND.B 2(A7),D3 TEST MODE AND LEVEL OF CALLER
IF.B D3 <LE> #$20 THEN.S IF CALLED FROM REAL PROCESS THEN
AND.B #$7,D3 D3:= LEVEL OF CALLER;
IF <EQ> THEN.S IF CALLED FROM NORMAL CONTEXT THEN
MOVE.W (A7)+,D3 RESTORE D3.W AND A7
SUBQ.L #8,A7 PUSH DUMMY INF
MOVE.L #32+8,-(A7) CAUSE:=TRAP #8;
BRA.L INT_EXC GOTO INTERNAL EXCEPTION;
ENDI ENDI;
* CALLER IS A RESIDENT CONTEXT, OPRATION IS: JSR (A0) INTO SUPV MODE
MOVE.W 2(A7),D3 D3.W:= NEW_SR:= OLD_SR
BSET.L #5+8,D3 + SUPERVISOR BIT;
SWAP.W D3 SAVE HIGHBITS OF D3 AND
MOVE.L D3,-(A7) NEW_SR ON STACK;
MOVE.L A0,D3 D3:=PROC_ADDR;
MOVE.L D5,-(A7) SAVE D5;
BSR.L CONVADDR CONVADDR(D3=USER_ADDR,D3:=ADDR,D5:=MMU);
IF <NE> THEN.S IF OK THEN D3=SUPV_ADDRESS
MOVE.L (A7)+,D5 RESTORE D5;
MOVE.L 2(A7),-(A7) PUSH SAVED D3;
MOVE.L D3,6(A7) SAVE PROC_ADDR ON STACK
MOVE.L (A7)+,D3 RESTORE D3;
RTE CALL PROCEDURE IN SUPERVISOR MODE;
* NOTE RTE IS EXECUTED BY THE CALLED PROCEDURE TO RETURN TO MAIN PROGRAM.
ENDI ENDI;
* ILLEGAL A0: D3=USER ADDR,RETURN TO ILLEGAL ADDR => EXCEPTION IN CALLING CTX
MOVE.L (A7)+,D5 RESTORE D5;
MOVE.L D3,8(A7) SAVE ILLEGAL ADDRESS IN RETURN POINT
MOVE.L 2(A7),D3 RESTORE D3;
ADDQ.L #6,A7 RESTORE A7
RTE RETURN AND PROVOKE EXCEPTION
ENDI ENDI; TRAP #8 FROM REAL PROCESS;
* THE CALL IS MADE BY AN INTERRUPT PROCEDURE (LEVEL AND MODE <> 0).
MOVE.W (A7)+,D3 RESTORE D3;
ADDQ.L #6,A7 POP RETURN POINT FROM TRAP #8
MOVEM.L D0-D7/A0-A6,-(A7) SAVE REGS ON STACK
MOVE.W 60(A7),D0 D0:= SR OF INTERRUPTED LEVEL
ANDI.W #$0700,D0 D0.B:= PREVPRIO:= SR.INT_MASK
ORI.W #$00F0,D0 << 4 + F;
LSR.W #4,D0
MOVE.L USP,A0 A0:= USP OF INTERUPTED LEVEL
MOVE.L A0,-(A7) SAVE USP ON STACK
MOVE.L KV_CTX,-(A7) SAVE KV_CTX ON STACK
MOVE.L KV_PROC,-(A7) SAVE KV_PROC ON STACK
MOVE.L KV_SPSAVE,-(A7) SAVE KV_SPSAVE ON STACK
EOSBEGIN EQU * CALLED FROM 'ENTER' AFTER THE INITIALIZATION;
MOVE.B D0,-(A7) PUSH PREVPRIO ON STACK
LEA -18(A7),A7 KV_SPSAVE:=A7:= VALUE OF KV_SPSAVE
MOVE.L A7,KV_SPSAVE IN THE NEW SCHEDULER;
CLR.B 12(A7) STACK(SR).SUPV_BYTE:=NO_TIMOUT_PENDING:=0
PRT_MEM EOSBEGIN,(A7),60 ********
PAGE
BSR.L FIND_NXT FIND_NXT(D0.B=PREVPRIO,D0-D5/A4-A6=?,
* A1:=PROC,CC:=RESULT);
WHILE <LE> DO.S WHILE MORE PROCESSES DO
* STACK CONTAINS 18 BYTES. STACK(SR).SUPV_BYTE=0.
IF <EQ> THEN.S IF REAL PROCESS THEN
BSR.L RSTO_ALL RESTORE_ALL(A0-A3:=!,D0/A5/A6:=?,USP:=!);
* USP AND STACK RESTORED, A0=EXT, A1=PROC=KV_PROC, A2=A3=KV_CTX, SR=27XX
PRT_REG RESUME_A0-A1 ********
PRT_MEM SC_STATE,TIMER,RTCNT+8-TIMER ********
RTS RESUME SELECTED PROCESS
SUSPEND EQU * SUSPEND SELECTED PROCESS; A2=CTX,SR=27XX;
PRT_REG SUSPEND_A2 ********
PRT_MEM SC_STATE,TIMER,RTCNT+8-TIMER ********
BSR.L SAVE_STK SAVE_STACK(A2=CTX,D0/A5/A6:=?,!:=USP);
ELSE.S ELSE "DUMMY PROCESS AT LEVEL ZERO"
CLR.L KV_CTX NO CTX DESCRIBED IN MMU
LEA 18(A7),A7 RESTORE DUMMY STACK "CONTAINS ZERO BYTES"
STOP #$2000 WAIT FOR INTERRUPT
MOVE.W #$2700,SR PREVENT INTERRUPT
LEA -18(A7),A7 SAVE DUMMY STACK "CONTAINS ZERO BYTES"
ENDI ENDI;
NEXT_PROC EQU * CALLED BY KNELOP WHEN A PROC HAS RETURNED FROM ITS INITIAL CTX
MOVE.B 18(A7),D0 D0:=PREVPRIO;
CLR.B 12(A7) STACK(SR).SUPV_BYTE:=NO_TIMOUT_PENDING: 0
BSR.S FIND_NXT FIND_NXT(D0=PREVPRIO,D0-D5/A4-A6:=?,
* A1:=PROC,CC:=RESULT);
ENDW END WHILE MORE PROCESSES;
* NO MORE PROCS, RESTORE AND RETURN TO PREVIOUS LEVEL.
LEA 20(A7),A7 POP PREVPRIO AND 18 BYTES DUMMY STACK
MOVE.L (A7)+,KV_SPSAVE KV_SPSAVE:= PREVIOUS VALUE
MOVE.L (A7)+,KV_PROC KV_PROC:= PREVIOUS VALUE
MOVE.L (A7)+,A3 A3:= PREVIOUS CONTEXT
MOVE.L (A7)+,A0 A0:= PREVIOUS USP
MOVE.L A3,KV_CTX KV_CTX:= PREVIOUS CONTEXT
IF <NE> THEN.S IF PREVIOUS CONTEXT <> DUMMY_PROC THEN
BSR.L LOAD_MMU LOAD_MMU(A3=CTX,A4:=?);
MOVE.L A0,USP USP:= PREVIOUS USP
ENDI ENDI;
MOVEM.L (A7)+,D0-D7/A0-A6 RESTORE REGS FROM STACK
PRT_REG RTE_TR8 ********
RTE RETURN TO INTERRUPTED LEVEL
PAGE
FIND_NXT EQU * FIND THE NEXT PROCESS TO BE RESUMED
* CALL: RETURN:
* D0.B PREVPRIO UNDEF
* A1 ANY PROCESS TO BE RESUMED
* D0-D5 ANY UNDEF
* A4-A6 ANY UNDEF
* CC ANY <LT> RESUME DUMMY PROCESS
* <EQ> RESUME REAL PROCESS (IN A1)
* <GT> NO PROCESS TO RESUME
*
MOVE.L DRIVING,A6 A6:= MAIN QUEUE OF FIRST DRIVING
IF.L A6 <NE> (A6) THEN.S IF ANY DRIVING PROCESSES AND
IF.B D0 <LT> PR_PRI-PR_MAIN(A6) THEN.S PREVPRIO < PRIO OF FIRST DRIVING THEN
LEA -PR_MAIN(A6),A1 A1:= FIRST DRIVING PROCESS;
* THE DRIVING PROCESS MAY STILL BE WAITING FOR A CONDITION.
TST.B PR_STA(A1)
IF <NE> THEN.S IF PROC.STATE <> RUN THEN
REM_ELEM PR_AUX(A1),A4,A6,A4/A6 REMOVE PROC.AUX FROM CONDITION QUEUE
INIT_HEAD PR_AUX(A1),A4
CLR.B PR_STA(A1) PROC.STATE:= RUN; CC:=<EQ>;
ENDI ENDI;
RTS RETURN, RESULT = RESUME REAL PROC = <EQ>;
ENDI
ENDI ENDI REAL DRIVING COULD BE RESUMED;
TST.B D0
IF <LT>THEN.S IF PREVPRIO=LOWEST PRIO THEN
* RUNNING PROCESSES MAY BE SCHEDULED
MOVE.L RUNNING,A6 A6:= AUX QUEUE OF FIRST RUNNING
IF.L A6 <NE> (A6) THEN.S IF ANY RUNNING PROCS THEN
LEA -PR_AUX(A6),A1 A1:= FIRST RUNNING PROCESS;
MOVEQ #0,D0
MOVE.L #TIMESLIC,D1 D0/D1:= TIME_SLICE IN #USEC;
BSR.L TWAIT INSERT IN TIMER QUEUE(D0/D1,A1=PROC,
* D0-D5:=?,A4-A6:=?);
CMP D0,D0 RESULT:= RESUME REAL PROCESS:= <EQ>;
RTS
ENDI ENDI REAL RUNNING PROCESS WAS PRESENT
MOVEQ.L #-1,D0 RESULT:= RESUME DUMMY PROCESS:= <LT>;
RTS RETURN
ENDI ENDI PREVPRIO=LOWEST PRIO ;
MOVEQ.L #+1,D0 RESULT:= NO PROC TO RESUME:= <GT>;
RTS RTS
PAGE
EN_DIS EQU * ENABLE AND DISABLE INTERRUPTS
* CALL: RETURN:
* SR 27XX SAME
* THIS PROCEDURE IS CALLED WHEN A NORMAL RUNNING PROCESS EXECUTING A
* KERNEL OPERATION WILL ALLOW INTERRUPT TO BE GRANTED.
* THE INTERRUPT MASK IS LOWERED TO ZERO AND RAISED AGAIN TO SEVEN.
* EN_DIS MUST NEVER BE CALLED FROM KERNEL OPERATIONS EXECUTED BY
* INTERRUPT PROCEDURES OR DRIVING PROCESSES.
*
MOVE.W SR,-(A7) SAVE SR; (INCL. CONDITION CODES)
MOVE.W #$2000,SR ALLOW INTERRUPTS TO BE GRANTED
RTE PREVENT INTERRUPTS AND RETURN;
RSTO_ALL EQU * RESTORE KV_CTX, KV_PROC, A0/A2/A3, USP, SUPV.STACK OF PROC.
* CALL: RETURN:
* A0 ANY EXTENSION OBJECT
* A1 PROCESS TO BE RESUMED SAME
* A2 ANY CURRENT CONTEXT
* A3 ANY CURRENT CONTEXT
* USP ANY LOADED FROM CURRENT CONTEXT
* STACK: 18 BYTES TO BE POPPED, BEFORE THE STACK IS RESTORED
* RSTO_ALL IS CALLED BY THE SCHEDULER WHEN A NEW REAL PROCESS IS RESUMED.
MOVE.L A1,KV_PROC KV_PROC:= PROCESS TO BE RESUMED;
MOVE.L EX_EXT+4(A1),A0 A0:= Q_ELEM OF LAST EXTENSION OBJECT
LEA EX_CTX-EX_EXT(A0),A2 A2:= CONTEXT STACK HEAD OF EXTENSION OBJ;
MOVE.L 4(A2),A3 A3:= LAST CONTEXT OF LAST EXTENSION;
IF.L A2 <EQ> A3 THEN.S IF NO CONTEXTS IN LAST EXTENSION THEN
MOVE.L 4(A0),A2 A2:= EXTENSION PRIOR TO LAST EXTENSION
MOVE.L EX_CTX+4-EX_EXT(A2),A3 A3:= LAST CONTEXT OF PRIOR EXTENSION
ENDI ENDI;
LEA -EX_EXT(A0),A0 A0:= FIRST OF EXTENSION OBJECT;
LEA -ST_STK(A3),A3 A3:= A2:=
MOVE.L A3,A2 KV_CTX:=
MOVE.L A2,KV_CTX FIRST OF LAST CONTEXT
* CONTINUE IN RSTO_STACK BELOW
PAGE
RSTO_STK EQU * RESTORE SUPERVISOR STACK
* CALL: RETURN:
* A3 CTX SAME
* D0/A5/A6 ANY UNDEF
* USP ANY LOADED FROM CTX
* STACK: 18 BYTES TO BE POPPED LOADED FROM CTX
*
MOVE.L (A7)+,A6 A6:= RETURNPOINT
MOVE.L CT_USP(A3),A5 A5:= SAVED USP
MOVE.L A5,USP USP:= SAVED USP
LEA CT_WRK(A3),A5 A5:= TOP OF CTX.SAVED_STACK
MOVE.W CT_COUNT(A3),D0 D0:= - #ADDITIONAL WORDS SAVED
BTST.B #5,12(A7) TEST SR OF STACK TO BE POPPED
IF <NE> THEN.S IF SUPERVISOR BIT IS ON THEN
MOVE.L -(A5),SAVE_PC SAVE_PC:= CTX.SAVED_PC
MOVE.W -(A5),SAVE_SR SAVE_SR:= CTX.SAVED_SR
LEA 12(A7),A7 PC,SR STILL IN STACK AS SET BY EN_STOPR
ELSE.S ELSE
LEA 18(A7),A7 POP OLD STACK CONTENT;
MOVE.L -(A5),-(A7) RESTORE PC
MOVE.W -(A5),-(A7) RESTORE SR
ENDI ENDI;
BCLR.L #0,D0 IF D0 IS ODD THEN D0:= D0-1;
IF <NE> THEN.S IF D0 WAS ODD THEN
ADDQ.W #2,D0 D0:= D0+2;
MOVE.W -(A5),-(A7) MOVE ONE WORD FROM CTX TO STACK
ENDI ENDI;
JMP RSTO_0_W(PC,D0.W) MOVE REMAINING WORDS, D0= -#EXTRA_WORDS.
* WHEN 14/15 ADDITIONAL WORDS ARE SAVED, THEN THE NEXT INSTRUCTION IS ENTERED
MOVE.L -(A5),-(A7) 15/14 ADDITIONAL WORDS
MOVE.L -(A5),-(A7) 13/12
MOVE.L -(A5),-(A7) 11/10
MOVE.L -(A5),-(A7) 9/8
MOVE.L -(A5),-(A7) 7/6
MOVE.L -(A5),-(A7) 5/4
MOVE.L -(A5),-(A7) 3/2
RSTO_0_W EQU *
MOVE.L -(A5),-(A7) 1/0 A4/A5/A6 ARE ALWAYS RESTORE
MOVE.L -(A5),-(A7)
MOVE.L -(A5),-(A7) A7 POINTS TO TOP OF RESTORED STACK
PRT_MEM RSTO_STK,(A7),CT_SIZW*4 ********
JMP (A6) GOTO RETURN POINT
PAGE
SAVE_STK EQU * SAVE SUPERVISOR STACK AND USP IN CONTEXT
* CALL: RETURN:
* A2 CTX SAME
* D4/D5 ENTRY ADDR/FUNCTION SAME
* USP WILL BE SAVED IN CTX SAME
* D0/A5/A6 ANY UNDEF
* SAVES THE SUPERVISOR STACK AND USP IN THE CONTEXT AND INITIALIZES A STANDARD
* SUPERVISOR STACK IN RETURN. KV_SPSAVE POINTS TO THE STANDARD STACK (CONTAINS
* 18 BYTES). A7 POINTS TO THE TOP OF THE STACK TO BE SAVED.
* CALL STACK: WORDS,A4,A5,A6,SR,PC RETURN STACK: FUNCTION,??,??,SR,ENTRY ADDR
*
PRT_MEM SAVE_STK,(A7),CT_SIZW*4 ********
MOVE.L (A7)+,A6 A6:= RETURN POINT
MOVE.L USP,A5 A5:= USP
MOVE.L A5,CT_USP(A2) SAVE USP IN CTX
MOVE.L A7,D0 D0:= -#ADDITIONAL BYTES TO SAVE
SUB.L KV_SPSAVE,D0 := ADDR ACT. STACK - ADDR STD. STACK
IF.W D0 <LT> #-(CT_SIZW*4-18) THEN.S IF STACK IS TOO BIG TO BE SAVED THEN
ERROR 99 ERROR(99);
ENDI ENDI;
LEA CT_WRK-18(A2),A5 A5:= FIRST BYTE OF CTX
ADD.W D0,A5 TO BE USED FOR SAVE.
ASR.W #1,D0 D0:= - #ADDITIONAL WORDS TO SAVE
MOVE.W D0,CT_COUNT(A2) SAVE -#ADDITIONAL WORDS IN CONTEXT
BCLR.L #0,D0 IF D0 IS ODD THEN D0:= D0-1;
IF <NE> THEN.S IF ODD #WORDS THEN
ADDQ.W #2,D0 D0:= D0+2;
MOVE.W (A7)+,(A5)+ SAVE ONE WORD;
ENDI ENDI;
JMP SAVE_0_W(PC,D0.W) SAVE REMAINING WORDS, D0= -#EXTRA_WORDS.
* WHEN 15/14 WORDS ARE SAVED, ENTRY IS MADE TO THE FOLLOWING INSTRUCTION
MOVE.L (A7)+,(A5)+ 15/14 ADDITIONAL WORDS
MOVE.L (A7)+,(A5)+ 13/12
MOVE.L (A7)+,(A5)+ 11/10
MOVE.L (A7)+,(A5)+ 9/8
MOVE.L (A7)+,(A5)+ 7/6
MOVE.L (A7)+,(A5)+ 5/4
MOVE.L (A7)+,(A5)+ 3/2
SAVE_0_W EQU *
MOVE.L (A7)+,(A5)+ 0/1 A4/A5/A6 ARE ALWAYS SAVED
MOVE.L (A7)+,(A5)+
MOVE.L (A7)+,(A5)+
BTST.B #5,(A7) TEST SUPERVISOR BIT OF SR
IF <NE> THEN.S IF ON THEN "EN_STOPR HAS BEEN CALLED"
MOVE.W SAVE_SR,(A5) SAVE_SR ARE SAVED IN CTX
MOVE.L SAVE_PC,2(A5) SAVE_PC ARE SAVED IN CTX
MOVE.L D4,SAVE_PC SAVE_PC:= ENTRY ADDR;
* SAVE_SR IS UNCHANGED;
ELSE.S ELSE
MOVE.W (A7),(A5) SAVE SR IN CTX
MOVE.L 2(A7),2(A5) SAVE PC IN CTX
MOVE.L D4,2(A7) PC := ENTRY ADDR
* SR IS UNCHANGED;
ENDI ENDI;
SUBQ.L #8,A7 A5/A6 OF NEW STACK IS UNDEFINED;
MOVE.L D5,-(A7) PUSH FUNCTION ON STACK
JMP (A6) GOTO RETURN POINT
PAGE
TIMCHECK EQU * ALLOW OTHER PROCESSES TO RUN IF TIMEOUT HAS OCCURED
*
* CALLER MUST BE A NORMAL PROCESS.
* ALL REGISTERS ARE SPOILED. AT RETURN A2=CURRENT CONTEXT
*
LEA RUNNING,A1 A1:= RUNNING QUEUE;
MOVE.L KV_CTX,A2 A2:= CURRENT CONTEXT;
MOVE.L SUPV_STK,A6 A6:= BOTTOM OF STACK;
BTST.B #5,-8(A6) TEST SR OF CALLING PROCESS;
BNE.S KNELWAIT WHEN SUPV_BYTE <> 0 PAUSE CURRENT PROC;
RTS RETURN;
SYNCSTOP EQU * SYNCRONIZING PROCESS IS STOPPED
* COMMON WAY TO WAIT IN GATE OR COND OBJECT
* CALL: RETURN:
* A0 ANY EXTENSION OBJECT
* A1 ANY PROCESS OBJECT
* A2 CURRENT CONTEXT CURRENT CONTEXT
* A3 ANY CURRENT CONTEXT
* D7 ANY PROC.SYNC_RESULT
* SR/CCR 27/XX 27/EQ
*
BSR.L SUSPEND STOP AND WAIT(A2=CTX,A0/A1/A2/A3:=!);
CLR.L D7 D7:=
MOVE.W PR_SYN(A1),D7 PROC.SYNC_RESULT
CLR.B PR_STA(A1) (PROC.STATE:=RUN:=0;)CCR:=<EQ>;
RTS RETURN;
PAGE
KNELSIGN EQU * KERNEL DEFINED SIGNAL OPERATION
* CALL RETURN
* A1 QUEUE TO SIGNAL SAME
* A4,A5,A6 ANY UNDEF
* CCR <NE>: NO PROC SCHEDULED
* CCR <EQ>: ONE PROC SCHEDULED
* A1 MAY BE ONE OF THE QUEUES MENTIONED IN KNELWAIT
*
PRT_MEM KNELSIGN,(A1),8 ********
MOVE.L (A1),A4 A4:=FIRST PROC IN QUEUE
IF.L A1 <NE> A4 THEN.S IF QUEUE IS NOT EMPTY THEN
REM_ELEM (A4),A5,A6,A5/A6 REMOVE PROC FROM QUEUE
LEA RUNNING,A5 A5:=RUNNING QUEUE;
INS_ELEM A5,A4,A6,A5/A6 INSERT PROC AS LAST MEMBER OF RUNNING QUEU
CMP.W D0,D0 CCR:=<EQ>;
ELSE.S ELSE
MOVE.W #0,CCR CCR:=<NE>;
ENDI ENDI;
RTS RETURN;
KNELWAIT EQU * KERNEL DEFINED WAIT OPERATION
* CALL RETURN
* A0 ANY EXTENSION OBJECT
* A1 QUEUE TO WAIT IN CURRENT PROCESS OBJECT
* A2 CURRENT CONTEXT CURRENT CONTEXT
* A3 ANY CURRENT CONTEXT
* OTHER ANY UNDEF
*
* THE PROCEDURE IS CALLED WHEN KERNEL DEFINED SYNCHRONIZATION APPEAR:
* 1) CURRENT PROCESS DELETES ANOTHER PROCESS (A1=PR_TERM OF PROC TO BE DELETED)
* 2) CURRENT PROCESS DELETES A SEGMENT (A1=SE_WAIT OF SEGM TO BE DELETED)
* 3) CURRENT PROCESS CALLS THE ALLOCATER (CREATE/DELETE OPEN OBJ,A1=MM_QUEUE)
* A1=RUNNING QUEUE IMPLEMENTS: ALLOW SCHEDULER TO RESCHEDULE - USED BY TIMCHECK
*
MOVE.L KV_PROC,A0 A0:=CURRENT PROCESS;
REM_ELEM PR_MAIN(A0),A3,A4,A3/A4 REMOVE CUR_PROC FROM TIMER QUEUE;
INIT_HEAD PR_MAIN(A0),A3 INIT MAIN QUEUE ELEMENT
LEA PR_AUX(A0),A3 A3:=AUX CHAIN OF CUR PROC
REM_ELEM (A3),A4,A5,A4/A5 REMOVE PROC FROM RUNNING QUEUE
INS_ELEM A1,A3,A4,A1/A4 INSERT PROC.AUX IN WAIT QUEUE
PRT_MEM KNELWAIT,(A1),8 ********
BRA.L SUSPEND SUSPEND(A2=CTX,A0-A4:=!);
* RETURN IS MADE DIRECTLY TO THE CALLER WHEN THE PROC IS RESUMED
PAGE
SCHEDOBJ EQU * SCHEDULER OBJECT FUNCTIONS EXECUTED IN KERNEL MODE
* CALL RETURN
* D0-D4 ANY UNDEF
* D5 FUNCTION UNDEF
* D6 ARG # RESULT
* D7 ANY RESULT
* A0 EXTENSION SAME
* A1/A3/A6 ANY UNDEF
* A2 CUR_CTX SAME
* A4 ARGUMENT ADDR (PHYS) UNDEF
* A5 DECL_DIV OBJECT UNDEF
* CCR <EQ>
* THE FUNCTIONS ARE INVOKED BY THE GENERAL SCHEDULER OBJECTS WHEN THEY
* CALL THE FUNCTIONS OF THE "DECL_DIV OBJECT". NO OTHER OBJECTS
* HOLD A REFERENCE TO THE DECL_DIV OBJECT. CONSEQUENTLY, THE CALLS TO
* DECL_DIV CANNOT HAVE AN ILLEGAL SYNTAX. ARGUMENTS TO DECL_DIV (DIV_PAR BELOW)
* ARE LOCATED BEFORE THE OBJ_CALL ARGUMENTS. CONSEQUENTLY,THEY MAY BE ADDRESSED
* RELATIVE TO A4. THE FUNCTIONS OF DECL_DIV ARE:
* 1: DECL_DORMANT: CHANGES AN OPEN OBJECT TO A DORMANT PROCESS
* 2: DECL_COND: CHANGES AN OPEN OBJECT TO A CONDITION OBJECT
* 3: DECL_GATE: CHANGES AN OPEN OBJECT TO A GATE OBJECT
* 4: DECL_CHANNEL: INSTALLS AN INTERRUPT PROCEDURE
* 5: REM_EXT: SELECTS A STACK EXTENSION OBJECT THAT CAN BE DELETED.
* TERMDRIV IS THE INVERSE OPERATION OF DECL_CHANNEL, BUT IT IS NOT
* CALLED EXPLICITLY. IT IS CALLED WHEN THE KERNEL REMOVES A
* DRIVER POINTER. AN EXPLICIT FUNCTION CALLED "REM_CHANNEL" MIGHT
* BE IMPLEMENTED.
DIV_PAR EQU 4+4+4 SIZE OF (RETURN-PC + POINTER_ARG + FUNCTION_ARG)
* DIV_PAR(A4) CONTAINS NONSTANDARD ARGUMENTS
* TO THE FUNCTIONS OF DECL_DIV;
* ARGUMENT FOR DECLCHAN:
DIV_EXT EQU DIV_PAR EXTENSION
DIV_CHA EQU DIV_EXT+4 CHANNEL
DIV_LEV EQU DIV_CHA+4 LEVEL
DIV_STK EQU DIV_LEV+4 STACK
DIV_ENT EQU DIV_STK+4 ENTRY
* THE VECTOR TABLE (KV_INVEC) HOLDS ADDRESSES OF INTERRUPT PROCEDURES.
* THE DRIVER TABLE (DRIV_TAB) HOLDS ADDRESSES OF ENVELOPES.
* THE STACK TABLE (STAK-TAB) HOLDS DESCRIPTIONS OF THE DRIVERS.
* THE CODE AND THE LOCAL POINTERS OF A CHANNEL CAN BE "ADDRESSED"
* BY AN INTERRUPT USING THE FIRST TWO TABLES. A DESCRIPTION IN
* THE STACK TABLE HOLDS STACK <<16+LEVEL OF THE INTERRUPT.
* IT IS USED BY THE KERNEL TO MONITOR THE SIZE OF THE
* SUPERVISOR STACK
* "UNASSIGNED" ENTRIES IN THE DRIVER - AND STACK TABLE WILL CONTAIN
* EITHER -1: A DRIVER CAN NEVER BE ASSIGNED TO THIS CHANNEL
* AND NO STACK REQUIREMENT IS CLAIMED BY THIS CHENNEL.
* OR = 0: FREE CHANNEL;
PAGE
MOVEQ.L #4,D6 D6:= ARG# CORRESPONDING TO FORMAL-1
LSL.W #1,D5 D5:=FUNC:=FUNCTION <<1;
CASEJMP D5 GOTO CASE FUNC OF
CASELAB CASE_ERR 0<1: NOT POSSIBLE
CASELAB DECLDORM 1<1: DECL_DORMANT PROCESS
CASELAB DECLCOND 2<1: DECL_CONDITION OBJECT
CASELAB DECLGATE 3<1: DECL_GATE OBJECT
CASELAB DECLCHAN 4<1: DECL_CHANNEL
* CASELAB REM_EXT NOT IMPL. 5<1: REMOVE_EXTENSION
DECLDORM EQU * DECL.DORMANT PROCESS
* THE PARAMETERS ARE AS FOLLOWS:
* FORMAL-1 OF CALLING CONTEXT (=A2) SHOULD BE AN OPEN OBJECT
*
BSR.L C_OPENF1 CHECK_F1(A3:=OBJECT,...
BNE.L ER_GIVEUP WHEN <NE>:NOT_OK GOTO GIVE_UP;
DECLBOOT EQU * DECLARE BOOT PROCESS: "CALLED FROM ENTER"
MOVE.W #PR_SIZ-OB_SIZ,D0 D0:=KNEL BYTES FOR PROCESS DESCR;
EXG.L A3,A0 A0:=OBJECT; SAVE A0 IN A3;
BSR.L MM_PUSHO RESERVE KNEL BYTES (D0=BYTES, A0=OBJECT)
EXG.L A0,A3 A3:=OBJECT, RESTORE A0 FROM A3
BEQ.L ER_GIVEUP WHEN NO ROOM GOTO GIVE_UP;
INIT_HEAD EX_CTX(A3),A6 CONTEXTS:=EMPTY
INIT_HEAD EX_EXT(A3),A6 EXTENSIONS:=EMPTY
MOVE.L A3,EX_PR(A3) PROC_ADDR:=PROC_OBJECT;
INIT_HEAD PR_MAIN(A3),A6 MAIN_QUEUE NOT USED
INIT_HEAD PR_AUX(A3),A6 AUX_QUEUE NOT USED
INIT_HEAD PR_TERM(A3),A6 NO PROC WAITING FOR TEMRINATION;
MOVE.B #OB_DOOB,OB_KIN(A3) OBJECT.KIND:=DORMANT PROCESS;
CLR.L PR_CPU(A3) CLEAR SIMPLE FIELDS OF PROCESS
CLR.L PR_CPU+4(A3)
CLR.B PR_PRI(A3)
CLR.B PR_STA(A3)
* PR_TIMO NEED NOT BE ASSIGNED
CLR.L D7 D7:=RESULT:=OK; CCR:=RETURN := <EQ>;
PRT_MEM DECLDORM,(A3),PR_SIZ ********
RTS RETURN;
PAGE
DECLCOND EQU * DECL.CONDITION OBJECT
* THE PARAMETERS ARE AS FOLLOWS:
* FORMAL -1 OF CALLING CONTEXT SHOULD BE AN OPEN OBJECT
* FORMAL -2 OF CALLING CONTEXT SHOULD BE A GATE OBJECT
* THE OPEN OBJECT IS CHANGED TO A CONDITION MANAGED BY THE GATE;
*
BSR.L C_OPENF1 CHECK_F1(A3:=OBJECT,D0:=INDEX TO FORMAL-1;
BNE.L ER_GIVEUP WHEN <NE>:NOT_OK GOTO GIVE_UP;
MOVE.L #5,D6 D6:= ARG# OF FORMAL-2
ADD.W #FP_SIZ,D0 D0:=INDEX TO FORMAL-2:=D0+SIZE OF FORMAL P
LEA (A2,D0.W),A1 A1:=FORMAL-2;
CMP.B #PT_OBJ,PT_KIN(A1) TEST POINTER; "GATE MAY HAVE BEEN DELETED"
BNE.L ER_DUMMY WHEN KIND <> REF_OBJ GOTO DUMMYFIED;
MOVE.L PT_REF(A1),A1 A1:=GATE OBJECT;
CMP.B #OB_GAOB,OB_KIN(A1) TEST OBJECT; "GATE MAY HAVE BEEN TERMINATE
BNE.L ER_DUMMY WHEN KIND<>GATE GOTO DUMMYFIED;
* A1 = GATE OBJECT.
MOVE.W #CO_SIZ-OB_SIZ,D0 D0:=KNEL BYTES FOR CONDITION DESCR.
EXG.L A3,A0
BSR.L MM_PUSHO RESERVE KNEL BYTES (D0=BYTES,...
EXG.L A0,A3
BEQ.L ER_GIVEUP WHEN NOT OK GOTO GIVE_UP;
MOVE.B #OB_COOB,OB_KIN(A3) COND.KIND:=COND OBJ;
MOVE.L A1,CO_GA(A3) COND.GATE:=GATE OBJECT;
INIT_HEAD CO_WAIT(A3),A6 COND.WAITING_PROCS:=EMPTY;
LEA GA_SET(A1),A1 A1:=MAN_SET OF GATE;
LEA CO_MAN(A3),A3 A3:=MEMBER OF MANSET;
INS_ELEM A1,A3,A6,A1/A6 INSERT CONDITION IN MAN_SET OF GATE;
CLR.L D7 D7:=RESULT:=OK; CCR:= RETURN := <EQ>;
PRT_MEM DECLCOND,-CO_MAN(A3),CO_SIZ ********
RTS RETURN;
PAGE
DECLGATE EQU * DECL.GATE OBJECT
* THE PARAMETERS ARE AS FOLLOWS:
* FORMAL-1 OF CALLING CONTEXT SHOULD BE AN OPEN OBJECT.
* CURRENT OBJECT OF CALLING CONTEXT BECOMES THE SCHEDULER OF THE GATE.
* DIV_PAR HOLDS A LONG INTEGER. IF THE CALLING SCHEDULER IS AN INTERRUPT
* SCHEDULER, THE INTEGER DESIGNATE THE LEVEL OF THE DEVICE GATE TO BE CREATED.
*
BSR.L C_OPENF1 CHECK_F1(A3:=OBJECT;
BNE.L ER_GIVEUP WHEN <NE>:NOT_OK GOTO GIVE_UP;
MOVEQ.L #0,D6 D6:= ARG# OF
SUBQ.B #1,D6 FIRST VALUE;
BSR.L C_SCHED CHECK_SCHED(A1:=SCHEDULER,...
IF <NE> THEN.S IF INTERRUPT SCHEDULER THEN
MOVE.L DIV_PAR(A4),D1 D1:=LEVEL OF DEVICE GATE;
BLE.L ER_DAILL WHEN LEVEL <=0 GOTO DATA_VALUE_ILLEGAL;
CMP.L #6,D1
BGT.L ER_DAILL WHEN LEVEL > 6 GOTO DATA_VALUE_ILLEGAL;
ELSE.S ELSE "NORMAL SCHEDULER"
CLR.W D1 D1:=0; "LEVEL OF NORMAL GATE"
ENDI ENDI;
* A3=OPEN OBJ, A1=SCHEDULER, D1.W=LEVEL OF NEW GATE OBJECT
MOVE.W #GA_SIZ-OB_SIZ,D0 D0:=SIZE OF GATE DESCR;
EXG.L A3,A0
BSR.L MM_PUSHO RESERVE(D0:=KNEL BYTES,...
EXG.L A0,A3
BEQ.L ER_GIVEUP WHEN NOT OK GOTO GIVE_UP;
MOVE.B #OB_GAOB,OB_KIN(A3) GATA.KIND:= GATE_OBJ;
INIT_HEAD GA_SET(A3),A6 MAN_SET:=EMPTY;
INIT_HEAD GA_LOK(A3),A6 LOCKING:=EMPTY;
INIT_HEAD GA_RELOK(A3),A6 RELOCKING:=EMPTY;
INIT_HEAD GA_SPLOK(A3),A6 SPEED RELOCKING:=EMPTY;
MOVE.W D1,GA_STA(A3) STATE:=OPEN; LEVEL:=LEVEL;
LEA GA_SCH(A3),A3 A3:=SP:=SCHEDULER POINTER
MOVE.W #PT_OBJ<<8,PT_KIN(A3) SP.KIND:=REF_OBJ; SP.SCOPE:=NO_SCOPE;
MOVE.L A1,PT_REF(A3) SP.REF:=SCHEDULER;
LEA OB_REF(A1),A1 A1:=REF OBJECT CHAIN
INS_ELEM A1,A3,A6,A1/A6 INSERT POINTER IN REFOBJ CHAIN OF SCHED;
CLR.L D7 D7:=RESULT:=0; CCR:=RETURN:=<EQ>;
PRT_MEM DECLGATE,-GA_SCH(A3),GA_SIZ ********
RTS RETURN;
PAGE
DECLCHAN EQU * DECL_CHANNEL
* THE PARAMETERS ARE AS FOLLOWS:
* THE ACTUAL OF FORMAL-1 IN CURRENT CONTEXT SHOULD BE A LOCAL SIMPLE POINTER.
* IT BECOMES A DRIVER POINTER. FORMAL-2 SHOULD POINT TO A SEGMENT OBJECT.
* IT HOLDS THE CODE OF THE INTERRUPT PROCEDURE OF THE NEW CHANNEL.
* DIV_PAR CONTAINS FIVE LONG INTEGERS: EXTENSION, CHANNEL, LEVEL, STACK, ENTRY.
* EXTENSION=0: SETUP CHANNEL OR CLAIM CHANNEL AND SUPERVISOR STACK SPACE.
* EXTENSION>0: EXTEND STACK AND SETUP CHANNEL; TEMP-2 HOLDS THE EXT_OBJ.
* DECLCHAN IS ONLY CALLED BY THE INITIAL SCHEDULER. EXTENSION > 0 NOT IMPL.
*
MOVEQ.L #0,D6 D6:= ARG# OF
SUBQ.B #1,D6 FIRST VALUE;
MOVE.L DIV_CHA(A4),D1 D1:=CHANNEL;
BLT.L ER_DAILL WHEN CHANNEL <0 GOTO DATA_VALUE_ILLEGAL;
CMP.L #255,D1
BGT.L ER_DAILL WHEN CHANNEL > 255 GOTO DATA_VALUE_ILLEGAL;
LSL.W #2,D1 D1:=CHANNEL INDEX:=CHANNEL *4
SUBQ.B #1,D6 D6:= ARG# OG 2. VALUE
MOVE.L DIV_LEV(A4),D3 D2:=LEVEL;
BLE.L ER_DAILL WHEN LEVEL <=0 GOTO DATA_VALUE_ILLEGAL;
CMP.L #7,D3
BGT.L ER_DAILL WHEN LEVEL > 7 GOTO DATA_VALUE_ILLEGAL;
SUBQ.B #1,D6 D6:= ARG# OF 3. VALUE
MOVE.L DIV_STK(A4),D2 D2:=STACK; "USED BY INTERRUPTS"
BLT.L ER_DAILL WHEN STACK <0 GOTO DATA_VALUE_ILLEGAL;
CMP.L #1<<11,D2
BGT.L ER_DAILL WHEN STACK >2K GOTO DATA VALUE ILLEGAL;
ADD.L #TRP7RESI,D2 D2:=STACK:=...+KERNEL_OVERHEAD+$FF;
CLR.B D2 D2:= AN INTEGRAL #PAGES;
SWAP D2 D2:=STACK<<16
MOVE.B D3,D2 +LEVEL;
* D1 = CHANNEL INDEX, D2=STACK<<16+LEVEL
*
MOVE.L DIV_EXT(A4),D7 D7:=EXT PARAM;
**IF <EQ> THEN.S IF EXT = 0 THEN "NO OBJECT IN TEMP -2"
LEA STAK_TAB,A6 A6:=STACK_TABLE
TST.L (A6,D1.W) TEST FOR FREE CHANNEL
BNE.L ER_INUSE WHEN CHANNEL IN USE GOTO CHANNEL_IN_USE;
MOVE.L D2,(A6,D1.W) STACK_TAB(CHANNEL):="IN_USE";
BSR.L COMPSTAK COMPSTAK(D6:=DIF,A6=STACK,D2/D3/D4:=?);
IF <GT> THEN.S IF STACK TOO SMALL THEN
CLR.L (A6,D1.W) RELEASE CHANNEL;
BRA.L ER_NORES GOTO NO RESOURSES(D6=MISSING SPACE);
ENDI ENDI;
BSR.L C_FORM12 CHK_FORMLS(A1/A3/A5/D0/D5:=!,D3/D6/A6:=?)
IF <EQ> THEN.S IF NOT OK THEN
LEA STAK_TAB,A6 A6:=STACK_TABLE;
CLR.L (A6,D1.W) STACK_TABLE(CHANNEL):="FREE"; CCR:=<EQ>
RTS RETURN;
ENDI ENDI;
BSR.L CRE_CHAN CREATE_CHANNEL(A1/A3/A5/D0/D1/D5=!,
* A1/A3/A5/D0/D1/D5/A6:=?)
CLR.L D7 RESULT:=OK; CCR:=RETURN:=<EQ>;
RTS RETURN;
**ENDI ENDI; "EXT=0"
PAGE
* EXT >0, TEMP-2 SHOULD HOLD AN OPEN OBJECT
* THE CHANNEL AND THE CURRENT STACK HAS BEEN CLAIMED
* WHILE THE OPEN OBJECT WAS CREATED.
*
* 1. CHECK TEMP-2, FREE USER SPACE MUST BE EQUAL TO EXT
* 2. MOVE OBJECT TO OWNERSET OF LOCAL-2.
* 3. REMOVE FREE USER SPACE FROM THE OBJECT AND EXTEND THE STACK
* 4. CHECK FORMAL-1 AND -2;
* A. IF NOT OK THEN UNDO STEP 2 AND 3 AND RELEASE THE CHANNEL
* B. IF OK THEN CREATE THE CHANNEL DESCRIPTIONS
* 5. REDUCE CLAIMERS BY ONE.
*
* AT PRESENT ONLY STEP 4 AND 5 ARE IMPLEMENTED. (RESULT ALWAYS <> OK);
* MOVE.L #ECRG_UP,D7 D7:=RESULT:=GIVE_UP;
* BSR.L C_FORM12 CHECK_FORMALS(... D7 MAY CHANGE)
* LEA STAK_TAB,A6
* SUBQ.W #1,CLAIMERS CLAIMERS:=...-1;
* CLR.L (A6,D1.W) STAK_TAB(CHANNEL):="FREE"; CCR:=<EQ>
* RTS RETURN;
TERMDRIV EQU * REMOVE CHANNEL DESCRIPTIONS;
* CALL: RETURN:
* D0/D1 ANY UNDEF
* A1/A3 ANY UNDEF
* A6 POINTER ADDRESS UNDEF POINTER BECOMES NIL
* CALLED BY THE KERNEL BEFORE DRIVER POINTER IS DESTROYED.
* DECREASE RESIDENT COUNTS OF ENVELOPE AND CODE SEGMENT OBJECT
* ASSIGN "FREE" TO INTERRUPT VECTOR, DRIVER_TABLE AND STACK_TABLE
*
PRT_MEM TERMDRIV,(A6),PT_SIZ ********
CLR.W D1 D1.W:=CHANNEL_INDEX
MOVE.B PT_INF(A6),D1 :=CHANNEL
LSL.W #2,D1 *4;
* CHANGE DRIVER TO A LOCAL-NIL-POINTER.
MOVE.B #1<<PT_LSC,PT_INF(A6) SCOPE:=LOCAL;
MOVE.B #PT_NIL,PT_KIN(A6) KIND:=NIL;
REM_ELEM (A6),A1,A3,A1/A3 REMOVE POINTER FROM SEGMENT CHAIN;
* PT_REF IS LEFT UNCHANGED FOR USE IN DECREASE RES_COUNT.
INIT_HEAD (A6),A3 POINTER CHAIN:=EMPTY;
LEA DRIV_TAB,A3 A3:=DRIVER TABLE;
MOVE.L (A3,D1.W),A1 A1:=EN_STK OF ENVELOPE HOLDING DRIVER PT.
SUBQ.W #1,EN_RES-EN_STK(A1) ENV.RES_COUNT:=...-1;
PRT_MEM DRIV_ENV,-EN_STK(A1),ST_SIZ ********
CLR.L (A3,D1.W) DRIVER_TABLE(CHANNEL):=FREE:=0;
PRT_MEM DRIV_TAB,<(A3,D1.W)>,4 ********
LEA STAK_TAB,A3 A3:=STACK_TABLE;
CLR.L (A3,D1.W) STACK_TABLE(CHANNEL):=FREE:=0;
LEA KV_INVEC,A3 A3:=INTERRUPT VECTOR(=0!)
LEA RTEDUMMY,A1 A1:=DUMMY INTERRUPT PROCEDURE;
MOVE.L A1,(A3,D1.W) INT_VECTOR(CHANNEL):=DUMMY_PROC;
PRT_MEM KV_INVEC,<(A3,D1.W)>,4 ********
MOVEQ #-1,D0 D0:=DECREASE:=-1;
MOVE.W #OB_RES,D1 D1:=ADDRESS OF RES_COUNT;
BSR.L INCRDECR DECREASE (PT_REF(A6),...
RTS RETURN;
PAGE
COMPSTAK EQU * COMPUTE DIFFERENCE=NEEDED_SUPVSIZE-ACTUAL_SUPVSIZE
* CALL RETURN:
* D2/D3/D4 ANY UNDEF
* D6 DIFFERENCE
* A6 STAK_TAB SAME
* CCR <LE>:DIFFERENCE<=0; <GE>:DIFFERENCE>=0
CLR.L D6 D6:=NEEDED_STACK:=0;
FOR.W D2=#0 TO #7 BY #1 DO.S FOR ALL LEVELS DO.S
CLR.L D3 MAX:=0;
FOR.W D4=#0 TO #255*4 BY #4 DO.S FOR ALL CHANNELS DO.S
* THIS FOR LOOP USES MAX 84 CYCLES/CHANNEL
TST.B D4 TEST (CHANNEL*4) MOD 256 = 0
IF <EQ> THEN.S IF CHANNEL MOD 64 = 0 THEN
BSR.L EN_DIS ALLOW INTERUPS TO BE GRANTED;
ENDI ENDI;
MOVE.L (A6,D4.W),D5 D5:=DESC:=STAK_TAB(CHANNEL)
IF <GT> THEN.S IF CHANNEL IN USE THEN
IF.B D2 <EQ> D5 THEN.S IF DESC.LEVEL=CUR_LEVEL THEN
IF.L D5 <GT> D3 THEN.S IF DESC > MAX THEN
MOVE.L D5,D3 D3:=MAX:=DESC
ENDI ENDI;
ENDI ENDI;
ENDI ENDI;
ENDF ENDF;
CLR.W D3
SWAP D3 D3:=STACK USED BY LEVEL;
ADD.L D3,D6 D6:=NEEDED_STACK:=...+STACK USED BY LEVEL
ENDF ENDF;
MOVE.L SUPV_STK,D2 D2:=ACTUAL_SIZE:= LAST+1 BYTE OF STACK
SUB.L F_SUPVS,D2 - FIRST BYTE OF STACK;
SUB.L D2,D6 D6:=DIF:=NEEDED_STACK-ACTUAL_SIZE;CCR:=!;
RTS RETURN;
PAGE
C_FORM12 EQU * CHECK FORMAL-1 AND -2 IN DECL_CHANNEL
* CALL: RETURN;
* A1 ANY SEGMENT DATA
* A2 CUR_CTX SAME
* A3 ANY SEGMENT OBJECT
* A4 ARGUMENT ADDR SAME
* A5 ANY DRIVER ENVELOPE
* A6 ANY UNDEF
* DO ANY DRIVER POINTER OFFSET
* D3 ANY UNDEF
* D5 ANY ENTRY ADDRESS
* D6 ANY UNDEF
* D7 RESULT WHEN CCR = <EQ>
* CCR <NE>:OK; <EQ>:NOT OK
*
* FORMAL-1 SPECIFIES THE DRIVER POINTER
* FORMAL-2 SPECIFIES THE CODE SEGMENT OF THE INTERRUPT PROCEDURE
*
MOVEQ.L #4,D6 D6:= ARG# OF FORMAL-1;
MOVE.W CT_TOPT(A2),D0 D0:=INDEX TO FORMAL-1
LEA (A2,D0.W),A3 A3:=ADDRESS OF FORMAL-1
MOVE.W FP_OFF(A3),A6 A6:=FORMAL-1 IN THE SCHEDULER CTX
ADD.L FP_STR(A3),A6 CALLED BY THE USER;
BCLR.B #PT_RET,PT_INF(A6) CLEAR RETURN BIT ON FORMAL;
MOVE.W FP_OFF(A6),D0 (A5,D0):=ACTUAL DRIVER POINTER
MOVE.L FP_STR(A6),A5 AS DEFINED BY THE USER;
IF.W A5 <EQ> #0 THEN.S IF ACTUAL = DUMMY ACTUAL THEN
MOVE.L #ECRRETURN,D7 RESULT:=RETURN_POINTER_ILLEGAL;
CMP.W D0,D0 CCR:=<EQ>
RTS RETURN;
ENDI ENDI;
LEA (A5,D0.W),A6 A6:=DRIVER POINTER;
BTST.B #PT_LSC,PT_INF(A6) TEST FOR LOCAL SCOPE
IF <EQ> THEN.S IF SCOPE <> LOCAL THEN
MOVE.L #ECRSCOPE,D7 D7:=RESULT:=POINTER_SCOPE_ILLEGAL;
CMP.W D0,D0 CCR:=<EQ>
RTS RETURN;
ENDI ENDI;
PAGE
IF.B PT_KIN(A6) <GT> #PT_ENV THEN.S IF KIND <> SIMPLE THEN
MOVE.L #ECRRETURN,D7 D7:=RESULT:=RETURN_POINTER_ILLEGAL;
CMP.W D0,D0 CCR:=<EQ>
RTS RETURN;
ENDI ENDI;
MOVEQ.L #5,D6 D6:= ARG# OF FORMAL-2;
LEA FP_SIZ(A3),A6 A6:=FORMAL-2:=NEXT TO FORMAL-1;
MOVE.B PT_KIN(A6),D2 D2:=POINTER_KIND
BSR.L C_SEGM CHECK_SEGMENT(A1/A3/D3/D5:=SEGM DESC...)
IF <EQ> THEN.S IF NOT OK THEN
RTS RETURN
ENDI ENDI;
BTST.L #2,D5 TEST EXECUTE BIT IN USE-BITS OF SEGMENT
IF <EQ> THEN.S IF NO EXECUTE BIT THEN
MOVE.L #ECRCAP,D7 D7:=RESULT:=CAPABILITY_VIOLATION;
CMP.W D0,D0 CCR:=<EQ>
RTS RETURN;
ENDI ENDI;
MOVEQ.L #0,D6 D6:= ARG# OF
SUBQ.B #4,D6 4. VALUE
MOVE.L DIV_ENT(A4),D5 D5:=ENTRY ADDRESS;
BLT.S C_FORMXX WHEN ENTRY <0 GOTO ENTRY_ILLEGAL;
BTST.L #0,D5 TEST BIT 0 IN ENTRY ADDRESS
BNE.S C_FORMXX WHEN UNEVEN ADDRESS GOTO ENTRY_ILLEGAL;
SUB.L D5,D3 D3:=DATA LENGTH - ENTRY ADDRESS;
BLE.S C_FORMXX WHEN ENTRY OUTSIDE GOTO ENTRY_ILLEGAL;
RTS RETURN; "CCR = <NE>"
C_FORMXX EQU * ENTRY_ILLEGAL:
MOVE.L #ECRDATA,D7 D7:=RESULT:=DATA_VALUE_ILLEGAL;
CMP.W D0,D0 CCR:=<EQ>
RTS RETURN;
PAGE
CRE_CHAN EQU * CREATE CHANNEL DESCRIPTIONS
* CALL: RETURN:
* A1 SEGM DATA (INT_PROC_CODE) UNDEF
* A3 SEGM OBJECT UNDEF
* A5 DRIVER ENVELOPE UNDEF
* A6 ANY UNDEF
* D0 DRIVER POINTER OFFSET UNDEF
* D1 CHANNEL INDEX UNDEF
* D5 ENTRY ADDRESS (OF INTRPT) UNDEF
*
*
* ASSIGN TO DRIVER TABLE, INTERRUPT VECTOR AND DRIVER POINTER;
* INCREASE RESIDENT COUNT OF ENVELOPE AND CODE SEGMENT OBJECT;
PRT_REG CRE_CHAN_D0/D1/D5/A1/A3/A5/ ********
LEA DRIV_TAB,A6 A6:=DRIVER_TABLE ADDRESS
LEA EN_STK(A5),A5 A5:= STK_EL_ADDR:= ADDR OF ENV.EN_STK;
MOVE.L A5,(A6,D1.W) DRIVER_TABLE(CHANNEL):=STK_EL_ADDR;
PRT_MEM DRIV_TAB,<(A6,D1.W)>,4 ********
LEA KV_INVEC,A6 A6:=INTERRUPT VECTOR ADDRESS;"NORMALLY=0"
ADD.L D5,A1 A1:=INTERRUPT ENTRY (PHYS);"=DATA+ENTRY"
MOVE.L A1,(A6,D1.W) INT_VECTOR(CHANNEL):=INTERRUPT ENTRY;
PRT_MEM KV_INVEC,<(A6,D1.W)>,4 ********
LEA -EN_STK(A5),A1 A1:= ENVELOPE;"OFFSET"
ADDQ.W #1,EN_RES(A1) ENV.RES_COUNT:=...+1;
EXG D0,D1 D1:=DRIVER POINTER REL; SAVE D1 IN D0;
BSR.L CLR_SMP CLR_SMP((A1,D1)=PT, A6:=PT);
MOVE.L A6,A5 A5:= DRIVER POINTER:=A6;
EXG D1,D0 RESTORE D0,D1
LEA OB_REF(A3),A1 A1:=REF_OBJ CHAIN OF SEGMENT;
INS_ELEM A1,A5,A6,A1/A6 CHAIN DRIVER POINTER TO SEGMENT;
MOVE.L A3,PT_REF(A5) POINTER.REF:=SEGMENT OBJECT;
MOVE.B #PT_INT,PT_KIN(A5) POINTER.KIND:=DRIVER_POINTER;
LSR.W #2,D1 D1.B:=CHANNEL:=CHANNEL_INDEX DIV 4;
MOVE.B D1,PT_INF(A5) POINTER.INF:=CHANNEL;
PRT_MEM DRIV_PT,(A5),PT_SIZ ********
MOVEQ. #1,D0 D0:=INCREASE:=+1;
MOVE.W #OB_RES,D1 D1:=ADDRESS OF RESIDENT COUNT;
MOVE.L A5,A6 A6:=POINTER TO SEGMENT:=DRIVER_POINTER;
BSR.L INCRDECR INCREASE RESIDENT COUNTS
RTS RETURN;
C_SCHED EQU * CHECK CALLING SCHEDULER;
* CALL: RETURN:
* A1 ANY SCHEDULER OBJECT
* A2 CUR_CTX SAME
* A6 ANY UNDEF
* D0.B ANY POINTER KIND OF LOCAL-5 OF SCHEDULER
* CCR <EQ>: NORMAL, <NE>: INTERRUPT SCHEDULER
*
MOVE.L CT_OBJ(A2),A1 A1:=SCHED:=CURRENT_OBJECT
MOVE.L OB_SPA(A1),A6 A6:=TOP_OBJ=SPACE DESC;
MOVE.L SP_ENV+4(A6),A6 A6:=PRIMARY ENVELOPE
LEA EN_SIZ-EN_STK+4*PT_SIZ(A6),A6 A6:= ADDRESS OF LOCAL-5;
* A6 = LOCAL-5 OF CALLING SCHEDULER; PT_KIN=NIL=0 FOR A NORMAL SCHEDULER
MOVE.B PT_KIN(A6),D0 D0:=LOCAL-5.KIND, CCR:=SCHEDULER KIND;
RTS RETURN;
PAGE
C_OPENF1 EQU * CHECK THAT ONE OPEN OBJECT IS PRESENT IN FORMAL-1
* CALL: RETURN:
* D0 ANY INDEX TO FORMAL-1
* A2 CUR_CTX SAME
* A3 ANY OPEN OBJECT
* CCR: OBS, OBS, OBS, <NE>: NOT OK, <EQ>: OK
*
MOVE.W CT_TOPT(A2),D0 D0:=INDEX TO FIRST FORMAL;
LEA (A2,D0.W),A3 A3:=ADDRESS OF FIRST FORMAL POINTER;
CMP.B #PT_OWN,PT_KIN(A3) TEST KIND OF FIRST FORMAL
BNE.S C_OPENFX WHEN NOT OWNER GOTO EXIT_NOT_OK
MOVE.L (A3),A3 A3:= FIRST OBJECT IN OWN_SET;
CMPA.L 4(A2,D0.W),A3 COMPARE FIRST AND LAST OF OWN_SET;
BNE.S C_OPENFX WHEN MORE THAN ONE OBJ IN SET GOTO EXIT....
CMP.B #OB_OPOB,OB_KIN(A3) CCR:= KIND=OPEN;
C_OPENFX EQU * EXIT_NOT_OK:
RTS RETURN;
PAGE
* LABELS WITH "ER_" ARE USED IN THE ENVIRONMENT OF C_CALL
ER_GIVEUP EQU * GIVE_UP:
MOVE.L #ECSG_UP,D7 D7:=RESULT:=STATUS,GIVE_UP;
BRA.S ER_RTS GOTO RETURN
*
ER_DUMMY EQU * DUMMYFIED:
MOVE.L #ECSDUMMY,D7 D7:=RESULT:=STATUS,DUMMYFIED;
BRA.S ER_RTS GOTO RETURN;
*
ER_DAILL EQU * DATA_VALUE_ILLEGAL:
MOVE.L #ECRDATA,D7 D7:=RESULT:=DATA_VALUE_ILLEGAL;
BRA.S ER_RTS GOTO RETURN
*
ER_INUSE EQU * CHANNEL_IN_USE: ****** BAD ERROR CAUSE*******
MOVE.L #ECRCONC,D7 D7:=RESULT:=CONCURRENCY_VIOLATION;
BRA.S ER_RTS GOTO RETURN
*
ER_STATE EQU * OBJECT_STATE_ILLEGAL:
MOVE.L #ECRSTATE,D7 D7:=RESULT:=OBJECT_STATE_ILLEGAL;
* BRA.S ER_RTS GOTO RETURN;
*
ER_RTS EQU * RETURN
CMP.W D0,D0 CCR:=<EQ>; "RETURN TO CALLER"
RTS RETURN;
*
ER_VAILL EQU * POINTER_VALUE_ILLEGAL:
MOVE.L #ECRVALUE,D7 D7:=RESULT:=POINTER_VALUE_ILLEGAL
BRA.S ER_RTS GOTO RETURN;
*
ER_FUILL EQU * FUNCTION_ILLEGAL:
MOVE.L #ECRFUNC,D7 D7:=RESULT:=FUNCTION_ILLEGAL
BRA.S ER_RTS GOTO RETURN
*
ER_CAILL EQU * CAPABILITY_VIOLATION:
MOVE.L #ECRCAP,D7 D7:=RESULT:=CAPABILITY_VIOLATION;
BRA.S ER_RTS GOTO RETURN;
*
ER_NORES EQU * NO_RESOURSES:
MOVE.L #ECRNO_RES,D7 D7:=RESULT:=NO RESOURCES;
BRA.S ER_RTS GOTO RETURN;
*
ER_ADILL EQU * ADDRESS_ILLEGAL:
MOVE.L #ECRADDR,D7 D7:=RESULT:=ADDRESS ILLEGAL;
BRA.S ER_RTS GOTO RETURN;
*
ER_ARGMIS EQU * ARGUMENT_MISSING:
MOVE.L #ECRARGMIS,D7 D7:=RESULT:=ARGUMENT_MISSING
BRA.S ER_RTS GOTO RETURN;
*
ER_VAL3MIS EQU * VALUES_MISSING:
MOVEQ.L #3,D6 D6:= ARG# OF VALUE DATA ARGUMENT;
ER_VALMIS EQU * VALUE_MISSING: "D6=ARG# OF VALUE"
MOVE.L #ECRVALMIS,D7 D7:=RESULT:=VALUE_MISSING;
BRA.S ER_RTS GOTO RETURN;
PAGE
SCHEDENT EQU * ENTRY OF GENERAL OBJECT BEING A SCHEDULER OBJECT
* OBJ_CALL: OBJ_RETURN:
* D0 FUNCTION
* D2 (IMPLI)
* D3 #FORMALS
* D4 (INDEX)
* D5 (BYTES)
* D6 ANY RESULT
* D7 ANY RESULT
* A4 ANY RESTORED BY OBJ_RETURN
* A5 FTMP MOVED TO A4 IMMEDIATLY RESTORED BY OBJ_RETURN
* A6 TOPVAL RESTORED BY OBJ_RETURN
* A7 FIRST VAL
* THE ENTRY SITUATION IS THE NORMAL ENTRY SITUATION FOR CONTEXTS
* IN GENERAL OBJECTS
* THE SCHEDULER OBJECT "TYPES" ARE: INITIAL, NORMAL OR INTERRUPT.
* THE GENERAL SCHEDULER OBJECT IS CALLED TO CREATE VARIOUS OBJECTS.
* IT CALLS AN ALLOC OBJECT TO ALLOCATE AN OPEN OBJECT.
* A SPECIAL KERNEL DEFINED OBJECT, IS CALLED TO ASSIGN
* VALUES TO THE PROTECTED PARTS OF THE NEW OBJECT. THIS
* TRICK IS NEEDED BECAUSE THE GENERAL SCHEDULER OBJECT
* RUNS IN A PROTECTED ENVIRONMENT (LIKE ALL OTHER GENERAL OBJECTS).
*
* D0 CONTAINS THE FUNCTION CODE. THE FUNCTIONS ARE:
* 1: NEW_PROC (ÆR,PROCÅ; SIZE)
* 2: NEW_SCHD (ÆR,SCHDÅ,ÆC,ALLOCÅ)
* 3: NEW_GATE (ÆR,GATEÅ; LEVEL) LEVEL IS OPTIONAL
* 4: NEW_CHANNEL (ÆR,INT_PTÅ,ÆCODESEGMÅ; CHANNEL,LEVEL,STACK,ENTRY)
* 5: DEL_EXT
* -1: NOT USED
* -2: NOT USED
* -3: NEWSCOND (ÆR,CONDÅ,ÆC,GATEÅ)
* -4: NEWICHAN (ÆC,INT_PTÅ,ÆC,CODESEGMÅ,ÆC,ALLOCÅ; 4LONGS)
* -5: DELIEXT
* THE LOCAL POINTERS OF A GENERAL SCHEDULER OBJECT ARE USED AS FOLLOWS
*
* LOCAL-1, POINTS TO THE CODE SEGMENT CREATED DURING INITIALIZATION;
* LOCAL-2, INITIAL SCHEDULER: OWN_SET HOLDING STACK EXTENSION OBJECTS;
* OTHER SCHEDULERS: NIL
* LOCAL-3, REF_OBJ: POINTS TO ALLOC OBJECT
* LOCAL-4, REF_OBJ: POINTS TO DECL_DIV OBJECT
* LOCAL-5, INTERRUPT SCHEDULERS: REF_ENV TO INITIAL SCHEDULER;
* OTHER SCHEDULERS: NIL
* LOCAL-6, MAN_SET: SCHEDULERS CREATED BY THIS SCHEDULER,
*
* AFTER INITIALIZATION, THE INITIAL SCHEDULER EXISTS AND IS KNOWN
* BY ONE INTERRUPT SCHEDULER. A NORMAL SCHEDULER IS ALSO CREATED.
* THE "DECL_DIV OBJECT" IS KNOWN BY ALL THREE SCHEDULERS.
* THE STUB OBJECT ENTERED AFTER INITIALIZATION HOLDS A REFERENCE TO THE
* NORMAL SCHEDULER AND THE INTERRUPT SCHEDULER.
* DECL_DIV AND THE INITIAL SCHEDULER WILL NEVER BE KNOWN
* OUTSIDE THE SCHEDULER MODULE.
*
* THE CODE SEGMENT CORRESPONDS TO THE RUN_TIME SECTION OF
* THE SCHEDULER SOURCE. PROCEDURES OUTSIDE THIS SCOPE CANNOT
* BE CALLED.
PAGE
MOVEQ.L #2,D6 D6:=ARG# OF FUNCTION;
MOVE.L A5,A4 A4:= FTMP; "FIRST OF TEMP DATA STACK"
MOVE.L A7,A5 A5:= LOW_VALUE; "LOWEST VALUE ADDRESS"
* A6 DEFINES THE NEXT VALUE TO BE READ BY "NEXTNUMB", INITIALLY=TOP_VALUE
* !---SELFTEST---!
IF.L D0 <LT> #-5 OR.L D0 <GT> #5 THEN.S IF FUNCTION ILLEGAL THEN
BRA.L RE_FUILL GOTO FUNCTION_ILLEGAL;
ENDI ENDI;
ADDQ.W #5,D0 D0:=JMP:=(FUNCTION+5)
LSL.W #1,D0 *2;
CASEJMP D0 GOTO CASE JMP OF
CASELAB DELIEXT -5: DELIEXT "INITIAL SCHEDULER"
CASELAB NEWICHAN -4: NEWICHAN "INITIAL SCHEDULER"
CASELAB NEWSCOND -3: NEWSCOND
CASELAB RE_FUILL -2: RE_FUILL
CASELAB RE_FUILL -1: RE_FUILL
CASELAB RE_GIVEUP 0: RE_GIVEUP
CASELAB NEW_PROC +1: NEW_PROC
CASELAB NEW_SCHD +2: NEW_SCHD
CASELAB NEW_GATE +3: NEW_GATE
CASELAB NEW_CHAN +4: NEW_CHAN
CASELAB DEL_EXT +5: DEL_EXT
*
NEW_PROC EQU * CREATE NEW DORMANT PROCESS OBJECT
* CHECK THE CALL: #FORMALS MUST BE ONE, VALUE DATA MUST CONTAIN PROC_SIZE;
TST.W D3
BEQ.L RE_ARGMIS WHEN #FORMALS <1 GOTO ARGUMENT_MISSING(D3);
MOVE.L A6,D0
SUB.L A5,D0 D0:=VAL_SIZE:=TOP_VALUE-LOW_VALUE;
CMP.L #8,D0 TEST D0=VAL_SIZE -8;
BLT.L RE_VAL3MIS WHEN VAL_SIZE <8 GOTO VALUES_MISSING;
MOVEQ.L #0,D6 D6:= ARG# OF
SUBQ.B #1,D6 FIRST VALUE;
CMP.W #6,-(A6) TEST LENGTH OF FIRST VALUE PARAM;
BNE.L RE_DAILL WHEN LENGTH <> 6 THEN GOTO DATA VALUE ILL;
SUBQ.L #6,A6 A6:= FIRST ADDRESS OF FIRST VALUE PARAM;
MOVE.L (A6),D0 D0:= SIZE.USER_BYTES;
MOVE.W SZ_K(A6),D1 D1:= SIZE.KNEL_BYTES;
ADD.W #(PR_SIZ-OB_SIZ),D1 D1:= ... + ROOM FOR SCHEDULERS ENVELOPE;
* THE PROC_SIZE NOW INCLUDES ROOM FOR PROCESS DESCRIPTION ETC.
MOVE.L #A_LOCAL+3,D6 D6:=ALLOC_POINTER:=LOCAL-3;
MOVE.L #A_FORMAL+1,D2 D2:=FORMAL-1
BSR.L NEW_OPEN NEW_OPEN_OBJECT(D0/D1=SIZE,D2=/D6=PT_ADDR)
MOVEQ #1,D5 D5:=DECL_DORMANT:=1;
BSR.L DECL_DIV DECL_DORMANT(D6/D7:=RESULT);
BRA.L RETURNOP RETURN(D6/D7=RESULT);
PAGE
NEW_SCHD EQU * CREATE NEW SCHEDULER OBJECT
* CHECK THE CALL: #FORMALS MUST BE 2,
*
CMP.W #2,D3
BLT.L RE_ARGMIS WHEN #FORMALS<2 GOTO ARGUMENT_MISSING(D3);
CLR.L D0 D0:=USER_BYTES:=0;
MOVE.W #GE_SIZ-OB_SIZ+EN_SIZ+(PT_SIZ*6),D1
* D1:= KNEL BYTES FOR GENERAL OBJECT + A PRIMARY ENVELOPE + 6 LOCAL POINTERS;
MOVE.L #A_FORMAL+2,D6 D6:=ALLOC POINTER:=FORMAL-2;
MOVE.L #A_FORMAL+1,D2 D2:=OWNER_POINTER:=FORMAL-1;
BSR.L NEW_OPEN NEW_OPEN_OBJECT (D0/D1=SIZE,...
LEA D_GEN1F(PC),A0 A0:=
MOVE.L A0,D4 D4:=LOW_ARG
MOVE.L #D_GEN1T-D_GEN1F,D2 D2:=LENGTH OF ARG:=TOP_ARG-LOW_ARG;
MOVEQ #2,D5 D5:=DECL_GEN:=2;
TRAP #7 CALL THE KERNEL
TST.W D7 TEST RESULT
BNE.L RE_GIVEUP WHEN NOT OK GIVE_UP;
* TEMP-2 POINTS TO THE PRIMARY ENVELOPE; INITIALIZE LOCAL POINTERS;
* AND MAKE OBJECT REENTRANT;
CLR.L -(A7) PUSH ZERO TO SIGNAL END OF LIST;
MOVE.L #1,-(A7) STACK:=LIST
MOVE.L #4,-(A7) :=(#1,#4,#5);
MOVE.L #5,-(A7) .
MOVE.L #A_LOCAL,A6 A6:=DIRECT LOCAL; "CALLED SCHED"
MOVE.L #(A_TEMP+2)<<16,A5 A5:=INDIRECT TEMP-2; "CREATED SCHED"
MOVE.L #A_FORMAL+2-A_LOCAL,D0 FIRST_FROM:=FORMAL-2 "BAD TRICK"
MOVEQ #3,D1 FIRST_TO :=TEMP(2,3)
REPEAT REPEAT "SCAN LIST"
* D0 = D1 = INDEX OF POINTER TO COPY, EXCEPT WHEN THE LOOP IS ENTERED!!!
MOVE.L A7,D2 D2:=TOPARG
PEA (A6,D0.L) FIRST_ARG:=FROM:=LOCAL(INDEX);
PEA (A5,D1.L) SECOND ARG:=TO:=TEMP(2,INDEX);
MOVE.L A7,D4 D4:=LOWARG
MOVE.L D2,A7 A7:=TOPARG; "RESTORE A7"
SUB.L D4,D2 D2:=LENGTH:=TOPARG-FIRSTARG
MOVEQ #13,D5 D5:=COPY:=13;
TRAP #7 CALL KERNEL OPERATION;
MOVE.L (A7)+,D0 GET NEXT INDEX FROM THE LIST;
MOVE.L D0,D1
UNTIL <EQ> UNTIL END OF INDEX LIST;
*
MOVE.L A7,D3 D3:=TOPARG
MOVE.L #A_TEMP+2,-(A7) ARGUMENT:=TEMP-2; "REF TO PRIMENV"
MOVE.L A7,D4 D4:=LOWARG
MOVE.L D3,A7 A7:=TOPARG; "RESTORE A7"
SUB.L D4,D3 D3:=LENGTH:= TOPARG-LOWARG;
MOVE.L D3,D2 D2:=LENGTH;
MOVEQ #10,D5 D5:=MAKE_REENTRANT:=10;
TRAP #7 CALL KERNEL OPERATION
BRA.L RE_OK GOTO RETURN OK;
PAGE
* ARGUMENT LIST FOR DECL_GEN; USED BY NEW_SCHEDULER;
D_GEN1F EQU * LOWARG:
DC.W -1 OWNER HAS CALL_CAP;
DC.L 0 CALL STACK USER BYTES
DC.W 0 CALL STACK KNEL BYTES
DC.L SCHEDENT ENTRY ADDRESS ******** ONLY FOR RAM-KNEL.
DC.L 0 NO CONTROL PROCEDURE
DC.L SCHTEMD TEMP DATA STACK SIZE IN CTX
DC.L SCHTEMP-1 TEMP POINTERS IN CTX, EXCL. T(0)
DC.L -1 MAX_STACK
DC.W -1 = NONE
DC.L 0 DEALLOC_STACK
DC.W 0 = 0
DC.L 0 NO TERM PROCEDURE
DC.L 6 SIX LOCAL POINTERS
DC.L A_TEMP+2 REF_ENV RETURNED IN TEMP-2
DC.L A_LOCAL+6 MAN_SET=LOCAL-6
DC.L A_FORMAL+1 OPEN_OBJ=FORMAL-1;
D_GEN1T EQU * TOP OF ARGUMENT LIST
NEWSCOND EQU * CREATE NEW CONDITION
* THIS CALL IS A REDIRECTION OF A CALL TO A GATE OBJECT (NEWGCOND);
* TWO FORMALS WILL ALWAYS BE PRESENT
CLR.L D0 D0:=USER_BYTES:=0;
MOVE.W #CO_SIZ-OB_SIZ,D1 D1:=KNEL_BYTES:=COND_ENV_SIZE;
MOVE.L #A_LOCAL+3,D6 D6:=ALLOC-POINTER:=LOCAL-3;
MOVE.L #A_FORMAL+1,D2 D2:=FORMAL-1;
BSR.L NEW_OPEN NEW_OPEN_OBJECT(D0/D1=SIZE,D2/D6=PT_ADDR)
MOVEQ #2,D5 D5:=FUNCTION:=DECL_CONDITION:=2;
BSR.L DECL_DIV DECL_CONDITION(D6/D7:=RESULT);
BRA.L RETURNOP RETURN(D6/D7=RESULT);
NEW_GATE EQU * CREATE NEW GATE OBJECT
* CHECK THE CALL: #FORMALS=1; VALUE DATE MAY CONTAIN A LEVEL PARAMETER
CMP.W #1,D3
BLT.L RE_ARGMIS WHEN #FORMALS < 1 GOTO ARGUMENT_MISSING(D3)
CLR.L D0 D0:=USER_BYTES:=0
MOVE.W #GA_SIZ-OB_SIZ,D1 D1:=KNEL_BYTES:=GATE_SIZE;
MOVE.L #A_LOCAL+3,D6 D6:=ALLOC_POINTER:=LOCAL-3;
MOVE.L #A_FORMAL+1,D2 D2:=FORMAL-1
BSR.L NEW_OPEN NEW_OPEN_OBJECT(D0/D1=SIZE,D2/D6=PT_ADDR);
BSR.L NEXTNUMB NEXTNUMB(D0:=NUMBER,CCR:=RESULT,A6:=!);
* WHEN FORMAT ERROR D0 <= 0, WHICH IS ACCEPTABLE FOR DECLARE_NORMAL_GATE
* BUT NOT FOR DECLARE_DEVICE_GATE .
MOVE.L D0,-(A7) PUSH LEVEL ON THE STACK;
MOVEQ #3,D5 D5:=DECL_GATE:=3;
BSR.L DECL_DIV DECL_GATE((A7)=LEVEL,D6/D7:=RESULT);
BRA.L RETURNOP RETURN (D6/D7=RESULT);
PAGE
NEW_CHAN EQU * CREATE NEW DEVICE CHANNEL
* THE CALL IS PAST ON TO THE INITIAL SCHEDULER
* CHECK THE CALL AND CALL THE INITIAL SCHEDULER.
* TWO FORMALS AND FOUR NUMBERS ARE REQUIRED.
*
CMP.W #2,D3
BLT.L RE_ARGMIS WHEN #FORMALS <2 GOTO ARGUMENT_MISSING(D3);
* A6=NEXT_VAL=TOP_VAL; A5=LOW_VAL
MOVEQ.L #0,D6
FOR.W D2=#1 TO #4 DO.S DO FOUR TIMES
* NOTE THE ORDER OF THE FOUR INTEGERS IS REVERSED BY THIS COPY LOOP
SUBQ.B #1,D6 D6:=ARG# OF NEXT VALUE;
BSR.L NEXTNUMB D0:=NEXT NUMBER PARAMETER;A6:=NEXT_VAL;
BLT.L RE_DAILL WHEN ERROR GOTO DATA_VALUE_ILLEGAL;
BEQ.L RE_VALMIS WHEN NO_NEXT GOTO VALUE_MISSING;
MOVE.L D0,(A4)+ SAVE NUMBER IN FUTURE VALUE SEGMENT
ENDF ENDDO;
LEA OCALL_1F(PC),A0
MOVE.L A0,D4 D4:=LOWARG OF OBJ_CALL ARGUMENTS
MOVE.L #OCALL_1T-OCALL_1F,D2 D2:=LENGTH OF OBJ_CALL ARGUMENTS
* :=TOPARG-LOWARG;
MOVEQ #0,D5 D5:=OBJ_CALL:=0;
TRAP #7 CALL KERNEL (D6/D7:=RESULT);
IF.B D7 <EQ> #ECRVALUE AND.B D6 <EQ> #1 THEN.S
* IF FIRST POINTER ARGUMENT ILLEGAL THEN "LOCAL-5=NIL"
MOVE.W #ECRFUNC,D7 D7:=RESULT:=REJECTED,FUNCTION ILLEGAL;
ENDI ENDI;
BRA.L RETURNOP RETURN (D6/D7=RESULT);
* ARGUMENTS FOR CALLING THE NEWICHAN FUNCTION OF THE
* INITIAL INTERRUPT SCHEDULER.
* INITSCHED.NEWICHAN(4LONGS, ÆC,F(1)Å,ÆC,F(2)Å,ÆC,L(3)Å)
OCALL_1F EQU * LOWARG:
DC.L 0,0,$10000 CALL POINTER
DC.W A_LOCAL+3 ACTUAL-3=LOCAL-3=ALLOC OBJECT
DC.L 0,0,$10000 CALL POINTER
DC.W A_FORMAL+2 ACTUAL-2=FORMAL-2=CODE SEGMENT
DC.L 0,0,$10000 CALL POINTER
DC.W A_FORMAL+1 ACTUAL-1=FORMAL-1=LINK TO DRIVER POINTER;
DC.L 16,0 VALUE_DATA:=16,FIRST BYTES
DC.W 3 MUST BE READ+WRITE
DC.L A_TEMP+1 FROM TEMP-1 (THE STACK)
DC.L -4 FUNCTION CODE=NEWICHAN=-4
DC.L A_LOCAL+5 REF_ENVELOPE OR NIL IN LOCAL-5
OCALL_1T EQU *
PAGE
NEWICHAN EQU * NEW_CHANNEL, EXECUTED IN INITIAL SCHEDULER.
* CONCURRENT CALLS ARE NOT PREVENTED
*
MOVEQ #4,D5 D5:=DECL_CHANNEL:=4;
MOVE.L #0,-(A7) PUSH ZERO ON TOP OF VALUE DATA
BSR.S DECL_DIV DECL_CHANNEL(A7)=FIVE LONG INTEGERS,
* FORMAL-1 LINKS TO DRIVER POINTER,
* FORMAL-2 MUST BE A CODE SEGMENT,
* D6/D7:=RESULT);
* STACK EXTENSION IS NOT IMPLEMENTED AT PRESENT
* TST.W D7
* BEQ.L RE_OK WHEN OK GOTO RETURN_OK;
* CMP.W #ECRNO_REC,D7 NO_RESOURCES IS NOT AN ERROR;
* BNE.L RE_SAME WHEN ERROR GOTO RETURN_SAME;
* D6 = NEEDED STACKSPACE IN BYTES (AN INTEGRAL NUMBER OF PAGES)
* MOVE.L D6,(A7) SAVE A7 ON TOP OF VALUE DATA
* MOVE.L D6,D0 D0:=USER_BYTES:=NEEDED STACK SPACE
* MOVE.W #OB_SIZ+6+SP_SIZ,D1 D1:=KNEL_BYTES:=OPEN_OBJECT+6 BYTES
* MOVE.L #A_FORMAL+3,D6 D6:=ALLOC_POINTER:=FORMAL-3;
* MOVE.L #A_TEMP+2,D2 D2:=OWNER_POINTER:=TEMP-2 *
*
* BSR.S NEW_OPEN NEW_OPEN(D0/D1=SIZE,D2/D6=PT_ADDR);
* NEW_OPEN WILL ALWAYS RETURN
* MOVEQ #4,D5 D5:=DECL_CHANNEL:=4;
* BSR.S DECL_DIV DECL_CHANNEL((A7)=FIVE LONG INTEGER,
* FORMAL-1, FORMAL-2 AS BEFORE,
* TEMP-2= ALLOCATED OBJECT,
* D6/D7:=RESULT);
* IF RESULT=OK, THE OBJECT HAS BEEN MOVED FROM TEMP-1 TO LOCAL-2 AND
* THE DRIVER POINTER HAS BEEN CREATED IN THE LOCAL POINTER OF THE
* DRIVER OBJECT (FOUND AS THE ORIGINAL ACTUAL OF FORMAL-1).
*
BRA.L RETURNOP RETURN(D6/D7=RESULT)
PAGE
DEL_EXT EQU * DELETE SUPERVISOR STACK EXTENSIONS
* THE SUPERVISOR STACK MAY GROW WHEN NEW_CHANNEL IS CALLED.
* THE INSTALLED CHANNEL IS REMOVED WHEN THE ASSOCIATED
* DRIVER POINTER IS REMOVED (DEALLOC OR DEL_ENV), BUT THE
* SIZE OF THE SUPERVISOR STACK IS NOT AFFECTED. WHEN DEL_EXT IS CALLED,
* THE SCHEDULER IS ALLOWED TO RECOMPUTE THE SIZE OF THE
* SUPERVISOR STACK. IF IT IS TO BIG (CHANNEL HAVE BEEN REMOVED),
* SOME OF THE OBJECTS USED AS STACK EXTENSIONS ARE
* DEALLOCATED BY THE CALLING PROCESS.
* THE FUNCTION CAN ONLY BE EXECUTED BY THE INITIAL
* SCHEDULER. CALL DELIEXT TO PERFORM THE FUNCTION.
*
* NOT INPLEMENTED
BRA.L RE_FUILL
DELIEXT EQU * DELETE EXTENSIONS EXECUTED IN INITIAL SCHEDULER
* DECL_DIV.DEL_EXT IS CALLED. IT RETURNS AN OBJECT REFERENCE
* TO ONE OF THE EXTENSION OBJECTS. THE INITIAL SCHEDULER DEALLOCATES
* THE OBJECT FROM THE OWNER SET (LOCAL-2). DEALLOC MAY
* BE REJECTED BY THE KERNEL (THE OBJECT IS "DANGLING". IT WILL BE
* DELETED BY THE NEXT PROCESS CALLING DEL_EXT)
*
* NOT IMPLEMENTED
BRA.L RE_FUILL
* ALTERNATIVE: DECL_DIV.DEL_EXT MAY CHECK THE STACK REQUIREMENT,
* AND RETURN AN OWNER POINTER TO THE OBJECT INSTEAD OF A
* SIMPLE REFERENCE. IN THIS WAY THE OBJECT WILL NEVER ENTER THE
* "DANGLING" STATE.
PAGE
NEW_OPEN EQU * CREATE NEW OPEN OBJECT
* CALL: RETURN:
* D0/D1 SIZE UNDEF
* D2/D6 POINTER ADDRESSES TO OWNER_POINTER/ALLOC_POINTER
* A4 FTEMP SAME
* A5/A6 ANY SAME
* OTHER ANY UNDEF
* THE OBJECT IS CREATED BY THE ALLOC OBJECT OF D6
* D2 IS THE ADDRESS, OF THE FUTURE OWNER POINTER OF THE NEW OBJECT.
* IF THE RESULT OF ALLOC.NEW_OBJ <> OK THE ACTION DEPENDS ON
* D2 (SEE RE_ALILL)
* SET UP OBJ_CALL TO ALLOC ON THE STACK.
MOVE.W D2,-(A7) PUSH OWNER POINTER ADDRESS
MOVE.L A7,D3 D3:=TOPARG OF OBJ_CALL ARGUMENTS
MOVE.L D6,-(A7) OBJECT POINTER:=ALLOC-POINTER;
MOVE.L #1,-(A7) FUNCTION_NUMBER:=1; "NEW_OBJ"
MOVE.L #A_TEMP+1,-(A7) VALUE DATA IN STACK
MOVE.W #2+1,-(A7) READ+WRITE ALLOWED
CLR.L -(A7) STARTS IN FIRST BYTE OF STACK
MOVE.L #14,-(A7) LENGTH IS 14 BYTES
MOVE.L D2,-(A7) FIRST ACTUAL:=D2;
MOVE.W #2,-(A7) CALL/RETURN:=RETURN TO ACTUAL;
CLR.L -(A7) .
CLR.L -(A7) .
MOVE.L A7,D4 D4:=LOW.ARG OF OBJ_CALL ARGUMENTS
MOVE.L D3,A7 RESTORE STACK POINTER
SUB.L D4,D3 D3:=LENGTHARG:=TOPARG-LOWARG;
* SET UP VALUE DATA IN FIRST BYTES, OF TEMP DATA STACK (-A4).
MOVE.W #6,12(A4) LENGTH OF SIZE TYPE IS 12
MOVE.L D0,6(A4) USER BYTES, "CALL VALUE"
MOVE.W D1,6+SZ_K(A4) KNEL BYTES; "CALL VALUE"
MOVE.W #4,4(A4) LENGTH OF INTEGER TYPE IS 4
* CLR.L (A4) BYTES USED IS A RETURN VALUE;
MOVE.L D3,D2 LENGTH MUST BE IN D2;
MOVEQ #0,D5 D5:=OBJ_CALL:=0;
TRAP #7 CALL KERNEL (D6/D7:=RESULT);
TST.W D7
BNE.S RE_ALILL WHEN RESULT <> OK GOTO ALLOC_ILLEGAL ((A7))
ADDQ.L #2,A7 POP OWNER POINTER ADDRESS
RTS RETURN;
PAGE
DECL_DIV EQU * DECLARE A KERNEL DEFINED OBJECT
* CALL: RETURN:
* D5 FUNCTION UNDEF
* D6/D7 ANY RESULT
* A4,A5,A6 ANY SAME
* OTHER ANY UNDEF
* THE STACK MAY CONTAIN "SPECIAL PARAMETERS", AND THE POINTERS OF THE
* CURRENT CONTEXT MAY ALSO BE PARAMETERS TO THE KERNEL
* FUNCTION INVOKED VIA OBJ_CALL BELOW
*
MOVE.L A7,D3 D3:=TOPARG OF OBJ_CALL ARGUMENTS
MOVE.L #A_LOCAL+4,-(A7) OBJECT POINTER:=LOCAL-4; "DECL_DIV_OBJ"
MOVE.L D5,-(A7) FUNCTION NUMBER:=D5
CLR.L -(A7) VALUE DATA:=VOID;
CLR.W -(A7) .
CLR.L -(A7) .
CLR.L -(A7) .
MOVE.L A7,D4 D4:=LOWARG OF OBJ_CALL ARGUMENTS
MOVE.L D3,A7 RESTORE STACK POINTER;
SUB.L D4,D3 D3:=LENGTHARG:=TOPARG-LOWARG;
MOVE.L D3,D2 LENGTH MUST BE IN D2;
MOVEQ #0,D5 D5:=OBJ_CALL:=0;
TRAP #7 CALL KERNEL (D6/D7:=RESULT);
RTS RETURN;
PAGE
NEXTNUMB EQU * GET NEXT NUMBER PARAMETER AMONG THE VALUE DATA;
* CALL: RETURN
* D0 ANY NUMBER/0/-1/
* A5 LOW_VAL (FIRST ADDRESS) SAME
* A6 NEXT_VAL (TOP ADDRESS) NEXT_VALUE (UPDATED) / UNDEFINED
* CCR <EQ>: END OF VALUEDATA, <GT>: OK, <LT>: FORMAT ERROR => A6=?
IF.L A6 <EQ> A5 THEN.S IF.NEXT_VAL=LOW_VAL THEN
CLR.L D0 D0:=0;
RTS RETURN WITH CCR = <EQ>;
ENDI ENDI;
MOVE.W -(A6),D0 D0.L:=SIZE OF NEXT VALUE
SUB.W D0,A6 A6:=NEXT_VAL:=NEXT_VAL-SIZE;
CMPA.L A6,A5 TEST A5-A6 (=LOW_VAL-NEXT_VAL)
IF <GT> THEN.S IF LOW_VAL > NEXT_VAL THEN "FORMAT ERROR"
MOVEQ #-1,D0 D0:=-1;
RTS RETURN WITH CCR = <LT>;
ENDI ENDI;
* A6 POINTS TO FIRST OF CURRENT VALUE IN CASE SIZE WAS POSITIVE
IF.W D0 <EQ> #4 THEN.S IF SIZE = 4 THEN "LONG INTEGER"
MOVE.L (A6),D0 D0:=LONG INTEGER;
ELSE.S ELSE
IF.W D0 <EQ> #2 THEN.S IF SIZE = 2 THEN "WORD INTEGER"
MOVE.W (A6),D0 D0:=WORD INTEGER
EXT.L D0 D0:=SIGN EXTEND TO LONG
ELSE.S ELSE "NOT A NUMBER"
MOVEQ #-1,D0 CCR:=<LT>; NOT A NUMBER
RTS RETURN;
ENDI ENDI;
ENDI ENDI;
CMPA.W #0,A5 CCR:=<GT>; "OK"
RTS RETURN;
PAGE
* LABELS WITH "RE_" ARE USED IN THE NORMAL "CONTEXT" -ENVIRONMENT
RE_ALILL EQU * ALLOC_ILLEGAL: "***BAD TRICK BELOW"
IF.W (A7)+ <EQ> #A_TEMP+2 THEN.S IF CALLED FROM NEWICHAN THEN
* RETURN TO NEWICHAN: DECL_DIV MUST BE
RTS CALLED, ALTHOUGH ALLOC DID NOT WORK WELL;
ENDI ENDI;
* CONTINUE IN RE_SAME BELOW
*
RE_SAME EQU * RETURN_SAME:
BRA.S RETURNOP GOTO CALL_RETURN;
*
RE_GIVEUP EQU * GIVE_UP:
MOVE.L #ECSG_UP,D7 D7:=STATUS, GIVE_UP
BRA.S RETURNOP GORO CALL_RETURN;
*
RE_FUILL EQU * FUNCTION_ILLEGAL
MOVE.L #ECRFUNC,D7 D7:=REJECTED, FUNCTION ILLEGAL
BRA.S RETURNOP GOTO CALL_RETURN;
*
RE_DAILL EQU * DATA_VALUE_ILLEGAL
MOVE.L #ECRDATA,D7 D7:=REJECTED, DATA VALUE ILLEGAL
BRA.S RETURNOP GOTO CALL_RETURN;
*
RE_VAILL EQU * POINTER_VALUE_ILLEGAL
MOVE.L #ECRVALUE,D7 D7:=REJECTED, POINTER VALUE ILLEGAL;
BRA.S RETURNOP GOTO CALL_RETURN;
*
RE_ARGMIS EQU * ARGUMENT_MISSING: D3=NO OF FORMALS
MOVEQ.L #4,D6 D6:= ARG# OF FIRST FORMAL
ADD.B D3,D6 D6:= ARG# OF FIRST MISSING FORMAL
MOVE.L #ECRARGMIS,D7 D7:=RESULT:=ARGUMENT_MISSING;
BRA.S RETURNOP GOTO CALL_RETURN;
*
RE_VAL3MIS EQU * VALUES_MISSING:
MOVEQ.L #3,D6 D6:=ARG# OF VALUE DATA SEGM;
RE_VALMIS EQU * VALUE_MISSING: D6=ARG# OF VALUE
MOVE.L #ECRVALMIS,D7 D7:=RESULT:=VALUE_MISSING;
BRA.S RETURNOP GOTO CALL_RETURN;
*
RE_OK EQU * RETURN_OK
CLR.L D7 D7:=OK:=0;
*
RETURNOP EQU * CALL_RETURN:
* CALL:
* D6/D7 RESULT
* CALL THE KERNEL TO RETURN TO CALLING CONTEXT;
MOVEQ.L #1,D5 D5:=RETURN:=1;
TRAP #7 CALL THE KERNEL;
PAGE
INT_SIGN EQU * INTERRUPT SIGNAL OPERATION
* CALL RETURN
* D2/D4 LENGTH ARG/LOW ARG UNDEF
* A4 ANY RESTORED FROM STACK
* A5 ANY RESTORED FROM STACK
* A6 ANY RESTORED FROM STACK
* D4 LOWARG ADDR UNDEF
* D6/D7 ARG#/ANY RESULT
* STACK: A4-A6,SR,PC. NO RETURN POINT ON STACK.
* OTHER REGISTERS ARE UNDEFINED AT RETURN
*
* INT_SIGN IS A KERNEL OPERATION. IT IS USED BY AN INTERRUPT
* PROCEDURE TO SIGNAL A CONDITION. A SUSPENDED RESIDENT CONTEXT
* MAY BE SCHEDULED AS A RESULT OF THIS OPERATION.
*
BSR.L CR_INCTX A2:=INT_CTX,D3:=RES_LOCK REQUIRED:=-1;
* A4:=ARGUMENT ADDRESS;
BEQ.S II_RETURN WHEN NOT OK GOTO RETURN_RESULT;
BSR.L C_ENTRES CHECK_ENTRES(A5:=ENTITY,D5:=ENT.KIND,...
BEQ.S II_RETURN WHEN NOT OK GOTO RETURN_RESULT;
IF.B D5 <NE> #PT_OBJ THEN.S IF ENTITY KIND <> OBJECT THEN
MOVE.L #ECRVALUE,D7 D7:=RESULT:=POINTER_VALUE_ILLEGAL
ELSE.S ELSE "ENTITY KIND = OBJECT"
IF.B OB_KIN(A5) <NE> #OB_COOB THEN.S IF OBJECT <> CONDITION THEN
DUMMYCOND EQU * REJECT_SIG:
MOVE.L #ECRSTATE,D7 D7:=RESULT:=OBJECT_STATE_ILLEGAL;
ELSE.S ELSE "OBJECT IS A CONDITION"
PRT_MEM INT_SIGN,(A5),CO_SIZ ********
MOVE.L A5,A1 A1:=CONDITION;
MOVE.L CO_GA(A1),A5 A5:=GATE MANAGING THE CONDITION;
MOVE.L A5,D7 TEST A5 INTO D7 "GATE=0 <=> DUMMYFIED"
BEQ.S DUMMYCOND WHEN DUMMYFIED CONDITION GOTO REJECT_SIG;
MOVE.B 12(A7),D7 D7:= SUPV BYTE OF CALLER
AND.W #7,D7 D7:=INTERRUPT_LEVEL OF CALLER "INT_PROC"
IF.B D7 <NE> GA_LEV(A5) THEN.S IF INTERRUPT_LEVEL <> GATE.LEVEL THEN
MOVE.L #ECRFUNC,D7 D7:=REJECT,FUNCTION ILLEGAL;
RTS RETURN
ELSE.S ELSE
BSR.L CONDSIGN CONDSIGN (A5=GATE,A1=COND,D7=LEVEL);
*
ENDI ENDI;
ENDI ENDI;
ENDI ENDI;
II_RETURN EQU * RETURN_RESULT:
BRA.L RET_FAST RETURN TO CALLER;
PAGE
NIOBEGIN EQU * IO_BEGIN FROM NORMAL CONTEXT
*
MOVEQ.L #-2,D3 D3:=RES_LOCK REQUIRED:=-2;
BRA.S IO_BEGIN GOTO IO_BEGIN
IIOBEGIN EQU * IO_BEGIN CALLED FROM INTERRUPT PROCEDURE
*
BSR.L CR_INCTX A2:=INT_CTX,D3:=RES_LOCK REQUIRED:=-1;
BEQ.S II_RETURN WHEN ERROR GOTO RETURN_RESULT;
* CONTINUE IN IO_BEGIN
*
RIOBEGIN EQU * IO_BEGIN CALLED FROM RESIDENT CONTEXT (D3<>0);
*
IO_BEGIN EQU * SET IO_LOCK ON POINTER AND UPDATE IO_COUNT ON SEGMENTS
* CALL RETURN TO CALLING CONTEXT.
* A1 ANY ADDRESS OF SEGMENT DATA
* A2 CUR_CTX OR INT_CTX UNDEF
* A4 ARGUMENT ADDR(PHYS) RESTORED FROM STACK
* A5 ANY RESTORED FROM STACK
* A6 ANY RESTORED FROM STACK
* D3 RESIDENT LOCK REQUIRED! LENGTH OF SEGMENT DATA
* D4 LOWARG ADDR. UNDEF
* D5 ANY USE_BITS OF SEGMENT OBJECT
* D6/D7 ARG#/ANY RESULT
* STACK: SAVED A4-A6,SR,PC
* OTHER REGISTERS ARE UNDEFINED AT RETURN;
*
* IO_BEGIN IS A KERNEL OPERATION. IT IS USED TO KEEP THE SEGMENT DATA OF
* A RESIDENT SEGMENT ON THE SAME PHYSICAL LOCATION DURING A
* DMA-TRANSPORT TO/FROM THE SEGMENT.
* D3 WILL ALWAYS BE NON ZERO (RESIDENT LOCK IS REQUIRED)
*
*
*
*
BSR.S PTANDSEG CHK_POINTER_&_SEGM(A6:=PT,A5:=STRUCT,...
IF <NE> THEN.S
BSET.B #PT_IO,PT_INF(A6) POINTER.IO_LOCK:=ON;
IF <EQ> THEN.S IF LOCK WAS OFF THEN "ADJUST IO_COUNT"
ADDQ.W #1,ST_IO(A5) CTX/ENV.IO_COUNT:=...+1;
MOVEQ #1,D0 D0:=INCREASE:=+1;
MOVE.W #SE_IO,D1 D1:=IO_COUNT;
BSR.L INCRDECR INCREASE(D0/D1/A6=!,A6/A3:=?);
ENDI ENDI;
CLR.L D7 RESULT:=OK;
ENDI ENDI;
BRA.L RET_FAST RETURN TO CALLER
PAGE
NIO_END EQU * IO_END CALLED FROM NORMAL CONTEXT
*
MOVEQ.L #-2,D3 D3:=RES_LOCK REQUIRED:=-2;
BRA.S IO_END GOTO IO_END;
IIO_END EQU * IO_END CALLED FROM INTERRUPT PROCEDURE
*
BSR.L CR_INCTX A2:=INT_CTX,D3:=RES_LOCK REQUIRED:=-1;
BEQ.S II_RETURN WHEN ERROR GOTO RETURN_RESULT;
* CONTINUE IN IO_END
RIO_END EQU * IO_END CALLED FROM RESIDENT CONTEXT (D3<>0);
*
IO_END EQU * RESET IO_LOCK ON POINTER AND ADJUST IO_COUNT ON SEGMENTS
*
* CALL AND RETURN AS FOR IO_BEGIN
* IO_END IS A KERNEL OPERATION
* IT SIGNALS THE END OF A DMA-TRANSPORT.
*
BSR.S PTANDSEG CHK_POINTER_&_SEG(A6:=PT,A5:=STRUCT,...
IF <NE> THEN.S IF OK THEN
BCLR.B #PT_IO,PT_INF(A6) POINTER.IO_LOCK:=OFF
IF <NE> THEN.S IF LOCK WAS ON THEN "ADJUST IO_COUNT"
SUBQ.W #1,ST_IO(A5) CTX/ENV.IO_COUNT:=...-1;
MOVEQ #-1,D0 D0:=DECREASE:=-1;
MOVE.W #SE_IO,D1 D1:=IO_COUNT;
BSR.L INCRDECR DECREASE(D0/D1/A6=!,A6/A3:=?);
ENDI ENDI;
CLR.L D7 RESULT:=OK;
ENDI ENDI;
BRA.L RET_FAST RETURN TO CALLER;
PAGE
IABSADDR EQU * ABS_ADDR CALLED FROM INTERRUPT PROCEDURE
BSR.S CR_INCTX A2:= INT_CTX, D3:=RES_LOCK REQUIRED:=-1;
BEQ.S II_RETURN WHEN ERROR GOTO RETURN_RESULT;
*
NABSADDR EQU * ABS_ADDR CALLED FROM NORMAL CONTEXT (D3=0)
*
RABSADDR EQU * ABS_ADDR CALLED FROM RESIDENT CONTEXT (D3<>0)
*
ABS_ADDR EQU * GET PHYSICAL ADDRESS OF RESIDENT SEGMENT;
*
* CALL AND RETURN AS FOR IO_BEGIN
* ABS_ADDR IS A KERNEL OPERATION
* ABS_ADDR IS USED BY THE INTERRUPT PROCEDURES, TO GET THE PHYSICAL
* ADDRESS OF SEGMENT DATA. THE ADDRESS MAY CHANGE BETWEEN
* TWO "CALLS" TO THE INTERRUPT PROCEDURE; BUT IS CONSTANT
* WHILE THE INTERRUPT PROCEDURE IS RUNNING, BECAUSE THE SEGMENT IS RESIDENT.
BSR.S PTANDSEG CHECK POINTER AND SEGMENT (......
IF <NE> THEN.S IF OK THEN
CLR.L D7 RESULT:=OK
ENDI ENDI
BRA.L RET_FAST RETURN TO CALLER;
*
* NOTE: THE FUNCTION MAY BE CALLED FROM A CONTEXT, BUT THE
* ADDRESS RETURNED MAY CHANGE WITHOUT NOTICE.
PAGE
PTANDSEG EQU * CHECK POINTER AND SEGMENT
* CALL: RETURN:
* A1 ANY SEGMENT DATA
* A2 CUR_CTX OR INT_CTX SAME
* A3 ANY SEGMENT OBJECT
* A4 ARGUMENT ADDRESS SAME (UPDATED ONCE)
* A5 ANY POINTER STRUCTURE (CTX/ENV)
* A6 ANY POINTER TO SEGMENT OBJECT
* D1/D2 ANY POINTER REL/POINTER KIND
* D3 RESIDENT LOCK REQUIRED? LENGTH OF SEGMENT DATA
* D4/D5 ANY UNDEF/USE-BITS OF SEGMENT OBJECT
* D6/D7 ARG#/ANY RESULT WHEN CCR = <EQ>
* CCR <EQ>: NOT OK; <NE>: OK
* A2 MUST CONTAIN CUR_CTX OR INT_CTX. C_ENTRES IS USED TO CHECK THE POINTER ARG
* D3 <> 0: RESIDENT LOCK MUST BE "ON" IN THE POINTER
* A CALL TO C_SEGM IS MADE TO CHECK THAT A SEGMENT IS "POINTED".
*
BSR.L C_ENTRES CHK_ENTRES(A6:=PT,D5:=ENTITY_KIND,
* A1:=PT_STRUCT,A5=ENTITY,...
IF <NE> THEN.S IF OK THEN
MOVE.L A5,A3 A3:= ENTITY; HOPEFULLY AN OBJECT;
MOVEA.L A1,A5 A5:= POINTER STRUCTURE;
CMP.B #PT_OBJ,D5 TEST ENTITY KIND;
BEQ.S C_SEGMPS WHEN ENTITY IS AN OBJECT GOTO CHK_SEGM;
ENDI ENDI;
RTS RETURN WITH CCR=<EQ>:NOT_OK;
C_SEGM EQU * CHECK THAT THE ARGUMENT IS A SEGMENT OBJECT
* CALL: RETURN:
* A1/A3 ANY SEGMENT DATA/SEGMENT OBJECT
* A6 POINTER (MUST BE SIMPLE) SAME
* D2 POINTER KIND SAME
* D3 ANY LENGTH OF SEGMENT DATA
* D5 ANY USE BITS OF SEGMENT OBJECT
* D6/D7 ARG#/UNDEF RESULT WHEN CCR = <EQ>
* CCR <EQ>: NOT OK; <NE>: OK
* ATTRIBUTES OF THE SEGMENT OBJECT IS RETURNED IN A1,D3 AND D5
*
IF.B D2 <EQ> #PT_OBJ THEN.S IF POINTER_KIND=REF_OBJ THEN
MOVE.L PT_REF(A6),A3 A3:=SEGMENT OBJECT
C_SEGMPS EQU * ENTRY FROM PTANDSEGM.
IF.B OB_KIN(A3) <EQ> #OB_SEOB THEN.S IF OBJECT.KIND=SEGMENT THEN
MOVE.L SE_FIR(A3),A1 A1:=ADDRESS OF SEGMENT DATA
MOVE.L SE_LEN(A3),D3 D3:=LENGTH OF SEGMENT DATA;
MOVE.B OB_STA(A3),D5 D5:=USE BITS (B0=R,B1=W,B2=E)
LSR.B #OB_READ,D5 :=OBJECT.STATE>>OB_READ;
IF <NE> THEN.S IF USE_BITS <> 0 THEN
RTS RETURN; CCR=<NE>:OK;
ENDI ENDI;
MOVE.L #ECRCAP,D7 D7:= CAPABILITY VIOLATION; "NO USE BITS"
ELSE.S ELSE "NOT A SEGMENT OBJECT"
MOVE.L #ECRSTATE,D7 D7:=RESULT:=OBJECT_STATE ILLEGAL
ENDI ENDI
ELSE.S ELSE
MOVE.L #ECRVALUE,D7 D7:=RESULT:=POINTER_VALUE ILLEGAL
ENDI ENDI
CMP.W D0,D0 CCR:=<EQ>;
RTS RETURN; "NOT OK"
PAGE
CR_INCTX EQU * CREATE INTERRUPT CONTEXT
* CALL: RETURN
* A1 ANY UNDEF
* A2 ANY INTERRUPT CONTEXT
* A4 ANY ARG ADDRESS
* D2 LENGTH ARGUMENT SAME
* D3 ANY -1 <=> RESIDENT LOCKS REQUIRED
* D4 LOWARG SAME
* D6/D7 ARG#/ANY RESULT WHEN CCR = <EQ>
* CCR <EQ>: NOT OK; <NE>: OK
* AT RETURN A2 CONTAINS THE ADDRESS OF A "CONTEXT". IT HAS NO
* FORMAL OR TEMP POINTERS, BUT "THE LOCAL POINTERS OF THE CONTEXT"
* ARE THE LOCAL POINTERS OF THE DRIVER.
* THE DRIVER ENVELOPE HOLDING THE LOCAL POINTERS IS DETERMINED
* FROM THE CHANNEL ARGUMENT IN THE CALL TO THE KERNEL OPERATION.
* ARG ADDRESS IS COMPUTED. NO ADDRESS CONVERSION IS NEEDED BECAUSE
* THE CALLING INTERRUPT PROCEDURE RUNS IN SUPERVISOR MODE (NO MMU INVOLVED)
*
MOVE.L D4,A4 A4:= ARGUMENT ADDRESS:= LOWARG
ADDA.L D2,A4 + LENGTH ARG;
LEA -AR_PTSIZ-1(A4),A1 A1:=ADDRESS OF CHANNEL ARGUMENT;
IF.L D4 <LE> A1 THEN.S IF CHANNEL ARG PRESENT THEN
CLR.W D3
MOVE.B (A1),D3 D3:=CHANNEL#; "0..255"
LSL.W #2,D3 D3:=CHANNEL INDEX:=CHANNEL# *4;
LEA DRIV_TAB,A1 A1:=DRIVER_TABLE;
LEA INT_CTX,A2 A2:=INTERRUPT_CONTEXT;
MOVE.L (A1,D3.W),(A2) CONTEXT.ENVELOPE:=DRIVER_TABLE(CHANNEL);
PRT_MEM CR_INCTX,(A2),ST_SIZ+2 ********
IF <NE> THEN.S IF ENVELOPE IS DEFINED THEN
MOVEQ #-1,D3 D3:=RES_LOCK REQUIRED:=-1;
RTS RETURN; CCR = <NE>:OK;
ENDI ENDI;
ENDI ENDI;
MOVE.L #ECRDATA,D7 D7:= CHANNEL# ILLEGAL
MOVEQ.L #2,D6 D6:= ARG# OF CHANNEL#:=2;
CMP.W D0,D0 CCR:=<EQ>:NOT_OK;
RTS RETURN;
PAGE
GATE_OBJ EQU * CALLABLE GATE OBJECT FUNCTIONS
*
* GATE_OBJ IS A "CASE-BLOCK" OF PROCEDURE C_CALL; IT IS ENTERED
* WHEN A GATE OBJECT IS CALLED VIA OBJ_CALL
* OPEN/LOCK/RESBEGIN NEW_COND
* CALL RETURN RETURN;
* D3 RESIDENT CALLER UNDEF UNDEF
* D4 LOW_ARG UNDEF SCHEDULER LOW_ARG
* D5 FUNCTION UNDEF NEWSCOND = -3
* D6/D7 ARG#/ANY ARG#/RESULT ARG#/UNDEF
* A0/A2 EXTENSION/CUR_CTX SAME SAME
* A1 ANY, USED FOR PROC ADDR. UNDEF UNDEF
* A4 ARG UNDEF SCHEDULER ARG
* A5 GATE UNDEF SCHEDULER OBJ
* A3/A6 ANY UNDEF UNDEF
* CCR ANY <EQ>:RETURN <NE>:CALL,EXCEPT WHEN
* STACK: RETURN_PC,A4,A5,A6,SR,PC SR MAY BE MODIFIED ERR.
* THE FOLLOWING FUNCTIONS APPEAR:
* 1: LOCK
* 2: OPEN
* 3: NEW_COND (ÆR,CONDÅ)
* 4: RESBEGIN (USE,Æ?,SIMPELÅ); "SIMPEL POINTER TO ENV OR OBJECT"
PRT_MEM GATE_OBJ,(A5),GA_SIZ ********
LSL.W #1,D5 D5:=FUNC:=FUNCTION *2;
CMP.W #8,D5 TEST FUNCTION
BGT.L ER_FUILL WHEN FUNCTION >4 GOTO FUNCTION_ILLEGAL;
MOVE.L KV_PROC,A1 A1:= CURRENT PROCESS;
PRT_MEM PROCESS,(A1),PR_SIZ ********
MOVE.B GA_LEV(A5),D7 D7:=LEVEL:=GATE.LEVEL;
IF <EQ> THEN.S IF LEVEL = 0 THEN "NORMAL GATE"
TST.W D3 TEST RESIDENT_CALLER;
BNE.L ER_FUILL WHEN RESIDENT CALLER THEN GOTO FUNCTION_ILLE
CASEJMP D5 GOTO CASE D5=FUNC(:=SPOILED) OF
CASELAB CASE_ERR 0<<1: NOT POSSIBLE;
CASELAB GATELOCK 1<<1: GATELOCK;
CASELAB GATEOPEN 2<<1: GATEOPEN;
CASELAB NEWGCOND 3<<1: NEWGCOND;
CASELAB ER_FUILL 4<<1: FUNCTION_ILLEGAL;
ENDI ENDI;
IF.W D5 <NE> #2*2 THEN.S IF FUNCTION <> DEVICE_OPEN THEN
TST.W D3 TEST RESIDENT_CALLER;
BNE.L ER_FUILL WHEN RESIDENT CALLER GOTO FUNCTION ILLEGAL;
ELSE.S ELSE "FUNCTION=DEVICE_OPEN"
TST.W D3 TEST RESIDENT_CALLER;
BEQ.L ER_FUILL WHEN NOT RESIDENT GOTO FUNCTION ILLEGAL;
BSR.L CHECKLEV IS A CORRECT "LEVELED" GATE OPENED ?
IF <EQ> THEN.S IF WRONG LEVEL THEN
RTS RETURN;
ENDI ENDI;
ENDI ENDI;
CASEJMP D5 GOTO CASE D5=FUNC(:=SPOILED) OF
CASELAB CASE_ERR 0<<1: NOT POSSIBLE
CASELAB DEVILOCK 1<<1: DEVILOCK
CASELAB DEVIOPEN 2<<1: DEVIOPEN
CASELAB NEWGCOND 3<<1: NEWGCOND
CASELAB RESBEGIN 4<<1: RESBEGIN
PAGE
GATELOCK EQU * LOCK NORMAL GATE
BSR.L SPEEDCHK IF SPEEDUP PROPAGATES INTO GATE
BNE.L ER_RTS THEN GOTO RETURN;
TAS.B GA_STA(A5) TEST FOR OPEN, AND LOCK GATE;
IF <PL> THEN.S IF GATE WAS OPEN THEN
CLR.L D7 D7:=RESULT:=OK; CCR:=RETURN:=<EQ>;
RTS RETURN;
ENDI ENDI;
LEA GA_LOK(A5),A3 A3:=LOCK_QUEUE OF GATE
REM_ELEM PR_AUX(A1),A5,A6,A5/A6 REMOVE CURRENT PROC FROM RUNNING QUEUE;
INIT_HEAD PR_AUX(A1),A6 .
MOVE.B #6,PR_STA(A1) PROC.STATE:= LOCK;
CLR.W PR_SYN(A1) PROC.SYNC_RESULT:= OK;
LEA PR_MAIN(A1),A1 A1:= PROC.MAIN;
REM_ELEM (A1),A5,A6,A5/A6 REMOVE CURRENT PROC FROM TIMER QUEUE;
INS_ELEM A3,A1,A6,A3/A6 INSERT PROC IN LOCK_QUEUE OF GATE;
BRA.L SYNCSTOP GOTO STOP AND WAIT FOR OPEN GATE;
* RETURN DIRECTLY TO CALLER WHEN PROC IS RESUMED
DEVILOCK EQU * LOCK DEVICE GATE
BSR.L SPEEDCHK IF SPEEDUP PROPAGATES INTO GATE
BNE.L ER_RTS THEN GOTO RETURN;
REM_ELEM PR_AUX(A1),A3,A6,A3/A6 REMOVE CALLING PROC FROM RUNNING QUEUE;
INIT_HEAD PR_AUX(A1),A6 .
BTST.B #5,16(A7) TEST SUPERVISOR BIT IN SR OF CALLING PROC
IF <NE> THEN.S IF SUPV_BIT ON THEN "CLEAR STOP_RUN REQUEST
MOVE.L SAVE_PC,18(A7) RESTORE PC;
MOVE.W SAVE_SR,16(A7) RESTORE SR;
ENDI ENDI;
OR.B D7,16(A7) STACK(SR).INT_MASK:= GATE_LEVEL;
MOVEQ #1,D0 D0:=INCREASE;
BSR.L SETRESET SETRESET(A2:=CTX,D1/D5/A3/A6:=UNDEF)
LSL.B #4,D7 D7:=PRIO:=LEVEL<<4 +1;
ADDQ #1,D7
LEA PR_MAIN(A1),A1 A1:=PROC.MAIN;
REM_ELEM (A1),A3,A6,A3/A6 REMOVE PROC FROM TIMER QUEUE;
BSR.L QDRIV QUEUE TO DRIVING(D7,A1,A3/A6:=?)
* PROC.STATE REMAINS UNCHANGED (=RUN=0).
* PROCS WITH HIGHER LEVELS MAY BE WAITING (TIMED OUT) IN DRIVING QUEUE.
MOVEQ #0,D7 D7:=RESULT:=OK; CCR:=RETURN := <EQ>;
RTS RETURN;
SPEEDCHK EQU *
* CALL: RETURN:
* A2 CUR_CTX SAME
* D5 - UNDEF
* D7 - RESULT OR SAME
* CCR - <NE>: SPEEDUP PRESENT, <EQ>: NO SPEEDUP
*
MOVE.B CT_SPE(A2),D5
AND.B CT_MODE(A2),D5 D5:=MINIMUM(SPEEDUP_SATE,PROP_MODE);
IF <NE> THEN.S IF SPEEDUP PRESENT THEN
MOVE.L #ECRSPEED,D7 D7:= RESULT:= SPEEDED UP; CCR:=<NE>;
ENDI ENDI;
RTS RETURN;
PAGE
GATEOPEN EQU * OPEN NORMAL GATE
* CALLED ALSO FROM COND.WAIT
* A5=GATE, A1/A3/A4/A6:=?, D7:=RESULT, CCR=<EQ>:NOT_OK OR CCR=<NE>:OK
* SELECT A WAITING PROCESS OR OPEN THE GATE
* PROCESS SELECTION FOLLOWS THE RULE SHOWN BELOW
LEA GA_RELOK(A5),A3 A3:=RELOCKING QUEUE OF GATE OBJECT;
MOVE.L (A3),A1 A1:=MAIN_QUEUE OF FIRST RELOCKING PROCESS;
IF.L A1 <EQ> A3 THEN.S IF NO RELOCKING PROCESSES THEN
LEA GA_SPLOK(A5),A3 A3:=SPEED RELOCKING QUEUE OF GATE OBJECT;
MOVE.L (A3),A1 A1:=MAIN_QUEUE OF FIRST SPEED RELOCKING;
IF.L A1 <EQ> A3 THEN.S IF NO SPEED RELOCKING PROCESSES THEN
LEA GA_LOK(A5),A3 A3:=LOCKING QUEUE OF GATE OBJECT
MOVE.L (A3),A1 A1:=MAIN_QUEUE OF FIRST LOCKING PROCESS;
IF.L A1 <EQ> A3 THEN.S IF NO LOCKING PROCESSES THEN "OPEN THE GATE"
CLR.B GA_STA(A5) GATE.STATE:=OPEN;
CLR.L D7 D7:=RESULT:=OK;CCR:=RETURN:=<EQ>;
RTS RETURN;
ENDI ENDI;
ELSE.S ELSE "SPEED RELOCKING WAS PRESENT"
REM_ELEM PR_AUX-PR_MAIN(A1),A4,A6,A4/A6 REMOVE PROC.AUX FROM COND QUEUE;
ENDI ENDI;
ENDI ENDI;
* A1 = MAIN QUEUE OF SELECTED PROCESS;
REM_ELEM (A1),A4,A6,A4/A6 REMOVE PROC FROM THE GATE QUEUE;
MOVE.L A1,(A1)
MOVE.L A1,4(A1) MAIN_QUEUE OF PROCESS:=EMPTY;
LEA PR_AUX-PR_MAIN(A1),A3 A3:=AUX_QUEUE OF PROCESS;
LEA RUNNING,A1 A1:=RUNNING QUEUE;
INS_ELEM A1,A3,A6,A1/A6 INSERT PROC IN RUNNING QUEUE;
CLR.B PR_STA-PR_AUX(A3) PROC.STATE:=RUN:=0;
PRT_MEM GATEOPEN,-PR_AUX(A3),PR_SIZ ********
CLR.L D7 D7:=RESULT:=OK; CCR:=RETURN:=<EQ>;
RTS RETURN;
PAGE
FORCE_OPEN EQU * OPEN UNKNOWN DEVICE GATE
* A2=CURRENT CONTEXT, RETURNS THROUGH SYNCSTOP(A0/A1/A2/A3/D7:=!).
* STACK MUST CONTAIN (RETURN_PC,A4,A5,A6,SR,PC) WHEN THE CALL IS MADE.
* FORCE_OPEN IS CALLED WHEN RETURN IS EXECUTED BY A RESIDENT CONTEXT.
* CHECKLEV CANNOT BE CALLED BECAUSE THE GATE IS UNKNOWN.
*
MOVE.L KV_PROC,A1 A1:= CURRENT PROCESS;
PRT_MEM FORCE_OPEN,(A1),PR_SIZ ********
* CONTINUE IN DEVIOPEN BELOW
DEVIOPEN EQU * OPEN DEVICEGATE
* THE GATE OBJECT IS NOT SEARCHED FOR WAITING PROCESSES. THESE
* PROCESSES WILL ALREADY BE PRESENT IN THE DRIVING QUEUE
* NEXT TO CALLING PROCESS. (GA_STA OF THE DECIVE GATE IS NOT USED).
* CALLING PROCESS IS MOVED FROM THE DRIVING QUEUE TO THE
* RUNNING QUEUE;
*
MOVEQ #-1,D0 D0:=DECREASE;
BSR.L SETRESET SETRESET(A2=CTX,D1/D5/A3/A6:=UNDEF)
LEA PR_MAIN(A1),A1 A1:= PROC.MAIN;
REM_ELEM (A1),A3,A6,A3/A6 REMOVE PROC.MAIN FROM DRIVING;
MOVE.L A1,(A1) PROC.MAIN
MOVE.L A1,4(A1) :=EMPTY;
LEA PR_AUX-PR_MAIN(A1),A1 A1:=PROC.AUX;
LEA RUNNING,A3 A3:=RUNNING QUEUE;
INS_ELEM A3,A1,A6,A3/A6 INSERT PROC.AUX IN RUNNING QUEUE;
CLR.B PR_PRI-PR_AUX(A1) PROC.PRIO:=0;
LEA -PR_AUX(A1),A1 A1:=PROCESS
ANDI.B #$F8,16(A7) STACK(SR).INT_MASK:=0;
CLR.W PR_SYN(A1) PROC.SYNC_RESULT:=OK:=0;
BRA.L SYNCSTOP STOP PROC AND RUN DRIVING PROCS
* RETURN IS MADE DIRECTLY TO THE CALLER
PAGE
NEWGCOND EQU * CREATE NEW CONDITION OBJECT
* A NEW CONDITION MANAGED BY THE CALLED GATE OBJECT
* SHOULD BE CREATED. THE CALL IS REDIRECTED TO THE SCHEDULER
* THAT CREATED THE GATE OBJECT. THE SCHEDULER WILL CREATE
* THE CONDITION.
MOVEQ.L #4,D6 D6:=ARG# OF 1. ACTUAL;
LEA -ACT_SIZ<<1(A4),A1 TEST #REMAINING ARGUMENTS > = 2;
CMPA.L D4,A1 TEST (ARG-(2*ACT_SIZ)-LOWARG;
BLT.L ER_ARGMIS WHEN REMAIN < 2 GOTO ARGUMENT_MISSING;
MOVEQ.L #2,D6 D6:=ARG# OF FUNCTION; EXPECTED BY OBJCALL
LEA SCHD_ARG,A3 A3:=ADDRESS OF ACTUALS; (GLOBAL KNEL_VAR)
MOVE.L -(A4),-(A3) COPY VALUE DATA ARGUMENT
MOVE.L -(A4),-(A3) AND THE FIRST ACTUAL ARGUMENT.
MOVE.L -(A4),-(A3) .
MOVE.L -(A4),-(A3) .
MOVE.L -(A4),-(A3) .
MOVE.L -(A4),-(A3) .
MOVE.L -(A4),-(A3) .
LEA 4+ACT_SIZ+ACT_SIZ(A4),A4 A4:=POINTER ARGUMENT POINTING TO GATE
MOVE.L (A4),-(A3) COPY POINTER ADDRESS TO ACTUAL -2
MOVE.W #1,-(A3) CALL/RETURN:=CALL
CLR.L -(A3) THE SECOND ACTUAL IS
CLR.L -(A3) A POINTER ACTUAL;
LEA SCHD_ARG,A4 A4:=NEW ARGUMENT LIST;
PRT_MEM NEWGCOND,-3*ACT_SIZ(A4),3*ACT_SIZ ********
MOVE.L A3,D4 ADJUST LOWARG;
TST.W GA_SCH+PT_KIN(A5) TEST KIND OF POINTER TO SCHEDULER
BEQ.L ER_DUMMY WHEN NIL_POINTER GOTO UNDEF, DUMMYFIED;
MOVE.L GA_SCH+CH_HOLD(A5),A5 A5:=ADDRESS OF SCHEDULER OBJECT;
MOVEQ.L #-3,D5 D5:=FUNCTION:=NEWSCOND:=-3;CCR:=<NE>;
RTS RETURN; DO CALL SCHEDULER
* NOTE THAT A GATE IS NOT DUMMYFIED BECAUSE ITS SCHEDULER IS DELETED
* NOTE ALSO THAT THE POINTER ARGUMENT THAT ADRESSES THE GATE OBJECT IS READ
* TWICE. FIRST IN PROC OBJ_CALL, AND NOW IN THE PROC ABOVE. THE KERNAL MUST
* NOT ENABLE INTERRUPTS IN BETWEEN, BECAUSE PROCESSES SCHEDULED THROUGH
* INTERRUPTS COULD MODIFY THE POINTER ARGUMENT. IT MAY STILL BE MODIFIED
* THROUGH A DMA-CHANNEL, AND THIS WILL CREATE A PROBLEM TO THE USER IF THE
* MODIFIED ARGUMENT ADDRESSES A POINTER TO ANOTHER GATE.
PAGE
RESBEGIN EQU * SET RESIDENT LOCK ON, AND UPDATE RESIDENT COUNTS
* VALUE DATA SPECIFIES "REQUIRED USE BITS". FIRST ACTUAL IS A
* SIMPLE POINTER TO A SEGMENT OBJECT. USE BITS OF THE SEGMENT MUST
* INCLUDE "REQUIRED USE BITS".
MOVEQ.L #4,D6 D6:=ARG# OF 1. ACTUAL;
LEA -ACT_SIZ<<1(A4),A1 TEST #REMAINING ARGUMENTS >=2;
CMPA.L D4,A1 TEST (ARG-(2*ACT_SIZE)) -LOW_ARG;
BLT.L ER_ARGMIS WHEN REMAIN < 2 GOTO ARGUMENT_MISSING;
TST.W -2(A4) TEST FOR VOID VALUE DATA
IF <EQ> THEN.S IF VOID VALUE DATA THEN
CLR.L D0 D0:=REQUIRED:=NO_BITS:=0;
LEA -ACT_SIZ(A4),A4 A4:=NEXT ARGUMENT
ELSE.S ELSE
MOVEQ.L #2,D6 D6:= ARG#;
BSR.L C_SUB CHECK_SUB(A5:=BSEG,D5:=FREL,D2:=LENGTH,..
IF <EQ> THEN.S IF NOT_OK THEN
RTS RETURN;
ENDI ENDI;
* SHOULD USE-BITS BE CHECKED ???
MOVE.L SE_FIR(A5),A5 A5:=FIRST OF BASE SEGMENT DATA
ADDA.L D5,A5 A5:=FIRST VALUE:=FIRST DATA + FREL;
MOVE.W A5,D5 BIT0 OF D5 := ODD VALUE SEGM:=
OR.B D2,D5 (BIT0 OF FIRST) OR (BIT0 OF LENGTH);
BTST.L #0,D5
BNE.L ER_ADILL WHEN ODD VALUE SEGM GOTO ADDRESS ILLEGAL
LEA (A5,D2.L),A6 A6:=TOP_VALUE:=FIRST_VALUE+LENGTH;
MOVEQ.L #0,D6 D6:= ARG# OF
SUBQ.B #1,D6 FIRST VALUE;
BSR.L NEXTNUMB NEXTNUMB(A5/A6=!,D0:=32 BITS INTEGER);
BLE.L ER_DAILL WHEN ERROR GOTO DATA_VALUE_ILLEGAL;
ENDI ENDI;
MOVEQ.L #4,D6 D6:=ARG# OF 1. ACTUAL;
PAGE
* D0 = REQUIRED USE-BITS, A4 = NEXT ARGUMENT, A5=UNDEF, D6=ARG#
BSR.L C_PT CHECK_POINTER(A6:=PT,D2:=PT_KIND,...
IF <EQ> THEN.S IF NOT OK THEN
RTS RETURN;
ENDI ENDI;
IF.B D2 <EQ> #PT_OBJ THEN.S IF POINTER = REF_OBJ THEN
MOVE.W #OB_RES,D1 D1:=ADDR:=RESIDENT COUNT OF OBJECT
BSR.L C_SEGM CHECK_SEGM(A1:=DATA,A3:=OBJECT,D5:=USE,..
IF <NE> THEN.S IF OBJ = SEGMENT THEN.S
AND.B D0,D5 D5:=REQUIRED AND USE
IF.B D0 <EQ> D5 THEN.S IF REQUIRED BITS WERE PRESENT IN USE THEN
BSET.B #PT_RES,PT_INF(A6) POINTER.RESIDENT_LOCK:=ON;
IF <EQ> THEN.S IF LOCK WAS OFF THEN
MOVEQ. #1,D0 D0:=INCRESES:=+1;
BSR.S INCRDECR INCREASE RESIDENT COUNT OF SEGM OBJECTS
ENDI ENDI;
CLR.L D7 D7:=RESULT:=OK; CCR:=<EQ>;
RTS RETURN;
ENDI ENDI; "USE-BITS WAS OK"
BRA.L ER_CAILL GOTO CAPABILITY_VIOLATION;
ENDI ENDI; "OBJ = SEGMENT"
ELSE.S ELSE "POINTER <> REF_OBJ"
CMP.B #PT_ENV,D2 TEST POINTER KIND
BNE.L ER_VAILL WHEN POINTER <> REF_ENV GOTO
* POINTER_VALUE_ILLEGAL;
MOVE.L PT_REF(A6),A3 A3:=ENVELOPE
MOVE.W #EN_RES,D1 D1:=ADDR:=RESIDENT COUNT OF ENVELOPE;
ENDI ENDI;
* A6=POINTER, A3=ENTITY (NON_SEGM_OBJ OR ENV), D1=ADDR OF RES_COUNT IN ENTITY.
BSET.B #PT_RES,PT_INF(A6) POINTER.RESIDENT_LOCK:=ON;
IF <EQ> THEN.S IF LOCK WAS OFF THEN
ADDQ.W #1,(A3,D1.W) ENTITY.RES_COUNT:=...+1;
PRT_MEM RESBEGIN,(A3),ST_SIZ ********
ENDI ENDI;
CLR.L D7 D7:=RESULT:=OK; CCR:=<EQ>;
RTS RETURN;
PAGE
SETRESET EQU * ADJUST RESIDENT COUNTS FOR RESIDENT CONTEXT
* CALL RETURN
* A2 CTX (TOP_CTX OF DRIVING PROC) SAME
* D0 +1(INCREASE) OR -1(DECREASE) SAME
* D1/D5/A3/A6 UNDEF
* 1 IN/DECREASE RESIDENT COUNT OF THE CONTEXT (FROM ZERO TO ONE)
* 2 IN/DECREASE RESIDENT COUNT OF PRIMARY ENVELOPE OF CURRENT OBJECT
* 3 IN/DECREASE RESIDENT COUNT OF SEGMENTS MAPPED IN THE MMUS OF CTX
*
ADD.W D0,CT_RES(A2) CTX.RES_COUNT:=...+/-1;
MOVE.L CT_OBJ(A2),D1 D1:=CUR_OBJ:=CTX.CT_OBJ;
IF <NE> THEN.S IF CTX NOT ABORTED THEN
MOVE.L D1,A3 A3:=CUR_OBJ;
MOVE.L OB_SPA(A3),A3 A3:=TOP_OBJ;
MOVE.L SP_ENV+4(A3),A3 A3:=PRIM_ENV OF OBJECT;
ADD.W D0,EN_RES(A3) ENV.RES_COUNT:=...+/-1;
ENDI ENDI;
MOVE.W #OB_RES,D1 D1:=COUNT ADDRESS:=OB_RES;
FOR.W D5=#CT_MM0 TO #CT_MM3 BY #MM_SIZ DO.S FOR ALL MMU_DESCR DO
LEA (A2,D5.W),A6 A6:=MMU-POINTER; PT_REF(A6)=0 OR SEGM;
BSR.S INCRDECR INCRDECR (D0=+1/-1,D1=OB_RES,A6=MMU,.
ENDF ENDF;
RTS RETURN;
INCRDECR EQU * INCREASE OR DECREASE COUNT IN SEGMENT OBJECTS
* CALL: RETURN:
* D0.W +1(INCREASE) OR -1 (DECREASE) SAME
* D1.W OB_RES OR SE_IO SAME
* A3 ANY UNDEF
* A6 POINTER UNDEF
* PT_REF(A6) MUST BE ZERO OR POINT TO A SEGMENT OBJECT;
*
REPEAT REPEAT
MOVE.L PT_REF(A6),A3 A3:=SEGMENT OBJECT
CMP.W #0,A3 TEST A3.L=0
IF <EQ> THEN.S IF NO SEGMENT OBJECT THEN
RTS RETURN; "ROOT SEGM NOT REACHED"
ENDI ENDI;
ADD.W D0,(A3,D1.W) INCREASE/DECREASE COUNT
IF <EQ> THEN.S IF COUNT DECREASED TO ZERO THEN
IF.W D1 <EQ> #SE_IO THEN.S IF IO_COUNT DECREASED TO ZERO THEN
MOVEM.L A1/A4/A5,-(A7) SAVE REGISTERS;
LEA SE_WAIT(A3),A1 A1:=WAIT QUEUE OF SEGMENT
REPEAT REPEAT
BSR.L KNELSIGN SIGNAL THE FIRST WAITING PROC
UNTIL <NE> UNTIL NO MORE WAITING PROCS
MOVEM.L (A7)+,A1/A4/A5 RESTORE REGISTERS;
ENDI ENDI;
ENDI ENDI;
PRT_MEM INCRDECR,(A3),SU_SIZ ********
LEA SU_P(A3),A6 A6:=POINTER TO NEXT SEGMENT
BTST.B #OB_SUB,OB_STA(A3) TEST SEGMENT KIND;
UNTIL <EQ> UNTIL SEGMENT.KIND = ROOT SEGM;
RTS RETURN;
PAGE
QDRIV EQU * QUEUE PROC IN THE DRIVING QUEUE
* CALL RETURN:
* A1 MAIN QUEUE OF PROC SAME
* D7 PRIO OF PROC SAME
* A3/A6 ANY UNDEF
* PRIO=LEVEL<<4 + 1/0 1:RELOCKING(SIGNALED)/0:OTHER
* THE PROC IS PLACED IN THE DRIVING QUEUE AFTER THE LAST
* PROCESS P WHERE P.PRIO >= D7.
*
MOVE.B D7,PR_PRI-PR_MAIN(A1) PROC.PRIO:=PRIO=D7;
LEA DRIVING,A6 A6:=DRIVING QUEUE;
MOVE.L (A6),A3 A3:=CUR_PROC:=FIRST DRIVING PROC;
WHILE.L A6 <NE> A3 DO.S WHILE MORE DRIVING PROCS DO
IF.B PR_PRI-PR_MAIN(A3) <LT> D7 THEN.S IF CUR_PROC.PRIO < PRIO THEN
MOVE.L A3,A6 "A6:=NO MORE PROCS"
ELSE.S ELSE
MOVE.L (A3),A3 A3:=CUR_PROC:=NEXT PROC;
ENDI ENDI;
ENDW ENDW;
INS_ELEM A3,A1,A6,A3/A6 QUEUE PROC.MAIN TO DRIVING QUEUE;
PRT_MEM QDRIV,-PR_MAIN(A1),PR_SIZ ********
* PROC.STATE IS ASSIGNED BY THE CALLER OF QDRIV.
RTS RETURN;
PAGE
COND_OBJ EQU * CALLABLE CONDITION OBJECT FUNCTIONS
*
* COND_OBJ IS A "CASE_BLOCK" OF PROCEDURE C_CALL; IT IS ENTERED
* WHEN A COND OBJECT IS CALLED VIA OBJ_CALL.
*
* CALL: RETURN:
* D3 RESIDENT CTX (WHEN<>0) UNDEF
* D5 FUNCTION UNDEF
* D6/D7 ARG#/ANY ARG#/RESULT
* A0 EXTENSION SAME
* A2 CUR_CTX SAME
* A4 ARG UNDEF
* A5 OBJECT=CONDITION UNDEF
* OTHER ANY UNDEF
* CCR ANY <EQ>
*
PRT_MEM COND_OBJ,(A5),CO_SIZ ********
MOVE.L A5,A1 A1:=COND;
LSL.W #1,D5 D5:=FUNCTION:=FUNCTION * 2;
* CHECK FOR A TIMEOUT PARAMETER
IF.W D5 <EQ> #1*2 THEN.S IF FUNCTION = WAIT THEN
TST.W -2(A4) TEST NEXT ACTUAL
IF <EQ> THEN.S IF VOID ACTUAL THEN
CLR.L D0 DO/D1:=NO_TIMEOUT :=0;
CLR.L D1 .
ELSE.S ELSE "GET SUBSEGMENT DESCRIPTION"
MOVEM.L D5/A5,-(A7) SAVE D5/A5;
BSR.L C_SUB C_SUB(A5,D0,D2,D5:=...
MOVEM.L (A7)+,D1/A1 RESTORE D5 INTO D1; A1:=COND; "A7=OK";
IF <EQ> THEN.S IF NOT_OK THEN
RTS RETURN;
ENDI ENDI;
MOVE.L SE_FIR(A5),A5 A5:=ADDRESS OF VALUE DATA:=
ADDA.L D5,A5 BASE SEGMENT DATA + FIRST_REL;
CMP.L #10,D2 TEST D5-10=LENGTH-10
BLT.L ER_VAL3MIS WHEN LENGTH <10 GOTO VALUES_MISSING;
MOVE.W A5,D5 BIT0 OF D5:= ODD VALUE SEGM:=
OR.B D2,D5 (BIT0 OF FIRST) OR (BIT0 OF LENGTH);
BTST.L #0,D5
BNE.L ER_ADILL WHEN ODD VALUE SEGM GOTO ADDRESS ILLEGAL;
MOVE.L D1,D5 RESTORE D5 (=FUNC*2) FROM D1;
MOVEQ.L #0,D6 D6:=ARG# OF
SUBQ.B #1,D6 FIRST VALUE;
LEA (A5,D2.L),A6 A6:= TOP_VAL;
CMP.W #8,-(A6) TEST LENGTH OF FIRST VALUE
BNE.L ER_DAILL WHEN LENGTH<>8 GOT DATA VALUE ILLEGAL;
MOVE.L -(A6),D1 D1:=BIT31..0 OF TIMEOUT
MOVE.L -(A6),D0 D0:=BIT63..32 OF TIMEOUT
BLT.L ER_DAILL WHEN <0 GOTO DATA_VALUE ILLEGAL;
ENDI ENDI; "VOID ACTUAL"
ENDI ENDI; "FUNC<>WAIT "
* A1=COND
MOVEQ.L #1,D6 D6:= ARG# OF CALLED CONDITION:=1;
MOVE.L CO_GA(A1),A5 A5:=GATE MANAGING THE CONDITION;
MOVE.L A5,D7 A7:= TEST A5=0;
BEQ.L ER_STATE WHEN COND TERMINATED GOTO OBJECT_STATE_ILL
ADDQ.L #1,D6 D6:=ARG# OF FUNCTION ARGUMENT:=2;
CMP.W #4,D5
BGT.L ER_FUILL WHEN FUNCTION*2>4 GOTO FUNCTION_ILL;
PAGE
MOVE.B GA_LEV(A5),D7 D7:=GATE.LEVEL
BNE.S DEVICOND WHEN GATE.LEVEL > 0 GOTO DEVICE_CONDITION;
* NORMAL CONDITION OBJECT
TST.W D3 TEST CALLER
BNE.L ER_FUILL WHEN RESIDENT GOTO FUNCTION_ILLEGAL
* CHECK THAT THE MANAGING GATE IS LOCKED
BTST.B #7,GA_STA(A5)
BEQ.L ER_STATE WHEN GATE OPEN GOTO OBJ_STATE_ILLEGAL;
CASEJMP D5 GOTO CASE D5=FUNCTION(:=SPOILED) OF
CASELAB CASE_ERR 0<<1: NOT POSSIBLE
CASELAB CONDWAIT 1<<1: CONDWAIT
CASELAB CONDSIGN 2<<1: CONDSIGN
DEVICOND EQU * DEVICE CONDITION OBJECT
TST.W D3 TEST CALLER
BEQ.L ER_FUILL WHEN NOT RESIDENT GOTO FUNCTION ILLEGAL
* CHECK THAT THE DEVICE GATE IS LOCKED
MOVE.L A1,A4 A4:= SAVE A1
MOVE.L KV_PROC,A1 A1:= CURRENT PROCESS
PRT_MEM PROCESS,(A1),PR_SIZ ********
BSR.L CHECKLEV CHECKLEV(A1=PROC,D7=LEVEL,D3:=UNDEF);
IF <EQ> THEN.S IF NOT_OK THEN
RTS RETURN;"FUNCTION ILLEGAL"
ENDI ENDI;
MOVE.L A4,A1 A1:= RESTORE COND FROM A4;
CASEJMP D5 GOTO CASE D5=FUNCTION (:=SPOILED) OF
CASELAB CASE_ERR 0<<1: NOT POSSIBLE
CASELAB DEVIWAIT 1<<1: DEVIWAIT
CASELAB CONDSIGN 2<<1: CONDSIGN
PAGE
CONDWAIT EQU * WAIT ON NORMAL CONDITION, A5=GATE, A1=COND
BSR.L SPEEDCHK IF SPEEDUP PROPAGATES INTO CONDITION
BNE.L ER_RTS THEN GOTO RETURN;
MOVE.L A1,D5 D5:= SAVE COND ADDR;
BSR.L GATEOPEN GATEOPEN(A5=GATE,A1/A3/A4/A6:=?);
MOVE.L D5,A5 A5:= SAVED COND ADDR;
MOVE.L KV_PROC,A1 A1:=CURRENT_PROCESS
PRT_MEM PROCESS,(A1),PR_SIZ ********
REM_ELEM PR_AUX(A1),A0,A6,A0/A6 REMOVE PROC FROM RUNNING QUEU
MOVEQ #2,D7 D7:=STATE:=WAIT:=2
BRA.S WAITWAIT GOTO WAIT_ON_CONDITION:
DEVIWAIT EQU * WAIT ON DEVICE CONDITION, A5=GATE, A1=COND
BSR.L SPEEDCHK IF SPEEDUP PROPAGATES INTO CONDITION
BNE.L ER_RTS THEN GOTO RETURN;
MOVE.L A1,A5 A5:=COND;
MOVE.L KV_PROC,A1 A1:=CURRENT PROCESS;
MOVEQ #4,D7 D7:=STATE:=DWAIT:=4;
WAITWAIT EQU * WAIT ON CONDITION:
* D0/D1=#USEC,A1=PROC,A2=CTX,A5=CONDITION
* D7:=STATE,
REM_ELEM PR_MAIN(A1),A0,A6,A0/A6 REMOVE PROC FROM TIMEOUT OR DRIVI
TST.L D0
BNE.S YES_TIMO
TST.L D1
IF <NE> THEN.S IF TIME OUT ON THE WAIT OPERATION THEN
YES_TIMO EQU *
MOVE.L A5,A3 A3:= SAVED COND ADDR
BSR.L TWAIT PROC.MAIN:=TIMER_QUEUE(D0-D5/A4-A6:=?)
MOVE.L A3,A5 A5:= SAVED COND ADDR
ELSE.S ELSE "TIME OUT NOT SPECIFIED"
INIT_HEAD PR_MAIN(A1),A6 PROC.MAIN:=EMPTY;
ENDI ENDI; "TIME_OUT"
* A1=PROC,A2=CTX,A5=CONDITION,D7=STATE
LEA CO_WAIT(A5),A0 A0:=WAIT QUEUE; "OF CONDITION"
LEA PR_AUX(A1),A3 A3:=AUX QUEUE OF PROCESS
INS_ELEM A0,A3,A6,A0/A6 CHAIN PROC TO WAIT QUEUE
MOVE.L A5,PR_CON(A1) PROC.COND:=CONDITION;
MOVE.B D7,PR_STA(A1) PROC.STATE:=STATE "2 OR 4"
* PROC.SYNC_RESULT IS NOT ASSIGNED;
BRA.L SYNCSTOP WAIT UNTIL SIGNAL OR ...
* RETURN IS MADE DIRECTLY TO THE CALLER WITH A0/A1/A2/A3/D7 ASSIGNED
PAGE
CONDSIGN EQU * SIGNAL NORMAL/DEVI_COND ,OR INTERRUPT_SIGNAL DEVI_COND.
* D7 = LEVEL, A1 = COND, A5=GATE
LEA CO_WAIT(A1),A4 A4:=WAIT QUEUE OF CONDITION;
MOVE.L (A4),A3 A3:=FIRST PROC WAITING;
IF.L A3 <EQ> A4 THEN.S IF NO PROCS WAITING THEN
CLR.L D7 D7:=OK; CCR:=<EQ>;
RTS RETURN;
ENDI ENDI;
* A3 = AUX_QUEUE OF PROCESS TO BE SIGNALED, D7 = LEVEL
REM_ELEM (A3),A4,A6,A4/A6 REMOVE PROC FROM WAIT QUEUE OF COND;
MOVE.L A3,(A3) AUX_QUEUE OF PROC
MOVE.L A3,4(A3) := EMPTY;
CLR.W PR_SYN-PR_AUX(A3) PROC.SYNC_RESULT:=OK;
LEA PR_MAIN-PR_AUX(A3),A3 A3:=MAIN QUEUE OF PROCESS
* PROC MAY BE IN THE TIMER QUEUE, THE DRIVING QUEUE, OR IN A SPEED_RELOCK QUEUE
REM_ELEM (A3),A4,A6,A4/A6 REMOVE PROC FROM THE QUEUE
* REM_ELEM DOES NOT HARM, WHEN MAIN QUEUE IS EMPTY;
TST.B D7 TEST LEVEL
IF <EQ> THEN.S IF NORMAL CONDITION SIGNAL THEN
MOVE.B #8,PR_STA-PR_MAIN(A3) PROC.STATE:= SIGNALED;
LEA GA_RELOK(A5),A5 A5:=RELOCK QUEUE OF GATE
INS_ELEM A5,A3,A6,A5/A6 QUEUE PROC.MAIN TO RELOCK
ELSE.S ELSE "DEVICE CONDITION SIGNAL"
LSL.B #4,D7 D7:=PRIO:=LEVEL<<4+1;
ADDQ.B #1,D7 QUEUE PROC.MAIN INTO DRIVING QUEUE:
MOVE.L A3,A1 A1:= PROC.MAIN;
BSR.L QDRIV QDRIV(A1=MAIN,D7=PRIO,A3/A6:=UNDEF);
CLR.B PR_STA-PR_MAIN(A1) PROC.STATE:= RUN;
ENDI
CLR.L D7 D7:=OK; CCR:=<EQ>
RTS RETURN;
CHECKLEV EQU * CHECK PRIO OF PROCESS AGAINST DEVICE-LEVEL
* CALL RETURN
* D7 LEVEL OF DEVICE > 0 SAME
* A1 PROCESS SAME
* D3 ANY UNDEF
* CCR=<NE>:OK WHEN DEVICE.LEVEL=PROC.LEVEL, OTHERWISE CCR=<EQ>:NOT_OK
*
MOVE.B PR_PRI(A1),D3 D3:=PROC.PRIO
LSR.B #4,D3 D3:=LEVEL OF PROCESS
IF.B D3 <NE> D7 THEN.S IF LEVEL OF PROCESS <> DEVICE_LEVEL THEN
MOVE.L #ECRSTATE,D7 D7:=RESULT:=REJECTED,OBJ_STATE ILLEGAL;
CMP.W D0,D0 CCR:=<EQ>:NOT_OK;
ELSE.S ELSE
TST.B D7 CCR:=<NE>:OK;
ENDI ENDI;
RTS RETURN;
PAGE
TERMGATE EQU * TERMINATE GATE OBJECT
* CALL RETURN:
* A0 GATE SAME
*
* RETURN ALL PROCESSES WAITING ON GATE OR MANAGED CONDITIONS TO RUNNING QUEUE
*
ENTRYSAV D0/A0/A1/A3/A5/A6,.TERMGAT
PRT_MEM TERMGATE,(A0),GA_SIZ ********
* PROCS WILL ONLY BE WAITING IN QUEUES OF A NORMAL GATE.
MOVE.W #ECSDUMMY,D0 D0:=RESULT:=STATUS,DUMMYFIED;
FOR.W D5=#GA_LOK TO #GA_SPLOK BY #CH_SIZ DO.S FOR ALL LOCKING QUEUE DO
LEA (A0,D5.W),A5 A5:=SOME LOCKING QUEUE;
WHILE.L (A5) <NE> A5 DO.S WHILE PROCS IN LOCKING QUEUE DO
MOVE.L (A5),A1 A1:=PROC.MAIN OF FIRST PROC IN QUEUE;
LEA -PR_MAIN(A1),A1 A1:=PROCESS;
BSR.L SPED_RUN SPEDRUN(A1=PROC,D0=RESULT,A3/A6:=UNDEF);
ENDW ENDW;
ENDF EDNF;
LEA GA_SET(A0),A5 A5:=MANAGED CONDITIONS;
WHILE.L (A5) <NE> A5 DO.S WHILE MORE CONDITIONS DO
MOVE.L (A5),A0 A0:=COND.CO_MAN;
LEA -CO_MAN(A0),A0 A0:=CONDITION;
BSR.S TERMCOND TERMCOND(A0=CONDITION);
ENDW ENDW;
REM_ELEM GA_SCH-GA_SET(A5),A3,A6,A3/A6 UNCHAIN POINTER TO SCHEDULER;
INIT_HEAD GA_SCH-GA_SET(A5),A6 INIT_HEAD IS NICE, BUT NOT REALY NEEDED
RETURN .TERMGAT RETURN;
TERMCOND EQU * ABORT CONDITION AND "CONTEXTS" IN THE CONDITION
* CALL RETURN:
* A0 CONDITION SAME
*
* RETURN ALL PROC WAITING ON CONDITION, TO THE RUNNING QUEUE
ENTRYSAV D0/D7/A1/A3/A5/A6,.TERMCON
PRT_MEM TERMCOND,(A0),CO_SIZ ********
REM_ELEM CO_MAN(A0),A3,A6,A3/A6 REMOVE COND FROM MANAGING GATE
INIT_HEAD CO_MAN(A0),A6
CLR.L CO_GA(A0) COND.MANAGING_GATE:=0;"CONDITION ABORTED"
LEA CO_WAIT(A0),A5 A5:=COND.WAIT QUEUE
WHILE.L (A5) <NE> A5 DO.S WHILE PROCS IN WAITING QUEUE DO
MOVE.L (A5),A1 A1:=PROC.AUX OF WAITING PROC;
LEA -PR_AUX(A1),A1 A1:=PROCESS;
IF.B PR_STA(A1) <EQ> #4 THEN.S IF PROCES WAITING IN DEVI.WAIT THEN
MOVE.W #ECRDUMMY,D0 D0:=RESULT:=REJECT,DUMMYFIED;
BSR.L SPEDDEVI SPEDDEVI(A1=PROC,D0=RES,D7/A3/A6:=?);
REM_ELEM PR_AUX(A1),A3,A6,A3/A6 REMOVE PROC FROM CONDITION QUEUE;
INIT_HEAD PR_AUX(A1),A6 THE CONDITION CANNOT BE SIGNALED ANYMORE.
CLR.B PR_STA(A1) PROC.STATE:= RUN; "SIGNAL NOT POSSIBLE"
ELSE.S ELSE PROCESS WAITING IN NORMAL WAIT
MOVE.W #ECSDUMMY,D0 D0:=RESULT:=STATUS,DUMMYFIED;
BSR.L SPED_RUN SPED_RUN(A1=PROC,D0=RESULT,A3/A6:=UNDEF);
* PROC HAS BEEN REMOVED FROM THE CONDITION QUEUE BY SPED_RUN.
ENDI ENDI;
ENDW ENDW;
RETURN .TERMCON RETURN;
PAGE
PROPSPED EQU * PROPOGATE SPEEDUP INTO GATE OR CONDITION OBJECT
* CALL RETURN
* D0.B 1=REJECT,3=UNDEF UNDEFINED
* A1 PROCESS SAME
* D7/A3/A6 ANY UNDEFINED
*
MOVEQ.L #0,D7
MOVE.B PR_STA(A1),D7 D7.W:=PROC.STATE;
IF <EQ> THEN.S IF PROC.STATE = RUN THEN
RTS RETURN;
ENDI ENDI;
IF.B D7 <EQ> #6 OR.B D7 <EQ> #4 THEN.S
* IF PROC.STATE = LOCK OR STATE = DEVI.WAIT THEN
MOVEQ.L #1,D0 D0:=REJECT;
ENDI ENDI;
SUBQ.B #1,D0 TEST IF D0.B=UNDEF
IF <NE> THEN.S IF UNDEF THEN
MOVE.W #ECSSPEEDUP,D0 D0:=RESULT:=STATUS,SPEEDUP;
BRA.L SPED_RUN GOTO SPED_RUN(A1=PROC,D0=RESULT,A3/A6:=?);
ENDI ENDI;
* OPERATION RETURNS REJECT,SPEEDUP.
MOVE.W #ECRSPEEDUP,D0 D0:=RESULT:=REJECT,SPEEDUP;
CASEJMP D7 GOTO CASE D7 = STATE OF
CASELAB CASE_ERR 0: NOT POSSIBLE
CASELAB SPEDWAIT 2: SPEDWAIT
CASELAB SPEDDEVI 4: SPEDDEVI
CASELAB SPED_RUN 6: SPED_RUN "=SPEDLOCK"
CASELAB SPEDSIGN 8: SPEDSIGN
SPEDSIGN EQU * SPEEDUP SIGNALED PROCESS
RTS RETURN; "DO NOTHING"
SPEDWAIT EQU * SPEED UP PROCESS WAITING ON NORMAL CONDITION;
MOVE.W D0,PR_SYN(A1) PROC.SYNC_RESULT:=RESULT;
REM_ELEM PR_MAIN(A1),A3,A6,A3/A6 REMOVE PROC.MAIN FROM "SOME" QUEUE
MOVE.L PR_CON(A1),A3 A3:=CONDITION;
MOVE.L CO_GA(A3),A6 A6:=GATE MANAGING CONDITION;
* A3/A6 CANNOT BE ZERO
TAS.B GA_STA(A6) LOCK THE GATE
IF <EQ> THEN.S IF GATE WAS OPEN THEN
INIT_HEAD PR_MAIN(A1),A6 PROC.MAIN:=EMPTY
REM_ELEM PR_AUX(A1),A3,A6,A3/A6 REMOVE PROC FROM CONDITION;
LEA RUNNING,A3 A3:=RUNNING QUEUE;
CLR.B PR_STA(A1) PROC.STATE:= RUNNING;
MOVE.W #PR_AUX,D0 D0:=AUX_QUEUE OFFSET
ELSE.S ELSE
LEA GA_SPLOK(A6),A3 A3:=GATE.SPEED_RELOCK QUEUE;
MOVE.W #PR_MAIN,D0 D0:=MAIN_QUEUE OFFSET
ENDI ENDI;
* A1=PROC, A3=QUEUE, D0=QUEUE ELEMENT OFFSET
ADD.W D0,A1 A1:= PROC.OFFSET_QUEUE
INS_ELEM A3,A1,A6,A3/A6 INSERT PROC.OFFSET IN SELECTED QUEUE;
SUB.W D0,A1 RESTORE A1 AS PROCESS ADDRESS;
PRT_MEM SPEDWAIT,(A1),PR_SIZ ********
RTS RETURN
PAGE
SPEDDEVI EQU * SPEED UP PROCESS WAITING ON DEVICE CONDITION;D7/A3/A6:=?
MOVE.W D0,PR_SYN(A1) PROC.SYNC_RESULT:=RESULT;
MOVE.B PR_PRI(A1),D7 D7:=LEVEL << 4 + X
BCLR.L #0,D7 D7:=LEVEL << 4 + 0
LEA PR_MAIN(A1),A1 A1:=PROC.MAIN;
REM_ELEM (A1),A3,A6,A3/A6 REMOVE PROC.MAIN FROM "SOME" QUEUE;
BSR.L QDRIV QDRIV(A1=PROC,D7=PRIO,A3/A6:=UNDEF);
* PROC.STATE REMAINS UNCHANGED (=D_WAIT=4). PROC.AUX IS QUEUED TO COND.
LEA -PR_MAIN(A1),A1 A1:= PROCESS;
PRT_MEM SPEDDEVI,(A1),PR_SIZ ********
MOVE.L A4,A3 SAVE A4 IN A3
BSR.L EN_STOPR ENSURE STOP RUNNING PROCESS(D7/A4:=?);
MOVE.L A3,A4 RESTORE A4 FROM A3
RTS RETURN;
* WHEN THE KERNEL OPERATION THAT CALLED SPEDDEVI RETURNS TO THE
* USER CONTEXT, THE SCHEDULER WILL GET CONTROL, AND ACTIVATE
* THE DRIVER JUST SPEEDED UP.
SPED_RUN EQU * PUT THE PROCESS BACK INTO RUNNING QUEUE;
* CALL RETURN
* D0 SYNC_RESULT SAME
* A1 PROCESS SAME
* A3/A6 ANY UNDEF
MOVE.W D0,PR_SYN(A1) PROC.SYNC_RESULT:=RESULT;
REM_ELEM PR_MAIN(A1),A3,A6,A3/A6 REMOVE PROC.MAIN FROM
INIT_HEAD PR_MAIN(A1),A3 "SOME" QUEUE
CLR.B PR_STA(A1) PROC.STATE:=RUN:=0;
CLR.B PR_PRI(A1) PROC.PRIO:=0;
LEA PR_AUX(A1),A1 A1:=PROC.AUX
REM_ELEM (A1),A3,A6,A3/A6 REMOVE PROC.AUX FROM "SOME" QUEUE
LEA RUNNING,A3 A3:=RUNNING;
INS_ELEM A3,A1,A6,A3/A6 INSERT PROC.AUX IN RUNNING QUEUE;
LEA -PR_AUX(A1),A1 RESTORE A1 = PROCESS
PRT_MEM SPED_RUN,(A1),PR_SIZ ********
RTS RETURN;
CASE_ERR EQU * CASE ERROR
ERROR 88 ERROR(88);
* END OF SCHEDULER RUNTIME SECTION
SCH_TRUN EQU * TOP ADDRESS OF SCHEDULER RUNTIME SECTION
END ! END OF SCHEDULER SOURCE
«eof»