/* $Id: print_vhdl.c,v 1.1.1.1 2003/11/04 23:34:57 mjames Exp $ */
/*
* $Log: print_vhdl.c,v $
* Revision 1.1.1.1 2003/11/04 23:34:57 mjames
* Imported into local repositrory
*
* Revision 1.17 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.16 2002/09/30 13:23:05 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.15 2002/09/27 22:35:33 MJAMES
* Added lhs_expr for cases like
*
* x(0) <= y
*
* where x is std_logic_vector(0 downto 0) and y is std_logic.
*
* Also added printing for default values on signals : this to be extended
*
* Revision 1.14 2002/09/09 10:12:02 mjames
* Moved pin remapping function to pin ident editing function from
* sorting pin name routine.
*
* Revision 1.13 2002/08/23 14:19:19 mjames
* Introduced bundles and external sockets to VHDL from the Verilog printer.
*
* Revision 1.12 2001/12/13 22:18:52 mjames
* Using #ident with header to identify file
*
* Corrected an attempt to reference a null net
*
* Revision 1.11 2001/11/19 10:41:35 mjames
* Merged back DTC release
*
* Revision 1.10.2.1 2001/11/15 22:25:39 mjames
* Removed unused variables, added brackets
*
* Revision 1.10 2001/11/01 11:04:36 mjames
* Pin node identifier is printed out in a component declaration rather than
* node name which is more a property of the attached net.
*
* Revision 1.9 2001/10/31 22:20:12 mjames
* Tidying up problematical comments caused by CVS
* 'intelligent' comment guessing
*
* Revision 1.8 2001/10/10 20:18:22 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.7 2001/09/21 14:22:27 mjames
* Added prefix to instance name in order to avoid a Model Technology name
* space collision e.g.
*
* U1 : U1 port map () ...
*
* Now prints
*
* I_U1 : U1 port map which is safer.
*
* Revision 1.6 2001/06/22 11:06:19 mjames
* Modified to tag VHDL code generated so that
* Vertical can recognise it.
*
* Revision 1.5 2001/06/20 13:45:40 mjames
* For all components defined by 'Component' declarations, forced the
* printout of only one component for several instances sharing the same component declaration.
*
* Revision 1.4 2001/06/06 12:10:19 mjames
* Move from HPUX
*
* Revision 1.3 2001/04/27 08:08:44 mjames
* Extra tidying of the print_vhdl code
*
* Revision 1.2 2000/11/29 21:51:18 mjames
* Fine tuning of software
*
* Revision 1.1.1.1 2000/10/19 21:58:39 mjames
* Mike put it here
*
*
* Revision 1.23 2000/10/12 15:32:32 15:32:32 mjames (Mike James)
* Removed <cr>
*
* Revision 1.22 2000/10/12 14:25:55 14:25:55 mjames (Mike James)
* changed listing vhdl signals to expand expressions
* until a constant is located
*
* Revision 1.21 2000/10/04 10:37:08 10:37:08 mjames (Mike James)
* Modified for Vertical2 : support COMPONENTS and SIGNALS
*
* Revision 1.21 2000/10/04 10:37:08 10:37:08 mjames (Mike James)
* Part of Release PSAVAT01
*
* Revision 1.20 2000/10/02 11:04:17 11:04:17 mjames (Mike James)
* new_vhdl
*
* Revision 1.18 2000/09/21 10:15:48 10:15:48 mjames (Mike James)
* Part of Release Sep21Alpha
*
* Revision 1.17 2000/08/25 09:57:14 09:57:14 mjames (Mike James)
* Part of Release Aug25_alpha
*
* Revision 1.16 2000/08/25 09:55:33 09:55:33 mjames (Mike James)
* Corrected for the disappearance of generic information
*
* Revision 1.15 2000/08/16 08:57:30 08:57:30 mjames (Mike James)
* Part of Release CD01_Aug2000
*
* Revision 1.14 2000/08/14 14:45:11 14:45:11 mjames (Mike James)
* Part of Release Aug_14_2000
*
* Revision 1.13 2000/08/14 14:43:15 14:43:15 mjames (Mike James)
* Added power pins
*
* Revision 1.12 2000/08/11 08:30:32 08:30:32 mjames (Mike James)
* Part of Release Aug_11_2000
*
* Revision 1.11 2000/08/09 10:31:47 10:31:47 mjames (Mike James)
* Part of Release Aug__9_2000
*
* Revision 1.10 2000/05/31 11:42:56 11:42:56 mjames (Mike James)
* Part of Release May_31_2000
*
* Revision 1.9 2000/05/08 17:01:37 17:01:37 mjames (Mike James)
* Part of Release May__8_2000
*
* Revision 1.8 2000/05/08 16:59:30 16:59:30 mjames (Mike James)
* Part of Release May__8_2000
*
* Revision 1.7 2000/05/08 16:57:07 16:57:07 mjames (Mike James)
* Part of Release May__8_2000
*
* Revision 1.6 2000/03/08 16:19:22 16:19:22 mjames (Mike James)
* New version including PC
*
* Revision 1.3 2000/01/20 15:58:47 15:58:47 mjames (Mike James)
* Part of Release R22
*
* Revision 1.2 99/12/22 11:15:28 11:15:28 mjames (Mike James)
* Part of Release Dec_22_1999
*
* Revision 1.1 99/11/23 13:52:14 13:52:14 mjames (Mike James)
* Initial revision
*
*/
#include "print_vhdl.h"
#include "cmdlog.h"
#include "cmdparse.h"
#include "database.h"
#include "expression.h"
#include "generic.h"
#include "print_vlog.h"
#include "printout.h"
#include "sorting.h"
#include "vertcl_main.h"
#include <ctype.h>
#include <regex.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
/* for streq */
#include "lx_support.h"
/* ********************************************************************** */
/* Decoding pin direction in VHDL */
static char *decode_pin_VHDL[] = {"-NONE-",
"IN",
"OUT",
"BUFFER", /* buffer is a sort of Output pin */
"INOUT",
"CONFIG_PIN",
"POWER_PIN"};
/* ********************************************************************** */
/* VHDL output of the entities */
/* ********************************************************************** */
static char illegal[] = "$:|/.\\ ";
static char replace[] = "Sxxxxx_";
char *make_vhdl_name (char *buffer, char *str)
{
int i, j, l;
buffer[0] = 0;
if (str)
{
strcpy (buffer
, str
); /* should be a call to strncpy !! */
}
/* edit out illegal strings from the net name */
for (i = 0; i < l; i++)
{
for (j = 0; j < sizeof (illegal); j++)
if (buffer[i] == illegal[j])
buffer[i] = replace[j];
}
i = l - 1;
/* convert pin indices back from Altera form if we are looking at FIT files */
if (l)
{
/* name ends in underscore, this forces mapping name_nn_ --> name(nn) */
if (buffer[i] == '_')
{
buffer[i--] = ')';
while (i >= 0 && buffer[i] != '_')
i--;
if (i >= 0)
buffer[i] = '(';
}
}
return buffer;
}
/* ********************************************************************** */
/* decodes the 'vector' part of a bus , if known */
void decode_vhdl_bus (FILE *f, vhdl_t *vhdl, generic_print_style recurse_generics)
{
if (!vhdl)
vhdl = default_vhdl_datatype;
if (vhdl->is_vector)
print_range_expression (f, vhdl->expr, recurse_generics);
}
/* ********************************************************************** */
void decode_vhdl_type (FILE *f, vhdl_t *vhdl, generic_print_style recurse_generics)
{
/* avoid crashing on a null pointer */
if (!vhdl)
vhdl = default_vhdl_datatype;
fprintf (f
, "%s ", vhdl
->basetype
);
if (vhdl->is_vector)
decode_vhdl_bus (f, vhdl, recurse_generics);
}
/* ********************************************************************** */
/* print out a VHDL component declaration */
void print_VHDL_component (FILE *f, socket_t *dev, int All)
{
node_t *n;
/* sort the identifiers of the nodes */
sort_nodes (dev, NO_EXTRACT_XY);
fprintf (f
, "COMPONENT %s\n", check_null_str
(dev
->type
));
fprintf (f
, "-- DEV_IDENT \"%s\"\n\n", check_null_str
(dev
->identifier
));
if (dev->is_template)
fprintf (f
, "-- Defined by COMPONENT definition\n");
if (dev->generics)
list_VHDL_generic_values (f, &dev->generics);
/* sort the identifiers of the nodes */
sort_nodes (dev, NO_EXTRACT_XY);
n = dev->nodes;
while (n)
{
vhdl_t *pin_datatype = default_vhdl_datatype;
expression_t *default_expr = NULL;
char nam[MAXIDLEN];
if (n->orig_vhdltype)
{
pin_datatype = n->orig_vhdltype;
default_expr = n->orig_vhdltype->default_expr;
}
else if (n->vhdltype)
{
pin_datatype = n->vhdltype;
default_expr = n->vhdltype->default_expr;
}
if ((n->net_assigned && n->in_use) || (All || dev->is_template))
{
f,
" %-16s : %6s ",
make_vhdl_name (nam, check_null_str (n->identifier)), /* was
n->name */
decode_pin_VHDL[(int) n->pindir]);
decode_vhdl_type (f, pin_datatype, NO_RECURSE); /* until a generic
found */
/* ought to be optional dependent on synthesis style */
if (default_expr)
{
print_expression (f, default_expr, NO_RECURSE);
}
if (n->sktnext)
fprintf (f
, " -- i=%s r=%d --\n", n
->identifier
, n
->refcount
);
}
n = n->sktnext; /* traverse to next pin on socket */
};
fprintf (f
, ");\nEND COMPONENT;\n\n");
}
/* ********************************************************************** */
/* Printout an instance of a component */
/* ********************************************************************** */
void print_VHDL_instance (FILE *f, socket_t *dev, int All)
{
node_t *n;
int need_term = 0;
char *prefix;
/* only prefix devices with similar idents and types */
if (!ISNULLSTR (dev->identifier) && !ISNULLSTR (dev->type) &&
streq (dev->identifier, dev->type))
{
prefix = "I_";
}
else
{
prefix = "";
}
f,
"%s%s : %s \n",
prefix,
check_null_str (dev->identifier),
check_null_str (dev->type));
if (dev->generics)
list_VHDL_generic_map_values (f, &dev->generics);
/* sort the identifiers of the nodes */
sort_nodes (dev, NO_EXTRACT_XY);
n = dev->nodes;
while (n)
{
vhdl_t *pin_datatype = default_vhdl_datatype;
char nam1[MAXIDLEN], nam2[MAXIDLEN];
if (n->vhdltype)
pin_datatype = n->vhdltype;
if ((n->net_assigned && n->in_use) || All)
{
char *sig_prefix;
if (need_term)
else
need_term = 1;
/* is there a slice in the output */
if (n->net && n->net->needs_buff_sig)
sig_prefix = BUFPREFIX;
else
sig_prefix = "";
if (n->net)
{
f,
" %s",
make_vhdl_name (
nam1, check_null_str (n->identifier))); /* was n->name
*/
if (n->lhs_expr)
{
print_range_expression (f, n->lhs_expr, RECURSE_CONST);
}
f,
"=> %s%s ",
sig_prefix,
make_vhdl_name (nam2, check_null_str (n->net->name)));
}
else
{
f,
" %-20s => OPEN ",
make_vhdl_name (
nam1, check_null_str (n->identifier))); /* was n->name
*/
}
/* do bus slicing only if the connected net is a bus */
if (n->net && n->net->vhdltype)
{
decode_vhdl_bus (f, n->net->vhdltype, RECURSE_CONST);
}
else
{
/* fprintf(f,"\n"); */
}
}
n = n->sktnext; /* traverse to next pin on socket */
};
}
/* ********************************************************************** */
void print_VHDL_sigs (FILE *f)
{
net_t *net = named_list;
char nam[MAXIDLEN], *sig_prefix;
while (net)
{
if (net->needs_buff_sig)
sig_prefix = BUFPREFIX;
else
sig_prefix = "";
/* May 21 2001 only print nets that connect to 'external' tagged modules */
if ((IS_ROUTABLE (net->how_routed)) &&
((net->bundle_member) || ((net->inside_partition) && net->has_external)))
{
}
else
{
}
fprintf (f
, " signal %s%s : ", sig_prefix
, make_vhdl_name
(nam
, net
->name
));
decode_vhdl_type (f, net->vhdltype, RECURSE_CONST);
if (net->vhdltype)
{
if (net->vhdltype->decl_expr)
{
print_expression (f, net->vhdltype->decl_expr, NO_RECURSE);
}
if (net->vhdltype->default_expr)
{
print_expression (f, net->vhdltype->default_expr, NO_RECURSE);
}
}
f,
"; -- partition : %s %s %s %s %s\n",
net->inside_partition ? "used in," : "unused in,",
net->leaves_partition ? "leaves," : "buried,",
net->needs_buff_sig ? ", buffered," : "",
net->has_external ? "external skt" : "internal skt",
net->bundle_member ? "bundle member" : " not bundled");
net = net->next;
}
}
/* ********************************************************************** */
void print_VHDL_assignments (FILE *f)
{
net_t *net = named_list;
socket_t *socket = socket_head;
/* code borrowed from Verilog */
fprintf (f
, "-- Bundled signals\n\n");
while (socket)
{
node_t *nodes = socket->nodes;
if (socket->highest_bundle &&
(socket->bundle_width > MINBUNDLE)) /* will not do assigns on small bundles
*/
while (nodes)
{
if (nodes->bundle_index >= 0)
{
char nam[MAXIDLEN];
net_t *net = nodes->net;
make_vhdl_name (nam, net->name);
f,
" %s <= %s(%d);\n",
nam,
socket->identifier,
nodes->bundle_index);
}
nodes = nodes->sktnext;
}
/* else
fprintf(f,"-- %s;\n",
net->name);
*/
socket = socket->next;
}
fprintf (f
, "-- Buffered signals\n\n");
while (net)
{
if (net->inside_partition && net->needs_buff_sig)
{
char nam[MAXIDLEN];
make_vhdl_name (nam, net->name),
fprintf (f
, " %-20s <= " BUFPREFIX
"%s; -- buffer\n", nam
, nam
);
}
if (net->vhdl_connect_net && net->subnets)
{
char nam[MAXIDLEN], nam1[MAXIDLEN];
make_vhdl_name (nam, net->identifier);
make_vhdl_name (nam1, net->subnets->identifier);
fprintf (f
, " %-20s <= %s; -- connector\n", nam
, nam1
);
}
else if (net->inside_partition && net->vhdltype && net->vhdltype->default_expr)
{
char nam[MAXIDLEN];
make_vhdl_name (nam, net->identifier);
print_range_expression (f, net->vhdltype->default_expr, NO_RECURSE);
fprintf (f
, "; -- Defined default drive value\n");
}
net = net->next;
}
}
/* ********************************************************************** */
/* code lists bundles although they are probably broken */
void print_VHDL_entity (FILE *f, char *entityname)
{
net_t *net;
int need_term = 0;
socket_t *skt;
char nam[MAXIDLEN];
fprintf (f
, "ENTITY %s IS\n", entityname
);
/* print out global generic settings */
/*
list_VHDL_generic_values (f,&partition_generics);
*/
skt = socket_head;
/* bundles of pins are replaced by signals named the same as a socket which
they are bundled through , unless the bundles are too small in which case they
are replaced by separate wires */
while (skt)
{
if (skt->highest_bundle)
{
if (skt->bundle_width > MINBUNDLE)
{
if (need_term)
{
need_term = 0;
}
else
{
}
f,
" %-15s : %6s %s (%d downto 0) ",
make_vhdl_name (nam, skt->identifier),
decode_pin_VHDL[BIDIR],
default_vhdl_bustype->basetype,
skt->bundle_width - 1);
need_term = 1;
}
else
/* if the 'bundle' has less than MINBUNDLE pins, */
/* list out all of the nets in turn as pins */
{
node_t *node;
node = skt->nodes;
while (node)
{
net = node->net;
/*
printf("node %s\n",node->identifier);
*/
if (net && IS_ROUTABLE (net->how_routed) &&
net->bundle_member)
{
if (need_term)
{
need_term = 0;
}
else
{
}
f,
" %-15s : %6s ",
make_vhdl_name (nam, net->name),
decode_pin_VHDL[net->ext_dir]);
decode_vhdl_type (
f, net->vhdltype, RECURSE_NUMBER);
need_term = 1;
}
node = node->sktnext;
}
}
}
skt = skt->next;
}
/* go back and list all of the non-bundle pins */
net = named_list;
while (net)
{
/* print out only unbundled nets as ports of the pcb */
if (net->leaves_partition && !net->bundle_member)
{
if (need_term)
{
}
else
{
}
f,
" %-15s : %6s ",
make_vhdl_name (nam, net->name),
decode_pin_VHDL[net->ext_dir]);
decode_vhdl_type (f, net->vhdltype, RECURSE_NUMBER);
need_term = 1;
}
net = net->next;
}
fprintf (f
, "END %s;\n\n", entityname
);
}
/* ********************************************************************** */
/* generate default VHDL Libraries */
/* ********************************************************************** */
void print_VHDL_libs (FILE *f)
{
fprintf (f
, "LIBRARY IEEE,WORK;\nUSE IEEE.std_logic_1164.ALL;\n\n");
}
/* ********************************************************************** */
/* generate a VHDL architecture forselected sockets */
/* ********************************************************************** */
void print_VHDL_architecture (FILE *f, char *entityname)
{
socket_t *skt;
char *arch_name;
generic_info_t gen[1];
/* if we are using VHDL then look at the VHDL architecture name if defined*/
arch_name =
(get_generic_value (&global_generics, "vhdl_arch_name", gen) == IS_ENV_VAL &&
gen->expr)
? gen->expr->left.s
: "top_arch";
fprintf (f
, "\n\nARCHITECTURE %s OF %s IS\n\n", arch_name
, entityname
);
/* not allowed to have generics at the top level so put them here */
list_VHDL_constants (f, &partition_generics);
list_VHDL_constants (f, &global_generics);
/* clear type seen flags on all socket templates = components */
clr_type_seen ();
skt = socket_head;
/* list out templates for those sockets selected */
while (skt)
{
if (skt->is_external && skt->highest_bundle == 0)
{
/* suppress printout of duplicate components .... */
if (skt->template_socket)
{
if (skt->template_socket->socket_type_seen == 0)
{
print_VHDL_component (f, skt->template_socket, 0);
skt->template_socket->socket_type_seen = 1;
}
}
else
/* no components, use socket/entity as its own component */
print_VHDL_component (f, skt, 0);
}
skt = skt->next;
}
print_VHDL_sigs (f);
skt = socket_head;
while (skt)
{
if (skt->is_external && skt->highest_bundle == 0)
print_VHDL_instance (f, skt, 0);
skt = skt->next;
}
print_VHDL_assignments (f);
fprintf (f
, "END %s;\n\n", arch_name
);
}
/* ********************************************************************** */
/* generate a VHDL file */
/* ********************************************************************** */
void produce_VHDL (FILE *f, char *entityname, char *template)
{
char linebuff[256];
int done_entity = 0, done_architecture = 0;
if (!template || !template[0])
{ /* check null pointer or empty string */
print_header (f, "WRITE VHDL");
print_VHDL_libs (f);
fprintf (f
, "\n-- vertical read_off\n");
print_VHDL_entity (f, entityname);
fprintf (f
, "\n-- vertical read_on\n");
print_VHDL_libs (f);
print_VHDL_architecture (f, entityname);
fprintf (f
, "\n-- vertical end;\n");
}
else
{ /* there is a template file */
FILE *tp;
tp
= fopen (template
, "r");
if (tp)
{
print_header (f, "WRITE VHDL");
fprintf (f
, "-- Using template '%s'\n", template
);
{
if (fgets (linebuff
, 256, tp
))
{
if (strstr (linebuff
, "$ENT"))
{
fprintf (f
, "\n-- vertical read_off\n");
print_VHDL_entity (f, entityname);
fprintf (f
, "\n-- vertical read_on\n");
done_entity++;
}
else if (strstr (linebuff
, "$ARCH"))
{
print_VHDL_architecture (f, entityname);
done_architecture++;
}
else
fprintf (f
, "%s", linebuff
); /* it already has
a '\n' on the
end */
}
}
fprintf (f
, "\n-- vertical end;\n");
if (done_entity != 1)
Log (
LOG_ERROR,
"-- Error: %d $ENT$ tags counted in template '%s'\n",
template);
if (done_architecture != 1)
Log (
LOG_ERROR,
"-- Error: %d $ARCH$ tags counted in template '%s'\n",
template);
}
else
Log (
LOG_ERROR,
"-- Error: Cannot open VHDL template '%s'\n",
template);
}
}