blob: fed6c85e23a6002664e0aee273ff1914623cefe5 [file] [log] [blame] [edit]
/*
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
*/
#include <stdlib.h>
#include <stdio.h>
#include "misc/util/abc_namespaces.h"
#include "misc/st/st.h"
#include "bdd/cudd/cuddInt.h"
#include "bdd/cudd/cudd.h"
#include "odin_error.h"
#include "odin_util.h"
#include "ace.h"
#include "vtr_memory.h"
#define ACE_P0TO1(P1,PS) ((P1)==0.0)?0.0:(((P1)==1.0)?1.0:0.5*PS/(1.0-(P1)))
#define ACE_P1TO0(P1,PS) ((P1)==0.0)?1.0:(((P1)==0.0)?0.0:0.5*PS/(P1))
#define MAX(a,b) (a > b ? a : b)
/* Cube routines from Espresso-mv */
#define TWO 3
#define DASH 3
#define ONE 2
#define ZERO 1
#define BPI 32
#define LOGBPI 5
#define LOOPINIT(size) ((size <= BPI) ? 1 : WHICH_WORD((size)-1))
#define WHICH_WORD(element) (((element) >> LOGBPI) + 1)
#define WHICH_BIT(element) ((element) & (BPI-1))
#define GETINPUT(c, pos) ((c[WHICH_WORD(2*pos)] >> WHICH_BIT(2*pos)) & 3)
#define node_get_literal(c_, j_) ((c_) ? GETINPUT((c_), (j_)) : node_error(2))
typedef unsigned int *pset;
#define ALLOC(type, num) ((type *) malloc(sizeof(type) * (num)))
#define set_remove(set, e) (set[WHICH_WORD(e)] &= ~ (shift_left_value_with_overflow_check(0x1, WHICH_BIT(e))))
#define set_insert(set, e) (set[WHICH_WORD(e)] |= (shift_left_value_with_overflow_check(0x1, WHICH_BIT(e))))
#define set_new(size) set_clear(ALLOC(unsigned int, set_size(size)), size)
#define set_size(size) ((size) <= BPI ? 2 : (WHICH_WORD((size)-1) + 1))
typedef struct {
pset cube;
int num_literals;
double static_prob;
} ace_cube_t;
/******** Function prototypes ********/
ace_obj_info_t* alloc_and_init_ace_info_object ();
int calc_node_depth(nnode_t *node );
void compute_switching_activities ( netlist_t *net );
void prob_epsilon_fix(double * d);
void output_ace_info (netlist_t *net, FILE *act_out );
void output_ace_info_node ( char *name, ace_obj_info_t *info, FILE *act_out );
pset set_clear(pset r, int size);
ace_cube_t * ace_cube_dup(ace_cube_t * cube);
ace_cube_t * ace_cube_new_dc(int num_literals);
DdNode * build_bdd_for_node ( DdManager * dd, nnode_t *node );
void ace_bdd_count_paths(DdManager * mgr, DdNode * bdd, int * num_one_paths, int * num_zero_paths);
double calc_cube_switch_prob_recur(DdManager * mgr, DdNode * bdd, ace_cube_t * cube, nnode_t *node , st__table *visited, int phase );
double calc_cube_switch_prob(DdManager * mgr, DdNode * bdd, ace_cube_t * cube, nnode_t *node, int phase );
double calc_switch_prob_recur(DdManager * mgr, DdNode * bdd_next, DdNode * bdd, ace_cube_t * cube, nnode_t *node, double P1, int phase );
int node_error(int code);
/*---------------------------------------------------------------------------
* (function: alloc_and_init_ace_structs )
*
* Allocates and initializes Ace Objects for a given NetList
*
*---------------------------------------------------------------------------*/
void alloc_and_init_ace_structs(netlist_t *net) {
int x,y;
/*
printf ( "alloc_and_init_activity_info\n");
printf ( "----------------------------\n");
printf ("PIs in network: %ld\n", net->num_top_input_nodes);
printf ("POs in network: %ld\n", net->num_top_output_nodes);
printf ("Nodes in network: %ld\n", net->num_internal_nodes);
printf ("FF Nodes in network: %ld\n", net->num_ff_nodes);
printf ("Forward Level Nodes in network: %ld\n", net->num_forward_levels);
printf ("Backward Level Nodes in network: %ld\n", net->num_backward_levels);
*/
// GND Node
net->gnd_node->output_pins[0]->ace_info = alloc_and_init_ace_info_object();
// VCC Node
net->vcc_node->output_pins[0]->ace_info = alloc_and_init_ace_info_object();
// unconn Node
net->pad_node->output_pins[0]->ace_info = alloc_and_init_ace_info_object();
// Input Nodes
for ( x = 0; x < net->num_top_input_nodes; x++ ) {
for ( y = 0; y < net->top_input_nodes[x]->num_output_pins; y++ ) {
net->top_input_nodes[x]->output_pins[y]->ace_info = alloc_and_init_ace_info_object();
}
}
// FF Nodes
for ( x = 0; x < net->num_ff_nodes; x++ ) {
for ( y = 0; y < net->ff_nodes[x]->num_output_pins; y++ ) {
net->ff_nodes[x]->output_pins[y]->ace_info = alloc_and_init_ace_info_object();
}
}
// Internal Nodes
for ( x = 0; x < net->num_internal_nodes; x++ ) {
for ( y = 0; y < net->internal_nodes[x]->num_output_pins; y++ ) {
net->internal_nodes[x]->output_pins[y]->ace_info = alloc_and_init_ace_info_object();
}
}
// Calculate depth of nodes. Must have ace_info object allocated first
for ( x = 0; x < net->num_internal_nodes; x++ ) {
for ( y = 0; y < net->internal_nodes[x]->num_output_pins; y++ ) {
net->internal_nodes[x]->output_pins[y]->ace_info->depth = calc_node_depth ( net->internal_nodes[x] );
}
}
}
/*---------------------------------------------------------------------------
* (function: alloc_and_init_ace_info_object )
*
* Allocates, initializes and returns an Ace Object
*
*---------------------------------------------------------------------------*/
ace_obj_info_t* alloc_and_init_ace_info_object() {
ace_obj_info_t *new_node;
new_node = (ace_obj_info_t *)my_malloc_struct(sizeof(ace_obj_info_t));
new_node->value = -1;
new_node->num_toggles = 0;
new_node->num_ones = 0;
new_node->depth = 0;
return new_node;
}
/*---------------------------------------------------------------------------
* (function: calc_node_depth )
*
* Determine the depth of a given node within its netlist
*
*---------------------------------------------------------------------------*/
int calc_node_depth(nnode_t *node ) {
int x, depth = 0;
ace_obj_info_t * fanin_info;
for ( x = 0; x < node->num_input_pins; x++ ) {
fanin_info = node->input_pins[x]->net->driver_pin->ace_info;
depth = MAX ( depth, fanin_info->depth );
}
return depth + 1;
}
/*---------------------------------------------------------------------------------------------
* (function: calculate_activity )
*
* Calculates activity stats for a given netlist
*
*-------------------------------------------------------------------------------------------*/
void calculate_activity ( netlist_t *net, int max_cycles, FILE *act_out ) {
int x,y;
ace_obj_info_t *info;
/*
printf ( "Calculating Activity Stats\n");
printf ( "--------------------------\n");
*/
// Process Top Input Nodes
for ( x = 0; x < net->num_top_input_nodes; x++ ) {
info = net->top_input_nodes[x]->output_pins[0]->ace_info;
// Odin processes each vector 2 times, need to adjust count.
info->num_ones = info->num_ones / 2;
// Static Probability = NUMBER of ONES / Cycles
info->static_prob = (double ) info->num_ones / (double) max_cycles;
// Clock should toggle once per cycle
if ( net->top_input_nodes[x]->type == CLOCK_NODE ) {
info->num_toggles = max_cycles;
}
// Switching Probability = NUMBER of TOGGLES / Cycles
info->switch_prob = info->num_toggles / (double) max_cycles;
// Switch Activity = same as Switching Probability for top inputs.
info->switch_act = info->switch_prob;
}
// Process FF Nodes
for ( x = 0; x < net->num_ff_nodes; x++ ) {
info = net->ff_nodes[x]->output_pins[0]->ace_info;
// Odin process each vector 2 times, need to adjust count.
info->num_ones = info->num_ones / 2;
// Static Probability = NUMBER of ONES / Cycles
info->static_prob = info->num_ones / (double) max_cycles;
// Switching Probability = NUMBER of TOGGLES / Cycles
info->switch_prob = info->num_toggles / (double) max_cycles;
// Switch Activity = same as Switching Probability for FF nodes
info->switch_act = info->switch_prob;
}
// Process Internal Nodes
for ( x = 0; x < net->num_internal_nodes; x++ ) {
for ( y = 0; y < net->internal_nodes[x]->num_output_pins; y++ ) {
info = net->internal_nodes[x]->output_pins[y]->ace_info;
// Odin process each vector 2 times, need to adjust count.
info->num_ones = info->num_ones / 2;
// Static Probability = NUMBER of ONES / Cycles
info->static_prob = info->num_ones / (double) max_cycles;
// Switching Probability = NUMBER of TOGGLES / Cycles
info->switch_prob = info->num_toggles / (double) max_cycles;
}
}
//Compute Switching Activities for Internal Nodes
compute_switching_activities ( net );
// Output ACE Info
output_ace_info (net, act_out );
}
/*---------------------------------------------------------------------------------------------
* (function: compute_switching_activities )
*
* Calculates switchin activities for a given netlist
*
*-------------------------------------------------------------------------------------------*/
void compute_switching_activities ( netlist_t *net ) {
int x,y,z;
int n0, n1;
ace_obj_info_t *info, *fanin_info;
int d;
DdManager * dd;
DdNode * bdd;
ace_cube_t * cube;
// Initialize Cudd
dd = Cudd_Init( 0, 0, CUDD_UNIQUE_SLOTS, CUDD_CACHE_SLOTS, 0 );
// Process each internal node
for ( x = 0; x < net->num_internal_nodes; x++ ) {
// Process each output pin of node
for ( y = 0; y < net->internal_nodes[x]->num_output_pins; y++ ) {
info = net->internal_nodes[x]->output_pins[y]->ace_info;
d = info->depth;
d = (int) d * 0.4;
if (d < 1) {
d = 1;
}
// If nodes has a bitmap/truthtable use LAG 1 BDD model to determine switching activity
if ( net->internal_nodes[x]->bit_map_line_count > 0 ) {
bdd = build_bdd_for_node (dd, net->internal_nodes[x] );
Cudd_Ref ( bdd );
n0 = n1 = 0;
ace_bdd_count_paths(dd, bdd, &n1, &n0);
// Process each fanin node
for ( z = 0; z < net->internal_nodes[x]->num_input_pins; z++ ) {
fanin_info = net->internal_nodes[x]->input_pins[z]->net->driver_pin->ace_info;
fanin_info->prob0to1 = ACE_P0TO1 (fanin_info->static_prob, fanin_info->switch_prob / (double) d);
fanin_info->prob1to0 = ACE_P1TO0 (fanin_info->static_prob, fanin_info->switch_prob / (double) d);
prob_epsilon_fix(&fanin_info->prob0to1);
prob_epsilon_fix(&fanin_info->prob1to0);
}
cube = ace_cube_new_dc(net->internal_nodes[x]->num_input_pins);
info->switch_act = 2.0 * calc_switch_prob_recur ( dd, bdd, bdd, cube, net->internal_nodes[x], 1.0, n1 > n0 ) * (double) d;
}
// If nodes does not have a bitmap, use switching probability as switching activity
else {
info->switch_act = info->switch_prob;
}
}
}
Cudd_Quit(dd);
}
/*---------------------------------------------------------------------------------------------
* (function: prob_epsilon_fix )
*
* Adjust probabilty for machine epsilon rounding
*
*-------------------------------------------------------------------------------------------*/
void prob_epsilon_fix(double * d) {
if (*d < 0) {
*d = 0;
} else if (*d > 1) {
*d = 1.;
}
}
/*---------------------------------------------------------------------------------------------
* (function: output_ace_info )
*
* Outputs ACE information for a given NetList
*
*-------------------------------------------------------------------------------------------*/
void output_ace_info (netlist_t *net, FILE *act_out ) {
int x,y;
// Process Top Input Nodes
for ( x = 0; x < net->num_top_input_nodes; x++ ) {
output_ace_info_node (net->top_input_nodes[x]->name,
net->top_input_nodes[x]->output_pins[0]->ace_info,
act_out );
}
// Process FF Nodes
for ( x = 0; x < net->num_ff_nodes; x++ ) {
output_ace_info_node ( net->ff_nodes[x]->name,
net->ff_nodes[x]->output_pins[0]->ace_info,
act_out );
}
// Process Internal Nodes
for ( x = 0; x < net->num_internal_nodes; x++ ) {
for ( y = 0; y < net->internal_nodes[x]->num_output_pins; y++ ) {
output_ace_info_node ( net->internal_nodes[x]->output_pins[y]->name,
net->internal_nodes[x]->output_pins[y]->ace_info,
act_out );
}
}
}
/*---------------------------------------------------------------------------------------------
* (function: output_ace_info_node )
*
* Outputs ACE information for a given Node
*
*-------------------------------------------------------------------------------------------*/
void output_ace_info_node ( char *name, ace_obj_info_t *info, FILE *act_out ) {
/*
printf ( "%s %f %f %f DEBUG: ONES: %3d TOGGLES: %ld\n",
name,
info->static_prob,
info->switch_prob ,
info->switch_act,
info->num_ones,
info->num_toggles
);
*/
fprintf ( act_out, "%s %f %f %f\n",
name,
info->static_prob,
info->switch_prob ,
info->switch_act
);
}
/*---------------------------------------------------------------------------
* (function: set_clear )
*
* make "r" the empty set of "size" elements
*
* This function is from Espresso-mv
*
*---------------------------------------------------------------------------*/
pset set_clear(pset r, int size)
{
int i = LOOPINIT(size);
*r = i; do r[i] = 0; while (--i > 0);
return r;
}
/*---------------------------------------------------------------------------------------------
* (function: node_error )
*
*-------------------------------------------------------------------------------------------*/
int node_error(int code) {
switch (code) {
case 0:
error_message(ACE,-1, -1, "%s", "node_get_cube: node does not have a function");
/* NOTREACHED */
break;
case 1:
error_message(ACE,-1, -1, "%s","node_get_cube: cube index out of bounds");
/* NOTREACHED */
break;
case 2:
error_message(ACE,-1, -1, "%s","node_get_literal: bad cube");
/* NOTREACHED */
break;
case 4:
error_message(ACE,-1, -1, "%s","foreach_fanin: node changed during generation");
/* NOTREACHED */
break;
case 5:
error_message(ACE,-1, -1, "%s","foreach_fanout: node changed during generation");
/* NOTREACHED */
break;
default:
error_message(ACE,-1, -1, "%s","error code unused");
break;
}
return 0;
}
/*---------------------------------------------------------------------------------------------
* (function: ace_cube_dup )
*
*-------------------------------------------------------------------------------------------*/
ace_cube_t * ace_cube_dup(ace_cube_t * cube) {
int i;
ace_cube_t * cube_copy;
cube_copy = (ace_cube_t * ) malloc(sizeof(ace_cube_t));
cube_copy->static_prob = cube->static_prob;
cube_copy->num_literals = cube->num_literals;
cube_copy->cube = set_new (2 * cube->num_literals);
for (i = 0; i < cube->num_literals; i++) {
switch (node_get_literal (cube->cube, i)) {
case ZERO:
set_insert(cube_copy->cube, 2 * i);
set_remove(cube_copy->cube, 2 * i + 1);
break;
case ONE:
set_remove(cube_copy->cube, 2 * i);
set_insert(cube_copy->cube, 2 * i + 1);
break;
case TWO:
set_insert(cube_copy->cube, 2 * i);
set_insert(cube_copy->cube, 2 * i + 1);
break;
default:
error_message(ACE,-1, -1, "%s","Bad literal.");
}
}
return (cube_copy);
}
/*---------------------------------------------------------------------------------------------
* (function: ace_cube_new_dc )
*
*-------------------------------------------------------------------------------------------*/
ace_cube_t * ace_cube_new_dc(int num_literals) {
int i;
ace_cube_t * new_cube;
new_cube = (ace_cube_t * ) malloc(sizeof(ace_cube_t));
new_cube->num_literals = num_literals;
new_cube->static_prob = 1.0;
new_cube->cube = set_new (2 * num_literals);
for (i = 0; i < num_literals; i++) {
set_insert(new_cube->cube, 2 * i);
set_insert(new_cube->cube, 2 * i + 1);
}
return (new_cube);
}
/*---------------------------------------------------------------------------------------------
* (function: build_bdd_for_node )
*
* Returns a Binary Decision Diagram (bdd) for a given node base upon its truth table entries.
*
* This function is based upon ABC's Abc_ConvertSopToBdd.
*
*-------------------------------------------------------------------------------------------*/
DdNode * build_bdd_for_node ( DdManager * dd, nnode_t *node ) {
DdNode * bSum, * bCube, * bTemp, * bVar;
int Value, x, y;
bSum = Cudd_ReadLogicZero(dd);
Cudd_Ref( bSum );
// check the logic function of the node
for ( x = 0; x < node->bit_map_line_count; x++ ) {
bCube = Cudd_ReadOne(dd); Cudd_Ref( bCube );
for ( y = 0; y < (int) strlen(node->bit_map[x]); y++ ) {
Value = node->bit_map[x][y];
if ( Value == '0' )
bVar = Cudd_Not( Cudd_bddIthVar( dd, y ) );
else if ( Value == '1' )
bVar = Cudd_bddIthVar( dd, y );
else
continue;
bCube = Cudd_bddAnd( dd, bTemp = bCube, bVar ); Cudd_Ref( bCube );
Cudd_RecursiveDeref( dd, bTemp );
}
bSum = Cudd_bddOr( dd, bTemp = bSum, bCube );
Cudd_Ref( bSum );
Cudd_RecursiveDeref( dd, bTemp );
Cudd_RecursiveDeref( dd, bCube );
}
Cudd_Deref( bSum );
return bSum;
}
/*---------------------------------------------------------------------------------------------
* (function: ace_bdd_count_paths )
*
*-------------------------------------------------------------------------------------------*/
void ace_bdd_count_paths(DdManager * mgr, DdNode * bdd, int * num_one_paths, int * num_zero_paths) {
DdNode * then_bdd;
DdNode * else_bdd;
if (bdd == Cudd_ReadLogicZero(mgr)) {
*num_zero_paths = *num_zero_paths + 1;
return;
} else if (bdd == Cudd_ReadOne(mgr)) {
*num_one_paths = *num_one_paths + 1;
return;
}
then_bdd = Cudd_T(bdd);
ace_bdd_count_paths(mgr, then_bdd, num_one_paths, num_zero_paths);
else_bdd = Cudd_E(bdd);
ace_bdd_count_paths(mgr, else_bdd, num_one_paths, num_zero_paths);
}
/*---------------------------------------------------------------------------------------------
* (function: calc_cube_switch_prob_recur )
*
*-------------------------------------------------------------------------------------------*/
double calc_cube_switch_prob_recur(DdManager * mgr, DdNode * bdd, ace_cube_t * cube, nnode_t *node , st__table *visited, int phase ) {
double * current_prob;
short i;
DdNode * bdd_if1, *bdd_if0;
double then_prob, else_prob;
ace_obj_info_t *fanin_info;
if (bdd == Cudd_ReadLogicZero(mgr)) {
if (phase == 0)
return (1.0);
if (phase == 1)
return (0.0);
} else if (bdd == Cudd_ReadOne(mgr)) {
if (phase == 1)
return (1.0);
if (phase == 0)
return (0.0);
}
if (st__lookup(visited, (char *) bdd, (char **) &current_prob)) {
return (*current_prob);
}
i = Cudd_Regular(bdd)->index;
current_prob = ( double * ) malloc(sizeof(double));
if (Cudd_IsComplement(bdd)) {
bdd_if1 = Cudd_E(bdd);
bdd_if0 = Cudd_T(bdd);
} else {
bdd_if1 = Cudd_T(bdd);
bdd_if0 = Cudd_E(bdd);
}
fanin_info = node->input_pins[i]->net->driver_pin->ace_info;
then_prob = calc_cube_switch_prob_recur(mgr, bdd_if1, cube, node, visited, phase );
else_prob = calc_cube_switch_prob_recur(mgr, bdd_if0, cube, node, visited, phase );
switch (node_get_literal (cube->cube, i)) {
case ZERO:
*current_prob = fanin_info->prob0to1 * then_prob
+ (1.0 - fanin_info->prob0to1) * else_prob;
break;
case ONE:
*current_prob = (1.0 - fanin_info->prob1to0) * then_prob
+ fanin_info->prob1to0 * else_prob;
break;
case TWO:
*current_prob = fanin_info->static_prob * then_prob
+ (1.0 - fanin_info->static_prob) * else_prob;
break;
default:
error_message(ACE,-1, -1, "%s","Bad literal.");
}
st__insert(visited, (char *) bdd, (char *) current_prob);
return (*current_prob);
}
/*---------------------------------------------------------------------------------------------
* (function: calc_cube_switch_prob )
*
*-------------------------------------------------------------------------------------------*/
double calc_cube_switch_prob(DdManager * mgr, DdNode * bdd, ace_cube_t * cube, nnode_t *node, int phase ) {
double sp;
st__table * visited;
visited = (st__table * ) st__init_table( st__ptrcmp, st__ptrhash);
sp = calc_cube_switch_prob_recur(mgr, bdd, cube, node,visited, phase );
st__free_table(visited);
return (sp);
}
/*---------------------------------------------------------------------------------------------
* (function: calc_switch_prob_recur )
*
*-------------------------------------------------------------------------------------------*/
double calc_switch_prob_recur(DdManager * mgr, DdNode * bdd_next, DdNode * bdd, ace_cube_t * cube, nnode_t *node, double P1, int phase ) {
short i;
double switch_prob_t, switch_prob_e;
double prob;
DdNode * bdd_if1, *bdd_if0;
ace_cube_t * cube0, *cube1;
ace_obj_info_t * info;
if (bdd == Cudd_ReadLogicZero(mgr)) {
if (phase != 1) {
return (0.0);
}
prob = calc_cube_switch_prob(mgr, bdd_next, cube, node, phase );
prob *= P1;
return (prob * P1);
}
else if (bdd == Cudd_ReadOne(mgr)) {
if (phase != 0) {
return (0.0);
}
prob = calc_cube_switch_prob(mgr, bdd_next, cube, node, phase );
prob *= P1;
return (prob * P1);
}
/* Get literal index for this bdd node. */
i = Cudd_Regular(bdd)->index;
info = node->input_pins[i]->net->driver_pin->ace_info;
if (Cudd_IsComplement(bdd)) {
bdd_if1 = Cudd_E(bdd);
bdd_if0 = Cudd_T(bdd);
} else {
bdd_if1 = Cudd_T(bdd);
bdd_if0 = Cudd_E(bdd);
}
/* Recursive call down the THEN branch */
cube1 = ace_cube_dup(cube);
set_remove(cube1->cube, 2 * i);
set_insert(cube1->cube, 2 * i + 1);
switch_prob_t = calc_switch_prob_recur(mgr, bdd_next, bdd_if1, cube1, node,
P1 * info->static_prob, phase );
vtr::free(cube1->cube);
vtr::free(cube1);
/* Recursive call down the ELSE branch */
cube0 = ace_cube_dup(cube);
set_insert(cube0->cube, 2 * i);
set_remove(cube0->cube, 2 * i + 1);
switch_prob_e = calc_switch_prob_recur(mgr, bdd_next, bdd_if0, cube0, node,
P1 * (1.0 - info->static_prob), phase );
vtr::free(cube0->cube);
vtr::free(cube0);
return (switch_prob_t + switch_prob_e);
}