/**CFile***********************************************************************
FileName [spfdCmd.c]
PackageName [spfd]
Synopsis [Interface functions for commands spfd_pilo and spfd_pdlo.]
Description [Interface functions for commands spfd_pilo and spfd_pdlo.]
SeeAlso [spfdOpt.c]
Author [Balakrishna Kumthekar]
Copyright [This file was created at the University of Colorado at Boulder.
The University of Colorado at Boulder makes no warranty about the suitability
of this software for any purpose. It is presented on an AS IS basis.]
******************************************************************************/
#include "spfdInt.h"
static char rcsid[] UNUSED = "$Id: spfdCmd.c,v 1.28 2002/09/09 01:04:28 fabio Exp $";
/*---------------------------------------------------------------------------*/
/* Constant declarations */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/* Type declarations */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/* Structure declarations */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/* Variable declarations */
/*---------------------------------------------------------------------------*/
static jmp_buf timeOutEnv; /* time out */
int spfdCreatedPart; /* Whether network BDDs were created in the package */
int spfdVerbose; /* verbosity */
float spfdAlpha; /* spfdAlpha * load + (1-spfdAlpha) * topDepth, is used to order
fanin nodes during SPFD computation */
boolean spfdPerfSim; /* Perform simulation */
boolean spfdNtkChanged; /* TRUE if network changes structurally or functionally */
boolean spfdReprogNoWire; /* If TRUE, no functional changes are performed
unless required by structural changes */
int spfdWiresAdded, spfdNumWiresRem; /* Number of wires added and removed */
int spfdSortNodes; /* Method to sort nodes */
int spfdMethod; /* Optimization method */
/*---------------------------------------------------------------------------*/
/* Macro declarations */
/*---------------------------------------------------------------------------*/
/**AutomaticStart*************************************************************/
/*---------------------------------------------------------------------------*/
/* Static function prototypes */
/*---------------------------------------------------------------------------*/
static int CommandSpfdNetworkOptimize(Hrc_Manager_t **hmgr, int argc, char **argv);
static int CommandSpfdPlaceOptimize(Hrc_Manager_t **hmgr, int argc, char **argv);
static void TimeOutHandle(void);
static int TestIsNetworkMultipleValued(Ntk_Network_t *network);
static int SpfdSimultaneousPlacementAndLogicOpt(Ntk_Network_t *network, char *netFile, char *archFile, char *placeFile, char *routeFile, char *netOutFile, int regionDepth);
/**AutomaticEnd***************************************************************/
/*---------------------------------------------------------------------------*/
/* Definition of exported functions */
/*---------------------------------------------------------------------------*/
/**Function********************************************************************
Synopsis [This function initializes the spfd package.]
SideEffects [None]
SeeAlso [Spfd_End]
******************************************************************************/
void
Spfd_Init(void)
{
Cmd_CommandAdd("spfd_pilo", CommandSpfdNetworkOptimize, 1);
Cmd_CommandAdd("spfd_pdlo", CommandSpfdPlaceOptimize, 1);
} /* End of Spfd_Init */
/**Function********************************************************************
Synopsis [This function ends the spfd package.]
SideEffects [None]
SeeAlso [Spfd_Init]
******************************************************************************/
void
Spfd_End(void)
{
} /* End of Spfd_End */
/*---------------------------------------------------------------------------*/
/* Definition of internal functions */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/* Definition of static functions */
/*---------------------------------------------------------------------------*/
/**Function********************************************************************
Synopsis [Implements SPFD-based placement independent logic
optimization command, spfd_pilo, for combinational circuits mapped
to LUT-based FPGAs.]
CommandName [spfd_pilo]
CommandSynopsis [Perform SPFD-based placement independent logic
optimization.]
CommandArguments [\[-a <\[0,1\]>\] \[-D <depth>\] \[-f
<file>\] \[-h\] \[-i <freq>\] \[-p <percent>\]
\[-r\] \[-S <n>\] \[-t <sec>\] \[-v <n>\]
\[-w <file>\] ]
CommandDescription [This command performs SPFD-based wire
removal/replacement and reprogramming of combinational circuits
mapped to LUT-based FPGAs to reduce the number of wires and nodes
in the circuit. The flexibilities in the circuit are represented by
SPFDs. The following references explain in detail the theory behind
SPFDs.
S. Yamashita, H. Sawada, and A. Nagoya. A new method to express
functional permissibilities for LUT based FPGAs and its
applications. In International Conference on Computer Aided Design,
pages 254-261, 1996.
Subarnarekha Sinha and Robert K. Brayton. Implementation and use of
SPFDs in optimizaing Boolean networks. In International Conference
on Computer Aided Design, 1998.
Instead of computing the flexibilities for every node in the
network at once, the algorithm computes the flexibilities for one
cluster at a time. Working with clusters allows us to avoid the BDD
explosion problem and hence, handle large circuits. The SPFDs are
computed for the cluster and the cluster nodes are reprogrammed
based on the flexibility derived. Switching activity is used to
drive the choice of alternate function to be implemented at the
node. In the absence of switching activity information, the
function that can reduce support of the node can be chosen (not
implemented). Currently, an arbitrary choice is made from the
flexibilities provided by SPFDs. (-S 0, -S 2, and -S 4)
Before calling this command a network should be created for the
design (use flatten_hierarchy) and MDD ids for every node in the
network should be created (static_order -o all -n append, for
example). Dynamic variable ordering (dvo -e sift) can be enabled
to reduce BDD sizes.
Command options:
- -a <alpha>
- A convex combination of switched
capacitance (switching activity * fanout count, SWC) and topological
depth is used to sort the fanin nodes during SPFD computation. alpha
is between 0 and 1.0. The cost function is alpha*SWC +
(1.0-alpha)*topDepth. The default value is 0.5.
- -D <depth>
- A cluster is computed which includes nodes within the specified
'depth'. The default value is 1.
- -f <file>
- File with simulation vectors. The file
format is as below. The format is simple but strict and hence, few
checks are made.
.i c n d o e p f q g r h s i t j u k a l b m
.s
0 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 0 1 1 1 1 ;
0 1 1 0 0 0 0 1 0 1 1 0 1 1 1 1 0 0 0 0 1 ;
0 0 1 0 0 0 0 1 0 1 0 0 0 1 0 1 0 0 0 0 1 ;
0 1 1 0 0 0 0 1 1 1 1 1 1 1 1 1 0 1 0 0 1 ;
The .i statement specifies the primary inputs of the network. The
patterns start after .s key word. Each vector is a space separated list of
bits and ends in a semi-colon. The length of any vector should be equal
to the number of signals specified in the .i statement. A line starting
with # is a comment.
- -h
- Print usage.
- -i <freq>
- Number of iterations after which to update node switching
activity. This is valid only if patterns are provided in a file
using -f option. The default value is every 5 iterations.
- -m <n>
- Heuristics to optimize a selected node.
0
: Reduce the selected node's support.
1
: Reprogram the selected node.
2
: Reprogram the selected node's fanin nodes.
(default)
3
: Reduce the selected node's fanout wires.
- -p <percent>
- The percentage of vectors, specified via
-f
option, used to perform simulation (to update switching activity)
during logic optimization. The default value is 10%.
- -r
- Do not reprogram LUTs if no structural changes have been
performed with in the cluster, i.e., if no nodes or wires have been
removed do not change the local implementation of LUTs even if
alternate implementations are availabe from SPFD information. The
default is to reprogram.
- -S <n>
- Method used to sort nodes. The nodes are then optimized in
that order.
0
: Random node is chosen. (default)
1
: If switching activity is available, node with
maximum SWC is chosen.
2
: Node with maximum fanout is chosen.
3
: If switching activity is available, node with
minimum SWC is chosen.
4
: Node with minimum fanout is chosen.
- -t <sec>
- Time in seconds allowed to complete the command. If the
computation time goes above that limit, the process is aborted.
The default is no limit.
- -v <n>
- Verbosity level. Default value is 0.
- -w <file>
- File to output final optimized circuit.
]
Relevant flags to be set by the set command:
- spfd_repl_rem
- If no, the logic optimization performs only wire
removal. If yes, both wire replacement and removal are performed.
SideEffects [The network is changed to reflect the wires/nodes
removed or replaced. The internal function of the nodes is also
changed. The partition attached to the network is changed
accordingly.]
******************************************************************************/
static int
CommandSpfdNetworkOptimize(
Hrc_Manager_t **hmgr,
int argc,
char **argv)
{
Ntk_Network_t *network = NIL(Ntk_Network_t);
graph_t *simPart;
int status,percent,frequency,regionDepth;
int c;
long timeOutPeriod,initialTime,finalTime;
char *simFile,*writeFile;
char endPtr[128];
FILE *fp = NIL(FILE);
/* These are the default values. */
spfdCreatedPart = 0; /* Do not create a new partition */
timeOutPeriod = 0;
simFile = NIL(char); /* File containing simulation vectors */
spfdVerbose = 0; /* verbosity */
regionDepth = 1; /* Depth of cluster */
percent = 10; /* Percent of total vectors to be simulated during opt. */
frequency = 5; /* Perform simulation every frequency iterations */
spfdSortNodes = RANDOM; /* Choose a random node for optimization */
spfdMethod = 2;
spfdAlpha = 0.5;
writeFile = NIL(char); /* File to output final optimized ckt. */
spfdNtkChanged = FALSE;
spfdReprogNoWire = TRUE;
spfdWiresAdded = 0;
spfdNumWiresRem = 0;
spfdPerfSim = FALSE; /* Default */
if (bdd_get_package_name() != CUDD) {
(void) fprintf(vis_stderr,
"** spfd error: The spfd package can be used "
"only with CUDD package\n");
(void) fprintf(vis_stderr,
"** spfd error: Please link with CUDD package\n");
return 0;
}
util_getopt_reset();
while((c = util_getopt(argc, argv, "a:D:f:hi:m:p:rS:t:v:w:")) != EOF) {
switch(c) {
case 'a':
spfdAlpha = (float) strtod(util_optarg,(char **)&endPtr);
if (!strcmp(util_optarg,endPtr)) {
(void) fprintf(vis_stdout,
"** spfd warning: Invalid value <%s> specified for -a\n",
util_optarg);
(void) fprintf(vis_stdout,"** spfd warning: Assuming 0.5.\n");
spfdAlpha = 0.5;
} else if (spfdAlpha > 1.0 || spfdAlpha < 0.0) {
(void) fprintf(vis_stdout,
"** spfd warning: Value for -a <%f> not in [0,1]\n",
spfdAlpha);
(void) fprintf(vis_stdout,"** spfd warning: Assuming 0.5.\n");
spfdAlpha = 0.5;
}
break;
case 'D':
regionDepth = atoi(util_optarg);
break;
case 'f':
if (!util_optarg) {
(void) fprintf(vis_stderr,
"** spfd error: Simulation file not specified.\n");
goto usage;
} else {
simFile = util_strsav(util_optarg);
if ((fp = Cmd_FileOpen(simFile,"r",NIL(char *),1)) == NIL(FILE)) {
(void) fprintf(vis_stderr,
"** spfd error: Could not open %s for reading.\n",
simFile);
goto endgame;
} else {
fclose(fp);
}
spfdPerfSim = TRUE;
}
break;
case 'h':
goto usage;
case 'i':
frequency = atoi(util_optarg);
break;
case 'm':
spfdMethod = atoi(util_optarg);
if (spfdMethod > 3 || spfdMethod < 0) {
(void) fprintf(vis_stderr, "** spfd warning: -m has invalid argument\n");
(void) fprintf(vis_stderr, "** spfd warning: Using 2 instead.\n");
}
break;
case 'p':
percent = atoi(util_optarg);
if (percent > 100 || percent < 0) {
(void) fprintf(vis_stderr,
"** spfd warning: -p <%d> has invalid argument.\n",
percent);
(void) fprintf(vis_stderr,
"** spfd warning: Using 10%% instead.\n");
}
break;
case 'r':
spfdReprogNoWire = FALSE;
break;
case 'S':
spfdSortNodes = atoi(util_optarg);
if (spfdSortNodes > 4 || spfdSortNodes < 0) {
(void) fprintf(vis_stderr,
"** spfd warning: -S <%d> has invalid argument.\n",
spfdSortNodes);
(void) fprintf(vis_stderr,
"** spfd warning: Using 0 (random) instead.\n");
}
break;
case 't':
timeOutPeriod = atoi(util_optarg);
break;
case 'v':
spfdVerbose = atoi(util_optarg);
break;
case 'w':
writeFile = util_strsav(util_optarg);
if ((fp = Cmd_FileOpen(writeFile,"w",NIL(char *),1)) == NIL(FILE)) {
(void) fprintf(vis_stderr,
"** spfd error: Could not open %s for writing.\n",
writeFile);
goto endgame;
} else {
fclose(fp);
}
break;
default:
goto usage;
}
}
if(Hrc_ManagerReadCurrentNode(*hmgr) == NIL(Hrc_Node_t)) {
(void) fprintf(vis_stderr,"** spfd error: The hierarchy manager is empty."
" Read in design.\n");
goto endgame;
}
network = (Ntk_Network_t *)
Hrc_NodeReadApplInfo(Hrc_ManagerReadCurrentNode(*hmgr),
NTK_HRC_NODE_APPL_KEY);
if(network == NIL(Ntk_Network_t)) {
(void) fprintf(vis_stderr,"** spfd error: There is no network. ");
(void) fprintf(vis_stderr,"Use flatten_hierarchy.\n");
goto endgame;
}
/* Check if the current network has signals with multiple values. */
if (TestIsNetworkMultipleValued(network)) {
(void) fprintf(vis_stderr,"** spfd error: Circuit has multiple "
"valued variables.\n");
(void) fprintf(vis_stderr,"** spfd error: The algorithm currently "
"supports only Boolean valued variables.\n");
goto endgame;
}
if(Ntk_NetworkReadNumPrimaryInputs(network) !=
Ntk_NetworkReadNumInputs(network)) {
(void) fprintf(vis_stderr,"** spfd error: Pseudo inputs present "
"in the network.\n");
(void) fprintf(vis_stderr,"** spfd error: The algorithm does not apply.\n");
goto endgame;
}
if(Ntk_NetworkReadNumLatches(network) > 0) {
(void) fprintf(vis_stderr,"** spfd error: Sequential circuit.\n");
(void) fprintf(vis_stderr,"** spfd error: The command is only for combinational circuits.\n");
goto endgame;
}
/* Access a 'total' partition */
simPart = (graph_t *) Ntk_NetworkReadApplInfo(network,PART_NETWORK_APPL_KEY);
if (simPart == NIL(graph_t) ||
(Part_PartitionReadMethod(simPart) != Part_Total_c)) {
simPart = Part_NetworkCreatePartition(network,
NIL(Hrc_Node_t),
"dummy", (lsList) 0,
(lsList) 0, NIL(mdd_t),
Part_Total_c,
(lsList) 0,
FALSE, FALSE, TRUE);
if (simPart == NIL(graph_t)) {
(void) fprintf(vis_stderr,"** spfd error: Could not create partition.\n");
goto endgame;
}
Ntk_NetworkAddApplInfo(network,PART_NETWORK_APPL_KEY,
(Ntk_ApplInfoFreeFn)Part_PartitionFreeCallback,
(void *)simPart);
spfdCreatedPart = 1; /* Using new partition */
(void) fprintf(vis_stdout,
"** spfd info: A new partition created.\n");
}
/* Start the timer.*/
if (timeOutPeriod > 0){
(void) signal(SIGALRM, (void(*)(int))TimeOutHandle);
(void) alarm(timeOutPeriod);
if (setjmp(timeOutEnv) > 0) {
(void) fprintf(vis_stderr, "** spfd warning: Timeout occurred after ");
(void) fprintf(vis_stderr, "%ld seconds.\n", timeOutPeriod);
alarm(0);
goto endgame;
}
}
initialTime = util_cpu_time();
if (!spfdPerfSim) {
(void) fprintf(vis_stdout,
"** spfd info: Simulation vectors not specified.\n");
if (spfdSortNodes == MAXSWCAP) {
(void) fprintf(vis_stdout,
"** spfd info: Using method -S 2 instead of -S 1\n");
spfdSortNodes = MAXFANOUT;
} else if (spfdSortNodes == MINSWCAP) {
(void) fprintf(vis_stdout,
"** spfd info: Using method -S 4 instead of -S 3\n");
spfdSortNodes = MINFANOUT;
}
}
status = SpfdNetworkOptimize(network,simFile,percent,frequency,regionDepth);
finalTime = util_cpu_time();
if(status) {
(void) fprintf(vis_stdout, "%-20s%10ld\n", "** spfd info: analysis time =",
(finalTime-initialTime)/1000);
}
else {
(void) fprintf(vis_stdout, "** spfd error: Optimization failed.\n");
}
if (writeFile) {
SpfdNetworkWriteBlifFile(network,writeFile);
FREE(writeFile);
}
if (simFile)
FREE(simFile);
if (spfdCreatedPart)
Ntk_NetworkFreeApplInfo(network,PART_NETWORK_APPL_KEY);
alarm(0);
return 0; /* normal exit */
endgame:
/* Clean up */
if (simFile)
FREE(simFile);
if (writeFile)
FREE(writeFile);
if (spfdCreatedPart)
Ntk_NetworkFreeApplInfo(network,PART_NETWORK_APPL_KEY);
return 1; /* Error exit */
usage:
(void) fprintf(vis_stderr, "\nusage: Also see \'help spfd_pilo\' for more details.\n\n");
(void) fprintf(vis_stderr, " -a \t\t should be between 0.0 and 1.0\n");
(void) fprintf(vis_stderr, " \t\talpha*(SA*numFanout) + (1.0-alpha)*top_depth is used\n");
(void) fprintf(vis_stderr, " \t\tto order nodes during SPFD computation.\n");
(void) fprintf(vis_stderr, " \t\tSA is the switching activity of the node.\n");
(void) fprintf(vis_stderr, " \t\tThe default value is 0.5.\n\n");
(void) fprintf(vis_stderr, " -D \t\tCollect nodes that are within the specified depth.\n");
(void) fprintf(vis_stderr, " \t\tfrom the node being optimized.\n");
(void) fprintf(vis_stderr, " \t\tThe default is 1.\n\n");
(void) fprintf(vis_stderr, " -f \tFile containing simulation vectors.\n");
(void) fprintf(vis_stderr, " \t\tSee help for the format.\n\n");
(void) fprintf(vis_stderr, " -h \t\tCommand usage.\n\n");
(void) fprintf(vis_stderr, " -i \t\tPerform internal simulations after \n");
(void) fprintf(vis_stderr, " \t\tevery iterations.\n");
(void) fprintf(vis_stderr, " \t\tDefault is 5.\n\n");
(void) fprintf(vis_stderr, " -m \t\tHeuristics to optimize a selected node:\n");
(void) fprintf(vis_stderr, " \t\t0: Reduce the selected node's support.\n");
(void) fprintf(vis_stderr, " \t\t1: Reprogram the selected node.\n");
(void) fprintf(vis_stderr, " \t\t2: Reprogram the selected node's fanin nodes. (default)\n");
(void) fprintf(vis_stderr, " \t\t3: Reduce the selected node's fanout wires.\n\n");
(void) fprintf(vis_stderr, " -p \tPercent of total pattern vectors that\n");
(void) fprintf(vis_stderr, " \t\tshould be used during internal simulations.\n");
(void) fprintf(vis_stderr, " \t\tDefault is 10%%.\n\n");
(void) fprintf(vis_stderr, " -r \t\tDo not reprogram internal nodes if the network\n");
(void) fprintf(vis_stderr, " \t\thas not changed structurally.\n");
(void) fprintf(vis_stderr, " \t\tBy default, reprogram.\n\n");
(void) fprintf(vis_stderr, " -S \t\tHeuristic to select nodes for optimization.\n");
(void) fprintf(vis_stderr, " \t\t0. Random node. (default) \n");
(void) fprintf(vis_stderr, " \t\t1. Node with max. SA*numFanout.\n");
(void) fprintf(vis_stderr, " \t\t2. Node with max. fanout.\n");
(void) fprintf(vis_stderr, " \t\t3. Node with min. SA*numFanout.\n");
(void) fprintf(vis_stderr, " \t\t4. Node with min. fanout.\n\n");
(void) fprintf(vis_stderr, " -t \t\tTime (s) limit for the command.\n\n");
(void) fprintf(vis_stderr, " -v \t\tVerbosity level.\n\n");
(void) fprintf(vis_stderr, " -w \tFile to output final optimized circuit.\n\n");
(void) fprintf(vis_stderr, "set options: \n");
(void) fprintf(vis_stderr, "\tspfd_repl_rem \n");
(void) fprintf(vis_stderr, "\t\tReplace and remove wires simultaneously?\n");
return 1; /* error exit */
} /* End of CommandSpfdNetworkOptimize */
/**Function********************************************************************
Synopsis [Implements SPFD-based simultaneous placement and logic
optimization command, spfd_pdlo, for combinational circuits mapped
to LUT-based FPGAs.]
CommandName [spfd_pdlo]
CommandSynopsis [Perform SPFD-based simultaneous placement and
logic optimization.]
CommandArguments [\[-D <depth>\] \[-h\] \[-n <file>\]
\[-r\] \[-t <sec>\] \[-v <n>\] \[-w <file>\]
net_file arch_file place_file route_file]
CommandDescription [This command performs SPFD-based combined logic
and placement optimization of combinational circuits mapped to
LUT-based FPGAs to improve circuit area and speed. The
flexibilities in the circuit are represented by SPFDs. The
following references explain in detail the theory behind SPFDs.
S. Yamashita, H. Sawada, and A. Nagoya. A new method to express
functional permissibilities for LUT based FPGAs and its
applications. In International Conference on Computer Aided Design,
pages 254-261, 1996.
Subarnarekha Sinha and Robert K. Brayton. Implementation and use of
SPFDs in optimizaing Boolean networks. In International Conference
on Computer Aided Design, 1998.
The command implements a technique that tightly links the logic
and placement optimization steps. The algorithm is based on
simulated annealing. Two types of moves, directed towards global
reduction in the cost function (total wire length), are accepted by
the simulated annealing algorithm: (1) wire removal/replacement,
and (2) swapping of a pair of blocks in the FPGA. Feedback from
placement is valuable in making an informed choice of a target wire
during logic optimization moves. The logic optimization steps
performed are similar to those of spfd_pilo, except that the
placement information is now used instead of the fanout count.
More information on this technique can be found in :
Balakrishna Kumthekar and Fabio Somenzi. Power and delay reduction
via simultaneous logic and placement optimization in FPGAs. In Design,
Automation and Test in Europe, 2000.
The command produces a placement file which is used by VPR for
routing.
This command can be used only if VIS is linked with VPR 4.22
(Versatile Place and Route), the FPGA place and route tool VPR,
from the University of Toronto. Please follow the instructions
provided in the release notes to use VPR with VIS. You can also
contact kumtheka@avanticorp.com if you need more help.
Before calling this command a network should be created for the
design (use flatten_hierarchy) and MDD ids for every node in the
network should be created (static_order -o all -n append). Dynamic
variable ordering (dvo -e sift) can be enabled to reduce BDD sizes.
Command options:
- -D <depth>
- A cluster is computed which includes nodes within the specified
'depth'. The default value is 1.
- -n <file>
- File to output the optimized circuit in VPR's .net format.
- -r
- Do not reprogram LUTs if no structural changes have been
performed with in the cluster, i.e., if no nodes or wires have been
removed do not change the local implementation of LUTs even if
alternate implementations are availabe from SPFD information. The
default is to reprogram.
- -t <sec>
- Time in seconds allowed to complete the command. If the
computation time goes above that limit, the process is is aborted.
The default is no limit.
- -v <n>
- Verbosity level.
- -w <file>
- File to output final optimized circuit.
The following is needed by VPR:
- net_file
- The description of the circuit in the .net format. Logic
optimization uses the circuit described in .BLIF format whereas VPR
needs the same circuit described in .net format. VPack (which comes
with VPR) converts a .BLIF format into a .net format.
- arch_file
- Architecture description file for FPGAs. More information can be
found in VPR's manual.
- place_file
- File to dump placement information.
- route_file
- File to dump routing information.
Relevant flags to be set by the set command:
- spfd_pdlo_logic_move_freq "r1 m1 r2 m2 ..."
- Perform m1 logic moves whenever the rate of acceptance during
simulated annealing is greater than or equal to r1, and so on. r1,
r2, r3 ... should be monotonically decreasing, else the results would
be unpredictable. 0 <= ri <= 1.0. For example:
set spfd_pdlo_logic_move_freq "0.8 0 0.5 5 0.2 10"
In the above logic schedule, zero logic moves per temperature will
be performed when the rate of acceptance is above 0.8, 5 logic
moves between 0.8 and 0.5, 10 moves between 0.5 and 0.2. As no
value is specified for acceptance rate close to 0.0, by default, 1
logic move per temperature will be performed. In this example it
will be 1 logic move between 0.2 and 0.0.
The quotes around the schedule are necessary.
- spfd_repl_rem
- If no, the logic optimization performs only wire
removal. If yes, both wire replacement and removal are performed.
- spfd_pdlo_timing
- If set, use timing driven method to remove or replace wires on the
critical path. If not set, use bounding box of the wires as the
cost function.
- spfd_pdlo_timing_nodeorwire
- Remove/replace all the wires belonging to the most critical
net. If not set, attempt to remove/replace only the most critical
wire.
- spfd_pdlo_out_crit_nets_first
- Output the circuit in VPR's .net format with the nets
appearing in the increasing order of their slack. If not set, the
initial net order specified in the original circuit's .net file is
used. The file is specified with
-n
option. This
variable is valid only if spfd_pdlo_timing is set.
- spfd_pdlo_remap_clb_array
- During logic optimization, due to the removal of nodes in the
network, the current size of FPGA might be bigger than it is
necessary. In such cases, if this variable is set, the size of the
FPGA is reduced to fit the current logic network.
Relevant flags that are options to VPR:
For detailed information on the following options please refer to
the manual that accompanies VPR source distribution.
- vpr_nodisp
- vpr_fix_pins
- vpr_nx
- vpr_ny
- vpr_fast
- vpr_init_t
- vpr_alpha_t
- vpr_exit_t
- vpr_inner_num
- vpr_seet
- vpr_place_cost_exp
- vpr_place_chan_width
]
SideEffects [The network is changed to reflect the wires/nodes
removed or replaced. The internal function of the nodes is also
changed. The partition attached to the network is changed
accordingly.]
******************************************************************************/
static int
CommandSpfdPlaceOptimize(
Hrc_Manager_t **hmgr,
int argc,
char **argv)
{
#ifndef USE_VPR
(void) fprintf(vis_stdout,"** spfd info: This command requires VPR "
"(Versatile Place and Route)\n");
(void) fprintf(vis_stdout,"** spfd info: See \'help spfd_pdlo\' for more "
"information\n");
(void) fprintf(vis_stdout,"** spfd info: on how to compile VIS with VPR.\n");
(void) fprintf(vis_stdout,"** spfd info: Exiting calmly ...\n");
return 0;
#else
Ntk_Network_t *network;
graph_t *simPart;
int status,regionDepth;
int c;
long timeOutPeriod,initialTime,finalTime;
char *writeFile;
char *netFile,*archFile,*placeFile,*routeFile;
char *netOutFile;
FILE *fp = NIL(FILE);
/* These are the default values. */
spfdCreatedPart = 0; /* Do not create a new partition */
timeOutPeriod = 0;
spfdVerbose = 0; /* verbosity */
regionDepth = 1; /* Depth of cluster */
writeFile = NIL(char); /* File to output final optimized ckt. */
spfdNtkChanged = FALSE;
spfdReprogNoWire = TRUE;
netFile = archFile = NIL(char); /* Circuit specified in VPR's .net
format and FPGA architecture file */
placeFile = routeFile = NIL(char); /* File to store placement and
routing information */
spfdWiresAdded = 0;
spfdNumWiresRem = 0;
netOutFile = NIL(char); /* File to output the optimized circuit in
.net format */
status = FALSE;
if (bdd_get_package_name() != CUDD) {
(void) fprintf(vis_stderr,
"** spfd error: The spfd package can be used "
"only with CUDD package\n");
(void) fprintf(vis_stderr,
"** spfd error: Please link with CUDD package\n");
return 0;
}
util_getopt_reset();
while((c = util_getopt(argc, argv, "D:hn:rt:v:w:")) != EOF) {
switch(c) {
case 'D':
regionDepth = atoi(util_optarg);
break;
case 'h':
goto usage;
case 'n':
netOutFile = util_strsav(util_optarg);
break;
case 'r':
spfdReprogNoWire = FALSE;
break;
case 't':
timeOutPeriod = atoi(util_optarg);
break;
case 'v':
spfdVerbose = atoi(util_optarg);
break;
case 'w':
writeFile = util_strsav(util_optarg);
if ((fp = Cmd_FileOpen(writeFile,"w",NIL(char *),1)) == NIL(FILE)) {
(void) fprintf(vis_stderr,
"** spfd error: Could not open %s for writing.\n",
writeFile);
goto endgame;
} else {
fclose(fp);
}
break;
default:
goto usage;
}
}
/* netFile, archFile, and placeFile are essential. The user can
specify /dev/null for routeFile if they don't want to store the
routing information */
if (argc < 5 || argc < util_optind+4)
goto usage;
/* Get the net, architecture, place and route file names */
netFile = argv[util_optind];
archFile = argv[util_optind+1];
placeFile = argv[util_optind+2];
routeFile = argv[util_optind+3];
if(Hrc_ManagerReadCurrentNode(*hmgr) == NIL(Hrc_Node_t)) {
(void) fprintf(vis_stderr,"** spfd error: The hierarchy manager is empty. "
"Read in design.\n");
goto endgame;
}
network = (Ntk_Network_t *)
Hrc_NodeReadApplInfo(Hrc_ManagerReadCurrentNode(*hmgr),
NTK_HRC_NODE_APPL_KEY);
if(network == NIL(Ntk_Network_t)) {
(void) fprintf(vis_stderr,"** spfd error: There is no network. ");
(void) fprintf(vis_stderr,"Use flatten_hierarchy.\n");
goto endgame;
}
/* Check if the current network has signals with multiple values. */
if (TestIsNetworkMultipleValued(network)) {
(void) fprintf(vis_stderr,"** spfd error: Circuit has multiple "
"valued variables.\n");
(void) fprintf(vis_stderr,"** spfd error: The algorithm applies "
"to Boolean variables only.\n");
goto endgame;
}
if(Ntk_NetworkReadNumPrimaryInputs(network) !=
Ntk_NetworkReadNumInputs(network)) {
(void) fprintf(vis_stderr,"** spfd error: Pseudo inputs present "
"in the network.\n");
(void) fprintf(vis_stderr,"** spfd error: The algorithm does not apply.\n");
goto endgame;
}
/* Access a 'total' partition */
simPart = (graph_t *) Ntk_NetworkReadApplInfo(network,
PART_NETWORK_APPL_KEY);
if (simPart == NIL(graph_t) ||
(Part_PartitionReadMethod(simPart) != Part_Total_c)) {
simPart = Part_NetworkCreatePartition(network,
NIL(Hrc_Node_t),
"dummy", (lsList) 0,
(lsList) 0, NIL(mdd_t),
Part_Total_c,
(lsList) 0,
FALSE, FALSE, TRUE);
if (simPart == NIL(graph_t)) {
(void) fprintf(vis_stderr,"** spfd error: Could not create partition.\n");
goto endgame;
}
Ntk_NetworkAddApplInfo(network,PART_NETWORK_APPL_KEY,
(Ntk_ApplInfoFreeFn)Part_PartitionFreeCallback,
(void *)simPart);
spfdCreatedPart = 1; /* Using new partition */
(void) fprintf(vis_stdout,
"** spfd info: A new partition created.\n");
}
/* Start the timer.*/
if (timeOutPeriod > 0){
(void) signal(SIGALRM, (void(*)(int))TimeOutHandle);
(void) alarm(timeOutPeriod);
if (setjmp(timeOutEnv) > 0) {
(void) fprintf(vis_stderr, "** spfd warning: Timeout occurred after ");
(void) fprintf(vis_stderr, "%ld seconds.\n", timeOutPeriod);
alarm(0);
goto endgame;
}
}
initialTime = util_cpu_time();
/* Call the optimization routine. */
status = SpfdSimultaneousPlacementAndLogicOpt(network,netFile,archFile,
placeFile,routeFile,netOutFile,
regionDepth);
finalTime = util_cpu_time();
if(status) {
(void) fprintf(vis_stdout, "%-20s%10ld\n", "** spfd info: analysis time =",
(finalTime-initialTime)/1000);
}
else {
(void) fprintf(vis_stdout, "** spfd error: Optimization failed.\n");
}
if (writeFile) {
SpfdNetworkWriteBlifFile(network,writeFile);
FREE(writeFile);
}
if (netOutFile) {
FREE(netOutFile);
}
if (spfdCreatedPart)
Ntk_NetworkFreeApplInfo(network,PART_NETWORK_APPL_KEY);
alarm(0);
return 0; /* normal exit */
endgame:
/* Clean up */
if (writeFile)
FREE(writeFile);
if (netOutFile) {
FREE(netOutFile);
}
if (spfdCreatedPart)
Ntk_NetworkFreeApplInfo(network,PART_NETWORK_APPL_KEY);
return 1; /* Error exit */
usage:
(void) fprintf(vis_stderr, "\nusage: Also see \'help spfd_pdlo\' for more details.\n\n");
(void) fprintf(vis_stderr, "spfd_pdlo [options] net_file arch_file place_file route_file\n\n");
(void) fprintf(vis_stderr, " -D \t\tConsider region upto .\n\n");
(void) fprintf(vis_stderr, " -h \t\tCommand usage.\n\n");
(void) fprintf(vis_stderr, " -n \tFile to output optimized\n");
(void) fprintf(vis_stderr, " \t\tcircuit in .net format.\n\n");
(void) fprintf(vis_stderr, " -r \t\tDo not reprogram internal nodes if there are no\n");
(void) fprintf(vis_stderr, " \t\tstructural changes in the network.\n\n");
(void) fprintf(vis_stderr, " -t \t\tTime (s) limit for the command.\n\n");
(void) fprintf(vis_stderr, " -v \t\tVerbosity level.\n\n");
(void) fprintf(vis_stderr, " -w \tFile to output final optimized circuit.\n\n");
(void) fprintf(vis_stderr, "set options: \n");
(void) fprintf(vis_stderr, "\tspfd_pdlo_logic_move_freq \"r1 m1 r2 m2 ...\"\n");
(void) fprintf(vis_stderr, "\t\tPerform m1 logic moves per temperature whenever the rate\n");
(void) fprintf(vis_stderr, "\t\tof acceptance during simulated annealing is greater than\n");
(void) fprintf(vis_stderr, "\t\tor equal to r1, and so on. r1 > r2 > r3 ... \n");
(void) fprintf(vis_stderr, "\t\tand 0 <= ri <= 1.0.\n\n");
(void) fprintf(vis_stderr, "\tspfd_repl_rem \n");
(void) fprintf(vis_stderr, "\t\tPerform both wire replacement and removal?\n\n");
(void) fprintf(vis_stderr, "\tspfd_pdlo_timing\n");
(void) fprintf(vis_stderr, "\t\tUse timing driven method.\n");
(void) fprintf(vis_stderr, "\t\tIf not set, Bounding box method is used.\n\n");
(void) fprintf(vis_stderr, "\tspfd_pdlo_timing_nodeorwire\n");
(void) fprintf(vis_stderr, "\t\tProcess the fanouts of the most tcritical node. If not set,\n");
(void) fprintf(vis_stderr, "\t\tprocess only the wires on the critical path.\n\n");
(void) fprintf(vis_stderr, "\tspfd_pdlo_out_crit_nets_first\n");
(void) fprintf(vis_stderr, "\t\tOutput the circuit in VPR\'s .net format with\n");
(void) fprintf(vis_stderr, "\t\tnets appearing in the increasing order of their slack.\n");
(void) fprintf(vis_stderr, "\t\tIf not set, the initial net order specified in the original\n");
(void) fprintf(vis_stderr, "\t\tcircuit\'s .net file is used. The file specified in -n option\n");
(void) fprintf(vis_stderr, "\t\tis used. This option is valid only if spfd_pdlo_timing is set.\n\n");
(void) fprintf(vis_stderr, "\tspfd_pdlo_remap_clb_array\n");
(void) fprintf(vis_stderr, "\t\tReduce the size of FPGA if necessary during\n");
(void) fprintf(vis_stderr, "\t\tlogic optimization.\n\n");
(void) fprintf(vis_stderr, "set options for VPR: Please see VPR's manual for more information.\n");
(void) fprintf(vis_stderr, " vpr_nodisp\n");
(void) fprintf(vis_stderr, " vpr_fix_pins\n");
(void) fprintf(vis_stderr, " vpr_nx\n");
(void) fprintf(vis_stderr, " vpr_ny\n");
(void) fprintf(vis_stderr, " vpr_fast\n");
(void) fprintf(vis_stderr, " vpr_init_t\n");
(void) fprintf(vis_stderr, " vpr_alpha_t \n");
(void) fprintf(vis_stderr, " vpr_exit_t\n");
(void) fprintf(vis_stderr, " vpr_inner_num\n");
(void) fprintf(vis_stderr, " vpr_seed\n");
(void) fprintf(vis_stderr, " vpr_place_cost_exp\n");
(void) fprintf(vis_stderr, " vpr_place_chan_width\n");
return 1; /* error exit */
#endif /* ifdef USE_VPR */
} /* End of CommandSpfdPlaceOptimize */
/**Function********************************************************************
Synopsis [Handle function for timeout.]
Description [This function is called when the time out occurs.]
SideEffects []
******************************************************************************/
static void
TimeOutHandle(void)
{
longjmp(timeOutEnv, 1);
}
/**Function********************************************************************
Synopsis [Checks whether the network has multiple valued signals.]
Description [Checks whether the network has multiple valued
signals. Returns 1 if true, else 0.]
SideEffects [None]
SeeAlso []
******************************************************************************/
static int
TestIsNetworkMultipleValued(Ntk_Network_t *network)
{
Ntk_Node_t *node;
lsGen gen;
Var_Variable_t *var;
int numValues;
Ntk_NetworkForEachNode(network,gen,node) {
var = Ntk_NodeReadVariable(node);
numValues = Var_VariableReadNumValues(var);
if (numValues > 2)
return 1;
}
return 0;
}
#ifndef USE_VPR
/**Function********************************************************************
Synopsis [Dummy function]
SideEffects [None]
******************************************************************************/
static int
SpfdSimultaneousPlacementAndLogicOpt(
Ntk_Network_t *network,
char *netFile,
char *archFile,
char *placeFile,
char *routeFile,
char *netOutFile,
int regionDepth)
{
return 0;
}
#endif