Skip to content

Commit b029235

Browse files
authored
Merge pull request #2312 from CAS-Atlantic/mixed_adders
Mixed adders
2 parents 8d119de + b5ea674 commit b029235

File tree

15 files changed

+1480
-1065
lines changed

15 files changed

+1480
-1065
lines changed

odin_ii/src/config/read_xml_config_file.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,24 @@ void read_optimizations(pugi::xml_node a_node, config_t* config, const pugiutil:
247247
mixer->_opts[MULTIPLY] = new MultsOpt(exact);
248248
}
249249
}
250+
251+
prop = get_attribute(child, "adders_ratio", loc_data, OPTIONAL).as_string(NULL);
252+
if (prop != NULL) {
253+
float ratio = atof(prop);
254+
if (ratio >= 0.0 && ratio <= 1.0) {
255+
delete mixer->_opts[ADD];
256+
mixer->_opts[ADD] = new AddersOpt(ratio);
257+
}
258+
}
259+
260+
prop = get_attribute(child, "exact_adders", loc_data, OPTIONAL).as_string(NULL);
261+
if (prop != NULL) {
262+
int exact = atoi(prop);
263+
if (exact >= 0) {
264+
delete mixer->_opts[ADD];
265+
mixer->_opts[ADD] = new AddersOpt(exact);
266+
}
267+
}
250268
}
251269

252270
child = get_single_child(a_node, "memory", loc_data, OPTIONAL);

odin_ii/src/core/adders.cpp

Lines changed: 118 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ using vtr::t_linked_vptr;
4444
t_model* hard_adders = NULL;
4545
t_linked_vptr* add_list = NULL;
4646
t_linked_vptr* processed_adder_list = NULL;
47+
t_linked_vptr* split_adder_list = NULL;
4748
t_linked_vptr* chain_list = NULL;
4849
int total = 0;
4950
int* adder = NULL;
@@ -646,7 +647,7 @@ void split_adder(nnode_t* nodeo, int a, int b, int sizea, int sizeb, int cin, in
646647
init_split_adder(nodeo, node[i], a, sizea, b, sizeb, cin, cout, i, flag, netlist);
647648

648649
//store the processed hard adder node for optimization
649-
processed_adder_list = insert_in_vptr_list(processed_adder_list, node[i]);
650+
split_adder_list = insert_in_vptr_list(split_adder_list, node[i]);
650651
}
651652

652653
chain_information_t* adder_chain = allocate_chain_info();
@@ -767,21 +768,21 @@ void split_adder(nnode_t* nodeo, int a, int b, int sizea, int sizeb, int cin, in
767768
return;
768769
}
769770

770-
/*-------------------------------------------------------------------------
771-
* (function: iterate_adders)
772-
*
773-
* This function will iterate over all of the add operations that
774-
* exist in the netlist and perform a splitting so that they can
775-
* fit into a basic hard adder block that exists on the FPGA.
776-
* If the proper option is set, then it will be expanded as well
777-
* to just use a fixed size hard adder.
778-
*-----------------------------------------------------------------------*/
779-
void iterate_adders(netlist_t* netlist) {
771+
/**
772+
* -------------------------------------------------------------------------
773+
* (function: split_instantiate_hard_adder)
774+
*
775+
* @brief to split a hard adder into an adder chain of single
776+
* bit adders and instantiate each of them
777+
*
778+
* @param node multibit hard adder node
779+
* @param netlist pointer to netlist
780+
* -----------------------------------------------------------------------*/
781+
void split_instantiate_hard_adder(nnode_t* node, uintptr_t mark, netlist_t* netlist) {
780782
int sizea, sizeb, sizecin; //the size of
781783
int a, b;
782784
int count, counta, countb;
783785
int num = 0;
784-
nnode_t* node;
785786

786787
// offset to the adder size in case a dummy adder is added to
787788
// start of the adder chain to feed the first cin with gnd
@@ -796,6 +797,60 @@ void iterate_adders(netlist_t* netlist) {
796797
sizea = hard_adders->inputs->next->size;
797798

798799
oassert(sizecin == 1);
800+
oassert(node != NULL);
801+
802+
if (node->type == HARD_IP)
803+
node->type = ADD;
804+
805+
oassert(node->type == ADD);
806+
807+
a = node->input_port_sizes[0];
808+
b = node->input_port_sizes[1];
809+
num = (a >= b) ? a : b;
810+
node->bit_width = num;
811+
oassert(num >= min_threshold_adder && num >= min_add);
812+
// if the first cin in a chain is fed by a global input (offset = 0) the adder width is the
813+
// input width + 1 (to pass the last cout -> sumout) divided by size of the adder input ports
814+
// otherwise (offset = 1) a dummy adder is added to the chain to feed the first cin with gnd
815+
// how many adders a can split
816+
counta = (a + 1) / sizea + offset;
817+
// how many adders b can split
818+
countb = (b + 1) / sizeb + offset;
819+
// how many adders need to be split
820+
if (counta >= countb)
821+
count = counta;
822+
else
823+
count = countb;
824+
total++;
825+
split_adder(node, a, b, sizea, sizeb, 1, 1, count, netlist);
826+
827+
while (split_adder_list != NULL) {
828+
nnode_t* hard_adder = (nnode_t*)split_adder_list->data_vptr;
829+
split_adder_list = delete_in_vptr_list(split_adder_list);
830+
instantiate_hard_adder(hard_adder, mark, netlist);
831+
}
832+
return;
833+
}
834+
835+
/*-------------------------------------------------------------------------
836+
* (function: iterate_adders)
837+
*
838+
* This function will iterate over all of the add operations that
839+
* exist in the netlist and perform a splitting so that they can
840+
* fit into a basic hard adder block that exists on the FPGA.
841+
* If the proper option is set, then it will be expanded as well
842+
* to just use a fixed size hard adder.
843+
*-----------------------------------------------------------------------*/
844+
void iterate_adders(netlist_t* /* netlist */) {
845+
int a, b;
846+
int num = 0;
847+
nnode_t* node;
848+
849+
/* Can only perform the optimization if hard adders exist! */
850+
if (hard_adders == NULL)
851+
return;
852+
853+
t_linked_vptr* new_add_list = NULL;
799854

800855
while (add_list != NULL) {
801856
node = (nnode_t*)add_list->data_vptr;
@@ -811,25 +866,13 @@ void iterate_adders(netlist_t* netlist) {
811866
num = (a >= b) ? a : b;
812867
node->bit_width = num;
813868
if (num >= min_threshold_adder && num >= min_add) {
814-
// if the first cin in a chain is fed by a global input (offset = 0) the adder width is the
815-
// input width + 1 (to pass the last cout -> sumout) divided by size of the adder input ports
816-
// otherwise (offset = 1) a dummy adder is added to the chain to feed the first cin with gnd
817-
// how many adders a can split
818-
counta = (a + 1) / sizea + offset;
819-
// how many adders b can split
820-
countb = (b + 1) / sizeb + offset;
821-
// how many adders need to be split
822-
if (counta >= countb)
823-
count = counta;
824-
else
825-
count = countb;
826-
total++;
827-
split_adder(node, a, b, sizea, sizeb, 1, 1, count, netlist);
869+
new_add_list = insert_in_vptr_list(new_add_list, node);
828870
}
829871
// Store the node into processed_adder_list if the threshold is bigger than num
830872
else
831873
processed_adder_list = insert_in_vptr_list(processed_adder_list, node);
832874
}
875+
add_list = new_add_list;
833876
return;
834877
}
835878

@@ -1222,8 +1265,56 @@ static nnode_t* make_adder(operation_list funct, nnode_t* current_adder, nnode_t
12221265
return new_funct;
12231266
}
12241267

1268+
/*--------------------------------------------------------------------------
1269+
* (function: instantiate_simple_soft_adder )
1270+
* This is simply a copy of instantiate_add_w_carry;
1271+
* need to be worked out
1272+
* to use a single copy to avoid code repetition.
1273+
*------------------------------------------------------------------------*/
1274+
void instantiate_simple_soft_adder(nnode_t* node, short mark, netlist_t* netlist) {
1275+
// define locations in array when fetching pins
1276+
const int out = 0, input_a = 1, input_b = 2, pinout_count = 3;
1277+
1278+
oassert(node->num_input_pins > 0);
1279+
1280+
int* width = (int*)vtr::malloc(pinout_count * sizeof(int));
1281+
1282+
if (node->num_input_port_sizes == 2)
1283+
width[out] = node->output_port_sizes[0];
1284+
else
1285+
width[out] = node->num_output_pins;
1286+
1287+
width[input_a] = node->input_port_sizes[0];
1288+
width[input_b] = node->input_port_sizes[1];
1289+
1290+
instantiate_add_w_carry_block(width, node, mark, netlist, 0);
1291+
1292+
vtr::free(width);
1293+
}
1294+
12251295
void instantiate_add_w_carry_block(int* width, nnode_t* node, short mark, netlist_t* netlist, short subtraction) {
1226-
nnode_t* previous_carry = (subtraction) ? netlist->vcc_node : netlist->gnd_node;
1296+
nnode_t* previous_carry;
1297+
/**
1298+
* while hard adders are available, the function "iterate_adders"
1299+
* explode the add node into an adder chain in which each adders has cin
1300+
* pin. This is required due to adder hardblock structure. However, the
1301+
* cin pin need to be handled in the case of inferring a chain add node
1302+
* as soft logic (using MixingOptimization) since the soft logic inferrence
1303+
* automatically consider GND or VCC as cin pin according to the node type
1304+
*/
1305+
// check if node has cin port
1306+
if (node->num_input_port_sizes == 3) {
1307+
npin_t* cin = node->input_pins[width[1] + width[2]];
1308+
previous_carry = make_3port_gate(CARRY_FUNC, 1, 1, 1, 1, node, mark);
1309+
/* hook the GND as cin pin */
1310+
add_input_pin_to_node(previous_carry, get_zero_pin(netlist), 0);
1311+
/* connect the add node's cin as CARRY_FUNC inputs */
1312+
add_input_pin_to_node(previous_carry, get_one_pin(netlist), 1);
1313+
remap_pin_to_new_node(cin, previous_carry, 2);
1314+
} else {
1315+
/* considering VCC or GND as cin based on node type */
1316+
previous_carry = (subtraction) ? netlist->vcc_node : netlist->gnd_node;
1317+
}
12271318

12281319
for (int i = 0; i < width[0]; i++) {
12291320
/* set of flags for building purposes */

odin_ii/src/core/adders.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ void init_add_distribution();
5252
void report_add_distribution();
5353
void declare_hard_adder(nnode_t* node);
5454
void instantiate_hard_adder(nnode_t* node, short mark, netlist_t* netlist);
55+
void split_instantiate_hard_adder(nnode_t* node, uintptr_t mark, netlist_t* netlist);
5556
void find_hard_adders();
5657
void add_the_blackbox_for_adds(FILE* out);
5758
void define_add_function(nnode_t* node, FILE* out);
@@ -69,7 +70,7 @@ void remove_fanout_pins(nnode_t* node);
6970
void reallocate_pins(nnode_t* node, nnode_t* next_node);
7071
void free_op_nodes(nnode_t* node);
7172
int match_pins(nnode_t* node, nnode_t* next_node);
72-
73+
void instantiate_simple_soft_adder(nnode_t* node, short mark, netlist_t* netlist);
7374
void instantiate_add_w_carry_block(int* width, nnode_t* node, short mark, netlist_t* netlist, short subtraction);
7475
bool is_ast_adder(ast_node_t* node);
7576

odin_ii/src/core/multipliers.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ void instantiate_simple_soft_multiplier(nnode_t* node, short mark, netlist_t* ne
114114
width = node->output_port_sizes[0];
115115
multiplicand_width = width_b;
116116
multiplier_width = width_a;
117-
/* offset is related to which multport is chosen as the multiplicand */
117+
/* offset is related to which multiport is chosen as the multiplicand */
118118
multiplicand_offset_index = width_a;
119119
multiplier_offset_index = 0;
120120

@@ -354,7 +354,7 @@ void declare_hard_multiplier(nnode_t* node) {
354354
*-------------------------------------------------------------------------*/
355355
void instantiate_hard_multiplier(nnode_t* node, short mark, netlist_t* /*netlist*/) {
356356
oassert(node
357-
&& "node is NULL to instanciate hard multiplier");
357+
&& "node is NULL to instantiate hard multiplier");
358358

359359
declare_hard_multiplier(node);
360360

@@ -1323,7 +1323,7 @@ void clean_multipliers() {
13231323
* (function: cleanup_mult_old_node)
13241324
*
13251325
* @brief <clean up nodeo, a high level MULT node>
1326-
* In split_soft_multplier function, nodeo is splitted to small multipliers,
1326+
* In split_soft_multiplier function, nodeo is splitted to small multipliers,
13271327
* while because of the complexity of input pin connections they have not been
13281328
* remapped to new nodes, they just copied and added to new nodes. This function
13291329
* will detach input pins from the nodeo. Moreover, it will connect the net of

odin_ii/src/core/odin_ii.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -639,6 +639,16 @@ void get_options(int argc, char** argv) {
639639
.default_value("-1.0")
640640
.action(argparse::Action::STORE);
641641

642+
mixing_opt_grp.add_argument(global_args.exact_adders, "--exact_adders")
643+
.help("To enable mixing hard block and soft logic implementation of adders")
644+
.default_value("-1")
645+
.action(argparse::Action::STORE);
646+
647+
mixing_opt_grp.add_argument(global_args.adders_ratio, "--adders_ratio")
648+
.help("To enable mixing hard block and soft logic implementation of adders")
649+
.default_value("-1.0")
650+
.action(argparse::Action::STORE);
651+
642652
parser.parse_args(argc, argv);
643653

644654
//Check required options
@@ -720,6 +730,14 @@ void get_options(int argc, char** argv) {
720730
delete mixer->_opts[MULTIPLY];
721731
mixer->_opts[MULTIPLY] = new MultsOpt(global_args.exact_mults);
722732
}
733+
734+
if (global_args.adders_ratio >= 0.0 && global_args.adders_ratio <= 1.0) {
735+
delete mixer->_opts[ADD];
736+
mixer->_opts[ADD] = new AddersOpt(global_args.adders_ratio);
737+
} else if (global_args.exact_adders >= 0) {
738+
delete mixer->_opts[ADD];
739+
mixer->_opts[ADD] = new AddersOpt(global_args.exact_adders);
740+
}
723741
}
724742

725743
/*---------------------------------------------------------------------------

odin_ii/src/map/hard_soft_logic_mixer.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ HardSoftLogicMixer::HardSoftLogicMixer() {
3131
for (int i = 0; i < operation_list_END; i++) {
3232
if (i == MULTIPLY) {
3333
this->_opts[i] = new MultsOpt();
34+
} else if (i == ADD) {
35+
this->_opts[i] = new AddersOpt();
3436
} else {
3537
this->_opts[i] = new MixingOpt();
3638
}
@@ -70,4 +72,14 @@ void HardSoftLogicMixer::perform_optimizations(netlist_t* netlist) {
7072
_opts[MULTIPLY]->perform(netlist, _nodes_by_opt[MULTIPLY]);
7173
_opts[MULTIPLY]->instantiate_soft_logic(netlist, _nodes_by_opt[MULTIPLY]);
7274
}
75+
76+
if (_opts[ADD]->enabled()) {
77+
int blocks_needed = this->hard_blocks_needed(ADD);
78+
_opts[ADD]->set_blocks_needed(blocks_needed);
79+
_opts[ADD]->assign_weights(netlist, _nodes_by_opt[ADD]);
80+
_opts[ADD]->perform(netlist, _nodes_by_opt[ADD]);
81+
_opts[ADD]->instantiate_soft_logic(netlist, _nodes_by_opt[ADD]);
82+
} else {
83+
_opts[ADD]->instantiate_hard_logic(netlist, _nodes_by_opt[ADD]);
84+
}
7385
}

0 commit comments

Comments
 (0)