On Jul 20, 9:22=A0pm, rickman <gnu...@gmail.com> wrote:> On Jul 20, 4:51=A0am, Mike Harrison <m...@whitewing.co.uk> wrote: > > > I'm doing a project in Lattice ISPLever ( which bears uncanny similarit=ies to Xilinx ISE), which may> > end up having several product variants, and was wondering how people ty=pically handle compile-time> > build variants for different product functionalities? > > > The sort of thing that if it was C software, you'd do it easily with #i=ncludes, #defines and> > #ifdefs, but for reasons I can't understand, VHDL doesn't have anything=like these simple> > preprocessor functions. > > Although HDLs are very different from programming languages, a preproce=ssor would be equally useful> > & it seems ridiculous that nobody thought to include one in the standar=d.> > > Is there a simple way to 'add' a C style preprocessor to the build proc=ess?> > You should also look up GENERATE. =A0That is how to do actual code > "defines". =A0GENERICS only get you parameters. > > RickI may have mixed up DEFINE and something else. It has been awhile since it did C coding. GENERATE allows you to conditionally include sections of code, not just set values in contstants. GENERATE also lets you iterate on code to build multiple instances, etc. Rick
How do you handle build variants in VHDL?
Started by ●July 20, 2009
Reply by ●July 20, 20092009-07-20
Reply by ●July 21, 20092009-07-21
Charles Gardiner wrote:> So I do all the > configuration one level below. Each 'variant' has it's own top-level > entity and architecture, everything else is common.(snip)> The only module instanced in the > top-level architecture is my 'core' unit.This is _exactly_ what I did for a project that we prototyped on an eval board, and then migrated to the real hardware once it was developed. I also have a whole suite of "hobby" projects that have been ported to several different physical boards. Each "target" (PCB) has its own top-level and that instantiates the core plus a few target-specific modules for handle I/O, SDRAM, sound etc. I've also introduced a set of packages that are specific to each target(PCB), so-called platform (emulated hardware) and so-called project (software running on that hardware). It's a bit of a chore to setup for the 1st time, but it makes it _very_ easy to port projects that conform to the architecture between targets (PCBs). Less "wholesale" differences like minor build options are handled by either generics in the top-level or core modules, or alternatively in via constants in a global package. Then I use if-generate in the code. FWIW to prevent "debug" options from inadvertently creeping into production builds, I generally have a "DEBUG_BUILD" constant defined, and all (debug) build options are defined as "BUILD_OPT_X := DEBUG_BUILD and true/false". I've seriously considered using a C pre-processor for VHDL in the past. The really annoying thing is that if-generate code is always parsed, regardless if it's included or not, so you can't use it to exclude obsolete/experimental/irrelevant code without it passing elaboration for example. And if you instantiate an entity without a component declaration, then it needs to be compiled into the work library - ughh! Purists (KJ?) will of course proclaim that you shouldn't need to do such things, and that a pre-processor is entirely unnecessary. OTOH my colleague describes my coding style as "pack-rat" because I'm loathe to actually delete lines of code. Regardless, IMHO VHDL would only benefit (greatly) from such directives. Regards, -- Mark McDougall, Engineer Virtual Logic Pty Ltd, <http://www.vl.com.au> 21-25 King St, Rockdale, 2216 Ph: +612-9599-3255 Fax: +612-9599-3266
Reply by ●July 21, 20092009-07-21
Unfortunately, the generate statement only allows conditionally including concurrent statements. You must use subprograms or if- statements based on generics for conditionally executing sequential code. And while you can't conditionally declare objects, you can make unconditional declarations dependent upon generic parameters (constants can be initialized by a function call that takes a generic). Generate does allow a local declarative region for the concurrent statement(s) that are included, but those declarations are not visible outside of it. In most cases you can use a constant anywhere you could use a generic. You can use a generic anywhere you could use a deferred constant (beware locally static restrictions). With generic driven packages in the new standard, the (dis)advantages of generics vs package of constants may get more blurred. Andy
Reply by ●July 21, 20092009-07-21
On Jul 21, 6:08=A0am, Andy <jonesa...@comcast.net> wrote:> Unfortunately, the generate statement only allows conditionally > including concurrent statements. You must use subprograms or if- > statements based on generics for conditionally executing sequential > code. And while you can't conditionally declare objects, you can make > unconditional declarations dependent upon generic parameters > (constants can be initialized by a function call that takes a > generic). Generate does allow a local declarative region for the > concurrent statement(s) that are included, but those declarations are > not visible outside of it. > > In most cases you can use a constant anywhere you could use a generic. > You can use a generic anywhere you could use a deferred constant > (beware locally static restrictions). > > With generic driven packages in the new standard, the (dis)advantages > of generics vs package of constants may get more blurred.It may be convenient to use generics to control a generate which instantiates entities. -a
Reply by ●July 22, 20092009-07-22
On Tue, 21 Jul 2009 06:08:46 -0700 (PDT), Andy <jonesandy@comcast.net> wrote:>Unfortunately, the generate statement only allows conditionally >including concurrent statements.so does that mean that, for example, you couldn't use it to conditionally exclude particular case branches in a case structure?>You must use subprograms or if- >statements based on generics for conditionally executing sequential >code. And while you can't conditionally declare objects, you can make >unconditional declarations dependent upon generic parameters >(constants can be initialized by a function call that takes a >generic). Generate does allow a local declarative region for the >concurrent statement(s) that are included, but those declarations are >not visible outside of it. > >In most cases you can use a constant anywhere you could use a generic. >You can use a generic anywhere you could use a deferred constant >(beware locally static restrictions). > >With generic driven packages in the new standard, the (dis)advantages >of generics vs package of constants may get more blurred. > >AndyThe replies so far suggest to me that it could get far more complicated than it would be if a #ifdef type feature were available, which would be universally applicable to any type of construct. I've yet to look in detail but it seems like the code/project structure has to be significantly designed around the need to handle variants. ISPLever can specify pin mapping within the VHDL, so this would also provide a way to handle pinout differences between boards. I can't immediately see any way to make ISPLever select different preferences files based on a simple option - any suggestions/examples on this would be appreciated.
Reply by ●July 22, 20092009-07-22
On Jul 22, 5:09=A0am, Mike Harrison <m...@whitewing.co.uk> wrote:> On Tue, 21 Jul 2009 06:08:46 -0700 (PDT), Andy <jonesa...@comcast.net> wr=ote:> >Unfortunately, the generate statement only allows conditionally > >including concurrent statements. > > so does that mean that, for example, you couldn't use it to conditionally=exclude particular case> branches in a case structure? >Generate statements would not be used to conditionally exclude particular case branches, they can only exclude concurrent statements or instantiation of entities. I don't see much utility you would get from excluding particular case branches at all. The case conditions by definition must be - mutually exclusive - cover all cases Excluding a particular branch condition with an #ifdef would either violate the 'cover all cases' rule or force that particular branch to now follow the 'when others' default path. I haven't run across a situation where I've ever wanted to code something like that. In any case, you can still use the 'if...then' inside the case branch to branch around the code you would like to exclude. It's roughly the same amount of typing so it shouldn't be any extra work one way or the other.> > The replies so far suggest to me that it could get far more complicated t=han it would be if a #ifdef> type feature were available, which would be universally applicable to any=type of construct.> I've yet to look in detail but it seems like the code/project structure h=as to be significantly> designed around the need to handle variants. >'Far more' complicated and 'significantly designed' are relative measures that people will disagree on, one can always concoct an example that will showcase any language in either it's worst light or it's best depending on what you would like to demonstrate. You should probably consider looking a bit more in detail as well as come back with more specific examples of "code/project structure has to be significantly designed around the need to handle variants" to make the conversation a bit less abstract.> ISPLever can specify pin mapping within the VHDL, so this would also prov=ide a way to handle pinout> differences between boards.Just because it 'can' doesn't mean that you 'should' do it that way. Pin mapping specifications in VHDL are not standardized (although the method used to implement them 'attributes' is part of the language). Maybe you don't care now that this would be non-portable, but down the road you might. Pin mappings, timing requirement specifications, I/O drive strength, voltage standards, etc. are all examples of things that you 'could' specify in VHDL by using attributes (if the particular synthesis tool allows it), but they are all examples of things that you most likely should not specify this way. No matter how you cut it, a real design will have more to its specification than what you would find in the VHDL, there will always be a project file that will contain some or all of these specifications.> I can't immediately see any way to make ISPLever select different prefere=nces files based on a> simple option - any suggestions/examples on this would be appreciated.- H=ide quoted text ->Here might be your example of where upon first inspection an #ifdef might be thought to be useful since to define the pin number for a signal in VHDL you would most likely need to do this by assigning some form of pin number VHDL attribute to the I/O signal. If you have a need to do so, assigning the attribute value via a function probably is a bit clunkier than the #ifdef (not by much). The reason though that this is not really all that useful after all is - Pin numbers on physical parts never have a need to 'move'. A given board will have a given part which will have pins connected to specific other pins on that board. There will not be any reason to vary these pin numbers for a given design while also maintaining the old pin numbers. - Pin numbers are specific to a given part and the synthesis tool will need to know the target part. Where is that stored? The pin number info would best be stored in that place as well (which will be the synthesis tool's project file). - Migrating a design to a new environment (i.e. the 'variants') means either changing parts or changing the target board with different pinouts (although I would think that if the same part is plopped down on to a new board, that new board would be best off to use the old pinouts). In any case, to get to the final bitstream/JEDEC file you'll need a new project for the synthesis tool...the pinouts belong in there. Kevin Jennings
Reply by ●July 22, 20092009-07-22
On Wed, 22 Jul 2009 04:50:22 -0700 (PDT), KJ <kkjennings@sbcglobal.net> wrote:>On Jul 22, 5:09�am, Mike Harrison <m...@whitewing.co.uk> wrote: >> On Tue, 21 Jul 2009 06:08:46 -0700 (PDT), Andy <jonesa...@comcast.net> wrote: >> >Unfortunately, the generate statement only allows conditionally >> >including concurrent statements. >> >> so does that mean that, for example, you couldn't use it to conditionally exclude particular case >> branches in a case structure? >> >Generate statements would not be used to conditionally exclude >particular case branches, they can only exclude concurrent statements >or instantiation of entities. > >I don't see much utility you would get from excluding particular case >branches at all. The case conditions by definition must be >- mutually exclusive >- cover all cases > >Excluding a particular branch condition with an #ifdef would either >violate the 'cover all cases' rule or force that particular branch to >now follow the 'when others' default path. I haven't run across a >situation where I've ever wanted to code something like that. In any >case, you can still use the 'if...then' inside the case branch to >branch around the code you would like to exclude. It's roughly the >same amount of typing so it shouldn't be any extra work one way or the >other.The situation that comes to mind is a state machine where some of the cases handle debug functionality, or servicing peripheral devices which are not present in some variants Obviously 'others' will catch things that are conditionally excluded and take it to the 'idle' state.>- Pin numbers on physical parts never have a need to 'move'. >A given >board will have a given part which will have pins connected to >specific other pins on that board. There will not be any reason to >vary these pin numbers for a given design while also maintaining the >old pin numbers.Yes they will - I have a prototype running on a devboard with a 484BGA with tons of extra IOs for debug outputs, and the production board will be the same device in 144QFP. It is also quite plausible that changes in production boards need pin allocations to change for layout reasons, as the board is only 4 layer.. I would ideally like to have a single project and a simple way to flip it between 'devboard' and 'production board' mode, but it seems that this will be far from being as straightforward as it would be for a similarly 'varianted' microcontroller project.
Reply by ●July 22, 20092009-07-22
Mike Harrison wrote:> I would ideally like to have a single project and a simple way to flip it between 'devboard' and > 'production board' mode, but it seems that this will be far from being as straightforward as it > would be for a similarly 'varianted' microcontroller project.Any way I flip it, some file must be edited. -- Mike Treseler
Reply by ●July 22, 20092009-07-22
On Jul 22, 1:11 pm, Mike Harrison <m...@whitewing.co.uk> wrote:> On Wed, 22 Jul 2009 04:50:22 -0700 (PDT), KJ <kkjenni...@sbcglobal.net> wrote: > >On Jul 22, 5:09 am, Mike Harrison <m...@whitewing.co.uk> wrote: > >> On Tue, 21 Jul 2009 06:08:46 -0700 (PDT), Andy <jonesa...@comcast.net> wrote:> >I don't see much utility you would get from excluding particular case > >branches at all. The case conditions by definition must be > >- mutually exclusive > >- cover all cases > > >Excluding a particular branch condition with an #ifdef would either > >violate the 'cover all cases' rule or force that particular branch to > >now follow the 'when others' default path. I haven't run across a > >situation where I've ever wanted to code something like that. In any > >case, you can still use the 'if...then' inside the case branch to > >branch around the code you would like to exclude. It's roughly the > >same amount of typing so it shouldn't be any extra work one way or the > >other. > > The situation that comes to mind is a state machine where some of the cases handle debug > functionality,OK, so what is inherently better about this... case xyz is when Blah => #ifdef DEBUG -- Put your debug code here #end if ...etc... end case; Compared to this... case xyz is when Blah => if DEBUG -- Put your debug code here end if; ...etc... end case; where 'DEBUG' is some boolean. If instead you mean being able to put the #ifdef outside the branch like this... case xyz is #ifdef DEBUG when Blah => -- Put your debug code here #end if ...etc... end case; Then, OK the #ifdef lets you make this edit quicker. But that means either that you also have to edit the type definition to remove the 'Blah' state or leave it in and let the 'when others' pick it up and hope that this state bit synthesizes away so it doesn't cost you. The other way to code this would be... if (DEBUG and (xyz = Blah) then -- Put debug code here else case xyz is ... end case; end if; I don't see any inherent advantage in the situation you alluded to where #ifdef-ing the entire 'when xxx' statement versus using other coding styles...but you and others might disagree...that's fine.> or servicing peripheral devices which are not present in some variants > Obviously 'others' will catch things that are conditionally excluded and take it to the 'idle' > state. >If the peripherals are not there in some variants, then simply not connecting any of the output signals from the entity that produces the unneeded signals to any of the top level entity outputs is sufficient. The synthesis tool will not produce any logic to implement anything that doesn't affect an output pin.> >- Pin numbers on physical parts never have a need to 'move'. > >A given > >board will have a given part which will have pins connected to > >specific other pins on that board. There will not be any reason to > >vary these pin numbers for a given design while also maintaining the > >old pin numbers. > > Yes they will - I have a prototype running on a devboard with a 484BGA with tons of extra IOs for > debug outputs, and the production board will be the same device in 144QFP. > It is also quite plausible that changes in production boards need pin allocations to change for > layout reasons, as the board is only 4 layer.. >That would be an example of two different boards with two different parts...as I mentioned previously either of these two conditions is not an example of ever having to 'move' a signal, it is an example of two different designs. Your situation is describing two different boards that use two different parts that are intended to implement (I'm guessing) the exact same function (i.e. the same VHDL logic description). Taking that as the premise, you've got two unique designs that you need to maintain. The differences between those two design being all related to physical part differences and not (or possibly not) any logic differences. The synthesis process consists of running a tool that pulls together the following types of information in order to complete: - Target device - Device migration constraints - Logic description (i.e. the VHDL) - Pinout constraints - Timing constraints - I/O Drive constraints - Voltage standard constraints The logic description is the only thing that should be entered into the VHDL files. All of the other constraints are inherently device specific and therefore needed by the synthesis tool (i.e ISPLever), none of them belong in the VHDL files. They belong in whatever files the synthesis tool stores them in. The fact that you have two different end targets simply means that you have two different project files.> I would ideally like to have a single project and a simple way to flip it between 'devboard' and > 'production board' mode, but it seems that this will be far from being as straightforward as it > would be for a similarly 'varianted' microcontroller project.- Hide quoted text - >If the differences are only in the logic, then this can be handled pretty simply with a single project file. Synthesis tools allow you to set top level generics so to 'switch' between debug and release you would write your code to work with a generic called 'DEBUG' and then use the synthesis tool to set it however you want it today. When you get outside of logic and into the other constraints that I mentioned previously, what you really need then is something different from the synthesis tool, not the VHDL language. I kind of get the impression though that you'd like to treat all of these variants as if they were somehow really 'the same' in some sense. But in reality, each environment that a design is in (i.e. the devboard or the production board) will have their own quirks and require their own individual debug efforts and you'll likely find the designs will need to be archived properly so having separate project files and treating them like separate designs (which they really are) is a long term better approach. Bottom line is, it's just as easy to open a project file from 'File->Open...' as it is to otherwise change some setting from 'Debug' to'Release'. Kevin Jennings
Reply by ●July 22, 20092009-07-22
On Wed, 22 Jul 2009 13:16:17 -0700 (PDT), KJ <kkjennings@sbcglobal.net> wrote:>On Jul 22, 1:11 pm, Mike Harrison <m...@whitewing.co.uk> wrote: >> On Wed, 22 Jul 2009 04:50:22 -0700 (PDT), KJ <kkjenni...@sbcglobal.net> wrote: >> >On Jul 22, 5:09 am, Mike Harrison <m...@whitewing.co.uk> wrote: >> >> On Tue, 21 Jul 2009 06:08:46 -0700 (PDT), Andy <jonesa...@comcast.net> wrote: > >> >I don't see much utility you would get from excluding particular case >> >branches at all. The case conditions by definition must be >> >- mutually exclusive >> >- cover all cases >> >> >Excluding a particular branch condition with an #ifdef would either >> >violate the 'cover all cases' rule or force that particular branch to >> >now follow the 'when others' default path. I haven't run across a >> >situation where I've ever wanted to code something like that. In any >> >case, you can still use the 'if...then' inside the case branch to >> >branch around the code you would like to exclude. It's roughly the >> >same amount of typing so it shouldn't be any extra work one way or the >> >other. >> >> The situation that comes to mind is a state machine where some of the cases handle debug >> functionality, > >OK, so what is inherently better about this... > >case xyz is > when Blah => > #ifdef DEBUG > -- Put your debug code here > #end if > ...etc... >end case; > >Compared to this... >case xyz is > when Blah => > if DEBUG > -- Put your debug code here > end if; > ...etc... >end case; > >where 'DEBUG' is some boolean.Assuming this will accept a constant for the boolean, so no logic is generated when it is false, and the synthesiser doesn't complain too hard that you are including code that synthesises to nothing, it's close, except in that that the non-used case doesn't take the 'others' branch so there is some possibility it could get into a state it wouldn't get out of - of course the above could be augmented to prevent this, so I'd agree it's pretty much equivalent in practice. However if used in the neighbourhood of a complex nested bunch of If-Then's it would be a little less clear than a preprocessor style thing which is more immediately obvious as being a compile-time choice.>If instead you mean being able to put the #ifdef outside the branch >like this... >case xyz is > #ifdef DEBUG > when Blah => > -- Put your debug code here > #end if > ...etc... >end case;That's more what I was thinking>Then, OK the #ifdef lets you make this edit quicker. But that means >either that you also have to edit the type definition to remove the >'Blah' state or leave it in and let the 'when others' pick it up and >hope that this state bit synthesizes away so it doesn't cost you. The >other way to code this would be...A few extra unused states probably wouldn't be a big deal compared to the logic generated to deal with them.>if (DEBUG and (xyz = Blah) then > -- Put debug code here >else > case xyz is > ... > end case; >end if; > >I don't see any inherent advantage in the situation you alluded to >where #ifdef-ing the entire 'when xxx' statement versus using other >coding styles...but you and others might disagree...that's fine.The point was really that one construct - #ifdef etc. - could be used for pretty much all aspects that may be variable - state-machine behaviour, signal sizes, clock dividers, outputting debug data, pin assignments whatever. This seems a more logical way to do it, as the 'C' guys seem to have figured out a long tome ago.... I think the problem is that VHDL dates back before FPGAS, and ASICs don't tend to have many variants...>> or servicing peripheral devices which are not present in some variants >> Obviously 'others' will catch things that are conditionally excluded and take it to the 'idle' >> state. >> >If the peripherals are not there in some variants, then simply not >connecting any of the output signals from the entity that produces the >unneeded signals to any of the top level entity outputs is >sufficient. The synthesis tool will not produce any logic to >implement anything that doesn't affect an output pin.there may be input-only peripherals, and you may want to make sure no logic is generated as that variant may have alternative functionality that needs the space. The particular design I'm considering is going to end up in the smallest EC1 device and so this may be an issue.>> >- Pin numbers on physical parts never have a need to 'move'. >> >A given >> >board will have a given part which will have pins connected to >> >specific other pins on that board. There will not be any reason to >> >vary these pin numbers for a given design while also maintaining the >> >old pin numbers. >> >> Yes they will - I have a prototype running on a devboard with a 484BGA with tons of extra IOs for >> debug outputs, and the production board will be the same device in 144QFP. >> It is also quite plausible that changes in production boards need pin allocations to change for >> layout reasons, as the board is only 4 layer.. >> > >That would be an example of two different boards with two different >parts...as I mentioned previously either of these two conditions is >not an example of ever having to 'move' a signal, it is an example of >two different designs.Two different designs that share the same subset of functionality, which should also share the same source files, to minimise the effort switching between them/.>Your situation is describing two different boards that use two >different parts that are intended to implement (I'm guessing) the >exact same function (i.e. the same VHDL logic description). Taking >that as the premise, you've got two unique designs that you need to >maintain. >The differences between those two design being all related >to physical part differences and not (or possibly not) any logic >differences. The synthesis process consists of running a tool that >pulls together the following types of information in order to >complete: >- Target device >- Device migration constraints >- Logic description (i.e. the VHDL) >- Pinout constraints >- Timing constraints >- I/O Drive constraints >- Voltage standard constraints> >The logic description is the only thing that should be entered into >the VHDL files. All of the other constraints are inherently device >specific and therefore needed by the synthesis tool (i.e ISPLever), >none of them belong in the VHDL files. They belong in whatever files >the synthesis tool stores them in.Wherever they belong, the ability to easily switch versions would make things a whole lot easier.>The fact that you have two different end targets simply means that you >have two different project files. > >> I would ideally like to have a single project and a simple way to flip it between 'devboard' and >> 'production board' mode, but it seems that this will be far from being as straightforward as it >> would be for a similarly 'varianted' microcontroller project.- Hide quoted text - >> > >If the differences are only in the logic, then this can be handled >pretty simply with a single project file. Synthesis tools allow you >to set top level generics so to 'switch' between debug and release you >would write your code to work with a generic called 'DEBUG' and then >use the synthesis tool to set it however you want it today. When you >get outside of logic and into the other constraints that I mentioned >previously, what you really need then is something different from the >synthesis tool, not the VHDL language. > >I kind of get the impression though that you'd like to treat all of >these variants as if they were somehow really 'the same' in some >sense. But in reality, each environment that a design is in (i.e. the >devboard or the production board) will have their own quirks and >require their own individual debug efforts and you'll likely find the >designs will need to be archived properly so having separate project >files and treating them like separate designs (which they really are) >is a long term better approach. > >Bottom line is, it's just as easy to open a project file from 'File- >>Open...' as it is to otherwise change some setting from 'Debug' to >'Release'. > >Kevin JenningsI will need to look further into what can be done with the project system - I'm fairly new to this, need to get something working in a hurry but am conscious that there will be variants in the future. The IDE and number of files created by my (currently) two source files (VHDL and prefs) is somewhat bewildering - hopefully when I've got this prototype running I'll have time to sit down with all the documentation.... It just seems to me from a 'common sense' viewpoint that although the processes of compiling a C program and syntesising for an FPGA are very different, the requirements for managing variants are almost identical, so a means of doing it in the same way would seem to be a sensible way to do it. A preprocessor which preprocessed all source files in a project, be they VHDL, pin mappings, timing constraints, memory contents in a uniform fashion just seems to be an obvious way to do it... Of course I realise that all FPGA tools have a great deal of 'history' dating way before FPGAs, and everything is now probaly just too ingrained and hard to change to suit the current state of the art. Sort of like QWERTY keyboards....





