!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