blob: 0b2a09afba5f67c491877b880c6cfcadc7c463d8 [file] [log] [blame] [edit]
/*
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
*/
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <math.h>
#include <sstream>
#include "odin_globals.h"
#include "odin_types.h"
#include "ast_util.h"
#include "parse_making_ast.h"
#include "string_cache.h"
#include "verilog_bison_user_defined.h"
#include "verilog_preprocessor.h"
#include "hard_blocks.h"
#include "vtr_util.h"
#include "vtr_memory.h"
extern int yylineno;
//for module
STRING_CACHE **defines_for_module_sc;
STRING_CACHE *modules_inputs_sc;
STRING_CACHE *modules_outputs_sc;
//for function
STRING_CACHE **defines_for_function_sc;
STRING_CACHE *functions_inputs_sc;
STRING_CACHE *functions_outputs_sc;
STRING_CACHE *module_names_to_idx;
ast_node_t **block_instantiations_instance;
int size_block_instantiations;
ast_node_t **module_instantiations_instance;
int size_module_instantiations;
ast_node_t **module_variables_not_defined;
int size_module_variables_not_defined;
ast_node_t **function_instantiations_instance;
int size_function_instantiations;
ast_node_t **function_instantiations_instance_by_module;
int size_function_instantiations_by_module;
long num_modules;
long num_instances;
ast_node_t **ast_modules;
int num_functions;
ast_node_t **ast_functions;
ast_node_t **all_file_items_list;
int size_all_file_items_list;
short to_view_parse;
/*
* File-scope function declarations
*/
void graphVizOutputPreproc(FILE *yyin);
ast_node_t *newFunctionAssigning(ast_node_t *expression1, ast_node_t *expression2, int line_number);
ast_node_t *newHardBlockInstance(char* module_ref_name, ast_node_t *module_named_instance, int line_number);
ast_node_t *resolve_ports(ids top_type, ast_node_t *symbol_list);
/*
* Function implementations
*/
void graphVizOutputPreproc(FILE *yyin)
{
std::string file_out = configuration.debug_output_path
+ "/"
+ strip_path_and_ext(configuration.list_of_file_names[current_parse_file]).c_str()
+ "_preproc.v";
FILE *fp = fopen(file_out.c_str(), "w");
oassert(fp);
char *line = NULL;
while ((line = get_line(line, NULL, yyin)) != NULL)
{
fprintf(fp, "%s", line);
vtr::free(line);
}
fclose(fp);
rewind(yyin);
}
static void assert_supported_file_extension(std::string input_file, int file_number)
{
bool supported = false;
std::string extension = get_file_extension(input_file);
for(int i = 0; i< file_extension_supported_END && ! supported; i++)
{
supported = (extension == std::string(file_extension_supported_STR[i]) );
}
if(! supported)
{
std::string supported_extension_list = "";
for(int i=0; i<file_extension_supported_END; i++)
{
supported_extension_list += " ";
supported_extension_list += file_extension_supported_STR[i];
}
error_message(ARG_ERROR, -1, file_number,
"File (%s) has an unsupported extension (%s), Odin only support { %s }",
input_file.c_str(),
extension.c_str(),
supported_extension_list.c_str()
);
}
}
/*---------------------------------------------------------------------------------------------
* (function: parse_to_ast)
*-------------------------------------------------------------------------------------------*/
void parse_to_ast()
{
extern FILE *yyin;
extern int yylineno;
/* hooks into macro at the top of verilog_flex.l that shows the tokens as they're parsed. Set to true if you want to see it go...*/
to_view_parse = configuration.print_parse_tokens;
/* initialize the parser */
init_veri_preproc();
/* read all the files in the configuration file */
current_parse_file =0;
while (current_parse_file < configuration.list_of_file_names.size())
{
assert_supported_file_extension(configuration.list_of_file_names[current_parse_file], current_parse_file);
yyin = fopen(configuration.list_of_file_names[current_parse_file].c_str(), "r");
if (yyin == NULL)
{
error_message(ARG_ERROR, -1, -1, "cannot open file: %s\n", configuration.list_of_file_names[current_parse_file].c_str());
}
yyin = veri_preproc(yyin);
/* write out the pre-processed file */
if (configuration.output_preproc_source)
graphVizOutputPreproc(yyin);
/* reset the line count */
yylineno = 0;
/* setup the local parser structures for a file */
init_parser_for_file();
/* parse next file */
yyparse();
fclose(yyin);
current_parse_file++;
}
/* clean up all the structures in the parser */
cleanup_veri_preproc();
/* for error messages - this is in case we use any of the parser functions after parsing (i.e. create_case_control_signals()) */
current_parse_file = -1;
}
/* --------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------
BASIC PARSING FUNCTIONS
Assume that all `defines are constants so we can change the constant into a number (see def_reduct by performing a search in this file)
--------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------
* (function: cleanup_hard_blocks)
* This function will correctly label nodes in the AST as being part of a
* hard block and not a module. This needs to be done post parsing since
* there are no language differences between hard blocks and modules.
*--------------------------------------------------------------------------*/
void cleanup_hard_blocks()
{
int i;
long j;
ast_node_t *block_node, *instance_node, *connect_list_node;
for (i = 0; i < size_block_instantiations; i++)
{
block_node = block_instantiations_instance[i];
instance_node = block_node->children[1];
instance_node->type = HARD_BLOCK_NAMED_INSTANCE;
connect_list_node = instance_node->children[1];
connect_list_node->type = HARD_BLOCK_CONNECT_LIST;
for (j = 0; j < connect_list_node->num_children; j++)
{
connect_list_node->children[j]->type = HARD_BLOCK_CONNECT;
}
}
return;
}
/*---------------------------------------------------------------------------------------------
* (function: init_parser)
*-------------------------------------------------------------------------------------------*/
void init_parser()
{
defines_for_module_sc = NULL;
defines_for_function_sc = NULL;
/* record of each of the individual modules */
num_modules = 0; // we're going to record all the modules in a list so we can build a tree of them later
num_instances = 0;
num_functions = 0;
ast_modules = NULL;
ast_functions = NULL;
module_instantiations_instance = NULL;
function_instantiations_instance = NULL;
module_variables_not_defined = NULL;
size_module_variables_not_defined = 0;
size_module_instantiations = 0;
size_function_instantiations = 0;
function_instantiations_instance_by_module = NULL;
size_function_instantiations_by_module = 0;
block_instantiations_instance = NULL;
size_block_instantiations = 0;
/* keeps track of all the ast roots */
all_file_items_list = NULL;
size_all_file_items_list = 0;
}
/*---------------------------------------------------------------------------------------------
* (function: cleanup_parser)
*-------------------------------------------------------------------------------------------*/
void cleanup_parser()
{
long i;
/* frees all the defines for module string caches (used for parameters) */
if (num_modules > 0)
{
for (i = 0; i < num_modules; i++)
{
sc_free_string_cache(defines_for_module_sc[i]);
}
vtr::free(defines_for_module_sc);
}
}
/*---------------------------------------------------------------------------------------------
* (function: init_parser_for_file)
*-------------------------------------------------------------------------------------------*/
void init_parser_for_file()
{
/* crrate a hash for defines so we can look them up when we find them */
defines_for_module_sc = (STRING_CACHE**)vtr::realloc(defines_for_module_sc, sizeof(STRING_CACHE*)*(num_modules+1));
defines_for_module_sc[num_modules] = sc_new_string_cache();
/* create string caches to hookup PORTS with INPUT and OUTPUTs. This is made per module and will be cleaned and remade at next_module */
modules_inputs_sc = sc_new_string_cache();
modules_outputs_sc = sc_new_string_cache();
functions_inputs_sc = sc_new_string_cache();
functions_outputs_sc = sc_new_string_cache();
}
/*---------------------------------------------------------------------------------------------
* (function: clean_up_parser_for_file)
*-------------------------------------------------------------------------------------------*/
void cleanup_parser_for_file()
{
/* create string caches to hookup PORTS with INPUT and OUTPUTs. This is made per module and will be cleaned and remade at next_module */
modules_inputs_sc = sc_free_string_cache(modules_inputs_sc);
modules_outputs_sc = sc_free_string_cache(modules_outputs_sc);
functions_inputs_sc = sc_free_string_cache(functions_inputs_sc);
functions_outputs_sc = sc_free_string_cache(functions_outputs_sc);
}
/*---------------------------------------------------------------------------------------------
* (function: next_parsed_verilog_file)
*-------------------------------------------------------------------------------------------*/
void next_parsed_verilog_file(ast_node_t *file_items_list)
{
long i;
/* optimization entry point */
printf("Optimizing module by AST based optimizations\n");
cleanup_hard_blocks();
if (configuration.output_ast_graphs == 1)
{
/* IF - we want outputs for the graphViz files of each module */
for (i = 0; i < file_items_list->num_children; i++)
{
assert(file_items_list->children[i]);
graphVizOutputAst(configuration.debug_output_path, file_items_list->children[i]);
}
}
/* store the root of this files ast */
all_file_items_list = (ast_node_t**)vtr::realloc(all_file_items_list, sizeof(ast_node_t*)*(size_all_file_items_list+1));
all_file_items_list[size_all_file_items_list] = file_items_list;
size_all_file_items_list ++;
}
/*---------------------------------------------------------------------------------------------
* (function: newSymbolNode)
*-------------------------------------------------------------------------------------------*/
ast_node_t *newSymbolNode(char *id, int line_number)
{
return create_tree_node_id(id, line_number, current_parse_file);
}
/*---------------------------------------------------------------------------------------------
* (function: newNumberNode)
*-------------------------------------------------------------------------------------------*/
ast_node_t *newNumberNode(char *num, bases base, signedness sign, int line_number)
{
ast_node_t *current_node = create_tree_node_number(num, base, sign, line_number, current_parse_file);
vtr::free(num);
return current_node;
}
/*---------------------------------------------------------------------------------------------
* (function: newList)
*-------------------------------------------------------------------------------------------*/
ast_node_t *newList(ids node_type, ast_node_t *child)
{
/* create a node for this array reference */
ast_node_t* new_node = create_node_w_type(node_type, yylineno, current_parse_file);
/* allocate child nodes to this node */
allocate_children_to_node(new_node, 1, child);
return new_node;
}
ast_node_t *newfunctionList(ids node_type, ast_node_t *child)
{
/* create a output node for this array reference that is going to be the first child */
ast_node_t* output_node = create_node_w_type(IDENTIFIERS, yylineno, current_parse_file);
/* create a node for this array reference */
ast_node_t* new_node = create_node_w_type(node_type, yylineno, current_parse_file);
/* allocate child nodes to this node */
allocate_children_to_node(new_node, 2, output_node, child);
return new_node;
}
/*---------------------------------------------------------------------------------------------
* (function: newList_entry)
*-------------------------------------------------------------------------------------------*/
ast_node_t *newList_entry(ast_node_t *list, ast_node_t *child)
{
/* allocate child nodes to this node */
add_child_to_node(list, child);
return list;
}
/*---------------------------------------------------------------------------------------------
* (function: newListReplicate)
* Basically this functions emulates verilog replication: {5{1'b0}} by concatenating that many
* children together -- certainly not the most elegant solution, but was the easiest
*-------------------------------------------------------------------------------------------*/
ast_node_t *newListReplicate(ast_node_t *exp, ast_node_t *child)
{
/* create a node for this array reference */
ast_node_t* new_node = create_node_w_type(CONCATENATE, yylineno, current_parse_file);
new_node->types.concat.num_bit_strings = -1;
/* allocate child nodes to this node */
allocate_children_to_node(new_node, 1, child);
int i;
for (i = 1; i < exp->types.number.value; i++)
{
add_child_to_node(new_node, child);
}
return new_node;
}
static ast_node_t *resolve_symbol_node(ids top_type, ast_node_t *symbol_node)
{
ast_node_t *to_return = NULL;
switch(symbol_node->type)
{
case IDENTIFIERS:
{
ast_node_t *newNode = NULL;
if(top_type == MODULE)
{
long sc_spot = sc_lookup_string(defines_for_module_sc[num_modules-num_instances], symbol_node->types.identifier);
if(sc_spot != -1)
newNode = (ast_node_t *)defines_for_module_sc[num_modules-num_instances]->data[sc_spot];
}
else if(top_type == FUNCTION)
{
long sc_spot = sc_lookup_string(defines_for_function_sc[num_functions], symbol_node->types.identifier);
if (sc_spot != -1)
newNode = (ast_node_t *)defines_for_function_sc[num_functions]->data[sc_spot];
}
if (newNode && newNode->types.variable.is_parameter == TRUE)
{
to_return = symbol_node;
}
else
{
error_message(PARSE_ERROR, symbol_node->line_number, current_parse_file,
"no match for parameter %s\n", symbol_node->types.identifier);
}
break;
}
case NUMBERS:
case BINARY_OPERATION:
case UNARY_OPERATION:
{
to_return = symbol_node;
break;
}
default:
{
to_return = NULL;
break;
}
}
return to_return;
}
ast_node_t *resolve_ports(ids top_type, ast_node_t *symbol_list)
{
ast_node_t *unprocessed_ports = NULL;
long sc_spot;
for (long i = 0; i < symbol_list->num_children; i++)
{
if (symbol_list->children[i]->types.variable.is_port)
{
ast_node_t *this_port = symbol_list->children[i];
if (!unprocessed_ports)
{
unprocessed_ports = newList(VAR_DECLARE_LIST, this_port);
}
else
{
unprocessed_ports = newList_entry(unprocessed_ports, this_port);
}
/* grab and update all typeless ports immediately following this one */
long j = 0;
for (j = i + 1; j < symbol_list->num_children && !(symbol_list->children[j]->types.variable.is_port); j++)
{
/* port type */
symbol_list->children[j]->types.variable.is_input = this_port->types.variable.is_input;
symbol_list->children[j]->types.variable.is_output = this_port->types.variable.is_output;
symbol_list->children[j]->types.variable.is_inout = this_port->types.variable.is_inout;
/* net type */
symbol_list->children[j]->types.variable.is_wire = this_port->types.variable.is_wire;
symbol_list->children[j]->types.variable.is_reg = this_port->types.variable.is_reg;
symbol_list->children[j]->types.variable.is_integer = this_port->types.variable.is_integer;
/* range */
if (symbol_list->children[j]->children[1] == NULL)
{
symbol_list->children[j]->children[1] = this_port->children[1];
symbol_list->children[j]->children[2] = this_port->children[2];
symbol_list->children[j]->children[3] = this_port->children[3];
symbol_list->children[j]->children[4] = this_port->children[4];
if (this_port->num_children == 8)
{
symbol_list->children[j]->children = (ast_node_t**) realloc(symbol_list->children[j]->children, sizeof(ast_node_t*)*8);
symbol_list->children[j]->children[7] = symbol_list->children[j]->children[5];
symbol_list->children[j]->children[5] = this_port->children[5];
symbol_list->children[j]->children[6] = this_port->children[6];
}
}
/* error checking */
symbol_list->children[j] = markAndProcessPortWith(MODULE, NO_ID, NO_ID, symbol_list->children[j]);
}
}
else
{
if (top_type == MODULE)
{
/* find the related INPUT or OUTPUT definition and store that instead */
if ((sc_spot = sc_lookup_string(modules_inputs_sc, symbol_list->children[i]->children[0]->types.identifier)) != -1)
{
symbol_list->children[i]->types.variable.is_input = TRUE;
free_whole_tree(symbol_list->children[i]->children[0]);
symbol_list->children[i]->children[0] = (ast_node_t*)modules_inputs_sc->data[sc_spot];
}
else if ((sc_spot = sc_lookup_string(modules_outputs_sc, symbol_list->children[i]->children[0]->types.identifier)) != -1)
{
symbol_list->children[i]->types.variable.is_output = TRUE;
free_whole_tree(symbol_list->children[i]->children[0]);
symbol_list->children[i]->children[0] = (ast_node_t*)modules_outputs_sc->data[sc_spot];
}
else
{
error_message(PARSE_ERROR, symbol_list->children[i]->line_number, current_parse_file, "No matching declaration for port %s\n", symbol_list->children[i]->children[0]->types.identifier);
}
}
else if (top_type == FUNCTION)
{
/* find the related INPUT or OUTPUT definition and store that instead */
if ((sc_spot = sc_lookup_string(functions_inputs_sc, symbol_list->children[i]->children[0]->types.identifier)) != -1)
{
symbol_list->children[i]->types.variable.is_input = TRUE;
free_whole_tree(symbol_list->children[i]->children[0]);
symbol_list->children[i]->children[0] = (ast_node_t*)functions_inputs_sc->data[sc_spot];
}
else if ((sc_spot = sc_lookup_string(functions_outputs_sc, symbol_list->children[i]->children[0]->types.identifier)) != -1)
{
symbol_list->children[i]->types.variable.is_output = TRUE;
free_whole_tree(symbol_list->children[i]->children[0]);
symbol_list->children[i]->children[0] = (ast_node_t*)functions_outputs_sc->data[sc_spot];
}
else
{
error_message(PARSE_ERROR, symbol_list->children[i]->line_number, current_parse_file, "No matching declaration for port %s\n", symbol_list->children[i]->children[0]->types.identifier);
}
}
symbol_list->children[i]->types.variable.is_port = TRUE;
}
}
return unprocessed_ports;
}
ast_node_t *markAndProcessPortWith(ids top_type, ids port_id, ids net_id, ast_node_t *port)
{
long sc_spot;
STRING_CACHE *this_inputs_sc = NULL;
STRING_CACHE *this_outputs_sc = NULL;
const char *top_type_name = (top_type == MODULE) ? "Module" : "Function";
ids temp_net_id = NO_ID;
if (port->types.variable.is_port)
{
oassert(false && "Port was already marked");
}
if (top_type == MODULE)
{
this_inputs_sc = modules_inputs_sc;
this_outputs_sc = modules_outputs_sc;
}
else if (top_type == FUNCTION)
{
this_inputs_sc = functions_inputs_sc;
this_outputs_sc = functions_outputs_sc;
}
/* look for processed inputs with this name */
sc_spot = sc_lookup_string(this_inputs_sc, port->children[0]->types.identifier);
if (sc_spot > -1 && ((ast_node_t*)this_inputs_sc->data[sc_spot])->types.variable.is_port)
{
error_message(PARSE_ERROR, port->line_number, current_parse_file, "%s already has input with this name %s\n",
top_type_name, ((ast_node_t*)this_inputs_sc->data[sc_spot])->children[0]->types.identifier);
}
/* look for processed outputs with this name */
sc_spot = sc_lookup_string(this_outputs_sc, port->children[0]->types.identifier);
if (sc_spot > -1 && ((ast_node_t*)this_outputs_sc->data[sc_spot])->types.variable.is_port)
{
error_message(PARSE_ERROR, port->line_number, current_parse_file, "%s already has output with this name %s\n",
top_type_name, ((ast_node_t*)this_outputs_sc->data[sc_spot])->children[0]->types.identifier);
}
switch (net_id)
{
case REG:
if (port_id == INPUT)
{
error_message(NETLIST_ERROR, port->line_number, port->file_number, "%s",
"Input cannot be defined as a reg\n");
}
if (port_id == INOUT)
{
error_message(NETLIST_ERROR, port->line_number, port->file_number, "%s",
"Inout cannot be defined as a reg\n");
}
port->types.variable.is_reg = TRUE;
port->types.variable.is_wire = FALSE;
port->types.variable.is_integer = FALSE;
break;
case INTEGER:
if (port_id == INPUT)
{
error_message(NETLIST_ERROR, port->line_number, port->file_number, "%s",
"Input cannot be defined as an integer\n");
}
if (port_id == INOUT)
{
error_message(NETLIST_ERROR, port->line_number, port->file_number, "%s",
"Inout cannot be defined as an integer\n");
}
port->types.variable.is_integer = TRUE;
port->types.variable.is_reg = FALSE;
port->types.variable.is_wire = FALSE;
break;
case WIRE:
if (port->children[5] != NULL)
{
error_message(NETLIST_ERROR, port->line_number, port->file_number, "%s",
"Ports of type net cannot be initialized\n");
}
port->types.variable.is_wire = TRUE;
port->types.variable.is_reg = FALSE;
port->types.variable.is_integer = FALSE;
break;
default:
if (port->children[5] != NULL)
{
error_message(NETLIST_ERROR, port->line_number, port->file_number, "%s",
"Ports with undefined type cannot be initialized\n");
}
if (port->types.variable.is_reg
&& !(port->types.variable.is_wire)
&& !(port->types.variable.is_integer))
{
temp_net_id = REG;
}
else if (port->types.variable.is_integer
&& !(port->types.variable.is_wire)
&& !(port->types.variable.is_reg))
{
temp_net_id = INTEGER;
}
else if (port->types.variable.is_wire
&& !(port->types.variable.is_reg)
&& !(port->types.variable.is_integer))
{
temp_net_id = WIRE;
}
else
{
/* port cannot have more than one type */
oassert(!(port->types.variable.is_wire) &&
!(port->types.variable.is_reg) &&
!(port->types.variable.is_integer));
}
if (net_id == NO_ID)
{
/* will be marked later */
net_id = temp_net_id;
}
break;
}
switch (port_id)
{
case INPUT:
port->types.variable.is_input = TRUE;
port->types.variable.is_output = FALSE;
port->types.variable.is_inout = FALSE;
/* add this input to the modules string cache */
sc_spot = sc_add_string(this_inputs_sc, port->children[0]->types.identifier);
/* store the data which is an idx here */
this_inputs_sc->data[sc_spot] = (void*)port;
break;
case OUTPUT:
port->types.variable.is_output = TRUE;
port->types.variable.is_input = FALSE;
port->types.variable.is_inout = FALSE;
/* add this output to the modules string cache */
sc_spot = sc_add_string(this_outputs_sc, port->children[0]->types.identifier);
/* store the data which is an idx here */
this_outputs_sc->data[sc_spot] = (void*)port;
break;
case INOUT:
port->types.variable.is_inout = TRUE;
port->types.variable.is_input = FALSE;
port->types.variable.is_output = FALSE;
error_message(PARSE_ERROR, port->line_number, current_parse_file, "Odin does not handle inouts (%s)\n", port->children[0]->types.identifier);
break;
default:
if (port->types.variable.is_input
&& !(port->types.variable.is_output)
&& !(port->types.variable.is_inout))
{
port = markAndProcessPortWith(top_type, INPUT, net_id, port);
}
else if (port->types.variable.is_output
&& !(port->types.variable.is_input)
&& !(port->types.variable.is_inout))
{
port = markAndProcessPortWith(top_type, OUTPUT, net_id, port);
}
else if (port->types.variable.is_inout
&& !(port->types.variable.is_input)
&& !(port->types.variable.is_output))
{
error_message(PARSE_ERROR, port->line_number, current_parse_file, "Odin does not handle inouts (%s)\n", port->children[0]->types.identifier);
port = markAndProcessPortWith(top_type, INOUT, net_id, port);
}
else
{
// shouldn't ever get here...
oassert(port->types.variable.is_input
|| port->types.variable.is_output
|| port->types.variable.is_inout);
}
break;
}
port->types.variable.is_port = TRUE;
return port;
}
ast_node_t *markAndProcessParameterWith(ids top_type, ids id, ast_node_t *parameter)
{
long sc_spot;
STRING_CACHE **this_defines_sc = NULL;
long this_num_modules = 0;
const char *id_name = (id == PARAMETER) ? "Parameter" : "Localparam";
if (top_type == MODULE)
{
this_defines_sc = defines_for_module_sc;
this_num_modules = num_modules-num_instances;
}
else if (top_type == FUNCTION)
{
this_defines_sc = defines_for_function_sc;
this_num_modules = num_functions;
}
/* create an entry in the symbol table for this parameter */
if ((sc_spot = sc_lookup_string(this_defines_sc[this_num_modules], parameter->children[0]->types.identifier)) > -1)
{
error_message(PARSE_ERROR, parameter->children[5]->line_number, current_parse_file, "Module already has parameter with this name (%s)\n",
parameter->children[0]->types.identifier);
}
sc_spot = sc_add_string(this_defines_sc[this_num_modules], parameter->children[0]->types.identifier);
ast_node_t *value = parameter->children[5];
/* make sure that the parameter value is constant */
if (!node_is_ast_constant(value, this_defines_sc[this_num_modules]))
{
error_message(PARSE_ERROR, parameter->children[5]->line_number, current_parse_file, "%s value must be constant\n", id_name);
}
this_defines_sc[this_num_modules]->data[sc_spot] = (void*)parameter->children[5];
/* mark the node as shared so we don't delete it */
parameter->children[5]->shared_node = TRUE;
if (id == PARAMETER)
{
parameter->children[5]->types.variable.is_parameter = TRUE;
parameter->types.variable.is_parameter = TRUE;
}
else if (id == LOCALPARAM)
{
parameter->children[5]->types.variable.is_localparam = TRUE;
parameter->types.variable.is_localparam = TRUE;
}
return parameter;
}
ast_node_t *markAndProcessSymbolListWith(ids top_type, ids id, ast_node_t *symbol_list)
{
long i;
ast_node_t *range_min = 0;
ast_node_t *range_max = 0;
if(symbol_list && symbol_list->children[0] && symbol_list->children[0]->children[1])
{
range_max = resolve_symbol_node(top_type, symbol_list->children[0]->children[1]);
range_min = resolve_symbol_node(top_type, symbol_list->children[0]->children[2]);
}
for (i = 0; i < symbol_list->num_children; i++)
{
if ((symbol_list->children[i]->children[1] == NULL) && (symbol_list->children[i]->children[2] == NULL))
{
symbol_list->children[i]->children[1] = range_max;
symbol_list->children[i]->children[2] = range_min;
}
if(top_type == MODULE) {
switch(id)
{
case PARAMETER:
case LOCALPARAM:
{
markAndProcessParameterWith(top_type, id, symbol_list->children[i]);
break;
}
case INPUT:
case OUTPUT:
case INOUT:
symbol_list->children[i] = markAndProcessPortWith(top_type, id, NO_ID, symbol_list->children[i]);
break;
case WIRE:
if (symbol_list->children[i]->children[5] != NULL)
{
error_message(NETLIST_ERROR, symbol_list->children[i]->line_number, symbol_list->children[i]->file_number, "%s",
"Nets cannot be initialized\n");
}
symbol_list->children[i]->types.variable.is_wire = TRUE;
break;
case REG:
symbol_list->children[i]->types.variable.is_reg = TRUE;
break;
case INTEGER:
case GENVAR:
symbol_list->children[i]->types.variable.is_integer = TRUE;
break;
default:
oassert(FALSE);
}
}
else if(top_type == FUNCTION) {
switch(id)
{
case PARAMETER:
case LOCALPARAM:
{
markAndProcessParameterWith(top_type, id, symbol_list->children[i]);
break;
}
case INPUT:
case OUTPUT:
case INOUT:
symbol_list->children[i] = markAndProcessPortWith(top_type, id, NO_ID, symbol_list->children[i]);
break;
case WIRE:
if (symbol_list->children[i]->children[5] != NULL)
{
error_message(NETLIST_ERROR, symbol_list->children[i]->line_number, symbol_list->children[i]->file_number, "%s",
"Nets cannot be initialized\n");
}
symbol_list->children[i]->types.variable.is_wire = TRUE;
break;
case REG:
symbol_list->children[i]->types.variable.is_reg = TRUE;
break;
case INTEGER:
symbol_list->children[i]->types.variable.is_integer = TRUE;
break;
default:
oassert(FALSE);
}
}
}
return symbol_list;
}
/*---------------------------------------------------------------------------------------------
* (function: newArrayRef)
*-------------------------------------------------------------------------------------------*/
ast_node_t *newArrayRef(char *id, ast_node_t *expression, int line_number)
{
/* allocate or check if there's a node for this */
ast_node_t *symbol_node = newSymbolNode(id, line_number);
/* create a node for this array reference */
ast_node_t* new_node = create_node_w_type(ARRAY_REF, line_number, current_parse_file);
/* allocate child nodes to this node */
allocate_children_to_node(new_node, 2, symbol_node, expression);
return new_node;
}
/*---------------------------------------------------------------------------------------------
* (function: newRangeRef)
*-------------------------------------------------------------------------------------------*/
ast_node_t *newRangeRef(char *id, ast_node_t *expression1, ast_node_t *expression2, int line_number)
{
/* allocate or check if there's a node for this */
ast_node_t *symbol_node = newSymbolNode(id, line_number);
/* create a node for this array reference */
ast_node_t* new_node = create_node_w_type(RANGE_REF, line_number, current_parse_file);
/* allocate child nodes to this node */
allocate_children_to_node(new_node, 3, symbol_node, expression1, expression2);
return new_node;
}
/*---------------------------------------------------------------------------------------------
* (function: newPartSelectRangeRef)
*
* NB!! only support [msb:lsb], will always resolve to this syntax
*-------------------------------------------------------------------------------------------*/
ast_node_t *newMinusColonRangeRef(char *id, ast_node_t *expression1, ast_node_t *expression2, int line_number)
{
ast_node_t *msb = NULL;
ast_node_t *lsb = NULL;
if ( expression1 == NULL )
{
error_message(PARSE_ERROR, line_number, current_parse_file,
"first expression for range ref is NULL %s", id);
}
else if ( expression2 == NULL )
{
error_message(PARSE_ERROR, line_number, current_parse_file,
"first expression for range ref is NULL %s", id);
}
// expression 1 is the msb here since we subtract expression 2 from it
msb = expression1;
ast_node_t *number_one = create_tree_node_long_number(1, ODIN_STD_BITWIDTH, line_number, current_parse_file);
ast_node_t *size_to_index = newBinaryOperation(MINUS, expression2, number_one, line_number);
lsb = newBinaryOperation(MINUS, ast_node_deep_copy(expression1), size_to_index, line_number);
return newRangeRef(id, msb, lsb, line_number);
}
/*---------------------------------------------------------------------------------------------
* (function: newPartSelectRangeRef)
*
* NB!! only support [msb:lsb], will always resolve to this syntax
*-------------------------------------------------------------------------------------------*/
ast_node_t *newPlusColonRangeRef(char *id, ast_node_t *expression1, ast_node_t *expression2, int line_number)
{
ast_node_t *msb = NULL;
ast_node_t *lsb = NULL;
if ( expression1 == NULL )
{
error_message(PARSE_ERROR, line_number, current_parse_file,
"first expression for range ref is NULL %s", id);
}
else if ( expression2 == NULL )
{
error_message(PARSE_ERROR, line_number, current_parse_file,
"first expression for range ref is NULL %s", id);
}
// expression 1 is the lsb here since we add expression 2 to it
lsb = expression1;
ast_node_t *number_one = create_tree_node_long_number(1, ODIN_STD_BITWIDTH, line_number, current_parse_file);
ast_node_t *size_to_index = newBinaryOperation(MINUS, expression2, number_one, line_number);
msb = newBinaryOperation(ADD, ast_node_deep_copy(expression1), size_to_index, line_number);
return newRangeRef(id, msb, lsb, line_number);
}
/*---------------------------------------------------------------------------------------------
* (function: newBinaryOperation)
*-------------------------------------------------------------------------------------------*/
ast_node_t *newBinaryOperation(operation_list op_id, ast_node_t *expression1, ast_node_t *expression2, int line_number)
{
/* create a node for this array reference */
ast_node_t* new_node = create_node_w_type(BINARY_OPERATION, line_number, current_parse_file);
/* store the operation type */
new_node->types.operation.op = op_id;
/* allocate child nodes to this node */
allocate_children_to_node(new_node, 2, expression1, expression2);
/* see if this binary expression can have some constant folding */
new_node = resolve_ast_node(defines_for_module_sc[num_modules-num_instances],TRUE,NULL,new_node);
return new_node;
}
ast_node_t *newExpandPower(operation_list op_id, ast_node_t *expression1, ast_node_t *expression2, int line_number)
{
/* create a node for this array reference */
ast_node_t* new_node, *node;
ast_node_t *node_copy;
/* avoid uninitialized warning */
new_node = NULL;
/* allocate child nodes to this node */
if( expression2->type == NUMBERS ){
int len = expression2->types.number.value;
if( expression1->type == NUMBERS ){
int len1 = expression1->types.number.value;
long powRes = pow(len1, len);
new_node = create_tree_node_long_number(powRes,ODIN_STD_BITWIDTH, line_number, current_parse_file);
} else {
if (len == 0){
new_node = create_tree_node_long_number(1, ODIN_STD_BITWIDTH, line_number, current_parse_file);
} else {
new_node = expression1;
for(int i=1; i < len; ++i){
node = create_node_w_type(BINARY_OPERATION, line_number, current_parse_file);
node->types.operation.op = op_id;
node_copy = ast_node_deep_copy(expression1);
allocate_children_to_node(node, 2, node_copy, new_node);
new_node = node;
}
}
}
}
else
{
error_message(NETLIST_ERROR, line_number, current_parse_file, "%s", "Operation not supported by Odin\n");
}
/* see if this binary expression can have some constant folding */
new_node = resolve_ast_node(defines_for_module_sc[num_modules-num_instances],TRUE,NULL,new_node);
return new_node;
}
/*---------------------------------------------------------------------------------------------
* (function: newUnaryOperation)
*-------------------------------------------------------------------------------------------*/
ast_node_t *newUnaryOperation(operation_list op_id, ast_node_t *expression, int line_number)
{
/* $clog2() argument must be a constant expression */
if (op_id == CLOG2 && !node_is_ast_constant(expression, defines_for_module_sc[num_modules-num_instances]))
error_message(PARSE_ERROR, expression->line_number, current_parse_file, "%s", "Argument must be constant\n");
/* create a node for this array reference */
ast_node_t* new_node = create_node_w_type(UNARY_OPERATION, line_number, current_parse_file);
/* store the operation type */
new_node->types.operation.op = op_id;
/* allocate child nodes to this node */
allocate_children_to_node(new_node, 1, expression);
/* see if this binary expression can have some constant folding */
new_node = resolve_ast_node(defines_for_module_sc[num_modules-num_instances],TRUE,NULL,new_node);
return new_node;
}
/*---------------------------------------------------------------------------------------------
* (function: newNegedgeSymbol)
*-------------------------------------------------------------------------------------------*/
ast_node_t *newNegedgeSymbol(char *symbol, int line_number)
{
/* get the symbol node */
ast_node_t *symbol_node = newSymbolNode(symbol, line_number);
/* create a node for this array reference */
ast_node_t* new_node = create_node_w_type(NEGEDGE, line_number, current_parse_file);
/* allocate child nodes to this node */
allocate_children_to_node(new_node, 1, symbol_node);
return new_node;
}
/*---------------------------------------------------------------------------------------------
* (function: newPosedgeSymbol)
*-------------------------------------------------------------------------------------------*/
ast_node_t *newPosedgeSymbol(char *symbol, int line_number)
{
/* get the symbol node */
ast_node_t *symbol_node = newSymbolNode(symbol, line_number);
/* create a node for this array reference */
ast_node_t* new_node = create_node_w_type(POSEDGE, line_number, current_parse_file);
/* allocate child nodes to this node */
allocate_children_to_node(new_node, 1, symbol_node);
return new_node;
}
/*---------------------------------------------------------------------------------------------
* (function: newCaseItem)
*-------------------------------------------------------------------------------------------*/
ast_node_t *newCaseItem(ast_node_t *expression, ast_node_t *statement, int line_number)
{
/* create a node for this array reference */
ast_node_t* new_node = create_node_w_type(CASE_ITEM, line_number, current_parse_file);
/* allocate child nodes to this node */
allocate_children_to_node(new_node, 2, expression, statement);
return new_node;
}
/*---------------------------------------------------------------------------------------------
* (function: newDefaultCase)
*-------------------------------------------------------------------------------------------*/
ast_node_t *newDefaultCase(ast_node_t *statement, int line_number)
{
/* create a node for this array reference */
ast_node_t* new_node = create_node_w_type(CASE_DEFAULT, line_number, current_parse_file);
/* allocate child nodes to this node */
allocate_children_to_node(new_node, 1, statement);
return new_node;
}
/*---------------------------------------------------------------------------------------------
* (function: newNonBlocking)
*-------------------------------------------------------------------------------------------*/
ast_node_t *newParallelConnection(ast_node_t *expression1, ast_node_t *expression2, int line_number)
{
/* create a node for this array reference */
ast_node_t* new_node = create_node_w_type(SPECIFY_PAL_CONNECTION_STATEMENT, line_number, current_parse_file);
/* allocate child nodes to this node */
allocate_children_to_node(new_node, 2, expression1, expression2);
return new_node;
}
/*---------------------------------------------------------------------------------------------
* (function: newNonBlocking)
*-------------------------------------------------------------------------------------------*/
ast_node_t *newNonBlocking(ast_node_t *expression1, ast_node_t *expression2, int line_number)
{
/* create a node for this array reference */
ast_node_t* new_node = create_node_w_type(NON_BLOCKING_STATEMENT, line_number, current_parse_file);
/* allocate child nodes to this node */
allocate_children_to_node(new_node, 2, expression1, expression2);
return new_node;
}
/*---------------------------------------------------------------------------------------------
* (function: newInitial)
*-------------------------------------------------------------------------------------------*/
ast_node_t *newInitial(ast_node_t *expression1, int line_number)
{
/* create a node for this array reference */
ast_node_t* new_node = create_node_w_type(INITIALS, line_number, current_parse_file);
/* allocate child nodes to this node */
allocate_children_to_node(new_node, 1, expression1);
return new_node;
}
/*---------------------------------------------------------------------------------------------
* (function: newBlocking)
*-------------------------------------------------------------------------------------------*/
ast_node_t *newBlocking(ast_node_t *expression1, ast_node_t *expression2, int line_number)
{
/* create a node for this array reference */
ast_node_t* new_node = create_node_w_type(BLOCKING_STATEMENT, line_number, current_parse_file);
/* allocate child nodes to this node */
allocate_children_to_node(new_node, 2, expression1, expression2);
return new_node;
}
/*---------------------------------------------------------------------------------------------
* (function: newBlocking)
*-------------------------------------------------------------------------------------------*/
ast_node_t *newFunctionAssigning(ast_node_t *expression1, ast_node_t *expression2, int line_number)
{
char *label;
ast_node_t *node;
label = (char *)vtr::calloc(strlen(expression1->types.identifier)+10,sizeof(char));
strcpy(label,expression1->types.identifier);
node = newSymbolNode(label,line_number);
expression2->children[1]->children[1]->children[0] = newModuleConnection(NULL, node, line_number);
/* create a node for this array reference */
ast_node_t* new_node = create_node_w_type(BLOCKING_STATEMENT, line_number, current_parse_file);
/* allocate child nodes to this node */
allocate_children_to_node(new_node, 2, expression1, expression2);
return new_node;
}
/*---------------------------------------------------------------------------------------------
* (function: newFor)
*-------------------------------------------------------------------------------------------*/
ast_node_t *newFor(ast_node_t *initial, ast_node_t *compare_expression, ast_node_t *terminal, ast_node_t *statement, int line_number)
{
/* create a node for this for reference */
ast_node_t* new_node = create_node_w_type(FOR, line_number, current_parse_file);
/* allocate child nodes to this node */
allocate_children_to_node(new_node, 4, initial, compare_expression, terminal, statement);
return new_node;
}
/*---------------------------------------------------------------------------------------------
* (function: newWhile)
*-------------------------------------------------------------------------------------------*/
ast_node_t *newWhile(ast_node_t *compare_expression, ast_node_t *statement, int line_number)
{
/* create a node for this for reference */
ast_node_t* new_node = create_node_w_type(WHILE, line_number, current_parse_file);
/* allocate child nodes to this node */
allocate_children_to_node(new_node, 2, compare_expression, statement);
/* This needs to be removed once support is added */
error_message(PARSE_ERROR, line_number, current_parse_file, "%s", "While statements are NOT supported");
return new_node;
}
/*---------------------------------------------------------------------------------------------
* (function: newIf)
*-------------------------------------------------------------------------------------------*/
ast_node_t *newIf(ast_node_t *compare_expression, ast_node_t *true_expression, ast_node_t *false_expression, int line_number)
{
/* create a node for this array reference */
ast_node_t* new_node = create_node_w_type(IF, line_number, current_parse_file);
/* allocate child nodes to this node */
allocate_children_to_node(new_node, 3, compare_expression, true_expression, false_expression);
return new_node;
}
/*---------------------------------------------------------------------------------------------
* (function: newIfQuestion) for f = a ? b : c;
*-------------------------------------------------------------------------------------------*/
ast_node_t *newIfQuestion(ast_node_t *compare_expression, ast_node_t *true_expression, ast_node_t *false_expression, int line_number)
{
/* create a node for this array reference */
ast_node_t* new_node = create_node_w_type(IF_Q, line_number, current_parse_file);
/* allocate child nodes to this node */
allocate_children_to_node(new_node, 3, compare_expression, true_expression, false_expression);
return new_node;
}
/*---------------------------------------------------------------------------------------------
* (function: newCase)
*-------------------------------------------------------------------------------------------*/
ast_node_t *newCase(ast_node_t *compare_expression, ast_node_t *case_list, int line_number)
{
/* create a node for this array reference */
ast_node_t* new_node = create_node_w_type(CASE, line_number, current_parse_file);
/* allocate child nodes to this node */
allocate_children_to_node(new_node, 2, compare_expression, case_list);
return new_node;
}
/*---------------------------------------------------------------------------------------------
* (function: newAlways)
*-------------------------------------------------------------------------------------------*/
ast_node_t *newAlways(ast_node_t *delay_control, ast_node_t *statement, int line_number)
{
/* create a node for this array reference */
ast_node_t* new_node = create_node_w_type(ALWAYS, line_number, current_parse_file);
/* allocate child nodes to this node */
allocate_children_to_node(new_node, 2, delay_control, statement);
return new_node;
}
/*---------------------------------------------------------------------------------------------
* (function: newGenerate)
*-------------------------------------------------------------------------------------------*/
ast_node_t *newGenerate(ast_node_t *instantiations, int line_number)
{
/* create a node for this array reference */
ast_node_t* new_node = create_node_w_type(GENERATE, line_number, current_parse_file);
/* allocate child nodes to this node */
allocate_children_to_node(new_node, 1, instantiations);
return new_node;
}
/*---------------------------------------------------------------------------------------------
* (function: newModuleConnection)
*-------------------------------------------------------------------------------------------*/
ast_node_t *newModuleConnection(char* id, ast_node_t *expression, int line_number)
{
ast_node_t *symbol_node;
/* create a node for this array reference */
ast_node_t* new_node = create_node_w_type(MODULE_CONNECT, line_number, current_parse_file);
if (id != NULL)
{
symbol_node = newSymbolNode(id, line_number);
}
else
{
symbol_node = NULL;
}
/* allocate child nodes to this node */
allocate_children_to_node(new_node, 2, symbol_node, expression);
return new_node;
}
/*---------------------------------------------------------------------------------------------
* (function: newModuleParameter)
*-------------------------------------------------------------------------------------------*/
ast_node_t *newModuleParameter(char* id, ast_node_t *expression, int line_number)
{
ast_node_t *symbol_node;
/* create a node for this array reference */
ast_node_t* new_node = create_node_w_type(MODULE_PARAMETER, line_number, current_parse_file);
if (id != NULL)
{
symbol_node = newSymbolNode(id, line_number);
}
else
{
symbol_node = NULL;
}
if (expression && !node_is_ast_constant(expression, defines_for_module_sc[num_modules-num_instances]))
{
error_message(PARSE_ERROR, line_number, current_parse_file, "%s", "Parameter value must be constant\n");
}
/* allocate child nodes to this node */
// leave 4 blank nodes so that expression is the 6th node to behave just like
// a default var_declare parameter (see create_symbol_table_for_module)
allocate_children_to_node(new_node, 6, symbol_node, NULL, NULL, NULL, NULL, expression);
// set is_parameter for the same reason
new_node->types.variable.is_parameter = TRUE;
return new_node;
}
/*---------------------------------------------------------------------------------------------
* (function: newModuleNamedInstance)
*-------------------------------------------------------------------------------------------*/
ast_node_t *newModuleNamedInstance(char* unique_name, ast_node_t *module_connect_list, ast_node_t *module_parameter_list, int line_number)
{
ast_node_t *symbol_node = newSymbolNode(unique_name, line_number);
/* create a node for this array reference */
ast_node_t* new_node = create_node_w_type(MODULE_NAMED_INSTANCE, line_number, current_parse_file);
/* allocate child nodes to this node */
allocate_children_to_node(new_node, 3, symbol_node, module_connect_list, module_parameter_list);
return new_node;
}
/*---------------------------------------------------------------------------------------------
* (function: newModuleNamedInstance)
*-------------------------------------------------------------------------------------------*/
ast_node_t *newFunctionNamedInstance(ast_node_t *module_connect_list, ast_node_t *module_parameter_list, int line_number)
{
char *unique_name, *aux_name;
int char_qntd = 100;
aux_name = (char *)vtr::calloc(char_qntd,sizeof(char));
unique_name = (char *)vtr::calloc(char_qntd,sizeof(char));
strcpy(unique_name,"function_instance_");
odin_sprintf(aux_name,"%ld",size_function_instantiations_by_module);
strcat(unique_name,aux_name);
ast_node_t *symbol_node = newSymbolNode(unique_name, line_number);
/* create a node for this array reference */
ast_node_t* new_node = create_node_w_type(FUNCTION_NAMED_INSTANCE, line_number, current_parse_file);
/* allocate child nodes to this node */
allocate_children_to_node(new_node, 3, symbol_node, module_connect_list, module_parameter_list);
return new_node;
}
/*-------------------------------------------------------------------------
* (function: newHardBlockInstance)
*-----------------------------------------------------------------------*/
ast_node_t *newHardBlockInstance(char* module_ref_name, ast_node_t *module_named_instance, int line_number)
{
ast_node_t *symbol_node = newSymbolNode(module_ref_name, line_number);
// create a node for this array reference
ast_node_t* new_node = create_node_w_type(HARD_BLOCK, line_number, current_parse_file);
// allocate child nodes to this node
allocate_children_to_node(new_node, 2, symbol_node, module_named_instance);
// store the hard block symbol name that this calls in a list that will at the end be asociated with the hard block node
block_instantiations_instance = (ast_node_t **)vtr::realloc(block_instantiations_instance, sizeof(ast_node_t*)*(size_block_instantiations+1));
block_instantiations_instance[size_block_instantiations] = new_node;
size_block_instantiations++;
return new_node;
}
/*-------------------------------------------------------------------------
* (function: newModuleInstance)
*-----------------------------------------------------------------------*/
ast_node_t *newModuleInstance(char* module_ref_name, ast_node_t *module_named_instance, int line_number)
{
long i;
/* create a node for this array reference */
ast_node_t* new_master_node = create_node_w_type(MODULE_INSTANCE, line_number, current_parse_file);
for(i = 0; i < module_named_instance->num_children; i++){
if
(
sc_lookup_string(hard_block_names, module_ref_name) != -1
|| !strcmp(module_ref_name, SINGLE_PORT_RAM_string)
|| !strcmp(module_ref_name, DUAL_PORT_RAM_string)
)
{
return newHardBlockInstance(module_ref_name, module_named_instance->children[i], line_number);
}
// make a unique module name based on its parameter list
ast_node_t *module_param_list = module_named_instance->children[i]->children[2];
char *module_param_name = make_module_param_name(defines_for_module_sc[num_modules-num_instances], module_param_list, module_ref_name);
ast_node_t *symbol_node = newSymbolNode(module_param_name, line_number);
// if this is a parameterised instantiation
if (module_param_list)
{
// which doesn't exist in ast_modules yet
long sc_spot;
if ((sc_spot = sc_lookup_string(module_names_to_idx, module_param_name)) == -1)
{
// then add it, but set it to the symbol_node, because the
// module in question may not have been parsed yet
// later, we convert this symbol node back into a module node
ast_modules = (ast_node_t **)vtr::realloc(ast_modules, sizeof(ast_node_t*)*(num_modules+1));
ast_modules[num_modules] = symbol_node;
num_modules++;
num_instances++;
sc_spot = sc_add_string(module_names_to_idx, module_param_name);
module_names_to_idx->data[sc_spot] = symbol_node;
defines_for_module_sc = (STRING_CACHE**)vtr::realloc(defines_for_module_sc, sizeof(STRING_CACHE*)*(num_modules+1));
defines_for_module_sc[num_modules] = NULL;
}
}
/* create a node for this array reference */
ast_node_t* new_node = create_node_w_type(MODULE_INSTANCE, line_number, current_parse_file);
/* allocate child nodes to this node */
allocate_children_to_node(new_node, 2, symbol_node, module_named_instance->children[i]);
if(i == 0) allocate_children_to_node(new_master_node, 1, new_node);
else add_child_to_node(new_master_node,new_node);
/* store the module symbol name that this calls in a list that will at the end be asociated with the module node */
module_instantiations_instance = (ast_node_t **)vtr::realloc(module_instantiations_instance, sizeof(ast_node_t*)*(size_module_instantiations+1));
module_instantiations_instance[size_module_instantiations] = ast_node_deep_copy(new_node);
size_module_instantiations++;
}
//TODO: free_whole_tree ??
vtr::free(module_named_instance->children);
vtr::free(module_named_instance);
vtr::free(module_ref_name);
return new_master_node;
}
/*-------------------------------------------------------------------------
* (function: newFunctionInstance)
*-----------------------------------------------------------------------*/
ast_node_t *newFunctionInstance(char* function_ref_name, ast_node_t *function_named_instance, int line_number)
{
if
(
sc_lookup_string(hard_block_names, function_ref_name) != -1
|| !strcmp(function_ref_name, SINGLE_PORT_RAM_string)
|| !strcmp(function_ref_name, DUAL_PORT_RAM_string)
)
{
return newHardBlockInstance(function_ref_name, function_named_instance, line_number);
}
// make a unique module name based on its parameter list
ast_node_t *function_param_list = function_named_instance->children[2];
char *function_param_name = make_module_param_name(defines_for_module_sc[num_modules-num_instances], function_param_list, function_ref_name);
ast_node_t *symbol_node = newSymbolNode(function_param_name, line_number);
/* create a node for this array reference */
ast_node_t* new_node = create_node_w_type(FUNCTION_INSTANCE, line_number, current_parse_file);
/* allocate child nodes to this node */
allocate_children_to_node(new_node, 2, symbol_node, function_named_instance);
/* store the module symbol name that this calls in a list that will at the end be asociated with the module node */
function_instantiations_instance_by_module = (ast_node_t **)vtr::realloc(function_instantiations_instance_by_module, sizeof(ast_node_t*)*(size_function_instantiations_by_module+1));
function_instantiations_instance_by_module[size_function_instantiations_by_module] = new_node;
size_function_instantiations_by_module++;
return new_node;
}
/*---------------------------------------------------------------------------------------------
* (function: newGateInstance)
*-------------------------------------------------------------------------------------------*/
ast_node_t *newGateInstance(char* gate_instance_name, ast_node_t *expression1, ast_node_t *expression2, ast_node_t *expression3, int line_number)
{
/* create a node for this array reference */
ast_node_t* new_node = create_node_w_type(GATE_INSTANCE, line_number, current_parse_file);
ast_node_t *symbol_node = NULL;
if (gate_instance_name != NULL)
{
symbol_node = newSymbolNode(gate_instance_name, line_number);
}
char *newChar;
newChar = (char *)vtr::calloc(strlen(expression1->types.identifier)+10,sizeof(char));
strcpy(newChar,expression1->types.identifier);
ast_node_t *newVar = newVarDeclare(newChar, NULL, NULL, NULL, NULL, NULL, line_number);
ast_node_t *newVarList = newList(VAR_DECLARE_LIST, newVar);
ast_node_t *newVarMaked = markAndProcessSymbolListWith(MODULE,WIRE, newVarList);
if(size_module_variables_not_defined == 0){
module_variables_not_defined = (ast_node_t **)vtr::calloc(1, sizeof(ast_node_t*));
}
else{
module_variables_not_defined = (ast_node_t **)vtr::realloc(module_variables_not_defined, sizeof(ast_node_t*)*(size_module_variables_not_defined+1));
}
module_variables_not_defined[size_module_variables_not_defined] = newVarMaked;
size_module_variables_not_defined++;
/* allocate child nodes to this node */
allocate_children_to_node(new_node, 4, symbol_node, expression1, expression2, expression3);
return new_node;
}
ast_node_t *newMultipleInputsGateInstance(char* gate_instance_name, ast_node_t *expression1, ast_node_t *expression2, ast_node_t *expression3, int line_number)
{
long i;
/* create a node for this array reference */
ast_node_t* new_node = create_node_w_type(GATE_INSTANCE, line_number, current_parse_file);
ast_node_t* symbol_node = NULL;
if (gate_instance_name != NULL)
{
symbol_node = newSymbolNode(gate_instance_name, line_number);
}
char *newChar;
newChar = (char *)vtr::calloc(strlen(expression1->types.identifier)+10,sizeof(char));
strcpy(newChar,expression1->types.identifier);
ast_node_t *newVar = newVarDeclare(newChar, NULL, NULL, NULL, NULL, NULL, line_number);
ast_node_t *newVarList = newList(VAR_DECLARE_LIST, newVar);
ast_node_t *newVarMarked = markAndProcessSymbolListWith(MODULE, WIRE, newVarList);
if(size_module_variables_not_defined == 0){
module_variables_not_defined = (ast_node_t **)vtr::calloc(1, sizeof(ast_node_t*));
}
else{
module_variables_not_defined = (ast_node_t **)vtr::realloc(module_variables_not_defined, sizeof(ast_node_t*)*(size_module_variables_not_defined+1));
}
module_variables_not_defined[size_module_variables_not_defined] = newVarMarked;
size_module_variables_not_defined++;
allocate_children_to_node(new_node, 3, symbol_node, expression1, expression2);
/* allocate n children nodes to this node */
for(i = 1; i < expression3->num_children; i++) add_child_to_node(new_node, expression3->children[i]);
/* clean up */
if (expression3->type == MODULE_CONNECT) expression3 = free_single_node(expression3);
return new_node;
}
/*---------------------------------------------------------------------------------------------
* (function: newGate)
*-------------------------------------------------------------------------------------------*/
ast_node_t *newGate(operation_list op_id, ast_node_t *gate_instance, int line_number)
{
/* create a node for this array reference */
ast_node_t* new_node = create_node_w_type(GATE, line_number, current_parse_file);
/* store the operation type */
new_node->types.operation.op = op_id;
/* allocate child nodes to this node */
allocate_children_to_node(new_node, 1, gate_instance);
return new_node;
}
/*---------------------------------------------------------------------------------------------
* (function: newVarDeclare)
*-------------------------------------------------------------------------------------------*/
ast_node_t *newVarDeclare(char* symbol, ast_node_t *expression1, ast_node_t *expression2, ast_node_t *expression3, ast_node_t *expression4, ast_node_t *value, int line_number)
{
ast_node_t *symbol_node = newSymbolNode(symbol, line_number);
/* create a node for this array reference */
ast_node_t* new_node = create_node_w_type(VAR_DECLARE, line_number, current_parse_file);
/* allocate child nodes to this node */
allocate_children_to_node(new_node, 6, symbol_node, expression1, expression2, expression3, expression4, value);
return new_node;
}
/*---------------------------------------------------------------------------------------------
* (function: newIntegerTypeVarDeclare)
*-------------------------------------------------------------------------------------------*/
ast_node_t *newIntegerTypeVarDeclare(char* symbol, ast_node_t * /*expression1*/ , ast_node_t * /*expression2*/ , ast_node_t *expression3, ast_node_t *expression4, ast_node_t *value, int line_number)
{
ast_node_t *symbol_node = newSymbolNode(symbol, line_number);
ast_node_t *number_node_with_value_31 = create_tree_node_long_number(31, ODIN_STD_BITWIDTH, line_number,current_parse_file);
ast_node_t *number_node_with_value_0 = create_tree_node_long_number(0, ODIN_STD_BITWIDTH, line_number,current_parse_file);
/* create a node for this array reference */
ast_node_t* new_node = create_node_w_type(VAR_DECLARE, line_number, current_parse_file);
/* allocate child nodes to this node */
allocate_children_to_node(new_node, 6, symbol_node, number_node_with_value_31, number_node_with_value_0, expression3, expression4, value);
return new_node;
}
/*-----------------------------------------
* ----------------------------------------------------
* (function: newModule)
*-------------------------------------------------------------------------------------------*/
ast_node_t *newModule(char* module_name, ast_node_t *list_of_parameters, ast_node_t *list_of_ports, ast_node_t *list_of_module_items, int line_number)
{
int i;
long j, k;
long sc_spot;
ast_node_t *symbol_node = newSymbolNode(module_name, line_number);
if(sc_lookup_string(hard_block_names, module_name) != -1)
{
warning_message(PARSE_ERROR, line_number, current_parse_file,
"Probable module name collision with hard block of the same name -> %s\n", module_name);
}
/* create a node for this array reference */
ast_node_t *new_node = create_node_w_type(MODULE, line_number, current_parse_file);
/* mark all the ports symbols as ports */
ast_node_t *port_declarations = resolve_ports(MODULE, list_of_ports);
/* ports are expected to be in module items */
if (port_declarations)
{
add_child_at_the_beginning_of_the_node(list_of_module_items, port_declarations);
}
/* parameters are expected to be in module items */
if (list_of_parameters)
{
newList_entry(list_of_module_items, list_of_parameters);
}
/* allocate child nodes to this node */
allocate_children_to_node(new_node, 3, symbol_node, list_of_ports, list_of_module_items);
/* store the list of modules this module instantiates */
new_node->types.module.module_instantiations_instance = module_instantiations_instance;
new_node->types.module.size_module_instantiations = size_module_instantiations;
new_node->types.module.is_instantiated = FALSE;
new_node->types.module.index = num_modules;
new_node->types.function.function_instantiations_instance = function_instantiations_instance_by_module;
new_node->types.function.size_function_instantiations = size_function_instantiations_by_module;
new_node->types.function.is_instantiated = FALSE;
new_node->types.function.index = num_functions;
/* record this module in the list of modules (for evaluation later in terms of just nodes) */
ast_modules = (ast_node_t **)vtr::realloc(ast_modules, sizeof(ast_node_t*)*(num_modules+1));
ast_modules[num_modules] = new_node;
for(i = 0; i < size_module_variables_not_defined; i++){
short variable_found = FALSE;
for(j = 0; j < list_of_module_items->num_children && variable_found == FALSE; j++){
if(list_of_module_items->children[j]->type == VAR_DECLARE_LIST){
for(k = 0; k < list_of_module_items->children[j]->num_children; k++){
if(strcmp(list_of_module_items->children[j]->children[k]->children[0]->types.identifier,module_variables_not_defined[i]->children[0]->children[0]->types.identifier) == 0) variable_found = TRUE;
}
}
}
if(!variable_found) add_child_at_the_beginning_of_the_node(list_of_module_items, module_variables_not_defined[i]);
else free_whole_tree(module_variables_not_defined[i]);
}
/* clean up */
vtr::free(module_variables_not_defined);
sc_spot = sc_add_string(module_names_to_idx, module_name);
if (module_names_to_idx->data[sc_spot] != NULL)
{
error_message(PARSE_ERROR, line_number, current_parse_file, "module names with the same name -> %s\n", module_name);
}
/* store the data which is an idx here */
module_names_to_idx->data[sc_spot] = (void*)new_node;
/* now that we've bottom up built the parse tree for this module, go to the next module */
next_module();
return new_node;
}
/*-----------------------------------------
* ----------------------------------------------------
* (function: newFunction)
*-------------------------------------------------------------------------------------------*/
ast_node_t *newFunction(ast_node_t *list_of_ports, ast_node_t *list_of_module_items, int line_number) //function and module declaration work the same way (Lucas Cambuim)
{
long i,j;
long sc_spot;
char *function_name;
char *label;
ast_node_t *var_node;
ast_node_t *symbol_node, *output_node;
function_name = (char *)vtr::calloc(strlen(list_of_ports->children[0]->children[0]->types.identifier)+10,sizeof(char));
strcpy(function_name,list_of_ports->children[0]->children[0]->types.identifier);
label = (char *)vtr::calloc(strlen(list_of_ports->children[0]->children[0]->types.identifier)+10,sizeof(char));
strcpy(label,list_of_ports->children[0]->children[0]->types.identifier);
list_of_ports->children[0]->children[0]->types.identifier = label;
output_node = newList(VAR_DECLARE_LIST, list_of_ports->children[0]);
markAndProcessSymbolListWith(FUNCTION, OUTPUT, output_node);
add_child_at_the_beginning_of_the_node(list_of_module_items, output_node);
label = (char *)vtr::calloc(strlen(list_of_ports->children[0]->children[0]->types.identifier)+10,sizeof(char));
strcpy(label,list_of_ports->children[0]->children[0]->types.identifier);
var_node = newVarDeclare(label, NULL, NULL, NULL, NULL, NULL, yylineno);
list_of_ports->children[0] = var_node;
for(i = 0; i < list_of_module_items->num_children; i++) {
if(list_of_module_items->children[i]->type == VAR_DECLARE_LIST){
for(j = 0; j < list_of_module_items->children[i]->num_children; j++) {
if(list_of_module_items->children[i]->children[j]->types.variable.is_input){
label = (char *)vtr::calloc(strlen(list_of_module_items->children[i]->children[j]->children[0]->types.identifier)+10,sizeof(char));
strcpy(label,list_of_module_items->children[i]->children[j]->children[0]->types.identifier);
var_node = newVarDeclare(label, NULL, NULL, NULL, NULL, NULL, yylineno);
newList_entry(list_of_ports,var_node);
}
}
}
}
symbol_node = newSymbolNode(function_name, line_number);
/* create a node for this array reference */
ast_node_t* new_node = create_node_w_type(FUNCTION, line_number, current_parse_file);
/* mark all the ports symbols as ports */
ast_node_t *port_declarations = resolve_ports(FUNCTION, list_of_ports);
if (port_declarations)
{
add_child_at_the_beginning_of_the_node(list_of_module_items, port_declarations);
}
/* allocate child nodes to this node */
allocate_children_to_node(new_node, 3, symbol_node, list_of_ports, list_of_module_items);
/* store the list of modules this module instantiates */
new_node->types.function.function_instantiations_instance = function_instantiations_instance;
new_node->types.function.size_function_instantiations = size_function_instantiations;
new_node->types.function.is_instantiated = FALSE;
/* record this module in the list of modules (for evaluation later in terms of just nodes) */
ast_modules = (ast_node_t **)vtr::realloc(ast_modules, sizeof(ast_node_t*)*(num_modules+1));
ast_modules[num_modules] = new_node;
sc_spot = sc_add_string(module_names_to_idx, function_name);
if (module_names_to_idx->data[sc_spot] != NULL)
{
error_message(PARSE_ERROR, line_number, current_parse_file, "module names with the same name -> %s\n", function_name);
}
/* store the data which is an idx here */
module_names_to_idx->data[sc_spot] = (void*)new_node;
/* now that we've bottom up built the parse tree for this module, go to the next module */
next_function();
return new_node;
}
/*---------------------------------------------------------------------------------------------
* (function: next_function)
*-------------------------------------------------------------------------------------------*/
void next_function()
{
num_functions++;
//num_modules++;
/* define the string cache for the next function */
defines_for_function_sc = (STRING_CACHE**)vtr::realloc(defines_for_function_sc, sizeof(STRING_CACHE*)*(num_functions+1));
defines_for_function_sc[num_functions] = sc_new_string_cache();
/* create a new list for the instantiations list */
function_instantiations_instance = NULL;
size_function_instantiations = 0;
/* old ones are done so clean */
sc_free_string_cache(functions_inputs_sc);
sc_free_string_cache(functions_outputs_sc);
/* make for next function */
functions_inputs_sc = sc_new_string_cache();
functions_outputs_sc = sc_new_string_cache();
}
/*---------------------------------------------------------------------------------------------
* (function: next_module)
*-------------------------------------------------------------------------------------------*/
void next_module()
{
num_modules ++;
num_instances = 0;
num_functions = 0;
/* define the string cache for the next module */
defines_for_module_sc = (STRING_CACHE**)vtr::realloc(defines_for_module_sc, sizeof(STRING_CACHE*)*(num_modules+1));
defines_for_module_sc[num_modules] = sc_new_string_cache();
/* create a new list for the instantiations list */
module_instantiations_instance = NULL;
size_module_instantiations = 0;
function_instantiations_instance_by_module = NULL;
size_function_instantiations_by_module = 0;
module_variables_not_defined = NULL;
size_module_variables_not_defined = 0;
/* old ones are done so clean */
sc_free_string_cache(modules_inputs_sc);
sc_free_string_cache(modules_outputs_sc);
/* make for next module */
modules_inputs_sc = sc_new_string_cache();
modules_outputs_sc = sc_new_string_cache();
}
/*--------------------------------------------------------------------------
* (function: newDefparam)
*------------------------------------------------------------------------*/
ast_node_t *newDefparam(ids /*id*/, ast_node_t *val, int line_number)
{
ast_node_t *new_node = NULL;
ast_node_t *ref_node;
char *module_instance_name = NULL;
long i;
int j;
//long sc_spot;
if(val)
{
if(val->num_children > 1)
{
for(i = 0; i < val->num_children - 1; i++)
{
oassert(val->children[i]->num_children > 0);
if(i == 0 && val->num_children > 2)
module_instance_name = val->children[i]->children[0]->types.identifier;
else if(i == 0 && val->num_children == 2)
module_instance_name = val->children[i]->children[0]->types.identifier;
else
{
module_instance_name = strcat(module_instance_name, ".");
module_instance_name = strcat(module_instance_name, val->children[i]->children[0]->types.identifier);
}
}
new_node = val->children[(val->num_children - 1)];
if (!node_is_ast_constant(new_node->children[5], defines_for_module_sc[num_modules-num_instances]))
{
error_message(PARSE_ERROR, line_number, current_parse_file, "%s", "Parameter value must be constant\n");
}
new_node->type = MODULE_PARAMETER;
new_node->types.variable.is_parameter = TRUE;
new_node->shared_node = TRUE;
new_node->children[5]->types.variable.is_parameter = TRUE;
new_node->children[5]->shared_node = TRUE;
new_node->types.identifier = module_instance_name;
}
}
//flag = 0 can't find the instance
int flag = 0;
for(j = 0 ; j < size_module_instantiations ; j++)
{
if(flag == 0)
{
ref_node = module_instantiations_instance[j];
if(strcmp(ref_node->children[1]->children[0]->types.identifier, module_instance_name) == 0)
{
if(ref_node->children[1]->children[2])
add_child_to_node(ref_node->children[1]->children[2], new_node);
else
{
ast_node_t* symbol_node = create_node_w_type(MODULE_PARAMETER_LIST, line_number, current_parse_file);
ref_node->children[1]->children[2] = symbol_node;
add_child_to_node(ref_node->children[1]->children[2], new_node);
}
flag = 1;
}
}
}
//if the instance never showed before, dealt with this parameter in function convert_ast_to_netlist_recursing_via_modules
if(flag == 0)
{
new_node->shared_node = FALSE;
return new_node;
// add_child_to_node(new_node, symbol_node);
}
return NULL;
}
/* --------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------
AST VIEWING FUNCTIONS
--------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------*/
int unique_label_count;
/*---------------------------------------------------------------------------
* (function: graphVizOutputAst)
*-------------------------------------------------------------------------*/
void graphVizOutputAst(std::string path, ast_node_t *top)
{
char path_and_file[4096];
FILE *fp;
static int file_num = 0;
/* open the file */
odin_sprintf(path_and_file, "%s/%s_ast.dot", path.c_str(), top->children[0]->types.identifier);
fp = fopen(path_and_file, "w");
file_num++;
/* open graph */
fprintf(fp, "digraph G {\t\nranksep=.25;\n");
unique_label_count = 0;
graphVizOutputAst_traverse_node(fp, top, NULL, -1);
/* close graph */
fprintf(fp, "}\n");
fclose(fp);
}
/*---------------------------------------------------------------------------------------------
* (function: graphVizOutputAst_traverse_node)
*-------------------------------------------------------------------------------------------*/
void graphVizOutputAst_traverse_node(FILE *fp, ast_node_t *node, ast_node_t *from, int from_num)
{
if(!node)
return;
/* increase the unique count for other nodes since ours is recorded */
int my_label = unique_label_count++;
fprintf(fp, "\t%d [label=\"", my_label);
fprintf(fp, "%s", ids_STR[node->type]);
switch(node->type)
{
case VAR_DECLARE:
{
std::stringstream temp;
if(node->types.variable.is_input) temp << " INPUT";
if(node->types.variable.is_output) temp << " OUTPUT";
if(node->types.variable.is_inout) temp << " INOUT";
if(node->types.variable.is_port) temp << " PORT";
if(node->types.variable.is_parameter) temp << " PARAMETER";
if(node->types.variable.is_wire) temp << " WIRE";
if(node->types.variable.is_reg) temp << " REG";
fprintf(fp, ": %s", temp.str().c_str());
break;
}
case NUMBERS:
fprintf(fp, ": %s", node->types.number.binary_string );
break;
case UNARY_OPERATION: //fallthrough
case BINARY_OPERATION:
fprintf(fp, ": %s", name_based_on_op(node->types.operation.op));
break;
case IDENTIFIERS:
fprintf(fp, ": %s", node->types.identifier);
break;
default:
break;
}
fprintf(fp, "\"];\n");
/* print out the connection with the previous node */
if (from != NULL)
fprintf(fp, "\t%d -> %d;\n", from_num, my_label);
for (long i = 0; i < node->num_children; i++)
{
graphVizOutputAst_traverse_node(fp, node->children[i], node, my_label);
}
}
/*---------------------------------------------------------------------------------------------
* (function: newVarDeclare) for 2D Array
*-------------------------------------------------------------------------------------------*/
ast_node_t *newVarDeclare2D(char* symbol, ast_node_t *expression1, ast_node_t *expression2, ast_node_t *expression3, ast_node_t *expression4, ast_node_t *expression5, ast_node_t *expression6,ast_node_t *value, int line_number)
{
ast_node_t *symbol_node = newSymbolNode(symbol, line_number);
/* create a node for this array reference */
ast_node_t* new_node = create_node_w_type(VAR_DECLARE, line_number, current_parse_file);
/* allocate child nodes to this node */
allocate_children_to_node(new_node, 8, symbol_node, expression1, expression2, expression3, expression4, expression5, expression6, value);
return new_node;
}
/*---------------------------------------------------------------------------------------------
* (function: newArrayRef) for 2D Array
*-------------------------------------------------------------------------------------------*/
ast_node_t *newArrayRef2D(char *id, ast_node_t *expression1, ast_node_t *expression2, int line_number)
{
/* allocate or check if there's a node for this */
ast_node_t *symbol_node = newSymbolNode(id, line_number);
/* create a node for this array reference */
ast_node_t* new_node = create_node_w_type(ARRAY_REF, line_number, current_parse_file);
/* allocate child nodes to this node */
allocate_children_to_node(new_node, 3, symbol_node, expression1,expression2);
return new_node;
}
/*---------------------------------------------------------------------------------------------
* (function: newRangeRef) for 2D Array
*-------------------------------------------------------------------------------------------*/
ast_node_t *newRangeRef2D(char *id, ast_node_t *expression1, ast_node_t *expression2, ast_node_t *expression3, ast_node_t *expression4, int line_number)
{
/* allocate or check if there's a node for this */
ast_node_t *symbol_node = newSymbolNode(id, line_number);
/* create a node for this array reference */
ast_node_t* new_node = create_node_w_type(RANGE_REF, line_number, current_parse_file);
/* allocate child nodes to this node */
allocate_children_to_node(new_node, 5, symbol_node, expression1, expression2, expression3, expression4);
return new_node;
}