.. note:: This is a WIP Beta version. All content is subject to change. .. _user_guide: ========== 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`_ * `Configuring CIRCA`_ * `Built-in component implementations`_ * `Example configuration`_ 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 .. code-block:: bash 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 :ref:`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 :ref:`Standard FrontEnd ` as an example). .. Check the FrontEnd's documentation or log messages to see if your input design meets the FrontEnd's requirements. .. Additional arguments .. -------------------- .. .. todo:: Logging configuration, CIRCA purge command, etc. .. _config_circa: Configuring CIRCA ================= As mentioned in the :ref:`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. .. Since each implementation may provide its own parameter set, only the universally shared parameters and parameters of the built-in component implementations are documented in this section. .. .. todo:: This is very implementation-specific. Should be stated somewhere else, probably in the documentation of the method. .. FrontEnd implementations which support annotations in the input design allow additional options, directly specified in the Verilog design file. These options are generally directly related to specific parts of the input circuit and override the settings from the config. file. .. _approximation_candidate_settings: 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 :ref:`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 ----------------------------------- .. This section briefly explains the configuration file's structure; for an in-depth documentation of a specific method, visit the :ref:`configuration chapter `. 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 .. code-block:: none [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 :ref:`next section `. .. _quality_constraint_syntax: 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 .. code-block:: python 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 .. code-block:: python :bound=,step= where ```` is the unique identifier of the error metric, ```` is the maximum upper bound for this metric and ```` 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: .. code-block:: python 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 .. code-block:: python AppMethods:,, where ````, ```` and ```` are unique identifiers of approximation methods. Approximation method specifiers are usually only found in candidate annotations. Example approximation method specifier: .. code-block:: python 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: .. code-block:: python # 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 .. Configuration options .. --------------------- .. Each component implementation may specify additional options for its component's section which may be mandatory for the implementation to work. Examples for additional options, their possible values, and their effects can be found in the :ref:`next section `. .. _user_guide_built_ins: 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. .. toctree:: :maxdepth: 1 Input QualityAssurance Approximation Estimation Search Output 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. .. code-block:: verilog 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: .. code-block:: verilog // ... module <<>> MOD_1 (/*ports*/); // MOD_1 content endmodule // ... module <<>> MOD_2 (/*ports*/); // MOD_2 content endmodule // ... module <<>> 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: .. code-block:: verilog // ... module <<>><<>> 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: .. code-block:: none [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: .. code-block:: none [Input] Method = AnnotatedCandidates Key = <<>> 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`` .. code-block:: none [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: .. code-block:: none [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: .. code-block:: none [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: .. code-block:: none [Approximation] Method = AIG QualityConstraints = WC: step = 1 The ``Output`` implementation doesn't really matter for your purpose, so you keep the standard value: .. code-block:: none [Output] Method = output_best_area Finally, the input files are ready for the approximation process: ``my_circuit.v``: .. code-block:: verilog module TOP_MOD (/*ports*/); // Many MOD_1 instances // One MOD_2 instance // One MOD_3 instance // ... endmodule // ... module <<>><<>> MOD_1 (/*ports*/); // MOD_1 content endmodule // ... module <<>> MOD_2 (/*ports*/); // MOD_2 content endmodule // ... module <<>> MOD_3 (/*ports*/); // MOD_3 content endmodule // ... ``my_config.cfg``: .. code-block:: none [General] TopModule = TOP_MOD [Input] Method = AnnotatedCandidates Key = <<>> [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 .. code-block:: shell circa my_config.cfg my_circuit.v