@X @~
~V7 56 2 -5
~D10
~H                    MUSS
~
~
~D10
~H            SYS034
~D10
~MMANCHESTER UNIVERSITY  -  CONFIDENTIAL~
~
~
                                                            ISSUE 11~
~V9 -1
~P
~V9 1
~YSYS034
~S~M~OSYS IMPLEMENTATION DESCRIPTION
~S~M~OSection 3 Version 4
~S~OSection 3.4 Drum Manager
~S~O1. General Description
~BThis module is responsible for the management of the backing
store (the "drum").  It consists of a process for servicing
interrupts from the drum and starting transfers, and a set
of interface procedures for allocating/de-allocating
space on the drum and queuing transfer requests.
~BIn this version all allocation/ de-allocation is done in units of a fixed size
known as blocks.  Only individual blocks can be allocated,  not contigous groups
.
This means the allocation algorithm can be fast and simple,  and external fragme
ntation
of the drum is avoided.  The block size is some multiple of SYS14.PAGE.SIZE.
Increaseing this multiple reduces the size of data structures describing
drum allocation,  thus saving core space and speeding up allocation procedures.
This must be weighed against the increase in internal fragmentation
with block size.
~BNot all the drum is available for allocation in the manner
described above.  There are two other main areas of the drum.  One contains
all the fixed drum space requirements for other modules,  i.e areas of a known
size which are not allocated or released.  Examples are the contents of common
segments and file master blocks.  The other main area contains the data about
drum segments needed by the drum manager itself.  Both these areas are of a fixe
d
configuration dependant size.
~BMost allocation and release of blocks is done indirectly,  by the
segment operations (see below).  However some parts of the system may require
to be able to allocate, release and use blocks directly. For example, the
file manager may use blocks for its directories.  Therefore a set of interface
procedures are provided for block operations.
~BThe second main feature of this version is the provision of segment
operations.  These provide all the backing store facilities required for
system segments and files.  The basis of these operations is a table,
known as a block table,  containing the addresses of the drum blocks making
up the segment.  The drum manager creates and maintains these block tables.
The block tables may be in core or on the drum, and in the latter case
they are kept in an area reserved for that purpose, as mentioned earlier.
This area can be read into core in its entirety during initialisation,
allowing easy access to the block tables of files.  This speeds up the
initialisation process.

~S~O2. Interfaces
~
Interrupt level interface procedures.
~
   TRANSFER.DRUM.BLOCK.PAGES (BLOCK.ADDR, PAGE.NO, CORE.ADDR,~
       SIZE, DIRECTION) STATUS~
   TRANSFER.DRUM.SEGMENT.PAGES (SSN, PAGE.NO, CORE.ADDR,~
       SIZE, DIRECTION) STATUS~
~
Command level interface procedures.
~
   ALLOCATE.DRUM.BLOCK () BLOCK.ADDR~
   RELEASE.DRUM.BLOCK (BLOCK.ADDR)~
   OPEN.DRUM.SEGMENT (SSN, SEG.ADDR, SEG.SIZE)~
   CLOSE.DRUM.SEGMENT (SSN)~
   CHANGE.DRUM.SEGMENT.SIZE (SSN, NEW.SIZE)~
   READ.DRUM.SEGMENT.ADDR (SSN) SEG.ADDR~
   PROTECT.DRUM.SEGMENT (SSN, PROTECT.STATUS)~
   SECURE.DRUM.SEGMENT (SSN)~
   RESERVE.DRUM.BLOCK (BLOCK.ADDR)~
   RESERVE.DRUM.SEGMENT (SEG.ADDR, SEG.SIZE)~
   DRUM.INITIALISATION.COMPLETE ()~
~
Configuration parameters
~
   DRUM.BLOCK.SIZE~
~S~O2.2 Software Interface
~
~
1) TRANSFER.DRUM.BLOCK.PAGES (BLOCK.ADDR, PAGE.NO, CORE.ADDR, SIZE, DIRECTION) S
TATUS
~BThis procedure transfers pages of data of size
SYS14.PAGE.SIZE between a drum block and pages in core.  BLOCK.ADDR
identifies the drum block involved, and PAGE.NO indicates at which
page of this block the transfer starts.  CORE.ADDR is the number of the
core page at which the transfer starts.  SIZE is the number of pages
transferred.  The DIRECTION parameter is a single bit, interpreted as
0 = read from drum, 1 = write to drum.  The calling process will be
halted till the transfer is complete.  A non-zero status is returned
if the transfer is unsuccessful, such as in the case of a faulty area
on the drum.
~BIf BLOCK.ADDR is zero then PAGE.NO is treated as the
address of a page on the disc.
~
~
~
2) TRANSFER.DRUM.SEGMENT.PAGES (SSN, PAGE.NO, CORE.ADDR, SIZE, DIRECTION) STATUS
~BThis procedure is identical to TRANSFER.DRUM.BLOCK.PAGES except that the
transfer is to or from an open drum segment instead of a drum block.  SSN
identifies the segment and PAGE.NO is the page within the segment at which
the transfer starts.
~
~
~
3) ALLOCATE.DRUM.BLOCK () BLOCK.ADDR
~BThis procedure allocates a free block on the drum and returns a value
BLOCK.ADDR which should be used to identify the block on subsequent
calls of drum management procedures.  The block is ~Onot~O cleared
to zero.
~
~
~
4) RELEASE.DRUM.BLOCK (BLOCK.ADDR)
~BA call of this procedure means that the block identified
by BLOCK.ADDR is no longer needed, and is free to be re-allocated.
~
~
~
5) OPEN.DRUM.SEGMENT (SSN, SEG.ADDR, SEG.SIZE)
~BThis procedure associates a system segment number SSN with a drum
segment and opens it, i.e. allows certain operations to be performed
on the segment.  The operations which can only be performed on a
open segment are TRANSFER.DRUM.SEGMENT.PAGES, CHANGE.DRUM.SEGMENT.SIZE,
PROTECT.DRUM.SEGMENT, READ.DRUM.SEGMENT.ADDR and CLOSE.DRUM.SEGMENT.
SEG.ADDR identifies the required drum segment and SEG.SIZE gives its size.
If SEG.ADDR is non-zero then it should be a value previously returned by
READ.DRUM.SEGMENT.ADDR.  If it is zero a new drum segment of the required size
will be created. Initially all blocks of this newly created segment will be
read as zero.
~
~
~
6) CLOSE.DRUM.SEGMENT (SSN)
~BThis procedure closes a drum segment, i.e. the segment is no longer
open and the operations listed under OPEN.DRUM.SEGMENT can no longer be
performed on it.  The parameter SSN identifies the currently open drum
segment to which this is done.  If the drum segment is unprotected
(see PROTECT.DRUM.SEGMENT) all the drum space allocated to it will be
released at this time.
~
~
~
7) CHANGE.DRUM.SEGMENT.SIZE (SSN, NEW.SIZE)
~BThis procedure changes the size of the open drum segment
identified by SSN to the new value NEW.SIZE.  Any attempt to change
the size of a protected segment will fail and an error status will be
returned in PW0.  A successful call of CHANGE.SIZE may result in the
segment identifier (the value normally referred to as SEG.ADDR)
changing, however the segment remains open and accessible using
the same SSN.
~
~
~
8) READ.DRUM.SEGMENT.ADDR (SSN) SEG.ADDR
~BThis procedure returns the drum segment identifier, SEG.ADDR,
associated with the open drum segment identified by SSN.  This can
be used in future calls to OPEN.DRUM.SEGMENT.  The result SEG.ADDR
is only valid if SECURE.DRUM.SEGMENT has been called for this segment
at some time prior to this.
~
~
~
9) PROTECT.DRUM.SEGMENT (SSN, PROTECT.STATUS)
~BCalling this procedure changes the protection status of the
open drum segment identified by SSN.  If PROTECT.STATUS is zero
the segment becomes unprotected and its drum space will be
released when CLOSE.DRUM.SEGMENT is called.  If PROTECT.STATUS
is one then the segment becomes protected and the drum space will
not be released.  CHANGE.DRUM.SEGMENT.SIZE operations are not
permitted on protected segments hence their segment identifier values
will not change.
~
~
~
10) SECURE.DRUM.SEGMENT (SSN)
~BThis procedure is called to ensure that all information
associated with the open drum segment identified by SSN has an
up to date copy on the disc.
~
~
~
11) RESERVE.DRUM.BLOCK (BLOCK.ADDR)
~BThis procedure is called to indicate that the drum block,
identified by BLOCK.ADDR is in use.  It is called as part of the
initialisation of the drum data structures. i.e. before
DRUM.INITIALISATION.COMPLETE is called.
~
~
~
12) RESERVE.DRUM.SEGMENT (SEG.ADDR, SEG.SIZE)
~BThis procedure is called to indicate that the segment identified
by SEG.ADDR of size SEG.SIZE is in use.  It is called as part
of the initialisation of the drum data structures, i.e. before
DRUM.INITIALISATION.COMPLETE is called.
~
~
~
13) DRUM.INITIALISATION.COMPLETE ()
~BThis procedure is called to indicate the end of the initialisation
of the drum data structures.  It is only called once each time the
system is restarted.  Before ths procedure is called the initialisation
procedures (RESERVE.DRUM.BLOCK and RESERVE.DRUM.SEGMENT) may be
called, but the allocation procedures (ALLOCATE.DRUM.BLOCK and
ALLOCATE.DRUM.SEGMENT) may not.  After this procedure is called the
opposite is true (initialisation procedures forbidden, allocation
procedures allowed).
Since SYS16, the file manager does most of this initialisation,
it normally calls this procedure.  So other modules requiring such
initialisation must precede the file manager in the initialisation
sequence.
~
~
~
14) DRUM.BLOCK.SIZE
~BThis literal is the fixed size of a drum block, in units of
SYS14.PAGE.SIZE bytes.
~S1~O3. Implementation
~S1~O3.1 Outline of Operation
~BBlocks are allocated using a modified first fit algorithm.
~BWhen a segment is created all its block table entries are flagged as
"blank".  This means that all reads from these blocks will produce blank
pages.  When a page of one of these blocks is written to, the flag
is cleared and blank pages are written to the other pages of that
block.
~BThe block table of a drum segment is divided into sub-tables.  Only
one of these sub-tables per system segment is in core at a given time.  If
the current core sub-table does not contain a required drum block address,  it
is replaced by the appropriate one from the disc.  Allocation of space on
the drum for block tables is done in units of sub-tables.  Drum sectors are
divided into an integral number of sub-tables,  hence one sector transfer is all
that is needed to obtain a sub-table from the drum.


~S1~O3.2 Data Structures
~T% 30
~
~
DRUM.SST.ENTRY~IThe type of an entry describing an opend drum
segment, with the form:-~
  :BLOCK.TABLE.ADDR~IThe address of this disc copy of the
block table.~
  :SEG.SIZE~IThe size of the segment in blocks.~
  :BLOCK.SUB.TABLE~IPart of the block table of the segment.~
DRUM.SST~IAn array of entries of type DRUM.SST.ENTRY, one
entry per system segment number.~
~
FREE.BLOCK.TABLES~IA bit map indicating which block table
locations on the drum are free for use.~
~
FREE.BLOCKS~IA bit map indicating which blocks of the
drum are free for use.
~S1~O3.3 Special Notes
~BA segment of size less than or equal to DRUM.BLOCK.SIZE has its
segment address interpreted directly as a block address not a block
table address.~
~V9 -1
~Y
~P
~V9 -1
~D15
~HFLOWCHARTS
~
~
~H               SYS034
~V9 -1
~F
@TITLE SYS03(4,11)
@COL 1S-2R-3R-4R-5R-6F

@FLOW 1-2-3-4-5-6
@BOX 1.0
DRUM MANAGER
@BOX 6.0
END
@BOX 1.1
#SYS03/1
MODULE SYS03 (DRUM.INTERRUPT, TRANSFER.DRUM.BLOCK.PAGES, TRANSFER.DRUM.SEGMENT.P
AGES,
   ALLOCATE.DRUM.BLOCK, RELEASE.DRUM.BLOCK, OPEN.DRUM.SEGMENT, CLOSE.DRUM.SEGMEN
T,
   CHANGE.DRUM.SEGMENT.SIZE, READ.DRUM.SEGMENT.ADDR, PROTECT.DRUM.SEGMENT,
   SECURE.DRUM.SEGMENT, RESERVE.DRUM.BLOCK, RESERVE.DRUM.SEGMENT,
   DRUM.INITIALISATION.COMPLETE, DRUM.TASK, STATS.TYPE, INITIALISE.DRUM.SEGMENT)
;
@BOX 2.1
TYPE DRUM.Q.ENTRY IS
   INTEGER CORE.SECTOR, NO.OF.SECTORS, DRUM.SECTION
   LOGICAL32 DRUM.SECTOR
   LOGICAL8 DIRN
   LOGICAL ACTIVITY;
TYPE STATS.TYPE IS
   INTEGER TRANSFERS.IN, TRANSFERS.OUT, SECTORS.TRANSFERRED;
TYPE BLOCK.TABLE.ENTRY IS
   LOGICAL16 BLOCK.ADDR
   LOGICAL8 [DRUM.BLOCK.SIZE.BIT.VEC.SIZE] USED.PAGE.MAP;
TYPE DRUM.SST.ENTRY IS
   INTEGER SEG.SIZE
   LOGICAL16 BLOCK.TABLE.ADDR
   INTEGER8 SUB.TABLE.NO
   LOGICAL8 STATE
   BLOCK.TABLE.ENTRY [SUB.TABLE.SIZE]BLOCK.SUB.TABLE;
@BOX 3.1
*GLOBAL 5;
LITERAL / INTEGER RETRY.LIMIT = 8, DRUM.FAIL = %301, ALLOCATE.FAIL = %302,
   RESERVE.FAIL = %303, DOUBLE.RESERVE = %304, DOUBLE.RELEASE = %305, DOUBLE.ALL
OCATE = %306,
   RELEASE.FAIL = %307, ALTERED = 2, PROTECTED = 1, LOCKED = 4;
LITERAL / LOGICAL TRANSFER.COMPLETE = %100, START.READ.TRANSFER = 1,
   START.WRITE.TRANSFER = 2;
INTEGER DRUM.Q.ON, DRUM.Q.OFF, DRUM.Q.COUNT, DRUM.RETRY.COUNT,
    NEXT.FREE.BLOCK, SECTOR.BUF.LOCK, SECTOR.BUF.LOCK.ACTIVITIES;
DRUM.Q.ENTRY [SYS01.NO.OF.ACTIVITIES] DRUM.Q;
INTEGER [SYS01.NO.OF.ACTIVITIES] TRANSFER.STATUS, LOCKED.SEGMENT;
*GLOBAL 30;
DRUM.SST.ENTRY [SYS14.NO.OF.SYS.SEGS] DRUM.SST;
*GLOBAL 5;
INTEGER DRUM.SIZE, DRUM.SIZE.BIT.VEC.SIZE, TABLE.AREA.SIZE,
   TABLE.AREA.SIZE.BIT.VEC.SIZE, SECTORS.PER.PAGE, SUB.TABLES.PER.SECTOR,
   NEW.BLOCK.TABLE.ADDR;
BLOCK.TABLE.ENTRY ZERO.BLOCK.TABLE.ENTRY;
LOGICAL16 NEW.BLOCK;
ADDR STATS.TYPE STATS;
ADDR [BLOCK.TABLE.ENTRY] SECTOR.BUFF;
BLOCK.TABLE.ENTRY [MAX.SEG.SIZE] BLOCK.TABLE;
@BOX 4.1
#SYS03/2
@BOX 5.1
::*INIT %6000;
*CODE 7;
PSPEC INIT.SYS03 ();
INIT.SYS03 ();
PROC INIT.SYS03;
INTEGER I;
MAKE (STATS.TYPE, 0, SYS21.GET.STATS (3)) => STATS;
MAKE (BLOCK.TABLE.ENTRY, SECTOR.SIZE / BLOCK.TABLE.ENTRY.SIZE, SECTOR.BUFF.VA)
   => SECTOR.BUFF;
0 => DRUM.Q.ON => DRUM.Q.COUNT => NEXT.FREE.BLOCK;
1 => DRUM.Q.OFF;
SYS14.PAGE.SIZE / SECTOR.SIZE => SECTORS.PER.PAGE;
SUB.TABLE.SIZE * BLOCK.TABLE.ENTRY.SIZE /: SECTOR.SIZE => SUB.TABLES.PER.SECTOR;
SIZE (FREE.BLOCKS) => DRUM.SIZE.BIT.VEC.SIZE * 8 => DRUM.SIZE;
SIZE (FREE.SUB.TABLES) => TABLE.AREA.SIZE.BIT.VEC.SIZE
   * 8 => TABLE.AREA.SIZE;
SYS20.SET.TASK (SYS20.DRUM.TASK, 0);
END
@BOX 6.1
*END
@END
@TITLE SYS03/1(4,11)

@COL 1S-2R-3R-4R
@FLOW 1-2-3-4
@BOX 1.0
OTHER MODULES REFERENCED
@BOX 4.0
SYS01 COORDINATOR
SYS02 CORE MANAGER
SYS08 REAL TIME CLOCK
SYS13 PROCESS MANAGER
SYS14 VIRTUAL STORE MANAGER
SYS16 FILE MANAGER
@BOX 1.1
:: EXTERNAL ENVIRONMENT
@BOX 2.1
IMPORT VSTORE V.DRUM.CONTROL, V.DRUM.SIZE, V.DRUM.CADDRESS, V.DRUM.SECTION,
   V.CLEAR.PAGE;
IMPORT VSTORE LOGICAL32 V.DRUM.DADDRESS;
IMPORT LITERAL DRUM.BLOCK.SIZE, DRUM.BLOCK.SIZE.BIT.VEC.SIZE,
   SUB.TABLE.SIZE, MAX.SEG.SIZE, BLOCK.TABLE.ENTRY.SIZE;
INTEGER SECTOR.BUFF.RA, SECTOR.SIZE, CLEAR.PAGE.ADDR;
ADDR SECTOR.BUFF.VA;
LOGICAL32 TABLE.AREA.ADDR;
LOGICAL16  BLOCK.AREA.ADDR;
ADDR CORE.TABLE.AREA.VA;
INTEGER32 CORE.TABLE.AREA.RA;
ADDR [LOGICAL8] FREE.BLOCKS, FREE.SUB.TABLES;
IMPORT LITERAL PAGED.DATA.SEG, PAGED.DATA.MAPPED.SEG, BYTES.PER.WORD,
   NO.OF.DRUM.SECTIONS;
LOGICAL8 [NO.OF.DRUM.SECTIONS] DRUM.SECTION.AVAILABLE;
LOGICAL32 [NO.OF.DRUM.SECTIONS] DRUM.SECTION.SIZE;
@BOX 3.1
PSPEC SET.BIT (ADDR [LOGICAL8], INTEGER);
PSPEC CLEAR.BIT (ADDR [LOGICAL8], INTEGER);
PSPEC TEST.BIT (ADDR [LOGICAL8], INTEGER) / INTEGER;
PSPEC MS.BIT (LOGICAL) / INTEGER;
PSPEC BIT (INTEGER) / LOGICAL;
@BOX 4.1
IMPORT LITERAL SYS01.NO.OF.ACTIVITIES, SYS01.DRUM.ACTIVITY, SYS01.DTQ.HALT;
INTEGER SYS01.CURRENT.ACTIVITY;
LOGICAL SYS01.CURRENT.ACTIVITY.BIT;
PSPEC SYS01.NEXT.ACTIVITY ();
PSPEC SYS01.HALT (LOGICAL, INTEGER);
PSPEC SYS01.FREE (LOGICAL, INTEGER);
PSPEC SYS01.CLEAR.INTERRUPT ();
PSPEC SYS01.CHECK.IN (INTEGER, INTEGER);
PSPEC SYS01.CHECK.OUT (INTEGER, INTEGER);
IMPORT LITERAL SYS02.CORE.PAGE.SIZE;
PSPEC SYS02.RELEASE.PAGE (INTEGER, INTEGER);
PSPEC SYS08.START.DEVICE.CLOCK (LOGICAL);
PSPEC SYS08.STOP.DEVICE.CLOCK (LOGICAL);
PSPEC SYS12.SYSTEM.ERROR (INTEGER);
IMPORT LITERAL SYS13.NO.OF.PROCS;
INTEGER SYS13.CURRENT.SPN;
LOGICAL [SYS13.NO.OF.PROCS] SYS13.PROC.RESULT;
PSPEC SYS13.INT.PROC (LOGICAL, LOGICAL);
PSPEC SYS13.ENTER.INT.LEVEL (ADDR SYS13.INT.PROC, LOGICAL, LOGICAL);
IMPORT LITERAL SYS14.NO.OF.SYS.SEGS, SYS14.PAGE.SIZE, SYS14.PAGE.SHIFT;
PSPEC SYS14.MAP.ADDRESS (INTEGER32, INTEGER)  / ADDR [LOGICAL8];
PSPEC SYS14.CMD.MAP (INTEGER, INTEGER);
IMPORT LITERAL SYS20.DRUM.TASK;
PSPEC SYS20.SET.TASK (INTEGER, INTEGER);
PSPEC SYS21.GET.STATS (INTEGER) / ADDR;
ADDR PW0, PW1;
@END
@TITLE SYS03/2(4,11)
@COL 1S
@FLOW 1
@BOX 1.0
PROCEDURES IN MODULE:
   INT1 DRUM INTERRUPT
   INT2 TRANSFER SECTORS
   INT3 START TRANSFER
   INT4 TRANSFER DRUM BLOCK PAGES
   INT5 TRANSFER DRUM SEGMENT PAGES
   INT6 GET SUB TABLE
   INT7 SECURE SUB TABLE
   INT8 CLEAR BLOCK
   INT9 INITIALISE DRUM SEGMENT
   INT10 GET BLOCK TABLE AREA
   INT11 LOCK DRUM SEGMENT
   INT12 UNLOCK DRUM SEGMENT
   INT13 ALLOCATE BLOCK
   INT14 RELEASE BLOCK
   INT15 CHANGE SIZE
   CMD1 ALLOCATE DRUM BLOCK
   CMD2 RELEASE DRUM BLOCK
   CMD3 OPEN DRUM SEGMENT
   CMD4 CLOSE DRUM SEGMENT
   CMD5 CHANGE DRUM SEGMENT SIZE
   CMD6 READ DRUM SEGMENT ADDR
   CMD7 PROTECT DRUM SEGMENT
   CMD8 SECURE DRUM SEGMENT
   CMD9 ALLOCATE BLOCK TABLE
   CMD10 RELEASE BLOCK TABLE
   CMD11 RESERVE DRUM BLOCK
   CMD12 RESERVE DRUM SEGMENT
   CMD13 DRUM INITIALISATION COMPLETE
   TSK1 DRUM TASK
@BOX 1.1
*CODE 2;
PSPEC DRUM.INTERRUPT ();
PSPEC TRANSFER.SECTORS (LOGICAL32, INTEGER, INTEGER, INTEGER) / INTEGER;
PSPEC START.TRANSFER ();
PSPEC TRANSFER.DRUM.BLOCK.PAGES (LOGICAL, INTEGER, INTEGER, INTEGER,
      INTEGER) / INTEGER;
PSPEC TRANSFER.DRUM.SEGMENT.PAGES (INTEGER, INTEGER, INTEGER, INTEGER,
      INTEGER) / INTEGER;
PSPEC GET.SUB.TABLE (LOGICAL, LOGICAL);
PSPEC SECURE.SUB.TABLE (LOGICAL, LOGICAL);
PSPEC CLEAR.BLOCK (LOGICAL, LOGICAL);
PSPEC GET.BLOCK.TABLE.AREA (LOGICAL, LOGICAL);
PSPEC LOCK.DRUM.SEGMENT (INTEGER);
PSPEC UNLOCK.DRUM.SEGMENT(INTEGER);
PSPEC ALLOCATE.BLOCK (LOGICAL, LOGICAL);
PSPEC RELEASE.BLOCK (LOGICAL, LOGICAL);
PSPEC CHANGE.SIZE (LOGICAL, LOGICAL);
   #SYSINT03.1
   #SYSINT03.2
   #SYSINT03.3
   #SYSINT03.4
   #SYSINT03.5
   #SYSINT03.6
   #SYSINT03.7
   #SYSINT03.8
   #SYSINT03.10
   #SYSINT03.11
   #SYSINT03.12
   #SYSINT03.13
   #SYSINT03.14
   #SYSINT03.15
*CODE 7;
PSPEC INITIALISE.DRUM.SEGMENT (INTEGER, LOGICAL32, INTEGER, INTEGER);
   #SYSINT03.9
*CODE 26;
PSPEC ALLOCATE.DRUM.BLOCK () / LOGICAL;
PSPEC RELEASE.DRUM.BLOCK (LOGICAL);
PSPEC OPEN.DRUM.SEGMENT (INTEGER, LOGICAL32, INTEGER);
PSPEC CLOSE.DRUM.SEGMENT (INTEGER);
PSPEC CHANGE.DRUM.SEGMENT.SIZE (INTEGER, INTEGER);
PSPEC READ.DRUM.SEGMENT.ADDR (INTEGER) / LOGICAL32;
PSPEC PROTECT.DRUM.SEGMENT (INTEGER, INTEGER);
PSPEC SECURE.DRUM.SEGMENT (INTEGER);
PSPEC ALLOCATE.BLOCK.TABLE (INTEGER) / LOGICAL;
PSPEC RELEASE.BLOCK.TABLE (LOGICAL, INTEGER);
PSPEC RESERVE.DRUM.BLOCK (LOGICAL);
PSPEC RESERVE.DRUM.SEGMENT (LOGICAL32, INTEGER);
PSPEC DRUM.INITIALISATION.COMPLETE ();
   #SYSCMD03.1
   #SYSCMD03.2
   #SYSCMD03.3
   #SYSDMD03.4
   #SYSCMD03.5
   #SYSCMD03.6
   #SYSCMD03.7
   #SYSCMD03.8
   #SYSCMD03.9
   #SYSCMD03.10
   #SYSCMD03.11
   #SYSCMD03.12
   #SYSCMD03.13
PSPEC DRUM.TASK ();
   #SYSTSK03.1
@END

@TITLE SYSINT03.1(4,11)
@COL 1S-17N-2R-3R-15R-4T-12T-16R-5R-6T-7R-8R-9N-11F
@COL 18N-13R-19N-14R-10N

@ROW 17-18
@ROW 13-16
@ROW 7-14
@ROW 9-10

@FLOW 1-17-2-3-15-4YES-5-6-7-8-9-17
@FLOW 4NO-12YES-13-19-18-17
@FLOW 12NO-16-5
@FLOW 6NONE-14-10-9
@BOX 1.0
DRUM INTERRUPT
@BOX 2.0
CALL LOW LEVEL SCHEDULER
[SYS01]
@BOX 3.0
CLEAR SOFTWARE INTERRUPT
FOR CURRENT ACTIVITY
[SYS01]
@BOX 4.0
TRANSFER SUCCESSFUL ?
@BOX 5.0
FREE ACTIVITY HALTED
FOR THIS TRANSFER
[SYS01]
@BOX 6.0
MOVE TO NEXT ENTRY
IN DRUM TRANSFER QUEUE
@BOX 7.0
INITIALISE RETRY COUNT
@BOX 8.0
START TRANSFER AND RESET
DEVICE CLOCK
#SYSINT03.3
@BOX 11.0
END
@BOX 12.0
RETRY REQUIRED?
@BOX 13.0
START TRANSFER AND RESET
DEVICE CLOCK
#SYSINT03.3
@BOX 14.0
RESET INTERRUPT FOR THE
DEVICE
@BOX 15.0
STOP DEVICE CLOCK
[SYS08]
@BOX 16.0
RETURN FAULT TO ACTIVITY
@BOX 1.1
PROC DRUM.INTERRUPT;
@BOX 2.1
SYS01.NEXT.ACTIVITY ();
@BOX 3.1
SYS01.CLEAR.INTERRUPT ();
@BOX 4.1
IF V.DRUM.CONTROL & TRANSFER.COMPLETE /= 0
@BOX 5.1
SYS01.FREE (ACTIVITY OF DRUM.Q [DRUM.Q.OFF], SYS01.DTQ.HALT);
@BOX 6.1
IF 1 +> DRUM.Q.OFF = SYS01.NO.OF.ACTIVITIES THEN
   0 => DRUM.Q.OFF
FI
IF 1 -> DRUM.Q.COUNT = 0
@BOX 7.1
RETRY.LIMIT => DRUM.RETRY.COUNT;
@BOX 8.1
START.TRANSFER ();
@BOX 11.1
END
@BOX 12.1
IF 1 -> DRUM.RETRY.COUNT >= 0
@BOX 13.1
START.TRANSFER ();
@BOX 14.1
0 => V.DRUM.CONTROL;
@BOX 15.1
SYS08.STOP.DEVICE.CLOCK (SYS01.DRUM.ACTIVITY);
@BOX 16.1
-1 => TRANSFER.STATUS [MS.BIT (ACTIVITY OF DRUM.Q [DRUM.Q.OFF])];
@END
@TITLE SYSINT03.2(4,11)
@COL 1S-9T-4R-5T-6R-7R-2R-8F
@COL 10R
@FLOW 1-9NO-4-5NO-6-7-2-8
@FLOW 5YES-2-8
@FLOW 9YES-10-8
@BOX 1.0
TRANSFER.SECTORS (DRUM.ADDR, CORE.ADDR,
   TRANSFER SIZE, DIRECTION)
@BOX 2.0
HALT CURRENT ACTIVITY
FOR DRUM TRANSFER
[SYS01]
@BOX 4.0
ALLOCATE AN ENTRY ON THE QUEUE
AND INSERT TRANSFER INFORMATION
@BOX 5.0
ANY OTHER ENTRIES ON THE QUEUE ?
@BOX 6.0
INITIALISE RETRY COUNT
@BOX 7.0
START TRANSFER AND RESET
DEVICE CLOCK
@BOX 8.0
END
@BOX 9.0
IS DRUM SECTION AVAILABLE?
@BOX 10.0
RETURN FAULT STATUS
@BOX 1.1
PROC TRANSFER.SECTORS (DRUM.ADDR, CORE.ADDR,
   TRANSFER.SIZE, DIRECTION);
INTEGER D.SECTION;
LOGICAL32 SECTION.START;
@BOX 2.1
0 => TRANSFER.STATUS [SYS01.CURRENT.ACTIVITY];
SYS01.HALT (SYS01.CURRENT.ACTIVITY.BIT, SYS01.DTQ.HALT);
TRANSFER.STATUS [SYS01.CURRENT.ACTIVITY] => TRANSFER.SECTORS;
@BOX 4.1
IF 1 +> DRUM.Q.ON = SYS01.NO.OF.ACTIVITIES THEN
   0 => DRUM.Q.ON;
FI
SELECT DRUM.Q [DRUM.Q.ON];
TRANSFER.SIZE => NO.OF.SECTORS;
D.SECTION => DRUM.SECTION;
DRUM.ADDR - SECTION.START => DRUM.SECTOR;
CORE.ADDR => CORE.SECTOR;
SYS01.CURRENT.ACTIVITY.BIT => ACTIVITY;
DIRECTION => DIRN;
@BOX 5.1
IF 1 +> DRUM.Q.COUNT /= 1
@BOX 6.1
RETRY.LIMIT => DRUM.RETRY.COUNT;
@BOX 7.1
START.TRANSFER ();
@BOX 8.1
END
@BOX 9.1
0 => SECTION.START;
FOR D.SECTION < NO.OF.DRUM.SECTIONS DO
   IF DRUM.SECTION.SIZE [D.SECTION]
      + SECTION.START > DRUM.ADDR, -> OUT;
   DRUM.SECTION.SIZE [D.SECTION] +> SECTION.START;
OD
OUT:
IF D.SECTION = NO.OF.DRUM.SECTIONS OR
   DRUM.SECTION.AVAILABLE [D.SECTION] = 0
@BOX 10.1
1 => TRANSFER.SECTORS;
@END
@TITLE SYSINT03.3(4,11)

@COL 1S-2R-3R-4F

@FLOW 1-2-3-4
@BOX 1.0
START TRANSFER
@BOX 2.0
START DEVICE CLOCK
[SYS08]
@BOX 3.0
WRITE TRANSFER INFORMATION
TO DRUM CONTROL REGISTERS
@BOX 4.0
END
@BOX 1.1
PROC START.TRANSFER;
@BOX 2.1
SELECT DRUM.Q [DRUM.Q.OFF];
IF NO.OF.SECTORS =< SECTORS.PER.PAGE THEN
   SYS08.START.DEVICE.CLOCK (SYS01.DRUM.ACTIVITY);
FI
@BOX 3.1
NO.OF.SECTORS => V.DRUM.SIZE;
CORE.SECTOR => V.DRUM.CADDRESS;
DRUM.SECTION => V.DRUM.SECTION;
DRUM.SECTOR => V.DRUM.DADDRESS;
NO.OF.SECTORS +> SECTORS.TRANSFERRED OF STATS^;
IF DIRN = 0 THEN
   START.READ.TRANSFER => V.DRUM.CONTROL;
   1 +> TRANSFERS.IN OF STATS^;
ELSE
   START.WRITE.TRANSFER => V.DRUM.CONTROL;
   1 +> TRANSFERS.OUT OF STATS^;
FI
@BOX 4.1
END
@END
@TITLE SYSINT03.4(4,11)
@COL 1S-2R-3F
@FLOW 1-2-3
@BOX 1.0
@BOX 1.0
TRANSFER DRUM BLOCK PAGES (BLOCK ADDRESS, PAGE NO.,
   CORE ADDRESS, TRANSFER SIZE, DIRECTION)
@BOX 2.0
CALCULATE SECTOR ADDRESSES
AND TRANSFER SECTORS
[SYSINT03.2]
@BOX 3.0
END
@BOX 1.1
PROC TRANSFER.DRUM.BLOCK.PAGES (BLOCK.ADDR, PAGE.NO, CORE.ADDR,
   TRAN.SIZE, DIRECTION);
@BOX 2.1
TRANSFER.SECTORS (BLOCK.ADDR * DRUM.BLOCK.SIZE + PAGE.NO * SECTORS.PER.PAGE,
   CORE.ADDR * SECTORS.PER.PAGE, TRAN.SIZE * SECTORS.PER.PAGE, DIRECTION)
   => TRANSFER.DRUM.BLOCK.PAGES;
@BOX 3.1
END
@END
@TITLE SYSINT03.5(4,11)
@COL 1S-2T-20R-3T-4T-5R-24T-25T-6T-7T-8R-9R-10R-11T-21N-22R-19N-12R-13F
@COL 14R-17N-15R-16R-23N-18N
@ROW 3-14
@ROW 4-17
@ROW 8-15
@ROW 19-18
@ROW 23-21
@FLOW 1-2NO-20-3NO-4OK-5-24NO-25OK-6NO-7NO-8-9-10-11NO-21-22-19-12-13
@FLOW 2YES-14-18-19
@FLOW 3YES-5
@FLOW 4FAIL-17-23-21
@FLOW 6YES-9
@FLOW 7YES-15-16-11YES-3
@FLOW 24YES-6
@FLOW 25FAIL-23
@BOX 1.0
TRANSFER DRUM SEGMENT PAGES (SYSTEM SEGMENT NUMBER,
   PAGE NO., CORE ADDRESS, TRANSFER SIZE, DIRECTION)
@BOX 2.0
IS SEGMENT A SINGLE
BLOCK?
@BOX 3.0
IS REQUIRED SUB-TABLE
IN CORE?
@BOX 4.0
GET SUB-TABLE
[SYSINT03.6]
@BOX 5.0
DETERMINE BLOCK, PAGE
WITHIN BLOCK AND TRANSFER
SIZE
@BOX 6.0
WRITING TO DRUM?
@BOX 7.0
READING FROM UNUSED
PAGES?
@BOX 8.0
CHECK TRANSFER SIZE
@BOX 9.0
TRANSFER REQUIRED PAGES
IN SECTORS
[SYSINT03.2]
@BOX 10.0
NOTE WHICH UNUSED PAGES
ARE WRITTEN TO
@BOX 11.0
STILL PAGES TO TRANSFER?
@BOX 12.0
RETURN STATUS
@BOX 13.0
END
@BOX 14.0
TRANSFER REQUIRED
PAGES IN SECTORS
[SYSINT03.2]
@BOX 15.0
DETERMINE NUMBER
OF PAGES TO CLEAR
@BOX 16.0
CLEAR PAGES
@BOX 20.0
LOCK DRUM SEGMENT
[SYSINT03.11]
@BOX 22.0
UNLOCK DRUM SEGMENT
[SYSINT03.12]
@BOX 24.0
BLOCK ALREADY ALLOCATED?
@BOX 25.0
ALLOCATE BLOCK
@BOX 1.1
PROC TRANSFER.DRUM.SEGMENT.PAGES (SSN, PAGE.NO, CORE.ADDR,
   TRAN.SIZE, DIRECTION);
INTEGER STATUS, BLOCK.NO, SUB.TABLE.NUMBER, BLOCK.PAGE,
   TRANSFER.SIZE, I, J;
0 => STATUS;
@BOX 2.1
SELECT DRUM.SST [SSN];
IF SEG.SIZE = 1
@BOX 3.1
IF DRUM.BLOCK.SIZE * SUB.TABLE.SIZE /: PAGE.NO
   => SUB.TABLE.NUMBER = SUB.TABLE.NO
@BOX 4.1
GET.SUB.TABLE (SSN, SUB.TABLE.NUMBER);
IF TRANSFER.STATUS [SYS01.CURRENT.ACTIVITY]
   => STATUS /= 0
@BOX 5.1
SUB.TABLE.NO * SUB.TABLE.SIZE * DRUM.BLOCK.SIZE
   -: PAGE.NO => BLOCK.PAGE / DRUM.BLOCK.SIZE
   => BLOCK.NO * DRUM.BLOCK.SIZE -> BLOCK.PAGE;
IF DRUM.BLOCK.SIZE - BLOCK.PAGE
   => TRANSFER.SIZE > TRAN.SIZE THEN
   TRAN.SIZE => TRANSFER.SIZE;
FI
@BOX 6.1
IF DIRECTION = 1
@BOX 7.1
IF TEST.BIT (^USED.PAGE.MAP, BLOCK.PAGE) = 0
@BOX 8.1
0 => I;
WHILE 1 +> I < TRANSFER.SIZE
   AND TEST.BIT (^USED.PAGE.MAP,
   BLOCK.PAGE + I) /= 0 DO OD
I => TRANSFER.SIZE;
@BOX 9.1
TRANSFER.SECTORS (BLOCK.ADDR * DRUM.BLOCK.SIZE
   + BLOCK.PAGE * SECTORS.PER.PAGE,
   CORE.ADDR * SECTORS.PER.PAGE,
   TRANSFER.SIZE * SECTORS.PER.PAGE, DIRECTION) !> STATUS;
@BOX 10.1
IF DIRECTION = 1 THEN
   FOR I < TRANSFER.SIZE DO
      IF TEST.BIT (^USED.PAGE.MAP, BLOCK.PAGE + I) = 0 THEN
         SET.BIT (^USED.PAGE.MAP, BLOCK.PAGE + I);
         ALTERED !> STATE;
      FI
   OD
FI
@BOX 11.1
TRANSFER.SIZE +> PAGE.NO;
TRANSFER.SIZE +> CORE.ADDR;
IF TRANSFER.SIZE -> TRAN.SIZE /= 0
@BOX 12.1
STATUS => TRANSFER.DRUM.SEGMENT.PAGES;
@BOX 13.1
END
@BOX 14.1
IF BLOCK.TABLE.ADDR /= 0 THEN
    TRANSFER.SECTORS (BLOCK.TABLE.ADDR
      * DRUM.BLOCK.SIZE + PAGE.NO * SECTORS.PER.PAGE,
      CORE.ADDR * SECTORS.PER.PAGE,
      TRAN.SIZE * SECTORS.PER.PAGE, DIRECTION)
      => STATUS;
ELSE
   1 => STATUS;
FI
@BOX 15.1
0 => I;
WHILE 1 +> I < TRANSFER.SIZE
AND TEST.BIT (^USED.PAGE.MAP, BLOCK.PAGE
    + I) = 0 DO OD
I => TRANSFER.SIZE;
@BOX 16.1
FOR I < TRANSFER.SIZE DO
   CORE.ADDR + I => V.CLEAR.PAGE;
OD
@BOX 20.1
LOCK.DRUM.SEGMENT (SSN);
@BOX 22.1
UNLOCK.DRUM.SEGMENT (SSN);
@BOX 24.1
SELECT BLOCK.SUB.TABLE [BLOCK.NO];
IF BLOCK.ADDR /= 0
@BOX 25.1
ALLOCATE.BLOCK (0, 0);
IF NEW.BLOCK => BLOCK.ADDR /= 0 THEN
   FOR I < DRUM.BLOCK.SIZE.BIT.VEC.SIZE DO
      0 => USED.PAGE.MAP [I];
   OD
   ALTERED !> STATE;
ELSE
   1 => STATUS;
FI
IF STATUS /= 0
@END
@TITLE SYSINT03.6(4,11)
@COL 1S-9R-2T-3T-8T-5R-6R-7F
@COL 10R-4R-11R-12T
@ROW 10-3
@FLOW 1-9-2NO-3OK-8NO-5-6-7
@FLOW 2YES-10-4-11-12NO-6
@FLOW 12YES-5
@FLOW 3FAIL-6
@FLOW 8YES-4
@BOX 1.0
GET SUB TABLE (SYSTEM SEGMENT NUMBER,
   REQUIRED SUB TABLE NUMBER)
@BOX 2.0
IS CURRENT SUB-TABLE
UNALTERED?
@BOX 3.0
SECURE CURRENT SUB TABLE
TO DRUM
[SYSINT03.7]
@BOX 4.0
READ REQUIRED
SECTOR FROM DRUM
[SYSINT03.2]
@BOX 5.0
COPY SUB-TABLE FROM
SECTOR
@BOX 6.0
RETURN STATUS
@BOX 7.0
END
@BOX 8.0
IS CURRENT SECTOR DIFFERENT FROM
REQUIRED ONE?
@BOX 9.0
DETERMINE REQUIRED SECTOR NUMBER
@BOX 10.0
CHECK SECTOR BUFFER LOCK
@BOX 11.0
FREE HALTED ACTIVITES
@BOX 12.0
DID TRANSFER SUCCEED?
@BOX 1.1
PROC GET.SUB.TABLE (SSN, REQ.SUB.TABLE.NO);
INTEGER STATUS, I, SPN, TABLE.START;
LOGICAL32 SECTOR.NO;
SYS13.CURRENT.SPN => SPN;
@BOX 2.1
IF SUB.TABLE.NO < 0 OR STATE & ALTERED = 0
@BOX 3.1
SECURE.SUB.TABLE (SSN, 0)
IF TRANSFER.STATUS [SYS01.CURRENT.ACTIVITY]
   => STATUS /= 0
@BOX 4.1
TRANSFER.SECTORS (SECTOR.NO, SECTOR.BUFF.RA, 1, 0) => STATUS;
@BOX 5.1
SECTOR.NO - TABLE.AREA.ADDR * SUB.TABLES.PER.SECTOR -: TABLE.START
   * SUB.TABLE.SIZE => TABLE.START;
FOR I < SUB.TABLE.SIZE DO
   SECTOR.BUFF^ [TABLE.START + I]
      => BLOCK.SUB.TABLE [I];
OD
REQ.SUB.TABLE.NO => SUB.TABLE.NO;
STATE & ALTERED -=> STATE;
@BOX 6.1
STATUS => TRANSFER.STATUS [SYS01.CURRENT.ACTIVITY]
   => SYS13.PROC.RESULT [SPN];
@BOX 7.1
END
@BOX 8.1
IF BLOCK.TABLE.ADDR + SUB.TABLE.NO / SUB.TABLES.PER.SECTOR
   + TABLE.AREA.ADDR /= SECTOR.NO
@BOX 9.1
SELECT DRUM.SST [SSN];
BLOCK.TABLE.ADDR + REQ.SUB.TABLE.NO => TABLE.START / SUB.TABLES.PER.SECTOR
   + TABLE.AREA.ADDR => SECTOR.NO;
@BOX 10.1
WHILE SECTOR.BUF.LOCK /= 0 DO
   SYS01.CURRENT.ACTIVITY.BIT !> SECTOR.BUF.LOCK.ACTIVITIES;
   SYS01.HALT (SYS01.CURRENT.ACTIVITY.BIT, SYS01.DTQ.HALT);
OD
1 => SECTOR.BUF.LOCK;
@BOX 11.1
SYS01.FREE (SECTOR.BUF.LOCK.ACTIVITIES, SYS01.DTQ.HALT);
0 => SECTOR.BUF.LOCK.ACTIVITIES => SECTOR.BUF.LOCK;
@BOX 12.1
IF STATUS = 0
@END
@TITLE SYSINT03.7(4,11)
@COL 1S-7R-2T-3R-4R-8R-5R-6F
@FLOW 1-7-2OK-3-4-8-5-6
@FLOW 2FAIL-8
@BOX 1.0
SECURE SUB-TABLE (SYSTEM SEGMENT NUMBER, DUMMY)
@BOX 2.0
READ SECTOR CONTAINING
CURRENT SUB-TABLE FROM
DRUM
[SYSINT03.2]
@BOX 3.0
COPY SUB-TABLE INTO
SECTOR
@BOX 4.0
WRITE SECTOR BACK
TO DRUM
[SYSINT03.2]
@BOX 5.0
RETURN STATUS
@BOX 6.0
END
@BOX 7.0
CHECK SECTOR BUFFER LOCK
@BOX 8.0
FREE HALTED ACTIVITES
@BOX 1.1
PROC SECURE.SUB.TABLE (SSN, DUMMY);
INTEGER STATUS, I, SPN, TABLE.START;
LOGICAL32 SECTOR.NO;
SYS13.CURRENT.SPN => SPN;
@BOX 2.1
SELECT DRUM.SST [SSN];
BLOCK.TABLE.ADDR + SUB.TABLE.NO => TABLE.START / SUB.TABLES.PER.SECTOR
   + TABLE.AREA.ADDR => SECTOR.NO;
IF TRANSFER.SECTORS (SECTOR.NO, SECTOR.BUFF.RA, 1, 0) => STATUS /= 0
@BOX 3.1
SECTOR.NO - TABLE.AREA.ADDR * SUB.TABLES.PER.SECTOR -: TABLE.START
   * SUB.TABLE.SIZE => TABLE.START;
FOR I < SUB.TABLE.SIZE DO
   BLOCK.SUB.TABLE [I]
      => SECTOR.BUFF^ [TABLE.START + I];
OD
@BOX 4.1
TRANSFER.SECTORS (SECTOR.NO, SECTOR.BUFF.RA, 1, 1) => STATUS;
@BOX 5.1
STATUS => TRANSFER.STATUS [SYS01.CURRENT.ACTIVITY]
   => SYS13.PROC.RESULT [SPN];
@BOX 6.1
END
@BOX 7.1
WHILE SECTOR.BUF.LOCK /= 0 DO
   SYS01.CURRENT.ACTIVITY.BIT !> SECTOR.BUF.LOCK.ACTIVITIES;
   SYS01.HALT (SYS01.CURRENT.ACTIVITY.BIT, SYS01.DTQ.HALT);
OD
1 => SECTOR.BUF.LOCK;
@BOX 8.1
SYS01.FREE (SECTOR.BUF.LOCK.ACTIVITIES, SYS01.DTQ.HALT);
0 => SECTOR.BUF.LOCK.ACTIVITIES => SECTOR.BUF.LOCK;
@END

@TITLE SYSINT03.8(4,11)

@COL 1S-2R-3F

@FLOW 1-2-3
@BOX 1.0
CLEAR BLOCK (SYSTEM SEGMENT NUMBER, BLOCK)
@BOX 2.0
WRITE BLANK PAGES TO BLOCK
@BOX 3.0
END
@BOX 1.1
PROC CLEAR.BLOCK (SSN, BLOCK);
INTEGER I;
@BOX 2.1
FOR I < DRUM.BLOCK.SIZE DO
   TRANSFER.DRUM.SEGMENT.PAGES (SSN, BLOCK * DRUM.BLOCK.SIZE + I,
      CLEAR.PAGE.ADDR, 1, 1);
OD
@BOX 3.1
END
@END

@TITLE SYSINT03.9(4,11)
@COL 1S-2R-5T-3R-4F
@COL 6R
@ROW 6-3
@FLOW 1-2-5NO-3-4
@FLOW 5YES-6-4
@BOX 1.0
INITIALISE SEGMENT (SYSTEM SEGMENT NUMBER, SEGMENT ADDRESS, SEGMENT SIZE, INTIAL
 STATE)
@BOX 2.0
INITIALISE DRUM SST
@BOX 3.0
FILL IN SUB-TABLE
@BOX 4.0
END
@BOX 5.0
SINGLE BLOCK?
@BOX 6.0
NOTE BLOCK ADDRESS
@BOX 1.1
PROC INITIALISE.DRUM.SEGMENT (SSN, SEG.ADDR, SEGMENT.SIZE, INITIAL.STATE);
INTEGER I, J;
@BOX 2.1
SELECT DRUM.SST [SSN];
SEGMENT.SIZE + DRUM.BLOCK.SIZE - 1 / DRUM.BLOCK.SIZE
   => SEG.SIZE;
0 => SUB.TABLE.NO;
-1 => BLOCK.TABLE.ADDR;
ALTERED => STATE;
@BOX 3.1
IF INITIAL.STATE /= 0 THEN
   %FF => INITIAL.STATE;
FI
FOR I < SEG.SIZE DO
   SELECT BLOCK.SUB.TABLE [I];
   SEG.ADDR + I => BLOCK.ADDR;
   FOR J < DRUM.BLOCK.SIZE.BIT.VEC.SIZE DO
      INITIAL.STATE => USED.PAGE.MAP [J];
   OD
OD
@BOX 4.1
END
@BOX 5.1
IF SEG.SIZE = 1
@BOX 6.1
SEG.ADDR => BLOCK.TABLE.ADDR;
-1 => SUB.TABLE.NO;
@END

@TITLE SYSINT03.10(4,11)
@COL 1S-2R-3F
@FLOW 1-2-3
@BOX 1.0
GET BLOCK TABLE AREA
@BOX 2.0
TRANSFER BLOCK TABLE AREA FROM
DRUM TO CORE
@BOX 3.0
END
@BOX 1.1
PROC GET.BLOCK.TABLE.AREA (DUMMY1, DUMMY2);
INTEGER I;
@BOX 2.1
FOR I < TABLE.AREA.SIZE / SUB.TABLES.PER.SECTOR / SECTORS.PER.PAGE DO
   TRANSFER.SECTORS (I * SECTORS.PER.PAGE + TABLE.AREA.ADDR, CORE.TABLE.AREA.RA
/ SECTOR.SIZE
      + (I * SECTORS.PER.PAGE), SECTORS.PER.PAGE, 0);
OD
@BOX 3.1
END
@END

@TITLE SYSINT03.11(4,11)
@COL 1S-2R-3R-4F
@FLOW 1-2-3-4
@BOX 1.0
LOCK DRUM SEGMENT (SSN)
@BOX 2.0
WAIT FOR SEGMENT TO BE FREE
@BOX 3.0
MARK SEGMENT LOCKED
@BOX 4.0
END
@BOX 1.1
PROC LOCK.DRUM.SEGMENT (SSN);
@BOX 2.1
SELECT DRUM.SST [SSN];
WHILE STATE & LOCKED /= 0 DO
   SSN => LOCKED.SEGMENT [SYS01.CURRENT.ACTIVITY];
   SYS01.HALT (SYS01.CURRENT.ACTIVITY.BIT, SYS01.DTQ.HALT);
OD
@BOX 3.1
LOCKED !> STATE;
@BOX 4.1
END
@END


@TITLE SYSINT03.12(4,11)
@COL 1S-2R-3R-4F
@FLOW 1-2-3-4
@BOX 1.0
UNLOCK DRUM SEGMENT (SSN)
@BOX 2.0
FREE ACTIVITIES WAITING FOR
SEGMENT
@BOX 3.0
MARK SEGMENT FREE
@BOX 4.0
END
@BOX 1.1
PROC UNLOCK.DRUM.SEGMENT (SSN);
INTEGER I;
@BOX 2.1
FOR I < SYS01.NO.OF.ACTIVITIES DO
   IF LOCKED.SEGMENT [I] = SSN THEN
      SYS01.FREE (BIT(I), SYS01.DTQ.HALT);
      0 => LOCKED.SEGMENT [I];
   FI
OD
@BOX 3.1
LOCKED -=> STATE OF DRUM.SST [SSN];
@BOX 4.1
END
@END

@TITLE SYSINT03.13(4,11)
@COL 1S-3R-4T-5R-8F
@FLOW 1-3-4OK-5-8
@FLOW 4FAIL-8
@BOX 1.0
ALLOCATE BLOCK (LIMITED, DUMMY)
@BOX 3.0
NOTE LIMIT OF ALLOCATION
@BOX 4.0
FIND FIRST FREE
BLOCK
@BOX 5.0
ALLOCATE THE
BLOCK
@BOX 8.0
END
@BOX 1.1
PROC ALLOCATE.BLOCK (LIMITED, DUMMY2);
INTEGER COUNT, MAX.SIZE, OLD.NEXT.FREE.BLOCK;
@BOX 3.1
0 => OLD.NEXT.FREE.BLOCK;
IF LIMITED /= 0 THEN
   DRUM.SECTION.SIZE [0] / SECTORS.PER.PAGE
      / DRUM.BLOCK.SIZE - BLOCK.AREA.ADDR => MAX.SIZE;
   IF NEXT.FREE.BLOCK > MAX.SIZE THEN
      NEXT.FREE.BLOCK => OLD.NEXT.FREE.BLOCK;
      0 => NEXT.FREE.BLOCK;
   FI
ELSE
   DRUM.SIZE => MAX.SIZE;
FI
@BOX 4.1
0 => COUNT => NEW.BLOCK
   => SYS13.PROC.RESULT [SYS13.CURRENT.SPN];
WHILE 1 +> COUNT =< MAX.SIZE AND
   TEST.BIT (FREE.BLOCKS, NEXT.FREE.BLOCK) = 0 DO
   IF 1 +> NEXT.FREE.BLOCK >= MAX.SIZE THEN
      0 => NEXT.FREE.BLOCK;
   FI
OD
IF COUNT > MAX.SIZE
@BOX 5.1
NEXT.FREE.BLOCK + BLOCK.AREA.ADDR => NEW.BLOCK
   => SYS13.PROC.RESULT [SYS13.CURRENT.SPN];
CLEAR.BIT (FREE.BLOCKS, NEXT.FREE.BLOCK);
IF OLD.NEXT.FREE.BLOCK /= 0 THEN
   OLD.NEXT.FREE.BLOCK => NEXT.FREE.BLOCK;
ELSE
   IF 1 +> NEXT.FREE.BLOCK >= DRUM.SIZE THEN
      0 => NEXT.FREE.BLOCK;
   FI
FI
@BOX 8.1
END
@END
@TITLE SYSINT03.14(4,11)
@COL 1S-2T-3R-5F
@FLOW 1-2NO-3-5
@FLOW 2YES-5
@BOX 1.0
RELEASE BLOCK (BLOCK ADDRESS, DUMMY)
@BOX 2.0
IS DRUM.SECTION UNAVAILABLE?
@BOX 3.0
MARK DRUM BLOCK FREE
@BOX 5.0
END
@BOX 1.1
PROC RELEASE.BLOCK (BLOCK.ADDR, DUMMY);
INTEGER D.SECTION;
LOGICAL32 D.ADDR;
@BOX 2.1
BLOCK.ADDR * DRUM.BLOCK.SIZE * SECTORS.PER.PAGE
   => D.ADDR;
FOR D.SECTION < NO.OF.DRUM.SECTIONS DO
   IF DRUM.SECTION.SIZE [D.SECTION]
      -> D.ADDR < 0, -> OUT;
OD
OUT:
IF D.SECTION < NO.OF.DRUM.SECTIONS AND
   DRUM.SECTION.AVAILABLE [D.SECTION] = 0
@BOX 3.1
BLOCK.AREA.ADDR -> BLOCK.ADDR;
IF BLOCK.ADDR < 0 OR
   BLOCK.ADDR > DRUM.SIZE THEN
   SYS12.SYSTEM.ERROR (RELEASE.FAIL);
FI
IF TEST.BIT (FREE.BLOCKS, BLOCK.ADDR) /= 0 THEN
   SYS12.SYSTEM.ERROR (DOUBLE.RELEASE);
FI
SET.BIT (FREE.BLOCKS, BLOCK.ADDR);
@BOX 5.1
END
@END
@TITLE SYSINT03.15(4,11)
@COL 1S-2R-3T-4R-5T-6R-7R-14T-15T-16R-8R-9R-10R-11F
@COL 12R-13R

@ROW 12-6

@FLOW 1-2-3NO-4-5NO-6-7-14NO-15NO-16-8-9-10-11
@FLOW 3YES-5
@FLOW 5YES-12-13-9
@FLOW 14YES-9
@FLOW 15YES-8

@BOX 1.0
CHANGE SIZE (SYSTEM SEGMENT NUMBER, NEW SIZE)
@BOX 2.0
LOCK SEGMENT
[SYSINT03.11]
@BOX 3.0
SAME NUMBER OF SUB TABLES
@BOX 4.0
COPY UNCHANGED SUB TABLES
TO NEW BLOCK TABLE
@BOX 5.0
IS SEGMENT SIZE INCREASING?
@BOX 6.0
RELEASE BLOCKS ON UNWANTED SUB TABLES
@BOX 7.0
RELEASE BLOCKS ON LAST SUB TABLE
OF NEW SEGMENT SIZE
@BOX 8.0
CLEAR UNUSED PAGES
@BOX 9.0
SET NEW SEGMENT SIZE
@BOX 10.0
UNLOCK SEGMENT
[SYSINT03.12]
@BOX 11.0
END
@BOX 12.0
ZERO BLOCK TABLE ENTRIES ON LAST SUB TABLE
OF OLD SEGMENT SIZE
@BOX 13.0
ZERO BLOCKS OF NEW SUB TABLES
@BOX 14.0
NEW SIZE GREATER THAN ONE BLOCK?
@BOX 15.0
IS BLOCK ALLOCATED?
@BOX 16.0
ALLOCATE BLOCK
@BOX 1.1
PROC CHANGE.SIZE (SSN, NEW.SIZE);
INTEGER OLD.SUB.TABLE.COUNT, NEW.SUB.TABLE.COUNT, COUNT, OLD.BLOCK.TABLE.ADDR,
   I, J, B.ADDR;
@BOX 2.1
LOCK.DRUM.SEGMENT (SSN);
@BOX 3.1
SELECT DRUM.SST [SSN];
BLOCK.TABLE.ADDR => OLD.BLOCK.TABLE.ADDR;
SEG.SIZE + SUB.TABLE.SIZE - 1 / SUB.TABLE.SIZE
   => OLD.SUB.TABLE.COUNT;
NEW.SIZE + SUB.TABLE.SIZE - 1 / SUB.TABLE.SIZE
   => NEW.SUB.TABLE.COUNT;
IF OLD.SUB.TABLE.COUNT = NEW.SUB.TABLE.COUNT
@BOX 4.1
IF OLD.SUB.TABLE.COUNT => COUNT > NEW.SUB.TABLE.COUNT THEN
   NEW.SUB.TABLE.COUNT => COUNT;
FI
BLOCK.TABLE.ADDR => OLD.BLOCK.TABLE.ADDR;
FOR I < COUNT - 1 DO
   OLD.BLOCK.TABLE.ADDR => BLOCK.TABLE.ADDR;
   IF SUB.TABLE.NO /= I THEN
      GET.SUB.TABLE (SSN, I);
   FI
   NEW.BLOCK.TABLE.ADDR => BLOCK.TABLE.ADDR;
   SECURE.SUB.TABLE (SSN, I);
OD
OLD.BLOCK.TABLE.ADDR => BLOCK.TABLE.ADDR;
@BOX 5.1
IF NEW.SIZE > SEG.SIZE
@BOX 6.1
FOR I < OLD.SUB.TABLE.COUNT - NEW.SUB.TABLE.COUNT DO
   GET.SUB.TABLE (SSN, NEW.SUB.TABLE.COUNT + I);
   FOR  J < SUB.TABLE.SIZE DO
      IF BLOCK.ADDR OF BLOCK.SUB.TABLE [J]
         => B.ADDR /= 0 THEN
         RELEASE.BLOCK (B.ADDR, 0);
      FI
   OD
OD
@BOX 7.1
IF SUB.TABLE.NO /= NEW.SUB.TABLE.COUNT - 1 THEN
   GET.SUB.TABLE (SSN, NEW.SUB.TABLE.COUNT - 1);
FI
NEW.SUB.TABLE.COUNT * SUB.TABLE.SIZE - NEW.SIZE
   => COUNT;
FOR I < COUNT DO
   IF BLOCK.ADDR OF BLOCK.SUB.TABLE [SUB.TABLE.SIZE - I - 1]
      => B.ADDR /= 0 THEN
      RELEASE.BLOCK (B.ADDR, 0);
   FI
OD
NEW.BLOCK.TABLE.ADDR => BLOCK.TABLE.ADDR;
ALTERED !> STATE;
@BOX 8.1
-1 => SUB.TABLE.NO;
IF BLOCK.TABLE.ADDR /= 0 THEN
   FOR I < DRUM.BLOCK.SIZE DO
      IF TEST.BIT (^USED.PAGE.MAP OF BLOCK.SUB.TABLE [0], I)
         = 0 THEN
         TRANSFER.SECTORS (BLOCK.TABLE.ADDR * DRUM.BLOCK.SIZE
            + I * SECTORS.PER.PAGE, CLEAR.PAGE.ADDR * SECTORS.PER.PAGE,
            SECTORS.PER.PAGE, 1);
      FI
   OD
FI
@BOX 9.1
NEW.SIZE => SEG.SIZE;
@BOX 10.1
UNLOCK.DRUM.SEGMENT (SSN);
@BOX 11.1
END
@BOX 12.1
IF SEG.SIZE = 1 THEN
   BEGIN
   SELECT BLOCK.SUB.TABLE [0];
   OLD.BLOCK.TABLE.ADDR => BLOCK.ADDR;
   FOR I < DRUM.BLOCK.SIZE.BIT.VEC.SIZE DO
      %FF => USED.PAGE.MAP [I];
   OD
   END
   0 => SUB.TABLE.NO;
ELSE
   IF SUB.TABLE.NO /= OLD.SUB.TABLE.COUNT - 1 THEN
      GET.SUB.TABLE (SSN, OLD.SUB.TABLE.COUNT - 1);
   FI
FI
OLD.SUB.TABLE.COUNT * SUB.TABLE.SIZE - SEG.SIZE
   => COUNT;
FOR I < COUNT DO
   ZERO.BLOCK.TABLE.ENTRY => BLOCK.SUB.TABLE [SUB.TABLE.SIZE - I - 1]
OD
ALTERED !> STATE;
@BOX 13.1
NEW.BLOCK.TABLE.ADDR => BLOCK.TABLE.ADDR;
FOR I < NEW.SUB.TABLE.COUNT - OLD.SUB.TABLE.COUNT DO
   GET.SUB.TABLE (SSN, OLD.SUB.TABLE.COUNT + I);
   FOR J < SUB.TABLE.SIZE DO
      ZERO.BLOCK.TABLE.ENTRY => BLOCK.SUB.TABLE [J];
   OD
   ALTERED !> STATE;
OD
@BOX 14.1
IF NEW.SIZE /= 1
@BOX 15.1
IF BLOCK.ADDR OF BLOCK.SUB.TABLE [0]
   => BLOCK.TABLE.ADDR /= 0
@BOX 16.1
ALLOCATE.BLOCK (0, 0);
NEW.BLOCK => BLOCK.TABLE.ADDR;
ZERO.BLOCK.TABLE.ENTRY => BLOCK.SUB.TABLE [0];
@END

@TITLE SYSCMD03.1(4,11)
@COL 1S-2T-3R-4F
@FLOW 1-2FAIL-3-4
@FLOW 2OK-4
@BOX 1.0
ALLOCATE DRUM BLOCK ()
@BOX 2.0
ENTER INTERRUPT LEVEL TO ALLOCATE
BLOCK
[SYS03.13]
@BOX 3.0
RETURN FAULT STATUS -7
(INSUFFICIENT SYSTEM RESOURCE)
@BOX 4.1
END
@BOX 1.1
PROC ALLOCATE.DRUM.BLOCK;
@BOX 2.1
SYS13.ENTER.INT.LEVEL (^ALLOCATE.BLOCK, 1, 0);
IF SYS13.PROC.RESULT [SYS13.CURRENT.SPN]
   => ALLOCATE.DRUM.BLOCK /= 0
@BOX 3.1
-7 => PW0;
@BOX 4.1
END
@END
@TITLE SYSCMD03.2(4,11)
@COL 1S-2R-3F
@FLOW 1-2-3
@BOX 1.0
RELEASE DRUM BLOCK (BLOCK ADDRESS)
@BOX 2.0
ENTER INTERRUPT LEVEL TO FREE
BLOCK
[SYSINT03.14]
@BOX 3.0
END
@BOX 1.1
PROC RELEASE.DRUM.BLOCK (BLOCK.ADDR);
@BOX 2.1
SYS13.ENTER.INT.LEVEL (^RELEASE.BLOCK, BLOCK.ADDR, 0);
@BOX 3.1
END
@END
@TITLE SYSCMD03.3(4,11)
@COL 1S-2R-3T-4T-5T-7R-8T-9R-18T-15T-16R-17R-10F
@FLOW 1-2-3NO-4NO-5OK-7-8NO-9-7
@FLOW 3YES-10
@FLOW 4YES-7
@FLOW 8YES-18NO-15OK-16-17-10
@FLOW 5FAIL-10
@FLOW 15FAIL-10
@FLOW 18YES-10
@BOX 1.0
OPEN DRUM SEGMENT (SYSTEM SEGMENT NO,
   SEGMENT ADDRESS, SEGMENT SIZE)
@BOX 2.0
FILL IN DRUM SST ENTRY
@BOX 3.0
DOES SEGMENT ALREADY EXIST?
@BOX 4.0
ONLY ONE SUB-TABLE REQUIRED?
@BOX 5.0
ALLOCATE DRUM SPACE FOR
BLOCK TABLE
[SYSCMD03.9]
@BOX 7.0
FILL IN SUB-TABLE
@BOX 8.0
LAST SUB-TABLE?
@BOX 9.0
SECURE SUB-TABLE TO DRUM
[SYSINT03.7]
@BOX 10.0
END
@BOX 12.0
RELEASE PREVIOUSLY ALLOCATED
DRUM SPACE
@BOX 15.0
ALLOCATE DRUM SPACE FOR
BLOCK
@BOX 16.0
NOTE BLOCK ADDRESS
@BOX 17.0
CLEAR FIRST BLOCK
@BOX 18.0
GREATER THAN ONE BLOCK?
@BOX 1.1
PROC OPEN.DRUM.SEGMENT (SSN, SEG.ADDR, SEGMENT.SIZE);
INTEGER SUB.TABLE.COUNT, I, J, SAVE.PW0;
0 => PW0;
@BOX 2.1
SELECT DRUM.SST [SSN];
SEG.ADDR - 1 => BLOCK.TABLE.ADDR;
SEGMENT.SIZE + DRUM.BLOCK.SIZE - 1 / DRUM.BLOCK.SIZE
   => SEG.SIZE;
-1 => SUB.TABLE.NO;
0 => STATE;
@BOX 3.1
IF SEG.ADDR /= 0
@BOX 4.1
SEG.SIZE + SUB.TABLE.SIZE - 1 / SUB.TABLE.SIZE
   => SUB.TABLE.COUNT => SUB.TABLE.NO;
IF SUB.TABLE.COUNT = 1
@BOX 5.1
ALLOCATE.BLOCK.TABLE (SUB.TABLE.COUNT)
   => BLOCK.TABLE.ADDR;
IF PW0 /= 0
@BOX 7.1
1 -> SUB.TABLE.NO;
FOR I < SUB.TABLE.SIZE DO
   ZERO.BLOCK.TABLE.ENTRY => BLOCK.SUB.TABLE [I];
OD
ALTERED => STATE;
@BOX 8.1
IF SUB.TABLE.NO = 0
@BOX 9.1
SYS13.ENTER.INT.LEVEL (^SECURE.SUB.TABLE, SSN, 0);
@BOX 10.1
END
@BOX 15.1
SYS13.ENTER.INT.LEVEL (^ALLOCATE.BLOCK, 0, 0);
IF SYS13.PROC.RESULT [SYS13.CURRENT.SPN] = 0 THEN
   -7 => PW0;
FI
IF PW0 /= 0
@BOX 16.1
SYS13.PROC.RESULT [SYS13.CURRENT.SPN] => BLOCK.TABLE.ADDR;
-1 => SUB.TABLE.NO;
@BOX 17.1
SYS13.ENTER.INT.LEVEL (^CLEAR.BLOCK, SSN, 0);
@BOX 18.1
IF SEG.SIZE /= 1
@END
@TITLE SYSCMD03.4(4,11)
@COL 1S-2T-9T-3T-4R-5T-6T-7R-8F
@COL 10R
@ROW 10-3
@FLOW 1-2NO-9NO-3OK-4-5NO-6OK-4
@FLOW 2YES-8
@FLOW 3FAIL-7-8
@FLOW 5YES-7
@FLOW 6FAIL-7
@FLOW 9YES-10-8
@BOX 1.0
CLOSE DRUM SEGMENT (SYSTEM SEGMENT NO)
@BOX 2.0
IS SEGMENT PROTECTED?
@BOX 3.0
GET FIRST SUB-TABLE
@BOX 4.0
RELEASE DRUM BLOCKS
[SYSCMD03.2]
@BOX 5.0
LAST SUB-TABLE?
@BOX 6.0
GET NEXT SUB-TABLE
@BOX 7.0
RELEASE BLOCK TABLE
[SYSCMD3.10]
@BOX 8.0
END
@BOX 9.0
IS SEGMENT A SINGLE BLOCK?
@BOX 10.0
RELEASE BLOCK
[SYSCMD03.2]
@BOX 1.1
PROC CLOSE.DRUM.SEGMENT (SSN);
INTEGER LAST.SUB.TABLE, I, NO.OF.ENTRIES;
LOGICAL16 B.ADDR;
@BOX 2.1
SELECT DRUM.SST [SSN];
IF STATE & PROTECTED /= 0
@BOX 3.1
SEG.SIZE + SUB.TABLE.SIZE - 1 / SUB.TABLE.SIZE
  - 1 => LAST.SUB.TABLE;
0 => SYS13.PROC.RESULT [SYS13.CURRENT.SPN];
IF SUB.TABLE.NO /= 0 THEN
   SYS13.ENTER.INT.LEVEL (^GET.SUB.TABLE, SSN, 0);
FI
IF SYS13.PROC.RESULT [SYS13.CURRENT.SPN] /= 0
@BOX 4.1
IF SUB.TABLE.NO = LAST.SUB.TABLE THEN
   SUB.TABLE.NO * SUB.TABLE.SIZE -: SEG.SIZE
      => NO.OF.ENTRIES;
ELSE
   SUB.TABLE.SIZE => NO.OF.ENTRIES;
FI
FOR I < NO.OF.ENTRIES DO
   IF BLOCK.ADDR OF BLOCK.SUB.TABLE [I] => B.ADDR /= 0 THEN
      RELEASE.DRUM.BLOCK (B.ADDR);
   FI
OD
@BOX 5.1
IF SUB.TABLE.NO = LAST.SUB.TABLE
@BOX 6.1
SYS13.ENTER.INT.LEVEL (^GET.SUB.TABLE, SSN, SUB.TABLE.NO + 1);
IF SYS13.PROC.RESULT [SYS13.CURRENT.SPN] /= 0
@BOX 7.1
IF BLOCK.TABLE.ADDR >= 0 THEN
   RELEASE.BLOCK.TABLE (BLOCK.TABLE.ADDR, LAST.SUB.TABLE + 1);
FI
@BOX 8.1
END
@BOX 9.1
IF SEG.SIZE = 1
@BOX 10.1
RELEASE.DRUM.BLOCK (BLOCK.TABLE.ADDR);
@END
@TITLE SYSCMD03.5(4,11)
@COL 1S-2T-3T-6T-7T-8R-9R-10R-12R-27N-13F
@COL 28R
@ROW 28-3
@FLOW 1-2NO-3NO-6NO-7OK-8-9-10-12-27-13
@FLOW 2YES-28-27
@FLOW 3YES-27
@FLOW 6YES-8
@FLOW 7FAIL-27
@BOX 1.0
CHANGE DRUM SEGMENT SIZE (SYSTEM SEGMENT NUMBER, NEW SIZE)
@BOX 2.0
IS SEGMENT PROTECTED?
@BOX 3.0
SAME NUMBER OF DRUM BLOCKS REQUIRED?
@BOX 6.0
SAME NUMBER OF SUB-TABLES REQUIRED?
@BOX 7.0
ALLOCATE NEW BLOCK TABLE
@BOX 8.0
CHECK IN
[SYS01]
@BOX 9.0
ENTER INTERRUPT LEVEL TO CHANGE SIZE
@BOX 10.0
CHECKOUT
[SYS01]
@BOX 12.0
RELEASE UNWANTED BLOCK TABLE
@BOX 13.0
END
@BOX 28.0
RETURN FAULT STATUS -4
@BOX 1.1
PROC CHANGE.DRUM.SEGMENT.SIZE (SSN, NEW.SIZE);
INTEGER NEW.SUB.TABLE.COUNT,
   OLD.SUB.TABLE.COUNT, NEW.ADDR;
INTEGER16 OLD.BLOCK.TABLE.ADDR;
0 => PW0;
@BOX 2.1
SELECT DRUM.SST [SSN]
IF STATE & PROTECTED /= 0
@BOX 3.1
IF NEW.SIZE + DRUM.BLOCK.SIZE - 1 / DRUM.BLOCK.SIZE
   => NEW.SIZE = SEG.SIZE
@BOX 6.1
BLOCK.TABLE.ADDR => OLD.BLOCK.TABLE.ADDR
   => NEW.ADDR;
IF SEG.SIZE /= 1 THEN
   SEG.SIZE + SUB.TABLE.SIZE -1 / SUB.TABLE.SIZE
      => OLD.SUB.TABLE.COUNT;
ELSE
   0 => OLD.SUB.TABLE.COUNT;
   -1 => OLD.BLOCK.TABLE.ADDR;
FI
IF NEW.SIZE /= 1 THEN
   NEW.SIZE + SUB.TABLE.SIZE -1 / SUB.TABLE.SIZE
      => NEW.SUB.TABLE.COUNT;
ELSE
   0 => NEW.SUB.TABLE.COUNT;
FI
IF NEW.SUB.TABLE.COUNT = OLD.SUB.TABLE.COUNT
@BOX 7.1
IF NEW.SUB.TABLE.COUNT /= 0 THEN
   ALLOCATE.BLOCK.TABLE (NEW.SUB.TABLE.COUNT)
      => NEW.ADDR;
FI
IF PW0 /= 0
@BOX 8.1
SYS13.ENTER.INT.LEVEL (^SYS01.CHECK.IN, 0, 0);
@BOX 9.1
NEW.ADDR => NEW.BLOCK.TABLE.ADDR;
SYS13.ENTER.INT.LEVEL (^CHANGE.SIZE, SSN, NEW.SIZE);
@BOX 10.1
SYS13.ENTER.INT.LEVEL (^SYS01.CHECK.OUT, 0, 0);
@BOX 12.1
IF OLD.BLOCK.TABLE.ADDR /= BLOCK.TABLE.ADDR
   AND OLD.BLOCK.TABLE.ADDR >= 0 THEN
   RELEASE.BLOCK.TABLE (OLD.BLOCK.TABLE.ADDR,
      OLD.SUB.TABLE.COUNT);
FI
@BOX 13.1
END
@BOX 28.1
-4 => PW0;
@END
@TITLE SYSCMD03.6(4,11)
@COL 1S-2R-3F
@FLOW 1-2-3
@BOX 1.0
READ DRUM SEGMENT ADDR (SYSTEM SEGMENT NUMBER)
@BOX 2.0
RETURN ADDRESS OF
BLOCK TABLE
@BOX 3.0
END
@BOX 1.1
PROC READ.DRUM.SEGMENT.ADDR (SSN);
@BOX 2.1
SELECT DRUM.SST [SSN];
BLOCK.TABLE.ADDR + 1 => READ.DRUM.SEGMENT.ADDR;
@BOX 3.1
END
@END
@TITLE SYSCMD03.7(4,11)
@COL 1S-2R-3F
@FLOW 1-2-3
@BOX 1.0
PROTECT DRUM SEGMENT (SYSTEM SEGMENT NUMBER, PROTECT STATUS)
@BOX 2.0
SET SPECIFIED PROTECTION
FOR DRUM SEGMENT
@BOX 3.0
END
@BOX 1.1
PROC PROTECT.DRUM.SEGMENT (SSN, PROTECT.STATUS);
@BOX 2.1
SELECT DRUM.SST [SSN];
PROTECTED !> STATE;
IF PROTECT.STATUS = 0 THEN
   PROTECTED -=> STATE;
FI
@BOX 3.1
END
@END
@TITLE SYSCMD03.8(4,11)
@COL 1S-2T-5T-3R-4F
@FLOW 1-2NO-5OK-3-4
@FLOW 2YES-4
@FLOW 5FAIL-4
@BOX 1.0
SECURE DRUM SEGMENT (SYSTEM SEGMENT NUMBER)
@BOX 2.0
IS CURRENT SUB-TABLE
UNALTERED?
@BOX 3.0
SECURE SUB-TABLE
[SYSINT03.7]
@BOX 4.0
END
@BOX 5.0
ALLOCATE BLOCK TABLE IF NECESSARY
@BOX 1.1
PROC SECURE.DRUM.SEGMENT (SSN);
@BOX 2.1
SELECT DRUM.SST [SSN];
IF SUB.TABLE.NO < 0 OR STATE & ALTERED = 0
@BOX 3.1
SYS13.ENTER.INT.LEVEL (^SECURE.SUB.TABLE, SSN, 0);
@BOX 4.1
END
@BOX 5.1
0 => PW0;
IF BLOCK.TABLE.ADDR < 0 THEN
  ALLOCATE.BLOCK.TABLE (1) => BLOCK.TABLE.ADDR;
FI
IF PW0 /= 0
@END
@TITLE SYSCMD03.9(4,11)
@COL 1S-2R-3R-4T-5R-6T-7R-8R-9F
@COL 10R
@ROW 5-10
@FLOW 1-2-3-4NO-5-6NO-7-8-9
@FLOW 4YES-10-8
@FLOW 6YES-4
@BOX 1.0
ALLOCATE BLOCK.TABLE (NO.OF.SUB.TABLES)
@BOX 2.0
CHECKIN [SYS01]
@BOX 3.0
RESET POINTERS
@BOX 4.0
INSUFFICIENT SPACE IN AREA ?
@BOX 5.0
FIND FIRST FREE SUB-TABLE
@BOX 6.0
INSUFFICIENT SUB-TABLES FREE ?
@BOX 7.0
ALLOCATE THE BLOCK TABLE
@BOX 8.0
CHECKOUT [SYS01]
@BOX 9.0
END
@BOX 10.0
RETURN FAULT STATUS -7
(INSUFFICIENT SYSTEM RESOURCES)
@BOX 1.1
PROC ALLOCATE.BLOCK.TABLE (NO.OF.SUB.TABLES);
INTEGER PTR, COUNT, FREE.SUB.TABLE;
@BOX 2.1
SYS13.ENTER.INT.LEVEL (^SYS01.CHECK.IN, 0, 0);
@BOX 3.1
0 => FREE.SUB.TABLE => PTR
   => COUNT;
@BOX 4.1
IF COUNT >= TABLE.AREA.SIZE
@BOX 5.1
WHILE TEST.BIT (FREE.SUB.TABLES, PTR) = 0 DO
   1 +> COUNT;
   IF 1 +> PTR + NO.OF.SUB.TABLES >= TABLE.AREA.SIZE THEN
      0 => PTR;
   FI
OD
@BOX 6.1
PTR => FREE.SUB.TABLE;
NO.OF.SUB.TABLES +> PTR;
WHILE 1 -> PTR > FREE.SUB.TABLE
   AND TEST.BIT (FREE.SUB.TABLES, PTR) /= 0 DO OD
PTR - FREE.SUB.TABLE +> COUNT;
IF PTR > FREE.SUB.TABLE
@BOX 7.1
FREE.SUB.TABLE => ALLOCATE.BLOCK.TABLE;
FOR NO.OF.SUB.TABLES DO
   IF TEST.BIT (FREE.SUB.TABLES, FREE.SUB.TABLE) = 0 THEN
      SYS12.SYSTEM.ERROR (DOUBLE.ALLOCATE);
   FI
   CLEAR.BIT (FREE.SUB.TABLES, FREE.SUB.TABLE);
   1 +> FREE.SUB.TABLE;
OD
@BOX 8.1
SYS13.ENTER.INT.LEVEL (^SYS01.CHECK.OUT, 0, 0);
@BOX 9.1
END
@BOX 10.1
-7 => PW0;
@END
@TITLE SYSCMD03.10(4,11)
@COL 1S-2R-3R-4R-5F
@FLOW 1-2-3-4-5
@BOX 1.0
RELEASE BLOCK TABLE (DUMMY, BLOCK TABLE ADDR, NO. OF SUB-TABLES)
@BOX 2.0
CHECKIN [SYS01]
@BOX 3.0
MARK ALL SUB-TABLES FREE
@BOX 4.0
CHECKOUT [SYS01]
@BOX 5.0
END
@BOX 1.1
PROC RELEASE.BLOCK.TABLE (BLOCK.TABLE.ADDR, NO.OF.SUB.TABLES);
@BOX 2.1
SYS13.ENTER.INT.LEVEL (^SYS01.CHECK.IN, 0, 0);
@BOX 3.1
FOR NO.OF.SUB.TABLES DO
   SET.BIT (FREE.SUB.TABLES, BLOCK.TABLE.ADDR);
   1 +> BLOCK.TABLE.ADDR;
OD
@BOX 4.1
SYS13.ENTER.INT.LEVEL (^SYS01.CHECK.OUT, 0, 0);
@BOX 5.1
END
@END
@TITLE SYSCMD03.11(4,11)
@COL 1S-5T-4R-2R-3F
@FLOW 1-5NO-4-2-3
@FLOW 5YES-3
@BOX 1.0
RESERVE DRUM BLOCK (BLOCK ADDRESS)
@BOX 2.0
MARK DRUM BLOCK ALLOCATED
@BOX 3.0
END
@BOX 4.0
CHECK BLOCK
ADDRESS VALID
@BOX 5.0
DRUM SECTION UNAVAILABLE?
@BOX 1.1
PROC RESERVE.DRUM.BLOCK (BLOCK.ADDR);
INTEGER D.SECTION;
LOGICAL32 D.ADDR;
@BOX 2.1
IF TEST.BIT (FREE.BLOCKS, BLOCK.ADDR) = 0 THEN
   SYS12.SYSTEM.ERROR (DOUBLE.RESERVE);
FI
CLEAR.BIT (FREE.BLOCKS, BLOCK.ADDR);
@BOX 3.1
END
@BOX 4.1
BLOCK.AREA.ADDR -> BLOCK.ADDR;
IF BLOCK.ADDR < 0
   OR BLOCK.ADDR > DRUM.SIZE THEN
   SYS12.SYSTEM.ERROR (RESERVE.FAIL);
FI
@BOX 5.1
BLOCK.ADDR * DRUM.BLOCK.SIZE * SECTORS.PER.PAGE
   => D.ADDR;
FOR D.SECTION < NO.OF.DRUM.SECTIONS DO
   IF DRUM.SECTION.SIZE [D.SECTION]
      -> D.ADDR < 0, -> OUT;
OD
OUT:
IF D.SECTION < NO.OF.DRUM.SECTIONS AND
   DRUM.SECTION.AVAILABLE [D.SECTION] = 0
@END


@TITLE SYSCMD03.12(4,11)
@COL 1S-2T-3R-4R-5R-6R-7T-8F
@COL 9R
@ROW 4-9
@FLOW 1-2NO-3-4-5-6-7NO-8
@FLOW 2YES-9-8
@FLOW 7YES-5
@BOX 1.0
RESERVE DRUM SEGMENT (SEGMENT ADDRESS, SEGMENT SIZE)
@BOX 2.0
IS SEGMENT SINGLE BLOCK?
@BOX 3.0
CHECK BLOCK TABLE ADDRESS
@BOX 4.0
RESERVE BLOCK TABLE
@BOX 5.0
SET POINTER TO SUB-TABLE
@BOX 6.0
RESERVE BLOCKS OF SUB-TABLE
@BOX 7.0
MORE SUB-TABLES?
@BOX 8.0
END
@BOX 9.0
RESERVE BLOCK
@BOX 1.1
PROC RESERVE.DRUM.SEGMENT (SEG.ADDR, SEG.SIZE);
INTEGER SUB.TABLE.COUNT, I, COUNT, NO.OF.ENTRIES;
LOGICAL16 B.ADDR;
ADDR [BLOCK.TABLE.ENTRY] SUB.TABLE;
@BOX 2.1
1 -> SEG.ADDR;
SEG.SIZE + DRUM.BLOCK.SIZE - 1 / DRUM.BLOCK.SIZE
   => SEG.SIZE;
IF SEG.SIZE = 1
@BOX 3.1
SEG.SIZE + SUB.TABLE.SIZE - 1 / SUB.TABLE.SIZE
   => SUB.TABLE.COUNT;
IF SEG.ADDR < 0 OR
   SEG.ADDR + SUB.TABLE.COUNT > TABLE.AREA.SIZE THEN
   SYS12.SYSTEM.ERROR (RESERVE.FAIL);
FI
@BOX 4.1
FOR I < SUB.TABLE.COUNT DO
   IF TEST.BIT (FREE.SUB.TABLES, SEG.ADDR + I) = 0 THEN
      SYS12.SYSTEM.ERROR (DOUBLE.RESERVE);
   FI
   CLEAR.BIT (FREE.SUB.TABLES, SEG.ADDR + I);
OD
0 => COUNT;
@BOX 5.1
MAKE (BLOCK.TABLE.ENTRY, SUB.TABLE.SIZE, SEG.ADDR + COUNT * SUB.TABLE.SIZE * BLO
CK.TABLE.ENTRY.SIZE
   + CORE.TABLE.AREA.VA) => SUB.TABLE;
@BOX 6.1
IF COUNT + 1 = SUB.TABLE.COUNT THEN
   SUB.TABLE.COUNT-1 * SUB.TABLE.SIZE -: SEG.SIZE => NO.OF.ENTRIES;
ELSE
   SUB.TABLE.SIZE => NO.OF.ENTRIES
FI
FOR I < NO.OF.ENTRIES DO
   IF BLOCK.ADDR OF SUB.TABLE^ [I] => B.ADDR /= 0 THEN
      RESERVE.DRUM.BLOCK (B.ADDR);
   FI
OD
@BOX 7.1
IF 1 +> COUNT < SUB.TABLE.COUNT
@BOX 8.1
END
@BOX 9.1
RESERVE.DRUM.BLOCK (SEG.ADDR);
@END
@TITLE SYSCMD03.13(4,11)
@COL 1S-2R-3F
@FLOW 1-2-3
@BOX 1.0
DRUM INITIALISATION COMPLETE ()
@BOX 2.0
RELEASE CORE SPACE ALLOCATED
TO BLOCK TABLE AREA
@BOX 3.0
END
@BOX 1.1
PROC DRUM.INITIALISATION.COMPLETE;
INTEGER START, I;
INTEGER32 COUNT;
@BOX 2.1
CORE.TABLE.AREA.RA / SYS02.CORE.PAGE.SIZE => START;
TABLE.AREA.SIZE * SUB.TABLE.SIZE * BLOCK.TABLE.ENTRY.SIZE
   / SYS02.CORE.PAGE.SIZE => COUNT;
FOR I < COUNT DO
   SYS13.ENTER.INT.LEVEL (^SYS02.RELEASE.PAGE, START + I, 1);
OD
@BOX 3.1
END
@END
@TITLE SYSTSK03.1(4,11)
@COL 1S-3R-4R-6R-5F
@FLOW 1-3-4-6-5
@BOX 1.0
DRUM TASK
@BOX 3.0
INITIALISE FREE BLOCK TABLE
AND FREE SUB-TABLE TABLE
@BOX 4.0
CLEAR UNAVAILABLE SECTIONS
@BOX 5.0
END
@BOX 6.0
GET BLOCK TABLE AREA
[SYSINT03.10]
@BOX 1.1
PROC DRUM.TASK;
INTEGER I, J, SECTION.START, SECTION.SIZE;
@BOX 3.1
FOR I < DRUM.SIZE.BIT.VEC.SIZE DO
   %FF => FREE.BLOCKS^ [I];
OD
FOR I < TABLE.AREA.SIZE.BIT.VEC.SIZE DO
   %FF => FREE.SUB.TABLES^ [I];
OD
@BOX 4.1
DRUM.SECTION.SIZE [0] / SECTORS.PER.PAGE
   / DRUM.BLOCK.SIZE - BLOCK.AREA.ADDR => SECTION.START;
FOR I < NO.OF.DRUM.SECTIONS - 1 DO
   DRUM.SECTION.SIZE [I + 1] / SECTORS.PER.PAGE
      / DRUM.BLOCK.SIZE => SECTION.SIZE;
   IF DRUM.SECTION.AVAILABLE [I + 1] = 0 THEN
      FOR J < SECTION.SIZE DO
         CLEAR.BIT (FREE.BLOCKS, SECTION.START + J);
      OD
   FI
   SECTION.SIZE +> SECTION.START;
OD
@BOX 5.1
END
@BOX 6.1
SYS13.ENTER.INT.LEVEL (^GET.BLOCK.TABLE.AREA, 0, 0);
@END


