Four bit adder: Difference between revisions
Content added Content deleted
mNo edit summary |
(C++ version of this example.) |
||
Line 438: | Line 438: | ||
return 0; |
return 0; |
||
}</lang> |
}</lang> |
||
=={{header|C++}}== |
|||
Remarks before we start: |
|||
*'...aim of this task is to simulate a four-bit adder chip.' According to this, |
|||
the class design is laid out like this: starting with 'I/O pins' of our 'chip', we represent |
|||
its 'inner circuit' by a 'logic block'. Logic blocks have a transfer function which creates signals for the |
|||
output pins from the signals at the input pins (and the inner state of the block, if necessary). Logic blocks may be |
|||
connected to form a more complex logic block; thereby we work our way up from the simple gates (AND, OR etc.) via more |
|||
complex circuits (XOR, half adder, etc.) to the four bit adder. In order to avoid the tedious work of encoding numbers |
|||
to bits and vice versa, we added conveniency blocks: a source (logic block without input pins) which sets its output pins according |
|||
to a given decimal number, and a sink (logic block without output pins) which calculates a decimal number from the state of |
|||
its input pins. |
|||
*'... gates ... can be imitated by using the bitwise operators...' I decided to use a boolean for a bit - firstly because |
|||
the largest 'numbers' in this example are 5 bits wide and secondly because this is should become rather a prove of concept |
|||
than highly efficient code. |
|||
*As C++ provides nice operator overloading and sophisticated templates, we'll make heavy use of these features - just for fun and elegance of syntax! |
|||
A Pin just stores just its signal value; declared as follows (Pin.h)... |
|||
<lang cpp>#if !defined __PIN_H__ |
|||
#define __PIN_H__ |
|||
namespace rosetta |
|||
{ |
|||
namespace fourBitAdder |
|||
{ |
|||
namespace detail |
|||
{ |
|||
class Pin |
|||
{ |
|||
protected: |
|||
Pin(); |
|||
Pin& Signal(bool value); |
|||
bool Signal()const; |
|||
private: |
|||
bool signal; |
|||
}; |
|||
} //namespace detail |
|||
} //namespace fourBitAdder |
|||
} //namespace rosetta |
|||
#endif //!defined __PIN_H__</lang> |
|||
... and defined like that (Pin.cpp): |
|||
<lang cpp>#include "Pin.h" |
|||
using rosetta::fourBitAdder::detail::Pin; |
|||
Pin::Pin() |
|||
:signal(false) |
|||
{} |
|||
Pin& Pin::Signal(bool value) |
|||
{ |
|||
signal = value; |
|||
return *this; |
|||
} |
|||
bool Pin::Signal()const |
|||
{ |
|||
return signal; |
|||
}</lang> |
|||
An input pin is a Pin which a value may be assigned to and can be got from; also, the input pin may be |
|||
connected to a signal source which then determines the input pin's value. Obviously, in our simple world, |
|||
such a signal source needs to be an output pin (PinIn.h): |
|||
<lang cpp>#if !defined __PININ_H__ |
|||
#define __PININ_H__ |
|||
#include "Pin.h" |
|||
namespace rosetta |
|||
{ |
|||
namespace fourBitAdder |
|||
{ |
|||
class PinOut; |
|||
class PinIn |
|||
:public detail::Pin |
|||
{ |
|||
friend void operator>>(const PinOut&, PinIn&); |
|||
public: |
|||
PinIn(); |
|||
PinIn& operator=(bool signal); |
|||
operator bool()const; |
|||
void Disconnect(); |
|||
private: |
|||
void Connect(const PinOut& output); |
|||
const PinOut* signalSource; |
|||
}; |
|||
} //namespace fourBitAdder |
|||
} //namespace rosetta |
|||
#endif //!defined __PININ_H__</lang> |
|||
The input pin's definition (PinIn.cpp): |
|||
<lang cpp>#include <memory> |
|||
#include <cassert> |
|||
#include "PinIn.h" |
|||
#include "PinOut.h" |
|||
using rosetta::fourBitAdder::PinIn; |
|||
using rosetta::fourBitAdder::PinOut; |
|||
PinIn::PinIn() |
|||
:detail::Pin() |
|||
,signalSource(NULL) |
|||
{} |
|||
PinIn& PinIn::operator=(bool signal) |
|||
{ |
|||
assert(signalSource == NULL); //otherwise, this will not have any effect |
|||
return static_cast<PinIn&>(Signal(signal)); |
|||
} |
|||
PinIn::operator bool()const |
|||
{ |
|||
if(signalSource == NULL) |
|||
return Signal(); |
|||
else |
|||
return *signalSource; |
|||
} |
|||
void PinIn::Disconnect() |
|||
{ |
|||
signalSource = NULL; |
|||
} |
|||
void PinIn::Connect(const PinOut& output) |
|||
{ |
|||
signalSource = &output; |
|||
}</lang> |
|||
An output pin is a Pin which a value may be assigned to and can be got from; also, the output pin may be |
|||
get its signal from the transfer function of a (logic) block. For this to work out properly, it is necessary |
|||
that an output pin knows to which block ('chip') it belongs to and what position it has there. Being |
|||
the bridge between a chip's inner circuits (the logic block) and the outside world, an output pin |
|||
may be connected to an input pin (PinOut.h): |
|||
<lang cpp>#if !defined __PINOUT_H__ |
|||
#define __PINOUT_H__ |
|||
#include "Pin.h" |
|||
namespace rosetta |
|||
{ |
|||
namespace fourBitAdder |
|||
{ |
|||
namespace detail |
|||
{ |
|||
class Block; |
|||
template<int, int> class LogicBlock; |
|||
} |
|||
class PinIn; |
|||
class PinOut |
|||
:public detail::Pin |
|||
{ |
|||
friend void operator>>(const PinOut&, PinIn&); |
|||
template<int, int> friend class detail::LogicBlock; |
|||
public: |
|||
PinOut(); |
|||
operator bool()const; |
|||
PinOut& operator=(bool signal); |
|||
private: |
|||
PinOut(detail::Block& container, int indexOfPinInContainer); |
|||
detail::Block*const container; |
|||
int indexOfPinInContainer; |
|||
}; |
|||
void operator>>(const PinOut& output, PinIn& input); |
|||
} //namespace fourBitAdder |
|||
} //namespace rosetta |
|||
#endif //!defined __PINOUT_H__</lang> |
|||
The output pin's definition (PinOut.cpp): |
|||
<lang cpp>#include "cassert" |
|||
#include "BaseLogic.h" |
|||
using rosetta::fourBitAdder::detail::Block; |
|||
#include "PinOut.h" |
|||
using rosetta::fourBitAdder::PinOut; |
|||
PinOut::PinOut() |
|||
:detail::Pin() |
|||
,container(NULL) |
|||
{} |
|||
PinOut::PinOut(Block& container, int indexOfPinInContainer) |
|||
:detail::Pin() |
|||
,container(&container) |
|||
,indexOfPinInContainer(indexOfPinInContainer) |
|||
{} |
|||
PinOut::operator bool()const |
|||
{ |
|||
if(container == NULL) |
|||
return Signal(); |
|||
else |
|||
return container->TransferFunction(indexOfPinInContainer); |
|||
} |
|||
PinOut& PinOut::operator=(bool signal) |
|||
{ |
|||
assert(container == NULL); //otherwise, this will not have any effect |
|||
return static_cast<PinOut&>(Signal(signal)); |
|||
} |
|||
void rosetta::fourBitAdder::operator>>(const PinOut& output, PinIn& input) |
|||
{ |
|||
input.Connect(output); |
|||
}</lang> |
|||
Now, we define a block which has no more than a pure virtual transfer function. The block serves as |
|||
a base for a logic block which adds a certain number of input and output pins to the transfer function. |
|||
Note how the numbers of input and output pins come in as template parameters (BaseLogic.h): |
|||
<lang cpp>#if !defined __BASELOGIC_H__ |
|||
#define __BASELOGIC_H__ |
|||
#include<memory> |
|||
#include<stdexcept> |
|||
#include<vector> |
|||
#include "PinIn.h" |
|||
#include "PinOut.h" |
|||
namespace rosetta |
|||
{ |
|||
namespace fourBitAdder |
|||
{ |
|||
namespace detail |
|||
{ |
|||
class Block |
|||
{ |
|||
public: |
|||
virtual bool TransferFunction(unsigned indexOfOutput)=0; |
|||
}; |
|||
template<int NumIn, int NumOut> |
|||
class LogicBlock |
|||
:Block |
|||
{ |
|||
public: |
|||
PinIn& In(unsigned i = 0)const |
|||
{ |
|||
if(i >= NumIn) |
|||
throw std::out_of_range("Index of input pin is out of range!"); |
|||
return *in[i]; |
|||
} |
|||
const PinOut& Out(unsigned i = 0) |
|||
{ |
|||
if(i >= NumOut) |
|||
throw std::out_of_range("Index of output pin is out of range!"); |
|||
return *out[i]; |
|||
} |
|||
protected: |
|||
LogicBlock() |
|||
{ |
|||
for(int i =0; i < NumIn; i++) |
|||
in.push_back(std::auto_ptr<PinIn>(new PinIn())); |
|||
for(int i =0; i < NumOut; i++) |
|||
out.push_back(std::auto_ptr<PinOut>(new PinOut(*this, i))); |
|||
} |
|||
enum |
|||
{ |
|||
NumInputs = NumIn, |
|||
NumOutputs = NumOut |
|||
}; |
|||
private: |
|||
std::vector<std::auto_ptr<PinIn> > in; |
|||
std::vector<std::auto_ptr<PinOut> > out; |
|||
}; |
|||
} //namespace detail |
|||
} //namespace fourBitAdder |
|||
} //namespace rosetta |
|||
#endif //!defined __BASELOGIC_H__</lang> |
|||
Defining a gate as a logic block with just one output, we declare such a base class. Then, definition of |
|||
the basic AND, OR and NOT gates with an arbitrary number of input pins is as easy as writing down the |
|||
appropriate transfer function. |
|||
<lang cpp>#if !defined __GATES_H__ |
|||
#define __GATES_H__ |
|||
#include"PinIn.h" |
|||
#include"BaseLogic.h" |
|||
namespace rosetta |
|||
{ |
|||
namespace fourBitAdder |
|||
{ |
|||
namespace detail |
|||
{ |
|||
template<int NumIn> |
|||
class Gate |
|||
: public LogicBlock<NumIn, 1> |
|||
{ |
|||
protected: |
|||
Gate() |
|||
:LogicBlock() |
|||
{} |
|||
}; |
|||
} //namespace detail |
|||
template<int NumIn> |
|||
class AndGate |
|||
: public detail::Gate<NumIn> |
|||
{ |
|||
public: |
|||
bool TransferFunction(unsigned indexOfOutput) |
|||
{ |
|||
bool result = true; |
|||
for(unsigned i = 0; i < NumIn; i++) |
|||
result = result && In(i); |
|||
return result; |
|||
} |
|||
}; |
|||
template <int NumIn> |
|||
class OrGate |
|||
: public detail::Gate<NumIn> |
|||
{ |
|||
public: |
|||
bool TransferFunction(unsigned indexOfOutput) |
|||
{ |
|||
bool result = false; |
|||
for(unsigned i = 0; i < NumIn; i++) |
|||
result = result || In(i); |
|||
return result; |
|||
} |
|||
}; |
|||
class NotGate |
|||
: public detail::Gate<1> |
|||
{ |
|||
public: |
|||
bool TransferFunction(unsigned indexOfOutput) |
|||
{ |
|||
return !In(0); |
|||
} |
|||
}; |
|||
} //namespace fourBitAdder |
|||
} //namespace rosetta |
|||
#endif //!defined __GATES_H__</lang> |
|||
Now we are ready for our first circuit build from several gates: the xor gate, following the schematic |
|||
given with this task, consists of two AND, two NOT and one OR gates (XorGate.h). |
|||
<lang cpp>#if !defined __XORGATE_H__ |
|||
#define __XORGATE_H__ |
|||
#include "Gates.h" |
|||
namespace rosetta |
|||
{ |
|||
namespace fourBitAdder |
|||
{ |
|||
class XorGate |
|||
: public detail::Gate<2> |
|||
{ |
|||
public: |
|||
XorGate(); |
|||
bool TransferFunction(unsigned indexOfOutput); |
|||
private: |
|||
AndGate<2> andA, andB; |
|||
NotGate notA, notB; |
|||
OrGate<2> or; |
|||
}; |
|||
} //namespace fourBitAdder |
|||
} //namespace rosetta |
|||
#endif //!defined __XORGATE_H__</lang> |
|||
The XOR gate's definition needs to set up the internal connections of the constituting gates and to |
|||
write down the transfer function which infers the XOR's output signal from its input signals. |
|||
<lang cpp>#include "XorGate.h" |
|||
using namespace rosetta::fourBitAdder; |
|||
XorGate::XorGate() |
|||
:Gate() |
|||
{ |
|||
notA.Out()>>andB.In(1); |
|||
notB.Out()>>andA.In(1); |
|||
andA.Out()>>or.In(0); |
|||
andB.Out()>>or.In(1); |
|||
} |
|||
bool XorGate::TransferFunction(unsigned indexOfOutput) |
|||
{ |
|||
andA.In(0) = In(0); |
|||
notA.In(0) = In(0); |
|||
andB.In(0) = In(1); |
|||
notB.In(0) = In(1); |
|||
return or.Out(); |
|||
}</lang> |
|||
A half adder has two inputs (Bit A and B) and two outputs (Sum and Carry); it consists of an AND and a XOR gate (HalfAdder.h): |
|||
<lang cpp>#if !defined __HALFADDER_H__ |
|||
#define __HALFADDER_H__ |
|||
#include "XorGate.h" |
|||
#include "Gates.h" |
|||
#include "BaseLogic.h" |
|||
namespace rosetta |
|||
{ |
|||
namespace fourBitAdder |
|||
{ |
|||
class PinOut; |
|||
class PinIn; |
|||
template<int> class AndGate; |
|||
class HalfAdder |
|||
: public detail::LogicBlock<2,2> |
|||
{ |
|||
public: |
|||
bool TransferFunction(unsigned indexOfOutput); |
|||
PinIn& BitA(); |
|||
PinIn& BitB(); |
|||
const PinOut& Sum(); |
|||
const PinOut& Carry(); |
|||
private: |
|||
AndGate<2> and; |
|||
XorGate xor; |
|||
}; |
|||
} //namespace fourBitAdder |
|||
} //namespace rosetta |
|||
#endif //!defined __HALFADDER_H__</lang> |
|||
Internal wiring is not required for the half adder; we just write down the transfer function which |
|||
is able to provide the values for either of the two outputs (HalfAdder.cpp): |
|||
<lang cpp>#include <stdexcept> |
|||
using std::out_of_range; |
|||
#include "HalfAdder.h" |
|||
using namespace rosetta::fourBitAdder; |
|||
bool HalfAdder::TransferFunction(unsigned indexOfOutput) |
|||
{ |
|||
switch(indexOfOutput) |
|||
{ |
|||
case 0: // sum |
|||
xor.In(0) = BitA(); |
|||
xor.In(1) = BitB(); |
|||
return xor.Out(); |
|||
case 1: // carry |
|||
and.In(0) = BitA(); |
|||
and.In(1) = BitB(); |
|||
return and.Out(); |
|||
default: |
|||
throw new out_of_range("There are only two output pins."); |
|||
} |
|||
} |
|||
PinIn& HalfAdder::BitA() {return In(0);} |
|||
PinIn& HalfAdder::BitB() {return In(1);} |
|||
const PinOut& HalfAdder::Sum() {return Out(0);} |
|||
const PinOut& HalfAdder::Carry() {return Out(1);} |
|||
</lang> |
|||
A full adder has three inputs (bits A and B as well as carry) and two outputs (sum and carry); it |
|||
consists of an OR gate and two half adders (FullAdder.h): |
|||
<lang cpp>#if !defined __FULLADDER_H__ |
|||
#define __FULLADDER_H__ |
|||
#include "BaseLogic.h" |
|||
#include "Gates.h" |
|||
#include "HalfAdder.h" |
|||
namespace rosetta |
|||
{ |
|||
namespace fourBitAdder |
|||
{ |
|||
class PinOut; |
|||
class PinIn; |
|||
class FullAdder |
|||
: public detail::LogicBlock<3,2> |
|||
{ |
|||
public: |
|||
FullAdder(); |
|||
bool TransferFunction(unsigned indexOfOutput); |
|||
PinIn& CarryInput(); |
|||
PinIn& BitA(); |
|||
PinIn& BitB(); |
|||
const PinOut& Sum(); |
|||
const PinOut& CarryResult(); |
|||
private: |
|||
OrGate<2> or; |
|||
HalfAdder bitAHalfAdder; |
|||
HalfAdder bitBHalfAdder; |
|||
}; |
|||
} //namespace fourBitAdder |
|||
} //namespace rosetta |
|||
#endif //!defined __FULLADDER_H__</lang> |
|||
The full adder's definition consists of setting up the internal connections of writing down the |
|||
proper transfer function (FullAdder.cpp): |
|||
<lang cpp>#include <stdexcept> |
|||
using std::out_of_range; |
|||
#include "FullAdder.h" |
|||
using namespace rosetta::fourBitAdder; |
|||
FullAdder::FullAdder() |
|||
{ |
|||
bitAHalfAdder.Sum()>>bitBHalfAdder.BitA(); |
|||
bitAHalfAdder.Carry()>>or.In(0); |
|||
bitBHalfAdder.Carry()>>or.In(1); |
|||
} |
|||
bool FullAdder::TransferFunction(unsigned indexOfOutput) |
|||
{ |
|||
bitAHalfAdder.BitA() = CarryInput(); |
|||
bitAHalfAdder.BitB() = BitA(); |
|||
bitBHalfAdder.BitB() = BitB(); |
|||
switch(indexOfOutput) |
|||
{ |
|||
case 0: //sum |
|||
return bitBHalfAdder.Sum(); |
|||
case 1: //carry bit |
|||
return or.Out(); |
|||
default: |
|||
throw new out_of_range("There are only two output pins."); |
|||
} |
|||
} |
|||
const PinOut& FullAdder::Sum() {return Out(0);} |
|||
const PinOut& FullAdder::CarryResult() {return Out(1);} |
|||
PinIn& FullAdder::CarryInput(){return In(0);} |
|||
PinIn& FullAdder::BitA(){return In(1);} |
|||
PinIn& FullAdder::BitB(){return In(2);}</lang> |
|||
Finally, we arrive at the four bit adder, a circuit boasting 8 inputs (2 four bit numbers) and five |
|||
outputs (4 bit number plus carry, or just a five bit number) (FourBitAdder.h): |
|||
<lang cpp>#if !defined __FOURBITADDER_H__ |
|||
#define __FOURBITADDER_H__ |
|||
#include "BaseLogic.h" |
|||
#include <memory> |
|||
#include <vector> |
|||
#include "FullAdder.h" |
|||
namespace rosetta |
|||
{ |
|||
namespace fourBitAdder |
|||
{ |
|||
class PinOut; |
|||
class PinIn; |
|||
class FourBitAdder |
|||
: public detail::LogicBlock<8,5> |
|||
{ |
|||
public: |
|||
FourBitAdder(); |
|||
bool TransferFunction(unsigned indexOfOutput); |
|||
PinIn& BitA(unsigned index); |
|||
PinIn& BitB(unsigned index); |
|||
const PinOut& Sum(unsigned index); |
|||
const PinOut& Carry(); |
|||
private: |
|||
std::vector<std::auto_ptr<FullAdder> > fullAdder; |
|||
}; |
|||
} //namespace fourBitAdder |
|||
} //namespace rosetta |
|||
#endif //!defined __FOURBITADDER_H__</lang> |
|||
The four bit adder consists of four full adders; the internal connections are simple: the LSB full adder's |
|||
carry input is always false, and carry outputs are connected to carry inputs of the next full adder (the |
|||
MSB full adder's carry output is the four bit adders carry output). The other input and output pins of our |
|||
full adders are related to the four bit adders input and output by the transfer function (FourBitAdder.cpp): |
|||
<lang cpp>#include <stdexcept> |
|||
using std::out_of_range; |
|||
#include <memory> |
|||
using std::auto_ptr; |
|||
#include <cassert> |
|||
#include "FourBitAdder.h" |
|||
using namespace rosetta::fourBitAdder; |
|||
FourBitAdder::FourBitAdder() |
|||
{ |
|||
assert(NumInputs == 8); |
|||
for(int i =0; i < NumInputs/2; i++) |
|||
fullAdder.push_back(auto_ptr<FullAdder>(new FullAdder())); |
|||
fullAdder[0]->CarryInput() = false; |
|||
for(int i = 1; i < NumInputs/2; i++) |
|||
fullAdder[i-1]->CarryResult()>>fullAdder[i]->CarryInput(); |
|||
} |
|||
bool FourBitAdder::TransferFunction(unsigned indexOfOutput) |
|||
{ |
|||
int numBits = NumInputs/2; |
|||
for(int i = 0; i < numBits; i++) |
|||
{ |
|||
fullAdder[i]->BitA() = In(i); |
|||
fullAdder[i]->BitB() = In(i+numBits); |
|||
} |
|||
assert(NumOutputs == 5); |
|||
switch(indexOfOutput) |
|||
{ |
|||
case 0: |
|||
case 1: |
|||
case 2: |
|||
case 3: |
|||
return fullAdder[indexOfOutput]->Sum(); //bits of resulting sum |
|||
case 4: |
|||
return fullAdder[indexOfOutput - 1]->CarryResult(); //carry bit |
|||
default: |
|||
assert(false); |
|||
return false; |
|||
} |
|||
} |
|||
PinIn& FourBitAdder::BitA(unsigned index) |
|||
{ |
|||
if(index < NumInputs/2) |
|||
return In(index); |
|||
else |
|||
throw new out_of_range("Input A does not have that much bits."); |
|||
} |
|||
PinIn& FourBitAdder::BitB(unsigned index) |
|||
{ |
|||
if(index < NumInputs/2) |
|||
return In(index + NumInputs/2); |
|||
else |
|||
throw new out_of_range("Input A does not have that much bits."); |
|||
} |
|||
const PinOut& FourBitAdder::Sum(unsigned index) |
|||
{ |
|||
if(index < (NumOutputs - 1)) |
|||
return Out(index); |
|||
else |
|||
throw new out_of_range("Sum output does not have that much bits."); |
|||
} |
|||
const PinOut& FourBitAdder::Carry() |
|||
{return Out(4);} |
|||
</lang> |
|||
Note how the complexity of the code for the XOR, half adder, full adder and four bit adder remained |
|||
comparable and quite simple, despite the fact that the number of basic gates involved increased from |
|||
5 (XOR) to 6 (half adder) to 13 (full adder) and finally to 52 (four bit adder). |
|||
In order to avoid fiddling around with single bits, we provide two conveniency circuits. For input, there |
|||
is the source, a logic block providing an an arbitrary number of outputs, but no inputs. Instead, it accepts |
|||
a simple decimal number as input and sets the signal at its outputs accordingly. A source may be connected |
|||
to (some of) the inputs of a logic block and thus allows easy control of the latter (Source.h): |
|||
<lang cpp>#if !defined __SOURCE_H__ |
|||
#define __SOURCE_H__ |
|||
#include <stdexcept> |
|||
#include <string> |
|||
#include <sstream> |
|||
#include <ostream> |
|||
#include "BaseLogic.h" |
|||
namespace rosetta |
|||
{ |
|||
namespace fourBitAdder |
|||
{ |
|||
template<int NumSources> |
|||
class Source |
|||
: protected detail::LogicBlock<0, NumSources> |
|||
{ |
|||
public: |
|||
Source() |
|||
:LogicBlock() |
|||
,maxSourceStateDecimal((1<<NumSources) - 1) |
|||
,sourceStateDecimal(0) |
|||
{} |
|||
Source& operator=(unsigned sourceStateDecimal) |
|||
{ |
|||
if(sourceStateDecimal > maxSourceStateDecimal) |
|||
this->sourceStateDecimal = maxSourceStateDecimal; |
|||
else |
|||
this->sourceStateDecimal = sourceStateDecimal; |
|||
return *this; |
|||
} |
|||
operator unsigned()const |
|||
{ |
|||
return sourceStateDecimal; |
|||
} |
|||
const PinOut& Bit(int i = 0) |
|||
{ |
|||
return detail::LogicBlock<0, NumSources>::Out(i); |
|||
} |
|||
template<typename LogicBlock> |
|||
LogicBlock& operator>>(LogicBlock& consumer) |
|||
{ |
|||
for(unsigned i = 0; i < NumSources; i++) |
|||
Out(i)>>consumer.In(i); |
|||
return consumer; |
|||
} |
|||
operator std::string() |
|||
{ |
|||
std::stringstream s; |
|||
for(int i = (NumSources - 1); i >= 0; i--) |
|||
s << Out(i); |
|||
return s.str(); |
|||
} |
|||
protected: |
|||
bool TransferFunction(unsigned i) |
|||
{ |
|||
return (sourceStateDecimal & 1<<i) == 1<<i; |
|||
} |
|||
private: |
|||
const unsigned maxSourceStateDecimal; |
|||
unsigned sourceStateDecimal; |
|||
}; |
|||
template <int NumSources> |
|||
std::ostream& operator<<(std::ostream& os, Source<NumSources>& src) |
|||
{ |
|||
os<<(std::string)src; |
|||
return os; |
|||
} |
|||
} //namespace fourBitAdder |
|||
} //namespace rosetta |
|||
#endif //!defined __SOURCE_H__</lang> |
|||
In order to interpret output, there is the sink: a logic block providing an arbitrary number of inputs, |
|||
but no outputs. Instead, from its input signals the sink calculates a decimal number. A sink may be |
|||
connected to (some of) the outputs of a logic block and thus allows easy access to that state of the latter (Sink.h): |
|||
<lang cpp>#if !defined __SINK_H__ |
|||
#define __SINK_H__ |
|||
#include <stdexcept> |
|||
#include <string> |
|||
#include <sstream> |
|||
#include <ostream> |
|||
#include <cassert> |
|||
#include "BaseLogic.h" |
|||
namespace rosetta |
|||
{ |
|||
namespace fourBitAdder |
|||
{ |
|||
template<int NumSinks> |
|||
class Sink |
|||
: protected detail::LogicBlock<NumSinks, 0> |
|||
{ |
|||
template<typename LogicBlock, int NumSinks> |
|||
friend void operator>>(const LogicBlock&, Sink<NumSinks>&); |
|||
public: |
|||
Sink() |
|||
:LogicBlock() |
|||
{} |
|||
operator unsigned()const |
|||
{ |
|||
unsigned sinkStateDecimal = 0; |
|||
for(unsigned i = 0; i < NumSinks;i++) |
|||
if(In(i)) |
|||
sinkStateDecimal += 1<<i; |
|||
return sinkStateDecimal; |
|||
} |
|||
PinIn& In(int i = 0)const |
|||
{ |
|||
return detail::LogicBlock<NumSinks, 0>::In(i); |
|||
} |
|||
operator std::string()const |
|||
{ |
|||
std::stringstream s; |
|||
for(int i = (NumSinks - 1); i >= 0; i--) |
|||
s << In(i); |
|||
return s.str(); |
|||
} |
|||
protected: |
|||
bool TransferFunction(unsigned i) |
|||
{ |
|||
assert(false); |
|||
return false; |
|||
} |
|||
}; |
|||
template<typename LogicBlock, int NumSinks> |
|||
void operator>>(LogicBlock& producer, Sink<NumSinks>& sink) |
|||
{ |
|||
for(unsigned i = 0; i < NumSinks; i++) |
|||
producer.Out(i)>>sink.In(i); |
|||
} |
|||
template <int NumSinks> |
|||
std::ostream& operator<<(std::ostream& os, Sink<NumSinks>& src) |
|||
{ |
|||
os<<(std::string)src; |
|||
return os; |
|||
} |
|||
} //namespace fourBitAdder |
|||
} //namespace rosetta |
|||
#endif //!defined __SINK_H__</lang> |
|||
Now, using the four bit adder with two sources of input and one sink for the result is quite simple: |
|||
We create the four necessary objects and connect them properly. With these preparations, |
|||
making the four bit adder do its calculation is just a matter of setting the sources to the |
|||
desired numbers and reading their sum from the sink. There's main.cpp: |
|||
<lang cpp>#include <iostream> |
|||
using std::cout; |
|||
using std::endl; |
|||
#include "FourBitAdder.h" |
|||
#include "Source.h" |
|||
#include "Sink.h" |
|||
using namespace rosetta::fourBitAdder; |
|||
int main(int argc, char** argv) |
|||
{ |
|||
//create four bit adder, 'input numbers' and 'output display' |
|||
Source<4> |
|||
fourBitAdderInputA, |
|||
fourBitAdderInputB; |
|||
FourBitAdder fba; |
|||
Sink<5> fourBitAdderResult; |
|||
//connect inputs, four bit adder and output |
|||
for(int i = 0; i < 4; i++) |
|||
{ |
|||
fourBitAdderInputA.Bit(i)>>fba.BitA(i); |
|||
fourBitAdderInputB.Bit(i)>>fba.BitB(i); |
|||
} |
|||
fba>>fourBitAdderResult; |
|||
//do (and check) all possible additions of two four bit numbers and print the results |
|||
for(unsigned a = 0; a < 16; a++) |
|||
for(unsigned b = 0; b < 16; b++) |
|||
{ |
|||
fourBitAdderInputA = a; |
|||
fourBitAdderInputB = b; |
|||
cout<<fourBitAdderInputA<<" + "<<fourBitAdderInputB<<" = "<<fourBitAdderResult<<endl; |
|||
assert(fourBitAdderInputA + fourBitAdderInputB == fourBitAdderResult); |
|||
} |
|||
return 0; |
|||
}</lang> |
|||
Output (source code is compiled by MS Visual C++ 10.0 (WinXP 32 bit) compiler): |
|||
<div style="height: 320px;overflow:scroll"> |
|||
<pre> |
|||
0000 + 0000 = 00000 |
|||
0000 + 0001 = 00001 |
|||
0000 + 0010 = 00010 |
|||
0000 + 0011 = 00011 |
|||
0000 + 0100 = 00100 |
|||
0000 + 0101 = 00101 |
|||
0000 + 0110 = 00110 |
|||
0000 + 0111 = 00111 |
|||
0000 + 1000 = 01000 |
|||
0000 + 1001 = 01001 |
|||
0000 + 1010 = 01010 |
|||
0000 + 1011 = 01011 |
|||
0000 + 1100 = 01100 |
|||
0000 + 1101 = 01101 |
|||
0000 + 1110 = 01110 |
|||
0000 + 1111 = 01111 |
|||
0001 + 0000 = 00001 |
|||
0001 + 0001 = 00010 |
|||
0001 + 0010 = 00011 |
|||
0001 + 0011 = 00100 |
|||
0001 + 0100 = 00101 |
|||
0001 + 0101 = 00110 |
|||
0001 + 0110 = 00111 |
|||
0001 + 0111 = 01000 |
|||
0001 + 1000 = 01001 |
|||
0001 + 1001 = 01010 |
|||
0001 + 1010 = 01011 |
|||
0001 + 1011 = 01100 |
|||
0001 + 1100 = 01101 |
|||
0001 + 1101 = 01110 |
|||
0001 + 1110 = 01111 |
|||
0001 + 1111 = 10000 |
|||
0010 + 0000 = 00010 |
|||
0010 + 0001 = 00011 |
|||
0010 + 0010 = 00100 |
|||
0010 + 0011 = 00101 |
|||
0010 + 0100 = 00110 |
|||
0010 + 0101 = 00111 |
|||
0010 + 0110 = 01000 |
|||
0010 + 0111 = 01001 |
|||
0010 + 1000 = 01010 |
|||
0010 + 1001 = 01011 |
|||
0010 + 1010 = 01100 |
|||
0010 + 1011 = 01101 |
|||
0010 + 1100 = 01110 |
|||
0010 + 1101 = 01111 |
|||
0010 + 1110 = 10000 |
|||
0010 + 1111 = 10001 |
|||
0011 + 0000 = 00011 |
|||
0011 + 0001 = 00100 |
|||
0011 + 0010 = 00101 |
|||
0011 + 0011 = 00110 |
|||
0011 + 0100 = 00111 |
|||
0011 + 0101 = 01000 |
|||
0011 + 0110 = 01001 |
|||
0011 + 0111 = 01010 |
|||
0011 + 1000 = 01011 |
|||
0011 + 1001 = 01100 |
|||
0011 + 1010 = 01101 |
|||
0011 + 1011 = 01110 |
|||
0011 + 1100 = 01111 |
|||
0011 + 1101 = 10000 |
|||
0011 + 1110 = 10001 |
|||
0011 + 1111 = 10010 |
|||
0100 + 0000 = 00100 |
|||
0100 + 0001 = 00101 |
|||
0100 + 0010 = 00110 |
|||
0100 + 0011 = 00111 |
|||
0100 + 0100 = 01000 |
|||
0100 + 0101 = 01001 |
|||
0100 + 0110 = 01010 |
|||
0100 + 0111 = 01011 |
|||
0100 + 1000 = 01100 |
|||
0100 + 1001 = 01101 |
|||
0100 + 1010 = 01110 |
|||
0100 + 1011 = 01111 |
|||
0100 + 1100 = 10000 |
|||
0100 + 1101 = 10001 |
|||
0100 + 1110 = 10010 |
|||
0100 + 1111 = 10011 |
|||
0101 + 0000 = 00101 |
|||
0101 + 0001 = 00110 |
|||
0101 + 0010 = 00111 |
|||
0101 + 0011 = 01000 |
|||
0101 + 0100 = 01001 |
|||
0101 + 0101 = 01010 |
|||
0101 + 0110 = 01011 |
|||
0101 + 0111 = 01100 |
|||
0101 + 1000 = 01101 |
|||
0101 + 1001 = 01110 |
|||
0101 + 1010 = 01111 |
|||
0101 + 1011 = 10000 |
|||
0101 + 1100 = 10001 |
|||
0101 + 1101 = 10010 |
|||
0101 + 1110 = 10011 |
|||
0101 + 1111 = 10100 |
|||
0110 + 0000 = 00110 |
|||
0110 + 0001 = 00111 |
|||
0110 + 0010 = 01000 |
|||
0110 + 0011 = 01001 |
|||
0110 + 0100 = 01010 |
|||
0110 + 0101 = 01011 |
|||
0110 + 0110 = 01100 |
|||
0110 + 0111 = 01101 |
|||
0110 + 1000 = 01110 |
|||
0110 + 1001 = 01111 |
|||
0110 + 1010 = 10000 |
|||
0110 + 1011 = 10001 |
|||
0110 + 1100 = 10010 |
|||
0110 + 1101 = 10011 |
|||
0110 + 1110 = 10100 |
|||
0110 + 1111 = 10101 |
|||
0111 + 0000 = 00111 |
|||
0111 + 0001 = 01000 |
|||
0111 + 0010 = 01001 |
|||
0111 + 0011 = 01010 |
|||
0111 + 0100 = 01011 |
|||
0111 + 0101 = 01100 |
|||
0111 + 0110 = 01101 |
|||
0111 + 0111 = 01110 |
|||
0111 + 1000 = 01111 |
|||
0111 + 1001 = 10000 |
|||
0111 + 1010 = 10001 |
|||
0111 + 1011 = 10010 |
|||
0111 + 1100 = 10011 |
|||
0111 + 1101 = 10100 |
|||
0111 + 1110 = 10101 |
|||
0111 + 1111 = 10110 |
|||
1000 + 0000 = 01000 |
|||
1000 + 0001 = 01001 |
|||
1000 + 0010 = 01010 |
|||
1000 + 0011 = 01011 |
|||
1000 + 0100 = 01100 |
|||
1000 + 0101 = 01101 |
|||
1000 + 0110 = 01110 |
|||
1000 + 0111 = 01111 |
|||
1000 + 1000 = 10000 |
|||
1000 + 1001 = 10001 |
|||
1000 + 1010 = 10010 |
|||
1000 + 1011 = 10011 |
|||
1000 + 1100 = 10100 |
|||
1000 + 1101 = 10101 |
|||
1000 + 1110 = 10110 |
|||
1000 + 1111 = 10111 |
|||
1001 + 0000 = 01001 |
|||
1001 + 0001 = 01010 |
|||
1001 + 0010 = 01011 |
|||
1001 + 0011 = 01100 |
|||
1001 + 0100 = 01101 |
|||
1001 + 0101 = 01110 |
|||
1001 + 0110 = 01111 |
|||
1001 + 0111 = 10000 |
|||
1001 + 1000 = 10001 |
|||
1001 + 1001 = 10010 |
|||
1001 + 1010 = 10011 |
|||
1001 + 1011 = 10100 |
|||
1001 + 1100 = 10101 |
|||
1001 + 1101 = 10110 |
|||
1001 + 1110 = 10111 |
|||
1001 + 1111 = 11000 |
|||
1010 + 0000 = 01010 |
|||
1010 + 0001 = 01011 |
|||
1010 + 0010 = 01100 |
|||
1010 + 0011 = 01101 |
|||
1010 + 0100 = 01110 |
|||
1010 + 0101 = 01111 |
|||
1010 + 0110 = 10000 |
|||
1010 + 0111 = 10001 |
|||
1010 + 1000 = 10010 |
|||
1010 + 1001 = 10011 |
|||
1010 + 1010 = 10100 |
|||
1010 + 1011 = 10101 |
|||
1010 + 1100 = 10110 |
|||
1010 + 1101 = 10111 |
|||
1010 + 1110 = 11000 |
|||
1010 + 1111 = 11001 |
|||
1011 + 0000 = 01011 |
|||
1011 + 0001 = 01100 |
|||
1011 + 0010 = 01101 |
|||
1011 + 0011 = 01110 |
|||
1011 + 0100 = 01111 |
|||
1011 + 0101 = 10000 |
|||
1011 + 0110 = 10001 |
|||
1011 + 0111 = 10010 |
|||
1011 + 1000 = 10011 |
|||
1011 + 1001 = 10100 |
|||
1011 + 1010 = 10101 |
|||
1011 + 1011 = 10110 |
|||
1011 + 1100 = 10111 |
|||
1011 + 1101 = 11000 |
|||
1011 + 1110 = 11001 |
|||
1011 + 1111 = 11010 |
|||
1100 + 0000 = 01100 |
|||
1100 + 0001 = 01101 |
|||
1100 + 0010 = 01110 |
|||
1100 + 0011 = 01111 |
|||
1100 + 0100 = 10000 |
|||
1100 + 0101 = 10001 |
|||
1100 + 0110 = 10010 |
|||
1100 + 0111 = 10011 |
|||
1100 + 1000 = 10100 |
|||
1100 + 1001 = 10101 |
|||
1100 + 1010 = 10110 |
|||
1100 + 1011 = 10111 |
|||
1100 + 1100 = 11000 |
|||
1100 + 1101 = 11001 |
|||
1100 + 1110 = 11010 |
|||
1100 + 1111 = 11011 |
|||
1101 + 0000 = 01101 |
|||
1101 + 0001 = 01110 |
|||
1101 + 0010 = 01111 |
|||
1101 + 0011 = 10000 |
|||
1101 + 0100 = 10001 |
|||
1101 + 0101 = 10010 |
|||
1101 + 0110 = 10011 |
|||
1101 + 0111 = 10100 |
|||
1101 + 1000 = 10101 |
|||
1101 + 1001 = 10110 |
|||
1101 + 1010 = 10111 |
|||
1101 + 1011 = 11000 |
|||
1101 + 1100 = 11001 |
|||
1101 + 1101 = 11010 |
|||
1101 + 1110 = 11011 |
|||
1101 + 1111 = 11100 |
|||
1110 + 0000 = 01110 |
|||
1110 + 0001 = 01111 |
|||
1110 + 0010 = 10000 |
|||
1110 + 0011 = 10001 |
|||
1110 + 0100 = 10010 |
|||
1110 + 0101 = 10011 |
|||
1110 + 0110 = 10100 |
|||
1110 + 0111 = 10101 |
|||
1110 + 1000 = 10110 |
|||
1110 + 1001 = 10111 |
|||
1110 + 1010 = 11000 |
|||
1110 + 1011 = 11001 |
|||
1110 + 1100 = 11010 |
|||
1110 + 1101 = 11011 |
|||
1110 + 1110 = 11100 |
|||
1110 + 1111 = 11101 |
|||
1111 + 0000 = 01111 |
|||
1111 + 0001 = 10000 |
|||
1111 + 0010 = 10001 |
|||
1111 + 0011 = 10010 |
|||
1111 + 0100 = 10011 |
|||
1111 + 0101 = 10100 |
|||
1111 + 0110 = 10101 |
|||
1111 + 0111 = 10110 |
|||
1111 + 1000 = 10111 |
|||
1111 + 1001 = 11000 |
|||
1111 + 1010 = 11001 |
|||
1111 + 1011 = 11010 |
|||
1111 + 1100 = 11011 |
|||
1111 + 1101 = 11100 |
|||
1111 + 1110 = 11101 |
|||
1111 + 1111 = 11110 |
|||
</pre> |
|||
</div> |
|||
=={{header|C sharp|C#}}== |
=={{header|C sharp|C#}}== |