Could someone explain inexperienced VHDL coder what this error message trying to tell me in simple words? I found a similar question here, but here was no answer to it:
ERROR:Place:1108 - A clock IOB / BUFGMUX clock component pair have been found
that are not placed at an optimal clock IOB / BUFGMUX site pair. The clock
IOB component is placed at site . The corresponding BUFG component
is placed at site . There is only a select set
of IOBs that can use the fast path to the Clocker buffer, and they are not
being used. You may want to analyze why this problem exists and correct it.
If this sub optimal condition is acceptable for this design, you may use the
CLOCK_DEDICATED_ROUTE constraint in the .ucf file to demote this message to a
WARNING and allow your design to continue. However, the use of this override
is highly discouraged as it may lead to very poor timing results. It is
recommended that this error condition be corrected in the design. A list of
all the COMP.PINs used in this clock placement rule is listed below. These
examples can be used directly in the .ucf file to override this clock rule.
< NET "HREF" CLOCK_DEDICATED_ROUTE = FALSE; >
ERROR:Pack:1654 - The timing-driven placement phase encountered an error.
I just want to use external HREF signal as the trigger to count lines and for some other things. Is there a better way to configure logic? Here's what I have:
ENTITY mainModule IS
PORT(
CLK160 : IN STD_LOGIC;
BUFOUT : OUT STD_LOGIC_VECTOR (11 DOWNTO 0) := (OTHERS => '0');
RESET_B : OUT STD_LOGIC := '1';
HREF : IN STD_LOGIC;
DATA_IM : IN STD_LOGIC_VECTOR (9 DOWNTO 0);
PCLK : IN STD_LOGIC;
XVCLK : OUT STD_LOGIC := '0');
END mainModule;
ARCHITECTURE BEHAVIORAL OF mainModule IS
SIGNAL CLK10 : STD_LOGIC := '0';
SIGNAL SKIP : STD_LOGIC := '0';
SIGNAL LineCounter : UNSIGNED(9 DOWNTO 0) := (OTHERS => '0');
component CLK_DIV16 is port (CLKIN : in STD_LOGIC; CLKDV : out STD_LOGIC );end component;
BEGIN
U1: CLK_DIV16 port map(CLKIN => CLK160,CLKDV => CLK10);
OUT_TEST: PROCESS(PCLK)
BEGIN
IF RISING_EDGE(PCLK) THEN
BUFOUT(9 DOWNTO 0) <= DATA_IM(9 DOWNTO 0);
ELSE NULL;
END IF;
END PROCESS OUT_TEST;
LINECOUNT: PROCESS (HREF)
BEGIN
IF RISING_EDGE(HREF) THEN
IF LineCounter > 488 THEN
LineCounter <= (OTHERS => '0');
SKIP <= NOT SKIP;
ELSE LineCounter <= LineCounter + 1;
END IF;
ELSE NULL;
END IF;
END PROCESS LINECOUNT;
BUFOUT(11) <= PCLK AND HREF AND SKIP;
XVCLK <= CLK10;
END Behavioral;
I assume from the presense of IOB
and BUFGMUX
and .UCF that this must be a Xilinx FPGA. Note that as I work in the industry I use Verilog, but I think I can more or less follow what's going on in the VHDL code.
Background: what is this Global Clock Distribution
Clock signals are special because they need to arrive at all of the flip-flops throughout the entire FPGA chip at exactly the same time. Here I mean routing in the actual silicon and metal of the FPGA chip, not routing in the sense of configurable logic. These are hard, metal, permanent routes. The only configurable part about these global clock routes is which external clock pin supplies the clock signal and which flip-flops listen to this clock. If the clock distribution was not carefully routed by the FPGA manufacturer, then the flip-flops that are closer to the clock pin would capture their inputs sooner than flip-flops that are placed farther away -- and the design would no longer be synchronous logic. So to make the FPGA support the use of synchronous logic throughout the entire chip, there are some special global clock
routes that are dedicated to distributing a clock signal from one of the dedicated clock inputs, to every flip-flop on the entire FPGA, such that the clock edge arrives at exactly the same time at each flip-flop. (Even if your design doesn't configure the flip-flop to connect to that clock, the FPGA silicon still has to contain the route. FPGA configuration can only enable routes that are already built into the chip.)
These global clock routes are "expensive" because each one spans an entire layer of the FPGA chip, so typically there are very few of these routes on the chip. This is OK because clocking is a one-to-many relationship (one clock driving many flip-flops), most designs use only 1 or 2 clocks anyway. And, typical HDL designs use recognizable synchronous logic constructs, like state machines. The HDL compiler can recognize a state machine or a bunch of flip-flops that share the same clock domain.
What the error message means
Xilinx requires the use of some special primitive constructs in their RTL code to route a clock signal onto these global clock routes, this is the BUFG
(global clock buffer) or BUFGMUX
(global clock multiplexer) that the error message references. IOB
is a generic input/output buffer associated with a pin. And -- there are only a few special dedicated clock input pins (IOB
) that can drive any of the global clock distribution systems (BUFGMUX
). So the error message is telling you that you can't use that pin (that the HREF
is assigned to) as a clock input (as the VHDL code requires).
Why the error message?
When the HDL compiler translates your VHDL source code, the synthesis tools infer from the expression RISING_EDGE(PCLK)
that the PCLK
input is a clock. So far, so good. But then the synthesis tools infer from the expression RISING_EDGE(HREF)
that the HREF
input is another clock. This is a problem. Your design doesn't really address split clock domains, clearly you intended to use HREF
as a control input not a clock. And, unlike PCLK
, the HREF
signal is not assigned to an input pin that can receive an external clock. It's just not physically possible. The FPGA silicon chip doesn't have a configurable pathway from that particular pin's IOB
to any global clock BUFG
.
As your HDL code is written now, the HREF
rising edge would be detected immediately, as though it was another clock signal. But then the SKIP
signal is treated as if it was in the same clock domain as PCLK
.
It's good to read up on the Xilinx literature about what these clock primitives are and how to use them; I recently had a project where I needed to select between an on-board clock and an optional user-supplied clock, and use with a couple of internal DCM
(digital PLL sort of clock multiplier), and for that one I did have to "manually" instantiate all of the IOB
and BUFGMUX
and connect them "manually" because there were several clock domains of different frequencies.
For most projects you don't have to worry about any of this. As long as the synchronous logic all uses one clock ( Verilog always @(posedge clk)
or VHDL RISING_EDGE(CLK)
), and the clock is assigned to one of the special dedicated clock input pins, then the HDL compiler automatically determines where it needs BUFGMUX
and IOB
, and it silently inserts these as part of the normal synthesis. The only reason you got this error message was because your HDL code looked like it was using a clock signal that wasn't physically capable of being a clock.
What to do about it
A better approach is to modify your LINECOUNT:
process to use RISING_EDGE(PCLK)
so it is in the same clock domain as the rest of the design, and detect the rising edge on the HREF
control input by using a flip-flop and comparing to the current HREF
value. Store the previous HREF
value as HREF_PREVIOUS
( I think in VHDL you use HREF_PREVIOUS <= HREF
thereby inferring a flip-flop). When HREF_PREVIOUS
is 0 and HREF
is 1, then you have detected the rising edge during that PCLK clock cycle -- and can trigger the LineCounter
action and determine the next value of SKIP
.
As a control input rather than a second clock, the HREF
control input cannot be faster than PCLK
, or else it will not be reliably detectable. This design assumes that the master clock PCLK
is the fastest timing signal.
What if you really meant to use two clocks?
If in the future you do have a design that really does require splitting the logic across multiple clock domains, the usual technique for sending signals across the clock domain split involves a chain of 3 flip-flops (one in the source clock domain followed by two in the destination clock domain), to try to avoid metastable operation. Again, I don't think that's what you're trying to do here.
What NOT to do about it
If you really really really want the HDL compiler to route a clock signal (badly) from that HREF
pin (which is physically impossible to connect to the FPGA's internal global clock distribution system), to drive a flip-flop (from some random signal instead of the usual global clock system), the error message text you posted does tell you how to override the error message. In your project's .ucf file (User Configuration File), you would add the CLOCK_DEDICATED_ROUTE
attribute. (Note Xilinx .UCF is only for the older ISE and XST tool; Vivado has a different kind of constraint system.) And the performance would not be very good, so you'd have to keep everything at a slower clock speed to allow everything more time to settle. Really though that's probably a bad way to hack, unless you understand what's going on at the level of the FPGA primitive elements. (Technique would be OK if you were building a massive ripple counter using all of the flip-flops... but again, why would be trying to build a crummy ripple counter.) On balance, it's usually easier to write clean HDL code that synthesizes what you want, instead of trying to force a bad solution.
More tips
I notice this code is written as Behavioral
... which is OK, but just remember that this is a Hardware Description Language, not a C compiler. If you want to successfully design code that can be synthesized, always keep in mind what the actual hardware is that you're describing. I come from a background of 25+ years as a C programmer, and it's a constant struggle for me to see the HDL code in terms of the actual hardware. Structural description (wiring connection) is closer to what will actually be synthesized. The synthesis tools can usually recognize what is intended from a behavioral description if you stick with commonly used forms, but it's very easy to confuse the synthesis tools and end up describing something that can't be built.
Get in the habit of skimming through the reams of output that the HDL compiler generates. It can be a bit overwhelming at first, but since you're starting with some small entry-level teaching circuits, it should be manageable. Xilinx ISE lets you view the RTL code post-synthesis, this is a good way to check that nothing important is left out. (I once had an error in a verilog initial
block that only triggered a warning message, not an error... but it made the output of that module constant 0. And so that module was silently trimmed out because it had become a do-nothing module. And everything else that used that module got trimmed out too. Spent nearly a day trying to figure out why my custom SPI interface wasn't driving any output, then looked at RTL schematic and there was no SPI output pin. The actual output pin just wasn't being driven by any active HDL code. Almost half of my design was silently ripped out and trashed, all because of one little warning message.)