Thursday, March 24, 2011

Remembering classic logic... (part 10)

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.


I finished up a number of the odd chips I had in the box but I'll mention a few here.


The 74x521 is a very simple chip that just compares two 8 bit inputs and if they are the same (bit for bit) then it outputs low and otherwise it output high.  Very simple to code in verilog...

  always @ (*) begin
      if (A == B) begin
         Q <= 1'b0;
      end
      else begin
         Q <= 1'b1;
      end
   end
 The 74x280 is much more interesting... This chip looks at 9 input lines and if there is an odd number of high bits then it outputs odd and if the number of high bits is even it outputs even.  This is very useful in determining whether a bit was corrupted in flight (although there are much better parity algorithms when you know something about the type of data or there are many more bits than 9.

It's not too hard to figure out how to design this one... there are a number of ways to do it, but I like symmetry and I like verilog that's easy to understand.


   // If you have 2 inputs then an exclusive or would let you know the parity - 01 and 10.
   // If you have 3 inputs then it's a bit harder - 001, 010, 100 are the cases. Which can be
   // thought of as (!A & !B & C) or (!A & B & !C) or (A & !B & !C).  Since we have 9 inputs
   // we can then use the same mechanism to compare the results of the first 3 triplets as triplets.
   assign J    = (!A & !B & C) | (!A & B & !C) | (A & !B & !C) | (A & B & C);
   assign K    = (!D & !E & F) | (!D & E & !F) | (D & !E & !F) | (D & E & F);
   assign L    = (!G & !H & I) | (!G & H & !I) | (G & !H & !I) | (G & H & I);  
   assign odd  = (!J & !K & L) | (!J & K & !L) | (J & !K & !L) | (J & K & L);
   assign even = ~odd;
This gives you a quick idea of what the mapping looks like (just counting through the progression in binary).

Looking only at the first part you can see the unfolded bits of the count below and the numerical representation under the outputs (which is a nice way to check that it works correctly).
       
The last one I'll mention here is the 74x249.  This is an open collector (it either grounds an output or let's it float in high impedance) that takes a 4 bit bcd input and maps it to the parts of a 7 segment display... there are lots of ways to drive 7 segment displays and usually I use a little microcontroller now, but these little chips were a very reliable way to get the job done... (other variants with true outputs can be used to supply current if your display is setup that way).


   always @ (*) begin
      if (!lt) begin
     dataout = 7'b0000000;
      end
      else if (lt & (!rbo | (!rbi & (datain == 4'b0000)))) begin
     // if rbo is low or rbi is low and the data in is 0000 then off
     dataout = 7'bzzzzzzz;
      end
      else if (lt & rbo) begin
     case (datain)
       (4'b0000): begin
          dataout = 7'b000000z;
       end
       (4'b0001): begin
          dataout = 7'bz00zzzz;
       end
       (4'b0010): begin
          dataout = 7'b00z00z0;
       end
       (4'b0011): begin
          dataout = 7'b0000zz0;
       end
       (4'b0100): begin
          dataout = 7'bz00zz00;
       end
       (4'b0101): begin
          dataout = 7'b0z00z00;
       end
       (4'b0110): begin
          dataout = 7'b0z00000;
       end
       (4'b0111): begin
          dataout = 7'b000zzzz;
       end
       (4'b1000): begin
          dataout = 7'b0000000;
       end
       (4'b1001): begin
          dataout = 7'b0000z00;
       end
       (4'b1010): begin
          dataout = 7'bzzz00z0;
       end
       (4'b1011): begin
          dataout = 7'bzz00zz0;
       end
       (4'b1100): begin
          dataout = 7'bz0zzz00;
       end
       (4'b1101): begin
          dataout = 7'b0zz0z00;
       end
       (4'b1110): begin
          dataout = 7'bzzz0000;
       end
       (4'b1111): begin
          dataout = 7'bzzzzzzz;
       end      
     endcase  
      end     
   end

That would be easier if it was binary rather than bcd, but the idea behind the 7 segment was to display base 10 data (0123456789) and bcd is a very common way to handle this; however,  incomplete symbol set mapping to the field space available always makes things uglier to handle than when the mapping is unique and complete...

That's about it for the classic logic I have available... I think next we will look at spi interfaces...