Note

This is a WIP Beta version. All content is subject to change.

User Guide

This section will teach you how to use CIRCA for approximate circuit generation from a user’s perspective. You will learn to configure and run CIRCA’s approximation process in the following sections:

Basic usage

Note

Make sure you run source circa/settings.sh before each terminal session.

After installation, you can run the circa command from any directory you like. Simply type

circa your_config_file.cfg your_input_design.v

into the console and the approximation process will start, generating logs and output files along the way. (Note that the input design’s directory is usually used as a base directory for output generated during CIRCA’s approximation process.)

The command takes two arguments: the configuration file followed by the input design. The config. file defines the particular approximation process. In general, the config. file contains information about the input design and specifies the employed implementation in a stage or processing block, respectively, and its parameter set. To edit the config., it is generally a good idea to start with a copy of an existing config. file (for example, the file provided in the demo) and only edit the settings you want to change, leaving the rest of the file unchanged. The following sections will give you an in-depth overview of what you can configure in the config. file and how it will affect the framework’s behavior. To learn about the config.’s structure and how to edit the settings, go to the configuration chapter.

In the current implementation, the input design argument is a Verilog description of the circuit you want to approximate (note that CIRCA is not limited to only Verilog, it is up to now just the format we use). It must have a top-level module whose name must be specified in the configuration file. In general, the input design must comply to the standard Verilog syntax. Some FrontEnd implementations, for example, state exceptions to this rule, since they may support or even require code annotations, violating the Verilog standard. Such exceptions, however, will always be described in the documentation to make the users aware.

Some implementations also may require certain limitations of the input design regarding language constructs which cannot be processed (see Standard FrontEnd as an example).

Configuring CIRCA

As mentioned in the Getting Started section, CIRCA distributes the approximation process on several independent and interchangeable components which form the framework’s three stages input (or FrontEnd), output, and QUAES. While the input and output stages are each handled by a single component, the QUAES stage comprises of four components, one for each processing block (Quality Assurance, Approximation, Estimation, and Search).

Using the configuration file, each method employed in these six components can easily be parameterized or exchanged. In general, each method provides its own set of parameters, which is usually not shared among different methods. The following sections will describe universally shared parameters and the parameters of the built-in methods.

Approximation candidate settings

The approximation process heavily relies on the detection and processing of approximation candidates, the parts of the input circuit subject to approximations. The configuration of the processing of the candidates impacts the quality of the approximated outcome directly. By default, there are two parameters which determine how the approximation of a candidate is carried out: the approximation method and the quality constraints.

The approximation method specifies the algorithm or technique that is used to perform the approximation in the Approximation block. For example, one of CIRCA’s standard approximation methods is precision scaling (PS). It approximates a candidate by replacing bits of the output vector with constant logic 1s or 0s and thereby rendering all logic behind the replaced bits obsolete. A synthesis tool is then able to optimize the resulting circuit and reduce its area, delay, power consumption etc. If multiple approximation methods are assigned to a candidate, they will be handled separately to make the approximation results of different methods comparable.

The quality constraints assigned to a candidate specify a boundary for the approximation methods. We denote quality constraints assigned to a candidate as local quality constraints - or the reciprocal, local error bounds. These local quality constraints allow CIRCA to control the quality of a candidate, or more precisely, its particular variant. Being able to control the quality of a variant, enables CIRCA to expand the search space in a controlled manner. The local error bounds of a candidate represent the maximal accepted error of a candidate. The local error bounds applied to the candidate’s variants are in the range of no error (representing the original implementation of the candidate) and the local error bounds of the candidate. For example, a valid local worst-case error bound for a candidate with an 8-bit output (representing unsigned integer values) would be 255 since this expresses the maximal possible output value of the candidate. Any error bound larger than 255 would be meaningless.

Quality can be measured in several different error metrics. Standard error metrics of CIRCA are, for example, worst-case and bit-flip errors (WC and BF). The worst-case error of an approximated variant is the maximum numerical difference between its output and the output of the original variant, which is always used as the point of reference. The bit-flip error is the maximum Hamming distance between the original and the approximated output vectors. To be considered valid, an approximated variant must satisfy all quality constraints specified for the candidate.

The approximation process works by gradually increasing the local error bounds, i.e., the error bounds of each candidate. The rate at which the error bounds are increased can be specified via a step parameter. The bounds will not be increased beyond the maximum error value, specified by the bound parameter.

There are many different ways to specify approximation methods and quality constraints for the candidates. They depend on the used component implementations and may include default settings for all candidates, specific settings for a candidate provided via annotations in the input design, and global quality constraints assigned to the whole circuit.

Working with the configuration file

The configuration file is a simple text file which is divided into sections. To parse a config. file, CIRCA employs Python’s configparser module, which also dictates its structure. Each section has a section header, indicated by square brackets encapsulating the name of the section [section name]. The section header is followed by a list of options and their values, which are assigned using a =. The file can be commented by using a # to make the configuration parser ignore the rest of the line. A simple example for the configuration file syntax would be

[Section1]
Option1 = Value1
Option2 = Value2_1, Value2_2

[Section2]
# This section has no options

# [Section3 (will be ignored)]

The option values are arbitrary strings, but for most options, only certain values can be interpreted. The set of possible option values is documented in the component implementation’s documentation or directly in the configuration file.

Configuration sections

CIRCA’s configuration file has seven sections, each having one mandatory option by default.

The section General is used for providing information about the input design that is not specific to one of the components or cannot be acquired from the input design automatically (yet). The section contains the mandatory option TopModule to which the name of the input design’s top-level module must be assigned.

The other six sections, named Input, Search, Estimation, QualityAssurance, Approximation, and Output, each refer to one of the stages or processing blocks. For each of these sections, the parameter Method has to be defined. The value of this parameter determines the employed method for the corresponding stage or processing block, respectively. Additional parameters may follow the Method parameter to parameterize the employed method further. Examples for additional options, their possible values, and their effects can be found in the next section.

Standardized quality constraint syntax

CIRCA defines a standardized syntax for the specification of quality constraints and approximation methods which is used by the built-in component implementations and recommended to be used for custom implementations as well. This syntax specification applies to the values of the QualityConstraints options of the sections [QualityAssurance] and [Approximation] in the configuration file and to the candidate annotations in the input design if the built-in implementations for the QualityAssurance, Approximation or Input component AnnotatedCandidates are used.

The general syntax is a simple list of elements separated by ;, like for examle

element1;element2;element3

Whitespace before and after the ; is ignored.

Each element can be a specifier for either an error metric or an approximation method. Error metric specifiers have the format

<ID>:bound=<bound>,step=<step>

where <ID> is the unique identifier of the error metric, <bound> is the maximum upper bound for this metric and <step> is the step size, i.e., the amount by which the error bound is increased in one step. Note that both the bound and step parameters are not always required (e.g. the [QualityAssurance] section does not need a step size) and can be omitted in such a case. Also, their order can be changed and whitespace around the :, = and , is ignored. Multiple occurrences of a parameter will at least generate a warning message and may abort the approximation process.

Example error metric specifier:

WC:bound=16,step=2

This expression specifies a worst-case error with a maximum upper bound of 16 and upper bound increment of 2 in each step.

Approximation method specifiers have the format

AppMethods:<ID1>,<ID2>,<ID3>

where <ID1>, <ID2> and <ID3> are unique identifiers of approximation methods. Approximation method specifiers are usually only found in candidate annotations.

Example approximation method specifier:

AppMethods:PS,AIG

This expression specifies the approximation methods Precision Scaling and AIG-Rewriting.

Here are a few examples for complete valid quality constraint specification expressions:

# Bit-flip error with max. upper bound 4 and default step size,
# worst-case error with auto-detected maximum bound and step size 5
# and only precision scaling as approximation method
BF:bound=4;WC:step=5;AppMethods:PS

# Worst-case error with max. bound 10 and step size 1
# and AIG-Rewriting and Precision Scaling as approx. methods
WC:step=1,bound=10;AppMethods:AIG,PS

# Approximation method AIG-Rewriting
# and error metrics worst-case and bit-flip,
# both with default step size and maximum upper bound
AppMethods:AIG;WC;BF

Built-in component implementations

The following list leads to a documentation of CIRCA’s six, method-specific config. sections. For each section, you can find a brief description of the component’s tasks, the currently implemented methods, and the documentation of the available parameters for each method.

Example configuration

This is an example walkthrough of the configuration process to give you an idea of the steps required for making CIRCA work with your own input design.

Let’s assume you have a run-to-completion circuit my_circuit.v with a top-level module called TOP_MOD and three other modules called MOD_1, MOD_2 and MOD_3, which are instantiated in the top module. The goal is to generate an approximate version of the circuit with minimal area, but its output must not deviate from the original circuit’s output by an absolute value of more than 42.

module TOP_MOD (/*portlist...*/);
// Many MOD_1 instances
// One MOD_2 instance
// One MOD_3 instance
// ...
endmodule

// MOD_1, MOD_2 and MOD_3 definitions

All three modules shall be considered as approximation candidates, but MOD_1 is special in that it has far more instances than the other two. You decide that it should not be approximated as far as the other modules and may only have a maximum bit-flip error of 2. However, multiple approximation methods should be used on it, while MOD_2 and MOD_3 should have AIG-rewriting as their only approximation method. They may also have a worst-case error as high as necessary to achieve a good area.

The circuit is quite large, but you have a powerful system and some time, so you are ready to accept a longer runtime in exchange for better results. However, since you want to test CIRCA’s accuracy, you decide to choose a medium-effort search strategy and compare the results to a brute-force search later.

Preparing the circuit

To assign different approximation methods and quality constraints to the modules, you may have to use annotations in the input design. The AnnotatedCandidates FrontEnd implementation offers exactly the required functionality and is applicable to the circuit, because all approximation candidates are modules and all primary input and output signals have a static size.

To mark the modules as candidates, you decide to use the recommended annotation key:

// ...
module <<<APPROX_CAND>>> MOD_1 (/*ports*/);
// MOD_1 content
endmodule
// ...
module <<<APPROX_CAND>>> MOD_2 (/*ports*/);
// MOD_2 content
endmodule
// ...
module <<<APPROX_CAND>>> MOD_3 (/*ports*/);
// MOD_3 content
endmodule

The candidate MOD_1 needs very specific settings, while MOD_2 and MOD_3 can have the same, so their settings can be specified as default settings in the configuration file. After adding the approximation method and quality constraints for MOD_1, its definition looks like this:

// ...
module <<<APPROX_CAND>>><<<BF:step=1,bound=2;appMethods:PS,AIG>>> MOD_1 (/*ports*/);
// MOD_1 content
endmodule
// ...

The circuit is now ready for approximation.

Note

The specification of candidate-specific setting, such as for MOD_1 in the example above, is optional. If no parameters are specified, the configuration specified in the configuration file is used.

Preparing the configuration file

Because you never used CIRCA before, you make a copy of the supplied example configuration and adjust each section if necessary:

The General Section must specify the name of the top module, so it looks like this:

[General]
TopModule = TOP_MOD

Since you decided to use the AnnotatedCandidates FrontEnd implementation, its name must be specified as value of the Method option. The annotation key must be the same as the one in the input design, which is already the case:

[Input]
Method = AnnotatedCandidates
Key = <<<APPROX_CAND>>>

As search method with adjustable effort level, gradient_descent is suitable. To get a medium effort, you decide to use effort level 4. To test CIRCA’s accuracy, the SelectStrategy should be left at the default value best

[Search]
Method = gradient_descent
Effort = 4
SelectStrategy = best

The standard Estimation implementaion abc_if provides a good area estimation, so this section can be left unchanged:

[Estimation]
Method = abc_if

For the QualityAssurance section, you remember the global quality constraint of a maximum worst-case error of 42. You don’t know the difference between the standard methods, so you decide to leave it at abc_dprove. You also have to look up the name of the output signal and specify the circuit type. Since it is run_to_completion, the name of the valid-signal must be specified aswell. The circuit has no start- or reset-signal, so these options are omitted:

[QualityAssurance]
Method = abc_dprove
QualityConstraints = WC:bound=42
OutputSignal = out
OutputIsSigned = 0
CircuitType = run_to_completion
ValidSignal = valid

In the Approximation section, you specify the approximation method and quality constraints for the modules MOD_2 and MOD_3: they were supposed to use AIG-rewriting and have maximum worst-case error if necessary. Since this makes the bound parameter unnecessary, it can be omitted. However, the step size should be small in order to get accurate results:

[Approximation]
Method = AIG
QualityConstraints = WC: step = 1

The Output implementation doesn’t really matter for your purpose, so you keep the standard value:

[Output]
Method = output_best_area

Finally, the input files are ready for the approximation process:

my_circuit.v:

module TOP_MOD (/*ports*/);
// Many MOD_1 instances
// One MOD_2 instance
// One MOD_3 instance
// ...
endmodule
// ...
module <<<APPROX_CAND>>><<<BF:step=1,bound=2;appMethods:PS,AIG>>> MOD_1 (/*ports*/);
// MOD_1 content
endmodule
// ...
module <<<APPROX_CAND>>> MOD_2 (/*ports*/);
// MOD_2 content
endmodule
// ...
module <<<APPROX_CAND>>> MOD_3 (/*ports*/);
// MOD_3 content
endmodule
// ...

my_config.cfg:

[General]
TopModule = TOP_MOD

[Input]
Method = AnnotatedCandidates
Key = <<<APPROX_CAND>>>

[Search]
Method = gradient_descent
Effort = 4
SelectStrategy = best

[Estimation]
Method = abc_if

[QualityAssurance]
Method = abc_dprove
QualityConstraints = WC:bound=42
OutputSignal = out
OutputIsSigned = 0
CircuitType = run_to_completion
ValidSignal = valid

[Approximation]
Method = AIG
QualityConstraints = WC: step = 1

[Output]
Method = output_best_area

Executing CIRCA

The approximation process can now be started by navigating to the directory with the input design and the configuration file and typing

circa my_config.cfg my_circuit.v