Thursday, March 17, 2011

Remembering classic logic... (part 5)

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.

We just looked at chips that use latches (and registers) to sample the state of wires and hold that state (memory) after the signal has changed.  Here we are going to look at chips that can allow not just reading the state of a wire but also writing the state to the wire (transceivers).

The 74x245 (and the similar 74x545 and 74x645 variants) allow two 8 bit buses to be connected in such a way that data from one can be retained and sent to the other (or vice versa).  There is an output enable line that can tristate the outputs (high impedance) and a directional control line that determines whether data from bus A appears on bus B or data from bus B appears on bus A.

 assign A1 = (!enable & !direction) ? B1 : 1'Bz;
   assign A2 = (!enable & !direction) ? B2 : 1'Bz;
   assign A3 = (!enable & !direction) ? B3 : 1'Bz;
   assign A4 = (!enable & !direction) ? B4 : 1'Bz;
   assign A5 = (!enable & !direction) ? B5 : 1'Bz;
   assign A6 = (!enable & !direction) ? B6 : 1'Bz;
   assign A7 = (!enable & !direction) ? B7 : 1'Bz;
   assign A8 = (!enable & !direction) ? B8 : 1'Bz;
  
   assign B1 = (!enable & direction) ? A1 : 1'Bz;
   assign B2 = (!enable & direction) ? A2 : 1'Bz;
   assign B3 = (!enable & direction) ? A3 : 1'Bz;
   assign B4 = (!enable & direction) ? A4 : 1'Bz;
   assign B5 = (!enable & direction) ? A5 : 1'Bz;
   assign B6 = (!enable & direction) ? A6 : 1'Bz;
   assign B7 = (!enable & direction) ? A7 : 1'Bz;
   assign B8 = (!enable & direction) ? A8 : 1'Bz;

It's a straightforward thing to do in verilog, but by now you are probably aware that you will get warnings about using latches in your design.

The 74x543 (and the similar 74x544 with inverted outputs) accomplishes a similar thing, but includes internal registers so that the states of either bus can be retained and sent over the other bus.  Here the direction is set by eab (for data from a to b), the sampling is done by leab (for latch enable a to b) and the status of the outputs is done by oeab (output enable a to b/tristate).  There are complimentary lines for the opposite bus direction (eba, leba and oeba).


The hdl is easy here as well...
 // for the tristates
   assign B1 = !(oeab & eab) ? A1reg : 1'bz;
   assign B2 = !(oeab & eab) ? A2reg : 1'bz;
   assign B3 = !(oeab & eab) ? A3reg : 1'bz;
   assign B4 = !(oeab & eab) ? A4reg : 1'bz;
   assign B5 = !(oeab & eab) ? A5reg : 1'bz;
   assign B6 = !(oeab & eab) ? A6reg : 1'bz;
   assign B7 = !(oeab & eab) ? A7reg : 1'bz;
   assign B8 = !(oeab & eab) ? A8reg : 1'bz;
  
   assign A1 = !(oeba & eba) ? B1reg : 1'bz;
   assign A2 = !(oeba & eba) ? B2reg : 1'bz;
   assign A3 = !(oeba & eba) ? B3reg : 1'bz;
   assign A4 = !(oeba & eba) ? B4reg : 1'bz;
   assign A5 = !(oeba & eba) ? B5reg : 1'bz;
   assign A6 = !(oeba & eba) ? B6reg : 1'bz;
   assign A7 = !(oeba & eba) ? B7reg : 1'bz;
   assign A8 = !(oeba & eba) ? B8reg : 1'bz;
  
   // on the rising edge of leab store the value of
   always @ (*) begin
      if (!eab & !leab) begin
     B1reg <= A1;
     B2reg <= A2;
     B3reg <= A3;
     B4reg <= A4;
     B5reg <= A5;
     B6reg <= A6;
     B7reg <= A7;
     B8reg <= A8;     
      end
     
      if (!eba & !leba) begin
     A1reg <= B1;
     A2reg <= B2;
     A3reg <= B3;
     A4reg <= B4;
     A5reg <= B5;
     A6reg <= B6;
     A7reg <= B7;
     A8reg <= B8;     
      end
   end
These two approaches are just about sufficient for just about all the basic ways one would connect multiple devices to a simple bus: 1) ability to tristate or truestate 2) ability to set the direction of data flow 3) ability to retain the current bus state after it changes (optional).  What these two groups do here is reduce the number of chips needed to achieve this... and really that's why the more complex chips were built the way they were - people used used multiple simpler components in a particular arrangement often enough that it was worth designing a product that incorporated them in one package.

One last point to make here is that there isn't really a good way to "know" that a particular chip is the only active device on a bus at a given moment (and when that's not the case it can be very difficult to troubleshoot).  The approaches of open collector/open drain bus lines with pullup/pulldown resistors makes it possible to detect relevant arbitration failures (who has the right to write on the bus).  It's a matter of design choice really, do you want to have more hardware (and cost) for each device to have it's own wires that one it can write to, or do you want to share wires among devices (and rely on an out of band channel for arbitration or more complex logic for in band arbitration)...

I think next time it's shift registers...