Subject: How does a PDP8 boot?

From: [email-masked] (Bob Supnik)
Date: 11 FEB 94 18:46:19

I'm hunting up information on how the PDP8 boots.

1. Off RK8E.  The bootstrap reads cylinder 0, surface 0, sector 0 into
   locations 0-377(8).  The bootstrap is located so that it sits in
   a loop

	31/ DSKP
	32/ JMP .-1

   even as the boot block is read over it.  When the read completes,
   the code at location 33 is the start of the actual boot routine.
   (From Bill Haygood's simulator and OS/8 simulated disk.)

2. Off RX8.  The bootstrap reads track 1, sector 1 into the buffer,
   and then empties the buffer into memory starting at location 2
   (not 0).  The empty buffer loop is locationed at

	47/ JMS 53
	50/ DCA 2		/modified by next instruction
	51/ ISZ 50
	52/ JMP 47
	53/ 0
	54/ STR
	55/ JMP 33		/tests for done, if not, jmps to 54
	56/ XDR
	57/ JMP I 53

    Since the buffer is 64(10) words long, this loop will overwrite
    itself as it empties the buffer; I presume the boot block is set
    up to allow this.  (From the RX01/RX02 Pocket Service Guide; I
    don't have an RX01 disk image to look at.)

Can anyone confirm, deny, or add detail to the above?

Bob Supnik	>[email-masked]
		>All opinions expressed are those of a hardline microcoder
		>and do not reflect those of Digital Equipment Corporation

---

From: [email-masked] (Charles Lasner)
Date: 12 Feb 1994 19:31:32 GMT

>   (From Bill Haygood's simulator and OS/8 simulated disk.)

Since you want *accurate* info, I will take you task on the description above.

There are basically three ways a prevailing PDP-8 operating system
boots:

1)  DMA-style

2)  Program-transfer style

3)  Exceptions to 1) and 2)

The only standard exception to 1) and 2) is the RX which will be
handled below.

DMA style is the simplest to explain.  Basically, an operation is
initiated by the code placed in memory by the primary boot process.
This initial code may come from a ROM or manual toggle-in, but the
point is that this code does not come from the disk device itself.

Generally, the primary boot code has some form of wait loop.  In some
cases, that looks sort of like:

        DSKP
        JMP     .-1

In this form, the done flag is being waited for, and eventually it
skips.  Assuming this code *doesn't change* then eventually the flag
skips causing the next instruction after the JMP .-1 to come into
play, etc.

However, there are two variants to what happens here depending on the
type of boot.

The first type of boot is the one usually documented for TC01/08
DECtape (and notably it's far longer than necessary!).  The boot code
that checks for the done flag skip is *not* overlayed.  Thus, the
code that follows the JMP .-1 is provided as part of the primary
bootstrap code itself.  In general, it's likely little more than a
JMP to the code just read in, etc.  This implies that the code read
in is ready to go, and just merely needs to be started at the correct
location.  In this instance, the primary boot is a simple image
loader for the secondary boot code brought in from the disk device.

In the case of the TC01/08 boot, this is *not* the only way to
achieve a correct boot!  The alternative is that the waiting loop is
itself placed in the midst of the DMA buffer!  In this case, the
device-read code overlays the waiting loop as the DMA occurs.  The
device-read code may even modify the wait loop as it waits!

Generally the second method achieves the shortest primary code for
the benefit of manual toggle-in.  In the case of the RK8E, it's the
standard method:

        *30                     /THE STANDARD SHORT BOOT STARTS HERE

        6743                    /DLAG, WHICH READS IN SECTOR 0
        JMP     .               /WAIT FOR OVERLAY       

The program is waiting at 0031 for something to happen.  As the DMA
starts, it first loads 00000, then 00001, etc.  Eventually, it loads
00031 with a JMP to a lesser location such as 00004.  (This is the
secondary code in the O/S on the disk.  Each system can do it a
little differently.  Constrained by this boot method, the RK8E
requires each O/S to make the data overlaying 0031 to be a JMP to a
lesser location between 00000 and 00030.)  Thus, the just-read code
is now waiting for a done flag, but this execution between DMA cycles
is occurring at 00004-00005 or somesuch.  Eventually the rest of the
record is read into all locations through 00377, the done flag
raises, and the waiting code skips to now execute additional
secondary code to do whatever is required, generally to cause
additional records to be brought into memory, and likely to move the
code in 00000-00377 elsewhere, such as into 07600-07777 and/or
17600-17777 as required by the system.  Often advantage is taken by
the fact that some of the locations are the auto-index registers, now
preloaded to useful values towards this endeavor of moving blocks of
data, etc.

Note that the TC01/08 DECtape can use either method.  When the
overlaying method is chosen, there is a standard among DECtape
systems that a wait loop generally exists at 07616-07617.  Each
DECtape O/S places DTSF;JMP .-1 over these locations as the DMA
occurs to ensure the overlay boot can succeed, etc.

Note that in the non-overlaying case, the DECtape routine just read
in is completely ready to continue the secondary boot process if you
start it at 07600.  Thus, most non-overlaying (and longer) boot
routines wait for the done flag and JMP (indirectly) to 07600.

The RK8E *only* supports the overlay form of boot!  Not only is it
shorter, but due to limitations of the RK hardware, it's the only
way to accomplish it due to space limitations.  The RK boot
convention is to include in the AC the unit number, because the
hardware cannot self-interrogate to find this info out at the point
of booting.  The longer form of the primary boot code does a few
extra instructions to load an additional register for the unit
number, and it also places that info in the AC.  As the DMA occurs
and overlays the JMP ., the first thing that must be done is to save
the AC passed in from the primary boot, as it contains the unit
number needed later.  Were a non-overlaying boot allowed, there would
have to be an alternate convention of where to JMP to for the purpose
of saving the passed unit number, etc.

While I haven't investigated what was implied above, it appears that
the boot procedure in the emulator may be defective, and may only
coincidentally work for OS/8 packs!  In order to qualify correctly,
the boot has to work as I have described it.  The more general form
of the boot is as follows:

        *25                     /WHERE LONGER BOOT LOADS

        LAS                     /GET UNIT NUMBER INTO THE SWITCHS
        DLDC                    /LOAD UNIT NUMBER; AC GETS CLEARED!
        DLAG                    /START THE DISK UP (AC CLEAR)
        LAS                     /RE-ESTABLISH UNIT NUMBER IN AC
        JMP     .               /WAIT FOR OVERLAY

The first switch-register read sets up the unit number.  The DLAG is
issued with a clear AC to read in sector 0, etc.  The second
switch-register read will inform the secondary code that it's coming
in on the selected pack.  (The shorter boot can only boot unit 0.)

Note that devices such as the DF32, RF08, and TC01/08 also have to
setup the 3-cycle data break locations in 7750-51 or 7754-55.  As the
image of block 0000 is read in, each location overlays the word count
location or current address locations as required, to either
maintain, modify, or even extend the transfer as required.  In the
case of TC01/08 DECtape, the external boot allows these locations to
just count normally, then a JMP to 7600 starts up a secondary
operation in the just-read-in handler that sets up for further
O/S-specific transfers.  The overlay boot will place the same values
over these locations as they already are at the precise point of
progressive DMA operations, etc.  This is the method OS/8 uses in the
case of overlay boot.

In the P?S/8 case, the process is taken one step further: As the DMA
progresses, the word count and current address locations are modified
to continue the transfer, as the memory layout of P?S/8 is such that
if the next 17 octal blocks are read in order into 00000 onward, the
system is just about up.  Thus, when P?S/8 is booted, the tape does
*not* rock forward and back, but rather just comes up in one smooth
motion (and of course faster!).  (Of course if the external method is
used, P?S/8 has to search backwards, turn around, come forward and
accomplish that transfer, the same way OS/8 always does it, etc.)

Both OS/8 and P?S/8 can take advantage of the overlay form of boot on
DECtape, thus it is possible to create bootstraps that end with
waiting code of

        *7616

        DTSF
        JMP     .-1

or even

        *7617

        JMP     .

depending on the rest of the primary code.

An additional note about the data break type of boot:

Generally, because of where the data break locations are, the boot
process is constrained to operate within 07600-07777 so that an
on-page reference to the locations can be made, etc.  Thus, there is
an additional convention possible not shared by such as the RK8E
(which loads into 00000 because the simplest boot is defined to do
that; it takes too much manual effort to do otherwise, etc.) in that
the overlaying code knows more intimately the environment it is
bringing in with correct absolute addresses.  Thus, one of the
conventions of the TC01/08 is that a waiting subroutine defined at
7616-7617 and also adjacent locations will be completely read in by
the boot process (should it be of the overlay type!).  Thus, a
typical boot practice is to preload the subroutine at about 7614 with
a return address into once-only code within the handler.  Thus, any
original "call" is obliterated in favor of a transfer that furthers
the boot process instead, etc.  In the case of P?S/8, this allows the
curious warm boot code located at 07600:  Jumping to 07600 in P?S/8
TC01/08 starts up a conventional subroutine call to the handler to
ask for block zero to be read into 07600-07777 directly!  This would
seem to ask the image of the handler to self-destruct!  However, as
the process starts, the waiting subroutine's return address is
changed to a just-read-in address of a new routine that causes the
additional transfers to occur precisely as if the overlay form of
boot had occurred (waiting at 07616-07617), thus the boot process not
only succeeds, but it's the single smooth motion kind as well!  Thus,
every time a program exits on this system, tape motion is minimized.

A similar effect occurs in the DF32 and RF08 boot for OS/8 and P?S/8
in that the word count location need not be precisely set, just to
avoid an amount that would transfer too few words to get the word
count location overlayed.  Most documented boot programs dictate that
it be set to the same value as the current address (which must be
set as stated!).  In actuality, that value is just one of thousands
of acceptable values, but it's also the one next required for the
next toggled-in location (for the current address setting) so it's
convenient to minimize switch register changes, etc.  As the O/S
secondary code is read in, the word count as overlayed with an
O/S-dependent value that causes the proper amount of data to be read.
The current address is always overlayed with itself, i.e., it points
to the word after it as the next word to be transferred.  Thus, the
location is unchanged from its immediate pre-DMA value.

Program Transfer Devices (other than the RX).

Program transfer devices such as the TD8E actually work similar to
DMA devices in terms of the overlay process.  Most program-transfer
devices require the overlay type of boot.  As the waiting and storing
loop gets device data, it blindly overlays the waiting loop itself.
Thus, the data that overlays the waiting loop must be identical to
the loop code itself.

Generally, program transfer devices have precisely defined boot
locations to ensure the ability of this one-at-a-time overlay to
succeed.  The trick of overlaying a return address can apply as well,
but this constrains the device of supporting a precise form of
waiting subroutine.  (This is one of the major limitations of the
RX!)

It is possible for a program transfer device to support an external
boot process as well, as long as the just-read-in code can have an
alternate starting address aware of that method.  The TD8E supports
this convention so that the MR8E-C field 7 ROM can also boot the
device.  (Note: the MR8E-C is not required to run the non-ROM systems
such as the 12K TD8E OS/8 system and 8K P?S/8 systems, but both of
these systems can be booted by the ROM!)  In that particular case,
the ROM is started at 77470.  (This value was chosen for minimal
switch manipulation.  You set the switches to 7470.  This allows an
extended address load to IF 70 and DF 00 and an address load to 7470
within the ROM.)  Of course if the ROM versions of these systems are
booted, their secondary code will presume the ROM is present and make
direct calls to ROM code as required, etc.

When a DMA overlay boot modifies a wait loop routine, it must overlay
it with either the same code, or a JMP back to an earlier location
already read in.  When a program-transfer overlay boot modifies a
wait loop routine, the same sort of thing applies.  In some cases,
the form of the wait loop is drastically changed at some point to
serve the rest of the boot process.  In any case, such an operation
requires an overlay type boot, thus limiting the device to that form
of boot operation unless there is also room in the disk data to
handle the external boot case.  (In the case of the RX, this isn't
the case; see below.)

>    don't have an RX01 disk image to look at.)

This doesn't show the entire operation!  Note that at 00055 there is
a JMP 33.  At 00033 there is a SDN followed by a JMP 54.  This is
known as a "figure-8" loop.  The idea is that eventually the transfer
flag will not come up anymore, and instead the done flag raises.  At
that point, the code *then* in memory decides what to do next in an
O/S-dependent manner.

What is typically done is that 00052 is eventually overlayed with
something else, perhaps a JMP to an earlier location where a
different transfer is initiated.  A likely choice is to continue the
transfer, but store into 00060 and following.

The reason for all of this is that there is a design weakness in the
RX preventing any future optimization not shared by any prior device!
Unlike other devices, the RX has the dubious distinction of being the
only device where some of the boot code cannot get overlayed.  Not
only must the boot code not overlay 00033 and 00034 with anything
different from what's already presumed there, but also the code at
00047-00051.  (00050 has to be overlayed with a DCA 50, which is what
it is at the point of overlay.)  The part *never* overlayed is the
code at 00054-00057, thus all RX boots must assume the permanent
presence of these locations.  (00053 is a subroutine header which
will also have to contain an appropriate value, but as 00052 is
overlayed with something (typically a JMP to a lesser just-read-in
location lower than 00033), the overlay code is aware of the
appropriate address which is likely 00050 caused by the JMS 53 at
00047, etc.)

Were 00054-00057 not "unreachable" by the secondary boot code,
perhaps a more efficient bootstrap could be constructed.  This will
never happen as the locations are totally fixed at 00054-00057.

Depending on which RX it is (RX01, 02, 50), transfers are made to
various locations within the rest of 00000-00377, or are redirected
into 17600-17777 or 27600-27777.  Generally, the code is loaded into
00002 and following through the overlay of 00052 which then JMP's to
a just-read-in routine to continue loading in 00060 and following
until the done flag raises.  At that point, the SDN in 00033 skips
thus the just-read-in code at 00035 is in control, generally
initiating another transfer, etc.

Note that by fixing this bizarre form of boot method where the data
neither loads into neat page boundary locations (perhaps on the
"wrong" page needing to be moved to the "right" page ala the RK8E)
nor does contiguous loading (the RK08 (NOT RK8E!) boot loads two
contiguous pages one-off of a page boundary requiring an
after-the-fact simple move of the pages-long data), forever makes the
notion of an external boot process impossible.  Each O/S has to "fend
for itself" in terms of having a boot process that is initiated in a
time-sequence-dependent way.  Merely doing a contiguous load of
record 0000 into an arbitrary location cannot get such a system up!

This forever means that the boot process is inherently unreliable.
You cannot write a general boot procedure for the device where a
"smarter" boot program reads the data in after checking for errors,
then transfers control to the just-read-in data.  To do so would
require a different program for each O/S's individual handlers,
literally dozens of cases considering how many O/S's for the various
RX systems there are (even though one master boot suffices for them
all!  That code is "cross-your-fingers-that-it-works only!)

Additionally, in the case of all RX02 and most RX01, it's not
possible to write-protect the device during the boot process, thus
the system is vulnerable to corruption at this critical juncture.
(RK8E can be write-protected; my 4-function 8/a boot code does a
software-initiated write protect and boot on the selected drive,
etc.)  (Also note that most boot code looks very much like write
code, since it's only a few bits different from read code!)

(Of course, an emulator generally won't have problems like this, but
there exists at least one emulator where the device is emulated on
real hardware, i.e., diskettes.  The possibility of an emulator
foolishly carrying out the dictates of mis-read code does apply!
Some pragmatic kludges can be applied as a partial safety net, such as
disallowing device writes until there have at least some requisite
number of reads, etc.  However, there are perfectly normal boot
circumstances in OS/8 where the boot process includes JMP'ing to
07600 which causes a write to occur!)

As a consequence of the feebleness of the RX design, extra pains had
to be taken to boot P?S/8 on it.  In fact, the overall design of the
system was changed primarily to accommodate the RX!  Before
considering the RX, P?S/8 had only seen devices that required one or
two page handlers.  The RK increased that requirement to 4-page
handlers (P?S/8 addresses the RK disk to the nearest one-half
physical sector, a technique used later in some CP/M and early MS-DOS
systems such as a logically subdivided diskette with 1K physical
sectors, etc.  In all of these systems, a buffer is required to hold
the image of the physical sector.  The code to manage this in P?S/8
fits in two pages; the buffer is an additional two pages within the
handler space, etc.).  The RX has caused the latest P?S/8 definition
to be a total of 9 pages.  Thus, a P?S/8 system handler either
totally resides in 07600-07777 and the system can be configured to
run in 4K minimum, or it is presumed to also need x6000-x7777 where x
is field 1-7 as available.  Thus, the minimum configuration is 8K in
these cases.  (Note: most of these cases cause OS/8 to require 12K!)
However, by allowing that much space for the handler, excellent error
recovery and performance are possible.  *EVERY* OS/8 RX handler is
compromised!

>		>and do not reflect those of Digital Equipment Corporation

cjl