apollo guidance computer agc
DESCRIPTION
This is a compilation of nine sections which describe and document every detail on how to build and make fully functional an Apollo Guidance Computer. Not for the casual hobbyist. The author of this incredible work actually built one of these in his basement, took four years. Also, the types of integrated circuits used are not low power, collectively it draws quite a bit of DC current. If you think that take on a monumental challenge, try this - or at least read all about it...TRANSCRIPT
Block IApollo Guidance Computer (AGC)
How to build one in your basement
Part 1: Overview
John Pultorak
December, 2004
Abstract
This report describes my successful project to build a working reproduction of the 1964
prototype for the Block I Apollo Guidance Computer. The AGC is the flight computer for the
Apollo moon landings, and is the world’s first integrated circuit computer.
I built it in my basement. It took me 4 years.
If you like, you can build one too. It will take you less time, and yours will be better than
mine.
I documented my project in 9 separate .pdf files:
Part 1 Overview: Introduces the project.
Part 2 CTL Module: Design and construction of the control module.
Part 3 PROC Module: Design and construction of the processing (CPU) module.
Part 4 MEM Module: Design and construction of the memory module.
Part 5 IO Module: Design and construction of the display/keyboard (DSKY) module.
Part 6 Assembler: A cross-assembler for AGC software development.
Part 7 C++ Simulator: A low-level simulator that runs assembled AGC code.
Part 8 Flight Software: My translation of portions of the COLOSSUS 249 flight
software.
Part 9 Test & Checkout: A suite of test programs in AGC assembly language.
Why build an AGC?
Early computers are interesting. Because they’re simple, you can (if you like) actually
understand the entire computer, from hardware to software.
The AGC is the most interesting early computer because: a) it flew the first men to the
moon; and b) it’s the world’s first integrated circuit (IC, or microchip) computer. It also has
interesting architectural features.
Original AGC:Designed by M.I.T. in 1964
World's first microchip computer
Prototype computer for Apollo moon landing
Memory: 12K fixed (ROM), 1K eraseable (RAM)
Clock: 1.024 MHz
Computing: 11 instructions, 16 bit word
Logic: ~5000 ICs (3-input NOR gates, RTL logic)
My AGC:Built from original M.I.T. design documents
Started November 2000, completed October 2004
~15K hand-wrapped wire connections; ~3500 feet of wire
Cost (parts only): $2,980.
Labor: ~2500 hours
Logic: ~500 ICs (LSTTL logic)
Runs flight software (1969 program name: COLOSSUS 249)
How did I build it?I collected orig inal documents from libraries, technical services, and the internet. I had to
pay for some (~$350.) Mostly, they’re available for free now.
I wrote an AGC software simulation (in C++) and cross-assembler (to program it). Then, I
wrote test and checkout programs in AGC assembly language to check the simulator against
specifications in the original documents.
I downloaded a big chunk of original flight software from M.I.T. and got it running on my
simulator.
The simulator was my baseline for logic design. I put my logic design into a circuit design
tool (CircuitMaker) which “captures” schematics and (digitally) simulates circuits. Using
CircuitMaker, I “unit-tested” each AGC subsystem logic design (there are about 20).
Then, I assembled my subsystem logic simulations into one really huge dig ital circuit
simulation of the entire AGC and “integration-tested” this for about 6 months. I eventually
ran my entire suite of AGC test and checkout software on this circuit simulation. (The
simulation was extremely slow, running at about a 500,000 : 1 rate, but very detailed).
I bought parts, mostly from JAMECO, and wire-wrapped the entire computer on 15 circuit
boards in my basement. I built the “relay rack” out of 1x2 inch pine boards, rails for
shelving (can you spot them?), plexiglass, screws, and spray paint.
Three AGCs
To succeed, I had to build the AGC three times. Or rather, I had to bu ild three AGCs. Each
one is a fully functional computer. Each one is a step toward building the next. The last one
is the one I wanted.
Here’s the “faces” of my three AGCs:
AGC #1: my C++ AGC simulator.
It has every register and logic
signal in the original
documentation.
I use it to develop and debug
AGC assembly language code.
When I got this working, I knew I
understood the AGC. I knew I
could do the rest of the project.
AGC #2: my CircuitMaker digital circuit
simulator AGC. What you see here are front
panel logic indicators for signals and registers.
The remaining part: about 60 or so pages of
logic diagrams; the same schematics you’ll see
in the CTL, PROC, MEM, and IO .pdf files that
follow this overview.
This AGC literally runs about a half-million
times slower than the first! I used it to debug
my logic design.
When I got this working, I knew I still had a
year (14 months, actually) of tedious work
ahead.
AGC #3: This is
the final one.
My hardware AGC
is built into a
relay rack to give
it the same
prototyped
appearance as
the original. The
dimensions are
about 3 x 5 feet.
The upper left
module (CTL) is
the control logic.
The lower left
module (PROC) is
the CPU.
The lower right
module (MEM) is
the memory.
The upper left
module (IO) has
the inputs and
outputs. The
keyboard and
display (DSKY)
for user input are
on the upper-
middle-right.
The white KYNAR
wires look like
cobwebs to me.
This was
photographed in
my back yard.
Can you see the
blue sky and tree
branch reflections
in the upper
panels?
Here I am, plugging COLOSSUS 249 flight
software EPROMs into ZIF sockets.
We lugged the AGC out of the basement and
took it outdoors for these photographs. It’s in
the backyard, propped against the back of my
house.
A close-up of COLOSSUS EPROMs. I put red
tape over the quartz windows to keep them
from erasing themselves.
A bought the toggle switches a few years
ago from a surplus vendor. They were so
cheap, I bought a 100 of them. Aren’t they
great?
I really like flashing lights and control panels.
There’s no way to debug something this
complex without them.
I bought LEDs in bulk from the same place
that sold me the switches.
AGC Demonstration
Here’s a demonstration of my AGC. It’s running my version of the COLOSSUS 249 flight
software load:
At power-on, the AGC initializes to major mode 00
(POO).
Display CM clock:
<VERB> <0> <6> <NOUN> <3> <6> <ENTER>
The red buttons were from Radio Shack.
The AGC samples and displays the CM clock. 58
hours, 44 minutes, 34.27 seconds.
Test display lights:<VERB> <3> <5> <ENTER>
All DSKY lamps and display segments illuminate
for 5 sec. The Verb and Noun displays flash. After
5 sec, the DSKY lamps extinguish. The 88888
displays are left in the registers.
Load component 1 for dataset atoctal address 50 with octal 123:
<VERB> <2> <1> <NOUN> <0> <1>
<ENTER>
Verb/noun display flashes: waiting for address
<5> <0> <ENTER>
Verb/noun display flash continues: waiting for
data
<1> <2> <3> <ENTER>
Octal word from R1 is loaded into memory at
address 50.
Start a monitor program tocontinuously display elapsed timefrom the CM clock:
<VERB> <1> <6> <NOUN> <3> <6>
<ENTER>
The monitor program starts to continuously
display the CM clock, updating the display about
about 1 second intervals. The time shown is 58
hours, 47 minutes, and 23.67 seconds.
Display component 1 of dataset atoctal address 50:
<VERB> <0> <1>
The “key rel” light flashes because the CM clock
monitor program has been suspended.
<NOUN> <0> <1> <ENTER>
verb/noun display flashes: waiting for address
<5> <0> <ENTER>
The octal word from address 50 is displayed in
R1. In a previous operation, we had set the word
to 123.
Increment the address:
<NOUN> <1> <5> <ENTER>
The octal word in address 51 is displayed in R1,
incremented address in R3.
<ENTER>
The octal word in address 52 is displayed in R1,
incremented address in R3.
Resume the CM clock monitorprogram:
<KEY REL>
Verb 16, noun 36 reappears, along with the
clock display. The key release light goes out.
(I’m not sure why the photos suddenly turned
darker; I think someone must have turned off a
light in an adjoining room)
Terminate the CM clock monitorprogram:
<VERB> <3> <4> <ENTER>
Change major mode to P00:
<VERB> <3> <7> <ENTER>
Verb/noun display flashes: waiting for major
mode.
Enter major mode P00:
<0> <0> <ENTER>
AGC starts POO.
AGC Project Diary
October - November, 2000:
Thinking about building a computer. Decided to reproduce a minicomputer from the
1960's or ‘70's. Started gathering technical documentation on DEC PDP 8 and Data
General NOVA.
Found a book in the local library (Ceruzzi, “A history of Modern Computing”) with a
page on the AGC. Decided to build a NASA flight computer; Gemini or Apollo. Gemini
interests me more, because it’s the earlier. Downloaded Tomayko’s “Computers in
Spaceflight.”
December 2000:
My search for Gemini computer documentation on CASI and NTIS is fruitless. IBM
federal systems division is gone. Found some interesting AGC documentation. Asked
for, and received, E.C. Hall’s “History of the Apollo Guidance Computer” for
Christmas.
January - February 2001:
Decided to buld an AGC. Ordered about $300. of technical documents from CASI and
NTIS. Discovered you can’t judge a document by it’s title.
Sent e-mail to Goddard Space Flight Center; got a copy of the AGC Basic Training
Manual, a programmer’s manual for the Block II. Went to CompUSA and bought a
Microsoft C++ compiler. Starting to build a AGC Block II software simulation.
Sent an e-mail to Draper Labs (former MIT Instrumentation Lab where AGC was
designed) asking for R-393 (Block I “Logic Description”). This might be the key
document. Draper responds by sending R-393 (free!).
JACKPOT!
Abandoning Block II simulator. I am building a Block I AGC.
March - May 2001:
Rapid progress on the Block I simulation. Wrote an AGC cross-assembler in C++; it
produces object code readable by the AGC simulator. Generating test code to debug
AGC basic instructions.
Designed the simulator to map as closely as possib le to the R-393 hardware
registers, buses, microinstructions, and control signals. Broke the simulation into 20
subsystems that map to AGC hardware. I will eventually use the simulator code to
guide my hardware logic design.
Finished emulation of all 11 normal and extracode instructions. Wrote my first Block I
assembly language program! Starting to simulate the priority counters and
interrupts.
June - August 2001:
Finished v1.0 of the Block I simulator. Wrote a suite of AGC assembly language test
and checkout programs: TECO1 checks basic instructions; TECO2 checks extracode
instructions; TECO3 checks editing registers. Everything works, including interrupts
and counters.
Found MIT website with AGC history and interesting online documentation.
E-mailed Eldon Hall, designer of the AGC, telling him about my project. His reply was
gracious and encouraging. Wrote many emails to others asking for Block I source
code.
I order a 2.048 MHz crystal from DigiKey. My first hardware purchase.
September - October 2001:
Can’t find any original Block I source code, except tiny fragments in the documents.
Recoded my own EXEC, WAITLIST, and interrupt handlers using specifications from
R-393 and others. I’m starting to become a good AGC programmer. Now my
simulator can multitask!
Discovered Block II flight software (COLOSSUS 249) is now downloadable from MIT.
300+ pages of blurry assembler source code listing. Is that an eight, a six, number
zero with a slash through it, or the letter “O”, or maybe “G”? Printed a hardcopy. I
think I can make most of it out.
The second half of COLOSSUS is missing! The missing part has the INTERBANK
COMMUNICATION, EXEC, and WAITLIST. E-mailed MIT. Their reply: they don’t have
the missing portion.
November - December 2001:
Tried to reproduce DSKY code using flowcharts from Green’s “Keyboard and Display
System Program”. Green calls it PINBALL GAME. Very confusing. Started writing a
C++ simulation from Green’s flowcharts. Things are becoming clearer.
Located PINBALL in my COLOSSUS fragment. Abandoned effort to code my own. I
will use the real thing.
January - February 2002:
Retyped most of COLOSSUS PINBALL back into machine-readable form. 95% is
already Block I instructions; recoded the remaining 5% into Block I equivalent.
Finished all the octal display verbs (1-5) and decimal verb (6) and the load verbs
(21-25), but they’re only tested for octal loads so far. Noun tables are stubbed, but I
can manually set them for different scaling.
Integrated PINBALL into my EXEC and WAITLIST. Coded up a few missing pieces for
interbank communication. Also had to code a math library (yikes). But it works.
The AGC simulator is running at about 1/30 the speed of the original. I need to speed
it up.
March - May 2002:
Bought a new, faster PC. The simulator now runs at about 1/5 speed. Recoded some
simulator pieces. Now its 1:1.
Finished PINBALL. All regular verbs (0-39) work. Also, normal nouns 1, 2, 3, 9, 15,
26, and 36. Very cool. My favorites: verb 16, noun 36, a monitor routine to
continuously display the AGC clock, and verb 35 which does the lamp test.
Now that I have some proficiency, I am reluctant to leave AGC software, but it’s time
to start hardware logic design.
June - December 2002:
Decided to use 74LS logic family. Started designing AGC logic, subsystem-by-
subsystem, using the C++ simulator code as my guide. Began with MBF. Posted a
subsystem block diagram on the wall. I’m coloring in blocks as I finish each
subsystem design.
Entered logic designs into the CircuitMaker PC tool. Using CircuitMaker’s digital circuit
simulation to unit-test each subsystem.
Struggling with ALU and read/write bus design. The original AGC OR’ed everything
onto the bus, and the default bus state was logical zero: sometimes, they read the
bus without writing to clear registers. Other times, they wrote multip le registers
simultaneously to OR the data. These tricks won’t work with tri-state bus drivers. I
identify where tricks are used and add ALU logic to handle the cases. My ALU sort-of
feeds back on itself. Confusing, but it should work.
Logic design the old way: Karnaugh maps, excitation tables, and bubble-pushing.
Fun, sort of.
Logic design is now finished, except for the DSKY. Unit tests are done.
I start ordering parts from JAMECO. The first order is for more than 200 ICs.
January 2003:
DSKY logic design is now finished and unit tested in CircuitMaker. All blocks on my
diagram are colored in. Will the subsystems work together?
February - May 2003:
Using CircuitMaker to integrate subsystems. Diagrams for each subsystem are
hooked into CircuitMaker “macros”; rectangular components with all inputs and
outputs for that subsystem. “Wired” all subsystem macros together. Will it run? I call
it AGC2, to differentiate it from the C++ simulator, which I now call AGC1.
Now I have two AGCs! When I build the hardware, that will make three.
Started debugging a TC instruction, the simplest, in AGC2. Worked it through, step-
by-step, fixing logic and interface errors. Finally, it works. Debugging the remaining
8 basic instructions.
Massive snowstorm; snowed in, 3 days straight. Lots of time for AGC2 debugging and
testing.
I estimate my power budget and order a 15A 5V supply. More ICs and sockets are
ordered, too.
Sick of hand-assembling test code for AGC2. Wrote a version of the cross-assembler
that produces object code for AGC2. Broke TECO1 into 8 parts; one for each
instruction. One-by-one, I get all portions of TECO1 to run on AGC2.
Broke TECO2 and TECO3 into pieces and got them to run on AGC2 also.
INTEGRATION TESTING IS DONE!
How to build it? There are too many subsystems and interfaces.
June - August 2003
Grouped the 20 subsystems into 4 “assemblies” (soon to be called “modules”): I/O,
CTL, PROC, and MEM. This is more manageable.
Wrote C++ code that checks the netlists produced by CircuitMaker for fan-out.
Established a limit of 8 TTL loads, and added buffers where necessary. Added buffers
between the 4 modules to make the fan-in for each module/module interface 1 TTL
load.
Stuffed IC sockets into 13 circuit boards; each board is 13"x5". What connectors and
cables to use between boards? Between modules? Should I worry about bus
termination? What kind of chassis?
Decided to build each module as a small relay rack. Board-to-board connections
inside each module are wire-wrapped--no connectors. Between modules, 40-pin IDE
cables, mating to 30-pin wire-wrap connectors, are for module/module interfaces.
Too lazy to pull 500 IC sockets and redo the boards. I’ll work in connectors and
additional buffers where I can. Better buy the longest IDE cables (3 feet). More worry
about bus termination.
Module/Module interfaces are now defined: 6 IDE cables.
Built a rack for the I/O module out of 1x2 pine boards. Spray-painted gray; it looks
pretty good. Hired my engineering student son to wire-wrap some I/O module logic
during summer vacation. He wires most of the DSKY. It lights up and multiplexes,
but operation is erratic; set aside for now.
September - December 2003:
Built control panels for PROC, CTL, and MEM modules by mounting switches on a
wooden frame. Used thick styrene plastic for a faceplate, hand-lettered with indelible
marker. It doesn’t look too bad.
Built indicator light panels for PROC, CTL, and MEM by punching holes in styrene
plastic with a push-pin and then shoving LEDs through the plastic into the PCB.
Hundreds of LEDs; my thumb has a blister.
Built 3 more relay racks for the PROC, CTL, and MEM modules. Laid all the boards out
on the racks. Will the IDE cables reach? Yes, but in some cases, barely.
Bought an EPROM programmer. Learned Motorola S-format. Wrote yet another
version of the cross-assembler that outputs S-Record (s2f) format object code.
Burned EPROMs with TECO1, TECO2, TECO3, and the AGC flight software.
Modified the C++ simulator (AGC1) so it dumps its microinstructions (subsystem
CPM-A) in Motorola S-format. Burned EPROMS for CPM-A. Created a special version
of AGC1 that reads CPM-A S-format microinstructions to verify the tables and reads
AGC object code in S-format to verify the cross-assembler.
January - April 2004
Powered up, and started debugging the partly completed I/O module. Corrected a
design error and a few minor wiring errors; cleaned up some cold-solder joints. It
now works reliably. Finished wiring the I/O module. It’s difficult to test, but it seems
to work.
May - September 2004
Wired the power connections for all sockets on the CTL module; added a bypassing
capacitor for every 2 packages, and a 10uf tantalum capacitor for each row of ICs.
Wired the LED lamps and drivers, and then the logic for each subsystem. Plugged all
the CTL chips into the sockets.
Discovered all control signals from CPM-A were inverted: the EPROM tables were
generated from AGC1, which uses positive logic. The hardware AGC uses negative
logic, because TTL inputs float high; I wanted floating inputs to assume the inactive
state during assembly and test. Pried the EPROMs out of their sockets, bit-flipped the
tables, erased and reprogrammed the chips, and reinserted them. Now it works.
Completed wiring for the other modules. Now to hook them up.
September - October 2004
Built a large rack to hold the 4 modules. Screwed the 4 modules into the rack and
hooked up the IDE cables. Powered it on. Everything lights up. No smoke. Amazing!
It runs part of TECO1, getting through dozens of instructions including subroutine
calls, before bombing out.
Trying to debug the AGC by burning test EPROMs, single-stepping the clock, and
comparing the results to the AGC1 C++ simulator. It’s acting flaky. Could it be a
supply problem?
Tore out my flimsy power distribution; replaced it with heavy aluminum bus bars.
Supply lines look cleaner on the scope, but the operation is just as flaky as before.
Maybe worse. It’s bombing out in d ifferent places. Is there some common element?
Common element: the problem always involves read bus microinstructions. The ALU
sets a default state on the read bus if no other subsystem is using it. My bus
arbitration scheme stinks: if a read signal is asserted, the ALU disables its default
state, but propagation delays cause both drivers to enable simultaneously for a brief
period. Is this the problem?
I kludge-in logic to disable the read bus during CLK1. This gives the read bus logic
time to settle. I add propagation delay to the CLK1 input to TPG so the bus is
disabled before the TPG state transition occurs. Will this fix the problem?
No. It gets farther along, but still bombs out on read bus operations. It’s time to
download internet advice on bus termination. I add 220/330 ohm passive
termination to the read bus input in the ALU. IT WORKS!! TECO1 and TECO3 run
flawlessly.
TECO2 bombs out while testing the DV (divide) instruction. It produces different
results than the AGC1 simulator in the tests that involve division by zero. Do I care?
I decide I don’t.
I load the COLOSSUS EPROMs. The AGC flight software hangs at first; but I add
some passive termination to the “busy” bus driver (for the read bus, of course) and
then it works flawlessly too. The project is finished (except, I have to write up these
reports!)
AGC Block I Diagram
I constructed this diagram in the first months of my project. It shows the AGC subsystems
as boxes. I gave them three-letter names. My diagram is derived from a sim ilar block II
diagram I found in R-700.
I used this diagram to
organize my simulator and
logic designs. But, when it
became time to build the
AGC, I felt this diagram
had too many interfaces;
too much complexity.
To simplify things, I
grouped the subsystems
from this diagram into 4
modules.
The KBD, INP, OUT, and
DSP subsystems were
external interfaces, so I
grouped them into an IO
module. I’ll tell you about
it in part 5 of this report.
The ADR, MEM, MBF, and
PAR subsystems dealt with
memory, so they went into
a MEM module (described
in part 4).
The MON, CLK, SCL, TPG, SEQ, and CPM subsystems generated the timing and control
pulses that run all the other subsystems, so I gathered them into a CTL (control) module (in
part 2).
What remained? The ALU, CRG, INT, and CTR subsystems. I put them in a PROC
(processing) module (part 3).
How my AGC differs from the original
For my purposes, the original AGC is described in a M.I.T. document called R-393 (A.
Hopkins, R. Alonso, and H. Blair-Smith, "Logical Description for the Apollo Guidance
Computer (AGC4)", R-393, MIT Instrumentation Laboratory, Cambridge, MA, Mar. 1963).
Logic DesignThe original AGC4 was built almost entirely from 1964-era 3-input NOR gate ICs; about
5,000 of them. Original gate-level logic designs are not available.
Logic for my replica was recreated using specifications in R-393, and architecture
information/diagrams from R-700. Since R-393 defines (in detail) AGC registers, register
transfers, microinstructions, and most control pulses (logic signals), the architecture of my
replica closely mirrors the original to a low level.
The logic design for my replica uses late 1960's-early 1970's 74LS TTL logic, which affords
about a 10-to-1 reduction in package count. Flip-flop and register chips are used instead of
constructing each element from NOR gates.
The replica successfully runs those portions of the original COLOSSUS flight software that
have been loaded onto it.
ClockThe original AGC4 divided its 2.048 MHz clock down into 4-phase 1.024 MHz signals to drive
asynchronous, level-triggered, register logic.
My replica divides the 2.048 MHz clock into a 2 phased, non-overlapping 1.024 MHz clock to
drive synchronous, edge-triggered register logic. Phase 1 of the clock (CLK1) steps a
sequencer (TPG), which sets up the control signals. Those signals have time to propagate
(settle) between phase 1 and phase 2. Phase 2 (CLK2) clocks the registers using the control
signals established in phase 1. Data transfer occurs at phase 2.
Timing Pulses and Control StatesThe original AGC4 operation was controlled by 12 non-overlapping timing pulses (TP1 -
TP12) generated from a 4-bit gray code counter. Two SR FFs (called R1 and R2) were used
to generate 3 states to control standby operation (STANDBY, POWERON, RUN). R-393
identifies a start/stop logic subsystem which gates the time pulse generator to run and halt
AGC4 for ground test purposes but the internals were not defined.
My control states are integrated into one state machine with 16 states. The 12 timing pulses
(TP1 - TP12) are implemented as states along with 2 additional states for standby operation
(STBY, PWRON). The remaining 2 states (RLSE, WAIT) handle front panel switch inputs for
single stepping.
Interpolation of Gaps in Control LogicR-393 defines control pulses for TP1-TP11, but does not define control pulses for TP12.
Interfaces between interrupts, involuntary counters, and the main control logic are not well
defined. For this reason, logic in the gaps in R-393 had to be interpolated, based upon
functional requirements.
Number and Address of Involuntary CountersThe number of involuntary counters and their address range is ambiguously defined in R-
393. Table 1-1 in R-393 says AGC4 has 20 (base 10, I assume) counters. This is supported
by Figure 2-5 which numbers counters from 1-20. However, Table 3-1 which shows AGC
special registers assigns the counters to addresses 0030 through 0056 (base 8) which
translates to 23 (base 10) counters. And Table 5-1, section D gives the counter addresses
from 0034 for OVCTR through 0056 for TRKR R, which translates to 19 (base 10) counters.
So, its unclear whether AGC4 had 19, 20, or 23 counters and whether the counter addresses
start at 0030 or 0034.
To resolve the ambiguity, I set the starting address for the counters to 34 (octal), which is
the starting address used in the Block II AGC (COLOSSUS program listing). For convenience,
I only implemented counters that were used by the AGC EXEC and WAITLIST, the real-time
clock, and the overflow (5 in all). These are:
address counter
34 OVCTR
35 TIME2
36 TIME1
37 TIME3
40 TIME4
I also used the Block II ordering of TIME1 and TIME2, for compatibility with the COLOSSUS
flight software. In the AGC4, TIME1 is at the lower address.
Address of Interrupt Vectors and GOPROGIn the Block II AGC, GOPROG (the starting address for execution) is at the bottom of fixed
memory at address 4000, and the interrupt vectors follow at 4004, 4010, 4014, etc. By
extension, it would seem that the Block I AGC GOPROG would be at the bottom of fixed
memory at 2000, followed by interrupt vectors at 2004, 2010, 2014, etc. However, R-393
has the interrupt vectors starting at the bottom of fixed memory at 2000 (according to the
RUPT3 sequence on pages 3-67/3-68). R-393 doesn’t identify the address for the Block I
GOPROG.
For compatibility with the COLOSSUS source code (which I translated and cross-assembled
for Block I), I set GOPROG to 2000, with the interrupt vectors beginning at 2004.
Number of InterruptsThe original AGC had 5 vectored interrupts: UPRUPT, ERUPT, KEYRUPT, T3RUPT, and
DSRUPT. UPRUPT was used for uplinked commands; ERUPT was generated when hardware
errors were detected. Since I didn’t plan to use these interrupts, I eliminated the hardware
that supports them from my replica.
My replica implements the remaining 3 interrupts: KEYRUPT, T3RUPT, and DSRUPT
(T4RUPT).
Priority Counter sequencesThe original AGC4 implemented 3 sequences: PINC, MINC, and SHINC. PINC increments
counter locations in memory; MINC decrements them. SHINC implements a shift operation
used to shift telemetry bits into the AGC. After 16 bits were shifted into an AGC word, an
interrupt UPRUPT was triggered, so the AGC could pull the telemetry word out of the
counter.
Since I’m not receiving telemetry, I didn’t implement the SHINC subsequence or the UPRUPT
interrupt.
MemoryAGC memory is 16-bit words, organized into 1024 word banks. The lowest bank (bank 0) is
erasable memory, originally core, but implemented in my replica as static RAM. All banks
above bank 0 are fixed memory (originally implemented as rope core, but implemented in
my replica as EPROM). AGC4 initially had 12K words of fixed memory. My replica has 15K.
BusesThe original AGC OR’ed everything onto the bus, and the default bus state was logical zero:
Registers were sometimes cleared by reading the default state off the bus. Other times,
several registers were simultaneously read to OR the data. Because these tricks won’t work
well w ith tri-state bus drivers, I identified these instances and added logic to the ALU to
handle them.
Flight SoftwareThe original Block I flight software is not available (at least, to me). The Block II software
(COLOSSUS 249) is available. Block II is an extension of the Block I instruction set.
However, most of the Block II software was originally coded as Block I, so translating the
Block II code back to Block I only involves changing about 5% of the instructions back to
their Block I equivalents. This is what I did.
Back in 2002, only a portion of the COLOSSUS Block II code was available. Some key
portions, such as the EXEC and WAITLIST, were missing. I coded these parts in, using
information from the M.I.T. documents and the interfaces and functional requirements
implied by their use in the portions of COLOSSUS that were available.
Sources
Many of these sources are now (2004) available (free!) online at
http://hrst.mit.edu/hrs/apollo/public/
R. Alonso, J. H. Laning, Jr. and H. Blair-Smith, "Preliminary MOD 3C Programmer's Manual",
E-1077, MIT Instrumentation Laboratory, Cambridge, MA, Nov. 1961.
Useful information on AGC4's predecessor: AGC3. AGC3 had fewer instructions (8 vs.
11) and a shorter instruction cycle (8 vs 12 timing pulses). It is primarily helpful for
its presentation of AGC Block I programming techniques and examples.
A. I. Green and J. J. Rocchio, "Keyboard and Display System Program for AGC (Program
Sunrise)", E-1574, MIT Instrumentation Laboratory, Cambridge, MA, Aug. 1964.
Flowcharts for DSKY software; no source code. Gives input codes for the DSKY
keyboard and the output codes for display characters and registers.
E. C. Hall, "Journey to the Moon: The History of the Apollo Guidance Computer", AIAA,
Reston VA, 1996.
Nice information on the AGC development history with photos; R-700 (also by E.C.
Hall) is a better technical summary.
E. C. Hall, "MIT's Role in Project Apollo, Volume III, Computer Subsystem", R-700, MIT
Charles Stark Draper Laboratory, Cambridge, MA, Aug. 1972.
An excellent overview of the AGC; more technical than Hall's "Journey to the Moon"
book. It contains an excellent diagram of the Block II register architecture and a nice
diagram of a bit-slice of the register/bus logic. My copy from NTIS is somewhat poor
quality. There is also a useful discussion of the AGC test and checkout software.
A. Hopkins, "Guidance Computer Design, Part VI"
Extracted from some (unknown) larger document. An excellent overview of the Block
II AGC with emphasis on the I/O circuits. A very useful discussion of number
representation and overflow handling in the AGC, which is unconventional.
A. Hopkins, R. Alonso, and H. Blair-Smith, "Logical Description for the Apollo Guidance
Computer (AGC4)", R-393, MIT Instrumentation Laboratory, Cambridge, MA, Mar. 1963.
My primary source. It has a nearly complete specification of the AGC4 (Block I)
instruction set, register transfers, and control pulses. Information on the logic design
is largely absent, however. There are some internal inconsistencies and gaps in the
definition of the control logic: particularly at TP12, in the memory cycle, and at the
intersection of the control logic with the interrupts and involuntary counters.
Unfortunately, there are few diagrams; its mostly text and tables. There are also
some examples of double-precision math routines.
B. I. Savage and A. Drake, "AGC4 Basic Train ing Manual, Volume I", E-2052, MIT
Instrumentation Laboratory, Cambridge, MA, Jan. 1967.
The software manual for the Block II AGC. It has a fairly complete presentation of the
instruction set, but lacks example code.
Now, what?
There’s 8 more parts to this report. Download and read the parts you’re interested in.
Perhaps you want to build your own AGC. You can use my software and logic designs, or
develop your own. There’s lots of room for improvement in my work. You could use it as
your starting point.
If you like, you can contact me at: [email protected]
Block IApollo Guidance Computer (AGC)
How to build one in your basement
Part 2: Control (CTL) Module
John Pultorak
December, 2004
Abstract
This report describes my successful project to build a working reproduction of the 1964
prototype for the Block I Apollo Guidance Computer. The AGC is the flight computer for the
Apollo moon landings, and is the world’s first integrated circuit computer.
I built it in my basement. It took me 4 years.
If you like, you can build one too. It will take you less time, and yours will be better than
mine.
I documented my project in 9 separate .pdf files:
Part 1 Overview: Introduces the project.
Part 2 CTL Module: Design and construction of the control module.
Part 3 PROC Module: Design and construction of the processing (CPU) module.
Part 4 MEM Module: Design and construction of the memory module.
Part 5 IO Module: Design and construction of the display/keyboard (DSKY) module.
Part 6 Assembler: A cross-assembler for AGC software development.
Part 7 C++ Simulator: A low-level simulator that runs assembled AGC code.
Part 8 Flight Software: My translation of portions of the COLOSSUS 249 flight
software.
Part 9 Test & Checkout: A suite of test programs in AGC assembly language.
Overview
The Control Module (CTL) has 9 subsystems: CMI, MON, CLK, SCL, TPG, SEQ, CPM-A,
CPM-B, CPM-C
CMI (Control Module external
Interface)
The CMI interfaces the other control
module subsystems (described below)
to external AGC modules. 40-pin IDE
connectors interface to the PROC,
MEM, and IO modules. Inputs from
those modules are buffered to 1 LSTTL
load.
MON (AGC Monitor)
The monitor subsystem has the
front-panel switches that control AGC
operation, and also implements the
power-up reset circuit.
CLK (Clock)
The AGC is controlled by a 2.048 MHz
crystal clock. The clock is divided to
produce a 2-phase, non-overlapping
1.024 MHz AGC system clock for
nominal operation. For test purposes,
a low-frequency RC clock can also be
selected, or the clock can be
single-stepped.
SCL (Scaler)
The 1.024 MHz AGC clock is divided by
two to produce a 512 kHz signal called
the MASTER FREQUENCY; this signal
is further divided through a SCALER,
first by five to produce a 102.4 kHz
signal. This is then divided by two
through 17 successive stages called F1
(51.2 kHz) through F17 (0.78125 Hz).
The F10 stage (100 Hz) is fed back into the AGC to increment the real-time clock and other
priority counters in the PROC module. The F17 stage is used to intermittently run the AGC
when it operates in the STANDBY mode.
TPG (Time Pulse Generator)
AGC instructions are implemented in groups of 12 steps, called timing pulses. The timing
pulses, named TP1 through TP12, are produced by the Time Pulse Generator (TPG). Each set
of 12 timing pulses is called an instruction subsequence. Simple instructions, such as TC,
execute in a single subsequence of 12 pulses. More complex instructions require several
subsequences.
SEQ (Sequence Generator)
The sequence generator has the SQ register, which holds the next op-code, and the CTR
register--a counter used to count instruction subsequences during multiplication. The
sequence generator also has the branch register (BR) which controls conditional processing
during instruction execution, and the STAGE registers (STA and STB) which select the
instruction subsequences for complex instructions that have more than one subsequence.
CPM-A (Control
Pulse Matrix A)
The CPM-A is the
combinational logic
matrix that
implements most
of the control logic.
It is driven by
inputs from the SQ
register (which
selects the
instruction), the
STB stage register
(which selects the
instruction
subsequence), and
the BR branch
register (which
selects conditional
steps in a
subsequence).
CPM-B (Control
Pulse Matrix B)
The CPM-B
decodes read and
write control
signals for special
memory location associated with input/output registers, central registers (A, Q, Z, and LP),
and the editing registers used for rotation and shifting.
CPM-C (Control Pulse Matrix C)
The CPM-C decodes control signals primarily associated with interrupts, the memory cycle,
and the selection of new instructions and instruction subsequences.
This is a functional diagram showing the interrelationships between the Time Pulse
Generator (TPG), the Control Pulse Matrix (CPM-A, B, and C), and the registers that are in
the Sequence
Generator (SEQ).
The diagram is
mine, but the style
is borrowed from
original AGC
documentation:
control signals are
represented by
diamonds. The
arrows show the
direction of data
flow. When a control
signal is asserted,
data is allowed to
flow through the
diamond. For
example, when WSQ
is asserted, the
opcode is written
from the Read/Write
bus into the SQ
register.
Registers (LOOPCTR, STA, STB, SQ, BR, and SNI) are represented by rectangles. The lower
bit of the 2-bit STA register is set by ST1. The upper bit is set by any one of the 3 control
signals flowing into it. The STA register is cleared by CLRSTA.
When WSTB is asserted, the STA register is copied to STB. STB and the SQ register select
the instruction subsequence.
The instruction subsequence, time pulse generator, BR register, and SNI all feed into the
Control Pulse Matrix to select the active control pulses.
The diagram was developed by analyzing the R-393 document. It was one of my first
diagrams; a sort-of conceptual breakthrough that became my gateway for understanding
the AGC control module.
The instruction
subsequences
executed by the
AGC are shown
in this diagram.
Each yellow
circle is a
subsequence; a
set of 12 steps,
with each step
generating 0-5
control pulses.
Eleven steps
(TP1-TP11) are
in the yellow
circle; the 12th
step, which
selects the next
subsequence
(TP12), is in the
orange circle.
This is discussed
in more detail in
the TPG, SEQ,
and CPM-A
subsystems.
A late addition to the CTL design fixed a problem with the read bus logic. Due to
propagation delays (and some poor design on my part), the tri-state buffers from multiple
registers were simultaneously enabled for brief periods causing some transients. I “kludged”
in a design change that suppressed output to the read bus during CLK1, thereby giving the
bus control logic time to settle.
CTL Internal Subsystem Interconnections
This diagram shows internal interconnections for the subsystems in the CTL module.
CTL Module External Interfaces
The CTL module interfaces to the PROC, MEM, and IO modules through 40-pin IDE ribbon
cables.
J100-CTL: CTL-to-PROC I/F
J100 is a 40-pin IDE ribbon cable that connects the CTL module to the PROC module.
OUTPUTS (from CTL):
PIN signal full name state definition
1 WA3 WRITE ADDR 3 (74) 0=Write reg at address 3 (LP)
2 WA2 WRITE ADDR 2 (73) 0=Write reg at address 2 (Z)
3 WA1 WRITE ADDR 1 (72) 0=Write reg at address 1 (Q)
4 WA0 WRITE ADDR 0 (71) 0=Write reg at address 0 (A)
5 RA3 READ ADDR 3 (60) 0=Read reg at address 3 (LP)
6 RA2 READ ADDR 2 (59) 0=Read reg at address 2 (Z)
7 RA1 READ ADDR 1 (58) 0=Read reg at address 1 (Q)
8 RA0 READ ADDR 0 (57) 0=Read reg at address 0 (A)
9 WZ WRITE Z (50) 0=Write Z
10 WYx WRITE Y NO RESET (49) 0=Write Y (do not reset)
11 WY WRITE Y (48) 0=Write Y
12 WX WRITE X (47) 0=Write X
13 WQ WRITE Q (45) 0=Write Q
14 WOVR WRITE OVF (41) 0=Write overflow
15 WOVI WRITE OVF RUPT INH (40) 0=Write overflow RUPT inh ibit
16 WOVC WRITE OVF CNTR (39) 0=Write overflow counter
17 WLP WRITE LP (38) 0=Write LP
18 WB WRITE B (36) 0=Write B
19 WALP WRITE A/LP (35) 0=Write A and LP
20 WA WRITE A (34) 0=Write A
21 F10X F10 SCALER ONESHOT 1=timed out (100.0 Hz)
23 R24 READ 24 (25) 0=Read 24
24 R22 READ 22 (24) 0=Read 22
25 R2 READ 2 (23) 0=Read 2
26 R1C READ 1 COMP (22) 0=Read 1 complimented
27 R1 READ 1 (21) 0=Read 1
28 RZ READ Z (20) 0=Read Z
29 RU READ U (19) 0=Read sum
30 RSCT READ CNTR ADDR (18) 0=Read selected counter address
31 RSB READ SIGN (17) 0=Read sign bit
32 RRPA READ RUPT ADDR (16) 0=Read RUPT address
33 RQ READ Q (15) 0=Read Q
34 RLP READ LP (13) 0=Read LP
35 RC READ C (11) 0=Read C
36 RB14 READ BIT 14 (10) 0=Read bit 14
37 RB READ B (9) 0=Read B
38 RA READ A (8) 0=Read A
39 KRPT KNOCK DOWN RUPT (6) 0=Knock down Rupt priority
40 CI SET CARRY IN (1) 0=Carry in
J101-CTL: CTL-to-PROC I/F
J101 is a 40-pin IDE ribbon cable that connects the CTL module to the PROC module.
INPUTS (to CTL):
PIN signal full name state definition
21 SB_01 SUB SEL 01 SB_01 is LSB; SB_02 is MSB
22 SB_02 SUB SEL 02 00=no counter; 01=PINC; 10=MINC
23 IRQ INT RQST 0=interrupt requested.
25 WB_01 WRITE BUS 01 (lsb)
26 WB_02 WRITE BUS 02
27 WB_03 WRITE BUS 03
28 WB_04 WRITE BUS 04
29 WB_05 WRITE BUS 05
30 WB_06 WRITE BUS 06
31 WB_07 WRITE BUS 07
32 WB_08 WRITE BUS 08
33 WB_09 WRITE BUS 09
34 WB_10 WRITE BUS 10
35 WB_11 WRITE BUS 11
36 WB_12 WRITE BUS 12
37 WB_13 WRITE BUS 13
38 WB_14 WRITE BUS 14
39 WB_15 WRITE BUS 15 US (overflow) bit
40 WB_16 WRITE BUS 16 SG (sign) bit
OUTPUTS (from CTL):
PIN signal full name state definition
1 R2000 READ 2000 (101) 0=Read 2000
2 WPCTR WRITE PCTR (98) 0=Write PCTR (latch priority counter
sequence)
3 RPT READ RUPT (94) 0=Read RUPT opcode
4 INH SET INHINT (93) 0=Set INHINT
5 CLRP CLEAR RPCELL (92) 0=Clear RPCELL
6 CLINH1 CLEAR INHINT1 (88) 0=Clear INHINT1
7 CLINH CLEAR INHINT (87) 0=Clear INHINT
8 GENRST GENERAL RESET (86) 0=General Reset
19 CLK1 CLOCK1 1.024 MHz AGC clock 1 (normally low)
20 CLK2 CLOCK2 1.024 MHz AGC clock 2 (normally low)
J102-CTL: CTL-to-MEM I/F
J102 is a 40-pin IDE ribbon cable that connects the CTL module to the MEM module.
INPUTS (to CTL):
PIN signal full name state definition
31 EQU_16 ADDRESS = 016 (1) 0=CADR in register S = 016
32 EQU_17 ADDRESS = 017 (2) 0=CADR in register S = 017
33 GTR_17 ADDRESS > 017 (3) 0=CADR in register S > 017
34 EQU_25 ADDRESS = 025 (4) 0=CADR in register S = 025
35 GTR_27 ADDRESS > 027 (5) 0=CADR in register S > 027
36 GTR_1777 ADDRESS > 01777 (6) 0=CADR in register S > 01777
37 AD_1 ADDRESS (1) where AD_4 is MSB, AD_1 is LSB:
38 AD_2 ADDRESS (2) (low-order bits of address)
38 AD_3 ADDRESS (3)
40 AD_4 ADDRESS (4)
OUTPUTS (from CTL):
PIN signal full name state definition
1 WE WRITE EMEM (97) 0=Write E-MEM from G
2 SBWG WRITE G (95) 0=Write G from memory
3 GENRST GENERAL RESET (86) 0=General Reset
4 W23 WRITE ADDR 23 (85) 0=Write into SL
5 W22 WRITE ADDR 22 (84) 0=Write into CYL
6 W21 WRITE ADDR 21 (83) 0=Write into SR
7 W20 WRITE ADDR 20 (82) 0=Write into CYR
8 WGn WRITE G NORMAL (81) 0=Write G (normal gates)
9 WBK WRITE BNK (80) 0=Write BNK reg
10 RBK READ BNK (70) 0=Read BNK reg
11 WS WRITE S (46) 0=Write S
12 WP2 WRITE P2 (44) 0=Write P2
13 WPx WRITE P NO RESET (43) 0=Write P (do not reset)
14 WP WRITE P (42) 0=Write P
15 WGx WRITE G NO RESET (37) 0=Write G (do not reset)
16 TP TEST PARITY (30) 0=Test parity
17 RP2 READ PARITY 2 (14) 0=Read parity 2
18 RG READ G (12) 0=Read G
19 GP GEN PARITY (5) 0=Generate Parity
20 CLG CLR G (2) 0=Clear G
21 CLK2 CLOCK2 1.024 MHz AGC clock 2 (normally low)
22 CLK1 CLOCK1 1.024 MHz AGC clock 1 (normally low)
23 NPURST POWER UP RESET 0=reset, 1=normal operation.
24 SWCLK DEBOUNCE CLOCK low freq clk for switch debounce
25 FCLK CLOCK MODE 1=free-running clk mode; 0=single clk
mode
J103-CTL: CTL-to-I/O I/F
J100 is a 40-pin IDE ribbon cable that connects the CTL module to the I/O module.
INPUTS (to CTL):
PIN signal full name state definition
40 OUT1_8 STANDBY ENABLED 1=standby enabled; works with STANDBY
ALLOWED switch
OUTPUTS (from CTL):
PIN signal full name state definition
1 CLK1 CLOCK1 1.024 MHz AGC clock 1 (normally low)
2 CLK2 CLOCK2 1.024 MHz AGC clock 2 (normally low)
3 NSA STANDBY ALLOWED 0=standby allowed
5 GENRST GENERAL RESET (86) 0=clear the DSKY, OUT1, and OUT2.
6 WA11 WRITE OUT1 (76) 0=write into OUT1 from write bus
7 WA10 WRITE OUT0 (75) 0=write into OUT0 (DSKY) from write bus
8 RA11 READ OUT1 (66) 0=output OUT1 register to read bus
9 RA4 READ IN0 (61) 0=output IN0 register to read bus
20 STBY STANDBY 0=AGC is in the standby state
MON (AGC Monitor)
MON INPUTS:
I/F signal full name state definition
SW-RUN RUN/STEP SELECT SW
NSW-RUN
SW-INS STEP MODE SW
NSW-INS
SW-FCL CLOCK MODE SW
NSW-FCL
SW-SA STANDBY ALLOWED SW
NSW-SA
SW-STP INST STEP SW
NSW-STP
SW-MCL CLOCK STEP SW
NSW-MCL
SW-RST MASTER RESET SW
MON OUTPUTS:
signal full name state definition
NRUN RUN/HALT 0=run, 1=step
INST INST STEP MODE 1=instruction step, 0=sequence step
NSTEP SINGLE STEP 0=step (momentary)
NSA STANDBY ALLOWED 0=standby allowed
MCLK CLOCK STEP 1=step (momentary); triggers a single
clock pulse. Ignored if FCLK is 1.
FCLK CLOCK MODE 1=continuous clock output at 1.024 MHz,
0=single clock
NPURST POWER UP RESET 0=reset, 1=normal operation.
SENAB SCALER ENABLE 1=enable counting; 0=hold
CTL CONTROL PANEL SWITCHES
Clock Control:
RATE Controls the slow clock rate when the 1MHZ/SLOW switch is in the SLOW
position.
1MHZ/SLOW Selects the free-running clock rate when the RUN/STEP switch is in the RUN
position. The 1MHZ position gates a 2MHz signal into the 2-phased clock
which produces a 1MHz 2-phased clock rate. The SLOW position gates a low
frequency clock; the frequency is controlled by RATE.
RUN/STEP Selects a free-running (RUN) or a single-stepped (STEP) clock. In the RUN
position, the rate is controlled by the 1MHZ/SLOW switch. In the STEP
position, the clock steps each time the STEP button is depressed.
STEP Manually steps the clock when the RUN/STEP switch is in the STEP position.
The clock is 2-phased, so each press steps an alternate phase.
Scaler:
ENAB/DISAB Enables or disables the SCALER.
F10 Manually triggers the F10 stage of the SCALER.
F13 Manually triggers the F13 stage of the SCALER.
F17 Manually triggers the F17 stage of the SCALER.
Execution Control:
RUN/STEP In the RUN position, the AGC free-runs at a rate determined by the clock
controls. In the STEP position, the AGC single-steps to the next instruction or
next sequence when the STEP button is depressed; the rate is determined by
the clock controls.
INST/SEQ Selects whether the AGC single-steps all the way to the next instruction
(INST) or just to the next sequence (SEQ). Some instructions, such as TC,
have a single sequence; on these instructions, the switch has the same effect
in either position.
STEP Single-steps the AGC when the RUN/STEP switch is in the STEP position.
RESET Reset the entire AGC. Puts the TPG into the standby state.
Standby:
ALLOW/DISA The ALLOWED position authorizes the AGC software to put the AGC in standby
mode. The AGC is released from standby mode by a signal from F17 in the
SCALER. If the scaler switch is in the DISAB position, the scaler is disabled,
and the AGC will remain in the standby state. When the standby switch is in
the DISAB position, the standby mode is inhibited.
Normal Operation:
Set the following switch positions for nominal operation:
switch position
1MHZ/SLOW 1MHZ
RUN/STEP RUN (clock control)
ENAB/DISAB ENAB (scaler)
RUN/STEP RUN (execution control)
ALLOW/DISA ALLOWED (standby)
CTL CONTROL SWITCH CONNECTIONS
PIN signal state definition
1 BUS#10, line 1 Execution control: RUN/STEP
2 BUS#10, line 2
3 BUS#10, line 3 Execution control: INST/SEQ
4 BUS#10, line 4
5 BUS#10, line 5 Clock control: RUN/STEP
6 BUS#10, line 6
7 BUS#10, line 7 STANDBY ALLOWED/DISABLED
8 BUS#10, line 8
9 BUS#10, line 9 Execution control: STEP
10 BUS#10, line 10
11 BUS#10, line 11 Clock control: STEP
12 BUS#10, line 12
13 BUS#10, line 13 RESET
14 BUS#10, line 14 SCALER DISAB
15 RATE (SLOW) CLOCK CONTROL RATE
16 1MHZ Clock control: 1MHZ/SLOW
17 SLOW
18 F10 MANUAL TRIGGER F10
19 F13 MANUAL TRIGGER F13
20 F17 MANUAL TRIGGER F17
CTL INDICATORS
The CTL module has a panel of indicator lamps (LEDs) to show the state of CTL registers and
critical logic signals.
These indicator
lamps show the
current state of all
registers and some
additional,
important logic
signals produced by
the CTL module.
The matrix of lamps
in the lower portion
show active
subsequences. Much
of the control logic
is negative (active
low) where an
illuminated lamp
means that the
signal is NOT
asserted. At the
time the photo was
taken the AGC was
running
the COLOSSUS 249
flight software load, executing Verb 16, Noun 36: a monitor verb which displays the AGC
real time clock.
CLK (Clock)
The original AGC used asynchronous logic driven by a 4-phase clock. This recreation uses
synchronous logic driven by a 2-phase non-
overlapping clock. The synchronous clock logic
was designed to produce the follow ing state
transitions:
FFA FFB
0 0 idle state
0 1 decoded for phase 1
1 1
1 0 decoded for phase 2
The outputs of FFA and FFB are decoded by
combinational logic to produce the non-
overlapping phase 1 and phase 2 clock signals.
The sequence is arranged so there is a single
logic level transition for each state transition to
prevent transients.
CLK INPUTS:
I/F signal full name state definition
MON:
MCLK CLOCK STEP 1=step (momentary); triggers a single
clock pulse. Ignored if FCLK is 1.
FCLK CLOCK MODE 1=continuous clock output at 1.024 MHz,
0=single clock whenever MCLK is 1.
NPURST POWER UP RESET 0=power up reset
OUTPUTS:
signal full name state definition
CLK1 CLOCK1 1.024 MHz AGC clock 1 (normally low)
CLK2 CLOCK2 1.024 MHz AGC clock 2 (normally low)
SCL (Scaler)
The 1.024 MHz AGC clock is
divided by two to produce a
512 kHz signal called the
MASTER FREQUENCY; this
signal is further divided
through a SCALER, first by
five to produce a 102.4 kHz
signal. This is then divided
by two through 17
successive stages called F1
(51.2 kHz) through F17
(0.78125 Hz). The F10 stage
(100 Hz) is fed back into the
AGC to increment the
real-time clock and other
priority counters in the PROC
module. The F17 stage is
used to intermittently run
the AGC when it operates in
the STANDBY mode.
The F10, F13, and F17
outputs of the SCALER feed
into a synchronous one-shot
that produces a short output
pulse on the rising edge of
the input.
SCALER (SCL) ONE-SHOT LOGIC DESIGN
Boolean operators:
* (AND), + (OR), ' (NOT)
Scaler Divide-by-10 Excitation Table:
The divide-by-10 state machine is implemented with a 74161 parallel counter. Control Mode
for 74161 Parallel Counter:
NPE CET
0 x LOAD
1 1 COUNT
1 0 HOLD
Current Next Par In
State D C B A D C B A NPE CET D C B A
0 0 0 0 0 0 0 0 1 1 1
1 0 0 0 1 0 0 1 0 1 1
2 0 0 1 0 0 0 1 1 1 1
3 0 0 1 1 0 1 0 0 1 1
4 0 1 0 0 0 1 0 1 1 1
5 0 1 0 1 0 1 1 0 1 1
6 0 1 1 0 0 1 1 1 1 1
7 0 1 1 1 1 0 0 0 1 1
8 1 0 0 0 1 0 0 1 1 1
9 1 0 0 1 0 0 0 0 0 x 0 0 0 0
NPE = (D * A)'
CET = 1
One-shot Excitation Table:
The one-shot state machine is implemented with two J-K FFs.
JK flip-flop excitation table:
J K
0 0 Qn-1 (no change)
0 1 0
1 0 1
1 1 Qn-1' (toggle)
FN is the one-shot trigger; Q(A) is the one-shot output.
Cur Inp Nxt ffB ffA
State B A FN B A J K J K
IDLE 0 0 0 0 0 0 x 0 x
0 0 1 0 1 0 x 1 x
HIGH 0 1 0 1 0 1 x x 1
0 1 1 1 0 1 x x 1
LOW 1 0 0 0 0 x 1 0 x
1 0 1 1 0 x 0 0 x
UNUSED 1 1 0 x x x x x x
1 1 1 x x x x x x
The excitation table and logic equations were derived from the CLK subsystem state
machine which also performs a one-shot function. The CLK subsystems's FCLK signal was
factored out by setting it to zero. The MCLK input is the one-shot trigger; it was renamed
FN.
ff(B) J = QA
ff(B) K = FN'
ff(A) J = QB' * FN
ff(A) K = QA
SCL INPUTS:
I/F signal full name state definition
CLK:
CLK1 CLOCK1 1.024 MHz AGC clock
MON:
SW-SEN SCALER ENABLE 1=enable counting;
0=hold
NPURST POWER UP RESET 0=power up reset
SCL OUTPUTS:signal full name state definition
F10X F10 SCALER ONESHOT 1=timed out (100.0 Hz)
F13X F13 SCALER ONESHOT 1=timed out ( 12.5 Hz)
F17X F17 SCALER ONESHOT 1=timed out ( 0.78125
Hz)
F1 SCALER OUT F1 51.2 KHz square wave
F2 SCALER OUT F2 25.6 KHz square wave
F3 SCALER OUT F3 12.8 KHz square wave
F4 SCALER OUT F4 6,4 KHz square wave
F5 SCALER OUT F5 3.2 KHz square wave
F6 SCALER OUT F6 1.6 KHz square wave
F7 SCALER OUT F7 0.8 KHz square wave
F8 SCALER OUT F8 0.4 KHz square wave
F9 SCALER OUT F9 0.2 KHz square wave
F10 SCALER OUT F10 0.1 KHz square wave (100 Hz)
F11 SCALER OUT F11 50.0 Hz square wave
F12 SCALER OUT F12 25.0 Hz square wave
F13 SCALER OUT F13 12.5 Hz square wave
F14 SCALER OUT F14 6.25 Hz square wave
F15 SCALER OUT F15 3.125 Hz square wave
F16 SCALER OUT F16 1.5625 Hz square wave
F17 SCALER OUT F17 0.78125 Hz square wave
Note: One shot outputs are active for one clock pulse.
State transitions occur on the rising edge of CLK1
TPG (Time Pulse Generator)
TIME PULSE GENERATOR (TPG) LOGIC DESIGN
Boolean operators:
* (AND), + (OR), ' (NOT)
TPG Internal Control Signals:
These are local to the TPG; if the signal is asserte
d, TPG makes a state transition. These decoded
signals are the inputs to the excitation table.
TPG_0 = PURST' * ( FCLK' + F17X )
TPG_1 = FCLK' + F13X
TPG_2 = RUN + (SNI' * INST)
TPG_3 = SNI * OUT1_8 * SA
TPG_4 = STEP'
TPG_5 = STEP + RUN
TPG Excitation Table:
Control Mode for 74161 Parallel Counter:
NPE CET
0 x LOAD
1 1 COUNT
1 0 HOLD
*denotes active low
Current *Current TPG_x Next Par In
State D C B A Decoder 0 1 2 3 4 5 D C B A *NPE CET D C B A
STBY 0 0 0 0 NSTBY 0 x x x x x 0 0 0 0 1 0
1 x x x x x 0 0 0 1 1 1
PWRON0 0 0 1 NPWRON x 0 x x x x 0 0 0 1 1 0
x 1 x x x x 0 0 1 0 1 1
TP1 0 0 1 0 NTP1 x x x x x x 0 0 1 1 1 1
TP2 0 0 1 1 NTP2 x x x x x x 0 1 0 0 1 1
TP3 0 1 0 0 NTP3 x x x x x x 0 1 0 1 1 1
TP4 0 1 0 1 NTP4 x x x x x x 0 1 1 0 1 1
TP5 0 1 1 0 NTP5 x x x x x x 0 1 1 1 1 1
TP6 0 1 1 1 NTP6 x x x x x x 1 0 0 0 1 1
TP7 1 0 0 0 NTP7 x x x x x x 1 0 0 1 1 1
TP8 1 0 0 1 NTP8 x x x x x x 1 0 1 0 1 1
TP9 1 0 1 0 NTP9 x x x x x x 1 0 1 1 1 1
TP10 1 0 1 1 NTP10 x x x x x x 1 1 0 0 1 1
TP11 1 1 0 0 NTP11 x x x x x x 1 1 0 1 1 1
TP12 1 1 0 1 NTP12 x x x 1 x x 0 0 0 0 0 x 0 0 0 0
x x 1 0 x x 0 0 1 0 0 x 0 0 1 0
x x 0 0 x x 1 1 1 0 1 1
SRLSE 1 1 1 0 NSRLSE x x x x 0 x 1 1 1 0 1 0
x x x x 1 x 1 1 1 1 1 1
WAIT 1 1 1 1 NWAIT x x x x x 1 0 0 1 0 0 x 0 0 1 0
x x x x x 0 1 1 1 1 1 0
Maxterms:
NPE = (NTP12 + TPG_3') * (NTP12 + TPG_2' + TPG_3) * (NWAIT + TPG_5')
CET = (NSTBY + TPG_0) * (NPWRON + TPG_1) * (NSRLSE + TPG_4) * (NWAIT + TPG_5)
Par In A,B,C = 0
Par In B = (NTP12' * TPG_3)'
TPG INPUTS:
I/F signal full name state definition
MON:
NRUN RUN/HALT 0=run, 1=step
INST INST STEP MODE 1=instruction step,
0=sequence step
NSTEP SINGLE STEP 0=step (momentary)
FCLK CLOCK MODE 1=continuous, 0=single
clock
NSA STANDBY ALLOWED 0=standby allowed
NPURST POWER UP RESET 0=power up reset
CLK:
CLK1 CLOCK1 1024 MHz AGC clock 1
SEQ:
SNI SELECT NEXT INST 1=select next instruction
SCL:
F17X F17 SCALER ONESHOT 1=timed out
F13X F13 SCALER ONESHOT 1=timed out
OUT:
OUT1_8 STANDBY ENABLED 1=standby enabled; works with STANDBY
ALLOWED switch
TPG OUTPUTS:
signal full name state definition
TPG_Q3 TPG STATE where Q0 is LSB, Q3 is MSB:
TPG_Q2 00 = STBY
TPG_Q1 01 = PWRON
TPG_Q0 02 = TP1
03 = TP2
04 = TP3
05 = TP4
06 = TP5
07 = TP6
08 = TP7
09 = TP8
10 = TP9
11 = TP10
12 = TP11
13 = TP12
14 = SRLSE
15 = WAIT
SEQ (Sequence Generator)
The sequence generator contains the stage registers and branch registers that (along with
the time pulse generator) control execution of the microinstruction sequence.
Some back-of-the-envelope design that went into the branch
register logic is shown in the next few charts. This is the
conceptual design for the branch register. It has 2 flip-flops
named BR2 and BR1. The flip-flops are set by the control signals
shown as diamonds in this diagram.
The J and K
inputs to the BR1
flip-flop are
developed in this
chart.
This chart shows
the J and K inputs
to the BR2 flip-flop.
Logic to sense a 1's
compliment minus
zero from the write
bus is also
developed.
Here are some charts showing the stage
register design. This is the conceptual
design. There are (2) 2-bit stage registers:
STA and STB.
This is my initial cut at STA and STB. My initial attempt at CLSTB is scratched out and then
developed into the correct solution on the later charts.
This is the J input to the STA2 flip-
flop. The initial design is at the
top. In the middle, I
“DeMorganize” it using some
bubble-pushing to get the final
implementation at the bottom.
Here’s the J and K inputs to
STB1 and STB2. This is the
logic that transfers the
contents of the STA flip-
flops to STB.
The J and K inputs to STB1 and STB2 move through a multi-step DeMorganizing process in
the next 2 charts to reach their final state:
SEQ INPUTS:
I/F signal full name state definition
CLK:
CLK2 CLOCK 2 data transfer occurs on falling edge
CPM-C:
GENRST GENERAL RESET 0=General Reset
WSQ WRITE SQ 0=Write SQ
CLISQ CLEAR SNI 0=Clear SNI
CLSTA CLEAR STA 0=Clear state counter A
(STA)
WSTB WRITE STB 0=Write stage counter B
(STB)
CLSTB CLEAR STB 0=Clear state counter B
(STB)
SETSTB SET ST1 0=Set the ST1 bit of STB
CPM-A:
TRSM TEST RESUME 0=Test for resume
TSGN TEST SIGN 0=Test sign
TSGN2 TEST SIGN 2 0=Test sign 2
ST1 SET STAGE 1 0=Stage 1
ST2 SET STAGE 2 0=Stage 2
CLCTR CLR LOOP CTR 0=Clear loop counter
CTR INCR LOOP CTR 0=Loop counter
TMZ TEST MINUS ZERO 0=Test for minus zero
TOV TEST OVF 0=Test for overflow
NISQ NEW INSTRUCT 0=New instruction to the
SQ reg
WBUS:
WB_01 WRITE BUS 01
... ...
WB_14 WRITE BUS 14
WB_15 WRITE BUS 15 US (overflow) bit for write bus
WB_16 WRITE BUS 16 SG (sign) bit for write bus
ADR:
EQU_25 ADDRESS = 025 0=CADR in register S evaluates to = 025
SEQ OUTPUTS:
I/F signal full name state definition
CPM-A:
BR1 BRANCH REG 1 where BR1 is MSB, BR2 is LSB
BR2 BRANCH REG 2 BR00 =0 BR1=0, BR2=0
BR01 =1 BR1=0, BR2=1
BR10 =2 BR1=1, BR2=0
BR11 =3 BR1=1, BR2=1
SQ_3 INST REG where SQ_3 is MSB, SQ_0 is LSB
SQ_2
SQ_1
SQ_0
STB_1 STAGE REG where STB_1 is MSB, STB_0 is LSB
STB_0
LOOP6 LOOPCNTR EQ 6 0=LOOPCNTR is holding the number 6.
SNI SELECT NEXT INST 1=select next instruction (SNI register)
CPM-A (Control Pulse Matrix A)
In this AGC replica, the CPM-A subsequences are implemented in EPROM (they were
implemented as a diode matrix in the original). The address into the EPROM is constructed
as follows (bit 1 is the LSB):
bit
13,14 CTR subsequence (2)
9-12: register SQ (4)
7,8: register STB (2)
3-6: register SG (4)
2: register BR1 (1)
1: register BR2 (1)
Bits 7-14 (STB, SQ, and CTR) select the instruction subsequence. Bits 1-6 select the control
pulses (control logic signals) that are asserted from that subsequence.
SELECTING THE INSTRUCTION SUBSEQUENCE
The 11 AGC instructions, priority counter operations, and interrupt operations are
implemented in 22 instruction subsequences. Some instructions (TC) have a single
subsequence; others have several subsequences.
The instruction subsequence is choosen by CTR, SQ, and STB. These form bits 7-14 of the
CPM-A EPROM address.
CTR (EPROM address bits 13-14)
The CTR signal has 2 lines: SB_02 is the MSB; SB_01 is the LSB. The signal comes from the
CTR subsystem in the PROC module. It indicates whether processing needs to be briefly
interrupted to insert a PINC or MINC subsequence to increment or decrement a priority
counter.
CTR00: SB_02=0, SB_01=0 no counter; do the next subsequence
CTR01: SB_02=0, SB_01=1 PINC
CTR10: SB_02=1, SB_01=0 MINC
CTR11: SB_02=1, SB_01=1 both; they cancel out, so do the next
subsequence
Register SQ (EPROM address bits 9-12)
The 4-bit SQ register holds the currently executing instruction. The code in the SQ register
is the same as the op code for these four instructions.
NMEM SQ REG OPCODE USAGE DESCRIPTION CYCLESTC 00 00 TC K Transfer Control 1 MCTCCS 01 01 CCS K Count, Compare, Skip 2 MCTINDEX 02 02 INDEX K Index 2 MCTXCH 03 03 XCH K Exchange 2 MCT
The SQ register code for these four instructions is the op code + 010 (octal). This happens
because all of these instructions have bit 15 set (the sign (SG) bit) while in memory. When
the instruction is copied from memory to the memory buffer register (G) to register B, the
SG bit moves from bit 15 to bit 16 and the sign is copied back into bit 15 (US). Therefore,
the CS op code (04) becomes (14), and so on.
NMEM SQ REG OPCODE USAGE DESCRIPTION CYCLESCS 014 04 CS K Clear and Subtract 2 MCTTS 015 05 TS K Transfer to Storage 2 MCTAD 016 06 AD K Add 2 or 3 MCTMASK 017 07 MASK K Bitwise AND 2 MCT
These are the three extended instructions. They are accessed by executing an INDEX 5777
before each instruction. By convention, address 5777 contains 47777. The INDEX instruction
adds 47777 to the extended instruction to form the SQ op code. For example, the INDEX
adds 4 to the 4 op code for MP to produce the 11 (octal; the addition generates an
end-around-carry). SQ register code (the 7777 part is a negative zero).
NMEM SQ REG OPCODE USAGE DESCRIPTION CYCLESMP 011 04 MP K Multiply 10 MCTDV 012 05 DV K Divide 18 MCTSU 013 06 SU K Subtract 4 or 5 MCT
STB (EPROM address bits 7-8)
The stage register B (STB) selects the subsequence for a given instruction. Some instructions
have multiple subsequences; others (TC) have only one.
The stage register has 2 bits: STB2 is the MSB; STB1 is the LSB. All instructions initiallly
begin with the stage register set to zero. If an instruction needs more than one subsequence,
the stage register is incremented to select the next subsequence.
STB00: STB2=0, STB1=0
STB01: STB2=0, STB1=1
STB10: STB2=1, STB1=0
STB11: STB2=1, STB1=1
INSTRUCTION SUBSEQUENCES
There are 22 instruction subsequences:
TC0 0
CCS0 1
CCS1 2
NDX0 3
NDX1 4
RSM3 5
XCH0 6
CS0 7
TS0 8
AD0 9
MASK0 10
MP0 11
MP1 12
MP3 13
DV0 14
DV1 15
SU0 16
RUPT1 17
RUPT3 18
STD2 19
PINC0 20
MINC0 21
If the CTR signals are 01 (SB_02=0, SB_01=1) the PINC subsequence is selected. If the CTR
signals are 10 (SB_02=1, SB_01=0) the MINC subsequence is selected. Otherwise,
subsequences for each instruction are selected using the 4-bit SQ register and the 2-bit stage
register (STB2, STB1, where STB2 is the MSB). Some instructions (TC) have only one
subsequence. At the start of each instruction, the stage counter is initially set to zero. The
interrupt call and resturn sequences are also stored at SQ=00.
SQ STB00 STB01 STB10 STB11
TC/RUPT 00: TC0 RUPT1 STD2 RUPT3
CCS 01: CCS0 CCS1 ---- ----
INDEX 02: NDX0 NDX1 ---- RSM3
XCH 03: XCH0 ---- STD2 ----
04: ---- ---- ---- ----
05: ---- ---- ---- ----
06: ---- ---- ---- ----
07: ---- ---- ---- ----
10: ---- ---- ---- ----
MP 11: MP0 MP1 ---- MP3
DV 12: DV0 DV1 STD2 ----
SU 13: SU0 ---- STD2 ----
CS 14: CS0 ---- STD2 ----
TS 15: TS0 ---- STD2 ----
AD 16: AD0 ---- STD2 ----
MASK 17: MASK0 ---- STD2 ----
SELECTING THE CONTROL PULSES
Each subsequence consists of 12 steps (TP1 - TP12), with each step asserting up to 5 control
pulses (control logic signals). Steps TP1-TP11 are unique to each subsequence; step TP12 is
common to all subsequences. Control pulses for TP12 are discussed in CPM-C.
For some steps, selection of the control pulses is also conditional on the state of the 2-bit
branch register (BR1 and BR2: BR1 is the MSB and BR2 is the LSB):
BR00 BR1=0, BR2=0
BR01 BR1=0, BR2=1
BR10 BR1=1, BR2=0
BR11 BR1=1, BR2=1
Bits 1-6 of the CPM-A EPROM address is formed as follows:
3-6: register SG (4)
2: register BR1 (1)
1: register BR2 (1)
The column on the far left is the step; columns to the right specify the control pulses that are
asserted for that step. Some steps have no control pulses.
subsequence TC0:
TP1 RB WY WS CI ----
TP2
TP3 WG ---- ---- ---- ----
TP4 RA WOVI ---- ---- ----
TP5
TP6
TP7 RG RSC WB WP ----
TP8 RZ WQ GP TP ----
TP9 RB WSC WG ---- ----
TP10 RU WZ ---- ---- ----
TP11 NISQ ---- ---- ---- ----
subsequence CCS0:
TP1 RB WS ---- ---- ----
TP2 RZ WY ---- ---- ----
TP3 WG ---- ---- ---- ----
TP4
TP5
TP6 RG RSC WB TSGN WP
TP7 BR00, RC TMZ ---- ---- ----
BR01, RC TMZ ---- ---- ----
BR10, RB TMZ ---- ---- ----
BR11, RB TMZ ---- ---- ----
TP8 BR00, GP TP ---- ---- ----
BR01, R1 WX GP TP ----
BR10, R2 WX GP TP ----
BR11, R1 R2 WX GP TP,
TP9 RB WSC WG ---- ----
TP10 BR00, RC WA ---- ---- ----
BR01, WA R1C ---- ---- ----
BR10, RB WA ---- ---- ----
BR11, WA R1C ---- ---- ----
TP11 RU ST1 WZ ---- ----
subsequence CCS1:
TP1 RZ WY WS CI ----
TP2
TP3 WG ---- ---- ---- ----
TP4 RU WZ ---- ---- ----
TP5 RA WY CI ---- ----
TP6
TP7 RG RSC WB WP ----
TP8 RU WB GP TP ----
TP9
TP10 RC WA WOVI ---- ----
TP11 RG RSC WB NISQ ----
subsequence NDX0:
TP1 RB WS ---- ---- ----
TP2
TP3 WG ---- ---- ---- ----
TP4 RA WOVI ---- ---- ----
TP5
TP6
TP7 RG RSC WB WP ----
TP8 GP TP ---- ---- ----
TP9 RB WSC WG ---- ----
TP10 TRSM ---- ---- ---- ----
TP11 ST1 ---- ---- ---- ----
subsequence NDX1:
TP1 RZ WY WS CI ----
TP2
TP3 WG ---- ---- ---- ----
TP4 RU WZ ---- ---- ----
TP5
TP6 RB WY ---- ---- ----
TP7 RG RSC WB WP ----
TP8 RB WX GP TP ----
TP9 RB WSC WG ---- ----
TP10
TP11 RU WB WOVI NISQ ----
subsequence RSM3:
TP1 R24 WS ---- ---- ----
TP2
TP3 WG ---- ---- ---- ----
TP4
TP5
TP6
TP7 RG WZ ---- ---- ----
TP8
TP9
TP10
TP11 NISQ ---- ---- ---- ----
subsequence XCH0:
TP1 RB WS ---- ---- ----
TP2 RA WP ---- ---- ----
TP3 WG ---- ---- ---- ----
TP4 WP2 ---- ---- ---- ----
TP5
TP6
TP7 RG RSC WB WP, ----
TP8 GP TP ---- ---- ----
TP9 RA WSC WG RP2 ----
TP10 RB WA WOVI ---- ----
TP11 ST2 ---- ---- ---- ----
subsequence CS0:
TP1 RB WS ---- ---- ----
TP2
TP3 WG ---- ---- ---- ----
TP4
TP5
TP6
TP7 RG RSC WB WP, ----
TP8 GP TP ---- ---- ----
TP9 RB WSC WG ---- ----
TP10 RC WA WOVI ---- ----
TP11 ST2 ---- ---- ---- ----
subsequence TS0:
TP1 RB WS ---- ---- ----
TP2 RA WB TOV WP ----
TP3 WG ---- ---- ---- ----
TP4 BR00, ---- ---- ---- ---- ----
BR01, RZ WY CI ---- ---- (overflow)
BR10, RZ WY CI ---- ---- (underflow)
BR11, ---- ---- ---- ---- ----
TP5 BR00, ---- ---- ---- ---- ----
BR01, R1 WA ---- ---- ----
BR10, WA R1C ---- ---- ----
BR11, ---- ---- ---- ---- ----
TP6
TP7 BR00, ---- ---- ---- ---- ----
BR01, RU WZ ---- ---- ----
BR10, RU WZ ---- ---- ----
BR11, ---- ---- ---- ---- ----
TP8 GP ---- ---- ---- ----
TP9 RB WSC WG ---- ----
TP10 RA WOVI ---- ---- ----
TP11 ST2 ---- ---- ---- ----
subsequence AD0:
TP1 RB WS ---- ---- ----
TP2 RA WY ---- ---- ----
TP3 WG ---- ---- ---- ----
TP4
TP5
TP6
TP7 RG RSC WB WP ----
TP8 RB WX GP TP ----
TP9 RB WSC WG ---- ----
TP10
TP11 RU WA WOVC ST2 WOVI
SUB_MASK0 performs a logical AND using DeMorgan's Theorem: the inputs are inverted, a
logical OR is performed, and the result is inverted. The implementation of the OR (at TP8) is
somewhat unorthodox: the inverted inputs are in registers U and C. The OR is achieved by
gating both registers onto the read/write bus simultaneously. (The bus only transfers logical
1's; register-to-register transfers are performed by clearing the destination register and then
transferring the 1's from the source register to the destination). When the 1's from both
registers are simultaneously gated onto the bus, the word on the bus is a logical OR of both
registers.
subsequence MASK0:
TP1 RB WS ---- ---- ----
TP2 RA WB ---- ---- ----
TP3 WG ---- ---- ---- ----
TP4 RC WY ---- ---- ----
TP5
TP6
TP7 RG RSC WB WP ----
TP8 RU RC WA GP TP
TP9
TP10 RA WB ---- ---- ----
TP11 RC WA ST2 WOVI ----
subsequence MP0:
TP1 RB WS ---- ---- ----
TP2 RA WB TSGN ---- ----
TP3 RSC WG ---- ---- ----
TP4 BR00, RB WLP ---- ---- ----
BR01, RB WLP ---- ---- ----
BR10, RC WLP ---- ---- ----
BR11, RC WLP ---- ---- ----
TP5 RLP WA ---- ---- ----
TP6
TP7 BR00, RG WY WP ---- ----
BR01, RG WY WP ---- ----
BR10, RG WB WP ---- ----
BR11, RG WB WP ---- ----
TP8 BR00, GP TP ---- ---- ----
BR01, GP TP ---- ---- ----
BR10, RC WY GP TP ----
BR11, RC WY GP TP ----
TP9 RU WB TSGN2 ---- ----
TP10 BR00, RA WLP TSGN ---- ----
BR01, RA RB14 WLP TSGN ----
BR10, RA WLP TSGN ---- ----
BR11, RA RB14 WLP TSGN ----
TP11 BR00, ST1 WALP ---- ---- ----
BR01, R1 ST1 WALP R1C ----
BR10, RU ST1 WALP ---- ----
BR11, RU ST1 WALP ---- ----
subsequence MP1:
TP1 RA WY ---- ---- ----
TP2 RLP WA TSGN ---- ----
TP3 BR00, ---- ---- ---- ---- ----
BR01, ---- ---- ---- ---- ----
BR10, RB WX ---- ---- ----
BR11, RB WX ---- ---- ----
TP4 RA WLP ---- ---- ----
TP5 RLP TSGN ---- ---- ----
TP6 RU WALP ---- ---- ----
TP7 RA WY ---- ---- ----
TP8 BR00, ---- ---- ---- ---- ----
BR01, ---- ---- ---- ---- ----
BR10, RB WX ---- ---- ----
BR11, RB WX ---- ---- ----
TP9 RLP WA ---- ---- ----
TP10 RA WLP CTR ---- ----
TP11 RU ST1 WALP ---- ----
subsequence MP3:
TP1 RZ WY WS CI ----
TP2 RLP TSGN ---- ---- ----
TP3 WG ---- ---- ---- ----
TP4 RU WZ ---- ---- ----
TP5 RA WY ---- ---- ----
TP6 BR00, ---- ---- ---- ---- ----
BR01, ---- ---- ---- ---- ----
BR10, RB WX ---- ---- ----
BR11, RB WX ---- ---- ----
TP7 RG RSC WB WP ----
TP8 RLP WA GP TP ----
TP9 RB WSC WG ---- ----
TP10 RA WLP ---- ---- ----
TP11 RU WALP NISQ ---- ----
subsequence DV0:
TP1 RB WS ---- ---- ----
TP2 RA WB TSGN ---- ----
TP3 RSC WG ---- ---- ----
TP4 BR00, RC WA ---- ---- ----
BR01, RC WA ---- ---- ----
BR10, ---- ---- ---- ---- ----
BR11, ---- ---- ---- ---- ----
TP5 BR00, R1 WLP ---- ---- ----
BR01, R1 WLP ---- ---- ----
BR10, R2 WLP ---- ---- ----
BR11, R2 WLP ---- ---- ----
TP6 RA WQ ---- ---- ----
TP7 RG WB TSGN WP ----
TP8 RB WA GP TP ----
TP9 BR00, RLP R2 WB ---- ----
BR01, RLP R2 WB ---- ----
BR10, ---- ---- ---- ---- ----
BR11, ---- ---- ---- ---- ----
TP10 BR00, RB WLP ---- ---- ----
BR01, RB WLP ---- ---- ----
BR10, RC WA ---- ---- ----
BR11, RC WA ---- ---- ----
TP11 R1 ST1 WB ---- ----
subsequence DV1:
TP1 R22 WS ---- ---- ----
TP2 RQ WG ---- ---- ----
TP3 RG WQ WY RSB ----
TP4 RA WX ---- ---- ----
TP5 RLP TSGN2 ---- ---- ----
TP6
TP7 RU TSGN ---- ---- ----
TP8 BR00, ---- ---- ---- ---- ----
BR01, ---- ---- ---- ---- ----
BR10, RU WQ ---- ---- ----
BR11, RU WQ ---- ---- ----
TP9 BR00, RB RSB WG ---- ----
BR01, RB RSB WG ---- ----
BR10, RB WG ---- ---- ----
BR11, RB WG ---- ---- ----
TP10 RG WB TSGN ---- ----
TP11 BR00, ST1 ---- ---- ---- ----
BR01, ST1 ---- ---- ---- ----
BR10, RC WA ST2 ---- ----
BR11, RB WA ST2 ---- ----
subsequence SU0:
TP1 RB WS ---- ---- ----
TP2 RA WY ---- ---- ----
TP3 WG ---- ---- ---- ----
TP4
TP5
TP6
TP7 RG RSC WB WP ----
TP8 RC WX GP TP ----
TP9 RB WSC WG ---- ----
TP10
TP11 RU WA WOVC ST2 WOVI
subsequence RUPT1:
TP1 R24 WY WS CI, ----
TP2
TP3 WG ---- ---- ---- ----
TP4
TP5
TP6
TP7
TP8
TP9 RZ WG ---- ---- ----
TP10 RU WZ ---- ---- ----
TP11 ST1 ST2 ---- ---- ----
subsequence RUPT3:
TP1 RZ WS ---- ---- ----
TP2 RRPA WZ ---- ---- ----
TP3 RZ KRPT WG ---- ----
TP4
TP5
TP6
TP7
TP8
TP9 RB WSC WG ---- ----
TP10
TP11 ST2 ---- ---- ---- ----
subsequence STD2:
TP1 RZ WY WS CI, ----
TP2
TP3 WG ---- ---- ---- ----
TP4 RU WZ ---- ---- ----
TP5
TP6
TP7 RG RSC WB WP ----
TP8 GP TP ---- ---- ----
TP9 RB WSC WG ---- ----
TP10
TP11 NISQ ---- ---- ---- ----
subsequence PINC:
TP1 WS RSCT ---- ---- ----
TP2
TP3 WG ---- ---- ---- ----
TP4 R1 WY ---- ---- ----
TP5
TP6 RG WX WP ---- ----
TP7 TP ---- ---- ---- ----
TP8 WP ---- ---- ---- ----
TP9 RU CLG WPx ---- ----
TP10 RU WGx WOVR ---- ----
TP11
subsequence MINC:
TP1 WS, RSCT ---- ---- ----
TP2
TP3 WG ---- ---- ---- ----
TP4 WY R1C ---- ---- ----
TP5
TP6 RG WX WP ---- ----
TP7 TP ---- ---- ---- ----
TP8 WP ---- ---- ---- ----
TP9 RU CLG WPx ---- ----
TP10 RU WGx WOVR ---- ----
TP11
Here’s some of the analysis used to develop the instruction sequence decoder. This decoder
takes in the STB and SQ inputs and decodes the instruction sequence for display to the
operator.
CONTROL SIGNAL DEFINITIONS
SIGNAL # DESCRIPTION
CI 1 Carry in
CLG 2 Clear G
CLCTR 3 Clear loop counter
CTR 4 Loop counter
GP 5 Generate Parity
KRPT 6 Knock down Rupt priority
NISQ 7 New instruction to the SQ register
RA 8 Read A
RB 9 Read B
RB14 10 Read bit 14
RC 11 Read C
RG 12 Read G
RLP 13 Read LP
RP2 14 Read parity 2
RQ 15 Read Q
RRPA 16 Read RUPT address
RSB 17 Read sign bit
RSCT 18 Read selected counter address
RU 19 Read sum
RZ 20 Read Z
R1 21 Read 1
R1C 22 Read 1 complimented
R2 23 Read 2
R22 24 Read 22
R24 25 Read 24
ST1 26 Stage 1
ST2 27 Stage 2
TMZ 28 Test for minus zero
TOV 29 Test for overflow
TP 30 Test parity
TRSM 31 Test for resume
TSGN 32 Test sign
TSGN2 33 Test sign 2
WA 34 Write A
WALP 35 Write A and LP
WB 36 Write B
Wgx 37 Write G (do not reset)
WLP 38 Write LP
WOVC 39 Write overflow counter
WOVI 40 Write overflow RUPT inh ibit
WOVR 41 Write overflow
WP 42 Write P
Wpx 43 Write P (do not reset)
WP2 44 Write P2
WQ 45 Write Q
WS 46 Write S
WX 47 Write X
WY 48 Write Y
Wyx 49 Write Y (do not reset)
WZ 50 Write Z
Control signal outputs from CPM-A used as inputs to CPM-B only (not used outside of CPM):
SIGNAL # DESCRIPTION
RSC 51 Read special and central (output to B only, not outside CPM)
WSC 52 Write special and central (output to B only, not outside CPM)
WG 53 Write G (output to B only, not outside CPM)
Control signal outputs from CPM-A used as inputs to CPM-C only (not used outside of CPM):
SIGNAL # DESCRIPTION
SDV1 54 Subsequence DV1 is currently active
SMP1 55 Subsequence MP1 is currently active
SRSM3 56 Subsequence RSM3 is currently active
CPM-A INPUTS:
I/F signal full name state definition
TPG:
TPG_Q3 TPG STATE where Q3 is MSB, Q0 is
LSB:
TPG_Q2 00 = STBY
TPG_Q1 01 = PWRON
TPG_Q0 02 = TP1
03 = TP2
04 = TP3
05 = TP4
06 = TP5
07 = TP6
08 = TP7
09 = TP8
10 = TP9
11 = TP10
12 = TP11
13 = TP12
14 = SRLSE
15 = WAIT
SEQ:
BR1 BRANCH REG 1 BR1 is MSB, BR2 is LSB
BR2 BRANCH REG 2 BR00=0:BR1=0, BR2=0
BR01=1:BR1=0, BR2=1
BR10=2:BR1=1, BR2=0
BR11=3:BR1=1, BR2=1
SQ_3 INST REG where SQ_3 is MSB,
SQ_0 is LSB
SQ_2
SQ_1
SQ_0
STB_1 STAGE REG where STB_1 is MSB,
STB_0 is LSB
STB_0
LOOP6 LOOPCNTR EQ 6 0=LOOPCNTR is holding
the number 6.
SNI SELECT NEXT INST 1=select next instruction (SNI register)
CTR:
SB_01 SUB SEL 01 SB_01 is LSB; SB_02 is MSB
SB_02 SUB SEL 02 00=no counter; 01=PINC; 10=MINC
INT:
IRQ INT RQST 0=interrupt requested.
MON:
NRUN RUN/HALT 0=run, 1=step
CPM-A OUTPUTS:
signal full name state definition
CI SET CARRY IN 0=Carry in
CLG CLR G 0=Clear G
CLCTR CLR LOOP CTR 0=Clear loop counter
CTR INCR LOOP CTR 0=Loop counter
GP GEN PARITY 0=Generate Parity
KRPT KNOCK DOWN RUPT 0=Knock down Rupt priority
NISQ NEW INSTRUCT 0=New instruction to the SQ reg
RA READ A 0=Read A
RB READ B 0=Read B
RB14 READ BIT 14 0=Read bit 14
RC READ C 0=Read C
RG READ G 0=Read G
RLP READ LP 0=Read LP
RP2 READ PARITY 2 0=Read parity 2
RQ READ Q 0=Read Q
RRPA READ RUPT ADDR 0=Read RUPT address
RSB READ SIGN 0=Read sign bit
RSCT READ CNTR ADDR 0=Read selected counter address
RU READ U 0=Read sum
RZ READ Z 0=Read Z
R1 READ 1 0=Read 1
R1C READ 1 COMP 0=Read 1 complimented
R2 READ 2 0=Read 2
R22 READ 22 0=Read 22
R24 READ 24 0=Read 24
ST1 SET STAGE 1 0=Stage 1
ST2 SET STAGE 2 0=Stage 2
TMZ TEST MINUS ZERO 0=Test for minus zero
TOV TEST OVF 0=Test for overflow
TP TEST PARITY 0=Test parity
TRSM TEST RESUME 0=Test for resume
TSGN TEST SIGN 0=Test sign
TSGN2 TEST SIGN 2 0=Test sign 2
WA WRITE A 0=Write A
WALP WRITE A/LP 0=Write A and LP
WB WRITE B 0=Write B
WGx WRITE G NO RESET 0=Write G (do not reset)
WLP WRITE LP 0=Write LP
WOVC WRITE OVF CNTR 0=Write overflow counter
WOVI WRITE OVF RUPT INH 0=Write overflow RUPT inh ibit
WOVR WRITE OVF 0=Write overflow
WP WRITE P 0=Write P
WPx WRITE P NO RESET 0=Write P (do not reset)
WP2 WRITE P2 0=Write P2
WQ WRITE Q 0=Write Q
WS WRITE S 0=Write S
WX WRITE X 0=Write X
WY WRITE Y 0=Write Y
WYx WRITE Y NO RESET 0=Write Y (do not reset)
WZ WRITE Z 0=Write Z
OUTPUTS TO CPM-B ONLY; NOT USED OUTSIDE CPM
RSC READ SPECIAL REG 0=Read special and central
WSC WRITE SPECIAL REG 0=Write special and central
WG WRITE G 0=Write G
OUTPUTS TO CPM-C ONLY; NOT USED OUTSIDE CPM
SDV1 SUBSEQ DV1 0=Subsequence DV1 is selected
SMP1 SUBSEQ MP1 0=Subsequence MP1 is selected
SRSM3 SUBSEQ RSM3 0=Subsequence RSM3 is selected
CPM-B (Control Pulse Matrix B)
Some AGC registers are mapped onto low memory addresses (00 - 17 octal), so reading or
writing to those addresses causes data to be read from, or written into, flip-flop registers
instead of memory. These addresses include the central registers (A, Q, Z, LP), the bank
register (BNK), and I/O registers.
Addresses 16 and 17 are used in conjunction with the INDEX instruction to inhibit or enable
interrupts; this is a trick used to extend the instruction set; to cram more instructions into a
3-bit op code.
The addresses from 20-23 are in eraseable memory, but any data written into those
addresses is rotated or shifted. This is implemented through the G register in the MEM
module.
Addresses 24-27 are reserved for saving the central register before servicing an interrupt.
Registers Z and B are automatically saved by the interrupt subsequence. Registers A and Q
must be saved by the interrupt service routine.
SPECIAL REGISTERS
These addresses called special registers. All numbers are in octal.
addr Flip-Flop registers
00 A register (accumulator)
01 Q register
02 Z register (program counter)
03 LP register
04 IN0 input register 0
05 IN1 input register 1
06 IN2 input register 2
07 IN3 input register 3
10 OUT0 output register 0
11 OUT1 output register 1
12 OUT2 output register 2
13 OUT3 output register 3
14 OUT4 output register 4
15 BANK bank register
16 RELINT
17 INHINT
Eraseable memory registers
20 CYR cycle right
21 SR shift right
22 CYL cycle left
23 SL shift left
24 ZRUPT save register Z
25 BRUPT save register B
26 ARUPT save register A
27 QRUPT save register Q
CPM-B translates the WG, RSC, and WSC signals generated by SUBSYSTEM A into signals
that read from or write to these registers. The logic is given below (all numbers are in octal):
if WG is asserted from CPM-A,
...and the address bus = 020: assert:W20
...and the address bus = 021: assert:W21
...and the address bus = 022: assert:W22
...and the address bus = 023: assert:W23
...otherwise, if the address bus > 17: assert:WGn (not a central register)
if RSC is asserted from CPM-A
...and the address bus = 00: assert:RA0
...and the address bus = 01: assert:RA1
...and the address bus = 02: assert:RA2
...and the address bus = 03: assert:RA3
...and the address bus = 04: assert:RA4
...and the address bus = 05: assert:RA5
...and the address bus = 06: assert:RA6
...and the address bus = 07: assert:RA7
...and the address bus = 010: assert:RA10
...and the address bus = 011: assert:RA11
...and the address bus = 012: assert:RA12
...and the address bus = 013: assert:RA13
...and the address bus = 014: assert:RA14
...and the address bus = 015: assert:RBK
...and the address bus = 016: do nothing
...and the address bus = 017: do nothing
if WSC is asserted from CPM-A,
...and the address bus = 00: assert:WA0
...and the address bus = 01: assert:WA1
...and the address bus = 02: assert:WA2
...and the address bus = 03: assert:WA3
...and the address bus = 010: assert:WA10
...and the address bus = 011: assert:WA11
...and the address bus = 012: assert:WA12
...and the address bus = 013: assert:WA13
...and the address bus = 014: assert:WA14
...and the address bus = 015: assert:WBK
...and the address bus = 016: do nothing
...and the address bus = 017: do nothing
Here’s a table I developed to work out the relationships between addresses and CPM-B logic
signals:
CPM-B CONTROL SIGNALS
SIGNAL # DESCRIPTION
RA0 57 Read register at address 0 (A)
RA1 58 Read register at address 1 (Q)
RA2 59 Read register at address 2 (Z)
RA3 60 Read register at address 3 (LP)
RA4 61 Read register at address 4
RA5 62 Read register at address 5
RA6 63 Read register at address 6
RA7 64 Read register at address 7
RA10 65 Read register at address 10 (octal)
RA11 66 Read register at address 11 (octal)
RA12 67 Read register at address 12 (octal)
RA13 68 Read register at address 13 (octal)
RA14 69 Read register at address 14 (octal)
RBK 70 Read BNK
WA0 71 Write register at address 0 (A)
WA1 72 Write register at address 1 (Q)
WA2 73 Write register at address 2 (Z)
WA3 74 Write register at address 3 (LP)
WA10 75 Write register at address 10 (octal)
WA11 76 Write register at address 11 (octal)
WA12 77 Write register at address 12 (octal)
WA13 78 Write register at address 13 (octal)
WA14 79 Write register at address 14 (octal)
WBK 80 Write BNK
WGn 81 Write G (normal gates)
W20 82 Write into CYR
W21 83 Write into SR
W22 84 Write into CYL
W23 85 Write into SL
CPM-B INPUTS:
I/F signal full name state definition
CPM-A
RSC READ SPECIAL REG 0=Read special and central
WSC WRITE SPECIAL REG 0=Write special and central
WG WRITE G 0=Write G
ADR:
AD_4 ADDRESS AD_4=MSB, AD_1=LSB:
AD_3 (low-order bits of 14-bit
address)
AD_2
AD_1
GTR_17 ADDRESS > 017 0=CADR in register S >
017
GTR_27 ADDRESS > 027 0=CADR in register S >
027
CPM-B OUTPUTS:
I/F signal full name state definition
RA0 READ ADDR 0 0=Read reg at address 0
(A)
RA1 READ ADDR 1 0=Read reg at address 1 (Q)
RA2 READ ADDR 2 0=Read reg at address 2 (Z)
RA3 READ ADDR 3 0=Read reg at address 3 (LP)
RA4 READ ADDR 4 0=Read reg at address 4
RA5 READ ADDR 5 0=Read reg at address 5
RA6 READ ADDR 6 0=Read reg at address 6
RA7 READ ADDR 7 0=Read reg at address 7
RA10 READ ADDR 10 0=Read reg at address 10 (octal)
RA11 READ ADDR 11 0=Read reg at address 11 (octal)
RA12 READ ADDR 12 0=Read reg at address 12 (octal)
RA13 READ ADDR 13 0=Read reg at address 13 (octal)
RA14 READ ADDR 14 0=Read reg at address 14 (octal)
RBK READ BNK 0=Read BNK reg
WA0 WRITE ADDR 0 0=Write reg at address 0 (A)
WA1 WRITE ADDR 1 0=Write reg at address 1 (Q)
WA2 WRITE ADDR 2 0=Write reg at address 2 (Z)
WA3 WRITE ADDR 3 0=Write reg at address 3 (LP)
WA10 WRITE ADDR 10 0=Write reg at address 10 (octal)
WA11 WRITE ADDR 11 0=Write reg at address 11 (octal)
WA12 WRITE ADDR 12 0=Write reg at address 12 (octal)
WA13 WRITE ADDR 13 0=Write reg at address 13 (octal)
WA14 WRITE ADDR 14 0=Write reg at address 14 (octal)
WBK WRITE BNK 0=Write BNK reg
WGn WRITE G NORMAL 0=Write G (normal gates)
W20 WRITE ADDR 20 0=Write into CYR
W21 WRITE ADDR 21 0=Write into SR
W22 WRITE ADDR 22 0=Write into CYL
W23 WRITE ADDR 23 0=Write into SL
CPM-C (Control Pulse Matrix C)
The CPM-C subsystem issues control signals for the memory cycle, selecting the next
instruction, and performing priority counter subsequences. These signals are issued at
specific points in the 12-step cycle of the time pulse generator (TPG).
STBY: assert:GENRST Resets various AGC registers.
PWRON: assert:R2000 Put the starting address on the read bus.
CPM-A asserts:WB, which copies the data
into register B, which is the prefetch
register for the next instruction. Since the
opcode for a branch is 0, the instruction in
B becomes TC 2000, which is the first
instruction always executed by the AGC.
TP1: assert:CLISQ SNI <- 0. Moved from TP12 to TP1 because
CLISQ was getting cleared in this hardware
AGC replica before TPG was clocked;
therefore TPG was not seeing the SNI
indication.
TP5: if: the address bus > 17 (not a central register)
and the address bus < 2000 (not fixed memory; must be erasable)
and SDV1 or SMP1 are not asserted (not a loop counter subsequence)
then: assert:SBWG read erasable memory into G by TP6
if: the address bus = 17
then: assert:INH INHINT instruction (INDEX 017)
if: the address bus = 16
then: assert:CLINH RELINT instruction (INDEX 016)
TP6: if: the address bus > 1777 (not eraseable memory)
and SDV1 or SMP1 are not asserted (not a loop counter subsequence)
then: assert:SBWG read fixed memory into G register by TP7
TP11: if: the address bus > 17 (not a central register)
and the address bus < 2000 (not fixed memory; must be erasable)
and SDV1 or SMP1 are not asserted (not a loop counter subsequence)
then: assert:WE G register written to memory beginning at
TP11; Memory updates are in G by TP10
for all normal and extracode instructions,
but the PINC and MINC sequences write to
G in TP10 because they need to update the
parity bit.
if: SRSM3 is asserted
then: assert:CLRP Additional interrupts are inhibited during
servicing of an interrupt; Remove the
inhibition when RESUME is executed
(INDEX 025)
TP12: assert:WPCTR Check the priority counters; service any
waiting inputs on the next memory cycle.
if: the SNI register = 1 (if SNI is set, get next instruction)
then:
if: IRQ is asserted (if interrupt requested (see CPM-A for
similar assertion))
then:
assert:RPT Read the interrupt vector.
assert:SETSTB STB <- 1. Will cause the RUPT1
subsequence to execute.
else: (not an interrupt; a normal instruction)
assert:CLSTB STB <- 0 . The CPM-A will assert RB here,
which, when accompanied by WSQ
(below), will read the next instruction from
register B onto the bus. WSQ will write it
into SQ.
endif
assert:WSQ Write the next instruction (on the write
bus) into the SQ register.
assert:CLSTA Clear STA register.
assert:CLINH1 Clear INHINT1. Removes inhibition of
interrupts (if they were) AFTER the next
instruction
else: (not a new instruction)
if: CTR00 or CTR11 if previous sequence was not a PINC or
MINC, get next subsequence for same
instruction. if the previous sequence was
PINC or MINC, we already have the
subsequence, but it was interrupted by the
counter.
then:
assert:WSTB Copy STB <- STA. Gets next sequence for
same instruction.
assert:CLSTA STA <- 0
This truth table shows the logic
needed at TP12 to produce the
RPT, SETSTB, CLSTB, CLSTA,
WSQ, WSTB, CLISQ, and CLINH1
signals, given the SNI, IRQ,
NRUN, and SB inputs.
This chart shows the logic for
some of the more simple
control pulses generated by
CMP-C. Some pulses reduce to
states from the TPG, such as
CLISQ, WPCTR, and CLINH1,
which reduce to TP12.
This is the logic for RPT and SETSTB.
The design for CLSTB is a
little more complex. The
truth table to the left is
reduced through the
Karnaugh map to the
Minterm equation below
the map. A little bubble
pushing DeMorganizes
the logic to the final
solution at the bottom
right.
This is the logic for
WE and SBWG, two
signals that control
memory access.
CPM-C CONTROL SIGNALS
SIGNAL # DESCRIPTION
GENRST 86 General Reset
CLINH 87 Clear INHINT
CLINH1 88 Clear INHINT1
CLSTA 89 Clear state counter A (STA)
CLSTB 90 Clear state counter B (STB)
CLISQ 91 Clear SNI
CLRP 92 Clear RPCELL
INH 93 Set INHINT
RPT 94 Read RUPT opcode
SBWG 95 Write G from memory
SETSTB 96 Set the ST1 bit of STB
WE 97 Write E-MEM from G
WPCTR 98 Write PCTR (latch priority counter sequence)
WSQ 99 Write SQ
WSTB 100 Write stage counter B (STB)
R2000 101 Read 2000
CPM INPUTS:
I/F signal full name state definition
TPG:
TPG_Q3 TPG STATE where Q3 is MSB, Q0 is
LSB:
TPG_Q2 00 = STBY
TPG_Q1 01 = PWRON
TPG_Q0 02 = TP1
03 = TP2
04 = TP3
05 = TP4
06 = TP5
07 = TP6
08 = TP7
09 = TP8
10 = TP9
11 = TP10
12 = TP11
13 = TP12
14 = SRLSE
15 = WAIT
ADR:
EQU_16 ADDRESS = 016 0=CADR in register S = 016
EQU_17 ADDRESS = 017 0=CADR in register S = 017
GTR_17 ADDRESS > 017 0=CADR in register S > 017
GTR_1777 ADDRESS > 01777 0=CADR in register S > 01777
CPM-A:
SDV1 SUBSEQ DV1 0=Subsequence DV1 is selected
SMP1 SUBSEQ MP1 0=Subsequence MP1 is selected
SRSM3 SUBSEQ RSM3 0=Subsequence RSM3 is selected
CTR:
SB_01 SUB SEL 01 SB_01 is LSB; SB_02 is MSB
SB_02 SUB SEL 02 00=no counter; 01=PINC; 10=MINC
SEQ:
SNI SELECT NEXT INST 1=select next instruction (SNI register)
INT:
IRQ INT RQST 0=interrupt requested.
MON:
NRUN RUN/HALT 0=run, 1=step
CPM OUTPUTS:
I/F signal full name state definition
GENRST GENERAL RESET 0=General Reset
CLINH CLEAR INHINT 0=Clear INHINT
CLINH1 CLEAR INHINT1 0=Clear INHINT1
CLSTA CLEAR STA 0=Clear state counter A (STA)
CLSTB CLEAR STB 0=Clear state counter B (STB)
CLISQ CLEAR SNI 0=Clear SNI
CLRP CLEAR RPCELL 0=Clear RPCELL
INH SET INHINT 0=Set INHINT
RPT READ RUPT 0=Read RUPT opcode
SBWG WRITE G 0=Write G from memory
SETSTB SET ST1 0=Set the ST1 bit of STB
WE WRITE EMEM 0=Write E-MEM from G
WPCTR WRITE PCTR 0=Write PCTR (latch priority counter
sequence)
WSQ WRITE SQ 0=Write SQ
WSTB WRITE STB 0=Write stage counter B (STB)
R2000 READ 2000 0=Read 2000
Fabrication
The CTL module is (3) 13"x5" circuit boards, and 1 control panel.
Module Rack
The module framework is designed to resemble a relay rack, but scaled to fit the circuit
board dimensions. It is constructed out of 1"x2" pine and spray-painted semi-gloss gray.
Circu it boards are mounted to the rack by 2 phillips screws at either end. Nylon spacers
(1/4") are used as standoffs to hold the board edges above the rack. The boards are
mounted so the chips are in the back and the pins are wiring are visible from the front.
Power is distributed by 2 heavy aluminum bus bars mounted vertically, one per side, on the
back of the module. Machine screws are mounted through the bus bars at evenly-spaced
intervals to provide connection points for the boards.
Solid copper wire (24 gauge) connects the boards to the bus bars. Ring terminals are used
on the bus bar side of the connection. On the circuit board size, the wires are soldered
directly to the supply rails.
Materials were purchased from Home Depot, ACE Hardware, and Radio Shack.
Circuit Boards
The circuit boards are 13"x5" general purpose prototyping boards, epoxy glass with double-
side plated through pads on 0.1" centers (JAMECO 21477CL).
ICs are mounted in level 3 machine tooled wire-wrap sockets: 8, 14, 16, 20, 24, and 28 pin
(JAMECO). Each socket has the pin-out labeled with a wire-wrap socket ID marker, which
slips onto the socket before wrapping (JAMECO). The part number is written onto the ID
marker.
Sockets are arranged in 4 horizontal rows on each board, with
about 10 sockets per row.
Power is distributed on the back-side of each board by bare 24-
gauge solid copper wire supply rails soldered at equal intervals
to Klipwrap terminals: 3-prong terminals with a square tail for
wire-wrapping (JAMECO 34163CL). A +5V rail runs above each
row of sockets and a ground rail runs below. Each rail connects
directly to the alum inum module power bus using a ring tail
connector.
On the pin side of the board, all connections are made with 30
AWG Kynar wire-wrap wire (JAMECO). Red wire is used for direct
connections to the +5V supply rail. Black w ire is used for direct connections to ground. White
wire is used for everything else.
Power connections from the supply rails to each ICs are double-wrapped. Bypassing
capacitors (.1 uf disc ) are soldered across the supply rails at the Klipwrap terminals; about 1
capacitor for every 2 IC packages.
All connections were stripped and hand-wrapped using a Radio Shack hand-wrap tool. As
each connection was made, the corresponding line on the schematic was marked with a
colored highlighter.
DIP resistor networks (JAMECO) plugged into 20-pin wire-wrap sockets were used as current
limiting resistors for the panel indicators.
CTL Printed Circuit Board (PCB) A
The A board contains the clock (CLK), the scaler (SCL), and the time pulse generator (TPG).
CTL Printed Circuit Board (PCB) B
The B board contains the display indicators, their current-limiting resistor networks, and the
open collector drivers. The display panel is a sheet of white styrene plastic. A push pin was
used to make holes through the plastic, and the LEDs were inserted in rows. The panel was
hand-lettered with an indelible marker. A few chips near the bottom right of the B board are
associated with subsystems on the C board.
CTL Printed Circuit Board (PCB) C
The C board contains the sequence generator (SEQ) and control pulse matrixes (CPM-A,
CPM-B, and CPM-C). The big ICs at the bottom are the EPROMs that hold the control pulse
matrix table for CPM-A. Each EPROM holds the tables for 8 control signals. The large ICs at
the top are decoders for the CPM-B and CPM-C logic.
Parts (ICs)
74LS00 (14) U74,U26,U27,U25,U79,U78,U55,U54,U53,U48,U13,U42,U34,U28
74LS02 (9) U4,U77,U9,U73,U45,U43,U3,U38,U32
74LS04 (15) U62,U29,U76,U69,U64,U57,U71,U59,U58,U56,U49,U41,U40,U39,U33
74LS06 (11) U22,U21,U20,U23,U14,U17,U18,U19,U16,U15,U1
74LS08 (2) U65,U10
74LS10 (4) U12,U70,U52,U51
74LS20 (8) U67,U68,U66,U63,U75,U61,U60,U6
74LS27 (3) U7,U44,U2
74LS32 (3) U72,U11,U5
74LS74 (1) U24
74LS112 (8) U8,U50,U47,U46,U35,U36,U37,U31
74LS138 (1) U99
74LS154 (7) U81,U82,U83,U98,U100,U101,U106
74LS161 (8) U104,U107,U108,U109,U110,U111,U112,U113
74LS244 (10) U80,U84,U85,U93,U94,U95,U96,U97,U102,U103
74LS273 (1) U105
27C128 (7) U86,U87,U88,U89,U90,U91,U92
4001 (1) U30
555 (1) U114
IC’s, sockets, PCB’s, resistors, capacitors, wire-wrap wire were purchased from JAMECO. The
2.048 MHz crystal and the IDE wire-wrap were from DigiKey. Wire ties, wire-wrap tools, and
copper wire were purchased from Radio Shack. IDE ribbon cables were purchased from an
online computer supplier.
Power Budget
qty mA (ea) mA (tot)
74LS00 14 2.4 33.6
74LS02 9 2.4 21.6
74LS04 15 3.6 54.0
74LS06 11 3.6 39.6
74LS08 2 4.4 8.8
74LS10 4 1.8 7.2
74LS20 8 1.2 9.6
74LS27 3 3.4 10.2
74LS32 3 4.9 14.7
74LS74 1 4.0 4.0
74LS112 8 4.0 32.0
74LS138 1 6.3 6.3
74LS154 7 6.2 43.4
74LS161 8 19.0 152.0
74LS244 10 32.0 320.0
74LS273 1 17.0 17.0
27C128 7 25.0 175.0
4001 1 0.4 0.4
555 1 3.0 3.0
LED 61 20.0 1220.0
-------
2.2 Amps total
1.0 Amps (excluding LEDs)
EPROM generator program
This C++ program generates all files needed to program the CPM-A EPROMs. The files are
generated in Motorola S-Record format.
/*
****************************************************************
*
* CPM-A EPROM GENERATOR
*
*9/14/01
*
*****************************************************************
Versions:
Derived from AGC C++ simulator 1.15.
Operation:
Generates all of the CPM-A EPROM files in Motorola s2f S-Record format
suitable for EPROM program mers.
*/
#include <str ing.h>
#include <stdlib.h>
#include <ctype.h>
#include <iostream.h>
#include <stdio.h>
#define MAXPULSES 15
#de fine M AX_IPULSES 5 // no m ore than 5 ins tru ct ion -gen erated pu lses act ive at any t ime
enum cpType { // **inferred; not defined in orignal R393 AGC 4 spec.
NO_PULSE=0,
// OUTPUTS FROM SUBSYSTEM A
CI =1, // C ar ry in
CLG =2, // Clear G
CLCTR =3, // Clear loop counter
CTR =4, // Loop counter
GP =5, // Gen erate Parity
KRPT =6, // Knock dow n Ru pt priority
NISQ =7, // New instruction to the SQ register
RA =8, // Read A
RB =9, // Read B
RB14 =10, // Read bit 14
RC =11, // Read C
RG =12, // Read G
RLP =13, // Read LP
RP2 =14, // Read parity 2
RQ =15, // Read Q
RRPA =16, // Read RU PT add ress
RSB =17, // R ead s ign bit
RSCT =18, // Read selected cou nter addre ss
RU =19, // Read sum
RZ =20, // Read Z
R1 =21, // Read 1
R1C =22, // Read 1 complimented
R2 =23, // Read 2
R22 =24, // Read 22
R24 =25, // Read 24
ST1 =26, // Stage 1
ST2 =27, // Stage 2
TMZ =28, // Test for minus zero
TOV =29, // Test for overflow
TP =30, // Test parity
TRSM =31, // Tes t fo r resume
TSGN =32, // Test sign
TSGN2 =33, // Test sign 2
WA =34, // Write A
WA LP =35, // Write A and LP
WB =36, // Write B
WGx =37, // Write G (do no t reset)
WLP =38, // Write LP
WOVC =39, // Write overf low counter
WOVI =40, // W rite over flow RU PT inh ibit
WOVR =41, // Write overflow
WP =42, // Write P
WPx =43, // Write P (do no t reset)
WP2 =44, // Write P2
WQ =45, // Write Q
WS =46, // Write S
WX =47, // Write X
WY =48, // Write Y
WYx =49, // Write Y (do no t reset)
WZ =50, // Write Z
// OUTPUTS FROM SUBSYSTEM A; USED AS INPUTS TO SUBSYSTEM B ONLY;
// NOT USED OUTS IDE CPM
RSC =51, // Read special and central (output to B only, not outside CPM)
WSC =52, // Write special and central (output to B only, not outside CPM)
WG =53, // Wr ite G (output to B only , not outs ide CPM)
// OUTPUTS FROM SUBSYSTEM A; USED AS INPUTS TO SUBSYSTEM C ONLY;
// NOT USED OUTS IDE CPM
SDV1 =54, // Subsequence D V1 is currently active
SMP1 =55, // Subsequence M P1 is currently active
SRSM3 =56, // Subsequence RS M3 is currently active
// EXTERNAL OUTPUTS FROM SUBSYSTEM B
//
RA0 =57, // Read register at address 0 (A)
RA1 =58, // Read reg is ter a t address 1 (Q)
RA2 =59, // Read register at address 2 (Z)
RA3 =60, // Read register at address 3 (LP)
RA4 =61, // Read reg ister at address 4
RA5 =62, // Read reg ister at address 5
RA6 =63, // Read reg ister at address 6
RA7 =64, // Read reg ister at address 7
RA10 =65, // R ead reg iste r a t add ress 10 (octal)
RA11 =66, // R ead reg iste r a t add ress 11 (octal)
RA12 =67, // R ead reg iste r a t add ress 12 (octal)
RA13 =68, // R ead reg iste r a t add ress 13 (octal)
RA14 =69, // R ead reg iste r a t add ress 14 (octal)
RBK =70, // Read BNK
WA0 =71, // Write register at address 0 (A)
WA1 =72, // Wr ite reg is ter a t address 1 (Q)
WA2 =73, // Write register at address 2 (Z)
WA3 =74, // Write register at address 3 (LP)
WA10 =75, // W rite regis ter a t add ress 10 (octal)
WA11 =76, // W rite regis ter a t add ress 11 (octal)
WA12 =77, // W rite regis ter a t add ress 12 (octal)
WA13 =78, // W rite regis ter a t add ress 13 (octal)
WA14 =79, // W rite regis ter a t add ress 14 (octal)
WBK =80, // Write BNK
WGn =81, // Write G (normal gates)**
W20 =82, // Write into CYR
W21 =83, // Write into SR
W22 =84, // Write into CYL
W23 =85, // Write into SL
// THESE ARE THE LEFTOVERS -- THEY 'RE PROBABLY USED IN SUBSYSTEM C
//
GENRST =86, // General Reset**
CLINH =87, // Clear INHINT**
CLINH1 =88, // Clear INHINT1**
CLSTA =89, // Clear state counter A (STA)**
CLSTB =90, // Clear state counter B (STB)**
CLISQ =91, // Clear SNI**
CLRP =92, // Clear RPCELL**
INH =93, // Set INHINT**
RPT =94, // Read RUPT opcode **
SBWG =95, // Write G from m emory
SETSTB =96, // Set the ST1 bit of STB
WE =97, // Wr ite E-MEM from G
WPCTR =98, // Write PCTR (latch priority counter sequence)**
WSQ =99, // Write SQ
WSTB =100, // Write stage counter B (STB)**
R2000 =101, // Read 2000 **
};
stat ic cpType glb l_cp[MAXPULSES]; // current set of asserted control pulses (MAXPULSES)
enum scType { // identif ies subsequence for a given instruction
SUB0=0, // ST2=0, ST1=0
SUB1=1, // ST2=0, ST1=1
SUB2=2, // ST2=1, ST1=0
SUB3=3 // ST2=1, ST1=1
};
enum brType {
BR00 =0, // BR1=0, BR2=0
BR01 =1, // BR1=0, BR2=1
BR10 =2, // BR1=1, BR2=0
BR11 =3, // BR1=1, BR2=1
NO_BR =4 // NO BRANCH
};
struct controlSubStep {
brType br; // normally no branch (NO_BR)
cpType pulse[MAX_IPULSES]; // contains 0 - MAXPULSES control pulses
};
struct controlStep {
controlSubStep substep[4]; // indexed by brType (BR00, BR01, BR10, BR11)
};
struct subsequence {
controlStep tp[11]; // indexed by tpType (TP1-TP11)
};
struct sequence {
subsequence* subseq[4]; // indexed by scType
};
#define STEP_INACTIVE \
NO_BR, {NO_ PULSE , NO _PU LSE , NO _PU LSE , NO _PU LSE , NO _PU LSE }, \
NO_BR, {NO_ PULSE , NO _PU LSE , NO _PU LSE , NO _PU LSE , NO _PU LSE }, \
NO_BR, {NO_ PULSE , NO _PU LSE , NO _PU LSE , NO _PU LSE , NO _PU LSE }, \
NO_BR, {NO_PULSE, NO_PULSE, NO_PULSE, NO_PULSE, NO_PULSE}
#de fine STE P(p1 , p2, p3 , p4, p5 ) \
NO_BR, { p1 , p2, p3, p4 , p5} , \
NO_BR, {NO_ PULSE , NO _PU LSE , NO _PU LSE , NO _PU LSE , NO _PU LSE }, \
NO_BR, {NO_ PULSE , NO _PU LSE , NO _PU LSE , NO _PU LSE , NO _PU LSE }, \
NO_BR, {NO_PULSE, NO_PULSE, NO_PULSE, NO_PULSE, NO_PULSE}
subsequence SUB_TC0 = {
STEP ( RB, WY, WS, CI, NO_PULSE ), // TP 1
STEP_INACTIVE, // TP 2
STEP ( WG, NO_PULSE, NO_PULSE, NO_PULSE, NO_PULSE ), // TP 3
STEP ( RA, WOV I, NO_PULSE, NO_PULSE, NO_PULSE ), // TP 4
STEP_INACTIVE, // TP 5
STEP_INACTIVE, // TP 6
STEP ( RG, RSC, WB, WP, NO_PULSE ), // TP 7
STEP ( RZ, WQ, GP, TP, NO_PULSE ), // TP 8
STEP ( RB, WSC, WG, NO_PULSE, NO_PULSE ), // TP 9
STEP ( RU, WZ, NO_PULSE, NO_PULSE, NO_PULSE ), // TP 10
STEP ( NISQ, NO_PULSE, NO_PULSE, NO_PULSE, NO_PULSE ), // TP 11
};
subsequence SUB_CCS0 = {
STEP ( RB, WS, NO_PULSE, NO_PULSE, NO_PULSE ), // TP 1
STEP ( RZ, WY, NO_PULSE, NO_PULSE, NO_PULSE ), // TP 2
STEP ( WG, NO_PULSE, NO_PULSE, NO_PULSE, NO_PULSE ), // TP 3
STEP_INACTIVE, // TP 4
STEP_INACTIVE, // TP 5
STEP ( RG, RSC, WB, TSGN, WP ), // TP 6
BR00, RC, TMZ, NO_PULSE, NO_PULSE, NO_PULSE, // TP 7
BR01, RC, TMZ, NO_PULSE, NO_PULSE, NO_PULSE,
BR10, RB, TMZ, NO_PULSE, NO_PULSE, NO_PULSE,
BR11, RB, TMZ, NO_PULSE, NO_PULSE, NO_PULSE,
BR00, GP, TP, NO_PULSE, NO_PULSE, NO_PULSE, // TP 8
BR01, R1, WX, GP, TP, NO_PULSE,
BR10, R2, WX, GP, TP, NO_PULSE,
BR11, R1, R2, WX, GP, TP,
STEP ( RB, WSC, WG, NO_PULSE, NO_PULSE ), // TP 9
BR00, RC, WA, NO_PULSE, NO_PULSE, NO_PULSE, // TP 10
BR01, WA, R1C, NO_PULSE, NO_PULSE, NO_PULSE,
BR10, RB, WA, NO_PULSE, NO_PULSE, NO_PULSE,
BR11, WA, R1C, NO_PULSE, NO_PULSE, NO_PULSE,
STEP ( RU, ST1, WZ, NO_PULSE, NO_PULSE ) // TP 11
};
subsequence SUB_CCS1 = {
STEP ( RZ, WY, WS, CI, NO_PULSE ), // TP 1
STEP_INACTIVE, // TP 2
STEP ( WG, NO_PULSE, NO_PULSE, NO_PULSE, NO_PULSE ), // TP 3
STEP ( RU, WZ, NO_PULSE, NO_PULSE, NO_PULSE ), // TP 4
STEP ( RA, WY, CI, NO_PULSE, NO_PULSE ), // TP 5
STEP_INACTIVE, // TP 6
STEP ( RG, RSC, WB, WP, NO_PULSE ), // TP 7
STEP ( RU, WB, GP, TP, NO_PULSE ), // TP 8
STEP_INACTIVE, // TP 9
STEP ( RC, WA, WOV I, NO_PULSE, NO_PULSE ), // TP 10
STEP ( RG, RSC, WB, NISQ, NO_PULSE ) // TP 11
};
subsequence SUB_NDX0 = {
STEP ( RB, WS, NO_PULSE, NO_PULSE, NO_PULSE ), // TP 1
STEP_INACTIVE, // TP 2
STEP ( WG, NO_PULSE, NO_PULSE, NO_PULSE, NO_PULSE ), // TP 3
STEP ( RA, WOV I, NO_PULSE, NO_PULSE, NO_PULSE ), // TP 4
STEP_INACTIVE, // TP 5
STEP_INACTIVE, // TP 6
STEP ( RG, RSC, WB, WP, NO_PULSE ), // TP 7
STEP ( GP, TP, NO_PULSE, NO_PULSE, NO_PULSE ), // TP 8
STEP ( RB, WSC, WG, NO_PULSE, NO_PULSE ), // TP 9
STEP ( TRSM, NO_PULSE, NO_PULSE, NO_PULSE, NO_PULSE ), // TP 10
STEP ( ST1, NO_PULSE, NO_PULSE, NO_PULSE, NO_PULSE ), // TP 11
};
subsequence SUB_NDX1 = {
STEP ( RZ, WY, WS, CI, NO_PULSE ), // TP 1
STEP_INACTIVE, // TP 2
STEP ( WG, NO_PULSE, NO_PULSE, NO_PULSE, NO_PULSE ), // TP 3
STEP ( RU, WZ, NO_PULSE, NO_PULSE, NO_PULSE ), // TP 4
STEP_INACTIVE, // TP 5
STEP ( RB, WY, NO_PULSE, NO_PULSE, NO_PULSE ), // TP 6
STEP ( RG, RSC, WB, WP, NO_PULSE ), // TP 7
STEP ( RB, WX, GP, TP, NO_PULSE ), // TP 8
STEP ( RB, WSC, WG, NO_PULSE, NO_PULSE ), // TP 9
STEP_INACTIVE, // TP 10
STEP ( RU, WB, WOV I, NISQ, NO_PULSE ), // TP 11
};
subsequence SUB_RSM3 = {
STEP ( R24, WS, NO_PULSE, NO_PULSE, NO_PULSE ), // TP 1
STEP_INACTIVE, // TP 2
STEP ( WG, NO_PULSE, NO_PULSE, NO_PULSE, NO_PULSE ), // TP 3
STEP_INACTIVE, // TP 4
STEP_INACTIVE, // TP 5
STEP_INACTIVE, // TP 6
STEP ( RG, WZ, NO_PULSE, NO_PULSE, NO_PULSE ), // TP 7
STEP_INACTIVE, // TP 8
STEP_INACTIVE, // TP 9
STEP_INACTIVE, // TP 10
STEP ( NISQ, NO_PULSE, NO_PULSE, NO_PULSE, NO_PULSE ), // TP 11
};
subsequence SUB_XCH0 = {
STEP ( RB, WS, NO_PULSE, NO_PULSE, NO_PULSE ), // TP 1
STEP ( RA, WP, NO_PULSE, NO_PULSE, NO_PULSE ), // TP 2
STEP ( WG, NO_PULSE, NO_PULSE, NO_PULSE, NO_PULSE ), // TP 3
STEP ( WP2, NO_PULSE, NO_PULSE, NO_PULSE, NO_PULSE ), // TP 4
STEP_INACTIVE, // TP 5
STEP_INACTIVE, // TP 6
STEP ( RG, RSC, WB, WP, NO_PULSE ), // TP 7
STEP ( GP, TP, NO_PULSE, NO_PULSE, NO_PULSE ), // TP 8
STEP ( RA, WSC, WG, RP2, NO_PULSE ), // TP 9
STEP ( RB, WA, WOV I, NO_PULSE, NO_PULSE ), // TP 10
STEP ( ST2, NO_PULSE, NO_PULSE, NO_PULSE, NO_PULSE ), // TP 11
};
subsequence SUB_CS0 = {
STEP ( RB, WS, NO_PULSE, NO_PULSE, NO_PULSE ), // TP 1
STEP_INACTIVE, // TP 2
STEP ( WG, NO_PULSE, NO_PULSE, NO_PULSE, NO_PULSE ), // TP 3
STEP_INACTIVE, // TP 4
STEP_INACTIVE, // TP 5
STEP_INACTIVE, // TP 6
STEP ( RG, RSC, WB, WP, NO_PULSE ), // TP 7
STEP ( GP, TP, NO_PULSE, NO_PULSE, NO_PULSE ), // TP 8
STEP ( RB, WSC, WG, NO_PULSE, NO_PULSE ), // TP 9
STEP ( RC, WA, WOV I, NO_PULSE, NO_PULSE ), // TP 10
STEP ( ST2, NO_PULSE, NO_PULSE, NO_PULSE, NO_PULSE ), // TP 11
};
subsequence SUB_TS0 = {
STEP ( RB, WS, NO_PULSE, NO_PULSE, NO_PULSE ), // TP 1
STEP ( RA, WB, TOV, WP, NO_PULSE
), // TP 2
STEP ( WG, NO_PULSE, NO_PULSE, NO_PULSE, NO_PULSE ), // TP 3
BR00, NO_PULSE, NO_PULSE, NO_PULSE, NO_PULSE, NO_PULSE, // TP 4
BR01, RZ, WY, CI, NO_PULSE, NO_PULSE, //
overflow
BR10, RZ, WY, CI, NO_PULSE, NO_PULSE, //
underflow
BR11, NO_PULSE, NO_PULSE, NO_PULSE, NO_PULSE, NO_PULSE,
BR00, NO_PULSE, NO_PULSE, NO_PULSE, NO_PULSE, NO_PULSE, // TP 5
BR01, R1, WA, NO_PULSE, NO_PULSE, NO_PULSE,
BR10, WA, R1C, NO_PULSE, NO_PULSE, NO_PULSE,
BR11, NO_PULSE, NO_PULSE, NO_PULSE, NO_PULSE, NO_PULSE,
STEP_INACTIVE, // TP 6
BR00, NO_PULSE, NO_PULSE, NO_PULSE, NO_PULSE, NO_PULSE, // TP 7
BR01, RU, WZ, NO_PULSE, NO_PULSE, NO_PULSE,
BR10, RU, WZ, NO_PULSE, NO_PULSE, NO_PULSE,
BR11, NO_PULSE, NO_PULSE, NO_PULSE, NO_PULSE, NO_PULSE,
STEP ( GP, NO_PULSE, NO_PULSE, NO_PULSE, NO_PULSE ), // TP 8
STEP ( RB, WSC, WG, NO_PULSE, NO_PULSE
), // TP 9
STEP ( RA, WOV I, NO_PULSE, NO_PULSE, NO_PULSE ), // TP 10
STEP ( ST2, NO_PULSE, NO_PULSE, NO_PULSE, NO_PULSE ), // TP 11
};
subsequence SUB_AD0 = {
STEP ( RB, WS, NO_PULSE, NO_PULSE, NO_PULSE ), // TP 1
STEP ( RA, WY, NO_PULSE, NO_PULSE, NO_PULSE ), // TP 2
STEP ( WG, NO_PULSE, NO_PULSE, NO_PULSE, NO_PULSE ), // TP 3
STEP_INACTIVE, // TP 4
STEP_INACTIVE, // TP 5
STEP_INACTIVE, // TP 6
STEP ( RG, RSC, WB, WP, NO_PULSE ), // TP 7
STEP ( RB, WX, GP, TP, NO_PULSE ), // TP 8
STEP ( RB, WSC, WG, NO_PULSE, NO_PULSE ), // TP 9
STEP_INACTIVE, // TP 10
STEP ( RU, WA, WOVC, ST2, WOVI ), // TP 11
};
// No te: AND is perfo rmed u sing D eM orga n's Theorem: the inpu ts are inver ted , a
// logical OR is performed, and the result is inverted. The implementation of the
// OR (at TP8 ) is somewh at unorthodox: the inverted inpu ts are in registers U
// and C. The OR is achieved by gating both registers onto the read/write bus
// simu ltaneously. (The bus on ly transfers logical 1's; register-to-register transfers
// are performed by clearing the destination register and then transferr ing the
// 1's from the source register to th e destination). When the 1 's from both
// registers are simultaneously gated onto the bus, the word on the bus is a logical
// OR of both reg isters.
subsequence SUB_MASK0 = {
STEP ( RB, WS, NO_PULSE, NO_PULSE, NO_PULSE ), // TP 1
STEP ( RA, WB, NO_PULSE, NO_PULSE, NO_PULSE ), // TP 2
STEP ( WG, NO_PULSE, NO_PULSE, NO_PULSE, NO_PULSE ), // TP 3
STEP ( RC, WY, NO_PULSE, NO_PULSE, NO_PULSE ), // TP 4
STEP_INACTIVE, // TP 5
STEP_INACTIVE, // TP 6
STEP ( RG, RSC, WB, WP, NO_PULSE ), // TP 7
STEP ( RU, RC, WA, GP, TP ), // TP 8
(CHANGED)
STEP_INACTIVE, // TP 9
STEP ( RA, WB, NO_PULSE, NO_PULSE, NO_PULSE ), // TP 10
(CHANGED)
STEP ( RC, WA, ST2, WOV I, NO_PULSE ), // TP 11
};
subsequence SUB_MP0 = {
STEP ( RB, WS, NO_PULSE, NO_PULSE, NO_PULSE ), // TP 1
STEP ( RA, WB, TSGN, NO_PULSE, NO_PULSE ), // TP 2
STEP ( RSC, WG, NO_PULSE, NO_PULSE, NO_PULSE ), // TP 3
BR00, RB, WLP, NO_PULSE, NO_PULSE, NO_PULSE, // TP 4
BR01, RB, WLP, NO_PULSE, NO_PULSE, NO_PULSE,
BR10, RC, WLP, NO_PULSE, NO_PULSE, NO_PULSE,
BR11, RC, WLP, NO_PULSE, NO_PULSE, NO_PULSE,
STEP ( RLP, WA, NO_PULSE, NO_PULSE, NO_PULSE ), // TP 5
STEP_INACTIVE, // TP 6
BR00, RG, WY, WP, NO_PULSE, NO_PULSE, // TP 7
BR01, RG, WY, WP, NO_PULSE, NO_PULSE,
BR10, RG, WB, WP, NO_PULSE, NO_PULSE,
BR11, RG, WB, WP, NO_PULSE, NO_PULSE,
BR00, GP, TP, NO_PULSE, NO_PULSE, NO_PULSE, // TP 8
BR01, GP, TP, NO_PULSE, NO_PULSE, NO_PULSE,
BR10, RC, WY, GP, TP, NO_PULSE,
BR11, RC, WY, GP, TP, NO_PULSE,
STEP ( RU, WB, TSGN2, NO_PULSE, NO_PULSE ), // TP 9
BR00, RA, WLP, TSGN, NO_PULSE, NO_PULSE, // TP 10
BR01, RA, RB14, WLP, TSGN, NO_PULSE,
BR10, RA, WLP, TSGN, NO_PULSE, NO_PULSE,
BR11, RA, RB14, WLP, TSGN, NO_PULSE,
BR00, ST1, WALP, NO_PULSE, NO_PULSE, NO_PULSE, // TP 11
BR01, R1, ST1, WALP, R1C, NO_PULSE,
BR10, RU, ST1, WALP, NO_PULSE, NO_PULSE,
BR11, RU, ST1, WALP, NO_PULSE, NO_PULSE,
};
subsequence SUB_MP1 = {
STEP ( RA, WY, NO_PULSE, NO_PULSE, NO_PULSE ), // TP 1
STEP ( RLP, WA, TSGN, NO_PULSE, NO_PULSE ), // TP 2
BR00, NO_PULSE, NO_PULSE, NO_PULSE, NO_PULSE, NO_PULSE, // TP 3
BR01, NO_PULSE, NO_PULSE, NO_PULSE, NO_PULSE, NO_PULSE,
BR10, RB, WX, NO_PULSE, NO_PULSE, NO_PULSE,
BR11, RB, WX, NO_PULSE, NO_PULSE, NO_PULSE,
STEP ( RA, WLP, NO_PULSE, NO_PULSE, NO_PULSE ), // TP 4
STEP ( RLP, TSGN, NO_PULSE, NO_PULSE, NO_PULSE ), // TP 5
STEP ( RU, WALP, NO_PULSE, NO_PULSE, NO_PULSE ), // TP 6
STEP ( RA, WY, NO_PULSE, NO_PULSE, NO_PULSE ), // TP 7
BR00, NO_PULSE, NO_PULSE, NO_PULSE, NO_PULSE, NO_PULSE, // TP 8
BR01, NO_PULSE, NO_PULSE, NO_PULSE, NO_PULSE, NO_PULSE,
BR10, RB, WX, NO_PULSE, NO_PULSE, NO_PULSE,
BR11, RB, WX, NO_PULSE, NO_PULSE, NO_PULSE,
STEP ( RLP, WA, NO_PULSE, NO_PULSE, NO_PULSE ), // TP 9
STEP ( RA, WLP, CTR, NO_PULSE, NO_PULSE ), // TP 10
STEP ( RU, ST1, WALP, NO_PULSE, NO_PULSE ), // TP 11
};
subsequence SUB_MP3 = {
STEP ( RZ, WY, WS, CI, NO_PULSE ), // TP 1
STEP ( RLP, TSGN, NO_PULSE, NO_PULSE, NO_PULSE ), // TP 2
STEP ( WG, NO_PULSE, NO_PULSE, NO_PULSE, NO_PULSE ), // TP 3
STEP ( RU, WZ, NO_PULSE, NO_PULSE, NO_PULSE ), // TP 4
STEP ( RA, WY, NO_PULSE, NO_PULSE, NO_PULSE ), // TP 5
BR00, NO_PULSE, NO_PULSE, NO_PULSE, NO_PULSE, NO_PULSE, // TP 6
BR01, NO_PULSE, NO_PULSE, NO_PULSE, NO_PULSE, NO_PULSE,
BR10, RB, WX, NO_PULSE, NO_PULSE, NO_PULSE,
BR11, RB, WX, NO_PULSE, NO_PULSE, NO_PULSE,
STEP ( RG, RSC, WB, WP, NO_PULSE ), // TP 7
STEP ( RLP, WA, GP, TP, NO_PULSE ), // TP 8
STEP ( RB, WSC, WG, NO_PULSE, NO_PULSE ), // TP 9
STEP ( RA, WLP, NO_PULSE, NO_PULSE, NO_PULSE ), // TP 10
STEP ( RU, WALP, NISQ, NO_PULSE, NO_PULSE ), // TP 11
};
subsequence SUB_DV0 = {
STEP ( RB, WS, NO_PULSE, NO_PULSE, NO_PULSE ), // TP 1
STEP ( RA, WB, TSGN, NO_PULSE, NO_PULSE ), // TP 2
STEP ( RSC, WG, NO_PULSE, NO_PULSE, NO_PULSE ), // TP 3
BR00, RC, WA, NO_PULSE, NO_PULSE, NO_PULSE, // TP 4
BR01, RC, WA, NO_PULSE, NO_PULSE, NO_PULSE,
BR10, NO_PULSE, NO_PULSE, NO_PULSE, NO_PULSE, NO_PULSE,
BR11, NO_PULSE, NO_PULSE, NO_PULSE, NO_PULSE, NO_PULSE,
BR00, R1, WLP, NO_PULSE, NO_PULSE, NO_PULSE, // TP 5
BR01, R1, WLP, NO_PULSE, NO_PULSE, NO_PULSE,
BR10, R2, WLP, NO_PULSE, NO_PULSE, NO_PULSE,
BR11, R2, WLP, NO_PULSE, NO_PULSE, NO_PULSE,
STEP ( RA, WQ, NO_PULSE, NO_PULSE, NO_PULSE ), // TP 6
STEP ( RG, WB, TSGN, WP, NO_PULSE ), // TP 7
STEP ( RB, WA, GP, TP, NO_PULSE ), // TP 8
BR00, RLP, R2, WB, NO_PULSE, NO_PULSE, // TP 9
BR01, RLP, R2, WB, NO_PULSE, NO_PULSE,
BR10, NO_PULSE, NO_PULSE, NO_PULSE, NO_PULSE, NO_PULSE,
BR11, NO_PULSE, NO_PULSE, NO_PULSE, NO_PULSE, NO_PULSE,
BR00, RB, WLP, NO_PULSE, NO_PULSE, NO_PULSE, // TP 10
BR01, RB, WLP, NO_PULSE, NO_PULSE, NO_PULSE,
BR10, RC, WA, NO_PULSE, NO_PULSE, NO_PULSE,
BR11, RC, WA, NO_PULSE, NO_PULSE, NO_PULSE,
STEP ( R1, ST1, WB, NO_PULSE, NO_PULSE ), // TP 11
};
subsequence SUB_DV1 = {
STEP ( R22, WS, NO_PULSE, NO_PULSE, NO_PULSE ), // TP 1
STEP ( RQ, WG, NO_PULSE, NO_PULSE, NO_PULSE ), // TP 2
STEP ( RG, WQ, WY, RSB, NO_PULSE ), // TP 3
STEP ( RA, WX, NO_PULSE, NO_PULSE, NO_PULSE ), // TP 4
STEP ( RLP, TSGN2, NO_PULSE, NO_PULSE, NO_PULSE ), // TP 5
STEP_INACTIVE, // TP 6
STEP ( RU, TSGN, NO_PULSE, NO_PULSE, NO_PULSE ), // TP 7
BR00, NO_PULSE, NO_PULSE, NO_PULSE, NO_PULSE, NO_PULSE, // TP 8
BR01, NO_PULSE, NO_PULSE, NO_PULSE, NO_PULSE, NO_PULSE,
BR10, RU, WQ, NO_PULSE, NO_PULSE, NO_PULSE,
BR11, RU, WQ, NO_PULSE, NO_PULSE, NO_PULSE,
BR00, RB, RSB, WG, NO_PULSE, NO_PULSE, // TP 9
BR01, RB, RSB, WG, NO_PULSE, NO_PULSE,
BR10, RB, WG, NO_PULSE, NO_PULSE, NO_PULSE,
BR11, RB, WG, NO_PULSE, NO_PULSE, NO_PULSE,
STEP ( RG, WB, TSGN, NO_PULSE, NO_PULSE ), // TP 10
BR00, ST1, NO_PULSE, NO_PULSE, NO_PULSE, NO_PULSE, // TP 11
BR01, ST1, NO_PULSE, NO_PULSE, NO_PULSE, NO_PULSE,
BR10, RC, WA, ST2, NO_PULSE, NO_PULSE,
BR11, RB, WA, ST2, NO_PULSE, NO_PULSE,
};
subsequence SUB_SU0 = {
STEP ( RB, WS, NO_PULSE, NO_PULSE, NO_PULSE ), // TP 1
STEP ( RA, WY, NO_PULSE, NO_PULSE, NO_PULSE ), // TP 2
STEP ( WG, NO_PULSE, NO_PULSE, NO_PULSE, NO_PULSE ), // TP 3
STEP_INACTIVE, // TP 4
STEP_INACTIVE, // TP 5
STEP_INACTIVE, // TP 6
STEP ( RG, RSC, WB, WP, NO_PULSE ), // TP 7
STEP ( RC, WX, GP, TP, NO_PULSE ), // TP 8
STEP ( RB, WSC, WG, NO_PULSE, NO_PULSE ), // TP 9
STEP_INACTIVE, // TP 10
STEP ( RU, WA, WOVC, ST2, WOVI ), // TP 11
};
subsequence SUB_RUPT1 = {
STEP ( R24, WY, WS, CI, NO_PULSE ), // TP 1
STEP_INACTIVE, // TP 2
STEP ( WG, NO_PULSE, NO_PULSE, NO_PULSE, NO_PULSE ), // TP 3
STEP_INACTIVE, // TP 4
STEP_INACTIVE, // TP 5
STEP_INACTIVE, // TP 6
STEP_INACTIVE, // TP 7
STEP_INACTIVE, // TP 8
STEP ( RZ, WG, NO_PULSE, NO_PULSE, NO_PULSE ), // TP 9
STEP ( RU, WZ, NO_PULSE, NO_PULSE, NO_PULSE ), // TP 10
STEP ( ST1, ST2, NO_PULSE, NO_PULSE, NO_PULSE ), // TP 11
};
subsequence SUB_RUPT3 = {
STEP ( RZ, WS, NO_PULSE, NO_PULSE, NO_PULSE ), // TP 1
STEP ( RRPA, WZ, NO_PULSE, NO_PULSE, NO_PULSE ), // TP 2
STEP ( RZ, KRPT, WG, NO_PULSE, NO_PULSE ), // TP 3
STEP_INACTIVE, // TP 4
STEP_INACTIVE, // TP 5
STEP_INACTIVE, // TP 6
STEP_INACTIVE, // TP 7
STEP_INACTIVE, // TP 8
STEP ( RB, WSC, WG, NO_PULSE, NO_PULSE ), // TP 9
STEP_INACTIVE, // TP 10
STEP ( ST2, NO_PULSE, NO_PULSE, NO_PULSE, NO_PULSE ), // TP 11
};
subsequence SUB_STD2 = {
STEP ( RZ, WY, WS, CI, NO_PULSE ), // TP 1
STEP_INACTIVE, // TP 2
STEP ( WG, NO_PULSE, NO_PULSE, NO_PULSE, NO_PULSE ), // TP 3
STEP ( RU, WZ, NO_PULSE, NO_PULSE, NO_PULSE ), // TP
STEP_INACTIVE, // TP 5
STEP_INACTIVE, // TP 6
STEP ( RG, RSC, WB, WP, NO_PULSE ), // TP 7
STEP ( GP, TP, NO_PULSE, NO_PULSE, NO_PULSE ), // TP 8
STEP ( RB, WSC, WG, NO_PULSE, NO_PULSE ), // TP 9
STEP_INACTIVE, // TP 10
STEP ( NISQ, NO_PULSE, NO_PULSE, NO_PULSE, NO_PULSE ), // TP 11
};
subsequence SUB_PINC = {
STEP ( WS, RSCT, NO_PULSE, NO_PULSE, NO_PULSE ), // TP 1
STEP_INACTIVE, // TP 2
STEP ( WG, NO_PULSE, NO_PULSE, NO_PULSE, NO_PULSE ), // TP 3
STEP ( R1, WY, NO_PULSE, NO_PULSE, NO_PULSE ), // TP 4
STEP_INACTIVE, // TP 5
STEP ( RG, WX, WP, NO_PULSE, NO_PULSE ), // TP 6
STEP ( TP, NO_PULSE, NO_PULSE, NO_PULSE, NO_PULSE ), // TP 7
STEP ( WP, NO_PULSE, NO_PULSE, NO_PULSE, NO_PULSE ), // TP 8
STEP ( RU, CLG, WPx, NO_PULSE, NO_PULSE ), // TP 9
STEP ( RU, WG x, WOVR, NO_PULSE, NO_PULSE ), // TP 10
STEP_INACTIVE, // TP 11
};
subsequence SUB_MINC = {
STEP ( WS, RSCT, NO_PULSE, NO_PULSE, NO_PULSE ), // TP 1
STEP_INACTIVE, // TP 2
STEP ( WG, NO_PULSE, NO_PULSE, NO_PULSE, NO_PULSE ), // TP 3
STEP ( WY, R1C, NO_PULSE, NO_PULSE, NO_PULSE ), // TP 4
STEP_INACTIVE, // TP 5
STEP ( RG, WX, WP, NO_PULSE, NO_PULSE ), // TP 6
STEP ( TP, NO_PULSE, NO_PULSE, NO_PULSE, NO_PULSE ), // TP 7
STEP ( WP, NO_PULSE, NO_PULSE, NO_PULSE, NO_PULSE ), // TP 8
STEP ( RU, CLG, WPx, NO_PULSE, NO_PULSE ), // TP 9
STEP ( RU, WG x, WOVR, NO_PULSE, NO_PULSE ), // TP 10
STEP_INACTIVE, // TP 11
};
subsequence SUB_SHINC = {
STEP ( WS, RSCT, NO_PULSE, NO_PULSE, NO_PULSE ), // TP 1
STEP_INACTIVE, // TP 2
STEP ( WG, NO_PULSE, NO_PULSE, NO_PULSE, NO_PULSE ), // TP 3
STEP ( WY, NO_PULSE, NO_PULSE, NO_PULSE, NO_PULSE ), // TP 4
STEP_INACTIVE, // TP 5
STEP ( RG, WYx, WX, WP, NO_PULSE ), // TP 6
STEP ( TP, NO_PULSE, NO_PULSE, NO_PULSE, NO_PULSE ), // TP 7
STEP ( WP, NO_PULSE, NO_PULSE, NO_PULSE, NO_PULSE ), // TP 8
STEP ( RU, CLG, WPx, NO_PULSE, NO_PULSE ), // TP 9
STEP ( RU, WG x, WOVR, NO_PULSE, NO_PULSE ), // TP 10
STEP_INACTIVE, // TP 11
};
char* subse qString [] =
{
"TC0",
"CCS0 ",
"CCS1 ",
"NDX0 ",
"NDX1 ",
"RSM3 ",
"XCH0",
"CS0",
"TS0",
"AD0",
"MAS K0",
"MP0",
"MP1",
"MP3",
"DV0",
"DV1",
"SU0",
"RUPT1",
"RUPT3",
"STD2 ",
"PINC0",
"MINC0",
"SHINC0 ",
"NO_SEQ"
};
enum subseq {
TC0 =0,
CCS0 =1,
CCS1 =2,
NDX0 =3,
NDX1 =4,
RSM3 =5,
XCH0 =6,
CS0 =7,
TS0 =8,
AD0 =9,
MASK0 =10,
MP0 =11,
MP1 =12,
MP3 =13,
DV0 =14,
DV1 =15,
SU0 =16,
RUPT1 =17,
RUPT3 =18,
STD2 =19,
PINC0 =20,
MINC0 =21,
SHINC0 =22,
NO_SEQ =23
};
enum tpType {
STBY =0,
PWRON =1,
TP1 =2, // TIME PULSE 1: start of memory cycle t ime (MCT)
TP2 =3,
TP3 =4,
TP4 =5,
TP5 =6,
TP6 =7, // EMEM is available in G register by TP6
TP7 =8, // FMEM is available in G register by TP7
TP8 =9,
TP9 =10,
TP10 =11, // G register written to memory beginning at TP10
TP11 =12, // TIME PULSE 11: end of memory cycle t ime (MCT)
TP12 =13, // select new subsequence/select new instruction
SRLSE =14, // step switch release
WAIT =15
};
subseq instructionSubsequenceD ecoder(
int SB2_field, int SB1_field, int SQ_field, int STB_field)
{
// Com binationa l logic decodes instru ction and the stage coun t
// to get the instruction subsequence.
static subseq decode[16][4] = {
{ TC0, RUPT1, STD2, RUPT3 }, // 00
{ CCS0, CCS1, NO_SEQ, NO_SEQ }, // 01
{ NDX0, NDX1, NO_SEQ, RSM3 }, // 02
{ XCH0, NO_SEQ, STD2, NO_SEQ }, // 03
{ NO_SEQ, NO_SEQ, NO_SEQ, NO_SEQ }, // 04
{ NO_SEQ, NO_SEQ, NO_SEQ, NO_SEQ }, // 05
{ NO_SEQ, NO_SEQ, NO_SEQ, NO_SEQ }, // 06
{ NO_SEQ, NO_SEQ, NO_SEQ, NO_SEQ }, // 07
{ NO_SEQ, NO_SEQ, NO_SEQ, NO_SEQ }, // 10
{ MP0, MP1, NO_SEQ, MP3 }, // 11
{ DV0, DV1, STD2, NO_SEQ }, // 12
{ SU0, NO_SEQ, STD2, NO_SEQ }, // 13
{ CS0, NO_SEQ, STD2, NO_SEQ }, // 14
{ TS0, NO_SEQ, STD2, NO_SEQ }, // 15
{ AD0, NO_SEQ, STD2, NO_SEQ }, // 16
{ MASK0, NO_SEQ, STD2, NO_SEQ } // 17
};
if(SB2_field == 0 && SB1_field == 1)
return PINC0;
else if(SB2_field == 1 && SB1_field == 0)
return MINC0;
else
return decode[SQ_ field][STB_ field];
}
void clearControlPu lses()
{
for(unsigned i=0; i<MAXPULSES; i++)
glbl_cp[i] = NO_PULSE;
}
void assert(cpType* pulse)
{
int j=0;
for(unsigned i=0; i<MAXPULSES && j<MAX_IPULSES && pulse[j] != NO_PULSE; i++)
{
if(glbl_cp[i] == NO_PULSE)
{
glbl_cp[i] = pu lse[j];
j++;
}
}
}
void assert(cpType pulse)
{
for(unsigned i=0; i<MAXPULSES; i++)
{
if(glbl_cp[i] == NO_PULSE)
{
glbl_cp[i] = pulse;
break;
}
}
}
void get_CPM_A (int CPM_A _addre ss)
{
// EPROM address bits (bit 1 is LSB)
// 1: register BR2
// 2: register BR1
// 3-6: register SG (4)
// 7,8: register STB (2)
// 9-12: register SQ (4)
// 13: STB_01
// 14: STB_02
//***********************************************************
// EPROM emulator
int SB2_field = (CPM_A_address >> 13) & 0x1;
int SB1_field = (CPM_A_address >> 12) & 0x1;
int SQ_ field = (CPM _A_address >> 8 ) & 0 xf;
int STB_field = (CPM_A_address >> 6) & 0x3;
int SG_ field = (CPM _A_address >> 2 ) & 0 xf;
int BR1_field = (CPM_A_address >> 1) & 0x1;
int BR2_field = (CPM_A_address ) & 0x1;
// Decode the cu rrent instru ction subsequ ence (glbl_subse q).
subse q glbl_subseq = instructionSubse quenceD ecoder(SB 2_field, SB1_field, SQ _field, STB_field);
static subsequence* subsp[] =
{
&SUB_TC0, &SUB_CCS0, &SUB_CCS1, &SUB_NDX0, &SUB_NDX1, &SUB_RSM3,
&SUB_XCH0, &SUB_CS0, &SUB_TS0, &SUB_AD0, &SUB_MASK0, &SUB_MP0,
&SUB_MP1, &SUB_MP3, &SUB_DV0, &SUB_DV1, &SUB_SU0, &SUB_RUPT1,
&SUB_RUPT3, &SUB_STD2, &SUB_PINC, &SUB_MINC, &SUB_SHIN C,0
};
// Clear old control pulses.
clearControlPulses ();
// Get new control pulses for the current instruction subsequence.
if(glb l_subseq != NO_SEQ && // THIS TESTS OUT OK
SG_fie ld >= TP1 &&
SG_field <= TP11)
{
subse quence* subseqP = subsp [glbl_subse q];
if(subseqP)
{
// index t-2 because TP1= 2, but array is indexed from zero
contro lStep& csref = subse qP-> tp[SG _field-2];
brTyp e b = (brType) ((BR1_field << 1) | BR2_field);
contro lSubS tep& cssref = csref.substep[b ];
if(cssref.br == NO_BR)
cssref = csref.substep[0 ];
cpType* p = cssref.pulse;
asser t(p);
}
}
// Implement these h ere, becau se the instruction sequence de coder
// function is buried in the CPM-A ROM and so, identif ication of
// the se quences is no t availab le ou tside CPM-A. CPM-C needs info
// on these 3 sequences.
switch(glbl_subseq)
{
case DV1: assert(SDV1); break;
case MP1: assert(SMP1); break;
case RSM3: assert(SRSM3); break;
}
//***********************************************************
}
char* cpTypeStr ing[] =
{
"NO_PU LSE",
/ / OUTPUTS FROM SUBSYSTEM A
"CI" , "CLG" , "CLCTR", "C TR", "GP", "K RPT ", "NISQ ", "RA ", "RB ",
"RB 14", "RC ", "RG ", "RLP", "R P2" , "RQ ", "RR PA", "RS B", "RSCT ",
"RU ", "RZ ", "R1 ", "R1 C", "R2", "R2 2", "R 24", "ST1", "ST2", "TM Z",
"TO V", "TP" , "TRSM ", "TS GN ", "TS GN 2", "W A", "WALP ", "W B", "WGx",
"WLP", "WOV C", "WOV I", "W OV R", "W P", "W Px" , "WP2" , "WQ", "WS",
"WX", "WY", "WYx", "WZ",
// OUTPUTS FROM SUBSYSTEM A; USED AS INPUTS TO SUBSYSTEM B ONLY;
// NOT USED OUTS IDE CPM
//
"RSC", "WS C", "WG",
// OUTPUTS FROM SUBSYSTEM A; USED AS INPUTS TO SUBSYSTEM C ONLY;
// NOT USED OUTS IDE CPM
//
"SDV1 ", "SMP1", "SRSM 3",
/ / EXTERNAL OUTPUTS FROM SUBSYSTEM B
//
"RA 0", "R A1", "RA 2", "R A3", "RA 4", "R A5", "RA 6", "R A7", "RA 10", "RA 11",
"RA 12", "RA 13", "RA 14", "RB K", "W A0", "W A1", "W A2", "W A3", "W A10",
"WA1 1", "WA12", "WA 13", "WA14 ", "WBK", "WG n", "W20", "W21 ", "W22", "W23",
/ / THESE ARE THE LEFTOVERS -- THEY 'RE PROBABLY USED IN SUBSYSTEM C
//
"GENRST", "C LINH ", "CLINH 1", "C LST A", "CLSTB", "CLISQ ", "CLRP ", "INH" ,
"RPT", "SBWG", "SETSTB", "WE", "WPCTR", "WSQ", "WSTB", "R2000"
};
// for debug purposes only
char* printControlPulses ()
{
static char buf[MA XPU LSES*6 ];
strcpy(buf,"");
for(unsigned i=0; i<MAXPULSES && g lb l_cp[ i] != NO_PULSE; i++)
{
strcat(bu f, cpTypeString[g lbl_cp[i]]);
strcat(bu f," ");
}
//if(strcmp(bu f,"") == 0) strcat(buf,"NO NE" );
return bu f;
}
// return the EPROM word corresponding to the pulses
// in glbl_cp.
unsigned w riteEPROM (int lowBit)
{
un signe d EPROMword = 0x00 ; // no pu lses; de fault
for(unsigned i=0; i<MAXPULSES && g lb l_cp[ i] != NO_PULSE; i++)
{
int pulse = glbl_cp[i] - lowBit;
if(pulse < 0 || pulse > 7)
continue; // pulse is not in this EPROM
EPROMword |= 0x01 << pulse;
}
// printf("%02X \n",EPROMw ord);
//return EPROMword;
// The CPM -A con trol signals are nega tive logic, so we n eed to
// b it-f lip the word. No signa l is a 1, and an a sser ted s ignal is
// a 0:
return ((~EP ROMw ord) & 0xff);
}
const unsigned agcMem Size = 0x3fff+1; // # of cells in a 16-bit address range
void writeEPRO M(FILE * fpObj, int lowBit)
{
// Write an EPROM file using M otorola's S -Reco rd form at (s2f).
// Some parameters that control f ile format. You can change maxBytes
// without affecting anything else. 'addressBytes' is determined by
// the choosen S-R ecord forma t.
const int m axBytes = 20; // se t limit on record length
const int addressBytes = 3; // 24-bit address range
const int sumCheckBytes = 1;
const int maxdata = m axBytes - ad dressByte s - sumC heckBytes;
int i=0; // current E PROM address
int sumCheck = 0;
while ( i < agcMemSize)
{
// get dataByteCount; the number of bytes of EPROM data per record.
int dataByteCount = maxdata;
if(i + dataByteCount >= agcMemSize)
{
da taByteC ount = agcM em Size - i;
}
// write record header (*** 3 byte address assumed ***)
int totalByteCount = dataByteCoun t + addre ssBytes + sumCheckBytes;
fprintf(fpObj, "S2% 02X %06X ", totalByteCou nt, i);
sumCh eck = tota lByteCount & 0x ff;
sumCheck = (sumCheck + ((i & 0xff0000) >> 16)) % 256;
sumCheck = (sumCheck + ((i & 0x00ff00) >> 8)) % 256;
sumCheck = (sumCheck + ((i & 0x0000ff) )) % 256;
// write data bytes into record
for(int j=0; j<dataByteCount; j++)
{
get_CPM_A( i+j); // get CPM-A pulses for address i+j
int data = writeEPROM(lowBit); // comvert pulses to EPROM format
fprintf(fpObj, "% 02X ", data);
sumCheck = (sumCheck + data) % 256;
}
// terminate record by adding the checksum and a newline.
fprintf(fpObj, "% 02X \n", (~sum Check) & 0xff);
i += da taBy teCount;
}
// write an end-of-file record here
i = 0; // use address ze ro for last record
sumCheck = 0x04; // byte count
sumCheck = (sumCheck + ((i & 0xff0000) >> 16)) % 256;
sumCheck = (sumCheck + ((i & 0x00ff00) >> 8)) % 256;
sumCheck = (sumCheck + ((i & 0x0000ff) )) % 256;
fprintf(fpObj, "S804%06X %02X ", i, (~sumCheck) & 0xff);
}
void main(int argc, ch ar* a rgv[])
{
FILE* fpObj = 0;
fpOb j = fopen("CPM1_8 .hex" , "w");
if(!fpOb j)
{
perro r("fopen failed for object file");
exit(-1);
}
writeEPROM(fpO bj, 1); // pulses 1 -8
fclose(fpOb j);
fpOb j = fopen("CPM9_16.hex", "w" );
if(!fpOb j)
{
perro r("fopen failed for object file");
exit(-1);
}
writeEPROM(fpObj, 9); // pulses 9-16
fclose(fpOb j);
fpOb j = fopen("CPM17_24.hex", "w ");
if(!fpOb j)
{
perro r("fopen failed for object file");
exit(-1);
}
writeEPROM(fpObj, 17); // pulses 17-24
fclose(fpOb j);
fpOb j = fopen("CPM25_32.hex", "w ");
if(!fpOb j)
{
perro r("fopen failed for object file");
exit(-1);
}
writeEPROM(fpObj, 25); // pulses 25-32
fclose(fpOb j);
fpOb j = fopen("CPM33_40.hex", "w ");
if(!fpOb j)
{
perro r("fopen failed for object file");
exit(-1);
}
writeEPROM(fpObj, 33); // pulses 33-40
fclose(fpOb j);
fpOb j = fopen("CPM41_48.hex", "w ");
if(!fpOb j)
{
perro r("fopen failed for object file");
exit(-1);
}
writeEPROM(fpObj, 41); // pulses 41-48
fclose(fpOb j);
fpOb j = fopen("CPM49_56.hex", "w ");
if(!fpOb j)
{
perro r("fopen failed for object file");
exit(-1);
}
writeEPROM(fpObj, 49); // pulses 49-56
fclose(fpOb j);
}
Block IApollo Guidance Computer (AGC)
How to build one in your basement
Part 3: Processing (PROC) Module
John Pultorak
December, 2004
Abstract
This report describes my successful project to build a working reproduction of the 1964
prototype for the Block I Apollo Guidance Computer. The AGC is the flight computer for the
Apollo moon landings, and is the world’s first integrated circuit computer.
I built it in my basement. It took me 4 years.
If you like, you can build one too. It will take you less time, and yours will be better than
mine.
I documented my project in 9 separate .pdf files:
Part 1 Overview: Introduces the project.
Part 2 CTL Module: Design and construction of the control module.
Part 3 PROC Module: Design and construction of the processing (CPU) module.
Part 4 MEM Module: Design and construction of the memory module.
Part 5 IO Module: Design and construction of the display/keyboard (DSKY) module.
Part 6 Assembler: A cross-assembler for AGC software development.
Part 7 C++ Simulator: A low-level simulator that runs assembled AGC code.
Part 8 Flight Software: My translation of portions of the COLOSSUS 249 flight
software.
Part 9 Test & Checkout: A suite of test programs in AGC assembly language.
Overview
The Processing Module (PROC) has 5 subsystems: PMI, ALU, CRG, INT, CTR
PMI (Processing Module
external Interface)
The PMI interfaces other
processing module subsystems
to external AGC modules.
40-pin IDE connectors interface
to the other CTL, MEM, and IO
modules. Inputs from those
modules are buffered to 1
LSTTL load.
ALU (Arithmetic Logic Unit)
The ALU contains the 16-bit
ADDER to perform 1's
complement arithmetic and
increment the program counter
(Z register). The ALU also
contains the B and C registers,
and logic to inclusive OR the
contents of the them with the
ADDER. The inclusive OR occurs
when the control module (CTL)
issues signals to READ the
contents of both registers onto
the READ bus simultaneously.
The ALU transfers data from the
READ bus to the WRITE bus for
register-to-register transfers
and can force the data lines of
the WRITE bus to specific states
to gate various constants into
the AGC registers
CRG (Central Register)
The AGC has four 16-bit
“central registers” for general
computational use. These are
the accumulator (A) for general
computation; the program counter (Z) which contains the address of the next instruction;
the Q register holding the remainder in the DV instruction, and the return address after TC
instructions; and the LP register used to hold the lower product after MP instructions.
INT (Interrupt Priority)
The original AGC had five vectored interrupts. This recreation implements three of them:
RUPT1, also called T3RUPT which is used as general-purpose timer by the AGC WAITLIST
software; RUPT3, also called T4RUPT or DSRUPT, which is used to update the DSKY display
at regular intervals; and RUPT4, also called KERUPT, which is triggered by a key press from
the user's keyboard. The AGC responds to each interrupt by temporarily suspending the
current program, executing a short interrupt service routine, and then resuming the
interrupted program.
CTR (Priority Counter)
Twenty memory locations in the original AGC functioned as up/down counters. The counters
would increment (PINC) or decrement (MINC) in response to external inputs. Increment or
decrement was handled by one 12-step subsequence of microinstructions inserted between
any two regular instructions. This replica implements 5 of the counters: OVCTR, an overflow
counter incremented or decremented by arithmetic overflow during certain instructions;
TIME2 and TIME1, the AGC real-time clock; TIME3, a general purpose timer incremented by
a 100Hz signal from the SCALER (SCL); and TIME4, a timer used to update the DSKY
display.
The ALU has a 16-bit
parallel adder. The
addend and augend
are supplied by the
X and Y registers.
The sum, called the
U register although
it is not really a
register at all, is
gated to the read
bus through the RU
(read U) control
signal. The WX and
WY control signals
copy the contents of
the write bus into
the X and Y
registers.
The B register is
loaded from the
write bus with the
WB (write B) signal.
The contents of B
are output to the
read bus with the RB
(read B) signal. The
inverted output of B
can be gated to the
read bus with the RC
(read C) signal.
The AGC has four user-accessible central registers. The A register is the accumulator; Z is
the program counter; Q stores the return address for jumps (TC instruction), and LP stores
the lower product (MP
instruction).
Central register contents
can be output to the read
bus by asserting the
appropriate read control
pulse (RA, RQ, RZ, or
RLP). Each register is
also mapped to a
memory location, with
register A mapped to
address 0, Q to address
1, Z to 2, and LP to 3.
The R0, R1, R2, and R3
control pulses output
those registers to the
read bus.
The write bus contents
can be loaded into a
central register with a
write control pulse. WA
and WALP load the A
register; WQ, the Q
register; WZ the Z
register; and WLP and
WALP the LP register.
The W0, W1, W2, and
W3 control pulses
mapped to memory
addresses 0,1,2, and 3
also load those registers.
The interrupt priority
subsystem manages
vectored interrupts. Five
interrupts (0-4) are
implemented. Each
interrupt is latched by its
own “RP cell” flip-flop.
Signals from all RP cells
feed into a priority
encoder; a combinational
logic array that outputs
the code of the highest
priority interrupt in the
RP cells. When RPT is
asserted, the priority
code is latched into
RPCELL. This is decoded
into an address which is
the interrupt vector; the
address is written to the
read bus when RRPA is
asserted.
After the interrupt code
has been loaded into
RPCELL, asserting KRPT
(knock-down RPT) causes
the RP cell for that
interrupt to be reset. This
causes the next highest
priority interrupt to be
decoded by the priority
encoder.
The INHINT and INHINT1
flip-flops inhibit
interrupts.
The priority counter
logic design is similar
to the interrupt
subsystem. Up (+)
and down (-) count
input signals feed into
20 PCELLs, one PCELL
for each counter. The
PCELLs feed into the
priority encoder which
outputs the code of
the highest priority
PCELL having a up or
down input set. The
PCELL code is written
to the PCELL register
when WPCTR is
asserted.
The PCELL memory
address, derived from
PCELL, is written to
read bus when RSCT
is asserted. After the
code is latched into
the PCELL register,
the corresponding
PCELL is reset by
asserting WOVR.
The up or down code
for the selected PCELL is written to PSEQ when WPCTR is asserted. This code feeds to the
control logic on the CTL module which selects the PINC (increment) or MINC (decrement)
instruction subsequence to bump the priority counter up or down.
The PINC and MINC subsequences are inserted between normal instruction subsequences. A
SHINC subsequence implements a bit-shift which is used to load telemetry bits into the AGC
and assemble them into words. SHINC is not implemented in this AGC replica.
PROC Internal Subsystem Interconnections
This diagram shows internal interconnections for the subsystems in the PROC module.
PROC Module External Interfaces
The PROC module interfaces to the CTL, MEM, and IO modules through 40-pin IDE ribbon
cables.
J100-PROC: PROC-to-CTL I/F
J100 is a 40-pin IDE cable that connects the PROC module to the CTL module.
INPUTS (to PROC):
PIN signal full name state definition
1 WA3 WRITE ADDR 3 (74) 0=Write reg at address 3 (LP)
2 WA2 WRITE ADDR 2 (73) 0=Write reg at address 2 (Z)
3 WA1 WRITE ADDR 1 (72) 0=Write reg at address 1 (Q)
4 WA0 WRITE ADDR 0 (71) 0=Write reg at address 0 (A)
5 RA3 READ ADDR 3 (60) 0=Read reg at address 3 (LP)
6 RA2 READ ADDR 2 (59) 0=Read reg at address 2 (Z)
7 RA1 READ ADDR 1 (58) 0=Read reg at address 1 (Q)
8 RA0 READ ADDR 0 (57) 0=Read reg at address 0 (A)
9 WZ WRITE Z (50) 0=Write Z
10 WYx WRITE Y NO RESET (49) 0=Write Y (do not reset)
11 WY WRITE Y (48) 0=Write Y
12 WX WRITE X (47) 0=Write X
13 WQ WRITE Q (45) 0=Write Q
14 WOVR WRITE OVF (41) 0=Write overflow
15 WOVI WRITE OVF RUPT INH (40) 0=Write overflow RUPT inh ibit
16 WOVC WRITE OVF CNTR (39) 0=Write overflow counter
17 WLP WRITE LP (38) 0=Write LP
18 WB WRITE B (36) 0=Write B
19 WALP WRITE A/LP (35) 0=Write A and LP
20 WA WRITE A (34) 0=Write A
21 F10X F10 SCALER ONESHOT 1=timed out (100.0 Hz)
23 R24 READ 24 (25) 0=Read 24
24 R22 READ 22 (24) 0=Read 22
25 R2 READ 2 (23) 0=Read 2
26 R1C READ 1 COMP (22) 0=Read 1 complimented
27 R1 READ 1 (21) 0=Read 1
28 RZ READ Z (20) 0=Read Z
29 RU READ U (19) 0=Read sum
30 RSCT READ CNTR ADDR (18) 0=Read selected counter address
31 RSB READ SIGN (17) 0=Read sign bit
32 RRPA READ RUPT ADDR (16) 0=Read RUPT address
33 RQ READ Q (15) 0=Read Q
34 RLP READ LP (13) 0=Read LP
35 RC READ C (11) 0=Read C
36 RB14 READ BIT 14 (10) 0=Read bit 14
37 RB READ B (9) 0=Read B
38 RA READ A (8) 0=Read A
39 KRPT KNOCK DOWN RUPT (6) 0=Knock down Rupt priority
40 CI SET CARRY IN (1) 0=Carry in
J101-PROC: PROC-to-CTL I/F
J101 is a 40-pin IDE cable that connects the PROC module to the CTL module.
INPUTS (to PROC):
PIN signal full name state definition
1 R2000 READ 2000 (101) 0=Read 2000
2 WPCTR WRITE PCTR (98) 0=Write PCTR (latch priority counter seq)
3 RPT READ RUPT (94) 0=Read RUPT opcode
4 INH SET INHINT (93) 0=Set INHINT
5 CLRP CLEAR RPCELL (92) 0=Clear RPCELL
6 CLINH1 CLEAR INHINT1 (88) 0=Clear INHINT1
7 CLINH CLEAR INHINT (87) 0=Clear INHINT
8 GENRST GENERAL RESET (86) 0=General Reset
19 CLK1 CLOCK1 1.024 MHz AGC clock 1 (normally low)
20 CLK2 CLOCK2 1.024 MHz AGC clock 2 (normally low)
OUTPUTS (from PROC):
PIN signal full name state definition
21 SB_01 SUB SEL 01 SB_01 is LSB; SB_02 is MSB
22 SB_02 SUB SEL 02 00=no counter; 01=PINC; 10=MINC
23 IRQ INT RQST 0=interrupt requested.
25 WB_01 WRITE BUS 01 (lsb)
26 WB_02 WRITE BUS 02
27 WB_03 WRITE BUS 03
28 WB_04 WRITE BUS 04
29 WB_05 WRITE BUS 05
30 WB_06 WRITE BUS 06
31 WB_07 WRITE BUS 07
32 WB_08 WRITE BUS 08
33 WB_09 WRITE BUS 09
34 WB_10 WRITE BUS 10
35 WB_11 WRITE BUS 11
36 WB_12 WRITE BUS 12
37 WB_13 WRITE BUS 13
38 WB_14 WRITE BUS 14
39 WB_15 WRITE BUS 15 US (overflow) bit
40 WB_16 WRITE BUS 16 SG (sign) bit
J104-PROC: PROC-to-IO I/F
J104 is a 40-pin IDE cable that connects the PROC module to the IO module.
INPUTS (to PROC):
PIN signal full name state definition
40 RB_01 READ BUS 01 (lsb)
39 RB_02 READ BUS 02
38 RB_03 READ BUS 03
37 RB_04 READ BUS 04
36 RB_05 READ BUS 05
35 RB_06 READ BUS 06
34 RB_07 READ BUS 07
33 RB_08 READ BUS 08
32 RB_09 READ BUS 09
31 RB_10 READ BUS 10
30 RB_11 READ BUS 11
29 RB_12 READ BUS 12
28 RB_13 READ BUS 13
27 RB_14 READ BUS 14
26 RB_15 READ BUS 15 US (overflow) bit
25 RB_16 READ BUS 16 SG (sign) bit
22 BUSY2 READ BUS BUSY 0=OUT register output to read bus
21 BUSY1 READ BUS BUSY 0=INP register output to read bus
20 KB_STR KEY STROBE 1=key pressed strobe; to KEYRUPT. Key
data is valid on the negative edge of
KB_STR. Data is latched until the next
keypress.
OUTPUTS (from PROC):
PIN signal full name state definition
1 WB_01 WRITE BUS 01 (lsb)
2 WB_02 WRITE BUS 02
3 WB_03 WRITE BUS 03
4 WB_04 WRITE BUS 04
5 WB_05 WRITE BUS 05
6 WB_06 WRITE BUS 06
7 WB_07 WRITE BUS 07
8 WB_08 WRITE BUS 08
9 WB_09 WRITE BUS 09
10 WB_10 WRITE BUS 10
11 WB_11 WRITE BUS 11
12 WB_12 WRITE BUS 12
13 WB_13 WRITE BUS 13
14 WB_14 WRITE BUS 14
15 WB_15 WRITE BUS 15 US (overflow) bit
16 WB_16 WRITE BUS 16 SG (sign) bit
J105-PROC: PROC-to-MEM I/F
J105 is a 40-pin IDE cable that connects the PROC module to the MEM module.
INPUTS (to PROC):
PIN signal full name state definition
40 RB_01 READ BUS 01 (lsb)
39 RB_02 READ BUS 02
38 RB_03 READ BUS 03
37 RB_04 READ BUS 04
36 RB_05 READ BUS 05
35 RB_06 READ BUS 06
34 RB_07 READ BUS 07
33 RB_08 READ BUS 08
32 RB_09 READ BUS 09
31 RB_10 READ BUS 10
30 RB_11 READ BUS 11
29 RB_12 READ BUS 12
28 RB_13 READ BUS 13
27 RB_14 READ BUS 14
26 RB_15 READ BUS 15 US (overflow) bit
25 RB_16 READ BUS 16 SG (sign) bit
22 BUSY7 READ BUS BUSY 0=BNK register output enabled to read
bus
21 BUSY5 READ BUS BUSY 0=G register output enabled to read bus
OUTPUTS (from PROC):
PIN signal full name state definition
1 WB_01 WRITE BUS 01 (lsb)
2 WB_02 WRITE BUS 02
3 WB_03 WRITE BUS 03
4 WB_04 WRITE BUS 04
5 WB_05 WRITE BUS 05
6 WB_06 WRITE BUS 06
7 WB_07 WRITE BUS 07
8 WB_08 WRITE BUS 08
9 WB_09 WRITE BUS 09
10 WB_10 WRITE BUS 10
11 WB_11 WRITE BUS 11
12 WB_12 WRITE BUS 12
13 WB_13 WRITE BUS 13
14 WB_14 WRITE BUS 14
15 WB_15 WRITE BUS 15 US (overflow) bit
16 WB_16 WRITE BUS 16 SG (sign) bit
PROC CONTROL PANEL PUSHBUTTONS
RUPT1 Set the RUPT1 flip-flop (FF). Simulates a TIME3 overflow. Triggers a T3RUPT.
RUPT3 Set the RUPT3 flip-flop (FF). Simulates a TIME4 overflow. Triggers a T4RUPT
(DSRUPT).
RUPT4 Set the RUPT4 flip-flop (FF). Simulates a DSKY keypress. Triggers a KEYRUPT.
TIME1 Set the TIME1 flip-flop (FF). Increments the low-order word of the AGC
real-time clock.
TIME2 Set the TIME2 flip-flop (FF). Increments the high-order word of the AGC
real-time-clock.
TIME3 Set the TIME3 flip-flop (FF). Increments the general purpose timer.
TIME4 Set the TIME4 flip-flop (FF). Increments the display update timer.
PROC CONTROL PANEL CONNECTIONS
PIN signal state definition
1 RUPT1 GND=set RUPT1 FF
2 RUPT3 GND=set RUPT3 FF
3 RUPT4 GND=set RUPT4 FF
4 TIME1 GND=set TIME1 FF
5 TIME2 GND=set TIME2 FF
6 TIME3 GND=set TIME3 FF
7 TIME4 GND=set TIME4 FF
8 GND
PROC INDICATORS
The PROC module has a panel of indicator lamps (LEDs) to show the state of PROC registers
and critical logic signals.
These indicator lamps
show the current state of
all registers and some
additional, important
logic signals produced by
the PROC module. AGC
numbers are represented
in octal, so all register
lamps are in groups of
three. At the time the
photo was taken the
AGC was running
the COLOSSUS 249
flight software load,
executing Verb 16, Noun
36: a monitor verb
which displays the AGC
real time clock.
ALU (Arithmetic Logic Unit)
My earliest architectural representation of the ALU logic is shown below:
The ALU contains the 16-bit ADDER (colored orange in the diagram) which performs 1's
complement arithmetic, and increments the program counter (Z register). Each orange box is
a 4-bit parallel adder; collectively, they add 16 bits. The ADDER uses the X, Y, and U
registers:
X: the 16-bit extension register (2 8-bit registers in yellow) that holds one of two inputs
to the ADDER.
Y: the 16-bit extension register (also in yellow) that holds the other input to the ADDER.
U: the ADDER output (the 1's complement sum of the contents of registers X and Y).
Outputs to the bus labeled “B” on the diagram.
The ALU also contains the B and C registers:
B: a general-purpose buffer register (shown as 2 8-bit registers in yellow), also used to
pre-fetch the next instruction. At the start of the next instruction sequence, the upper
bits of B (containing the next op code) are copied to the SQ register (in CTL), and the
lower bits (the address) are copied to the S register in (MEM). Output to the bus
labeled “A” on the diagram.
C: not a separate register, but the 1's complement of B.
The ALU contains logic (using
74LS181 ALU chips, shown in
green) to do any of the following:
select the B register; select the
complement of the B register (the
“C” register); select the U register;
select the C register OR’ed with U,
or select logical zero. Those logic
functions, needed for AGC
operation, are shown in the upper
right corner of the diagram. The
outputs of the 74LS181 selector are
gated through a buffer to the read
bus.
The original AGC could inclusive OR
the outputs of any combination of
registers onto the bus, but the
control module only used this
feature for the B/C and U registers.
One of the uses involved the MASK
instruction, which is a logical AND:
DeMorgan's theorem was used to
implement the equivalent of a
logical AND by inverting operands
through the C register, performing a
logical OR through the bus, and
then inverting the result.
The 74LS181 logic functions are
gated to the read bus through the
data selector logic, shown in the adjacent diagram.
The ALU also transfers data from the
READ bus to the WRITE bus for
register-to-register data moves: Data
is output from the source register
onto the READ bus, then transferred
from the READ bus to the WRITE bus
through the ALU, and finally loaded
from the WRITE bus into the
destination register.
The logic that translates the READ
bus to the WRITE bus can also force
the data lines of the WRITE bus to
specific states to gate various
arithmetic constants onto the bus.
The accompanying diagram shows
the the control signal on the left
(RB14, R1, etc) and to the right is
the bit pattern that’s OR’ed onto the
bus when the signal is asserted. The
default state of the read bus is
logical zero, so if no other read signal
is asserted, the number that appears
on the bus is the constant;
otherwise, it’s the constant inclusive
OR’ed with the contents of the READ
bus.
The ALU contains READ bus control
logic. Registers in the MEM module,
the central registers in the PROC
module, and the ALU all interface to
the READ bus through tri-state
buffers. These buffers are normally in
the high-impedance state, but the
control module (CTL) issues READ
control signals to output the contents
of specific registers to the READ bus
at certain times. Only one register
should be gated onto the READ bus
at any given time.
When no READ control signals are asserted, the ALU gates its output onto the READ bus by
default. When the control module gates a register onto the READ bus, a BUSY signal is sent
to the ALU module, which causes the ALU to inhibit its output. Because of propagation
delays, the ALU might continue to output to the READ bus for a brief time while another
register is also gated to the bus. To prevent this, all output to the read bus is inhibited during
CLK1. This gives the control signals, which transition on the leading edge of CLK1, enough
setup time to resolve the conflict.
ALU INPUTS:
I/F signal full name state definition
CLK:
CLK1 CLOCK 1 1=read bus setup; inhibit read bus out
CLK2 CLOCK 2 data transfer occurs on falling edge
CPM:
RB READ B 0=output B register to write bus
RC READ C 0=output comp of reg B (C) to write bus
RU READ G 0=output U register to write bus
R1 READ OCTAL 1 0=incl OR 000001 w/write bus
R1C READ OCTAL -1 0=incl OR 177776 w/write bus
R2 READ OCTAL 2 0=incl OR 000002 w/write bus
R22 READ OCTAL 22 0=incl OR 000022 w/write bus
R24 READ OCTAL 24 0=incl OR 000024 w/write bus
R2000 READ OCTAL 2000 0=incl OR 002000 w/write bus
RB14 READ BIT14 0=incl OR 020000 w/write bus
RSB READ SIGN BIT 0=incl OR 100000 w/write bus
WB WRITE B 0=write into B from write
bus
CI WRITE CI 0=set carry register to 1
WY WRITE Y 0=write Y
WX WRITE X 0=write into X from write
bus
WYX WRITE Y 0=write into Y from write
bus
RBUS:
RB_01 READ BUS 01
...
RB_14 READ BUS 14
RB_15 READ BUS 15 US (overflow) bit for read
bus
RB_16 READ BUS 16 SG (sign) bit for read bus
INP: BUSY1 READ BUS BUSY 0=valid data from INP on
read bus
OUT: BUSY2 READ BUS BUSY 0=valid data from OUT on
read bus
CTR: BUSY3 READ BUS BUSY 0=valid data from CTR on
read bus
INT: BUSY4 READ BUS BUSY 0=valid data from INT on read bus
MBF: BUSY5 READ BUS BUSY 0=valid data from MBF on read bus
CRG: BUSY6 READ BUS BUSY 0=valid data from CRG on read bus
ADR: BUSY7 READ BUS BUSY 0=valid data from ADR on read bus
MBF OUTPUTS:
I/F signal full name state definition
WBUS:
WB_01 WRITE BUS 01
...
WB_14 WRITE BUS 14
WB_15 WRITE BUS 15 US (overflow) bit for write bus
WB_16 WRITE BUS 16 SG (sign) bit for write bus
CRG (Central Register)
The AGC has four 16-bit registers for general computational use. These are called the
"central registers":
A: the 16-bit accumulator, used
for general computation.
Z: the 16-bit program counter,
which contains the address of
the next instruction to be
executed.
Q: the 16-bit register used to
hold the remainder in the DV
instruction, and to hold the
return address after TC
instructions.
LP: the 16-bit register used to
hold the lower product after
MP instructions.
Register A and LP shifters
In addition to “normal” control pulses that write each line of the write bus into the
corresponding bit of the registers, the A and LP registers have special write control pulses
that shift bits:
The WALP control pulse bit-shifts into the A and LP register. The table below shows how the
shifter works. The row of 16 comma-separated entries represent bits in the register. The
leftmost position is the register MSB, rightmost position is the LSB. The entry shows the bit
of the WRITE bus that’s mapped onto that register bit by the shifter.
For the WALP pulse, bit 1 of the WRITE bus (B1) is written into bit 14 of the LP register. “BX”
means leave that bit of the register alone (don’t change it).
The same WALP pulse causes bit 2 of the WRITE bus (B2) to be written into the lowest bit of
the A register, bit 3 of the WRITE bus (B3) to be written into the next bit, and so forth. “US”
(uncorrected sign) is the overflow bit (bit 15) of the WRITE bus. “SG” is the 1's complement
sign (bit 16) from the WRITE bus.
WALP for register LP:
BX, BX, B1, BX, BX, BX, BX, BX, BX, BX, BX, BX, BX, BX, BX, BX
WALP for register A:
SG, SG, US, B14, B13, B12, B11, B10, B9, B8, B7, B6, B5, B4, B3, B2
Similarly, the WLP control pulse bit-shifts the WRITE bus into the LP register as follows (D0
on bit 14 of the LP register means force the bit to zero):
WLP
B1, B1, D0, B14, B13, B12, B11, B10, B9, B8, B7, B6, B5, B4, B3, B2
The logic design for handling bit 14 of the LP
register, which takes control inputs from
WALP, WLP, and WA3 is shown here. WA3 is
identical to WLP.
Depending upon the WALP, WLP, or WA3
inputs, bit 14 of LP will either be set to B1 of
the WRITE bus, or forced to zero.
CRG INPUTS:
I/F signal full name state definition
CLK:
CLK1 CLOCK 1 1=read bus setup; inhibit read bus output
CLK2 CLOCK 2 data transfer occurs on falling edge
CPM:
RA READ A 0=output A to read bus
RA0 READ A 0=output A to read bus
RQ READ Q 0=output Q to read bus
RA1 READ Q 0=output Q to read bus
RZ READ Z 0=output Z to read bus
RA2 READ Z 0=output Zto read bus
RLP READ LP 0=output LPto read bus
RA3 READ LP 0=output LP to read bus
WA WRITE A 0=load A from write bus
WA0 WRITE A 0=load A from write bus
WQ WRITE Q 0=load Q from write bus
WA1 WRITE Q 0=load Q from write bus
WZ WRITE Z 0=load Z from write bus
WA2 WRITE Z 0=load Z from write bus
WALP WRITE A,LP 0=load A,LP from write
bus
WLP WRITE LP 0=load LP from write bus
GENRST GENERAL RESET 0=General Reset
WBUS:
WB_01 WRITE BUS 01
...
WB_14 WRITE BUS 14
WB_15 WRITE BUS 15 US (overflow) bit for write bus
WB_16 WRITE BUS 16 SG (sign) bit for write bus
MBF OUTPUTS:
I/F signal full name state definition
RBUS:
RB_01 READ BUS 01
...
RB_14 READ BUS 14
RB_15 READ BUS 15 US (overflow) bit for read/write bus
RB_16 READ BUS 16 SG (sign) bit for read/write bus
BUSY READ BUS BUSY 0=output enabled to read bus
INT (Interrupt Priority)
The original AGC had five vectored interrupts. This recreation implements the following 3:
RUPT1 Also called T3RUPT because it's triggered by overflow of the TIME3 priority
counter.
RUPT3 Also called T4RUPT because it's triggered by overflow of the TIME4 priority
counter. Because the interrupt is used by software to update the DSKY display
at regular intervals, it's sometimes called DSRUPT.
RUPT4 Triggered by a key press from the user's keyboard. Also called KEYRUPT.
The AGC software responds to each interrupt by temporarily suspending the current program,
executing a short interrupt service routine, and then resuming the interrupted program.
INT INPUTS:
I/F signal full name state definition
CLK:
CLK1 CLOCK 1 1=read bus setup; inhibit read bus out
CLK2 CLOCK 2 data transfer occurs on falling edge
CPM:
GENRST GENERAL RESET 0=reset INT registers
RRPA READ RUPT ADDRESS 0=output RPCELL address
(2004,2010,2014,2020,2024) to read bus
RPT READ RUPT OPCODE 0=load RUPT opcode into RPCELL register
KRPT KNOCK DOWN RUPT PRIO 0=reset RUPT latch currently selected by
RPCELL register
CLRP CLEAR RPCELL 0=clear RPCELL register
WOVI WRITE OVF RUPT INH 0=test overflow; if
overflow, inhibit interrupt
(set INHINT1)
CLINH1 CLEAR INHINT1 0=clear INHINT1 register
INH SET INHINT 0=set INHINT register
CLINH CLEAR INHINT 0=clear INHINT register
WBUS:
WB_15 WRITE BUS 15 US (overflow) bit for write
bus
WB_16 WRITE BUS 16 SG (sign) bit for write bus
CTR/KBD:
RUPT1 INTERRUPT 1 0=trigger interrupt 1 (2004 octal; TIME3
overflow)
RUPT3 INTERRUPT 3 0=trigger interrupt 3 (2014 octal; TIME4
overflow)
RUPT4 INTERRUPT 4 0=trigger interrupt 4 (negative edge)
(2020 octal; keyboard activity)
Note: interrupt cells above RUPT4 not implemented.
INT OUTPUTS:
I/F signal full name state definition
SEQ:
IRQ INT RQST 0=interrupt requested. Active if allof the
following are true:
a) one or more RUPT FF's are set
b) interrupt is not currently being serviced
c) interrupts are not inhibited
RBUS:
RB_01 READ BUS 01
...
RB_14 READ BUS 14
RB_15 READ BUS 15 US (overflow) bit for read/write bus
RB_16 READ BUS 16 SG (sign) bit for read/write bus
BUSY READ BUS BUSY 0=output enabled to read bus
CTR (Priority Counter)
The Block I AGC had 20 memory locations dedicated as up/down counters (involuntary
counters). The counters would increment or decrement in response to external plus or minus
logic signals. Increment (PINC) or decrement (MINC) was handled by one subsequence of
microinstructions inserted between any two regular instruction subsequences when counter
inputs occurred.
This replica implements 5 counters used by the AGC operating system and user interface:
Counter Addr Description
OVCTR 34 An overflow counter incremented (PINC) or decremented (MINC) when
overflow conditions occur during certain instructions.
TIME2 35 The high-order bits of the AGC clock; incremented (PINC) by overflow
of TIME1.
TIME1 36 The low-order bits of the AGC clock; incremented (PINC) by a 100Hz
signal from the SCALER (SCL) in the control module (CTL).
TIME3 37 A general purpose timer incremented by a 100Hz signal from the
SCALER (SCL) in the control module (CTL).
TIME4 40 A special purpose timer used for software update of the DSKY display.
Incremented by a 100Hz signal from the SCALER (SCL) in the control
module (CTL).
INT/CTR interface
This chart shows how counter
overflows are handled. F10 (from
the scaler) increments TIME1,
TIME3, and TIME4.
A positive overflow of TIME1
causes an increment of TIME2.
Positive overflow of TIME3
triggers a T3RUPT interrupt.
Positive overflow of TIME4
triggers a DSRUPT (T4RUPT)
interrupt.
The addresses of TIME1 and
TIME2 are reversed for Block II.
This chart shows the Block I
order, but my replica used the
Block II order for compatibility
with the COLOSSUS flight
software.
CTR Design Problem
During unit testing, I uncovered a bug in my implementation of CTR: The plus inputs set the
P-cell which eventually triggers a PINC subsequence and increments the counter. Minus
inputs set the M-cell, which triggers a MINC subsequence and decrements the counter.
Near-simultaneous plus and m inus inputs should cancel out, producing no change in count.
As a consequence, the counter logic was designed so that, if the P- and M-cells are both set,
no counter sequence (PINC or MINC) is selected. The problem is, the P- and M-cells are reset
by WOVR, which only occurs in PINC or MINC. So, if both cells are set--and therefore, no
subsequence is selected--WOVR is never issued, the cells never reset, and all counting
activity is disabled for that counter.
Here are the options I developed fixing the design:
a) Create a new subsequence similar to PINC or MINC that issues WOVR, but does not
change the counter. Select this new subsequence when the P- and M-cells are simultaneously
set.
b) Allow the P- and M-cells to trigger PINC and MINC sequences, resulting in a net change of
zero to the counter.
c) Leave the design as-is, because the M-cell is only used for OVCTR in my implementation,
and therefore, the problem can never occur.
I choose option C to avoid redesign and re-unit-testing of CTR.
CTR INPUTS:
I/F signal full name state definition
CLK:
CLK1 CLOCK 1 1=read bus setup; inhibit read bus out
CLK2 CLOCK 2 data transfer occurs on falling edge
CPM:
GENRST GENERAL RESET 0=reset CTR registers
WPCTR WRITE PSEQ 0=write sequence into
PSEQ
RSCT READ PCELL ADDRESS 0=output PCELL address
(034-043) to read bus
WOVC WRITE OVRFLOW CNTR 0=test overflow and
inc/dec OVCTR
WOVR WRITE OVERFLOW 0=clear selected PCELL
and handle
counter overflow (if any)
WBUS:
WB_15 WRITE BUS 15 US (overflow) bit for
write bus
WB_16 WRITE BUS 16 SG (sign) bit for write
bus
EXTERNAL:
P3P P3 CELL + COUNT 0=count up P3 counter
(036 octal; TIME1)
P4P P4 CELL + COUNT 0=count up P4 counter
(037 octal; TIME3)
P5P P5 CELL + COUNT 0=count up P5 counter
(040 octal, TIME4)
Note: priority cells 6-20 not implemented.
CTR OUTPUTS:
I/F signal full name state definition
COUNTER OVERFLOW:
CPO_04 P4 + OVERFLOW 0=P4 cell pos ovf (during WOVR)
note: TIME3 + overflow; connect
to INT subsystem to trigger T3RUPT
interrupt.
CPO_05 P5 + OVERFLOW 0=P5 cell pos ovf (during WOVR)
note: TIME4 + overflow; connect
to INT subsystem to trigger T4RUPT
(DSRUPT) interrupt.
SEQ:
SB_01 SUB SEL 01 SB_01 is LSB; SB_02 is MSB
SB_02 SUB SEL 02 00=no counter; 01=PINC; 10=MINC
RBUS:
RB_01 READ BUS 01
...
RB_14 READ BUS 14
RB_15 READ BUS 15 US (overflow) bit for read/write bus
RB_16 READ BUS 16 SG (sign) bit for read/write bus
BUSY READ BUS BUSY 0=output enabled to read bus
Fabrication
The PROC module is (4) 13"x5" circuit boards, and 1 control panel.
Module Rack
The module framework is designed
to resemble a relay rack, but scaled
to fit the circuit board dimensions.
It is constructed out of 1"x2" pine
and spray-painted semi-gloss gray.
Circuit boards are mounted to the
rack by 2 phillips screws at either
end. Nylon spacers (1/4") are used
as standoffs to hold the board
edges above the rack. The boards
are mounted so the chips are in the
back and the pins are wiring are
visible from the front.
Power is distributed by 2 heavy
aluminum bus bars mounted
vertically, one per side, on the back
of the module. Machine screws are
mounted through the bus bars at
evenly-spaced intervals to provide
connection points for the boards.
Solid copper wire (24 gauge) connects the boards to the bus bars. Ring terminals are used
on the bus bar side of the connection. On the circuit board size, the wires are soldered
directly to the supply rails.
Materials were purchased from Home Depot, ACE Hardware, and Radio Shack.
Circuit Boards
The circuit boards are 13"x5" general purpose prototyping boards, epoxy glass with double-
side plated through pads on 0.1" centers (JAMECO 21477CL).
ICs are mounted in level 3 machine tooled wire-wrap sockets: 8, 14,
16, 20, 24, and 28 pin (JAMECO). Each socket has the pin-out labeled
with a w ire-wrap socket ID marker, which slips onto the socket before
wrapping (JAMECO). The part number is written onto the ID marker.
Sockets are arranged in 4 horizontal rows on each board, with about
10 sockets per row.
Power is distributed on the back-side of each board by bare 24-gauge
solid copper wire supply rails soldered at equal intervals to Klipwrap terminals: 3-prong
terminals with a square tail for wire-wrapping (JAMECO 34163CL). A +5V rail runs above
each row of sockets and a ground rail runs below. Each rail connects directly to the aluminum
module power bus using a ring tail connector.
On the pin side of the board, all connections are made with 30 AWG Kynar wire-wrap wire
(JAMECO). Red wire is used for direct connections to the +5V supply rail. Black wire is used
for direct connections to ground. White wire is used for everything else.
Power connections from the supply rails to each ICs are double-wrapped. Bypassing
capacitors (.1 uf disc ) are soldered across the supply rails at the Klipwrap terminals; about 1
capacitor for every 2 IC packages.
All connections were stripped and hand-wrapped using a Radio Shack hand-wrap tool. As
each connection was made, the corresponding line on the schematic was marked with a
colored highlighter.
DIP resistor networks (JAMECO) plugged into 20-pin wire-wrap sockets were used as current
limiting resistors for the panel indicators.
PROC Printed Circuit Board (PCB) A
The A board contains display drivers for the B board (left side), buffers for the interfaces to
external modules (bottom right), and priority counter logic (upper right). Sockets for 3 IDE
interface cables to external modules are visible at the bottom.
PROC Printed Circuit Board (PCB) B
The B board contains the display indicators, their current limiting resistor networks, and the
open collector drivers. The display panel is a sheet of white styrene plastic. A push pin was
used to make holes through the plastic and the LEDs were inserted in rows. The panel was
hand-lettered with an indelible marker.
PROC Printed Circuit Board (PCB) C
The C board contains the the logic for the interrupt (INT) subsystem (upper half of the
board), and the central registers (CRG; lower half of the board).
PROC Printed Circuit Board (PCB) D
The D board contains the ALU logic. The large 74181 ALU chips are at the bottom right. The
four chips that form the ADDER are in the bottom half of the board, slightly to the right of
the middle.
Parts (ICs)
IC’s, sockets, PCB’s, resistors, capacitors, wire-wrap wire were purchased from JAMECO. IDE
wire-wrap sockets were from DigiKey. Wire ties, wire-wrap tools, and copper wire were from
Radio Shack. IDE ribbon cables were purchased from an online computer supplier.
74LS00 (9) U60,U66,U57,U53,U51,U44,U46,U47,U42
74LS02 (4) U70,U6,U49,U2
74LS04 (11) U54,U45,U37,U68,U7,U36,U69,U71,U59,U48,U72
74LS06 (26) U28,U29,U30,U31,U27,U26,U23,U24,U25,U22,U21,U20,U18,U19,U17,U
16,U15,U12,U13,U14,U11,U10,U35,U34,U33,U32
74LS08 (4) U63,U61,U56,U52
74LS10 (2) U50,U43
74LS20 (2) U67,U73
74LS21 (1) U1
74LS27 (1) U9
74LS32 (5) U4,U41,U40,U39,U38
74LS83 (4) U134,U135,U136,U137
74LS86 (1) U5
74LS112 (7) U65,U64,U62,U58,U55,U8,U3
74LS138 (4) U84,U85,U86,U94
74LS148 (2) U93,U97
74LS151 (2) U87,U88
74LS181 (4) U130,U131,U132,U133
74LS244 (33) U74,U75,U76,U77,U78,U79,U80,U81,U82,U83,U89,U90,U95,U96,U101,
U102,U104,U105,U108,U111,U112,U115,U116,U117,U118,U119,U120,
U121,U122,U124,U125,U128,U129
74LS273 (19) U91,U92,U98,U99,U100,U103,U106,U107,U109,U110,U113,U114,U123
,U126,U127,U138,U139,U140,U141
Power Budget
qty mA (ea) mA (tot)
74LS00 9 2.4 21.6
74LS02 4 2.4 9.6
74LS04 11 3.6 39.6
74LS06 26 3.6 93.6
74LS08 4 4.4 17.6
74LS10 2 1.8 3.6
74LS20 2 1.2 2.4
74LS21 1 2.2 2.2
74LS27 1 3.4 3.4
74LS32 5 4.9 24.5
74LS83 4 22.0 88.0
74LS86 1 6.1 6.1
74LS112 7 4.0 28.0
74LS138 4 6.3 25.2
74LS148 2 12.0 24.0
74LS151 2 6.0 12.0
74LS181 4 21.0 84.0
74LS244 33 32.0 1056.0
74LS273 19 17.0 323.0
LED 153 20.0 3060.0
-----
4.9 Amps total
1.9 Amps (excluding LEDs)
Block IApollo Guidance Computer (AGC)
How to build one in your basement
Part 4: Memory (MEM) Module
John Pultorak
December, 2004
Abstract
This report describes my successful project to build a working reproduction of the 1964
prototype for the Block I Apollo Guidance Computer. The AGC is the flight computer for the
Apollo moon landings, and is the world’s first integrated circuit computer.
I built it in my basement. It took me 4 years.
If you like, you can build one too. It will take you less time, and yours will be better than
mine.
I documented my project in 9 separate .pdf files:
Part 1 Overview: Introduces the project.
Part 2 CTL Module: Design and construction of the control module.
Part 3 PROC Module: Design and construction of the processing (CPU) module.
Part 4 MEM Module: Design and construction of the memory module.
Part 5 IO Module: Design and construction of the display/keyboard (DSKY) module.
Part 6 Assembler: A cross-assembler for AGC software development.
Part 7 C++ Simulator: A low-level simulator that runs assembled AGC code.
Part 8 Flight Software: My translation of portions of the COLOSSUS 249 flight
software.
Part 9 Test & Checkout: A suite of test programs in AGC assembly language.
Overview
The Memory Module (MEM) has 5 subsystems: MMI, ADR, EMM/FMM, MBF, and PAR
MMI (Memory Module external
Interface)
The MMI interfaces other memory
module subsystems (ADR, EMM/FMM,
MBF, and PAR; described below) to
external AGC modules. 40-pin IDE
connectors interface to the PROC and
CTL modules. Inputs from those
modules are buffered to 1 LSTTL load.
A 1-pin connector interfaces to the IO
module.
EMM/FMM (Eraseable/Fixed
Memory)
The EMM/FMM is the AGC memory.
AGC memory is 16-bit words,
organized into 1024 word banks. The
lowest bank (bank 0) is erasable
memory (EMM), originally implemented
as core, but implemented here as RAM.
All banks above bank 0 are fixed
memory (originally implemented as
rope core, but implemented here as
EPROM). The Block I AGC initially had
12K words of fixed memory. This
implementation has 15K.
The MSB (bit 16) in memory is an odd
parity bit. The lower 15 bits hold
instructions or data.
MBF (Memory Buffer Register)
The MBF has the 16-bit memory buffer
register which holds 16-bit data words moving to and from memory. This is also called the G
register.
The AGC transfers data to and from memory through the G register during the "memory
cycle." The memory cycle takes 12 timing pulses (11.72 microseconds). During AGC
operation, data words cycle continuously from memory to the G register and then back
again to memory.
There are four locations in eraseable memory, at addresses 20-23 (octal), dubbed "editing
locations" because whatever was stored there would emerge shifted or rotated by one bit
position. This shifting is performed in the MBF.
PAR (Parity Generate and Test)
The PAR generates and tests the memory parity bit. The lower 15 bits of each memory word
hold AGC instructions or data. Each word is protected by a 16th "odd parity" bit. This bit is
set to 1 or 0 by a parity generator circuit so a count of the 1's in each memory word always
produces an odd number. A parity checking circuit tests the parity bit during each memory
cycle; if the bit doesn't match the expected value, the memory word is assumed to be
corrupted and a PARITY ALARM panel light illuminates on the IO module.
ADR (Memory Address)
The ADR constructs the AGC memory address. The address is formed from the S register
which holds the lower 12-bits that directly address the lowest 4K of memory, and the BANK
register, which selects higher memory banks when addressing is in the fixed-switchable
mode.
The AGC transfers data to and from memory through the G register in a process called the
"memory cycle." The memory cycle takes 12 timing pulses (11.72 microseconds). The cycle
begins at tim ing pulse 1 (TP1) when the AGC loads the memory address to be fetched into
the S register in ADR. Memory hardware retrieves the data word from memory at the
address specified by the S register. Words from erasable memory are deposited into the G
register by timing pulse 6 (TP6); words from fixed memory are deposited by timing pulse 7.
The retrieved
memory word is
then available in the
G register for AGC
access during timing
pulses 7 through 10.
After timing pulse
10, data in the G
register is written
back to memory.
The memory address
is formed from the
12-bit S register and
the 4-bit BANK
register. Memory in
the lowest 4 1K
banks is directly
addressed by the S
register. The higher
1K banks (5-12) are
address through the
bank register as
described in the ADR
subsystem section of
this document.
The high-order bit in
memory (bit 15) is an
odd parity bit. If the
memory word is a
data word, the 14th bit
is the sign, and bits
13 through 1 hold the
magnitude. The
number
representation is 1's
complement.
The first half of the
memory cycle copies
data from memory to
the G register, The
sign bit in memory
(bit 14) is copied to bits 15 and 14 of the G register. Bits 13 through 1 in memory are
copied to bits 13 through 1 in G. This is performed in the MBF and EMM/FMM subsystems.
The parity bit (bit 16 in memory) is read by the PAR subsystem and tested against parity
generated on the memory word copied into G. If the parity bits fail to match, a parity alarm
is generated.
The 14th bit in the G register (and the central registers in the AGC) is called the Uncorrected
Sign (US). This extra sign bit is used as an overflow indication in multi-word operations.
Normally, the Sign and Uncorrected sign should agree. When overflow or underflow
conditions occur, both signs will disagree, and are reconciled by software in an operation at
the end of a long string of multi-word computations.
At the end of the memory cycle, the G register is copied back to memory. The sign bit in G
(bit 15) is written to the sign bit (bit 14) in memory. Bits 13 through 1 in G are written to
bits 13 through 1 in memory. A new odd parity bit is computed in the PAR subsystem and
written to the 16th bit in memory.
These diagrams
show the timing
of the memory
cycle. The top
chart is a little
more
conceptual; the
bottom chart
shows the clock
cycles and
control pulses
directly
associated with
reading
eraseable
memory
(SBEWG) or
fixed memory
(SBFWG) to the
G register (the
‘WG’ part
means ‘write to
G’). The WE
pulse writes G
back to memory.
CLK1 steps the
sequencer in the
CTL module that
enables the
control signals.
The signals have
time to settle
between CLK1
and CLK2. Data
transfer occurs
on CLK2.
This is a functional
diagram of the ADR,
EMM/FMM, and MBF
subsystems in the
MEM module.
The diagram is mine,
but the style is
borrowed from
original AGC
documentation:
control signals are
represented by
diamonds. The
arrows show the
direction of data
flow. When a control
signal is asserted,
data is allowed to
flow through the
diamond.
For example, when
WE is asserted, the
contents of the G
register are written
into eraseable
memory (bank 0).
Note the different
formats for data and
instruction word in
memory, shown at
the bottom of the
diagram.
This is a functional
diagram of the
PAR subsystem in
the MEM module.
The diagram was
developed during
the early stages of
my AGC
architecture
analysis in 2001.
MEM Internal Subsystem InterconnectionsThis diagram shows internal interconnections for subsystems in the MEM module.
MEM Module External Interfaces
The MEM module interfaces to the PROC and CTL modules through 40-pin IDE ribbon cables.
J102-CTL: CTL-to-MEM I/F
J102 is a 40-pin IDE cable that connects the MEM module to the CTL module.
INPUTS (to CTL):
PIN signal full name state definition
1 WE WRITE EMEM (97) 0=Write E-MEM from G
2 SBWG WRITE G (95) 0=Write G from memory
3 GENRST GENERAL RESET (86) 0=General Reset
4 W23 WRITE ADDR 23 (85) 0=Write into SL
5 W22 WRITE ADDR 22 (84) 0=Write into CYL
6 W21 WRITE ADDR 21 (83) 0=Write into SR
7 W20 WRITE ADDR 20 (82) 0=Write into CYR
8 WGn WRITE G NORMAL (81) 0=Write G (normal gates)
9 WBK WRITE BNK (80) 0=Write BNK reg
10 RBK READ BNK (70) 0=Read BNK reg
11 WS WRITE S (46) 0=Write S
12 WP2 WRITE P2 (44) 0=Write P2
13 WPx WRITE P NO RESET (43) 0=Write P (do not reset)
14 WP WRITE P (42) 0=Write P
15 WGx WRITE G NO RESET (37) 0=Write G (do not reset)
16 TP TEST PARITY (30) 0=Test parity
17 RP2 READ PARITY 2 (14) 0=Read parity 2
18 RG READ G (12) 0=Read G
19 GP GEN PARITY (5) 0=Generate Parity
20 CLG CLR G (2) 0=Clear G
21 CLK2 CLOCK2 1.024 MHz AGC clock phase 2 (normally
low)
22 CLK1 CLOCK1 1.024 MHz AGC clock phase 2 (normally
low)
23 NPURST POWER UP RESET 0=reset, 1=normal operation.
24 SWCLK DEBOUNCE CLOCK low freq clk for switch debounce (not
used)
25 FCLK CLOCK MODE 1=free-running clk mode; 0=single clk
mode
OUTPUTS (from CTL):
PIN signal full name state definition
31 EQU_16 ADDRESS = 016 (1) 0=CADR in register S = 016
32 EQU_17 ADDRESS = 017 (2) 0=CADR in register S= 017
33 GTR_17 ADDRESS > 017 (3) 0=CADR in register S > 017
34 EQU_25 ADDRESS = 025 (4) 0=CADR in register S = 025
35 GTR_27 ADDRESS > 027 (5) 0=CADR in register S > 027
36 GTR_1777 ADDRESS > 01777 (6) 0=CADR in register S > 01777
37 AD_1 ADDRESS (1) where AD_4 is MSB, AD_1 is LSB
38 AD_2 ADDRESS (2)
39 AD_3 ADDRESS (3)
40 AD_4 ADDRESS (4)
J105-MEM: MEM-to-PROC I/F
J102 is a 40-pin IDE cable that connects the MEM module to the PROC module.
INPUTS (to MEM):
PIN signal full name state definition
1 WB_01 WRITE BUS 01 (lsb)
2 WB_02 WRITE BUS 02
3 WB_03 WRITE BUS 03
4 WB_04 WRITE BUS 04
5 WB_05 WRITE BUS 05
6 WB_06 WRITE BUS 06
7 WB_07 WRITE BUS 07
8 WB_08 WRITE BUS 08
9 WB_09 WRITE BUS 09
10 WB_10 WRITE BUS 10
11 WB_11 WRITE BUS 11
12 WB_12 WRITE BUS 12
13 WB_13 WRITE BUS 13
14 WB_14 WRITE BUS 14
15 WB_15 WRITE BUS 15 US (overflow) bit
16 WB_16 WRITE BUS 16 SG (sign) bit
OUTPUTS (from MEM):
PIN signal full name state definition
40 RB_01 READ BUS 01 (lsb)
39 RB_02 READ BUS 02
38 RB_03 READ BUS 03
37 RB_04 READ BUS 04
36 RB_05 READ BUS 05
35 RB_06 READ BUS 06
34 RB_07 READ BUS 07
33 RB_08 READ BUS 08
32 RB_09 READ BUS 09
31 RB_10 READ BUS 10
30 RB_11 READ BUS 11
29 RB_12 READ BUS 12
28 RB_13 READ BUS 13
27 RB_14 READ BUS 14
26 RB_15 READ BUS 15 US (overflow) bit
25 RB_16 READ BUS 16 SG (sign) bit
22 BUSY7 READ BUS BUSY 0=BNK register output to read bus
21 BUSY5 READ BUS BUSY 0=G register output to read bus
MEM CONTROL PANEL SWITCHES
AGC/MANUAL Permits memory to be examined and loaded when the switch is in the
MANUAL position and the AGC is halted.
EXAM Loads the address counter with the contents of the switch register. To
work, the following switches must also be set: AGC/MANUAL -->
MANUAL
NEXT Steps the address to the next location. To work, the following switches
must also be set: AGC/MANUAL --> MANUAL
READ/WRITE Displays memory contents in the READ position; displays switch
register contents in the WRITE position.
LOAD Load memory with data manually entered into the switch register. To
work, the following switches must also be set prior to LOAD: CLOCK
CONTROL (on CTL module) --> STEP; AGC/MANUAL --> MANUAL;
READ/WRITE --> WRITE
CLEAR PARITY Clears a parity alarm indication by resetting the parity alarm (PALM)
register. The parity alarm indicator is on the IO module.
MEM CONTROL SWITCH CONNECTIONS
PIN signal state definition
1 READ/WRITE GND=read
2 AGC/MANUAL GND=manual
3 EXAM GND=examine
4 NEXT GND=examine next
5 CLEAR PARITY GND=clear
6 LOAD LOAD switch contact
7 LOAD LOAD switch contact
PIN signal full name state definition
1 D1 DATA1 LSB on switch bus 101
2 D2 DATA2
3 D3 DATA3
4 D4 DATA4
5 D5 DATA5
6 D6 DATA6
7 D7 DATA7
8 D8 DATA8
9 D9 DATA9
10 D10 DATA10
11 D11 DATA11
12 D12 DATA12
13 D13 DATA13
14 D14 DATA14
15 D15 DATA15
16 D16 DATA16 LSB on switch bus 101
17 GND GND
MEM INDICATORS
These indicator lamps show the
current state of all registers and
some additional, important logic
signals produced by the MEM
module. AGC numbers are
represented in octal, so all
register lamps are in groups of
three. At the time the photo was
taken the AGC was running
the COLOSSUS 249 flight
software load, executing Verb
16, Noun 36: a monitor verb
which disp lays the AGC real time
clock.
ADR (Memory Address)
The AGC has a 14-bit address range. Memory address is selected by the 12-bit S register
and the 4-b it BANK register.
S: the 12-bit memory address register, which holds the lower portion of
the memory address.
BANK: the 4-bit memory bank register, which selects the memory bank when
addressing is in the fixed-switchable mode.
Each AGC instruction has a 12-bit address field. The lower bits (1-10) address memory
inside each bank. Bits 11 and 12 select the bank:
00: selects the erasable memory bank; the BANK register is ignored.
01: selects the lowest bank (bank 1) of fixed memory; the BANK register is
ignored.
10: selects the next bank (bank 2) of fixed memory; the BANK register is
ignored.
11: selects the BANK register, which is used to address any bank above 2.
If the BANK register contains 0, 1, or 2, the BANK register is
overridden and bank 3 is selected.
Banks 1 and 2 are called "fixed-fixed" memory, because they are always available,
regardless of the contents of the BANK register. Banks 3 and above are called
"fixed-switchable" because the selected bank is determined by the BANK register.
Type:
E Eraseable Memory
FF Fixed-Fixed Memory
FS Fixed-Switchable Memory
S Register:
14-bit BANK bits 12-bit
address bank type Reg. 12,11 address
00000 - 01777 0 (E) ignored 00 0000 - 1777
02000 - 03777 1 (FF) ignored 01 2000 - 3777
04000 - 05777 2 (FF) ignored 10 4000 - 5777
06000 - 07777 3 (FS) 0000 - 0011 11 6000 - 7777
10000 - 11777 4 (FS) 0100 11 6000 - 7777
12000 - 13777 5 (FS) 0101 11 6000 - 7777
14000 - 15777 6 (FS) 0110 11 6000 - 7777
16000 - 17777 7 (FS) 0111 11 6000 - 7777
20000 - 21777 8 (FS) 1000 11 6000 - 7777
22000 - 23777 9 (FS) 1001 11 6000 - 7777
24000 - 25777 10 (FS) 1010 11 6000 - 7777
26000 - 27777 11 (FS) 1011 11 6000 - 7777
30000 - 31777 12 (FS) 1100 11 6000 - 7777
BANK register (B) + S register (S) Decodes to address:
B4 B3 B2 B1 S12 S11 A14 A13 A12 A11
X X X X 0 0 0 0 0 0
X X X X 0 1 0 0 0 1
X X X X 1 0 0 0 1 0
0 0 0 0 1 1 0 0 1 1
0 0 0 1 1 1 0 0 1 1
0 0 1 0 1 1 0 0 1 1
0 0 1 1 1 1 0 0 1 1
0 1 0 0 1 1 0 1 0 0
0 1 0 1 1 1 0 1 0 1
0 1 1 0 1 1 0 1 1 0
0 1 1 1 1 1 0 1 1 1
1 0 0 0 1 1 1 0 0 0
1 0 0 1 1 1 1 0 0 1
1 0 1 0 1 1 1 0 1 0
1 0 1 1 1 1 1 0 1 1
1 1 0 0 1 1 1 1 0 0
1 1 0 1 1 1 1 1 0 1
1 1 1 0 1 1 1 1 1 0
1 1 1 1 1 1 1 1 1 1
X=don’t care
This is an early conceptual diagram of
ADR architecture. The WRITE bus loads
the BNK register or S register. Outputs
from both registers feed into the bank
decoder to generate the bank address.
The ADR generates some logic
signals to test the address.
These are internally used in
MEM and also made available
to the external modules. The
GTR signals test whether the
generated address is greater
than 1777, 27, or 17 (all octal).
The EQU logic tests whether the
generated address is equal to a specific
value: 14, 16, 17, or 25.
The bank select logic chooses
between the S register or a
combination of the S register
and the bank register to
generate address bits 14-11. It
uses S register bits 11 and 12
to make the decision. The
selection signal enables tri-
state buffer A or B to produce
the correct bank address.
ADR INPUTS:
I/F signal full name state definition
CLK:
CLK1 CLOCK 1 1=read bus setup; inhibit read bus output
CLK2 CLOCK 2 data transfer occurs on falling edge
CPM:
GENRST GENERAL RESET 0=reset ADR registers
RBK READ BANK 0=output BNK register to read bus
WBK WRITE BANK 0=write into BNK register
from write bus
WS WRITE S 0=write into S register
from write bus
WBUS:
WB_01 WRITE BUS 01
...
WB_14 WRITE BUS 14
ADR OUTPUTS:
I/F signal full name state definition
MEM:
AD_11 ADDRESS BUS 11 bank select bits
...
AD_14 ADDRESS BUS 14
AD_1 ADDRESS BUS 1 low order address
...
AD_10 ADDRESS BUS 10
various:
EQU_16 ADDRESS = 016 0=CADR in reg S = 016
EQU_17 ADDRESS = 017 0=CADR in reg S = 017
GTR_17 ADDRESS > 017 0=CADR in reg S > 017
EQU_25 ADDRESS = 025 0=CADR in reg S = 025
GTR_27 ADDRESS > 027 0=CADR in reg S > 027
GTR_1777 ADDRESS > 01777 0=CADR in reg S > 01777
RBUS:
RB_01 READ BUS 01
...
RB_16 READ BUS 16
BUSY READ BUS BUSY 0=output to read bus
EMM/FMM (Eraseable/Fixed Memory)
MEM INPUTS:
I/F signal full name state definition
CLK:
CLK2 CLOCK 2 data transfer occurs on CLK2
CPM:
WE WRITE ERASEABLE 0=write memory bus to
eraseable memory
SBWG WRITE G (MEM) 0=read eraseable or fixed
memory onto memory bus
ADR: GTR_1777 ADDRESS > 01777 0=CADR in reg S > 01777
AD_01 ADDRESS BUS 01
...
AD_10 ADDRESS BUS 10
AD_11 ADDRESS BUS 11 bank select portion of
address bus
...
AD_14 ADDRESS BUS 14 bank select portion of
address bus
BIDIRECTIONAL (IN/OUT):
I/F signal full name state definition
EMM/FMM:
MEM_01 MEMORY_BUS 01 Memory word formats:
... inst: 15-13:op code; 12-1:address
MEM_15 MEMORY_BUS 15 data: 15:SG; 14-1 data
MEM_16 MEMORY_BUS 16 parity (odd) bit for memory bus
MBF (Memory Buffer Register)
The AGC has a 16-
bit G register for
transferring data to
and from memory.
WRITE bus data can
be written directly
into the G register,
or can be bit-shifted
before writing. Data
from the G register
can be copied to the
READ bus, or to the
memory bus.
The following
section shows how
bits are shifted in
bus-to-register-to-
memory transfers.
The row of 16
comma-separated
entries represent bit
locations at the
destination; the leftmost entry is the MSB, and the rightmost is the LSB. The designation in
each location identifies source bit location. This will become clearer shortly.
In memory, the 16th bit is the odd parity bit, and the 15th bit is the sign. In the G register,
the bits are flipped: the 16th bit is the sign, and the 15th bit is the parity. The WE pulse,
which writes from the G register to memory, causes the sign bit (SG; bit 16 in G) to be
written to bit 15 in memory. Parity is written to memory from the parity generator (PAR),
not from the parity bit in G. (The G parity bit holds the parity read from memory.)
WE:
BX, SG, B14, B13, B12, B11, B10, B9, B8, B7, B6, B5, B4, B3, B2, B1
Data is written from memory to G by the SBWG control pulse. The sign in memory (SG; bit
15) is written to bit 16 in G. The parity bit (bit 16 in memory) is written to bit 15 in G by the
PAR subsystem.
SBWG:
SG, BX, B14, B13, B12, B11, B10, B9, B8, B7, B6, B5, B4, B3, B2, B1
Data is written into G from the WRITE bus using WG (no shift), or one of the following
control pulses that produce the following shifts:
W20:
B1, BX, SG, B14, B13, B12, B11, B10, B9, B8, B7, B6, B5, B4, B3, B2
W21:
SG, BX, SG, B14, B13, B12, B11, B10, B9, B8, B7, B6, B5, B4, B3, B2
W22:
B14, BX, B13, B12, B11, B10, B9, B8, B7, B6, B5, B4, B3, B2, B1, SG
W23:
SG, BX, B13, B12, B11, B10, B9, B8, B7, B6, B5, B4, B3, B2, B1, SG
Data is read from G to the READ bus as follows. The parity bit (bit 15 in G) is not transferred
to the read bus; instead, the sign bit is copied onto bits 15 and 16 of the READ bus.
RG:
SG, SG, B14, B13,
B12, B11, B10, B9, B8,
B7, B6, B5, B4, B3, B2, B1
Some of the design that
went into the
combinational logic that
sets bit 16 in the G
register from the READ
bus is shown here. The
MB_B16 output controls
the 16th bit for the W20
and W21 control pulses.
The MB_C16 output controls the
16th bit for the W22 and W23
control pulses.
MBF INPUTS:
I/F signal full name state definition
CLK:
CLK1 CLOCK 1 1=read bus setup; inhibit read bus output
CLK2 CLOCK 2 data transfer occurs on falling edge
CPM:
RG READ G 0=output G register to read/write bus
WE WRITE ERASEABLE 0=output G register to memory bus
GTR_17 ADDRESS > 017 0=CADR in register S > 017
SBWG WRITE G (MEM) 0=write G from memory bus
WGN WRITE G 0=write G from read/write
bus (no shift)
WGX WRITE G 0=write G from read/write
bus (no shift)
W20 WRITE G (SHIFT) 0=write G
W21 WRITE G (SHIFT) 0=write G
W22 WRITE G (SHIFT) 0=write G
W23 WRITE G (SHIFT) 0=write G
GENRST GENERAL RESET 0=General Reset
WBUS:
WB_01 WRITE BUS 01
...
WB_14 WRITE BUS 14
WB_15 WRITE BUS 15 US (overflow) bit for write
bus
WB_16 WRITE BUS 16 SG (sign) bit for write bus
MBF OUTPUTS:
I/F signal full name state definition
RBUS:
RB_01 READ BUS 01
...
RB_14 READ BUS 14
RB_15 READ BUS 15 US (overflow) bit for read/write bus
RB_16 READ BUS 16 SG (sign) bit for read/write bus
BUSY READ BUS BUSY 0=output enabled to read bus
BIDIRECTIONAL (IN/OUT):
I/F signal full name state definition
EMM/FMM:
MEM_01 MEMORY_BUS 01 Memory word formats:
... inst: 15-13:op code; 12-1:address
MEM_15 MEMORY_BUS 15 data: 15:SG; 14-1 data
MEM_16 MEMORY_BUS 16 parity (odd) bit for memory bus
PAR (Parity Generation and Test)
The PAR subsystem checks
the memory parity bit
during each memory cycle
and generates an alarm if
the parity bit in memory
does not match the
expected odd parity. The
PAR subsystem also
generates parity from the
contents of G and writes
this parity back to memory.
This block diagram of the PAR
subsystem emerges from the
previous diagram.
This is the combinational
logic used to generate
the input to the G15
register. This is the 1-bit
register that holds bit 15
(the parity bit) for the G
register. The remainder
of the G register (bits 1-
14 and bit 16) is in the
MBF subsystem.
The minterms are written
out on top. DeMorgan’s
Theorem and a little
bubble-pushing changes
the OR gate into a NAND.
PAR INPUTS:
I/F signal full name state definition
CLK:
CLK2 CLOCK 2 data transfer occurs on
falling edge
CPM:
RG READ G15 0=write G15 into P
RP2 READ P2 0=write P2 into G15
WP WRITE P 0=write P (same as WPX)
WPX WRITE P 0=write P (same as WP)
WP2 WRITE P2 0=write P2 from 1-15
generator
SBWG WRITE G15 (MEM) 0=write G15 from memory
parity bit
GP WRITE G15 0=write G15 from 1-15
generator (same as WGX)
WGX WRITE G15 0=write G15 from 1-15
generator (same as GP)
CLG CLEAR G15 0=clear G15
TP TEST PARITY 0=test parity from P-15
ADR:
GTR_27 ADDRESS > 027 0=CADR in Register S evaluates to > 027
WBUS:
WB_01 WRITE BUS 01
...
WB_14 WRITE BUS 14
WB_15 WRITE BUS 15 US (overflow) bit for write bus
WB_16 WRITE BUS 16 SG (sign) bit for write bus
MON:
CLRPLM CLEAR PARITY ALM 0=clear parity alarm
PAR OUTPUTS:
I/F signal full name state definition
MON
PARALM PARITY ALARM 1=parity alarm
BIDIRECTIONAL (IN/OUT):
I/F signal full name state definition
EMM/FMM:
MEM_16 MEMORY_BUS 16 parity (odd) bit for memory bus
Fabrication
The MEM module is (3) 13"x5" circuit boards, and 1 control panel.
Module Rack
The module framework is designed
to resemble a relay rack, but
scaled to fit the circuit board
dimensions. It is constructed out
of 1"x2" pine and spray-painted
semi-gloss gray.
Circuit boards are mounted to the
rack by 2 phillips screws at either
end. Nylon spacers (1/4") are
used as standoffs to hold the
board edges above the rack. The
boards are mounted so the chips
are in the back and the pins are
wiring are visib le from the front.
Power is distributed by 2 heavy
aluminum bus bars mounted
vertically, one per side, on the
back of the module. Machine
screws are mounted through the bus bars at evenly-spaced intervals to provide connection
points for the boards.
Solid copper wire (24 gauge) connects the boards to the bus bars. Ring terminals are used
on the bus bar side of the connection. On the circuit board size, the wires are soldered
directly to the supply rails.
Materials were purchased from Home Depot, ACE Hardware, and Radio Shack.
Circuit Boards
The circuit boards are 13"x5" general purpose prototyping boards,
epoxy glass with double-side plated through pads on 0.1" centers
(JAMECO 21477CL).
ICs are mounted in level 3 machine tooled wire-wrap sockets: 8, 14,
16, 20, 24, and 28 pin (JAMECO). Each socket has the pin-out labeled
with a w ire-wrap socket ID marker, which slips onto the socket before
wrapping (JAMECO). The part number is written onto the ID marker.
Sockets are arranged in 4 horizontal rows on each board, with about
10 sockets per row.
Power is distributed on the back-side of each board by bare 24-gauge solid copper wire
supply rails soldered at equal intervals to Klipwrap terminals: 3-prong terminals with a
square tail for wire-wrapping (JAMECO 34163CL). A +5V rail runs above each row of sockets
and a ground rail runs below. Each rail connects directly to the aluminum module power bus
using a ring tail connector.
On the pin side of the board, all connections are made with 30 AWG Kynar wire-wrap wire
(JAMECO). Red wire is used for direct connections to the +5V supply rail. Black wire is used
for direct connections to ground. White wire is used for everything else.
Power connections from the supply rails to each ICs are double-wrapped. Bypassing
capacitors (.1 uf disc ) are soldered across the supply rails at the Klipwrap terminals; about
1 capacitor for every 2 IC packages.
All connections were stripped and hand-wrapped using a Radio Shack hand-wrap tool. As
each connection was made, the corresponding line on the schematic was marked with a
colored highlighter.
DIP resistor networks (JAMECO) plugged into 20-pin wire-wrap sockets were used as current
limiting resistors for the panel indicators.
MEM Printed Circuit Board (PCB) A
The A board contains the zero-insertion force (ZIF) sockets for the fixed memory EPROMs,
and the 2 40-pin IDE connectors that interface to the other modules. The eraseable
memories (U101, U102) are also clearly visible next to the EPROMs. The Memory Address
(ADR) and Eraseable/Fixed Memory (EMM/FMM) subsystems are primarily located on this
board.
MEM Printed Circuit Board (PCB) B
The B board contains the display indicators, their current-limiting resistor networks, and the
open collector drivers. The display panel is a sheet of white styrene plastic. A push pin was
used to make holes through the plastic and the LEDs were inserted in rows. The panel was
hand-lettered with an indelible marker.
MEM Printed Circuit Board (PCB) C
The C board primarily contains the Memory Buffer (MBF) and Parity Generation and Test
(PAR) subsystems.
Parts (ICs)
74LS00 (11) U50,U25,U26,U27,U40,U32,U33,U34,U43,U44,U53
74LS02 (3) U52,U31,U55
74LS04 (12) U39,U28,U51,U56,U48,U46,U45,U41,U30,U35,U36,U54
74LS06 (21) U20,U19,U18,U15,U16,U17,U14,U13,U12,U10,U11,U9,U6,U7,U8,U5,U
4,U21,U22,U23,U24
74LS10 (3) U49,U37,U42
74LS20 (2) U47,U29
74LS27 (2) U2,U38
74LS74 (1) U1
74LS86 (1) U3
74LS154 (1) U72
74LS193 (4) U63,U64,U65,U66
74LS244 (31) U57,U58,U59,U60,U61,U62,U67,U68,U69,U70,U71,U73,U83,U84,U85,
U86,U87,U88,U89,U90,U91,U92,U93,U94,U95,U96,U97,U98,U103,U10
4,U105
74LS273 (10) U74,U75,U76,U79,U80,U81,U82,U106,U107,U108
74S280 (2) U77,U78
27C128 (2) U99,U100
2016 (2) U101,U102
Power Budget
qty mA (ea) mA (tot)
74LS00 11 2.4 26.4
74LS02 3 2.4 7.2
74LS04 12 3.6 43.2
74LS06 21 3.6 75.6
74LS10 3 1.8 5.4
74LS20 2 1.2 2.4
74LS27 2 3.4 6.8
74LS74 1 4.0 4.0
74LS86 1 6.1 6.1
74LS154 1 6.2 6.2
74LS193 4 19.0 76.0
74LS244 31 32.0 992.0
74LS273 10 17.0 170.0
74LS280 2 16.0 32.0
27C128 2 25.0 50.0
2016 2 25.0 50.0
LED 124 20.0 2480.0
-------
4.0 Amps total
1.6 Amps (excluding LEDs)
Block IApollo Guidance Computer (AGC)
How to build one in your basement
Part 5: Input/Output (IO) Module
John Pultorak
December, 2004
Abstract
This report describes my successful project to build a working reproduction of the 1964
prototype for the Block I Apollo Guidance Computer. The AGC is the flight computer for the
Apollo moon landings, and is the world’s first integrated circuit computer.
I built it in my basement. It took me 4 years.
If you like, you can build one too. It will take you less time, and yours will be better than
mine.
I documented my project in 9 separate .pdf files:
Part 1 Overview: Introduces the project.
Part 2 CTL Module: Design and construction of the control module.
Part 3 PROC Module: Design and construction of the processing (CPU) module.
Part 4 MEM Module: Design and construction of the memory module.
Part 5 IO Module: Design and construction of the display/keyboard (DSKY) module.
Part 6 Assembler: A cross-assembler for AGC software development.
Part 7 C++ Simulator: A low-level simulator that runs assembled AGC code.
Part 8 Flight Software: My translation of portions of the COLOSSUS 249 flight
software.
Part 9 Test & Checkout: A suite of test programs in AGC assembly language.
Overview
The I/O Module (IO) has 5 subsystems: IMI, KBD, INP, OUT, DSP
IMI (I/O Module
external Interface)
The IMI interfaces the
I/O module to other
AGC modules. 40-pin
IDE connectors
interface to the PROC
and CTL modules. A 1-
pin connector interfaces
to the MEM module.
Inputs taken those
modules are buffered to
1 LSTTL load.
KBD (Keyboard)
An 18-button keyboard;
the AGC’s flight
software user input
interface. The
keyboard/display unit is
called the DSKY.
INP (Input
Registers)
The AGC has 4 16-bit
input registers that
receive data from the
keyboard and discrete
logic signals. IN0 reads
from the keyboard and
the STANDBY ALLOWED
discrete signal. IN1-IN3
are not implemented in
this replica.
OUT (Output
Registers)
The AGC has 5 16-bit
output registers that
drive the DSKY display
and other spacecraft
subsystems. OUT0
writes to the DSKY
display; OUT1 drives
the 6 discrete indicator
lamps on the AGC DSKY
display; OUT2-OUT4
are not implemented in this replica.
DSP (Display)
A matrix of green 7-segment displays; the output side of the AGC’s flight software user
interface. There are (3) 5-digit displays with +/- signs which can display decimal or octal
data, and (3) 2-digit displays to show the current program (PROG), verb, and noun.
An additional panel of 6 indicator lamps shows AGC status and alarm states.
AGC input registers and
control signals that read
them onto the bus are
shown in the diagram to
the right. The 5-bit
keyboard code and
STANDBY ALLOWED switch
are read from “register 0"
(IN0) when the R4 (RA4)
control pulse is asserted.
The signal is R4 because
the register is mapped to
memory address 4. The
registers are actually
buffers, not latches.
Keyboard codes are latched
internally in the keyboard
subsystem.
The IN1, IN2, and IN3
registers are not
implemented in this
replica.
AGC output registers are shown in the next
figure. OUT0 drives the 7-segment DSKY
displays. W10 (WA10) loads data from the
write bus into the DSKY display; the “10" is
because it is mapped onto memory location 10
(octal). Each 16-bit word controls 2 digits on
the display. The digit pair is selected by a 4-bit
code at the top of the word.
OUT1 drives discrete indicator lamps on a
panel adjacent to the 7-segment display. W11
(WA11) writes to the register, and R11 (RA11)
reads from it.
The OUT2, OUT3, and OUT4 registers are not
implemented in this replica.
IO Internal Subsystem Interconnections
This diagram shows internal interconnections for the subsystems in the IO module.
IO Module External Interfaces
The IO module interfaces to the CTL and PROC modules through 40-pin IDE ribbon cables.
J103-IO: CTL-to-I/O I/F
INPUTS (to IO):
PIN signal full name state definition
1 CLK1 CLOCK1 1.024 MHz AGC clock phase 2 (normally
low)
2 CLK2 CLOCK2 1.024 MHz AGC clock phase 2 (normally
low)
3 NSA STANDBY ALLOWED 0=standby allowed
5 GENRST GENERAL RESET (86) 0=clear the DSKY, OUT1, and OUT2.
6 WA11 WRITE OUT1 (76) 0=write into OUT1 from write bus
7 WA10 WRITE OUT0 (75) 0=write into OUT0 (DSKY) from write bus
8 RA11 READ OUT1 (66) 0=output OUT1 register to read bus
9 RA4 READ IN0 (61) 0=output IN0 register to read bus
20 STBY STANDBY 0=AGC is in the standby state
OUTPUTS (from IO):
PIN signal full name state definition
40 OUT1_8 STANDBY ENABLED 1=standby enabled; works with STANDBY
ALLOWED switch
J104-IO: PROC-to-IO I/F
INPUTS (to IO):
PIN signal full name state definition
1 WB_01 WRITE BUS 01 (lsb)
2 WB_02 WRITE BUS 02
3 WB_03 WRITE BUS 03
4 WB_04 WRITE BUS 04
5 WB_05 WRITE BUS 05
6 WB_06 WRITE BUS 06
7 WB_07 WRITE BUS 07
8 WB_08 WRITE BUS 08
9 WB_09 WRITE BUS 09
10 WB_10 WRITE BUS 10
11 WB_11 WRITE BUS 11
12 WB_12 WRITE BUS 12
13 WB_13 WRITE BUS 13
14 WB_14 WRITE BUS 14
15 WB_15 WRITE BUS 15 US (overflow) bit
16 WB_16 WRITE BUS 16 SG (sign) bit
OUTPUTS (from IO):
PIN signal full name state definition
40 RB_01 READ BUS 01 (lsb)
39 RB_02 READ BUS 02
38 RB_03 READ BUS 03
37 RB_04 READ BUS 04
36 RB_05 READ BUS 05
35 RB_06 READ BUS 06
34 RB_07 READ BUS 07
33 RB_08 READ BUS 08
32 RB_09 READ BUS 09
31 RB_10 READ BUS 10
30 RB_11 READ BUS 11
29 RB_12 READ BUS 12
28 RB_13 READ BUS 13
27 RB_14 READ BUS 14
26 RB_15 READ BUS 15 US (overflow) bit
25 RB_16 READ BUS 16 SG (sign) bit
22 BUSY2 READ BUS BUSY 0=OUT registers output to read bus
21 BUSY1 READ BUS BUSY 0=INP registers output to read bus
20 KB_STR KEY STROBE 1=key pressed strobe; to KEYRUPT. Key
data is valid on the negative edge of
KB_STR. Data is latched until the next
keypress.
IO DISPLAY/KEYBOARD (DSKY)
The keyboard/display portion of the IO module contains a keyboard, a bank of 7-segment
displays, a panel of discrete indicator lamps, and a board of display drivers.
DSKY KEYBOARD
The DSKY has an 18-button keyboard:
0-9 Decimal (or octal) digits.
+ Plus sign for decimal entries.
- Minus sign for decimal entries.
VERB Tells the AGC the next 2 digits
entered will be a VERB.
NOUN Tells the AGC the next 2 digits
entered will be a NOUN.
ENTER Tells the AGC the data entry is
finished.
CLEAR Clears an error in entry.
ERR RST Resets the OPR ERR alarm lamp.
KEY REL Tells the AGC it can have control of
the display. If the AGC wants
control of the display, the KEL REL
lamp will be flashing.
DSKY 7-SEGMENT DISPLAY
COMP ACTY A green indicator lamp that
illuminates when the AGC is not
idle. The lamp is controlled by the
“dummy job”, the lowest priority
job in the AGC EXEC software’s
non-preemptive multitasking.
When the dummy job is running,
the lamp is extinguished because
the AGC is idle. When the dummy
job exits because there is a higher
priority job running, the lamp
illuminates. The light is driven by
bit 1 of OUT1.
PROG The 2-digit code for the current
AGC program. Driven by OUT0.
VERB The 2-digit code for the selected
VERB. Verbs are actions;
directives for the AGC to do
something, such as loading or
displaying memory data. Driven
by OUT0.
NOUN The 2-digit code for the selected
NOUN. The noun is the thing
acted upon by the verb. Nouns usually refer to memory locations, which are
mapped to some AGC function. Driven by OUT0.
R1 Register 1. The uppermost of the three 5-digit displays. Registers R1, R2, and
R3 can display data in octal or decimal. Octal data is displayed without a sign.
Decimal data is indicated by the presence of a + or - sign in front of the data.
The displays I used in my replica cannot display a + sign, so I modified the
logic slightly: decimal data is represented by a leftmost decimal point.
Negative decimal numbers have a - sign and the decimal point; positive
numbers just have the decimal point. Driven by OUT0.
R2 Register 2. The middle of the three 5-digit displays. Driven by OUT0.
R3 Register 3. The bottommost of the three 5-digit displays. Driven by OUT0.
IO DISCRETE INDICATORS
The DSKY has a panel of discrete indicator lamps (LEDs) to show status or caution and
warning signals. Four of the lamps are driven by bits in output register 1 (OUT1). The parity
alarm is driven by a signal from the MEM module. The standby lamp is driven by the
standby state of the time pulse generator (TPG) in the CTL module.
UPLINK ACTY Uplink activity. Illuminates when data is uplinked to the AGC. Driven
by bit 3 (UPTL) of OUT1.
OPR ERR Operator Error (also called CHECK FAIL). Illuminates when the AGC
detects a data entry error. Driven by bit 7 of OUT1.
KEY REL Key Release. Illuminated by the AGC when it needs to use the display,
but the operator has taken control of it. The AGC causes this lamp to
flash to signal the operator to release control of the display by hitting
the KEY REL button. Driven by bit 5 (KEY RELS) of OUT1.
PROG Program Alarm. Illuminates when the AGC encounters an error
condition. Driven by bit 8 of OUT1.
STBY Standby. Illuminates when the AGC is in the STANDBY mode.
PARITY ALARM Illuminates when a parity error is detected during the memory cycle in
the MEM module.
KBD (Keyboard)
The keyboard is an 18-pushbutton unit that
generates and latches a 5-bit code. The code is
given in “Keyboard and Display System Program
for AGC (Program Sunrise)”, A. I. Green and J.
J. Rocchio, E-1574, MIT Instrumentation
Laboratory, Cambridge, MA, 1964.
The keyboard codes and logic for generating the
5-bit signal is reproduced to the right. The “Key
Name” column identifies the name of the
keyboard key; “A” through “E” are the 5 logic
signals for the 5-bit code, where “A” is the MSB.
The 18 switches in the
keyboard feed into the
combinational logic encoder
which generates the 5-bit
signal. The output of the
encoder feeds into a 5-bit
latch.
The keys are debounced by
generating a “keypress”
signal whenever a key is
pushed. The keypress signal
feeds through a “D” flip-flop
clocked at around 100Hz.
This samples the keypress
signal every 10 mSec and
latches the sample. The 10
mSec interval exceeds the
contact bounce time of the
keyboard switches.
To give the combinational logic time to settle before the keycode is latched, the output of the
keypress D flip-flop is fed into an RC monstable. Latching occurs on the trailing edge of the
one-shot pulse.
The keyboard codes are fed into “input register” IN0, which is really just a buffer that gates
the codes onto the read bus when the proper read signal is asserted. The original design also
maps the keypress strobe which generates the keyboard interrupt (KEYRUPT) onto bit 6 of
the register, but I skipped this since there doesn’t seem to be any practical reason for doing
it and the COLOSSUS flight software doesn’t seem to look at the field.
The STANDBY ALLOWED switch (CTL module) maps to be 14.
KBD INPUTS:
I/F signal full name state definition
CLK:
CLK2 CLOCK 2 data transfer occurs on falling edge
CPM:
GENRST GENERAL RESET 0=reset KBD register
KBD OUTPUTS:
I/F signal full name state definition
KBD:
KB_01 KEYBOARD BUS 01 Keyboard codes
...
KB_05 KEYBOARD BUS 05
INT:
KB_STR KEY STROBE 1=key pressed strobe; to KEYRUPT. Key
data is valid on the negative edge of
KB_STR. Data is latched until the next
keypress.
INP (Input Registers)
INP INPUTS:
I/F signal full name state definition
CPM:
RA4 READ IN0 0=output IN0 register to read bus
RA5 READ IN1 0=output IN1 register to read bus
RA6 READ IN2 0=output IN2 register to read bus
RA7 READ IN3 0=output IN3 register to read bus
KBD:
KB_01 KEYBOARD BUS 01
...
KB_05 KEYBOARD BUS 05
NSA STANDBY ALLOWED 0=standby allowed
INP OUTPUTS:
I/F signal full name state definition
RBUS:
RB_01 READ BUS 01
...
RB_14 READ BUS 14
RB_15 READ BUS 15 US (overflow) bit for read/write bus
RB_16 READ BUS 16 SG (sign) bit for read/write bus
BUSY READ BUS BUSY 0=output enabled to read bus
OUT (Output Registers)
OUT INPUTS:
I/F signal full name state definition
CLK:
CLK2 CLOCK 2 data transfer occurs on falling edge
CPM:
RA11 READ OUT1 0=OUT1 to read bus
RA12 READ OUT2 0=OUT2 to read bus
RA13 READ OUT3 0=OUT3 to read bus
RA14 READ OUT4 0=OUT4 to read bus
WA11 WRITE OUT1 0=load OUT1 from
write bus
WA12 WRITE OUT2 0=load OUT2 from
write bus
WA13 WRITE OUT3 0=load OUT3 from
write bus
WA14 WRITE OUT4 0=load OUT4 from
write bus
GENRST GENERAL RESET 0=clear DSKY, OUT1,
and OUT2.
WBUS:
WB_01 WRITE BUS 01
...
WB_14 WRITE BUS 14
WB_15 WRITE BUS 15 US (overflow) bit for
write bus
WB_16 WRITE BUS 16 SG (sign) bit for write
bus
OUT OUTPUTS:
I/F signal full name state definition
DSP:
OT0_01 OUT0 REG 01 OUT0 register output to
DSKY
...
OT0_16 OUT0 REG 16
OT1_01 OUT1 REG 01 COMP panel indicator; 1=on
OT1_03 OUT1 REG 03 UPTL panel indicator; 1=on
OT1_05 OUT1 REG 05 KEY RELS panel indicator; 1=on
OT1_07 OUT1 REG 07 CHECK FAIL panel indicator 1=on
OT1_08 OUT1 REG 08 STBY panel indicator 1=on
OT1_09 OUT1 REG 09 PROG ALM panel indicator 1=on
RBUS:
RB_01 READ BUS 01
...
RB_14 READ BUS 14
RB_15 READ BUS 15 US (overflow) bit for read/write bus
RB_16 READ BUS 16 SG (sign) bit for read/write bus
BUSY READ BUS BUSY 0=output enabled to read bus
DSP (Display)
The 7-segment DSKY display is driven by output register 0 (OUT0). Each 16-bit write to
OUT0 writes data to a pair of 7-segment digits.
Four fields in OUT0 are involved: The relay word (RLYWD; bits 12-15) field selects the pair of
digits; the DSPH field (bits 6-10) contains the 5-bit numerical code for the left digit in the
pair, and DPSL (bits 1-5) has the code for the right digit. The 1-bit DPSC (bit 11) field
controls verb/noun flash (enables 1 Hz blinking of the VERB and NOUN digits) and the plus
and minus signs to the left of the three 5-digit “registers” on the DSKY display.
Bits 15-12 Bit 11 Bits 10-6 Bits 5-1
RLYWD DSPC DSPH DSPL
1011 MD1 MD2
1010 FLASH VD1 VD2
1001 ND1 ND2
1000 UPACT R1D1
0111 +R1S R1D2 R1D3
0110 -R1S R1D4 R1D5
0101 +R2S R2D1 R2D2
0100 -R2S R2D3 R2D4
0011 R2D5 R3D1
0010 +R3S R3D2 R3D3
0001 -R3S R3D4 R3D5
Each 7-segment digit on the display has a name (VD1, VD2, etc). The
digits are physically arranged like this:
MD1 MD2 : major mode (PROG)
VD1 VD2 : VERB ND1 ND2 : NOUN
R1S R1D1 R1D2 R1D3 R1D4 R1D5 : register 1
R2S R2D1 R2D2 R2D3 R2D4 R2D5 : register 2
R3S R3D1 R3D2 R3D3 R3D4 R3D5 : register 3
In my assembled unit, the displays were in groups of 3, so some digits
were not needed and left unwired.
The 5-bit codes that illuminate each digit in the display are given below; these are the codes
sent to the DPSH and DPSL fields in OUT0.
In my implementation, I translate them into 4-bit binary-coded decimal representation (BCD)
and feed them into a 74LS47 7-segment decoder. The mapping of the AGC digit to my
74LS47 decoder code is also given. The AGC digit codes are very peculiar; I suspect they
were chosen for easy decoding into the 7-segment displays.
Digit AGC 74LS47
Blank 00000 1111
0 10101 0000
1 00011 0001
2 11001 0010
3 11011 0011
4 01111 0100
5 11110 0101
6 11100 0110
7 10011 0111
8 11101 1000
9 11111 1001
My initial block diagram for the DSP logic is shown here. Two combinational logic code
converters changes the 5-bit AGC code (DSPH, DPSL) into 4-bit BCD. The converted codes
are latched into 4-bit registers by write pulses decoded by the relay word (RLYWD) decoder.
Single bit latches hold the flash and sign bit codes transmitted by DSPC (bit 11 of OUT0).
Although I show separate decoders for each digit, I actually multiplexed the display to
minimize the hardware. In this way, I only needed a pair of 74LS47 decoders; one for DSPH
and the other for DSPL.
Some back-of-the-envelope bits and
pieces of the logic design are also
shown here. One “diagram” shows the
verb/noun flash logic. Note the simple
Karnaugh map (a graphical method for
reducing boolean expressions), and a
bit of bubble-pushing (a graphical
technique for applying DeMorgan’s
Theorem to transform logic functions
between AND and OR).
The other “diagram” shows the logic for
the +/- signs on registers 1, 2, and 3. The
displays I used in my replica cannot
display a + sign, so I modified the AGC
logic slightly: decimal data is represented
by a leftmost decimal point. Negative
decimal numbers have a - sign and
decimal point; positive decimal numbers
just have the decimal point.
The digit display portion of the DSKY uses green common-anode LED displays grouped in
three’s. Like most components, these were purchased from JAMECO. Here’s the pinouts:
A panel of discrete indicator LEDs are mapped against bits in output register 1 (OUT1).
DSP INPUTS:
I/F signal full name state definition
CLK:
CLK2 CLOCK 2 data transfer occurs on falling edge
PAR:
PARALM PARITY ALARM 1=parity alarm
INP:
OT0_01 OUT0 REG 01 OUT0 register output to DSKY
...
OT0_15 OUT0 REG 15
OT1_01 OUT1 REG 01 COMP panel indicator; 1=on
OT1_03 OUT1 REG 03 UPTL panel indicator;
1=on
OT1_05 OUT1 REG 05 KEY RELS panel
indicator; 1=on
OT1_07 OUT1 REG 07 CHECK FAIL panel
indicator 1=on
OT1_08 OUT1 REG 08 STBY panel indicator
1=on
OT1_09 OUT1 REG 09 PROG ALM panel
indicator 1=on
CPM:
WA10 WRITE OUT0 0=write into OUT0
(DSKY) from write bus
GENRST GENERAL RESET 0=clear the DSKY.
DSP OUTPUTS:
I/F signal full name state definition
none.
Fabrication
The IO module is (2) 13"x5" circuit boards, and 1 DSKY panel containing a display driver
board, a 7-segment display board, a discrete LED indicator board, and a keyboard.
Module Rack
The module framework is designed to
resemble a relay rack, but scaled to fit the
circuit board dimensions. It is constructed
out of 1"x2" pine and spray-painted semi-
gloss gray.
Circuit boards are mounted to the rack by 2
phillips screws at either end. Nylon spacers
(1/4") are used as standoffs to hold the
board edges above the rack. The boards are
mounted so the chips are in the back and
the pins are wiring are visible from the
front.
Power is distributed by 2 heavy aluminum
bus bars mounted vertically, one per side,
on the back of the module. Machine screws
are mounted through the bus bars at
evenly-spaced intervals to provide
connection points for the boards.
Solid copper wire (24 gauge) connects the
boards to the bus bars. Ring terminals are
used on the bus bar side of the connection. On the circuit board size, the wires are soldered
directly to the supply rails.
Materials were purchased from Home Depot, ACE Hardware, and Radio Shack.
Circuit Boards
The circuit boards are 13"x5" general purpose prototyping boards, epoxy glass with double-
side plated through pads on 0.1" centers (JAMECO 21477CL).
ICs are mounted in level 3 machine tooled wire-wrap sockets: 8, 14,
16, 20, 24, and 28 pin (JAMECO). Each socket has the pin-out labeled
with a w ire-wrap socket ID marker, which slips onto the socket before
wrapping (JAMECO). The part number is written onto the ID marker.
Sockets are arranged in 4 horizontal rows on each board, with about
10 sockets per row.
Power is distributed on the back-side of each board by bare 24-gauge
solid copper wire supply rails soldered at equal intervals to Klipwrap terminals: 3-prong
terminals with a square tail for wire-wrapping (JAMECO 34163CL). A +5V rail runs above
each row of sockets and a ground rail runs below. Each rail connects directly to the aluminum
module power bus using a ring tail connector.
On the pin side of the board, all connections are made with 30 AWG Kynar wire-wrap wire
(JAMECO). Red wire is used for direct connections to the +5V supply rail. Black wire is used
for direct connections to ground. White wire is used for everything else.
Power connections from the supply rails to each ICs are double-wrapped. Bypassing
capacitors (.1 uf disc ) are soldered across the supply rails at the Klipwrap terminals; about 1
capacitor for every 2 IC packages.
All connections were stripped and hand-wrapped using a Radio Shack hand-wrap tool. As
each connection was made, the corresponding line on the schematic was marked with a
colored highlighter.
DIP resistor networks (JAMECO) plugged into 20-pin wire-wrap sockets were used as current
limiting resistors for the panel indicators.
IO Circuit Board A
The A board contains the module interface buffers, input and output registers, and the
latches that hold the BCD codes for the 7-segment displays.
IO Circuit Board B
The B board contains keyboard and display logic. The 40-pin IDE connectors that interface to
the other modules are visible at the bottom. The 5 red LEDs show the keyboard code latched
into the KBD output register.
IO Device Driver Board C
The C board contains driver transistors and their associated resistors. The transistors are
plastic medium-power complementary si licon: NPN transistors are TIP102, PNP transistors
are TIP107. Viewed from the front of the TO-220 case, the base (1) is to the left, collector
(2) in the middle, and emitter (3) to the right. The metal tab (4) is the collector.
An empty space at the top of the IO module rack was filled with a plexiglass panel listing
verb and noun codes:
Parts (ICs)
IC’s, sockets, PCB’s, resistors, capacitors, wire-wrap wire were purchased from JAMECO. IDE
wire-wrap sockets were from DigiKey. Wire ties, wire-wrap tools, and copper wire were from
Radio Shack. IDE ribbon cables were purchased from an online computer supplier.
74LS00 (13) U27, U27B, U27C, U15C, U15B, U15, U14C, U14B, U14, U29D, U29C,
U29B, U34B
74LS02 (3) U25,U25,U33C
74LS04 (27) U40E, U40D, U38D, U38C, U40F, U40C, U39E, U39D, U39C, U39B,
U41D, U40B, U37F, U39F, U12, U12B, U12C, U12D, U12E, U11F, U11E,
U11D, U11C, U11B, U11, U39A, U37
74LS06 (41) U26F, U26E, U26D, U26C, U26B, U26, U20, U18D, U18C, U18B, U18,
U20C, U17E, U17D, U20B, U16F, U16E, U9, U9B, U9C, U9D, U9E, U9F,
U10, U10B, U10C, U10D, U7, U7B, U7C, U7D, U7E, U7F, U8, U20,
U19F, U19E, U19D, U19C, U19B, U19
74LS08 (1) U28
74LS10 (1) U4
74LS20 (5) U2, U3, U5, U31, U32
74LS27 (2) U35C, U36
74LS47 (4) U46, U47, U48, U45
74LS74 (1) U1
74LS86 (1) U24C
74LS112 (5) U6A, U23B, U22B, U21B, U30
74LS138 (9) U50, U67, U68, U69, U70, U73, U74, U75, U76
74LS148 (4) U65, U66, U71, U72
74LS154 (1) U51
74LS161A (1) U49
74LS244 (10) U101, U100, U52, U53, U77, U78, U81, U82, U83, U84
74LS273 (3) U79, U80, U44
74LS374 (11) U54, U55, U56, U57, U58, U59, U60, U61, U62, U63, U64
GREENCA (21) DISP1, DISP2, DISP3, DISP4,DISP5, DISP6, DISP7, DISP8, DISP9,
DISP10, DISP11, DISP12, DISP13, DISP14, DISP15, DISP16, DISP17,
DISP18, DISP19, DISP20, DISP21
555 (3) U85, U42, U43
NPN3 (35) Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q15, Q16, Q17, Q18, Q19, Q20, Q21,
Q32, Q33, Q34, Q35, Q36, Q37, Q38, Q39, Q40, Q41, Q42, Q43, Q44,
Q45, Q8, Q9, Q10, Q11, Q12, Q13, Q14
PNP3 (22) Q22, Q23, Q24, Q25, Q26, Q27, Q28, Q29, Q30, Q31, Q46, Q47, Q48,
Q49, Q50, Q51, Q52, Q53, Q54, Q55, Q56, Q57
Power Budget
qty mA (ea) mA (tot)
74LS00 13 2.4 31.2
74LS02 3 2.4 7.2
74LS04 27 3.6 97.2
74LS06 41 3.6 147.6
74LS08 1 4.4 4.4
74LS10 1 1.8 1.8
74LS20 5 1.2 6.0
74LS27 2 3.4 6.8
74LS47 4 7.0 28.0
74LS74 1 4.0 4.0
74LS86 1 6.1 6.1
74LS112 5 4.0 20.0
74LS138 9 6.3 56.7
74LS148 4 12.0 48.0
74LS154 1 6.2 6.2
74LS161 1 19.0 19.0
74LS244 10 32.0 320.0
74LS273 3 17.0 51.0
74LS374 11 27.0 297.0
555 3 3.0 9.0
GREENCA 21 140.0 2940.0
LED 25 20.0 500.0
----
4.6 Amps total
4.1 Amps (excluding single LEDs)
Block IApollo Guidance Computer (AGC)
How to build one in your basement
Part 6: Assembler
John Pultorak
December, 2004
Abstract
This report describes my successful project to build a working reproduction of the 1964
prototype for the Block I Apollo Guidance Computer. The AGC is the flight computer for the
Apollo moon landings, and is the world’s first integrated circuit computer.
I built it in my basement. It took me 4 years.
If you like, you can build one too. It will take you less time, and yours will be better than
mine.
I documented my project in 9 separate .pdf files:
Part 1 Overview: Introduces the project.
Part 2 CTL Module: Design and construction of the control module.
Part 3 PROC Module: Design and construction of the processing (CPU) module.
Part 4 MEM Module: Design and construction of the memory module.
Part 5 IO Module: Design and construction of the display/keyboard (DSKY) module.
Part 6 Assembler: A cross-assembler for AGC software development.
Part 7 C++ Simulator: A low-level simulator that runs assembled AGC code.
Part 8 Flight Software: My translation of portions of the COLOSSUS 249 flight
software.
Part 9 Test & Checkout: A suite of test programs in AGC assembly language.
Overview
This AGC cross-assembler, coded in C++, produces AGC object code in Motorola S-format.
The code can be burned into EPROM for use by the hardware AGC, or executed by the C++
AGC simulator.
OperationThe assembler reads an AGC source code text file (having a .asm extension). It generates
an assembly listing text file (.lst extension) and an two object code text files (_H.hex and
_L.hex suffixes). The object code files are readable by the AGC simulator or an EPROM
programmer.
SyntaxSource code files are text files containing multiple lines of source code. Each line is
terminated by a newline character. Source code files can be produced by any editor, as long
as it doesn't insert any hidden characters or formatting information.
Each line of source code consists of one of the following:
a) A blank line.
b) A comment (comments must begin with a semicolon (;)).
c) A line of assembler code.
The assembler ignores blank lines and anything that occurs after a semicolon on any given
line.
A line of assembler code consists of the following components:
1) A label (this is optional).
2) An op code or assembler directive.
3) An operand (also optional).
4) A comment (optional; comments must start with a semicolon).
The components, if present, must appear in the order given. Each component is separated
from the next by one or more white spaces or tabs. The only constraint is that the label, if
present, must start in the 1st column of the line. If no label is present, the op code or
assembler directive must not start in the 1st column, but may appear in any subsequent
column.
The operand may consist of one of the following:
a) An asterisk (the assembler substitutes in the current value of the location
counter.
b) A symbolic name (the assemble substitutes in the value during the second
pass of the assembly.
c) A numeric constant. Octal contants must be preceeded by a '%'; hexadecimal
constants are preceeded by a '$'; anything else is treated as a decimal.
d) An expression consisting of one or more of the above, separated by the
operators: +, -, @ (for multiplication), or / (for division). Unary plus or minus
is also allowed.
Examples:
*+2 Location counter plus 2.
LABEL+%10/2 LABEL plus octal number 10 divided by decimal number 2.
-5 Negative decimal 5.
Assembler DirectivesThe following directives are supported:
ORG Set the location counter to the operand following ORG.
EQU Set the label to the operand value.
DS Define a word of storage; set the value to the operand value.
CADR Define a word of storage; set the value to the operand value (assumed
to be a 14-bit address; this is an alias for CADR).
ADRES Define a word of storage; set the value to the operand value (operand
is treated as a 12-bit address).
INCL Inline include a file; the operand contains the filename.
AddressingThe location counter and symbol table always contain the full 14-bit address. AGC
instructions require a 12-bit address as an operand. Addressing is implemented in 1K banks
(bits 10 through 1). Bits 12 and 11 select banks 0 (erasable memory), 1 (fixed-fixed), or 2
(fixed-fixed). These banks are directly addressable in 12-bits. Banks above 2 are called
'fixed-switchable' and are addressed using the BANK register: bits 12 and 11 of the operand
are set to '1' and the bank register provides the high-order 4 bits (bits 14 through 11) of the
address. The lower 10 bits of the operand provide the address within the bank.
Errataa) The assembler ignores the last line of the source (.asm) file. If the last line of your
source file contains code, you must add an additional blank line to the end of your
source file to ensure that your last line of code is assembled.
b) The symbol table could be sorted before the second pass. The linear search through
the symbol table could be replaced by a more efficient method. (But, assembly is so
fast, it doesn’t matter).
c) The assembler directives and syntax don't match those of the original block I AGC.
d) A macro definition capability might be handy.
e) Generates empty .lst and .obj files if the source code file does not exist.
f) Incorrectly assigns a zero value to labels that equate to a forward referenced label.
i.e.:
LABEL1 EQU LABEL2 ; assembler incorrectly sets LABEL1 to zero
LABEL2 EQU *
Assembler listing
The assembler produces a list file (.lst) that shows the assembled source code. The format
of the file was designed to mimic (somewhat) the format of the original assembler. You will
find a fragment of the original assembler listing reproduced in part 8.
List files from my assembler have this format:
Object code
The object code is output to text files in Motorola S-Record format (S2F) suitable for
immediate use by EPROM programmers, and also readable by the C++ simulator.
There’s lots of documentation on S-Record formats on the internet.
The files are pretty big. If you open one up, you’ll discover they contain many short records
that look like these:
This is a fragment of the source code for the lower 8 bits of the TECO1 test and checkout
program (described in part 9).
The assembler contains C++ code for generating these files; the C++ simulator has code for
reading them.
Assembler v1.6
/* **************************************************************** * * Cross Assembler for Block I Apollo Guidance Computer (AGC4) * THIS VERSION IS MODIFIED TO OUTPUT IN S-RECORD FORMAT SUITABLE FOR * LOADING IN EPROM (s2f format). * Author: John Pultorak * 6/1/2002 * *****************************************************************
Versions:1.0 - First version of the AGC assembler.1.1 - Added ability to handle simple arithmetic expressions for the operand.1.2 - Changed label fields to 14 char. Printed symbol table in 3 columns.
Corrected wrong implementation of OVSK.1.3 - Added support for bank addressing.1.4 - Added capability to inline code with nested includes.1.5 - Added CADR, ADRES assembler directives. Swapped addresses for
TIME1 and TIME2 for compatibility with Block II PINBALL routines.1.6 - Fixed the parser so it doesn't mangle comments anymore. Added
FCADR and ECADR to the assembler directives. Added a check forassembled code that overwrites already used locations.
1.6 - EPROM Assembler outputs to low and high EPROM files.
Operation:The assembler reads an AGC source code file (having a .asm extension).It generates an assembly listing text file (.lst extension) and anobject code text file (.obj extension). The object code file is readableby the AGC simulator.
Syntax:Source code files are text files containing multiple lines of source code.Each line is terminated by a newline character. Source code files can beproduced by any editor, as long as it doesn't insert any hidden charactersor formatting information.
Each line of assembly code consists of one of the following:a) a blank line;b) a comment (comments must begin with a semicolon (;));c) or a line of assembler code.
The assembler ignores blank lines and anything that occurs after a semicolonon any given line.
A line of assembler code consists of the following components:1) a label (this is optional);2) an op code or assembler directive;3) an operand (also optional);4) a comment (optional; comments must start with a semicolon)
The components, if present, must appear in the order given. Each component isseparated from the next by one or more white spaces or tabs. The only constraintis that the label, if present, must start in the 1st column of the line. If nolabel is present, the op code or assembler directive must not start in the 1stcolumn, but may appear in any subsequent column.
The operand may consist of one of the following:a) an asterisk (the assembler substitutes in the current value of the
location counter;b) a symbolic name (the assemble substitutes in the value during the
second pass of the assembly;c) a numeric constant. Octal contants must be preceeded by a '%';
hexadecimal constants are preceeded by a '$'; anything elseis treated as a decimal.
d) an expression consisting of one or more of the above, separated by the operators: +, -, @ (for multiplication), or / (for division).
Unary plus or minus is also allowed.examples:
*+2 means location counter plus 2LABEL+%10/2-5
Assembler Directives:The following directives are supported:ORG - set the location counter to the operand following ORG.EQU - set the label to the operand value.DS - define a word of storage; set the value to the operand value.CADR - define a word of storage; set the value to the operand value (assumed to be a 14-bit address; this is an alias for CADR).ADRES - define a word of storage; set the value to the operand value (operand is treated as a 12-bit address).INCL - inline include a file; the operand contains the filename.
Addressing:The location counter and symbol table always contain the full 14-bit address.AGC instructions require a 12-bit address as an operand. Addressing is implementedin 1K banks (bits 10 through 1). Bits 12 and 11 select banks 0 (erasable memory),1 (fixed-fixed), or 2 (fixed-fixed). These banks are directly addressable in12-bits. Banks above 2 are called 'fixed-switchable' and are addressed usingthe BANK register: bits 12 and 11 of the operand are set to '1' and the bank register provides the high-order 4 bits (bits 14 through 11) of the address. The lower 10 bits of the operand provide the address within the bank.
Errata:The assembler ignores the last line of the source (.asm) file. If the lastline of your source file contains code, you must add an additional blankline to the end of your source file to ensure that your last line of codeis assembled.
The symbol table should be sorted before the second pass. The linearsearch through the symbol table should be replaced by a more efficientmethod.
The assembler directives and syntax don't match those of the original block I AGC.
A macro definition capability would be handy.
Generates empty .lst and .obj files if the source code file does not exist.
Incorrectly assigns a zero value to labels that equate to a forward referencedlabel. i.e.:
LABEL1 EQU LABEL2 ; assembler incorrectly sets LABEL1to zero
LABEL2 EQU *
The assembler generates object code for eraseable memory addresses.*/
#include <string.h>#include <stdlib.h>#include <ctype.h>#include <iostream.h>#include <stdio.h>
// Create a flag for each memory location in a 14-bit address space// These are initialized to false, and then set as the code is assembled.// An attempt to assemble code on top of a previously used location is// flagged as an error.
const unsigned agcMemSize = 037777+1; // # of cells in a 14-bit address rangebool memoryUsed [agcMemSize];
//***********************************************************************// MODIFIED FROM THE ORIGINAL ASSEMBLER HERE.// This array represents the fixed memory PROM (14-bit address) int EPROM_H [agcMemSize];int EPROM_L [agcMemSize];//***********************************************************************
unsigned pass = 0;unsigned locCntr = 0; // address in 14-bit formatunsigned errorCount = 0;
FILE* fpList = 0; // output (assembly listing)
//***********************************************************************// MODIFIED FROM THE ORIGINAL ASSEMBLER HERE.FILE* fpObj_H = 0; // output MSB's (object code in S-RECORD format)FILE* fpObj_L = 0; // output LSB's (object code in S-RECORD format)//***********************************************************************
struct ocode{
char* name;unsigned code;bool isOpCode; // true=it is an op codebool addrOpnd; // true=convert operand to 12-bit address formatunsigned len; // words
};
ocode allcodes[] = {
// Block I op codes.{ "TC", 0000000, true, true, 1 }, { "CCS", 0010000, true, true, 1 }, { "INDEX", 0020000, true, true, 1 }, { "XCH", 0030000, true, true, 1 }, { "CS", 0040000, true, true, 1 }, { "TS", 0050000, true, true, 1 }, { "AD", 0060000, true, true, 1 }, { "MASK", 0070000, true, true, 1 }, { "MP", 0040000, true, true, 1 }, { "DV", 0050000, true, true, 1 }, { "SU", 0060000, true, true, 1 },
// Implied address codes (R393: 3-12){ "RESUME", 0020025, true, false, 1 }, // INDEX 25{ "EXTEND", 0025777, true, false, 1 }, // INDEX 5777{ "INHINT", 0020017, true, false, 1 }, // INDEX 17{ "RELINT", 0020016, true, false, 1 }, // INDEX 16{ "XAQ", 0000000, true, false, 1 }, // TC A{ "RETURN", 0000001, true, false, 1 }, // TC Q{ "NOOP", 0030000, true, false, 1 }, // XCH A{ "COM", 0040000, true, false, 1 }, // CS A{ "TCAA", 0050002, true, false, 1 }, // TS Z{ "OVSK", 0050000, true, false, 1 }, // TS A{ "DOUBLE", 0060000, true, false, 1 }, // AD A{ "SQUARE", 0040000, true, false, 1 }, // MP A
// For "clarity" (R393: 3-12){ "TCR", 0000000, true, true, 1 }, // same as TC; subroutine call with return{ "CAF", 0030000, true, true, 1 }, // same as XCH; address to fixed acts like
Clear and Add{ "OVIND", 0050000, true, true, 1 }, // same as TS
// Assembler directives{ "DS", 0, false, false, 1 }, // define storage; reserves 1 word of memory{ "CADR", 0, false, false, 1 }, // define 14-bit addr; reserves 1 word of memory{ "FCADR", 0, false, false, 1 }, // define 14-bit addr; reserves 1 word of memory{ "ECADR", 0, false, false, 1 }, // define 14-bit addr; reserves 1 word of memory{ "ADRES", 0, false, true, 1 }, // define 12-bit addr; reserves 1 word of memory{ "ORG", 0, false, false, 0 }, // origin; sets location counter to operand value{ "EQU", 0, false, false, 0 }, // equate; assigns a value to a label{ "INCL", 0, false, false, 0 }, // include; inline include source code{ "", 0, false, false, 99 } // end-of-list flag
};
void parse(char* buf, char* labl, char* opcd, char* opnd, char* cmnt){
// strip off newline char.buf[strlen(buf) - 1] = '\0';
// replace any horizontal tabs with spacesfor(unsigned i=0; i<strlen(buf); i++) {
if(buf[i] == ';') break; // don't edit commentsif(buf[i] == '\t') buf[i] = ' ';
}
strcpy(labl,"");
strcpy(opcd,""); strcpy(opnd,""); strcpy(cmnt,"");
char* sp = buf;char* s = 0;
enum {_labl=0, _opcd, _opnd, _cmnt } mode = _labl;
if(buf[0] == ' ') mode = _opcd;do{
s = strtok(sp, " "); sp = 0;if(s){
if(s[0] == ';'){
// Copy the remainder of the comment verbatim.strcat(cmnt, s); strcat(cmnt, " "); s += strlen(s) + 1; strcat(cmnt, s);return;
}switch(mode){case _labl: strcat(labl, s); mode = _opcd; break;case _opcd: strcat(opcd, s); mode = _opnd; break;case _opnd: strcat(opnd, s); mode = _cmnt; break;}
}} while(s);
}
struct symbl{
char name[20];unsigned val;
};
symbl symTab[5000];unsigned nSym = 0;
// Pre-defined symbols corresponding to architectural// conventions in the block I AGC4.
symbl constSymTab[] = {
{ "A", 00 },{ "Q", 01 },{ "Z", 02 },{ "LP", 03 },{ "IN0", 04 },{ "IN1", 05 },{ "IN2", 06 },{ "IN3", 07 },{ "OUT0", 010 },{ "OUT1", 011 },{ "OUT2", 012 },{ "OUT3", 013 },{ "OUT4", 014 },{ "BANK", 015 },{ "CYR", 020 },{ "SR", 021 },{ "CYL", 022 },{ "SL", 023 },{ "ZRUPT", 024 },{ "BRUPT", 025 },{ "ARUPT", 026 },{ "QRUPT", 027 },{ "OVCTR", 034 },{ "TIME2", 035 },{ "TIME1", 036 },{ "TIME3", 037 },{ "TIME4", 040 },{ "GOPROG", 02000 },
{ "T3RUPT", 02004 },{ "ERRUPT", 02010 },{ "DSRUPT", 02014 },{ "KEYRUPT", 02020 },{ "UPRUPT", 02024 },{ "EXTENDER", 05777 },{ "BANK0", 000057 }, // erasable memory, just above the counter assignments{ "BANK1", 002000 }, // fixed-fixed{ "BANK2", 004000 }, // fixed-fixed{ "BANK3", 006000 }, // start of fixed-switchable{ "BANK4", 010000 },{ "BANK5", 012000 },{ "BANK6", 014000 },{ "BANK7", 016000 },{ "BANK10", 020000 },{ "BANK11", 022000 },{ "BANK12", 024000 },{ "BANK13", 026000 },{ "BANK14", 030000 },{ "", 0 }
};
void add(char* labl, unsigned value){
// Check whether symbol is already defined.unsigned i;for(i=0; i<nSym; i++){
if(strcmp(symTab[i].name, labl)==0){
fprintf(fpList,"*** ERROR: %s redefined.\n", symTab[i].name);errorCount++;return;
}}
// Add new symbol to symbol tablestrcpy(symTab[nSym].name, labl);symTab[nSym].val = value;nSym++;
}
// Return the int value of the operand string. The string is// assumed to be a simple value (not an expression)int _getopnd(char* opnd){
if(strlen(opnd)==0)return 0;
else if(opnd[0] == '$') // hex numberreturn strtol(opnd+1, 0, 16);
else if(opnd[0] == '%') // octal numberreturn strtol(opnd+1, 0, 8);
else if(isdigit(opnd[0])) // decimal numberreturn strtol(opnd, 0, 10);
else if(opnd[0] == '*')return locCntr;
else // must be label; look up value{
unsigned i;for(i=0; i<nSym; i++){
if(strcmp(symTab[i].name, opnd)==0)return symTab[i].val;
}
// Not there, so check whether symbol is an// assembler-defined constant. If so, copy it to// the user-defined symbols.for(i=0; strcmp(constSymTab[i].name,"") != 0; i++){
if(strcmp(constSymTab[i].name, opnd)==0){
strcpy(symTab[nSym].name, opnd);symTab[nSym].val = constSymTab[i].val;nSym++;
return constSymTab[i].val;}
}
if(pass == 1){
fprintf(fpList,"*** ERROR: %s undefined.\n", opnd);errorCount++;
}}return 0;
}
// returns pointer to new position in istrchar* getToken(char* istr, char* ostr){
*ostr = '\0';
// bump past any whitespacewhile(*istr == ' ') istr++;
if(*istr == '\0') return istr;
bool keepGoing = true;do{
*ostr = *istr;if(*ostr == '+' || *ostr == '-' || *ostr == '@' || *ostr == '/')
keepGoing = false;ostr++; istr++;
}while(keepGoing && *istr != '\0' && *istr != '+' && *istr != '-'
&& *istr != '@' && *istr != '/');
*ostr = '\0';return istr;
}
int _eval(char* sp, int tot){
if(*sp == '\0') return tot;
char op[20];sp = getToken(sp, op);
char vstr[20];int val = 0;sp = getToken(sp,vstr);if(*vstr =='-') // unary minus{
sp = getToken(sp, vstr);val = -(_getopnd(vstr));
}else
val = _getopnd(vstr);
switch(*op){case '+': tot += val; break;case '-': tot -= val; break;case '@': tot *= val; break;case '/': tot /= val; break;}
return _eval(sp,tot);}
int eval(char* sp){
char op[20];getToken(sp, op);char sp1[80];if(*op != '+' && *op != '-')
strcpy(sp1,"+");else
strcpy(sp1,"");
strcat(sp1, sp);return _eval(sp1, 0);
}
// Return the value of the operand string. The string may// be a simple token or an expression consisting of multiple// tokens and operators. Evaluation occurs from left to right;// no parenthesis allowed. Unary minus is allowed and correctly// evaluated. Valid operators are +, -, @, and /. The @ operator// is multiplication (the traditional * operator already is used// to refer to the location counter.unsigned getopnd(char* opnd){
//return _getopnd(opnd); // the old call did not allow for expressions
unsigned retval = 0;if(strcmp(opnd,"-0") == 0 || strcmp(opnd,"-%0") == 0 || strcmp(opnd,"-$0") == 0)
retval = 077777; // -0else{ // return the int value of the operand
int opndVal = eval(opnd);
// now, convert the number into 16-bit signed AGC formatif(opndVal < 0){
// convert negative values into AGC 16-bit 1's C form.opndVal = 077777 + opndVal;if(opndVal < 0){
fprintf(fpList,"*** ERROR: %s underflowed.\n", opnd);errorCount++;opndVal = 0;
}}else if(opndVal > 077777){
fprintf(fpList,"*** ERROR: %s overflowed.\n", opnd);errorCount++;opndVal = 0;
}retval = (unsigned) opndVal;
}return retval;
}
bool isDefined(char* opcd){
for(int j=0; allcodes[j].len != 99; j++){
if(strcmp(allcodes[j].name, opcd) == 0){
return true;}
}return false;
}
unsigned getopcode(char* opcd){
for(int j=0; allcodes[j].len != 99; j++){
if(strcmp(allcodes[j].name, opcd) == 0){
return allcodes[j].code;}
}fprintf(fpList,"*** ERROR: %s undefined.\n", opcd);errorCount++;
return 0;}
bool has12bitAddr(char* opcd){
for(int j=0; allcodes[j].len != 99; j++)
{if(strcmp(allcodes[j].name, opcd) == 0){
return allcodes[j].addrOpnd;}
}return false;
}
bool isOpCode(char* opcd){
for(int j=0; allcodes[j].len != 99; j++){
if(strcmp(allcodes[j].name, opcd) == 0){
return allcodes[j].isOpCode;}
}return false;
}
unsigned getoplen(char* opcd){
for(int j=0; allcodes[j].len != 99; j++){
if(strcmp(allcodes[j].name, opcd) == 0){
return allcodes[j].len;}
}return 0;
}
void updateLocCntr(char* opcd, char* opnd){
unsigned size = 0;for(int i=0; allcodes[i].len != 99; i++){
if(strcmp(allcodes[i].name, opcd) == 0){
size = allcodes[i].len; break;}
}locCntr += size;
if(strcmp(opcd,"ORG") == 0){
locCntr = getopnd(opnd);}
}
unsigned genOddParity(unsigned r){
//check the lower 15 bits of 'r' and return the odd parityunsigned evenParity =
(1&(r>>0)) ^ (1&(r>>1)) ^ (1&(r>>2)) ^ (1&(r>>3)) ^(1&(r>>4)) ^ (1&(r>>5)) ^ (1&(r>>6)) ^ (1&(r>>7)) ^(1&(r>>8)) ^ (1&(r>>9)) ^ (1&(r>>10)) ^ (1&(r>>11)) ^(1&(r>>12)) ^ (1&(r>>13)) ^ (1&(r>>14));
return ~evenParity & 1; // odd parity}
// Read the source file and build the symbol table.void readSourceForPass1(char* fn){
char buf[256];char labl[100]; // labelchar opcd[100]; // op codechar opnd[100]; // operandchar cmnt[100]; // comment
// Open the source code file.FILE* fp = fopen(fn, "r");if(!fp){
perror("fopen failed for source file");return;
}
while(fgets(buf, 256, fp)){
parse(buf, labl, opcd, opnd, cmnt);
if(strcmp(opcd,"INCL")==0)readSourceForPass1(opnd);
if(strlen(labl)>0){
if(strcmp(opcd,"EQU")==0)add(labl, getopnd(opnd));
elseadd(labl, locCntr);
}updateLocCntr(opcd, opnd);
}fclose(fp);
}
// Read the source file and symbol table and build// the object code
void readSourceForPass2(char* fn){
char buf[256];char labl[100]; // labelchar opcd[100]; // op codechar opnd[100]; // operandchar cmnt[100]; // comment
// Open the source code file.FILE* fp = fopen(fn, "r");if(!fp){
perror("fopen failed for source file");return;
}
while(fgets(buf,256,fp)){
parse(buf, labl, opcd, opnd, cmnt);
if(strcmp(opcd,"INCL")==0){
// Include directive (INCL).fprintf(fpList, " %-14s %-8s %-14s %s\n",
labl, opcd, opnd, cmnt);readSourceForPass2(opnd);
}else if(strcmp(opcd,"")==0){
// Comment.fprintf(fpList, " %s\n", cmnt);
}else if(getoplen(opcd) == 0){
// Must be ORG or EQU assembler directive.fprintf(fpList, " %-14s %-8s %-14s %s\n",
labl, opcd, opnd, cmnt);
if(!isDefined(opcd)){
fprintf(fpList,"*** ERROR: %s undefined.\n", opcd);errorCount++;
}}else{
// Since we got this far, we know the assembly line contains a// valid 'opcd' that reserves some storage space. It must be an// instruction or a DS.
// Location counter (locCntr) contains 14-bit address; symbol table
// also stores 14-bit addresses. If the operand is an address above// bank 3 (05777), it is not directly addressable and needs to be// converted into a 12-bit bank address. In bank addressing, bits// 12,11 are set and bits 10-1 contain the address inside the bank.// (The programmer must set the bank register to select the correct// bank.)
// Generate a string containing the address (for the list file).// If the address is erasable, or fixed-fixed, show the 12-bit// address. // If the address is fixed-switchable, show the bank number,// followed by the 10-bit bank address.
unsigned locCntrBank = (036000 & locCntr) >> 10;char locCntrString[20];if(locCntrBank <= 3) sprintf(locCntrString, " %04o", locCntr);else
sprintf(locCntrString, "%2o,%04o", locCntrBank, 01777 & locCntr);
// Generate the data to be stored at that address. Convert to// 12-bit address format, if necessary.
unsigned operValue = getopnd(opnd);unsigned operBank = (036000 & operValue) >> 10;if(has12bitAddr(opcd)){
// Convert operand from a 14-bit address to a 12-bit// address.// First, find bank (bits 14-11). If the bank is <= 03, no// conversion is necessary.
if(operBank > 03){
// Bank is not directly addressable, so get 10 bit// bank address and set fixed-switchable flag bits// 12 and 11.
operValue = (01777 & operValue) | 06000;}
}unsigned data = getopcode(opcd) + operValue;data |= genOddParity(data) << 15;
// Generate a string containing the data info for the list file.char dataString[20];if(isOpCode(opcd))
sprintf(dataString, "%01o %2o,%04o %1o", (getopcode(opcd) & 070000) >> 12, operBank, operValue,
genOddParity(data));else
sprintf(dataString, " %05o %1o", operValue, genOddParity(data));
if(memoryUsed[locCntr]){
fprintf(fpList,"*** ERROR: %06o address already in use.\n",locCntr);
errorCount++;}memoryUsed[locCntr] = true;
fprintf(fpList, "%05o %7s %11s %-14s %-8s %-14s %s\n",locCntr, locCntrString, dataString, labl, opcd, opnd, cmnt);
//***********************************************************************// MODIFIED FROM THE ORIGINAL ASSEMBLER HERE.// Insert the assembled code into an array, indexed by the address.// This has the effect of sorting the data by address, so we can walk// through the addresses and output the code to EPROM later.unsigned dataLow = 0x00ff & data;unsigned dataHigh = (0xff00 & data) >> 8;
if(locCntr >=1024) // FIXED MEMORY only; not ERASEABLE{
// fixed memoryEPROM_H [locCntr] = dataHigh;EPROM_L [locCntr] = dataLow;
}//***********************************************************************
}
updateLocCntr(opcd, opnd);}fclose(fp);
}
//***********************************************************************// MODIFIED FROM THE ORIGINAL ASSEMBLER HERE.
void writeEPROM(FILE* fpObj, int EPROM[]){
// Write an EPROM file using Motorola's S-Record format (s2f).
// Some parameters that control file format. You can change maxBytes// without affecting anything else. 'addressBytes' is determined by// the choosen S-Record format.
const int maxBytes = 20; // set limit on record lengthconst int addressBytes = 3; // 16-bit address rangeconst int sumCheckBytes = 1;
const int maxdata = maxBytes - addressBytes - sumCheckBytes;
int i=0; // current EPROM addressint sumCheck = 0;while (i < agcMemSize){
// get dataByteCount; the number of bytes of EPROM data per record.int dataByteCount = maxdata;if(i + dataByteCount >= agcMemSize){
dataByteCount = agcMemSize - i;}
// write record header (*** 2 byte address assumed ***)int totalByteCount = dataByteCount + addressBytes + sumCheckBytes;fprintf(fpObj, "S2%02X%06X", totalByteCount, i);sumCheck = totalByteCount & 0xff;sumCheck = (sumCheck + ((i & 0xff0000) >> 16)) % 256;sumCheck = (sumCheck + ((i & 0x00ff00) >> 8)) % 256;sumCheck = (sumCheck + ((i & 0x0000ff) )) % 256;
// write data bytes into recordfor(int j=0; j<dataByteCount; j++){
fprintf(fpObj, "%02X", EPROM [i+j]);sumCheck = (sumCheck + EPROM [i+j]) % 256;
}// terminate record by adding the checksum and a newline.
fprintf(fpObj, "%02X\n", (~sumCheck) & 0xff);
i += dataByteCount;}
// write an end-of-file record herei=0; // set address zero for last recordsumCheck = 0x04; // byte countsumCheck = (sumCheck + ((i & 0xff0000) >> 16)) % 256;sumCheck = (sumCheck + ((i & 0x00ff00) >> 8)) % 256;sumCheck = (sumCheck + ((i & 0x0000ff) )) % 256;fprintf(fpObj, "S804%06X%02X", i, (~sumCheck) & 0xff);
}
//***********************************************************************
void main(int argc, char* argv[]){
cout << "AGC Block I assembler" << endl;
// The assembler reads an assembly source code file// with a .asm extension; i.e.: myProg.asm// It writes an assembly listing text file with// a .lst extension (myProg.lst) and an object code
// text file with a .obj extension (myProg.obj)#ifdef NOTDEF
// use this to enter the source file using command lineif(argc != 2){
cout << "*** ERROR: source file name not specified." << endl;exit(-1);
}
fp = fopen(argv[1], "r");#endif
char sourcefile[80];cout << "Enter source file: ";cin >> sourcefile;
// Valid source files have a .asm extension; strip the// extension off so we can use the prefix for the list// and object files.
char prefix[80];strcpy(prefix, sourcefile);
char* p = prefix;while(*p != '\0') { p++; if(*p == '.') break; }if(strcmp(p,".asm") != 0){
cerr << "*** ERROR: Source file not *.asm" << endl;exit(-1);
}*p = '\0';
// Open a text file for the assembly listing. The filename// will have a .lst extension.
char listfile[80];sprintf(listfile, "%s.lst", prefix);fpList = fopen(listfile, "w");if(!fpList){
perror("fopen failed for assembly list file");exit(-1);
}
//***********************************************************************// MODIFIED FROM THE ORIGINAL ASSEMBLER HERE.
// Open a two text files for the object code. The filenames// will have a .hex extension
char objfile[80];
sprintf(objfile, "%s_H.hex", prefix);fpObj_H = fopen(objfile, "w");if(!fpObj_H){
perror("fopen failed for object file");exit(-1);
}
sprintf(objfile, "%s_L.hex", prefix);fpObj_L = fopen(objfile, "w");if(!fpObj_L){
perror("fopen failed for object file");exit(-1);
}
fprintf(fpList,"Block I Apollo Guidance Computer (AGC4) assembler version 1.6 forEPROM\n\n");
// INITIALIZE EPROMfor(int k=0; k< agcMemSize; k++){
EPROM_H [k] = 0;EPROM_L [k] = 0;
}//***********************************************************************
fprintf(fpList,"First pass: generate symbol table.\n");
readSourceForPass1(sourcefile);
locCntr = 0;pass++;
// Clear the memory use flags; these are used to catch// any overwriting of already assembled code.
memset(memoryUsed, false, sizeof(bool) * agcMemSize);
fprintf(fpList,"Second pass: generate object code.\n\n");readSourceForPass2(sourcefile);
//***********************************************************************// MODIFIED FROM THE ORIGINAL ASSEMBLER HERE.
// Write the EPROM data to filewriteEPROM(fpObj_H, EPROM_H);writeEPROM(fpObj_L, EPROM_L);
fclose(fpObj_H);fclose(fpObj_L);//***********************************************************************
fprintf(fpList,"\nAssembly complete. Errors = %d\n", errorCount);
fprintf(fpList,"\nSymbol table:\n");
unsigned j=0;for(unsigned i=0; i<nSym; i++){
fprintf(fpList,"%-14s %06o ", symTab[i].name, symTab[i].val);j = (j+1) % 3;if(j==0) fprintf(fpList,"\n");
}fclose(fpList);
}
Block IApollo Guidance Computer (AGC)
How to build one in your basement
Part 7: C++ Simulator
John Pultorak
December, 2004
Abstract
This report describes my successful project to build a working reproduction of the 1964
prototype for the Block I Apollo Guidance Computer. The AGC is the flight computer for the
Apollo moon landings, and is the world’s first integrated circuit computer.
I built it in my basement. It took me 4 years.
If you like, you can build one too. It will take you less time, and yours will be better than
mine.
I documented my project in 9 separate .pdf files:
Part 1 Overview: Introduces the project.
Part 2 CTL Module: Design and construction of the control module.
Part 3 PROC Module: Design and construction of the processing (CPU) module.
Part 4 MEM Module: Design and construction of the memory module.
Part 5 IO Module: Design and construction of the display/keyboard (DSKY) module.
Part 6 Assembler: A cross-assembler for AGC software development.
Part 7 C++ Simulator: A low-level simulator that runs assembled AGC code.
Part 8 Flight Software: My translation of portions of the COLOSSUS 249 flight
software.
Part 9 Test & Checkout: A suite of test programs in AGC assembly language.
Overview
This document describes my AGC Block I C++ simulator. I developed it almost entirely from
detailed information in this document:
A. Hopkins, R. Alonso, and H. Blair-Smith, "Logical Description for the Apollo Guidance
Computer (AGC4)", R-393, MIT Instrumentation Laboratory, Cambridge, MA, Mar. 1963.
My simulator reproduces not only the AGC instruction set and user-accessible registers, but
all of the registers, all microinstructions, time-pulse generator states, read, write and
memory busses, and control pulses (logic signals) for all AGC subsystems.
The simulator is a tool I used to capture AGC design from the R-393 document. When I got
it working well enough to run my test and checkout software suite (described in part 9) and
flight software (described in part 8), I knew I understood the AGC well enough to build one.
The simulator header and source code files became requirements that guided my AGC logic
design (described in parts 2-5).
Running the simulator
The simulator is run by keyboard commands. The output is a scrolling, formatted text
display; the compiler obligingly provides a little DOS window for viewing the output. It looks
like this (most of
the numbers are
in octal):
The top line is
the revision
number of the
simulator. I
went through
lots of versions.
The second line
shows the Time
Pulse Generator
state (TP11) and
some of the
important scaler
outputs.
The next line shows the current state of some small registers in the SEQ subsystem, which
is part of the AGC control module. STA and STB stage registers which select instruction
subsequences. BR1 and 2 are the branch registers. SNI is “select next instruction”, a 1-bit
register that does exactly that. CI is the “carry-in” bit for the ALU. The loop counter is used
for iterating through arithmetic instructions.
The next line, starting with RPCELL, shows important registers associated with interrupts
and the priority counters. The tail-end of the line shows the current instruction (in the SQ
register), which is an INDEX instruction. The subsequence is NDX0.
The next line (CP) shows currently asserted control pulses (logic signals). ST1 and WE are
being asserted.
The left side of the next 4 lines shows the state of registers associated with memory (S, G,
P, P2, and CADR), the ALU (B, X, Y, U), and the read bus (RBU) and write bus (WBU).
The right side of those 4 lines shows control inputs for running, stepping, and clocking the
simulator.
The bottom part of the display shows AGC memory. The 2-digit numbers on the left show
memory addresses from 00-56. Each memory location has a name; it’s shown to the right of
the address. Immediately to the right of that is the contents of that location.
Addresses 00-17 are mapped to AGC registers, and are not really part of the AGC eraseable
memory. Addresses 00-03 are the AGC central registers, followed by input and output
registers.
Addresses 16 and 17 are not storage locations, but a means for enabling and disabling
interrupts.
The eraseable memory starts at address 20. Addresses 20-23 are the editing registers.
Writing to these causes the data in the registers to be shifted or rotated.
Addresses 24-27 are used for saving the central registers (00-03) when an interrupt occurs.
Addresses 34-56 are priority counter locations. The AGC will increment or decrement these
based on + pr - logic signals to the priority counter cells.
The lower right of the simulator is the DSKY: the display/keyboard user interface for the
astronauts. The simulator is running the COLOSSUS 249 flight software load, and is
currently executing major mode 0 (P00), verb 16, noun 36, which is a monitor program to
continuously display the command module elapsed time clock. The clock, displayed in R1,
R2, and R3, shows 0 hours, 1 minute, and 54.23 seconds. It updates about once a second
but, of course, you can’t see that here.
Compiler
The simulator was compiled with Microsoft Visual C++ 6.0 Standard Edition.
Commands
Here’s the complete list of commands the simulator knows. The keyboard key you hit is:
{Q}, and the name of the command is: <QUIT>.
Simulator commands{q} <QUIT> Exits the simulator.
{l} <LOAD> The command is a lower case “L”, not a “1". Load fixed
memory with object code produced by the assembler.
The object code files are in Motorola S-Record format
(compatible with EPROM programmers). The command
will ask for a filename.
{m} <MENU> Intended to be a useful menu of simulator command,
but I never got around to it.
Hardware reset commands{p} <POWER UP RESET> Asserts the PURST control signal. This is a power-up
reset signal that is supposed to be automatically
generated when the AGC initially powers on.
{h} <RESET> Asserts the GENRST control signal.
Clock controls{F1} <CLK> Single-step the AGC clock. Only works when MCLK <F2>
has been selected.
{F2} <MCLK> Asserts the MCLK control signal. Disables the free-
running 1MHz clock. When MCLK is selected, you can
single-step the clock by by pressing <F1>.
{F4} <FCLK> Asserts the FCLK control signal. Causes the simulator
clock to free-run at 1MHz. This is the normal operational
mode.
Time pulse generator (TPG) controls{r} <RUN> Toggles between the “run” (1) and “step” (0) modes.
“Run” makes the AGC free-run (the normal mode).
“Step” single-steps the AGC, either by instruction or by
instruction subsequence.
{s} <STEP> Steps the AGC to the next instruction or instruction
sequence when <R> is toggled to the step mode.
{n} <INST> Toggles whether the AGC steps by instruction (1) or
instruction subsequence (0). Each instruction contains
one or more subsequences. Each subsequence is 12
steps or timing pulses long.
Debugger commands{e} <EXAMINE> Examines the contents of memory. The command asks
for a starting address and then displays the memory
data at that address and following locations.
{y} <WATCH> Halts the AGC when any instruction changes a watched
memory location. The command asks for a memory
address (CADR) to watch.
{b} <BREAKPOINT> Toggles a breakpoint on/off. When the breakpoint is on,
it halts the AGC when instruction execution hits that
address.
{d} <DISPLAY> Displays or refreshes the standard AGC register display.
{f} <DEBUG> Displays the currently executing AGC source code. You
can single step with this display and watch the AGC
move through the source code. Very useful for
debugging. A “>” arrow shows the next instruction to be
executed in the listing.
Scaler controls{z} <F17> Manually generates the <F17> scaler pulse. Useful for
testing when the scaler has been toggled to off <C>, or
when you’re single-stepping the AGC.
{x} <F13> Manually generates the <F13> scaler pulse. Useful for
testing when the scaler has been toggled to off <C>, or
when you’re single-stepping the AGC.
{c} <TOGGLE SCALER> Toggle the scaler on/off. When the scaler is off, the F13
and F17 signals are not automatically generated.
Priority counter controls{[} <-CNTR> Manually assert a m inus input to a prority counter cell.
The command will ask for the cell number.
{]} <+CNTR> Manually assert a p lus input to a priority counter cell.
The command will ask for the cell number.
Interrupt controls{i} <INTERRUPT> Generates an AGC interrupt. The command will ask you
for an interrupt number (1-5).
Other AGC controls{a} <STANDBY ALLOWED> The standby allowed switch lets the AGC software put
the AGC in a standby mode.
{;} <CLEAR PARITY ALARM> Clears the parity alarm. The alarm is generated when an
error occurs (odd parity) in memory.
DSKY controls{/} <VERB> The VERB key on the DSKY display.
{*} <NOUN> The NOUN key on the DSKY display.
{-} <MINUS> The MINUS key on the DSKY display.
{+} <PLUS> The PLUS key on the DSKY display.
{.} <CLEAR> The CLEAR key on the DSKY display.
{j} <ENTER> The ENTER key on the DSKY display.
{g} <KEY REL> The KEY RELEASE key on the DSKY display.
Simulator demonstration
Here’s the simulator, demonstrating some COLOSSUS 249 flight software functions. This is
the same scenario I ran in Part 1 using my hardware AGC.
Initialization
At startup, the simulator loads the microinstructions from the EPROM tables. These are the
same tables I eventually used to program the hardware AGC EPROMs.
Reading EPROM: CPM1_8.hex
Reading EPROM: CPM9_16.hex
Reading EPROM: CPM17_24.hex
Reading EPROM: CPM25_32.hex
Reading EPROM: CPM33_40.hex
Reading EPROM: CPM41_48.hex
Reading EPROM: CPM49_56.hex
The simulator is now initialized
and ready for commands.
<LOAD>
The simulator asks, and I enter the name of object files containing the COLOSSUS flight
software.
<POWER UP RESET> <RUN>
<FCLK>
I tell the simulator to start
running, and enable the free-
running clock. The AGC starts
running in real-time with the 1MHz
clock. The DSKY shows major
mode 00 (P00).
Display elapsed time fromthe CM clock
<VERB> <0> <6> <NOUN> <3>
<6> <ENTER>
Test display lights
<VERB> <3> <5> <ENTER>
All DSKY lamps and display
segments illuminate for 5 sec;
after 5 sec, the DSKY lamps
extinguish.
Load component 1 fordataset at octal address50 with octal 123
<VERB> <2> <1> <NOUN> <0>
<1> <ENTER>
Verb/noun display flashes: waiting
for address. Flashing is indicated
by the asterisk to the right of the
NOUN display.
<5> <0> <ENTER>
Verb/noun display flash continues:
waiting for data.
<1> <2> <3> <ENTER>
Octal word from R1 is loaded at
address 50.
Start a monitor programto continuously displayelapsed time from the CMclock
<VERB> <1> <6> <NOUN> <3>
<6> <ENTER>
Display component 1 ofdataset at octal address50
<VERB> <0> <1>
The key rel light flashes because
the CM clock monitor program has
been suspended. This is indicated
by an asterisk in the KR display
above the DSKY.
<NOUN> <0> <1> <ENTER>
Verb/noun display flashes: waiting
for address.
<5> <0> <ENTER>
Octal word from address 50 is
displayed in R1.
Increment the address
<NOUN> <1> <5> <ENTER>
Octal word from address 51 is
displayed in R1, address in R3.
<ENTER>
Octal word from address 52 is
displayed in R1, address in R3.
Resume the CM clockmonitor program
<KEY REL>
Verb 16, noun 36 reappears, along
with the clock display. Notice that
the KR light (asterisk) goes out.
Terminate the CM clockmonitor program
<VERB> <3> <4> <ENTER>
Change major mode toP00
<VERB> <3> <7> <ENTER>
Verb/noun display flashes:
waiting for major mode.
<0> <0> <ENTER>
The 20-or-so
subsystems in the AGC
are represented by C++
classes. There are some
additional classes for
registers and other
things.
I wanted a simulator
architecture I could
develop quickly that
would easily and directly
map to a hardware logic
design. I went through
16 versions of the
simulator; they’re
discussed at the top of
the AGCMain.cpp file
which contains,
unsurprisingly, the
main().
If you want to run the
simulator, you can
compile it from the
source code given here. To run it, you’ll also need the assembler (discussed in part 6), some
AGC software (parts 8 and 9), and the EPROM tables in Motorola S-Record format. The C++
code to generate these tables is given at the end of part 2.
Here it is, warts and all...
Main (AGCMain.cpp)
/**************************************************************************** * AGC4 (Apollo Guidance Computer) BLOCK I Simulator * * AUTHOR: John Pultorak * DATE: 07/29/02 * FILE: AGCmain.cpp * * VERSIONS: * 1.0 - initial version. * 1.1 - fixed minor bugs; passed automated test and checkout programs: * teco1.asm, teco2.asm, and teco3.asm to test basic instructions, * extended instructions, and editing registers. * 1.2 - decomposed architecture into subsystems; fixed minor bug in DSKY * keyboard logic (not tested in current teco*.asm suite). * Implemented scaler pulses F17, F13, F10. Tied scaler output to * involuntary counters and interrupts. Implemented counter overflow * logic and tied it to interrupts and other counters. Added simple * set/clear breakpoint. Fixed a bug in bank addressing. * 1.3 - fixed bugs in the DSKY. Added 14-bit effective address (CADR) to the * simulator display output. Inhibited interrupts when the operator * single-steps the AGC. * 1.4 - performance enhancements. Recoded the control pulse execution code * for better simulator performance. Also changed the main loop so it * polls the keyboard and system clock less often for better performance. * 1.5 - reversed the addresses of TIME1 and TIME2 so TIME2 occurs first. * This is the way its done in Block II so that a common routine (READLO) * can be used to read the double word for AGC time. * 1.6 - added indicators for 'CHECK FAIL' and 'KEY RELS'. Mapped them to OUT1, * bits 5 and 7. Added a function to display the current location in * the source code list file using the current CADR. * 1.7 - increased length of 'examine' function display. Any changes in DSKY now * force the simulator to update the display immediately. Added a 'watch' * function that looks for changes in a memory location and halts the * AGC. Added the 'UPTL', 'COMP', and "PROG ALM" lights to the DSKY. * 1.8 - started reorganizing the simulator in preparation for H/W logic design. * Eliminated slow (1Hz) clock capability. Removed BUS REQUEST feature. * Eliminated SWRST switch. * 1.9 - eliminated the inclusive 'OR' of the output for all registers onto the * R/W bus. The real AGC OR'ed all register output onto the bus; normally * only one register was enabled at a time, but for some functions several * were simultaneously enabled to take advantage of the 'OR' function (i.e.: * for the MASK instruction). The updated logic will use tristate outputs * to the bus except for the few places where the 'OR' function is actually * needed. Moved the parity bit out of the G register into a 1-bit G15 * register. This was done for convenience because the parity bit in G * is set independently from the rest of the register. * 1.10 - moved the G15 parity register from MBF to the PAR subsystem. Merged SBFWG * and SBEWG pulses into a single SBWG pulse. Deleted the CLG pulse for MBF * (not needed). Separated the ALU read pulses from all others so they can * be executed last to implement the ALU inclusive OR functions. Implemented * separate read and write busses, linked through the ALU. Implemented test * parity (TP) signal in PAR; added parity alarm (PALM) FF to latch PARITY * ALARM indicator in PAR. * 1.11 - consolidated address testing signals and moved them to ADR. Moved memory * read/write functions from MBF to MEM. Merged EMM and FMM subsystems into * MEM. Fixed a bad logic bug in writeMemory() that was causing the load of * the fixed memory to overwrite array boundaries and clobber the CPM table. * Added a memory bus (MEM_DATA_BUS, MEM_PARITY_BUS). * 1.12 - reduced the number of involuntary counters (CTR) from 20 to 8. Eliminated * the SHINC subsequence. Changed the (CTR) sequence and priority registers into * a single synchronization register clocked by WPCTR. Eliminated the fifth * interrupt (UPRUPT; INT). Eliminated (OUT) the signal to read from output * register 0 (the DSKY register), since it was not used and did not provide * any useful function, anyway. Deleted register OUT0 (OUT) which shadowed * the addressed DSKY register and did not provide any useful function. * Eliminated the unused logic that sets the parity bit in OUT2 for downlink * telemetry. * 1.13 - reorganized the CPM control pulses into CPM-A, CPM-B, and CPM-C groups. * Added the SDV1, SMP1, and SRSM3 control pulses to CPM-A to indicate when * those subsequences are active; these signals are input to CPM-C. Moved the * ISD function into CPM-A. Fixed a minor bug causing subsequence RSM3 to be * displayed as RSM0. Added GENRST to clear most registers during STBY. * 1.14 - Moved CLISQ to TP1 to fix a problem in the hardware AGC. CLISQ was clearing
* SNI on CLK2 at TP12, but the TPG was advancing on CLK1 which occurs after * CLK2, so the TPG state machine was not seeing SNI and was not moving to * the correct state. In this software simulation, everything advances on * the same pulse, so it wasn't a problem to clear SNI on TP12. Added a * switch to enable/disable the scaler. * 1.15 - Reenabled interrupts during stepping (by removing MON::RUN) signals from * CPM-A and CPM-C logic). Interrupts can be prevented by disabling the scaler. * Fixed a problem with INHINT1; it is supposed to prevent an interrupt * between instructions if there's an overflow. It was supposed to be cleared * on TP12 after SNI (after a new instruction), but was being cleared on TP12 * after every subsequence. * 1.16 - Changed CPM-A to load and use EPROM tables for the control pulse matrix. The * EPROM tables are negative logic (0=asserted), but this simulator expects * positive logic, so each word is bit-flipped when the EPROM tables load * during simulator initialization. * SOURCES: * Mostly based on information from "Logical Description for the Apollo Guidance * Computer (AGC4)", Albert Hopkins, Ramon Alonso, and Hugh Blair-Smith, R-393, * MIT Instrumentation Laboratory, 1963. * * PORTABILITY: * Compiled with Microsoft Visual C++ 6.0 standard edition. Should be fairly * portable, except for some Microsoft-specific I/O and timer calls in this file. * * NOTE: set tabs to 4 spaces to keep columns formatted correctly. * ***************************************************************************** */
#include <conio.h>
#include <iostream.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <conio.h>#include <stdio.h>#include <time.h>#include <ctype.h>
#include "reg.h"
#include "TPG.h"#include "MON.h"#include "SCL.h"#include "SEQ.h"#include "INP.h"#include "OUT.h"#include "BUS.h"#include "DSP.h"#include "ADR.h"#include "PAR.h"#include "MBF.h"#include "MEM.h"#include "CTR.h"#include "INT.h"#include "KBD.h"#include "CRG.h"#include "ALU.h"#include "CPM.h"#include "ISD.h"#include "CLK.h"
extern bool dskyChanged;
//-----------------------------------------------------------------------// CONTROL LOGIC
void genAGCStates(){
// 1) Decode the current instruction subsequence (glbl_subseq).// SEQ::glbl_subseq = CPM::instructionSubsequenceDecoder();
// 2) Build a list of control pulses for this state.CPM::controlPulseMatrix();
// 3) Execute the control pulses for this state. In the real AGC, these occur// simultaneously. Since we can't achieve that here, we break it down into the// following steps:// Most operations involve data transfers--usually reading data from// a register onto a bus and then writing that data into another register. To// approximate this, we first iterate through all registers to perform// the 'read' operation--this transfers data from register to bus.// Then we again iterate through the registers to do 'write' operations,// which move data from the bus back into the register.
BUS::glbl_READ_BUS = 0; // clear bus; necessary because words are logical // OR'ed onto the bus.
MEM::MEM_DATA_BUS = 0; // clear data lines: memory bits 15-1MEM::MEM_PARITY_BUS = 0; // parity line: memory bit 16
// Now start executing the pulses:
// First, read register outputs onto the bus or anywhere else.int i;for(i=0; i<MAXPULSES && SEQ::glbl_cp[i] != NO_PULSE; i++){
CLK::doexecR(SEQ::glbl_cp[i]);}
// Next, execute ALU read pulses. See comments in ALU .C fileALU::glbl_BUS = 0;for(i=0; i<MAXPULSES && SEQ::glbl_cp[i] != NO_PULSE; i++){
CLK::doexecR_ALU(SEQ::glbl_cp[i]);}BUS::glbl_WRITE_BUS = BUS::glbl_READ_BUS; // in case nothing is logically OR'ed below;for(i=0; i<MAXPULSES && SEQ::glbl_cp[i] != NO_PULSE; i++){
CLK::doexecR_ALU_OR(SEQ::glbl_cp[i]);}
// Now, write the bus and any other signals into the register inputs.
for(i=0; i<MAXPULSES && SEQ::glbl_cp[i] != NO_PULSE; i++){
CLK::doexecW(SEQ::glbl_cp[i]);}
// Always execute these pulses.SCL::doexecWP_SCL();SCL::doexecWP_F17();SCL::doexecWP_F13();SCL::doexecWP_F10();TPG::doexecWP_TPG();
}
//-----------------------------------------------------------------------// SIMULATION LOGIC
// contains prefix for source filename; i.e.: the portion// of the filename before .obj or .lst
char filename[80];
char* getCommand(char* prompt){
static char s[80];char* sp = s;
cout << prompt; cout.flush();
char key;while((key = _getch()) != 13){
if(isprint(key)){
cout << key; cout.flush();*sp = key; sp++;
}
else if(key == 8 && sp != s){
cout << key << " " << key; cout.flush();sp--;
}}*sp = '\0';return s;
}
bool breakpointEnab = false;unsigned breakpoint = 0;void toggleBreakpoint(){
if(!breakpointEnab){
char b[80];strcpy(b, getCommand("Set breakpoint: -- enter 14-bit CADR (octal): "));cout << endl;
breakpoint = strtol(b,0,8);breakpointEnab = true;
}else{
cout << "Clearing breakpoint." << endl;breakpointEnab = false;
}}
bool watchEnab = false;unsigned watchAddr = 0;unsigned oldWatchValue = 0;void toggleWatch(){
if(!watchEnab){
char b[80];strcpy(b, getCommand("Set watch: -- enter 14-bit CADR (octal): "));cout << endl;
watchAddr = strtol(b,0,8);watchEnab = true;oldWatchValue = MEM::readMemory(watchAddr);
char buf[100];sprintf(buf, "%06o: %06o", watchAddr, oldWatchValue);cout << buf << endl;
}else{
cout << "Clearing watch." << endl;watchEnab = false;
}}
void incrCntr(){
char cntrname[80];strcpy(cntrname, getCommand("Increment counter: -- enter pcell (0-19): "));cout << endl;
int pc = atoi(cntrname);CTR::pcUp[pc] = 1;
}
void decrCntr(){
char cntrname[80];strcpy(cntrname, getCommand("Decrement counter: -- enter pcell (0-19): "));cout << endl;
int pc = atoi(cntrname);CTR::pcDn[pc] = 1;
}
void interrupt(){
char iname[80];strcpy(iname, getCommand("Interrupt: -- enter priority (1-5): "));cout << endl;
int i = atoi(iname) - 1;INT::rupt[i] = 1;
}
#ifdef NOTDEF// Load AGC memory from the specified file object file
void loadMemory(){
strcpy(filename, getCommand("Load Memory -- enter filename: "));cout << endl;
// Add the .obj extension.char fname[80];strcpy(fname, filename);strcat(fname, ".obj");
FILE* fp = fopen(fname, "r");if(!fp){
perror("fopen failed:");cout << "*** ERROR: Can't load memory for file: " << fname << endl;return;
}unsigned addr;unsigned data;while(fscanf(fp, "%o %o", &addr, &data) != EOF){
MEM::writeMemory(addr, data);}fclose(fp);cout << "Memory loaded." << endl;
}#endif
static int loadBuf[0xffff+1]; // tempory buffer for assembling H,L memory data
void loadEPROM(char* fileName, bool highBytes){
cout << "Reading EPROM: " << fileName << endl;
// Open the EPROM file.FILE* ifp = fopen(fileName, "r");if(!ifp){
perror("fopen failed for source file");exit(-1);
}
const int addressBytes = 3; // 24-bit address rangeconst int sumCheckBytes = 1;
char buf[4096]; // buffer holds a single S-Recordwhile(fgets(buf,4096,ifp)){
// process a recordif(buf[0] != 'S'){
cout << "Error reading start of EPROM record for: " << fileName << endl;exit(-1);
}
char tmp[256];
strncpy(tmp, &buf[2], 2); tmp[2] = '\0';int totalByteCount = strtol(tmp, 0, 16);int mySumCheck = totalByteCount & 0xff;
strncpy(tmp, &buf[4], 6); tmp[addressBytes*2] = '\0';int address = strtol(tmp, 0, 16);mySumCheck = (mySumCheck + ((address & 0xff0000) >> 16)) % 256;mySumCheck = (mySumCheck + ((address & 0x00ff00) >> 8)) % 256;mySumCheck = (mySumCheck + ((address & 0x0000ff) )) % 256;
//cout << hex << totalByteCount << ", " << address << dec << endl;
int dataBytes = totalByteCount - addressBytes - sumCheckBytes;
int i = (addressBytes+2)*2; // index to 1st databyte char.for(int j=0; j<dataBytes; j++){
// get a data bytestrncpy(tmp, &buf[i], 2); tmp[2] = '\0';int data = strtol(tmp, 0, 16);//cout << hex << data << dec << endl;mySumCheck = (mySumCheck + data) % 256;
if(highBytes){
loadBuf[address] = loadBuf[address] | ((data << 8) & 0xff00);}else{
loadBuf[address] = loadBuf[address] | (data & 0xff);}address++;
i+=2; // bump to next databyte char}strncpy(tmp, &buf[i], 2); tmp[2] = '\0';int sumCheck = strtol(tmp, 0, 16);
if(sumCheck != ((~mySumCheck) & 0xff)){
cout << "sumCheck failed; file: " << fileName << ", address: " << hex << address << ", sumCheck: " << sumCheck << ", mySumCheck: " << mySumCheck << dec << endl;
exit(-1);}
}fclose(ifp);cout << "Memory loaded." << endl;
}
// Load AGC memory from the specified EPROM filesvoid loadMemory(){
strcpy(filename, getCommand("Load Memory -- enter filename: "));cout << endl;
char fname[80];
// Add the _H.hex extension.strcpy(fname, filename);strcat(fname, "_H.hex");
loadEPROM(fname, true);
// Add the _L.hex extension.strcpy(fname, filename);strcat(fname, "_L.hex");
loadEPROM(fname, false);
//*******************************************************************// EPROM is now in loadBuf; move it to AGC memory.// AGC fixed memory only uses NUMFBANK banks.
for(int address=1024; address < 1024*(NUMFBANK+1); address++){
// Don't load address region 0-1023; that region is allocated
// to eraseable memory.//cout << "loading CADR=" << hex << address << endl;MEM::writeMemory(address, loadBuf[address]);
}//*******************************************************************
}
// Write the entire contents of fixed and// eraseable memory to the specified file.// Does not write the registers
void saveMemory(char* filename){
FILE* fp = fopen(filename, "w");if(!fp){
perror("*** ERROR: fopen failed:");exit(-1);
}char buf[100];for(unsigned addr=020; addr<=031777; addr++){
sprintf(buf, "%06o %06o\n", addr, MEM::readMemory(addr));fputs(buf, fp);
}fclose(fp);
}
void examineMemory(){
char theAddress[20];strcpy(theAddress, getCommand("Examine Memory -- enter address (octal): "));cout << endl;
unsigned address = strtol(theAddress, 0, 8);
char buf[100];for(unsigned i=address; i<address+23; i++){
sprintf(buf, "%06o: %06o", i, MEM::readMemory(i));cout << buf << endl;
}}
// Returns true if time (s) elapsed since last time it returned true; does not block// search for "Time Management"
bool checkElapsedTime(time_t s){
if(!s) return true;
static clock_t start = clock();clock_t finish = clock();
double duration = (double)(finish - start) / CLOCKS_PER_SEC;if(duration >= s){ start = finish;
return true;}return false;
}
// Blocks until time (s) has elapsed.void delay(time_t s){
if(!s) return;
clock_t start = clock();clock_t finish = 0;double duration = 0;
do{
finish = clock();}while((duration = (double)(finish - start) / CLOCKS_PER_SEC) < s);
}
void updateAGCDisplay(){
static bool displayTimeout = false;static int clockCounter = 0;
if(checkElapsedTime(2)) displayTimeout = true;if(MON::FCLK){
if(MON::RUN){
// update every 2 seconds at the start of a new instructionif(displayTimeout || dskyChanged){
clockCounter++;if(
(TPG::register_SG.read() == TP12 && SEQ::register_SNI.read() == 1) ||
(TPG::register_SG.read() == STBY) ||clockCounter > 500 ||dskyChanged)
{MON::displayAGC();displayTimeout = false;clockCounter = 0;dskyChanged = false;
}}
}else{
static bool displayOnce = false;if(TPG::register_SG.read() == WAIT){
if(displayOnce == false){
MON::displayAGC();displayOnce = true;clockCounter = 0;
}}else{
displayOnce = false;}
}}else
MON::displayAGC(); // When the clock is manual or slow, always update.}
void showMenu(){
cout << "AGC4 EMULATOR MENU:" << endl;cout << " 'r' = RUN: toggle RUN/HALT switch upward to the RUN position." << endl;
}
const int startCol = 0; // columns are numbered 0-nconst int colLen = 5; // number of chars in column
const int maxLines = 23; // # of total lines to displayconst int noffset = 10; // # of lines prior to, and including, selected line
const int maxLineLen = 79;
void showSourceCode(){
// Add the .lst extension.char fname[80];strcpy(fname, filename);strcat(fname, ".lst");
// Open the file containing the source code listing.FILE* fp = fopen(fname, "r");if(!fp)
{perror("fopen failed:");cout << "*** ERROR: Can't load source list file: " << fname << endl;return;
}cout << endl;
// Get the address of the source code line to display.// The address we want is the current effective address is the// S and bank registers.
char CADR[colLen+1];sprintf(CADR, "%05o", ADR::getEffectiveAddress());
int op = 0; // offset indexlong foffset[noffset];for(int i=0; i<noffset; i++) foffset[i]=0;
bool foundit = false;int lineCount = 0;
char s[256];char valString[20];char out[256];
while(!feof(fp)){
if(!foundit){
foffset[op] = ftell(fp);op = (op + 1) % noffset;
}
// Read a line of the source code list file.if(fgets(s, 256, fp)){
// Get the address (CADR) from the line.strncpy(valString, s+startCol, colLen);valString[colLen]='\0';
// 'foundit' is true after we have found the desired line.if(foundit){
if(strcmp(valString,CADR) == 0)cout << ">";
elsecout << " ";
// truncate line so it fits in 80 col displaystrncpy(out, s, maxLineLen);out[maxLineLen] = '\0';cout << out;
lineCount++;if(lineCount >= maxLines)
break;}else{
if(strcmp(valString, CADR) == 0){
// Reposition the file pointer back several lines so// we can see the code that preceeds the desired// line, too.
foundit = true;fseek(fp, foffset[op], 0);
}}
}}fclose(fp);
}
void main(int argc, char* argv[]){
CPM::readEPROM( "CPM1_8.hex", CPM::EPROM1_8);CPM::readEPROM( "CPM9_16.hex", CPM::EPROM9_16);CPM::readEPROM("CPM17_24.hex", CPM::EPROM17_24);CPM::readEPROM("CPM25_32.hex", CPM::EPROM25_32);CPM::readEPROM("CPM33_40.hex", CPM::EPROM33_40);CPM::readEPROM("CPM41_48.hex", CPM::EPROM41_48);CPM::readEPROM("CPM49_56.hex", CPM::EPROM49_56);
bool singleClock = false;
genAGCStates();MON::displayAGC();
while(1){
// NOTE: assumes that the display is always pointing to the start of// a new line at the top of this loop!
// Clock the AGC, but between clocks, poll the keyboard// for front-panel input by the user. This uses a Microsoft function;// substitute some other non-blocking function to access the keyboard// if you're porting this to a different platform.cout << "> "; cout.flush(); // display prompt
while( !_kbhit() ){
if(MON::FCLK || singleClock){
// This is a performance enhancement. If the AGC is running,// don't check the keyboard or simulator display every// simulation cycle, because that slows the simulator // down too much.
int genStateCntr = 100;do { CLK::clkAGC();
singleClock = false;
genAGCStates(); genStateCntr--;
// Needs more work. It doesn't always stop at the// right location and sometimes stops at the// instruction afterwards, too.
if(breakpointEnab && breakpoint == ADR::getEffectiveAddress())
{MON::RUN = 0;
}
// Halt right after instr that changes a watched// memory location.
if(watchEnab){
unsigned newWatchValue = MEM::readMemory(watchAddr);if(newWatchValue != oldWatchValue){
MON::RUN = 0;}oldWatchValue = newWatchValue;
}
} while (MON::FCLK && MON::RUN && genStateCntr > 0);
updateAGCDisplay();
}// for convenience, clear the single step switch on TP1; in the// hardware AGC, this happens when the switch is releasedif(MON::STEP && TPG::register_SG.read() == TP1) MON::STEP = 0;
}char key = _getch();
// Keyboard controls for front-panel:switch(key)
{// AGC controls// simulator controls
case 'q': cout << "QUIT..." << endl; exit(0);case 'm': showMenu(); break;
case 'd': genAGCStates(); MON::displayAGC(); break; // update display
case 'l': loadMemory(); break;case 'e': examineMemory(); break;
case 'f':showSourceCode();break;
case ']': incrCntr(); //genAGCStates();//displayAGC(EVERY_CYCLE);break;
case '[': decrCntr(); //genAGCStates();//displayAGC(EVERY_CYCLE);break;
case 'i': interrupt(); //genAGCStates();//displayAGC(EVERY_CYCLE);break;
case 'z'://SCL::F17 = (SCL::F17 + 1) % 2; genAGCStates();MON::displayAGC();break;
case 'x'://SCL::F13 = (SCL::F13 + 1) % 2; genAGCStates();MON::displayAGC();break;
case 'c': MON::SCL_ENAB = (MON::SCL_ENAB + 1) % 2;genAGCStates();MON::displayAGC();break;
case 'r': MON::RUN = (MON::RUN + 1) % 2; genAGCStates();if(!MON::FCLK) MON::displayAGC();break;
case 's': MON::STEP = (MON::STEP + 1) % 2; genAGCStates();if(!MON::FCLK) MON::displayAGC();break;
case 'a': MON::SA = (MON::SA + 1) % 2; genAGCStates();MON::displayAGC();break;
case 'n': MON::INST = (MON::INST + 1) % 2; genAGCStates();
MON::displayAGC();break;
case 'p': MON::PURST = (MON::PURST + 1) % 2;genAGCStates();MON::displayAGC();break;
case 'b':toggleBreakpoint();break;
case 'y':toggleWatch();break;
case ';': // Clear ALARM indicators
PAR::CLR_PALM(); // Asynchronously clear PARITY FAILMON::displayAGC();break;
// DSKY:case '0': KBD::keypress(KEYIN_0); break;case '1': KBD::keypress(KEYIN_1); break;case '2': KBD::keypress(KEYIN_2); break;case '3': KBD::keypress(KEYIN_3); break;case '4': KBD::keypress(KEYIN_4); break;case '5': KBD::keypress(KEYIN_5); break;case '6': KBD::keypress(KEYIN_6); break;case '7': KBD::keypress(KEYIN_7); break;case '8': KBD::keypress(KEYIN_8); break;case '9': KBD::keypress(KEYIN_9); break;case '+': KBD::keypress(KEYIN_PLUS); break;case '-': KBD::keypress(KEYIN_MINUS); break;case '.': KBD::keypress(KEYIN_CLEAR); break;case '/': KBD::keypress(KEYIN_VERB); break;case '*': KBD::keypress(KEYIN_NOUN); break;case 'g': KBD::keypress(KEYIN_KEY_RELEASE); break;case 'h': KBD::keypress(KEYIN_ERROR_RESET); break;case 'j': KBD::keypress(KEYIN_ENTER); break;
case '\0': // must be a function keykey = _getch();switch(key){case 0x3b: // F1: single clock pulse (when system clock off)
singleClock = true; break; case 0x3c: // F2: manual clock (FCLK=0)
MON::FCLK = 0; genAGCStates(); MON::displayAGC(); break; case 0x3e: // F4: fast clock (FCLK=1)
MON::FCLK = 1; genAGCStates(); MON::displayAGC(); break;default: cout << "function key: " << key << "="
<< hex << (int) key << dec << endl;}break;
//default: cout << "??" << endl;default: cout << key << "=" << hex << (int) key << dec << endl;}
}}
ADR (ADR.h)
/**************************************************************************** * ADR - MEMORY ADDRESS subsystem * * AUTHOR: John Pultorak * DATE: 9/22/01 * FILE: ADR.h * * VERSIONS: * * DESCRIPTION: * Memory address for the Block 1 Apollo Guidance Computer prototype (AGC4). * * SOURCES: * Mostly based on information from "Logical Description for the Apollo * Guidance Computer (AGC4)", Albert Hopkins, Ramon Alonso, and Hugh * Blair-Smith, R-393, MIT Instrumentation Laboratory, 1963. * * NOTES: * ***************************************************************************** */#ifndef ADR_H#define ADR_H
enum specialRegister { // octal addresses of special registers// Flip-Flop registers
A_ADDR =00,Q_ADDR =01,Z_ADDR =02,LP_ADDR =03,IN0_ADDR =04,IN1_ADDR =05,IN2_ADDR =06,IN3_ADDR =07,OUT0_ADDR =010,OUT1_ADDR =011,OUT2_ADDR =012,OUT3_ADDR =013,OUT4_ADDR =014,BANK_ADDR =015,
// No bits in these registersRELINT_ADDR =016,INHINT_ADDR =017,
// In eraseable memoryCYR_ADDR =020,SR_ADDR =021,CYL_ADDR =022,SL_ADDR =023,ZRUPT_ADDR =024,BRUPT_ADDR =025,ARUPT_ADDR =026,QRUPT_ADDR =027,
};
class regS : public reg { public:
regS() : reg(12, "%04o") { }};
class regBNK : public reg { public:
regBNK() : reg(4, "%02o") { }};
class ADR
{friend class MON;
friend class MEM;
friend class CLK;friend class CPM;
public:static void execWP_WS();static void execRP_RBK();
static void execWP_WBK();
static bool GTR_17(); // for MBF, CPM static bool GTR_27(); // for PAR static bool EQU_16(); // for CPM static bool EQU_17(); // for CPM static bool EQU_25(); // for SEQ static bool GTR_1777(); // for CPM
static unsigned getEffectiveAddress();
private:static regS register_S; // address registerstatic regBNK register_BNK; // bank register
static unsigned bankDecoder();
static unsigned conv_WBK[];};
#endif
ADR (ADR.cpp)
/**************************************************************************** * ADR - MEMORY ADDRESS subsystem * * AUTHOR: John Pultorak * DATE: 9/22/01 * FILE: ADR.cpp * * NOTES: see header file. * ***************************************************************************** */#include "reg.h"#include "ADR.h"#include "SEQ.h"#include "BUS.h"
regS ADR::register_S; // address registerregBNK ADR::register_BNK; // bank register
// transfer bits 14-11 from the bus into the 4-bit bank registerunsigned ADR::conv_WBK[] ={ BX, BX, BX, BX, BX, BX, BX, BX, BX, BX, BX, BX, B14, B13, B12, B11 };
void ADR::execWP_WS(){
register_S.write(BUS::glbl_WRITE_BUS);}
void ADR::execRP_RBK(){
BUS::glbl_READ_BUS = register_BNK.read() << 10;}
void ADR::execWP_WBK(){
register_BNK.writeShift(BUS::glbl_WRITE_BUS, ADR::conv_WBK);}
bool ADR::GTR_27(){
return (register_S.read() > 027); }
bool ADR::GTR_17(){
// check: address is not a central registerreturn (register_S.read() > 017);
}
bool ADR::EQU_25(){
return (register_S.read() == 025); }
bool ADR::EQU_17(){
// check: instruction is INHINT (INDEX 017)return (register_S.read() == 017);
}
bool ADR::EQU_16(){
// check: instruction is RELINT (INDEX 016))return (register_S.read() == 016);
}
bool ADR::GTR_1777(){
// check: address is fixed memory
return (register_S.read() > 01777); }
unsigned ADR::bankDecoder(){
// Memory is organized into 13 banks of 1K words each. The banks are numbered// 0-12. Bank 0 is erasable memory; banks 1-12 are fixed (rope) memory. The 10// lower bits in the S register address memory inside a bank. The 2 upper bits// in the S register select the bank. If the 2 upper bits are both 1, the 4-bit// bank register is used to select the bank.// 12 11 Bank// 0 0 0 erasable memory// 0 1 1 fixed-fixed 1 memory// 1 0 2 fixed-fixed 2 memory// 1 1 3-12 fixed-switchable memory (bank register selects bank)unsigned bank = ADR::register_S.readField(12,11);if(bank == 3){
// fixed-switchableif(register_BNK.read() <= 03) // defaults to 6000 - 7777
return 03;else
return register_BNK.read(); // 10000 - 31777}else
return bank; // erasable or fixed-fixed}
unsigned ADR::getEffectiveAddress(){
// Return the 14-bit address selected by lower 10 bits of the S register (1K)// and the bank decoder (which selects the 1K bank)
unsigned lowAddress = ADR::register_S.readField(10,1);
if(ADR::bankDecoder() == 0)return lowAddress;
unsigned highAddress = ADR::bankDecoder() << 10;return highAddress | lowAddress;
}
ALU (ALU.h)
/**************************************************************************** * ALU - ARITHMETIC UNIT subsystem * * AUTHOR: John Pultorak * DATE: 9/22/01 * FILE: ALU.h * * VERSIONS: * * DESCRIPTION: * Arithmetic Unit for the Block 1 Apollo Guidance Computer prototype (AGC4). * * SOURCES: * Mostly based on information from "Logical Description for the Apollo * Guidance Computer (AGC4)", Albert Hopkins, Ramon Alonso, and Hugh * Blair-Smith, R-393, MIT Instrumentation Laboratory, 1963. * * NOTES: * ***************************************************************************** */#ifndef ALU_H#define ALU_H
#include "reg.h"
class regB : public reg { public:
regB() : reg(16, "%06o") { }};
class regCI : public reg { public:
regCI() : reg(1, "%01o") { }};
class regX : public reg { public:
regX() : reg(16, "%06o") { }};
class regY : public reg { public:
regY() : reg(16, "%06o") { }};
class regU : public reg { public:
regU() : reg(16, "%06o") { }virtual unsigned read();
};
class ALU{public:
static unsigned glbl_BUS; // mixes the RC and RU together for MASK
// In the hardware AGC, all read pulses are enabled simultaneously// by CLK1. This simulator has to do the pulses one-at-a-time, so// they are executed in the following sequence to mimic the hardware://// 1) all read pulses involving subsystems other than ALU are executed,// These read pulses output to the glbl_READ_BUS. Only 0 or 1// of these pulses should be active at any time (never 2 or more),//// 2) next, the read pulses for the ALU are executed. The ALU is treated// differently because it is the only subsystem where several read
// pulses can be active simultaneously. In the original AGC, these// pulses 'inclusive OR' their output to the glbl_READ_BUS, so the// simulator has be implemented to execute all read pulses other than// the ALU reads first, so the ALU will have the bus data it needs// in order to do the inclusive OR.// In the recreated AGC hardware design, the ALU is also the subsystem// that links the glbl_READ_BUS to the glbl_WRITE_BUS.//// The recreated ALU hardware design checks whether anything is being// written to the glbl_READ_BUS by the other subsystems. If not, it// outputs zeroes to the glbl_READ_BUS for input to the inclusive OR// operation.// It then transfers data on the glbl_READ_BUS to the glbl_WRITE_BUS// using an inclusive OR with data generated by other ALU read pulses.// The AGC sequencer uses this operation to set certain data lines.//// 3) finally, all write pulses are executed.
static void execRP_ALU_RB();static void execRP_ALU_RC();static void execRP_ALU_RU();
static void execRP_ALU_OR_RB14();static void execRP_ALU_OR_R1();static void execRP_ALU_OR_R1C();static void execRP_ALU_OR_R2();static void execRP_ALU_OR_R22();static void execRP_ALU_OR_R24();static void execRP_ALU_OR_R2000();static void execRP_ALU_OR_RSB();
static void execWP_GENRST();static void execWP_WB();
static void execWP_CI();static void execWP_WY();
static void execWP_WX();static void execWP_WYx();
static regB register_B; // next instructionstatic regCI register_CI; // ALU carry-in flip flopstatic regX register_X; // ALU X registerstatic regY register_Y; // ALU Y registerstatic regU register_U; // ALU sum
};
#endif
ALU (ALU.cpp)
/**************************************************************************** * ALU - ARITHMETIC UNIT subsystem * * AUTHOR: John Pultorak * DATE: 9/22/01 * FILE: ALU.cpp * * NOTES: see header file. * ***************************************************************************** */#include "ALU.h"#include "SEQ.h"#include "BUS.h"
regB ALU::register_B; // next instructionregCI ALU::register_CI; // ALU carry-in flip flopregX ALU::register_X; // ALU X registerregY ALU::register_Y; // ALU Y registerregU ALU::register_U; // ALU sum
unsigned ALU::glbl_BUS = 0;
//************************************************************
void ALU::execRP_ALU_RB(){
BUS::glbl_READ_BUS = register_B.read();}
// Performs an inclusive OR or register U and register C; // in the MASK instruction, the RC and RU control pulses// are activated simultaneously. This causes both to be// gated onto the AGC bus which performs the logical OR.
void ALU::execRP_ALU_RC(){
ALU::glbl_BUS |= register_B.outmask() & (~register_B.read());BUS::glbl_READ_BUS = ALU::glbl_BUS;
}
// Performs an inclusive OR or register U and register C; // in the MASK instruction, the RC and RU control pulses// are activated simultaneously. This causes both to be// gated onto the AGC bus which performs the logical OR.
void ALU::execRP_ALU_RU(){
ALU::glbl_BUS |= register_U.read();BUS::glbl_READ_BUS = ALU::glbl_BUS;
}
//************************************************************
//************************************************************// This is the interface between the read and write busses
void ALU::execRP_ALU_OR_RB14(){
BUS::glbl_WRITE_BUS |= 0020000 | BUS::glbl_READ_BUS;}
void ALU::execRP_ALU_OR_R1(){
BUS::glbl_WRITE_BUS |= 0000001 | BUS::glbl_READ_BUS;}
void ALU::execRP_ALU_OR_R1C(){
BUS::glbl_WRITE_BUS |= 0177776 | BUS::glbl_READ_BUS;}
void ALU::execRP_ALU_OR_R2(){
BUS::glbl_WRITE_BUS |= 0000002 | BUS::glbl_READ_BUS;}
void ALU::execRP_ALU_OR_RSB(){
BUS::glbl_WRITE_BUS |= 0100000 | BUS::glbl_READ_BUS;}
void ALU::execRP_ALU_OR_R22(){
BUS::glbl_WRITE_BUS |= 0000022 | BUS::glbl_READ_BUS;}
void ALU::execRP_ALU_OR_R24(){
BUS::glbl_WRITE_BUS |= 0000024 | BUS::glbl_READ_BUS;}
void ALU::execRP_ALU_OR_R2000(){
BUS::glbl_WRITE_BUS |= 0002000 | BUS::glbl_READ_BUS; // TC GOPROG instruction}
//************************************************************
void ALU::execWP_GENRST(){}
void ALU::execWP_CI(){
register_CI.writeField(1,1,1);}
void ALU::execWP_WX(){
register_X.write(BUS::glbl_WRITE_BUS);}
void ALU::execWP_WB(){
register_B.write(BUS::glbl_WRITE_BUS);}
void ALU::execWP_WYx(){
register_Y.write(BUS::glbl_WRITE_BUS);}
void ALU::execWP_WY(){
if(!SEQ::isAsserted(CI)) register_CI.writeField(1,1,0);register_X.write(0);register_Y.write(BUS::glbl_WRITE_BUS);
}
unsigned regU::read(){
unsigned carry = (outmask()+1) & (ALU::register_X.read() + ALU::register_Y.read()); // end-around
carryif(carry || ALU::register_CI.read())
carry = 1; else
carry = 0; return outmask() & (ALU::register_X.read() + ALU::register_Y.read() + carry);}
BUS (BUS.h)
/**************************************************************************** * BUS - READ/WRITE BUS subsystem * * AUTHOR: John Pultorak * DATE: 9/22/01 * FILE: BUS.h * * VERSIONS: * * DESCRIPTION: * RW Bus for the Block 1 Apollo Guidance Computer prototype (AGC4). * * SOURCES: * Mostly based on information from "Logical Description for the Apollo * Guidance Computer (AGC4)", Albert Hopkins, Ramon Alonso, and Hugh * Blair-Smith, R-393, MIT Instrumentation Laboratory, 1963. * * NOTES: * ***************************************************************************** */#ifndef BUS_H#define BUS_H
// BUS LINE DESIGNATIONS// Specify the assignment of bus lines to the inputs of a register (for a 'write'// operation into a register). Each 'conv_' array specifies the inputs into a// single register. The index into the array corresponds to the bit position in// the register, where the first parameter (index=0) is bit 16 of the register (msb)// and the last parameter (index=15) is register bit 1 (lsb). The value of// the parameter identifies the bus line assigned to that register bit. 'BX'// means 'don't care'; i.e.: leave that register bit alone.
enum { D0=17, // force bit to zeroSGM=15, // sign bit in memorySG=16, // sign (S2; one's compliment)US=15, // uncorrected sign (S1; overflow), except in register GB14=14, B13=13, B12=12, B11=11, B10=10, B9=9, B8=8, B7=7, B6=6, B5=5, B4=4, B3=3, B2=2, B1=1, BX=0 // ignore
};
enum ovfState { NO_OVF, POS_OVF, NEG_OVF };
class BUS{public:
static unsigned glbl_READ_BUS; // read/write bus for xfer between central regsstatic unsigned glbl_WRITE_BUS; // read/write bus for xfer between central regs
friend class INT;friend class CTR;
private:static ovfState testOverflow(unsigned bus);
};
#endif
BUS (BUS.cpp)
/**************************************************************************** * BUS - READ/WRITE BUS subsystem * * AUTHOR: John Pultorak * DATE: 9/22/01 * FILE: BUS.cpp * * NOTES: see header file. * ***************************************************************************** */#include "BUS.h"
unsigned BUS::glbl_READ_BUS = 0;unsigned BUS::glbl_WRITE_BUS = 0;
ovfState BUS::testOverflow(unsigned bus){
if((bus & 0100000) && !(bus & 0040000))return NEG_OVF; // negative overflow
else if(!(bus & 0100000) && (bus & 0040000))return POS_OVF; // positive overflow
elsereturn NO_OVF;
}
CLK (CLK.h)
/**************************************************************************** * CLK - CLOCK subsystem * * AUTHOR: John Pultorak * DATE: 9/22/01 * FILE: CLK.h * * VERSIONS: * * DESCRIPTION: * Clock for the Block 1 Apollo Guidance Computer prototype (AGC4). * * SOURCES: * Mostly based on information from "Logical Description for the Apollo * Guidance Computer (AGC4)", Albert Hopkins, Ramon Alonso, and Hugh * Blair-Smith, R-393, MIT Instrumentation Laboratory, 1963. * * NOTES: * ***************************************************************************** */#ifndef CLK_H#define CLK_H
#include "reg.h"
// define pointer-to-function typetypedef void (*EXECTYPE)();
class CLK{public:
static void doexecR(int pulse);static void doexecR_ALU(int pulse);static void doexecR_ALU_OR(int pulse);static void doexecW(int pulse);
static void clkAGC();
static reg* registerList[];
};
#endif
CLK (CLK.cpp)
/**************************************************************************** * CLK - CLOCK subsystem * * AUTHOR: John Pultorak * DATE: 9/22/01 * FILE: CLK.cpp * * NOTES: see header file. * ***************************************************************************** */#include "CLK.h"#include "INP.h"#include "OUT.h"#include "MBF.h"#include "ADR.h"#include "SEQ.h"#include "ALU.h"#include "CRG.h"#include "CTR.h"#include "INT.h"#include "PAR.h"#include "TPG.h"#include "SCL.h"#include "MEM.h"
// A container for all registers. This is kept so we can iterate through// all registers to execute the control pulses. For simulation purposes// only; this has no counterpart in the hardware AGC.
reg* CLK::registerList[] = // registers are in no particular sequence{
&INP::register_IN0, &INP::register_IN1, &INP::register_IN2, &INP::register_IN3,&OUT::register_OUT1, &OUT::register_OUT2, &OUT::register_OUT3, &OUT::register_OUT4,&MBF::register_G, &PAR::register_G15, &ADR::register_S, &ADR::register_BNK,
&SEQ::register_SQ, &ALU::register_B,&CRG::register_Q, &CRG::register_Z, &CRG::register_LP, &CRG::register_A, &ALU::register_X,&ALU::register_Y, &ALU::register_U, &SEQ::register_STA, &SEQ::register_STB, &SEQ::register_SNI,&SEQ::register_LOOPCTR, &ALU::register_CI, &SEQ::register_BR1, &SEQ::register_BR2, &CTR::register_UpCELL, &CTR::register_DnCELL,&INT::register_RPCELL, &INT::register_INHINT1, &INT::register_INHINT,&PAR::register_P, &PAR::register_P2, &PAR::register_PALM,&TPG::register_SG,&SCL::register_SCL,&SCL::register_F17, &SCL::register_F13, &SCL::register_F10,0 // zero is end-of-list flag
};
void CLK::clkAGC(){
// Now that all the inputs are set up, clock the registers so the outputs// can change state in accordance with the inputs.
for(int i=0; registerList[i]; i++){
registerList[i]->clk();}
}
void execR_NOPULSE() { }void execR_RA0() { CRG::execRP_RA0(); }void execR_RA1() { CRG::execRP_RA1(); }void execR_RA2() { CRG::execRP_RA2(); }void execR_RA3() { CRG::execRP_RA3(); }void execR_RA4() { INP::execRP_RA4(); }void execR_RA5() { INP::execRP_RA5(); }void execR_RA6() { INP::execRP_RA6(); }
void execR_RA7() { INP::execRP_RA7(); }void execR_RA11() { OUT::execRP_RA11(); }void execR_RA12() { OUT::execRP_RA12(); }void execR_RA13() { OUT::execRP_RA13(); }void execR_RA14() { OUT::execRP_RA14(); }void execR_RA() { CRG::execRP_RA(); }void execR_RBK() { ADR::execRP_RBK(); }void execR_RG() { MBF::execRP_RG(); }void execR_RLP() { CRG::execRP_RLP(); }void execR_RQ() { CRG::execRP_RQ(); }void execR_RRPA() { INT::execRP_RRPA(); }void execR_RSCT() { CTR::execRP_RSCT(); }void execR_RZ() { CRG::execRP_RZ(); }void execR_SBWG() { MEM::execRP_SBWG(); }void execR_WE() { MBF::execRP_WE(); PAR::execRP_WE(); }
void execR_ALU_RB() { ALU::execRP_ALU_RB(); }void execR_ALU_RC() { ALU::execRP_ALU_RC(); }void execR_ALU_RU() { ALU::execRP_ALU_RU(); }
void execR_ALU_OR_RSB() { ALU::execRP_ALU_OR_RSB(); }void execR_ALU_OR_R1() { ALU::execRP_ALU_OR_R1(); }void execR_ALU_OR_R1C() { ALU::execRP_ALU_OR_R1C(); }void execR_ALU_OR_R2() { ALU::execRP_ALU_OR_R2(); }void execR_ALU_OR_R22() { ALU::execRP_ALU_OR_R22(); }void execR_ALU_OR_R24() { ALU::execRP_ALU_OR_R24(); }void execR_ALU_OR_R2000() { ALU::execRP_ALU_OR_R2000(); }void execR_ALU_OR_RB14() { ALU::execRP_ALU_OR_RB14(); }
EXECTYPE execR[] ={
execR_NOPULSE, // NO_PULSE,execR_NOPULSE, // CI, // Carry inexecR_NOPULSE, // CLG, // Clear GexecR_NOPULSE, // CLCTR, // Clear loop counter**execR_NOPULSE, // CTR, // Loop counterexecR_NOPULSE, // GP, // Generate ParityexecR_NOPULSE, // KRPT, // Knock down Rupt priorityexecR_NOPULSE, // NISQ, // New instruction to the SQ registerexecR_RA, // RA, // Read AexecR_NOPULSE, // RB, // Read BexecR_NOPULSE, // RB14, // Read bit 14execR_NOPULSE, // RC, // Read CexecR_RG, // RG, // Read GexecR_RLP, // RLP, // Read LPexecR_NOPULSE, // RP2, // Read parity 2execR_RQ, // RQ, // Read QexecR_RRPA, // RRPA, // Read RUPT addressexecR_NOPULSE, // RSB, // Read sign bitexecR_RSCT, // RSCT, // Read selected counter addressexecR_NOPULSE, // RU, // Read sumexecR_RZ, // RZ, // Read ZexecR_NOPULSE, // R1, // Read 1execR_NOPULSE, // R1C, // Read 1 complimentedexecR_NOPULSE, // R2, // Read 2execR_NOPULSE, // R22, // Read 22execR_NOPULSE, // R24, // Read 24execR_NOPULSE, // ST1, // Stage 1execR_NOPULSE, // ST2, // Stage 2execR_NOPULSE, // TMZ, // Test for minus zeroexecR_NOPULSE, // TOV, // Test for overflowexecR_NOPULSE, // TP, // Test parityexecR_NOPULSE, // TRSM, // Test for resumeexecR_NOPULSE, // TSGN, // Test signexecR_NOPULSE, // TSGN2, // Test sign 2execR_NOPULSE, // WA, // Write AexecR_NOPULSE, // WALP, // Write A and LPexecR_NOPULSE, // WB, // Write BexecR_NOPULSE, // WGx, // Write G (do not reset)execR_NOPULSE, // WLP, // Write LPexecR_NOPULSE, // WOVC, // Write overflow counterexecR_NOPULSE, // WOVI, // Write overflow RUPT inhibitexecR_NOPULSE, // WOVR, // Write overflowexecR_NOPULSE, // WP, // Write P
execR_NOPULSE, // WPx, // Write P (do not reset)execR_NOPULSE, // WP2, // Write P2execR_NOPULSE, // WQ, // Write QexecR_NOPULSE, // WS, // Write SexecR_NOPULSE, // WX, // Write XexecR_NOPULSE, // WY, // Write YexecR_NOPULSE, // WYx, // Write Y (do not reset)execR_NOPULSE, // WZ, // Write Z
execR_NOPULSE, // RSC, // Read special and centralexecR_NOPULSE, // WSC, // Write special and centralexecR_NOPULSE, // WG, // Write G
execR_NOPULSE, // SDV1, // Subsequence DV1 is activeexecR_NOPULSE, // SMP1, // Subsequence MP1 is activeexecR_NOPULSE, // SRSM3, // Subsequence RSM3 is active
execR_RA0, // RA0, // Read register at address 0 (A)execR_RA1, // RA1, // Read register at address 1 (Q)execR_RA2, // RA2, // Read register at address 2 (Z)execR_RA3, // RA3, // Read register at address 3 (LP)execR_RA4, // RA4, // Read register at address 4execR_RA5, // RA5, // Read register at address 5execR_RA6, // RA6, // Read register at address 6execR_RA7, // RA7, // Read register at address 7execR_NOPULSE, // RA10, // Read register at address 10 (octal)execR_RA11, // RA11, // Read register at address 11 (octal)execR_RA12, // RA12, // Read register at address 12 (octal)execR_RA13, // RA13, // Read register at address 13 (octal)execR_RA14, // RA14, // Read register at address 14 (octal)execR_RBK, // RBK, // Read BNKexecR_NOPULSE, // WA0, // Write register at address 0 (A)execR_NOPULSE, // WA1, // Write register at address 1 (Q)execR_NOPULSE, // WA2, // Write register at address 2 (Z)execR_NOPULSE, // WA3, // Write register at address 3 (LP)execR_NOPULSE, // WA10, // Write register at address 10 (octal)execR_NOPULSE, // WA11, // Write register at address 11 (octal)execR_NOPULSE, // WA12, // Write register at address 12 (octal)execR_NOPULSE, // WA13, // Write register at address 13 (octal)execR_NOPULSE, // WA14, // Write register at address 14 (octal)execR_NOPULSE, // WBK, // Write BNKexecR_NOPULSE, // WGn, // Write G (normal gates)**execR_NOPULSE, // W20, // Write into CYRexecR_NOPULSE, // W21, // Write into SRexecR_NOPULSE, // W22, // Write into CYLexecR_NOPULSE, // W23 // Write into SL
execR_NOPULSE, // GENRST,// General Reset**execR_NOPULSE, // CLINH, // Clear INHINT**execR_NOPULSE, // CLINH1,// Clear INHINT1**execR_NOPULSE, // CLSTA, // Clear state counter A (STA)**execR_NOPULSE, // CLSTB, // Clear state counter B (STB)**execR_NOPULSE, // CLISQ, // Clear SNI**execR_NOPULSE, // CLRP, // Clear RPCELL**execR_NOPULSE, // INH, // Set INHINT**execR_NOPULSE, // RPT, // Read RUPT opcode **execR_SBWG, // SBWG, // Write G from memoryexecR_NOPULSE, // SETSTB,// Set the ST1 bit of STBexecR_WE, // WE, // Write E-MEM from GexecR_NOPULSE, // WPCTR, // Write PCTR (latch priority counter sequence)**execR_NOPULSE, // WSQ, // Write SQexecR_NOPULSE, // WSTB, // Write stage counter B (STB)**execR_NOPULSE, // R2000, // Read 2000 **
}; // 99
void CLK::doexecR(int pulse) { execR[pulse](); }
EXECTYPE execR_ALU[] ={
execR_NOPULSE, // NO_PULSE,execR_NOPULSE, // CI, // Carry inexecR_NOPULSE, // CLG, // Clear G
execR_NOPULSE, // CLCTR, // Clear loop counter**execR_NOPULSE, // CTR, // Loop counterexecR_NOPULSE, // GP, // Generate ParityexecR_NOPULSE, // KRPT, // Knock down Rupt priorityexecR_NOPULSE, // NISQ, // New instruction to the SQ registerexecR_NOPULSE, // RA, // Read AexecR_ALU_RB, // RB, // Read BexecR_NOPULSE, // RB14, // Read bit 14execR_ALU_RC, // RC, // Read CexecR_NOPULSE, // RG, // Read GexecR_NOPULSE, // RLP, // Read LPexecR_NOPULSE, // RP2, // Read parity 2execR_NOPULSE, // RQ, // Read QexecR_NOPULSE, // RRPA, // Read RUPT addressexecR_NOPULSE, // RSB, // Read sign bitexecR_NOPULSE, // RSCT, // Read selected counter addressexecR_ALU_RU, // RU, // Read sumexecR_NOPULSE, // RZ, // Read ZexecR_NOPULSE, // R1, // Read 1execR_NOPULSE, // R1C, // Read 1 complimentedexecR_NOPULSE, // R2, // Read 2execR_NOPULSE, // R22, // Read 22execR_NOPULSE, // R24, // Read 24execR_NOPULSE, // ST1, // Stage 1execR_NOPULSE, // ST2, // Stage 2execR_NOPULSE, // TMZ, // Test for minus zeroexecR_NOPULSE, // TOV, // Test for overflowexecR_NOPULSE, // TP, // Test parityexecR_NOPULSE, // TRSM, // Test for resumeexecR_NOPULSE, // TSGN, // Test signexecR_NOPULSE, // TSGN2, // Test sign 2execR_NOPULSE, // WA, // Write AexecR_NOPULSE, // WALP, // Write A and LPexecR_NOPULSE, // WB, // Write BexecR_NOPULSE, // WGx, // Write G (do not reset)execR_NOPULSE, // WLP, // Write LPexecR_NOPULSE, // WOVC, // Write overflow counterexecR_NOPULSE, // WOVI, // Write overflow RUPT inhibitexecR_NOPULSE, // WOVR, // Write overflowexecR_NOPULSE, // WP, // Write PexecR_NOPULSE, // WPx, // Write P (do not reset)execR_NOPULSE, // WP2, // Write P2execR_NOPULSE, // WQ, // Write QexecR_NOPULSE, // WS, // Write SexecR_NOPULSE, // WX, // Write XexecR_NOPULSE, // WY, // Write YexecR_NOPULSE, // WYx, // Write Y (do not reset)execR_NOPULSE, // WZ, // Write Z
execR_NOPULSE, // RSC, // Read special and centralexecR_NOPULSE, // WSC, // Write special and centralexecR_NOPULSE, // WG, // Write G
execR_NOPULSE, // SDV1, // Subsequence DV1 is activeexecR_NOPULSE, // SMP1, // Subsequence MP1 is activeexecR_NOPULSE, // SRSM3, // Subsequence RSM3 is active
execR_NOPULSE, // RA0, // Read register at address 0 (A)execR_NOPULSE, // RA1, // Read register at address 1 (Q)execR_NOPULSE, // RA2, // Read register at address 2 (Z)execR_NOPULSE, // RA3, // Read register at address 3 (LP)execR_NOPULSE, // RA4, // Read register at address 4execR_NOPULSE, // RA5, // Read register at address 5execR_NOPULSE, // RA6, // Read register at address 6execR_NOPULSE, // RA7, // Read register at address 7execR_NOPULSE, // RA10, // Read register at address 10 (octal)execR_NOPULSE, // RA11, // Read register at address 11 (octal)execR_NOPULSE, // RA12, // Read register at address 12 (octal)execR_NOPULSE, // RA13, // Read register at address 13 (octal)execR_NOPULSE, // RA14, // Read register at address 14 (octal)execR_NOPULSE, // RBK, // Read BNKexecR_NOPULSE, // WA0, // Write register at address 0 (A)execR_NOPULSE, // WA1, // Write register at address 1 (Q)execR_NOPULSE, // WA2, // Write register at address 2 (Z)execR_NOPULSE, // WA3, // Write register at address 3 (LP)execR_NOPULSE, // WA10, // Write register at address 10 (octal)
execR_NOPULSE, // WA11, // Write register at address 11 (octal)execR_NOPULSE, // WA12, // Write register at address 12 (octal)execR_NOPULSE, // WA13, // Write register at address 13 (octal)execR_NOPULSE, // WA14, // Write register at address 14 (octal)execR_NOPULSE, // WBK, // Write BNKexecR_NOPULSE, // WGn, // Write G (normal gates)**execR_NOPULSE, // W20, // Write into CYRexecR_NOPULSE, // W21, // Write into SRexecR_NOPULSE, // W22, // Write into CYLexecR_NOPULSE, // W23 // Write into SL
execR_NOPULSE, // GENRST,// General Reset**execR_NOPULSE, // CLINH, // Clear INHINT**execR_NOPULSE, // CLINH1,// Clear INHINT1**execR_NOPULSE, // CLSTA, // Clear state counter A (STA)**execR_NOPULSE, // CLSTB, // Clear state counter B (STB)**execR_NOPULSE, // CLISQ, // Clear SNI**execR_NOPULSE, // CLRP, // Clear RPCELL**execR_NOPULSE, // INH, // Set INHINT**execR_NOPULSE, // RPT, // Read RUPT opcode **execR_NOPULSE, // SBWG, // Write G from memoryexecR_NOPULSE, // SETSTB,// Set the ST1 bit of STBexecR_NOPULSE, // WE, // Write E-MEM from GexecR_NOPULSE, // WPCTR, // Write PCTR (latch priority counter sequence)**execR_NOPULSE, // WSQ, // Write SQexecR_NOPULSE, // WSTB, // Write stage counter B (STB)**execR_NOPULSE, // R2000, // Read 2000 **
};
void CLK::doexecR_ALU(int pulse) { execR_ALU[pulse](); }
EXECTYPE execR_ALU_OR[] ={
execR_NOPULSE, // NO_PULSE,execR_NOPULSE, // CI, // Carry inexecR_NOPULSE, // CLG, // Clear GexecR_NOPULSE, // CLCTR, // Clear loop counter**execR_NOPULSE, // CTR, // Loop counterexecR_NOPULSE, // GP, // Generate ParityexecR_NOPULSE, // KRPT, // Knock down Rupt priorityexecR_NOPULSE, // NISQ, // New instruction to the SQ registerexecR_NOPULSE, // RA, // Read AexecR_NOPULSE, // RB, // Read BexecR_ALU_OR_RB14, // RB14, // Read bit 14execR_NOPULSE, // RC, // Read CexecR_NOPULSE, // RG, // Read GexecR_NOPULSE, // RLP, // Read LPexecR_NOPULSE, // RP2, // Read parity 2execR_NOPULSE, // RQ, // Read QexecR_NOPULSE, // RRPA, // Read RUPT addressexecR_ALU_OR_RSB, // RSB, // Read sign bitexecR_NOPULSE, // RSCT, // Read selected counter addressexecR_NOPULSE, // RU, // Read sumexecR_NOPULSE, // RZ, // Read ZexecR_ALU_OR_R1, // R1, // Read 1execR_ALU_OR_R1C, // R1C, // Read 1 complimentedexecR_ALU_OR_R2, // R2, // Read 2execR_ALU_OR_R22, // R22, // Read 22execR_ALU_OR_R24, // R24, // Read 24execR_NOPULSE, // ST1, // Stage 1execR_NOPULSE, // ST2, // Stage 2execR_NOPULSE, // TMZ, // Test for minus zeroexecR_NOPULSE, // TOV, // Test for overflowexecR_NOPULSE, // TP, // Test parityexecR_NOPULSE, // TRSM, // Test for resumeexecR_NOPULSE, // TSGN, // Test signexecR_NOPULSE, // TSGN2, // Test sign 2execR_NOPULSE, // WA, // Write AexecR_NOPULSE, // WALP, // Write A and LPexecR_NOPULSE, // WB, // Write BexecR_NOPULSE, // WGx, // Write G (do not reset)execR_NOPULSE, // WLP, // Write LP
execR_NOPULSE, // WOVC, // Write overflow counterexecR_NOPULSE, // WOVI, // Write overflow RUPT inhibitexecR_NOPULSE, // WOVR, // Write overflowexecR_NOPULSE, // WP, // Write PexecR_NOPULSE, // WPx, // Write P (do not reset)execR_NOPULSE, // WP2, // Write P2execR_NOPULSE, // WQ, // Write QexecR_NOPULSE, // WS, // Write SexecR_NOPULSE, // WX, // Write XexecR_NOPULSE, // WY, // Write YexecR_NOPULSE, // WYx, // Write Y (do not reset)execR_NOPULSE, // WZ, // Write Z
execR_NOPULSE, // RSC, // Read special and centralexecR_NOPULSE, // WSC, // Write special and centralexecR_NOPULSE, // WG, // Write G
execR_NOPULSE, // SDV1, // Subsequence DV1 is activeexecR_NOPULSE, // SMP1, // Subsequence MP1 is activeexecR_NOPULSE, // SRSM3, // Subsequence RSM3 is active
execR_NOPULSE, // RA0, // Read register at address 0 (A)execR_NOPULSE, // RA1, // Read register at address 1 (Q)execR_NOPULSE, // RA2, // Read register at address 2 (Z)execR_NOPULSE, // RA3, // Read register at address 3 (LP)execR_NOPULSE, // RA4, // Read register at address 4execR_NOPULSE, // RA5, // Read register at address 5execR_NOPULSE, // RA6, // Read register at address 6execR_NOPULSE, // RA7, // Read register at address 7execR_NOPULSE, // RA10, // Read register at address 10 (octal)execR_NOPULSE, // RA11, // Read register at address 11 (octal)execR_NOPULSE, // RA12, // Read register at address 12 (octal)execR_NOPULSE, // RA13, // Read register at address 13 (octal)execR_NOPULSE, // RA14, // Read register at address 14 (octal)execR_NOPULSE, // RBK, // Read BNKexecR_NOPULSE, // WA0, // Write register at address 0 (A)execR_NOPULSE, // WA1, // Write register at address 1 (Q)execR_NOPULSE, // WA2, // Write register at address 2 (Z)execR_NOPULSE, // WA3, // Write register at address 3 (LP)execR_NOPULSE, // WA10, // Write register at address 10 (octal)execR_NOPULSE, // WA11, // Write register at address 11 (octal)execR_NOPULSE, // WA12, // Write register at address 12 (octal)execR_NOPULSE, // WA13, // Write register at address 13 (octal)execR_NOPULSE, // WA14, // Write register at address 14 (octal)execR_NOPULSE, // WBK, // Write BNKexecR_NOPULSE, // WGn, // Write G (normal gates)**execR_NOPULSE, // W20, // Write into CYRexecR_NOPULSE, // W21, // Write into SRexecR_NOPULSE, // W22, // Write into CYLexecR_NOPULSE, // W23 // Write into SL
execR_NOPULSE, // GENRST,// General Reset**execR_NOPULSE, // CLINH, // Clear INHINT**execR_NOPULSE, // CLINH1,// Clear INHINT1**execR_NOPULSE, // CLSTA, // Clear state counter A (STA)**execR_NOPULSE, // CLSTB, // Clear state counter B (STB)**execR_NOPULSE, // CLISQ, // Clear SNI**execR_NOPULSE, // CLRP, // Clear RPCELL**execR_NOPULSE, // INH, // Set INHINT**execR_NOPULSE, // RPT, // Read RUPT opcode **execR_NOPULSE, // SBWG, // Write G from memoryexecR_NOPULSE, // SETSTB,// Set the ST1 bit of STBexecR_NOPULSE, // WE, // Write E-MEM from GexecR_NOPULSE, // WPCTR, // Write PCTR (latch priority counter sequence)**execR_NOPULSE, // WSQ, // Write SQexecR_NOPULSE, // WSTB, // Write stage counter B (STB)**execR_ALU_OR_R2000, // R2000, // Read 2000 **
};
void CLK::doexecR_ALU_OR(int pulse) { execR_ALU_OR[pulse](); }
void execW_NOPULSE() { }void execW_CI() { ALU::execWP_CI(); }void execW_CLG() { PAR::execWP_CLG(); }void execW_CLINH() { INT::execWP_CLINH(); }void execW_CLINH1() { INT::execWP_CLINH1(); }void execW_CLISQ() { SEQ::execWP_CLISQ(); }void execW_CLCTR() { SEQ::execWP_CLCTR(); }void execW_CLRP() { INT::execWP_CLRP(); }void execW_CLSTA() { SEQ::execWP_CLSTA(); }void execW_CLSTB() { SEQ::execWP_CLSTB(); }void execW_CTR() { SEQ::execWP_CTR(); }
void execW_GENRST() { SEQ::execWP_GENRST(); MBF::execWP_GENRST(); CRG::execWP_GENRST(); PAR::execWP_GENRST(); ALU::execWP_GENRST(); CTR::execWP_GENRST(); INT::execWP_GENRST(); OUT::execWP_GENRST(); }
void execW_GP() { PAR::execWP_GP(); }void execW_INH() { INT::execWP_INH(); }void execW_KRPT() { INT::execWP_KRPT(); }void execW_NISQ() { SEQ::execWP_NISQ(); }void execW_RPT() { INT::execWP_RPT(); }void execW_RP2() { PAR::execWP_RP2(); }void execW_SBWG() { MBF::execWP_SBWG(); PAR::execWP_SBWG(); }void execW_SETSTB() { SEQ::execWP_SETSTB(); }void execW_ST1() { SEQ::execWP_ST1(); }void execW_ST2() { SEQ::execWP_ST2(); }void execW_TMZ() { SEQ::execWP_TMZ(); }void execW_TOV() { SEQ::execWP_TOV(); }void execW_TP() { PAR::execWP_TP(); }void execW_TRSM() { SEQ::execWP_TRSM(); }void execW_TSGN() { SEQ::execWP_TSGN(); }void execW_TSGN2() { SEQ::execWP_TSGN2(); }void execW_WA0() { CRG::execWP_WA0(); }void execW_WA1() { CRG::execWP_WA1(); }void execW_WA2() { CRG::execWP_WA2(); }void execW_WA3() { CRG::execWP_WA3(); }void execW_WA10() { OUT::execWP_WA10(); }void execW_WA11() { OUT::execWP_WA11(); }void execW_WA12() { OUT::execWP_WA12(); }void execW_WA13() { OUT::execWP_WA13(); }void execW_WA14() { OUT::execWP_WA14(); }void execW_WA() { CRG::execWP_WA(); }void execW_WALP() { CRG::execWP_WALP(); }void execW_WB() { ALU::execWP_WB(); }void execW_WBK() { ADR::execWP_WBK(); }void execW_WE() { MEM::execWP_WE(); }void execW_WGn() { MBF::execWP_WGn(); }void execW_WGx() { MBF::execWP_WGx(); PAR::execWP_WGx(); }void execW_WLP() { CRG::execWP_WLP(); }void execW_WOVC() { CTR::execWP_WOVC(); }void execW_WOVI() { INT::execWP_WOVI(); }void execW_WOVR() { CTR::execWP_WOVR(); }void execW_WP() { PAR::execWP_WP(); }void execW_WPx() { PAR::execWP_WPx(); }void execW_WP2() { PAR::execWP_WP2(); }void execW_WPCTR() { CTR::execWP_WPCTR(); }void execW_WQ() { CRG::execWP_WQ(); }void execW_WS() { ADR::execWP_WS(); }void execW_WSQ() { SEQ::execWP_WSQ(); }void execW_WSTB() { SEQ::execWP_WSTB(); }void execW_WX() { ALU::execWP_WX(); }void execW_WY() { ALU::execWP_WY(); }void execW_WYx() { ALU::execWP_WYx(); }void execW_WZ() { CRG::execWP_WZ(); }void execW_W20() { MBF::execWP_W20(); }void execW_W21() { MBF::execWP_W21(); }void execW_W22() { MBF::execWP_W22(); }void execW_W23() { MBF::execWP_W23(); }
EXECTYPE execW[] ={
execW_NOPULSE, // NO_PULSE,execW_CI, // CI, // Carry inexecW_CLG, // CLG, // Clear GexecW_CLCTR, // CLCTR, // Clear loop counter**execW_CTR, // CTR, // Loop counterexecW_GP, // GP, // Generate ParityexecW_KRPT, // KRPT, // Knock down Rupt priorityexecW_NISQ, // NISQ, // New instruction to the SQ registerexecW_NOPULSE, // RA, // Read AexecW_NOPULSE, // RB, // Read BexecW_NOPULSE, // RB14, // Read bit 14execW_NOPULSE, // RC, // Read CexecW_NOPULSE, // RG, // Read GexecW_NOPULSE, // RLP, // Read LPexecW_RP2, // RP2, // Read parity 2execW_NOPULSE, // RQ, // Read QexecW_NOPULSE, // RRPA, // Read RUPT addressexecW_NOPULSE, // RSB, // Read sign bitexecW_NOPULSE, // RSCT, // Read selected counter addressexecW_NOPULSE, // RU, // Read sumexecW_NOPULSE, // RZ, // Read ZexecW_NOPULSE, // R1, // Read 1execW_NOPULSE, // R1C, // Read 1 complimentedexecW_NOPULSE, // R2, // Read 2execW_NOPULSE, // R22, // Read 22execW_NOPULSE, // R24, // Read 24execW_ST1, // ST1, // Stage 1execW_ST2, // ST2, // Stage 2execW_TMZ, // TMZ, // Test for minus zeroexecW_TOV, // TOV, // Test for overflowexecW_TP, // TP, // Test parityexecW_TRSM, // TRSM, // Test for resumeexecW_TSGN, // TSGN, // Test signexecW_TSGN2, // TSGN2, // Test sign 2execW_WA, // WA, // Write AexecW_WALP, // WALP, // Write A and LPexecW_WB, // WB, // Write BexecW_WGx, // WGx, // Write G (do not reset)execW_WLP, // WLP, // Write LPexecW_WOVC, // WOVC, // Write overflow counterexecW_WOVI, // WOVI, // Write overflow RUPT inhibitexecW_WOVR, // WOVR, // Write overflowexecW_WP, // WP, // Write PexecW_WPx, // WPx, // Write P (do not reset)execW_WP2, // WP2, // Write P2execW_WQ, // WQ, // Write QexecW_WS, // WS, // Write SexecW_WX, // WX, // Write XexecW_WY, // WY, // Write YexecW_WYx, // WYx, // Write Y (do not reset)execW_WZ, // WZ, // Write Z
execW_NOPULSE, // RSC, // Read special and centralexecW_NOPULSE, // WSC, // Write special and centralexecW_NOPULSE, // WG, // Write G
execR_NOPULSE, // SDV1, // Subsequence DV1 is activeexecR_NOPULSE, // SMP1, // Subsequence MP1 is activeexecR_NOPULSE, // SRSM3, // Subsequence RSM3 is active
execW_NOPULSE, // RA0, // Read register at address 0 (A)execW_NOPULSE, // RA1, // Read register at address 1 (Q)execW_NOPULSE, // RA2, // Read register at address 2 (Z)execW_NOPULSE, // RA3, // Read register at address 3 (LP)execW_NOPULSE, // RA4, // Read register at address 4execW_NOPULSE, // RA5, // Read register at address 5execW_NOPULSE, // RA6, // Read register at address 6execW_NOPULSE, // RA7, // Read register at address 7execW_NOPULSE, // RA10, // Read register at address 10 (octal)execW_NOPULSE, // RA11, // Read register at address 11 (octal)execW_NOPULSE, // RA12, // Read register at address 12 (octal)execW_NOPULSE, // RA13, // Read register at address 13 (octal)execW_NOPULSE, // RA14, // Read register at address 14 (octal)execW_NOPULSE, // RBK, // Read BNK
execW_WA0, // WA0, // Write register at address 0 (A)execW_WA1, // WA1, // Write register at address 1 (Q)execW_WA2, // WA2, // Write register at address 2 (Z)execW_WA3, // WA3, // Write register at address 3 (LP)execW_WA10, // WA10, // Write register at address 10 (octal)execW_WA11, // WA11, // Write register at address 11 (octal)execW_WA12, // WA12, // Write register at address 12 (octal)execW_WA13, // WA13, // Write register at address 13 (octal)execW_WA14, // WA14, // Write register at address 14 (octal)execW_WBK, // WBK, // Write BNKexecW_WGn, // WGn, // Write G (normal gates)**execW_W20, // W20, // Write into CYRexecW_W21, // W21, // Write into SRexecW_W22, // W22, // Write into CYLexecW_W23, // W23 // Write into SL
execW_GENRST, // GENRST,// General Reset**execW_CLINH, // CLINH, // Clear INHINT**execW_CLINH1, // CLINH1,// Clear INHINT1**execW_CLSTA, // CLSTA, // Clear state counter A (STA)**execW_CLSTB, // CLSTB, // Clear state counter B (STB)**execW_CLISQ, // CLISQ, // Clear SNI**execW_CLRP, // CLRP, // Clear RPCELL**execW_INH, // INH, // Set INHINT**execW_RPT, // RPT, // Read RUPT opcode **execW_SBWG, // SBWG, // Write G from memoryexecW_SETSTB, // SETSTB,// Set the ST1 bit of STBexecW_WE, // WE, // Write E-MEM from GexecW_WPCTR, // WPCTR, // Write PCTR (latch priority counter sequence)**execW_WSQ, // WSQ, // Write SQexecW_WSTB, // WSTB, // Write stage counter B (STB)**execW_NOPULSE, // R2000, // Read 2000 **
}; // 99
void CLK::doexecW(int pulse) { execW[pulse](); }
CPM (CPM.h)
/**************************************************************************** * CPM - CONTROL PULSE MATRIX subsystem * * AUTHOR: John Pultorak * DATE: 9/22/01 * FILE: CPM.h * * VERSIONS: * * DESCRIPTION: * Control Pulse Matrix for the Block 1 Apollo Guidance Computer prototype (AGC4). * * SOURCES: * Mostly based on information from "Logical Description for the Apollo * Guidance Computer (AGC4)", Albert Hopkins, Ramon Alonso, and Hugh * Blair-Smith, R-393, MIT Instrumentation Laboratory, 1963. * * NOTES: * ***************************************************************************** */#ifndef CPM_H#define CPM_H
#include "TPG.h"#include "SEQ.h"
class CPM{public:
static subseq instructionSubsequenceDecoder(int counter_subseq, int SQ_field, int STB_field);
static char* subseqString[];
static void controlPulseMatrix();
static void readEPROM(char* fileName, int* eprom);
static int EPROM1_8 [0x3fff+1];static int EPROM9_16 [0x3fff+1];static int EPROM17_24[0x3fff+1];static int EPROM25_32[0x3fff+1];static int EPROM33_40[0x3fff+1];static int EPROM41_48[0x3fff+1];static int EPROM49_56[0x3fff+1];
private:// Clear the list of currently asserted control pulses.
static void clearControlPulses();
// Assert the set of control pulses by adding them to the list of currently// active control signals.static void assert(cpType* pulse);
// Assert a control pulse by adding it to the list of currently asserted// control pulses.static void assert(cpType pulse);
static void get_CPM_A(int CPM_A_address);
static void getControlPulses_EPROM(int address);
static void checkEPROM(int inval, int lowbit);};
#endif
CPM (CPM.cpp)
/**************************************************************************** * CPM - CONTROL PULSE MATRIX subsystem * * AUTHOR: John Pultorak * DATE: 9/22/01 * FILE: CPM.cpp * * NOTES: see header file. * ***************************************************************************** */#include "CPM.h"#include "SEQ.h"#include "MON.h"#include "CTR.h"#include "INT.h"#include "ADR.h"
#include <stdlib.h>
char* CPM::subseqString[] ={
"TC0","CCS0","CCS1","NDX0","NDX1","RSM3","XCH0","CS0","TS0","AD0","MASK0","MP0","MP1","MP3","DV0","DV1","SU0","RUPT1","RUPT3","STD2","PINC0","MINC0","SHINC0","NO_SEQ"
};
subseq CPM::instructionSubsequenceDecoder(int counter_subseq, int SQ_field, int STB_field)
{// Combinational logic decodes instruction and the stage count // to get the instruction subsequence.
static subseq decode[16][4] = {{ TC0, RUPT1, STD2, RUPT3 }, // 00{ CCS0, CCS1, NO_SEQ, NO_SEQ }, // 01{ NDX0, NDX1, NO_SEQ, RSM3 }, // 02{ XCH0, NO_SEQ, STD2, NO_SEQ }, // 03
{ NO_SEQ, NO_SEQ, NO_SEQ, NO_SEQ }, // 04{ NO_SEQ, NO_SEQ, NO_SEQ, NO_SEQ }, // 05{ NO_SEQ, NO_SEQ, NO_SEQ, NO_SEQ }, // 06{ NO_SEQ, NO_SEQ, NO_SEQ, NO_SEQ }, // 07{ NO_SEQ, NO_SEQ, NO_SEQ, NO_SEQ }, // 10
{ MP0, MP1, NO_SEQ, MP3 }, // 11{ DV0, DV1, STD2, NO_SEQ }, // 12{ SU0, NO_SEQ, STD2, NO_SEQ }, // 13
{ CS0, NO_SEQ, STD2, NO_SEQ }, // 14{ TS0, NO_SEQ, STD2, NO_SEQ }, // 15{ AD0, NO_SEQ, STD2, NO_SEQ }, // 16
{ MASK0, NO_SEQ, STD2, NO_SEQ } // 17
};
if(counter_subseq == PINCSEL)return PINC0;
else if(counter_subseq == MINCSEL)return MINC0;
elsereturn decode[SQ_field][STB_field];
}
void CPM::clearControlPulses(){
for(unsigned i=0; i<MAXPULSES; i++)SEQ::glbl_cp[i] = NO_PULSE;
}
void CPM::assert(cpType* pulse){
int j=0;for(unsigned i=0; i<MAXPULSES && j<MAX_IPULSES && pulse[j] != NO_PULSE; i++){
if(SEQ::glbl_cp[i] == NO_PULSE){
SEQ::glbl_cp[i] = pulse[j];j++;
}}
}
void CPM::assert(cpType pulse){
for(unsigned i=0; i<MAXPULSES; i++){
if(SEQ::glbl_cp[i] == NO_PULSE){
SEQ::glbl_cp[i] = pulse;break;
}}
}
int CPM::EPROM1_8 [];int CPM::EPROM9_16 [];int CPM::EPROM17_24[];int CPM::EPROM25_32[];int CPM::EPROM33_40[];int CPM::EPROM41_48[];int CPM::EPROM49_56[];
void CPM::readEPROM(char* fileName, int* eprom){
cout << "Reading EPROM: " << fileName << endl;
// Open the EPROM file.FILE* ifp = fopen(fileName, "r");if(!ifp){
perror("fopen failed for source file");exit(-1);
}
const int addressBytes = 3; // 24-bit address rangeconst int sumCheckBytes = 1;
char buf[4096];while(fgets(buf,4096,ifp)){
// process a recordif(buf[0] != 'S'){
cout << "Error reading start of EPROM record for: " << fileName << endl;exit(-1);
}
char tmp[256];
strncpy(tmp, &buf[2], 2); tmp[2] = '\0';int totalByteCount = strtol(tmp, 0, 16);int mySumCheck = totalByteCount & 0xff;
strncpy(tmp, &buf[4], 6); tmp[addressBytes*2] = '\0';int address = strtol(tmp, 0, 16);mySumCheck = (mySumCheck + ((address & 0xff0000) >> 16)) % 256;mySumCheck = (mySumCheck + ((address & 0x00ff00) >> 8)) % 256;mySumCheck = (mySumCheck + ((address & 0x0000ff) )) % 256;
//cout << hex << totalByteCount << ", " << address << dec << endl;
int dataBytes = totalByteCount - addressBytes - sumCheckBytes;int i = (addressBytes+2)*2; // index to 1st databyte char.for(int j=0; j<dataBytes; j++){
// get a data bytestrncpy(tmp, &buf[i], 2); tmp[2] = '\0';int data = strtol(tmp, 0, 16);//cout << hex << data << dec << endl;mySumCheck = (mySumCheck + data) % 256;
// The H/W AGC needs negative logic in the EPROMS (0=asserted)// but this simulator needs positive logic, so we bit flip the word.//eprom[address] = data;eprom[address] = ((~data) & 0xff);address++;
i+=2; // bump to next databyte char}strncpy(tmp, &buf[i], 2); tmp[2] = '\0';int sumCheck = strtol(tmp, 0, 16);
if(sumCheck != ((~mySumCheck) & 0xff)){
cout << "sumCheck failed; file: " << fileName << ", address: " << hex <<address
<< ", sumCheck: " << sumCheck << ", mySumCheck: " << mySumCheck <<dec << endl;
exit(-1);}
}fclose(ifp);
}
void CPM::checkEPROM(int inval, int lowbit){
for(int mask=0x1; inval && mask !=0x100; mask=mask<<1){
if(inval & mask)assert((cpType) lowbit);
lowbit++;}
}
// perform the CPM-A EPROM function using the EPROM filesvoid CPM::getControlPulses_EPROM(int address){
checkEPROM(EPROM1_8 [address], 1);checkEPROM(EPROM9_16 [address], 9);checkEPROM(EPROM17_24[address], 17);checkEPROM(EPROM25_32[address], 25);checkEPROM(EPROM33_40[address], 33);checkEPROM(EPROM41_48[address], 41);checkEPROM(EPROM49_56[address], 49);
}
void CPM::get_CPM_A(int address)
{// Use the EPROM tables to get the CPM-A control pulses documented// in R-393.
getControlPulses_EPROM(address);
// Now add some additional control pulses implied, but not documented// in R-393.if(SEQ::register_LOOPCTR.read() == 6){
assert(ST2); // STA <- 2assert(CLCTR); // CTR <- 0
}
//*****************************************************************// Now that the EPROM tables are used for CPM-A, this function is only // used to display the instruction subsequence in MON.
SEQ::glbl_subseq = CPM::instructionSubsequenceDecoder(CTR::getSubseq(), SEQ::register_SQ.read(), SEQ::register_STB.read());//*****************************************************************
// These were in CPM-C, where the rest of the control signal assertions// related to their use still are, but were moved here because WB and RB// are part of the R-393 sequence tables. Check CPM-C to see how these// assertions fit in (the former use is commented out there).
switch(TPG::register_SG.read()){
case PWRON:assert(WB); // TC GOPROG copied to B (see CPM-C for related assertions)break;
case TP12:if(SEQ::register_SNI.read() == 1){
if(!INT::IRQ()){
// Normal instructionassert(RB); // SQ <- B (see CPM-C for related assertions)
}}break;
default: ;}
}
void CPM::controlPulseMatrix(){
// Combination logic decodes time pulse, subsequence, branch register, and// "select next instruction" latch to get control pulses associated with // those states.
// Get rid of any old control pulses.clearControlPulses();
//*******************************************************************************// SUBSYSTEM A
int SB2_field = 0;int SB1_field = 0;
switch(CTR::getSubseq()){case PINCSEL:
SB2_field = 0;SB1_field = 1;break;
case MINCSEL:SB2_field = 1;SB1_field = 0;break;
default:
SB2_field = 0;SB1_field = 0;
};
int CPM_A_address = 0;CPM_A_address =
(SB2_field << 13) | (SB1_field << 12) |(SEQ::register_SQ.read() << 8) | (SEQ::register_STB.read() << 6) | (TPG::register_SG.read() << 2) | (SEQ::register_BR1.read() << 1) | SEQ::register_BR2.read();
// Construct address into CPM-A control pulse ROM:// Address bits (bit 1 is LSB)// 1: register BR2// 2: register BR1// 3-6: register SG (4)// 7,8: register STB (2)// 9-12: register SQ (4)// 13: STB_01 (from CTR: selects PINC, MINC, or none)// 14: STB_02 (from CTR: selects PINC, MINC, or none)
get_CPM_A(CPM_A_address);
//*******************************************************************************
//*******************************************************************************// SUBSYSTEM B
// NOTE: WG, RSC, WSC are generated by SUBSYSTEM A. Those 3 signals are only used// by SUBSYSTEM B; not anywhere else.
// CONSIDER MOVING TO ADR **********************8
if(SEQ::isAsserted(WG)){
switch(ADR::register_S.read()){case 020: assert(W20); break;case 021: assert(W21); break;case 022: assert(W22); break;case 023: assert(W23); break;default: if(ADR::GTR_17()) assert(WGn); // not a central register}
}if(SEQ::isAsserted(RSC)){
switch(ADR::register_S.read()){case 00: assert(RA0); break;case 01: assert(RA1); break;case 02: assert(RA2); break;case 03: assert(RA3); break;case 04: assert(RA4); break;case 05: assert(RA5); break;case 06: assert(RA6); break;case 07: assert(RA7); break;case 010: assert(RA10); break;case 011: assert(RA11); break;case 012: assert(RA12); break;case 013: assert(RA13); break;case 014: assert(RA14); break;case 015: assert(RBK); break;default: break; // 016, 017}
}if(SEQ::isAsserted(WSC))
switch(ADR::register_S.read()){case 00: assert(WA0); break;
case 01: assert(WA1); break;case 02: assert(WA2); break;case 03: assert(WA3); break;case 010: assert(WA10); break;case 011: assert(WA11); break;case 012: assert(WA12); break;case 013: assert(WA13); break;case 014: assert(WA14); break;case 015: assert(WBK); break;default: break; // 016, 017}
//*******************************************************************************
//*******************************************************************************// SUBSYSTEM C
switch(TPG::register_SG.read()){
case STBY:assert(GENRST);// inhibit all alarms// init "SQ" complex// clear branch registers// stage registers are not cleared; should they be?
// zeroes are already gated onto bus when no read pulses are asserted.// to zero synchronous-clocked registers, assert write pulses here.// Level-triggered registers are zeroed by GENRST anded with CLK2.break;
case PWRON:assert(R2000);//assert(WB); // TC GOPROG copied to B (implemented in CPM-A)break;
case TP1:// Moved this from TP12 to TP1 because CLISQ was getting cleared in the// hardware AGC before TPG was clocked; therefore TPG was not seeing the// SNI indication.
assert(CLISQ); // SNI <- 0
case TP5:// EMEM must be available in G register by TP6if( ADR::GTR_17() && // not a central register
!ADR::GTR_1777() && // not fixed memory!SEQ::isAsserted(SDV1) && // not a loop counter subseq!SEQ::isAsserted(SMP1))
{assert(SBWG);
}if( ADR::EQU_17() ) assert (INH); // INHINT (INDEX 017)if( ADR::EQU_16() ) assert (CLINH); // RELINT (INDEX 016)break;
case TP6:// FMEM must be available in G register by TP7if( ADR::GTR_1777() && // not eraseable
memory!SEQ::isAsserted(SDV1) && // not a loop counter subseq!SEQ::isAsserted(SMP1))
{assert(SBWG);
}break;
case TP11:// G register written to memory beginning at TP11; Memory updates are in// G by TP10 for all normal and extracode instructions, but the PINC, MINC,
// and SHINC sequences write to G in TP10 because they need to update the// parity bit.if( ADR::GTR_17() && // not a central register
!ADR::GTR_1777() && // not fixed memory!SEQ::isAsserted(SDV1) && // not a loop counter subseq!SEQ::isAsserted(SMP1))
{assert(WE);
}// Additional interrupts are inhibited during servicing of an interrupt;// Remove the inhibition when RESUME is executed (INDEX 025)if(SEQ::isAsserted(SRSM3)) assert(CLRP);break;
case TP12:// DISABLE INPUT CHANGE TO PRIORITY COUNTER (reenable after TP1)// Check the priority counters; service any waiting inputs on the next// memory cycle.assert(WPCTR);if(SEQ::register_SNI.read() == 1) // if SNI is set, get next instruction{
if(INT::IRQ()) // if interrupt requested (see CPM-A for similar assertion){
// Interrupt: SQ <- 0 (the default RW bus state)assert(RPT); // latch interrupt vectorassert(SETSTB); // STB <- 1
}else{
// Normal instruction//assert(RB); // SQ <- B (implemented in CPM-A)assert(CLSTB); // STB <- 0
}assert(WSQ);assert(CLSTA); // STA <- 0
// Remove inhibition of interrupts (if they were) AFTER the nextinstruction
assert(CLINH1); // INHINT1 <- 0}else if(CTR::getSubseq() == NOPSEL) // if previous sequence was not a counter{
// get next sequence for same instruction.assert(WSTB); // STB <- STAassert(CLSTA); // STA <- 0
}//assert(CLISQ); // SNI <- 0 (moved to TP1)
break;
default: ;}//*******************************************************************************
}
CRG (CRG.h)
/**************************************************************************** * CRG - ADDRESSABLE CENTRAL REGISTER subsystem * * AUTHOR: John Pultorak * DATE: 9/22/01 * FILE: CRG.h * * VERSIONS: * * DESCRIPTION: * Addressable Central Registers for the Block 1 Apollo Guidance Computer * prototype (AGC4). * * SOURCES: * Mostly based on information from "Logical Description for the Apollo * Guidance Computer (AGC4)", Albert Hopkins, Ramon Alonso, and Hugh * Blair-Smith, R-393, MIT Instrumentation Laboratory, 1963. * * NOTES: * ***************************************************************************** */#ifndef CRG_H#define CRG_H
#include "reg.h"
class regQ : public reg { public:
regQ() : reg(16, "%06o") { }};
class regZ : public reg { public:
regZ() : reg(16, "%06o") { }};
class regLP : public reg { public:
regLP() : reg(16, "%06o") { }};
class regA : public reg { public:
regA() : reg(16, "%06o") { }};
class CRG{public:
static void execWP_GENRST();
static void execRP_RQ();static void execRP_RA1();static void execWP_WQ();static void execWP_WA1();static void execRP_RZ();static void execRP_RA2();static void execWP_WZ();static void execWP_WA2();static void execRP_RLP();static void execRP_RA3();static void execRP_RA();static void execRP_RA0();static void execWP_WA();static void execWP_WA0();static void execWP_WALP();
static void execWP_WLP();static void execWP_WA3();
static regQ register_Q; // return addressstatic regZ register_Z; // program counterstatic regLP register_LP; // lower accumulatorstatic regA register_A; // accumulator
static unsigned conv_WALP_LP[];static unsigned conv_WALP_A[];static unsigned conv_WLP[];
};
#endif
CRG (CRG.cpp)
/**************************************************************************** * CRG - ADDRESSABLE CENTRAL REGISTER subsystem * * AUTHOR: John Pultorak * DATE: 9/22/01 * FILE: CRG.cpp * * NOTES: see header file. * ***************************************************************************** */#include "CRG.h"#include "SEQ.h"#include "BUS.h"
regQ CRG::register_Q; // return addressregZ CRG::register_Z; // program counterregLP CRG::register_LP; // lower accumulatorregA CRG::register_A; // accumulator
// BUS LINE ASSIGNMENTS// Specify the assignment of bus lines to the inputs of a register (for a 'write'// operation into a register). Each 'conv_' array specifies the inputs into a// single register. The index into the array corresponds to the bit position in// the register, where the first parameter (index=0) is bit 16 of the register (msb)// and the last parameter (index=15) is register bit 1 (lsb). The value of// the parameter identifies the bus line assigned to that register bit. 'BX'// means 'don't care'; i.e.: leave that register bit alone.
unsigned CRG::conv_WALP_LP[] ={ BX, BX, B1, BX, BX, BX, BX, BX, BX, BX, BX, BX, BX, BX, BX, BX };
unsigned CRG::conv_WALP_A[] ={ SG, SG, US, B14, B13, B12, B11, B10, B9, B8, B7, B6, B5, B4, B3, B2 };
unsigned CRG::conv_WLP[] ={ B1, B1, D0, B14, B13, B12, B11, B10, B9, B8, B7, B6, B5, B4, B3, B2 };
void CRG::execWP_GENRST(){
register_Q.write(0);register_Z.write(0);register_LP.write(0);register_A.write(0);
}
void CRG::execRP_RQ(){
BUS::glbl_READ_BUS = register_Q.read();}void CRG::execRP_RA1(){
BUS::glbl_READ_BUS = register_Q.read();}
void CRG::execWP_WQ(){
register_Q.write(BUS::glbl_WRITE_BUS);}
void CRG::execWP_WA1(){
register_Q.write(BUS::glbl_WRITE_BUS);
}
void CRG::execRP_RZ(){
BUS::glbl_READ_BUS = register_Z.read();}
void CRG::execRP_RA2(){
BUS::glbl_READ_BUS = register_Z.read();}
void CRG::execWP_WZ(){
register_Z.write(BUS::glbl_WRITE_BUS);}
void CRG::execWP_WA2(){
register_Z.write(BUS::glbl_WRITE_BUS);}
void CRG::execRP_RLP(){
BUS::glbl_READ_BUS = register_LP.read();}
void CRG::execRP_RA3(){
BUS::glbl_READ_BUS = register_LP.read();}
void CRG::execWP_WALP(){
register_LP.writeShift(BUS::glbl_WRITE_BUS, CRG::conv_WALP_LP);register_A.writeShift(BUS::glbl_WRITE_BUS, CRG::conv_WALP_A);
}void CRG::execWP_WLP(){
register_LP.writeShift(BUS::glbl_WRITE_BUS, CRG::conv_WLP);}
void CRG::execWP_WA3(){
register_LP.writeShift(BUS::glbl_WRITE_BUS, CRG::conv_WLP);}
void CRG::execRP_RA(){
BUS::glbl_READ_BUS = register_A.read();}
void CRG::execRP_RA0(){
BUS::glbl_READ_BUS = register_A.read();}
void CRG::execWP_WA(){
register_A.write(BUS::glbl_WRITE_BUS);}
void CRG::execWP_WA0(){
register_A.write(BUS::glbl_WRITE_BUS);
}
CTR (CTR.h)
/**************************************************************************** * CTR - INVOLUNTARY PRIORITY COUNTER subsystem * * AUTHOR: John Pultorak * DATE: 10/25/02 * FILE: CTR.h * * VERSIONS: * * DESCRIPTION: * Involuntary Counters for the Block 1 Apollo Guidance Computer prototype (AGC4). * * SOURCES: * Mostly based on information from "Logical Description for the Apollo * Guidance Computer (AGC4)", Albert Hopkins, Ramon Alonso, and Hugh * Blair-Smith, R-393, MIT Instrumentation Laboratory, 1963. * * NOTES: * ***************************************************************************** */#ifndef CTR_H#define CTR_H
#include "reg.h"
enum ctrNumber { // indexes for priority cellsOVCTR =0,
TIME2 =1, // Block II puts TIME2 firstTIME1 =2,TIME3 =3,TIME4 =4,
};
enum ctrAddr { // octal addresses of counters// Note: In Block 1, TIME1 preceeds TIME2. In Block II,// this is reversed: TIME2 preceeds TIME1. This reversal// was done so that the most significant time word occurs// at the lower address in the 2 word AGC clock. Therefore,// a common AGC software routine can be used to read the// time.
OVCTR_ADDR =0034,
TIME2_ADDR =0035, // Block II puts TIME2 firstTIME1_ADDR =0036,TIME3_ADDR =0037,TIME4_ADDR =0040,
SPARE1_ADDR =0041,
SPARE2_ADDR =0042,SPARE3_ADDR =0043
};
enum pCntrType {NOPSEL =0, // NO COUNTERPINCSEL =1, // PINCMINCSEL =2 // MINC
};
class regUpCELL : public reg { public:
// Bit synchronize the counter inputs.regUpCELL() : reg(8, "%03o") { }
};
class regDnCELL : public reg { public:
// Bit synchronize the counter inputs.regDnCELL() : reg(8, "%03o") { }
};
class CTR{public:
static void execWP_GENRST();static void execWP_WPCTR();static void execRP_RSCT();static void execWP_WOVR();static void execWP_WOVC();
static unsigned getSubseq();
static unsigned pcUp[];static unsigned pcDn[];
static regUpCELL register_UpCELL; // latches the selected priority counter cell (0-7)static regDnCELL register_DnCELL; // latches the selected priority counter cell (0-7)
private:static void resetAllpc();
};
#endif
CTR (CTR.cpp)
/**************************************************************************** * CTR - INVOLUNTARY PRIORITY COUNTER subsystem * * AUTHOR: John Pultorak * DATE: 10/25/02 * FILE: CTR.cpp * * NOTES: see header file. * ***************************************************************************** */#include "CTR.h"#include "INT.h"#include "BUS.h"#include "SEQ.h"
regUpCELL CTR::register_UpCELL; // latches the selected priority counter cell (0-7 (decimal))regDnCELL CTR::register_DnCELL; // latches the selected priority counter cell (0-7 (decimal))
unsigned CTR::pcUp[8];unsigned CTR::pcDn[8];
// PRIORITY COUNTERS
// ****************************************************// The interrupt priorities are stored in RPCELL as 1-5, but// the priority counter priorities are stored as 0-7; this// inconsistency should be fixed, probably. Also, the method// of address determination for the priority counters needs work
void CTR::resetAllpc(){
for(int i=0; i<8; i++) { pcUp[i]=0; pcDn[i]=0; }}
// priority encoder; outputs 0-7; 0=highest priority (OVCTR), 1=TIME2, 2=TIME1, etcstatic bool newPriority = true; // a simulator performance optimization; not in the hardware AGCunsigned getPriority(){
// simulator optimization; don't recompute priority if the priority inputs haven'tchanged
static unsigned priority = 7; // default (lowest priority)if(!newPriority) return priority;
priority = 7; // default (lowest priority)for(int i=0; i<8; i++) {
if(CTR::register_UpCELL.readField(i+1,i+1) |CTR::register_DnCELL.readField(i+1,i+1))
{priority = i;break;
}}newPriority = false;return priority;
}
unsigned CTR::getSubseq(){
unsigned pc = getPriority();
unsigned upCell = CTR::register_UpCELL.readField(pc+1,pc+1);unsigned dnCell = CTR::register_DnCELL.readField(pc+1,pc+1);
if(upCell == 1 && dnCell == 0)return PINCSEL;
else if(upCell == 0 && dnCell == 1) return MINCSEL;
else return NOPSEL;
}
void CTR::execWP_GENRST(){
register_UpCELL.write(0);register_DnCELL.write(0);
resetAllpc();}
void CTR::execWP_WPCTR(){
// transfer cell data into up and down synch registers
for(int i=0; i<8; i++) {
register_UpCELL.writeField(i+1,i+1,pcUp[i]);register_DnCELL.writeField(i+1,i+1,pcDn[i]);
}newPriority=true; // a simulator performance optimization; not in hardware AGC
}
// Selected counter address is requested at TP1.// Counter address is latched at TP12
void CTR::execRP_RSCT(){
BUS::glbl_READ_BUS = 034 + getPriority();}
void CTR::execWP_WOVR(){
unsigned pc = getPriority();if(register_UpCELL.readField(pc+1,pc+1)){
pcUp[pc]=0;}if(register_DnCELL.readField(pc+1,pc+1)){
pcDn[pc]=0;}
// generate various actions in response to counter overflows:switch(BUS::testOverflow(BUS::glbl_WRITE_BUS)){
case POS_OVF: // positive overflowswitch(getPriority()) // get the counter{case TIME1: CTR::pcUp[TIME2]=1; break; // overflow from TIME1 increments
TIME2case TIME3: INT::rupt[T3RUPT]=1; break; // overflow from TIME3 triggers
T3RUPTcase TIME4: INT::rupt[DSRUPT]=1; break; // overflow from TIME4 triggers
DSRUPT}break;
case NEG_OVF: break; // no actions for negative counter overflow}
}
void CTR::execWP_WOVC(){
switch(BUS::testOverflow(BUS::glbl_WRITE_BUS)){
case POS_OVF: CTR::pcUp[OVCTR]=1; break; // incr OVCTR (034)case NEG_OVF: CTR::pcDn[OVCTR]=1; break; // decr OVCTR (034)
}
}
// register_PCELL: Overflow from the selected counter appears// on the bus when WOVR or WOVC is asserted;// it could be used to trigger an interrupt// or routed to increment another counter
DSP (DSP.h)
/**************************************************************************** * DSP - DSKY DISPLAY subsystem * * AUTHOR: John Pultorak * DATE: 9/22/01 * FILE: DSP.h * * VERSIONS: * * DESCRIPTION: * DSKY Display for the Block 1 Apollo Guidance Computer prototype (AGC4). * * SOURCES: * Mostly based on information from "Logical Description for the Apollo * Guidance Computer (AGC4)", Albert Hopkins, Ramon Alonso, and Hugh * Blair-Smith, R-393, MIT Instrumentation Laboratory, 1963. * * NOTES: * ***************************************************************************** */#ifndef DSP_H#define DSP_H
class DSP{public:
// DSKY display
// major mode displaystatic char MD1;static char MD2;
// verb displaystatic char VD1;static char VD2;
// noun displaystatic char ND1;static char ND2;
// R1static char R1S;static char R1D1;static char R1D2;static char R1D3;static char R1D4;static char R1D5;
// R2static char R2S;static char R2D1;static char R2D2;static char R2D3;static char R2D4;static char R2D5;
// R3static char R3S;static char R3D1;static char R3D2;static char R3D3;static char R3D4;static char R3D5;
// These flags control the sign; if both bits are 0 or 1, there is no sign.// Otherwise, the sign is set by the selected bit.
static unsigned R1SP;static unsigned R1SM;static unsigned R2SP;static unsigned R2SM;static unsigned R3SP;static unsigned R3SM;
// verb/noun flashstatic unsigned flash;
static void clearOut0();
static char signConv(unsigned p, unsigned m);
static char outConv(unsigned in);
static void decodeRelayWord(unsigned in);};
#endif
DSP (DSP.cpp)
/**************************************************************************** * DSP - DSKY DISPLAY subsystem * * AUTHOR: John Pultorak * DATE: 9/22/01 * FILE: DSP.cpp * * NOTES: see header file. * ***************************************************************************** */#include "DSP.h"#include <string.h>#include <iostream.h>#include <stdio.h>
bool dskyChanged = false; // true when DSKY display changes
// major mode displaychar DSP::MD1=0;char DSP::MD2=0;
// verb displaychar DSP::VD1=0;char DSP::VD2=0;
// noun displaychar DSP::ND1=0;char DSP::ND2=0;
// R1char DSP::R1S=0;char DSP::R1D1=0;char DSP::R1D2=0;char DSP::R1D3=0;char DSP::R1D4=0;char DSP::R1D5=0;
// R2char DSP::R2S=0;char DSP::R2D1=0;char DSP::R2D2=0;char DSP::R2D3=0;char DSP::R2D4=0;char DSP::R2D5=0;
// R3char DSP::R3S=0;char DSP::R3D1=0;char DSP::R3D2=0;char DSP::R3D3=0;char DSP::R3D4=0;char DSP::R3D5=0;
// These flags control the sign; if both bits are 0 or 1, there is no sign.// Otherwise, the sign is set by the selected bit.
unsigned DSP::R1SP=0;unsigned DSP::R1SM=0;unsigned DSP::R2SP=0;unsigned DSP::R2SM=0;unsigned DSP::R3SP=0;unsigned DSP::R3SM=0;
// flag controls 1 Hz flash of verb and noun displayunsigned DSP::flash = 0; // 0=flash off, 1=flash on
void DSP::clearOut0(){
MD1 = MD2 = ' '; // major mode displayVD1 = VD2 = ' '; // verb display
ND1 = ND2 = ' '; // noun displayR1S = R1D1 = R1D2 = R1D3 = R1D4 = R1D5 = ' '; // R1R2S = R2D1 = R2D2 = R2D3 = R2D4 = R2D5 = ' '; // R2R3S = R3D1 = R3D2 = R3D3 = R3D4 = R3D5 = ' '; // R3
R1SP = R1SM = 0;R2SP = R2SM = 0;R3SP = R3SM = 0;
}
char DSP::signConv(unsigned p, unsigned m){
if(p && !m)return '+';
else if(m && !p)return '-';
elsereturn ' ';
}
char DSP::outConv(unsigned in){
switch(in){case 000: return ' ';case 025: return '0';case 003: return '1';case 031: return '2';case 033: return '3';case 017: return '4';case 036: return '5';case 034: return '6';case 023: return '7';case 035: return '8';case 037: return '9';}return ' '; // error
}
void DSP::decodeRelayWord(unsigned in){
unsigned charSelect = (in & 074000) >> 11; // get bits 15-12unsigned b11 = (in & 02000) >> 10; // get bit 11unsigned bHigh = (in & 01740) >> 5; // get bits 10-6unsigned bLow = in & 037;
//******************************#ifdef NOTDEF
char buf[80]; sprintf(buf, "bits15-12: %02o, Bit11: %01o, bits10-6: %02o, bits5-1: %02o",
charSelect, b11, bHigh, bLow);cout << buf << endl;
#endifdskyChanged = true;//******************************
switch(charSelect){case 013: MD1 = outConv(bHigh); MD2 = outConv(bLow); break;case 012: VD1 = outConv(bHigh); VD2 = outConv(bLow); flash = b11; break;case 011: ND1 = outConv(bHigh); ND2 = outConv(bLow); break;case 010: R1D1 = outConv(bLow); break;// UPACT not implemented
case 007: R1SP = b11; R1S = signConv(R1SP, R1SM);R1D2 = outConv(bHigh);R1D3 = outConv(bLow); break;
case 006: R1SM = b11; R1S = signConv(R1SP, R1SM);R1D4 = outConv(bHigh);R1D5 = outConv(bLow); break;
case 005: R2SP = b11; R2S = signConv(R2SP, R2SM);R2D1 = outConv(bHigh);R2D2 = outConv(bLow); break;
case 004: R2SM = b11; R2S = signConv(R2SP, R2SM);R2D3 = outConv(bHigh);R2D4 = outConv(bLow); break;
case 003: R2D5 = outConv(bHigh);R3D1 = outConv(bLow); break;
case 002: R3SP = b11; R3S = signConv(R3SP, R3SM);R3D2 = outConv(bHigh);R3D3 = outConv(bLow); break;
case 001: R3SM = b11; R3S = signConv(R3SP, R3SM);R3D4 = outConv(bHigh);R3D5 = outConv(bLow); break;
}}
INP (INP.h)
/**************************************************************************** * INP - INPUT REGISTER subsystem * * AUTHOR: John Pultorak * DATE: 9/22/01 * FILE: INP.h * * VERSIONS: * * DESCRIPTION: * Input Registers for the Block 1 Apollo Guidance Computer prototype (AGC4). * * SOURCES: * Mostly based on information from "Logical Description for the Apollo * Guidance Computer (AGC4)", Albert Hopkins, Ramon Alonso, and Hugh * Blair-Smith, R-393, MIT Instrumentation Laboratory, 1963. * * NOTES: * ***************************************************************************** */#ifndef INP_H#define INP_H
#include "reg.h"
class regIn0 : public reg { public:
regIn0() : reg(16, "%06o") { }};
class regIn1 : public reg { public:
regIn1() : reg(16, "%06o") { }};
class regIn2 : public reg { public:
regIn2() : reg(16, "%06o") { }};
class regIn3 : public reg { public:
regIn3() : reg(16, "%06o") { }};
class INP{public:
static void execRP_RA4();static void execRP_RA5();static void execRP_RA6();static void execRP_RA7();static regIn0 register_IN0; // input register 0static regIn1 register_IN1; // input register 1static regIn2 register_IN2; // input register 2static regIn3 register_IN3; // input register 3
};
#endif
INP (INP.cpp)
/**************************************************************************** * INP - INPUT REGISTER subsystem * * AUTHOR: John Pultorak * DATE: 9/22/01 * FILE: INP.cpp * * NOTES: see header file. * ***************************************************************************** */#include "INP.h"#include "SEQ.h"#include "KBD.h"#include "MON.h"#include "BUS.h"
regIn0 INP::register_IN0; // input register 0regIn1 INP::register_IN1; // input register 1regIn2 INP::register_IN2; // input register 2regIn3 INP::register_IN3; // input register 3
void INP::execRP_RA4(){
// Sample the state of the inputs at the moment the// read pulse is asserted. In the H/W implementation,// register 0 is a buffer, not a latch.
register_IN0.writeField(5,1,KBD::kbd);register_IN0.writeField(6,6,0); // actually should be keypressed stroberegister_IN0.writeField(14,14,MON::SA);register_IN0.clk();BUS::glbl_READ_BUS = register_IN0.read();
}
void INP::execRP_RA5(){
BUS::glbl_READ_BUS = register_IN1.read();}
void INP::execRP_RA6(){
BUS::glbl_READ_BUS = register_IN2.read();}
void INP::execRP_RA7(){
BUS::glbl_READ_BUS = register_IN3.read();}
INT (INT.h)
/**************************************************************************** * INT - PRIORITY INTERRUPT subsystem * * AUTHOR: John Pultorak * DATE: 9/22/01 * FILE: INT.h * * VERSIONS: * * DESCRIPTION: * Priority Interrupts for the Block 1 Apollo Guidance Computer prototype (AGC4). * * SOURCES: * Mostly based on information from "Logical Description for the Apollo * Guidance Computer (AGC4)", Albert Hopkins, Ramon Alonso, and Hugh * Blair-Smith, R-393, MIT Instrumentation Laboratory, 1963. * * NOTES: * ***************************************************************************** */#ifndef INT_H#define INT_H
#include "reg.h"
enum ruptAddress {// Addresses for service routines of vectored interrupts
T3RUPT_ADDR =02004, // option 1: overflow of TIME 3ERRUPT_ADDR =02010, // option 2: error signalDSRUPT_ADDR =02014, // option 3: telemetry end pulse or TIME 4 overflowKEYRUPT_ADDR =02020, // option 4: activity from MARK, keyboard, or tape reader
};
enum ruptNumber {// Option number (selects rupt priority cell)// NOTE: the priority cells (rupt[]) are indexed 0-4, but stored in the // RPCELL register as 1-5; (0 in RPCELL means no interrupt)
T3RUPT =0, // option 1: overflow of TIME 3ERRUPT =1, // option 2: error signalDSRUPT =2, // option 3: telemetry end pulse or TIME 4 overflowKEYRUPT =3, // option 4: activity from MARK, keyboard, or tape reader
};
class regRPCELL : public reg { public:
regRPCELL() : reg(5, "%02o") { }};// also inhibits additional interrupts while an interrupt is being processed
class regINHINT1 : public reg { public:
regINHINT1() : reg(1, "%01o") { }};
class regINHINT : public reg { public:
regINHINT() : reg(1, "%01o") { }};
class INT{public:
friend class CLK;friend class MON;
static void execRP_RRPA();
static void execWP_GENRST();static void execWP_RPT();static void execWP_KRPT();static void execWP_CLRP();static void execWP_WOVI();static void execWP_CLINH1();static void execWP_INH();static void execWP_CLINH();
static bool IRQ(); // returns true if an interrupt is requested
static unsigned rupt[];
private:static void resetAllRupt();static unsigned getPriorityRupt();
static regRPCELL register_RPCELL; // latches the selected priority interrupt vector (1-5)static regINHINT1 register_INHINT1; // inhibits interrupts for 1 instruction (on WOVI)static regINHINT register_INHINT; // inhibits interrupts on INHINT, reenables on RELINT
};
#endif
INT (INT.cpp)
/**************************************************************************** * INT - PRIORITY INTERRUPT subsystem * * AUTHOR: John Pultorak * DATE: 9/22/01 * FILE: INT.cpp * * NOTES: see header file. * ***************************************************************************** */#include "INT.h"#include "SEQ.h"#include "BUS.h"
regRPCELL INT::register_RPCELL; // latches the selected priority interrupt vector (1-5)regINHINT1 INT::register_INHINT1; // inhibits interrupts for 1 instruction (on WOVI)regINHINT INT::register_INHINT; // inhibits interrupts on INHINT, reenables on RELINT
// NOTE: the priority cells (rupt[]) are indexed 0-4, but stored in the // RPCELL register as 1-5; (0 in RPCELL means no interrupt)unsigned INT::rupt[5];
bool INT::IRQ(){
if( INT::getPriorityRupt() // if interruptrequested
&& INT::register_RPCELL.read() == 0 // and interrupt not currently beingserviced
&& INT::register_INHINT1.read() == 0 // and interrupt not inhibited for 1instruction
&& INT::register_INHINT.read() == 0) // and interrupts enabled (RELINT){
return true;}return false;
}
void INT::resetAllRupt(){
for(int i=0; i<5; i++) { rupt[i]=0; }}
// interrupt vector; outputs 1-5 (decimal) == vector; 0 == no interruptunsigned INT::getPriorityRupt(){
for(int i=0; i<5; i++) { if(rupt[i]) return i+1; }return 0;
}
void INT::execRP_RRPA(){
BUS::glbl_READ_BUS = 02000 + (register_RPCELL.read() << 2);}
// latches the selected priority interrupt vector (1-5)// also inhibits additional interrupts while an interrupt is being processed
void INT::execWP_GENRST(){
register_RPCELL.write(0);register_INHINT.write(1);resetAllRupt();
}
void INT::execWP_RPT(){
register_RPCELL.write(INT::getPriorityRupt());}
void INT::execWP_KRPT(){
INT::rupt[register_RPCELL.read()-1] = 0;}
void INT::execWP_CLRP(){
register_RPCELL.write(0);}
// INHINT1: inhibits interrupts for 1 instruction (on WOVI)
void INT::execWP_WOVI(){
if(BUS::testOverflow(BUS::glbl_WRITE_BUS) != NO_OVF) register_INHINT1.write(1);
}
void INT::execWP_CLINH1(){
register_INHINT1.write(0);}
// INHINT: inhibits interrupts on INHINT, reenables on RELINT
void INT::execWP_INH(){
register_INHINT.write(1);}
void INT::execWP_CLINH(){
register_INHINT.write(0);}
ISD (ISD.h)
/**************************************************************************** * ISD - INSTRUCTION SUBSEQUENCE DECODER subsystem * * AUTHOR: John Pultorak * DATE: 9/22/01 * FILE: ISD.h * * VERSIONS: * * DESCRIPTION: * Instruction Subsequence Decoder for the Block 1 Apollo Guidance Computer * prototype (AGC4). * * SOURCES: * Mostly based on information from "Logical Description for the Apollo * Guidance Computer (AGC4)", Albert Hopkins, Ramon Alonso, and Hugh * Blair-Smith, R-393, MIT Instrumentation Laboratory, 1963. * * NOTES: * ***************************************************************************** */#ifndef ISD_H#define ISD_H
#include "SEQ.h"#include "CTR.h"
// INSTRUCTION SUBSEQUENCE DECODER
#ifdef NOTDEFclass ISD{public:
static subseq instructionSubsequenceDecoder();
static char* ISD::subseqString[];};#endif
#endif
ISD (ISD.cpp)
/**************************************************************************** * ISD - INSTRUCTION SUBSEQUENCE DECODER subsystem * * AUTHOR: John Pultorak * DATE: 9/22/01 * FILE: ISD.cpp * * NOTES: see header file. * ***************************************************************************** */#include "ISD.h"
#ifdef NOTDEFchar* ISD::subseqString[] ={
"TC0","CCS0","CCS1","NDX0","NDX1","RSM3","XCH0","CS0","TS0","AD0","MASK0","MP0","MP1","MP3","DV0","DV1","SU0","RUPT1","RUPT3","STD2","PINC0","MINC0","SHINC0","NO_SEQ"
};
subseq ISD::instructionSubsequenceDecoder(){
// Combinational logic decodes instruction and the stage count // to get the instruction subsequence.
static subseq decode[16][4] = {{ TC0, RUPT1, STD2, RUPT3 }, // 00{ CCS0, CCS1, NO_SEQ, NO_SEQ }, // 01{ NDX0, NDX1, NO_SEQ, RSM3 }, // 02{ XCH0, NO_SEQ, STD2, NO_SEQ }, // 03
{ NO_SEQ, NO_SEQ, NO_SEQ, NO_SEQ }, // 04{ NO_SEQ, NO_SEQ, NO_SEQ, NO_SEQ }, // 05{ NO_SEQ, NO_SEQ, NO_SEQ, NO_SEQ }, // 06{ NO_SEQ, NO_SEQ, NO_SEQ, NO_SEQ }, // 07{ NO_SEQ, NO_SEQ, NO_SEQ, NO_SEQ }, // 10
{ MP0, MP1, NO_SEQ, MP3 }, // 11{ DV0, DV1, STD2, NO_SEQ }, // 12{ SU0, NO_SEQ, STD2, NO_SEQ }, // 13
{ CS0, NO_SEQ, STD2, NO_SEQ }, // 14{ TS0, NO_SEQ, STD2, NO_SEQ }, // 15{ AD0, NO_SEQ, STD2, NO_SEQ }, // 16{ MASK0, NO_SEQ, STD2, NO_SEQ } // 17
};
switch(CTR::getSubseq()){case PINCSEL: return PINC0;
case MINCSEL: return MINC0;default: return decode[SEQ::register_SQ.read()][SEQ::register_STB.read()];}
}
#endif
KBD (KBD.h)
/**************************************************************************** * KBD - DSKY KEYBOARD subsystem * * AUTHOR: John Pultorak * DATE: 9/22/01 * FILE: KBD.h * * VERSIONS: * * DESCRIPTION: * DSKY Keyboard for the Block 1 Apollo Guidance Computer prototype (AGC4). * * SOURCES: * Mostly based on information from "Logical Description for the Apollo * Guidance Computer (AGC4)", Albert Hopkins, Ramon Alonso, and Hugh * Blair-Smith, R-393, MIT Instrumentation Laboratory, 1963. * * NOTES: * ***************************************************************************** */#ifndef KBD_H#define KBD_H
enum keyInType {// DSKY keyboard input codes: Taken from E-1574, Appendix 1// These codes enter the computer through bits 1-5 of IN0.// The MSB is in bit 5; LSB in bit 1. Key entry generates KEYRUPT.KEYIN_NONE =0, // no key depressed**KEYIN_0 =020,KEYIN_1 =001,KEYIN_2 =002,KEYIN_3 =003,KEYIN_4 =004,KEYIN_5 =005,KEYIN_6 =006,KEYIN_7 =007,KEYIN_8 =010,KEYIN_9 =011,KEYIN_VERB =021,KEYIN_ERROR_RESET =022,KEYIN_KEY_RELEASE =031,KEYIN_PLUS =032,KEYIN_MINUS =033,KEYIN_ENTER =034,KEYIN_CLEAR =036,KEYIN_NOUN =037,
};
class KBD{public:
static keyInType kbd; // latches the last key entry from the DSKYstatic void keypress(keyInType c);
};
#endif
KBD (KBD.cpp)
/**************************************************************************** * KBD - DSKY KEYBOARD subsystem * * AUTHOR: John Pultorak * DATE: 9/22/01 * FILE: KBD.cpp * * NOTES: see header file. * ***************************************************************************** */#include "KBD.h"#include "INT.h"
// DSKY keyboardkeyInType KBD::kbd=KEYIN_NONE; // latches the last key entry from the DSKY
void KBD::keypress(keyInType c){
// latch the keycodekbd = c;
// generate KEYRUPT interruptINT::rupt[KEYRUPT] = 1;
}
MBF (MBF.h)
/**************************************************************************** * MBF - MEMORY BUFFER REGISTER subsystem * * AUTHOR: John Pultorak * DATE: 9/22/01 * FILE: MBF.h * * VERSIONS: * * DESCRIPTION: * Memory Buffer Register for the Block 1 Apollo Guidance Computer prototype (AGC4). * * SOURCES: * Mostly based on information from "Logical Description for the Apollo * Guidance Computer (AGC4)", Albert Hopkins, Ramon Alonso, and Hugh * Blair-Smith, R-393, MIT Instrumentation Laboratory, 1963. * * NOTES: * ***************************************************************************** */#ifndef MBF_H#define MBF_H
#include "reg.h"
class regG : public reg { public:
// all memory bits except bit 15 (parity)// bit 15 is not used, so ignore it.
regG() : reg(16, "%06o") { }};
class MBF{public:
static void execWP_GENRST();
static void execRP_RG();static void execRP_WE();
static void execWP_WGn();static void execWP_WGx();static void execWP_W20();static void execWP_W21();static void execWP_W22();static void execWP_W23();static void execWP_SBWG();
// Bit 15 (parity) is kept in a separate register in PAR// because it is independently loaded.
static regG register_G; // memory buffer register (except for bit 15)
static unsigned conv_RG[];static unsigned conv_WGn[];static unsigned conv_W20[];static unsigned conv_W21[];static unsigned conv_W22[];static unsigned conv_W23[];static unsigned conv_SBWG[];static unsigned conv_WE[];
};
#endif
MBF (MBF.cpp)
/**************************************************************************** * MBF - MEMORY BUFFER REGISTER subsystem * * AUTHOR: John Pultorak * DATE: 9/22/01 * FILE: MBF.cpp * * NOTES: see header file. * ***************************************************************************** */#include "MBF.h"#include "SEQ.h"#include "ADR.h"#include "BUS.h"#include "PAR.h"#include "MEM.h"
// The actual bit 15 of register_G is not used.regG MBF::register_G; // memory buffer register (except bit 15: parity)
unsigned MBF::conv_RG[] ={ SG, SG, B14, B13, B12, B11, B10, B9, B8, B7, B6, B5, B4, B3, B2, B1 };
unsigned MBF::conv_SBWG[] ={ SGM, BX, B14, B13, B12, B11, B10, B9, B8, B7, B6, B5, B4, B3, B2, B1 };
unsigned MBF::conv_WE[] ={ BX, SG, B14, B13, B12, B11, B10, B9, B8, B7, B6, B5, B4, B3, B2, B1 };
unsigned MBF::conv_W20[] ={ B1, BX, SG, B14, B13, B12, B11, B10, B9, B8, B7, B6, B5, B4, B3, B2 };
unsigned MBF::conv_W21[] ={ SG, BX, SG, B14, B13, B12, B11, B10, B9, B8, B7, B6, B5, B4, B3, B2 };
unsigned MBF::conv_W22[] ={ B14, BX, B13, B12, B11, B10, B9, B8, B7, B6, B5, B4, B3, B2, B1, SG };
unsigned MBF::conv_W23[] ={ SG, BX, B13, B12, B11, B10, B9, B8, B7, B6, B5, B4, B3, B2, B1, SG };
void MBF::execWP_GENRST(){
register_G.write(0);}
void MBF::execRP_RG(){
if(ADR::GTR_17()){
BUS::glbl_READ_BUS = register_G.shiftData(0, register_G.read(), MBF::conv_RG); }
}
void MBF::execRP_WE(){
// Write G into memory; shift the sign to bit 15; parity is written from the // PAR subsystem
MEM::MEM_DATA_BUS = (register_G.shiftData(0, MBF::register_G.read(), MBF::conv_WE));}
void MBF::execWP_WGn(){
register_G.write(BUS::glbl_WRITE_BUS);}
void MBF::execWP_WGx(){
// This is only used in PINC, MINC, and SHINC. Does not clear G// register; writes (ORs) into G from RWBus and writes into parity// from 1-15 generator. The sequence calls CLG in a previous TP to// reset G to zero, so the OR operation can be safely eliminated// from my implementation of the design.
register_G.write(BUS::glbl_WRITE_BUS);}
void MBF::execWP_W20(){
register_G.writeShift(BUS::glbl_WRITE_BUS, MBF::conv_W20);}
void MBF::execWP_W21(){
register_G.writeShift(BUS::glbl_WRITE_BUS, MBF::conv_W21);}
void MBF::execWP_W22(){
register_G.writeShift(BUS::glbl_WRITE_BUS, MBF::conv_W22);}
void MBF::execWP_W23(){
register_G.writeShift(BUS::glbl_WRITE_BUS, MBF::conv_W23);}
void MBF::execWP_SBWG(){
register_G.writeShift(MEM::MEM_DATA_BUS, MBF::conv_SBWG);
}
MEM (MEM.h)
/**************************************************************************** * MEM - ERASEABLE/FIXED MEMORY subsystem * * AUTHOR: John Pultorak * DATE: 9/26/02 * FILE: MEM.h * * VERSIONS: * * DESCRIPTION: * Eraseable & Fixed Memory for the Block 1 Apollo Guidance Computer * prototype (AGC4). * * SOURCES: * Mostly based on information from "Logical Description for the Apollo * Guidance Computer (AGC4)", Albert Hopkins, Ramon Alonso, and Hugh * Blair-Smith, R-393, MIT Instrumentation Laboratory, 1963. * * NOTES: * ***************************************************************************** */#ifndef MEM_H#define MEM_H
#include "reg.h"
#define NUMFBANK 12 // number of 1024 word fixed memory banks
class regEMEM : public reg { public:
regEMEM() : reg(16, "%06o") { }regEMEM& operator= (const unsigned& r) { write(r); return *this; }
};
class regFMEM : public reg { public:
regFMEM() : reg(16, "%06o") { }regFMEM& operator= (const unsigned& r) { write(r); return *this; }
};
class MEM{public:
static void execWP_WE();static void execRP_SBWG();
static regEMEM register_EMEM[]; // erasable memorystatic regFMEM register_FMEM[]; // fixed memory
static unsigned MEM_DATA_BUS; // data lines: memory bits 15-1static unsigned MEM_PARITY_BUS; // parity line: memory bit 16
static unsigned readMemory();static void writeMemory(unsigned data);
// The following functions are used in the simulator,// but are implemented in the AGC design.
static unsigned readMemory(unsigned address);static void writeMemory(unsigned address, unsigned data);
};
#endif
MEM (MEM.cpp)
/**************************************************************************** * MEM - ERASEABLE/FIXED MEMORY subsystem * * AUTHOR: John Pultorak * DATE: 9/26/02 * FILE: MEM.cpp * * NOTES: see header file. * ***************************************************************************** */#include "MEM.h"#include "ADR.h"#include "stdlib.h"
regEMEM MEM::register_EMEM[1024]; // erasable memoryregFMEM MEM::register_FMEM[1024*(NUMFBANK+1)]; // fixed memory (lowest 1024 words ignored)
unsigned MEM::MEM_DATA_BUS = 0; // data lines: memory bits 15-1unsigned MEM::MEM_PARITY_BUS = 0; // parity line: memory bit 16
void MEM::execWP_WE(){
// Write into memory; parity bit in bit 16writeMemory( (MEM_PARITY_BUS << 15) | MEM_DATA_BUS );
}
void MEM::execRP_SBWG(){
MEM_DATA_BUS = readMemory() & 0077777; // everything except parityMEM_PARITY_BUS = (readMemory() & 0100000) >> 15; // parity bit only
}
unsigned MEM::readMemory(){
// Return memory value addressed by lower 10 bits of the S register (1K) and the// bank decoder (which selects the 1K bank)
unsigned lowAddress = ADR::register_S.readField(10,1);
if(ADR::bankDecoder() == 0)return MEM::register_EMEM[lowAddress].read();
unsigned highAddress = ADR::bankDecoder() << 10;return MEM::register_FMEM[highAddress | lowAddress].read();
}
void MEM::writeMemory(unsigned data){
// Write into erasable memory addressed by lower 10 bits of the S register (1K) // and the bank decoder (which selects the 1K bank)
unsigned lowAddress = ADR::register_S.readField(10,1);if(ADR::bankDecoder() == 0){
MEM::register_EMEM[lowAddress].write(data);MEM::register_EMEM[lowAddress].clk(); // not a synchronous FF, so execute
immediately *************}
}
unsigned MEM::readMemory(unsigned address){
// Address is 14 bits. This function is used by the simulator for examining// memory; it is not part of the AGC design.
unsigned lowAddress = address & 01777;unsigned bank = (address & 036000) >> 10;
if(bank == 0)return MEM::register_EMEM[lowAddress].read();
unsigned highAddress = bank << 10;return MEM::register_FMEM[highAddress | lowAddress].read();
}
void MEM::writeMemory(unsigned address, unsigned data){
// Address is 14 bits. This function is used by the simulator for depositing into// memory; it is not part of the AGC design. This function is also used to// initialize fixed memory.
//************************************************************// This function could also write the parity into memory//************************************************************unsigned lowAddress = address & 01777;unsigned bank = (address & 036000) >> 10;
if(bank == 0){
if(lowAddress > 1024) {
cout << "Error: Eraseable address=" << lowAddress << endl; exit(0);
}MEM::register_EMEM[lowAddress].write(data);MEM::register_EMEM[lowAddress].clk(); // execute immediately
}else{
unsigned highAddress = bank << 10;if((highAddress | lowAddress) >= 1024*(NUMFBANK+1)) {
cout << "Error: Fixed address=" << (highAddress | lowAddress) << endl; exit(0);
}
MEM::register_FMEM[highAddress | lowAddress].write(data);MEM::register_FMEM[highAddress | lowAddress].clk(); // execute immediately
}}
MON (MON.h)
/**************************************************************************** * MON - AGC MONITOR subsystem * * AUTHOR: John Pultorak * DATE: 9/22/01 * FILE: MON.h * * VERSIONS: * * DESCRIPTION: * AGC Monitor for the Block 1 Apollo Guidance Computer prototype (AGC4). * * SOURCES: * Mostly based on information from "Logical Description for the Apollo * Guidance Computer (AGC4)", Albert Hopkins, Ramon Alonso, and Hugh * Blair-Smith, R-393, MIT Instrumentation Laboratory, 1963. * * NOTES: * ***************************************************************************** */#ifndef MON_H#define MON_H
class MON{public:
static void displayAGC();
static char* MON::clkTypestring[];
static unsigned PURST; // power up resetstatic unsigned RUN; // run/halt switchstatic unsigned STEP; // single step switchstatic unsigned INST; // instruction/sequence step select switchstatic unsigned FCLK; // clock mode (0=single (manual) clock, 1=continuous clock)
static unsigned SA; // "standby allowed" SW; // 0=NO (full power), 1=YES (low power)
static unsigned SCL_ENAB; // "scaler enabled" SW; 0=NO (scaler halted), 1=YES(scaler running)
};
#endif
MON (MON.cpp)
/**************************************************************************** * MON - AGC MONITOR subsystem * * AUTHOR: John Pultorak * DATE: 9/22/01 * FILE: MON.cpp * * NOTES: see header file. * ***************************************************************************** */#include "MON.h"
#include "TPG.h"#include "MON.h"#include "SCL.h"#include "SEQ.h"#include "INP.h"#include "OUT.h"#include "BUS.h"#include "DSP.h"#include "ADR.h"#include "PAR.h"#include "MBF.h"#include "MEM.h"#include "CTR.h"#include "INT.h"#include "KBD.h"#include "CRG.h"#include "ALU.h"#include "CPM.h"#include "ISD.h"#include "CLK.h"
unsigned MON::PURST=1; // power up reset; initially high at startupunsigned MON::RUN=0; // run/halt switchunsigned MON::STEP=0; // single step switchunsigned MON::INST=1; // instruction/sequence step select switchunsigned MON::FCLK=0; // clock mode
unsigned MON::SA=0; // "standby allowed" SW; 0=NO (full power), 1=YES (low power)
unsigned MON::SCL_ENAB=1; // "scaler enabled" SW; 0=NO (scaler halted), 1=YES (scalerrunning)
void MON::displayAGC(){
char buf[100];cout << "AGC4 SIMULATOR 1.16 -------------------------------" << endl;sprintf(buf," TP: %-5s F17:%1d F13:%1d F10:%1d SCL:%06o",
TPG::tpTypestring[TPG::register_SG.read()], SCL::register_F17.read(), SCL::register_F13.read(), SCL::register_F10.read(),SCL::register_SCL.read());
cout << buf << endl;
sprintf(buf, " STA:%01o STB:%01o BR1:%01o BR2:%01o SNI:%01o CI:%01o LOOPCTR:%01o",
SEQ::register_STA.read(), SEQ::register_STB.read(), SEQ::register_BR1.read(), SEQ::register_BR2.read(),SEQ::register_SNI.read(), ALU::register_CI.read(), SEQ::register_LOOPCTR.read());
cout << buf << endl;
sprintf(buf, " RPCELL:%05o INH1:%01o INH:%01o UpCELL:%03o DnCELL:%03o SQ:%02o %-6s %-6s",
INT::register_RPCELL.read(), INT::register_INHINT1.read(),INT::register_INHINT.read(),
CTR::register_UpCELL.read(), CTR::register_DnCELL.read(),SEQ::register_SQ.read(), SEQ::instructionString[SEQ::register_SQ.read()], CPM::subseqString[SEQ::glbl_subseq]);
cout << buf << endl;
sprintf(buf, " CP:%s", SEQ::getControlPulses());cout << buf << endl;
// For the G register, bit 15 comes from register G15; the other bits (16, 14-1)come
// from register G.sprintf(buf, " S: %04o G:%06o P:%06o (r)RUN :%1d (p)PURST:%1d
(F2,F4)FCLK:%1d", ADR::register_S.read(), (MBF::register_G.read() & 0137777) | (PAR::register_G15.read() << 14), PAR::register_P.read(),MON::RUN, MON::PURST, MON::FCLK);
cout << buf << endl;
sprintf(buf, " RBU:%06o WBU:%06o P2:%01o (s)STEP:%1d", BUS::glbl_READ_BUS & 0177777, BUS::glbl_WRITE_BUS & 0177777,
PAR::register_P2.read(), MON::STEP);cout << buf << endl;
char parityAlm = ' ';if(PAR::register_PALM.read()) parityAlm = '*';
sprintf(buf, " B:%06o CADR:%06o (n)INST:%1d PALM:[%c]", ALU::register_B.read(), ADR::getEffectiveAddress(), MON::INST, parityAlm);
cout << buf << endl;
sprintf(buf, " X:%06o Y:%06o U:%06o (a)SA :%1d", ALU::register_X.read(), ALU::register_Y.read(), ALU::register_U.read(), MON::SA);
cout << buf << endl;
cout << endl;sprintf(buf, "00 A:%06o 15 BANK:%02o 36 TIME1:%06o 53 OPT Y:%06o",
CRG::register_A.read(), ADR::register_BNK.read(), MEM::readMemory(036),MEM::readMemory(053));
cout << buf << endl;sprintf(buf, "01 Q:%06o 16 RELINT:%6s 37 TIME3:%06o 54 TRKR X:%06o",
CRG::register_Q.read(),"", MEM::readMemory(037), MEM::readMemory(054));cout << buf << endl;sprintf(buf, "02 Z:%06o 17 INHINT:%6s 40 TIME4:%06o 55 TRKR Y:%06o",
CRG::register_Z.read(),"", MEM::readMemory(040), MEM::readMemory(055));cout << buf << endl;sprintf(buf, "03 LP:%06o 20 CYR:%06o 41 UPLINK:%06o 56 TRKR Z:%06o",
CRG::register_LP.read(), MEM::readMemory(020), MEM::readMemory(041),MEM::readMemory(056));
cout << buf << endl;
sprintf(buf, "04 IN0:%06o 21 SR:%06o 42 OUTCR1:%06o", INP::register_IN0.read(), MEM::readMemory(021), MEM::readMemory(042));
cout << buf << endl;
char progAlm = ' ';if(OUT::register_OUT1.read() & 0400) progAlm = '*';
char compFail = ' '; // also called 'check fail' and 'oper err'if(OUT::register_OUT1.read() & 0100) compFail = '*';
char keyRels = ' ';if(OUT::register_OUT1.read() & 020) keyRels = '*';
char upTl = ' ';if(OUT::register_OUT1.read() & 004) upTl = '*';
char comp = ' '; // also called comp actyif(OUT::register_OUT1.read() & 001) comp = '*';
sprintf(buf, "05 IN1:%06o 22 CYL:%06o 43 OUTCR2:%06o CF:[%c%c]:KR [%c]:PA", INP::register_IN1.read(), MEM::readMemory(022), MEM::readMemory(043),compFail, keyRels, progAlm);
cout << buf << endl;
sprintf(buf, "06 IN2:%06o 23 SL:%06o 44 PIPA X:%06o", INP::register_IN2.read(), MEM::readMemory(023), MEM::readMemory(044));
cout << buf << endl;
sprintf(buf, "07 IN3:%06o 24 ZRUPT:%06o 45 PIPA Y:%06o A:[%c%c] M:[%c%c]", INP::register_IN3.read(), MEM::readMemory(024), MEM::readMemory(045),
upTl, comp, DSP::MD1, DSP::MD2);
cout << buf << endl;char fc = ' '; if(DSP::flash) fc = '*';sprintf(buf, "10 OUT0: 25 BRUPT:%06o 46 PIPA Z:%06o V:[%c%c] N:[%c%c] %c",
MEM::readMemory(025), MEM::readMemory(046),DSP::VD1, DSP::VD2, DSP::ND1, DSP::ND2, fc);
cout << buf << endl;sprintf(buf, "11 OUT1:%06o 26 ARUPT:%06o 47 CDU X:%06o R1:[ %c%c%c%c%c%c ]",
OUT::register_OUT1.read(), MEM::readMemory(026), MEM::readMemory(047),DSP::R1S, DSP::R1D1, DSP::R1D2, DSP::R1D3, DSP::R1D4, DSP::R1D5);
cout << buf << endl;sprintf(buf, "12 OUT2:%06o 27 QRUPT:%06o 50 CDU Y:%06o R2:[ %c%c%c%c%c%c ]",
OUT::register_OUT2.read(), MEM::readMemory(027), MEM::readMemory(050),DSP::R2S, DSP::R2D1, DSP::R2D2, DSP::R2D3, DSP::R2D4, DSP::R2D5);
cout << buf << endl;sprintf(buf, "13 OUT3:%06o 34 OVCTR:%06o 51 CDU Z:%06o R3:[ %c%c%c%c%c%c ]",
OUT::register_OUT3.read(), MEM::readMemory(034), MEM::readMemory(051),DSP::R3S, DSP::R3D1, DSP::R3D2, DSP::R3D3, DSP::R3D4, DSP::R3D5);
cout << buf << endl;sprintf(buf, "14 OUT4:%06o 35 TIME2:%06o 52 OPT X:%06o",
OUT::register_OUT4.read(), MEM::readMemory(035), MEM::readMemory(052));cout << buf << endl;
}
OUT (OUT.h)
/**************************************************************************** * OUT - OUTPUT REGISTER subsystem * * AUTHOR: John Pultorak * DATE: 9/22/01 * FILE: OUT.h * * VERSIONS: * * DESCRIPTION: * Output Registers for the Block 1 Apollo Guidance Computer prototype (AGC4). * * SOURCES: * Mostly based on information from "Logical Description for the Apollo * Guidance Computer (AGC4)", Albert Hopkins, Ramon Alonso, and Hugh * Blair-Smith, R-393, MIT Instrumentation Laboratory, 1963. * * NOTES: * ***************************************************************************** */#ifndef OUT_H#define OUT_H
#include "reg.h"
class regOut1 : public reg { public: regOut1() : reg(16, "%06o") { }};
class regOut2 : public reg { public: regOut2() : reg(16, "%06o") { }
};
class regOut3 : public reg { public: regOut3() : reg(16, "%06o") { }};
class regOut4 : public reg { public: regOut4() : reg(16, "%06o") { }};
class OUT{public:
static void execWP_GENRST();static void execWP_WA10();static void execRP_RA11();static void execWP_WA11();static void execRP_RA12();static void execWP_WA12();static void execRP_RA13();static void execWP_WA13();static void execRP_RA14();static void execWP_WA14();
static regOut1 register_OUT1; // output register 1static regOut2 register_OUT2; // output register 2static regOut3 register_OUT3; // output register 3static regOut4 register_OUT4; // output register 4
};
#endif
OUT (OUT.cpp)
/**************************************************************************** * OUT - OUTPUT REGISTER subsystem * * AUTHOR: John Pultorak * DATE: 9/22/01 * FILE: OUT.cpp * * NOTES: see header file. * ***************************************************************************** */#include "OUT.h"#include "SEQ.h"#include "BUS.h"#include "DSP.h"#include "ADR.h"#include "PAR.h"#include <stdlib.h>
regOut1 OUT::register_OUT1; // output register 1regOut2 OUT::register_OUT2; // output register 2regOut3 OUT::register_OUT3; // output register 3regOut4 OUT::register_OUT4; // output register 4
// Writing to OUT0 loads the selected DSKY display register.
void OUT::execWP_GENRST(){
DSP::clearOut0();
register_OUT1.write(0);register_OUT2.write(0);
}
void OUT::execWP_WA10(){
DSP::decodeRelayWord(BUS::glbl_WRITE_BUS); }
void OUT::execRP_RA11(){
BUS::glbl_READ_BUS = register_OUT1.read();}
void OUT::execWP_WA11(){
register_OUT1.write(BUS::glbl_WRITE_BUS);}
void OUT::execRP_RA12(){
BUS::glbl_READ_BUS = register_OUT2.read();}
void OUT::execWP_WA12(){
register_OUT2.write(BUS::glbl_WRITE_BUS);}
void OUT::execRP_RA13(){
BUS::glbl_READ_BUS = register_OUT3.read();}
void OUT::execWP_WA13(){
register_OUT3.write(BUS::glbl_WRITE_BUS);}
void OUT::execRP_RA14(){
BUS::glbl_READ_BUS = register_OUT4.read();}
void OUT::execWP_WA14(){
register_OUT4.write(BUS::glbl_WRITE_BUS);}
PAR (PAR.h)
/**************************************************************************** * PAR - PARITY GENERATION AND TEST subsystem * * AUTHOR: John Pultorak * DATE: 9/22/01 * FILE: PAR.h * * VERSIONS: * * DESCRIPTION: * Parity Generation and Test for the Block 1 Apollo Guidance Computer * prototype (AGC4). * * SOURCES: * Mostly based on information from "Logical Description for the Apollo * Guidance Computer (AGC4)", Albert Hopkins, Ramon Alonso, and Hugh * Blair-Smith, R-393, MIT Instrumentation Laboratory, 1963. * * NOTES: * ***************************************************************************** */#ifndef PAR_H#define PAR_H
#include "reg.h"
class regG15 : public reg { public:
// memory buffer register bit 15 (parity) onlyregG15() : reg(1, "%01o") { }
};
class regP : public reg { public: regP() : reg(16, "%06o") { }};
class regP2 : public reg { public:
regP2() : reg(1, "%01o") { }};
class regPALM : public reg { public:
// parity alarm FF (set on TP)regPALM() : reg(1, "%01o") { }
};
class PAR{public:
static void execRP_WE();
static void execWP_WP();static void execWP_WPx();static void execWP_WP2();static void execWP_RP2();static void execWP_GP();static void execWP_SBWG();static void execWP_WGx();static void execWP_CLG();
static void execWP_GENRST();
static void execWP_TP();
static void CLR_PALM(); // asynchronous clear for PARITY ALARM
// memory buffer register bit 15; the rest of the// memory buffer register is defined in MBF
static regG15 register_G15;
static regP2 register_P2;static regP register_P;
static regPALM register_PALM;
static unsigned gen1_15Parity(unsigned r);static unsigned genP_15Parity(unsigned r);
static unsigned conv_WP[];};
#endif
PAR (PAR.cpp)
/**************************************************************************** * PAR - PARITY GENERATION AND TEST subsystem * * AUTHOR: John Pultorak * DATE: 9/22/01 * FILE: PAR.cpp * * NOTES: see header file. * ***************************************************************************** */#include "PAR.h"#include "SEQ.h"#include "BUS.h"#include "MBF.h"#include "ADR.h"#include "MEM.h"
regP PAR::register_P;regP2 PAR::register_P2;regG15 PAR::register_G15; // memory buffer register bit 15regPALM PAR::register_PALM; // PARITY ALARM FF
unsigned PAR::conv_WP[] ={
BX, SG, B14, B13, B12, B11, B10, B9, B8, B7, B6, B5, B4, B3, B2, B1 };
void PAR::execRP_WE(){
// Write parity into memory.MEM::MEM_PARITY_BUS = PAR::register_G15.read();
}
// IMPLEMENTATION NOTE: It has been empirically determined that the following// control signals are mutually exclusive (there is never more than one of these// generated at any time):// GP, WGX, RP2, SBWG, CLG
// NOTE: WP clears register_P before writing into it. Strictly speaking, WPx isn't// supposed to clear the register (should OR into the register), but in the counter// sequences where WPx is used, register_P is always cleared in the previous TP by// asserting WP with default zeroes on the write bus.
void PAR::execWP_WP(){
// set all bits except parity bitregister_P.writeShift(BUS::glbl_WRITE_BUS, PAR::conv_WP);
// now set parity bit; in the actual AGC, this is// a single operation.
if(SEQ::isAsserted(RG))register_P.writeField(16, 16, register_G15.read());
elseregister_P.writeField(16, 16, 0); // clear parity bit
}
void PAR::execWP_WPx(){
// set all bits except parity bitregister_P.writeShift(BUS::glbl_WRITE_BUS, PAR::conv_WP);
// now set parity bit; in the actual AGC, this is// a single operation.
if(SEQ::isAsserted(RG))register_P.writeField(16, 16, register_G15.read());
else
register_P.writeField(16, 16, 0); // clear parity bit}
void PAR::execWP_WP2(){
register_P2.write(gen1_15Parity(register_P.read()));}
void PAR::execWP_RP2(){
register_G15.write(register_P2.read());}
void PAR::execWP_GP(){
register_G15.write(gen1_15Parity(register_P.read()));}
void PAR::execWP_SBWG(){
register_G15.write(MEM::MEM_PARITY_BUS); // load memory bit 16 (parity) into G15}
void PAR::execWP_WGx(){
// This is only used in PINC, MINC, and SHINC. Does not clear G// register; writes (ORs) into G from RWBus and writes into parity// from 1-15 generator. All done in one operation, although I show// it in two steps here. The sequence calls CLG in a previous TP.
register_G15.write(PAR::gen1_15Parity(register_P.read()));}
void PAR::execWP_CLG(){
register_G15.write(0);}
void PAR::execWP_GENRST(){
register_PALM.write(0);}
void PAR::execWP_TP(){
if(ADR::GTR_27() && genP_15Parity(register_P.read())) register_PALM.write(genP_15Parity(register_P.read()));}
void PAR::CLR_PALM(){
// asynchronous clear for PARITY ALARM (from MON)register_PALM.clear();
}
unsigned PAR::gen1_15Parity(unsigned r){
//check the lower 15 bits of 'r' and return the odd parity;//bit 16 is ignored.unsigned evenParity =
(1&(r>>0)) ^ (1&(r>>1)) ^ (1&(r>>2)) ^ (1&(r>>3)) ^(1&(r>>4)) ^ (1&(r>>5)) ^ (1&(r>>6)) ^ (1&(r>>7)) ^(1&(r>>8)) ^ (1&(r>>9)) ^ (1&(r>>10)) ^ (1&(r>>11)) ^(1&(r>>12)) ^ (1&(r>>13)) ^ (1&(r>>14));
return ~evenParity & 1; // odd parity}
unsigned PAR::genP_15Parity(unsigned r){
//check all 16 bits of 'r' and return the odd parityunsigned evenParity =
(1&(r>>0)) ^ (1&(r>>1)) ^ (1&(r>>2)) ^ (1&(r>>3)) ^(1&(r>>4)) ^ (1&(r>>5)) ^ (1&(r>>6)) ^ (1&(r>>7)) ^(1&(r>>8)) ^ (1&(r>>9)) ^ (1&(r>>10)) ^ (1&(r>>11)) ^
(1&(r>>12)) ^ (1&(r>>13)) ^ (1&(r>>14)) ^ (1&(r>>15));return ~evenParity & 1; // odd parity
}
Registers (reg.h)
#ifndef reg_H#define reg_H
#include <iostream.h>#include <string.h>#include <stdio.h>
class reg{public:
virtual unsigned read() { return mask & slaveVal; }virtual void write(unsigned v) { load = true; masterVal = mask & v; }
// asynchronous clearvoid clear() { slaveVal = 0; }
// load is set when a register is written into.void clk() { if(load) slaveVal = masterVal; load = false; }
unsigned readField(unsigned msb, unsigned lsb); // bitfield numbered n - 1void writeField(unsigned msb, unsigned lsb, unsigned v); // bitfield numbered n - 1
// Write a 16-bit word (in) into the register. Transpose the bits according to// the specification (ib).void writeShift(unsigned in, unsigned* ib);
// Return a shifted 16-bit word. Transpose the 'in' bits according to// the specification 'ib'. 'Or' the result to out and return the value.unsigned shiftData(unsigned out, unsigned in, unsigned* ib);
unsigned outmask() { return mask; }
protected:reg(unsigned s, char* fs)
: size(s), mask(0), masterVal(0), slaveVal(0), fmtString(fs), load(false){ mask = buildMask(size);}
static unsigned buildMask(unsigned s);
friend ostream& operator << (ostream& os, const reg& r){ char buf[32]; sprintf(buf, r.fmtString, r.slaveVal); os << buf; return os; }
private:unsigned size; // bitsunsigned masterVal;unsigned slaveVal;unsigned mask;char* fmtString;bool load;
reg(); // prevent instantiation of default constructor};
#endif
Registers (reg.cpp)
#include "reg.h"#include <math.h>#include "BUS.h"
unsigned reg::buildMask(unsigned s){
unsigned msk = 0;for(unsigned i=0; i<s; i++){
msk = (msk << 1) | 1;}return msk;
}
unsigned reg::readField(unsigned msb, unsigned lsb){
return (slaveVal >> (lsb-1)) & buildMask((msb-lsb)+1);}
void reg::writeField(unsigned msb, unsigned lsb, unsigned v){
load = true;unsigned fmask = buildMask((msb-lsb)+1) << (lsb-1);v = (v << (lsb-1)) & fmask;masterVal = (masterVal &(~fmask)) | v;
}
void reg::writeShift(unsigned in, unsigned* ib){
load = true;unsigned out = masterVal;
// iterate through each bit of the output word, copying in bits from the input// word and transposing bit position according to the specification (ib)
for(unsigned i=0; i<16; i++){
if(ib[i] == BX) continue; // BX is 'don't care', so leave it alone
// zero the output bit at 'ob', where ob specifies a bit// position (numbered 16-1, where 1 is lsb)
unsigned ob = 16-i;unsigned obmask = 1 << (ob - 1); // create mask for output bitout &= ~obmask;
if(ib[i] == D0) continue; // D0 is 'force the bit to zero'
// copy input bit ib[i] to output bit 'ob', where ib and ob// specify bit positions (numbered 16-1, where 1 is lsb)
unsigned ibmask = 1 << (ib[i] - 1); // create mask for input bitunsigned inbit = in & ibmask;
int shift = ib[i]-ob;if(shift<0)
inbit = inbit << abs(shift);else if(shift > 0)
inbit = inbit >> shift;out |= inbit;
}masterVal = out;
}
unsigned reg::shiftData(unsigned out, unsigned in, unsigned* ib){
// iterate through each bit of the output word, copying in bits from the input// word and transposing bit position according to the specification (ib)
for(unsigned i=0; i<16; i++){
if(ib[i] == BX) continue; // BX is 'don't care', so leave it alone
// zero the output bit at 'ob', where ob specifies a bit// position (numbered 16-1, where 1 is lsb)
unsigned ob = 16-i;
unsigned obmask = 1 << (ob - 1); // create mask for output bitout &= ~obmask;
if(ib[i] == D0) continue; // D0 is 'force the bit to zero'
// copy input bit ib[i] to output bit 'ob', where ib and ob// specify bit positions (numbered 16-1, where 1 is lsb)
unsigned ibmask = 1 << (ib[i] - 1); // create mask for input bitunsigned inbit = in & ibmask;
int shift = ib[i]-ob;if(shift<0)
inbit = inbit << abs(shift);else if(shift > 0)
inbit = inbit >> shift;out |= inbit;
}return out;
}
SCL (SCL.h)
/**************************************************************************** * SCL - SCALER subsystem * * AUTHOR: John Pultorak * DATE: 9/22/01 * FILE: SCL.h * * VERSIONS: * * DESCRIPTION: * Scaler for the Block 1 Apollo Guidance Computer prototype (AGC4). * * SOURCES: * Mostly based on information from "Logical Description for the Apollo * Guidance Computer (AGC4)", Albert Hopkins, Ramon Alonso, and Hugh * Blair-Smith, R-393, MIT Instrumentation Laboratory, 1963. * * NOTES: * ***************************************************************************** */#ifndef SCL_H#define SCL_H
#include "reg.h"
class regF17 : public reg { public:
regF17() : reg(2, "%01o") { }};
class regF13 : public reg { public:
regF13() : reg(2, "%01o") { }};
class regF10 : public reg { public:
regF10() : reg(2, "%01o") { }};
class regSCL : public reg { public:
regSCL() : reg(17, "%06o") { }};
class SCL{public:
static void doexecWP_SCL();static void doexecWP_F17();static void doexecWP_F13();static void doexecWP_F10();
static regSCL register_SCL;
// Normally outputs '0'; outputs '1' for one// clock pulse at the indicated frequency.
static unsigned F17x(); // 0.78125 Hz scaler outputstatic unsigned F13x(); // 12.5 Hz scaler outputstatic unsigned F10x(); // 100 Hz scaler output
static regF17 register_F17;static regF13 register_F13;static regF10 register_F10;
};
#endif
SCL (SCL.cpp)
/**************************************************************************** * SCL - SCALER subsystem * * AUTHOR: John Pultorak * DATE: 9/22/01 * FILE: SCL.cpp * * NOTES: see header file. * ***************************************************************************** */#include "SCL.h"#include "CTR.h"#include "MON.h"
regSCL SCL::register_SCL;regF17 SCL::register_F17;regF13 SCL::register_F13;regF10 SCL::register_F10;
enum oneShotType { // **inferred; not defined in orignal R393 AGC4 spec.WAIT_FOR_TRIGGER=0,OUTPUT_PULSE=1, // LSB (bit 1) is the output bit for the one-shotWAIT_FOR_RESET=2
};
void SCL::doexecWP_F17(){
int bit = SCL::register_SCL.readField(17,17);switch(register_F17.read()){case WAIT_FOR_TRIGGER: if(bit==1) register_F17.write(OUTPUT_PULSE); break;case OUTPUT_PULSE: register_F17.write(WAIT_FOR_RESET); break;case WAIT_FOR_RESET: if(bit==0) register_F17.write(WAIT_FOR_TRIGGER); break;default: ;}
}
void SCL::doexecWP_F13(){
int bit = SCL::register_SCL.readField(13,13);switch(register_F13.read()){case WAIT_FOR_TRIGGER: if(bit==1) register_F13.write(OUTPUT_PULSE); break;case OUTPUT_PULSE: register_F13.write(WAIT_FOR_RESET); break;case WAIT_FOR_RESET: if(bit==0) register_F13.write(WAIT_FOR_TRIGGER); break;default: ;}
}
void SCL::doexecWP_F10(){
int bit = SCL::register_SCL.readField(10,10);switch(register_F10.read()){case WAIT_FOR_TRIGGER: if(bit==1) register_F10.write(OUTPUT_PULSE); break;case OUTPUT_PULSE: register_F10.write(WAIT_FOR_RESET);
CTR::pcUp[TIME1] = 1;CTR::pcUp[TIME3] = 1;CTR::pcUp[TIME4] = 1;break;
case WAIT_FOR_RESET: if(bit==0) register_F10.write(WAIT_FOR_TRIGGER); break;default: ;}
}
unsigned SCL::F17x(){
return register_F17.readField(1,1);
}
unsigned SCL::F13x(){
return register_F13.readField(1,1);}
unsigned SCL::F10x(){
return register_F10.readField(1,1);}
void SCL::doexecWP_SCL(){
if(MON::SCL_ENAB) // if the scaler is enabled{
//write((read() + 1) % outmask());register_SCL.write((register_SCL.read() + 1));
}}
SEQ (SEQ.h)
/**************************************************************************** * SEQ - SEQUENCE GENERATOR subsystem * * AUTHOR: John Pultorak * DATE: 9/22/01 * FILE: SEQ.h * * VERSIONS: * * DESCRIPTION: * Sequence Generator for the Block 1 Apollo Guidance Computer prototype (AGC4). * * SOURCES: * Mostly based on information from "Logical Description for the Apollo * Guidance Computer (AGC4)", Albert Hopkins, Ramon Alonso, and Hugh * Blair-Smith, R-393, MIT Instrumentation Laboratory, 1963. * * NOTES: * ***************************************************************************** */#ifndef SEQ_H#define SEQ_H
#include "reg.h"
#define MAXPULSES 15#define MAX_IPULSES 5 // no more than 5 instruction-generated pulses active at any time
enum cpType { // **inferred; not defined in orignal R393 AGC4 spec.NO_PULSE=0,
// OUTPUTS FROM SUBSYSTEM ACI =1, // Carry inCLG =2, // Clear GCLCTR =3, // Clear loop counterCTR =4, // Loop counterGP =5, // Generate ParityKRPT =6, // Knock down Rupt priorityNISQ =7, // New instruction to the SQ registerRA =8, // Read ARB =9, // Read BRB14 =10, // Read bit 14RC =11, // Read CRG =12, // Read GRLP =13, // Read LPRP2 =14, // Read parity 2RQ =15, // Read QRRPA =16, // Read RUPT addressRSB =17, // Read sign bitRSCT =18, // Read selected counter addressRU =19, // Read sumRZ =20, // Read ZR1 =21, // Read 1R1C =22, // Read 1 complimentedR2 =23, // Read 2R22 =24, // Read 22R24 =25, // Read 24ST1 =26, // Stage 1ST2 =27, // Stage 2TMZ =28, // Test for minus zeroTOV =29, // Test for overflowTP =30, // Test parityTRSM =31, // Test for resumeTSGN =32, // Test signTSGN2 =33, // Test sign 2WA =34, // Write AWALP =35, // Write A and LPWB =36, // Write BWGx =37, // Write G (do not reset)
WLP =38, // Write LPWOVC =39, // Write overflow counterWOVI =40, // Write overflow RUPT inhibitWOVR =41, // Write overflowWP =42, // Write PWPx =43, // Write P (do not reset)WP2 =44, // Write P2WQ =45, // Write QWS =46, // Write SWX =47, // Write XWY =48, // Write YWYx =49, // Write Y (do not reset)WZ =50, // Write Z
// OUTPUTS FROM SUBSYSTEM A; USED AS INPUTS TO SUBSYSTEM B ONLY;// NOT USED OUTSIDE CPMRSC =51, // Read special and central (output to B only, not outside CPM)WSC =52, // Write special and central (output to B only, not outside CPM)WG =53, // Write G (output to B only, not outside CPM)
// OUTPUTS FROM SUBSYSTEM A; USED AS INPUTS TO SUBSYSTEM C ONLY;// NOT USED OUTSIDE CPMSDV1 =54, // Subsequence DV1 is currently activeSMP1 =55, // Subsequence MP1 is currently activeSRSM3 =56, // Subsequence RSM3 is currently active
// EXTERNAL OUTPUTS FROM SUBSYSTEM B//RA0 =57, // Read register at address 0 (A)RA1 =58, // Read register at address 1 (Q)RA2 =59, // Read register at address 2 (Z)RA3 =60, // Read register at address 3 (LP)RA4 =61, // Read register at address 4RA5 =62, // Read register at address 5RA6 =63, // Read register at address 6RA7 =64, // Read register at address 7RA10 =65, // Read register at address 10 (octal)RA11 =66, // Read register at address 11 (octal)RA12 =67, // Read register at address 12 (octal)RA13 =68, // Read register at address 13 (octal)RA14 =69, // Read register at address 14 (octal)RBK =70, // Read BNKWA0 =71, // Write register at address 0 (A)WA1 =72, // Write register at address 1 (Q)WA2 =73, // Write register at address 2 (Z)WA3 =74, // Write register at address 3 (LP)WA10 =75, // Write register at address 10 (octal)WA11 =76, // Write register at address 11 (octal)WA12 =77, // Write register at address 12 (octal)WA13 =78, // Write register at address 13 (octal)WA14 =79, // Write register at address 14 (octal)WBK =80, // Write BNKWGn =81, // Write G (normal gates)**W20 =82, // Write into CYRW21 =83, // Write into SRW22 =84, // Write into CYLW23 =85, // Write into SL
// THESE ARE THE LEFTOVERS -- THEY'RE PROBABLY USED IN SUBSYSTEM C//GENRST =86, // General Reset**CLINH =87, // Clear INHINT**CLINH1 =88, // Clear INHINT1**CLSTA =89, // Clear state counter A (STA)**CLSTB =90, // Clear state counter B (STB)**CLISQ =91, // Clear SNI**CLRP =92, // Clear RPCELL**INH =93, // Set INHINT**RPT =94, // Read RUPT opcode **SBWG =95, // Write G from memorySETSTB =96, // Set the ST1 bit of STBWE =97, // Write E-MEM from GWPCTR =98, // Write PCTR (latch priority counter sequence)**WSQ =99, // Write SQ
WSTB =100, // Write stage counter B (STB)**R2000 =101, // Read 2000 **
};
// INSTRUCTIONS
// Op Codes, as they appear in the SQ register.enum instruction {
// The code in the SQ register is the same as the op code for these// four instructions.TC =00, // 00 TC K Transfer Control 1 MCTCCS =01, // 01 CCS K Count, Compare, and Skip 2 MCTINDEX =02, // 02 INDEX K 2 MCTXCH =03, // 03 XCH K Exchange 2 MCT
// The SQ register code is the op code + 010 (octal). This happens because all// of these instructions have bit 15 set (the sign (SG) bit) while in memory. When the// instruction is copied from memory to the memory buffer register (G) to register// B, the SG bit moves from bit 15 to bit 16 and the sign is copied back into bit// 15 (US). Therefore, the CS op code (04) becomes (14), and so on.CS =014, // 04 CS K Clear and Subtract 2 MCTTS =015, // 05 TS K Transfer to Storage 2 MCTAD =016, // 06 AD K Add 2 or 3 MCTMASK =017, // 07 MASK K Bitwise AND 2 MCT
// These are extended instructions. They are accessed by executing an INDEX 5777// before each instruction. By convention, address 5777 contains 47777. The INDEX// instruction adds 47777 to the extended instruction to form the SQ op code. For// example, the INDEX adds 4 to the 4 op code for MP to produce the 11 (octal; the// addition generates an end-around-carry). SQ register code (the 7777 part is a // negative zero).MP =011, // 04 MP K Multiply 10 MCTDV =012, // 05 DV K Divide 18 MCTSU =013, // 06 SU K Subtract 4 or 5 MCT
};
enum subseq {TC0 =0,CCS0 =1,CCS1 =2,NDX0 =3,NDX1 =4,RSM3 =5,XCH0 =6,CS0 =7,TS0 =8,AD0 =9,MASK0 =10,MP0 =11,MP1 =12,MP3 =13,DV0 =14,DV1 =15,SU0 =16,RUPT1 =17,RUPT3 =18,STD2 =19,PINC0 =20,MINC0 =21,SHINC0 =22,NO_SEQ =23
};
enum scType { // identifies subsequence for a given instructionSUB0=0, // ST2=0, ST1=0SUB1=1, // ST2=0, ST1=1SUB2=2, // ST2=1, ST1=0SUB3=3 // ST2=1, ST1=1
};
enum brType {BR00 =0, // BR1=0, BR2=0BR01 =1, // BR1=0, BR2=1
BR10 =2, // BR1=1, BR2=0BR11 =3, // BR1=1, BR2=1NO_BR =4 // NO BRANCH
};
const int GOPROG =02000; // bottom address of fixed memory
class regSQ : public reg { public:
regSQ() : reg(4, "%02o") { }};
class regSTA : public reg { public:
regSTA() : reg(2, "%01o") { }};
class regSTB : public reg { public:
regSTB() : reg(2, "%01o") { }};
class regBR1 : public reg { public:
regBR1() : reg(1, "%01o") { }};
class regBR2 : public reg { public:
regBR2() : reg(1, "%01o") { }};
class regCTR : public reg { public:
regCTR() : reg(3, "%01o") { }};
class regSNI : public reg { public: regSNI() : reg(1, "%01o") { }};
class SEQ{public:
static void execWP_GENRST();static void execWP_WSQ(); static void execWP_NISQ();static void execWP_CLISQ();static void execWP_ST1();static void execWP_ST2();static void execWP_TRSM();static void execWP_CLSTA();static void execWP_WSTB();static void execWP_CLSTB();static void execWP_SETSTB();static void execWP_TSGN();static void execWP_TOV();static void execWP_TMZ();static void execWP_TSGN2();static void execWP_CTR();static void execWP_CLCTR();
static regSNI register_SNI; // select next intruction flagstatic cpType glbl_cp[MAXPULSES]; // current set of asserted control pulses
(MAXPULSES)
static char* cpTypeString[];
// Test the currently asserted control pulses; return true if the specified// control pulse is active.static bool isAsserted(cpType pulse);
// Return a string containing the names of all asserted control pulses.static char* getControlPulses();
static subseq glbl_subseq; // currently decoded instruction subsequence
static regSQ register_SQ; // instruction registerstatic regSTA register_STA; // stage counter Astatic regSTB register_STB; // stage counter Bstatic regBR1 register_BR1; // branch register1static regBR2 register_BR2; // branch register2static regCTR register_LOOPCTR; // loop counter
static char* instructionString[];};
#endif
SEQ (SEQ.cpp)
/**************************************************************************** * SEQ - SEQUENCE GENERATOR subsystem * * AUTHOR: John Pultorak * DATE: 9/22/01 * FILE: SEQ.cpp * * NOTES: see header file. * ***************************************************************************** */#include "SEQ.h"#include "ADR.h"#include "BUS.h"
regSNI SEQ::register_SNI; // select next intruction flagcpType SEQ::glbl_cp[]; // current set of asserted control pulses (MAXPULSES)
regSQ SEQ::register_SQ; // instruction registerregSTA SEQ::register_STA; // stage counter AregSTB SEQ::register_STB; // stage counter BregBR1 SEQ::register_BR1; // branch register1regBR2 SEQ::register_BR2; // branch register2regCTR SEQ::register_LOOPCTR; // loop countersubseq SEQ::glbl_subseq; // currently decoded instruction subsequence
char* SEQ::instructionString[] ={
"TC","CCS","INDEX","XCH","***","***","***","***","***","MP","DV","SU","CS","TS","AD","MASK"
};
char* SEQ::cpTypeString[] = {
"NO_PULSE",
// OUTPUTS FROM SUBSYSTEM A"CI", "CLG", "CLCTR", "CTR", "GP", "KRPT", "NISQ", "RA", "RB", "RB14", "RC", "RG", "RLP", "RP2", "RQ", "RRPA", "RSB", "RSCT", "RU", "RZ", "R1", "R1C", "R2", "R22", "R24", "ST1", "ST2", "TMZ", "TOV", "TP", "TRSM", "TSGN", "TSGN2", "WA", "WALP", "WB", "WGx", "WLP", "WOVC", "WOVI", "WOVR", "WP", "WPx", "WP2", "WQ", "WS", "WX", "WY", "WYx", "WZ",
// OUTPUTS FROM SUBSYSTEM A; USED AS INPUTS TO SUBSYSTEM B ONLY;// NOT USED OUTSIDE CPM//"RSC", "WSC", "WG",
// OUTPUTS FROM SUBSYSTEM A; USED AS INPUTS TO SUBSYSTEM C ONLY;// NOT USED OUTSIDE CPM//"SDV1", "SMP1", "SRSM3",
// EXTERNAL OUTPUTS FROM SUBSYSTEM B
//"RA0", "RA1", "RA2", "RA3", "RA4", "RA5", "RA6", "RA7", "RA10", "RA11", "RA12", "RA13", "RA14", "RBK", "WA0", "WA1", "WA2", "WA3", "WA10", "WA11", "WA12", "WA13", "WA14", "WBK", "WGn", "W20", "W21", "W22", "W23",
// THESE ARE THE LEFTOVERS -- THEY'RE PROBABLY USED IN SUBSYSTEM C//"GENRST", "CLINH", "CLINH1", "CLSTA", "CLSTB", "CLISQ", "CLRP", "INH", "RPT", "SBWG", "SETSTB", "WE", "WPCTR", "WSQ", "WSTB", "R2000"
};
void SEQ::execWP_GENRST(){
register_SQ.write(0);register_BR1.write(0);register_BR2.write(0);register_SNI.write(0);register_LOOPCTR.write(0);register_STA.write(0);register_STB.write(0);
}
void SEQ::execWP_WSQ(){
register_SQ.write(BUS::glbl_WRITE_BUS >> 12);}
void SEQ::execWP_NISQ(){
register_SNI.writeField(1,1,1); // change to write(1)??}
void SEQ::execWP_CLISQ(){
register_SNI.writeField(1,1,0); // change to write(0)??}
bool SEQ::isAsserted(cpType pulse){
for(unsigned i=0; i<MAXPULSES; i++)if(glbl_cp[i] == pulse) return true;
return false;}
char* SEQ::getControlPulses(){
static char buf[MAXPULSES*6];strcpy(buf,"");
for(unsigned i=0; i<MAXPULSES && glbl_cp[i] != NO_PULSE; i++){
strcat(buf, cpTypeString[glbl_cp[i]]);strcat(buf," ");
}//if(strcmp(buf,"") == 0) strcat(buf,"NONE");return buf;
}
void SEQ::execWP_ST1(){
register_STA.writeField(1,1,1);}
void SEQ::execWP_ST2(){
register_STA.writeField(2,2,1);}
void SEQ::execWP_TRSM(){
if(ADR::EQU_25()) register_STA.writeField(2,2,1);
}
void SEQ::execWP_CLSTA(){
register_STA.writeField(2,1,0);}
void SEQ::execWP_WSTB(){
register_STB.write(SEQ::register_STA.read()); }
void SEQ::execWP_CLSTB(){
register_STB.writeField(2,1,0);}
void SEQ::execWP_SETSTB(){
register_STB.writeField(2,1,1);}
void SEQ::execWP_TSGN(){
// Set Branch 1 FF// if sign bit is '1' (negative sign)
if(BUS::glbl_WRITE_BUS & 0100000) register_BR1.write(1);
else register_BR1.write(0);
}
void SEQ::execWP_TOV(){
// Set Branch 1 FF// if negative overflow (sign==1; overflow==0)
if((BUS::glbl_WRITE_BUS & 0140000) == 0100000) register_BR1.write(1);
else register_BR1.write(0);
// Set Branch 2 FF// if positive overflow (sign==0; oveflow==1)
if((BUS::glbl_WRITE_BUS & 0140000) == 0040000) register_BR2.write(1);
else register_BR2.write(0);
}
void SEQ::execWP_TSGN2(){
// Set Branch 2 FF// if sign bit is '1' (negative sign)
if(BUS::glbl_WRITE_BUS & 0100000) register_BR2.write(1);
else register_BR2.write(0);
}
void SEQ::execWP_TMZ(){
// Set Branch 2 FF// if minus zero
if(BUS::glbl_WRITE_BUS == 0177777) register_BR2.write(1);
else register_BR2.write(0);
}
void SEQ::execWP_CTR(){
register_LOOPCTR.write(register_LOOPCTR.read()+1);}
void SEQ::execWP_CLCTR(){
register_LOOPCTR.write(0);}
TPG (TPG.h)
/**************************************************************************** * TPG - TIME PULSE GENERATOR subsystem * * AUTHOR: John Pultorak * DATE: 9/22/01 * FILE: TPG.h * * VERSIONS: * * DESCRIPTION: * Time Pulse Generator and Start/Stop Logic for the Block 1 Apollo Guidance * Computer prototype (AGC4). * * SOURCES: * Mostly based on information from "Logical Description for the Apollo * Guidance Computer (AGC4)", Albert Hopkins, Ramon Alonso, and Hugh * Blair-Smith, R-393, MIT Instrumentation Laboratory, 1963. * * NOTES: * ***************************************************************************** */#ifndef TPG_H#define TPG_H
#include "reg.h"
// Start/Stop Logic and Time Pulse Generator Subsystem
enum tpType {STBY =0,PWRON =1,
TP1 =2, // TIME PULSE 1: start of memory cycle time (MCT)TP2 =3,TP3 =4,TP4 =5,TP5 =6,TP6 =7, // EMEM is available in G register by TP6TP7 =8, // FMEM is available in G register by TP7TP8 =9,TP9 =10,TP10 =11, // G register written to memory beginning at TP10TP11 =12, // TIME PULSE 11: end of memory cycle time (MCT)TP12 =13, // select new subsequence/select new instruction
SRLSE =14, // step switch releaseWAIT =15
};
class regSG : public reg { public: regSG() : reg(4, "%02o") { }
};
class TPG{public:
static void doexecWP_TPG();
static regSG register_SG;
static char* tpTypestring[];};
#endif
TPG (TPG.cpp)
/**************************************************************************** * TPG - TIME PULSE GENERATOR subsystem * * AUTHOR: John Pultorak * DATE: 9/22/01 * FILE: TPG.cpp * * NOTES: see header file. * ***************************************************************************** */#include "TPG.h"#include "MON.h"#include "SCL.h"#include "SEQ.h"#include "OUT.h"
char* TPG::tpTypestring[] = // must correspond to tpType enumerated type{
"STBY", "PWRON", "TP1", "TP2", "TP3", "TP4", "TP5", "TP6", "TP7", "TP8","TP9", "TP10", "TP11", "TP12", "SRLSE", "WAIT"
};
regSG TPG::register_SG; // static member
void TPG::doexecWP_TPG() {
unsigned mystate = register_SG.read();if(MON::PURST)
mystate = STBY;elseswitch(mystate){case STBY: if(!MON::PURST && ((!MON::FCLK) || SCL::F17x())) mystate = PWRON; break;case PWRON: if(((!MON::FCLK) || SCL::F13x())) mystate = TP1; break;
case TP1: mystate = TP2; break;case TP2: mystate = TP3; break;case TP3: mystate = TP4; break;case TP4: mystate = TP5; break;case TP5: mystate = TP6; break;case TP6: mystate = TP7; break;case TP7: mystate = TP8; break;case TP8: mystate = TP9; break;case TP9: mystate = TP10; break;case TP10: mystate = TP11; break;case TP11: mystate = TP12; break;case TP12:
if(SEQ::register_SNI.read() && OUT::register_OUT1.readField(8,8) && MON::SA)mystate = STBY;// the next transition to TP1 is incompletely decoded; it works because// the transition to STBY has already been tested.
else if((MON::RUN) || (!SEQ::register_SNI.read() && MON::INST))mystate = TP1;
elsemystate = SRLSE;
break;case SRLSE: if(!MON::STEP) mystate = WAIT; break;case WAIT:
if(MON::STEP || MON::RUN) mystate = TP1;
break;default: break;}register_SG.write(mystate);
}
Block IApollo Guidance Computer (AGC)
How to build one in your basement
Part 8: Flight Software
John Pultorak
December, 2004
Abstract
This report describes my successful project to build a working reproduction of the 1964
prototype for the Block I Apollo Guidance Computer. The AGC is the flight computer for the
Apollo moon landings, and is the world’s first integrated circuit computer.
I built it in my basement. It took me 4 years.
If you like, you can build one too. It will take you less time, and yours will be better than
mine.
I documented my project in 9 separate .pdf files:
Part 1 Overview: Introduces the project.
Part 2 CTL Module: Design and construction of the control module.
Part 3 PROC Module: Design and construction of the processing (CPU) module.
Part 4 MEM Module: Design and construction of the memory module.
Part 5 IO Module: Design and construction of the display/keyboard (DSKY) module.
Part 6 Assembler: A cross-assembler for AGC software development.
Part 7 C++ Simulator: A low-level simulator that runs assembled AGC code.
Part 8 Flight Software: My translation of portions of the COLOSSUS 249 flight
software.
Part 9 Test & Checkout: A suite of test programs in AGC assembly language.
Overview
I wanted genuine Block I flight software for my AGC, but couldn’t find any. I eventually
wound up recreating Block I software from Block II code listings that were available. Major
portions of Block II were originally coded as Block I anyway, so the conversion back was not
too difficult. About 95% of the instructions were already Block I, so I just had to translate
the remaining 5% into their Block I equivalents.
I downloaded a partial listing of the COLOSSUS 249 flight software for the Block II Apollo
Command Module AGC from a M.I.T website in late 2001. The listing (at that time)
comprised first half
of the flight
software load. The
second half was
missing.
The part that was
present contained
eraseable memory
declarations, and
PINBALL, the AGC
user interface. The
missing portion
contained (among
other things) the
EXEC and
WAITLIST pieces of
the operating
system, bank
register calling
routines, and math
libraries.
The downloaded
document was a .pdf file containing 300 or so fuzzy dig ital images of assembler listing. I
printed it, and then retyped the erasable memory and PINBALL portions into a text file,
marking off each reentered line in the original listing with a highlighter.
I coded my own versions of the EXEC, WAITLIST, BANKCALL, and other missing routines
used by PINBALL. The R-393 document from M.I.T. provided some guidance.
Over a 6 month period, I was able to get all regular verbs and generic normal nouns
working. These are listed near the top of my assembler listing.
I added additional comments to portions of code taken from COLOSSUS. The page numbers
in my comments refer to pages in the COLOSSUS 249 assembler listing.
Original COLOSSUS 249 Assembler Code
For comparison purposes, here’s a page of the original AGC assembly code, downloaded
from the M.I.T. website. This is a tiny portion of the PINBALL code. I marked each line with
a yellow highlighter as I reentered it into a text file.
My COLOSSUS Assembler Code
Here’s the exact same portion of code, assembled for my Block I AGC. If you compare the
two listings, you’ll see that I defined some different assembler directives for allocating
storage (DS % instead of OCT) and that my code is sitting in a different bank (5 vs. 40) at a
different offset than the original Block II code.
Scenarios
Here’s how some AGC verbs and nouns are used to do commonplace operations. The
overview (part 1) and simulator (part 7) documents contain actual examples of some of
these operations in the simulated and hardware AGCs.
Display elapsed time from the AGC clock:
<VERB> <0> <6> <NOUN> <3> <6> <ENTER>
Start a monitor program to continuously display the AGC clock:
<VERB> <1> <6> <NOUN> <3> <6> <ENTER>
Terminate a monitor program:
<VERB> <3> <4> <ENTER>
Test DSJT display lights:
<VERB> <3> <5> <ENTER>
All DSKY lamps and display segments illuminate for 5 sec. after 5 sec, the DSKY
lamps extinguish.
Load component 1 for dataset at octal address 50 with octal 123:
<VERB> <2> <1> <NOUN> <0> <1> <ENTER>
Verb/noun display flashes: waiting for address.
<5> <0> <ENTER>
Verb/noun display flash continues: waiting for data.
<1> <2> <3> <ENTER>
Octal word from R1 is loaded at address 50.
Display component 1 of dataset at octal address 50:
<VERB> <0> <1> <NOUN> <0> <1> <ENTER>
Verb/noun display flashes: waiting for address.
<5> <0> <ENTER>
Octal word from address 50 is displayed in R1.
Display component 1 of dataset incrementing from 50:
<VERB> <0> <1> <NOUN> <0> <1> <ENTER>
Verb/noun display flashes: waiting for address.
<5> <0> <ENTER>
Octal word from address 50 is displayed in R1.
<NOUN> <1> <5> <ENTER>
Octal word from address 51 is displayed in R1, address in R3.
<ENTER>
Octal word from address 52 is displayed in R1, address in R3.
Load 3 component dataset at octal address 50 with octal values: 123, 456, 701:
<VERB> <2> <5> <NOUN> <0> <1> <ENTER>
Verb/noun display flashes: waiting for address.
<5> <0> <ENTER>
Verb/noun display flash continues: waiting for data.
<1> <2> <3> <ENTER>
<4> <5> <6> <ENTER>
<7> <0> <1> <ENTER>
Octal word from R1 is loaded at address 50; Octal word from R2 is loaded at address
51, Octal word from R3 is loaded at address 52.
Display 3 component dataset beginning at address 50:
<VERB> <0> <5> <NOUN> <0> <1> <ENTER>
Verb/noun display flashes: waiting for address.
<5> <0> <ENTER>
Octal word from address 50 is displayed in R1; Octal word from address 51 is
displayed in R2; Octal word from address 52 is displayed in R3.
Change major mode to P00:
<VERB> <3> <7> <ENTER>
Verb/noun display flashes: waiting for major mode
<0> <0> <ENTER>
VERBS and NOUNS
COLOSSUS REGULAR VERBS (00-39 decimal)
This is adapted from the Apollo 204 accident report posted on multiple
web sites by Richard F. Drushel. The information has been changed as
necessary to be consistent with usage in COLOSSUS 249.
Verb | |Code | Description | Remarks | |01 | Display octal comp 1 in R1 | Performs octal display of data on | | REGISTER 1. | |02 | Display octal comp 2 in R2 | Performs octal display of data on | | REGISTER 1. | |03 | Display octal comp 3 in R3 | Performs octal display of data on | | REGISTER 1. | |04 | Display octal comp 1,2 | Performs octal display of data on | in R1,R2 | REGISTER 1 and REGISTER 2 | |05 | Display octal comp 1,2,3 | Performs octal display of data on | in R1,R2,R3 | REGISTER 1, REGISTER 2, and REGISTER 3. | |06 | Display decimal in R1 or | Performs decimal display of data on | R1,R2 or R1,R2,R3 | appropriate registers. The scale | | factors, types of scale factor | | routines, and component information | | are stored within the machine for each | | noun which it is required to display | | in decimal. | |07 | Display DP decimal in R1,R2 | Performs a double precision decimal | | display of data on REGISTER 1 and | | REGISTER 2. It does no scale | | factoring. It merely performs a 10- | | character, fractional decimal | | conversion of two consecutive, erasable | | registers, using REGISTER 1 and | | REGISTER 2. The sign is placed in the | | REGISTER 1 sign position with the | | REGISTER 2 sign position remaining | | blank. It cannot be used with mixed | | nouns. Its intended use is primarily | | with "machine address to be specified" | | nouns. | |08 | (Spare) | | |09 | (Spare) | | |10 | (Spare) | | |11 | Monitor octal comp 1 in R1 | Performs octal display of updated data | | every 1/2 second on REGISTER 1. | |12 | Monitor octal comp 2 in R2 | Performs octal display of updated data | | every 1/2 second on REGISTER 1. | |13 | Monitor octal comp 3 in R3 | Performs octal display of updated data | | every 1/2 second on REGISTER 1. | |14 | Monitor octal comp 1,2 | Performs octal display of updated data | in R1,R2 | every 1/2 second on REGISTER 1 and | | REGISTER 2. | |15 | Monitor octal comp 1,2,3 | Performs octal display of updated data | in R1,R2,R3 | every 1/2 second on REGISTER 1, | | REGISTER 2, and REGISTER 3. | |
16 | Monitor decimal in R1 or | Performs decimal display of updated | R1,R2, or R1,R2,R3 | data every 1/2 second on appropriate | | registers. | |17 | Monitor DP decimal in R1,R2 | Performs double precision display of | | decimal data on REGISTER 1 and | | REGISTER 2. No scale factoring is | | performed. Provides 10-character, | | fractional decimal conversion of two | | consecutive erasable registers. The | | sign is placed in the sign-bit | | position of REGISTER 1. REGISTER 2 | | sign bit is blank. | |18 | (Spare) | | |19 | (Spare) | | |20 | (Spare) | | |21 | Load component 1 into R1 | Performs data loading. Octal | | quantities are unsigned. Decimal | | quantities are preceded by + or - | | sign. Data is displayed on REGISTER | | 1. | |22 | Load component 2 into R2 | Performs data loading. Octal | | quantities are unsigned. Decimal | | quantities are preceded by + or - | | sign. Data is displayed on REGISTER | | 2. | |23 | Load component 3 into R3 | Performs data loading. Octal | | quantities are unsigned. Decimal | | quantities are preceded by + or - | | sign. Data is displayed on REGISTER | | 3. | |24 | Load component 1,2 into | Performs data loading. Octal | R1,R2 | quantities are unsigned. Decimal | | quantities are preceded by + or - | | sign. Data is displayed on REGISTER | | 1 and REGISTER 2. | |25 | Load component 1,2,3 into | Performs data loading. Octal | R1,R2,R3 | quantities are unsigned. Decimal | | quantities are preceded by + or - | | sign. Data is displayed on REGISTER | | 1, REGISTER 2, and REGISTER 3. | |26 | (Spare) | | |27 | Display fixed memory | This verb is included to permit | | displaying the contents of fixed | | memory in any bank. Its intended use | | is for checking program ropes and the | | BANK positions of program ropes. | |28 | (Spare) | | |29 | (Spare) | | |30 | Request EXECUTIVE | Enters request to executive routine | (Used only during ground | for any machine address with priority | checkout.) | involved. This verb assumes that the | | desired priority has been loaded into | | bits 10-14 of the prio/delay register | | (noun 26). This verb is used with the | | noun, "machine address to be | | specified". The complete address of | | the desired location is then keyed in. | | (Refer to "Machine address to be | | specified" in paragraph on Verb/Noun | | Formats.) | |31 | Request WAITLIST | Enters request to "waitlist routine"
| (Used only during ground | for any machine address with delay | checkout.) | involved. This verb assumes that the | | desired number of 10-millisecond units | | of delay has been loaded into the low | | order bits of the prio/delay register | | (noun 26). This verb is used with the | | "machine address to be specified" noun. | | The complete address of the desired | | location is then keyed in. (Refer to | | "Machine address to be specified" in | | paragraph on Verb/Noun Formats.) | |32 | Recycle | | |33 | Proceed (without data) | Informs routine requesting data that | | the operator chooses not to load | | fresh data, but wishes the routine to | | continue as best it can with old data. | | Final decision for what action should | | be taken is left to the requesting | | routine. | |34 | Terminate | Informs routine requesting data to be | | loaded that the operator chooses not | | to load fresh data and wishes the | | routine to terminate. Final decision | | for what action should be taken is | | left to the requesting routine. If | | monitor is on, it is turned off. | |35 | Test lights | | |36 | Request fresh start | Initializes the program control | | software and the keyboard and display | | system program. | |37 | Change program (major mode) | Change to new major mode. (Refer to | | "Change major mode" in paragraph on | | Verb/Noun Formats.) | |;--------------------------------------------------------------------------
COLOSSUS EXTENDED VERBS (40-99 decimal)
Not implemented. Use of these verbs triggers the 'check fail ' indicator.
COLOSSUS NORMAL NOUNS (00-39 decimal)
This is adapted from the Apollo 204 accident report posted on multiple
web sites by Richard F. Drushel. The information has been changed as
necessary to be consistent with usage in COLOSSUS 249.
Noun | |Code | Description | Scale/Units | |01 | Specify machine address (frac) | .XXXXX FRAC | | .XXXXX FRAC | | .XXXXX FRAC | | 02 | Specify machine address (whole) | XXXXX INTEGER | | XXXXX INTEGER | | XXXXX INTEGER | | 03 | Specify machine address (degree) | XXX.XX DEG | | XXX.XX DEG | | XXX.XX DEG
| | 04 | (Spare) | | |05 | (Spare) | | |06 | (Spare) | | |07 | (Spare) | | |08 | (Spare) | | |09 | Alarm codes | OCT | | OCT | | OCT | |10 | (Spare) | | |11 | (Spare) | | |12 | (Spare) | | |13 | (Spare) | | |14 | (Spare) | | |15 | Increment address | OCT | | | |16 | (Spare) | | |17 | (Spare) | | |18 | (Spare) | | |19 | (Spare) | | |20 | (Spare) | | |21 | (Spare) | | |22 | (Spare) | | |23 | (Spare) | | |24 | (Spare) | | |25 | (Spare) | | |26 | Prio/delay, address | OCT (prio/delay) | | OCT (14-bit CADR) | | (not used) | |27 | (Spare) | | |28 | (Spare) | | |29 | (Spare) | | |30 | (Spare) | | |31 | (Spare) | | |32 | (Spare) | | |33 | (Spare) | | |34 | (Spare) | | |35 | (Spare) | | |36 | Time of CMC clock: | | REGISTER 1 | 00XXX. hours | REGISTER 2 | 000XX. minutes | REGISTER 3 | 0XX.XX seconds | |37 | (Spare) |
| |38 | (Spare) | | |39 | (Spare) | | |;--------------------------------------------------------------------------
COLOSSUS MIXED NOUNS (40-99 decimal)
Not implemented.
Flight software assembler listing
Block I Apollo Guidance Computer (AGC4) assembler version 1.6 for EPROM
First pass: generate symbol table.Second pass: generate object code.
;========================================================================== ; AGC (file:agc.asm) ; ; Version: 1.0 ; Author: John Pultorak ; Date: 6/7/2002 ; ; PURPOSE: ; AGC Block I demonstration. Includes most of the AGC operating system: ; WAITLIST, EXEC, PINBALL (DSKY routines), NOUN tables, VERB tables, ; bank intercommunication routines, the KEY, T3, and T4 interrupt handlers, ; and some dual precision (DP) math routines. ; ; The interpreter is not currently implemented. ; ; Where available, the source is from the Apollo 8 command module computer (CMC) ; load (called COLOSSUS). In cases where COLOSSUS source is not available, ; functionally equivalent code was constructed using COLOSSUS calling and return ; parameters and according to specifications in the technical reports given below. ; ; OPERATION: ; TBD. ; ; ERRATA: ; - Adapted for the AGC4R assembler. The assembler directives and syntax ; differ somewhat from the original AGC assembler. ; - some of the original source was missing from the COLOSSUS listing and ; had to be reverse engineered. Those portions probably differ somewhat ; from the original code in implementation, but should be functionally ; identical. ; - because the COLOSSUS source is for a block II AGC, but the AGC ; implemented here is block I, about 5% of COLOSSUS had to be translated ; to equivalent block I code. ; ; SOURCES: ; Information on the Block I architecture: instruction set, instruction ; sequences, registers, register transfers, control pulses, memory and ; memory addressing, I/O assignments, interrupts, and involuntary counters ; was obtained from: ; ; A. Hopkins, R. Alonso, and H. Blair-Smith, "Logical Description ; for the Apollo Guidance Computer (AGC4)", R-393, ; MIT Instrumentation Laboratory, Cambridge, MA, Mar. 1963. ; ; Supplementary AGC hardware information was obtained from: ; ; R. Alonso, J. H. Laning, Jr. and H. Blair-Smith, "Preliminary ; MOD 3C Programmer's Manual", E-1077, MIT Instrumentation ; Laboratory, Cambridge, MA, Nov. 1961. ; ; B. I. Savage and A. Drake, "AGC4 Basic Training Manual, Volume I", ; E-2052, MIT Instrumentation Laboratory, Cambridge, ; MA, Jan. 1967. ; ; E. C. Hall, "MIT's Role in Project Apollo, Volume III, Computer ; Subsystem", R-700, MIT Charles Stark Draper Laboratory, ; Cambridge, MA, Aug. 1972. ; ; A. Hopkins, "Guidance Computer Design, Part VI", source unknown. ; ; E, C. Hall, "Journey to the Moon: The History of the Apollo ; Guidance Computer", AIAA, Reston VA, 1996. ; ; AGC software information was obtained from: ; ; AGC Block II COLOSSUS rev 249 assembly listing, Oct 28, 1968. (A ; listing of the 1st 50% of the build. It encludes the entire ; eraseable memory, restart initialization, T4RUPT, and the ; entire set of DSKY routines. About 5% of instructions ; had to be converted from Block II to Block I). ; ; A. I. Green and J. J. Rocchio, "Keyboard and Display System Program ; for AGC (Program Sunrise)", E-1574, MIT Instrumentation ; Laboratory, Cambridge, MA, Aug. 1964. Contains detailed ; flowcharts and design materials for the DSKY software. ; ; A. Hopkins, R. Alonso, and H. Blair-Smith, "Logical Description ; for the Apollo Guidance Computer (AGC4)", R-393,
; MIT Instrumentation Laboratory, Cambridge, MA, Mar. 1963. ; Contains the software interfaces for EXEC and WAITLIST, and ; portions of the dual precision (DP) math library. ; ;========================================================================== INCL doc.asm ;========================================================================== ; AGC documentation (file:doc.asm) ; ; Version: 1.0 ; Author: John Pultorak ; Date: 06/01/2002 ; ; PURPOSE: ; Documents AGC ops source code. ;========================================================================== ;-------------------------------------------------------------------------- ; DSKY OPERATION (examples) ; ; verb/noun (V/N) flash: When the verb and noun indicators flash ; at 1Hz, the DSKY is waiting for keyboard input. ; ; ; Display elapsed time from the AGC clock: ; <VERB> <0> <6> <NOUN> <3> <6> <ENTER> ; ; Test display lights ; a) <VERB> <3> <5> <ENTER> ; b) all DSKY lamps and display segments illuminate for 5 sec. ; c) after 5 sec, the DSKY lamps extinguish ; ; Load component 1 for dataset at octal address 50 with octal 123 ; a) <VERB> <2> <1> <NOUN> <0> <1> <ENTER> ; b) verb/noun display flashes; waiting for address ; c) <5> <0> <ENTER> ; d) verb/noun display flash continues; waiting for data ; e) <1> <2> <3> <ENTER> ; f) octal word from R1 is loaded at address 50, ; ; Display component 1 of dataset at octal address 50: ; a) <VERB> <0> <1> <NOUN> <0> <1> <ENTER> ; b) verb/noun display flashes; waiting for address ; c) <5> <0> <ENTER> ; d) octal word from address 50 is displayed in R1 ; ; Load 3 component dataset at octal address 50 with octal values ; 123,456,701 ; a) <VERB> <2> <5> <NOUN> <0> <1> <ENTER> ; b) verb/noun display flashes; waiting for address ; c) <5> <0> <ENTER> ; d) verb/noun display flash continues; waiting for data ; e) <1> <2> <3> <ENTER> ; f) <4> <5> <6> <ENTER> ; g) <7> <0> <1> <ENTER> ; h) octal word from R1 is loaded at address 50, ; octal word from R2 is loaded at address 51, ; octal word from R3 is loaded at address 52 ; ; Display 3 component dataset beginning at address 50: ; a) <VERB> <0> <5> <NOUN> <0> <1> <ENTER> ; b) verb/noun display flashes; waiting for address ; c) <5> <0> <ENTER> ; d) octal word from address 50 is displayed in R1, ; octal word from address 51 is displayed in R2, ; octal word from address 52 is displayed in R3 ; ;-------------------------------------------------------------------------- ;-------------------------------------------------------------------------- ; COLOSSUS REGULAR VERBS (00-39 decimal) ; ; This is adapted from the Apollo 204 accident report posted on multiple ; web sites by Richard F. Drushel. The information has been changed as ; necessary to be consistent with usage in COLOSSUS. ; ; ; Verb | | ; Code | Description | Remarks ; | | ; 01 | Display octal comp 1 in R1 | Performs octal display of data on ; | | REGISTER 1. ; | | ; 02 | Display octal comp 2 in R2 | Performs octal display of data on
; | | REGISTER 1. ; | | ; 03 | Display octal comp 3 in R3 | Performs octal display of data on ; | | REGISTER 1. ; | | ; 04 | Display octal comp 1,2 | Performs octal display of data on ; | in R1,R2 | REGISTER 1 and REGISTER 2 ; | | ; 05 | Display octal comp 1,2,3 | Performs octal display of data on ; | in R1,R2,R3 | REGISTER 1, REGISTER 2, and REGISTER 3. ; | | ; 06 | Display decimal in R1 or | Performs decimal display of data on ; | R1,R2 or R1,R2,R3 | appropriate registers. The scale ; | | factors, types of scale factor ; | | routines, and component information ; | | are stored within the machine for each ; | | noun which it is required to display ; | | in decimal. ; | | ; 07 | Display DP decimal in R1,R2 | Performs a double precision decimal ; | | display of data on REGISTER 1 and ; | | REGISTER 2. It does no scale ; | | factoring. It merely performs a 10- ; | | character, fractional decimal ; | | conversion of two consecutive, erasable ; | | registers, using REGISTER 1 and ; | | REGISTER 2. The sign is placed in the ; | | REGISTER 1 sign position with the ; | | REGISTER 2 sign position remaining ; | | blank. It cannot be used with mixed ; | | nouns. Its intended use is primarily ; | | with "machine address to be specified" ; | | nouns. ; | | ; 08 | (Spare) | ; | | ; 09 | (Spare) | ; | | ; 10 | (Spare) | ; | | ; 11 | Monitor octal comp 1 in R1 | Performs octal display of updated data ; | | every 1/2 second on REGISTER 1. ; | | ; 12 | Monitor octal comp 2 in R2 | Performs octal display of updated data ; | | every 1/2 second on REGISTER 1. ; | | ; 13 | Monitor octal comp 3 in R3 | Performs octal display of updated data ; | | every 1/2 second on REGISTER 1. ; | | ; 14 | Monitor octal comp 1,2 | Performs octal display of updated data ; | in R1,R2 | every 1/2 second on REGISTER 1 and ; | | REGISTER 2. ; | | ; 15 | Monitor octal comp 1,2,3 | Performs octal display of updated data ; | in R1,R2,R3 | every 1/2 second on REGISTER 1, ; | | REGISTER 2, and REGISTER 3. ; | | ; 16 | Monitor decimal in R1 or | Performs decimal display of updated ; | R1,R2, or R1,R2,R3 | data every 1/2 second on appropriate ; | | registers. ; | | ; 17 | Monitor DP decimal in R1,R2 | Performs double precision display of ; | | decimal data on REGISTER 1 and ; | | REGISTER 2. No scale factoring is ; | | performed. Provides 10-character, ; | | fractional decimal conversion of two ; | | consecutive erasable registers. The ; | | sign is placed in the sign-bit ; | | position of REGISTER 1. REGISTER 2 ; | | sign bit is blank. ; | | ; 18 | (Spare) | ; | | ; 19 | (Spare) | ; | | ; 20 | (Spare) | ; | | ; 21 | Load component 1 into R1 | Performs data loading. Octal ; | | quantities are unsigned. Decimal ; | | quantities are preceded by + or - ; | | sign. Data is displayed on REGISTER ; | | 1. ; | | ; 22 | Load component 2 into R2 | Performs data loading. Octal ; | | quantities are unsigned. Decimal ; | | quantities are preceded by + or - ; | | sign. Data is displayed on REGISTER
; | | 2. ; | | ; 23 | Load component 3 into R3 | Performs data loading. Octal ; | | quantities are unsigned. Decimal ; | | quantities are preceded by + or - ; | | sign. Data is displayed on REGISTER ; | | 3. ; | | ; 24 | Load component 1,2 into | Performs data loading. Octal ; | R1,R2 | quantities are unsigned. Decimal ; | | quantities are preceded by + or - ; | | sign. Data is displayed on REGISTER ; | | 1 and REGISTER 2. ; | | ; 25 | Load component 1,2,3 into | Performs data loading. Octal ; | R1,R2,R3 | quantities are unsigned. Decimal ; | | quantities are preceded by + or - ; | | sign. Data is displayed on REGISTER ; | | 1, REGISTER 2, and REGISTER 3. ; | | ; 26 | (Spare) | ; | | ; 27 | Display fixed memory | This verb is included to permit ; | | displaying the contents of fixed ; | | memory in any bank. Its intended use ; | | is for checking program ropes and the ; | | BANK positions of program ropes. ; | | ; 28 | (Spare) | ; | | ; 29 | (Spare) | ; | | ; 30 | Request EXECUTIVE | Enters request to executive routine ; | (Used only during ground | for any machine address with priority ; | checkout.) | involved. This verb assumes that the ; | | desired priority has been loaded into ; | | bits 10-14 of the prio/delay register ; | | (noun 26). This verb is used with the ; | | noun, "machine address to be ; | | specified". The complete address of ; | | the desired location is then keyed in. ; | | (Refer to "Machine address to be ; | | specified" in paragraph on Verb/Noun ; | | Formats.) ; | | ; 31 | Request WAITLIST | Enters request to "waitlist routine" ; | (Used only during ground | for any machine address with delay ; | checkout.) | involved. This verb assumes that the ; | | desired number of 10-millisecond units ; | | of delay has been loaded into the low ; | | order bits of the prio/delay register ; | | (noun 26). This verb is used with the ; | | "machine address to be specified" noun. ; | | The complete address of the desired ; | | location is then keyed in. (Refer to ; | | "Machine address to be specified" in ; | | paragraph on Verb/Noun Formats.) ; | | ; 32 | Recycle | ; | | ; 33 | Proceed (without data) | Informs routine requesting data that ; | | the operator chooses not to load ; | | fresh data, but wishes the routine to ; | | continue as best it can with old data. ; | | Final decision for what action should ; | | be taken is left to the requesting ; | | routine. ; | | ; 34 | Terminate | Informs routine requesting data to be ; | | loaded that the operator chooses not ; | | to load fresh data and wishes the ; | | routine to terminate. Final decision ; | | for what action should be taken is ; | | left to the requesting routine. If ; | | monitor is on, it is turned off. ; | | ; 35 | Test lights | ; | | ; 36 | Request fresh start | Initializes the program control ; | | software and the keyboard and display ; | | system program. ; | | ; 37 | Change program (major mode) | Change to new major mode. (Refer to ; | | "Change major mode" in paragraph on ; | | Verb/Noun Formats.) ; | | ;--------------------------------------------------------------------------
;-------------------------------------------------------------------------- ; COLOSSUS EXTENDED VERBS (40-99 decimal) ; ; Not implemented. Use of these verbs triggers the 'check fail' indicator. ;-------------------------------------------------------------------------- ;-------------------------------------------------------------------------- ; COLOSSUS NORMAL NOUNS (00-39 decimal) ; ; This is adapted from the Apollo 204 accident report posted on multiple ; web sites by Richard F. Drushel. The information has been changed as ; necessary to be consistent with usage in COLOSSUS. ; ; ; Noun | | ; Code | Description | Scale/Units ; | | ; 01 | Specify machine address (frac) | .XXXXX FRAC ; | | .XXXXX FRAC ; | | .XXXXX FRAC ; | | ; 02 | Specify machine address (whole) | XXXXX INTEGER ; | | XXXXX INTEGER ; | | XXXXX INTEGER ; | | ; 03 | Specify machine address (degree) | XXX.XX DEG ; | | XXX.XX DEG ; | | XXX.XX DEG ; | | ; 04 | (Spare) | ; | | ; 05 | (Spare) | ; | | ; 06 | (Spare) | ; | | ; 07 | (Spare) | ; | | ; 08 | (Spare) | ; | | ; 09 | Alarm codes | OCT ; | | OCT ; | | OCT ; | | ; 10 | (Spare) | ; | | ; 11 | (Spare) | ; | | ; 12 | (Spare) | ; | | ; 13 | (Spare) | ; | | ; 14 | (Spare) | ; | | ; 15 | Increment address | OCT ; | | ; | | ; 16 | (Spare) | ; | | ; 17 | (Spare) | ; | | ; 18 | (Spare) | ; | | ; 19 | (Spare) | ; | | ; 20 | (Spare) | ; | | ; 21 | (Spare) | ; | | ; 22 | (Spare) | ; | | ; 23 | (Spare) | ; | | ; 24 | (Spare) | ; | | ; 25 | (Spare) | ; | | ; 26 | Prio/delay, address | OCT (prio/delay) ; | | OCT (14-bit CADR) ; | | (not used) ; | | ; 27 | (Spare) | ; | |
; 28 | (Spare) | ; | | ; 29 | (Spare) | ; | | ; 30 | (Spare) | ; | | ; 31 | (Spare) | ; | | ; 32 | (Spare) | ; | | ; 33 | (Spare) | ; | | ; 34 | (Spare) | ; | | ; 35 | (Spare) | ; | | ; 36 | Time of CMC clock: | ; | REGISTER 1 | 00XXX. hours ; | REGISTER 2 | 000XX. minutes ; | REGISTER 3 | 0XX.XX seconds ; | | ; 37 | (Spare) | ; | | ; 38 | (Spare) | ; | | ; 39 | (Spare) | ; | | ;-------------------------------------------------------------------------- ;-------------------------------------------------------------------------- ; COLOSSUS MIXED NOUNS (40-99 decimal) ; ; Not implemented. ;-------------------------------------------------------------------------- ;-------------------------------------------------------------------------- ; AGC ADDRESS ASSIGNMENTS ; ; Central Registers ; ; 000000 A accumulator ; 000001 Q subroutine return address ; 000002 Z program counter ; 000003 LP lower product register ; ; Input Registers ; ; 000004 IN0 ; 000005 IN1 ; 000006 IN2 ; 000007 IN3 ; ; Output Registers ; ; 000010 OUT0 ; 000011 OUT1 ; 000012 OUT2 ; 000013 OUT3 ; 000014 OUT4 ; ; Memory Bank Select ; ; 000015 BANK ; ; Interrupt Control ; ; 000016 RELINT re-enable interrupts ; 000017 INHINT inhibit interrupts ; ; Editing Registers ; ; 000020 CYR cycle right ; 000021 SR shift rRight ; 000022 CYL cycle left ; 000023 SL shift left ; ; Interrupt Storage Area ; ; 000024 ZRUPT save program counter (Z) ; 000025 BRUPT save B register ; 000026 ARUPT save accumulator (A) ; 000027 QRUPT save Q register ;
; 000030 - 000033 NOT USED ; ; Involuntary Counters ; ; 000034 OVCTR arithmetic overflow counter ; 000035 TIME2 AGC clock (high) ; 000036 TIME1 AGC clock (low) ; 000037 TIME3 WAITLIST (T3) timer ; 000040 TIME4 DISPLAY (T4) timer ; ; Involuntary Counters -- currently unused ; ; 000041 - 000056 NOT USED ; ; Eraseable Memory ; ; 000057 - 001777 ; ; Start of fixed memory ; ; 002000 GOPROG AGC (re)start vector ; ; 002004 T3RUPT interrupt vector for TIME3 (T3RUPT) ; 020010 ERRUPT interrupt vector ; 020014 DSRUPT interrupt vector for DSRUPT (T4RUPT) ; 020020 KEYRUPT interrupt vector for keyboard ; 020024 UPRUPT interrupt vector for uplink ;-------------------------------------------------------------------------- ;-------------------------------------------------------------------------- ; AGC TABLES (name, file, description) ; ; Keyboard/display ; CHARIN2 bank40_1.asm keyboard character table ; INRELTAB bank40_1.asm DSKY register/display table map ; DSPTAB dsky_e.asm display table for DSKY ; ; Verbs: ; VERBTAB bank41_1.asm regular verb routines (00-39) ; ; Nouns: ; NNADTAB bank42_3.asm noun address table (00-99) ; NNTYPTAB bank42_3.asm noun type table (00-99) ; SFINTAB bank42_3.asm noun input scale factor select ; SFOUTAB bank42_3.asm nout output scale factor select ; IDADDTAB bank42_3.asm mixed noun address table (40-99) ; RUTMXTAB bank42_3.asm mixed noun scale factor routine (40-99) ; ; Noun scale factor routines: ; SFOUTABR bank41_1.asm scale factor output routines ; SFINTABR bank41_2.asm scale factor input routines ; ; Major Modes: ; FCADRMM bank04_1.asm entry points for MM jobs ; EPREMM1 bank04_1,asm priorities for MM jobs ;-------------------------------------------------------------------------- ; ERASEABLE MEMORY DECLARATIONS ORG BANK0 ; immediately following counters INCL waitlist_e.asm ; WAITLIST variables ;========================================================================== ; WAITLIST (file:waitlist_e.asm) ; ; Version: 1.0 ; Author: John Pultorak ; Date: 11/15/2001 ; ; PURPOSE: ; Eraseable memory variables and structures for the WAITLIST. See the ; WAITLIST source code file for more information. ;========================================================================== MAXTASK EQU 7 ; max number of tasks MAXVAL EQU %037777 ; largest pos 15-bit int (+16383 dec) MAXDELAY EQU 12000 ; 120 seconds (in .01 sec ticks) MAXTIMEOUT EQU MAXVAL-MAXDELAY+1 ; TIME3 setting for MAXDELAY ; task delta t: number of 10 mSec ticks until timeout. ; i.e.: 0=timeout, 1=10mS until timeout, 2=20mS until timeout... ; maximum time delay is 120 (decimal) seconds. ;
; If a task record is empty (unused), the address is always set to ; zero and the time is set to MAXDELAY. ; task record structure TSKTIME EQU 0 ; offset to task delta time TSKADDR EQU 1 ; offset to 14-bit task address TRECSZ EQU 2 ; size of task record (words) ; Array of all task records WL_taskList EQU * 00057 0057 00000 1 DS 0 ; record 000060 0060 00000 1 DS 0 00061 0061 00000 1 DS 0 ; record 100062 0062 00000 1 DS 0 00063 0063 00000 1 DS 0 ; record 200064 0064 00000 1 DS 0 00065 0065 00000 1 DS 0 ; record 300066 0066 00000 1 DS 0 00067 0067 00000 1 DS 0 ; record 400070 0070 00000 1 DS 0 00071 0071 00000 1 DS 0 ; record 500072 0072 00000 1 DS 0 00073 0073 00000 1 DS 0 ; record 600074 0074 00000 1 DS 0 00075 0075 00000 1 WL_IN_saveQ DS 0 ; return address00076 0076 00000 1 WL_IN_taskPtr DS 0 ; points to task rec in list00077 0077 00000 1 WL_IN_loopCnt DS 0 ; loop counter 00100 0100 00000 1 WL_AT_saveQ DS 0 ; return address00101 0101 00000 1 WL_AT_taskPtr DS 0 ; points to task rec in list00102 0102 00000 1 WL_AT_newTime DS 0 ; time to be inserted00103 0103 00000 1 WL_AT_timeLeft DS 0 ; time remaining until timeout00104 0104 00000 1 WL_AT_loopCnt DS 0 ; loop counter 00105 0105 00000 1 WL_T3_saveQ DS 0 ; return address00106 0106 00000 1 WL_T3_oldBank DS 0 ; current bank 00107 0107 00000 1 WL_ST_saveQ DS 0 ; return address00110 0110 00000 1 WL_ST_taskPtr DS 0 ; points to task rec in list00111 0111 00000 1 WL_ST_newTime DS 0 ; time-out time00112 0112 00000 1 WL_ST_loopCnt DS 0 ; loop counter 00113 0113 00000 1 WL_RT_saveQ DS 0 ; return address00114 0114 00000 1 WL_RT_runAddr DS 0 ; address of task to run 00115 0115 00000 1 WL_RM_saveQ DS 0 ; return address00116 0116 00000 1 WL_RM_taskPtr DS 0 ; points to task rec in list00117 0117 00000 1 WL_RM_taskPtr2 DS 0 ; points to task rec behind taskPtr00120 0120 00000 1 WL_RM_loopCnt DS 0 ; loop counter00121 0121 00000 1 WL_RM_retval DS 0 ; tmp store for return value 00122 0122 00000 1 WL_IS_newTime DS 0 ; INPUT: time to be inserted00123 0123 00000 1 WL_IS_newAddr DS 0 ; INPUT: address to be inserted00124 0124 00000 1 WL_IS_saveQ DS 0 ; return address00125 0125 00000 1 WL_IS_taskPtr DS 0 ; points to task rec in list00126 0126 00000 1 WL_IS_taskPtr2 DS 0 ; points to task rec ahead of taskPtr00127 0127 00000 1 WL_IS_loopCnt DS 0 ; loop counter INCL exec_e.asm ; EXEC variables ;========================================================================== ; EXEC (file:exec_e.asm) ; ; Version: 1.0 ; Author: John Pultorak ; Date: 04/26/2002 ; ; PURPOSE: ; Eraseable memory variables and structures for the EXEX. See the EXEC ; source code file for more information. ; ; The COLOSSUS version of this is on p. 70. ; ; ERRATA: The current version of the EXEC does not set the BANKSET parameter. ; Instead, it stores the 14-bit CADR in LOC. Also, the JOBPRIOBASE field ; has been added. ;==========================================================================
MAXJOBS EQU 7 ; max number jobs (not incl current job) JRECSZ EQU 13 ; size of job record (words) ; (COLOSSUS, p. 70) ; dynamically allocated core sets for EXEC jobs (8 sets) ; record for current (running) job ; Job priority: 0=no job, 1=lowest priority job, 2=... EX_currentJob EQU * MPAC EQU * ; multi-purpose accumulator00130 0130 00000 1 DS 0 00131 0131 00000 1 DS 0 00132 0132 00000 1 DS 0 00133 0133 00000 1 DS 0 00134 0134 00000 1 DS 0 00135 0135 00000 1 DS 0 00136 0136 00000 1 DS 0 00137 0137 00000 1 MODE DS 0 ; +1 for TP, +0 for DP, or -1 for vector00140 0140 00000 1 LOC DS 0 ; location associated with job00141 0141 00000 1 BANKSET DS 0 ; usually contains bank setting00142 0142 00000 1 PUSHLOC DS 0 ; word of packed interpretive parameters00143 0143 00000 1 PRIORITY DS 0 ; priority of present job and work area00144 0144 00000 1 JOBPRIOBASE DS 0 ; nominal job priority ; records for additional jobs waiting to run JREC0 EQU * ORG JREC0+JRECSZ JREC1 EQU * ORG JREC1+JRECSZ JREC2 EQU * ORG JREC2+JRECSZ JREC3 EQU * ORG JREC3+JRECSZ JREC4 EQU * ORG JREC4+JRECSZ JREC5 EQU * ORG JREC5+JRECSZ JREC6 EQU * ORG JREC6+JRECSZ ; sorted list of jobs to run. The list is sorted by job priority ; with the highest priority job at the top of the list. Each ; entry on the list is a word index to a job record; the indexes are ; relative to 'EX_currentJob', but the current job is not on the ; list. EX_jobList EQU * ORG EX_jobList+MAXJOBS LOCCTR EQU EX_jobList ; index to next job record CHGJOB EQU 1 ; change jobs at next opportunity KEEPJOB EQU 0 ; keep the same job00307 0307 00000 1 newJob DS 0 ; change flag (set to CHGJOB or KEEPJOB) 00310 0310 00000 1 EX_JW_saveQ DS 0 ; return address00311 0311 00000 1 EX_JW_loopCnt DS 0 ; loop counter00312 0312 00000 1 EX_JW_CADR DS 0 ; address of job to wake00313 0313 00000 1 EX_JW_foundit DS 0 ; 0=job not found, 1=found00314 0314 00000 1 EX_JW_jobPtr DS 0 ; points to job rec in list00315 0315 00000 1 EX_JW_jobPtr2 DS 0 ; points to job rec ahead of jobPtr00316 0316 00000 1 EX_JW_fndIndx DS 0 ; index to awoken record 00317 0317 00000 1 EX_AJ_saveQ DS 0 ; return address00320 0320 00000 1 EX_AJ_loopCnt DS 0 ; loop counter00321 0321 00000 1 EX_AJ_jobPrio DS 0 ; priority of new job00322 0322 00000 1 EX_AJ_jobPtr DS 0 ; initialized to EX_jobList at startup00323 0323 00000 1 EX_AJ_field DS 0 ; index to field from start of record00324 0324 00000 1 EX_AJ_findx DS 0 ; total index to field
00325 0325 00000 1 EX_IN_saveQ DS 0 ; return address00326 0326 00000 1 EX_IN_loopCnt DS 0 ; loop counter00327 0327 00000 1 EX_IN_jobPtr DS 0 ; points to job rec in list00330 0330 00000 1 EX_IN_recIndex DS 0 ; record index init counter00331 0331 00000 1 EX_IN_field DS 0 ; index to field from start of record00332 0332 00000 1 EX_IN_findx DS 0 ; total index to field 00333 0333 00000 1 EX_MN_runAddr DS 0 ; address of job to run00334 0334 00000 1 EX_MN_field DS 0 ; index to field from start of record00335 0335 00000 1 EX_MN_findx DS 0 ; total index to field 00336 0336 00000 1 EX_RM_saveQ DS 0 ; return address00337 0337 00000 1 EX_RM_jobPtr DS 0 ; points to job rec in list00340 0340 00000 1 EX_RM_jobPtr2 DS 0 ; points to job rec behind jobPtr00341 0341 00000 1 EX_RM_savePtr DS 0 ; tmp store for index taken off list00342 0342 00000 1 EX_RM_loopCnt DS 0 ; loop counter00343 0343 00000 1 EX_RM_retval DS 0 ; tmp store for return value00344 0344 00000 1 EX_RM_field DS 0 ; index to field from start of record00345 0345 00000 1 EX_RM_findx DS 0 ; total index to field 00346 0346 00000 1 EX_IS_newPrio DS 0 ; INPUT: priority to be inserted00347 0347 00000 1 EX_IS_newPrioB DS 0 ; INPUT: nominal priority to be inserted00350 0350 00000 1 EX_IS_newLoc DS 0 ; INPUT: address to be inserted00351 0351 00000 1 EX_IS_saveQ DS 0 ; return address00352 0352 00000 1 EX_IS_jobPtr DS 0 ; points to job rec in list00353 0353 00000 1 EX_IS_jobPtr2 DS 0 ; points to job rec ahead of jobPtr00354 0354 00000 1 EX_IS_loopCnt DS 0 ; loop counter INCL dsky_e.asm ; DSKY variables ;========================================================================== ; DSKY (file:dsky_e.asm) ; ; Version: 1.0 ; Author: John Pultorak ; Date: 12/14/2001 ; ; PURPOSE: ; Eraseable memory variables and structures for the DSKY. See the EXEC ; source code file for more information. ; ; Adapted from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968. ;========================================================================== 00355 0355 00000 1 FLAGWRD5 DS 0 ; GENERAL ERASABLE ASSIGNMENTS ; (COLOSSUS, p. 66) ; interrupt temporary storage pool ; (ITEMP1 through RUPTREG4) 00356 0356 00000 1 ITEMP1 DS 0 WAITEXIT EQU ITEMP1 EXECTEM1 EQU ITEMP1 00357 0357 00000 1 ITEMP2 DS 0 WAITBANK EQU ITEMP2 EXECTEM2 EQU ITEMP2 00360 0360 00000 1 ITEMP3 DS 0 RUPTSTOR EQU ITEMP3 WAITADR EQU ITEMP3 NEWPRIO EQU ITEMP3 00361 0361 00000 1 ITEMP4 DS 0 ;LOCCTR EQU ITEMP4 ; moved to EXEC WAITTEMP EQU ITEMP4 00362 0362 00000 1 ITEMP5 DS 0 NEWLOC EQU ITEMP5 00363 0363 00000 1 ITEMP6 DS 0 NEWLOCP1 EQU ITEMP6 ; DP address 00364 0364 00000 1 NEWJOB DS 0 ; COLOSSUS: must be at loc 68 due to wiring00365 0365 00000 1 RUPTREG1 DS 0 00366 0366 00000 1 RUPTREG2 DS 0 00367 0367 00000 1 RUPTREG3 DS 0 00370 0370 00000 1 RUPTREG4 DS 0 KEYTEMP1 EQU RUPTREG4 DSRUPTEM EQU RUPTREG4 ; FLAGWORD reservations
STATE EQU * ; 12 words00371 0371 00000 1 DS 0 00372 0372 00000 1 DS 0 00373 0373 00000 1 DS 0 00374 0374 00000 1 DS 0 00375 0375 00000 1 DS 0 00376 0376 00000 1 DS 0 00377 0377 00000 1 DS 0 00400 0400 00000 1 DS 0 00401 0401 00000 1 DS 0 00402 0402 00000 1 DS 0 00403 0403 00000 1 DS 0 00404 0404 00000 1 DS 0 FLAGFILL EQU * ; space for future flags00405 0405 00000 1 DS 0 00406 0406 00000 1 DS 0 00407 0407 00000 1 DS 0 00410 0410 00000 1 DS 0 ; pad load for DAPs ; (COLOSSUS, p. 67) EMDOT EQU FLAGFILL ; exit for VB3 STATEXIT EQU FLAGFILL+2 ; EXEC temporaries which may be used between CCS NEWJOBS. ; (INTB15P through RUPTMXM) 00411 0411 00000 1 INTB15P DS 0 ; reflects 15th bit of indexable addresses DSEXIT EQU INTB15P ; return for DSPIN EXITEM EQU INTB15P ; return for scale factor routine select BLANKRET EQU INTB15P ; return for 2BLANK 00412 0412 00000 1 INTBIT15 DS 0 ; similar to above WRDRET EQU INTBIT15 ; return for 5BLANK WDRET EQU INTBIT15 ; return for DSPWD DECRET EQU INTBIT15 ; return for PUTCOM (dec load) _2122REG EQU INTBIT15 ; temp for CHARIN ; The registers between ADDRWD and PRIORITY must stay in the following order ; for interpretive trace. 00413 0413 00000 1 ADDRWD DS 0 ; 12 bit interpretive operand subaddress00414 0414 00000 1 POLISH DS 0 ; holds CADR made from POLISH address UPDATRET EQU POLISH ; return for UPDATNN, UPDATVB CHAR EQU POLISH ; temp for CHARIN ERCNT EQU POLISH ; counter for error light reset DECOUNT EQU POLISH ; counter for scaling and display (dec) 00415 0415 00000 1 FIXLOC DS 0 ; work area address00416 0416 00000 1 OVFIND DS 0 ; set non-zero on overflow VBUF EQU * ; temporary storage used for vectors00417 0417 00000 1 DS 0 00420 0420 00000 1 DS 0 00421 0421 00000 1 DS 0 00422 0422 00000 1 DS 0 00423 0423 00000 1 DS 0 00424 0424 00000 1 DS 0 SGNON EQU VBUF ; temp for +,- on NOUNTEM EQU VBUF ; counter for MIXNOUN fetch DISTEM EQU VBUF ; counter for octal display verbs DECTEM EQU VBUF ; counter for fetch (dec display verbs) SGNOFF EQU VBUF+1 ; temp for +,- off NVTEMP EQU VBUF+1 ; temp for NVSUB SFTEMP1 EQU VBUF+1 ; storage for SF const hi part(=SFTEMP2-1) HITEMIN EQU VBUF+1 ; temp for load of hrs, min, sec ; must = LOWTEMIN-1 CODE EQU VBUF+2 ; for DSPIN SFTEMP2 EQU VBUF+2 ; storage for SF const low part(=SFTEMP1+1) LOWTEMIN EQU VBUF+2 ; temp for load of hrs, min, sec ; must = HITEMIN+1 ; (COLOSSUS, p. 68) MIXTEMP EQU VBUF+3 ; for MIXNOUN data SIGNRET EQU VBUF+3 ; return for +,- on ; Also, MIXTEMP+1 = VBUF+4, MIXTEMP+2 = VBUF+5 BUF EQU * ; temporary scalar storage
00425 0425 00000 1 DS 0 00426 0426 00000 1 DS 0 00427 0427 00000 1 DS 0 00430 0430 00000 1 BUF2 DS 0 00431 0431 00000 1 DS 0 INDEXLOC EQU BUF ; contains address of specified index SWWORD EQU BUF ; address of switch word SWBIT EQU BUF+1 ; switch bit within switch word00432 0432 00000 1 MPTEMP DS 0 ; temporary used in multiply and shift DMPNTEMP EQU MPTEMP ; DMPSUB temporary00433 0433 00000 1 DOTINC DS 0 ; component increment for DOT subroutine DVSIGN EQU DOTINC ; determines sign of DDV result ESCAPE EQU DOTINC ; used in arcsin/arccos ENTRET EQU DOTINC ; exit from enter 00434 0434 00000 1 DOTRET DS 0 ; return from DOT subroutine DVNORMCT EQU DOTRET ; dividend normalization count in DDV ESCAPE2 EQU DOTRET ; alternate arcsin/arccos switch WDCNT EQU DOTRET ; char counter for DSPWD INREL EQU DOTRET ; input buffer selector (X,Y,Z REG) 00435 0435 00000 1 MATINC DS 0 ; vector increment in MXV and VXM MAXDVSW EQU MATINC ; +0 if DP quotient is near one - else -1 POLYCNT EQU MATINC ; polynomial loop counter DSPMMTEM EQU MATINC ; DSPCOUNT save for DSPMM MIXBR EQU MATINC ; indicator for mixed or normal noun 00436 0436 00000 1 TEM1 DS 0 ; EXEC temp POLYRET EQU TEM1 DSREL EQU TEM1 ; rel address for DSPIN 00437 0437 00000 1 TEM2 DS 0 ; EXEC temp DSMAG EQU TEM2 ; magnitude store for DSPIN IDADDTEM EQU TEM2 ; mixnoun indirect address store 00440 0440 00000 1 TEM3 DS 0 ; EXEC temp COUNT EQU TEM3 ; for DSPIN 00441 0441 00000 1 TEM4 DS 0 ; EXEC temp LSTPTR EQU TEM4 ; list pointer for GRABUSY RELRET EQU TEM4 ; return for RELDSP FREERET EQU TEM4 ; return for FREEDSP DSPWDRET EQU TEM4 ; return for DSPSIGN SEPSCRET EQU TEM4 ; return for SEPSEC SEPMNRET EQU TEM4 ; return for SEPMIN 00442 0442 00000 1 TEM5 DS 0 ; EXEC temp NOUNADD EQU TEM5 ; temp storage for noun address ; (COLOSSUS, p. 69) 00443 0443 00000 1 NNADTEM DS 0 ; temp for noun address table entry00444 0444 00000 1 NNTYPTEM DS 0 ; temp for noun type table entry00445 0445 00000 1 IDAD1TEM DS 0 ; temp for indir address table entry (MIXNN) ; must - IDAD2TEM-1, = IDAD3TEM-200446 0446 00000 1 IDAD2TEM DS 0 ; temp for indir address table entry (MIXNN) ; must - IDAD2TEM+1, = IDAD3TEM-100447 0447 00000 1 IDAD3TEM DS 0 ; temp for indir address table entry (MIXNN) ; must - IDAD1TEM+2, = IDAD2TEM+100450 0450 00000 1 RUTMXTEM DS 0 ; temp for SF rout table entry (MIXNN only) ; AX*SR*T storage DEXDEX EQU TEM2 ; B(1) tmp DEX1 EQU TEM3 ; B(1) tmp DEX2 EQU TEM4 ; B(1) tmp RTNSAVER EQU TEM5 ; B(1) tmp TERM1TMP EQU BUF2 ; B(2) tmp ; (COLOSSUS, p. 70) Note: the eraseable memory for the EXEC. ; Moved to the EXEC area ; (COLOSSUS, p. 72) ; unswitched for display interface routines 00451 0451 00000 1 RESTREG DS 0 ; B(1) prm for display starts00452 0452 00000 1 NVWORD DS 0 00453 0453 00000 1 MARXNV DS 0 00454 0454 00000 1 NVSAVE DS 0 ; (retain the order of CADRFLSH to FAILREG+2 for downlink purposes)00455 0455 00000 1 CADRFLSH DS 0 ; B(1) tmp00456 0456 00000 1 CADRMARK DS 0 ; B(1) tmp
00457 0457 00000 1 TEMPFLSH DS 0 ; B(1) tmp 00460 0460 00000 1 FAILREG DS 0 ; B(3) prm 3 alarm-abort user=S 2CADR00461 0461 00000 1 DS 0 00462 0462 00000 1 DS 0 ; (COLOSSUS, p. 73) ; verb 37 storage 00463 0463 00000 1 MINDEX DS 0 ; B(1) tmp index for major mode00464 0464 00000 1 MMNUMBER DS 0 ; B(1) tmp major mode requested via V37 ; pinball interrupt storage 00465 0465 00000 1 DSPCNT DS 0 ; B(1) prm DSPOUT counter ; pinball executive action 00466 0466 00000 1 DSPCOUNT DS 0 ; display position indicator00467 0467 00000 1 DECBRNCH DS 0 ; Bits2,1: octal=0, +dec=1, -dec=2 ; Bit5=R1 (dec), Bit4=R2 (dec), Bit3=R3 (dec)00470 0470 00000 1 VERBREG DS 0 ; verb code00471 0471 00000 1 NOUNREG DS 0 ; noun code00472 0472 00000 1 XREG DS 0 ; R1 input buffer00473 0473 00000 1 YREG DS 0 ; R2 input buffer00474 0474 00000 1 ZREG DS 0 ; R3 input buffer00475 0475 00000 1 XREGLP DS 0 ; low part of XREG (for ded conv only)00476 0476 00000 1 YREGLP DS 0 ; low part of YREG (for ded conv only) HITEMOUT EQU YREGLP ; temp for display of HRS, MIN, SEC ; must equal LOTEMOUT-100477 0477 00000 1 ZREGLP DS 0 ; low part of ZREG (for ded conv only) LOTEMOUT EQU ZREGLP ; temp for display of HRS, MIN, SEC ; must equal HITEMOUT+1 ; (COLOSSUS, p. 74) 00500 0500 00000 1 MODREG DS 0 ; mode code00501 0501 00000 1 DSPLOCK DS 0 ; keyboard/subroutine call interlock00502 0502 00000 1 REQRET DS 0 ; return register for load00503 0503 00000 1 LOADSTAT DS 0 ; status indicator for LOADTST00504 0504 00000 1 CLPASS DS 0 ; pass indicator clear00505 0505 00000 1 NOUT DS 0 ; activity counter for DSPTAB00506 0506 00000 1 NOUNCADR DS 0 ; machine CADR for noun00507 0507 00000 1 MONSAVE DS 0 ; N/V code for monitor (= MONSAVE1 - 1)00510 0510 00000 1 MONSAVE1 DS 0 ; NOUNCADR for monitor (MATBS) = MONSAVE + 100511 0511 00000 1 MONSAVE2 DS 0 ; NVMONOPT options ; The 11 register table for the display panel (COLOSSUS, p.74, p.306) ; comment key = RELADD: RELAYWD BIT11 BITS10-6 BITS5-1 DSPTAB EQU * 00512 0512 00000 1 DS 0 ; 0: 0001 -R3 R3D4( 1) R3D5( 0)00513 0513 00000 1 DS 0 ; 1: 0010 +R3 R3D2( 3) R3D3( 2)00514 0514 00000 1 DS 0 ; 2: 0011 --- R2D5( 5) R3D1( 4)00515 0515 00000 1 DS 0 ; 3: 0100 -R2 R2D3( 7) R2D4( 6)00516 0516 00000 1 DS 0 ; 4: 0101 +R2 R2D1(11) R2D2(10)00517 0517 00000 1 DS 0 ; 5: 0110 -R1 R1D4(13) R1D5(12)00520 0520 00000 1 DS 0 ; 6: 0111 +R1 R1D2(15) R1D3(14)00521 0521 00000 1 DS 0 ; 7: 1000 --- -------- R1D1(16)00522 0522 00000 1 DS 0 ; 8: 1001 --- ND1 (21) ND2 (20)00523 0523 00000 1 DS 0 ; 9: 1010 --- VD1 (23) VD2 (22)00524 0524 00000 1 DS 0 ; 10:1011 --- MD1 (25) MD1 (24)00525 0525 00000 1 DS 0 ; 11: C/S lights 00526 0526 00000 1 NVQTEM DS 0 ; NVSUB storage for calling address ; must = NVBNKTEM-100527 0527 00000 1 NVBNKTEM DS 0 ; NVSUB storage for calling bank ; must = NVQTEM+100530 0530 00000 1 VERBSAVE DS 0 ; needed for recycle00531 0531 00000 1 CADRSTOR DS 0 ; ENDIDLE storage00532 0532 00000 1 DSPLIST DS 0 ; waiting reg for DSP syst internal use00533 0533 00000 1 EXTVRACT DS 0 ; extended verb activity interlock 00534 0534 00000 1 DSPTEM1 DS 0 ; buffer storage area 1 (mostly for time)00535 0535 00000 1 DS 0 00536 0536 00000 1 DS 0 00537 0537 00000 1 DSPTEM2 DS 0 ; buffer storage area 2 (mostly for deg)00540 0540 00000 1 DS 0 00541 0541 00000 1 DS 0 DSPTEMX EQU DSPTEM2 ; B(2) S-S display buffer for external verbs NORMTEM1 EQU DSPTEM1 ; B(3) DSP normal display registers ; display for extended verbs OPTIONX EQU DSPTEMX ; B(2) extended verb option code N12(VB2)
; temp store for major mode change 00542 0542 00000 1 MMTEMP DS 0 ; T4RUPT Erasable 00543 0543 00000 1 DSRUPTSW DS 0 ; (COLOSSUS, p. 78)00544 0544 00000 1 T4RET DS 0 ; added, not part of COLOSSUS00545 0545 00000 1 DSPOUTRET DS 0 ; added, not part of COLOSSUS00546 0546 00000 1 DK_IN_saveQ DS 0 ; return for T4RUPT init ; Replacement for Block II LXCH instruction (not part of COLOSSUS) 00547 0547 00000 1 LXCH_LPRET DS 0 ; LP return address00550 0550 00000 1 LXCH_A DS 0 ; save A ; vars for KEYPROG 00551 0551 00000 1 KP_MPAC DS 0 ; Vars for DPTEST (not part of COLOSSUS) 00552 0552 00000 1 DPTEST_A DS 0 00553 0553 00000 1 DPTEST_Q DS 0 ; Vars for REQDATX, REQDATY, REQDATZ (not part of COLOSSUS) 00554 0554 00000 1 REQ_Q DS 0 ; Vars for SETNCADR (not part of COLOSSUS) 00555 0555 00000 1 SETNCADR_Q DS 0 ; Vars for ALLDC_OC (not part of COLOSSUS) 00556 0556 00000 1 ALLDC_OC_Q DS 0 ; Vars for SFRUTMIX (not part of COLOSSUS) 00557 0557 00000 1 SFRUTMIX_L DS 0 ; Vars for SFCONUM (not part of COLOSSUS) 00560 0560 00000 1 SFCONUM_L DS 0 ; vars for BLANKSUB (not part of COLOSSUS) 00561 0561 00000 1 BLANKSUB_Q DS 0 ; Vars for GTSFOUT, GTSFIN (not part of COLOSSUS) 00562 0562 00000 1 GTSF_RET DS 0 ; Vars for FIXRANGE (not part of COLOSSUS) 00563 0563 00000 1 FR_RETQ DS 0 ; Vars for NVSUB (not part of COLOSSUS) 00564 0564 00000 1 NVSUB_L DS 0 00565 0565 00000 1 NVSUB_A DS 0 ; Vars for ENDIDLE (not part of COLOSSUS) 00566 0566 00000 1 ENDIDLE_L DS 0 ; Vars for NVSUBUSY (not part of COLOSSUS) 00567 0567 00000 1 NBSUBSY1_L DS 0 ; Vars for FLASHON/FLASHOFF (not part of COLOSSUS) 00570 0570 00000 1 FLASHRET DS 0 ; vars for PASTEVB (not part of COLOSSUS) 00571 0571 00000 1 PASTE_TMP DS 0
; vars for NEWMODEA (not part of COLOSSUS) 00572 0572 00000 1 NEWMODEA_Q DS 0 ; Vars for MATH LIB (not part of COLOSSUS) 00573 0573 00000 1 SHORTMP_A DS 0 00574 0574 00000 1 SHORTMP_OVFL DS 0 00575 0575 00000 1 SHORTMP_OVFH DS 0 00576 0576 00000 1 ADDRWD1 DS 0 00577 0577 00000 1 MATH_Q DS 0 00600 0600 00000 1 PRSHRTMP_Q DS 0 ; KEYRUPT Eraseable 00601 0601 00000 1 KEYRET DS 0 ; added, not part of COLOSSUS 00602 0602 00000 1 SAVEQ DS 0 ; temp for return addr ; Bank intercommunication 00603 0603 00000 1 BJBANK DS 0 00604 0604 00000 1 BJRET DS 0 00605 0605 00000 1 PJBANK DS 0 00606 0606 00000 1 PJRET DS 0 00607 0607 00000 1 PJA DS 0 00610 0610 00000 1 BCBANK DS 0 00611 0611 00000 1 BCRET DS 0 00612 0612 00000 1 BCA DS 0 00613 0613 00000 1 MBCBANK DS 0 00614 0614 00000 1 MBCRET DS 0 00615 0615 00000 1 MBCA DS 0 00616 0616 00000 1 DCBANK DS 0 00617 0617 00000 1 DCRET DS 0 ; FIXED MEMORY DECLARATIONS ORG EXTENDER 05777 5777 47777 0 DS %47777 ; needed for EXTEND ;-------------------------------------------------------------------------- ; RESTART/INTERRUPT ENTRY POINTS ;-------------------------------------------------------------------------- ; Program (re)start ORG GOPROG 02000 2000 0 1,2126 0 TC goMAIN ; AGC (re)start begins here! ; Interrupt vectors ORG T3RUPT 02004 2004 5 0,0026 0 TS ARUPT ; TIME3 interrupt vector02005 2005 3 0,0001 0 XCH Q 02006 2006 5 0,0027 1 TS QRUPT 02007 2007 0 1,2034 1 TC goT3 ORG ERRUPT 02010 2010 5 0,0026 0 TS ARUPT 02011 2011 3 0,0001 0 XCH Q 02012 2012 5 0,0027 1 TS QRUPT 02013 2013 0 1,2036 0 TC goER ORG DSRUPT ; T4RUPT for DSKY display02014 2014 5 0,0026 0 TS ARUPT 02015 2015 3 0,0001 0 XCH Q 02016 2016 5 0,0027 1 TS QRUPT 02017 2017 0 1,2037 1 TC goDS ORG KEYRUPT ; DSKY keyboard interrupt vector02020 2020 5 0,0026 0 TS ARUPT 02021 2021 3 0,0001 0 XCH Q 02022 2022 5 0,0027 1 TS QRUPT 02023 2023 0 1,2041 0 TC goKEY ORG UPRUPT 02024 2024 5 0,0026 0 TS ARUPT 02025 2025 3 0,0001 0 XCH Q 02026 2026 5 0,0027 1 TS QRUPT 02027 2027 0 1,2043 1 TC goUP
; restore Q and A registers and resume endRUPT EQU * 02030 2030 3 0,0027 1 XCH QRUPT ; restore Q02031 2031 5 0,0001 0 TS Q 02032 2032 3 0,0026 0 XCH ARUPT ; restore A02033 2033 2 0,0000 1 RESUME ; resume normal program execution ;-------------------------------------------------------------------------- ; RUPT (INTERRUPT) SERVICE ROUTINES ; ; Upon entry, registers will contain these values: ; - ZRUPT: Prior contents of program counter (Z register). ; - BRUPT: Prior contents of B register. ; - ARUPT: Prior contents of accumulator (A register). ; - QRUPT: Prior contents of Q register. ; ; When the service routine is finished, jump to endRUPT to restore the A ; and Q registers. Call RESUME to restore Z and B, which causes a return ; to normal (non-interrupt) execution. Interrupts are disabled upon entry ; to the service routine; they are reenabled following RESUME. ;-------------------------------------------------------------------------- goT3 EQU * 02034 2034 0 1,2347 0 TCR WL_TIME3task ; handle T3RUPT for WAITLIST02035 2035 0 1,2030 0 TC endRUPT goER EQU * 02036 2036 0 1,2030 0 TC endRUPT goDS EQU * 02037 2037 0 2,4047 0 TCR T4PROG ; handle T4RUPT for DSKY display02040 2040 0 1,2030 0 TC endRUPT goKEY EQU * 02041 2041 0 2,4132 0 TCR KEYPROG ; handle keyrupt for keyboard entry02042 2042 0 1,2030 0 TC endRUPT goUP EQU * 02043 2043 0 1,2030 0 TC endRUPT ;-------------------------------------------------------------------------- ; FIXED MEMORY CONSTANTS ;-------------------------------------------------------------------------- 02044 2044 00200 0 ofbit DS %200 ; OUT1, bit 8 initiates standby 02045 2045 77777 0 NEG0 DS -0 02046 2046 77776 1 NEG1 DS -1 02047 2047 77775 1 NEG2 DS -2 02050 2050 00000 1 ZERO DS 0 02051 2051 00001 0 ONE DS 1 02052 2052 00002 0 TWO DS 2 02053 2053 00003 1 THREE DS 3 02054 2054 00004 0 FOUR DS 4 02055 2055 00005 1 FIVE DS 5 02056 2056 00006 1 SIX DS 6 02057 2057 00007 0 SEVEN DS 7 02060 2060 00012 1 TEN DS 10 02061 2061 00013 0 ELEVEN DS 11 ; must be in reverse order. Pinball treats this as a table ; and indexes thru it. 02062 2062 40000 0 BIT15 DS %40000 02063 2063 20000 0 BIT14 DS %20000 02064 2064 10000 0 BIT13 DS %10000 02065 2065 04000 0 BIT12 DS %04000 02066 2066 02000 0 BIT11 DS %02000 02067 2067 01000 0 BIT10 DS %01000 02070 2070 00400 0 BIT9 DS %00400 02071 2071 00200 0 BIT8 DS %00200 02072 2072 00100 0 BIT7 DS %00100 02073 2073 00040 0 BIT6 DS %00040 02074 2074 00020 0 BIT5 DS %00020 02075 2075 00010 0 BIT4 DS %00010 02076 2076 00004 0 BIT3 DS %00004 02077 2077 00002 0 BIT2 DS %00002 02100 2100 00001 0 BIT1 DS %00001 02101 2101 00177 0 LOW7 DS %00177 02102 2102 06000 1 bankAddr DS %6000 ; fixed-switchable addr range starts here02103 2103 01777 1 lowAddr DS %1777 ; mask for 10-bit address02104 2104 01400 1 OCT1400 DS %1400
02105 2105 00013 0 NOUTCON DS 11 02106 2106 37777 1 POSMAX DS %37777 ;------------------------------------------------------------------------- ; CLRMEM - INITIALIZE ERASEABLE MEMORY ; ; Uses QRUPT and ARUPT as scratchpad. This is OK, because interrupts ; are disabled anyway. All eraseable memory above the AGC clock (TIME1, ; TIME2) is cleared. The AGC clock is not cleared because this might ; be a restart or a startup from standby mode. ;------------------------------------------------------------------------- CLRMEM EQU * 02107 2107 3 0,0001 0 XCH Q 02110 2110 5 0,0027 1 TS QRUPT ; save return address 02111 2111 3 1,2123 0 XCH CLRMEM_WC ; init count of words to clear02112 2112 5 0,0026 0 TS ARUPT CLRMEM_CHK EQU * 02113 2113 1 0,0026 1 CCS ARUPT 02114 2114 0 1,2116 0 TC CLRMEM_WORD 02115 2115 0 0,0027 1 TC QRUPT ; return CLRMEM_WORD EQU * 02116 2116 5 0,0026 0 TS ARUPT 02117 2117 3 1,2050 0 CAF CLRMEM_VAL 02120 2120 2 0,0026 1 INDEX ARUPT 02121 2121 5 0,0037 0 TS CLRMEM_BADDR ; clear a word02122 2122 0 1,2113 0 TC CLRMEM_CHK ; done? CLRMEM_VAL EQU ZERO ; set memory to this value CLRMEM_BADDR EQU TIME3 ; base address to clear02123 2123 01741 1 CLRMEM_WC DS %1777-TIME3+1 ; clear everything >= TIME3 ;------------------------------------------------------------------------- ; FRESH START ; ; AGC starts executing here, following power-up, or restart. ;------------------------------------------------------------------------- 02124 2124 10000 0 V37BANK DS %10000 ; BANK (4) containg PREMM1, FCADRMM102125 2125 37600 0 SAMASK DS %37600 ; mask to zero lower 7 bits goMAIN EQU * SLAP1 EQU goMAIN ; entry for V36 (fresh start request) 02126 2126 2 0,0000 0 INHINT ; First, check for standby operation. Loosely based on the standby ; algorithm in R-393. Probably should flash the 'computer activity' ; light as well. 02127 2127 3 1,2071 0 CAF BIT8 ; add 2 to 7th power to AGC clock02130 2130 6 0,0036 1 AD TIME1 02131 2131 5 0,0036 1 TS TIME1 02132 2132 3 1,2050 0 CAF ZERO ; skipped on ovf and C(A) set to 102133 2133 6 0,0035 1 AD TIME2 ; bump TIME2 with overflow, if any02134 2134 5 0,0035 1 TS TIME2 02135 2135 3 1,2125 0 CAF SAMASK ; zero the LSBs of TIME102136 2136 7 0,0036 0 MASK TIME1 02137 2137 5 0,0036 1 TS TIME1 02140 2140 3 1,2044 0 XCH ofbit ; enable standby operation02141 2141 5 0,0011 1 TS OUT1 02142 2142 0 1,2107 0 TC CLRMEM ; clear everything but the AGC clock ; set fresh start major mode to P00 (AGC CMC idle) 02143 2143 3 1,2124 1 CAF V37BANK 02144 2144 5 0,0015 0 TS BANK ; bank for major mode tables 02145 2145 3 4,6046 0 CAF NOV37MM ; assumes BANK is set (above)02146 2146 5 0,0463 0 TS MINDEX ; index to P00 goMMchange EQU * 02147 2147 2 0,0000 0 INHINT ; inhibit interrupts ; Initialize WAITLIST and EXEC eraseable memory. Initialize DSKY eraseable
; memory (but don't initialize BANK or MINDEX; they are used to start the ; main job for this major mode. 02150 2150 0 1,3252 1 TCR EX_initEX ; initialize EXEC02151 2151 0 1,2204 0 TCR WL_initWL ; initialize WAITLIST02152 2152 0 2,4007 1 TCR DK_initDK ; initialize DSKY ; Start the major mode job. This is modified from COLOSSUS because block I ; doesn't have E-bank and my SPVAC interface is a little different from the ; original. The references to PREMM1 and FCADRMM1 assume that the BANK is ; set to the one containing those tables. V37XEQ EQU * 02153 2153 2 0,0000 0 INHINT 02154 2154 2 0,0463 1 INDEX MINDEX 02155 2155 3 4,6037 0 CAF PREMM1 02156 2156 5 0,0542 1 TS MMTEMP 02157 2157 7 2,4666 1 MASK HI5 ; obtain priority bits 15-1102160 2160 0 2,4640 1 TC RIGHT5 02161 2161 0 2,4640 1 TC RIGHT5 ; shift right to bits 5-102162 2162 5 0,0360 1 TS NEWPRIO ; store PRIO for SPVAC 02163 2163 2 0,0463 1 INDEX MINDEX 02164 2164 3 4,6030 1 CAF FCADRMM1 02165 2165 0 1,3075 0 TC SPVAC ; job CADR in C(A), job prio in NEWPRIO V37XEQC EQU * 02166 2166 3 1,2050 0 CAF ZERO ; was CA MMTEMP in Block II02167 2167 6 0,0542 1 AD MMTEMP ; upon return from FINDVAC, place the02170 2170 7 1,2101 1 MASK LOW7 ; new MM in MODREG (the low 7 bits of02171 2171 0 2,5036 1 TC NEWMODEA ; PHSERDT1) 02172 2172 0 2,5003 1 TC RELDSP ; release display ; Start the EXEC. 02173 2173 0 1,2656 0 TC EX_exec ; never returns ;------------------------------------------------------------------------- ; AGC LIBRARIES ; ; System services in fixed-fixed memory. ;------------------------------------------------------------------------- INCL waitlist_f.asm ; WAITLIST, incl. T3RUPT handler ;========================================================================== ; WAITLIST (file:waitlist_f.asm) ; ; Version: 1.0 ; Author: John Pultorak ; Date: 11/15/2001 ; ; PURPOSE: ; Constants and source code for WAITLIST. ; ; Non-preemptive interrupt timer routines, originally implemented by J. H. ; Laning, Jr. for AGC3 and later adapted for AGC4. Briefly discussed in ; R-393, which gives some of the software interfaces into the WAITLIST. ; This is my own recreation, and the internals may differ from the original. ; ; A task is scheduled for execution by calling 'WAITLIST' and ; furnishing the time-out time and starting address. ; L XCH TASK_TIMEOUT ; in 10 mSec ticks ; L+1 TC WAITLIST ; L+2 DS TASK_ADDRESS ; 14-bit address ; L+3 ... execution resumes here ; ; TASK_TIMEOUT = a positive integer from 1 - MAXDELAY that specifies the delay ; in 10 mSec ticks. Maximum delay is 12000 (2 minutes). ; TASK_ADDRESS = starting address of the task (14-bit address) ; ; WAITLIST can be called from from an interrupt, or from normal execution. ; It is the only public function of the waitlist. ; ; **** WARNING **** If WAITLIST is not called from an interrupt, be sure to ; inhibit interrupts before calling it to protect the integrity of the list. ; ; Tasks execute when TIME3 overflows and generates an interrupt (T3RUPT). ; The task executes during the interrupt. Tasks terminate themselves by ; jumping to TASKOVER. ; TC TASKOVER ; ; Because tasks execute during an interrupt, they should be fairly short. ; Tasks can initiate longer operations by scheduling a 'job' using EXEC.
;========================================================================== 02174 2174 00002 0 WL_taskRecSize DS TRECSZ ; size of a task record (words)02175 2175 00057 0 WL_tskLstStart DS WL_taskList ; starting address for task list02176 2176 00073 0 WL_tskLstEnd DS MAXTASK-1@TRECSZ+WL_taskList 02177 2177 00006 1 WL_numTasks DS MAXTASK-1 ; init loop counter for all tasks02200 2200 00005 1 WL_numTasks1 DS MAXTASK-2 ; init loop counter for all tasks - 1 02201 2201 37777 1 WL_maxVal DS MAXVAL 02202 2202 27340 0 WL_maxDelay DS MAXDELAY 02203 2203 10440 0 WL_maxTimeOut DS MAXTIMEOUT ;-------------------------------------------------------------------------- ; WL_initWL - INITIALIZE WAITLIST ; ; Subroutine initializes the eraseable memory segment for WAITLIST. ; Necessary in case the AGC is restarted. ; ; Note: the valid range for TIME3 is 10440 to 37777 (which spans ; 12000 (base 10) ticks, which corresponds to 120 seconds) ; positive overflow occurs at 40000, which triggers T3RUPT. ; TIME3 values of 0 to 10437 are illegal; these values occur ; after timeout when the counter overflows. TIME3 values in this ; range indicate that timeout has occurred and that T3RUPT is ; presently occuring, or is pending. ;-------------------------------------------------------------------------- WL_initWL EQU * 02204 2204 3 0,0001 0 XCH Q 02205 2205 5 0,0075 0 TS WL_IN_saveQ ; save return address 02206 2206 3 1,2203 1 CAF WL_maxTimeOut 02207 2207 5 0,0037 0 TS TIME3 ; Iterate through task list and initialize all records to NIL 02210 2210 3 1,2175 0 CAF WL_tskLstStart ; init pointer to start of list02211 2211 5 0,0076 0 TS WL_IN_taskPtr 02212 2212 3 1,2177 1 CAF WL_numTasks ; loop for number of tasks WL_IN_loop EQU * 02213 2213 5 0,0077 1 TS WL_IN_loopCnt 02214 2214 3 1,2202 0 CAF WL_maxDelay 02215 2215 2 0,0076 1 INDEX WL_IN_taskPtr 02216 2216 5 0,0000 1 TS TSKTIME 02217 2217 3 1,2050 0 CAF ZERO 02220 2220 2 0,0076 1 INDEX WL_IN_taskPtr 02221 2221 5 0,0001 0 TS TSKADDR 02222 2222 3 0,0076 0 XCH WL_IN_taskPtr ; bump task pointer back 1 record02223 2223 6 1,2174 1 AD WL_taskRecSize 02224 2224 5 0,0076 0 TS WL_IN_taskPtr 02225 2225 1 0,0077 0 CCS WL_IN_loopCnt ; done checking task list?02226 2226 0 1,2213 0 TC WL_IN_loop ; not yet 02227 2227 3 0,0075 0 XCH WL_IN_saveQ 02230 2230 5 0,0001 0 TS Q ; restore return address02231 2231 0 0,0000 0 RETURN ;-------------------------------------------------------------------------- ; WAITLIST - ADD TASK TO WAITLIST ; ; Subroutine adds a task to WL_taskList. The following conditions are ; true upon entry. ; 1) The task list is sorted so the next task scheduled for execution ; is at the front of the list. ; 2) If no tasks are currently scheduled, the task record at the front ; of the list will be NIL. ; 3) Unused (NIL) records in the task list have their time fields set to ; MAXDELAY and their address fields set to zero. ; 4) If any tasks are on the waitlist, the time field in that task's ; record will contain the remaining time AFTER the next timeout. The ; task scheduled for execution at timeout will have a time remaining ; of zero. ; Any other tasks that will execute at that time will also have a time of ; zero. Tasks that will execute some time in the future AFTER timeout ; will have nonzero times; these times indicate the additional time ; needed after the next timeout. ; ; This is the only 'public' function. It can be called from a job or from ; a task or other interrupt. It disables interrupts to maintain the integrity ; of the taskList.
;-------------------------------------------------------------------------- WAITLIST EQU * 02232 2232 5 0,0102 1 TS WL_AT_newTime ; save task time02233 2233 3 0,0001 0 XCH Q 02234 2234 5 0,0100 0 TS WL_AT_saveQ ; save return address-1 02235 2235 3 1,2050 0 CAF ZERO 02236 2236 2 1,2176 1 INDEX WL_tskLstEnd 02237 2237 6 0,0001 0 AD TSKADDR 02240 2240 1 0,0000 0 CCS A ; list full?02241 2241 0 1,2343 1 TC WL_AT_done ; >0 yes, so give up ; Calculate time remaining until currently scheduled time-out. 02242 2242 3 1,2050 0 CAF ZERO 02243 2243 6 0,0037 0 AD TIME3 ; get time02244 2244 5 0,0103 0 TS WL_AT_timeLeft ; save it, temporarily ; Did TIME3 recently overflow? If so, we are inside T3RUPT, or T3RUPT ; is pending. TIME3 values from 0 - 10437 are not legal, so they ; indicate that an overflow has occurred. 02245 2245 4 1,2203 0 CS WL_maxTimeOut 02246 2246 6 0,0103 0 AD WL_AT_timeLeft 02247 2247 1 0,0000 0 CCS A ; TIME3 recently overflowed?02250 2250 0 1,2264 0 TC WL_AT_noOvf ; >0 no02251 2251 0 1,2264 0 TC WL_AT_noOvf ; +0 no02252 2252 0 1,2254 0 TC *+2 ; <0 yes02253 2253 0 1,2264 0 TC WL_AT_noOvf ; -0 no ; TIME3 already timed-out, so we must be inside T3RUPT, or T3RUPT ; is pending. Just add the new task to the list. No time correction ; is necessary; the epoch is NOW. 02254 2254 3 1,2050 0 CAF ZERO 02255 2255 6 0,0102 1 AD WL_AT_newTime 02256 2256 5 0,0122 0 TS WL_IS_newTime ; set time field in new task record 02257 2257 2 0,0100 1 INDEX WL_AT_saveQ ; indirectly address WL_AT_saveQ02260 2260 3 0,0000 1 CAF 0 02261 2261 5 0,0123 1 TS WL_IS_newAddr ; set addr field in new task record 02262 2262 0 1,2473 0 TCR WL_insert ; add new task to task list02263 2263 0 1,2343 1 TC WL_AT_done ; TIME3 has not timed out yet. Calculate time remaining until timeout ; (timeout occurs when TIME3 overflows) WL_AT_noOvf EQU * 02264 2264 4 0,0103 1 CS WL_AT_timeLeft ; get -TIME302265 2265 6 1,2201 0 AD WL_maxVal 02266 2266 6 1,2051 1 AD ONE 02267 2267 5 0,0103 0 TS WL_AT_timeLeft ; time left = -TIME3 + %37777 + 1 ; Compare that time against the timeout for the new task. WL_AT_chkOrder EQU * 02270 2270 4 0,0102 0 CS WL_AT_newTime 02271 2271 6 0,0103 0 AD WL_AT_timeLeft 02272 2272 1 0,0000 0 CCS A ; compare new task to current02273 2273 0 1,2306 0 TC WL_AT_mkFirst ; >0 (make new task 1st)02274 2274 0 1,2276 0 TC *+2 ; +002275 2275 0 1,2276 0 TC *+1 ; <0 ; The new task does not need to run before the current time-out, so ; just add it to the list. Subtract the remaining time interval from the ; new task's time, so the new task will have the same epoch as the other ; tasks on the list. 02276 2276 4 0,0103 1 CS WL_AT_timeLeft 02277 2277 6 0,0102 1 AD WL_AT_newTime ; make epoch correction02300 2300 5 0,0122 0 TS WL_IS_newTime ; set time field in new task record 02301 2301 2 0,0100 1 INDEX WL_AT_saveQ ; indirectly address WL_AT_saveQ02302 2302 3 0,0000 1 CAF 0 02303 2303 5 0,0123 1 TS WL_IS_newAddr ; set addr field in new task record 02304 2304 0 1,2473 0 TCR WL_insert ; add new task to task list02305 2305 0 1,2343 1 TC WL_AT_done ; The new task needs to run prior to the current time-out. Add the time ; remaining to all tasks currently on the list to change their epoch ; to NOW. WL_AT_mkFirst EQU * 02306 2306 3 1,2175 0 CAF WL_tskLstStart ; set pointer to front of list
02307 2307 5 0,0101 1 TS WL_AT_taskPtr 02310 2310 3 1,2177 1 CAF WL_numTasks ; loop for number of tasks WL_AT_loop EQU * 02311 2311 5 0,0104 1 TS WL_AT_loopCnt 02312 2312 3 1,2050 0 CAF ZERO 02313 2313 2 0,0101 0 INDEX WL_AT_taskPtr 02314 2314 6 0,0001 0 AD TSKADDR 02315 2315 1 0,0000 0 CCS A ; end of list?02316 2316 0 1,2320 1 TC *+2 ; >0 no, so keep going02317 2317 0 1,2333 0 TC WL_AT_schTsk ; +0 yes, add the new task 02320 2320 3 1,2050 0 CAF ZERO 02321 2321 2 0,0101 0 INDEX WL_AT_taskPtr 02322 2322 6 0,0000 1 AD TSKTIME 02323 2323 6 0,0103 0 AD WL_AT_timeLeft ; time-out = time-out + timeLeft02324 2324 2 0,0101 0 INDEX WL_AT_taskPtr 02325 2325 5 0,0000 1 TS TSKTIME 02326 2326 3 0,0101 1 XCH WL_AT_taskPtr ; bump task pointer back 1 record02327 2327 6 1,2174 1 AD WL_taskRecSize 02330 2330 5 0,0101 1 TS WL_AT_taskPtr 02331 2331 1 0,0104 0 CCS WL_AT_loopCnt ; done fixing the times?02332 2332 0 1,2311 0 TC WL_AT_loop ; not yet ; Now that the tasks all share the same epoch, add the new task to the ; list and call the scheduler to schedule the next task. WL_AT_schTsk EQU * 02333 2333 3 1,2050 0 CAF ZERO 02334 2334 6 0,0102 1 AD WL_AT_newTime 02335 2335 5 0,0122 0 TS WL_IS_newTime ; set time field in new task record 02336 2336 2 0,0100 1 INDEX WL_AT_saveQ ; indirectly address WL_AT_saveQ02337 2337 3 0,0000 1 CAF 0 02340 2340 5 0,0123 1 TS WL_IS_newAddr ; set addr field in new task record 02341 2341 0 1,2473 0 TCR WL_insert ; add new task to task list 02342 2342 0 1,2417 1 TCR WL_schedTask ; schedule the next task WL_AT_done EQU * 02343 2343 3 0,0100 0 XCH WL_AT_saveQ 02344 2344 6 1,2051 1 AD ONE 02345 2345 5 0,0001 0 TS Q ; restore return address02346 2346 0 0,0000 0 RETURN ;-------------------------------------------------------------------------- ; WL_TIME3task - T3 TIMEOUT ; ; Perform WAITLIST activities when TIME3 times-out. Called by the ; T3 interrupt handler. ;-------------------------------------------------------------------------- WL_TIME3task EQU * 02347 2347 3 0,0001 0 XCH Q 02350 2350 5 0,0105 0 TS WL_T3_saveQ ; save return address02351 2351 3 0,0015 0 XCH BANK 02352 2352 5 0,0106 0 TS WL_T3_oldBank ; save current bank ; Execute all timed-out tasks. 02353 2353 0 1,2362 1 TCR WL_runTasks ; Set up TIME3 to overflow at the next task's time-out. ; Adjust the time-outs for all remaining tasks. 02354 2354 0 1,2417 1 TCR WL_schedTask 02355 2355 3 0,0106 0 XCH WL_T3_oldBank 02356 2356 5 0,0015 0 TS BANK ; restore previous bank02357 2357 3 0,0105 0 XCH WL_T3_saveQ 02360 2360 5 0,0001 0 TS Q ; restore return address02361 2361 0 0,0000 0 RETURN ;-------------------------------------------------------------------------- ; WL_runTasks - RUN TIMED-OUT TASK(S) ; ; Runs all tasks timed-out on WL_taskList. Tasks are removed ; from the list before they are run. ;-------------------------------------------------------------------------- WL_runTasks EQU * 02362 2362 3 0,0001 0 XCH Q 02363 2363 5 0,0113 1 TS WL_RT_saveQ ; save return address
; loop, checking the task on the front of the list. If it is ; timed out, remove it from the list and run it. WL_RT_loop EQU * 02364 2364 3 1,2050 0 CAF ZERO 02365 2365 2 1,2175 1 INDEX WL_tskLstStart 02366 2366 6 0,0000 1 AD TSKTIME 02367 2367 1 0,0000 0 CCS A ; task timed out?02370 2370 0 1,2414 1 TC WL_RT_done ; >0 no, so we are done02371 2371 0 1,2373 1 TC *+2 ; +002372 2372 0 1,2373 1 TC *+1 ; <0 ; This task has timed out, so run it. 02373 2373 0 1,2565 0 TCR WL_remove ; remove task from list02374 2374 5 0,0114 0 TS WL_RT_runAddr ; save 14-bit address of task to run ; The task address is always 14-bit, so check whether the address falls ; within erasable or fixed-fixed memory. If so, use it as-is; otherwise, ; set the bank register and change the address to 12-bit. 02375 2375 4 0,0000 0 COM ; -(14bitAddr)+%600002376 2376 6 1,2102 0 AD bankAddr 02377 2377 1 0,0000 0 CCS A ; task is bank addressed?02400 2400 0 1,2411 1 TC WL_RT_runIt ; >0 no, just run it, as is02401 2401 0 1,2403 1 TC *+2 ; +0 yes02402 2402 0 1,2403 1 TC *+1 ; <0 yes 02403 2403 3 1,2050 0 CAF ZERO 02404 2404 6 0,0114 0 AD WL_RT_runAddr 02405 2405 5 0,0015 0 TS BANK ; set the bank 02406 2406 7 1,2103 0 MASK lowAddr ; get lowest 10-bits of address02407 2407 6 1,2102 0 AD bankAddr ; set bits 11,12 for fixed-switchable02410 2410 5 0,0114 0 TS WL_RT_runAddr WL_RT_runIt EQU * 02411 2411 2 0,0114 1 INDEX WL_RT_runAddr ; apply indirect address to next instr.02412 2412 0 0,0000 1 TC 0 ; run the task TASKOVER EQU * ; task returns here02413 2413 0 1,2364 1 TC WL_RT_loop ; check next task on list WL_RT_done EQU * 02414 2414 3 0,0113 1 XCH WL_RT_saveQ 02415 2415 5 0,0001 0 TS Q ; restore return address02416 2416 0 0,0000 0 RETURN ;-------------------------------------------------------------------------- ; WL_schedTask - SCHEDULE NEXT TASK ; ; Schedule task on the front of list for the next time-out. Adjust the ; time-out for all other tasks on the list, so they contain the remaining ; time after the next timeout. ;-------------------------------------------------------------------------- WL_schedTask EQU * 02417 2417 3 0,0001 0 XCH Q 02420 2420 5 0,0107 1 TS WL_ST_saveQ ; save return address 02421 2421 3 1,2050 0 CAF ZERO 02422 2422 2 1,2175 1 INDEX WL_tskLstStart 02423 2423 6 0,0001 0 AD TSKADDR 02424 2424 1 0,0000 0 CCS A ; task scheduled?02425 2425 0 1,2427 1 TC *+2 ; >0 yes02426 2426 0 1,2466 1 TC WL_ST_noTask ; +0 no, so we are done 02427 2427 3 1,2050 0 CAF ZERO 02430 2430 2 1,2175 1 INDEX WL_tskLstStart 02431 2431 6 0,0000 1 AD TSKTIME 02432 2432 5 0,0111 0 TS WL_ST_newTime ; save the new task's time-out ; Iterate through all tasks on the list. Subtract the time-out time ; from each task. (The 1st task on the list will now have a time-out ; of zero) 02433 2433 3 1,2175 0 CAF WL_tskLstStart ; set pointer to front of list02434 2434 5 0,0110 1 TS WL_ST_taskPtr 02435 2435 3 1,2177 1 CAF WL_numTasks ; loop for number of tasks WL_ST_loop EQU * 02436 2436 5 0,0112 0 TS WL_ST_loopCnt 02437 2437 3 1,2050 0 CAF ZERO 02440 2440 2 0,0110 0 INDEX WL_ST_taskPtr 02441 2441 6 0,0001 0 AD TSKADDR
02442 2442 1 0,0000 0 CCS A ; end of list?02443 2443 0 1,2445 0 TC *+2 ; >0 no, so keep going02444 2444 0 1,2461 0 TC WL_ST_setT3 ; +0 yes, set TIME3 02445 2445 3 1,2050 0 CAF ZERO 02446 2446 2 0,0110 0 INDEX WL_ST_taskPtr 02447 2447 6 0,0000 1 AD TSKTIME 02450 2450 2 0,0000 1 EXTEND 02451 2451 6 0,0111 0 SU WL_ST_newTime ; time-out = time-out - newtime02452 2452 2 0,0110 0 INDEX WL_ST_taskPtr 02453 2453 5 0,0000 1 TS TSKTIME 02454 2454 3 0,0110 1 XCH WL_ST_taskPtr ; bump task pointer back 1 record02455 2455 6 1,2174 1 AD WL_taskRecSize 02456 2456 5 0,0110 1 TS WL_ST_taskPtr 02457 2457 1 0,0112 1 CCS WL_ST_loopCnt ; done fixing the times?02460 2460 0 1,2436 1 TC WL_ST_loop ; not yet ; Set TIME3 to overflow at the time-out of the task on the front ; of the list: TIME3 = %37777 - WL_ST_newTime + 1 WL_ST_setT3 EQU * 02461 2461 4 0,0111 1 CS WL_ST_newTime 02462 2462 6 1,2201 0 AD WL_maxVal 02463 2463 6 1,2051 1 AD ONE 02464 2464 5 0,0037 0 TS TIME3 ; overflow at new time-out time02465 2465 0 1,2470 0 TC WL_ST_done WL_ST_noTask EQU * 02466 2466 3 1,2203 1 CAF WL_maxTimeOut 02467 2467 5 0,0037 0 TS TIME3 ; nothing scheduled, reset the clock WL_ST_done EQU * 02470 2470 3 0,0107 1 XCH WL_ST_saveQ 02471 2471 5 0,0001 0 TS Q ; restore return address02472 2472 0 0,0000 0 RETURN ;-------------------------------------------------------------------------- ; WL_insert - INSERT TASK INTO SORTED LIST ; ; Insert a task record into the sorted list. Use 'WL_IS_newTime' and ; 'WL_IS_newAddr' to set the fields of record to be inserted. ; Performs an insertion sort, with the records sorted by time. ; Lowest times are at the front of the list. If several records ; have the same time, the records inserted first will appear first ; in the list. NIL records have a time of NOTASK and a address ; of positive zero. ;-------------------------------------------------------------------------- WL_insert EQU * 02473 2473 3 0,0001 0 XCH Q 02474 2474 5 0,0124 0 TS WL_IS_saveQ ; save return address 02475 2475 3 1,2176 0 CAF WL_tskLstEnd ; set pointer to back of list02476 2476 5 0,0125 1 TS WL_IS_taskPtr 02477 2477 2 0,0000 1 EXTEND 02500 2500 6 1,2174 1 SU WL_taskRecSize ; set pointer to rec in front of it02501 2501 5 0,0126 1 TS WL_IS_taskPtr2 02502 2502 3 1,2050 0 CAF ZERO 02503 2503 2 0,0125 0 INDEX WL_IS_taskPtr 02504 2504 6 0,0001 0 AD TSKADDR 02505 2505 1 0,0000 0 CCS A ; list full?02506 2506 0 1,2562 1 TC WL_IS_done ; >0 yes ; Work from the back of the list to the front, pushing each record ; to the back until the insertion point is found. 02507 2507 3 1,2200 1 CAF WL_numTasks1 ; loop for number of tasks minus 1 WL_IS_loop EQU * 02510 2510 5 0,0127 0 TS WL_IS_loopCnt 02511 2511 3 1,2050 0 CAF ZERO 02512 2512 2 0,0126 0 INDEX WL_IS_taskPtr2 02513 2513 6 0,0001 0 AD TSKADDR 02514 2514 1 0,0000 0 CCS A ; previous record is NIL?02515 2515 0 1,2517 0 TC *+2 ; no, so check it02516 2516 0 1,2541 0 TC WL_IS_bumpPtr ; yes, so skip to next record ; Is this the insertion point? 02517 2517 4 0,0122 1 CS WL_IS_newTime 02520 2520 2 0,0126 0 INDEX WL_IS_taskPtr2 02521 2521 6 0,0000 1 AD TSKTIME
02522 2522 1 0,0000 0 CCS A ; found insertion point?02523 2523 0 1,2527 0 TC *+4 ; >0 no, keep checking02524 2524 0 1,2552 1 TC WL_IS_insRec ; +0 yes02525 2525 0 1,2552 1 TC WL_IS_insRec ; <0 yes02526 2526 0 1,2552 1 TC WL_IS_insRec ; -0 yes ; No, bump the record toward the back of the list. 02527 2527 3 1,2050 0 CAF ZERO 02530 2530 2 0,0126 0 INDEX WL_IS_taskPtr2 02531 2531 6 0,0000 1 AD TSKTIME 02532 2532 2 0,0125 0 INDEX WL_IS_taskPtr 02533 2533 5 0,0000 1 TS TSKTIME ; copy time field 02534 2534 3 1,2050 0 CAF ZERO 02535 2535 2 0,0126 0 INDEX WL_IS_taskPtr2 02536 2536 6 0,0001 0 AD TSKADDR 02537 2537 2 0,0125 0 INDEX WL_IS_taskPtr 02540 2540 5 0,0001 0 TS TSKADDR ; copy address field WL_IS_bumpPtr EQU * 02541 2541 3 0,0125 1 XCH WL_IS_taskPtr ; bump task pointer forward 1 record02542 2542 2 0,0000 1 EXTEND 02543 2543 6 1,2174 1 SU WL_taskRecSize 02544 2544 5 0,0125 1 TS WL_IS_taskPtr 02545 2545 2 0,0000 1 EXTEND 02546 2546 6 1,2174 1 SU WL_taskRecSize ; set pointer to record in front of it02547 2547 5 0,0126 1 TS WL_IS_taskPtr2 02550 2550 1 0,0127 1 CCS WL_IS_loopCnt ; done bumping tasks backward?02551 2551 0 1,2510 1 TC WL_IS_loop ; not yet ; Insert new record. WL_IS_insRec EQU * 02552 2552 3 1,2050 0 CAF ZERO 02553 2553 6 0,0122 0 AD WL_IS_newTime 02554 2554 2 0,0125 0 INDEX WL_IS_taskPtr 02555 2555 5 0,0000 1 TS TSKTIME ; set time field 02556 2556 3 1,2050 0 CAF ZERO 02557 2557 6 0,0123 1 AD WL_IS_newAddr 02560 2560 2 0,0125 0 INDEX WL_IS_taskPtr 02561 2561 5 0,0001 0 TS TSKADDR ; set address field WL_IS_done EQU * 02562 2562 3 0,0124 0 XCH WL_IS_saveQ 02563 2563 5 0,0001 0 TS Q ; restore return address02564 2564 0 0,0000 0 RETURN ;-------------------------------------------------------------------------- ; WL_remove - REMOVE TASK FROM FRONT OF LIST ; ; Returns the address of the task in register A. If the list is ; empty, it returns zero in A. If a task is removed from the list, ; the remaining tasks are moved up to the front. ;-------------------------------------------------------------------------- WL_remove EQU * 02565 2565 3 0,0001 0 XCH Q 02566 2566 5 0,0115 1 TS WL_RM_saveQ ; save return address 02567 2567 3 1,2175 0 CAF WL_tskLstStart ; set pointer to front of list02570 2570 5 0,0116 1 TS WL_RM_taskPtr 02571 2571 6 1,2174 1 AD WL_taskRecSize ; set pointer to next rec behind it02572 2572 5 0,0117 0 TS WL_RM_taskPtr2 ; Save the address of record at the front of the list. 02573 2573 3 1,2050 0 CAF ZERO 02574 2574 2 0,0116 0 INDEX WL_RM_taskPtr 02575 2575 6 0,0001 0 AD TSKADDR 02576 2576 5 0,0121 0 TS WL_RM_retval ; get address of 1st task 02577 2577 1 0,0000 0 CCS A ; list empty?02600 2600 0 1,2602 1 TC *+2 ; >0, no02601 2601 0 1,2636 0 TC WL_RM_done ; +0, yes, so exit ; Loop through the remaining records in the task list and ; bubble them up to the front. 02602 2602 3 1,2200 1 CAF WL_numTasks1 ; loop for number of tasks minus 1 WL_RM_loop EQU * 02603 2603 5 0,0120 1 TS WL_RM_loopCnt
02604 2604 3 1,2050 0 CAF ZERO 02605 2605 2 0,0117 1 INDEX WL_RM_taskPtr2 02606 2606 6 0,0000 1 AD TSKTIME 02607 2607 2 0,0116 0 INDEX WL_RM_taskPtr 02610 2610 5 0,0000 1 TS TSKTIME ; copy time field 02611 2611 3 1,2050 0 CAF ZERO 02612 2612 2 0,0117 1 INDEX WL_RM_taskPtr2 02613 2613 6 0,0001 0 AD TSKADDR 02614 2614 2 0,0116 0 INDEX WL_RM_taskPtr 02615 2615 5 0,0001 0 TS TSKADDR ; copy address field 02616 2616 1 0,0000 0 CCS A ; remainder of list empty?02617 2617 0 1,2621 0 TC *+2 ; >0, no02620 2620 0 1,2636 0 TC WL_RM_done ; +0, yes, so exit 02621 2621 3 0,0116 1 XCH WL_RM_taskPtr ; bump task pointer back 1 record02622 2622 6 1,2174 1 AD WL_taskRecSize 02623 2623 5 0,0116 1 TS WL_RM_taskPtr 02624 2624 6 1,2174 1 AD WL_taskRecSize ; set pointer to record behind it02625 2625 5 0,0117 0 TS WL_RM_taskPtr2 02626 2626 1 0,0120 0 CCS WL_RM_loopCnt ; done bumping tasks upward?02627 2627 0 1,2603 0 TC WL_RM_loop ; not yet ; Since we removed a record, the last record on the list ; should be NIL. 02630 2630 3 1,2202 0 CAF WL_maxDelay 02631 2631 2 0,0116 0 INDEX WL_RM_taskPtr 02632 2632 5 0,0000 1 TS TSKTIME ; set time field to NIL 02633 2633 3 1,2050 0 CAF ZERO 02634 2634 2 0,0116 0 INDEX WL_RM_taskPtr 02635 2635 5 0,0001 0 TS TSKADDR ; set address field to NIL WL_RM_done EQU * 02636 2636 3 0,0115 1 XCH WL_RM_saveQ 02637 2637 5 0,0001 0 TS Q ; restore return address02640 2640 3 0,0121 0 XCH WL_RM_retval ; return task address in A02641 2641 0 0,0000 0 RETURN INCL exec_f.asm ; EXEC ;========================================================================== ; EXEC (file:exec_f.asm) ; ; Version: 1.0 ; Author: John Pultorak ; Date: 04/26/2002 ; ; PURPOSE: ; Constants and source code for EXEC. ; ; Non-preemptive multitasking routines, originally implemented by J. H. ; Laning, Jr. for AGC3 and later adapted for AGC4. Briefly discussed in ; R-393, which gives some of the software interfaces into the ; multitasking. This is my own recreation, and it only includes the job ; scheduling. The original EXEC also includes memory management for the ; eraseable memory; this is not reproduced here. ; ; Overview: scheduled elements are called 'jobs'. Up to 7 jobs can be ; concurrently scheduled. An 8th 'dummy' job is always scheduled. Each ; job has an assigned priority (1-n, where 1 is the lowest priority). ; The highest priority job always executes. When that job terminates, ; the next highest priority job is selected for execution. If several ; jobs have the same priority, they are executed round-robin. ; ; A job is scheduled for execution by calling 'NOVAC' and ; furnishing the job priority and starting address. ; L XCH JOB_PRIORITY ; L+1 TC NOVAC ; L+2 DS JOB_ADDRESS ; L+3 ... execution resumes here ; ; JOB_PRIORITY = a positive integer from %3 - %37776 where a higher number ; indicates higher priority. Priorities below 3 are reserved for ; internal EXEC use: 0=no job, 1=sleeping job, 2=dummy job. ; Priority %37777 is also reserved for woken jobs. ; JOB_ADDRESS = starting address of the job. ; ; **** WARNING **** If NOVAC is not being called from an interrupt, be sure to ; inhibit interrupts before calling it to protect the integrity of the list. ; ; When a new job is added, the new job's record (core set) is ; initialized with a copy of the current job's record (MPAC and other ; parameters), except for the new job priority and address, which are ; set by the 'add job' routine. Therefore, data can be stored into
; MPAC prior to starting a new job as a method of passing data into ; the new job. ; ; Jobs terminate themselves by jumping to ENDOFJOB. This removes them ; from the EXEC scheduler: ; TC ENDOFJOB ; ; Jobs can suspend themselves (yield to a higher priority job) by ; executing the following sequence. If there is no other job of ; higher priority, executing of the yielded job resumes at L+2 ; L CCS newJob ; L+1 TC CHANG1 ; L+2 ... execution resumes here ; ; If there is no other job of equal or higher priority, the branch is ; not taken. ; ; Jobs can put themselves to sleep by calling JOBSLEEP. The address ; where execution of the sleeping job should resume must be in register ; A before calling JOBSLEEP. The job will remain sleeping until JOBWAKE ; is called: ; ; L CAF WAKECADR ; L+1 TC JOBSLEEP ; (does not return from JOBSLEEP) ; ; Sleeping jobs are awakened by calling JOBWAKE. The address where ; execution of the sleeping job should resume must be in register A. ; JOBWAKE returns to the address after the call and execution continues ; for the calling job. The job that was sleeping will now be the next ; job to execute. ; ; L CAF WAKECADR ; L+1 TC JOBWAKE ; L+2 ... execution continues here ; ;========================================================================== 02642 2642 37777 1 EX_WAKE_PRIO DS %37777 ; waking job priority (highest)02643 2643 00002 0 EX_DUMMY_PRIO DS %00002 ; dummy job priority (lowest runnable)02644 2644 00001 0 EX_SLEEP_PRIO DS %00001 ; sleeping job; must be < dummy 02645 2645 00130 0 EX_jobCurStart DS EX_currentJob ; starting address for current job 02646 2646 00015 0 EX_jobRecSize DS JRECSZ ; size of a job record (words)02647 2647 00300 1 EX_jobLstStart DS EX_jobList ; starting address for jobList02650 2650 00307 0 EX_jobLstEnd DS MAXJOBS+EX_jobList 02651 2651 00306 1 EX_jobLstEnd1 DS MAXJOBS-1+EX_jobList 02652 2652 00006 1 EX_numJobs DS MAXJOBS-1 ; init loop counter for all jobs02653 2653 00005 1 EX_numJobs1 DS MAXJOBS-2 ; init loop counter for all jobs - 1 ; enumerated types for setting change flag:02654 2654 00001 0 EX_changeJob DS CHGJOB ; change job02655 2655 00000 1 EX_keepJob DS KEEPJOB ; keep job ;-------------------------------------------------------------------------- ; EX_exec -- EXEC SCHEDULER ; ; Executes the highest priority job. Enables interrupts while the job is ; running. Once called, this function never returns. ;-------------------------------------------------------------------------- EX_exec EQU * ; entry point ; Add a dummy job (lowest priority) that never terminates. 02656 2656 3 1,2643 1 CAF EX_DUMMY_PRIO ; job priority02657 2657 0 1,3162 1 TC NOVAC 02660 2660 03510 0 DS dumJob ; 14 bit job address02661 2661 2 0,0000 0 INHINT ; inhibit RUPTs enab by addJob ; Get the next job to run. EX_MN_findJob EQU * 02662 2662 0 1,3410 1 TCR EX_remove ; compare priority of current job to priority of next waiting job. ; If next job has same priority as current job, set the newJob ; flag so they will be scheduled round-robin. 02663 2663 4 0,0143 0 CS PRIORITY ; get priority of current job 02664 2664 2 1,2647 1 INDEX EX_jobLstStart 02665 2665 2 0,0000 0 INDEX 0 02666 2666 6 0,0143 1 AD PRIORITY ; compare with priority of next job
02667 2667 1 0,0000 0 CCS A ; next job has equal priority?02670 2670 0 1,2677 0 TC EX_MN_setFlg ; >0 (error!)02671 2671 0 1,2677 0 TC EX_MN_setFlg ; +0 yes, set flag 02672 2672 0 1,2674 0 TC *+2 ; <0 no, clear flag02673 2673 0 1,2677 0 TC EX_MN_setFlg ; -0 yes, set flag 02674 2674 3 1,2655 0 CAF EX_keepJob ; clear change flag02675 2675 5 0,0307 0 TS newJob 02676 2676 0 1,2701 0 TC EX_MN_runJob EX_MN_setFlg EQU * 02677 2677 3 1,2654 1 CAF EX_changeJob ; set change flag02700 2700 5 0,0307 0 TS newJob ; Start the job. Interrupts are reenabled before 'EX_curJobPtr' is ; referenced, but the interrupts can only call 'NOVAC' which does ; not change 'EX_curJobPtr'. ; The job address is always 14-bit, so check whether the address falls ; within erasable or fixed-fixed memory. If so, use it as-is; otherwise, ; set the bank register and change the address to 12-bit. EX_MN_runJob EQU * 02701 2701 3 1,2050 0 CAF ZERO 02702 2702 6 0,0140 1 AD LOC 02703 2703 5 0,0333 1 TS EX_MN_runAddr ; save job's 14 bit address 02704 2704 4 0,0000 0 COM 02705 2705 6 1,2102 0 AD bankAddr ; -(14bitAddr)+%600002706 2706 1 0,0000 0 CCS A ; job is bank addressed?02707 2707 0 1,2720 0 TC EX_MN_runIt ; >0 no, just run it, as is02710 2710 0 1,2712 1 TC *+2 ; +0 yes02711 2711 0 1,2712 1 TC *+1 ; <0 yes 02712 2712 3 1,2050 0 CAF ZERO 02713 2713 6 0,0333 1 AD EX_MN_runAddr 02714 2714 5 0,0015 0 TS BANK ; set the bank 02715 2715 7 1,2103 0 MASK lowAddr ; get lowest 10-bits of address02716 2716 6 1,2102 0 AD bankAddr ; set bits 11,12 for fixed-switchable02717 2717 5 0,0333 1 TS EX_MN_runAddr EX_MN_runIt EQU * 02720 2720 2 0,0000 1 RELINT ; enable interrupts02721 2721 2 0,0333 0 INDEX EX_MN_runAddr ; apply indirect address to next instr.02722 2722 0 0,0000 1 TC 0 ; run the job ; Job is terminated. Delete the job record. ENDOFJOB EQU * 02723 2723 2 0,0000 0 INHINT ; inhibit interrupts02724 2724 0 1,2662 1 TC EX_MN_findJob ; get next job ; job is sleeping. Keep the job record, but drop the priority so it ; is below the priority of the dummy job. This will keep the job ; from running until JOBWAKE is called. The address where it should ; resume running when awoken is in register A. JOBSLEEP EQU * 02725 2725 2 0,0000 0 INHINT ; inhibit interrupts02726 2726 5 0,0140 1 TS LOC ; save restart address 02727 2727 3 1,2644 0 CAF EX_SLEEP_PRIO 02730 2730 5 0,0143 1 TS PRIORITY ; set sleeping priority02731 2731 5 0,0346 0 TS EX_IS_newPrio 02732 2732 0 1,2757 0 TC EX_MN_mvRec ; finish up ; Job is suspended. Keep the job record, but update the address, so ; execution will resume at the point after suspension. CHANG1 EQU * 02733 2733 2 0,0000 0 INHINT ; inhibit interrupts02734 2734 3 0,0001 0 XCH Q 02735 2735 5 0,0333 1 TS EX_MN_runAddr ; save job's 12 bit restart address 02736 2736 4 0,0000 0 COM 02737 2737 6 1,2102 0 AD bankAddr ; -(12bitAddr)+%600002740 2740 1 0,0000 0 CCS A ; job is bank addressed?02741 2741 0 1,2750 1 TC EX_MN_notBank ; >0 no, just save it, as is02742 2742 0 1,2744 1 TC *+2 ; +0 yes02743 2743 0 1,2744 1 TC *+1 ; <0 yes 02744 2744 4 1,2102 1 CS bankAddr ; 12bitAddr - %600002745 2745 6 0,0333 1 AD EX_MN_runAddr
02746 2746 6 0,0015 0 AD BANK ; make it a 14-bit address02747 2747 0 1,2752 0 TC EX_MN_saveIt EX_MN_notBank EQU * 02750 2750 3 1,2050 0 CAF ZERO 02751 2751 6 0,0333 1 AD EX_MN_runAddr ; get restart address EX_MN_saveIt EQU * 02752 2752 5 0,0140 1 TS LOC ; save job's new starting address 02753 2753 3 1,2050 0 CAF ZERO 02754 2754 6 0,0144 0 AD JOBPRIOBASE 02755 2755 5 0,0143 1 TS PRIORITY 02756 2756 5 0,0346 0 TS EX_IS_newPrio ; restore job priority to nominal value ; given the priority, find the insertion point in the list. Copy ; the current job into the list at the correct insertion point. EX_MN_mvRec EQU * 02757 2757 0 1,3332 0 TCR EX_findIns 02760 2760 5 0,0352 0 TS EX_IS_jobPtr ; save address of insertion point ; copy all fields in current record to list 02761 2761 3 1,2646 1 XCH EX_jobRecSize 02762 2762 5 0,0334 0 TS EX_MN_field EX_MN_loop3 EQU * 02763 2763 1 0,0334 1 CCS EX_MN_field ; done?02764 2764 0 1,2766 1 TC *+2 ; not yet02765 2765 0 1,3002 0 TC EX_MN_done3 ; yes02766 2766 5 0,0334 0 TS EX_MN_field ; copy this field to list 02767 2767 3 1,2050 0 CAF ZERO 02770 2770 2 0,0352 1 INDEX EX_IS_jobPtr 02771 2771 6 0,0000 1 AD 0 ; get index to record in list02772 2772 6 0,0334 0 AD EX_MN_field ; add field displacement02773 2773 5 0,0335 1 TS EX_MN_findx ; save index to field in list 02774 2774 3 1,2050 0 CAF ZERO 02775 2775 2 0,0334 1 INDEX EX_MN_field 02776 2776 6 0,0130 0 AD EX_currentJob ; get field from current job02777 2777 2 0,0335 0 INDEX EX_MN_findx 03000 3000 5 0,0130 0 TS EX_currentJob ; copy field to list 03001 3001 0 1,2763 1 TC EX_MN_loop3 EX_MN_done3 EQU * 03002 3002 0 1,2662 1 TC EX_MN_findJob ; get next job ;-------------------------------------------------------------------------- ; JOBWAKE - wake up the job identified by address in register A ; ; Search jobList for a job with address matching the address in A. ; If found, bump the priority up to the highest level, so the job ; will be the next to run. ; ; This is a 'public' function. It assumes that interrupts are already ; disabled before it is called. Disabling interrupts during JOBWAKE ; is necessary to preserve the integrity of the joblist. ;-------------------------------------------------------------------------- JOBWAKE EQU * 03003 3003 5 0,0312 1 TS EX_JW_CADR ; save job address03004 3004 3 0,0001 0 XCH Q 03005 3005 5 0,0310 0 TS EX_JW_saveQ ; save return address ; Search the joblist for the job to wake (job address matches ; EX_JW_CADR). 03006 3006 3 1,2050 0 CAF ZERO 03007 3007 5 0,0313 0 TS EX_JW_foundit ; clear 'found it' flag 03010 3010 3 1,2651 1 CAF EX_jobLstEnd1 ; set pointer to back of list03011 3011 5 0,0314 1 TS EX_JW_jobPtr 03012 3012 6 1,2046 1 AD NEG1 ; set pointer to rec in front of it03013 3013 5 0,0315 0 TS EX_JW_jobPtr2 03014 3014 3 1,2653 0 CAF EX_numJobs1 ; loop for number of jobs minus 1 EX_JW_loop EQU * 03015 3015 5 0,0311 1 TS EX_JW_loopCnt ; if foundit=0, job has not been found yet. Keep searching toward
; the front of the list. ; if foundit=1, the job has been found and removed from the list. ; push all jobs in front of the removed job one step to the back ; to fill in the gap and to make room at the front of the list ; for the awoken job. 03016 3016 1 0,0313 1 CCS EX_JW_foundit ; already found job to wake?03017 3017 0 1,3035 1 TC EX_JW_moveRec ; >0, yes ; Is this the job? 03020 3020 4 0,0312 0 CS EX_JW_CADR 03021 3021 2 0,0314 0 INDEX EX_JW_jobPtr 03022 3022 2 0,0000 0 INDEX 0 03023 3023 6 0,0140 1 AD LOC 03024 3024 1 0,0000 0 CCS A ; found job to wake?03025 3025 0 1,3041 1 TC EX_JW_bumpPtr ; >0, no03026 3026 0 1,3030 1 TC *+2 ; +0, yes03027 3027 0 1,3041 1 TC EX_JW_bumpPtr ; <0, no ; found the job to wake. 03030 3030 3 1,2051 1 CAF ONE 03031 3031 5 0,0313 0 TS EX_JW_foundit ; set 'found it' flag ; save record index for awoken job 03032 3032 2 0,0314 0 INDEX EX_JW_jobPtr 03033 3033 3 0,0000 1 XCH 0 03034 3034 5 0,0316 0 TS EX_JW_fndIndx ; index for awoken job ; bump prior record back EX_JW_moveRec EQU * 03035 3035 2 0,0315 1 INDEX EX_JW_jobPtr2 03036 3036 3 0,0000 1 XCH 0 03037 3037 2 0,0314 0 INDEX EX_JW_jobPtr 03040 3040 3 0,0000 1 XCH 0 EX_JW_bumpPtr EQU * 03041 3041 3 0,0314 1 XCH EX_JW_jobPtr ; bump job pointer forward 1 record03042 3042 6 1,2046 1 AD NEG1 03043 3043 5 0,0314 1 TS EX_JW_jobPtr 03044 3044 6 1,2046 1 AD NEG1 ; set pointer to record in front of it03045 3045 5 0,0315 0 TS EX_JW_jobPtr2 03046 3046 1 0,0311 0 CCS EX_JW_loopCnt ; done bumping jobs backward?03047 3047 0 1,3015 0 TC EX_JW_loop ; not yet 03050 3050 1 0,0313 1 CCS EX_JW_foundit ; found job to wake?03051 3051 0 1,3053 1 TC *+2 ; >0, yes03052 3052 0 1,3056 1 TC EX_JW_done ; no 03053 3053 3 0,0316 0 XCH EX_JW_fndIndx ; put awoken job on front of list03054 3054 2 1,2647 1 INDEX EX_jobLstStart 03055 3055 5 0,0000 1 TS 0 EX_JW_done EQU * ; Is the awoken job at the front of the list? ; (If it was already there before we started searching, 'foundIt' ; will be false (0) so we need to make this test). 03056 3056 4 0,0312 0 CS EX_JW_CADR 03057 3057 2 1,2647 1 INDEX EX_jobLstStart 03060 3060 2 0,0000 0 INDEX 0 03061 3061 6 0,0140 1 AD LOC 03062 3062 1 0,0000 0 CCS A ; woken job at front of list?03063 3063 0 1,3074 1 TC EX_JW_return ; >0, no03064 3064 0 1,3066 1 TC *+2 ; +0, yes03065 3065 0 1,3074 1 TC EX_JW_return ; <0, no ; set awoken priority and change job flag 03066 3066 3 1,2642 0 CAF EX_WAKE_PRIO 03067 3067 2 1,2647 1 INDEX EX_jobLstStart 03070 3070 2 0,0000 0 INDEX 0 03071 3071 5 0,0143 1 TS PRIORITY ; set waking priority 03072 3072 3 1,2654 1 CAF EX_changeJob ; set the change flag03073 3073 5 0,0307 0 TS newJob EX_JW_return EQU * 03074 3074 0 0,0310 0 TC EX_JW_saveQ ; return
;-------------------------------------------------------------------------- ; SPVAC - ADD A JOB TO THE JOBLIST ; ; Similar to NOVAC, but used by VERB 37. The job CADR is in register A. ; The job priority is in NEWPRIO. Return to the address in Q. ; ; NOVAC differs from SPVAC, because NOVAC has the job CADR at the address ; in Q, and returns to Q+1. Also, in NOVAC the job priority is in A. ; ; This is a 'public' function. It can be called from a job ; or from an interrupt. ;-------------------------------------------------------------------------- SPVAC EQU * 03075 3075 5 0,0350 1 TS EX_IS_newLoc ; store new job address03076 3076 3 0,0001 0 XCH Q 03077 3077 5 0,0317 1 TS EX_AJ_saveQ ; save return address ; add new job to end of list 03100 3100 3 1,2050 0 CAF ZERO 03101 3101 6 0,0360 1 AD NEWPRIO 03102 3102 5 0,0346 0 TS EX_IS_newPrio 03103 3103 5 0,0347 1 TS EX_IS_newPrioB ; store new job priority 03104 3104 0 1,3332 0 TCR EX_findIns ; find insertion point in list03105 3105 5 0,0352 0 TS EX_IS_jobPtr ; save address of insertion point ; Initialize relevant fields in new job. The remaining fields ; should already be zeroed. ; Initialize fields for new job record. New job inherits copy of ; MPAC from current job, so copy all fields in current job to new ; job in list 03106 3106 3 1,2646 1 XCH EX_jobRecSize 03107 3107 5 0,0323 0 TS EX_AJ_field EX_SP_loop1 EQU * 03110 3110 1 0,0323 1 CCS EX_AJ_field ; done?03111 3111 0 1,3113 1 TC *+2 ; not yet03112 3112 0 1,3127 0 TC EX_SP_done1 ; yes03113 3113 5 0,0323 0 TS EX_AJ_field ; copy this field to list 03114 3114 3 1,2050 0 CAF ZERO 03115 3115 2 0,0352 1 INDEX EX_IS_jobPtr 03116 3116 6 0,0000 1 AD 0 ; get index to record in list03117 3117 6 0,0323 0 AD EX_AJ_field ; add field displacement03120 3120 5 0,0324 1 TS EX_AJ_findx ; save index to field in list 03121 3121 3 1,2050 0 CAF ZERO 03122 3122 2 0,0323 1 INDEX EX_AJ_field 03123 3123 6 0,0130 0 AD EX_currentJob ; get field from current job03124 3124 2 0,0324 0 INDEX EX_AJ_findx 03125 3125 5 0,0130 0 TS EX_currentJob ; copy field to list 03126 3126 0 1,3110 1 TC EX_SP_loop1 ; now, overwrite fields in the record with the priority ; and location unique to this job. EX_SP_done1 EQU * 03127 3127 3 1,2050 0 CAF ZERO 03130 3130 6 0,0346 0 AD EX_IS_newPrio 03131 3131 2 0,0352 1 INDEX EX_IS_jobPtr 03132 3132 2 0,0000 0 INDEX 0 03133 3133 5 0,0143 1 TS PRIORITY ; set priority field 03134 3134 3 1,2050 0 CAF ZERO 03135 3135 6 0,0347 1 AD EX_IS_newPrioB 03136 3136 2 0,0352 1 INDEX EX_IS_jobPtr 03137 3137 2 0,0000 0 INDEX 0 03140 3140 5 0,0144 0 TS JOBPRIOBASE ; set nominal priority field 03141 3141 3 1,2050 0 CAF ZERO 03142 3142 6 0,0350 1 AD EX_IS_newLoc 03143 3143 2 0,0352 1 INDEX EX_IS_jobPtr 03144 3144 2 0,0000 0 INDEX 0 03145 3145 5 0,0140 1 TS LOC ; set address field ; Set changeflag if priority of new job >= priority of current job
EX_SP_testFlg EQU * 03146 3146 4 0,0143 0 CS PRIORITY ; get -priority of current job 03147 3147 6 0,0321 1 AD EX_AJ_jobPrio ; add positive priority of new job03150 3150 1 0,0000 0 CCS A ; new job is highest priority?03151 3151 0 1,3154 1 TC *+3 ; >0, yes03152 3152 0 1,3154 1 TC *+2 ; +0, yes03153 3153 0 1,3156 0 TC EX_SP_done2 ; <0, no, current job is higher priority 03154 3154 3 1,2654 1 CAF EX_changeJob ; set the change flag03155 3155 5 0,0307 0 TS newJob EX_SP_done2 EQU * 03156 3156 3 0,0317 1 XCH EX_AJ_saveQ 03157 3157 5 0,0001 0 TS Q 03160 3160 0 0,0000 0 RETURN ;-------------------------------------------------------------------------- ; FINDVAC - not implemented ; ;-------------------------------------------------------------------------- 03161 3161 0 0,0001 0 FINDVAC TC Q ; just return ;-------------------------------------------------------------------------- ; NOVAC - ADD A JOB TO THE JOBLIST ; ; Search jobList for an empty slot. If found, put the new job in the ; empty slot. If the new job has the same, or higher, priority than the ; current job, set the change flag to 'CHGJOB' (change jobs at the next ; opportunity). ; ; This is a 'public' function. It can be called from a job ; or from an interrupt. ;-------------------------------------------------------------------------- NOVAC EQU * 03162 3162 5 0,0321 1 TS EX_AJ_jobPrio ; save job priority03163 3163 3 0,0001 0 XCH Q 03164 3164 5 0,0317 1 TS EX_AJ_saveQ ; save return address-1 ; add new job to end of list 03165 3165 3 1,2050 0 CAF ZERO 03166 3166 6 0,0321 1 AD EX_AJ_jobPrio 03167 3167 5 0,0346 0 TS EX_IS_newPrio 03170 3170 5 0,0347 1 TS EX_IS_newPrioB ; store new job priority 03171 3171 2 0,0317 0 INDEX EX_AJ_saveQ ; indirectly address addJobQ03172 3172 3 0,0000 1 CAF 0 03173 3173 5 0,0350 1 TS EX_IS_newLoc ; store new job address 03174 3174 0 1,3332 0 TCR EX_findIns ; find insertion point in list03175 3175 5 0,0352 0 TS EX_IS_jobPtr ; save address of insertion point ; Initialize relevant fields in new job. The remaining fields ; should already be zeroed. ; Initialize fields for new job record. New job inherits copy of ; MPAC from current job, so copy all fields in current job to new ; job in list 03176 3176 3 1,2646 1 XCH EX_jobRecSize 03177 3177 5 0,0323 0 TS EX_AJ_field EX_AJ_loop1 EQU * 03200 3200 1 0,0323 1 CCS EX_AJ_field ; done?03201 3201 0 1,3203 0 TC *+2 ; not yet03202 3202 0 1,3217 0 TC EX_AJ_done1 ; yes03203 3203 5 0,0323 0 TS EX_AJ_field ; copy this field to list 03204 3204 3 1,2050 0 CAF ZERO 03205 3205 2 0,0352 1 INDEX EX_IS_jobPtr 03206 3206 6 0,0000 1 AD 0 ; get index to record in list03207 3207 6 0,0323 0 AD EX_AJ_field ; add field displacement03210 3210 5 0,0324 1 TS EX_AJ_findx ; save index to field in list 03211 3211 3 1,2050 0 CAF ZERO 03212 3212 2 0,0323 1 INDEX EX_AJ_field 03213 3213 6 0,0130 0 AD EX_currentJob ; get field from current job03214 3214 2 0,0324 0 INDEX EX_AJ_findx
03215 3215 5 0,0130 0 TS EX_currentJob ; copy field to list 03216 3216 0 1,3200 0 TC EX_AJ_loop1 ; now, overwrite fields in the record with the priority ; and location unique to this job. EX_AJ_done1 EQU * 03217 3217 3 1,2050 0 CAF ZERO 03220 3220 6 0,0346 0 AD EX_IS_newPrio 03221 3221 2 0,0352 1 INDEX EX_IS_jobPtr 03222 3222 2 0,0000 0 INDEX 0 03223 3223 5 0,0143 1 TS PRIORITY ; set priority field 03224 3224 3 1,2050 0 CAF ZERO 03225 3225 6 0,0347 1 AD EX_IS_newPrioB 03226 3226 2 0,0352 1 INDEX EX_IS_jobPtr 03227 3227 2 0,0000 0 INDEX 0 03230 3230 5 0,0144 0 TS JOBPRIOBASE ; set nominal priority field 03231 3231 3 1,2050 0 CAF ZERO 03232 3232 6 0,0350 1 AD EX_IS_newLoc 03233 3233 2 0,0352 1 INDEX EX_IS_jobPtr 03234 3234 2 0,0000 0 INDEX 0 03235 3235 5 0,0140 1 TS LOC ; set address field ; Set changeflag if priority of new job >= priority of current job EX_AJ_testFlg EQU * 03236 3236 4 0,0143 0 CS PRIORITY ; get -priority of current job 03237 3237 6 0,0321 1 AD EX_AJ_jobPrio ; add positive priority of new job03240 3240 1 0,0000 0 CCS A ; new job is highest priority?03241 3241 0 1,3244 0 TC *+3 ; >0, yes03242 3242 0 1,3244 0 TC *+2 ; +0, yes03243 3243 0 1,3246 1 TC EX_AJ_done2 ; <0, no, current job is higher priority 03244 3244 3 1,2654 1 CAF EX_changeJob ; set the change flag03245 3245 5 0,0307 0 TS newJob EX_AJ_done2 EQU * 03246 3246 3 0,0317 1 XCH EX_AJ_saveQ 03247 3247 6 1,2051 1 AD ONE 03250 3250 5 0,0001 0 TS Q 03251 3251 0 0,0000 0 RETURN ;-------------------------------------------------------------------------- ; EX_initEX - INITIALIZE EXEC ; ; Initialize the eraseable memory segment for EXEC. Necessary in ; case the AGC is restarted. ;-------------------------------------------------------------------------- EX_initEX EQU * 03252 3252 3 0,0001 0 XCH Q 03253 3253 5 0,0325 0 TS EX_IN_saveQ ; save return address 03254 3254 3 1,2655 0 CAF EX_keepJob ; clear change flag03255 3255 5 0,0307 0 TS newJob 03256 3256 3 1,2050 0 CAF ZERO 03257 3257 5 0,0143 1 TS PRIORITY ; set current job record to NIL ; Iterate through jobList, initialize each element on the list so it ; points to its own job record. 03260 3260 3 1,2647 0 CAF EX_jobLstStart ; init pointer to start of list03261 3261 5 0,0327 1 TS EX_IN_jobPtr 03262 3262 3 1,2050 0 CAF ZERO 03263 3263 6 1,2646 1 AD EX_jobRecSize 03264 3264 5 0,0330 1 TS EX_IN_recIndex 03265 3265 3 1,2652 1 CAF EX_numJobs ; loop for number of jobs EX_IN_loop1 EQU * 03266 3266 5 0,0326 0 TS EX_IN_loopCnt 03267 3267 3 0,0330 1 XCH EX_IN_recIndex 03270 3270 2 0,0327 0 INDEX EX_IN_jobPtr 03271 3271 5 0,0000 1 TS 0 ; initialize record index03272 3272 6 1,2646 1 AD EX_jobRecSize 03273 3273 5 0,0330 1 TS EX_IN_recIndex ; bump index to next record 03274 3274 3 0,0327 1 XCH EX_IN_jobPtr ; bump job pointer back 1 record03275 3275 6 1,2051 1 AD ONE
03276 3276 5 0,0327 1 TS EX_IN_jobPtr 03277 3277 1 0,0326 1 CCS EX_IN_loopCnt ; done clearing jobList?03300 3300 0 1,3266 0 TC EX_IN_loop1 ; not yet ; Iterate through job records, initialize each field to zero. 03301 3301 3 1,2647 0 CAF EX_jobLstStart ; init pointer to start of list03302 3302 5 0,0327 1 TS EX_IN_jobPtr 03303 3303 3 1,2652 1 CAF EX_numJobs ; loop for number of jobs EX_IN_loop2 EQU * 03304 3304 5 0,0326 0 TS EX_IN_loopCnt ; loop for number of fields in each record 03305 3305 3 1,2646 1 XCH EX_jobRecSize 03306 3306 5 0,0331 0 TS EX_IN_field EX_IN_loop3 EQU * 03307 3307 1 0,0331 1 CCS EX_IN_field ; done?03310 3310 0 1,3312 1 TC *+2 ; not yet03311 3311 0 1,3324 1 TC EX_IN_done ; yes03312 3312 5 0,0331 0 TS EX_IN_field ; set the field to zero 03313 3313 3 1,2050 0 CAF ZERO 03314 3314 2 0,0327 0 INDEX EX_IN_jobPtr 03315 3315 6 0,0000 1 AD 0 ; get index to record03316 3316 6 0,0331 0 AD EX_IN_field ; add field displacement03317 3317 5 0,0332 0 TS EX_IN_findx ; save index to field03320 3320 3 1,2050 0 CAF ZERO 03321 3321 2 0,0332 1 INDEX EX_IN_findx 03322 3322 5 0,0130 0 TS EX_currentJob ; clear field 03323 3323 0 1,3307 0 TC EX_IN_loop3 ; done clearing all fields in record, so do next record EX_IN_done EQU * 03324 3324 3 0,0327 1 XCH EX_IN_jobPtr ; bump job pointer back 1 record03325 3325 6 1,2051 1 AD ONE 03326 3326 5 0,0327 1 TS EX_IN_jobPtr 03327 3327 1 0,0326 1 CCS EX_IN_loopCnt ; done clearing jobList?03330 3330 0 1,3304 0 TC EX_IN_loop2 ; not yet 03331 3331 0 0,0325 0 TC EX_IN_saveQ ; return ;-------------------------------------------------------------------------- ; EX_findIns - FIND INSERTION POINT INTO SORTED LIST ; ; Insert a job record into the sorted list. Use 'EX_IS_newPrio', ; EX_IS_newPrioB and 'EX_IS_newLoc' to set the fields of record to ; be inserted. ; Performs an insertion sort, with the records sorted by priority. ; Highest priority is at the front of the list. If several records ; have the same priority, the records inserted first will appear first ; in the list. NIL records have a priority of zero. ;-------------------------------------------------------------------------- EX_findIns EQU * 03332 3332 3 0,0001 0 XCH Q 03333 3333 5 0,0351 0 TS EX_IS_saveQ ; save return address 03334 3334 3 1,2651 1 CAF EX_jobLstEnd1 ; set pointer to back of list03335 3335 5 0,0352 0 TS EX_IS_jobPtr 03336 3336 6 1,2046 1 AD NEG1 ; set pointer to rec in front of it03337 3337 5 0,0353 1 TS EX_IS_jobPtr2 03340 3340 3 1,2050 0 CAF ZERO 03341 3341 2 0,0352 1 INDEX EX_IS_jobPtr 03342 3342 2 0,0000 0 INDEX 0 03343 3343 6 0,0143 1 AD PRIORITY ; check last record on list 03344 3344 1 0,0000 0 CCS A ; list full?03345 3345 0 1,3405 0 TC EX_FI_done ; >0 yes ; Work from the back of the list to the front, pushing each record ; to the back until the insertion point is found. 03346 3346 3 1,2653 0 CAF EX_numJobs1 ; loop for number of jobs minus 1 EX_FI_loop EQU *
03347 3347 5 0,0354 0 TS EX_IS_loopCnt 03350 3350 3 1,2050 0 CAF ZERO 03351 3351 2 0,0353 0 INDEX EX_IS_jobPtr2 03352 3352 2 0,0000 0 INDEX 0 03353 3353 6 0,0143 1 AD PRIORITY 03354 3354 1 0,0000 0 CCS A ; previous record is NIL?03355 3355 0 1,3357 0 TC *+2 ; no, so check it03356 3356 0 1,3376 0 TC EX_FI_bumpPtr ; yes, so skip to next record ; Is this the insertion point? 03357 3357 4 0,0346 1 CS EX_IS_newPrio 03360 3360 2 0,0353 0 INDEX EX_IS_jobPtr2 03361 3361 2 0,0000 0 INDEX 0 03362 3362 6 0,0143 1 AD PRIORITY 03363 3363 1 0,0000 0 CCS A ; found insertion point?03364 3364 0 1,3405 0 TC EX_FI_insRec ; >0 yes03365 3365 0 1,3405 0 TC EX_FI_insRec ; +0 yes03366 3366 0 1,3370 0 TC *+2 ; <0 no, keep checking03367 3367 0 1,3405 0 TC EX_FI_insRec ; -0 yes ; No, bump the record toward the back of the list. 03370 3370 2 0,0353 0 INDEX EX_IS_jobPtr2 03371 3371 3 0,0000 1 XCH 0 03372 3372 2 0,0352 1 INDEX EX_IS_jobPtr 03373 3373 3 0,0000 1 XCH 0 03374 3374 2 0,0353 0 INDEX EX_IS_jobPtr2 03375 3375 3 0,0000 1 XCH 0 EX_FI_bumpPtr EQU * 03376 3376 3 0,0352 0 XCH EX_IS_jobPtr ; bump job pointer forward 1 record03377 3377 6 1,2046 1 AD NEG1 03400 3400 5 0,0352 0 TS EX_IS_jobPtr 03401 3401 6 1,2046 1 AD NEG1 ; set pointer to record in front of it03402 3402 5 0,0353 1 TS EX_IS_jobPtr2 03403 3403 1 0,0354 1 CCS EX_IS_loopCnt ; done bumping jobs backward?03404 3404 0 1,3347 1 TC EX_FI_loop ; not yet ; New record should be inserted at EX_IS_jobPtr. EX_FI_insRec EQU * EX_FI_done EQU * 03405 3405 3 1,2050 0 CAF ZERO 03406 3406 6 0,0352 0 AD EX_IS_jobPtr ; get insertion spot in list03407 3407 0 0,0351 0 TC EX_IS_saveQ ; return ;-------------------------------------------------------------------------- ; EX_remove - REMOVE JOB FROM FRONT OF LIST ; ; Remove job from front of list and copy it to the current job. Bubble ; any remaining jobs toward the front of the list. ;-------------------------------------------------------------------------- EX_remove EQU * 03410 3410 3 0,0001 0 XCH Q 03411 3411 5 0,0336 1 TS EX_RM_saveQ ; save return address 03412 3412 3 1,2647 0 CAF EX_jobLstStart ; set pointer to front of list03413 3413 5 0,0337 0 TS EX_RM_jobPtr 03414 3414 6 1,2051 1 AD ONE ; set pointer to next rec behind it03415 3415 5 0,0340 0 TS EX_RM_jobPtr2 ; Dequeue the record at the top of the list (the next job to run). ; Make it the current job by copying it to the current job record. 03416 3416 3 1,2646 1 XCH EX_jobRecSize 03417 3417 5 0,0344 1 TS EX_RM_field EX_RM_loop1 EQU * 03420 3420 1 0,0344 0 CCS EX_RM_field ; done?03421 3421 0 1,3423 1 TC *+2 ; not yet03422 3422 0 1,3437 1 TC EX_RM_done1 ; yes03423 3423 5 0,0344 1 TS EX_RM_field ; copy field from list to current job 03424 3424 3 1,2050 0 CAF ZERO 03425 3425 2 0,0337 1 INDEX EX_RM_jobPtr 03426 3426 6 0,0000 1 AD 0 ; get index to record
03427 3427 6 0,0344 1 AD EX_RM_field ; add field displacement03430 3430 5 0,0345 0 TS EX_RM_findx ; save index to field03431 3431 3 1,2050 0 CAF ZERO 03432 3432 2 0,0345 1 INDEX EX_RM_findx 03433 3433 6 0,0130 0 AD EX_currentJob ; get field03434 3434 2 0,0344 0 INDEX EX_RM_field 03435 3435 5 0,0130 0 TS EX_currentJob ; move to current job 03436 3436 0 1,3420 1 TC EX_RM_loop1 ; done copying record for current job. Restore the current job to ; its default priority, in case it was previously elevated. EX_RM_done1 EQU * 03437 3437 3 1,2050 0 CAF ZERO 03440 3440 6 0,0144 0 AD JOBPRIOBASE 03441 3441 5 0,0143 1 TS PRIORITY 03442 3442 2 0,0337 1 INDEX EX_RM_jobPtr 03443 3443 3 0,0000 1 XCH 0 03444 3444 5 0,0341 1 TS EX_RM_savePtr ; so we can move it to the end later ; Loop through the remaining records in the job list and ; bubble them up to the front. 03445 3445 3 1,2653 0 CAF EX_numJobs1 ; loop for number of jobs minus 1 EX_RM_loop2 EQU * 03446 3446 5 0,0342 1 TS EX_RM_loopCnt 03447 3447 2 0,0340 1 INDEX EX_RM_jobPtr2 03450 3450 3 0,0000 1 XCH 0 03451 3451 2 0,0337 1 INDEX EX_RM_jobPtr 03452 3452 5 0,0000 1 TS 0 03453 3453 1 0,0000 0 CCS A ; remainder of list empty?03454 3454 0 1,3456 0 TC *+2 ; >0, no03455 3455 0 1,3465 0 TC EX_RM_done2 ; +0, yes, so exit 03456 3456 3 0,0337 0 XCH EX_RM_jobPtr ; bump job pointer back 1 record03457 3457 6 1,2051 1 AD ONE 03460 3460 5 0,0337 0 TS EX_RM_jobPtr 03461 3461 6 1,2051 1 AD ONE ; set pointer to record behind it03462 3462 5 0,0340 0 TS EX_RM_jobPtr2 03463 3463 1 0,0342 0 CCS EX_RM_loopCnt ; done bumping jobs upward?03464 3464 0 1,3446 1 TC EX_RM_loop2 ; not yet ; Since we removed a record, the last record on the list ; should be NIL. EX_RM_done2 EQU * 03465 3465 3 0,0341 1 XCH EX_RM_savePtr 03466 3466 2 0,0337 1 INDEX EX_RM_jobPtr ; move the index for the top record03467 3467 5 0,0000 1 TS 0 ; to the bottom of the list ; set all fields in NIL record to zero 03470 3470 3 1,2646 1 XCH EX_jobRecSize 03471 3471 5 0,0344 1 TS EX_RM_field EX_RM_loop3 EQU * 03472 3472 1 0,0344 0 CCS EX_RM_field ; done?03473 3473 0 1,3475 1 TC *+2 ; not yet03474 3474 0 1,3507 0 TC EX_RM_done3 ; yes03475 3475 5 0,0344 1 TS EX_RM_field ; set this field to zero 03476 3476 3 1,2050 0 CAF ZERO 03477 3477 2 0,0337 1 INDEX EX_RM_jobPtr 03500 3500 6 0,0000 1 AD 0 ; get index to record03501 3501 6 0,0344 1 AD EX_RM_field ; add field displacement03502 3502 5 0,0345 0 TS EX_RM_findx ; save index to field03503 3503 3 1,2050 0 CAF ZERO 03504 3504 2 0,0345 1 INDEX EX_RM_findx 03505 3505 5 0,0130 0 TS EX_currentJob ; clear field 03506 3506 0 1,3472 0 TC EX_RM_loop3 EX_RM_done3 EQU * 03507 3507 0 0,0336 1 TC EX_RM_saveQ ; return ;--------------------------------------------------------------------------
; DUMMY JOB - runs at the lowest priority and never terminates. Ensures ; that there is always at least one job executing. Sleeping jobs are ; given a lower priority than the dummy job. ; ; The dummy job controls the computer activity light on the DSKY. When ; the dummy job is running, the light is off. When the dummy job is ; preempted by a higher priority job, the light is on. ; ; I couldn't find good information on the computer activity light ; in COLOSSUS, so this is my best guess concerning its operation. It ; seems consistent witht the MPEG video of the Apollo 11 DSKY. ;-------------------------------------------------------------------------- ; entering dummy job -- turn off computer activity light dumJob EQU * 03510 3510 3 1,2050 0 CAF ZERO 03511 3511 6 0,0011 1 AD DSALMOUT 03512 3512 7 1,3525 1 MASK NOTACTLT 03513 3513 5 0,0011 1 TS DSALMOUT ; turn bit1 off ; runtime loop for dummy job dumJob1 EQU * 03514 3514 1 0,0307 1 CCS newJob ; check for context switch03515 3515 0 1,3517 1 TC dumJob2 ; yes03516 3516 0 1,3514 1 TC dumJob1 ; no ; exiting dummy job -- turn on computer activity light dumJob2 EQU * 03517 3517 4 0,0011 0 CS DSALMOUT ; inclusive OR bit 1 with 1 using03520 3520 7 1,3525 1 MASK NOTACTLT ; Demorgan's theorem03521 3521 4 0,0000 0 COM 03522 3522 5 0,0011 1 TS DSALMOUT 03523 3523 0 1,2733 1 TC CHANG1 ; exit to run higher priority job03524 3524 0 1,3510 0 TC dumJob ; job done, return here, light off again 03525 3525 77776 1 NOTACTLT DS %77776 ; 1's compliment of bit1 (comp activity light) INCL bank_f.asm ; bank intercommunication routines ;========================================================================== ; BANK INTERCOMMUNICATION (file:bank_f.asm) ; ; Version: 1.0 ; Author: John Pultorak ; Date: 01/19/2002 ; ; PURPOSE: ; Contains bank intercommunication routines. ; The source is missing from my (incomplete) listing of COLOSSUS. The ; implementation here is inferred from the usage in the COLOSSUS pinball ; routines. Some of these routines could probably be combined or optimized ; away if I understood the pinball software architecture a little better. ;========================================================================== ;-------------------------------------------------------------------------- ; DXCHJUMP ; Do a bank jump to the CADR in register A. After the bank jump, the return ; CADR is in register A. Contents of register Q are destroyed. ; This is my attempt to implement the block I equivalent for ; DCA MY2CADR ; DXCH Z ;... which is used in some places in COLOSSUS to implement bank jumps. In that ; implementation, MY2CADR has the lower portion of the address in MYCADR and ; the bank portion in MY2CADR+1. DCA loads the lower address into A and the ; bank address into L. DXCH loads the lower address into Z and the bank portion ; into BB (both bank register), thereby doing a bank call. After the call, ; the lower return address is in A and the return bank is in L. ;-------------------------------------------------------------------------- DXCHJUMP EQU * 03526 3526 5 0,0576 0 TS ADDRWD1 ; save 14-bit destination address 03527 3527 3 0,0001 0 XCH Q 03530 3530 5 0,0617 1 TS DCRET ; save old return address 03531 3531 3 0,0015 0 XCH BANK 03532 3532 5 0,0616 0 TS DCBANK ; save old bank ; put the 12-bit destination address in ADDRWD1 03533 3533 4 0,0576 1 CS ADDRWD1 ; -(14bitAddr)+%600003534 3534 6 1,2102 0 AD bankAddr 03535 3535 1 0,0000 0 CCS A ; CADR is bank addressed?03536 3536 0 1,3547 1 TC DODXCHCALL ; >0 no, just run it, as is
03537 3537 0 1,3541 1 TC *+2 ; +0 yes03540 3540 0 1,3541 1 TC *+1 ; <0 yes 03541 3541 3 1,2050 0 CAF ZERO 03542 3542 6 0,0576 0 AD ADDRWD1 03543 3543 5 0,0015 0 TS BANK ; set the bank 03544 3544 7 1,2103 0 MASK lowAddr ; get lowest 10-bits of address03545 3545 6 1,2102 0 AD bankAddr ; set bits 11,12 for fixed-switchable03546 3546 5 0,0576 0 TS ADDRWD1 ; save 12-bit destination address ; put the 14-bit return CADR into A. DODXCHCALL EQU * 03547 3547 4 0,0617 0 CS DCRET ; get 12-bit return address03550 3550 6 1,2102 0 AD bankAddr ; -(12bitAddr)+%600003551 3551 1 0,0000 0 CCS A ; return address is bank addressed?03552 3552 0 1,3561 0 TC DC_NOTBANK ; >0 no, just use it, as is03553 3553 0 1,3555 1 TC *+2 ; +0 yes03554 3554 0 1,3555 1 TC *+1 ; <0 yes 03555 3555 4 1,2102 1 CS bankAddr ; 12bitAddr - %600003556 3556 6 0,0617 1 AD DCRET 03557 3557 6 0,0616 0 AD DCBANK ; put return CADR in A03560 3560 0 1,3563 1 TC *+3 DC_NOTBANK EQU * 03561 3561 3 1,2050 0 CAF ZERO 03562 3562 6 0,0617 1 AD DCRET ; put return CADR in A 03563 3563 2 0,0576 1 INDEX ADDRWD1 ; apply indirect address to next instr.03564 3564 0 0,0000 1 TC 0 ; make the jump ;-------------------------------------------------------------------------- ; BANKCALL ; Do a bank jump to the location referenced by the 14-bit address referenced ; in Q. Does not affect register A (but assumes A does not contain an ; overflow). Functionally identical to POSTJUMP. ; Usage: ; TC BANKCALL ; bank jump to CADR ; DS MYCADR ; the 14-bit address ; returns here if MYCADR calls TC Q. ; ; Inferred from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968. ;-------------------------------------------------------------------------- BANKCALL EQU * 03565 3565 5 0,0612 1 TS BCA ; save A 03566 3566 2 0,0001 1 INDEX Q ; load the CADR into A03567 3567 3 0,0000 1 CAF 0 03570 3570 5 0,0576 0 TS ADDRWD1 ; save 14-bit destination address 03571 3571 3 0,0001 0 XCH Q 03572 3572 5 0,0611 1 TS BCRET ; save old return address-1 03573 3573 3 0,0015 0 XCH BANK 03574 3574 5 0,0610 0 TS BCBANK ; save old bank 03575 3575 4 0,0576 1 CS ADDRWD1 ; -(14bitAddr)+%600003576 3576 6 1,2102 0 AD bankAddr 03577 3577 1 0,0000 0 CCS A ; CADR is bank addressed?03600 3600 0 1,3611 1 TC DOBANKCALL ; >0 no, just run it, as is03601 3601 0 1,3603 1 TC *+2 ; +0 yes03602 3602 0 1,3603 1 TC *+1 ; <0 yes 03603 3603 3 1,2050 0 CAF ZERO 03604 3604 6 0,0576 0 AD ADDRWD1 03605 3605 5 0,0015 0 TS BANK ; set the bank 03606 3606 7 1,2103 0 MASK lowAddr ; get lowest 10-bits of address03607 3607 6 1,2102 0 AD bankAddr ; set bits 11,12 for fixed-switchable03610 3610 5 0,0576 0 TS ADDRWD1 DOBANKCALL EQU * 03611 3611 3 0,0612 1 XCH BCA ; restore A03612 3612 2 0,0576 1 INDEX ADDRWD1 ; apply indirect address to next instr.03613 3613 0 0,0000 1 TC 0 ; make the jump ; Jump returns here; restore the old bank and return 03614 3614 5 0,0612 1 TS BCA ; save A03615 3615 3 0,0610 0 XCH BCBANK 03616 3616 5 0,0015 0 TS BANK
03617 3617 3 0,0611 1 XCH BCRET 03620 3620 6 1,2051 1 AD ONE ; skip CADR03621 3621 5 0,0001 0 TS Q 03622 3622 3 0,0612 1 XCH BCA ; restore A03623 3623 0 0,0000 0 RETURN ;-------------------------------------------------------------------------- ; MYBANKCALL ; Functionally identical to BANKCALL. Used for converting the FLASHON/FLASHOFF ; COLOSSUS block II code to block I. In Block II, the V/N flash is controlled by ; setting a bit in an I/O channel. In Block I, a bit in the display table must ; be set using _11DSPIN. Because _11DSPIN is in fixed/switchable memory, but is ; called from fixed/fixed, a bank call function is needed. The original BANKCALL ; could not be used because it is not reentrant and I dont understand its usage ; in COLOSSUS well enough to be certain that FLASHON/FLASHOFF isn't already ; being called somewhere through BANKCALL. ;-------------------------------------------------------------------------- MYBANKCALL EQU * 03624 3624 5 0,0615 0 TS MBCA ; save A 03625 3625 2 0,0001 1 INDEX Q ; load the CADR into A03626 3626 3 0,0000 1 CAF 0 03627 3627 5 0,0576 0 TS ADDRWD1 ; save 14-bit destination address 03630 3630 3 0,0001 0 XCH Q 03631 3631 6 1,2051 1 AD ONE ; skip CADR03632 3632 5 0,0614 1 TS MBCRET ; save old return address 03633 3633 3 0,0015 0 XCH BANK 03634 3634 5 0,0613 0 TS MBCBANK ; save old bank 03635 3635 3 1,2050 0 CAF ZERO 03636 3636 6 0,0576 0 AD ADDRWD1 03637 3637 5 0,0015 0 TS BANK ; set the bank 03640 3640 7 1,2103 0 MASK lowAddr ; get lowest 10-bits of address03641 3641 6 1,2102 0 AD bankAddr ; set bits 11,12 for fixed-switchable03642 3642 5 0,0576 0 TS ADDRWD1 03643 3643 3 0,0615 0 XCH MBCA ; restore A03644 3644 2 0,0576 1 INDEX ADDRWD1 ; apply indirect address to next instr.03645 3645 0 0,0000 1 TC 0 ; make the jump ; Jump returns here; restore the old bank and return 03646 3646 5 0,0615 0 TS MBCA ; save A03647 3647 3 0,0613 0 XCH MBCBANK 03650 3650 5 0,0015 0 TS BANK 03651 3651 3 0,0615 0 XCH MBCA ; restore A03652 3652 0 0,0614 1 TC MBCRET ;-------------------------------------------------------------------------- ; POSTJUMP ; Do a bank jump to the location referenced by the 14-bit address referenced ; in Q. Does not affect register A (but assumes A does not contain an ; overflow). Functionally identical to BANKCALL ; Usage: ; TC POSTJUMP ; bank jump to CADR ; DS MYCADR ; the 14-bit address ; returns here if MYCADR calls TC Q. ; ; Inferred from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968. ;-------------------------------------------------------------------------- POSTJUMP EQU * 03653 3653 5 0,0607 0 TS PJA ; save A 03654 3654 2 0,0001 1 INDEX Q ; load the CADR into A03655 3655 3 0,0000 1 CAF 0 03656 3656 5 0,0576 0 TS ADDRWD1 ; save 14-bit destination address 03657 3657 3 0,0001 0 XCH Q 03660 3660 5 0,0606 1 TS PJRET ; save old return address-1 03661 3661 3 0,0015 0 XCH BANK 03662 3662 5 0,0605 1 TS PJBANK ; save old bank 03663 3663 4 0,0576 1 CS ADDRWD1 ; -(14bitAddr)+%600003664 3664 6 1,2102 0 AD bankAddr 03665 3665 1 0,0000 0 CCS A ; CADR is bank addressed?03666 3666 0 1,3677 1 TC DOPOSTJUMP ; >0 no, just run it, as is
03667 3667 0 1,3671 1 TC *+2 ; +0 yes03670 3670 0 1,3671 1 TC *+1 ; <0 yes 03671 3671 3 1,2050 0 CAF ZERO 03672 3672 6 0,0576 0 AD ADDRWD1 03673 3673 5 0,0015 0 TS BANK ; set the bank 03674 3674 7 1,2103 0 MASK lowAddr ; get lowest 10-bits of address03675 3675 6 1,2102 0 AD bankAddr ; set bits 11,12 for fixed-switchable03676 3676 5 0,0576 0 TS ADDRWD1 DOPOSTJUMP EQU * 03677 3677 3 0,0607 0 XCH PJA ; restore A03700 3700 2 0,0576 1 INDEX ADDRWD1 ; apply indirect address to next instr.03701 3701 0 0,0000 1 TC 0 ; make the jump ; Jump returns here; restore the old bank and return 03702 3702 5 0,0607 0 TS PJA ; save A 03703 3703 3 0,0605 1 XCH PJBANK 03704 3704 5 0,0015 0 TS BANK 03705 3705 3 0,0606 1 XCH PJRET 03706 3706 6 1,2051 1 AD ONE ; skip CADR03707 3707 5 0,0001 0 TS Q 03710 3710 3 0,0607 0 XCH PJA ; restore A03711 3711 0 0,0000 0 RETURN ;-------------------------------------------------------------------------- ; BANKJUMP ; Do a bank jump to the location referenced by the 14-bit address in A. ; Usage: ; CADRSTOR DS MYCADR ; ; CAF CADRSTOR ; load the 14-bit address ; TC BANKJUMP ; bank jump to CADR ; returns here if MYCADR calls TC Q ; ; Inferred from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968. ;-------------------------------------------------------------------------- BANKJUMP EQU * 03712 3712 5 0,0576 0 TS ADDRWD1 ; save 14-bit destination address 03713 3713 3 0,0001 0 XCH Q 03714 3714 5 0,0604 0 TS BJRET ; save old return address 03715 3715 3 0,0015 0 XCH BANK 03716 3716 5 0,0603 1 TS BJBANK ; save old bank 03717 3717 4 0,0576 1 CS ADDRWD1 ; -(14bitAddr)+%600003720 3720 6 1,2102 0 AD bankAddr 03721 3721 1 0,0000 0 CCS A ; CADR is bank addressed?03722 3722 0 1,3733 0 TC DOBANKJUMP ; >0 no, just run it, as is03723 3723 0 1,3725 1 TC *+2 ; +0 yes03724 3724 0 1,3725 1 TC *+1 ; <0 yes 03725 3725 3 1,2050 0 CAF ZERO 03726 3726 6 0,0576 0 AD ADDRWD1 03727 3727 5 0,0015 0 TS BANK ; set the bank 03730 3730 7 1,2103 0 MASK lowAddr ; get lowest 10-bits of address03731 3731 6 1,2102 0 AD bankAddr ; set bits 11,12 for fixed-switchable03732 3732 5 0,0576 0 TS ADDRWD1 DOBANKJUMP EQU * 03733 3733 2 0,0576 1 INDEX ADDRWD1 ; apply indirect address to next instr.03734 3734 0 0,0000 1 TC 0 ; make the jump ; Jump returns here; restore the old bank and return 03735 3735 3 0,0603 1 XCH BJBANK 03736 3736 5 0,0015 0 TS BANK 03737 3737 3 0,0604 0 XCH BJRET 03740 3740 5 0,0001 0 TS Q 03741 3741 0 0,0000 0 RETURN ;-------------------------------------------------------------------------- ; DATACALL ; Retrieve memory contents at location referenced by the 14-bit address in A. ; Usage:
; CADRSTOR DS MYCADR ; ; CAF CADRSTOR ; load the 14-bit address ; TC DATACALL ; return data in A ; ; Inferred from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968. ;-------------------------------------------------------------------------- DATACALL EQU * 03742 3742 5 0,0576 0 TS ADDRWD1 ; save 14-bit address 03743 3743 3 0,0001 0 XCH Q 03744 3744 5 0,0604 0 TS BJRET ; save old return address 03745 3745 3 0,0015 0 XCH BANK 03746 3746 5 0,0603 1 TS BJBANK ; save old bank 03747 3747 4 0,0576 1 CS ADDRWD1 ; -(14bitAddr)+%600003750 3750 6 1,2102 0 AD bankAddr 03751 3751 1 0,0000 0 CCS A ; CADR is bank addressed?03752 3752 0 1,3763 0 TC DODATACALL ; >0 no, just use it, as is03753 3753 0 1,3755 0 TC *+2 ; +0 yes03754 3754 0 1,3755 0 TC *+1 ; <0 yes 03755 3755 3 1,2050 0 CAF ZERO 03756 3756 6 0,0576 0 AD ADDRWD1 03757 3757 5 0,0015 0 TS BANK ; set the bank 03760 3760 7 1,2103 0 MASK lowAddr ; get lowest 10-bits of address03761 3761 6 1,2102 0 AD bankAddr ; set bits 11,12 for fixed-switchable03762 3762 5 0,0576 0 TS ADDRWD1 DODATACALL EQU * 03763 3763 3 1,2050 0 CAF ZERO 03764 3764 2 0,0576 1 INDEX ADDRWD1 ; apply indirect address to next instr.03765 3765 6 0,0000 1 AD 0 ; load the word 03766 3766 3 0,0603 1 XCH BJBANK ; restore the old bank03767 3767 5 0,0015 0 TS BANK 03770 3770 3 0,0603 1 XCH BJBANK ; get the word03771 3771 0 0,0604 0 TC BJRET ; return INCL T4rupt_f.asm ; T4RUPT handler ;========================================================================== ; T4RUPT (file:T4rupt_f.asm) ; ; Version: 1.0 ; Author: John Pultorak ; Date: 01/09/2002 ; ; PURPOSE: ; Contains T4RUPT handler and DSPOUT subroutine to update DSKY. ;========================================================================== ; RELTAB is a packed table. RELAYWORD code in upper 4 bits, RELAY code ; in lower 5 bits. In COLOSSUS, p. 129. RELTAB EQU * 03772 3772 04025 1 DS %04025 03773 3773 10003 0 DS %10003 03774 3774 14031 0 DS %14031 03775 3775 20033 0 DS %20033 03776 3776 24017 1 DS %24017 03777 3777 30036 1 DS %30036 04000 4000 34034 1 DS %34034 04001 4001 40023 1 DS %40023 04002 4002 44035 1 DS %44035 04003 4003 50037 0 DS %50037 04004 4004 54000 0 DS %54000 04005 4005 60000 1 RELTAB11 DS %60000 ;-------------------------------------------------------------------------- ; DK_initDK - INITIALIZE DSKY ; ; Subroutine initializes the eraseable memory segment for DSKY displays. ; Blank DSKY registers program, verb, noun, R1, R2, R3. ; ; Adapted from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, Fresh Start and Restart, p.187. ;-------------------------------------------------------------------------- 04006 4006 05265 0 DKTESTINIT DS %5265 ; init DSKY to all zeroes (TEST ONLY)
DK_initDK EQU * 04007 4007 3 0,0001 0 XCH Q 04010 4010 5 0,0546 0 TS DK_IN_saveQ ; save return address 04011 4011 3 1,2060 0 CAF TEN ; blank DSKY registers04012 4012 5 0,0130 0 DSPOFF TS MPAC 04013 4013 4 1,2065 1 CS BIT12 ; CS DKTESTINIT ; set display to '0' 04014 4014 2 0,0130 1 INDEX MPAC 04015 4015 5 0,0512 1 TS DSPTAB 04016 4016 1 0,0130 1 CCS MPAC 04017 4017 0 2,4012 0 TC DSPOFF ; followed by additional DSKY initialization p 187, 188) 04020 4020 3 1,2050 0 CAF ZERO 04021 4021 5 0,0465 0 TS DSPCNT 04022 4022 5 0,0531 0 TS CADRSTOR 04023 4023 5 0,0502 0 TS REQRET 04024 4024 5 0,0504 0 TS CLPASS 04025 4025 5 0,0501 0 TS DSPLOCK 04026 4026 5 0,0507 0 TS MONSAVE ; kill monitor04027 4027 5 0,0510 0 TS MONSAVE1 04030 4030 5 0,0470 1 TS VERBREG 04031 4031 5 0,0471 0 TS NOUNREG 04032 4032 5 0,0532 0 TS DSPLIST 04033 4033 3 1,2105 1 CAF NOUTCON 04034 4034 5 0,0505 1 TS NOUT ; set DSKY display bit (sign bit). Word must be negative, but ; not minus zero (find out where they do this in COLOSSUS) 04035 4035 4 1,2051 0 CS ONE 04036 4036 5 0,0355 1 TS FLAGWRD5 ; initialize DSPCNT (index into DSPTAB). 04037 4037 3 1,2050 0 CAF ZERO 04040 4040 6 2,4072 0 AD TABLNTH 04041 4041 5 0,0465 0 TS DSPCNT ; schedule 1st T4RUPT 04042 4042 3 2,4074 0 CAF _120MRUPT ; reschedule interrupt for 120 mSec04043 4043 5 0,0040 0 TS TIME4 04044 4044 3 0,0546 0 XCH DK_IN_saveQ 04045 4045 5 0,0001 0 TS Q ; restore return address04046 4046 0 0,0000 0 RETURN ;-------------------------------------------------------------------------- ; T4PROG -- T4RUPT PROGRAM ; ; Performs T4RUPT (DSRUPT) functions. ; ; Adapted from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, p.129. ;-------------------------------------------------------------------------- T4PROG EQU * 04047 4047 3 0,0001 0 XCH Q 04050 4050 5 0,0544 1 TS T4RET ; save return address 04051 4051 0 2,4116 0 TC DSPOUT ; update DSKY display 04052 4052 3 2,4074 0 CAF _120MRUPT ; reschedule interrupt for 120 mSec04053 4053 5 0,0040 0 TS TIME4 04054 4054 3 0,0544 1 XCH T4RET 04055 4055 5 0,0001 0 TS Q ; restore return address04056 4056 0 0,0000 0 RETURN ;-------------------------------------------------------------------------- ; DSPOUT -- PUTS OUT DISPLAYS ; ; Writes changes in the software display buffer to the AGC DSKY hardware ; display. ; ; Adapted from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, p.131. ;-------------------------------------------------------------------------- DSPOUTSR EQU *
04057 4057 5 0,0505 1 TS NOUT ; decrement NOUT 04060 4060 4 1,2050 1 CS ZERO 04061 4061 5 0,0370 0 TS DSRUPTEM ; set to -0 for 1st pass thru DSPTAB 04062 4062 3 0,0465 0 XCH DSPCNT 04063 4063 6 1,2045 1 AD NEG0 ; to prevent +004064 4064 5 0,0465 0 TS DSPCNT DSPSCAN EQU * 04065 4065 2 0,0465 1 INDEX DSPCNT 04066 4066 1 0,0512 0 CCS DSPTAB ; test sign of DSPTAB + DSPCNT 04067 4067 1 0,0465 1 CCS DSPCNT ; >0, already displayed, test DSPCNT04070 4070 0 2,4063 0 TC DSPSCAN-2 ; if DSPCNT +, again04071 4071 0 2,4103 1 TC DSPLAY ; <0, not yet displayed 04072 4072 00012 1 TABLNTH DS %12 ; dec 10, length of DSPTAB04073 4073 1 0,0370 1 CCS DSRUPTEM ; if DSRUPTEM=+0, 2nd pass thru DSPTAB 04074 4074 37764 0 _120MRUPT DS 16372 ; (DSPCNT=0), +0 into NOUT 04075 4075 5 0,0505 1 TS NOUT ; DSRUPTEM=+0, every table entry was checked04076 4076 0 2,4126 0 TC DSPOUTEXIT ; return 04077 4077 5 0,0370 0 TS DSRUPTEM ; DSRUPTEM=-0, 1st pass thru DSPTAB04100 4100 3 2,4072 0 CAF TABLNTH ; (DSPCNT=0), +0 into DSRUPTEM, pass again04101 4101 0 2,4064 1 TC DSPSCAN-1 04102 4102 0 2,4126 0 TC DSPOUTEXIT ; return DSPLAY EQU * 04103 4103 6 1,2051 1 AD ONE 04104 4104 2 0,0465 1 INDEX DSPCNT 04105 4105 5 0,0512 1 TS DSPTAB ; replace positively04106 4106 7 2,4672 1 MASK LOW11 ; remove bits 12 to 1504107 4107 5 0,0370 0 TS DSRUPTEM 04110 4110 3 2,4666 0 CAF HI5 04111 4111 2 0,0465 1 INDEX DSPCNT 04112 4112 7 1,3772 1 MASK RELTAB ; pick up bits 12 to 15 of RELTAB entry04113 4113 6 0,0370 0 AD DSRUPTEM 04114 4114 5 0,0010 0 TS OUT0 ; was EXTEND/WRITE OUT0 in block II 04115 4115 0 2,4126 0 TC DSPOUTEXIT ; return DSPOUT EQU * 04116 4116 3 0,0001 0 XCH Q 04117 4117 5 0,0545 0 TS DSPOUTRET ; save return address 04120 4120 1 0,0355 0 CCS FLAGWRD5 ; no display unless DSKY flag (sign bit) on04121 4121 3 1,2050 0 CAF ZERO ; >0, DSKY disabled04122 4122 0 2,4126 0 TC NODSPOUT ; +0, DSKY disabled04123 4123 1 0,0505 0 CCS NOUT ; <0, DSKY enabled, so test NOUT04124 4124 0 2,4057 1 TC DSPOUTSR ; >0, handle display requests04125 4125 0 2,4126 0 TC NODSPOUT ; +0, no display requests NODSPOUT EQU * DSPOUTEXIT EQU * 04126 4126 3 0,0545 0 XCH DSPOUTRET ; return to calling routine04127 4127 5 0,0001 0 TS Q 04130 4130 0 0,0000 0 RETURN INCL keyrupt_f.asm ; KEYRUPT handler ;========================================================================== ; KEYRUPT (file:keyrupt_f.asm) ; ; Adapted from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, pp. 77. ;========================================================================== ;-------------------------------------------------------------------------- ; KEYRUPT -- KEYBOARD INTERRUPT HANDLER ; ; Performs keyRUPT functions. Triggered by a keyboard key entry. N-key ; rollover, implemented as follows: When an interrupt occurs, the current ; job record is saved and then restored when the job resumes after the ; interrupt. The job record includes MPAC, a set of general purpose ; registers assigned to the job. When the keyboard interrupt occurs, the ; interrupt handler stores the keyboard character in MPAC. A job is then ; started to process the character. The new job copies its MPAC fields from ; the current job, so the character is copied to storage owned by the job. ; When additional keyboard interrupts occur, they start their own jobs. ; Up to 7 jobs can be waiting in a queue for execution, so as many as ; 7 keyboard characters can be enqueued for processing. Since all keyboard ; jobs have the same priority, they are enqueued in the order received.
; Its OK for the keyboard handler to modify the MPAC of the interrupted job ; because the interrupted job's record is restored at the end of the ; interrupt service routine. ; ; Not included in my partial AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, so I had to improvise it from the original flow charts in ; E-1574, p.77. ;-------------------------------------------------------------------------- 04131 4131 37776 0 CHRPRIO DS %37776 ; priority of CHARIN job (highest) KEYPROG EQU * 04132 4132 3 0,0001 0 XCH Q 04133 4133 5 0,0601 0 TS KEYRET ; save return address ; prepare to EXEC a job to handle the keystroke. 04134 4134 3 0,0004 0 XCH IN0 04135 4135 7 2,4664 0 MASK LOW5 04136 4136 3 0,0130 0 XCH MPAC ; save keyboard code04137 4137 3 0,0551 0 XCH KP_MPAC ; save previous MPAC ; create the job. It terminates when it finishes processing the key. 04140 4140 3 2,4131 0 CAF CHRPRIO ; CHARIN job priority04141 4141 0 1,3162 1 TC NOVAC 04142 4142 12000 1 CADR CHARIN ; 14 bit CHARIN job address 04143 4143 3 0,0551 0 XCH KP_MPAC 04144 4144 3 0,0130 0 XCH MPAC ; restore previous MPAC 04145 4145 3 0,0601 0 XCH KEYRET 04146 4146 5 0,0001 0 TS Q ; restore return address04147 4147 0 0,0000 0 RETURN INCL math_f.asm ; DP math routines ;========================================================================== ; MATH LIBRARY (file:math_f.asm) ; ; Version: 1.0 ; Author: John Pultorak ; Date: 03/01/2002 ; ; PURPOSE: ; Contains double precision math routines. ;========================================================================== ;-------------------------------------------------------------------------- ; TPAGREE ; Force the signs in a triple precision (TP) word to agree. The word is ; in MPAC, MPAC+1, MPAC+2 ; ; The sign of the corrected number is always the sign of the most-significant ; non-zero word. ; ; This isn't included in my partial COLOSSUS listing, so I had to invent ; my own version. ;-------------------------------------------------------------------------- TPAGREE EQU * 04150 4150 3 0,0001 0 XCH Q 04151 4151 5 0,0577 1 TS MATH_Q ; return address ; Find the sign to convert to. It will be the sign ; of the most significant non-zero word. TPA_SGN0 EQU * 04152 4152 1 0,0130 1 CCS MPAC 04153 4153 0 2,4157 0 TC TPA_P0 ; >0, sign will be +04154 4154 0 2,4241 1 TC TPA_SGN1 ; +0, still don't know sign, check MPAC+104155 4155 0 2,4210 0 TC TPA_M0 ; <0, sign will be -04156 4156 0 2,4241 1 TC TPA_SGN1 ; -0, still don't know sign, check MPAC+1 ; MPAC is non-zero positive, so reconcile signs to a positive number. TPA_P0 EQU * 04157 4157 1 0,0131 0 CCS MPAC+1 04160 4160 0 2,4250 1 TC TPA_P1+2 ; >0, MPAC+1 is OK, check MPAC+204161 4161 0 2,4167 0 TC TPA_PZ0 ; +0, 04162 4162 0 2,4164 0 TC *+2 ; <0, fix MPAC+104163 4163 0 2,4167 0 TC TPA_PZ0 ; -0, 04164 4164 3 2,4317 0 CAF TPA_MPAC0 ; borrow from MPAC to correct MPAC+1
04165 4165 0 2,4337 1 TC TPA_FIXP 04166 4166 0 2,4250 1 TC TPA_P1+2 ; MPAC+1 is now non-zero positive; checkMPAC+2 ; MPAC is non-zero positive, MPAC+1 is zero TPA_PZ0 EQU * 04167 4167 1 0,0132 0 CCS MPAC+2 04170 4170 0 2,4175 0 TC *+5 ; >0, zero MPAC+1, MPAC+2 is OK04171 4171 0 2,4173 0 TC *+2 ; +0, MPAC+1, +2 both zero04172 4172 0 2,4200 1 TC TPA_PZ0FIX ; <0, 04173 4173 3 1,2050 0 CAF ZERO ; make sure they're both +004174 4174 5 0,0132 1 TS MPAC+2 04175 4175 3 1,2050 0 CAF ZERO 04176 4176 5 0,0131 1 TS MPAC+1 04177 4177 0 0,0577 1 TC MATH_Q ; MPAC is non-zero positive, MPAC+1 is zero, MPAC+2 is non-zero negative. ; Solution: borrow from MPAC, transfer borrowed value to MPAC+1, but also ; borrow from MPAC+1, use borrowed value to correct MPAC+2. TPA_PZ0FIX EQU * 04200 4200 3 0,0132 1 XCH MPAC+2 ; move MPAC+2 to MPAC+1 so we can use04201 4201 5 0,0131 1 TS MPAC+1 ; our standard correction function 04202 4202 3 2,4317 0 CAF TPA_MPAC0 ; borrow from MPAC to correct MPAC+104203 4203 0 2,4337 1 TC TPA_FIXP 04204 4204 3 2,4315 1 CAF MAXPOS ; move corrected value from MPAC+1 back04205 4205 3 0,0131 1 XCH MPAC+1 ; to MPAC+2. Set MPAC+1 to correct value04206 4206 5 0,0132 1 TS MPAC+2 ; borrowed from MPAC.04207 4207 0 0,0577 1 TC MATH_Q ; The MPAC is non-zero negative, so reconcile signs to a negative number. TPA_M0 EQU * 04210 4210 1 0,0131 0 CCS MPAC+1 04211 4211 0 2,4215 0 TC *+4 ; >0, fix MPAC+104212 4212 0 2,4220 0 TC TPA_MZ0 ; +0, 04213 4213 0 2,4264 0 TC TPA_M1+2 ; <0, MPAC+1 is OK, check MPAC+204214 4214 0 2,4220 0 TC TPA_MZ0 ; -0, 04215 4215 3 2,4317 0 CAF TPA_MPAC0 ; borrow from MPAC to correct MPAC+104216 4216 0 2,4321 0 TC TPA_FIXM 04217 4217 0 2,4264 0 TC TPA_M1+2 ; MPAC is non-zero negative, MPAC+1 is zero TPA_MZ0 EQU * 04220 4220 1 0,0132 0 CCS MPAC+2 04221 4221 0 2,4231 0 TC TPA_MZ0FIX ; >0, 04222 4222 0 2,4224 1 TC *+2 ; +0, MPAC+1, +2 both zero04223 4223 0 2,4226 0 TC *+3 ; <0, zero MPAC+1, MPAC+2 is OK 04224 4224 3 1,2045 1 CAF NEG0 ; make sure they're both -004225 4225 5 0,0132 1 TS MPAC+2 04226 4226 3 1,2045 1 CAF NEG0 04227 4227 5 0,0131 1 TS MPAC+1 04230 4230 0 0,0577 1 TC MATH_Q ; MPAC is non-zero negative, MPAC+1 is zero, MPAC+2 is non-zero positive ; Solution: borrow from MPAC, transfer borrowed value to MPAC+1, but also ; borrow from MPAC+1, use borrowed value to correct MPAC+2. TPA_MZ0FIX EQU * 04231 4231 3 0,0132 1 XCH MPAC+2 ; move MPAC+2 to MPAC+1 so we can use04232 4232 5 0,0131 1 TS MPAC+1 ; our standard correction function 04233 4233 3 2,4317 0 CAF TPA_MPAC0 ; borrow from MPAC to correct MPAC+104234 4234 0 2,4321 0 TC TPA_FIXM 04235 4235 3 2,4316 1 CAF MAXNEG ; move corrected value from MPAC+1 back04236 4236 3 0,0131 1 XCH MPAC+1 ; to MPAC+2. Set MPAC+1 to correct value04237 4237 5 0,0132 1 TS MPAC+2 ; borrowed from MPAC.04240 4240 0 0,0577 1 TC MATH_Q ; MPAC was zero, so we still don't know the sign. Check MPAC+1. TPA_SGN1 EQU * 04241 4241 1 0,0131 0 CCS MPAC+1 04242 4242 0 2,4246 0 TC TPA_P1 ; >0, sign will be +04243 4243 0 2,4277 1 TC TPA_SGN2 ; +0, still don't know sign, check MPAC+204244 4244 0 2,4262 0 TC TPA_M1 ; <0, sign will be -04245 4245 0 2,4277 1 TC TPA_SGN2 ; -0, still don't know sign, check MPAC+2
; MPAC+1 is non-zero positive, so reconcile signs to a positive number. TPA_P1 EQU * 04246 4246 3 1,2050 0 CAF ZERO 04247 4247 5 0,0130 0 TS MPAC ; set MPAC to +0 04250 4250 1 0,0132 0 CCS MPAC+2 04251 4251 0 0,0577 1 TC MATH_Q ; >0, all words are positive04252 4252 0 0,0577 1 TC MATH_Q ; +0, all words are positive04253 4253 0 2,4257 0 TC *+4 ; <0, MPAC+2 is nonzero -04254 4254 3 1,2050 0 CAF ZERO ; -0, change to +0 and we're done04255 4255 5 0,0132 1 TS MPAC+2 04256 4256 0 0,0577 1 TC MATH_Q 04257 4257 3 2,4320 1 CAF TPA_MPAC1 ; borrow from MPAC+1 to correct MPAC+204260 4260 0 2,4337 1 TC TPA_FIXP 04261 4261 0 0,0577 1 TC MATH_Q ; MPAC+1 is non-zero negative, so reconcile signs to a negative number. TPA_M1 EQU * 04262 4262 3 1,2045 1 CAF NEG0 04263 4263 5 0,0130 0 TS MPAC ; set MPAC to -0 04264 4264 1 0,0132 0 CCS MPAC+2 04265 4265 0 2,4274 1 TC *+7 ; >0, MPAC+2 is nonzero +04266 4266 0 2,4271 1 TC *+3 ; +0, change to -0 and we're done04267 4267 0 0,0577 1 TC MATH_Q ; <0, all words are negative04270 4270 0 0,0577 1 TC MATH_Q ; -0, all words are negative 04271 4271 3 1,2045 1 CAF NEG0 ; +0, change to -0 and we're done04272 4272 5 0,0132 1 TS MPAC+2 04273 4273 0 0,0577 1 TC MATH_Q 04274 4274 3 2,4320 1 CAF TPA_MPAC1 ; borrow from MPAC+1 to correct MPAC+204275 4275 0 2,4321 0 TC TPA_FIXM 04276 4276 0 0,0577 1 TC MATH_Q ; MPAC and MPAC+1 were both zero, so we still don't know the sign. ; Check MPAC+2. TPA_SGN2 EQU * 04277 4277 1 0,0132 0 CCS MPAC+2 04300 4300 0 2,4304 1 TC TPA_P2 ; >0, sign is +04301 4301 0 2,4310 1 TC TPA_P3 ; +0, number is all zeros04302 4302 0 2,4306 0 TC TPA_M2 ; <0, sign is -04303 4303 0 2,4310 1 TC TPA_P3 ; -0, number is all zeros 04304 4304 3 1,2050 0 TPA_P2 CAF ZERO 04305 4305 0 2,4312 0 TC *+5 ; set MPAC, MPAC+1 to +0 04306 4306 3 1,2045 1 TPA_M2 CAF NEG0 ; set MPAC, MPAC+1 to -004307 4307 0 2,4312 0 TC *+3 04310 4310 3 1,2050 0 TPA_P3 CAF ZERO 04311 4311 5 0,0132 1 TS MPAC+2 ; set MPAC, MPAC+1, MPAC+2 to +0 04312 4312 5 0,0131 1 TS MPAC+1 04313 4313 5 0,0130 0 TS MPAC 04314 4314 0 0,0577 1 TC MATH_Q 04315 4315 37777 1 MAXPOS DS %37777 ; largest non-overflow pos number04316 4316 40000 0 MAXNEG DS %40000 ; largest non-overflow neg number 04317 4317 00130 0 TPA_MPAC0 DS MPAC 04320 4320 00131 1 TPA_MPAC1 DS MPAC+1 ;-------------------------------------------------------------------------- ; TPA_FIXM ; Reconcile the signs in a double precision word. The most significant word ; is in C(A), the lesser word in C(A+1). Reconcilliation occurs by borrowing ; from C(A) and adding the borrowed amount to C(A+1). C(A) is assumed to be ; negative non-zero number and C(A+1) positive non-zero. The reconciliation ; makes both numbers negative. ; ; This is part of my implementation of TPAGREE. ;-------------------------------------------------------------------------- TPA_FIXM EQU * 04321 4321 5 0,0576 0 TS ADDRWD1 04322 4322 2 0,0576 1 INDEX ADDRWD1 04323 4323 4 0,0000 0 CS 0 ; borrow from 1st word
04324 4324 1 0,0000 0 CCS A 04325 4325 4 0,0000 0 COM 04326 4326 2 0,0576 1 INDEX ADDRWD1 04327 4327 5 0,0000 1 TS 0 04330 4330 3 2,4316 1 CAF MAXNEG 04331 4331 6 1,2046 1 AD NEG1 ; create negative overflow04332 4332 2 0,0576 1 INDEX ADDRWD1 04333 4333 6 0,0001 0 AD 1 ; correct 2nd word, changes sign04334 4334 2 0,0576 1 INDEX ADDRWD1 04335 4335 5 0,0001 0 TS 1 04336 4336 0 0,0001 0 TC Q ;-------------------------------------------------------------------------- ; TPA_FIXP ; Reconcile the signs in a double precision word. The most significant word ; is in C(A), the lesser word in C(A+1). Reconcilliation occurs by borrowing ; from C(A) and adding the borrowed amount to C(A+1). C(A) is assumed to be ; positive non-zero number and C(A+1) negative non-zero. The reconciliation ; makes both numbers positive. ; ; This is part of my implementation of TPAGREE. ;-------------------------------------------------------------------------- TPA_FIXP EQU * 04337 4337 5 0,0576 0 TS ADDRWD1 04340 4340 2 0,0576 1 INDEX ADDRWD1 04341 4341 1 0,0000 0 CCS 0 ; borrow from 1st word04342 4342 2 0,0576 1 INDEX ADDRWD1 04343 4343 5 0,0000 1 TS 0 04344 4344 3 2,4315 1 CAF MAXPOS 04345 4345 6 1,2051 1 AD ONE ; create positive overflow04346 4346 2 0,0576 1 INDEX ADDRWD1 04347 4347 6 0,0001 0 AD 1 ; correct 2nd word, changes sign04350 4350 2 0,0576 1 INDEX ADDRWD1 04351 4351 5 0,0001 0 TS 1 04352 4352 0 0,0001 0 TC Q ;-------------------------------------------------------------------------- ; SHORTMP -- MULTIPLY DOUBLE WORD BY A SINGLE WORD ; Multiply C(MPAC, MPAC+1) by the contents of A. Put the product in MPAC, ; MPAC+1, MPAC+2. ;; ; These aren't included in my partial COLOSSUS listing, so I had to invent ; my own version. ;-------------------------------------------------------------------------- SHORTMP EQU * 04353 4353 5 0,0573 0 TS SHORTMP_A ; MPAC+2 = MPAC+1 * A 04354 4354 2 0,0000 1 EXTEND 04355 4355 4 0,0131 0 MP MPAC+1 04356 4356 5 0,0574 1 TS SHORTMP_OVFL 04357 4357 3 0,0003 1 XCH LP 04360 4360 5 0,0132 1 TS MPAC+2 ; MPAC+1 = (MPAC * A) + overflow 04361 4361 3 0,0573 0 XCH SHORTMP_A 04362 4362 2 0,0000 1 EXTEND 04363 4363 4 0,0130 1 MP MPAC 04364 4364 5 0,0575 0 TS SHORTMP_OVFH 04365 4365 3 0,0003 1 XCH LP 04366 4366 6 0,0574 1 AD SHORTMP_OVFL 04367 4367 5 0,0131 1 TS MPAC+1 ; skip on overflow04370 4370 3 1,2050 0 CAF ZERO ; otherwise, make interword carry=0 ; MPAC = overflow 04371 4371 6 0,0575 0 AD SHORTMP_OVFH 04372 4372 5 0,0130 0 TS MPAC 04373 4373 0 0,0001 0 TC Q ; return ;-------------------------------------------------------------------------- ; DMP -- DOUBLE PRECISION MULTIPLY ; Multiply val, val+1 with C(MPAC, MPAC+1). 'ADDRWD1' contains the ; address of 'val'. The product appears in MPAC, MPAC+1, MPAC+2 ; ; This isn't included in my partial COLOSSUS listing, but is taken from
; the double precision math examples in R-393. ;-------------------------------------------------------------------------- DMP EQU * 04374 4374 2 0,0001 1 INDEX Q 04375 4375 3 0,0000 1 CAF 0 04376 4376 6 2,5777 0 AD EXTENDER 04377 4377 5 0,0576 0 TS ADDRWD1 04400 4400 3 0,0131 1 XCH MPAC+1 04401 4401 5 0,0034 0 TS OVCTR 04402 4402 2 0,0576 1 INDEX ADDRWD1 04403 4403 4 0,0001 1 MP 1 04404 4404 3 0,0034 0 XCH OVCTR 04405 4405 2 0,0576 1 INDEX ADDRWD1 04406 4406 4 0,0000 0 MP 0 04407 4407 3 0,0034 0 XCH OVCTR 04410 4410 6 0,0003 1 AD LP 04411 4411 3 0,0130 0 XCH MPAC 04412 4412 5 0,0132 1 TS MPAC+2 04413 4413 2 0,0576 1 INDEX ADDRWD1 04414 4414 4 0,0001 1 MP 1 04415 4415 3 0,0034 0 XCH OVCTR 04416 4416 3 0,0130 0 XCH MPAC 04417 4417 6 0,0003 1 AD LP 04420 4420 3 0,0132 1 XCH MPAC+2 04421 4421 2 0,0576 1 INDEX ADDRWD1 04422 4422 4 0,0000 0 MP 0 04423 4423 3 0,0034 0 XCH OVCTR 04424 4424 6 0,0130 0 AD MPAC 04425 4425 6 0,0003 1 AD LP 04426 4426 3 0,0131 1 XCH MPAC+1 04427 4427 3 0,0034 0 XCH OVCTR 04430 4430 5 0,0130 0 TS MPAC 04431 4431 3 0,0001 0 XCH Q ; skip next word on return04432 4432 6 1,2051 1 AD ONE 04433 4433 5 0,0001 0 TS Q 04434 4434 0 0,0001 0 TC Q BANKFF_1 EQU * ;------------------------------------------------------------------------- ; PINBALL ; ; Now, do the "pinball game" (DSKY) routines. ; ; Mimic the bank assignments in COLOSSUS. Since this is a block I AGC that ; has fewer banks, different bank numbers are used, but the sequence and ; relative allocation of routines to various banks is preserved. ;------------------------------------------------------------------------- ; don't change BANK04_1 without also changing V37BANK BANK04_1 EQU BANK4 ; was BANK 04 in COLOSSUS BANK40_1 EQU BANK5 ; was BANK 40 in COLOSSUS BANK41_1 EQU BANK6 ; was BANK 41 in COLOSSUS BANK42_1 EQU BANK7 ; was BANK 42 in COLOSSUS BANK43_1 EQU BANK10 ; was BANK 43 in COLOSSUS ; start of COLOSSUS routines ORG BANK04_1 ; COLOSSUS pp. 192-204 INCL bank04_1.asm ;========================================================================== ; MAJOR MODE CHANGE (file:bank04_1.asm) ; ; Adapted from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, pp. 192-204. ;========================================================================== ;-------------------------------------------------------------------------- ; VERB 37 ; ; In COLOSSUS, a successful V37 apparently also restarts the AGC. Here, ; we implement a subset of COLOSSUS to kick off a job associated with the ; verb. ; ; Adapted from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, p.192-204. ;--------------------------------------------------------------------------
V37 EQU * ; verb 3710000 4,0000 5 0,0464 1 TS MMNUMBER ; save major mode ; ** skipped quite a bit of guidance system-related code ** 10001 4,0001 0 4,6005 1 TC CHECKTAB ; ** skipped more guidance system-related code ** V37BAD EQU * 10002 4,0002 0 2,5003 1 TC RELDSP ; releases display from astronaut10003 4,0003 0 1,3653 1 TC POSTJUMP ; bring back last normal display if there10004 4,0004 05067 0 CADR PINBRNCH ; was one, OY ; Search table for entry matching major mode number. Table entries ; are sorted by major mode number, so the search occurs in order from ; lowest number to highest. CHECKTAB EQU * 10005 4,0005 3 1,2050 0 CAF ZERO ; was CA NOV37MM in Block II10006 4,0006 6 4,6046 0 AD NOV37MM ; the no. of MM in table (minus 1) 10007 4,0007 5 0,0131 1 AGAINMM TS MPAC+1 10010 4,0010 3 1,2050 0 CAF ZERO ; was CA PREMM1 in Block II10011 4,0011 2 0,0131 0 INDEX MPAC+1 10012 4,0012 6 4,6037 0 AD PREMM1 ; obtain which MM this is for10013 4,0013 7 1,2101 1 MASK LOW7 10014 4,0014 4 0,0000 0 COM 10015 4,0015 6 0,0464 1 AD MMNUMBER 10016 4,0016 1 0,0000 0 CCS A ; MMNUMBER - current table MM number 10017 4,0017 1 0,0131 0 CCS MPAC+1 ; if GR, see if anymore in list10020 4,0020 0 4,6007 0 TC AGAINMM ; yes, get next one (was TCF)10021 4,0021 0 4,6026 0 TC V37NONO ; last time or passed MM (was TCF) ; Found the index into the major mode table for entry matching the ; major mode number input by the user. 10022 4,0022 3 1,2050 0 CAF ZERO ; was CA MPAC+1 in Block II10023 4,0023 6 0,0131 1 AD MPAC+1 10024 4,0024 5 0,0463 0 TS MINDEX ; save index for later 10025 4,0025 0 1,2147 1 TC goMMchange ; in Block II, jumped to restart AGC ; Requested MM doesn't exist V37NONO EQU * 10026 4,0026 0 2,4701 0 TC FALTON ; come here if MM requested doesn't exist10027 4,0027 0 4,6002 0 TC V37BAD ;-------------------------------------------------------------------------- ; FCADRMM ; ; For verb 37, two tables are maintained. Each table has an entry for each ; major mode that can be started from the keyboard. The entries are put ; into the table with the entry for the highest major mode coming first, ; to the lowest major mode which is the last entry in the table. ; ; The FCADRMM table contains the FCADR of the starting job of the major mode. ; ; The entries in this table must match the entries in PREMM1 below. ;-------------------------------------------------------------------------- FCADRMM1 EQU * 10030 4,0030 22147 0 CADR P79 10031 4,0031 22142 0 CADR P78 10032 4,0032 22127 0 CADR P04 10033 4,0033 22066 1 CADR P03 10034 4,0034 22036 1 CADR P02 10035 4,0035 22022 1 CADR P01 10036 4,0036 22000 1 CADR P00 ; etc ********* ;-------------------------------------------------------------------------- ; PREMM1 ; ; The PREMM1 table contains the E-bank, major mode, and priority information. ; It is in the following form: ; ; PPP PPE EEM MMM MMM ; ; Where, ; the 7 'M' bits contain the major mode number
; the 3 'E' bits contain the E-bank number (ignored in Block I) ; the 5 'P' bits contain the priority at which the job is to be started ; ; The entries in this table must match the entries in FCADRMM1 above. ;-------------------------------------------------------------------------- PREMM1 EQU * 10037 4,0037 26117 1 DS %26117 ; MM 79, PRIO 1310040 4,0040 26116 0 DS %26116 ; MM 78, PRIO 1310041 4,0041 26004 1 DS %26004 ; MM 04, PRIO 1310042 4,0042 26003 0 DS %26003 ; MM 03, PRIO 1310043 4,0043 26002 1 DS %26002 ; MM 02, PRIO 1310044 4,0044 26001 1 DS %26001 ; MM 01, PRIO 1310045 4,0045 26000 0 DS %26000 ; MM 00, PRIO 13 ; etc ********* EPREMM1 EQU * 10046 4,0046 00006 1 NOV37MM DS EPREMM1-PREMM1-1 ; number of entries in table (minus 1) BANK04_2 EQU * ORG BANK40_1 ; COLOSSUS pp. 310-317 INCL bank40_1.asm ;========================================================================== ; PINBALL GAME (file:bank40_1.asm) ; ; AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, p.310-317. ;========================================================================== ;-------------------------------------------------------------------------- ; CHARIN -- PROCESS KEYBOARD CHARACTER FROM KEYRUPT ; ; Adapted from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, p.310. ;-------------------------------------------------------------------------- CHARIN EQU * 12000 5,0000 3 1,2051 1 CAF ONE ; block display syst12001 5,0001 3 0,0501 0 XCH DSPLOCK ; make dsp syst busy, but save old12002 5,0002 5 0,0412 0 TS _2122REG ; C(DSPLOCK) for error light reset12003 5,0003 1 0,0531 1 CCS CADRSTOR ; all keys except ER turn on KR lite if12004 5,0004 0 5,6006 1 TC *+2 ; CADRSTOR is full. This reminds operator12005 5,0005 0 5,6016 0 TC CHARIN2 ; to re-establish a flashing display12006 5,0006 4 5,6062 1 CS ELRCODE1 ; which he has obscured with displays of12007 5,0007 6 0,0130 0 AD MPAC ; his own (see remarks preceding routine ; VBRELDSP). 12010 5,0010 1 0,0000 0 CCS A ; was BZF CHARIN2 in Block II12011 5,0011 0 5,6015 0 TC *+4 ; >012012 5,0012 0 5,6014 1 TC *+2 ; +012013 5,0013 0 5,6015 0 TC *+2 ; <012014 5,0014 0 5,6016 0 TC CHARIN2 ; -0 12015 5,0015 0 2,4713 0 TC RELDSPON CHARIN2 EQU * 12016 5,0016 3 0,0130 0 XCH MPAC 12017 5,0017 5 0,0414 0 TS CHAR 12020 5,0020 2 0,0000 0 INDEX A 12021 5,0021 0 5,6022 1 TC *+1 ; input_code function12022 5,0022 0 5,7307 1 TC CHARALRM ; 012023 5,0023 0 5,6101 1 TC NUM ; 112024 5,0024 0 5,6101 1 TC NUM ; 212025 5,0025 0 5,6101 1 TC NUM ; 312026 5,0026 0 5,6101 1 TC NUM ; 412027 5,0027 0 5,6101 1 TC NUM ; 512030 5,0030 0 5,6101 1 TC NUM ; 612031 5,0031 0 5,6101 1 TC NUM ; 712032 5,0032 0 5,6065 1 TC _89TEST 12033 5,0033 0 5,6065 1 TC _89TEST ; 11 912034 5,0034 0 5,7307 1 TC CHARALRM ; 1212035 5,0035 0 5,7307 1 TC CHARALRM ; 1312036 5,0036 0 5,7307 1 TC CHARALRM ; 1412037 5,0037 0 5,7307 1 TC CHARALRM ; 1512040 5,0040 0 5,7307 1 TC CHARALRM ; 1612041 5,0041 0 5,7307 1 TC CHARALRM ; 1712042 5,0042 0 5,6077 1 TC NUM-2 ; 20 012043 5,0043 0 5,6272 0 TC VERB ; 21 VERB12044 5,0044 0 5,7462 0 TC ERROR ; 22 ERROR LIGHT RESET12045 5,0045 0 5,7307 1 TC CHARALRM ; 2312046 5,0046 0 5,7307 1 TC CHARALRM ; 2412047 5,0047 0 5,7307 1 TC CHARALRM ; 2512050 5,0050 0 5,7307 1 TC CHARALRM ; 2612051 5,0051 0 5,7307 1 TC CHARALRM ; 2712052 5,0052 0 5,7307 1 TC CHARALRM ; 3012053 5,0053 0 5,7327 0 TC VBRELDSP ; 31 KEY RELEASE
12054 5,0054 0 5,6326 0 TC POSGN ; 32 +12055 5,0055 0 5,6312 1 TC NEGSGN ; 33 -12056 5,0056 0 5,6063 1 TC ENTERJMP ; 34 ENTER12057 5,0057 0 5,7307 1 TC CHARALRM ; 3512060 5,0060 0 5,6412 0 TC CLEAR ; 36 CLEAR12061 5,0061 0 5,6306 1 TC NOUN ; 37 NOUN 12062 5,0062 00022 1 ELRCODE1 DS %22 12063 5,0063 0 1,3653 1 ENTERJMP TC POSTJUMP 12064 5,0064 14002 0 DS ENTER _89TEST EQU * 12065 5,0065 1 0,0466 1 CCS DSPCOUNT 12066 5,0066 0 5,6072 1 TC *+4 ; >012067 5,0067 0 5,6072 1 TC *+3 ; +012070 5,0070 0 1,2723 0 TC ENDOFJOB ; <0, block data in if DSPCOUNT is <0 or -012071 5,0071 0 1,2723 0 TC ENDOFJOB ; -0 12072 5,0072 3 1,2053 0 CAF THREE 12073 5,0073 7 0,0467 0 MASK DECBRNCH 12074 5,0074 1 0,0000 0 CCS A 12075 5,0075 0 5,6101 1 TC NUM ; if DECBRNCH is +, 8 or 9 OK12076 5,0076 0 5,7307 1 TC CHARALRM ; if DECBRNCH is +0, reject 8 or 9 ;-------------------------------------------------------------------------- ; NUM -- PROCESS NUMERICAL KEYBOARD CHARACTER ; Assembles octal, 3 bits at a time. For decimal, it converts incoming word ; as a fraction, keeping results to DP (double precision). ; Octal results are left in XREG, YREG, or ZREG. High part of DEC in XREG, ; YREG, ZREG; the low parts in XREGLP, YREGLP, or ZREGLP). ; DECBRNCH is left at +0 for octal, +1 for +DEC, +2 for -DEC. ; If DSPCOUNT was left -, no more data is accepted. ; ; Adapted from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, p.311. ;-------------------------------------------------------------------------- 12077 5,0077 3 1,2050 0 CAF ZERO 12100 5,0100 5 0,0414 0 TS CHAR NUM EQU * 12101 5,0101 1 0,0466 1 CCS DSPCOUNT 12102 5,0102 0 5,6106 0 TC *+4 ; >012103 5,0103 0 5,6106 0 TC *+3 ; +012104 5,0104 0 5,6105 0 TC *+1 ; <0, block datain if DSPCOUNT is <0 or -012105 5,0105 0 1,2723 0 TC ENDOFJOB ; -012106 5,0106 0 5,6241 0 TC GETINREL 12107 5,0107 1 0,0504 1 CCS CLPASS ; if CLPASS is >0 or +0, make it +012110 5,0110 3 1,2050 0 CAF ZERO 12111 5,0111 5 0,0504 0 TS CLPASS 12112 5,0112 0 5,6113 1 TC *+1 12113 5,0113 2 0,0414 1 INDEX CHAR 12114 5,0114 3 1,3772 0 CAF RELTAB 12115 5,0115 7 2,4664 0 MASK LOW5 12116 5,0116 5 0,0421 0 TS CODE 12117 5,0117 3 1,2050 0 CAF ZERO ; was CA DSPCOUNT in Block II12120 5,0120 6 0,0466 0 AD DSPCOUNT 12121 5,0121 5 0,0440 1 TS COUNT 12122 5,0122 0 5,7161 0 TC DSPIN 12123 5,0123 3 1,2053 0 CAF THREE 12124 5,0124 7 0,0467 0 MASK DECBRNCH 12125 5,0125 1 0,0000 0 CCS A ; +0=octal, +1=+dec, +2=-dec12126 5,0126 0 5,6137 1 TC DECTOBIN ; >012127 5,0127 2 0,0434 0 INDEX INREL ; +0 (octal)12130 5,0130 3 0,0470 1 XCH VERBREG 12131 5,0131 5 0,0022 1 TS CYL 12132 5,0132 4 0,0022 0 CS CYL 12133 5,0133 4 0,0022 0 CS CYL 12134 5,0134 3 0,0022 1 XCH CYL 12135 5,0135 6 0,0414 0 AD CHAR 12136 5,0136 0 5,6155 0 TC ENDNMTST DECTOBIN EQU * 12137 5,0137 2 0,0434 0 INDEX INREL 12140 5,0140 3 0,0470 1 XCH VERBREG 12141 5,0141 5 0,0130 0 TS MPAC ; sum x 2EXP-14 in MPAC12142 5,0142 3 1,2050 0 CAF ZERO 12143 5,0143 5 0,0131 1 TS MPAC+1 12144 5,0144 3 1,2060 0 CAF TEN ; 10 x 3EXP-1412145 5,0145 0 2,4353 0 TC SHORTMP ; 10SUM x 2EXP-28 in MPAC, MPAC+1 12146 5,0146 3 0,0131 1 XCH MPAC+1 12147 5,0147 6 0,0414 0 AD CHAR 12150 5,0150 5 0,0131 1 TS MPAC+1 12151 5,0151 0 5,6155 0 TC ENDNMTST ; no overflow 12152 5,0152 6 0,0130 0 AD MPAC ; overflow, must be 5th character
12153 5,0153 5 0,0130 0 TS MPAC 12154 5,0154 0 5,6176 1 TC DECEND ENDNMTST EQU * 12155 5,0155 2 0,0434 0 INDEX INREL 12156 5,0156 5 0,0470 1 TS VERBREG 12157 5,0157 4 0,0466 1 CS DSPCOUNT 12160 5,0160 2 0,0434 0 INDEX INREL 12161 5,0161 6 5,6232 1 AD CRITCON 12162 5,0162 1 0,0000 0 CCS A ; was BZF ENDNUM in Block II12163 5,0163 0 5,6167 1 TC *+4 ; >012164 5,0164 0 5,6166 0 TC *+2 ; +0, DSPCOUNT = CRITCON12165 5,0165 0 5,6167 1 TC *+2 ; <012166 5,0166 0 5,6170 1 TC ENDNUM ; -0 12167 5,0167 0 5,6227 0 TC MORNUM ; - , DSPCOUNT G/ CRITCON ENDNUM EQU * 12170 5,0170 3 1,2053 0 CAF THREE 12171 5,0171 7 0,0467 0 MASK DECBRNCH 12172 5,0172 1 0,0000 0 CCS A 12173 5,0173 0 5,6176 1 TC DECEND ENDALL EQU * 12174 5,0174 4 0,0466 1 CS DSPCOUNT ; block NUMIN by placing DSPCOUNT12175 5,0175 0 5,6230 0 TC MORNUM+1 ; negatively DECEND EQU * 12176 5,0176 4 1,2051 0 CS ONE 12177 5,0177 6 0,0434 1 AD INREL 12200 5,0200 1 0,0000 0 CCS A ; was BZMF ENDALL in Block II12201 5,0201 0 5,6205 0 TC *+4 ; >012202 5,0202 0 5,6204 1 TC *+2 ; +0, INREL=0,1(VBREG,NNREG), leave whole12203 5,0203 0 5,6204 1 TC *+1 ; <0, INREL=0,1(VBREG,NNREG), leave whole12204 5,0204 0 5,6174 0 TC ENDALL ; -0, INREL=0,1(VBREG,NNREG), leave whole 12205 5,0205 0 2,4374 0 TC DMP ; if INREL=2,3,4(R1,R2,R3), convert to frac ; mult sum x2EXP-28 in MPAC, MPAC+1 by12206 5,0206 06237 1 ADRES DECON ; 2EXP14/10EPX5. Gives(sum/10EXP5)x2EXP-14 ; in MPAC, +1, +212207 5,0207 3 1,2053 0 CAF THREE 12210 5,0210 7 0,0467 0 MASK DECBRNCH 12211 5,0211 2 0,0000 0 INDEX A 12212 5,0212 0 5,6212 0 TC *+0 12213 5,0213 0 5,6220 1 TC PDECSGN 12214 5,0214 4 0,0131 0 CS MPAC+1 ; - case (was DCS, DXCH in Block II)12215 5,0215 5 0,0131 1 TS MPAC+1 12216 5,0216 4 0,0132 0 CS MPAC+2 12217 5,0217 5 0,0132 1 TS MPAC+2 PDECSGN EQU * 12220 5,0220 3 0,0132 1 XCH MPAC+2 12221 5,0221 2 0,0434 0 INDEX INREL 12222 5,0222 5 0,0473 1 TS XREGLP-2 12223 5,0223 3 0,0131 1 XCH MPAC+1 12224 5,0224 2 0,0434 0 INDEX INREL 12225 5,0225 5 0,0470 1 TS VERBREG 12226 5,0226 0 5,6174 0 TC ENDALL MORNUM EQU * 12227 5,0227 1 0,0466 1 CCS DSPCOUNT ; decrement DSPCOUNT12230 5,0230 5 0,0466 0 TS DSPCOUNT 12231 5,0231 0 1,2723 0 TC ENDOFJOB CRITCON EQU * 12232 5,0232 00022 1 DS %22 ; dec 1812233 5,0233 00020 0 DS %20 ; dec 1612234 5,0234 00012 1 DS %12 ; dec 1012235 5,0235 00005 1 DS %5 12236 5,0236 00000 1 DS %0 DECON EQU * 12237 5,0237 05174 0 DS %05174 ; 2EXP14/10EXP5 = .16384 DEC12240 5,0240 13261 0 DS %13261 ;-------------------------------------------------------------------------- ; GETINREL ; Gets proper data register relative address for current C(DSPCOUNT) and ; puts into INREL: +0 VERBREG, 1 NOUNREG, 2 XREG, 3 YREG, 4 ZREG ;
; Adapted from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, p.313. ;-------------------------------------------------------------------------- GETINREL EQU * 12241 5,0241 2 0,0466 1 INDEX DSPCOUNT 12242 5,0242 3 5,6245 1 CAF INRELTAB 12243 5,0243 5 0,0434 1 TS INREL ; (A TEMP, REG)12244 5,0244 0 0,0001 0 TC Q INRELTAB EQU * 12245 5,0245 00004 0 DS %4 ; R3D5, 0 = DSPCOUNT12246 5,0246 00004 0 DS %4 ; R3D4, 112247 5,0247 00004 0 DS %4 ; R3D3, 212250 5,0250 00004 0 DS %4 ; R3D2, 312251 5,0251 00004 0 DS %4 ; R3D1, 412252 5,0252 00003 1 DS %3 ; R2D5, 512253 5,0253 00003 1 DS %3 ; R2D4, 612254 5,0254 00003 1 DS %3 ; R2D3, 712255 5,0255 00003 1 DS %3 ; R2D2, 8D12256 5,0256 00003 1 DS %3 ; R2D1, 9D12257 5,0257 00002 0 DS %2 ; R1D5, 10D12260 5,0260 00002 0 DS %2 ; R1D4, 11D12261 5,0261 00002 0 DS %2 ; R1D3, 12D12262 5,0262 00002 0 DS %2 ; R1D2, 13D12263 5,0263 00002 0 DS %2 ; R1D1, 14D12264 5,0264 0 5,6271 0 TC CCSHOLE ; no DSPCOUNT numbers12265 5,0265 00001 0 DS %1 ; ND2, 16D12266 5,0266 00001 0 DS %1 ; ND1, 17D12267 5,0267 00000 1 DS %0 ; VD2, 18D12270 5,0270 00000 1 DS %0 ; VD1, 19D 12271 5,0271 0 1,2723 0 CCSHOLE TC ENDOFJOB ; can't find this anywhere; best guess ;-------------------------------------------------------------------------- ; VERB ; Verb key was pressed; prepare to enter a 2 decimal digit verb. ; Blank the verb display and call ENDOFJOB. ; ; NOUN ; Noun key was pressed; prepare to enter a 2 decimal digit noun. ; Blank the noun display and call ENDOFJOB. ; ; Adapted from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, p.314. ;-------------------------------------------------------------------------- VERB EQU * 12272 5,0272 3 1,2050 0 CAF ZERO 12273 5,0273 5 0,0470 1 TS VERBREG 12274 5,0274 3 2,4675 1 CAF VD1 NVCOM EQU * 12275 5,0275 5 0,0466 0 TS DSPCOUNT 12276 5,0276 0 5,6540 0 TC _2BLANK 12277 5,0277 3 1,2051 1 CAF ONE 12300 5,0300 5 0,0467 1 TS DECBRNCH ; set for dec V/N code12301 5,0301 3 1,2050 0 CAF ZERO 12302 5,0302 5 0,0502 0 TS REQRET ; set for ENTPAS012303 5,0303 3 2,4553 0 CAF ENDINST ; if DSPALARM occurs before first ENTPAS012304 5,0304 5 0,0433 0 TS ENTRET ; or NVSUB, ENTRET must already be set ; to TC ENDOFJOB12305 5,0305 0 1,2723 0 TC ENDOFJOB NOUN EQU * 12306 5,0306 3 1,2050 0 CAF ZERO 12307 5,0307 5 0,0471 0 TS NOUNREG 12310 5,0310 3 2,4676 1 CAF ND1 ; ND1, OCT 21 (DEC 17)12311 5,0311 0 5,6275 1 TC NVCOM ;-------------------------------------------------------------------------- ; NEGSGN ; Turn the minus sign on for the register selected by DSPCOUNT. ; Call ENDOFJOB when done. ; ; POSGN ; Turn the plus sign on for the register selected by DSPCOUNT. ; Call ENDOFJOB when done. ; ; Adapted from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, p.314. ;-------------------------------------------------------------------------- NEGSGN EQU *
12312 5,0312 0 5,6367 0 TC SIGNTEST 12313 5,0313 0 5,6353 1 TC M_ON 12314 5,0314 3 1,2052 1 CAF TWO BOTHSGN EQU * 12315 5,0315 2 0,0434 0 INDEX INREL ; set DEC compu bit to 1 (in DECBRNCH)12316 5,0316 6 1,2072 0 AD BIT7 ; Bit 5 for R1, bit 4 for R2, bit 3 for R312317 5,0317 6 0,0467 1 AD DECBRNCH 12320 5,0320 5 0,0467 1 TS DECBRNCH PIXCLPAS EQU * 12321 5,0321 1 0,0504 1 CCS CLPASS ; if CLPASS is + or +0, make it +012322 5,0322 3 1,2050 0 CAF ZERO 12323 5,0323 5 0,0504 0 TS CLPASS 12324 5,0324 0 5,6325 0 TC *+1 12325 5,0325 0 1,2723 0 TC ENDOFJOB POSGN EQU * 12326 5,0326 0 5,6367 0 TC SIGNTEST 12327 5,0327 0 5,6332 0 TC P_ON 12330 5,0330 3 1,2051 1 CAF ONE 12331 5,0331 0 5,6315 0 TC BOTHSGN ;-------------------------------------------------------------------------- ; P_ON ; Turn the plus sign on for register selected by DSPCOUNT. ; Return when done. ; ; M_ON ; Turn the minus sign on for register selected by DSPCOUNT. ; Return when done. ; Adapted from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, p.314. ;-------------------------------------------------------------------------- P_ON EQU * 12332 5,0332 3 0,0001 0 XCH Q ; was LXCH Q in block II12333 5,0333 5 0,0547 1 TS LXCH_LPRET ; save return address in faux LP 12334 5,0334 0 5,6241 0 TC GETINREL 12335 5,0335 2 0,0434 0 INDEX INREL 12336 5,0336 3 5,6362 0 CAF SGNTAB-2 12337 5,0337 5 0,0420 1 TS SGNOFF 12340 5,0340 6 1,2051 1 AD ONE 12341 5,0341 5 0,0417 0 TS SGNON SGNCOM EQU * 12342 5,0342 3 1,2050 0 CAF ZERO 12343 5,0343 5 0,0421 0 TS CODE 12344 5,0344 3 0,0420 1 XCH SGNOFF 12345 5,0345 0 5,7253 1 TC _11DSPIN 12346 5,0346 3 1,2066 0 CAF BIT11 12347 5,0347 5 0,0421 0 TS CODE 12350 5,0350 3 0,0417 0 XCH SGNON 12351 5,0351 0 5,7253 1 TC _11DSPIN 12352 5,0352 0 0,0547 1 TC LXCH_LPRET ; return M_ON EQU * 12353 5,0353 3 0,0001 0 XCH Q ; was LXCH Q in block II12354 5,0354 5 0,0547 1 TS LXCH_LPRET ; save return address in faux LP 12355 5,0355 0 5,6241 0 TC GETINREL 12356 5,0356 2 0,0434 0 INDEX INREL 12357 5,0357 3 5,6362 0 CAF SGNTAB-2 12360 5,0360 5 0,0417 0 TS SGNON 12361 5,0361 6 1,2051 1 AD ONE 12362 5,0362 5 0,0420 1 TS SGNOFF 12363 5,0363 0 5,6342 1 TC SGNCOM SGNTAB EQU * 12364 5,0364 00005 1 DS %5 ; -R112365 5,0365 00003 1 DS %3 ; -R212366 5,0366 00000 1 DS %0 ; -R3 ;-------------------------------------------------------------------------- ; SIGNTEST ; Test whether this is a valid point for entering a + or - sign character. ; Returns if valid; calls ENDOFJOB if invalid. ; ; Adapted from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, p.314. ;--------------------------------------------------------------------------
SIGNTEST EQU * 12367 5,0367 3 0,0001 0 XCH Q ; was LXCH Q in block II12370 5,0370 5 0,0547 1 TS LXCH_LPRET ; save return address in faux LP ; allows +,- only when DSPCOUNT=R1D112371 5,0371 3 1,2053 0 CAF THREE ; R2D1, or D3D1. Allows only first of12372 5,0372 7 0,0467 0 MASK DECBRNCH ; consecutive +/- characters.12373 5,0373 1 0,0000 0 CCS A ; if low2 bits of DECBRNCH not=0, sign12374 5,0374 0 1,2723 0 TC ENDOFJOB ; for this word already in, reject. 12375 5,0375 4 2,4635 1 CS R1D1 12376 5,0376 0 5,6404 1 TC SGNTST1 ; DSPCOUNT is R1D1?12377 5,0377 4 2,4636 1 CS R2D1 12400 5,0400 0 5,6404 1 TC SGNTST1 12401 5,0401 4 2,4637 0 CS R3D1 12402 5,0402 0 5,6404 1 TC SGNTST1 12403 5,0403 0 1,2723 0 TC ENDOFJOB ; no match found, sign illegal SGNTST1 EQU * 12404 5,0404 6 0,0466 0 AD DSPCOUNT 12405 5,0405 1 0,0000 0 CCS A ; was BZF *+2 in Block II12406 5,0406 0 0,0001 0 TC Q ; >0, no match, check next register12407 5,0407 0 0,0547 1 TC LXCH_LPRET ; +0, match found, sign is legal12410 5,0410 0 0,0001 0 TC Q ; <0, no match, check next register12411 5,0411 0 0,0547 1 TC LXCH_LPRET ; -0, match found, sign is legal ;-------------------------------------------------------------------------- ; CLEAR -- PROCESS CLEAR KEY ; Clear blanks which R1, R2, R3 is current or last to be displayed (pertinent ; XREG, YREG, ZREG is cleared). Successive clears take care of each RX L/ ; RC until R1 is done, then no further action. ; ; The single component load verbs allow only the single RC that is appropriate ; to be cleared. ; ; CLPASS = 0, PASSO, can be backed up ; CLPASS = +NZ, HIPASS, can be backed up ; CLPASS = -NZ, PASSO, cannot be backed up ; ; Adapted from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, p.316. ;-------------------------------------------------------------------------- CLEAR EQU * 12412 5,0412 1 0,0466 1 CCS DSPCOUNT 12413 5,0413 6 1,2051 1 AD ONE 12414 5,0414 0 5,6416 1 TC *+2 12415 5,0415 6 1,2051 1 AD ONE 12416 5,0416 2 0,0000 0 INDEX A ; do not change DSPCOUNT because may later12417 5,0417 3 5,6245 1 CAF INRELTAB ; fail LEGALTST12420 5,0420 5 0,0434 1 TS INREL ; must set INREL, even for HIPASS12421 5,0421 1 0,0504 1 CCS CLPASS 12422 5,0422 0 5,6431 1 TC CLPASHI ; +12423 5,0423 0 5,6425 1 TC *+2 ; +0, if CCLPASS is +0 or -, it is PASS012424 5,0424 0 5,6425 1 TC *+1 ; -12425 5,0425 3 1,2050 0 CAF ZERO ; was CA INREL in Block II12426 5,0426 6 0,0434 1 AD INREL 12427 5,0427 0 5,6464 1 TC LEGALTST 12430 5,0430 0 5,6454 1 TC CLEAR1 CLPASHI EQU * 12431 5,0431 1 0,0434 0 CCS INREL 12432 5,0432 5 0,0434 1 TS INREL 12433 5,0433 0 5,6464 1 TC LEGALTST 12434 5,0434 3 5,6536 1 CAF DOUBLK+2 ; +3 to - number, backs data requests12435 5,0435 6 0,0502 0 AD REQRET ; was ADS REQRET in Block II12436 5,0436 5 0,0502 0 TS REQRET 12437 5,0437 3 1,2050 0 CAF ZERO ; was CA INREL in Block II12440 5,0440 6 0,0434 1 AD INREL 12441 5,0441 5 0,0422 0 TS MIXTEMP ; temp storage for INREL 12442 5,0442 1 0,0470 0 CCS VERBREG ; was DIM VERBREG in Block II12443 5,0443 0 5,6446 1 TC *+3 12444 5,0444 0 5,6446 1 TC *+2 12445 5,0445 0 5,6446 1 TC *+1 12446 5,0446 5 0,0470 1 TS VERBREG ; decrement VERB and redisplay 12447 5,0447 0 1,3565 1 TC BANKCALL 12450 5,0450 14327 1 DS UPDATVB 12451 5,0451 3 1,2050 0 CAF ZERO ; was CA MIXTEMP in Block II12452 5,0452 6 0,0422 0 AD MIXTEMP
12453 5,0453 5 0,0434 1 TS INREL ; restore INREL CLEAR1 EQU * 12454 5,0454 0 5,6461 1 TC CLR5 12455 5,0455 3 0,0504 0 XCH CLPASS ; was INCR CLPASS in Block II12456 5,0456 6 1,2051 1 AD ONE 12457 5,0457 5 0,0504 0 TS CLPASS ; only if CLPASS is + or +0 12460 5,0460 0 1,2723 0 TC ENDOFJOB ; set for higher pass ;-------------------------------------------------------------------------- ; CLR5 ; blanks 5 char display word by calling _5BLANK, but avoids TC GETINREL. ; Returns when done. ; ; Adapted from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, p.316. ;-------------------------------------------------------------------------- CLR5 EQU * 12461 5,0461 3 0,0001 0 XCH Q ; was LXCH Q in block II12462 5,0462 5 0,0547 1 TS LXCH_LPRET ; save return address in faux LP12463 5,0463 0 5,6476 1 TC _5BLANK+3 ; uses _5BLANK, but avoids its TC GETINREL ;-------------------------------------------------------------------------- ; LEGALTST ; Returns if LEGAL, calls ENDOFJOB if illegal. ; ; Adapted from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, p.316. ;-------------------------------------------------------------------------- LEGALTST EQU * 12464 5,0464 6 1,2047 0 AD NEG2 12465 5,0465 1 0,0000 0 CCS A 12466 5,0466 0 0,0001 0 TC Q ; LEGAL, INREL G/ 212467 5,0467 0 5,6271 0 TC CCSHOLE 12470 5,0470 0 1,2723 0 TC ENDOFJOB ; ILLEGAL, INREL = 0, 112471 5,0471 0 0,0001 0 TC Q ; LEGAL, INREL = 2 ;-------------------------------------------------------------------------- ; _5BLANK ; blanks 5 char display word in R1,R2,or R3. It also zeroes XREG, YREG or ; ZREG. Place any + DSPCOUNT number for pertinent RC into DSPCOUNT. ; DSPCOUNT is left set to left most DSP numb for RC just blanked. ; Returns when done. ; ; Adapted from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, p.316. ;-------------------------------------------------------------------------- 12472 5,0472 5 0,0466 0 TS DSPCOUNT ; needed for BLANKSUB _5BLANK EQU * 12473 5,0473 3 0,0001 0 XCH Q ; was LXCH Q in block II12474 5,0474 5 0,0547 1 TS LXCH_LPRET ; save return address in faux LP 12475 5,0475 0 5,6241 0 TC GETINREL 12476 5,0476 3 1,2050 0 CAF ZERO 12477 5,0477 2 0,0434 0 INDEX INREL 12500 5,0500 5 0,0470 1 TS VERBREG ; zero X, Y, Z reg12501 5,0501 2 0,0434 0 INDEX INREL 12502 5,0502 5 0,0473 1 TS XREGLP-2 12503 5,0503 5 0,0421 0 TS CODE 12504 5,0504 2 0,0434 0 INDEX INREL ; zero pertinent DEC comp bit12505 5,0505 4 1,2072 1 CS BIT7 12506 5,0506 7 0,0467 0 MASK DECBRNCH 12507 5,0507 7 5,6537 1 MASK BRNCHCON ; zero low 3 bits12510 5,0510 5 0,0467 1 TS DECBRNCH 12511 5,0511 2 0,0434 0 INDEX INREL 12512 5,0512 3 5,6527 1 CAF SINBLANK-2 ; blank isolated char separately12513 5,0513 5 0,0440 1 TS COUNT 12514 5,0514 0 5,7161 0 TC DSPIN _5BLANK1 EQU * 12515 5,0515 2 0,0434 0 INDEX INREL 12516 5,0516 3 5,6532 0 CAF DOUBLK-2 12517 5,0517 5 0,0466 0 TS DSPCOUNT 12520 5,0520 0 5,6540 0 TC _2BLANK 12521 5,0521 4 1,2052 0 CS TWO 12522 5,0522 6 0,0466 0 AD DSPCOUNT ; was ADS DSPCOUNT in Block II12523 5,0523 5 0,0466 0 TS DSPCOUNT
12524 5,0524 0 5,6540 0 TC _2BLANK 12525 5,0525 2 0,0434 0 INDEX INREL 12526 5,0526 3 2,4633 0 CAF R1D1-2 12527 5,0527 5 0,0466 0 TS DSPCOUNT ; set DSPCOUNT to leftmost DSP number12530 5,0530 0 0,0547 1 TC LXCH_LPRET ; of REG, just blanked SINBLANK EQU * 12531 5,0531 00016 0 DS %16 ; DEC 1412532 5,0532 00005 1 DS %5 12533 5,0533 00004 0 DS %4 DOUBLK EQU * 12534 5,0534 00015 0 DS %15 ; DEC 1312535 5,0535 00011 1 DS %11 ; DEC 912536 5,0536 00003 1 DS %3 12537 5,0537 77774 0 BRNCHCON DS %77774 ;-------------------------------------------------------------------------- ; _2BLANK ; blanks 2 char, place DSP number of left char of the pair into DSPCOUNT. ; This number is left in DSPCOUNT. Returns when done. ; ; Adapted from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, p.317. ;-------------------------------------------------------------------------- _2BLANK EQU * 12540 5,0540 3 0,0001 0 XCH Q 12541 5,0541 5 0,0602 0 TS SAVEQ 12542 5,0542 3 1,2050 0 CAF ZERO ; was CA DSPCOUNT in Block II12543 5,0543 6 0,0466 0 AD DSPCOUNT 12544 5,0544 5 0,0021 1 TS SR 12545 5,0545 4 5,6563 0 CS BLANKCON 12546 5,0546 2 0,0000 0 INHINT 12547 5,0547 2 0,0021 0 INDEX SR 12550 5,0550 3 0,0512 1 XCH DSPTAB 12551 5,0551 1 0,0000 0 CCS A ; was BZMF *+2 in Block II12552 5,0552 0 5,6556 1 TC *+4 ; >012553 5,0553 0 5,6555 1 TC *+2 ; +0, if old contents -, NOUT OK12554 5,0554 0 5,6555 1 TC *+1 ; <0, if old contents -, NOUT OK12555 5,0555 0 5,6557 0 TC *+2 ; -0, if old contents -, NOUT OK 12556 5,0556 3 0,0505 1 XCH NOUT ; was INCR NOUT in Block II12557 5,0557 6 1,2051 1 AD ONE 12560 5,0560 5 0,0505 1 TS NOUT ; if old contents +, +1 to NOUT12561 5,0561 2 0,0000 1 RELINT 12562 5,0562 0 0,0602 0 TC SAVEQ 12563 5,0563 04000 0 BLANKCON DS %4000 BANK40_2 EQU * ORG BANK41_1 ; COLOSSUS pp. 318-329 INCL bank41_1.asm ;========================================================================== ; DISPLAY ROUTINES (file:bank41_1.asm) ; ; Adapted from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, pp. 318-329. ;========================================================================== ;-------------------------------------------------------------------------- ; ENTER -- PROCESS ENTER KEY ; Enter pass 0 is the execute function. Higher order enters are to load ; data. The sign of REQRET determines the pass, + for pass 0, - for higher ; passes. ; Machine CADR to be specified (MCTBS) nouns desire an ECADR to be loaded ; when used with load verbs, monitor verbs, or display verbs (except ; verb = fixed memory display, which requires a FCADR). ; ; Adapted from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, p.318. ;-------------------------------------------------------------------------- 14000 6,0000 0 6,7505 0 NVSUBR TC NVSUB1 ; standard lead-ins, don't move14001 6,0001 0 6,6723 1 LOADLV1 TC LOADLV
ENTER EQU * 14002 6,0002 3 1,2050 0 CAF ZERO 14003 6,0003 5 0,0504 0 TS CLPASS 14004 6,0004 3 2,4553 0 CAF ENDINST 14005 6,0005 5 0,0433 0 TS ENTRET 14006 6,0006 1 0,0502 1 CCS REQRET 14007 6,0007 0 6,6040 0 TC ENTPAS0 ; if +, pass 014010 6,0010 0 6,6040 0 TC ENTPAS0 ; if +, pass 014011 6,0011 0 6,6012 1 TC *+1 ; if -, not pass 0 ; not first pass thru ENTER, so enter data word ENTPASHI EQU * 14012 6,0012 3 6,6036 1 CAF MMADREF 14013 6,0013 6 0,0502 0 AD REQRET ; if L/2 char in for MM code, alarm 14014 6,0014 1 0,0000 0 CCS A ; and recycle (decide at MMCHANG+1)14015 6,0015 0 6,6021 1 TC *+4 ; >014016 6,0016 0 6,6020 0 TC *+2 ; +014017 6,0017 0 6,6021 1 TC *+2 ; <014020 6,0020 0 6,6032 0 TC ACCEPTWD ; -0, was BZF ACCEPTWD in Block II 14021 6,0021 3 1,2053 0 CAF THREE ; if DEC, alarm if L/5 char in for data,14022 6,0022 7 0,0467 0 MASK DECBRNCH ; but leave REQRET - and flash on, so14023 6,0023 1 0,0000 0 CCS A ; operator can supply missing numerical14024 6,0024 0 6,6026 0 TC *+2 ; characters and continue.14025 6,0025 0 6,6032 0 TC ACCEPTWD ; octal, any number of char OK.14026 6,0026 1 0,0466 1 CCS DSPCOUNT 14027 6,0027 0 6,6341 1 TC GODSPALM ; less than 5 char DEC(DSPCOUNT is +)14030 6,0030 0 6,6341 1 TC GODSPALM ; less than 5 char DEC(DSPCOUNT is +)14031 6,0031 0 6,6032 0 TC *+1 ; 5 char in (DSPCOUNT is -) ACCEPTWD EQU * 14032 6,0032 4 0,0502 1 CS REQRET ; 5 char in (DSPCOUNT is -)14033 6,0033 5 0,0502 0 TS REQRET ; set REQRET +14034 6,0034 0 2,4770 0 TC FLASHOFF 14035 6,0035 0 0,0502 0 TC REQRET ENTEXIT EQU ENTRET 14036 6,0036 15357 1 MMADREF DS MMCHANG+1 ; assumes TC REGMM at MMCHANG 14037 6,0037 00034 0 LOWVERB DS 28 ; lower verb that avoids nount test. ; first pass thru ENTER, so execute VERB/NOUN ENTPAS0 EQU * 14040 6,0040 3 1,2050 0 CAF ZERO ; noun verb sub enters here14041 6,0041 5 0,0467 1 TS DECBRNCH 14042 6,0042 4 2,4675 0 CS VD1 ; block further num char, so that stray14043 6,0043 5 0,0466 0 TS DSPCOUNT ; char do not get into verb or nount lights. ; test VERB TESTVB EQU * 14044 6,0044 4 0,0470 0 CS VERBREG ; if verb is G/E LOWVB, skip noun test14045 6,0045 5 0,0530 1 TS VERBSAVE ; save verb for possible recycle.14046 6,0046 6 6,6037 0 AD LOWVERB ; LOWVERB - VB 14047 6,0047 1 0,0000 0 CCS A ; was BZMF VERBFAN in Block II14050 6,0050 0 6,6054 0 TC *+4 ; >014051 6,0051 0 6,6053 1 TC *+2 ; +0, VERB G/E LOWVERB14052 6,0052 0 6,6053 1 TC *+1 ; <0, VERB G/E LOWVERB14053 6,0053 0 6,6151 1 TC VERBFAN ; -0, VERB G/E LOWVERB ; test NOUN TESTNN EQU * ; set MIXBR and put the noun address into NNADTEM ; MIXBR is an enumerated type: ; 1 = normal nouns ; 2 = mixed nouns 14054 6,0054 3 6,6124 0 CAF LODNNLOC ; was DCA LODNNLOC, DXCH Z in Block II14055 6,0055 0 1,3526 0 TC DXCHJUMP ; bank jump to noun table read rtne 14056 6,0056 2 0,0435 1 INDEX MIXBR ; computed GOTO14057 6,0057 0 6,6057 0 TC *+0 14060 6,0060 0 6,6062 0 TC *+2 ; returns here for normal noun14061 6,0061 0 6,6237 1 TC MIXNOUN ; returns here for mixed noun
; normal noun, so test noun address table entry (NNADTEM) 14062 6,0062 1 0,0443 0 CCS NNADTEM ; normal14063 6,0063 0 6,6147 0 TC VERBFAN-2 ; normal if +14064 6,0064 0 6,6341 1 TC GODSPALM ; not in use if +014065 6,0065 0 6,6073 0 TC REQADD ; specify machine CADR if - ; NNADTEM was -0, so just increment noun address (in NOUNCADR) and ; set the result in NOUNADD 14066 6,0066 3 0,0506 1 XCH NOUNCADR ; augment machine CADR if -014067 6,0067 6 1,2051 1 AD ONE 14070 6,0070 5 0,0506 1 TS NOUNCADR ; was INCR NOUNCADR in Block II 14071 6,0071 0 2,4625 1 TC SETNADD ; set NOUNADD14072 6,0072 0 6,6132 1 TC INTMCTBS+3 ; NNADTEM was -, so noun address needs to be specified (loaded). REQADD EQU * 14073 6,0073 3 1,2062 1 CAF BIT15 ; set CLPASS for pass0 only14074 6,0074 5 0,0504 0 TS CLPASS 14075 6,0075 4 2,4553 1 CS ENDINST ; test if reach here from internal or14076 6,0076 6 0,0433 0 AD ENTEXIT ; from external 14077 6,0077 1 0,0000 0 CCS A ; was BZF *+2 in Block II14100 6,0100 0 6,6104 1 TC *+4 ; >014101 6,0101 0 6,6103 0 TC *+2 ; +014102 6,0102 0 6,6104 1 TC *+2 ; <014103 6,0103 0 6,6105 0 TC *+2 ; -0, external mach CADR to be specified 14104 6,0104 0 6,6127 0 TC INTMCTBS 14105 6,0105 0 6,6274 0 TC REQDATZ ; external mach CADR to be specified 14106 6,0106 1 0,0467 0 CCS DECBRNCH ; alarm and recycle if decimal used14107 6,0107 0 2,4474 1 TC ALMCYCLE ; for MCTBS14110 6,0110 4 2,4675 0 CS VD1 ; octal used OK14111 6,0111 5 0,0466 0 TS DSPCOUNT ; block num char in 14112 6,0112 1 0,0531 1 CCS CADRSTOR 14113 6,0113 0 6,6116 1 TC *+3 ; external MCTBS display will leave flash14114 6,0114 0 6,6117 0 TC USEADD ; on if ENDIDLE not = +014115 6,0115 0 6,6116 1 TC *+1 14116 6,0116 0 2,4760 1 TC FLASHON ; noun address has now been loaded into the Z register. Copy it into ; NOUNCADR and NOUNADD and then jump to the VERBFAN. USEADD EQU * 14117 6,0117 3 0,0474 0 XCH ZREG 14120 6,0120 0 2,4616 1 TC SETNCADR ; ECADR into NOUNCADR, set EB, NOUNADD 14121 6,0121 3 6,6124 0 CAF LODNNLOC ; was DCA LODNNLOC, DXCH Z in Block II14122 6,0122 0 1,3526 0 TC DXCHJUMP ; bank jump to noun table read rtne 14123 6,0123 0 6,6151 1 TC VERBFAN 14124 6,0124 16114 1 LODNNLOC DS LODNNTAB ; *** uses 2 words in Block II ***14125 6,0125 00000 1 DS 0 14126 6,0126 77772 0 NEG5 DS -5 ; If external (keyboard input), noun address is in register A. ; If internal (S/W input), noun address is in MPAC+2. ; Store the noun address into NOUNCADR and NOUNADD. If the verb ; is O5. go directly to the VERBFAN; for all other verbs, display ; the noun address in R3 and then go to the VERBFAN. INTMCTBS EQU * ; entry point for internal: 14127 6,0127 3 1,2050 0 CAF ZERO ; was CA MPAC+2 in Block II14130 6,0130 6 0,0132 1 AD MPAC+2 ; internal mach CADR to be specified ; entry point for external (keyboard input): 14131 6,0131 0 2,4616 1 TC SETNCADR ; store addr (A) into NOUNCADR and NOUNADD 14132 6,0132 4 1,2055 1 CS FIVE ; NVSUB call left CADR in MAPC+2 for mach14133 6,0133 6 0,0470 1 AD VERBREG ; CADR to be specified.
14134 6,0134 1 0,0000 0 CCS A ; was BZF VERBFAN in Block II14135 6,0135 0 6,6141 0 TC *+4 ; >014136 6,0136 0 6,6140 1 TC *+2 ; +014137 6,0137 0 6,6141 0 TC *+2 ; <014140 6,0140 0 6,6151 1 TC VERBFAN ; -0, don't display CADR if verb = 05 14141 6,0141 3 2,4637 1 CAF R3D1 ; verb not = 05, display CADR14142 6,0142 5 0,0466 0 TS DSPCOUNT 14143 6,0143 3 1,2050 0 CAF ZERO ; was CA NOUNCADR in Block II14144 6,0144 6 0,0506 1 AD NOUNCADR 14145 6,0145 0 6,7310 1 TC DSPOCTWD 14146 6,0146 0 6,6151 1 TC VERBFAN ; NNADTEM was + (normal), so just use the noun address straight from the ; noun table (currently in A). The CCS instruction used to test the ; address also decremented it, so we add one to restore the correct address. 14147 6,0147 6 1,2051 1 AD ONE 14150 6,0150 0 2,4616 1 TC SETNCADR ; store addr (A) into NOUNCADR and NOUNADD ; noun address is currently in NOUNCADR and NOUNADD. VERBFAN EQU * 14151 6,0151 4 6,6163 1 CS LST2CON 14152 6,0152 6 0,0470 1 AD VERBREG ; verb-LST2CON 14153 6,0153 1 0,0000 0 CCS A 14154 6,0154 6 1,2051 1 AD ONE ; ver G/ LST2CON14155 6,0155 0 6,6157 1 TC *+2 14156 6,0156 0 6,6164 1 TC VBFANDIR ; verb L/ LST2CON14157 6,0157 5 0,0130 0 TS MPAC 14160 6,0160 0 2,5003 1 TC RELDSP ; release display syst14161 6,0161 0 1,3653 1 TC POSTJUMP ; go to GOEXTVB with VB-40 in MPAC14162 6,0162 20000 0 DS GOEXTVB 14163 6,0163 00050 1 LST2CON DS 40 ; first list2 verb (extended verb) VBFANDIR EQU * 14164 6,0164 2 0,0470 0 INDEX VERBREG 14165 6,0165 3 6,6167 1 CAF VERBTAB 14166 6,0166 0 1,3712 0 TC BANKJUMP VERBTAB EQU * 14167 6,0167 14341 1 CADR GODSPALM ; VB00 Illegal14170 6,0170 14355 1 CADR DSPA ; VB01 display oct comp 1 (R1)14171 6,0171 14363 1 CADR DSPB ; VB02 display oct comp 2 (R1)14172 6,0172 14370 0 CADR DSPC ; VB03 display oct comp 3 (R1)14173 6,0173 14350 1 CADR DSPAB ; VB04 display oct comp 1,2 (R1,R2)14174 6,0174 14343 0 CADR DSPABC ; VB05 display oct comp 1,2,3 (R1,R2,R3)14175 6,0175 14510 0 CADR DECDSP ; VB06 decimal display14176 6,0176 12704 1 CADR DSPDPDEC ; VB07 DP decimal display (R1,R2)14177 6,0177 14341 1 CADR GODSPALM ; VB08 spare14200 6,0200 14341 1 CADR GODSPALM ; VB09 spare14201 6,0201 14341 1 CADR GODSPALM ; VB10 spare14202 6,0202 15146 0 CADR MONITOR ; VB11 monitor oct comp 1 (R1)14203 6,0203 15146 0 CADR MONITOR ; VB12 monitor oct comp 2 (R2)14204 6,0204 15146 0 CADR MONITOR ; VB13 monitor oct comp 3 (R3)14205 6,0205 15146 0 CADR MONITOR ; VB14 monitor oct comp 1,2 (R1,R2)14206 6,0206 15146 0 CADR MONITOR ; VB15 monitor oct comp 1,2,3 (R1,R2,R3)14207 6,0207 15146 0 CADR MONITOR ; VB16 monitor decimal14210 6,0210 15146 0 CADR MONITOR ; VB17 monitor DP decimal (R1,R2)14211 6,0211 14341 1 CADR GODSPALM ; VB18 spare14212 6,0212 14341 1 CADR GODSPALM ; VB19 spare14213 6,0213 14341 1 CADR GODSPALM ; VB20 spare14214 6,0214 14663 1 CADR ALOAD ; VB21 load comp 1 (R1)14215 6,0215 14673 0 CADR BLOAD ; VB22 load comp 2 (R2)14216 6,0216 14707 1 CADR CLOAD ; VB23 load comp 3 (R3)14217 6,0217 14635 1 CADR ABLOAD ; VB24 load comp 1,2 (R1,R2)14220 6,0220 14600 1 CADR ABCLOAD ; VB25 load comp 1,2,3 (R1,R2,R3)14221 6,0221 14341 1 CADR GODSPALM ; VB26 spare14222 6,0222 15301 1 CADR DSPFMEM ; VB27 fixed memory display14223 6,0223 14341 1 CADR GODSPALM ; VB28 spare14224 6,0224 14341 1 CADR GODSPALM ; VB29 spare14225 6,0225 15420 0 CADR VBRQEXEC ; VB30 request executive14226 6,0226 15446 0 CADR VBRQWAIT ; VB31 request waitlist14227 6,0227 13325 1 CADR VBRESEQ ; VB32 resequence14230 6,0230 13315 1 CADR VBPROC ; VB33 proceed (without data)14231 6,0231 13323 1 CADR VBTERM ; VB34 terminate14232 6,0232 15572 0 CADR VBTSTLTS ; VB35 test lights14233 6,0233 02126 0 CADR SLAP1 ; VB36 fresh start14234 6,0234 15356 0 CADR MMCHANG ; VB37 change major mode14235 6,0235 14341 1 CADR GODSPALM ; VB38 spare14236 6,0236 14341 1 CADR GODSPALM ; VB39 spare
;-------------------------------------------------------------------------- ; MIXNOUN ; NNADTAB contains a relative address, IDADDREL(in low 10 bits), referring ; to where 3 consecutive addresses are stored (in IDADDTAB). ; MIXNOUN gets data and stores in MIXTEMP, +1, +2. It sets NOUNADD for ; MIXTEMP. ; ; Adapted from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, p.322. ;-------------------------------------------------------------------------- MIXNOUN EQU * 14237 6,0237 0 6,6341 1 TC GODSPALM ; not currently implemented ; ************ BUNCH OF MISSING STUFF ************ ;-------------------------------------------------------------------------- ; DPTEST ; enter with SF routine code number (SF ROUT) in A. Returns to L+1 if no DP. ; Returns to L+2 if DP. ; ; Adapted from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, p.322. Also, see p. 263. ;-------------------------------------------------------------------------- DPTEST EQU * 14240 6,0240 5 0,0552 0 TS DPTEST_A 14241 6,0241 3 0,0001 0 XCH Q 14242 6,0242 5 0,0553 1 TS DPTEST_Q 14243 6,0243 2 0,0552 1 INDEX DPTEST_A 14244 6,0244 0 6,6245 1 TC *+1 14245 6,0245 0 0,0553 1 TC DPTEST_Q ; octal only, no DP14246 6,0246 0 0,0553 1 TC DPTEST_Q ; straight fractional, no DP14247 6,0247 0 0,0553 1 TC DPTEST_Q ; CDU degrees (XXX.XX), no DP14250 6,0250 0 0,0553 1 TC DPTEST_Q ; arithmetic SF, no DP14251 6,0251 0 6,6262 1 TC DPTEST1 ; DP1OUT14252 6,0252 0 6,6262 1 TC DPTEST1 ; DP2OUT14253 6,0253 0 0,0553 1 TC DPTEST_Q ; Y OPTICS DEGREES, no DP14254 6,0254 0 6,6262 1 TC DPTEST1 ; DP3OUT14255 6,0255 0 0,0553 1 TC DPTEST_Q ; HMS, no DP14256 6,0256 0 0,0553 1 TC DPTEST_Q ; MS, no DP14257 6,0257 0 6,6262 1 TC DPTEST1 ; DP4OUT14260 6,0260 0 0,0553 1 TC DPTEST_Q ; arith1, no DP14261 6,0261 0 0,0553 1 TC DPTEST_Q ; 2INTOUT, no DP to get hi part in MPAC DPTEST1 EQU * 14262 6,0262 2 0,0553 0 INDEX DPTEST_Q 14263 6,0263 0 0,0001 0 TC 1 ; return to L+2 ;-------------------------------------------------------------------------- ; REQDATX, REQDATY, REQDATZ ; ; Adapted from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, p.323. ;-------------------------------------------------------------------------- REQDATX EQU * 14264 6,0264 3 0,0001 0 XCH Q 14265 6,0265 5 0,0554 0 TS REQ_Q 14266 6,0266 3 2,4635 0 CAF R1D1 14267 6,0267 0 6,6277 0 TC REQCOM REQDATY EQU * 14270 6,0270 3 0,0001 0 XCH Q 14271 6,0271 5 0,0554 0 TS REQ_Q 14272 6,0272 3 2,4636 0 CAF R2D1 14273 6,0273 0 6,6277 0 TC REQCOM REQDATZ EQU * 14274 6,0274 3 0,0001 0 XCH Q 14275 6,0275 5 0,0554 0 TS REQ_Q 14276 6,0276 3 2,4637 1 CAF R3D1 14277 6,0277 5 0,0466 0 REQCOM TS DSPCOUNT 14300 6,0300 4 0,0554 1 CS REQ_Q 14301 6,0301 5 0,0502 0 TS REQRET 14302 6,0302 0 1,3565 1 TC BANKCALL 14303 6,0303 12473 1 DS _5BLANK 14304 6,0304 0 2,4760 1 TC FLASHON
ENDRQDAT EQU * 14305 6,0305 0 0,0433 0 TC ENTEXIT ;-------------------------------------------------------------------------- ; UPDATNN, UPDATVB ; ; Adapted from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, p.323. ;-------------------------------------------------------------------------- 14306 6,0306 5 0,0471 0 TS NOUNREG UPDATNN EQU * 14307 6,0307 3 0,0001 0 XCH Q 14310 6,0310 5 0,0414 0 TS UPDATRET 14311 6,0311 3 6,6124 0 CAF LODNNLOC ; was DCA LODNNLOC, DXCH Z in Block II14312 6,0312 0 1,3526 0 TC DXCHJUMP ; bank jump to noun table read rtne 14313 6,0313 1 0,0443 0 CCS NNADTEM 14314 6,0314 6 1,2051 1 AD ONE ; >0, normal14315 6,0315 0 6,6320 0 TC PUTADD ; +0, normal14316 6,0316 0 6,6321 1 TC PUTADD+1 ; <0, MCTBS don't change NOUNADD14317 6,0317 0 6,6321 1 TC PUTADD+1 ; -0, MCTBI don't change NOUNADD PUTADD EQU * 14320 6,0320 0 2,4616 1 TC SETNCADR ; ECADR into NOUNCADR, sets NOUNADD 14321 6,0321 3 2,4676 1 CAF ND1 14322 6,0322 5 0,0466 0 TS DSPCOUNT 14323 6,0323 3 1,2050 0 CAF ZERO ; was CA NOUNREG in Block II14324 6,0324 6 0,0471 0 AD NOUNREG 14325 6,0325 0 6,6335 1 TC UPDAT1 14326 6,0326 5 0,0470 1 TS VERBREG UPDATVB EQU * 14327 6,0327 3 0,0001 0 XCH Q 14330 6,0330 5 0,0414 0 TS UPDATRET 14331 6,0331 3 2,4675 1 CAF VD1 14332 6,0332 5 0,0466 0 TS DSPCOUNT 14333 6,0333 3 1,2050 0 CAF ZERO ; was CA VERBREG in Block II14334 6,0334 6 0,0470 1 AD VERBREG UPDAT1 EQU * 14335 6,0335 0 1,3653 1 TC POSTJUMP ; can't use SWCALL to go to DSPDECVN, since14336 6,0336 13156 1 DS GOVNUPDT ; UPDATVB can itself be called by SWCALL14337 6,0337 0 0,0414 0 TC UPDATRET ;-------------------------------------------------------------------------- ; GOALMCYC, GODSPALM ; ; Adapted from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, p.324. ;-------------------------------------------------------------------------- 14340 6,0340 0 2,4474 1 GOALMCYC TC ALMCYCLE ; needed because bankjump cant handle F/F
14341 6,0341 0 1,3653 1 GODSPALM TC POSTJUMP 14342 6,0342 13267 0 DS DSPALARM ;-------------------------------------------------------------------------- ; DISPLAY VERBS ; ; Adapted from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, p.326. ;-------------------------------------------------------------------------- DSPABC EQU * 14343 6,0343 4 1,2052 0 CS TWO 14344 6,0344 0 6,6414 0 TC COMPTEST 14345 6,0345 2 0,0442 1 INDEX NOUNADD 14346 6,0346 4 0,0002 1 CS 2 14347 6,0347 3 0,0427 0 XCH BUF+2 DSPAB EQU * 14350 6,0350 4 1,2051 0 CS ONE 14351 6,0351 0 6,6414 0 TC COMPTEST 14352 6,0352 2 0,0442 1 INDEX NOUNADD 14353 6,0353 4 0,0001 1 CS 1
14354 6,0354 3 0,0426 1 XCH BUF+1 DSPA EQU * 14355 6,0355 0 6,6435 0 TC DECTEST 14356 6,0356 0 6,6462 1 TC TSTFORDP 14357 6,0357 2 0,0442 1 INDEX NOUNADD 14360 6,0360 4 0,0000 0 CS 0 DSPCOM1 EQU * 14361 6,0361 3 0,0425 1 XCH BUF 14362 6,0362 0 6,6375 0 TC DSPCOM2 DSPB EQU * 14363 6,0363 4 1,2051 0 CS ONE 14364 6,0364 0 6,6430 0 TC DCOMPTST 14365 6,0365 2 0,0442 1 INDEX NOUNADD 14366 6,0366 4 0,0001 1 CS 1 14367 6,0367 0 6,6361 0 TC DSPCOM1 DSPC EQU * 14370 6,0370 4 1,2052 0 CS TWO 14371 6,0371 0 6,6430 0 TC DCOMPTST 14372 6,0372 2 0,0442 1 INDEX NOUNADD 14373 6,0373 4 0,0002 1 CS 2 14374 6,0374 0 6,6361 0 TC DSPCOM1 DSPCOM2 EQU * 14375 6,0375 4 1,2052 0 CS TWO ; A B C AB ABC14376 6,0376 6 0,0470 1 AD VERBREG ; -1 -0 +1 +2 +3 IN A14377 6,0377 1 0,0000 0 CCS A ; +0 +0 +0 +1 +2 IN A AFTER CCS14400 6,0400 0 6,6403 0 TC DSPCOM3 14401 6,0401 0 0,0433 0 TC ENTEXIT 14402 6,0402 0 6,6403 0 TC *+1 DSPCOM3 EQU * 14403 6,0403 5 0,0417 0 TS DISTEM ; +0, +1, +2 into DISTEM14404 6,0404 2 0,0000 0 INDEX A 14405 6,0405 3 2,4635 0 CAF R1D1 14406 6,0406 5 0,0466 0 TS DSPCOUNT 14407 6,0407 2 0,0417 1 INDEX DISTEM 14410 6,0410 4 0,0425 0 CS BUF 14411 6,0411 0 6,7310 1 TC DSPOCTWD 14412 6,0412 3 0,0417 0 XCH DISTEM 14413 6,0413 0 6,6377 1 TC DSPCOM2+2 ;-------------------------------------------------------------------------- ; COMPTEST ; alarms if component number of verb (load or oct display) is ; greater than the highest component number of noun. ; ; DCOMPTST ; alarms if decimal only bit (bit 4 of comp code number) = 1. ; If not, it performs regular COMPTEST. ; ; Adapted from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, p.326. ;-------------------------------------------------------------------------- COMPTEST EQU * 14414 6,0414 5 0,0420 1 TS SFTEMP1 ; - verb comp14415 6,0415 3 0,0001 0 XCH Q ; was LXCH Q in block II14416 6,0416 5 0,0547 1 TS LXCH_LPRET ; save return address in faux LP COMPTST1 EQU * 14417 6,0417 0 6,6501 0 TC GETCOMP 14420 6,0420 0 2,4647 0 TC LEFT5 14421 6,0421 7 1,2053 1 MASK THREE ; noun comp14422 6,0422 6 0,0420 1 AD SFTEMP1 ; noun comp - verb comp14423 6,0423 1 0,0000 0 CCS A 14424 6,0424 0 0,0547 1 TC LXCH_LPRET ; noun comp G/ verb comp; return14425 6,0425 0 5,6271 0 TC CCSHOLE 14426 6,0426 0 6,6341 1 TC GODSPALM ; noun comp L/ verb comp NDOMPTST EQU * 14427 6,0427 0 0,0547 1 TC LXCH_LPRET ; noun comp = verb comp; return DCOMPTST EQU * 14430 6,0430 5 0,0420 1 TS SFTEMP1 ; - verb comp 14431 6,0431 3 0,0001 0 XCH Q ; was LXCH Q in block II14432 6,0432 5 0,0547 1 TS LXCH_LPRET ; save return address in faux LP 14433 6,0433 0 6,6435 0 TC DECTEST 14434 6,0434 0 6,6417 0 TC COMPTST1 ;--------------------------------------------------------------------------
; DECTEST ; alarms if dec only bit = 1 (bit 4 of comp code number1). Returns if not. ; ; Adapted from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, p.327. ;-------------------------------------------------------------------------- DECTEST EQU * 14435 6,0435 3 0,0001 0 XCH Q ; was QXCH MPAC+2 in block II14436 6,0436 5 0,0132 1 TS MPAC+2 14437 6,0437 0 6,6501 0 TC GETCOMP 14440 6,0440 7 1,2063 1 MASK BIT14 14441 6,0441 1 0,0000 0 CCS A 14442 6,0442 0 6,6341 1 TC GODSPALM 14443 6,0443 0 0,0132 1 TC MPAC+2 ;-------------------------------------------------------------------------- ; DCTSTCYC ; alarms and recycles if dec only bit = 1 (bit 4 of comp code number). ; Returns if not. Used by load verbs. ; ; Adapted from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, p.327. ;-------------------------------------------------------------------------- DCTSTCYC EQU * 14444 6,0444 3 0,0001 0 XCH Q ; was LXCH Q in block II14445 6,0445 5 0,0547 1 TS LXCH_LPRET ; save return address in faux LP 14446 6,0446 0 6,6501 0 TC GETCOMP 14447 6,0447 7 1,2063 1 MASK BIT14 14450 6,0450 1 0,0000 0 CCS A 14451 6,0451 0 2,4474 1 TC ALMCYCLE 14452 6,0452 0 0,0547 1 TC LXCH_LPRET ;-------------------------------------------------------------------------- ; NOUNTEST ; alarms if no-load bit (bit 5 of comp code number) = 1 ; if not, it returns. ; ; Adapted from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, p.327. ;-------------------------------------------------------------------------- NOUNTEST EQU * 14453 6,0453 3 0,0001 0 XCH Q ; was LXCH Q in block II14454 6,0454 5 0,0547 1 TS LXCH_LPRET ; save return address in faux LP 14455 6,0455 0 6,6501 0 TC GETCOMP 14456 6,0456 1 0,0000 0 CCS A 14457 6,0457 0 0,0547 1 TC LXCH_LPRET 14460 6,0460 0 0,0547 1 TC LXCH_LPRET 14461 6,0461 0 6,6341 1 TC GODSPALM ;-------------------------------------------------------------------------- ; TSTFORDP ; test for DP. If so, get minor part only. ; The Block II version had some code that checked for a -1 in NNADTEM ; which meant use an I/O channel instead of memory. This was removed ; for the Block I. ; ; Adapted from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, p.327. ;-------------------------------------------------------------------------- TSTFORDP EQU * 14462 6,0462 3 0,0001 0 XCH Q ; was LXCH Q in block II14463 6,0463 5 0,0547 1 TS LXCH_LPRET ; save return address in faux LP 14464 6,0464 2 0,0435 1 INDEX MIXBR 14465 6,0465 0 6,6465 0 TC * 14466 6,0466 0 6,6470 1 TC *+2 ; normal14467 6,0467 0 0,0547 1 TC LXCH_LPRET ; mixed case already handled in MIXNOUN 14470 6,0470 0 6,6762 1 TC SFRUTNOR 14471 6,0471 0 6,6240 1 TC DPTEST 14472 6,0472 0 0,0547 1 TC LXCH_LPRET ; no DP 14473 6,0473 3 0,0442 0 XCH NOUNADD ; was INCR NOUNADD in Block II14474 6,0474 6 1,2051 1 AD ONE ; DP E+1 into NOUNADD for minor part14475 6,0475 5 0,0442 0 TS NOUNADD
14476 6,0476 0 0,0547 1 TC LXCH_LPRET ;-------------------------------------------------------------------------- ; GETCOMP ; ; noun address is in NNADTEM ; noun type is in NNTYPTEM ; ; MIXBR is an enumerated type: ; 1 = normal nouns ; 2 = mixed nouns ; ; Adapted from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, p.328. ;-------------------------------------------------------------------------- 14477 6,0477 00444 0 COMPICK DS NNTYPTEM 14500 6,0500 00443 1 DS NNADTEM GETCOMP EQU * 14501 6,0501 2 0,0435 1 INDEX MIXBR ; normal mixed14502 6,0502 3 6,6476 1 CAF COMPICK-1 ; ADRES NNTYPTEM ADRES NNADTEM 14503 6,0503 2 0,0000 0 INDEX A 14504 6,0504 4 0,0000 0 CS 0 ; C(NNTYPTEM) C(NNADTEM)14505 6,0505 4 0,0000 0 COM ; was CA 0 in Block II14506 6,0506 7 2,4666 1 MASK HI5 14507 6,0507 0 0,0001 0 TC Q ;-------------------------------------------------------------------------- ; DECDSP -- DECIMAL DISPLAY ; ; Adapted from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, p.328. ;-------------------------------------------------------------------------- DECDSP EQU * 14510 6,0510 0 6,6501 0 TC GETCOMP 14511 6,0511 0 2,4647 0 TC LEFT5 14512 6,0512 7 1,2053 1 MASK THREE 14513 6,0513 5 0,0414 0 TS DECOUNT ; comp number into DECOUNT DSPDCGET EQU * 14514 6,0514 5 0,0417 0 TS DECTEM ; picks up data14515 6,0515 6 0,0442 0 AD NOUNADD ; DECTEM 1COMP +0, 2COMP +1, 3COMP +214516 6,0516 2 0,0000 0 INDEX A 14517 6,0517 4 0,0000 0 CS 0 14520 6,0520 2 0,0417 1 INDEX DECTEM 14521 6,0521 3 0,0472 0 XCH XREG ; cant use BUF since DMP uses it14522 6,0522 1 0,0417 1 CCS DECTEM 14523 6,0523 0 6,6514 1 TC DSPDCGET ; more to get DSPDCPUT EQU * 14524 6,0524 3 1,2050 0 CAF ZERO ; displays data14525 6,0525 5 0,0131 1 TS MPAC+1 ; DECOUNT 1COMP +0, 2COMP +1, 3COMP +214526 6,0526 5 0,0132 1 TS MPAC+2 14527 6,0527 2 0,0414 1 INDEX DECOUNT 14530 6,0530 3 2,4635 0 CAF R1D1 14531 6,0531 5 0,0466 0 TS DSPCOUNT 14532 6,0532 2 0,0414 1 INDEX DECOUNT 14533 6,0533 4 0,0472 1 CS XREG 14534 6,0534 5 0,0130 0 TS MPAC 14535 6,0535 0 6,7003 0 TC SFCONUM ; 2X (SF CON NUMB) in A14536 6,0536 5 0,0420 1 TS SFTEMP1 14537 6,0537 3 6,6550 1 CAF GTSFOUTL ; was DCA GTSFOUTL, DXCH Z in Block II14540 6,0540 0 1,3526 0 TC DXCHJUMP ; bank jump to SF constant table read rtne 14541 6,0541 2 0,0435 1 INDEX MIXBR 14542 6,0542 0 6,6542 1 TC *+0 14543 6,0543 0 6,6546 0 TC DSPSFNOR 14544 6,0544 0 6,6770 1 TC SFRUTMIX 14545 6,0545 0 6,6560 1 TC DECDSP3 DSPSFNOR EQU * 14546 6,0546 0 6,6762 1 TC SFRUTNOR 14547 6,0547 0 6,6560 1 TC DECDSP3 14550 6,0550 16162 0 GTSFOUTL DS GTSFOUT DSPDCEND EQU * 14551 6,0551 0 1,3565 1 TC BANKCALL ; all SFOUT routines end here14552 6,0552 13064 1 DS DSPDECWD 14553 6,0553 1 0,0414 1 CCS DECOUNT 14554 6,0554 0 6,6556 1 TC *+2 14555 6,0555 0 0,0433 0 TC ENTEXIT 14556 6,0556 5 0,0414 0 TS DECOUNT
14557 6,0557 0 6,6524 1 TC DSPDCPUT ; more to display DECDSP3 EQU * 14560 6,0560 2 0,0000 0 INDEX A 14561 6,0561 3 6,6563 1 CAF SFOUTABR 14562 6,0562 0 1,3712 0 TC BANKJUMP SFOUTABR EQU * 14563 6,0563 13265 1 CADR PREDSPAL ; 0, alarm if dec display with octal only noun14564 6,0564 14551 0 CADR DSPDCEND ; 1 14565 6,0565 12564 0 CADR DEGOUTSF ; 214566 6,0566 12644 1 CADR ARTOUTSF ; 3 14567 6,0567 00000 1 CADR 0 ; 4 **********14570 6,0570 00000 1 CADR 0 ; 5 **********14571 6,0571 00000 1 CADR 0 ; 6 **********14572 6,0572 00000 1 CADR 0 ; 7 **********14573 6,0573 16000 0 CADR HMSOUT ; 814574 6,0574 00000 1 CADR 0 ; 9 **********14575 6,0575 00000 1 CADR 0 ; 10 *********14576 6,0576 00000 1 CADR 0 ; 11 *********14577 6,0577 00000 1 CADR 0 ; 12 ********* BANK41_2 EQU * ORG BANK40_2 ; COLOSSUS pp. 330-332 INCL bank40_2.asm ;========================================================================== ; SCALE FACTOR ROUTINES (file:bank40_2.asm) ; ; Adapted from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, pp. 330-332. ;========================================================================== DEGOUTSF EQU * 12564 5,0564 3 1,2050 0 CAF ZERO 12565 5,0565 5 0,0132 1 TS MPAC+2 ; set index for full scale12566 5,0566 0 5,6603 1 TC FIXRANGE 12567 5,0567 0 5,6571 1 TC *+2 ; no augment needed (SFTEMP1 and 2 are 0)12570 5,0570 0 5,6572 1 TC SETAUG ; set augmenter according to C(MPAC+2)12571 5,0571 0 5,6616 0 TC DEGCOM SETAUG EQU * 12572 5,0572 3 1,2050 0 CAF ZERO ; loads SFTEMP1 and SFTEMP2 with the12573 5,0573 2 0,0132 0 INDEX MPAC+2 ; DP augmenter constant12574 5,0574 6 5,6640 0 AD DEGTAB ; was DCA DEGTAB, DXCH SFTEMP1 in Block II12575 5,0575 3 0,0420 1 XCH SFTEMP1 12576 5,0576 3 1,2050 0 CAF ZERO 12577 5,0577 2 0,0132 0 INDEX MPAC+2 12600 5,0600 6 5,6641 1 AD DEGTAB+1 12601 5,0601 3 0,0421 0 XCH SFTEMP1+1 12602 5,0602 0 0,0001 0 TC Q FIXRANGE EQU * 12603 5,0603 3 0,0001 0 XCH Q 12604 5,0604 5 0,0563 1 TS FR_RETQ 12605 5,0605 1 0,0130 1 CCS MPAC ; if MPAC is +, return to L+112606 5,0606 0 0,0563 1 TC FR_RETQ ; if MPAC is -, return to L+2 after12607 5,0607 0 0,0563 1 TC FR_RETQ ; masking out the sign bit12610 5,0610 0 5,6611 1 TC *+1 ; was TCF *+1 in Block II12611 5,0611 4 1,2062 0 CS BIT15 12612 5,0612 7 0,0130 1 MASK MPAC 12613 5,0613 5 0,0130 0 TS MPAC 12614 5,0614 2 0,0563 0 INDEX FR_RETQ 12615 5,0615 0 0,0001 0 TC 1 DEGCOM EQU * 12616 5,0616 3 1,2050 0 CAF ZERO ; was INDEX MPAC+2, DCA DEGTAB, DXCH MPAC inBlock II12617 5,0617 2 0,0132 0 INDEX MPAC+2 ; loads multiplier, does SHORTMP, and12620 5,0620 6 5,6641 1 AD DEGTAB+1 ; adds augmenter12621 5,0621 3 0,0131 1 XCH MPAC+1 ; adjusted angle in A 12622 5,0622 3 1,2050 0 CAF ZERO 12623 5,0623 2 0,0132 0 INDEX MPAC+2 12624 5,0624 6 5,6640 0 AD DEGTAB 12625 5,0625 3 0,0130 0 XCH MPAC 12626 5,0626 0 2,4353 0 TC SHORTMP 12627 5,0627 3 0,0421 0 XCH SFTEMP1+1 ; was DXCH SFTEMP1, DAS MPAC in Block II12630 5,0630 6 0,0131 1 AD MPAC+1
12631 5,0631 5 0,0131 1 TS MPAC+1 ; skip on overflow12632 5,0632 3 1,2050 0 CAF ZERO ; otherwise, make interword carry=0 12633 5,0633 6 0,0420 1 AD SFTEMP1 12634 5,0634 6 0,0130 0 AD MPAC 12635 5,0635 5 0,0130 0 TS MPAC ; skip on overflow12636 5,0636 3 1,2050 0 CAF ZERO ; otherwise, make interword carry=0 12637 5,0637 0 5,6651 0 TC SCOUTEND DEGTAB EQU * 12640 5,0640 05605 1 DS %05605 ; Hi part of .1812641 5,0641 03656 1 DS %03656 ; Lo part of .1812642 5,0642 16314 0 DS %16314 ; Hi part of .4512643 5,0643 31463 1 DS %31463 ; Lo part of .45 ARTOUTSF EQU * 12644 5,0644 3 0,0421 0 XCH SFTEMP1+1 ; was DXCH SFTEMP1, DXCH MPAC in Block II12645 5,0645 3 0,0131 1 XCH MPAC+1 ; assumes point at left of DP SFCON12646 5,0646 3 0,0420 1 XCH SFTEMP1 12647 5,0647 3 0,0130 0 XCH MPAC 12650 5,0650 0 2,4740 0 TC PRSHRTMP ; if C(A) = -0, SHORTMP fails to give -012651 5,0651 0 1,3653 1 SCOUTEND TC POSTJUMP 12652 5,0652 14551 0 CADR DSPDCEND ;-------------------------------------------------------------------------- ; READLO ; Picks up fresh data for both HI and LO and leaves it in MPAC, MPAC+1. ; This is needed for time display. It zeroes MPAC+2, but does not force ; TPAGREE. ; ; Adapted from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, p.332. ;-------------------------------------------------------------------------- READLO EQU * 12653 5,0653 3 0,0001 0 XCH Q 12654 5,0654 5 0,0441 0 TS TEM4 ; save return address 12655 5,0655 2 0,0435 1 INDEX MIXBR 12656 5,0656 0 5,6656 1 TC * 12657 5,0657 0 5,6701 1 TC RDLONOR ; MIXBR=1, so normal noun 12660 5,0660 3 1,2050 0 CAF ZERO ; MIXBR=2, so mixed noun12661 5,0661 2 0,0414 1 INDEX DECOUNT ; was INDEX DECOUNT, CA IDAD1TEM in Block II12662 5,0662 6 0,0445 1 AD IDAD1TEM ; get IDADDTAB entry for comp K of noun12663 5,0663 7 2,4672 1 MASK LOW11 ; E bank12664 5,0664 0 2,4633 0 TC SETEBANK ; set EB, leave E address in A ; Dereference noun address to move components of noun into MPAC, MPAC+1 ; mixed normal ; C(E SUBK) C(E) ; C((E SUBK)+1) C(E+1) READLO1 EQU * 12665 5,0665 5 0,0576 0 TS ADDRWD1 ; temp store addr for immediate use below 12666 5,0666 3 1,2050 0 CAF ZERO ; was INDEX A, DCA Q, DXCH MPAC in Block II12667 5,0667 2 0,0576 1 INDEX ADDRWD1 12670 5,0670 6 0,0000 1 AD 0 12671 5,0671 5 0,0130 0 TS MPAC 12672 5,0672 3 1,2050 0 CAF ZERO 12673 5,0673 2 0,0576 1 INDEX ADDRWD1 12674 5,0674 6 0,0001 0 AD 1 12675 5,0675 5 0,0131 1 TS MPAC+1 12676 5,0676 3 1,2050 0 CAF ZERO 12677 5,0677 5 0,0132 1 TS MPAC+2 12700 5,0700 0 0,0441 0 TC TEM4 ; return 12701 5,0701 3 1,2050 0 RDLONOR CAF ZERO ; was CA NOUNADD in Block II12702 5,0702 6 0,0442 0 AD NOUNADD 12703 5,0703 0 5,6665 1 ENDRDLO TC READLO1 BANK40_3 EQU * ORG BANK42_1 ; COLOSSUS pp. 333-336 INCL bank42_1.asm
;========================================================================== ; DISPLAY ROUTINES (file:bank42_1.asm) ; ; Adapted from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, pp. 333-336. ;========================================================================== ;-------------------------------------------------------------------------- ; HMSOUT -- OUTPUT SCALE FACTOR ROUTINE ; ; Adapted from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, p.333. ;-------------------------------------------------------------------------- HMSOUT EQU * 16000 7,0000 0 1,3565 1 TC BANKCALL ; read fresh data for HI and LO into MPAC,16001 7,0001 12653 1 DS READLO ; MPAC+1. 16002 7,0002 0 2,4150 1 TC TPAGREE ; make DP data agree16003 7,0003 0 7,6053 1 TC SEPSECNR ; leave frac sec/60 in MPAC, MPAC+1, leave ; whole min in bit13 of LOWTEMOUT and above16004 7,0004 0 2,4374 0 TC DMP ; use only fract sec/60 mod 6016005 7,0005 06043 0 ADRES SECON2 ; mult by .06 16006 7,0006 3 2,4637 1 CAF R3D1 ; gives CENT1-SEC/10EXP5 mod 6016007 7,0007 5 0,0466 0 TS DSPCOUNT 16010 7,0010 0 1,3565 1 TC BANKCALL ; display sec mod 6016011 7,0011 13064 1 DS DSPDECWD 16012 7,0012 0 7,6074 1 TC SEPMIN ; remove rest of seconds16013 7,0013 3 7,6045 0 CAF MINCON2 ; leave fract min/60 in MPAC+1, leave16014 7,0014 3 0,0130 0 XCH MPAC ; whole hours in MPAC16015 7,0015 5 0,0476 1 TS HITEMOUT ; save whole hours16016 7,0016 3 7,6046 0 CAF MINCON2+1 16017 7,0017 3 0,0131 1 XCH MPAC+1 ; use only fract min/60 mod 6016020 7,0020 0 2,4740 0 TC PRSHRTMP ; if C(A) = -0, SHORTMP fails to give -0. ; mult by .000616021 7,0021 3 2,4636 0 CAF R2D1 ; gives min/10EXP5 mod 6016022 7,0022 5 0,0466 0 TS DSPCOUNT 16023 7,0023 0 1,3565 1 TC BANKCALL ; display min mod 6016024 7,0024 13064 1 DS DSPDECWD 16025 7,0025 3 7,6051 0 CAF HRCON1 ; was DCA HRCON1, DXCH MPAC in Block II16026 7,0026 5 0,0130 0 TS MPAC 16027 7,0027 3 7,6052 0 CAF HRCON1+1 16030 7,0030 5 0,0131 1 TS MPAC+1 ; minutes, seconds have been removed 16031 7,0031 3 1,2050 0 CAF ZERO ; was CA HITEMOUT in Block II16032 7,0032 6 0,0476 1 AD HITEMOUT ; use whole hours16033 7,0033 0 2,4740 0 TC PRSHRTMP ; if C(A) = -0, SHORTMP fails to give -0. ; mult by .1638416034 7,0034 3 2,4635 0 CAF R1D1 ; gives hours/10EXP516035 7,0035 5 0,0466 0 TS DSPCOUNT 16036 7,0036 0 1,3565 1 TC BANKCALL ; use regular DSPDECWD, with round off16037 7,0037 13064 1 DS DSPDECWD 16040 7,0040 0 0,0433 0 TC ENTEXIT 16041 7,0041 25660 0 SECON1 DS %25660 ; 2EXP12/600016042 7,0042 31742 1 DS %31742 16043 7,0043 01727 1 SECON2 DS %01727 ; .06 for seconds display16044 7,0044 01217 1 DS %01217 16045 7,0045 00011 1 MINCON2 DS %00011 ; .0006 for minutes display16046 7,0046 32445 0 DS %32445 16047 7,0047 02104 0 MINCON1 DS %02104 ; .066..66 upped by 2EXP-2816050 7,0050 10422 1 DS %10422 16051 7,0051 05174 0 HRCON1 DS %05174 ; .16384 decimal16052 7,0052 13261 0 DS %13261 ; ************* missing stuff **************** SEPSECNR EQU * 16053 7,0053 3 0,0001 0 XCH Q ; this entry avoid rounding by .5 secs16054 7,0054 5 0,0441 0 TS SEPSCRET 16055 7,0055 0 2,4374 0 TC DMP ; mult by 2EXP12/600016056 7,0056 06041 1 ADRES SECON1 ; gives fract sec/60 in bit12 of MPAC+1
16057 7,0057 3 1,2050 0 CAF ZERO ; was DCA MPAC, DXCH HITEMOUT in Block II16060 7,0060 6 0,0130 0 AD MPAC ; save minutes and hours16061 7,0061 3 0,0476 1 XCH HITEMOUT 16062 7,0062 3 1,2050 0 CAF ZERO 16063 7,0063 6 0,0131 1 AD MPAC+1 16064 7,0064 3 0,0477 0 XCH HITEMOUT+1 16065 7,0065 0 2,4721 1 TC TPSL1 16066 7,0066 0 2,4721 1 TC TPSL1 ; gives fract sec/60 in MPAC+1, MPAC+2 16067 7,0067 3 1,2050 0 CAF ZERO 16070 7,0070 3 0,0132 1 XCH MPAC+2 ; leave fract sec/60 in MPAC, MPAC+116071 7,0071 3 0,0131 1 XCH MPAC+1 16072 7,0072 3 0,0130 0 XCH MPAC 16073 7,0073 0 0,0441 0 TC SEPSCRET SEPMIN EQU * 16074 7,0074 3 0,0001 0 XCH Q ; finds whole minutes in bit1316075 7,0075 5 0,0441 0 TS SEPMNRET ; of LOWTEMOUT and above. 16076 7,0076 3 1,2050 0 CAF ZERO 16077 7,0077 6 0,0477 0 AD LOTEMOUT ; removes rest of seconds 16100 7,0100 2 0,0000 1 EXTEND ; leaves fract min/60 in MPAC+116101 7,0101 4 1,2076 0 MP BIT3 ; leaves whole hours in MPAC16102 7,0102 2 0,0000 1 EXTEND ; SR 12, throw away LP16103 7,0103 4 1,2064 0 MP BIT13 ; SR 2?, take from LP. = SL 12 16104 7,0104 3 0,0003 1 XCH LP ; was LXCH MPAC+1 in Block II16105 7,0105 5 0,0131 1 TS MPAC+1 ; this forces bits 12-1 to 0 if +, ; forces bits 12-1 to 1 if -. 16106 7,0106 3 1,2050 0 CAF ZERO 16107 7,0107 6 0,0476 1 AD HITEMOUT 16110 7,0110 5 0,0130 0 TS MPAC 16111 7,0111 0 2,4374 0 TC DMP ; mult by 1/1516112 7,0112 06047 1 ADRES MINCON1 ; gives fract min/60 in MPAC+116113 7,0113 0 0,0441 0 ENDSPMIN TC SEPMNRET ; gives whole hours in MPAC BANK42_2 EQU * ORG BANK40_3 ; COLOSSUS pp. 336 INCL bank40_3.asm ;========================================================================== ; WORD DISPLAY ROUTINES (file:bank40_3.asm) ; ; AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, p.336. ;========================================================================== ;-------------------------------------------------------------------------- ; DSPDPDEC ; This is a special purpose verb for displaying a double precision AGC ; word as 10 decimal digits on the AGC display panel. It can be used with ; any noun, except mixed nouns. It displays the contents of the register ; NOUNADD is pointing to. If used with nouns which are inherently not DP ; such as the CDU counters, the display will be garbage. ; Display is in R1 and R2 only with the sign in R1. ; ; Adapted from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, p.353. ;-------------------------------------------------------------------------- DSPDPDEC EQU * 12704 5,0704 2 0,0435 1 INDEX MIXBR 12705 5,0705 0 5,6705 0 TC *+0 12706 5,0706 0 5,6710 1 TC *+2 ; normal noun12707 5,0707 0 5,7267 0 TC DSPALARM 12710 5,0710 3 1,2050 0 CAF ZERO 12711 5,0711 2 0,0442 1 INDEX NOUNADD 12712 5,0712 6 0,0000 1 AD 0 ; was DCA 0, DXCH MPAC in Block II12713 5,0713 5 0,0130 0 TS MPAC 12714 5,0714 3 1,2050 0 CAF ZERO 12715 5,0715 2 0,0442 1 INDEX NOUNADD 12716 5,0716 6 0,0001 0 AD 1 ; was DCA 0, DXCH MPAC in Block II12717 5,0717 5 0,0131 1 TS MPAC+1 12720 5,0720 3 2,4635 0 CAF R1D1 12721 5,0721 5 0,0466 0 TS DSPCOUNT
12722 5,0722 3 1,2050 0 CAF ZERO 12723 5,0723 5 0,0132 1 TS MPAC+2 12724 5,0724 0 2,4150 1 TC TPAGREE 12725 5,0725 0 5,7131 0 TC DSP2DEC 12726 5,0726 0 0,0433 0 ENDDPDEC TC ENTEXIT BANK40_4 EQU * ORG BANK41_2 ; COLOSSUS pp. 337-342 INCL bank41_2.asm ;========================================================================== ; DISPLAY ROUTINES (file:bank41_2.asm) ; ; Adapted from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, pp. 337-342. ;========================================================================== ;========================================================================== ; PINBALL GAME LOAD VERBS (file:bank41_2.asm) ; ; If alarm condition is detected during execute, check fail light is ; turned on and ENDOFJOB. If alarm condition is detected during enter ; of data, check fail is turned on and it recycles to execute of ; original load verb. Recycle caused by 1) decimal machine CADR, ; 2) mixture of octal/decimal data, 3) octal data into decimal only ; noun, 4) decimal data into octal only noun, 5) data too large for ; scale, 6) fewer than two data words loaded for HRS, MIN, SEC noun. ; For #2-6, alarm and recycle occur at final enter of set; for #1, ; alarm and recycle occur at enter of CADR. ; ; AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, p.337-343. ;========================================================================== ABCLOAD EQU * 14600 6,0600 4 1,2052 0 CS TWO 14601 6,0601 0 6,6414 0 TC COMPTEST 14602 6,0602 0 6,6453 0 TC NOUNTEST ; test if noun can be loaded 14603 6,0603 3 6,6733 0 CAF VBSP1LD 14604 6,0604 0 6,6326 0 TC UPDATVB-1 14605 6,0605 0 6,6264 1 TC REQDATX 14606 6,0606 3 6,6734 1 CAF VBSP2LD 14607 6,0607 0 6,6326 0 TC UPDATVB-1 14610 6,0610 0 6,6270 1 TC REQDATY 14611 6,0611 3 6,6735 0 CAF VBSP3LD 14612 6,0612 0 6,6326 0 TC UPDATVB-1 14613 6,0613 0 6,6274 0 TC REQDATZ PUTXYZ EQU * 14614 6,0614 4 1,2056 1 CS SIX ; test that the 3 data words loaded are14615 6,0615 0 6,6736 0 TC ALLDC_OC ; all dec or all oct 14616 6,0616 3 6,6124 0 CAF LODNNLOC ; was DCA LODNNLOC, DXCH Z in Block II14617 6,0617 0 1,3526 0 TC DXCHJUMP ; bank jump to noun table read rtne 14620 6,0620 3 1,2050 0 CAF ZERO ; X comp14621 6,0621 0 6,7031 1 TC PUTCOM 14622 6,0622 2 0,0442 1 INDEX NOUNADD 14623 6,0623 5 0,0000 1 TS 0 14624 6,0624 3 1,2051 1 CAF ONE ; Y comp14625 6,0625 0 6,7031 1 TC PUTCOM 14626 6,0626 2 0,0442 1 INDEX NOUNADD 14627 6,0627 5 0,0001 0 TS 1 14630 6,0630 3 1,2052 1 CAF TWO ; Z comp14631 6,0631 0 6,7031 1 TC PUTCOM 14632 6,0632 2 0,0442 1 INDEX NOUNADD 14633 6,0633 5 0,0002 0 TS 2 ; *************** missing stuff ***************** ; Omitted a bunch of code from here that does special stuff if the noun=7. ; (a noun that operates on I/O channels and flagbits) 14634 6,0634 0 6,6723 1 TC LOADLV ABLOAD EQU *
14635 6,0635 4 1,2051 0 CS ONE 14636 6,0636 0 6,6414 0 TC COMPTEST 14637 6,0637 0 6,6453 0 TC NOUNTEST ; test if noun can be loaded 14640 6,0640 3 6,6733 0 CAF VBSP1LD 14641 6,0641 0 6,6326 0 TC UPDATVB-1 14642 6,0642 0 6,6264 1 TC REQDATX 14643 6,0643 3 6,6734 1 CAF VBSP2LD 14644 6,0644 0 6,6326 0 TC UPDATVB-1 14645 6,0645 0 6,6270 1 TC REQDATY PUTXY EQU * 14646 6,0646 4 1,2055 1 CS FIVE ; test that the 2 data words loaded are14647 6,0647 0 6,6736 0 TC ALLDC_OC ; all dec or all oct 14650 6,0650 3 6,6124 0 CAF LODNNLOC ; was DCA LODNNLOC, DXCH Z in Block II14651 6,0651 0 1,3526 0 TC DXCHJUMP ; bank jump to noun table read rtne 14652 6,0652 3 1,2050 0 CAF ZERO ; X comp14653 6,0653 0 6,7031 1 TC PUTCOM 14654 6,0654 2 0,0442 1 INDEX NOUNADD 14655 6,0655 5 0,0000 1 TS 0 14656 6,0656 3 1,2051 1 CAF ONE ; Y comp14657 6,0657 0 6,7031 1 TC PUTCOM 14660 6,0660 2 0,0442 1 INDEX NOUNADD 14661 6,0661 5 0,0001 0 TS 1 14662 6,0662 0 6,6723 1 TC LOADLV ALOAD EQU * 14663 6,0663 0 6,6264 1 TC REQDATX 14664 6,0664 3 6,6124 0 CAF LODNNLOC ; was DCA LODNNLOC, DXCH Z in Block II14665 6,0665 0 1,3526 0 TC DXCHJUMP ; bank jump to noun table read rtne 14666 6,0666 3 1,2050 0 CAF ZERO ; X comp14667 6,0667 0 6,7031 1 TC PUTCOM 14670 6,0670 2 0,0442 1 INDEX NOUNADD 14671 6,0671 5 0,0000 1 TS 0 14672 6,0672 0 6,6723 1 TC LOADLV BLOAD EQU * 14673 6,0673 4 1,2051 0 CS ONE 14674 6,0674 0 6,6414 0 TC COMPTEST 14675 6,0675 3 1,2062 1 CAF BIT15 ; set CLPASS for PASS0 only14676 6,0676 5 0,0504 0 TS CLPASS 14677 6,0677 0 6,6270 1 TC REQDATY 14700 6,0700 3 6,6124 0 CAF LODNNLOC ; was DCA LODNNLOC, DXCH Z in Block II14701 6,0701 0 1,3526 0 TC DXCHJUMP ; bank jump to noun table read rtne14702 6,0702 3 1,2051 1 CAF ONE 14703 6,0703 0 6,7031 1 TC PUTCOM 14704 6,0704 2 0,0442 1 INDEX NOUNADD 14705 6,0705 5 0,0001 0 TS 1 14706 6,0706 0 6,6723 1 TC LOADLV CLOAD EQU * 14707 6,0707 4 1,2052 0 CS TWO 14710 6,0710 0 6,6414 0 TC COMPTEST 14711 6,0711 3 1,2062 1 CAF BIT15 ; set CLPASS for PASS0 only14712 6,0712 5 0,0504 0 TS CLPASS 14713 6,0713 0 6,6274 0 TC REQDATZ 14714 6,0714 3 6,6124 0 CAF LODNNLOC ; was DCA LODNNLOC, DXCH Z in Block II14715 6,0715 0 1,3526 0 TC DXCHJUMP ; bank jump to noun table read rtne14716 6,0716 3 1,2052 1 CAF TWO 14717 6,0717 0 6,7031 1 TC PUTCOM 14720 6,0720 2 0,0442 1 INDEX NOUNADD 14721 6,0721 5 0,0002 0 TS 2 14722 6,0722 0 6,6723 1 TC LOADLV ; yes, COLOSSUS actually did this LOADLV EQU * 14723 6,0723 3 1,2050 0 CAF ZERO 14724 6,0724 5 0,0467 1 TS DECBRNCH 14725 6,0725 4 1,2050 1 CS ZERO 14726 6,0726 5 0,0503 1 TS LOADSTAT 14727 6,0727 4 2,4675 0 CS VD1 ; to block numerical chars and14730 6,0730 5 0,0466 0 TS DSPCOUNT ; clears after a completed load14731 6,0731 0 1,3653 1 TC POSTJUMP ; after completed load, go to RECALTST14732 6,0732 13413 0 DS RECALTST ; to see if there is RECALL from ENDIDLE 14733 6,0733 00025 0 VBSP1LD DS 21 ; VB21 = ALOAD14734 6,0734 00026 0 VBSP2LD DS 22 ; VB22 = BLOAD14735 6,0735 00027 1 VBSP3LD DS 23 ; VB23 = CLOAD ALLDC_OC EQU * 14736 6,0736 5 0,0414 0 TS DECOUNT ; test that data words loaded are either
14737 6,0737 3 0,0001 0 XCH Q ; (needed to handle TCF conversion below)14740 6,0740 5 0,0556 1 TS ALLDC_OC_Q ; save return address 14741 6,0741 4 0,0467 0 CS DECBRNCH ; all dec or all oct; alarms if not14742 6,0742 5 0,0021 1 TS SR 14743 6,0743 4 0,0021 0 CS SR 14744 6,0744 4 0,0021 0 CS SR ; shifted right 214745 6,0745 1 0,0000 0 CCS A ; dec comp bits in low 314746 6,0746 0 6,6750 0 TC *+2 ; some ones in low 3 (was TCF in Block II)14747 6,0747 0 0,0556 1 TC ALLDC_OC_Q ; all zeros, all oct, OK so return14750 6,0750 6 0,0414 0 AD DECOUNT ; dec comp = 7 for 3comp, =6 for 2comp ; (but it has been decremented by CCS)14751 6,0751 1 0,0000 0 CCS A ; must match 6 for 3comp, 5 for 2comp14752 6,0752 0 6,6756 0 TC *+4 ; >014753 6,0753 0 6,6755 0 TC *+2 ; +014754 6,0754 0 6,6756 0 TC *+2 ; <014755 6,0755 0 6,6757 1 TC *+2 ; -0, was BZF *+2 in Block II 14756 6,0756 0 2,4474 1 TC ALMCYCLE ; alarm and recycle (does not return) 14757 6,0757 3 0,0556 1 XCH ALLDC_OC_Q ; restore return address14760 6,0760 5 0,0001 0 TS Q 14761 6,0761 0 0,0001 0 GOQ TC Q ; all required are dec, OK ;-------------------------------------------------------------------------- ; SFRUTNOR ; gets SF routine number for normal case. ; ; Adapted from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, p.340. ;-------------------------------------------------------------------------- SFRUTNOR EQU * 14762 6,0762 3 0,0001 0 XCH Q 14763 6,0763 5 0,0411 0 TS EXITEM ; can't use L for return. TESTFORDP uses L.14764 6,0764 3 2,4665 0 CAF MID5 14765 6,0765 7 0,0444 1 MASK NNTYPTEM 14766 6,0766 0 2,4640 1 TC RIGHT5 14767 6,0767 0 0,0411 0 TC EXITEM ; SF routine number in A ;-------------------------------------------------------------------------- ; SFRUTMIX ; gets SF routine number for mixed case. ; ; Adapted from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, p.340. ;-------------------------------------------------------------------------- SFRUTMIX EQU * 14770 6,0770 3 0,0001 0 XCH Q ; gets SF routine number for mixed case14771 6,0771 5 0,0411 0 TS EXITEM 14772 6,0772 2 0,0414 1 INDEX DECOUNT 14773 6,0773 3 6,7022 0 CAF DISPLACE ; put TC GOQ, TC RIGHT5, or TC LEFT5 in L14774 6,0774 5 0,0557 0 TS SFRUTMIX_L 14775 6,0775 2 0,0414 1 INDEX DECOUNT 14776 6,0776 3 2,4664 1 CAF LOW5 ; LOW5, MID5, or HI5 in A14777 6,0777 7 0,0450 1 MASK RUTMXTEM ; get HI5, MID5, or LOW5 of RUTMXTAB entry 15000 6,1000 2 0,0557 1 INDEX SFRUTMIX_L 15001 6,1001 0 0,0000 1 TC 0 ; do TC GOQ (DECOUNT=0), do TC RIGHT5 (DECOUNT=1), do TC LEFT5 (DECOUNT=2) 15002 6,1002 0 0,0411 0 SFRET1 TC EXITEM ; SF routine number in A SFCONUM EQU * 15003 6,1003 3 0,0001 0 XCH Q ; gets 2X (SF constant number)15004 6,1004 5 0,0411 0 TS EXITEM 15005 6,1005 2 0,0435 1 INDEX MIXBR 15006 6,1006 0 6,7006 0 TC *+0 15007 6,1007 0 6,7025 1 TC CONUMNOR ; normal noun15010 6,1010 2 0,0414 1 INDEX DECOUNT ; mixed noun15011 6,1011 3 6,7022 0 CAF DISPLACE 15012 6,1012 5 0,0560 1 TS SFCONUM_L ; put TC GOQ, TC RIGHT5, or TC LEFT5 in L15013 6,1013 2 0,0414 1 INDEX DECOUNT 15014 6,1014 3 2,4664 1 CAF LOW5 15015 6,1015 7 0,0444 1 MASK NNTYPTEM 15016 6,1016 2 0,0560 0 INDEX SFCONUM_L 15017 6,1017 0 0,0000 1 TC 0 ; do TC GOQ (DECOUNT=0), do TC RIGHT5 (DECOUNT=1), do TC LEFT5 (DECOUNT=2)
15020 6,1020 6 0,0000 1 SFRET DOUBLE ; 2X (SF constant number) in A15021 6,1021 0 0,0411 0 TC EXITEM DISPLACE EQU * 15022 6,1022 0 6,6761 1 TC GOQ 15023 6,1023 0 2,4640 1 TC RIGHT5 15024 6,1024 0 2,4647 0 TC LEFT5 CONUMNOR EQU * 15025 6,1025 3 2,4664 1 CAF LOW5 ; normal noun always gets low 5 of15026 6,1026 7 0,0444 1 MASK NNTYPTEM ; NNTYPTAB for SF CONUM15027 6,1027 6 0,0000 1 DOUBLE 15030 6,1030 0 0,0411 0 TC EXITEM ; 2X (SF constant number) in A PUTCOM EQU * 15031 6,1031 5 0,0414 0 TS DECOUNT 15032 6,1032 3 0,0001 0 XCH Q 15033 6,1033 5 0,0412 0 TS DECRET 15034 6,1034 3 1,2050 0 CAF ZERO 15035 6,1035 5 0,0136 0 TS MPAC+6 15036 6,1036 2 0,0414 1 INDEX DECOUNT 15037 6,1037 3 0,0475 1 XCH XREGLP 15040 6,1040 5 0,0131 1 TS MPAC+1 15041 6,1041 2 0,0414 1 INDEX DECOUNT 15042 6,1042 3 0,0472 0 XCH XREG 15043 6,1043 5 0,0130 0 TS MPAC 15044 6,1044 2 0,0435 1 INDEX MIXBR 15045 6,1045 0 6,7045 1 TC * 15046 6,1046 0 6,7077 0 TC PUTNORM ; normal noun ; if mixnoun, place address for component K into NOUNADD, set EBANK bits. 15047 6,1047 2 0,0414 1 INDEX DECOUNT ; set IDADDTAB entry for component K15050 6,1050 3 1,2050 0 CAF ZERO ; of noun15051 6,1051 6 0,0445 1 AD IDAD1TEM ; was CA IDAD1TEM in Block II15052 6,1052 7 2,4672 1 MASK LOW11 ; (ECADR) SUBK for current comp of noun15053 6,1053 0 2,4616 1 TC SETNCADR ; ECADR into NOUNCADR, sets EB, NOUNADD15054 6,1054 2 0,0000 1 EXTEND ; C(NOUNADD) in A upon return15055 6,1055 6 0,0414 0 SU DECOUNT ; place (ESUBK)-K into NOUNADD15056 6,1056 5 0,0442 0 TS NOUNADD 15057 6,1057 1 0,0467 0 CCS DECBRNCH 15060 6,1060 0 6,7114 1 TC PUTDECSF ; + dec15061 6,1061 0 6,6444 0 TC DCTSTCYC ; +0 octal15062 6,1062 0 6,6770 1 TC SFRUTMIX ; test if dec only bit = 1. If so,15063 6,1063 0 6,6240 1 TC DPTEST ; alarm and recycle. If not, continue.15064 6,1064 0 6,7111 1 TC PUTCOM2 ; no DP ; test for DP scale for oct load. If so, ; +0 into major part. Set NOUNADD for ; loading octal word into minor part. PUTDPCOM EQU * 15065 6,1065 3 1,2050 0 CAF ZERO ; was INCR NOUNADD in Block II15066 6,1066 6 0,0442 0 AD NOUNADD ; DP (RSUBK)-K+1 or E+115067 6,1067 6 1,2051 1 AD ONE 15070 6,1070 5 0,0442 0 TS NOUNADD 15071 6,1071 6 0,0414 0 AD DECOUNT ; (ESUBK)+1 or E+1 into DECOUNT15072 6,1072 5 0,0414 0 TS DECOUNT ; was ADS DECOUNT in Block II 15073 6,1073 3 1,2050 0 CAF ZERO ; NOUNADD set for minor part15074 6,1074 2 0,0414 1 INDEX DECOUNT 15075 6,1075 5 17,7776 0 TS -1 ; zero major part (ESUBK or E1)15076 6,1076 0 6,7111 1 TC PUTCOM2 PUTNORM EQU * 15077 6,1077 0 2,4625 1 TC SETNADD ; ECADR from NOUNCADR, sets EB, NOUNADD15100 6,1100 1 0,0467 0 CCS DECBRNCH 15101 6,1101 0 6,7114 1 TC PUTDECSF ; +DEC15102 6,1102 0 6,6444 0 TC DCTSTCYC ; +0 octal15103 6,1103 0 6,6762 1 TC SFRUTNOR ; test if dec only bit = 1. If so,15104 6,1104 0 6,6240 1 TC DPTEST ; alarm and recycle. If not, continue.15105 6,1105 0 6,7111 1 TC PUTNORM_1 ; no DP15106 6,1106 3 1,2050 0 CAF ZERO 15107 6,1107 5 0,0414 0 TS DECOUNT 15110 6,1110 0 6,7065 0 TC PUTDPCOM PUTNORM_1 EQU * ; eliminated Block II CHANNEL LOAD code PUTCOM2 EQU * 15111 6,1111 3 0,0130 0 XCH MPAC 15112 6,1112 0 0,0412 0 TC DECRET 15113 6,1113 16176 0 GTSFINLC DS GTSFIN ; *************** missing stuff *****************
; PUTDECSF ; Finds MIXBR and DECOUNT still set from PUTCOM PUTDECSF EQU * 15114 6,1114 0 6,7003 0 TC SFCONUM ; 2X (SF CON NUM) in A15115 6,1115 5 0,0420 1 TS SFTEMP1 15116 6,1116 3 6,7113 0 CAF GTSFINLC ; was DCA GTSFINLC, DXCH Z in Block II15117 6,1117 0 1,3526 0 TC DXCHJUMP ; bank jump to SF const table read rtne ; loads SFTEMP1, SFTEMP215120 6,1120 2 0,0435 1 INDEX MIXBR 15121 6,1121 0 6,7121 1 TC * 15122 6,1122 0 6,7125 0 TC PUTSFNOR 15123 6,1123 0 6,6770 1 TC SFRUTMIX 15124 6,1124 0 6,7126 0 TC PUTDCSF2 15125 6,1125 0 6,6762 1 PUTSFNOR TC SFRUTNOR 15126 6,1126 2 0,0000 0 PUTDCSF2 INDEX A 15127 6,1127 3 6,7131 0 CAF SFINTABR 15130 6,1130 0 1,3712 0 TC BANKJUMP ; switch banks for expansion room15131 6,1131 14340 0 SFINTABR CADR GOALMCYC ; 0, alarm and recycle if dec load15132 6,1132 13011 0 CADR BINROUND ; 115133 6,1133 12727 0 CADR DEGINSF ; 215134 6,1134 12776 1 CADR ARTHINSF ; 315135 6,1135 00000 1 CADR 0 ; 4 **********15136 6,1136 00000 1 CADR 0 ; 5 **********15137 6,1137 00000 1 CADR 0 ; 6 **********15140 6,1140 00000 1 CADR 0 ; 7 **********15141 6,1141 00000 1 CADR 0 ; 8 **********15142 6,1142 00000 1 CADR 0 ; 9 **********15143 6,1143 00000 1 CADR 0 ; 10 *********15144 6,1144 00000 1 CADR 0 ; 11 *********15145 6,1145 00000 1 CADR 0 ; 12 ********* ; BUNCH OF TABLE ENTRIES GO HERE!!!!! ; ************ NEED TO ADD THE REST ************* BANK41_3 EQU * ORG BANK40_4 ; COLOSSUS pp. 343-346 INCL bank40_4.asm ;========================================================================== ; SCALE FACTOR ROUTINES (file:bank40_4.asm) ; ; Adapted from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, pp. 343-346. ;========================================================================== DEGINSF EQU * 12727 5,0727 0 2,4374 0 TC DMP ; SF routine for dec degrees12730 5,0730 06772 0 ADRES DEGCON1 ; mult by 5.5 5(10)X2EXP-312731 5,0731 1 0,0131 0 CCS MPAC+1 ; this rounds off MPAC+1 before shift12732 5,0732 3 1,2066 0 CAF BIT11 ; left 3, and causes 360.00 to OF/UF12733 5,0733 0 5,6735 0 TC *+2 ; when shifted left and alarm12734 5,0734 4 1,2066 1 CS BIT11 12735 5,0735 6 0,0131 1 AD MPAC+1 12736 5,0736 0 5,7016 1 TC _2ROUND+2 12737 5,0737 0 2,4721 1 TC TPSL1 ; left 112740 5,0740 0 2,4721 1 DEGINSF2 TC TPSL1 ; left 212741 5,0741 0 5,7025 1 TC TESTOFUF 12742 5,0742 0 2,4721 1 TC TPSL1 ; returns if no OF/UF (left 3)12743 5,0743 1 0,0130 1 CCS MPAC 12744 5,0744 0 5,6750 0 TC SIGNFIX ; if +, go to SIGNFIX12745 5,0745 0 5,6750 0 TC SIGNFIX ; if +0, go to SIGNFIX12746 5,0746 4 0,0000 0 COM ; if -, use -MAGNITUDE + 112747 5,0747 5 0,0130 0 TS MPAC ; -f -0; use +012750 5,0750 1 0,0136 1 SIGNFIX CCS MPAC+6 12751 5,0751 0 5,6766 0 TC SGNTO1 ; if overflow12752 5,0752 0 5,6762 1 TC ENDSCALE ; no overflow/underflow12753 5,0753 1 0,0130 1 CCS MPAC ; if UF, force sign to 0 except -18012754 5,0754 0 5,6271 0 TC CCSHOLE 12755 5,0755 0 5,6764 1 TC NEG180 12756 5,0756 0 5,6757 1 TC *+1 12757 5,0757 3 0,0130 0 XCH MPAC 12760 5,0760 7 1,2106 0 MASK POSMAX 12761 5,0761 5 0,0130 0 TS MPAC ENDSCALE EQU * 12762 5,0762 0 1,3653 1 TC POSTJUMP 12763 5,0763 15111 1 CADR PUTCOM2 12764 5,0764 4 1,2106 0 NEG180 CS POSMAX 12765 5,0765 0 5,6761 1 TC ENDSCALE-1
SGNTO1 EQU * 12766 5,0766 4 0,0130 1 CS MPAC ; if OV force sign to 112767 5,0767 7 1,2106 0 MASK POSMAX 12770 5,0770 4 0,0000 0 CS A 12771 5,0771 0 5,6761 1 TC ENDSCALE-1 12772 5,0772 26161 0 DEGCON1 DS %26161 12773 5,0773 30707 1 DS %30707 12774 5,0774 21616 0 DEGCON2 DS %21616 12775 5,0775 07071 0 DS %07071 ; ************ missing stuff *************** ARTHINSF EQU * 12776 5,0776 0 2,4374 0 TC DMP ; scales MPAC, +1 by SFTEMP1, SFTEMP212777 5,0777 00420 1 ADRES SFTEMP1 ; assumes point between HI and LO parts13000 5,1000 3 0,0132 1 XCH MPAC+2 ; of SFCON, shifts results left by 14.13001 5,1001 3 0,0131 1 XCH MPAC+1 ; (by taking results from MPAC+1, MPAC+2)13002 5,1002 3 0,0130 0 XCH MPAC 13003 5,1003 1 0,0000 0 CCS A ; was BZF BINROUND in Block II13004 5,1004 0 5,7010 1 TC *+4 ; >013005 5,1005 0 5,7007 1 TC *+2 ; +013006 5,1006 0 5,7010 1 TC *+2 ; <013007 5,1007 0 5,7011 0 TC BINROUND ; -0 13010 5,1010 0 2,4474 1 TC ALMCYCLE ; too large a load, alarm and recycle BINROUND EQU * 13011 5,1011 0 5,7014 0 TC _2ROUND 13012 5,1012 0 5,7025 1 TC TESTOFUF 13013 5,1013 0 5,6762 1 TC ENDSCALE ; ************ missing stuff *************** _2ROUND EQU * 13014 5,1014 3 0,0131 1 XCH MPAC+1 13015 5,1015 6 0,0000 1 DOUBLE 13016 5,1016 5 0,0131 1 TS MPAC+1 13017 5,1017 0 0,0001 0 TC Q ; if MPAC+1 does not OF/UF13020 5,1020 6 0,0130 0 AD MPAC 13021 5,1021 5 0,0130 0 TS MPAC 13022 5,1022 0 0,0001 0 TC Q ; if MPAC does not OF/UF13023 5,1023 5 0,0136 0 TS MPAC+6 13024 5,1024 0 0,0001 0 _2RNDEND TC Q TESTOFUF EQU * 13025 5,1025 1 0,0136 1 CCS MPAC+6 ; returns if no OF/UF13026 5,1026 0 2,4474 1 TC ALMCYCLE ; OF, alarm and recycle13027 5,1027 0 0,0001 0 TC Q 13030 5,1030 0 2,4474 1 TC ALMCYCLE ; UF, alarm and recycle BANK40_5 EQU * ORG BANK42_2 BANK42_3 EQU * ORG BANK41_3 INCL bank41_3.asm ; COLOSSUS pp. 349-351 ;========================================================================== ; DISPLAY ROUTINES (file:bank41_3.asm) ; ; Adapted from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, pp. 349-351. ;========================================================================== ; MONITOR allows other keyboard activity. It is ended by verb TERMINATE ; verb PROCEED WITHOUT DATA, verb RESEQUENCE, another monitor, or any ; NVSUB call that passes DSPLOCK (provided that the operator has somehow ; allowed the ending of a monitor which he has initiated through the ; keyboard. ; ; MONITOR action is suspended, but not ended, by any keyboard action, ; except error light reset. It begins again when KEY RELEASE is performed. ; MONITOR saves the noun and appropriate display verb in MONSAVE. It saves ; NOUNCADR in MONSAVE1, if noun = machine CADR to be specified. Bit 15 of ; MONSAVE1 is the kill monitor signal (killer bit). Bit 14 of MONSAVE1 ; indicates the current monitor was externally initiated (external monitor ; bit). It is turned off by RELDSP and KILMONON. ; ; MONSAVE indicates if MONITOR is on (+=ON, +0=OFF) ; If MONSAVE is +, monitor enters no request, but turns killer bit off. ; If MONSAVE is +0, monitor enters request and turns killer bit off. ; ; NVSUB (if external monitor bit is off), VB=PROCEED WITHOUT DATA,
; VB=RESEQUENCE, and VB=TERMINATE turn kill monitor bit on. ; ; If killer bit is on, MONREQ enters no further requests, zeroes MONSAVE ; and MONSAVE1 (turning off killer bit and external monitor bit). ; ; MONITOR doesn't test for MATBS since NVSUB can handle internal MATBS now. MONITOR EQU * 15146 6,1146 4 6,7155 0 CS BIT15_14 15147 6,1147 7 0,0506 0 MASK NOUNCADR MONIT1 EQU * 15150 6,1150 5 0,0131 1 TS MPAC+1 ; temp storage 15151 6,1151 4 0,0433 1 CS ENTEXIT 15152 6,1152 6 2,4553 0 AD ENDINST 15153 6,1153 1 0,0000 0 CCS A 15154 6,1154 0 6,7164 0 TC MONIT2 15155 6,1155 60000 1 BIT15_14 DS %60000 15156 6,1156 0 6,7164 0 TC MONIT2 15157 6,1157 3 1,2063 0 CAF BIT14 ; externally initiated monitor15160 6,1160 6 0,0131 1 AD MPAC+1 ; was ADS MPAC+1 in Block II15161 6,1161 5 0,0131 1 TS MPAC+1 ; set bit 14 for MONSAVE1 15162 6,1162 3 1,2050 0 CAF ZERO 15163 6,1163 5 0,0511 1 TS MONSAVE2 ; zero NVMONOPT options MONIT2 EQU * 15164 6,1164 3 1,2101 0 CAF LOW7 15165 6,1165 7 0,0470 0 MASK VERBREG 15166 6,1166 0 2,4647 0 TC LEFT5 15167 6,1167 5 0,0022 1 TS CYL 15170 6,1170 4 0,0022 0 CS CYL 15171 6,1171 3 0,0022 1 XCH CYL 15172 6,1172 6 0,0471 0 AD NOUNREG 15173 6,1173 5 0,0130 0 TS MPAC ; temp storage15174 6,1174 3 1,2050 0 CAF ZERO 15175 6,1175 5 0,0501 0 TS DSPLOCK ; +0 into DSPLOCK so monitor can run15176 6,1176 1 0,0531 1 CCS CADRSTOR ; turn off KR lite if CADRSTOR and DSPLIST15177 6,1177 0 6,7201 0 TC *+2 ; are both empty. (Lite comes on if new15200 6,1200 0 2,5026 0 TC RELDSP1 ; monitor is keyed in over old monitor.)15201 6,1201 2 0,0000 0 INHINT 15202 6,1202 1 0,0507 1 CCS MONSAVE 15203 6,1203 0 6,7207 0 TC *+4 ; if MONSAVE was +, no request 15204 6,1204 3 1,2051 1 CAF ONE ; if MONSAVE was 0, request MONREQ15205 6,1205 0 1,2232 0 TC WAITLIST 15206 6,1206 15215 0 CADR MONREQ 15207 6,1207 3 0,0131 1 XCH MPAC+1 ; was DXCH MPAC, DXCH MONSAVE15210 6,1210 3 0,0510 0 XCH MONSAVE+1 15211 6,1211 3 0,0130 0 XCH MPAC ; place monitor verb and noun into MONSAVE15212 6,1212 3 0,0507 0 XCH MONSAVE ; zero the kill monitor bit 15213 6,1213 2 0,0000 1 RELINT ; set up external monitor bit15214 6,1214 0 0,0433 0 TC ENTRET MONREQ EQU * 15215 6,1215 0 6,7300 0 TC LODSAMPT ; called by waitlist (see COLOSSUS p. 374)15216 6,1216 1 0,0510 1 CCS MONSAVE1 ; time is snatched in RUPT for NOUN 6515217 6,1217 0 6,7223 0 TC *+4 ; if killer bit = 0, enter requests15220 6,1220 0 6,7223 0 TC *+3 ; if killer bit = 0, enter requests15221 6,1221 0 6,7232 0 TC KILLMON ; if killer bit = 1, no requests15222 6,1222 0 6,7232 0 TC KILLMON ; if killer bit = 1, no requests 15223 6,1223 3 6,7236 1 CAF MONDEL 15224 6,1224 0 1,2232 0 TC WAITLIST ; enter waitlist request for MONREQ15225 6,1225 15215 0 CADR MONREQ 15226 6,1226 3 2,4131 0 CAF CHRPRIO 15227 6,1227 0 1,3162 1 TC NOVAC ; enter EXEC request for MONDO15230 6,1230 15237 0 CADR MONDO 15231 6,1231 0 1,2413 0 TC TASKOVER KILLMON EQU * 15232 6,1232 3 1,2050 0 CAF ZERO ; zero MONSAVE and turn killer bit off15233 6,1233 5 0,0507 0 TS MONSAVE 15234 6,1234 5 0,0510 0 TS MONSAVE1 ; turn off kill monitor bit15235 6,1235 0 1,2413 0 TC TASKOVER ; turn off external monitor bit 15236 6,1236 00144 0 MONDEL DS %144 ; for 1 sec monitor intervals
MONDO EQU * 15237 6,1237 1 0,0510 1 CCS MONSAVE1 ; called by EXEC15240 6,1240 0 6,7244 1 TC *+4 ; if killer bit = 0, continue15241 6,1241 0 6,7244 1 TC *+3 ; if killer bit = 0, continue15242 6,1242 0 1,2723 0 TC ENDOFJOB ; in case TERMINATE came since last MONREQ15243 6,1243 0 1,2723 0 TC ENDOFJOB ; in case TERMINATE came since last MONREQ15244 6,1244 1 0,0501 1 CCS DSPLOCK 15245 6,1245 0 6,7276 0 TC MONBUSY ; NVSUB is busy15246 6,1246 3 1,2101 0 CAF LOW7 15247 6,1247 7 0,0507 1 MASK MONSAVE 15250 6,1250 0 6,6306 1 TC UPDATNN-1 ; place noun into NOUNREG and display it15251 6,1251 3 2,4473 0 CAF MID7 15252 6,1252 7 0,0507 1 MASK MONSAVE ; change monitor verb to display verb15253 6,1253 6 6,7274 1 AD MONREF ; -DEC10, starting in bit5 15254 6,1254 5 0,0020 0 TS CYR ; shift right 7, was TS EDOP, CA EDOP in BII15255 6,1255 4 0,0020 1 CS CYR 15256 6,1256 4 0,0020 1 CS CYR 15257 6,1257 4 0,0020 1 CS CYR 15260 6,1260 4 0,0020 1 CS CYR 15261 6,1261 4 0,0020 1 CS CYR 15262 6,1262 4 0,0020 1 CS CYR 15263 6,1263 3 0,0020 0 XCH CYR 15264 6,1264 7 1,2101 1 MASK LOW7 15265 6,1265 5 0,0470 1 TS VERBREG 15266 6,1266 3 6,7275 0 CAF MONBACK ; set return to PASTEVB after data display15267 6,1267 5 0,0433 0 TS ENTRET 15270 6,1270 4 6,7155 0 CS BIT15_14 15271 6,1271 7 0,0510 1 MASK MONSAVE1 15272 6,1272 5 0,0132 1 TS MPAC+2 ; display it and set NOUNCADR, NOUNADD,15273 6,1273 0 6,6054 0 ENDMONDO TC TESTNN ; EBANK ; COLOSSUS switches to fixed/fixed memory and inserts PASTEVB here-- ; Probably, because their assembler couldn't handle forward references. 15274 6,1274 75377 0 MONREF DS %75377 ; -dec10, starting in bit815275 6,1275 04435 1 MONBACK CADR PASTEVB 15276 6,1276 0 2,4713 0 MONBUSY TC RELDSPON ; turn key release light15277 6,1277 0 1,2723 0 TC ENDOFJOB 15300 6,1300 0 0,0001 0 LODSAMPT TC Q ; ************************** FIX**************************** BANK41_4 EQU * ORG BANKFF_1 INCL bankff_1.asm ; COLOSSUS pp. 351 ;========================================================================== ; DISPLAY ROUTINES (file:bankff_1.asm) ; ; Adapted from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, pp. 351. ;========================================================================== PASTEVB EQU * 04435 4435 3 2,4473 0 CAF MID7 04436 4436 7 0,0511 0 MASK MONSAVE2 ; NVMONOPT paste option04437 4437 5 0,0571 1 TS PASTE_TMP 04440 4440 1 0,0000 0 CCS A ; was BZF *+2 in Block II04441 4441 0 2,4443 0 TC *+2 ; >0,04442 4442 0 2,4444 1 TC *+2 ; +0,04443 4443 0 2,4445 0 TC *+2 ; <0,04444 4444 0 2,4447 1 TC *+3 ; -0, 04445 4445 3 0,0571 1 XCH PASTE_TMP 04446 4446 0 2,4451 0 TC PASTEOPT ; paste please verb for NVMONOPT 04447 4447 3 1,2050 0 CAF ZERO ; was CA MONSAVE in BII04450 4450 6 0,0507 0 AD MONSAVE ; paste monitor verb - paste option is 0 PASTEOPT EQU * 04451 4451 5 0,0020 0 TS CYR ; shift right 7, was TS EDOP, CA EDOP in BII04452 4452 4 0,0020 1 CS CYR 04453 4453 4 0,0020 1 CS CYR 04454 4454 4 0,0020 1 CS CYR 04455 4455 4 0,0020 1 CS CYR 04456 4456 4 0,0020 1 CS CYR 04457 4457 4 0,0020 1 CS CYR 04460 4460 3 0,0020 0 XCH CYR 04461 4461 7 1,2101 1 MASK LOW7 ; place monitor verb or please verb into 04462 4462 0 1,3565 1 TC BANKCALL ; VERBREG and display it.04463 4463 14326 0 CADR UPDATVB-1
04464 4464 3 1,2050 0 CAF ZERO ; zero REQRET so that pasted verbs can04465 4465 5 0,0502 0 TS REQRET ; be executed by operator. 04466 4466 3 1,2050 0 CAF ZERO 04467 4467 6 0,0511 1 AD MONSAVE2 ; was CA MONSAVE2 in BII04470 4470 0 2,4565 0 TC BLANKSUB ; process NVMONOPT blank option if any (p.368)04471 4471 0 2,4472 1 TC *+1 04472 4472 0 1,2723 0 ENDPASTE TC ENDOFJOB 04473 4473 37600 0 MID7 DS %37600 BANKFF_2 EQU * ORG BANK41_4 INCL bank41_4.asm ; COLOSSUS pp. 352 ;========================================================================== ; DISPLAY ROUTINES (file:bank41_4.asm) ; ; Adapted from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, pp. 352. ;========================================================================== ;-------------------------------------------------------------------------- ; DSPFMEM -- DISPLAY FIXED MEMORY ; Used to display (in octal) any fixed register. It is used with NOUN = ; machine CADR to be specified. The FCADR of the desired location is then ; punched in. It handles F/F (FCADR 4000-7777) ; ; Adapted from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, p.352. ;-------------------------------------------------------------------------- DSPFMEM EQU * 15301 6,1301 3 2,4635 0 CAF R1D1 ; If F/F, DATACALL uses bank 02 or 0315302 6,1302 5 0,0466 0 TS DSPCOUNT 15303 6,1303 3 1,2050 0 CAF ZERO ; was CA NOUNCADR, TC SUPDACAL in Block II15304 6,1304 6 0,0506 1 AD NOUNCADR ; original FCADR loaded still in NOUNCADR15305 6,1305 0 1,3742 0 TC DATACALL ; call with FCADR in A 15306 6,1306 0 6,7310 1 TC DSPOCTWD 15307 6,1307 0 1,2723 0 ENDSPF TC ENDOFJOB BANK41_5 EQU * ORG BANK40_5 ; COLOSSUS pp. 353-355 INCL bank40_5.asm ;========================================================================== ; WORD DISPLAY ROUTINES (file:bank40_5.asm) ; ; Adapted from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, pp. 353-355. ;========================================================================== DSPSIGN EQU * 13031 5,1031 3 0,0001 0 XCH Q 13032 5,1032 5 0,0441 0 TS DSPWDRET 13033 5,1033 1 0,0130 1 CCS MPAC 13034 5,1034 0 5,7044 0 TC *+8 ; >0, positive sign13035 5,1035 0 5,7044 0 TC *+7 ; +0, positive sign 13036 5,1036 6 1,2051 1 AD ONE 13037 5,1037 5 0,0130 0 TS MPAC 13040 5,1040 0 5,6353 1 TC M_ON ; display minus sign13041 5,1041 4 0,0131 0 CS MPAC+1 13042 5,1042 5 0,0131 1 TS MPAC+1 13043 5,1043 0 0,0441 0 TC DSPWDRET 13044 5,1044 0 5,6332 0 TC P_ON ; display plus sign 13045 5,1045 0 0,0441 0 TC DSPWDRET ; return ;-------------------------------------------------------------------------- ; DSPRND ; Round up decimal fraction by 5 EXP -6. This was entirely coded in ; Block II instructions, so I translated it to the functional ; equivalent in Block I code. ; ; Adapted from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, p.353. ;-------------------------------------------------------------------------- DSPRND EQU * 13046 5,1046 3 5,7117 1 CAF DECROUND 13047 5,1047 6 0,0131 1 AD MPAC+1
13050 5,1050 5 0,0131 1 TS MPAC+1 ; skip on overflow13051 5,1051 3 1,2050 0 CAF ZERO ; otherwise, make interword carry=013052 5,1052 6 0,0130 0 AD MPAC 13053 5,1053 5 0,0130 0 TS MPAC ; skip on overflow13054 5,1054 0 0,0001 0 TC Q ; return 13055 5,1055 3 5,7063 0 CAF DPOSMAX+1 ; number overflows, so set to max13056 5,1056 5 0,0131 1 TS MPAC+1 13057 5,1057 3 5,7062 1 CAF DPOSMAX 13060 5,1060 5 0,0130 0 TS MPAC 13061 5,1061 0 0,0001 0 TC Q ; return DPOSMAX EQU * ; max positive decimal fraction13062 5,1062 37777 1 DS %37777 13063 5,1063 34000 0 DS %34000 ;-------------------------------------------------------------------------- ; DSPDECTWD -- DISPLAY DECIMAL WORD ; Converts C(MPAC, MPAC+1) into a sign and 5 char decimal starting in loc ; specified in DSPCOUNT. it rounds by 5 exp 6. ; ; Adapted from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, p.353. ;-------------------------------------------------------------------------- DSPDECWD EQU * 13064 5,1064 3 0,0001 0 XCH Q 13065 5,1065 5 0,0412 0 TS WDRET 13066 5,1066 0 5,7031 1 TC DSPSIGN 13067 5,1067 0 5,7046 1 TC DSPRND 13070 5,1070 3 1,2054 1 CAF FOUR DSPDCWD1 EQU * 13071 5,1071 5 0,0434 1 TS WDCNT 13072 5,1072 3 2,4700 1 CAF BINCON 13073 5,1073 0 2,4353 0 TC SHORTMP TRACE1 EQU * 13074 5,1074 2 0,0130 1 INDEX MPAC 13075 5,1075 3 1,3772 0 CAF RELTAB 13076 5,1076 7 2,4664 0 MASK LOW5 13077 5,1077 5 0,0421 0 TS CODE 13100 5,1100 3 1,2050 0 CAF ZERO 13101 5,1101 3 0,0132 1 XCH MPAC+2 13102 5,1102 3 0,0131 1 XCH MPAC+1 13103 5,1103 5 0,0130 0 TS MPAC 13104 5,1104 3 0,0466 0 XCH DSPCOUNT TRACE1S EQU * 13105 5,1105 5 0,0440 1 TS COUNT 13106 5,1106 1 0,0000 0 CCS A ; decrement DSPCOUNT except at +013107 5,1107 5 0,0466 0 TS DSPCOUNT 13110 5,1110 0 5,7161 0 TC DSPIN 13111 5,1111 1 0,0434 0 CCS WDCNT 13112 5,1112 0 5,7071 0 TC DSPDCWD1 ; >0, not done yet 13113 5,1113 4 2,4675 0 CS VD1 ; +013114 5,1114 5 0,0466 0 TS DSPCOUNT 13115 5,1115 0 0,0412 0 TC WDRET ; return 13116 5,1116 00000 1 DS %00000 13117 5,1117 02476 0 DECROUND DS %02476 ;-------------------------------------------------------------------------- ; DSPDECNR ; Converts C(MPAC, MPAC+1) into a sign and 5 char decimal starting in loc ; specified in DSPCOUNT. It does not round. ; ; Adapted from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, p.354. ;-------------------------------------------------------------------------- DSPDECNR EQU * 13120 5,1120 3 0,0001 0 XCH Q 13121 5,1121 5 0,0412 0 TS WDRET 13122 5,1122 0 5,7031 1 TC DSPSIGN 13123 5,1123 0 5,7070 1 TC DSPDCWD1-1 ;-------------------------------------------------------------------------- ; DSPDC2NR ; Converts C(MPAC, MPAC+1) into a sign and 2 char decimal starting in loc ; specified by DSPCOUNT. It does not round. ;
; Adapted from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, p.354. ;-------------------------------------------------------------------------- DSPDC2NR EQU * 13124 5,1124 3 0,0001 0 XCH Q 13125 5,1125 5 0,0412 0 TS WDRET 13126 5,1126 0 5,7031 1 TC DSPSIGN 13127 5,1127 3 1,2051 1 CAF ONE 13130 5,1130 0 5,7071 0 TC DSPDCWD1 ;-------------------------------------------------------------------------- ; DSP2DEC ; Converts C(MPAC) and C(MPAC+1) into a sign and 10 char decimal starting ; in the loc specified in DSPCOUNT. ; ; Adapted from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, p.354. ;-------------------------------------------------------------------------- DSP2DEC EQU * 13131 5,1131 3 0,0001 0 XCH Q 13132 5,1132 5 0,0412 0 TS WDRET 13133 5,1133 3 1,2050 0 CAF ZERO 13134 5,1134 5 0,0421 0 TS CODE 13135 5,1135 3 1,2053 0 CAF THREE 13136 5,1136 0 5,7253 1 TC _11DSPIN ; -R2 off13137 5,1137 3 1,2054 1 CAF FOUR 13140 5,1140 0 5,7253 1 TC _11DSPIN ; +R2 off13141 5,1141 0 5,7031 1 TC DSPSIGN 13142 5,1142 3 2,4636 0 CAF R2D1 13143 5,1143 0 5,7071 0 END2DEC TC DSPDCWD1 ;-------------------------------------------------------------------------- ; DSPDECVN ; Displays C(A) upon entry as a 2 char decimal beginning in the ; loc specified in DSPCOUNT. ; C(A) should be in form N x 2EXP-14. This is scaled to form N/100 before ; display conversion. ; ; Adapted from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, p.353. ;-------------------------------------------------------------------------- DSPDECVN EQU * 13144 5,1144 2 0,0000 1 EXTEND 13145 5,1145 4 5,7155 0 MP VNDSPCON ; mult by .01 13146 5,1146 3 0,0003 1 XCH LP ; was LXCH MPAC in Block II13147 5,1147 5 0,0130 0 TS MPAC ; take results from LP (mult by 2EXP14) 13150 5,1150 3 1,2050 0 CAF ZERO 13151 5,1151 5 0,0131 1 TS MPAC+1 13152 5,1152 3 0,0001 0 XCH Q 13153 5,1153 5 0,0412 0 TS WDRET 13154 5,1154 0 5,7127 1 TC DSPDC2NR+3 ; no sign, no round, 2 char 13155 5,1155 00244 0 VNDSPCON DS %00244 ; .01 rounded up GOVNUPDT EQU * 13156 5,1156 0 5,7144 1 TC DSPDECVN ; this is not for general use. Really part13157 5,1157 0 1,3653 1 TC POSTJUMP ; of UPDATVB13160 5,1160 14337 0 DS UPDAT1+2 BANK40_6 EQU * ORG BANK41_5 ; COLOSSUS pp. 355-356 INCL bank41_5.asm ;========================================================================== ; DISPLAY ROUTINES (file:bank41_5.asm) ; ; Adapted from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, pp. 355-356. ;========================================================================== ;-------------------------------------------------------------------------- ; DSPOCTWD -- DISPLAY OCTAL WORD ; Displays C(A) upon entry as a 5 char octal starting in the DSP char ; specified in DSPCOUNT. It stops after 5 char have been displayed. ; ; ; DSP2BIT -- DISPLAY 2 OCTAL CHARS ; Displays C(A) upon entry as a 2 char oct beginning in the DSP ; loc specified in DSPCOUNT by pre-cycling right C(A) and using ; the logic of the 5 char octal display. ;
; Adapted from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, p.355/356. ;-------------------------------------------------------------------------- DSPOCTWD EQU * 15310 6,1310 5 0,0022 1 TS CYL 15311 6,1311 3 0,0001 0 XCH Q 15312 6,1312 5 0,0412 0 TS WDRET ; must use the same return as DSP2BIT 15313 6,1313 3 1,2063 0 CAF BIT14 ; to blank signs15314 6,1314 6 0,0466 0 AD DSPCOUNT ; was ADS DSPCOUNT in block II15315 6,1315 5 0,0466 0 TS DSPCOUNT 15316 6,1316 3 1,2054 1 CAF FOUR WDAGAIN EQU * 15317 6,1317 5 0,0434 1 TS WDCNT 15320 6,1320 4 0,0022 0 CS CYL 15321 6,1321 4 0,0022 0 CS CYL 15322 6,1322 4 0,0022 0 CS CYL 15323 6,1323 4 0,0000 0 CS A 15324 6,1324 7 1,2057 0 MASK DSPMSK 15325 6,1325 2 0,0000 0 INDEX A 15326 6,1326 3 1,3772 0 CAF RELTAB 15327 6,1327 7 2,4664 0 MASK LOW5 15330 6,1330 5 0,0421 0 TS CODE 15331 6,1331 3 0,0466 0 XCH DSPCOUNT 15332 6,1332 5 0,0440 1 TS COUNT 15333 6,1333 1 0,0000 0 CCS A ; decrement DSPCOUNT except at +015334 6,1334 5 0,0466 0 TS DSPCOUNT ; > 015335 6,1335 0 1,3653 1 TC POSTJUMP ; + 015336 6,1336 13261 0 DS DSPOCTIN OCTBACK EQU * 15337 6,1337 1 0,0434 0 CCS WDCNT 15340 6,1340 0 6,7317 0 TC WDAGAIN DSPLW EQU * 15341 6,1341 4 2,4675 0 CS VD1 ; to block numerical characters, clears15342 6,1342 5 0,0466 0 TS DSPCOUNT 15343 6,1343 0 0,0412 0 TC WDRET ; * return DSPMSK EQU SEVEN DSP2BIT EQU * 15344 6,1344 5 0,0020 0 TS CYR 15345 6,1345 3 0,0001 0 XCH Q 15346 6,1346 5 0,0412 0 TS WDRET 15347 6,1347 3 1,2051 1 CAF ONE 15350 6,1350 5 0,0434 1 TS WDCNT 15351 6,1351 4 0,0020 1 CS CYR 15352 6,1352 4 0,0020 1 CS CYR 15353 6,1353 3 0,0020 0 XCH CYR 15354 6,1354 5 0,0022 1 TS CYL 15355 6,1355 0 6,7324 0 TC WDAGAIN+5 BANK41_6 EQU * ORG BANK40_6 ; COLOSSUS pp. 356-358 INCL bank40_6.asm ;========================================================================== ; DISPLAY ROUTINES (file:bank40_6.asm) ; ; Adapted from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, pp. 356-358. ;========================================================================== ;-------------------------------------------------------------------------- ; DSPIN -- DISPLAY RELAY CODE ; ; For DSPIN, place 0-25 oct into COUNT to select the character (same as DSPCOUNT), ; 5 bit relay code into CODE. Both are destroyed. If bit 14 of COUNT is 1, sign is ; blanked with left char. ; For DSPIN11, place 0,1 into CODE, 2 into COUNT, rel address of DSPTAB entry ; into DSREL. ; ; Adapted from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, p.356. ;-------------------------------------------------------------------------- DSPIN EQU * 13161 5,1161 3 0,0001 0 XCH Q ; cant use L for RETURN, since many of the13162 5,1162 5 0,0411 0 TS DSEXIT ; routines calling DSPIN use L as RETURN
; Set DSREL to index into DSPTAB; the index corresponds to the display character ; referenced by COUNT (which is derived from DSPCOUNT) 13163 5,1163 3 2,4664 1 CAF LOW5 13164 5,1164 7 0,0440 0 MASK COUNT 13165 5,1165 5 0,0021 1 TS SR ; divides by 213166 5,1166 3 0,0021 1 XCH SR 13167 5,1167 5 0,0436 0 TS DSREL ; Check COUNT (derived from DSPCOUNT) to find whether the character to be ; displayed is in the right (Bits 5-1) or left (Bits 10-6) bits of the ; DSPTAB word. 13170 5,1170 3 1,2100 1 CAF BIT1 13171 5,1171 7 0,0440 0 MASK COUNT 13172 5,1172 1 0,0000 0 CCS A 13173 5,1173 0 5,7175 0 TC *+2 ; >0, left if COUNT is odd13174 5,1174 0 5,7205 1 TC DSPIN1-1 ; +0, right if COUNT is even ; Character to be displayed should be in the left bits (Bit 10-6), so ; shift it left into bits 10-6. 13175 5,1175 3 0,0421 0 XCH CODE 13176 5,1176 0 2,4656 0 TC SLEFT5 ; does not use CYL13177 5,1177 5 0,0421 0 TS CODE ; Set COUNT as an enumerated type; tells how to mask the new character ; into the relay word. ; 0 = mask new character into right side of relayword (bits 5-1) ; 1 = mask into left side (bits 10-6) and leave old sign (bit 11) alone. ; 2 = mask into left side (bits 10-6) and blank sign bit (bit 11) 13200 5,1200 3 1,2063 0 CAF BIT14 13201 5,1201 7 0,0440 0 MASK COUNT 13202 5,1202 1 0,0000 0 CCS A 13203 5,1203 3 1,2052 1 CAF TWO ; >0, BIT14 = 1, blank sign13204 5,1204 6 1,2051 1 AD ONE ; +0, BIT14 = 0, leave sign alone 13205 5,1205 5 0,0440 1 TS COUNT ; New display character in CODE has been bit-shifted into the correct (left ; or right) bit position. All other bits are zeroed. DSPIN1 EQU * 13206 5,1206 2 0,0000 0 INHINT ; Get the existing display word from DSPTAB. Words that have already been ; displayed will be positive; words yet to be displayed will be negative. ; Use CCS to load the absolute value of the display word. Since CCS decrements ; it, we need to add 1 to restore the value. 13207 5,1207 2 0,0436 1 INDEX DSREL 13210 5,1210 1 0,0512 0 CCS DSPTAB 13211 5,1211 0 5,7213 0 TC *+2 ; >0, old word already displayed13212 5,1212 0 5,7245 0 TC DSLV ; +0, illegal DSPCOUNT (was TC CCSHOLE)13213 5,1213 6 1,2051 1 AD ONE ; <0, old word not displayed yet 13214 5,1214 5 0,0437 1 TS DSMAG ; store the old relay word ; Now, mask off the portion of the old relay word corresponding to the ; new character. Subtract the new character from the old to see whether ; they are the same. 13215 5,1215 2 0,0440 0 INDEX COUNT 13216 5,1216 7 5,7247 0 MASK DSMSK ; mask with 00037, 01740, 02000, or 0374013217 5,1217 2 0,0000 1 EXTEND 13220 5,1220 6 0,0421 0 SU CODE ; Old code same as new code? If so, we don't need to redisplay it. 13221 5,1221 1 0,0000 0 CCS A ; was BZF DSLV in Block II13222 5,1222 0 5,7226 0 TC DFRNT ; >013223 5,1223 0 5,7245 0 TC DSLV ; +0, same, so return13224 5,1224 0 5,7226 0 TC DFRNT ; <013225 5,1225 0 5,7245 0 TC DSLV ; -0, same, so return ; New code is different. DFRNT EQU * ; different13226 5,1226 2 0,0440 0 INDEX COUNT 13227 5,1227 4 5,7247 0 CS DSMSK ; mask with 77740, 76037, 75777, or 7403713230 5,1230 7 0,0437 0 MASK DSMAG 13231 5,1231 6 0,0421 0 AD CODE ; Store new DSPTAB word and get the old (previous) word. If the old word is ; negative, it had not been displayed yet, so NOUT (the count of undisplayed
; words) has already been incremented for this DSPTAB word. If the old word ; is positive, it has already been displayed, so we need to increment NOUT ; to tell DSPOUT to display the new word. 13232 5,1232 4 0,0000 0 CS A 13233 5,1233 2 0,0436 1 INDEX DSREL 13234 5,1234 3 0,0512 1 XCH DSPTAB 13235 5,1235 1 0,0000 0 CCS A ; was BZMF DSLV in Block II13236 5,1236 0 5,7242 1 TC *+4 ; >013237 5,1237 0 5,7241 1 TC *+2 ; +0, DSPTAB entry was -13240 5,1240 0 5,7241 1 TC *+1 ; <0, DSPTAB entry was -13241 5,1241 0 5,7245 0 TC DSLV ; -0, DSPTAB entry was - 13242 5,1242 3 0,0505 1 XCH NOUT ; DSPTAB entry was + (was INCR NOUT in BlockII)13243 5,1243 6 1,2051 1 AD ONE 13244 5,1244 5 0,0505 1 TS NOUT 13245 5,1245 2 0,0000 1 DSLV RELINT 13246 5,1246 0 0,0411 0 TC DSEXIT ; return DSMSK EQU * 13247 5,1247 00037 0 DS %00037 ; COUNT=013250 5,1250 01740 0 DS %01740 ; COUNT=113251 5,1251 02000 0 DS %02000 ; COUNT=213252 5,1252 03740 1 DS %03740 ; COUNT=3 ; For 11DSPIN, put rel address of DSPTAB entry into A, 1 in BIT11 or 0 in ; BIT11 of CODE. I changed the name to _11DSPIN because my assembler doesn't ; like labels that start with a digit. _11DSPIN EQU * 13253 5,1253 5 0,0436 0 TS DSREL 13254 5,1254 3 1,2052 1 CAF TWO 13255 5,1255 5 0,0440 1 TS COUNT 13256 5,1256 3 0,0001 0 XCH Q ; must use same return as DSPIN13257 5,1257 5 0,0411 0 TS DSEXIT 13260 5,1260 0 5,7206 1 TC DSPIN1 DSPOCTIN EQU * 13261 5,1261 0 5,7161 0 TC DSPIN ; so DSPOCTWD doesn't use SWCALL13262 5,1262 3 5,7264 0 CAF *+2 13263 5,1263 0 1,3712 0 TC BANKJUMP 13264 5,1264 15337 1 ENDSPOCT DS OCTBACK ; DSPALARM finds TC NVSUBEND in ENTRET for NVSUB initiated routines. ; Abort with 01501. ; DSPALARM finds TC ENDOFJOB in ENTRET for keyboard initiated routines. ; do TC ENTRET. PREDSPAL EQU * 13265 5,1265 4 2,4675 0 CS VD1 13266 5,1266 5 0,0466 0 TS DSPCOUNT DSPALARM EQU * 13267 5,1267 4 5,7314 1 CS NVSBENDL 13270 5,1270 6 0,0433 0 AD ENTEXIT 13271 5,1271 1 0,0000 0 CCS A ; was BZF CHARALRM+2 in Block II13272 5,1272 0 5,7276 0 TC *+4 ; >013273 5,1273 0 5,7275 0 TC *+2 ; +013274 5,1274 0 5,7276 0 TC *+2 ; <013275 5,1275 0 5,7311 0 TC CHARALRM+2 ; -0 13276 5,1276 4 5,7313 0 CS MONADR ; if this is a monitor, kill it13277 5,1277 6 0,0433 0 AD ENTEXIT 13300 5,1300 1 0,0000 0 CCS A ; was BZF *+2 in Block II13301 5,1301 0 5,7305 0 TC *+4 ; >013302 5,1302 0 5,7304 1 TC *+2 ; +013303 5,1303 0 5,7305 0 TC *+2 ; <013304 5,1304 0 5,7306 0 TC *+2 ; -0 13305 5,1305 0 5,7307 1 TC *+2 13306 5,1306 0 2,4536 0 TC KILMONON CHARALRM EQU * 13307 5,1307 0 2,4701 0 TC FALTON ; not NVSUB initiated, turn on OPR error13310 5,1310 0 1,2723 0 TC ENDOFJOB 13311 5,1311 0 2,5050 1 TC POODOO 13312 5,1312 01501 1 DS %01501 13313 5,1313 04435 1 MONADR DS PASTEVB 13314 5,1314 0 2,4532 1 NVSBENDL TC NVSUBEND
BANK40_7 EQU * ORG BANKFF_2 ; COLOSSUS pp. 358 INCL bankff_2.asm ;========================================================================== ; DISPLAY ROUTINES (file:bankff_2.asm) ; ; Adapted from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, pp. 358. ;========================================================================== ;-------------------------------------------------------------------------- ; ALMCYCLE ; Turns on check fail light, redisplays the original verb that was executed, ; and recycles to execute the original verb/noun combination that was last ; executed. Used for bad data during load verbs and by MCTBS. Also by MMCHANG ; if 2 numerical chars were not punched in for MM code. ; ; Adapted from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, p.358. ;-------------------------------------------------------------------------- ALMCYCLE EQU * 04474 4474 0 2,4701 0 TC FALTON ; turn on check fail light04475 4475 4 0,0530 0 CS VERBSAVE ; get original verb that was executed04476 4476 5 0,0502 0 TS REQRET ; set for ENTPAS004477 4477 0 1,3565 1 TC BANKCALL ; puts original verb into VERBREG and04500 4500 14326 0 DS UPDATVB-1 ; displays it in verb lights04501 4501 0 1,3653 1 TC POSTJUMP 04502 4502 14002 0 ENDALM DS ENTER BANKFF_3 EQU * ORG BANK41_6 ; COLOSSUS pp. 359-360 INCL bank41_6.asm ;========================================================================== ; DISPLAY ROUTINES (file:bank41_6.asm) ; ; Adapted from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, pp. 359-360. ;========================================================================== ;-------------------------------------------------------------------------- ; MMCHANG -- MAJOR MODE CHANGE ; Uses noun display until ENTER; then it uses MODE display. It goes to ; MODROUT with the new MM code in A, but not displayed in MM lights. ; It demands 2 numerical characters be punched in for new MM code. ; ; Adapted from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, p.359. ;-------------------------------------------------------------------------- MMCHANG EQU * 15356 6,1356 0 6,7404 0 TC REQMM ; ENTPASHI assumes the TC GRQMM at MMCHANG ; if this moves at all, must change ; MMADREF at ENTPASHI15357 6,1357 3 1,2074 0 CAF BIT5 ; OCT 20 = ND215360 6,1360 6 0,0466 0 AD DSPCOUNT ; DSPCOUNT must = -ND2 15361 6,1361 1 0,0000 0 CCS A ; was BZF *+2 in Block II15362 6,1362 0 6,7366 0 TC *+4 ; >015363 6,1363 0 6,7365 0 TC *+2 ; +015364 6,1364 0 6,7366 0 TC *+2 ; <015365 6,1365 0 6,7367 1 TC *+2 ; -0 15366 6,1366 0 2,4474 1 TC ALMCYCLE ; DSPCOUNT not -ND2. Alarm and recycle. 15367 6,1367 3 1,2050 0 CAF ZERO 15370 6,1370 3 0,0471 0 XCH NOUNREG 15371 6,1371 5 0,0130 0 TS MPAC 15372 6,1372 3 2,4676 1 CAF ND1 15373 6,1373 5 0,0466 0 TS DSPCOUNT 15374 6,1374 0 1,3565 1 TC BANKCALL 15375 6,1375 12540 0 DS _2BLANK 15376 6,1376 4 2,4675 0 CS VD1 ; block num char in15377 6,1377 5 0,0466 0 TS DSPCOUNT 15400 6,1400 3 1,2050 0 CAF ZERO ; was CA MPAC in Block II15401 6,1401 6 0,0130 0 AD MPAC 15402 6,1402 0 1,3653 1 TC POSTJUMP 15403 6,1403 10000 0 DS MODROUTR ; go thru standard loc. MODROUTR EQU V37
REQMM EQU * 15404 6,1404 4 0,0001 1 CS Q 15405 6,1405 5 0,0502 0 TS REQRET 15406 6,1406 3 2,4676 1 CAF ND1 15407 6,1407 5 0,0466 0 TS DSPCOUNT 15410 6,1410 3 1,2050 0 CAF ZERO 15411 6,1411 5 0,0471 0 TS NOUNREG 15412 6,1412 0 1,3565 1 TC BANKCALL 15413 6,1413 12540 0 DS _2BLANK 15414 6,1414 0 2,4760 1 TC FLASHON 15415 6,1415 3 1,2051 1 CAF ONE 15416 6,1416 5 0,0467 1 TS DECBRNCH ; set for dec15417 6,1417 0 0,0433 0 TC ENTEXIT ;-------------------------------------------------------------------------- ; VBRQEXEC -- REQUEST EXECUTIVE ; ; Enters request to EXEC for any address with any priority. It does ENDOFJOB ; after entering request. Display syst is released. It assumes NOUN 26 has been ; preloaded with: ; COMPONENT 1 -- priority (bits 10-14), bit1=0 for NOVAC, bit1=1 for FINDVAC ; COMPONENT 2 -- job CADR (14 bit; was 12 bit in Block II) ; COMPONENT 3 -- not used (was BBCON in Block II) ; ; Adapted from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, p.360. ;-------------------------------------------------------------------------- VBRQEXEC EQU * 15420 6,1420 3 1,2100 1 CAF BIT1 15421 6,1421 7 0,0534 1 MASK DSPTEM1 15422 6,1422 1 0,0000 0 CCS A 15423 6,1423 0 6,7444 1 TC SETVAC ; if bit1=1, FINDVAC15424 6,1424 3 2,4667 1 CAF TCNOVAC ; if bit1=0, NOVAC ; sets up to call NOVAC or FINDVAC thru MPAC as follows: ; MPAC = TC NOVAC ; MPAC+1 = job CADR ; MPAC+2 = TC ENDOFJOB ; MPAC+3 = temp store for job PRIO REQEX1 EQU * 15425 6,1425 5 0,0130 0 TS MPAC ; TC NOVAC or TC FINDVAC into MPAC15426 6,1426 4 1,2100 0 CS BIT1 15427 6,1427 7 0,0534 1 MASK DSPTEM1 15430 6,1430 5 0,0133 0 TS MPAC+3 ; PRIO into MPAC+3 as a temp (was +4) REQUESTC EQU * 15431 6,1431 0 2,5003 1 TC RELDSP 15432 6,1432 3 1,2050 0 CAF ZERO ; was CA ENDINST in Block II15433 6,1433 6 2,4553 0 AD ENDINST 15434 6,1434 5 0,0132 1 TS MPAC+2 ; TC ENDOFJOB into MPAC+2 (was +3) 15435 6,1435 3 1,2050 0 CAF ZERO ; set BBCON for Block II dropped15436 6,1436 6 0,0535 1 AD DSPTEM1+1 ; job adres into MPAC+115437 6,1437 5 0,0131 1 TS MPAC+1 15440 6,1440 3 1,2050 0 CAF ZERO ; was CA MPAC+4 in Block II15441 6,1441 6 0,0133 0 AD MPAC+3 ; PRIO in A15442 6,1442 2 0,0000 0 INHINT 15443 6,1443 0 0,0130 0 TC MPAC SETVAC EQU * 15444 6,1444 3 2,4671 0 CAF TCFINDVAC 15445 6,1445 0 6,7425 0 TC REQEX1 ;-------------------------------------------------------------------------- ; VBRQWAIT -- REQUEST WAITLIST ; ; Enters request to WAITLIST for any address with any delay. It does ENDOFJOB ; after entering request. Display syst is released. It assumes NOUN 26 has been ; preloaded with: ; COMPONENT 1 -- delay (low bits) ; COMPONENT 2 -- task CADR (14 bit; was 12 bit in Block II) ; COMPONENT 3 -- not used (was BBCON in Block II) ; ; Adapted from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, p.360. ;-------------------------------------------------------------------------- VBRQWAIT EQU * 15446 6,1446 3 2,4670 1 CAF TCWAIT 15447 6,1447 5 0,0130 0 TS MPAC ; TC WAITLIST into MPAC
15450 6,1450 3 1,2050 0 CAF ZERO ; was CA DSPTEM1 in Block II15451 6,1451 6 0,0534 0 AD DSPTEM1 ; time delay15452 6,1452 0 6,7430 1 ENDRQWT TC REQUESTC-1 ; REQUESTC will put task address in MPAC+1, TC ENDOFJOB in MPAC+2. ; It will take the time delay out of MPAC+3 and leave it in A, INHINT ; and TC MPAC. BANK41_7 EQU * ORG BANK40_7 ; COLOSSUS pp. 360-362 INCL bank40_7.asm ;========================================================================== ; DISPLAY ROUTINES (file:bank40_7.asm) ; ; Adapted from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, pp. 360-362. ;========================================================================== ;-------------------------------------------------------------------------- ; VBPROC -- PROCEED WITHOUT DATA ; VBTERM -- TERMINATE ; ; Adapted from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, p.360. ;-------------------------------------------------------------------------- VBPROC EQU * 13315 5,1315 3 1,2051 1 CAF ONE ; proceed without data13316 5,1316 5 0,0503 1 TS LOADSTAT 13317 5,1317 0 2,4536 0 TC KILMONON ; turn on kill monitor bit13320 5,1320 0 2,5003 1 TC RELDSP 13321 5,1321 0 2,4770 0 TC FLASHOFF 13322 5,1322 0 5,7413 0 TC RECALTST ; see if there is any recall from endidle VBTERM EQU * 13323 5,1323 4 1,2051 0 CS ONE 13324 5,1324 0 5,7316 1 TC VBPROC+1 ; term verb sets loadstat neg ;-------------------------------------------------------------------------- ; VBRESEQ ; Wakes ENDIDLE at same line as final enter of load (L+3). Main use is ; intended as response to internally initiated flashing displays in ENDIDLE. ; Should not be used with load verbs, please perform, or please mark verbs ; because they already use L+3 in another context. ; ; Adapted from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, p.361. ;-------------------------------------------------------------------------- VBRESEQ EQU * 13325 5,1325 4 1,2050 1 CS ZERO ; make it look like data in.13326 5,1326 0 5,7316 1 TC VBPROC+1 ; flash is turned off by proceed without data, terminate, ; resequence, end of load. ;-------------------------------------------------------------------------- ; VBRELDSP ; This routine always turns off the UPACT light and always clears ; DSPLOCK. ; ; Adapted from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, p.362. ;-------------------------------------------------------------------------- VBRELDSP EQU * ; some code here to turn off the UPACT light is omitted 13327 5,1327 1 0,0412 1 CCS _2122REG ; old DSPLOCK13330 5,1330 3 1,2063 0 CAF BIT14 13331 5,1331 7 0,0510 1 MASK MONSAVE1 ; external monitor bit (EMB)13332 5,1332 1 0,0000 0 CCS A 13333 5,1333 0 5,7342 0 TC UNSUSPEN ; old DSPLOCK and EMB both 1, unsuspend 13334 5,1334 0 2,5003 1 TSTLTS4 TC RELDSP ; not unsuspending external monitor,13335 5,1335 1 0,0531 1 CCS CADRSTOR ; release display system and13336 5,1336 0 5,7340 1 TC *+2 ; do reestablish if CADRSTOR is full13337 5,1337 0 1,2723 0 TC ENDOFJOB 13340 5,1340 0 1,3653 1 TC POSTJUMP 13341 5,1341 05067 0 CADR PINBRNCH UNSUSPEN EQU * 13342 5,1342 3 1,2050 0 CAF ZERO ; external monitor is suspended13343 5,1343 5 0,0501 0 TS DSPLOCK ; just unsuspend it by clearing DSPLOCK
13344 5,1344 1 0,0531 1 CCS CADRSTOR ; turn key release light off if both13345 5,1345 0 1,2723 0 TC ENDOFJOB ; CADRSTOR and DSPLIST are empty13346 5,1346 0 2,5026 0 TC RELDSP1 13347 5,1347 0 1,2723 0 TC ENDOFJOB BANK40_8 EQU * ORG BANKFF_3 ; COLOSSUS pp. 363-364 INCL bankff_3.asm ;========================================================================== ; DISPLAY ROUTINES (file:bankff_3.asm) ; ; Adapted from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, pp. 363-364. ;========================================================================== ; COLOSSUS p. 364 - comments are taken from the Block I flow charts with some ; additional annotations by me. NVSUB EQU * 04503 4503 5 0,0565 1 TS NVSUB_A ; more gymnastics for Block II conversion 04504 4504 3 1,2050 0 CAF ZERO ; was LXCH 7 in Block II04505 4505 5 0,0564 0 TS NVSUB_L ; zero NVMONOPT options ; save C(A). C(A) should be holding the noun/verb code; C(L) should ; be holding NVMONOPT options. In this Block I version, the NVMONOPT ; options should be placed in NVSUB_L before calling NVMONOPT. 04506 4506 3 0,0565 1 XCH NVSUB_A NVMONOPT EQU * 04507 4507 5 0,0420 1 TS NVTEMP ; Test DSPLOCK (+NZ=busy; +0=display system available) ; Display is blocked by DSPLOCK=1 or external monitor bit set (bit 14) 04510 4510 3 1,2063 0 CAF BIT14 04511 4511 7 0,0510 1 MASK MONSAVE1 ; external monitor bit04512 4512 6 0,0501 0 AD DSPLOCK 04513 4513 1 0,0000 0 CCS A 04514 4514 0 0,0001 0 TC Q ; dsp syst blocked, ret to 1, calling loc ; Store calling line +2 in NVQTEM 04515 4515 3 1,2051 1 CAF ONE ; dsp syst available04516 4516 6 0,0001 0 NVSBCOM AD Q 04517 4517 5 0,0526 0 TS NVQTEM ; 2+calling loc into NVQTEM ; Force bit 15 of MONSAVE to 1, turn off bit 14. 04520 4520 3 0,0564 0 XCH NVSUB_L ; was LXCH MONSAVE2 in Block II04521 4521 3 0,0511 1 XCH MONSAVE2 ; store NVMONOPT options04522 4522 5 0,0564 0 TS NVSUB_L ; replaces LXCH by working through A instead 04523 4523 0 2,4536 0 TC KILMONON ; turn on kill monitor bit ; Store calling bank in NVBNKTEM ; ** this was changed quite a bit from Block II ** NVSUBCOM EQU * 04524 4524 3 1,2050 0 CAF ZERO 04525 4525 6 0,0015 0 AD BANK 04526 4526 5 0,0527 1 TS NVBNKTEM 04527 4527 0 1,3624 1 TC MYBANKCALL ; go to NVSUB1 thru standard loc04530 4530 14000 1 CADR NVSUBR 04531 4531 15505 0 NVSRRBNK CADR NVSUB1 ; ****** WHAT'S THIS FOR?? ******** ; Restore calling bank and TC NVQTEM ; ** this was changed quite a bit from Block II ** NVSUBEND EQU * 04532 4532 3 1,2050 0 CAF ZERO 04533 4533 6 0,0527 1 AD NVBNKTEM 04534 4534 5 0,0015 0 TS BANK ; restore calling bank04535 4535 0 0,0526 0 TC NVQTEM BANKFF_4 EQU * ORG BANK41_7 ; COLOSSUS pp. 365-366 INCL bank41_7.asm ;==========================================================================
; DISPLAY ROUTINES (file:bank41_7.asm) ; ; Adapted from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, pp. 365-366. ;========================================================================== ; BLANKDSP blanks display according to option number in NVTEMP as follows: ; -4 full blank, -3 leave mode, -2 leave mode and verb, -1 blank R-S only BLANKDSP EQU * 15453 6,1453 6 1,2057 1 AD SEVEN ; 7,8,9,or 10 (A had 0,1,2,or 3)15454 6,1454 2 0,0000 0 INHINT 15455 6,1455 5 0,0421 0 TS CODE ; blank specified DSPTABS15456 6,1456 4 1,2065 1 CS BIT12 15457 6,1457 2 0,0421 1 INDEX CODE 15460 6,1460 3 0,0512 1 XCH DSPTAB 15461 6,1461 1 0,0000 0 CCS A 15462 6,1462 0 6,7501 1 TC INCR_NOUT ; was INCR NOUT in Block II15463 6,1463 0 6,7464 0 INCR_NOUT_RET TC *+1 15464 6,1464 1 0,0421 1 CCS CODE 15465 6,1465 0 6,7455 1 TC BLANKDSP+2 15466 6,1466 2 0,0000 1 RELINT 15467 6,1467 2 0,0420 0 INDEX NVTEMP 15470 6,1470 0 6,7475 0 TC *+5 15471 6,1471 0 6,7472 1 TC *+1 ; NVTEMP has -4 (never touch MODREG)15472 6,1472 5 0,0470 1 TS VERBREG ; -315473 6,1473 5 0,0471 0 TS NOUNREG ; -215474 6,1474 5 0,0504 0 TS CLPASS ; -1 15475 6,1475 4 2,4675 0 CS VD1 15476 6,1476 5 0,0466 0 TS DSPCOUNT 15477 6,1477 0 2,4770 0 TC FLASHOFF ; protect against invisible flash15500 6,1500 0 6,7540 1 TC ENTSET-2 ; zeroes REQRET INCR_NOUT EQU * 15501 6,1501 3 0,0505 1 XCH NOUT ; was INCR NOUT in Block II15502 6,1502 6 1,2051 1 AD ONE ; have to make it a separate routine15503 6,1503 5 0,0505 1 TS NOUT ; because it was nested inside15504 6,1504 0 6,7463 1 TC INCR_NOUT_RET ; a CCS. NVSUB1 EQU * 15505 6,1505 3 6,7542 0 CAF ENTSET ; in bank15506 6,1506 5 0,0433 0 TS ENTRET ; set return to NVSUBEND 15507 6,1507 1 0,0420 0 CCS NVTEMP ; what now15510 6,1510 0 6,7514 0 TC *+4 ; normal NVSUB call (execute VN or paste)15511 6,1511 0 6,6341 1 TC GODSPALM 15512 6,1512 0 6,7453 1 TC BLANKDSP ; blank display as specified15513 6,1513 0 6,6341 1 TC GODSPALM 15514 6,1514 3 1,2101 0 CAF LOW7 15515 6,1515 7 0,0420 0 MASK NVTEMP 15516 6,1516 5 0,0133 0 TS MPAC+3 ; temp for noun (can't use MPAC, DSPDECVN ; uses MPAC, +1, +215517 6,1517 3 1,2050 0 CAF ZERO ; was CA NVTEMP15520 6,1520 6 0,0420 1 AD NVTEMP 15521 6,1521 5 0,0020 0 TS CYR ; shift right 7, was TS EDOP, CA EDOP in BII15522 6,1522 4 0,0020 1 CS CYR 15523 6,1523 4 0,0020 1 CS CYR 15524 6,1524 4 0,0020 1 CS CYR 15525 6,1525 4 0,0020 1 CS CYR 15526 6,1526 4 0,0020 1 CS CYR 15527 6,1527 4 0,0020 1 CS CYR 15530 6,1530 3 0,0020 0 XCH CYR 15531 6,1531 7 1,2101 1 MASK LOW7 15532 6,1532 5 0,0134 1 TS MPAC+4 ; temp for verb (can't use MPAC, DSPDECVN ; uses MPAC, +1, +2 15533 6,1533 1 0,0133 1 CCS MPAC+3 ; test noun (+NZ or +0)15534 6,1534 0 6,7543 1 TC NVSUB2 ; if noun not +0, DC on 15535 6,1535 3 1,2050 0 CAF ZERO ; was CA MPAC+4 in Block II15536 6,1536 6 0,0134 1 AD MPAC+4 15537 6,1537 0 6,6326 0 TC UPDATVB-1 ; if noun = +0, display verb then return 15540 6,1540 3 1,2050 0 CAF ZERO ; zero REQRET so that pasted verbs can15541 6,1541 5 0,0502 0 TS REQRET ; be executed by operator 15542 6,1542 0 2,4532 1 ENTSET TC NVSUBEND
15543 6,1543 1 0,0134 0 NVSUB2 CCS MPAC+4 ; test verb (+NZ or +0)15544 6,1544 0 6,7551 1 TC *+5 ; if verb not +0, go on 15545 6,1545 3 1,2050 0 CAF ZERO ; was CA MPAC+3 in Block II15546 6,1546 6 0,0133 0 AD MPAC+3 15547 6,1547 0 6,6306 1 TC UPDATNN-1 ; if verb = +0, display noun, then return15550 6,1550 0 2,4532 1 TC NVSUBEND 15551 6,1551 3 1,2050 0 CAF ZERO ; was CA MPAC+2 in Block II15552 6,1552 6 0,0132 1 AD MPAC+2 ; temp for mach CADR to be spec, (DSPDECVN15553 6,1553 5 0,0135 0 TS MPAC+5 ; uses MPAC, +1, +2 15554 6,1554 3 1,2050 0 CAF ZERO ; was CA MPAC+4 in Block II15555 6,1555 6 0,0134 1 AD MPAC+4 15556 6,1556 0 6,6326 0 TC UPDATVB-1 ; if both noun and verb not +0, display 15557 6,1557 3 1,2050 0 CAF ZERO ; was CA MPAC+3 in Block II15560 6,1560 6 0,0133 0 AD MPAC+3 ; both and go to ENTPAS015561 6,1561 0 6,6306 1 TC UPDATNN-1 15562 6,1562 3 1,2050 0 CAF ZERO 15563 6,1563 5 0,0503 1 TS LOADSTAT ; set for waiting for data condition15564 6,1564 5 0,0504 0 TS CLPASS 15565 6,1565 5 0,0502 0 TS REQRET ; set request for pass 0 15566 6,1566 3 1,2050 0 CAF ZERO ; was CA MPAC+5 in Block II15567 6,1567 6 0,0135 0 AD MPAC+5 ; restores mach CADR to be spec to MPAC+215570 6,1570 5 0,0132 1 TS MPAC+2 ; for use in INTMCTBS (in ENTPAS0) 15571 6,1571 0 6,6040 0 ENDNVSB1 TC ENTPAS0 ; if internal mach CADR to be specified, MPAC+2 will be placed into ; NOUNCADR in ENTPAS0 (INTMCTBS) BANK41_8 EQU * ORG BANKFF_4 ; COLOSSUS pp. 366-368 INCL bankff_4.asm ;========================================================================== ; DISPLAY ROUTINES (file:bankff_4.asm) ; ; Adapted from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, pp. 366-368. ;========================================================================== KILMONON EQU * ; force bit 15 of MONSAVE1 to 1.04536 4536 3 1,2062 1 CAF BIT15 ; this is the kill monitor bit.04537 4537 5 0,0510 0 TS MONSAVE1 ; turn off bit 14, the external04540 4540 0 0,0001 0 TC Q ; monitor bit. ; COLOSSUS p. 367 ENDIDLE EQU * 04541 4541 3 0,0001 0 XCH Q ; was LXCH Q in Block II04542 4542 5 0,0566 1 TS ENDIDLE_L ; return address into L 04543 4543 0 2,4554 1 TC ISCADR_P0 ; abort if CADRSTOR not= +004544 4544 0 2,4560 0 TC ISLIST_P0 ; abort if DSPLIST not= +0 04545 4545 3 1,2050 0 CAF ZERO ; was CA L in Block II04546 4546 6 0,0566 1 AD ENDIDLE_L ; don't set DSPLOCK to 1 so can use04547 4547 7 2,4674 1 MASK LOW10 ; ENDIDLE with NVSUB initiated monitor.04550 4550 6 0,0015 0 AD BANK ; same strategy for CADR as MAKECADR04551 4551 5 0,0531 0 TS CADRSTOR 04552 4552 0 1,2725 0 TC JOBSLEEP 04553 4553 0 1,2723 0 ENDINST TC ENDOFJOB ISCADR_P0 EQU * 04554 4554 1 0,0531 1 CCS CADRSTOR ; aborts (code 1206 if CADRSTOR not= +004555 4555 0 2,4563 0 TC DSPABORT ; returns if CADRSTOR = +004556 4556 0 0,0001 0 TC Q 04557 4557 0 2,4563 0 TC DSPABORT ISLIST_P0 EQU * 04560 4560 1 0,0532 1 CCS DSPLIST ; aborts (code 1206 if DSPLIST not= +004561 4561 0 2,4563 0 TC DSPABORT ; returns if DSPLIST = +004562 4562 0 0,0001 0 TC Q 04563 4563 0 2,5050 1 DSPABORT TC POODOO 04564 4564 01206 1 DS %1206
; BLANKSUB blanks any combination of R1, R2, R3. Call with blanking code in A. ; BIT1=1 blanks R1, BIT2=1 blanks R2, BIT3=1 blanks R3. Any combination of these ; three bits is accepted. ; ; DSPCOUNT is restored to the state it was in before BLANKSUB was executed. BLANKSUB EQU * 04565 4565 7 1,2057 0 MASK SEVEN 04566 4566 5 0,0420 1 TS NVTEMP ; store blanking code in NVTEMP04567 4567 3 1,2063 0 CAF BIT14 04570 4570 7 0,0510 1 MASK MONSAVE1 ; external monitor bit04571 4571 6 0,0501 0 AD DSPLOCK 04572 4572 1 0,0000 0 CCS A 04573 4573 0 0,0001 0 TC Q ; dsp syst blocked. Return to 1+calling loc04574 4574 3 0,0001 0 XCH Q ; was INCR Q in Block II04575 4575 6 1,2051 1 AD ONE ; set return for 2+calling location04576 4576 5 0,0561 0 TS BLANKSUB_Q ; was TC Q in Block II 04577 4577 1 0,0420 0 CCS NVTEMP 04600 4600 0 2,4602 1 TC *+2 ; was TCF in Block II04601 4601 0 0,0561 0 TC BLANKSUB_Q ; nothing to blank, Return to 2+calling loc ; the return address+2 is now in BLANKSUB_Q. We need to call BLNKSUB1 in ; in "bank 40", so we'll have to save the bank register so that we can ; return to the address in BLANKSUB_Q. The block II code had a bunch of ; tricky stuff involving the both bank bits and superbit. Block I doesn't ; need to worry about that, so we can substitute this simplified code. ; As in the Block II code, the return bank gets saved to BUF and the return ; address+2 gets saved to BUF+1. 04602 4602 3 1,2050 0 CAF ZERO 04603 4603 6 0,0561 0 AD BLANKSUB_Q 04604 4604 3 0,0426 1 XCH BUF+1 ; set return for 2+calling loc 04605 4605 3 1,2050 0 CAF ZERO 04606 4606 6 0,0015 0 AD BANK 04607 4607 3 0,0425 1 XCH BUF ; save return bank 04610 4610 3 2,4612 0 CAF BSUB1ADDR 04611 4611 0 1,3526 0 TC DXCHJUMP ; bank jump to BLNKSUB1 rtne 04612 4612 13350 0 BSUB1ADDR CADR BLNKSUB1 ; this is my attempt to implement the return from BLNKSUB1. In BII, it executes ; as part of the BLNKSUB1 routine: ; DXCH BUF ; TC SUPDXCHZ+1 ; to jump from the BLNKSUB1 bank to the calling bank. BS_SUPDXCHZ EQU * 04613 4613 3 0,0425 1 XCH BUF 04614 4614 3 0,0015 0 XCH BANK ; restore the calling bank bits04615 4615 0 0,0426 1 TC BUF+1 ; return to calling loc+2 (set in BLANKSUB) BANKFF_5 EQU * ORG BANK04_2 ; COLOSSUS pp. 369 INCL bank04_2.asm ;========================================================================== ; DSPMM - DISPLAY MODREG (file: bank04_2.asm) ; ; DSPMM does not display MODREG directly. It puts EXEC request with ; prio=CHARPRIO for DSPMMJB and returns to caller. ; ; If MODREG contains -0, DSPMMJB blanks the MODE lights. ; ; Adapted from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, pp. 369. ;========================================================================== DSPMM EQU * 10047 4,0047 3 0,0001 0 XCH Q 10050 4,0050 5 0,0130 0 TS MPAC 10051 4,0051 2 0,0000 0 INHINT 10052 4,0052 3 2,4131 0 CAF CHRPRIO 10053 4,0053 0 1,3162 1 TC NOVAC 10054 4,0054 13400 1 CADR DSPMMJB 10055 4,0055 2 0,0000 1 RELINT 10056 4,0056 0 0,0130 0 ENDSPMM TC MPAC BANK04_3 EQU * ORG BANK40_8 ; COLOSSUS pp. 369-371 INCL bank40_8.asm ;==========================================================================
; DISPLAY ROUTINES (file:bank40_8.asm) ; ; Adapted from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, pp. 369-371. ;========================================================================== BLNKSUB1 EQU * 13350 5,1350 3 1,2050 0 CAF ZERO ; was CA DSPCOUNT in Block II13351 5,1351 6 0,0466 0 AD DSPCOUNT ; save old DSPCOUNT for later restoration13352 5,1352 5 0,0427 0 TS BUF+2 13353 5,1353 3 1,2100 1 CAF BIT1 ; test bit 1. See if R1 to be blanked.13354 5,1354 0 5,7373 1 TC TESTBIT 13355 5,1355 3 2,4635 0 CAF R1D1 13356 5,1356 0 5,6472 0 TC _5BLANK-1 13357 5,1357 3 1,2077 0 CAF BIT2 ; test bit 2. See if R2 to be blanked.13360 5,1360 0 5,7373 1 TC TESTBIT 13361 5,1361 3 2,4636 0 CAF R2D1 13362 5,1362 0 5,6472 0 TC _5BLANK-1 13363 5,1363 3 1,2076 1 CAF BIT3 ; test bit 3. See if R3 to be blanked.13364 5,1364 0 5,7373 1 TC TESTBIT 13365 5,1365 3 2,4637 1 CAF R3D1 13366 5,1366 0 5,6472 0 TC _5BLANK-1 13367 5,1367 3 1,2050 0 CAF ZERO ; was CA BUF+2 in Block II13370 5,1370 6 0,0427 0 AD BUF+2 ; restore DSPCOUNT to state it had13371 5,1371 5 0,0466 0 TS DSPCOUNT ; before BLANKSUB 13372 5,1372 0 2,4613 1 TC BS_SUPDXCHZ ; was DXCH BUF, TC SUPDXCHZ+1 in BII TESTBIT EQU * 13373 5,1373 7 0,0420 0 MASK NVTEMP ; NVTEMP contains blanking code13374 5,1374 1 0,0000 0 CCS A 13375 5,1375 0 0,0001 0 TC Q ; if current bit = 1, return to L+113376 5,1376 2 0,0001 1 INDEX Q ; if current bit = 0, return to L+313377 5,1377 0 0,0002 0 TC 2 DSPMMJB EQU * 13400 5,1400 3 2,4677 0 CAF MD1 ; gets here thru DSPMM13401 5,1401 3 0,0466 0 XCH DSPCOUNT 13402 5,1402 5 0,0435 0 TS DSPMMTEM ; save DSPCOUNT13403 5,1403 1 0,0500 0 CCS MODREG 13404 5,1404 6 1,2051 1 AD ONE 13405 5,1405 0 5,7144 1 TC DSPDECVN ; if MODREG is + or +0, display MODREG13406 5,1406 0 5,7410 0 TC *+2 ; if MODREG is -NZ, do nothing13407 5,1407 0 5,6540 0 TC _2BLANK ; if MODREG is -0, blank MM13410 5,1410 3 0,0435 0 XCH DSPMMTEM ; restore DSPCOUNT13411 5,1411 5 0,0466 0 TS DSPCOUNT 13412 5,1412 0 1,2723 0 TC ENDOFJOB ;-------------------------------------------------------------------------- ; RECALTST ; Entered directly after data is loaded (or resequence verb is executed), ; terminate verb is executed, or proceed without data verb is executed. ; It wakes up job that did TC ENDIDLE. ; If CADRSTOR not = +0, it puts +0 into DSPLOCK, and turns off KEY RLSE ; light if DSPLIST is empty (leaves KEY RLSE light alone if not empty). ; ; Adapted from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, p.370. ;-------------------------------------------------------------------------- RECALTST EQU * 13413 5,1413 1 0,0531 1 CCS CADRSTOR 13414 5,1414 0 5,7416 0 TC RECAL1 13415 5,1415 0 1,2723 0 TC ENDOFJOB ; normal exit if keyboard initiated. RECAL1 EQU * 13416 5,1416 3 1,2050 0 CAF ZERO 13417 5,1417 3 0,0531 0 XCH CADRSTOR 13420 5,1420 2 0,0000 0 INHINT 13421 5,1421 0 1,3003 1 TC JOBWAKE 13422 5,1422 1 0,0503 0 CCS LOADSTAT 13423 5,1423 0 5,7450 1 TC DOPROC ; + proceed without data13424 5,1424 0 1,2723 0 TC ENDOFJOB ; pathological case exit13425 5,1425 0 5,7446 0 TC DOTERM ; - terminate13426 5,1426 3 1,2052 1 CAF TWO ; -0, data in or resequence RECAL2 EQU * 13427 5,1427 2 0,0300 0 INDEX LOCCTR 13430 5,1430 6 0,0140 1 AD LOC ; loc is + for basic jobs13431 5,1431 2 0,0300 0 INDEX LOCCTR 13432 5,1432 5 0,0140 1 TS LOC
13433 5,1433 3 1,2050 0 CAF ZERO ; save verb in MPAC, noun in MPAC+1 at13434 5,1434 6 0,0471 0 AD NOUNREG ; time of response to ENDIDLE for13435 5,1435 2 0,0300 0 INDEX LOCCTR ; possible later testing by job that has13436 5,1436 5 0,0131 1 TS MPAC+1 ; been waked up 13437 5,1437 3 1,2050 0 CAF ZERO 13440 5,1440 6 0,0470 1 AD VERBREG 13441 5,1441 2 0,0300 0 INDEX LOCCTR 13442 5,1442 5 0,0130 0 TS MPAC 13443 5,1443 2 0,0000 1 RELINT RECAL3 EQU * 13444 5,1444 0 2,5003 1 TC RELDSP 13445 5,1445 0 1,2723 0 TC ENDOFJOB DOTERM EQU * 13446 5,1446 3 1,2050 0 CAF ZERO 13447 5,1447 0 5,7427 1 TC RECAL2 DOPROC EQU * 13450 5,1450 3 1,2051 1 CAF ONE 13451 5,1451 0 5,7427 1 TC RECAL2 BANK40_8a EQU * ORG BANKFF_5 ; COLOSSUS pp. 372-376 INCL bankff_5.asm ;========================================================================== ; DISPLAY ROUTINES (file:bankff_5.asm) ; ; Adapted from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, pp. 372-376. ;========================================================================== ;-------------------------------------------------------------------------- ; MISCELLANEOUS SERVICE ROUTINES IN FIXED-FIXED ; ; Adapted from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, p.372. ;-------------------------------------------------------------------------- ; SETNCADR ; Store the eraseable memory address from A into NOUNCADR and NOUNADD. ; (changed from Block II, because there is no bank addressing for block I) ; SETNADD ; Get the eraseable memory address from NOUNCADR and store it into NOUNADD. ; (changed from Block II, because there is no bank addressing for block I) ; ; SETEBANK ; E CADR arrives in A. E ADRES is "derived" and left in A. ; (changed from Block II, because there is no bank addressing for block I) SETNCADR EQU * 04616 4616 3 0,0001 0 XCH Q 04617 4617 5 0,0555 1 TS SETNCADR_Q ; save return address04620 4620 3 0,0001 0 XCH Q ; restore A 04621 4621 5 0,0506 1 TS NOUNCADR ; store ECADR04622 4622 7 2,4674 1 MASK LOW10 04623 4623 5 0,0442 0 TS NOUNADD ; put E ADRES into NOUNADD04624 4624 0 0,0555 1 TC SETNCADR_Q SETNADD EQU * 04625 4625 3 0,0001 0 XCH Q 04626 4626 5 0,0555 1 TS SETNCADR_Q ; save return address04627 4627 3 0,0001 0 XCH Q ; restore A 04630 4630 3 1,2050 0 CAF ZERO 04631 4631 6 0,0506 1 AD NOUNCADR ; get NOUNCADR04632 4632 0 2,4622 0 TC SETNCADR+4 SETEBANK EQU * 04633 4633 7 2,4674 1 MASK LOW10 04634 4634 0 0,0001 0 TC Q 04635 4635 00016 0 R1D1 DS %16 ; these 3 constants form a packed table04636 4636 00011 1 R2D1 DS %11 ; don't separate04637 4637 00004 0 R3D1 DS %4 ; must stay here RIGHT5 EQU * 04640 4640 5 0,0020 0 TS CYR 04641 4641 4 0,0020 1 CS CYR 04642 4642 4 0,0020 1 CS CYR
04643 4643 4 0,0020 1 CS CYR 04644 4644 4 0,0020 1 CS CYR 04645 4645 3 0,0020 0 XCH CYR 04646 4646 0 0,0001 0 TC Q LEFT5 EQU * 04647 4647 5 0,0022 1 TS CYL 04650 4650 4 0,0022 0 CS CYL 04651 4651 4 0,0022 0 CS CYL 04652 4652 4 0,0022 0 CS CYL 04653 4653 4 0,0022 0 CS CYL 04654 4654 3 0,0022 1 XCH CYL 04655 4655 0 0,0001 0 TC Q SLEFT5 EQU * 04656 4656 6 0,0000 1 DOUBLE 04657 4657 6 0,0000 1 DOUBLE 04660 4660 6 0,0000 1 DOUBLE 04661 4661 6 0,0000 1 DOUBLE 04662 4662 6 0,0000 1 DOUBLE 04663 4663 0 0,0001 0 TC Q 04664 4664 00037 0 LOW5 DS %00037 ; these 3 constants form a packed table04665 4665 01740 0 MID5 DS %01740 ; don't separate04666 4666 76000 0 HI5 DS %76000 ; must stay here 04667 4667 0 1,3162 1 TCNOVAC TC NOVAC 04670 4670 0 1,2232 0 TCWAIT TC WAITLIST ;TCTSKOVR TC TASKOVER 04671 4671 0 1,3161 1 TCFINDVAC TC FINDVAC ;CHRPRIO DS %30000 ; EXEC priority of CHARIN04672 4672 03777 0 LOW11 DS %3777 B12M1 EQU LOW11 04673 4673 00377 1 LOW8 DS %377 04674 4674 01777 1 LOW10 DS %01777 04675 4675 00023 0 VD1 DS %23 ; these 3 constants form a packed table04676 4676 00021 1 ND1 DS %21 ; don't separate04677 4677 00025 0 MD1 DS %25 ; must stay here 04700 4700 00012 1 BINCON DS 10 ;**************** TURN ON/OFF OPERATOR ERROR LIGHT ******* p. 373 DSALMOUT EQU OUT1 ; channel 11 in Block II is OUT1 in Block I FALTON EQU * 04701 4701 4 0,0011 0 CS DSALMOUT ; inclusive OR bit 7 with 1 using04702 4702 7 2,4712 0 MASK FALTOR ; Demorgan's theorem04703 4703 4 0,0000 0 COM 04704 4704 5 0,0011 1 TS DSALMOUT ; was bit 7 of channel 11 in Block II04705 4705 0 0,0001 0 TC Q FALTOF EQU * 04706 4706 4 1,2072 1 CS BIT7 04707 4707 7 0,0011 0 MASK DSALMOUT 04710 4710 5 0,0011 1 TS DSALMOUT ; was bit 7 of channel 11 in Block II04711 4711 0 0,0001 0 TC Q 04712 4712 77677 1 FALTOR DS %77677 ; 1's compliment of bit 7 ;**************** TURN ON KEY RELEASE LIGHT ******* p. 373 RELDSPON EQU * 04713 4713 4 0,0011 0 CS DSALMOUT ; inclusive OR bit 5 with 1 using04714 4714 7 2,4720 1 MASK RELDSPOR ; Demorgan's theorem04715 4715 4 0,0000 0 COM 04716 4716 5 0,0011 1 TS DSALMOUT ; was bit 5 of channel 11 in Block II04717 4717 0 0,0001 0 TC Q 04720 4720 77757 1 RELDSPOR DS %77757 ; 1's compliment of bit 5 ; TPSL1 ; Shift triple word MPAC, MPAC+1, MPAC+2 left 1 bit TPSL1 EQU * 04721 4721 3 1,2050 0 CAF ZERO 04722 4722 6 0,0132 1 AD MPAC+2 04723 4723 6 0,0132 1 AD MPAC+2 04724 4724 5 0,0132 1 TS MPAC+2 ; skip on overflow 04725 4725 3 1,2050 0 CAF ZERO ; otherwise, make interword carry=004726 4726 6 0,0131 1 AD MPAC+1 04727 4727 6 0,0131 1 AD MPAC+1
04730 4730 5 0,0131 1 TS MPAC+1 ; skip on overflow 04731 4731 3 1,2050 0 CAF ZERO ; otherwise, make interword carry=004732 4732 6 0,0130 0 AD MPAC 04733 4733 6 0,0130 0 AD MPAC 04734 4734 5 0,0130 0 TS MPAC ; skip on overflow 04735 4735 0 0,0001 0 TC Q ; no net OV/UF04736 4736 5 0,0136 0 TS MPAC+6 ; MPAC+6 set to +/- 1 for OV/UF04737 4737 0 0,0001 0 TC Q ; PRSHRTMP ; if MPAC, +1 are each +NZ or +0 and C(A)=-0, SHORTMP wrongly gives +0. ; if MPAC, +1 are each -NZ or -0 and C(A)=+0, SHORTMP wrongly gives +0. ; PRSHRTMP fixes first case only, by merely testing C(A) and if it = -0, ; setting result to -0. ; (Do not use PRSHRTMP unless MPAC, +1 are each +NZ or +0, as they are ; when they contain the SF constants). PRSHRTMP EQU * 04740 4740 5 0,0432 1 TS MPTEMP 04741 4741 3 0,0001 0 XCH Q 04742 4742 5 0,0600 1 TS PRSHRTMP_Q 04743 4743 1 0,0432 0 CCS MPTEMP 04744 4744 0 2,4754 0 TC DOSHRTMP ; C(A) +, do regular SHORTMP04745 4745 0 2,4754 0 TC DOSHRTMP ; C(A) +0, do regular SHORTMP04746 4746 0 2,4754 0 TC DOSHRTMP ; C(A) -, do regular SHORTMP04747 4747 4 1,2050 1 CS ZERO ; C(A) -0, force result to -0 and return04750 4750 5 0,0130 0 TS MPAC 04751 4751 5 0,0131 1 TS MPAC+1 04752 4752 5 0,0132 1 TS MPAC+2 04753 4753 0 0,0600 1 TC PRSHRTMP_Q DOSHRTMP EQU * 04754 4754 3 1,2050 0 CAF ZERO 04755 4755 6 0,0432 1 AD MPTEMP 04756 4756 0 2,4353 0 TC SHORTMP 04757 4757 0 0,0600 1 TC PRSHRTMP_Q ;**************** TURN ON/OFF V/N FLASH ******* p. 374 ; this is handled by setting a bit in channel 11 in Block II. ; In Block I, it has to be set through the display table, so I ; borrowed this method from SGNCOM (the DSKY +/- sign routine) ; Uses MYBANKCALL because BANKCALL is not reentrant and I dont ; understand its usage in COLOSSUS well enough to be certain ; that FLASHON/FLASHOFF isn't being called somewhere through ; BANKCALL. FLASHON EQU * 04760 4760 3 0,0001 0 XCH Q 04761 4761 5 0,0570 0 TS FLASHRET 04762 4762 3 1,2066 0 CAF BIT11 04763 4763 5 0,0421 0 TS CODE 04764 4764 3 2,5000 1 CAF FLSHTAB 04765 4765 0 1,3624 1 TC MYBANKCALL 04766 4766 13253 1 CADR _11DSPIN 04767 4767 0 0,0570 0 TC FLASHRET FLASHOFF EQU * 04770 4770 3 0,0001 0 XCH Q 04771 4771 5 0,0570 0 TS FLASHRET 04772 4772 3 1,2050 0 CAF ZERO 04773 4773 5 0,0421 0 TS CODE 04774 4774 3 2,5000 1 CAF FLSHTAB 04775 4775 0 1,3624 1 TC MYBANKCALL 04776 4776 13253 1 CADR _11DSPIN 04777 4777 0 0,0570 0 TC FLASHRET 05000 5000 00011 1 FLSHTAB DS %11 ; V/N flash NVSUBUSY EQU * 05001 5001 0 1,3653 1 TC POSTJUMP 05002 5002 13452 0 CADR NVSUBSY1
BANKFF_5a EQU * ORG BANK40_8a ; COLOSSUS pp. 376 INCL bank40_8a.asm ;========================================================================== ; DISPLAY ROUTINES (file:bank40_8a.asm) ; ; Adapted from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, pp. 376. ;========================================================================== ;-------------------------------------------------------------------------- ; MISCELLANEOUS SERVICE ROUTINES IN FIXED-FIXED ; ; Adapted from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, p.376. ;-------------------------------------------------------------------------- NVSUBSY1 EQU * 13452 5,1452 5 0,0567 0 TS NBSUBSY1_L ; save CADR13453 5,1453 0 2,4554 1 TC ISCADR_P0 ; abort if CADRSTOR not = +013454 5,1454 0 2,4560 0 TC ISLIST_P0 ; abort if DSPLIST not = +013455 5,1455 0 2,4713 0 TC RELDSPON 13456 5,1456 3 1,2050 0 CAF ZERO ; was CA L in Block II13457 5,1457 6 0,0567 0 AD NBSUBSY1_L 13460 5,1460 5 0,0532 0 TS DSPLIST 13461 5,1461 0 1,2725 0 ENDNVBSY TC JOBSLEEP BANK40_9 EQU * ORG BANKFF_5a ; COLOSSUS pp. 376-378 INCL bankff_5a.asm ;========================================================================== ; DISPLAY ROUTINES (file:bankff_5a.asm) ; ; Adapted from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, pp. 376-378. ;========================================================================== ;-------------------------------------------------------------------------- ; MISCELLANEOUS SERVICE ROUTINES IN FIXED-FIXED ; ; Adapted from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, p.376. ;-------------------------------------------------------------------------- ; RELDSP ; used by VBPROC, VBTERM, VBRQEXEC, VBRQWAIT, VBRELDSP, EXTENDED VERB ; DISPATCHER, VBRESEQ, and RECALTST. ; RELDSP1 ; used by monitor set up, VBRELDSP RELDSP EQU * 05003 5003 3 0,0001 0 XCH Q ; set DSPLOCK to +0, turn RELDSP light05004 5004 5 0,0441 0 TS RELRET ; off, search DSPLIST05005 5005 4 1,2063 1 CS BIT14 05006 5006 2 0,0000 0 INHINT 05007 5007 7 0,0510 1 MASK MONSAVE1 05010 5010 5 0,0510 0 TS MONSAVE1 ; turn off external monitor bit05011 5011 1 0,0532 1 CCS DSPLIST 05012 5012 0 2,5014 1 TC *+2 05013 5013 0 2,5017 1 TC RELDSP2 ; list empty05014 5014 3 1,2050 0 CAF ZERO 05015 5015 3 0,0532 0 XCH DSPLIST 05016 5016 0 1,3003 1 TC JOBWAKE RELDSP2 EQU * 05017 5017 2 0,0000 1 RELINT 05020 5020 4 1,2074 1 CS BIT5 ; turn off KEY RLSE light05021 5021 7 0,0011 0 MASK DSALMOUT ; was WAND DSALMOUT in Block II05022 5022 5 0,0011 1 TS DSALMOUT 05023 5023 3 1,2050 0 CAF ZERO 05024 5024 5 0,0501 0 TS DSPLOCK 05025 5025 0 0,0441 0 TC RELRET RELDSP1 EQU * 05026 5026 3 0,0001 0 XCH Q ; set DSPLOCK to +0, No DSPLIST search05027 5027 5 0,0441 0 TS RELRET ; turn KEY RLSE light off if DSPLIST is ; empty. Leave KEY RLSE light alone if ; DSPLIST is not empty.05030 5030 1 0,0532 1 CCS DSPLIST 05031 5031 0 2,5033 1 TC *+2 ; + not empty, leave KEY RLSE light alone05032 5032 0 2,5017 1 TC RELDSP2 ; +0, list empty, turn off KEY RLSE light05033 5033 3 1,2050 0 CAF ZERO ; - not empty, leave KEY RLSE light alone
05034 5034 5 0,0501 0 TS DSPLOCK 05035 5035 0 0,0441 0 TC RELRET ;-------------------------------------------------------------------------- ; NEWMODEA ; ; The new major mode is in register A. Store the major mode in MODREG and update ; the major mode display. ; ; I couldn't find this in my COLOSSUS listing, so I borrowed it from UPDATVB-1 ; (but modified it to work with the major mode instead of the verb). ;-------------------------------------------------------------------------- NEWMODEA EQU * 05036 5036 5 0,0500 1 TS MODREG ; store new major mode05037 5037 3 0,0001 0 XCH Q 05040 5040 5 0,0572 1 TS NEWMODEA_Q ; save Q 05041 5041 3 2,4677 0 CAF MD1 05042 5042 5 0,0466 0 TS DSPCOUNT 05043 5043 3 1,2050 0 CAF ZERO 05044 5044 6 0,0500 1 AD MODREG 05045 5045 0 1,3565 1 TC BANKCALL 05046 5046 13144 1 CADR DSPDECVN 05047 5047 0 0,0572 1 TC NEWMODEA_Q ; return ;------------------------------------------------------------------------- ; POODOO - Program alarm. ; ; Turn on program alarm light and store alarm code in FAILREG. The alarm code ; is retrieved from the address pointed to by Q. The most recent code is stored ; in FAILREG. Older codes are scrolled to FAILREG+1,+2. Older CADRs are ; scrolled down. ; ; This was missing from my COLOSSUS listing, so I had to guess at the ; implementation, based upon calling references in COLOSSUS, and textual ; descriptions of normal noun 9 which retrieves alarm codes. ;------------------------------------------------------------------------- POODOO EQU * 05050 5050 3 0,0001 0 XCH Q 05051 5051 5 0,0130 0 TS MPAC 05052 5052 4 0,0011 0 CS DSALMOUT ; inclusive OR bit 9 with 1 using05053 5053 7 2,5066 0 MASK NOTPALT ; Demorgan's theorem05054 5054 4 0,0000 0 COM 05055 5055 5 0,0011 1 TS DSALMOUT ; turn on PROG ALM light05056 5056 3 0,0461 1 XCH FAILREG+1 ; scroll previous codes down05057 5057 5 0,0462 1 TS FAILREG+2 05060 5060 3 0,0460 0 XCH FAILREG 05061 5061 5 0,0461 1 TS FAILREG+1 05062 5062 2 0,0130 1 INDEX MPAC ; indirectly address Q05063 5063 3 0,0000 1 CAF 0 ; (gets alarm code)05064 5064 5 0,0460 0 TS FAILREG ; store alarm code05065 5065 0 1,2723 0 TC ENDOFJOB 05066 5066 77377 1 NOTPALT DS %77377 ; 1's compliment of bit9 (PROG ALM) ;------------------------------------------------------------------------- ; PINBRNCH ; ; This is supposed to restore the DSKY display to its former state in the ; event of error. According to COLOSSUS, it works if you use "Margaret's" ; code. I don't have that portion of the listing, so I just terminate ; the job, which seems to be an acceptable work-around, even though the ; old display is not restored. ;------------------------------------------------------------------------- 05067 5067 0 1,2723 0 PINBRNCH TC ENDOFJOB BANKFF_6 EQU * ORG BANK41_8 ; COLOSSUS pp. 379-380 INCL bank41_8.asm ;========================================================================== ; DISPLAY ROUTINES (file:bank41_8.asm) ; ; Adapted from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, pp. 379-380. ;==========================================================================
VBTSTLTS EQU * 15572 6,1572 2 0,0000 0 INHINT ; heavily modified from the original Block II code... 15573 6,1573 4 0,0011 0 CS DSALMOUT ; turn on lights15574 6,1574 7 6,7623 0 MASK TSTCON1 ; inclusive OR light bits with 1's using15575 6,1575 4 0,0000 0 COM ; Demorgan's theorem15576 6,1576 5 0,0011 1 TS DSALMOUT 15577 6,1577 3 1,2060 0 CAF TEN 15600 6,1600 5 0,0414 0 TSTLTS1 TS ERCNT 15601 6,1601 4 6,7621 1 CS FULLDSP 15602 6,1602 2 0,0414 1 INDEX ERCNT 15603 6,1603 5 0,0512 1 TS DSPTAB 15604 6,1604 1 0,0414 1 CCS ERCNT 15605 6,1605 0 6,7600 0 TC TSTLTS1 15606 6,1606 4 6,7622 1 CS FULLDSP1 15607 6,1607 5 0,0513 0 TS DSPTAB+1 ; turn on 3 plus signs15610 6,1610 5 0,0516 0 TS DSPTAB+4 15611 6,1611 5 0,0520 0 TS DSPTAB+6 15612 6,1612 3 1,2061 1 CAF ELEVEN 15613 6,1613 5 0,0505 1 TS NOUT 15614 6,1614 0 2,4760 1 TC FLASHON 15615 6,1615 3 6,7624 0 CAF SHOLTS 15616 6,1616 0 1,2232 0 TC WAITLIST 15617 6,1617 15625 1 CADR TSTLTS2 15620 6,1620 0 1,2723 0 TC ENDOFJOB ; DSPLOCK is left busy (from keyboard ; action) until TSTLTS3 to ensure that ; lights test will be seen. 15621 6,1621 05675 0 FULLDSP DS %05675 ; display all 8's15622 6,1622 07675 1 FULLDSP1 DS %07675 ; display all 8's and + ; 1's Comp of UPTEL=bit3, KEY REL=bit5, oper err=bit7, PROG ALM=bit 9 15623 6,1623 77253 0 TSTCON1 DS %77253 15624 6,1624 00764 1 SHOLTS DS %764 ; 5 sec TSTLTS2 EQU * 15625 6,1625 3 2,4131 0 CAF CHRPRIO ; called by WAITLIST15626 6,1626 0 1,3162 1 TC NOVAC 15627 6,1627 15631 1 CADR TSTLTS3 15630 6,1630 0 1,2413 0 TC TASKOVER TSTLTS3 EQU * 15631 6,1631 2 0,0000 0 INHINT 15632 6,1632 3 6,7623 1 CAF TSTCON1 ; turn off lights15633 6,1633 7 0,0011 0 MASK DSALMOUT 15634 6,1634 5 0,0011 1 TS DSALMOUT 15635 6,1635 2 0,0000 1 RELINT 15636 6,1636 0 1,3565 1 TC BANKCALL ; redisplay C(MODREG)15637 6,1637 10047 0 CADR DSPMM 15640 6,1640 0 2,4536 0 TC KILMONON ; turn on kill monitor bit15641 6,1641 0 2,4770 0 TC FLASHOFF ; turn off V/N flash15642 6,1642 0 1,3653 1 TC POSTJUMP ; does RELDSP and goes to PINBRNCH if15643 6,1643 13334 1 CADR TSTLTS4 ; ENDIDLE is awaiting operator response BANK41_9 EQU * ORG BANK40_9 ; COLOSSUS pp. 381-382 INCL bank40_9.asm ;========================================================================== ; DISPLAY ROUTINES (file:bank40_9.asm) ; ; Adapted from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, pp. 381-382. ;========================================================================== ;-------------------------------------------------------------------------- ; ERROR - Error light reset. ; ; Adapted from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, p.381. ;--------------------------------------------------------------------------
ERROR EQU * 13462 5,1462 3 0,0412 0 XCH _2122REG ; restore original C(DSPLOCK), thus error13463 5,1463 5 0,0501 0 TS DSPLOCK ; light reset leaves DSPLOCK unchanged ; omitted some stuff in COLOSSUS here 13464 5,1464 4 5,7520 0 CS ERCON ; turn off UPTL, OPER ERR, PROG ALM13465 5,1465 7 0,0011 0 MASK DSALMOUT 13466 5,1466 5 0,0011 1 TS DSALMOUT 13467 5,1467 3 2,4700 1 TSTAB CAF BINCON ; dec 1013470 5,1470 5 0,0414 0 TS ERCNT ; ERCNT = count13471 5,1471 2 0,0000 0 INHINT 13472 5,1472 2 0,0414 1 INDEX ERCNT 13473 5,1473 1 0,0512 0 CCS DSPTAB 13474 5,1474 6 1,2051 1 AD ONE 13475 5,1475 0 5,7502 1 TC ERPLUS 13476 5,1476 6 1,2051 1 AD ONE 13477 5,1477 4 0,0000 0 ERMINUS CS A 13500 5,1500 7 5,7517 1 MASK NOTBIT12 13501 5,1501 0 5,7505 0 TC ERCOM 13502 5,1502 4 0,0000 0 ERPLUS CS A 13503 5,1503 7 5,7517 1 MASK NOTBIT12 13504 5,1504 4 0,0000 0 CS A 13505 5,1505 2 0,0414 1 ERCOM INDEX ERCNT 13506 5,1506 5 0,0512 1 TS DSPTAB 13507 5,1507 2 0,0000 1 RELINT 13510 5,1510 1 0,0414 1 CCS ERCNT 13511 5,1511 0 5,7470 0 TC TSTAB+1 13512 5,1512 3 1,2050 0 CAF ZERO ; clear the error codes for PROG ALM13513 5,1513 5 0,0460 0 TS FAILREG 13514 5,1514 5 0,0461 1 TS FAILREG+1 13515 5,1515 5 0,0462 1 TS FAILREG+2 13516 5,1516 0 1,2723 0 TC ENDOFJOB 13517 5,1517 73777 1 NOTBIT12 DS %73777 13520 5,1520 00504 0 ERCON DS %504 ; channel 11 bits 3,7,9 BANK40_10 EQU * ; end of PINBALL routines ; PINBALL NOUN tables ORG BANK42_3 INCL bank42_3.asm ; COLOSSUS pp. 263-279 ;========================================================================== ; PINBALL NOUN TABLES (file:bank42_3.asm) ; ; The following routines are for reading the noun tables and the scale ; factor (SF) tables (which are in a separate bank from the rest of ; PINBALL). These reading routines are in the same bank as the tables. ; They are called by DXCH Z (translated to DXCHJUMP for Block I). ; ; Adapted from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, pp. 263-279. ;========================================================================== ;-------------------------------------------------------------------------- ; Noun table info from COLOSSUS, p.325 ; ; noun code < 40 : normal noun case ; noun code >= 40: mixed noun case ;-------------------------------------------------------------------------- ; NNADTAB: ; for normal noun case, NNADTAB contains one CADR for each noun. ; +entry = noun CADR ; +0 = noun not used. ; -entry = machine CADR (E or F) to be specified. ; -1 = channel to be specified (not used for Block I); ; -0 = augment of last machine CADR supplied. ; for mixed noun case, NNADTAB contains one indirect address (IDADDREL) ; in low 10 bits, and the component code number in the high 5 bits. ; Examples: ; NNADTAB = %00042 ; CADR for octal address 42 ; NNADTAB = %00000 ; noun not used ; NNADTAB = %40000 ; specify machine address ; NNADTAB = %77777 ; augment last address
;-------------------------------------------------------------------------- ; NNTYPETAB (normal case): ; a packed table of the form: MMMMM NNNNN PPPPP ; for the normal case: ; MMMMM (bits 15-11): COMPONENT CODE NUMBER (p.263) ; 00000 = 1 component ; 00001 = 2 component ; 00010 = 3 component ; X1XXX = bit4=1, decimal only ; 1XXXX = bit5=1, no load ; ; NNNNN (bits 10-6): SF ROUTINE CODE NUMBER (p.263) ; 00000 = octal only ; 00001 = straight fractional (decimal) ; 00010 = CDU degrees (XXX.XX) ; 00011 = arithmetic SF ; 00100 = arith DP1, OUT(mult by 2EXP14 at end), IN(straight) ; 00101 = arith DP2, OUT(straight), IN(SL 7 at end) ; 00110 = Y optics degrees (XX.XXX max at 89.999) ; 00111 = arith DP3, OUT(SL 7 at end) IN(straight) ; 01000 = whole hours in R1, whole minutes (mod 60) in R2, ; seconds (mod 60) 0XX.XX in R3 *** alarms if used withoctal ; ; PPPPP (bits 5-1): SF CONSTANT CODE NUMBER (p.263) ; 00000 = whole, use arith ; Examples: ; NNTYPTAB = %00000 ; 1 comp, octal only ; NNTYPTAB = %02000 ; 2 comp, octal only ; NNTYPTAB = %04000 ; 3 comp, octal only ; NNTYPTAB = %00040 ; 1 comp ,straight fractional ; NNTYPTAB = %04040 ; 3 comp ,straight fractional ;-------------------------------------------------------------------------- ; NNTYPETAB (mixed case): ; a packed table of the form: MMMMM NNNNN PPPPP ; for the mixed case (3 component): ; MMMMM (bits 15-11) = SF constant3 code number. ; NNNNN (bits 10-6) = SF constant2 code number. ; PPPPP (bits 5-1) = SF constant1 code number. ; for the mixed case (2 component): ; NNNNN (bits 10-6) = SF constant2 code number. ; PPPPP (bits 5-1) = SF constant1 code number. ; for the mixed case (1 component): ; PPPPP (bits 5-1) = SF constant1 code number. ;-------------------------------------------------------------------------- ; IDADDTAB (mixed case only): ; there is also an indirect address table for mixed case only. ; Each entry contains one ECADR. IDADDREL is the relative address of ; the first of these entries. ; There is one entry in this table for each component of a mixed noun. ; They are listed in order of ascending K. ;-------------------------------------------------------------------------- ; RUTMXTAB (mixed case only): ; there is also a scale factor routine number table for mixed case only. ; There is one entry per mixed noun. The form is: QQQQQ RRRRR SSSSS ; for the 3 component case ; QQQQQ (bits 15-11) = SF routine3 code number. ; RRRRR (bits 10-6) = SF routine2 code number. ; SSSSS (bits 5-1) = SF routine1 code number. ; for the 2 component case ; RRRRR (bits 10-6) = SF routine2 code number. ; SSSSS (bits 5-1) = SF routine1 code number. ; In octal display and load (oct or dec) verbs, exclude use of verbs whose ; component number is greater than the number of components in noun. ; (All machine address to be specified nouns are 3 component) ; In multi-component load verbs, no mixing of octal and decimal data ; component words is allowed; alarm if violation. ; In decimal loads of data, 5 numerical chars must be keyed in before ; each enter; if not, alarm. ;--------------------------------------------------------------------------
; LODNNTAB ; loads NNADTEM with the NNADTAB entry, NNTYPTEM with the NNTYPTAB ; entry. If the noun is mixed, IDAD1TEM is loaded with the first IDADTAB ; entry, IDAD2TEM the second IDADTAB entry, IDAD3TEM the third IDADTAB ; entry, RUTMXTEM with the RUTMXTAB entry. MIXBR is set for mixed=2 ; or normal=1 noun. ; ; NOTE: in BlockII, NNADTEM = -1 means use an I/O channel instead of a ; memory address (channel specified in NOUNCADR). Block I does not have ; I/O channels. ; ; Adapted from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, p.265. ;-------------------------------------------------------------------------- LODNNTAB EQU * 16114 7,0114 5 0,0562 0 TS GTSF_RET ; save return CADR 16115 7,0115 2 0,0471 1 INDEX NOUNREG 16116 7,0116 3 7,6210 1 CAF NNADTAB 16117 7,0117 5 0,0443 1 TS NNADTEM 16120 7,0120 2 0,0471 1 INDEX NOUNREG 16121 7,0121 3 7,6354 0 CAF NNTYPTAB 16122 7,0122 5 0,0444 0 TS NNTYPTEM 16123 7,0123 4 0,0471 1 CS NOUNREG 16124 7,0124 6 7,6161 1 AD MIXCON 16125 7,0125 1 0,0000 0 CCS A ; was BZMF LODMIXNN in Block II16126 7,0126 0 7,6132 1 TC *+4 ; >016127 7,0127 0 7,6131 1 TC *+2 ; +0, noun number G/E first mixed noun16130 7,0130 0 7,6131 1 TC *+1 ; <0, noun number G/E first mixed noun16131 7,0131 0 7,6135 0 TC LODMIXNN ; -0, noun number G/E first mixed noun 16132 7,0132 3 1,2051 1 CAF ONE ; noun number L/ first mixed noun16133 7,0133 5 0,0435 0 TS MIXBR ; normal, +1 into MIXBR 16134 7,0134 0 7,6156 0 TC LODNLV LODMIXNN EQU * 16135 7,0135 3 1,2052 1 CAF TWO ; mixed, +2 into MIXBR16136 7,0136 5 0,0435 0 TS MIXBR 16137 7,0137 2 0,0471 1 INDEX NOUNREG 16140 7,0140 3 7,7054 1 CAF RUTMXTAB-40 ; first mixed noun = 4016141 7,0141 5 0,0450 0 TS RUTMXTEM 16142 7,0142 3 2,4674 0 CAF LOW10 16143 7,0143 7 0,0443 0 MASK NNADTEM 16144 7,0144 5 0,0001 0 TS Q ; temp 16145 7,0145 2 0,0000 0 INDEX A 16146 7,0146 3 7,6640 0 CAF IDADDTAB 16147 7,0147 5 0,0445 1 TS IDAD1TEM ; load IDAD1TEM with first IDADDTAB entry 16150 7,0150 2 0,0001 1 INDEX Q 16151 7,0151 3 7,6641 1 CAF IDADDTAB+1 16152 7,0152 5 0,0446 1 TS IDAD2TEM ; load IDAD2TEM with 2nd IDADDTAB entry 16153 7,0153 2 0,0001 1 INDEX Q 16154 7,0154 3 7,6642 1 CAF IDADDTAB+2 16155 7,0155 5 0,0447 0 TS IDAD3TEM ; load IDAD3TEM with 3rd IDADDTAB entry LODNLV EQU * 16156 7,0156 3 1,2050 0 CAF ZERO 16157 7,0157 6 0,0562 0 AD GTSF_RET ; load return CADR16160 7,0160 0 1,3526 0 TC DXCHJUMP ; return 16161 7,0161 00050 1 MIXCON DS %50 ; 1st mixed noun = 40 (DEC 40) ;-------------------------------------------------------------------------- ; GTSFOUT ; On entry, SFTEMP1 contains SFCONUM X 2. ; Loads SFTEMP1, SFTEMP2 with the DP SFOUTAB entries ; ; GTSFIN ; On entry, SFTEMP1 contains SFCONUM X 2. ; Loads SFTEMP1, SFTEMP2 with the DP SFINTAB entries ; ; Adapted from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, p.266. ;-------------------------------------------------------------------------- GTSFOUT EQU * 16162 7,0162 5 0,0562 0 TS GTSF_RET ; save return CADR
16163 7,0163 3 0,0420 1 XCH SFTEMP1 16164 7,0164 5 0,0001 0 TS Q ; temp 16165 7,0165 2 0,0001 1 INDEX Q 16166 7,0166 3 7,6570 0 CAF SFOUTAB 16167 7,0167 5 0,0420 1 TS SFTEMP1 16170 7,0170 2 0,0001 1 INDEX Q 16171 7,0171 3 7,6571 1 CAF SFOUTAB+1 16172 7,0172 5 0,0421 0 TS SFTEMP2 SFCOM EQU * 16173 7,0173 3 1,2050 0 CAF ZERO 16174 7,0174 6 0,0562 0 AD GTSF_RET ; load return CADR16175 7,0175 0 1,3526 0 TC DXCHJUMP ; return GTSFIN EQU * 16176 7,0176 5 0,0562 0 TS GTSF_RET ; save return CADR 16177 7,0177 3 0,0420 1 XCH SFTEMP1 16200 7,0200 5 0,0001 0 TS Q ; temp 16201 7,0201 2 0,0001 1 INDEX Q 16202 7,0202 3 7,6520 0 CAF SFINTAB 16203 7,0203 5 0,0420 1 TS SFTEMP1 16204 7,0204 2 0,0001 1 INDEX Q 16205 7,0205 3 7,6521 1 CAF SFINTAB+1 16206 7,0206 5 0,0421 0 TS SFTEMP2 16207 7,0207 0 7,6173 1 TC SFCOM ;-------------------------------------------------------------------------- ; NOUN ADDRESS TABLE (NNADTAB) ; Indexed by noun number (0-39 decimal for normal nouns). ; ; Adapted from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, p.266. ;-------------------------------------------------------------------------- NNADTAB EQU * ; NN - NORMAL NOUNS16210 7,0210 00000 1 DS %0 ; 00 - not in use16211 7,0211 40000 0 DS %40000 ; 01 - specify machine address (fractional)16212 7,0212 40000 0 DS %40000 ; 02 - specify machine address (whole)16213 7,0213 40000 0 DS %40000 ; 03 - specify machine address (degrees)16214 7,0214 00036 1 DS %00036 ; 04 - spare *********** TEST, CHANGE TO ZERO16215 7,0215 00000 1 DS %0 ; 05 - spare16216 7,0216 00000 1 DS %0 ; 06 - spare16217 7,0217 00000 1 DS %0 ; 07 - spare16220 7,0220 00000 1 DS %0 ; 08 - spare16221 7,0221 00460 0 ECADR FAILREG ; 09 - alarm codes16222 7,0222 00000 1 DS %0 ; 10 - spare16223 7,0223 00000 1 DS %0 ; 11 - spare16224 7,0224 00000 1 DS %0 ; 12 - spare16225 7,0225 00000 1 DS %0 ; 13 - spare16226 7,0226 00000 1 DS %0 ; 14 - spare16227 7,0227 77777 0 DS %77777 ; 15 - increment machine address16230 7,0230 00000 1 DS %0 ; 16 - spare16231 7,0231 00000 1 DS %0 ; 17 - spare16232 7,0232 00000 1 DS %0 ; 18 - spare16233 7,0233 00000 1 DS %0 ; 19 - spare16234 7,0234 00000 1 DS %0 ; 20 - spare16235 7,0235 00000 1 DS %0 ; 21 - spare16236 7,0236 00000 1 DS %0 ; 22 - spare16237 7,0237 00000 1 DS %0 ; 23 - spare16240 7,0240 00000 1 DS %0 ; 24 - spare16241 7,0241 00000 1 DS %0 ; 25 - spare16242 7,0242 00534 0 ECADR DSPTEM1 ; 26 - prio/delay, adres, BBCON16243 7,0243 00000 1 DS %0 ; 27 - spare16244 7,0244 00000 1 DS %0 ; 28 - spare16245 7,0245 00000 1 DS %0 ; 29 - spare16246 7,0246 00000 1 DS %0 ; 30 - spare16247 7,0247 00000 1 DS %0 ; 31 - spare16250 7,0250 00000 1 DS %0 ; 32 - spare16251 7,0251 00000 1 DS %0 ; 33 - spare16252 7,0252 00000 1 DS %0 ; 34 - spare16253 7,0253 00000 1 DS %0 ; 35 - spare16254 7,0254 00035 1 ECADR TIME2 ; 36 - time of AGC clock (hrs, min, sec)16255 7,0255 00000 1 DS %0 ; 37 - spare16256 7,0256 00000 1 DS %0 ; 38 - spare16257 7,0257 00000 1 DS %0 ; 39 - spare ; end of normal nouns ; start of mixed nouns 16260 7,0260 00000 1 DS %0 ; 40 - spare16261 7,0261 00000 1 DS %0 ; 41 - spare
16262 7,0262 00000 1 DS %0 ; 42 - spare16263 7,0263 00000 1 DS %0 ; 43 - spare16264 7,0264 00000 1 DS %0 ; 44 - spare16265 7,0265 00000 1 DS %0 ; 45 - spare16266 7,0266 00000 1 DS %0 ; 46 - spare16267 7,0267 00000 1 DS %0 ; 47 - spare16270 7,0270 00000 1 DS %0 ; 48 - spare16271 7,0271 00000 1 DS %0 ; 49 - spare16272 7,0272 00000 1 DS %0 ; 50 - spare16273 7,0273 00000 1 DS %0 ; 51 - spare16274 7,0274 00000 1 DS %0 ; 52 - spare16275 7,0275 00000 1 DS %0 ; 53 - spare16276 7,0276 00000 1 DS %0 ; 54 - spare16277 7,0277 00000 1 DS %0 ; 55 - spare16300 7,0300 00000 1 DS %0 ; 56 - spare16301 7,0301 00000 1 DS %0 ; 57 - spare16302 7,0302 00000 1 DS %0 ; 58 - spare16303 7,0303 00000 1 DS %0 ; 59 - spare16304 7,0304 00000 1 DS %0 ; 60 - spare16305 7,0305 00000 1 DS %0 ; 61 - spare16306 7,0306 00000 1 DS %0 ; 62 - spare16307 7,0307 00000 1 DS %0 ; 63 - spare16310 7,0310 00000 1 DS %0 ; 64 - spare16311 7,0311 00000 1 DS %0 ; 65 - spare16312 7,0312 00000 1 DS %0 ; 66 - spare16313 7,0313 00000 1 DS %0 ; 67 - spare16314 7,0314 00000 1 DS %0 ; 68 - spare16315 7,0315 00000 1 DS %0 ; 69 - spare16316 7,0316 00000 1 DS %0 ; 70 - spare16317 7,0317 00000 1 DS %0 ; 71 - spare16320 7,0320 00000 1 DS %0 ; 72 - spare16321 7,0321 00000 1 DS %0 ; 73 - spare16322 7,0322 00000 1 DS %0 ; 74 - spare16323 7,0323 00000 1 DS %0 ; 75 - spare16324 7,0324 00000 1 DS %0 ; 76 - spare16325 7,0325 00000 1 DS %0 ; 77 - spare16326 7,0326 00000 1 DS %0 ; 78 - spare16327 7,0327 00000 1 DS %0 ; 79 - spare16330 7,0330 00000 1 DS %0 ; 80 - spare16331 7,0331 00000 1 DS %0 ; 81 - spare16332 7,0332 00000 1 DS %0 ; 82 - spare16333 7,0333 00000 1 DS %0 ; 83 - spare16334 7,0334 00000 1 DS %0 ; 84 - spare16335 7,0335 00000 1 DS %0 ; 85 - spare16336 7,0336 00000 1 DS %0 ; 86 - spare16337 7,0337 00000 1 DS %0 ; 87 - spare16340 7,0340 00000 1 DS %0 ; 88 - spare16341 7,0341 00000 1 DS %0 ; 89 - spare16342 7,0342 00000 1 DS %0 ; 90 - spare16343 7,0343 00000 1 DS %0 ; 91 - spare16344 7,0344 00000 1 DS %0 ; 92 - spare16345 7,0345 00000 1 DS %0 ; 93 - spare16346 7,0346 00000 1 DS %0 ; 94 - spare16347 7,0347 00000 1 DS %0 ; 95 - spare16350 7,0350 00000 1 DS %0 ; 96 - spare16351 7,0351 00000 1 DS %0 ; 97 - spare16352 7,0352 00000 1 DS %0 ; 98 - spare16353 7,0353 00000 1 DS %0 ; 99 - spare ; end of mixed nouns ;-------------------------------------------------------------------------- ; NOUN TYPE TABLE (NNTYPTAB) ; Indexed by noun number (0-39 decimal for normal nouns). ; ; Adapted from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, p.269. ;-------------------------------------------------------------------------- NNTYPTAB EQU * ; NN - NORMAL NOUNS16354 7,0354 00000 1 DS %0 ; 00 - not in use16355 7,0355 04040 1 DS %04040 ; 01 - 3 component (fractional)16356 7,0356 04140 0 DS %04140 ; 02 - 3 component (whole)16357 7,0357 04102 0 DS %04102 ; 03 - 3 component (CDU degrees)16360 7,0360 00000 1 DS %0 ; 04 - spare16361 7,0361 00000 1 DS %0 ; 05 - spare16362 7,0362 00000 1 DS %0 ; 06 - spare16363 7,0363 00000 1 DS %0 ; 07 - spare16364 7,0364 00000 1 DS %0 ; 08 - spare16365 7,0365 04000 0 DS %04000 ; 09 - 3 component, octal only16366 7,0366 00000 1 DS %0 ; 10 - spare16367 7,0367 00000 1 DS %0 ; 11 - spare16370 7,0370 00000 1 DS %0 ; 12 - spare16371 7,0371 00000 1 DS %0 ; 13 - spare16372 7,0372 00000 1 DS %0 ; 14 - spare16373 7,0373 00000 1 DS %0 ; 15 - 1 component, octal only16374 7,0374 00000 1 DS %0 ; 16 - spare16375 7,0375 00000 1 DS %0 ; 17 - spare
16376 7,0376 00000 1 DS %0 ; 18 - spare16377 7,0377 00000 1 DS %0 ; 19 - spare16400 7,0400 00000 1 DS %0 ; 20 - spare16401 7,0401 00000 1 DS %0 ; 21 - spare16402 7,0402 00000 1 DS %0 ; 22 - spare16403 7,0403 00000 1 DS %0 ; 23 - spare16404 7,0404 00000 1 DS %0 ; 24 - spare16405 7,0405 00000 1 DS %0 ; 25 - spare16406 7,0406 04000 0 DS %04000 ; 26 - 3 component, octal only16407 7,0407 00000 1 DS %0 ; 27 - spare16410 7,0410 00000 1 DS %0 ; 28 - spare16411 7,0411 00000 1 DS %0 ; 29 - spare16412 7,0412 00000 1 DS %0 ; 30 - spare16413 7,0413 00000 1 DS %0 ; 31 - spare16414 7,0414 00000 1 DS %0 ; 32 - spare16415 7,0415 00000 1 DS %0 ; 33 - spare16416 7,0416 00000 1 DS %0 ; 34 - spare16417 7,0417 00000 1 DS %0 ; 35 - spare16420 7,0420 24400 0 DS %24400 ; 36 - 3 component, HMS, (dec only)16421 7,0421 00000 1 DS %0 ; 37 - spare16422 7,0422 00000 1 DS %0 ; 38 - spare16423 7,0423 00000 1 DS %0 ; 39 - spare ; end of normal nouns ; start of mixed nouns 16424 7,0424 00000 1 DS %0 ; 40 - spare16425 7,0425 00000 1 DS %0 ; 41 - spare16426 7,0426 00000 1 DS %0 ; 42 - spare16427 7,0427 00000 1 DS %0 ; 43 - spare16430 7,0430 00000 1 DS %0 ; 44 - spare16431 7,0431 00000 1 DS %0 ; 45 - spare16432 7,0432 00000 1 DS %0 ; 46 - spare16433 7,0433 00000 1 DS %0 ; 47 - spare16434 7,0434 00000 1 DS %0 ; 48 - spare16435 7,0435 00000 1 DS %0 ; 49 - spare16436 7,0436 00000 1 DS %0 ; 50 - spare16437 7,0437 00000 1 DS %0 ; 51 - spare16440 7,0440 00000 1 DS %0 ; 52 - spare16441 7,0441 00000 1 DS %0 ; 53 - spare16442 7,0442 00000 1 DS %0 ; 54 - spare16443 7,0443 00000 1 DS %0 ; 55 - spare16444 7,0444 00000 1 DS %0 ; 56 - spare16445 7,0445 00000 1 DS %0 ; 57 - spare16446 7,0446 00000 1 DS %0 ; 58 - spare16447 7,0447 00000 1 DS %0 ; 59 - spare16450 7,0450 00000 1 DS %0 ; 60 - spare16451 7,0451 00000 1 DS %0 ; 61 - spare16452 7,0452 00000 1 DS %0 ; 62 - spare16453 7,0453 00000 1 DS %0 ; 63 - spare16454 7,0454 00000 1 DS %0 ; 64 - spare16455 7,0455 00000 1 DS %0 ; 65 - spare16456 7,0456 00000 1 DS %0 ; 66 - spare16457 7,0457 00000 1 DS %0 ; 67 - spare16460 7,0460 00000 1 DS %0 ; 68 - spare16461 7,0461 00000 1 DS %0 ; 69 - spare16462 7,0462 00000 1 DS %0 ; 70 - spare16463 7,0463 00000 1 DS %0 ; 71 - spare16464 7,0464 00000 1 DS %0 ; 72 - spare16465 7,0465 00000 1 DS %0 ; 73 - spare16466 7,0466 00000 1 DS %0 ; 74 - spare16467 7,0467 00000 1 DS %0 ; 75 - spare16470 7,0470 00000 1 DS %0 ; 76 - spare16471 7,0471 00000 1 DS %0 ; 77 - spare16472 7,0472 00000 1 DS %0 ; 78 - spare16473 7,0473 00000 1 DS %0 ; 79 - spare16474 7,0474 00000 1 DS %0 ; 80 - spare16475 7,0475 00000 1 DS %0 ; 81 - spare16476 7,0476 00000 1 DS %0 ; 82 - spare16477 7,0477 00000 1 DS %0 ; 83 - spare16500 7,0500 00000 1 DS %0 ; 84 - spare16501 7,0501 00000 1 DS %0 ; 85 - spare16502 7,0502 00000 1 DS %0 ; 86 - spare16503 7,0503 00000 1 DS %0 ; 87 - spare16504 7,0504 00000 1 DS %0 ; 88 - spare16505 7,0505 00000 1 DS %0 ; 89 - spare16506 7,0506 00000 1 DS %0 ; 90 - spare16507 7,0507 00000 1 DS %0 ; 91 - spare16510 7,0510 00000 1 DS %0 ; 92 - spare16511 7,0511 00000 1 DS %0 ; 93 - spare16512 7,0512 00000 1 DS %0 ; 94 - spare16513 7,0513 00000 1 DS %0 ; 95 - spare16514 7,0514 00000 1 DS %0 ; 96 - spare16515 7,0515 00000 1 DS %0 ; 97 - spare16516 7,0516 00000 1 DS %0 ; 98 - spare16517 7,0517 00000 1 DS %0 ; 99 - spare ; end of mixed nouns
;-------------------------------------------------------------------------- ; SCALE FACTOR INPUT TABLE (SFINTAB) ; Indexed by SF constant code number x 2 PPPPP (0-19 decimal; 0-23 octal) ; ; Adapted from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, p.272. ;-------------------------------------------------------------------------- SFINTAB EQU * 16520 7,0520 00006 1 DS %00006 ; 00 - whole, DP time (sec)16521 7,0521 03240 1 DS %03240 ; 00 16522 7,0522 00000 1 DS %00000 ; 01 - spare16523 7,0523 00000 1 DS %00000 ; 01 16524 7,0524 00000 1 DS %00000 ; 02 - CDU degrees, Y optics degrees16525 7,0525 00000 1 DS %00000 ; 02 (SFCONs in DEGINSF, OPTDEGIN 16526 7,0526 00000 1 DS %00000 ; 0316527 7,0527 00000 1 DS %00000 ; 03 16530 7,0530 00000 1 DS %00000 ; 0416531 7,0531 00000 1 DS %00000 ; 04 16532 7,0532 00000 1 DS %00000 ; 0516533 7,0533 00000 1 DS %00000 ; 05 16534 7,0534 00000 1 DS %00000 ; 0616535 7,0535 00000 1 DS %00000 ; 06 16536 7,0536 00000 1 DS %00000 ; 0716537 7,0537 00000 1 DS %00000 ; 07 16540 7,0540 00000 1 DS %00000 ; 1016541 7,0541 00000 1 DS %00000 ; 10 16542 7,0542 00000 1 DS %00000 ; 1116543 7,0543 00000 1 DS %00000 ; 11 16544 7,0544 00000 1 DS %00000 ; 1216545 7,0545 00000 1 DS %00000 ; 12 16546 7,0546 00000 1 DS %00000 ; 1316547 7,0547 00000 1 DS %00000 ; 13 16550 7,0550 00000 1 DS %00000 ; 1416551 7,0551 00000 1 DS %00000 ; 14 16552 7,0552 00000 1 DS %00000 ; 1516553 7,0553 00000 1 DS %00000 ; 15 16554 7,0554 00000 1 DS %00000 ; 1616555 7,0555 00000 1 DS %00000 ; 16 16556 7,0556 00000 1 DS %00000 ; 1716557 7,0557 00000 1 DS %00000 ; 17 16560 7,0560 00000 1 DS %00000 ; 2016561 7,0561 00000 1 DS %00000 ; 20 16562 7,0562 00000 1 DS %00000 ; 2116563 7,0563 00000 1 DS %00000 ; 21 16564 7,0564 00000 1 DS %00000 ; 2216565 7,0565 00000 1 DS %00000 ; 22 16566 7,0566 00000 1 DS %00000 ; 2316567 7,0567 00000 1 DS %00000 ; 23 ;-------------------------------------------------------------------------- ; SCALE FACTOR OUTPUT TABLE (SFOUTAB) ; Indexed by SF constant code number x 2 PPPPP (0-19 decimal; 0-23 octal) ; ; Adapted from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, p.273. ;-------------------------------------------------------------------------- SFOUTAB EQU * 16570 7,0570 05174 0 DS %05174 ; 00 - whole, DP time (sec)16571 7,0571 13261 0 DS %13261 ; 00 16572 7,0572 00000 1 DS %00000 ; 01 - spare16573 7,0573 00000 1 DS %00000 ; 01 16574 7,0574 00000 1 DS %00000 ; 02 - CDU degrees, Y optics degrees16575 7,0575 00000 1 DS %00000 ; 02 (SFCONs in DEGOURSF, OPTDEGOUT
16576 7,0576 00000 1 DS %00000 ; 0316577 7,0577 00000 1 DS %00000 ; 03 16600 7,0600 00000 1 DS %00000 ; 0416601 7,0601 00000 1 DS %00000 ; 04 16602 7,0602 00000 1 DS %00000 ; 0516603 7,0603 00000 1 DS %00000 ; 05 16604 7,0604 00000 1 DS %00000 ; 0616605 7,0605 00000 1 DS %00000 ; 06 16606 7,0606 00000 1 DS %00000 ; 0716607 7,0607 00000 1 DS %00000 ; 07 16610 7,0610 00000 1 DS %00000 ; 1016611 7,0611 00000 1 DS %00000 ; 10 16612 7,0612 00000 1 DS %00000 ; 1116613 7,0613 00000 1 DS %00000 ; 11 16614 7,0614 00000 1 DS %00000 ; 1216615 7,0615 00000 1 DS %00000 ; 12 16616 7,0616 00000 1 DS %00000 ; 1316617 7,0617 00000 1 DS %00000 ; 13 16620 7,0620 00000 1 DS %00000 ; 1416621 7,0621 00000 1 DS %00000 ; 14 16622 7,0622 00000 1 DS %00000 ; 1516623 7,0623 00000 1 DS %00000 ; 15 16624 7,0624 00000 1 DS %00000 ; 1616625 7,0625 00000 1 DS %00000 ; 16 16626 7,0626 00000 1 DS %00000 ; 1716627 7,0627 00000 1 DS %00000 ; 17 16630 7,0630 00000 1 DS %00000 ; 2016631 7,0631 00000 1 DS %00000 ; 20 16632 7,0632 00000 1 DS %00000 ; 2116633 7,0633 00000 1 DS %00000 ; 21 16634 7,0634 00000 1 DS %00000 ; 2216635 7,0635 00000 1 DS %00000 ; 22 16636 7,0636 00000 1 DS %00000 ; 2316637 7,0637 00000 1 DS %00000 ; 23 ; SCALE FACTOR INPUT ROUTINE TABLE is on pp. 342, 343 of COLOSSUS ; SCALE FACTOR OUTPUT ROUTINE TABLE is on p. 329 of COLOSSUS ;-------------------------------------------------------------------------- ; MIXED NOUN ADDRESS TABLE (IDADDTAB) ; ; Adapted from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, p.274. ;-------------------------------------------------------------------------- ; ** currently, the table is not populated ** IDADDTAB EQU * 16640 7,0640 00000 1 DS %0 ; 40 - spare component16641 7,0641 00000 1 DS %0 ; 40 - spare component16642 7,0642 00000 1 DS %0 ; 40 - spare component 16643 7,0643 00000 1 DS %0 ; 41 - spare component16644 7,0644 00000 1 DS %0 ; 41 - spare component16645 7,0645 00000 1 DS %0 ; 41 - spare component 16646 7,0646 00000 1 DS %0 ; 42 - spare component16647 7,0647 00000 1 DS %0 ; 42 - spare component16650 7,0650 00000 1 DS %0 ; 42 - spare component 16651 7,0651 00000 1 DS %0 ; 43 - spare component16652 7,0652 00000 1 DS %0 ; 43 - spare component16653 7,0653 00000 1 DS %0 ; 43 - spare component 16654 7,0654 00000 1 DS %0 ; 44 - spare component16655 7,0655 00000 1 DS %0 ; 44 - spare component16656 7,0656 00000 1 DS %0 ; 44 - spare component 16657 7,0657 00000 1 DS %0 ; 45 - spare component
16660 7,0660 00000 1 DS %0 ; 45 - spare component16661 7,0661 00000 1 DS %0 ; 45 - spare component 16662 7,0662 00000 1 DS %0 ; 46 - spare component16663 7,0663 00000 1 DS %0 ; 46 - spare component16664 7,0664 00000 1 DS %0 ; 46 - spare component 16665 7,0665 00000 1 DS %0 ; 47 - spare component16666 7,0666 00000 1 DS %0 ; 47 - spare component16667 7,0667 00000 1 DS %0 ; 47 - spare component 16670 7,0670 00000 1 DS %0 ; 48 - spare component16671 7,0671 00000 1 DS %0 ; 48 - spare component16672 7,0672 00000 1 DS %0 ; 48 - spare component 16673 7,0673 00000 1 DS %0 ; 49 - spare component16674 7,0674 00000 1 DS %0 ; 49 - spare component16675 7,0675 00000 1 DS %0 ; 49 - spare component 16676 7,0676 00000 1 DS %0 ; 50 - spare component16677 7,0677 00000 1 DS %0 ; 50 - spare component16700 7,0700 00000 1 DS %0 ; 50 - spare component 16701 7,0701 00000 1 DS %0 ; 51 - spare component16702 7,0702 00000 1 DS %0 ; 51 - spare component16703 7,0703 00000 1 DS %0 ; 51 - spare component 16704 7,0704 00000 1 DS %0 ; 52 - spare component16705 7,0705 00000 1 DS %0 ; 52 - spare component16706 7,0706 00000 1 DS %0 ; 52 - spare component 16707 7,0707 00000 1 DS %0 ; 53 - spare component16710 7,0710 00000 1 DS %0 ; 53 - spare component16711 7,0711 00000 1 DS %0 ; 53 - spare component 16712 7,0712 00000 1 DS %0 ; 54 - spare component16713 7,0713 00000 1 DS %0 ; 54 - spare component16714 7,0714 00000 1 DS %0 ; 54 - spare component 16715 7,0715 00000 1 DS %0 ; 55 - spare component16716 7,0716 00000 1 DS %0 ; 55 - spare component16717 7,0717 00000 1 DS %0 ; 55 - spare component 16720 7,0720 00000 1 DS %0 ; 56 - spare component16721 7,0721 00000 1 DS %0 ; 56 - spare component16722 7,0722 00000 1 DS %0 ; 56 - spare component 16723 7,0723 00000 1 DS %0 ; 57 - spare component16724 7,0724 00000 1 DS %0 ; 57 - spare component16725 7,0725 00000 1 DS %0 ; 57 - spare component 16726 7,0726 00000 1 DS %0 ; 58 - spare component16727 7,0727 00000 1 DS %0 ; 58 - spare component16730 7,0730 00000 1 DS %0 ; 58 - spare component 16731 7,0731 00000 1 DS %0 ; 59 - spare component16732 7,0732 00000 1 DS %0 ; 59 - spare component16733 7,0733 00000 1 DS %0 ; 59 - spare component 16734 7,0734 00000 1 DS %0 ; 60 - spare component16735 7,0735 00000 1 DS %0 ; 60 - spare component16736 7,0736 00000 1 DS %0 ; 60 - spare component 16737 7,0737 00000 1 DS %0 ; 61 - spare component16740 7,0740 00000 1 DS %0 ; 61 - spare component16741 7,0741 00000 1 DS %0 ; 61 - spare component 16742 7,0742 00000 1 DS %0 ; 62 - spare component16743 7,0743 00000 1 DS %0 ; 62 - spare component16744 7,0744 00000 1 DS %0 ; 62 - spare component 16745 7,0745 00000 1 DS %0 ; 63 - spare component16746 7,0746 00000 1 DS %0 ; 63 - spare component16747 7,0747 00000 1 DS %0 ; 63 - spare component 16750 7,0750 00000 1 DS %0 ; 64 - spare component16751 7,0751 00000 1 DS %0 ; 64 - spare component16752 7,0752 00000 1 DS %0 ; 64 - spare component 16753 7,0753 00000 1 DS %0 ; 65 - spare component16754 7,0754 00000 1 DS %0 ; 65 - spare component16755 7,0755 00000 1 DS %0 ; 65 - spare component 16756 7,0756 00000 1 DS %0 ; 66 - spare component16757 7,0757 00000 1 DS %0 ; 66 - spare component16760 7,0760 00000 1 DS %0 ; 66 - spare component
16761 7,0761 00000 1 DS %0 ; 67 - spare component16762 7,0762 00000 1 DS %0 ; 67 - spare component16763 7,0763 00000 1 DS %0 ; 67 - spare component 16764 7,0764 00000 1 DS %0 ; 68 - spare component16765 7,0765 00000 1 DS %0 ; 68 - spare component16766 7,0766 00000 1 DS %0 ; 68 - spare component 16767 7,0767 00000 1 DS %0 ; 69 - spare component16770 7,0770 00000 1 DS %0 ; 69 - spare component16771 7,0771 00000 1 DS %0 ; 69 - spare component 16772 7,0772 00000 1 DS %0 ; 70 - spare component16773 7,0773 00000 1 DS %0 ; 70 - spare component16774 7,0774 00000 1 DS %0 ; 70 - spare component 16775 7,0775 00000 1 DS %0 ; 71 - spare component16776 7,0776 00000 1 DS %0 ; 71 - spare component16777 7,0777 00000 1 DS %0 ; 71 - spare component 17000 7,1000 00000 1 DS %0 ; 72 - spare component17001 7,1001 00000 1 DS %0 ; 72 - spare component17002 7,1002 00000 1 DS %0 ; 72 - spare component 17003 7,1003 00000 1 DS %0 ; 73 - spare component17004 7,1004 00000 1 DS %0 ; 73 - spare component17005 7,1005 00000 1 DS %0 ; 73 - spare component 17006 7,1006 00000 1 DS %0 ; 74 - spare component17007 7,1007 00000 1 DS %0 ; 74 - spare component17010 7,1010 00000 1 DS %0 ; 74 - spare component 17011 7,1011 00000 1 DS %0 ; 75 - spare component17012 7,1012 00000 1 DS %0 ; 75 - spare component17013 7,1013 00000 1 DS %0 ; 75 - spare component 17014 7,1014 00000 1 DS %0 ; 76 - spare component17015 7,1015 00000 1 DS %0 ; 76 - spare component17016 7,1016 00000 1 DS %0 ; 76 - spare component 17017 7,1017 00000 1 DS %0 ; 77 - spare component17020 7,1020 00000 1 DS %0 ; 77 - spare component17021 7,1021 00000 1 DS %0 ; 77 - spare component 17022 7,1022 00000 1 DS %0 ; 78 - spare component17023 7,1023 00000 1 DS %0 ; 78 - spare component17024 7,1024 00000 1 DS %0 ; 78 - spare component 17025 7,1025 00000 1 DS %0 ; 79 - spare component17026 7,1026 00000 1 DS %0 ; 79 - spare component17027 7,1027 00000 1 DS %0 ; 79 - spare component 17030 7,1030 00000 1 DS %0 ; 80 - spare component17031 7,1031 00000 1 DS %0 ; 80 - spare component17032 7,1032 00000 1 DS %0 ; 80 - spare component 17033 7,1033 00000 1 DS %0 ; 81 - spare component17034 7,1034 00000 1 DS %0 ; 81 - spare component17035 7,1035 00000 1 DS %0 ; 81 - spare component 17036 7,1036 00000 1 DS %0 ; 82 - spare component17037 7,1037 00000 1 DS %0 ; 82 - spare component17040 7,1040 00000 1 DS %0 ; 82 - spare component 17041 7,1041 00000 1 DS %0 ; 83 - spare component17042 7,1042 00000 1 DS %0 ; 83 - spare component17043 7,1043 00000 1 DS %0 ; 83 - spare component 17044 7,1044 00000 1 DS %0 ; 84 - spare component17045 7,1045 00000 1 DS %0 ; 84 - spare component17046 7,1046 00000 1 DS %0 ; 84 - spare component 17047 7,1047 00000 1 DS %0 ; 85 - spare component17050 7,1050 00000 1 DS %0 ; 85 - spare component17051 7,1051 00000 1 DS %0 ; 85 - spare component 17052 7,1052 00000 1 DS %0 ; 86 - spare component17053 7,1053 00000 1 DS %0 ; 86 - spare component17054 7,1054 00000 1 DS %0 ; 86 - spare component 17055 7,1055 00000 1 DS %0 ; 87 - spare component17056 7,1056 00000 1 DS %0 ; 87 - spare component17057 7,1057 00000 1 DS %0 ; 87 - spare component 17060 7,1060 00000 1 DS %0 ; 88 - spare component17061 7,1061 00000 1 DS %0 ; 88 - spare component17062 7,1062 00000 1 DS %0 ; 88 - spare component
17063 7,1063 00000 1 DS %0 ; 89 - spare component17064 7,1064 00000 1 DS %0 ; 89 - spare component17065 7,1065 00000 1 DS %0 ; 89 - spare component 17066 7,1066 00000 1 DS %0 ; 90 - spare component17067 7,1067 00000 1 DS %0 ; 90 - spare component17070 7,1070 00000 1 DS %0 ; 90 - spare component 17071 7,1071 00000 1 DS %0 ; 91 - spare component17072 7,1072 00000 1 DS %0 ; 91 - spare component17073 7,1073 00000 1 DS %0 ; 91 - spare component 17074 7,1074 00000 1 DS %0 ; 92 - spare component17075 7,1075 00000 1 DS %0 ; 92 - spare component17076 7,1076 00000 1 DS %0 ; 92 - spare component 17077 7,1077 00000 1 DS %0 ; 93 - spare component17100 7,1100 00000 1 DS %0 ; 93 - spare component17101 7,1101 00000 1 DS %0 ; 93 - spare component 17102 7,1102 00000 1 DS %0 ; 94 - spare component17103 7,1103 00000 1 DS %0 ; 94 - spare component17104 7,1104 00000 1 DS %0 ; 94 - spare component 17105 7,1105 00000 1 DS %0 ; 95 - spare component17106 7,1106 00000 1 DS %0 ; 95 - spare component17107 7,1107 00000 1 DS %0 ; 95 - spare component 17110 7,1110 00000 1 DS %0 ; 96 - spare component17111 7,1111 00000 1 DS %0 ; 96 - spare component17112 7,1112 00000 1 DS %0 ; 96 - spare component 17113 7,1113 00000 1 DS %0 ; 97 - spare component17114 7,1114 00000 1 DS %0 ; 97 - spare component17115 7,1115 00000 1 DS %0 ; 97 - spare component 17116 7,1116 00000 1 DS %0 ; 98 - spare component17117 7,1117 00000 1 DS %0 ; 98 - spare component17120 7,1120 00000 1 DS %0 ; 98 - spare component 17121 7,1121 00000 1 DS %0 ; 99 - spare component17122 7,1122 00000 1 DS %0 ; 99 - spare component17123 7,1123 00000 1 DS %0 ; 99 - spare component ; end of mixed noun address table ;-------------------------------------------------------------------------- ; MIXED NOUN SCALE FACTOR ROUTINE TABLE (RUTMXTAB) ; ; Adapted from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, p.278. ;-------------------------------------------------------------------------- ; ** currently, the table is not populated ** RUTMXTAB EQU * 17124 7,1124 00000 1 DS %0 ; 40 - spare17125 7,1125 00000 1 DS %0 ; 41 - spare17126 7,1126 00000 1 DS %0 ; 42 - spare17127 7,1127 00000 1 DS %0 ; 43 - spare17130 7,1130 00000 1 DS %0 ; 44 - spare17131 7,1131 00000 1 DS %0 ; 45 - spare17132 7,1132 00000 1 DS %0 ; 46 - spare17133 7,1133 00000 1 DS %0 ; 47 - spare17134 7,1134 00000 1 DS %0 ; 48 - spare17135 7,1135 00000 1 DS %0 ; 49 - spare17136 7,1136 00000 1 DS %0 ; 50 - spare17137 7,1137 00000 1 DS %0 ; 51 - spare17140 7,1140 00000 1 DS %0 ; 52 - spare17141 7,1141 00000 1 DS %0 ; 53 - spare17142 7,1142 00000 1 DS %0 ; 54 - spare17143 7,1143 00000 1 DS %0 ; 55 - spare17144 7,1144 00000 1 DS %0 ; 56 - spare17145 7,1145 00000 1 DS %0 ; 57 - spare17146 7,1146 00000 1 DS %0 ; 58 - spare17147 7,1147 00000 1 DS %0 ; 59 - spare17150 7,1150 00000 1 DS %0 ; 60 - spare17151 7,1151 00000 1 DS %0 ; 61 - spare17152 7,1152 00000 1 DS %0 ; 62 - spare17153 7,1153 00000 1 DS %0 ; 63 - spare17154 7,1154 00000 1 DS %0 ; 64 - spare17155 7,1155 00000 1 DS %0 ; 65 - spare17156 7,1156 00000 1 DS %0 ; 66 - spare17157 7,1157 00000 1 DS %0 ; 67 - spare17160 7,1160 00000 1 DS %0 ; 68 - spare17161 7,1161 00000 1 DS %0 ; 69 - spare17162 7,1162 00000 1 DS %0 ; 70 - spare
17163 7,1163 00000 1 DS %0 ; 71 - spare17164 7,1164 00000 1 DS %0 ; 72 - spare17165 7,1165 00000 1 DS %0 ; 73 - spare17166 7,1166 00000 1 DS %0 ; 74 - spare17167 7,1167 00000 1 DS %0 ; 75 - spare17170 7,1170 00000 1 DS %0 ; 76 - spare17171 7,1171 00000 1 DS %0 ; 77 - spare17172 7,1172 00000 1 DS %0 ; 78 - spare17173 7,1173 00000 1 DS %0 ; 79 - spare17174 7,1174 00000 1 DS %0 ; 80 - spare17175 7,1175 00000 1 DS %0 ; 81 - spare17176 7,1176 00000 1 DS %0 ; 82 - spare17177 7,1177 00000 1 DS %0 ; 83 - spare17200 7,1200 00000 1 DS %0 ; 84 - spare17201 7,1201 00000 1 DS %0 ; 85 - spare17202 7,1202 00000 1 DS %0 ; 86 - spare17203 7,1203 00000 1 DS %0 ; 87 - spare17204 7,1204 00000 1 DS %0 ; 88 - spare17205 7,1205 00000 1 DS %0 ; 89 - spare17206 7,1206 00000 1 DS %0 ; 90 - spare17207 7,1207 00000 1 DS %0 ; 91 - spare17210 7,1210 00000 1 DS %0 ; 92 - spare17211 7,1211 00000 1 DS %0 ; 93 - spare17212 7,1212 00000 1 DS %0 ; 94 - spare17213 7,1213 00000 1 DS %0 ; 95 - spare17214 7,1214 00000 1 DS %0 ; 96 - spare17215 7,1215 00000 1 DS %0 ; 97 - spare17216 7,1216 00000 1 DS %0 ; 98 - spare17217 7,1217 00000 1 DS %0 ; 99 - spare ; end of mixed noun scale factor routine table BANK42_4 EQU * ; extended verb tables ORG BANK43_1 INCL bank43_1.asm ; COLOSSUS pp. 230-232 ;========================================================================== ; DISPLAY ROUTINES (file:bank43_1.asm) ; ; Adapted from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, pp. 230. ;========================================================================== ;-------------------------------------------------------------------------- ; GOEXTVB -- EXTENDED VERBS ; ; Adapted from the AGC Block II COLOSSUS rev 249 assembly listing, ; Oct 28, 1968, p.230. ;-------------------------------------------------------------------------- GOEXTVB EQU * 20000 10,0000 2 0,0130 1 INDEX MPAC ; verb-40 is in MPAC20001 10,0001 0 10,6002 0 TC LST2FAN ; fan as before LST2FAN EQU * 20002 10,0002 0 10,6076 0 TC ALM_END ; VB40 - spare20003 10,0003 0 10,6076 0 TC ALM_END ; VB41 - spare20004 10,0004 0 10,6076 0 TC ALM_END ; VB42 - spare20005 10,0005 0 10,6076 0 TC ALM_END ; VB43 - spare20006 10,0006 0 10,6076 0 TC ALM_END ; VB44 - spare20007 10,0007 0 10,6076 0 TC ALM_END ; VB45 - spare20010 10,0010 0 10,6076 0 TC ALM_END ; VB46 - spare20011 10,0011 0 10,6076 0 TC ALM_END ; VB47 - spare20012 10,0012 0 10,6076 0 TC ALM_END ; VB48 - spare20013 10,0013 0 10,6076 0 TC ALM_END ; VB49 - spare20014 10,0014 0 10,6076 0 TC ALM_END ; VB50 - spare20015 10,0015 0 10,6076 0 TC ALM_END ; VB51 - spare20016 10,0016 0 10,6076 0 TC ALM_END ; VB52 - spare20017 10,0017 0 10,6076 0 TC ALM_END ; VB53 - spare20020 10,0020 0 10,6076 0 TC ALM_END ; VB54 - spare20021 10,0021 0 10,6076 0 TC ALM_END ; VB55 - spare20022 10,0022 0 10,6076 0 TC ALM_END ; VB56 - spare20023 10,0023 0 10,6076 0 TC ALM_END ; VB57 - spare20024 10,0024 0 10,6076 0 TC ALM_END ; VB58 - spare20025 10,0025 0 10,6076 0 TC ALM_END ; VB59 - spare20026 10,0026 0 10,6076 0 TC ALM_END ; VB60 - spare20027 10,0027 0 10,6076 0 TC ALM_END ; VB61 - spare20030 10,0030 0 10,6076 0 TC ALM_END ; VB62 - spare20031 10,0031 0 10,6076 0 TC ALM_END ; VB63 - spare20032 10,0032 0 10,6076 0 TC ALM_END ; VB64 - spare20033 10,0033 0 10,6076 0 TC ALM_END ; VB65 - spare20034 10,0034 0 10,6076 0 TC ALM_END ; VB66 - spare20035 10,0035 0 10,6076 0 TC ALM_END ; VB67 - spare20036 10,0036 0 10,6076 0 TC ALM_END ; VB68 - spare20037 10,0037 0 10,6076 0 TC ALM_END ; VB69 - spare20040 10,0040 0 10,6076 0 TC ALM_END ; VB70 - spare
20041 10,0041 0 10,6076 0 TC ALM_END ; VB71 - spare20042 10,0042 0 10,6076 0 TC ALM_END ; VB72 - spare20043 10,0043 0 10,6076 0 TC ALM_END ; VB73 - spare20044 10,0044 0 10,6076 0 TC ALM_END ; VB74 - spare20045 10,0045 0 10,6076 0 TC ALM_END ; VB75 - spare20046 10,0046 0 10,6076 0 TC ALM_END ; VB76 - spare20047 10,0047 0 10,6076 0 TC ALM_END ; VB77 - spare20050 10,0050 0 10,6076 0 TC ALM_END ; VB78 - spare20051 10,0051 0 10,6076 0 TC ALM_END ; VB79 - spare20052 10,0052 0 10,6076 0 TC ALM_END ; VB80 - spare20053 10,0053 0 10,6076 0 TC ALM_END ; VB81 - spare20054 10,0054 0 10,6076 0 TC ALM_END ; VB82 - spare20055 10,0055 0 10,6076 0 TC ALM_END ; VB83 - spare20056 10,0056 0 10,6076 0 TC ALM_END ; VB84 - spare20057 10,0057 0 10,6076 0 TC ALM_END ; VB85 - spare20060 10,0060 0 10,6076 0 TC ALM_END ; VB86 - spare20061 10,0061 0 10,6076 0 TC ALM_END ; VB87 - spare20062 10,0062 0 10,6076 0 TC ALM_END ; VB88 - spare20063 10,0063 0 10,6076 0 TC ALM_END ; VB89 - spare20064 10,0064 0 10,6076 0 TC ALM_END ; VB90 - spare20065 10,0065 0 10,6076 0 TC ALM_END ; VB91 - spare20066 10,0066 0 10,6076 0 TC ALM_END ; VB92 - spare20067 10,0067 0 10,6076 0 TC ALM_END ; VB93 - spare20070 10,0070 0 10,6076 0 TC ALM_END ; VB94 - spare20071 10,0071 0 10,6076 0 TC ALM_END ; VB95 - spare20072 10,0072 0 10,6076 0 TC ALM_END ; VB96 - spare20073 10,0073 0 10,6076 0 TC ALM_END ; VB97 - spare20074 10,0074 0 10,6076 0 TC ALM_END ; VB98 - spare20075 10,0075 0 10,6076 0 TC ALM_END ; VB99 - spare ALM_END EQU * 20076 10,0076 0 2,4701 0 TC FALTON ; turn on operator error light20077 10,0077 0 1,3653 1 GOPIN TC POSTJUMP 20100 10,0100 05067 0 FCADR PINBRNCH BANK43_2 EQU * ;-------------------------------------------------------------------------- ; TEST JOBS & TASKS ;-------------------------------------------------------------------------- ORG BANKFF_6 ;-------------------------------------------------------------------------- ; MAJOR MODES ;-------------------------------------------------------------------------- ORG BANK11 ;-------------------------------------------------------------------------- ; P00 CMC IDLE PROGRAM ; ; Does nothing ;-------------------------------------------------------------------------- P00 EQU * ; Start any jobs or tasks needed at AGC initialization. 22000 11,0000 3 11,6004 0 CAF time1 ; add a test task22001 11,0001 0 1,2232 0 TC WAITLIST 22002 11,0002 22005 1 CADR task1 ; 14-bit task address22003 11,0003 0 1,2723 0 TC ENDOFJOB ; TEST CODE - task started by P00 22004 11,0004 01750 1 time1 DS 1000 ; 10 seconds task1 EQU * 22005 11,0005 3 11,6011 1 XCH prio1 ; job priority22006 11,0006 0 1,3162 1 TC NOVAC 22007 11,0007 22012 1 CADR job1 ; 14 bit job address 22010 11,0010 0 1,2413 0 TC TASKOVER ; TEST CODE - job started by task 22011 11,0011 00003 1 prio1 DS %3 ; lowest priority job1 EQU * 22012 11,0012 3 1,2050 0 CAF ZERO
22013 11,0013 6 0,0053 1 AD %53 22014 11,0014 6 1,2051 1 AD ONE 22015 11,0015 5 0,0053 1 TS %53 ; incr data at this address22016 11,0016 0 1,2723 0 TC ENDOFJOB ;-------------------------------------------------------------------------- ; P01 DEMO PROGRAM ; ; Calls pinball: verb 1, noun 4. ;-------------------------------------------------------------------------- 22017 11,0017 00204 1 nvcode1 DS %0204 ; verb 01, noun 0422020 11,0020 22024 1 restart1_addr DS P01_restart 22021 11,0021 00042 1 tcadr1 DS %42 P01 EQU * 22022 11,0022 3 11,6021 1 CAF tcadr1 ; load 'machine address to be specified'22023 11,0023 5 0,0132 1 TS MPAC+2 P01_restart EQU * 22024 11,0024 3 11,6017 1 CAF nvcode1 22025 11,0025 0 2,4503 0 TC NVSUB 22026 11,0026 0 11,6030 1 TC *+2 ; display busy22027 11,0027 0 1,2723 0 TC ENDOFJOB ; execution of verb/noun succeeded 22030 11,0030 3 11,6020 0 CAF restart1_addr 22031 11,0031 0 2,5001 0 TC NVSUBUSY ; go to sleep until display released 22032 11,0032 0 1,2723 0 TC ENDOFJOB ; error: another job is already waiting ;-------------------------------------------------------------------------- ; P02 DEMO PROGRAM ; ; Calls pinball: verb 21, noun 2. ; ; Sleeps if DSKY is busy until KEYREL. Executes verb 21, noun 2 to do ; an external load. Then it sleeps with ENDIDLE until the user loads ; the data or terminatest the load with PROCEED or TERMINATE. ; NOTE: routines that call ENDIDLE must be in fixed-switchable memory ;-------------------------------------------------------------------------- 22033 11,0033 05202 1 nvcode2 DS %05202 ; verb 21, noun 0222034 11,0034 22040 0 restart2_addr DS P02_restart 22035 11,0035 00042 1 tcadr2 DS %42 P02 EQU * 22036 11,0036 3 11,6035 1 CAF tcadr2 22037 11,0037 5 0,0132 1 TS MPAC+2 P02_restart EQU * 22040 11,0040 3 11,6033 1 CAF nvcode2 22041 11,0041 0 2,4503 0 TC NVSUB 22042 11,0042 0 11,6044 1 TC *+2 ; display busy22043 11,0043 0 11,6047 1 TC P02_wait ; execution of verb/noun succeeded 22044 11,0044 3 11,6034 0 CAF restart2_addr 22045 11,0045 0 2,5001 0 TC NVSUBUSY ; go to sleep until display released22046 11,0046 0 1,2723 0 TC ENDOFJOB ; another job is already sleeping P02_wait EQU * 22047 11,0047 0 2,4541 0 TC ENDIDLE 22050 11,0050 0 11,6060 1 TC P02_ter ; terminate22051 11,0051 0 11,6055 1 TC P02_pwd ; proceed without data22052 11,0052 3 1,2051 1 CAF ONE ; data in22053 11,0053 5 0,0043 0 TS %43 ; set loc=122054 11,0054 0 1,2723 0 TC ENDOFJOB P02_pwd EQU * ; proceed without data22055 11,0055 3 1,2052 1 CAF TWO 22056 11,0056 5 0,0043 0 TS %43 ; set loc=222057 11,0057 0 1,2723 0 TC ENDOFJOB P02_ter EQU * ; terminate22060 11,0060 3 1,2053 0 CAF THREE 22061 11,0061 5 0,0043 0 TS %43 ; set loc=322062 11,0062 0 1,2723 0 TC ENDOFJOB ;-------------------------------------------------------------------------- ; P03 DEMO PROGRAM ;
; Nearly identical to P02, except that the job does not go to sleep ; waiting for the load with ENDIDLE. Instead, it busy-waits on LOADSTAT. ; NOTE: routines that call ENDIDLE must be in fixed-switchable memory ;-------------------------------------------------------------------------- 22063 11,0063 05202 1 nvcode3 DS %05202 ; verb 21, noun 0222064 11,0064 22070 0 restart3_addr DS P03_restart 22065 11,0065 00042 1 tcadr3 DS %42 P03 EQU * 22066 11,0066 3 11,6065 1 CAF tcadr3 22067 11,0067 5 0,0132 1 TS MPAC+2 P03_restart EQU * 22070 11,0070 3 11,6063 1 CAF nvcode3 22071 11,0071 0 2,4503 0 TC NVSUB 22072 11,0072 0 11,6074 1 TC *+2 ; display busy22073 11,0073 0 11,6077 1 TC P03_wait ; execution of verb/noun succeeded 22074 11,0074 3 11,6064 0 CAF restart3_addr 22075 11,0075 0 2,5001 0 TC NVSUBUSY ; go to sleep until display released22076 11,0076 0 1,2723 0 TC ENDOFJOB ; another job is already sleeping P03_wait EQU * 22077 11,0077 1 0,0503 0 CCS LOADSTAT 22100 11,0100 0 11,6115 1 TC P03_pwd ; >0, verb "proceed w/o data" has been keyedin22101 11,0101 0 11,6107 1 TC P03_yield ; +0, waiting for data22102 11,0102 0 11,6120 1 TC P03_ter ; <0, verb "terminate" has been keyed in22103 11,0103 3 0,0000 1 NOOP ; -0, load has been completed 22104 11,0104 3 1,2051 1 CAF ONE ; data in22105 11,0105 5 0,0043 0 TS %43 ; set loc=122106 11,0106 0 1,2723 0 TC ENDOFJOB P03_yield EQU * 22107 11,0107 3 1,2051 1 CAF ONE 22110 11,0110 6 0,0043 0 AD %43 22111 11,0111 5 0,0043 0 TS %43 ; incr loc while busy-waiting 22112 11,0112 1 0,0307 1 CCS newJob ; yield to higher priority job?22113 11,0113 0 1,2733 1 TC CHANG1 ; yes22114 11,0114 0 11,6077 1 TC P03_wait ; no, keep busy-waiting P03_pwd EQU * ; proceed without data22115 11,0115 3 1,2052 1 CAF TWO 22116 11,0116 5 0,0043 0 TS %43 ; set loc=222117 11,0117 0 1,2723 0 TC ENDOFJOB P03_ter EQU * ; terminate22120 11,0120 3 1,2053 0 CAF THREE 22121 11,0121 5 0,0043 0 TS %43 ; set loc=322122 11,0122 0 1,2723 0 TC ENDOFJOB ;-------------------------------------------------------------------------- ; P04 DEMO PROGRAM ; ; Calls pinball: monitor verb 11, noun 04. ;-------------------------------------------------------------------------- 22123 11,0123 02604 1 nvcode4 DS %02604 ; verb 11, noun 0422124 11,0124 22131 1 restart4_addr DS P04_restart 22125 11,0125 00042 1 tcadr4 DS %42 ;mon_option DS %6 22126 11,0126 02206 1 mon_option DS %2206 P04 EQU * 22127 11,0127 3 11,6125 1 CAF tcadr4 ; load 'machine address to be specified'22130 11,0130 5 0,0132 1 TS MPAC+2 P04_restart EQU * 22131 11,0131 3 11,6126 1 CAF mon_option ; paste verb 09, blank R2, R322132 11,0132 5 0,0564 0 TS NVSUB_L 22133 11,0133 3 11,6123 1 CAF nvcode4 22134 11,0134 0 2,4507 1 TC NVMONOPT ; was NVSUB 22135 11,0135 0 11,6137 1 TC *+2 ; display busy22136 11,0136 0 1,2723 0 TC ENDOFJOB ; execution of verb/noun succeeded 22137 11,0137 3 11,6124 0 CAF restart4_addr 22140 11,0140 0 2,5001 0 TC NVSUBUSY ; go to sleep until display released
22141 11,0141 0 1,2723 0 TC ENDOFJOB ; error: another job is already waiting ;-------------------------------------------------------------------------- ; P78 DEMO PROGRAM ; ;-------------------------------------------------------------------------- P78 EQU * 22142 11,0142 3 1,2050 0 CAF ZERO 22143 11,0143 6 0,0051 0 AD %51 22144 11,0144 6 1,2051 1 AD ONE 22145 11,0145 5 0,0051 0 TS %51 ; incr data at this address22146 11,0146 0 1,2723 0 TC ENDOFJOB ;-------------------------------------------------------------------------- ; P79 DEMO PROGRAM ; ;-------------------------------------------------------------------------- P79 EQU * 22147 11,0147 3 1,2050 0 CAF ZERO 22150 11,0150 6 0,0052 0 AD %52 22151 11,0151 6 1,2051 1 AD ONE 22152 11,0152 5 0,0052 0 TS %52 ; incr data at this address22153 11,0153 0 1,2723 0 TC ENDOFJOB
Assembly complete. Errors = 0
Symbol table:BANK0 000057 MAXTASK 000007 MAXVAL 037777 MAXDELAY 027340 MAXTIMEOUT 010440 TSKTIME 000000 TSKADDR 000001 TRECSZ 000002 WL_taskList 000057 WL_IN_saveQ 000075 WL_IN_taskPtr 000076 WL_IN_loopCnt 000077 WL_AT_saveQ 000100 WL_AT_taskPtr 000101 WL_AT_newTime 000102 WL_AT_timeLeft 000103 WL_AT_loopCnt 000104 WL_T3_saveQ 000105 WL_T3_oldBank 000106 WL_ST_saveQ 000107 WL_ST_taskPtr 000110 WL_ST_newTime 000111 WL_ST_loopCnt 000112 WL_RT_saveQ 000113 WL_RT_runAddr 000114 WL_RM_saveQ 000115 WL_RM_taskPtr 000116 WL_RM_taskPtr2 000117 WL_RM_loopCnt 000120 WL_RM_retval 000121 WL_IS_newTime 000122 WL_IS_newAddr 000123 WL_IS_saveQ 000124 WL_IS_taskPtr 000125 WL_IS_taskPtr2 000126 WL_IS_loopCnt 000127 MAXJOBS 000007 JRECSZ 000015 EX_currentJob 000130 MPAC 000130 MODE 000137 LOC 000140 BANKSET 000141 PUSHLOC 000142 PRIORITY 000143 JOBPRIOBASE 000144 JREC0 000145 JREC1 000162 JREC2 000177 JREC3 000214 JREC4 000231 JREC5 000246 JREC6 000263 EX_jobList 000300 LOCCTR 000300 CHGJOB 000001 KEEPJOB 000000 newJob 000307 EX_JW_saveQ 000310 EX_JW_loopCnt 000311 EX_JW_CADR 000312 EX_JW_foundit 000313 EX_JW_jobPtr 000314 EX_JW_jobPtr2 000315 EX_JW_fndIndx 000316 EX_AJ_saveQ 000317 EX_AJ_loopCnt 000320 EX_AJ_jobPrio 000321 EX_AJ_jobPtr 000322 EX_AJ_field 000323 EX_AJ_findx 000324 EX_IN_saveQ 000325 EX_IN_loopCnt 000326 EX_IN_jobPtr 000327 EX_IN_recIndex 000330 EX_IN_field 000331 EX_IN_findx 000332 EX_MN_runAddr 000333 EX_MN_field 000334 EX_MN_findx 000335 EX_RM_saveQ 000336 EX_RM_jobPtr 000337 EX_RM_jobPtr2 000340 EX_RM_savePtr 000341 EX_RM_loopCnt 000342 EX_RM_retval 000343 EX_RM_field 000344 EX_RM_findx 000345 EX_IS_newPrio 000346 EX_IS_newPrioB 000347 EX_IS_newLoc 000350 EX_IS_saveQ 000351 EX_IS_jobPtr 000352 EX_IS_jobPtr2 000353 EX_IS_loopCnt 000354 FLAGWRD5 000355 ITEMP1 000356 WAITEXIT 000356 EXECTEM1 000356 ITEMP2 000357 WAITBANK 000357 EXECTEM2 000357 ITEMP3 000360 RUPTSTOR 000360 WAITADR 000360 NEWPRIO 000360 ITEMP4 000361 WAITTEMP 000361 ITEMP5 000362 NEWLOC 000362 ITEMP6 000363 NEWLOCP1 000363 NEWJOB 000364 RUPTREG1 000365 RUPTREG2 000366 RUPTREG3 000367 RUPTREG4 000370 KEYTEMP1 000370 DSRUPTEM 000370 STATE 000371 FLAGFILL 000405 EMDOT 000405 STATEXIT 000407 INTB15P 000411 DSEXIT 000411 EXITEM 000411 BLANKRET 000411 INTBIT15 000412 WRDRET 000412 WDRET 000412 DECRET 000412 _2122REG 000412 ADDRWD 000413 POLISH 000414 UPDATRET 000414 CHAR 000414 ERCNT 000414 DECOUNT 000414 FIXLOC 000415 OVFIND 000416 VBUF 000417 SGNON 000417 NOUNTEM 000417 DISTEM 000417 DECTEM 000417 SGNOFF 000420 NVTEMP 000420 SFTEMP1 000420 HITEMIN 000420 CODE 000421 SFTEMP2 000421 LOWTEMIN 000421 MIXTEMP 000422 SIGNRET 000422 BUF 000425 BUF2 000430 INDEXLOC 000425 SWWORD 000425 SWBIT 000426 MPTEMP 000432 DMPNTEMP 000432 DOTINC 000433
DVSIGN 000433 ESCAPE 000433 ENTRET 000433 DOTRET 000434 DVNORMCT 000434 ESCAPE2 000434 WDCNT 000434 INREL 000434 MATINC 000435 MAXDVSW 000435 POLYCNT 000435 DSPMMTEM 000435 MIXBR 000435 TEM1 000436 POLYRET 000436 DSREL 000436 TEM2 000437 DSMAG 000437 IDADDTEM 000437 TEM3 000440 COUNT 000440 TEM4 000441 LSTPTR 000441 RELRET 000441 FREERET 000441 DSPWDRET 000441 SEPSCRET 000441 SEPMNRET 000441 TEM5 000442 NOUNADD 000442 NNADTEM 000443 NNTYPTEM 000444 IDAD1TEM 000445 IDAD2TEM 000446 IDAD3TEM 000447 RUTMXTEM 000450 DEXDEX 000437 DEX1 000440 DEX2 000441 RTNSAVER 000442 TERM1TMP 000430 RESTREG 000451 NVWORD 000452 MARXNV 000453 NVSAVE 000454 CADRFLSH 000455 CADRMARK 000456 TEMPFLSH 000457 FAILREG 000460 MINDEX 000463 MMNUMBER 000464 DSPCNT 000465 DSPCOUNT 000466 DECBRNCH 000467 VERBREG 000470 NOUNREG 000471 XREG 000472 YREG 000473 ZREG 000474 XREGLP 000475 YREGLP 000476 HITEMOUT 000476 ZREGLP 000477 LOTEMOUT 000477 MODREG 000500 DSPLOCK 000501 REQRET 000502 LOADSTAT 000503 CLPASS 000504 NOUT 000505 NOUNCADR 000506 MONSAVE 000507 MONSAVE1 000510 MONSAVE2 000511 DSPTAB 000512 NVQTEM 000526 NVBNKTEM 000527 VERBSAVE 000530 CADRSTOR 000531 DSPLIST 000532 EXTVRACT 000533 DSPTEM1 000534 DSPTEM2 000537 DSPTEMX 000537 NORMTEM1 000534 OPTIONX 000537 MMTEMP 000542 DSRUPTSW 000543 T4RET 000544 DSPOUTRET 000545 DK_IN_saveQ 000546 LXCH_LPRET 000547 LXCH_A 000550 KP_MPAC 000551 DPTEST_A 000552 DPTEST_Q 000553 REQ_Q 000554 SETNCADR_Q 000555 ALLDC_OC_Q 000556 SFRUTMIX_L 000557 SFCONUM_L 000560 BLANKSUB_Q 000561 GTSF_RET 000562 FR_RETQ 000563 NVSUB_L 000564 NVSUB_A 000565 ENDIDLE_L 000566 NBSUBSY1_L 000567 FLASHRET 000570 PASTE_TMP 000571 NEWMODEA_Q 000572 SHORTMP_A 000573 SHORTMP_OVFL 000574 SHORTMP_OVFH 000575 ADDRWD1 000576 MATH_Q 000577 PRSHRTMP_Q 000600 KEYRET 000601 SAVEQ 000602 BJBANK 000603 BJRET 000604 PJBANK 000605 PJRET 000606 PJA 000607 BCBANK 000610 BCRET 000611 BCA 000612 MBCBANK 000613 MBCRET 000614 MBCA 000615 DCBANK 000616 DCRET 000617 EXTENDER 005777 GOPROG 002000 T3RUPT 002004 ERRUPT 002010 DSRUPT 002014 KEYRUPT 002020 UPRUPT 002024 endRUPT 002030 goT3 002034 goER 002036 goDS 002037 goKEY 002041 goUP 002043 ofbit 002044 NEG0 002045 NEG1 002046 NEG2 002047 ZERO 002050 ONE 002051 TWO 002052 THREE 002053 FOUR 002054 FIVE 002055 SIX 002056 SEVEN 002057 TEN 002060 ELEVEN 002061 BIT15 002062 BIT14 002063 BIT13 002064 BIT12 002065 BIT11 002066 BIT10 002067 BIT9 002070 BIT8 002071 BIT7 002072 BIT6 002073 BIT5 002074 BIT4 002075 BIT3 002076 BIT2 002077 BIT1 002100 LOW7 002101 bankAddr 002102 lowAddr 002103 OCT1400 002104 NOUTCON 002105 POSMAX 002106 CLRMEM 002107 CLRMEM_CHK 002113 CLRMEM_WORD 002116 CLRMEM_VAL 002050 TIME3 000037 CLRMEM_BADDR 000037 CLRMEM_WC 002123 V37BANK 002124 SAMASK 002125 goMAIN 002126 SLAP1 002126 goMMchange 002147 V37XEQ 002153 V37XEQC 002166 WL_taskRecSize 002174 WL_tskLstStart 002175 WL_tskLstEnd 002176 WL_numTasks 002177 WL_numTasks1 002200 WL_maxVal 002201 WL_maxDelay 002202 WL_maxTimeOut 002203 WL_initWL 002204 WL_IN_loop 002213 WAITLIST 002232 WL_AT_noOvf 002264 WL_AT_chkOrder 002270 WL_AT_mkFirst 002306 WL_AT_loop 002311 WL_AT_schTsk 002333 WL_AT_done 002343 WL_TIME3task 002347 WL_runTasks 002362 WL_RT_loop 002364 WL_RT_runIt 002411 TASKOVER 002413 WL_RT_done 002414 WL_schedTask 002417 WL_ST_loop 002436 WL_ST_setT3 002461 WL_ST_noTask 002466 WL_ST_done 002470 WL_insert 002473 WL_IS_loop 002510 WL_IS_bumpPtr 002541 WL_IS_insRec 002552 WL_IS_done 002562 WL_remove 002565 WL_RM_loop 002603 WL_RM_done 002636 EX_WAKE_PRIO 002642 EX_DUMMY_PRIO 002643 EX_SLEEP_PRIO 002644 EX_jobCurStart 002645 EX_jobRecSize 002646 EX_jobLstStart 002647 EX_jobLstEnd 002650 EX_jobLstEnd1 002651 EX_numJobs 002652 EX_numJobs1 002653 EX_changeJob 002654 EX_keepJob 002655 EX_exec 002656 EX_MN_findJob 002662 EX_MN_setFlg 002677 EX_MN_runJob 002701 EX_MN_runIt 002720 ENDOFJOB 002723 JOBSLEEP 002725 CHANG1 002733 EX_MN_notBank 002750 EX_MN_saveIt 002752 EX_MN_mvRec 002757 EX_MN_loop3 002763 EX_MN_done3 003002 JOBWAKE 003003 EX_JW_loop 003015 EX_JW_moveRec 003035 EX_JW_bumpPtr 003041 EX_JW_done 003056 EX_JW_return 003074
SPVAC 003075 EX_SP_loop1 003110 EX_SP_done1 003127 EX_SP_testFlg 003146 EX_SP_done2 003156 FINDVAC 003161 NOVAC 003162 EX_AJ_loop1 003200 EX_AJ_done1 003217 EX_AJ_testFlg 003236 EX_AJ_done2 003246 EX_initEX 003252 EX_IN_loop1 003266 EX_IN_loop2 003304 EX_IN_loop3 003307 EX_IN_done 003324 EX_findIns 003332 EX_FI_loop 003347 EX_FI_bumpPtr 003376 EX_FI_insRec 003405 EX_FI_done 003405 EX_remove 003410 EX_RM_loop1 003420 EX_RM_done1 003437 EX_RM_loop2 003446 EX_RM_done2 003465 EX_RM_loop3 003472 EX_RM_done3 003507 dumJob 003510 dumJob1 003514 dumJob2 003517 NOTACTLT 003525 DXCHJUMP 003526 DODXCHCALL 003547 DC_NOTBANK 003561 BANKCALL 003565 DOBANKCALL 003611 MYBANKCALL 003624 POSTJUMP 003653 DOPOSTJUMP 003677 BANKJUMP 003712 DOBANKJUMP 003733 DATACALL 003742 DODATACALL 003763 RELTAB 003772 RELTAB11 004005 DKTESTINIT 004006 DK_initDK 004007 DSPOFF 004012 T4PROG 004047 DSPOUTSR 004057 DSPSCAN 004065 TABLNTH 004072 _120MRUPT 004074 DSPLAY 004103 DSPOUT 004116 NODSPOUT 004126 DSPOUTEXIT 004126 CHRPRIO 004131 KEYPROG 004132 TPAGREE 004150 TPA_SGN0 004152 TPA_P0 004157 TPA_PZ0 004167 TPA_PZ0FIX 004200 TPA_M0 004210 TPA_MZ0 004220 TPA_MZ0FIX 004231 TPA_SGN1 004241 TPA_P1 004246 TPA_M1 004262 TPA_SGN2 004277 TPA_P2 004304 TPA_M2 004306 TPA_P3 004310 MAXPOS 004315 MAXNEG 004316 TPA_MPAC0 004317 TPA_MPAC1 004320 TPA_FIXM 004321 TPA_FIXP 004337 SHORTMP 004353 DMP 004374 BANKFF_1 004435 BANK4 010000 BANK04_1 010000 BANK5 012000 BANK40_1 012000 BANK6 014000 BANK41_1 014000 BANK7 016000 BANK42_1 016000 BANK10 020000 BANK43_1 020000 V37 010000 V37BAD 010002 CHECKTAB 010005 AGAINMM 010007 V37NONO 010026 FCADRMM1 010030 PREMM1 010037 EPREMM1 010046 NOV37MM 010046 BANK04_2 010047 CHARIN 012000 CHARIN2 012016 ELRCODE1 012062 ENTERJMP 012063 _89TEST 012065 NUM 012101 DECTOBIN 012137 ENDNMTST 012155 ENDNUM 012170 ENDALL 012174 DECEND 012176 PDECSGN 012220 MORNUM 012227 CRITCON 012232 DECON 012237 GETINREL 012241 INRELTAB 012245 CCSHOLE 012271 VERB 012272 NVCOM 012275 NOUN 012306 NEGSGN 012312 BOTHSGN 012315 PIXCLPAS 012321 POSGN 012326 P_ON 012332 SGNCOM 012342 M_ON 012353 SGNTAB 012364 SIGNTEST 012367 SGNTST1 012404 CLEAR 012412 CLPASHI 012431 CLEAR1 012454 CLR5 012461 LEGALTST 012464 _5BLANK 012473 _5BLANK1 012515 SINBLANK 012531 DOUBLK 012534 BRNCHCON 012537 _2BLANK 012540 BLANKCON 012563 BANK40_2 012564 NVSUBR 014000 LOADLV1 014001 ENTER 014002 ENTPASHI 014012 ACCEPTWD 014032 ENTEXIT 000433 MMADREF 014036 LOWVERB 014037 ENTPAS0 014040 TESTVB 014044 TESTNN 014054 REQADD 014073 USEADD 014117 LODNNLOC 014124 NEG5 014126 INTMCTBS 014127 VERBFAN 014151 LST2CON 014163 VBFANDIR 014164 VERBTAB 014167 MIXNOUN 014237 DPTEST 014240 DPTEST1 014262 REQDATX 014264 REQDATY 014270 REQDATZ 014274 REQCOM 014277 ENDRQDAT 014305 UPDATNN 014307 PUTADD 014320 UPDATVB 014327 UPDAT1 014335 GOALMCYC 014340 GODSPALM 014341 DSPABC 014343 DSPAB 014350 DSPA 014355 DSPCOM1 014361 DSPB 014363 DSPC 014370 DSPCOM2 014375 DSPCOM3 014403 COMPTEST 014414 COMPTST1 014417 NDOMPTST 014427 DCOMPTST 014430 DECTEST 014435 DCTSTCYC 014444 NOUNTEST 014453 TSTFORDP 014462 COMPICK 014477 GETCOMP 014501 DECDSP 014510 DSPDCGET 014514 DSPDCPUT 014524 DSPSFNOR 014546 GTSFOUTL 014550 DSPDCEND 014551 DECDSP3 014560 SFOUTABR 014563 BANK41_2 014600 DEGOUTSF 012564 SETAUG 012572 FIXRANGE 012603 DEGCOM 012616 DEGTAB 012640 ARTOUTSF 012644 SCOUTEND 012651 READLO 012653 READLO1 012665 RDLONOR 012701 ENDRDLO 012703 BANK40_3 012704 HMSOUT 016000 SECON1 016041 SECON2 016043 MINCON2 016045 MINCON1 016047 HRCON1 016051 SEPSECNR 016053 SEPMIN 016074 ENDSPMIN 016113 BANK42_2 016114 DSPDPDEC 012704 ENDDPDEC 012726 BANK40_4 012727 ABCLOAD 014600 PUTXYZ 014614 ABLOAD 014635 PUTXY 014646 ALOAD 014663 BLOAD 014673 CLOAD 014707 LOADLV 014723 VBSP1LD 014733 VBSP2LD 014734 VBSP3LD 014735 ALLDC_OC 014736 GOQ 014761 SFRUTNOR 014762 SFRUTMIX 014770 SFRET1 015002 SFCONUM 015003 SFRET 015020 DISPLACE 015022 CONUMNOR 015025 PUTCOM 015031 PUTDPCOM 015065 PUTNORM 015077 PUTNORM_1 015111 PUTCOM2 015111 GTSFINLC 015113 PUTDECSF 015114
PUTSFNOR 015125 PUTDCSF2 015126 SFINTABR 015131 BANK41_3 015146 DEGINSF 012727 DEGINSF2 012740 SIGNFIX 012750 ENDSCALE 012762 NEG180 012764 SGNTO1 012766 DEGCON1 012772 DEGCON2 012774 ARTHINSF 012776 BINROUND 013011 _2ROUND 013014 _2RNDEND 013024 TESTOFUF 013025 BANK40_5 013031 BANK42_3 016114 MONITOR 015146 MONIT1 015150 BIT15_14 015155 MONIT2 015164 MONREQ 015215 KILLMON 015232 MONDEL 015236 MONDO 015237 ENDMONDO 015273 MONREF 015274 MONBACK 015275 MONBUSY 015276 LODSAMPT 015300 BANK41_4 015301 PASTEVB 004435 PASTEOPT 004451 ENDPASTE 004472 MID7 004473 BANKFF_2 004474 DSPFMEM 015301 ENDSPF 015307 BANK41_5 015310 DSPSIGN 013031 DSPRND 013046 DPOSMAX 013062 DSPDECWD 013064 DSPDCWD1 013071 TRACE1 013074 TRACE1S 013105 DECROUND 013117 DSPDECNR 013120 DSPDC2NR 013124 DSP2DEC 013131 END2DEC 013143 DSPDECVN 013144 VNDSPCON 013155 GOVNUPDT 013156 BANK40_6 013161 DSPOCTWD 015310 WDAGAIN 015317 OCTBACK 015337 DSPLW 015341 DSPMSK 002057 DSP2BIT 015344 BANK41_6 015356 DSPIN 013161 DSPIN1 013206 DFRNT 013226 DSLV 013245 DSMSK 013247 _11DSPIN 013253 DSPOCTIN 013261 ENDSPOCT 013264 PREDSPAL 013265 DSPALARM 013267 CHARALRM 013307 MONADR 013313 NVSBENDL 013314 BANK40_7 013315 ALMCYCLE 004474 ENDALM 004502 BANKFF_3 004503 MMCHANG 015356 MODROUTR 010000 REQMM 015404 VBRQEXEC 015420 REQEX1 015425 REQUESTC 015431 SETVAC 015444 VBRQWAIT 015446 ENDRQWT 015452 BANK41_7 015453 VBPROC 013315 VBTERM 013323 VBRESEQ 013325 VBRELDSP 013327 TSTLTS4 013334 UNSUSPEN 013342 BANK40_8 013350 NVSUB 004503 NVMONOPT 004507 NVSBCOM 004516 NVSUBCOM 004524 NVSRRBNK 004531 NVSUBEND 004532 BANKFF_4 004536 BLANKDSP 015453 INCR_NOUT_RET 015463 INCR_NOUT 015501 NVSUB1 015505 ENTSET 015542 NVSUB2 015543 ENDNVSB1 015571 BANK41_8 015572 KILMONON 004536 ENDIDLE 004541 ENDINST 004553 ISCADR_P0 004554 ISLIST_P0 004560 DSPABORT 004563 BLANKSUB 004565 BSUB1ADDR 004612 BS_SUPDXCHZ 004613 BANKFF_5 004616 DSPMM 010047 ENDSPMM 010056 BANK04_3 010057 BLNKSUB1 013350 TESTBIT 013373 DSPMMJB 013400 RECALTST 013413 RECAL1 013416 RECAL2 013427 RECAL3 013444 DOTERM 013446 DOPROC 013450 BANK40_8a 013452 SETNCADR 004616 SETNADD 004625 SETEBANK 004633 R1D1 004635 R2D1 004636 R3D1 004637 RIGHT5 004640 LEFT5 004647 SLEFT5 004656 LOW5 004664 MID5 004665 HI5 004666 TCNOVAC 004667 TCWAIT 004670 TCFINDVAC 004671 LOW11 004672 B12M1 004672 LOW8 004673 LOW10 004674 VD1 004675 ND1 004676 MD1 004677 BINCON 004700 OUT1 000011 DSALMOUT 000011 FALTON 004701 FALTOF 004706 FALTOR 004712 RELDSPON 004713 RELDSPOR 004720 TPSL1 004721 PRSHRTMP 004740 DOSHRTMP 004754 FLASHON 004760 FLASHOFF 004770 FLSHTAB 005000 NVSUBUSY 005001 BANKFF_5a 005003 NVSUBSY1 013452 ENDNVBSY 013461 BANK40_9 013462 RELDSP 005003 RELDSP2 005017 RELDSP1 005026 NEWMODEA 005036 POODOO 005050 NOTPALT 005066 PINBRNCH 005067 BANKFF_6 005070 VBTSTLTS 015572 TSTLTS1 015600 FULLDSP 015621 FULLDSP1 015622 TSTCON1 015623 SHOLTS 015624 TSTLTS2 015625 TSTLTS3 015631 BANK41_9 015644 ERROR 013462 TSTAB 013467 ERMINUS 013477 ERPLUS 013502 ERCOM 013505 NOTBIT12 013517 ERCON 013520 BANK40_10 013521 LODNNTAB 016114 LODMIXNN 016135 LODNLV 016156 MIXCON 016161 GTSFOUT 016162 SFCOM 016173 GTSFIN 016176 NNADTAB 016210 NNTYPTAB 016354 SFINTAB 016520 SFOUTAB 016570 IDADDTAB 016640 RUTMXTAB 017124 BANK42_4 017220 GOEXTVB 020000 LST2FAN 020002 ALM_END 020076 GOPIN 020077 BANK43_2 020101 BANK11 022000 P00 022000 time1 022004 task1 022005 prio1 022011 job1 022012 nvcode1 022017 restart1_addr 022020 tcadr1 022021 P01 022022 P01_restart 022024 nvcode2 022033 restart2_addr 022034 tcadr2 022035 P02 022036 P02_restart 022040 P02_wait 022047 P02_pwd 022055 P02_ter 022060 nvcode3 022063 restart3_addr 022064 tcadr3 022065 P03 022066 P03_restart 022070 P03_wait 022077 P03_yield 022107 P03_pwd 022115 P03_ter 022120 nvcode4 022123 restart4_addr 022124 tcadr4 022125 mon_option 022126 P04 022127 P04_restart 022131 P78 022142 P79 022147 ARUPT 000026 Q 000001 QRUPT 000027 TIME1 000036
TIME2 000035 BANK 000015 A 000000 TIME4 000040 OUT0 000010 IN0 000004 LP 000003 OVCTR 000034 CYL 000022 SR 000021 CYR 000020
Block IApollo Guidance Computer (AGC)
How to build one in your basement
Part 9: Test and Checkout Software
John Pultorak
December, 2004
Abstract
This report describes my successful project to build a working reproduction of the 1964
prototype for the Block I Apollo Guidance Computer. The AGC is the flight computer for the
Apollo moon landings, and is the world’s first integrated circuit computer.
I built it in my basement. It took me 4 years.
If you like, you can build one too. It will take you less time, and yours will be better than
mine.
I documented my project in 9 separate .pdf files:
Part 1 Overview: Introduces the project.
Part 2 CTL Module: Design and construction of the control module.
Part 3 PROC Module: Design and construction of the processing (CPU) module.
Part 4 MEM Module: Design and construction of the memory module.
Part 5 IO Module: Design and construction of the display/keyboard (DSKY) module.
Part 6 Assembler: A cross-assembler for AGC software development.
Part 7 C++ Simulator: A low-level simulator that runs assembled AGC code.
Part 8 Flight Software: My translation of portions of the COLOSSUS 249 flight
software.
Part 9 Test & Checkout: A suite of test programs in AGC assembly language.
Overview
A suite of test and checkout programs were coded to verify the operation of the AGC
simulators and the hardware AGC.
TECO1First test and checkout program for the Block 1 AGC. Tests basic instructions: TC, CCS,
INDEX, XCH, CS, TS, AD, MASK. Enters an infinite loop at the end of the test. The A register
contains the code for the test that failed, or the PASS code if all tests succeeded. See test
codes (in octal) below.
Code Interpretation
01 TC check failed
02 CCS check failed
03 INDEX check failed
04 XCH check failed
05 CS check failed
06 TS check failed
07 AD check failed
10 MASK check failed
12345 PASSED all checks
TECO2Second test and checkout program for the Block 1 AGC. Tests extracode instructions: MP,
DV, SU. Enters an infinite loop at the end of the test. The A register contains the code for
the test that failed, or the PASS code if all tests succeeded. See test codes (in octal) below.
Code Interpretation
01 MP check failed
02 DV check failed
03 SU check failed
12345 PASSED all checks
TECO3Third test and checkout program for the Block 1 AGC. Tests editing registers: CYR, SR, CYL,
SL. Enters an infinite loop at the end of the test. The A register contains the code for the
test that failed, or the PASS code if all tests succeeded. See test codes (in octal) below.
Code Interpretation
01 CYR check failed
02 SR check failed
03 CYL check failed
04 SL check failed
12345 PASSED all checks
TECO5Exercises AGC interrupts by initializing 4 counters, and then entering into a loop that
increments the first counter on each iteration. Each of the other 3 counters is assigned to an
interrupt and is incremented in the interrupt service routine for that interrupt: KEYRUPT,
T3RUPT, and DSRUPT. Interrupts are inhib ited and enabled during each iteration of the main
loop with INHINT and RELINT instructions, and are automatically inhibited during part of
each iteration by an overflow condition in register A.
TECO_STBYAn extremely simple program for testing the STANDBY function. STANDBY is disabled for 2
NOOP instructions and then is enabled. After that, the program infinitely loops (TC TRAP)
with STANDBY enabled.
TECO1 assembler listing
Block I Apollo Guidance Computer (AGC4) assembler version 1.6 for EPROM
First pass: generate symbol table.Second pass: generate object code.
; TECO1 (file:teco1.asm) ; ; Version: 1.0 ; Author: John Pultorak ; Date: 9/14/2001 ; ; PURPOSE: ; Test and checkout program for the Block 1 Apollo Guidance Computer. ; Tests basic instructions: TC, CCS, INDEX, XCH, CS, TS, AD, MASK. ; ; OPERATION: ; Enters an infinite loop at the end of the test. The A register ; contains the code for the test that failed, or the PASS code if all ; tests succeeded. See test codes below. ; ; ERRATA: ; - Written for the AGC4R assembler. The assembler directives and ; syntax differ somewhat from the original AGC assembler. ; - The tests attempt to check all threads, but are not exhaustive. ; ; SOURCES: ; Information on the Block 1 architecture: instruction set, instruction ; sequences, registers, register transfers, control pulses, memory and ; memory addressing, I/O assignments, interrupts, and involuntary ; counters was obtained from: ; ; A. Hopkins, R. Alonso, and H. Blair-Smith, "Logical Description ; for the Apollo Guidance Computer (AGC4)", R-393, ; MIT Instrumentation Laboratory, Cambridge, MA, Mar. 1963. ; ; Supplementary information was obtained from: ; ; R. Alonso, J. H. Laning, Jr. and H. Blair-Smith, "Preliminary ; MOD 3C Programmer's Manual", E-1077, MIT Instrumentation ; Laboratory, Cambridge, MA, Nov. 1961. ; ; B. I. Savage and A. Drake, "AGC4 Basic Training Manual, Volume I", ; E-2052, MIT Instrumentation Laboratory, Cambridge, ; MA, Jan. 1967. ; ; E. C. Hall, "MIT's Role in Project Apollo, Volume III, Computer ; Subsystem", R-700, MIT Charles Stark Draper Laboratory, ; Cambridge, MA, Aug. 1972. ; ; A. Hopkins, "Guidance Computer Design, Part VI", source unknown. ; ; A. I. Green and J. J. Rocchio, "Keyboard and Display System Program ; for AGC (Program Sunrise)", E-1574, MIT Instrumentation ; Laboratory, Cambridge, MA, Aug. 1964. ; ; E, C. Hall, "Journey to the Moon: The History of the Apollo ; Guidance Computer", AIAA, Reston VA, 1996. ; START EQU %00 TCtst EQU %01 ; TC check failed CCStst EQU %02 ; CCS check failed INDEXtst EQU %03 ; INDEX check failed XCHtst EQU %04 ; XCH check failed CStst EQU %05 ; CS check failed TStst EQU %06 ; TS check failed ADtst EQU %07 ; AD check failed MASKtst EQU %10 ; MASK check failed PASS EQU %12345 ; PASSED all checks ; ----------------------------------------------
ORG EXTENDER 05777 5777 47777 0 DS %47777 ; needed for EXTEND OVFCNTR EQU %00034 ; overflow counter ; ---------------------------------------------- ; ERASEABLE MEMORY -- DATA SEGMENT ORG %100 ; start of data area00100 0100 00000 1 curtest DS START ; current test00101 0101 00000 1 savQ DS %0 ; CCS test00102 0102 00000 1 CCSk DS %0 ; INDEX test00103 0103 00000 1 INDXval DS 0 ; XCH test ; pre-set in erasable memory because we don't ; want to use XCH to initialize them prior to testing XCH.00104 0104 00000 1 XCHkP0 DS +0 00105 0105 77777 0 XCHkM0 DS -0 00106 0106 52525 1 XCHkalt1 DS %52525 ; alternating bit pattern 100107 0107 25252 0 XCHkalt2 DS %25252 ; alternating bit pattern 2 ; TS test00110 0110 77777 0 TSk DS -0 ; AD test00111 0111 77777 0 ADk DS -0 ; ---------------------------------------------- ; ENTRY POINTS ; program (re)start ORG GOPROG 02000 2000 0 1,2030 0 TC goMAIN ; interrupt service entry points ORG T3RUPT 02004 2004 5 0,0026 0 TS ARUPT 02005 2005 3 0,0001 0 XCH Q 02006 2006 5 0,0027 1 TS QRUPT 02007 2007 0 1,2717 1 TC goT3 ORG ERRUPT 02010 2010 5 0,0026 0 TS ARUPT 02011 2011 3 0,0001 0 XCH Q 02012 2012 5 0,0027 1 TS QRUPT 02013 2013 0 1,2717 1 TC goER ORG DSRUPT 02014 2014 5 0,0026 0 TS ARUPT 02015 2015 3 0,0001 0 XCH Q 02016 2016 5 0,0027 1 TS QRUPT 02017 2017 0 1,2717 1 TC goDS ORG KEYRUPT 02020 2020 5 0,0026 0 TS ARUPT 02021 2021 3 0,0001 0 XCH Q 02022 2022 5 0,0027 1 TS QRUPT 02023 2023 0 1,2717 1 TC goKEY ORG UPRUPT 02024 2024 5 0,0026 0 TS ARUPT 02025 2025 3 0,0001 0 XCH Q 02026 2026 5 0,0027 1 TS QRUPT 02027 2027 0 1,2717 1 TC goUP ; ---------------------------------------------- ; FIXED MEMORY -- SHARED DATA SEGMENT ; ----------------------------------------------
; MAIN PROGRAM goMAIN EQU * 02030 2030 2 0,0000 0 INHINT ; disable interrupts 02031 2031 0 1,2047 0 TCR begin ; Test basic instructions.02032 2032 0 1,2054 1 TCR chkTC 02033 2033 0 1,2110 0 TCR chkCCS 02034 2034 0 1,2244 1 TCR chkINDEX 02035 2035 0 1,2274 1 TCR chkXCH 02036 2036 0 1,2400 1 TCR chkCS 02037 2037 0 1,2446 0 TCR chkTS 02040 2040 0 1,2573 1 TCR chkAD 02041 2041 0 1,2674 0 TCR chkMASK ; Passed all tests.02042 2042 0 1,2714 1 TCR finish fail EQU * 02043 2043 3 0,0100 0 XCH curtest ; load last passed test into A02044 2044 5 0,0100 0 TS curtest end EQU * 02045 2045 0 1,2045 1 TC end ; finished, TC trap ; ---------------------------------------------- ; INITIALIZE FOR START OF TESTING 02046 2046 00000 1 STRTcode DS START begin EQU * 02047 2047 3 1,2046 1 XCH STRTcode 02050 2050 5 0,0100 0 TS curtest ; set current test code to START02051 2051 0 0,0000 0 RETURN ; ---------------------------------------------- ; TEST TC INSTRUCTION SUBROUTINE ; L: TC K ; Verifies the following: ; - Set C(Q) = TC L+1 ; - Take next instruction from K, and proceed from there. 02052 2052 00001 0 TCcode DS TCtst ; code for this test02053 2053 02061 1 Qtest DS TCret1 ; expected return address chkTC EQU * 02054 2054 3 0,0001 0 XCH Q 02055 2055 5 0,0101 1 TS savQ ; save return address 02056 2056 3 1,2052 1 CAF TCcode 02057 2057 5 0,0100 0 TS curtest ; set test code to this test ; attempt a jump02060 2060 0 1,2062 1 TC *+2 ; make test jump02061 2061 0 1,2043 1 TCret1 TC fail ; failed to jump ; verify correct return address in Q02062 2062 4 0,0001 1 CS Q 02063 2063 6 1,2053 0 AD Qtest ; put (-Q) + val2 in A02064 2064 1 0,0000 0 CCS A ; A = DABS02065 2065 0 1,2043 1 TC fail ; >0 (Q < Qtest)02066 2066 0 1,2043 1 TC fail ; +0 (never happens)02067 2067 0 1,2043 1 TC fail ; <0 (Q > Qtest) ; passed the test02070 2070 3 0,0101 1 XCH savQ 02071 2071 5 0,0001 0 TS Q ; restore return address02072 2072 0 0,0000 0 RETURN ; ---------------------------------------------- ; TEST CCS INSTRUCTION SUBROUTINE ; L: CCS K ; Verifies the following: ; - take next instruction from L+n and proceed from there, where: ; -- n = 1 if C(K) > 0
; -- n = 2 if C(K) = +0 ; -- n = 3 if C(K) < 0 ; -- n = 4 if C(K) = -0 ; - set C(A) = DABS[C(K)], where DABS (diminished abs value): ; -- DABS(a) = abs(a) - 1, if abs(a) > 1 ; -- DABS(a) = +0, if abs(a) <= 1 02073 2073 00002 0 CCScode DS CCStst ; code for this test ; test values (K)02074 2074 77775 1 CCSkM2 DS -2 02075 2075 77776 1 CCSkM1 DS -1 02076 2076 77777 0 CCSkM0 DS -0 02077 2077 00000 1 CCSkP0 DS +0 02100 2100 00001 0 CCSkP1 DS +1 02101 2101 00002 0 CCSkP2 DS +2 ; expected DABS values02102 2102 00001 0 CCSdM2 DS 1 ; for K=-2, DABS = +102103 2103 00000 1 CCSdM1 DS 0 ; for K=-1, DABS = +002104 2104 00000 1 CCSdM0 DS 0 ; for K=-0, DABS = +002105 2105 00000 1 CCSdP0 DS 0 ; for K=+0, DABS = +002106 2106 00000 1 CCSdP1 DS 0 ; for K=+1, DABS = +002107 2107 00001 0 CCSdP2 DS 1 ; for K=+2, DABS = +1 chkCCS EQU * 02110 2110 3 0,0001 0 XCH Q 02111 2111 5 0,0101 1 TS savQ ; save return address 02112 2112 3 1,2073 1 CAF CCScode 02113 2113 5 0,0100 0 TS curtest ; set test code to this test ; set K to -2 and execute CCS: ; check for correct branch02114 2114 3 1,2074 0 CAF CCSkM2 ; set K = -202115 2115 5 0,0102 1 TS CCSk 02116 2116 1 0,0102 0 CCS CCSk ; A = DABS[C(K)]02117 2117 0 1,2043 1 TC fail ; K > 002120 2120 0 1,2043 1 TC fail ; K= +002121 2121 0 1,2123 0 TC *+2 ; K < 002122 2122 0 1,2043 1 TC fail ; K= -0 ; check for correct DABS in A (for K=-2, it should be 1)02123 2123 4 0,0000 0 COM ; 1's compliment of A02124 2124 6 1,2102 0 AD CCSdM2 ; put (-A) + expected value in A02125 2125 1 0,0000 0 CCS A ; A = DABS02126 2126 0 1,2043 1 TC fail ; >0 (A < expected value)02127 2127 0 1,2043 1 TC fail ; +002130 2130 0 1,2043 1 TC fail ; <0 (A > expected value) ; set K to -1 and execute CCS: ; check for correct branch02131 2131 3 1,2075 1 CAF CCSkM1 ; set K = -102132 2132 5 0,0102 1 TS CCSk 02133 2133 1 0,0102 0 CCS CCSk ; A = DABS[C(K)]02134 2134 0 1,2043 1 TC fail ; K > 002135 2135 0 1,2043 1 TC fail ; K= +002136 2136 0 1,2140 0 TC *+2 ; K < 002137 2137 0 1,2043 1 TC fail ; K= -0 ; check for correct DABS in A (for K=-1, it should be +0)02140 2140 4 0,0000 0 COM ; 1's compliment of A02141 2141 6 1,2103 1 AD CCSdM1 ; put (-A) + expected value in A02142 2142 1 0,0000 0 CCS A ; A = DABS02143 2143 0 1,2043 1 TC fail ; >0 (A < expected value)02144 2144 0 1,2043 1 TC fail ; +002145 2145 0 1,2043 1 TC fail ; <0 (A > expected value) ; set K to -0 and execute CCS: ; check for correct branch02146 2146 3 1,2076 1 CAF CCSkM0 ; set K = -002147 2147 5 0,0102 1 TS CCSk 02150 2150 1 0,0102 0 CCS CCSk ; A = DABS[C(K)]02151 2151 0 1,2043 1 TC fail ; K > 002152 2152 0 1,2043 1 TC fail ; K= +002153 2153 0 1,2043 1 TC fail ; K < 0 ; check for correct DABS in A (for K=-0, it should be +0)02154 2154 4 0,0000 0 COM ; 1's compliment of A02155 2155 6 1,2104 0 AD CCSdM0 ; put (-A) + expected value in A
02156 2156 1 0,0000 0 CCS A ; A = DABS02157 2157 0 1,2043 1 TC fail ; >0 (A < expected value)02160 2160 0 1,2043 1 TC fail ; +002161 2161 0 1,2043 1 TC fail ; <0 (A > expected value) ; set K to +0 and execute CCS: ; check for correct branch02162 2162 3 1,2077 0 CAF CCSkP0 ; set K = +002163 2163 5 0,0102 1 TS CCSk 02164 2164 1 0,0102 0 CCS CCSk ; A = DABS[C(K)]02165 2165 0 1,2043 1 TC fail ; K > 002166 2166 0 1,2171 1 TC *+3 ; K= +002167 2167 0 1,2043 1 TC fail ; K < 002170 2170 0 1,2043 1 TC fail ; K= -0 ; check for correct DABS in A (for K=+0, it should be +0)02171 2171 4 0,0000 0 COM ; 1's compliment of A02172 2172 6 1,2105 1 AD CCSdP0 ; put (-A) + expected value in A02173 2173 1 0,0000 0 CCS A ; A = DABS02174 2174 0 1,2043 1 TC fail ; >0 (A < expected value)02175 2175 0 1,2043 1 TC fail ; +002176 2176 0 1,2043 1 TC fail ; <0 (A > expected value) ; set K to +1 and execute CCS: ; check for correct branch02177 2177 3 1,2100 1 CAF CCSkP1 ; set K = +102200 2200 5 0,0102 1 TS CCSk 02201 2201 1 0,0102 0 CCS CCSk ; A = DABS[C(K)]02202 2202 0 1,2206 1 TC *+4 ; K > 002203 2203 0 1,2043 1 TC fail ; K= +002204 2204 0 1,2043 1 TC fail ; K < 002205 2205 0 1,2043 1 TC fail ; K= -0 ; check for correct DABS in A (for K=+1, it should be +0)02206 2206 4 0,0000 0 COM ; 1's compliment of A02207 2207 6 1,2106 1 AD CCSdP1 ; put (-A) + expected value in A02210 2210 1 0,0000 0 CCS A ; A = DABS02211 2211 0 1,2043 1 TC fail ; >0 (A < expected value)02212 2212 0 1,2043 1 TC fail ; +002213 2213 0 1,2043 1 TC fail ; <0 (A > expected value) ; set K to +2 and execute CCS: ; check for correct branch02214 2214 3 1,2101 0 CAF CCSkP2 ; set K = +202215 2215 5 0,0102 1 TS CCSk 02216 2216 1 0,0102 0 CCS CCSk ; A = DABS[C(K)]02217 2217 0 1,2223 0 TC *+4 ; K > 002220 2220 0 1,2043 1 TC fail ; K= +002221 2221 0 1,2043 1 TC fail ; K < 002222 2222 0 1,2043 1 TC fail ; K= -0 ; check for correct DABS in A (for K=+2, it should be +1)02223 2223 4 0,0000 0 COM ; 1's compliment of A02224 2224 6 1,2107 0 AD CCSdP2 ; put (-A) + expected value in A02225 2225 1 0,0000 0 CCS A ; A = DABS02226 2226 0 1,2043 1 TC fail ; >0 (A < expected value)02227 2227 0 1,2043 1 TC fail ; +002230 2230 0 1,2043 1 TC fail ; <0 (A > expected value) ; passed the test02231 2231 3 0,0101 1 XCH savQ 02232 2232 5 0,0001 0 TS Q ; restore return address02233 2233 0 0,0000 0 RETURN ; ---------------------------------------------- ; TEST INDEX INSTRUCTION SUBROUTINE ; L: INDEX K (where K != 0025) ; Verifies the following; ; - Use the sum of C(L+1) + C(K) as the next instruction ; -- just as if that sum had been taken from L+1. 02234 2234 00003 1 INDXcode DS INDEXtst ; code for this test02235 2235 00005 1 INDXst DS 5 ; somewhere in fixed memory 02236 2236 00000 1 INDXbas DS 0 ; base address for indexing02237 2237 00001 0 DS 1 02240 2240 00002 0 DS 2 02241 2241 00003 1 DS 3 02242 2242 00004 0 DS 4 02243 2243 00005 1 DS 5
chkINDEX EQU * 02244 2244 3 0,0001 0 XCH Q 02245 2245 5 0,0101 1 TS savQ ; save return address 02246 2246 3 1,2234 0 CAF INDXcode 02247 2247 5 0,0100 0 TS curtest ; set test code to this test ; Decrementing loop ; - always executes at least once (tests at end of loop) ; - loops 'INDXst+1' times; decrements INDXval 02250 2250 3 1,2235 1 XCH INDXst ; initialize loop counter INDXlop EQU * 02251 2251 5 0,0103 0 TS INDXval ; perform indexed CAF of values in INDXbas array; ; index values range from 5 to 002252 2252 2 0,0103 1 INDEX INDXval 02253 2253 3 1,2236 1 CAF INDXbas ; verify value retrieved using INDEX matches expected value02254 2254 4 0,0000 0 COM ; get -A02255 2255 6 0,0103 0 AD INDXval ; put (-A) + expected value in A02256 2256 1 0,0000 0 CCS A ; compare02257 2257 0 1,2043 1 TC fail ; >0 (A < expected value)02260 2260 0 1,2043 1 TC fail ; +002261 2261 0 1,2043 1 TC fail ; <0 (A > expected value) 02262 2262 1 0,0103 1 CCS INDXval ; done?02263 2263 0 1,2251 0 TC INDXlop ; not yet 02264 2264 3 0,0101 1 XCH savQ 02265 2265 5 0,0001 0 TS Q ; restore return address02266 2266 0 0,0000 0 RETURN ; ---------------------------------------------- ; TEST XCH INSTRUCTION SUBROUTINE ; L: XCH K ; Verifies the following: ; - set C(A) = b(K) ; - set C(K) = b(A) ; - take next instruction from L+1 02267 2267 00004 0 XCHcode DS XCHtst ; code for this test ; XCH test values02270 2270 00000 1 XCHfP0 DS +0 02271 2271 77777 0 XCHfM0 DS -0 02272 2272 52525 1 XCHfalt1 DS %52525 ; alternating bit pattern 102273 2273 25252 0 XCHfalt2 DS %25252 ; alternating bit pattern 2 chkXCH EQU * 02274 2274 3 0,0001 0 XCH Q 02275 2275 5 0,0101 1 TS savQ ; save return address 02276 2276 3 1,2267 0 CAF XCHcode 02277 2277 5 0,0100 0 TS curtest ; set test code to this test ; test - initial conditions: K=+0, A=-0 ; initialize A02300 2300 4 1,2270 1 CS XCHfP0 ; exchange A and K02301 2301 3 0,0104 1 XCH XCHkP0 ; test contents of A for expected value02302 2302 4 0,0000 0 COM ; get -A02303 2303 6 1,2270 0 AD XCHfP0 ; put (-A) + expected value in A02304 2304 1 0,0000 0 CCS A ; A = DABS02305 2305 0 1,2043 1 TC fail ; >0 (A < expected value)02306 2306 0 1,2043 1 TC fail ; +002307 2307 0 1,2043 1 TC fail ; <0 (A > expected value) ; test contents of K for expected value02310 2310 4 0,0104 0 CS XCHkP0 ; get -A02311 2311 6 1,2271 1 AD XCHfM0 ; put (-A) + expected value in A02312 2312 1 0,0000 0 CCS A ; A = DABS02313 2313 0 1,2043 1 TC fail ; >0 (A < expected value)02314 2314 0 1,2043 1 TC fail ; +0
02315 2315 0 1,2043 1 TC fail ; <0 (A > expected value) ; test - initial conditions: K=-0, A=+0 ; initialize A02316 2316 4 1,2271 0 CS XCHfM0 ; exchange A and K02317 2317 3 0,0105 0 XCH XCHkM0 ; test contents of A for expected value02320 2320 4 0,0000 0 COM ; get -A02321 2321 6 1,2271 1 AD XCHfM0 ; put (-A) + expected value in A02322 2322 1 0,0000 0 CCS A ; A = DABS02323 2323 0 1,2043 1 TC fail ; >0 (A < expected value)02324 2324 0 1,2043 1 TC fail ; +002325 2325 0 1,2043 1 TC fail ; <0 (A > expected value) ; test contents of K for expected value02326 2326 4 0,0105 1 CS XCHkM0 ; get -A02327 2327 6 1,2270 0 AD XCHfP0 ; put (-A) + expected value in A02330 2330 1 0,0000 0 CCS A ; A = DABS02331 2331 0 1,2043 1 TC fail ; >0 (A < expected value)02332 2332 0 1,2043 1 TC fail ; +002333 2333 0 1,2043 1 TC fail ; <0 (A > expected value) ; test - initial conditions: K=52525, A=25252 ; initialize A02334 2334 4 1,2272 0 CS XCHfalt1 ; exchange A and K02335 2335 3 0,0106 0 XCH XCHkalt1 ; test contents of A for expected value02336 2336 4 0,0000 0 COM ; get -A02337 2337 6 1,2272 1 AD XCHfalt1 ; put (-A) + expected value in A02340 2340 1 0,0000 0 CCS A ; A = DABS02341 2341 0 1,2043 1 TC fail ; >0 (A < expected value)02342 2342 0 1,2043 1 TC fail ; +002343 2343 0 1,2043 1 TC fail ; <0 (A > expected value) ; test contents of K for expected value02344 2344 4 0,0106 1 CS XCHkalt1 ; get -A02345 2345 6 1,2273 0 AD XCHfalt2 ; put (-A) + expected value in A02346 2346 1 0,0000 0 CCS A ; A = DABS02347 2347 0 1,2043 1 TC fail ; >0 (A < expected value)02350 2350 0 1,2043 1 TC fail ; +002351 2351 0 1,2043 1 TC fail ; <0 (A > expected value) ; test - initial conditions: K=25252, A=52525 ; initialize A02352 2352 4 1,2273 1 CS XCHfalt2 ; exchange A and K02353 2353 3 0,0107 1 XCH XCHkalt2 ; test contents of A for expected value02354 2354 4 0,0000 0 COM ; get -A02355 2355 6 1,2273 0 AD XCHfalt2 ; put (-A) + expected value in A02356 2356 1 0,0000 0 CCS A ; A = DABS02357 2357 0 1,2043 1 TC fail ; >0 (A < expected value)02360 2360 0 1,2043 1 TC fail ; +002361 2361 0 1,2043 1 TC fail ; <0 (A > expected value) ; test contents of K for expected value02362 2362 4 0,0107 0 CS XCHkalt2 ; get -A02363 2363 6 1,2272 1 AD XCHfalt1 ; put (-A) + expected value in A02364 2364 1 0,0000 0 CCS A ; A = DABS02365 2365 0 1,2043 1 TC fail ; >0 (A < expected value)02366 2366 0 1,2043 1 TC fail ; +002367 2367 0 1,2043 1 TC fail ; <0 (A > expected value) ; passed the test02370 2370 3 0,0101 1 XCH savQ 02371 2371 5 0,0001 0 TS Q ; restore return address02372 2372 0 0,0000 0 RETURN ; ---------------------------------------------- ; TEST CS INSTRUCTION SUBROUTINE ; L: CS K ; Verifies the following: ; - Set C(A) = -C(K) ; - Take next instruction from L+1 02373 2373 00005 1 CScode DS CStst ; code for this test ; test values (K)
02374 2374 00000 1 CSkP0 DS +0 02375 2375 77777 0 CSkM0 DS -0 02376 2376 52525 1 CSkalt1 DS %52525 ; 1's C of CSkalt202377 2377 25252 0 CSkalt2 DS %25252 ; 1's C of CSkalt1 chkCS EQU * 02400 2400 3 0,0001 0 XCH Q 02401 2401 5 0,0101 1 TS savQ ; save return address 02402 2402 3 1,2373 1 CAF CScode 02403 2403 5 0,0100 0 TS curtest ; set test code to this test ; clear and subtract +002404 2404 4 1,2374 1 CS CSkP0 ; load 1's comp of K into A02405 2405 6 1,2374 0 AD CSkP0 ; put (-A) + expected value in A02406 2406 1 0,0000 0 CCS A ; compare02407 2407 0 1,2043 1 TC fail ; >0 (A < expected value)02410 2410 0 1,2043 1 TC fail ; +002411 2411 0 1,2043 1 TC fail ; <0 (A > expected value) ; clear and subtract -002412 2412 4 1,2375 0 CS CSkM0 ; load 1's comp of K into A02413 2413 6 1,2375 1 AD CSkM0 ; put (-A) + expected value in A02414 2414 1 0,0000 0 CCS A ; compare02415 2415 0 1,2043 1 TC fail ; >0 (A < expected value)02416 2416 0 1,2043 1 TC fail ; +002417 2417 0 1,2043 1 TC fail ; <0 (A > expected value) ; clear and subtract alternating bit pattern %5252502420 2420 4 1,2376 0 CS CSkalt1 ; load 1's comp of K into A02421 2421 6 1,2376 1 AD CSkalt1 ; put (-A) + expected value in A02422 2422 1 0,0000 0 CCS A ; compare02423 2423 0 1,2043 1 TC fail ; >0 (A < expected value)02424 2424 0 1,2043 1 TC fail ; +002425 2425 0 1,2043 1 TC fail ; <0 (A > expected value) ; clear and subtract alternating bit pattern %2525202426 2426 4 1,2377 1 CS CSkalt2 ; load 1's comp of K into A02427 2427 6 1,2377 0 AD CSkalt2 ; put (-A) + expected value in A02430 2430 1 0,0000 0 CCS A ; compare02431 2431 0 1,2043 1 TC fail ; >0 (A < expected value)02432 2432 0 1,2043 1 TC fail ; +002433 2433 0 1,2043 1 TC fail ; <0 (A > expected value) ; passed the test02434 2434 3 0,0101 1 XCH savQ 02435 2435 5 0,0001 0 TS Q ; restore return address02436 2436 0 0,0000 0 RETURN ; ---------------------------------------------- ; TEST TS INSTRUCTION SUBROUTINE ; L; TS K ; Verifies the following: ; - Set C(K) = b(A) ; - If b(A) contains no overflow, ; -- C(A) = b(A); take next instruction from L+1 ; - If b(A) has positive overflow, C(A) = 000001; ; -- take next instruction from L+2 ; - If b(A) has negative overflow, C(A) = 177776; ; -- take next instruction from L+2 02437 2437 00006 1 TScode DS TStst ; code for this test02440 2440 00001 0 TSone DS +1 02441 2441 00000 1 TSzero DS +0 02442 2442 77777 0 TSmzero DS -0 02443 2443 77776 1 TSmone DS -1 02444 2444 37777 1 TSkP1 DS %37777 ; TEST1: largest + num w/no ovf02445 2445 40000 0 TSkM1 DS %40000 ; TEST2: largest - num w/no ovf chkTS EQU * 02446 2446 3 0,0001 0 XCH Q 02447 2447 5 0,0101 1 TS savQ ; save return address 02450 2450 3 1,2437 0 CAF TScode 02451 2451 5 0,0100 0 TS curtest ; set test code to this test ; initialize TSk to -0
02452 2452 3 1,2442 1 CAF TSmzero 02453 2453 3 0,0110 1 XCH TSk ; TEST 1: store positive number, no overflow02454 2454 3 1,2444 1 CAF TSkP1 02455 2455 5 0,0110 1 TS TSk 02456 2456 0 1,2460 1 TC *+2 ; no overflow02457 2457 0 1,2043 1 TC fail ; overflow ; verify C(A) = b(A)02460 2460 4 0,0000 0 COM ; get -A02461 2461 6 1,2444 1 AD TSkP1 ; put (-A) + expected value in A02462 2462 1 0,0000 0 CCS A ; compare02463 2463 0 1,2043 1 TC fail ; >0 (A < expected value)02464 2464 0 1,2043 1 TC fail ; +002465 2465 0 1,2043 1 TC fail ; <0 (A > expected value) ; verify C(K) = b(A)02466 2466 4 1,2444 0 CS TSkP1 ; get -expected value02467 2467 6 0,0110 1 AD TSk ; put value + C(K) into A02470 2470 1 0,0000 0 CCS A ; compare02471 2471 0 1,2043 1 TC fail ; >0 (A < expected value)02472 2472 0 1,2043 1 TC fail ; +002473 2473 0 1,2043 1 TC fail ; <0 (A > expected value) ; TEST 2: store negative number, no overflow02474 2474 3 1,2445 0 CAF TSkM1 02475 2475 5 0,0110 1 TS TSk 02476 2476 0 1,2500 0 TC *+2 ; no overflow02477 2477 0 1,2043 1 TC fail ; overflow ; verify C(A) = b(A)02500 2500 4 0,0000 0 COM ; get -A02501 2501 6 1,2445 0 AD TSkM1 ; put (-A) + expected value in A02502 2502 1 0,0000 0 CCS A ; compare02503 2503 0 1,2043 1 TC fail ; >0 (A < expected value)02504 2504 0 1,2043 1 TC fail ; +002505 2505 0 1,2043 1 TC fail ; <0 (A > expected value) ; verify C(K) = b(A)02506 2506 4 1,2445 1 CS TSkM1 ; get -expected value02507 2507 6 0,0110 1 AD TSk ; put value + C(K) into A02510 2510 1 0,0000 0 CCS A ; compare02511 2511 0 1,2043 1 TC fail ; >0 (A < expected value)02512 2512 0 1,2043 1 TC fail ; +002513 2513 0 1,2043 1 TC fail ; <0 (A > expected value) ; TEST 3: store positive number, overflow02514 2514 3 1,2444 1 CAF TSkP1 ; get largest positive number02515 2515 6 1,2440 0 AD TSone ; make it overflow; A = neg ovf02516 2516 5 0,0110 1 TS TSk ; store the positive overflow02517 2517 0 1,2043 1 TC fail ; no overflow ; verify C(A) = 00000102520 2520 4 0,0000 0 COM ; get -A02521 2521 6 1,2440 0 AD TSone ; put (-A) + expected value in A02522 2522 1 0,0000 0 CCS A ; compare02523 2523 0 1,2043 1 TC fail ; >0 (A < expected value)02524 2524 0 1,2043 1 TC fail ; +002525 2525 0 1,2043 1 TC fail ; <0 (A > expected value) ; verify C(K) = positive overflow02526 2526 4 1,2441 0 CS TSzero ; get -expected value02527 2527 6 0,0110 1 AD TSk ; put value + C(K) into A02530 2530 1 0,0000 0 CCS A ; compare02531 2531 0 1,2043 1 TC fail ; >0 (A < expected value)02532 2532 0 1,2043 1 TC fail ; +002533 2533 0 1,2043 1 TC fail ; <0 (A > expected value) ; TEST 4: store negative number, overflow02534 2534 3 1,2445 0 CAF TSkM1 ; get largest negative number02535 2535 6 1,2443 0 AD TSmone ; make it overflow; A = neg ovf02536 2536 5 0,0110 1 TS TSk ; store the negative overflow02537 2537 0 1,2043 1 TC fail ; no overflow ; verify C(A) = 17777602540 2540 4 0,0000 0 COM ; get -A02541 2541 6 1,2443 0 AD TSmone ; put (-A) + expected value in A02542 2542 1 0,0000 0 CCS A ; compare02543 2543 0 1,2043 1 TC fail ; >0 (A < expected value)02544 2544 0 1,2043 1 TC fail ; +002545 2545 0 1,2043 1 TC fail ; <0 (A > expected value) ; verify C(K) = negative overflow
02546 2546 4 1,2442 0 CS TSmzero ; get -expected value02547 2547 6 0,0110 1 AD TSk ; put value + C(K) into A02550 2550 1 0,0000 0 CCS A ; compare02551 2551 0 1,2043 1 TC fail ; >0 (A < expected value)02552 2552 0 1,2043 1 TC fail ; +002553 2553 0 1,2043 1 TC fail ; <0 (A > expected value) 02554 2554 3 0,0101 1 XCH savQ 02555 2555 5 0,0001 0 TS Q ; restore return address02556 2556 0 0,0000 0 RETURN ; ---------------------------------------------- ; TEST AD INSTRUCTION SUBROUTINE ; L: AD K ; Verifies the following: ; - Set C(A) = b(A) + C(K) ; - Take next instruction from L+1 ; - if C(A) has positive overflow, ; -- increment overflow counter by 1 ; - if C(A) has negative overflow, ; -- decrement overflow counter by 1 02557 2557 00007 0 ADcode DS ADtst ; code for this test02560 2560 00000 1 ADplus0 DS +0 02561 2561 00001 0 ADplus1 DS 1 02562 2562 77776 1 ADmin1 DS -1 02563 2563 25252 0 AD25252 DS %25252 ; +10922 decimal02564 2564 12525 0 AD12525 DS %12525 ; +5461 decimal02565 2565 37777 1 AD37777 DS %37777 ; largest positive number02566 2566 12524 1 AD12524 DS %12524 ; + overflow of %25252+%25252 02567 2567 52525 1 AD52525 DS %52525 ; -10922 decimal02570 2570 65252 1 AD65252 DS %65252 ; -5461 decimal02571 2571 40000 0 AD40000 DS %40000 ; largest negative number02572 2572 65253 0 AD65253 DS %65253 ; neg overflow of %52525+65252 chkAD EQU * 02573 2573 3 0,0001 0 XCH Q 02574 2574 5 0,0101 1 TS savQ ; save return address 02575 2575 3 1,2557 1 CAF ADcode 02576 2576 5 0,0100 0 TS curtest ; set test code to this test ; TEST1: sum positive, no overflow ; add: %25252 + %12525 = %37777 (sign + 14 magnitude)02577 2577 3 1,2563 0 CAF AD25252 02600 2600 6 1,2564 1 AD AD12525 ; verify C(A) = %3777702601 2601 4 0,0000 0 COM ; get -A02602 2602 6 1,2565 0 AD AD37777 ; put (-A) + expected value in A02603 2603 1 0,0000 0 CCS A ; compare02604 2604 0 1,2043 1 TC fail ; >0 (A < expected value)02605 2605 0 1,2043 1 TC fail ; +002606 2606 0 1,2043 1 TC fail ; <0 (A > expected value) ; TEST2: sum negative, no overflow (sign + 14 magnitude) ; add: %52525 + %65252 = %4000002607 2607 3 1,2567 1 CAF AD52525 02610 2610 6 1,2570 1 AD AD65252 ; verify C(A) = %4000002611 2611 4 0,0000 0 COM ; get -A02612 2612 6 1,2571 0 AD AD40000 ; put (-A) + expected value in A02613 2613 1 0,0000 0 CCS A ; compare02614 2614 0 1,2043 1 TC fail ; >0 (A < expected value)02615 2615 0 1,2043 1 TC fail ; +002616 2616 0 1,2043 1 TC fail ; <0 (A > expected value) ; TEST3: sum positive, overflow ; initialize overflow counter and positive overflow storage02617 2617 3 1,2560 0 CAF ADplus0 02620 2620 5 0,0034 0 TS OVFCNTR 02621 2621 5 0,0111 0 TS ADk ; add: %25252 + %25252 = %52524 (sign + 14 magnitude)02622 2622 3 1,2563 0 CAF AD25252 02623 2623 6 1,2563 0 AD AD25252 02624 2624 5 0,0111 0 TS ADk ; store positive overflow
02625 2625 0 1,2043 1 TC fail ; verify ADk = %1252402626 2626 4 0,0111 1 CS ADk ; get -A02627 2627 6 1,2566 0 AD AD12524 ; put (-A) + expected value in A02630 2630 1 0,0000 0 CCS A ; compare02631 2631 0 1,2043 1 TC fail ; >0 (A < expected value)02632 2632 0 1,2043 1 TC fail ; +002633 2633 0 1,2043 1 TC fail ; <0 (A > expected value) ; verify overflow counter =%0000102634 2634 4 0,0034 1 CS OVFCNTR ; get -A02635 2635 6 1,2561 1 AD ADplus1 ; put (-A) + expected value in A02636 2636 1 0,0000 0 CCS A ; compare02637 2637 0 1,2043 1 TC fail ; >0 (A < expected value)02640 2640 0 1,2043 1 TC fail ; +002641 2641 0 1,2043 1 TC fail ; <0 (A > expected value) ; TEST4: sum negative, overflow02642 2642 3 1,2560 0 CAF ADplus0 02643 2643 5 0,0034 0 TS OVFCNTR 02644 2644 5 0,0111 0 TS ADk ; add: %52525 + %52525 = %25253 (sign + 14 magnitude)02645 2645 3 1,2567 1 CAF AD52525 02646 2646 6 1,2567 1 AD AD52525 02647 2647 5 0,0111 0 TS ADk ; store negative overflow02650 2650 0 1,2043 1 TC fail ; verify ADk = %6525302651 2651 4 0,0111 1 CS ADk ; get -A02652 2652 6 1,2572 0 AD AD65253 ; put (-A) + expected value in A02653 2653 1 0,0000 0 CCS A ; compare02654 2654 0 1,2043 1 TC fail ; >0 (A < expected value)02655 2655 0 1,2043 1 TC fail ; +002656 2656 0 1,2043 1 TC fail ; <0 (A > expected value) ; verify overflow counter =%7777602657 2657 4 0,0034 1 CS OVFCNTR ; get -A02660 2660 6 1,2562 1 AD ADmin1 ; put (-A) + expected value in A02661 2661 1 0,0000 0 CCS A ; compare02662 2662 0 1,2043 1 TC fail ; >0 (A < expected value)02663 2663 0 1,2043 1 TC fail ; +002664 2664 0 1,2043 1 TC fail ; <0 (A > expected value) 02665 2665 3 0,0101 1 XCH savQ 02666 2666 5 0,0001 0 TS Q ; restore return address02667 2667 0 0,0000 0 RETURN ; ---------------------------------------------- ; TEST MASK INSTRUCTION SUBROUTINE ; L: MASK K ; Verifies the following: ; - Set C(A) = b(A) & C(K) 02670 2670 00010 0 MASKcode DS MASKtst ; code for this test02671 2671 46314 0 MASK1 DS %46314 02672 2672 25252 0 MASK2 DS %25252 02673 2673 04210 0 MASKval DS %04210 ; expected result: MASK1 & MASK2 chkMASK EQU * 02674 2674 3 0,0001 0 XCH Q 02675 2675 5 0,0101 1 TS savQ ; save return address ; perform logical and of MASK1 and MASK202676 2676 3 1,2671 0 CAF MASK1 02677 2677 7 1,2672 1 MASK MASK2 ; verify C(A) = b(A) & C(K)02700 2700 4 0,0000 0 COM ; get -A02701 2701 6 1,2673 1 AD MASKval ; put (-A) + expected value in A02702 2702 1 0,0000 0 CCS A ; compare02703 2703 0 1,2043 1 TC fail ; >0 (A < expected value)02704 2704 0 1,2043 1 TC fail ; +002705 2705 0 1,2043 1 TC fail ; <0 (A > expected value) 02706 2706 3 1,2670 1 CAF MASKcode 02707 2707 5 0,0100 0 TS curtest ; set test code to this test ; passed the test02710 2710 3 0,0101 1 XCH savQ 02711 2711 5 0,0001 0 TS Q ; restore return address02712 2712 0 0,0000 0 RETURN
; ---------------------------------------------- ; PASSED ALL TESTS! 02713 2713 12345 0 PASScode DS PASS finish EQU * 02714 2714 3 1,2713 0 CAF PASScode 02715 2715 5 0,0100 0 TS curtest ; set current test code to PASS02716 2716 0 0,0000 0 RETURN ; ---------------------------------------------- ; INTERRUPT SERVICE ROUTINE goT3 EQU * goER EQU * goDS EQU * goKEY EQU * goUP EQU * endRUPT EQU * 02717 2717 3 0,0027 1 XCH QRUPT ; restore Q02720 2720 5 0,0001 0 TS Q 02721 2721 3 0,0026 0 XCH ARUPT ; restore A02722 2722 2 0,0000 1 RESUME ; finished, go back
Assembly complete. Errors = 0
Symbol table:START 000000 TCtst 000001 CCStst 000002 INDEXtst 000003 XCHtst 000004 CStst 000005 TStst 000006 ADtst 000007 MASKtst 000010 PASS 012345 EXTENDER 005777 OVFCNTR 000034 curtest 000100 savQ 000101 CCSk 000102 INDXval 000103 XCHkP0 000104 XCHkM0 000105 XCHkalt1 000106 XCHkalt2 000107 TSk 000110 ADk 000111 GOPROG 002000 T3RUPT 002004 ERRUPT 002010 DSRUPT 002014 KEYRUPT 002020 UPRUPT 002024 goMAIN 002030 fail 002043 end 002045 STRTcode 002046 begin 002047 TCcode 002052 Qtest 002053 chkTC 002054 TCret1 002061 CCScode 002073 CCSkM2 002074 CCSkM1 002075 CCSkM0 002076 CCSkP0 002077 CCSkP1 002100 CCSkP2 002101 CCSdM2 002102 CCSdM1 002103 CCSdM0 002104 CCSdP0 002105 CCSdP1 002106 CCSdP2 002107 chkCCS 002110 INDXcode 002234 INDXst 002235 INDXbas 002236 chkINDEX 002244 INDXlop 002251 XCHcode 002267 XCHfP0 002270 XCHfM0 002271 XCHfalt1 002272 XCHfalt2 002273 chkXCH 002274 CScode 002373 CSkP0 002374 CSkM0 002375 CSkalt1 002376 CSkalt2 002377 chkCS 002400 TScode 002437 TSone 002440 TSzero 002441 TSmzero 002442 TSmone 002443 TSkP1 002444 TSkM1 002445 chkTS 002446 ADcode 002557 ADplus0 002560 ADplus1 002561 ADmin1 002562 AD25252 002563 AD12525 002564 AD37777 002565 AD12524 002566 AD52525 002567 AD65252 002570 AD40000 002571 AD65253 002572 chkAD 002573 MASKcode 002670 MASK1 002671 MASK2 002672 MASKval 002673 chkMASK 002674 PASScode 002713 finish 002714 goT3 002717 goER 002717 goDS 002717 goKEY 002717 goUP 002717 endRUPT 002717 ARUPT 000026 Q 000001 QRUPT 000027 A 000000
TECO2 assembler listing
Block I Apollo Guidance Computer (AGC4) assembler version 1.6 for EPROM
First pass: generate symbol table.Second pass: generate object code.
; TECO2 (file:teco2.asm) ; ; Version: 1.0 ; Author: John Pultorak ; Date: 9/14/2001 ; ; PURPOSE: ; Test and checkout program for the Block 1 Apollo Guidance Computer. ; Tests extracode instructions: MP, DV, SU ; ; OPERATION: ; Enters an infinite loop at the end of the test. The A register ; contains the code for the test that failed, or the PASS code if all ; tests succeeded. See test codes below. ; ; ERRATA: ; - Written for the AGC4R assembler. The assembler directives and ; syntax differ somewhat from the original AGC assembler. ; - The tests attempt to check all threads, but are not exhaustive. ; ; SOURCES: ; Information on the Block 1 architecture: instruction set, instruction ; sequences, registers, register transfers, control pulses, memory and ; memory addressing, I/O assignments, interrupts, and involuntary ; counters was obtained from: ; ; A. Hopkins, R. Alonso, and H. Blair-Smith, "Logical Description ; for the Apollo Guidance Computer (AGC4)", R-393, ; MIT Instrumentation Laboratory, Cambridge, MA, Mar. 1963. ; ; Supplementary information was obtained from: ; ; R. Alonso, J. H. Laning, Jr. and H. Blair-Smith, "Preliminary ; MOD 3C Programmer's Manual", E-1077, MIT Instrumentation ; Laboratory, Cambridge, MA, Nov. 1961. ; ; B. I. Savage and A. Drake, "AGC4 Basic Training Manual, Volume I", ; E-2052, MIT Instrumentation Laboratory, Cambridge, ; MA, Jan. 1967. ; ; E. C. Hall, "MIT's Role in Project Apollo, Volume III, Computer ; Subsystem", R-700, MIT Charles Stark Draper Laboratory, ; Cambridge, MA, Aug. 1972. ; ; A. Hopkins, "Guidance Computer Design, Part VI", source unknown. ; ; A. I. Green and J. J. Rocchio, "Keyboard and Display System Program ; for AGC (Program Sunrise)", E-1574, MIT Instrumentation ; Laboratory, Cambridge, MA, Aug. 1964. ; ; E, C. Hall, "Journey to the Moon: The History of the Apollo ; Guidance Computer", AIAA, Reston VA, 1996. ; START EQU %00 MPtst EQU %01 ; MP check failed DVtst EQU %02 ; DV check failed SUtst EQU %03 ; SU check failed PASS EQU %12345 ; PASSED all checks ; ---------------------------------------------- ORG EXTENDER 05777 5777 47777 0 DS %47777 ; needed for EXTEND
OVFCNTR EQU %00034 ; overflow counter ; ---------------------------------------------- ; ERASEABLE MEMORY -- DATA SEGMENT ORG %100 ; start of data area00100 0100 00000 1 curtest DS START ; current test00101 0101 00000 1 savQ DS %0 ; MP test00102 0102 00000 1 MPindex DS %0 00103 0103 00000 1 MPXTND DS %0 ; indexed extend ; DV test00104 0104 00000 1 DVsavA DS %0 00105 0105 00000 1 DVindex DS %0 00106 0106 00000 1 DVXTND DS %0 ; indexed extend ; SU test00107 0107 77777 0 SUk DS -0 ; ---------------------------------------------- ; ENTRY POINTS ; program (re)start ORG GOPROG 02000 2000 0 1,2030 0 TC goMAIN ; interrupt service entry points ORG T3RUPT 02004 2004 5 0,0026 0 TS ARUPT 02005 2005 3 0,0001 0 XCH Q 02006 2006 5 0,0027 1 TS QRUPT 02007 2007 0 1,2742 1 TC goT3 ORG ERRUPT 02010 2010 5 0,0026 0 TS ARUPT 02011 2011 3 0,0001 0 XCH Q 02012 2012 5 0,0027 1 TS QRUPT 02013 2013 0 1,2742 1 TC goER ORG DSRUPT 02014 2014 5 0,0026 0 TS ARUPT 02015 2015 3 0,0001 0 XCH Q 02016 2016 5 0,0027 1 TS QRUPT 02017 2017 0 1,2742 1 TC goDS ORG KEYRUPT 02020 2020 5 0,0026 0 TS ARUPT 02021 2021 3 0,0001 0 XCH Q 02022 2022 5 0,0027 1 TS QRUPT 02023 2023 0 1,2742 1 TC goKEY ORG UPRUPT 02024 2024 5 0,0026 0 TS ARUPT 02025 2025 3 0,0001 0 XCH Q 02026 2026 5 0,0027 1 TS QRUPT 02027 2027 0 1,2742 1 TC goUP ; ---------------------------------------------- ; FIXED MEMORY -- SHARED DATA SEGMENT ; ---------------------------------------------- ; MAIN PROGRAM goMAIN EQU * 02030 2030 2 0,0000 0 INHINT ; disable interrupts 02031 2031 0 1,2042 0 TCR begin ; Test extracode instructions.02032 2032 0 1,2247 1 TCR chkMP 02033 2033 0 1,2551 1 TCR chkDV 02034 2034 0 1,2635 0 TCR chkSU
; Passed all tests.02035 2035 0 1,2737 0 TCR finish fail EQU * 02036 2036 3 0,0100 0 XCH curtest ; load last passed test into A02037 2037 5 0,0100 0 TS curtest end EQU * 02040 2040 0 1,2040 1 TC end ; finished, TC trap ; ---------------------------------------------- ; INITIALIZE FOR START OF TESTING 02041 2041 00000 1 STRTcode DS START begin EQU * 02042 2042 3 1,2041 0 XCH STRTcode 02043 2043 5 0,0100 0 TS curtest ; set current test code to START02044 2044 0 0,0000 0 RETURN ; ---------------------------------------------- ; TEST MP INSTRUCTION SUBROUTINE ; L: MP K ; Verifies the following ; - Set C(A,LP) = b(A) * C(K) ; - Take next instruction from L+1 02045 2045 00001 0 MPcode DS MPtst ; code for this test ; MP test values ; 02046 2046 00037 0 MPstart DS 31 ; loop MPstart+1 times ; C(A) test values mp1 EQU * ; check boundary conditions02047 2047 37777 1 DS %37777 ; check #00 (+16383 * +16383)02050 2050 37777 1 DS %37777 ; check #01 (+16383 * -16383)02051 2051 40000 0 DS %40000 ; check #02 (-16383 * +16383)02052 2052 40000 0 DS %40000 ; check #03 (-16383 * -16383)02053 2053 00000 1 DS %00000 ; check #04 (+0 * +0)02054 2054 00000 1 DS %00000 ; check #05 (+0 * -0)02055 2055 77777 0 DS %77777 ; check #06 (-0 * +0)02056 2056 77777 0 DS %77777 ; check #07 (-0 * -0) ; randomly selected checks (one word product)02057 2057 00007 0 DS %00007 ; check #08 (7 * 17)02060 2060 00021 1 DS %00021 ; check #09 (17 * 7)02061 2061 00035 1 DS %00035 ; check #10 (29 * 41)02062 2062 00051 0 DS %00051 ; check #11 (41 * 29)02063 2063 00065 1 DS %00065 ; check #12 (53 * 67)02064 2064 00103 0 DS %00103 ; check #13 (67 * 53)02065 2065 00117 0 DS %00117 ; check #14 (79 * 97)02066 2066 00141 0 DS %00141 ; check #15 (97 * 79)02067 2067 00153 0 DS %00153 ; check #16 (107 * 127)02070 2070 00177 0 DS %00177 ; check #17 (127 * 107) ; randomly selected checks (two word product)02071 2071 00375 0 DS %00375 ; check #18 (253 * 197)02072 2072 00305 1 DS %00305 ; check #19 (197 * 253)02073 2073 00655 1 DS %00655 ; check #20 (429 * 351)02074 2074 00537 0 DS %00537 ; check #21 (351 * 429)02075 2075 02455 1 DS %02455 ; check #22 (1325 * 1067)02076 2076 02053 0 DS %02053 ; check #23 (1067 * 1325)02077 2077 11151 1 DS %11151 ; check #24 (4713 * 3605)02100 2100 07025 1 DS %07025 ; check #25 (3605 * 4713)02101 2101 20032 1 DS %20032 ; check #26 (8218 * 7733)02102 2102 17065 1 DS %17065 ; check #27 (7733 * 8218)02103 2103 30273 1 DS %30273 ; check #28 (12475 * 11501)02104 2104 26355 0 DS %26355 ; check #29 (11501 * 12475)02105 2105 37553 0 DS %37553 ; check #30 (16235 * 15372)02106 2106 36014 1 DS %36014 ; check #31 (15372 * 16235) ; C(K) test values mp2 EQU * ; check boundary conditions02107 2107 37777 1 DS %37777 ; check #00 (+16383 * +16383)
02110 2110 40000 0 DS %40000 ; check #01 (+16383 * -16383)02111 2111 37777 1 DS %37777 ; check #02 (-16383 * +16383)02112 2112 40000 0 DS %40000 ; check #03 (-16383 * -16383)02113 2113 00000 1 DS %00000 ; check #04 (+0 * +0)02114 2114 77777 0 DS %77777 ; check #05 (+0 * -0)02115 2115 00000 1 DS %00000 ; check #06 (-0 * +0)02116 2116 77777 0 DS %77777 ; check #07 (-0 * -0) ; randomly selected checks (one word product)02117 2117 00021 1 DS %00021 ; check #08 (7 * 17)02120 2120 00007 0 DS %00007 ; check #09 (17 * 7)02121 2121 00051 0 DS %00051 ; check #10 (29 * 41)02122 2122 00035 1 DS %00035 ; check #11 (41 * 29)02123 2123 00103 0 DS %00103 ; check #12 (53 * 67)02124 2124 00065 1 DS %00065 ; check #13 (67 * 53)02125 2125 00141 0 DS %00141 ; check #14 (79 * 97)02126 2126 00117 0 DS %00117 ; check #15 (97 * 79)02127 2127 00177 0 DS %00177 ; check #16 (107 * 127)02130 2130 00153 0 DS %00153 ; check #17 (127 * 107) ; randomly selected checks (two word product)02131 2131 00305 1 DS %00305 ; check #18 (253 * 197)02132 2132 00375 0 DS %00375 ; check #19 (197 * 253)02133 2133 00537 0 DS %00537 ; check #20 (429 * 351)02134 2134 00655 1 DS %00655 ; check #21 (351 * 429)02135 2135 02053 0 DS %02053 ; check #22 (1325 * 1067)02136 2136 02455 1 DS %02455 ; check #23 (1067 * 1325)02137 2137 07025 1 DS %07025 ; check #24 (4713 * 3605)02140 2140 11151 1 DS %11151 ; check #25 (3605 * 4713)02141 2141 17065 1 DS %17065 ; check #26 (8218 * 7733)02142 2142 20032 1 DS %20032 ; check #27 (7733 * 8218)02143 2143 26355 0 DS %26355 ; check #28 (12475 * 11501)02144 2144 30273 1 DS %30273 ; check #29 (11501 * 12475)02145 2145 36014 1 DS %36014 ; check #30 (16235 * 15372)02146 2146 37553 0 DS %37553 ; check #31 (15372 * 16235) ; A = upper product MPchkA EQU * ; check boundary conditions02147 2147 37776 0 DS %37776 ; check #0002150 2150 40001 1 DS %40001 ; check #0102151 2151 40001 1 DS %40001 ; check #0202152 2152 37776 0 DS %37776 ; check #0302153 2153 00000 1 DS %00000 ; check #0402154 2154 77777 0 DS %77777 ; check #0502155 2155 77777 0 DS %77777 ; check #0602156 2156 00000 1 DS %00000 ; check #07 ; randomly selected checks02157 2157 00000 1 DS %00000 ; check #08 (7 * 17)02160 2160 00000 1 DS %00000 ; check #09 (17 * 7)02161 2161 00000 1 DS %00000 ; check #10 (29 * 41)02162 2162 00000 1 DS %00000 ; check #11 (41 * 29)02163 2163 00000 1 DS %00000 ; check #12 (53 * 67)02164 2164 00000 1 DS %00000 ; check #13 (67 * 53)02165 2165 00000 1 DS %00000 ; check #14 (79 * 97)02166 2166 00000 1 DS %00000 ; check #15 (97 * 79)02167 2167 00000 1 DS %00000 ; check #16 (107 * 127)02170 2170 00000 1 DS %00000 ; check #17 (127 * 107) ; randomly selected checks (two word product)02171 2171 00003 1 DS %00003 ; check #18 (253 * 197)02172 2172 00003 1 DS %00003 ; check #19 (197 * 253)02173 2173 00011 1 DS %00011 ; check #20 (429 * 351)02174 2174 00011 1 DS %00011 ; check #21 (351 * 429)02175 2175 00126 1 DS %00126 ; check #22 (1325 * 1067)02176 2176 00126 1 DS %00126 ; check #23 (1067 * 1325)02177 2177 02015 1 DS %02015 ; check #24 (4713 * 3605)02200 2200 02015 1 DS %02015 ; check #25 (3605 * 4713)02201 2201 07446 0 DS %07446 ; check #26 (8218 * 7733)02202 2202 07446 0 DS %07446 ; check #27 (7733 * 8218)02203 2203 21065 1 DS %21065 ; check #28 (12475 * 11501)02204 2204 21065 1 DS %21065 ; check #29 (11501 * 12475)02205 2205 35600 1 DS %35600 ; check #30 (16235 * 15372)02206 2206 35600 1 DS %35600 ; check #31 (15372 * 16235) ; LP = lower product MPchkLP EQU * ; check boundary conditions02207 2207 00001 0 DS %00001 ; check #00
02210 2210 77776 1 DS %77776 ; check #0102211 2211 77776 1 DS %77776 ; check #0202212 2212 00001 0 DS %00001 ; check #0302213 2213 00000 1 DS %00000 ; check #0402214 2214 77777 0 DS %77777 ; check #0502215 2215 77777 0 DS %77777 ; check #0602216 2216 00000 1 DS %00000 ; check #07 ; randomly selected checks02217 2217 00167 1 DS %00167 ; check #08 (7 * 17)02220 2220 00167 1 DS %00167 ; check #09 (17 * 7)02221 2221 02245 0 DS %02245 ; check #10 (29 * 41)02222 2222 02245 0 DS %02245 ; check #11 (41 * 29)02223 2223 06737 1 DS %06737 ; check #12 (53 * 67)02224 2224 06737 1 DS %06737 ; check #13 (67 * 53)02225 2225 16757 0 DS %16757 ; check #14 (79 * 97)02226 2226 16757 0 DS %16757 ; check #15 (97 * 79)02227 2227 32425 0 DS %32425 ; check #16 (107 * 127)02230 2230 32425 0 DS %32425 ; check #17 (127 * 107) ; randomly selected checks (two word product)02231 2231 01261 0 DS %01261 ; check #18 (253 * 197)02232 2232 01261 0 DS %01261 ; check #19 (197 * 253)02233 2233 06063 1 DS %06063 ; check #20 (429 * 351)02234 2234 06063 1 DS %06063 ; check #21 (351 * 429)02235 2235 11217 0 DS %11217 ; check #22 (1325 * 1067)02236 2236 11217 0 DS %11217 ; check #23 (1067 * 1325)02237 2237 00235 0 DS %00235 ; check #24 (4713 * 3605)02240 2240 00235 0 DS %00235 ; check #24 (3605 * 4713)02241 2241 30542 1 DS %30542 ; check #26 (8218 * 7733)02242 2242 30542 1 DS %30542 ; check #27 (7733 * 8218)02243 2243 00437 1 DS %00437 ; check #28 (12475 * 11501)02244 2244 00437 1 DS %00437 ; check #29 (11501 * 12475)02245 2245 06404 1 DS %06404 ; check #30 (16235 * 15372)02246 2246 06404 1 DS %06404 ; check #31 (15372 * 16235) chkMP EQU * 02247 2247 3 0,0001 0 XCH Q 02250 2250 5 0,0101 1 TS savQ ; save return address 02251 2251 3 1,2045 1 CAF MPcode 02252 2252 5 0,0100 0 TS curtest ; set test code to this test ; Decrementing loop ; - always executes at least once (tests at end of loop)
; - loops 'MPstart+1' times; decrements MPindex02253 2253 3 1,2046 1 XCH MPstart ; initialize loop counter ;------------------------------ ; MP check starts here ; uses MPindex to access test values MPloop EQU * 02254 2254 5 0,0102 1 TS MPindex ; save new index 02255 2255 3 2,5777 0 CAF EXTENDER 02256 2256 6 0,0102 1 AD MPindex 02257 2257 5 0,0103 0 TS MPXTND 02260 2260 2 0,0102 0 INDEX MPindex 02261 2261 3 1,2047 0 CAF mp1 02262 2262 2 0,0103 1 INDEX MPXTND ; EXTEND using MPindex02263 2263 4 1,2107 1 MP mp2 ; verify C(A)02264 2264 4 0,0000 0 COM ; get -A02265 2265 2 0,0102 0 INDEX MPindex 02266 2266 6 1,2147 1 AD MPchkA ; put (-A) + expected value in A02267 2267 1 0,0000 0 CCS A ; compare02270 2270 0 1,2036 0 TC fail ; >0 (A < expected value)02271 2271 0 1,2036 0 TC fail ; +002272 2272 0 1,2036 0 TC fail ; <0 (A > expected value) ; verify C(LP)02273 2273 4 0,0003 0 CS LP ; get -A02274 2274 2 0,0102 0 INDEX MPindex 02275 2275 6 1,2207 0 AD MPchkLP ; put (-A) + expected value in A02276 2276 1 0,0000 0 CCS A ; compare
02277 2277 0 1,2036 0 TC fail ; >0 (A < expected value)02300 2300 0 1,2036 0 TC fail ; +002301 2301 0 1,2036 0 TC fail ; <0 (A > expected value) ; end of MP check ;------------------------------ 02302 2302 1 0,0102 0 CCS MPindex ; done?02303 2303 0 1,2254 0 TC MPloop ; not yet, do next check 02304 2304 3 0,0101 1 XCH savQ 02305 2305 5 0,0001 0 TS Q ; restore return address02306 2306 0 0,0000 0 RETURN ; ---------------------------------------------- ; TEST DV INSTRUCTION SUBROUTINE ; L: DV K ; Verifies the following: ; - Set C(A) = b(A) / C(K) ; - Set C(Q) = - abs(remainder) ; - Set C(LP) > 0 if quotient is positive ; - Set C(LP) < 0 if quotient is negative ; - Take next instruction from L+1 02307 2307 00002 0 DVcode DS DVtst ; code for this test ; DV test values ; 02310 2310 00037 0 DVstart DS 31 ; loop DVstart+1 times ; C(A) test values div1 EQU * 02311 2311 00000 1 DS %00000 ; check #00 (+0/+0)02312 2312 00000 1 DS %00000 ; check #01 (+0/-0)02313 2313 77777 0 DS %77777 ; check #02 (-0/+0)02314 2314 77777 0 DS %77777 ; check #03 (-0/-0) 02315 2315 00000 1 DS %00000 ; check #04 (+0/+1)02316 2316 00000 1 DS %00000 ; check #05 (+0/-1)02317 2317 77777 0 DS %77777 ; check #06 (-0/+1)02320 2320 77777 0 DS %77777 ; check #07 (-0/-1) 02321 2321 00000 1 DS %00000 ; check #08 (+0/+16383)02322 2322 00000 1 DS %00000 ; check #09 (+0/-16383)02323 2323 77777 0 DS %77777 ; check #10 (-0/+16383)02324 2324 77777 0 DS %77777 ; check #11 (-0/-16383) 02325 2325 37776 0 DS %37776 ; check #12 (+16382/+16383)02326 2326 37776 0 DS %37776 ; check #13 (+16382/-16383)02327 2327 40001 1 DS %40001 ; check #14 (-16382/+16383)02330 2330 40001 1 DS %40001 ; check #15 (-16382/-16383) 02331 2331 37777 1 DS %37777 ; check #16 (+16383/+16383)02332 2332 37777 1 DS %37777 ; check #17 (+16383/-16383)02333 2333 40000 0 DS %40000 ; check #18 (-16383/+16383)02334 2334 40000 0 DS %40000 ; check #19 (-16383/-16383) 02335 2335 00001 0 DS %00001 ; check #20 (+1/+2)02336 2336 00001 0 DS %00001 ; check #21 (+1/+3)02337 2337 00001 0 DS %00001 ; check #22 (+1/+4)02340 2340 00001 0 DS %00001 ; check #23 (+1/+5)02341 2341 00001 0 DS %00001 ; check #24 (+1/+6)02342 2342 00001 0 DS %00001 ; check #25 (+1/+7)02343 2343 00001 0 DS %00001 ; check #26 (+1/+8) 02344 2344 00001 0 DS %00001 ; check #27 (+1/+6)02345 2345 00002 0 DS %00002 ; check #28 (+2/+12)02346 2346 00004 0 DS %00004 ; check #29 (+4/+24)02347 2347 00010 0 DS %00010 ; check #30 (+8/+48)02350 2350 00020 0 DS %00020 ; check #31 (+16/+96) ; C(K) test values div2 EQU * 02351 2351 00000 1 DS %00000 ; check #00 (+0/+0)02352 2352 77777 0 DS %77777 ; check #01 (+0/-0)02353 2353 00000 1 DS %00000 ; check #02 (-0/+0)02354 2354 77777 0 DS %77777 ; check #03 (-0/-0)
02355 2355 00001 0 DS %00001 ; check #04 (+0/+1)02356 2356 77776 1 DS %77776 ; check #05 (+0/-1)02357 2357 00001 0 DS %00001 ; check #06 (-0/+1)02360 2360 77776 1 DS %77776 ; check #07 (-0/-1) 02361 2361 37777 1 DS %37777 ; check #08 (+0/+16383)02362 2362 40000 0 DS %40000 ; check #09 (+0/-16383)02363 2363 37777 1 DS %37777 ; check #10 (-0/+16383)02364 2364 40000 0 DS %40000 ; check #11 (-0/-16383) 02365 2365 37777 1 DS %37777 ; check #12 (+16382/+16383)02366 2366 40000 0 DS %40000 ; check #13 (+16382/-16383)02367 2367 37777 1 DS %37777 ; check #14 (-16382/+16383)02370 2370 40000 0 DS %40000 ; check #15 (-16382/-16383) 02371 2371 37777 1 DS %37777 ; check #16 (+16383/+16383)02372 2372 40000 0 DS %40000 ; check #17 (+16383/-16383)02373 2373 37777 1 DS %37777 ; check #18 (-16383/+16383)02374 2374 40000 0 DS %40000 ; check #19 (-16383/-16383) 02375 2375 00002 0 DS %00002 ; check #20 (+1/+2)02376 2376 00003 1 DS %00003 ; check #21 (+1/+3)02377 2377 00004 0 DS %00004 ; check #22 (+1/+4)02400 2400 00005 1 DS %00005 ; check #23 (+1/+5)02401 2401 00006 1 DS %00006 ; check #24 (+1/+6)02402 2402 00007 0 DS %00007 ; check #25 (+1/+7)02403 2403 00010 0 DS %00010 ; check #26 (+1/+8) 02404 2404 00006 1 DS %00006 ; check #27 (+1/+6)02405 2405 00014 1 DS %00014 ; check #28 (+2/+12)02406 2406 00030 1 DS %00030 ; check #29 (+4/+24)02407 2407 00060 1 DS %00060 ; check #30 (+8/+48)02410 2410 00140 1 DS %00140 ; check #31 (+16/+96) ; A = quotient DVchkA EQU * 02411 2411 37777 1 DS %37777 ; check #00 (+0/+0)02412 2412 40000 0 DS %40000 ; check #01 (+0/-0)02413 2413 40000 0 DS %40000 ; check #02 (-0/+0)02414 2414 37777 1 DS %37777 ; check #03 (-0/-0) 02415 2415 00000 1 DS %00000 ; check #04 (+0/+1)02416 2416 77777 0 DS %77777 ; check #05 (+0/-1)02417 2417 77777 0 DS %77777 ; check #06 (-0/+1)02420 2420 00000 1 DS %00000 ; check #07 (-0/-1) 02421 2421 00000 1 DS %00000 ; check #08 (+0/+16383)02422 2422 77777 0 DS %77777 ; check #09 (+0/-16383)02423 2423 77777 0 DS %77777 ; check #10 (-0/+16383)02424 2424 00000 1 DS %00000 ; check #11 (-0/-16383) 02425 2425 37776 0 DS %37776 ; check #12 (+16382/+16383)02426 2426 40001 1 DS %40001 ; check #13 (+16382/-16383)02427 2427 40001 1 DS %40001 ; check #14 (-16382/+16383)02430 2430 37776 0 DS %37776 ; check #15 (-16382/-16383) 02431 2431 37777 1 DS %37777 ; check #16 (+16383/+16383)02432 2432 40000 0 DS %40000 ; check #17 (+16383/-16383)02433 2433 40000 0 DS %40000 ; check #18 (-16383/+16383)02434 2434 37777 1 DS %37777 ; check #19 (-16383/-16383) 02435 2435 20000 0 DS %20000 ; check #20 (+1/+2)02436 2436 12525 0 DS %12525 ; check #21 (+1/+3)02437 2437 10000 0 DS %10000 ; check #22 (+1/+4)02440 2440 06314 1 DS %06314 ; check #23 (+1/+5)02441 2441 05252 1 DS %05252 ; check #24 (+1/+6)02442 2442 04444 1 DS %04444 ; check #25 (+1/+7)02443 2443 04000 0 DS %04000 ; check #26 (+1/+8) 02444 2444 05252 1 DS %05252 ; check #27 (+1/+6)02445 2445 05252 1 DS %05252 ; check #28 (+2/+12)02446 2446 05252 1 DS %05252 ; check #29 (+4/+24)02447 2447 05252 1 DS %05252 ; check #30 (+8/+48)02450 2450 05252 1 DS %05252 ; check #31 (+16/+96)
; Q = remainder DVchkQ EQU * 02451 2451 77777 0 DS %77777 ; check #00 (+0/+0)02452 2452 77777 0 DS %77777 ; check #01 (+0/-0)02453 2453 77777 0 DS %77777 ; check #02 (-0/+0)02454 2454 77777 0 DS %77777 ; check #03 (-0/-0) 02455 2455 77777 0 DS %77777 ; check #04 (+0/+1)02456 2456 77777 0 DS %77777 ; check #05 (+0/-1)02457 2457 77777 0 DS %77777 ; check #06 (-0/+1)02460 2460 77777 0 DS %77777 ; check #07 (-0/-1) 02461 2461 77777 0 DS %77777 ; check #08 (+0/+16383)02462 2462 77777 0 DS %77777 ; check #09 (+0/-16383)02463 2463 77777 0 DS %77777 ; check #10 (-0/+16383)02464 2464 77777 0 DS %77777 ; check #11 (-0/-16383) 02465 2465 40001 1 DS %40001 ; check #12 (+16382/+16383)02466 2466 40001 1 DS %40001 ; check #13 (+16382/-16383)02467 2467 40001 1 DS %40001 ; check #14 (-16382/+16383)02470 2470 40001 1 DS %40001 ; check #15 (-16382/-16383) 02471 2471 40000 0 DS %40000 ; check #16 (+16383/+16383)02472 2472 40000 0 DS %40000 ; check #17 (+16383/-16383)02473 2473 40000 0 DS %40000 ; check #18 (-16383/+16383)02474 2474 40000 0 DS %40000 ; check #19 (-16383/-16383) 02475 2475 77777 0 DS %77777 ; check #20 (+1/+2)02476 2476 77776 1 DS %77776 ; check #21 (+1/+3)02477 2477 77777 0 DS %77777 ; check #22 (+1/+4)02500 2500 77773 1 DS %77773 ; check #23 (+1/+5)02501 2501 77773 1 DS %77773 ; check #24 (+1/+6)02502 2502 77773 1 DS %77773 ; check #25 (+1/+7)02503 2503 77777 0 DS %77777 ; check #26 (+1/+8) 02504 2504 77773 1 DS %77773 ; check #27 (+1/+6)02505 2505 77767 1 DS %77767 ; check #28 (+2/+12)02506 2506 77757 1 DS %77757 ; check #29 (+4/+24)02507 2507 77737 1 DS %77737 ; check #30 (+8/+48)02510 2510 77677 1 DS %77677 ; check #31 (+16/+96) ; LP = sign DVchkLP EQU * 02511 2511 00001 0 DS %00001 ; check #00 (+0/+0)02512 2512 40000 0 DS %40000 ; check #01 (+0/-0)02513 2513 40001 1 DS %40001 ; check #02 (-0/+0)02514 2514 00001 0 DS %00001 ; check #03 (-0/-0) 02515 2515 00001 0 DS %00001 ; check #04 (+0/+1)02516 2516 40000 0 DS %40000 ; check #05 (+0/-1)02517 2517 40001 1 DS %40001 ; check #06 (-0/+1)02520 2520 00001 0 DS %00001 ; check #07 (-0/-1) 02521 2521 00001 0 DS %00001 ; check #08 (+0/+16383)02522 2522 40000 0 DS %40000 ; check #09 (+0/-16383)02523 2523 40001 1 DS %40001 ; check #10 (-0/+16383)02524 2524 00001 0 DS %00001 ; check #11 (-0/-16383) 02525 2525 00001 0 DS %00001 ; check #12 (+16382/+16383)02526 2526 40000 0 DS %40000 ; check #13 (+16382/-16383)02527 2527 40001 1 DS %40001 ; check #14 (-16382/+16383)02530 2530 00001 0 DS %00001 ; check #15 (-16382/-16383) 02531 2531 00001 0 DS %00001 ; check #16 (+16383/+16383)02532 2532 40000 0 DS %40000 ; check #17 (+16383/-16383)02533 2533 40001 1 DS %40001 ; check #18 (-16383/+16383)02534 2534 00001 0 DS %00001 ; check #19 (-16383/-16383) 02535 2535 00001 0 DS %00001 ; check #20 (+1/+2)02536 2536 00001 0 DS %00001 ; check #21 (+1/+3)02537 2537 00001 0 DS %00001 ; check #22 (+1/+4)02540 2540 00001 0 DS %00001 ; check #23 (+1/+5)02541 2541 00001 0 DS %00001 ; check #24 (+1/+6)02542 2542 00001 0 DS %00001 ; check #25 (+1/+7)02543 2543 00001 0 DS %00001 ; check #26 (+1/+8)
02544 2544 00001 0 DS %00001 ; check #27 (+1/+6)02545 2545 00001 0 DS %00001 ; check #28 (+2/+12)02546 2546 00001 0 DS %00001 ; check #29 (+4/+24)02547 2547 00001 0 DS %00001 ; check #30 (+8/+48)02550 2550 00001 0 DS %00001 ; check #31 (+16/+96) chkDV EQU * 02551 2551 3 0,0001 0 XCH Q 02552 2552 5 0,0101 1 TS savQ ; save return address 02553 2553 3 1,2307 1 CAF DVcode 02554 2554 5 0,0100 0 TS curtest ; set code identifying test ; Decrementing loop ; - always executes at least once (tests at end of loop)
; - loops 'DVstart+1' times; decrements DVindex02555 2555 3 1,2310 1 XCH DVstart ; initialize loop counter ;------------------------------ ; DV check starts here ; uses DVindex to access test values DVloop EQU * 02556 2556 5 0,0105 0 TS DVindex ; save new index 02557 2557 3 2,5777 0 CAF EXTENDER 02560 2560 6 0,0105 0 AD DVindex 02561 2561 5 0,0106 0 TS DVXTND 02562 2562 2 0,0105 1 INDEX DVindex 02563 2563 3 1,2311 0 CAF div1 02564 2564 2 0,0106 1 INDEX DVXTND ; EXTEND using DVindex02565 2565 5 1,2351 1 DV div2 02566 2566 5 0,0104 1 TS DVsavA ; verify C(Q)02567 2567 4 0,0001 1 CS Q ; get -A02570 2570 2 0,0105 1 INDEX DVindex 02571 2571 6 1,2451 0 AD DVchkQ ; put (-A) + expected value in A02572 2572 1 0,0000 0 CCS A ; compare02573 2573 0 1,2036 0 TC fail ; >0 (A < expected value)02574 2574 0 1,2036 0 TC fail ; +002575 2575 0 1,2036 0 TC fail ; <0 (A > expected value) ; verify C(A)02576 2576 4 0,0104 0 CS DVsavA ; get -A02577 2577 2 0,0105 1 INDEX DVindex 02600 2600 6 1,2411 1 AD DVchkA ; put (-A) + expected value in A02601 2601 1 0,0000 0 CCS A ; compare02602 2602 0 1,2036 0 TC fail ; >0 (A < expected value)02603 2603 0 1,2036 0 TC fail ; +002604 2604 0 1,2036 0 TC fail ; <0 (A > expected value) ; verify C(LP)02605 2605 4 0,0003 0 CS LP ; get -A02606 2606 2 0,0105 1 INDEX DVindex 02607 2607 6 1,2511 0 AD DVchkLP ; put (-A) + expected value in A02610 2610 1 0,0000 0 CCS A ; compare02611 2611 0 1,2036 0 TC fail ; >0 (A < expected value)02612 2612 0 1,2036 0 TC fail ; +002613 2613 0 1,2036 0 TC fail ; <0 (A > expected value) ; end of DV check ;------------------------------ 02614 2614 1 0,0105 1 CCS DVindex ; done?02615 2615 0 1,2556 0 TC DVloop ; not yet, do next check 02616 2616 3 0,0101 1 XCH savQ 02617 2617 5 0,0001 0 TS Q ; restore return address02620 2620 0 0,0000 0 RETURN ; ---------------------------------------------- ; TEST SU INSTRUCTION SUBROUTINE
; L: SU K ; Verifies the following: ; - Set C(A) = b(A) - C(K) ; - Take next instruction from L+1 ; - if C(A) has positive overflow, ; -- increment overflow counter by 1 ; - if C(A) has negative overflow, ; -- decrement overflow counter by 1 02621 2621 00003 1 SUcode DS SUtst ; code for this test 02622 2622 00000 1 SUplus0 DS +0 02623 2623 00001 0 SUplus1 DS 1 02624 2624 77776 1 SUmin1 DS -1 02625 2625 25252 0 SU25252 DS %25252 ; +10922 decimal02626 2626 12525 0 SU12525 DS %12525 ; +5461 decimal02627 2627 37777 1 SU37777 DS %37777 ; largest positive number02630 2630 12524 1 SU12524 DS %12524 ; + overflow of %25252+%25252 02631 2631 52525 1 SU52525 DS %52525 ; -10922 decimal02632 2632 65252 1 SU65252 DS %65252 ; -5461 decimal02633 2633 40000 0 SU40000 DS %40000 ; largest negative number02634 2634 65253 0 SU65253 DS %65253 ; - overflow of %52525+65252 chkSU EQU * 02635 2635 3 0,0001 0 XCH Q 02636 2636 5 0,0101 1 TS savQ ; save return address 02637 2637 3 1,2621 0 CAF SUcode 02640 2640 5 0,0100 0 TS curtest ; set test code to this test ; NOTE: these test are similar to the checks for AD, but ; the AD augend value has been changed to negative and AD has ; been changed to SU. The results produced by this change ; are identical to AD, and so the checks are the same. ; TEST1: difference positive, no overflow ; sub: %25252 - %65252 = %37777 (sign + 14 magnitude)02641 2641 3 1,2625 1 CAF SU25252 02642 2642 2 0,0000 1 EXTEND 02643 2643 6 1,2632 1 SU SU65252 ; verify C(A) = %3777702644 2644 4 0,0000 0 COM ; get -A02645 2645 6 1,2627 0 AD SU37777 ; put (-A) + expected value in A02646 2646 1 0,0000 0 CCS A ; compare02647 2647 0 1,2036 0 TC fail ; >0 (A < expected value)02650 2650 0 1,2036 0 TC fail ; +002651 2651 0 1,2036 0 TC fail ; <0 (A > expected value) ; TEST2: difference negative, no overflow (sign + 14 magnitude) ; sub: %52525 - %12525 = %4000002652 2652 3 1,2631 1 CAF SU52525 02653 2653 2 0,0000 1 EXTEND 02654 2654 6 1,2626 1 SU SU12525 ; verify C(A) = %4000002655 2655 4 0,0000 0 COM ; get -A02656 2656 6 1,2633 0 AD SU40000 ; put (-A) + expected value in A02657 2657 1 0,0000 0 CCS A ; compare02660 2660 0 1,2036 0 TC fail ; >0 (A < expected value)02661 2661 0 1,2036 0 TC fail ; +002662 2662 0 1,2036 0 TC fail ; <0 (A > expected value) ; TEST3: difference positive, overflow ; initialize overflow counter and positive overflow storage02663 2663 3 1,2622 0 CAF SUplus0 02664 2664 5 0,0034 0 TS OVFCNTR 02665 2665 5 0,0107 1 TS SUk ; sub: %25252 - %52525 = %52524 (sign + 14 magnitude)02666 2666 3 1,2625 1 CAF SU25252 02667 2667 2 0,0000 1 EXTEND 02670 2670 6 1,2631 1 SU SU52525 02671 2671 5 0,0107 1 TS SUk ; store positive overflow02672 2672 0 1,2036 0 TC fail ; verify SUk = %1252402673 2673 4 0,0107 0 CS SUk ; get -A
02674 2674 6 1,2630 0 AD SU12524 ; put (-A) + expected value in A02675 2675 1 0,0000 0 CCS A ; compare02676 2676 0 1,2036 0 TC fail ; >0 (A < expected value)02677 2677 0 1,2036 0 TC fail ; +002700 2700 0 1,2036 0 TC fail ; <0 (A > expected value) ; verify overflow counter =%0000102701 2701 4 0,0034 1 CS OVFCNTR ; get -A02702 2702 6 1,2623 1 AD SUplus1 ; put (-A) + expected value in A02703 2703 1 0,0000 0 CCS A ; compare02704 2704 0 1,2036 0 TC fail ; >0 (A < expected value)02705 2705 0 1,2036 0 TC fail ; +002706 2706 0 1,2036 0 TC fail ; <0 (A > expected value) ; TEST4: difference negative, overflow02707 2707 3 1,2622 0 CAF SUplus0 02710 2710 5 0,0034 0 TS OVFCNTR 02711 2711 5 0,0107 1 TS SUk ; add: %52525 + %25252 = %25253 (sign + 14 magnitude)02712 2712 3 1,2631 1 CAF SU52525 02713 2713 2 0,0000 1 EXTEND 02714 2714 6 1,2625 1 SU SU25252 02715 2715 5 0,0107 1 TS SUk ; store negative overflow02716 2716 0 1,2036 0 TC fail ; verify SUk = %6525302717 2717 4 0,0107 0 CS SUk ; get -A02720 2720 6 1,2634 1 AD SU65253 ; put (-A) + expected value in A02721 2721 1 0,0000 0 CCS A ; compare02722 2722 0 1,2036 0 TC fail ; >0 (A < expected value)02723 2723 0 1,2036 0 TC fail ; +002724 2724 0 1,2036 0 TC fail ; <0 (A > expected value) ; verify overflow counter =%7777602725 2725 4 0,0034 1 CS OVFCNTR ; get -A02726 2726 6 1,2624 0 AD SUmin1 ; put (-A) + expected value in A02727 2727 1 0,0000 0 CCS A ; compare02730 2730 0 1,2036 0 TC fail ; >0 (A < expected value)02731 2731 0 1,2036 0 TC fail ; +002732 2732 0 1,2036 0 TC fail ; <0 (A > expected value) 02733 2733 3 0,0101 1 XCH savQ 02734 2734 5 0,0001 0 TS Q ; restore return address02735 2735 0 0,0000 0 RETURN ; ---------------------------------------------- ; PASSED ALL TESTS! 02736 2736 12345 0 PASScode DS PASS finish EQU * 02737 2737 3 1,2736 1 CAF PASScode 02740 2740 5 0,0100 0 TS curtest ; set current test code to PASS02741 2741 0 0,0000 0 RETURN ; ---------------------------------------------- ; INTERRUPT SERVICE ROUTINE goT3 EQU * goER EQU * goDS EQU * goKEY EQU * goUP EQU * endRUPT EQU * 02742 2742 3 0,0027 1 XCH QRUPT ; restore Q02743 2743 5 0,0001 0 TS Q 02744 2744 3 0,0026 0 XCH ARUPT ; restore A02745 2745 2 0,0000 1 RESUME ; finished, go back
Assembly complete. Errors = 0
Symbol table:START 000000 MPtst 000001 DVtst 000002 SUtst 000003 PASS 012345 EXTENDER 005777 OVFCNTR 000034 curtest 000100 savQ 000101
MPindex 000102 MPXTND 000103 DVsavA 000104 DVindex 000105 DVXTND 000106 SUk 000107 GOPROG 002000 T3RUPT 002004 ERRUPT 002010 DSRUPT 002014 KEYRUPT 002020 UPRUPT 002024 goMAIN 002030 fail 002036 end 002040 STRTcode 002041 begin 002042 MPcode 002045 MPstart 002046 mp1 002047 mp2 002107 MPchkA 002147 MPchkLP 002207 chkMP 002247 MPloop 002254 DVcode 002307 DVstart 002310 div1 002311 div2 002351 DVchkA 002411 DVchkQ 002451 DVchkLP 002511 chkDV 002551 DVloop 002556 SUcode 002621 SUplus0 002622 SUplus1 002623 SUmin1 002624 SU25252 002625 SU12525 002626 SU37777 002627 SU12524 002630 SU52525 002631 SU65252 002632 SU40000 002633 SU65253 002634 chkSU 002635 PASScode 002736 finish 002737 goT3 002742 goER 002742 goDS 002742 goKEY 002742 goUP 002742 endRUPT 002742 ARUPT 000026 Q 000001 QRUPT 000027 A 000000 LP 000003
TECO3 assembler listing
Block I Apollo Guidance Computer (AGC4) assembler version 1.6 for EPROM
First pass: generate symbol table.Second pass: generate object code.
; TECO3 (file:teco3.asm) ; ; Version: 1.0 ; Author: John Pultorak ; Date: 9/14/2001 ; ; PURPOSE: ; Test and checkout program for the Block 1 Apollo Guidance Computer. ; Tests editing registers: CYR, SR, CYL, SL. ; ; OPERATION: ; Enters an infinite loop at the end of the test. The A register ; contains the code for the test that failed, or the PASS code if all ; tests succeeded. See test codes below. ; ; ERRATA: ; - Written for the AGC4R assembler. The assembler directives and ; syntax differ somewhat from the original AGC assembler. ; - The tests attempt to check all threads, but are not exhaustive. ; ; SOURCES: ; Information on the Block 1 architecture: instruction set, instruction ; sequences, registers, register transfers, control pulses, memory and ; memory addressing, I/O assignments, interrupts, and involuntary ; counters was obtained from: ; ; A. Hopkins, R. Alonso, and H. Blair-Smith, "Logical Description ; for the Apollo Guidance Computer (AGC4)", R-393, ; MIT Instrumentation Laboratory, Cambridge, MA, Mar. 1963. ; ; Supplementary information was obtained from: ; ; R. Alonso, J. H. Laning, Jr. and H. Blair-Smith, "Preliminary ; MOD 3C Programmer's Manual", E-1077, MIT Instrumentation ; Laboratory, Cambridge, MA, Nov. 1961. ; ; B. I. Savage and A. Drake, "AGC4 Basic Training Manual, Volume I", ; E-2052, MIT Instrumentation Laboratory, Cambridge, ; MA, Jan. 1967. ; ; E. C. Hall, "MIT's Role in Project Apollo, Volume III, Computer ; Subsystem", R-700, MIT Charles Stark Draper Laboratory, ; Cambridge, MA, Aug. 1972. ; ; A. Hopkins, "Guidance Computer Design, Part VI", source unknown. ; ; A. I. Green and J. J. Rocchio, "Keyboard and Display System Program ; for AGC (Program Sunrise)", E-1574, MIT Instrumentation ; Laboratory, Cambridge, MA, Aug. 1964. ; ; E, C. Hall, "Journey to the Moon: The History of the Apollo ; Guidance Computer", AIAA, Reston VA, 1996. ; START EQU %00 CYRtst EQU %01 ; CYR check failed SRtst EQU %02 ; SR check failed CYLtst EQU %03 ; CYL check failed SLtst EQU %04 ; SL check failed PASS EQU %12345 ; PASSED all checks ; ---------------------------------------------- ORG EXTENDER 05777 5777 47777 0 DS %47777 ; needed for EXTEND
; ---------------------------------------------- ; ERASEABLE MEMORY -- DATA SEGMENT ORG %100 ; start of data area00100 0100 00000 1 curtest DS START ; current test00101 0101 00000 1 savQ DS %0 ; CYR test values00102 0102 00000 1 CYRval DS %0 ; current test value00103 0103 00000 1 iCYR DS %0 ; current index ; SR test values00104 0104 00000 1 SRval DS %0 ; current test value00105 0105 00000 1 iSR DS %0 ; current index ; CYL test values00106 0106 00000 1 CYLval DS %0 ; current test value00107 0107 00000 1 iCYL DS %0 ; current index ; SL test values00110 0110 00000 1 SLval DS %0 ; current test value00111 0111 00000 1 iSL DS %0 ; current index ; ---------------------------------------------- ; ENTRY POINTS ; program (re)start ORG GOPROG 02000 2000 0 1,2030 0 TC goMAIN ; interrupt service entry points ORG T3RUPT 02004 2004 5 0,0026 0 TS ARUPT 02005 2005 3 0,0001 0 XCH Q 02006 2006 5 0,0027 1 TS QRUPT 02007 2007 0 1,2424 1 TC goT3 ORG ERRUPT 02010 2010 5 0,0026 0 TS ARUPT 02011 2011 3 0,0001 0 XCH Q 02012 2012 5 0,0027 1 TS QRUPT 02013 2013 0 1,2424 1 TC goER ORG DSRUPT 02014 2014 5 0,0026 0 TS ARUPT 02015 2015 3 0,0001 0 XCH Q 02016 2016 5 0,0027 1 TS QRUPT 02017 2017 0 1,2424 1 TC goDS ORG KEYRUPT 02020 2020 5 0,0026 0 TS ARUPT 02021 2021 3 0,0001 0 XCH Q 02022 2022 5 0,0027 1 TS QRUPT 02023 2023 0 1,2424 1 TC goKEY ORG UPRUPT 02024 2024 5 0,0026 0 TS ARUPT 02025 2025 3 0,0001 0 XCH Q 02026 2026 5 0,0027 1 TS QRUPT 02027 2027 0 1,2424 1 TC goUP ; ---------------------------------------------- ; FIXED MEMORY -- SHARED DATA SEGMENT ; ---------------------------------------------- ; MAIN PROGRAM goMAIN EQU * 02030 2030 2 0,0000 0 INHINT ; disable interrupts 02031 2031 0 1,2043 1 TCR begin ; Test extracode instructions.02032 2032 0 1,2070 1 TCR chkCYR
02033 2033 0 1,2162 0 TCR chkSR 02034 2034 0 1,2255 1 TCR chkCYL 02035 2035 0 1,2347 0 TCR chkSL ; Passed all tests.02036 2036 0 1,2421 1 TCR finish fail EQU * 02037 2037 3 0,0100 0 XCH curtest ; load last passed test into A02040 2040 5 0,0100 0 TS curtest end EQU * 02041 2041 0 1,2041 0 TC end ; finished, TC trap ; ---------------------------------------------- ; INITIALIZE FOR START OF TESTING 02042 2042 00000 1 STRTcode DS START begin EQU * 02043 2043 3 1,2042 0 XCH STRTcode 02044 2044 5 0,0100 0 TS curtest ; set current test code to START02045 2045 0 0,0000 0 RETURN ; ---------------------------------------------- ; TEST CYR EDITING FUNCTION SUBROUTINE ; Rotate a test value right through CYR 15 times. ; Test the value against an expected value for each time. ; After 15 rotations, the value should equal the initial ; value. 02046 2046 00001 0 CYRcode DS CYRtst ; code for this test ; CYR test values02047 2047 03431 1 CYRinit DS %03431 ; init test value02050 2050 00016 0 CYRindx DS 14 ; loop CYRindx+1 times ; check CYR against these values CYRbase EQU * 02051 2051 03431 1 DS %03431 ; check #0 (back to start)02052 2052 07062 1 DS %07062 ; check #102053 2053 16144 1 DS %16144 ; check #202054 2054 34310 1 DS %34310 ; check #302055 2055 70620 1 DS %70620 ; check #402056 2056 61441 1 DS %61441 ; check #502057 2057 43103 1 DS %43103 ; check #602060 2060 06207 1 DS %06207 ; check #702061 2061 14416 1 DS %14416 ; check #802062 2062 31034 1 DS %31034 ; check #902063 2063 62070 1 DS %62070 ; check #1002064 2064 44161 1 DS %44161 ; check #1102065 2065 10343 1 DS %10343 ; check #1202066 2066 20706 1 DS %20706 ; check #1302067 2067 41614 1 DS %41614 ; check #14 chkCYR EQU * 02070 2070 3 0,0001 0 XCH Q 02071 2071 5 0,0101 1 TS savQ ; save return address 02072 2072 3 1,2046 1 CAF CYRcode 02073 2073 5 0,0100 0 TS curtest ; set test code to this test 02074 2074 3 1,2047 0 XCH CYRinit ; init value to rotate02075 2075 5 0,0102 1 TS CYRval 02076 2076 3 1,2050 0 XCH CYRindx ; load init index CYRloop EQU * 02077 2077 5 0,0103 0 TS iCYR ; save index ; rotate A right (CYR)02100 2100 3 0,0102 1 XCH CYRval 02101 2101 5 0,0020 0 TS CYR ; rotate02102 2102 3 0,0020 0 XCH CYR ; put result in A02103 2103 5 0,0102 1 TS CYRval
; verify C(A)02104 2104 4 0,0000 0 COM ; get -A02105 2105 2 0,0103 1 INDEX iCYR 02106 2106 6 1,2051 1 AD CYRbase ; put (-A) + expected value in A02107 2107 1 0,0000 0 CCS A ; compare02110 2110 0 1,2037 1 TC fail ; >0 (A < expected value)02111 2111 0 1,2037 1 TC fail ; +002112 2112 0 1,2037 1 TC fail ; <0 (A > expected value) ; loop back to test next value02113 2113 1 0,0103 1 CCS iCYR ; done?02114 2114 0 1,2077 0 TC CYRloop ; not yet, do next check 02115 2115 3 0,0101 1 XCH savQ 02116 2116 5 0,0001 0 TS Q ; restore return address02117 2117 0 0,0000 0 RETURN ; ---------------------------------------------- ; TEST SR EDITING FUNCTION SUBROUTINE ; Shift a test value right through SR 15 times. ; Test the value against an expected value for each time. ; After 15 shifts, the value should equal the sign (SG). 02120 2120 00002 0 SRcode DS SRtst ; code for this test ; SR test values02121 2121 03431 1 SRinitP DS %03431 ; positive init test value02122 2122 44346 0 SRinitN DS %44346 ; negative init test value02123 2123 00016 0 SRindx DS 14 ; loop SRindx+1 times ; check SR against these values (positive) SRbaseP EQU * 02124 2124 00000 1 DS %00000 ; check #0 (back to start)02125 2125 00000 1 DS %00000 ; check #102126 2126 00000 1 DS %00000 ; check #202127 2127 00000 1 DS %00000 ; check #302130 2130 00000 1 DS %00000 ; check #402131 2131 00001 0 DS %00001 ; check #502132 2132 00003 1 DS %00003 ; check #602133 2133 00007 0 DS %00007 ; check #702134 2134 00016 0 DS %00016 ; check #802135 2135 00034 0 DS %00034 ; check #902136 2136 00070 0 DS %00070 ; check #1002137 2137 00161 1 DS %00161 ; check #1102140 2140 00343 0 DS %00343 ; check #1202141 2141 00706 0 DS %00706 ; check #1302142 2142 01614 0 DS %01614 ; check #14 ; check SR against these values (negative) SRbaseN EQU * 02143 2143 77777 0 DS %77777 ; check #0 (back to start)02144 2144 77777 0 DS %77777 ; check #102145 2145 77776 1 DS %77776 ; check #202146 2146 77774 0 DS %77774 ; check #302147 2147 77771 0 DS %77771 ; check #402150 2150 77762 1 DS %77762 ; check #502151 2151 77744 0 DS %77744 ; check #602152 2152 77710 1 DS %77710 ; check #702153 2153 77621 1 DS %77621 ; check #802154 2154 77443 1 DS %77443 ; check #902155 2155 77107 1 DS %77107 ; check #1002156 2156 76216 0 DS %76216 ; check #1102157 2157 74434 1 DS %74434 ; check #1202160 2160 71071 1 DS %71071 ; check #1302161 2161 62163 1 DS %62163 ; check #14 chkSR EQU * 02162 2162 3 0,0001 0 XCH Q 02163 2163 5 0,0101 1 TS savQ ; save return address 02164 2164 3 1,2120 0 CAF SRcode 02165 2165 5 0,0100 0 TS curtest ; set test code to this test ; TEST 1: shift a postive value.02166 2166 3 1,2121 1 XCH SRinitP ; init value to shift02167 2167 5 0,0104 1 TS SRval
02170 2170 3 1,2123 0 XCH SRindx ; load init index SRloopP EQU * 02171 2171 5 0,0105 0 TS iSR ; save index ; shift A right (SR)02172 2172 3 0,0104 1 XCH SRval 02173 2173 5 0,0021 1 TS SR ; shift02174 2174 3 0,0021 1 XCH SR ; put result in A02175 2175 5 0,0104 1 TS SRval ; verify C(A)02176 2176 4 0,0000 0 COM ; get -A02177 2177 2 0,0105 1 INDEX iSR 02200 2200 6 1,2124 1 AD SRbaseP ; put (-A) + expected value in A02201 2201 1 0,0000 0 CCS A ; compare02202 2202 0 1,2037 1 TC fail ; >0 (A < expected value)02203 2203 0 1,2037 1 TC fail ; +002204 2204 0 1,2037 1 TC fail ; <0 (A > expected value) ; loop back to test next value02205 2205 1 0,0105 1 CCS iSR ; done?02206 2206 0 1,2171 1 TC SRloopP ; not yet, do next check ; TEST 2: shift a negative value02207 2207 3 1,2122 1 XCH SRinitN ; init value to shift02210 2210 5 0,0104 1 TS SRval 02211 2211 3 1,2123 0 XCH SRindx ; load init index SRloopN EQU * 02212 2212 5 0,0105 0 TS iSR ; save index ; shift A left (SR)02213 2213 3 0,0104 1 XCH SRval 02214 2214 5 0,0021 1 TS SR ; shift02215 2215 3 0,0021 1 XCH SR ; put result in A02216 2216 5 0,0104 1 TS SRval ; verify C(A)02217 2217 4 0,0000 0 COM ; get -A02220 2220 2 0,0105 1 INDEX iSR 02221 2221 6 1,2143 0 AD SRbaseN ; put (-A) + expected value in A02222 2222 1 0,0000 0 CCS A ; compare02223 2223 0 1,2037 1 TC fail ; >0 (A < expected value)02224 2224 0 1,2037 1 TC fail ; +002225 2225 0 1,2037 1 TC fail ; <0 (A > expected value) ; loop back to test next value02226 2226 1 0,0105 1 CCS iSR ; done?02227 2227 0 1,2212 1 TC SRloopN ; not yet, do next check 02230 2230 3 0,0101 1 XCH savQ 02231 2231 5 0,0001 0 TS Q ; restore return address02232 2232 0 0,0000 0 RETURN ; ---------------------------------------------- ; TEST CYL EDITING FUNCTION SUBROUTINE ; Rotate a test value left through CYL 15 times. ; Test the value against an expected value for each time. ; After 15 rotations, the value should equal the initial ; value. 02233 2233 00003 1 CYLcode DS CYLtst ; code for this test ; CYL test values02234 2234 03431 1 CYLinit DS %03431 ; init test value02235 2235 00016 0 CYLindx DS 14 ; loop CYLindx+1 times ; check CYL against these values CYLbase EQU * 02236 2236 03431 1 DS %03431 ; check #0 (back to start)02237 2237 41614 1 DS %41614 ; check #1
02240 2240 20706 1 DS %20706 ; check #202241 2241 10343 1 DS %10343 ; check #302242 2242 44161 1 DS %44161 ; check #402243 2243 62070 1 DS %62070 ; check #502244 2244 31034 1 DS %31034 ; check #602245 2245 14416 1 DS %14416 ; check #702246 2246 06207 1 DS %06207 ; check #802247 2247 43103 1 DS %43103 ; check #902250 2250 61441 1 DS %61441 ; check #1002251 2251 70620 1 DS %70620 ; check #1102252 2252 34310 1 DS %34310 ; check #1202253 2253 16144 1 DS %16144 ; check #1302254 2254 07062 1 DS %07062 ; check #14 chkCYL EQU * 02255 2255 3 0,0001 0 XCH Q 02256 2256 5 0,0101 1 TS savQ ; save return address 02257 2257 3 1,2233 1 CAF CYLcode 02260 2260 5 0,0100 0 TS curtest ; set test code to this test 02261 2261 3 1,2234 0 XCH CYLinit ; init value to rotate02262 2262 5 0,0106 0 TS CYLval 02263 2263 3 1,2235 1 XCH CYLindx ; load init index CYLloop EQU * 02264 2264 5 0,0107 1 TS iCYL ; save index ; rotate A left (CYL)02265 2265 3 0,0106 0 XCH CYLval 02266 2266 5 0,0022 1 TS CYL ; rotate02267 2267 3 0,0022 1 XCH CYL ; put result in A02270 2270 5 0,0106 0 TS CYLval ; verify C(A)02271 2271 4 0,0000 0 COM ; get -A02272 2272 2 0,0107 0 INDEX iCYL 02273 2273 6 1,2236 1 AD CYLbase ; put (-A) + expected value in A02274 2274 1 0,0000 0 CCS A ; compare02275 2275 0 1,2037 1 TC fail ; >0 (A < expected value)02276 2276 0 1,2037 1 TC fail ; +002277 2277 0 1,2037 1 TC fail ; <0 (A > expected value) ; loop back to test next value02300 2300 1 0,0107 0 CCS iCYL ; done?02301 2301 0 1,2264 0 TC CYLloop ; not yet, do next check 02302 2302 3 0,0101 1 XCH savQ 02303 2303 5 0,0001 0 TS Q ; restore return address02304 2304 0 0,0000 0 RETURN ; ---------------------------------------------- ; TEST SL EDITING FUNCTION SUBROUTINE ; Shift a test value left through SL 15 times. ; Test the value against an expected value for each time. ; After 15 shifts, the value should equal the sign (SG). 02305 2305 00004 0 SLcode DS SLtst ; code for this test ; SL test values02306 2306 03431 1 SLinitP DS %03431 ; positive init test value02307 2307 44346 0 SLinitN DS %44346 ; negative init test value02310 2310 00016 0 SLindx DS 14 ; loop SLindx+1 times ; check SL against these values (positive) SLbaseP EQU * 02311 2311 00000 1 DS %00000 ; check #0 (back to start)02312 2312 00000 1 DS %00000 ; check #102313 2313 20000 0 DS %20000 ; check #202314 2314 10000 0 DS %10000 ; check #302315 2315 04000 0 DS %04000 ; check #402316 2316 22000 1 DS %22000 ; check #502317 2317 31000 0 DS %31000 ; check #602320 2320 14400 0 DS %14400 ; check #702321 2321 06200 0 DS %06200 ; check #8
02322 2322 03100 0 DS %03100 ; check #902323 2323 21440 1 DS %21440 ; check #1002324 2324 30620 0 DS %30620 ; check #1102325 2325 34310 1 DS %34310 ; check #1202326 2326 16144 1 DS %16144 ; check #1302327 2327 07062 1 DS %07062 ; check #14 ; check SL against these values (negative) SLbaseN EQU * 02330 2330 77777 0 DS %77777 ; check #0 (back to start)02331 2331 77777 0 DS %77777 ; check #102332 2332 57777 1 DS %57777 ; check #202333 2333 67777 1 DS %67777 ; check #302334 2334 73777 1 DS %73777 ; check #402335 2335 55777 0 DS %55777 ; check #502336 2336 46777 1 DS %46777 ; check #602337 2337 63377 1 DS %63377 ; check #702340 2340 71577 1 DS %71577 ; check #802341 2341 74677 1 DS %74677 ; check #902342 2342 56337 0 DS %56337 ; check #1002343 2343 47157 1 DS %47157 ; check #1102344 2344 43467 0 DS %43467 ; check #1202345 2345 61633 0 DS %61633 ; check #1302346 2346 50715 1 DS %50715 ; check #14 chkSL EQU * 02347 2347 3 0,0001 0 XCH Q 02350 2350 5 0,0101 1 TS savQ ; save return address 02351 2351 3 1,2305 0 CAF SLcode 02352 2352 5 0,0100 0 TS curtest ; set test code to this test ; TEST 1: shift a postive value.02353 2353 3 1,2306 0 XCH SLinitP ; init value to shift02354 2354 5 0,0110 1 TS SLval 02355 2355 3 1,2310 1 XCH SLindx ; load init index SLloopP EQU * 02356 2356 5 0,0111 0 TS iSL ; save index ; shift A left (SL)02357 2357 3 0,0110 1 XCH SLval 02360 2360 5 0,0023 0 TS SL ; shift02361 2361 3 0,0023 0 XCH SL ; put result in A02362 2362 5 0,0110 1 TS SLval ; verify C(A)02363 2363 4 0,0000 0 COM ; get -A02364 2364 2 0,0111 1 INDEX iSL 02365 2365 6 1,2311 0 AD SLbaseP ; put (-A) + expected value in A02366 2366 1 0,0000 0 CCS A ; compare02367 2367 0 1,2037 1 TC fail ; >0 (A < expected value)02370 2370 0 1,2037 1 TC fail ; +002371 2371 0 1,2037 1 TC fail ; <0 (A > expected value) ; loop back to test next value02372 2372 1 0,0111 1 CCS iSL ; done?02373 2373 0 1,2356 0 TC SLloopP ; not yet, do next check ; TEST 2: shift a negative value02374 2374 3 1,2307 1 XCH SLinitN ; init value to shift02375 2375 5 0,0110 1 TS SLval 02376 2376 3 1,2310 1 XCH SLindx ; load init index SLloopN EQU * 02377 2377 5 0,0111 0 TS iSL ; save index ; shift A left (SL)02400 2400 3 0,0110 1 XCH SLval 02401 2401 5 0,0023 0 TS SL ; shift02402 2402 3 0,0023 0 XCH SL ; put result in A02403 2403 5 0,0110 1 TS SLval
; verify C(A)02404 2404 4 0,0000 0 COM ; get -A02405 2405 2 0,0111 1 INDEX iSL 02406 2406 6 1,2330 0 AD SLbaseN ; put (-A) + expected value in A02407 2407 1 0,0000 0 CCS A ; compare02410 2410 0 1,2037 1 TC fail ; >0 (A < expected value)02411 2411 0 1,2037 1 TC fail ; +002412 2412 0 1,2037 1 TC fail ; <0 (A > expected value) ; loop back to test next value02413 2413 1 0,0111 1 CCS iSL ; done?02414 2414 0 1,2377 0 TC SLloopN ; not yet, do next check 02415 2415 3 0,0101 1 XCH savQ 02416 2416 5 0,0001 0 TS Q ; restore return address02417 2417 0 0,0000 0 RETURN ; ---------------------------------------------- ; PASSED ALL TESTS! 02420 2420 12345 0 PASScode DS PASS finish EQU * 02421 2421 3 1,2420 0 CAF PASScode 02422 2422 5 0,0100 0 TS curtest ; set current test code to PASS02423 2423 0 0,0000 0 RETURN ; ---------------------------------------------- ; INTERRUPT SERVICE ROUTINE goT3 EQU * goER EQU * goDS EQU * goKEY EQU * goUP EQU * endRUPT EQU * 02424 2424 3 0,0027 1 XCH QRUPT ; restore Q02425 2425 5 0,0001 0 TS Q 02426 2426 3 0,0026 0 XCH ARUPT ; restore A02427 2427 2 0,0000 1 RESUME ; finished, go back
Assembly complete. Errors = 0
Symbol table:START 000000 CYRtst 000001 SRtst 000002 CYLtst 000003 SLtst 000004 PASS 012345 EXTENDER 005777 curtest 000100 savQ 000101 CYRval 000102 iCYR 000103 SRval 000104 iSR 000105 CYLval 000106 iCYL 000107 SLval 000110 iSL 000111 GOPROG 002000 T3RUPT 002004 ERRUPT 002010 DSRUPT 002014 KEYRUPT 002020 UPRUPT 002024 goMAIN 002030 fail 002037 end 002041 STRTcode 002042 begin 002043 CYRcode 002046 CYRinit 002047 CYRindx 002050 CYRbase 002051 chkCYR 002070 CYRloop 002077 SRcode 002120 SRinitP 002121 SRinitN 002122 SRindx 002123 SRbaseP 002124 SRbaseN 002143 chkSR 002162 SRloopP 002171 SRloopN 002212 CYLcode 002233 CYLinit 002234 CYLindx 002235 CYLbase 002236 chkCYL 002255 CYLloop 002264 SLcode 002305 SLinitP 002306 SLinitN 002307 SLindx 002310 SLbaseP 002311 SLbaseN 002330 chkSL 002347 SLloopP 002356 SLloopN 002377 PASScode 002420 finish 002421 goT3 002424 goER 002424 goDS 002424 goKEY 002424 goUP 002424 endRUPT 002424 ARUPT 000026 Q 000001 QRUPT 000027 CYR 000020 A 000000 SR 000021 CYL 000022 SL 000023
TECO5 assembler listing
Block I Apollo Guidance Computer (AGC4) assembler version 1.6 for EPROM
First pass: generate symbol table.Second pass: generate object code.
; TECO5 (file:teco5.asm) ; ; Version: 1.0 ; Author: John Pultorak ; Date: 9/14/2001 ; ; PURPOSE: ; Test and checkout program for the Block 1 Apollo Guidance Computer. ; Tests interrupts. ; ; OPERATION: ; Tests the interrupts by initializing 4 counters to zero and then ; entering a loop where the 1st counter (mainCtr) is incremented on ; each iteration of the loop. ; ; Interrupts are disabled and enabled during each iteration by INHINT ; and RELINT instructions. ; ; Interrupts are automatically inhibited during part of each iteration ; by an overflow condition in register A. ; ; Interrupt service routines for T3RUPT, DSRUPT (aka T4RUPT) and ; KEYRUPT increment their own counters upon each interrupt. ; ; ERRATA: ; - Written for the AGC4R assembler. The assembler directives and ; syntax differ somewhat from the original AGC assembler. ; - The tests attempt to check all threads, but are not exhaustive. ; ; SOURCES: ; Information on the Block 1 architecture: instruction set, instruction ; sequences, registers, register transfers, control pulses, memory and ; memory addressing, I/O assignments, interrupts, and involuntary ; counters was obtained from: ; ; A. Hopkins, R. Alonso, and H. Blair-Smith, "Logical Description ; for the Apollo Guidance Computer (AGC4)", R-393, ; MIT Instrumentation Laboratory, Cambridge, MA, Mar. 1963. ; ; Supplementary information was obtained from: ; ; R. Alonso, J. H. Laning, Jr. and H. Blair-Smith, "Preliminary ; MOD 3C Programmer's Manual", E-1077, MIT Instrumentation ; Laboratory, Cambridge, MA, Nov. 1961. ; ; B. I. Savage and A. Drake, "AGC4 Basic Training Manual, Volume I", ; E-2052, MIT Instrumentation Laboratory, Cambridge, ; MA, Jan. 1967. ; ; E. C. Hall, "MIT's Role in Project Apollo, Volume III, Computer ; Subsystem", R-700, MIT Charles Stark Draper Laboratory, ; Cambridge, MA, Aug. 1972. ; ; A. Hopkins, "Guidance Computer Design, Part VI", source unknown. ; ; A. I. Green and J. J. Rocchio, "Keyboard and Display System Program ; for AGC (Program Sunrise)", E-1574, MIT Instrumentation ; Laboratory, Cambridge, MA, Aug. 1964. ; ; E, C. Hall, "Journey to the Moon: The History of the Apollo ; Guidance Computer", AIAA, Reston VA, 1996. ; ; ---------------------------------------------- ; ---------------------------------------------- ; ERASEABLE MEMORY -- DATA SEGMENT
ORG %47 ; start of data area00047 0047 00000 1 mainCtr DS %0 00050 0050 00000 1 T3Ctr DS %0 ; counts T3RUPTs00051 0051 00000 1 DSCtr DS %0 ; counts DSRUPTs (T4RUPT)00052 0052 00000 1 KYCtr DS %0 ; counts KEYRUPT ; ---------------------------------------------- ; ENTRY POINTS ; program (re)start ORG GOPROG 02000 2000 0 1,2030 0 TC goMAIN ; interrupt service entry points ORG T3RUPT 02004 2004 5 0,0026 0 TS ARUPT 02005 2005 3 0,0001 0 XCH Q 02006 2006 5 0,0027 1 TS QRUPT 02007 2007 0 1,2064 1 TC goT3 ORG DSRUPT ; aka T4RUPT02014 2014 5 0,0026 0 TS ARUPT 02015 2015 3 0,0001 0 XCH Q 02016 2016 5 0,0027 1 TS QRUPT 02017 2017 0 1,2071 0 TC goDS ORG KEYRUPT 02020 2020 5 0,0026 0 TS ARUPT 02021 2021 3 0,0001 0 XCH Q 02022 2022 5 0,0027 1 TS QRUPT 02023 2023 0 1,2076 1 TC goKEY ; ---------------------------------------------- ; FIXED MEMORY -- SHARED DATA SEGMENT 02024 2024 00000 1 ZERO DS %0 02025 2025 00001 0 ONE DS %1 02026 2026 25252 0 AD25252 DS %25252 ;+10922 dec, see TECO1 AD test02027 2027 52525 1 AD52525 DS %52525 ;-10922 dec, see TECO1 AD test ; ---------------------------------------------- ; MAIN PROGRAM goMAIN EQU * 02030 2030 2 0,0000 0 INHINT ; disable interrupts ; clear counters for interrupts and for interations ; though main loop. 02031 2031 3 1,2024 0 CAF ZERO 02032 2032 5 0,0047 1 TS mainCtr ; mainCtr = 002033 2033 5 0,0050 1 TS T3Ctr ; T3Ctr = 002034 2034 5 0,0051 0 TS DSCtr ; DSCtr = 002035 2035 5 0,0052 0 TS KYCtr ; KYCtr = 0 ; keeps bumping mainCtr in an infinite loop. ; interrupts are disabled and enabled on each ; iteration of the loop. infLoop EQU * 02036 2036 2 0,0000 0 INHINT ; disable interrupt ; increment mainCtr while interrupt is inhibited. 02037 2037 3 1,2024 0 CAF ZERO 02040 2040 6 0,0047 1 AD mainCtr ; load mainCtr into A02041 2041 6 1,2025 1 AD ONE ; incr 02042 2042 2 0,0000 1 RELINT ; enable interrupts 02043 2043 5 0,0047 1 TS mainCtr ; store increment value
; create a positive overflow in A. Interrupts are inhibited ; while A contains an overflow. The overflow is produced ; by adding %25252 + %25252 = %52524 (sign + 14 magnitude). ; This is the overflow test in TECO1 for the AD instruction. 02044 2044 3 1,2026 1 CAF AD25252 02045 2045 6 1,2026 1 AD AD25252 ; positive overflow 02046 2046 3 0,0000 1 NOOP ; interrupt should be inhib02047 2047 3 0,0000 1 NOOP ; remove the overflow, this reenables the interrupt. 02050 2050 3 1,2024 0 CAF ZERO ; clear the overflow in A 02051 2051 3 0,0000 1 NOOP ; interrupt should be reenab02052 2052 3 0,0000 1 NOOP ; create a negative overflow in A. Interrupts are inhibited ; while A contains an overflow. The overflow is produced ; by adding %52525 + %52525 = %25253 (sign + 14 magnitude). ; This is the overflow test in TECO1 for the AD instruction. 02053 2053 3 1,2027 0 CAF AD52525 02054 2054 6 1,2027 0 AD AD52525 ; positive overflow 02055 2055 3 0,0000 1 NOOP ; interrupt should be inhib02056 2056 3 0,0000 1 NOOP ; remove the overflow, this reenables the interrupt. 02057 2057 3 1,2024 0 CAF ZERO ; clear the overflow in A 02060 2060 3 0,0000 1 NOOP ; interrupt should be reenab02061 2061 3 0,0000 1 NOOP 02062 2062 0 1,2036 0 TC infLoop ; mainCtr no overflow02063 2063 0 1,2036 0 TC infLoop ; mainCtr overflowed ; ---------------------------------------------- ; INTERRUPT SERVICE ROUTINE goT3 EQU * 02064 2064 3 1,2024 0 CAF ZERO 02065 2065 6 0,0050 1 AD T3Ctr ; load T3Ctr into A02066 2066 6 1,2025 1 AD ONE ; incr02067 2067 5 0,0050 1 TS T3Ctr ; store02070 2070 0 1,2103 1 TC endRUPT goDS EQU * 02071 2071 3 1,2024 0 CAF ZERO 02072 2072 6 0,0051 0 AD DSCtr ; load DSCtr into A02073 2073 6 1,2025 1 AD ONE ; incr02074 2074 5 0,0051 0 TS DSCtr ; store02075 2075 0 1,2103 1 TC endRUPT goKEY EQU * 02076 2076 3 1,2024 0 CAF ZERO 02077 2077 6 0,0052 0 AD KYCtr ; load KYCtr into A02100 2100 6 1,2025 1 AD ONE ; incr02101 2101 5 0,0052 0 TS KYCtr ; store02102 2102 0 1,2103 1 TC endRUPT endRUPT EQU * 02103 2103 3 0,0027 1 XCH QRUPT ; restore Q02104 2104 5 0,0001 0 TS Q 02105 2105 3 0,0026 0 XCH ARUPT ; restore A02106 2106 2 0,0000 1 RESUME ; finished, go back
Assembly complete. Errors = 0
Symbol table:
mainCtr 000047 T3Ctr 000050 DSCtr 000051 KYCtr 000052 GOPROG 002000 T3RUPT 002004 DSRUPT 002014 KEYRUPT 002020 ZERO 002024 ONE 002025 AD25252 002026 AD52525 002027 goMAIN 002030 infLoop 002036 goT3 002064 goDS 002071 goKEY 002076 endRUPT 002103 ARUPT 000026 Q 000001 QRUPT 000027
TECO_STBY assembler listing
Block I Apollo Guidance Computer (AGC4) assembler version 1.6
First pass: generate symbol table.Second pass: generate object code.
; TECO_STBY (file:stby.asm) ; ; Tests the standby operation. ; program (re)start ORG GOPROG 02000 2000 0 1,2002 1 TC goMAIN 02001 2001 00200 0 ofbit DS %200 ; OUT1, bit 8 initiates standby ; MAIN PROGRAM goMAIN EQU * ; standby is disabled02002 2002 3 0,0000 1 NOOP 02003 2003 3 0,0000 1 NOOP ; enable standby02004 2004 3 1,2001 1 XCH ofbit 02005 2005 5 0,0011 1 TS OUT1 infLoop EQU * 02006 2006 0 1,2006 0 TC infLoop
Assembly complete. Errors = 0
Symbol table:GOPROG 002000 ofbit 002001 goMAIN 002002 infLoop 002006 OUT1 000011