/* $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 <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <time.h>
#include <regex.h>
#include "vertcl_main.h"
#include "expression.h"
#include "generic.h"
#include "database.h"
#include "printout.h"
#include "print_vhdl.h"
#include "print_vlog.h"
#include "sorting.h"
#include "cmdparse.h"
#include "cmdlog.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;
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)){
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)
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 = "";
}
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)
{
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);
}
sig_prefix,
make_vhdl_name(nam2,check_null_str(n->net->name)));
}
else
{
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
{
}
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);
}
}
fprintf(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);
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
{
}
fprintf(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
{
}
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
{
}
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);
}
else { /* there is a template file */
FILE * tp;
if(tp) {
print_header(f,"WRITE VHDL");
fprintf(f
,"-- Using template '%s'\n",template
);
if(fgets(linebuff
,256,tp
)) {
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 */
}
}
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);
}
}