vhdlfpgaspartan

FPGA : using both falling and rising edge in same process


I'm a fpga & vhdl newbie..

My development environment is as follows.

FPGA :Spartan 6 XC6SLX9

Compiler : ISE 14.04

Simulator : Isim

I'm making a simple counter, but there are some things I can't understand.

The following code is what I wrote. What I expected was w_count increased every falling edge of the clock, and reset to 0 when w_count reach to N_data during rising edge of the clock. There was no problem in the compilation process, and simulation also works well as I expected. But when applied to real fpga, w_count was incremented for each trigger, but was not initialized to zero when reached to N_data..

w_state_proc : process(r_clk, reset_n_clean)
begin
    if(reset_n_clean = '0') then
        w_count <= 0;
    elsif(r_clk'event and r_clk = '0') then
        if(state = write_state and w_proc = '1') then
            w_count <= w_count + 1;
        end if;
    elsif(r_clk'event and r_clk = '1') then
        if(w_count = N_data) then
            w_count <= 0;
        end if;
    end if;
end process w_state_proc;

When I changed the position of two elsif statements, w_count didn't increase at all..

w_state_proc : process(r_clk, reset_n_clean)
begin
    if(reset_n_clean = '0') then
        w_count <= 0;
    elsif(r_clk'event and r_clk = '1') then
        if(w_count = N_data) then
            w_count <= 0;
        end if;
    elsif(r_clk'event and r_clk = '0') then
        if(state = write_state and w_proc = '1') then
            w_count <= w_count + 1;
        end if;
    end if;
end process w_state_proc;

I could see a lot of feedback that these statements are not recommended, but I don't understand why these statements cause this problems..


Solution

  • Your FPGA doesn't have dual data rate (DDR) flip flops in the general purpose fabric, that's why it's not recommended - "as is" it cannot implement the desired functionality.

    Also, you are using asynchronous reset. While possible, also highly not recommended, as the FPGA already has synchronous reset flip-flops and thus it doesn't take any extra logic have it, unlike in ASIC, and you'll get known value to every signal even without reset. Asynchronous reset will create trouble for you in achieving the timing closure one way or another.

    In your example, there is really no need for DDR FFs anyhow. It would seem that the reason to have the behavior you have is that the w_count can be cleared between the clock cycles so that w_count never is N_data when incremented. Why not have the compare it to value that is one smaller?

    Or, you could use variables (very carefully!) to achieve very similar behavior:

      w_state_proc : process(r_clk) is
        variable v_count : integer range 0 to N_data;
      begin
        if (rising_edge(r_clk)) then
          v_count := w_count;
          if(state = write_state and w_proc = '1') then
            v_count := v_count + 1;
          end if;
    
          if(reset_n_clean = '0' or v_count = N_data) then
            w_count <= 0;
          else
            w_count <= v_count;
          end if;
    
        end if;
      end process w_state_proc;
    

    If you would really need the w_count to have the value of N_data for half a clock cycle, you can always make the clock twice as fast and use enable signal active every other clock cycle, and propagate that alongside your pipeline. That'll get you in a whole host of other (very educational) trouble, but doable.