Česky
Kamil Dudka

Non-Uniform CA Designer (C++, GAlib, Boost)

File detail

Name:DownloadCaFactory.cpp [Download]
Location: nucad > src
Size:15.2 KB
Last modification:2009-07-12 01:46

Source code

/*
 * Copyright (C) 2009 Kamil Dudka <xdudka00@stud.fit.vutbr.cz>
 *
 * This file is part of nucad (Non-Uniform CA Designer).
 *
 * nucad is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * any later version.
 *
 * nucad is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with nucad.  If not, see <http://www.gnu.org/licenses/>.
 */
 
/**
 * @file CaFactory.cpp
 * Implementation of basic circuits shipped with nucad, all registered in a
 * factory class CaEvaluatorFactory.
 */
 
#include "config.h"
#include "CaFactory.h"
#include "Ca.h"
#include "Color.h"
 
#ifndef BUILDING_DOX
#   include <map>
#   include <set>
#   include <stdexcept>
#   include <sstream>
 
#   define DOX_FAKE_PARENT(PARENT)
#else
#   define DOX_FAKE_PARENT(PARENT) : public PARENT
#endif
 
#ifndef GF_INCLUDE_TRIVIAL
#   define GF_INCLUDE_TRIVIAL 0
#endif
 
#ifndef GF_INCLUDE_COMPLEX
#   define GF_INCLUDE_COMPLEX 0
#endif
 
/**
 * Default evaluation parameters used by PrivateFactory if not specified
 * otherwise.
 */
struct DefParams: public CaEvalParams {
    DefParams() {
        caSize = 5;
        nSteps = 6;
    }
};
 
/**
 * Collection of universal binders for specified count of inputs/outputs.
 * @param N_IN Count of input signals to bind.
 * @param N_OUT Count of output signals to bind.
 */
template <int N_IN, int N_OUT>
struct Binder
{
    /* no tag - this will fail intentionally */
};
 
/// generic binder - @b 2 input signals, @b 1 output signal
template <> struct Binder<2,1> DOX_FAKE_PARENT(Binder)
{
    typedef BindInput<0, 1, 0,
            BindInput<1, 3, 0,
            BindOutput<0, 2, 4>
            > > tag;
};
 
/// generic binder - @b 3 input signals, @b 1 output signal
template <> struct Binder<3,1> DOX_FAKE_PARENT(Binder)
{
    typedef BindInput<0, 0, 0,
            BindInput<1, 2, 0,
            BindInput<2, 4, 0,
            BindOutput<0, 2, 4>
            > > > tag;
};
 
/// generic binder - @b 5 input signals, @b 1 output signal
template <> struct Binder<5,1> DOX_FAKE_PARENT(Binder)
{
    typedef BindInput<0, 0, 0,
            BindInput<1, 1, 0,
            BindInput<2, 2, 0,
            BindInput<3, 3, 0,
            BindInput<4, 4, 0,
            BindOutput<0, 2, 4>
            > > > > > tag;
};
 
/// generic binder - @b 2 input signals, @b 2 output signals
template <> struct Binder<2,2> DOX_FAKE_PARENT(Binder)
{
    typedef BindInput<0, 1, 0,
            BindInput<1, 3, 0,
            BindOutput<0, 1, 4,
            BindOutput<1, 3, 4>
            > > > tag;
};
 
/// generic binder - @b 3 input signals, @b 3 output signals
template <> struct Binder<3,3> DOX_FAKE_PARENT(Binder)
{
    typedef BindInput<0, 0, 0,
            BindInput<1, 2, 0,
            BindInput<2, 4, 0,
            BindOutput<0, 0, 4,
            BindOutput<1, 2, 4,
            BindOutput<2, 4, 4>
            > > > > > tag;
};
 
/// generic binder - @b 4 input signals, @b 4 output signals
template <> struct Binder<4,4> DOX_FAKE_PARENT(Binder)
{
    typedef BindInput<0, 0, 1,
            BindInput<1, 0, 3,
            BindInput<2, 1, 0,
            BindInput<3, 3, 0,
            BindOutput<0, 4, 3,
            BindOutput<1, 4, 1,
            BindOutput<2, 3, 4,
            BindOutput<3, 1, 4>
            > > > > > > > tag;
};
 
/**
 * Static-only evaluator factory used as basic block of other (more specialised)
 * factories.
 * @param CIRCUIT IGate implementation to use as a circuit.
 * @param BINDING IGateBinding implementation to use for circuit/CA binding.
 * @param PARAMS CaEvalParams class specifying extra evaluation parameters if
 * needed.
 */
template <class CIRCUIT, class BINDING, class PARAMS = DefParams>
class PrivateFactory {
    public:
        /**
         * Return newly created instance of CaEvaluator object.
         */
        static CaEvaluator* create() {
            return new CaEvaluator(CIRCUIT(), BINDING(), PARAMS());
        }
};
 
/**
 * Static-only factory creating evaluators for GATE circuits.
 * @param GATE Template specifying the gate. This parameter is a template
 * accepting one parameter (count of input wires).
 * @param N Count of input wires.
 */
template <template <int> class GATE, int N>
class GateFactory {
    public:
        typedef GATE<N>                                 TGate;
        typedef typename Binder<N,1>::tag               TBinding;
 
    public:
        /**
         * Return newly created instance of CaEvaluator object.
         */
        static CaEvaluator* create() {
            return PrivateFactory<TGate, TBinding>::create();
        }
 
    private:
        /// abort compilation if the input binding is inappropriate
        CT_ASSERT<TBinding::BOUND_INPUTS + 1 == 1 << N>
            ___COMPILE_TIME_ERROR__INAPPROPRIATE_INPUT_BINDING_FOR_GATE___;
 
        /// abort compilation if the output binding is inappropriate
        CT_ASSERT<TBinding::BOUND_OUTPUTS == 1>
            ___COMPILE_TIME_ERROR__INAPPROPRIATE_OUTPUT_BINDING_FOR_GATE___;
};
 
/**
 * Static-only factory creating evaluators for wire-cross circuits.
 * @param GATE Template specifying the gate. This parameter is a template
 * accepting one parameter (count of input wires).
 * @param N Count of input wires.
 */
template <int N, template <int> class GATE = CrossGate>
class WireCrossFactory {
    public:
        typedef GATE<N>                                 TGate;
        typedef typename Binder<N,N>::tag               TBinding;
 
    public:
        /**
         * Return newly created instance of CaEvaluator object.
         */
        static CaEvaluator* create() {
            return PrivateFactory<TGate, TBinding>::create();
        }
 
    private:
        /// abort compilation if the input binding is inappropriate
        CT_ASSERT<TBinding::BOUND_INPUTS + 1 == 1 << N>
            ___COMPILE_TIME_ERROR__INAPPROPRIATE_INPUT_BINDING_FOR_CROSS___;
 
        /// abort compilation if the output binding is inappropriate
        CT_ASSERT<TBinding::BOUND_OUTPUTS + 1 == 1 << N>
            ___COMPILE_TIME_ERROR__INAPPROPRIATE_OUTPUT_BINDING_FOR_CROSS___;
};
 
/**
 * IGate implementation of N-inputs multiplexer (hard-wired).
 * @todo fully generic mux definition in CaFactory.h
 * @param N @b total count of inputs (data wires + select wires).
 */
template <int N> class MuxGate;
 
/**
 * mux2 implementation (2+1 inputs, 1 output).
 */
template <>
class MuxGate<3>: public AbstractGate<3,1> {
    public:
        virtual IGate* clone() const {
            return new MuxGate(*this);
        }
        virtual TBus operator[] (TBus in) const {
            bool result = (in & 4)
                ? (in & 2)
                : (in & 1);
            return result;
        }
};
 
/**
 * mux4 implementation (4+2 inputs, 1 output).
 */
template <>
class MuxGate<6>: public AbstractGate<6,1> {
    public:
        virtual IGate* clone() const {
            return new MuxGate(*this);
        }
        virtual TBus operator[] (TBus in) const {
            const TBus select = (in & 0x30) >> 4;
            switch (select) {
                case 0: return static_cast<bool>(in & (1 << 0));
                case 1: return static_cast<bool>(in & (1 << 1));
                case 2: return static_cast<bool>(in & (1 << 2));
                case 3: return static_cast<bool>(in & (1 << 3));
                default:
                    assert(false);
            }
        }
};
 
/**
 * Static-only factory creating evaluators for mux4 circuits.
 */
class Mux4Factory {
    private:
#ifndef BUILDING_DOX
        struct Mux4Params: public CaEvalParams {
            Mux4Params() {
                caSize = 3;
                nSteps = 4;
            }
        };
#endif
 
    public:
        typedef MuxGate<6>                              TGate;
        typedef BindInput<0, 0, 0,
                BindInput<1, 0, 2,
                BindInput<2, 2, 0,
                BindInput<3, 2, 1,
                BindInput<4, 0, 1,
                BindInput<5, 1, 1,
                BindOutput<0, 2, 2>
                > > > > > >                             TBinding;
        typedef Mux4Params                              TParams;
 
    public:
        /**
         * Return newly created instance of CaEvaluator object.
         */
        static CaEvaluator* create() {
            return PrivateFactory<TGate, TBinding, TParams>::create();
        }
 
    private:
        /// abort compilation if the input binding is inappropriate
        CT_ASSERT<TBinding::BOUND_INPUTS == 63>
            ___COMPILE_TIME_ERROR__INAPPROPRIATE_INPUT_BINDING_FOR_MUX4___;
 
        /// abort compilation if the output binding is inappropriate
        CT_ASSERT<TBinding::BOUND_OUTPUTS == 1>
            ___COMPILE_TIME_ERROR__INAPPROPRIATE_OUTPUT_BINDING_FOR_MUX4___;
};
 
/**
 * Collection of mul2x3/mul3x3 binders.
 * @param N Count of input/output signals to bind.
 * @param CA_SIZE CA's size in one direction.
 */
template <int N, int CA_SIZE>
struct MulBinder {
    /* no tag - this will fail intentionally */
};
 
/// mul2x3 binder (CA 3x3)
template <> struct MulBinder<5, 3> DOX_FAKE_PARENT(MulBinder)
{
    typedef BindInput<0, 0, 2,
            BindInput<1, 0, 1,
            BindInput<2, 2, 2,
            BindInput<3, 2, 1,
            BindInput<4, 2, 0,
            BindOutput<0, 0, 2,
            BindOutput<1, 2, 2,
            BindOutput<2, 0, 1,
            BindOutput<3, 2, 1,
            BindOutput<4, 2, 0>
            > > > > > > > > > tag;
};
 
/// mul3x3-ca3x3 binder
template <> struct MulBinder<6, 3> DOX_FAKE_PARENT(MulBinder)
{
    typedef BindInput<0, 1, 2,
            BindInput<1, 0, 1,
            BindInput<2, 2, 0,
            BindInput<3, 2, 2,
            BindInput<4, 1, 1,
            BindInput<5, 0, 0,
            BindOutput<0, 1, 2,
            BindOutput<1, 0, 2,
            BindOutput<2, 0, 1,
            BindOutput<3, 2, 1,
            BindOutput<4, 2, 0,
            BindOutput<5, 1, 0>
            > > > > > > > > > > > tag;
};
 
/// mul3x3-ca4x4 binder
template <> struct MulBinder<6, 4> DOX_FAKE_PARENT(MulBinder)
{
    typedef BindInput<0, 2, 3,
            BindInput<1, 1, 2,
            BindInput<2, 0, 1,
            BindInput<3, 3, 2,
            BindInput<4, 2, 1,
            BindInput<5, 1, 0,
            BindOutput<0, 2, 3,
            BindOutput<1, 3, 2,
            BindOutput<2, 1, 2,
            BindOutput<3, 2, 1,
            BindOutput<4, 0, 1,
            BindOutput<5, 1, 0>
            > > > > > > > > > > > tag;
};
 
/**
 * Static-only factory creating evaluators for mul2x3/mul3x3 circuits.
 * @param N Count of input/output signals to bind.
 * @param CA_SIZE CA's size in one direction.
 */
template <int N, int CA_SIZE>
class MulFactory {
    private:
        static const size_t MASK = (1 << N) - 1;
#ifndef BUILDING_DOX
        struct MulParams: public CaEvalParams {
            MulParams() {
                caSize = CA_SIZE;
                nSteps = 13;
            }
        };
#endif
 
    public:
        typedef MulGate<N>                              TGate;
        typedef typename MulBinder<N, CA_SIZE>::tag     TBinding;
        typedef MulParams                               TParams;
 
    public:
        /**
         * Return newly created instance of CaEvaluator object.
         */
        static CaEvaluator* create() {
            return PrivateFactory<TGate, TBinding, TParams>::create();
        }
 
    private:
        /// abort compilation if the input binding is inappropriate
        CT_ASSERT<TBinding::BOUND_INPUTS == MASK>
            ___COMPILE_TIME_ERROR__INAPPROPRIATE_INPUT_BINDING_FOR_MUX4___;
 
        /// abort compilation if the output binding is inappropriate
        CT_ASSERT<TBinding::BOUND_OUTPUTS == MASK>
            ___COMPILE_TIME_ERROR__INAPPROPRIATE_OUTPUT_BINDING_FOR_MUX4___;
};
 
// /////////////////////////////////////////////////////////////////////////////
// CaEvaluatorFactory implementation
#ifndef BUILDING_DOX
struct CaEvaluatorFactory::Private {
    typedef std::map<std::string, CaEvaluator* (*)()>   TMap;
    typedef std::set<std::string>                       TSet;
 
    TMap map;
    TSet trivialSet;
    TSet complexSet;
};
#endif
 
CaEvaluatorFactory::CaEvaluatorFactory():
    d(new Private)
{
    // 2-inputs gates
    d->map["and2"] = GateFactory <AndGate, 2> ::create;
    d->map[ "or2"] = GateFactory < OrGate, 2> ::create;
    d->map["xor2"] = GateFactory <XorGate, 2> ::create;
 
    // 3-inputs gates
    d->map["mux2"] = GateFactory <MuxGate, 3> ::create;
    d->map["and3"] = GateFactory <AndGate, 3> ::create;
    d->map[ "or3"] = GateFactory < OrGate, 3> ::create;
    d->map["xor3"] = GateFactory <XorGate, 3> ::create;
 
    // 5-inputs gates
    d->map["and5"] = GateFactory <AndGate, 5> ::create;
    d->map[ "or5"] = GateFactory < OrGate, 5> ::create;
 
    // xor5 converges immediately with incremental nStep
    // TODO: implement incremental nStep as an option
    d->map["xor5"] = GateFactory <XorGate, 5> ::create;
 
    // wire crossing
    d->map["cross2"] = WireCrossFactory <2> ::create;
    d->map["cross3"] = WireCrossFactory <3> ::create;
    d->map["cross2x2"] = WireCrossFactory <4, BusGate> ::create;
 
    // 4-input mux converges immediately with incremental caStep
    // TODO: implement incremental nStep as an option
    d->map["mux4"] = Mux4Factory::create;
 
    // mul
    d->map["mul2x3"] = MulFactory<5, 3>::create;
    d->map["mul3x3-ca3x3"] = MulFactory<6, 3>::create;
    d->map["mul3x3-ca4x4"] = MulFactory<6, 4>::create;
 
    // mark 2-inputs gates as trivial
    d->trivialSet.insert("and2");
    d->trivialSet.insert( "or2");
    d->trivialSet.insert("xor2");
    d->trivialSet.insert("cross2");
 
    // mark 4+ inputs gates as complex
    d->complexSet.insert("cross2x2");
    d->complexSet.insert("mux4");
    d->complexSet.insert("and5");
    d->complexSet.insert( "or5");
    d->complexSet.insert("xor5");
    d->complexSet.insert("mul2x3");
    d->complexSet.insert("mul3x3-ca3x3");
    d->complexSet.insert("mul3x3-ca4x4");
}
 
CaEvaluatorFactory::~CaEvaluatorFactory() {
    delete d;
}
 
CaEvaluator* CaEvaluatorFactory::create(const std::string &what) {
    // circuit lookup
    Private::TMap::iterator i = d->map.find(what);
    if (i != d->map.end())
        return (i->second)();
 
    // circuit not found
    // throw an exception containing list of available circuits
    std::ostringstream str;
    str << "invalid circuit: "
        << Color(C_LIGHT_RED) << what << Color(C_NO_COLOR)
        << " (implemented circuits are: " << Color(C_LIGHT_BLUE);
    for (i = d->map.begin(); i != d->map.end(); ++i) {
        if (i != d->map.begin())
            str << ", ";
        str << i->first;
    }
    str << Color(C_NO_COLOR) << ")";
    throw std::runtime_error(str.str());
}
 
void CaEvaluatorFactory::printList(std::ostream &str) {
    Private::TMap::iterator i;
    for (i = d->map.begin(); i != d->map.end(); ++i) {
#if !GF_INCLUDE_TRIVIAL
        if (d->trivialSet.end() != d->trivialSet.find(i->first))
            continue;
#endif
#if !GF_INCLUDE_COMPLEX
        if (d->complexSet.end() != d->complexSet.find(i->first))
            continue;
#endif
        str << i->first << std::endl;
    }
}