Electronics > FPGA

work around VHDL's lack of a preprocessor

(1/10) > >>

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 is
    when 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 other
            params.XYZ <= argument;
            response <= HANDLED;
            response <= NOT_IMPLEMENTED;
        end if;

    when others =>
        response <= NOT_IMPLEMENTED;

--- End code ---

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, or
2. 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 ...

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?

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.

There is a project called vhdlpp which allows to configure VHDL code before  synthesizing it. Itseems quite similar to cppmake: http://vhdlpp.sourceforge.net/README

Nevertheless, generics are normally the recommended way of achieving that, as they avoid problems that copypasting a macro could cause

What's wrong with just having your build system run the actual C preprocessor?


[0] Message Index

[#] Next page

There was an error while thanking
Go to full version