@X @~
~V7 56 2 -5
~D10
~H                    MUSS
~
~
~D10
~H            AP3071
~D10
~MMANCHESTER UNIVERSITY  -  CONFIDENTIAL~
~
~
                                                             ISSUE 11~
~V9 -1
~P
~V9 1
~YAP3071
~S1~M~OAP3 IMPLEMENTATION DESCRIPTION
~S1~M~OSection 7 Version 1
~S1~OSection 7.1 LP11 Lineprinter Driver Appendix
~S1~O1. General Description
~BThis module is concerned with driving the
LP11 lineprinter, 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~
   LP11.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.LP11S~
   LP11.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 LP11 Interface
~BSee LP11 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 LP11 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.
~BThe result returned by the I.CONTROL procedure
and the parameter of the NOTIFY procedure give 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 LP11 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
~
~
LP11.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~
~
LP11.STATUS
~IAn array, indexed by device number, holding the status
of the device.~
~
LP11.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.~
~
LP11.L.DEV
~IAn array, indexed by device number, giving the ideal
device corresponding to a LP11 device.~
~
NO.OF.LP11S~IAn integer literal specifying the number
of LP11's serviced.~
~
LP11.ADDRS~IA data vector giving the bus address of each LP11 device.~
~S1~O3.3 Special Notes
~Y
~V9 -1
~P
~D15
~HFLOWCHARTS
~
~
~H               AP3071
~V9 -1
~F
@TITLE AP307.LP11(1,10)

@COL 1S-2R-3R-4R-5R-6F
@FLOW 1-2-3-4-5-6
@BOX 1.0
LP11 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
#AP307.LP11/1
MODULE LP11 (O.CONTROL, POLL)
@BOX 2.1
TYPE PTR.TYPE IS
   ADDR VAL
OR
   ADDR LOGICAL8 PTR;
TYPE LP11.PARAMS.TYPE IS
   PTR.TYPE BUFF.PTR
   INTEGER16 COUNT
   LOGICAL8 MODE, HEADER.CH;
@BOX 3.1
:: DATA DECLARATIONS
#AP307.LP11/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 ();
   #AP307.LP11.1
   #AP307.LP11.2
   #AP307.LP11.3
   #AP307.LP11.4
@BOX 5.1
*CODE 7;
PSPEC INIT.AP307 ();
INIT.AP307 ();
PROC INIT.AP307;
*VTYPE LABEL;
VSTORE VEC.LABEL %8003006C;
*VTYPE LOGICAL32;
VSTORE VEC.ADDR %8003006C;
VSTORE INT.STORE [%FFFF] %80040000;
VSTORE WORKSPACE.PTR %8003006C;
VSTORE CSR.PTR %80030070;
TYPE PROC.ADDR.TYPE IS
   ADDR PROCESS.SPECIAL.O.CH P
OR
   LOGICAL32 PROC.ADDRESS;
PROC.ADDR.TYPE PROC.ADDR;
RAW.OUTPUT.INT.0 => VEC.LABEL;
VEC.ADDR + 3 & %FFFFFFFC + 1 => INT.STORE [%CA0];
^PROCESS.SPECIAL.O.CH => P OF PROC.ADDR;
PROC.ADDRESS OF PROC.ADDR => INT.STORE [%DA0];
BYTE (^LP11.PARAMS [0]) => WORKSPACE.PTR;
BYTE (^LP11.ADDRS [0]) => CSR.PTR;
END
@BOX 6.1
*END
@END
@TITLE AP307.LP11/1(1,10)

@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.LP11S,
   START.TR.CMD, INIT.CMD, DISENGAGE.CMD, CON.OUT.CMD,
   TR.COMP, TR.FAILED, BREAKIN, ENGAGE.DEV, DISENGAGE.DEV, DEV.DISENGAGED;
ADDR [NO.OF.LP11S] LP11.ADDRS;
@BOX 3.1
PSPEC NOTIFY (INTEGER, LOGICAL, LOGICAL);
LOGICAL8 [256] O.CH.TABLE;
@END
@TITLE AP307.LP11/2(1,10)

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

@TITLE AP307.LP11.1(1,10)

@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 LP11.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
   CR => HEADER.CH;
   0 => STATE [DEV];
FI
STARTED !> LP11.STATUS [DEV];
%40 => LP11.CSR [DEV]^ [LPS];
@BOX 7.1
END
@BOX 9.1
IF CMD /= INIT.CMD
@BOX 10.1
BUFFER => LP11.L.DEV [DEV];
O.MODE => REQ.MODE [DEV];
STOPPED &> LP11.STATUS [DEV];
FREE ! ENGAGED !> LP11.STATUS [DEV];
MAKE (LOGICAL16, 2, LP11.ADDRS [DEV])
   => LP11.CSR [DEV];
@BOX 11.1
DISENGAGED &> LP11.STATUS [DEV];
DISENGAGE.DEV !> O.CONTROL;
@BOX 12.1
IF CMD /= DISENGAGE.CMD
@BOX 13.1
DISCONNECTED &> LP11.STATUS [DEV];
@BOX 14.1
SELECT LP11.PARAMS [DEV];
@BOX 15.1
IF CMD /= CON.OUT.CMD
@BOX 16.1
IF LP11.STATUS [DEV] & ENGAGED = 0 THEN
   DEV.DISENGAGED !> O.CONTROL;
FI
@BOX 17.1
IF DEV >= NO.OF.LP11S OR
   LP11.ADDRS [DEV] = 0
@BOX 18.1
TR.FAILED => O.CONTROL;
@END
@TITLE AP307.LP11.2(1,10)
@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.LP11S DO
   IF LP11.STATUS [DEV] & ENGAGED = 0 THEN
         IF LP11.CSR [DEV]^ [LPS] >= 0 THEN
         ENGAGED !> LP11.STATUS [DEV];
         %40 => LP11.CSR [DEV]^ [LPS];
      FI
   FI
OD
@BOX 3.1
END
@END
@TITLE AP307.LP11.3(1,10)
@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 LP11 CHANNEL
AND LP11 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 LP11 NUMBER
   *#%01 %01 %01 %01;
   *#%DD %00 ::PUSHL #0;
   -> RAW.OUTPUT.INT;

RAW.OUTPUT.INT: BEGIN
@BOX 2.1
*#%BB %8F %3F %00 ::PUSHR %003F;
@BOX 3.1
::R0 = LP11 REGISTER ADDRESS
*#%D0 %AE %18 %52 ::MOVL %18(R14), R2;
*#%D0 %9F %70 ::MOVL @CSR.PTR, R1;
*#%00 %03 %80 %51;
*#%D0 %42 %61 %50 ::MOVL (R1) [R2], R0;
::R1 = ADDRESS OF PARAMETERS
*#%78 %03 %52 %51 ::ASHL 3, R12, R1;
*#%C0 %9F %6C %00 ::ADDL PARAMETER, R1;
*#%03 %80 %51;
::R2 = BUFFER ADDRESS
*#%D0 %61 %52 ::MOVL (R1), R2;
*#%D4 %54 ::CLRL R4;
@BOX 4.1
*#%B5 %A1 %04 ::TSTW 4(R1);
*#%15 %03 ::BLEQ + 3;
-> ROI.5;
*#%D0 %8F %80 %00 ::MOVL %80, R4;
*#%00 %00 %54;
-> ROI.9 ::IGNORE FLIP JUMP
@BOX 5.1
ROI.5:
*#%D4 %53 ::CLRL R3;
*#%90 %82 %53 ::MOVB (R2)+, R3;
*#%B0 %53 %A0 %02 ::MOVW R3, 2(R0);
*#%D0 %52 %61 ::MOVL R2, (R1);
*#%B7 %A1 %04 ::DECW 4(R1);
@BOX 6.1
*#%D0 %9F %60 %00  ::MOVL @O.CH.TABLE.PTR, R2;
*#%03 %80 %52;
*#%92 %42 %63 %54 ::MCOMB (R3) [R2], R4;
*#%8B %54 %A1 %06 %54 ::BICB3 R4, 6(R1), R4;
*#%13 %03 ::BEQL + 3;
-> ROI.9 ::IGNORE FLIP JUMP
@BOX 7.1
*#%BA %8F %3F %00 ::POPR %003F;
*#%D5 %8E ::REMOVE PARAMETER;
*#%02 ::REI;
@BOX 8.1
END
@BOX 9.1
ROI.9:
*#%D4 %50 ::CLRL R0;
*#%B1 %0F %54 ::CMPW #%F, R4;
*#%18 %08 ::BGEQ + 8;
*#%78 %8F %FC %54 %54 ::ASHL - 4, R4, R4;
*#%80 %04 %50 ::ADDB2 4, R0;
*#%B1 %03 %54 ::CMPW #%3, R4;
*#%18 %08 ::BGEQ + 8;
*#%78 %8F %FE %54 %54 ::ASHL - 2, R4, R4;
*#%80 %02 %50 ::ADDB2 2, R0;
*#%B1 %01 %54 ::CMPW #%1, R4;
*#%18 %02 ::BGEQ + 2;
*#%96 %50 ::INCB R0;
@BOX 10.1
*#%78 %08 %AE %18 ::ASHL #8, %18 (R14), %18 (R14);
*#%AE %18;
*#%C8 %50 %AE %18 ::BISL2 R0, %18(R14);
@BOX 11.1
*#%BA %8F %3F %00 ::POPR %003F;
*#%DD %8F ::PUSHL PROC ADDR;
*#%80 %36 %04 %80;
*#%17 %9F ::JUMP TO END VAX11 INT;
*#%00 %00 %02 %80;
@BOX 12.1
*#%D4 %53 ::CLRL R3;
*#%90 %A1 %07 %53 ::MOVB 7(R1), R3;
*#%13 %03 ::BEQL + 3;
-> ROI.13 ::IGNORE FLIP JUMP
@BOX 13.1
ROI.13:
*#%94 %A1 %07 ::CLRB 7(R1);
*#%B0 %53 %A0 %02 ::MOVW R3, 2(R0);
*#%D0 %08 %50 ::MOVL #8, R0;
@BOX 14.1
ROI.14:
*#%B4 %60 ::CLRW (R0);
*#%D0 %06 %50 ::MOVL #6, R0;
@BOX 15.1
*#%B5 %60 ::TSTW (R0);
*#%18 %03 ::BGEQ +3;
-> ROI.14 ::IGNORE FLIP JUMP
@END
@TITLE AP307.LP11.4(1,10)

@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 LP11 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 LP11.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
   LF => HEADER.CH;
   1 +> STATE [DEV.NO];
   132 => STAR.COUNT[DEV.NO];
ELSE
   IF STATE [DEV.NO] & 6 /= 6 THEN
      "*" => HEADER.CH;
      IF 1 -> STAR.COUNT [DEV.NO] = 0 THEN
         1 +> STATE [DEV.NO];
      FI
   ELSE
      IF STATE [DEV.NO] & 8 /= 0 THEN
         -> BUFF.EMPTY;
      ELSE
         IF STATE [DEV.NO] = 23 THEN
            31 => STATE [DEV.NO];
            0 => LAST.CMD [DEV.NO];
            FF => HEADER.CH;
         FI
      FI
   FI
FI
@BOX 9.1
OUT:
END
@BOX 10.1
DISEN:
@BOX 11.1
DISENGAGED &> LP11.STATUS [DEV.NO];
@BOX 14.1
BUFF.EMPTY:
@BOX 15.1
0 => LP11.CSR [DEV.NO]^ [LPS];
IF STATE [DEV.NO] = 7 THEN
   CR => HEADER.CH;
   IF LAST.CMD [DEV.NO] & 2 /= 0 THEN
      16 => STATE [DEV.NO];
   ELSE
      8 => STATE [DEV.NO];
   FI
   %40 => LP11.CSR [DEV.NO]^ [LPS];
   EXIT;
FI
IF LAST.CMD [DEV.NO] & 2 /= 0 THEN
   16 => STATE [DEV.NO];
   CR => HEADER.CH;
   %40 => LP11.CSR [DEV.NO]^ [LPS];
   EXIT;
FI
0 => LP11.CSR [DEV.NO]^ [LPS];
IF LP11.STATUS [DEV.NO] & (FREE ! STARTED) = FREE ! STARTED THEN
   STOPPED &> LP11.STATUS [DEV.NO];
   NOTIFY (LP11.L.DEV [DEV.NO], TR.COMP ! REASON, 0);
FI
@BOX 16.1
C2:
C3:
C4:
C5:
C6:
C7:
@END


