I understand the usual textbook difference between signal and variable in VHDL:
variable :=updates immediately inside a processsignal <=updates after a delta cyclevariables are local, signals are global
However, I am confused about how this maps to actual FPGA hardware after synthesis and implementation.
My Lead engineer told me:
“In hardware, variable and signal are the same.
Both appear one clock later because hardware uses flip-flops.
So using a variable for edge detection is wrong.”
I want to check if that is actually true.
Context: SPI master with internal SCLK and edge detection
I have an SPI master where I generate an internal SCLK (from a system clock) and detect its edges using variables inside a single clocked process.
Here is a trimmed version of the real code:
⚙ Example code
Inside a clocked process:
process (CLK, RSTB)
-- edge detection variables
variable prev_sclk_v : std_logic := '0';
variable next_sclk_v : std_logic;
variable sclk_rise_v : std_logic;
variable sclk_fall_v : std_logic;
begin
if RSTB = '0' then
sclk_r <= '0';
sclk_div_cnt <= 0;
prev_sclk_v := '0';
...
elsif rising_edge(CLK) then
done_r <= '0';
sclk_rise_v := '0';
sclk_fall_v := '0';
-- SCLK next value (divider logic, 40MHz -> 10MHz)
next_sclk_v := sclk_r;
if busy_r = '1' then
if sclk_div_cnt = 1 then
sclk_div_cnt <= 0;
next_sclk_v := not sclk_r;
else
sclk_div_cnt <= sclk_div_cnt + 1;
end if;
else
sclk_div_cnt <= 0;
next_sclk_v := '0'; -- idle: SCLK low (mode 0)
end if;
-- edge detection using variables (same-cycle valid)
if (prev_sclk_v = '0' and next_sclk_v = '1') then
sclk_rise_v := '1';
elsif (prev_sclk_v = '1' and next_sclk_v = '0') then
sclk_fall_v := '1';
end if;
-- store for next cycle
prev_sclk_v := next_sclk_v;
sclk_r <= next_sclk_v;
-- FSM example: use edge flags in the same clock
case state_r is
when send_header =>
if sclk_fall_v = '1' then
-- shift MSB first, etc...
end if;
when receive_byte_a =>
if sclk_rise_v = '1' then
-- sample SDIO on SCLK rising edge
end if;
...
end case;
end if;
end process;
My understanding of how these map to hardware
From a hardware point of view, my interpretation is:
sclk_ris a signal assigned in a clocked process ⇒ it is a flip-flop (registered SCLK).prev_sclk_vis a variable, but its value is carried from cycle to cycle via
prev_sclk_v := next_sclk_v;
⇒ this infers a flip-flop as well (state).next_sclk_vis a variable used only to compute “next SCLK” in the current clock cycle and then assigned tosclk_r.
It does not hold state by itself ⇒ synthesized as pure combinational logic feeding the D input ofsclk_r.sclk_rise_v/sclk_fall_vare variables used only within this one clock cycle as edge-detect flags.
They are not stored into a signal or reused in the next cycle ⇒ they should be synthesized as pure combinational signals (no flip-flops).
What another engineer told me
Another engineer told me essentially:
“In hardware, variable and signal are the same.
Everything is driven by flip-flops, so both are effectively one-clock delayed.
A variable ‘still depends on flip-flops’ so your variable-based edge detection is conceptually wrong.”
This conflicts with my understanding that:
- Whether something becomes a register or not is not about “variable vs signal”,
but about whether its value needs to be preserved across clock cycles.
My actual questions
My actual questions
From a real FPGA synthesis/implementation perspective (not just simulation semantics):
1) Is this statement correct?
A variable only infers a flip-flop if its value must be preserved across clock cycles
(for example, if it feeds itself or is stored into a registered signal).If a variable is used only as an intermediate value within a single clock cycle and
its value is not needed in the next cycle, it is synthesized as pure combinational logic,
not a register.
2) In my specific code, is the following mapping accurate?
prev_sclk_v→ variable, but used as state across cycles ⇒ register (FF)sclk_r→ signal assigned in a clocked process ⇒ register (FF)next_sclk_v,sclk_rise_v,sclk_fall_v→ used only within this cycle ⇒ combinational (no FF)
3) Is the following summary accurate?
“variable vs signal” is not the true hardware distinction;
the real distinction is combinational vs sequential (state).A variable becomes a register only if it represents state across cycles;
otherwise it is purely combinational.A signal assigned in a clocked process is typically used to hold state (flip-flops).
4) If my understanding is correct, what would be the proper way to explain this to an engineer who claims that “variables and signals behave the same in hardware and both update next clock anyway”?
I want to explain clearly—based on actual synthesis behavior—why edge-detect flags implemented as variables are combinational in this context, while converting them to signals would introduce a one-cycle delay.
If any part of this reasoning is incorrect, I’d really appreciate a detailed correction.
I want to be sure I understand not just simulation behavior, but the actual synthesized hardware differences between variables and signals in this kind of design.