SV Macros : Basic with some Interesting facts!!

Dear Readers,

Recently I found very interesting thing about ‘macro’, Let me discuss this in detail. First let's understand what is macro and how is it useful for us ?

What is Macro ?
A macro is a literal name used in a program that is substituted by some value before the program is compiled. Macros are useful as an alias, they are not variables. Almost all modern languages supports macros ! An interesting feature which helps helps engineers in making some complex thing easy (However, clubbing information in macro itself is tough and challenging in some situation ;))
Now, lets discuss on How & Where to use macros?
Where : Macros are used in various places during the implementation, some places like:
  1. Interface instantiation in test bench
  2. Functional Coverage
  3. Assertion/Checker 
These are some of the major places where people mostly use macros to reduce the number of code lines and to understand and utilize same piece of logic in test bench.

How : Explaining a how part is always easy with example, engineers understand things quickly with examples, right ?

Example :

`define XYZ (i) i``_suffix

This expands:
`XYZ(bar) to bar_suffix

Let's take an one more example:

`define DATA_TYPE(A) A

Using this macro we can do following.

Instead of writing integer a, we can write `DATA_TYPE(integer) a;

Above mention examples are basic and simple to understand but in complex test benches we might end up having an requirement where we need macro which can hold hundreds of code lines information
For example, my RTL has an interface, where hundreds of signals defined but signals are repetitive in nature with respect to number of client/hosts etc...

So during the instantiation of these kind of DUT, I would suggest to use macros for these kind of signals and try to club in to one macro which can hold an argument, based on argument passed, it will generate sets of signals for each client/hosts and make and instantiation.

For example:
RTL has signals given below

write_0_host, write_1_host, write_2_host
while instantiating these signal in test bench, we can use macro mechanism to make it easy and controllable:
`define WRITE_FOR_HOST(i) \
.write_``i``_host   (write_``i``_host)

After defining macro, use these in your port connection

abc  xyz (
   ..... signals port instantiation
   .abc  (abc),
   `WRITE_FOR_HOST(0),
   `WRITE_FOR_HOST(1),
   `WRITE_FOR_HOST(1),
   ......
   .......
   .pqr (pqr)
)

These way you can create a sets of signal instantiation by using macro and is very useful when you have hundreds of this kind of signals.

Some interesting facts:

  1. If you have space in between macro name and argument, we need to maintain the space during the call of that macro. In above example WRITE_FOR_HOST(i) does not have space in between macro name and argument "(i)" list. If you use `WRITE_FOR_HOST  (i) then compiler will give you an error. So always take care of space between macro name and its argument.
  2. If you have some white space after your end of character "\", compiler gives you an error like ""zero length escaped identifier". While space are not visible. In some cases by mistake we might have left some white spaces after "\", which means "\" is not at the end of line and compiler will shout for this kind of issue. Issues mentioned above are generally hard to debug because both the issues are with white spaces and white space are not visible!!
Wishing you a happy SV writing ! Keep reading, comments and suggestions are always welcome.

Happy Reading,