VHDL - FSM not starting (JUST in timing simulation)

一笑奈何 提交于 2019-12-01 13:41:13
Brian Drummond

I prefer the single-process form of state machine, which is cleaner, simpler and much less prone to bugs like sensitivity-list errors. I would also endorse the points in Paebbels' excellent answer. However I don't think any of these are the problem here.

One thing to be aware of in post-synth and post-PAR simulations is that their model of time is different from the behavioural model. The behavioural model follows simple rules as I described in this answer and ensures that in a typical design flow you can go straight to hardware - without post-synth simulation, without worry.

Indeed I only use post-synth or post-PAR simulations if I'm chasing a suspected tool bug. (For FPGA designs, not ASIC, that is!)

However, that simple timing model has its limitations. You may be familiar with problems like a clock signal assigned via signal assignment (usually buried in a 3rd party model where you don't expect it) which consumes a delta cycle, and ensures that your clocked data arrives before your clock instead of after, and everything subsequently occurs one cycle earlier than intended...

In behavioural modelling, a little discipline will keep clear of such troubles. But the same is not true of post-PAR modelling.

Your testbench is probably set up the same way as the behavioural model. And if so, that is likely to be the problem.

Here's what I do in this situation : I claim no formal authority for it, just experience. It also works well when interfacing the FPGA to external memory models with realistic timings.

1) I assume the simple (behavioural) timing model works correctly for all signals INTERNAL to the design.

2) I assume nothing of the sort for inputs and outputs from the design.

3) I take note of the estimated setup and hold timings on the inputs, (a) from the FPGA datasheet or better, (b) from the worst case values shown in the post-synth or post-PAR report, and structure the testbench around them. Worked example : setup time 1 ns, hold time 2 ns, clock period 10 ns. This means that any input between 2 ns and 9 ns after a clock edge is guaranteed to be corrrectly read. I choose (arbitrarily) 5 ns.

signal_to_fpga <= driving_value after 5 ns;

(Note that Xilinx makes this absurdly counter-intuitive by expressing them as "offset in/out before/after" which refers timings to a previous or future clock edge instead of the one you're looking at)

Alternatively, if the input is fed from a CPU or memory in the real world, I use datasheet timing specifications for that device.

4) I take note of the worst case clk-out timing reported in the datasheet or report, and structure the design around them. (say, 7 ns)

fpga_output_pin <= driving_value after 7 ns;

Note that this "after" clause is obviously ignored by synthesis; however the post-synth back-annotation will introduce something very like it.
5) If this turns out to be not good enough, then (possibly in a wrapper component to avoid polluting the synthesisable code) improve accuracy like

fpga_output_pin <= 'X' after 1 ps, driving_value after 7 ns;

6) I re-run the behavioural simulation. Typically, it now fails, because it was written without realistic timings in mind.

7) I fix those failures. This may include adding realistic delays before testing values output from the design. It can be an iterative process.

Now, I have a reasonable expectation that the post-PAR simulation model will drop straight in to the testbench and work.

Here are some hints to improve your code:

  1. You can remove the Xilinx dependencies to UNISIM, because you are not using any Xilinx Primitves.
  2. Applying attribute ENUM_ENCODING has no effect on state encoding unless you also define the attribute FSM_ENCODING and set it's value to user. One-Hot encoding can be forced by setting FSM_ENCODING to one-hot. Normally synthesis is smart enough to find the best encoding.
    read more ...
  3. None of your registers has a default value:
    signal current_state : state_type := idle;
  4. Your FSM is no FSM in the eyes of Xilinx synthesis tool (XST). I'm sure if you look into your synthesis report, you won't find that XST reports a FSM for current_state.
    So what's wrong with your FSM?
    • Your FSM has no initial state.
    • Your FSM has multiple reset states (idle, load_and_prepare_data)
    • Your FSM has no transition from idle to load_and_prepare_data (reset is no transition)
    • Writing next_state transitions for the current state can cause XST to think it's no FSM
      the default assignment next_state <= current_state; is sufficient.
  5. If you change the type of signal clk_counter to unsigned you can do arithmetic much easier.
    increment: clk_counter <= clk_counter + 1;
    clear: clk_counter <= (others => '0');
    compare: if (clk_counter = 23) then
  6. It's no good style to use the FSM's state signal outside of the FSM processes.

    FSM_next_state_process: process(current_state, start,  clk_counter, reset_all_dac)
    begin
      next_state  <= current_state;
    
      OutReg_busy        <= '1';
      OutReg_reset_out   <= '1';
      OutReg_sync_out    <= '1';
      clk_counter_enable <= '0';
    
      case (current_state) is
        when idle =>
          OutReg_busy      <= '0';
          if (reset_all_dac = '1') then
            OutReg_reset_out <= '0';
          end if;
    
        when load_and_prepare_data =>
          next_state <= transmission;
    
        when transmission =>
          clk_counter_enable <= '1';
          OutReg_sync_out <= '0';
    
          if (clk_counter = 23) then
            next_state <= idle;
          end if;
    
        when others =>
          next_state <= idle;
    
      end case ;
    end process;
    
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!