mirror of
https://github.com/PDP-10/its.git
synced 2026-01-30 13:36:42 +00:00
474 lines
22 KiB
Plaintext
Executable File
474 lines
22 KiB
Plaintext
Executable File
STANFORD ARTIFICIAL INTELLIGENCE LABORATORY
|
||
Rr
|
||
|
||
DDT FOR THE PDP-11
|
||
|
||
Jeff Rubin
|
||
(with additions by Bo Eross)
|
||
|
||
|
||
DDT is a symbolic debugger written for the PDP-11. Its command
|
||
structure is quite similar to that of PDP-10 DDT except where
|
||
machine differences dictated otherwise. The current version of DDT
|
||
runs on a PDP-11/45 with a floating point processor (FPP) but with
|
||
no memory management unit. It is expected that DDT will be revised
|
||
when the page map is installed on the 11/45 and also for the 11/40
|
||
which will come with the KL-10. All numbers in this manual are assumed
|
||
to be in decimal unless otherwise indicated. The letter will be used
|
||
indicate alt-mode unless the text specifies differently. The
|
||
character ^ will be used directly in front of an uppercase letter to
|
||
indicate that that letter should be typed with the control key
|
||
held down. { and } are used as meta parentheses and are not meant to
|
||
be typed in or typed out.
|
||
|
||
1 Examining and Altering Locations
|
||
|
||
1.1 Expressions
|
||
|
||
DDT parses arithmetic expressions in either integer or floating
|
||
point. Mixed mode is not allowed. Expressions may be fully parenthesized
|
||
and are interpreted using a strict precedence scheme. The operators are:
|
||
|
||
Precedence Operator Operation
|
||
|
||
0 ,, high byte,,low byte
|
||
2 + or space binary addition
|
||
2 - binary subtraction
|
||
3 * binary multiplication
|
||
3 ! binary division
|
||
4 - unary minus
|
||
|
||
+ used as a unary operator is ignored. Operations associate to the left
|
||
where the precedence is the same for
|
||
both operations. Operands may be integer, floating point or text constants,
|
||
symbol names or special symbols.
|
||
|
||
1.1.1 Integers
|
||
|
||
Integers are assumed to be in octal unless they are immediately followed
|
||
by a decimal point. Integers must fit into a 16 bit field.
|
||
|
||
1.1.2 Floating Point Numbers
|
||
|
||
DDT accumulates floating point numbers in double precision. Floating
|
||
point is indicated either by having digits both before and after a
|
||
decimal point or by using the standard E notation. In E notation, there
|
||
must first be an integer optionally followed by a decimal point and another
|
||
integer followed immediately by an E and an (optionally signed) integer
|
||
power of 10 to scale the number by. All the integers in a floating point
|
||
number are assumed to be decimal. The following are all valid floating
|
||
point numbers:
|
||
|
||
0.12 105.0 3.14E-6 0.21718E1 105.69E+4
|
||
|
||
1.1.3 Text Constants
|
||
|
||
There are three types of text constants: single character ascii, double
|
||
character ascii and radix 50. '{char} has the value of the ascii character
|
||
char. "{char1}{char2} has the ascii value of char1 in the low
|
||
byte and the ascii value of char2 in the high byte. &{char1}{char2}{char3}
|
||
has the value of the radix 50 equivalent of the symbol {char1}{char2}{char3}.
|
||
If it is desired to not have all three characters in the value then fewer
|
||
characters
|
||
may be given as long as they are followed by some non radix 50 character. In this
|
||
case the resulting radix 50 value will be left justified within a word. The
|
||
following table lists the correspondence between ascii and radix 50:
|
||
|
||
ASCII RADIX 50 (in octal)
|
||
|
||
A - Z 1 - 32
|
||
$ (dollar) 33
|
||
. 34
|
||
% 35
|
||
0 - 9 36 - 47
|
||
|
||
1.1.4 Symbols and Register Values
|
||
|
||
Symbols may be constructed with from 1 to 6 radix 50 characters. The
|
||
first character of a symbol may not be an integer and it may not be . if
|
||
all the remaining characters are integers. DDT maintains a symbol table
|
||
and the symbol typed by the user is looked up in this table. If it is found,
|
||
then the corresponding value from the table is used in the expression evaluation.
|
||
If not then the message ?U? is typed and the current expression evaluation is
|
||
aborted. Symbol values may be either integer or register values. A register
|
||
value, when used in an integer expression, causes a flag to be set so that
|
||
the resulting expression value is considered a register value. Register values
|
||
must be between 0 and 7 inclusive. Register values can only be typed in as
|
||
a result of typing a symbol which has a register value. See section 1.1.5 on
|
||
special symbols for
|
||
a description of predefined symbols which have register values. Symbols may
|
||
be defined in two ways. First, typing FOO: defines FOO to have the
|
||
value of . (see section 1.1.5 on special symbols). If . is a register value then
|
||
FOO will be defined as a register symbol. The second way is to type
|
||
val<FOO: which defines FOO to have the value val. Again, if
|
||
val is a register value then FOO will also be a register value.
|
||
DDT uses symbols for typing out values whenever possible (see section 1.2.2 on
|
||
typeout modes). Sometimes it is undesirable for certain symbols to be used
|
||
on typeout. It is possible to half-kill these symbols, which leaves
|
||
their values alone but marks them so that DDT will never use them for typeout
|
||
purposes. FOOK half-kills FOO.
|
||
|
||
1.1.5 Special Symbols
|
||
|
||
Certain symbols have been predefined in DDT. They are:
|
||
|
||
. current location counter (see section
|
||
1.2 on opening locations)
|
||
Q last value typed in or out
|
||
0Q low byte of Q if it was an integer
|
||
1Q same as 0Q but the high byte
|
||
M address within DDT where the search mask is stored
|
||
(see section on searches)
|
||
%0 through %7 register values 0 through 7
|
||
|
||
1.1.6 Instruction Typein
|
||
|
||
An instruction may be typed in instead of an expression. Instructions are
|
||
typed in the same way as in PALX with the exception of the condition code
|
||
instructions. Any address or constant in an instruction may be a normal
|
||
expression. The condition code instructions are input by typing CL
|
||
or SE followed by a space followed by the condition code letters to
|
||
be set or cleared (C, Z, N or V).
|
||
|
||
1.2 Opening Locations
|
||
|
||
The commands that open locations are / \ [ linefeed and tab. Each
|
||
command sets the value of the symbol . to the location being opened, which
|
||
may be a register. The last two, linefeed and tab, have the ability to
|
||
alter locations and if a value is typed in front of them that value is stored
|
||
in the currently open location, if any.
|
||
|
||
1.2.1 / and [
|
||
|
||
Three commands for examining core locations are addr0/
|
||
addr[ and addr\. These commands all open location addr
|
||
and type out the contents of the byte or word at addr in some mode.
|
||
There are two modes in which a location can be open: word mode and
|
||
byte mode. Any command that opens a location in byte mode will type
|
||
the contents of the open byte as an unsigned integer. Any address
|
||
(odd or even) can be opened in byte mode. The \ command always opens locations
|
||
in byte mode. The [ command opens the location in word mode and types out
|
||
the contents of the word as an unsigned integer. If the location was at
|
||
an odd address then the command acts as if it were addr\. The / command
|
||
also opens the location in word mode, but it types out the contents of the
|
||
word in the current typeout mode (see section 1.2.2 on typeout modes). It also
|
||
acts like \ if the location is odd. Once a location is opened it is enabled
|
||
for having things stored into it. The location stays open until a command
|
||
is executed which specifically closes the location (see section 1.2.4 on altering
|
||
locations).
|
||
|
||
These three commands may also be executed without a preceding
|
||
argument, in which case the location that is opened is the value that
|
||
was last typed out as the result of opening some location. If that open location
|
||
was typed as an instruction, then the new location to be opened is the last
|
||
address referenced by that instruction.
|
||
|
||
There are several other commands which open locations, but these will be
|
||
discussed in section 1.2.4 on altering locations.
|
||
|
||
1.2.2 Typeout Modes
|
||
|
||
The form in which an even addressed location is typed by the / command
|
||
depends upon the typeout mode. The typeout modes are:
|
||
|
||
Mode Description
|
||
|
||
constants signed 16 bit number
|
||
symbolic (non half-killed) symbol plus numeric offset (like FOO+12)
|
||
byte unsigned 8 bit number
|
||
halfword high byte,,low byte both as unsigned 8 bit numbers
|
||
floating this and the next location (or the next three) are typed
|
||
as a single (or double) precision floating point number
|
||
text ascii and radix 50 characters
|
||
instruction this location and those following that make up the instruction
|
||
are typed out as an instruction (floating point instructions
|
||
optional)
|
||
|
||
Within these modes there are the following submodes:
|
||
|
||
octal/decimal the numeric parts of all integer typeouts (except in
|
||
a floating point number) are controlled by this submode
|
||
absolute/relative in absolute mode no symbols are typed out
|
||
floating double in this submode, floating point typeout types four words in
|
||
double precision; this submode also controls how many words
|
||
are stored in a location when a floating point number is
|
||
stored (see section 1.2.4 on altering locations)
|
||
floating instruction in this submode of instruction mode floating
|
||
point instructions are typed rather than negative numbers
|
||
|
||
For each of the above modes except for the floating point submodes
|
||
there is a temporary mode and a permanent mode. The floating point submodes
|
||
are permanent only.
|
||
It is the temporary modes that control typeout. The permanent modes are
|
||
copied into the temporary modes whenever carriage return is typed or
|
||
when DDT is entered from a breakpoint or startup. Corresponding to each
|
||
of the modes is a letter. The command {letter} sets the corresponding
|
||
temporary and permanent modes. The command {letter} sets the
|
||
temporary mode only. The single commands may be typed anywhere within an
|
||
expression, while the double commands terminate and ignore any expression
|
||
that might be in progress. The letters are as follows:
|
||
|
||
letter function
|
||
|
||
A absolute mode
|
||
C constants mode
|
||
D decimal mode
|
||
F floating mode
|
||
H halfword mode
|
||
I instructions mode
|
||
L floating long (double precision) mode
|
||
O octal mode
|
||
R relative mode
|
||
S symbolic mode
|
||
nT text mode, where n=5 for radix 50, n=7 or absent for ascii
|
||
V floating instruction typeout mode
|
||
Y byte mode
|
||
|
||
1.2.3 _ and @
|
||
|
||
There are two further commands which open locations.
|
||
_ is intended for opening the source location of the most recently
|
||
typed out binary instruction. For example if the last thing typed
|
||
out was MOV FOO,BAR then _ will open FOO (whereas / will open
|
||
BAR).
|
||
@ causes the contents of the PC to be the location opened and it sets
|
||
the temporary typeout mode to instruction mode. It is useful for
|
||
seeing what instruction will be executed next.
|
||
|
||
1.2.4 Altering Locations: tab, linefeed and carriage return
|
||
|
||
Once a location is opened it may be altered by depositing a new
|
||
value in that location. There are three commands used to alter locations, tab,
|
||
linefeed and carriage return. Each of these commands may be preceded by a
|
||
value which is then deposited in the currently open location if there is one.
|
||
How much is stored depends upon the mode in which the location is open and
|
||
upon what value was typed. If the location was open in byte mode then floating
|
||
point values and instructions may not be stored. The value that is stored will
|
||
be deposited only in the byte that is open, even if it is a register open in byte
|
||
mode. If the open location is a register in word mode then again, floating
|
||
point values and instructions cannot be stored. If a floating point value is
|
||
being stored in word mode then either two words or four are stored depending
|
||
upon the state of double precision floating point mode (see section 1.2.2
|
||
on typeout modes). An instruction that is being stored will take up the
|
||
appropriate number of words (from one to three). After a value is stored (if
|
||
there was a value typed) the open location is then closed.
|
||
|
||
Carriage return resets the temporary typeout modes from the permanent
|
||
typeout modes (see section 1.2.2 on typeout modes).
|
||
|
||
Linefeed opens a new location by adding an appropriate increment to the
|
||
value of the symbol . and opening . again in the same mode as it was opened in
|
||
before. The appropriate value is determined
|
||
by what value is typed before the linefeed and what mode the location was open
|
||
in. If the location was open in byte mode, then the linefeed increment is
|
||
always one, that is, the next byte will be opened. If the location was open
|
||
in word mode, then the increment depends upon what value was typed preceding
|
||
the line-feed. If there is no value,then the increment is two. If there
|
||
is an instruction, then the increment is such that the location opened is
|
||
the one immediately following the stored instruction. If the value being
|
||
stored is a floating point number then the increment is four if double
|
||
precision mode is off and eight otherwise.
|
||
|
||
Tab opens the location whose address is the value stored in the previously
|
||
open location (i.e., the location open just before the tab was typed).
|
||
|
||
2 Program Execution and Control
|
||
|
||
2.1 Setting and Clearing Breakpoints
|
||
|
||
There are seven breakpoints which may be set in a program,
|
||
numbered from 1 to 7. A breakpoint may be set at a location by typing
|
||
an expression for the address followed by an altmode, an optional expression
|
||
in parentheses, an optional digit from 1 to 7 and the letter B. For
|
||
example,
|
||
addr+4B base+2*index3B loop+4(%4)5B
|
||
are all legal.
|
||
The address expression specifies where the breakpoint is to be placed. The
|
||
digit, if supplied, indicates which breakpoint number should be used.
|
||
The expression in parentheses should be an address whose
|
||
contents will be typed out in the current typeout mode when the breakpoint
|
||
is hit. If no digit is given, then DDT will assign a breakpoint number
|
||
starting from 1, using the first breakpoint number that is not in use.
|
||
A breakpoint is not in use if the address at which the breakpoint is set
|
||
is zero. Therefore, breakpoint n may be cleared by typing 0nB
|
||
which sets the address of breakpoint n to zero. A breakpoint may also be
|
||
cleared by specifiying the address where it resides, as in
|
||
<expr>B, which clears the breakpoint at <expr>, if there is one.
|
||
The command B will clear all the breakpoints.
|
||
If you try to set a breakpoint without specifying a number and all
|
||
seven are in use, then the message
|
||
?TMB? is typed and no action is taken.
|
||
|
||
2.2 Starting Programs
|
||
|
||
The command addrG starts the program at addr. addr
|
||
may be any expression whose value is a non-register integer. If the program
|
||
had a starting address (i.e., if there was a label after the end statement
|
||
in the source code) then the command G will start the program at its
|
||
starting address. Finally, the command addrG will start the program
|
||
at addr and will also set the starting address of the program to
|
||
addr so that future G commands will start the program at this
|
||
same address.
|
||
|
||
2.3 Proceeding Programs
|
||
|
||
Once a program has been started it may reenter DDT in three ways. First
|
||
it may hit a breakpoint. Second, it may execute a BPT instruction.
|
||
Third, it may transfer to DDT's starting
|
||
address, which at this time is 50000 (octal) although this may change
|
||
when the map "arrives". The second method is generally preferable to the
|
||
third, for the following reasons: you don't have to know the right starting
|
||
address, and the breakpoint trap procedure saves your program's status
|
||
so that you can tell where in your program the call to DDT was.
|
||
If DDT is entered via a breakpoint, it will type
|
||
the breakpoint number followed by the instruction at that address
|
||
followed by the contents of the location that was in parentheses in the
|
||
breakpoint command. Entering by a BPT causes a typeout similar
|
||
to that for a breakpoint, identified by the letters BE at the left
|
||
margin. You can proceed from a breakpoint by using the P command,
|
||
which will resume execution at the interrupted instruction. There are
|
||
two variations on this command. First, nP will proceed from this
|
||
breakpoint n times; however, it will break at any other breakpoint
|
||
it may hit before the n times are up. After breaking the nth time,
|
||
control will stay in DDT as if it had hit that breakpoint normally.
|
||
The second form is P which will proceed all breakpoints indefinitely.
|
||
However, the standard breakpoint information is typed out at each breakpoint
|
||
and the process may be stopped by typing any character at DDT (the character
|
||
itself is ignored).
|
||
There is a second proceed command
|
||
included for convenience. Typing ^P has the effect of planting
|
||
a breakpoint at . and then proceeding. The breakpoint will be automatically
|
||
removed when it is hit. Typing <expr>^P sets the temporary
|
||
breakpoint at the location addressed by <expr> (without changing
|
||
the value of .) and proceeding. Note: there is only one such temporary
|
||
breakpoint. When your program runs into it, DDT will identify it as
|
||
breakpoint 8. Also, if you already had a breakpoint set at the location
|
||
that ^P affects, the original breakpoint is lost, along with the specification
|
||
(if any) of a location to type out.
|
||
If you hit the ^P breakpoint while P is in effect, it will stop
|
||
as if you had typed something.
|
||
^Q does like P, continuing automatically from all breakpoints, but
|
||
it doesn't type out. Typing anything will cause it to break at the
|
||
next breakpoint.
|
||
|
||
2.4 Single Stepping
|
||
|
||
After a program hits a breakpoint, it is often desirable to
|
||
watch what the code does one instruction at a time.
|
||
It would be cumbersome to plant breakpoints at each succeeding instruction,
|
||
proceed and then remove the breakpoints. To ease this problem, there is
|
||
a single step feature. Typing ^X will execute the next sequential
|
||
instruction, then type out "SS;" followed by
|
||
the new value of the PC and the next
|
||
instruction to be executed. The value of . is not changed.
|
||
If there is a breakpoint at the next instruction,
|
||
DDT will type the breakpoint message instead of the one-step message.
|
||
The commands ^N and ^S are exactly
|
||
the same as ^X. Single stepping is legal after having
|
||
hit a breakpoint or can be begun by typing <expr>^S (or ^X or
|
||
^N), which sets PC_<expr>, then one-steps.
|
||
|
||
2.5 Debugging interrupt code
|
||
|
||
DDT attempts to be as flexible as possible in the way it handles
|
||
breakpoints and one-stepping, so things may get pretty confusing at times.
|
||
For example, suppose you just said ^S when your program's priority level
|
||
is low and an interrupt is pending. What happens is (1) DDT sets the
|
||
Trace Trap bit and does a RTT to get back to your program. (2)
|
||
The 11 is about to fetch your instruction, but it notices the interrupt
|
||
and answers it. (3) The interrupt procedure starts out by loading a
|
||
new PSW which doesn't have the Trace bit on, so the service routine
|
||
just runs away at full speed. (4) The interrupt routine ends by doing
|
||
a RTI. This loads up your PSW again, with the Trace bit on.
|
||
The 11 is again about to fetch your instruction, but it sees the
|
||
Trace bit so it takes the trace trap. (5) And now we're back in DDT,
|
||
and the PC is still pointing at the instruction you wanted to step,
|
||
which was never executed. You might think, all right, let the interrupt
|
||
routine return using RTT instead of RTI. That will have
|
||
the right effect if the interrupt was pending when you did the ^S, but
|
||
if it happens after your instruction was fetched the result will be
|
||
that the next one will be stepped, too! It's a design flaw in the
|
||
hardware... complain to DEC.
|
||
|
||
However, you can have a breakpoint in an interrupt routine while you're
|
||
one-stepping your main program. Then when you step and the interrupt
|
||
strikes and hits its breakpoint, DDT will astonish you by typing out
|
||
the breakpoint message instead of the single step you expected. You
|
||
can step the interrupt routine if you like, or proceed it, and the
|
||
trace trap will happen when it returns and DDT will finish up the
|
||
one-step you started way back there. One warning, though... if you
|
||
have a breakpoint at the RTI or RTT that ends the interrupt
|
||
routine, you should either remove it or STEP that instruction. If you
|
||
proceed it, DDT will forget about the original one-step and wind up
|
||
proceeding your main program.
|
||
|
||
If you set a breakpoint at a TRAP or EMT instruction, you
|
||
should clear it before you proceed or step. Otherwise, the trap service
|
||
routine may see a BPT opcode instead of the TRAP or EMT
|
||
that you specified.
|
||
|
||
By the way, the SPL instruction has the side effect of suppressing
|
||
all interrupts including the trace trap during the next instruction
|
||
fetch. Because of this effect, DDT checks to see whether the target
|
||
of a ^S is a SPL. If it is, DDT simulates the SPL by
|
||
changing your priority without returning to your program, and pending
|
||
interrupts can't strike during that process.
|
||
|
||
3 Special Locations in DDT
|
||
|
||
Several locations inside DDT are available by way of predefined
|
||
symbols, to give you some control over DDT's workings.
|
||
|
||
3.1 Program Status Word (%PS)
|
||
|
||
If you refer to %PS you get your program's status word.
|
||
You may modify
|
||
any part of this cell except bit 4 (the Trace Trap bit, octal 20).
|
||
DDT uses bits 14-15 to decide which of the three stack pointers to give
|
||
you when you ask for %6, and bit 11 to decide which of the two general
|
||
register sets you mean when you talk about %0 through %5. There is
|
||
no check for whether you set the processor state to a legal value -
|
||
that's up to you.
|
||
|
||
3.2 DDT's Status Word (%DDTS)
|
||
|
||
This word is the PSW that DDT uses. You may change bits 5-7 only,
|
||
determining the priority level that DDT runs at. This allows you to run
|
||
an interrupt-driven routine in the background while you're talking to DDT.
|
||
WARNING! The background code that is capable of interrupting DDT
|
||
had better not have any breakpoints or BPT instructions, or a
|
||
re-entrant call to DDT will happen and things will get very confused.
|
||
%DDTS is assigned the absolute location HCOR-12, where
|
||
HCOR is what DDT thinks is the first nonexistent memory location
|
||
(100000 on our 16K system).
|
||
|
||
3.3 Teletype switch (%TT10)
|
||
|
||
This word, located at HCOR-6, determines which way DDT's
|
||
input and output will go. If the contents of %TT10 are zero,
|
||
I/O goes to your console via the 11TTY program; if nonzero, I/O goes
|
||
to the PDP-11's console terminal. You may change this switch at any
|
||
time, either by command or by program, and DDT will immediately begin
|
||
using the device you specified. A great convenience if you left 11TTY's
|
||
"V" switch in the wrong state when you loaded your program.
|
||
|
||
3.4 Floating-point Registers (%AC0 through %AC5 and %FPS)
|
||
|
||
The symbols %AC0 through %AC5 refer to the locations
|
||
(four words each) where DDT stores the floating-point accumulators.
|
||
Note that these are memory locations and not the registers themselves.
|
||
If you refer to these locations it is up to you to make sure that the
|
||
typeout mode is appropriate to the data. %FPS gets you the
|
||
location where DDT stored your program's floating-point status register.
|
||
If you change the contents of these locations the right thing will
|
||
happen when you proceed or step your program.
|
||
|
||
3.5 Maximum symbolic offset (%MXOFF)
|
||
|
||
This location contains the upper limit on the numeric offset that
|
||
DDT will type out when printing an address. The default value is 100 -
|
||
that is, if FOO=1000 and there are no other symbols defined between 1000
|
||
and 1100, DDT will type the address 1077 as FOO+77 and 1100 as 1100.
|
||
You can change the limit on these offsets by changing the value in
|
||
%MXOFF.
|
||
|