@X @~
~V7 56 2 -5
~D10
~H                    MUSS
~
~
~D10
~H            AP7121
~D10
~MMANCHESTER UNIVERSITY  -  CONFIDENTIAL~
~
~
                                                             ISSUE 11~
~V9 -1
~P
~V9 1
~YAP7121
~S1~M~OAP7 IMPLEMENTATION DESCRIPTION
~S1~M~OSection 12 Version 1
~S1~OSection 12.1 PC11 Paper tape punch Driver Appendix
~S1~O1. General Description
~BThis module is concerned with driving the
PC11 paper tape punch, described in the DEC peripheral handbook.
~S1~O2. Interfaces~
Other modules used~
   AP1 Section 3 (I/O Appendix)~
Ideal hardware registers used~
   None~
Interrupt procedures~
   PC11.INT - RAW M/C LEVEL~
   SPECIAL.CHAR (DEV/COND)~
Interface procedures~
   O.CONTROL (PHYS.DEV.NO, COMMAND, ADDR, COUNT, O.MODE) DUMMY~
Interface variables~
   None~
Configuration parameters~
   NO.OF.PC11S~
   PC11.ADDRS~
~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) 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 PC11 Interface
~BSee PC11 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~
~
~Mconfigure  = 1
~Ndisconnect = 2
~Ndisengage  = 3
~Nstart      = 4-7
~
~
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.
~BA device may only be started, stopped or disconnected.  Disengage is a
null command in the case of a PC11 output channel.
Started devices will output a character each time an interrupt is received
until the buffer is emptied, when stopped mode is assumed.
A started device may be started again, in which case transfer
starts with the new count and address.
~BAny headers or trailers are output as a sequence of NUL characters.
~BThe parameter of the NOTIFY procedure gives the
interrupt status of the device.
~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.
~S~O3.1.1 Procedures Private to This Module
~S11) RAW.INT
~BThis procedure services the PC11 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.
~S12) PROCESS.SPECIAL.CH(DEV.NO/COND)
~BThis procedure implements the device behaviour as described above.
~S13) POLL
~BThis procedure periodically checks the status of the device to
detect changes in the engaged/disengaged status.
~S1~O3.2 Data Structures~
~T% 30
~
~
PC11.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~
~
PC11.STATUS
~IAn array, indexed by device number, holding the status
of the device.~
~
PC11.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.~
~
PC11.L.DEV
~IAn array, indexed by device number, giving the ideal
device corresponding to a PC11 device.~
~
NO.OF.PC11S~IAn integer literal specifying the number
of PC11's serviced.~
~
PC11.ADDRS~IA data vector giving the bus address of each PC11 device.~
~S1~O3.3 Special Notes
~Y
~V9 -1
~P
~V9 -1
~D15
~HFLOWCHARTS
~
~
~H               AP7121
~V9 -1
~F
@TITLE AP712.PC11(1,11)

@COL 1S-2R-3R-4R-5R-6F
@FLOW 1-2-3-4-5-6
@BOX 1.0
PC11 (TAPE PUNCH) DRIVER
@BOX 4.0
PROCEDURES IN MODULE:
    1   O CONTROL
    2   RAW OUTPUT INT
    3   PROCESS SPECIAL O CH
    4   POLL
@BOX 6.0
END
@BOX 1.1
#AP712.PC11/1
MODULE PC11 (O.CONTROL, POLL);
@BOX 2.1
TYPE PTR.TYPE IS
   LOGICAL16 VAL
OR
   ADDR LOGICAL8 PTR;
TYPE PC11.PARAMS.TYPE IS
   LOGICAL16 FILLER
   PTR.TYPE BUFF.PTR
   INTEGER16 COUNT
   LOGICAL8 MODE, HEADER.CH;
@BOX 3.1
:: DATA DECLARATIONS
#AP712.PC11/2
@BOX 4.1
*CODE 23;
PSPEC O.CONTROL (INTEGER, INTEGER, ADDR, LOGICAL, LOGICAL32) / LOGICAL32;
:: RAW.INT
PSPEC PROCESS.SPECIAL.O.CH (INTEGER);
PSPEC POLL ();
   #AP712.PC11.1
   #AP712.PC11.2
   #AP712.PC11.3
   #AP712.PC11.4
@BOX 5.1
*CODE 7;
PSPEC INIT.AP712 ();
INIT.AP712 ();
PROC INIT.AP712;
INTEGER I;
*VTYPE LOGICAL16;
VSTORE INT.STORE [%100] %0;
VSTORE WORKSPACE.PTR %230;
VSTORE CSR.PTR %232;
VSTORE SPECIAL.O.CH.PTR %234;
TYPE PROC.ADDR.TYPE IS
   ADDR PROCESS.SPECIAL.O.CH P
OR
   LOGICAL16 PROC.ADDRESS;
PROC.ADDR.TYPE PROC.ADDR;
RAW.OUTPUT.INT.0 => INT.STORE [%1E];
%E0 => INT.STORE [%1F];
^PROCESS.SPECIAL.O.CH => P OF PROC.ADDR;
PROC.ADDRESS OF PROC.ADDR => SPECIAL.O.CH.PTR;
BYTE (^PC11.PARAMS [0]) => WORKSPACE.PTR;
BYTE (^PC11.ADDRS [0]) => CSR.PTR;
FOR I < NO.OF.PC11S DO
   %FF => HEADER.CH OF PC11.PARAMS [I];
OD
END
@BOX 6.1
*END
@END
@TITLE AP712.PC11/1(1,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.PC11S,
   START.TR.CMD, INIT.CMD, DISENGAGE.CMD, CON.OUT.CMD,
   TR.COMP, TR.FAILED, BREAKIN, ENGAGE.DEV, DISENGAGE.DEV, DEV.DISENGAGED;
ADDR [NO.OF.PC11S] PC11.ADDRS;
IMPORT LABEL PDP11.APPENDIX.INT;
@BOX 3.1
PSPEC NOTIFY (INTEGER, LOGICAL, LOGICAL);
LOGICAL8 [256] O.CH.TABLE;
@END
@TITLE AP712.PC11/2(1,11)

@COL 1S
@BOX 1.0
DATA DECLARATIONS
@BOX 1.1
*GLOBAL 5;
LITERAL / INTEGER PPS = 0, PPB = 1, LEADER.SIZE = 128;
LITERAL / LOGICAL8 FF = %C, LF = %A, CR = %D, NUL = 0;
LITERAL / LOGICAL8 CONNECTED = 1, ENGAGED = 2, OVERRUN = 4,
   STARTED = 8, FREE = %20, DISCONNECTED = %FE, DISENGAGED = %FD,
   STOPPED = %F7;
PC11.PARAMS.TYPE [NO.OF.PC11S] PC11.PARAMS;
INTEGER [NO.OF.PC11S] PC11.L.DEV, NULL.COUNT, STATE;
LOGICAL8 [NO.OF.PC11S] PC11.STATUS, REQ.MODE, LAST.CMD;
ADDR [LOGICAL16] [NO.OF.PC11S] PC11.CSR;
@END

@TITLE AP712.PC11.1(1,11)

@COL 9T-10R-12T-11R-15T-13R-16R
@COL 1S-17T-2T-3T-14R-5R-6R-7F
@COL 18R-4R-19N
@ROW 2-18
@ROW 3-9
@ROW 4-14
@ROW 6-16
@FLOW 1-17NO-2TRANSFER-3NO-14-5-6-7
@FLOW 17YES-18-19-7
@FLOW 2NON TRANSFER-9YES-10-7
@FLOW 3YES-4-19
@FLOW 9NO-12YES-11-7
@FLOW 12NO-15YES-13-7
@FLOW 15NO-16-7
@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 PC11.PARAMS FOR DEV
@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 14.0
SELECT DEVICE PARAMETERS
@BOX 15.0
DISCONNECT COMMAND?
@BOX 16.0
RETURN DEVICE STATUS
@BOX 17.0
INVALID DEVICE?
@BOX 18.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 => LAST.CMD [DEV] & 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;
REQ.MODE [DEV] => MODE;
@BOX 6.1
IF CMD & 1 /= 0 THEN
   NUL => HEADER.CH;
   0 => STATE [DEV];
   (LEADER.SIZE - 1) => NULL.COUNT [DEV];
FI
STARTED !> PC11.STATUS [DEV];
%40 => PC11.CSR [DEV]^ [PPS];
@BOX 7.1
END
@BOX 9.1
IF CMD /= INIT.CMD
@BOX 10.1
BUFFER => PC11.L.DEV [DEV];
O.MODE => REQ.MODE [DEV];
STOPPED &> PC11.STATUS [DEV];
FREE ! ENGAGED !> PC11.STATUS [DEV];
MAKE (LOGICAL16, 2, PC11.ADDRS [DEV])
   => PC11.CSR [DEV];
@BOX 11.1
DISENGAGED &> PC11.STATUS [DEV];
DISENGAGE.DEV !> O.CONTROL;
@BOX 12.1
IF CMD /= DISENGAGE.CMD
@BOX 13.1
DISCONNECTED &> PC11.STATUS [DEV];
@BOX 14.1
SELECT PC11.PARAMS [DEV];
@BOX 15.1
IF CMD /= CON.OUT.CMD
@BOX 16.1
IF PC11.STATUS [DEV] & ENGAGED = 0 THEN
   DEV.DISENGAGED !> O.CONTROL;
FI
@BOX 17.1
IF DEV >= NO.OF.PC11S OR
   PC11.ADDRS [DEV] = 0
@BOX 18.1
TR.FAILED => O.CONTROL;
@END
@TITLE AP712.PC11.2(1,11)
@COL 1S-2R-3F
@FLOW 1-2-3
@BOX 1.0
POLL
@BOX 2.0
GENERATE INTERRUPT IF STATUS OF
DEVICE HAS CHANGED
@BOX 3.0
END
@BOX 1.1
PROC POLL;
INTEGER DEV;
@BOX 2.1
FOR DEV < NO.OF.PC11S DO
   IF PC11.STATUS [DEV] & ENGAGED = 0 THEN
         IF PC11.CSR [DEV]^ [PPS] >= 0 THEN
         ENGAGED !> PC11.STATUS [DEV];
         %40 => PC11.CSR [DEV]^ [PPS];
      FI
   FI
OD
@BOX 3.1
END
@END
@TITLE AP712.PC11.3(1,11)
@COL 1S-2R-3R-15T-12T-4T-5R-6T-7R-8F
@COL 14R-13R-9R-10R-11R
@ROW 14-12
@ROW 4-13
@ROW 7-9
@FLOW 1-2-3-15NO-12NO-4NO-5-6NO-7-8
@FLOW 15YES-14-10
@FLOW 12YES-13-10
@FLOW 4YES-9-10-11
@FLOW 6YES-9-10-11
@BOX 1.0
RAW OUTPUT INT
@BOX 2.0
STACK REGISTERS
@BOX 3.0
SET POINTER TO PC11 CHANNEL
AND PC11 PARAMETERS
@BOX 4.0
BUFFER EMPTY?
@BOX 5.0
OUTPUT CHARACTER
@BOX 6.0
SPECIAL CHARACTER?
@BOX 7.0
UNSTACK REGISTERS AND
RETURN FROM INTERRUPT
@BOX 8.0
END
@BOX 9.0
OBTAIN CONDITION INDEX
@BOX 10.0
GENERATE DEV NO/CONDITION
INDEX PARAMETER
@BOX 11.0
UNSTACK REGISTERS, STACK
SPECIAL PROCEDURE INDEX
AND JUMP TO PROCEDURE ENTRY CODE
@BOX 12.0
HEADER OR TRAILER?
@BOX 13.0
PRINT HEADER CHARACTER
@BOX 14.0
DISENGAGE DEVICE
@BOX 15.0
DEVICE IN ERROR?
@BOX 1.1
RAW.OUTPUT.INT.0: ::STACK PC11 NUMBER
   *#%15E6 %0000 ::MOV #0,-(SP);
   -> RAW.OUTPUT.INT;

RAW.OUTPUT.INT: BEGIN
@BOX 2.1
*#%1026  ::MOV R0,-(SP);
*#%1066  ::MOV R1,-(SP);
*#%10A6  ::MOV R2,-(SP);
*#%10E6  ::MOV R3,-(SP);
*#%1126  ::MOV R4,-(SP);
*#%1166  ::MOV R5,-(SP);
@BOX 3.1
::R0 = PC11 REGISTER ADDRESS
*#%1D82 %000C ::MOV %C(SP),R2;
*#%17C1 %232 ::MOV @#CSR.PTR,R1;
*#%0CC2  ::ASL R2;
*#%6081  ::ADD R2,R1;
*#%1240  ::MOV (R1),R0;
::R1 = ADDRESS OF PARAMETERS
*#%1081  ::MOV R2,R1;
*#%7457 %0002 ::ASH #2,R1;
*#%67C1 %230::ADD @#WORKSPACE.PTR,R1;
::R2 = BUFFER ADDRESS
*#%1C42 %0002 ::MOV 2(R1), R2;
*#%0A04  ::CLR R4;
@BOX 4.1
*#%0BF1 %0004 ::TST 4(R1);
*#%0701  ::BLE + 1;
-> ROI.5;
*#%15C4 %0080 ::MOV %80, R4;
-> ROI.9 ::IGNORE FLIP JUMP
@BOX 5.1
ROI.5:
*#%0A03  ::CLR R3;
*#%9483  ::MOVB (R2)+, R3;
*#%10F0 %0002 ::MOV R3, 2(R0);
*#%10B1 %0002  ::MOV R2, 2(R1);
*#%0AF1 %0004 ::DEC 4(R1);
@BOX 6.1
*#%17C2 %224 ::MOV @#O.CH.TABLE.PTR, R2;
*#%60C2  ::ADD R3,R2;
*#%9282  ::MOVB (R2),R2;
*#%8A42  ::COMB R2;
*#%9C44 %0006 ::MOVB 6(R1),R4;
*#%C084  ::BICB R2,R4;
*#%45C4 %FF00 ::BIC %FF00, R4;
*#%0301  ::BEQ + 1;
-> ROI.9 ::IGNORE FLIP JUMP
@BOX 7.1
*#%1585  ::MOV (SP)+,R5;
*#%1584  ::MOV (SP)+,R4;
*#%1583  ::MOV (SP)+,R3;
*#%1582  ::MOV (SP)+,R2;
*#%1581  ::MOV (SP)+,R1;
*#%1580  ::MOV (SP)+,R0;
*#%0A16  ::REMOVE PARAMETER;
*#%0002 ::RTI;
@BOX 8.1
END
@BOX 9.1
ROI.9:
*#%0A00  ::CLR R0;
*#%25C4 %000F ::CMP #%F, R4;
*#%0404  ::BGE + 4;
*#%7517 %FFFC ::ASH - 4,R4;
*#%65C0 %0004 ::ADD 4, R0;
*#%25C4 %0003 ::CMP #%3, R4;
*#%0404  ::BGE + 4;
*#%7517 %FFFE ::ASH - 2,R4;
*#%65C0 %0002 ::ADD 2, R0;
*#%25C4 %0001 ::CMP #%1, R4;
*#%0401  ::BGE + 1;
*#%0A80  ::INC R0;
@BOX 10.1
*#%1D85 %000C ::MOV %C(SP),R5;
*#%7557 %0008 ::ASH 8,R5;
*#%5005  ::BIS R0,R5;
*#%1176 %000C ::MOV R5,%C(SP);
@BOX 11.1
*#%1585  ::MOV (SP)+,R5;
*#%1584  ::MOV (SP)+,R4;
*#%1583  ::MOV (SP)+,R3;
*#%1582  ::MOV (SP)+,R2;
*#%1581  ::MOV (SP)+,R1;
*#%1580  ::MOV (SP)+,R0;
*#%17E6 %234 ::MOV PROC.ADDR,-(SP);
-> PDP11.APPENDIX.INT;
@BOX 12.1
*#%0A03  ::CLR R3;
*#%9C43 %0007 ::MOVB 7(R1), R3;
*#%8101 ::BMI + 1;
-> ROI.13 ::IGNORE FLIP JUMP
@BOX 13.1
ROI.13:
*#%95F1 %00FF %0007 ::MOVB #%FF,7(R1);
*#%10F0 %0002 ::MOV R3, 2(R0);
*#%15C0 %0008 ::MOV #8, R0;
@BOX 14.1
ROI.14:
*#%0A08  ::CLR (R0);
*#%15C0 %0006 ::MOV #6, R0;
@BOX 15.1
*#%0BC8  ::TST (R0);
*#%0401  ::BGE +1;
-> ROI.14 ::IGNORE FLIP JUMP
@END
@TITLE AP712.PC11.4(1,11)

@COL 10C-11R-14C-15R-22N
@COL 1S-2R-3R-4C-5R-23N-9F
@COL 16C
@ROW 10-4-16
@ROW 22-23
@FLOW 1-2-3
@FLOW 16-23-9
@FLOW 4-5-23
@FLOW 10-11-23
@FLOW 14-15-22-23
@BOX 1.0
PROCESS SPECIAL O CH (DEV/COND)
@BOX 2.0
SELECT PC11 PARAMS
FOR SPECIFIED DEVICE
@BOX 3.0
SWITCH ON COND
@BOX 4.0
HEADER OR TRAILER
@BOX 5.0
SELECT NEXT CHARACTER
TO BE PRINTED
@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 PC11.PARAMS [DEV.COND ->> 8 => DEV.NO];
@BOX 3.1
SWITCH DEV.COND & %FF \
   C7, C6, C5, C4, C3,
   C2, DISEN, BUFF.EMPTY, HEADER;
@BOX 4.1
HEADER:
@BOX 5.1
IF STATE [DEV.NO] & 1 = 0 THEN
   NUL => HEADER.CH;
   IF 1 -> NULL.COUNT [DEV.NO] =< 0 THEN
      1 +> STATE [DEV.NO];
   FI
FI
@BOX 9.1
OUT:
END
@BOX 10.1
DISEN:
@BOX 11.1
DISENGAGED &> PC11.STATUS [DEV.NO];
@BOX 14.1
BUFF.EMPTY:
@BOX 15.1
0 => PC11.CSR [DEV.NO]^ [PPS];
IF LAST.CMD [DEV.NO] & 2 /= 0 THEN
   2 => STATE [DEV.NO];
   NUL => HEADER.CH;
   (LEADER.SIZE - 1) => NULL.COUNT [DEV.NO];
   0 => LAST.CMD [DEV.NO];
   %40 => PC11.CSR [DEV.NO]^ [PPS];
   EXIT;
FI
0 => PC11.CSR [DEV.NO]^ [PPS];
IF PC11.STATUS [DEV.NO] & (FREE ! STARTED) = FREE ! STARTED THEN
   STOPPED &> PC11.STATUS [DEV.NO];
   NOTIFY (PC11.L.DEV [DEV.NO], TR.COMP ! REASON, 0);
FI
@BOX 16.1
C2:
C3:
C4:
C5:
C6:
C7:
@END


