
/* $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 !! */
    }
  l=strlen(buffer);
  /* 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);



  fprintf(f,"  PORT ( \n");
  /* 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)){
      fprintf(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)
        {
        fprintf(f,":= ");
        print_expression(f,default_expr,NO_RECURSE);
        }
        

      if (n->sktnext) 
        fprintf(f,";");
      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 = "";
    }
    
  fprintf(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);

  fprintf(f,"  PORT MAP ( \n");
  /* 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)
        fprintf(f,",\n");
      else
        fprintf(f,"\n");
      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)
        {      
        fprintf(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);
          }
        fprintf(f,"=> %s%s ",
               sig_prefix,
               make_vhdl_name(nam2,check_null_str(n->net->name)));
        }
      else
        {      
        fprintf(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 */
  };
  fprintf(f,"\n   );\n\n");
}

/* ********************************************************************** */

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)) )
      {                                                                                
      fprintf(f,"    ");
      }
    else
      {
      fprintf(f,"  --");
      }


    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)
        {
        fprintf(f,":= ");
        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);
        fprintf(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);
        fprintf(f," %-20s <= ",nam);
        print_range_expression(f, net->vhdltype->default_expr,NO_RECURSE);
        fprintf(f,"; -- Defined default drive value\n");

        }

    net=net->next;
  }
  fprintf(f,"-- \n\n");
  

  
  
}

/* ********************************************************************** */
/* 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);  
*/
  fprintf(f,"  PORT (\n");

  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)
          {
          fprintf(f,";\n");
          need_term = 0;
          }
        else 
          {
          fprintf(f,"\n");
          }
        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)
            {
            fprintf(f,";\n");
            need_term = 0;
            }
          else 
            {
            fprintf(f,"\n");
            }
           fprintf(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)
        {
        fprintf(f,";\n");
        }
      else
        {
        fprintf(f,"\n");
        }
      fprintf(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,"\n     );\n");
  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);
  fprintf(f,"\n\nBEGIN\n\n");
  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 */
    fprintf(f,"-- vertical vhdl\n");
    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) {
    
      fprintf(f,"-- vertical vhdl\n");
      print_header(f,"WRITE VHDL");
      fprintf(f,"-- Using template '%s'\n",template);
      while(!feof(tp)){
        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");
      fclose(tp);
      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);
      
    }
  }
        


