@X @~ %`
~V7 56 2 -5
~D10
~H                       MUSS
~
~
~HAPPENDIX  7
~D13
This volume contains the machine dependent software for MU6G11.~
~D12
~MUNIVERSITY OF MANCHESTER~
~V9 -1
~P
~V9 1
~D10
~S1~MAppendix 7   CONTENTS~
~
~
~MAP7001   -  Basic Bootstrap Facilities for MU6G~
~
~NAP7011   -  MU6G CPU Appendix~
~
~NAP7021   -  Drum Appendix (SI9500)~
~
~NAP1031   -  MU6G I/O Appendix~
~
~NAP7041   -  Computer Interface Unit Appendix (CIU)
~
~NAP7111   -  MU6G Console Terminal Appendix~
~
~NAP7211   -  Bootstrap~
~
~NAP7991   -  End of Initialisation~
~V9 -1
~P
~D10
~H                 MUSS
~
~
~D10
~H           AP7001
~D10
~MMANCHESTER UNIVERSITY  -  CONFIDENTIAL~
~
~
                                                             ISSUE 11~
~V9 -1
~P
~V9 1
~YAP7001
~S1~M~OAP7 IMPLEMENTATION DESCRIPTION~
~S1~M~OSection 0 Version 1~
~S1~OSection 0.1 Basic Bootstrap Facilities for MU6G~
~S1~O1. General Description
~
~BThe MUSS bootstrap provides the operator with several actions. When the
initial bootstrap is 'booted' in, it presents the operator with the following
menu as the means of selection.
~
~
~MTYPE:                         ~
~N0 TO COMMUNICATE WITH HOST
~N1 FOR MUSS V1
~N2 FOR MUSS V2
~
~S~O1.1 Disc Copy
~BThe disc copy procedure facilitates the copying of files from one disc
(on drive 0) onto another (on drive 1). It provides the following copy
options to the operator
~
~
~M1) all the Disc
~N2) the system (versions 1 and 2 of MUSS)
~N3) files only
~
~BThese options are listed out in a menu when the procedure is entered.
The procedure allows for the possibility of faulty pages.
For this to work, a certain number of contiguous pages are reserved at the
highest page address end of the disc. The last page in this reserved
block of pages is used for holding
the list of faulty pages and the pages which have been substituted
for them. The last entry in this list holds the
nember of substitute pages which are used. A disc cannot be used if this page is
 bad.
The rest of the reserved pages are allocated consecutively.
~BThe list of faulty pages are checked before each read operation, and whenever
a substitute page is allocated to a block, the block is read from this substitut
e
page. All read faults are monitored but no further action is taken. Normally
blocks are written to the correct position on the disc.
~BWhenever a write operation encounters a bad page, one of the substitute
pages is allocated for use and the write error is monitored.
If the procedure runs out of substitute pages, a message is printed and the copy
 stops to wait operator action.
~
~BAll reading and writing are done on a track at a time basis unless when
a read operation involves reading a block from its substitute page or when
a write error occured. When either one of these conditions arises the operation
on the track is done on a page at a time basis.
~BThe procedure starts by reading into store the table holding the
list of faulty pages. A new table is initiallised or in the case
of a partial copy read from the disc on drive 1, and used during the procedure.
At the end of the procedure this table is written on the disc on drive 1.
~S~O1.2 Disc Consolidation
~BThis section is only relevant on discs which are un-paged.
As the disc fills up, it becomes more and more difficult
to satisfy large block requests. The Consolidate procedure simply move user
files (including directories) into one large contigous block at the low
page address end of the disc. The first n blocks are not
consolidated as they are used for the Operating System.

~BThe procedure starts by initially constructing a table. This table contains
information about the block usage of the disc. The table is updated
whenever a file or directory is moved on the disc. At the end of all file
movement the disc addresses in the directories and the file master block
are updated using information from the table.

~
~S~O1.3 Down-line Load
~
~BThe bootstrap also acts as a means of communication between the operator termi
nal
and another (host) system connected into multiplexor port 0. By means
of this connection a downline load can be initiated from the host
system and the information transferred this way can be written to a
specified disc address.
~BIn this communication mode each character typed is transmitted to
the host, and each character sent by the host is printed unless the
character # is typed. After a '#' has been input the communication
still applies but an '^' returned from the host will be treated as a
warning character requesting special action. The action is selected by
the next character. Down load to disc is selected by a '6'.
~BThe information is transmitted during a download as 4 bits per
(hex) character. The values 0 - 15 are represented by the characters A
- P.
~BEach block to be loaded to disc is transmitted as~
~
~M^ disc address in hex
~Nblock in hex
~N^
~
After the terminating '^' of a block the sequence reverts to
communication mode.
~BThis primitive loader is driven from the host by means of the
private library DOWNLD1 under MUSM.
~S13. DISC Layout
~BThis loader operates on the MU6G. The Disc Layout
is as follows~
~
~M~OSingle Density Layout~O           ~
~Nsectors   0 -  31  PRE BOOTSTRAP
~Nsectors  32 -  63  BASIC BOOTSTRAP FACILITIES
~Nsectors  64 -  95  V1 BOOTSTRAP
~Nsectors  64 -  95  V2 BOOTSTRAP
~
~
~N~ODouble Density Layout~
~Nsectors   0 -  31  PRE BOOTSTRAP
~Nsectors  32 -  47  BASIC BOOTSTRAP FACILITIES
~Nsectors  48 -  63  V1 BOOTSTRAP
~Nsectors  48 -  63  V2 BOOTSTRAP
~S1~O4. Bootstrap and Loader Compile (MU6G)~
~S14.1 Compiling the MU6G Loader
~
~OFiles Produced
~
DOWNLD7 DOWNLD70~
~
::BEGIN CMPDLD7~
DO 0 MUSM:DLD7LOG %200~
OPENDIR MUSM MSUM~
OUTFN CDOWNLD7~
FLIP MU6S:AP7001 1~
DOWNLD~
DI 4~
MUSL 0 DOWNLD7 5 8~
**TLSEG 0 %0 %220000 -1~
**TLSEG 1 %0 %0 -3~
**TLSEG 2 %0 %320000 -3~
*TLLOAD 1 2;~
*TLLOAD 2 10;~
*INFORM %2400;~
**SELECTINPUT 4~
ENDINPUT 4~
STOP~
::END CMPDLD7~
~S14.1 Compiling the MU6G Bootstrap
~
~OFiles Produced
~
BOOT7~
~
::BEGIN CBOOT7
LIB MUSM:DOWNLD7~
LIB MUSM:MUTLX7~
LIB MUSM:MUSL~
LIB MUSM:L2X7~
OUTFN CBOOT7~
FLIP MU6S:AP7001 1~
AP700~
ED~
(FD/::? /)E~
**DI 4 0~
MUSL %0 %0 %60B~
*INFORM %2400;~
**TLSEG 0 %1000 %0 %230000 0~
**TLSEG 1 %1000 %1004 -1 0~
**TLSEG 2 %1000 %2000 -3 0~
**TLSEG 3 %4000 %10000 -3 0~
*TLLOAD 0 5;~
*TLLOAD 1 2;~
*TLLOAD 2 3;~
*TLLOAD 3 4;~
**SELECTINPUT 4~
ENDINPUT 4~
DEL~
MUSL %0 %0 %E00~
MODULE (SERVICE.ROUTINE);~
*CODE 2;~
PSPEC SERVICE.ROUTINE (INTEGER);~
PROC SERVICE.ROUTINE (DUMMY);~
END~
*END~
FILE BOOT7? 0 35~
STOP~
::END CBOOT7
~S15.1 Downline Loading the Bootstrap Onto a New Disc
~BRunning the above compile job will produce the bootstrap (BOOT51)
and the library DOWNLD1. The sequence
to load to a new disc is to log into the host from the MU6G and
obey the following commands~
~T# 7
~
  1)~IOPENDIR MUSM MSUM~
  2)~ILIB DOWNLD1~
  3)~I$UPDATE BOOT~
~
The success of this operation can be tested by booting in from the new
disc.
~Y
~V9 -1
~P
~V9 -1
~D15
~HFLOWCHARTS
~
~
~H               AP7001
~V9 -1
~F
@TITLE AP700(1,9)

@COL 1S-2R-3R-4R-5R-6F
@FLOW 1-2-3-4-5-6
@BOX 1.0
BASIC BOOTSTRAP FACILITIES
@BOX 3.0
DECLARATIONS
@BOX 4.0
PROCEDURES IN MODULE:
#AP700/1
@BOX 6.0
END
@BOX 1.1
PSPEC SERVICE.ROUTINE (INTEGER);
MODULE (DISC.TRAN, CONS.IN.CH, CONS.OUT.CH, TRANSMIT.CH, GET.CH,
   PRINT, INIT.DISC, DISC.COMMAND, DISC.TYPE, READ, WRITE);
@BOX 3.1
LITERAL / LOGICAL8 BS = 8, LF = %A, CR = %D, SP = %20;
LITERAL / LOGICAL READY = 1, NOT.READY = 1, TX.READY = 1, RX.READY = 1, KBD.READ
Y = 1,
   READ = 0, WRITE = 1, MAX.TRANSFER.SIZE = 32, SECTOR.SIZE = 256, PORT = 0;
LITERAL / ADDR OLAY.ADDR = %1000, OLAY.SIZE = 4;
*GLOBAL 3;
LOGICAL CONS.I.STAT, COMMS.RX.STAT;
INTEGER GET.SW, GET.SIZE, BOUNDARY, I;
*GLOBAL 4;
LOGICAL32 [%4000] BUFFER;
*VTYPE LOGICAL;
VSTORE V.I.STATUS %74;
VSTORE V.O.STATUS %6C;
VSTORE V.CONS.I.STAT CONS.I.STAT < CONS.I.STAT.PRE.PROC;
VSTORE V.CONS.I.BUFF %64;
VSTORE V.CONS.O.BUFF %64;
VSTORE V.COMMS.RX.STAT COMMS.RX.STAT < COMMS.RX.STAT.PRE.PROC;
VSTORE V.COMMS.TX.STAT %6C;
VSTORE V.COMMS.RX.BUFF %64;
VSTORE V.COMMS.TX.BUFF %64;
VSTORE V.MU6G.EXTENSION %48004;
VSTORE V.UNIBUS.EXTENSION %4800C;
VSTORE V.SI.CONTROL %4F704;
VSTORE V.SI.COUNT %4F70C;
VSTORE V.SI.CYL %4F714;
VSTORE V.SI.TRACK %4F71C;
VSTORE V.SI.CADDR %4F724;
VSTORE V.SI.ERROR %4F72C;
VSTORE V.SI.SEEK.STATUS %4F734;
VSTORE V.SI.SEEK.ADDR %4F73C;
VSTORE V.SI.DATA.BUFFER %4F744;
VSTORE V.SI.COMMS %4F74C;
VSTORE V.SI.SC %4F754;
@BOX 4.1
:: PROCEDURE DECLARATIONS
#AP700/1
@BOX 5.1
*#%6500 %0020; :: BM3 = %20
*#%7C30; :: BM3 <<- 16
*#%C653; :: SF = BM3
:: SET STACK TO TOP OF STORE
MENU ();
@BOX 6.1
*END
@END
@TITLE AP700/1

@COL 1S
@BOX 1.0
PROCEDURES IN MODULE:
   1 CONS OUT CH
   2 CONS IN CH
   3 MENU
   4 COMMS
   5 PRINT
   6 DISC TRAN
   7 LOAD DISC
   8 TRANSMIT CH
   9 GET BLOCK
   10 GET HEX WORD
   11 GET BYTE
@BOX 1.1
*CODE 1;
-> START;
*CODE 2;
*GLOBAL 0;
*CODE 1;
START:
PSPEC DISC.TRAN (ADDR, ADDR, LOGICAL, LOGICAL);
PSPEC CONS.OUT.CH (INTEGER);
PSPEC CONS.IN.CH () / INTEGER;
PSPEC GET.CH () / INTEGER;
PSPEC PRINT (ADDR [LOGICAL8]);
PSPEC TRANSMIT.CH (INTEGER) / INTEGER;
PSPEC GET.HEX () / LOGICAL32;
PSPEC GET.BLOCK () / ADDR;
PSPEC LOAD.DISC ();
PSPEC COMMS ();
PSPEC MENU ();
#AP700.12
#AP700.13
#AP700.6
#AP700.1
#AP700.2
#AP700.11
#AP700.5
#AP700.8
#AP700.10
#AP700.9
#AP700.7
#AP700.4
#AP700.3
@END

@TITLE AP700.1(1,9)
@COL 1S-2R-3F

@FLOW 1-2-3

@BOX 1.1
PROC CONS.OUT.CH (CH);
@BOX 2.1
0 => V.I.STATUS;
WHILE V.O.STATUS = NOT.READY DO OD
CH => V.CONS.O.BUFF;
@BOX 3.1
END
@END
@TITLE AP700.2(1,9)

@COL 1S-2R-3R-4F
@FLOW 1-2-3-4
@BOX 1.0
CONS IN CH () CH
@BOX 2.0
LOOP UNTIL DEVICE READY
@BOX 3.0
GET CH FROM DEVICE BUFFER
@BOX 4.0
END
@BOX 1.1
PROC CONS.IN.CH;
@BOX 2.1
WHILE V.I.STATUS = 0 DO OD
@BOX 3.1
WHILE %80 & V.CONS.I.BUFF /= 0 DO
   0 => V.I.STATUS;
   WHILE V.I.STATUS = 0 DO OD
OD
V.CONS.I.BUFF => CONS.IN.CH;
0 => V.I.STATUS;
@BOX 4.1
END
@END

@TITLE AP700.3(1,9)

@COL 1S-2R-6R-13R-14T-15R-16F
@FLOW 1-2-6-13-14Y-15
@FLOW 14N-6
@BOX 1.0
MENU SELECT
@BOX 2.0
READ IN OVERLAY
@BOX 6.0
OUTPUT MENU TABLE
@BOX 13.0
CONS OUT CH (CH)
@BOX 14.0
VALID BOOT COMMAND?
@BOX 15.0
ENTER SPECIFIED SERVICE ROUTINE
@BOX 16.0
END
@BOX 1.1
PROC MENU;
INTEGER CH, D.ADDR, DISC;
@BOX 2.1
::DISC.TRAN (1, %3F4 %DFF, READ);
:: READ REST OF CODE SEG IF NECESSARY
@BOX 6.1
DATAVEC MENU.MESS (LOGICAL8)
   LF "TYPE:"
   LF "0 TO COMMUNICATE WITH HOST"
   LF "1 FOR MUSS V1"
   LF "2 FOR MUSS V2"
   LF
END
PRINT (^MENU.MESS);
@BOX 13.1
CONS.OUT.CH (CONS.IN.CH () => CH);
@BOX 14.1
IF CH - "0" => CH < 0 OR CH > 2
@BOX 15.1
DATAVEC DAD (LOGICAL)
   32 32
END
IF CH = 0 THEN
   COMMS ();
ELSE
   DAD [CH -1] => D.ADDR;
   DISC.TRAN (D.ADDR, OLAY.ADDR, OLAY.SIZE, READ);
   SERVICE.ROUTINE (CH);
FI
@BOX 16.1
END
@END
@TITLE AP700.4(1,9)

@COL 1S-4R-5T-6T-7T-8R-9R-10T-12R-13T-14T-15R-17F
@FLOW 1-4-5Y-6Y-7Y-8-10Y-12-13Y-14Y-15-9-10
@FLOW 5N-10
@FLOW 6N-10
@FLOW 7-9
@FLOW 10N-5
@FLOW 13N-5
@FLOW 14N-5
@BOX 1.0
COMMS
@BOX 4.0
CLEAR SWITCH
@BOX 5.0
ANY CONSOLE INPUT
@BOX 6.0
READY FOR COMMS OUTPUT
@BOX 7.0
IS CH = $
@BOX 8.0
SET SWITCH
@BOX 9.0
TRANSMIT CH
@BOX 10.0
ANY COMMS INPUT
@BOX 12.0
CONS OUT CH
@BOX 13.0
IS THE CH = ^
@BOX 14.0
IS SWITCH SET
@BOX 15.0
DECODE SERVICE AND SWITCH
THEN OUTPUT?
AND GENERATE OR RESPONSE
@BOX 16.0
SERVICES AVAILABLE ARE
LOAD TO DISC
@BOX 17.0
END
@BOX 1.1
PROC COMMS;
INTEGER I, CH, SW;
DATAVEC WCH (LOGICAL8)
   6
END
@BOX 4.1
0 => SW;
@BOX 5.1
IF V.CONS.I.STAT & KBD.READY = 0
@BOX 6.1
IF V.COMMS.TX.STAT & TX.READY = NOT.READY
@BOX 7.1
IF CONS.IN.CH () => CH /= "$$"
@BOX 8.1
1 +> SW;
@BOX 9.1
%80 ! CH => V.COMMS.TX.BUFF;
@BOX 10.1
IF V.COMMS.RX.STAT & RX.READY = 0
@BOX 12.1
CONS.OUT.CH (V.COMMS.RX.BUFF & %7F => CH);
@BOX 13.1
IF CH /= "^"
@BOX 14.1
IF SW = 0
@BOX 15.1
GET.CH () => CH;
FOR I < SIZE (^WCH) DO
   IF CH = WCH [I] THEN
::      ALTERNATIVE I FROM
         LOAD.DISC ();
::      END
      WHILE V.COMMS.RX.STAT & RX.READY = 0 DO OD
      0 => V.I.STATUS;
      FOR %1800 DO OD
      CONS.OUT.CH ("?");
      -> OUT;
   FI
OD
OUT:
CR => CH;
@BOX 16.1
@BOX 17.1
END
@END
@TITLE AP700.5(1,9)

@COL 1S-3R-4F
@FLOW 1-3-4
@BOX 1.0
PRINT MESSAGE
@BOX 3.0
OUTPUT CHARACTERS OF MESSAGE
@BOX 4.0
END
@BOX 1.1
PROC PRINT (MESS);
INTEGER PTR;
@BOX 3.1
FOR PTR < SIZE (MESS) DO
   CONS.OUT.CH (MESS^ [PTR]);
OD
@BOX 4.1
END
@END
@TITLE AP700.6(1,9)

@COL 1S-2R-3R-4R-5R-6R-7R-8F

@FLOW 1-2-3-4-5-6-7-8

@BOX 1.1
PROC DISC.TRAN (SECTOR, C.ADDR, TRAN.SIZE, DIRN);
INTEGER CYL, TRACK;
@BOX 2.1
%3F => V.UNIBUS.EXTENSION;
1 => V.SI.SC;
WHILE V.SI.SC & %80 = 0 DO OD;
@BOX 3.1
WHILE V.SI.SEEK.STATUS & 7 = 1 DO OD;
WHILE V.SI.SEEK.STATUS & 7 /= 0 DO
   1 => V.SI.CONTROL;
OD
@BOX 4.1
SECTOR / 608 => CYL ! PORT => V.SI.CYL;
CYL * 608 -: SECTOR => V.SI.TRACK;
256 * TRAN.SIZE => V.SI.COUNT;
@BOX 5.1
C.ADDR => V.SI.CADDR;
C.ADDR ->> 15 => V.MU6G.EXTENSION;
@BOX 6.1
IF DIRN = READ THEN
   5 => V.SI.CONTROL;
ELSE
   3 => V.SI.CONTROL;
FI
@BOX 7.1
WHILE V.SI.CONTROL & %80 = 0 DO OD;
0 => V.SI.SC;
@BOX 8.1
END
@END
@TITLE AP700.7(1,9)

@COL 1S-6R-2T-3R-5R-4F
@COL 8R
@ROW 3-8
@FLOW 1-6-2YES-3-5-4
@FLOW 2NO-8-4
@BOX 1.0
LOAD BLOCK TO DISC (SPECIFIED SECTOR SIZE)
@BOX 2.0
GET BLOCK FROM HOST
SUCCESSFUL?
@BOX 3.0
DISC TRANSFER
@BOX 4.0
END
@BOX 5.0
SIGNAL SUCCESS TO HOST
@BOX 6.0
SAVE AND RESET GLOBAL SECTOR SIZE
@BOX 8.0
SIGNAL FAILURE TO HOST
@BOX 1.1
PROC LOAD.DISC;
ADDR D.ADDR, C.ADDR;
@BOX 2.1
IF GET.BLOCK () => D.ADDR < 0
@BOX 3.1
BYTE (^BUFFER) => C.ADDR;
WHILE GET.SIZE > MAX.TRANSFER.SIZE DO
   DISC.TRAN (D.ADDR, C.ADDR, MAX.TRANSFER.SIZE, WRITE);
   MAX.TRANSFER.SIZE -> GET.SIZE;
   MAX.TRANSFER.SIZE +> D.ADDR;
   MAX.TRANSFER.SIZE * 512 +> C.ADDR;
OD
DISC.TRAN (D.ADDR, C.ADDR, GET.SIZE, WRITE);
@BOX 4.1
END
@BOX 5.1
TRANSMIT.CH ("@");
@BOX 8.1
TRANSMIT.CH ("A");
@END
@TITLE AP700.8(1,9)

@COL 1S-3R-4R-5R-6R-7F
@FLOW 1-3-4-5-6-7
@BOX 1.0
TRANSMIT CH TO HOST MACHINE
@BOX 3.0
WAIT UNTIL READY TO TRANSMIT
@BOX 4.0
WRITE CH TO COMMS BUFFER
@BOX 5.0
WAIT UNTIL ECHO RECEIVED
@BOX 6.0
RETURN ECHOED CHARACTER
DELAY LOOP
@BOX 7.0
END
@BOX 1.1
PROC TRANSMIT.CH (CH);
@BOX 3.1
WHILE V.COMMS.TX.STAT & TX.READY = NOT.READY DO OD
@BOX 4.1
%80 ! CH => V.COMMS.TX.BUFF;
@BOX 5.1
WHILE V.COMMS.RX.STAT & RX.READY = 0 DO OD
@BOX 6.1
V.COMMS.RX.BUFF & %7F => TRANSMIT.CH;
0 => V.I.STATUS;
FOR 500 DO OD
@BOX 7.1
END
@END
@TITLE AP700.9(1,9)

@COL 1S-2R-3R-5R-7R-8T-9R-11R-12R-10F
@FLOW 1-2-3-5-7-8N-7
@FLOW 8Y-9-11-12-10
@BOX 1.0
GET BLOCK FROM HOST MACHINE
@BOX 2.0
SET PTR TO BUFFER
@BOX 3.0
LOOP UNTIL CH = "^"
@BOX 5.0
GET HEX BYTE
@BOX 7.0
GET HEX BYTE
@BOX 8.0
END OF BLOCK
@BOX 9.0
CALCULATE BLOCK SIZE
@BOX 10.0
END
@BOX 11.0
VALIDATE CHECKSUM
@BOX 12.0
FLAG IF CHECKSUM INVALID
@BOX 1.1
PROC GET.BLOCK;
INTEGER PTR, I, J;
LOGICAL32 LONGWORD, CHECKSUM, SUM;
INTEGER LW.SECTOR.SIZE;
SECTOR.SIZE ->> 1 => LW.SECTOR.SIZE;
0 => GET.SW;
@BOX 2.1
-1 => PTR;
@BOX 3.1
WHILE GET.CH () /= "^" DO OD
@BOX 5.1
GET.HEX () => GET.BLOCK;
@BOX 7.1
GET.HEX () => BUFFER [1 +> PTR];
@BOX 8.1
IF GET.SW = 0
@BOX 9.1
IF BOUNDARY /= 0 THEN
   1 -> PTR;
FI
PTR + LW.SECTOR.SIZE / LW.SECTOR.SIZE => GET.SIZE;
@BOX 10.1
END
@BOX 11.1
GET.HEX () => CHECKSUM;
0 => SUM;
-1 => I;
WHILE 1 +> I =< PTR DO
   32 => J;
   BUFFER [I] => LONGWORD;
   WHILE 8 -> J >= 0 DO
      LONGWORD ->> J & %FF + SUM & %3F(7) => SUM;
   OD
OD
@BOX 12.1
IF CHECKSUM /= SUM THEN
   DATAVEC CF.MESS (LOGICAL8)
      LF "CHECKSUM FAIL" LF
   END
   PRINT (^CF.MESS);
   -1 => GET.BLOCK;
FI
@END
@TITLE AP700.10(1,9)

@COL 1S-2R-3T-4T-5R-6R-8T-11F
@FLOW 1-2-3N-4Y-5
@FLOW 4N-3
@FLOW 3Y-6-8N-11
@FLOW 8Y-3
@BOX 1.0
GET HEX WORD
@BOX 2.0
SET COUNT
CLEAR RESULT
@BOX 3.0
IS THE NEXT CH A HEX CH
@BOX 4.0
IS IT "^"
@BOX 5.0
NOTE END OF BLOCK
AND EXIT
@BOX 6.0
RESULT <<- 4 + NEWCH
@BOX 8.0
COUNT > 0?
@BOX 11.0
END
@BOX 1.1
PROC GET.HEX;
INTEGER COUNT, CH;
@BOX 2.1
8 => COUNT;
0 => GET.HEX;
@BOX 3.1
IF GET.CH () => CH >= "A" =< "P"
@BOX 4.1
IF CH /= "^"
@BOX 5.1
IF COUNT & 1 /= 0 THEN
   DATAVEC BD.MESS (LOGICAL8)
      LF "BYTE DROPPED" LF
   END
   PRINT (^BD.MESS);
FI
IF COUNT < 8 THEN
   COUNT <<- 2 => COUNT;
   GET.HEX <<- COUNT => GET.HEX;
   0 => BOUNDARY;
ELSE
   1 => BOUNDARY;
FI
1 => GET.SW;
EXIT;
@BOX 6.1
"A" -> CH;
GET.HEX <<- 4 + CH => GET.HEX;
@BOX 8.1
IF 1 -> COUNT > 0
@BOX 11.1
END
@END
@TITLE AP700.11(1,9)

@COL 1S-2R-3R-4F
@FLOW 1-2-3-4
@BOX 1.0
GET CH FROM HOST MACHINE
@BOX 2.0
WAIT UNTIL CH AVAILABLE
@BOX 3.0
READ AND RETURN CH
@BOX 4.0
END
@BOX 1.1
PROC GET.CH;
@BOX 2.1
WHILE V.COMMS.RX.STAT & RX.READY = 0 DO OD
@BOX 3.1
V.COMMS.RX.BUFF & %7F => GET.CH;
0 => V.I.STATUS;
@BOX 4.1
END
@END
@TITLE AP700.12(1,9)

@COL 1S-3R-4F
@FLOW 1-3-4
@BOX 1.0
CLEAR NEXT LINE
@BOX 2.0
CALCULATE NEXT LINE NO
@BOX 3.0
CLEAR NEXT LINE
@BOX 4.0
END
@BOX 1.1
PROC CONS.I.STAT.PRE.PROC;
@BOX 3.1
IF V.I.STATUS /= 0 AND %80 & V.CONS.I.BUFF = 0 THEN
   1 => CONS.I.STAT;
ELSE
   0 => CONS.I.STAT;
FI
@BOX 4.1
END
@END

@TITLE AP700.13(1,9)

@COL 1S-3R-4F
@FLOW 1-3-4
@BOX 1.0
INITIALIZE CONSOLE
@BOX 2.0
INIT KEYBOARD
@BOX 3.0
INIT CRTC
@BOX 4.0
END
@BOX 1.1
PROC COMMS.RX.STAT.PRE.PROC;
@BOX 3.1
IF V.I.STATUS /= 0 AND %80 & V.COMMS.RX.BUFF /= 0 THEN
   1 => COMMS.RX.STAT;
ELSE
   0 => COMMS.RX.STAT;
FI
@BOX 4.1
END
@END

@TITLE DOWNLD(1,11)

@COL 1S-2R-3R-4R-5R-6F
@FLOW 1-2-3-4-5-6
@BOX 1.0
DOWN LOAD
@BOX 4.0
PROCEDURES IN MODULE
     UTILITY PROCS
   1 LOAD
   2 OUT.SEG
   3 UPDATE
   4 FORMAT
@BOX 6.0
END
@BOX 1.1
#DOWNLD/1
MODULE (LOAD, OUT.SEG, UPDATE);
@BOX 3.1
*GLOBAL 2;
INTEGER PW0, PW1, PW2, PW3, PW4, PW5, PW6;
*GLOBAL 10;
LOGICAL8 [%4000] BUFF;
@BOX 4.1
PSPEC S.AND.W () / INTEGER;
PSPEC OUT.FN (LOGICAL64);
LSPEC LOAD (LOGICAL32, LOGICAL64, INTEGER);
LSPEC OUT.SEG (INTEGER, INTEGER, LOGICAL64);
LSPEC UPDATE (LOGICAL64);
PSPEC MAKE.NAME (LOGICAL64, ADDR [LOGICAL8])/ADDR [LOGICAL8];
PROC MAKE.NAME (FILE.N, NAME);
INTEGER I, J;
FOR I < 8 DO
   I*8 => J;
   FILE.N ->> J => NAME^ [7 - I];
OD;
NAME => MAKE.NAME;
END
   #DOWNLD.UTIL
   #DOWNLD.1
   #DOWNLD.2
   #DOWNLD.3
@BOX 6.1
*END
@END

@TITLE DOWNLD/1(7,11)

@COL 1S
@BOX 1.0
EXTERNAL ENVIRONMENT
@BOX 1.1
LSPEC OUT.HDR (ADDR [LOGICAL8]);
LSPEC SELECT.OUTPUT (INTEGER);
LSPEC END.OUTPUT (INTEGER, INTEGER);
LSPEC CURRENT.OUTPUT () / INTEGER;
LSPEC DEFINE.OUTPUT (INTEGER, ADDR [LOGICAL8], INTEGER, INTEGER,
   INTEGER, INTEGER) / INTEGER;
LSPEC IN.I () / INTEGER;
LSPEC OUT.I (INTEGER, INTEGER);
LSPEC CAPTION (ADDR [LOGICAL8]);
LSPEC PROMPT (ADDR [LOGICAL8]);
LSPEC NEW.LINES (INTEGER);
LSPEC SPACES (INTEGER);
LSPEC BREAK.INPUT (INTEGER);
LSPEC BREAK.OUTPUT (INTEGER);
LSPEC IN.CH () / INTEGER
LSPEC OUT.CH (INTEGER);
LSPEC SELECT.INPUT (INTEGER);
LSPEC CURRENT.INPUT () / INTEGER
LSPEC OUT.TIME ();
LSPEC OPEN.FILE (ADDR [LOGICAL8], LOGICAL64, INTEGER, LOGICAL);
LSPEC CREATE.SEGMENT (INTEGER, INTEGER);
LSPEC RELEASE.SEGMENT (INTEGER);
LSPEC OPEN.DIR (LOGICAL64, LOGICAL64);
LSPEC FILE (ADDR [LOGICAL8], LOGICAL64, INTEGER);
LSPEC INTERCHANGE (INTEGER, INTEGER);
LSPEC CHANGE.SIZE (INTEGER, INTEGER);
LSPEC READ.SEGMENT.STATUS (INTEGER);
@END

@TITLE DOWNLD.UTIL(7,9)

@COL 1S
@BOX 1.0
UTILITY PROCEDURES
   S AND W
   OUT FN
@BOX 1.1
PROC S.AND.W;
INTEGER C.IN;
   BREAK.OUTPUT (-1);
   CURRENT.INPUT () => C.IN;
   SELECT.INPUT (0);
   PROMPT (%">>");
   BREAK.INPUT (0);
   IN.CH () - "@" => S.AND.W;
   SELECT.INPUT (C.IN);
END

PROC OUT.FN (WORD);
INTEGER I, J;
   FOR I < 8 DO
      (7-I) <<- 3 => J;
      OUT.CH (WORD ->> J & %FF);
   OD
END
@END

@TITLE DOWNLD.1(7,11)

@COL 11T-12R
@COL 1S-2T-3T-4R-5R-6R-7R-8R-14T-9R-10F
@COL 13R
@ROW 11-3
@ROW 12-5-13
@FLOW 1-2N-3Y-4-5-6-7-8-14YES-9-10
@FLOW 2Y-11Y-5
@FLOW 11N-12-10
@FLOW 3N-13-10
@FLOW 14NO-7
@BOX 1.0
LOAD (POSITION, FILE NAME, LIMIT)
@BOX 2.0
FILE = 0?
@BOX 3.0
OPEN FILE OK?
@BOX 4.0
INTERCHANGE SEGS
@BOX 5.0
OBTAIN LIMIT
@BOX 6.0
SET UP FOR OUTPUT
@BOX 7.0
OUTPUT DISC POSITION
@BOX 8.0
OUTPUT "CODE"
AND CHECKSUM
@BOX 9.0
TIDY UP
@BOX 10.0
END
@BOX 11.0
SEGMENT STATUS OK?
@BOX 12.0
SEGMENT DOES NOT EXIST
@BOX 13.0
UNABLE TO OPEN FILE
@BOX 14.0
TRANSFER OK?
@BOX 1.1
PROC LOAD (POSITION, FILE, LIMIT);
INTEGER COUNT, O.OUT, N.OUT, PTR,
   CH, SEG, SEG.SIZE, CHECKSUM;
LOGICAL8 [16] F.NAME;
@BOX 2.1
IF FILE = 0
@BOX 3.1
OPEN.FILE (MAKE.NAME (FILE,^F.NAME), 0, -1, %1E);
IF PW0 /= 0
@BOX 4.1
PW2 => SEG.SIZE;
INTERCHANGE (PW1 => SEG, 50);
@BOX 5.1
IF LIMIT =< 0 THEN
   SEG.SIZE => LIMIT;
   WHILE BUFF [1 -> LIMIT] = 0 AND LIMIT > 256 DO OD
ELSE
   IF 1 -> LIMIT > SEG.SIZE THEN
      SEG.SIZE - 1 => LIMIT;
   FI
FI
@BOX 6.1
DEFINE.OUTPUT (-1, %"REP0*", %8000, 64, 32000, 0) => N.OUT;
CURRENT.OUTPUT () => O.OUT;
SELECT.OUTPUT (N.OUT);
@BOX 7.1
OUT.HDR (%"$N$N");
OUT.CH ("^");
OUT.CH (6);
OUT.CH ("^");
32 => COUNT;
WHILE 4 -> COUNT >= 0 DO
   OUT.CH (POSITION ->> COUNT & %F + "A");
OD
@BOX 8.1
0 => COUNT => CHECKSUM;
FOR PTR < LIMIT + 1 DO
   OUT.CH (BUFF [PTR] => CH ->> 4 + "A");
   OUT.CH (CH & %F + "A");
   CH + CHECKSUM & %3F(7) => CHECKSUM;
   IF 1 +> COUNT = 24 THEN
      0 => COUNT;
      NEW.LINES (1);
   FI
OD
OUT.CH ("^");
32 => COUNT;
WHILE 4 -> COUNT >= 0 DO
   OUT.CH (CHECKSUM ->> COUNT & %F + "A");
OD
@BOX 9.1
SELECT.OUTPUT (O.OUT);
END.OUTPUT (N.OUT, 0);
RELEASE.SEGMENT (50);
IF FILE /= 0 THEN
   INTERCHANGE (SEG, 50);
FI
@BOX 10.1
END
@BOX 11.1
READ.SEGMENT.STATUS (50);
PW1 => SEG.SIZE;
IF PW0 = 0
@BOX 12.1
0 => PW0;
CAPTION (%"SEGMENT DOES NOT EXIST$L");
@BOX 13.1
0 => PW0;
CAPTION (%"UNABLE TO OPEN FILE$L");
@BOX 14.1
IF S.AND.W () /= 0
@END

@TITLE DOWNLD.2(7,9)

@COL 1S-3R-4R-5F
@FLOW 1-3-4-5
@BOX 1.0
OUT.SEG (SECTOR, SECTOR COUNT, FN, DENSITY)
@BOX 3.0
DOWN LINE LOAD
@BOX 4.0
COMPLETION MESSAGE
@BOX 5.0
END
@BOX 1.1
PROC OUT.SEG (SECTOR, SEC.COUNT, FN);
@BOX 3.1
LOAD (SECTOR, FN, SEC.COUNT <<- 9);
@BOX 4.1
CAPTION (%"OUT.SEG");
OUT.I (SECTOR, 6);
OUT.I (SEC.COUNT, 6);
SPACES (1);
OUT.FN (FN);
CAPTION (%"  COMPLETE AT ");
OUT.TIME ();
NEW.LINES (1);
@BOX 5.1
END
@END

@TITLE DOWNLD.3(7,9)

@COL 8R
@COL 1S-7T-2T-3R-4R-5F
@COL 6R
@ROW 8-3-6
@FLOW 1-7N-2Y-3-4-5
@FLOW 2N-6-5
@FLOW 7Y-8-5
@BOX 1.0
UPDATE (MNEM)
@BOX 2.0
UPDATE ENTITY EXISTS?
@BOX 3.0
GET VERSION NUMBER
@BOX 4.0
UPDATE COMMON SEGMENTS
@BOX 5.0
END
@BOX 6.0
NAME NOT RECOGNIZED
@BOX 7.0
IS ENTITY BOOTSTRAP?
@BOX 8.0
UPDATE BOOTSTRAP
@BOX 1.1
PROC UPDATE (MNEM);
LITERAL / INTEGER NO.OF.UPDS = 14,
   TWO.VERSIONS = 8, BASIC.SYSTEM = 3;
INTEGER UPD.TYPE, VERSION, I, LIMIT;
ADDR [INTEGER16] D.SIZE;
ADDR [INTEGER32] D.ADDR;
:: UPDATE DATAVECS
#DOWNLD.3.1
@BOX 2.1
-1 => UPD.TYPE;
WHILE 1 +> UPD.TYPE < NO.OF.UPDS AND
   MNEMS [UPD.TYPE] /= MNEM DO OD
IF UPD.TYPE = NO.OF.UPDS
@BOX 3.1
1 => VERSION;
@BOX 4.1
IF VERSION = 1 THEN
   ^V1.D.ADDR => D.ADDR;
   ^V1.D.SIZE => D.SIZE;
ELSE
   ^V2.D.ADDR => D.ADDR;
   ^V2.D.SIZE => D.SIZE;
FI
ENTRY.NO [UPD.TYPE] => I;
ENTRY.NO [UPD.TYPE + 1] => LIMIT;
IF UPD.TYPE < TWO.VERSIONS THEN
   IF MNEM = "DIR" THEN
      WHILE I < LIMIT DO
         OUT.SEG (D.ADDR^ [I] * 4, D.SIZE^ [I],
            FILE.NAME [I]);
         1 +> I;
      OD
   ELSE
      WHILE I < LIMIT DO
         OUT.SEG (D.ADDR^ [I] * 4, D.SIZE^ [I],
            FILE.NAME [I]);
         1 +> I;
      OD
   FI
ELSE
   WHILE I < LIMIT DO
      OUT.SEG (D.ADDR^ [I] * 4, D.SIZE^ [I],
         FILE.NAME [I]);
      1 +> I;
   OD
FI
@BOX 5.1
END
@BOX 6.1
CAPTION (%"NAME NOT RECOGNIZED$L");
@BOX 7.1
OPEN.DIR ("MUSM", "MSUM");
IF MNEM = "BOOT"
@BOX 8.1
OUT.SEG (0, 8, "BOOT71");
@END

@TITLE DOWNLD.3.1(5,8)

@COL 1S
@BOX 1.0
UPDATE DATAVECS
@BOX 1.1
DATAVEC MNEMS (LOGICAL64)
   "SYS" "LIB" "DIR" "MUSL"
   "MUTL" "MURD" "DOC" "MFN"
   "CWU" "UTIL" "FIO" "FTN" "PASCAL"
   "PIO"
END
DATAVEC FILE.NAME (LOGICAL64)
   :: SYS
   "BBST7100" "BSYS7110" "BSYS7120" "BSYS7100"
   "BSYS7130" "BSYS7140"
   :: LIB
   "BLIB7100"
   :: DIR
   "TLDIR71"
   :: END OF BASIC SYSTEM
   "BMSL7100" "BMTL7100" "BMTL7101"
   "BMRD7100" "BDOC7100" "BMFN7100"
   :: ONE VERSION ONLY
   "BCWU7100" "BUTL7100"
   "BFIO7100" "BFTN7100" "BFTN7101"
   "BPAS7100" "BPAS7101" "BPAS7110" "BPIO7100"
END
DATAVEC V1.D.ADDR (INTEGER32)
   8 160 224 32
   456 416
   288 424
   488 552 584
   680 776 744
   904 840
 -1 [6]
END
DATAVEC V1.D.SIZE (INTEGER16)
   3 80 128
   96 9 8 128 64
   128 128 128
   128 128 128
   128 128
   -1 [6]
END
DATAVEC V2.D.ADDR (INTEGER32)
   0 [22]
END
DATAVEC V2.D.SIZE (INTEGER16)
   0 [22]
END
DATAVEC ENTRY.NO (INTEGER8)
    0  6 7  8  9
    11 12 13 14 15
   16 17 19 22
   23
END
@END


