# Digital Logic Simulation with the Intel® TBB Flow Graph, Part 2: Building bigger components

In Part 1, I described how to put together a basic logic gate using the Intel® Threading Building Blocks flow graph nodes `or_node` and `multifunction_node`. In this blog, I will assume the basic logic gates `and_gate`, `or_gate` and `xor_gate` exist, and use them to construct a four-bit adder.

To begin with, I'll first construct a one-bit full adder as in Figure 2 below: The inputs are A and B, and a Carry-in bit, and the output is the sum S, and a Carry-out bit. Here is the code for the `one_bit_adder` class:

```class one_bit_adder {

broadcast_node < signal_t > A_port;

broadcast_node < signal_t > B_port;

broadcast_node < signal_t > CI_port;

xor_gate < two_input > FirstXOR;

xor_gate < two_input > SecondXOR;

and_gate < two_input > FirstAND;

and_gate < two_input > SecondAND;

or_gate < two_input > FirstOR;

graph& my_graph;

void make_connections() {

make_edge(A_port, FirstXOR.get_in(0));

make_edge(A_port, FirstAND.get_in(0));

make_edge(B_port, FirstXOR.get_in(1));

make_edge(B_port, FirstAND.get_in(1));

make_edge(CI_port, SecondXOR.get_in(1));

make_edge(CI_port, SecondAND.get_in(1));

make_edge(FirstXOR.get_out(), SecondXOR.get_in(0));

make_edge(FirstXOR.get_out(), SecondAND.get_in(0));

make_edge(SecondAND.get_out(), FirstOR.get_in(0));

make_edge(FirstAND.get_out(), FirstOR.get_in(1));

}

public:

one_bit_adder(graph& g) :

my_graph(g), A_port(g), B_port(g), CI_port(g), FirstXOR(g),

SecondXOR(g), FirstAND(g), SecondAND(g), FirstOR(g)

{

make_connections();

}

one_bit_adder(const one_bit_adder& src) :

my_graph(src.my_graph), A_port(src.my_graph), B_port(src.my_graph),

CI_port(src.my_graph), FirstXOR(src.my_graph), SecondXOR(src.my_graph),

FirstAND(src.my_graph), SecondAND(src.my_graph), FirstOR(src.my_graph)

{

make_connections();

}

~one_bit_adder() {}

receiver < signal_t > & get_A() { return A_port; }

receiver < signal_t > & get_B() { return B_port; }

receiver < signal_t > & get_CI() { return CI_port; }

sender < signal_t > & get_out() { return SecondXOR.get_out(); }

sender < signal_t > & get_CO() { return FirstOR.get_out(); }

};```

This implementation is almost a straightforward translation of the gates and their connections into the flow graph format. The one complication is the addition of the `broadcast_node`s for each of the input ports. The reason for this is simply to enable connection to a single port from outside of the adder. Since each of the inputs is connected to two gates inside of the `one_bit_adder` object, there is no single port associated with them automatically. Adding the `broadcast_node`s enables us to provide the methods `get_A`, `get_B` and `get_CI` that each return a single port capable of receiving data. So, in looking at the diagram above, you can think of the three `broadcast_node`s as standing in for the black junction circles that the three inputs are connected to directly.

To make the `four_bit_adder` class, simply chain together a set of four `one_bit_adder`s and connect the Carry-out port of each adder to the Carry-in port of the next adder, as shown in Figure 3 below: This time, the class is even more straightforward to implement, because no `broadcast_node`s are needed; every input already has exactly one internal connection.

```class four_bit_adder {

graph& my_graph;

std::vector < one_bit_adder > four_adders;

void make_connections() {

make_edge(four_adders.get_CO(), four_adders.get_CI());

make_edge(four_adders.get_CO(), four_adders.get_CI());

make_edge(four_adders.get_CO(), four_adders.get_CI());

}

public:

four_bit_adder(graph& g) : my_graph(g), four_adders(4, one_bit_adder(g)) {

make_connections();

}

four_bit_adder(const four_bit_adder& src) :

my_graph(src.my_graph), four_adders(4, one_bit_adder(src.my_graph))

{

make_connections();

}

~four_bit_adder() {}

receiver < signal_t > & get_A(size_t bit) {

return four_adders[bit].get_A();

}

receiver < signal_t > & get_B(size_t bit) {

return four_adders[bit].get_B();

}

receiver < signal_t > & get_CI() {

return four_adders.get_CI();

}

sender < signal_t > & get_out(size_t bit) {

return four_adders[bit].get_out();

}

sender < signal_t > & get_CO() {

return four_adders.get_CO();

}

};```

Here, the constructor makes a vector of exactly four adders, and connects the Carry-out ports to the Carry-in ports as appropriate. The multi-bit inputs and outputs have port access methods that take a bit as a parameter. So for example, to get the input port for bit 2 of input B, you would use `get_B(2)`.

In Part 3, I will present some interesting input and output devices to add to the logic simulation library, and with those, I’ll put together a small simulation that shows the `four_bit_adder` in action.

Для получения подробной информации о возможностях оптимизации компилятора обратитесь к нашему Уведомлению об оптимизации.
Возможность комментирования русскоязычного контента была отключена. Узнать подробнее.