Integer to unsigned conversion going wrong VHDL qu

2019-09-16 06:43发布

问题:

I am having problem with an output error in a waveform, basically my code works as a counter, when i have a load signal equal '1' the counter goes up, if the load signal is '0' the counter doesn't counts. I have a clear signal to get the counter in 0, my problem is in the output, the output shows always the same value and doesn't get in 0 when the clear signal is equal 1.

Below the waveform:

Below the code:

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity tot is
port (
      i_CLR  : IN STD_LOGIC;         
      i_CLK  : IN STD_ULOGIC;        
      i_DINL : IN STD_LOGIC ;        
      i_DINK : IN INTEGER;           
      o_DOUTK : BUFFER INTEGER);      
end tot;

architecture arch_1 of tot is
signal w_K : integer;                
begin
PROCESS (i_DINL)
begin
    IF rising_edge(i_CLK) THEN       
        IF (i_CLR = '1') THEN        
            w_K <= 0;                
        ELSE                         
            w_K <= i_DINK;           
        END IF;
        IF (i_DINL = '1') THEN       
            w_K <= w_K + 1;          
        ELSE                      
            w_K <= w_K;              
        END IF;
        o_DOUTK <= w_K;            
    END IF;
    end process;
end arch_1;

Update 1:

architecture arch_1 of tot is
    signal w_k:  integer;                
begin
process (i_clk)   -- WAS (i_dinl)
begin
    if rising_edge(i_clk) then     
        if i_clr = '1' then        
            w_k <= 0;                
        else
            w_k <= i_dink;       
        end if;
        if i_dinl = '1' then       
            w_k <= w_k + 1;          
        -- else
        --     w_k <= w_k;          
        end if;
        -- o_doutk <= w_k;            
    end if;
    end process;

    o_doutk <= w_k;  -- MOVED to here.

end architecture arch_1;

When i try to do this logic to load a value from k to the initial count value, the error in the waveform still appears.

Waveform:


Update 2 (correct situation):

After reading the comments i get this solution to my problem, i've used a state machine to make my counter load the previous value from K, with this code I've get the code working correctly.

LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
USE IEEE.std_logic_unsigned.ALL;
use IEEE.std_logic_arith.ALL;

ENTITY controle IS
  PORT (
      i_RST  : IN STD_LOGIC;
      i_CLR  : IN STD_LOGIC;         -- Sinal vindo do controle para limpar o valor de K
      i_CLK  : IN STD_ULOGIC;        -- Sinal de clock para sincronizar com o controle
      i_DINL : IN STD_LOGIC ;        -- Sinal de load para carregar K
      i_DINK : IN INTEGER;           -- Valor antigo de K
      o_DOUTK : BUFFER INTEGER
      );     
END controle;

ARCHITECTURE arch_1 OF controle IS
  TYPE state_type IS (s0, s1, s2,s3);
  SIGNAL stateT : state_type;

   signal w_k:  integer;  
BEGIN

  PROCESS(i_CLK)
  BEGIN
    IF rising_edge(i_CLK) THEN
      IF (i_RST = '1') THEN
        stateT <= s0;
      ELSE
        CASE stateT IS
          when s0 => if (i_CLR = '1') THEN
                        w_k <= 0;
                        stateT <= s2;
                     else
                        stateT <= s1;
                     end if;
          when s1 => if (i_dinl = '1') then 
                       w_k <= i_dink;
                       stateT <= s2;
                     end if;
          when s2 => w_K <= w_k + 1;
                     stateT <= s3;
          when s3 => o_DOUTK <= w_K; 
                     stateT <= s0;
        END CASE;
      END IF;
    END IF;
  END PROCESS;


END arch_1;

回答1:

Your sensitivity list and if statements don't do what you intend.

Try:

architecture arch_1 of tot is
    signal w_k:  integer;                
begin
process (i_clk)   -- WAS (i_dinl)
begin
    if rising_edge(i_clk) then       
        if i_clr = '1' then        
            w_k <= 0;                
        -- else
        --     w_k <= i_dink;       
        -- end if;
        elsif i_dinl = '1' then       
            w_k <= w_k + 1;          
        -- else
        --     w_k <= w_k;          
        end if;
        -- o_doutk <= w_k;            
    end if;
    end process;

    o_doutk <= w_k;  -- MOVED to here.

end architecture arch_1;

Which gives:

I used this testbench to create a complete MCVE:

library ieee;
use ieee.std_logic_1164.all;

entity tot_tb is
end entity;

architecture foo of tot_tb is
    signal clr:     std_logic := '1';
    signal clk:     std_logic := '0';
    signal dinl:    std_logic := '1';
    signal dink:    integer := 8;
    signal doutk:   integer;
begin
DUT:
    entity work.tot
        port map (
            i_clr => clr,
            i_clk => clk,
            i_dinl => dinl,
            i_dink => dink,
            o_doutk => doutk
        );
CLOCK:
    process
    begin
        wait for 10 ns;
        clk <= not clk;
        if now > 650 ns then
            wait;
        end if;
    end process;
STIMULI:
    process
    begin
        wait for 240 ns;
        clr <= '0';
        wait for 100 ns;
        clr <= '1';
        wait for 40 ns;
        clr <= '0';
        wait;
    end process;

end architecture;

The use clause mentioning package numeric_std is also not needed (all your arithmetic is integer based).

Without seeing a full representation of what you're intending to do here, o_doutk doesn't need to be mode buffer, it can be mode out.

All assignments are inside the if statement with the condition predicated on the rising edge of i_clk, so i_clk should be a sensitivity list item. There is no other signal that should be in the sensitivity list.

The assignment to the output is a concurrent statement which will be elaborated to an equivalent process. The idea behind a separate statement/process is to prevent a clock delay assigning the new value of w_k to o_doutk in simulation.

No signal value is updated while any pending process has yet to resume and suspend. The reason w_k was not changing is because you had two independent if statements. There's only one projected output waveform for any target simulation time, the second if statement supplanted the projected value for w_k from the first if statement supplying the reset value assignment.

Because the process assigning w_k models sequential (clocked) logic you don't infer latches by failing to provide values for else alternatives. If you had i_clk in your sensitivity list instead of i_dinl and your waveform had shown the entire value of w_k (o_doutk) you would have seen that it incremented during reset, starting at INTEGER'LOW because no initial value nor range constraint is provided in the declaration w_k.

Creating a single if statement allows only one assignment statement to be conditionally encountered, meaning the reset value of 0 will take effect.

From IEEE Std 1076-2008 10.8 If statement:

An if statement selects for execution one or none of the enclosed sequences of statements, depending on the value of one or more corresponding conditions.

Your eventual solution with a state machine doesn't appear useful:

architecture arch_1 of tot is          -- WAS controle NOW tot
    type state_type is (s0, s1, s2,s3);
    signal statet : state_type;

    signal w_k:  integer;  

begin

    process (i_clk)
    begin
        if rising_edge(i_clk) then
            if i_clr = '1' then           -- WAS i_rst NOW i_clr
                statet <= s0;
            else
                case statet is
                    when s0 => 
                        if i_clr = '1' then
                            w_k <= 0;
                        else
                            statet <= s1;
                        end if;
                    when s1 => 
                        if i_dinl = '1' then 
                            w_k <= i_dink;
                            statet <= s2;
                        end if;
                    when s2 => 
                        w_k <= w_k + 1;
                        statet <= s3;
                    when s3 => 
                        o_doutk <= w_k; 
                        statet <= s0;
                end case;
            end if;
        end if;
    end process;
END arch_1;

It produces:

Which doesn't match any possible narrative constructed from your question.

Note there's a one clock delay between w_k showing an incremented value and o_doutk and you only reach state s3 with a new value on w_k once. There's also a one clock delay between reset invalid and i_dink load into w_k.

If this waveform is what you wanted this answer is wrong. If this isn't what you want your question is unclear, your solution is wrong. In either scenario you should withdraw acceptance of this answer.

Instead of states it might be more appropriate to either load or increment w_k based on the state of i_dinl:

architecture foo of tot is
    signal w_k:  integer;
begin
    process (i_clk)   -- WAS (i_dinl)
    begin
        if rising_edge(i_clk) then
            if i_clr = '1' then
                w_k <= 0;
            -- else
            --     w_k <= i_dink;
            -- end if;
            elsif i_dinl = '1' then
                w_k <= w_k + 1;
            -- else
            else 
            --     w_k <= w_k;
                w_k <= i_dink;
            end if;
            -- o_doutk <= w_k;
        end if;
    end process;

    o_doutk <= w_k;  -- MOVED to here.

end architecture;

Which gives:

In general you'd expect a separate control signal for count enable, particularly if you had used an asynchronous reset.

The suggest by wahab to use states is predicated on encoding four functions (clr, load, increment, hold) into two inputs. The state is held by whatever provides the two control inputs.

Note that this doesn't match either of your two waveforms and your question isn't a MCVE](https://stackoverflow.com/help/mcve) for either your solution nor this one.