Skip to content

Commit a304b42

Browse files
georgkrylovjeanlego
authored andcommitted
ODIN_II: introduction of mixing hard multipliers complex optimization.
This commit introduces a new optimization allowing to mix hard and soft logic implementation for some circuits. This optimization allows exploring frequency and device size trade-off. The optimization can be enabled from command line options. The optimization currently works only for architecture files that do not have hard adders. This commit also changes the nnode_t structure shape Signed-off-by: Georgiy Krylov <[email protected]>
1 parent a9af579 commit a304b42

File tree

8 files changed

+622
-1
lines changed

8 files changed

+622
-1
lines changed

ODIN_II/SRC/HardSoftLogicMixer.cpp

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/*
2+
* Permission is hereby granted, free of charge, to any person
3+
* obtaining a copy of this software and associated documentation
4+
* files (the "Software"), to deal in the Software without
5+
* restriction, including without limitation the rights to use,
6+
* copy, modify, merge, publish, distribute, sublicense, and/or sell
7+
* copies of the Software, and to permit persons to whom the
8+
* Software is furnished to do so, subject to the following
9+
* conditions:
10+
*
11+
* The above copyright notice and this permission notice shall be
12+
* included in all copies or substantial portions of the Software.
13+
*
14+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15+
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
16+
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17+
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
18+
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
19+
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20+
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
21+
* OTHER DEALINGS IN THE SOFTWARE.
22+
*/
23+
#include "HardSoftLogicMixer.hpp"
24+
25+
#include <stdint.h> // INT_MAX
26+
#include <vector>
27+
28+
#include "multipliers.h" // instantiate_simple_soft_multiplier
29+
#include "odin_error.h" // error_message
30+
31+
HardSoftLogicMixer::HardSoftLogicMixer() {
32+
for (int i = 0; i < operation_list_END; i++) {
33+
if (i == MULTIPLY) {
34+
this->_opts[i] = new MultsOpt();
35+
} else {
36+
this->_opts[i] = new MixingOpt();
37+
}
38+
}
39+
}
40+
41+
HardSoftLogicMixer::~HardSoftLogicMixer() {
42+
for (int i = 0; i < operation_list_END; i++) {
43+
delete this->_opts[i];
44+
}
45+
}
46+
void HardSoftLogicMixer::note_candidate_node(nnode_t* opNode) {
47+
_nodes_by_opt[opNode->type].push_back(opNode);
48+
}
49+
50+
bool HardSoftLogicMixer::hardenable(nnode_t* node) {
51+
return this->_opts[node->type]->hardenable(node);
52+
}
53+
54+
bool HardSoftLogicMixer::enabled(nnode_t* node) {
55+
return this->_opts[node->type]->enabled();
56+
}
57+
58+
int HardSoftLogicMixer::hard_blocks_needed(operation_list opt) {
59+
return _nodes_by_opt[opt].size();
60+
}
61+
62+
void HardSoftLogicMixer::partial_map_node(nnode_t* node, short traverse_number, netlist_t* netlist) {
63+
_opts[node->type]->partial_map_node(node, traverse_number, netlist, this);
64+
}
65+
66+
void HardSoftLogicMixer::perform_optimizations(netlist_t* netlist) {
67+
if (_opts[MULTIPLY]->enabled()) {
68+
int blocks_needed = this->hard_blocks_needed(MULTIPLY);
69+
_opts[MULTIPLY]->set_blocks_needed(blocks_needed);
70+
_opts[MULTIPLY]->assign_weights(netlist, _nodes_by_opt[MULTIPLY]);
71+
_opts[MULTIPLY]->perform(netlist, _nodes_by_opt[MULTIPLY]);
72+
_opts[MULTIPLY]->instantiate_soft_logic(netlist, _nodes_by_opt[MULTIPLY]);
73+
}
74+
}

ODIN_II/SRC/MixingOptimization.cpp

Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
/*
2+
* Permission is hereby granted, free of charge, to any person
3+
* obtaining a copy of this software and associated documentation
4+
* files (the "Software"), to deal in the Software without
5+
* restriction, including without limitation the rights to use,
6+
* copy, modify, merge, publish, distribute, sublicense, and/or sell
7+
* copies of the Software, and to permit persons to whom the
8+
* Software is furnished to do so, subject to the following
9+
* conditions:
10+
*
11+
* The above copyright notice and this permission notice shall be
12+
* included in all copies or substantial portions of the Software.
13+
*
14+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15+
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
16+
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17+
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
18+
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
19+
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20+
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
21+
* OTHER DEALINGS IN THE SOFTWARE.
22+
*/
23+
24+
#include "MixingOptimization.hpp"
25+
26+
#include <stdint.h> // INT_MAX
27+
#include <vector>
28+
29+
#include "netlist_statistic.h" // mixing_optimization_stats
30+
#include "multipliers.h" // instantiate_simple_soft_multiplier
31+
#include "odin_error.h" // error_message
32+
#include "adders.h" // hard_adders
33+
#include "HardSoftLogicMixer.hpp" // HardSoftLogicMixer
34+
35+
void MixingOpt::scale_counts() {
36+
if (this->_blocks_count < 0 || this->_blocks_count == INT_MAX || this->_ratio < 0.0 || this->_ratio > 1.0) {
37+
error_message(NETLIST, unknown_location, "%s",
38+
"The parameters for optimization kind:%i are configured incorrectly : count %i, ratio %f\n", this->_kind, this->_blocks_count, this->_ratio);
39+
exit(0);
40+
}
41+
this->_blocks_count = this->_blocks_count * this->_ratio;
42+
}
43+
44+
void MixingOpt::assign_weights(netlist_t* /*netlist*/, std::vector<nnode_t*> /*nodes*/) {
45+
// compute weights for all noted nodes
46+
error_message(NETLIST, unknown_location, "%s",
47+
"Assign_weights mixing optimization was called for optimization without specification provided, for kind %i\n", this->_kind);
48+
exit(0);
49+
}
50+
51+
void MixingOpt::perform(netlist_t*, std::vector<nnode_t*>&) {
52+
error_message(NETLIST, unknown_location, "%s",
53+
"Performing mixing optimization was called for optimization without method provided, for kind %i\n", this->_kind);
54+
exit(0);
55+
}
56+
57+
MultsOpt::MultsOpt(int _exact)
58+
: MixingOpt(1.0, MULTIPLY) {
59+
this->_blocks_count = _exact;
60+
this->_enabled = true;
61+
}
62+
63+
MultsOpt::MultsOpt(float ratio)
64+
: MixingOpt(ratio, MULTIPLY) {
65+
if (ratio < 0.0 || ratio > 1.0) {
66+
error_message(NETLIST, unknown_location, "%s",
67+
"Miltipliers mixing optimization is started with wrong ratio %f\n", ratio);
68+
exit(0);
69+
}
70+
71+
//Explicitly set all hard block multipliers to max
72+
this->_blocks_count = INT_MAX;
73+
this->_enabled = true;
74+
}
75+
76+
bool MultsOpt::hardenable(nnode_t* node) {
77+
int mult_size = std::max<int>(node->input_port_sizes[0], node->input_port_sizes[1]);
78+
return (hard_multipliers && (mult_size > min_mult));
79+
}
80+
81+
void MultsOpt::assign_weights(netlist_t* netlist, std::vector<nnode_t*> nodes) {
82+
// compute weights for all noted nodes
83+
for (size_t i = 0; i < nodes.size(); i++) {
84+
mixing_optimization_stats(nodes[i], netlist);
85+
}
86+
}
87+
88+
void MultsOpt::perform(netlist_t* netlist, std::vector<nnode_t*>& weighted_nodes) {
89+
size_t nodes_count = weighted_nodes.size();
90+
91+
// per optimization, instantiate hard logic
92+
for (int i = 0; i < this->_blocks_count; i++) {
93+
int maximal_cost = -1;
94+
int index = -1;
95+
for (size_t j = 0; j < nodes_count; j++) {
96+
// if found a new maximal cost that is higher than a current maximum AND is not restricted by input
97+
// params for minimal "hardenable" multiplier width
98+
if (maximal_cost < weighted_nodes[j]->weight && this->hardenable(weighted_nodes[j])) {
99+
maximal_cost = weighted_nodes[j]->weight;
100+
index = j;
101+
}
102+
}
103+
104+
// if there are no suitable nodes left, leave the loop to
105+
// implement remaining nodes in soft logic
106+
if (index < 0)
107+
break;
108+
109+
// indicate for future iterations the node was hardened
110+
weighted_nodes[index]->weight = -1;
111+
112+
if (hard_multipliers) {
113+
instantiate_hard_multiplier(weighted_nodes[index], this->cached_traverse_value, netlist);
114+
}
115+
}
116+
117+
// From the end of the vector, remove all nodes that were implemented in hard logic. The remaining
118+
// nodes will be instantiated in soft_map_remaining_nodes
119+
for (int i = nodes_count - 1; i >= 0; i--) {
120+
if (weighted_nodes[i]->weight == -1) {
121+
weighted_nodes.erase(weighted_nodes.begin() + i);
122+
}
123+
}
124+
}
125+
126+
void MixingOpt::set_blocks_needed(int new_count) {
127+
this->_blocks_count = new_count;
128+
}
129+
130+
void MultsOpt::set_blocks_needed(int new_count) {
131+
// with development for fixed_layout, this value will change
132+
int availableHardBlocks = INT_MAX;
133+
int hardBlocksNeeded = new_count;
134+
int hardBlocksCount = availableHardBlocks;
135+
136+
if (hardBlocksCount > hardBlocksNeeded) {
137+
hardBlocksCount = hardBlocksNeeded;
138+
}
139+
140+
if (hardBlocksCount < this->_blocks_count) {
141+
this->_blocks_count = hardBlocksCount;
142+
}
143+
144+
this->scale_counts();
145+
}
146+
void MixingOpt::instantiate_soft_logic(netlist_t* /*netlist*/, std::vector<nnode_t*> /* nodes*/) {
147+
error_message(NETLIST, unknown_location, "%s",
148+
"Performing instantiate_soft_logic was called for optimization without method provided, for kind %i\n", this->_kind);
149+
exit(0);
150+
}
151+
152+
void MixingOpt::partial_map_node(nnode_t* /*node*/, short /*traverse_value*/, netlist_t*, /*netlist*/ HardSoftLogicMixer* /*mixer*/) {
153+
error_message(NETLIST, unknown_location, "%s",
154+
"Performing partial_map_node was called for optimization without method provided, for kind %i\n", this->_kind);
155+
exit(0);
156+
}
157+
158+
void MultsOpt::partial_map_node(nnode_t* node, short traverse_value, netlist_t* netlist, HardSoftLogicMixer* mixer) {
159+
if (mixer->enabled(node) && mixer->hardenable(node)) {
160+
mixer->note_candidate_node(node);
161+
} else if (mixer->hardenable(node)) {
162+
instantiate_hard_multiplier(node, traverse_value, netlist);
163+
} else if (!hard_adders) {
164+
instantiate_simple_soft_multiplier(node, traverse_value, netlist);
165+
}
166+
this->cached_traverse_value = traverse_value;
167+
}
168+
169+
void MultsOpt::instantiate_soft_logic(netlist_t* netlist, std::vector<nnode_t*> nodes) {
170+
unsigned int size = nodes.size();
171+
for (unsigned int j = 0; j < size; j++) {
172+
instantiate_simple_soft_multiplier(nodes[j], this->cached_traverse_value, netlist);
173+
}
174+
for (int i = size - 1; i >= 0; i--) {
175+
nodes[i] = free_nnode(nodes[i]);
176+
nodes.erase(nodes.begin() + i);
177+
}
178+
}
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
/*
2+
* Permission is hereby granted, free of charge, to any person
3+
* obtaining a copy of this software and associated documentation
4+
* files (the "Software"), to deal in the Software without
5+
* restriction, including without limitation the rights to use,
6+
* copy, modify, merge, publish, distribute, sublicense, and/or sell
7+
* copies of the Software, and to permit persons to whom the
8+
* Software is furnished to do so, subject to the following
9+
* conditions:
10+
*
11+
* The above copyright notice and this permission notice shall be
12+
* included in all copies or substantial portions of the Software.
13+
*
14+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15+
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
16+
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17+
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
18+
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
19+
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20+
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
21+
* OTHER DEALINGS IN THE SOFTWARE.
22+
*/
23+
24+
#ifndef HARD_SOFT_LOGIC_MIXER_HPP
25+
#define HARD_SOFT_LOGIC_MIXER_HPP
26+
27+
#include "odin_types.h" // netlist_t, config_t
28+
#include "MixingOptimization.hpp"
29+
30+
class HardSoftLogicMixer {
31+
public:
32+
HardSoftLogicMixer();
33+
~HardSoftLogicMixer();
34+
/*----------------------------------------------------------------------
35+
* Returns whether the specific node is a candidate for implementing
36+
* in hard block
37+
*---------------------------------------------------------------------
38+
*/
39+
bool hardenable(nnode_t* node);
40+
41+
/*----------------------------------------------------------------------
42+
* Function: map_deferred_blocksQueries if mixing optimization is enabled for this kind of
43+
* of hard blocks
44+
*---------------------------------------------------------------------
45+
*/
46+
bool enabled(nnode_t* node);
47+
48+
/*----------------------------------------------------------------------
49+
* Function: perform_optimizations
50+
* For all noted nodes, that were noted as candidates to be implemented
51+
* on the hard blocks, launches corresponding procedure of chosing the
52+
* corresponding blocks
53+
* Parameters: netlist_t *
54+
*---------------------------------------------------------------------
55+
*/
56+
void perform_optimizations(netlist_t* netlist);
57+
58+
/*----------------------------------------------------------------------
59+
* Function: partial_map_node
60+
* High-level call to provide support for partial mapping layer
61+
* Parameters:
62+
* node_t * : pointer to node needs to perform mapping
63+
* netlist_t : pointer to netlist
64+
*---------------------------------------------------------------------
65+
*/
66+
void partial_map_node(nnode_t* node, short traverse_number, netlist_t*);
67+
68+
/*----------------------------------------------------------------------
69+
* Function: note_candidate_node
70+
* Calculates number of available hard blocks by issuing a call,
71+
* traverses the netlist and statistics to figure out
72+
* which operation should be implemented on the hard block
73+
* Parameters:
74+
* node_t * : pointer to candidate node
75+
*---------------------------------------------------------------------
76+
*/
77+
void note_candidate_node(nnode_t* node);
78+
79+
// This is a container containing all optimization passes
80+
MixingOpt* _opts[operation_list_END];
81+
82+
private:
83+
/*----------------------------------------------------------------------
84+
* Function: hard_blocks_needed
85+
* Returns cached value calculated from netlist, for a specific optimiza
86+
* tion kind
87+
*---------------------------------------------------------------------
88+
*/
89+
int hard_blocks_needed(operation_list);
90+
91+
// This array is composed of vectors, that store nodes that
92+
// are potential candidates for performing mixing optimization
93+
std::vector<nnode_t*> _nodes_by_opt[operation_list_END];
94+
};
95+
96+
#endif

0 commit comments

Comments
 (0)