cancel
Showing results for 
Search instead for 
Did you mean: 
Highlighted
Observer
Observer
591 Views
Registered: ‎09-06-2016

The question that fell in a black hole for 3 weeks and counting

Jump to solution
Registered: ‎09-06-2016
How to replicate ports created with IP and example design
 
 

My last 2 attempts to get this answered (starting April 18) got me more confused and wasted a ton of trial and error time.  Rather than ask for an explanation here, let me ask if there is a video or tutorial showing step by step how to do the following.  The various user guides do not cover this design goal in enough detail and have few screen shots.

After creating four separately placed instances of an communication IP with the wizard, I want to place them under a top level design and implement.  If you have done this and have an example, I'd appreciate it.  I have received missing or conflicting written or out of date online advice, along with some incomprehensible verbal advice.  I'm new to this.  So I need to see all the steps rather than broad stroke statements.

1.  Do I add the .veo or the .xci or a whole directory or 4 directories to the top (?) or just cut and paste the instantiation templates into the top level .v ?  If directories, is it IP or example design directories?  If files, which files specifically?  If I need to cut and paste anything, what and where?

2.  Once the designs are pasted in, how can I tell which lines in the subdesigns represent I/O ports going to pins that I have to constrain if not so identified by comment?

3.  Equivalently, which signals are ports that I must declare differently in the top level for each port and name the same for each instance?

4.  Is there any difference doing this with a hard IP (eg cmac_usplus) vs a soft IP (eg aurora)?

Thanks in advance??

0 Kudos
1 Solution

Accepted Solutions
Highlighted
Guide
Guide
563 Views
Registered: ‎01-23-2009

Re: Designing a system with multiple IP cores of the same or similar type

Jump to solution

Unfortunately I don't think you are going to get the "step by step" answers you are looking for - there isn't a template for this, and it isn't even entirely the same for all IPs.

I will try and give you some knowledge that will help...

First, you need to be careful of the word "instance" - it means different things to different people. In Verilog/SystemVerilog/VHDL an "instance" is an instantiation of a module (Verilog/SystemVerilog) or entity (VHDL). Using the language and in synthesis it is generally possible to make multiple instances of the same module/entity.

However, many of these cores (anything that uses high speed transceivers) generate top level modules/entities that have some placement information in them - they are specific to a location on the die, using specific resources on the die. You cannot use more than one instance of these cores (at least not using a normal flow).

So you have to start by generating four different IP cores. These are not four instances of the same core, but four different cores of the same type - each it its own hierarchy of modules/entities with a top level module/entity that you can instantiate in your design. So your final design will require one instance of each of these four different cores. The good news is that Xilinx is careful to ensure that any module/entity generated as part of a core design will be unique - each of the four different cores is guaranteed not to reuse the same module/entity name at any level of hierarchy (since it is illegal in to have two module/entities of the same name in a system - even if they are "identical").

Next, the instantiation of a complex IP core is not trivial. In many cases, these cores require specific clocking, reset or other logic external to the core to make them work. To facilitate this, Xilinx has the option of generating an example design for the core; this gives you (as the name implies) an example of how to instantiate it. But it is just that, an example, and it doesn't necessarily mean that this is the only way to instantiate it, nor is this intended to cover any possible scenario of using this core - it is up to you to design the top level of your system, taking inspiration from this example design.

Continuing on, some cores need specific "other" FPGA resources as part of a general solution. For example, some may require specific clocking resource like an MMCM and/or BUFGs to be used as part of the system that includes the IP. Xilinx generally provides two solutions to this

  • Generate the core that includes all the FPGA resources required for the core inside the core
    • This generally results in the simplest "example design" because all the required resources are inside the core
  • Generate the core without all the external stuff inside the core
    • Anything that is potentially shareable between multiple cores (or between this core and other things in your design) are not included inside the core, but are instead moved to the example design, which shows you how to connect the "other stuff"

The first solution is generally best for a design with a single core - the example design generally is just an instantiation of the core in a top level with no connections to anything other than ports. However, if you create a system that has four such cores, you will get four copies of everything - and some of the stuff inside these cores is not meant to be instantiated once per core, but once per system. For example, any of the main user clocks for a core will require a clock buffer for the clock. With the first style, the BUFGs for these main clocks will be instantiated inside each core. But in your full system, you may want all of these cores to share the same system clock, and hence it is illegal to have one BUFG in each core for this clock. So you have to take the more complex solution - one that moves the "shared resources" outside the core (and this is generally an option in the core generation wizard).

When you move the shared stuff out, you still get a single core and a single example design. The example design is still just an example design for instantiating one core, but since the core doesn't have the shared stuff in it, the example design now has to have the shared stuff. The net result of having a top level that looks like the example design provided by one core is no different; you still have one core and one instance of all the shared stuff. 

Now comes the complex part. If you really want to use four such cores, you need to generate four separate cores, all with the "shared stuff" external to the core. You will get an example design with each of them, which will be basically the same thing - showing you how to create a system with the instance of the core you just generated and instances of each of the shared resources you need (and how to connect them).

For your real system, you need to generate a new "top" that includes one instantiation of each of the four cores you generated, but only (maybe) one instantiation of the "shared stuff", which you then need to connect appropriately to each of the four cores. Here is where you are a bit on your own. The user guides may help you understand what each of the "shared stuff" is, which, with enough expertise, you should be able to figure out how to share it with the four cores. But each core and each element within the "shared stuff" is different (which is why there is no single tutorial that shows you how to do this). Unfortunately, you will just have to learn enough about the system to figure out how to do this.

And it has to be done right. There are some resources (like the PLL structures in the GT quads) that must be shared properly; physically there are certain resources that are bound to the quads; for some of them each GT in the quad has its own, but for others there is only one in the Quad.

Now to your specific questions:

1. Do I add the .veo or the .xci or a whole directory or 4 directories to the top (?) or just cut and paste the instantiation templates into the top level .v ? If directories, is it IP or example design directories? If files, which files specifically? If I need to cut and paste anything, what and where?

The reason you are confused is that there are many different ways of doing it. First, there different ways of generating the cores - you can generate them inside your "real" project, in which case the generated cores are already in the project structure and added to your design, so you don't need to do anything. This is (by far) the simplest method - but it is entirely manual - you must generate all the cores for each project that you intend to implement.

The other way is to generate them outside your main project (not associated with a design). Xilinx used to have the concept of an IP collection project (I don't remember exactly what it was called), but this doesn't appear to be there anymore. This was just a project that had no real "top" but was just a container for a whole bunch of IP cores. You can still do this with a "fake" project and build all your cores there. But if you do, the next part of the question is "how do you move the cores generated here (or even in multiple different fake projects) into your real project. There are multiple ways

  • Import only the .xci
    • If you import the .xci (without all the directory stuff around it) the tool will be able to regenerate the entire core directory structure from the .xci file alone
  • Import the whole core directory
    • If you import an .xci file that is still in the directory structure of the entire core, the tool can reuse the build done at the time the core was created
  • Import the "core container"
    • When you build an IP you now have the option of packaging it in a "core container" which contains the entire core hierarchy (including the .xci) in what is essentially a zip file
  • Capture the .tcl commands that were used by the IP wizard that generates the .xci (that generates the entire directory) and execute that script
  • For some cores (although this is not recommended) you can copy the RTL generated in the synthesis directory of the core and add that as a "regular" RTL file to your design

The simplest of these (these days) is probably the core container (but I haven't used them much). Again, this is if you choose to generate the core outside your main project.

Again the .veo files are never "part" of your design - they are just examples that you can use as helpers to instantiate your core into a top level design.

2. Once the designs are pasted in, how can I tell which lines in the subdesigns represent I/O ports going to pins that I have to constrain if not so identified by comment?

Each IP should generate a scoped XDC file associated with the core which should apply placement constraints to all the ports of the core (assuming these are transceiver based cores - for "general purpose" cores, like block RAMs or other things, there are no placement constraints done at the core level).

Any signal of the core that doesn't go directly to a port does not need any placement constraints. These would be going to other resources in your FPGA - either to some of the "shared stuff" or to your user logic. There is no formulaic way to recognize which is which - you need to understand the ports of the core and how to instantiate them in your top level design (based on inspiration from the example designs).

3. Equivalently, which signals are ports that I must declare differently in the top level for each port and name the same for each instance?

Same answer as above - you need to read enough documentation to understand what each of these ports are and how to instantiate them in a system.

4. Is there any difference doing this with a hard IP (eg cmac_usplus) vs a soft IP (eg aurora)?

As I mentioned, each type of core may be different. Some that have no specific physical resource requirements (i.e. no GTs or other hard macros) may not have any placement constraints inside the IP core and therefore you would be able to instantiate multiple instances of the same core. Others are bound to specific physical resources in the die and thus must have a separate core generated for each copy you need. Again, something like the output of a the RAM or FIFO generator has no specific constraints, so can just be instantiated like any other module. Others (like both of the ones you ask about above) ask you to choose specific GT resources, and hence can be instantiated only once.

So that's the best I can do. I hope it helps, but, as I said, this is not a trivial thing that has a single formula for how to do this - you need to have some knowledge of the core and the resources in the FPGA required in order to get this core running.

Avrum

View solution in original post

2 Replies
Highlighted
Guide
Guide
564 Views
Registered: ‎01-23-2009

Re: Designing a system with multiple IP cores of the same or similar type

Jump to solution

Unfortunately I don't think you are going to get the "step by step" answers you are looking for - there isn't a template for this, and it isn't even entirely the same for all IPs.

I will try and give you some knowledge that will help...

First, you need to be careful of the word "instance" - it means different things to different people. In Verilog/SystemVerilog/VHDL an "instance" is an instantiation of a module (Verilog/SystemVerilog) or entity (VHDL). Using the language and in synthesis it is generally possible to make multiple instances of the same module/entity.

However, many of these cores (anything that uses high speed transceivers) generate top level modules/entities that have some placement information in them - they are specific to a location on the die, using specific resources on the die. You cannot use more than one instance of these cores (at least not using a normal flow).

So you have to start by generating four different IP cores. These are not four instances of the same core, but four different cores of the same type - each it its own hierarchy of modules/entities with a top level module/entity that you can instantiate in your design. So your final design will require one instance of each of these four different cores. The good news is that Xilinx is careful to ensure that any module/entity generated as part of a core design will be unique - each of the four different cores is guaranteed not to reuse the same module/entity name at any level of hierarchy (since it is illegal in to have two module/entities of the same name in a system - even if they are "identical").

Next, the instantiation of a complex IP core is not trivial. In many cases, these cores require specific clocking, reset or other logic external to the core to make them work. To facilitate this, Xilinx has the option of generating an example design for the core; this gives you (as the name implies) an example of how to instantiate it. But it is just that, an example, and it doesn't necessarily mean that this is the only way to instantiate it, nor is this intended to cover any possible scenario of using this core - it is up to you to design the top level of your system, taking inspiration from this example design.

Continuing on, some cores need specific "other" FPGA resources as part of a general solution. For example, some may require specific clocking resource like an MMCM and/or BUFGs to be used as part of the system that includes the IP. Xilinx generally provides two solutions to this

  • Generate the core that includes all the FPGA resources required for the core inside the core
    • This generally results in the simplest "example design" because all the required resources are inside the core
  • Generate the core without all the external stuff inside the core
    • Anything that is potentially shareable between multiple cores (or between this core and other things in your design) are not included inside the core, but are instead moved to the example design, which shows you how to connect the "other stuff"

The first solution is generally best for a design with a single core - the example design generally is just an instantiation of the core in a top level with no connections to anything other than ports. However, if you create a system that has four such cores, you will get four copies of everything - and some of the stuff inside these cores is not meant to be instantiated once per core, but once per system. For example, any of the main user clocks for a core will require a clock buffer for the clock. With the first style, the BUFGs for these main clocks will be instantiated inside each core. But in your full system, you may want all of these cores to share the same system clock, and hence it is illegal to have one BUFG in each core for this clock. So you have to take the more complex solution - one that moves the "shared resources" outside the core (and this is generally an option in the core generation wizard).

When you move the shared stuff out, you still get a single core and a single example design. The example design is still just an example design for instantiating one core, but since the core doesn't have the shared stuff in it, the example design now has to have the shared stuff. The net result of having a top level that looks like the example design provided by one core is no different; you still have one core and one instance of all the shared stuff. 

Now comes the complex part. If you really want to use four such cores, you need to generate four separate cores, all with the "shared stuff" external to the core. You will get an example design with each of them, which will be basically the same thing - showing you how to create a system with the instance of the core you just generated and instances of each of the shared resources you need (and how to connect them).

For your real system, you need to generate a new "top" that includes one instantiation of each of the four cores you generated, but only (maybe) one instantiation of the "shared stuff", which you then need to connect appropriately to each of the four cores. Here is where you are a bit on your own. The user guides may help you understand what each of the "shared stuff" is, which, with enough expertise, you should be able to figure out how to share it with the four cores. But each core and each element within the "shared stuff" is different (which is why there is no single tutorial that shows you how to do this). Unfortunately, you will just have to learn enough about the system to figure out how to do this.

And it has to be done right. There are some resources (like the PLL structures in the GT quads) that must be shared properly; physically there are certain resources that are bound to the quads; for some of them each GT in the quad has its own, but for others there is only one in the Quad.

Now to your specific questions:

1. Do I add the .veo or the .xci or a whole directory or 4 directories to the top (?) or just cut and paste the instantiation templates into the top level .v ? If directories, is it IP or example design directories? If files, which files specifically? If I need to cut and paste anything, what and where?

The reason you are confused is that there are many different ways of doing it. First, there different ways of generating the cores - you can generate them inside your "real" project, in which case the generated cores are already in the project structure and added to your design, so you don't need to do anything. This is (by far) the simplest method - but it is entirely manual - you must generate all the cores for each project that you intend to implement.

The other way is to generate them outside your main project (not associated with a design). Xilinx used to have the concept of an IP collection project (I don't remember exactly what it was called), but this doesn't appear to be there anymore. This was just a project that had no real "top" but was just a container for a whole bunch of IP cores. You can still do this with a "fake" project and build all your cores there. But if you do, the next part of the question is "how do you move the cores generated here (or even in multiple different fake projects) into your real project. There are multiple ways

  • Import only the .xci
    • If you import the .xci (without all the directory stuff around it) the tool will be able to regenerate the entire core directory structure from the .xci file alone
  • Import the whole core directory
    • If you import an .xci file that is still in the directory structure of the entire core, the tool can reuse the build done at the time the core was created
  • Import the "core container"
    • When you build an IP you now have the option of packaging it in a "core container" which contains the entire core hierarchy (including the .xci) in what is essentially a zip file
  • Capture the .tcl commands that were used by the IP wizard that generates the .xci (that generates the entire directory) and execute that script
  • For some cores (although this is not recommended) you can copy the RTL generated in the synthesis directory of the core and add that as a "regular" RTL file to your design

The simplest of these (these days) is probably the core container (but I haven't used them much). Again, this is if you choose to generate the core outside your main project.

Again the .veo files are never "part" of your design - they are just examples that you can use as helpers to instantiate your core into a top level design.

2. Once the designs are pasted in, how can I tell which lines in the subdesigns represent I/O ports going to pins that I have to constrain if not so identified by comment?

Each IP should generate a scoped XDC file associated with the core which should apply placement constraints to all the ports of the core (assuming these are transceiver based cores - for "general purpose" cores, like block RAMs or other things, there are no placement constraints done at the core level).

Any signal of the core that doesn't go directly to a port does not need any placement constraints. These would be going to other resources in your FPGA - either to some of the "shared stuff" or to your user logic. There is no formulaic way to recognize which is which - you need to understand the ports of the core and how to instantiate them in your top level design (based on inspiration from the example designs).

3. Equivalently, which signals are ports that I must declare differently in the top level for each port and name the same for each instance?

Same answer as above - you need to read enough documentation to understand what each of these ports are and how to instantiate them in a system.

4. Is there any difference doing this with a hard IP (eg cmac_usplus) vs a soft IP (eg aurora)?

As I mentioned, each type of core may be different. Some that have no specific physical resource requirements (i.e. no GTs or other hard macros) may not have any placement constraints inside the IP core and therefore you would be able to instantiate multiple instances of the same core. Others are bound to specific physical resources in the die and thus must have a separate core generated for each copy you need. Again, something like the output of a the RAM or FIFO generator has no specific constraints, so can just be instantiated like any other module. Others (like both of the ones you ask about above) ask you to choose specific GT resources, and hence can be instantiated only once.

So that's the best I can do. I hope it helps, but, as I said, this is not a trivial thing that has a single formula for how to do this - you need to have some knowledge of the core and the resources in the FPGA required in order to get this core running.

Avrum

View solution in original post

Highlighted
Observer
Observer
534 Views
Registered: ‎09-06-2016

Re: The question that fell in a black hole for 3 weeks and counting

Jump to solution

Thank you Avrum!  This is the most coherent answer I have received, and it does help a great deal.  I have tried adding the CMAC IP 4 times within a 'virgin' top level design, versus 4 times adding the .xci from 4 different example designs (along with different variations of adding other files or directories from the example designs which looks unnecessary from what you said).  I specified 4 different XnYm coordinates for those 4 CMAC IPs in their respective wizard session.  The IPs each autoatically got a different name as you said.

I then modified the top level design to include and have separately named instances for each of the 4 CMAC IPs, and I used the example design ports to make 4 sets of distinct port & wire names at the top for each of the 4 instances (just to get started - I do see that there is a lot more left to hook up).  Then I edited the associated signal '.gtx' port names in those instances to match the top. This almost gets through synthesis without any fatal errors, just warnings about unused signals optimized out, but also a few others being debugged that have to do with pin assignments and clocks.  

Where I seem to get most confused is what to do with the constraint files from the example designs.  They are not automatically shown in the list of constraints for the top level project design as I would have expected from the example designs after adding them.  So I thought they were forgotten or otherwise required manual addition.  If I am reading you right and reading the .xci file right, those various .xdc files are automatically used even if not listed among the constraint files.  I only need to add the 'hidden' xdc files to the constraint section for any such files where I have to edit a name or property, and those edited files will override (?).  As far as the 'quad' pins, I inferred that they will be taken care of based on where I placed things without my doing anything further as they were in the example designs.  I hope at least that much is automatic (?).

Maybe I have to edit the ...gt.xdc files to also use those port names from the top level design, not sure.  Right now I'm lost on a couple remaining error messages and reading the IP descriptions as you suggest.  I'm hoping you can take a further look at what is attached.

You answer was a big help either way.  

Steve

The_hierarchy_now.jpg
Synth_Errors.jpg
The_latest_log.jpg
Top_and_Constraint_Files_Sample.jpg
Instantiation_for Port_0_wheres_the_beef.jpg
0 Kudos