/*
* $Id: partition.c,v 1.1.1.1 2003/11/04 23:34:57 mjames Exp $
*
* $Log: partition.c,v $
* Revision 1.1.1.1 2003/11/04 23:34:57 mjames
* Imported into local repositrory
*
* Revision 1.15 2003/01/02 21:37:16 mjames
* Experiment on creating NOT_ROUTABLE_H and NOT_ROUTABLE_L
* properties on the nets so that pin jumpers can be made without a problem.
*
* Still need to sort out pin assignments made to these not_routable nets
* which will become legal in some cases so that pullups and pulldown
* pins can be used on the FPGA.
*
* Revision 1.14 2002/09/30 13:20:29 MJAMES
* Modified partition rules to include 'default assignment on declaration'
* which maps to inputs being driven with default values on
* productuion of a partition.
*
* signal c : std_logic := '0';
*
* becomes
*
* signal c: std_logic;
*
* begin
* c<= '0';
*
* Revision 1.13 2002/09/18 08:51:24 mjames
* Removed unused variables
*
* Revision 1.12 2002/09/09 10:13:09 mjames
* Moved pin remapping function to pin ident editing function from
* sorting pin name routine.
*
* Revision 1.11 2002/01/16 11:22:47 mjames
* database.h header file is read in first as it undefined DLL stuff irrelevant
* to HPUX
*
* Revision 1.10 2001/12/13 22:17:28 mjames
* Using #ident with header to identify file
*
* removed debug messages
*
* Revision 1.9 2001/10/31 22:20:11 mjames
* Tidying up problematical comments caused by CVS
* 'intelligent' comment guessing
*
* Revision 1.8 2001/10/31 16:21:46 mjames
* Added a datastructure to hide regular expression information from programs.
* Changed call to regexec to indicate 0 subexpressions to be matched
* rather than a number dependent on strlen(string) which was wrong.
* Altered diagnostics while debugging checked in because useful at other
* times
*
* Revision 1.7 2001/10/10 20:18:23 mjames
* Added a vert_regcomp function to compile regular expressions
* with '^' (match start string) and '$' (match end string) bracketing
* this => wildcard must match entire string not just a part of it.
*
* Revision 1.6 2001/10/07 20:50:53 mjames
* Added wildcard checking (warn user about
* using wildcard '*' on the end of a string in stead of wildcard '.*')
*
* Revision 1.5 2001/09/25 23:24:18 mjames
* Update because wildcard behaviour amended
*
* Revision 1.4 2001/08/01 07:38:03 mjames
* Removed multiple informational messages
* replaced with summary unless debug level is higher
*
* Revision 1.3 2001/06/06 12:10:19 mjames
* Move from HPUX
*
* Revision 1.2 2000/11/29 21:51:18 mjames
* Fine tuning of software
*
* Revision 1.1.1.1 2000/10/19 21:58:38 mjames
* Mike put it here
*
*
* Revision 1.36 2000/10/12 15:32:31 15:32:31 mjames (Mike James)
* Removed <cr>
*
* Revision 1.35 2000/10/12 14:25:49 14:25:49 mjames (Mike James)
* removed <cr>
*
* Revision 1.34 2000/10/04 10:37:07 10:37:07 mjames (Mike James)
* Modified for Vertical2 : support COMPONENTS and SIGNALS
*
* Revision 1.34 2000/10/04 10:37:07 10:37:07 mjames (Mike James)
* Part of Release PSAVAT01
*
* Revision 1.33 2000/10/03 10:05:31 10:05:31 mjames (Mike James)
* Added CONSTANTS and SIGNALS to architecture
*
* Revision 1.31 2000/09/27 14:42:17 14:42:17 mjames (Mike James)
* Part of Release Sep_27_ST_2000
*
* Revision 1.30 2000/09/21 10:15:48 10:15:48 mjames (Mike James)
* Part of Release Sep21Alpha
*
* Revision 1.29 2000/08/25 09:57:13 09:57:13 mjames (Mike James)
* Part of Release Aug25_alpha
*
* Revision 1.28 2000/08/16 08:57:30 08:57:30 mjames (Mike James)
* Part of Release CD01_Aug2000
*
* Revision 1.27 2000/08/14 14:45:11 14:45:11 mjames (Mike James)
* Part of Release Aug_14_2000
*
* Revision 1.26 2000/08/11 08:30:32 08:30:32 mjames (Mike James)
* Part of Release Aug_11_2000
*
* Revision 1.25 2000/08/09 10:31:46 10:31:46 mjames (Mike James)
* Part of Release Aug__9_2000
*
* Revision 1.24 2000/05/31 11:42:56 11:42:56 mjames (Mike James)
* Part of Release May_31_2000
*
* Revision 1.23 2000/05/31 11:30:18 11:30:18 mjames (Mike James)
* Added acfread.ini file reading
*
* Revision 1.22 2000/05/08 17:01:37 17:01:37 mjames (Mike James)
* Part of Release May__8_2000
*
* Revision 1.21 2000/05/08 16:59:30 16:59:30 mjames (Mike James)
* Part of Release May__8_2000
*
* Revision 1.20 2000/05/08 16:57:07 16:57:07 mjames (Mike James)
* Part of Release May__8_2000
*
* Revision 1.19 2000/03/08 16:19:20 16:19:20 mjames (Mike James)
* New version including PC
*
* Revision 1.16 2000/01/20 15:58:47 15:58:47 mjames (Mike James)
* Part of Release R22
*
* Revision 1.15 99/12/22 11:15:27 11:15:27 mjames (Mike James)
* Part of Release Dec_22_1999
*
* Revision 1.14 99/11/23 13:52:12 13:52:12 mjames (Mike James)
* Addded syntax to support special generics for Certify support
*
* Revision 1.13 99/06/25 14:35:46 14:35:46 mjames (Mike James)
* Added in reference to expression.h, but no changes made
* to the function of acfread yet.
*
* Revision 1.12 99/06/18 09:25:37 09:25:37 mjames (Mike James)
* Added generics exported upwards
*
* Revision 1.11 98/10/01 15:25:30 15:25:30 mjames (Mike James)
* Added templates (name*) or * to set/del port
*
* Revision 1.10 98/04/24 13:49:07 13:49:07 mjames (Mike James)
* Added extra force_port flag to net for 'set port' command
*
* Revision 1.9 98/02/11 11:26:53 11:26:53 mjames (Mike James)
* Checked in for version 6.2a
*
* Revision 1.8 97/04/23 08:43:20 08:43:20 mjames (Mike James)
* CHecked in for release rel23041997
*
* Revision 1.7 96/12/23 15:15:51 15:15:51 mjames (Mike James)
* Altered because find_socket takes a reference
* to the head-of-list-pointer noth the pointer itself.
*
* Revision 1.6 96/07/19 14:38:47 14:38:47 mjames (Mike James)
* Update to give to PRL
*
* Revision 1.5 1996/05/23 10:32:26 mjames
* Altered BUFFER and OUT pin rules to decide whether a
* signal crosses a partition boundary.
*
* Revision 1.4 96/05/21 14:16:07 14:16:07 mjames (Mike James)
* Added the concept ogf buffered pins to get some Shoamra2
* partitions to work properly.
*
* Revision 1.3 96/04/26 16:01:55 16:01:55 mjames (Mike James)
* Altered inside/outside determination of signal directions
*
* Revision 1.2 96/04/15 14:19:31 14:19:31 mjames (Mike James)
* Checkin before datatype printing
*
* Revision 1.1 96/03/29 14:46:13 14:46:13 mjames (Mike James)
* Initial revision
*
* */
/* The Partition module. This combines VHDL for the purposes of creating
EPLDs */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <regex.h>
#include "vertcl_main.h"
#include "expression.h"
#include "generic.h"
#include "database.h"
#include "partition.h"
#include "cmdparse.h"
#include "cmdlog.h"
#include "acf_yacc.h"
#include "vertcl_main.h"
#include "chck_names.h"
#include "sorting.h"
#include "routing.h"
#ident "@(#)$Header: c:\\cygwin\\cvsroot/Vert03/vertlib/partition.c,v 1.1.1.1 2003/11/04 23:34:57 mjames Exp $"
/* nets created as a result of partition are ripped up when a new partition
is created */
void clear_partition_nets(void)
{
net_t * net = named_list; /* only interested in nets carrying a signal */
while(net){
net->leaves_partition = 0; /* not leaving partition */
net->inside_partition = 0; /* not used inside partition */
#if defined BLOB
if(!net->type_defined && net->vhdltype) {
if(net->vhdltype->basetype) {
/* ought to free it */
free(net
->vhdltype
->basetype
);
net->vhdltype->basetype = NULL;
}
if(net->vhdltype->expr) {
net->vhdltype = NULL;
free_expression(net->vhdltype->expr);
}
}
#endif
net = net->next;
}
}
/* all nets that are in the routed list are named and placed in the named list */
void name_routed_nets(void)
{
net_t * link;
net_t * net = routed_list; /* check each net in turn */
/* this code is here : shoould it be ? */
while(net) {
noderef_t * noderefs = net->nodes;
link = net->next;
if(IS_ROUTABLE(noderefs->net->how_routed)) {
if (ISNULLSTR(net->name))
net->name = net->identifier;
while(noderefs){
/* noderefs->node->in_use = 1; */
noderefs->node->name = net->name;
noderefs = noderefs->next;
}
combine_routed_and_unrouted (net, net);
transfer_net_to_named (&routed_list, net);
}
net = link;
}
}
int set_clear_partition(char * expr,int set_clear)
{
int rc;
socket_t * skt = socket_head;
int found = 0;
int process_count = 0;
/* compile regular expression */
vert_regex_t * preg;
rc = vert_regcomp(&preg,expr);
if (rc != 0 )
{
char errbuff[100];
regerror(rc,preg->preg,errbuff,100);
Log(LOG_ERROR,"-- Problem (rc=%d) %s with '%s' as regular expression\n",rc,errbuff,expr);
return /*TCL_ERROR*/;
}
else
{
Log(LOG_GENERAL,"-- Using '%s' as match pattern\n",expr);
}
while(skt) {
found = regexec(preg->preg,skt->identifier,0,preg->regpatt,0);
if(!found)
{
if (skt && ISNULLSTR(skt->name))
{
skt->name = skt->identifier;
}
skt->selected = set_clear;
process_count++;
}
skt = skt->next;
}
vert_regfree(&preg);
Log(LOG_GENERAL,"-- Processed %d sockets\n",process_count++);
return OKCMD;
}
int add_all_to_partition(void)
{
return set_clear_partition(".*",1);
}
/* printout the sockets that are selected inside the partition */
void list_partition(FILE * f)
{
socket_t * skt = socket_head;
fprintf(f
,"Partition includes the following blocks:\n");
while(skt){
if(skt->selected) /* selected */
skt = skt->next;
}
}
/* the partitioning algorithm is implemented here */
/*
for each net on the named list -- Made it to routing
if the only nodes on the list that are 'in use' only connect
to 'selected' sockets and there is an output or buffer pin inside the then the net is inside the partition.
if the net is all inputs the the net has to leave the
partition as an input.
*/
void perform_partition(void)
{
net_t * net = named_list; /* check each net in turn */
int ports = 0;
int port_wires = 0;
int signals = 0;
int signal_wires = 0;
while(net) {
noderef_t * noderefs = net->nodes;
char used_outside = 0; /* set if the net goes outside */
char used_inside = 0; /* set if the net used inside */
char inputs_on_net = 0;
char outputs_on_net = 0;
char buffers_on_net = 0; /* another pin type that we must handle */
char bidirs_on_net = 0;
char default_drive = 0; /* Was this net defined with a default value ? */
int width = 0; /* how many wires in the bundle */
int high = 0;
int low = 1000;
expression_t
* exp,* variable_seen
,
*high_ref, * low_ref, * high_exp, *low_exp, * highest_exp, * lowest_exp ;
highest_exp = NULL;
lowest_exp = NULL;
high_ref = NULL; /* reference to expression containing highest expr */
low_ref = NULL;
variable_seen = NULL;
net->ext_dir = NONE; /* not yet known */
/* set flag if the net was defined as "signal x : type := value;" */
default_drive = net->type_defined && net->vhdltype && net->vhdltype->default_expr;
/* predefined net type definition, can already know upper ansd lower bounds */
#if defined DEBUG_EXPRESSION
printf("net %s \n",net
->identifier
);
#endif
while(noderefs){
node_t * n = noderefs->node;
if(n->in_use) {
int h,l;
vhdl_t * vhdl;
vhdl = noderefs->vhdltype;
if(vhdl && vhdl->expr)
else
#if defined DEBUG_EXPRESSION
print_range_expression
(stdout
,exp,0);
}
#endif
/* if we have a variable defining width,
remember what the top level variable is called,
then keep expanding it until we get an expression
rather than a variable */
if(exp && exp
->opcode
== EXP_VARIABLE
) {
while(exp->opcode == EXP_VARIABLE)
}
if (exp->opcode == TO) {
high_exp = exp->right.e;
low_exp = exp->left.e;
}
else if (exp->opcode == DOWNTO) {
high_exp = exp->left.e;
low_exp = exp->right.e;
}
else
high_exp
= low_exp
= exp; /* not a range, just a single value */
l = eval_expression(low_exp, NULL);
h = eval_expression(high_exp, NULL);
/* sort out the highest and lowest bound of any logic vector pins
on the net (high and low are zero for single bits so calculation
applies here) */
if (h > high) {
highest_exp = high_exp;
high = h;
}
if (l < low){
lowest_exp = low_exp;
low = l;
}
}
else {
high=0;
low=0;
};
/* discover it is routed outside - it links to an unselected socket */
/* but if it only links to unselected sockets,
used_inside wont be set as well */
if(!n->socket->selected)
used_outside = 1;
else{
used_inside = 1;
if (noderefs->pindir == INPUT)
inputs_on_net = 1;
if (noderefs->pindir == OUTPUT)
outputs_on_net = 1;
if (noderefs->pindir == BIDIR)
bidirs_on_net = 1;
if (noderefs->pindir == BUFFER)
buffers_on_net = 1;
/* I was using the ordinal value of the pindir_t type
if (noderefs->pindir >= net->ext_dir ) || */
/* now June 1999 takes on the type of the first node ,
or if one of the nodes has a bus connection use that : still a
guess. Alternatively if the net was declared so it has a
type defined then keep that as it is more correct... */
if(!net->type_defined && ( !net->vhdltype || !net->vhdltype->basetype ||
(!net->vhdltype->is_vector && vhdl->is_vector))) {
/* copy over base VHDL type and vector/single signal attribute*/
net->vhdltype = copy_vhdl(vhdl,NULL);
}
}
}
noderefs = noderefs->next;
}
/* nets with a VHDL type will simply use this type as the definition of the expression */
#if defined IGNORE_DEFINED
if(net->type_defined && net->vhdltype ) {
exp = net
->vhdltype
->expr
;
if(exp && exp
->opcode
== EXP_VARIABLE
)
if (exp->opcode == TO) {
highest_exp = exp->right.e;
lowest_exp = exp->left.e;
}
else if (exp->opcode == DOWNTO) {
highest_exp = exp->left.e;
lowest_exp = exp->right.e;
}
else
highest_exp = lowest_exp = exp->left.e;
low = eval_expression(lowest_exp,NULL);
high = eval_expression(highest_exp,NULL);
}
}
#endif
if ( !net->type_defined && net->vhdltype && net->vhdltype->is_vector) {
if(variable_seen)
net->vhdltype->expr = variable_seen;
else if(highest_exp && lowest_exp) {
if (high_ref && (high_ref == low_ref))
net->vhdltype->expr = high_ref;
else
net->vhdltype->expr = compile_expression(DOWNTO,highest_exp,lowest_exp);
}
else
net->vhdltype->expr = compile_constant(0);
}
/* pin will appear on port list if : */
/* routed inside & outside */
net->leaves_partition = (used_inside && used_outside) ||
/* inputs but not any sort of outputs, or default drive (a kind of output) */
(inputs_on_net && !( default_drive || outputs_on_net || buffers_on_net)) ||
/* any sort of outputs but not inputs */
((outputs_on_net || buffers_on_net) && !inputs_on_net) ||
/* any bidirectional pins */
bidirs_on_net ||
/* net is forced as a port */
net->force_port;
net->needs_buff_sig = inputs_on_net &&
(outputs_on_net || buffers_on_net) &&
net->leaves_partition;
/* sort out the pin directions */
/* any bidirectional pins */
if(bidirs_on_net)
net->ext_dir = BIDIR;
/* inputs but not any sort of outputs */
else if(inputs_on_net && !(outputs_on_net || buffers_on_net))
net->ext_dir = INPUT;
/* any sort of outputs but not inputs */
else if (outputs_on_net || buffers_on_net)
net->ext_dir = OUTPUT;
else
net->ext_dir = NONE;
/* net will appear in local signal definition if : */
/* it is used inside */
/* and either only inside or it is a BUFFER
port in which
case a temporary signal is provided by
printout.c */
net->inside_partition = used_inside && (
(!net->leaves_partition) ||
(net->needs_buff_sig));
width = high-low+1;
if(level & 1)
{
printf("Partition : Net %-20s Inside %d Outside %d Crossing Dir %d width %d %c%c%c%c%c\n",
net->name,net->inside_partition,net->leaves_partition,
net->ext_dir,width,
outputs_on_net?'O':'o',
inputs_on_net ?'I':'i',
bidirs_on_net ?'B':'b',
buffers_on_net?'U':'u',
default_drive ?'D':'d');
}
/* compute the bus width unless it is already defined */
if(net->leaves_partition) {
port_wires+= width;
ports++;
};
if(net->inside_partition) {
signal_wires+= width;
signals++;
};
net = net->next;
}
Log(LOG_GENERAL,"-- %5d Nets (%5d wires) leaving partition\n"
"-- %5d Signals (%5d wires) inside partition\n",
ports,port_wires,signals,signal_wires);
}
/* remove a port from the partition as I dont want it outside */
void delete_port(char * template)
{
int rc;
net_t * net = named_list;
int found = 0;
int net_count = 0;
/* compile regular expression */
vert_regex_t * preg;
rc = vert_regcomp(&preg,template);
if (rc != 0 )
{
char errbuff[100];
regerror(rc,preg->preg,errbuff,100);
Log(LOG_ERROR,"-- Problem (rc=%d) %s with '%s' as regular expression\n",rc,errbuff,template);
return /*TCL_ERROR */;
}
Log(LOG_GENERAL,"-- Beginning removing ports : prefix '%s' --\n",template );
while(net)
{
found = regexec(preg->preg,net->name,0,preg->regpatt,0);
if(found && found!=REG_NOMATCH)
{
char errbuff[100];
regerror(found,preg->preg,errbuff,100);
Log(LOG_ERROR,"-- Problem (rc=%d) %s with '%s' as regular expression\n",found,errbuff,template);
}
if (level & 1)
{
Log(LOG_GENERAL,"-- Net '%s'%s",net->name,found?"\n":"");
}
if(!found)
{
if (level & 1)
{
Log(LOG_GENERAL,"inside=%d leaves=%d buffer=%d force_port=%d\n",
net->inside_partition,
net->leaves_partition,
net->needs_buff_sig,
net->force_port);
}
net->force_port = 0;
/* now to delete the port the following is needed to be done */
/* Is it going outside ? If not , forget it */
/* otherwise ensure its used inside, not a port and its not needing a buffer */
if( net->leaves_partition || net->needs_buff_sig )
{
net->leaves_partition = 0;
net->inside_partition = 1;
net->needs_buff_sig = 0;
if (level & 1)
Log(LOG_GENERAL,"-- Removed port '%s' from partion\n",net->name);
net_count++;
}
}
net = net->next;
}
Log(LOG_GENERAL,"-- Removed %d ports from partiton\n",net_count);
Log(LOG_GENERAL,"-- Done removing ports \n");
vert_regfree(&preg);
}
/* force a net to be a port on the partition as I want it outside */
void force_port(char * template)
{
int rc;
net_t * net = named_list;
int found ;
int net_count = 0;
/* compile regular expression */
vert_regex_t * preg;
rc = vert_regcomp(&preg,template);
if (rc != 0 )
{
char errbuff[100];
regerror(rc,preg->preg,errbuff,100);
Log(LOG_ERROR,"-- Problem (rc=%d) %s with '%s' as regular expression\n",rc,errbuff,template);
return /*TCL_ERROR */;
}
Log(LOG_GENERAL,"-- Beginning setting ports : prefix '%s' --\n",template );
while(net) {
found = regexec(preg->preg,net->name,0,preg->regpatt,0);
if(!found) {
if(level &1)
Log(LOG_GENERAL,"-- Set '%s' as a port if it is inside partition\n",net->name);
net->force_port = 1;
net_count++;
}
net = net->next;
}
Log(LOG_GENERAL,"-- Forced %d ports on partion\n",net_count);
Log(LOG_GENERAL,"-- Port forcing done\n");
vert_regfree(&preg);
}