Volume IX is Now a Memory

Testing of the ALDs in volume IX is now complete. With that all ALD pages for the main CPU and the channels (including the I/O channels E and F) have been tested, some more thoroughly than others. Memory spans volumes IX and X, so memory isn’t done yet.

After that comes the last volume I plan on working on for now, volume X. The main piece is the I/O Selectric console support.

Adventures in Error Land

One of the things that is interesting about the IBM is the extent of error checking. The Core has parity (check bit), but all of the major data paths (called “channels” on the IBM 1410) as well (A, B and Assembly channels, for example). Unfortunately, some of this is not covered in the ILD diagrams. While it is covered in the System Fundamentals manual, the logic actually used on some of the ALD’s is a bit different from channel to channel, even though the end result is essentially the same. In particular, while all of the pages use card type DHL (And-Or-Invert, or And/Nor, if you like), some of the pages use plain old NOR gates in places in combination with NAND gates – resulting in differences in positive +S inputs vs. negative -S inputs, so that I was not able to just copy the test bench code from one channel to the next.

Also, page 18.13.03.1 had an error – combining two outputs with and AND on the ILD when the circuit is actually OR. When the test failed, the reason was apparent, comparing it with others on the same ILD, figure 59.

Page 18.14.06.1 had a different kind of error. The polarity of the signal shown as “+S LOG GT E.2ND+3RD CHK TEST” is incorrect. It is correctly depicted as -S on the destination sheet, 18.14.07.1. The ILD also shows this as Logic Gate F rather than E, even though the ILD for the destination page (on the same ILD sheet) correctly shows Logic Gate E. So, yet another vote of confidence for the testing process. 😉

Set… No, Reset…, No Set…. I’m all Confused

Page 18.14.03.1 presented an interesting challenge. This is the Address Channel Validity check trigger. It is reset via collector pullover of the OFF output when a valid character is present and sets when an invalid character show sup (except during Logic Gate A of a 1401 cycle). It then also has a latch, along with a feedback path besides, to keep it set. That feedback path prevents a valid character from resetting the trigger once set.

But it also has a DC Set via the check test switch. The two are connected to their respective inputs by 4.7K ohm resistors. The interesting situation happens when you think about there being a valid character present (thus the off input is pulled high) when one presses the check test switch (which wants to pull the on input high). If this were ordinary logic levels fed from different gates, this would leave one input being logic 1 (0v) and the other being logic 0 (-12V) and would leave the base on the “on” side in no-man’s land. HOWEVER, the check test switch supplies -V voltage – more than enough to force the “on” side on and the on output to ground (logic 0).

In VHDL, one or the other necessarily takes precedence. When I developed the circuit for the DEZ trigger card type, I set it up with the Off output pullover taking precedence. That has worked fine – until this page.

But that does not mean one ought to reverse it. That might break some other page. For my test bench, I worked around the issue by putting an invalid character up long enough for the trigger to set. It would be interesting to scope this situation on a real machine, though that will never ever happen.

(Oh, and did I forget to mention that Triggers are a Pain? 8D).

Oh, and have I mentioned…

Page 18.14.08.1 presented a challenge. It has a trigger (naturally) with the ubiquitous pull on and pull off connections. Unlike the previous ones, however, this pull off DOT function is driven by two gates instead of just one. The program logic recognizes the case where a single gate pulls on or pulls of a trigger, but not one where more than one gate is involved.

Rather than futzing with the program logic for what appears to be a single case (we’ll see about that), instead I inserted a gate “FXOR” (for faux OR) befoer the DOT function to fix it.

(Oh, and did I forget to mention … never mind. 😉 ).

We Interrupt this program…

Near the end of Volume IX were the ILD pages for interrupt processing. Most of that was straightforward: if interrupts are enabled, and an I/O operation completes (presumably in overlap mode), an interrupt is generated.\

But while there is a section on interrupts in the CPU instructional materials, including some ILD-type diagrams, their coverage is not as thorough as a regular ILD.

There is also a special case for interrupts for unit record equipment, perhaps intended for SPOOL (simultaneous peripheral operation online) support. There is a toggle switch for turning on interrupts for overlapped I/O operations (including 1301 seek), console inquiry, console output, non-overlapped seek and disk device “attention” signals.

Unit record interrupts are special, however: the operator must select one (card reader, punch, printer or paper tape) using a rotary switch, and then push a special priority interrupt button. This generates an initial interrupt – completed I/O turns on subsequent interrupts.

This last one was tricky to test, because it is implemented using a set of three latches – the first one being a “one and only one” latch to handle the button press. (We didn’t ever actually use that on the School of Business IBM 1410).

Chains of latches, especially where the signals are not brought out to the sheet edge are almost as much “fun” to work with as triggers. 😉

Mutually exclusive logic blocks

Memory testing also brought up the first case where I could not test an ALD without disabling one or more logic blocks. In particular a couple of sheets had gates for both feature S10 (10K of memory) and S2 (20K or more of memory), and the logic design was such that they cannot coexist, so I used the application to disable generation of the logic blocks related to feature S10 on those pages. (Other pages may still have both – but in those cases coexistence seemed possible.)

Load Sharing Matrix Switches

While I am testing or at least sort of testing most of the memory related circuits, including the sense amplifiers from a digital point of view, and the drivers for the LSMS units, I am not testing/generating/simulating the LSMS units themselves. This is mostly because each LSMS takes up four logic blocks on an ALD, and I don’t currently have a way to merge more than two logic blocks or merge two that are not vertically adjacent to each other. Finally it would just add complexity to the memory unit when I generate an FPGA to actually simulate the core. Instead I will just simulate Read/Write/Inhibit on 8 bits at a time directly from the storage / memory address register (variously referred to as STAR and MAR – the former in the documentation, the latter in the ALD signal names.

A Sense of Forcing my h-AND

Finally, the ALDs related to sense amplifiers required special treatment. For each bit of each of the possible four memory readout characters on a system with 40K, there are two sense amplifiers, one supporting 5K bits of a core plane – either the 0-4999 or 5000-5999 portions. These gates’ outputs are then connected together, but not using just load resistors. Instead, each sense amplifier card has a diode on the output such that when they are connected together driving a -Y signal level, they comprise an AND gate.

The HDL generation currently supposes that B level DOT functions are AND and that the others are OR (with a per signal level setting). Most cases for Y signal level DOT functions are indeed OR, but not in this case, because of the diodes that are present (anode facing out from the gate). Fortunately, a while back I added the ability to force a given DOT function’s generated logic, so this was easy to deal with.

IBM 1410 ALD to FPGA Volume VIII complete – only two to go

Volume VIII started off pretty uneventfully, for a while. I did find another page (16.20.02.1) where a couple of gates have their internal connections brought to the edge of the sheet, but those are trivial to fix by adding “faux pins” to the gate definitions and using those on the sheet.

I continue to be somewhat surprised that I haven’t found very many connector errors – a testament to the value of verifying gate and signal use counts on each sheet.

Also, the number of ILD diagrams I have checked off as being completely tested in the CPU section is approaching closure. Of 65 such ILD diagrams, I have completely checked off the diagrams in all but 15 of them. (In addition I have quite a number of additional diagrams of the ILD ilk (i.e., drawn as positive logic with AND and OR gates, etc.).

Page 16.20.10.1 was a bit more interesting. On the surface, it is just a couple of latches. However, the corresponding diagrams on ILD figure 31 were in error. The outputs of these latches go to DOT-ed connection. While they are not like triggers in that they don’t “pull over” the output directly, they DO form part of the feedback loop for the latch, and thus can cause it to set (provided nothing else is keeping it reset). However, the engineer drawing the ILD didn’t take that behavior into account (and it did seem rather odd, just looking at the ILD, to have both a latch and a combinatorial group feeding the same output. ;))

In addition, on that same page, the latch comprised of the gates at 4E and 3E are unusual – the reset portion (4E) is a NAND gate, but at I first I thought that the set portion (3E) was NOR gate thinking that the engineer doing the ILD diagram did not spot it, which caused them to depict it as part of an “OR” to set the latch, when in fact those two inputs are effectively ANDed together.

However, when I ran into the same situation on page 16.20.14.1, the second use of card type YLH in my travels, I got suspicious and took a closer look at the circuit, which has a 3 diode DDTL (0-6V) *AND* circuit feeding an inverter/converter to SDRTL (-12V – 0V) – in other words, a NAND gate. This was actually the third card type where I had made this error – it caused me to go through all the card types I had interpreted as NOR gates to confirm that there were not any more such gaffes.

Page 16.20.15.1 had something else interesting. This is the Complement Latch page. There is also a related signal, “+B COMP ADD A” derived from that latch anded with “ADDER A CH USE T + C” (OR’ed with a couple of other things). The latch is set, among other ways, by the OR of a couple of signals “START COMPL ADD 1” or “START COMPL ADD 2”. Interestingly, “+B COMP ADD A” will also generate its output via (“START COMPL ADD 1” or “START COMPL ADD 2”) and that same “ADDER A CH USE T + C”. Since the effect of the OR part of this would also be setting the latch, it is in a sense redundant. I suspect that this might be in place get the +B COMP ADD A signal up just a tad quicker than the latch sets, by OR’ing it with the pair of signals that are also going to eventually to set the latch.

A “D’Oh” Moment

I had noticed in my travels that a number of signals end in asterisk or have an asterisk near the end. I had seen quite a number of them, particularly as inputs to DOT’ed connections on their destination sheets. But it wasn’t until I got to page 16.50.04.1 where what was logically an identical signal appeared with both a name without an asterisk and one with an asterisk (-B MPLY.MQ.B.B0 and -B MPLY.MQ.B.B0*) that I finally recognized what that actually meant – that those signals are indeed open collector outputs intended to be DOT’ed on their destination sheets. D’Oh. Sheesh – it took me two YEARS to catch on.

(Addendum: There are exceptions – probably when things were changed. Example: Page 17.13.06.1 generates signal “-S SET DOLLAR SIGN * EDIT”. However, this is a driven signal, not open collector and in most places, the “* EDIT” does not appear on the input side – only on page 12.12.51.1 does that signal appear with an asterisk – and it is not dotted. My guess is that originally there was an open collector variant, but they later found they did not need it.)

Signal Names Can Be Misleading

There are a lot of straight-forward if complex combinatorial sheets in this parcel of ALDs, and sometimes there is no corresponding ILD. In such cases I have been using the signal name to drive my test bench, but sometimes those signal names can be misleading. Case in point, on page 16.50.04.1 there is a signal name “-B MPLY.MQ.B.1.B0.BW” which implies Multiply OP and MQ latch and B Cycle and 1st Scan and B Channel 0 and B Channel wordmark. However, when I ran my test, it failed, because, looking at the ALD, it also incorporates the True Latch (usually represented at a “T” in the signal name dot sequence – but missing from this particular signal name.) I suppose that they added this factor somewhere during the design and testing phase, but didn’t want to bother renaming the signal to “-B MPLY.MQ.B.T.1.B0.BW”.

When a Space is NOT a Blank and vice-versa

Came across something interesting on the Edit Translator pages (17.11.*.1). These pages refer to “Blank” and “Space” as different characters. Say whaaaat? Fortunately, the ILD Figure 41.1 contained a hint: “NOT SPACE (NOT &)”. There are four BCD characters that have no number bits (bits 8, 4, 2 and 1 are all 0). “Blank” (no bits), – (Just a B Bit), Cent sign – which is also called “alternate or substitute blank” (just an A bit) and & – also known as “+” and, apparently, as “Space” (just the BA bits). I had been aware of the blank / alternate blank thing, because it appears in the principles of operation, but calling BA—- as anything but ampersand or “+” was a new one on me.

Keep on Learning, Learning, Learning

One of the fascinating things that has been going on throughout this entire project is learning to write test benches. Once I am through it all, I plan to post the generated VHDL on github, and this evolution will be very apparent. Ordinary VHDL of course, with signals, requires a flip flop/register/latch to remember state – they correspond to actual hardware logic signals. The IBM 1410 has a bunch of those latches, and some of them have “control” latches that remember something until the next major cycle comes around. What is more, often those control latches are hidden, i.e., their signals are not brought out on the ALD sheet. This presents a challenge in writing a test bench – because you need to know the state of that control latch from a previous iteration of the test vector to know whether the actual latch whose signal does appear as an ALD output ought to be. Even worse, some of these latches are in a latch loop – using the “visible” latch to “regenerate” the setting into the control latch until some kind of condition is satisfied. Up until today, I had been “remembering” that with code – which made writing the test bench both more intricate and complicated, and less complete as well. Enter another “D’Oh” moment: test benches can and do make use of VHDL variables, which, unlike signals, “remember” – they are like variables in most any other programming language. So, one can remember the *expected* state of the control latch, and then see if that results in the corresponding state of the “visible” latch on the next iteration. Better still, another variable enables the test bench to “remember” the state of the visible latch as well. This makes testing significantly easier and more thorough. The test bench for page 17.12.01.1 shows this new technique in practice. With this technique the latch testing on this page worked perfectly the first time – and was verified with the waveform trace in the simulator. BIG time saver here. Wish I had thought of it sooner.

(With apologies to Dory and Ellen DeGeneres. 😉 ).

   -- The variable declarations, VHDL wrapper declarations, etc. etc. are not shown here...

   testName := "17.12.01.1        ";
   
   MS_LOGIC_GATE_B_1 <= '0';
   MS_LOGIC_GATE_D_1 <= '0';
   wait for 30 ns;
   MS_LOGIC_GATE_B_1 <= '0';
   MS_LOGIC_GATE_D_1 <= '0';
   wait for 30 ns;
   
   check1(PS_NOT_0_SUPPRESS,'0',testName,"+S ZS Reset");
   check1(MS_NOT_0_SUPPRESS,'1',testName,"-S ZS Reset");

   for tt in 0 to 2**10 loop
      tv := std_logic_vector(to_unsigned(tt,tv'Length));
      d := tv(0);
      e := tv(1);
      f := tv(2);
      g := tv(3);
      h := tv(4);
      j := tv(5);
      k := tv(6);
      l := tv(7);
      m := tv(8);
      n := tv(9);

      g1 := g and h and k;
      g2 := g1 or (k and l) or m or n;
      g3 := d and e;
      g4 := (lastNotZSLatch and g2 and e) or g3 or (e and f and k);
      -- Note that g4 (gate 4) depends on the state from the previous iteration!!
      
      lastNotZS <= lastNotZSLatch;
       -- These two signals are just here so that I can see the variables on the "scope" waveform trace
      lastNotZSCtrlA <= lastNotZSCtrl;   -- There declarations appear before this "code" nearer the top of the test bench and are not shown

      -- Reset Not 0 Suppress Latch
      
      MS_LOGIC_GATE_B_1 <= '0';
      wait for 30 ns;
      MS_LOGIC_GATE_B_1 <= '1';
      wait for 30 ns;

      check1(PS_NOT_0_SUPPRESS,'0',testName,"+S ZS Loop Reset");
      check1(MS_NOT_0_SUPPRESS,'1',testName,"-S ZS Loop Reset");

      -- If Not ZS Ctrl was set last iteration, then set Not ZS Latch now
      
      PS_LOGIC_GATE_C_1 <= '1';
      wait for 30 ns;
      PS_LOGIC_GATE_C_1 <= '0';
      wait for 30 ns;
      
      check1(PS_NOT_0_SUPPRESS,lastNotZSCtrl,testName,"+S ZS From Ctrl");
      check1(MS_NOT_0_SUPPRESS,not lastNotZSCtrl,testName,"-S ZS From Ctrl");
      
      -- Reset Not ZS Ctrl  This should not affect Not ZS Latch
      
      MS_LOGIC_GATE_D_1 <= '0';
      wait for 30 ns;
      MS_LOGIC_GATE_D_1 <= '1';
      wait for 30 ns;
      
      check1(PS_NOT_0_SUPPRESS,lastNotZSCtrl,testName,"+S ZS From Ctrl Reset ZS Ctrl");
      check1(MS_NOT_0_SUPPRESS,not lastNotZSCtrl,testName,"-S ZS From Ctrl Reset ZS Ctrl");
      
      -- Remember the setting of the Not ZS Latch for the next iteration
      
      lastNotZSLatch := PS_NOT_0_SUPPRESS;
      
      -- Now maybe set Not ZS Ctrl
      
      PS_LAST_INSN_RO_CYCLE <= d;
      PS_LAST_LOGIC_GATE_1 <= e;
      
      PS_SIG_DIGIT <= f;
      PS_1ST_SCAN <= g;
      PS_NOT_CTRL_0 <= h;
      PS_E_OP_DOT_B_CYCLE_1 <= j;
      PS_E_OR_Z_DOT_2ND_SCAN_DOT_EXTENSION <= k;
      PS_BLK_0_PUNCT_OR_SIG_DIGIT <= l;
      MS_A_CYCLE <= not m;
      MS_3RD_SCAN <= not n;

      wait for 30 ns; -- Perhaps set Not ZS Ctrl
      
      -- Remember the *expected* state of Not ZS Ctrl for the next iteration
      
      lastNotZSCtrl := g4;
      
      -- Reset the signals before the next iteration
      
      PS_LAST_INSN_RO_CYCLE <= '0';
      PS_LAST_LOGIC_GATE_1 <= '0';
      
      PS_SIG_DIGIT <= '0';
      PS_1ST_SCAN <= '0';
      PS_NOT_CTRL_0 <= '0';
      PS_E_OP_DOT_B_CYCLE_1 <= '0';
      PS_E_OR_Z_DOT_2ND_SCAN_DOT_EXTENSION <= '0';
      PS_BLK_0_PUNCT_OR_SIG_DIGIT <= '0';
      MS_A_CYCLE <= '1';
      MS_3RD_SCAN <= '1';
                                
   end loop;