Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F27032949
unique_table.hpp
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Authored By
Unknown
Size
40 KB
Referenced Files
None
Subscribers
None
unique_table.hpp
View Options
// Copyright 2025 Oliver Theimer
#pragma once
#include
<algorithm>
#include
<cassert>
#include
<climits>
#include
<cmath>
#include
<cstdint>
#include
<cstdio>
#include
<fstream>
#include
<iostream>
#include
<string>
#include
<unordered_map>
#include
<vector>
#include
"./bbdd_node.hpp"
#include
"./bbdd_types.hpp"
#include
"./chain_variable_ordering.hpp"
#include
"./computed_table.hpp"
#include
"./extend_table.hpp"
// idea from CUDD package
#define SIZEOF_VOID_P 8
#define SIZEOF_INT 4
#if SIZEOF_VOID_P == 8 && SIZEOF_INT == 4
typedef
uint32_t
bbdd_halfword_t
;
#else
typedef
uint16_t
bbdd_halfword_t
;
#endif
#define REF(n) entries[n].ref
#define LEVEL(n) entries[n].node.cvo_lvl
#define EQ(n) entries[n].node.eq_child
#define NEQ(n) entries[n].node.neq_child
#define INDEX(n) entries[n].node.index
#define NEXT(n) entries[n].next
#define NEXT_ENTRY(n) entries[n->next]
typedef
uint32_t
node_index_t
;
/**
* @class variable_relation_t
* @brief struct used to store information about a bbdd to generate its truth
* table
*
*/
struct
variable_relation_t
{
node_index_t
pv
;
node_index_t
sv
;
bool
eq
;
};
/**
* @class table_entry_t
* @brief struct that stored a single entry of the hash table
*
*/
struct
table_entry_t
{
bbdd_node_t
node
;
bbdd_halfword_t
next
;
bbdd_halfword_t
ref
;
};
/**
* @class output_map_t
* @brief struct that maps a bbdd root node to a human readable string
*
*/
struct
output_map_t
{
std
::
string
output
;
bbdd_node_t
*
bbdd
;
};
class
Unique_table
{
enum
return_codes
{
SUCCESS
,
OUT_OF_MEMORY
,
TABLE_FULL
};
#define NODE(n) entries[n].node
#define ENTRY(n) entries[n]
private
:
table_entry_t
*
entries
;
node_index_t
free_pos
;
uint32_t
capacity
;
std
::
string
module_name
;
std
::
vector
<
node_index_t
>
free_slots
;
/**
* @brief swap two adhacent variables in variable ordering
*
* @param pos_b position of the first variable
* @param pos_c position of the second variable
*/
void
swap_variable_order
(
node_index_t
pos_b
,
node_index_t
pos_c
)
{
assert
(
pos_b
+
1
==
pos_c
);
node_index_t
temp
=
(
*
cvo
)[
pos_b
].
in
;
(
*
cvo
)[
pos_b
].
in
=
(
*
cvo
)[
pos_c
].
in
;
(
*
cvo
)[
pos_c
].
in
=
temp
;
(
*
cvo
)[(
*
cvo
)[
pos_b
].
in
%
num_inputs
].
pos
=
pos_b
;
(
*
cvo
)[(
*
cvo
)[
pos_c
].
in
%
num_inputs
].
pos
=
pos_c
;
}
/**
* @brief recursive helper function to count the number of nodes in bbdd
*
* @param node bbdd root node whose size should be evaluated
* @return number of nodes in subgraph denoted by root node
*/
uint32_t
get_number_nodes_recursive
(
bbdd_node_t
*
node
)
{
if
(
IS_TERM
(
node
->
index
)
||
MARKED
(
node
))
{
return
0
;
}
SET_MARKED
(
node
);
uint32_t
neq_size
=
get_number_nodes_recursive
(
get_node_p
(
node
->
neq_child
));
uint32_t
eq_size
=
get_number_nodes_recursive
(
get_node_p
(
node
->
eq_child
));
return
(
neq_size
+
eq_size
)
+
1
;
}
/**
* @brief recursive helper function to dump a bbdd into a dot file format
*
* @param file dot file in which the output should be written to
* @param node root node whose subgraph should be printed into dot file format
* @return node index used for recursive print
*/
node_index_t
recursive_dump_dot
(
std
::
ofstream
&
file
,
bbdd_node_t
*
node
)
{
if
(
IS_TERM
(
node
->
index
)
||
MARKED
(
node
))
{
return
node
->
index
;
}
if
(
node
->
cvo_lvl
.
sv
!=
INT_MAX
)
{
file
<<
"
\n\t
"
<<
(
GET_INDEX
(
node
))
<<
" [label=
\"
"
<<
node
->
ref
<<
""
<<
(
GET_INDEX
(
node
))
<<
": "
<<
node
->
cvo_lvl
.
pv
<<
","
<<
node
->
cvo_lvl
.
sv
<<
"
\"
]
\n
"
;
}
else
{
file
<<
"
\n\t
"
<<
(
GET_INDEX
(
node
))
<<
" [label=
\"
"
<<
node
->
ref
<<
""
<<
(
GET_INDEX
(
node
))
<<
": "
<<
node
->
cvo_lvl
.
pv
<<
","
<<
1
<<
"
\"
]
\n
"
;
}
SET_MARKED
(
node
);
recursive_dump_dot
(
file
,
get_node_p
(
node
->
neq_child
));
recursive_dump_dot
(
file
,
get_node_p
(
node
->
eq_child
));
file
<<
"
\t
"
<<
(
GET_INDEX
(
node
))
<<
" -- "
<<
node
->
neq_child
<<
"[style=
\"
dashed
\"
]
\n
"
;
//<< "[style=\"dashed\", label=<<FONT POINT-SIZE=\"14\">≠</FONT>>]\n";
file
<<
"
\t
"
<<
(
GET_INDEX
(
node
))
<<
" -- "
<<
node
->
eq_child
<<
"
\n
"
;
return
(
GET_INDEX
(
node
));
}
/**
* @brief return the ith bit of an integer
*
* @param integer integer from which the bit should be retrieved
* @param bits number of bits in the integer
* @param index position of bit that should be retrieved
* @return boolean rather the bit is high (true) or low (false)
*/
bool
get_ith_bit
(
node_index_t
integer
,
node_index_t
bits
,
uint8_t
index
)
{
return
integer
&
(
1
<<
((
bits
-
1
)
-
index
));
}
/**
* @brief helper function that is used to collect truth table entries based on
* a variable relation list
*
* @param var_rel vector of variable relation entries retrieved from
* traversing the bbdd
* @param inputs number of inputs to the truth table
* @param tt vector of truth table values that should be filled by this
* function
* @param value that should be inserted into the truth table
*/
void
insert_tt_value
(
std
::
vector
<
variable_relation_t
>
var_rel
,
node_index_t
inputs
,
std
::
vector
<
bool
>
&
tt
,
bool
value
)
{
if
(
!
value
)
{
return
;
}
for
(
variable_relation_t
rel
:
var_rel
)
{
#ifdef DEBUG_TABLE
printf
(
"%d %s %d
\n
"
,
rel
.
pv
,
rel
.
eq
?
"="
:
"!="
,
rel
.
sv
);
#endif
}
for
(
uint32_t
i
=
0
;
i
<
tt
.
size
();
i
++
)
{
bool
insert
=
true
;
for
(
variable_relation_t
rel
:
var_rel
)
{
if
(
rel
.
eq
)
{
if
(
rel
.
sv
==
INT_MAX
)
{
if
(
!
get_ith_bit
(
i
,
inputs
,
rel
.
pv
-
2
))
{
insert
=
false
;
}
}
else
if
(
get_ith_bit
(
i
,
inputs
,
rel
.
pv
-
2
)
!=
get_ith_bit
(
i
,
inputs
,
rel
.
sv
-
2
))
{
insert
=
false
;
}
}
else
{
if
(
rel
.
sv
==
INT_MAX
)
{
if
(
get_ith_bit
(
i
,
inputs
,
rel
.
pv
-
2
))
{
insert
=
false
;
}
}
else
if
(
get_ith_bit
(
i
,
inputs
,
rel
.
pv
-
2
)
==
get_ith_bit
(
i
,
inputs
,
rel
.
sv
-
2
))
{
insert
=
false
;
}
}
}
if
(
insert
&&
value
)
{
#ifdef DEBUG_TABLE
printf
(
"INSERTED %d at : %d %d%d%d%d
\n
"
,
value
,
i
,
get_ith_bit
(
i
,
inputs
,
3
),
get_ith_bit
(
i
,
inputs
,
2
),
get_ith_bit
(
i
,
inputs
,
1
),
get_ith_bit
(
i
,
inputs
,
0
));
#endif
tt
[
i
]
=
value
;
}
}
}
/**
* @brief helper function that is used to recursively fill the truth table of
* the target bbdd
*
* @param node bbdd root node for which the truth table should be created
* @param var_rel helper data structure that stores the relation between the
* inputs
* @param inputs number of inputs to be considered for the truth table
* @param tt truth table data structure that should be filled by this function
*/
void
recursive_dump_tt
(
bbdd_node_t
*
node
,
std
::
vector
<
variable_relation_t
>
var_rel
,
node_index_t
inputs
,
std
::
vector
<
bool
>
&
tt
)
{
std
::
vector
<
variable_relation_t
>
neq_rel
=
var_rel
;
std
::
vector
<
variable_relation_t
>
eq_rel
=
var_rel
;
if
(
IS_TERM
(
node
->
index
))
{
return
;
}
neq_rel
.
push_back
({
node
->
cvo_lvl
.
pv
,
node
->
cvo_lvl
.
sv
,
false
});
eq_rel
.
push_back
({
node
->
cvo_lvl
.
pv
,
node
->
cvo_lvl
.
sv
,
true
});
if
(
node
->
neq_child
==
1
)
{
insert_tt_value
(
neq_rel
,
inputs
,
tt
,
true
);
}
if
(
node
->
eq_child
==
1
)
{
insert_tt_value
(
eq_rel
,
inputs
,
tt
,
true
);
}
recursive_dump_tt
(
get_node_p
(
node
->
neq_child
),
neq_rel
,
inputs
,
tt
);
recursive_dump_tt
(
get_node_p
(
node
->
eq_child
),
eq_rel
,
inputs
,
tt
);
}
/**
* @brief recursive helper function that recursively writes the bbdd into a
* blif file format uses only multiplexer and xor nodes
*
* @param blif_file output filestream in which the bbdd should be written to
* @param node root node to the bbdd that should be converted
* @param signal_map signal mal between internal indices and human readable
* strings
* @param output helper variable rather the current node is a output node or
* internal node
* @return index of the current bbdd node
*/
uint32_t
write_blif_recursive
(
std
::
ofstream
&
blif_file
,
bbdd_node_t
*
node
,
std
::
vector
<
std
::
string
>
signal_map
,
bool
output
)
{
if
(
IS_TERM
(
node
->
index
)
||
MARKED
(
node
))
{
return
GET_INDEX
(
node
);
}
SET_MARKED
(
node
);
uint32_t
left_child
=
write_blif_recursive
(
blif_file
,
get_node_p
(
node
->
neq_child
),
signal_map
,
false
);
uint32_t
right_child
=
write_blif_recursive
(
blif_file
,
get_node_p
(
node
->
eq_child
),
signal_map
,
false
);
if
(
node
->
cvo_lvl
.
sv
!=
INT_MAX
)
{
blif_file
<<
".names "
<<
signal_map
[
node
->
cvo_lvl
.
pv
-
2
].
c_str
()
<<
" "
<<
signal_map
[
node
->
cvo_lvl
.
sv
-
2
].
c_str
()
<<
" "
<<
std
::
to_string
(
GET_INDEX
(
node
))
<<
"s
\n
"
;
}
else
{
blif_file
<<
".names "
<<
signal_map
[
node
->
cvo_lvl
.
pv
-
2
].
c_str
()
<<
" $true "
<<
std
::
to_string
(
GET_INDEX
(
node
))
<<
"s
\n
"
;
}
blif_file
<<
"00 1
\n
11 1
\n
"
;
blif_file
<<
".names "
<<
std
::
to_string
(
GET_INDEX
(
node
))
<<
"s "
;
if
(
IS_TERM
(
right_child
))
{
if
(
right_child
==
0
)
{
blif_file
<<
"$false "
;
}
else
{
blif_file
<<
"$true "
;
}
}
else
{
blif_file
<<
std
::
to_string
(
right_child
);
}
blif_file
<<
" "
;
if
(
IS_TERM
(
left_child
))
{
if
(
left_child
==
0
)
{
blif_file
<<
"$false "
;
}
else
{
blif_file
<<
"$true "
;
}
}
else
{
blif_file
<<
std
::
to_string
(
left_child
);
}
blif_file
<<
" "
;
if
(
!
output
)
{
blif_file
<<
std
::
to_string
(
GET_INDEX
(
node
))
<<
"
\n
"
;
}
if
(
!
output
)
{
blif_file
<<
"0-1 1
\n
11- 1
\n
"
;
}
return
GET_INDEX
(
node
);
}
/**
* @brief recursive helper function that dumps the bbdd node into a blif file
* format and only uses NEMS specific muxxor nodes
*
* @param blif_file output file in which should the design by written to
* @param node root node of the bbdd that should be dumped
* @param signal_map map between the internal indices and human readable
* string used for the design inputs
* @param output boolean that represents if the current bbdd node is an output
* or not
* @return bbdd node index of the current bbdd node only used during recursion
*/
uint32_t
write_blif_recursive_muxxor
(
std
::
ofstream
&
blif_file
,
bbdd_node_t
*
node
,
std
::
vector
<
std
::
string
>
signal_map
,
bool
output
)
{
if
(
IS_TERM
(
node
->
index
)
||
MARKED
(
node
))
{
return
GET_INDEX
(
node
);
}
SET_MARKED
(
node
);
// format a, b, in0, in1, out
// 00-1 1
// 011- 1
// 101- 1
// 11-1 1
uint32_t
left_child
=
write_blif_recursive_muxxor
(
blif_file
,
get_node_p
(
node
->
neq_child
),
signal_map
,
false
);
uint32_t
right_child
=
write_blif_recursive_muxxor
(
blif_file
,
get_node_p
(
node
->
eq_child
),
signal_map
,
false
);
// MUXXOR part
std
::
string
a
,
b
,
in0
,
in1
,
out
;
a
=
signal_map
[
node
->
cvo_lvl
.
pv
-
2
].
c_str
();
if
(
node
->
cvo_lvl
.
sv
!=
INT_MAX
)
{
b
=
signal_map
[
node
->
cvo_lvl
.
sv
-
2
].
c_str
();
}
else
{
b
=
"$true"
;
}
if
(
IS_TERM
(
right_child
))
{
in1
=
right_child
==
0
?
"$false"
:
"$true"
;
}
else
{
in1
=
std
::
to_string
(
right_child
);
}
if
(
IS_TERM
(
left_child
))
{
in0
=
left_child
==
0
?
"$false"
:
"$true"
;
}
else
{
in0
=
std
::
to_string
(
left_child
);
}
blif_file
<<
".names "
<<
a
<<
" "
<<
b
<<
" "
<<
in0
<<
" "
<<
in1
<<
" "
;
if
(
!
output
)
{
blif_file
<<
std
::
to_string
(
GET_INDEX
(
node
))
<<
"
\n
"
;
// blif_file << "0-1 1\n11- 1\n";
blif_file
<<
"00-1 1
\n
011- 1
\n
101- 1
\n
11-1 1
\n
"
;
}
return
GET_INDEX
(
node
);
}
public
:
#ifdef CACHE_STATS
struct
cache_stats_t
{
uint32_t
hits
;
uint32_t
inserts
;
uint32_t
misses
;
uint32_t
chain
;
uint32_t
current_chain
;
uint32_t
extend_hits
;
uint32_t
extend_lookups
;
uint32_t
merge_hits
;
uint32_t
merge_lookups
;
};
cache_stats_t
cache_stats
;
#endif
std
::
vector
<
output_map_t
>
output_map
;
std
::
vector
<
std
::
string
>
signal_map
;
cvo_t
*
cvo
;
uint32_t
num_inputs
;
std
::
unordered_map
<
merge_key
,
node_index_t
,
merge_hash
>
computed_table
;
std
::
unordered_map
<
extend_key
,
bbdd_node_ppair_t
,
extend_hash
>
extend_table
;
Unique_table
()
{}
/**
* @brief return bbdd node based on given index
*
* @param index for which the bbdd node should be retrieved
* @return bbdd node at index
*/
bbdd_node_t
get_node
(
node_index_t
index
)
{
return
entries
[
index
].
node
;
}
/**
* @brief return pointer to node at given index
*
* @param index for which the pointer to the bbdd node should be retrieved
* @return pointer to bbdd node at index
*/
bbdd_node_t
*
get_node_p
(
node_index_t
index
)
{
return
&
entries
[
index
].
node
;
}
/**
* @brief initialize cvo based on input list, cvo initial ordering strategy
* and optional ordering that should be used
*
* @param inputs list of inputs that should are going to be used in design
* @param cvo_opt chain variable ordering initial ordering strategy. Currently
* strategies available: cvo_none, cvo_even, cvo_even_reversed, cvo_random,
* cvo_input
* @param input_cvo list of initial ordering only considered when cvo_opt is
* cvo_input
*/
void
init_cvo
(
std
::
vector
<
uint64_t
>
inputs
,
cvo_init_t
cvo_opt
,
std
::
vector
<
node_index_t
>
input_cvo
=
std
::
vector
<
node_index_t
>
())
{
cvo
=
reinterpret_cast
<
cvo_t
*>
(
malloc
(
sizeof
(
cvo_t
)));
num_inputs
=
inputs
.
size
();
init_ordering
(
inputs
,
cvo
,
cvo_opt
,
input_cvo
);
}
/**
* @brief initial signal map with a list of input name strings. Only required
* if output should be written to blif file
*
* @param input_names list of input name strings
*/
void
init_signal_map
(
std
::
vector
<
std
::
string
>
input_names
)
{
for
(
std
::
string
input
:
input_names
)
{
this
->
signal_map
.
emplace_back
(
input
);
}
}
/**
* @brief Clear cache that is used during merge operations
*/
void
clear_computed_table
()
{
computed_table
.
clear
();
}
/**
* @brief Clear cache that is used during extend operations
*/
void
clear_extend_table
()
{
extend_table
.
clear
();
}
/**
* @brief Get next free position in the hash table
*
* @return index of next free position
*/
uint32_t
get_free_pos
()
{
return
free_pos
;
}
/**
* @brief initialise has table that stores the node information
*
* @param init_node_count capacity of the hash table
* @param module_name name of the module that is represented by the bbdds,
* only required for writing the design into blif file format
* @return status code depending if the operations was succesful
*/
int8_t
init_table
(
uint64_t
init_node_count
,
std
::
string
module_name
)
{
if
(
init_node_count
>
pow
(
2
,
31
))
{
std
::
cerr
<<
"[ERROR] init table: node count is too large
\n
"
;
return
-1
;
}
this
->
module_name
=
module_name
;
entries
=
reinterpret_cast
<
table_entry_t
*>
(
malloc
(
sizeof
(
table_entry_t
)
*
init_node_count
));
if
(
entries
==
NULL
)
{
std
::
cerr
<<
"[ERROR] init failed, because out of memeory
\n
"
;
return
OUT_OF_MEMORY
;
}
capacity
=
init_node_count
;
for
(
node_index_t
i
=
0
;
i
<
init_node_count
;
i
++
)
{
// init with zero
LEVEL
(
i
).
pv
=
0
;
LEVEL
(
i
).
sv
=
0
;
EQ
(
i
)
=
0
;
NEQ
(
i
)
=
0
;
NEXT
(
i
)
=
0
;
REF
(
i
)
=
0
;
INDEX
(
i
)
=
0
;
}
LEVEL
(
0
).
pv
=
INT_MAX
;
LEVEL
(
0
).
sv
=
INT_MAX
;
INDEX
(
0
)
=
0
;
// Constant 1
LEVEL
(
1
).
pv
=
INT_MAX
;
LEVEL
(
1
).
sv
=
INT_MAX
;
INDEX
(
1
)
=
1
;
REF
(
1
)
=
1
;
// first empty space after constants
free_pos
=
2
;
#ifdef CACHE_STATS
cache_stats
.
hits
=
0
;
cache_stats
.
inserts
=
0
;
cache_stats
.
misses
=
0
;
cache_stats
.
chain
=
0
;
cache_stats
.
current_chain
=
0
;
cache_stats
.
extend_lookups
=
0
;
cache_stats
.
extend_hits
=
0
;
cache_stats
.
merge_lookups
=
0
;
cache_stats
.
merge_hits
=
0
;
#endif
return
SUCCESS
;
}
/**
* @brief free hash table
*/
void
free_table
()
{
free
(
entries
);
}
/**
* @brief insert bbdd node into the hash table
*
* @param node_t bbdd node template that should be inserted
* @return pointer to bbdd node in the hash table
*/
bbdd_node_t
*
insert_node
(
bbdd_node_template_t
node_t
)
{
#ifdef CACHE_STATS
cache_stats
.
inserts
++
;
#endif
assert
(
node_t
.
cvo_lvl
.
sv
==
INT_MAX
||
POS
(
node_t
.
cvo_lvl
.
pv
,
cvo
)
<
POS
(
node_t
.
cvo_lvl
.
sv
,
cvo
));
node_index_t
hash
=
hash_node
(
node_t
,
capacity
);
#ifdef DEBUG_TABLE
printf
(
"[INFO] INSERT: trying (%d, %d) %d %d hash: %d
\n
"
,
node_t
.
cvo_lvl
.
pv
,
node_t
.
cvo_lvl
.
sv
,
node_t
.
neq_child
,
node_t
.
eq_child
,
hash
);
#endif
if
(
free_pos
>=
capacity
&&
free_slots
.
empty
())
{
// resize not implemented yet
std
::
cerr
<<
"[ERROR] Unique Table is full resize not implemented yet"
;
int
count
=
0
;
for
(
int
i
=
0
;
i
<
capacity
;
i
++
)
{
if
(
entries
[
i
].
ref
==
0
)
{
count
++
;
}
}
assert
(
false
);
return
0
;
}
table_entry_t
*
entry
=
&
entries
[
hash
];
node_index_t
chain_i
=
-1
;
if
(
entry
->
ref
!=
0
)
{
// there is already a node with this hash
chain_i
=
entry
->
ref
;
#ifdef CACHE_STATS
cache_stats
.
current_chain
=
0
;
#endif
while
(
true
)
{
// see if that is the node we currently want to insert
if
(
node_eq
(
entries
[
chain_i
].
node
,
node_t
))
{
#ifdef DEBUG_TABLE
std
::
cout
<<
"[INFO] INSERT: node hit "
;
dump_node
(
&
entries
[
chain_i
].
node
);
std
::
cout
<<
"
\n
"
;
#endif
#ifdef CACHE_STATS
cache_stats
.
hits
++
;
#endif
return
&
entries
[
chain_i
].
node
;
}
// if there is no more node in the chain break and insert at that
// position
if
(
NEXT
(
chain_i
)
==
0
)
{
#ifdef CACHE_STATS
if
(
cache_stats
.
current_chain
>
cache_stats
.
chain
)
{
cache_stats
.
chain
=
cache_stats
.
current_chain
;
}
#endif
break
;
}
chain_i
=
NEXT
(
chain_i
);
#ifdef CACHE_STATS
cache_stats
.
current_chain
++
;
#endif
}
}
node_index_t
insert_pos
;
if
(
free_slots
.
empty
())
{
insert_pos
=
free_pos
;
free_pos
++
;
}
else
{
insert_pos
=
free_slots
.
back
();
free_slots
.
pop_back
();
}
// insert node
bbdd_node_t
node
=
{
0
,
insert_pos
,
node_t
.
cvo_lvl
,
node_t
.
neq_child
,
node_t
.
eq_child
};
get_node_p
(
node_t
.
eq_child
)
->
ref
++
;
get_node_p
(
node_t
.
neq_child
)
->
ref
++
;
NODE
(
insert_pos
)
=
node
;
// extend chain
if
(
chain_i
!=
-1
)
{
#ifdef DEBUG_TABLE
std
::
cout
<<
"[INFO] INSERT: extending chain at "
<<
chain_i
<<
" "
;
dump_node
(
&
NODE
(
insert_pos
));
std
::
cout
<<
"
\n
"
;
#endif
entries
[
chain_i
].
next
=
insert_pos
;
}
else
{
entry
->
ref
=
insert_pos
;
#ifdef DEBUG_TABLE
printf
(
"[INFO] INSERT: no chain "
);
dump_node
(
&
NODE
(
insert_pos
));
std
::
cout
<<
"
\n
"
;
#endif
}
#ifdef CACHE_STATS
cache_stats
.
misses
++
;
#endif
return
&
NODE
(
insert_pos
);
}
/**
* @brief delte bbdd node from the hash table
*
* @param node pointer to bbdd node that should be deleted from the hash table
*/
void
delete_node
(
bbdd_node_t
*
node
)
{
node_index_t
hash
=
hash_node
(
*
node
,
capacity
);
// assert(entries[hash].ref != 0);
node_index_t
ref
=
entries
[
hash
].
ref
;
if
(
ref
==
node
->
index
)
{
// not part of a chain
#ifdef DEBUG_TABLE
printf
(
"[INFO] DELETE: no chain replacing %d with %d
\n
"
,
node
->
index
,
entries
[
ref
].
next
);
#endif
entries
[
hash
].
ref
=
entries
[
ref
].
next
;
free_slots
.
emplace_back
(
node
->
index
);
}
else
{
// part of a chain get first element
table_entry_t
*
chain_entry
=
&
entries
[
entries
[
hash
].
ref
];
for
(
int
i
=
0
;
i
<
capacity
;
i
++
)
{
if
(
node_eq
(
entries
[
chain_entry
->
next
].
node
,
*
node
))
{
// remove node from chain
#ifdef DEBUG_TABLE
printf
(
"[INFO] DELETE: chain replacing at %d with %d
\n
"
,
chain_entry
->
node
.
index
,
entries
[
node
->
index
].
next
);
#endif
chain_entry
->
next
=
entries
[
node
->
index
].
next
;
entries
[
node
->
index
].
next
=
0
;
entries
[
node
->
index
].
node
=
{
0
,
0
,
{
0
,
0
},
0
,
0
};
free_slots
.
emplace_back
(
node
->
index
);
return
;
}
chain_entry
=
&
entries
[
chain_entry
->
next
];
}
dump_table
();
std
::
cout
<<
"[ERROR] Node Node found: "
<<
node
->
index
<<
"
\n
"
;
dump_node
(
node
);
std
::
cout
<<
" with hash "
<<
hash
<<
"
\n
"
;
fflush
(
stdout
);
assert
(
false
&&
"node not found"
);
}
}
/**
* @brief add output map from bbdd node pointer to a string, used for
* displaying and blif file purposes
*
* @param output string to human readable output
* @param bbdd root bbdd node that represents output function
*/
void
add_output
(
std
::
string
output
,
bbdd_node_t
*
bbdd
)
{
output_map_t
map
=
{
output
,
bbdd
};
bbdd
->
ref
++
;
output_map
.
emplace_back
(
map
);
}
/**
* @brief recursively clears marks from bbdd
*
* @param bbdd root bbdd node for which all marks should be cleared
*/
void
clear_marks
(
bbdd_node_t
*
bbdd
)
{
if
(
IS_TERM
(
bbdd
->
index
))
{
return
;
}
CLEAR_MARKED
(
bbdd
);
clear_marks
(
get_node_p
(
bbdd
->
neq_child
));
clear_marks
(
get_node_p
(
bbdd
->
eq_child
));
}
/**
* @brief dump hash table entries, only entries with data are printed
*/
void
dump_table
()
{
for
(
uint64_t
i
=
0
;
i
<
free_pos
;
i
++
)
{
printf
(
"Hash: %6d Ref: %3d Next: %4d Node: "
,
hash_node
(
entries
[
i
].
node
,
capacity
),
entries
[
i
].
ref
,
entries
[
i
].
next
);
dump_node
(
&
entries
[
i
].
node
);
std
::
cout
<<
"
\n
"
;
}
for
(
uint64_t
i
=
free_pos
;
i
<
capacity
;
i
++
)
{
if
(
entries
[
i
].
ref
!=
0
)
{
printf
(
"i: %3lu Ref: %2d Next: %4d Node:
\n
"
,
i
,
entries
[
i
].
ref
,
entries
[
i
].
next
);
}
}
}
/**
* @brief dump the truth table of given bbdd
*
* @param output pointer to the root of a bbdd for which the truth table
* should be printed
* @return string of the output tt
*/
std
::
string
dump_tt
(
bbdd_node_t
*
output
)
{
std
::
vector
<
bool
>
tt
(
std
::
pow
(
2
,
this
->
num_inputs
),
false
);
std
::
vector
<
variable_relation_t
>
var_rel
;
recursive_dump_tt
(
output
,
var_rel
,
this
->
num_inputs
,
tt
);
for
(
int
i
=
0
;
i
<
tt
.
size
();
i
++
)
{
for
(
int
j
=
0
;
j
<
this
->
num_inputs
;
j
++
)
{
printf
(
"%d"
,
get_ith_bit
(
i
,
this
->
num_inputs
,
j
));
}
printf
(
" | %s
\n
"
,
tt
[
i
]
?
"1"
:
"0"
);
}
std
::
string
out_string
=
""
;
for
(
int
i
=
0
;
i
<
tt
.
size
();
i
++
)
{
out_string
+=
tt
[
i
]
?
"1"
:
"0"
;
}
return
out_string
;
}
/**
* @brief dump truth table for output string name
*
* @param output name of the output in the output map
* @return string of the tt, empty if output name does not exist in output map
*/
std
::
string
dump_tt
(
std
::
string
output
)
{
std
::
printf
(
"Truth table of output %s
\n
"
,
output
.
c_str
());
for
(
output_map_t
out_map
:
this
->
output_map
)
{
if
(
out_map
.
output
==
output
)
{
return
dump_tt
(
out_map
.
bbdd
);
}
}
return
""
;
}
/**
* @brief dump bbdd of given output into a dot file format
*
* @param filename name of the file in which the output will be dumped
* @param output name of the output which should be dumped, dot file only
* consists of terminal node if output name is not in the output map
*/
void
dump_dot
(
std
::
string
filename
,
std
::
string
output
)
{
std
::
ofstream
dot_file
(
filename
);
dot_file
<<
"graph bbdd {
\n
"
;
// terminal nodes
dot_file
<<
"
\t
0 [shape=square]
\n
"
;
dot_file
<<
"
\t
1 [shape=square]"
;
bbdd_node_t
*
root_node
;
for
(
output_map_t
map
:
output_map
)
{
if
(
map
.
output
==
output
)
{
root_node
=
map
.
bbdd
;
break
;
}
}
node_index_t
root
=
recursive_dump_dot
(
dot_file
,
root_node
);
clear_marks
(
root_node
);
dot_file
<<
"
\n\t
"
<<
free_pos
+
1
<<
" [shape=plaintext, label=
\"
"
<<
output
<<
"
\"
]
\n
"
;
dot_file
<<
"
\t
"
<<
free_pos
+
1
<<
" -- "
<<
root_node
->
index
<<
"
\n
"
;
dot_file
<<
"}
\n
"
;
}
/**
* @brief dump all bbdd nodes that have a defined output of the module into a
* dot file format
*
* @param filename name in which the design should be printed to
*/
void
dump_dot
(
std
::
string
filename
)
{
std
::
ofstream
dot_file
(
filename
);
dot_file
<<
"graph bbdd {
\n
"
;
// terminal nodes
dot_file
<<
"
\t
0 [shape=square]
\n
"
;
dot_file
<<
"
\t
1 [shape=square]
\n
"
;
// insert nodes
for
(
uint64_t
i
=
2
;
i
<
free_pos
;
i
++
)
{
table_entry_t
entry
=
entries
[
i
];
if
(
entry
.
node
.
cvo_lvl
.
sv
!=
INT_MAX
)
{
dot_file
<<
"
\n
"
<<
i
<<
" [label=
\"
"
<<
entry
.
node
.
ref
<<
"
\n
"
<<
i
<<
": "
<<
entry
.
node
.
cvo_lvl
.
pv
<<
","
<<
entry
.
node
.
cvo_lvl
.
sv
<<
"
\"
]"
;
}
else
{
dot_file
<<
"
\n
"
<<
i
<<
" [label=
\"
"
<<
entry
.
node
.
ref
<<
"
\n
"
<<
i
<<
": "
<<
entry
.
node
.
cvo_lvl
.
pv
<<
",1"
<<
"
\"
]"
;
}
dot_file
<<
"
\t
"
<<
i
<<
" -- "
<<
entry
.
node
.
neq_child
<<
"[label=<<FONT POINT-SIZE=
\"
14
\"
>≠</FONT>>, "
"style=
\"
dashed
\"
]
\n
"
;
dot_file
<<
"
\t
"
<<
i
<<
" -- "
<<
entry
.
node
.
eq_child
<<
"[label=
\"
=
\"
]
\n
"
;
}
for
(
output_map_t
map
:
output_map
)
{
dot_file
<<
"
\n
"
<<
map
.
output
<<
" [shape=plaintext, label=
\"
"
<<
map
.
output
<<
"
\"
]"
;
dot_file
<<
"
\t
"
<<
map
.
output
<<
" -- "
<<
map
.
bbdd
->
index
<<
"
\n
"
;
}
dot_file
<<
"}
\n
"
;
}
/**
* @brief same as previous dump_dot function but it uses a signal map that
* maps primary and secondary variables to human readable strings
*
* @param filename in which the design should be written to
* @param signal_map maps indices of primary and secondary variables to human
* readable strings
*/
void
dump_dot
(
std
::
string
filename
,
std
::
vector
<
std
::
string
>
signal_map
)
{
std
::
ofstream
dot_file
(
filename
);
dot_file
<<
"graph bbdd {
\n
"
;
// terminal nodes
dot_file
<<
"
\t
0 [shape=square]"
;
dot_file
<<
"
\t
1 [shape=square]"
;
// insert nodes
for
(
uint64_t
i
=
2
;
i
<
free_pos
;
i
++
)
{
table_entry_t
entry
=
entries
[
i
];
if
(
entry
.
node
.
ref
==
0
)
{
continue
;
}
if
(
entry
.
node
.
cvo_lvl
.
sv
!=
INT_MAX
)
{
dot_file
<<
"
\n
"
<<
i
<<
" [label=
\"
"
<<
entry
.
node
.
ref
<<
"
\n
"
<<
i
<<
": "
<<
signal_map
[
entry
.
node
.
cvo_lvl
.
pv
-
2
]
<<
","
<<
signal_map
[
entry
.
node
.
cvo_lvl
.
sv
-
2
]
<<
"
\"
]"
;
}
else
{
dot_file
<<
"
\n
"
<<
i
<<
" [label=
\"
"
<<
entry
.
node
.
ref
<<
"
\n
"
<<
i
<<
": "
<<
signal_map
[
entry
.
node
.
cvo_lvl
.
pv
-
2
]
<<
",1"
<<
"
\"
]"
;
}
dot_file
<<
"
\t
"
<<
i
<<
" -- "
<<
entry
.
node
.
neq_child
<<
"[label=<<FONT POINT-SIZE=
\"
14
\"
>≠</FONT>>, "
"style=
\"
dashed
\"
]
\n
"
;
dot_file
<<
"
\t
"
<<
i
<<
" -- "
<<
entry
.
node
.
eq_child
<<
"[label=
\"
=
\"
]
\n
"
;
}
for
(
output_map_t
map
:
output_map
)
{
dot_file
<<
"
\n
"
<<
map
.
output
<<
" [shape=plaintext, label=
\"
"
<<
map
.
output
<<
"
\"
]"
;
dot_file
<<
"
\t
"
<<
map
.
output
<<
" -- "
<<
map
.
bbdd
->
index
<<
"
\n
"
;
}
dot_file
<<
"}
\n
"
;
}
/**
* @brief dump the current module into blif file format
*
* @param filename name of the file in which the diagrams should be dumped
* into, only outputs are considered that are present in the output map
*/
void
write_blif
(
std
::
string
filename
)
{
std
::
ofstream
blif_file
(
filename
);
blif_file
<<
".model "
+
this
->
module_name
+
"
\n
"
;
blif_file
<<
".inputs"
;
for
(
int
i
=
0
;
i
<
this
->
signal_map
.
size
();
i
++
)
{
blif_file
<<
" "
<<
this
->
signal_map
[
i
];
}
blif_file
<<
"
\n
.outputs"
;
for
(
output_map_t
output
:
this
->
output_map
)
{
blif_file
<<
" "
<<
output
.
output
;
}
blif_file
<<
"
\n
.names $true
\n
1
\n
"
;
blif_file
<<
".names $false
\n
"
;
for
(
output_map_t
map
:
this
->
output_map
)
{
if
(
IS_TERM
(
map
.
bbdd
->
index
))
{
if
(
map
.
bbdd
->
index
==
0
)
{
blif_file
<<
".names "
<<
map
.
output
<<
"
\n
"
;
}
else
{
blif_file
<<
".names "
<<
map
.
output
<<
"
\n
1
\n
"
;
}
}
else
if
(
MARKED
(
map
.
bbdd
))
{
blif_file
<<
".names "
<<
(
GET_INDEX
(
map
.
bbdd
))
<<
" "
<<
map
.
output
<<
"
\n
1 1
\n
"
;
}
else
{
// write_blif_recursive(blif_file, map.bbdd, cover.signal_map, true);
// blif_file << map.output << "\n0-1 1\n11- 1\n";
write_blif_recursive_muxxor
(
blif_file
,
map
.
bbdd
,
signal_map
,
true
);
blif_file
<<
map
.
output
<<
"
\n
00-1 1
\n
011- 1
\n
101- 1
\n
11-1 1
\n
"
;
}
}
blif_file
<<
".end
\n
"
;
}
#ifdef CACHE_STATS
void
print_cache_stats
()
{
printf
(
"[INFO] CACHE STATS: inserts: %d, hits: %d, misses %d, max chain: %d
\n
"
,
cache_stats
.
inserts
,
cache_stats
.
hits
,
cache_stats
.
misses
,
cache_stats
.
chain
);
}
void
dump_cache_stats
(
std
::
string
path
)
{
std
::
ofstream
csv_file
(
path
);
csv_file
<<
"inserts;hits;misses;max_chain;extend_lookups;extend_hits;"
"merge_lookups;merge_hits
\n
"
;
csv_file
<<
std
::
to_string
(
cache_stats
.
inserts
)
<<
";"
<<
std
::
to_string
(
cache_stats
.
hits
)
<<
";"
<<
std
::
to_string
(
cache_stats
.
misses
)
<<
";"
<<
std
::
to_string
(
cache_stats
.
chain
)
<<
";"
<<
std
::
to_string
(
cache_stats
.
extend_lookups
)
<<
";"
<<
std
::
to_string
(
cache_stats
.
extend_hits
)
<<
";"
<<
std
::
to_string
(
cache_stats
.
merge_lookups
)
<<
";"
<<
std
::
to_string
(
cache_stats
.
merge_hits
)
<<
"
\n
"
;
csv_file
.
close
();
}
#endif
/**
* @brief get maximum tree height of a bbdd
*
* @param root root node of bbdd node for which the height should be
* calculated
* @param height intermediate values used for the recursion
* @return maximum height of the current bbdd node to any terminal node
*/
uint32_t
get_tree_height
(
bbdd_node_t
*
root
,
uint32_t
height
)
{
if
(
IS_TERM
(
root
->
index
))
{
return
0
;
}
bbdd_node_t
*
neq
=
get_node_p
(
root
->
neq_child
);
bbdd_node_t
*
eq
=
get_node_p
(
root
->
eq_child
);
return
std
::
max
(
get_tree_height
(
neq
,
height
)
+
1
,
get_tree_height
(
eq
,
height
)
+
1
);
}
/**
* @brief gets maximum tree height of a bbdd
*
* @param node root node of bbdd node for which the height should be
* calculated
* @return maximum height of the current bbdd node to any terminal node
*/
uint32_t
get_tree_height
(
bbdd_node_t
*
node
)
{
return
get_tree_height
(
node
,
0
);
}
/**
* @brief return the maximum tree height of all bbdds registered in the output
* map
*
* @return maximum tree height of all bbdds in the design
*/
uint32_t
get_max_height
()
{
uint32_t
max_height
=
-1
;
uint32_t
current_height
;
for
(
output_map_t
out_map
:
output_map
)
{
current_height
=
get_tree_height
(
out_map
.
bbdd
);
if
(
current_height
>
max_height
)
{
max_height
=
current_height
;
}
}
return
max_height
;
}
/**
* @brief return the sum of all maximum tree heights of all bbdd nodes that
* have registered an output in the output map
*
* @return sum of all maximum tree heights
*/
uint32_t
get_total_height
()
{
uint32_t
sum
=
0
;
for
(
output_map_t
out_map
:
output_map
)
{
sum
+=
get_tree_height
(
out_map
.
bbdd
);
}
return
sum
;
}
/**
* @brief reorders a bbdd based on two variables that are swapped
*
* @param node root node to the bbdd which should be reordered
* @param b first variable
* @param c second variable
* @return newly created bbdd based on the swapped varaibles inserted into the
* hash table
*/
bbdd_node_t
*
reorder_bbdd
(
bbdd_node_t
*
node
,
node_index_t
b
,
node_index_t
c
)
{
#ifdef DEBUG_REORDER
printf
(
"reorder: "
);
dump_node
(
node
);
printf
(
"
\n
"
);
#endif
if
(
IS_TERM
(
node
->
index
))
{
return
node
;
}
bbdd_node_t
*
neq_child
=
get_node_p
(
node
->
neq_child
);
bbdd_node_t
*
eq_child
=
get_node_p
(
node
->
eq_child
);
bbdd_node_t
*
new_neq
,
*
new_eq
,
*
new_neq_neq
,
*
new_neq_eq
,
*
new_eq_neq
,
*
new_eq_eq
;
bbdd_node_t
*
neq_neq_child
,
*
neq_eq_child
,
*
eq_neq_child
,
*
eq_eq_child
;
node_index_t
nnn
,
nne
,
nen
,
nee
,
enn
,
ene
,
een
,
eee
;
uint32_t
nn_sv
,
ne_sv
,
en_sv
,
ee_sv
;
// b no SV
if
(
node
->
cvo_lvl
.
pv
==
b
)
{
// c not present in this bbdd
if
(
node
->
cvo_lvl
.
sv
!=
c
)
{
return
node
;
}
// NEQ-Child
if
(
neq_child
->
cvo_lvl
.
pv
!=
c
)
{
new_neq
=
neq_child
;
}
else
{
new_neq
=
insert_node
({{
b
,
neq_child
->
cvo_lvl
.
sv
},
neq_child
->
eq_child
,
neq_child
->
neq_child
});
}
// EQ-Child
if
(
eq_child
->
cvo_lvl
.
pv
!=
c
)
{
new_eq
=
eq_child
;
}
else
{
new_eq
=
insert_node
({{
b
,
eq_child
->
cvo_lvl
.
sv
},
eq_child
->
neq_child
,
eq_child
->
eq_child
});
}
assert
(
new_neq
->
cvo_lvl
.
sv
==
INT_MAX
||
POS
(
new_neq
->
cvo_lvl
.
pv
,
cvo
)
<
POS
(
new_neq
->
cvo_lvl
.
sv
,
cvo
));
assert
(
new_eq
->
cvo_lvl
.
sv
==
INT_MAX
||
POS
(
new_eq
->
cvo_lvl
.
pv
,
cvo
)
<
POS
(
new_eq
->
cvo_lvl
.
sv
,
cvo
));
assert
(
POS
(
c
,
cvo
)
<
POS
(
b
,
cvo
));
return
insert_node
({{
c
,
b
},
new_neq
->
index
,
new_eq
->
index
});
}
// b SV
if
(
node
->
cvo_lvl
.
sv
==
b
)
{
// NEQ-Child
if
(
neq_child
->
cvo_lvl
.
pv
==
b
)
{
if
(
neq_child
->
cvo_lvl
.
sv
!=
c
)
{
nnn
=
nee
=
neq_child
->
eq_child
;
nne
=
nen
=
neq_child
->
neq_child
;
nn_sv
=
ne_sv
=
neq_child
->
cvo_lvl
.
sv
;
}
else
{
// c SV in neq_child
neq_neq_child
=
get_node_p
(
neq_child
->
neq_child
);
neq_eq_child
=
get_node_p
(
neq_child
->
eq_child
);
// full neq neq
if
(
neq_neq_child
->
cvo_lvl
.
pv
==
c
)
{
nnn
=
neq_neq_child
->
neq_child
;
nne
=
neq_neq_child
->
eq_child
;
nn_sv
=
neq_neq_child
->
cvo_lvl
.
sv
;
// c no neq neq PV
}
else
{
nnn
=
nne
=
neq_neq_child
->
index
;
nn_sv
=
neq_neq_child
->
cvo_lvl
.
pv
;
}
// full neq eq
if
(
neq_eq_child
->
cvo_lvl
.
pv
==
c
)
{
nen
=
neq_eq_child
->
neq_child
;
nee
=
neq_eq_child
->
eq_child
;
ne_sv
=
neq_eq_child
->
cvo_lvl
.
sv
;
// c no neq eq PV
}
else
{
nen
=
nee
=
neq_eq_child
->
index
;
ne_sv
=
neq_eq_child
->
cvo_lvl
.
pv
;
}
}
}
else
{
// b no PV in neq_child
if
(
neq_child
->
cvo_lvl
.
pv
==
c
)
{
// c PV in neq_child
nnn
=
nen
=
neq_child
->
neq_child
;
nne
=
nee
=
neq_child
->
eq_child
;
nn_sv
=
ne_sv
=
neq_child
->
cvo_lvl
.
sv
;
}
else
{
nnn
=
nne
=
nen
=
nee
=
neq_child
->
index
;
nn_sv
=
ne_sv
=
neq_child
->
cvo_lvl
.
pv
;
}
}
// EQ-Child
if
(
eq_child
->
cvo_lvl
.
pv
==
b
)
{
if
(
eq_child
->
cvo_lvl
.
sv
!=
c
)
{
ene
=
een
=
eq_child
->
neq_child
;
enn
=
eee
=
eq_child
->
eq_child
;
en_sv
=
ee_sv
=
eq_child
->
cvo_lvl
.
sv
;
}
else
{
// c is sv in eq_child
eq_neq_child
=
get_node_p
(
eq_child
->
neq_child
);
eq_eq_child
=
get_node_p
(
eq_child
->
eq_child
);
if
(
eq_neq_child
->
cvo_lvl
.
pv
==
c
)
{
enn
=
eq_neq_child
->
neq_child
;
ene
=
eq_neq_child
->
eq_child
;
en_sv
=
eq_neq_child
->
cvo_lvl
.
sv
;
}
else
{
enn
=
ene
=
eq_neq_child
->
index
;
en_sv
=
eq_neq_child
->
cvo_lvl
.
pv
;
}
if
(
eq_eq_child
->
cvo_lvl
.
pv
==
c
)
{
een
=
eq_eq_child
->
neq_child
;
eee
=
eq_eq_child
->
eq_child
;
ee_sv
=
eq_eq_child
->
cvo_lvl
.
sv
;
}
else
{
een
=
eee
=
eq_eq_child
->
index
;
ee_sv
=
eq_eq_child
->
cvo_lvl
.
pv
;
}
}
}
else
{
// b is not pv in eq_child
if
(
eq_child
->
cvo_lvl
.
pv
==
c
)
{
enn
=
een
=
eq_child
->
neq_child
;
ene
=
eee
=
eq_child
->
eq_child
;
en_sv
=
ee_sv
=
eq_child
->
cvo_lvl
.
sv
;
}
else
{
enn
=
ene
=
een
=
eee
=
eq_child
->
index
;
en_sv
=
ee_sv
=
eq_child
->
cvo_lvl
.
pv
;
}
}
// create new bbdd
// new neq
assert
(
en_sv
==
INT_MAX
||
ene
==
enn
||
POS
(
b
,
cvo
)
<
POS
(
en_sv
,
cvo
));
assert
(
ne_sv
==
INT_MAX
||
nen
==
nee
||
POS
(
b
,
cvo
)
<
POS
(
ne_sv
,
cvo
));
assert
(
POS
(
c
,
cvo
)
<
POS
(
b
,
cvo
));
new_neq_neq
=
insert_node
({{
b
,
en_sv
},
ene
,
enn
});
new_neq_eq
=
insert_node
({{
b
,
ne_sv
},
nen
,
nee
});
new_neq
=
insert_node
({{
c
,
b
},
new_neq_neq
->
index
,
new_neq_eq
->
index
});
// new eq
assert
(
nn_sv
==
INT_MAX
||
nne
==
nnn
||
POS
(
b
,
cvo
)
<
POS
(
nn_sv
,
cvo
));
assert
(
ee_sv
==
INT_MAX
||
een
==
eee
||
POS
(
b
,
cvo
)
<
POS
(
ee_sv
,
cvo
));
assert
(
POS
(
c
,
cvo
)
<
POS
(
b
,
cvo
));
new_eq_neq
=
insert_node
({{
b
,
nn_sv
},
nne
,
nnn
});
new_eq_eq
=
insert_node
({{
b
,
ee_sv
},
een
,
eee
});
new_eq
=
insert_node
({{
c
,
b
},
new_eq_neq
->
index
,
new_eq_eq
->
index
});
// new root
assert
(
POS
(
node
->
cvo_lvl
.
pv
,
cvo
)
<
POS
(
c
,
cvo
));
return
insert_node
(
{{
node
->
cvo_lvl
.
pv
,
c
},
new_neq
->
index
,
new_eq
->
index
});
}
new_neq
=
reorder_bbdd
(
get_node_p
(
node
->
neq_child
),
b
,
c
);
new_eq
=
reorder_bbdd
(
get_node_p
(
node
->
eq_child
),
b
,
c
);
if
(
!
(
node
->
cvo_lvl
.
sv
==
INT_MAX
||
POS
(
node
->
cvo_lvl
.
pv
,
cvo
)
<
POS
(
node
->
cvo_lvl
.
sv
,
cvo
)))
{
dump_node
(
node
);
std
::
cout
<<
"
\n
"
;
}
assert
(
node
->
cvo_lvl
.
sv
==
INT_MAX
||
POS
(
node
->
cvo_lvl
.
pv
,
cvo
)
<
POS
(
node
->
cvo_lvl
.
sv
,
cvo
));
return
insert_node
({{
node
->
cvo_lvl
},
new_neq
->
index
,
new_eq
->
index
});
}
/**
* @brief return the total number of nodes in a bbdd
*
* @return total number od nodes in a bbdd
*/
uint32_t
get_total_number_nodes
()
{
uint32_t
count
=
0
;
for
(
output_map_t
out_map
:
output_map
)
{
count
+=
get_number_nodes_recursive
(
out_map
.
bbdd
);
}
for
(
output_map_t
out_map
:
output_map
)
{
clear_marks
(
out_map
.
bbdd
);
}
return
count
;
}
/**
* @brief dump information stored in the output map: name of the output and
* the index of the bbdd node that is the root noddump information stored in
* the output map: name of the output and the index of the bbdd node that is
* the root node for that output
*/
void
dump_outputs
()
{
for
(
output_map_t
out_map
:
output_map
)
{
printf
(
"Output: %s: "
,
out_map
.
output
.
c_str
());
dump_node
(
out_map
.
bbdd
);
printf
(
"
\n
"
);
}
}
/**
* @brief swap two inputs in the variable ordering and reorder bbdd based on the new ordering
*
* @param root root bbdd node that should be reordered after variable swap
* @param b first variable
* @param c second variable
* @return newly created bbdd node based on new variable order
*/
bbdd_node_t
*
swap_positions
(
bbdd_node_t
*
root
,
node_index_t
b
,
node_index_t
c
)
{
// assert(POS(b, cvo) + 1 == POS(c, cvo));
assert
(
b
+
1
==
c
);
node_index_t
temp
=
(
*
cvo
)[
b
].
in
;
(
*
cvo
)[
b
].
in
=
(
*
cvo
)[
c
].
in
;
(
*
cvo
)[
c
].
in
=
temp
;
(
*
cvo
)[(
*
cvo
)[
b
].
in
%
num_inputs
].
pos
=
b
;
(
*
cvo
)[(
*
cvo
)[
c
].
in
%
num_inputs
].
pos
=
c
;
return
reorder_bbdd
(
root
,
VAR
(
c
,
cvo
),
VAR
(
b
,
cvo
));
}
/**
* @brief reduce size of the bbdd node based on reduction rules
*
* @param f root node to bbdd that should be reduced
* @return pointer to reduced bbdd
*/
bbdd_node_t
*
reduce_bbdd
(
bbdd_node_t
*
f
)
{
if
(
IS_TERM
(
f
->
index
))
{
return
f
;
}
bbdd_node_t
*
child_neq
=
get_node_p
(
f
->
neq_child
),
*
child_eq
=
get_node_p
(
f
->
eq_child
);
bbdd_node_t
*
new_neq
,
*
new_eq
,
new_root
;
new_neq
=
reduce_bbdd
(
child_neq
);
new_eq
=
reduce_bbdd
(
child_eq
);
if
(
new_neq
->
index
==
new_eq
->
index
)
{
#ifdef DEBUG_BBDD
printf
(
"[INFO] REDUCE: node %d
\n
"
,
f
->
index
);
#endif
return
new_neq
;
}
if
(
!
(
IS_TERM
(
new_neq
->
index
))
&&
!
(
IS_TERM
(
new_eq
->
index
))
&&
new_neq
->
cvo_lvl
.
pv
==
new_eq
->
cvo_lvl
.
pv
&&
new_neq
->
cvo_lvl
.
sv
==
new_eq
->
cvo_lvl
.
sv
&&
f
->
cvo_lvl
.
sv
==
new_neq
->
cvo_lvl
.
pv
&&
new_neq
->
neq_child
==
new_eq
->
eq_child
&&
new_neq
->
eq_child
==
new_eq
->
neq_child
)
{
return
insert_node
({{
f
->
cvo_lvl
.
pv
,
new_neq
->
cvo_lvl
.
sv
},
new_neq
->
eq_child
,
new_neq
->
neq_child
});
}
assert
(
f
->
cvo_lvl
.
sv
==
INT_MAX
||
POS
(
f
->
cvo_lvl
.
pv
,
cvo
)
<
POS
(
f
->
cvo_lvl
.
sv
,
cvo
));
return
insert_node
({
f
->
cvo_lvl
,
new_neq
->
index
,
new_eq
->
index
});
}
/**
* @brief swap two adjacent variables in ordering and reorder all bbdd that have a registered output
*
* @param pos_b position of first variable
* @param pos_c position of second variable
*/
void
swap_all_positions
(
node_index_t
pos_b
,
node_index_t
pos_c
)
{
node_index_t
var_b
=
(
*
cvo
)[
pos_b
].
in
;
node_index_t
var_c
=
(
*
cvo
)[
pos_c
].
in
;
swap_variable_order
(
pos_b
,
pos_c
);
for
(
uint32_t
i
=
0
;
i
<
output_map
.
size
();
i
++
)
{
output_map
[
i
].
bbdd
=
reduce_bbdd
(
reorder_bbdd
(
output_map
[
i
].
bbdd
,
var_b
,
var_c
));
}
}
};
File Metadata
Details
Attached
Mime Type
text/x-c++
Expires
Tue, Oct 27, 3:31 PM (23 h, 48 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
406179
Default Alt Text
unique_table.hpp (40 KB)
Attached To
Mode
R271 SoC_BBDD_Library
Attached
Detach File
Event Timeline