Contents

What is the Launch Vehicle Digital Computer (LVDC)?



Factoid

People generally think that the guidance computer (AGC) of the command module controlled the Saturn rocket, but it isn't true. During burns of the S-II and S-IVB rocket stages, it was possible for the CSM's AGC to control the steering, as a backup to the LVDC. That backup capability was never used in a mission. This was not possible during burns of the first stage (S-IB or S-IC). However, the AGC's ability to directly control the Saturn IVB was used for other purposes during the mission. Also, see below.























Peripheral Devices

The Launch Vehicle Data Adapter (LVDA) interfaced the LVDC's digital signals to the analog world of the Instrument Unit's sensors. Actually, the LVDA is so closely coupled to the LVDC that it may make more sense to consider them as forming a single unit, though packaged separately.



The ST-124-M Inertial Platform Assembly—catchy name!—was an inertial measuring unit that supplied the LVDC with information about the rocket's orientation and acceleration. It had 3 integrating accelerometers that measured acceleration with respect to the stable (space-fixed as opposed to rocket-fixed) platform, as well as angular sensors to measure the orientation of the stable platform with respect to the rocket. Like the AGC IMU, it was a 3-gimbal system and therefore theoretically subject to "gimbal lock", but because the range of motion of the rocket during the burn phase, I suppose that avoidance of gimbal lock must have been somewhat easier than in the CM or LM.



The "Control Computer" or "Flight Control Computer" was an analog computer that translated attitude-correction commands, angular change, and vehicle lateral acceleration information into propulsion-system thruster nozzle and/or engine actuator positioning commands. As such, it is of little interest in simulation of the LVDC (which is our primary concern at Virtual AGC). If the naming of this device seems odd, note that it follows the general convention of the word "control" being defined to mean the execution of an action that has been decided upon elsewhere, and not the act of decision-making.



The Control-EDS Rate Gyros.

The Control Accelerometers (Saturn IB only).

The propulsion engine actuators.

The auxiliary propulsion system. This was a set of 6 nozzles mounted on the aft end of the S-IVB stage which were used to provide attitude control in coasting (non-burn) periods. I believe that it may also have provided roll control during the S-IVB turn during boost. (The engines of the S-IC and S-II stages could provide complete pitch/yaw/roll control, but the engine of the S-IVB state could only control pitch and yaw, and therefore needed to be supplemented to provide control of roll.) The auxiliary propulsion system was directly controlled by the Flight Control Computer, but the Flight Control Computer was commanded by the LVDC.

Telemetry downlink.

Command uplink.









Saturn Interaction with the AGC The LVDC and the AGC did not actually have any direct interaction, so we may as well talk about how the AGC interacted with the Saturn before immersing ourselves in too much detail about the LVDC.

If you look at either of the graphics at the end of the preceding section, you'll see the four ways that the Instrumentation Unit (IU) in the Saturn IVB and the Spacecraft (i.e, the Command Module) — which are separated by a horizontal dotted line near the tops of the two graphics — interacted:

The Abort Decision signal. The Status signal. The Mode Command signal. The Alternate Steering Commands signals. The Saturn was always steered by the so-called Flight Control Computer (depicted in the picture at the right), an analog computer whose salient characteristic for our purposes is that it was not the LVDC. However, the flight-control computer did not operate on its own, and thus itself needed to be supervised. Normally, that supervision was performed, by default, by the LVDC, indirectly through the LVDA, the Launch Vehicle Data Adapter.

The Saturn was always steered by the so-called Flight Control Computer (depicted in the picture at the right), an analog computer whose salient characteristic for our purposes is that it wasthe LVDC. However, the flight-control computer did not operate on its own, and thus itself needed to be supervised. Normally, that supervision was performed, by default, by the LVDC, indirectly through the LVDA, the Launch Vehicle Data Adapter. However, it was also possible for the spacecraft to send the flight control computer a signal, the Mode Command, which instructed it to accept Alternate Steering Commands from the AGC rather than the default steering commands from the LVDC/LVDA. Thus, the AGC could steer the Saturn IVB (but not some of the other Saturn stages) by this mechanism.

Of course, it was also desirable for the spacecraft to be able to monitor the activity of the Saturn, even under normal conditions when the LVDC was controlling the rocket. Since the spacecraft had its own Inertial Measurement Unit (IMU), it knew its own orientation and acceleration — and hence the Saturn's — at all times, and the AGC could integrate these quantities to know the velocity and position at all times. Thus it was not necessary for the IU to communicate that information to the spacecraft in order for the AGC to monitor the physical motion of the rocket and to display it for the astronauts on the DSKY.

I actually have an interesting graphic of the monitoring process to show you. This graphic is not from physical system. Rather, Riley Rainey has used the "equation defining document" which specified how the Instrumentation Unit (IU) was supposed to behave, to model the physical behavior of the rocket and the spacecraft's IMU, allowing Virtual AGC to monitor the launch behavior on a simulated DSKY. Here's a short movie he has created of that simulation. It's admittedly a little fuzzy, since I blew it up by about 2×, but perhaps we'll be able to get a better one sometime in the future:

Of course, at the left in the video, you can see the simulated FDAI and DSKY. At the right, you can see telemetry from the AGC. You'll notice that at the beginning of the movie, the DSKY's UPLINK indicator is on. That's apparently because Riley's simulated DSKY (which is his own, and not the simulated DSKY we provide) isn't fully functional in the sense of accepting keypad input, so Riley is instead feeding the AGC commands via the digital uplink.

Of course, at the left in the video, you can see the simulated FDAI and DSKY. At the right, you can see telemetry from the AGC. You'll notice that at the beginning of the movie, the DSKY's UPLINK indicator is on. That's apparently because Riley's simulated DSKY (which is his own, and not the simulated DSKY we provide) isn't fully functional in the sense of accepting keypad input, so Riley is instead feeding the AGC commands via the digital uplink. and for the Saturn V:

LVDC Documentation

LVDC Software

Overall Structure

Describing the overall structure of the software loaded into the LVDC is a bit tricky at the present time. That's because documentation is scarce, our cache of original LVDC software is sparse, and the original development process seemed quite compartmentalized. By the latter, I mean that programmers concentrated on the specific areas to which they were assigned, and often seem to have had little cognizance of even the most basic features of the software when those features happened to be outside their narrow specialization. Plus the set of LVDC programmers available to me is limited, so I don't have representatives of all of those specializations to consult with. Of course, it's also possible that the many decades between the time they spent working on the project and the time I was able to quiz them about it may also have acted to erase some of the information.



In short, important aspects of my descriptions in these sections concerning the gross structure of the software are based on my own inferences and on the recollections of developers not entirely familiar with the details. So my comments about the program structure with a large grain of salt.



With that said, let's contrast the overall structure of the LVDC code vs the software source code for the Apollo Guidance Computer (the programs COLOSSUS, LUMINARY, and so on) and for the Abort Guidance System. All of these non-LVDC programs were monolithic in nature. What I mean by that is that although the AGC and AGS software was structured into various semi-independent sections, for which the development of each was presided over by specialists in those specific areas, the source code for them was nevertheless presented to the programmers in a single large chunk — i.e., a single, unified program listing. Every AGC or AGS developer saw the entire source code, regardless of whether it pertained to them or not. The natural result was that it was possible (and even likely) for an AGC or AGS developer to have some grasp of the large-scale structure of the software, beyond his or her own narrow area of specialization. Similarly, every word stored in the AGC or AGS core memory came from that source code. In that sense, each AGC or AGS program listing was entirely self-contained. If you were able to assemble those program listings, then you obtained a rope image that could be loaded into the computer and run. Conversely, every word in core-memory either came directly from the associate program listing or from some action taken by the code in that program listing. When you look at a program listing for (say) LUMINARY, you see the entire contents of the Lunar Module's AGC's core memory.



The overall structure of the LVDC software, however, is fundamentally different. Simultaneously loaded into the LVDC core memory were several different logically-distinct "programs", each with different sets of source code, assembled separately from each other, and having different areas of specialization. Thus assembly of any given one of these programs did not produce a full core-rope image: merely a partial rope image. A full rope image could be obtained only by merging all of the partial core-rope images from the different assemblies of the several sets of source code. The separate programs I'm aware of are discussed individually in the sections that follow, but in brief, they were:



The Preflight Program

The Executive Control Program

The Flight Program



A similar situation arises in modern computer systems, where you typically have an "operating system" program and "application programs" running in the computer at the same time. The application programs rely on the operating system for certain functionality, but have no understanding of how the operating system provides that functionality. All the application program needs to know is the exact method for requesting the desired function from the operating system. Similarly, the operation system stands ready to provide the desired functionality, but has no knowledge of the internal workings of the application program requesting service.



In the LVDC, the method by which interaction between independent but simultaneously-loaded programs worked was for there to be an agreed-upon set of specific memory addresses hard coded into the programs. For example, one program would know that to obtain a certain type of service, it had to call a routine at a certain fixed address in memory. Another program would know that it had to put code providing certain types of services at certain fixed addresses, but have no other knowledge of the program(s) utilizing that functionality.



Because of this much higher degree of compartmentalization, programmers working on (say) the Flight Program might have no cognizance at all of the Preflight Program, the developers of which might have no cognizance of the Executive Control Program, and so on. And unfortunately, that means that we don't, either.



Preflight Program

I don't know anything at all about the Preflight Program at present. I.e., there is no surviving documentation or source code for it as far as I know. I will provide information about it if/when it becomes available.



As it relates to the AS-206RAM Flight Program, however, I do have a couple of reasons to believe that the AS-206RAM Flight Program would have been used in conjunction with a Preflight Program:



In the AS-206RAM Flight Program (1967), there are jumps to various memory locations in regions of core memory at which AS-206RAM itself does not define any code or variables. It stands to reason that something is stored there. This is discussed in more detail below.

One of the original LVDC software developers (thanks, Pat Woods!) tells me that he believes that the Flight Program shared memory with a Preflight Program that ran before liftoff.

Executive Control Program

Original LVDC software developer Pat Woods tells me that there was no Executive Control Program (ECP) in use until the Apollo 12 mission. This anecdotal information is backed up by the fact that the Saturn Launch Vehicle Astrionics Systems Handbook has 14 pages of descriptive material about the ECP in its November 15 1969 release (see section 11.2.1 in particular), but does not even mention the ECP at all in its November 1 1968 release.



I won't describe the ECP further here, since we have no source code for it, but if you are interested you should consult the later release of the Astrionics Systems Handbook mentioned above.



It is unfortunately not clear from the description whether the ECP constituted a program separate from the Flight Program with which it was used — i.e., whether it had a separate set of source code that was assembled separately from the Flight Program — or whether the two had an integrated code base that was assembled as a single operation.



Flight Program in General

The software was apparently known simply as the Flight Program, and didn't have a catchy name such as "Luminary".



You may also see references to the Generalized Flight Program (GFP) or generalized Flight Program System, in use from Apollo 12 onward. You may recall from the preceding section that the Executive Control Program also came into use from Apollo 12 onward. My supposition would be that this simply means that



GFP = ECP + FP



CONFIDENTIAL

SECRET

TOP SECRET

AS-206RAM Flight Program



The basic purpose of the Apollo Saturn 206 S-IVB Restart Alternate Mission is to place the S-IVB stage into orbit and test its restart capability, simulating the AS-501 mission profile. In the event S-IVB restart problems occur in the early Saturn V flights, this mission will be flown to help correct or solve the problems. The primary objective of the SA-206 Launch Vehicle is to insert the S-IVB/IU/Payload configuration into a near earth 100 nautical mile circular orbit. The payload consists of a Spacecraft LM Adapter (SLA) and a 25° Nose Cone (NC #2).



As it happens, the source code from the assembly-listing printout has been entirely transcribed into machine readable form. That's a lot more convenient to deal with that scanned page images, since you can do things like text searches on it, or even assemble it using the nifty new LVDC assembler I've written (see below). The problem, of course, is that the transcribed source code is just as much subject (or hopefully, it will eventually turn out, not subject) to ITAR export restrictions as the scanned images are, so this LVDC source code is not presently available in our software repository.







The middle group of pages above shows a few auxiliary subroutines for computing the sine, cosine, arctangent, and spare root functions, plus a 3×3 matrix-multiply routine. Note that these are some of the very algorithms described in section 13 of the EDD (LVDC Equation Defining Document), so the source code can actually be compared to the defining documentation if one so desired. The two images at the top show an area of the program where some constants are defined, while the two at the bottom show a portion of the assembly listing's cross-reference table.



0

1

5

5A

6

9

0







... prior? ...



AS-501 (Apollo 4)



AS-502 (Apollo 6)



AS-503 (Apollo 8)



AS-504 (Apollo 9)



AS-505 and 506 (Apollo 10-11)



Regarding preloaded constants for LVDC memory, all missions (I think!) were associated with a report called the "launch vehicle operational flight trajectory", and these documents (among other things) listed the LVDC preload settings. Unfortunately, most of these reports are presently unavailable, though we do have a few of them. For example, the AS-202 report says that "LVDC symbol" T 1i , the time-to-go for first IGM stage, is preloaded with 299.25 sec, while Vex 1 , the J2 exhaust velocity for first IGM stage, is loaded with 4165.45 m/sec, and so on.



Finally, I claimed earlier that the AS-206RAM Flight Program is not, of itself, a complete program. In that assessment, I'm not referring to the fact that when you try to assemble it you find that there are a few missing symbols, associated with variables that haven't been allocated. That problem is simply due to the fact that the listing we have is an engineering version of the code that had never been debugged to the point of being released. It's quite easy, I think, to fix up the assembly-time errors and warnings in the AS-206RAM so that it assembles error-free, and is entirely self-contained in that sense. But it is still not complete in the larger sense I mean.



Rather, when I say that AS-206RAM is incomplete, I mean that it references code at specific hard-coded addresses which are not defined by the AS-206RAM program. Indeed, there are large areas of core memory left undefined by the program. Even the location in memory at which the power-up entry point should be stored is left undefined. But for example, consider the concrete example of the code necessary for processing commands uploaded to the LVDC from mission control, as described in the Up-data section of this web-page. When such a command is uploaded to the LVDC, an interrupt occurs. The software then looks in an interrupt-vector table, which appears on p. 207 of the program listing, and looks like the following:







HOP

HOP HCCMDC

HCCMDC





In other words, the interrupt-service routine for a command-upload is in memory module 4, sector 17, and its entry point is syllable 1 of location 267. Similarly, the data-memory environment associated with that interrupt-service routine is module 4, sector 17.



And yet ... the source code contains no code in module 4, sector 17. Indeed, module 4 sector 17 does not even appear at all in the octal listing of the assembled AS-206RAM code. Some initialization routines do actually dynamically initialize a handful of constants in that sector, but they certainly do not seem to put any code at those locations.



Thus if a command-upload interrupt were to occur, the result would be that the software jumped into the middle of a no-man's land of uninitialized memory. And it's not just the command-upload interrupt, you can see from the image above that other no-man's-land jumps could occur as well: to the self-test program, to the hardware evaluation program, or upon telemetry-station acquisition.



My inference from all that is that there is a separately assembled program which provides the code in those locations, and



That's not to say that AS-206RAM cannot be run, if LVDC emulator software were to become available. One workaround for this specific problem is to simply modify the interrupt-vector table to contain a HOP HCIRTN instruction in place of the HOP HCCMDC instruction it contains now. Another workaround would be to simply disable the command-upload interrupt. But alas, that's just one example of the potential range of problems the missing Preflight Program might cause. Until a complete survey of all jumps into no-man's land is made, it's impossible to know yet whether all of them can be worked around so easily.

PTC ADAPT Self-Test (PAST) Program In other words, the interrupt-service routine for a command-upload is in memory module 4, sector 17, and its entry point is syllable 1 of location 267. Similarly, the data-memory environment associated with that interrupt-service routine is module 4, sector 17.And yet ... the source code contains no code in module 4, sector 17. Indeed, module 4 sector 17 does not even appear at all in the octal listing of the assembled AS-206RAM code. Some initialization routines do actuallyinitialize a handful of constants in that sector, but they certainly do not seem to put any code at those locations.Thus if a command-upload interrupt were to occur, the result would be that the software jumped into the middle of a no-man's land of uninitialized memory. And it's not just the command-upload interrupt, you can see from the image above that other no-man's-land jumps could occur as well: to the self-test program, to the hardware evaluation program, or upon telemetry-station acquisition.My inference from all that is that there is a separately assembled program which provides the code in those locations, and as discussed earlier , the best candidate for that at the moment is the Preflight Program ... for which we have no source code and no description whatsoever.That's not to say that AS-206RAM cannot be run, if LVDC emulator software were to become available. One workaround for this specific problem is to simply modify the interrupt-vector table to contain ainstruction in place of theinstruction it contains now. Another workaround would be to simply disable the command-upload interrupt. But alas, that's just one example of the potential range of problems the missing Preflight Program might cause. Until a complete survey of all jumps into no-man's land is made, it's impossible to know yet whether all of them can be worked around so easily. This section concerns the "PTC ADAPT Self-Test Program", the only LVDC program other than the AS206-RAM Flight Program of which we have a copy. Since "PTC ADAPT Self-Test Program" is quite a mouthful, I'll just refer to it as the PAST program. Not only is that nice and short, it's also apt since the PAST program chronologically preceded the AS206-RAM Flight Program discussed in the preceding section. But beware: The acronym "PAST" is mine, and doesn't come from the contemporary Apollo documentation.

Strictly speaking, the PAST program is actually not "LVDC" software, and it is certainly not flight software. But it's really quite significant in spite of that, and shouldn't be ignored if you're interested technically in the LVDC itself, rather than merely how the LVDC fits into the context of the launch vehicle. The PAST program fills in an important gaps in our understanding of the LVDC and it is technically so close to being "LVDC software" that it's really a matter of opinion as to whether you want to label it as LVDC software or not. (Hint: I do want to call it that.) Let's begin the explanation with a little acronym-rich terminology:

The PTC ("Programmable Test Controller"), pictured to the right, was ground-based IBM Federal Systems Division equipment for evaluating the LVDC and/or LVDA, using either the ADAPT or the ASTEC laboratory test equipment.



The ADAPT ("Aerospace Data Adapter/Processor Tester"), in turn, was equipment to evaluate the LVDA.

The ASTEC ("Aerospace System Test And Evaluation Console") was equipment to evaluate the LVDC and LVDA separately or to evaluate the LVDC/LVDA integration. The PTC is documented here. (A tiny bit of ADAPT and ASTEC documentation is here.) This PTC documentation includes (in Chapter 7) a printout of the assembly listing of the PAST program and is our only-known source for it.

But it's not necessary to go into great detail about the PTC, ADAPT, and ASTEC at the moment. Indeed, for our immediate purposes, we can ignore the ADAPT and ASTEC entirely and the only important things to know about the PTC are:

The PTC contains a CPU ... which is a modified LVDC. In saying this, I don't mean that the PTC has a modified LVDC mounted in it, but rather that the PTC's CPU is a reimplementation (albeit modified) of an LVDC CPU.

The PTC's CPU runs software ... in this case, the PAST program. In some sense, you can think of the PTC as a large LVDC that has been fixed up to allow various kinds of debugging activities. For example, the PTC provides support via circuitry enabling things like single-stepping through the software. (In the PTC documentation, see section 2-80, "External Control Element"; section 2-216, "External Control Logic Circuits".) It's the fact that the PTC's CPU is a "modified" LVDC which means the PAST program is not strictly LVDC software. Rather, it's modified-LVDC software. Still, except for small list of differences I'll list in a minute, the PAST program matches LVDC Flight Program syntax. Indeed, its assembly listing has clearly been produced by the LVDC assembler program, although there are a few differences in the way some of the output is formatted. In terms of how the PTC's CPU has been "modified" relative to the LVDC, those changes are described in detail later but here's a list of some of the differences visible at the software level, though admittedly it may not be too meaningful to you until you study more about how the LVDC works (and particularly its instruction set) later on:

The HOP register is parsed into fields slightly differently.



LVDC CPU instructions eliminated in the PTC CPU: MPY and MPH (both of which are multiplication instructions), DIV (divide), and EXM ("execute modified").

and (both of which are multiplication instructions), (divide), and ("execute modified"). Instructions added to the PTC but not present in LVDC: PRS (printer operation) and CIO (CPU i/o control).

(printer operation) and (CPU i/o control). Instructions that are a little different:

CDS (set data sector) and RSU (reverse subtract) have the same functionality as for LVDC, but their instruction words coded slightly differently.

(set data sector) and (reverse subtract) have the same functionality as for LVDC, but their instruction words coded slightly differently.

SHF (logical shift) remains similar, but no longer has a "clear accumulator" function and can shift by up to 6 positions (rather than just by 1 or 2).

(logical shift) remains similar, but no longer has a "clear accumulator" function and can shift by up to 6 positions (rather than just by 1 or 2).

XOR and RSU (reverse subract) use different opcodes than the LVDC does, but are otherwise identical.



and (reverse subract) use different opcodes than the LVDC does, but are otherwise identical. Other:

There is a single "residual" memory sector, in memory module 0, serving all memory modules. (Whereas the LVDC has a separate residual sector for each memory module.)





Boot: Execution begins at memory module 0, sector 0, syllable 0, location 0. (Whereas for the LVDC, module 0, sector 0, location 0 contains an address at which execution should begin.)



The assembler has a few non-LVDC pseudo-ops it recognizes, and few LVDC pseudo-ops which it does not. For example, the PTC has an ORG (origin) pseudo-op where the LVDC has the functionally-equivalent ORGDD pseudo-op.

How can I justify my claim that the PAST program is "significant" and thus deserves your attention? There are actually quite a few reasons to think so:

As self-test software, significant chunks of the program are devoted to testing the CPU instructions themselves; i.e., deep, system-level self-test code which is not present in the AS206-RAM Flight Program. In AGC terms, the PAST program most resembles our "Validation Test Suite" program ... except that being instead of being written by the Virtual AGC Project (as the Validation Test Suite was, because MIT/IL itself hadn't left us any AGC self-test software as far as we could determine at the time), the PAST program was actually supplied by the IBM Federal Systems Division itself. This will obviously be very helpful in validating any eventual LVDC CPU emulator we may be able to come up with, since developers of emulations are always faced with uncomfortable questions about the accuracy those emulations. Unfortunately, experience with the AGC suggests that the most -interesting CPU instructions to check would have been the very instructions which the PTC omits from its repertoire, and therefore the PAST software cannot test them. But that's a minor quibble.



-interesting CPU instructions to check would have been the very instructions which the PTC omits from its repertoire, and therefore the PAST software cannot test them. But that's a minor quibble. Indeed, speaking of LVDC-CPU emulation, running the PAST program in an LVDC emulation should in some ways be even more convenient than running an LVDC flight program, since (as a black box) the LVDC itself has no user interface as such, although you could consider its telemetered data streams as being a kind of "user interface". Whereas the PTC does have a user interface of sorts, including a plotter, printer, typewriter (keyboard), various electronic displays, and switches. Thus the learning curve for seeing an emulated LVDC actually do something is much gentler for the PAST program than it would be for an LVDC flight program, since the normal behavior of the PAST program is already to interact with the test technician.



have a user interface of sorts, including a plotter, printer, typewriter (keyboard), various electronic displays, and switches. Thus the learning curve for seeing an emulated LVDC actually is much gentler for the PAST program than it would be for an LVDC flight program, since the normal behavior of the PAST program is already to interact with the test technician. Nor is the PAST program a light-weight in terms of size, being nearly 60% the size of the AS206-RAM Flight Program, both in terms of page-count of source code and in terms of the size of the assembled executable. The structure of the PAST program is quite simple, which means that much of its bulk is related to repetition and variation of simple blocks of code rather than to complexity of software structure. Pedagogically, I suppose you could argue the latter point as being either an disadvantage or an advantage, depending on your point of view.



And there's no question of the PAST program's "export" being restricted by ITAR: It isn't, since it can't even be run within the launch vehicle's computer! So it can be freely provided to you, and you need not (please don't!) apply personally to me to get access to it (as you still have to do for the AS206-RAM Flight Program). Just follow the links given below.



An additional bonus is that while the AS206-RAM assembly listing we've obtained is simply a snapshot of work of ancient work in progress, which cannot even be assembled error-free without a bit of massaging, the PAST program is unambiguously a mature, debugged, working program.

As far as the versioning of the software, there is nothing embedded within the assembly listing itself which dates it. However, given that it is printed in the PTC document mentioned above, which is dated 5 MARCH 1965, I think we can tentatively suppose that the PAST program too is from early 1965. (Whereas the AS206-RAM program is from late 1967.)

Beyond that, there's also the academic question of the versioning of the LVDC assembler used. Both the feature set and the format of the output is more primitive in the PAST assembly than in the AS206-RAM assembly. For all these reasons, it's fair to infer that an earlier version of the assembler was used for the PTC assembly, in which various more-advanced convenience features did not yet exist.

The PAST program's source code has been transcribed into textual form, so that it can be assembled. You can get that source code from our software repository:

Folder in our GitHub repository for PAST program source-code files I should note that while this code assembles 100% correctly — i.e., without errors, and producing octal executables 100% identical to those of the original scanned assembly listing — there were nevertheless some behaviors (and perhaps bugs) of the original assembler that I've not yet been able to figure out how to mimic in the modern assembler. Thus to get an assembled output identical to the original, some workaround code consisting of a handful of ORG , DOG , and TRA pseudo-ops and instructions have been inserted into the source code. Hopefully it will be possible to update the modern assembler at some point in the future, and thus eliminate the workarounds.

You can also look at the scanned assembly listing created by the Apollo-era assembler. To make it a little more convenient to work with, I've extracted the listing from the original scanned PTC document linked earlier, so that it can be viewed as a set of image files, one per scanned page of the listing:

Zipfile of scanned page images for the PAST program Here's a quick index to the zipfile:

The source-code listing: pp. 1-171

The symbol table: pp. 172-220

The assembled octal listing: pp. 221-284 These images correspond to the original PTC document's pages 434-717. In general, the entire Chapter 7 ("Calibration") of that document is relevant, as it contains detailed flowcharts for the program, in addition to operating instructions. Chapter 2 ("Theory of Operation") contains detailed information about the PTC CPU and its peripheral devices.



Architecture of the LVDC

References



General Characteristics of the Computer











However, the LVDC and the Launch Vehicle Data Adapter (LVDA) really operated as a pair, and neither is of use without the other, so in considering the mechanical and electrical characteristics of the LVDC one really needs to include those of those of the LVDA into their thinking. The LVDA had dimensions of about TBD"×TBD"×TBD", and weighed about 214 pounds. Its electrical budget was about 320W and it accepted +28V power. The purpose of the LVDA was basically to intermediate between the LVDC and the remainder of the rocket.



In computer terms, LVDC had the following characteristics:

The computer was triply redundant, with 3 identical circuits conforming to the block diagram shown above. There was a "voting" circuit not shown, and any two of the 3 sub-systems could outvote the other on every output control signal.



Memory was ferrite core and was entirely RAM. In other words, there was no ROM memory as there was in the AGC. This meant that the flight program could theoretically be changed much closer to flight time than could the program of the AGC, but it also meant that the program contained within the computer could be destroyed much more easily than with the AGC. (But remember, the operating life of the LVDC was very short compared to that of the AGC.) Actually, reading RAM based on ferrite cores is inherently destructive, so every read must be accompanied by a write-back operation to restore the contents of memory.



Memory words were 28 bits, with 2 of those bits being for parity, and thus the data portion of memory words was only 26 bits. Memory was accessed serially, at a 512K bits/second rate, though this fact is not relevant as far as software coding is concerned.

Each memory word was logically subdivided into two 14-bit "syllables" (13 data bits + 1 parity bit), and computer instructions were encoded in 13 bits. Therefore, each memory word could hold two computer instructions, one in each syllable. Data, on the other hand, required a complete word.



The total amount of memory varied from mission to mission, I believe. The LVDC could be populated with up to 8 modules of memory, with each module comprising 16 "sectors" of 256 words each (4096 words), for a maximum of 32768 words. One word in each block wasn't memory as such but was a mirror of the CPU's Product-Quotient Register (see below), so the usable memory in each block was really only 4095 words.



Memory could be operated in two different modes, under program control, called "simplex" and "duplex". In "duplex" mode, the memory was divided into two banks, each of which was an identical mirror of the other in order to improve reliability, whereas in "simplex" mode the memory wasn't redundant in this way (though it was still triply redundant as mentioned above) but the number of memory words was double. In duplex mode, the odd-numbered modules mirrored the even-numbered modules, so that one would typically used only modules 0, 2, 4, and 6 in duplex mode. For the AS-206RAM LVDC Flight Program, a simplex model was required.



The basic CPU clock was 2048 KHz, but computer instructions were executed in a "computer cycle" time which was 82.03125μs. The latter may seem like an unusual number, but where it comes from is that each instruction required reading/writing 3 syllables (1 holding the instruction and 2 holding the data) of 14 bits each, with each bit requiring 4 clocks to process. 3×14×4=168, so the computer cycle was 168/(2.048MHz)=82.03125μs. Although most instructions took a single computer cycle, some instructions (particularly multiplication and division) took longer. The longest instruction, MPH , took 5 cycles. The MPY and DIV instructions (see below) theoretically took only a single cycle, but could only begin their operations in that amount of time, and the results weren't accessible until later (4 cycles total for MPY and 8 cycles total for DIV ).



, took 5 cycles. The and instructions (see below) theoretically took only a single cycle, but could only begin their operations in that amount of time, and the results weren't accessible until later (4 cycles total for and 8 cycles total for ). Arithmetic was 2's complement, integer only.

There were two arithmetic units, one of which could perform addition, subtractions, and logical operations, whilst the other could perform multiplication and division. The two units could be operated independently, which is significant because multiplications required 4 computer cycles and divisions required 8 computer cycles, and instruction execution could continue while the multiplication or division proceeded. In other words, one could begin a multiplication or division, proceed to execute some unrelated instructions, and then later fetch the results of completed multiplication or division.

The illustration above shows a simplified block diagram of the LVDC. The device itself was designed and manufactured by IBM Federal Systems Division. Mechanically, the LVDC had dimensions of about 29.5"×12.5"×10.5", and weighed about 72.5 pounds. A number of different power supplies were needed: +6V, -3V, +12V, and +20V, at roughly 150W.However, the LVDC and the Launch Vehicle Data Adapter (LVDA) really operated as a pair, and neither is of use without the other, so in considering the mechanical and electrical characteristics of the LVDC one really needs to include those of those of the LVDA into their thinking. The LVDA had dimensions of about TBD"×TBD"×TBD", and weighed about 214 pounds. Its electrical budget was about 320W and it accepted +28V power. The purpose of the LVDA was basically to intermediate between the LVDC and the remainder of the rocket.In computer terms, LVDC had the following characteristics:

The Accumulator Register.

The Product-Quotient Register (or just P-Q Register) can be accessed at address 0775 (octal) regardless of which memory modules and sectors were currently selected. (This happens to be an address in the "residual sector", as described below, so it represents a single address in each memory module rather than an address within each memory sector.) However, it is used by the MPY and DIV instructions (see below) and therefore cannot be treated as an ordinary memory location.

and instructions (see below) and therefore cannot be treated as an ordinary memory location. The HOP Register, discussed further below.

... and various hidden registers not directly relevant to software: the Transfer Register, the Address Register, the Data Module Register, the Data Sector Register, the Instruction Sector Register, the Operation Code Register, and the Memory Buffer Registers.

0400 stores a HOP Register code (see below) for vectoring to interrupts.



0600, 0640, 0700, 0740 are used for the EXM instruction (see below).

instruction (see below). 0776, 0777 are used for the "HOP save" feature (see below).

LVDC: Address 000—I believe, in module 0 sector 0 but am not sure—stores a HOP Register code loaded at reset.



PTC: Execution seems to simply begin at module 0, sector 0, syllable 0, location 0.



Layout of Memory Words









TRA

HOP

The "residual sector" is always sector 017 (octal)









Bits IM1-IM3 (not contiguous) select the memory module from which instructions are fetched. (Recall that there are up to 8 memory modules installed in the LVDC. The PTC has only 2.)

Bit DUPIN selects whether the portion of memory from which instructions are fetched is accessed in duplex mode or in simplex mode. (Recall that in duplex mode there is only half the addressable memory as in simplex mode, because the memory is dual-redundant and half of the memory mirrors the other half.)

Bits IS1-IS4 select the 256-word sector within the selected memory module from which instructions are fetched.

Bits A1-A8 (the Instruction Counter) point to the next instruction word to be fetched from the selected sector in the selected block.

Bit SYL indicates the next instruction syllable in the next instruction word.

And similarly, bits DM1-DM3, bit DUPDN, and bits DS1-DS4 serve analogous purposes except for data words rather than instruction words.

AA — a network which can provide several combinations of logic functions, depending on wiring: e.g., 4 2-input AND gates, 2 4-input AND gates, etc.



CDR — a pull-up/down resistor.



CLI — TBD



CLN — a resistor-divider network.

DD — logical disagreement detector. (Detects if any 1 of 3 inputs differs from the other 2 inputs.)

DDI — TBD

FP 2412 — a pair of PNP transistors. This is technically not a "ULD", but can be installed in a ULD location.



HCI — high-current inverter.

INV — an AND gate and a NAND gate.



TMV — a logical majority detector. (Output is the majority of the 3 inputs.)



VI — a logical inverter, capable of driving 10 AND-get inputs.

VIP — TBD

... and presumably a number others, although the documentation suggests that an effort was made to minimize the number of types.



CPU Instructions





Mnemonic



A

8



A

9

O

P

4

O

P

3

O

P

2

O

P

1

Timing

(computer

cycles)





Description of the instruction

HOP





0

0

0

0

1

This instruction combines an unconditional jump instruction with various other configuration options, such as memory-sector selection. The way it works is that the address A1-A9 points to a memory word that contains a "HOP constant", and the HOP instruction transfers that HOP constant into the HOP register. Recall that A1-A8 select the offset within a 256-word sector, and A9 is the "residual bit" that selects between the current sector and the "residual sector". There is no provision for a partial HOP constant, and the full HOP constant needs to be given every time a HOP instruction is used. See also CDS and TRA .



Although the machine instruction requires the address of the HOP constant to be provided as its operand, the assembler is flexible enough to allow the operand to instead be a left-hand symbol for the target location in the code. When it encounters this situation, the assembler transparently performs a workaround. For the sake of discussion, imagine assembly-language code something like the following:

HOP HIGTHR

.

.

.

HIGTHR ... more code ...

What the assembler does in a case like this is:

If the target address is in the current instruction-memory sector (either in the same or the opposite syllable), transparently replace the HOP instruction by a TRA instruction. Otherwise, proceed to step 2.

Allocate a data word in the current data sector. Do this by searching upward in the data sector, looking for the first unused location. The residual sector is searched if there's no room left in the current sector.

Create a HOP constant for the target location , and store it in the newly-allocated data word. Use the address of the newly-allocated data word as the operand for the HOP instruction. Whenever such a substitution was performed by the assembler, it noted it in the assembly listing by printing " HOP* " as the name of the instruction rather than " HOP " as what would have been used on the actual punch card. MPY





0

0

0

1

1

(results

available after 4)

LVDC only ... not PTC.



This is a multiplication instruction. It multiplies two 24-bit numbers to produce a 26-bit product. The accumulator provides the address of one operand, and the address embedded in the instruction points to the other operand. Recall that A1-A8 select the offset within a 256-word sector, and A9 is the "residual bit" that selects between the current sector and the "residual sector". In both cases, the most-significant 24-bits of the operands are used, and the least-significant 2 bits of the operand are ignored. A partial product (24 bits from the addressed memory times the 12 less-significant bits from the accumulator) can be fetched from the P-Q Register (0775 octal) on the 2nd instruction (or more accurately, two computer cycles) following MPY , though there is no need to do so if that value isn't desired by the program. The full product is available from the accumulator or from the P-Q Register on the 4th instruction (more accurately, 4 computer cycles) following MPY . However, the result will remain in the P-Q register until the next MPH , MPY , or DIV . PRS



0

0

0

0

1

TBD

PTC only ... not LVDC



This is a "print store" operation. Here's what the PTC documentation (see p. V-2-22) has to say about it: Initiates a printer operation. That rather laconic description is trying to tell you that the PRS instruction can send either 4 or 12 characters to the printer peripheral, for printing.



In assembly language, the operand of the instruction is always a literal 3-digit octal number or else a symbolic label representing a memory address in the range 000 8 to 773 8 . Recall that addresses in the range 400 8 to 777 8 refer to addresses 400 8 to 777 8 in the residual memory sector.

Address

Operation

000 8 to 773 8

Data word in the specified memory address specified is transferred to the printer and to the accumulator.

774 8

A group mark is sent to the printer.

775 8

Data word in the accumulator is transferred to the printer.

See also the discussion of the BCI pseudo-op, farther down on this page, which is a convenient way in assembly language to encode memory-operand data for PRS .



Each PRS instruction conveys 26 bits of data to the printer, and that 26-bit word is capable of encoding either 4 or 12 characters. The number of characters encoded depends on whether the printer is in "octal mode" (activated by the CIO 164 instruction) or "BCD mode" (activated by the CIO 170 instruction). The term "BCD mode" is a misnomer, in modern terms, since it would seem to imply that it covers only Binary Coded Decimals, whereas in fact it covers the complete repertoire of printable characters. Besides those, see also CIO 160 , which conveys certain control commands to the printer.



In octal mode, the 26 data bits comprise 8 octal character encoded as 3 bits each (000="0", 001="1", ..., 111="7"), plus a single "2-bit character", plus three blanks (which are always present, and thus require no bits to encode). So far, I've found no written explanation of what these "2-bit characters" are, but due to the way 26-bit data words are invariably represented in LVDC/PTC assembly listings — namely, as 9 octal digits with the final one being even — I feel confident that the 9th character is encoded as 00="0", 01="2", 10="4", 11="6".



In BCD mode, the 26 data bits comprise 4 6-bit character code, left-aligned in the data word. In other words, the first character's most-significant bit appears at the SIGN bit of the 26-bit word. The least-significant 2 bits of the data word are not used as far as I can tell. (That's a pity, because it seems to me that it would be reasonable to use them to indicate how many characters the word contained, rather than just always being 4. Alas, that doesn't seem to be the case.) The 6-bit encoding scheme, called "BA8421", is covered in the discussion of the BCI pseudo-op.



The PRS instruction has a side effect: It overwrites the interrupt latch. This potentially triggers interrupts if not inhibited; or, more usefully, the interrupt latch can be read back using the CIO 154 instruction for self-test purposes. Which particular bits are set depends on which characters are being printed. I can't give you too satisfactory a rationale as to the particular bit patterns used. Nor are they documented (unless they can be deduced from the 2nd-level schematics, which I've failed at so far). So all I can do is infer the bit patterns from how the PAST program source code uses them. But take what I say with a big grain of salt, because there's no unique way of making these inferences! With that said, here are the rules for deriving the interrupt-latch patterns that I've built into the PTC emulation software. The bit patterns are all 12-bit codes (stored in SIGN and bits 1-11 of the interrupt latch) as follows:

A group mark ( CIO 774 ): 0047 8

): 0047 Character data ( CIO 775 , or CIO 000 through CIO 773 ):

, or through ): Bits SIGN, 1-5: Logical OR, bitwise, of the 6-bit BA8421 codes for all characters encoded in the data. In octal mode, this is additionally OR'd with 12 8 .



.

Bit 6: Parity bit. Computation of this can't be easily described concisely, so there's an extended explanation below.





Bits 7-11: 03 8 .

.

Bits 12-25: 0. The parity bit for character data appears to be an odd parity bit for the most-recently processed character of the 4 (BCD mode) or 12 (octal mode) encoded in the 26-bit data word at the time CIO 154 is issued to read back the interrupt latch. The characters are processed sequentially after the PRS instruction is executed. The 4 characters in BCD mode can be processed within a single CPU instruction cycle, but the 12 characters in octal mode cannot be, and require two instruction cycles to fully process. I think that the timing for this processing is not synchronized with the CPU clock, and indeed has some tolerance in terms of frequency, so that it cannot be known deterministically how many characters have been processed until enough machine cycles have elapsed to guarantee that all characters have been processed. I suspect that's why all octal-mode PRS test cases in the PAST program consist of strings of characters having all the same parity; that way, it doesn't matter which specific character has just been processed, because the parity of each character is the same anyway.

This leaves many questions unanswered about the precise original behavior of the PTC panel. Therefore, ignoring the original behavior and thinking just in terms of how the PTC emulation implements the parity in the face of this indeterminacy, I recognize 3 distinct cases:

Immediate readback. In this case the emulation returns the parity for the 2nd character in the data word: PRS something

CIO 154

Readback after 1 machine cycle. In this case, the emulation returns the parity for the 7th character in the data word in octal mode, or simply the last of the 4 characters in BCD mode: PRS something

... a single instruction to expend 1 machine cycle ...

CIO 154

Readback after 2 or more machine cycles. In this case, the emulation returns the parity for the final character. In BCD mode that's pretty straightforward, but in octal mode the interpretation of "final" will depend on what has previously been done with the CIO 250 instruction. If CIO 250 has been used to inhibit the check bit for the 3 implicit blank spaces, then the "final" character will be the last character explicitly encoded in the data word, namely the octal digit encoded with just 2 bits. Conversely, if those check bits have not been inhibited, then the parity will be that of an implicit blank space, namely 1.

PRS something

... 2 or more instructions to expend 2 or more machine cycles ...

CIO 154

Any intervening CIO or PIO instructions that result in a modification of the interrupt latch will prevent the parity-check bit from appearing in CIO 154 .

SUB





0

0

1

0

1

Subtracts the contents of a word pointed to by the address embedded within the instruction from the accumulator, and puts the result back into the accumulator. Recall that A1-A8 select the offset within a 256-word sector, and A9 is the "residual bit" that selects between the current sector and the "residual sector". See also RSU .



Regarding borrow from the operation, the CPU provides no direct way of accessing it, and thus no easy way to perform multi-precision subtraction. Refer to the notes for the ADD instruction for more information.

DIV





0

0

1

1

1

(results

available

after 8) LVDC only ... not PTC.



This is the division instruction. The contents of the accumulator are divided by the operand pointed to by the address A1-A9 embedded within the instruction to produce a 24-bit quotient. Recall that A1-A8 select the offset within a 256-word sector, and A9 is the "residual bit" that selects between the current sector and the "residual sector". The quotient is available in the P-Q Register (0775 octal) on the 8th instruction (more accurately, 8 computer cycles) following the DIV . However, the result will remain in the P-Q register until the next MPH , MPY , or DIV . TNZ





0

1

0

0

1

This is a conditional jump instruction, which branches to the address embedded in the instruction if the accumulator is not zero, but simply continues to the next instruction in sequence if the accumulator is zero. Bits A1-A8 of the embedded address represent the new offset within the currently selected 256-word instruction sector, while bit A9 gives the syllable number within that word. The "residual sector" cannot be accessed. See also TMI .



As mentioned, the target address for the machine instruction itself had to be within the current sector, because its 8-bit address offset is embedded within the instruction. However, the assembler would transparently work around this problem, allowing essentially any target address to be used. For the sake of discussion, imagine an assembly language instruction,

TNZ OINIT

in which the target location OINIT is not in the current memory sector. The workaround procedure used by the assembler was this:

Working downward from the top of the current instruction-memory sector, find an unallocated memory location. In that newly-allocated memory location, put a " HOP OINIT " instruction. Use the newly-allocated memory location as the target of the TNZ instruction. In the assembly listing, display the operator as " TNZ* " rather than " TNZ ". (But " TNZ " is nevertheless what actually appeared on the punch cards.)

Of course, this workaround preserves the intended logic, at the cost of an extra instruction word and a couple of extra machine cycles.

MPH





0

1

0

1

5

LVDC only ... not PTC.



This is a multiplication instruction. It is exactly like MPY except that the program "holds" until the multiplication is complete, so that the product is available from the accumulator or from the P-Q Register at the next instruction following MPY . However, the result will remain in the P-Q register until the next MPH , MPY , or DIV .

CIO



0

0

1

0

1

TBD

PTC only ... not LVDC. There is no LVDC equivalent for this instruction, which can be viewed as a way of extending the LVDC/PTC PIO instruction (see below) to a wider range of uses.



Here's what the original PTC documentation has to say about CIO : "Controls the input, output operations of the CPU. The operand address bits specify the operation to be performed."



A list of the CIO i/o ports is given below. As far as I know, only ports 154, 214, and 220 are for input, and they load the accumulator when used. Other ports are for output only, and the accumulator should to be loaded, prior to the CIO itself, with any additional data the specific operation requires, but is not affected by the operation. Note that most output operations do not require any such supplemental data, and therefore ignore whatever value is stored in the accumulator. Many of the operations relate to inhibiting or enabling interrupts (as you can see from the table above!), sending commands to the PTC's printer or plotter, etc.



In assembly language, the operand of the instruction is always a literal 3-digit octal number.

AND





0

1

1

0

1

Logically ANDs the contents of the accumulator with the contents of the address embedded within the instruction and places the result in the accumulator. Recall that A1-A8 select the offset within a 256-word sector, and A9 is the "residual bit" that selects between the current sector and the "residual sector". ADD





0

1

1

1

1

Adds the contents of the accumulator with the contents of the address embedded within the instruction and places the result in the accumulator. Recall that A1-A8 select the offset within a 256-word sector, and A9 is the "residual bit" that selects between the current sector and the "residual sector".



What about the carry bit? As far as I can tell, the CPU has no provision for carry bit that's useful at the software level. If you want to do multi-word precision arithmetic (say, 52-bit addition instead of just 26-bit addition), then you have to find some indirect, software-only way of detecting carry rather than on relying on the CPU to provide you with some easy way of handling it. It's certainly mathematically possible to do so: When adding two addends of the same sign using 2's-complement arithmetic, you can detect carry because the sum has the opposite sign of the addends, whereas adding two addends of opposite signs cannot result in carry anyway. But the coding to exploit this mathematical possibility is obviously going to be cumbersome and inconvenient. (The low-level adder circuit itself can deal with a carry bit, of course. The adder performs additions serially, starting with the least-significant bit and moving upward to the most-significant, and at each bit-stage there's a carry bit from the previous stage to worry about. However, the final carry bit is not accessible to software, and the carry-bit latch is cleared by any CLA instruction, making it very tough to transfer the carry-bit latch's contents from one word-addition to the next. In theory, if you could figure out a way to do multi-precision arithmetic without using CLA , perhaps you could exploit that hidden carry bit. But I'm having trouble seeing any way you might do it. That could just be my failure of imagination, of course.)

TRA





1

0

0

0

1

TRA is an unconditional jump instruction, which branches to the address embedded in the instruction. Bits A1-A8 of the embedded address represent the new offset within the currently selected 256-word instruction sector, while bit A9 gives the syllable number within that word. The "residual sector" cannot be accessed.



Note, however, that the assembler transparently worked around the limitation that the target address had to be in the same sector. The assembler would automatically insert a HOP instruction instead of a TRA whenever it found that it was necessary to do so. For example, consider the instruction " TRA ETCBTC ". If the target location ETCBTC is within the current instruction sector, the assembler would indeed assemble this exactly as expected, using a TRA instruction with opcode 1000 . Actually, the assembler would refuse to directly do a TRA to a target in the same instruction sector under some circumstances, presumably to help guard the programmer from easy-to-make errors. The condition I've noticed in which this occurs is if the target address has been tagged by the assembler as being in a region with a different setting for the data module or sector, since unlike a HOP instruction, a TRA instruction doesn't alter the DM/DS settings. Whereas if a CDS instruction (which changes the DM/DS settings in the processor itself) happens to be at the target location, it doesn't trigger a replacement by HOP . Quite a complicated set of conditions! One wonders if the original programmers actually had much awareness at the time (or cared!) that these substitutions were being made for them.



But if the target location ( ETCBTC in this example) wasn't within the current instruction sector or failed the DM/DS conditions, then the assembler would instead perform the following complicated maneuver which preserves the expected program logic, at the cost of an extra machine cycle and an extra word of memory:

Allocate a data word in the current data sector. This is done by searching upward through the current data sector (or the residual sector, failing that) until an unallocated word is found.



Create a HOP constant for the target location ETCBTC , and store it in the newly-allocated data word.

, and store it in the newly-allocated data word. Assemble a HOP instruction with the newly-allocated data word as its operand.

instruction with the newly-allocated data word as its operand. Whenever such a substitution was performed by the assembler, it noted it in the assembly listing by replacing " TRA " with " TRA* ". However, I think that " TRA " is always what would have originally been used on the punch card.

" with " ". However, I think that " " is always what would have originally been used on the punch card. Workaround for PTC: For the PTC version of the original assembler, I've unfortunately been forced to provide hints to the modern assembler (yaASM.py) by explicitly using " TRA* " in the source code when necessary. With either of " TRA " or " TRA* ", the modern assembler provides a behaviorally-correct fixup, but when " TRA " is used rather than " TRA* ", the automatically-allocated memory words are at different addresses than originally, thus preventing validation of the assembler. Deducing the original PTC algorithm and thus allowing universal use of " TRA " in PTC source code is a reverse-engineering problem I have been unable to solve so far. (Although, for all I know, the PTC programmers may themselves have had to explicitly use " TRA* " as well. There's no available original documentation to answer that question one way or the other.) This in so far as the assembly-language source code is concerned, it seems that one may as well always use TRA rather than HOP , since TRA is more economical than HOP , and the assembler will always substitute HOP anyway whenever some limitation of TRA necessitates it.

XOR





1

1

0

1

0

0

1

1

1

Logically exclusive-ORs the contents of the accumulator with the contents of the address embedded within the instruction and places the result in the accumulator. Recall that A1-A8 select the offset within a 256-word sector, and A9 is the "residual bit" that selects between the current sector and the "residual sector".



Note: The opcode bits for XOR are 1001 (11 8 ) for LVDC, but 1101 (15 8 ) for PTC. However, the PTC documentation incorrectly indicates that the coding is 1001. (Either that, or the assembler assembled the instruction incorrectly; take your pick of explanations.)

PIO





1

0

1

0

1

Reads or writes an i/o port. Bits A1-A9 select the source and destination of the i/o. A table of the i/o ports vs. addresses is given in the following section.



In so far as assembly-language syntax is concerned, the operand of the instruction is always a literal octal numerical constant.

STO





1

0

1

1

1

Stores the contents of the accumulator in the word indicated by the address embedded within the instruction. Recall that A1-A8 select the offset within a 256-word sector, and A9 is the "residual bit" that selects between the current sector and the "residual sector". The following addresses are special, as described in the documentation of the STO instruction (see p. 2-17):

Residual sector, location 0375 8 (often referred to simply as 775):

(often referred to simply as 775): LVDC: Stores into the Product-Quotient register rather than to normal memory.



PTC: Just a normal memory store (into 0375 8 of the residual sector).



of the residual sector). Residual sector, locations 0376 8 and 0377 8 (often referred to simply as 776 and 777):

and 0377 (often referred to simply as 776 and 777): LVDC:



During a multiplication or division operation, stores the contents of the Multiplicand-Divisor register (rather than the accumulator) to the selected address.





Otherwise (i.e., normally), store the contents of the (otherwise inaccessible) HOP-saver register to the selected address.





PTC: Store the contents of the (otherwise inaccessible) HOP-saver register to the selected address.

The LVDC and PTC cases appear to be very different, but the difference is really just that the PTC has no multiplication and division instructions, and hence has no product-quotient or multiplicand-divisor register.

Nevertheless, the description of 776 and 777 above is admittedly a bit tricky to understand, so let's try to get at it another way. It's mainly about return addresses for subroutines and interrupt-service routines. Most modern CPU's have a "CALL" instruction for calling subroutines, and part of what CALL would do is to push the return address onto a dedicated "stack" in memory; a subsequent "RET" instruction would then pop the return address out of the stack and jump to that return address. But the LVDC/PTC CPU has no such features ... no CALL, no RET, no stack. What it does instead is this: During the process of executing any given LVDC/PTC instruction, a HOP constant for the LVDC instruction at the next successive memory address is formed. Keep in mind that the next instruction successively in memory is not necessarily the next instruction sequentially executed. Whatever the next instruction executed, the previously-generated HOP constant is temporarily shoved into a register called "HOP-saver". Thus if the very next instruction executed after a transfer instruction ( HOP , TRA , TMI , or TNZ ) is STO 776 or STO 777 , what ends up getting stored in location 776 or 777 is the HOP constant for the memory address that follows the previously executed transfer instruction instruction in memory. Or in brief, for a transfer instruction to a subroutine, what gets saved at 776 or 777 is the return address of the subroutine. In fact, this is the only easy method for accessing such return addresses, and the only way at all for accessing return addresses of interrupt-service routines.

As an example, here's a simple framework for calling an LVDC/PTC subroutine:

...

HOP SUB # Call a subroutine.

...



# The subroutine.

SUB STO 776 # Save the return address.

... # ... do stuff ...

HOP 776 # Return from SUB.

This becomes trickier if you have nested subroutine calls, because the nested routines can't each use the same storage buffers for their return addresses, and there's no way to temporarily replace the contents of 776/777 while still being able to restore the original contents afterward. (You can certainly read 776/777, for example with CLA 776 , but you can't save an arbitrary value into either 776 or 777 afterward.) In other words, if you have a nested subroutine, you have to manage the return address of the parent subroutine manually. Here's an example I've constructed to illustrate the method:

...

HOP SUB # Call a subroutine.

...

SUBRET BSS 1 # Variable for saving a return address.

# A subroutine.

SUB STO 776 # Save the return address.

CLA 776 # Move the return address to SUBRET,

STO SUBRET # thus freeing up 776.

...

HOP NESTED # Call a nested subroutine.

...

HOP SUBRET # Return from SUB. # Another subroutine, called by SUB.

NESTED STO 776

...

HOP 776 # Return from NESTED.

You can, of course, perform the same trick with multiple levels of nesting, at the cost of allocating more and more variables to store the manually-managed return addresses.



It is perhaps obvious as well that the same address (776 vs 777) should not be used for interrupt-service routines and and for regular subroutines, even for the few instruction cycles needed for manual management, or else tremendous care needs to be taken to insure that no interrupt can occur during a subroutine with conflicting storage requirements for the return addresses. The safest thing would be to use 776 for interrupt-service routines (and their subroutines) and 777 for non-interrupt subroutines, or vice-versa. In examining the PTC ADAPT Self-Test Program and the AS206-RAM Flight Program, the two seem to use the opposite choice, so there may not have been a customary standard for doing so from one program to the next.

TMI





1

1

0

0

1

This is a conditional jump instruction, which branches to the address embedded in the instruction if the accumulator is less than zero, but simply continues to the next instruction in sequence if the accumulator greater than or equal to zero. Bits A1-A8 of the embedded address represent the new offset within the currently selected 256-word instruction sector, while bit A9 gives the syllable number within that word. The "residual sector" cannot be accessed. See also TNZ .



As mentioned, the target address for the machine instruction itself had to be within the current sector, because its 8-bit address offset is embedded within the instruction. However, the assembler would transparently work around this problem, allowing essentially any target address to be used. The workaround used by the assembler is that same as that described for the TNZ instruction above. Instructions for which the workaround have been applied are shown on the assembly listing as " TMI* " rather than " TMI ".

RSU





1

0

1

0

0

1

1

1

1

Same as SUB, except that the order of the operands in the subtraction is reversed.



Note: The opcode bits for RSU are 1101 (15 8 ) for LVDC, but 0011 (03) for PTC. (0011 in LVDC is for the DIV instruction, which is missing from PTC.)

CDS

or

CDSD

or

CDSS



0

1

1

1

0

1

LVDC only ... not PTC.



Change the currently-selected 256-word data sector. For this instruction, A9 forms a part of the instruction itself, so only A1-A8 are significant. The partially overwrite the HOP Register as follows:







See also HOP .



In terms of assembly-language syntax, there are the following variations:

CDS SYMBOLNAME

CDSD DM,DS

CDSS DM,DS

Thus CDS uses the characteristics of a variable name or a name defined with the DEQD or DEQS pseudo-ops (see below), whereas the module number and sector number are simply supplied with octal numeric literals in CDSD or CDSS . The difference between CDSD and CDSS is that the former selects duplex memory while the later selects simplex memory.



In the usage I've seen, usage of CDSS is confined almost entirely to the context of USE DAT (see below).

See alsoIn terms of assembly-language syntax, there are the following variations:Thususes the characteristics of a variable name or a name defined with theorpseudo-ops (see below), whereas the module number and sector number are simply supplied with octal numeric literals inor. The difference betweenandis that the former selects duplex memory while the later selects simplex memory.In the usage I've seen, usage ofis confined almost entirely to the context of(see below). CDS

1

0

1

1

1

0

TBD

PTC only ... not LVDC. This functionally identical to the identically-named LVDC instruction above, but is slightly different both syntactically and in the encoding of the assembled instruction.



Changes the currently-selected 256-word data sector by partially overwriting the HOP Register as follows:







See also HOP .



In terms of assembly-language syntax:

CDS DM,DS

DM is limited to 0 or 1, while DS is an octal literal from 0 to 17.

SHF

0

1

1

1

1

0

1

LVDC only ... not PTC.



Performs a shift operation on the accumulator. For this instruction, bits A8 and A9 form a part of the instruction itself, but of the remaining bits only A1, A2, A5, and A6 are actually used, as follows:



A1

A2

A5

A6

Description of operation

0

0

0

0

Clears the accumulator

1

0

0

0

Shift one position right, duplicating the sign bit into the vacated position

0

1

0

0

Shift two positions right, duplicating the sign bit into the vacated position

0

0

1

0

Shift one position left, filling the vacated position with 0

0

0

0

1

Shift two positions left, filling the vacated positions with 0



By a "left" shift, we mean a shift toward the more-significant direction (multiplying by powers of 2); by a "right" shift, we mean a shift toward the less-significant direction (dividing by powers of 2).



In terms of assembly-language syntax, I have never seen SHF itself used. Rather, the synonyms SHL (left shift) and SHR (right shift) are used, and only in the following variations:

SHL N

SHR N

where N is a literal decimal numerical constant. However, N is not limited to just 0, 1, or 2, even those are all that SHF directly supports. If an operand N >2 is encountered, the assembler transparently replaces it with an appropriate sequence of shift-by-2 and shift-by-1 instructions.



Note: The original documentation of the SHF instruction itself does not actually describe the directionality of the shifts, nor the nature of the data used to fill the bit-positions vacated by the shift. It instead simply refers to the there-undefined terms "MSD shift" and "LSD shift". Elsewhere in the original documentation is a theory-of-operation for the electronic circuitry, and the additional information about directionality and fill-values given above is derived from the theory of operation.

SHF 0

1

1

1

1

0

TBD

PTC only ... not LVDC.



Functionally similar to the identically-named LVDC instruction, but differs in detail. It does not provide a "clear accumulator" function as the LVDC instruction does, but allows a shift of up to 6 bit-positions in a single instruction (rather than up to 2 as in the LVDC).



As far as the encoding is concerned: A7 determines the direction of the shift: 0 = left shift (filling vacated bit positions with 0), 1 = right shift (duplicating the sign bit into the vacated bit positions). As for A6-A1:



A1

A2

A3

A4

A5

A6

Description of operation

1

0

0

0

0

0

Shift by one position (left or right as determined by A7)

0

1

0

0

0

0

Shift by two positions (left or right as determined by A7) 0

0

1

0

0

0

Shift by three positions (left or right as determined by A7) 0

0

0

1

0

0

Shift by four positions (left or right as determined by A7) 0

0

0

0

1

0

Shift by five positions (left or right as determined by A7) 0

0

0

0

0

1

Shift by six positions (left or right as determined by A7)

In terms of assembly-language syntax, I have never seen SHF itself used. Rather, the synonyms SHL (left shift) and SHR (right shift) are used, and only in the following variations:

SHL N

SHR N

where N is a literal decimal numerical constant. However, N is not limited to just 1 through 6, even those are all that SHF directly supports. If an operand N >6 is encountered, the assembler transparently replaces it with an appropriate sequence of shift-by-6 (or less) instructions.



Note: The original documentation of the SHF instruction itself does not actually describe the directionality of the shifts, nor the nature of the data used to fill the bit-positions vacated by the shift. It instead simply refers to the there-undefined terms "MSD shift" and "LSD shift". Elsewhere in the original documentation is a theory-of-operation for the electronic circuitry, and the additional information about directionality and fill-values given above is derived from the theory of operation.

EXM

1

1

1

1

1

0

1

LVDC only ... not PTC.



"Execute modified". In baseball terms, this is the "infield fly rule" of the LVDC: it clearly does something, but upon first acquaintance it's hard to grasp exactly what it does.



The EXM instruction takes a target instruction stored at a different memory location, forms a modified operand for that instruction, executes the modified instruction, and then continues with the next instruction following the EXM (unless the program counter has been changed by the modified instruction). For this instruction, A8 and A9 form a part of the instruction code, so only A1-A7 are significant.



It is important to understand that the target instruction is not modified within the LVDC memory; rather, it is modified and executed without the modified form of it being stored in memory at all.



Only 4 different choices of memory address are allowed to contain the target instruction which is to be modified, namely 0200, 0240, 0300, and 0340 in the "residual sector" in the memory module selected by the current DM (data module) bit. (The original documentation does not actually indicate whether it is the IM or DM bit that selects the particular memory module in which the target instruction is stored, and I think that it would be very reasonable to suppose that the IM bit is used. But from the actual AS206-RAM Flight Program source code, it is obvious that DM is the bit which is used.)



Some of the bits in A1-A7 of the EXM instruction represent various types of modifications to the embedded address at the target address rather than themselves being address bits. Here are the interpretations of bits A1-A7 found in the EXM instruction:

A1-A4 modify the address embedded in the target instruction as described below.



A5 indicates the syllable in which the target instruction resides in residual memory.

A7,A6 selects the target address, as follows:

0,0 for target address 0200



0,1 for target address 0240



1,0 for target address 0300



1,1 for target address 0340 To modify the target instruction, its A1-A9 bits are formed as follows:

A1-A2 come from A1-A2 of the EXM instruction.

instruction. A3 is the logical OR of the A3 of the target instruction and A3 of the EXM instruction.

instruction. A4 is the logical OR of the A4 of the target instruction and A4 of the EXM instruction.

instruction. A5-A8 come from A5-A8 of the target instruction, and remain unchanged.

A9 becomes 0, thus the target instruction cannot be either EXM or SHF/SHR/SHL . (The original documentation does not actually say anything about how the target instruction's A9 is modified, but if it were allowed to remain 1, the data-sector discussion which immediately follows would not make sense.)

The data sector used when the target instruction is executed is also changed for the duration of that one instruction, as determined by bits A1, A2, and A9 of the unmodified target instruction, as follows:



A2

A1

A9

Data Sector

0

0

0

004

0

0

1

014

0

1

0

005

0

1

1

015

1

0

0

006

1

0

1

016

1

1

0

007

1

1

1

017 ("residual" sector)



The assembly-language syntax is

EXM adr,syl,mod

where adr (0, 1, 2, or 3) selects target address 200, 240, 300, or 340, respectively; syl (0 or 1) is the syllable of the target address; and mod (00-17 octal) is the 4-bit modification to be applied to bits A1-A4 of the target instruction's operand.

CLA





1

1

1

1

1

Store a value to the accumulator, from the memory word at the address embedded within the instruction. Recall that A1-A8 select the offset within a 256-word sector, and A9 is the "residual bit" that selects between the current sector and the "residual sector".

I/O Ports (For LVDC/PTC PIO Instruction)

Note that the LVDC code is self-modifying, and thus ports that don't explicitly appear in the source code may actually be accessed at runtime, while ports that do explicitly appear in the code may be changed to something else before having a chance to be accessed at runtime. For example, on p. 227 of the AS206-RAM source code (look at labels MLDBUX , MLDBUY , and MLDBUZ ), there's self-modifying code that changes an instruction PIO 203 to a PIO 303 , then changes it to a PIO 273 , and then finally changes it back to PIO 203 . Unfortunately, with programming and documentation practices like these, getting a complete list of ports used — other than by just running the code under all possible combinations of conditions and recording what happens — is a tough proposition. (That's not intended as a criticism of the programming practices IBM FSD had back in 1967 ... but it goes to show why, today, there are reasons that practices such as these are frowned upon.)



At any rate, here is a table of ports from the original documentation, though massaged a bit by me.



Address Field from PIO Instruction

Data Source

Data Destination

Specific I/O Ports

A9

A8

A7

A6

A5

A4

A3

A2

A1

X

0

A

A

A

A

A

0

A

Accumulator Register

LVDA Telemetry Registers



or PTC

general

purpose

For LVDC, used to output telemetry consisting of the values of variables, typically via the TELEM macro in the LVDC source code. For definitions of non-standard units of measurement, see the later discussion of that topic. Page-number references are to the AS-206RAM LVDC source code or to its abridged form.)



LVDC

PTC

A9-A1 (octal)

Variable

Scale

Units

Interpretation

000

TASEC

ONTAS

B15

sec

Time elapsed from GRR or time of last orbit navigation

001

CHIZ

B0

pirad

Yaw guidance command in space-fixed coordinates

004

ACCZ



0.05 m/sec

Accelerator optisyn reading

005

CHIX

B0

pirad

Pitch guidance command in space-fixed coordinates 010

ACCX



0.05 m/sec Accelerator optisyn reading 011

CHIY

B0

pirad

Roll guidance command in space-fixed coordinates 014

ACCY



0.05 m/sec Accelerator optisyn reading 015

THETZ B0

pirad Whole yaw gimbal angle

021

THETX

B0

pirad Whole roll gimbal angle 025

THETY

B0

pirad Whole pitch gimbal angle 030

TLTBB

B15

sec

Biased time elapsed in time base

031

TB

B15

sec

Time elapsed in current time base

034

ZS

ONZN

B23

m

Component of position in space-fixed coordinates

044

XS

ONXN

B23

m

Component of position in space-fixed coordinates 050

Y S

ONYN

B23

m

Component of position in space-fixed coordinates 054

GR10R

B-22

m-1 Reciprocal of total radius in space-fixed coordinates

060

GZ

B4

m/sec2 Component of gravitational acceleration

064

GX

B4

m/sec2 Component of gravitational acceleration 070

GY

B4

m/sec2 Component of gravitational acceleration 074

TBA

B15

sec

Set equal to TBB at the time of a C-band station gain or loss

075

SS





Switch selector interrupt

110

ZDS

B14

m/sec

Component of velocity in space-fixed coordinates

114

XDS

B14

m/sec Component of velocity in space-fixed coordinates 120

YDS

B14

m/sec Component of velocity in space-fixed coordinates 124

V

B14

m/sec Total velocity in space-fixed coordinates

134

ZS

B23

m

Component of position in space-fixed coordinates 144

XS

B23

m

Component of position in space-fixed coordinates 150

YS

B23

m

Component of position in space-fixed coordinates 174

ACCT

TLPAST

B25

qms

Real time clock reading

400

T1I

B10

sec

First IGM phase time-to-go

414

MC28





Mode code 28 status changes. Refer to p. 12.

415

MC24





Mode code 24 status changes. Refer to pp. 4-5.

420

MC27





Mode code 27 status changes. Refer to pp. 11-12

421

MC25





Mode code 25 status changes. Refer to p. 5. 425

DORSW





Discrete output register contents. A change indicates a guidance failure.

431

ICR





LVDA internal control register contents. Refer to pp. 5-6.

434

Z4

B23

m

Position in target plane coordinates

435

EMRR

TLEMR1





Error monitor register contents. Change indicates ladder failure or redundancy disagreement.

441

INT





LLS, OBCO, TLC, or S4BCO interrupt. Refer to p. 6. 444

X4

B23

m

Position in target plane coordinates 450

Y4

B23

m

Position in target plane coordinates 460

T3I

B10

sec

Time-to-go in S4B second burn

461

TLCHPC





TLC ("tough luck charlie") HOP constant

465

DIS.IN





Discrete inputs. Refer to p. 6. 471

SQ3

B1



(1-ZSP2)1/2 475

TBBU





Time base backup

500

FDBK





Switch-selector feedback register, in the event of an error

501

MLCHIZ

B0

pirad

Minor loop CHIZ

504

ZDDV

B4

m/sec2 Component of vent acceleration

505

MLCHIX

B0

pirad

Minor loop CHIX 510

XDDV

B4

m/sec2 Component of vent acceleration

511

MLCHIY

B0

pirad

Minor loop CHIY 514

YDDV

B4

m/sec2 Component of vent acceleration

520

ZDDD

B4

m/sec2 Component of drag acceleration 524

XDDD

B4

m/sec2 Component of drag acceleration 530

YDDD

B4

m/sec2 Component of drag acceleration 534

ALT

B4

m

Altitude

535

TLEMR8





Minor-loop error code

544

TAUD

B10

sec

Time-to-go

561

TI

B15

sec

Time from GRR of time-base change

570

(various)





Minor-loop error code. Refer to pp. 6 and 14.

571

ETC





End of telemetry cycle, one per computation cycle

575

BTC





Begin telemetry cycle, one per computation cycle

A9-A1

(octal)

Purpose

000

I suspect this may clear the entire interrupt latch.

001

Set interrupt 1 latch.

004

Set interrupt 3 latch.

010

Set interrupt 4 latch.

020

Set interrupt 5 latch.

021



034



040

Set interrupt 6 latch.

065



075



100

Set interrupt 7 latch.

135



200

Set interrupt 8 latch.

210

Enables one of six output discretes to be generated. Discretes 1 through 6, respectively, are controlled by positions 25, 24, 23, 22, 21, and 20 of the accumulator data word. I'm not sure how this differs from CIO 210 (see next section). In fact, the source-code comment in the PAST program even mentions CIO 210 . From the test procedures in the PAST program, it appears to me that these are the same 6 bits which can be read back with CIO 214 (bits 22-17) when appropriately gated by the PROG REG A toggle switches.

221



340



400

Set interrupt 9 latch.

525







0

1

A A A A A 0

A

Main Memory

LVDA Telemetry Registers 1

1

A A A A A 0

A

Residual Memory

LVDA Telemetry Registers X

0

A

A

A

A

A

1

0

Accumulator Register LVDA Output Registers



or



PTC

general

purpose

LVDC

PTC

A9-A1 (octal) Purpose

006

Mode Register

012 Discrete Output Register (Reset). The LVDC EDD for the Saturn IB Flight Program document, section 7.3, summarizes the discrete outputs as:



016 Discrete Output Register (Set). See PIO 012 above.

022 Internal Control Register (Set)

026 Internal Control Register (Reset)

032 Interrupt Register Reset. Resets the interrupts whose bits are set in ACC. See 072 below.

036 Switch Selector Register (Load)

042 Orbital Checkout

052 Switch Selector & Discrete Output Registers (Read)

062 Switch Selector Interrupt Counter

066 COD Error (Read)

072 Interrupt-inhibit latch. (None of the following is covered by the available documentation, so everything I say about it is inferred or guessed from source code.) It's not clear to me whether this simply writes the value in ACC to the latch, or whether it logically-OR's ACC to the latch; I presume the latter. There are 13 interrupts covered, and the mask comprises the 12 most-significant bits of ACC other than SIGN. Here's how I think the bit-positions of the latch are interpreted:

S: n/a (0)

1: ML (Minor Loop)

2: SS (Switch Select)



3: CIU? In the AS206-RAM Flight Program, the interrupt-service routine for this always immediately exits. So in effect, these interrupts are always ignored whether inhibited or not.



4: TLC (Tough Luck Charlie)

5: Command Receiver? The interrupt-service routine for this is not part of the AS206-RAM Flight Program, and is instead in unassigned memory. Presumably it is serviced by some other program co-loaded into memory along with the flight program.



6: GRR? In the AS206-RAM Flight Program, the interrupt-service routine for this always immediately exits. So in effect, these interrupts are always ignored whether inhibited or not.

7: S2 PROP. DEPL.? In the AS206-RAM Flight Program, the interrupt-service routine for this always immediately exits. So in effect, these interrupts are always ignored whether inhibited or not.

8: OECO/OBCO (Outboard Engine Cut Off, starts Time Base 3)



9: S4B/S4BEO/S4BCO (S4B Engine Cut Off)



10: RCA? In the AS206-RAM Flight Program, the interrupt-service routine for this always immediately exits. So in effect, these interrupts are always ignored whether inhibited or not.

11: LLS (Low Level Sense, starts Time Base 2)



12: ?



13-25: n/a (0) 076 Minor Loop Timed Interrupt Counter

146 Ladder No. 1

152 Ladder No. 2

156 Ladder No. 3

162 Ladder No. 4

166 Ladder No. 5

172

Clamp adders. (This is not covered by the available documentation, but seems to be implied by the comments in the source code.) 672

(None of this is covered by the available documentation.) Clear interrupt-inhibit latch, using a mask. It's not clear to me whether this logically-inverts the mask and then AND's it to the latch, or whether it XOR's the mask to the latch; I presume the former. In the AS206RAM Flight Program's source code, PIO 672 is used in memory module 2, and address 672 translates to 2-17-272, which is the variable IHBT . I infer that the technique for temporarily inhibiting LVDA-generated interrupts is:

Create a bit-mask determining which interrupts to inhibit.

Store the mask at IHBT .

. Write the mask out to the interrupt-inhibit latch with PIO 072 (and possibly PIO 032 ).



(and possibly ). ... do stuff ...

Use PIO 672 to undo the masked interrupt-inhibit bits in the latch.

A9-A1

(octal)

Purpose

002

Set interrupt 2 latch.

006



016



022



026



032



036



056



066



076



136



222



252



402



776







0

1

A

A

A

A

A

1

0

Main Memory LVDA Output Registers 1

1

A

A

A

A

A

1

0

Residual Memory LVDA Output Registers X

0

A

A

A

A

A

1

1

LVDA Peripheral Inputs and Errors

Accumulator

LVDC

PTC

A9-A1 (octal) Purpose

023

Error Monitor Register

043

Command Receiver or RCA-110

053

Discrete Input Spares. Refer to the DIS1-DIS8 inputs in the table for PIO 057 below.

057

Discrete Inputs. The LVDC EDD for the Saturn IB Flight Program document, section 7.4, summarizes the discrete inputs in the table below. (The DIS1-DIS8 inputs in the table for PIO 053 above.)



PIO 057 . A value of 1 in the OM/D bit indicates that a "mode" command word has been received (and is accessible via PIO 043 ), while a value of 0 indicates instead that a "data" command word has been received (in PIO 043 ).

The Command Decoder OM/D bits mentioned in the table originate in an up-data command word transmitted to the rocket from mission control. There are two such bits in the transmitted word, but the LVDA combines them into a single bit before passing them to the LVDC — hence, OM/D bits "A" and "B" both appear at the same position in. A value of 1 in the OM/D bit indicates that a "mode" command word has been received (and is accessible via), while a value of 0 indicates instead that a "data" command word has been received (in). 067

Telemetry Scanner

077

Switch Selector

103

Real Time

107

Accelerometer Processor X

117

Accelerometer Processor Z

127

Accelerometer Processor Y 137

Interrupt Storage A9-A1

(octal)

Purpose

003



017



023



027



033



037



043



047



053



057



063



067



073



077



117



123



127



133



137



157



167



177







X

1

A

A

A

A

A

1

1

LVDA Resolver Processor Inputs

Accumulator LVDC

PTC

A9-A1 (octal) Purpose

203

Z Gimbal Backup. (This is not covered by the available documentation, but seems to be implied by the comments in the source code.)

207

Spare No. 6

217

Computer COD Counter Start

223

Fine Gimbal No. 1

233

Coarse Gimbal No. 3

237

Computer COD Counter Start

243

Coarse Gimbal No. 1

247

Horizon Seeker No. 1

257

Spare No. 3

273

Y Gimbal Backup. (This is not covered by the available documentation, but seems to be implied by the comments in the source code.) 277

Spare No. 4

303

X Gimbal Backup. (This is not covered by the available documentation, but seems to be implied by the comments in the source code.) 313

Fine Gimbal No. 4

317

Spare No. 1

323

Horizon Seeker No. 3

327

Horizon Seeker No. 2

333

Coarse Gimbal No. 4

337

Spare No. 5

343

Coarse Gimbal No. 2

353

Fine Gimbal No. 3

357

Spare No. 2

363

Fine Gimbal No. 2

367

Horizon Seeker No. 4

A9-A1

(octal)

Purpose

203



213



223



227



233



237



243



247



253



257



263



267



273



277



303



313



317



323



333



337



343



347



353



357



363



367



373



403

See CIO 230 .

773



777

Address register







I/O Ports (for PTC CIO Instruction)

Figure 2-11 of the original PTC documentation gives a list of i/o ports employed by the PTC's CIO instruction. Unfortunately, by my count, 137 different CIO ports are used just within the PAST program, while the documentation lists only 35 of them. The following is a table of all known CIO ports, including not only those listed in the original documentation, but also those found in the source code of the PAST program. Sometimes the functionality of a port referenced only in the PAST program is easily inferred from comments in the source code, so I've supplied my inferences in the table below, while in other cases I haven't yet deduced that functionality. In other words, as usual, this is a work in progress! Port numbers whose descriptions were pasted from the original documentation are in bold text, to distinguish them from those whose functionality has merely been inferred.



CIO Operand Address

Operation

000

Enables the interrupt inhibit register latches to be set under control of accumulator data bits 11 through 25 (Data bit 11 sets interrupt inhibit latch 15, etc.)

001

Set interrupt 3 latch. For additional functionality beyond this, see CIO 234 .

002

Set interrupt 1 latch

003

TBD

004

Enables the interrupt inhibit register latches to be reset under control of accumulator data bits 11 through 25 (Data bit 25 resets interrupt inhibit latch 1, etc.)

005

Set interrupt 4 latch

006

Set interrupt 2 latch

007

TBD 010

Reset interrupt 1 latch

011

Set interrupt 5 latch

012

Set interrupt 3 latch

014

Reset interrupt 2 latch

015

Set interrupt 6 latch

016

Set interrupt 4 latch

017

TBD 020

Reset interrupt 3 latch

021

Set interrupt 7 latch

022

Set interrupt 5 latch

023

TBD 024

Reset interrupt 4 latch

025

Set interrupt 8 latch

026

Set interrupt 6 latch

030

Reset interrupt 5 latch

031

Set interrupt 9 latch

032

Set interrupt 7 latch

034

Reset interrupt 6 latch

035

Set interrupt 10 latch

036

Set interrupt 8 latch

037

TBD 040

Reset interrupt 7 latch

041

Set interrupt 11 latch

042

Set interrupt 9 latch

044

Reset interrupt 8 latch

045

Set interrupt 12 latch

046

Set interrupt 10 latch

050

Reset interrupt 9 latch

051

Set interrupt 13 latch

052

Set interrupt 11 latch

054

Reset interrupt 10 latch

055

Set interrupt 14 latch

056

Set interrupt 12 latch

057

TBD 060

Reset interrupt 11 latch

061

Set interrupt latch 15

062

Set interrupt latch 13

064

Reset interrupt 12 latch

065

Set interrupt latch 9 066

May do the following: set interrupt 14 latch and then "enable compare" (if SIGN=1) or "disable compare / reset compare latch" (if SIGN=0). In other words, I suspect that an interrupt of type 14 occurs when a comparison match occurs. The other bits in ACC may be the bit pattern against which the comparison is made. I would suggest further that the the "compare latch" referred to is the Address Compare (ADR COMP) latch, discussed on p. V-2-69 of the PTC documentation, so that the contents of ACC would be something like a HOP constant. A perhaps illustrative usage in the PAST program code is found at label L9P36 , shortly after which we find ACC indeed being loaded with the HOP constant (for location L9P36 ), and then output via CIO 066 . A similar sequence of code occurs at label L10P33 . On the other hand, this interpretation is inconsistent with the notion that the SIGN bit must be non-zero to enable comparisons, since L9P36 's HOP constant has a SIGN bit of 0, so perhaps more thought is required to unravel what this operation is doing.

070

Reset interrupt 13 latch

071

Set interrupt latch 10 072

May do the following: set interrupt latch 15, and load a register determining the behavior of TSYNC signal. The PAST program comments that relate to the values loaded in ACC are:

137777777, solid TSYNC reset, diode check



337777777, single TSYNC pulse (if not followed by CIO 102 ) or 240 TSYNC pulses per second (if followed by CIO 102 ). 074

Reset interrupt 14 latch

075

Set interrupt latch 1

076

May be the same kind of thing as CIO 072 , except for interrupt latch 11 and the GCSYNC signal:

000000002, solid GSYNC reset, diode check.

257777777, reset solid GSYNC

357777777, single GSYNC pulse (if not followed by CIO 102 ) or 240 GSYNC pulses per second (if followed by CIO 102 ).

) or 240 GSYNC pulses per second (if followed by ). 377777777, solid GSYNC

(The PAST program source code actually indicates that the first item on the list above is a CIO 072 ... but I think this may be a bug in the PAST program, and it may have intended to say CIO 076 rather than CIO 072 .) 077

TBD 100

Reset interrupt 15 latch

101

Set interrupt latch 2

102

Set interrupt latch 13

104

Reset interrupt 16 latch

105

Set interrupt latch 3

106

Set interrupt latch 1

110

Resets the main interrupt latch, also known as the INT B latch. The value provided in ACC is ignored.

111

Set interrupt latch 4

112

Set interrupt latch 2

114

Generates a PTC single step command.

115

Set interrupt latch 5

116

Set interrupt latch 3

117

TBD 120

Sends a single character to be printed on the typewriter. This character is encoded in 6 bits (SIGN and bits 1-5) in BA8421 format. See the BCI pseudo-op for an explanation of BA8421.



The typewriter BUSY signal (see CIO 214 below) becomes active while this operation occurs physically, and then becomes inactive when the operation is complete.



For reasons which are unclear to me, CIO 120 appears to enable various interrupts in the interrupt latch, with different interrupts being enabled for different characters. The same holds true for CIO 124 and CIO 130 , with the same interrupts being enabled for the same printable characters. Moreover, the conditions enabled by CIO 130 affect still other interrupt bits. In the PAST program source code, the characters printed vs the interrupt bits expected to be set are given by a 1-to-1 relationship between the arrays CHAR and PATN , with the exception that PATN does not distinguish between "upper case" and "lower case" characters as described below. Though not mentioning interrupts at all, the interrupt-bit patterns seem to be derivable from Figure 2-56 of the PTC document, "Selection and Tilt-Rotate Schedule", in which the following relationship between individual BCD keyboard solenoids (or other conditions) and interrupt bits seems to hold empirically:

Interrupt 3 latch: R1 ( CIO 120/124/130 )

) Interrupt 4 latch: R2 ( CIO 120/124/130 )

) Interrupt 5 latch: R2A ( CIO 120/124/130 )

) Interrupt 6 latch: R5 ( CIO 120/124/130 )

) Interrupt 7 latch: T1 ( CIO 120/124/130 )

) Interrupt 8 latch: T2 ( CIO 120/124/130 )

) Interrupt 9 latch: Check Bit ( CIO 120/124/130 )

) Interrupt 10 latch: TAB ( CIO 134 )

) Interrupt 11 latch: INDEX ( CIO 134 )



) Interrupt 12 latch: RED ( CIO 134 )



) Interrupt 13 latch: BLACK ( CIO 134 )

