@X @~
~L3 COUK1247
80
~V7 56 2 -5
~D10
~H                    MUSS
~
~
~D10
~H            AP5042
~D10
~MMANCHESTER UNIVERSITY  -  CONFIDENTIAL~
~
~
                                                             ISSUE 11~
~V9 -1
~P
~V9 1
~YAP5042
~S1~M~OAP5 IMPLEMENTATION DESCRIPTION
~S1~M~OSection 4 Version 2
~S1~OSection 4.2 GEM Device Driver Appendix
~S1~O1. General Description
~BThis module is concerned with driving the Gemstone communications devices via
the line modules.
~S1~O2. Interfaces~
Other modules used~
   AP1 Section 3 (I/O Appendix)~
Ideal hardware registers used~
   None~
Interrupt procedures~
   GEM.INPUT.INT - RAW M/C LEVEL~
   GEM.OUTPUT.INT - RAW M/C LEVEL~
Interface procedures~
   I.CONTROL (PHYS.DEV.NO, COMMAND, ADDR, COUNT, I.MODE) STATUS~
   O.CONTROL (PHYS.DEV.NO, COMMAND, ADDR, COUNT, O.MODE) DUMMY~
Interface variables~
   None~
Configuration parameters~
   NO.OF.GEM.CHANNELS~
   NO.OF.GEM.DEVICES~
~S1~O2.1 MUSS Interface
~BThis module does not interface with MUSS in the normal
way.  Its only interface is a
procedural one with Appendix 1 Section 3 (the I/O Appendix).
~S1~O2.1.1 Hardware Interface
~BNone.
~S1~O2.1.2 Software Interface
~S11) I,CONTROL (PHYS.DEV.NO,COMMAND,BUFFER,ADDR,COUNT,I.O.MODE) STATUS
~BThis procedure implements the ideal input commands configure, disconnect, star
t,
disengage.  Some commands may result in immediate interrupts
(see 3.1), therefore this procedure returns a STATUS which contains
the interrupt status and count which would otherwise be returned by
calling the NOTIFY procedure of AP103.
~S12) O.CONTROL (PHYS.DEV.NO,COMMAND,BUFFER,ADDR,COUNT,I.O.MODE) DUMMY
~BThis procedure implements the ideal output commands configure,
disconnect, start, disengage.
~S1~O2.2 Gemstone Line Module Interface
~BSee Gemstone documentation.
~S1~O3. Implementation
~S1~O3.1 Outline of Operation
~BThe devices under the control of this module are managed through
the CONTROL procedure.  This has a command
parameter which may specify the operations~
~3
~
~Mconfigure  = 1
~Ndisconnect = 2
~Ndisengage  = 3
~Nstart      = 4-7
~0
~
~
encoded as in V.IO.CONTROL.  Started devices operate under the
rules specified by the MODE parameter, encoded as in V.IO.MODE.
When the command is start, the ADDR and COUNT parameters specify
a device buffer.  They have no significance when the command
is disengage or disconnect and in the case of initialise the 'ADDR' parameter
actually gives the logical device number.  This number is used
as the device identification when the NOTIFY procedure of AP103
is called.
~BAn input device may be in one of four internal modes, started,
stopped, disengaged or disconnected.
When a specified stopping condition arises on a started device,
or when the device buffer becomes full, the main I/O appendix is
notified and stopped mode is entered.
However, there is an overrun buffer which
allows input (up to the size limit of the overrun buffer) to be
received whilst the device is apparently stopped.
When the overrun buffer is nearly full an attempt is made to
prevent further input by removing the ready to receive signal.
If input continues to arrive characters will be lost.  If an apparently
stopped device is started the contents of its overrun buffer are
immediately copied to the device buffer,
and if a stopping condition is detected stopped mode is
immediately entered, otherwise new input will be accepted into the device
buffer until a stopping condition arises.
~BIn order to keep the path length minimal, in the case when the
required interrupt action is to transfer a character between buffer
and device, a table lookup technique is used to identify special
action characters.  There is a table with one entry per character
which defines particular properties of characters as follows~
~3
~U 12
~
          ~O                 ~O
          ~O| | | | | | | | |~O
           | | | | | | | |
           | | | | | | |  -- 'LINE' TERMINATOR (CR, LF, FF)
           | | | | | |  ---- ETX
           | | | | |  ------ ALL CHARACTERS
           | | | |  -------- STX
           | | |  ---------- CR
           | |  ------------ DEL, BS
           |  -------------- BREAK (ETX)
            ---------------- XON/XOFF
~0
~
~
As each input character is processed it is '&'d with the device MODE and a
non-zero result causes the special action implied by the most
significant '1' to be initiated.  These actions are as follows~
~3
~T% 20
~
%1) PAUSE OR RESUME output~
%2) Break both input and output~
%3) Delete previous character~
%4) Change CR to Newline (tnen act as for NL)~
%5) Start ignoring buffered prelude~
%6) Act according to status~
%7) Delete ETX and force transfer complete~
%8) Force transfer complete.~
~0
~
In addition, the buffer full condition has to be detected.~
~BThe only special action required on output involves the
detection of the buffer being empty.~
~BWhen a device is disengaged its overrun buffer is cleared.
Receipt of the first input character from a disengaged device
will cause stopped state to be entered and an engaged notification
is sent to the main I/O appendix.
~BAn output device may only be started, stopped or disconnected.  Disengage is a
null command in the case of output channels.
An output device may, however, be disengaged by requesting it to transmit FF
(ASCII group separator) character. Started devices
will output a character each time an interrupt is received
until the buffer is emptied, when stopped mode is assumed.
A started output device may be started again, in which case transfer
starts with the new count and address.
~BThe result returned by the I.CONTROL procedure
and the parameter of the NOTIFY procedure give the
interrupt status of the device, and, in the case of an
input transfer complete, a count of the number of
characters in the buffer.
~BA break condition can only occur when an input device is
started or when an output device is started/stopped. If the
output device is stopped, the break action will notify with
%0040 as the reason, otherwise as stated above.
~BAt system START UP time devices are put into disconnected mode.
The configure command may then
specify an operating mode and the mode will
switch to stopped.
~S2~O3.1.1 Procedures Private to This Module
~S11) INIT(DEV.NO,L.DEV.NO,SETTINGS)
~BThis procedure is used to initialise a device whenever it is reconfigured.  A
successful
initialisation puts the device into disengage mode.
~S12) RAW.INT
~BThis procedure services the I/O interrupts.  It is entered
directly from the interrupt vector and must therefore preserve the
register contents of any registers which it uses.  If the action
required is more than simply a transfer between device and buffer the
procedure will save the machine state and make a call into the
SPECIAL.CHAR procedure.
~S13) PROCESS.SPECIAL.CH(DEV.NO/COND)
~BThis procedure implements the device behaviour as described above.
~S14) COPY.OVERRUN()
~BThis procedure is used to copy characters from an overrun buffer
into the device buffer.
~S15) START.TRANSFER(DEV.NO, CMD)
~BThis procedure initiates the first commmand the the line module
controlling the device.
~S1~O3.2 Data Structures~
~T% 30
~
GEM.PARAMS~IAn array indexed by device number holding the
information required by the 'raw' interrupt procedure, namely~
~
~IPTR/VAL OF BUFF.PTR~
~ICOUNT~
~IMODE~
~IREQ.MODE~
~IPACKET~
~ISTART REG~
~
GEM.STATUS
~IAn array, indexed by device number, holding the status
of the device.~
~
GEM.BUFFERS~IAn array indexed by input device number,
holding the current starting address of each
buffer.~
~
CH.TABLE~IAn array of bytes indexed by character code.  The
bit encoding of the byte associated with each character indicates
whether or not it is special in any of the senses encoded into the
I.O.MODE.~
~
OVERRUN.AREA~IAn array of bytes into which the overrun buffers
are mapped.~
~
OVERRUN.BUFFS~IAn array indexed by input device number
(device number/2) holding the starting address of each overrun buffer.~
~
OVERRUN.SIZE~IAn integer literal giving the overrun buffer size.~
~
GEM.L.DEV
~IAn array, indexed by device number, giving the ideal
device corresponding to an GEM device.~
~
NO.OF.GEM.CHANNELS
~IAn integer literal, specifying the total number of the
GEM channels.~
~
NO.OF.GEM.DEVICES~IAn integer literal, specifying the total number
of input/output devices.~
~
~S1~O3.3 Special Notes
~Y
~V9 -1
~P
~D15
~HFLOWCHARTS
~
~
~H               AP5042
~V9 -1
~F
@TITLE AP504.GEM(2,11)

@COL 1S-2R-3R-4R-5R-6F
@FLOW 1-2-3-4-5-6
@BOX 1.0
GEM DEVICE DRIVER
@BOX 4.0
PROCEDURES IN MODULE:
   1 I CONTROL
   2 O CONTROL
   3 INIT
   4 RAW INPUT INT
   5 RAW OUTPUT INT
   6 ENTER SPECIAL CONDITION
   7 PROCESS ONE SPECIAL I CH
   8 PROCESS SPECIAL O CH
   9 ENTER OVERRUN
   10 START TRANSFER
   11 PROCESS SPECIAL I CH
@BOX 6.0
END
@BOX 1.1
#AP504.GEM/1
MODULE GEM (I.CONTROL, O.CONTROL, PROCESS.SPECIAL.I.CH, PROCESS.SPECIAL.O.CH,
   RESET.GEM);
@BOX 2.1
TYPE PTR.TYPE IS
   ADDR VAL
OR
   ADDR LOGICAL8 PTR;
TYPE PACKET.TYPE IS
   LOGICAL8 CMD1, CMD2, STATUS1, STATUS2
   LOGICAL64 ZERO
   LOGICAL8 CMD.COUNT, DATA.COUNT
   LOGICAL32 DATA.ADDR
   LOGICAL16 BYTE.COUNT;
TYPE GEM.PARAMS.TYPE IS
   PTR.TYPE BUFF.PTR
   INTEGER COUNT
   LOGICAL8 BIT.MASK, MODE
   ADDR PACKET.TYPE PACKET
   ADDR LOGICAL16 START.REG
   LOGICAL8 [16] CHAR;
@BOX 3.1
:: DATA DECLARATIONS
#AP504.GEM/2
@BOX 4.1
*CODE 23;
PSPEC RESET.GEM (INTEGER);
PROC RESET.GEM (DEV);
IF BYTE.COUNT OF PACKET^ OF GEM.PARAMS [DEV] /= 0 THEN
   0 => PACKET.SENT [DEV];
FI
END
PSPEC I.CONTROL (INTEGER, INTEGER, ADDR, INTEGER, LOGICAL32) / LOGICAL32;
PSPEC O.CONTROL (INTEGER, INTEGER, ADDR, INTEGER, LOGICAL32) / LOGICAL32;
PSPEC INIT (LOGICAL, LOGICAL, LOGICAL32);
:: RAW.INPUT.INT
:: RAW.OUTPUT.INT
:: ENTER.SPECIAL.CONDITION
PSPEC PROCESS.ONE.SPECIAL.I.CH (INTEGER, INTEGER);
PSPEC PROCESS.SPECIAL.O.CH (INTEGER);
PSPEC ENTER.OVERRUN (INTEGER);
PSPEC START.TRANSFER (INTEGER, INTEGER);
PSPEC PROCESS.SPECIAL.I.CH (INTEGER);
   #AP504.GEM.1
   #AP504.GEM.2
   #AP504.GEM.3
:: SWITCH ON LONG BRANCH ONLY MODE
   #AP504.GEM.4
   #AP504.GEM.5
   #AP504.GEM.6
:: SWITCH OFF LONG BRANCH ONLY MODE
   #AP504.GEM.7
   #AP504.GEM.8
   #AP504.GEM.9
   #AP504.GEM.10
   #AP504.GEM.11
@BOX 5.1
DATAVEC INT.LABS (LABEL);
   IN.0  OUT.0
   IN.1  OUT.1
   IN.2  OUT.2
   IN.3  OUT.3
END
*CODE 7;
PSPEC INIT.AP504 ();
INIT.AP504 ();
PROC INIT.AP504;
INTEGER I;
ADDR OB.ADDR;
ADDR [ADDR] INT;
ADDR ADDR INT.VEC;
ADDR PACKET.TYPE CONFIG.PKT;
ADDR LOGICAL16 CONFIG.START;
*VTYPE ADDR;
VSTORE WORKSPACE.PTR %840C06;
*VTYPE LOGICAL;
MAKE (ADDR, NO.OF.GEM.DEVICES, BYTE (^INT.LABS)) => INT;
FOR I < NO.OF.GEM.DEVICES DO
   INIT (I, 0, 0);
   MAKE (ADDR, 0, VEC.ADDR [I]) => INT.VEC;
   INT^ [I] => INT.VEC^;
OD
BYTE (^GEM.PARAMS [0]) => WORKSPACE.PTR;
BYTE (^OVERRUN.AREA) => OB.ADDR;
FOR I < NO.OF.GEM.CHANNELS DO
   OB.ADDR => OVERRUN.BUFFS [I];
   OVERRUN.SIZE +> OB.ADDR;
OD
MAKE (PACKET.TYPE, 0, CONFIG.PACKET) => CONFIG.PKT;
SELECT CONFIG.PKT^;
%13 => CMD1;
0 => CMD2 => STATUS1 => STATUS2 => CMD.COUNT;
0 => ZERO;
1 => DATA.COUNT;
BYTE (^CONF.PACKET) - %83E000 => DATA.ADDR;
%30 => BYTE.COUNT;
MAKE (LOGICAL16, 0, CONFIG.COMMAND) => CONFIG.START;
0 => CONFIG.START^;
END
@BOX 6.1
*END
@END
@TITLE AP504.GEM/1(2,11)

@COL 1S-2R-3R
@FLOW 1-2-3
@BOX 1.0
OTHER MODULES REFERENCED
@BOX 1.1
:: EXTERNAL ENVIRONMENT
@BOX 2.1
IMPORT LITERAL INTEGER NO.OF.GEM.CHANNELS,
   NO.OF.GEM.DEVICES, OVERRUN.SIZE, OVERRUN.AREA.SIZE,
   START.TR.CMD, START.COMMS.CMD, INIT.CMD, DISENGAGE.CMD, CON.OUT.CMD,
   TR.COMP, BREAKIN, ENGAGE.DEV, DISENGAGE.DEV, DEV.DISENGAGED;
IMPORT VSTORE LOGICAL32 V.TIME;
ADDR [NO.OF.GEM.DEVICES] PACKET.ADDR, COMMAND.ADDR, VEC.ADDR;
@BOX 3.1
PSPEC NOTIFY (INTEGER, LOGICAL, LOGICAL);
LOGICAL8 [256] I.CH.TABLE, O.CH.TABLE;
@END
@TITLE AP504.GEM/2(2,11)

@COL 1S
@BOX 1.0
DATA DECLARATIONS
@BOX 1.1
*GLOBAL 5;
LITERAL / LOGICAL8 ETX = 3, LF = %A, CR = %D, XON = %11, XOFF = %13, BS = 8;
LITERAL / LOGICAL8 CONNECTED = 1, ENGAGED = 2, OVERRUN = 4,
   STARTED = 8, PRELUDE = 16, FREE = %20, DISCONNECTED = %FE, DISENGAGED = %FD,
   STOPPED = %F7, NOT.PRELUDE = %EF, SUSPENDED = %DF, ALL = 4,
   OVERRUN.MASK = %F8, COPY.MASK = 7, NORMAL = %FB, LINE.MODE = 1,
   EDULERP = %1E, TX.ON = %80, TX.OFF = %7F, ECHO.ON = %10;
GEM.PARAMS.TYPE [NO.OF.GEM.DEVICES] GEM.PARAMS;
INTEGER [NO.OF.GEM.DEVICES] GEM.L.DEV;
LOGICAL8 [NO.OF.GEM.DEVICES] GEM.STATUS, REQ.MODE, PACKET.SENT;
LOGICAL8 [NO.OF.GEM.CHANNELS] STOP.RX;
*GLOBAL 24;
LOGICAL8 [OVERRUN.AREA.SIZE] OVERRUN.AREA;
*GLOBAL 5;
LOGICAL32 [NO.OF.GEM.CHANNELS] BREAK.TIME;
INTEGER [NO.OF.GEM.CHANNELS] XOFF.COUNT;
ADDR [NO.OF.GEM.CHANNELS] GEM.BUFFERS, OVERRUN.BUFFS;
LITERAL / ADDR CONFIG.COMMAND = %685400, CONFIG.PACKET = %40D480;
DATAVEC CONF.PACKET (LOGICAL16)
   %4C %4D %4E %4F %50 %51
   %401 %601
   0 [40]
END
@END

@TITLE AP504.GEM.1(2,11)

@COL 9T-10R-12T-11R-16T-13R-17R
@COL 1S-14R-2T-3T-5R-6R-15R-7F
@COL 8T
@ROW 3-9
@ROW 8-10
@ROW 5-12
@ROW 6-13
@ROW 15-17
@FLOW 1-14-2TRANSFER-3NO-5-6-15-7
@FLOW 8YES-7
@FLOW 3YES-8NO-5
@FLOW 2NON TRANSFER-9YES-10-11
@FLOW 9NO-12YES-11-15
@FLOW 12NO-16YES-13-7
@FLOW 16N0-17-7
@BOX 1.0
I CONTROL (DEV, COMMAND, BUFF.ADDR, I.SIZE, I.MODE)
-ASSUMES INTERRUPTS INHIBITED-
@BOX 2.0
CHECK COMMAND TYPE
@BOX 3.0
OVERRUN STATE
@BOX 5.0
SET BUFF.PTR/SIZE/MODE
IN GEM.PARAMS FOR DEV
@BOX 6.0
NOTE STATUS
@BOX 7.0
END
@BOX 8.0
COPY OVERRUN BUFFER
TO DEVICE BUFFER
#AP504.GEM.1.1
IS DEVICE STOPPED?
@BOX 9.0
CONFIGURE COMMAND?
@BOX 10.0
INITIALISE DEVICE
[AP504.GEM.3]
@BOX 11.0
SET DISENGAGED STATUS AND
SET NOTIFY ON ALL CHARS MODE
@BOX 12.0
DISENGAGE COMMAND?
@BOX 13.0
SET DISCONNECTED STATUS
AND DISABLE RECEIVER
@BOX 14.0
SELECT DEVICE PARAMETERS
@BOX 15.0
START DEVICE
@BOX 16.0
DISCONNECT COMMAND?
@BOX 17.0
RETURN DEVICE STATUS
@BOX 1.1
PROC I.CONTROL (DEV, CMD, BUFFER, I.SIZE, I.MODE);
INTEGER OVERRUN.CHARS;
0 => I.CONTROL => OVERRUN.CHARS;
@BOX 2.1
IF CMD & START.TR.CMD = 0
@BOX 3.1
IF CMD /= START.COMMS.CMD AND
   GEM.STATUS [DEV] & OVERRUN /= 0
@BOX 5.1
BUFFER => GEM.BUFFERS [DEV ->> 1]
   + OVERRUN.CHARS => VAL OF BUFF.PTR;
I.SIZE - OVERRUN.CHARS => COUNT;
REQ.MODE [DEV] => MODE;
@BOX 6.1
NORMAL & GEM.STATUS [DEV]
   ! STARTED => GEM.STATUS [DEV];
@BOX 7.1
END
@BOX 8.1
:: COPY OVERRUN
#AP504.GEM.1.1
IF I.CONTROL = 0
@BOX 9.1
IF CMD /= INIT.CMD
@BOX 10.1
INIT (DEV, BUFFER, I.MODE);
@BOX 11.1
ENTER.OVERRUN (DEV);
STARTED !> GEM.STATUS [DEV];
DISENGAGED &> GEM.STATUS [DEV];
REQ.MODE [DEV] & %80 ! ALL => MODE;
DISENGAGE.DEV => I.CONTROL;
@BOX 12.1
IF CMD /= DISENGAGE.CMD
@BOX 13.1
DISCONNECTED &> GEM.STATUS [DEV];
@BOX 14.1
SELECT GEM.PARAMS [DEV];
@BOX 15.1
START.TRANSFER (DEV, 2);
@BOX 16.1
IF CMD /= CON.OUT.CMD
@BOX 17.1
IF GEM.STATUS [DEV] & ENGAGED = 0 THEN
   DEV.DISENGAGED !> I.CONTROL;
FI
@END
@TITLE AP504.GEM.1.1(2,11)

@COL 1S-2T-3R-4R-5R-6R-7R-8F
@FLOW 1-2YES-3-4-5-6-7-8
@FLOW 2NO-8
@BOX 1.0
COPY OVERRUN BUFFER
@BOX 2.0
ANY OVERRUN
@BOX 3.0
SET OVERRUN.CHARS TO THE MAXIMUM AMOUNT
OF OVERRUN WHICH THE DEVICE BUFFER WILL HOLD
AND SET RESULT IF BUFFER FULL CONDITION IMPLIED
@BOX 4.0
RESET OVERRUN.CHARS TO EXCLUDE ANY
OVERRUN AFTER MOST RECENT NOTIFY CONDITION
AND RESET RESULT ACCORDINGLY
@BOX 5.0
COPY THE AMOUNT SPECIFIED BY OVERRUN.CHARS
FROM OVERRUN TO DEVICE BUFFERS
@BOX 6.0
DELETE COPIED CHARS FROM
OVERRUN BUFFER
@BOX 7.0
REMOVE ETX FROM END OF DEV BUFFER IF ANY
@BOX 8.0
END
@BOX 1.1
:: COPY OVERRUN
BEGIN
INTEGER I, K, COPY.MODE;
ADDR [LOGICAL8] DEV.B, ORUN.B;
MAKE (LOGICAL8, I.SIZE, BUFFER) => DEV.B;
MAKE (LOGICAL8, OVERRUN.SIZE, OVERRUN.BUFFS [DEV ->> 1]) => ORUN.B;
@BOX 2.1
IF OVERRUN.SIZE - COUNT => OVERRUN.CHARS = 0
@BOX 3.1
IF OVERRUN.CHARS > I.SIZE THEN
   I.SIZE => OVERRUN.CHARS;
   TR.COMP => I.CONTROL;
FI
@BOX 4.1
REQ.MODE [DEV] & COPY.MASK => COPY.MODE;
FOR I < OVERRUN.CHARS DO
   IF I.CH.TABLE [ORUN.B^ [OVERRUN.CHARS - I - 1]] & COPY.MODE /= 0 THEN
      I -> OVERRUN.CHARS;
      TR.COMP => I.CONTROL;
      -> OUT;
   FI
OD
0 => I;
OUT:
@BOX 5.1
FOR K < OVERRUN.CHARS DO
   ORUN.B^ [K] => DEV.B^ [K];
OD
@BOX 6.1
FOR K < I DO
   ORUN.B^ [K + OVERRUN.CHARS] => ORUN.B^ [K];
OD
OVERRUN.CHARS -> VAL OF BUFF.PTR;
OVERRUN.CHARS +> COUNT;
IF I.CONTROL /= 0 THEN
   I.SIZE - OVERRUN.CHARS <<- 16
      !> I.CONTROL;
FI
@BOX 7.1
IF REQ.MODE [DEV] & 2 /= 0 AND
   DEV.B^ [OVERRUN.CHARS - 1] = ETX THEN
   1 -> OVERRUN.CHARS;
FI
@BOX 8.1
END
@END
@TITLE AP504.GEM.2(2,11)

@COL 9T-10R-12T-11R-15T-13R-16R
@COL 1S-2T-3T-14R-17T-5R-8R-6R-20R-7F
@COL 4R-18R-19N
@ROW 3-9
@ROW 4-14
@ROW 5-18
@ROW 6-16
@FLOW 1-2TRANSFER-3NO-14-17NO-5-8-6-20-7
@FLOW 2NON TRANSFER-9YES-10-7
@FLOW 3YES-4-19-7
@FLOW 9NO-12YES-11-7
@FLOW 12NO-15YES-13-7
@FLOW 15NO-16-7
@FLOW 17YES-18-19
@BOX 1.0
O CONTROL (DEV, COMMAND, BUFF.ADDR, O.SIZE, O.MODE)
-ASSUMES INTERRUPTS INHIBITED-
@BOX 2.0
CHECK COMMAND TYPE
@BOX 3.0
BUFFER EMPTY?
@BOX 4.0
RETURN TRANSFER COMPLETE
STATUS
@BOX 5.0
SET BUFF.PTR/SIZE/MODE
IN GEM.PARAMS FOR DEV
@BOX 6.0
START DEVICE AND
NOTE STATUS
@BOX 7.0
END
@BOX 8.0
OBTAIN FIRST CH TO OUTPUT
@BOX 9.0
CONFIGURE COMMAND?
@BOX 10.0
INITIALISE DEVICE
[AP504.GEM.3]
AND SET STOPPED STATUS
@BOX 11.0
SET DISENGAGE STATUS
@BOX 12.0
DISENGAGE COMMAND?
@BOX 13.0
SET DISCONNECTED STATUS
@BOX 14.0
SELECT DEVICE PARAMETERS
@BOX 15.0
DISCONNECT COMMAND?
@BOX 16.0
RETURN DEVICE STATUS
@BOX 17.0
OUTPUT SUSPENDED?
@BOX 18.0
NOTE REQUIRED COUNT
@BOX 20.0
PROCESS SPECIAL CHARACTER IF REQUIRED
@BOX 1.1
PROC O.CONTROL (DEV, CMD, BUFFER, O.SIZE, O.MODE);
LOGICAL8 CH, COND, BIT.COND;
0 => O.CONTROL;
@BOX 2.1
IF CMD & START.TR.CMD = 0
@BOX 3.1
IF O.SIZE = 0
@BOX 4.1
TR.COMP
   => O.CONTROL;
@BOX 5.1
BUFFER => VAL OF BUFF.PTR;
O.SIZE => COUNT;
TX.ON ! REQ.MODE [DEV] => MODE;
@BOX 6.1
STARTED !> GEM.STATUS [DEV];
CH => CHAR [0];
START.TRANSFER (DEV, 1);
@BOX 7.1
END
@BOX 8.1
PTR^ OF BUFF.PTR => CH;
1 +> VAL OF BUFF.PTR;
1 -> COUNT;
@BOX 9.1
IF CMD /= INIT.CMD
@BOX 10.1
INIT (DEV, BUFFER, O.MODE);
STOPPED &> GEM.STATUS [DEV];
FREE ! ENGAGED !> GEM.STATUS [DEV];
@BOX 11.1
DISENGAGED &> GEM.STATUS [DEV];
DISENGAGE.DEV !> O.CONTROL;
@BOX 12.1
IF CMD /= DISENGAGE.CMD
@BOX 13.1
DISCONNECTED &> GEM.STATUS [DEV];
@BOX 14.1
SELECT GEM.PARAMS [DEV];
@BOX 15.1
IF CMD /= CON.OUT.CMD
@BOX 16.1
IF GEM.STATUS [DEV] & ENGAGED = 0 THEN
   DEV.DISENGAGED !> O.CONTROL;
FI
@BOX 17.1
IF GEM.STATUS [DEV] & FREE = 0
@BOX 18.1
BUFFER => VAL  OF BUFF.PTR;
O.SIZE => XOFF.COUNT [DEV ->> 1];
REQ.MODE [DEV] => MODE;
@BOX 20.1
IF O.CH.TABLE [CH] & MODE => BIT.COND /= 0 THEN
   7 => COND;
   WHILE BIT.COND & %80 = 0 DO
      1 -> COND;
      BIT.COND <<- 1 => BIT.COND;
   OD
   PROCESS.SPECIAL.O.CH (DEV <<- 8 ! COND);
FI
@END
@TITLE AP504.GEM.3(2,11)

@COL 1S-6R-4R-2R-3R-5F
@FLOW 1-6-4-2-3-5
@BOX 1.0
INIT (PHYSICAL DEV NO, LOGICAL DEV NO, SETTINGS)
@BOX 2.0
GENERATE CONTROL REGISTER ADDRESS
@BOX 3.0
SEND CONFIGURATION INFORMATION
TO THE LINE MODULE
@BOX 4.0
SET UP DEVICE MODE
@BOX 5.0
END
@BOX 6.0
NOTE LOGICAL DEVICE NO
@BOX 1.1
PROC INIT (DEV, L.DEV, SET);
DATAVEC BIT.MASKS (LOGICAL8)
   %1F %3F %7F %FF
END
@BOX 2.1
SELECT GEM.PARAMS [DEV];
MAKE (PACKET.TYPE, 0, PACKET.ADDR [DEV]) => PACKET;
MAKE (LOGICAL16, 0, COMMAND.ADDR [DEV]) => START.REG;
@BOX 3.1
BIT.MASKS [SET ->> 10 & 3] => BIT.MASK;
@BOX 4.1
SET => REQ.MODE [DEV];
@BOX 5.1
END
@BOX 6.1
L.DEV => GEM.L.DEV [DEV];
@END
@TITLE AP504.GEM.4(2,11)

@COL 1S-15R-16R-17T-5R-4T-6R-19T-7T-27R-2T-21R-8R-20F
@COL 24N-22R
@ROW 24-7
@FLOW 1-15-16-17NO-5-4NO-6-19NO-7NO-27-2NO-21-8
@FLOW 17YES-8
@FLOW 4YES-24
@FLOW 7YES-24-22
@FLOW 19YES-24
@FLOW 2YES-5
@BOX 1.0
RAW INPUT INT
@BOX 2.0
ANY MORE CHARACTERS?
@BOX 4.0
BREAK IN?
@BOX 5.0
GET CHARACTER
@BOX 6.0
PLACE CHAR IN BUFFER
@BOX 7.0
IS THE BUFFER FULL
@BOX 8.0
UNSTACK REGISTERS,
REMOVE "PARAMETER" AND
RETURN FROM INT
@BOX 15.0
LEAVE SPACE FOR PROC PARAM
(IF REQUIRED)
AND STACK REGISTERS
@BOX 16.0
SET PTRS TO GEM PARAMS
#AP504.GEM.4.3
@BOX 17.0
IS INTERRUPT TO BE IGNORED?
@BOX 19.0
SPECIAL CHAR?
@BOX 20.0
END
@BOX 21.0
RESTART DEVICE
@BOX 22.0
ENTER PROCESS-SPECIAL-I-CH
@BOX 27.0
ECHO IF REQUIRED
@BOX 1.1
IN.0: *#%3F3C %0000; ::MOVW #0, -(A7);
-> RAW.INPUT.INT;

IN.1: *#%3F3C %0002; ::MOVW #2, -(A7);
-> RAW.INPUT.INT;

IN.2: *#%3F3C %0004; ::MOVW #4, -(A7);
-> RAW.INPUT.INT;

IN.3: *#%3F3C %0006; ::MOVW #6, -(A7);
-> RAW.INPUT.INT;
RAW.INPUT.INT:
@BOX 2.1
I.OUT:
*#%2069 %0008; ::MOVAL 8(A1), A0;
*#%0468 %0001 %0012; ::SUBI 1, 18(A0);
*#%6F04; ::BLE +4;
-> NEXT.CHAR;
*#%4E71; ::NO OP
@BOX 4.1
::BREAK?
@BOX 5.1
NEXT.CHAR:
*#%4280; :: CLRL D0
*#%2668 %000E; ::MOVAL 14(A0), A3;
*#%101B; ::MOVB (A3)+, D0;
*#%214B %000E; ::MOVL A3, 14(A0);
@BOX 6.1
NO.BREAK:
*#%C029 %0006; :: ANDB 6(A1), D0
*#%14C0; :: MOVEB D0, (A2)+
*#%5369 %0004; :: SUBIW #1, 4(A1)
*#%228A; :: MOVEL A2, (A1)
@BOX 7.1
*#%4A69 %0004; :: TSTW 4(A1)
*#%6704; :: BEQ +4
-> ECHO; ::
*#%4E71; :: NOP
:: TEMP UNTIL GET LBO MODE
*#%7201  ::MOVEQ #1, D1
-> ENTER.PROCESS.SPECIAL; ::
@BOX 8.1
I.IGNORE:
*#%4CDF %0F07;
:: MOVEML (A7)+, D0 - D2, A0 - A3
*#%5C8F; :: ADDQL #6, A7
*#%4E73; :: RTE
@BOX 15.1
*#%2F3C %0000 %0025; ::MOVL #37, -(A7);
*#%48E7 %E0F0;
:: MOVEML D0 - D2, A0 - A3, -(A7)
@BOX 16.1
*#%4282; ::CLRL D2;
*#%342F %0020; ::MOVW 32(A7), D2;
*#%2002; ::MOVL D2, D0;
*#%EB88; ::LSLL #5, D0;
*#%D0B9 %0084 %0C06; ::ADDL WORKSPACE.PTR, D0;
*#%2240; ::MOVAL D0, A1 <GEM PARAM PTR>;
*#%2451; ::MOVAL (A1), A2 <BUFF PTR>;
@BOX 17.1
*#%2069 %0008; ::MOVAL 8(A1), A0;
::A0 = PACKET ADDRESS;
*#%2009; ::MOVL A1, D0;
*#%0480 %0083 %DFF0; ::SUBL VIRT ADDR - 16, D0;
*#%2140 %000E; ::MOVL D0, 14(A0);
*#%0C10 %0011; ::CMPB (A0), %11;
*#%6704; ::BEQ +4;
-> I.IGNORE;
*#%4A28 %0002; ::TSTB 2(A0);
*#%6704; ::BEQ +4;
-> I.IGNORE; ::
@BOX 19.1
*#%2679 %0084 %0C16;
:: MOVEAL I.CH.TALE.PTR, A3
*#%4281; :: CLRL D1
*#%1233 %0000; :: MOVEB 0(A3, D0.W), D1
*#%C229 %0007; :: ANDB 7(A1), D1
*#%6704; :: BEQ +4
-> ENTER.PROCESS.SPECIAL;
*#%4E71; :: NOP
:: TEMP UNTIL GET LBO MODE
@BOX 21.1
*#%2069 %0008; ::MOVAL 8(A1), A0;
::A0 = INPUT PACKET ADDRESS;
*#%117C %0001 %000D; ::MOVB #1, 13(A0) DATA COUNT;
*#%317C %0000 %0012; ::MOVW #0, 18(A0) BYTE COUNT;
*#%2149 %000E; ::MOV A1, 14(A0) DATA ADDR;
*#%04A8 %0083 %DFF0 %000E; ::SUBL VIRT ADDR - 16, 14(A0);
*#%2069 %000C; ::MOVAL 12(A1), A0 START REG;
*#%4250; ::CLRW (A0);
@BOX 22.1
SPECIAL.CASE.I:
-> ENTER.PROCESS.SPECIAL;
@BOX 27.1
ECHO:
*#%0829 %0004 %0027; :: BTST #4, 39(A1)
*#%6604; :: BNE + 4
-> I.OUT;
*#%4E71; :: NOP
*#%4A29 %0027; :: TST 39(A1)
*#%6A08; :: BPL + 8
*#%1340 %0026; ::MOVB D0, 38(A1);
-> I.OUT;
*#%1340 %0030; ::MOVB D0, 48(A1);
*#%2069 %0028; ::MOVAL 40(A1), A0;
::A0 = OUTPUT PACKET ADDRESS;
*#%117C %0001 %000D; ::MOVB #1, 13(A0) DATA COUNT;
*#%317C %0001 %0012; ::MOVW #1, 18(A0) BYTE COUNT;
*#%2149 %000E; ::MOV A1, 14(A0) DATA ADDR;
*#%04A8 %0083 %DFD0 %000E; ::SUBL VIRT ADDR - 48, 14(A0);
*#%2069 %002C; ::MOVAL 44(A1), A0 START REG;
*#%4250; ::CLRW (A0);
*#%B03C %000D; :: CMPB #CR, D0
*#%6606; :: BNE + 6
*#%137C %000A %0026; :: MOVB #NL, 38(A1)
@END

@TITLE AP504.GEM.5(2,11)

@COL 1S-18R-3R-25T-9T-10R-11T-12R-4R-2F

@FLOW 1-18-3-25NO-9YES-10-11YES-12
@FLOW 25YES-4
@FLOW 9NO-12
@FLOW 11NO-4
@BOX 1.0
OUTPUT INTERRUPT
@BOX 2.0
END
@BOX 3.0
SET POINTER TO GEM PARAMS
@BOX 4.0
UNSTACK REGISTERS
REMOVE "PARAMETER" AND
RETURN FROM INT
@BOX 9.0
MORE CHARS IN BUFFER?
@BOX 10.0
OUTPUT CHAR
@BOX 11.0
SPECIAL CHAR?
@BOX 12.0
ENTER PROCESS-SPECIAL-O-CH
@BOX 18.0
STACK REGISTERS
@BOX 25.0
CHARACTER ECHOED?
@BOX 1.1
OUT.0: *#%3F3C %0001; ::MOVW #1, -(A7);
-> RAW.OUTPUT.INT;

OUT.1: *#%3F3C %0003; ::MOVW #3, -(A7);
-> RAW.OUTPUT.INT;

OUT.2: *#%3F3C %0005; ::MOVW #5, -(A7);
-> RAW.OUTPUT.INT;

OUT.3: *#%3F3C %0007; ::MOVW #7, -(A7);
-> RAW.OUTPUT.INT;
RAW.OUTPUT.INT:
@BOX 3.1
*#%4282; ::CLRL D2;
*#%342F %0020; ::MOVW 32(A7), D2;
*#%2002; ::MOVL D2, D0;
*#%EB88; ::LSLL #5, D0;
*#%D0B9 %0084 %0C06; ::ADDL WORKSPACE PTR, D0;
*#%2240; ::MOVAL D0, A1 GEM PARAM PTR;
*#%2451; ::MOVAL (A1), A2 BUFFER PTR;
@BOX 4.1
O.OUT: *#%4CDF %0F07; ::MOVML (A7)+, D0-D2, A0-A3;
*#%5C8F; ::ADDQL #6, A7;
*#%4E73; ::RTE;
@BOX 9.1
OUT.BUF.CH:
*#%4A69 %0004; :: TSTW 4(A1)
*#%6F04; :: BLE +4
-> OUTPUT; ::
*#%4E71; :: NOP
:: TEMP UNTIL GET LBO MODE
*#%323C %0080; :: MOVEW #%80, D1
-> ENTER.PROCESS.SPECIAL; ::
@BOX 10.1
OUTPUT:
*#%4280; :: CLRL D0
*#%101A; :: MOVEB (A2)+, D0
*#%2069 %0008; ::MOVAL 8(A1), A0;
::A0 = OUTPUT PACKET ADDRESS;
*#%117C %0001 %000D; ::MOVB #1, 13(A0) DATA COUNT;
*#%317C %0001 %0012; ::MOVW #1, 18(A0) BYTE COUNT;
*#%1340 %0010; ::MOVB D0, 16(A0) CHAR;
*#%2149 %000E; ::MOV A1, 14(A0) DATA ADDR;
*#%04A8 %0083 %DFF0 %000E; ::SUBL VIRT ADDR - 16, 14(A0);
*#%2069 %000C; ::MOVL 12(A1), A0 START REG;
*#%4250; ::CLRW (A0);
*#%228A; :: MOVEL A2, (A1)
*#%5369 %0004; :: SUBIW #1, 4(A1)
@BOX 11.1
*#%2679 %0084 %0C1E;
::MOVEAL O.CH.TABLE.PTR, A3
*#%4281; :: CLRL D1
*#%1233 %0000; :: MOVEB 0(A3, D0.W), D1
*#%C229 %0007; :: ANDB 7(A1), D1
*#%6604; :: BNE +4
-> O.OUT; ::
*#%4E71; :: NOP
:: TEMP UNTIL GET LBO MODE
@BOX 12.1
SPECIAL.CASE.O:
-> ENTER.PROCESS.SPECIAL;
@BOX 18.1
*#%2F3C %0000 %0026; ::MOVL #38, -(A7);
*#%48E7 %E0F0; ::MOVEML D0-D2, A0-A3, -(A7);
@BOX 25.1
*#%1029 %0006; :: MOVB 6(A1), D0
*#%6604; :: BNE +4
-> OUT.BUF.CH;
*#%4E71; :: NOP
*#%2069 %0008; ::MOVAL 8(A1), A0;
::A0 = OUTPUT PACKET ADDRESS;
*#%117C %0001 %000D; ::MOVB #1, 13(A0) DATA COUNT;
*#%317C %0001 %0012; ::MOVW #1, 18(A0) BYTE COUNT;
*#%1340 %0010; ::MOVB DO, 16(A1) CHAR;
*#%2149 %000E; ::MOV A1, 14(A0) DATA ADDR;
*#%04A8 %0083 %DFF0 %000E; ::SUBL VIRT ADDR - 16, 14(A0);
*#%2069 %000C; ::MOVL 12(A1), A0 START REG;
*#%4250; ::CLRW (A0);
*#%B03C %000D; :: CMPB CR, DO
*#%6608; :: BNE + 8
*#%137C %000A %0006; :: MOVB #NL, 6(A1)
*#%6004; :: BRA + 4
*#%4229 %0006; :: CLRB 6(A1)
-> O.OUT;
::
@END
@TITLE AP504.GEM.6(2,11)

@COL 1S-3R-4R-5R-6F
@FLOW 1-3-4-5
@BOX 1.0
ENTER PROCESS SPECIAL
@BOX 3.0
OBTAIN CONDITION INDEX
@BOX 4.0
GENERATE DEV.NO/COND.INDEX PARAM
AND PLACE ON STACK
@BOX 5.0
UNSTACK REGISTERS USED
AND JUMP TO INT PROC ENTRY CODE
@BOX 6.0
END
@BOX 1.1
ENTER.PROCESS.SPECIAL:
BEGIN
@BOX 3.1
*#%4280; :: CLRL D0
*#%0C41 %000F; :: CMPIW #%F, D1
*#%6F04; :: BLE +4
*#%E809 :: LSRB #4, D1
*#%5800; :: ADDQB #4, D0
*#%0C01 %0003; :: CMPIB #03, D1
*#%6F04; :: BLE +4
*#%E409 :: LSRB #2, D1
*#%5400; :: ADDQB #2, D0
*#%0C01 %0001; :: CMPIB #1, D1
*#%6F02; :: BLE +2
*#%5200; :: ADDQL #1, D0
@BOX 4.1
*#%E14A; :: LSLW #8, D2
*#%8400; :: ORB D0, D2
*#%3F42 %0020; :: MOVEW D2, 32(A7)
@BOX 5.1
*#%4CDF %0F07; :: MOVEML (A7)+, D0 - D2, A0 - A3
*#%4EF9 %80 %0000; :: JMP %800000
@BOX 6.1
END
@END

@TITLE AP504.GEM.7(2,11)

@COL 10C-11R-12C-13R-14C-15R-22N
@COL 1S-2R-28R-3R-4C-5R-6T-7C-8R-23N-29R-9F
@COL 16C-17R-18C-30T-25T-31T-19R-26R-20C-21R-27R-24N
@ROW 10-4-16
@ROW 22-23
@FLOW 1-2-28-3
@FLOW 4-5-6YES-7-8-23-29-9
@FLOW 6NO-23
@FLOW 10-11-22-23
@FLOW 12-13-22
@FLOW 14-15-22
@FLOW 16-17-8
@FLOW 18-30NO-25NO-31NO-19-23
@FLOW 31YES-23
@FLOW 20-21-27-24-23
@FLOW 25YES-26-24
@FLOW 30YES-23
@BOX 1.0
PROCESS ONE SPECIAL I CH (DEV, COND)
@BOX 2.0
SELECT GEM PARAMS
FOR SPECIFIED DEVICE
@BOX 3.0
SWITCH ON COND
@BOX 4.0
CR
@BOX 5.0
CHANGE BUFF CHAR TO LF
@BOX 6.0
BUFF FULL OR LINE MODE
@BOX 7.0
XFER CH/BUFF FULL
@BOX 8.0
NOTIFY AND ENTER OVERRUN MODE
@BOX 9.0
END
@BOX 10.0
DEL
@BOX 11.0
DELETE PREVIOUS CH
@BOX 12.0
STX
@BOX 13.0
SET STATUS FOR PRELUDE
AND MODE TO ALL
@BOX 14.0
ALL
@BOX 15.0
PROCESS ALL CONDITION
ACCORDING TO STATUS
#AP504.GEM.7.1
@BOX 16.0
ETX
@BOX 17.0
DELETE ETX AND
ADJUST COUNT
@BOX 18.0
BREAK
@BOX 19.0
STOP DEVICE,
CLEAR OVERRUN
AND NOTIFY
@BOX 20.0
XOFF/XON
@BOX 21.0
DELETE AND NOTE CH
@BOX 25.0
BREAK IS
ENGAGE/DISENGAGE?
@BOX 26.0
NOTE WHETHER ENGAGE
OR DISENGAGE REQUIRED
@BOX 30.0
MULTIPLE BREAK?
@BOX 27.0
PROCESS XOFF/XON
#AP504.GEM.7.2
@BOX 28.0
NOTE CHARACTER TO BE ECHOED
@BOX 29.0
ECHO CHARACTER IF REQUIRED
@BOX 31.0
DEVICE DISENGAGED?
@BOX 1.1
PROC PROCESS.ONE.SPECIAL.I.CH (DEV, COND);
INTEGER CH, REASON, CNT, ECHO.CH;
@BOX 2.1
SELECT GEM.PARAMS [DEV];
@BOX 3.1
SWITCH COND \
   EOM, ETX, PROCESS.ALL, STX,
   CR, DEL, BREAK, XOFF.XON;
@BOX 4.1
CR:
@BOX 5.1
1 -> VAL OF BUFF.PTR;
LF => PTR^ OF BUFF.PTR;
 1 +> VAL OF BUFF.PTR;
@BOX 6.1
IF COUNT /= 0 AND MODE & LINE.MODE = 0
@BOX 7.1
EOM:
@BOX 8.1
IF GEM.STATUS [DEV] & OVERRUN = 0 THEN
   COUNT => CNT;
   ENTER.OVERRUN (DEV);
   NOTIFY (GEM.L.DEV [DEV], TR.COMP, CNT);
ELSE
   STOPPED &> GEM.STATUS [DEV];
   ALL => MODE;
FI
@BOX 9.1
END
@BOX 10.1
DEL:
@BOX 11.1
IF 1 -> VAL OF BUFF.PTR /=
   GEM.BUFFERS [DEV ->> 1] THEN
   1 -> VAL OF BUFF.PTR;
   2 +> COUNT;
   BS => ECHO.CH;
ELSE
   1 +> COUNT;
   0 => ECHO.CH;
FI
@BOX 12.1
STX:
@BOX 13.1
1 +> COUNT;
1 -> VAL OF BUFF.PTR;
ALL => MODE;
PRELUDE !> GEM.STATUS [DEV];
@BOX 14.1
PROCESS.ALL:
@BOX 15.1
#AP504.GEM.7.1
@BOX 16.1
ETX:
@BOX 17.1
1 +> COUNT;
1 -> VAL OF BUFF.PTR;
@BOX 18.1
BREAK:
@BOX 19.1
IF GEM.STATUS [DEV] & (OVERRUN ! STARTED)
   = STARTED THEN
   BREAKIN ! TR.COMP => REASON;
ELSE
   BREAKIN => REASON;
FI
NOTIFY (GEM.L.DEV [DEV], REASON, COUNT);
0 => COUNT OF GEM.PARAMS [DEV + 1];
IF GEM.STATUS [DEV + 1] & STARTED /= 0 THEN
   NOTIFY (GEM.L.DEV [DEV + 1],
      BREAKIN ! TR.COMP, 0);
FI
STOPPED & GEM.STATUS [DEV + 1] ! FREE => GEM.STATUS [DEV + 1];
ENTER.OVERRUN (DEV);
@BOX 20.1
XOFF.XON:
@BOX 21.1
0 => ECHO.CH;
1 +> COUNT;
1 -> VAL OF BUFF.PTR;
PTR^ OF BUFF.PTR => CH;
@BOX 25.1
V.TIME ->> 1 => BREAK.TIME [DEV ->> 1];
IF REQ.MODE [DEV + 1] & 1 /= 0
@BOX 26.1
IF GEM.STATUS [DEV + 1] & ENGAGED /= 0 THEN
   NOTIFY (GEM.L.DEV [DEV + 1],
      DISENGAGE.DEV ! TR.COMP,
      COUNT OF GEM.PARAMS [DEV + 1]);
   0 => COUNT OF GEM.PARAMS [DEV + 1];
   DISENGAGED &> GEM.STATUS [DEV + 1];
   STOPPED &> GEM.STATUS [DEV + 1];
ELSE
   ENGAGED !> GEM.STATUS [DEV + 1];
   NOTIFY (GEM.L.DEV [DEV + 1],
      ENGAGE.DEV, 0);
FI
@BOX 30.1
0 => ECHO.CH;
IF BREAK.TIME [DEV ->> 1] + 1
   >= V.TIME ->> 1
@BOX 27.1
:: PROCESS.XOFF.XON
#AP504.GEM.7.2
@BOX 28.1
1 -> VAL OF BUFF.PTR;
PTR^ OF BUFF.PTR => ECHO.CH;
1 +> VAL OF BUFF.PTR;
@BOX 29.1
IF ECHO.CH /= 0 THEN
   BEGIN
   SELECT GEM.PARAMS [DEV + 1];
   IF MODE & ECHO.ON /= 0 THEN
      IF MODE & TX.ON = 0 THEN
         ECHO.CH => CHAR [0];
         START.TRANSFER (DEV + 1, 1);
         IF ECHO.CH = %D THEN
            LF => BIT.MASK;
         FI
      ELSE
         ECHO.CH => BIT.MASK;
      FI
   FI
   END
FI
@BOX 31.1
IF GEM.STATUS [DEV] & ENGAGED = 0
@END

@TITLE AP504.GEM.7.1(2,11)

@COL 5R
@COL 1S-2T-4T-3T-9R-14N-7F
@COL 8R-10R-11T-12R-15N
@ROW 4-8
@ROW 5-9
@ROW 14-15
@FLOW 1-2NO-4NO-3NOTIFY ON ALL-9-14-7
@FLOW 2YES-8-15-14
@FLOW 3YES-5-14
@FLOW 4YES-10-11YES-12-15
@FLOW 11NO-15
@BOX 1.0
PROCESS ALL MODE
@BOX 2.0
STOPPED?
@BOX 3.0
DISENGAGED?
@BOX 4.0
PRELUDE?
@BOX 5.0
NOTIFY TO ENGAGE DEVICE
@BOX 7.0
END
@BOX 8.0
DELETE CH
@BOX 9.0
NOTIFY AND CHANGE TO OVERRUN
@BOX 10.0
DELETE CH
@BOX 11.0
END OF PRELUDE?
@BOX 12.0
CLEAR PRELUDE STATUS
@BOX 1.1
:: PROCESS ALL
BEGIN
@BOX 2.1
IF GEM.STATUS [DEV] & STARTED = 0
@BOX 3.1
IF GEM.STATUS [DEV] & ENGAGED = 0
@BOX 4.1
IF GEM.STATUS [DEV] & PRELUDE /= 0
@BOX 5.1
OVERRUN.MASK &> MODE;
NOTIFY (GEM.L.DEV [DEV], ENGAGE.DEV, 0);
ENGAGED !> GEM.STATUS [DEV];
IF GEM.STATUS [DEV + 1] & ENGAGED = 0 THEN
   NOTIFY (GEM.L.DEV [DEV + 1], ENGAGE.DEV, 0);
   ENGAGED !> GEM.STATUS [DEV + 1];
FI
@BOX 7.1
END
@BOX 8.1
0 => ECHO.CH;
1 +> COUNT;
1 -> VAL OF BUFF.PTR;
@BOX 9.1
NOTIFY (GEM.L.DEV [DEV], TR.COMP, COUNT);
ENTER.OVERRUN (DEV);
@BOX 10.1
1 +> COUNT;
1 -> VAL OF BUFF.PTR;
@BOX 11.1
IF PTR^ OF BUFF.PTR /= EDULERP
@BOX 12.1
NOT.PRELUDE &> GEM.STATUS [DEV];
REQ.MODE [DEV] => MODE;
@END

@TITLE AP504.GEM.7.2(2,11)

@COL 1S-2R-3F
@FLOW 1-2-3
@BOX 1.0
PROCESS XOFF/XON
@BOX 2.0
STOP OR START OUTPUT
AS APPROPRIATE
@BOX 3.0
END
@BOX 1.1
:: PROCESS.XOFF.XON
BEGIN
LOGICAL O.STATUS;
@BOX 2.1
IF CH = XOFF THEN
   IF GEM.STATUS [DEV + 1] & FREE /= 0 THEN
      SUSPENDED &> GEM.STATUS [DEV + 1];
      BEGIN
         SELECT GEM.PARAMS [DEV + 1];
         COUNT => XOFF.COUNT [DEV ->> 1];
         0 => COUNT;
      END
   FI
ELSE
   IF GEM.STATUS [DEV + 1] & FREE = 0 THEN
      FREE !> GEM.STATUS [DEV + 1];
      O.CONTROL (DEV + 1, START.TR.CMD,
         VAL OF BUFF.PTR OF GEM.PARAMS [DEV + 1],
         XOFF.COUNT [DEV ->> 1], 0) => O.STATUS;
      IF O.STATUS /= 0 THEN
         NOTIFY (GEM.L.DEV [DEV + 1], O.STATUS,
            COUNT OF GEM.PARAMS [DEV + 1]);
      FI
   FI
FI
@BOX 3.1
END
@END

@TITLE AP504.GEM.8(2,11)

@COL 10C-11R-14C-15R-22N
@COL 1S-2R-3R-4C-5R-25N-23N-9F
@COL 16C
@ROW 10-4-16
@ROW 22-23
@FLOW 1-2-3
@FLOW 4-5-25-23-9
@FLOW 10-11-14
@FLOW 14-15-22-23
@FLOW 16-25
@BOX 1.0
PROCESS SPECIAL O CH (DEV/COND)
@BOX 2.0
SELECT GEM PARAMS
FOR SPECIFIED DEVICE
@BOX 3.0
SWITCH ON COND
@BOX 4.0
LF
@BOX 5.0
CHANGE BUFF CHAR TO CR
@BOX 9.0
END
@BOX 10.0
DISEN
@BOX 11.0
SET STATUS FOR DISENGAGED
@BOX 14.0
OUTPUT BUFFER EMPTY
@BOX 15.0
NOTIFY TRANSFER COMPLETE
@BOX 16.0
OTHERS
@BOX 1.1
PROC PROCESS.SPECIAL.O.CH (DEV.COND);
INTEGER DEV.NO, REASON, CNT;
0 => REASON;
@BOX 2.1
SELECT GEM.PARAMS [DEV.COND ->> 8 => DEV.NO];
@BOX 3.1
SWITCH DEV.COND & %FF \
   C7, C6, C5, C4, C3,
   LF, DISEN, BUFF.EMPTY;
@BOX 4.1
LF:
@BOX 5.1
1 -> VAL OF BUFF.PTR;
1 +> COUNT;
CR => PTR^ OF BUFF.PTR;
@BOX 9.1
END
@BOX 10.1
DISEN:
@BOX 11.1
DISENGAGED &> GEM.STATUS [DEV.NO];
DISENGAGE.DEV !> REASON;
@BOX 14.1
BUFF.EMPTY:
@BOX 15.1
0 => PACKET.SENT [DEV.NO];
TX.OFF &> MODE;
IF GEM.STATUS [DEV.NO] & (FREE ! STARTED) = FREE ! STARTED THEN
   STOPPED &> GEM.STATUS [DEV.NO];
   COUNT => CNT;
   0 => COUNT;
   NOTIFY (GEM.L.DEV [DEV.NO], TR.COMP ! REASON, CNT);
FI
@BOX 16.1
C3:
C4:
C5:
C6:
C7:
@END

@TITLE AP504.GEM.9(2,11)

@COL 1S-2R-3F
@FLOW 1-2-3
@BOX 1.0
ENTER OVERRUN (DEV)
@BOX 2.0
SET UP BUFFER ADDRS,
COUNT AND MODE FOR OVERRUN
@BOX 3.0
END
@BOX 1.1
PROC ENTER.OVERRUN (DEV);
@BOX 2.1
OVERRUN !> GEM.STATUS [DEV];
SELECT GEM.PARAMS [DEV];
OVERRUN.BUFFS [DEV ->> 1] => GEM.BUFFERS [DEV ->> 1]
    => VAL OF BUFF.PTR;
OVERRUN.SIZE => COUNT;
REQ.MODE [DEV] & OVERRUN.MASK => MODE;
@BOX 3.1
END
@END

@TITLE AP504.GEM.10(2,11)

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

@FLOW 1-5NO-2-3-4
@FLOW 5YES-4

@BOX 1.0
START TRANSFER (DEV, CMD)
@BOX 2.0
CREATE PACKET TO
INITIATE TRANSFER
@BOX 3.0
SEND PACKET TO LINE MODULE
@BOX 4.0
END
@BOX 5.0
TRANSFER IN PROGRESS?
@BOX 1.1
PROC START.TRANSFER (DEV, CMD);
@BOX 2.1
1 => PACKET.SENT [DEV];
SELECT GEM.PARAMS [DEV];
SELECT PACKET^;
%11 => CMD1;
CMD => CMD2;
0 => STATUS1 => STATUS2 => CMD.COUNT;
0 => ZERO;
1 => DATA.COUNT;
BYTE (^CHAR [0]) - %83E000 => DATA.ADDR;
DEV & 1 => BYTE.COUNT;
@BOX 3.1
0 => START.REG^;
@BOX 4.1
END
@BOX 5.1
IF PACKET.SENT [DEV] /= 0
@END



@TITLE AP504.GEM.11(2,11)

@COL 10N-11R-12N
@COL 1S-2R-3R-14N-4T-5R-6T-7T-8R-9N
@COL 13R-15F

@ROW 10-14
@ROW 5-13
@ROW 11-8
@ROW 12-9

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

@BOX 1.0
PROCESS SPECIAL I CH (DEV / COND)
@BOX 2.0
PROCESS ONE SPECIAL I CH
@BOX 3.0
SELECT GEM PARAMS
FOR SPECIFIED DEVICE
@BOX 4.0
MORE CHARACTERS TO PROCESS?
@BOX 5.0
COPY CHARACTER TO BUFFER
@BOX 6.0
SPECIAL CHARACTER?
@BOX 7.0
BUFFER FULL?
@BOX 8.0
ECHO CHARACTER IF NECESSARY
@BOX 11.0
PROCESS ONE SPECIAL I CH
@BOX 13.0
RESTART DEVICE
@BOX 14.0
END
@BOX 1.1
PROC PROCESS.SPECIAL.I.CH (DEV.COND);
INTEGER DEV, CH, BIT.COND, COND;
ADDR LOGICAL8 I.CHAR;
@BOX 2.1
PROCESS.ONE.SPECIAL.I.CH (DEV.COND ->> 8 => DEV, DEV.COND & %FF);
@BOX 3.1
SELECT GEM.PARAMS [DEV];
SELECT PACKET^;
@BOX 4.1
IF 1 -> BYTE.COUNT =< 0
@BOX 5.1
MAKE (LOGICAL8, 0, DATA.ADDR) => I.CHAR;
1 +> DATA.ADDR;
I.CHAR^ => CH => PTR^ OF BUFF.PTR;
1 +> VAL OF BUFF.PTR;
1 -> COUNT;
@BOX 6.1
IF I.CH.TABLE [CH] & MODE => BIT.COND /= 0
@BOX 7.1
1 => BIT.COND;
IF COUNT = 0
@BOX 8.1
BEGIN
SELECT GEM.PARAMS [DEV + 1];
IF MODE & ECHO.ON /= 0 THEN
   IF MODE & TX.ON = 0 THEN
      CH => CHAR [0];
      START.TRANSFER (DEV + 1, 1);
      IF CH = %D THEN
         LF => BIT.MASK;
      FI
   ELSE
      CH => BIT.MASK;
   FI
FI
END
@BOX 11.1
7 => COND;
WHILE BIT.COND & %80 = 0 DO
   1 -> COND;
   BIT.COND <<- 1 => BIT.COND;
OD
PROCESS.ONE.SPECIAL.I.CH (DEV, COND);
@BOX 13.1
0 => PACKET.SENT [DEV];
START.TRANSFER (DEV, 2);
@BOX 15.1
END
@END



