Tuesday, March 22, 2011

Remembering classic logic... (part 8)

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, on a whim I thought that I'd bang out verilog modules for the chips I have on hand.  I'm putting the files for these modules in the tanukifu project here.


There are many times when exactly one of a set of lines needs to be set differently (high or low) then the other members in the group.  Demuxes (De-multiplexers) do this by having more outputs than inputs (always a power of 2 since we are unfolding a binary number - the inputs are often considered address lines).   Just about any time you have multiple chips on a bus and need to communicated with them individually you need a mus (unless you want to put a lot of overhead on the bus and additional logic in each chip).


It's not unusual for multiple demuxes to be chained together and for complex logic to determine when output should be expressed so many times demuxes will have multiple enables in various groups of active high/active low lines.  While the 74x138 is less complex, the 74x137 is one of the more popular chips in my box.  The hdl is easy in verilog...




   // If GL is low and G2 is high or G1 is low then the outputs are high
   assign Y1 = (!GL & (G2 | !G1)) ? 1'b1 : ~Yreg1;
   assign Y2 = (!GL & (G2 | !G1)) ? 1'b1 : ~Yreg2;
   assign Y3 = (!GL & (G2 | !G1)) ? 1'b1 : ~Yreg3;
   assign Y4 = (!GL & (G2 | !G1)) ? 1'b1 : ~Yreg4;
   assign Y5 = (!GL & (G2 | !G1)) ? 1'b1 : ~Yreg5;
   assign Y6 = (!GL & (G2 | !G1)) ? 1'b1 : ~Yreg6;
   assign Y7 = (!GL & (G2 | !G1)) ? 1'b1 : ~Yreg7;
   assign Y8 = (!GL & (G2 | !G1)) ? 1'b1 : ~Yreg8;
     
   // If GL is low and G2 is low and G1 is high then the selects act on Y1 to Y8.
   // If GL is high and G2 is low and G1 is high then the last state set is still presented
   // Direct binary counting...
   always @ (*) begin
      if (!GL & G1 & !G2) begin
     Yreg1 <= (!Asel & !Bsel & !Csel); // 000
     Yreg2 <= (!Asel & !Bsel &  Csel); // 001
     Yreg3 <= (!Asel &  Bsel & !Csel); // 010
     Yreg4 <= (!Asel &  Bsel &  Csel); // 011
     Yreg5 <= ( Asel & !Bsel & !Csel); // 100
     Yreg6 <= ( Asel & !Bsel &  Csel); // 101
     Yreg7 <= ( Asel &  Bsel & !Csel); // 110
     Yreg8 <= ( Asel &  Bsel &  Csel); // 111   
      end
   end
The most popular demux for me is the 74x538.  Here we have not only multiple enables, but also multiples output enables witht he ability to tristate the outputs - so we can have a bus that controls a bus in effect.  It also have the magical P input which allows us to set the not enabled state to either high or low on demand.  The simpler 74x238 and 74x138 chips are useful as well but aren't as adaptable...

Still easy to do in verilog...
   // Tristate unless both enables are low
   assign Y1 = (!Oen1 & !Oen2) ? Yint1 : 1'bz;
   assign Y2 = (!Oen1 & !Oen2) ? Yint2 : 1'bz;
   assign Y3 = (!Oen1 & !Oen2) ? Yint3 : 1'bz;
   assign Y4 = (!Oen1 & !Oen2) ? Yint4 : 1'bz;
   assign Y5 = (!Oen1 & !Oen2) ? Yint5 : 1'bz;
   assign Y6 = (!Oen1 & !Oen2) ? Yint6 : 1'bz;
   assign Y7 = (!Oen1 & !Oen2) ? Yint7 : 1'bz;
   assign Y8 = (!Oen1 & !Oen2) ? Yint8 : 1'bz;
  
  
   // set the state if E1 and E2 are low and E3 and E4 are high otherwise all outputs are P
   assign Yint1 = (!E1 & !E2 & E3 & E4) ?  (!Asel & !Bsel & !Csel) : P;
   assign Yint2 = (!E1 & !E2 & E3 & E4) ?  (!Asel & !Bsel &  Csel) : P;
   assign Yint3 = (!E1 & !E2 & E3 & E4) ?  (!Asel &  Bsel & !Csel) : P;
   assign Yint4 = (!E1 & !E2 & E3 & E4) ?  (!Asel &  Bsel &  Csel) : P;
   assign Yint5 = (!E1 & !E2 & E3 & E4) ?  ( Asel & !Bsel & !Csel) : P;
   assign Yint6 = (!E1 & !E2 & E3 & E4) ?  ( Asel & !Bsel &  Csel) : P;
   assign Yint7 = (!E1 & !E2 & E3 & E4) ?  ( Asel &  Bsel & !Csel) : P;
   assign Yint8 = (!E1 & !E2 & E3 & E4) ?  ( Asel &  Bsel &  Csel) : P;

Another useful variant is the 74x157 which is the classic quad 2 to 1 mux.   You can think of it as selecting between two 4 bit groups, two 3 bit groups plus a 1 bit group, two 2 bit groups, or four 1 bit groups... by chaining them together this can be 2 of any number of groups.
The hdl is easy in verilog...




   // bind outputs to selected input or gnd based on strobe
   assign Y1 = strobe ? Ysel1 : 1'b0;
   assign Y2 = strobe ? Ysel2 : 1'b0;
   assign Y3 = strobe ? Ysel3 : 1'b0;
   assign Y4 = strobe ? Ysel4 : 1'b0;

   // connect output selection based on select state
   assign Ysel1 = select ? B1 : A1;
   assign Ysel2 = select ? B2 : A2;
   assign Ysel3 = select ? B3 : A3;
   assign Ysel4 = select ? B4 : A4;

As with muxes you can do more complex math by using feedback designs and when linked to memory/registers some of the basic elements of processors can be built.

Next time I think we'll do counters...