Time is only advanced when no more processes can be awakened by any event. If process "P" is awakened by its sensitivity list, it will execute in zero time and schedule signal assignments, and these assignments may awaken other processes. If at the next delta (which does not advance time) any process (including itself) affects P's sensitivity list, then P will be re-awakened. This happens as many times as necessary (or until the simulator gives up or the set maximum number of deltas have occurred).
In the particular example of your question with ABC = 101
, if you had:
process(A,B) begin
B <= not A;
C <= A xor B;
end process;
process(C) begin
end process;
When A
changes to 0
, BC
are scheduled with assignments of 10
. A delta passes, B
becomes 1
and re-awakens the process, which schedules C
back to 1
. At the end of this second delta the values are 011
, and there are no more events that could awaken the process, and when no other process can be awakened, time advances.
Consequently, process(A,B)
is awakened once when A
changes, and a second time when B
is changed. As a result, the "process awakening counter" counts twice.
In the case of process(C)
, it will also be awakened twice, because C
will "delta glitch" due to process(A,B)
.
However, if B
was implicit:
process(A) begin
C <= A xor (not A);
end process;
process(C) begin
end process;
Or if B
was a local variable:
process(A)
variable B : std_logic_vector;
begin
B := not A;
C <= A xor (not B);
end process;
process(C) begin
end process;
Then process(A) would only be awakened once, but process(C) would remain suspended.
You are performing a division and a multiplication operation on a signal. At least the multiplication is mapped to a hardware multiplication circuit on your FPGA.
Your module provides the generic parameter N, which could also be called PWM_RESOLUTION. Beside this, I miss two additional parameters or constants in your module:
- The clock frequency of the system clock
- The pwm output frequency [Notice: don't forget that pwm signals have a fixed frequency but variable duty cycle.]
One easy way to build a pwm generator is to use two counters:
- Counter 1 is a frequency divider, which divides the system clock into \$2^N \cdot f_{pwm}\$ Hz
- Counter 2 counts \$2^N\$ cycles on every tick from counter 1
Here some calculations for the frequency counter:
constant PWM_FREQ : freq := 25 kHz;
constant SYSTEM_CLOCK_FREQ : freq := 100 MHz;
constant STEPS : positive := 2**N;
constant STEP_FREQ : freq := PWM_FREQ * STEPS;
constant FREQ_COUNTER_MAX : positive := TimingToCycles(to_period(STEP_FREQ), SYSTEM_CLOCK_FREQ);
constant FREQ_COUNTER_BITS : positive := log2ceilnz(FREQ_COUNTER_MAX);
signal Freq_Counter : unsigned(FREQ_COUNTER_BITS - 1 downto 0) := (others => '0');
signal Pulse_Counter : unsigned(N - 1 downto 0) := (others => '0');
Some hints on the compact code above:
- freq is a new physical type representing a frequency - you can also use the real type
- to_period converty a frequency into a period (a time)
- TimingToCyles is a function which calculates how many cycles must pass until a given timing (period) has elapsed at a given circuit frequency.
- log2ceilnz (logarithm dualis, round up, not zero) calculates \$max(1, \lceil log_2(x)\rceil)\$
Example 1:
If N=4 the pwm signal can have 16 duty cycle steps. Counter 1 is running at 400 kHz. This equals a period of 2.5 us, which need 250 cycles at 100 MHz to achieve this timing. A 8 bit signal is needed for counter 1.
The output is then a simple comparison:
PWMOut <= to_sl(PulseCounters < unsigned(PWMIn));
This code does not prohibit the input of PWMIn=0 to produce a flat-line output, which would not be a correct pwm signal (100% low, 0% high, no edges -> no frequency)
Example 2:
If PWMIn is 3 ("0011") then PWMOut is '1' for counter values 0,1,2 else '0'.
Best Answer
The process sensitivity list is primarily a hint to a simulator. It only triggers an evaluation of (i.e., "activates") the process when an event occurs on any signal that's listed there.
It does NOT affect synthesis at all, to my knowledge. Synthesis is based entirely on the behavior described inside the process block.