Set and reset on rising and falling edge - vhdl

How to set a bit on rising edge and reset that bit on falling edge of a clock signal?
I would like to know how i can achieve the same. Depending upon a condition i want to set on rising edge and reset on falling edge. It's like getting clock pulse itself at the output.
I implemented for two different clock pulses but i am getting glitches like these.
My code for same is as this
process(clk)
begin
if rising_edge(clk) then
d0 <= new_data;
end if;
end process;
process(clk)
begin
if falling_edge(clk) then
d1 <= new_data;
end if;
end process;
out <= d0 when clk = '1' else d1;

If you want DDR data, which is the only time I can see that you'd actually want to do this, there are a number of ways of modelling it. If you want synthesis, instantiate the appropriate vendors primitive
However, for a model:
process(clk)
begin
-- you could use this
if clock'event = '1' then
bit <= new_data;
end if;
-- or this
if rising_edge(clk) ot falling_edge(clk) then
bit <= new_data;
end if;
end process;
You could also model it as 2 processes and a mux
process(clk)
begin
if rising_edge(clk) then
d0 <= new_data;
end if;
end process;
process(clk)
begin
if falling_edge(clk) then
d1 <= new_data;
end if;
end process;
out <= d0 when clk = '1' else d1;

Having now seen your waveform, you could do the following to get a glitch free pulse train
process(clk)
begin
if falling_edge(clk) then
if pass_next_clock = '1' then
mask <= '1';
else
mask <= '0';
end if;
end if;
end process;
pulse <= clk and mask;
This requires you to have a signal called pass_next_clock, which can be aligned to either clock edge to signal that you want the next clock high pulse to be output.

Ok i got it work. My final code looks like
shared variables d0 ,d1 : std_logic;
process(clk)
begin
if rising_edge(clk) then
d0 := new_data;
end if;
end process;
process(clk)
begin
if falling_edge(clk) then
d1 := new_data;
end if;
end process;
out <= d0 when clk = '1' else d1;

Related

"Wait" for a clock cycle in VHDL process

Let's say that there is a RAM component entity as below
entity RAM is
port(
-- other port such as clk, reset, ...
en: in std_logic;
addr: in std_logic_vector(7 downto 0);
dataR: out std_logic_vector(7 downto 0));
end RAM;
RAM specification is that when en = '1', the value stored at addr is available on dataR one clock cycle afterwards.
For now, my process in which I use the RAM component looks like this:
process(state)
begin
case(state) is
-- ...
when ReadMemory =>
addr <= "00000000";
en <= '1';
next_mem <= dataR;
-- ...
end case;
end process;
This design does not work because because dataR is read on the same clock cycle as when addr and en are set.
How can I "wait" a single clck cycle in order to read the correct value from the memory ?
You are using a finite state machine, so you can use a "waiting" state
process(state)
begin
case(state) is
-- ...
when ReadMemory =>
addr <= "00000000";
en <= '1';
next_state <= WaitMemory;
when WaitMemory =>
next_mem <= dataR;
next_state <= another_state;
-- ...
end case;
end process;
Be careful, with certain kind of finite state machine you could have to wait 2 clocks. To be more specififc, with this kind of FSM :
process(CLK)
begin
if rising_edge(CLK) then
state <= next_state;
end if;
end process;
process(state)
begin
case(state) is
-- ...
-- YOUR FSM with next_state attribution
-- ...
end case;
end process;
You have to wait 1 clock.
But with this one :
process(CLK)
begin
if rising_edge(CLK) then
case(state) is
-- ...
-- YOUR FSM with state attribution
-- ...
end case;
end if;
end process;
You will have to wait 2 clocks

Register loading when it shouldnt

So, i've this register that has synchronous load (e_inter(4)) and reset signals:
--Register Rx2
process (clk)
begin
if clk'event and clk = '1'then
if reset = '1' then
Rx2 <= X"00000000";
elsif e_inter(4) = '1'then
Rx2 <= mul1;
end if;
end if;
end process;
Problem is that even if i allways set e_inter(4) = '0' all the time, the register still loads the value from mul1 into Rx2. I can see that e_inter(4) = '0' in the simulation and that when the rising edge of clock comes it makes Rx2 <= mul1 . Any thoughts?

Generating 2 clock pulses in VHDL

How do I generate two clock pulses based on a trigger signal. I have found this code (which works very well) here in stackoverflow :
get_data:process(clk, reset)
variable idle : boolean;
begin
if reset = '1' then
idle := true;
elsif rising_edge(clk) then
clr_flag <= '0'; -- default action
if idle then
if flag = '1' then
clr_flag <= '1'; -- overrides default FOR THIS CYCLE ONLY
idle <= false;
end if;
else
if flag = '0' then
idle := true;
end if;
end if;
end if;
end process;
I was wondering if someone can help me in generating a flag that lasts 2 clock pulses instead of one.
I would just do this:
signal s_flag, s_flag_1z : std_logic := '0';
begin
get_data:process(clk, reset)
variable idle : boolean;
begin
if reset = '1' then
idle := true;
s_flag <= '0';
s_flag_1z <= '0';
elsif rising_edge(clk) then
s_flag <= '0'; -- default action
s_flag_1z <= s_flag;
if idle then
if flag = '1' then
s_flag <= '1'; -- overrides default FOR THIS CYCLE ONLY
idle <= false;
end if;
else
if flag = '0' then
idle := true;
end if;
end if;
end if;
end process;
cl_flag <= '1' when (s_flag & s_flag_1) /= "00" else '0';
Now the flag will be 2 clock cycles high and only a small addition was required.
/Ben
A variable length pulse is cleanest and easiest with a tap at the top of a shift register
get_data:process(clk, reset) --make sure you really want asynchronous reset
variable pulse_line : std_logic_vector(1 downto 0); --set the width to how many clocks you want the pulse
begin
if reset = '1' then --again make sure you really want asynchronous reset
pulse_line := (others => '1');
elsif rising_edge(clk) then
if flag = '1' then
pulse_line := (others => '1'); --reset the shift register
else
pulse_line := pulse_line(pulse_line'high-1 downto 0) & '0'; --push a 0 onto bottom of the shift register
end if;
clr_flag <= pulse_line(pulse_line'high); --tap out the top of the shift register
end if;
end process;

Synthesis error in VHDL clock synchronizer

I am trying to implement clock synchronization and clock divider in the following piece of VHDL code. The clocks(clk_rx and clk_tx) should synchronize at the rising and falling edges of 'RX' signal on the bus. I can simulate the following but it is not synthesizable in ISE since i am using " RX'EVENT ". Could any one suggest an alternative for this? (Verilog also will work)
-------------------------------------------- CLOCK DIVIDER----------------------------------------------------------------------------------------
PROCESS (CLK_I, RX)
BEGIN
IF (RX'EVENT) THEN
clk_cnt <= to_unsigned(0,clk_cnt'LENGTH);
ELSIF (CLK_I'EVENT AND CLK_I = '1') THEN
IF clk_cnt >2499 THEN
clk_cnt <= to_unsigned(0,clk_cnt'LENGTH);
ELSE
clk_cnt <= clk_cnt + 1;
END IF;
END IF;
END PROCESS;
clk_rx <= '1' WHEN clk_cnt = 1250 ELSE '0'; -----clk_rx=1 only at the half of the counter period----------clk enable
clk_tx <= '1' WHEN clk_cnt = 2499 ELSE '0';
You can find a suggestion for code below. Note the following properties:
clk_rx_o (clk_rx) and clk_rx_o (clk_tx) are generated as outputs from flip-flops, since to avoid glitches which may occur if the signals are generated based on combinatorial compare of cnt outside the process
rx_i is synchronized by two flip-flops, assuming that it is not already synchronous to clk_i
Clock division is by 2501, since cnt goes from 0 .. 2500 due to wrap when (cnt > 2499). For division by 2500 use (cnt >= 2499) instead.
VHDL coding style: All signal names are lower case, as are VHDL statements, consistent spacing around expressions for readability
Code:
library ieee;
use ieee.std_logic_1164.all;
entity mdl is
port(
clk_i : in std_logic;
rx_i : in std_logic;
clk_rx_o : out std_logic;
clk_tx_o : out std_logic);
end entity;
library ieee;
use ieee.numeric_std.all;
architecture syn of mdl is
signal rx_meta : std_logic;
signal rx_sync : std_logic;
signal cnt : std_logic_vector(12 - 1 downto 0);
begin
-- rx_i sync to clk_i
process (clk_i) is
begin
if rising_edge(clk_i) then
rx_meta <= rx_i;
rx_sync <= rx_meta;
end if;
end process;
process (clk_i) is
begin
if rising_edge(clk_i) then
-- Clock align and divide
if rx_sync = '1' then
cnt <= std_logic_vector(to_unsigned(0, cnt'length));
else
if unsigned(cnt) > 2499 then
cnt <= std_logic_vector(to_unsigned(0, cnt'length));
else
cnt <= std_logic_vector(unsigned(cnt) + 1);
end if;
end if;
-- Clock generate as single cycle pulse
clk_rx_o <= '0';
if unsigned(cnt) = 1250 then
clk_rx_o <= '1';
end if;
clk_tx_o <= '0';
if unsigned(cnt) = 2499 then
clk_tx_o <= '1';
end if;
end if;
end process;
end architecture;
The problem is not simply that you are using RX'EVENT, it's that you have a CLK_I'EVENT conditional inside an RX'EVENT condition. That's just not synthesizable.
Assuming that CLK_I is much higher frequency than RX'EVENT, try sampling RX using CLK_I. If the previous value of RX is low and the current value is high, then synchronously reset clk_cnt on CLK_I'EVENT. Note that if RX is truly asynchronous to CLK_I you need to worry about metastability and you should add 2 flip-flops to synchronize RX before you look for a change from 0 to 1.
Try this code. There are still no flip flops in my code to solve metastability of RX as #Joe Hass explains.
But there is a scheme for synchronizing the RX signal.
PROCESS (CLK_I, RX)
BEGIN
IF (CLK_I'EVENT AND CLK_I = '1') THEN
IF (RX='1') THEN
clk_cnt <= to_unsigned(0,clk_cnt'LENGTH);
ELSE
IF clk_cnt >2499 THEN
clk_cnt <= to_unsigned(0,clk_cnt'LENGTH);
ELSE
clk_cnt <= clk_cnt + 1;
END IF;
END IF;
END IF;
END PROCESS;
Thank you very much for your support.
I modified the code as #Joe and #MortenZdk suggested. Now I am able to synthesize it.
I have to detect both posedge and negedge of "RX". So I changed the code as follows:
PROCESS(CLK_I) -- Stabilizing the RX signal to avoid meta stable state
begin
if rising_edge(CLK_I) then
rx_meta <= RX;
rx_sync <= rx_meta;
end if;
END PROCESS;
PROCESS (CLK_I)
BEGIN
IF (CLK_I'EVENT AND CLK_I = '1') THEN
tmp_RX <= rx_sync;
IF (rx_sync /= tmp_RX) THEN
clk_cnt <= to_unsigned(0,clk_cnt'LENGTH);
ELSE
IF clk_cnt >2499 THEN
clk_cnt <= to_unsigned(0,clk_cnt'LENGTH);
ELSE
clk_cnt <= clk_cnt + 1;
END IF;
END IF;
-- Clock generate as single cycle pulse
clk_rx <= '0';
IF clk_cnt = 1250 THEN
clk_rx <= '1';
END IF;
clk_tx <= '0';
IF clk_cnt = 2500 THEN
clk_tx <= '1';
END IF;
END IF;
END PROCESS;

VHDL edge detection

I want to detect the edges on the serial data signal (din). I have written the following code in VHDL which is running successfully but the edges are detected with one clock period delay i.e change output is generated with one clk_50mhz period delay at each edge. Could anyone please help me to detect edges without delay. Thank you.
process (clk_50mhz)
begin
if clk_50mhz'event and clk_50mhz = '1' then
if (rst = '0') then
shift_reg <= (others => '0');
else
shift_reg(1) <= shift_reg(0);
shift_reg(0) <= din;
end if;
end if;
end process;
process (clk_50mhz)
begin
if clk_50mhz'event and clk_50mhz = '1' then
if rst = '0' then
change <= '0' ;
elsif(clk_enable_2mhz = '1') then
change <= shift_reg(0) xor shift_reg(1);
end if ;
end if ;
end process ;
When I changed my code to following I am able to detect the edges
process (clk_50mhz)
begin
if clk_50mhz'event and clk_50mhz = '1' then
if (RST = '0') then
shift_reg <= (others=>'0');
else
shift_reg(1) <= shift_reg(0);
shift_reg(0) <= din;
end if;
end if;
end process;
change <= shift_reg(1) xor din;
Here you go
library ieee;
use ieee.std_logic_1164.all;
entity double_edge_detector is
port (
clk_50mhz : in std_logic;
rst : in std_logic;
din : in std_logic;
change : out std_logic
);
end double_edge_detector;
architecture bhv of double_edge_detector is
signal din_delayed1 :std_logic;
begin
process(clk_50mhz)
begin
if rising_edge(clk_50mhz) then
if rst = '1' then
din_delayed1 <= '0';
else
din_delayed1 <= din;
end if;
end if;
end process;
change <= (din_delayed1 xor din); --rising or falling edge (0 -> 1 xor 1 -> 0)
end bhv;
You have to use a combinatorial process to detect the difference without incurring extra clock cycle delays. (You will still need one register to delay the input as well.)
DELAY: process(clk_50mhz)
begin
if clk_50mhz'event and clk_50mhz = '1' then
din_reg <= din;
end if;
end process;
change <= din xor din_reg;

Resources