
/* generics.c */
/* contains the database functions for lookup of generic information  */
/*
 * $Header: c:\\cygwin\\cvsroot/Vert03/vertlib/generic.c,v 1.1.1.1 2003/11/04 23:34:57 mjames
 * Exp $ $Log: generic.c,v $ Revision 1.1.1.1  2003/11/04 23:34:57  mjames Imported into local
 * repositrory
 *
 * Revision 1.15  2002/09/30 13:27:43  MJAMES
 * Created function to tidy up partition generics.
 *
 * Revision 1.14  2002/09/18 08:51:33  mjames
 * Removed unused variables
 *
 * Revision 1.13  2002/09/09 10:27:53  mjames
 * Removed set generic range and replaced it with a set generic value command
 * that takes both integers and ranges.
 *
 * Revision 1.12  2002/01/15 12:35:23  mjames
 * DLL declarations put in
 *
 * Revision 1.11  2001/12/14 15:01:39  mjames
 * Removed unecessary 'generic_waste' function
 *
 * Revision 1.10  2001/12/13 22:20:11  mjames
 * Using #ident with header to identify file
 *
 * Corrected GENERIC MAP printout (partially !)
 *
 * Revision 1.9  2001/11/19 10:41:51  mjames
 * Merged back DTC release
 *
 * Revision 1.8.2.1  2001/11/16 15:06:57  mjames
 * Corrected an error in the return value of a function
 *
 * Revision 1.8  2001/11/01 11:05:32  mjames
 * Printing a list of generic definitiions for ACFP files: case
 * for handling integer constants was omitted.
 *
 * Revision 1.7  2001/10/31 22:20:07  mjames
 * Tidying up problematical comments caused by CVS
 * 'intelligent' comment guessing
 *
 * Revision 1.6  2001/10/22 10:59:57  mjames
 * Added IS_ATTRIBUTE : a generic attribute used for controlling VERTICAL.
 * Can have either string or expression here.
 *
 * Revision 1.5  2001/06/06 12:10:21  mjames
 * Move from HPUX
 *
 * Revision 1.4  2001/04/09 14:58:29  mjames
 * Added capability to delete generics from specific sockets.
 *
 * Revision 1.3  2001/04/06 22:47:02  mjames
 * Added doc2, the creator of documentation to Vertical scripts uses PERL
 *
 *
 * Also correcting generic behaviour and the printing of Verilog.
 *
 * 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.28  2000/10/12  15:32:26  15:32:26  mjames (Mike James)
 * Removed <cr>
 *
 * Revision 1.27  2000/10/04  10:37:06  10:37:06  mjames (Mike James)
 * Modified for Vertical2 : support COMPONENTS and SIGNALS
 *
 * Revision 1.27  2000/10/04  10:37:06  10:37:06  mjames (Mike James)
 * Part of Release PSAVAT01
 *
 * Revision 1.26  2000/10/02  11:04:14  11:04:14  mjames (Mike James)
 * new_vhdl
 *
 * Revision 1.25  2000/09/27  14:42:15  14:42:15  mjames (Mike James)
 * Part of Release Sep_27_ST_2000
 *
 * Revision 1.24  2000/09/27  10:45:43  10:45:43  mjames (Mike James)
 * Started using the g_class member of the generic structu[re
 *
 * Revision 1.23  2000/09/21  10:15:45  10:15:45  mjames (Mike James)
 * Part of Release Sep21Alpha
 *
 * Revision 1.22  2000/08/25  09:57:12  09:57:12  mjames (Mike James)
 * Part of Release Aug25_alpha
 *
 * Revision 1.21  2000/08/16  08:57:28  08:57:28  mjames (Mike James)
 * Part of Release CD01_Aug2000
 *
 * Revision 1.20  2000/08/14  14:45:09  14:45:09  mjames (Mike James)
 * Part of Release Aug_14_2000
 *
 * Revision 1.19  2000/08/11  08:30:30  08:30:30  mjames (Mike James)
 * Part of Release Aug_11_2000
 *
 * Revision 1.18  2000/08/09  10:31:44  10:31:44  mjames (Mike James)
 * Part of Release Aug__9_2000
 *
 * Revision 1.17  2000/05/31  11:42:53  11:42:53  mjames (Mike James)
 * Part of Release May_31_2000
 *
 * Revision 1.16  2000/05/08  17:01:35  17:01:35  mjames (Mike James)
 * Part of Release May__8_2000
 *
 * Revision 1.15  2000/05/08  16:59:28  16:59:28  mjames (Mike James)
 * Part of Release May__8_2000
 *
 * Revision 1.14  2000/05/08  16:57:05  16:57:05  mjames (Mike James)
 * Part of Release May__8_2000
 *
 * Revision 1.13  2000/03/08  16:19:08  16:19:08  mjames (Mike James)
 * New version including PC
 *
 * Revision 1.10  2000/01/20  15:58:44  15:58:44  mjames (Mike James)
 * Part of Release R22
 *
 * Revision 1.9  99/12/22  11:15:25  11:15:25  mjames (Mike James)
 * Part of Release Dec_22_1999
 *
 * Revision 1.8  99/11/23  13:52:05  13:52:05  mjames (Mike James)
 * Addded syntax to support special generics for Certify support
 *
 * Revision 1.7  99/06/25  14:35:35  14:35:35  mjames (Mike James)
 * Added in reference to expression.h, but no changes made
 * to the function of acfread yet.
 *
 * Revision 1.6  99/06/18  09:24:17  09:24:17  mjames (Mike James)
 * Added new VHDL printing of generic information
 *
 * Revision 1.5  99/05/04  09:51:21  09:51:21  mjames (Mike James)
 * Amended generic lookup rules
 *
 * Revision 1.4  98/08/12  14:20:50  14:20:50  mjames (Mike James)
 * removed bug in generic lookup.
 *
 * Revision 1.3  98/07/14  13:24:16  13:24:16  mjames (Mike James)
 * fixed errors in lookup of generic variables -
 * now works better
 *
 * Revision 1.2  98/03/16  11:37:09  11:37:09  mjames (Mike James)
 * Updated generic storage and lookup
 *
 * Revision 1.1  98/02/11  11:26:11  11:26:11  mjames (Mike James)
 * Initial revision
 *
 */
#include "generic.h"

#include "cmdlog.h"
#include "cmdparse.h"
#include "database.h"
#include "expression.h"
#include "vertcl_main.h"

#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* this is included regardless of the translator being built */
#include "acf_yacc.h"

#ident                                                                                        \
    "@(#)$Header: c:\\cygwin\\cvsroot/Vert03/vertlib/generic.c,v 1.1.1.1 2003/11/04 23:34:57 mjames Exp $"

generic_info_t *global_generics = NULL; /* list of user set generics */

generic_info_t *partition_generics = NULL; /* list of all unique generic names found on
                                              entities within a partition */
/* This function converts an integer value expressed in a number base
   e.g. 2_1010110 binary
        16_0xf002 hex
        3234      decimal */
int convert_num (char *string, int *value)
{
        char *endptr;
        int base;
        long val;
        /* identify numbers like base_nnnnnn */
        if (isdigit (string[0]))
        {
                val = strtol (string, &endptr, 10);
                if (*endptr == '_')
                {
                        base = (int) val;
                        endptr++;
                        val = (int) strtol (endptr, &endptr, base);
                }
                *value = (int) val;
                return 1; /* success */
        }
        else
        {
                /*    *value = 1; */
                return 0; /* fail */
        }
}

__declspec(dllexport) generic_type_t
    get_generic_value (generic_info_t **list, char *string, generic_info_t *result)
{
        generic_info_t *ptr;
        int val;

        if (list)
                ptr = *list;

        result->g_type = NO_VALUE; /* Unknown information */
        /* identify numbers like base_nnnnnn */
        if (convert_num (string, &val) == 1)
        {
                result->g_type = IS_INTEGER;
                result->expr = compile_constant (val);
        }
        else
        {
                /* look up name and see if it has an integer value */
                while (ptr)
                {
                        if (strcmp2 (ptr->name, string) == 0)
                                break;
                        ptr = ptr->next;
                }
                if (ptr)
                {
                        /*      printf("%s : found value = %d\n",string,ptr->value); */
                        *result = *ptr;
                        /*      printf("%s : found value = %s\n",string,ptr->name); */
                }
                /* check to see if the string returned is valid in future at this point */
        }
#if defined DEBUG_EXPRESSION
        if (ptr)
                printf ("GET %s %p looked up\n", ptr->name, ptr);
#endif
        return result->g_type;
}

__declspec(dllexport) generic_info_t *get_generic_ref (generic_info_t **list, char *string)
{
        generic_info_t *ptr;
        if (list)
        {
                ptr = *list;
        }
        else
        {
                return NULL;
        }
        /* look up name and see if it has an integer value */
        while (ptr)
        {
                if (strcmp2 (ptr->name, string) == 0)
                        break;
#if defined DEBUG_EXPRESSION
                if (ptr)
                        printf ("REF %s %p looked up\n", ptr->name, ptr);
#endif
                ptr = ptr->next;
        }

#if defined DEBUG_EXPRESSION
        if (ptr)
                printf ("REF %s %p looked up\n", ptr->name, ptr);
#endif
        return ptr;
}

/* this function makes a copy of the generic passed to it */
/* but it cannot make a copy of the expression because it
 * requires knowledge of whether this generic is local to
 * a component instance or global : this is done by the caller
 */
__declspec(dllexport)
    generic_info_t *set_generic_value (generic_info_t **list, generic_info_t *info)
{
        generic_info_t *ptr, *prev;

        prev = NULL;
        if (list)
                ptr = *list;
        else
                return NULL;

        while (ptr)
        {
                if (strcmp2 (ptr->name, info->name) == 0)
                        break;
                prev = ptr;
                ptr = ptr->next;
        }

        /* there is no existing generic of the appropriate name */

        if (!ptr)
        {
                ptr = calloc (1, sizeof (generic_info_t));
                if (!prev)
                        *list = ptr;
                else
                        prev->next = ptr;
                ptr->next = NULL;
                ptr->expr_ref = NULL;
                ptr->is_component_generic =
                    info->is_component_generic; /* allows me to find which list defined on */
                ptr->name = allocstr (info->name);
        }
        else
        {
                /*    free(ptr->typename);  */
                /*    free(ptr->valuename); */
        }
        if (ptr)
        {
#if defined DEBUG_EXPRESSION
                printf ("SET %s %p assign '", info->name, ptr);
                print_expression (stdout, info->expr, 0);
                printf ("'=%d was '", eval_expression (info->expr, list));
                print_expression (stdout, ptr->expr, 0);
                printf ("'\n");
#endif
                ptr->typename = allocstr (info->typename);

                ptr->valid = 0;
                ptr->expr = info->expr;
                ptr->g_type = info->g_type;
                ptr->g_class = info->g_class;
        }
        return ptr;
}

/* new delete generic call is used to clean up databases */
__declspec(dllexport) int del_generic_value (generic_info_t **list, generic_info_t *info)
{
        generic_info_t *ptr, *prev = NULL;

        if (list)
                ptr = *list;
        else
                return 1;

        while (ptr)
        {
                if (strcmp2 (ptr->name, info->name) == 0)
                        break;
                prev = ptr;
                ptr = ptr->next;
        }

        if (!ptr)
                return 1;

        /* we have found a generic of the appropriate name and now
         * it will be deleted. We cannot remove any of the expressions
         * or strings used as they may be shared if they were declared
         * with the use of a wildcard assignment. Pay the price
         * of a potential memory leak here ....  */

        if (prev)
                prev->next = ptr->next;
        else
                *list = ptr->next;

        free (ptr); /* we can be sure this is unique however */

        return 0;
}

#define MAXINDENT 8

static char linebuff[MAXIDLEN];

static char *escape_quote (char *str)
{
        char *f = str, *t = linebuff;
        while (*f)
        {
                if (*f == '\"' || *f == '\\')
                        *t++ = '\\';
                *t++ = *f++;
        }
        *t = 0;
        return linebuff;
}

__declspec(dllexport) void list_generic_values (FILE *f, generic_info_t **list, int indent)
{
        generic_info_t *ptr;
        int i;
        char indents[MAXINDENT + 1];

        if (list)
                ptr = *list;
        else
                ptr = NULL;
        /* build up the line of indents */
        for (i = 0; (i < indent) && (i < MAXINDENT); indents[i++] = ' ')
                ;
        indents[indent] = 0;

        fprintf (f, "%sGENERIC -- Generic constants \n", indents);
        while (ptr)
        {
                char *string = NULL;
                if (ptr->expr)
                        string = ptr->expr->left.s; /* pickup string for future use */
                fprintf (f, "%s  %-20s : ", indents, ptr->name); /* print its name */

                switch (ptr->g_type)
                {
                case NO_VALUE:
                case IS_STRING:
                case IS_ENV_VAL:
                        fprintf (
                            f,
                            " %-10s      := \"%s\"",
                            ptr->typename ? ptr->typename : "",
                            string ? escape_quote (string) : "");
                        break;
                case IS_ATTRIBUTE:
                        fprintf (f, " attribute      ");
                        if (ptr->g_class == DEFINED)
                        {
                                fprintf (f, " := ");
                                print_expression (f, ptr->expr, 0);
                        }
                        break;
                case IS_BOOLEAN:
                        fprintf (f, " boolean        ");
                        if (ptr->g_class == DEFINED)
                        {
                                fprintf (f, " := ");
                                print_expression (f, ptr->expr, 0);
                        }
                        break;
                case IS_INTEGER:
                        fprintf (f, " integer   ");
                        if (ptr->g_class == DEFINED)
                        {
                                fprintf (f, " := ");
                                print_expression (f, ptr->expr, 0);
                        }
                        break;
                case TO:
                case DOWNTO:
                        fprintf (f, " integer range  ");
                        if (ptr->g_class == DEFINED)
                        {
                                fprintf (f, " := ");
                                print_range_expression (f, ptr->expr, 0);
                        }
                        break;

                case IS_DECLARATION_DIRECTIVE:
                        if (!ISNULLSTR (string))
                                fprintf (f, " declaration  :=  \"%s\"", escape_quote (string));
                        else
                                fprintf (f, " declaration");
                        break;
                case IS_INSTANCE_DIRECTIVE:
                        if (!ISNULLSTR (string))
                                fprintf (f, " instance     :=  \"%s\"", escape_quote (string));
                        else
                                fprintf (f, " instance");
                        break;
                };

                if (ptr->next)
                        fprintf (f, ";\n");
                ptr = ptr->next;
        }
        fprintf (f, "\n%sEND;\n\n", indents);
}

__declspec(dllexport) void list_VHDL_generic_map_values (FILE *f, generic_info_t **list)
{
        generic_info_t *ptr = *list;
        if (ptr)
        {
                fprintf (f, "-- Generic constants\n");
                fprintf (f, " GENERIC MAP  ( \n");
        }
        while (ptr)
        {
                /* only integer and string generic constants OK */
                switch (ptr->g_type)
                {
                case IS_STRING:
                case IS_INTEGER:
                case IS_BOOLEAN:
                        fprintf (f, "    %-10s => ", ptr->name ? ptr->name : "");
                        print_expression (f, ptr->expr, 0);
                        break;
                default:
                        fprintf (f, "--  %-10s", ptr->name ? ptr->name : "");
                        break;
                }

                if (ptr->next)
                        fprintf (f, ",\n");
                else
                        fprintf (f, "\n    )\n"); /* no closing semi on GENERIC MAP */
                ptr = ptr->next;
        }
}

/********************************************************************/
__declspec(dllexport) int print_VHDL_constant (
    FILE *f, char *s, generic_info_t *ptr, generic_print_style recurse_generics)
{
        expression_t *exp;
        if (!ptr)
                return 0;
        exp = ptr->expr;

        if (exp)
        {
                switch (ptr->g_type)
                {
                case TXT_STRING:
                        fprintf (f, " %s  %-20s : string  := ", s, ptr->name);
                        print_expression (f, exp, recurse_generics);
                        return 1;
                        break;
                case TO:
                case DOWNTO:
                        fprintf (f, " %s  %-20s : integer range:= ", s, ptr->name);
                        print_range_expression (f, exp, recurse_generics);
                        return 1;
                        break;

                case IS_INTEGER:
                        fprintf (f, " %s  %-20s : integer:= ", s, ptr->name);
                        print_expression (f, exp, recurse_generics);
                        return 1;
                        break;
                case IS_BOOLEAN:
                        fprintf (f, " %s  %-20s : boolean:= ", s, ptr->name);
                        print_expression (f, exp, recurse_generics);
                        return 1;
                        break;
                default:
                        return 0;
                        /* nothing */
                };
        }
        return 0;
}

/********************************************************************/
__declspec(dllexport) void list_VHDL_generic_values (FILE *f, generic_info_t **list)
{
        generic_info_t *ptr;
        int printed;
        ptr = *list;

        if (ptr)
        {
                fprintf (f, "-- Generic constants\n");
                fprintf (f, "  GENERIC  ( \n");
        }
        printed = 0;
        while (ptr)
        {
                if (printed)
                        fprintf (f, ";\n");
                printed = print_VHDL_constant (f, "", ptr, 0);
                ptr = ptr->next;
        }
        if (*list)
                fprintf (f, ");\n"); /*  closing semi on GENERIC */
}
/********************************************************************/
void list_VHDL_constants (FILE *f, generic_info_t **list)
{
        generic_info_t *ptr = *list;

        while (ptr)
        { /* recursively expand generics to the full expression */
                if (print_VHDL_constant (f, "   CONSTANT ", ptr, 1))
                        fprintf (f, ";\n");
                ptr = ptr->next;
        }
        fprintf (f, "\n");
}
/********************************************************************/
/* this was used before CONSTANTS were used. Keeping it because it
 * will be useful when name spaces are properly implemented : if there
 * are any unresolved global generics then partition generics should be
 * created
 */

/********************************************************************/

void setup_generic_types (generic_info_t *list)
{
        generic_info_t *ptr = list;
        /* invalidate all values */
        while (ptr)
        {
                ptr->valid = 0;
                ptr = ptr->next;
        }
        ptr = list;
        while (ptr)
        {
                if (!ptr->valid)
                {
                        /* this simply does type extraction from the expression
                           component now */
                        eval_gen_expression (ptr);
                }
                ptr->valid = 1;
                ptr = ptr->next;
        }
}

/* if a generic has an expression which is a string or integer constant,
   transfer it to the other list */
void transfer_constant_generics (generic_info_t **src, generic_info_t **dst)
{
        generic_info_t *prev, *curr, *next;
        prev = NULL;
        curr = *src;

        while (curr)
        {
                expression_t *exp;
                exp = curr->expr;
                next = curr->next; /* remember the next pointer for later */
                if (exp && (exp->opcode == EXP_STRING || exp->opcode == EXP_CONSTANT))
                {
                        if (prev)
                                prev->next = curr->next; /* link over it */
                        if (curr == *src) /* if was first element of list, set head to next */
                                *src = curr->next;
                        curr->next = *dst; /* link to old head of destination list */
                        *dst = curr;       /* place on head of destination list */
                }
                else
                        prev = curr; /* only move on prev if we have not removed curr..*/
                curr = next;
        }
}

extern void clear_partition_generics (generic_info_t **list)
{
        generic_info_t *ptr, *prev_ptr;
        expr_ref_t *refs, *prev_refs;
        ptr = *list;
        while (ptr)
        {
                prev_ptr = ptr;
                refs = ptr->expr_ref;
                while (refs)
                {
                        prev_refs = refs;
                        if (refs->expr)
                        {
                                refs->expr->opcode = EXP_UNDEF_VAR;
                                refs->expr->left.g = NULL;
                        }
                        refs = refs->expr_ref;
                        free (prev_refs);
                };
                ptr = ptr->next;
                free (prev_ptr);
        };
        *list = NULL;
}

/* compute the values of all expressions */

void elaborate_all (void)
{
        socket_t *socket;

        printf ("elaborate\n");
        setup_generic_types (global_generics);
        setup_generic_types (partition_generics);
        transfer_constant_generics (&global_generics, &partition_generics);
        socket = socket_head;
        while (socket)
        {
                setup_generic_types (socket->generics);
                socket = socket->next;
        }
}

void copy_declaration_generics (socket_t *skt, socket_t *from)
{
        generic_info_t *src;

        /*  puts("copy_declaration_generics"); */
        src = from->generics;
        while (src)
        {
                if (get_generic_ref (&skt->generics, src->name))
                        set_generic_value (&(skt->generics), src);
                src = src->next;
        }
        src = skt->unrouted_generics;
        while (src)
        {
                if (get_generic_ref (&skt->generics, src->name))
                        set_generic_value (&(skt->generics), src);
                src = src->next;
        }
        puts ("done declaration generics");
}