!TITLE The Distributed Array Processor (DAP) ! %externalintegerfn DDAP(%integer ACT, ADR) ! ! ACT is an activity number and ADR is the address of a record DAP of ! format DAPF: ! ! %recordformat DAPF(%integer CONF, INSTAT, STATUS, ADVIOL, ! COB, COL, NDPC, IT, ! IC, DOLOG1, DOLOG2, ILOG1, ! ILOG2, SECONDS, KBYTES, VADDR, ! BATCH LIMIT, INTER LIMIT, SPOOLR BATCH LIMIT, ! %string(6)SOLE USER1, SOLE USER2) ! ! !ACT = 0 ! Called by DSTOP if DAP STATE is not zero to tidy up ! !ACT = 1 ! DAP store of DAP_KBYTES is claimed. If the call is successful, ! DAP_VADDR is set to the virtual address by which the claimed DAP ! store may be referenced. ! ! ! ! Spec for Allocate call to Supervisor. Service number 31 (decimal). ! !DACT = 1 Allocate P_P1 blocks of DAP store. ! Reply: P_P1 = 0 OK and ! P_P2 = logical DAP no<<16 ! physical DAP SMAC number ! P_P3 = number of first block allocated ! P_P4 = number of blocks allocated. ! 1 No DAP in configuration ! 2 insufficient contiguous DAP blocks ! available ! 3 DAP closing ! 4 process already has some DAP. ! !ACT = 2 ! Any DAP store that has been claimed is released. ! !DACT = 2 De-allocate DAP (i.e. whole of allocated DAP store). ! P_P1 = logical DAP no<<16 ! physical DAP SMAC number ! P_P2 = number of first block allocated ! P_P3 = number of blocks allocated. ! Reply: P_P1 = 0 OK, 1 fail !ACT = 3 ! DAP start. ! ! ! ! Spec for Supervisor Start DAP service (DSNO = 31 decimal DACT = 4) ! ! P_P1 = DATUM rel to start DAP program datum (displacement in ! of DAP store words of the first word of the DAP ! program block relative to the base of ! the DAP store). ! ! P_P2 = LIMIT rel to DATUM DAP program limit (displacement in ! words of the last plane of the program ! block relative to DATUM). ! ! P_P3 = COB rel to DATUM Code base (words from DATUM). ! ! P_P4 = COL rel to DATUM Code limit (word address of first word ! of last plane of code area relative to ! DATUM). ! ! P_P5 = NDPC rel to COB Program counter (word address relative ! to COB) ! P_P6 = IC Instruction counter ! ! ! For further information about these DAP registers see DAP/TN/6 ! Section 4.3 ! ! ! On return from the DAP START request, the record P is set up as ! follows. ! ! The SACT field tells whether DAP execution was aborted by the DDAP STOP ! procedure. Even if DDAP STOP was called, the execution may have already ! terminated due to some program condition (e.g. stop instruction ! executed). Or the DAP START request may have been queued by the ! supervisor, i.e. execution has not yet started. ! ! Thus the SACT field will be set as follows. ! ! SACT = 4 the DAP was not in fact started. (A STOP request ! was received before the preceeding START request was ! actually scheduled). The record P contains the same ! information as was given in the START request. ! P_P1 = 1 DAP not claimed, 2 DAP closing ! ! SACT = 3 the DAP WAS running. The record P contains information ! necessary (e.g. NDPC) for a re-start, if required, as ! below. ! ! ! P_P1 has the following packed-up data: ! ! bits 0 - 7 bottom byte of INSTAT ! bits 8 - 23 bits 8 -23 of ADVIOL ! bits 24 - 31 bits 24 - 31 of STATUS ! ! P_P2 has NDPC ! ! P_P3 has the following packed-up data: ! ! bits 0 - 16 bits 15 - 31 of DLOG1 ! bits 17 - 31 bits 17 - 31 of DLOG2 ! ! P_P4 has IC ! ! P_P5 has the following packed-up data: ! ! bits 0 - 11 bits 16 - 23 of DOLOG1 ! bits 12 - 31 the failing instruction ! ! P_P6 has the following packed-up data: ! ! bits 0 - 11 bits 20 - 31 of DOLOG2 ! bits 12 - 31 the instruction which was executed prior to ! the failing instruction. ! !ACT = 4 ! DAP stop. ! ! This activity is intended to be called on the signal stack following an ! Int:A frm the user. (Otherwise it's not easy to see why it should be ! relevant, as not both the user process and the DAP MCU should be ! running simulataneously). ! ! A DAP STOP message is sent to Supervisor (no reply, at least not to the ! calling service). What happens is: ! ! If the DAP was running for "this user", then a reply is given to ! the START DAP request, and the user finds that the HOST FORCED ! STOP bit is set in STATUS. ! ! If the DAP was not running for "this user", but the user has a ! "claim" request queued, then Supervisor gives a special reply to ! the claim request (SRCE=X'1F0005', P_P1=-1), and we interpret ! this and pass the reply back to the user. ! ! If neither of the above things are the case (and this could arise ! when the user does an Int:A such that the DAP STOP request goes ! to Supervisor before the claim request was queued, because the ! DDAP routine has been interrupted after setting the STATE to ! SUPVR TOLD but before the claim request was PONned), then ! Supervisor ignores the DAP STOP message. ! !ACT = 5 ! DAP related data. ! ! The following fields are set in the 'DAP' record: ! DAP_CONF to Current ClaimQ limit (DIRCOM_CLAIMQ LIMIT) ! DAP_SECONDS to H_DAPSECS ! DAP_BATCH LIMIT to DIRCOM_DAP BATCH LIMIT ! DAP_INTER LIMIT to DIRCOM_DAP INTER LIMIT ! DAP_SOLE USER to DIRCOM_DAP SOLE USER ! DAP_SPOOLR BATCH LIMIT either to DAP_BATCH LIMIT or, if DAP ! not available for (any) batch job, 0 ! ! !ACT = 6 ! Give users currently having Claim requests queued (or currently using ! DAP). ADR points to a %STRING(6) %ARRAY A(1:20), initially set to all ! zeroes by the caller. Director stuffs in the usernames (procnos ! obtained from Supervisor) - first username is RUNNING in the DAP and ! subsequent ones have Claim requests queued. ! !! New entries to DDAP (August 1983) ! ! ! ACT = 7 ADR points to a record format: ! ! (%string(31) TO USER, FROM USER, TO FILE, FROM FILE, ! %integer TO FSYS, FROM FSYS, DAP PAGE NO, TO FILE PAGE, ! FROM FILE PAGE, NO OF PAGES, IDENT) ! ! Causes transfers of NO OF PAGES of data from ! ! FROM FILE PAGE to DAP PAGE NO (if FROM FILE PAGE ! non-zero) ! ! and/or from ! ! DAP PAGE NO to TO FILE PAGE (if TO FILE PAGE ! non-zero) ! ! FROM FILE PAGE and TO FILE PAGE describe pages within the files ! FROMUSER.FROMFILE on FROMFSYS and TOUSER.TOFILE on TO FSYS ! respectively. If FROM FILE PAGE is minus one then no transfer takes ! place FROM the file. If TO FILE PAGE is minus one then no transfer ! takes place TO the file. BOTH may not be minus one. ! ! DAP PAGE NO is the start-page-number of the required DAP page ! within the DAP block. ! ! The IDENT field is set to a number identifying the transfer request. ! Idents are bit settings, so that several may be ORed together to ! represent several idents. ! ! ! ACT = 8 ADR points to the same record format described above. The IDENTS ! field should be set with IDENTs supplied from the ACT=7 call, to ! indicate one or more transfers. ! ! The EMAS process suspends until the transfers represented by the ! given IDENTS are complete. ! ! ! -------------------------------------------------------------------------------- ! ! Programming notes. ! ! These entries may be called only from the ROUTINE which is given in the call of ! DDAP. (This routine is called when a X'F7Fxxxxx' DAP stop instruction ! is executed). On return from this routine, DAP execution resumes at the next ! DAP instruction (except for ACT=9). But in all cases, return MUST BE MADE, so ! that DDAP can "collect all replies to oustanding page in/out requests. ! The integerfunction given as the parameter to DDAP should be specified: ! ! %integerfn UROUTINE(%integer ILOG1, ILOG2, NDPC) ! ! Any non-zero result given by further calls of DDAP from UROUTINE should be ! given as the result from UROUTINE. This will disable further DAP execution. ! Thus giving a non-zero result is a way (THE way) of aborting the DAP run at ! this point. The parameters handed are (obviously) ILOG1, ILOG2, and DAP PC. ! ! -------------------------------------------------------------------------------- ! Estimated timings ! ! Transfer speed (after seek and rotational delay) is 5 msecs/page. ! Average latency is 7.5 msecs. ! Seek time is 10 to 60 msecs. ! ! One-eighth of the DAP is 256 Kbytes or 64 pages. These will in practice appear ! as two contiguous blocks of 32 pages with no seek or latency within the 32-page ! transfers. Transfer time for 32 pages will therefore be ! ! 35 + 7.5 + 32*5 msecs = 202.5 msecs ! ! and for 64 pages on the same disc 505 msecs at best. We must double this for ! the swap, giving 1.01 secs. And we must also allow for disc contention and for ! channel (DFC) contention, resulting from other users' presence. At worst this ! might involve a further factor of four for channel contention and four for disc ! contention. At best, perhaps two and two (say for night or weekend usage). ! ! We might expect a one-eighth DAP swap, therefore, to take from 5 to 18 seconds. ! In an empty machine, we might get down to two seconds. Remember we have to wake ! up and page in the EMAS process itself, as well as getting the actual transfers ! done. ! ! -------------------------------------------------------------------------------- ! ! !DAP related error numbers: ! 62 ClaimQ limit would be exceeded ! 63 DAP not claimed at START ! 64 DAP Claim de-queued (as a result of a DAP STOP request to ! Supervisor) ! 67 Not claimed at Release ! 71 No time left ! 72 DAP not started ! 73 DAP not available ! 74 Not enough contiguous DAP blocks ! 75 DAP closing ! 76 User already has DAP ! 90 Max already allocated ! 92 Interactive use not allowed ! ! ! Commentary on COM_DAP STATE: ! ! 0 No DAP (allocated as store if DAP exists) ! 1 DAP free and idle (ready to be claimed as DAP) ! 2 Claimed by some user. ! 3 DAP running. ! 16 DAP is available as store, but will become DAP if ! someone does an Allocate. ! 17 DAP is free and idle (after user de-allocate) and ! is going to revert to being store, after a short ! timeout. !> INCLUDE "PD22S_C03FORMATS" ! recordformat c DAPF(INTEGER CONF, INSTAT, STATUS, ADVIOL, COB, COL, NDPC, IT, IC, DOLOG1, DOLOG2, ILOG1, ILOG2, SECONDS, KBYTES, VADDR, BATCH LIMIT, INTER LIMIT, SPOOLR BATCH LIMIT, STRING (6)ARRAY DAP USER(0 : 2), INTEGERARRAY DAP INTEGER(1 : 8)) CONSTINTEGER DAPF LEN = 132 recordformat c DFINFOF(integer NKB, RUP, EEP, APF, USE, ARCH, FSYS, CONSEG, CCT, CODES, byteinteger SP1, DAYNO, POOL, CODES2, integer SSBYTE, string (6)OFFER) recordformat c PROCF(STRING (6)USER, BYTEINTEGER INCAR,CATEGORY,WSN,RUNQ,ACTIVE, INTEGER ACTWO, LSTAD, LAMTX, STACK, STATUS) ! ! ! ! CONSTRECORD (UINFF) NAME UINF = 9<<18 CONSTINTEGER NO = 0 CONSTINTEGER YES = 1 CONSTINTEGER INTER = 0 CONSTINTEGER BATCH = 2 CONSTINTEGER DAP BLOCK SIZE = X'20000' {bytes, i.e. half-seg} CONSTINTEGER DAP BLOCKS = 16 CONSTINTEGER LEAVE = 8 ! ! ! EXTERNALINTEGERFNSPEC C DCONNECTI(STRING (31) FILE, INTEGER FSYS, MODE, APF, INTEGERNAME SEG, GAP) EXTERNALINTEGERFNSPEC C DCREATEF(STRING (31) FILE, INTEGER FSYS, NKB, ALLOC, LEAVE, INTEGERNAME DA) EXTERNALINTEGERFNSPEC C DDESTROYF(STRING (31) FILE, INTEGER FSYS, DEALLOC) EXTERNALINTEGERFNSPEC C DDISCONNECTI(STRING (31) FILE, INTEGER FSYS, LO) externalintegerfnSPEC C DFINFO(string (31)FILE INDEX, FILE, integer FSYS, ADR) EXTERNALINTEGERFNSPEC C DGETDA(STRING (31) USER, FILE, INTEGER FSYS, ADR) EXTERNALROUTINESPEC C DOUT11I(RECORD (PARMF)NAME P) EXTERNALROUTINESPEC C DOUTI(RECORD (PARMF) NAME P) EXTERNALROUTINESPEC C DPONI(RECORD (PARMF) NAME P) EXTERNALROUTINESPEC C DPOFFI(RECORD (PARMF) NAME P) externalroutinespec c DTOFF(record (PARMF)name P) EXTERNALINTEGERFNSPEC C HINDA(STRING (6)USER, INTEGERNAME FSYS, INDAD, INTEGER TYPE) EXTERNALINTEGERFNSPEC C IN2(INTEGER FN) EXTERNALSTRINGFNSPEC C ITOS(INTEGER I) EXTERNALINTEGERFNSPEC C OUT(INTEGER FLAG, STRING (63) TEMPLATE) EXTERNALROUTINESPEC C PREC(STRING (255)S, RECORD (PARMF)NAME P, INTEGER NL) EXTERNALINTEGERFNSPEC C SYSAD(INTEGER KEY, FSYS) EXTERNALINTEGERFNSPEC C VAL(INTEGER ADR, LEN, RW, PSR) EXTERNALROUTINESPEC C WRS(STRING (255) S) EXTERNALROUTINESPEC C WRSN(STRING (255) S, INTEGER N) EXTERNALROUTINESPEC C WRSNT(STRING (255) S, INTEGER N, T) ! ! ! EXTRINSICINTEGER DAP STATE; ! defined for DSTOP EXTRINSICINTEGER D CALLERS ACR EXTRINSICINTEGER D CALLERS PSR EXTRINSICINTEGER DIRMON EXTRINSICINTEGER D TRYING EXTRINSICINTEGER OUTPAD EXTRINSICSTRING (6) PROCUSER ! ! OWNINTEGER DAP SEG OWNINTEGER DAP GAP OWNINTEGER KBYTES OWNINTEGER DAP BLOCKS ALLOC, DAP BLOCK NO, DAP IDENT, LOGICAL DAP NO OWNINTEGER EXTRA BLOCKS {this can be used to leave unused the low-} {numbered blocks, to avoid the areas giving} {hardware trouble} OWNSTRING (3) SUFF OWNINTEGER DAP ACR OWNINTEGER DAP PSR ! DATUM and LIMIT are word quantities and must be plane-aligned. ! A plane, in the 64 X 64 DAP is 128 words (64 rows, each row being 64 bits). CONSTINTEGER PLANE SIZE = 128 {words} CONSTINTEGER DAP INS PER SEC = 3300000; ! increased by 10% in Director 19 ! following receipt of figures from ! Mike Brown. CONSTLONGINTEGER COME BACK AFTER = 120 * DAP INSPERSEC; ! max IC value set per DAPSTART CONSTINTEGER HOST FORCED STOP = B'10000000' {bit 24} {These come as } CONSTINTEGER DAP STOP = B'1000000' {bit 25} { bits 0-7 of } CONSTINTEGER DAP EXSTP = B'100000' {bit 26} { P_P1 in reply } CONSTINTEGER DAP INTR = B'10000' {bit 27} { from DAPSTART } CONSTINTEGER DAP HWARE ERR = B'1000' {bit 28} CONSTINTEGER DAP PROG ERR = B'100' {bit 29} CONSTINTEGER DAP IT EXPIRED = B'10' {bit 30} CONSTINTEGER DAP IC EXPIRED = B'1' {bit 31} CONSTINTEGER SWAP OUT BIT = B'10000000'; ! {bit 24 (ICL unused) in STATUS CONSTINTEGER REPORT DAP START REQUEST = B'1' CONSTINTEGER REPORT DAP RESPONSE = B'10' CONSTINTEGER REPORT DAP SEGNUMBER = B'100' CONSTINTEGER CLAIMED = B'1' CONSTINTEGER SUPVR TOLD = B'10' CONSTINTEGER DAP TO FILE = 2, FILE TO DAP = 1 CONSTINTEGER SECT SIZE = 32 {i.e. pages per sect} CONSTINTEGER MAX IN PROGRESS = 64 {max no of page transfer requests allowed to be in progress at any time} INTEGERFN DDAPI(INTEGERFN UROUTINE(INTEGER ILOG1, ILOG2, NDPC), INTEGER ACT, ADR) ! ! ! INTEGER FLAG, J, K, DA, XEXIT, DAP VREALADDR, DATUM, LIMIT, SEG INTEGER COB, COL, NDPC, IC, INSTAT, KK, UROUT FLAG, DAPTIMEOUTFLAG INTEGER MINSTRS, DSECS, FSYS, INDAD, THIS LONGINTEGER ILEFT, IUSED STRING (6)USER RECORD (HF) NAME H RECORD (PARMF) P, DAPSTARTP RECORD (DAPF) NAME DAP RECORD (DIRCOMF) NAME DIRCOM RECORD (PROCF)ARRAYFORMAT PROCAF(0:COM_MAXPROCS) RECORD (PROCF)ARRAYNAME PROCLIST INTEGERARRAY SECTS( - 4:16 {allows 2 Mbytes: 16 sects @ 128K}) CONSTSTRING (4) DAPFILE = "#DAP" OWNINTEGER LAST PRINT CONSTSTRING (4)ARRAY TAG1(0:2)="B0 ", ",B1 ", ",I " CONSTSTRING (4)ARRAY TAG2(1:8)=",CQ",",I",",L0",",H0",",L1",",H1",",SB0",",SB1" ! CONSTINTEGER TOPACT = 8 SWITCH SW(1:TOPACT) SWITCH SW5(0 : 2) {used in activity 5} ! ! ! ROUTINE DSEGMENT(INTEGER SEG) ! REQUESTS THE LOCAL CONTROLLER TO REMOVE ACTIVE MEMORY ! TABLE ENTRIES FOR SEGMENT SEG RECORD (PARMF)NAME P INTEGER J ! Reference a page in each block, just to ensure that zero pages are ! provided for each block which has not been referenced. In fact DAPRUN ! has definitely referenced each page, because it zeroes the whole program ! block, ie. the whole file, first. However, we'll do this to be rigorous ! and enforce integrity. The top bit in the SEG parameter is SET if the segment ! has two blocks, and is ZERO if the segment has one block. J=INTEGER(SEG<<18) J=INTEGER(SEG<<18 + X'20000') IF SEG<0 SEG=SEG<<1>>1 P==RECORD(OUTPAD) P=0 P_P1=SEG *OUT_3; ! We would set P_P2=1 for "DESTROYING SEGMENT". But we are not destroying it. IF P_DEST=-1 THEN WRS("DSEGMENT fails in DDAP") END ; ! DSEGMENT INTEGERFN PAGE TRANSFERS(INTEGER DIRECTION) ! In this routine we move data from the #DAP file into the real DAP and vv, ! allowing a maximum of MAX IN PROGRESS transfers to be outstanding at atime ! (so as not to swamp the transferqueues unnecessarily). ! Result 0 no failures ! 1 a transfer failed INTEGER PAGE, DATUM PAGE, LIMIT PAGE, CODE BASE PAGE, CODE LIMIT PAGE INTEGER FAIL, TFERS OUTSTANDING, DISC SECT, SECT PAGE, TFERS RECORD (PARMF) P RECORD (PARMF) NAME OUTP TFERS = 0 {remove this variable "sometime" - was just for some monitoring} TFERS OUTSTANDING = 0 FAIL = 0 DISC SECT = 0 SECT PAGE = 0 ! DATUM PAGE is the lowest relative pageno of DAP which is to be swapped DATUM PAGE = DATUM {words} >> 10 ! LIMIT PAGE is the highest relative pageno of DAP which is to be swapped LIMIT PAGE = DATUM PAGE + KBYTES >> 2 - 1 ! CODE BASE PAGE is the lowest page containing code WHICH DOES NOT NEED TO ! BE SWAPPED OUT. CODE BASE PAGE = DATUM PAGE + (COB + 1023) >> 10 ! CODE LIMIT PAGE is the highest relative pageno of DAP which does not need to be SWAPPED OUT. CODE LIMIT PAGE = DATUM PAGE + ((COL + PLANE SIZE) >> 10) - 1 ! This bunch of monitoring can be removed, say at next Director relase. { WRSNT("CODE BASE PAGE", CODE BASE PAGE, 4+2);WRSNT("' CODE LIMIT PAGE", { CODE LIMIT PAGE, 2) { WRSNT("' LIMIT",LIMIT,4+2);WRSNT("' LIMIT PAGE", { LIMIT PAGE,4+2);WRSNT("' KBYTES",KBYTES,2) PAGE = DATUM PAGE IF DIRECTION = FILE TO DAP START ! Make sure that pages of the first section are back to disc (redundant ! code on calls of PAGE TRANSFERS after the first following the ! ddisconnect, but never mind). Subsequent sections (blocks) are checked ! below, when DISC SECT is incremented. ! WRSNT("OUT_17A ON", SECTS(0), 2) OUTP == RECORD(OUTPAD) OUTP = 0 OUTP_DEST = SECTS(0) *OUT_17; ! Returns p_dest=-1 if block still active, 0 if not still active IF OUTP_DEST = - 1 START WRS("DAP PAGE TRANSFERS: block still active!!") FAIL = 1 -> OUT FINISH FINISH CYCLE WHILE FAIL = 0 AND PAGE <= LIMIT PAGE AND C TFERS OUTSTANDING < MAX IN PROGRESS CYCLE IF DIRECTION = FILE TO DAP OR (DIRECTION = DAP TO FILE AND C NOT (CODE BASE PAGE <= PAGE <= CODE LIMIT PAGE)) START P = 0 P_DEST = 33 {SNO for PDISC} << 16 ! DIRECTION {1=read disc to store 2=write store to disc} P_P3 = DAP VREALADDR + PAGE << 12 P_P2 = SECTS(DISC SECT) + SECT PAGE IF DIRECTION = DAP TO FILE THEN P_P6 = M'DTOF' ELSE P_P6 = M'FTOD' {to see in Dirmonning} DPONI(P) TFERS OUTSTANDING = TFERS OUTSTANDING + 1 TFERS = TFERS + 1 FINISH PAGE = PAGE + 1 SECT PAGE = SECT PAGE + 1 IF SECT PAGE >= SECT SIZE AND C DISC SECT < SECTS( - 3) {no of sections} - 1 START DISC SECT = DISC SECT + 1 SECT PAGE = 0 IF DIRECTION = FILE TO DAP START ! See comment before outer cycle. ! WRSNT("OUT_17B ON", SECTS(DISC SECT), 2) OUTP == RECORD(OUTPAD) OUTP = 0 OUTP_DEST = SECTS(DISC SECT) *OUT_17; ! Returns p_dest=-1 if block still active, 0 if not still active IF OUTP_DEST = - 1 START WRS("DAP PAGE TRANSFERS: block still active!!") FAIL = 1 {fail} FINISH FINISH FINISH REPEAT DPOFFI(P) IF P_P2 # 0 THEN FAIL = 1 TFERS OUTSTANDING = TFERS OUTSTANDING - 1 REPEATUNTIL TFERS OUTSTANDING = 0 { WRSNT("Page transfers =", TFERS, 4+2); WRSNT(" FAIL =", FAIL, 2) } OUT: ! %IF DIRECTION = FILE TO DAP %C ! %THEN PRINTSTRING("FILE TO DAP") %C ! %ELSE PRINTSTRING("DAP TO FILE") ! WRSN(" flag", FAIL) ! RESULT = FAIL END ; ! PAGE TRANSFERS !------------------------------------------------------------------------------- OWN INTEGER TRANSFER REC ADDR = 0; ! This variable is zero except when the ! DAP-start (entry 3) has been made. CONSTINTEGER MAX DDE SECTS = 15; ! Max 2 Mbytes/transfer, less one section ! (We need to record data for one extra ! section, in case transfer-start disc ! address is not aligned with start of ! section). CONSTINTEGER TOP SLOT = 1; ! Allowing two simultaneous transfers RECORDFORMAT TFRF(INTEGERARRAY TO SECTS, FROM SECTS, SECT CHKD(0:MAX DDE SECTS), BYTEINTEGERARRAY STATE(0:(MAX DDE SECTS*SECT SIZE)-1), INTEGER REQ COUNT, TERM COUNT, DAP PAGENO, FROM PAGENO, TO PAGENO, NPAGES, SEG1, SEG2) RECORDFORMAT TRF(INTEGER TFRS WAITING, TFRS SUSPENDED, HI SLOT, SLOTS IN USE, SLOTS WAITING TFR,TFRS IN PROGRESS, DAP VREALADDR, RECORD (TFRF)ARRAY TFERS(0:TOP SLOT)) RECORD (TRF) TRANSFER REC ! We wish to be able to swap 2 Meg = 8 segments = 16 blocks or sections ! (But less one section, see comment near MAX DE SECTS above). CONSTINTEGER AWAIT DAP STOP=1, FINISH TRANSFERS=2 CONSTINTEGER TO PAGE OUT THEN PAGE IN = 5 CONSTINTEGER AWAITING TERM THEN PAGE IN = 4 CONSTINTEGER TO PAGE OUT ONLY = 3 CONSTINTEGER TO PAGE IN ONLY = 2 CONSTINTEGER AWAITING TERM = 1 CONSTINTEGER DONE = 0 ! AWAITING TERM goes to DONE ! TO PAGE IN ONLY goes to AWAITING TERM ! TO PAGE OUT ONLY goes to AWAITING TERM ! AWAITING TERM THEN PAGE IN goes to AWAITING TERM ! TO PAGE OUT THEN PAGE IN goes to AWAITING PAGE IN RECORDFORMAT FORMAT7(STRING (31) TO USER, FROM USER, TO FILE, FROM FILE, INTEGER TO FSYS, FROM FSYS, DAP PAGENO, TO FILE PAGENO, FROM FILE PAGENO, NO OF PAGES, IDENT) CONST INTEGER DAPF LEN7 = 156 RECORD (FORMAT7) NAME REQ8 ! The general scheme of things for our block transfer system (BTS) is as follows. First, nothing is ! different (from previous arrangements, pre-BTS) unless and until a special DAP STOP instruction is executed ! by the DAP MCU. The special stop is one with op-code F7 and stop parameter Fxxxxx (agreed between Mike ! Brown and Keith Yarwood). When such a stop instruction is executed (and even if other exception conditions ! are present), the user-supplied procedure UROUTINE is executed. This procedure is expected to supply ! details of swap-in/out operations on part of the DAP program block by calling DDAP entry 7 (recursive ! call). This entry records details of required page transfers and returns zero result if OK. Provided that ! UROUTINE also returns a zero result, DAP execution then continues at the current DAP PC (viz. after the ! special stop instruction). If UROUTINE gives a non-zero result then the DAP is not re-started and control ! eventually returns again to user, but in fact AFTER completing all successfully- requested transfers. ! Likewise if any other exception condition (e.g. "time exceeded") is present simultaneously with the the ! special DAP stop, then it is treated after the return from UROUTINE. If this exception would cause return ! to user in the "pre-BTS" situation, then it will still do so, again after all current BTS requests are ! complete. ! ! The other thing that UROUTINE can do, in addition to requesting a series of BTS transfers, is to request ! DAP suspension (i.e. continued suspension - the DAP is already stopped) UNTIL one or more previous BTS ! transfer requests are complete. This it does by calling DDAP entry 8, setting one or more bits in the ! IDENT field of the supplied record with the identifier bits supplied from previous calls of DDAP entry 7. ! Return is made from DDAP entry 8 only when all the specified transfers are complete. ! ! In DDAP, the guiding principle is that all requested BTS transfers are complete before return is made from ! the start-DAP entry - they must be, otherwise the termination POFF messages cannot be collected. This is ! the purpose of the ACTION=AWAIT entry to the CHECK BTS TRANSFERS function. INTEGERFN INITIALISE REQUEST RECORDS INTEGER FLAG, I, TO FILE PAGES, FROM FILE PAGES, NPAGES, ID, RET ID, SLOT, DAP PAGENO, TO FILE PAGENO, FROM FILE PAGENO, TO START SECT, FROM START SECT, INIT STATE, OPINC, SEG1, SEG2, NSEGS, LASTSEG, KK ! %RECORD(TFRF)%ARRAYFORMAT TFERSF(0:TOP SLOT) RECORD (TFRF)ARRAYNAME TFERS RECORD (TRF)NAME TRANSFER REC RECORD (TFRF)NAME T RECORD (FORMAT7)NAME REQ RECORD (DFINFOF) FINFOREC INTEGERARRAY TO SECTS, FROM SECTS(-4 : 255) ! This procedure is called during a RECURSIVE call of DDAP. We must be sure to ! map onto the TRANSFER REQUESTS array in the ORIGINAL INVOCATION of DDAP. ! REMOVE THIS CODE WHEN IN DIRECTOR. IT'S TO AVOID UNASSIGNED CHECK DURING TESTING******** {FOR I=255, -1, 0 %CYCLE; TO SECTS(I)=0; FROM SECTS(I)=0; %REPEAT; FROM START SECT=0; TO START SECT=0 REQ == RECORD(ADR) DAP PAGENO = REQ_DAP PAGENO TO FILE PAGENO = REQ_TO FILE PAGENO FROM FILE PAGENO = REQ_FROM FILE PAGENO NPAGES = REQ_NO OF PAGES OPINC = 1 {This is the number of operations per request page. It becomes 2 for a "swap"} SEG1 = 0 SEG2 = 0 INIT STATE = DONE IF TO FILE PAGENO>=0 START UNLESS DIRMON = 0 START WRSNT("DAP OUT REQUEST ON FSYS", REQ_TO FSYS, 4) WRSNT(" DAP page", DAP PAGENO, 4) WRSNT(" PAGES:", NPAGES, 4) WRSNT(" to PAGENO", TO FILE PAGENO, 0) FINISH FLAG = DGETDA(REQ_TO USER, REQ_TO FILE, REQ_TO FSYS, ADDR(TO SECTS(-4))) RESULT = FLAG UNLESS FLAG = 0 TO FILE PAGES = (TO SECTS(-3)-1)*SECT SIZE + TO SECTS(-2) TO START SECT = TO FILE PAGENO//SECT SIZE INIT STATE = TO PAGE OUT ONLY FINISH IF FROM FILE PAGENO>=0 START UNLESS DIRMON = 0 START WRSNT("DAP IN REQUEST ON FSYS", REQ_FROM FSYS, 4) WRSNT(" DAP page", DAP PAGENO, 4) WRSNT(" PAGES:", NPAGES, 4) WRSNT(" from PAGENO", FROM FILE PAGENO, 0) FINISH FLAG = DGETDA(REQ_FROM USER, REQ_FROM FILE, REQ_FROM FSYS, ADDR(FROM SECTS(-4))) UNLESS FLAG = 0 THEN RESULT = FLAG FROM FILE PAGES = (FROM SECTS(-3)-1)*SECT SIZE + FROM SECTS(-2) FROM START SECT = FROM FILE PAGENO//SECT SIZE FLAG = DFINFO(REQ_FROM USER, REQ_FROM FILE, REQ_FROM FSYS, ADDR(FINFOREC)) UNLESS FLAG = 0 THEN RESULT = FLAG IF FINFOREC_CONSEG # 0 START ! Work out start and end-segment numbers. This is so that we have ! the necessary information to ensure that pages are on disc before ! we bulk move them. FLAG = 1 - (FROM SECTS(-3){no of sects} & 1) ! namely, zero if last seg of file has one block, and one if it has two NSEGS = (FROM SECTS(-3) + 1) >> 1 LASTSEG = FINFOREC_CONSEG + NSEGS - 1 SEG1 = FINFOREC_CONSEG + (FROM FILE PAGENO >> 6) IF SEG1 < LASTSEG THEN KK = 1 ELSE KK = FLAG SEG1 = SEG1 ! (KK << 31) SEG2 = FINFOREC_CONSEG + ((FROM FILE PAGENO + NPAGES - 1) >> 6) IF SEG2 < LASTSEG THEN KK = 1 ELSE KK = FLAG SEG2 = SEG2 ! (KK << 31) FINISH IF INIT STATE = TO PAGE OUT ONLY START ! A swap INIT STATE = TO PAGE OUT THEN PAGE IN OPINC = 2 FINISH ELSE INIT STATE = TO PAGE IN ONLY FINISH UNLESS 0 < DAP PAGENO + NPAGES <= KBYTES>>2 AND (TO FILE PAGENO = -1 OR C (TO FILE PAGENO >= 0 AND TO FILE PAGENO < TO FILE PAGES C AND TO FILE PAGENO + NPAGES <= TO FILE PAGES)) AND C (FROM FILE PAGENO = -1 OR C (FROM FILE PAGENO >= 0 AND FROM FILE PAGENO < FROM FILE PAGES C AND FROM FILE PAGENO + NPAGES <= FROM FILE PAGES)) AND C NPAGES > 0 AND TRANSFER REC ADDR > 0 AND NPAGES <= MAX DDE SECTS C * SECT SIZE THEN RESULT = 8 ID = 1 {slot zero} RET ID = 0 {ident to be returned} TRANSFER REC == RECORD(TRANSFER REC ADDR) TFERS == TRANSFER REC_TFERS {see note at declaration} ! Look for a free transfer request slot (indicated by zero count fields) SLOT = 0 UNTIL SLOT = 0 CYCLE T == TFERS(SLOT) IF TFERS(SLOT)_REQ COUNT = 0 = TFERS(SLOT)_TERM COUNT START ! Slot free TFERS(SLOT) = 0 RET ID = ID ! Fill up the request entry ! First the (up to) MAX DDE SECTS+1 disc addresses required FOR I = 0, 1, MAX DDE SECTS CYCLE TFERS(SLOT)_TO SECTS(I) = TO SECTS(TO START SECT + I) IF TO FILE PAGENO >= 0 TFERS(SLOT)_FROM SECTS(I) = FROM SECTS(FROM START SECT + I) IF FROM FILE PAGENO >= 0 REPEAT TFERS(SLOT)_FROM PAGENO = FROM FILE PAGENO & (SECT SIZE-1) TFERS(SLOT)_TO PAGENO = TO FILE PAGENO & (SECT SIZE-1) ! And set the necessary number of STATE bytes to get the required ! transfers effected FOR I = 0, 1, NPAGES-1 CYCLE TFERS(SLOT)_STATE(I) = INIT STATE TFERS(SLOT)_REQ COUNT = TFERS(SLOT)_REQ COUNT + OPINC TFERS(SLOT)_TERM COUNT = TFERS(SLOT)_REQ COUNT TRANSFER REC_TFRS WAITING = TRANSFER REC_TFRS WAITING + 1 TRANSFER REC_TFRS SUSPENDED = TRANSFER REC_TFRS SUSPENDED + 1 IF OPINC = 2 ! In the case of TO PAGE OUT THEN PAGE IN, the second transfer is ! suspended until the first terminates. We need to distinguish in ! the loop which fires off the transfers. REPEAT TFERS(SLOT)_DAP PAGENO = DAP PAGENO TFERS(SLOT)_NPAGES = NPAGES TFERS(SLOT)_SEG1 = SEG1 TFERS(SLOT)_SEG2 = SEG2 TRANSFER REC_SLOTS IN USE = TRANSFER REC_SLOTS IN USE ! RET ID TRANSFER REC_SLOTS WAITING TFR = TRANSFER REC_SLOTS WAITING TFR ! RET ID IF SLOT > TRANSFER REC_HI SLOT THEN TRANSFER REC_HI SLOT = SLOT EXIT FINISH SLOT = SLOT + 1 ID = ID << 1 IF SLOT > TOP SLOT THEN SLOT = 0 AND ID = 1 REPEAT IF RET ID = 0 THEN RESULT = 99 {no free slot/max tfrs outstanding} REQ_IDENT = RET ID RESULT = 0 END {INITIALISE REQUEST RECORDS} INTEGERFN CHECK BTS TRANSFERS(INTEGER ACTION, IDENTS) ! Does two things: ! ACTION = FINISH TRANSFERS accepts POFF messages and returns only when all ! BTS transfers represented by bits in IDENTS are ! complete. This entry is made (only) when the DAP ! is stopped, and the purpose is to ensure that ! specified (or all) requested BTS transfers are complete ! (i.e. initiated and terminated). ! ! Calls with this ACTION may be during recursive ! execution of DDAP [as when UROUTINE calls DDAP(8, )] ! or during non-recursive calls [as called from DDAP(3, )] ! ! ACTION = AWAIT DAP STOP accepts POFF messages and initiates more BTS ! transfers if any are waiting to be fired off. ! This entry is made (only) when the DAP is ! running (namely after the DAP has been started). ! The purpose of this entry is to field page-transfer ! terminations, and to initiate further page-transfers ! if any are outstanding. Return is made from this ! call only when the DAP stops. At this point, page ! transfers may still be in progress. ! ! Calls with this ACTION occur only during non-recursive ! execution of DDAP. ! ! ! POFF messages received can be BTS transfer completions OR a DAP STOPS message. ! If the latter, then record DAPSTART is set with the DAP STOPS POFF-data. ! Result from this function determines whether the DAP run continues ! subsequently, or aborts. If result is ZERO, all has gone OK. If result ! is NON-ZERO then an error has occurred, and the DAP run is to be terminated. INTEGER I, SLOT, PG, DISC ADDRESS, DIRECTION, TO SINDEX, FROM SINDEX, TO PINDEX, FROM PINDEX, STATE, FAIL FLAG, SEG,SEG1, SEG2 RECORD (PARMF) P RECORD (TFRF) NAME T RECORD (PARMF) NAME OUTP ! %RECORD(TFRF)%ARRAYFORMAT TFERSF(0:TOP SLOT) RECORD (TFRF)ARRAYNAME TFERS RECORD (TRF)NAME TRANSFER REC ! Constants used in positioning the page & slot in the Page Transfer Request CONSTINTEGER SLOTSHIFT = 10, PAGEMASK = X'3FF' RESULT = 8 IF TRANSFER REC ADDR = 0 FAIL FLAG = 0 TRANSFER REC == RECORD(TRANSFER REC ADDR) TFERS == TRANSFER REC_TFERS {see note at declaration} I = 1 SLOT = 0 UNLESS DIRMON = 0 START PRINTSTRING("CHK BTS, ") IF ACTION = FINISH TRANSFERS C THEN PRINTSTRING("Finish TFRS ".ITOS(IDENTS)) C ELSE PRINTSTRING("Await STOP") WRSN(" SLOTS IN USE: ", TRANSFER REC_SLOTS IN USE) FINISH CYCLE IF ACTION = FINISH TRANSFERS AND TRANSFER REC_SLOTS IN USE & IDENTS = 0 THEN RESULT = FAIL FLAG ! Take, or wait for, a POFF message IF TRANSFER REC_TFRS WAITING > 0 AND TRANSFER REC_TFRS IN PROGRESS < MAX IN PROGRESS C THEN DTOFF(P) ELSE DPOFFI(P) IF P_DEST # 0 START IF P_SRCE>>16 = X'1F' {DAP driver} START IF ACTION # AWAIT DAP STOP THEN WRS("Ouch A") DAPSTARTP = P {we are in non-recursive exec of DDAP, so this is the right DAPSTARTP} RESULT = 0 FINISH ELSE IF P_SRCE>>16 = 33 {PDISC} START IF P_P2 # 0 THEN FAIL FLAG=1 {Abort - failed transfer} ! Termination - update relevant slot. ! P_P1 has SLOT<<8 ! PAGE BEGIN INTEGER SLOT RECORD (TFRF) NAME T BYTEINTEGERNAME STATE SLOT = P_P1 >> SLOTSHIFT T == TRANSFER REC_TFERS(SLOT) STATE == T_STATE(P_P1&PAGEMASK) IF STATE = TO PAGE OUT THEN PAGE IN OR STATE = TO PAGE OUT ONLY C OR STATE = TO PAGE IN ONLY OR STATE = DONE THEN WRS("Ouch C") ELSE START IF STATE = AWAITING TERM THEN PAGE IN START STATE = TO PAGE IN ONLY TRANSFER REC_TFRS SUSPENDED = TRANSFER REC_TFRS SUSPENDED - 1 TRANSFER REC_TFRS WAITING = TRANSFER REC_TFRS WAITING + 1 FINISH ELSE IF STATE = AWAITING TERM THEN STATE = DONE T_TERM COUNT = T_TERM COUNT - 1 IF T_TERM COUNT = 0 THEN TRANSFER REC_SLOTS IN USE = TRANSFER REC_SLOTS IN USE & (¬(1<<SLOT)) TRANSFER REC_TFRS IN PROGRESS = TRANSFER REC_TFRS IN PROGRESS - 1 FINISH END {begin-block} FINISH ELSE PREC("Ouch B ", P, 0) FINISH IF TRANSFER REC_TFRS IN PROGRESS < MAX IN PROGRESS AND TRANSFER REC_SLOTS WAITING TFR & I # 0 START T == TRANSFER REC_TFERS(SLOT) TO SINDEX = 0; FROM SINDEX = 0 TO PINDEX = T_TO PAGENO; FROM PINDEX = T_FROM PAGENO PG = 0 WHILE PG < T_NPAGES CYCLE STATE = T_STATE(PG) DIRECTION = 0 {shows whether or not a transfer is to be performed for this page} IF STATE = TO PAGE OUT THEN PAGE IN START DISC ADDRESS = T_TO SECTS(TO SINDEX) + TO PINDEX DIRECTION = DAP TO FILE STATE = AWAITING TERM THEN PAGE IN FINISH ELSE IF STATE = TO PAGE IN ONLY START DISC ADDRESS = T_FROM SECTS(FROM SINDEX) + FROM PINDEX DIRECTION = FILE TO DAP STATE = AWAITING TERM FINISH ELSE IF STATE = TO PAGE OUT ONLY START DISC ADDRESS = T_TO SECTS(TO SINDEX) + TO PINDEX DIRECTION = DAP TO FILE STATE = AWAITING TERM FINISH IF DIRECTION # 0 START IF DIRECTION = FILE TO DAP START SEG1 = T_SEG1<<1>>1; SEG2 = T_SEG2<<1>>1 if seg2 > 0 start FOR SEG = SEG1, 1, SEG2 CYCLE IF SEG = SEG2 THEN DSEGMENT(T_SEG2) ELSE DSEGMENT(SEG) REPEAT finish T_SEG2 = 0; ! So that the cycle is executed once per transfer ! per call of this function only. IF T_SECT CHKD(FROM SINDEX) = 0 START T_SECT CHKD(FROM SINDEX) = 1 ! WRSNT("OUT_17C ON SECT ", T_FROM SECTS(FROM SINDEX), 2) OUTP == RECORD(OUTPAD) OUTP = 0 OUTP_DEST = T_FROM SECTS(FROM SINDEX) *OUT_17 IF OUTP_DEST = -1 START WRS("DAP BTS: block still active") RESULT = 1 {abort} FINISH FINISH FINISH P_DEST = 33<<16 ! DIRECTION {pdisc} P_P1 = SLOT<<SLOTSHIFT ! PG; ! IDENT, returned in P_P1 of reply P_P2 = DISC ADDRESS P_P3 = TRANSFER REC_DAP VREALADDR + (T_DAP PAGENO + PG)<<12 IF DIRECTION = DAP TO FILE THEN P_P6 = M'BTOT' ELSE P_P6 = M'BTIN' {to see in Dirmonning} DPONI(P) T_REQ COUNT = T_REQ COUNT - 1 IF T_REQ COUNT = 0 THEN TRANSFER REC_SLOTS WAITING TFR = TRANSFER REC_SLOTS WAITING TFR & (¬I) T_STATE(PG) = STATE TRANSFER REC_TFRS WAITING = TRANSFER REC_TFRS WAITING - 1 TRANSFER REC_TFRS IN PROGRESS = TRANSFER REC_TFRS IN PROGRESS + 1 EXIT IF TRANSFER REC_TFRS IN PROGRESS >= MAX IN PROGRESS FINISH PG = PG + 1 FROM PINDEX = FROM PINDEX + 1 IF FROM PINDEX >= SECT SIZE START FROM SINDEX = FROM SINDEX + 1 FROM PINDEX = 0 FINISH TO PINDEX = TO PINDEX + 1 IF TO PINDEX >= SECT SIZE START TO SINDEX = TO SINDEX+ 1 TO PINDEX = 0 FINISH REPEAT FINISH {slot in use} SLOT = SLOT + 1 I = I <<1 IF SLOT > TRANSFER REC_HI SLOT THEN SLOT = 0 AND I = 1 REPEAT END {CHECK BTS TRANSFERS} ! ! ! ! ! ! PRINTSTRING("DAP ") UNLESS ACT > 4 ! FLAG = IN2(256 + 96) ! ->OUT %UNLESS FLAG = 0 DIRCOM == RECORD(SYSAD(DIRCOMKEY, - 1)) PROCLIST == ARRAY(COM_PROCAAD, PROCAF) ->SW0 IF ACT = 0 FLAG = 8 ->OUT UNLESS 1 <= ACT <= TOPACT FLAG = 45 IF ACT < 7 THEN J = DAPF LEN ELSE J = DAPF LEN7 ->OUT IF VAL(ADR, J, 1, DAP PSR) = 0 ! DAP ACR = D CALLERS ACR; ! gets set to '2' subsequently DAP == RECORD(ADR) ->SW(ACT) ! !-------------------------------------------------- ! SW0: ! tidy up at DSTOP ! invoked by statement in DSTOP: ! flag = DDAP(0, 0) unless DAPSTATE = 0 WRSNT("Act 0, State =", DAPSTATE, 4) UNLESS DAP STATE & SUPVR TOLD = 0 START P = 0 P_DEST = (31 << 16) ! (LOGICAL DAP NO ! 5); ! STOP DPONI(P) ! P = 0 P_DEST = (31 << 16) ! (LOGICAL DAP NO ! 2); ! DE-ALLOC P_P1 = DAP IDENT P_P2 = DAP BLOCK NO P_P3 = DAP BLOCKS ALLOC DOUTI(P) FINISH ! DAP STATE = 0 ->OK ! !---------------------------------------- ! SW(1): ! CLAIM PRINTSTRING("Claim ") FLAG = 73; ! DAP not available ->OUT IF COM_CDR(1)_DAP STATE = 0 = COM_CDR(2)_DAP STATE ! FLAG = 76 -> OUT UNLESS DAP STATE & CLAIMED = 0 ! FLAG = 90; ! max (one DAP) already claimed ->OUT IF UINF_REASON = BATCH AND UINF_DAPINSTRS <= 0 ! no DAP time requested ! IF UINF_REASON = INTER START FLAG = 62 {Max requests on DAP ClaimQ} P = 0 P_DEST = (31 << 16) ! 10 DOUT11I(P) P_P1 = 0 UNLESS 0 <= P_P1 <= 20 -> OUT IF P_P1 >= DIRCOM_DAP INTEGER(1) {CLAIMQ LIMIT} FLAG = 92; ! interactive use (of DAP) not allowed ->OUT IF DTRYING << 17 >= 0 -> OUT IF PROCUSER # DIRCOM_DAP USER(2) # "" UINF_DAPINSTRS = LENGTHENI(DIRCOM_DAP INTEGER(2)) * DAP INSPERSEC FINISH ! ! Make attempts to destroy the file (in case re-starting from disorder. ! SUFF = ITOS(UINF_ISUFF) FLAG = DDISCONNECTI(DAPFILE.SUFF, - 1, 2 {and destroy}) FLAG = DDESTROYF(DAPFILE.SUFF, - 1, 1) ! DAP_KBYTES = (DAP_KBYTES + 3) & ( ¬ 3); ! make it a whole no of pages for the swap in/out FLAG = DCREATEF(DAPFILE.SUFF, - 1, DAP_KBYTES, 5, LEAVE, DA) {temp} ->OUT UNLESS FLAG = 0 ! DAPSEG = 0 DAPGAP = 0 FLAG = DCONNECTI(DAPFILE.SUFF, - 1, 3, (DAP ACR << 4) ! DAP ACR, DAPSEG, DAPGAP) ->OUT UNLESS FLAG = 0 ! KBYTES = DAP_KBYTES DAP_VADDR = DAPSEG << 18 DAP STATE = CLAIMED ->OK ! !-------------------------------------------------- ! SW(2): ! RELEASE PRINTSTRING("Release ") FLAG = 67 ->OUT IF DAP STATE & CLAIMED = 0 ! ! K = DDISCONNECTI(DAPFILE.SUFF, - 1, 0{temp}); !2 {and destroy}) ! result not interesting ! DAP STATE = 0 ->OK ! !-------------------------------------------------- ! SW(3): ! START PRINTSTRING("Start ") FLAG = 63 {not claimed} ->OUT IF DAP STATE & CLAIMED = 0 UROUT FLAG = 0 COB = DAP_COB COL = DAP_COL NDPC = DAP_NDPC LIMIT = (KBYTES << 8 {to words}) - PLANE SIZE FLAG = 8 ->OUT UNLESS 40 * PLANE SIZE {workspace+control area=40 planes} < COB ->OUT UNLESS COB <= COL < LIMIT ->OUT UNLESS 0 <= NDPC < COL - COB + PLANE SIZE WRSNT(" secs", DAP_SECONDS, 5) -> OUT UNLESS 0 < DAP_SECONDS < 72*3600; ! 3 day max! FLAG = 71 ->OUT IF UINF_DAPINSTRS <= 0; ! nothing left ILEFT = LENGTHENI(DAP_SECONDS) * DAP INSPERSEC; ! length of this run ->OUT IF ILEFT > UINF_DAPINSTRS; ! not enough left for the full run IUSED = 0 NEWLINE FLAG = DGETDA(PROCUSER, DAPFILE.SUFF, - 1, ADDR(SECTS( - 4))) ->OUT IF FLAG # 0 {but what about a nice flag?} ! Remove AMT entries for the file, ie. get all pages out of store and back to disc. ! We check in fn PAGE TRANSFER that these transfers have completed. J = 1 - (SECTS(-3){no of sects} & 1) ! J is now zero if the file has an odd number of sections (blocks), and is ! 1 if it has an odd number of blocks. This way we get the right parameter ! for DSEGMENT for the final segment. K = DAPSEG + DAPGAP - 1 FOR SEG = DAPSEG, 1, K CYCLE IF SEG < K THEN KK = 1 ELSE KK = J DSEGMENT(SEG ! (KK << 31)) REPEAT FLAG = DGETDA(PROCUSER, DAPFILE.SUFF, - 1, ADDR(SECTS( - 4))) ->OUT IF FLAG # 0 {but what about a nice flag?} DAPTIMEOUTFLAG = 0 CYCLE FLAG = 0 P = 0 P_DEST = (31 << 16) ! 1; ! Allocate P_P1 = ((((LIMIT + PLANE SIZE) << 2 {to bytes}) C + DAP BLOCK SIZE - 1) // DAP BLOCK SIZE) + EXTRA BLOCKS DAP STATE = DAP STATE ! SUPVR TOLD DOUTI(P) {This is where we CLAIM a DAP from SUPERVISOR} ! WRSNT("Status ", PROCLIST(UINF_PROCNO)_STATUS, X'32') FLAG = P_P1 PREC("Allocate: ", P, 0) UNLESS FLAG = 0 IF FLAG = -1 AND P_SRCE = X'1F0005' START ! DAP Claim request has been de-queued (abandoned) in response to a ! DAP STOP request (DAP Driver DACT=5). FLAG = 64 {DAP Claim de-queued} -> OUT FINISH FLAG = FLAG + 72 AND ->OUT IF FLAG # 0 DAP IDENT = P_P2 LOGICAL DAP NO = DAP IDENT >> 16 << 8 {see note in spec for supvr allocate call} DAP BLOCK NO = P_P3 + EXTRA BLOCKS DAP BLOCKS ALLOC = P_P4 - EXTRA BLOCKS DAP VREALADDR = ((DAP IDENT << 22) ! C (DAP BLOCK NO * DAP BLOCK SIZE) + X'1000000') ! X'80000000' ! This is a virtual address referencing the first page of the first ! DAP block of the current allocation. DATUM = (DAP BLOCK NO * DAP BLOCK SIZE {bytes}) >> 2 LIMIT = DATUM + (KBYTES << 8 {to words}) - PLANE SIZE XEXIT = PAGE TRANSFERS(FILE TO DAP) IF XEXIT = 0 START TRANSFER REC ADDR = ADDR(TRANSFER REC) {this variable tells whether a recursive call has been made} TRANSFER REC = 0 TRANSFER REC_DAP VREALADDR = DAP VREALADDR {to pass the right address to recursive calls} CYCLE IC = COME BACK AFTER IC = ILEFT IF ILEFT < COME BACK AFTER DAPSTARTP = 0 DAPSTARTP_DEST = (31 << 16) ! (LOGICAL DAP NO ! 4); ! Start DAPSTARTP_P1 = DATUM DAPSTARTP_P2 = LIMIT DAPSTARTP_P3 = COB DAPSTARTP_P4 = COL DAPSTARTP_P5 = NDPC DAPSTARTP_P6 = IC DPONI(DAPSTARTP) XEXIT = CHECK BTS TRANSFERS(AWAIT DAP STOP, 0) ! Result is zero if no page transfer failures have occurred, else 1 J = DAPSTARTP_SRCE & X'FFFF' DAPTIMEOUTFLAG = 44 AND XEXIT = 1 AND EXIT IF J = 11 IF J = 3 C THEN FLAG = 0 C ELSE START PREC("Start: ", DAPSTARTP, 0) FLAG = 72 XEXIT = 1 EXIT FINISH INSTAT = DAPSTARTP_P1 >> 24 NDPC = DAPSTARTP_P2 THIS = IC - DAPSTARTP_P4; ! amount used this time IUSED = IUSED + THIS ILEFT = ILEFT - THIS ! Now see if the special DAP STOP instruction has been executed. ! This is in connection with the block transfer system (BTS). IF DAPSTARTP_P5 {ILOG1} >> 20 = X'F7F' START UROUT FLAG = UROUTINE(DAPSTARTP_P5, DAPSTARTP_P6, NDPC) XEXIT = XEXIT ! UROUT FLAG ! Remove the DAP STOP bit, because we don't really want it to stop - quite the reverse INSTAT = INSTAT & (¬DAP STOP) FINISH XEXIT = XEXIT ! INSTAT & (DAP PROGERR ! DAP HWARE ERR ! DAP INTR ! DAP STOP ! HOST FORCED STOP) XEXIT = XEXIT ! 1 IF ILEFT <= 0 REPEAT UNTIL XEXIT # 0 OR DAPSTARTP_P1 {STATUS bits, 24-31} & SWAP OUT BIT # 0 XEXIT = XEXIT ! CHECK BTS TRANSFERS(FINISH TRANSFERS, -1) {ensure all BTS transfers complete} XEXIT = XEXIT ! PAGE TRANSFERS(DAP TO FILE) FINISH TRANSFER REC ADDR = 0 P = 0 P_DEST = (31 << 16) ! (LOGICAL DAP NO ! 2); ! De-allocate P_P1 = DAP IDENT P_P2 = DAP BLOCK NO - EXTRA BLOCKS P_P3 = DAP BLOCKS ALLOC + EXTRA BLOCKS DOUTI(P); ! De-allocate J = P_P1 UNLESS J = 0 AND FLAG = 0 START PREC("De-alloc: ", P, 0) FLAG = 67 IF FLAG = 0; ! may have been set to 72 by the DAP START DOUT above ->OUT FINISH DAP STATE = DAP STATE & ( ¬ SUPVR TOLD) REPEATUNTIL XEXIT # 0 UINF_DAPINSTRS = UINF_DAPINSTRS - IUSED MINSTRS = (IUSED + 500000) // 1000000 DSECS = (IUSED + DAP INSPERSEC - 1) // DAP INSPERSEC; ! round up for safety WRSNT("DAP stops.", MINSTRS, 5) WRSNT(" million instructions. Notional time", DSECS, 5) PRINTSTRING(" seconds ") FSYS = - 1 J = HINDA(PROCUSER, FSYS, INDAD, 0) IF J = 0 START H == RECORD(INDAD) H_DAPSECS = H_DAPSECS + DSECS FINISH ! ! Give back neccessary data from Image Store ! DAP_CONF = LOGICAL DAP NO >> 8 DAP_INSTAT = INSTAT DAP_ADVIOL = DAPSTARTP_P1 & X'00FFFF00' DAP_STATUS = DAPSTARTP_P1 & X'000000FF' DAP_NDPC = NDPC DAP_IC = IC DAP_DOLOG1 = (DAPSTARTP_P3 & X'FFFF8000') >> 15 DAP_DOLOG2 = DAPSTARTP_P3 & X'00007FFF' DAP_ILOG1 = DAPSTARTP_P5 DAP_ILOG2 = DAPSTARTP_P6 DAP_SECONDS = DAP_SECONDS - DSECS FLAG = UROUT FLAG IF FLAG = 0 THEN FLAG = DAPTIMEOUTFLAG {Error if non-zero} IF FLAG # 0 THEN ->OUT ->OK ! !-------------------------------------------------- ! SW(4): ! STOP PRINTSTRING("Stop ") FLAG = 67 {not claimed} ->OUT IF DAP STATE & CLAIMED = 0 FLAG = 72 ->OUT IF DAP STATE & SUPVR TOLD = 0 ! ! See comments above for DDAP ACT = 4, for the detailed effects of this ! message to Supervisor. P = 0 P_DEST = (31 << 16) ! (LOGICAL DAP NO ! 5); ! Stop DPONI(P) ->OK ! !-------------------------------------------------- ! SW(5): ! DAP RELATED DATA FSYS = - 1 FLAG = HINDA(PROCUSER, FSYS, INDAD, 0) ->OUT1 UNLESS FLAG = 0 ! J = COM_SECSFRMN - LAST PRINT J = J + 24*60*60 IF J < 0 IF J > 600 AND DTRYING = X'F7F7F7F7' START FLAG = 1; ! non-zero to indicate that print reqd LAST PRINT = COM_SECSFRMN PRINTSTRING("DAP Data ") FINISH ! H == RECORD(INDAD) DAP_CONF=DIRCOM_DAP INTEGER(1) {CLAIMQ LIMIT} DAP_SECONDS = H_DAPSECS DAP_BATCH LIMIT = DIRCOM_DAP INTEGER(4) {BATCH LIMIT} DAP_INTER LIMIT = DIRCOM_DAP INTEGER(2) {INTER LIMIT} CYCLE J = 0, 1, 2 USER = DIRCOM_DAP USER(J) DAP_DAP USER(J) = USER PRINTSTRING(TAG1(J) . USER) UNLESS FLAG = 0 REPEAT ! PRINTSTRING(",CB0 " . DIRCOM_DAP BATCH USER(0)) UNLESS FLAG = 0 PRINTSTRING(",CB1 " . DIRCOM_DAP BATCH USER(1)) UNLESS FLAG = 0 ! CYCLE J = 1, 1, 6 DAP_DAP INTEGER(J) = DIRCOM_DAP INTEGER(J) REPEAT ! DAP_DAP INTEGER(7) = 0 DAP_DAP INTEGER(8) = 0 J = 0 {count how many DAP's we have} J = 1 IF COM_CDR(1)_DAP STATE > 0 J = J + 1 IF COM_CDR(2)_DAP STATE > 0 PRINTSTRING(", " . ITOS(J) . " daps") UNLESS FLAG = 0 -> SW5(J) SW5(1): -> SW52 IF DIRCOM_DAP BATCH USER(1) = "" -> SW5(0) SW5(2): IF DIRCOM_DAP BATCH USER(1) = "" C THEN DAP_DAP INTEGER(8) = DIRCOM_DAP INTEGER(6) {HI B1} SW52: IF DIRCOM_DAP BATCH USER(0) = "" C THEN DAP_DAP INTEGER(7) = DIRCOM_DAP INTEGER(4) {HI B0} SW5(0): DAP_SPOOLR BATCH LIMIT = DAP_DAP INTEGER(7) -> OK1 IF FLAG = 0; ! no more printing reqd ! CYCLE J = 1, 1, 8 PRINTSTRING(TAG2(J)) WRITE(DAP_DAP INTEGER(J), 1) REPEAT SPACE ! ->OK ! !----------------------------------------------------------------------- ! SW(6): ! Give users running or queued for the DAP ! ADR is address of a %STRING(6)%ARRAY 1:20 ! initially all zeroes, into which this code ! places the usernames currently queued for or ! using the DAP. First username is the one which ! HAS the DAP. FLAG = 45 ->OUT IF VAL(ADR, 20*7, 1, DAP PSR) = 0 P = 0 P_DEST = (31<<16) ! 10 {enquire for queued users} DOUT11I(P) ! P_P1 holds number of users, P_P2 to P_P6 is a byte array of the process ! numbers. P_P1 = 0 UNLESS 0<=P_P1<=20 FOR J = 0, 1, P_P1-1 CYCLE {zero times round cycle if P_P1 zero} K = BYTEINTEGER(ADDR(P_P2)+J) {procno} ! Obtain username from proclist STRING(ADR) = PROCLIST(K)_USER ADR = ADR + 7 REPEAT -> OK1 SW(7): ! Specify (possibly asynchronous) ! transfers into and/or out of the DAP FLAG = INITIALISE REQUEST RECORDS IF FLAG # 0 THEN -> OUT -> OK1 SW(8): ! Await completion of specified, or all, ! transfers initiated via entry 7 REQ8 == RECORD(ADR) FLAG = CHECK BTS TRANSFERS(FINISH TRANSFERS, REQ8_IDENT) -> OUT IF FLAG # 0 -> OK1 OK: WRS("OK") OK1: RESULT = 0 OUT: WRSN(" Flag", FLAG) OUT1: RESULT = FLAG END ; ! DDAPI ! !----------------------------------------------------------------------- ! EXTERNALINTEGERFN DDAP(INTEGERFN A(INTEGER A, B, C), INTEGER B, C) INTEGER J J = IN2(256+96) -> OUT UNLESS J = 0 ! DAP ACR = D CALLERS ACR DAP PSR = D CALLERS PSR ! J = DDAPI(A, B, C) OUT: RESULT = OUT(J, "----II") END ; ! DDAP ! !----------------------------------------------------------------------- ! EXTERNALINTEGERFN DAZ(INTEGERFN A(INTEGER A, B, C), INTEGER B, C) INTEGER J J = IN2(256+96) -> OUT UNLESS J = 0 ! DAP ACR = D CALLERS ACR DAP PSR = D CALLERS PSR ! J = DDAPI(A, B, C) OUT: RESULT = OUT(J, "----II") END ; ! DAZ ! !----------------------------------------------------------------------- ! EXTERNALROUTINE DAP INTERFACE(INTEGER ACT) INTEGER J RECORD (DIRCOMF)NAME DIRCOM SWITCH SW(1 : 3) DIRCOM == RECORD(SYSAD(DIRCOMKEY, -1)) -> SW(ACT) SW(1): ! Set defaults in DIRCOM DIRCOM_DAP USER(0) = "" DIRCOM_DAP USER(1) = "" DIRCOM_DAP USER(2) = "" DIRCOM_DAP BATCH USER(0) = "" DIRCOM_DAP BATCH USER(1) = "" DIRCOM_DAP INTEGER(1) = 4 DIRCOM_DAP INTEGER(2) = 600 DIRCOM_DAP INTEGER(3) = 0 DIRCOM_DAP INTEGER(4) = 3600 DIRCOM_DAP INTEGER(5) = 0 DIRCOM_DAP INTEGER(6) = 3600 RETURN SW(2): ! Called at start of a batch job WRSNT(",DAPsecs=", UINF_DAPSECS, 5) J = UINF_DAP NO WRSNT(",DAPno=", J, 4) UINF_DAP NO = 0 UNLESS 0 <= J <= 1 WRS(",Slot=" . DIRCOM_DAP BATCH USER(UINF_DAP NO)) DIRCOM_DAP BATCH USER(UINF_DAP NO) = PROCUSER UINF_DAPINSTRS = LENGTHENI(UINF_DAPSECS) * DAPINSPERSEC RETURN SW(3): ! Called at DSTOP DIRCOM_DAP BATCH USER(UINF_DAP NO) = "" END ; ! DAP INTERFACE ! ! ! ENDOFFILE