If PLASYD programs are run using the TASK system then the PLAN library is automatically searched for any external procedures that have not been included explicitly. Full details of the library procedures available are given in the relevant ICL manuals. Additional library routines appear in ACL's 1906A User Notes. In this chapter a few procedures are listed which should be particularly useful.
The aim of this routine is to print out areas of store during the running of the PLASYD program. The user may insert MONITOR requests at various points in his program. Whether or not printing actually takes place will depend on the current settings of the switches corresponding to bits 0 to 9 of word 30 of each program. The link used by the procedure MONITOR is X1 so that a declaration:
EXTERNAL MONITOR(X1);
should appear at the head of the program somewhere in the declarations.
A typical call of MONITOR would be as follows:
LINK:=X1; MONITOR; DATA(1CNT+502,50CNT+@Z);
Before the call of MONITOR the user must insert an instruction which stores the integer accumulator X1 into a lower variable. The areas of store printed depend on the parameters immediately following the call to MONITOR. These take the general form:
DATA(nCNT+m, cCNT+a, .....);
The parameters have the following meaning:
n = an integer in the range 0 to 511 which gives the number of cCNT+a parameters following.
m = usually a three digit number where the first digit defines the switch which will determine whether printing will take place and the remaining two digits can be used to identify the point in the source program from which the output comes. It is usual to have the m values for different calls of MONITOR unique. In the example given above, the number 502 identifies this MONITOR call and the output from it will only be printed if switch 5 is set on.
If a 1000 is added to the value of m then the contents of the integer accumulators which are normally output at the head of the MONITOR print will be omitted.
c = number of words of store to be printed out. The count must be less than 512.
a = address of first word of store to be printed. Using a number of parameters of this type, the one MONITOR can print several different areas of store.
The format of the printout is as follows:
MONITOR PRINT m
Zero words are not printed; in their place **** is printed.
Printing continues from the next non-zero word. Two newlines are output before and after the MONITOR printout with single newlines between the individual areas requested. The procedure is 338 words long including data areas used. None of the values of accumulators are disturbed by the procedure. If only the integer accumulators themselves are required, this can be achieved by setting n = 0. For example, arguments:
DATA(0CNT+504);
would just print the integer accumulators.
The best method of using MONITOR is to set up debug prints in groups controlled by different switch values. If the program has the name XYZ then it can be run from a MOP console by:
TASK PLASYD,*CR XYZ,#??(ON 5),#??(ON 3),#LP0
This would cause all MONITOR printing controlled by switches 5 and 3 to be printed. Modifying the TASK command to include additional ON commands would allow other printing to take place.
The MONITOR procedure only works in 15 bit address mode and direct branch mode. If programs require monitor printing in any other mode then the procedure MONITORX should be used. Output goes to the stream *LP0.
This procedure is very similar in format to MONITOR which was described in Section 24.2. The major differences are that it will work in any mode and the addresses to be printed are only listed in octal. Thus a valid call of MONITORX is:
LINK :=X1; MONITORX; DATA(1CNT+502, 50CNT+@Z);
The format of the printout is:
MONITOR PRINT m
The other major difference between MONITOR and MONITORX is that there is a second form of the parameter defining the area to be output As well as cCNT+a it is also possible to write a parameter as two separate words, for example:
DATA(1CNT+502, 50, @Z);
This is used when c is greater than 511 or the address a is greater than or equal to 32K.
The procedure is 255 words long including data areas.
This routine is similar to MONITOR and MONITORX except that it is designed to print only those locations which have been changed in value since the last call of MONITORI for a specific point in the program. The format of the calls to MONITORI is the same as for MONITOR and the parameters have basically the same meaning.
The first time any MONITORI call is reached in the program the contents of the 8 integer accumulators will be printed unless 1000 has been added to the monitor identifying parameter. Subsequently, when the MONITORI call is reached, the accumulators will only be printed if their contents have changed since last being printed. Similarly, the contents of the areas specified will be output in full the first time a particular monitor point is reached. However, on reaching the monitor point identified by m subsequently, only those locations whose contents have changed since the last print of this monitor point will be printed.
The final values of all locations in the monitor prints can be obtained by the inclusion of a monitor point whose first parameter after the identifying parameter is zero. In this case, the print out of store locations will be the same as if all previous different monitor points were repeated at this point in the program (only those locations that have changed will be printed).
The format of the printout for each location is as follows:
Two monitor points with the same identifying parameter but different parameter lists will be regarded as being the same point if and only if the locations to be monitored at the second point are a leading subset of the locations to be monitored at the first point.
As the last locations printed have to be stated for comparison purposes, the user must set up a scratch area on disc. Also the output is defined to go to *LP7. A suitable TASK command to run a program in file FRED containing MONITORI commands would be:
TASK PLASYD,*CR FRED,#LP7,#??(CE!(*ED,BUCK1,KWOR0)),- #??(AS *ED7,!(WRITE)),#??(ON 5)
if monitor switch 5 was required on.
Alternatively the scratch file assignment could be put in a macro file giving:
TASK PLASYD,*CR FRED,#LP7,MAC
where a macro FRED-MAC was:
CE!(*ED,BUCK1,KWORD) AS *ED7,!(WRITE) ON5
The routine requires 610 words of storage including data areas.
It is often necessary for the user to do his own handling of either data input or output. Below are simple procedures for reading and writing lines of data.
PROCEDURE INLINE(X1); BEGIN LOWER INTEGER INCTRL(4)=(3CNT,0,80,@INPUTBF); INTEGER INPUTBF(20); LOWEND; !PERI(1,INCTRL); X0 :=INCTRL(1); IF X0<0 THEN !SUSBY(0,3); END; PROCEDURE OUTLINE(X1); BEGIN LOWER INTEGER OUTCTRL(4) = (4CNT,0,80,@OUTPUTBF); INTEGER OUTPUTBF(20); LOWEND; !PERI(0,OUTCTRL); X0:=OUTCTRL(1); IFX0<0 THEN !SUSBY(0,4); END;
The first argument of the PERI in the procedure INLINE defines that input will be from unit number 1 and the control INCTRL indicates that the input is from the card reader. Thus the procedure INLINE will read the next card from *CR and place the 80 characters read into the locations INPUTBF(0) to INPUTBF(19), four characters to a word.
Similarly the procedure OUTLINE will pass the 80 characters contained in the buffer OUTPUTBF(0) to OUTPUTBF(19) to the stream *CP0.
The following routine will convert a binary integer into a decimal or octal character representation, and place the characters in a buffer specified by the calling routine. The integer is placed in X4 before the call, and the address of the buffer in X2. Note that the address supplied is the address of the first character after the number in the buffer. The decimal conversion routine will deal correctly with positive or negative numbers, preceding them with a space or minus sign respectively, Note also that a number consisting of a one in the sign bit and zeroes elsewhere cannot be converted by the routine, and is therefore trapped as a special case. The use of the routine should be made clear by the following examples.
(1) Convert the value held in COUNT to decimal characters, and place in BUFFER and BUFFER(1). Leading zeroes are to be replaced with spaces.
X4:= ' '; BUFFER:= X4; BUFFER(1):= X4; X2:= @BUFFER(2); X4:= COUNT; OUTDECIMAL;
(2) Convert the value held in COUNT to octal characters, and place in BUFFER (3) and BUFFER(4). All eight digits are to be printed.
BUFFER(3):=0 BUFFER(4):=0 X2:= @BUFFER(5); X4:= COUNT; OUTOCTAL;
(3) Convert the value held in TOTAL to decimal characters, and place in BUFFER(6) and BUFFER(7). TOTAL is known to be in the range 10000 to 99999, and it is desired to place the digits in character positions 1-3 of BUFFER(6) and 0-1 of BUFFER(7). Character 0 of BUFFER(6) will contain a space for the sign, and character 2 of BUFFER(7) is to contain a semicolon.
X4:= ' '; BUFFER(7):= X4; X2:=@BUFFER(7) + CHAR 2; X4:= TOTAL; OUTDECIMAL;
LOCAL ALL; PROCEDURE OUTDECIMAL (X0); BEGIN LOWER LOGICAL STRING(2) = ("-8388608"); LOWEND; [CALL WITH BINARY NUMBER IN X4] [X2 = ADDRESS OF CHARACTER AFTER NUMBER IN OUTPUT BUFFER] X1 := ' '; X7:=10; IF X4 < 0 THEN BEGIN X4:= NEG X4; X1:= '-'; IF X4 < 0 THEN GOTO MAXNEG; LOOP: X2:= X2 SLC 2 - 1 SRC 2; !DVS(3,X7); (X2):= CH X3; IF X4 NOT= 0 THEN GOTO LOOP; X2:= X2 SLC 2 - 1 SRC 2; (X2):= CH X1; RETURN; MAXNEG: X2:=X2-2; X1:= @STRING; !MVCH(l,8); RETURN; GLABEL OUTOCTAL: X2:= X2 SLC 2 - 1 SRC 2; X45:= X45 SRL 3; X5:=X5 SRL 21; (X2):= CH X5; IF X4 NOT= 0 THEN GOTO OUTOCTAL; END;