@X @~
~V7 56 2 -5
~L3 COUK1247
80
~D10
~H                    MUSS
~
~
~D10
~H             AP7101
~D10
~MMANCHESTER UNIVERSITY  -  CONFIDENTIAL
~
~
                                                            ISSUE 11~
~V9 -1
~P
~V9 1
~YAP7101
~S~M~OAP7 IMPLEMENTATION DESCRIPTION
~S~M~OSection 10 Version 1
~S~OSection 10.1 Centrenet Driver Appendix
~S~O1. General Description
~BThis module is concerned with driving the Cenrenet Superport,
described in Appendix B of the Centrenet Specification Manual.
~S~O2. Interfaces
~
Other modules used:~
   AP103   I/O Appendix~
~
Ideal hardware registers used:~
   None~
~
Interrupt procedures:~
   INTERRUPT~
~
Interface procedures:~
   I.CONTROL(DEV,CMD,BUFFER,I.SIZE,I.MODE);~
   O.CONTROL(DEV,CMD,BUFFER,O.SIZE,O.MODE);~
~
Configurations parameters:~
   CNET.ADDR~
   CNET.DST.ADDR~
   CNET.SRC.ADDR~
~S~O2.1 Hardware Interface
~BThis module does not interface with the MUSS ideal machine
in the normal way.  Its only interface is a procedural one
with AP103.
~BThe interface with the Superport hardware is via the block
of registers described in Appendix B of the Centrenet Specification Manual.
~S~O2.2 Software Interface
~
~
~
1) I.CONTROL(DEV,CMD,BUFFER,I.SIZE,I.MODE)~
~BThis procedure implements the ideal device commands
CONFIGURE, INITIALISE, ENGAGE/DISENGAGE and START TRANSFER
for the input channel of the Superport.
~BThe significance of the parameters is dependent on the command.
In all cases P1 and P2 specify the physical device number and the
command.  For data transfers P3 and P4 contain the buffer address
and count value, while for initialisation commands P3 contains
the logical device number.
~
~
~
2) D.CONTROL(DEV,CMD,BUFFER,D.SIZE,D.MODE)
~BThis procedure performs similar functions to I.CONTROL but for
the output channel of the Superport.
~
~
~
3) INTERRUPT()~
~BThis procedure services the interrupts generated by the Superport
hardware.  The cause of the interrupt is determined and appropriate
action taken.
~S~O3. Implementation
~S~O3.1 Outline of Operation
~BThe structure of the two CONTROL procedures is similar;
non-transfer commands initiate the appropriate change of state,
with the resulting status reported back, while transfer
commands cause the appropriate Superport registers to be set
up.  In the I.CONTROL case, when DISENGAGED the Superport is set
to point to an overrun buffer and is started; the device is thus
left "listening out" for possible transfers.  Since the protocol
is provided by AP103, the first message in a transfer will always
be a short (control) message, which can safely be directed to a
small buffer.  Subsequent transfers are not initiated by the
receiver until requested by AP103, and are directed to the buffer
address provided.
~BSince only one interrupt vector is used, the interrupt procedures must
first determine whether the interrupt was caused by the receive
or transmit channel.  The steps followed are then broadly similar,
with an error bit set causing a notification of TRANSFER FAILED,
otherwise TRANSFER COMPLETE.  In the receive case, if the message
is in the overrun buffer then the device must have been
"listening out" and the NOTIFY will reason 0 causes a switch from
POLLING to RECEIVING to occur.  The next call of I.CONTROL will copy
the message from the overrun buffer rather than setting up the
Superport.
~S~O3.2 Data Structures
~T# 20
~3
~
I.LOG.DEV.NO )   }-{~Iused at initialisation to store the logical
device~
O.LOG.DEV.NO )~Inumber to which this physical device has been allocated.~
~
I.COUNT )        }-{~Istores the requested transfer size for~
O.COUNT )~Isubsequent use in NOTIFY calls.~
~
I.STATUS )       }-{~Ihold the ideal state of the~
O.STATUS )~Iappropriate channel.~
~
CNET.REG         -~Ia vector of LOGCAL16s which is the Superport
register block.~
~0
~S13.3 ~OSpecial notes.
~BAlthough the interrupt procedure is written in MUSL, and is therefore
machine independent, the raw interrupt entry code and interrupt
vector initialisation are machine dependent.  They appear in boxes
1 and 2 respectively of AP710.CNET.4.~
~Y
~V9 -1
~P
~D 15
~HFLOWCHARTS
~
~
~H                AP7101
~V9 -1
~F
@TITLE AP710.CNET(1,11)
@COL 1S-2R-3R-4R-5R-6F
@FLOW 1-2-3-4-5-6
@BOX 1.0
CENTRENET SUPERPORT DRIVER
@BOX 4.0
PROCEDURES IN THIS MODULE
1  I CONTROL
2  O CONTROL
3  INTERRUPT
@BOX 5.0
INITIALISATION
@BOX 6.0
END
@BOX 1.1
#AP710.CNET/1
MODULE CNET (I.CONTROL, O.CONTROL);
@BOX 2.1
@BOX 3.1
*GLOBAL 5;
LITERAL / INTEGER CHAN.SELECT = 59, RX.INT = 62, TX.INT = 63,
   RX.CSR = 64, RX.ERR = 65, SRC.ADDR = 66, RX.BUFF.LEN = 67,
   RX.BUFF.ST.L = 68, RX.BUFF.ST.M = 69,
   TX.CSR = 80, TX.ERR = 81, DST.ADDR = 82, TX.BUFF.LEN = 83,
   TX.BUFF.ST.L = 84, TX.BUFF.ST.M = 85;
LITERAL / LOGICAL8 SET = %FF, RESET = 0, READY = %F0,
   STARTED = 8, CONNECTED = 1, ENGAGED = 2, FREE = %20,
   STOPPED = %F7, DISCONNECTED = %FE, DISENGAGED = %FD;
LITERAL / LOGICAL16 BUSY = %800, START = 1, STOP = %FE,
   ABORT = %100, ERROR = %8000;
INTEGER I.LOG.DEV.NO, O.LOG.DEV.NO, I.COUNT, O.COUNT;
LOGICAL8 I.STATUS, O.STATUS;
*GLOBAL 24;
ADDR [LOGICAL16] CNET.REG;
@BOX 4.1
*CODE 2;
PSPEC I.CONTROL (INTEGER, INTEGER, ADDR, LOGICAL, LOGICAL32) / LOGICAL32;
PSPEC O.CONTROL (INTEGER, INTEGER, ADDR, LOGICAL, LOGICAL32) / LOGICAL32;
PSPEC INTERRUPT ();
::RAW INTERRUPT ENTRY
PSPEC INIT.INT.VECS ();
   #AP710.CNET.1
   #AP710.CNET.2
   #AP710.CNET.3
   #AP710.CNET.4
@BOX 5.1
*CODE 7;
PSPEC INIT.AP710 ();
INIT.AP710 ();
PROC INIT.AP710;
MAKE (LOGICAL16, 256, CNET.ADDR) => CNET.REG;
0 => CNET.REG^ [CHAN.SELECT];
CNET.DST.ADDR => CNET.REG^ [DST.ADDR];
CNET.SRC.ADDR => CNET.REG^ [SRC.ADDR];
0 => CNET.REG^ [TX.ERR] => CNET.REG^ [RX.ERR]
   => CNET.REG^ [TX.CSR] => CNET.REG^ [RX.CSR];
INIT.INT.VECS ();
END
@BOX 6.1
*END
@END
@TITLE AP710.CNET/1(1,11)
@COL 1S-2R-3R-4R
@FLOW 1-2-3-4
@BOX 1.0
OTHER MODULES REFERENCED
@BOX 4.0
AP103 I/O APPENDIX
@BOX 1.1
::EXTERNAL ENVIRONMENT
@BOX 2.1
IMPORT LITERAL INTEGER START.TR.CMD, INIT.CMD, DISENGAGE.CMD,
   CON.OUT.CMD, TR.COMP, TR.FAILED, DISENGAGE.DEV, DEV.DISENGAGED;
IMPORT LABEL PDP11.APPENDIX.INT;
@BOX 3.1
PSPEC NOTIFY (INTEGER, LOGICAL, LOGICAL);
@BOX 4.1
IMPORT LITERAL ADDR CNET.ADDR, CNET.DST.ADDR, CNET.SRC.ADDR, CNET.VEC;
@END
@TITLE AP710.CNET.1(1,11)

@COL 9T-10R-12T-11R-16T-13R-17R
@COL 1S-18T-2T-3R-15R-22R-7F
@COL 19R
@ROW 2-19
@ROW 3-9
@FLOW 1-18NO-2TRANSFER-3-15-22-7
@FLOW 18YES-19-7
@FLOW 2NON TRANSFER-9YES-10-11
@FLOW 9NO-12YES-11-7
@FLOW 12NO-16YES-13-7
@FLOW 16NO-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
ABORT TRANSFER IF
DEVICE IS BUSY
@BOX 7.0
END
@BOX 9.0
CONFIGURE COMMAND?
@BOX 10.0
INITIALISE DEVICE
@BOX 11.0
SET DISENGAGED STATUS
@BOX 12.0
DISENGAGE COMMAND?
@BOX 13.0
SET DISCONNECTED STATUS
@BOX 15.0
DIRECT INPUT TO DEVICE BUFFER
RESET OVERRUN FLAG
@BOX 16.0
DISCONNECT COMMAND?
@BOX 17.0
RETURN DEVICE STATUS
@BOX 18.0
INVALID DEVICE?
@BOX 19.0
RETURN FAIL STATUS
@BOX 22.0
START DEVICE
@BOX 1.1
PROC I.CONTROL (DEV, CMD, BUFFER, I.SIZE, I.MODE);
INTEGER I;
ADDR [LOGICAL8] DEV.B;
0 => I.CONTROL;
@BOX 2.1
IF CMD & START.TR.CMD = 0
@BOX 3.1
IF CNET.REG^ [RX.CSR] & BUSY /= 0 THEN
  ABORT => CNET.REG^ [RX.CSR];
FI
@BOX 7.1
END
@BOX 9.1
IF CMD /= INIT.CMD
@BOX 10.1
BUFFER => I.LOG.DEV.NO;
0 => CNET.REG^ [RX.CSR];
@BOX 11.1
STARTED !> I.STATUS;
DISENGAGED &> I.STATUS;
DISENGAGE.DEV => I.CONTROL;
@BOX 12.1
IF CMD /= DISENGAGE.CMD
@BOX 13.1
DISCONNECTED &> I.STATUS;
ABORT => CNET.REG^ [RX.CSR];
@BOX 15.1
BUFFER => CNET.REG^ [RX.BUFF.ST.L];
BUFFER ->> 16 => CNET.REG^ [RX.BUFF.ST.M];
I.SIZE + 1 ->> 1 => CNET.REG^ [RX.BUFF.LEN];
I.SIZE => I.COUNT;
@BOX 16.1
IF CMD /= CON.OUT.CMD
@BOX 17.1
IF I.STATUS & ENGAGED = 0 THEN
   DEV.DISENGAGED !> I.CONTROL;
FI
@BOX 18.1
IF DEV >= 1
@BOX 19.1
TR.FAILED => I.CONTROL;
@BOX 22.1
START => CNET.REG^ [RX.CSR];
@END
@TITLE AP710.CNET.2(1,11)

@COL 9T-10R-12T-11R-15T-13R-16R
@COL 1S-20T-2T-17R-3T-5R-6R-7F
@COL 21R-4R-19N
@ROW 2-21
@ROW 6-16-19
@ROW 4-5
@FLOW 1-20NO-2TRANSFER-17-3NO-5-6-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 20YES-21-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
LOAD BUFF.ADDR AND
WORDS IN BLOCK TO DEVICE
@BOX 6.0
START DEVICE AND
NOTE STATUS
@BOX 7.0
END
@BOX 9.0
CONFIGURE COMMAND?
@BOX 10.0
INITIALISE DEVICE
AND SET STOPPED STATUS
@BOX 11.0
SET DISENGAGE STATUS
@BOX 12.0
DISENGAGE COMMAND?
@BOX 13.0
SET DISCONNECTED STATUS
@BOX 15.0
DISCONNECT COMMAND?
@BOX 16.0
RETURN DEVICE STATUS
@BOX 17.0
ABORT TRANSFER IF
DEVICE IS BUSY
@BOX 20.0
INVALID DEVICE?
@BOX 21.0
RETURN FAIL STATUS
@BOX 1.1
PROC O.CONTROL (DEV, CMD, BUFFER, O.SIZE, O.MODE);
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 => CNET.REG^ [TX.BUFF.ST.L];
BUFFER ->> 16 => CNET.REG^ [TX.BUFF.ST.M];
O.SIZE + 1 ->> 1 => CNET.REG^ [TX.BUFF.LEN];
O.SIZE => O.COUNT;
@BOX 6.1
STARTED !> O.STATUS;
START => CNET.REG^ [TX.CSR];
@BOX 7.1
END
@BOX 9.1
IF CMD /= INIT.CMD
@BOX 10.1
BUFFER => O.LOG.DEV.NO;
STOPPED &> O.STATUS;
FREE ! ENGAGED !> O.STATUS;
@BOX 11.1
DISENGAGED &> O.STATUS;
DISENGAGE.DEV !> O.CONTROL;
@BOX 12.1
IF CMD /= DISENGAGE.CMD
@BOX 13.1
DISCONNECTED &> O.STATUS;
@BOX 15.1
IF CMD /= CON.OUT.CMD
@BOX 16.1
STOPPED &> O.STATUS;
IF O.STATUS & ENGAGED = 0 THEN
   DEV.DISENGAGED !> O.CONTROL;
FI
@BOX 17.1
IF CNET.REG^ [TX.CSR] & (BUSY ! START) /= 0 THEN
   ABORT => CNET.REG^ [TX.CSR];
FI

@BOX 20.1
IF DEV >= 1
@BOX 21.1
TR.FAILED => O.CONTROL;
@END
@TITLE AP710.CNET.3(1,11)
@COL 1S-2T-3R-4T-5R-6F
@FLOW 1-2INTERRUPTS-3-2NONE-4INTERRUPTS-5-4NONE-6

@BOX 1.0
INTERRUPT PROCEDURE
@BOX 2.0
RECEIVER INTERRUPTS?
@BOX 3.0
STOP DEVICE AND NOTIFY
TRANSFER COMPLETE
@BOX 4.0
TRANSMITTER INTERRUPTS?
@BOX 5.0
STOP DEVICE AND NOTIFY
TRANSFER COMPLETE
@BOX 6.0
END
@BOX 1.1
PROC INTERRUPT;
LOGICAL DEVICE.STATUS;
@BOX 2.1
IF CNET.REG^ [RX.INT] = 0
@BOX 3.1
CNET.REG^ [RX.CSR] => DEVICE.STATUS;
0 => CNET.REG^ [RX.CSR] => CNET.REG^ [RX.ERR];
IF DEVICE.STATUS & ERROR /= 0 THEN
   NOTIFY (I.LOG.DEV.NO, TR.FAILED, 0);
ELSE
   NOTIFY (I.LOG.DEV.NO, TR.COMP, I.COUNT);
FI
@BOX 4.1
IF CNET.REG^ [TX.INT] = 0
@BOX 5.1
CNET.REG^ [TX.CSR] => DEVICE.STATUS;
0 => CNET.REG^ [TX.CSR] => CNET.REG^ [TX.ERR];
STOPPED &> O.STATUS;
IF DEVICE.STATUS & ERROR /= 0 THEN
   NOTIFY (O.LOG.DEV.NO, TR.FAILED, 0);
ELSE
   NOTIFY (O.LOG.DEV.NO, TR.COMP, O.COUNT);
FI
@BOX 6.1
END
@END
@TITLE AP710.CNET.4(1,11)
@COL 1R-2R
@BOX 1.0
RAW INTERRUPT ENTRY CODE
@BOX 2.0
INTERRUPT INITIALISATION PROC
@BOX 1.1
*CODE 2;
RAW.INTERRUPT:
*#%17E6 %023C ::MOV PROC.ADDR,-(SP);
-> PDP11.APPENDIX.INT;
@BOX 2.1
*CODE 7;
PROC INIT.INT.VECS;
TYPE PROC.ADDR.TYPE IS
   ADDR INTERRUPT P
OR
   LOGICAL16 PROC.ADDRESS;
PROC.ADDR.TYPE PROC.ADDR;
*VTYPE LOGICAL16;
VSTORE INT.STORE [%100] 0;
VSTORE CNET.INT.PROC.PTR %23C;
RAW.INTERRUPT => INT.STORE [CNET.VEC];
%E0 => INT.STORE [CNET.VEC + 1];
^INTERRUPT => P OF PROC.ADDR;
PROC.ADDRESS OF PROC.ADDR => CNET.INT.PROC.PTR;
END
@END
