Synchronous Circuit Hardware Orchestration System

Ronny Krashinsky



Please refer to "SyCHOSys: Compiled Energy-Performance Cycle Simulation" for an overview, although that document is not completely up to date with the current version of sychosys.

The input to sychosys is a structural netlist (e.g. gcd.sychonet) describing the circuit, and behavioral models describing the components (e.g. SychoBlock_gcd.h).  The output is a simulation object whose main interface is the clock_tick() method.  This simulation object is instantiated and driven by a user simulation program (e.g.

'Component' and 'Block' are used interchangeably in this document, I should really make up my mind.


The netlist describes how components in a circuit are connected together, and how they are clocked.  It consists of net declarations and component declarations.  The order of these declarations is unimportant.  Capitalization for syntax tokens is unimportant (e.g. wire, WIRE, Wire).  Whitespace is unimportant.  Names for nets and components must start with a letter; can contain letters, digits, '-' (dash), and, '_' (underscore); and are case-sensitive.  A "#" or "//" anywhere in a line begins a comment and the remaining characters on that line are ignored.  A region can be commented out using "/*" and "*/", and these can be nested.

Net Declarations

The format for net declarations is demonstrated by the following non-exhaustive examples.
wire 32 x; a 32-bit net named "x".
wire 32 x, y, z; three 32-bit nets.
wire x; a 1-bit net, bit-width specifier is optional
tri 32 x; a 32-bit tri-state net (driven by more than one component)
wire const 32 x = 300; a constant net with a numerical value
wire const 32 x = 0xff800; hex works too
wire const 32 x = MY_RESET_VEC; a constant net with a value obtained from the C++ files
wire monitor 32 x; a net which is monitored by the simulation program, but is not part of the circuit.
wire external 32 x; a net which is an external input or output of the circuit
wire nostats 32 x; a net which should be excluded from statistics gathering

Component Declarations

Consider an example component declaration:
p_pc_mux { Mux5<30>() }
(p_pcplus4_p, p_brtarg_p, d_rs_p[31:2], m_epc_np, p_prenextpc_np, p_selpc)

The name of the component is "p_pc_mux".  The type of the component is a "Mux5", this name corresponds to a component behavioral model.  "30" is a template argument for the behavioral model, in this case it is the bit-width of the mux.  A list of template arguments can be supplied in order, or the angle brackets can be eliminated if there are no template arguments.  Following the template arguments in parentheses are a list of initialization arguments for the behavioral model; there are none in this case, so the parentheses are optional.  Next is the list of input nets to the component in parentheses, followed by the list of output nets in parentheses.  The order must match that of the behavioral model parameters.

The example above also shows a bit-index of a net, "d_rs_p[31:2]".  Examples of supported bit manipulations for input nets are:
x[31:2] bit-index, based on 0 as the lowest order bit, in order only (x[2:31] not allowed)
x[31] bit-index for one bit (x[31:31] is also ok)
< x : y > concatenation, left to right is highest order to lowest order
< x[4:0] : y : z > combination of bit-index and concatenation

Bit manipulations are not supported for output nets.

Components which are clocked have special tags.  For example, a positive-edge-triggered flip-flop:
my_ff { P-Clk FF<32> }  (in) (out);

Clock tags correspond to when a component's evaluation methods should be invoked:

Clock:  Rising (P) High (H) Falling (N) Low (L)
Clock Tag
none (combinational) Evaluate Evaluate
P-Clk Evaluate
N-Clk Evaluate
H-Latch Evaluate
L-Latch Evaluate
LP-Dynamic PrechargeLow Evaluate
LN-Dynamic PrechargeHigh Evaluate
HP-Dynamic Evaluate PrechargeLow
HN-Dynamic Evaluate PrechargeHigh

Additionally, a component can define arbitrary behavioral methods corresponding to Clk-P, Clk-H, Clk-N, and Clk-L.  For example:
m_dcache { (CLK-P.EvalAddr, CLK-N.EvalData) Cache<32, 30> } 
(x_addrbuf_pn,  x_sdalignbuf_pn, x_memwrite, x_memread, m_pipectrl_sdbyteen) 
(m_ld_p, m_dcachewait_np, m_dcachewait_early_np);

Components which calculate internal statistics for energy measurement have a 'STATS' tag.  For example:
my_ff { P-Clk FF<32> STATS }  (in) (out);

Behavioral Models

The behavioral models for components are in the form of C++ objects.  For example:

  template<int bits>
  class Mux2 : public Sycho_Block {
    inline void Evaluate(const BitVecN<bits>& input0, const BitVecN<bits>& input1,
                         const BitVecN<1>& select, BitVecN<bits>& output) {
    if (select)
      output = input1;
      output = input0;

The behavioral component blocks inherit from Sycho_Block.  Each C++ behavioral model defines an Evaluate() method which maps inputs to outputs.  The arguments consist of the block's inputs and outputs in the same order that they appear in the netlist.  The type for each argument is a reference to a BitVecN bit-vector object, and inputs should be declared const.  Behavioral objects may be parameterized with template arguments as shown by this example.  Each may also define a CalcStats method (with the same arguments as the Evaluate method) which can be used to take internal statistics.  Currently, all behavioral models must be in a single .h file (e.g. SychoBlock_gcd.h).

BitVecN provides an optimized implementation of bit-vectors with arbitrary length.  It is based on the C++ Standard Template Library (STL) bitset container, but it is enhanced to support some arithmetic operations.  For a description of how to use BitVecN objects, refer to the bitset documentation at: .  For performance, it is important to pass BitVecN objects by reference (using '&' in the function declaration, as shown above) so that the compiler will not create a temporary copy of the object.  It is also best to use assignment operators (e.g. |=, +=, etc.) with BitVecN objects so that the compiler will not generate temporary objects to hold the results of binary operations.  Please note that the arithmetic extensions  to the bitset container have not yet been tested extensively with large (> 32 bits) bit-vectors.

WARNING: If the declared type of an output bit-vector argument is a value instead of a reference (e.g. "BitVecN<bits> output" instead of "BitVecN<bits>& output"), the compiler will generate a local copy of the argument and any modifications inside the function will not affect the actual bit-vector argument.  This will not cause any compile-time errors or warnings, but during simulation the component will appear to be broken since the output will never change.

Component Libraries

It should be possible to create libraries of behavioral models for standard components.  Some components are included by default with sychosys.  Currently, these are bit manipulation blocks: sb_BitSlice, sb_SetSlice, sb_BitMerge, and sb_BitExplode.  I don't feel like describing these right now, most of their functionality is accomplished by the netlist bit manipulation features described above.


A sychosys netlist is compiled by the sychosys scheduler, sychosked.  The output is a SyCHOTick simulation object.  This comes in the form of .h and .cc files which contain calls to the components' behavioral methods.

The scheduler first parses and checks the syntax of the netlist and reports any errors that it finds. It then checks for errors in the semantics of the netlist, such as multiple nets declared with the same name.

Combinational logic cycles are not allowed and will be reported as errors. You may have to repartition your behavioral blocks to avoid combinational cycles if they are an artifact of how you divided up the circuit. It would be nice to have an example here, in the meantime ask me if you have questions.

Cycles consisting only of components clocked with the same clock edge are also not allowed and will be reported as errors. This problem can be fixed by inserting any component in the cycle which is not clocked by the same clock edge, such as a buffer. Although I expect that this is an atypical circumstance, sychosys should really be able to deal with these cycles, and I may fix this some day.

Simulation Object

The main interface to a SyCHOTick simulation object is the clock_tick() method which simulates one clock cycle.  This interface is defined in SychoTick_Base which all sychosys simulation objects inherit from.  Currently the supported methods include:
clock_tick() simulate one clock cycle
dump trace or vcd output and take stats if these are enabled
set_trace_out(ostream&) set the output stream for trace output, defaults to cout
set_trace(bool) enable or disable trace output
set_trace2(bool) enable or disable trace output for other clock phase
use trace and trace2 together for trace output twice per clock period
dump_nodes() dump all nets in the circuit, this is what trace does automatically
enable_vcd(ostream&) enable and initialize vcd (value change dump) output to a given stream, defaults to cout
set_vcd(bool) enable or disable vcd output
set_stats(bool) enable or disable statistics taking
dump_stats_blockinfo(ostream&) statistics output
dump_stats_data(ostream&) statistics output

More fine-grained clock_tick() methods are also available.

Additionally, all nets and component blocks in a design are public members of the simulation object, with the same name as in the netlist.  The type for nets is BitVecN.  Other public members include cycle_count, and lists of the nets and blocks.


A simulator (e.g. instantiates a simulation object and runs a simulation.  Details will depend on the application.  Conceivably multiple simulation objects could be combined to simulate an asynchronous interface, but currently there is no automatic support for this.