Secondly, I now see in one module that it warns of a non-clock source driving clock inputs. The non-clock source is, of course, SR3. It is definitely a trigger for the case of advancing an address counter, but it's also an asynchronous level trigger for the purpose of making SD an output, and an asynchronous clear for another counter. It is NOT a clock. If I specify it as one, then the timing constraints cry about cross-domain interaction. It seems that Vivado hates asynchronous triggers. Are there any tricks for telling it that you definitely want an input to be asynchronous and you'll take your lumps from any race conditions?
It's not that Vivado hates asynchronous triggers. It's that that FPGA fabric hates having flip-flop clock inputs driven regular logic signals not on a global clock net.
Remember any signal on the sensitivity list with a negedge or posedge decoration is considered to be either an async reset or a clock, and the discussion above tells how the two are distinguished. So you wrote your code to infer an edge-triggered flip-flop.
Try putting a BUFG macro on the signal which you are using as that clock. That will put the signal on the global clock net and satisfy the tools. Note that you might incur a routing delay penalty for doing so.
Well, I tried that. The schematic shows it appearing on a BUFG buffer, but it still gives me the same message: "The clock pin card_addr_reg[0].C is not reached by a timing clock" and in the timing report it says "Register/Latch pins with no clock driven by root clock pin: SR3" and lists card_addr_reg[0..7]/C. In "no_input_delay" it complains with high severity about a lack of timing constraints on my asynchronous inputs (yeah, that's part of being asynchronous).
Well, here's what I have currently:
module CARDADDR(
(* CLOCK_BUFFER_TYPE = "BUFG" *) input SR3,
input P2,
input BUSAK,
input mode,
output reg [7:0] card_addr,
output reg loading_values
);
...
always@(posedge P2, posedge SR3) begin
if(SR3) begin
card_load_count <= 0;
LD_EN <= 0;
end else if(P2) begin
if(!LD_EN) begin
{LD_EN, card_load_count} <= { 1'b0, card_load_count } + 1;
end
end
end
I should note that if this is the only code, all clears are asynchronous. But with the follow-on code, it apparently freaks out about the possibility of loading a transitional value from LD_EN and converts it to a synchronous clear.
Well, you described a synchronous clear.
Actually, it's more confusing than that. In the above block, which is the "clock" and which is the "asynchronous reset?" Looks to me like SR3 is the reset and P2 is the clock. What might be confusing the tools (and you, and me) is that you check the state of P2 for your clock edge detector. Now, I'm a VHDL guy, and this is one of the "features" of Verilog that still makes me wonder what they were thinking. (VHDL is absolutely clear on this: you'd use
rising_edge(P2) to clearly indicate "I want to infer a rising-edge-triggered flip-flop with the clock as P2." But I digress.)
So what you described above -- and this is, I think the root of your problem -- will asynchronously clear LD_EN when SR3 is high. Here is where Verilog gets REALLY confusing. FPGA flip-flops have only one clock. The normal idiom for inferring a flip-flop with an async clear is:
always @(posedge clk, negedge rst) begin
if (!rst)
q <= 1'b0;
else
q <=d;
end
The synthesizer does pattern-matching. The above idiom is the pattern for a flip-flop and the synthesizer "knows" that rst is the async reset and clk is the rising-edge-triggered clock. It's strange how the sensitivity list looks suggests the reset is edge triggered. As we know, an async reset overrides a clock. Imagine we've brought rst low -- we've triggered a reset. Now, when there's a positive edge on the clock, the process is triggered again. But since we first check the state of rst and we see that it's low, that condition wins and the reset assignment continues. (I honestly don't know why the idiom isn't @(posedge clk, rst), and I've been musing over this since first doing Verilog in 1996.)
But what you wrote above? That's confusing! It really does look like you want two clocks, and I'm not surprised that the synthesizer is giving you fits.
You might wish to simulate that block and see what it's actually doing. Because it looks to me like LD_EN is permanently low. Look at the assignment:
if(!LD_EN) begin
{LD_EN, card_load_count} <= { 1'b0, card_load_count } + 1;
end
LD_EN is always assigned 1'b0, so it's always low and on every rising edge of P2 card_load_count increments. What happens when that incremented overloads? I have no idea. I don't know what you intend with this code.
always@(posedge P2, posedge BUSAK) begin
if(BUSAK) begin
loading_values <= 0;
end else if(P2) begin
loading_values <= 1;
end
end
Here you're doing a simpler flop with async clear. Get rid of the check if (P2). It is implied that if BUSAK has not seen a rising edge, then the only thing that triggers the block is the rising edge of P2. And that should infer a proper edge-triggered flip-flop with P2 as the clock and BUSAK as the async clear.
It generates a little more circuitry for this part than I'd deem necessary, but whatever.
From what I understand, you're trying to model exactly how the original design, implemented in basically async logic, in an inherently-synchronous device (the FPGA). The reason for doing it the "old way" in the old days was because that's what was available to the design engineers. Thankfully, we don't have to design like that any more. And you're learning the reasons why -- for one, the tools don't like async design.
Finally, the section that it panics about clocking without a timed clock (and also freaks out about all the other inputs to its generated FFs being possibly unconstrained):
always@(negedge SR3, negedge mode)
begin
if(!mode) begin
card_addr <= 0;
end else begin
if(loading_values) begin
card_addr <= card_addr + 1;
end
end
end
For clarity: the complaints you get come from the timing analyzer or the synthesizer?
In any case, you've used SR3 as a reset way up above and now you're using it as a clock, so there's no surprise that the tools can't make heads or tail of what you want to do.