/* 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 */
{
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);
#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:
f,
" %-10s := \"%s\"",
ptr->typename ? ptr->typename : "",
string ? escape_quote (string) : "");
break;
case IS_ATTRIBUTE:
if (ptr->g_class == DEFINED)
{
print_expression (f, ptr->expr, 0);
}
break;
case IS_BOOLEAN:
if (ptr->g_class == DEFINED)
{
print_expression (f, ptr->expr, 0);
}
break;
case IS_INTEGER:
if (ptr->g_class == DEFINED)
{
print_expression (f, ptr->expr, 0);
}
break;
case TO:
case DOWNTO:
if (ptr->g_class == DEFINED)
{
print_range_expression (f, ptr->expr, 0);
}
break;
case IS_DECLARATION_DIRECTIVE:
if (!ISNULLSTR (string))
fprintf (f
, " declaration := \"%s\"", escape_quote
(string
));
else
break;
case IS_INSTANCE_DIRECTIVE:
if (!ISNULLSTR (string))
fprintf (f
, " instance := \"%s\"", escape_quote
(string
));
else
break;
};
if (ptr->next)
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");
}
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)
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)
{
if (!ptr)
return 0;
{
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");
}
printed = 0;
while (ptr)
{
if (printed)
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))
ptr = ptr->next;
}
}
/********************************************************************/
/* 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)
{
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;
};
ptr = ptr->next;
};
*list = NULL;
}
/* compute the values of all expressions */
void elaborate_all (void)
{
socket_t *socket;
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");
}