Hierarchical Design

Master hierarchical circuit composition and abstraction levels.

Introduction

SNL supports hierarchy in a regular manner, allowing you to build complex circuits from simpler building blocks. Components can be built-in primitives, user-defined primitives, or macros (structural descriptions containing primitives and/or other macros). The depth or level of nesting is unrestricted.

A SNL description contains one or more type blocks, each defining a macro or BOOLEAN subcircuit. An entire circuit description can span multiple files, making large designs manageable.

Instantiating Macros

Instantiating a macro in a PART statement is structurally identical to instantiating a primitive. The key is that the number of connections must match the macro's declared pins.

Example: Four-Bit Ripple-Carry Adder

This example demonstrates hierarchical composition using a full-adder macro as a building block:

* Full-adder macro definition:
!format p= t= i= o=
type=full-adder i=ia,ib,c-in o=sum,c-out

xor     exor    ia,ib,c-in      sum
and1    and     ia,c-in
and2    and     ib,c-in
and3    and     ia,ib
or1     or      and1,and2,and3  c-out

* Four-bit adder using full-adder macros:
type=four-bit i=a[3:0],b[3:0],carry-in o=s[4:0],carry-out

%declare integer2=a[3:0],b[3:0],s[4:0]

a0      full-adder      a[0],b[0],carry-in      s[0],c[0]
a1      full-adder      a[1],b[1],c[0]          s[1],c[1]
a2      full-adder      a[2],b[2],c[1]          s[2],c[2]
a3      full-adder      a[3],b[3],c[2]          s[3],carry-out
s4      exor            a[3],b[3],carry-out     s[4]

Key observations:

Hierarchical Naming (Dotted Notation)

Internal parts and signals of macro instances must be distinguished from those in other instances of the same macro. SIMIC uses pathname prefixing with dot delimiters.

Pathname Construction

The pathname is constructed by concatenating all part names from the highest level to the current part, separated by dots (.).

Example: Hierarchical Names in Four-Bit Adder

For the full-adder instance named a1 in the four-bit adder:

For example, the macro instance:

a1 full-adder a[1],b[1],c[0] s[1],c[1]

Expands internally with:

Debugging Tip: Use hierarchical names with the TRACE and LOOK commands to inspect specific instances in nested designs (e.g., TRACE a1.xor).

Levels of Abstraction

Any component instantiated in a PART statement has one of four abstraction levels:

Abstraction Hierarchy

  1. MACRO - Structural description using gates and macros (default search order)
  2. BOOLEAN - Behavioral functional description using Boolean equations
  3. BEHAVIORAL - High-level models (C, Python, shared libraries)
  4. PRIMITIVE - Built-in SIMIC elements (AND, OR, flip-flops, etc.)

Naming Rules

The COMPOSITION Keyword

The COMPOSITION keyword-field specifies which abstraction level to instantiate when multiple definitions exist.

Default Search Order

If COMPOSITION is not specified, SIMIC searches in this order:

  1. MACRO (checked first)
  2. BOOLEAN
  3. BEHAVIORAL
  4. PRIMITIVE (checked last)

Explicit Selection

* Force instantiation of BOOLEAN variant:
p=fad t=full-adder i=a1,b1,c1 o=s1,co1 composition=boolean

* Force instantiation of PRIMITIVE variant:
p=g1 t=and i=a,b,c composition=primitive
Warning: While possible, defining a MACRO or BOOLEAN with the same name as a SIMIC primitive is poor practice and can lead to confusion. Use COMPOSITION=PRIMITIVE to ensure the built-in is used.

Multi-File Designs

Large designs can be organized across multiple files. Type definitions are accessible across file boundaries.

Managing Variants

If you have multiple implementations of the same type name at the same abstraction level:

Example: Variant Selection

* Load fast variant:
>>: get type=processor file=proc_fast.net

* Load low-power variant:
>>: get type=processor file=proc_lowpower.net

BOOLEAN Type Blocks

The BOOLEAN abstraction level allows functional descriptions using Boolean equations instead of structural gates.

Basic Structure

A BOOLEAN type block contains only a TYPE statement with Boolean equations (no PART statements):

type=half-adder i=a,b o=sum,carry boolean=BEGIN; sum == a@b; carry == a*b; END;

Placeholder BOOLEAN Types

For experimentation, you can define a BOOLEAN type without equations and specify them at runtime using the CLAMP command. In this case, include COMPOSITION=BOOLEAN to identify the type:

type=test-logic i=a,b,c o=z composition=boolean

* Specify behavior at runtime:
>>: clamp type=test-logic boolean=BEGIN; z == a*b+c; END;

Design Patterns & Best Practices

Modular Design

Abstraction Strategy

Debugging Hierarchical Designs