Coding for sharing – two design rules that will make your colleagues happy

RTL code, or any other code for that matter, is rarely written from scratch. Usually you start your design based on someone else’s code. So to make your code easier to understand for your colleagues or any other person that want to use it, consider these two simple design rules.

Divide your design into structural and functional blocks

A structural block is a block that only contain instances of other blocks and the interconnects between them. A functional block contains logic, registers, memories, and all other neat stuff you want to put in your design.

Most designs have this division naturally. A design is usually a bunch of functional blocks that are connected together in a higher level block.

What is important is to resist the urge to add logic in a structural block, even though this may be the easiest place to fix a bug or change the functionality to match your needs. This is for two reasons:

  • Logic outside a functional block will not be included when the block is copied or re-used in other designs, leading to higher risk of bugs.
  • It is not clear who is responsible for the logic in a structural block.

Use this convention, and no logic will be forgotten or misplaced.

Use special names for I/O signals and interconnects

This naming convention makes it much easier to see the structure of the design for a person that is new to the code.

  • I/O signals get a reserved prefix. For example:
    • Input signals are named i_<signal_name>
    • Output signals are named o_<signal_name>
  • Interconnect signals between blocks are named <driver_instance>_<signal_name>

An example is shown in the picture below.

signal_naming

Signal naming in a structural block. The instance “m” of the module “master” sends a request signal to the instance “s” of the module “slave” and receives an acknowledgment.

If these conventions are used it is always clear whether a port of an instantiated block is an input or an output. The driver of a signal can also be easily seen from the name of the signal. So no more backwards tracing of signals in huge interconnect blocks.

Happy code sharing!

Note: if you use VHDL for coding it is not allowed to read output ports. To get around this problem it is common practice to use an internal signal as an alias for the output port, and then connect the alias signal to the output port. It is a good idea to use special names for these alias signals too, such as a_<signal_name> .

2 Comments

  1. Regarding port naming conventions, I rarely have trouble understanding if a signal is an input or an output, so I never use an i/o prefix/suffix. HDL languages are often verbose, and it is handy to be able to copy post names between modules, and also structural blocks, suffixes might have to be edited, which is extra work and might be a source of bugs. Prefixes on the other hand cause trouble in waveform viewers where signals are ordered alphabetically. I like to have all signals from a bus to be together, so I do not have to search for them in the list.
    Instead I like my signal names to have a hierarchical organization. A good example here would be the signal name for AMBA AXI buses. The signals are grouped into 5 groups: AW, W, B, AR, R. The group name is a prefix. The second part of the name describes the functionality inside the group. Whether the signal is an input or output or it comes from a slave or a master or a streaming source or drain, depends on context, and I do not like signal names to change depending on context.
    Lately I use SystemVerilog interfaces, which kind of enforce this naming conventions using the dot operator to get access to signals inside a hierarchy.

    • Max Bjurling

      January 25, 2016 at 9:09 am

      Thanks for your input Iztok! I love SystemVerilog interfaces, they really force you to take the whole structure up one abstraction level and is one of the best features of SystemVerilog when used for design. Using modports provide the same information as using input/output prefixes, and a lot more!

      The purpose of signals change depending on context. ReadData from one module may very well be WriteData of another, and then it is hard to keep the same name for the signal without confusion. If you use standards like AMBA then signal names are well known and it is a good idea not to change them, but for your own custom code there’s usually not as much thought put into the naming. Do you use hierarchical naming for all your signal names or is it just for standard interfaces like AMBA AXI?

Leave a Reply

© 2018 Bjurling Logic

Theme by Anders NorenUp ↑