work around VHDL's lack of a preprocessor - Page 1
Forum section: electronics / general

author: Bassman59
author_rank: Super Contributor
timestamp: September 23, 2021, 12:04:21 am
content: In all of my years doing VHDL I've never needed a preprocessor. Until now.I am working on a command parser that is meant to be used on a number of design variants. For the most part, the commands set (and get) parameters. Each variant implements most of the commands, but there are a handful of things used by one variant which don't exist in the others. The command space is 256 possible entries, of which most are not implemented.Something higher up provides a command token along with an argument. After parsing the command, a response is sent to the higher up.All of the various parameters are wrapped up into a nice record type. This makes the entity's port list manageable, and it also makes it straightforward to have variant-specific parameter lists: just define the record type with the parameters needed. There is no need to change the parser entity port list.The command parser boils down to a big case statement, with the command token as the selector. Any commands not implemented fall through the "when others" and the response to higher up indicates "not implemented."Here's the rub. Like I said, each variant has some special commands which don't exist in the other variants. It Would Be Nice if there was a C-style pre-processor which can exclude certain lines from analysis. VHDL-2008 does not have such a feature. (The good news is that it has been added to VHDL-2019, but I expect to be well into retirement by the time the tools support it.)Is there a "good" way of excluding, at compile time, individual "when" entries in the case statement? The reason is that if a parameter is not defined for a variant, then it's not in the record type and you can't have it appear at all in the "when" section. Some code:Code:Decoder : case token iswhen CMD_XYZ =>-- VARIANT is a generic:if VARIANT = THIS_ONE then-- XYZ is in the THIS_ONE version of the params record, but not in any otherparams.XYZ <= argument;response <= HANDLED;elseresponse <= NOT_IMPLEMENTED;end if;when others =>response <= NOT_IMPLEMENTED;In CMD_XYZ the analyzer will always consider both the true and the false conditions, so even if VARIANT is not THIS_ONE, the analyzer expects params.XYZ to be defined. Like I said, a pre-processor is the simple solution.I suppose the workarounds are:1. Have an architecture for each variant, which is selected in the usual way at instantiation of the entity, or2. Write what I did in the example, and actually include all of the possible parameters even if not used, and assume the synthesizer will optimize away the actual assignments to the unused parameters. Remember VARIANT is a generic and THIS_ONE is a constant.There's an added complication: all of these parameters get written to non-volatile storage and that's a somewhat precious resource and I'd rather not waste space in it for parameters that are not used.Please don't say "Use SystemVerilog" even if that language has such support!Hope this is clear enough and makes sense ...

author: Someone
author_rank: Super Contributor
timestamp: September 23, 2021, 04:24:49 am
content: What you described (propagating a constant to prune conditionals/states) works ok, by wrapping it in if's at that level makes it clearer to the tools. Messy code but gets the job done.An alternative would be to make the tools realise some of the literals of the enum aren't possible on the case expression (state machines are pruned/optimised like this). A function in the package declaring the enum that takes all the possible inputs and translates it to the set implemented in that variant?

author: AaronLee
author_rank: Regular Contributor
timestamp: September 23, 2021, 05:51:52 am
content: Coming from the world of programming in C and other languages, VHDL is in desperate need of a preprocessor in my opinion. In C, you can, for example, comment out a section of code with '/*' and '*/'. Or you can define macros to conditionally enable/disable sections of code. I found from day one of learning VHDL how inadequate it is without a preprocessor, but have no choice when the company/customer require it to be written in VHDL. Perhaps someone has written a preprocessor for VHDL to do those things, but unfortunately even if it existed, it's likely not integrated with the development environment, nor is standard VHDL (before the preprocessor) and to which the company/customer would likely complain being it wouldn't be readable by other engineers.

author: Just_another_Dave
author_rank: Regular Contributor
timestamp: September 23, 2021, 07:15:12 am
content: There is a project called vhdlpp which allows to configure VHDL code before synthesizing it. Itseems quite similar to cppmake:http://vhdlpp.sourceforge.net/READMENevertheless, generics are normally the recommended way of achieving that, as they avoid problems that copypasting a macro could cause

author: brucehoult
author_rank: Super Contributor
timestamp: September 23, 2021, 08:21:56 am
content: What's wrong with just having your build system run the actual C preprocessor?

author: paf
author_rank: Regular Contributor
timestamp: September 23, 2021, 09:31:12 am
content: From the web page:VHDLproc is a simple command line VHDL preprocessor written in Python following the conditional compilation directives outlined in VHDL-2019, with a few extensions.https://github.com/nobodywasishere/VHDLprocSo, this may give you the macro extensions of VHDL-2019, without VHDL-2019. Disclaimer: I have not tried it.Other suggestions may be valid or not, depending on the languages you may already know, like or want to know more.M4 -- is present on all Unix machines, and is useful for other things.https://www.gnu.org/software/m4/manual/index.htmlhttps://mbreen.com/m4.htmlIn TCL you have these two preprocessors:G2http://users.telenet.be/koen.vandamme1/c_tools/g2/_index.htmExpandhttps://wiki.tcl-lang.org/page/expandI have used the first, to pre-process Verilog.Jinja -- in Pythonhttps://jinja.palletsprojects.com/en/3.0.x/Free Marker -- in Javahttps://freemarker.apache.orgYou have lots of choices.

author: Bassman59
author_rank: Super Contributor
timestamp: September 23, 2021, 02:54:36 pm
content: Quote from: AaronLee on September 23, 2021, 05:51:52 amC-style block comments /* */ are actually already included in VHDL-2008 -- see LRM section 15.9. It's easy enough to select a block of code and do C-c C-c in emacs, though. But that doesn't solve my problem, which is to be able to include or exclude blocks of code within a process at analysis time.For my purposes, my company has no particular style requirements, so I can use whatever I want, as long as I document what I'm doing. (Mainly soIremember what the hell I did.)

author: Bassman59
author_rank: Super Contributor
timestamp: September 23, 2021, 02:57:07 pm
content: Quote from: brucehoult on September 23, 2021, 08:21:56 amTo be honest, I hadn't thought about that, although the build environment is basically the vendor tools.

author: Bassman59
author_rank: Super Contributor
timestamp: September 23, 2021, 03:03:00 pm
content: Quote from: Just_another_Dave on September 23, 2021, 07:15:12 amThat "preprocessor" seems to be just a way to cleverly comment-out code.Generics should drive the process (not the VHDL process) of determining what gets included and excluded. But the usual way of doing that is to have generate statements which use the generics, and that works well for things like replicating entity instances and blocks of code, all sorts of things. But generates don't work within a process.

author: Bassman59
author_rank: Super Contributor
timestamp: September 23, 2021, 03:08:18 pm
content: Quote from: paf on September 23, 2021, 09:31:12 amOh, wow, that looks like it might be the ticket! I'll play with it and report back. This is especially interesting because it won't require any source code changes once the tool vendors finally decide to support VHDL-2019 (in like 20 years).QuoteMy first and last time looking at M4 macros was a zillion years ago when I looked (very briefly) at possibly using gEDA for schematics and PCB layout. I think they used M4 macros to define footprints. I cannot imagine a less user-friendly way to do that.gEDA was such a disaster and the developers were so openly hostile to suggestions that I ignored it. Anyway.QuoteI'll look at those, thanks.

author: Bassman59
author_rank: Super Contributor
timestamp: September 23, 2021, 03:50:17 pm
content: Quote from: Someone on September 23, 2021, 04:24:49 amI'm not sure what that function is supposed to do?Remember the thing is a command decoder, and each command basically updates signals used elsewhere in the design. By this I mean: the TRIGGER command asserts a trigger strobe to the data-capture machine. The SET_TEMPERATURE command loads a DAC used as a temperature set-point. The rub is that for example SET_PARAMETER_FOO, which updates a parameter called FOO, exists only in variant A, not in B, C or D.After thinking about this overnight, if I can't get that VHDL-2019 pre-processor Python thing to work, I will just bite the bullet and declare the parameter record to hold all parameters that exist in all variants, and then use a generic to gate on commands which exist in a given variant. After the synthesizer gets through with the code, the unused stuff will get optimized away, with a host of red warnings in the report. The memory map for the parameters in the non-volatile storage will have some holes in it for one variant or another (the map itself is the same for all variants), but that's fine. It's not like I have a thousand parameters to manage.

author: SiliconWizard
author_rank: Super Contributor
timestamp: September 23, 2021, 05:06:55 pm
content: Yes, the only way of doing this in VHDL is to use "if" statements as you did.When the "if" clause is known at compile-time and is false, the corresponding code will just get pruned. Likewise, any signal (including record members) that is not used in a design will get pruned. So this is the exact equivalent of a preprocessor.What would a preprocessor bring here?One thing to realize is that many features of VHDL, when they can be evaluated at compile-time, are actually equivalent to preprocessing - just much better.

author: blacksheeplogic
author_rank: Frequent Contributor
timestamp: September 23, 2021, 09:43:08 pm
content: Quote from: brucehoult on September 23, 2021, 08:21:56 amIt's really going to depend on what you are allowed to get away with changing:I've done this in the past when I have needed a pre-processor, for example an assembler that did not support include files. I've also needed to write my own pre-processors which are typically very simple programs. But you also need to either modify a default build rule which I don't like doing or add a build rule + dependency to the makefile which may also require modifying the dependency generator and if you are using a source editor with syntax support you may need to modify your editors config as well. On large projects it may not be possible to change the build procedures and at least the build teams I have worked with could best be described as change adverse. I've checked in the processed source files and just kept the custom build tools within the team in these cases.It can also piss off other developers when you change the build tools especially if you change a tool for example create your own make. Don't expect other developers to ever read readme.txt.

author: Someone
author_rank: Super Contributor
timestamp: September 23, 2021, 10:49:03 pm
content: Quote from: Bassman59 on September 23, 2021, 03:03:00 pmYou might be limiting your scope/applications of generics thinking of them this way. They are a fancy constant, that can be set at compile time to differentiate the entity from other instantiations (be that within the same project, or between projects, or at different times, etc, etc).Quote from: Bassman59 on September 23, 2021, 03:50:17 pmYou need a function/assignment/process that the tools recognise will only ever have a subset of the "states" of the enum coming out of them. Think of it as the next step after constant propagation, set reduction/pruning. I've not tested this for the general sense, but the major tools are certainly doing this for state machines (particularly when spread across multiple processes). They know which states are unused in a case select and optimise them out automatically.

author: Bassman59
author_rank: Super Contributor
timestamp: September 24, 2021, 02:10:51 am
content: Quote from: Someone on September 23, 2021, 10:49:03 pmOh, believe me, I love to use generics for many things. I use them for setting part revisions and beta build constants (as read back over some communications link). I use them to set clock division ratios for, say, an SPI peripheral. If it's a constant that I might want to override, I make it a generic!QuoteOhhh, wait, I think I am getting the idea!Let's begin with my command parser description. I create an enumeration that defines all possible command tokens for all design variants. A signal of that type is the case expression. (Just like a state machine.) Each entry in the enumeration is a selector in the case statement. Each selector drives some signals. This case statement therefore covers all possible design variants.Even if a particular variant will never get some of the defined commands (this is guaranteed because I control both sides of the command-sending pipe), the selectors for the commands will still exist. Now if there is nothing connected to those signals (this is in the variant-specific code), then we might assume that the tools will recognize this and work backwards and ultimately optimize away the case selector.But the problem is that in the system, every command sent to the FPGA gets a response back. Unimplemented and undefined commands get a response that says, "not supported!" (Again, because I control both ends of the communications, undefined commands are never sent ... but we should be prudent and define what happens when such an event occurs.)It is because of the requirement that a response is returned that I have to work out what happens if the unimplemented for this variant command is mistakenly sent.So then what is needed is a "prescreener" function: the input is the command token. The function has a variant-specific mechanism (lookup table?) that replaces unsupported commands with a default "not implemented" command. If the command is supported, the output is the input command. This lookup is all a ROM made at compile time. The output of this function is used as the case expression. (I think VHDL-2008 even allows for the function call to be part of the case expression; if not, whatever, I'll make an intermediate signal.)Aside: I think I can use a package generic to choose which variant's lookup table is used in that function. The function will be in the same package.Will it result in the unpossible command selectors being optimized away? There's only one way to find out: code it and synthesize it, which will be project for tomorrow.

author: SiliconWizard
author_rank: Super Contributor
timestamp: September 24, 2021, 07:42:12 pm
content: In synthesizable code, functions and procedures in VHDL can only be evaluated at compile time - thus when properly used, they give fancy preprocessing features.Then, outside of processes, you can use 'generate' blocks. (if generate / for generate). They also give you the equivalent of a conventional preprocessor. You can't use them inside a process though, so in this context, you can use 'if' statements as I said above - if the clause is known at compile time, this will be equivalent to preprocessing - and also functions and procedures.With all this, I actually almost never see a need for an additional preprocessor.

author: nctnico
author_rank: Super Contributor
timestamp: September 24, 2021, 11:19:39 pm
content: The 'generate' statement is the way to get this kind of things done.Using the 'if' statement is just as messy as littering C code with #ifdefs. It doesn't result in code that is very maintanable so some restructuring needs to be done to have a better isolation between the variants. Perhaps using an array with initialised value pairs that defines the behaviour of each while using generic code is a way to deal with the problem.

author: Someone
author_rank: Super Contributor
timestamp: September 25, 2021, 02:11:58 am
content: Quote from: SiliconWizard on September 24, 2021, 07:42:12 pmThat might be a bad use of the term "evaluated", since both functions and processes are synthesiseable and used to produce complex combinatorial results (the majority of ieee packages are functions alongside operator overrides which are functions themselves). So they are most certainly evaluated at runtime.Things that are only evaluated at compile time are called static.Quote from: nctnico on September 24, 2021, 11:19:39 pmExcept generate is restricted in scope, so cant be placed inside the case select. At which point the OP would be replicating/cut/pasting the different variants of their case select into different generate clauses (no else on generate!). Its absolutely the wrong way to do it, the if statements with constants to gate them is much more maintainable/readable since the common parts are repeated in separate lines. Perhaps you could provide an example following the OPs excellent post with their sample code....

author: SiliconWizard
author_rank: Super Contributor
timestamp: September 25, 2021, 05:15:07 pm
content: Quote from: Someone on September 25, 2021, 02:11:58 amNope nope. This was a carefully choosen term here.You show a misconception of what functions and procedures are in VHDL, or you just didn't understand or even read what I wrote. When synthesized, they can ONLY be evaluated at compile-time. They always yield static logic structures that reflect their behavior. That's why, for synthesis, they act as preprocessing and nothing else.But reading your paragraph, I'm pretty sure you didn't understand what I said and just took it as a way of saying functions and procedures have no use for synthesis, which is pretty much the opposite of what I said.They are indeed "evaluated" at compile-time for synthesis. Only for simulation they can be evaluated during run-time. Evaluated at compile-time for synthesis means: they yield static logic at compile-time. Always. That didn't mean they can't take signals as inputs, for instance. Yeah, re-reading what you said convinces me you thought I meant that they could only be used with constants, and not signals or variables.Thus, for synthesis, they can be seen as templates. This is the closest parallel I can think of with software.Once you understand this, what is synthesizable and what isn't when using functions and procedures becomes almost obvious.

author: nctnico
author_rank: Super Contributor
timestamp: September 25, 2021, 06:14:23 pm
content: Quote from: Someone on September 25, 2021, 02:11:58 amI already wrote that in the part you snipped: use table driven case statements to make functionality optional without littering the code with ifs. But the OP's example is probably just an example. And you don't need to make things complicated or replicate code; just think & do research a bit longer about how to structure code to suit the problem the best instead of getting behind the keyboard and start writing code into a dead end street. Maybe -as SiliconWizard wrote- functions and procedures can also help to un-spaghetti the code.

author: asmi
author_rank: Super Contributor
timestamp: September 25, 2021, 07:11:44 pm
content: LOL you guys as always went deep into the woods in your attempts to defend that POS of a languageAs I understood, what OP wants is this (code in C so that even VHDLers would understand):Code:switch (op){case OP_FOO://handing operation FOObreak;case OP_BAR://handing operation BARbreak;#ifdef OP_EXTENDED_1_SUPPORTEDcase OP_EXTENDED_1://handing operation OP_EXTENDED_1break;#endif#ifdef OP_EXTENDED_2_SUPPORTEDcase OP_EXTENDED_2://handing operation OP_EXTENDED_2break;#endifdefault://handing unknown operationbreak;}Important point is that OP_EXTENDED_x opcodes are treated as unknown ones if such support is disabled. Now please show us how to implement this trivial code. And no, a bunch of generate's with copy-pasted switched for all possible permutations of supported opcodes is not acceptable.So yes, "use SystemVerilog" is the only sureway solution to avoid having to deal with this garbage again.

author: nctnico
author_rank: Super Contributor
timestamp: September 25, 2021, 07:25:45 pm
content: One way: make a component for the body of each case statement. That component's contents can have a generate statement that creates output based on what is being generated. There is zero code replication. In fact, closely related functions can be implemented using the same component.

author: asmi
author_rank: Super Contributor
timestamp: September 25, 2021, 07:40:38 pm
content: Enough talk, show us the code already! The C code I've posed above can be transferred into SystemVerilog pretty much in exact same form with no trickery required, so please show us how to achieve the same thing in VHDL.

author: SiliconWizard
author_rank: Super Contributor
timestamp: September 25, 2021, 08:13:51 pm
content: Quote from: nctnico on September 25, 2021, 07:25:45 pmWhy not, but this would be unnecessarily heavy.Again, just using "if" with a constant clause is guaranteed to be optimized. This is one of the most basic optimizations possible. No need to question that.

author: nctnico
author_rank: Super Contributor
timestamp: September 25, 2021, 08:28:38 pm
content: Quote from: asmi on September 25, 2021, 07:40:38 pmActually you can but you'd use a plain if instead of #ifdef. You basically insist on using #ifdef while there is a VHDL language construct (namely the 'if statement') that does exactly the same from a functional point of view when the condition is based on a constant. The OP's question however seems to be how to create nicer looking code that isn't littered with a whole bunch of ifs and #ifdef doesn't make things any nicer. Take note of SiliconWizzards remark about how and why a synthesizer is already doing the same as the C pre-processor. VHDL code that is never used, is optimised away so why insist on adding an extra layer to the language that does the same?

author: SiliconWizard
author_rank: Super Contributor
timestamp: September 25, 2021, 09:09:51 pm
content: But yes, if the point is making the code look "cleaner" with fewer if's, then you can structure your code differently. Not sure going through hoops is worth it for the example the OP gave though.But sometimes you have groups of 'when' clauses depending on a given contant/generic inside a 'case' statement, and using a 'if' for each is clunky. Grouping would look tidier (and probably less error-prone).I sometimes do that by splitting a 'case' into several 'case', each guarded by an 'if'. With the VHDL rule for a sequence of statements, this works fine.Such as, taking the OP's example:Code:response <= NOT_IMPLEMENTED;if VARIANT = THIS_ONE thenDecoder_THISONE : case token iswhen CMD_XYZ =>params.XYZ <= argument;response <= HANDLED;when ... =>...when others =>end case;end if;if VARIANT = OTHER_ONE thenDecoder_OTHER_ONE : case token iswhen CMD_SOMETHING =>...response <= HANDLED;when ... =>...when others =>end case;end if;You get the idea.

author: asmi
author_rank: Super Contributor
timestamp: September 25, 2021, 10:54:32 pm
content: Quote from: nctnico on September 25, 2021, 08:28:38 pmThat's more talking, while I still don't see the code. Please show us the version of a code for my example above. Remember, there are four possible cases as each of EXTENDED_OPs can be enabled or disabled independently. This is a quite common use case, so there's got to be a way to make it happen.

author: Someone
author_rank: Super Contributor
timestamp: September 26, 2021, 12:36:27 am
content: Quote from: SiliconWizard on September 25, 2021, 05:15:07 pmStatic is a strictly defined term in VHDL (the language) so you cant just redefine and reuse it how you like. Evaluated is not strictly defined but most people would understand it to mean the inputs are parsed to produce the output. Elaboration is probably where you were headed, but your refining/misunderstanding of terms makes your contributions incoherent.

author: SiliconWizard
author_rank: Super Contributor
timestamp: September 26, 2021, 01:57:47 am
content: Quote from: Someone on September 26, 2021, 12:36:27 amLet's not uselessly pollute this thread please.I'll just reply to this: 1/ that my use of 'static' here was strictly in "static logic structure", which had nothing to do with the "static expressions" which is the only thing defined in the VHDL standard related to the word 'static'. One may object that 'static' here would be sort of redundant, as synthesis tools can only generate a static logic structure anyway. Static as in fixed. 2/ That if anything, the term of "compilation" I used could have been questioned, as it's not how the VHDL standard defines how VHDL input is processed - it talks about analysis and elaboration. But almost anyone using HDL routinely talks about "compilation", including tools vendors. Then whether it actually happens during analysis or elaboration, probably nobody cares here, unless you're writing VHDL tools. Point is, again, (was it really not clear?) that functions and procedures in the context of synthesis are nothing but fancy preprocessing - which was the whole point all along.

author: BrianHG
author_rank: Super Contributor
timestamp: September 26, 2021, 02:26:16 am
content: @Bassman59, have you test compiled placing an 'IF (option_parameter)' inside the optional cases VS selecting 2 groups of functions?I know in SV, when test compiling two similar scenarios, as long as it is a parameter or fixed value, the compiler prunes out the unused logic and ends up generating A or B as if I wrote out a single selected case group.The other option is a 2 dimensional case, the outer being the 'option_parameter' and the compiler still simplifies/prunes down the logic to A or B. The case where this simplification doesn't happen is if the 'option_parameter' is a variable logic input instead of a parameter constant, or hard wired high or low.

author: Someone
author_rank: Super Contributor
timestamp: September 26, 2021, 02:52:32 am
content: Quote from: SiliconWizard on September 26, 2021, 01:57:47 amFunctions are functions as defined by the language, their implementation is important to keep in mind but its much clearer in VHDL than in some other languages. In VHDL functions are evaluated at execution ("runtime") and not limited to evaluation at compile time.Restricting the design at compile time is one of the significant differences in HDL design vs normal software development, as the FPGA resources are typically scarce/precious. You keep flamingyourpoor communication:Quote from: SiliconWizard on September 24, 2021, 07:42:12 pmNo, functions are still able to be evaluated/executed after compilation. You said only, I left you ample room to be gracious, but you just dig in.

author: Someone
author_rank: Super Contributor
timestamp: September 26, 2021, 03:15:44 am
content: Quote from: Bassman59 on September 24, 2021, 02:10:51 amCant wait to hear the result! Since you are chasing that implementation concept, I took another to test out:Quote(get stuffed scrolling "code" box)The if in the function is a little inelegant with its verbose range indexing, but the optimization rips through it and does what you were asking for in the original post. Most of the declaration above can be pushed back into a suitable package and it ends up quite nice to use.

author: nctnico
author_rank: Super Contributor
timestamp: September 26, 2021, 11:14:42 am
content: The problem the OP has is a code structuring one. First thing that needs to be done is for the command handling part to always support all commands (so the enumeration needs to be complete with all commands). Secondly a layer (translation table, function, whatever) needs to go between the input and command processing. That layer uses the variant type to check if a certain command is supported or not. This likely takes some restructuring of the code but that advantage is that determining which commands are supported by what type is in 1 location. This will help to keep code maintainable.@Someone: it is better when your function returns an enumeration. Then the synthesizer can decide what kind of encoding is the most efficient.

author: asmi
author_rank: Super Contributor
timestamp: September 26, 2021, 11:29:49 am
content: Quote from: nctnico on September 26, 2021, 11:14:42 amThat's more useless talk. Show us the code already!

author: nctnico
author_rank: Super Contributor
timestamp: September 26, 2021, 11:55:32 am
content: Quote from: asmi on September 26, 2021, 11:29:49 amStop trolling and do your own homework. Maybe you can add something useful to this thread instead of trying to bait people into yet another VHDL versus systemVerilog thread. The OP uses VHDL and needs a solution that is written using VHDL.

author: asmi
author_rank: Super Contributor
timestamp: September 26, 2021, 12:23:00 pm
content: Quote from: nctnico on September 26, 2021, 11:55:32 amThere is no trolling. Show us the solution already. Or admit that there isn't one. Empty talk doesn't help anyone over here.

author: Bassman59
author_rank: Super Contributor
timestamp: September 26, 2021, 07:39:24 pm
content: Quote from: asmi on September 25, 2021, 07:11:44 pmWell, despite being a VHDL partisan with an allergy to all things Verilog, I will state that what asmi writes above isexactlywhat I want.I will again note that VHDL-2019 actually supports this, but like I said, I expect tool support for VHDL-2019 to arrive sometime after the universe has gone cold and shrunk back into a pea-sized lump of coal.And that still won't make me switch to SystemVeriilog.

author: Bassman59
author_rank: Super Contributor
timestamp: September 26, 2021, 07:40:26 pm
content: Quote from: nctnico on September 24, 2021, 11:19:39 pmGenerate does not work within a process. Come on, this is freshman VHDL.

author: Bassman59
author_rank: Super Contributor
timestamp: September 26, 2021, 07:41:17 pm
content: Quote from: nctnico on September 25, 2021, 07:25:45 pmYou can't instantiate an entity within a process.It's the same problem as trying to put a generate within a process.

author: nctnico
author_rank: Super Contributor
timestamp: September 26, 2021, 07:55:39 pm
content: Quote from: Bassman59 on September 26, 2021, 07:41:17 pmDon't get too hung up on details; you can use a function or procedure as well. I'm just trying to help you while juggling a boat load of other projects in my mind (none of them dealing with VHDL so forgive me for not having that clear). However, looking at the big picture I see that the root of the problem is the overall structure of how you organised your code.

author: Bassman59
author_rank: Super Contributor
timestamp: September 27, 2021, 05:47:41 am
content: Attached is an archive of a small test design I hacked up to test the two suggested methods of implementing a command parser that has a way of not firing the case selector for commands we'd like to disable. As a side effect of disabling a command, a signal assigned in that select should also get optimized away if it is not referenced in higher-up code.For purposes of discussion, the design has three variants: DEFAULT, A and B. In the default, all commands are handled. In A, some commands are disabled. In B, the other commands are disabled. The variant is set with a generic at the top level.A command sets or clears an output, depending on the bit in the argument. If the command is valid, the signal cmd_ok is strobed. If the command is invalid (because it is disabled) the signal cmd_nok is strobed.The two methods of disabling commands are:1. a function is used to "filter" out invalid commands, based on the variant chosen. Commands not handled are "invalid." In the parser case statement, all possible commands are listed as selectors, but the commands not handled in a given variant have been "remapped" by the parser to the invalid command, so their selectors are never invoked.2. in each case selector, if the variant chosen allows the command, it is handled: the output bit is assigned and cmd_ok asserted, otherwise the output signal is ignored and cmd_nok is asserted.The source code is three files.cmd_pkg.vhdl defines a few useful types and two functions. One function handles that remapping and outputs an enumerated type. The other simply converts the std_logic_vector command to that same enumerated type.parser.vhdl is the parser. It has two architectures: one, called "filter," uses the filter method described above to get the case expression. The other, "nofilter," does as #2 described above and tests each case selector to see whether it should be handled in the chosen variant.top.vhdl holds six different top-level entities. Three are for the "filter" parser, with variants default, A and B, and three are for the "no-filter" parser. This could have been boiled down to just two entities, filter and no filter, but the synthesizer doesn't allow setting a generic with an enumerated type from the command line. Please note: the top-level entities do not have the signals assigned in "unused" command case selectors. My real design is like that -- those signals simply don't exist.In the synthesis directory is a Synplify Pro project file. I used the version of Synplify that ships with Lattice Diamond 3.12, which is Q-2020.03L-SP1.(Interestingly,this version of Synplify claims to support VHDL-2019's conditional analysis feature -- the preprocessor! But, I didn't test it, because the point was to test how a synthesizer would handle the test cases.)The project includes the three source files and has two implementations: "top_A_nf" and "top_A_f," for variant A with no filter function and with the filter function. The target is a MachXO2-1200, chosen for no good reason. The correct top level entities are chosen for both.And the results:In the filter version, the only obvious synthesis warning is for some input bits not being used. These bits would be assigned to output bits if the command wasn't filtered out. In the non-filter version, the output bits that are not used because their commands don't exist are never assigned, so we're told that. (also the same input-not-used warning is here.)Let's look at the synthesis outputs.Here is the RTL schematic of the "filtered command" parser. (The top level schematic is nothing more than ports connected to the parser.) It's down to three flip-flops for the outputs that are enabled (E, F, G) and two more for the OK and NOK flags. The command was turned into a one-hot vector, so three valid commands mean three command bits which are ANDed and drive the flops' enables. Clearly the filter did its job, there is no logic at all for the disabled commands.Here is the RTL schematic for the "no filter" parser. It's all just ... more complicated.Now the fun ... the optimized schematics. The top level schematics are the same for both versions, so I'll post only one (the "filter" version):The parser schematic is highly the same for both versions. Both have one LUT per output (five outputs: three E, F, G flag bits, and the two OK/NOK bits). How the LUTs are configured are slightly different, but they boil down to the same exact resource usage, and of course they are functionally identical. Here is the "filter" parser schematic:CONCLUSION!Both styles result in the same resource use for this example. The signals associated with disabled commands are optimized away, as are the decoders for those commands. This is ultimately what I wanted.So the question is, which should I (we, you) use? Possibly a matter of preference.I will give an edge to the "no filter" version, where the test for whether the command is enabled is in the decoder selector. Why? Because in my design, the number of commands that are common to all variants is much greater than the number of variant-specific commands. It's a lot more obvious to see what's going on if you put the "if VARIANT = THISONE" in the handful of case selectors that care, rather than to bury the command disable/enable in a function in a package in a different source file. We all like to write code that is very obvious to the reader, right? Of course we do!I hope this was enlightening, and it shows that we don't need no stinkin' preprocessor! All we need to do is to just ignore a few synthesis warnings about signals not being used or being optimized.

author: asmi
author_rank: Super Contributor
timestamp: September 27, 2021, 11:41:49 am
content: Quote from: Bassman59 on September 26, 2021, 07:39:24 pmIn my experience people use VHDL because they are too old/too lazy/too stubborn to learn SystemVerilog. I'm yet to meet a person who learned both languages and voluntarily chose VHDL over SV.So I'll hazard a guess that all these "allergies" are just a lousy coverup for good old laziness.

author: Just_another_Dave
author_rank: Regular Contributor
timestamp: September 27, 2021, 12:29:49 pm
content: Quote from: asmi on September 27, 2021, 11:41:49 amWell, in Europe VHDL is used because it is the language that most companies ask for in their job offers. Therefore, it is the language that universities usually teach in their EE degrees. Consequently, it is better to focus your efforts on learning about dynamic reconfiguration of FPGAs, reliability, IC design, etc. than learning another language

author: asmi
author_rank: Super Contributor
timestamp: September 27, 2021, 12:38:39 pm
content: Quote from: Just_another_Dave on September 27, 2021, 12:29:49 pmYou still got to learn both at least to some degree because chances are you are going to have to work with third-party IPs written in another language. So you can only really ignore other languages if you are a hobbyist and can afford to roll your own, in professional setting you will have to deal with both.But I was talking about personal choice given both options are on the table. I've never met a VDHL person who also knows SystemVerilog well, but I've met a plenty of SV people which also know VHDL.

author: Just_another_Dave
author_rank: Regular Contributor
timestamp: September 27, 2021, 01:07:31 pm
content: Quote from: asmi on September 27, 2021, 12:38:39 pmMaybe it is something related to the type of applications that they design, but the companies for which I have worked for didn’t allow us to use any IP programmed in a different language to VHDL

author: asmi
author_rank: Super Contributor
timestamp: September 27, 2021, 02:31:23 pm
content: Quote from: Just_another_Dave on September 27, 2021, 01:07:31 pmI guess so, in my experience (admittedly not very long) I had to deal with third-party components written in all languages - regular Verilog, and VDHL. While I prefer SV, but I know enough of other languages to read and understand the code, and do some debugging if integration doesn't work like it should.

author: Bassman59
author_rank: Super Contributor
timestamp: September 27, 2021, 02:44:02 pm
content: Quote from: asmi on September 27, 2021, 11:41:49 amThank you for impugning our cocksmanship.

author: SiliconWizard
author_rank: Super Contributor
timestamp: September 27, 2021, 11:17:22 pm
content: Quote from: Bassman59 on September 26, 2021, 07:39:24 pmAs you saw later on, I would rather say: no, you *thought* that's what you wanted. But there are more elegant ways to do it in VHDL that get you the exact same thing. As I said, many VHDL features are equivalent to a fancy preprocessor. That's what you could see for yourself.VHDL has strong similarities with ADA, which doesn't need a preprocessor either for generic programming. Thinking of using a preprocessor mostly comes from our habits with C. For lack of a better approach. So yeah, properly using VHDL for generic programming requires a slightly different mindset and knowing the language a bit better.Now if warnings about removed logic and removed signals annoy you... well. In a moderately complex design, there will be tons of those warnings, even when there are no conditional exclusions. That's part of logic optimization. Many signals can get optimized out due to being logically equivalent to others in some way. So that doesn't make much difference...Now you could also do this with 'if generate' statements, which would completely exclude some parts of code conditionally. In the case you showed, that would mean splitting your decoder into several processes/or even entities, which would be pretty cumbersome - and would need additional steps for combining the outputs of the various parts together. I wouldn't recommend it here. (That's what I think nctnico suggested at some point?) But that would be yet another approach.VHDL-2019 additions look nice, but frankly we can do without them. And, I wouldn't hold my breath for tools support any time soon...

author: nctnico
author_rank: Super Contributor
timestamp: September 28, 2021, 12:35:06 am
content: Yeah, bolting on C-isms to a language is never a good idea. Borland Delphi from the early 2000's comes to mind. What a steaming pile of rubbish!Just for clarity: I didn't suggest to break the logic that handles the commands into several pieces but to handle it before (the filtering). It is just that my brain isn't set to VHDL at this moment.