VHDL internal signal to change output - not working?

7.7k views Asked by At

I have this PC module, very simple (Code at the end). I first generate some input signal port_int and at the end of the process say pc_out <= port_int. My goal is to either increment or add or subtract from PC, depending on input signals.

In the simulation, the internal port_int signal works fine, but pc_out doesn't. Why is this happening? Look at the simulation: sim

Look how port_int changes as it should, while pc_out is late. Later in the simulation, pc_out gets even worse, changing irregularly, not even just being late.

What am I doing wrong? Is there another way to change pc_out? Bcoz you can't change out signals, and I've been told that inout is extremely bad practice..

Here's the code:

entity PC is
    Port ( clk : in STD_LOGIC; 
       enable : in STD_LOGIC; 
       reset : in STD_LOGIC;
       pc_out : out  STD_LOGIC_VECTOR (3 downto 0);
       data : in  STD_LOGIC_VECTOR (3 downto 0);    -- jump value
       zero : in  STD_LOGIC;    -- jump condition
       jmp_en : in  STD_LOGIC;      -- jump enable
       jmp_dir : in STD_LOGIC;  -- jump direction
       ctrl_en : out STD_LOGIC);   -- output signal
end PC;

architecture Behavioral of PC is

type state_type is (s0, s1, s2, s3);
signal reg_state, next_state : state_type;

signal port_int : std_logic_vector(3 downto 0);

begin

state_transition: process(clk, reset)
begin
    if (reset = '1') then
        reg_state <= s0;
    elsif(rising_edge(clk)) then
        reg_state <= next_state;
    end if;
end process;

next_state_logic: process(reg_state, enable)
begin
    case reg_state is
        when s0 =>
            if(enable = '1') then
                next_state <= s2;
            else
                next_state <= s1;
            end if;

        when s1 =>
            if(enable = '1') then
                next_state <= s2;
            else
                next_state <= s1;
            end if;

        when s2 =>
            next_state <= s3;

        when s3 =>
            if(enable = '1') then
                next_state <= s2;
            else
                next_state <= s1;
            end if;
    end case;
end process;

output_logic: process(reg_state, zero, jmp_en, jmp_dir, data)
begin
    case reg_state is
        when s0 =>
            pc_out <= "0000";
            port_int <= "0000";
            ctrl_en <= '0';

        when s1 =>
            ctrl_en <= '0';

        when s2 =>
            if(zero = '1' and jmp_en = '1' and jmp_dir = '1')then
                port_int <= port_int + data;    -- jump forward
            elsif(zero = '1' and jmp_en = '1' and jmp_dir = '0')then
                port_int <= port_int - data;    -- jump backward
            else    -- nije ispunjen uslov skoka
                port_int <= port_int + '1'; -- increment PC
            end if;
            pc_out <= port_int;

        when s3 =>
            ctrl_en <= '1';
    end case;
end process;

end Behavioral;

EDIT:

When I import the module in a whole processor, this happens: sim3 the same pc_out signal acts strangely, adn all the inputs are the same. I use the pc_out signal just in one place, to select memory. Why isn't it behaving normally? What could have caused this?

2

There are 2 answers

0
VAP On BEST ANSWER

The second process (output_logic: process), which computes the output values, has some problems.

First, recall that it implements a combinational circuit (therefore, memoryless), so equations like port_int <= port_int + data can only be computed if the value of port_int is stored somewhere. By the way, after fixing the code, you can drop the internal signal port_int and use pc_out directly.

Second, being this process a combinational circuit, its full truth table must be specified; otherwise, latches will be inferred. Note, for example, that only the value of ctrl_en is specified in state s1. You must either specify all output values (same list) in all states or, equivalently, you can make a list of output values before the case statements, so the compiler will use them as default values when the values are not explicitly declared.

4
godel9 On

If I understand what you're trying to do correctly, you just need a single statement outside the process blocks:

pc_out <= port_int;

Take all other statements assigning something to pc_out out of your design. I think you're getting tripped up by the <= operator, which waits until the next simulation delta to actually update the signal driver.