I don't have experience with Quartus, so treat this as general advice.
When working on paths between clock domains, timing tools expand the clocks to the least common multiple of their periods and select the closest pair of edges.
For paths from a 36 MHz clock (27.777 ns) to a 100 MHz clock (10 ns), if I did my quick calculations correctly, the closest pair of rising edges is 138.888 ns on the source clock and 140 ns on the destination clock. That's effectively a 900 MHz constraint for those paths! Depending on rounding (or for clocks with no relationship), it could come out worse than that.
There are at least three ways to write constraints for this structure. I am going to call the clocks fast_clk
and slow_clk
as I think that's clearer for illustration.
Option 1: disable timing with set_false_path
The easiest solution is to use set_false_path
to disable timing between the clocks:
set_false_path -from [get_clocks fast_clk] -to [get_clocks slow_clk]
set_false_path -from [get_clocks slow_clk] -to [get_clocks fast_clk]
This is not strictly correct, since there are timing requirements for the synchronizer to work correctly. If the physical implementation delays the data too much relative to the control signal, then the synchronizer will not work. However, since there isn't any logic on the path, it's unlikely that the timing constraint will be violated. set_false_path
is commonly used for this kind of structure, even in ASICs, where the effort vs. risk tradeoff for low-probability failures is more cautious than for FPGAs.
Option 2: relax the constraint with set_multicycle_path
You can allow additional time for certain paths with set_multicycle_path
. It is more common to use multicycle paths with closely related clocks (e.g. interacting 1X and 2X clocks), but it will work here if the tool supports it sufficiently.
set_multicycle_path 2 -from [get_clocks slow_clk] -to [get_clocks fast_clk] -end -setup
set_multicycle_path 1 -from [get_clocks slow_clk] -to [get_clocks fast_clk] -end -hold
The default edge relationship for setup is single cycle, i.e. set_multicycle_path 1
. These commands allow one more cycle of the endpoint clock (-end
) for setup paths. The -hold
adjustment with a number one less than the setup constraint is almost always needed when setting multi cycle paths, for more see below.
To constrain paths in the other direction similarly (relaxing the constraint by one period of the faster clock), change -end
to -start
:
set_multicycle_path 2 -from [get_clocks fast_clk] -to [get_clocks slow_clk] -start -setup
set_multicycle_path 1 -from [get_clocks fast_clk] -to [get_clocks slow_clk] -start -hold
Option 3: specify requirement directly with set_max_delay
This is similar to the effect of set_multicycle_path
but saves having to think through the edge relationships and the effect on hold constraints.
set_max_delay 10 -from [get_clocks fast_clk] -to [get_clocks slow_clk]
set_max_delay 10 -from [get_clocks slow_clk] -to [get_clocks fast_clk]
You may want to pair this with set_min_delay
for hold checks, or leave the default hold check in place. You may also be able to do set_false_path -hold
to disable hold checks, if your tool supports it.
Gory details of edge selection for multi-cycle paths
To understand the hold adjustment that gets paired with each setup adjustment, consider this simple example with a 3:2 relationship. Each digit represents a rising clock edge:
1 2 3
4 5 6 7
The default setup check uses edges 2 and 6. The default hold check uses edges 1 and 4.
Applying a multi-cycle constraint of 2 with -end
adjusts the default setup and hold checks to use the next edge after what they were originally using, meaning the setup check now uses edges 2 and 7 and the hold check uses edges 1 and 5. For two clocks at the same frequency, this adjustment makes sense — each data launch corresponds with one data capture, and if the capture edge is moved out by one, the hold check should also move out by one. This kind of constraint might make sense for two branches of a single clock if one of the branches has a large delay. However, for the situation here, a hold check using edges 1 and 5 isn't desirable, since the only way to fix it is to add an entire clock cycle of delay on the path.
The multi-cycle hold constraint of 1 (for hold, the default is 0) adjusts the edge of the destination clock uesd for hold checks backwards by one edge. The combination of 2-cycle setup MCP and 1-cycle hold MCP constraints will result in a setup check using edges 2 and 7, and a hold check using edges 1 and 4.
Your code is not quite right.
If you want to set something to a value, you need to create a register and set it accordingly, then assign the value to an output. Generally you cannot use initial
statements for synthesis (check your documentation) so setting the register to a constant on a reset signal, or using a ROM block are options.
Let's say you want to flash the LEDs though, this is more exciting than just turning them on. Say we have a 16MHz clock, to slow the clock down so the LEDs flash visibly, we need to divide it down. If we pick a 24 bit count register, 16e6 / (2^24) = ~1Hz so LEDs will update once per second.
module fpga(
input clk,
output LEDG[7:0);
// output reg to set
reg rOUT[7:0]
// counter reg to slow clock down
reg rCOUNT[24:0]
// this models the synchronous logic, the block is activated on each positive edge of clk
always(@ posedge clk)
begin
// add one to rCOUNT on each clock positive edge
rCOUNT <= rCOUNT + 1;
// if rCOUNT equals 0xFFFFFF then increment rOUT by 1
if(rCOUNT == 24'hFFFFFF)
begin
rOUT <= rOUT + 1;
end
end
assign value of rOUT to LEDG so LEDs will light according to rOUTs current value
assign LEDG = rOUT;
endmodule
Note that when assigning a value to a register, you need to specify the width otherwise it will default to the default width of the system (e.g. 32 bits)
So if you create an 8 bit register rOUT
and you want to set it to all 1's, then assuming your sythesis software allows assigning an intitial value you would write reg rOUT = 8'b11111111;
or reg rOUT = 8'hFF;
This will all become clear as you read more.
About the Quartus pin planner, I'm not sure (as I use Xilinx/Actel FPGAs), but make sure the pin assignments are correct. YOu should be able to either change them in the pin planner or manually edit the constraints file as necessary. It will all be there in the (no doubt very lengthy) documentation.
A good book is "FPGA Prototyping by Verilog Examples" (Pong P Chu), but there are some examples out there you can follow - fpga4fun is a good site with many example projects. Spend some time reading and getting to know the constructs of the language. Try stuff out in the simulator first to confirm correct operation before programming FPGA.
Best Answer
Run design assistant and try to optimize design for speed if Your timing constrains doesn't help You to reach the required times. What frequency do You need and how much do You get? What's the worst path? Give us more information.
What You can do is to optimize all combinatorial logic plus always remember to add several pipeline stages if possible. You can also half the internal clock and transfer required data DDR internally. Tell us more about Your application and critical paths, it would be easier to help You. E.g. I recently had a problem to meet timing of MII/GMII mux for Gig-E.