2
\$\begingroup\$

I'm a mostly analog EE who's trying to set up an fpga dev kit (terasic de0-nano) to twiddle the control bits on some pulse control parts I'm doing an evaluation board for. I'm using an external dip switch to change an output pulse width and I want to confirm which pulse width selection I'm in by lighting up the onboard LEDs.

I know very little about FPGAs; I implemented a clocked state machine as it seemed like a good starting place. I'm sure I'm doing lots of bad things in general but I'm having one particular problem - my status LEDs aren't working.

I'm trying to get rid of an inferred latch that "has unsafe behavior". I was getting inferred latches for both txTime and ledOut in some prior code. I followed the advice in

https://stackoverflow.com/questions/15500510/how-can-i-make-this-vhdl-code-synthesizable

and put the different options for the cfgDIP 8 bit dip switch into a case statement. I made sure there was an others case to handle states I didn't explicitly address. This made the txTime latch go away; however, it did not fix the ledOut latch unsafe behavior. And either way the inferred latches are still there so it seems like there's a more fundamental problem.

Questions 1) What's a good way to for someone like me to learn to implement practical vhdl FPGA code very quickly? My old undergrad digital logic books are hard to glean practical coding advice from.

2) How do I fix the ledOut latch unsafe behavior?

3) How do I eliminate the inferred latches altogether? There are inferred latches for triggerOut, rxTime, ledOut, clampToRxTime and clampToTxTime. I don't understand why there isn't a txTime inferred latch since it's also used in two states.

My VHDL Code:

LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.std_logic_unsigned.all;
USE ieee.numeric_std.all;

ENTITY pulserLogic IS
    PORT(   clk, reset_n                    : IN STD_LOGIC; 
            cfgDIP, stIn, maxIn         : IN STD_LOGIC_VECTOR (7 DOWNTO 0); 
            stOut, maxOut                   : OUT STD_LOGIC_VECTOR (15 DOWNTO 0);
            ledOut                          : OUT STD_LOGIC_VECTOR (7 DOWNTO 0);
            triggerOut                      : OUT STD_LOGIC);               
END pulserLogic;

ARCHITECTURE logic OF pulserLogic IS
    SIGNAL              timeCounter         : INTEGER  RANGE 0 TO 300_000;          --timing counter
    TYPE                state IS (state_init,state_TxVPP,state_clampToRx,state_Rx,state_clampToTx);
    SIGNAL          pr_state, nx_state: state;


BEGIN
--reset and clocked state machine controller process
    PROCESS (clk,reset_n)
        VARIABLE count : INTEGER RANGE 0 to 300_000;
    BEGIN
        IF(reset_n = '0') THEN                 --asynchronous reset 
            pr_state <= state_init;
            count := 0;
        ELSIF(RISING_EDGE(clk)) THEN                --stay in current state for set number of clock cycles then move to next state
            count := count + 1;
            IF (count = timeCounter) THEN
                pr_state <= nx_state;
                count := 0;
            END IF;
        END IF;
    END PROCESS;

--state declaration process
    PROCESS (pr_state,timeCounter,cfgDIP,stIn,maxIn)
        VARIABLE txTime : INTEGER RANGE 0 to 50;
        VARIABLE    rxTime  : INTEGER RANGE 0 to 250000000; --at 250MHz clock 1hz= 250000000 and 2khz = 125000, 
        VARIABLE    clampToRxTime   : INTEGER RANGE 0 to 250000000; --at 250MHz clock 1hz= 250000000 and 2khz = 125000 
        VARIABLE    clampToTxTime   : INTEGER RANGE 0 to 250000000; --at 250MHz clock 1hz= 250000000 and 2khz = 125000
        Variable ledOutVar : STD_LOGIC_VECTOR (7 DOWNTO 0);

    BEGIN
        CASE pr_state IS
            WHEN state_init =>                                  -- initialize   
                triggerOut <= '0';
                txTime := 5;                                                            -- set to nominal 20ns pulse width (4ns clock * 5)
                rxTime := 10000;                                                        -- set to nominal 40us rx time 
                ledOut <= "01000010";
                clampToRxTime := 200;                                               -- time between end of Tx and start of Rx, default 800ns (200 *4)
                clampToTxTime := 2500000-txTime-clampToRxTime-rxTime;       -- time between end of Rx and start of Tx, default to 100Hz PRF
                stOut <= "0000000000000000";                                    -- clamp all outputs
                maxOut <= "0000000000000000";                               
                timeCounter <= 10;                                                  -- nominal num of cycles in the init state
                nx_state <= state_TxVPP;  

            WHEN state_TxVPP =>                         
                stOut <= "1010101010101010";
                maxOut <= "1010101010101010";

                case cfgDIP is
                    when "00000001" => 
                        txTime := 15;
                        ledOut <= "00000001";
                    when "00000011" =>
                        txTime := 20;
                        ledOut <= "00000011";
                    when "00000111" =>
                        txTime := 25;   
                        ledOut <= "00000111";                   
                    when others =>
                        txTime := 10;
                        ledOut <= "00001111";
                end case;

                timeCounter <= txTime;  
                nx_state <= state_clampToRx;    

            WHEN state_clampToRx =>
                stOut <= "0000000000000000";
                maxOut <= "0000000000000000";
                timeCounter <= clampToRxTime;
                nx_state <= state_Rx;

            WHEN state_Rx =>
                stOut <= "1111111111111111";
                maxOut <= "1111111111111111";
                timeCounter <= rxTime;
                nx_state <= state_clampToTx;    

            WHEN state_clampToTx =>
                stOut <= "0000000000000000";
                maxOut <= "0000000000000000";
                timeCounter <= clampToTxTime;
                nx_state <= state_TxVPP;

        END CASE;
    END PROCESS;    
END logic;

Quartus Output:

Info (12021): Found 1 design units, including 1 entities, in source file pulserevalboardcontroller.bdf
    Info (12023): Found entity 1: pulserEvalBoardController
Info (12021): Found 2 design units, including 1 entities, in source file pulserlogic.vhd
    Info (12022): Found design unit 1: pulserLogic-logic
    Info (12023): Found entity 1: pulserLogic
Info (12021): Found 2 design units, including 1 entities, in source file pulserpll.vhd
    Info (12022): Found design unit 1: pulserpll-SYN
    Info (12023): Found entity 1: pulserPLL
Info (12021): Found 2 design units, including 1 entities, in source file pulsepll.vhd
    Info (12022): Found design unit 1: pulsepll-SYN
    Info (12023): Found entity 1: pulsePLL
Info (12127): Elaborating entity "pulserEvalBoardController" for the top level hierarchy
Info (12128): Elaborating entity "pulserLogic" for hierarchy "pulserLogic:inst"
Warning (10631): VHDL Process Statement warning at pulserLogic.vhd(38): inferring latch(es) for signal or variable "triggerOut", which holds its previous value in one or more paths through the process
Warning (10631): VHDL Process Statement warning at pulserLogic.vhd(38): inferring latch(es) for signal or variable "rxTime", which holds its previous value in one or more paths through the process
Warning (10631): VHDL Process Statement warning at pulserLogic.vhd(38): inferring latch(es) for signal or variable "ledOut", which holds its previous value in one or more paths through the process
Warning (10631): VHDL Process Statement warning at pulserLogic.vhd(38): inferring latch(es) for signal or variable "clampToRxTime", which holds its previous value in one or more paths through the process
Warning (10631): VHDL Process Statement warning at pulserLogic.vhd(38): inferring latch(es) for signal or variable "clampToTxTime", which holds its previous value in one or more paths through the process
Info (10041): Inferred latch for "clampToTxTime[0]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "clampToTxTime[1]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "clampToTxTime[2]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "clampToTxTime[3]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "clampToTxTime[4]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "clampToTxTime[5]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "clampToTxTime[6]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "clampToTxTime[7]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "clampToTxTime[8]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "clampToTxTime[9]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "clampToTxTime[10]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "clampToTxTime[11]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "clampToTxTime[12]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "clampToTxTime[13]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "clampToTxTime[14]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "clampToTxTime[15]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "clampToTxTime[16]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "clampToTxTime[17]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "clampToTxTime[18]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "clampToRxTime[0]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "clampToRxTime[1]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "clampToRxTime[2]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "clampToRxTime[3]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "clampToRxTime[4]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "clampToRxTime[5]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "clampToRxTime[6]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "clampToRxTime[7]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "clampToRxTime[8]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "clampToRxTime[9]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "clampToRxTime[10]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "clampToRxTime[11]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "clampToRxTime[12]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "clampToRxTime[13]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "clampToRxTime[14]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "clampToRxTime[15]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "clampToRxTime[16]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "clampToRxTime[17]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "clampToRxTime[18]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "ledOut[0]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "ledOut[1]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "ledOut[2]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "ledOut[3]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "ledOut[4]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "ledOut[5]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "ledOut[6]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "ledOut[7]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "rxTime[0]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "rxTime[1]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "rxTime[2]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "rxTime[3]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "rxTime[4]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "rxTime[5]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "rxTime[6]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "rxTime[7]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "rxTime[8]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "rxTime[9]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "rxTime[10]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "rxTime[11]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "rxTime[12]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "rxTime[13]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "rxTime[14]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "rxTime[15]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "rxTime[16]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "rxTime[17]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "rxTime[18]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "triggerOut" at pulserLogic.vhd(38)
Info (12128): Elaborating entity "pulsePLL" for hierarchy "pulsePLL:inst1"
Info (12128): Elaborating entity "altpll" for hierarchy "pulsePLL:inst1|altpll:altpll_component"
Info (12130): Elaborated megafunction instantiation "pulsePLL:inst1|altpll:altpll_component"
Info (12133): Instantiated megafunction "pulsePLL:inst1|altpll:altpll_component" with the following parameter:
    Info (12134): Parameter "bandwidth_type" = "AUTO"
    Info (12134): Parameter "clk0_divide_by" = "1"
    Info (12134): Parameter "clk0_duty_cycle" = "50"
    Info (12134): Parameter "clk0_multiply_by" = "5"
    Info (12134): Parameter "clk0_phase_shift" = "0"
    Info (12134): Parameter "compensate_clock" = "CLK0"
    Info (12134): Parameter "inclk0_input_frequency" = "20000"
    Info (12134): Parameter "intended_device_family" = "Cyclone IV E"
    Info (12134): Parameter "lpm_hint" = "CBX_MODULE_PREFIX=pulsePLL"
    Info (12134): Parameter "lpm_type" = "altpll"
    Info (12134): Parameter "operation_mode" = "NORMAL"
    Info (12134): Parameter "pll_type" = "AUTO"
    Info (12134): Parameter "port_activeclock" = "PORT_UNUSED"
    Info (12134): Parameter "port_areset" = "PORT_UNUSED"
    Info (12134): Parameter "port_clkbad0" = "PORT_UNUSED"
    Info (12134): Parameter "port_clkbad1" = "PORT_UNUSED"
    Info (12134): Parameter "port_clkloss" = "PORT_UNUSED"
    Info (12134): Parameter "port_clkswitch" = "PORT_UNUSED"
    Info (12134): Parameter "port_configupdate" = "PORT_UNUSED"
    Info (12134): Parameter "port_fbin" = "PORT_UNUSED"
    Info (12134): Parameter "port_inclk0" = "PORT_USED"
    Info (12134): Parameter "port_inclk1" = "PORT_UNUSED"
    Info (12134): Parameter "port_locked" = "PORT_UNUSED"
    Info (12134): Parameter "port_pfdena" = "PORT_UNUSED"
    Info (12134): Parameter "port_phasecounterselect" = "PORT_UNUSED"
    Info (12134): Parameter "port_phasedone" = "PORT_UNUSED"
    Info (12134): Parameter "port_phasestep" = "PORT_UNUSED"
    Info (12134): Parameter "port_phaseupdown" = "PORT_UNUSED"
    Info (12134): Parameter "port_pllena" = "PORT_UNUSED"
    Info (12134): Parameter "port_scanaclr" = "PORT_UNUSED"
    Info (12134): Parameter "port_scanclk" = "PORT_UNUSED"
    Info (12134): Parameter "port_scanclkena" = "PORT_UNUSED"
    Info (12134): Parameter "port_scandata" = "PORT_UNUSED"
    Info (12134): Parameter "port_scandataout" = "PORT_UNUSED"
    Info (12134): Parameter "port_scandone" = "PORT_UNUSED"
    Info (12134): Parameter "port_scanread" = "PORT_UNUSED"
    Info (12134): Parameter "port_scanwrite" = "PORT_UNUSED"
    Info (12134): Parameter "port_clk0" = "PORT_USED"
    Info (12134): Parameter "port_clk1" = "PORT_UNUSED"
    Info (12134): Parameter "port_clk2" = "PORT_UNUSED"
    Info (12134): Parameter "port_clk3" = "PORT_UNUSED"
    Info (12134): Parameter "port_clk4" = "PORT_UNUSED"
    Info (12134): Parameter "port_clk5" = "PORT_UNUSED"
    Info (12134): Parameter "port_clkena0" = "PORT_UNUSED"
    Info (12134): Parameter "port_clkena1" = "PORT_UNUSED"
    Info (12134): Parameter "port_clkena2" = "PORT_UNUSED"
    Info (12134): Parameter "port_clkena3" = "PORT_UNUSED"
    Info (12134): Parameter "port_clkena4" = "PORT_UNUSED"
    Info (12134): Parameter "port_clkena5" = "PORT_UNUSED"
    Info (12134): Parameter "port_extclk0" = "PORT_UNUSED"
    Info (12134): Parameter "port_extclk1" = "PORT_UNUSED"
    Info (12134): Parameter "port_extclk2" = "PORT_UNUSED"
    Info (12134): Parameter "port_extclk3" = "PORT_UNUSED"
    Info (12134): Parameter "width_clock" = "5"
Info (12021): Found 1 design units, including 1 entities, in source file db/pulsepll_altpll.v
    Info (12023): Found entity 1: pulsePLL_altpll
Info (12128): Elaborating entity "pulsePLL_altpll" for hierarchy "pulsePLL:inst1|altpll:altpll_component|pulsePLL_altpll:auto_generated"
Warning (13012): Latch pulserLogic:inst|ledOut[6] has unsafe behavior
    Warning (13013): Ports D and ENA on the latch are fed by the same signal pulserLogic:inst|pr_state.state_TxVPP
Warning (13012): Latch pulserLogic:inst|ledOut[3] has unsafe behavior
    Warning (13013): Ports D and ENA on the latch are fed by the same signal pulserLogic:inst|pr_state.state_TxVPP
Warning (13012): Latch pulserLogic:inst|ledOut[2] has unsafe behavior
    Warning (13013): Ports D and ENA on the latch are fed by the same signal pulserLogic:inst|pr_state.state_TxVPP
Warning (13012): Latch pulserLogic:inst|ledOut[1] has unsafe behavior
    Warning (13013): Ports D and ENA on the latch are fed by the same signal pulserLogic:inst|pr_state.state_TxVPP
Warning (13012): Latch pulserLogic:inst|ledOut[0] has unsafe behavior
    Warning (13013): Ports D and ENA on the latch are fed by the same signal pulserLogic:inst|pr_state.state_TxVPP
Warning (13024): Output pins are stuck at VCC or GND
    Warning (13410): Pin "triggerOut" is stuck at GND
    Warning (13410): Pin "ledOut[7]" is stuck at GND
    Warning (13410): Pin "ledOut[5]" is stuck at GND
    Warning (13410): Pin "ledOut[4]" is stuck at GND
Info (286030): Timing-Driven Synthesis is running
\$\endgroup\$
3
  • 2
    \$\begingroup\$ Rewrite in single process form with a clocked process. Various aspects of the combinational process can be problematic, including assignments that ought to be in the clocked process, and the sensitivity list. \$\endgroup\$
    – user16324
    Aug 15, 2017 at 20:13
  • \$\begingroup\$ In addition to only assigning a value in one state (causing the inferred latches) there is a combinatorial loop in it's assignment due to feeding it's value into the expression determining it's value. clampToTxTime wants to be loaded on a clock edge. Note some of your variables are also assigned a single value and can be constants. \$\endgroup\$
    – user8352
    Aug 15, 2017 at 20:16
  • \$\begingroup\$ Don't USE ieee.std_logic_unsigned.all;. See stackoverflow.com/a/45707415/4090959 \$\endgroup\$
    – scary_jeff
    Aug 16, 2017 at 8:13

2 Answers 2

3
\$\begingroup\$

The reason for the latches is due to the fact that the outputs of your case statement are not assigned for every possible case selection. So you have created a storage element without a clock - which is the definition of a latch.

What is ledOut when pr_state is state_Rx? It's not specified by your case statement, so the synthesizer assumes it needs to hold ledOut to whatever its previous value was - which requires a storage element (memory).

  • For example, the following design will infer a latch:
entity inferred_latch is
  Port ( a  : in std_logic;
         b  : in std_logic;
         c  : out std_logic );
end inferred_latch;

architecture Behavioral of inferred_latch is begin process (a,b) begin case a is when '0' => c <= b; when others => end case; end process; end Behavioral;

inferred latch

However, if we assign a signal level to c for all possible states of a, no memory is necessary:

architecture Behavioral of no_latch is
begin
    process (a,b)
    begin
        case a is
            when '0'    => c <= b;
            when others => c <= '0'
        end case;
    end process;
end Behavioral;

no latch

For question 1: The question is a little off-topic since it is opinion based, but I will say that I remember getting a lot of use from the book Circuit Design with VHDL by Pedroni (ISBN 0262162245).

Hope this helps.


edit in response to comment:
I think the design below is equivalent to your original. I can't say that it correctly behaves as you expect. In fact, there is definitely a problem with the range of the timeCounter signal. In your state_init state, you assign a value to clampToTxTime which is much too large to fit into the declared range of timeCounter, but later in the state_clampToTx state, you assign it anyway.

I'll leave you to iron out these details. But, I believe this code is equivalent to your original - but without the latches:


LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.std_logic_unsigned.all;
USE ieee.numeric_std.all;

ENTITY pulserLogic IS
    PORT(   clk, reset_n        : IN STD_LOGIC; 
            cfgDIP, stIn, maxIn : IN STD_LOGIC_VECTOR (7 DOWNTO 0); 
            stOut, maxOut       : OUT STD_LOGIC_VECTOR (15 DOWNTO 0);
            ledOut              : OUT STD_LOGIC_VECTOR (7 DOWNTO 0);
            triggerOut          : OUT STD_LOGIC );               
END pulserLogic;

ARCHITECTURE logic OF pulserLogic IS
    SIGNAL              timeCounter         : INTEGER  RANGE 0 TO 300_000;          --timing counter
    TYPE                state IS (state_init,state_TxVPP,state_clampToRx,state_Rx,state_clampToTx);
    SIGNAL          pr_state, nx_state: state;

    signal pre_led : std_logic_vector (7 downto 0);
    signal cur_led : std_logic_vector (7 downto 0);

BEGIN

    ledOut     <= cur_led;
    triggerOut <= '0';

--reset and clocked state machine controller process
    PROCESS (clk,reset_n)
        VARIABLE count : INTEGER RANGE 0 to 300_000;
    BEGIN
        IF(reset_n = '0') THEN             --asynchronous reset 
            pr_state <= state_init;
            count := 0;
        ELSIF(RISING_EDGE(clk)) THEN       --stay in current state for set number of clock cycles then move to next state
            count := count + 1;
            IF (count = timeCounter) THEN
                pr_state <= nx_state;
                pre_led  <= cur_led;
                count := 0;
            END IF;
        END IF;
    END PROCESS;

--state declaration process
    PROCESS (pr_state, cfgDIP, pre_led)
        VARIABLE txTime : INTEGER RANGE 0 to 50;
        VARIABLE st_max_out : STD_LOGIC_VECTOR (15 DOWNTO 0) := "0000000000000000";
    BEGIN

        stOut      <= st_max_out;
        maxOut     <= st_max_out;

        CASE cfgDIP IS
            WHEN "00000001" => 
                txTime := 15;
            WHEN "00000011" =>
                txTime := 20;
            WHEN "00000111" =>
                txTime := 25;   
            WHEN others =>
                txTime := 10;
        end case;

        CASE pr_state IS
            WHEN state_init =>                  -- initialize   
                cur_led <= "01000010";
                st_max_out := "0000000000000000";    -- clamp all outputs
                timeCounter <= 10;              -- nominal num of cycles in the init state
                nx_state <= state_TxVPP;  

            WHEN state_TxVPP =>
                cur_led <= cfgDIP;
                st_max_out := "1010101010101010";
                timeCounter <= txTime;  
                nx_state <= state_clampToRx;    

            WHEN state_clampToRx =>
                cur_led <= pre_led;
                st_max_out := "0000000000000000";
                timeCounter <= 200;             -- time between end of Tx and start of Rx, default 800ns (200 *4)
                nx_state <= state_Rx;

            WHEN state_Rx =>
                cur_led <= pre_led;
                st_max_out := "1111111111111111";
                timeCounter <= 10000;           -- set to nominal 40us rx time 
                nx_state <= state_clampToTx;    

            WHEN state_clampToTx =>
                cur_led <= pre_led;
                st_max_out := "0000000000000000";
                timeCounter <= 2489795;         -- time between end of Rx and start of Tx, default to 100Hz PRF
                nx_state <= state_TxVPP;
        END CASE;
    END PROCESS;    
END logic;
\$\endgroup\$
2
  • \$\begingroup\$ Thank you @blairFonville for the latch explanation; that makes sense. I copied all the logic into all of the states and it did eliminate the latches. Is there a better way to do this than having the cfgDIP case statement in all the prcase states? \$\endgroup\$
    – cgram
    Aug 16, 2017 at 12:37
  • \$\begingroup\$ @cgram I added a possibility to the answer. Good luck. Let me know how it goes. \$\endgroup\$ Aug 16, 2017 at 19:06
2
\$\begingroup\$

pr_state is being asynchronously latched since reset_n is part of the sensitivity list of that process. Since pr_state is part of the sensitivity list of your "next state" logic state machine process, everything within that process is getting flagged with the "this is a bad idea" kind of warning. In case you didn't know, the logic interpreter views the sensitivity list as "if this signal changes at all, I need to re-run through this process and see if the outputs need to update".

If you are starting out, here are my suggestions:

1) Don't use asynchronous resets unless you absolutely have to. If you need a clocked process, put only the clock signal in the sensitivity list. You can still implement a reset logic, but do a synchronous version (IE the "if (reset_n = '0') then ..." statement goes inside the "if(rising_edge(clk)) then..." statement. The downside of this is that the desired reset behavior will not happen for 1 extra clock cycle, but that is usually fine. Also, the place and route tools have a much easier time routing synchronous resets than global asynchronous resets. There are some special cases where you will want a "asynchronously reset, synchronously set" behavior, but 99.9% of your logic shouldn't be like this.

2) Combine your clocked process and "next state" logic process into a single process. I know a lot of old VHDL books did it this way, but I find it usually easier to write it as a single process. You can get rid of the next_state signal and just update the pr_state signal directly.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.