Search code examples
vectorvariable-assignmentvhdl

std_logic vector (15 downto 0) value doesn't get assigned


So, long story short, I'm trying to make a processor of sorts ('of sorts' is put there for a reason, but let's not go into details), and I'm running into one problem which pretty much ruins the whole thing.

Namely, in this piece of code :

programmProcess: process (clk,rst) is
    variable counter : natural;
begin
    if (rst = '1') then
        counter := 0;
    elsif (clk'event and clk = '1' and pm_nEn= '1') then
        RAM(counter) <= data; --This is where the issue is
        counter := counter + 1;
        if (counter = 1024) then
            counter := 0;
        end if;
    end if;
    data <= "ZZZZZZZZZZZZZZZZ";
end process programmProcess;

... and this is the testbench process :

 stim_proc1: process 
 begin  
    rst <= '1';
    pm_nEn <= '1';
    wait for clk_period;

    rst <= '0' ;

    data <="0000111110111001";
    wait for clk_period;

    data <="0000111010111001";
    wait for clk_period;

    data <= "ZZZZZZZZZZZZZZZZ";
    pm_nEn <= '0';
    wait for 10*clk_period;
    wait;
end process;

... where RAM is an array of 1024 vectors of 16 bits, data is a 16 bit inout vector and pm_nEn is a single bit which basically allows the RAM to be filled with values.

The idea is that RAM(counter) gets values from the data vector, which is manually fed values in the testbench, but this doesn't happen. Namely, all of RAM's values just stay "UUUUUUUUUUUUUUUU", despite data having the required values. Even when it's first evaluated and counter is 0, RAM(0) is undefined.

I'm using the ISE suite, and I tried simulating, and then just tracing through all the steps, and the step where RAM(counter) should get assigned a value is shown, the data vector does have the value which is added manually from the testbench, but RAM still doesn't get any values.

So, the question is basically - why does this happen? Why doesn't RAM get its values assigned?

Also, here's the full VHDL and testbench (which was conveniently generated by ISE) in google doc form -

VHDL

Testbench


Solution

  • Assigning "zzzz" to Data within the main process should do no harm (although in the current code fragment, it is redundant).

    One thing that may lead to problems in synthesis is:

     elsif (clk'event and clk = '1' and pm_nEn= '1') then
        ... actions
     end if;
    

    To match the pattern a synthesis tool expects for a clocked process, it is better to write

     elsif clk'event and clk = '1' then
        if pm_nEn= '1' then
           ... actions
        end if;
     end if;
    

    though I would expect the two versions to be equivalent in simulation. There isn't another driver on RAM in another process, is there?

    EDIT: apparently there IS a separate driver setting RAM in another process. Now from a software perspective, you might think that is OK because one process drives when en = '0' and the other when en = '1'. However you can't make the driver hardware appear and disappear at the flick of a boolean; there are always two drivers on the RAM signal. And the one you aren't explicitly using is holding the value as "UUUU".

    The best thing to do is to eliminate one of them. Make one process or the other responsible for writing to RAM. I'll use this process; you may find the design is cleaner and tidier using the other process; that's OK too.

    It's easy : just reorganise this process along these lines:

     elsif clk'event and clk = '1' then
        if pm_nEn= '1' then
           ... actions
        else    -- or elsif external_enable then 
           RAM(external_address) <= external_data;
        end if;
     end if;
    

    Incidentally, when you see an expression like RAM(to_integer(unsigned(R(to_integer(unsigned(IR(5 downto 3))))))) <= std_logic_vector(signed(OP1) + signed(OP2)); it's usually a clue that some things have been declared as the wrong types in the first place : for example, OP1 and OP2 should possibly be signed, R should be an array of integers, and so on. If you can't eliminate all the ugliness, you can at least stop it interfering with the main program flow using helper functions (possibly in a package):

    function gen_reg_addr(IR : Register) return natural is ...
    
    RAM(gen_reg_addr(IR)) <= ...