2
\$\begingroup\$

There is a great free (gratis and libre) VHDL book called Free-Range VHDL which is quick starter. As a neophyte, I am having difficulties judging the relative rules of thumb when it comes to process blocks.

From the book:

In VHDL, the best approach is to keep your process statements centered arounda single function and have several process statements that communicate with each other. The bad approach is to have one massive process statement that does everything for you. [p. 49]

I'm not sure how long exactly it too long. For instance, while trying to designing a simple 4-bit counter with enable, reset and load value functions, my process statement exceeds 40 lines of code. Since we're targeting actual hardware, we were able to synthesize it without a problem.

\$\endgroup\$

closed as primarily opinion-based by Elliot Alderson, Dmitry Grigoryev, awjlogan, Finbarr, Voltage Spike Oct 5 '18 at 19:17

Many good questions generate some degree of opinion based on expert experience, but answers to this question will tend to be almost entirely based on opinions, rather than facts, references, or specific expertise. If this question can be reworded to fit the rules in the help center, please edit the question.

  • 2
    \$\begingroup\$ That sounds like a lot of lines for the function you describe. Why don't you show us your code? Maybe we could help you tighten it up. VHDL is a relatively verbose language, and there's no reason to be more verbose than necessary -- after a certain point, it actually begins to impede readability. \$\endgroup\$ – Dave Tweed Oct 5 '18 at 0:39
  • \$\begingroup\$ Your question is subjective. There are no limits in VHDL other than value ranges, host resources (memory, CPU performance). Simulation and synthesis tools can adapt. Simulation throughput can suffer when unrelated assignments occur in the same process updating signals whose value doesn't doesn't cause an event (isn't different from the previous value) or isn't evaluated and can be caused by wide sensitivity lists to accommodate unrelated logic. The effect on synthesis is mostly caused by memory usage due to complexity. The rest is readability, your counter could be all on one line. \$\endgroup\$ – user8352 Oct 5 '18 at 1:31
  • 3
    \$\begingroup\$ This may be true for small functional blocks, but not for for everything. For example, when you code a state machine in VHDL, it is natural for it to be in a single process. In my experience, it is not unusual for a complicated state machine to be hundreds of lines long, including comments of course. \$\endgroup\$ – crj11 Oct 5 '18 at 3:00
  • \$\begingroup\$ Usually process is too long if you can't look at it and understand it fully. It is too short if you understand it, but alone it doesn't make any sense. So it should be a stand alone entity, but not too big for your mind. \$\endgroup\$ – Gregory Kornblum Oct 5 '18 at 8:36
  • 1
    \$\begingroup\$ Writing code is about semantically compound regions, one purpose paradigm and maintainability. So, a process should serve only one function. It should be maintainable. Optimizers are not dumb and who cares about an additional bit on big FPGAs or ASICs if it helps to maintain a circuit design for the next 5 years? \$\endgroup\$ – Paebbels Oct 5 '18 at 20:25
2
\$\begingroup\$

Fundamentally the only real constraint on this is TIMING.

One could put some arbitrary limit on the sensitivity list (personally I would always push CLK and RST only in the sensitivity list to ensure synchronous operation)

One could put some arbitrary limit on the SLOC but this is downto personal style or company schema

One could put merit onto reuse and thus advocate processes that do one specific job really well and configurable via generics BUT again personal style or company schema

... number of IN/OUT on an entity... style,schema

... adherence to some process like DO254 with regards to code audit ... style,schema

At the end of the day what is written must synthesis and be routed. If the code that is written produces a serialised chain of logic such that the propagation time through this is not completed by the time the next clock comes along, then there will be problems.

I would always push small simply entities, only clk-rst in sensitivity etc as best practice for re-use and auditing but fundamentally if you violate timing constrains setup & hold, it really doesn't matter how you code because it will not function

\$\endgroup\$
  • \$\begingroup\$ During implementation of my counter, I did notice that timing constraints were being violated with a critical warning. Since the counter did not have to operate at clock speed, simply adding a clock divider prevented any timing errors. \$\endgroup\$ – nabulator Oct 7 '18 at 1:39
2
\$\begingroup\$

Code is too long if you find that when you need to find a specific part of it (e.g. to make a change or to check exactly what it does) it takes longer than a few moments to locate it. Like most high level languages, VHDL provides many ways that can be used to split a large block of code into smaller modules; use them whenever you start to find it's getting hard to navigate.

\$\endgroup\$
0
\$\begingroup\$

As long as the code is not complex, It could be long. In fact Complexity is equal with bug or at least low maintainability. It is true for software and HDLs. In software engineering There is a metric with name Halstead. in this metric, You can have estimated number of bugs of your code. This metric is working based on John Stroud's number (a psychologist). the Stroud's number for computer engineers is set to 18 (the maximum is 20) and its mean that If you had a code with more than 18 tokens, you probably had done a mistake some where. The Stroud's number has been extracted from human brain natural capabilities. therefore the same limitations exist for making human made HDLs. Metrics based on Stroud's number are using for estimation of project time. the following thesis could be a little helpful. https://www.researchgate.net/publication/283455241_Analysis_and_optimization_of_dynamic_dataflow_programs

\$\endgroup\$
0
\$\begingroup\$

There's no fix number to determine whether a block of code is too large or not. In general I try to separate distinct funtionalities in different processes. Means I have one process for signal synchronization, maybe one for counter functionality, one for the state machine. On the other hand, especially the process that holds the statemachine can be several hundred lines of code. Of course here you have different approaches, some like to split them into a next_state process that just evaluates the states and a signal process that applies the corresponding signal state to each state of the state machine... but that's a different topic.

So long story short, it's all about maintainability, if the process is devided into clear sections (like a state machine) then it can be much larger before it becomes unreadable than if you have a process that "just" does some signal manipulation.

Further you can increase readability and maintainability with the use of meaningful comments and self-explaining signal names.

\$\endgroup\$
0
\$\begingroup\$

The book is wrong, but not in the sense that long processes should be acceptable, it's just that multiple processes communicating with each other is even harder to debug (note that there are a few paradigms for writing VHDL, I'm a defender of the single process style, there are some people who prefer the two process style for good reasons, there's no one worth their salt that will or needs to use more than two processes for a single-clocked module).

What is true, is that if you have a long process, you could probably split of recurring portions into (preferably pure) functions and procedures. Probably defined in the declaration portion of the process, but functions might/should be in external packages.

Negative aspects of using multiple processes:

  • Sensitivity lists suddenly become relevant, beginners don't even get their sensitivity lists right with just a few processes
  • Some simulation tools merge all processes with equivalent sensitivity lists, so your view in the simulator is no longer the same as what you wrote in the code
  • The communication channels between your processes will be signals, which decreases your simulation speed, in a single process you can do everything with variables, which makes the code easier to read: assignments are not scheduled but happen where you think they will
  • Linked to the previous point is that changing the code will inevitably end up with multiple drivers or spaghetti code: 3 processes each go their merry way and drive their designated signals, now one spec changes and a decision in process 1 has to influence the driving of a signal in process two: you now either have multiple drivers (impossible) or have to introduce extra communication between the processes (spaghetti). With one process, you introduce an overwrite of the output signal and a clean mux is inferred.

Only reason to use more than 2 processes per module is if you have multiple clocks, in which case you end up with one or two processes per clock (depending on what style you use), using synchronized signals to communicate between the clock domains.

\$\endgroup\$
0
\$\begingroup\$

In general, I like to keep a process down to a particular function, especially when writing for synthesis. I haven't written VHDL for a number of years, and the synthesis tools back then needed some help optimizing elaborate designs. Also, I like a process block to represent a schematic block (from back in the day when people drew schematics). I suspect that as synthesis and simulation tools progress, it may become more of a stylistic issue, but my general rule for either sequential or HDL code is that when you're debugging it, if you're looking at a block and dismissing parts of it as not relative to your issue, that block should be at least two different blocks.

\$\endgroup\$

Not the answer you're looking for? Browse other questions tagged or ask your own question.