VHDL coding
VHDL Training
On-line courses
- Doulos VHDL Pacemaker
-
Introduction au VHDL et utilisation du simulateur
NCVHDL
(in French!)
- Based on CERN technical training, S.Brobecker.
Books
- VHDL for logic synthesis, Rushton (CERN Library, older edition)
VHDL Coding Guidelines
OHWR Guidelines for VHDL coding
Many projects on OHWR use the Guidelines for VHDL Coding. Using similar coding styles will ease re-useability.
-
Guidelines for VHDL Coding
(from HDL Core Lib
project)
- The White Rabbit core collection
project gives some
exceptions and hints to make the Guidelines better usable for
large complex modules.
- White Rabbit core collection - Development - Coding style
- The White Rabbit core collection
project gives some
exceptions and hints to make the Guidelines better usable for
large complex modules.
Other
VHDL Review Checklist
Before the review of your project/module, check whether it follows the these simple tips/guidelines (these are the usual remarks that you would receive from reviewers)
- Use registers in IOB for in/out to get well-defined timing, independent of routing
- Check crossings of clock domains, use synchronizer stages when needed (e.g. gc_sync_ffs in modules/common of general-cores)
- Replace deep if-then statements by state machine
- Initialize in reset all signals for which you assign value in a process
- State machine recover from illegal states, i.e. always define the "others" state, preferably to go to IDLE state of your state machine, if happens.
- Follow the naming convention from the
guidelines, at minimum check
that
- the names of inputs/output signals of your module(s) finish with "_i"/"_o", bidirectional with "_b", asynchronous signals have "a" before "_i"/"_o"/"_b", and pulses have "pX" in their names (where X is the width of the pulse, e.g. single-cycle pulse should have _p1 in its name)
- the names of the signals inside your module(s) do not finish with "_i"/"_o"/"b" and do not begin with "s" (the optional naming convention from the guidelines that is not recommended)
- the names of clock signals, whenever it is known/fixed, indicate the frequency, e.g..: clk_125m_pllref, clk_80m_ADC, clk_20m_vcxo_i
- Make sure that only needed signals are in sensitivity list of a process (e.g. if you use process with synchronous reset, make sure reset is not in sensitivity list)
- Do not use "new" and "old" in the names (the new will become old very fast and the name will mean nothing)
- Check whether any module or function that you need in your design
and that is not specific to your project (say, it deals with
Endianness or calculate CRC) exists already in
general-cores,
wr-cores, or opencores.org:
- if it does not exist, consider adding it there
- if it does exist already, consider reusing and extending/fixing if needed
- Before using an asynchronous input signal (e.g. from DIO) in your synchronous design, first synchronise it with your clock domain and then deglitch the signal, preferably use gc_async_signals_input_stage in modules/common of general-cores
- If your code is auto-generated (e.g. by wbgen2) do not modify it, unless you are really sure what you do (usually you need to do the modification because you don't know)
- State copyright and license in all files, see example
- Follow good practices when using git, in specific for HDL designs:
- don't commit Modelsim "transcript"
- don't commit the "*.xise" in syn/ folder unless it's in a release commit
- Remove unused signals/variables/inputs/outputs
- Avoid ambiguous code, e.g:
- Set a signal, use value on line afterwards (takes 'previous' value). Behavior would be different if it was a variable
- Provide minimum description in the header of each file, see example
- Follow, as closely as possible, the suggested file structure
Wishbone bus
Many Open designs use the Wishbone specification. You may want to generate the Wishbone slaves to be specified and automatically generated by the Wishbone Generator wbgen [2].
Usage of registers
The following are some hints that I received when I was a young fellow designing some interface and spoke with a clever guy with login 'tbl' who gave me some useful hints to make hardware that is easy to program. Although those ideas are from the same time the web was being invented at CERN, I think they are still valid and useful.
Control registers
- Make control registers all write-read. That way you can easily set a single bit if needed without needing a copy of the data. Also easy to check if everything works as you expect.
- Default value (everything working as normal) should be 0. Anything 'special' set should be written as a 1.
- Unused bits: define as: "reserved, write as 0.". This allows future upgrades of hardware that still will work with old software that doesn't know about added or hidden possibilities.
Status registers
- Default value (everything normal) should be 0. So you can easily see if a bit is set.
- Unused bits: define as: "reserved, ignore on read". This allows future upgrades of hardware that still will work with old software that doesn't know about added or hidden possibilities.
- Interrupt status register (showing the cause of an interrupt): actually the same as rule 1. But make the most significant bit an OR of all the other bits, likely combined with an interrupt mask register. With a single assembly instruction (check if negative) you can see if any of the bits is set. This would make software go faster if it has to scan many devices to check who has interrupted.
General
- Make that everything goes fast when things are OK (e.g with hint 6). To find out what was the cause of an error condition may take much more time.
- If possible, make that your hardware can continue without an interrupt being handled. E.g. one can have a counter that would show how many interrupts it would have given when continued (e.g. number of packets sent, so the software can just check off many items in a list in one interrupt service routine).
Examples of gateware design reviews
- VHDL design review of nanoFIP
Erik van der Bij, Maciej Lipinski - 28 November 2016