In Xilinx ISE (using VHDL language), I have defined these signals:
signal counter : integer range 0 to 24_000_000;
signal chTriger : std_logic :='0';
and have written the following code:
process_counter: process(clk)
begin
if ( clk'event and clk = '1') then
if (counter < 8192) then
counter <= counter + 1;
chTriger <= not chTriger;
end if;
end if;
end process process_counter;`
In ChipScope's select net menu, there is neither a counter nor chTriger signal due to optimization.
How can I force ISE synthesis tool to synthesize a signal?
Read through the Xilinx constraints guide here
especially the synthesis constraints.
There is one which is called "KEEP".
In general it is a very useful document to browse if only so you have an idea what you can (and can't do).
Output chTriger to an external pin on the FPGA. Then it can't be optimized away.
And since chTriger depends on counter, then counter won't be optimized away either.
Related
I have the following code (a primitive "RS-232 signalling" transmitter)...
LIBRARY ieee;
USE ieee.std_logic_1164.all;
entity SerialTX is
port(
baud_clk : in std_logic;
data : in std_logic_vector(7 downto 0);
send : in std_logic;
serial_out : out std_logic := '0';
busy : out std_logic := '0'
);
end entity;
----------------------------------------
architecture behavioural of SerialTX is
constant IDLE_BITS : std_logic_vector(10 downto 0) := "00000000001";
signal shifter : std_logic_vector(10 downto 0) := IDLE_BITS;
signal shift : std_logic := '0';
signal internal_busy : std_logic := '0';
begin
-------- ALWAYS HAPPENING --------
serial_out <= shifter(0);
busy <= internal_busy;
internal_busy <= '1' when (shifter /= IDLE_BITS) else '0';
----------------------------------
shifting_handler:
process(baud_clk) is
begin
if rising_edge(baud_clk) then
if (send = '1') and (shifter = IDLE_BITS) then
shifter <= "11" & data & '0';
elsif (shifter /= IDLE_BITS) then
shifter <= '0' & shifter(10 downto 1); -- shifter >>= 1;
end if;
end if;
end process;
end architecture behavioural;
... it works well (in simulation) but has a limitation. The send signal (that causes a transmission to begin) has to be a '1' level for longer than at least one full cycle of the baud_clk in order for the transmitter to see it reliably.
I have been trying to find a way to convert this code so that it responds to the rising edge of the send signal instead of testing its level at the rising edge of baud_clk. I want to be able to respond to a send pulse less than 100ns in duration even when the baud_clk is running at a much slower rate (115200 hz for instance).
I've tried (naively) altering the process thus...
shifting_handler:
process(baud_clk) is
begin
if rising_edge(baud_clk) then
if (shifter /= IDLE_BITS) then
shifter <= '0' & shifter(10 downto 1); -- shifter >>= 1;
end if;
elsif rising_edge(send) and (shifter = IDLE_BITS) then
shifter <= "11" & data & '0';
end if;
end process;
Here I was hoping to change the logic to test for a rising edge on send when there isn't a rising edge on baud_clk.
I know that this is not a valid approach to the problem (the synthesizer moans of course) but I was hoping that someone could explain in simple terms why this cannot be done. What would happen if it was possible to use two edge detectors in a process? There is a concept here I cannot grasp and I always seem to end up writing the code in the same way and producing this problem. I'm fighting hard against years of ingrained software programming habits, which doesn't help much!
It sounds like send is asynchronous with respect to baud_clk. You therefore need to perform some form of clock domain crossing (CDC) in order to correctly implement your design, otherwise you will have a design that cannot pass timing and has the potential to not function correctly. CDC is a standard term that you should be able to find more information about in other questions, and elsewhere.
As you have found, you cannot have a design realised in real hardware if it has a process sensitive to edges on two different signals. There's no one 'right' way to do what you want, but here is one example that uses a simple 'toggle' CDC. This is very simple, but note that the design could miss sending a byte if one send request arrives before a previous byte has been transmitted. There will also be some delay introduced between assertion of the send signal, and the transmission starting. It's not clear if these issues matter in your system.
Create another process sensitive to send:
-- The initial state doesn't matter, but we want the design to work in simulation
signal send_toggle : std_logic := '0';
process(send)
begin
if (rising_edge(send)) then
send_toggle <= not send_toggle;
end if;
end process;
Now another process to synchronize this to the baud_clk domain. Use two cascaded registers to produce a design that is largely immune to any metastability (this is another standard term that you can look up) that can result from sampling a signal generated from a different clock domain:
signal send_toggle_r1 : std_logic;
signal send_toggle_r2 : std_logic;
process(baud_clk)
begin
if (rising_edge(baud_clk)) then
send_toggle_r1 <= send_toggle;
send_toggle_r2 <= send_toggle_r1;
end if;
end process;
The above is a very standard circuit block that you can use in many single-bit CDC scenarios.
Your transmit process can then register the send_toggle_r2 signal in order to look for a transition, in order to determine whether it should start sending. This signal is in the correct clock domain:
signal send_toggle_r3 : std_logic;
process(baud_clk) is
begin
if rising_edge(baud_clk) then
send_toggle_r3 <= send_toggle_r2;
if ((send_toggle_r3 /= send_toggle_r2) and (shifter = IDLE_BITS)) then
shifter <= "11" & data & '0';
elsif (shifter /= IDLE_BITS) then
shifter <= '0' & shifter(10 downto 1); -- shifter >>= 1;
end if;
end if;
end process;
Lastly, you will need to implement timing constraints to tell your tool chain not to worry about timing of the send_toggle_r1 register.
You might spot that if you are targeting hardware where the initial states of registers are random, you might get an erroneous byte transmission after the first few baud_clk cycles. To prevent this, you might choose to hold your baud_clk process in reset for some clock cycles after start up, but as I don't know if this is relevant for you, I won't detail this part.
This whole answer addresses your question directly, but my personal approach would be to use whatever higher-rate clock is generating your send signal to drive the entire design. The serial transmission would then in fact use the higher rate clock, with shifting enabled by a CDC > edge detector chain driven from the baud_clk. The bit timing would not be absolutely perfect, but this should not matter for a standard 'UART' scenario.
I am designing a parking-lot gate in VHDL. When I simulate it using Quartus VWF files, I am getting unknown values (X), but I don't know why.
Basically you just have to validate your card (Sin) and the gate opens for 10 seconds.
And when a car exits the parking lot (Sout), it counts the total cars at the moment inside of the parking lot.
I have created the signal Ncarros (to count number of cars) and s_count for the timer.
It all compiles correctly. But when I'm testing it using a VWF file, this is what I get:
Original simulation output
I'm using Altera Quartus Prime Lite Edition.
Can someone check my code and tell me what I'm doing wrong?
library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.NUMERIC_STD.all;
entity MicroProj is
port (clk : in std_logic;
Sin : in std_logic;
Sout : in std_logic;
cancela : out std_logic;
timerOut : out std_logic);
end MicroProj;
architecture Behavioral of MicroProj is
signal Ncarros : integer := 0;
signal s_count : integer := 0;
begin
process (Sin,Sout,clk)
begin
if (Sin = '0') then
cancela <= '0';
else
if (Ncarros < 99) then
Ncarros <= Ncarros + 1;
cancela <= '1';
if(rising_edge(clk)) then
if(s_count /= 0) then
if(s_count = 499999999) then
timerOut <= '1';
s_count <= 0;
else
timerOut <= '0';
s_count <= s_count + 1;
end if;
else
timerOut <= '0';
s_count <= s_count + 1;
end if;
end if;
end if;
end if;
if (Sout ='1') then
Ncarros <= Ncarros - 1;
end if;
end process;
end Behavioral;
When you simulate with a Vector Waveform File (VWF), Quartus-II actually simulates the behaviour of the synthesized netlist (checked here with Quartus-II 13.1). If you haven't run the step "Analysis & Synthesis", Quartus asks to do so. You have to always run this step manually, when you change your VHDL files before simulating the VWF again. The synthesized netlist is written out as Verilog code which will be the input of the ModelSim simulator. You can find it in the file simulation/qsim/microproj.vo.
As long as Quartus reports warnings (or errors), the behavior of the synthesized design can differ from the VHDL description. And this is the case here as pointed out below. To directly simulate the behavior of your VHDL description, you have to write a testbench.
The following testbench will be a good starter. It assign the same input values as in your VWF file for the first 200 ns. You will have to extend the code at the indicated location to add more signal transitions.
library ieee;
use ieee.std_logic_1164.all;
entity microproj_tb is
end entity microproj_tb;
architecture sim of microproj_tb is
-- component ports
signal clk : std_logic := '0';
signal Sin : std_logic;
signal Sout : std_logic;
signal cancela : std_logic;
signal timerOut : std_logic;
begin -- architecture sim
-- component instantiation
DUT: entity work.microproj
port map (
clk => clk,
Sin => Sin,
Sout => Sout,
cancela => cancela,
timerOut => timerOut);
-- clock generation
clk <= not clk after 10 ns;
-- waveform generation
WaveGen : process
begin
Sin <= '0';
Sout <= '0';
wait for 40 ns; -- simulation time = 40 ns
Sin <= '1';
wait for 70 ns; -- simulation time = 110 ns
Sin <= '0';
wait for 50 ns; -- simulation time = 160 ns
Sin <= '1';
-- Extend here to add more signal transistions
wait;
end process WaveGen;
end architecture sim;
The Quartus Prime Lite Edition includes an installation of the ModelSim Altera Edition. You can setup and start the simulation using ModelSim directly within the Quartus project settings. The simulation output for the first 200 ns using my testbench is as follows:
As you see, the output differs from your simulation of the VWF file because the VHDL design itself is simulated now.
In your VHDL code you described latches for the signals cancela and Ncarros as also reported by the "Analysis & Synthesis" step:
Warning (10492): VHDL Process Statement warning at MicroProj.vhdl(26): signal "Ncarros" is read inside the Process Statement but isn't in the Process Statement's sensitivity list
Warning (10492): VHDL Process Statement warning at MicroProj.vhdl(27): signal "Ncarros" is read inside the Process Statement but isn't in the Process Statement's sensitivity list
Warning (10492): VHDL Process Statement warning at MicroProj.vhdl(48): signal "Ncarros" is read inside the Process Statement but isn't in the Process Statement's sensitivity list
Warning (10631): VHDL Process Statement warning at MicroProj.vhdl(21): inferring latch(es) for signal or variable "cancela", which holds its previous value in one or more paths through the process
Warning (10631): VHDL Process Statement warning at MicroProj.vhdl(21): inferring latch(es) for signal or variable "Ncarros", which holds its previous value in one or more paths through the process
Info (10041): Inferred latch for "Ncarros[0]" at MicroProj.vhdl(20)
Info (10041): Inferred latch for "Ncarros[1]" at MicroProj.vhdl(20)
Info (10041): Inferred latch for "Ncarros[2]" at MicroProj.vhdl(20)
...
Info (10041): Inferred latch for "Ncarros[31]" at MicroProj.vhdl(20)
Info (10041): Inferred latch for "cancela" at MicroProj.vhdl(20)
On Altera FPGAs, latches are implemented using the look-up table (LUT) and a combinational feedback path within the logic element (LE). The state of such a latch is undefined after programming the FPGA. The simulation of the synthesized netlist shows this as 'X'es.
I recommend to fix the latches anyway and transform your code into a fullly synchronous, clock-edge driven design. That is, assign new values to cancela and Ncarros only at the rising edge of the clock. The VHDL code pattern is:
process(clk)
begin
if rising_edge(clk) then
-- put all your assignments to cancela and Ncarros here
end if;
end process;
I have the below code in VHDL that I use in a project. I have been using a Process within the architecture and wanted to know if there were any other means which I'm sure there are of accomplishing the same goal.. in essence to take one number compare it to another and if there is a difference of +/- 2 reflect this in the output. I am using the following:
LIBRARY IEEE;
USE IEEE.std_logic_1164.all, IEEE.std_logic_arith.all, IEEE.std_logic_signed;
ENTITY thermo IS
PORT (
CLK : in std_logic;
Tset, Tact : in std_logic_vector (6 DOWNTO 0);
Heaton : out std_logic
);
END ENTITY thermo;
ARCHITECTURE behavioral OF thermo IS
SIGNAL TsetINT, TactINT : integer RANGE 63 Downto -64; --INT range so no 32bit usage
BEGIN
Heat_on_off: PROCESS
VARIABLE ONOFF: std_logic;
BEGIN
TsetINT <= conv_integer (signed (Tset));--converts vector to Int
TactINT <= conv_integer (signed (Tact));--converts vector to Int
--If you read this why is it conv_integer not to_integer?? thx
ONOFF := '0'; --so variable does not hang on start
WAIT UNTIL CLK'EVENT and CLK = '1';
IF TactINT <= (TsetINT - 2) then
ONOFF := '1';
ELSIF TactINT >= (TsetINT + 2) then
ONOFF := '0';
END IF;
Heaton <= ONOFF;
END PROCESS;
END ARCHITECTURE behavioral;
I'm just after a comparison really and to know if there are any better ways of doing what I have already done.
Why convert Tact and Tset to an integer?
Why have the variable ONOFF? The variable initialization appears to remove any sense of hysteresis, is that what you intended? Based on your other code, I bet not. I recommend that you assign directly to the signal Heaton instead of using the variable ONOFF.
If I were to create TsetINT and TactINt, these would be good candidates to be variables. However, there is no need to do the integer conversion as you can simply do the following:
if signed(Tact) <= signed(Tset) - 2 then
...
elsif signed(Tact) >= signed(Tset) + 2 then
Please use numeric_std. Please ask your professor why they are teaching you old methodologies that are not current industry practice. Numeric_std is an IEEE standard and is updated with the standard, std_logic_arith is not an IEEE standard.
use ieee.numeric_std.all ;
In response to Jim's comment I wrote a simple thermal model test bench to test your design.
I only changed your design to use package numeric_std instead of the Synopsys packages. The rest is just prettifying and eliminating comments not germane to the question of whether or not Tact ever reaches Tset.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity thermo is
port (
CLK: in std_logic;
Tset, Tact: in std_logic_vector (6 downto 0);
Heaton: out std_logic
);
end entity thermo;
architecture behavioral of thermo is
signal TsetINT, TactINT: integer range 63 downto -64;
begin
HEAT_ON_OFF:
process
variable ONOFF: std_logic;
begin
TsetINT <= to_integer (signed (Tset)); -- package numeric_std
TactINT <= to_integer (signed (Tact)); -- instead of conv_integer
ONOFF := '0'; -- AT ISSUE -- so variable does not hang on start
wait until CLK'event and CLK = '1';
if TactINT <= TsetINT - 2 then -- operator precedence needs no parens
ONOFF := '1';
elsif TactINT >= TsetINT + 2 then
ONOFF := '0';
end if;
Heaton <= ONOFF;
end process;
end architecture behavioral;
You have a comment in your process asking why conv_integer was required instead of to_integer. That prompted the change.
I removed superfluous parentheses based on operator order precedence (adding operators being higher precedence than relational operators), notice Jim's answer did the same.
So the simple model thermal model runs with a clock set to a 1 second period, and has two coefficients, relating to the temperature increase when Heaton is '1' or not. I arbitrarily set the heating up coefficient to 1 every 4 clocks, and the temperature decay coefficient to 1 every 10 clocks. Also set the ambient temperature (tout) to 10 and tset to 22. The numbers selected are severe to keep the model run time short enhancing portability without relying on setting a simulator resolution limit.
The thermal model was implemented using fixed signed arithmetic without using fixed_generic_pkg, allowing portability to -1993 tools without math packages and includes a fractional part, responsible for the different widths of Heaton true after reaching normal operating temperature. The model could just as easily have been implemented with two different precursor counters used to tell when to increment or decrement Tact.
Using REAL types is possible, not desirable because converting REAL to INTEGER (then to SIGNED) isn't portable (IEEE Std 1076-2008 Annex D).
The idea here is to demonstrate the lack of hysteresis and demonstrate the model doesn't reach Tset:
The lack of hitting Tset (22 + 2) is based on the lack of hysteresis. Hysteresis is desirable for reducing the number of heat on and off cycles The idea is once you start the heater you leave in on for a while, and once you stop it you want to leave it off for a while too.
Using Jim's modification:
-- signal TsetINT, TactINT: integer range 63 downto -64;
begin
HEAT_ON_OFF:
process (CLK)
begin
if rising_edge(CLK) then
if signed(Tact) <= signed(Tset) - 2 then
Heaton <= '1';
elsif signed(Tact) >= signed(Tset) + 2 then
Heaton <= '0';
end if;
end if;
end process;
gives us longer Heaton on and off cycles, decreasing how many times the heater starts and stops:
And actually allows us to see the temperature reach Tset + 2 as well as Tset - 2. where these thresholds provide the hysteresis which is characterized as a minimum on or minimum off time, depending on the efficiency of the heater and heat loss rate when the heater is off.
So what changed in the execution of the thermo model process? Look at the difference in the synthesis results for the two versions.
I want to take samples of digital data coming externaly to FPGA spartan 3.
I want to take 1000 samples/sec initially. How to select a clock frequency in vhdl coding?
Thanks.
Do not use a counter to generate a lower frequency clock signal.
Multiple clock frequencies in an FPGA cause a variety of design problems, some of which come under the heading of "advanced topics" and, while they can (if necessary) all be dealt with and solved, learning how to use a single fast clock is both simpler and generally better practice (synchronous design).
Instead, use whatever fast clock your FPGA board provides, and generate lower frequency timing signals from it, and - crucially - use them as clock enables, not clock signals.
DLLs, DCMs, PLLs and other clock managers do have their uses, but generating 1 kHz clock signals is generally not a good use, even if their limitations permit it. This application is just crying out for a clock enable...
Also, don't mess around with magic numbers, let the VHDL compiler do the work! I have put the timing requirements in a package, so you can share them with the testbench and anything else that needs to use them.
package timing is
-- Change the first two constants to match your system requirements...
constant Clock_Freq : real := 40.0E6;
constant Sample_Rate : real := 1000.0;
-- These are calculated from the above, so stay correct when you make changes
constant Divide : natural := natural(Clock_Freq / Sample_Rate);
-- sometimes you also need a period, e.g. in a testbench.
constant clock_period : time := 1 sec / Clock_Freq;
end package timing;
And we can write the sampler as follows:
(I have split the clock enable out into a separate process to clarify the use of clock enables, but the two processes could be easily rolled into one for some further simplification; the "sample" signal would then be unnecessary)
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.numeric_std.all;
use work.timing.all;
entity sampler is
Port (
Clock : in std_logic;
Reset : in std_logic;
ADC_In : in signed(7 downto 0);
-- signed for audio, or unsigned, depending on your app
Sampled : out signed(7 downto 0);
);
end sampler;
architecture Behavioral of Sampler is
signal Sample : std_logic;
begin
Gen_Sample : process (Clock,Reset)
variable Count : natural;
begin
if reset = '1' then
Sample <= '0';
Count := 0;
elsif rising_edge(Clock) then
Sample <= '0';
Count := Count + 1;
if Count = Divide then
Sample <= '1';
Count := 0;
end if;
end if;
end process;
Sample_Data : process (Clock)
begin
if rising_edge(Clock) then
if Sample = '1' then
Sampled <= ADC_In;
end if;
end if;
end process;
end Behavioral;
The base clock must be based on an external clock, and can't be generated just through internal resources in a Spartan-3 FPGA. If required, you can use the Spartan-3 FPGA Digital Clock Manager (DCM) resources to scale the external clock. Synthesized VHDL code in itself can't generate a clock.
Once you have some base clock at a higher frequency, for example 100 MHz, you can easily divide this down to generate an indication at 1 kHz for sampling of the external input.
It depends on what clock frequency you have available. If you have a 20MHz clock source, you need to divided it by 20000 in order to get 1KHz, you can do it in VHDL or use a DCM to do this.
This is from an example on how to create a 1kHz clock from a 20MHz input:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity clk20Hz is
Port (
clk_in : in STD_LOGIC;
reset : in STD_LOGIC;
clk_out: out STD_LOGIC
);
end clk200Hz;
architecture Behavioral of clk20Hz is
signal temporal: STD_LOGIC;
signal counter : integer range 0 to 10000 := 0;
begin
frequency_divider: process (reset, clk_in) begin
if (reset = '1') then
temporal <= '0';
counter <= 0;
elsif rising_edge(clk_in) then
if (counter = 10000) then
temporal <= NOT(temporal);
counter <= 0;
else
counter <= counter + 1;
end if;
end if;
end process;
clk_out <= temporal;
end Behavioral;
I am writing a RS232 module for my Nexys2 board. I am currently having issues with my baud rate controller which I want to set to 19200.
For this I am using a Mod-M counter, after many ISim simulations the problem with my code is in the mod-m counter as it is not producing any ticks.
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 baud_rate is
generic (
N: integer := 8;
M: integer :=163);
Port (clk, reset : in STD_LOGIC;
tick : out STD_LOGIC;
q : out STD_LOGIC_VECTOR(N-1 downto 0));
end baud_rate;
architecture Behavioral of baud_rate is
signal r_reg : unsigned(N-1 downto 0);
signal r_next : unsigned(N-1 downto 0);
begin
process(clk,reset)
begin
if (reset ='1') then
r_reg <= (others=>'0');
elsif(clk'event and clk='1') then
r_reg <= r_next;
end if;
end process;
r_next <= (others =>'0') when r_reg=(M-1) else r_reg+1;
tick <='1' when r_reg=(M-1) else '0';
q <= std_logic_vector(r_reg);
end Behavioral;
I have tested and all the clk inputs and run fine and the issue seems to be with the r_reg and r_next registers. In ISim when outputing either of these on q I get UUUUUUUU, so it seems they are not generating signal. From this i can infer that the two r_reg and r_next registers aren't being created or storing values, is there an issue when using unsigned?
To make triple sure I have even copied the mod-m counter from the book FPGA Prototyping with VHDL (which is the code shown) BUT still this does not work and q output is UUUUUUUU.
If there are any better ways of creating a baud rate from the nexys2 50mz clock that would also be appreciated!
Cheers
Frankly I am horrified if people are expected to learn VHDL from a book where examples like this are presented. I know the author has a similar book on Verilog : do people end up thinking VHDL is just a more verbose Verilog?
Specific criticisms (actually 7,8 are more observations):
1) Spurious type conversions.
Q represents an unsigned number. So make it unsigned!
The baud generator isn't the only thing in your FPGA so Q isn't likely to be an off-chip port. There are good arguments for making top level, off-chip ports std_logic_vector but even that isn't compulsory. However, if your customer's specification or coding style insists on spurious type conversions on ports; follow it.
2) the DRY principle:
package CPU_types is
subtype baud_count is unsigned(7 downto 0);
end CPU_types;
Spot the simplification in maintenance.
If you are using a subtype in several places, put it in a package; the universal code reuse tool.
3) Indentation, formatting. (I recognise that may have become garbled by editor settings). It adds to the brain load reading it. What I've done here isn't The One Way though.
4) Spurious brackets round logical expressions. Harmless, but look like crutches for C programmers.
5) Antique clk'event style. Next year, the rising_edge function will be old enough to drink (in America. In Britain it's been getting plastered every Saturday night for a couple of years now...)
6) The "two process" style with r_reg and r_next. Does he also write state machines with a separate combinational process on next_state? Given this, I'm guessing so. Single process state machines are easier, smaller (to write : they don't generate smaller hardware) and safer.
7) I cheated and my tick is one cycle later than in the original. If that is critical, restore the external "tick" assignment. I also made it synchronous vhich will help performance. Some people would prefer tick <= '0' in an else clause; however the default assignment I used is safe, and prevents a lot of mistakes (and unnecessary else clauses) in larger designs.
8) The assignment to Q can be brought into the process too; if you made r_reg a process variable you'd have to. There is room for other variations and preferences.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
use CPU_types.all;
entity baud_rate is
generic (
M: integer := 163);
Port (
clk, reset : in STD_LOGIC;
tick : out STD_LOGIC;
q : out baud_count);
end baud_rate;
architecture Behavioral of baud_rate is
signal r_reg : baud_count;
begin
process(clk,reset)
begin
if reset ='1' then
r_reg <= (others=>'0');
elsif rising_edge(clk) then
tick <= 0;
r_reg <= r_reg+1;
if r_reg = M then
tick <= '1';
r_reg <= (others=>'0');
end if;
end if;
end process;
-- tick <='1' when r_reg = M-1 else '0';
-- or simpler, when r_reg = 0
q <= r_reg;
end Behavioral;