Tuesday, March 8, 2011

Remembering classic logic... (part 1)

Recently I pulled out my boxes of 7400 series logic (working on a few old school projects that were idled for a bit).  There's something special about these chips - so many memories...

It occurred to me that there was something to learn in studying the choices the engineers made in deciding exactly what logic to include (remember it's expensive to setup a production line) and how successful most of them became... There are so many ways to solve each particular problem and while now I tend to use software on powerful general purpose machines, or a quick embedded solution on a microcontroller or when needed I can just use programmable logic if I need performance or it's easier to implement in parallel - back when these were thought out the primary considerations were adaptability and fitness of purpose.  It's amazing how elegant some of the old designs were when the designers really had to try to get an optimal solution (because of what was available to work with compared to today)...

So, on a whim I thought that I'd bang out verilog modules for the chips I have on hand.  I got through the logic ones and I'll include those here... in subsequent posts I'll do the flip-flops, the buffers, the counters and so on...

I'm going to refer to them generically (for example 74HCT04N and 74S04 will both be known as 74x04) because the designations in the middle (S,LS, HCT...) refer to changes in the performance but not the logic.  I'm putting the files for these modules in the tanukifu project here.

The 74x00 contains four nand gates, each with 2 inputs and 1 output.  The nand gate is one of those constructs from which just about any other logical construct can be built (which is probably why it's used so often).  The output of a nand gate is true (high, 1) if the two inputs are different and false (low, 0) if the two inputs are the same (not this and that).  The verilog for this is very simple:
   assign Aout = (Ain1 & Ain2) ? 1'b0 : 1'b1;
   assign Bout = (Bin1 & Bin2) ? 1'b0 : 1'b1;
   assign Cout = (Cin1 & Cin2) ? 1'b0 : 1'b1;
   assign Dout = (Din1 & Din2) ? 1'b0 : 1'b1;
Each of the four gates is independent (and does not require a clock or a reset) so the outputs change as fast as the hardware can detect and react to a change in the input lines.  The 74x10 is very similar and has three nand gates each with three inputs and one output and needs only a tiny change in the verilog:
 assign Aout = (Ain1 & Ain2 & Ain3) ? 1'b0 : 1'b1;
Along the same lines, the 74x20 has 2 nand gates with 4 inputs and one output and the 74x30 has 1 nand gate with 8 inputs and one output.  Breaking the theme of staying in the same package, the 74x133 has a 13 input nand gate.

Another type of variation has to do not with the number of inputs, but rather the way in which the output functions.  The above chips have true outputs (driving the line high (source) or driving the line low (sink).  This works well when there are only two devices connected to a wire, but when multiple devices need to be connected to the same wire (making a bus) then bad things can happen if different devices are trying to each do their own thing... One way around that is to only allow the outputs to either act as a source or a sink (but not both) and then to use a passive device (a resistor usually) to weakly drive the wire either high or low.  These types of outputs are called tristates - the third state is a high impedance connection to the wire (it will not affect the state of the wire).  The changes needed to the verilog are easy:
 assign Aout = (Ain1 & Ain2) ? 1'b0 : 1'bz;
The 74x01 is similar to the 74x00 (four 2 input nand gates) but has open collector tristate outputs (the BUFT is the tristate buffer for the output but otherwise the logic is the same). 

Another variation is to change the type of gate.  The 74x02 is similar to the 74x04 but uses nor gates instead of nand gates (still four 2 input, 1 output gates).

  assign Aout = (Ain1 | Ain2) ? 1'b0 : 1'b1;
All that is changed here is the type of gate (nor instead of nand).  Along the same lines, the 74x08 uses and gates (both inputs have to be the same for the output to be true), the 74x32 uses or (either input needs to be true for the output to be true) gates, and the 74x86 uses exclusive or (exactly one input has to be true for the output to be true) gates.

Other slight variations have to do with the hardware (schmitt triggers to reduce sensitivity to noise on the 74x13).

The simplest (but very useful) 74x04 is an inverter (low input becomes a high output and high input becomes low output).

   assign Aout = ~Ain;
Since 6 could be fit in the same package it's known as a hex inverter... I always thought it was strange to have 6 inverters in one package and thought it would have been better to have a 2 input nand a 2 input xor and 3 inverters in a single package.
Sometimes more complicated arrangements became so useful that more than one gate was used... (usually for simple math or address decoding or event handing).   The 74x51 is a 2,2 AOI (and or inverter) and contains two 3 input and gates that feed an or gate and then an inverter.
 assign Aout = ((Ain1 & Ain2 & Ain3) | (Ain4 & Ain5 & Ain6)) ? 1'b0 : 1'b1;
The 74x64 is a little more complicated (a 4,2,3,2 AOI) where you have two 2 input, one 3 input and one 4 input and gates feeding the or gate that feeds the inverter - but still very easy to do in verilog:
 assign Aout = ((Ain1 & Ain2 & Ain3  &Ain4) |
                  (Ain5 & Ain6) |
                  (Ain7 & Ain8 &Ain9) |
                  (Ain10 & Ain11)) ? 1'b0 : 1'b1;
   Well, those are the basic 7400 series I have on hand.  I'll get to the more interesting ones later (flip-flops, counters, buffers, drivers and so on...).  I've always liked the basic logic chips (durable, easy to understand, easy to use, symmetry in design, symmetry in the product family... This a quick little table of the basic logic ones I tend to use: