home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
kermit.columbia.edu
/
kermit.columbia.edu.tar
/
kermit.columbia.edu
/
archives
/
dec20.zip
/
assembler-guide.txt
next >
Wrap
Text File
|
2002-09-30
|
485KB
|
11,878 lines
DECSYSTEM-20 Assembly Language Guide
Edited by:
Frank da Cruz
Chris Ryland
Columbia University Center for Computing Activities
New York, New York 10027
3 July 1980
Assembly Language Guide Page 1
Preface
This document is intended to be a comprehensive introduction to assembly
language programming on the DECSYSTEM-20. It consists of excerpts from
various DEC manuals and other documents, with the addition of programming
examples and some original material. Appropriate credit is given in each
chapter or section in which the material is not original.
Chapter 8 attempts to present a programming standard for Macro programs; in a
sense it is the most important chapter because unless a program is clear and
understandable, it will not be adaptable to new circumstances, and its
usefulness and lifetime will be limited.
This is a draft. Various sections still need to be filled in or
refined, and more material added. This will be done from time to
time. Comments are welcome.
Introduction Page 2
1. Introduction
Assembly language is a tool for writing computer programs consisting, at the
source (program text) level, of actual machine instructions. It is sometimes
desirable or necessary to use assembly language for two reasons:
1. Only in assembly language can you write a program that can take
advantage of all the features of a given machine. Higher-level
languages purposely conceal the machine from programmers so that
programs may be transported from one machine to another.
2. You have maximum control over every aspect of the operation of your
program, especially storage allocation and efficiency.
In order to use an assembler, you must first be familiar with the machine's
instruction set. This is described in Chapter 2. You will notice that this
chapter actually describes three different machines: the KA10, the KI10, and
the KL10. You should be aware that DEC-20's are KL10's (2020's are KS10's,
but these are identical to KL10's for all practical purposes).
There are several assemblers suitable for use on the DEC-20. These include
Macro-20 (the standard DEC assembler), Midas (an alternative from MIT), and
Fail (a fast 1-pass block structured assembler from Stanford). Only Macro-20
is supported by DEC, but the other two have certain distinct advantages.
Macro-20 is described in Chapter 3.
Another thing that assembly-language programmers need to know about is monitor
calls. On a timesharing system, such as the DECSYSTEM-20, there are many
things that you cannot do even in assembly language, such as issue
input/output instructions; only the monitor can do such things. You can ask
the monitor to perform services for you by issuing a monitor call (a DEC-20
monitor call is called a 'JSYS' (Jump to SYStem)), which amounts to calling a
subroutine in the monitor. Information about DEC-20 monitor calls is given in
Chapters 4 and 5
There are various aids available to assembly language programmers; these
include libraries of helpful macros and routines (Chapters 6, 7), and
interactive, symbolic debugging facilities (Chapter 10). In addition, there
are chapters on how to write, run, and debug programs on the DECSYSTEM-20 (9),
and some sample programs (11). And, as pointed out in the Preface, a very
important Chapter on programming style and standards (8).
The major intent of this guide is to provide a consolidated resource for those
who wish to write assembly language programs, not assembly language
subroutines to be called from higher-level languages; such subroutines can
only be written with detailed knowledge of the calling conventions and
internal data representations of the given language.
The reader should have some knowledge of programming and some familiarity with
DECSYSTEM-20 commands and procedures.
Introduction Page 3
1.1. Basic Concepts
Before we can proceed with descriptions of the instruction set, assembler, and
monitor calls, some terminology and a few basic concepts of machine
organization must be introduced.
1.1.1. Terminology
Timesharing One way of running a computer. Timesharing allows many users
to use the computer at once, seated at terminals, and to
converse via the terminal with various programs on the
computer.
DECSYSTEM-20 A timesharing computer system, the subject of this manual.
DEC Digital Equipment Corporation. The manufacturer of the
DECSYSTEM-20, and of its predecessors, the PDP-10 and PDP-6.
Operating System A program, or set of programs, that controls the operation of
the computer. On a timesharing computer, the operating system
functions include scheduling among users, allocating resources
to users, controlling devices, and performing various other
services for users that could not be done by the users
themselves.
Tops-20 Timesharing OPerating System-20. This is the name of the
DECSYSTEM-20's operating system.
Monitor One component of Tops-20. It is a program that is always
running, and that performs most operating system functions.
Exec Another component of Tops-20. It is the program by which
users communicate their desires to the monitor, and through
which the monitor communicates to the user.
1.1.2. Machine Organization
The computer consists of various entities. You must be aware of what some of
them are in order to program in assembly language:
Memory This is a device that allows the computer to store and
retrieve a limited amount of data very quickly. It is not
permanent storage. It is often referred to as "core" memory
(it is sometimes made from magnetic cores), to differentiate
it from registers, disks, and other kinds of memory. Whether
it's made from cores or not, it is solid-state memory, i.e. it
has no moving parts.
Register (Also called an Accumulator) This is a special kind of solid-
state memory that is much faster than ordinary memory, and
that allows operations such as arithmetic to be performed on
data that is stored there. The DECSYSTEM-20 has 16 registers.
Disk A kind of mechanical memory that is much slower than registers
Introduction Page 4
or core memory, but which allows long-term storage of data in
files whose names are kept in directories. Disks can hold
much more data than core memory.
CPU Central Processing Unit. This is the part of the computer
that does most of the work, and where the major "intelligence"
is to be found. It consists of the registers and the logic to
move data to and from the registers, as well as logic to
operate on the data in the registers (e.g. to do arithmetic).
Instruction An instruction is a code to activate some function of the CPU.
Typically, it specifies what operation to perform, what data
to operate on, and where to put the result. Typical
operations include arithmetic (add, subtract, etc.), transfer
of control, comparison of numbers, etc. Assembly language
programs consist of a sequence of instructions. When the
program is being executed, the instructions are kept in
memory.
Address An address is a number that expresses the location of a
quantity (instruction or data) in memory. Used as a verb,
"address" means to "refer to".
Bit (BInary Digit) The smallest unit of storage in memory. A bit
is a quantity whose value can be 0 or 1.
Word The major unit of storage in memory. In the DECSYSTEM-20,
each word consists of 36 bits, and has its own address. You
can address 262144 words of memory on the DECSYSTEM-20.
Byte An intermediate unit of storage; any sequence of bits within a
word. A byte is often the unit of storage for a character.
Input/Output This is the act of transferring data between memory and some
device, typically a disk or a terminal.
1.1.3. Instructions and Addressing Modes
[ this is mostly taken care of in Ch. 2 ]
1.1.4. Internal Representation of Numbers
1.1.4.1. Binary Numbers
[ to be filled in ]
Introduction Page 5
1.1.4.2. Two's Complement Representation
[ to be filled in ]
1.1.4.3. Integers
[ to be filed in ]
1.1.4.4. Floating Point Numbers
[ to be filled in ]
1.1.5. Arithmetic
[ to be filled in ]
1.1.5.1. Integer Arithmetic
[ to be filled in ]
1.1.5.2. Floating Point Arithmetic
[ to be filled in ]
1.1.6. Logical Operations
[ to be filled in ]
1.1.7. Character String Manipulation
[ to be filled in ]
1.1.8. Elementary Data Structures
1.1.8.1. Tables (Arrays) and Indexing
[ to be filled in ]
Introduction Page 6
1.1.8.2. Stacks
[ to be filled in ]
Instruction Set Page 7
2. The PDP-10/DECSYSTEM-20 Instruction Set
2.1. Introduction
This chapter was written by Ralph E. Gorin at Stanford University
and modified slightly at Columbia.
The PDP-10 is a general purpose stored program computer. There are four
different processors (computers) in the PDP-10 family: the PDP-6, the KA10,
the KI10 and the KL10. The newest of these is the KL10 which is the central
processor in various DECsystem-10 and DECSYSTEM-20 configurations. (The KS10,
found only in the DECSYSTEM-2020, is nearly identical to the KL10.) In
general, we shall discuss the KL10 processor.
There are three principal aspects of assembly language programming: the
machine instructions, the assembler, and the operating system. The machine
instructions are the primitive operations with which we write programs.
Learning the instruction set means learning what operations are performed by
each instruction. Programming is the art or science of combining these
operations to accomplish some particular task.
The machine instructions, like everything else in a computer, are in binary.
The assembler is a program that translates the mnemonic names by which we
refer to instructons into the binary form that the computer recognizes. The
assembler also does a variety of other chores that are essentially
bookkeeping.
The operating system, or "monitor", is a special program that handles all
input and output and which schedules among user programs. For its own
protection and the protection of other users the operating system places
various restrictions on user programs. User mode programs are resticted to
memory assigned to them by the operating system; they may not perform any
machine input-output instructions, nor can they perform several other
restricted operations (e.g., HALT instruction). To facilitate user
input-output and core allocation the operating system provides various monitor
calls ( or JSYS operations) by which a user program can communicate its wishes
to the system. Essentially all programs except the operating system itself
are run as user mode programs. Editors, assemblers, compilers, utilities, and
programs that you write yourself are all user mode programs.
The PDP-10 is a word oriented machine. Words contain 36 data bits, numbered
(left to right) 0 to 35. Every machine instruction is one word. There are
two formats for machine instructions.
Most instructions have the format:
Bit 000000000 0111 1 1111 112222222222333333
Position 012345678 9012 3 4567 890123456789012345
________________________________________
| | | | | |
| OP | AC |I| X | Y |
|_________|____|_|____|__________________|
In the diagram the field names are:
Instruction Set Page 8
- OP = operation code
- AC = accumulator field
- I = indirect bit
- X = index field
- Y = address field
Some example intructions are:
move 1, @100 ; MOVE is the OP. AC is 1.
; @ sets the I bit.
; X is zero, Y is 100.
hrrz 17, 1(3) ; HRRZ is the OP. AC is 17,
; Y = 1, X = 3, I = 0
sos foo ; SOS is OP, FOO is symbolic
; for the Y field. AC, X, I
; are 0.
All instructions without exception calculate an "effective address". The
effective address may itself be used as data or it may be used to address the
data or result word for a particular instruction. The effective address
computation is described by the following program. MA means memory address.
means program counter. C(MA) means contents of the word addressed by MA.
Effective Address Calculation:
IFETCH: MA := PC
OP := Bits 0:8 of C(MA);
AC := Bits 9:12 of C(MA);
EACOMP: I := Bit 13 of C(MA);
X := Bits 14:17 of C(MA);
Y := Bits 18:35 of C(MA);
E := Y;
IF X <> 0 then E := Bits 18:35 of E+C(X);
IF I=0 then go to DONE;
MA := E;
go to EACOMP
DONE:
The effective address is an 18 bit quantity. If the I and X fields of the
instruction are zero then the effective address is simply the address (Y)
field of the instruction. If X isn't zero, then the contents of the word
addressed by X (i.e., the contents a register serving as the index register
for this instruction) are added to the contents of the Y field (the sum is
truncated to 18 bits). This sum serves as the effective address, unless the
indirect (I) bit is set. If the I bit is set, a word is read from the address
specified by X and Y, and the I, X, and Y fields of that new word are used for
repeating the effective address calculation. Note that this calculation will
loop until a word is read in which the I field is zero.
Instruction Set Page 9
The result of the effective address calculation may be thought of as an
instruction word where bits 0:12 are copied from the original instruction,
bits 13:17 are zero, and 18:35 contain the effective address.
In programming the PDP-10 it is convenient to imagine that your program
occupies contiguous virtual memory locations from 0 to some maximum address.
All memory locations are equivalent for most purposes (but some operating
systems reserve some of your space for their own purposes).
Sixteen memory locations (addresses 0 to 17 - note that addresses will appear
in octal) are distinguished by their use as general purpose registers (also
called accumulators or index registers). Most PDP-10 instructions address one
memory operand and one accumulator (so-called "one and a half address"
architecture). This means that nearly all instructions affect some
accumulator. These registers are actually implemented in high speed solid
state memory rather than in slower main memory. For any purpose where it is
convenient to do so, a user may reference an accumulator as memory.
Instruction classes are formed by a mnemonic class name and one or more
modifier letters. The modifiers usually signify some transformation on the
data or the direction of data movement or the skip or jump condition. Some
functional duplications and some no-ops result from this scheme. However,
despite these drawbacks, this notion of instruction classes and modifiers
makes the instruction set easy to learn.
2.2. Full Word Instructions
These are the instructions whose basic purpose is to move one or more full
words of data from one location to another, usualy from an accumulator to a
memory location or vice versa. In some cases, minor arithmetic operations are
performed, such as taking the magnitude or negative of a word.
2.2.1. MOVE
The MOVE class of instructions perform full word data transmission between an
accumulator and a memory location. There are sixteen instructions in the MOVE
class. All mnemonics begin with MOV. The first modifier specifies a data
transformation operation; the second modifier specifies the source of data and
the destination of the result.
|E no modification | from memory to AC
MOV |N negate source |I Immediate. Source is 0,,E to AC
|M magnitude |M from AC to memory
|S swap source |S to self. If AC<>0 to AC also
C(E) signifies contents of E (effective address) prior to the execution of the
instruction. C(AC) signifies contents of the AC specified. CS(E) and CS(AC)
signify the contents of E or AC with left and right halves swapped. CR(AC)
and CL(AC) signify the 18 bit right and left contents of the AC. PC signifies
the 18 bit contents of the program counter.
Instruction Set Page 10
MOVE C(AC) := C(E)
MOVEI C(AC) := 0,,E
MOVEM C(E) := C(AC)
MOVES C(E) := C(E); if AC<>0 then C(AC) := C(E)
MOVN C(AC) := -C(E)
MOVNI C(AC) := -E
MOVNM C(E) := -C(AC)
MOVNS C(E) := -C(E); if AC<>0 then C(AC) := -C(E)
MOVM C(AC) := |C(E)|
MOVMI C(AC) := 0,,E
MOVMM C(E) := |C(AC)|
MOVMS C(E) := |C(E)|; if AC<>0 then C(AC) := |C(E)|
MOVS C(AC) := CS(E)
MOVSI C(AC) := E,,0
MOVSM C(E) := CS(AC)
MOVSS C(E) := CS(E); if AC<>0 then C(AC) := CS(E)
2.2.2. EXCH - Exchange
EXCH exchanges the contents of the selected ac with the contents of the
effective address.
EXCH C(AC):=:C(E)
2.2.3. BLT - Block Transfer
The instruction copies words from memory to memory. The left half of the
selected AC specifies the first source address. The right half of the AC
specifies the first destination address. The effective address specifies the
last destination address. Words are copied, one by one, from the source to
the destination, until a word is stored in an address greater than or equal to
the effective address of the BLT.
Caution: BLT clobbers the specified AC. Don't use the BLT AC in
address calculation for the BLT, results will be random. If source
and destination overlap, remember that BLT moves the lowest source
word first. If the destination of the BLT includes the BLT AC, then
the BLT AC better be the last destination address.
2.2.4. Programming Examples Using Fullword Instructions
In these examples, several standard PDP-10 assembly languange notations are
used:
[] Square brackets enclose a "literal". The contents of the
brackets are assembled in another place, and the bracketed
expression is replaced by the address of that place.
Instruction Set Page 11
<> Angle brackets enclose an expression.
,, Separates left- and right-half quantities in a word. In
<a,,b>, a is right-adjusted in bits 0:17, and b is right-
adjusted in bits 18:35. If either quantity is too big, it is
truncated on the left.
() Parentheses enclose an expression which denotes an index
register.
. (pronounced "dot") Denotes the current location.
; Save all the accumulators:
movem 17, savac+17
movei 17, savac ; Source is 0, destination
blt 17, savac+16 ; is SAVAC.
; Restore all the accumulators:
movsi 17, savac ; Source is SAVAC,
blt 17, 17 ; destination is 0.
; Zero 100 words starting at TABLE.
setzm table
move t1, [table,,table+1] ; Source and
blt t1, table+77 ; destination overlap
; Move 77 words from TABLE thru TABLE+76 to TABLE+1 thru
; table+77: BLT can't be done here because the source and
; destination overlap. (See the description of POP.)
move t1, [400076,,table+76]
pop t1, 1(t1) ; Store TABLE+76 into
jumpl t1, .-1 ; table+77, etc.
2.3. Stack Instructions
These two instructions insert and remove full words in a pushdown list. The
address of the top of the list is kept in the right half of the AC referenced
by these instructions. The program may keep a control count in the left half
of the AC. There are also two subroutine calling instructions (PUSHJ and
POPJ) that use this same format pushdown list.
2.3.1. PUSH - Push on Stack
PUSH C(AC):=C(AC)+<1,,1>; C(CR(AC)):=C(E)
The specified accumulator is incremented by adding 1 to each half (in the KI10
and KL10 carry out of the right half is suppressed). If, as result of the
addition, the left half of the AC becomes positive, a pushdown overflow
condition results (but the instruction procedes to completion). The word
Instruction Set Page 12
addressed by the effective address is fetched and stored on the top of the
stack which is addressed by the right half of the (incremented) accumulator.
2.3.2. POP - Pop Stack
POP C(E):=C(CR(AC)); C(AC):=C(AC)-<1,,1>
POP undoes PUSH as follows: the word at the top of the stack (addressed by the
right half of the selected AC) is fetched and stored at the effective address.
Then the AC is decremented by subtracting 1 from both halves (in the KI10 and
KL10 carry out of bit 18 is suppressed). If the AC becomes negative as a
result of the subtraction a pushdown overflow results.
Often the accumulator used as the pushdown pointer is given the symbolic name
P. To initialize a pushdown pointer (e.g., for N words starting at PDLIST),
one might do the following:
move p, [iowd n, pdList]
where the IOWD pseudo op assembles -N,,PDLIST-1. Elsewhere in the program
should appear:
pdList: block n
which defines the symbolic label PDLIST and reserves N words following it for
the stack.
2.3.3. ADJSP - Adjust Stack Pointer
ADJSP CL(AC) := CL(AC)+E; CR(AC) := CR(AC)+E
E is added algebraically, with bit 18 acting as the sign bit, to both halves
of AC. If a negative E changes the count in AC left from positive or zero to
negative, or a positive E changes the count from negative to positive or zero,
set trap 2.
2.4. Halfword Instructions
The halfword class of instructions perform data transmission between one half
of an accumulator and one half of a memory location. There are sixty-four
halfword instructions. Each mnemonic begins with H and has four modifiers.
The first modifier specifies which half of the source word; the second
specifies which half of the destination. The third modifier specifies what to
do to the other half of the destination. The fourth modifier specifies the
source of data and the destination of the result.
Instruction Set Page 13
H halfword from |R right of source
|L left
|R right of destination
|L left
| no modification of other half
|Z zero other half
|O set other half to ones
|E sign extend source to other half
| from memory to AC
|I Immediate
|M from AC to memory
|S to self. If AC<>0 to AC also.
2.4.1. HR - Halfword Right
HRR CR(AC) := CR(E)
HRRI CR(AC) := E
HRRM CR(E) := CR(AC)
HRRS CR(E) := CR(E); if AC<>0 then CR(AC) := CR(E)
HRRZ C(AC) := 0,,CR(E)
HRRZI C(AC) := 0,,E
HRRZM C(E) := 0,,CR(AC)
HRRZS C(E) := 0,,CR(E); if AC<>0 then C(AC) := 0,,CR(E)
HRRO C(AC) := 777777,,CR(E)
HRROI C(AC) := 777777,,E
HRROM C(E) := 777777,,CR(AC)
HRROS C(E) := 777777,,CR(E);
if AC<>0 then C(AC) := 777777,,CR(E)
HRRE C(AC) := 777777*C18(E),,CR(E)
HRREI C(AC) := 777777*E18,,E
HRREM C(E) := 777777*C18(AC),,CR(AC)
HRRES C(E) := 777777*C18(E),,CR(E);
if AC<>0 then C(AC) := 777777*C18(E),,CR(E)
HRL CL(AC) := CR(E)
HRLI CL(AC) := E
HRLM CL(E) := CR(AC)
HRLS CL(E) := CR(E); if AC<>0 then CL(AC) := CR(E)
HRLZ C(AC) := CR(E),,0
HRLZI C(AC) := E,,0
HRLZM C(E) := CR(AC),,0
HRLZS C(E) := CR(E),,0;
if AC<>0 then C(AC) := CR(E),,0
Instruction Set Page 14
HRLO C(AC) := CR(E),,777777
HRLOI C(AC) := E,,777777
HRLOM C(E) := CR(E),,777777
HRLOS C(E) := CR(E),,777777;
if AC<>0 then C(AC) := CR(E),,777777
HRLE C(AC) := CR(E),,777777*C18(E)
HRLEI C(AC) := E,,777777*E18
HRLEM C(E) := CR(AC),,777777*C18(AC)
HRLES C(E) := CR(E),,777777*C18(E);
if AC<>0 then C(AC) := CR(E),,777777*C18(E)
2.4.2. HL Halfword Left
HLR CR(AC) := CL(E)
HLRI CR(AC) := 0
HLRM CR(E) := CL(AC)
HLRS CR(E) := CL(E); if AC<>0 then CR(AC) := CL(E)
HLRZ C(AC) := 0,,CL(E)
HLRZI C(AC) := 0
HLRZM C(E) := 0,,CL(AC)
HLRZS C(E) := 0,,CL(E);
if AC<>0 then C(AC) := 0,,CL(E)
HLRO C(AC) := 777777,,CL(E)
HLROI C(AC) := 777777,,0
HLROM C(E) := 777777,,CL(AC)
HLROS C(E) := 777777,,CL(E);
if AC<>0 then C(AC) := 777777,,CL(E)
HLRE C(AC) := 777777*C0(E),,CL(E)
HLREI C(AC) := 0
HRREM C(E) := 777777*C0(AC),,CL(AC)
HRRES C(E) := 777777*C0(E),,CL(E);
if AC<>0 then C(AC) := 777777*C0(E),,CR(E)
HLL CL(AC) := CL(E)
HLLI CL(AC) := 0
HLLM CL(E) := CL(AC)
HLLS CL(E) := CL(E); if AC<>0 then CL(AC) := CL(E)
HLLZ C(AC) := CL(E),,0
HLLZI C(AC) := 0
HLLZM C(E) := CL(AC),,0
HLLZS C(E) := CL(E),,0;
if AC<>0 then C(AC) := CL(E),,0
HLLO C(AC) := CL(E),,777777
HLLOI C(AC) := 0,,777777
HLLOM C(E) := CL(E),,777777
HLLOS C(E) := CL(E),,777777;
if AC<>0 then C(AC) := CL(E),,777777
Instruction Set Page 15
HLLE C(AC) := CL(E),,777777*C0(E)
HLLEI C(AC) := 0
HLLEM C(E) := CL(AC),,777777*C0(AC)
HLLES C(E) := CL(E),,777777*C0(E);
if AC<>0 then C(AC) := CL(E),,777777*C0(E)
2.5. Arithmetic Testing
2.5.1. AOBJ - Add One to Both Halves and Jump
The AOBJx (Add One to Both halves of AC and Jump) instructions allow forward
indexing through an array while maintaining a control count in the left half
of an accumulator. Use of AOBJN and AOBJP can reduce loop control to one
instruction.
AOBJN C(AC):=C(AC)+<1,,1>; if C(AC)<0 then PC:=E
AOBJP C(AC):=C(AC)+<1,,1>; if C(AC)>=0 then PC:=E
Example. Add 3 to N words starting at location TAB:
movsi 1, -N ; Initialize register 1 to -N,,0.
movei 2, 3 ; Register 2 gets the constant 3.
addm 2, tab(1) ; Add 3 to one array element.
aobjn 1, .-1 ; Increment both the index and the
; control. Loop until the ADDM has
; been done N times.
By the way, for the sake of consistency, AOBJN should have been called AOBJL
and AOBJP should have been called AOBJGE. However, they weren't.
2.5.2. JUMP
The JUMP instructions compare the selected accumulator to zero and jump (to
the effective address of the instruction) if the specified relation is true.
JUMP Jump never.
JUMPL if C(AC) < 0 then PC:=E
JUMPLE if C(AC) <= 0 then PC:=E
JUMPE if C(AC) = 0 then PC:=E
JUMPN if C(AC) <> 0 then PC:=E
JUMPGE if C(AC) >= 0 then PC:=E
JUMPG if C(AC) > 0 then PC:=E
JUMPA PC:=E
Instruction Set Page 16
2.5.3. SKIP
The SKIP instructions compare the contents of the effective address to zero
and skip the next instruction if the specified relation is true. If a
non-zero AC field appears, the selected AC is loaded from memory.
SKIP if AC<>0 then C(AC):=C(E); don't skip
SKIPL if AC<>0 then C(AC):=C(E);
if C(E) < 0 then skip
SKIPLE if AC<>0 then C(AC):=C(E);
if C(E) <= 0 then skip
SKIPE if AC<>0 then C(AC):=C(E);
if C(E) = 0 then skip
SKIPN if AC<>0 then C(AC):=C(E);
if C(E) <> 0 then skip
SKIPGE if AC<>0 then C(AC):=C(E);
if C(E) >= 0 then skip
SKIPG if AC<>0 then C(AC):=C(E);
if C(E) > 0 then skip
SKIPA if AC<>0 then C(AC):=C(E); skip
2.5.4. AOS - Add One and Skip
The AOS (Add One to memory and Skip) instructions increment a memory location,
compare the result to zero to determine the skip condition, If a non-zero AC
field appears then the AC selected will be loaded (with the incremented data).
AOS C(E) := C(E)+1; if AC<>0 then C(AC):=C(E)
AOSL C(E) := C(E)+1; if AC<>0 then C(AC):=C(E);
if C(E) < 0 then skip
AOSLE C(E) := C(E)+1; if AC<>0 then C(AC):=C(E);
if C(E) <= 0 then skip
AOSE C(E) := C(E)+1; if AC<>0 then C(AC):=C(E);
if C(E) = 0 then skip
AOSN C(E) := C(E)+1; if AC<>0 then C(AC):=C(E);
if C(E) <> 0 then skip
AOSGE C(E) := C(E)+1; if AC<>0 then C(AC):=C(E);
if C(E) >= 0 then skip
AOSG C(E) := C(E)+1; if AC<>0 then C(AC):=C(E);
if C(E) > 0 then skip
AOSA C(E) := C(E)+1; if AC<>0 then C(AC):=C(E);
skip
2.5.5. SOS - Subtract One and Skip
The SOS (Subtract One from memory and Skip) instructions decrement a memory
location, compare the result to zero to determine the skip condition, If a
non-zero AC field appears then the AC selected will be loaded (with the
decremented data).
Instruction Set Page 17
SOS C(E) := C(E)-1; if AC<>0 then C(AC):=C(E)
SOSL C(E) := C(E)-1; if AC<>0 then C(AC):=C(E);
if C(E) < 0 then skip
SOSLE C(E) := C(E)-1; if AC<>0 then C(AC):=C(E);
if C(E) <= 0 then skip
SOSE C(E) := C(E)-1; if AC<>0 then C(AC):=C(E);
if C(E) = 0 then skip
SOSN C(E) := C(E)-1; if AC<>0 then C(AC):=C(E);
C(E) <> 0 then skip
SOSGE C(E) := C(E)-1; if AC<>0 then C(AC):=C(E);
if C(E) >= 0 then skip
SOSG C(E) := C(E)-1; if AC<>0 then C(AC):=C(E);
if C(E) > 0 then skip
SOSA C(E) := C(E)-1; if AC<>0 then C(AC):=C(E);
skip
2.5.6. AOJ - Add One and Jump
The AOJ (Add One to AC and Jump) instructions increment the contents of the
selected accumulator. If the result bears the indicated relation to zero then
the instruction will jump to the effective address.
AOJ C(AC) := C(AC)+1;
AOJL C(AC) := C(AC)+1; if C(AC) < 0 then PC:=E
AOJLE C(AC) := C(AC)+1; if C(AC) <= 0 then PC:=E
AOJE C(AC) := C(AC)+1; if C(AC) = 0 then PC:=E
AOJN C(AC) := C(AC)+1; if C(AC) <> 0 then PC:=E
AOJGE C(AC) := C(AC)+1; if C(AC) >= 0 then PC:=E
AOJG C(AC) := C(AC)+1; if C(AC) > 0 then PC:=E
AOJA C(AC) := C(AC)+1; PC:=E
2.5.7. SOJ - Subtract One and Jump
The SOJ (Subtract One from AC and Jump) instructions decrement the contents of
the selected accumulator. If the result bears the indicated relation to zero
then the instruction will jump to the effective address.
SOJ C(AC) := C(AC)-1
SOJL C(AC) := C(AC)-1; if C(AC) < 0 then PC:=E
SOJLE C(AC) := C(AC)-1; if C(AC) <= 0 then PC:=E
SOJE C(AC) := C(AC)-1; if C(AC) = 0 then PC:=E
SOJN C(AC) := C(AC)-1; if C(AC) <> 0 then PC:=E
SOJGE C(AC) := C(AC)-1; if C(AC) >= 0 then PC:=E
SOJG C(AC) := C(AC)-1; if C(AC) > 0 then PC:=E
SOJA C(AC) := C(AC)-1; PC:=E
Instruction Set Page 18
2.5.8. CAM - Compare Accumulator to Memory
The CAM (Compare Accumulator to Memory) class compare the contents of the
selected accumulator to the contents of the effective address. If the
indicated condition is true, the instruction will skip. The CAM instruction
is suitable for arithmetic comparision of either fixed point quantities or
normalized floating point quantities. Needless to say, for the comparison to
be meaningful both C(AC) and C(E) should be in the same format (i.e., either
both fixed or both floating).
CAM no op (references memory)
CAML if C(AC) < C(E) then skip
CAMLE if C(AC) <= C(E) then skip
CAME if C(AC) = C(E) then skip
CAMN if C(AC) <> C(E) then skip
CAMGE if C(AC) >= C(E) then skip
CAMG if C(AC) > C(E) then skip
CAMA skip
2.5.9. CAI - Compare Accumulator Immediate
The CAI (Compare Accumulator Immediate) class compare the contents of the
selected accumulator to the effective address. If the indicated condition is
true, the instruction will skip. Note than an effective address is an 18 bit
quantity that is always considered to be positive.
CAI no op
CAIL if C(AC) < E then skip
CAILE if C(AC) <= E then skip
CAIE if C(AC) = E then skip
CAIN if C(AC) <> E then skip
CAIGE if C(AC) >= E then skip
CAIG if C(AC) > E then skip
CAIA skip
Skipping instructions can be combined to achieve ANDing or ORing of logical
expressions, e.g. the sequence
cail t1, 1
caile t1, 1000
jrst bad
is equivalent to
if C(t1) < 1 or C(t1) > 1000 then go to BAD
Instruction Set Page 19
2.6. Fixed Point Arithmetic
In positive numbers bit 0 is zero. Bit 1 is most significant; bit 35 is least
significant. Negative numbers are the two's complement of positive numbers.
Results (of ADD, SUB or IMUL) outside the range -2^35 to 2^35-1 will set
overflow ( PC bit 0).
2.6.1. ADD
ADD C(AC) := C(AC) + C(E)
ADDI C(AC) := C(AC) + E
ADDM C(E) := C(AC) + C(E)
ADDB C(AC) := C(AC) + C(E); C(E) := C(AC)
2.6.2. SUB - Subtract
SUB C(AC) := C(AC) - C(E)
SUBI C(AC) := C(AC) - E
SUBM C(E) := C(AC) - C(E)
SUBB C(AC) := C(AC) - C(E); C(E) := C(AC)
2.6.3. IMUL - Single-Word Multiply
The IMUL instructions are for multiplying numbers where the product is
expected to be representable as one word.
IMUL C(AC) := C(AC) * C(E)
IMULI C(AC) := C(AC) * E
IMULM C(E) := C(AC) * C(E)
IMULB C(AC) := C(AC) * C(E); C(E) := C(AC)
2.6.4. IDIV - Single-Word Divide
The IDIV instructions are for divisions in which the dividend is a one word
quantity. AC+1 signifes the quantity (AC+1 modulo 20 octal). If the divisor
is zero set overflow and no divide; don't change AC or memory operands. The
remainder will have the same sign as the dividend.
IDIV C(AC) := C(AC) / C(E); C(AC+1) := remainder
IDIVI C(AC) := C(AC) / E; C(AC+1) := remainder
IDIVM C(E) := C(AC) / E
IDIVB C(AC) := C(AC) / C(E); C(AC+1) := remainder;
C(E) := C(AC)
Instruction Set Page 20
2.6.5. MUL - Multiply
The MUL instructions produce a double word product. A double word integer has
70 bits of significance. Bit 0 of the high order word is the sign bit. In
data, Bit 0 of the low order word is ignored by the hardware. In results, bit
0 of the low word is the same as bit 0 in the high word. MUL will set
overflow if both operands are -2^35.
MUL C(AC AC+1) := C(AC) * C(E)
MULI C(AC AC+1) := C(AC) * E
MULM C(E) := high word of product of C(AC) * C(E)
MULB C(AC AC+1) := C(AC) * C(E); C(E) := C(AC)
2.6.6. DIV - Divide
The DIV instructions are for divisions in which the dividend is a two word
quantity (such as produced by MUL). If C(AC) is greater than the memory
operand then set overflow and no divide.
DIV C(AC) := C(AC AC+1) / C(E); C(AC+1) := remainder
DIVI C(AC) := C(AC AC+1) / E; C(AC+1) := remainder
DIVM C(E) := C(AC AC+1) / E
DIVB C(AC) := C(AC AC+1) / C(E); C(AC+1) := remainder;
C(E) := C(AC)
2.7. Double Word Move Instructions (KI10 and KL10)
There are four double word move instructions. These are suitable for
manipulating KI10 and KL10 double precision floating point numbers, and for
KL10 double precision integers.
DMOVE C(AC AC+1) := C(E E+1)
DMOVEM C(E E+1) := C(AC AC+1)
DMOVN C(AC AC+1) := -C(E E+1)
DMOVNM C(E E+1) := -C(AC AC+1)
Note that the DMOVN and DMOVNM are NOT to be used for KA10 double
precision floating point numbers!
If a program is written that may be have to be run on a KA10, the use of all
double word instructions should be avoided.
2.8. Double Precision Integer Arithmetic (KL10 only)
There are four instructions for double precision integer arithmetic. None of
these instructions have any modifier: they all operate on double (or
quadruple) accumulators and double words in memory with results to double (or
quadruple) accumulators.
Instruction Set Page 21
The format for a double word integer is the same as that produced by MUL,
i.e., a 70 bit integer in two's complement, with bit 0 of the most significant
word is the sign; in operands, bit 0 of the low order word is ignored. A
quadruple word has 140 bits; bit 0 of the most significant word is the sign;
in operands, bit 0 in all other words is ignored. In double (and quadruple)
arithmetic results bit 0 of the low order word(s) is stored with the same
value as bit 0 of the high order word.
DADD C(AC AC+1) := C(AC AC+1) + C(E E+1)
DSUB C(AC AC+1) := C(AC AC+1) - C(E E+1)
DMUL C(AC AC+1 AC+2 AC+3) := C(AC AC+1) * C(E E+1)
DDIV C(AC AC+1) := C(AC AC+1 AC+2 AC+3) / C(E E+1)
C(AC+2 AC+3) := remainder
2.9. Floating Point Arithmetic
Single precision floating point numbers are represented in one 36 bit word as
follows:
Bit 0 00000000 011111111112222222222333333
Position 0 12345678 901234567890123456789012345
______________________________________
| | | |
|S| Exp | Fraction |
|_|________|___________________________|
If S is zero, the sign is positive. If S is one the sign is negative and the
word is in two's complement format. The fraction is interpreted as having a
binary point between bits 8 and 9. The exponent is a power of 2 represented
in excess 200 (octal) notation. In a normalized floating point number bit 9
is different from bit 0, except in a negative number bits 0 and 9 may both be
one if bits 10:35 are all zero. A floating point zero is represented by a
word with 36 bits of zero. Floating point numbers can represent numbers with
magnitude within the range 0.5*2^-128 to (1-2^-27)*2^127, and zero.
A number in which bit 0 is one and bits 9-35 are zero can produce an incorrect
result in any floating point operation. Any word with a zero fraction and
non-zero exponent can produce extreme loss of precision if used as an operand
in a floating point addition or subtraction.
In KI10 (and KL10) double precision floating point, a second word is included
which contains in bits 1:35 an additional 35 fraction bits. The additional
fraction bits do not significantly affect the range of representable numbers,
rather they extend the precision.
The KA10 lacks double precision floating point hardware, but there are several
instructions by which software may implement double precision. These
instructions are DFN, UFA, FADL, FSBL, FMPL, and FDVL. Users of the KL10 are
strongly advised to avoid using these intructions.
In the PDP-6 floating point is somewhat different. Consult an wizard.
Instruction Set Page 22
F floating
|AD add | result to AC
|SB subtract |R rounded |I Immediate. result to AC
|MP multiply | |M result to memory
|DV divide | |B result to memory and AC
|
|
| no rounding | result to AC
|L Long mode
|M result to memory
|B result to memory and AC
|AD add
DF double floating |SB subtract
|MP multiply
|DV divide
Note: In immediate mode, the memory operand is <E,,0>. In long
mode (except FDVL) the result appears in AC and AC+1. In FDVL the AC
operand is in AC and AC+1 and the quotient is stored in AC with the
remainder in AC+1.
2.10. Other Floating Point Instructions
2.10.1. FSC - Floating Scale
FSC (Floating SCale) will add E to the exponent of the number in AC and
normalize the result. One use of FSC is to convert an integer in AC to
floating point (but FLTR, available in the KI and KL is better). To use FSC
to float an integer, set E to 233 (excess 200 and shift the binary point 27
bits). The integer being floated must not have more than 27 significant bits.
FSC will set AROV and FOV if the resulting exponent exceeds 127. FXU (and
AROV and FOV) will be set if the exponent becomes smaller than -128.
2.10.2. FIX - Convert Floating Point to Integer
FIX will convert a floating point number to an integer. If the exponent of
the floating point number in C(E) is greater than (decimal) 35 (which is octal
243) then this instruction will set AROV and not affect C(AC). Otherwise,
convert C(E) to fixed point by the following procedure: Move C(E) to AC,
copying bit 0 of C(E) to bits 1:8 of AC (sign extend). Then ASH AC by X-27
bits (where X is the exponent from bits 1:9 of C(E) less 200 octal). FIX will
truncate towards zero, i.e., 1.9 is fixed to 1 and -1.9 is fixed to -1.
Instruction Set Page 23
2.10.3. FIXR - Fix and Round
FIXR (Fix and round) will convert a number to an integer by rounding. If the
exponent of the floating point number in C(E) is greater than (decimal) 35
(which is octal 243) then this instruction will set AROV and not affect C(AC).
Otherwise, convert C(E) to fixed point by the following procedure: Move C(E)
to AC, copying bit 0 of C(E) to bits 1:8 of AC (sign extend). Then ASH AC by
X-27 bits (where X is the exponent from bits 1:9 of C(E) less 200 octal). If
X-27 is negative (i.e., right shift) then the rounding process will consider
the bits shifted off the right end of AC. If AC is positive and the discarded
bits are >=1/2 then 1 is added to AC. If AC is negative and the discarded
bits are >1/2 then 1 is added to AC. Rounding is always in the positive
direction: 1.4 becomes 1, 1.5 becomes 2, -1.5 becomes -1, and -1.6 becomes
-2.
2.10.4. FLTR - Float and Round
FLTR (FLoaT and Round) will convert C(E), an integer, to floating point and
place the result in AC. The data from C(E) is copied to AC where its is
arithmetic shifted right 8 places (keeping the bits that fall off the end) and
the exponent 243 is inserted in bits 1:8. The resulting number is normalized
until bit 9 is significant (normalization may result in some or all of the
bits that were right shifted being brought back into AC). Finally, if any of
the bits that were right shifted still remain outside the AC the result is
rounded by looking at the bit to the right of the AC.
2.11. Shift Instructions
The following instructions shift or rotate the AC or the formed by AC and
AC+1. The number of places to shift is specified by the effective address
which is considered to be a signed number modulo 256 in magnitude. That is,
the effective shift is the number composed of bit 18 (the sign) of the
effective address and bits 28:35 of the effective address. If E is positive,
a left shift occurs. If E is negative a right shift occurs.
LSH Logical Shift. C(AC) is shifted as specified by E. Zero bits
are shifted into the AC.
LSHC Logical Shift Combined. C(AC AC+1) is shifted as a 72 bit
quantity. Zero bits are shifted in.
ASH Arithmetic Shift. Bit 0 is not changed. In a left shift zero
bits are shifted into the right end of AC. In a left shift,
if any bit of significance is shifted out of bit 1, AROV
( overflow) is set. In a right shift, bit 0 is shifted into
bit 1.
ASHC Arithmetic Shift Combined. AC bit 0 is not changed. If E is
non zero, AC bit 0 is copied to AC+1 bit 0. C(AC AC+1) is
shifted as a 70 bit quantity. In a left shift zero bits are
shifted into the right end of AC+1. In a left shift, if any
bit of significance is shifted out of AC bit 1 then AROV is
set. In a right shift AC bit 0 is shifted into AC bit 1.
Instruction Set Page 24
ROT Rotate. The 36 bit C(AC) is rotated. In a left rotate bits
shifted out of bit 0 are shifted into bit 35. In a right
rotate, Bit 35 is shifted into bit 0.
ROTC Rotate Combined. AC and AC+1 are rotated as a 72 bit
quantity. In a left rotate AC bit 0 shifts into AC+1 bit 35
and AC+1 bit 0 shifts into AC bit 35. In a right rotate, AC+1
bit 35 shifts into AC bit 0, etc.
2.12. Byte Instructions
In the PDP-10 a "byte" is some number of contiguous bits within one word. A
byte pointer is a word that describes the byte. There are three parts to the
description of a byte: the word (i.e., address) in which the byte occurs, the
position of the byte within the word, and the length of the byte.
A byte pointer has the following format:
Bit 000000 000011 1 1 1111 112222222222333333
Position 012345 678901 2 3 4567 890123456789012345
_________________________________________
| | | | | | |
| POS | SIZE |U|I| X | Y |
|______|______|_|_|____|__________________|
- POS is the byte position: the number of bits remaining in the word
to the right of the byte.
- SIZE is the byte size in bits.
- The U field is reserved for future use and must be zero.
- I, X, and Y are the same as in an instruction.
2.12.1. LDB - Load Byte
The contents of the effective address of the LDB instruction is interpreted as
a byte pointer. The byte described there is loaded, right adjusted, into the
AC. The rest of the AC is cleared.
2.12.2. DPB - Deposit Byte
The contents of the effective address of the DPB instruction is interpreted as
a byte pointer. The byte described there is deposited from the byte of the
same size at the right end of the AC. AC and the remainder of the word into
which the byte is deposited are left unchanged.
Instruction Set Page 25
2.12.3. IBP - Increment Byte Pointer
The AC field must be zero. The contents of the effective address are fetched.
The POS field is changed by subtracting the size field from it. If the result
of the subtraction is greater than or equal to zero, store the difference in
the POS field. If the difference is negative, add 1 to the Y field (in the
KA10 and PDP-6 if Y contains 777777 then this will carry into the X field; in
the KI10 and KL10 the carry out is suppressed) and set POS field to 44-SIZE
(44 is octal). The effect of this is to modify the byte pointer to address
the next byte (of the same size) that follows the byte addressed by the
original pointer, skipping over any bits that may be left over at the end of a
word (when the bytesize does not divide evenly into the wordsize, 36).
2.12.4. ILDB - Increment and Load Byte
Increment the byte pointer contained at the effective address. Then perform a
LDB function using the updated byte pointer.
2.12.5. IDPB - Increment and Deposit Byte
Increment the byte pointer contained at the effective address. Then perform a
DPB function using the updated byte pointer.
2.12.6. ADJBP - Adjust Byte Pointer
Fetch the byte pointer at the effective address, increment or decrement it by
the number of bytes specified in the AC, then place the adjusted byte pointer
in the AC. The original byte pointer is unchanged.
2.12.7. POINT - Construct a Byte Pointer
For convenience, the Macro assembler (and Fail) has a pseudo op for creating
byte pointers. The POINT pseudo op has three parameters: size, address, and
position. In the POINT pseudo op, the position argument specifies the bit
number of the right most bit in the byte. If the position field is omitted,
bit number "-1" is assumed (this assembles 44 in the POS field) which doesn't
address any byte, but which, when incremented once, will address the first
byte in the specified word.
POINT 7, 100(1) 440701,,100
POINT 36, @2000,35 004420,,2000
POINT 7, FOO 440700,,foo
Instruction Set Page 26
2.13. Logical Testing and Modification
The TEST instructions are for testing and modifying bits in an accumulator.
There are 64 instructions. Each mnemonic begins with a T and is followed by
three modifiers.
Test accumulator
|R right half immediate
|L left half immediate
|D direct mask
|S swapped mask
|N no modification
|Z zero selected bits
|O set selected bits to One
|C complement selected bits
| never skip
|N skip unless all selected bits are zero
|E skip if all selected bits are zero
|A skip always
The test operation considers two 36 bit quantities. One of these is the
contents of the selected AC. The other quantity, called the mask, depends on
the first modifier letter. For R the mask is <0,,E>; for L it is <E,,0>. For
D the mask is C(E), and for S the mask is CS(E), the swapped contents of E.
- If the skip condition N is specified, then the test instruction will
skip if the AND of the mask and the AC operand is Not equal to zero.
- If the skip condition E is specified, then the test instruction will
skip if the AND of the mask and the AC operand is Equal to zero.
- If the modification code Z appears then bits that are one in the
mask are made zero in the AC.
- If the modification code O appears then bits that are one in the
mask are made one in the AC.
- If the modification code C appears then bits that are one in the
mask are complemented in the AC.
Note that the skip condition is determined on the basis of the contents of the
AC before it is modified.
The principle use for the Test instructions is in testing and modifying single
bit flags that are kept in an accumulator.
2.14. Boolean Logic
There are 16 possible boolean functions of 2 variables. The PDP-10 has 16
instruction classes (each with 4 modifiers) that perform these operations.
Each boolean function operates on the 36 bits of AC and memory as individual
bits.
Instruction Set Page 27
Table of the Boolean functions
C(AC) 0 0 1 1
C(E) 0 1 0 1
SETZ 0 0 0 0 SET to Zero
AND 0 0 0 1 AND
ANDCM 0 0 1 0 AND with Complement of Memory
SETA 0 0 1 1 SET to AC
ANDCA 0 1 0 0 AND with Complement of AC
SETM 0 1 0 1 SET to Memory
XOR 0 1 1 0 eXclusive OR
IOR 0 1 1 1 Inclusive OR
ANDCB 1 0 0 0 AND with Complements of Both
EQV 1 0 0 1 EQuiValence
SETCM 1 0 1 0 SET to Complement of Memory
ORCA 1 0 1 1 OR with Complement of Memory
SETCA 1 1 0 0 SET to Complement of AC
ORCA 1 1 0 1 OR with Complement of AC
ORCB 1 1 1 0 OR with Complements of Both
SETO 1 1 1 1 SET to One
Each of the 16 instructions above have four modifiers that specify where to
store the result. No modifier means result to AC. Modifier I means
Immediate: the memory data is <0,,E> and the result goes to AC. M as a
modifier means result should be stored in memory. B means store the results
in both memory and AC.
2.15. PC Format
JSR, JSP, and PUSHJ all store a full word that contains the PC (Program
Counter) and various flags.
The format of a PC word is:
0 0 0 0 0 0 0 0 0 0 1 1 1 11111 112222222222333333
0 1 2 3 4 5 6 7 8 9 0 1 2 34567 890123456789012345
__________________________________________________
|A|C|C|F|F|U|I|P|A|T|T|F|D| | |
|R|R|R|O|P|S|O|U|F|R|R|X|C|00000| PC |
|O|Y|Y|V|D|E|T|B|I|A|A|U|K| | |
|V|0|1| | |R| |L| |P|P| | | | |
| | | | | | | | | |2|1| | | | |
|_|_|_|_|_|_|_|_|_|_|_|_|_|_____|__________________|
AROV, ARithmetic OVerflow, is set by any of the following:
- A single instruction has set one of CRY0 or CRY1 without setting
them both.
- An ASH or ASHC has left shifted a significant bit out of AC bit 1.
- A MULx instruction has multiplied -2^35 by itself.
Instruction Set Page 28
- A DMUL instruction has multiplied -2^70 by itself.
- An IMULx instruction has produced a product less than -2^35 or
greater than 2^35-1.
- A FIX or FIXR has fetched an operand with exponent greater than 35.
- FOV (Floating Overflow) has been set.
- DCK (Divide ChecK) has been set.
- CRY0, CaRrY 0, if set without CRY1 being set will set AROV. This
indicates any of the following conditions:
1. An ADDx has added two negative numbers with sum less than
-2^35.
2. A SUBx has subtracted a positive number from a negative number
and produced a result less than -2^35.
3. A SOSx or SOJx has decremented -2^35.
- If CRY0 and CRY1 are both set, this indicates that one of the
following non-overflow events has occurred:
1. In ADDx both summands were negative, or their signs differed
and the postive one was greater than or equal to the magnitude
of the negative summand.
2. In SUBx the sign of both operands was the same and the AC
operand was greater than or equal to the memory operand, or
the AC operand was negative and the memory operand was
positive.
3. An AOJx or AOSx has incremented -1.
4. SOJx or SOS has decremented a nonzero number other than -2^35.
5. A MOVNx has negated zero.
- CRY1, CaRrY 1, if set without CRY0 being set will set AROV. This
indicates any of the following conditions:
1. An ADDx has added two positive number with a sum greater than
2^35-1.
2. A SUBx has subtracted a negative number from a positive number
to form a difference greater than 2^35-1.
3. An AOSx or AOJx instruction has incremented 2^35-1.
4. A MOVNx or MOVMx has negated -2^35.
5. A DMOVNx has negated -2^70
The following conditions are also indicated in the PC word:
- FOV, Floating point OVerflow, is set by any of:
Instruction Set Page 29
1. In a floating point instruction other than FLTR, DMOVNx, or
DFN the exponent of the result exceeds 127.
2. FXU (Floating eXponent Underflow) has been set.
3. DCK ( Divide ChecK) has been set by FDVx, FDVRx, or DFDV.
- FPD, First Part Done, is set when the processor responds to a
priority interrupt, after having completed the first part of a two
part instruction (e.g., ILDB). This flag is not usually of interest
to the programmer.
- USER is set while the processor is in user mode. In user mode,
various instruction and addressing restrictions are in effect.
- IOT, User IN-Out mode, (also called IOT User), is a special mode in
which some of the user mode instruction (but not addressing)
restrictions are removed. In this mode a user program may perform
the hardware I/O instructions.
- PUBL, Public mode, signifies that the processor is in user public
mode or in exec supervisor mode [KI10, KL10 only].
- AFI, Address Failure Inhibit, if this flag is set, address break is
inhibited for during the execution of the next instruction [KI10,
KL10 only].
- TRAP2 - if bit 10 is not also set, pushdown overflow has occurred.
If traps are enabled, setting this flag immediately causes a trap.
At present no hardware condition sets both TRAP1 and TRAP2
simultaneously. [KI10 KL10 only]
- TRAP1 - if bit 9 is not also set, arithemetic overflow has occurred.
If traps are enabled, setting this flag immediately causes a trap.
At present no hardware condition sets both TRAP1 and TRAP2
simultaneously. [KI10 KL10 only]
- FXU, Floating eXponent Underflow, is set to signify that in a
floating instruction other than DMOVNx, FLTR, or DFN, the exponent
of the result was less than -128 and AROV and FOV have been set.
- DCK, Divide ChecK, signifies that one of the following conditions
has set AROV:
1. In a DIVx the high order word of the dividend was greater than
or equal to the divisor.
2. In an IDIVx the divisor was zero.
3. In an FDVx, FDVRx, or DFDV, the divisor was zero, or the
magnitude of the dividend fraction was greater than or equal
to twice the magnitude of the divisor fraction. In either
case, FOV is also set.
Bits 13 through 17 of the PC word are always zero to facilitate the use of
indirect addressing to return from a subroutine.
Bits 18 through 35 store an address that is one greater than the address of
Instruction Set Page 30
the instruction that stores the PC. Thus, the PC word points at the
instruction immediately following the subroutine call.
2.16. Program Control
2.16.1. JSR - Jump to Subroutine
JSR C(E):=<flags,,PC>; PC:=E+1
JSR, Jump to SubRoutine, stores the PC in the word addressed by the effective
address and jumps to the word following the word where the PC is stored. This
is the only PDP-10 instruction that stores the PC and flags without modifying
any ACs; however, it is non-reentrant, so PUSHJ is favored in most cases. The
usual return from a subroutine called by a JSR is via JRST (or JRST 2,)
indirect through the PC word. (See JRST)
2.16.2. JSP - Jump & Save PC
JSP C(AC):=<flags,,PC>; PC:=E
JSP, Jump and Save PC, stores the PC and flags in the selected accumulator and
jumps.
2.16.3. JSA - Jump and Save Accumulator
JSA C(E):=C(AC); C(AC):=<E,,PC>; PC:=E+1
JSA, Jump and Save AC, stores the AC in word addressed by the effective
address. Then the left half of the AC is set to the effective address and the
right half of AC is set to the return PC. Then the PC is set to one greater
than the effective address. The JRA instruction unwinds this call. The
advantage of this call is that a routine may have multiple entry points (which
is difficult to do with JSR) and it's easy to find (and later to skip over)
arguments that follow the calling instruction (which is possible to do with
PUSHJ, but not quite so convenient). Among the disadvantages of this call is
that it is not reentrant, and it doesn't save flags.
2.16.4. JRA - Jump and Restore Accumulator
JRA C(AC):=C(CL(AC)); PC:=E
JRA, Jump and Restore AC, is the return from JSA. If, e.g., a subrountine is
called with JSA AC, then the return is made by: JRA AC,(AC).
Instruction Set Page 31
2.16.5. PUSHJ - Push on stack and Jump
PUSHJ C(AC):=C(AC)+<1,,1>; C(CR(AC)):=<flags,,PC>;
PC:=E
PUSHJ (PUSH return address and Jump) is like PUSH except the data that is
pushed onto the top of the stack is the PC and flags word. The PC that is
stored is the PC of the instruction that follows the PUSHJ. Then the PC is
set to the effective address of the instruction. Pushdown overflow results if
the AC becomes positive when it is incremented.
2.16.6. POPJ - Pop stack and Jump
POPJ PC:=CR(CR(AC)); C(AC):=C(AC)-<1,,1>
POPJ (POP return address and Jump) undoes PUSHJ. The right half of the word
at the top of the stack is loaded into the PC (the flags are unchanged). Then
the stack pointer is decremented as in POP. The effective address of POPJ is
ignored. Pushdown overflow obtains if the AC becomes negative as a result of
the subtraction.
2.16.7. Programming Hints Using PUSHJ and POPJ
If a subroutine called by PUSHJ AC, wants to skip over the instruction
following the PUSHJ, the following sequence accomplishes that result:
aos (ac) ; AC better be nonzero.
popj ac,
If you must restore the flags that PUSHJ saved, the following sequence should
be used instead of POPJ:
pop ac, (ac) ; Adjust the stack
jrst 2, ; Restore flags and PC from
; old stack top.
2.16.8. JRST - Jump and Restore
JRST, Jump and ReSTore, is an unconditional jump instruction. In JRST, the AC
field does not address an accumulator. Instead, the AC is decoded to signify
various things.
JRST PC:=E
JRST 2, PC:=E; flags are restored (see text)
JRST 10, PC:=E; Dismiss current priority interrupt
JRST 12, PC:=E; restore flags and dismiss priority
interrupt
Instruction Set Page 32
If the AC field is zero, only a jump occurs. JRST is everyone's favorite
unconditional jump instruction (the only other one is JUMPA which is more
typing, also, on older machines JUMPA was slower than JRST).
JRST 2, (i.e., JRST with AC field set to 2) signifies jump and restore flags.
(The assembler also recognizes the mnemonic JRSTF for JRST 2,). If
indirection is used in JRSTF, then the flags are restored from the last word
fetched in the address calculation. If indexing is used with no indirection,
the flags are restored from the left half of the specified index register. If
neither indexing nor indirection is used in the address calculation the flags
are restored from the left half of the JRSTF itself! In a user mode program
JRSTF cannot clear USER nor can it set IOT User (it can however, clear IOT
User). JRST 4, JRST 10, and JRST 12 are illegal in user mode and are trapped
as UUOs.
2.16.9. JFCL - Jump on Flag and Clear
The JFCL instruction is another case in which the AC field is decoded to
modify the instruction. The AC field selects the four flags in PC bits 0
through 3. PC bits 0 to 3 correspond to bits 9 to 12 in the JFCL instruction.
JFCL will jump if any flag selected by the AC field is a 1. All flags
selected by the AC field are set to zero.
JFCL 0, since it selects no PC bits, is a no-op.
JFCL 17, will clear all flags, and will jump if any of AROV, CRY0,
CRY1, or FOV are set.
JFCL 1, (JFOV) jumps if FOV is set and clears FOV.
JFCL 10, (JOV) jumps if AROV is set and clears AROV.
2.16.10. XCT - Execute
XCT, the eXeCuTe instruction, fetches the word addressed by the effective
address and executes that word as an instruction. In the case of XCTing an
instruction that stores a PC, the PC that is stored is the address of the
instruction that follows the XCT. If the executed instruction skips, then
that skip is relative to the XCT. The AC field of the XCT should be zero.
[In monitor mode a nonzero AC field in an XCT is significant.]
The XCT instruction can be used to acheive the effect of a CASE statement, as
in the following example:
xct @[ call foo
move q1, p1
jfcl
aos q1 ](t1)
where t1 contains the case index, which should have a value (in this case)
between 0 and 3.
Instruction Set Page 33
2.16.11. JFFO - Jump if Find First One
JFFO tests the selected AC. If C(AC)=0 then set C(AC+1) to zero and execute
the next instruction. If C(AC)<>0 then set C(AC+1) to the count of the number
of zero bits in C(AC) to the left of the first one bit and jump to the
effective address. C(AC) is unchanged.
2.17. References
The following manual presents the instruction set of the PDP-10/DECSYSTEM-20
in complete detail:
DECsystem-10/DECSYSTEM-20 Hardware Reference Manual, Volume I,
Central Processor, EK-10/20-HR-001, Digital Equipment Corporation
(1978).
Historical information can be found in:
Bell, et al., "The Evolution of the DECsystem-10", CACM Jan 1978.
Macro Page 34
3. The DECSYSTEM-20 Macro Assembler
3.1. Introduction
This chapter presents excerpts from the DEC Macro-20 Reference
Manual. Certain advanced (or rarely used) features - mainly those
dealing with storage allocation and polish fixups - have been omitted;
see the actual manual if you must have them. Unfortunately, the Macro
manual does not present the material in a tutorial fashion; this
rendition of it is not much better than the original in that respect,
although examples have been added here and there, and explanations are
a little more thorough. Given the absence of a good tutorial, the
best approach to teaching yourself Macro is to read through this
chapter from beginning to end to get an idea of what kinds of things
Macro does, and what its syntax is, and then to study some
well-written Macro programs.
At the time of this writing (3 July 1980), Macro suffers from
certain limitations traceable to its origins in Tops-10 (PDP-6,
really): symbols are limited to 6 characters in length, and input
(.MAC) and output (.REL, usually) files are limited to 6 characters in
the filename and 3 in the extension (file type).
Macro is the symbolic assembler program for the DECSYSTEM-20. The assembler
reads a file of Macro statements and composes relocatable binary machine
instruction code suitable for loading by Link, the system's linking loader.
Macro is a statement-oriented language; statements are in free format and are
processed in two passes. In processing statements, the assembler:
1. Interprets machine instruction mnemonics.
2. Accepts symbol definitions.
3. Interprets symbols.
4. Interprets pseudo-ops.
5. Accepts macro definitions.
6. Expands macros on call.
7. Assigns memory addresses.
8. Generates a relocatable binary program file ( .REL file) for input
to Link.
9. Optionally generates a program listing file showing source
statements, the corresponding binary code, and any errors found.
10. Optionally generates a universal ( .UNV) file that can be searched
during other assemblies.
The following conventions are used throughout this chapter:
1. All numbers in the examples are octal unless otherwise noted.
Macro Page 35
2. All numbers in the text are decimal unless otherwise noted.
3. The name of the assembler, Macro, is capitalized; references to
user-defined macros are in lower case.
3.2. Elements of Macro
The character set recognized in Macro statements includes all ASCII
alphanumeric characters and 28 special characters (ASCII 40 through 137
(octal)). Lowercase letters are not distinguished from uppercase letters.
Macro recognizes several ASCII control codes including horizontal tab (^I),
linefeed (^J), formfeed (^L), carriage-return (^M), and control-underscore
(^_). Macro accepts any ASCII character in quoted text, or in text argument
to the ASCII and ASCIZ pseudo-ops. The line continuation character, ^_, is
always effective. Delimiters for certain pseudo-ops (such as ASCII, ASCIZ,
and COMMENT) can be any nonblank, nontab ASCII character.
A Macro program consists of statements made up of Macro language elements.
Separated into general types, these are:
1. Special characters.
2. Numbers.
3. Literals.
4. Symbols.
5. Expressions.
6. Macro-defined mnemonics.
7. Pseudo-ops.
8. Macros.
The format of a Macro statement is discussed later.
3.2.1. Special Characters
Some characters and combinations of characters have special interpretations.
These interpretations apply only in the contexts described. In particular,
they do not apply within comment fields or text strings. Uparrow (^) is to be
taken literally, e.g. ^B means the uparrow character followed by a B, not
control-B.
Char(s) (Form) Context and Interpretation
B (mBn) Between 2 integer expressions, causes the binary
representation of m to be placed with rightmost bit at bit n
(decimal).
^B (^Bn) Before an integer expression, shows that n is a binary
Macro Page 36
(base 2) number.
^D (^Dn) Before an integer expression, shows that n is a decimal
number.
E (fE+n,fE-n,fEn) Between a floating-point decimal number and a signed decimal
integer, multiplies f by the +nth power of 10 (decimal).
^O (^On) Before an integer expression, shows that n is an octal number.
: (sym:) After a symbol, shows that sym is a label, i.e. that its value
is to become the current value of the location counter.
:: (sym::) After a symbol, shows that sym is a global INTERNAL label.
; (;text) Before the end of a line, shows that text is a comment.
;; (;;text) Before end of line (usually in a macro definition), shows that
text is a comment to be printed in the macro definition but
not at call, i.e. in macro expansion.
. (.) As an expression, is replaced by the current value of the
location counter.
, (,) Among numbers and symbols, delimits operands, accumulator,
arguments. In a macro call, delimits a null argument.
,, (lhw,,rhw) Between two expressions, delimits left halfword from right
halfword.
! (A!B) Between two expressions, generates the logical inclusive OR of
A and B.
^! (A^!B) Between two expressions, generates the logical exclusive OR of
A and B.
& (A&B) Between two expressions, generates the logical AND of A and
B.
^- (^-A) Before an expression, generates the logical complement of A
(NOT A).
* (A*B) Between two expressions, generates the product of A and B.
/ (A/B) Between two expressions, generates the quotient of A by B.
+ (A+B) Between two expressions, generates the sum of A and B.
- (A-B) Between two expressions, generates the difference of A and B.
- (-A) Before an expression, generates the two's complement of the
value of A.
" ("text") In pairs around text, shows that text is a 7-bit ASCII string,
to be right justified in a field of five characters.
' ('text') In pairs around text, shows that text is a SIXBIT string, to
be right justified in a field of six characters.
Macro Page 37
' (arg'text, text'arg) Adjoing a dummy argument in the body of a macro
definition, concatenates the value of the argument to the text
during macro expansion.
\ (\expr) Prefixed to an expression in a macro call, directs that the
argument passed be the string for the ASCII value of expr in
the current radix.
\' (\'expr) Prefixed to an expression in a macro call, directs that the
argument passed be the string whose SIXBIT code is the value
of expr.
\" (\"expr) Prefixed to an expression in a macro call, directs that the
argument passed be the string whose ASCII code is the value of
expr.
^_ (Control-underscore, not uparrow underscore) before a CRLF,
continues its argument to the next line. Does not operate
across end-of-macro.
_ (A_B) Between two expressions, shifts the binary representation of A
to the left B positions (if B is negative, shift is to the
right).
@ (@address) Prefixed to an address, sets bit 13 of the instruction word,
indicating indirect addressing.
% (%arg) As the first character of a dummy argument in a macro
definition, directs that %arg be replaced by a created symbol
during macro expansion; Macro will substitute a different
symbol for it on each invocation of the macro.
() Encloses index field, encloses dummy arguments in macro
definition or parameters in a macro invocation, quotes
characters for macro argument handling, swaps the two halves
of a value.
<> Nests expressions, encloses conditional assembly code,
encloses code in REPEAT, IRP, and IRPC pseudo-ops, encloses
macro body in DEFINE pseudo-op, quotes characters for macro
argument handling, forces evaluation of a symbol.
[] delimits literals (causing the contents of the brackets to be
moved to the literal pool, and the bracketed expression to be
replaced by the location of its contents); delimits argument
in ARRAY, .COMMON, and OPDEF pseudo-ops; quotes characters for
macro argument handling.
= (sym=expr) Between symbol and expression, assigns the value of expr to
sym.
=: (sym=:) Between symbol and expression, assigns the value of expr to
sym and declares sym to be global INTERNAL.
Macro Page 38
3.2.2. Numbers
The two properties of numbers that are important in Macro are
1. The radix (base) in which the number is written.
2. How the number should be placed in memory.
You can control the interpretation of these properties by using pseudo-ops or
special characters to indicate your choices.
3.2.2.1. Integers
Macro stores an integer in its binary form, right justified in bits 1 to 35 of
its storage word. If you use a sign, place it immediately before the integer
(if you omit the sign, the integer is assumed to be positive). For a negative
number, Macro first forms its absolute value in bits 1 to 35, then replaces it
by its two's complement. Therefore a positive integer is stored with 0 in bit
0, while a negative integer has 1 in bit 0.
The largest positive integer that Macro can store is 377777 777777 (octal);
the smallest (most negative) is 400000 000000 (octal).
3.2.2.2. Radix
The initial implicit radix for a Macro program is octal (base 8). The
integers you use in your program will be interpreted as octal unless you
indicate otherwise. You can change the radix to any base from 2 to 10 by
using the RADIX pseudo-op. The new radix will be in effect until you change
it again.
Without changing the prevailing radix, you can write a particular integer in
binary, octal, or decimal. To do this, prefix the integer with ^B for binary,
^O for octal, ^D for decimal. The indicated radix applies only to the single
integer immediately following it.
A single-digit number is always interpreted as radix 10. Thus 9 is seen as
decimal 9, even if the current radix is 8.
For example, suppose the current radix is 8. Then you can write the decimal
number 23 as:
27 octal (current radix)
^d23 decimal
^b10111 binary
but you cannot write decimal 23 as ^d45-22 since the ^d applies only to the
first number, 45; the 22 is still interpreted as octal. However, you can
write decimal 23 as ^d<45-22>.
Macro Page 39
3.2.2.3. Floating-point Decimal Numbers
In your program, a floating-point decimal number is a string of digits with a
leading, trailing, or embedded decimal point and an optional leading sign.
Macro recognizes this as a mixed number in radix 10.
Macro forms a floating-point decimal number with the sign in bit 0, a binary
exponent in bits 1 to 8, and a normalized binary fraction in bits 9 to 35.
The normalized fraction can be viewed as followed: its numerator is the binary
number in bits 9 to 35, whose value is less than 2 to the 28th power, but
greater than or equal to 2 to the 27th power. Its denominator is 2 to the
28th power, so that the value of the fraction is always less than 1, but
greater than or equal to 0. (This value is 0 only if the entire stored number
is 0.)
The binary exponent is incremented by 128 so that exponents from -128 to 127
are represented as 0 to 255.
For a negative floating-point number, Macro first forms its absolute value as
a positive number, then takes the two's complement for the entire word.
Examples:
The floating point number 17.0 generates the binary word
0 10 000 101 100 010 000 000 000 000 000 000 000
where bit 0 shows the positive sign, bits 1 to 8 show the binary exponent, and
bits 9 to 35 show the proper binary fraction. The binary exponent is 133
(decimal), which after subtracting the added 128 gives 5. The fraction is
equal to 0.53125 decimal. And 0.53125 times 2 to the 5th power is 17, which
is the number given.
Similarly, 153. generates
0 10 001 000 100 110 010 000 000 000 000 000 000
while -153. generates
1 01 110 111 011 001 110 000 000 000 000 000 000
These two examples show that a negative number is two's complemented. Notice
that since the binary fraction for a negative number always has some nonzero
bits, the exponent field (taken by itself) appears to be one's complemented.
As in Fortran, you can write a floating point decimal number with a suffixed
E+/-n, and the number will be multiplied by 10 to the +/-nth power. If the
sign is missing, n is assumed to be positive. Examples: 2840000. can be
written 284.E+4 or .284E7; .0000284 can be written .284E-4 or 284.E-7.
Using this E notation with an integer (no decimal point) is not allowed, and
causes an error. Therefore you can use 284.E4 but not 284E4.
Note: Macro's algorithm for handling numbers given with the E notation is not
identical for Fortran's. The binary values generated by the two translators
may differ in the lowest order bits.
Macro Page 40
3.2.2.4. Binary Shifting
Binary shifting of a number with Bn sets the location of the rightmost bit at
bit n in the storage word, where n is a decimal integer. The shift takes
place after the binary number is formed. Any bits shifted outside the range
(bits 0 through 35) of the storage word are lost.
For example, here are some numbers with their binary representations given in
octal:
300000 000000 ^d3b2
000000 042000 ^d17b25
000001 000000 1b17
777777 777777 -1b35
000000 000001 1b35
000000 777777 -1b17
3.2.2.5. Underscore Shifting
You can also shift a number by using the underscore operator. If V is an
expression with value n, suffixing _V to a number shifts it n bits to the
left. If n is negative, the shift is to the right.
In an expression of the form W_V, W and V can be any expressions including
symbols. The binary value of W is formed in a register, V is evaluated, and
the binary value of W is shifted V bits when placed in storage.
An expression such as -3.75E4_^d18 is legal, but the shift occurs after
conversion to floating point decimal storage format. Therefore the sign,
exponent, and fraction fields are all shifted away from their usual locations.
This is true also of other storage formats.
3.2.3. Literals
A literal is a character string within square brackets inserted in your source
code. Macro stores the code generated by the enclosed string in a literal
pool beginning with the first available literal storage location, and places
the address of this location in place of the literal. The literal pool is
normally at the end of the binary program.
The statements
Macro Page 41
ldb t1, [point 6, .JBVER, 17]
LIT
are equivalent to
ldb t1, foo
foo: point 6, .JBVER, 17
A literal can also be used to generate a constant:
push p, [0] ; Generate a zero fullword.
move q1, [3,,14] ; Generate a word with 3 in
; the left half and 14 in the right.
Multiline literals are also allowed:
getChr: ildb t2, t1 ; Get a character.
cain t2, 0 ; Is it a null?
jrst [ move t1, txtPtr ; Yes, use this pointer
ildb t2, t1 ; to get a new character.
cain t2, "?" ; Is it a question mark?
jrst [ move t1, txtPt2 ; Yes, use this pointer
ildb t2, t1 ; to get the message character,
jrst getHlp ] ; and go to the help routine.
ret ] ; Not a question mark, return from getChr.
ret ; Not a null, return with char in t2.
The text of a literal continues until a matching closing square bracket is
found (unquoted and not in a comment field).
A literal can include any term, symbol, expression, or statement, but it must
generate at least one but no more than 99 words of data. A statement that
does not generate data (such as a direct assignment statement or a RADIX
pseudo-op) can be included in a literal, but the literal must not consist
entirely of such statements.
You can nest literals up to 18 levels. You can include any number of labels
in a literal, but a forward reference to a label in a literal is illegal.
If you use a dot (.) in a literal to retrieve the location counter, remember
that the location counter is pointing at the statement containing the literal,
not at the literal itself. In nested literals, a dot location counter
references a statement outside the the outermost literal. In the sequence
jrst [ hrrz t1, v
caie t1, op
jrst .+1
jrst foo ]
skipe t3
the expression .+1 generates the address of skipe t3, not jrst foo.
Macro Page 42
Literals having the same value are collapsed in Macro's literal pool. Thus
for the statements
push p,[0]
caml t2,[0]
movei t1, [asciz /frotz/]
the same address is shared by the two literals [0], and by the null word
generated at the end of [asciz /frotz/]. Literal collapsing is suppressed for
those literals that contain errors, undefined expressions, or EXTERNAL
symbols.
3.2.4. Symbols
Macro symbols include:
1. Macro-defined pseudo-ops.
2. Macro-defined mnemonics.
3. User-defined macros.
4. User-defined opdefs.
5. User-defined labels.
6. Direct-assignment symbols.
7. Dummy arguments for macros.
Macro stores symbols in three symbol tables: one for opcodes and pseudo-ops,
one for macros and opdefs, and one for user defined labels and
direct-assignment symbols. An entry in one of these tables shows the symbol,
its type, and its value.
Symbols are helpful in your program because:
1. Defining a symbol as a label gives a name to an address. You can
use the label in debugging or as a target for program control
statements.
2. In revising a program, you can change a value throughout your
program by changing a single symbol definition.
3. You can give names to values to make computations clearer.
4. You can make values available to other programs.
Macro Page 43
3.2.4.1. Selecting Valid Symbols
Follow these rules in selecting symbols:
1. Use only letters, numerals, dots (.), dollar signs ($), and percent
signs (%). Macro will consider any other character (including
blank) as a delimiter.
2. Do not begin a symbol with a numeral.
3. If you use a dot for the first character, do not use a numeral for
the second. Do not use dots for the first two characters; doing so
can interfere with Macro's created symbols.
4. Make the first six characters unique among your symbols. You can
use more than six characters, but Macro will use only the first
six.
5. Don't choose symbols composed of 1 to 4 letters followed by a
percent sign; names of this form are reserved for new monitor
calls.
Examples:
velocity Legal, only "veloci" is heeded by Macro.
chg.vel Legal, only "chg.ve" is heeded by Macro.
chg vel Illegal, looks like two symbols to Macro.
chgVel Legal.
1stNum Illegal, begins with numeral.
.11111 Illegal, begins with dot-numeral.
..1111 Unwise, could interfere with created symbols.
3.2.4.2. Defining Symbols
You can define a symbol by making it a label or by giving its value in a
direct-assignment statement. Labels cannot be redefined, but
direct-assignment symbols can be redefined anywhere in your program.
You can also define special-purpose symbols called OPDEFs and macros using the
pseudo-ops OPDEF and DEFINE.
A label is always a symbol with a suffixed colon. A label is in the first
(leftmost) field of a Macro statement and is one of the forms:
errFound: Macro uses only "errfou".
case1: Legal label.
OK:contin: Legal; you can use more than one label at a location.
Macro Page 44
case2:: Double colon declares the label to be global INTERNAL.
When Macro processes the label, the symbol and the current value of the
location counter are entered in the user symbol table. A reference to the
symbol addresses the code at the label.
You cannot redefine a label to have a value different from its original value.
A label is relocatable if the address is represents is relocatable; otherwise
it is absolute.
You can define a direct-assignment symbol by associating it with an
expression. A direct assignment is in one of the forms:
symbol=expression - The symbol and the value of the expression are entered
together in the user symbol table.
symbol=:expression - The symbol and the value of the expression are entered
together in the user symbol table and the symbol is declared
INTERNAL.
You can redefine a direct-assignment symbol at any time; the new direct
assignment simply replaces the old definition.
Note:
If you assign a multiword value using direct assignment, only the
first word of the value is assigned to the symbol. For example,
A=asciz/abcdefgh/ is equivalent to A=asciz/abcde/, since only the
first five characters in the string correspond to code in the first
word.
3.2.4.3. Symbol-table Search Order
When you use a symbol in your program, Macro looks it up in the symbol tables.
Normal Macro searches the macro table first, then the opcode table, and
finally the user symbol table. However, if Macro has already found an
operator in the current statement and is expecting operands, then it searches
the user symbol table first.
3.2.4.4. Symbol Attributes
Each symbol in your program has one of the following attributes: local,
INTERNAL global, or EXTERNAL global. This attribute is determined when the
symbol is defined.
A local symbol is defined for the use of the current program only. You can
define the same symbol to have different values in separately assembled
programs. A symbol is local unless you indicate otherwise.
A global symbol is defined in one program, but is also available for use in
other programs. Its table entry is visible to all programs in which the
symbol is declared global. A global symbol must be declared INTERNAL in the
progam where it is defined; it can be defined in only one program. In other
programs sharing the global symbol, it must be declared EXTERNAL; it can be
Macro Page 45
EXTERNAL in any number of programs.
To declare a symbol as INTERNAL global, you can:
1. Use the INTERN pseudo-op, e.g. INTERN flag1
2. Insert a colon after the "=" in a direct assignment statement, e.g.
flag2=:200.
3. Use an extra colon with a label, e.g. flag3::.
4. For subroutine entry points, use the ENTRY pseudo-op, e.g.
ENTRY foo.
To declare a symbol as an EXTERNAL global, you can use the EXTERN pseudo-op,
e.g. EXTERN flag4.
3.2.5. Expressions
You can combine numbers and defined symbols with arithmetic and logical
operators to form expressions. You can nest expressions by using angle
brackets. Macro evaluates each expression (innermost nesting levels first),
and either resolves it to a fullword value, or generates a Polish expression
to pass to Link.
3.2.5.1. Arithmetic Expressions
An arithmetic expression can include any number or defined symbol, and any of
the following operators +, -, *, /. Examples (in which words, x, y, and z
have been defined elsewhere):
movei t3, words/5
addi q2, <x+y-z>
addi q2, <<words/5>+1>*5
3.2.5.2. Logical Expressions
A logical expression can include any number or defined symbol whose value is
absolute, and any of the operators &, !, ^!, ^-. Each of the binary
operations &, !, and ^! generates a fullword by performing the indicated
operation over corresponding bits of the two operands. For example, a&b
generates a fullword whose bit 0 is the result of a's bit 0 ANDed with b's bit
0, and so forth for all 36 bits.
Macro Page 46
3.2.5.3. Evaluating Expressions
Macro has a hierarchy of operations in evaluating expressions. In an
expression without nests (angle brackets), Macro performs its operations in
this effective order:
1. All unary operations and shifts: +, -, ^-, ^d, ^o, ^b, b (binary
shift), _ (underscore shift), E.
2. Logical binary operations (from left to right): !, ^!, &.
3. Multiplication and division (from left to right): *, /.
4. Addition and subtraction (binary operations): +, -.
You can override this hierarchy by using angle brackets to show what you want
done first. For example, suppose you want to calculate the sum of a and b,
divided by c. You cannot do this with a+b/c because Macro will perform the
division b/c first, then add the result to a. With angle brackets you can
write the expresssion <a+b>/c to force Macro to add a and b first, then divide
the result by c.
Expressions can be nested to any level. The innermost nest is evaluated
first; the outermost last. Some examples of legal expressions (assuming that
a1, b1, and c are defined symbols) are:
a1+b1/5
<a1+b1>/5
^-a1&b1^!c
^b101b17-^d98+6
An expression given in halfword notation <lefthalf,,righthalf> has each half
evaluated separately in a 36-bit register. Then the 18 low-order bits of each
half are joined to form a fullword. For example, the expression <4,,6>/2
generates the value 000002 000003.
Macro Page 47
3.3. Pseudo-ops
A pseudo-op is a statement that gives the assembler information to allow it to
assemble your program in the desired way. For example, the pseudo-op RADIX
does not generate code itself, but tells Macro how to interpret numbers in
your program. The pseudo-op EXP generates one word of code for each argument
given with it.
To use a pseudo-op in your program, follow it with a space or tab, and any
required or optional arguments or parameters.
This section describes the use and functions of each pseudo-op. The headings
for each description, if applicable, are Format, Function, Examples, and
Optional Notations.
3.3.1. ARRAY
Format ARRAY sym[expression]
Expression is an integer value (to be intterpreted in the
current radix, indicating the number of words to be allocated;
the expression cannot be EXTERNAL, relocatable, or negative.
Note that although the expression must be in square brackets,
this use of the brackets is completely unrelated to literals.
Function Reserves a block of storage whose length is the value of the
expression, and whose location is identified by the symbol.
Storage is allocated along with other variable symbols in the
program, usually at the end. The allocated storage is not
necessarily zeroed.
3.3.2. ASCII
Format ASCII dtextd
where d = delimiter; first nonblank character, whose second
appearance terminates the text, and text = a string of text
characters to be entered.
Function Enters ASCII text in the binary code. Each character uses
seven bits. Characters are left justified in storage, five
per word, with bit 35 in each word set to 0, and any unused
bits in the last word set to 0.
Examples
ASCII /This is a string/
ascii !ps:<frotz>foo.txt!
Ascii?foo?
Optional Notations: Omit the space or tab after ASCII. Not allowed if the
delimiter is a letter, number, dot, dollar or percent sign
(i.e. a possible symbol constituent), or if the delimiter
character is a control character.
Macro Page 48
Right-justified ASCII can be entered by using double quotes to
surround up to five characters, as in: movei t1, "A".
3.3.3. ASCIZ
Exactly like ASCII, except that a trailing null is guaranteed, even if an
extra word of nulls must be added. Most Tops-20 monitor calls expect strings
to be in this format.
3.3.4. BLOCK
Format BLOCK expression
where the expression is not EXTERNAL or relocatable, and
evaluates to a positive integer.
Function Reserves, at the point of invocation, a block of locations
whose length is the value of the expression. The location
counter is incremented by this value. The allocated locations
are not necessarily zeroed. Note that the BLOCK pseudo-op
does not generate or store code; therefore it should not be
used in a literal, since this will result in overwriting the
reserved space during literal pooling.
Examples
BLOCK 500
block <^d512/5+1>
block <$nPag_9 - fooLen>
Optional Notations: Use the pseudo-op Z inside literals.
3.3.5. BYTE
Format BYTE bytedef ... bytedef
bytedef = (n)expression, ..., expression
n = byte size in bits; n is a decimal expression in the range
1 to 36.
Function Stores values of expressions in n-bit bytes, starting at bit 0
of the storage word. The first value is stored in bits 0 to
n-1; the second in bits n to 2n-1, and so forth for each given
value. If a byte will not fit in the remaining bits of a
word, those bits are zeroed and the byte begins in bit 0 of
the next word. If a value is too large for a byte, it is
truncated on the left. If the byte size is 0 or is missing
(empty parentheses), a zero word is generated.
Examples
Macro Page 49
V=2
BYTE (6),5,0,,101,5,V
generates the storage value 050000 010502. The two commas
indicate a null argument; the 101 (octal) is too large for the
byte size and is left truncated.
byte (6)7,0,1(9)7,0,1,"A"
generates two words: 070001 007000 and 001101 000000. Notice
that "A" is right-justified in its 9-bit byte.
Note that a comma before a left parenthesis will generate a
null byte.
3.3.6. COMMENT
Format COMMENT dtextd
d = delimiter; the first nonblank character, whose second
appearance terminates the text.
Function Treats the text between the delimiters as a comment. The text
can include carriage returns to facilitate multiline comments.
Optional Notations: Omit the space or tab after COMMENT. This is not allowed
if the delimiter is a valid character for identifiers, or is a
control character. Use a semicolon (;) to make the rest of
the line into a comment. Be careful not to use the delimiter
in the text of the comment, and avoid the use of nonprinting
delimiters.
Example :
foo: comment | Subroutine Foo
This subroutine writes a poem in the style of a given poet.
Enter with:
t1/ Pointer to asciz name of poet.
t2/ Destination designator for poem.
t3/ Pointer to asciz string describing desired topic.
Returns:
+1: always, with t1, t2, and t3 updated appropriately.
|
Macro Page 50
3.3.7. DEC
Format DEC expression, ..., expression
Function Defines the local radix for the line as decimal, then enters
the value of each given expression in a fullword of code. The
location counter is incremented by 1 for each expression.
Example DEC 10, 938, 512, 4.5, 6.03E-5
Optional Notation: Use the EXP pseudo-op and prefix ^d to each expression
that must be evaluated in radix 10.
3.3.8. DEFINE
Format DEFINE macroName(dArgList)<macroBody>
where
- macroName is a symbolic name for the macro being
defined. This name must be unique among all macro
and OPDEF symbols.
- dArgList is a list of dummy arguments.
- macroBody is the source code to be assembled when
the macro is invoked.
Function defines the macro. See the section on macros.
3.3.9. END
Format END expression
where expression is an optional operand that specifies the
address of the first instruction to be executed, which can be
EXTERNAL, in the right half and, optionally, the length of the
entry vectory in the left.
Function Must be the last statement in a Macro program. Statements
after END are ignored. The starting address is optional and
normally is given only in the main program (since subroutines
are called from the main program, they should not specify a
starting address). When the assembler first encounters an END
statement, it terminates pass 1 and begins pass 2. The END
terminates pass 2 on the second encounter, and unallocated
literals and variables (e.g. ARRAYs) are assembled at the
current location.
Examples:
end
end start
end <3,,entVec>
Macro Page 51
end <evLen,,entVec>
3.3.10. ENTRY
Format ENTRY symbol, ..., symbol
Each symbol is the name of an entry point in a library
subroutine.
Function Defines each symbol in the list following the ENTRY pseudo-op
as an INTERNAL symbol, and puts appropriate information in the
.REL file to allow the symbols to be included in an index
(such as that constructed by the MAKLIB program). Each symbol
must correspond to a label of the same name. Programs
referring to these symbols must, of course, declare them
EXTERNAL.
3.3.11. EXP
Format EXP expression, ..., expression
Function Enters the value of each expression in a fullword of code.
3.3.12. EXTERN
Format EXTERN symbol, ..., symbol
Function Identifies symbols as being defined in other programs.
EXTERNAL symbols cannot be defined within the current program.
At load time, the value of an EXTERNAL symbol is resolved by
Link if you load a module that defines the symbol as an
INTERNAL symbol; if you do not load such a module, Link gives
an error message for the undefined global symbol(s).
3.3.13. IFx Group
Gives criterion and code for conditional assembly. A symbol or expression
used to define the conditions for assembly must be defined before Macro
reaches the conditional statement. If the value of such a symbol or
expression is not the same on both assembly passes, a different number of
words of code may be generated (resulting in a phase error).
The forms of IF pseudo-op are listed below; in the first six forms, n is the
value of the given expression.
IFE expression,<code> - assemble code if n=0.
IFN expression,<code> - assemble code if n not = 0.
IFG expression,<code> - assemble code if n>0.
Macro Page 52
IFGE expression,<code> - assemble code if n>=0.
IFL expression,<code> - assemble code if n<0.
IFLE expression,<code> - assemble code if n<=0.
IF1 <code> - assemble code on Pass 1.
IF2 <code> - assemble code on Pass 2.
IFDEF symbol,<code> - assemble code if the symbol is defined as user-defined,
an opcode, or a pseudo-op.
IFNDEF symbol,<code> - assemble code if the symbol is not defined as
user-defined, an opcode, or a pseudo-op. Code is also
assembled if the symbol has been referenced, but is not yet
defined. This can occur during pass 1.
IFIDN <string1><string2>,<code> - assemble code if the strings are identical.
IFDIF <string1><string2>,<code> - assemble code if the strings are different.
IFB <string>,<code> - assemble code if the strings contain only blanks and
tabs.
IFNB <string>,<code> - assemble code if the string does not contain only
blanks and tabs.
Example:
$cc=$cc+1 ; Count a character.
ifg <$cc-5>,< ; Word overflowed?
$cc=0 ; Yes, reset character counter
$wc=$wc+1 ; and count a word.
>
Optional notations: Omit angle brackets enclosing code for single-line
conditionals. For IFIDN, IFDIF, IFB, and IFNB only: use a
nonblank, nontab character other than < as the initial and
terminal delimiters for a string (as in the pseudo-ops ASCII
and ASCIZ); you can then include angle brackets in the string.
3.3.14. INTERN
Format INTERN symbol, ..., symbol
Function Declares each given symbol to be INTERNAL global; therefore
its definition, which must be in the current program, is
available to other programs at load time. Each such symbol
must be defined as a label, a variable, or a direct assignment
symbol. OPDEF symbols can be declared INTERNAL, and thus be
made available to other programs at load time. However, if
the current program has another symbol (besides the OPDEF
symbol) of the same name, the INTERNAL declaration will apply
to that symbol rather than to the OPDEF symbol.
Macro Page 53
3.3.15. IOWD
Format IOWD exp1,exp2
Function Generations a word in a special format for use by all five
pushdown stack instructions (adjsp, push, pop, pushj, popj),
as well as for i/o instructions (hence its name). The left
half of the assembled word contains the 2's complement of the
value of exp1, and the right half contains the value exp2-1.
Example: Setting up a pushdown stack.
stkLen=100
array stack[stkLen]
move p, [iowd stkLen,stack]
3.3.16. IRP
Format IRP arg,<code>
where arg is one of the dummy arguments of the enclosing macro
definition; you can only use IRP in the body of a macro
definition.
Function Generates one expansion of the code enclosed in angle brackets
for each subargument of the string that replaces arg. Each
occurrence of arg within the expansion is replaced by the
subargument currently controlling the expansion (see the
section on macros).
Example:
define sum(a,b)<
movei q, 0
irp a,<add q,a>
movem q, b
>
sum (<x,y,z>,foo)
This invocation of sum is replaced by:
movei q, o
add q, x
add q, y
add q, z
movem q, foo
Macro Page 54
3.3.17. IRPC
Format IRPC arg,<code>
Function Generates one expansion of the bracketed code for each
character of the string that replaces arg (a dummy argument of
the enclosing macro definition). Each occurrence of arg
within the expansion is replaced by the character currently
controlling the expansion. Concatenation and line
continuation are not allowed across end-of-IRPC, since a
carriage return and linefeed are appended to each expansion.
Example:
define deposit (string,bp)<
irpc string, <
movei q, "string"
idpb q, bp
>
>
deposit <foo>,x
expands to:
movei q, "f"
idpb q, x
movei q, "o"
idpb q, x
movei q, "o"
idpb q, x
3.3.18. LIT
Format LIT
Function Assembles literals beginning at the current address. The
literals assembled are those found since the previous LIT, or
since the beginning of the program, whichever is later. The
location counter is incremented by 1 for each word assembled.
A literal found after the LIT is not affected. It will be
assembled at the next following LIT, or at the END statement,
whichever is earlier. Literals having the same value are
collapsed in Macro's literal pool.
3.3.19. OCT
Format OCT expression, ..., expresssion
Function Defines the local radix for the line as octal; the value of
each each expression is entered in a fullword of code. The
location counter is incremented by 1 for each expression.
Equivalent to using EXP with each argument prefixed by ^o.
Macro Page 55
3.3.20. OPDEF
Format OPDEF symbol[expression]
Function Defines the symbol as an operator equivalent to the
expression, giving the symbol a fullword value. When the
operator is later used with operands, the accumulator fields
are added, the indirect bits are ORed, the memory addresses
are added, and the index register addresses are added. An
OPDEF can be declared INTERNAL, using the INTERN pseudo-op.
However, if a symbol of the same name exists, the INTERNAL
declaration will apply only to that symbol, and not to the
OPDEF. Although the expression portion of an OPDEF must be in
square brackets, this use of the brackets is completely
unrelated to literals or literal handling.
3.3.21. POINT
Format POINT byteSize,address,bitPosition
Function Generates a byte pointer word for use with the machine
language byte instructions adjbp, ldb, ibp, ildb, and idbp.
The byteSize gives the decimal number of bits in the byte, and
is assembled in bits 6 to 11 of the storage word. Address
gives the location of the word containing the byte, and is
assembled in bits 13 through 35 (with normal indirect, index,
and offset fields). BitPosition gives the position (in
decimal) of the rightmost bit in the byte. Macro places the
value <35-bitPosition> in bits 0-5 of the storage word. The
default bitPosition is -1, so that the byte increment
instructions ipb, ildb, and idpb will operate on the first
byte in the address word.
3.3.22. PRGEND
Format PRGEND
Function Replaces the END statement for all except the last program of
a multiprogram assembly. PRGEND closes the local symbol table
for the current module. You can use PRGEND to place several
small programs into one file to save space and disk accesses.
The resulting binary file can be loaded in library search mode
(refer to the Link and MakLib manuals for more information
about this). PRGEND is not allowed in macros. Like END,
PRGEND causes the assembly of all unassembled literals. In a
file containing PRGENDs, using more than one LIT pseudo-op in
any but the last program produces unpredictable results. A
starting address for the program terminated by PRGEND may
optionally be given as an argument to PRGEND.
Macro Page 56
3.3.23. PRINTX
Format PRINTX text
Function Causes text to be output at the terminal during assembly,
normally once for each pass.
Example:
define prVal (v,msg)<printx [msg v]>
if2, <
$$len=.-buffer
prVal \$$len, <Size of buffer (in words):>
ifg <.-20000>,<printx <Buffer too big!>>
>
3.3.24. PURGE
Format PURGE symbol, ..., symbol
Function Deletes symbols from the symbol tables. Normally used at the
end of a program to fix multiply defined global symbol errors
that occur at Link time, or to remove unwanted symbols from
DDT typeout. If you use the same symbol for both a macro name
or OPDEF and a label, a PURGE statement deletes the macro name
or OPDEF. Repeating the PURGE statement then purges the
label.
3.3.25. RADIX
Format RADIX expression
Function Sets the radix to the value of the expression, which is
interpreted in decimal, and must be in the range 2 to 10. An
implicit RADIX 8 statement begins each Macro program. All
numerical expressions that follow (up to the next RADIX
pseudo-op) are interpreted in the given radix unless another
local radix is indicated via ^d, ^o, ^b, OCT, DEC, etc.
Ordinarily, numbers outside the range of the given radix are
not interpreted. For example, in radix 8, the number 99
causes an error. However, a single-digit number is
interpreted in any case. For example, in radix 8, the number
9 is recognized as octal 11.
3.3.26. REPEAT
Format REPEAT expression,<code>
Function Generates the bracketed code n times, where n is the value of
the expression, and must be a nonnegative integer. REPEAT
statements can be nested to any level. Line continuation is
Macro Page 57
not allowed across end-of-REPEAT, since a carriage return and
linefeed are appended to each expansion of the code. Note
that REPEAT 0,<code> is logically equivalent to a false
conditional (and is often used to "comment out" a large
section of code), and REPEAT 1,<code> is logically equivalent
to a true conditional.
3.3.27. .REQUIRE
Format .REQUIRE filespec
Function Causes the specified file to be loaded automatically at Link
time. The filespec must not include a file type, and it must
be a Tops-10 (not Tops-20!) file specification.
3.3.28. SEARCH
Format SEARCH tableName(fileName), ..., tableName(fileName)
Function Defines a list of symbol tables for Macro to search if a
symbol is not found in the current symbol table. A maximum of
ten tables can be specified. Tables are searched in the order
specified. When the SEARCH pseudo-op is seen, Macro checks
its internal UNIVERSAL tagble for a memory-resident UNIVERSAL
of the specified name. If no such entry is found, Macro reads
in the symbol table using the given file specification. If no
file specification is given, Macro reads tableName.UNV from
the connected directory, and on failure tries the same
filename in UNV: and SYS:, in that order. When all the
specified files are found, Macro builds a table for the search
sequence. If Macro cannot find a given symbol in the current
symbol table, the UNIVERSAL tables are searched in the order
specified. When the symbol is found, it is moved into the
current symbol table. This procedure saves time (at the
expense of core) on future references to the same symbol. A
UNIVERSAL file can search other UNIVERSAL files, provided all
names in the search list have been assembled.
Optional notation: Omit the filename and its enclosing parentheses. Macro
then looks on DSK:, UNV:, and SYS: (in that order) for
tableName.UNV.
3.3.29. SIXBIT
Format SIXBIT dtextd
d = delimiter (first nonblank character, whose second
appearance terminates the text)
Function Enters strings of text characters in 6-bit format. Six
characters per word are left justified in sequential storage
words. Any unused bits are set to zero. Lowercase letters in
Macro Page 58
SIXBIT text strings are treated as uppercase. Otherwise, only
the SIXBIT character set allowed. The SIXBIT character set
consists of all the printable ASCII characters except
lowercase letters, and the following symbols: `{|}~. The
values of the SIXBIT characters are 0-77 (octal); they are
offset from the corresponding ASCII values by octal 40, e.g.
ASCII "A" is 101, and SIXBIT "A" is 41. Historically, this
was a popular format for the storage of strings whose maximum
length was 6, such as filenames or program names under
Tops-10, because it allowed word comparisons and transfers
instead of slower byte manipulations.
Optional Notation: Right-justified SIXBIT can be entered by using single
quotes to surround uf to six characters, as in
move t1, ['FOOBAZ']
3.3.30. STOPI
Ends an IRP or IRPC before all subarguments or characters are used. The
current expansion is completed, but no new expansions are started. STOPI can
be used with conditionals inside IRP or IRPC to end the repeat if the given
condition is met.
3.3.31. SUBTTL
Format SUBTTL String
Function Defines a subtitle (of up to 80 characters) to be printed at
the top of each page of the listing file until the end-of-
listing or until another SUBBTL statement is found. The
initial SUBTTL usually appears on the second line of the first
page of the input file, immediately following the TITLE
statement. For subsequent SUBTTL statements, the following
rule applies: if the new SUBTTL is on the first line of a new
page, then the new subtitle appears on that page; if not, the
new subtitle appears on the next page. Even if you do not
plan to generate listing files, SUBTTL is still a useful
documentation device, and is recognized by certain programming
aids.
3.3.32. TITLE
Format TITLE String
Function Gives the program name and a title to be printed at the top of
each page of the program listing. The first characters (up to
6) are the program name; the program is saved by this name
unless another is explicitly given in the 'save' command. In
addition, the name is used when debugging with DDT to gain
access to the program's symbol table. Only one TITLE is
allowed per module (file or section of file delimited by
Macro Page 59
PRGEND's). The TITLE statement usually appears as the first
line of a program. If no TITLE statement is used, the
assembler inserts the program name ".MAIN".
3.3.33. XWD
Format XWD leftHalf,rightHalf
Function Enters two halfwords in a single storage word. Each half is
formed in a 36-bit register, and the low-order 18 bits are
placed in the halfword. The high-order bits are ignored.
Optional Notation: leftHalf,,rightHalf
3.3.34. Z
Format Z accumulator, address
Function Z is treated as if it were the null machine language mnemonic
( opcode). An instruction word if formed with zeros in bits 0
to 8. The rest of the word is formed from the accumulator an
address. If the accumulator and address fields are omitted, a
zero word is assembled.
3.4. Macro Statements and Statement Processing
A Macro statement has one or more of the following: a label, an opcode, zero
or more operands, and a comment. The general form of a macro statement is:
label: operator operand, operand ; Comment.
A carriage return ends the statement.
Direct assignment statements receive special handling.
Processing of macros is not discussed in this section because a macro call
produces text substitution. After substitution, the text is processed as
described in this section. Macros are discussed in their own chapter.
3.4.1. Labels
A label is always a symbol with a suffixed colon. The assembler recognizes a
label by finding the colon. If a statement has labels (you can use more than
one), they must be the first elements in the statement.
A label can be defined only once; its value is the address of the first word
of code generated after it.
Macro Page 60
Since a label gives an address, the label can be either absolute or
relocatable. A label is a local symbol by default, but you can declare a
label to be INTERNAL globel or EXTERNAL global.
3.4.2. Operators
After processing any labels, the assembler views the first group of following
nonblank, nontab characters as a possible operator. An operator is one of the
following:
1. A mnemonic symbol defined by Macro to stand for a machine opcode
(see Chapter 2).
2. A user-defined operator, such as an OPDEF or macro invocation.
3. A Macro pseudo-op.
If the characters found do not form one of the above, Macro views them as an
expression.
An operator is ended by the first non-alphanumeric character that is not a .,
$, or %. If it is ended by blank or tab, operands may follow; if it is ended
by a semicolon, there are no operands and the comment field begins; if it is
ended by a carriage return, the statement ends and there are no operands or
comments.
3.4.3. Operands
After processing labels and the operator, if any, the assembler views as
operands all characters up to the first unquoted semicolon or carriage return.
Unquoted commas delimit the operands.
The operator in a statement determines the number (none, one, two, or more)
and kinds of permitted or required operands. Any expected operand not found
is interpreted as null. An operand can be any expression or symbol
appropriate for the operator.
Examples:
loop: move t1, x
%print <x is %d, y is %d>,<exp t1, y>
In the first line, t1 and x are operands. In the second line, a macro,
%print, is invoked with two operands. Each of these operands is quoted by
enclosing it in angle brackets; this is necessary because each operand
contains an internal comma.
Macro Page 61
3.4.4. Comments
The first unquoted semicolon in a statement begins the comment field. You can
use any ASCII characters in a comment; however, angle brackets in a comment
may produce unpredictable results (such as unexpected termination of a macro
definition or conditional-assembly code) and should be avoided.
If the first nonblank, nontab character in a line is a semicolon, the entire
line is a comment. You can also enter a full line of comment with the
pseudo-op REMARK, or a multiline comment with the pseudo-op COMMENT.
Comments do not affect binary program output.
3.4.5. Statement Processing
Macro processes your program as a linear stream of data. During Pass 1 of an
assembly, Macro may find references to symbols not yet defined in the user
symbol table. Whenever a symbol is defined, it is entered in the table with
its value, so that on Pass 2 all definitions can be found in the table. The
values then replace the symbols in the binary code that is generated.
Note: Delayed definition is allowed only for labels and direct-
assignment symbols. A symbol that contributes to code generation (for
example, an OPDEF, a macro, or a REPEAT index) must be defined before
any reference to it.
Statement processing proceeds as follows:
1. Labels are found and entered in the user symbol table.
2. The next characters up to the first unquoted semicolon, blank, tab,
comma, or equal sign are processed:
a. Equal sign: the preceding characters form a symbol, and the
following characters form an expression. The symbol and the
value of the expression are entered in the user symbol table.
b. Other delimiter: the preceding characters form an expression
or an operator. If an operator, it is found in a table and
assembled. If an expression, its value is assembled.
If the operator takes operands, the next characters up to the first
unquoted semicolon or carriage return form operands. Unquoted
commas delimit operands. For each operand, leading and trailing
blanks and tabs are ignored. Operands are evaluated and assembled
for the given operator.
3. The first unquoted semicolon ends processing of the line. Any
further characters up to the first carriage return are comment.
4. The first unquoted carriage return ends the statement. Any
following characters begin a new statement.
Macro Page 62
3.4.6. Assigning Addresses
Macro normally (and by default) assembles statements with relocatable
addresses. Assembly begins with the zero storage word and proceeds
sequentially. Each time Macro assembles a word of binary code, it increments
its location counter by 1.
A mnemonic operator generates one word of binary code. Direct assignment
statements and some pseudo-ops do not generate any binary code. Some
pseudo-ops generate one or more word of binary code.
You can control address assignment by setting the assembler's location counter
using the pseudo-ops LOC and RELOC. You can also reference addresses relative
to the location counter by using the dot symbol (.). For example, the
expression .-1 used as an address refers to the location immediately preceding
the current location. Use of this construction is not encouraged (see Chapter
8), because you can cause an incorrect address to be assembled by adding or
removing statements withing the range of a .+n expression. Labels should be
used except when n = plus or minus 1.
3.4.7. Machine Instruction Mnemonics and Formats
An instruction is in one of the following forms:
mnemonic accumulator, address
mnemonic accumulator,
mnemonic address
where "mnemonic" evaluates to a machine operation code (opcode), "accumulator"
is an accumulator (or register) address, and "address" is a memory address,
possibly modified by indexing, indirect addressing, or both.
The accumulator address can be any expression whose value is in the range 0 to
17 (octal).
The memory address gives a location in memory, and can be any expression or
symbol whose value is an integer in the range 0 to octal 777777.
You can modify the memory address by indirect addressing, indexed addressing,
or both. For indirect addressing, prefix an at-sign (@) to the memory address
in your program. For indexed addressing, suffix an index register address in
parentheses to the memory address in your program. This address can be any
expression or symbol whose value is an integer in the range 1 to octal 17.
Note: To assemble the index, Macro places the index register
address in a fullword of storage, swaps its halfwords (as it does to
any expression in parentheses), and then adds the swapped word to the
instruction word.
Example (in which t1=1, temp=100, and x=3):
add t1, @temp(x)
This generates the following binary code:
Macro Page 63
instruction indirect
code bit memory address
010 111 000 0 001 1 0 011 000 000 000 001 000 000
accumulator index
register
The mnemonic ADD has the octal code 270, and this is assembled into bits 0 to
8. The accumulator goes into bits 9 to 12. Since the @ appears with the
memory address, bit 13 is set to 1. The index register goes into bits 14 to
17. Finally, the memory address is assembled into bits 18 to 35.
If any element is missing from a primary instruction, zeros are assembled in
its instruction word field.
3.4.8. Mnemonics with Implicit Accumulators
A few mnemonics set bits in the accumulator field as well as in the
instruction field. Therefore these mnemonics do not take accumulator
operands, and are of the form
mnemonic address
For example, JFOV gives the octal code 25504; JFCL gives 255. They both give
the opcode 255 in bits 0 to 8, but JFOV also sets the accumulator (bits 9 to
12) to binary 0001. This makes JFOV 100 equivalent to JFCL 1,100.
3.5. Using Macros
A macro is a sequence of statements defined and named in your program. When
you invoke a macro (by mentioning its name in your program), the sequence of
statements from its definition is generated in place of the invocation,
possibly with "arguments" plugged in.
By using macros with arguments, you can generate passages of code that are
similar, but whose differences are controlled by the arguments. This saves
repetition in building a source file.
3.5.1. Defining Macros
Before you can invoke a macro, you must define it. You can also redefine a
macro if you wish; the new definition simply replaces the old one.
To define (or redefine) a macro, use the pseudo-op DEFINE:
DEFINE macroName (dArgList)<macroBody>
where "macroName" is the name of the macro, "dArgList" is an optional list of
"dummy arguments", and "macroBody" is a sequence of statements. The macroName
is a symbol constructed according to the rules for symbols.
Macro Page 64
The optional dummy-argument list can give one or more dummy-argument symbols
through which values are passed to the sequence of statements. If a macro
definition has dummy arguments, they must be enclosed in parentheses. Use
commas as delimiters between dummy arguments. For each dummy argument,
leading and trailing spaces and tabs are ignored.
The macroBody is the sequence of statements you want to generate when you
invoke the macro. The macroBody must be enclosed in angle brackets.
Here is a sample macro definition:
define vMag (adrs,len) < ;; Vector Magnitude macro.
move t1, adrs ;; Get first component.
fmp t1, t1 ;; Square it.
move t2, adrs+1 ;; Get second component.
fmp t2, t2 ;; Square it
fad t1, t2 ;; and add in square of first.
move t2, adrs+2 ;; Third component...
fmp t2, t2 ;; squared...
fad t1, t2 ;; and added in to the sum.
call fSqrt ;; Go get the floating square root
movem t1, len ;; and store the result.
>
Note the double semicolons; this device allows comments to be included in
macro definitions but omitted from macro expansions.
3.5.2. Invoking Macros
You can invoke a macro by putting its name in your program. Recall that you
must define the macro before you can invoke it. You can use the macroName as
a label, an operator, or an operand.
If the macro's definition has dummy arguments, the macro invocation can have
arguments. The arguments passed to the macro are inserted into the defined
sequence of statements as it is generated. The first passed argument replaces
the first dummy argument; the second passed argument replaces the second dummy
argument; this treatment continues for each argument passed. Any missing
arguments are passed as nulls (zeros) or filled in by default arguments (see
below).
Note: if FOO is a macro with four dummy arguments, the call
FOO (a,,c) passes a and c as the first and third arguments. The
second argument is passed as null; it is not considered missing and
cannot be replaced by a default argument. The fourth argument is
missing and will be replaced by a default argument if one has been
defined; otherwise it will be passed as nulls.
After argument substitution, the defined sequence of statements replaces the
macroName and the argument list in the source text. For example, suppose you
have defined vMag(adrs,len) as shown in Section 3.5.1 above, and vMag is
invoked in your program as follows:
getMag: vMag coord, q1
Macro Page 65
Then the effect would be as if you had written the following code in your
program in place of the invocation of vMag:
getMag: move t1, coord
fmp t1, t1
move t2, coord+1
fmp t2, t2
fad t1, t2
move t2, coord+2
fmp t2, t2
fad t1, t2
call fSqrt
movem t1, q1
This code is called the "macro expansion"; the invocation of vMag has been
replaced by the macroBody from the definition of vMag, with the actual
arguments from the invocation (coord and q1) replacing the dummy arguments
from the definition (coord and len) throughout the text of the macroBody.
3.5.3. Macro Invocation Format
In a macro invocation, delimit the macroName with one or more blanks or tabs.
If the macro has arguments, the first nonblank, nontab character begins the
argument list. Each argument ends with a comma, a carriage return, or a
semicolon. These three characters cannot be used within arguments unless
enclosed by special quoting characters.
Leading spaces and tabs are stripped from each argument unless they are within
special quoting characters. Embedded spaces and tabs are not stripped.
Examples:
%erMsg eh?,errLoc
The macroName is %erMsg; the arguments are the strings "eh?" and
"errLoc".
%erMsg <Invalid foo, baz, or frotz>,errLoc
Here the first argument is quoted, because it contains commas.
%print <The coordinates are %d, %d, %d>,<
x
y
z
>
Here the first argument is quoted because it contains commas, and the second
argument is quoted because it contains carriage returns.
Macro Page 66
3.5.4. Quoting Characters in Macro Arguments
The special quoting characters for macro arguments are:
< > Angle brackets
( ) Parentheses
[ ] Square brackets
" " Doublequotes (but not single quotes (apostrophes))
Any character, including the semicolon (;), enclosed in special quoting
characters is treated as a regular character. If one of the special quoting
characters is to be passed as a regular character, it must be enclosed by
different special quoting characters.
Here are the rules for macro argument handling. In the examples, "foo" is
assumed to be a defined macro:
1. The special quoting characters are not argument delimiters. They
only tell the assembler to treat the enclosed characters as regular
characters.
foo c<a,b> has one argument: c<a,b>.
foo c,d<a,b> has two arguments: c and c<a,b>.
2. With the two exceptions explained below, special quoting characters
are always included in passed arguments.
foo a,(b,c) has two arguments: a and (b,c).
foo [xwd 1,L1]-1(ac) has one argument: [xwd 1,L1]-1(ac).
foo "(",0 has two arguments: "(" and 0.
Exceptions:
a. If the first character of the argument list is a left
parenthesis, then it and its matching right parenthesis
delimit the argument list. They are not treated as special
quoting characters and are not included in passed arguments.
All nested quoting characters except angle brackets are
disabled. After stripping the outer parentheses, angle
brackets are handled as described in Exception 2, below.
foo (a,b,c) has 3 arguments: a, b, and c.
foo (?Length > 132) has one argument: ?Length > 132.
foo ([a,b]) has two arguments: [a and b].
foo (<a,b>) has one argument: a,b.
b. If a left angle bracket is the first character of the
argument list, or the first character after an unquoted
comma, then it and its matching right angle bracket are
treated as special quoting characters, but are not included
in passed arguments.
Macro Page 67
foo <a,b>,c has two arguments: a,b and c.
foo c,<a,b> has two arguments: c and a,b.
3.5.5. Nesting Macro Definitions
You can define a macro within the body of another macro definition. The
nested macro is not defined to the assembler until the enclosing macro is
invoked. See the example in 3.5.6.
3.5.6. Concatenating Macro Arguments
The apostrophe (') is the concatenation operator for macro calls. If you
insert an apostrophe immediately before or after a dummy argument in the body
of a macro, the assembler removes it at invocation. This removal joins
(concatenates) the passed argument to the neighboring character in the
generated text.
If the apostrophe precedes the dummy argument, the passed argument is suffixed
to the preceding character; if the apostrophe is follows the dummy argument,
the passed argument is prefixed to the following character.
You can use more than one apostrophe with a dummy argument. In this case only
apostrophes next to the dummy argument will be removed (at most one from each
side). Other apostrophes are treated as regular characters in the macroBody.
The following example shows the treatment of apostrophes on both sides of the
dummy argument, and of double apostrophes:
define o (prefix,midfix) <
define ocomp (suffix) <
prefix'o'midfix''suffix
>
>
The invocation "o a,j" generates:
aoj'suffix
because when the assembler replaces "prefix" with "a", the apostrophe
following is removed to form "ao". When "j" replaces "midfix", the preceding
apostrophe and first following apostrophe are removed to form "aoj'suffix".
Now the invocation "ocomp le" generates "aojle" since the apostrophe is
removed to join "aoj" and "le".
3.5.7. Default Arguments and Created Symbols
Ordinarily, an argument missing from a macro invocation is passed as nulls.
For example, the macro defined by
Macro Page 68
define words (a,b,c) <
exp a,b,c
>
when invoked by "words 1,1" generates three words containing 1, 1, and 0,
respectively.
You can, however, alter this handling by specifying default values other than
nulls, or by using created symbols.
3.5.7.1. Specifying Default Values
If you want a missing argument to default to some value other than nulls, you
can specify the default value in your DEFINE statement. Do this by inserting
the default value in angle brackets immediately after the dummy argument. For
example, the macro defined by
define words (a,b<222>,c<333>) <
exp a, b, c
>
when invoked by "words 1,1" generates three words containing 1, 1, and 333,
respectively.
An argument passed as nulls by consecutive commas is NOT considered missing
and cannot cause a default value to be supplied. Therefore missing arguments
can occur only at the end of the list of passed arguments.
3.5.7.2. Created Symbols
A symbol used as a label in a macroBody must be different for each call of the
macro, since duplicate labels are not allowed. Therefore for each call a
different symbol for the label must be passed as an argument.
If you do not refer to such a label from outside the macro, you can simply let
the assembler provide a new label for each call. This label is called a
created symbol, and is of the form ..nnnn where nnnn is a 4-digit number.
To use a created symbol in place of a passed argument, use the percent sign
(%) as the first character of the dummy argument in your DEFINE statement.
The assembler then creates a symbol for use in the macro expansion if that
argument is missing from a call to the macro. If you provide an argument in
the call, the passed argument overrides the created symbol.
The argument is determined to be missing from, or present in, the macro
invocation in the same way in 3.5.7.1, i.e. only a trailing argument can be
missing.
Example:
Macro Page 69
define compare (test,save,index,%loc) <
%loc: move save, test
setz index,
came save, table(index)
jrst %loc
>
compare t1, t1, t3
expands to:
..0001: move t2, t1
setz t3,
came t2, table(t3)
jrst ..0001
while
compare t1, t2, t4, foo
expands to:
foo: move t2, t1
setz t4,
came t2, table(t4)
jrst foo
3.5.8. Indefinite Repetition
The pseudo-ops IRP, IRPC, and STOPI give a convenient way to repeat all or
part of a macro; you can change arguments on each repetition if you wish, and
the number of repetitions can be computed at assembly time. You can use these
three pseudo-ops only within the body of a macro definition.
To see how IRP works, assume the macro definition
define doEach (a) <
IRP a,<a>
>
The invocation "doEach <alpha,beta,gamma>" produces the code:
alpha
beta
gamma
because each subargument passed to IRP generates one repetition of the code.
Notice that the range of IRP must be enclosed in angle brackets.
Using angle brackets in the invocation of doEach is critical, since they make
the string "alpha,beta,gamma" a single argument for IRP. IRP then sees the
commas as delimiting subarguments.
IRPC is similar to IRP, but an argument passed to IRPC generates one
Macro Page 70
repetition for each character of the argument. See 3.3.17 for an example of
IRPC.
STOPI ends the action of IRP or IRPC after assembly of the current expansion.
You can use STOPI with a conditional assembly to calculate a stopping point
during assembly. Here's an example, in which IRPC is used to generate code to
copy either a whole string or the first five characters, whichever is shorter:
define copy5 (string, dest) <
$count=5
irpc string, < ;; Get a character from String.
movei t1, "string" ;; Copy it.
idpb t1, dest ;; ...
$count=$count-1 ;; Count it.
ife $count,<stopi> ;; If we've done 5, then quit.
>
>
3.5.9. Alternate Interpretations of Characters Passed to Macros
The normal argument passed by a macro call is simply the string of characters
given with the call. Macro offers three alternate interpretations of the
passed argument.
- If you prefix a backslash (\) to an expression argument, the
argument passed is the ASCII numeric character string giving the
value of the expression. See 3.3.23 for a useful example.
- If you prefix a backslash-apostrophe (\') to an expression argument,
the argument passed is the string whose value is the SIXBIT string
with the integer value of the expression.
- If you prefix backslash-doublequote (\") to an expression argument,
the argument passed is the string whose value is the ASCII string
with the integer value of the expression.
Illustration: a macro "foo" that just replaces itself by its argument can
work in many ways.
define foo (a) <
a
>
Sample invocations of foo; assume the following symbol definitions:
Z=60
ZZ='SIXBIT'
ZZZ="ASCII"
Invocation Expansion
foo 60 60
Macro Page 71
foo \60 60
foo \'60 P
foo \"60 0
foo Z Z
foo \Z 60
foo \'Z P
foo \"Z 0
foo ZZ ZZ
foo \ZZ 635170425164
foo \'ZZ SIXBIT
foo ZZZ ZZZ
foo \ZZZ 203234162311
foo \"ZZZ ASCII
3.6. Errors and Messages
Macro has three kinds of messages:
1. Informational messages
2. Single-character error codes
3. MCRxxx (where xxx is a 3-letter mnemonic code)
3.6.1. Informational Messages
This are found at the end of listings, and some of them are printed at your
terminal. The only truly useful one is:
UNASSIGNED DEFINED AS IF EXTERNAL
This message lists symbols that were not defined. A symbol can be undefined
for several reasons:
1. You forgot to define it, e.g. you referred to a label that you
forgot to include in your program.
2. You spelled it wrong either when defining it or when referring to
it.
3. You are referring to a symbol defined in another module, but you
forgot to declare it EXTERNAL in the current module.
Macro Page 72
3.6.2. Single-Character Error Codes
These cryptic and uninformative codes are printed at your terminal when Macro
encounters various kinds of errors.
A Argument error in pseudo-op.
D The statement refers to a multiply defined symbol.
E Improper use of EXTERNAL symbol.
L Literal generates less than 1 or more than 99 words of code.
M Symbol has already been defined; it will retain its first
definition.
N Number error.
O Opcode undefined, assembled as zeros.
P Phase error. In general, the assembler generates the same
number of locations on Pass 1 and Pass 2. Any discrepancy
causes a phase error.
Q Questionable. A broad class of warnings issued when the
assembler finds ambiguous language.
R Relocation error.
U Undefined Symbol.
V Symbol used to control the assembler is undefined.
X Error in defining or calling a macro during Pass 1.
3.6.3. MCRxxx Messages
These appear at your terminal during assembly, and are followed by an English
phrase that explains the problem, e.g.
MCRCFU - CANNOT FIND UNIVERSAL
The MCRxxx messages should be more or less self-explanatory.
Monitor Calls Page 73
4. Introduction to Tops-20 Monitor Calls
4.1. Introduction
This document contains all the information you need to do certain basic
monitor calls (mostly those for input/output) from assembly language programs
on the DECSYSTEM-20. Only a few of the many existing monitor calls are
described, and these are not always described in complete detail. Any
information not covered here can be found in most recent edition of the
DECSYSTEM-20 Monitor Calls Reference Manual.
Knowledge of the KL10 (DECSYSTEM-20) instruction set, and of an assembler
(preferably Macro-20), is assumed. All numbers in the following text, except
bit positions (which are always decimal), are octal (base 8) unless otherwise
noted.
4.2. General Information
Monitor calls are invocations of subroutines in the Tops-20 monitor. A DEC-20
monitor call is known as a JSYS (Jump to System). All JSYS's have opcode 104,
which is trapped by the monitor which in turn looks at the address field of
the instruction to find out which JSYS is being called. The following
conventions apply to all JSYS's:
Arguments for the JSYS are placed in accumulators (AC's). The first argument
is in AC1, the second in AC2, and so forth up to a maximum of four AC's. If
more than four arguments need to be passed, they are placed in an argument
block pointed to by an AC.
Results are also returned in AC's 1-4; if more than 4 results are to be
returned, they are returned in a block of memory whose address was specified
in the calling sequence. Any AC which does not return a result should have
the same contents after the call as before.
After execution of the JSYS, control is returned to the caller at one of two
locations. The +1 return (calling location plus 1) is often used to indicate
failure of the JSYS to perform its intended function, and an error code is
stored somewhere to indicate the exact cause of the failure. The +2 return is
used to indicate successful completion of the JSYS.
However, some JSYS's have only a single return to the instruction following
the call (+1) regardless of success or failure; this is the newer convention.
For this reason, it is generally not wise to depend on the +1/+2 convention;
another mechanism has been provided which should be used instead: erjmp/ercal.
Erjmp (which assembles as 'jump 16,') causes a jump to the specified location
if the JSYS, which must precede it immediately, failed. Ercal ('jump 17,')
works in the same way except it 'calls' rather than 'jumps'. Each JSYS, upon
encountering an error, inspects the contents of the instruction following the
JSYS call. If it is an erjmp or ercal, it takes the indicated action; if not,
it returns +1 or +2 according to its definition.
Every JSYS error has an associated error message, which provides a one-line
English description of the error, e.g.
Monitor Calls Page 74
?Directory access privileges required
The erring JSYS does not print the message; other JSYS's are provided to print
these error strings in a standard way (on the left margin, preceded by a
question mark). In general, recovery from a JSYS error involves printing the
error message and then either halting or going to some special section of code
that takes corrective action. Since these cases are overwhelmingly common,
let us assume that a special macro, called %jsErr, has been provided to take
care of them. It has the following format:
%jsErr message,address
If the message is specified, it is printed as a standard error message; if
not, the appropriate system-defined JSYS error message is printed. If the
address is specified, control will transfer to it after the message is
printed, otherwise the program will halt (but can be continued at the
instruction following the %jserr). Here are some examples (shown without
setting up the AC's):
GTJFN ; JSYS to Get Job File Number.
%jsErr ; Print standard message and halt on error.
GTJFN
%jsErr <Can't get the JFN> ; Print custom message, then halt.
GTJFN
%jsErr (,foo) ; Print standard message then go to foo.
A couple more examples not using the macro:
GTJFN
erjmp foo ; Go to foo on error.
GTJFN
ercal baz ; Call subroutine baz on error.
GTJFN
ercal [setz t1 ; Execute these instructions on error.
movei t2, 1
ret ] ; (ret = 'popj 17,')
movem t1, injfn ; Come here regardless of success or failure.
GTJFN
erjmp [setz t1 ; On failure, execute these instructions
movei t2, 1 ; ...
jrst foo ] ; then go to foo.
movem t1, injfn ; Come here only on success.
Erjmp and ercal are defined in monSym (i.e. in sys:monSym.unv) for Macro
programs, and predefined for Midas programs. %jsErr is defined, for Macro, in
CUSYM; jsErr is defined for Midas in MAC:MacSym.mid.
Monitor Calls Page 75
4.3. Using Mnemonic Symbols
Most JSYS's include among their arguments a number of arbitrarily chosen
numeric constants, including special numbers to designate the source for input
or output, and bits that can be on or off depending on whether the
corresponding option is selected. These bits are listed in the description of
each JSYS. Of course it is possible to write the (possibly combined) bits as
octal constants, but this would be extremely poor programming practice,
because the resulting code would be unreadable. Therefore, symbols have been
defined to stand for each bit. These symbols have some mnemonic value, and
they should always be used. The definitions appear in SYS:MONSYM.UNV, and you
access them from your Macro program by including the "search monSym"
directive. (Midas has the symbols built in.)
Some of the very common symbols that are not specific to any particular JSYS
are:
Value:
Symbol Left Half Right Half Meaning
------ --------- ---------- -------
.PRIIN 0 100 Primary input (usually TTY)
.PRIOU 0 101 Primary output (ditto)
.FHSLF 0 400000 Fork Handle Self (current process)
When a JSYS has option bits, these have symbols of the form JJ%NNN, where JJ
denotes which JSYS, and NNN denotes the option. The % is included to prevent
confusion with user defined symbols (which should not be of this form), and to
emphasize that the symbol stands for a JSYS bit. Examples:
Symbol JSYS Bit Meaning
------ ---- --- -------
GJ%NEW GTJFN 1 Want JFN for a new file.
GJ%OLD GTJFN 2 Want JFN for an old (i.e. existing) file.
OF%RD OPENF 19 Want to open a file for read access.
OF%WR OPENF 20 Want to open a file for write access.
4.4. Source/Destination Designators
Many monitor calls operate on or transmit byte streams; a byte stream is a
sequence of bytes of some size from 1 to 36 bits, most commonly 7 bit bytes
(ASCII text) or 36 bit bytes (machine words). The source or destination of
these bytes can be any one of several items, including a file, a terminal, or
a string in the caller's address space. In these cases, a standard 36-bit
quantity, called the source/designation designator, is used as a JSYS argument
to declare the byte stream on which to operate. It can have various formats;
these are the most common:
Monitor Calls Page 76
Value:
Symbol Left Half Right Half Meaning
------ --------- ---------- -------
(none) 0 a JFN Job file number, i.e. a file.
.PRIIN 0 100 Primary input (usually TTY).
.PRIOU 0 101 Primary output (usually TTY).
(none) reasonable address Pointer to beginning of a string
left half of in the caller's address space.
byte pointer.
(none) 777777 address Equivalent to 440700,,address,
i.e. a 7-bit byte pointer.
The monitor can tell which type of designator is intended either from its
format or from option settings which you provide. The last format is provided
to allow you to write
hrroi t1, [asciz/foo/]
rather than
move t1, [point 7, [asciz/foo/]] ; Macro
or
move t1, [440700,,[asciz/foo/]] ; Midas or Macro
This saves a memory reference, and it's easier to type. But it only works for
JSYS's, not for byte instructions; the JSYS internally translates 777777 in
the left half of a source/destination designator to 440700.
Note that JSYS's usually assume that an input byte string in memory (i.e. one
pointed to by a byte pointer) ends with a zero byte; strings are usually kept
in memory in this format, which is known as ASCIZ (7-bit ASCII, terminated by
zero).
4.5. Setting up a JSYS Invocation
You may have noticed that some of the JSYS bits described above fall in the
left half of the word, while others fall in the right half. This means that
to load the AC's with the appropriate bits could require different
instructions. Since programs should not depend on the actual values of the
symbols for JSYS bits, a macro is provided to free you from worrying about
whether a given symbol is a left-half or right-half quantity: the macro is
called MOVX; it translates to the appropriate instruction based on its
argument, e.g. if
JS%FOO = bit 35
JS%BAZ = bit 0,
() swaps its contents,
[] specifies the address of the enclosed quantity, and
! is the logical OR operator, then:
Monitor Calls Page 77
movx t1, JS%FOO (becomes) movei t1, JS%FOO
movx t1, JS%BAZ (becomes) movsi t1, (JS%BAZ)
movx t1, JS%FOO!JS%BAZ (becomes) move t1, [JS%FOO!JS%BAZ]
If you would rather avoid movx, you can use the third form; it will always
work, but it often costs an extra memory reference (and a little more typing).
One final complication: some JSYS arguments consist of fields which must take
on certain values. The desired value must somehow be logically ANDed with a
mask of 1's that specifies the field. For instance, the NOUT JSYS (which
outputs a number according to a format which you specify) accepts as one of
its arguments, the number of columns in which to print the number. This field
happens to be in bits 11-17. If you want the number to be printed in a field
of, say, 5 columns, you must put a 5 right-justified in bits 11-17. This
field has a name, NO%COL, and it assembles as 000177000000. It would be hard
to imagine how to logically AND a 5 with this field at assembly time.
Fortunately, a macro is provided for this purpose: FLD(value,mask), which in
this case would be written FLD(5,NO%COL). The result here is 000005000000,
which in turn can be logically ORed with other bits and fields to provide all
the information needed for the JSYS to return the desired result.
The FLD and MOVX macros are defined for Macro-20 in SYS:MACSYM.UNV.
Here's a fullblown example, in which the NOUT JSYS is set up to print a
number, which is stored at location foo, on the terminal in a field of 5
characters, usigned, with leading blanks, in base-4 notation. First, the
symbol definitions are reproduced from MONSYM:
Symbol Bit(s) Meaning
------ ------ -------
NO%MAG 0 Output the magnitude (i.e. unsigned).
NO%LFL 2 Output leading filler specified by NO%ZRO.
NO%ZRO 3 Output 0's as leading filler.
If off, output 1's as leading filler.
NO%COL 11-17 Number of columns to output.
NO%RDX 18-35 Radix (2-36) of number being output.
Now here's the actual JSYS setup and call:
movx t1, .PRIOU ; Output goes to terminal.
move t2, foo ; The number is stored in foo.
movx t3, NO%MAG!NO%LFL!fld(5,NO%COL)!fld(4,NO%RDX) ; Format.
NOUT ; Number Out JSYS.
%jserr ; Print message and halt on error.
This should be sufficient background for you to understand the descriptions of
the specific JSYS's.
4.6. JSYS's to Open and Close Files
A file in Tops-20 is identified by its device name, directory name, filename,
file type, and generation number. These 5 items uniquely identify any file on
the system that is accessible to a user. The device name identifies the
device on which the file is stored (or it can be a "logical device name" that
Monitor Calls Page 78
specifies a list of one or more devices and/or directories which is to be
searched for the file); the directory name identifies the directory containing
the file. The filename, type, and generation number identify a particular
file in the given device and directory.
Tops-20 requires references to files to be via "handles" that can be contained
in a few bits (a halfword, really) and do not require extensive lookup
procedures for each reference. Such a handle is called a JFN (Job File
Number); it is a small integer, valid within a particular job (even if the job
consists of many processes) but not valid across jobs; JFN 2 in job 11 will
generally be a handle on a completely different file than JFN 2 in job 18.
A JFN is associated with a file by means of the GTJFN (Get JFN) monitor call,
which accepts a file specification and returns a JFN for the indicated file.
The special JFN's 100 ( .PRIIN) and 101 ( .PRIOU) are reserved for the primary
input and output designators, respectively, and are never returned by the
GTJFN call.
To do i/o (input/output) to a file, you must first get a JFN for it, using
GTJFN. You must then open the file by giving the JFN to the OPENF JSYS. Then
you can use various monitor calls to actually transfer data. When you are
finished with the file, you must close it using the CLOSF monitor call.
These essential monitor calls are now described, but not in complete detail.
For the more esoteric features, refer to the Monitor Calls Reference Manual.
The examples shown here are for Macro programs. In general the only
difference between Macro and Midas (for these examples) the logical OR
operator (in Macro, it's "!"; in Midas it's "\")
4.6.1. GTJFN (JSYS 20) - Get Job File Number (short form)
Returns the JFN for the specified file. Accepts the specification for the
file from a string in memory or from a file (possibly a terminal) but not
both. If the source is the terminal, recognition can be done. One or more
fields of the file specification can be represented by a logical name. If any
fields are omitted, the system will provide default values as follows:
Device Connected structure.
Directory Connected directory.
Name No default; must be specified.
Type Null.
Generation Highest existing (input file); next higher (output).
Accepts in AC1: Flag bits in the left half, default generation number
in the right half (usually 0).
AC2: Source designator from which to obtain the file
specification (see description of flag bit GJ%FNS).
Returns: +1: Failure, error code in AC1.
+2: Success, flags in the left half of AC1, and the JFN
in the right.
Flag bits:
Monitor Calls Page 79
Symbol (Bit(s)) Meaning
GJ%FOU (0) (File OUtput) The file given is to be assigned the next higher
generation number; this bit indicates that a new version of a
file is to be created and is normally set if the file is for
output use.
GJ%NEW (1) The file specification must not refer to an existing file,
i.e. the file must be a new file.
GJ%OLD (2) The file specification given must refer to an existing file,
i.e. the file must be an old file. Note: if you want to open a
file in ' append' mode (i.e. you want to create a new file if
none exists, or else write to the end of an existing file),
don't specify GJ%OLD or GJ%NEW, and use OF%APP in the OPENF
call (see below).
GJ%CFM (4) ConFirMation from the user will be required (if GJ%FNS is on)
to verify that the file specification is correct. This
generally means that the user will have to type carriage
return after typing the file specification.
GJ%FNS (16) (File Name Source) The contents of AC2 are to be interpreted
as follows:
1. If this bit is on, AC2 contains an input JFN in the
left half, and an output JFN in the right. The
input JFN is used to obtain the file specification
to be associated with the JFN. The output JFN is
used to indicate the destination for printing the
names of any fields being recognized. To omit
either JFN, specify .NULIO (377777). This option
is generally used when the file specification is
being obtained from the terminal, and recognition
is being performed. The JFN's will normally be
.PRIIN and .PRIOU.
2. If this bit is off, AC2 contains a pointer to an
ASCIZ string in memory that specifies the file to
be associated with the JFN.
GJ%SHT (17) This bit should always be on to indicate that the long form of
GTJFN is not being used (the long form requires extra input).
(none) (18-35) The generation number of the file. Usually one of the
following:
1. .GJDEF (0) - the normal case - to indicate that the
next higher generation number of the file is to be
used if GJ%FOU is on, or that the highest existing
generation of the file is to be used if GJ%FOU is
off.
2. .GJNHG (-1) - to indicate that the next higher
generation number is to be used if no generation
number is supplied.
To translate a JFN to its corresponding filename string, see the description
Monitor Calls Page 80
of JFNS in the Monitor Calls Reference Manual.
Examples:
; Get a JFN from a filename string in memory.
movx t1, GJ%OLD!GJ%SHT ; For an "old" file
hrroi t2, [asciz/foo.txt/] ; called "foo.txt",
GTJFN ; get a Job File Number.
%jsErr ; Print message and halt on error.
hrrzm t1, iJfn ; Save the JFN in location "ijfn".
Note the "hrrzm", rather than "movem". This eliminates the extraneous flags
that are returned in the left half, which could cause errors in some
applications that don't need them (most don't).
; Get a JFN from the terminal, allowing recognition.
movx t1, GJ%OLD!GJ%FNS!GJ%CFM!GJ%SHT ; Old, tty i/o, confirm.
move t2, [.PRIIN,,.PRIOU] ; Get filename from terminal.
GTJFN ; Get the JFN.
%jsErr (,err) ; Print msg & go to "err" on error.
hrrzm t1, iJfn ; Save the result.
4.6.2. OPENF (JSYS 21) - Open a File
Opens the given file. No data transfer can be done until the file is open.
Accepts in AC1: JFN of the file being opened, in the right half.
AC2: Various control information, including:
Symbol Bit(s) Meaning
------ ------ -------
OF%BSZ 0-5 Byte size (maximum 36 decimal)
OF%RD 19 Allow read access.
OF%WR 20 Allow write access.
OF%APP 22 Allow append access.
OF%PLN 30 Disable line number checking and consider a line number
as 5 characters of text. If this bit is off, line
numbers will be discarded automatically.
Returns: +1: Failure, error code in AC1.
+2: Success.
No values are returned.
Monitor Calls Page 81
Example:
; Open an old file for read access.
move t1, iJfn ; The JFN already obtained by GTJFN.
movx t2, fld(7,OF%BSZ)!OF%RD ; 7-bit bytes, read access desired.
OPENF ; Open the file.
%jsErr (<Can't open the file>,fail) ; Print this message and
; go to location "fail" on error.
4.6.3. CLOSF (JSYS 22) - Close a File.
Closes a specific file.
Accepts in AC1: Flags, normally 0, in left half, JFN in right half.
Returns +1: Failure, error code in AC1.
+2: Success.
No value is returned.
Flags:
CO%NRJ (0) Do not release the JFN.
CO%ABT (6) abort any output operations currently being done. Close the
file, but do not perform any cleanup operations normally
associated with closing a file (e.g. do not output remaining
buffers). If output to a new disk file that has not been
closed (i.e. is nonexistent) is aborted, the file is closed
and then expunged.
Example:
; Close a file
move t1, ijfn ; Get the JFN into AC1.
CLOSF ; Close the file.
%jsErr (,.+1) ; On error, print message but continue.
4.7. File i/o JSYS's
There are three ways to do file i/o: by character (byte), by character string
(byte string), and by page. Of these, only the first two will be discussed.
For paged i/o see the Monitor Calls Reference Manual.
When doing input, whether byte- or string-oriented, you must always be
prepared to handle errors, and to distinguish a normal end-of-file (eof) error
from other errors. A monitor call is provided that can be used for this
purpose (among others):
Monitor Calls Page 82
4.7.1. GTSTS (JSYS 24) - Get file Status
Returns the status of a file associated with a JFN.
ACCEPTS in AC1: JFN in the right half.
Returns: +1: always, with JFN status word in AC2. If the JFN is
illegal in any way, bit GS%NAM will be 0.
The JFN Status Word has the following format:
Symbol Bit Meaning
------ --- -------
GS%OPN 0 File is open.
GS%RDF 1 Read access is allowed.
GS%WRF 2 Write access allowed.
GS%EOF 8 Last read was past end of file.
GS%NAM 10 A file specification is associated with this JFN.
If GS%OPN is 0, then the settings of the other bits are meaningless. There
are other bits and fields in the JFN Status Word; for these, see the Monitor
Calls Reference Manual.
When testing the status word for some (combination of) bit(s), you are faced
with a situation similar to loading some combination of option bits into an AC
for a JSYS call, i.e. you don't know (or at least you shouldn't depend on)
whether the bits form a left-half, right-half, or fullword quantity, and
therefore you don't know which test instruction to use (tl--, tr--, ts--, or
td--). Of course, td-- will always work if you put the argument in square
brackets, but this requires an extra memory fetch at runtime. For this
reason, a set of tx-- macros have been defined that are analogous in purpose
and operation to the "movx" macro described above. You can always use a tx--
without worrying about the actual value of the quantity being tested. These
comments apply not just to testing the JFN status word, but to testing any
word for symbolically defined bits.
Example (assume that a JSYS error has just occurred during input):
; Check for end of file.
move t1, iJfn ; Load the JFN of the input file.
GTSTS ; Get the status of the file.
txnn t2, GS%EOF ; Are we at eof?
jrst error ; No, must be some other error.
; Come here on end of file.
4.7.2. Sequential Byte i/o
The following JSYS's input or output bytes sequentially.
Monitor Calls Page 83
4.7.2.1. BIN (JSYS 50) - Byte In
Inputs the next byte from the specified source. When the byte is read from a
file, the file must first be opened, and the size of the byte given, with the
OPENF call. When the byte is read from memory, a pointer to the byte is
given; this pointer is always updated after the call (a BIN to a character
string in memory is equivalent to an ildb instruction).
Accepts in AC1: source designator (JFN or byte pointer)
Returns +1: always, with the byte right-adjusted in AC2.
If the end of file is reached, AC2 contains 0 and an erjmp or ercal
instruction following the BIN call will be activated (but note that end of
file is not the only error possible).
4.7.2.2. PBIN (JSYS 73) - Primary Byte In
Like BIN, but always obtains the byte from the primary input source (i.e. the
.PRIIN JFN, usually the terminal). Needs no input.
Returns: +1: always, with byte right-adjusted in AC1.
Various errors are possible, including end-of-file.
4.7.2.3. BOUT (JSYS 51) - Byte Out
Outputs a byte sequentially to the specified destination. When the byte is
written to a file, the file must first be opened, and the size of the byte
given, with the OPENF call. When the byte is written to memory, a pointer to
the location in which to write the byte is given in AC1. This pointer is
updated after the call.
Accepts in AC1: destination designator (JFN or byte pointer).
Returns +1: always.
Various errors are possible.
4.7.2.4. PBOUT (JSYS 74) - Primary Byte Out
Like BOUT, except byte always goes to the primary output destination (i.e. the
.PRIOU JFN, usually the terminal).
Accepts in AC1: byte to be output, right-justified.
Returns: +1: always.
Various errors are possible.
Monitor Calls Page 84
4.7.2.5. Example of Byte i/o
; This program segment reads bytes one at a time from a file whose
; JFN is stored in location "iJfn". If a byte is null (zero), it is
; discarded, otherwise it is written to the output file, whose JFN
; is stored in location "oJfn". Both files are assumed to be open.
copy: move t1, iJfn ; Load input JFN into t1.
BIN ; Get next byte.
erjmp tstEof ; On error, go test for eof.
jumpe t2, copy ; If the character was zero, ignore it.
move t1, oJfn ; Load output jfn into t1.
BOUT ; Write the byte to the output file.
%jsErr ; Print message and halt on error.
jrst copy ; Loop for all bytes in file.
; Come here on error in the BIN JSYS. Check for end of file.
tsteof: GTSTS ; JSYS to Get file Status (JFN is in t1).
txnn t2, GS%EOF ; Was it an eof?
%erMsg (,done) ; No, print the error message and finish up.
; Here when we've copied the entire file.
done: move t1, iJfn ; Close the input file
CLOSF ; using the CLOSF JSYS.
%jsErr (,.+1) ; On error, print message but continue.
move t1, ojfn ; And close the ouput file too.
CLOSF
%jsErr (,.+1)
; End of program fragment.
Note the %erMsg macro; it is identical to %jsErr, except that it is executed
unconditionally rather than via erjmp or ercal. It is mainly intended for use
after a skipping instruction or subroutine call.
4.7.3. String-oriented i/o
The following JSYS's input or output byte strings.
4.7.3.1. SIN (JSYS 52) - String In
Reads a string from the specified source into the caller's address space. The
string can be a specified number of bytes or terminated with a specified byte.
Monitor Calls Page 85
Accepts in AC1: Source designator (JFN or byte pointer).
AC2: Pointer to string in the caller's address space (destination).
AC3: Count of number of bytes to input, or 0.
AC4: Byte (right-justified) on which to terminate input (optional).
Returns: +1: Always, with updated string pointers in AC1 and AC2
(if pertinent), and updated count in AC3 (if pertinent).
The contents of AC3 controls the number of bytes to read as follows:
AC3=0 The string being read is terminated with a 0 byte.
AC3>0 A string of the specified number of bytes is to be read or a
string terminated with the byte given in AC4 is to be read,
whichever occurs first.
AC3<0 A string of minus the number of bytes is to be read.
AC4 is ignored unless AC3 contains a positive number.
An end of file can be processed as in the example above. After execution of
the call, the file's pointer is updated for subsequent i/o to the file. AC2
is updated to point to the last byte read or, if AC3 contained 0, the last
nonzero byte read. The count in AC3 is updated toward 0 by subtracting the
number of bytes read from the number of bytes requested to be read. If the
input was terminated by an end-of-file condition, AC1 thru AC3 are updated
(where pertinent) to reflect the number of bytes transferred before the end of
file was reached.
Various errors, besides eof, are possible (e.g. invalid JFN, file not open,
device or data error, etc.).
Note: The source JFN can be .PRIIN (i.e. the terminal), but SIN is
not the best JSYS to use for input of strings from the terminal,
because it does not allow for editing (via DEL, ^U, ^W, and ^R) or
prompting. Terminal string input is best done using the TEXTI or
RDTTY JSYS (RDTTY is described below); better still, all terminal
input can be done using the COMND JSYS (Chapter 5), which allows not
only prompting and editing, but automatic help and recognition, as
well as syntax checking for all sorts of fields (numbers, file names,
keywords, etc). For TEXTI and COMND, refer to the Monitor Calls
Reference Manual.
4.7.3.2. SOUT (JSYS 53) - String Out
Writes a string from the caller's address space to the specified destination.
The string can be a specified number of bytes or terminated with a specified
byte.
Monitor Calls Page 86
Accepts in AC1: Destination designator.
AC2: Pointer to string to be written.
AC3: Count of the number of bytes to be written, or 0.
AC4: Byte (right-justified) on which to terminate output.
Returns: +1: Always, updated string pointers and counts in the
AC's, if pertinent.
Interpretation of the arguments is exactly the same as by SIN, and the
operation is entirely analogous, but in the opposite direction.
4.7.3.3. PSOUT (JSYS 76) - Primary String Out
A short form of SOUT (there is no corresponding short form of SIN). Outputs a
string sequentially to the primary output destination (usually the terminal).
Accepts in AC1: Pointer to ASCIZ (zero-terminated) string in the
caller's address space.
Returns: +1: Always, with updated string pointer in AC1.
As usual, various errors are possible (usually an invalid byte pointer is the
culprit).
Monitor Calls Page 87
4.7.3.4. Example of String I/O
This program fragment copies the input file (which is already opened in 7-bit
mode and whose JFN is stored in location "iJfn") to the output file (open
similarly, JFN in "oJfn"), a string at a time, where a string is considered to
be a sequence of bytes terminated by a linefeed, but of maximum lenth 512
(decimal). Note that the linefeed character is represented symbolically; this
is considered good technique because it makes the program more readable. The
symbolic definitions of the (nonprinting) ASCII control characters are
obtained by searching MACSYM.
maxLen=^d512 ; Define maximum length symbolically.
buffer: block <maxlen/5+1> ; String buffer (convert bytes to words).
:
:
copy: move t1, iJfn ; Load the input file JFN.
hrroi t2, buffer ; Point to place in memory to put string.
movei t3, maxLen ; Maximum number of characters.
movei t4, .CHLFD ; Terminate on the CHaracter LineFeeD.
SIN ; Read the string into the buffer.
erjmp tstEof ; On error, go test for eof.
; Now write the string into the output file. Note that t3 contains
; <maxlen - <length of string>>. We can't count on the presence of the
; terminating linefeed because input may have exhausted the maximum byte
; count before a linefeed was encountered.
move t1, oJfn ; Load the output file JFN.
hrroi t2, buffer ; Point to the string to be written.
subi t3, maxLen ; Get negative length into t3.
SOUT ; Write the string out.
%jserr (,done) ; Print message and finish up on error.
jrst copy ; Loop for all strings in file.
tstEof: GTSTS ; JFN of input file already in t1.
txnn t2, GS%EOF ; Error caused by end of file?
%ermsg (,done) ; No, print message and finish up.
done: hrroi t1, [asciz /All done/] ; Type this message
PSOUT ; at the terminal.
; Now just close the files in the normal way.
; (end of program fragment)
4.7.3.5. RDTTY (JSYS 523) - Read string interactively from TTY
RDTTY is the JSYS most suited to simple terminal input; it is a subset of the
TEXTI JSYS, which is much more flexible, more powerful, but more complicated
to use (see the Monitor Calls Reference Manual for details on TEXTI and full
Monitor Calls Page 88
details on RDTTY). We will describe the most useful options of the RDTTY
JSYS.
RDTTY is most suited for interactive terminal input because it lets the user
edit her/his input, on a line-by-line (or several-line) basis, before it's
"eaten" by the program. All the editing characters, viz., ^R, ^W, ^U, ^L, and
RUBOUT, are available for editing (though no recognition is possible, since
command parsing is not being done). There are basically two ways to call
RDTTY: to read a single line (up to a carriage-return or line-feed), and to
read a whole group of lines (up to a ^Z or ESCAPE). In the single-line mode,
the program receives each line as the user types it, and thus only permits
editing on a single-line basis; in the line-group mode, the user can enter any
number of lines (limited only by the size of your input buffer) and edit all
the way back to the beginning of input (for example, MM and Mail use the
1
line-group mode to collect the text of messages to be sent).
The RDTTY JSYS reads input from the primary input port ( .PRIIN), until either
a break character is seen (such as ^Z or carriage-return) or the given byte
count is exhausted (which means your buffer is full). Output generated as a
result of editing the input text (such as echoing of deleted characters after
backslashes, as in "foo<RUBOUT><RUBOUT>ee", which echoes as "foo\o\oee" on a
hardcopy terminal) goes to the primary output port (.PRIOU). .PRIIN and
.PRIOU normally designate the user's terminal (TTY) as an both input and
output device, respectively.
Accepts in AC1: pointer to string in caller's address space where
input is to be placed.
AC2: control bits in left half, as described below, and
number of bytes available in the buffer (pointed to
by AC1) in the right half.
AC3: 0, if no prompt is wanted, or
byte pointer to prompting text (^R) buffer.
Returns: +1: failure, error code is in AC1.
+2: success, updated string pointer in AC1, appropriate
bits set in the left half of AC2, and updated count of
available bytes in the right half of AC2.
Note that the prompting text buffer is not automatically output by RDTTY; you
have to output it yourself before doing the RDTTY (but it will be output
properly if ^R or ^L is typed during user input).
The control flags in the left half of AC2 are broken into two groups: those
given to RDTTY, and those returned (see the Monitor Calls Manual for a
---------------
1
If you need to read in a group of text lines, even a large group, it's
advisable to use the the line-group mode of RDTTY, since memory is 'cheap':
just give RDTTY a large buffer area; this makes things much easier for the
poor, fallible human out there.
Monitor Calls Page 89
complete description of the control flags).
Symbol (Bit(s)) Meaning
Given to RDTTY in AC2:
RD%BRK (0) BReaK on ^Z or ESCAPE (i.e., line-group mode)
RD%BEL (3) Break on End of Line (carriage return or linefeed, i.e.,
single-line mode)
RD%RAI (10) RAIse user input: convert lower case to upper case
Returned from RDTTY in AC2:
RD%BTM (12) Break character TerMinated input: if this is set, the input
was terminated because a break character was seen; if not,
then input was terminated because the buffer is full (as
determined by the byte count given in the right half of AC2)
4.7.3.6. RDTTY Example
The following example uses the RDTTY JSYS to collect a "note", or a group of
lines about some subject, and write it all to a file (which is opened and
closed elsewhere).
; Data area
maxLen==^d10000 ; Allow 10k characters in note input.
prompt: asciz/Text of note (end with ^Z or ESCAPE): /
inBuf: block maxLen/5 + 1 ; Input buffer.
oJfn: block 1 ; Output JFN.
.
.
.
Monitor Calls Page 90
; Assume oJfn is set up with the output file JFN.
note: hrroi t1, prompt ; Prompt for the note.
PSOUT ; ...
hrroi t1, inBuf ; Get a pointer to destination buffer.
movx t2, <RD%BRK!maxLen> ; Break on ^Z, ESC, up to buffer size.
hrroi t3, prompt ; Use prompt on ^R, etc.
RDTTY ; Read the note.
%jsErr ; Die loudly if fails.
hrrz t3, t2 ; Get remaining byte count.
movns t3 ; Negate it and add to maxLen to get
add t3, [maxLen] ; number of bytes input.
hrroi t1, inBuf ; What we want to output.
move t2, oJfn ; Get destination JFN,
SOUT ; and output what we just read.
%jsErr ; Handle failure nicely.
.
.
4.7.4. Number conversion JSYS's
These are similar to string i/o JSYS's in that their input or output is a
string (in memory or in a file), but the string is the ASCII character
representation of a number in some base, and conversion is done either from
the internal form of the number to the string or vice versa.
4.7.4.1. NIN (JSYS 225) - Number In
Inputs the character-string representation of an integer number, ignoring
leading spaces. This call terminates on the first character not in the
specified radix. If that character is a carriage return followed by a line
feed, the line feed is also input.
Accepts in AC1: Source designator (JFN or byte pointer).
AC3: Radix (2-10) of number being input.
Returns: +1: Failure, error code in AC3, updated string pointer
(if pertinent) in AC1.
+2: Success, internal two's complement binary representation
of number in AC2, and updated string pointer (if
pertinent) in AC1.
Various errors are possible (invalid JFN, file not open, invalid radix, first
nonspace character not a digit, overflow, etc.). It is not advisable to use
NIN to input a number from the terminal because NIN does not allow editing and
reprompting, as does RDTTY; RDTTY should be used to get the string
representation of the number into memory, and then NIN should be used to
Monitor Calls Page 91
convert the string to a number; if the string contains invalid characters, the
error can be caught and the user can be informed and reprompted (by a
%jsErr (,foo) after the NIN, where foo is the address of the RDTTY sequence).
This technique is shown in a subsequent example.
4.7.4.2. NOUT (JSYS 224) - Number Out
Outputs an integer number to a file or to a string in memory.
Accepts in AC1: Destination designator.
AC2: Number to be output.
AC3: Format control information as follows:
Symbol (bit(s)) Meaning
NO%MAG (0) Output the magnitude. That is, output the number as an
unsigned 36-bit number (e.g. output -1 as 777777777777 in base
8).
NO%SGN (1) Output a plus sign for a positive number.
NO%LFL (2) Output leading filler. If this bit is not set, trailing
filler is output, and bit NO%ZRO is ignored.
NO%ZRO (3) Output 0's as the leading filler if the specified number of
columns (NO%COL) allows filling. If this bit is not set,
blanks are output as leading filler if the number of columns
allows filling.
NO%OOV (4) Output on column overflow and return an error. If this bit is
not set, column overflow is not output.
NO%AST (5) Output asterisks on column overflow. If this bit is not set
and NO%OOV is set, all necessary digits are output on column
oveflow.
NO%COL (11-17) Number of columns (including the sign column) to output is
right-justified in this field. If this field is 0, as many
columns as necessary are output.
NO%RDX (18-35) Radix (2-36) of number being output.
Returns: +1: Failure, error code in AC3.
+2: Success, updated string pointer in AC1, if pertinent.
Various errors are possible, including NOUTX2 (column overflow), plus those
that are possible for NIN.
Monitor Calls Page 92
4.7.4.3. NIN/NOUT Example
Here, the user is prompted at the terminal to type in a decimal number. The
number is then typed back to the user, in octal (base 8) notation,
right-adjusted in a field of width 9.
prompt: asciz /Decimal number: / ; The prompt.
numLen=^d20 ; Length of buffer for number string.
numBuf: block numLen ; The input buffer.
:
:
reTry: hrroi t1, prompt
PSOUT ; Prompt the user for a decimal number.
; Get the alleged number from the terminal into memory in string form.
hrroi t1, numBuf ; Point to buffer for string that user types.
movx t2, RD%BEL!numLen ; Break on CRLF, max length for typein.
hrroi t3, prompt ; Reprompting text.
RDTTY ; Get string, allowing editing.
%jsErr (,reTry) ; Print message & reprompt on error.
; Now convert the string to a number.
hrroi t1, numBuf ; Point to string representation of number.
movei t3, ^d10 ; Radix for interpretation.
NIN ; Number In - do the conversion.
%jsErr (,reTry) ; On error, print msg and ask again.
; Now type it back, converting to octal notation. The number is still in t2.
movx t1, .PRIOU ; Output is to primary output destination.
movx t3, NO%MAG!NO%LFL!NO%AST!fld(^d9,NO%COL)!fld(^d8,NO%RDX)
NOUT ; Type the number.
%jserr (,prompt) ; On error, print message and reprompt.
; (end of program fragment)
Similar monitor calls ( FLIN and FLOUT) exist for input and output of floating
point numbers; see the Monitor Calls Reference Manual for these.
Monitor Calls Page 93
4.7.5. Random-access i/o
Tops-20 gives you the ability to randomly access files on disk storage, which
is the only kind of device which supports this type of access (other than
DECtape, which is now essentially defunct in "DEC land").
As described earlier, disk files can be considered to be merely a sequence of
bytes, of some size from 1 to 36 bits (the normal sizes are 7, for text files,
and 36, for binary, word-oriented files); the byte size of the file is
determined at the time of the OPENF for the file (and can thus be changed from
open to open, if you're daring). Each byte in the file has a label, or index,
which is its position in the sequence, starting at zero. For example, the
text file containing the 15 ascii bytes "This is a file." can be considered to
be a sequence of bytes, as follows:
Index Byte Value Index Byte Value
0 "T" 124 8 "a" 141
1 "h" 150 9 " " 040
2 "i" 151 10 "f" 146
3 "s" 163 11 "i" 151
4 " " 040 12 "l" 154
5 "i" 151 13 "e" 145
6 "s" 163 14 "." 056
7 " " 040
For example, the zero'th byte of the file is an ascii "T" (octal value 124),
the tenth byte is an ascii "f" (octal value 146), and the fourteenth, and
last, byte is a period, "." (octal value 056).
Although it's not important to understanding the notion of random-access i/o,
it's culturally interesting to note that disk files are stored in units of
pages, or 512 36-bit words, or 2560 (512*5) 7-bit bytes. Thus, the above
file, which is 15 bytes long, would occupy 3 (15/5) words, or one page. Why
one page? Because pages are the minimum unit of disk file storage, and thus,
the above file is "wasting" 509 words of disk space (this much of the one page
it uses is unoccupied). The 512 words-per-page is a hardware parameter, which
we can't do much about, so we'll accept this waste as reasonable, since files
are generally many pages in length (and the wasted portion is then
proportionally smaller).
Tops-20 keeps track of two items, when you're doing i/o with disk files: the
current byte index (the one you would read next if you did a BIN JSYS, or
write next if you did a BOUT), known in JSYS jargon as the 'file pointer', and
the end-of-file byte index, which is simply the length of the file, in bytes
(and is thus, conceptually, the non-existent byte after the last byte in the
file).
When you first open the file (with an OPENF), the file pointer is set
depending on how you opened the file. If you opened it for reading or writing
(or both), then the file pointer will be zero, i.e., you're initially
positioned to read or write the first (zero'th) byte in the file. If you
opened it for appending, then the file pointer is initially set to the
end-of-file byte index, i.e., you're positioned to read or write the byte
right after the last real byte in the file; in the case of a BIN this first
read will return a zero byte and indicate you're at end of file; in the case
of a BOUT this first write will simply extend the file by one byte.
For example, if you had done 15 BIN JSYS's on the sample file shown above
Monitor Calls Page 94
after opening it, on the 16th BIN you would be at end-of-file (i.e., there are
no more bytes to read), and Tops-20 would obey an erjmp instruction after the
BIN, going to where you specified (which would presumably check for a true
end-of-file condition and handle it appropriately). For a more graphic
example, after 10 BIN's, say, then the situation looks like:
Index Byte Value
0 "T" 124 <- byte read on the first BIN
: : :
8 "a" 141
9 " " 040 <- byte just read on the 10th BIN
10 "f" 146 <- file pointer (what will be
11 "i" 151 read by the next BIN)
12 "l" 154
13 "e" 145
14 "." 056
15 -none- <- end-of-file byte index
Thus, as mentioned in the previous example, when the file pointer becomes
equal to the end-of-file byte index (15 in this example), end-of-file is said
to be "reached". Of course, if you're writing a file, then the end-of-file
byte index is normally the same as the file pointer, since the file pointer
indexes the next byte to be read or written.
Of course, you can mix random-access i/o with sequential i/o in any old way,
and the results are very well-defined. The SFPTR JSYS simply sets the file
pointer to the next byte to be read or written; once it's set, you can merrily
BIN, BOUT, SIN and SOUT, and they'll take place at the file pointer position,
updating the pointer appropriately. Using the sample file from before,
imagine that you've done a SFPTR to the 4th byte (which is the space after
"This" - why isn't it the "s" in "This"?). Then, suppose you do a BOUT of a
"-" character to the file. The resulting situation will be:
Index Byte Value
0 "T" 124
1 "h" 150
2 "i" 151
3 "s" 163
4 "-" 055 <- file pointer after the SFPTR
5 "i" 151 <- file pointer after the BOUT
6 "s" 163
: : :
In a more 'cultural' vein, again, you should know that Tops-20 considers a
disk file to be a completely extensible sequence of bytes, i.e., it is
possible, and quite easy, to extend a file by simply positioning to the
end-of-file position (with the SFPTR JSYS, as described below) and writing
more bytes with BOUTs or SOUTs. The end-of-file byte index will be updated
appropriately. Even more, it's possible to position the file pointer to some
point way beyond the end-of-file index, and write more bytes. The file will
simply be extended appropriately with zero bytes, up to the point at which you
started writing (technically speaking, there may be some 'holes' in the file,
but they will look like zero, or null, bytes when you read over them; they
only matter if you don't like nulls, or are doing your own direct disk page
manipulation). For example, given the sample file above, if you positioned to
the 20th byte (which doesn't exist yet), and wrote the byte string "more.",
then the file would simply be extended, resulting in a file with 25 bytes,
with the end-of-file and file pointer equal to 25, and with the file
Monitor Calls Page 95
containing
This is a file.<0><0><0><0><0>more.
where the <0>'s represent null (zero) bytes.
There are basically four JSYS's designed for dealing with disk files in a
random (not purposeless!) fashion: read the current file pointer for a file
(RFPTR), set the file pointer for a file (SFPTR), read a byte from a file,
given its index (RIN, for Random IN), and write a byte to a file, given the
desired byte index (ROUT, for Random OUT).
4.7.5.1. RFPTR (JSYS 43) - Read File Pointer
Returns the current file pointer of the specified file.
Accepts in AC1: JFN of an open file.
Returns: +1: Failure, error code in AC1.
+2: Success, byte number (index) in AC2.
Actually, you can read the file pointer of a non-disk file, but it is either
meaningless or the number of bytes read so far from the file (e.g., in a tape
file). RFPTR can fail in various ways, but only if you don't give it a valid
JFN for an open file.
4.7.5.2. SFPTR (JSYS 27) - Set File Pointer
Sets the specified file's file pointer for subsequent i/o to the file. Note
that doing an SFPTR specifying a certain byte index, followed by a BIN or BOUT
JSYS, is the same as doing a RIN or ROUT JSYS, respectively, specifying the
same byte index.
Accepts in AC1: JFN of an open disk file.
AC2: byte index to which the file pointer is to be set,
or, -1 to set the pointer to the current end-of-file
index.
Returns: +1: failure, error code in AC1.
+2: success, file pointer has been set.
The SFPTR JSYS can fail in various ways, but only if you don't give it a valid
disk file JFN.
Monitor Calls Page 96
4.7.5.3. RIN (JSYS 54) - Random byte In
Inputs a byte nonsequentially (i.e., random byte input) from the specified
file. The size of the byte is that given in the OPENF call for the file.
Accepts in AC1: JFN of an open disk file.
AC2: byte index within the file of the byte desired.
Returns: +1: always, with the byte right-justified in AC2.
If the end of file is reached (i.e., you specify a byte index greater than or
equal to the end-of-file index), a zero is returned in AC2; this is not really
an error condition, but you can catch it if you want to with an erjmp or ercal
after the RIN. The file's file pointer is updated for subsequent sequential
i/o to the file. Several errors are possible, but not if you give it a real
JFN for a file opened in (at least) read mode (unless the file is opened for
append access only, in which case you can't change the file pointer, to avoid
letting you read the part of the file you're not supposed to see, e.g., a
mail.txt file with protection 770404).
4.7.5.4. ROUT (JSYS 55) - Random byte Out
ROUT outputs a byte nonsequentially (i.e., random byte output) to the
specified file. The size of the byte is that given in the OPENF call for the
file.
Accepts in AC1: JFN for an open disk file.
AC2: the byte to be output, right-justified.
AC3: the byte index within the file at which to write
the byte in AC2.
Returns: +1: always, with the byte written in the file.
The file byte pointer after the ROUT is C(AC3)+1 (i.e., the file pointer is
set to C(AC3), the byte is written, and the file pointer updated to account
for the byte just written). ROUT will always succeed if you give it a JFN for
a disk file opened for writing and ask it to write at a nonnegative byte index
that is less than the upper limit for the disk (you can have at most 512*512
pages (or 512*512*512 36-bit bytes) in a file); also, it may fail if you try
to ROUT to a file opened in append-only mode (because that would allow you to
change parts of a file you weren't supposed to access, such as a mail.txt file
protected at 770404).
Monitor Calls Page 97
4.8. Fork-Handling JSYS's
4.8.1. What's in a Fork?
To effectively use machine language on the DEC-20, you have to understand
something about what programs are, how they are born, how they live, and how
they die.
The term 'program' can be understood in many ways; most intuitively, because
it's in the form that we understand more easily, it means a text file in some
source language, such as Macro-20 or Pascal. But, this textual form of the
program must be processed by a translator (an assembler or compiler) to
produce a form more palatable to the actual machine. Even in this form, which
is normally a '.REL' or relocatable file, it isn't quite understandable to the
machine. It needs to go a further step, called linking, which involves
combining it with any other program segments which it needs to interact with
during execution by the machine (such as a language support package for doing
input/output, etc.). Once it's linked, the result can be saved as an '.EXE'
or executable file.
An executable file is nothing more than a program in vestigial or 'pure
potential' form, i.e., a data file with contents specifying how memory is to
be filled when it is incarnated as an active, or executing, program. We can
distinguish between a program in this passive state (the result of compiling,
linking and saving), from a program actually in execution by the Tops-20
system. Using this distinction, we can properly call the passive element
--the EXE file-- the 'program', and the active element --the part that
executes the program-- the 'process' or 'fork' (the latter is jargon used when
dealing with Tops-20 processes).
It may be helpful to think of the fork as a self-contained machine with a
well-defined 'control panel', or interface to the outside world. This control
panel has a set of 'knobs' for controlling it and objects which are dealt with
via 'handles'; the knobs and handles are manipulated by other forks, via
JSYS's. A fork, considered in this way, is a machine with power to follow
instructions, which come from the passive program (EXE file); a fork is loaded
up with its instructions by pulling in the program's pages from the EXE file.
Then, it can be started, temporarily stopped (frozen), continued, stopped,
etc. There also must be a way to create and destroy these fork machines, and
there is. The fork can, under its own power, follow the program's
instructions and stop itself (it can't start itself, for obvious reasons).
From the time a fork is created until it is annihilated, it is necessarily in
some 'state', just like any good mechanical machine: stopped, running,
waiting for something external to it to happen, etc.
A Tops-20 job is nothing more than a related collection of forks; since a fork
can only come into existence by being created by another fork, each fork has a
superior fork (which created it) and some number of inferior forks (which it
created). It's also helpful to think of a fork's superior as its parent and
its inferiors as its children. The top-level fork in each job (which has no
superior) is the Tops-20 EXECutive command processor, which is responsible for
creating other forks and running programs in them. The EXEC is thus the
super-parent fork in each job, and is created by Tops-20 when you type a
control-C on an unlogged-in terminal. In a graphic form, suppose you've
logged in and have run EMACS as a kept editor, written a program, gotten out
Monitor Calls Page 98
of EMACS and started to compile it with MIDAS. At this point, your job's fork
structure looks like:
(W: Your EXEC fork)
/ #0
/ |
/ |
(H: EMACS) (R: MIDAS)
#1 #2
For convenience' sake, we label the forks with numbers (in the order in which
they were created). In fork #2, the MIDAS EXE file is being executed (R:
means running), and fork #1, containing the EMACS EXE and various TECO files,
is temporarily halted (H: means halted), since you're not using it currently.
The EXEC fork, fork #0, is waiting for the MIDAS fork to halt itself before
going on and prompting you for more commands (W: means waiting for another
fork).
Suppose, after running MIDAS, you Push to a new EXEC and run your program
(somewhat useless, but helpful for this example). At the time your program is
running, your job fork structure looks like:
(W: your EXEC)
/ #0 \
/ | \
/ | \
(H: EMACS) (H: MIDAS) (W: Pushed-to EXEC)
#1 #2 / #3
/
/
(R: your program)
#4
Here you see more clearly the 'tree' structure of the forks in your job. As
with most other trees encountered in computer science, this one is drawn
upside-down, with the branches growing down. You can also see why Tops-20
processes are called 'forks', as the tree structure forks out at each process,
just as a road forks at a junction.
To elaborate more on the superior and inferior notion, fork #0 has forks #1,
#2, and #3 as inferiors, and fork #3 has fork #4 as an inferior. Of course,
forks #1, #2 and #3 have fork #0 as a superior, and fork #4's superior is fork
#3.
Notice the states of the various forks: the top-level EXEC is now waiting on
the pushed-to EXEC to stop; your MIDAS fork has halted itself (which made the
top EXEC go on and ask you for more commands, at which point you Pushed to the
new EXEC); the EMACS fork's state hasn't changed, since you haven't told the
top EXEC to do anything with it; the pushed-to EXEC is waiting for your
running program to finish.
Monitor Calls Page 99
4.8.2. The Fork Environment
As mentioned above, each fork has a 'control panel', or interface with the
external environment, i.e. the world of forks outside itself. This panel has
several different areas, relating to the various kinds of interactions
possible with the outside world. These areas are as follows (don't worry
about the areas we haven't discussed yet):
1. The file system, each file represented by a Job File Handle (JFN);
2. The fork world, each inferior fork represented by a relative fork
handle;
3. The software interrupt system, as described by various enabled or
disabled channels and their handler address, as well as the global
state of the interrupt system for the fork;
4. Inter-process communication system, each channel of communication
represented by a Process ID (PID);
5. Inter-process sychronization system, each sychronization request
represented by outstanding Enqueue request (ENQs);
6. The user-terminal interface, consisting of various mode information
for the terminal apropos this fork;
Note that each area on the 'control panel' has a method of referencing the
various external objects related to the area; these are called 'handles' in
general (Job File Handles, Relative Fork Handles, Process ID Handles, etc.).
This is no coincidence: you have to refer to one of several objects --forks,
files, process IDs, etc.-- when you want to do something with them --open a
file, start a fork, send a message to another process, etc.-- and thus the
need for a handle. A handle is usually nothing more than a small integer
uniquely identifying the particular object you want to deal with.
4.8.3. Basic Fork-Handling JSYS's
With the above introduction to forks and their environment, we can proceed to
the two most basic fork-handling JSYS's: RESET and HALTF.
4.8.3.1. RESET (JSYS 147): Reset the current fork
This JSYS, in the terms of the previous section, cleans up the interface to
the external environment for this fork. It's always a good idea to use this
JSYS at the start of your program to make sure there are no 'loose ends' lying
around.
Returns: +1: Always (no errors are possible).
The RESET JSYS (cf. the list above in section 4.8.2):
1. closes all files for this fork (and any inferiors) and releases all
Monitor Calls Page 100
Job File Numbers (JFNs);
2. destroys all inferior forks and releases any Relative Fork Handles
it can;
3. resets the software interrupt system for this fork;
4. releases all handles on inter-process communication channels
(PIDs);
5. releases all inter-process sychronization requests (ENQs);
6. resets the terminal for this process to wake up on every character,
echo input, and translate output normally;
4.8.3.2. HALTF (JSYS 170) - Halt the current fork
Halts this fork and any forks inferior to this one; this fork (the one
executing this JSYS) then goes into the 'halted' state (with a 'voluntarily
terminated' flavor). If this fork is resumed (with a RFORK JSYS), then it
will continue with the instruction after this HALTF JSYS.
Returns: +1: only if this fork is later resumed (no errors are
possible from the HALTF itself).
4.8.3.3. Examples of RESET and HALTF
These two JSYS's are fairly simply used in practice. An example of a complete
MACRO program that prints "I'm here" and stops is:
title ImHere
search monsym
ImHere: RESET ; Tidy up the environment.
hrroi 1, [asciz/I'm here/] ; Print our
PSOUT ; message to the terminal,
HALTF ; and stop this fork.
jrst ImHere ; If this fork is continued, start over.
end ImHere
4.9. Miscellaneous JSYS's
Monitor Calls Page 101
4.9.1. STCMP (JSYS 540) - STring CoMParison
Compares two ASCIZ strings in memory. Letters are always considered as upper
case regardless of their case within the string; e.g. "ABC" and "abc" are
considered an exact match.
Accepts in AC1: Pointer to test string.
AC2: Pointer to base string.
Returns: +1: always, with
AC1 containing the compare code:
SC%LSS (bit 0) Test string less than base string.
SC%SUB (bit 1) Test string is a subset of
base string.
SC%GTR (bit 2) Test string greater than base string.
No bits are set in AC1 if the strings are equal.
AC2 containing base string pointer, updated such that
an ildb instruction will reference the first
nonmatching byte.
One string is considered less than another string if the ASCII value of the
first nonmatching character in the first string is less than the ASCII value
of the character in the same position in the second string.
On string is considered a subset of another string if both of the following
conditions are true:
1. From left to right, the ASCII values of the characters in
corresponding positions are the same.
2. The test string is shorter than the base string.
Two strings are considered equal if the ASCII values of the characters in
corresponding positions are the same and the two strings are the same size.
In this case, the contents of AC1 is 0 on return.
Example:
move t1, [point 7, string1] ; Pointers to test string
move t2, [point 7, [asciz /FOO/]] ; and base string.
STCMP ; Compare them.
jumpe t1, equal ; Do this if they're equal.
txnn t1, SC%LSS!SC%SUB ; Not equal. Test string less?
jrst greater ; No, greater - go handle.
; Get here only if test string lexically less than base string.
:
:
COMND JSYS Page 102
5. The COMND JSYS - JSYS 544
The COMND JSYS is probably the single most attractive feature of
the DECSYSTEM-20. It allows any interactive program to be totally
(and automatically) fault-tolerant and helpful to its users. The pain
involved in learning to use it effectively is worth suffering, but
should probably be deferred until you have become comfortable with the
instruction set, Macro-20, and the monitor calls described in Chapter
4.
The following introductory material was adapted for use in this
manual from a document written by Andrew R. Lowry and David S. Millman
at Columbia in August 1978.
5.1. Informal Introduction
You are probably already at least partially familiar with the workings of the
COMND jsys, although you may not be aware of your education. The COMND jsys
is the thing that figures out what you mean when you abbreviate your commands
to the EXEC, or when the EXEC finishes up your commands for you when you types
an ESCAPE character. It is also what types guide words in parentheses telling
you what you must type next, and it is the thing that will untiringly answer
your question marks with lists of alternatives for you to choose from. In
short, it is one of the things that makes learning and typing in commands to
the EXEC as easy as it is.
Using the COMND jsys mainly consists of the following: you tell it what
you're looking for, and it tells you what it finds. All the complexities have
to do with how this communication takes place. A great deal of this is common
to all the calls you can give to COMND, but some of it depends on exactly what
you're asking COMND to look for.
All the information which you must supply to COMND may be broken down
basically into two sets, the Command State Block (CSB) and the Function
Descriptor Block (FDB).
The CSB is ten words (storage locations) long and contains information about
what has been typed so far, how much more can be typed without overflowing the
space that has been set aside to store it, and where COMND can find other
information that it needs. Most of this information must be supplied only once
by the program using COMND, and from that point on COMND will update the
information as it goes.
The FDB is four words long and contains information which is more specific to
the type of call which is being made than is the information in the CSB. It
is here that COMND finds out what type of information it should be looking for
-- file name, time of day, one out of a list of possible keywords, or any
other of the 24 different items it knows how to look for. Also in the FDB it
finds pointers to a help string and a default string which the controlling
program supplies. The help string is what will be typed if the user types a
question mark, and the default string is what COMND will fill in if the user
types an escape character. Finally, COMND finds several indicators in the FDB
telling it how to process the request -- things like whether or not to convert
lower case input into upper case, whether or not to accept indirect file
specifications, etc.
COMND JSYS Page 103
The only thing left to do after the CSB and the FDB have been properly filled
in is to tell COMND where they are and let it go do its work. The only
questions now are, what does it do, and what are all the things it might give
back?
When COMND is invoked, it starts accepting characters, usually from the job's
controlling terminal. It keeps taking characters until the user types what is
called an "action" chatacter. Action characters include question mark,
escape, ctrl/f and carriage return, and they are called action characters
because COMND won't start doing what it is supposed to do until one of them is
typed. Once an action character is encountered, COMND will determine whether
or not the user has finished typing what s/he was supposed to type, and if so,
will return control to the calling program. This can be done in any of three
possible states.
If COMND was able to interpret what was typed, and decided that it was an
appropriate response, then it returns normally with the data that it received
stored in a place where the program can easily retrieve it.
If COMND was unable to understand what was typed in the context of what it was
told to look for, then it will return with an error indicator set so that the
program will know that something went wrong.
The third possibility is best shown by example. Suppose a program desires to
obtain from the user first a file name, then a time of day. This will involve
two calls to COMND. When the first call is executed, suppose the user (call
him Fred) types in FOO.BAR as his file name. COMND accepts this as a valid
file name and returns normally to the calling program, which then executes
COMND again, this time asking for a time of day.
At this point, Fred decides that he really didn't want to use FOO.BAR, but
wanted FOO.BAZ instead. So he deletes back to the R and types in a Z, and
then he goes ahead and types in a time of day as required. Now it looks like
trouble ... COMND has already told the program that Fred wanted FOO.BAR, and
now it needs some way to let the program know that he changed his mind. In
COMND jargon, we say that a "reparse" is needed. COMND sets a flag to let the
program know what has happened, and now the program must start right from the
beginning and reissue all the calls that it made to COMND for the current
command line (this rather vague term will be firmed up shortly). Thus it
redoes the call to get a file name, and COMND fills in FOO.BAZ this time, and
then it continues with the time of day call just like before. If there had
been other calls on this command line before the file name, they too would
have to be reissued in the same order as they originally were called.
The term "command line" was used a few times in the preceeding paragraph, and
although it may have a fairly intuitive meaning, it also has a very strict
meaning in the context of the COMND jsys, which will be explained now and
should be kept in mind when trying to understand the reparse mechanism.
One of the calls that can be made to COMND is called "CMINI" (each different
call has its own slightly mnemonic name). The CM signifies that it has
something to do with COMND, and the INI stands for "INItialize". This call,
unlike the rest of the calls, accepts no input from the terminal. It is used
to set up initial values in the CSB and to type out the command line prompt.
The end of this prompt is the farthest back that a user may delete when typing
the prompted-for command.
A "command line", then, consists of all responses to COMND calls made between
COMND JSYS Page 104
successive CMINI's. For a reparse, the program reissues COMND calls starting
with the one after the CMINI call that initiated the command line. The CMINI
call should not be reissued. That would be done if an error were detected and
the entire command line had to be restarted. The difference is that when
CMINI is done, COMND forgets everything that was previously contained in the
buffer. This is appropriate for a complete restart after an error, but not
for merely backing up on a reparse.
A final general topic is the concept of multiple function calls. This refers
to giving COMND more than one alternative to look for. For instance, it may
be equally acceptable at a particular point in a command line for the user to
type either a date, or simply a decimal integer, specifying possibly a number
of days from the current date. It would be advantageous for COMND to know
about the alternatives and not have to return an error if the second
alternative were chosen.
To accomplish this, it is possible to have several FDB'S all linked together
in a chain. The first one contains a pointer to the second, which contains a
pointer to the third, etc. Then if COMND can't make sense of what is typed in
the context of the first FDB, it goes on and tries the next FDB, and so on
right down the line until it gets to an FDB that does not point to another
one. At that point, if none of the FDB's succeeded, an error condition is
finally signalled and COMND returns. If one of the FDB's does fit, then not
only is the normal data returned, but also the location of the succeeding FDB
so that the program will be able to determine what ultimately happened.
The same procedures apply to multiple FDB's as to single ones in regard to
reparsing, error restarts, etc. Remember that when using multiple FDB's only
one input item is parsed, not several. The multiple nature comes from the
fact that COMND is given several choices as to how it should attempt to
interpret that item.
Note that when using multiple FDB's, only one CSB is used. This fact
underlines the main difference between the natures of information stored in
the two blocks, the CSB being fairly call-independent, while almost all of the
information in the FDB depends on exactly what call is being made.
At this point you should have an idea of what is involved in getting the COMND
jsys to do your work for you.
Various people have written comprehensive sets of macros or UUO's to simplify
use of the COMND JSYS. Such macros appear in MACSYM, CUsym, and elsewhere. A
sample program is included in Chapter 11, and a description of Columbia's
COMND macro/UUO package is included in 7.1.
This remainder of the Chapter is taken intact from the Tops-20 v4
Monitor Calls Reference Manual.
5.2. General Information
COMND - JSYS 544
Parses one field of a command that is either typed by a user or contained in a
file. When this monitor call is used to read a command from a terminal, it
provides the following features:
COMND JSYS Page 105
1. Allows the input of a command (including the guide words) to be
given in abbreviated, recognition (ESC and CTRL/F), and/or full
input mode.
2. Allows the user to edit his input with the DELETE, CTRL/U, CTRL/W,
and CTRL/R editing keys.
3. Allows fields of the command to be defaulted if an ESC or CTRL/F is
typed at the beginning of any field or if a field is omitted
entirely.
4. Allows a help message to be given if a question mark (?) is typed
at the beginning of any field.
5. Allows input of an indirect file (@file) that contains the fields
for all or the remainder of the command.
6. Allows a recall of the correct portion of the last command (i.e.,
up to the beginning of the field where an error was detected) if
the next command line begins with CTRL/H. The correct portion of
the command is retyped, and the user can then continue typing from
that point.
7. Allows input of a line to be continued onto the next line if the
user types a hyphen (-) immediately preceding a carriage return.
(The carriage return is invisible to the program executing the
COMND call, although it is stored in the text buffer.) The hyphen
can be typed by the user while he is typing a comment. The comment
is then continued onto the next line.
The COMND call allows the command line that is input to contain a comment if
the comment is preceded by either an exclamation point or a semicolon and the
previous field has been terminated. When the COMND call inputs an exclamation
point after a field that has been terminated, it ignores all text on the
remainder of the line or up to the next exclamation point. When the COMND
call inputs a semicolon after a field that has been terminated, it ignores all
text on the remainder of the line.
When an indirect file is given on the command line, it can be given at the
beginning of any field. However, it must be the last item typed on the line,
and its contents must complete the current command. The user must terminate
his input of the indirect file (after any recognition is performed) with a
carriage return. If he does not terminate his input, the message ?INDIRECT
FILE NOT CONFIRMED is output. Also, if the user types a question mark
(instead of the file specification of the indirect file) after he types the
@ character, the message FILESPEC OF INDIRECT FILE is output. The indirect
file itself should not contain an ESC or carriage return; if these characters
are included, they will be treated as spaces. The contents of the indirect
file are placed in the text buffer but are not typed on the user's terminal.
As the user types his command, the characters are placed in a command text
buffer. This buffer can also include the command line prompt, if any.
Several byte pointers and counts reflect the current state of the parsing of
the command. These pointers and counts are as follows:
1. Byte pointer to the beginning of the prompting-text buffer
(.CMRTY). This pointer is also called the CTRL/R buffer byte
pointer since it indicates the initial part of the text that will
COMND JSYS Page 106
be output on a CTRL/R. (The remainder of the text output on a
CTRL/R is what the user had typed before he typed CTRL/R.) The
buffer containing the prompt need not be contiguous with the buffer
containing the remainder of the command line. Typically this
pointer is to a string in the literals area.
2. Byte pointer to the beginning of the user's input (.CMBFP). This
is the limit back to which the user can edit.
3. Byte pointer to the beginning of the next field to be parsed
(.CMPTR).
4. Count of the space remaining in the text input buffer (.CMCNT).
5. Count of the number of characters in the buffer that have not yet
been parsed (.CMINC).
The illustration below is a logical arrangement of the byte pointers and
counts. Remember that the prompting-text buffer does not have to be adjacent
to the text buffer.
.CMCNT
!=======================================================!
! ! ! ! !
! ! ! ! !
!=======================================================!
^ ^ ^
! ! !
! ! ! .CMINC
! ! !
! ! !
! .CMBFP .CMPTR
.CMRTY
These byte pointers and other information are contained in a command state
block, whose address is given as an argument to the COMND monitor call. The
.CMINI function initializes these pointers.
Parsing of a command is performed field by field and by default begins when
the user types a carriage return, ESC, CTRL/F, or question mark. These
characters are called action characters because they cause the system to act
on the command as typed so far. A field can also be terminated with a space,
tab, slash, comma, or any other nonalphanumeric character. Normally, the
parsing does not begin, and the COMND call does not return control to the
program, until an action character is typed. However, if B8(CM%WKF) is on in
word .CMFLG when the COMND call is executed, parsing begins after each field
is terminated.
The command is parsed by repeated COMND calls. Each call specifies the type
of field expected to be parsed by supplying an appropriate function code and
any data needed for the function. This information is given in a function
descriptor block. On successful completion of each call, the current byte
pointers and the counts are updated in the command state block, and any data
COMND JSYS Page 107
obtained for the field is returned.
The program executing the COMND call should not reset the byte pointers in the
command state block after it completes the parsing of each command. It should
set up the state block once at the beginning and then use the .CMINI function
when it begins parsing each line of a command. This is true because the
.CMINI function implements the CTRL/H error recovery feature in addition to
initializing the byte pointers in the state block and printing the prompt for
the line. If the program resets the pointers, the CTRL/H feature is not
possible because the pointers from the previous command are not available.
When a CTRL/H is input, the .CMINI function allows error recovery from the
last command only if both (1) the pointer to the beginning of the user's input
(.CMBFP) is not equal to the pointer to the beginning of the next field to be
parsed (.CMPTR) and (2) the last character parsed in the previous command was
not an end-of-line character.
The design of the COMND call allows the user to delete his typed input with
the DELETE, CTRL/W, and CTRL/U keys without regard to field boundaries. When
the user deletes into a field that has already been parsed, the COMND call
returns to the program with B3(CM%RPT) set in word .CMFLG. This return
informs the program to forget the current state of the command and to reparse
from the beginning of the line. Because the complete line as typed and
corrected by the user is in the text buffer, the parse can be repeated and
will yield the same result up to the point of the change.
The calling sequence to the COMND call is as follows:
ACCEPTS IN AC1: address of the command state block
AC2: address of the first alternative function descriptor
block
RETURNS +1: always (unless a reparse is needed and the right half
of .CMFLG is nonzero), with
AC1 containing flags in the left half, and the
address of the command state block in the right
half. The flags are copied from word .CMFLG in
the command state block.
AC2 containing either the data obtained for the field
or an error code if the field could not be parsed
(CM%NOP is on).
AC3 containing in the left half the address of the
function descriptor block given in the call, and
in the right half the address of the function
descriptor block actually used (i.e., the one
that matched the input).
The format of the command state block is shown below.
COMND JSYS Page 108
0 17 18 35
!=======================================================!
.CMFLG ! Flag Bits ! Reparse Dispatch Address !
!-------------------------------------------------------!
.CMIOJ ! Input JFN ! Output JFN !
!-------------------------------------------------------!
.CMRTY ! Byte Pointer to CTRL/R Text !
!-------------------------------------------------------!
.CMBFP ! Byte Pointer to Start of Text Buffer !
!-------------------------------------------------------!
.CMPTR ! Byte Pointer to Next Input To Be Parsed !
!-------------------------------------------------------!
.CMCNT ! Count of Space Left in Buffer !
!-------------------------------------------------------!
.CMINC ! Count of Characters Left in Buffer !
!-------------------------------------------------------!
.CMABP ! Byte Pointer to Atom Buffer !
!-------------------------------------------------------!
.CMABC ! Size of Atom Buffer !
!-------------------------------------------------------!
.CMGJB ! Address of GTJFN Argument Block !
!=======================================================!
Command State Block
Word (Symbol) Meaning
.CMFLG (0) Flag bits in the left half, and the reparse dispatch address
in the right half. Some flag bits can be set by the program
executing the COMND call; others can be set by the COMND call
after its execution. The bits that can be set by the program
are described following the Command State Block description.
The bits that can be set by COMND are described following the
Function Descriptor Block description.
The reparse dispatch address is the location to which control
is automatically transferred when a reparse of the command is
needed because the user edited past the current pointer (i.e.,
the user edited characters that were already parsed). If this
field is zero, the COMND call sets B3(CM%RPT) in the left half
of this word and gives the +1 return when a reparse is needed.
The program must then test CM%RPT and, if on, must reenter the
code that parses the first field of the command. When the
reparse dispatch address is given, control is transferred
automatically to that address.
The code at the reparse dispatch address should initialize the
program's state to what it was after the last .CMINI function.
This initialization should include resetting the stack
pointer, closing and releasing any JFNs acquired since the
last .CMINI function, and transferring control to the code
immediately following the last .CMINI function call.
.CMIOJ (1) Input JFN in the left half, and output JFN in the right half.
These designators identify the source for the input of the
command and the destination for the output of the typescript.
COMND JSYS Page 109
These designators are usually .PRIIN (for input) and .PRIOU
(for output).
.CMRTY (2) Byte pointer to the beginning of the prompting-text.
.CMBFP (3) Byte pointer to the beginning of the user's input. The user
cannot edit back past this pointer.
.CMPTR (4) Byte pointer to the beginning of the next field to be parsed.
.CMCNT (5) Count of the space remaining in the buffer after the .CMPTR
pointer.
.CMINC (6) Count of the number of unparsed characters in the buffer after
the .CMPTR pointer.
.CMABP (7) Byte pointer to the atom buffer, a temporary storage buffer
that contains the last field parsed by the COMND call. The
terminator of the field is not placed in this buffer. The
atom buffer is terminated with a null.
.CMABC (10) Count of the number of characters in the atom tbuffer. This
count should be at least as large as the largest field
expected to be parsed.
.CMGJB (11) Address of a GTJFN argument block. This block must be at
least 16(octal) words long and must be writable. If a longer
GTJFN block is being reserved, the count in the right half of
word .GJF2 of the GTJFN argument block must be greater than
four. This block is usually filled in by the COMND call with
arguments for the GTJFN call if the specifified function is
requesting a JFN (i.e., functions .CMIFI, .CMOFI, and .CMFIL).
The user should store data in this block on the .CMFIL
function only.
The flag bits that can be set by the user in the left half of word .CMFLG in
the Command State Block are described below. These bits apply to the parsing
of the entire command and are preserved by COMND after execution. See the end
of the COMND JSYS discussion for the bits that are returned by COMND in the
left half of word .CMFLG.
5.3. Bits Supplied in State Block on COMND Call
Symbol (bit) Meaning
CM%RAI (6) Convert lowercase input to uppercase.
CM%XIF (7) Do not recognize the @ character as designating an indirect
file; instead consider the character as ordinary unctuation.
A program sets this bit to prevent the input of an indirect
file.
CM%WKF (8) Begin parsing after each field is terminated instead of only
after an action character (carriage return, ESC, CTRL/F,
question mark) is typed. For example, a program sets this bit
if it must change terminal characteristics (e.g., it must turn
COMND JSYS Page 110
off echoing because a password may be input) in the middle of
a command. However, use of this bit is not recommended
because terminal wakeup occurs after each field is terminated,
thereby increasing system overhead. The recommended method of
changing terminal characteristics within a command is to input
the field requiring the special characteristic on the next
line with its own prompt. For example, if a program is
accepting a password, it should turn off echoing after the
.CMCFM function of the main command and perform the .CMINI
function to type the prompt requesting a password on the next
line.
The format of the function descriptor block is shown below.
0 8 9 17 18 35
!=======================================================!
! function ! function ! address of next function !
.CMFNP! code ! flags ! descriptor block !
!-------------------------------------------------------!
.CMDAT! Data for specific function !
!-------------------------------------------------------!
.CMHLP! Byte pointer to help text for field !
!-------------------------------------------------------!
.CMDEF! Byte pointer to default string for field !
!-------------------------------------------------------!
.CMBRK! Pointer to 4-word break mask !
!=======================================================!
5.4. Function Descriptor Block
Symbol (word) Meaning
.CMFNP (0) Function code and pointer to next function descriptor block
(FDB).
B0-B8(CM%FNC) Function code
B9-B17(CM%FFL) Function-specific flags
B18-B35(CM%LST) Address of the next FDB
.CMDAT (1) Data for the specific function, if any.
.CMHLP (2) Byte pointer to the help text for this field. This word can
be zero if the program is not supplying its own help text.
CM%HPP must be set (in word 0) in order for this pointer to be
used.
.CMDEF (3) Byte pointer to the default string for this field. This word
can be zero if the program is not supplying its own default
string.
.CMBRK (4) Pointer to a 4-word break mask that specifies which characters
constitute end of field. Word .CMBRK is ignored unless CM%BRK
(B13) is on.
The individual words in the function descriptor block are described in the
COMND JSYS Page 111
following paragraphs.
5.4.1. Words .CMFNP and .CMDAT of the FDB
Word .CMFNP contains the function code for the expected field to be parsed,
and word .CMDAT contains any additional data needed for that function. The
function codes, along with any required data for the functions, are described
below.
Symbol (code) Meaning
.CMKEY (0) Parse a keyword, such as a command name. Word .CMDAT contains
the address of a keyword symbol table in the format described
in the TBLUK monitor call description (i.e., alphabetical).
The data bits that can be defined in the right half of the
first word of the argument pointed to by the table entries
(when B0-B6 of the first word are off and B7(CM%FW) is on) are
as follows:
B35(CM%INV) Suppress this keyword in the list output on a
?. The program can set this bit to include
entries in the table that should be invisible
because they are not preferred keywords. For
example, this bit can be set to allow the
keyword LIST to be valid, even though the
preferred keyword may be PRINT. The LIST
keyword would not be listed in the output
given on a ?. This bit is also used in
conjunction with the CM%ABR bit to suppress an
abbreviation in the output given on a ?.
B34(CM%NOR) Do not recognize this keyword even if an exact
match is typed by the user and suppress its
listing in the list output on a ?. (Refer to
the TBLUK call description for more
information on using this bit.)
B33(CM%ABR) Consider this keyword a valid abbreviation for
another entry in the table. The right half of
this table entry points to the keyword for
which this is an abbreviation. The program
can set this bit to include entries in the
table that are less than the minimum unique
abbreviation. For example, this bit can be
set to include the entry ST (for START) in the
table. If the user then types ST as a
keyword, it will be accepted as a valid
abbreviation even though there may be other
keywords beginning with ST. To suppress the
output of this abbreviation in the list typed
on a ?, the program must also set the CM%INV
bit.
On a successful return from .CMKEY, AC2 contains the address of the table
entry where the keyword was found.
COMND JSYS Page 112
CMNUM (1) Parse a number. Word .CMDAT contains the radix from 2 to 10)
of the number. On a successful return, AC2 contains the
number.
.CMNOI (2) Parse a guide word string, but do not return an error if no
guide word is input. An error is returned only if a guide
word is input that does not match the one expected by the
COMND call. A guide word field must be delimited by
parentheses. Word .CMDAT contains a byte pointer to an ASCIZ
string. This string does not contain the parentheses of the
guide word. Guide words are output if the user terminated the
previous field with ESC. Guide words are not output, nor can
they be input, if the user has caused parsing into the next
field.
.CMSWI (3) Parse a switch. A switch field must begin with a slash and
can be terminated with a colon in addition to any of the legal
terminators. Word .CMDAT contains the address of a switch
keyword symbol table. (Refer to the TBLUK monitor call
description for the format of the table.) The entries in the
table do not contain the slash of the switch keywords;
however, they should end with a colon if the switch requires a
value. The data bits CM%INV, CM%NOR, and CM%ABR defined for
the .CMKEY function can also be set on this function. On a
successful return, AC2 contains the address of the table entry
where the switch keyword was found.
.CMIFI (4) Parse an input file specification. This function causes the
COMND call to execute a GTJFN call to attempt to parse the
specification for an existing file, using no default fields.
The .CMGJB address (word 11 in the command state block) must
be supplied, but the GTJFN block should be empty. (Data
stored in the block will be overwritten by the COMND JSYS.
Also, certain GTJFN flags are set.) On a successful return,
AC2 contains the JFN assigned. Hyphens are treated as
alphanumeric characters for this function
See note following .CMFIL function.
.CMOFI (5) Parse an output file specification. This function causes the
COMND call to execute a GTJFN call to attempt to parse the
specification for either a new or an existing file. The
default generation number is the generation number of the
existing file plus 1. The .CMGJB address must be supplied,
but the GTJFN block should be empty. (Data stored in the
block will be overwritten by the COMND JSYS. Also, certain
GTJFN flags are set.) On a successful return, AC2 contains
the JFN assigned. Hyphens are treated as alphanumeric
characters for this function.
See note following .CMFIL function.
.CMFIL (6) Parse a general (arbitrary) file specification. This function
causes the COMND call to execute a GTJFN to attempt to parse
the specification for the file. The .CMGJB address must be
supplied, but data stored in certain words of the GTJFN block
will be overwritten by the COMND JSYS and certain GTJFN flags
will be set (see note below). On a successful return, AC2
COMND JSYS Page 113
contains the JFN assigned. Hyphens are treated as
alphanumeric characters for this function.
Note that portions of the GTJFN block used by functions
.CMOFI, .CMIFI, and .CMFIL are controlled by COMND. The
following list shows which words are under the control of
COMND and which words are under the control of the user:
GTJFN Controlled Characteristics
Word(s) by
.GJGEN COMND
1. .CMOFI sets flags
GJ%FOU, GJ%MSG, and
GJ%XTN and clears all
other flags.
2. .CMIFI sets flag
GJ%OLD, and GJ%XTN
and clears all other
flags.
3. .CMOFI and .CMIFI
zero the right half
of word .GJGEN
4. .CMFIL sets flag
GJ%XTN and clears
GJ%FCM
.GJSRC COMND None
.GJDEV -
.GJJFN COMND/
USER Functions .CMIFI AND
.CMOFI give COMND control
of these words. .CMFIL
gives the user control of
these words.
.GJF2 -
.GJATR COMND None
.CMFLD (7) Parse an arbitrary field. This function is useful for fields
not normally handled by the COMND call. The input, as
delimited by the first nonalphanumeric character, is copied
into the atom buffer; the delimiter is not copied. Note the
following:
1. This function will parse a null field
2. Hyphens are treated as alphanumeric characters for
this function
3. No validation is performed (such as filename
validation)
4. No standard help message is available (see below)
COMND JSYS Page 114
5. The FLDBK. and BRMSK. macros may be used for
including other characters in the field (like "*").
.CMCFM (10) Confirm. This function waits for the user to confirm the
command with a carriage return and should be used at the end
of parsing a command line.
.CMDIR (11) Parse a directory name. Login and files-only directories are
allowed. Word .CMDAT contains data bits for this function.
The currently defined bit is as follows:
B0(CM%DWC) Allow wildcard characters
On a successful return, AC2 contains the 36-bit directory
number.
.CMUSR (12) Parse a user name. Only login directories are allowed. On a
successful return, AC2 contains the 36-bit user number.
.CMCMA (13) Comma. Sets B1(CM%NOP-no parse) in word .CMFLG of the command
state block and returns if a comma is not the next item in the
input. Blanks can appear on either side of the comma. This
function is useful for parsing a list of arguments.
.CMINI (14) Initialize the command line (e.g., set up internal monitor
pointers, type the prompt, and check for CTRL/H). This
function should be used at the beginning of parsing a command
line but not when reparsing a line. Otherwise, the CTRL/H
feature will not work.
To use this function, the user first moves the appropriate
data into the command state block and then issues .CMINI. If,
at any time during the parsing of a line, an error occurs,
.CMINI is issued again to reinitialize the line. However, for
the 2'nd thru N'th invocation of .CMINI for a given line, the
user should not alter the byte pointers and character counts
in the command state block. To do so would disable the CTRL/H
feature. This feature allows the user program, on parsing a
bad atom, to print an error message, reissue the prompt, and
parse the command line again without forcing the user to
retype the entire line.
If .CMINI reads a CTRL/H character, .CMINI will reset all byte
pointers and character counts except the .CMINC count to their
original state. .CMINI will set the .CMINC count to the
number of characters in the buffer up to the bad atom. These
characters are output to the terminal and parsed again.
Control then passes to the reparse address (if provided) and
normal parsing resumes. The effect on the program is as if
the bad atom had never been typed.
.CMFLT (15) Parse a floating-point number. On a successful return, AC2
contains the floating-point number.
.CMDEV (16) Parse a device name. On a successful return, AC2 contains the
device designator.
.CMTXT (17) Parse the input text up to the next carriage return, place the
COMND JSYS Page 115
text in the atom buffer, and return. If an ESC or CTRL/F is
typed, it causes the terminal bell to ring (because
recognition is not available with this function) and is
otherwise ignored. If a ? is typed, an appropriate response
is given, and the ? is not included in the atom buffer. (A ?
can be included in the input text if it is preceded by a
CTRL/V.)
.CMTAD (20) Parse a date and/or time field according to the setting of
bits CM%IDA and CM%ITM. The user must input the field as
requested. Any date format allowed by the IDTIM call can be
input. If a date is not input, it is assumed to be the
current date. If a time is not input, it is assumed to be
00:00:01. When both the date and time fields are input, they
must be separated by one or more spaces. If the fields are
input separately, they must be terminated with a space or
carriage return. Word .CMDAT contains bits in the left half
and an address in the right half as data for the function.
The bits are:
B0(CM%IDA) Parse a date
B1(CM%ITM) Parse a time
B2(CM%NCI) Do not convert the date and/or time to
internal format.
The address in the right half is the beginning of a 3-word
block in the caller's address space. On a successful return,
this block contains data returned from the IDTNC call executed
by COMND if B2(CM%NCI) was on in the COMND call (i.e., if the
input date and/or time field was not to be converted to
internal format). If B2(CM%NCI) was off in the COMND call, on
a successful return, AC2 contains the internal date and time
format.
.CMQST (21) Parse a quoted string up to the terminating quote. The
delimiters for the string must be double quotation marks and
are not copied to the atom buffer. A double quotation mark is
input as part of the string if two double quotation marks
appear together. This function is useful if the legal field
terminators and the action characters are to be included as
part of a string. The characters ?, ESC, and CTRL/F are not
treated as action characters and are included in the string
stored in the atom buffer. Carriage return is an invalid
character in a quoted string and causes B1(CM%NOP) to be set
on return.
.CMUQS (22) Parse an unquoted string up to one of the specified break
characters. Word .CMDAT contains the address of a 4-word
block of 128 break character mask bits. (Refer to word .RDBRK
of the TEXTI call description for an explanation of the mask.)
The characters scanned are not placed in the atom buffer. On
return, .CMPTR is pointing to the break character. This
function is useful for parsing a string with an arbitrary
delimiter. The characters ?, ESC, and CTRL/F are not treated
as action characters (unless they are specified in the mask)
and can be included in the string. Carriage return can also
be included if it is not one of the specified break
characters.
COMND JSYS Page 116
.CMTOK (23) Parse the input and compare it with a given string ("token").
Word .CMDAT contains the byte pointer to the given string.
This function sets B1(CM%NOP) in word .CMFLG of the command
state block and returns if the next input characters do not
match the given string. Leading blanks in the input are
ignored. This function is useful for parsing single or
multiple character operators (e.g., + or **).
.CMNUX (24) Parse a number and terminate on the first non-numeric
character. Word .CMDAT contains the radix (from 2 to 10) of
the number. On a successful return, AC2 contains the number.
This function is useful for parsing a number that may not be
terminated with a nonalphabetic character (e.g., 100PRINT
FILEA).
Note that non-numeric identifiers can begin with a digit
(e.g., 1SMITH as a user name). When a non-numeric identifier
and a number appear as alternates for a field, the order of
the function descriptor blocks is important. The .CMNUX
function, if given first, would accept the digit in the
non-numeric identifier as a valid number instead of as the
beginning character of a non-numeric identifier.
.CMACT (25) Parse an account string. The input, as delimited by the first
nonalphanumeric character, is copied into the atom buffer; the
delimiter is not copied. No verification is performed nor is
any standard help message available.
.CMNOD (26) Parse a network node name. A node name consists of up to six
alphanumeric characters followed by 2 colons ("::").
Lowercase characters are converted to uppercase characters.
The node name is copied into the atom buffer without the
colons. Note that this function does not verify the existence
of the node.
In addition to the .CMFNP word of the function descriptor block containing the
function code in bits 0-8 (CM%FNC), this word also contains function-specific
flag bits in bits 9-17 (CM%FFL) and the address of another function descriptor
block in bits 18-35 (CM%LST).
The flag bits that can be set in bits 9-17 (CM%FFL) are as follows:
Symbol (bit) Meaning
CM%PO (14) The field is to be parsed only and the field's existence is
not to be verified. This bit currently applies to the .CMDIR
and .CMUSR functions and is ignored for the remaining
functions. On return, COMND sets B1(CM%NOP-no parse) only if
the field typed is not in the correct syntax. Also, data
returned in AC2 may not be correct.
CM%HPP (15) A byte pointer to a program-supplied help message for this
field is given in word 2 (.CMHLP) of this function descriptor
block.
CM%DPP (16) A byte pointer to a program-supplied default string for this
field is given in word 3 (.CMDEF) of this function descriptor
block.
COMND JSYS Page 117
CM%SDH (17) The output of the default help message is to be suppressed if
the user types a question mark. (See below for the default
messages.)
The address of another function descriptor block can be given in bits 18-35
(CM%LST) of the .CMFNP word. The use of this second descriptor block is
described below.
Usually one COMND call is executed for each field in the command. However,
for some fields, more than one type of input may be possible (e.g., after a
keyword field, the next field could be a switch or a filename field). In
these cases, all the possibilities for a field must be tried in an order
selected to test unambiguous cases first.
When the COMND call cannot parse the field as indicated by the function code,
it does one of two things:
1. It sets the current pointer and counts such that the next call will
attempt to parse the same input over again. It then returns with
B1(CM%NOP) set in the left half of the .CMFLG word in the command
state block. The caller can then issue another COMND call with a
function code indicating another of the possible fields. After the
execution of each call, the caller should test the CM%NOP flag to
see if the field was parsed successfully.
2. If an address of another function descriptor block is given in
CM%LST, the COMND call moves to this descriptor block automatically
and attempts to parse the field as indicated by the function code
contained in B0-B8(CM%FNC) in word .CMFNP of that block. If the
COMND call fails to parse the field using this new function code,
it moves to a third descriptor block if one is given. This
sequence continues until either the field is successfully parsed or
the end of the chain of function blocks is reached. Upon
completion of the COMND call, AC3 contains the addresses of the
first and last function blocks used.
By specifying a chained list of function blocks, the program can have the
COMND call automatically check all possible alternatives for a field and not
have to issue a separate call for each one. In addition, if the user types a
question mark, a list is output of all the alternatives for the field as
indicated by the list of function descriptor blocks.
5.4.2. Word .CMHLP of the FDB
This word contains a byte pointer to a program-supplied help text to be output
if the user types a question mark when entering his command. The default help
message is appended to the output of the program-supplied message if
B17(CM%SDH) is not set. If B17(CM%SDH) is set, only the program-supplied
message is output. If this word in the descriptor block is zero, only the
default message is output when the user types a question mark. Bit 15(CM%HPP)
must be set in word 0 (.CMFNP) of the function descriptor block for this
pointer to be used. The default help message depends on the particular
function being used to parse the current field. The table below lists the
default help message for each function available in the COMND call.
COMND JSYS Page 118
5.4.3. Default Help Messages
Function Message
.CMKEY (keyword) ONE OF THE FOLLOWING followed by the alphabetical list of
valid keywords. If the user types a question mark in the
middle of the field, only the keywords that can possibly match
the field as currently typed are output. If no keyword can
possibly match the currently typed field, the message KEYWORD
(NO DEFINED KEYWORDS MATCH THIS INPUT) is output.
.CMNUM (number) The help message output depends on the radix specified in
.CMDAT in the descriptor block. If the radix is octal, the
help message is OCTAL NUMBER If the radix is decimal, the help
message is DECIMAL NUMBER If the radix is any other radix, the
help message is A NUMBER IN BASE nn where nn is the radix.
.CMNOI (guide word) None
.CMSWI (switch) ONE OF THE FOLLOWING followed by the alphabetical list of
valid switch keywords. The same rules apply as for .CMKEY
function. (See above.)
.CMIFI (input file) The help message output depends on the
.CMOFI (output file) settings of certain bits in the GTJFN call.
.CMFIL (any file) If bit GJ%OLD is off and bit GJ%FOU is on, the help message
is OUTPUT FILESPEC Otherwise, the help message is INPUT
FILESPEC
.CMFLD (any field) None
.CMCFM (confirm) CONFIRM WITH CARRIAGE RETURN
.CMDIR (directory) DIRECTORY NAME
.CMUSR (user) USER NAME
.CMCMA (comma) COMMA
.CMINI (initialize) None
.CMFLT (floating point) NUMBER
.CMDEV (device) DEVICE NAME
.CMTXT (text) TEXT STRING
.CMTAD (date) The help message depends on the bits set in .CMDAT in the
descriptor block. If CM%IDA is set, the help message is DATE
If CM%ITM is set, the help message is TIME If both are set,
the help message is DATE AND TIME
.CMQST (quoted) QUOTED STRING
.CMUQS (unquoted) None
COMND JSYS Page 119
.CMTOK (token) None
.CMNUX (number) Same as .CMNUM
.CMACT (account) None
.CMNOD (node) NODE NAME
5.4.4. Word .CMDEF of the FDB
This word contains a byte pointer to the ASCIZ string to be used as the
default for this field. For this pointer to be used, bit 16 (CM%DPP) must be
set in word 0 (.CMFNP) of the descriptor block. The string is output to the
destination, as well as copied to the text buffer, if the user types an ESC or
CTRL/F as the first non-blank character in the field. If the user types a
carriage return, the string is copied to the atom buffer but is not output to
the destination.
When the caller supplies a list of function descriptor blocks, the byte
pointer for the default string must be included in the first block. The
CM%DPP bit and the pointer for the default string are ignored when they appear
in subsequent blocks. However, the default string can be worded so that it
will apply to any of the alternative fields. The effect is the same as if the
user had typed the given string.
Defaults for fields of a file specification can also be supplied with the
.CMFIL function. If both the byte pointer to the default string and the GTJFN
defaults have been provided, the COMND default will be used first and then, if
necessary, the GTJFN defaults.
NOTE: The function descriptor block, whose address is given in AC2,
can be set up by the FLDDB. and FLDBK. macros defined in MACSYM. (See
end of COMND section for a description of these macros.)
5.4.5. Word .CMBRK of the FDB
This word contains a pointer to a 4-word user-specified mask that determines
which characters constitute end of field. The leftmost 32 bits of each word
correspond to a character in the ASCII collating sequence (in ascending
order). If the bit is on for a given character, typing that character will
cause the COMND JSYS to treat the characters typed so far as a separate field
and parse it according to the function being used. CM%BRK (B13) must be on in
the first word of the function descriptor block or COMND will ignore word
.CMBRK.
Ordinarily, the user would rely on COMND's default masks (varying according to
function) to specify which characters signal end of field and thus would not
be concerned with word .CMBRK of the function block. However, for special
purposes such as allowing "*" or "%" to be part of a field rather than a field
delimiter, the user must specify his own mask. (In this example, the bits for
"*" and "%" would be off in the mask word.) The user may inspect COMND's
default masks (defined in MONSYM) for help in designing a custom mask.
The following is a list of the COMND functions that use masks:
COMND JSYS Page 120
Mask COMND Changeable
Symbols Function by User
KEYB0. - KEYB3. .CMKEY Yes
DEVB0. - DEVB3. .CMDEV Yes (only if parse-only)
FLDB0. - FLDB3. .CMFLD Yes
EOLB0. - EOLB3. .CMTXT Yes
KEYB0. - KEYB3. .CMSWI Yes
User specified .CMDAT Yes
USRB0. - USRB3. .CMUSR No
FILB0. - FILB3. .CMFIL No
FILB0. - FILB3. .CMIFI No
FILB0. - FILB3. .CMOFI No
internal .CMNUM No
FILB0. - FILB3. .CMDIR No
internal .CMFLT No
ACTB0. - ACTB3. .CMACT No
COMND will ignore any break masks that are specified for functions that do not
allow user-modified masks.
Note that specifying a zero mask with CM%BRK set will cause the TTY line
buffer to fill up and generate an error.
On a successful return, the COMND call returns flag bits in the left half of
AC1 and preserves the address of the command state block in the right half of
AC1. These flag bits are copied from word .CMFLG in the command state block
and are described as follows.
5.5. Bits Returned on COMND Call
Symbol (bit) Meaning
CM%ESC (0) An ESC was typed by the user as the terminator for this field.
CM%NOP (1) The field could not be parsed because it did not conform to
the specified function(s). An error code is returned in AC2.
CM%EOC (2) The field was terminated with a carriage return.
CM%RPT (3) Characters already parsed need to be reparsed because the user
edited them. This bit does not need to be examined if the
program has supplied a reparse dispatch address in the right
half of .CMFLG in the command state block.
CM%SWT (4) A switch field was terminated with a colon. This bit is on if
the user either used recognition on a switch that ends with a
colon or typed a colon at the end of the switch.
CM%PFE (5) The previous field was terminated with an ESC.
When a field cannot be parsed, B1(CM%NOP) is set in AC1, and one of the
following error codes is returned in AC2. Note that if a list of function
descriptor blocks is given and an error code is returned, the error is
associated with the last function descriptor block in the list.
COMND JSYS Page 121
NPXAMB: ambiguous
NPXNSW: not a switch - does not begin with slash
NPXNOM: does not match switch or keyword
NPXNUL: null switch or keyword given
NPXINW: invalid guide word
NPXNC: not confirmed
NPXICN: invalid character in number
NPXIDT: invalid device terminator
NPXNQS: not a quoted string - does not begin with double quote
NPXNMT: does not match token
NPXNMD: does not match directory or user name
NPXCMA: comma not given
COMX18: invalid character in node name
COMX19: too many characters in node name
5.6. Macros
Several macros (defined in MACSYM) are available to make using the COMND JSYS
more convenient. These macros are as follows:
5.6.1. FLDDB.(TYP,FLGS,DATA,HLPM,DEFM,LST)
where:
TYP = function type
FLGS = function flags
DATA = function-specific data
HLPM = help message
DEFM = default text
LST = additional invocations of the FLDDB. macro (used
only if multiple function blocks are required)
This macro generates function descriptor blocks for COMND. For example, the
following code would perform a .CMINI function:
MOVEI T1,STEBLK ; Get address of COMND state block
MOVEI T2,[FLDDB.(.CMINI)] ; Get address of function block
COMND
COMND JSYS Page 122
The following code would perform a .CMKEY function (assuming that the keyword
table started at address CMDTAB:
MOVEI T1,STEBLK ; Get address of COMND state block
MOVEI T2,[FLDDB(.CMKEY,<CM%DPP+CM%+CM%HPP>,CMDTAB,
<help text>,<default text>)]
COMND
5.6.2. FLDBK.(TYP,FLGS,DATA,HLPM,DEFM,BRKADR,LST)
This is exactly the same as FLDDB. except that a provision has been made for
the address of the first word of a 4-word character mask (BRKADR). This
version is for use when a user-specified character mask is required.
5.6.3. BRMSK.(INI0,INI1,INI2,INI3,ALLOW,DISALLOW)
where:
INI0 = first word of character mask
INI1 = second word of character mask
INI2 = third word of character mask
INI3 = fourth word of character mask
ALLOW = characters to allow in the mask
DISALLOW = characters to disallow in the mask
This macro generates 4-word character masks for use with those COMND functions
that allow the user to specify his own mask. For example, executing the
following code would allow "*" in the predefined mask for the .CMFLD function
(FLDB0 thru BLDB3):
BRMSK.(FLDB0.,FLDB1.,FLDB2.,FLDB3.,<*>,)
5.6.4. FLDBK.
Also, the BRMSK. macro may be invoked within the FLDBK. macro:
FLDBK.(TYP,FLGS,DATA,HLPM,DEFM,[
BRMSK.(INI0,INI1,INI2,INI3,ALLOW,DISALLOW)],LST)
The COMND call causes other monitor calls to be executed, depending on the
particular function that is requested. Failure of these calls usually results
in the failure to parse the requested field. In these cases, the relevant
error code can be obtained via the GETER and ERSTR monitor calls.
- Any TBLUK error can occur on the keyword and switch functions.
- Any NIN/NOUT and FLIN/FLOUT error can occur on the number functions.
COMND JSYS Page 123
- Any GTJFN error except for GJFX37 can occur on the file
specification functions.
- Any IDTNC error can occur on the date/time function.
- Any RCDIR or RCUSR error can occur on the directory and user
functions.
- Any STDEV error can occur on the device function.
5.7. Errors
Generates an illegal instruction interrupt on error conditions below.
COMND ERROR MNEMONICS:
COMNX1: invalid COMND function code
COMNX2: field too long for internal buffer
COMNX3: command too long for internal buffer
COMNX5: invalid string pointer argument
COMNX8: number base out of range 2-10
COMNX9: end of input file reached
COMX10: invalid default string
COMX11: invalid CMRTY pointer
COMX12: invalid CMBFP pointer
COMX13: invalid CMPTR pointer
COMX14: invalid CMABP pointer
COMX15: invalid default string pointer
COMX16: invalid help message pointer
COMX17: invalid byte pointer in function block
MACSYM Page 124
6. MACSYM System Macros
This chapter was written by Dan Murphy, Digital Equipment
Corporation, July 1976.
6.1. Introduction
MACSYM is a file of standard macro and symbol definitions for use with TOPS20
machine language programs. Use of these definitions is recommended as a means
of producing more consistent and readable MACRO sources. Some of the
definitions were obtained from C.MAC; others will be added if they are
generally useful.
MACSYM is available on SYS: in two forms, MACSYM.UNV and MACREL.REL. The
first is the universal file of macro and symbol definitions; the second is a
file of small support routines used by certain of the facilities (e.g., stack
variables). The universal file is normally obtained at assembly time by the
source statement
SEARCH MACSYM
The object file, if necessary, may be obtained by the source statement
.REQUIRE SYS:MACREL
This instructs LINK to load the object file along with the main program. The
file is loaded only once even if the .REQUIRE appears in several source
modules, and no explicit LINK command need be given.
Certain conventions are observed regarding the construction of symbols as
follows: ("x" represents any alphanumeric)
xxxxx. an opdef or macro defininition
.xxxxx a constant value
xx%xxx a mask, i.e., a bit or bits which specify a field.
Symbols containing multiple periods may be used internally by some macros.
Symbols containing "$" are not used or defined by DEC and are reserved for
customer use.
6.2. Definitions
The following definitions are available in MACSYM and are arranged into groups
as shown.
MACSYM Page 125
6.2.1. Standard Program Version
This macro assembles the standard contents of .JBVER.
PGVER. VERS,UPDAT,EDIT,CUST
where
VERS is the major version number
UPDAT is the update or minor version number (1=A, 2=B, ...)
EDIT is the edit number
CUST is the customer/SWS edit code (1=SWS, 2-7= customer)
A word constructed from these quantities is assembled into absolute location
.JBVER (137); the current assembly location is restored.
6.2.2. Miscellaneous Constants (Symbols)
.INFIN = 377777,,777777 ;plus infinity
.MINFI = 400000,,0 ;minus infinity
.LHALF = 777777,,0 ;left half
.RHALF = 0,,777777 ;right half
.FWORD = 777777,,777777 ;full word
6.2.3. Control Characters (Symbols)
Symbols are defined for all control character codes 0 to 37 and 175-177. The
following are the commonly used characters; see source listing for others.
.CHBEL = 07 ;bell
.CHBSP = 10 ;backspace
.CHTAB = 11 ;tab
.CHLFD = 12 ;linefeed
.CHFFD = 14 ;formfeed
.CHCRT = 15 ;carriage return
.CHESC = 33 ;escape
.CHDEL = 177 ;delete (rubout)
6.2.4. PC Flags (Mask Symbols)
PC%OVF = 1B0 ;overflow
PC%CYO = 1B1 ;carry 0
PC%CY1 = 1B2 ;carry 1
PC%FOV = 1B3 ;floating overflow
PC%BIS = 1B4 ;first part done (byte increment
suppress)
PC%USR = 1B5 ;user mode
MACSYM Page 126
PC%UIO = 1B6 ;user IO mode
PC%LIP = 1B7 ;last instruction public
PC%AFI = 1B9 ;ADDRESS FAILURE INHIBIT
PC%ATN = 1B10 ;apr trap number
PC%FUF = 1B11 ;floating underflow
PC%NDV = 1B12 ;no divide
6.2.5. Macros to Manipulate Field Masks
Many of the symbols in MACSYM and MONSYM define flag bits and fields. A field
mask is a full-word value with a single contiguous group of 1's in the field.
E.g., 000000,,777000 defines a field consisting of bits 18-26. The following
macros may be used in expressions to deal with these masks.
6.2.5.1. WID(MASK)
Width - computes the width of the field defined by the mask, i.e., the number
of contiguous 1-bits. Value is not defined if mask contains non-contiguous
1-bits.
6.2.5.2. POS(MASK)
Position - computes the position of the field defined by the mask. The
position of a field is always represented by the bit number of the rightmost
bit of the field regardless of the width of the field. This is sufficient to
specify the entire field in the case of flags (1-bit fields).
6.2.5.3. POINTR(LOC,MASK)
Byte pointer - constructs a byte pointer to location LOC which references the
byte defined by MASK, e.g.,
POINTR(100,77) = POINT 6,100,35 = 000600,,100
6.2.5.4. FLD(VAL,MASK)
Field value - Places the value VAL into the field defined by MASK, e.g.,
FLD(3,700) = 0,,000300
6.2.5.5. .RTJST(VAL,MASK)
Right-justify - Shift VAL right such that the field defined by MASK is moved
to the low-order bits of the word, e.g.,
.RTJST(300,700) = 3
MACSYM Page 127
6.2.5.6. MASKB(LBIT,RBIT)
Mask - construct a mask word which defines a field from bit LBIT to bit RBIT
inclusive. E.g., MASKB(18,26) = 0,,777000.
6.2.6. Instructions Using Field Masks (Macros)
The following mnemonics are similar to certain machine instructions used to
move and test bits and fields. These macros select the most efficient
instruction for the mask being used.
6.2.6.1. MOVX AC,MASK
Load AC with constant. MASK may be any constant; this assembles one of the
following instructions: MOVEI, MOVSI, HRROI, HRLOI, or MOVE literal.
6.2.6.2. TXmn AC,MASK
where m is: N, Z, O, C
n is: E, N, A, null
There are 16 definitions of this form which include all of the modification
and testing combinations fo the test instructions, i.e., TXNN, TXNE, TXO,
TXON, etc. A TL, TR, or TD literal is assembled as appropriate.
6.2.6.3. IORX AC,MASK; ANDX AC,MASK; XORX AC,MASK
These are equivalent to certain of the TX functions but are provided for
mnemonic value.
6.2.6.4. JXm AC,MASK,ADDRESS
This is a set of four definitions which jump to ADDRESS if the field specified
by MASK meets a certain condition. The condition (m) may be:
E - jump if all masked bits are 0
N - jump if not all masked bits are 0
O - jump if all masked bits are 1
F - jump if not al masked bits are 1 (false)
These macros will assemble into one, two, or three instructions as necessary
to effect the specified result, e.g.
JXN T1,1B0,FOO = JUMPL T1,FOO
JXE T1,770,FOO = TRNN T1,770
JRST FOO
MACSYM Page 128
6.2.7. Data Structure Facility (Macros)
This set of macros provides a comprehensive facility for the definition and
use of data structures. It is an extension of some of the techniques
represented by the field mask facilities above. Typically, a data structure
definition will include some information about the location of the data in
memory as well as its position within a word. These facilities are intended
to provide the following advantages:
- Data items may be referenced more mnemonically, e.g., two data items
in the same word would be given different names rather than merely
being known as the left half or right half of the word.
- Should the need arise, storage formats may be changed without
incurring the expense of a search of the code to change each
reference.
6.2.7.1. DEFSTR and MSKSTR
DEFSTR NAME,LOCATION,POSITION,SIZE
MSKSTR NAME,LOCATION,MASK
These macros both define a data structure called NAME. LOCATION specifies the
memory location of the desired word and consists of address, index, and
indirect fields in the usual form, i.e., @address(index). Any of the fields
may be omitted if not needed, and the entire location argument may be null in
some circumstances. The remaining arguments define the desired field. DEFSTR
specifies the field in terms of its position (right-most bit number) and size
(number of bits), while MSKSTR specifies the field by a full-word mask as
described earlier. Normally, the actual storage to be used is declared
separately, e.g., by a BLOCK statement.
As a simple example, consider an array of full-word data items. We wish to
use the name FOO for the data itself, so we declare the actual storage by some
other name, e.g.,
FOO1: BLOCK n
Then we declare the structure by
DEFSTR FOO,FOO1(FOOX),35,36
This says that we declare a data item called FOO, that the items are addressed
by FOO1(FOOX) (assuming that the index is kept in register FOOX), that the
items are 36-bit quantities with the rightmost bit in bit 35 (i.e., full
words). If instead, we wish to declare that each word of FOO1 consists of an
item in the left half and two 9-bit items in the right half, we could write:
DEFSTR FIRSTD,FOO1(FOOX),17,18 ; LH item.
DEFSTR SECOND,FOO1(FOOX),26,9 ; One 9-bit item
DEFSTR THIRDD,FOO1(FOOX),35,9 ; Another 9-bit item.
Data items defined with DEFSTR or MSKSTR may be referenced in a general way.
MACSYM Page 129
At each instance, additional location information may be given if necessary.
A set of reference functions (macros) is defined for most common operations,
some affecting AC and memory, others only memory. For example, the LOAD
function loads a data item into an AC and is written as
LOAD AC,NAME,LOCATION
where
AC is the AC to be loaded
NAME is the structure name as defined with DEFSTR
LOC is location specification in addition to that declared in the
structure definition. This field may be null in some cases.
Taking the example definitions above, we may write
LOAD T1,FOO
which would assemble into
MOVE T1,FOO1(FOOX)
or
LOAD T1,SECOND = LDB T1,[POINT 9,FOO1(FOOX),26]
LOAD T1,FIRSTD = HLRZ T1,FOO1(FOOX)
Note that the macro compiles the most efficient instruction available to
reference the specified field.
The optional third argument is provided to allow some of the location
information to be specified at each instance. For example, if the definition
is
DEFSTR FOO,FOO1,35,36
Then the index may be specified at each instance, e.g.,
LOAD T1,FOO,(XX)
LOAD T2,FOO,(T1)
The specification given in the definition is concatentated with the
specification given in the reference.
The following reference functions are presently defined:
LOAD AC,NAME,LOC load data item into AC
STOR AC,NAME,LOC store data item from AC into
memory
The data item is right justified in the AC.
MACSYM Page 130
SETZRO NAME,LOC set the data item to zero
SETONE NAME,LOC set the data item to all ones
SETCMP NAME,LOC complement the data item
INCR NAME,LOC increment the data item
DECR NAME,LOC decrement the data item
For functions not specifically provided, the following may be used:
OPSTR OP,NAME,LOC
OPSTRM OP,NAME,LOC
OP is any machine instruction written without an address field. It will be
assembled such as to reference the specified data structure. OPSTR is used if
memory is not modified, OPSTRM is used if memory is modified. E.g.,
OPSTRM <ADDM T1,>,FOO
to add the quantity in T1 to the data item FOO.
The following test and transfer functions are presently defined:
JE NAME,LOC,ADDR jump to ADDR if data is 0
JN NAME,LOC,ADDR jump to ADDR if data is not 0
The following test and transfer functions take a list of structure names
(surrounded by angle-brackets) or a single structure name. They compile code
to test each data item in the order given, and will stop as soon as the result
of the function is known (e.g., AND encounters a false term).
JOR NAMLST,LOC,ADDR jump to ADDR if any data item is true
(non-0)
JAND NAMLST,LOC,ADDR jump to ADDR if all data items true
(non-0)
JNOR NAMLST,LOC,ADDR jump to ADDR if all data items false
(0)
JNAND NAMLST,LOC,ADDR jump to ADDR if any data item is false
(0)
These functions optimize multiple fields in the same word if they are adjacent
in the structure list. If the final location is an accumulator, further
optimization is done.
As a final example of the data structure facility, consider the typical case
of data organized into unit blocks with pointers to other blocks. Such a
block may appear as
Flag 1 Flag 2 Code List pointer
! ! ! !
V V v V
+---+---+---------+---------+-------------------------+
! ! !/////////! ! !
+---+---+---------+---------+-------------------------+
! additional node data !
+-----------------------------------------------------+
! '''''''' !
MACSYM Page 131
We assume that n-word blocks will be allocated from a free pool at execution
time. The structure of the block is declared as follows:
MSKSTR FLAG1,0,1B0
MSKSTR FLAG2,0,1B1
DEFSTR CODE,0,17,9
DEFSTR LINK,0,35,18
DEFSTR NODDAT,1,35,36
Note that the location field contains only the offset address of the word
within the block; the address of the block will be specified in an index at
each reference. References would appear as follows:
LOAD T1,LINK,(T1) ;step to next node in list
STOR T2,CODE,(T1) ;set new block code
JE FLAG1,(T1),FLOFF ;jump if flag1 is off
JAND <FLAG1,FLAG2>,(T1),FLGSON ;jump if flag1 and
; flag2 are both on
6.2.8. Subroutine Conventions (Macros/opDefs)
The following definitions are used to make subroutine mechanics more mnemonic.
Reference is made to these conventions elsewhere in this document.
6.2.8.1. CALL address
Call subroutine at address; equivalent to PUSHJ P,address
6.2.8.2. RET
Return from subroutine; equivalent to POPJ P,
6.2.8.3. RETSKP
Return from subroutine and skip; equivalent to
JRST [AOS 0(P)
RET]
6.2.8.4. CALLRET address
Call the subroutine at address and return immediately thereafter; equivalent
to
MACSYM Page 132
CALL address
RET
RETSKP
CALLRET assembles as JRST but should be treated as if it assembles into
several instructions and cannot be skipped over.
6.2.8.5. AC Conventions
The facilities described here assume in some cases the following accumulator
naming conventions:
AC1-AC4 temporary, may be used to pass and return values
AC0,AC5-AC15 preserved, i.e., saved and restored if used by subroutine
AC16 temporary, used as scratch by some MACSYM facilities
AC17 stack pointer
6.2.9. Named Variable Facilities (Macros and Runtime Code)
A traditional deficiency of machine language coding environments is facilities
for named transient storage ("automatic", etc.). Sometimes, permanent storage
is assigned (e.g., by BLOCK statements) when no recursion is expected. More
often, ACs are used for a small number of local variables. In this case, the
previous contents must usually be saved, and a general mnemonic (e.g., T1, A,
X) is usually used. In some cases, data on the stack is referenced, e.g.,
MOVE T1,-2(P)
but this is completely non-mnemonic and likely to fail if addition storage is
added to or removed from the stack. The facilities described here provide
local named variable storage. Two of these allocate the storage on the stack;
the third allocates it in the ACs.
6.2.9.1. STKVAR namelist
This statement allocates space on the stack and assigns local names. The list
consists of one or more symbols separated by commas. Each symbol is assigned
to one stack word. If more than one word is needed for a particular variable,
then a size parameter may be given enclosed with the symbol in angle-brackets.
E.g.,
STKVAR <AA,BB>
STKVAR <AA,<BB,3>>
Variables declared in this way may be referenced as ordinary memory operands,
e.g.,
MACSYM Page 133
MOVE T1,AA
DPB T1,[POINT 6,BB,5]
Each variable is assembled as a negative offset from the current stack
location, e.g.,
MOVE T1,AA = MOVE T1,-2(P)
Hence, no other index may be given in the address field. Indirection may be
used if desired. There is no explicit limit to the scope of the variables
defined by STKVAR, but the following logical constraints must be observed:
1. The stack pointer must not be changed within the logical scope of
the variables, e.g., by PUSH or PUSHJ instructions. This also
implies that the variables may not be referenced within a local
subroutine called from the declaring routine.
2. The declaring routine must return with a RET or RETSKP. This will
cause the stack storage to be automatically deallocated.
STKVAR assumes that the stack pointer is in P, and it uses .A16 (AC16) as a
temporary.
6.2.9.2. TRVAR namelist
This statement allocates stack space and assigns local names. It is
equivalent to STKVAR except that it uses one additional preserved AC and
eliminates some of the scope restrictions of STKVAR. In particular, it uses
.FP (AC15) as a frame pointer. .FP is setup (and the previous contents saved)
at the same time as the stack space is allocated, and references to the
variables use .FP as the index rather than P. This allows additional storage
to be allocated on the stack and allows the variables to be referenced from
local subroutines. Note that all such subroutines (i.e., all variable
references) must appear after the declaration in the source. STKVAR may be
used within TRVAR, e.g., by a local subroutine.
STKVAR and TRVAR declarations are normally placed at the beginning of a
routine. They need not be the first statement. If a routine has two or more
entry points, a single declaration may be placed in the common path, or
several identical declarations may be used in each of the separate paths.
Care must be taken that control passes through exactly one declaration before
any variables are referenced. E.g.,
MACSYM Page 134
;MAIN ROUTINE
ENT1: TXO F,FLAG ;entry 1, set flag
JRST ENT0 ;join common code
ENT2: TXZ F,FLAG ;entry 2, clear flag
ENT0: TRVAR <AA,BB> ;common code, declare locals
..
CALL LSUBR ;call local subroutine
..
RET
;LOCAL SUBROUTINE
LSUBR: STKVAR <CC> ;local subroutine, declare
; locals
MOVE T1,AA ;reference outer routine
; variable
MOVEM T1,CC ;reference local variable
..
RETSKP ;skip return
6.2.9.3. ASUBR namelist
This statement is used to declare formals for a subroutine. The namelist
consists of from one to four variable names. The arguments are passed to the
subroutine in ACs T1 to T4, and values may be returned in these same ACs.
ASUBR causes these four ACs to be stored on the stack (regardless of how many
formals are declared), and defines the variable names as the corresponding
stack locations. The return does not restore T1-T4. The same frame pointer
AC is used by ASUBR and TRVAR, hence these declarations may not be used within
the same routine. Scope rules are the same as for TRVAR.
6.2.9.4. ACVAR namelist
This statement declares local storage which is allocated from the set of
preserved ACs. An optional size parameter may be given for each variable.
The previous contents of the ACs are saved on the stack and automatically
restored on the next return. Variables declared by ACVAR may be referenced as
ordinary AC operands.
6.2.10. Miscellaneous
6.2.10.1. TMSG string
Type literal string; uses AC1, outputs to primary output. E.g., TMSG <TYPE
THIS TEXT>
MACSYM Page 135
6.2.10.2. JSERR
Handle unexpected JSYS error; type "?JSYS ERROR: message". This is a single
instruction subroutine call which returns +1 always.
6.2.10.3. JSHLT
Handle unexpected fatal JSYS error; same as JSERR except does HALTF instead of
returning.
6.2.10.4. MOD.(DEND,DSOR)
Modulo - In assembly-time expression, gives remainder of DEND divided by DSOR;
e.g., MOD. 10,3 = 1.
Columbia Page 136
7. Columbia Macros and Packages
The items described in this chapter are peculiar to Columbia's DECSYSTEM-20.
Programs that use these facilities are not transportable to other
DECSYSTEM-20's (except in their .EXE form) unless the appropriate library
files are taken, too.
7.1. Utility UUO Package for Macro-20
[ Programs and text by Chris Ryland, 1978. ]
Preliminary Specs
Note: all of these UUOs have a general restriction that must be
observed: no strings addressed as arguments may live in the ACs.
Further, none of the COMND functions may use FLDDBs that address
indirectly through ac's t1-t4, .fp or p.
7.1.1. Formatted Printing Package
%print <format string>, <
addr of arg1
addr of arg2
...>
This expands into a call on the %uprint uuo, with argument
[[point 7,[asciz/string/], addr of arg1, addr of arg2, ...]
If you understand that the arguments are just part of a literal, then you can
understand why they're in this format, and how to extend it; e.g., you might
also say
%print <format>, <exp arg1-addr, arg2-addr, ...>
or call the %uprint uuo directly, if the format string is a variable, e.g.,
%uprint [exp fmstr, arg1-addr, arg2-addr]
The semantics of this beast are: the characters in the format string are
output sequentially, until an escape character `%' is seen; then, a argument
descriptor is eaten from the format string (see below for the definition of
the argument descriptor), and one or more arguments are eaten from the
argument list, and used for output, as directed by the descriptor. the basic
idea here is that each argument descriptor item directs special output
handling for a group of argument items (usually one). to make this discussion
more concrete, here is an example of how this macro might be used:
Columbia Page 137
%print <Here's a number: %d, and the time: %@n%/>, <
[^d234]
[ot%day!ot%fdy]
>
What happens here is that "Here's a number: " is printed on the primary
output, and then the argument descriptor %d is processed, which slurps up the
next argument, [^d234] (remember, all arguments are actually addresses of the
object in question), and prints it as a decimal number. then, ", and the
time: " is printed --nothing special here--, and the argument descriptor %@n
is hit; this descriptor, mnemonic for `the time as of now', has a @ modifier
(described in detail below) which causes the print package to pick up the next
argument from the list and use it as the date/time format value (again, what's
actually there is a literal, since arguments are always addresses of the value
to be used). finally, the arg descriptor `%/' is seen, which means print a
CRLF, and we're all done (because we hit the end of the asciz format string).
Each argument descriptor is of the form `%<@><key>'. The `@' means pick up
additional data to modify the action of the <key>, from the argument list
(this data is eaten just like data that is output; see below). Then, the
action denoted by <key> is taken, which results in one or more data items
being eaten from the argument list and output according the the format <key>.
these constant references to `eating' are to graphically state that when an
argument is used, it disappears from the argument list. thus, you can think
of the argument list as being eaten one argument at a time, from the top to
the bottom (or left to right, depending on how you coded it).
Note that this type of output differs from Fortran-style formatting, in that
it is format-driven, not argument-driven. E.g., in Fortran, each list item
(argument) is taken in turn, and the next format item selected to be used as
the output specification. in this package, just the reverse is done; the
format items cause argument-handling.
If any Jsys errors occur during printing, then if the %print is followed by an
erjmp or ercal, the jump or call is taken, just as in a jsys invocation.
Otherwise, a fatal error occurs.
The equivalent, but skipping, UUO is %prSkp; it returns +2 on success (or +3
if it has an erjmp or ercal after it).
The various argument descriptors, also known as format items, are:
%% print a `%'
%! ignore all following characters until a `!' is seen, at which
point formatting resumes normally. This is designed to allow
formats to nicely cross line boundaries.
%{ print a <
%} print a > (these last two are for non-paired <>)
%/ print a Carriage-Return/Line-feed pair
%= use the argument as a destination designator for the remainder
of the output for this %print call; note that any JFN
top-of-stack is then ignored for the rest of the %print (and
Columbia Page 138
is NOT updated after the %print is done).
%_ print a Horizontal Tab
%^ print a Form-Feed (^L)
%c print the name of the Connected directory, with punctuation
(str:<...>); use any @ modifier value as a directory number,
and print its name instead
%d print a Decimal number; use any @ modifier as the NOUT format.
If no radix is given in the @ modifier case, decimal radix is
used.
%e with no modifier, print the last error message encountered by
this process; with a modifier, use the argument value as an
error number to print symbolically.
%? do error synchronization: clear terminal input and wait for
terminal output to drain, and print a newline, followed by a
"?". Rest of this %print will go to the physical terminal
device.
%f print the Floating (single-precision) value of the argument;
use any @ modifier as the FLOUT format
%h print the ascii cHaracter value of the argument
%i like %d, but print +Inf if negative (for printing positive
numbers)
%j print the name of the file as given by the Jfn argument; use
any @ modifier value as the JFNS format
%n print the date and time of Now; use any @ modifier value as
the ODTIM format
%o print the argument as an (unsigned) Octal number; use any
@ modifier value as the NOUT format. If no radix is given in
the @ modifier case, octal radix is used.
%s print the argument as an asciz String (of byte size as given
by the argument's byte size); -1 in the left half of the
argument means treat it as 7-bit asciz (NB: the argument is a
really the address of a byte pointer, not a byte pointer
itself; see examples below)
%t print the date and Time as given by the argument; use any
@ modifier value as the ODTIM format
%u print the user's login ID, with no punctuation; with a
@ modifier, print the user name of the given user number
%v print the deVice name for the designator given as argument
%x print the argument as a siX-bit value.
Columbia Page 139
7.1.2. %prPush and %prPop
Warning: this facility is not implemented yet!
These two instructions push and pop the %print UUO's output JFN stack,
respectively. The top-of-stack entry (or .priou if the stack is empty) is
used as the destination designator, and is updated after each %print (unless a
%= or %? is used in the format string, see above), so that a byte pointer may
be effectively used as the output destination. %prPush takes an argument
which is an address of the output designator (a JFN or a byte pointer).
%prPop simply pops off the top of stack and discards it. (Note that you can't
have indexed or indirected byte pointers, as this is doable but infinitely
hairy for the UUO package. Also note that since the destination designator
itself is updated after each %print, you can't use a literal (e.g. a byte
pointer) for the argument to %prPush, unless you don't mind modifying pure
data (which you should!).)
Some examples are:
sPtr: point 7, buffer ; Byte pointer to a memory buffer.
:
%prPush sPtr ; Use buffer as general
: ; output area.
%print <foo, bar> ; Output to it.
: ; (sPtr now points at last char).
%prPop ; Get rid of this destination
: ; now that we're done.
Columbia Page 140
7.1.3. COMND-Jsys-Made-Easy Package
This set of macros implements an easy access route to the COMND Jsys;
familiarity with COMND and its functions IS required, though - we're only
trying to ease the pain of using it, not learning about it.
Following are the macros used to invoke the different functions of the COMND
Jsys as well as ancillary tasks such as setting up various control blocks,
getting information out of some of the data structures deliberately hidden to
ease use of COMND, etc. The naming conventions used are designed to follow as
much as possible the names of each of the COMND functions, with slightly
varied punctuation that corresponds to CUsym conventions. E.g., the .cmkey
function of COMND is invoked with the %cmkey macro; induction should get you
the rest.
Some philosophy about error-handling: any COMND function can fail in two ways
(actually, three, but the third is merged into the first to make your job all
that much easier): the function can't be parsed with the given input, or the
user deletes input back into an already-parsed field. We treat these two
`errors' uniformly: each invocation of a function either returns normally if
no error occurs, or takes an erjmp or ercal path (if provided) if an error is
found. Thus, a simple, uniform method of handling parse errors and reparse
conditions is provided: each subroutine of the main parse routine can always
return non-skip on any error (real or reparse), or skip on success. The main
parse routine can worry about whether a real error occurred, and print an
appropriate message, restarting the parse from scratch, or whether just a
reparse is needed, restarting from the first parse step. When an error
occurs, t1 contains the flags from COMND (note in the success case that t1
isn't modified), and t1 is not set. If a real COMND Jsys error (i.e., not a
user parse error occurs, like a COMND internal buffer overflow), the parse
error bit will be set, and the error return will happen as usual; this is done
to make COMND errors be treated uniformly.
Note that each COMND function, if it succeeds, returns a value in t2 (even if
it doesn't return any useful result).
Also, if any COMND function is invoked with more than one FDB (i.e., alternate
FDBs are used), then upon return t3 contains what it normally after the COMND
Jsys (q.v.): the FDB actually used, and the first FDB given.
%cmini (prompt, flags, iojfn, gjfblk)
This macro prepares everything for a command parse. All the arguments are
optional; their use is:
prompt a text string used as the prompt; e.g., <<CRDIR>>. If not
supplied, the prompt `>' is used. Note that if a `>' is
required on the end of this prompt, then you must use the form
<<prompt>>. Blame macro.
flags the flags destined for the (left half of the) CSB .cmflg word,
such as raise all input, wake on every field, etc.
iojfn the <input jfn,,output jfn> pair for the parse.
gjfblk the address of the GTJFN argument block, used in the .cmifi,
.cmofi, .cmfil functions (and it must be supplied if you plan
to use these functions). Its length must be at least .gjln
Columbia Page 141
(defined in CUsym).
This function will only fail if some horrible mistake has been made, usually
by the COMND package, so expect success. Note that this UUO only does a
.CMini COMND Jsys on the second and subsequent invocations, until a %cmres UUO
is done, at which point it will re-initialize everything (see the %cmres UUO
description below for an explanation).
7.1.3.1. %cmRes
This UUO, automatically done by %setUp at normal program startup, resets all
COMND parsing information, so that the next %cmini UUO will cause a full setup
of the Command State Block (set up the prompt, reset all the buffer pointers,
etc.). It should be invoked whenever you intend to start a whole new section
of parsing (e.g., changing the prompt or the set of commands, such as
subcommand mode). In the simplest case, you never have to worry about it, as
it's automatically done at startup. In the most usual case where it would be
needed, a subroutine called to do some subsidiary parsing (e.g., the GetOK
routine in mac:), the safest approach is to do a %cmres before the
subroutine's %cmini, and a %cmres after finishing its parsing job. This
guarantees that the caller won't get hurt.
7.1.3.2. %cmKey (keytab, help, default, flags)
This macro invokes the .cmkey COMND function; upon success, t2 contains the
address of the table entry where the parsed keyword was found. All but the
first arguments are optional.
keytab address of a TBLUK keyword table
help a literal string (usually enclosed in <> if it contains
anything other than alphanumerics and spaces) that will be
used as the help message. if not given, the default help
message is used.
default a literal string that will be used as the default keyword if
none is supplied; if not given, no default is possible.
flags flags, such as suppress default help, etc.
Note that these arguments are just used to build a function descriptor block,
and thus the usual things happen in their absence or presence. Many of the
other macros use the same structure for their arguments, and the same comments
apply as here, so they will usually be elided. If you need to use a
hand-crafted function descriptor block, you can call the COMND package uuo
directly, with the address of the FDB, as in %comnd [flddb. .cmkey,...].
Rather than give each COMND function as above, we will let you induce on the
`base step' above and assume that the remaining functions are invoked
similarly. What follows are those functions that do not map directly to a
COMND function.
Columbia Page 142
7.1.3.3. %cmgab bp
This function asks the COMND interface package to get the current contents of
the atom buffer into the string pointed to by the byte-pointer given as
argument; this cannot fail. Note that the atom buffer can be quite long --how
long depends on the current implementation of the COMND package, but a
reasonable size would be 100 words--, so be wary of extremely long atoms. The
byte pointer is updated.
Note that `bp' is the address of where the byte pointer can be found; i.e.,
the effective address of this UUO is the address of the byte pointer. BEWARE:
if you supply the argument as a literal, the byte pointer gets updated in the
literal pool; if you use the same literal later, it will not be pointing where
you think!
7.1.3.4. %comnd flddb
This is the general COMND function interface, for doing things not directly
supported by this package. `flddb' is the address of a function descriptor
block. It returns the data as the COMND jsys does, except that t1 is not used
to return the parse flags (see %cmgfg below, if you want to do this).
7.1.3.5. %cmgfg flag
This function get the flags from the .cmflg word of the Command State Block
into the word addressed by `flag'; e.g., to get the parse flags into t1, a
%cmgfg t1 will do just fine.
Some notes about using these COMND support macros in a structured fashion:
- The basic idea, as hinted at in the description above, is that each
COMND function either returns successfully if the parse succeeded
(including no reparse needed), or takes an erjmp/ercal path if one
is provided. Thus, each subroutine that is doing some `piece' of
the parsing can, at each step in its job, simply return non-skip on
error, or go on if each parse step succeeds, returning skip when it
finally finishes successfully. Only the top-level parse routine has
to worry about whether a reparse is needed, or an actual parse error
occurred; in the former case, the routine only needs to start the
parse over (without re-initializing); in the latter, an error
message can be issued, and the parse started over from scratch.
- There are several macros to help with this philosophy of parsing:
%pret To be used in a parse subroutine after each COMND
function; it just returns non-skip if a parse error
occurs.
%errep errlab, replab
To be used in a situation (either top-level or a
subroutine) where an error or reparse must be
handled specially. Mostly useful in the top-level
parse routine.
Columbia Page 143
%merrep errlab, replab
Mostly like %errep, but it prints a parse error
message before going to errlab; this is useful in
the top-level parse routine.
Note that an erjmp or ercal after a COMND function invocation is usually
sufficient for handling most errors; e.g., after a %cmfil invocation in a
parse subroutine, if any errors occur later in the same routine, an erjmp to a
cleanup segment (that releases the jfn gotten by the %cmfil) is quite
sufficient for handling both noparse and reparse errors.
Columbia Page 144
7.2. CUrel Utility Subroutines
CUrel.rel is an indexed library that can be searched for the handlers for the
Columbia UUOs for COMND Jsys calls and formatted printing (described in
CUUOs.doc) and for the routines described below.
7.2.1. Helper
Types the desired help file at the job's controlling terminal. Actually, it
will type any 7-bit ASCII file, but the error messages all refer to help
files.
Input:
t2/ 7-bit byte pointer to ASCIZ filespec.
Effects:
If the specified file is found and accessible then it is typed,
otherwise an appropriate error message is typed.
Returns +1 always.
Calling sequence:
search CUsym
extern helper
:
%setup
:
move t2, [point 7, [asciz\HLP:FILE.HLP\]]
call helper
:
- F. da Cruz, CUCCA, 1978
7.2.2. GetOK
Get affirmative or negative response to a question, using the COMND Jsys (help
is given on '?', recognition on ESC).
A default answer can be specified, which will be supplied automatically if the
user types carriage return alone in response to the question.
Columbia Page 145
Input:
t1/ 7-bit byte pointer to ASCIZ string posing the question.
t2/ zero -- no default answer.
positive (nonzero) -- default answer is "yes".
negative -- default is "no".
Returns:
+1 if response was negative.
+2 if response was affirmative.
Caution:
Don't call this routine while processing
another COMND Jsys (i.e. after .CMINI but before .CMCFM).
Example:
move t1, [point 7, [asciz\Really delete all your files? \]]
move t2, [-1] ; default is 'no'.
call getok
jrst dont ; answer was no, don't do it.
; code here will be executed if answer was 'yes'.
- F. da Cruz, C. Ryland, CUCCA, 1978
7.2.3. Gfcpg
This routine will allocate a page to the user. This is useful, for instance,
when PMAPping is to be done to a single page in memory.
Returns:
+1: error, no free core pages;
+2: success, page number in t1.
Example:
call %gfcpg
%ermsg <couldn't get a page>,nopage ; do this on +1 return
; come here when a page has been successfully allocated
- George Lotridge (DEC), CUCCA, 1977
7.2.4. pagMgr
A page management facility. Gives greater functionality that gfcpg at a
slightly greater cost in overhead. Allows allocation and deallocation of
consecutive blocks of pages. Keeps an internal 'own' page table for page
management.
Columbia Page 146
Call with:
Function codes in t1:
0: Get pages, searching from 770 -> 0.
1: Get pages, searching from 0 -> 770.
2: Free pages.
3: Initialize the pages-in-use vector.
(this is done automatically the first time this routine
is called, before the selected function is executed).
Arguments in t2:
For get-page functions:
Left half contains number of consecutive pages to get,
Right half contains starting page number to search from.
For free-page function:
Left half contains number of consecutive pages to free,
Right half contains starting page number to free from.
(in these functions, if the number of pages given is 0,
it will be treated as 1.)
For reinitialize function:
t2 is not examined.
Returns
+1: Not enough pages available; t2 contains maximum
number available of type requested.
If there was an error on initialization (e.g. invalid argument),
a message is typed at the terminal, and t1 is set to -1.
+2: t1/ Address of block of pages in right half, and page
number in the left.
t2/ page count.
Joel Rosenblatt, CUCCA, 1978.
7.2.5. Subbp
Subroutine to subtract two byte pointers, i.e. to tell the number of bytes
between the bytes pointed by the first one and the second one. The two byte
pointers must point to bytes of the same size. Indirection (@) and indexing
is handled properly.
Columbia Page 147
Call with:
t1/ First byte pointer.
t2/ Second byte pointer.
Returns:
+1 if the byte sizes are different, with t1-t3 unchanged, or else
+2 with:
t1/ Unchanged.
t2/ Unchanged.
t3/ The number of bytes of the specified bytesize in
thee string pointed to by the first byte pointer (in t1)
up to, but not including, the byte pointed to by the
second byte pointer (in t2).
Example:
; assume a SIN has just been done to get a string into location
; 'buffer'. SIN returns the updated byte pointer in t2. This
; call to Subbp will tell how many characters were in the string.
move t1, [point 7, buffer] ; Point to beginning of buffer.
call subbp ; (t2 already has the pointer to the end).
%ermsg <bytesize error>,error ; Do this on error.
movem t3, count ; Save the byte count.
- F. da Cruz, CUCCA, November 1977
7.2.6. Rescan
Allow arguments to be passed to programs via the Exec command line.
Look in the rescan buffer for the name of the calling program followed by any
arguments. If the first field found in the rescan buffer is not the same as
the program name, or if the program name matches but there are no arguments
after it then this routine returns +2 with no other effect. Otherwise it
returns +1 to indicate that special handling (usually the setting of a flag)
can be done.
Enter with:
t1/ Byte pointer to asciz program name.
Returns:
+1: If arguments found in rescan buffer,
with updated pointer in t1.
+2: otherwise.
Example:
extern Rescan
%trnOff rscFlg ; Assume no rescan args.
move t1, [point 7, [asciz/foo/]] ; Name of this program.
call rescan ; Rescan args on command line?
%trnOn rscFlg ; Yes, turn on the flag.
Columbia Page 148
If arguments were detected then subsequent requests for tty input will be
satisfied by the data in the rescan buffer until the rescan buffer is
exhausted or the program issues a .CMINI (or otherwise clears the input
buffer), at which time tty input will automatically revert to the physical
tty. The caller should skip over the first .CMINI after return from this
routine, which has already issued a .CMINI.
The contents of the rescan buffer are discarded if the first field found on
rescan does not match the program name passed in t1.
- Jeff Langer, CUCCA, April 1979
Columbia Page 149
7.3. CUsym MACSYM Augmentation Macros
The CUsym macros and documentation were written by George
L. Lotridge of Digital Equipment Corporation (while he was assigned to
Columbia University as a resident software specialist) and Chris
Ryland of Columbia.
CUsym contains a whole set of symbol and macro definitions to augment MONSYM
and MACSYM. Included are the standard register definitions, macros for
interfacing to the UUO package (which supports standard I/O, simple uses of
the COMND Jsys, etc.), and generally any macro which has been found to be
useful and which is missing from MONSYM and MACSYM (a working knowledge of
which is assumed).
NOTE: you should have a good feel for the contents of MACSYM (6)
document and the Macro coding standards document (8) before using this
package.
A word about naming conventions: all names in this module are of the form
%symbol; this will hopefully sidestep any name conflicts with a SEARCHing
program. DEC has reserved names with % and . in them, but their use of % is
restricted to other than the first char- acter, so we're safe. (Actually, a
few of our Useful Symbols, below, use a "." as their first character, which is
also DEC-reserved, but they're simple and few enough to cause no problems.)
Also, a few of the 'hidden' symbols used herein (e.g., the stack, or global
symbols in the support package) begin with "%%".
7.3.1. Accumulator Support
Accumulator (register) definitions (conform to the DEC coding standard) These
must be used exclusively, unless specifically redefined at the start of a
module with the %DefAC macro (see below).
p=:17 ; Stack pointer
cx=:16 ; Call/Return temporary
.sac=:16 ; CU/MacSym utility reg
f=:0 ; Flag register (preserved)
t1=:1 ; General temp and Jsys registers:
t2=:2 ; never preserved
t3=:3 ; ...
t4=:4 ;
q1=:5 ; First set of preserved regs
q2=:6 ; (must be preserved by callee
q3=:7 ; across a call)
p1=:10 ; Second set of preserved regs
p2=:11 ; (ditto)
p3=:12 ;
p4=:13 ;
p5=:14 ;
p6=:15 ; NB: not useable with TrVar MacSym facility
.fp=:15 ; Frame pointer for TrVar facility
Columbia Page 150
7.3.2. %DefAC
Define an alternate name for one of the registers; this macro should egisters
are re-defined, and the new definition should be made in terms of one of the
definitions above. This macro purges the old name, thus preventing multiple
names for one register.
define %defac(new, old)
7.3.3. Useful Symbols
.prjfn=<.priin,, .priou> ; Symbol for usual primary JFN pair
.null==0 ; General nothing value
.nil==0 ; General nothing pointer
.True==1 ; General boolean truth value
.False==0 ; and its complement
; Lengths of various Jsys control blocks; ommitted from MONSYM, sadly.
.acln ; Length of ACCES arg block
.ckln ; Length of CHKAC arg block
.cmln ; Length of Command State Block
.cmfln ; Length of Function Descriptor Block
.cdln ; Length of CRDIR arg block
.cjln ; Length of CRJOB arg block
.jiln ; Length of GETJI arg block
.gjln ; Length of (long form) GTJFN arg block
.ipln ; Length of ipcf packet descriptor block
.rsln ; Length of SFTAD arg block
.rdln ; Length of TEXTI arg block
7.3.4. UUO Package OPDEFs and Interface Symbols
%uprin ; Print UUO
%comnd ; COMND interface UUO
%ucmin ; COMND initializer UUO
%cmgfg ; Get COMND flags UUO
%cmgab ; Get COMND atom buffer UUO
%nuuo ; Add-new-UUO UUO
%cmres ; COMND reset UUO
%prPush ; JFN-stack push (%print package) UUO
%prPop ; JFN-stack pop (ditto) UUO
; length of COMND interface UUO atom buffer:
%atmbl==^d250/5+1 ; in words
extern %csb ; command state block, for you hackers
Columbia Page 151
7.3.5. Setup Environment Macros
7.3.5.1. %setEnv
%SetEnv is a macro that must be used as the first thing after your Title and
Search CUsym statements; it sets up the CUsym, MonSym, and MacSym environments
properly. Its use is envisioned as:
title Baz - tweak the frob's runtime
search CUsym ; (No MAC: needed!)
%setenv ; Set up our environment
...
7.3.5.2. %setUp
%SetUp is a macro that you should use as the first executable action in your
program; it Resets the execution environment, sets up a stack, clears the flag
register F, sets up for UUO calls, sets up for COMND parsing (resetting) (and
starts off your code in %Pure mode).
7.3.6. Storage Declaration Macros
%Pure, %Impure, %Routine
Use these macros to declare what sort of storage follows them: either %pure
code (or read-only data) or %impure data (read-write). Thus, before beginning
a new logical section of code or data, always use one of them to declare what
follows (if you don't use them, you may be surprised!). It goes without
saying that %Pure should precede all code (which is NEVER impure). Using this
pair of macros is a good way of keeping impure data, which belongs to a
routine, physically (on the written page, that is) together with the routine.
The alias %routine for %pure exists for purely mnemonic purposes; its use is
suggested, as in:
%routine
openit: stkvar <fee,<foo,,5>>
7.3.7. General-Purpose Macros
7.3.7.1. %Stack
This macro creates the stack area, and loads P with the stack pointer. Its
argument, the stack height, is optional, and defaults reasonably.
Columbia Page 152
7.3.7.2. %Version
This macro builds a standard DEC version word from its arguments. In order,
its arguments are the major version, the edit number, the minor version, and
the customer version. Omitted fields default to zero.
7.3.7.3. %Clear
This macro takes three args, two of which are optional. The first,
non-optional, argument is the starting address of the area to be cleared. The
next is the number of locations to clear, which defaults to one. The last
argument is the desired filler, which defaults to zero.
7.3.8. Macros Used for Common Primary I/O
Note that since these macros use %print, that any string argument shouldn't
include `%'s, or things may get very confusing. Also note that %typnum's
first argument, the address of the number, must conform to the %print argument
standard (q.v.).
7.3.8.1. %typeCR(string)
Types the given literal string at your terminal, followed by a carriage return
(CR).
Example:
%typeCR <And your little dog, too!>
7.3.8.2. %crType(string)
Like %typeCR, but types the CR before, instead of after, the string.
To type a literal string with no CR, either before or after, use
the MACSYM macro TMSG.
7.3.8.3. %typNum(num,cols,rdx)
Types the number in location 'num' at your terminal. The two trailing
arguments are optional.
cols Field width in which to print the number. Default is 0, i.e.
use only as many character positions as are necessary to type
the number.
rdx Radix in which to type the number. Default is 10 (decimal).
Columbia Page 153
7.3.8.4. %crlf
Types a carriage-return/linefeed sequence at your terminal.
7.3.8.5. %tab
Types a horizontal tab at your terminal.
7.3.9. JSYS Support Macros
7.3.9.1. %jsErr
Macro to be used after a Jsys that either returns +1 on error or always
returns +1 (i.e., all but two of the Jsysi); %JSerr types the user's error
message (if given) or the Jsys error that caused it to be invoked (if no
message is given); it then either halts (if no address is supplied) or goes to
the address (if given).
Note: this is similar to the MacSym macro JSERR, but it only works
after a Jsys, since it is invoked by an erjmp; %JSerr has the
advantage, though, that it ALWAYS works after a Jsys, which JSERR
doesn't.
Note also that both %Jserr and %ErMsg, if they halt and are continued, will
simply return to the point after the invocation of the %Jserr or %ErMsg.
Both of these macros, since they use %print, can produce customized error
messages (eg, %jsErr <CUsym: Bad command %s [%e]>,,<ptrToS> will print an
error-synchronized message, with a string argument and the monitor error
message in brackets, and then halt).
7.3.9.2. %erMsg
This macro, which, in contrast to %JSerr, is designed to be used in a non-Jsys
skip context, will print a message (if given) or the last fork error (if not
given); finally, it either jumps to an address (if given), or halts (if not
given). See %Jserr comments for more info.
7.3.10. Local Label Support Macros
The intent of this set of macros is to provide a facility usually available in
good assemblers (hint, hint): local labels. The idea, due to Knuth, is that
instead of agonizing over choosing a label for each little local motion within
some code, you simply plant one of nine local labels, of the form %N, and
refer to the next local label %N by %NF, and the previous local label %N by
%NB - a simple example of all this is:
Columbia Page 154
some: stkvar <from,to>
txne t1,gj%old ; Does he want an old file?
jrst %1f ; Yes, go handle it
txz t1,gj%fou ; No, reset this
setom from ; and set 'from' flag
%1 call foo ; Continue with processing
jrst %1b ; Failed: try it again
... ; etc etc
These macros (internally) use symbols of the form %n% and %n%m, where n ranges
from 1 to 9, and m from 0 to 777, so be wary.
7.3.10.1. %Cat(a,b)
Useful macro that just returns its two arguments (as text strings),
concatenated.
7.3.11. COMND JSYS Support Macros
7.3.11.1. %Ptr(string)
Build a standard 7-bit ASCIZ pointer to a literal string.
7.3.11.2. %table and %tbEnd
%table is used to start a keyword table definition; %tbEnd ends a keyword
table definition. Suggested use is as in the following example, which also
illustrates %key.
cmtb: %table ; Keywords for frotz program
%key Mumble,domum,cm%inv ; mumble command (invisible)
%key Noodle,donood ; noodle command
%key Zork,dungeo ; invoke dungeon command
%tbend ; End of this keyword table
7.3.11.3. %key(name, data, flags)
This macro takes three arguments: an (alphanumerics only!) name, the data to
be associated with the name, and an (optional) flag value. It creates either
a flag-less keyword (the normal case), or, if flags are given, a keyword with
flags in the first word (and cm%fw set). Thus, the result is a TBLUK table
entry, suitable for use by the .CMkey COMND Jsys function. Note that all %Key
words in a table must be bracketted by %table and %TbEnd macros (see above).
Columbia Page 155
7.3.11.4. %Flddb (typ, flgs, data, hlpm, defm, lst)
This macro is useful for building function descriptor blocks that don't
contain just literal strings for the help and default components; otherwise,
it's the same as the MONSYM flddb. macro.
7.3.11.5. %Handlr(p,e), %PrsAdr, %EvlAdr
Macros to support structured parse/evaluation; %Handlr builds a structure
comprised of the parse routine address (p) and evaluation routine address (e),
for a given keyword (it should be in a literal in the %Key macro); %prsAdr and
%evlAdr are the DEFSTR structures for accessing these two elements of a
structure, respectively.
An example of all this:
:
%cmkey comtab, <command,> ; Get a top-level keyword
%merrep restart, repars; Usual error handling
hrrz t2, (t2) ; Pick up data value from keyword
load t2, %evladr, (t2) ; Get evaluation routine
movem t2, evaler ; Save its address
load t2, %prsadr, (t2) ; Now, get parse routine
call (t2) ; And call it
%jmerrep restart, repars, restart ; Handle errors
: ; Continue
; Pure data for main parse
%table ; Main command table
%key bletch, [%handlr(bletcm, doblet)] ; Bletch mode
%key mumble, [%handlr(mumbcm, domumbl)] ; Mumble mode
%tbend
:
7.3.11.6. %CMxxx Macros to Invoke .CMxxx COMND Functions
See the CUUOS document (7.1) for information about using these. They are
listed here for convenience:
- %cmIni (prompt, flags, ioJfn, gjfBlk): Initialize parse.
- %cmKey (keyTab, help, defalt, flags): Parse a keyword.
- %cmNum (radx, help, defalt, flags): Parse a number.
- %cmNoi (guide-word): Parse guide words.
- %cmSwi (swTab, help, defalt, flags): Parse a switch.
- %cmIfi (help, defalt, flags): Parse an input filespec.
- %cmOfi (help, defalt, flags): Parse an output filespec.
Columbia Page 156
- %cmFil (help, defalt, flags): Parse a general filespec.
- cmFld (help, defalt, flags): Parse a "field".
- %cmCfm (help, flags): Get confirmation (CR).
- %cmDir (data, help, defalt, flags): Parse a directory name.
- %cmUsr (help, defalt, flags): Parse a user name.
- %cmCma (help, flags): Parse a comma.
- %cmFlt (help, defalt, flags): Parse a floating-point number.
- %cmDev (help, defalt, flags): Parse a device name.
- %cmTxt (help, defalt, flags): Parse a text string.
- %cmTad (tadBlk, help, defalt, flags): Parse time and date. Note
that the Time-and-Date flags belong to the first argument, since
they're part of the data to the function.
- %cmQst (help, defalt, flags): Parse a quoted string.
- %cmUqs (brkTab, help, defalt, flags): Parse an unquoted string.
- %cmTok (token, help, defalt, flags): Parse a token. The token as
given should be a string in double quotes, as in %cmtok "*"; if you
need some other form, use the %comnd UUO bare.
- %cmNux (radix, help, defalt, flags): Parse a number.
- %cmAct (help, defalt, flags): Parse an account string.
- %cmNod (help, defalt, flags): Parse a network node name.
7.3.12. Macros to Handle COMND Errors
7.3.12.1. %pret
For use in secondary parsing subroutines. Handle a parse error or reparse by
just returning non-skip.
7.3.12.2. %errep errlab, replab
For use in top-level command parser. Handle an error by going to errlab, and
a reparse by going to replab.
Columbia Page 157
7.3.12.3. %merrep errlab, replab
For use in top-level command parser. Handle an error by giving an error
message and going to errlab, and a reparse by going to replab.
7.3.12.4. Macros for Fail-Return from Parsing Routines
These macros help with error- and reparse-handling after a parse subroutine
call (which is expected to return skip on success, and non-skip on failure);
three sorts of errors can be expected from such subroutines: parse error,
reparse needed, other type of failure (usually a semantic problem). Thus,
these macros have three dispatch addresses, corresponding to these three
errors. Note that the method used here assumes that if neither the parse
error or reparse flags are set in the command state block, then the error is
of type `other'.
7.3.12.5. %jerrep errlab, replab, othrlb
Handle a skip-return error condition as described above.
7.3.12.6. %jmerrep errlab, replab, othrlb
Handle a skip-return error condition as described above, printing an error
message on a parse error.
Note! t1 is clobbered by %errep, %merrep, %jerrep, %jmerrep.
7.3.13. Flag-Handling Macros
All of the following flag-handling macros use register F, the preserved flag
register. F is assumed to be the flag register for any program that uses
these macros. Note that %SetUp clears F, thus initializing flag management.
7.3.13.1. %Flags(aFlg,bFlg,cFlg,...)
This macro takes a list of flag names, and assigns a flag value to each name
(within a 36-bit word). It can be used more than once, but no more than 36
flags can be defined.
7.3.13.2. %trnOn & %trnOff
These macros take a flag quantity (one or more flags ORed together), and turn
them on or off, respectively (with no skipping).
Columbia Page 158
7.3.13.3. %TrOnS & %TrOfS
Like %TrnOn and %TrnOff, but skip always afterwards.
7.3.13.4. %SkpOn & %SkpOff
These macros take a flag quantity, and will skip if ALL the flags are on or
off, respectively.
7.3.13.5. %AnyOn & %AnyOff
These macros take a flag quantity, and will skip if ANY of the flags are on or
off, respectively.
7.3.14. CUuos (CUCCA Utility UUOs) Interface
7.3.14.1. %print, %prSkp
Formatted-print macros: output the arguments according to the format string.
%PrSkp returns skipping (+2 instead of +1, but handling a following
erjmp/ercal properly). See 7.1 for details.
A note about arguments: the argument list is really nothing more than a
sequence of addresses, so if you choose to use addressing forms such as
address(index), be sure and use the <z address(index)> form so that macro will
be happy with the address. The same applies to address forms such as
<z @(t1)>, etc.
Standards Page 159
8. Macro-20 Programming Standards and Conventions
8.1. Introduction
This document was adapted in April 1979 at the Columbia University Computer
Center from the document
TOPS20 Coding Standards and Conventions, 17 January 1974, revised
8 September 1976
written by the DEC Tops-20 monitor group for its own use. This version
departs from the original in certain ways, by additions and deletions, and by
modifications of certain details, but the net effect is about the same. These
standards and specifications apply in specific detail to Macro-20 programs,
and in spirit to other DEC-20/DEC-10 assemblers (Macro-10, Midas, Fail). They
do not apply in their entirety to assembly language routines written to be
called from other languages, which usually have different subroutine calling
conventions, and may have registers dedicated to different uses, precluding
the use of certain MACSYM facilities. Familiarity with Macro-20 and DEC-20
monitor calls is assumed.
A standard of programming style and conventions is especially important for
the assembly language programmer because assembly language lacks high-level
language facilities such as control and data structures, scoping of variables,
etc., without which the programmer must exercise tremendous discipline to
write a clear, easily modifiable program. It is hoped that this standard will
make assembly language programming easier by relieving the programmer of the
burden of deciding at every turn how to format a statement, how to use
registers, how to pass parameters to a subroutine, and so forth. Like any
standard, this one contains many elements that are arbitrary and capricious,
and few people will agree with every detail. The bulk of the standard comes
to us as a fait accompli, having been in use at DEC for several years and
forming the basis for a very large amount of code. Other facets have been
added after long experience both in writing programs and in reading and
modifying code from various installations. It is felt the rules of style and
usage given here can result in programs that are as clear as Macro-20 programs
can be.
8.2. Statements
The general form of a statment should be:
label: opcode ac, @addr(x) ; Comment.
where:
1. Tabstops are assumed to be set every 8 spaces.
2. The label begins at the left margin.
3. The opcode begins at the first tab stop. There should be one tab
before the opcode. If the label and colon(s) occupy 8 or more
spaces, the opcode should start at the first tab stop on the next
Standards Page 160
line. Exceptions to this rule apply in multi-line literals and
following skipping instructions, JSYS's, and subroutine calls (see
below).
4. One space (a blank, not a tab) should follow the opcode unless
there are no other fields except the comment to be specified in the
statement, in which case sufficient tabs should follow to put the
comment field at the 4th tab stop. Space is preferred to tab for a
number of reasons: spaces take up less space and cause fewer
overflows into the comment field; an instruction is typed the same
way in the program text as it is in DDT (DDT will not accept a tab
in an instruction); tabbing does not achieve vertical alignment of
equivalent fields since various quantities can follow the opcode
(register, address, and others); tabs would line up the operands
with the opcodes of multiline literals; using tab prevents the
operands of an indented opcode from reflecting the indentation and
sometimes forces the operand forward an additional tab stop. This
standard attempts to help the whole instruction to be perceived
visually as a single unit; the use of tab tends to visually
separate opcode and operands for no useful reason. Vertical
alignment of operand fields such as produced by tab in this context
appears to be mainly a carryover from punched-card oriented
processors where parsing was done by field rather than on a
character stream.
5. When any field is not used by the instruction, it may be omitted
along with its directly related punctuation. A field which is
affected by an instruction should NOT be defaulted to 0 by omitting
it.
6. The semicolon which begins the comment should be at the 4th tab
stop. There should be one or more tabs preceding the semicolon as
necessary to place the semicolon at the 4th tab stop unless the
preceding fields extend to or beyond the 4th tab stop. In this
case, one space (blank) should be used to separate the last
preceding field and the semicolon. The semicolon should be
followed by a space.
The instruction which follows a skipping monitor or subroutine call should be
indented 1 additional space (1 space beyond the first tab stop) to indicate
the possibility of that instruction being skipped. Indenting in this manner
should also be done following skipping machine instructions; when several
skipping instructions appear consecutively, each instruction that could be
skipped should be indented 1 space.
8.3. Comments
A comment on the same line as a statement should begin at the 4th tab stop as
described above. When a comment consists of a single sentence or phrase which
requires more than one line, the subsequent lines should have two spaces
between the semicolon (at the 4th tab stop) and the comment to indicate to the
reader that the several lines are part of one logical statement.
A comment on a line by itself should begin at the left margin.
A group of comment lines (1 or more lines) should be preceded and followed by
Standards Page 161
a blank line.
A long comment (10 or more lines) may be enclosed within a REPEAT 0 or COMMENT
pseudo-op and the semicolons omitted.
Extensive commenting of source listings is strongly encouraged:
1. Routines, modules, sections, macro definitions, etc., should be
described at their beginning. See also requirements for subroutine
comments below.
2. Comments should appear on almost every statement line. As the
reader views the listing page, the comments (aligned at the 4th tab
stop) should appear as a running commentary on what the code is
doing. These on-line comments should explain the logical procedure
being carried out, not just describe the obvious action of the
instruction. Humorous or irrelevant comments (e.g. "; Oops...",
"; Oh well...") are discouraged since they provide no information
to the reader.
Comments should be written in plain English, without jargon, following normal
rules of capitalization, punctuation, and grammar. A reader should be able to
read the comments without seeing the code and obtain a coherent understanding
of what the program is doing. When a variable or other mnemonic symbol is
referred to in the comments, an english phrase rather than the mnemonic itself
should frequently be used (e.g. "last page address" rather than "LPGADR").
Comments, particularly routine headers, should describe why non-obvious
actions are being taken and/or what assumptions are being made (e.g. "Get
here only when ...").
Comments should exist on three levels. The highest level is a sentence or
paragraph that describes the operation of an entire program or routine, and
appears at the head of the program or routine (at the top of a page), usually
enclosed by the COMMENT pseudo-op so that each line need not begin with a
semicolon. The first top-level comment in a file should include the author's
name, organization (and department), the date, and possibly a copyright
notice. The lowest level is the per-statement comment at the 4th tab stop.
The intermediate level is a one- or two-line comment, beginning on the left
margin, which describes the purpose or operation of a group of statements.
There should never be more than 8 or 10 lines of code without such an
intermediate comment.
Think of any program you write as if it were a letter to a stranger who will
have to fix all the bugs you left in it, add new functionality, or translate
it to another language. It should be possible to read through a program on
four levels:
1. At the top level only. Reading only the highest-level comments
should give the reader a broad idea of the purpose and structure of
the program.
2. At the intermediate level. Reading the top- and intermediate-level
comments should show you not only what the program does, but what
algorithm was used.
3. At the lowest comment level. Including these comments in a reading
of the program adds detailed information about the actual
implementation of the algorithm.
Standards Page 162
4. At the code level. Including the code itself brings you down to
the bit-twiddling level. It should never be necessary to read code
unless you want to learn how things are done, or you are modifying
the program.
Example showing intermediate- and low-level comments:
; Get a JFN for the input file.
movx t1, GJ%SHT!GJ%OLD ; Using short form GTJFN, for an old file
hrroi t2, [asciz /foo.txt/] ; called foo.txt,
GTJFN ; get a Job File Number.
erjmp filErr ; On error go to the file-error handler.
hrrzm t1, inJfn ; No error, save the JFN (without flags).
; Now open the file.
movx t2, fld(7,OF%BSZ)!OF%RD ; In 7-bit byte read mode,
OPENF ; open the file.
erjmp filErr ; On error go to the file-error handler.
; File is open. Now begin processing.
:
:
The style of capitalization of the opcodes, JSYS bits, and variables is a
matter of taste, but consistent use of a mixture of upper and lower case to
enhance the readability of the program is strongly encouraged. In this
example, MONSYM symbols (JSYS names and bits) are capitalized, instructions
and register names are in lower case, and variable names formed from multiple
words have capital letters at word breaks (e.g. filErr = file error).
8.4. Pagination of Source Programs
Source listings should be divided into pages by formfeed (control-L)
characters. A CRLF should precede and follow each formfeed. Source files
should be arranged so that major modules, subroutines, etc., begin at the top
of a page. Only when a subroutine is a quarter page or less in total size
should it begin other than at the top of a page.
Judicious use should be made of blank lines (they should be inserted to
emphasize logical boundaries, but without large gaps). Garish graphic devices
like lines across the page, boxes around headings, etc., should be avoided
since they waste the programmer's time (both in typing them in and in waiting
for them to be typed out) without adding any useful information to the
program; the principle formatting devices for separating things and getting
attention should be blank lines and formfeed characters.
It should rarely be necessary for flow of control to cross a listing page.
That is, the last instruction on each page would normally be an unconditional
transfer of control not preceded by a skipping instruction. An unbroken
sequence of instructions longer than one listing page is strong evidence of
insufficient subroutinization. However, when a sequence of instructions does
Standards Page 163
cross a page, the last line on the preceding page and the first line on the
following page should be a comment line of the form
; ..
where the semicolon appears at the first tab stop directly under the preceding
opcode. E.g.,
move t1, foo ; Comment
; ..
^L
; Comment about continuation.
; ..
label: movem t1, baz ; Comment
The page break should occur at a natural juncture in the program logic.
8.5. Other Assembler Functions
For top-level macro definitions, the DEFINE should appear at the left margin
and be followed by one space. The name of the macro being defined should
appear next, followed by one space. The dummy argument list, if any, should
appear next, followed by the open angle-bracket. E.g.,
define macnam (a,b,c)<
or
define macnam <
A comment or CRLF should follow the open angle-bracket, and the body of the
macro definition should begin on the next line, except when the entire macro
definition is on one line in order to be used as part of an expression. The
terminating right angle bracket should be on a line by itelf, on the left
margin.
Example:
define getSum (a,b,c)< ;; Macro to get a sum into an AC.
move a, b ;; Load contents of b into AC a,
add a, c ;; and add contents of c.
>
Macro calls generally do not require parentheses surrounding the arguments.
The exception is a macro call appearing within an expression, e.g.
aa+foo(xx,yy)+bb
Standards Page 164
In some cases, however, the parentheses improve clarity, e.g. "foo (,x)" shows
more clearly that the first argument to foo is omitted than does "foo ,x".
Angle-brackets should be used to quote any argument containing
non-alphanumeric characters; this is especially true of character strings with
imbedded blanks.
Examples (where %jsErr is a macro name):
GTJFN
%jsErr <Can't get a JFN>, r
OPENF
%jsErr (,r)
Top level assembler conditionals should be indented 3 spaces from the left
margin (so that tag and comment lines may always be leftmost). Lower level
conditionals should be indented 3 or more spaces. The terminating
angle-bracket of a conditional should appear:
1. immediately following the last instruction if the conditional is
only one line long;
2. on a separate line indented the same amount as the pseudo-op which
began the conditional.
Example:
tag:
ife ftFoo,<move t1, mumble> ; If feature Foo is selected just do this.
ifn ftFoo,< ; If feature Foo is not selected...
move t1, mumble ; then do this,
ifn ftBaz,< ; and if feature Baz is selected...
add t1, baz ; do this
move t2, frotz ; and this too.
> ; End of ifn ftBaz.
jrst frotzH ; Go to the frotz handler.
> ; End of ifn ftFoo.
A closing angle bracket should NEVER appear in a comment (i.e. following a
semicolon on the same line). The coding should be correct even if the
assembler were made to ignore angle-brackets in comments.
Assembly listing options are provided for those who want listings, but
experience has shown that assembly listings are rarely useful; it is usually
sufficient to work from a source listing. However, all assemblies should
begin with SALL which has been shown to produce the most readable assembly
listings. In addition, all source files should have a TITLE, and SUBTTL's for
each logical section of the program (e.g. symbol definitions, initialization,
main program, support routines, data area).
In general, macros worth defining at all are worth defining on a system-wide
basis. Therefore, localized, special-purpose macros are discouraged.
Standards Page 165
8.6. Instruction Mnemonics
The standard KL-10 instruction mnemonics as defined by the DECsystem-10/20
Hardware Reference Manual should be used throughout. No abbreviated opcodes
should be used.
Macro or opdef definitions should be made to define a useful mnemonic which is
related to a function being performed in the code. See the subroutine
conventions below for examples.
8.7. Variables and Structures
Use of the stack variable and data structure facilities in MACSYM is
recommended. See MACSYM documentation. Because of these facilities, the
following should be observed:
1. Explicit pushing and popping of quantities is rarely done.
2. Explicit referencing of the stack, e.g. as -n(p) is never done.
3. Fields within data blocks or tables are not referenced by halfword
instructions or explicit byte pointers but rather by the MACSYM
facilities LOAD, STOR, etc.
4. Flags can be defined with DEFSTR, MSKSTR, or as full-word
parameters, and can be referenced with the TXmn MACSYM macro. Flags
should never be defined as half-word quantities which require the
programmer to remember whether to use TL or TR. Other macros may
be defined to operate on single-bit flags, which should be held in
register 0; in this case too, no instruction should depend on the
actual value or location of a flag.
8.8. Subroutines
All AC's should be preserved over a subroutine call unless an explicit
statement to the contrary appears in the subroutine description. ACs are
changed over a subroutine call only when values are to be returned to the
caller.
The allocation of ACs for all inter- and intra-module subroutine calls should
be:
ACs 1,2,3,4 Passing arguments and returning results.
ACs 0, 5-15 Preserved, not changed by subroutine (or saved and restored if
necessary).
AC 16 Temporary, used by MACSYM call/return procedure and reserved
for use by other call/return procedures.
AC 17 Global stack pointer
Call and return should be effected by 'pushj p,' and 'popj p,' respectively.
A set of assembler mnemonics has been defined for subroutine mechanics as
Standards Page 166
follows:
call (= pushj p,) should be used to call subroutines, e.g.
'call subr'.
ret (= popj p,) should be used to return +1 from subroutines.
retskp should be used to return +2 from subroutines. Retskp is
equivalent to:
jrst [ aos (p)
popj p,]
callret may be used to call a subroutine and return immediately
thereafter. It is equivalent to
call subr
ret
or
call subr
ret
retskp
Note that 'callret' is not guaranteed to be a single instruction; therefore it
may not be skipped over. The other returns above are guaranteed to be single
instructions.
These mnemonics are used to emphasize the FUNCTION being performed (calling,
returning) rather than the mechanics of the function (pushing, jumping, etc.).
Also, these mnemonics could continue to be used even if a more general calling
standard were adopted at some time in the future.
Return may also be effected by transferring control to one of the global
labels R or RSKP, e.g.
jumpe t1, r ; Equivalent to "jumpe t1, [ret]".
jumpn t1, rskp ; Equivalent to "jumpn t1, [retskp]".
The general temporaries should be used for passing arguments to subroutines
and returning values. AC1 (t1) should be used for a single argument routine,
ACs 1 and 2 for a two-argument routine, etc. When subroutines modify of
depend on global data, including flags, such effects should be clearly and
completely documented.
A routine defined to return caller +2 (skip) on success and caller +1 (noskip)
on failure is acceptable. Returns greater than caller +2 are considered very
bad form.
Standards Page 167
8.9. AC Definitions
The following mnemonics have been chosen to be consistent with the AC-use
conventions above. The preserved ACs are divided into three groups, f
intended for Flags, and q1-q3 and p1-p6 intended for general use. The ACs
within each group are consecutive.
0 - f 10 - p1
1 - t1 11 - p2
2 - t2 12 - p3
3 - t3 13 - p4
4 - t4 14 - p5
5 - q1 15 - p6
6 - q2 16 - cx
7 - q3 17 - p
The programmer should assume that each group (Tn, Qn, Pn,) is in ascending
order, e.g. that t2 = t1+1, but that the specific assignment of numbers may
change. Explicit numeric offsets from AC symbols (e.g. T1+1) should NEVER be
used. Instructions which use more than one AC (e.g. div, jffo) must be given
an AC operand such that the other AC(s) implicitly affected are in the same
group. E.g. t3 (and t4) is OK for idiv because t3+1=t4, but q3 is not because
q3+1=??. AC0 is almost universally used as a flag register, and should not be
used for any other purpose.
There is a facility in MACSYM to save and automatically restore ACs. The
indicated ACs are saved on the stack at the point of execution and a dummy
return is placed on the stack which causes these ACs to be restored
automatically when the current routine returns. Use of this facility
eliminates the need for matching push/pop pairs at the entry and exits of
routines and eliminates the bugs which often arise from an unmatched push or
pop. The facility is:
saveAC <a,b,c>
in which a, b, and c are AC names; one or more may be specified.
Defining a different mnemonic for a preserved AC may be of value when the AC
is used for a specific function by a large body of code. However, it offers
the possibility of confusion because two different symbols may refer to the
same AC unbeknownst to the programmer. In smaller programs, use of certain
ACs can be restricted to specific functions, and a global definition is
appropriate. A very large program, however, usually cannot accomodate a
sufficient number of dedicated ACs.
Therefore, when a specific function-oriented AC definition is made, it should
be explicitly decided which modules should use the definition (by "module" is
meant a separately-compiled section of code). Within these modules, the usual
name for the AC must be purged so that there is no possibility of using two
different symbols for the same AC.
Only preserved ACs may be used for special definitions. Parameters to
subroutines may be passed in functionally defined ACs in the following cases:
1. On an intra-module call where the contents of the AC is appropriate
to its function definition.
Standards Page 168
2. On an inter-module call where the same definition exists in both
modules and the AC is being used for its intended function.
A parameter may NOT be passed in a preserved AC unless both caller and callee
know it by the same name, and that name must be a specific one related to the
function which the AC is performing.
The procedure for declaring a functionally defined AC is:
defAC newAC,oldAC
This must be done at the beginning of an assembly, and it causes newAC to take
on the value of oldAC. OldAC must be the mnemonic for one of the regular
preserved ACs, and this mnemonic will be purged and therefore unavailable for
use in the current assembly.
An AC with a special definition should not be used for other purposes; e.g.
"JFN" should not be used to hold some quantity other than a JFN merely because
it happens to be available.
8.10. Subroutine Documentation
The following is a suggested format for documenting the calling sequence of a
subroutine. A description of this sort should appear at the beginning of
every subroutine, no matter how short.
srName: comment |
One or more lines describing what the subroutine does.
Enter with:
t1/ Description of first argument.
t2/ Description of second argument.
:
:
global foo/ Description of required global variable.
Returns:
+1: Conditions giving this return, with:
t1/ Value(s) returned.
t2/ More value(s) returned.
:
:
global foo/ Description of how it was effected.
+2: Conditions and values as above.
|
Notes:
1. The arguments, if any, should be documented as the contents of
registers and/or variables as shown. If there are more than 4
arguments, then the address of an argument list should be passed.
2. It is absolutely essential that all global inputs and outputs
(variables, tables, flags, etc., that are not declared within the
Standards Page 169
subroutine) be noted; failure to do so hides crucial assumptions
and effects from readers, and makes modification a very tricky
business.
3. An example of argument setup, call, and +1/+2 handling should be
given if necessary for clarification.
4. The return(s) should be noted as shown; "Always" or "Never" may be
used as the condition where appropriate; the +2 return need not be
shown if it does not exist; values returned should be described in
the same form as arguments.
8.11. Multi-line Literals
The use of multi-line literals is encouraged as a technique for making code
more readable and easier to follow. The following additional rules apply:
1. The opening bracket for a multi-line literal should occur in the
position that the first character of the address field would have
appeared if the instruction had an ordinary address, e.g.
skipge foo
jrst [
2. The first and all following instructions within the literal should
begin at the second tab stop, e.g.
jrst [ move t1, mumble ; Comment
jrst fie ] ; Comment
The tab between the open bracket and the first opcode may be
omitted if the line position is already at or beyond the second tab
stop, e.g.
GTJFN
ercal [move t1, mumble
If the first opcode is beyond the second tab stop, it is better to
start the enclosed code on a new line, e.g.
jumpge t1, [
move t1, mumble
3. The closing bracket should follow the last field of the last
instruction (as above), and should be before the comment on the
same line. It should have a blank before it to set it off from the
preceding token.
Standards Page 170
4. Nesting of multi-line literals to a depth greater than two is
discouraged because of awkward formatting problems.
5. Labels should not appear in multi-line literals.
6. No hard and fast fules can be given as to when to use or not use
multi-line literals. However, a literal longer than about 10 lines
becomes suspect.
7. Use of ".+1" is legal in a literal to return to the main sequence.
8.12. Flow of Control - Branch Conventions
In general, jumps should be to labels forward (down the page) from the point
of branch except for loops. Tops of loops should be identified by comment.
The expressions ".+1" and ".-1" are the only legal uses of "." (this
location). All other potential uses should be avoided in favor of an
explicitly defined label.
"Global" jumps should be avoided altogether. Higher-level languages do not
permit them, and with good reason. The only exceptions are jumps to well
defined and published exit sequences, e.g. R, RSKP (see subroutine
conventions, above).
8.13. Numbers
In general, there should be no occasion to use a literal number in in-line
code. All parameters, bit definitions, etc., should be defined mnemonically
at appropriate places. It is much easier to err in the direction of too
little use of mnemonics rather than too much; therefore, when in the slightest
doubt, define a mnemonic.
8.14. Sharability
When two or more people are running the same (copy of a) program, they can
share the memory pages it occupies. This cuts down on page faults and makes
the program, and the system, run more efficiently. Most higher level
languages produce sharable code automatically, but the assembly language
programmer must take special pains to do so. To write sharable programs, you
must collect all your impure data together in one place, segregating it from
actual program code and pure data (a word is impure if it can be modified at
runtime). Each user gets a private copy of any page that has been written
into, so sharability is greatest when all the impure data has been collected
into the fewest possible pages. Pure data (e.g. command or dispatch tables)
can be freely mingled with code provided there is no way for control to pass
into it.
Standards Page 171
8.15. Living in an Imperfect World
Much of the current DECSYSTEM-20 software was written before the existence of
this standard and therefore does not conform to it. A great deal of
systematic editing has already been done to improve conformance, but obvious
irregularities exist. In general, new code being added should conform exactly
to this standard even if being integrated with old code. The following are
some specific problems which may arise and the recommended solutions:
8.15.1. AC Mnemonics
Some code uses absolute numeric ACs. If new code is being integrated into a
sequence which uses numeric ACs, it is desirable that the existing code be
edited to use the standard mnemonics, particularly for the preserved ACs. If
the programmer cannot take the time to do that, then the mnemonics T1-T4
should be used for ACs 1-4, and other ACs should be referenced in the same way
as is done by the existing code. Some code uses mnemonics A,B,C,D for the
temporary ACs. These same mnemonics should be used for new code integrated
into this existing code, or all references can be edited to use the standard
mnemonics. You may write some code using the standard mnemonics for preserved
ACs and then discover that the module into which you wish to put this code has
redefined some of these ACs. The solution is one or a combination of the
following:
1. Move the new code to a module which does not redefine the preserved
ACs.
2. Use different preserved ACs -- ones which have not been redefined.
(Note it is not acceptable to use an AC with a special definition
for other than its special purpose.)
Clearly, code which needs some of the special definitions must be placed in a
module which has these ACs defined and must therefore use only the other
preserved ACs.
Note that a value which usually resides in a special AC need not ALWAYS reside
there; for example, it can be placed in one of t1-t4 as a subroutine argument.
8.15.2. Stack Handling
Use of the several stack variable facilities defined in MACSYM is recommended.
Some old code uses explicit PUSH and POP and references of the form -n(p)
however, and when anything more than trivial modifications must be made to
such code, it is most strongly recommended that the code be edited to use
STKVAR or TRVAR. Failing that, references must be consistent with the
existing code.
How To Page 172
9. How to Write, Assemble, and Run Programs
Macro programs must be entered into the computer by means of a text editor.
The best such editor is EMACS, which not only surpasses other editors in power
and flexibility, but understands the syntax of Macro programs; to take
advantage of this understanding you should put EMACS in Macro mode (MM Macro
Mode).
Macro programs are fully compatible with the Exec Load-Class commands. These
are:
COMPILE The COMPILE command produces a relocatable object program from
one or more source programs. The resulting object file has
the extension .REL. If there is already a .REL file of the
given name that is newer than any of the source files, no
compilation will be done unless the /COMPILE switch is
included.
LOAD The LOAD command invokes LINK, the system linkage-editor and
loader, to bring compiled modules into memory, resolving any
unresolved references, and produce an executable core image.
The LOAD command will recompile any module whose most recent
.REL file is older than the most recent source (.MAC), i.e.,
any source file you've edited since the last LOAD. If you
want to have a directly-executable (.EXE) version of your
program on the disk, you should issue the SAVE or CSAVE
command after the LOAD command completes. LOAD does not start
the program; you must use the START command to do this.
EXECUTE The EXECUTE does what the LOAD command does and then STARTs
execution of your program.
DEBUG The DEBUG command acts like the EXECUTE command, but it also
loads DDT (the source-level assembly language debugger) into
memory and starts DDT instead of the program. It is
equivalent to LOAD followed by DDT.
If you repeatedly edit your program with EMACS, EDIT, or Otto, you can issue a
special command which saves the .MAC file, exits from the editor, and then
tells the Exec to reissue its last load class command, with the 'saved
arguments'. In EDIT the command is 'g'; in Otto it is 'go'; in EMACS it must
be assigned to a key in your EMACS.INIT file.
All the LOAD-class commands have the following features:
1. Recognizing that your program is in Macro, provided the extension
(filetype) of the source file is .MAC.
2. Saving their arguments, or if no arguments were specified,
recalling the arguments of the last LOAD-class command in which
arguments were specified. For instance, if you have already issued
the command
LOAD foo,mylib:bar
you can achieve the same effect in subsequent compilations by
merely typing
How To Page 173
LOAD
The same effect is achieved by exiting the editor with a 'go'-type
command, as described above.
3. Taking arguments from an indirect file. You can put repeatedly used
arguments in a file as they would appear in the command and then
give a command like 'load @mac'. The '@' indicates that the
command should look to the file for its arguments.
4. Gathering files together to produce one program. This is done by
separating the files to be worked on by either commas or plus signs
on the command line; commas mean to consider the files as separate
modules (with surrounded by Title and End pseudo-ops), a plus signs
means to concatenate the enclosing files.
5. Passing switches to the compilers and LINK.
The load-class commands themselves have many switches. Type any load-class
command followed by a slash and then a question mark to see what they are.
DDT Page 174
10. Interactive Debugging of Assembly Language Programs
This chapter was adapted from the DECsystem-10 Utilities Manual and
the Rutgers University IDDT manual.
DDT (Dynamic Debugging Tool) is a program that allows you to test and debug
assembly language programs interactively using the same symbols (labels and
register names) that are used in the program. You can invoke DDT in either of
two ways: type 'DDT' after the completion of a LOAD command (or after GETting
an .EXE file) or by using the DEBUG command (see 9). In either case, the
effect is the same: DDT is loaded into pages 770-777 of your address space
(your program should not use these pages) and started. You may then type DDT
commands to examine storage locations, set breakpoints, execute selected
sections of the program, single-step through the program, search for certain
instructions or data, modify code or data, and so forth.
DDT commands are purposely terse, and therefore somewhat cryptic. You can use
DEL (RUBOUT) and ^U to edit commands; these have the expected effect, but echo
as "XXX".
In the following descriptions, a dollar sign ($) indicates that the ESC
(ESCAPE or ALTMODE) character should be typed. All numbers are in octal
unless otherwise noted.
10.1. Typeout Modes
You can select how DDT will display the contents of memory. Normally (i.e. by
default) it tries to interpret each word as an instruction, decoding the
opcode, accumulator, index, indirect, index, and address fields and
substituting appropriate values from the program's (or DDT's own) symbol
table, e.g. 202067,,1000 (octal) would be typed by DDT as
MOVEM T1, @FOO(Q3)
assuming that T1 is defined to be 1, Q3 to be 7, and FOO to be 100 in the
program's symbol table.
You can tell DDT to interpret words in other ways, either on a temporary or
prevailing basis.
The following commands are used to set the type-out modes:
$S Symbolic instruction.
$C Numeric, in current radix.
$F Floating point.
$T 7-bit ASCII text.
$6T SIXBIT text.
$5T RADIX50.
$H Halfwords, two addresses.
DDT Page 175
$nO Bytes (of n bits each), separated by commas.
10.1.1. Address Mode Typeout
The following commands are used to set the address modes in typeout of
symbolic instructions and halfwords:
$R Relative to symbolic address, e.g. FOO+17
$A Absolute numeric address, e.g. 4023.
10.1.2. Radix Typeout
You can also determine the radix (base, e.g. decimal, octal) in which the
numeric parts of a displayed word are typed, using the following command:
$nR Change radix to n (n>1).
10.1.3. Prevailing vs Temporary Modes
The typout-mode commands shown above may be started with a single ESC ($), or
two ESC's ($$):
$$ Set the prevailing type-out or address mode or a prevailing
radix (e.g. $$10R - set prevailing numeric radix to 10)
$ Set the temporary typeout mode; display words or fields in
this mode until carriage return is typed (e.g. $2R - set the
temporary numeric radix to 2).
CR (carriage return) Terminate temporary modes, and revert to prevailing
modes.
Initial modes are: $$S (symbolic instructions), $$R (relative addresses), and
$$8R (radix 8 [octal]).
10.2. Storage Words
The following commands are used to examine storage words. If you type ESC
between the address and the delimiter, the effective address of the typed
quantity will be calculated first, e.g. 1(p)$/ will print the contents of the
word after the one pointed to by p.
adr/ Open and examine the contents of adr in current type-out mode.
adr! Open, but inhibit the type-out.
adr[ Open and examine word as a number in current radix.
adr] Open and examine word as symbolic instruction.
DDT Page 176
; retype last quantity typed (useful after setting a temporary
type-out mode, e.g. $6T;).
adr\ Open in current mode, but don't change location counter.
10.2.1. Related Storage Words
The following are used to examine related storage words:
<lf> (linefeed or ^J) Close the current word (making any modifications typed
in) and to open the following word.
^ (circumflex) or ^H (backspace) to close current word (with modifications)
and open adr-1.
^I (tab) Close current word (with modifications) and open word
specified by address of current word and to set the location
counter to that place.
\ Same as ^I, but location counter is not changed.
<cr> Close word (with modifications) and revert type-out to
prevailing mode.
10.2.2. Retyping In Modes Other than the Prevailing Mode
Each of the following commands specifies the mode in which DDT should
immediately retype the last expression typed by DDT or the user. Neither the
temporary nor the prevailing mode is altered.
= Retype as halfwords in current radix.
_ (undescore) Retype as a symbolic instruction (address part determined by
$A or $R).
/ Type out, in current type-out mode, the contents of the
location specified by the address in the open instruction
word, and to open that location, but not to change the
location counter.
[ Retype as a number and open contents of the location specified
by the open instruction and not to change the location
counter.
] Same as above, but type out as a symbolic instruction.
10.3. Typing In
These are shown by example:
ADD AC1,@DATE(17) to type in instruction simply type it in symbolically.
DDT Page 177
402,,202 to type in halfwords.
1234 to type in octal values.
99. to type in fixed point decimal integer.
101.11 to type in ..
77.0E+2 ... a floating-point number.
"/ABCDE/ ASCII input (/ is delimiter; up to 5 characters).
"A$ ASCII input (one character, right justified).
$"/ABCDEF/ SIXBIT input (/ is delimiter; up to 6 characters).
$"Q$ one SIXBIT character.
10.4. Symbols
A symbol is is defined in DDT as a string of up to six letters and numbers
including the special characters ., %, and $. Characters after the sixth are
ignored. They are defined in a table kept with the program you are DDTing,
called the "symbol table". Programs have only one symbol table unless their
authors have taken explicit action to create more than one. Such actions
include compiling and/or linking the program from more than one source and/or
.REL file.
foo$: Permit reference to local symbols within a module with title
"foo" (open the symbol table of foo). You can refer to
symbols in a program without issuing this command, but DDT
always appends "#" to the symbol on typeout in this case to
show that it's only guessing. If a program has more than one
symbol table, you should use this command to let it know which
table to use.
n<sym Insert or redefine a symbol in the symbol table and give it a
value n.
sym: Insert or redefine a symbol and give a value equal to the
current location counter (.).
sym$$K Delete a symbol from the symbol table.
sym$K Kill a symbol for type-outs (but sill permit it for type-ins).
$D Perform a $K on last symbol typed out and then retype the last
quantity.
sym# Declare a symbol whose value is to be defined later.
? Type a list of all undefined symbols (created by #).
DDT Page 178
10.4.1. Special DDT Symbols
. The present location counter.
$Q The last quantity typed.
$$Q The last quantity typed, halves reversed.
@ Indirect bit.
$M The address of the mask register.
$I The address of save flags.
$nB Pointer to nth breakpoint.
10.4.2. Arithmetic Operators
DDT can evaluate expressions involving the following arithmetic operators:
+ two's complement addition.
- two's complement subtraction.
* integer multiplication.
' integer division (apostrophe).
Parentheses are used to denote an index field or to interchange the left and
right halves of the enclosed expression.
Expressions are evaluated as follows: A left parenthesis stores the states of
the storage-word assembler on a stack and reinitializes the assembler to form
a new storage word. A right parenthesis terminates the storage word and swaps
its two halves to form the result inside the parentheses. The result is
treated in one of two ways:
1. If +, -, ', or * immediately preceded the left parenthesis, the
expression is treated as a term in the larger expression being
assembled and therefore may be truncated to 18 bits if part of an
address field.
2. Otherwise, the swapped quantity is added into the storage word.
Parentheses may be nested to form subexpressions, to specify the left half of
an expression, or to swap the left half of an expression into the right half.
10.4.3. Field Delimiters In Symbolic Type-ins
SPACE Delimit opcode name (spaces or blanks). Add the value of the
immediately preceding expression (normally an opcode) into the
sotrage word, and set a flag so that the expression going into
the address field is truncated to 18 bits.
DDT Page 179
, (comma) Delimit accumulator field. The comma does three things:
1. The left half of the expression is added into the
storage word.
2. The right half is shifted left 23 bits (into the
accumulator field) and added into the storage word.
3. A flag is set to truncate addresses to 18 bits.
,, (double comma) Delimit two halfwords.
( ) Delimit index register (the halfwords are swapped).
@ Indicate indirect addressing (set bit 13).
The address field expression is terminated by any word termination command or
character.
10.5. Breakpoints
You can automatically stop your program at a strategic point by specifying an
address at which the program should stop if the instruction at that address is
about to be executed (i.e. if the PC (Program Counter) attains that value).
These addresses are called breakpoints; there may be up to eight of them
active at one time. Breakpoints may be set before the debugging run is
started or during another breakpoint stop.
The commands to set and remove breakpoints are:
adr$nB Set breakpoint n.
adr$B Set next unused breakpoint.
adr$$nB Set breakpoint...
adr$$B ... with automatic proceed.
x,,adr$nB Set breakpoint which will...
x,,adr$B ...automaticaly open and...
x,,adr$$nB ...display the contents of...
x,,adr$$B ...address X.
0$nB Remove breakpoint n.
$B Remove all breakpoints.
$nB/ Check status of a breakpoint.
If the address field (adr) is omitted, the breakpoint will be set at the
current location.
When your program reaches a breakpoint, DDT types (for example)
DDT Page 180
$7B>>FOO+23
where breakpoint number 7 was set at location FOO+23 (for instance, by the
command FOO+23$7B).
10.5.1. Proceeding from a Breakpoint
After you have poked around to your satisfaction, you may continue the program
using the following commands:
$P Proceed from a breakpoint. Keep executing until another (or
the same) breakpoint is encountered, or the program halts.
n$P Proceed as above, but pass this breakpoint n-1 times (i.e.
ignore it until the nth encounter).
$$P Proceed from a breakpoint...
n$$P ...and thereafter proceed automatically.
10.5.2. Single Stepping
After a breakpoint has been encountered, you may wish to single-step through
your program, rather than continuing with $P. DDT provides the following
commands for single-stepping:
$x Execute the current instruction, type out the new contents of
any locations affected by the instruction, type out the next
instruction, and wait. No breakpoints are moved or removed.
n$x Like $x, but do it for n instructions.
n$$x Same as $x, but execute instructions unconditionally, without
typing anything out, until PC reaches either .+1 or .+2. This
is useful for executing debugged subroutines or UUO's.
10.5.3. Conditional Breakpoints
You can insert a conditional instruction, or a call to a closed subroutine,
using the following command:
$nB+1/instruction Insert a conditional instruction or call a conditional
routine, when breakpoint n is reached.
When the breakpoint is reached, this instruction or subroutine is executed.
If the instruction (or subroutine) does not skip, the program either stops or
continues based on the contents of the proceed counter (located at $nB+2). If
the instruction or subroutine skips, the program stops. If the subroutine
causes a double skip return, the program proceeds. This works as follows:
DDT Page 181
skipe $nB+1 ; Conditional break instruction?
xct $nB+1 ; Yes, execute it (it may skip).
sosg $nB+2 ; Decrement proceed counter.
jrst <break routine> ; If greater than 0 then break
jrst <proceed routine> ; else proceed.
10.5.4. Starting the Program
$G Start at .JBSA (the normal starting address).
adr$G Start or continue at a specific address.
10.6. Searching
There are three kinds of searches: word search, not-word search, and
effective address search. In the following commands, a<b>c are respectively:
lower limit, upper limit, searchword; a defaults to 0, b defaults to "end".
The word search and not-word search compare each storage word with the word
being searched for in those bit positions where the mask, located at $M, has
ones. The mask word contains all ones unless otherwise set by you. All words
in the given range that show equality to the search object under the mask are
typed out.
a<b>c$w Search for word containing c.
a<b>c$N Search for word not containg c.
a<b>c$E Search for a word containing effective address c.
n$M Set the mask to n.
$M/ Examine the mask.
You may use the word search command to list the range of locations from
'first' to 'last', as follows:
0$M first<last>0$W
This sets the mask to 0 and then performs a word search for 0. Remember to
put the mask back to -1 (or whatever its previous value was) before
continuing.
10.6.1. Zeroing Memory
$$Z Zero memory except DDT, locations 20-137, and the symbol
table.
first<last$$Z Zero locations 'first' thru 'last'.
DDT Page 182
10.7. Special Characters
The following are used in DDT type-outs:
> Break caused by conditional break instruction.
>> Break because proceed counter exhausted.
U Undefined symbol can not be assembled.
# (as in FOO#) The symbol has been interpreted from a symbol
table you have not formally opened.
number,,number Half-word number type-out.
#1.234E+27 Unnormalized floating-point number.
123. Decimal point indicates decimal number.
? Illegal command or all 8 breakpoints used.
XXX Rubout, ^U echo.
10.8. Miscellaneous DDT Commands
10.8.1. Immediate Mode Instruction Execution
instr$X Execute the instruction in immediate mode.
10.8.2. Execute Indirect Command File
$Y Read and execute a command file called BATCH.DDT.
$"/name/$Y Read and execute a command file called name.DDT.
10.8.3. Patch
A patch is a section of code or data inserted into an .EXE file, usually to
correct a bug. At the appropriate location, an instruction is replaced by an
unconditional jump to the new code; the instruction that was displaced is
included in the new code, and the new code usually terminates with a jump back
the original sequence. You can use DDT to insert a patch with the following
commands:
$< Patch before the currently open location.
$$< Patch after the currently open location.
$> End the patch.
DDT Page 183
When you begin a patch, DDT will open the first location in the patch area (an
area set aside automatically by Macro, or by other means, for the installation
of patches). The patch area is defined by the symbol PAT.. or PATCH or
C(.JBFF), whichever is found first. Alternately, you can type a single symbol
preceding the patch begin command (as in "FF$<"), and it will be taken as the
beginning of the patch area. If you are doing a patch after the current
location, DDT will insert your original instruction and then open open the
next location. You may now proceed to enter your patch using linefeeds to
enter the new instructions or data.
When you have finished the patch, type $> and DDT will:
1. Close the current location, if any.
2. If a patch "before" was was being done, DDT will insert the
instruction from the original location.
3. DDT will insert JUMPA 1,LOC+1 and JUMPA 2,LOC+2, where LOC is the
original patch location. Thus skipping instructions may be
patched.
Note: the original location is not changed until the patch completion command
is given. Thus, you can give up or restart the patch at any time. DDT
remembers the parameters of the most recent patch begin command and uses them
at patch completion, whereupon they are forgotten. A second patch completion
will produce an error indication.
10.9. Sample DDT Session
Here's a very short DDT session, just to get you started. A Macro program is
compiled and loaded, DDT is called in, a breakpoint is set, the program is
started and runs until the breakpoint is encountered. A location is examined
and its contents replaced, and the program is then continued. This short
example illustrates the most useful DDT commands. In the example, after DDT
is started, DDT typeout is shown in upper case; your commands are shown in
lower case.
@load foo ; Compile and load the program.
MACRO: Foo
LINK: Loading
EXIT
@ddt ; Start DDT.
DDT ; DDT's greeting.
foo$: ; Open Foo's symbol table.
subr$b $g ; Set a breakpoint and start.
$1B>>SUBR ; The breakpoint is encountered.
./ MOVEM T1, FROB ; Display the instruction at the breakpoint.
t1/ 5 -1 ; Display contents of t1, then replace
; it with -1.
$x ; Now execute the instruction.
T1/ -1 FROB/ -1 ; The effected locations are displayed.
SUBR+1/ MOVE T1,Q1 $p ; The next instruction is shown, and
. ; the program is continued using $P.
. ; (the session continues...
. ; ...)
DDT Page 184
^Z ; Exit from DDT
@ ; back to the Exec.
10.10. IDDT (Invisible DDT)
This section is extracted from a document from Rutgers University,
describing IDDT, a program that has a long lineage, starting at BBN
and including at least SRI, MIT, and Rutgers. All of the elementary
commands and features have been included. For further details, see
the complete IDDT manual.
IDDT is a debugger which will handle programs with multiple forks and ones
which use high core (which is used by regular DDT) as well as other programs
which DDT can't handle. It has many of the same commands as the standard DDT
and ordinarily may be used without regard to the fact that it is a different
debugger.
The primary feature of IDDT is that it operates on user programs which run in
any inferior fork of IDDT. Thus, an errant user program cannot destroy the
debugger or its symbol table because the debugger is in a totally different
address space. This relation between the program being debugged and IDDT is
much the same as the relation between current user programs (including IDDT)
and the Exec. Because of this, IDDT must simulate many of the services
ordinarily provided by the EXEC, such as GET, LINK, RUN, etc.
10.10.1. Using IDDT
IDDT may be called into service either before or after programs have been
loaded into memory. This is done by typing the Exec command IDDT.
This command causes the EXEC to splice a fork containing IDDT in between
itself and the program to be debugged. This operation is done in a way that
preserves the state of the user's program including its fork structure. It is
possible to ^C out of a running program and get IDDT. If this is done, a $P
(Proceed) command will resume running the user program.
The EXEC command "NO IDDT" will unsplice the fork containing IDDT in the event
the user wishes to continue his program without having an IDDT above it.
A fairly common practice is to get IDDT first and use it to load the program
to be debugged. One of three IDDT commands may be used to load the object
program: $L (run LINK in the user fork), ;L (Loadgo (RUN) named file), or ;Y
(Yank (GET) the named file). The first of these is essentially the same as
the EXEC command, LINK. The second is comparable to RUN, while the last is
similar to GET. In addition the ;M (Merge the named file) will simulate the
MERGE EXEC command.
The $L command causes IDDT to run LINK in the user's address space. Upon
completion, LINK may return control to IDDT. At this point IDDT will have the
LOADER's symbol table. In order to switch to the symbols of the program which
was loaded, the ;S (Symbol) command should be typed. ;S tells IDDT to look
for a standard symbol table pointer in location 116 (.JBSYM).
DDT Page 185
10.10.2. EXEC-like Features
For convenience, IDDT has several commands which provide the same services as
some EXEC commands. These are:
<n>;A Give informaton about page n or if n is missing about all
pages. (like a INFO MEMORY command)
<n>;F Fork information about fork n or if n is missing about all
forks. (like INFO FORK command)
<n>;J JFN information on JFN n or if n is missing about all JFNs.
(like INFO FILES)
;;J Job information (like INFO JOB and INFO FORK)
;I Interupt status of PSI system (like INFO PSI-STATUS)
<n>;V "View cell" - sets address, contents of which is displayed
when ^T (control T) is typed. If n is missing clear "view
cell"
;Y Yank - analogous to EXEC command GET
;M Merge - analogous to EXEC command MERGE
;L Loadgo - Analogous to EXEC command RUN
$$G Go - analogous to EXEC command START
$$1G Analogous to EXEC command REENTER
$$nG Analogous to EXEC command START at offset n of entry vector
$P Proceed - analogous to EXEC command CONTINUE
;U Unget (SAVE 0 777)
a<b$nU Unprotect page (like SET PAGE-ACCESS command)
loc$$nU Set address break trap for loc in current fork; n is the type
of access to trap on (defaults to 2): 1 - read, 2 - write, 4
- execute (these can be or'ed together); like the EXEC command
SET ADDRESS-BREAK
;O Obtain symbol file (no EXEC equivalent)
;W Write symbol file (no EXEC equivalent)
;H Halt IDDT (return to EXEC)
;W, ;M, ;Y, ;O, ;L, and ;U ask for a file name from the user. The default
extension will be .EXE or .SYMBOLS as appropriate.
DDT Page 186
10.10.3. View Cell
A command such as FOO+5;V or 12345;V will define the "view cell". When IDDT
handles a ^T (control T) the address and contents of the view cell will be
typed. The view cell may be undefined and consequently removed from the ^T
(control T) typeout by ;V (no argument).
Note: The contents of the view cell in the fork to which IDDT's attention has
been directed to is what will be typed out on the ^T.
10.10.4. Breakpoints
When a fork hits a breakpoint, IDDT's handle on the breaking fork is printed
in parens before the breakpoint name unless it is the the top fork, e.g.
(2)$1B>>105.
10.10.5. Fork Handles
IDDT's attention can be shifted to any fork in the program being debugged
using the ;;F command. In the form: n;;F, fork n becomes current and all
examines, deposits, breakpoints etc pertain to it. n is a small number
(actually the low bits of IDDT's fork handle on the fork in question). 0
always means the top fork of the debugee. In the form m<n;;F, attention is
switched to the m-th inferior of fork n. Again, n is IDDT's handle on some
fork in the debugee. m is the low bits of fork n's relative handle on some
fork (IDDT executes GFRKH(400000+n, 400000+m) to get the new handle). The
relative handle so obtained is printed.
10.10.6. Escape character
IDDT initially arms ^D (control D) as an interrupt character. This may be
changes with the ;E (set Escape character) command. If a user program has
been started under IDDT, typing ^D (the escape character) will gracefully
suspend that process and give control to IDDT which then types a message of
the form
XXX:FOO+5/ MOVE A,DAT+21
The interrupt is understood to have occurred immediately before this
instruction, and that if a $P (proceed) command is typed, this instruction
will be the next one executed by the user.
10.10.7. RUBOUT and Type-in Editing
RUBOUTs typed while IDDT is running behave much the same as they do in normal
DDTs, that is, the current command is aborted. This is particularly
convenient for stopping long searches ($W, $N and $E commands), with IDDT
because it is an interrupt and does not have to be read by a PBIN to initiate
action as it does with old-style DDT's.
DDT Page 187
On command typein RUBOUT acts as it does under the EXEC, that is to delete the
previous character in the input buffer. In addition ^W and ^U (control W and
control U) also work as in the EXEC by deleting the word and line
respectively.
10.10.8. Interface with the Exec
The EXEC command "FORK n" may be used to switch the EXEC's attention between
the fork containing IDDT and the one containing the user's program. This may
be done for the purpose of doing a "MEMSTAT" or ^T. The EXEC examine and
deposit commands also pertain to the currently selected fork.
If the user has returned to the EXEC by typing ;H to IDDT, IDDT may be resumed
by a "CONTINUE". A HALTF in the user's program will return to IDDT. It may
be continued by a $P to IDDT.
10.10.9. Saving a Core Image
The ;U command asks for a file name and then does the equivalent of a SAVE
from page 0 through page 777 on this file. The entry vector will be copied if
it exists. If no entry vector has been declared for the fork, IDDT will set a
length one entry vector at "." . A message is typed to this effect.
10.10.10. Single Instruction Executes
When the user types an instruction followed by $X, IDDT pushes down several
words of state information, plants the instruction in the user's address space
followed by three breakpoints, and restarts the user at this special location.
When the instruction completes, IDDT types the proper number of $-signs to
indicate how many times the instruction skipped, and pops back the saved state
information. The state information currently includes the program counter
($G), and which breakpoint (if any) the user was stopped at. This makes it
possible to hit a breakpoint, execute an instruction (which might be a PUSHJ
to a subroutine), and then, upon completion of the $X, do a $P to proceed the
breakpoint.
IDDT's $X register points in the user's address space to the four words which
will be used for $X commands. $X initially contains 777774 so that the top
four words are used. The user is free to change the contents of $X.
10.10.11. Search Commands
The search commands ($W, $N, and $N) have been generalized to take an argument
which specifies the maximum number of "finds" that shall occur before the
search will terminate. An example is:
FOO<BAR>QQZZ$5E
This command will stop after typing five instructions lying between locations
"FOO" and "BAR" which have an effective address of "QQZZ".
DDT Page 188
10.10.12. Single Stepping
There are two flavors of single stepping, $Y and $J:
$J just fetches the next instruction and executes it, so if that next
instruction is a subroutine call, the entire subroutine will be executed, and
if that instruction is a jrst, the program will be continued.
$Y fetches the next instruction and if it is a jump of any sort, it is
interpreted so that in fact only one instruction is executed at a time, so
that if the instruction is a subroutine call, the program counter will be set
to the beginning of the subroutine. (this is most like $X in other DDTs)
Both commands have the same syntax:
$J single steps
<num>$J will step num times
<num>(<loc>)$J will step num instruction or until the contents of location loc
are changed, in which case it will stop and say
(WP)PC LOC/ new contents of loc
where pc is the instruction after the one that attempted to change the value
of loc. Note, however the contents of loc will not be changed.
<loc>$$J is equivalent to infinity(<loc>)$J, ie it will single step until an
attempt is made to change the contents of loc.
If the verbose switch is on, the instruction being executed and any AC's or
the view cell (see above) that change will be typed out.
Both instruction are extremely slow.
10.10.13. Other Commands
^L blanks the screen
$. returns current PC
;.<internal symbol name> inserts the value of the internal symbol into the
expression. Current internal symbols are:
SYMOFS Offset from symbol printed as in
<symbol>+<nnn> (default value is 777 octal).
PC Current PC (see also $.) (can be set with
<adr>$0G).
example: ;.PC/ 10010 displays the contants of the PC register
Examples Page 189
11. Programming Examples
The programs in this chapter are purely pedagogical in nature and don't do
anything useful.
11.1. Binary Search Program
title binSrc - Demonstration of binary search.
$VERNO=1 ; Program version number
$EDNO=2 ; Program edit number
comment \ Most recent update: 10:23am Thursday, 19 April 1979
Prompts user for a number, looks it up in a list containing the
even numbers from 2 to 12 (with some duplicates).
H. Eskin, F. da Cruz, CUCCA, April 1979
\
search CUsym ; Obtain Columbia macros, symbols, etc.
%setEnv ; Search Monsym, Macsym, initialize things.
numLen=^d20 ; Buffer for number typein.
; Standard 3-word entry vector
entVec: jrst start ; Start address
jrst reEntr ; Reentry address
%version ($VERNO,$EDNO) ; Standard version number
evlen=.-entvec ; Entry vector length
reentr: jrst start ; reentry handling (nothing special)
start: %setUp ; RESET, set up stack, etc.
hrroi t1, [asciz /Number to search for: /]
call getNum
call search
%print < No exact match%/>
%print < %d found at %o%/>,<exp t1,t2>
jrst start
Examples: Binary Search Page 190
search: comment | Binary search routine
Looks the given number up in a list, which is presumed to be
in ascending numeric order (with duplications allowed).
Returns values appropriately for insertion of a new element.
Enter with:
t1/ Number to search for.
global list/ list of numbers to be searched, in ascending order.
global top/ address of the word after the last element in the list.
Returns:
+1: if number not found,
+2: if number found, with (in either case):
t1/ Number that was found;
t2/ The address of the greatest number less than or equal
to the desired number. If no such number, then the address
of the word before the beginning of the list.
|
Lo=p1 ; Mnemonic aliases for registers
hi=p2 ; (not normally recommended).
PURGE p1,p2 ; (to avoid duplicate names for same ACs).
saveAC <hi,Lo,q1> ; Save these registers.
; Set up initial conditions.
movei Lo, list-1 ; Point before search list
move hi, top ; and after it.
; This loop does the binary search.
loop: cail lo, -1(hi) ; Is the list null?
jrst nFound ; Yes, then the element has not been found.
move q1, Lo ; No, calculate midpoint: set probe to Lo
add q1, hi ; ... + hi
idivi q1, 2 ; ... / 2.
camn t1, (q1) ; Exact match?
jrst found ; Yes, done.
; No match, adjust boundaries of list appropriately.
caml t1, (q1) ; If search key is not less than this one
skipa Lo, q1 ; then move low bound and skip
move hi, q1 ; else move high bound,
jrst loop ; and go back and try again.
;.. ; (continued next page...
Examples: Binary Search Page 191
;...continued from preceding page)
; Get here when the list is used up (and the search object not found).
nFound: move t1, (Lo) ; Greatest element that was less than search
move t2, Lo ; key was found at this address.
ret ; Return indicating failure to find key.
; Get here only on exact match. Must check for duplicates.
; Put aobjn counter in left half of probe, then search.
found: movn t2, top ; Negative Address of 1st element not in list.
add t2, q1 ; Calculate -number of elements to be checked.
hrl q1, t2 ; Make aobjn pointer.
next: camn t1, 1(q1) ; Toodle down the list until no match
aobjn q1, next ; or no more elements.
fin: move t1, (q1) ; Return the value that was found
hrrz t2, q1 ; and its address.
retskp ; Skip return to indicate that it was found.
p1=Lo ; Restore normal AC mnemonics
p2=hi ; ...
PURGE hi, Lo ; ...
Examples: Binary Search Page 192
getNum: comment | Get a number from the terminal, allowing editing.
Enter with:
t1/ pointer to asciz prompt.
global numBuf defined to be of length numLen.
Returns +1 always, with
t1/ number that was typed.
This routine catches all format errors and reprompts the user
until a valid integer is typed.
|
saveAC <t2,t3,q1> ; Since not used for passing args.
move q1, t1 ; Save pointer to prompt.
reTry: move t1, q1 ; And restore it in case of error.
PSOUT ; Issue the first prompt.
hrroi t1, numBuf ; Point to buffer for string that user types.
movx t2, RD%BEL!numLen ; Break on CRLF, max length for typein.
move t3, q1 ; Reprompting text.
RDTTY ; Get string, allowing editing.
%jsErr ; Errors are fatal, but very unlikely.
; Now convert the string to a number. We don't do the NIN directly from
; the terminal because NIN does not allow editing.
hrroi t1, numBuf ; Point to string representation of number.
movei t3, ^d10 ; Radix for interpretation.
NIN ; Number In - do the conversion.
%jsErr (,reTry) ; On error, print msg and ask again.
move t1, t2
ret ; All OK, return.
Examples: Binary Search Page 193
%impure ; impure data
numBuf: block numLen ; For number typein.
radix ^d10
list: 0
2
2
2
4
6
8
10
10
12
top: .
^L
end <evlen,,entvec>
; - EMACS editing modes -
; local modes:
; mode:Macro
; comment start:;
; comment rounding:+1
; end:
Examples: COMND JSYS Page 194
11.2. COMND Example
title Foo - A small Exec
$VERNO=1 ; Program version number
$EDNO=1 ; Program edit number
comment \ most recent update: 11:04am Wednesday, 30 May 1979
This program is written to demonstrate various things:
1. Use of the COMND JSYS via the Columbia UUOs, with secondary
parsing done by subroutines, which return success or failure indications
to the main parsing sequence. This is the recommended method for
writing most interactive programs.
2. The normal convention for "rescan" entry into a program. If the program
is invoked by typing "foo xxx" to the Exec, where "xxx" is a Foo command,
the program executes that command and then halts; in other words, it
behaves as though "foo xxx" was an Exec command. On the other hand, if
the program is invoked by typing "foo", the user is prompted for commands
until the "exit" command is given.
3. The $dir routine shows how to do filename stepping with the GNJFN JSYS.
4. The %print UUO is demonstrated in various places. The fact that it
assembles into one word in line is shown to be handy; it can be used
in "case" statements, it can be skipped over, etc.
F. da Cruz, CUCCA, May 1979
\
search CUsym ; Obtain macros, symbols, etc.
%setEnv ; Search Monsym, Macsym, initialize things.
extern rescan ; Routines from CUrel.
; Symbol and flag definitions
%flags <xitFlg>
Examples: COMND JSYS Page 195
; Standard 3-word entry vector
entVec: jrst start ; Start address
jrst reEntr ; Reentry address
%version ($VERNO,$EDNO) ; Standard version number
evLen=.-entVec ; Entry vector length
reEntr: jrst start ; Nothing special on reentry.
start: %setUp ; RESET, set up stack, etc.
call init ; Initialize.
jrst [ HALTF ; On failure, halt
jrst . ] ; and don't allow continuation.
; Get here after successful initialization, or upon continuation.
cont: call main ; Do the work.
HALTF ; and stop the program.
%trnOff xitFlg ; (In case they continue
jrst cont ; ...)
Examples: COMND JSYS Page 196
subttl Initialization
init: comment | Initialize the program. |
; Pass rescan argument (if any) to command parser
%trnOff xitFlg ; Turn off the exit flag
move t1, [point 7, [asciz/Foo/]] ; Name of this program.
call rescan ; Do rescan processing.
%trnOn xitFlg ; Rescan arg was found, turn on flag.
retskp
Examples: COMND JSYS Page 197
subttl Main program - highest level command parser.
main: stkVar temp ; Allocate local temporary variable on stack.
%skpOff xitFlg ; Rescan entry?
jrst repars ; Yes, don't set up prompt.
restar: %skpOff xitFlg ; If we get here with the exit-flag on, there
ret ; was an error in the rescan line, so exit.
; Come here when there were no arguments on the Exec command line.
%cmIni <<Foo>>,,,gjfBlk ; Issue prompt, specify GTJFN block address.
%jsErr <Foo internal error: .CMINI failure> ; Handle errors.
; This is the reparse address. Come here after any parse error, including
; deletion into a field previously parsed (this is done automatically by
; the %merrep and %jmerrep macros).
repars: %cmKey cmdTab,<command,> ; Get major command.
%merrep restar, repars ; Handle any parse errors.
hrrz t2, (t2) ; Get address of associated dispatch word
hrrzm t2, temp ; (we'll need it again soon)
load t1, %prsAd, (t2) ; and secondary parse routine address
call (t1) ; which we call to parse the next field(s).
%jmerrep restar, repars, restar ; Handle error return.
; Get here after all fields have been successfully parsed.
move t2, temp ; Get command table word back again,
load t1, %evlAd, (t2) ; and from it, the action routine address.
call (t1) ; Call the action routine.
nop ; (ignore failure)
%skpOff xitFlg ; Was it an exit command?
ret ; Yes, exit.
jrst restar ; No, keep going.
; This is the major command table. Note that it although it is data and
; not code, it is still pure storage, and can be kept with the routine
; that uses it.
cmdTab: %table
%key <directory>, [.dir,,$dir]
%key <echo>, [.echo,,$echo]
%key <exit>, [.exit,,$exit]
%key <help>, [.help,,$help]
%key <information>, [.info,,$info]
%tbEnd
Examples: COMND JSYS Page 198
subttl Secondary Parsing Routines and Action Routines.
.dir: comment | Parse rest of "directory" command. |
movx t1, CZ%NCL!.FHSLF ; Release all non-open JFNs
CLZFF ; ...
%cmNoi <of files> ; Issue guide words.
%pret ; Fail-return on error.
; Get file specification for directory listing.
%cmFil <file specification, possibly wild>,,CM%SDH
%pret ; Fail-return on error.
move q1, t2 ; Save directory JFN in q1.
%cmCfm ; Get confirmation.
%pret ; Fail-return on error.
retskp ; Return successfully.
$dir: comment | Execute the "directory" command. |
setzi p1, ; File counter.
move t1, q1 ; JFN of first file.
; Loop to get the next file that matches the given specification
; and to print its name at the terminal.
$dLoop: aos p1 ; Count the file.
hrrzs t1 ; Clear out the wildcard flags,
%print < %j%/>,<t1> ; and print the filename.
move t1, q1 ; Get back the original JFN.
GNJFN ; Get the Next JFN that matches.
jrst $dDone ; If none, then all done.
jrst $dLoop ; Loop for all files.
; Come here when no more files match the given specification.
$dDone: %print <%/ %d File>,<p1> ; Say how many files.
caie p1, 1 ; If other than one,
%print <s> ; then pluralize.
retskp ; Return successfully.
Examples: COMND JSYS Page 199
.echo: comment | Parse rest of "echo" command. |
%cmNoi <line> ; Issue noise word.
%pret ; Fail-return on error.
%cmTxt <line to be echoed,> ; Get a text line.
%pret ; Fail-return on error.
move t1, [point 7, buf] ; Get the text line into buf
%cmGab t1 ; from the atom buffer.
%cmCfm ; Get confirmation.
%pret ; Fail-return on error,
retskp ; otherwise return successfully.
$echo: comment | Execute the "echo" command. |
%print <%s>,<[point 7, buf]> ; Print the text line.
retskp
Examples: COMND JSYS Page 200
.exit: comment | Parse the rest of the "exit" command. |
%cmNoi <from Foo> ; Issue guide words.
%pret ; Fail-return on error.
%cmCfm ; Get confirmation.
%pret ; Fail-return on error,
retskp ; otherwise, return successfully.
$exit: comment | Execute the "exit" command. |
%trnOn xitFlg ; Just turn on the exit flag,
retskp ; and return successfully.
Examples: COMND JSYS Page 201
.help: comment | Parse the rest of the "help" command. |
%cmNoi <about> ; Issue noise words.
%pret ; Fail-return on error.
%cmKey hlpTab, <command,>, help ; Get command to help with.
%pret ; Fail-return on error.
hrrz p1, (t2) ; Get address of help text.
%cmCfm ; Get confirmation.
%pret ; Fail-return on error,
retskp ; otherwise return successfully.
$help: comment | Execute the "help" command. |
%print <%s>,<[point 7, (p1)]> ; Print the help text.
retskp
hlpTab: %table ; Table of help commands.
%key <directory>, $$dir
%key <echo>, $$echo
%key <exit>, $$exit
%key <help>, $$help
%key <information>, $$info
%tbEnd
$$dir: asciz |
Type "directory xxx", where "xxx" is a file specification. If there
is a file that matches that specification, its name will be typed.
If the specification is "wild", i.e. contains "*" or "%" characters,
the names of all files that match will be typed.
|
$$echo: asciz |
The 'echo' command types back what you type as its argument, e.g.
"echo xxx" types "xxx" at your terminal.
|
$$exit: asciz |
The 'exit' command halts the program. You can continue by
typing the Exec 'continue' command.
|
$$help: asciz |
The 'help' command gives information about the various Foo commands.
Type "help xxx" where 'xxx' is any Foo command. Type "help ?" to see
what commands have help available.
|
$$info: asciz |
The 'information' command prints information about various things.
Type 'information ?' to see what things are available.
|
Examples: COMND JSYS Page 202
.info: comment | Parse rest of "information" command. |
%cmNoi <about> ; Noise word.
%pret ; Fail-return on error.
%cmKey <infTab> ; Get keyword.
%pret ; Fail-return on error.
hrrz p1, (t2) ; Get info routine index.
%cmCfm ; Get confirmation,
%pret ; Fail-return on error,
retskp ; otherwise return successfully.
infTab: %table ; Info command table.
%key <connected-directory>, 0
%key <date-and-time>, 1
%key <logged-in-directory>, 2
%tbEnd
$info: comment | Execute the "information" command. |
xct [ %print < You are connected to %c> ; Print the quantity
%print < %n> ; given by the
%print < You are logged in as %u> ; "case index"
](p1) ; in p1.
retskp ; Return successfully
Examples: COMND JSYS Page 203
subttl Impure Data Section
%impure ; Declare it impure for sharability.
; GTJFN block for %cmFil. Some of the words are filled in by COMND,
; so this block must be in the impure section.
gjfBlk: GJ%OLD!GJ%IFG!GJ%FLG!GJ%ACC!.GJALL ; Flag bits,,generation number.
.PRIIN,,.PRIOU ; Input,,output JFNs.
0 ; Default device (none).
0 ; Default directory (none).
point 7, [asciz/*/] ; Default Filename (wild).
point 7, [asciz/*/] ; Default filetype (wild).
0 ; Default protection (none).
0 ; Default account (none).
0 ; JFN to assign (none).
0 ; No extended block.
block ^d10 ; Other args not used either.
buf: block ^d500/5+1 ; Buffer for "echo" string.
^L
end <evLen,,entVec> ; Address,,length of entry vector.
; - EMACS editing modes -
; local modes:
; mode:Macro
; comment start:;
; comment rounding:+1
; end:
Assembly Language Guide Page 204
Index
%clear 152
%cmRes 141
%erMsg 84, 153
%jsErr 74, 153
%print 136
%prSkp 137
%setEnv 151
%setUp 141, 151
.EXE 97, 174
.MAC 34, 172
.PRIIN 75, 78, 79, 83, 88
.PRIOU 75, 78, 79, 83, 88
.REL 34, 51, 97, 172, 177
.REQUIRE 57, 124
.RTJST 126
.UNV 34, 57
Accumulator 3, 8, 9, 12, 15, 73, 132, 149, 159, 165, 167, 174
Accumulators, Restoring 167
Accumulators, Saving 11, 167
ACVAR 134
ADD 19, 28
Address 4, 8, 62, 159, 174, 175
Address Space 184
ADJBP 25
ADJSP 12
AND 26, 36, 77
ANDCA 26
ANDCB 26
ANDCM 26
AOBJ 15
AOJ 17, 28, 67
AOS 16, 28
Appending to a File 79, 80
Argument 37, 63, 64, 67, 70, 73, 163, 168
Arithmetic 19, 20, 21
Arithmetic Expression 45
Arithmetic Shift 23
AROV 27
Array 15, 37, 47
ASCII 35, 36, 47, 70, 75, 101, 174, 177
ASCIZ 48, 76, 79, 101
ASH 22, 23, 27
ASHC 23, 27
Assembler 7, 34, 97
Assembly Language 2, 159
ASUBR 134
BIN 83
Binary 7, 35, 38
Bit 4, 8, 19, 26, 40, 75, 124, 174
BLOCK 48
Assembly Language Guide Page 205
BLT 10, 11
Boolean Logic 26
BOUT 83
Breakpoint 179, 186
Byte 4, 24, 48, 58, 75, 93, 174
Byte Pointer 24, 25, 55, 75, 126, 146, 165
CAI 18
CALL 131, 165
CALLRET 131, 166
CAM 18
Case Statement 32
Character 4
CLOSF 78, 81
Closing a File 81
Command Initialization 114, 140
Comment 36, 49, 59, 61, 64, 105, 159, 160, 168
COMND 85, 102, 136, 140, 144, 149, 154
COMPILE 172
Concatenation 37, 67
Conditional Assembly 164
Confirmation 79, 114
Continuation 35, 37, 105
CPU 4
CUrel 144
CUsym 104
CUUOs 136
Data Structure 128, 165
DCK 28, 29
DDT 58, 160, 172, 174
DDT Type-in 176
DDT Type-out 174, 182
Debug 172
DEC 3, 50
Decimal 34, 36, 38, 177
DECR 129
DECsystem-10 33
DECSYSTEM-20 3
Default Argument 64, 67
DEFINE 50, 63
DEFSTR 128, 165
Destination 12, 75
Device 78, 114, 138
DFAD 22
DFDV 22, 29
DFMP 22
DFSB 22
Difference 36
Directory 4, 78, 114, 138
Disk 3
DIV 20, 29
Divide 19, 20, 29
DMOVE 20
DMOVN 28
DMUL 27
Double Precision 20, 21, 22
Double Word 20, 23
Assembly Language Guide Page 206
DPB 24
Dummy Argument 63, 64
Effective Address 8, 175
EMACS 172
END 50, 54, 55
End of File 81, 82, 83, 85, 93, 96
ENTRY 45, 51
EQV 26
ERCAL 73, 137
ERJMP 73, 137
Error Message 73, 138, 153
Errors 71
Excess 200 21
EXCH 10
Exec 3, 97, 172, 184, 185, 187
Execute 172
EXP 51, 54
Exponent 21, 22, 23, 39
Expression 10, 37, 40, 45, 60, 70, 178
EXTERN 51
FAD 21
Fail 2, 159
Failure Return 73, 157
FDV 21, 29
FDVR 29
Field 77, 113, 126
File 4, 75, 77, 78, 93
File Name 78
File Pointer 93
File Type 78
FIX 22, 28
Fixed Point Arithmetic 19, 20
FIXR 23, 28
Flag 157, 165
FLD 77, 126
FLIN 92
Floating Point 21, 23, 36, 39, 92, 114, 138, 177
Floating Point Arithmetic 21
Floating Point Overflow 28
Floating Point Zero 21
FLOUT 92
FLTR 22, 23
FMP 21
Fork 97, 184
Fortran 39
FOV 28, 29
Fraction 21, 39
FSB 21
FSC 22
Generation Number 78, 79
GetOK 144
Global 44
GTJFN 78, 140
GTSTS 82
Guide Word 112
Assembly Language Guide Page 207
Halfword 12, 36, 46, 59, 76, 165, 174
HALTF 100
Handle 99
Help Message 105, 116, 144
HRROI 76
IBP 25
IDDT 184
IDIV 19, 29
IDPB 25, 55
IFx 51
ILDB 25, 55
IMUL 19, 28
INCR 129
Indefinite Repetition 69
Indentation 160
Index 8, 15, 37, 62, 159, 174
Indirect 8, 29, 30, 32, 37, 62, 159, 174
Indirect File 105, 173
Input File 79, 112
Input/Output 4, 81, 82, 84
Instruction 4, 7, 165
Instruction Modifier 9, 27
Integer 22, 23, 38, 90, 91
Integer Arithmetic 19, 20
INTERN 52
INTERNAL 36, 37, 44
IOR 26
IOWD 12, 53
IPB 55
IRP 53, 58, 69
IRPC 54, 58, 69
JAND 130
JFCL 32, 63
JFFO 33
JFN 78, 99
JFNS 79, 138
JFOV 63
JNAND 130
JNOR 130
JOR 130
JRA 30
JRST 31, 132
JSA 30
JSERR 135, 153
JSHLT 135
JSP 27, 30
JSR 27, 30
JSYS 7, 73
JSYS Error Recovery 74
JUMP 15
JXm 127
KA10 2, 7, 20, 21, 25
Keyword 111, 141, 154
KI10 2, 7, 11, 25
Assembly Language Guide Page 208
KL10 2, 7, 11, 25, 73
KS10 2, 7
Label 36, 43, 59, 159
LDB 24
Link 34, 51, 57, 124, 172
Linked List 130
LIT 40, 54, 55
Literal 10, 37, 40, 54, 136, 169
LOAD 129, 165, 172
Load-Class Commands 172
LOC 62
Local 44
Local Label 153
Location Counter 36, 41, 62
Logical Complement 36
Logical Expression 18, 45
Logical Shift 23
Logical Testing 26
Loop 15
Lowercase 35
LSH 23
LSHC 23
Macro Expansion 65
Macro-20 2, 34, 73, 159
Macros 35, 36, 37, 50, 59, 61, 63, 77, 124, 163
MACSYM 77, 86, 104, 124, 149, 165
MAKLIB 51
Mask 26, 77, 124, 126, 127
MASKB 127
Memory 3, 9, 12, 62, 97
Midas 2, 159
MOD. 135
Module 167
Modulo 135
Monitor 3, 7
Monitor Call 2, 7, 43, 73
MONSYM 75, 77, 149
MOVE 9, 20
MOVM 28
MOVN 28
MOVX 76, 127
MSKSTR 128, 165
MUL 20, 27
Multiply 19
NIN 90, 92
NOUT 77, 91, 92, 138
Number 111, 116, 152, 170
Number Conversion 22, 90
OCT 54
Octal 34, 36, 38, 138, 177
Opcode 59, 60, 62, 73, 159, 162, 174, 178
OPDEF 55, 60, 61, 165
OPENF 78, 80
Opening a File 80
Assembly Language Guide Page 209
Operand 59, 60
Operating System 3, 7
Operator 60
OPSTR 130
OPSTRM 130
OR 36, 77, 78
ORCA 26
ORCB 26
Output File 79, 112
Overflow 11, 12, 19, 20, 22, 23, 27, 31
Page 93, 145
Pagination of Programs 162
Pass 34, 61, 72
Patch 182
PBIN 83
PBOUT 83
PC 8, 19, 27, 31, 32, 125, 179, 188
PDP-10 3, 7, 33
PDP-6 3, 7, 21, 25
Phase 51, 72
POINT 25, 55
POINTR 126
POP 11, 12, 165, 171
POPJ 165
POS 126
PRGEND 55, 58
PRINTX 56
Process 97
Product 36
Program 97
Program Control 15, 30, 42, 73, 162, 170
Program Counter 27
Program Version Number 152
Prompt 88, 105, 140
Pseudo-op 47, 60
PSOUT 86
PURGE 56
PUSH 11, 12, 133, 165, 171
PUSHJ 27, 31, 133, 165
Quadruple Word 20
Quotient 36
R 166
Radix 38, 56, 175
RADIX50 174
Random-access Input/Output 93
RDTTY 85, 87, 90
Recognition 78, 79, 105
Reentrant 30, 170
Register 3, 9
RELOC 62
Remainder 19
REPEAT 56, 61
Rescan 147
RESET 99
RET 131, 133
Assembly Language Guide Page 210
RETSKP 131, 133
Return 165
RFORK 100
RFPTR 95
RIN 96
ROT 23
Rotate 23
ROTC 24
Round 23
ROUT 96
RSKP 166
Save 187
Scale 22
SEARCH 57, 124, 149
Sequential Input/Output 82, 94
SETA 26
SETCA 26
SETCM 26
SETCMP 129
SETM 26
SETO 26
SETONE 129
SETZ 26
SETZRO 129
SFPTR 94, 95
Sharability 170
Shift 23, 37, 40, 126
Sign 21, 38, 39, 91
SIN 84, 147
SIXBIT 36, 37, 57, 70, 138, 174, 177
SKIP 16
Skip Return 31, 73, 166
Skipping Instruction 160
SOJ 17, 28
SOS 16, 28
Source 12, 75
Source/Destination Designator 75
SOUT 85
Stack 11, 12, 31, 132, 151, 165, 171
Standards 159
Statement 34, 59, 61, 159
STCMP 101
STKVAR 132, 171
STOPI 58, 69, 70
STOR 165
String 75, 115
String Input/Output 84, 86
Style 159
SUB 19, 28
Subroutine 45, 73, 142, 165, 168
SUBTTL 58, 164
Sum 36
Swap 37
Switch 112
Symbol 37, 42, 75, 124, 150, 170, 177
Symbol Table 42, 44, 55, 57, 58, 61, 177
Symbol, Created 67, 68
Assembly Language Guide Page 211
Terminal 75, 78, 87, 99
TEST Instructions 26
TEXTI 85
Timesharing 3
TITLE 58, 164, 177
TMSG 134, 152
Token 115
Tops-10 34, 57, 58
Tops-20 3, 73
TRVAR 133, 171
Two's Complement 19, 21, 36, 38
TXmn 82, 127, 165
Unconditional Jump 31
UNIVERSAL 57
UUO 7, 144, 150
WID 126
Word 4, 7, 19, 21, 38, 40, 175
XCT 32
XOR 26
XWD 59
Z 59
Assembly Language Guide Page i
Table of Contents
1. Introduction 2
1.1. Basic Concepts 3
1.1.1. Terminology 3
1.1.2. Machine Organization 3
1.1.3. Instructions and Addressing Modes 4
1.1.4. Internal Representation of Numbers 4
1.1.4.1. Binary Numbers 4
1.1.4.2. Two's Complement Representation 5
1.1.4.3. Integers 5
1.1.4.4. Floating Point Numbers 5
1.1.5. Arithmetic 5
1.1.5.1. Integer Arithmetic 5
1.1.5.2. Floating Point Arithmetic 5
1.1.6. Logical Operations 5
1.1.7. Character String Manipulation 5
1.1.8. Elementary Data Structures 5
1.1.8.1. Tables (Arrays) and Indexing 5
1.1.8.2. Stacks 6
2. The PDP-10/DECSYSTEM-20 Instruction Set 7
2.1. Introduction 7
2.2. Full Word Instructions 9
2.2.1. MOVE 9
2.2.2. EXCH - Exchange 10
2.2.3. BLT - Block Transfer 10
2.2.4. Programming Examples Using Fullword Instructions 10
2.3. Stack Instructions 11
2.3.1. PUSH - Push on Stack 11
2.3.2. POP - Pop Stack 12
2.3.3. ADJSP - Adjust Stack Pointer 12
2.4. Halfword Instructions 12
2.4.1. HR - Halfword Right 13
2.4.2. HL Halfword Left 14
2.5. Arithmetic Testing 15
2.5.1. AOBJ - Add One to Both Halves and Jump 15
2.5.2. JUMP 15
2.5.3. SKIP 16
2.5.4. AOS - Add One and Skip 16
2.5.5. SOS - Subtract One and Skip 16
2.5.6. AOJ - Add One and Jump 17
2.5.7. SOJ - Subtract One and Jump 17
2.5.8. CAM - Compare Accumulator to Memory 18
2.5.9. CAI - Compare Accumulator Immediate 18
2.6. Fixed Point Arithmetic 19
2.6.1. ADD 19
2.6.2. SUB - Subtract 19
2.6.3. IMUL - Single-Word Multiply 19
2.6.4. IDIV - Single-Word Divide 19
2.6.5. MUL - Multiply 20
2.6.6. DIV - Divide 20
Assembly Language Guide Page ii
2.7. Double Word Move Instructions (KI10 and KL10) 20
2.8. Double Precision Integer Arithmetic (KL10 only) 20
2.9. Floating Point Arithmetic 21
2.10. Other Floating Point Instructions 22
2.10.1. FSC - Floating Scale 22
2.10.2. FIX - Convert Floating Point to Integer 22
2.10.3. FIXR - Fix and Round 23
2.10.4. FLTR - Float and Round 23
2.11. Shift Instructions 23
2.12. Byte Instructions 24
2.12.1. LDB - Load Byte 24
2.12.2. DPB - Deposit Byte 24
2.12.3. IBP - Increment Byte Pointer 25
2.12.4. ILDB - Increment and Load Byte 25
2.12.5. IDPB - Increment and Deposit Byte 25
2.12.6. ADJBP - Adjust Byte Pointer 25
2.12.7. POINT - Construct a Byte Pointer 25
2.13. Logical Testing and Modification 26
2.14. Boolean Logic 26
2.15. PC Format 27
2.16. Program Control 30
2.16.1. JSR - Jump to Subroutine 30
2.16.2. JSP - Jump & Save PC 30
2.16.3. JSA - Jump and Save Accumulator 30
2.16.4. JRA - Jump and Restore Accumulator 30
2.16.5. PUSHJ - Push on stack and Jump 31
2.16.6. POPJ - Pop stack and Jump 31
2.16.7. Programming Hints Using PUSHJ and POPJ 31
2.16.8. JRST - Jump and Restore 31
2.16.9. JFCL - Jump on Flag and Clear 32
2.16.10. XCT - Execute 32
2.16.11. JFFO - Jump if Find First One 33
2.17. References 33
3. The DECSYSTEM-20 Macro Assembler 34
3.1. Introduction 34
3.2. Elements of Macro 35
3.2.1. Special Characters 35
3.2.2. Numbers 38
3.2.2.1. Integers 38
3.2.2.2. Radix 38
3.2.2.3. Floating-point Decimal Numbers 39
3.2.2.4. Binary Shifting 40
3.2.2.5. Underscore Shifting 40
3.2.3. Literals 40
3.2.4. Symbols 42
3.2.4.1. Selecting Valid Symbols 43
3.2.4.2. Defining Symbols 43
3.2.4.3. Symbol-table Search Order 44
3.2.4.4. Symbol Attributes 44
3.2.5. Expressions 45
3.2.5.1. Arithmetic Expressions 45
3.2.5.2. Logical Expressions 45
3.2.5.3. Evaluating Expressions 46
Assembly Language Guide Page iii
3.3. Pseudo-ops 47
3.3.1. ARRAY 47
3.3.2. ASCII 47
3.3.3. ASCIZ 48
3.3.4. BLOCK 48
3.3.5. BYTE 48
3.3.6. COMMENT 49
3.3.7. DEC 50
3.3.8. DEFINE 50
3.3.9. END 50
3.3.10. ENTRY 51
3.3.11. EXP 51
3.3.12. EXTERN 51
3.3.13. IFx Group 51
3.3.14. INTERN 52
3.3.15. IOWD 53
3.3.16. IRP 53
3.3.17. IRPC 54
3.3.18. LIT 54
3.3.19. OCT 54
3.3.20. OPDEF 55
3.3.21. POINT 55
3.3.22. PRGEND 55
3.3.23. PRINTX 56
3.3.24. PURGE 56
3.3.25. RADIX 56
3.3.26. REPEAT 56
3.3.27. .REQUIRE 57
3.3.28. SEARCH 57
3.3.29. SIXBIT 57
3.3.30. STOPI 58
3.3.31. SUBTTL 58
3.3.32. TITLE 58
3.3.33. XWD 59
3.3.34. Z 59
3.4. Macro Statements and Statement Processing 59
3.4.1. Labels 59
3.4.2. Operators 60
3.4.3. Operands 60
3.4.4. Comments 61
3.4.5. Statement Processing 61
3.4.6. Assigning Addresses 62
3.4.7. Machine Instruction Mnemonics and Formats 62
3.4.8. Mnemonics with Implicit Accumulators 63
3.5. Using Macros 63
3.5.1. Defining Macros 63
3.5.2. Invoking Macros 64
3.5.3. Macro Invocation Format 65
3.5.4. Quoting Characters in Macro Arguments 66
3.5.5. Nesting Macro Definitions 67
3.5.6. Concatenating Macro Arguments 67
3.5.7. Default Arguments and Created Symbols 67
3.5.7.1. Specifying Default Values 68
3.5.7.2. Created Symbols 68
3.5.8. Indefinite Repetition 69
3.5.9. Alternate Interpretations of Characters Passed to Macros 70
Assembly Language Guide Page iv
3.6. Errors and Messages 71
3.6.1. Informational Messages 71
3.6.2. Single-Character Error Codes 72
3.6.3. MCRxxx Messages 72
4. Introduction to Tops-20 Monitor Calls 73
4.1. Introduction 73
4.2. General Information 73
4.3. Using Mnemonic Symbols 75
4.4. Source/Destination Designators 75
4.5. Setting up a JSYS Invocation 76
4.6. JSYS's to Open and Close Files 77
4.6.1. GTJFN (JSYS 20) - Get Job File Number (short form) 78
4.6.2. OPENF (JSYS 21) - Open a File 80
4.6.3. CLOSF (JSYS 22) - Close a File. 81
4.7. File i/o JSYS's 81
4.7.1. GTSTS (JSYS 24) - Get file Status 82
4.7.2. Sequential Byte i/o 82
4.7.2.1. BIN (JSYS 50) - Byte In 83
4.7.2.2. PBIN (JSYS 73) - Primary Byte In 83
4.7.2.3. BOUT (JSYS 51) - Byte Out 83
4.7.2.4. PBOUT (JSYS 74) - Primary Byte Out 83
4.7.2.5. Example of Byte i/o 84
4.7.3. String-oriented i/o 84
4.7.3.1. SIN (JSYS 52) - String In 84
4.7.3.2. SOUT (JSYS 53) - String Out 85
4.7.3.3. PSOUT (JSYS 76) - Primary String Out 86
4.7.3.4. Example of String I/O 86
4.7.3.5. RDTTY (JSYS 523) - Read string interactively from TTY 87
4.7.3.6. RDTTY Example 89
4.7.4. Number conversion JSYS's 90
4.7.4.1. NIN (JSYS 225) - Number In 90
4.7.4.2. NOUT (JSYS 224) - Number Out 91
4.7.4.3. NIN/NOUT Example 92
4.7.5. Random-access i/o 93
4.7.5.1. RFPTR (JSYS 43) - Read File Pointer 95
4.7.5.2. SFPTR (JSYS 27) - Set File Pointer 95
4.7.5.3. RIN (JSYS 54) - Random byte In 96
4.7.5.4. ROUT (JSYS 55) - Random byte Out 96
4.8. Fork-Handling JSYS's 97
4.8.1. What's in a Fork? 97
4.8.2. The Fork Environment 99
4.8.3. Basic Fork-Handling JSYS's 99
4.8.3.1. RESET (JSYS 147): Reset the current fork 99
4.8.3.2. HALTF (JSYS 170) - Halt the current fork 100
4.8.3.3. Examples of RESET and HALTF 100
4.9. Miscellaneous JSYS's 100
4.9.1. STCMP (JSYS 540) - STring CoMParison 101
5. The COMND JSYS - JSYS 544 102
5.1. Informal Introduction 102
Assembly Language Guide Page v
5.2. General Information 104
5.3. Bits Supplied in State Block on COMND Call 109
5.4. Function Descriptor Block 110
5.4.1. Words .CMFNP and .CMDAT of the FDB 111
5.4.2. Word .CMHLP of the FDB 117
5.4.3. Default Help Messages 118
5.4.4. Word .CMDEF of the FDB 119
5.4.5. Word .CMBRK of the FDB 119
5.5. Bits Returned on COMND Call 120
5.6. Macros 121
5.6.1. FLDDB.(TYP,FLGS,DATA,HLPM,DEFM,LST) 121
5.6.2. FLDBK.(TYP,FLGS,DATA,HLPM,DEFM,BRKADR,LST) 122
5.6.3. BRMSK.(INI0,INI1,INI2,INI3,ALLOW,DISALLOW) 122
5.6.4. FLDBK. 122
5.7. Errors 123
6. MACSYM System Macros 124
6.1. Introduction 124
6.2. Definitions 124
6.2.1. Standard Program Version 125
6.2.2. Miscellaneous Constants (Symbols) 125
6.2.3. Control Characters (Symbols) 125
6.2.4. PC Flags (Mask Symbols) 125
6.2.5. Macros to Manipulate Field Masks 126
6.2.5.1. WID(MASK) 126
6.2.5.2. POS(MASK) 126
6.2.5.3. POINTR(LOC,MASK) 126
6.2.5.4. FLD(VAL,MASK) 126
6.2.5.5. .RTJST(VAL,MASK) 126
6.2.5.6. MASKB(LBIT,RBIT) 127
6.2.6. Instructions Using Field Masks (Macros) 127
6.2.6.1. MOVX AC,MASK 127
6.2.6.2. TXmn AC,MASK 127
6.2.6.3. IORX AC,MASK; ANDX AC,MASK; XORX AC,MASK 127
6.2.6.4. JXm AC,MASK,ADDRESS 127
6.2.7. Data Structure Facility (Macros) 128
6.2.7.1. DEFSTR and MSKSTR 128
6.2.8. Subroutine Conventions (Macros/opDefs) 131
6.2.8.1. CALL address 131
6.2.8.2. RET 131
6.2.8.3. RETSKP 131
6.2.8.4. CALLRET address 131
6.2.8.5. AC Conventions 132
6.2.9. Named Variable Facilities (Macros and Runtime Code) 132
6.2.9.1. STKVAR namelist 132
6.2.9.2. TRVAR namelist 133
6.2.9.3. ASUBR namelist 134
6.2.9.4. ACVAR namelist 134
6.2.10. Miscellaneous 134
6.2.10.1. TMSG string 134
6.2.10.2. JSERR 135
6.2.10.3. JSHLT 135
6.2.10.4. MOD.(DEND,DSOR) 135
Assembly Language Guide Page vi
7. Columbia Macros and Packages 136
7.1. Utility UUO Package for Macro-20 136
7.1.1. Formatted Printing Package 136
7.1.2. %prPush and %prPop 139
7.1.3. COMND-Jsys-Made-Easy Package 140
7.1.3.1. %cmRes 141
7.1.3.2. %cmKey (keytab, help, default, flags) 141
7.1.3.3. %cmgab bp 142
7.1.3.4. %comnd flddb 142
7.1.3.5. %cmgfg flag 142
7.2. CUrel Utility Subroutines 144
7.2.1. Helper 144
7.2.2. GetOK 144
7.2.3. Gfcpg 145
7.2.4. pagMgr 145
7.2.5. Subbp 146
7.2.6. Rescan 147
7.3. CUsym MACSYM Augmentation Macros 149
7.3.1. Accumulator Support 149
7.3.2. %DefAC 150
7.3.3. Useful Symbols 150
7.3.4. UUO Package OPDEFs and Interface Symbols 150
7.3.5. Setup Environment Macros 151
7.3.5.1. %setEnv 151
7.3.5.2. %setUp 151
7.3.6. Storage Declaration Macros 151
7.3.7. General-Purpose Macros 151
7.3.7.1. %Stack 151
7.3.7.2. %Version 152
7.3.7.3. %Clear 152
7.3.8. Macros Used for Common Primary I/O 152
7.3.8.1. %typeCR(string) 152
7.3.8.2. %crType(string) 152
7.3.8.3. %typNum(num,cols,rdx) 152
7.3.8.4. %crlf 153
7.3.8.5. %tab 153
7.3.9. JSYS Support Macros 153
7.3.9.1. %jsErr 153
7.3.9.2. %erMsg 153
7.3.10. Local Label Support Macros 153
7.3.10.1. %Cat(a,b) 154
7.3.11. COMND JSYS Support Macros 154
7.3.11.1. %Ptr(string) 154
7.3.11.2. %table and %tbEnd 154
7.3.11.3. %key(name, data, flags) 154
7.3.11.4. %Flddb (typ, flgs, data, hlpm, defm, lst) 155
7.3.11.5. %Handlr(p,e), %PrsAdr, %EvlAdr 155
7.3.11.6. %CMxxx Macros to Invoke .CMxxx COMND Functions 155
7.3.12. Macros to Handle COMND Errors 156
7.3.12.1. %pret 156
7.3.12.2. %errep errlab, replab 156
7.3.12.3. %merrep errlab, replab 157
7.3.12.4. Macros for Fail-Return from Parsing Routines 157
7.3.12.5. %jerrep errlab, replab, othrlb 157
7.3.12.6. %jmerrep errlab, replab, othrlb 157
7.3.13. Flag-Handling Macros 157
7.3.13.1. %Flags(aFlg,bFlg,cFlg,...) 157
Assembly Language Guide Page vii
7.3.13.2. %trnOn & %trnOff 157
7.3.13.3. %TrOnS & %TrOfS 158
7.3.13.4. %SkpOn & %SkpOff 158
7.3.13.5. %AnyOn & %AnyOff 158
7.3.14. CUuos (CUCCA Utility UUOs) Interface 158
7.3.14.1. %print, %prSkp 158
8. Macro-20 Programming Standards and Conventions 159
8.1. Introduction 159
8.2. Statements 159
8.3. Comments 160
8.4. Pagination of Source Programs 162
8.5. Other Assembler Functions 163
8.6. Instruction Mnemonics 165
8.7. Variables and Structures 165
8.8. Subroutines 165
8.9. AC Definitions 167
8.10. Subroutine Documentation 168
8.11. Multi-line Literals 169
8.12. Flow of Control - Branch Conventions 170
8.13. Numbers 170
8.14. Sharability 170
8.15. Living in an Imperfect World 171
8.15.1. AC Mnemonics 171
8.15.2. Stack Handling 171
9. How to Write, Assemble, and Run Programs 172
10. Interactive Debugging of Assembly Language Programs 174
10.1. Typeout Modes 174
10.1.1. Address Mode Typeout 175
10.1.2. Radix Typeout 175
10.1.3. Prevailing vs Temporary Modes 175
10.2. Storage Words 175
10.2.1. Related Storage Words 176
10.2.2. Retyping In Modes Other than the Prevailing Mode 176
10.3. Typing In 176
10.4. Symbols 177
10.4.1. Special DDT Symbols 178
10.4.2. Arithmetic Operators 178
10.4.3. Field Delimiters In Symbolic Type-ins 178
10.5. Breakpoints 179
10.5.1. Proceeding from a Breakpoint 180
10.5.2. Single Stepping 180
10.5.3. Conditional Breakpoints 180
10.5.4. Starting the Program 181
10.6. Searching 181
10.6.1. Zeroing Memory 181
10.7. Special Characters 182
10.8. Miscellaneous DDT Commands 182
10.8.1. Immediate Mode Instruction Execution 182
10.8.2. Execute Indirect Command File 182
10.8.3. Patch 182
Assembly Language Guide Page viii
10.9. Sample DDT Session 183
10.10. IDDT (Invisible DDT) 184
10.10.1. Using IDDT 184
10.10.2. EXEC-like Features 185
10.10.3. View Cell 186
10.10.4. Breakpoints 186
10.10.5. Fork Handles 186
10.10.6. Escape character 186
10.10.7. RUBOUT and Type-in Editing 186
10.10.8. Interface with the Exec 187
10.10.9. Saving a Core Image 187
10.10.10. Single Instruction Executes 187
10.10.11. Search Commands 187
10.10.12. Single Stepping 188
10.10.13. Other Commands 188
11. Programming Examples 189
11.1. Binary Search Program 189
11.2. COMND Example 194
Index 204