ISIM signal assignment delay - vhdl

I expected signal 'delay' to be one clock cycle late wrt to the entities' port 'input', but ISIM shows no phase shift.
I thought there is always is a delay between signal assignment and actual value (when the process suspends), but I don't seee it here.
Why is this?
Code:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity test is
Port ( clk: in std_logic;
input: in std_logic
);
end test;
architecture Behavioral of test is
signal delay: std_logic:= '0';
begin
proc1: process(clk)
begin
if(rising_edge(clk)) then
delay <= input; -- ISIM shows no delay between them
end if;
end process;
end Behavioral;
Testbench:
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
ENTITY tb_testbench_test IS
END tb_testbench_test;
ARCHITECTURE behavior OF tb_testbench_test IS
-- Component Declaration for the Unit Under Test (UUT)
COMPONENT test
PORT(
clk: in std_logic;
input: in std_logic
);
END COMPONENT;
--Inputs
signal clk: std_logic := '0';
signal input: std_logic := '0';
-- Clock period definitions
constant clk_period : time := 10 ns;
BEGIN
-- Instantiate the Unit Under Test (UUT)
uut: test PORT MAP (
clk => clk,
input => input
);
-- Clock process definitions
clk_process :process
begin
clk <= '0';
wait for clk_period/2;
clk <= '1';
wait for clk_period/2;
end process;
-- Stimulus process
stim_proc: process
begin
wait for clk_period * 9.5;
input <= '1';
wait for clk_period;
input <= '0';
wait;
end process;
end;

Your test bench describes clk and input going high at the same time. You then have a process in your entity that is looking for a rising_edge of clk. Therefore, when your process runs, and asks 'was there a rising edge of the clock?', if the answer to this is 'yes', i.e. the clock signal had just become '1', then the state of the input must also be '1', because the two signals changed at the same time. The delay signal then takes this new input, giving the result you see.
A more realistic scenario would be a change of the input being caused by a rising edge of clk. You can easily simulate this by modifying your stimulus process:
stim_proc: process
begin
wait for clk_period * 9.5;
wait until clk = '1'; -- Sit here until we have seen a rising edge of `clk`
input <= '1'; -- This assignment now happens *after* the clock edge
wait until clk = '1';
input <= '0';
wait;
end process;

The delay between a signal assignment and the appearance of its value is ... one delta cycle. And the time taken by one delta cycle is 0 fS.
What your testbench represents is a race condition whereby you present the input signal and the clock signal at exactly the same time - i.e. in the same delta cycle.
In real hardware, what would happen would be a coin-toss whether the input was seen by this clock edge or the next, or would be some intermediate value when the clock edge happened, raising the possibility of metastable operation.
The simulation has accidentally alerted you to the possibility of such mis-operation.
If you delay the data signal by even one delta cycle (as is guaranteed to happen if it was the output from a previous clocked process) such as a concurrent signal assignment outside the process, you will eliminate the timing hazard and see the delay you expect.

Related

Reset from Port to internal components connection

I have a Module consisting from another module. e.g.
entity Layer is
port (
CLK: IN std_logic; -- Clock
DIN: IN std_logic;
RST: IN std_logic -- Reset
); -- Data
end Layer;
architecture Behavioral Layer is
component MVM
port (
CLK: IN std_logic; -- Clock
DIN: IN std_logic; -- Data
RST: IN std_logic -- Reset
);
end component;
signal MVM_RST: std_logic;
port MAP( DIN => DIN, CLK => CLK, RST => MVM_RST);
process(CLK) is
begin
if rising_edge(CLK) then
IF RST='1' then
MVM_RST <= '1';
ELSE
MVM_RST <= '0';
END IF;
END IF;
END PROCESS;
end Behavioral;
The logic behind this is I have several other modules connected to reset (not shown in this example) and want them to reset at different time steps but all at the beginning
(i dont know if this is runable, because i wrote it only as a minimin example)
my module 'MVM' is something like
IF RST='1' THEN
MVM_RESULT <= '0';
ELSE
MVM_RESULT <= DIN;
END IF;
The In port of the top module (the layer) is getting new data every clock cycle except for the first one. The first clock cycle is reserved for a high impulse of the reset signal. It starts with clock 0 to get a 0->1 transition
When I am looking at my simulation, the module receives data from the 3th cycle (or?). but so I am loosing 2 cycles instead of 1 cycle
The problem behind this is the part
if rising_edge(CLK) then
IF RST='1' then
MVM_RST <= '1';
ELSE
MVM_RST <= '0';
END IF;
As far as I understand, it means in the first cycle MVM_Res is seted to 1 (which is correct), at the second clock cycle is set to 0, this means for me it can receive data from the 3th cycle (or?)
How to avoid the delay of two cycles. I only want a maximum of 1 cycle delay. I also dont want to directly connect my top module-reset to the component-reset
Here is my testbench (I converted the values to std_logic instead std_logic_vectors to have a minimum example)
entity tb_Layer is
end tb_Layer;
architecture TEST of tb_Layer is
component Layer is
port(
CLK,DIN, RST: IN std_logic;
);
end component;
signal CLK, DIN, RST: std_logic;
BEGIN
uut: Layer PORT MAP(
CLK=> CLK, DIN => DIN, RST=> RST);
tb: process
BEGIN
CLK <= '0';
RST <= '1';
DIN <= '0';
wait for 100ns;
CLK <= '1';
wait for 100ns;
RST <= '0';
CLK <= '0';
DIN <= '1';
wait for 100ns;
CLK <= '1';
wait for 100ns;
CLK <= '0';
DIN <= '0';
wait for 100ns;
CLK <= '1';
wait for 100ns;
END PROCESS;
end TEST;
What the component sees:
The problem is that the first edge it transmits the RST high. SO the component sees after half a cycle too late the Reset high. But because of this the component sees a half cycle the 'u' and so the issue occurs.
You still have the same reason as in your other question, the synchronous reset. In that question, you left the stimulating signals undefined in the first clock cycle, and wondered why the result occurred one clock cycle later than you expected. The suggested change removed the first problem, but not your current issue.
BTW, the shown wave diagram does not match the code of the test bench. Therefore, I respond to the wave diagram, because it seems that this is you problem.
Again, the synchronous nature of the internally generated reset signal delays the reset of the component MVM by one cycle:
At the first rising edge of CLK the signal MVM_RST latches the 'U', as this is the value of RST.
At the second rising edge of CLK the signal MVM_RST latches the '1' of RST and resets MVM_RESULT to all zeroes.
At the third rising edge of CLK the signal MVM_RST latches the '0' of RST and let MVM_RESULT take the value of DIN.
If you had evaluated and simulated the shown test bench, it would go like this:
At the first rising edge of CLK the signal MVM_RST latches the '1' of RST and resets MVM_RESULT to all zeroes.
At the second rising edge of CLK the signal MVM_RST latches the '0' of RST and let MVM_RESULT take the value of DIN.
You might want to learn how to display waves of internal signals with your simulator. Then you can look at MVM_RST to see when it is active.

Unconditional WAIT statement's effect on processes in VHDL

There is something I do not understand about VHDL processes ending with an unconditional wait statement. To illustrate my problem, I need to compare the 2 following snipets :
snipet 1 :
library ieee;
use ieee.std_logic_1164.all;
entity foo is
end entity;
architecture sim of foo is
signal clk : std_logic := '0';
signal s : std_logic;
begin
clk <= not clk after 10 ns;
-- driver1
s <= '0';
-- driver2
process (clk) is
begin
s <= clk;
end process;
end architecture;
There is a double assignment for signal s: Driver1 drives the signal s to '0' while driver2 alternatively drives it to '0' and '1'. As we can see on the waveform graph, when clk is '0', the resulting s is '0' (green segments) but when clk is '1', the resulting s is 'X' (red segments).
=> I understand this behaviour, no problem with that one.
If I modify slightly this code by changing driver1 into a process ended with an unconditional wait instruction :
snipet2 :
library ieee;
use ieee.std_logic_1164.all;
entity foo is
end entity;
architecture sim of foo is
signal clk : std_logic := '0';
signal s : std_logic;
begin
clk <= not clk after 10 ns;
-- driver1
-- s <= '0';
process
begin
s <= '0';
wait;
end process;
-- driver2
process (clk) is
begin
s <= clk;
end process;
end architecture;
Surprisingly, for me, the snipet 2 produces the same waveform as the snipet 1. My understanding is that the instructions inside a process with a final "unconditional" wait statement will stop forever, meaning that their code will be inactive after the first execution run. But if this is truly the case, I would expect that driver1 in snipet 2 is inactive after its first run, and that from that point driver2 remains the only active driver of signal s, always assigning clk's alternative '1's and '0's to it.
Why isn't it the case?
When you assign a signal in a process, a driver is created for that signal from the moment it assigned until the end of simulation. So here, both code snippets are functionally equivalent, you create driver1 from time 0 and driver2 from the first clock.

Unexpected behavior of simple VHDL circuit

What the cause of different delays of signals Q_VLD1 and Q_VLD2 in simulator?
Result of simulation. Is it expected behaviour of simulator or not?
I use Xilinx Isim.
There is the code and testbench for it:
entity assign_test is
port(CLK : in STD_LOGIC;
D_VLD : in STD_LOGIC;
Q_VLD1 : out STD_LOGIC;
Q_VLD2 : out STD_LOGIC
);
end assign_test;
architecture Behavioral of assign_test is
signal D_VLD_i : std_logic;
signal d_vld_dly1 : std_logic;
signal d_vld_dly2 : std_logic;
begin
D_VLD_i <= D_VLD;
process (clk) is
begin
if rising_edge(clk) then
d_vld_dly1 <= D_VLD;
d_vld_dly2 <= D_VLD_i;
end if;
end process ;
Q_VLD1 <= d_vld_dly1;
Q_VLD2 <= d_vld_dly2;
end Behavioral;
ENTITY tb_assign_test IS
END tb_assign_test;
ARCHITECTURE behavior OF tb_assign_test IS
COMPONENT assign_test
PORT(
CLK : IN std_logic;
D_VLD : IN std_logic;
Q_VLD1 : OUT std_logic;
Q_VLD2 : OUT std_logic
);
END COMPONENT;
--Inputs
signal CLK : std_logic := '0';
signal D_VLD : std_logic := '0';
--Outputs
signal Q_VLD1 : std_logic;
signal Q_VLD2 : std_logic;
constant CLK_period : time := 10 ns;
BEGIN
uut: assign_test PORT MAP (
CLK => CLK,
D_VLD => D_VLD,
Q_VLD1 => Q_VLD1,
Q_VLD2 => Q_VLD2
);
CLK_process :process
begin
CLK <= '0';
wait for CLK_period/2;
CLK <= '1';
wait for CLK_period/2;
end process;
stim_proc: process
begin
wait for 100 ns;
wait for 5 ns;
wait for CLK_period*10;
D_VLD <= '1';
wait for CLK_period*3;
D_VLD <= '0';
wait;
end process;
END;
So if you look at the internal signals in the assign_test module, based on simulation time only, it may look as in figure below (d_vld_dly* is before assign to Q_VLD*).
But the figure is misleading, since that figure does not show the VHDL concept of delta delay. If the waveform is expanded to show delta delays (using ModelSim in this case), it looks like below.
So this reveals that the D_VLD_i <= D_VLD; in the assign_test actually delays the D_VLD_i a delta delay, whereby the new value is not seen at the clock until next rising clock edge.
The reason for this problem, is that the test bench does not generate input data as a cause of the clock, which would make data one delta delay after the clock, but independently and at the same simulation time and same delta delay as the clock.
The test bench can be updated to generate data as a cause of the clock, if wait for clock is changed from:
wait for CLK_period*10;
to:
for i in 1 to 10 loop
wait until rising_edge(CLK);
end loop;
which will then give a waveform as:
So based on this, a rule for good test bench design is to generate stimuli the same way as generating data in synthesized modules, so the stimuli from the test bench is like data between modules in general, in order to get expected and reliable and test bench behavior.

VHDL - FSM not starting (JUST in timing simulation)

I'm working for my master thesis and I'm pretty new to VHDL, but still I have to implement some complex things. This is one of the easiest structures I had to write, and still I'm encountering some problems.
It's a FSM implementing a 24bit shift register with an active-low sync signal (to program a DAC). It's just the end of a complex elaboration chain I created for my project. I followed the example model of a FSM as much as I could.
The behavioral simulation works fine, actually the whole elaboration chain I created works perfectly fine as far as the behavioral simulation concerns. However, once I try the Post-translate simulation things start to go wrong: lots of 'X' output signals.
With this simple shift register I DON'T get any 'X', however I can't get to the load_and_prepare_data phase. It seems that the current_state changes (by inspecting some signals), but the elaboration doesn't go on.
Please keep in mind that since I'm new to the language, I have no idea of what timing constraints I should set on this FSM (and I wouldn't know how to write them on the top.ucf anyway)
Can you see what's wrong?
Thanks in advance
EDIT
I followed your advices and cleaned up the FSM by using a single state process. I still have some doubts about "where to put what" but I really like the new implementation. Anyway I now get a clean behavioral simulation but 'X' on all outputs in post translate simulation.
What is causing this?
I'll post the both the new code and the testbench:
----------------------------------------------------------------------------------
-- Company:
-- Engineer:
--
-- Create Date: 14:44:03 11/28/2014
-- Design Name:
-- Module Name: dac_ad5764r_24bit_sr_programmer_v2 - Behavioral
-- Project Name:
-- Target Devices:
-- Tool versions:
-- Description: This is a PISO shift register that gets a 24bit parallel input word.
-- It outputs the 24bit input word starting from the MSB and enables
-- an active low ChipSelect line for 24 clock periods.
-- Dependencies:
--
-- Revision:
-- Revision 0.01 - File Created
-- Additional Comments:
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
use IEEE.NUMERIC_STD.ALL;
-- Uncomment the following library declaration if instantiating
-- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;
entity dac_ad5764r_24bit_sr_programmer_v2 is
Port ( clk : in STD_LOGIC;
start : in STD_LOGIC;
reset : in STD_LOGIC; -- Note that this reset is for the FSM not for the DAC
reset_all_dac : in STD_LOGIC;
data_in : in STD_LOGIC_VECTOR (23 downto 0);
serial_data_out : out STD_LOGIC;
sync_out : out STD_LOGIC; -- This is a chip select
reset_out : out STD_LOGIC;
busy : out STD_LOGIC
);
end dac_ad5764r_24bit_sr_programmer_v2;
architecture Behavioral of dac_ad5764r_24bit_sr_programmer_v2 is
-- Stati
type state_type is (idle, load_and_prepare_data, transmission);
--ATTRIBUTE ENUM_ENCODING : STRING;
--ATTRIBUTE ENUM_ENCODING OF state_type: TYPE IS "001 010 100";
signal state: state_type := idle;
--signal next_state: state_type := idle;
-- Clock counter
--signal clk_counter_enable : STD_LOGIC := '0';
signal clk_counter : unsigned(4 downto 0) := (others => '0');
-- Shift register
signal stored_data: STD_LOGIC_VECTOR (23 downto 0) := (others => '0');
begin
FSM_single_process: process(clk)
begin
if rising_edge(clk) then
if reset = '1' then
serial_data_out <= '0';
sync_out <= '1';
reset_out <= '1';
busy <= '0';
state <= idle;
else
-- Default
serial_data_out <= '0';
sync_out <= '1';
reset_out <= '1';
busy <= '0';
case (state) is
when transmission =>
serial_data_out <= stored_data(23);
sync_out <= '0';
busy <= '1';
clk_counter <= clk_counter + 1;
stored_data <= stored_data(22 downto 0) & "0";
state <= transmission;
if (clk_counter = 23) then
state <= idle;
end if;
when others => -- Idle
if start = '1' then
serial_data_out <= data_in(23);
sync_out <= '0';
reset_out <= '1';
busy <= '1';
stored_data <= data_in;
clk_counter <= "00001";
state <= transmission;
end if;
end case;
-- if (reset_all_dac = '1') then
-- reset_out <= '0';
-- end if;
end if;
end if;
end process;
end;
And the testbench:
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--USE ieee.numeric_std.ALL;
ENTITY dac_ad5764r_24bit_sr_programmer_tb IS
END dac_ad5764r_24bit_sr_programmer_tb;
ARCHITECTURE behavior OF dac_ad5764r_24bit_sr_programmer_tb IS
-- Component Declaration for the Unit Under Test (UUT)
COMPONENT dac_ad5764r_24bit_sr_programmer_v2
PORT(
clk : IN std_logic;
start : IN std_logic;
reset : IN std_logic;
data_in : IN std_logic_vector(23 downto 0);
serial_data_out : OUT std_logic;
reset_all_dac : IN std_logic;
sync_out : OUT std_logic;
reset_out : OUT std_logic;
--finish : OUT std_logic;
busy : OUT std_logic
);
END COMPONENT;
--Inputs
signal clk : std_logic := '0';
signal start : std_logic := '0';
signal reset : std_logic := '0';
signal data_in : std_logic_vector(23 downto 0) := (others => '0');
signal reset_all_dac : std_logic := '0';
--Outputs
signal serial_data_out : std_logic;
signal sync_out : std_logic;
signal reset_out : std_logic;
--signal finish : std_logic;
signal busy : std_logic;
-- Clock period definitions
constant clk_period : time := 100 ns;
BEGIN
-- Instantiate the Unit Under Test (UUT)
uut: dac_ad5764r_24bit_sr_programmer_v2 PORT MAP (
clk => clk,
start => start,
reset => reset,
data_in => data_in,
reset_all_dac => reset_all_dac,
serial_data_out => serial_data_out,
sync_out => sync_out,
reset_out => reset_out,
--finish => finish,
busy => busy
);
-- Clock process definitions
clk_process :process
begin
clk <= '0';
wait for clk_period/2;
clk <= '1';
wait for clk_period/2;
end process;
-- Stimulus process
stim_proc: process
begin
-- hold reset state for 100 ns.
wait for clk_period*10;
reset <= '1' after 25 ns;
wait for clk_period*1;
reset <= '0' after 25 ns;
wait for clk_period*3;
reset_all_dac <= '1' after 25 ns;
wait for clk_period*1;
reset_all_dac <= '0' after 25 ns;
wait for clk_period*5;
data_in <= "111111111111111111111111" after 25 ns;
wait for clk_period*3;
start <= '1' after 25 ns;
wait for clk_period*1;
start <= '0' after 25 ns;
wait;
end process;
END;
UPDATE 1
Updated with the last design: this code is not causing any 'X' (can't figure out why, this doesn't but the previous did). However it's not starting (in POST-TRANSLATE simulation) just like the first 3 process machine, and the signal sync_out is stuck at 0 while it should be '1' by default.
UPDATE 2
I've been looking into the tecnology schematic, starting from the problem of the sync_out=0: it's implemented with a FDS, S is the FSM reset signal, D is coming from a LUT3 with I = state&reset&start and INIT = 45 = "00101101". I've looked for this LUT3 in the simulation and I've noticed that it has INIT = "00000000"!
Is there something I'm missing about how to run this simulation? It seems that every LUT in the design have not been set!
UPDATE 3
It seems that the Post-Translate simulation is buggy in some way, or I'm not configuring it correctly for some reason: the Post-Map and the Post-PAR simulations work and display some outputs.
However there is an odd bug: the stored_data register is not updated with the complete data_in vector, after that, the FSM operates correctly and outputs the data stored.
I've looked in the tecnology schematic just after synthesis and for some reason the bits 23,22,21,19,18 are not connected to the corresponding data_in bit. You can see the effect in this screenshot from Post-Map simulation. Same happens in Post-PAR, but it seems that this problems comes directly from the synthesis!
Solved: the strange output comes from the Synthesis optimization. The tool realized that the previous block in the elaboration chain will never output a bit different from 0 for those specific bit. My mistake was assuming that I could test the single block alone: what I was really testing was the block synthetized for the FPGA taking into account everything else in the design!
Thanks to everybody helped me, I'm going to follow your advices!
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:
You can remove the Xilinx dependencies to UNISIM, because you are not using any Xilinx Primitves.
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 ...
None of your registers has a default value:
signal current_state : state_type := idle;
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.
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
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;

Ring Oscillator

I'm having some trouble implementing a ring oscillator. I don't care about it working on an FPGA. I only want to simulate using Xilinx ISE. Is the code below acceptable? I also addded the test bench. Thanks!
Code
library ieee;
use ieee.std_logic_1164.all;
-- 5 Ring Oscillator
entity ring_osc is
port (ro_en : in std_logic;
delay : in time;
ro_out : out std_logic);
end ring_osc;
architecture behavioral of ring_osc is
signal gate_out : std_logic_vector(5 downto 0) := (others => '0');
begin
process
begin
gate_out(0) <= ro_en and gate_out(5);
wait for delay;
gate_out(1) <= not(gate_out(0));
wait for delay;
gate_out(2) <= not(gate_out(1));
wait for delay;
gate_out(3) <= not(gate_out(2));
wait for delay;
gate_out(4) <= not(gate_out(3));
wait for delay;
gate_out(5) <= not(gate_out(4));
wait for delay;
ro_out <= gate_out(5);
end process;
end behavioral;
Test Bench
library ieee;
use ieee.std_logic_1164.all;
entity ring_osc_tb is
end ring_osc_tb;
architecture behavior of ring_osc_tb is
-- component declaration for the unit under test (uut)
component ring_osc
port (ro_en : in std_logic;
delay : in time;
ro_out : out std_logic);
end component;
-- Inputs
signal ro_en : std_logic := '0';
signal delay : time := 0.5 ns;
-- Outputs
signal ro_out : std_logic;
signal clk : std_logic := '0';
constant clk_period : time := 10 ns;
begin
-- instantiate the unit under test (uut)
uut: ring_osc port map (
ro_en => ro_en,
delay => delay,
ro_out => ro_out
);
-- clock process definitions
clk_process :process
begin
clk <= '0';
wait for clk_period/2;
clk <= '1';
wait for clk_period/2;
end process;
-- stimulus process
stim_proc: process
begin
ro_en <= '1';
delay <= 0.5 ns;
wait for 10*clk_period;
delay <= 1 ns;
wait for 5*clk_period;
assert false report "End of Simulation" severity failure;
end process;
end;
The process with sequential wait does not describe the concurrent nature of the gates in the Ring oscillator, since execution is suspended for delay time at each wait, which is not the way a real word design operates.
A description with concurrent evaluation of all the gates can be:
gate_out(0) <= ro_en and gate_out(5) after delay;
inv_g : for i in 1 to gate_out'high generate
gate_out(i) <= not gate_out(i - 1) after delay;
end generate;
ro_out <= gate_out(5);
This is for simulation only, as also noted in the question, due to the inherent loop nature of a ring oscillator.
Using test bench, with added disable at start:
-- Disable at start
ro_en <= '0';
delay <= 0.5 ns;
wait for 10 * 0.5 ns;
Then the resulting waveform is:

Resources