
In the examples given so far, all net names were either supplied as operands of the macro call, or constructed from values supplied by the macro call. In a sense, these names are the "primary inputs and outputs" of the macro. If additional net names are required beyond those specified as primary inputs and outputs, great care must be taken to avoid duplicating a net name. This is not of concern when one uses an FHDL subnet, because the FHDL circuit flattener renames these nets in such a way as to produce a unique name each time the subnet is called. The macro preprocessor does not provide such a mechanism, although several different mechanisms can be explicitly programmed. This section will give examples of several different methods for providing unique net names. Each of these examples will focus on the problem of creating a AOI32 gate out of AND, OR, and NOT gates. The logic diagram of the AOI32 gate is given below.
The macro to generate gates of this type is given below.
AOI32: 'macro
'inputs 'i1,'i2,'i3,'i4,'i5
'outputs 'out
and ('i1,'i2,'i3),("tempa"#'calln)
and ('i4,'i5),("tempb"#'calln)
or (tempb#'calln,tempb#'calln),(tempc#'calln)
not tempc#'calln,'out
'endmacro
The value of the built-in variable 'calln is the number of macro calls that have been processed so far, not counting those that were encountered during the processing of the current macro. The variable 'calln remains constant throughout the processing of the current macro. The value of 'calln is guaranteed to be different for each macro call.
This example also illustrates two different methods for specifying strings. A string may be enclosed in quotes thus: "this is a string". If a string is enclosed in quotes it may contain any character except the null character (zero character). If a string contains only upper and lower case letters, digits, periods and underlines, the quotes may be omitted.
The next method of handling internal signals emulates the method used by the FHDL circuit flattener.
AOI32: 'macro
'inputs 'i1,'i2,'i3,'i4,'i5
'outputs 'out
and ('i1,'i2,'i3),('label#.tempa)
and ('i4,'i5),('label#.tempb)
or ('label#.tempb,'label#.tempb),('label#.tempc)
not 'label#.tempc,'out
'endmacro
The the value of the built-in variable 'label is the text of the label field of the macro call. If there is no label the value of 'label is the null string. This, of course, can cause problems, so it might be wise to make the following change to the above macro.
AOI32: 'macro
'inputs 'i1,'i2,'i3,'i4,'i5
'outputs 'out
'str 'tlab
'if 'label'==""
'assign 'tlab,X#'calln
'else
'assign 'tlab,'label
'endif
and ('i1,'i2,'i3),('tlab#.tempa)
and ('i4,'i5),('tlab#.tempb)
or ('tlab#.tempb,'tlab#.tempb),('tlab#.tempc)
not 'tlab#.tempc,'out
'endmacro
This example illustrates the use of work variables of type string. The next example makes use of global variables as well as string variables.
AOI32: 'macro
'inputs 'i1,'i2,'i3,'i4,'i5
'outputs 'out
'str 't1,'t2,'t3
'gblint 'label_number
'assign 't1,L#'label_number
'assign 't2,L#'label_number+1
'assign 't3,L#'label_number+2
'assign 'label_number,'label_number+3
and ('i1,'i2,'i3),('t1)
and ('i4,'i5),('t2)
or ('t1,'t2),('t3)
not 't3,'out
'endmacro
This example illustrates the use of global variables. The integer variable 'label_number is declared to be global. Global variables retain their values from call to call, while local variables are initialized at the beginning of each call. Local variables are declared using 'int, 'str, and 'list statements, while global variables are declared using 'gblint, 'gblstr, and 'gbllist statements. All macros that declare the same global variable share access to the variable. A macro has no knowledge of undeclared global variables, so it is permissible for one macro to declare a local variable with the same name as a global variable declared by another macro. Global integers are initialized to zero, global strings are initialized to the null string, and global lists are initialized to the null list. These initializations are also done for local variables at the beginning of each call.
The second feature illustrated by this example is the coercion between integers and strings. When an integer variable is used as a string, it is automatically converted to a string of decimal digits without leading zeros (unless the value is zero). Negative numbers have a leading minus sign. A string that contains only digits can be used as a number. It will be coerced to an integer before use. The assumed radix is 10, regardless of leading zeros.