1st project having issues with latches?

Started by Corycet 6 years ago11 replieslatest reply 6 years ago89 views


So I am new to FPGA's and thought I would start an easy project which tries to recreate the Motorola MC14514 or 4 bit transparent latch/ 4 to 16 line decoder. So looking at the datasheet I thought the structural model would be a good choice to start with. I am running it on a spartan 3e board and when I run the code on the spartan, it appears to take 2 - 3 seconds for it to latch. It appears to work perfectly in the simulator but can't get it to work on the board like it should. I even tried to make a simpler behavioral model which acts the exact same way. So I hear that using latches in fpgas should be avoided like the plague. So maybe that is were my problem lies. However, since the original chip has latches I don't see how to write the code any other way. If you have any solutions for me to try please do so. 



library IEEE;





entity MC14514 is -- Motorola 4 to 16 Demultiplexer

     Port (d1 : in bit;

 d2 : in bit;

 d3 : in bit;

 d4 : in bit;

 str : in bit;

 inh : in bit;

 q0 : out bit;

 q1 : out bit;

 q2 : out bit;

 q3 : out bit;

 q4 : out bit;

 q5 : out bit;

 q6 : out bit;

 q7 : out bit;

 q8 : out bit;

 q9 : out bit;

 q10 : out bit;

 q11 : out bit;

 q12 : out bit;

 q13 : out bit;

 q14 : out bit;

 q15 : out bit);          

end MC14514;

   architecture struct of MC14514 is

signal s1,s2,s3,s4,s5,s6,s7,s8,s9,s10,s11,s12,s13,s14,s15,s16,s17,s18,s19,s20,s21,s22,s23,s24,s25,s26,s27,s28,str_s,inh_s : bit;


INV1 : entity work.inverter(basic)

port map (d1,s1);

INV2 : entity work.inverter(basic)

port map (d2,s2);

INV3 : entity work.inverter(basic)

port map (d3,s3);

INV4 : entity work.inverter(basic)

port map (d4,s4);

INV5 : entity work.inverter(basic)

port map (str,str_s);

INV6 : entity work.inverter(basic)

port map (inh,inh_s);

NOR1 : entity work.nor_gate(basic)

port map (s1,str_s,s5);

NOR2 : entity work.nor_gate(basic)

port map (s5,str_s,s9);

NOR3 : entity work.nor_gate(basic)

port map (s2,str_s,s6);

NOR4 : entity work.nor_gate(basic)

port map (s6,str_s,s10);

NOR5 : entity work.nor_gate(basic)

port map (s3,str_s,s7);

NOR6 : entity work.nor_gate(basic)

port map (s7,str_s,s11);

NOR7 : entity work.nor_gate(basic)

port map (s4,str_s,s8);

NOR8 : entity work.nor_gate(basic)

port map (s8,str_s,s12);

NOR9 : entity work.nor_gate(basic)

port map (s13,s14,s21);

NOR10 : entity work.nor_gate(basic)

port map (s17,s14,s22);

NOR11 : entity work.nor_gate(basic)

port map (s13,s18,s23);

NOR12 : entity work.nor_gate(basic)

port map (s17,s18,s24);

NOR13 : entity work.nor_gate(basic)

port map (s16,s15,s25);

NOR14 : entity work.nor_gate(basic)

port map (s19,s16,s26);

NOR15 : entity work.nor_gate(basic)

port map (s15,s20,s27);

NOR16 : entity work.nor_gate(basic)

port map (s19,s20,s28);

SRFF1 : entity work.srff(basic)

port map (s5,s9,s13,s17);

SRFF2 : entity work.srff(basic)

port map (s6,s10,s14,s18);

SRFF3 : entity work.srff(basic)

port map (s7,s11,s15,s19);

SRFF4 : entity work.srff(basic)

port map (s8,s12,s16,s20);

NAND1 : entity work.nand_gate(basic)

port map (s25,s21,inh_s,q0);

NAND2 : entity work.nand_gate(basic)

port map (s25,s22,inh_s,q1);

NAND3 : entity work.nand_gate(basic)

port map (s25,s23,inh_s,q2);

NAND4 : entity work.nand_gate(basic)

port map (s25,s24,inh_s,q3);

NAND5 : entity work.nand_gate(basic)

port map (s26,s21,inh_s,q4);

NAND6 : entity work.nand_gate(basic)

port map (s26,s22,inh_s,q5);

NAND7 : entity work.nand_gate(basic)

port map (s26,s23,inh_s,q6);

NAND8 : entity work.nand_gate(basic)

port map (s26,s24,inh_s,q7);

NAND9 : entity work.nand_gate(basic)

port map (s27,s21,inh_s,q8);

NAND10 : entity work.nand_gate(basic)

port map (s27,s22,inh_s,q9);

NAND11 : entity work.nand_gate(basic)

port map (s27,s23,inh_s,q10);

NAND12 : entity work.nand_gate(basic)

port map (s27,s24,inh_s,q11);

NAND13 : entity work.nand_gate(basic)

port map (s28,s21,inh_s,q12);

NAND14 : entity work.nand_gate(basic)

port map (s28,s22,inh_s,q13);

NAND15 : entity work.nand_gate(basic)

port map (s28,s23,inh_s,q14);

NAND16 : entity work.nand_gate(basic)

port map (s28,s24,inh_s,q15);

end architecture struct; 

entity SRFF is -- Set Reset Flip Flop

    Port ( S : in bit;

           R : in bit;

           Q : inout bit;

           QN : inout bit);

end SRFF;

architecture basic of SRFF is


            SRFF_behav : process (S,R,Q,QN)


Q <= R NOR QN;

               QN <= S NOR Q;

            end process SRFF_behav;

end basic;

entity NAND_GATE is -- Three Input NAND Gate

    Port ( A : in bit;

           B : in bit;

           C : in bit;

           Y : out bit);


architecture basic of NAND_GATE is


            NAND_GATE_behav : process (A,B,C)



            end process NAND_GATE_behav;

end basic;

entity NOR_GATE is -- NOR Gate

    Port ( A : in bit;

           B : in bit;

           Y : out bit);


architecture basic of NOR_GATE is


            NOR_GATE_behav : process (A,B)


Y <= A NOR B;

            end process NOR_GATE_behav;

end basic;

entity INVERTER is -- Inverter

    Port ( A : in bit;

           B : out bit);           


architecture basic of INVERTER is


            INVERTER_behav : process (A)


B <= NOT A;

            end process INVERTER_behav;

end basic;


[ - ]
Reply by adouvilleSeptember 12, 2017


You use the FPGA as an asynchronous component... Do you look at timing report? According your coding style, several logic stages will be implemented and depending on the FPGA speed grade, your design will be slow (even if 2/3 seconds seem to be very long).

FPGA should mainly be used with a global clock so as to synchronize all flip-flops. What is your interest in not using clock?

Secondly, your coding style is a bit confused as it would be nice to group all your instantiations into one VHDL construct (process).

[ - ]
Reply by CorycetSeptember 12, 2017

Thanks, for the response. Can you show an example how to group all of the instantiations into one VHDL construct? Also curious as how to implement the clock. Since the original chip does not have a clk input I did not think it was necessary. However, base on what you said it sounds like that might fix my issue. I am not sure how to integrate without some research though. 

[ - ]
Reply by adouvilleSeptember 13, 2017

Something like this... (not tested, nor simulated!)

VHDL is powerfull enough and you can add generic parameter to have a reusable component (generic parameter for MC14514 or MC14515, generic parameter for input width so for having a 3 to 8, 4 to 16, ... with the same code, ...)








  System_Clk                      : IN  STD_LOGIC;

  Reset                           : IN  STD_LOGIC;

  In_Data                         : IN  STD_LOGIC_VECTOR(3 DOWNTO 0);

  In_Strobe                       : IN  STD_LOGIC;

  In_Inhibit                      : IN  STD_LOGIC;

  Out_Data                        : OUT STD_LOGIC_VECTOR(15 DOWNTO 0)


END MC14514;


  SIGNAL Data_ABCD                : STD_LOGIC_VECTOR(3 DOWNTO 0);


  -- First part with the SR

  Latch_SR_Process: PROCESS(System_Clk, Reset)


    IF Reset = '1' THEN

      Data_ABCD <= (OTHERS=>'0');


      IF In_Strobe='1' THEN

        -- Latch the incoming data

        Data_ABCD <= In_Data;


        -- Keep 'Data_ABCD' untouched


      END IF;

    END IF;

  END PROCESS Latch_SR_Process;

  -- Second part with the decoding

  Decoding_Process: PROCESS(System_Clk, Reset)


    IF Reset = '1' THEN

      Out_Data <= (OTHERS=>'0');


      IF In_Inhibit='1' THEN

        -- All outputs = 0 for MC14514

        Out_Data <= (OTHERS=>'0');


        -- Decode according Data_ABCD

        Out_Data <= (OTHERS=>'0');

        CASE Data_ABCD IS

          WHEN X"0"   => Out_Data( 0) <= '1';

          WHEN X"1"   => Out_Data( 1) <= '1';

          WHEN X"2"   => Out_Data( 2) <= '1';

          WHEN X"3"   => Out_Data( 3) <= '1';

          WHEN X"4"   => Out_Data( 4) <= '1';

          WHEN X"5"   => Out_Data( 5) <= '1';

          WHEN X"6"   => Out_Data( 6) <= '1';

          WHEN X"7"   => Out_Data( 7) <= '1';

          WHEN X"8"   => Out_Data( 8) <= '1';

          WHEN X"9"   => Out_Data( 9) <= '1';

          WHEN X"A"   => Out_Data(10) <= '1';

          WHEN X"B"   => Out_Data(11) <= '1';

          WHEN X"C"   => Out_Data(12) <= '1';

          WHEN X"D"   => Out_Data(13) <= '1';

          WHEN X"E"   => Out_Data(14) <= '1';

          WHEN X"F"   => Out_Data(15) <= '1';

          WHEN OTHERS => NULL;

        END CASE;

      END IF;

    END IF;

  END PROCESS Decoding_Process;



[ - ]
Reply by CorycetSeptember 14, 2017

Thanks for providing a clock solution. I tested it and the latch issue seems to be solved but now the inhibit line takes 1-2 seconds to reactivate. It inhibits the output instantly but when it goes back to a low state it is stays in the inhibit state for 1 to 2 seconds. Also on a side note, I noticed you named the architecture RTL but it appears to be a behavioral model. Isn't RTL boolean algebra code?

[ - ]
Reply by adouvilleSeptember 14, 2017


As this is a clocked process, Out_Data will be evaluated at each rising edge of the clock so the 1-2 seconds are really strange.

One idea is that you underconstraint the clock: what is the clock frequency? Second idea is that the clock is not a 'true' clock (is it a true square model?). Third idea is that you have metastability on inputs (but 1-2 seconds are a bit too long for such problem). Try using Chipscope to see all signals and/or timing reports.

RTL vs behavioral model: I think that it should be a new discussion as several opinions exist. For my concern, RTL is a behavioural model that models the system at a register level (clocked process, combinatorial logic, ...). Behavioral model is at a higher level and (may) contains code that is not synthesizable.

In all cases, name does not matter. Whatever the name of the architecture is, it should works according your requirement/system.

[ - ]
Reply by CorycetSeptember 18, 2017


So it did not make sense to me why both my code and adouvilles code were both delayed, so I decided I was going to use a scope to see what was happening on the dev board as mentioned in one of the earlier responses. So I looked at the Spartan 3e manual to view the schematic and discovered that the ucf constraints had specific settings that were required for the buttons and LEDS. So I updated the ucf constraints and both code sets are working as designed. One minor issue with the inhibit line on the RTL model but no delay issues at all now on either code set. Thanks to everyone who responded to my post and helped me solve this issue. Every response was very helpful and I am very pleased with how fast the solutions came in. 

Here is the problem code followed by the working code.

Problem Code:

Net "d1" Loc = "l13";

Net "d2" Loc = "l14";

Net "d3" Loc = "h18";

Net "d4" Loc = "n17";

Net "INH"  Loc = "d18";

Net "STR"  Loc = "h13";

Net "Q0" loc = "f12" ;

Net "Q1" loc = "e12" ;

Net "Q2" loc = "e11" ;

Net "Q3" loc = "f11" ;

Net "Q4" loc = "c11" ;

Net "Q5" loc = "d11" ;

Net "Q6" loc = "e9" ;

Net "Q7" loc = "f9" ;

#Net "" loc = "f12";

#Net "" loc = "e12";

#Net "" loc = "e11";

#Net "" loc = "f11";

#Net "" loc = "c11";

#Net "" loc = "d11";

#Net "" loc = "e9";

#Net "" loc = "f9";

Working code:

Net "d1" Loc = "l13" | IOSTANDARD = LVTTL | PULLUP ;

Net "d2" Loc = "l14"| IOSTANDARD = LVTTL | PULLUP ;

Net "d3" Loc = "h18"| IOSTANDARD = LVTTL | PULLUP ;

Net "d4" Loc = "n17"| IOSTANDARD = LVTTL | PULLUP ;



Net "Q0" loc = "f12" | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 8;

Net "Q1" loc = "e12" | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 8;

Net "Q2" loc = "e11" | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 8;

Net "Q3" loc = "f11" | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 8;  

Net "Q4" loc = "c11" | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 8;

Net "Q5" loc = "d11" | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 8;

Net "Q6" loc = "e9" | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 8;

Net "Q7" loc = "f9" | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 8 ;

#Net "" loc = "f12" | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 8 ;

#Net "" loc = "e12"| IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 8 ;

#Net "" loc = "e11"| IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 8 ;

#Net "" loc = "f11"| IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 8 ;

#Net "" loc = "c11"| IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 8 ;

#Net "" loc = "d11"| IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 8 ;

#Net "" loc = "e9"| IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 8 ;

#Net "" loc = "f9"| IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 8 ;

[ - ]
Reply by stephanebSeptember 18, 2017

Thanks for taking the time to report the solution to your problem.

[ - ]
Reply by thorndbearSeptember 12, 2017

Hi Corycet,

This is an interesting puzzle. I agree that one should expect the basic logic of the MC14514 to be reproducible in a logic array.

You observe that it takes 2 to 3 second for the output to latch. I assume that on closer inspection, you would find it taking that 2-3 seconds for it to settle to a stable value. The delay that you are experiencing may be evidence of the meta-stability that one can experience with race conditions in combinatorial logic. This is why following a practice of synchronous design provides more assurance of consistent results, with a well distributed single clock edge that synchronizes the movement of data through a design.

A structural implementation like yours is common in some areas of FPGA design. So that alone isn't your problem. But I suspect your model of the SRFF is the primary source of your circuits instability.

Reduce your logic to just a single SRFF with its data input and strobe and observe the two outputs, ideally on an oscilloscope. The inherent instability of your latch may be more obvious.

From a general standpoint, I would not recommend trying to model a latch as an exercise in learning about logic design in FPGAs. As you mentioned, including a latch in your design should be (I would qualify as "must be") avoided like the plague. It is often flagged by design software as an error or at least a warning.

[ - ]
Reply by CorycetSeptember 12, 2017

I have a scope so I can do what you mentioned with SRFF. Will chipscope provide any useful data as well? Haven't used it yet but I heard its a good tool to use to see what the FPGA is actually doing compared to ISim.


[ - ]
Reply by thorndbearSeptember 12, 2017

I don't have experience with chipscope. But like other FPGA debugging tools, I assume it is less likely to accurately capture any metastable behavior at the outputs.

[ - ]
Reply by rajkeerthy18September 13, 2017

Hi @Coryset,

The MC14514 data sheet is available from ON Semi :

The select input is strobed and stored by transparent latches. To exactly replicate the behavior, choose the FPGA family and instantiate latch provided in the library. Implement decoder using a case statement. So the tools know the timing parameters and timing analysis would not be hassle dealing with hold violations that the tool would report later. Alternately the FPGA vendors publish app notes on coding styles to implement certain structures, if you follow the same, the  synthesis tool would infer such a structure. I would not suggest structures such as Set-Rest flops or JK flops. Implementing latches using discrete gates usually results in glitchy design.  Just noted this device MC14514 is quite slow, the FPGA implementation would be quite fast.