Author Topic: First FPGA project. Looking for advice  (Read 5663 times)

0 Members and 1 Guest are viewing this topic.

Offline hermitengineerTopic starter

  • Regular Contributor
  • *
  • Posts: 77
  • Country: us
Re: First FPGA project. Looking for advice
« Reply #25 on: May 16, 2021, 08:16:41 pm »
Look in the Message folder (tab) on the Console pane after running Synthesis.  It is unlikely that your code isn't generating a bunch of warnings.
Under RTL Analysis, Open Elaborated Design, open the Schematic and see what logic has been generated.  This will require successful synthesis.
Sampling and signal change do not occur simultaneously on the clock edge.  The signal is sampled no closer than tsetup before the clock and the output is stable no sooner than thold after the clock.  That's why asynchronous logic is so hard to create.  All of the potential transitions have to be covered in the Karnaugh Map and these small undefined regions generate glitches.  We get around this problem by designing synchronous logic.

https://www.nandland.com/articles/setup-and-hold-time-in-an-fpga.html
The RTL elaboration is definitely correct, the simulation test code passes, and it uses all of the bits of all of the memory in the testing.  Both synthesis and implementation are "successful".  0 warnings, 0 critical warnings, 0 errors, but the synthesized schematic has hacked out most of the logic.

What is most baffling, though, is that it only strips out 15 of the 16 memory bits.  It generates lookup tables to replace the parts that read RAM and replaces the data with constant values.  Then after deciding that nobody is reading 15 of the bits, apparently, it culls them.  But #15, apparently IS used.
 

Offline miken

  • Regular Contributor
  • *
  • Posts: 102
  • Country: us
Re: First FPGA project. Looking for advice
« Reply #26 on: May 16, 2021, 10:12:44 pm »
Hmm, maybe you fixed it after your initial post? This is what I get in 2019.2.
 

Offline hermitengineerTopic starter

  • Regular Contributor
  • *
  • Posts: 77
  • Country: us
Re: First FPGA project. Looking for advice
« Reply #27 on: May 16, 2021, 11:16:29 pm »
Well, I haven't fixed anything and it's still going wrong.  Is there a way to force a complete re-synthesis from nothing?  Maybe it's skipping some steps because it thinks some of the files are unchanged?

Anyway, DB is one of the chip's inout port vectors.  The RINGBUFFER's 'unconnected port' is connected to the memory output.  But maybe I specified it wrong?

DB (as an output) is also connected to memory output under the ram_to_db condition.
« Last Edit: May 16, 2021, 11:26:12 pm by hermitengineer »
 

Offline hermitengineerTopic starter

  • Regular Contributor
  • *
  • Posts: 77
  • Country: us
Re: First FPGA project. Looking for advice
« Reply #28 on: May 17, 2021, 12:18:47 am »
Even more curious, I tried to run the post-synthesis functional simulation.  It came up with errors that make no sense.

Code: [Select]
ERROR: [VRFC 10-3180] cannot find port 'SD_OBUF' on this module [C:/Users/Documents/RA_3_9600/RA_3_9600.sim/sim_1/synth/func/xsim/ra3_9600_tb_func_synth.v:1344]
ERROR: [VRFC 10-3180] cannot find port 'Q' on this module [C:/Users/Documents/RA_3_9600/RA_3_9600.sim/sim_1/synth/func/xsim/ra3_9600_tb_func_synth.v:1343]
ERROR: [VRFC 10-3180] cannot find port 'DB_IBUF' on this module [C:/Users/Documents/RA_3_9600/RA_3_9600.sim/sim_1/synth/func/xsim/ra3_9600_tb_func_synth.v:1342]
ERROR: [VRFC 10-3180] cannot find port 'CLK' on this module [C:/Users/Documents/RA_3_9600/RA_3_9600.sim/sim_1/synth/func/xsim/ra3_9600_tb_func_synth.v:1341]
ERROR: [VRFC 10-3180] cannot find port 'BUSAK_IBUF' on this module [C:/Users/Documents/RA_3_9600/RA_3_9600.sim/sim_1/synth/func/xsim/ra3_9600_tb_func_synth.v:1340]
ERROR: [XSIM 43-3322] Static elaboration of top level Verilog design unit(s) in library work failed.

The file in question, where the errors are:
Code: [Select]
  CPUBUSDECODER decoder
       (.BUSAK_IBUF(BUSAK_IBUF),
        .CLK(intak),
        .DB_IBUF(DB_IBUF[13:0]),
        .Q(\RING_reg[19] ),
        .SD_OBUF(SD_OBUF));

The module that it had just defined:
Code: [Select]
module CPUBUSDECODER
   (SD_OBUF,
    DB_IBUF,
    Q,
    CLK,
    BUSAK_IBUF);
  output [13:0]SD_OBUF;
  input [13:0]DB_IBUF;
  input [13:0]Q;
  input CLK;
  input BUSAK_IBUF;

  wire BUSAK_IBUF;
  wire CLK;
  wire [13:0]DB_IBUF;
  wire [13:0]Q;
  wire [13:0]SD_OBUF;
  wire mode;
  wire mode_i_2_n_0;
 

Offline rstofer

  • Super Contributor
  • ***
  • Posts: 9885
  • Country: us
Re: First FPGA project. Looking for advice
« Reply #29 on: May 17, 2021, 01:00:50 am »
Well, I haven't fixed anything and it's still going wrong.  Is there a way to force a complete re-synthesis from nothing?

Just click on Run Synthesis and click on OK in the popup dialog.
Follow this with Generate Bitstream to get all the errors and warnings.
« Last Edit: May 17, 2021, 01:05:05 am by rstofer »
 

Offline rstofer

  • Super Contributor
  • ***
  • Posts: 9885
  • Country: us
Re: First FPGA project. Looking for advice
« Reply #30 on: May 17, 2021, 01:06:32 am »
You do have a Constraints file to define the pinout of your project, right?
 

Offline hermitengineerTopic starter

  • Regular Contributor
  • *
  • Posts: 77
  • Country: us
Re: First FPGA project. Looking for advice
« Reply #31 on: May 17, 2021, 01:56:09 am »
Follow this with Generate Bitstream to get all the errors and warnings.
That might be the missing link.  I never generated the bitstream since I wasn't ready to try to upload it.

Edit:  Well, the bitstream added a couple more warnings, but none of the scale that deletes entire sections of your circuitry.  Two about the same LUT driving a clock, one that I haven't configured the voltage for the chip yet.

You do have a Constraints file to define the pinout of your project, right?
Yeah, I just used the auto-place pins tool for the moment.
« Last Edit: May 17, 2021, 02:08:22 am by hermitengineer »
 

Offline hermitengineerTopic starter

  • Regular Contributor
  • *
  • Posts: 77
  • Country: us
Re: First FPGA project. Looking for advice
« Reply #32 on: May 18, 2021, 04:20:50 am »
I've made some progress by splitting each module into its own project and compiling it separately.  It actually reports warnings and errors!  Most of the modules compiled cleanly.  But I note that it complains about a lack of input delay constraints in some cases.  But, what timing constraint would you place on an asynchronous input?

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?
 

Offline Bassman59

  • Super Contributor
  • ***
  • Posts: 2501
  • Country: us
  • Yes, I do this for a living
Re: First FPGA project. Looking for advice
« Reply #33 on: May 18, 2021, 05:27:32 am »
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.
 

Offline hermitengineerTopic starter

  • Regular Contributor
  • *
  • Posts: 77
  • Country: us
Re: First FPGA project. Looking for advice
« Reply #34 on: May 18, 2021, 06:45:43 am »
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:

Code: [Select]
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.
Code: [Select]
always@(posedge P2, posedge BUSAK) begin
    if(BUSAK) begin
        loading_values <= 0;
    end else if(P2) begin
        loading_values <= 1;
    end
end
It generates a little more circuitry for this part than I'd deem necessary, but whatever.
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):
Code: [Select]
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


And here's a basic circuit diagram of what I'm trying to synthesize
 

Offline Bassman59

  • Super Contributor
  • ***
  • Posts: 2501
  • Country: us
  • Yes, I do this for a living
Re: First FPGA project. Looking for advice
« Reply #35 on: May 18, 2021, 03:44:01 pm »
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:

Code: [Select]
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:

Code: [Select]
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:

Code: [Select]
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.

Quote
Code: [Select]
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.

Quote
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.

Quote
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):
Code: [Select]
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.
 

Offline hermitengineerTopic starter

  • Regular Contributor
  • *
  • Posts: 77
  • Country: us
Re: First FPGA project. Looking for advice
« Reply #36 on: May 18, 2021, 06:34:20 pm »
Code: [Select]
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.)

Yes, both card_load_count and LD_EN should be asynchronous clears based on SR3.  It's not the above code that converts LD_EN to a synchronous one though.  As I say, the above code alone leaves everything as intended.  It's the use of LD_EN in the next block that forces conversion to a synchronous clear.
 

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:

Code: [Select]
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.

Actually, Verilog handles this like a champ.  The {} construct tells it to treat the list of bit vectors as one large value concatenating the bits in the order presented.  So the 3-bit count is extended to a 4-bit count with a 0 for its high bit.  Then the arithmetic operation adds 1 and, on a count of 7, the count resets to 0 with a 1 in the high bit as expected.  This 4-bit value is then split back into count and LD_EN, with the 1 being assigned to LD_EN.  The auto-generated schematic bears this out, that LD_EN is treated exactly as if it were the 4th bit.

I did experiment earlier with making the count 4 bits and connecting LD_EN as a wire to the 4th bit.  This did not change the generated schematic at all, nor did it change the fact that the lower 3 bits are asynchronous clear but the 4th is converted to synchronous.

Quote
Code: [Select]
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.
Uggh... this is wrong though.  It needs to depend on LD_EN, as noted in my provided schematic.  This must be from backing out an experimental change stupidly, since not using the first block's output causes it to be optimized out.  Let's correct the block:
Code: [Select]
always@(posedge P2, posedge BUSAK) begin
    if(BUSAK) begin
        loading_values <= 0;
    end else begin
        if(LD_EN) begin
            loading_values <= 1;
        end
    end
end

For clarity: the complaints you get come from the timing analyzer or the synthesizer?
Timing analyzer.  These complaints come from the "Check Timing" section.

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.
Yeah and that's the problem:  It is both.  Is there a way to "clone" the signal in a way that fools Verilog into thinking one is a clock and the other is a reset signal?
 

Offline emece67

  • Frequent Contributor
  • **
  • !
  • Posts: 614
  • Country: 00
Re: First FPGA project. Looking for advice
« Reply #37 on: May 18, 2021, 11:39:17 pm »
.
« Last Edit: August 19, 2022, 05:56:27 pm by emece67 »
 

Offline hermitengineerTopic starter

  • Regular Contributor
  • *
  • Posts: 77
  • Country: us
Re: First FPGA project. Looking for advice
« Reply #38 on: May 19, 2021, 06:03:15 am »
Well, it turns out I'm an idiot.  (pauses for gasps to fade away)

that synthesizes to:

which is exactly as the circuit you posted, will do the job

Unfortunately, my circuit is wrong.  The flip-flop is only supposed to be set by the count, never reset.  Then the flip-flop can actually drive the address counter correctly rather than keeping it always on.


Anyway, I finally figured out that it's NOT doing a synchronous clear of the high bit.  It's inverting the sense.  FDCE vs FDPE, both are asynchronous.  But the latter turns on instead of off.  Vivado decided that was a more efficient implementation.

Now, one thing I've come up with as a kludge:  Provide SR3 on 2 separate pins to the chip.  This allows me to interpret one as a clock input and the other as an asynchronous input, even though they are both the same.  With that, my code shows:
Code: [Select]
always@(posedge P2, posedge SR3_RST) begin
    if(SR3_RST) 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

always@(posedge P2, posedge BUSAK) begin
    if(BUSAK) begin
        loading_values <= 0;
    end else begin
        if(LD_EN) begin
            loading_values <= 1;
        end
    end
end

// Advance the address if LD is active
always@(negedge SR3_CLK, negedge mode)
begin
    if(!mode) begin
        card_addr <= 0;
    end else begin
        if(loading_values) begin
            card_addr <= card_addr + 1;
        end
    end
end

I still have to make Vivado think that SR3_CLK is a timed clock, but at least that eliminates all of the gripes.  Adding a few other constraints has tamed the rest of the timing analysis, though I am not completely certain I specified sane values.

A final note is that I had to make 'mode' a false path to the clear pins, or it cries about that timing constraint.  Apparently, it attempts to implement the 8-bit counter using 2 lookahead carry units, and it gets paranoid about hold times with regards to SR3_CLK.  With the false path, it goes back to implementing the 8-bit counter with LUTs again, which apparently doesn't have hold time paranoia.

Code: [Select]
set_property IOSTANDARD LVTTL [get_ports {card_addr[7]}]
set_property IOSTANDARD LVTTL [get_ports {card_addr[6]}]
set_property IOSTANDARD LVTTL [get_ports {card_addr[5]}]
set_property IOSTANDARD LVTTL [get_ports {card_addr[4]}]
set_property IOSTANDARD LVTTL [get_ports {card_addr[3]}]
set_property IOSTANDARD LVTTL [get_ports {card_addr[2]}]
set_property IOSTANDARD LVTTL [get_ports {card_addr[1]}]
set_property IOSTANDARD LVTTL [get_ports {card_addr[0]}]
set_property IOSTANDARD LVTTL [get_ports BUSAK]
set_property IOSTANDARD LVTTL [get_ports loading_values]
set_property IOSTANDARD LVTTL [get_ports mode]
set_property IOSTANDARD LVTTL [get_ports P2]
create_clock -period 500.000 -name P2 -waveform {0.000 250.000} [get_ports P2]

# set_false_path -from [get_clocks SR3] -to [get_clocks P2]






create_clock -period 2000.000 -name SR3 -waveform {0.000 1000.000} [get_ports SR3_CLK]






set_input_delay 0.000 [get_ports {BUSAK mode SR3_RST}]




set_false_path -from [get_ports mode] -to [get_pins -hierarchical *card_addr_reg*/CLR*]

set_output_delay -clock [get_clocks SR3] -min 300.000 [get_ports {{card_addr[0]} {card_addr[1]} {card_addr[2]} {card_addr[3]} {card_addr[4]} {card_addr[5]} {card_addr[6]} {card_addr[7]}}]
set_output_delay -clock [get_clocks P2] -min 300.000 [get_ports loading_values]

set_output_delay -clock [get_clocks SR3] -max 400.000 [get_ports {{card_addr[0]} {card_addr[1]} {card_addr[2]} {card_addr[3]} {card_addr[4]} {card_addr[5]} {card_addr[6]} {card_addr[7]}}]
set_output_delay -clock [get_clocks P2] -max 400.000 [get_ports loading_values]
 

Offline Bassman59

  • Super Contributor
  • ***
  • Posts: 2501
  • Country: us
  • Yes, I do this for a living
Re: First FPGA project. Looking for advice
« Reply #39 on: May 19, 2021, 10:07:13 pm »
For clarity: the complaints you get come from the timing analyzer or the synthesizer?
Timing analyzer.  These complaints come from the "Check Timing" section.[/quote]

I think where the tools are not sufficient for dealing with this comes in the basic period constraint. They expect that when a signal is used as a clock, it will toggle at a given period and that your logic starts and ends with registers on that same clock. So the period constraint is really saying, "the prop delay between the start register and the end register must be no more than XX ns." The timing analyzer takes into account the start flop's clock-to-out, the end flop's setup requirements, and both the logic and the routing in between.

If there's no "start" and "end" registers, as such, the tools get ... confused. And this is really where the notion of doing asynchronous design in an FPGA kinda goes to hell. It's not that the design idiom itself is good, bad or indifferent. It's just that the FPGA fabric and the tools are not intended to deal with it. And, really, what you are doing is async design.

Quote
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.
Yeah and that's the problem:  It is both.  Is there a way to "clone" the signal in a way that fools Verilog into thinking one is a clock and the other is a reset signal?

Put a BUFG on SR3, call its output SR3_Clk or something, and then use SR3 for the reset and SR3_Clk as the clock.

NB: I haven't tried this so I don't know whether this will actually work.
 

Offline hermitengineerTopic starter

  • Regular Contributor
  • *
  • Posts: 77
  • Country: us
Re: First FPGA project. Looking for advice
« Reply #40 on: May 19, 2021, 10:22:48 pm »
Yeah I guess it also has such a thing as a "virtual clock" which is supposed to be the dumping ground for the combinational logic.  I guess even with that, it expects the results to be available before the next virtual cycle though.

I also discovered the "disable timing check" constraint.  This may be necessary for the asynchronous clears, since the analyzer wants to put some kind of limits on them even though they are async.  I sorta get the rationale, that if you, say, don't provide a large enough pulse width you might only catch 1 or 2 of them, or that if you drop the signal at just the wrong time you might see a FF do something stupid.  But since this is a simple design and the engineers who designed it way back then seem to have taken great care to keep the signal timing where everything behaves, I'd rather Vivado not concern itself with those details.

On the good side, it has been quite educational, to see how even the timing constraints will affect the implementation circuit design.
« Last Edit: May 19, 2021, 10:26:31 pm by hermitengineer »
 

Offline hermitengineerTopic starter

  • Regular Contributor
  • *
  • Posts: 77
  • Country: us
Re: First FPGA project. Looking for advice
« Reply #41 on: May 20, 2021, 09:48:17 am »
So, it's beginning to look like I at least have adequate grasp of Verilog.  But Vivado's timing constraints are still confusing.

If I use the constraints wizard to set an input delay, for instance, it asks which clock (makes sense) and which edge (also makes sense) but then asks for the delay value plus the trace delay.  Okay, I understand trace delay in principal: signals don't make it instantly from one location on the PCB to the other.  This was even becoming an issue in the days of 386.  I get it, but I can only guess at what the trace delay might be for this board (and at its paltry clock speed, it really won't matter).  So I just throw 1ns in there and call it good.

Then it wants to know about signal delay for each input.  This is where I get confused.  The signal paradigm is that the signal arrives long before the clock pulse.  But the timing diagram suggests that it wants to know how long AFTER the clock pulse to look for the signal.  Am I correct in this interpretation?  And if so, does that mean I should use negative numbers to say that the signal is already there?

Even with this, though, I get timing errors even on the simplest of circuits.  For instance:
Code: [Select]
module test(
  input a,
  input b,
  input c,
  input d,
  input e,
  output y,
  output reg z);

always@(posedge c) begin
  z <= a | b;
end

assign y = z & (c | d) ^ (c & e);
end

The combinational part is handled well.  In fact, if I don't trigger on any edges, it creates nothing but a combinational circuit.  Curiously, this is true even for the construct
Code: [Select]
always@ (c) begin
  z <= a | b;
end
It does not create a circuit that clocks on either change of c.  It just creates a combinational circuit a|b and wires it to z.

Anyway, if the circuit is purely combinational, then no timing analysis seems to be done.  Makes sense.  But with the trigger I added, and with a constraint file I added, it complains about the hold time for a in relation to c.
Code: [Select]
create_clock -period 100.000 -waveform {0.000 50.000} [get_ports c]
set_input_delay -clock [get_clocks c] -min -add_delay -25.000 [get_ports a]
set_input_delay -clock [get_clocks c] -max -add_delay 50.000 [get_ports a]
set_input_delay -clock [get_clocks c] -min -add_delay -25.000 [get_ports b]
set_input_delay -clock [get_clocks c] -max -add_delay 50.000 [get_ports b]
This results in a hold violation.  It seems mad that the data arrived before it was needed.  Why?  Furthermore, it only complained about input "a" and not "b".  Why? They are both placed on adjacent pads and are both sent on a whirlwind winding route throughout the entire chip before finally making it to the LUT.  So if there are skewed arrival times, it's the router's fault.  But either way, it appears that the timing check has decided that "a" arrived -11ns before the required time of 0.  Why is that a problem?
 

Offline emece67

  • Frequent Contributor
  • **
  • !
  • Posts: 614
  • Country: 00
Re: First FPGA project. Looking for advice
« Reply #42 on: May 20, 2021, 11:14:42 am »
.
« Last Edit: August 19, 2022, 04:26:09 pm by emece67 »
 
The following users thanked this post: Bassman59

Offline emece67

  • Frequent Contributor
  • **
  • !
  • Posts: 614
  • Country: 00
Re: First FPGA project. Looking for advice
« Reply #43 on: May 20, 2021, 11:55:03 am »
.
« Last Edit: August 19, 2022, 04:26:15 pm by emece67 »
 

Offline rstofer

  • Super Contributor
  • ***
  • Posts: 9885
  • Country: us
Re: First FPGA project. Looking for advice
« Reply #44 on: May 20, 2021, 03:50:37 pm »
An FPGA will easily run at 100 MHz and 10ns is a lot faster than the old LSTTL could run (14 ns clock to Q output, 32 MHz max, asynchronous inputs to output change 38 ns and 20-25 ns of setup time for clocked inputs).  So, this project will eventually come down to "what does the circuit do" instead of "how did the circuit do it".

Asynchronous design with FPGAs just isn't done.  The tools don't want to do it and they will be an impediment throughout the process.  A process destined to fail, IMO.

It would seem to me that it would be better to define how the inputs affected the outputs and then just design a simple synchronous circuit that would emulate the original.

Think of the new circuit as a 'black box'.  It has inputs and outputs and only one clock.  What should the outputs look like when the inputs change.  Maybe make up a timing diagram like the one on page 10 here but for the entire project.

https://www.ti.com/lit/ds/symlink/sn74ls163a.pdf

BTW, only synthesis matters.


 

Offline hermitengineerTopic starter

  • Regular Contributor
  • *
  • Posts: 77
  • Country: us
Re: First FPGA project. Looking for advice
« Reply #45 on: May 20, 2021, 05:54:05 pm »
You systematically refuse to adhere to the synchronous design paradigm, so the tools systematically complain. The always block means c is a clock. You cannot use a clock in a combinational circuit, as you do in the assign.
Yeah I saw that afterwards.  It was left over from the initial test where everything WAS combinational.  I removed the references to 'c' in the combinational part.  But it did not affect any of the timing-related gripes.

If there are no timing constraints given on the inputs, the router will make nice neat connections from the pads to the LUTs.  If the timing is specified as negative setup time, meaning the signal is already good, then the router will spaghetti the route all over the chip like a doodling child, give up, and say that it can't get the hold time within the required 0ns time.  The best I can figure is that it freaks out, thinking that the data is no longer valid after the rising edge, even if you specify a positive value for the max.  It seems that the only satisfactory answer would be "0" after the rising edge for the non-clock inputs.
« Last Edit: May 20, 2021, 06:27:59 pm by hermitengineer »
 

Offline miken

  • Regular Contributor
  • *
  • Posts: 102
  • Country: us
Re: First FPGA project. Looking for advice
« Reply #46 on: May 21, 2021, 07:10:04 am »
The most understandable presentation of the timing constraints I've seen is in Vivado under Tools -> Language Templates. Maybe that will help.
 
The following users thanked this post: FenTiger, hermitengineer

Offline hermitengineerTopic starter

  • Regular Contributor
  • *
  • Posts: 77
  • Country: us
Re: First FPGA project. Looking for advice
« Reply #47 on: May 22, 2021, 11:54:53 am »
On the original project, I fixed the memory problems.  First, Vivado doesn't seem to synthesize the dual-port memory well.  I always chose the latched address for a write, but read from either the latched one or the internal counter, depending on conditions.  This seems to be what broke Vivado's brain, even though they have memory primitives constructed for that purpose.

Oh well, if I switch to CPLD with external memory, I'll need to migrate to a single address port anyway.

The other issue was not using a power of 2 for memory size.  This caused problems with memory address sizes as it lost the high bit.  Specifying 512 instead of 352 words solved that issue.

But even still, the simulations of synthesis or implementation continue to fail for unknown reasons.  It has many ports that it claims don't exist, even though they definitely do exist in the code.  For instance, mode_reg_0 is defined for the module on line 9xx, but when it tries to instantiate the module it claims the port cannot be found.  Same for the IBUFs on a number of pins.  What's this about?
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf