blob: e4253fb1928246dfbbb2a10e5984144faaaaa599 [file] [log] [blame]
/*
Copyright (c) 2009 Peter Andrew Jamieson (jamieson.peter@gmail.com)
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 <math.h>
#include "odin_types.h"
#include "adders.h"
#include "ast_util.h"
#include "odin_util.h"
#include "ast_elaborate.h"
#include "ast_loop_unroll.h"
#include "hard_blocks.h"
#include "memories.h"
#include "multipliers.h"
#include "odin_util.h"
#include "parse_making_ast.h"
#include "verilog_bison.h"
#include "netlist_create_from_ast.h"
#include "netlist_utils.h"
#include "ctype.h"
#include "vtr_util.h"
#include "vtr_memory.h"
#include <string>
#include <iostream>
#include <vector>
#include <stack>
// #define read_node 1
// #define write_node 2
// #define e_data 1
// #define e_operation 2
// #define e_variable 3
// #define N 64
// #define Max_size 64
// long count_id = 0;
// long count_assign = 0;
// long count;
// long count_write;
//enode *head, *p;
// void reduce_assignment_expression();
// void reduce_assignment_expression(ast_node_t *ast_module);
// void find_assign_node(ast_node_t *node, std::vector<ast_node_t *> list, char *module_name);
// struct enode
// {
// struct
// {
// short operation;
// int data;
// std::string variable;
// }type;
// int id;
// int flag;
// int priority;
// struct enode *next;
// struct enode *pre;
// };
// void record_tree_info(ast_node_t *node);
// void store_exp_list(ast_node_t *node);
// void create_enode(ast_node_t *node);
// bool simplify_expression();
// bool adjoin_constant();
// enode *replace_enode(int data, enode *t, int mark);
// bool combine_constant();
// bool delete_continuous_multiply();
// void construct_new_tree(enode *tail, ast_node_t *node, int line_num, int file_num);
// void reduce_enode_list();
// enode *find_tail(enode *node);
// int check_exp_list(enode *tail);
// void create_ast_node(enode *temp, ast_node_t *node, int line_num, int file_num);
// void create_op_node(ast_node_t *node, enode *temp, int line_num, int file_num);
// void free_exp_list();
// void change_exp_list(enode *beign, enode *end, enode *s, int flag);
// enode *copy_enode_list(enode *new_head, enode *begin, enode *end);
// void copy_enode(enode *node, enode *new_node);
// bool check_tree_operation(ast_node_t *node);
// void check_operation(enode *begin, enode *end);
// bool check_mult_bracket(std::vector<int> list);
struct e_data
{
int pass;
int index;
struct
{
ast_node_t **defparams;
sc_hierarchy **sc_hierarchies; // for the correct scope
int num_defparams;
} defparam;
struct
{
ast_node_t **generate_constructs;
ast_node_t **generate_parents;
int *generate_indexes; // for the correct location of the parent's child
sc_hierarchy **sc_hierarchies; // for the correct scope
int num_generate_constructs;
} generate;
};
ast_node_t *build_hierarchy(ast_node_t *node, ast_node_t *parent, int index, sc_hierarchy *local_ref, bool is_generate_region, bool fold_expressions, e_data *data);
ast_node_t *finalize_ast(ast_node_t *node, ast_node_t *parent, sc_hierarchy *local_ref, bool is_generate_region, bool fold_expressions);
ast_node_t *reduce_expressions(ast_node_t *node, sc_hierarchy *local_ref, long *max_size, long assignment_size);
void update_string_caches(sc_hierarchy *local_ref);
void update_instance_parameter_table(ast_node_t *instance, STRING_CACHE *instance_param_table_sc);
void override_parameters_for_all_instances(ast_node_t *module, sc_hierarchy *local_ref);
void convert_2D_to_1D_array(ast_node_t **var_declare);
void convert_2D_to_1D_array_ref(ast_node_t **node, sc_hierarchy *local_ref);
char *make_chunk_size_name(char *instance_name_prefix, char *array_name);
ast_node_t *get_chunk_size_node(char *instance_name_prefix, char *array_name, sc_hierarchy *local_ref);
bool verify_terminal(ast_node_t *top, ast_node_t *iterator);
void verify_genvars(ast_node_t *node, sc_hierarchy *local_ref, char ***other_genvars, int num_genvars);
ast_node_t *look_for_matching_hard_block(ast_node_t *node, char *hard_block_name, sc_hierarchy *local_ref);
ast_node_t *look_for_matching_soft_logic(ast_node_t *node, char *hard_block_name);
int simplify_ast_module(ast_node_t **ast_module, sc_hierarchy *local_ref)
{
/* resolve constant expressions in string caches */
bool is_module = (*ast_module)->type == MODULE ? true : false;
/* set up elaboration data */
e_data *data = (e_data *)vtr::calloc(1, sizeof(e_data));
data->generate.generate_constructs = NULL;
data->generate.num_generate_constructs = 0;
data->generate.sc_hierarchies = NULL;
data->defparam.defparams = NULL;
data->defparam.num_defparams = 0;
data->defparam.sc_hierarchies = NULL;
data->index = -1;
/* TODO need to also store some kind of info about what defparams have been applied to... */
/* elaborate AST */
/* pass 1: elaborate everything except generate constructs */
data->pass = 1;
*ast_module = build_hierarchy(*ast_module, NULL, -1, local_ref, true, true, data);
/* apply defparam overrides for instances found during this pass */
override_parameters_for_all_instances(*ast_module, local_ref);
/* pass 2: elaborate generate constructs */
data->pass = 2;
for (int i = 0; i < data->generate.num_generate_constructs; i++)
{
ast_node_t *generate_node = data->generate.generate_constructs[i];
ast_node_t *parent = data->generate.generate_parents[i];
int index = data->generate.generate_indexes[i];
sc_hierarchy *sc_hierarchy = data->generate.sc_hierarchies[i];
generate_node = build_hierarchy(generate_node, parent, index, sc_hierarchy, true, true, data);
parent->children[index] = generate_node;
}
/* pass 3: finish AST elaboration */
update_string_caches(local_ref);
*ast_module = finalize_ast(*ast_module, NULL, local_ref, is_module, true);
*ast_module = reduce_expressions(*ast_module, local_ref, NULL, 0);
if (data->generate.num_generate_constructs > 0)
{
vtr::free(data->generate.generate_constructs);
vtr::free(data->generate.generate_parents);
vtr::free(data->generate.generate_indexes);
vtr::free(data->generate.sc_hierarchies);
}
vtr::free(data);
return 1;
}
/* -----------------------------------------------------------------------------------------------------
* (function: build_hierarchy)
*
* this function finds all instances in two passes and:
* 1. builds the official string cache list hierarchy so we can resolve identifiers
* 2. resolves defparams so that we properly override parameters
* ----------------------------------------------------------------------------------------------------- */
ast_node_t *build_hierarchy(ast_node_t *node, ast_node_t * parent, int index, sc_hierarchy *local_ref, bool is_generate_region, bool fold_expressions, e_data *data)
{
short *child_skip_list = NULL; // list of children not to traverse into
short skip_children = false; // skips the DFS completely if true
STRING_CACHE *local_defparam_table_sc = local_ref->local_defparam_table_sc;
STRING_CACHE *local_param_table_sc = local_ref->local_param_table_sc;
if (node)
{
if (node->num_children > 0)
{
child_skip_list = (short*)vtr::calloc(node->num_children, sizeof(short));
}
/* pre-amble */
switch (node->type)
{
case MODULE:
{
break;
}
case MODULE_INSTANCE:
{
/* flip hard blocks */
if (node->num_children == 1)
{
// check ports
ast_node_t *connect_list = node->children[0]->children[1]->children[1];
bool is_ordered_list;
if (connect_list->children[0]->children[0])
{
is_ordered_list = false; // name was specified
}
else
{
is_ordered_list = true;
}
for (int i = 1; i < connect_list->num_children; i++)
{
if ((connect_list->children[i]->children[0] && is_ordered_list)
|| (!connect_list->children[i]->children[0] && !is_ordered_list))
{
error_message(PARSE_ERROR, node->line_number, node->file_number,
"%s", "Cannot mix port connections by name and port connections by ordered list\n");
}
}
char *module_ref_name = node->children[0]->children[0]->types.identifier;
long sc_spot = sc_lookup_string(hard_block_names, module_ref_name);
/* TODO: strcmp on "multiply", "adder" for soft logic implementation? */
if
(
sc_spot != -1
|| !strcmp(module_ref_name, SINGLE_PORT_RAM_string)
|| !strcmp(module_ref_name, DUAL_PORT_RAM_string)
)
{
ast_node_t *hb_node = look_for_matching_hard_block(node->children[0], module_ref_name, local_ref);
if (hb_node != node->children[0])
{
free_whole_tree(node);
node = hb_node;
child_skip_list = (short *)vtr::realloc(child_skip_list, sizeof(short)*node->num_children);
child_skip_list[1] = false;
break;
}
}
}
break;
}
case FOR:
{
if (data->pass == 1 && is_generate_region)
{
// parameters haven't been resolved yet; don't elaborate until the second pass
data->generate.generate_constructs = (ast_node_t **)vtr::realloc(data->generate.generate_constructs, sizeof(ast_node_t *)*(data->generate.num_generate_constructs + 1));
data->generate.generate_constructs[data->generate.num_generate_constructs] = node;
data->generate.generate_parents = (ast_node_t **)vtr::realloc(data->generate.generate_parents, sizeof(ast_node_t *)*(data->generate.num_generate_constructs + 1));
data->generate.generate_parents[data->generate.num_generate_constructs] = parent;
data->generate.generate_indexes = (int *)vtr::realloc(data->generate.generate_indexes, sizeof(int)*(data->generate.num_generate_constructs + 1));
data->generate.generate_indexes[data->generate.num_generate_constructs] = index;
data->generate.sc_hierarchies = (sc_hierarchy **)vtr::realloc(data->generate.sc_hierarchies, sizeof(sc_hierarchy *)*(data->generate.num_generate_constructs + 1));
data->generate.sc_hierarchies[data->generate.num_generate_constructs] = local_ref;
data->generate.num_generate_constructs++;
skip_children = true;
break;
}
else if (!(data->pass == 2))
{
break;
}
oassert(child_skip_list);
// look ahead for parameters in loop conditions
node->children[0] = build_hierarchy(node->children[0], node, 0, local_ref, is_generate_region, true, data);
node->children[1] = build_hierarchy(node->children[1], node, 1, local_ref, is_generate_region, true, data);
node->children[2] = build_hierarchy(node->children[2], node, 2, local_ref, is_generate_region, true, data);
// update skip list
child_skip_list[0] = true;
child_skip_list[1] = true;
child_skip_list[2] = true;
// if this is a loop generate construct, verify constant expressions
if (is_generate_region)
{
ast_node_t *iterator = NULL;
ast_node_t *initial = node->children[0];
ast_node_t *compare_expression = node->children[1];
ast_node_t *terminal = node->children[2];
char **genvar_list = NULL;
verify_genvars(node, local_ref, &genvar_list, 0);
if (genvar_list) vtr::free(genvar_list);
iterator = resolve_hierarchical_name_reference(local_ref, initial->children[0]->types.identifier);
oassert(iterator != NULL);
if ( !(node_is_constant(initial->children[1]))
|| !(node_is_constant(compare_expression->children[1]))
|| !(verify_terminal(terminal->children[1], iterator))
)
{
error_message(NETLIST_ERROR, node->line_number, node->file_number,
"%s","Loop generate construct conditions must be constant expressions");
}
}
int num_unrolled = 0;
node = unroll_for_loop(node, parent, &num_unrolled, local_ref, is_generate_region);
for (int i = index; i < (num_unrolled + index); i++)
{
parent->children[i] = build_hierarchy(parent->children[i], parent, i, local_ref, is_generate_region, true, data);
}
break;
}
case IF_Q:
case IF:
{
if (data->pass == 1 && is_generate_region)
{
// parameters haven't been resolved yet; don't elaborate until the second pass
data->generate.generate_constructs = (ast_node_t **)vtr::realloc(data->generate.generate_constructs, sizeof(ast_node_t *)*(data->generate.num_generate_constructs + 1));
data->generate.generate_constructs[data->generate.num_generate_constructs] = node;
data->generate.generate_parents = (ast_node_t **)vtr::realloc(data->generate.generate_parents, sizeof(ast_node_t *)*(data->generate.num_generate_constructs + 1));
data->generate.generate_parents[data->generate.num_generate_constructs] = parent;
data->generate.generate_indexes = (int *)vtr::realloc(data->generate.generate_indexes, sizeof(int)*(data->generate.num_generate_constructs + 1));
data->generate.generate_indexes[data->generate.num_generate_constructs] = index;
data->generate.sc_hierarchies = (sc_hierarchy **)vtr::realloc(data->generate.sc_hierarchies, sizeof(sc_hierarchy *)*(data->generate.num_generate_constructs + 1));
data->generate.sc_hierarchies[data->generate.num_generate_constructs] = local_ref;
data->generate.num_generate_constructs++;
skip_children = true;
break;
}
else if (!(data->pass == 2))
{
break;
}
ast_node_t *to_return = NULL;
node->children[0] = build_hierarchy(node->children[0], node, 0, local_ref, is_generate_region, true, data);
ast_node_t *child_condition = node->children[0];
if(node_is_constant(child_condition))
{
VNumber condition = *(child_condition->types.vnumber);
if(V_TRUE(condition))
{
to_return = node->children[1];
node->children[1] = NULL;
}
else if(V_FALSE(condition))
{
to_return = node->children[2];
node->children[2] = NULL;
}
else if (node->type == IF && is_generate_region)
{
error_message(NETLIST_ERROR, node->line_number, node->file_number,
"%s","Could not resolve conditional generate construct");
}
// otherwise we keep it as is to build the circuitry
}
else if (node->type == IF && is_generate_region)
{
error_message(NETLIST_ERROR, node->line_number, node->file_number,
"%s","Could not resolve conditional generate construct");
}
if (to_return != NULL)
{
if (to_return->type == BLOCK && to_return->children[0]->type != IF &&
(is_generate_region || to_return->types.identifier != NULL))
{
// must create scope; parent has access to named block but not unnamed,
// and child always has access to parent
sc_hierarchy *new_hierarchy = init_sc_hierarchy();
to_return->types.hierarchy = new_hierarchy;
new_hierarchy->top_node = to_return;
new_hierarchy->parent = local_ref;
if (to_return->types.identifier != NULL)
{
// parent's children
local_ref->block_children = (sc_hierarchy **)vtr::realloc(local_ref->block_children, sizeof(sc_hierarchy *)*(local_ref->num_block_children + 1));
local_ref->block_children[local_ref->num_block_children] = new_hierarchy;
local_ref->num_block_children++;
// scope id/instance name prefix
new_hierarchy->scope_id = to_return->types.identifier;
new_hierarchy->instance_name_prefix = make_full_ref_name(local_ref->instance_name_prefix, NULL, to_return->types.identifier, NULL, -1);
}
else if (is_generate_region)
{
// create a unique scope id/instance name prefix for internal use
local_ref->num_unnamed_genblks++;
std::string new_scope_id("genblk" + std::to_string(local_ref->num_unnamed_genblks));
new_hierarchy->scope_id = vtr::strdup(new_scope_id.c_str());
new_hierarchy->instance_name_prefix = make_full_ref_name(local_ref->instance_name_prefix, NULL, new_hierarchy->scope_id, NULL, -1);
}
/* string caches */
create_param_table_for_scope(to_return, new_hierarchy);
create_symbol_table_for_scope(to_return, new_hierarchy);
}
oassert(node->children[1] == NULL || node->children[2] == NULL);
free_whole_tree(node);
node = to_return;
oassert(node->type != IF && node->type != IF_Q);
}
if (node->type == IF || node->type == IF_Q)
{
oassert(node->num_children > 0);
}
break;
}
case CASE:
{
if (data->pass == 1 && is_generate_region)
{
// parameters haven't been resolved yet; don't elaborate until the second pass
data->generate.generate_constructs = (ast_node_t **)vtr::realloc(data->generate.generate_constructs, sizeof(ast_node_t *)*(data->generate.num_generate_constructs + 1));
data->generate.generate_constructs[data->generate.num_generate_constructs] = node;
data->generate.generate_parents = (ast_node_t **)vtr::realloc(data->generate.generate_parents, sizeof(ast_node_t *)*(data->generate.num_generate_constructs + 1));
data->generate.generate_parents[data->generate.num_generate_constructs] = parent;
data->generate.generate_indexes = (int *)vtr::realloc(data->generate.generate_indexes, sizeof(int)*(data->generate.num_generate_constructs + 1));
data->generate.generate_indexes[data->generate.num_generate_constructs] = index;
data->generate.sc_hierarchies = (sc_hierarchy **)vtr::realloc(data->generate.sc_hierarchies, sizeof(sc_hierarchy *)*(data->generate.num_generate_constructs + 1));
data->generate.sc_hierarchies[data->generate.num_generate_constructs] = local_ref;
data->generate.num_generate_constructs++;
skip_children = true;
break;
}
else if (!(data->pass == 2))
{
break;
}
ast_node_t *to_return = NULL;
node->children[0] = build_hierarchy(node->children[0], node, 0, local_ref, is_generate_region, true, data);
ast_node_t *child_condition = node->children[0];
if(node_is_constant(child_condition))
{
ast_node_t *case_list = node->children[1];
for (int i = 0; i < case_list->num_children; i++)
{
ast_node_t *item = case_list->children[i];
if (i == case_list->num_children - 1 && item->type == CASE_DEFAULT)
{
to_return = item->children[0];
item->children[0] = NULL;
}
else
{
if (item->type != CASE_ITEM)
{
error_message(NETLIST_ERROR, node->line_number, node->file_number,
"%s","Default case must only be the last case");
}
item->children[0] = build_hierarchy(item->children[0], item, 0, local_ref, is_generate_region, true, data);
if (node_is_constant(item->children[0]))
{
VNumber eval = V_CASE_EQUAL(*(child_condition->types.vnumber), *(item->children[0]->types.vnumber));
if (V_TRUE(eval))
{
to_return = item->children[1];
item->children[1] = NULL;
break;
}
}
else if (is_generate_region)
{
error_message(NETLIST_ERROR, node->line_number, node->file_number,
"%s","Could not resolve conditional generate construct");
}
else
{
/* encountered non-constant item - don't continue searching */
break;
}
}
}
if (to_return)
{
if (to_return->type == BLOCK && (is_generate_region || to_return->types.identifier != NULL))
{
// must create scope; parent has access to named block but not unnamed,
// and child always has access to parent
sc_hierarchy *new_hierarchy = init_sc_hierarchy();
to_return->types.hierarchy = new_hierarchy;
new_hierarchy->top_node = to_return;
new_hierarchy->parent = local_ref;
if (to_return->types.identifier != NULL)
{
// parent's children
local_ref->block_children = (sc_hierarchy **)vtr::realloc(local_ref->block_children, sizeof(sc_hierarchy*)*(local_ref->num_block_children + 1));
local_ref->block_children[local_ref->num_block_children] = new_hierarchy;
local_ref->num_block_children++;
// scope id/instance name prefix
new_hierarchy->scope_id = to_return->types.identifier;
new_hierarchy->instance_name_prefix = make_full_ref_name(local_ref->instance_name_prefix, NULL, to_return->types.identifier, NULL, -1);
}
else if (is_generate_region)
{
// create a unique scope id/instance name prefix for internal use
local_ref->num_unnamed_genblks++;
std::string new_scope_id("genblk" + std::to_string(local_ref->num_unnamed_genblks));
new_hierarchy->scope_id = vtr::strdup(new_scope_id.c_str());
new_hierarchy->instance_name_prefix = make_full_ref_name(local_ref->instance_name_prefix, NULL, new_hierarchy->scope_id, NULL, -1);
}
/* string caches */
create_param_table_for_scope(to_return, new_hierarchy);
create_symbol_table_for_scope(to_return, new_hierarchy);
}
free_whole_tree(node);
node = to_return;
}
else if (is_generate_region)
{
/* no case */
error_message(NETLIST_ERROR, node->line_number, node->file_number,
"%s","Could not resolve conditional generate construct");
}
}
else if (is_generate_region)
{
error_message(NETLIST_ERROR, node->line_number, node->file_number,
"%s","Could not resolve conditional generate construct");
}
break;
}
case REPLICATE:
{
if (data->pass == 2)
{
node->children[0] = build_hierarchy(node->children[0], node, 0, local_ref, is_generate_region, true, data);
if (!(node_is_constant(node->children[0])))
{
error_message(NETLIST_ERROR, node->line_number, node->file_number,
"%s","Replication constant must be a constant expression");
}
else if (node->children[0]->types.vnumber->is_dont_care_string())
{
error_message(NETLIST_ERROR, node->line_number, node->file_number,
"%s","Replication constant cannot contain x or z");
}
ast_node_t *new_node = NULL;
int64_t value = node->children[0]->types.vnumber->get_value();
if (value > 0)
{
new_node = create_node_w_type(CONCATENATE, node->line_number, node->file_number);
for (size_t i = 0; i < value; i++)
{
add_child_to_node(new_node, ast_node_deep_copy(node->children[1]));
}
}
node->children[1] = free_whole_tree(node->children[1]);
node->children[1] = NULL;
node->num_children--;
node->children[0] = free_whole_tree(node->children[0]);
node->children[0] = new_node;
}
break;
}
case IDENTIFIERS:
{
if (data->pass == 2 && local_param_table_sc != NULL && node->types.identifier)
{
long sc_spot = sc_lookup_string(local_param_table_sc, node->types.identifier);
if (sc_spot != -1)
{
ast_node_t *newNode = ast_node_deep_copy((ast_node_t *)local_param_table_sc->data[sc_spot]);
if (newNode->type != NUMBERS)
{
newNode = build_hierarchy(newNode, parent, index, local_ref, is_generate_region, true, data);
oassert(newNode->type == NUMBERS);
/* this forces parameter values as unsigned, since we don't currently support signed keyword...
must be changed once support is added */
VNumber *temp = newNode->types.vnumber;
VNumber *to_unsigned = new VNumber(V_UNSIGNED(*temp));
newNode->types.vnumber = to_unsigned;
delete temp;
if (newNode->type != NUMBERS)
{
error_message(NETLIST_ERROR, node->line_number, node->file_number, "Parameter %s is not a constant expression\n", node->types.identifier);
}
}
node = free_whole_tree(node);
node = newNode;
}
}
break;
}
case BLOCKING_STATEMENT: // fallthrough
case NON_BLOCKING_STATEMENT:
{
// size of resolved expressions can depend on left-hand side of assignment
fold_expressions = false;
break;
}
case RANGE_REF: // fallthrough
case ARRAY_REF:
{
// sizes are independent of whether these are contained in blocking/non-blocking statements
fold_expressions = true;
break;
}
case TASK: //fallthrough
case STATEMENT: //fallthough
case FUNCTION: // fallthrough
case INITIAL: // fallthrough
case ALWAYS:
{
is_generate_region = false;
}
default:
{
break;
}
}
if (child_skip_list && node->num_children > 0 && skip_children == false)
{
/* use while loop and boolean to prevent optimizations
since number of children may change during recursion */
bool done = false;
int i = 0;
sc_hierarchy *new_ref = NULL;
if (node->type == BLOCK)
{
if (node->types.hierarchy)
{
new_ref = node->types.hierarchy;
}
}
if (!new_ref)
{
new_ref = local_ref;
}
/* traverse all the children */
while (done == false)
{
int num_original_children = node->num_children;
if (child_skip_list[i] == false)
{
/* recurse */
ast_node_t *old_child = node->children[i];
ast_node_t *new_child = build_hierarchy(old_child, node, i, new_ref, is_generate_region, fold_expressions, data);
node->children[i] = new_child;
if (old_child != new_child)
{
/* recurse on this child again in case it can be further reduced
(e.g. resolved generate constructs) */
i--;
}
}
if (num_original_children != node->num_children)
{
child_skip_list = (short *)vtr::realloc(child_skip_list, sizeof(short)*node->num_children);
for (int j = num_original_children; j < node->num_children; j++)
{
child_skip_list[j] = false;
}
}
i++;
if (i >= node->num_children)
{
done = true;
}
}
}
/* post-amble */
switch (node->type)
{
case MODULE:
{
int i, j;
/* update module instance parameters */
for (i = 0; i < node->types.module.size_module_instantiations; i++)
{
ast_node_t *instance_node = node->types.module.module_instantiations_instance[i];
std::string instance_name(instance_node->children[1]->children[0]->types.identifier);
// check defparams for a match
if (local_defparam_table_sc)
{
for (j = 0; j < local_defparam_table_sc->free; j++)
{
// a matching parameter at this scope will just have the instance name
// and parameter, e.g. defparam inst_1.a = 4
std::string defparam_ref(local_defparam_table_sc->string[j]);
size_t param_loc = defparam_ref.find_last_of('.');
std::string param_ref = defparam_ref.substr(param_loc+1, std::string::npos);
defparam_ref.erase(param_loc, std::string::npos);
if (defparam_ref.find_first_of('.') != std::string::npos)
{
continue;
}
// if this point is reached then the defparam is referencing an instance
// that was created in this module (or an instance in an encompassing module...
// but we'll add that functionality later (TODO))
if (strcmp(defparam_ref.c_str(), instance_name.c_str()) == 0)
{
ast_node_t *instance_param_list = instance_node->children[1]->children[2];
ast_node_t *param_node = ast_node_deep_copy((ast_node_t *)local_defparam_table_sc->data[j]);
// identifier expected to be parameter name only
vtr::free(param_node->children[0]->types.identifier);
param_node->children[0]->types.identifier = vtr::strdup(param_ref.c_str());
if (!instance_param_list)
{
instance_param_list = create_node_w_type(MODULE_PARAMETER_LIST, instance_node->line_number, current_parse_file);
instance_node->children[1]->children[2] = instance_param_list;
}
add_child_to_node(instance_param_list, param_node);
// set to null to find conflicts later
local_defparam_table_sc->data[j] = NULL;
break;
}
}
}
}
for (i = 0; i < node->types.function.size_function_instantiations; i++)
{
/* make the stringed up module instance name - instance name is
* MODULE_INSTANCE->MODULE_NAMED_INSTANCE(child[1])->IDENTIFIER(child[0]).
* module name is MODULE_INSTANCE->IDENTIFIER(child[0])
*/
ast_node_t *temp_instance = node->types.function.function_instantiations_instance[i];
char *instance_name_prefix = local_ref->instance_name_prefix;
char *temp_instance_name = make_full_ref_name(instance_name_prefix,
temp_instance->children[0]->types.identifier,
temp_instance->children[1]->children[0]->types.identifier,
NULL, -1);
long sc_spot;
/* lookup the name of the function associated with this instantiated point */
if ((sc_spot = sc_lookup_string(module_names_to_idx, temp_instance->children[0]->types.identifier)) == -1)
{
error_message(NETLIST_ERROR, node->line_number, node->file_number,
"Can't find function name %s\n", temp_instance->children[0]->types.identifier);
}
/* make a unique copy of this function */
ast_node_t *instance = ast_node_deep_copy((ast_node_t *)module_names_to_idx->data[sc_spot]);
long sc_spot_2 = sc_add_string(module_names_to_idx, temp_instance_name);
oassert(sc_spot_2 > -1 && module_names_to_idx->data[sc_spot_2] == NULL);
module_names_to_idx->data[sc_spot_2] = (void *)instance;
ast_modules = (ast_node_t **)vtr::realloc(ast_modules, sizeof(ast_node_t*)*(sc_spot_2 + 1));
ast_modules[sc_spot_2] = instance;
/* create the string cache list for the instantiated module */
sc_hierarchy *original_sc_hierarchy = ((ast_node_t *)module_names_to_idx->data[sc_spot])->types.hierarchy;
sc_hierarchy *function_sc_hierarchy = copy_sc_hierarchy(original_sc_hierarchy);
function_sc_hierarchy->parent = local_ref;
function_sc_hierarchy->instance_name_prefix = vtr::strdup(temp_instance_name);
function_sc_hierarchy->scope_id = vtr::strdup(temp_instance->children[1]->children[0]->types.identifier);
function_sc_hierarchy->top_node = instance;
/* update parent string cache list */
int num_function_children = local_ref->num_function_children;
local_ref->function_children = (sc_hierarchy **)vtr::realloc(local_ref->function_children, sizeof(sc_hierarchy *)*(num_function_children + 1));
local_ref->function_children[i] = function_sc_hierarchy;
local_ref->num_function_children++;
/* elaboration */
instance = build_hierarchy(instance, NULL, -1, function_sc_hierarchy, false, true, data);
/* clean up */
vtr::free(temp_instance_name);
}
for (i = 0; i < node->types.task.size_task_instantiations; i++)
{
/* make the stringed up module instance name - instance name is
* MODULE_INSTANCE->MODULE_NAMED_INSTANCE(child[1])->IDENTIFIER(child[0]).
* module name is MODULE_INSTANCE->IDENTIFIER(child[0])
*/
ast_node_t *temp_instance = node->types.task.task_instantiations_instance[i];
char *instance_name_prefix = local_ref->instance_name_prefix;
char *temp_instance_name = make_full_ref_name(instance_name_prefix,
temp_instance->children[0]->types.identifier,
temp_instance->children[1]->children[0]->types.identifier,
NULL, -1);
long sc_spot;
/* lookup the name of the task associated with this instantiated point */
if ((sc_spot = sc_lookup_string(module_names_to_idx, temp_instance->children[0]->types.identifier)) == -1)
{
error_message(NETLIST_ERROR, node->line_number, node->file_number,
"Can't find task name %s\n", temp_instance->children[0]->types.identifier);
}
/* make a unique copy of this task */
ast_node_t *instance = ast_node_deep_copy((ast_node_t *)module_names_to_idx->data[sc_spot]);
long sc_spot_2 = sc_add_string(module_names_to_idx, temp_instance_name);
oassert(sc_spot_2 > -1 && module_names_to_idx->data[sc_spot_2] == NULL);
module_names_to_idx->data[sc_spot_2] = (void *)instance;
ast_modules = (ast_node_t **)vtr::realloc(ast_modules, sizeof(ast_node_t*)*(sc_spot_2 + 1));
ast_modules[sc_spot_2] = instance;
/* create the string cache list for the instantiated module */
sc_hierarchy *original_sc_hierarchy = ((ast_node_t *)module_names_to_idx->data[sc_spot])->types.hierarchy;
sc_hierarchy *task_sc_hierarchy = copy_sc_hierarchy(original_sc_hierarchy);
task_sc_hierarchy->parent = local_ref;
task_sc_hierarchy->instance_name_prefix = vtr::strdup(temp_instance_name);
task_sc_hierarchy->scope_id = vtr::strdup(temp_instance->children[1]->children[0]->types.identifier);
/* update parent string cache list */
int num_task_children = local_ref->num_task_children;
local_ref->task_children = (sc_hierarchy **)vtr::realloc(local_ref->task_children, sizeof(sc_hierarchy *)*(num_task_children + 1));
local_ref->task_children[i] = task_sc_hierarchy;
local_ref->num_task_children++;
/* elaboration */
instance = build_hierarchy(instance, NULL, -1, task_sc_hierarchy, false, true, data);
/* clean up */
vtr::free(temp_instance_name);
}
break;
}
case MODULE_INSTANCE:
{
/* this should be encountered once generate constructs are resolved, so we don't have
stray instances that never get instantiated */
if (node->num_children == 2)
{
sc_hierarchy *this_ref = local_ref;
std::string new_id(node->children[1]->children[0]->types.identifier);
while (this_ref->top_node->type != MODULE)
{
std::string this_scope(this_ref->scope_id);
new_id = this_scope + "." + new_id;
this_ref = this_ref->parent;
oassert(this_ref);
}
ast_node_t *module = this_ref->top_node;
oassert(module->type == MODULE);
int num_instances = module->types.module.size_module_instantiations;
char *new_instance_name = vtr::strdup(new_id.c_str());
bool found = false;
for (int i = 0; i < num_instances; i++)
{
ast_node_t *temp_instance_node = module->types.module.module_instantiations_instance[i];
char *temp_instance_name = temp_instance_node->children[1]->children[0]->types.identifier;
if (strcmp(node->children[1]->children[0]->types.identifier, temp_instance_name) == 0
|| strcmp(new_instance_name, temp_instance_name) == 0)
{
found = true;
}
}
if (found)
{
vtr::free(new_instance_name);
break;
}
vtr::free(node->children[1]->children[0]->types.identifier);
node->children[1]->children[0]->types.identifier = new_instance_name;
module->types.module.module_instantiations_instance = (ast_node_t **)vtr::realloc(module->types.module.module_instantiations_instance, sizeof(ast_node_t*)*(num_instances+1));
module->types.module.module_instantiations_instance[num_instances] = node;
module->types.module.size_module_instantiations++;
/* make the stringed up module instance name - instance name is
* MODULE_INSTANCE->MODULE_NAMED_INSTANCE(child[1])->IDENTIFIER(child[0]).
* module name is MODULE_INSTANCE->IDENTIFIER(child[0])
*/
ast_node_t *temp_instance = node;
char *instance_name_prefix = this_ref->instance_name_prefix;
char *temp_instance_name = make_full_ref_name(instance_name_prefix,
temp_instance->children[0]->types.identifier,
temp_instance->children[1]->children[0]->types.identifier,
NULL, -1);
long sc_spot;
/* lookup the name of the module associated with this instantiated point */
if ((sc_spot = sc_lookup_string(module_names_to_idx, temp_instance->children[0]->types.identifier)) == -1)
{
error_message(NETLIST_ERROR, node->line_number, node->file_number,
"Can't find module name %s\n", temp_instance->children[0]->types.identifier);
}
/* make a unique copy of this module */
ast_node_t *instance = ast_node_deep_copy((ast_node_t *)module_names_to_idx->data[sc_spot]);
long sc_spot_2 = sc_add_string(module_names_to_idx, temp_instance_name);
oassert(sc_spot_2 > -1 && module_names_to_idx->data[sc_spot_2] == NULL);
module_names_to_idx->data[sc_spot_2] = (void *)instance;
ast_modules = (ast_node_t **)vtr::realloc(ast_modules, sizeof(ast_node_t*)*(sc_spot_2 + 1));
ast_modules[sc_spot_2] = instance;
/* create the string cache list for the instantiated module */
sc_hierarchy *original_sc_hierarchy = ((ast_node_t *)module_names_to_idx->data[sc_spot])->types.hierarchy;
sc_hierarchy *module_sc_hierarchy = copy_sc_hierarchy(original_sc_hierarchy);
instance->types.hierarchy = module_sc_hierarchy;
module_sc_hierarchy->parent = local_ref;
module_sc_hierarchy->instance_name_prefix = vtr::strdup(temp_instance_name);
module_sc_hierarchy->scope_id = vtr::strdup(temp_instance->children[1]->children[0]->types.identifier);
module_sc_hierarchy->top_node = instance;
/* update parent string cache list */
int num_module_children = local_ref->num_module_children;
local_ref->module_children = (sc_hierarchy **)vtr::realloc(local_ref->module_children, sizeof(sc_hierarchy *)*(num_module_children + 1));
local_ref->module_children[num_module_children] = module_sc_hierarchy;
local_ref->num_module_children++;
/* elaboration */
if (data->pass == 2)
{
/* make sure parameters are updated */
/* TODO apply remaining defparams and check for conflicts */
update_instance_parameter_table(temp_instance, module_sc_hierarchy->local_param_table_sc);
}
instance = build_hierarchy(instance, NULL, -1, module_sc_hierarchy, true, true, data);
/* clean up */
vtr::free(temp_instance_name);
}
break;
}
case BINARY_OPERATION:
{
if (node->children[0] == NULL || node->children[1] == NULL)
{
/* resulting from replication of zero */
error_message(NETLIST_ERROR, node->line_number, node->file_number,
"%s","Cannot perform operation with nonexistent value");
}
/* only fold if size can be self-determined */
if (data->pass == 2 && fold_expressions)
{
ast_node_t *new_node = fold_binary(&node);
if (node_is_constant(new_node))
{
/* resize as needed */
long child_0_size = node->children[0]->types.vnumber->size();
long child_1_size = node->children[1]->types.vnumber->size();
long new_size = (child_0_size > child_1_size) ? child_0_size : child_1_size;
/* clean up */
free_resolved_children(node);
change_to_number_node(node, VNumber(*(new_node->types.vnumber), new_size));
}
new_node = free_whole_tree(new_node);
}
break;
}
case UNARY_OPERATION:
{
if (node->children[0] == NULL)
{
/* resulting from replication of zero */
error_message(NETLIST_ERROR, node->line_number, node->file_number,
"%s","Cannot perform operation with nonexistent value");
}
/* only fold if size can be self-determined */
if (data->pass == 2 && fold_expressions)
{
ast_node_t *new_node = fold_unary(&node);
if (node_is_constant(new_node))
{
/* clean up */
free_resolved_children(node);
change_to_number_node(node, VNumber(*(new_node->types.vnumber), new_node->types.vnumber->size()));
}
new_node = free_whole_tree(new_node);
}
break;
}
case REPLICATE:
{
/* remove intermediate REPLICATE node */
if (data->pass == 2)
{
ast_node_t *child = node->children[0];
node->children[0] = NULL;
node = free_whole_tree(node);
node = child;
}
break;
}
case CONCATENATE:
{
if (data->pass == 2 && node->num_children > 0)
{
size_t current = 0;
size_t previous = -1;
bool previous_is_constant = false;
while (current < node->num_children)
{
bool current_is_constant = node_is_constant(node->children[current]);
if(previous_is_constant && current_is_constant)
{
resolve_concat_sizes(node->children[previous], local_ref);
resolve_concat_sizes(node->children[current], local_ref);
VNumber new_value = V_CONCAT({*(node->children[previous]->types.vnumber), *(node->children[current]->types.vnumber)});
node->children[current] = free_whole_tree(node->children[current]);
delete node->children[previous]->types.vnumber;
node->children[previous]->types.vnumber = new VNumber(new_value);
}
else if(node->children[current] != NULL)
{
previous += 1;
previous_is_constant = current_is_constant;
node->children[previous] = node->children[current];
}
current += 1;
}
node->num_children = previous+1;
if (node->num_children == 0)
{
// could we simply warn and continue ? any ways we can recover rather than fail?
/* resulting replication(s) of zero */
error_message(NETLIST_ERROR, node->line_number, node->file_number,
"%s","Cannot concatenate zero bitstrings");
}
// node was all constant
if (node->num_children == 1)
{
ast_node_t *tmp = node->children[0];
node->children[0] = NULL;
free_whole_tree(node);
node = tmp;
}
}
break;
}
case STATEMENT: //fallthrough
case TASK: //fallthrough
case FUNCTION: // fallthrough
case INITIAL: // fallthrough
case ALWAYS:
{
is_generate_region = true;
}
default:
{
break;
}
}
if (child_skip_list)
{
child_skip_list = (short*)vtr::free(child_skip_list);
}
}
return node;
}
/* ---------------------------------------------------------------------------------------------------
* (function: finalize_ast)
*
* This function resolves all parameters, folds constant expressions that can be self-determined
* (e.g. array/range refs, generate constructs), resolves module instances into module copies and hard
* blocks (while updating their parameter tables with defparams), and adds symbols that it finds to
* the symbol table.
* Basic sanity checks also happen here that weren't caught during parsing, e.g. checking port
* lists.
* --------------------------------------------------------------------------------------------------- */
ast_node_t *finalize_ast(ast_node_t *node, ast_node_t *parent, sc_hierarchy *local_ref, bool is_generate_region, bool fold_expressions)
{
short *child_skip_list = NULL; // list of children not to traverse into
short skip_children = false; // skips the DFS completely if true
STRING_CACHE *local_param_table_sc = local_ref->local_param_table_sc;
STRING_CACHE *local_symbol_table_sc = local_ref->local_symbol_table_sc;
if (node)
{
if (node->num_children > 0)
{
child_skip_list = (short*)vtr::calloc(node->num_children, sizeof(short));
}
/* pre-amble */
switch (node->type)
{
case MODULE:
{
oassert(child_skip_list);
// skip identifier
child_skip_list[0] = true;
break;
}
case FUNCTION:
{
if (parent != NULL)
{
skip_children = true;
}
break;
}
case FUNCTION_INSTANCE:
{
// check ports
ast_node_t *connect_list = node->children[1]->children[1];
bool is_ordered_list;
if (connect_list->children[1]->children[0]) // skip first connection
{
is_ordered_list = false; // name was specified
}
else
{
is_ordered_list = true;
}
for (int i = 1; i < connect_list->num_children; i++)
{
if ((connect_list->children[i]->children[0] && is_ordered_list)
|| (!connect_list->children[i]->children[0] && !is_ordered_list))
{
error_message(PARSE_ERROR, node->line_number, node->file_number,
"%s", "Cannot mix port connections by name and port connections by ordered list\n");
}
}
skip_children = true;
break;
}
case TASK:
{
if(parent != NULL)
{
skip_children = true;
}
break;
}
case TASK_INSTANCE:
{
// check ports
ast_node_t *connect_list = node->children[1]->children[1];
bool is_ordered_list;
if (connect_list->children[1]->children[0]) // skip first connection
{
is_ordered_list = false; // name was specified
}
else
{
is_ordered_list = true;
}
for (int i = 1; i < connect_list->num_children; i++)
{
if ((connect_list->children[i]
&& connect_list->children[i]->children)
&& (( connect_list->children[i]->children[0] && is_ordered_list)
|| (!connect_list->children[i]->children[0] && !is_ordered_list)))
{
error_message(PARSE_ERROR, node->line_number, node->file_number,
"%s", "Cannot mix port connections by name and port connections by ordered list\n");
}
}
skip_children = true;
break;
}
case MODULE_ITEMS:
{
/* look in the string cache for in-line continuous assignments */
ast_node_t **local_symbol_table = local_ref->local_symbol_table;
int num_local_symbol_table = local_ref->num_local_symbol_table;
for (int i = 0; i < num_local_symbol_table; i++)
{
ast_node_t *var_declare = local_symbol_table[i];
if (var_declare->types.variable.is_wire && var_declare->children[5] != NULL)
{
/* in-line assignment; split into its own continuous assignment */
ast_node_t *id = ast_node_copy(var_declare->children[0]);
ast_node_t *val = var_declare->children[5];
var_declare->children[5] = NULL;
ast_node_t *blocking_node = newBlocking(id, val, var_declare->line_number);
ast_node_t *assign_node = newList(ASSIGN, blocking_node, var_declare->line_number);
add_child_to_node(node, assign_node);
}
}
break;
}
case VAR_DECLARE:
{
oassert(child_skip_list);
child_skip_list[0] = true;
break;
}
case IDENTIFIERS:
{
if (local_param_table_sc != NULL && node->types.identifier)
{
long sc_spot = sc_lookup_string(local_param_table_sc, node->types.identifier);
if (sc_spot != -1)
{
ast_node_t *newNode = ast_node_deep_copy((ast_node_t *)local_param_table_sc->data[sc_spot]);
if (newNode->type != NUMBERS)
{
newNode = finalize_ast(newNode, parent, local_ref, is_generate_region, true);
oassert(newNode->type == NUMBERS);
/* this forces parameter values as unsigned, since we don't currently support signed keyword...
must be changed once support is added */
VNumber *temp = newNode->types.vnumber;
VNumber *to_unsigned = new VNumber(V_UNSIGNED(*temp));
newNode->types.vnumber = to_unsigned;
delete temp;
if (newNode->type != NUMBERS)
{
error_message(NETLIST_ERROR, node->line_number, node->file_number, "Parameter %s is not a constant expression\n", node->types.identifier);
}
}
node = free_whole_tree(node);
node = newNode;
}
}
break;
}
case FOR:
{
oassert(child_skip_list);
// look ahead for parameters in loop conditions
node->children[0] = finalize_ast(node->children[0], node, local_ref, is_generate_region, true);
node->children[1] = finalize_ast(node->children[1], node, local_ref, is_generate_region, true);
node->children[2] = finalize_ast(node->children[2], node, local_ref, is_generate_region, true);
// update skip list
child_skip_list[0] = true;
child_skip_list[1] = true;
child_skip_list[2] = true;
// if this is a loop generate construct, verify constant expressions
if (is_generate_region)
{
ast_node_t *iterator = NULL;
ast_node_t *initial = node->children[0];
ast_node_t *compare_expression = node->children[1];
ast_node_t *terminal = node->children[2];
char **genvar_list = NULL;
verify_genvars(node, local_ref, &genvar_list, 0);
if (genvar_list) vtr::free(genvar_list);
iterator = resolve_hierarchical_name_reference(local_ref, initial->children[0]->types.identifier);
oassert(iterator != NULL);
if ( !(node_is_constant(initial->children[1]))
|| !(node_is_constant(compare_expression->children[1]))
|| !(verify_terminal(terminal->children[1], iterator))
)
{
error_message(NETLIST_ERROR, node->line_number, node->file_number,
"%s","Loop generate construct conditions must be constant expressions");
}
}
int num_unrolled = 0;
node = unroll_for_loop(node, parent, &num_unrolled, local_ref, is_generate_region);
break;
}
case STATEMENT: //fallthrough
case ALWAYS: // fallthrough
case INITIAL:
{
is_generate_region = false;
break;
}
case BLOCKING_STATEMENT:
case NON_BLOCKING_STATEMENT:
{
/* fill out parameters and try to resolve self-determined expressions */
if (node->children[1]->type != FUNCTION_INSTANCE)
{
node->children[0] = finalize_ast(node->children[0], node, local_ref, is_generate_region, true);
if (node->children[1]->type != NUMBERS)
{
node->children[1] = finalize_ast(node->children[1], node, local_ref, is_generate_region, false);
if (node->children[1] == NULL)
{
/* resulting from replication of zero */
error_message(NETLIST_ERROR, node->line_number, node->file_number,
"%s","Cannot perform assignment with nonexistent value");
}
}
skip_children = true;
}
break;
}
case REPLICATE:
{
node->children[0] = finalize_ast(node->children[0], node, local_ref, is_generate_region, true);
if (!(node_is_constant(node->children[0])))
{
error_message(NETLIST_ERROR, node->line_number, node->file_number,
"%s","Replication constant must be a constant expression");
}
else if (node->children[0]->types.vnumber->is_dont_care_string())
{
error_message(NETLIST_ERROR, node->line_number, node->file_number,
"%s","Replication constant cannot contain x or z");
}
ast_node_t *new_node = NULL;
int64_t value = node->children[0]->types.vnumber->get_value();
if (value > 0)
{
new_node = create_node_w_type(CONCATENATE, node->line_number, node->file_number);
for (size_t i = 0; i < value; i++)
{
add_child_to_node(new_node, ast_node_deep_copy(node->children[1]));
}
}
node->children[1] = free_whole_tree(node->children[1]);
node->children[1] = NULL;
node->num_children--;
node->children[0] = free_whole_tree(node->children[0]);
node->children[0] = new_node;
break;
}
case RANGE_REF:
case ARRAY_REF:
{
/* these need to be folded if they are binary expressions... regardless of fold_expressions */
for (int i = 1; i < node->num_children; i++)
{
node->children[i] = finalize_ast(node->children[i], node, local_ref, is_generate_region, true);
}
skip_children = true;
break;
}
default:
{
break;
}
}
if (child_skip_list && node->num_children > 0 && skip_children == false)
{
/* use while loop and boolean to prevent optimizations
since number of children may change during recursion */
bool done = false;
int i = 0;
sc_hierarchy *new_ref = NULL;
if (node->type == BLOCK)
{
if (node->types.hierarchy)
{
new_ref = node->types.hierarchy;
}
}
if (!new_ref)
{
new_ref = local_ref;
}
/* traverse all the children */
while (done == false)
{
int num_original_children = node->num_children;
if (child_skip_list[i] == false)
{
/* recurse */
ast_node_t *old_child = node->children[i];
ast_node_t *new_child = finalize_ast(old_child, node, new_ref, is_generate_region, fold_expressions);
node->children[i] = new_child;
if (old_child != new_child)
{
/* recurse on this child again in case it can be further reduced
(e.g. resolved generate constructs) */
i--;
}
}
if (num_original_children != node->num_children)
{
child_skip_list = (short *)vtr::realloc(child_skip_list, sizeof(short)*node->num_children);
for (int j = num_original_children; j < node->num_children; j++)
{
child_skip_list[j] = false;
}
}
i++;
if (i >= node->num_children)
{
done = true;
}
}
}
/* post-amble */
switch (node->type)
{
case MODULE:
{
int i;
for (i = 0; i < node->types.module.size_module_instantiations; i++)
{
ast_node_t *instance;
/* make the stringed up module instance name - instance name is
* MODULE_INSTANCE->MODULE_NAMED_INSTANCE(child[1])->IDENTIFIER(child[0]).
* module name is MODULE_INSTANCE->IDENTIFIER(child[0])
*/
ast_node_t *temp_instance = node->types.module.module_instantiations_instance[i];
char *instance_name_prefix = local_ref->instance_name_prefix;
char *temp_instance_name = make_full_ref_name(instance_name_prefix,
temp_instance->children[0]->types.identifier,
temp_instance->children[1]->children[0]->types.identifier,
NULL, -1);
long sc_spot = sc_lookup_string(module_names_to_idx, temp_instance_name);
// TODO this part is temporary
if (sc_spot == -1)
{
// this was from a generate construct
long sc_spot_2;
/* lookup the name of the module associated with this instantiated point */
if ((sc_spot_2 = sc_lookup_string(module_names_to_idx, temp_instance->children[0]->types.identifier)) == -1)
{
error_message(NETLIST_ERROR, node->line_number, node->file_number,
"Can't find module name %s\n", temp_instance->children[0]->types.identifier);
}
/* make a unique copy of this module */
instance = ast_node_deep_copy((ast_node_t *)module_names_to_idx->data[sc_spot_2]);
sc_spot = sc_add_string(module_names_to_idx, temp_instance_name);
module_names_to_idx->data[sc_spot] = (void *)instance;
ast_modules = (ast_node_t **)vtr::realloc(ast_modules, sizeof(ast_node_t*)*(sc_spot + 1));
ast_modules[sc_spot] = instance;
/* create the string cache list for the instantiated module */
sc_hierarchy *original_sc_hierarchy = ((ast_node_t *)module_names_to_idx->data[sc_spot])->types.hierarchy;
sc_hierarchy *module_sc_hierarchy = copy_sc_hierarchy(original_sc_hierarchy);
module_sc_hierarchy->parent = local_ref;
module_sc_hierarchy->instance_name_prefix = vtr::strdup(temp_instance_name);
module_sc_hierarchy->scope_id = vtr::strdup(temp_instance->children[1]->children[0]->types.identifier);
/* update parent string cache list */
int num_module_children = local_ref->num_module_children;
local_ref->module_children = (sc_hierarchy **)vtr::realloc(local_ref->module_children, sizeof(sc_hierarchy *)*(num_module_children + 1));
local_ref->module_children[i] = module_sc_hierarchy;
local_ref->num_module_children++;
}
else
{
instance = (ast_node_t *)module_names_to_idx->data[sc_spot];
}
sc_hierarchy *module_sc_hierarchy = instance->types.hierarchy;
/* update the parameter table for the instantiated module */
STRING_CACHE *instance_param_table_sc = module_sc_hierarchy->local_param_table_sc;
update_instance_parameter_table(temp_instance, instance_param_table_sc);
/* elaboration */
update_string_caches(module_sc_hierarchy);
instance = finalize_ast(instance, NULL, module_sc_hierarchy, true, true);
/* clean up */
vtr::free(temp_instance_name);
}
for (i = 0; i < node->types.function.size_function_instantiations; i++)
{
/* make the stringed up module instance name - instance name is
* MODULE_INSTANCE->MODULE_NAMED_INSTANCE(child[1])->IDENTIFIER(child[0]).
* module name is MODULE_INSTANCE->IDENTIFIER(child[0])
*/
ast_node_t *temp_instance = node->types.function.function_instantiations_instance[i];
char *instance_name_prefix = local_ref->instance_name_prefix;
char *temp_instance_name = make_full_ref_name(instance_name_prefix,
temp_instance->children[0]->types.identifier,
temp_instance->children[1]->children[0]->types.identifier,
NULL, -1);
long sc_spot = sc_lookup_string(module_names_to_idx, temp_instance_name);
oassert(sc_spot > -1 && module_names_to_idx->data[sc_spot] != NULL);
ast_node_t *instance = (ast_node_t *)module_names_to_idx->data[sc_spot];
sc_hierarchy *function_sc_hierarchy = local_ref->function_children[i];
/* update the parameter table for the instantiated module */
STRING_CACHE *instance_param_table_sc = function_sc_hierarchy->local_param_table_sc;
update_instance_parameter_table(temp_instance, instance_param_table_sc);
/* elaboration */
update_string_caches(function_sc_hierarchy);
instance = finalize_ast(instance, NULL, function_sc_hierarchy, false, true);
/* clean up */
vtr::free(temp_instance_name);
}
for (i = 0; i < node->types.task.size_task_instantiations; i++)
{
/* make the stringed up module instance name - instance name is
* MODULE_INSTANCE->MODULE_NAMED_INSTANCE(child[1])->IDENTIFIER(child[0]).
* module name is MODULE_INSTANCE->IDENTIFIER(child[0])
*/
ast_node_t *temp_instance = node->types.task.task_instantiations_instance[i];
char *instance_name_prefix = local_ref->instance_name_prefix;
char *temp_instance_name = make_full_ref_name(instance_name_prefix,
temp_instance->children[0]->types.identifier,
temp_instance->children[1]->children[0]->types.identifier,
NULL, -1);
/* lookup the name of the task associated with this instantiated point */
long sc_spot = sc_lookup_string(module_names_to_idx, temp_instance->children[0]->types.identifier);
oassert(sc_spot > -1 && module_names_to_idx->data[sc_spot] != NULL);
ast_node_t *instance = (ast_node_t *)module_names_to_idx->data[sc_spot];
sc_hierarchy *task_sc_hierarchy = local_ref->task_children[i];
/* update the parameter table for the instantiated module */
STRING_CACHE *instance_param_table_sc = task_sc_hierarchy->local_param_table_sc;
update_instance_parameter_table(temp_instance, instance_param_table_sc);
/* elaboration */
update_string_caches(task_sc_hierarchy);
instance = finalize_ast(instance, NULL, task_sc_hierarchy, false, true);
/* clean up */
vtr::free(temp_instance_name);
}
break;
}
case MODULE_INSTANCE:
{
/* this should be encountered once generate constructs are resolved, so we don't have
stray instances that never get instantiated */
if (node->num_children == 2)
{
sc_hierarchy *this_ref = local_ref;
std::string new_id(node->children[1]->children[0]->types.identifier);
while (this_ref->top_node->type != MODULE)
{
std::string this_scope(this_ref->scope_id);
new_id = this_scope + "." + new_id;
this_ref = this_ref->parent;
oassert(this_ref);
}
ast_node_t *module = this_ref->top_node;
oassert(module->type == MODULE);
int num_instances = module->types.module.size_module_instantiations;
char *new_instance_name = vtr::strdup(new_id.c_str());
bool found = false;
for (int i = 0; i < num_instances; i++)
{
ast_node_t *temp_instance_node = module->types.module.module_instantiations_instance[i];
char *temp_instance_name = temp_instance_node->children[1]->children[0]->types.identifier;
if (strcmp(node->children[1]->children[0]->types.identifier, temp_instance_name) == 0
|| strcmp(new_instance_name, temp_instance_name) == 0)
{
found = true;
}
}
if (found)
{
vtr::free(new_instance_name);
break;
}
oassert(false); // module instances should be resolved at this point
}
break;
}
case VAR_DECLARE:
{
// pack 2d array into 1d
if (node->num_children == 8
&& node->children[5]
&& node->children[6])
{
convert_2D_to_1D_array(&node);
}
break;
}
case BINARY_OPERATION:
{
if (node->children[0] == NULL || node->children[1] == NULL)
{
/* resulting from replication of zero */
error_message(NETLIST_ERROR, node->line_number, node->file_number,
"%s","Cannot perform operation with nonexistent value");
}
/* only fold if size can be self-determined */
if (fold_expressions)
{
ast_node_t *new_node = fold_binary(&node);
if (node_is_constant(new_node))
{
/* resize as needed */
long child_0_size = node->children[0]->types.vnumber->size();
long child_1_size = node->children[1]->types.vnumber->size();
long new_size = (child_0_size > child_1_size) ? child_0_size : child_1_size;
/* clean up */
free_resolved_children(node);
change_to_number_node(node, VNumber(*(new_node->types.vnumber), new_size));
}
new_node = free_whole_tree(new_node);
}
break;
}
case UNARY_OPERATION:
{
if (node->children[0] == NULL)
{
/* resulting from replication of zero */
error_message(NETLIST_ERROR, node->line_number, node->file_number,
"%s","Cannot perform operation with nonexistent value");
}
/* only fold if size can be self-determined */
if (fold_expressions)
{
ast_node_t *new_node = fold_unary(&node);
if (node_is_constant(new_node))
{
/* clean up */
free_resolved_children(node);
change_to_number_node(node, VNumber(*(new_node->types.vnumber), new_node->types.vnumber->size()));
}
new_node = free_whole_tree(new_node);
}
break;
}
case REPLICATE:
{
/* remove intermediate REPLICATE node */
ast_node_t *child = node->children[0];
node->children[0] = NULL;
node = free_whole_tree(node);
node = child;
break;
}
case CONCATENATE:
{
if (node->num_children > 0)
{
size_t current = 0;
size_t previous = -1;
bool previous_is_constant = false;
while (current < node->num_children)
{
bool current_is_constant = node_is_constant(node->children[current]);
if(previous_is_constant && current_is_constant)
{
resolve_concat_sizes(node->children[previous], local_ref);
resolve_concat_sizes(node->children[current], local_ref);
VNumber new_value = V_CONCAT({*(node->children[previous]->types.vnumber), *(node->children[current]->types.vnumber)});
node->children[current] = free_whole_tree(node->children[current]);
delete node->children[previous]->types.vnumber;
node->children[previous]->types.vnumber = new VNumber(new_value);
}
else if(node->children[current] != NULL)
{
previous += 1;
previous_is_constant = current_is_constant;
node->children[previous] = node->children[current];
}
current += 1;
}
node->num_children = previous+1;
if (node->num_children == 0)
{
// could we simply warn and continue ? any ways we can recover rather than fail?
/* resulting replication(s) of zero */
error_message(NETLIST_ERROR, node->line_number, node->file_number,
"%s","Cannot concatenate zero bitstrings");
}
// node was all constant
if (node->num_children == 1)
{
ast_node_t *tmp = node->children[0];
node->children[0] = NULL;
free_whole_tree(node);
node = tmp;
}
}
break;
}
case RANGE_REF:
{
bool is_constant_ref = node_is_constant(node->children[1]);
if (is_constant_ref)
{
is_constant_ref = is_constant_ref && !(node->children[1]->types.vnumber->is_dont_care_string());
}
is_constant_ref = is_constant_ref && node_is_constant(node->children[2]);
if (is_constant_ref)
{
is_constant_ref = is_constant_ref && !(node->children[2]->types.vnumber->is_dont_care_string());
}
if (!is_constant_ref)
{
/* note: indexed part-selects (-: and +:) should support non-constant base expressions,
e.g. my_var[some_input+:3] = 4'b0101, but we don't support it right now... */
error_message(NETLIST_ERROR, node->line_number, node->file_number,
"%s","Part-selects can only contain constant expressions");
}
break;
}
case ARRAY_REF:
{
bool is_constant_ref = node_is_constant(node->children[1]);
if (is_constant_ref)
{
is_constant_ref = is_constant_ref && !(node->children[1]->types.vnumber->is_dont_care_string());
}
if (node->num_children == 3)
{
is_constant_ref = is_constant_ref && node_is_constant(node->children[2]);
if (is_constant_ref)
{
is_constant_ref = is_constant_ref && !(node->children[2]->types.vnumber->is_dont_care_string());
}
}
if (!is_constant_ref)
{
// this must be an implicit memory
long sc_spot = sc_lookup_string(local_symbol_table_sc, node->children[0]->types.identifier);
oassert(sc_spot > -1);
((ast_node_t *)local_symbol_table_sc->data[sc_spot])->types.variable.is_memory = true;
}
if (node->num_children == 3) convert_2D_to_1D_array_ref(&node, local_ref);
break;
}
case STATEMENT: //fallthrough
case ALWAYS: // fallthrough
case INITIAL:
{
is_generate_region = true;
break;
}
default:
{
break;
}
}
if (child_skip_list)
{
child_skip_list = (short*)vtr::free(child_skip_list);
}
}
return node;
}
/* ---------------------------------------------------------------------------------------------------
* (function: reduce_expressions)
*
* This function folds remaining constant expressions now that symbols are found (e.g. for assign)
* (TODO) and resolves hierarchical references, and call netlist_expand on the way back up.
* --------------------------------------------------------------------------------------------------- */
ast_node_t *reduce_expressions(ast_node_t *node, sc_hierarchy *local_ref, long *max_size, long assignment_size)
{
short *child_skip_list = NULL; // list of children not to traverse into
short skip_children = false; // skips the DFS completely if true
if (node)
{
oassert(node->type != NO_ID);
STRING_CACHE *local_symbol_table_sc = local_ref->local_symbol_table_sc;
if (node->num_children > 0)
{
child_skip_list = (short*)vtr::calloc(node->num_children, sizeof(short));
}
switch (node->type)
{
case MODULE:
{
oassert(child_skip_list);
// skip identifier
child_skip_list[0] = true;
break;
}
case FUNCTION:
{
skip_children = true;
break;
}
case TASK:
{
skip_children = true;
break;
}
case MODULE_INSTANCE:
{
skip_children = true;
break;
}
case BLOCKING_STATEMENT:
case NON_BLOCKING_STATEMENT:
{
/* try to resolve */
if (node->children[1]->type != FUNCTION_INSTANCE)
{
node->children[0] = reduce_expressions(node->children[0], local_ref, NULL, 0);
assignment_size = get_size_of_variable(node->children[0], local_ref);
max_size = (long*)calloc(1, sizeof(long));
if (node->children[1]->type != NUMBERS)
{
node->children[1] = reduce_expressions(node->children[1], local_ref, max_size, assignment_size);
if (node->children[1] == NULL)
{
/* resulting from replication of zero */
error_message(NETLIST_ERROR, node->line_number, node->file_number,
"%s","Cannot perform assignment with nonexistent value");
}
}
else
{
VNumber *temp = node->children[1]->types.vnumber;
node->children[1]->types.vnumber = new VNumber(*temp, assignment_size);
delete temp;
}
vtr::free(max_size);
/* cast to unsigned if necessary */
if (node_is_constant(node->children[1]))
{
char *id = NULL;
if (node->children[0]->type == IDENTIFIERS)
{
id = node->children[0]->types.identifier;
}
else
{
id = node->children[0]->children[0]->types.identifier;
}
long sc_spot = sc_lookup_string(local_symbol_table_sc, id);
if (sc_spot > -1)
{
bool is_signed = ((ast_node_t *)local_symbol_table_sc->data[sc_spot])->types.variable.is_signed;
if (!is_signed)
{
VNumber *temp = node->children[1]->types.vnumber;
VNumber *to_unsigned = new VNumber(V_UNSIGNED(*temp));
node->children[1]->types.vnumber = to_unsigned;
delete temp;
}
else
{
/* leave as is */
}
}
}
else
{
/* signed keyword is not supported, meaning unresolved values will already be handled as
unsigned at the netlist level... must update once signed support is added */
}
assignment_size = 0;
skip_children = true;
}
break;
}
case VAR_DECLARE_LIST:
{
skip_children = true;
break;
}
case ARRAY_REF: // fallthrough
case RANGE_REF:
{
/* resolve the identifier in case it's in a different scope */
oassert(child_skip_list);
child_skip_list[0] = true;
break;
}
case IDENTIFIERS:
{
/* TODO: hierarchical reference checking... */
// if (sc_lookup_string(local_symbol_table_sc, node->types.identifier) == -1)
// {
// char *id = vtr::strdup(node->types.identifier);
// ast_node_t *var_declare = resolve_hierarchical_name_reference(local_ref, id);
// vtr::free(id);
// if (var_declare)
// {
// long sc_spot = sc_add_string(local_symbol_table_sc, node->types.identifier);
// local_symbol_table_sc->data[sc_spot] = (void *)ast_node_deep_copy(var_declare);
// }
// else
// {
// /* error - symbol either doesn't exist or is not accessible to this scope */
// error_message(NETLIST_ERROR, node->line_number, node->file_number,
// "Missing declaration of this symbol %s\n", node->types.identifier);
// }
// }
break;
}
default:
{
break;
}
}
if (child_skip_list && node->num_children > 0 && skip_children == false)
{
/* use while loop and boolean to prevent optimizations
since number of children may change during recursion */
bool done = false;
int i = 0;
/* traverse all the children */
while (done == false)
{
int num_original_children = node->num_children;
if (child_skip_list[i] == false)
{
/* recurse */
ast_node_t *old_child = node->children[i];
ast_node_t *new_child = reduce_expressions(old_child, local_ref, max_size, assignment_size);
node->children[i] = new_child;
if (old_child != new_child)
{
/* recurse on this child again in case it can be further reduced */
i--;
}
}
if (num_original_children != node->num_children)
{
child_skip_list = (short *)vtr::realloc(child_skip_list, sizeof(short)*node->num_children);
for (int j = num_original_children; j < node->num_children; j++)
{
child_skip_list[j] = false;
}
}
i++;
if (i >= node->num_children)
{
done = true;
}
}
}
/* post-amble */
switch (node->type)
{
case MODULE:
{
int i;
/* sort of the same thing as we do in finalize_ast - call reduce_expressions on children */
for (i = 0; i < node->types.module.size_module_instantiations; i++)
{
/* make the stringed up module instance name - instance name is
* MODULE_INSTANCE->MODULE_NAMED_INSTANCE(child[1])->IDENTIFIER(child[0]).
* module name is MODULE_INSTANCE->IDENTIFIER(child[0])
*/
ast_node_t *temp_instance = node->types.module.module_instantiations_instance[i];
char *instance_name_prefix = local_ref->instance_name_prefix;
char *temp_instance_name = make_full_ref_name(instance_name_prefix,
temp_instance->children[0]->types.identifier,
temp_instance->children[1]->children[0]->types.identifier,
NULL, -1);
long sc_spot = sc_lookup_string(module_names_to_idx, temp_instance_name);
/* lookup the name of the module associated with this instantiated point */
oassert(sc_spot != -1);
ast_node_t *instance = (ast_node_t *)module_names_to_idx->data[sc_spot];
/* elaboration */
sc_hierarchy *module_sc_hierarchy = instance->types.hierarchy;
instance = reduce_expressions(instance, module_sc_hierarchy, NULL, 0);
/* clean up */
vtr::free(temp_instance_name);
}
for (i = 0; i < node->types.function.size_function_instantiations; i++)
{
/* make the stringed up module instance name - instance name is
* MODULE_INSTANCE->MODULE_NAMED_INSTANCE(child[1])->IDENTIFIER(child[0]).
* module name is MODULE_INSTANCE->IDENTIFIER(child[0])
*/
ast_node_t *temp_instance = node->types.function.function_instantiations_instance[i];
char *instance_name_prefix = local_ref->instance_name_prefix;
char *temp_instance_name = make_full_ref_name(instance_name_prefix,
temp_instance->children[0]->types.identifier,
temp_instance->children[1]->children[0]->types.identifier,
NULL, -1);
long sc_spot = sc_lookup_string(module_names_to_idx, temp_instance_name);
/* lookup the name of the module associated with this instantiated point */
oassert(sc_spot != -1);
ast_node_t *instance = (ast_node_t *)module_names_to_idx->data[sc_spot];
/* elaboration */
sc_hierarchy *function_sc_hierarchy = local_ref->function_children[i];
instance = reduce_expressions(instance, function_sc_hierarchy, NULL, 0);
/* clean up */
vtr::free(temp_instance_name);
}
break;
}
case CONCATENATE:
{
resolve_concat_sizes(node, local_ref);
break;
}
case BINARY_OPERATION:
{
if (node->children[0] == NULL || node->children[1] == NULL)
{
/* resulting from replication of zero */
error_message(NETLIST_ERROR, node->line_number, node->file_number,
"%s","Cannot perform operation with nonexistent value");
}
ast_node_t *new_node = fold_binary(&node);
if (node_is_constant(new_node))
{
/* resize as needed */
long new_size;
long this_size = new_node->types.vnumber->size();
if (assignment_size > 0)
{
new_size = assignment_size;
}
else if (max_size)
{
new_size = *max_size;
}
else
{
new_size = this_size;
}
/* clean up */
free_resolved_children(node);
change_to_number_node(node, VNumber(*(new_node->types.vnumber), new_size));
}
new_node = free_whole_tree(new_node);
break;
}
case UNARY_OPERATION:
{
if (node->children[0] == NULL)
{
/* resulting from replication of zero */
error_message(NETLIST_ERROR, node->line_number, node->file_number,
"%s","Cannot perform operation with nonexistent value");
}
ast_node_t *new_node = fold_unary(&node);
if (node_is_constant(new_node))
{
/* resize as needed */
long new_size;
long this_size = new_node->types.vnumber->size();
if (assignment_size > 0)
{
new_size = assignment_size;
}
else if (max_size)
{
new_size = *max_size;
}
else
{
new_size = this_size;
}
/* clean up */
free_resolved_children(node);
change_to_number_node(node, VNumber(*(new_node->types.vnumber), new_size));
}
new_node = free_whole_tree(new_node);
break;
}
case IDENTIFIERS:
{
// look up to resolve unresolved range refs
ast_node_t *var_node = NULL;
if (node->types.identifier)
{
long sc_spot = sc_lookup_string(local_symbol_table_sc, node->types.identifier);
if (sc_spot > -1)
{
var_node = (ast_node_t *)local_symbol_table_sc->data[sc_spot];
if (var_node->children[1] != NULL)
{
oassert(node_is_constant(var_node->children[1]) && node_is_constant(var_node->children[2]));
}
if (var_node->children[3] != NULL)
{
oassert(node_is_constant(var_node->children[3]) && node_is_constant(var_node->children[4]));
}
if (var_node->num_children == 8 && var_node->children[5])
{
oassert(node_is_constant(var_node->children[5]) && node_is_constant(var_node->children[6]));
}
local_symbol_table_sc->data[sc_spot] = (void *)var_node;
}
if (max_size)
{
long var_size = get_size_of_variable(node, local_ref);
if (var_size > *max_size)
{
*max_size = var_size;
}
}
}
break;
}
case NUMBERS:
{
if (max_size)
{
if (node->types.vnumber->size() > (*max_size))
{
*max_size = node->types.vnumber->size();
}
}
break;
}
default:
{
break;
}
}
if (child_skip_list)
{
child_skip_list = (short*)vtr::free(child_skip_list);
}
}
return node;
}
void update_string_caches(sc_hierarchy *local_ref)
{
STRING_CACHE *local_param_table_sc = local_ref->local_param_table_sc;
ast_node_t **local_symbol_table = local_ref->local_symbol_table;
int num_local_symbol_table = local_ref->num_local_symbol_table;
int i = 0;
if (local_param_table_sc)
{
while (i < local_param_table_sc->size && local_param_table_sc->data[i] != NULL)
{
ast_node_t *param_val = (ast_node_t *)local_param_table_sc->data[i];
if (param_val->type == VAR_DECLARE && !node_is_constant(param_val->children[5]))
{
ast_node_t *resolved_val = finalize_ast(param_val->children[5], NULL, local_ref, true, true);
oassert(resolved_val);
param_val->children[5] = NULL;
free_whole_tree(param_val);
param_val = resolved_val;
}
else
{
sc_hierarchy *this_ref = local_ref;
while (this_ref && !node_is_constant(param_val))
{
param_val = finalize_ast(param_val, NULL, this_ref, true, true);
this_ref = this_ref->parent;
}
}
oassert(node_is_constant(param_val));
/* this forces parameter values as unsigned, since we don't currently support signed keyword...
must be changed once support is added */
VNumber *temp = param_val->types.vnumber;
VNumber *to_unsigned = new VNumber(V_UNSIGNED(*temp));
param_val->types.vnumber = to_unsigned;
delete temp;
local_param_table_sc->data[i] = (void *)param_val;
i++;
}
}
for (i = 0; i < num_local_symbol_table; i++)
{
ast_node_t *var_declare = local_symbol_table[i];
if ((var_declare->children[1] && !node_is_constant(var_declare->children[1]))
|| (var_declare->children[2] && !node_is_constant(var_declare->children[2]))
|| (var_declare->children[3] && !node_is_constant(var_declare->children[3]))
|| (var_declare->children[4] && !node_is_constant(var_declare->children[4]))
|| var_declare->num_children == 8
)
{
local_symbol_table[i] = finalize_ast(var_declare, NULL, local_ref, true, true);
}
}
}
void update_instance_parameter_table(ast_node_t *instance, STRING_CACHE *instance_param_table_sc)
{
if (instance->children[1]->children[2] && instance->children[1]->children[2]->num_children > 0)
{
long sc_spot;
ast_node_t *parameter_override_list = instance->children[1]->children[2];
int param_count = 0;
bool is_by_name = parameter_override_list->children[0]->types.variable.is_parameter
&& parameter_override_list->children[0]->children[0] != NULL;
/* error checks for overrides passed directly into instance */
for (int j = 0; j < parameter_override_list->num_children; j++)
{
if (parameter_override_list->children[j]->types.variable.is_parameter)
{
param_count++;
if (is_by_name != (parameter_override_list->children[j]->children[0] != NULL))
{
error_message(PARSE_ERROR, parameter_override_list->line_number, parameter_override_list->file_number,
"%s", "Cannot mix parameters passed by name and parameters passed by ordered list\n");
}
else if (is_by_name)
{
char *param_id = parameter_override_list->children[j]->children[0]->types.identifier;
for (int k = 0; k < j; k++)
{
if (!strcmp(param_id, parameter_override_list->children[k]->children[0]->types.identifier))
{
error_message(PARSE_ERROR, parameter_override_list->line_number, parameter_override_list->file_number,
"Cannot override the same parameter twice (%s) within a module instance\n",
parameter_override_list->children[j]->children[0]->types.identifier);
}
}
sc_spot = sc_lookup_string(instance_param_table_sc, param_id);
if (sc_spot == -1)
{
error_message(NETLIST_ERROR, parameter_override_list->line_number, parameter_override_list->file_number,
"Can't find parameter name %s in module %s\n",
param_id, instance->children[0]->types.identifier);
}
}
else
{
char *param_id = vtr::strdup(instance_param_table_sc->string[j]);
ast_node_t *param_symbol = newSymbolNode(param_id, parameter_override_list->children[j]->line_number);
parameter_override_list->children[j]->children[0] = param_symbol;
}
}
else
{
oassert(parameter_override_list->children[j]->types.variable.is_defparam);
break;
}
}
if (!is_by_name && param_count > instance_param_table_sc->free)
{
error_message(NETLIST_ERROR, parameter_override_list->line_number, parameter_override_list->file_number,
"There are more parameters (%d) passed into %s than there are specified in the module (%ld)!",
param_count, instance->children[1]->children[0]->types.identifier, instance_param_table_sc->free);
}
/* fill out the overrides */
for (int j = (parameter_override_list->num_children - 1); j >= 0; j--)
{
char *param_id = parameter_override_list->children[j]->children[0]->types.identifier;
sc_spot = sc_lookup_string(instance_param_table_sc, param_id);
if (sc_spot == -1)
{
error_message(NETLIST_ERROR, parameter_override_list->line_number, parameter_override_list->file_number,
"Can't find parameter name %s in module %s\n",
param_id, instance->children[0]->types.identifier);
}
else
{
/* update this parameter and remove all other overrides with this name */
free_whole_tree(((ast_node_t *)instance_param_table_sc->data[sc_spot]));
instance_param_table_sc->data[sc_spot] = (void *)parameter_override_list->children[j]->children[5];
parameter_override_list->children[j]->children[5] = NULL;
for (int k = 0; k < j; k++)
{
if (!strcmp(parameter_override_list->children[k]->children[0]->types.identifier, param_id))
{
ast_node_t *temp = parameter_override_list->children[k];
remove_child_from_node_at_index(parameter_override_list, k);
temp = NULL;
j--;
k--;
}
}
ast_node_t *temp = parameter_override_list->children[j];
remove_child_from_node_at_index(parameter_override_list, j);
temp = NULL;
}
}
// check if there are still overrides in the list that haven't been deleted
if (parameter_override_list->num_children > 0)
{
oassert(false); // not reachable???
}
}
}
void override_parameters_for_all_instances(ast_node_t *module, sc_hierarchy *local_ref)
{
ast_node_t **module_instantiations_instance = module->types.module.module_instantiations_instance;
int size_module_instantiations = module->types.module.size_module_instantiations;
for (int i = 0; i < size_module_instantiations; i++)
{
ast_node_t *instance;
/* make the stringed up module instance name - instance name is
* MODULE_INSTANCE->MODULE_NAMED_INSTANCE(child[1])->IDENTIFIER(child[0]).
* module name is MODULE_INSTANCE->IDENTIFIER(child[0])
*/
ast_node_t *temp_instance = module_instantiations_instance[i];
char *instance_name_prefix = local_ref->instance_name_prefix;
char *temp_instance_name = make_full_ref_name(instance_name_prefix,
temp_instance->children[0]->types.identifier,
temp_instance->children[1]->children[0]->types.identifier,
NULL, -1);
long sc_spot = sc_lookup_string(module_names_to_idx, temp_instance_name);
vtr::free(temp_instance_name);
instance = (ast_node_t *)module_names_to_idx->data[sc_spot];
sc_hierarchy *module_sc_hierarchy = local_ref->module_children[i];
/* update the parameter table for the instantiated module */
STRING_CACHE *instance_param_table_sc = module_sc_hierarchy->local_param_table_sc;
update_instance_parameter_table(temp_instance, instance_param_table_sc);
/* go through this instance's children */
override_parameters_for_all_instances(instance, module_sc_hierarchy);
}
}
void convert_2D_to_1D_array(ast_node_t **var_declare)
{
ast_node_t *node_max2 = (*var_declare)->children[3];
ast_node_t *node_min2 = (*var_declare)->children[4];
ast_node_t *node_max3 = (*var_declare)->children[5];
ast_node_t *node_min3 = (*var_declare)->children[6];
oassert(node_min2->type == NUMBERS && node_max2->type == NUMBERS);
oassert(node_min3->type == NUMBERS && node_max3->type == NUMBERS);
long addr_min = node_min2->types.vnumber->get_value();
long addr_max = node_max2->types.vnumber->get_value();
long addr_min1= node_min3->types.vnumber->get_value();
long addr_max1= node_max3->types.vnumber->get_value();
if((addr_min > addr_max) || (addr_min1 > addr_max1))
{
error_message(NETLIST_ERROR, (*var_declare)->children[0]->line_number, (*var_declare)->children[0]->file_number, "%s",
"Odin doesn't support arrays declared [m:n] where m is less than n.");
}
else if((addr_min < 0 || addr_max < 0) || (addr_min1 < 0 || addr_max1 < 0))
{
error_message(NETLIST_ERROR, (*var_declare)->children[0]->line_number, (*var_declare)->children[0]->file_number, "%s",
"Odin doesn't support negative number in index.");
}
char *name = (*var_declare)->children[0]->types.identifier;
if (addr_min != 0 || addr_min1 != 0)
{
error_message(NETLIST_ERROR, (*var_declare)->children[0]->line_number, (*var_declare)->children[0]->file_number,
"%s: right memory address index must be zero\n", name);
}
long addr_chunk_size = (addr_max1 - addr_min1 + 1);
(*var_declare)->chunk_size = addr_chunk_size;
long new_address_max = (addr_max - addr_min + 1)*addr_chunk_size -1;
change_to_number_node((*var_declare)->children[3], new_address_max);
change_to_number_node((*var_declare)->children[4], 0);
(*var_declare)->children[5] = free_whole_tree((*var_declare)->children[5]);
(*var_declare)->children[6] = free_whole_tree((*var_declare)->children[6]);
(*var_declare)->children[5] = (*var_declare)->children[7];
(*var_declare)->children[7] = NULL;
(*var_declare)->num_children -= 2;
}
void convert_2D_to_1D_array_ref(ast_node_t **node, sc_hierarchy *local_ref)
{
STRING_CACHE *local_symbol_table_sc = local_ref->local_symbol_table_sc;
char * temp_string = make_full_ref_name(NULL, NULL, NULL, (*node)->children[0]->types.identifier, -1);
// look up chunk size
long sc_spot = sc_lookup_string(local_symbol_table_sc, temp_string);
oassert(sc_spot != -1);
ast_node_t *array_size = ast_node_deep_copy((ast_node_t *)local_symbol_table_sc->data[sc_spot]);
change_to_number_node(array_size, array_size->chunk_size);
ast_node_t *array_row = (*node)->children[1];
ast_node_t *array_col = (*node)->children[2];
// build the new AST
ast_node_t *new_node_1 = newBinaryOperation(MULTIPLY, array_row, array_size, (*node)->children[0]->line_number);
ast_node_t *new_node_2 = newBinaryOperation(ADD, new_node_1, array_col, (*node)->children[0]->line_number);
vtr::free(temp_string);
(*node)->children[1] = new_node_2;
(*node)->children[2] = NULL;
(*node)->num_children -= 1;
}
bool verify_terminal(ast_node_t *top, ast_node_t *iterator)
{
if (top)
{
if (top->type == BINARY_OPERATION)
{
return verify_terminal(top->children[0], iterator) && verify_terminal(top->children[1], iterator);
}
else if (top->type == UNARY_OPERATION)
{
return verify_terminal(top->children[0], iterator);
}
else if (top->type == IDENTIFIERS)
{
return (strcmp(top->types.identifier, iterator->children[0]->types.identifier) == 0);
}
else
{
return node_is_constant(top);
}
}
else
{
return false;
}
}
void verify_genvars(ast_node_t *node, sc_hierarchy *local_ref, char ***other_genvars, int num_genvars)
{
if (node)
{
if (node->type == FOR)
{
ast_node_t *initial = node->children[0];
ast_node_t *terminal = node->children[2];
ast_node_t *body = node->children[3];
ast_node_t *iterator = initial->children[0];
if (strcmp(initial->children[0]->types.identifier, terminal->children[0]->types.identifier) != 0)
{
/* must match */
error_message(NETLIST_ERROR, node->line_number, node->file_number,
"%s","Must use the same genvar for initial condition and iteration condition");
}
ast_node_t *var_declare = resolve_hierarchical_name_reference(local_ref, iterator->types.identifier);
if (var_declare == NULL)
{
error_message(NETLIST_ERROR, iterator->line_number, iterator->file_number,
"Missing declaration of this symbol %s\n", iterator->types.identifier);
}
else if (!var_declare->types.variable.is_genvar)
{
error_message(NETLIST_ERROR, node->line_number, node->file_number,
"%s","Iterator for loop generate construct must be declared as a genvar");
}
// check genvars that were already found
for (int i=0; i < num_genvars; i++)
{
if (!strcmp(iterator->types.identifier, (*other_genvars)[i]))
{
error_message(NETLIST_ERROR, node->line_number, node->file_number,
"%s","Cannot reuse a genvar in a nested loop sequence");
}
}
(*other_genvars) = (char **)vtr::realloc((*other_genvars), sizeof(char*)*(num_genvars+1));
(*other_genvars)[num_genvars] = iterator->types.identifier;
num_genvars++;
// look for nested loops to verify that each genvar is used in only one loop
for (int i=0; i < body->num_children; i++)
{
verify_genvars(body->children[i], local_ref, other_genvars, num_genvars);
}
}
else
{
// look for nested loops to verify that each genvar is used in only one loop
for (int i=0; i < node->num_children; i++)
{
verify_genvars(node->children[i], local_ref, other_genvars, num_genvars);
}
}
}
}
ast_node_t *look_for_matching_hard_block(ast_node_t *node, char *hard_block_name, sc_hierarchy *local_ref)
{
t_model *hb_model = find_hard_block(hard_block_name);
bool is_hb = true;
if (!hb_model)
{
/* check for soft logic RAM */
return look_for_matching_soft_logic(node, hard_block_name);
}
else
{
t_model_ports *hb_input_ports = hb_model->inputs;
t_model_ports *hb_output_ports = hb_model->outputs;
int num_hb_inputs = 0;
int num_hb_outputs = 0;
while (hb_input_ports != NULL)
{
num_hb_inputs++;
hb_input_ports = hb_input_ports->next;
}
while (hb_output_ports != NULL)
{
num_hb_outputs++;
hb_output_ports = hb_output_ports->next;
}
ast_node_t *connect_list = node->children[1]->children[1];
/* first check if the number of ports match up */
if (connect_list->num_children != (num_hb_inputs + num_hb_outputs))
{
is_hb = false;
}
if (is_hb && connect_list->children[0]->children[0] != NULL)
{
/* number of ports match and ports were passed in by name;
* if all port names match up, this is a hard block */
for (int i = 0; i < connect_list->num_children && is_hb; i++)
{
oassert(connect_list->children[i]->children[0]);
char *id = connect_list->children[i]->children[0]->types.identifier;
hb_input_ports = hb_model->inputs;
hb_output_ports = hb_model->outputs;
while ((hb_input_ports != NULL) && (strcmp(hb_input_ports->name, id) != 0))
{
hb_input_ports = hb_input_ports->next;
}
if (hb_input_ports == NULL)
{
while ((hb_output_ports != NULL) && (strcmp(hb_output_ports->name, id) != 0))
{
hb_output_ports = hb_output_ports->next;
}
}
else
{
/* matching input was found; move on to the next port connection */
continue;
}
if (hb_output_ports == NULL)
{
/* name doesn't match up with any of the defined ports; this is not a hard block */
is_hb = false;
}
else
{
/* matching output was found; move on to the next port connection */
continue;
}
}
}
else if (is_hb)
{
/* number of ports match and ports were passed in by ordered list;
* this is risky, but we will try to do some "smart" mapping to mark inputs and outputs
* by evaluating the port connections to determine the order */
warning_message(NETLIST_ERROR, connect_list->line_number, connect_list->file_number,
"Attempting to convert this instance to a hard block (%s) - unnamed port connections will be matched according to hard block specification and may produce unexpected results\n", hard_block_name);
t_model_ports *hb_ports_1 = NULL, *hb_ports_2 = NULL;
bool is_input, is_output;
int num_ports;
hb_input_ports = hb_model->inputs;
hb_output_ports = hb_model->outputs;
/* decide whether to look for inputs or outputs based on what there are less of */
if (num_hb_inputs <= num_hb_outputs)
{
is_input = true;
is_output = false;
num_ports = num_hb_inputs;
}
else
{
is_input = false;
is_output = true;
num_ports = num_hb_outputs;
}
STRING_CACHE *local_symbol_table_sc = local_ref->local_symbol_table_sc;
int i;
/* look through the first N (num_ports) port connections to look for a match */
for (i = 0; i < num_ports; i++)
{
char *port_id = connect_list->children[i]->children[1]->types.identifier;
long sc_spot = sc_lookup_string(local_symbol_table_sc, port_id);
oassert(sc_spot > -1);
ast_node_t *var_declare = (ast_node_t *)local_symbol_table_sc->data[sc_spot];
if (var_declare->types.variable.is_output == is_output
&& var_declare->types.variable.is_input == is_input)
{
/* found a match! check if it's an input or output */
if (is_input)
{
hb_ports_1 = hb_model->inputs;
hb_ports_2 = hb_model->outputs;
}
else
{
hb_ports_1 = hb_model->outputs;
hb_ports_2 = hb_model->inputs;
}
break;
}
else if (var_declare->types.variable.is_output != is_output
&& var_declare->types.variable.is_input != is_input)
{
/* found the opposite of what we were looking for */
if (is_input)
{
hb_ports_1 = hb_model->outputs;
hb_ports_2 = hb_model->inputs;
}
else
{
hb_ports_1 = hb_model->inputs;
hb_ports_2 = hb_model->outputs;
}
break;
}
}
/* if a match hasn't been found yet, look through the last N (num_ports) port connections */
if (!(hb_ports_1 && hb_ports_2))
{
for (i = connect_list->num_children - num_ports; i < connect_list->num_children; i++)
{
char *port_id = connect_list->children[i]->children[1]->types.identifier;
long sc_spot = sc_lookup_string(local_symbol_table_sc, port_id);
oassert(sc_spot > -1);
ast_node_t *var_declare = (ast_node_t *)local_symbol_table_sc->data[sc_spot];
if (var_declare->types.variable.is_output == is_output
&& var_declare->types.variable.is_input == is_input)
{
/* found a match! since we're at the other end, inputs/outputs should be reversed */
if (is_input)
{
hb_ports_1 = hb_model->outputs;
hb_ports_2 = hb_model->inputs;
}
else
{
hb_ports_1 = hb_model->inputs;
hb_ports_2 = hb_model->outputs;
}
break;
}
else if (var_declare->types.variable.is_output != is_output
&& var_declare->types.variable.is_input != is_input)
{
/* found the opposite of what we were looking for */
if (is_input)
{
hb_ports_1 = hb_model->inputs;
hb_ports_2 = hb_model->outputs;
}
else
{
hb_ports_1 = hb_model->outputs;
hb_ports_2 = hb_model->inputs;
}
break;
}
}
}
/* if a match hasn't been found, then there is no way to tell what should be done first;
* we will default to inputs first, then outputs after (this is an arbitrary decision) */
if (!(hb_ports_1 && hb_ports_2))
{
hb_ports_1 = hb_model->inputs;
hb_ports_2 = hb_model->outputs;
}
/* attach new port identifiers for later reference when building the hard block */
i = 0;
while (hb_ports_1)
{
oassert(connect_list->children[i] && !connect_list->children[i]->children[0]);
connect_list->children[i]->children[0] = newSymbolNode(vtr::strdup(hb_ports_1->name), connect_list->line_number);
hb_ports_1 = hb_ports_1->next;
i++;
}
while (hb_ports_2)
{
oassert(connect_list->children[i] && !connect_list->children[i]->children[0]);
connect_list->children[i]->children[0] = newSymbolNode(vtr::strdup(hb_ports_2->name), connect_list->line_number);
hb_ports_2 = hb_ports_2->next;
i++;
}
}
}
if (is_hb)
{
ast_node_t *instance = ast_node_deep_copy(node->children[1]);
char *new_hard_block_name = vtr::strdup(hard_block_name);
return newHardBlockInstance(new_hard_block_name, instance, instance->line_number);
}
else
{
return look_for_matching_soft_logic(node, hard_block_name);
}
}
ast_node_t *look_for_matching_soft_logic(ast_node_t *node, char *hard_block_name)
{
bool is_hb = true;
if (!is_ast_sp_ram(node) && !is_ast_dp_ram(node) && !is_ast_adder(node) && !is_ast_multiplier(node))
{
is_hb = false;
}
if (is_hb)
{
ast_node_t *instance = ast_node_deep_copy(node->children[1]);
char *new_hard_block_name = vtr::strdup(hard_block_name);
return newHardBlockInstance(new_hard_block_name, instance, instance->line_number);
}
else
{
return node;
}
}
/*---------------------------------------------------------------------------------------------
* (function: create_param_table_for_scope)
* Creates a lookup of the parameters declared here.
*
* (NOTE: this is intended for named or generate blocks only)
*-------------------------------------------------------------------------------------------*/
void create_param_table_for_scope(ast_node_t* module_items, sc_hierarchy *local_ref)
{
/* with the top module we need to visit the entire ast tree */
long i, j;
char *temp_string;
long sc_spot;
oassert(module_items->type == BLOCK);
STRING_CACHE *local_param_table_sc = local_ref->local_param_table_sc;
STRING_CACHE *local_defparam_table_sc = local_ref->local_defparam_table_sc;
/* search for VAR_DECLARE_LISTS */
if (module_items->num_children > 0)
{
for (i = 0; i < module_items->num_children; i++)
{
if (module_items->children[i]->type == VAR_DECLARE_LIST)
{
/* go through the vars in this declare list */
for (j = 0; j < module_items->children[i]->num_children; j++)
{
ast_node_t *var_declare = module_items->children[i]->children[j];
/* symbols are already dealt with */
if (var_declare->types.variable.is_input
|| var_declare->types.variable.is_output
|| var_declare->types.variable.is_reg
|| var_declare->types.variable.is_integer
|| var_declare->types.variable.is_genvar
|| var_declare->types.variable.is_wire
|| var_declare->types.variable.is_defparam)
continue;
oassert(module_items->children[i]->children[j]->type == VAR_DECLARE);
oassert (var_declare->types.variable.is_parameter
|| var_declare->types.variable.is_localparam
|| var_declare->types.variable.is_defparam);
/* make the string to add to the string cache */
temp_string = make_full_ref_name(NULL, NULL, NULL, var_declare->children[0]->types.identifier, -1);
if (var_declare->types.variable.is_parameter || var_declare->types.variable.is_localparam)
{
/* look for that element */
sc_spot = sc_add_string(local_param_table_sc, temp_string);
if (local_param_table_sc->data[sc_spot] != NULL)
{
error_message(PARSE_ERROR, var_declare->line_number, var_declare->file_number,
"Block already has parameter with this name (%s)\n", var_declare->children[0]->types.identifier);
}
/* store the data which is an idx here */
local_param_table_sc->data[sc_spot] = (void *)var_declare;
}
else
{
/* look for that element */
sc_spot = sc_add_string(local_defparam_table_sc, temp_string);
if (local_defparam_table_sc->data[sc_spot] != NULL)
{
error_message(PARSE_ERROR, var_declare->line_number, var_declare->file_number,
"Block already has defparam with this name (%s)\n", var_declare->children[0]->types.identifier);
}
/* store the data which is an idx here */
local_defparam_table_sc->data[sc_spot] = (void *)var_declare;
}
vtr::free(temp_string);
module_items->children[i]->children[j] = NULL;
remove_child_from_node_at_index(module_items->children[i], j);
j--;
}
if (module_items->children[i]->num_children == 0)
{
remove_child_from_node_at_index(module_items, i);
i--;
}
}
}
}
else
{
error_message(NETLIST_ERROR, module_items->line_number, module_items->file_number, "%s", "Empty module\n");
}
}
// /*---------------------------------------------------------------------------
// * (function: reduce_assignment_expression)
// * reduce the number nodes which can be calculated to optimize the AST
// *-------------------------------------------------------------------------*/
// void reduce_assignment_expression(ast_node_t *ast_module)
// {
// head = NULL;
// p = NULL;
// ast_node_t *T = NULL;
// if (count_id < ast_module->unique_count)
// count_id = ast_module->unique_count;
// count_assign = 0;
// std::vector<ast_node_t *> list_assign;
// find_assign_node(ast_module, list_assign, ast_module->children[0]->types.identifier);
// for (long j = 0; j < count_assign; j++)
// {
// if (check_tree_operation(list_assign[j]->children[1]) && (list_assign[j]->children[1]->num_children > 0))
// {
// store_exp_list(list_assign[j]->children[1]);
// if (simplify_expression())
// {
// enode *tail = find_tail(head);
// free_whole_tree(list_assign[j]->children[1]);
// T = (ast_node_t*)vtr::malloc(sizeof(ast_node_t));
// construct_new_tree(tail, T, list_assign[j]->line_number, list_assign[j]->file_number);
// list_assign[j]->children[1] = T;
// }
// free_exp_list();
// }
// }
// }
// /*---------------------------------------------------------------------------
// * (function: search_assign_node)
// * find the top of the assignment expression
// *-------------------------------------------------------------------------*/
// void find_assign_node(ast_node_t *node, std::vector<ast_node_t *> list, char *module_name)
// {
// if (node && node->num_children > 0 && (node->type == BLOCKING_STATEMENT || node->type == NON_BLOCKING_STATEMENT))
// {
// list.push_back(node);
// }
// for (long i = 0; node && i < node->num_children; i++)
// find_assign_node(node->children[i], list, module_name);
// }
// /*---------------------------------------------------------------------------
// * (function: simplify_expression)
// * simplify the expression stored in the linked_list
// *-------------------------------------------------------------------------*/
// bool simplify_expression()
// {
// bool build = adjoin_constant();
// reduce_enode_list();
// if(delete_continuous_multiply())
// build = true;
// if(combine_constant())
// build = true;
// reduce_enode_list();
// return build;
// }
// /*---------------------------------------------------------------------------
// * (function: find_tail)
// *-------------------------------------------------------------------------*/
// enode *find_tail(enode *node)
// {
// enode *temp;
// enode *tail = NULL;
// for (temp = node; temp != NULL; temp = temp->next)
// if (temp->next == NULL)
// tail = temp;
// return tail;
// }
// /*---------------------------------------------------------------------------
// * (function: reduce_enode_list)
// *-------------------------------------------------------------------------*/
// void reduce_enode_list()
// {
// enode *temp;
// int a;
// while(head != NULL && (head->type.data == 0) && (head->next->priority == 2) && (head->next->type.operation == '+')){
// temp=head;
// head = head->next->next;
// head->pre = NULL;
// vtr::free(temp->next);
// vtr::free(temp);
// }
// if(head == NULL){
// return;
// }
// temp = head->next;
// while (temp != NULL)
// {
// if ((temp->flag == 1) && (temp->pre->priority == 2))
// {
// if (temp->type.data == 0)
// {
// if (temp->next == NULL)
// temp->pre->pre->next = NULL;
// else
// {
// temp->pre->pre->next = temp->next;
// temp->next->pre = temp->pre->pre;
// }
// vtr::free(temp->pre);
// enode *toBeDeleted = temp;
// temp = temp->next;
// vtr::free(toBeDeleted);
// } else if (temp->type.data < 0)
// {
// if (temp->pre->type.operation == '+')
// temp->pre->type.operation = '-';
// else
// temp->pre->type.operation = '+';
// a = temp->type.data;
// temp->type.data = -a;
// temp = temp->next;
// } else {
// temp = temp->next;
// }
// } else {
// temp = temp->next;
// }
// }
// }
// /*---------------------------------------------------------------------------
// * (function: store_exp_list)
// *-------------------------------------------------------------------------*/
// void store_exp_list(ast_node_t *node)
// {
// enode *temp;
// head = (enode*)vtr::malloc(sizeof(enode));
// p = head;
// record_tree_info(node);
// temp = head;
// head = head->next;
// head->pre = NULL;
// p->next = NULL;
// vtr::free(temp);
// }
// /*---------------------------------------------------------------------------
// * (function: record_tree_info)
// *-------------------------------------------------------------------------*/
// void record_tree_info(ast_node_t *node)
// {
// if (node){
// if (node->num_children > 0)
// {
// record_tree_info(node->children[0]);
// create_enode(node);
// if (node->num_children > 1)
// record_tree_info(node->children[1]);
// }else{
// create_enode(node);
// }
// }
// }
// /*---------------------------------------------------------------------------
// * (function: create_enode)
// * store elements of an expression in nodes consisting the linked_list
// *-------------------------------------------------------------------------*/
// void create_enode(ast_node_t *node)
// {
// enode *s = (enode*)vtr::malloc(sizeof(enode));
// s->flag = -1;
// s->priority = -1;
// s->id = node->unique_count;
// switch (node->type)
// {
// case NUMBERS:
// {
// s->type.data = node->types.vnumber->get_value();
// s->flag = 1;
// s->priority = 0;
// break;
// }
// case BINARY_OPERATION:
// {
// s->flag = 2;
// switch(node->types.operation.op)
// {
// case ADD:
// {
// s->type.operation = '+';
// s->priority = 2;
// break;
// }
// case MINUS:
// {
// s->type.operation = '-';
// s->priority = 2;
// break;
// }
// case MULTIPLY:
// {
// s->type.operation = '*';
// s->priority = 1;
// break;
// }
// case DIVIDE:
// {
// s->type.operation = '/';
// s->priority = 1;
// break;
// }
// default:
// {
// break;
// }
// }
// break;
// }
// case IDENTIFIERS:
// {
// s->type.variable = node->types.identifier;
// s->flag = 3;
// s->priority = 0;
// break;
// }
// default:
// {
// break;
// }
// }
// p->next = s;
// s->pre = p;
// p = s;
// }
// /*---------------------------------------------------------------------------
// * (function: adjoin_constant)
// * compute the constant numbers in the linked_list
// *-------------------------------------------------------------------------*/
// bool adjoin_constant()
// {
// bool build = false;
// enode *t, *replace;
// int a, b, result = 0;
// int mark;
// for (t = head; t->next!= NULL; )
// {
// mark = 0;
// if ((t->flag == 1) && (t->next->next != NULL) && (t->next->next->flag ==1))
// {
// switch (t->next->priority)
// {
// case 1:
// a = t->type.data;
// b = t->next->next->type.data;
// if (t->next->type.operation == '*')
// result = a * b;
// else
// result = a / b;
// replace = replace_enode(result, t, 1);
// build = true;
// mark = 1;
// break;
// case 2:
// if (((t == head) || (t->pre->priority == 2)) && ((t->next->next->next == NULL) ||(t->next->next->next->priority ==2)))
// {
// a = t->type.data;
// b = t->next->next->type.data;
// if (t->pre->type.operation == '+')
// {
// if (t->next->type.operation == '+')
// result = a + b;
// else
// result = a - b;
// }
// if (t->pre->type.operation == '-')
// {
// if (t->next->type.operation == '+')
// result = a - b;
// else
// result = a + b;
// }
// replace = replace_enode(result, t, 1);
// build = true;
// mark = 1;
// }
// break;
// default:
// //pass
// break;
// }
// }
// if (mark == 0)
// t = t->next;
// else
// if (mark == 1)
// t = replace;
// }
// return build;
// }
// /*---------------------------------------------------------------------------
// * (function: replace_enode)
// *-------------------------------------------------------------------------*/
// enode *replace_enode(int data, enode *t, int mark)
// {
// enode *replace;
// replace = (enode*)vtr::malloc(sizeof(enode));
// replace->type.data = data;
// replace->flag = 1;
// replace->priority = 0;
// if (t == head)
// {
// replace->pre = NULL;
// head = replace;
// }
// else
// {
// replace->pre = t->pre;
// t->pre->next = replace;
// }
// if (mark == 1)
// {
// replace->next = t->next->next->next;
// if (t->next->next->next == NULL)
// replace->next = NULL;
// else
// t->next->next->next->pre = replace;
// vtr::free(t->next->next);
// vtr::free(t->next);
// }
// else
// {
// replace->next = t->next;
// t->next->pre = replace;
// }
// vtr::free(t);
// return replace;
// }
// /*---------------------------------------------------------------------------
// * (function: combine_constant)
// *-------------------------------------------------------------------------*/
// bool combine_constant()
// {
// enode *temp, *m, *s1, *s2, *replace;
// int a, b, result;
// int mark;
// bool build = false;
// for (temp = head; temp != NULL; )
// {
// mark = 0;
// if ((temp->flag == 1) && (temp->next != NULL) && (temp->next->priority == 2))
// {
// if ((temp == head) || (temp->pre->priority == 2))
// {
// for (m = temp->next; m != NULL; m = m->next)
// {
// if((m->flag == 1) && (m->pre->priority == 2) && ((m->next == NULL) || (m->next->priority == 2)))
// {
// s1 = temp;
// s2 = m;
// a = s1->type.data;
// b = s2->type.data;
// if ((s1 == head) || (s1->pre->type.operation == '+'))
// {
// if (s2->pre->type.operation == '+')
// result = a + b;
// else
// result = a - b;
// }
// else
// {
// if (s2->pre->type.operation == '+')
// result = a - b;
// else
// result = a + b;
// }
// replace = replace_enode(result, s1, 2);
// if (s2->next == NULL)
// {
// s2->pre->pre->next = NULL;
// mark = 2;
// }
// else
// {
// s2->pre->pre->next = s2->next;
// s2->next->pre = s2->pre->pre;
// }
// vtr::free(s2->pre);
// vtr::free(s2);
// if (replace == head)
// {
// temp = replace;
// mark = 1;
// }
// else
// temp = replace->pre;
// build = true;
// break;
// }
// }
// }
// }
// if (mark == 0)
// temp = temp->next;
// else
// if (mark == 1)
// continue;
// else
// break;
// }
// return build;
// }
// /*---------------------------------------------------------------------------
// * (function: construct_new_tree)
// *-------------------------------------------------------------------------*/
// void construct_new_tree(enode *tail, ast_node_t *node, int line_num, int file_num)
// {
// enode *temp, *tail1 = NULL, *tail2 = NULL;
// int prio = 0;
// if (tail == NULL)
// return;
// prio = check_exp_list(tail);
// if (prio == 1)
// {
// for (temp = tail; temp != NULL; temp = temp->pre)
// if ((temp->flag == 2) && (temp->priority == 2))
// {
// create_ast_node(temp, node, line_num, file_num);
// tail1 = temp->pre;
// tail2 = find_tail(temp->next);
// tail1->next = NULL;
// temp->next->pre = NULL;
// break;
// }
// }
// else
// if(prio == 2)
// {
// for (temp = tail; temp != NULL; temp = temp->pre)
// if ((temp->flag ==2) && (temp->priority == 1))
// {
// create_ast_node(temp, node, line_num, file_num);
// tail1 = temp->pre;
// tail2 = temp->next;
// tail2->pre = NULL;
// tail2->next = NULL;
// break;
// }
// }
// else
// if (prio == 3)
// create_ast_node(tail, node, line_num, file_num);
// if (prio == 1 || prio == 2)
// {
// node->children = (ast_node_t**)vtr::malloc(2*sizeof(ast_node_t*));
// node->children[0] = (ast_node_t*)vtr::malloc(sizeof(ast_node_t));
// node->children[1] = (ast_node_t*)vtr::malloc(sizeof(ast_node_t));
// create_ast_node(tail1, node->children[0], line_num, file_num);
// create_ast_node(tail2, node->children[1], line_num, file_num);
// construct_new_tree(tail1, node->children[0], line_num, file_num);
// construct_new_tree(tail2, node->children[1], line_num, file_num);
// }
// return;
// }
// /*---------------------------------------------------------------------------
// * (function: check_exp_list)
// *-------------------------------------------------------------------------*/
// int check_exp_list(enode *tail)
// {
// enode *temp;
// for (temp = tail; temp != NULL; temp = temp->pre)
// if ((temp->flag == 2) && (temp->priority == 2))
// return 1;
// for (temp = tail; temp != NULL; temp = temp->pre)
// if ((temp->flag == 2) && (temp->priority ==1))
// return 2;
// return 3;
// }
// /*---------------------------------------------------------------------------
// * (function: delete_continuous_multiply)
// *-------------------------------------------------------------------------*/
// bool delete_continuous_multiply()
// {
// enode *temp, *t, *m, *replace;
// bool build = false;
// int a, b, result;
// int mark;
// for (temp = head; temp != NULL; )
// {
// mark = 0;
// if ((temp->flag == 1) && (temp->next != NULL) && (temp->next->priority == 1))
// {
// for (t = temp->next; t != NULL; t = t->next)
// {
// if ((t->flag == 1) && (t->pre->priority ==1))
// {
// for (m = temp->next; m != t; m = m->next)
// {
// if ((m->flag == 2) && (m->priority != 1))
// {
// mark = 1;
// break;
// }
// }
// if (mark == 0)
// {
// a = temp->type.data;
// b = t->type.data;
// if (t->pre->type.operation == '*')
// result = a * b;
// else
// result = a / b;
// replace = replace_enode(result, temp, 3);
// if (t->next == NULL)
// t->pre->pre->next = NULL;
// else
// {
// t->pre->pre->next = t->next;
// t->next->pre = t->pre->pre;
// }
// mark = 2;
// build = true;
// vtr::free(t->pre);
// vtr::free(t);
// break;
// }
// break;
// }
// }
// }
// if ((mark == 0) || (mark == 1))
// temp = temp->next;
// else
// if (mark == 2)
// temp = replace;
// }
// return build;
// }
// /*---------------------------------------------------------------------------
// * (function: create_ast_node)
// *-------------------------------------------------------------------------*/
// void create_ast_node(enode *temp, ast_node_t *node, int line_num, int file_num)
// {
// switch(temp->flag)
// {
// case 1:
// initial_node(node, NUMBERS, line_num, file_num, ++count_id);
// change_to_number_node(node, temp->type.data);
// break;
// case 2:
// create_op_node(node, temp, line_num, file_num);
// break;
// case 3:
// initial_node(node, IDENTIFIERS, line_num, file_num, ++count_id);
// node->types.identifier = vtr::strdup(temp->type.variable.c_str());
// break;
// default:
// break;
// }
// }
// /*---------------------------------------------------------------------------
// * (function: create_op_node)
// *-------------------------------------------------------------------------*/
// void create_op_node(ast_node_t *node, enode *temp, int line_num, int file_num)
// {
// initial_node(node, BINARY_OPERATION, line_num, file_num, ++count_id);
// node->num_children = 2;
// switch(temp->type.operation)
// {
// case '+':
// node->types.operation.op = ADD;
// break;
// case '-':
// node->types.operation.op = MINUS;
// break;
// case '*':
// node->types.operation.op = MULTIPLY;
// break;
// case '/':
// node->types.operation.op = DIVIDE;
// break;
// default:
// oassert(false);
// break;
// }
// }
// /*---------------------------------------------------------------------------
// * (function: free_exp_list)
// *-------------------------------------------------------------------------*/
// void free_exp_list()
// {
// enode *next, *temp;
// for (temp = head; temp != NULL; temp = next)
// {
// next = temp->next;
// vtr::free(temp);
// }
// }
// /*---------------------------------------------------------------------------
// * (function: change_exp_list)
// *-------------------------------------------------------------------------*/
// void change_exp_list(enode *begin, enode *end, enode *s, int flag)
// {
// enode *temp, *new_head, *tail, *p2, *partial = NULL, *start = NULL;
// int mark;
// switch (flag)
// {
// case 1:
// {
// for (temp = begin; temp != end; temp = p2->next)
// {
// mark = 0;
// for (p2 = temp; p2 != end->next; p2 = p2->next)
// {
// if (p2 == end)
// {
// mark = 2;
// break;
// }
// if ((p2->flag == 2) && (p2->priority == 2))
// {
// partial = p2->pre;
// mark = 1;
// break;
// }
// }
// if (mark == 1)
// {
// new_head = (enode*)vtr::malloc(sizeof(enode));
// tail = copy_enode_list(new_head, end->next, s);
// tail = tail->pre;
// vtr::free(tail->next);
// partial->next = new_head;
// new_head->pre = partial;
// tail->next = p2;
// p2->pre = tail;
// }
// if (mark == 2)
// break;
// }
// break;
// }
// case 2:
// {
// for (temp = begin; temp != end->next; temp = temp->next)
// if ((temp->flag == 2) && (temp->priority == 2))
// {
// start = temp;
// break;
// }
// for (temp = start; temp != end->next; temp = partial->next)
// {
// mark = 0;
// for (p2 = temp; p2 != end->next; p2 = p2->next)
// {
// if (p2 == end)
// {
// mark = 2;
// break;
// }
// if ((p2->flag == 2) && (p2->priority == 2))
// {
// partial = p2->next;
// mark = 1;
// break;
// }
// }
// if (mark == 1)
// {
// new_head = (enode*)vtr::malloc(sizeof(enode));
// tail = copy_enode_list(new_head, s, begin->pre);
// tail = tail->pre;
// vtr::free(tail->next);
// p2->next = new_head;
// new_head->pre = p2;
// tail->next = partial;
// partial->pre = tail;
// }
// if (mark == 2)
// break;
// }
// break;
// }
// default:
// break;
// }
// }
// /*---------------------------------------------------------------------------
// * (function: copy_enode_list)
// *-------------------------------------------------------------------------*/
// enode *copy_enode_list(enode *new_head, enode *begin, enode *end)
// {
// enode *temp, *new_enode, *next_enode;
// new_enode = new_head;
// for (temp = begin; temp != end->next; temp = temp->next)
// {
// copy_enode(temp, new_enode);
// next_enode = (enode*)vtr::malloc(sizeof(enode));
// new_enode->next = next_enode;
// next_enode->pre = new_enode;
// new_enode = next_enode;
// }
// return new_enode;
// }
// /*---------------------------------------------------------------------------
// * (function: copy_enode)
// *-------------------------------------------------------------------------*/
// void copy_enode(enode *node, enode *new_node)
// {
// new_node->type = node->type;
// new_node->flag = node->flag;
// new_node->priority = node->priority;
// new_node->id = -1;
// }
// /*---------------------------------------------------------------------------
// * (function: check_tree_operation)
// *-------------------------------------------------------------------------*/
// bool check_tree_operation(ast_node_t *node)
// {
// if (node && (node->type == BINARY_OPERATION) && ((node->types.operation.op == ADD ) || (node->types.operation.op == MINUS) || (node->types.operation.op == MULTIPLY)))
// return true;
// for (long i = 0; node && i < node->num_children; i++)
// if(check_tree_operation(node->children[i]))
// return true;
// return false;
// }
// /*---------------------------------------------------------------------------
// * (function: check_operation)
// *-------------------------------------------------------------------------*/
// void check_operation(enode *begin, enode *end)
// {
// enode *temp, *op;
// for (temp = begin; temp != head; temp = temp->pre)
// {
// if (temp->flag == 2 && temp->priority == 2 && temp->type.operation == '-')
// {
// for (op = begin; op != end; op = op->next)
// {
// if (op->flag == 2 && op->priority == 2)
// {
// if (op->type.operation == '+')
// op->type.operation = '-';
// else
// op->type.operation = '+';
// }
// }
// }
// }
// }