AUTO_TEMPLATE

This document describes the AUTO_TEMPLATE system for customizing how ports are connected during AUTOINST expansion. Templates provide powerful pattern matching and signal transformation capabilities.

Introduction

When slang-autos expands /*AUTOINST*/, it connects each port to a signal with the same name by default. AUTO_TEMPLATE lets you override this behavior to:

  • Rename signals based on instance names (e.g., datafifo_0_data)

  • Transform port names (e.g., axi_wdatam_axi_wdata)

  • Tie off unused ports to constants

  • Leave specific ports unconnected

  • Compute signal names using math expressions

Templates are especially useful when instantiating multiple copies of a module where each instance needs different signal names.

Template Syntax

Basic Structure

A template is defined in a block comment immediately before one or more module instantiations:

/* module_name AUTO_TEMPLATE ["instance_pattern"]
   port_pattern => signal_expression
   port_pattern => signal_expression
*/
module_name instance_name (/*AUTOINST*/);

Components:

  • module_name: The module type this template applies to (required)

  • instance_pattern: Optional regex to match instance names and extract captures

  • port_pattern: Port name or regex pattern to match

  • signal_expression: The signal name or expression to connect

Rule Ordering

Rules are evaluated in order, and the first matching rule wins. This means more specific patterns should come before general catch-all patterns:

/* fifo AUTO_TEMPLATE
   clk      => sys_clk
   rst_n    => sys_rst_n
   data_.*  => fifo_$0
   .*       => $0
*/

In this example, clk and rst_n get specific mappings, ports starting with data_ get prefixed, and everything else passes through unchanged.

Instance Pattern Matching

The instance pattern is an optional regex that matches against instance names and extracts capture groups for use in signal expressions.

Default Behavior

When no instance pattern is specified, slang-autos automatically extracts the first number found in the instance name:

/* fifo AUTO_TEMPLATE
   din => fifo_@_din
*/
fifo u_fifo_0 (/*AUTOINST*/);  // @ = "0", connects to fifo_0_din
fifo u_fifo_1 (/*AUTOINST*/);  // @ = "1", connects to fifo_1_din

This works with numbers anywhere in the name:

  • u_fifo_0 → extracts 0

  • fifo3_inst → extracts 3

  • ms2m_adapter → extracts 2

Custom Instance Patterns

For more control, specify a regex pattern in quotes:

/* fifo AUTO_TEMPLATE "u_(.+)_fifo_(\d+)"
   din => %1_data_in[%2]
*/
fifo u_tx_fifo_0 (/*AUTOINST*/);  // %1="tx", %2="0" → tx_data_in[0]
fifo u_rx_fifo_3 (/*AUTOINST*/);  // %1="rx", %2="3" → rx_data_in[3]

Instance Capture Variables

  • %1, %2, %3, … - Capture groups from instance pattern

  • %{1}, %{2}, … - Brace variant (use when followed by a digit)

  • %0 or %{0} - Full instance name

  • @ - Alias for %1 (verilog-mode compatibility)

The brace variant is necessary when the variable is followed by a digit:

/* mem AUTO_TEMPLATE "bank_(\d+)"
   addr => bank%{1}0_addr
*/
mem bank_2 (/*AUTOINST*/);  // Connects to bank20_addr (not bank_addr with "20")

Port Pattern Matching

Port patterns can be literal names or regex patterns that match against port names and extract capture groups.

Literal Matching

Simple port names are matched exactly:

/* module AUTO_TEMPLATE
   clk   => sys_clk
   rst_n => sys_rst_n
*/

Regex Patterns

Use regex for flexible matching:

/* axi_slave AUTO_TEMPLATE
   axi_(.*)      => s_axi_$1
   data_([io])n  => port_$1
*/

Common patterns:

  • .* - Match any port (catch-all)

  • data_.* - Match ports starting with data_

  • (.*)_valid - Match ports ending with _valid, capture prefix

  • ([^_]+)_(.+) - Split on first underscore

Port Capture Variables

  • $1, $2, $3, … - Capture groups from port pattern

  • ${1}, ${2}, … - Brace variant

  • $0 or ${0} - Full port name (equivalent to port.name)

Substitution Variables

Signal expressions can include various substitution variables that are replaced during expansion.

Instance Captures

From the instance pattern regex:

Variable

Description

%1, %2, …

Capture groups from instance pattern

%{1}, %{2}, …

Brace variant (use when followed by digit)

%0, %{0}

Full instance name

@

Alias for %1 (verilog-mode compatible)

Port Captures

From the port pattern regex:

Variable

Description

$1, $2, …

Capture groups from port pattern

${1}, ${2}, …

Brace variant

$0, ${0}

Full port name

Port Properties

Access port metadata:

Variable

Description

port.name

Port name (same as $0)

port.width

Bit width as integer (e.g., 8)

port.range

Range string (e.g., [7:0])

port.direction

Direction string: "input", "output", or "inout"

port.input

1 if input, 0 otherwise

port.output

1 if output, 0 otherwise

port.inout

1 if inout, 0 otherwise

Instance Properties

Variable

Description

inst.name

Full instance name

Special Values

These special values have specific meanings in signal expressions:

Unconnected Ports

Use _ (underscore) to leave a port unconnected:

/* debug_module AUTO_TEMPLATE
   debug_.*  => _
*/

This generates an empty connection: .debug_port()

Constant Values

Tie ports to constant values:

Value

Description

'0

Logic zero (unsized)

'1

Logic one (unsized)

'z

High impedance / tri-state

Example:

/* unused_module AUTO_TEMPLATE
   enable => '1
   data   => '0
*/

Warning

Assigning constants to output ports generates a warning, as this is usually unintentional. Use ternary expressions to handle bidirectional cases.

Ternary Expressions

Ternary expressions allow conditional signal assignment based on port properties.

Syntax

condition ? true_value : false_value

The condition must evaluate to "0" or "1" after variable substitution. This is typically used with the port direction booleans.

Direction-Based Assignment

Connect different signals based on port direction:

/* bidir_module AUTO_TEMPLATE
   data => port.input ? data_in : data_out
*/

Tie-Off Patterns

A common pattern is to tie inputs to a constant while leaving outputs unconnected:

/* unused_module AUTO_TEMPLATE
   .* => port.input ? '0 : _
*/

Or vice versa - only connect outputs:

/* monitor AUTO_TEMPLATE
   .* => port.output ? mon_$0 : _
*/

Nested Ternaries

For more complex logic, ternaries can be nested:

/* complex AUTO_TEMPLATE
   .* => port.input ? input_bus : port.output ? output_bus : bidir_bus
*/

Math Functions

Math functions allow computing signal names or indices from numeric values.

Available Functions

Function

Description

add(a, b)

Addition: a + b

sub(a, b)

Subtraction: a - b

mul(a, b)

Multiplication: a * b

div(a, b)

Integer division: a / b

mod(a, b)

Modulo: a % b

Arguments must be integers after variable substitution. Negative results are supported.

Note

Division or modulo by zero returns 0 and generates a warning.

Basic Usage

Offset instance numbers:

/* stage AUTO_TEMPLATE "stage_(\d+)"
   prev_data => stage_sub(@, 1)_data
   next_data => stage_add(@, 1)_data
*/
stage stage_5 (/*AUTOINST*/);
// prev_data → stage_4_data
// next_data → stage_6_data

Nested Functions

Functions can be nested for complex calculations:

/* ring AUTO_TEMPLATE "node_(\d+)"
   next => node_mod(add(@, 1), 4)_port
*/
ring node_0 (/*AUTOINST*/);  // next → node_1_port
ring node_3 (/*AUTOINST*/);  // next → node_0_port (wraps around)

Array Indexing

Compute array indices from instance numbers:

/* slice AUTO_TEMPLATE "slice_(\d+)"
   data => bus_data[add(mul(@, 8), 7):mul(@, 8)]
*/
slice slice_0 (/*AUTOINST*/);  // data → bus_data[7:0]
slice slice_1 (/*AUTOINST*/);  // data → bus_data[15:8]
slice slice_2 (/*AUTOINST*/);  // data → bus_data[23:16]

Practical Examples

Basic Instance Numbering

Multiple FIFOs with numbered signals:

/* fifo AUTO_TEMPLATE "u_fifo_(\d+)"
   wr_data  => fifo_@_wr_data
   rd_data  => fifo_@_rd_data
   wr_en    => fifo_@_push
   rd_en    => fifo_@_pop
   full     => fifo_@_full
   empty    => fifo_@_empty
*/
fifo u_fifo_0 (/*AUTOINST*/);
fifo u_fifo_1 (/*AUTOINST*/);
fifo u_fifo_2 (/*AUTOINST*/);

Port Prefix Transformation

Add or change signal prefixes:

/* axi_master AUTO_TEMPLATE
   m_axi_(.*)  => axi_$1
   clk         => axi_clk
   rst_n       => axi_rst_n
*/

AXI Interface Remapping

Remap AXI signals between naming conventions:

/* axi_slave AUTO_TEMPLATE
   s_axi_aw(.*)  => axi_aw$1
   s_axi_w(.*)   => axi_w$1
   s_axi_b(.*)   => axi_b$1
   s_axi_ar(.*)  => axi_ar$1
   s_axi_r(.*)   => axi_r$1
   s_axi_(.*)    => axi_$1
*/

Multiple Capture Groups

Extract multiple parts from port names:

/* crossbar AUTO_TEMPLATE "xbar_(\d+)"
   port_(\d+)_(.*)  => node_%1_p$1_$2
*/
crossbar xbar_0 (/*AUTOINST*/);
// port_0_valid → node_0_p0_valid
// port_1_data  → node_0_p1_data

Unused Module Tie-Off

Completely tie off an unused module:

/* debug_controller AUTO_TEMPLATE
   .* => port.input ? '0 : _
*/
debug_controller u_debug (/*AUTOINST*/);

Ring Buffer Connections

Connect modules in a ring topology:

/* ring_node AUTO_TEMPLATE "node_(\d+)"
   to_next   => link_mod(add(@, 1), 8)
   from_prev => link_@
*/
ring_node node_0 (/*AUTOINST*/);  // to_next→link_1, from_prev→link_0
ring_node node_7 (/*AUTOINST*/);  // to_next→link_0, from_prev→link_7

Diagnostics and Troubleshooting

Common Warnings

Unresolved variable

Warning: Unresolved substitution variable '$2' in template

This occurs when referencing a capture group that doesn’t exist. Check that your regex has enough capture groups.

Invalid regex pattern

Error: Invalid regex pattern in template

The regex syntax is invalid. slang-autos uses std::regex (ECMAScript syntax), which differs slightly from Perl-compatible regex. An invalid regex in the instance pattern is a hard error and the whole template is rejected; an invalid regex in a port pattern is a warning and that rule is skipped.

Malformed template

Error: AUTO_TEMPLATE ... rejected

Templates are parsed strictly. The following are hard errors (the entire template block is rejected):

  • Legacy verilog-mode-style wrapper parens around the template body (AUTO_TEMPLATE(...)).

  • Stray trailing ) on rule signals (these used to be silently stripped, which would have broken expressions like add(@, 1)).

  • Invalid regex in the instance pattern (as above).

Constant assigned to output

Warning: Assigning constant to output port 'data_out'

You’re assigning '0, '1, or 'z to an output port. This is usually a mistake. Use a ternary expression if you need direction-aware behavior.

Common Mistakes

Forgetting braces around variables followed by digits

/* Wrong - %10 is interpreted as capture group 10 */
mem_addr => bank%10_addr

/* Correct - use braces */
mem_addr => bank%{1}0_addr

Order of rules matters

/* Wrong - catch-all first, specific rules never match */
/* module AUTO_TEMPLATE
   .*  => sig_$0
   clk => sys_clk
*/

/* Correct - specific rules first */
/* module AUTO_TEMPLATE
   clk => sys_clk
   .*  => sig_$0
*/

Regex special characters need escaping

/* Wrong - dot matches any character */
data.in => signal

/* Correct - escape the dot for literal match */
data\.in => signal

/* Or use it intentionally as wildcard */
data.* => prefix_$0