@X @~
~V7 56 2 -5
~D10
~H                    MUSS
~
~
~D10
~H            AP7091
~D10
~MMANCHESTER UNIVERSITY   -   CONFIDENTIAL~
~
~
                                                            ISSUE 11~
~V9 -1
~P
~V9 1
~YAP7091
~T% 3 6
~S~M~OAP7 IMPLEMENTATION DESCRIPTION
~S~M~OSection 9 Version 1
~S~OSection 9.1 I/O Manager Appendix
~S~O1. General Description
~BThe I/O manager appendix is part of the operating system
of the PDP11/10 used as a front end to MU6G.  It acts as the
interface between the I/O Appendix and the CIU Driver Appendix,
interfacing with the former in a similar way to the normal I/O
Manager (SYS07), which it replaces.
~S1~O2. Interfaces
~
Other modules used:~
~IAP103  I/O Appendix~
~IAP705  CIU Appendix~
~
Ideal hardware registers used:~
~IV.IO.DEV.NO~
~IV.IO.COUNT~
~IV.IO.CONTROL~
~IV.IO.ADDRESS~
~IV.IO.INT~
~IV.IO.P.DEV.PARS~
~IV.IO.P.DEV.NO~
~IV.IO.P.DEV.TYPE~
~IV.IO.P.DEV.MODE~
~IV.IO.P.DEV.PROTOCOL~
~
Interrupt procedures:~
~IIO.INTERRUPT ()~
~
Interface procedures:~
~IIO.RECEIVE ()~
~IIO.RESET ()~
~IIO.INFORM ()~
~
Configuration parameters:~
~ISYS19.NO.OF.DEVICES~
~ISYS19.MU6.IO.ADDR~
~ISYS19.LARGE.BUFFER.SIZE~
~ISYS19.SMALL.BUFFER.SIZE~
~ISYS19.NO.OF.LARGE.BUFFERS~
~ISYS19.NO.OF.SMALL.BUFFERS~
~ISYS19.BUFFER.BLOCK.ADDRESS~
~S~O2.1 Hardware interface
~BAll I/O devices are controlled through a set of eight registers.
These registers act as a window onto a pool of individual device registers. Writ
ing to the V.IO.DEV.NO selects a particular device. At the same
time, it causes the values of the registers of that device to be returned in the
 eight ideal registers.
~BV.IO.ADDRESS is used to specify the address, in byte units, of the
buffer to/from which a transfer is to be performed. On completion of a transfer
it will have been increased by the number of bytes actually transferred (which m
ay be zero).
~BV.IO.COUNT is used to specify the maximum number of bytes to be transferred.
On completion of a transfer it will have been decreased by the number of bytes a
ctually transferred (which may be zero).
~BV.IO.CONTROL is used to send commands to the device, and to receive status inf
ormation.
~BThe physical characteristics of a device are specified using five registers. T
hese registers pass device-dependent information.
~BV.IO.P.DEV.TYPE is used to specify the type of the physical device.
Each type refers to a certain physical cluster of devices (e.g. a multiplexer).
~BV.IO.P.DEV.NO is used to specify the corresponding device number within that p
hysical type.
~BV.IO.P.DEV.PARS is used to specify the parameters of the physical
device, including parity, character size, stop bits, and transfer rate.
~BV.IO.P.DEV.MODE is used to specify the mode of operation of the physical
device. It contains information which determines the actions
to be taken on each special character.
~BV.IO.P.DEV.PROTOCOL is used to specify the protocol associated with a physical
 device.
~BMore detailed information about the V-stores can be found in SYS076.
~S~O2.2 Software Interface
~S11) IO.RECEIVE
~BThis procedure is called by the CIU driver module when a control
message is received addressed to this module; appropriate action is
taken, according to the contents of the message.  Input requests and
change of state messages are passed directly to the I/O appendix,
whereas output commands initiate a series of transfer requests back
to MU6.  Each block transferred also causes this procedure to be called.
In this case the appropriate buffer address is passed back to the CIU driver;
otherwise zero is returned.
~S12) IO.INTERRUPT
~BThis procedure services the MUSS I/O interrupt, which occurs
whenever the I/O appendix requires service.  In the case of
either a receive transfer complete or a fault condition, information
is passed back to the MU6 I/O Manager immediately, whereas the
completion of an output block transfer causes another to be initiated
(unless all data has been transferred).  In all cases the CIU.TRANSMIT
procedure of the CIU driver module is used to initiate the transfer.
~S13) IO.INFORM
~BThis procedure is called by the CIU driver to indicate the completion
of a data block transfer from MU6.  It initiates an output transfer from
the appropriate channel by writing to the V-store of the I/O appendix.
~S14) IO.RESET
~BThis procedure is called by the CIU driver if a hardware reset of
MU6 is signalled.  A stop command is sent to all devices and the module
initialisation run.
~S~O3. Implementation
~BIn this system I/O messages are passed between the PDP11 and MU6,
via the CIU, in the form of V-store values (together with data
blocks if appropriate). It is the function of this module to
receive messages from the CIU and write them to the V-stores
in the I/O Appendix. Responses to these messages, and changes
due to device driver calls of NOTIFY in the I/O Appendix, are
dealt with by creating appropriate messages and sending them to
the CIU.  In the case of output transfers, due to storage limitations,
data transfer is controlled by the PDP11 and occurs as a succession
of suitably small blocks, individually requested.
~S~O3.1 Outline of operation
~BTransfers through the CIU always consist of a control message,
possibly followed by a data message.  In the case of input transfers,
the appropriate data buffer is transferred immediately after the
control message.  Output transfers however are dealt with differently;
here only a control message is transfered initially, specifying
the size of the accomanying data block.  Due to memory limitations
in the PDP11, the I/O buffers are smaller than those in MU6, so
information is transferred in units corresponding to the PDP11
buffer size.  Thus requests are issued by the PDP11 for data blocks,
specifying start address and block size.  When such a data block has
been transferred it is output by writing appropriate values into the
V-store of the I/O Appendix module.  The code for these activities is
contained in the modules IO.INTERRUPT, IO.RECEIVE and IO.INFORM.
~S11) IO.INTERRUPT
~BThe interrupt tree, contained in the V.IO.INT array, is scanned to
locate the interrupting device, generating its logical device number.
Reference to the IO.REPLY.PARS table indicates whether this channel
is engaged in an output transfer.  If not then assembly of a normal
reply-to-MU6 message is begun.  If the channel is an input, and has
data available, suitable entries are made in the DATA.MARKER of the
control message and the COUNT.TEMP variable.  Finally the standard
data items (destination, logical device number and control/status
register) are added into the message and the CIU Transmit procedure called.
~BIf the "transfer in progress" flag contains a START TRANSFER command two furth
er tests
are made.  The status is checked to see if the previous block has been
correctly output.  If not a fault message is transmitted to MU6,
indicating the reason for failure.  If the transfer completed
satisfactorily the value of COUNT in the reply table is checked to
see if more data remains to be transferred.  If not a TRANSFER COMPLETE
is returned, otherwise more data if requested; the count and address
parameters passed are those required for directly loading into the CIU.
~S12) IO.RECEIVE
~BByte 2 of the received message is checked to determine whether it is
a response to an output data transfer request.  If it is then the
buffer address allocated to that channel is returned to the CIU and
the logical device number noted for use when the data transfer
completes.  If byte 2 does not indicate a response to a data request,
it is tested to see if data is to follow.  If so then an output transfer is
indicated and steps are taken to initiate the sequence of data requests
necessary.  Note that a count correction is made - although the I/O
buffers in MU6 are allocated on 128 byte boundaries, a few bytes will
have been used to store temporary data relating to the transfer, and
since the CIU can only transfer data beginning from such a boundary
the temporary data is also transferred.  However the count correction
is stored in the reply table and used (in proc IO.INFORM) to ensure
that only wanted data is output.
~BIn the case of an input transfer a similar correction is applied.
Here the data received is loaded into the buffer at a starting
address offset by the correction, since the MU6 I/O manager is
expecting the data at a similarly offset position in its own buffer.
~BIf an initialisation message is received, a number of activities
are carried out.  All I/O devices connected to the PDP11 are classified
as one device type in MU6 - remote - so a conversion is carried out
on the physical device number, using an imported look-up table, to
obtain the correct physical device type and number.  The look-up table
also indicates the buffer type required by this device; communications
channels are allocated a larger proportion of the available buffer
space than character devices.  The reply parameter table is checked
to see if a buffer is already allocated; if one is, and is of the
correct type, no further action is required.  Otherwise the existing
buffer is de-allocated.  The allocation state of each buffer is
recorded in the arrays S.BUFFS.IN.USE and L.BUFFS.IN.USE; if no
buffer is currently allocated to a device the appropriate array
is searched until an unallocated buffer is found.  The size and location
of the buffer allocated is recorded in the reply table.
~BFinally the various physical device parameters are written to the
appropriate V-stores.
~S~O3.2 Data structures~
~T% 4 26
~
%TRANSFER.IN.PROG -~Ia variable indicating whether a sequence of output
data transfers is in progress. It contains the value of V.IO.CONTROL originally
transferred from MU6.~
~
%COUNT.CORRN -~Ia correction to be applied to the first transfer in
a sequence.~
~
%BUFFER.ALLOC -~Iindicates which buffer is being used by this channel.~
~
%BUFF.TYPE.ALLOC -~Iindicates whther this channel has a buffer allocated,
and if so whether it is a large or small type.~
~
%CONTROL -~Icontains the value of V.IO.CONTROL to be used for
output transfers in progress on this channel.~
~
%ADDRESS -~Icontains the last value of V.IO.ADDRESS sent to this
channel, (increased by the number of bytes transferred so far in the
case of output transfer).~
~
%COUNT -~Icontains the last value of V.IO.COUNT sent to this channel
(decreased by the number of bytes transferred so far in the case of
output transfer).~
~
%TRANSFER.COUNT -~Icontains the number of bytes requested from MU6 in
the most recent output data request.~
~
%BUFFER.ADDR -~Icontains the address of the buffer allocated to this channel.~
~
%BLOCK.SIZE -~Icontains the size of the buffer allocated to this
channel (and hence used as the maximum block size for output transfer).~
~
L.BUFFS.IN.USE )
  }-~Ivectors used to indicate which buffers are allocated.{~
{S.BUFFS.IN.USE )}~
~
TRANS.MESSAGE )
}  -~Ivectors in which the appropriate control messages are assembled.{~
{REQ.MESSAGE )}~
~Y
~V9 -1
~P
~D15
~HFLOWCHARTS
~
~
~H            AP7091
~V9 -1
~F
@TITLE AP709(1,11)
@COL 1S-2R-3R-4R-5R-6F
@FLOW 1-2-3-4-5-6
@BOX 1.0
I/O MANAGER APPENDIX
@BOX 4.0
PROCEDURES IN THIS MODULE
1  IO INTERRUPT
2  IO RECEIVE
3  IO RESET
4  IO INFORM
5  ADJUST
@BOX 5.0
INITIALISATION
@BOX 6.0
END
@BOX 1.1
#AP709/1
MODULE (IO.RESET, IO.INFORM, IO.RECEIVE, IO.INTERRUPT);
@BOX 2.1
TYPE IO.REPLY.TYPE IS
   LOGICAL8 BUFFER.ALLOC, BUFF.TYPE.ALLOC, COUNT.CORRN
   LOGICAL16 CONTROL, TRANSFER.COUNT, BLOCK.SIZE, TRANSFER.IN.PROG
   INTEGER16 COUNT
   LOGICAL32 ADDRESS, BUFFER.ADDR;
@BOX 3.1
*GLOBAL 5 ;
LITERAL / LOGICAL8 SET = %FF, RESET = 0, DATA.REQ = %F,
   NONE.ALLOC = 0, LARGE.BUFF = %F0, SMALL.BUFF = %F,
   TRANSFER.DONE = %FF, TRANSFER.FAILED = 0, OUTPUT = 1,
   DZ11.TYPE = 3;
LITERAL / LOGICAL16 INIT.CMD = 1, START.TR.CMD = 4, SOM = 1, EOM = 2,
   SHORT.MESS.PARAM = 11, FAULT.MASK = %FFE0, STOP.CMD = 0;
IO.REPLY.TYPE [SYS19.NO.OF.DEVICES] IO.REPLY.PARS;
LOGICAL16 DATA.TRANS.DEV.NO;
LOGICAL8 [SYS19.NO.OF.LARGE.BUFFERS] L.BUFFS.IN.USE;
LOGICAL8 [SYS19.NO.OF.SMALL.BUFFERS] S.BUFFS.IN.USE;
@BOX 4.1
PSPEC IO.RECEIVE () / LOGICAL32;
PSPEC IO.INTERRUPT ();
PSPEC IO.RESET ();
PSPEC IO.INFORM ();
PSPEC ADJUST (LOGICAL16) / LOGICAL16;
PSPEC INIT.AP709 ();
*CODE 2;
   #AP709.1
   #AP709.2
   #AP709.3
   #AP709.4
   #AP709.5
@BOX 5.1
*CODE 7;
INIT.AP709 ();
PROC INIT.AP709;
INTEGER DEV.NO;
SELECT IO.REPLY.PARS [DEV.NO];
FOR DEV.NO < SYS19.NO.OF.DEVICES DO
   RESET => TRANSFER.IN.PROG;
   0 => COUNT;
   NONE.ALLOC => BUFF.TYPE.ALLOC;
OD
FOR DEV.NO < SYS19.NO.OF.LARGE.BUFFERS DO
   RESET => L.BUFFS.IN.USE [DEV.NO];
OD
FOR DEV.NO < SYS19.NO.OF.SMALL.BUFFERS DO
   RESET => S.BUFFS.IN.USE [DEV.NO];
OD
END
@BOX 6.1
*END
@END
@TITLE AP709/1(1,11)
@COL 1S-2R-3R-4R
@FLOW 1-2-3-4
@BOX 1.0
OTHER MODULES REFERENCED
@BOX 4.0
SYS01 COORDINATOR
SYS19 CONFIGURATION MANAGER
@BOX 1.1
::EXTERNAL ENVIRONMENT
@BOX 2.1
IMPORT VSTORE LOGICAL VIO.DEV.NO, V.IO.COUNT, V.IO.CONTROL;
IMPORT VSTORE LOGICAL32 V.IO.ADDRESS;
IMPORT VSTORE LOGICAL16 V.IO.INT [], V.IO.P.DEV.PARS;
IMPORT VSTORE LOGICAL8 V.IO.P.DEV.NO, V.IO.P.DEV.TYPE,
   V.IO.P.DEV.MODE, V.IO.P.DEV.PROTOCOL;
@BOX 3.1
IMPORT LITERAL ADDR REAL.STORE.ADDRESS;
IMPORT LITERAL ADDR TRANS.MESSAGE.RA, REQ.MESSAGE.RA;
@BOX 4.1
PSPEC SYS01.NEXT.ACTIVITY ();
PSPEC CIU.TRANSMIT (ADDR, LOGICAL, ADDR, LOGICAL) / LOGICAL8;
IMPORT LITERAL INTEGER SYS19.NO.OF.DEVICES, SHORT.MESSAGE.LENGTH,
   SYS19.LARGE.BUFFER.SIZE, SYS19.SMALL.BUFFER.SIZE,
   SYS19.NO.OF.LARGE.BUFFERS, SYS19.NO.OF.SMALL.BUFFERS;
IMPORT LITERAL LOGICAL16 SYS19.MU6.IO.ADDR;
IMPORT LITERAL LOGICAL32 SYS19.BUFFER.BLOCK.ADDR;
LOGICAL32 [16] IO.P.DEV.NO.CONVERSION;
LOGICAL8 [SHORT.MESSAGE.LENGTH] REC.MESSAGE;
LOGICAL8 [SHORT.MESSAGE.LENGTH] TRANS.MESSAGE;
LOGICAL8 [SHORT.MESSAGE.LENGTH] REQ.MESSAGE;
LOGICAL8 CIU.TRANSMIT.BUSY;
@END
@TITLE AP709.1(1,11)
@COL 1S-9N-2T-3R-6R-4R-7R-5R-8F
@COL 10N-11R
@ROW 3-11
@ROW 9-10
@FLOW 1-9-2FOUND-3-6-4-7-5-9
@FLOW 2NONE-11-10-9
@BOX 1.0
IO INTERRUPT PROC
@BOX 2.0
FIND INTERRUPTING DEVICE
@BOX 3.0
CALCULATE DEVICE NUMBER
AND SELECT TABLE ENTRY
@BOX 4.0
FORM CONTROL MESSAGE
#AP709.1.1
@BOX 5.0
CALL CIU TRANSMIT PROC
@BOX 6.0
WAIT TILL CIU
TRANSMIT NOT BUSY
@BOX 7.0
ISSUE STOP COMMAND
TO DEVICE
@BOX 8.0
END
@BOX 11.0
WAIT FOR INTERRUPT
@BOX 1.1
PROC IO.INTERRUPT;
LOGICAL16 DEV.NO, GROUP.NO, IO.REQS, COUNT.TEMP;
LOGICAL8 TRANSMIT.STATUS;
LOGICAL32 ADDR.TEMP;
INTEGER I;
@BOX 2.1
0 => DEV.NO => GROUP.NO;
WHILE DEV.NO < SYS19.NO.OF.DEVICES
   AND V.IO.INT [GROUP.NO] => IO.REQS = 0 DO
   1 +> GROUP.NO;
   16 +> DEV.NO;
OD
IF DEV.NO >= SYS19.NO.OF.DEVICES
@BOX 3.1
WHILE IO.REQS & %8000 = 0 DO
   1 +> DEV.NO;
   IO.REQS <<- 1 => IO.REQS;
OD
DEV.NO => V.IO.DEV.NO;
@BOX 4.1
SELECT IO.REPLY.PARS [DEV.NO];
::FORM CONTROL MESSAGE
#AP709.1.1
@BOX 5.1
IF COUNT.TEMP /= 0 THEN
   ADJUST (COUNT.TEMP) => COUNT.TEMP;
FI
CIU.TRANSMIT (TRANS.MESSAGE.RA, SHORT.MESS.PARAM,
   BUFFER.ADDR, COUNT.TEMP) => TRANSMIT.STATUS;
@BOX 6.1
WHILE CIU.TRANSMIT.BUSY = SET DO
   *#%15DF %0000 %FFFE; ::ALLOW INTS
   *#%15DF %00E0 %FFFE; ::INHIBIT INTS
OD
SET => CIU.TRANSMIT.BUSY;
@BOX 7.1
STOP.CMD => V.IO.CONTROL;
@BOX 8.1
END
@BOX 11.1
SYS01.NEXT.ACTIVITY ();
@END
@TITLE AP709.1.1(1,11)
@COL 1S-16R-2T-3R-14F
@COL 6T-7R-12R
@ROW 3-6
@FLOW 1-16-2NO-3-14
@FLOW 2YES-6NO-7-14
@FLOW 6YES-12-14
@BOX 1.0
FORM CONTROL MESSAGE
@BOX 2.0
TRANSFER IN
PROGRESS?
@BOX 3.0
ENTER V-STORE
VALUES IF DATA TO SEND
@BOX 6.0
STATUS GOOD?
@BOX 7.0
FORM FAULT
MESSAGE
@BOX 12.0
FORM TRANSFER REQUEST
MESSAGE IF MORE DATA
@BOX 14.0
END
@BOX 16.0
ENTER COMMON
MESSAGE DATA
@BOX 1.1
::FORM CONTROL MESSAGE
@BOX 2.1
IF TRANSFER.IN.PROG & START.TR.CMD /= 0
@BOX 3.1
V.IO.COUNT => TRANS.MESSAGE [11];
V.IO.COUNT ->> 8 => TRANS.MESSAGE [12];
IF V.IO.P.DEV.PROTOCOL & OUTPUT = 0
   AND V.IO.COUNT /= COUNT THEN
   SET => TRANS.MESSAGE [2];
   COUNT - V.IO.COUNT + COUNT.CORRN => COUNT.TEMP;
FI
@BOX 6.1
IF V.IO.CONTROL & FAULT.MASK = 0
@BOX 7.1
V.IO.COUNT + COUNT => V.IO.COUNT => TRANS.MESSAGE [11];
V.IO.COUNT ->> 8 => TRANS.MESSAGE [12];
@BOX 12.1
IF COUNT > 0 THEN
   SOM & TRANSFER.IN.PROG -=> TRANSFER.IN.PROG;
   EOM & TRANSFER.IN.PROG -= TRANSFER.IN.PROG => CONTROL;
   IF COUNT > BLOCK.SIZE THEN
      BLOCK.SIZE => COUNT.TEMP;
   ELSE
      COUNT => COUNT.TEMP;
      TRANSFER.IN.PROG => CONTROL;
   FI
   COUNT.TEMP => TRANSFER.COUNT;
   ADJUST (COUNT.TEMP) => COUNT.TEMP => TRANS.MESSAGE [11];
   COUNT.TEMP ->> 8 => TRANS.MESSAGE [12];
   ADDRESS => ADDR.TEMP => TRANS.MESSAGE [7];
   ADDR.TEMP ->> 8 => ADDR.TEMP => TRANS.MESSAGE [8];
   ADDR.TEMP ->> 8 => ADDR.TEMP => TRANS.MESSAGE [9];
   ADDR.TEMP ->> 8 => TRANS.MESSAGE [10];
   0 => COUNT.TEMP;
   DATA.REQ => TRANS.MESSAGE [2];
ELSE
   0 => TRANSFER.IN.PROG;
FI
@BOX 14.1
::END
@BOX 16.1
FOR I < SHORT.MESSAGE.LENGTH DO
   0 => TRANS.MESSAGE [I];
OD
0 => COUNT.TEMP;
SYS19.MU6.IO.ADDR => TRANS.MESSAGE [0];
SYS19.MU6.IO.ADDR ->> 8 => TRANS.MESSAGE [1];
DEV.NO => TRANS.MESSAGE [3];
DEV.NO ->> 8 => TRANS.MESSAGE [4];
V.IO.CONTROL => TRANS.MESSAGE [5];
V.IO.CONTROL ->> 8 => TRANS.MESSAGE [6];
@END
@TITLE AP709.2(1,11)
@COL 1S-2R-3T-4T-5R-7R-6R-10F
@COL 8R-9R
@ROW 4-8
@FLOW 1-2-3NO-4NO-5-6-10
@FLOW 3YES-8-9-10
@FLOW 4YES-7-6
@BOX 1.0
IO.RECEIVE PROC
@BOX 2.0
TRANSFER MESSAGE
FROM CIU BUFFER
@BOX 3.0
DATA TRANSFER
MESSAGE?
@BOX 4.0
DATA TRANSFER
TO FOLLOW?
@BOX 5.0
NORMAL ACTION
#AP709.2.2
@BOX 6.0
RETURN ZERO
@BOX 7.0
INITIATE DATA
TRANSFER
#AP709.2.1
@BOX 8.0
FIND DEVICE NUMBER
AND ENTER IN DATA
TRANSFER FLAG
@BOX 9.0
RETURN APPROPRIATE
BUFFER ADDRESS
@BOX 10.0
END
@BOX 1.1
PROC IO.RECEIVE;
LOGICAL8 REQ.STATUS, P.DEV.TYPE.TEMP, P.DEV.NO.TEMP,
   BUFFER.TYPE;
LOGICAL16 LOG.DEV.NO.TEMP, CONTROL.TEMP,
   COUNT.TEMP, PARS.TEMP, BUFF.NO;
LOGICAL32 ADDRESS.TEMP, CONVERSION.PARAMS;
INTEGER I;
@BOX 2.1
REC.MESSAGE [4] <<- 8 ! REC.MESSAGE [3] => LOG.DEV.NO.TEMP;
REC.MESSAGE [6] <<- 8 ! REC.MESSAGE [5] => CONTROL.TEMP;
REC.MESSAGE [10] <<- 8 ! REC.MESSAGE [9] <<- 8
   ! REC.MESSAGE [8] <<- 8 ! REC.MESSAGE [7] => ADDRESS.TEMP;
REC.MESSAGE [12] <<- 8 ! REC.MESSAGE [11] => COUNT.TEMP;
SELECT IO.REPLY.PARS [LOG.DEV.NO.TEMP];
@BOX 3.1
IF REC.MESSAGE [2] = DATA.REQ
@BOX 4.1
IF REC.MESSAGE [2] = SET
@BOX 5.1
::NORMAL ACTION
#AP709.2.2
@BOX 6.1
0 => IO.RECEIVE;
@BOX 7.1
::INITIATE DATA TRANSFER
#AP709.2.1
@BOX 8.1
LOG.DEV.NO.TEMP => DATA.TRANS.DEV.NO;
@BOX 9.1
BUFFER.ADDR OF IO.REPLY.PARS [DATA.TRANS.DEV.NO]
   => IO.RECEIVE;
@BOX 10.1
END
@END
@TITLE AP709.2.1(1,11)
@COL 1S-2R-3R-7R-5R-6R-8F
@FLOW 1-2-3-7-5-6-8
@BOX 1.0
INITIATE DATA TRANSFER
@BOX 2.0
ENTER V-STORE VALUES
IN TABLE
@BOX 3.0
CALCULATE CORRECT
START POINT
AND SIZE
@BOX 5.0
FORM TRANSFER REQUEST MESSAGE
@BOX 6.0
CALL CIU TRANSMIT
@BOX 7.0
BOOK CIU TRANSMITTER
@BOX 8.0
END
@BOX 1.1
::INITIATE DATA TRANSFER
@BOX 2.1
CONTROL.TEMP => TRANSFER.IN.PROG;
ADDRESS.TEMP => ADDRESS;
COUNT.TEMP => COUNT;
@BOX 3.1
ADDRESS.TEMP & %7F => COUNT.CORRN +> COUNT.TEMP;
IF COUNT.TEMP > BLOCK.SIZE THEN
   BLOCK.SIZE => COUNT.TEMP;
   EOM & TRANSFER.IN.PROG -= TRANSFER.IN.PROG => CONTROL;
ELSE
   TRANSFER.IN.PROG => CONTROL;
FI
COUNT.TEMP => TRANSFER.COUNT;
ADJUST (COUNT.TEMP) => COUNT.TEMP;
@BOX 5.1
FOR I < SHORT.MESSAGE.LENGTH DO
   0 => REQ.MESSAGE [I];
OD
SYS19.MU6.IO.ADDR => REQ.MESSAGE [0];
SYS19.MU6.IO.ADDR ->> 8 => REQ.MESSAGE [1];
DATA.REQ => REQ.MESSAGE [2];
LOG.DEV.NO.TEMP => REQ.MESSAGE [3];
LOG.DEV.NO.TEMP ->> 8 => REQ.MESSAGE [4];
ADDRESS.TEMP => REQ.MESSAGE [7];
ADDRESS.TEMP ->> 8 => ADDRESS.TEMP => REQ.MESSAGE [8];
ADDRESS.TEMP ->> 8 => ADDRESS.TEMP => REQ.MESSAGE [9];
ADDRESS.TEMP ->> 8 => REQ.MESSAGE [10];
COUNT.TEMP => REQ.MESSAGE [11];
COUNT.TEMP ->> 8 => REQ.MESSAGE [12];
@BOX 6.1
CIU.TRANSMIT (REQ.MESSAGE.RA, SHORT.MESS.PARAM,
   0, 0) => REQ.STATUS;
@BOX 7.1
WHILE CIU.TRANSMIT.BUSY = SET DO
   *#%15DF %0000 %FFFE; ::ALLOW INTS
   *#%15DF %00E0 %FFFE; ::INHIBIT INTS
OD
SET => CIU.TRANSMIT.BUSY;
@BOX 8.1
::END
@END
@TITLE AP709.2.2(1,11)
@COL 1S-7R-2T-3R-6F
@COL 4R-5R
@ROW 3-4
@FLOW 1-7-2NO-3-6
@FLOW 2YES-4-5-6
@BOX 1.0
NORMAL ACTION
@BOX 2.0
INITIALISE COMMAND?
@BOX 3.0
WRITE TO V-STORES,
ENTER REPLY DETAILS
IN TABLE
@BOX 4.0
INITIALISE REPLY
TABLE ENTRY AND
DECODE PHYSICAL
DEVICE NUMBER
#AP709.2.2.1
@BOX 5.0
WRITE TO V-STORES
ISSUE STOP COMMAND
@BOX 6.0
END
@BOX 7.0
WRITE TO DEV.NO
V-STORE
@BOX 1.1
::NORMAL ACTION
@BOX 2.1
IF CONTROL.TEMP = INIT.CMD
@BOX 3.1
ADDRESS.TEMP & %7F => COUNT.CORRN + BUFFER.ADDR => V.IO.ADDRESS;
IF COUNT.TEMP + COUNT.CORRN > BLOCK.SIZE THEN
   BLOCK.SIZE - COUNT.CORRN => COUNT;
ELSE
   COUNT.TEMP => COUNT;
FI
COUNT => V.IO.COUNT;
CONTROL.TEMP => V.IO.CONTROL;
@BOX 4.1
::INIT TABLE, DECODE DEV.NO
#AP709.2.2.1
@BOX 5.1
P.DEV.TYPE.TEMP => V.IO.P.DEV.TYPE;
P.DEV.NO.TEMP => V.IO.P.DEV.NO;
REC.MESSAGE [15] => V.IO.P.DEV.MODE;
REC.MESSAGE [16] => V.IO.P.DEV.PROTOCOL;
REC.MESSAGE [18] <<- 8 ! REC.MESSAGE [17] => V.IO.P.DEV.PARS;
CONTROL.TEMP => V.IO.CONTROL;
STOP.CMD => V.IO.CONTROL;
@BOX 6.1
::END
@BOX 7.1
LOG.DEV.NO.TEMP => V.IO.DEV.NO;
@END
@TITLE AP709.2.2.1(1,11)
@COL 10R
@COL 1S-2R-3R-4R-5R-6T-7T-8R-9R-13F
@COL 11T-12R-14N
@ROW 6-11
@ROW 10-8
@ROW 13-14
@FLOW 1-2-3-4-5-6NO-7NO-8-9-13
@FLOW 6YES-11NO-12-7
@FLOW 11YES-14-13
@FLOW 7YES-10-9
@BOX 1.0
INITIALISE DEVICE, BUFFERS
@BOX 2.0
READ P.DEV.NO
@BOX 3.0
LOOK UP DATA
FOR DEV.TYPE
@BOX 4.0
FORM P.DEV.NO
AND P.DEV.TYPE
@BOX 5.0
FIND BUFFER TYPE
REQUIRED
@BOX 6.0
IS A BUFFER ALREADY
ALLOCATED?
@BOX 7.0
LARGE BUFFER
REQUIRED?
@BOX 8.0
ALLOCATE SMALL
BUFFER
@BOX 9.0
RECORD BUFFER
TYPE AND NUMBER
@BOX 10.0
ALLOCATE LARGE
BUFFER
@BOX 11.0
BUFFER OF
CORRECT TYPE?
@BOX 12.0
DE-ALLOCATE
PRESENT BUFFER
@BOX 13.0
END
@BOX 1.1
::INITIALISE DEVICE, BUFFER
@BOX 2.1
REC.MESSAGE [13] => P.DEV.NO.TEMP;
@BOX 3.1
IO.P.DEV.NO.CONVERSION [P.DEV.NO.TEMP ->> 4]
   => CONVERSION.PARAMS;
@BOX 4.1
CONVERSION.PARAMS ->> 16 => P.DEV.TYPE.TEMP;
IF P.DEV.TYPE.TEMP = DZ11.TYPE THEN
   P.DEV.NO.TEMP & %01 +> P.DEV.TYPE.TEMP;
FI
%F &> P.DEV.NO.TEMP;
CONVERSION.PARAMS ->> 4 & %F0 !> P.DEV.NO.TEMP;
@BOX 5.1
CONVERSION.PARAMS => BUFFER.TYPE;
@BOX 6.1
IF BUFF.TYPE.ALLOC /= NONE.ALLOC
@BOX 7.1
IF BUFFER.TYPE = LARGE.BUFF
@BOX 8.1
0 => BUFF.NO;
WHILE BUFF.NO < SYS19.NO.OF.SMALL.BUFFERS
   AND S.BUFFS.IN.USE [BUFF.NO] = SET DO
   1 +> BUFF.NO;
OD
SET => S.BUFFS.IN.USE [BUFF.NO];
SYS19.LARGE.BUFFER.SIZE * SYS19.NO.OF.LARGE.BUFFERS
   + SYS19.BUFFER.BLOCK.ADDR => BUFFER.ADDR;
BUFF.NO * SYS19.SMALL.BUFFER.SIZE +> BUFFER.ADDR;
SYS19.SMALL.BUFFER.SIZE => BLOCK.SIZE;
@BOX 9.1
BUFFER.TYPE => BUFF.TYPE.ALLOC;
BUFF.NO => BUFFER.ALLOC;
@BOX 10.1
0 => BUFF.NO;
WHILE BUFF.NO < SYS19.NO.OF.LARGE.BUFFERS
   AND L.BUFFS.IN.USE [BUFF.NO] = SET DO
   1 +> BUFF.NO;
OD
SET => L.BUFFS.IN.USE [BUFF.NO];
BUFF.NO * SYS19.LARGE.BUFFER.SIZE
   + SYS19.BUFFER.BLOCK.ADDR => BUFFER.ADDR;
SYS19.LARGE.BUFFER.SIZE => BLOCK.SIZE;
@BOX 11.1
IF BUFF.TYPE.ALLOC = BUFFER.TYPE
@BOX 12.1
IF BUFF.TYPE.ALLOC = LARGE.BUFF THEN
   RESET => L.BUFFS.IN.USE [BUFFER.ALLOC];
ELSE RESET => S.BUFFS.IN.USE [BUFFER.ALLOC];
FI
RESET => BUFF.TYPE.ALLOC;
@BOX 13.1
::END
@END
@TITLE AP709.3(1,11)
@COL 1S-2R-3F
@FLOW 1-2-3
@BOX 1.0
IO RESET PROC
@BOX 2.0
STOP DEVICES
RE-INITIALISE
@BOX 3.0
END
@BOX 1.1
PROC IO.RESET;
INTEGER DEVICE;
@BOX 2.1
::FOR DEVICE < SYS19.NO.OF.DEVICES DO
::   DEVICE => V.IO.DEV.NO;
::   STOP.CMD => V.IO.CONTROL;
::OD
::INIT.AP709 ();
@BOX 3.1
END
@END
@TITLE AP709.4(1,11)
@COL 1S-2R-3R-4R-5F
@FLOW 1-2-3-4-5
@BOX 1.0
IO INFORM PROC
@BOX 2.0
FIND DEVICE EXPECTING DATA
@BOX 3.0
WRITE TO V-LINES
@BOX 4.0
UPDATE REPLY TABLE.
RESET DATA TRANSFER
@BOX 5.0
END
@BOX 1.1
PROC IO.INFORM;
INTEGER COUNT.TEMP;
@BOX 2.1
SELECT IO.REPLY.PARS [DATA.TRANS.DEV.NO];
@BOX 3.1
DATA.TRANS.DEV.NO => V.IO.DEV.NO;
BUFFER.ADDR + COUNT.CORRN => V.IO.ADDRESS;
TRANSFER.COUNT - COUNT.CORRN => COUNT.TEMP => V.IO.COUNT;
CONTROL => V.IO.CONTROL;
@BOX 4.1
COUNT.TEMP +> ADDRESS;
COUNT.TEMP -> COUNT;
0 => COUNT.CORRN => DATA.TRANS.DEV.NO;
@BOX 5.1
END
@END
@TITLE AP709.5(1,11)
@COL 1S-2T-4R-6F
@COL 5R
@ROW 4-5
@FLOW 1-2NO-4-6
@FLOW 2YES-5-6
@BOX 1.0
ADJUST PROC
@BOX 2.0
VALUE ZERO?
@BOX 4.0
ROUND UP
@BOX 5.0
RETURN THREE
@BOX 6.0
END
@BOX 1.1
PROC ADJUST (BYTE.VAL);
@BOX 2.1
IF BYTE.VAL = 0
@BOX 4.1
BYTE.VAL + 7 & %FFF8 ->> 1 - 1 => ADJUST;
@BOX 5.1
3 => ADJUST;
@BOX 6.1
END
@END

