| /* |
| 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 <ctype.h> |
| #include <stdarg.h> |
| #include <math.h> |
| #include <algorithm> |
| #include "odin_globals.h" |
| #include "odin_types.h" |
| |
| #include "ast_util.h" |
| #include "odin_util.h" |
| #include "vtr_util.h" |
| #include "vtr_memory.h" |
| |
| char **get_name_of_pins_number(ast_node_t *var_node, int start, int width); |
| char *get_name_of_pin_number(ast_node_t *var_node, int bit); |
| void update_tree_tag(ast_node_t *node, int cases, int tagged); |
| STRING_CACHE *copy_param_table_sc(STRING_CACHE *to_copy); |
| |
| // HIGH LEVEL AST TAG |
| static int high_level_id; |
| |
| /*--------------------------------------------------------------------------- |
| * (function: update_tree) |
| *-------------------------------------------------------------------------*/ |
| void update_tree_tag(ast_node_t *node, int high_level_block_type_to_search, int tag) |
| { |
| long i; |
| int tagged = tag; |
| if (node){ |
| |
| if(node->type == high_level_block_type_to_search) |
| tagged = ++high_level_id; |
| |
| if(tagged > -1){ |
| node->far_tag = tagged; |
| node->high_number = node->line_number; |
| } |
| |
| for (i=0; i < node->num_children; i++) |
| update_tree_tag(node->children[i], high_level_block_type_to_search, tagged); |
| } |
| } |
| |
| /*--------------------------------------------------------------------------- |
| * (function: add_tag_data) |
| *-------------------------------------------------------------------------*/ |
| void add_tag_data() |
| { |
| long i; |
| high_level_id = -1; |
| |
| ids type = NO_ID; |
| if(global_args.high_level_block.value() == "if") |
| { |
| type = IF; |
| } |
| else if(global_args.high_level_block.value() == "always") |
| { |
| type = ALWAYS; |
| } |
| else if(global_args.high_level_block.value() == "module") |
| { |
| type = MODULE; |
| } |
| |
| if(type != NO_ID){ |
| for (i = 0; i < num_modules ; i++) |
| update_tree_tag(ast_modules[i],type, -1); |
| } |
| } |
| |
| // END HIGH LEVEL TAG |
| |
| /*--------------------------------------------------------------------------- |
| * (function: create_node_w_type) |
| *-------------------------------------------------------------------------*/ |
| static ast_node_t* create_node_w_type(ids id, int line_number, int file_number, bool update_unique_count) |
| { |
| oassert(id != NO_ID); |
| |
| static long unique_count = 0; |
| |
| ast_node_t* new_node; |
| |
| new_node = (ast_node_t*)vtr::calloc(1, sizeof(ast_node_t)); |
| oassert(new_node != NULL); |
| |
| initial_node(new_node, id, line_number, file_number, unique_count); |
| |
| if(update_unique_count) |
| unique_count += 1; |
| |
| return new_node; |
| } |
| |
| ast_node_t* create_node_w_type_no_count(ids id, int line_number, int file_number) |
| { |
| return create_node_w_type(id, line_number, file_number, false); |
| } |
| |
| /*--------------------------------------------------------------------------- |
| * (function: create_node_w_type) |
| *-------------------------------------------------------------------------*/ |
| ast_node_t* create_node_w_type(ids id, int line_number, int file_number) |
| { |
| return create_node_w_type(id, line_number, file_number, true); |
| } |
| |
| /*--------------------------------------------------------------------------- |
| * (function: free_assignement_of_node_keep_tree) |
| * free a node type but stay in tree structure |
| *-------------------------------------------------------------------------*/ |
| void free_assignement_of_node_keep_tree(ast_node_t *node) |
| { |
| if(node){ |
| int i; |
| vtr::free(node->types.identifier); |
| switch(node->type){ |
| case NUMBERS: |
| if (node->types.vnumber != nullptr) |
| delete node->types.vnumber; |
| node->types.vnumber = nullptr; |
| break; |
| |
| case CONCATENATE: |
| for(i=0; i<node->types.concat.num_bit_strings; i++){ |
| if(node->types.concat.bit_strings[i]) |
| vtr::free(node->types.concat.bit_strings[i]); |
| } |
| vtr::free(node->types.concat.bit_strings); |
| |
| |
| default: |
| break; |
| } |
| } |
| } |
| /*--------------------------------------------------------------------------- |
| * (function: free_single_node) |
| * free a node whose type is IDENTIFERS |
| *-------------------------------------------------------------------------*/ |
| ast_node_t *free_single_node(ast_node_t *node) |
| { |
| if(node){ |
| free_assignement_of_node_keep_tree(node); |
| vtr::free(node->children); |
| vtr::free(node); |
| } |
| return NULL; |
| |
| } |
| |
| /*--------------------------------------------------------------------------- |
| * (function: free_all_children) |
| *-------------------------------------------------------------------------*/ |
| void free_all_children(ast_node_t *node) |
| { |
| long i; |
| |
| if (node){ |
| for (i = 0; i < node->num_children; i++) |
| node->children[i] = free_whole_tree(node->children[i]); |
| vtr::free(node->children); |
| node->children = NULL; |
| node->num_children = 0; |
| } |
| |
| } |
| |
| /*--------------------------------------------------------------------------- |
| * (function: free_all_children) |
| *-------------------------------------------------------------------------*/ |
| void free_resolved_children(ast_node_t *node) |
| { |
| long i; |
| |
| if (node) |
| { |
| for (i = 0; i < node->num_children; i++) |
| { |
| node->children[i] = free_resolved_tree(node->children[i]); |
| node->children[i] = NULL; |
| } |
| |
| vtr::free(node->children); |
| node->children = NULL; |
| node->num_children = 0; |
| } |
| |
| } |
| |
| /*--------------------------------------------------------------------------- |
| * (function: free_whole_tree) |
| *-------------------------------------------------------------------------*/ |
| ast_node_t *free_whole_tree(ast_node_t *node) |
| { |
| free_all_children(node); |
| return free_single_node(node); |
| } |
| |
| /*--------------------------------------------------------------------------- |
| * (function: free_whole_tree) |
| *-------------------------------------------------------------------------*/ |
| ast_node_t *free_resolved_tree(ast_node_t *node) |
| { |
| free_resolved_children(node); |
| if (node->type != IDENTIFIERS) |
| { |
| node = free_single_node(node); |
| } |
| |
| return NULL; |
| } |
| |
| /*--------------------------------------------------------------------------------------------- |
| * (function: create_tree_node_id) |
| *-------------------------------------------------------------------------------------------*/ |
| ast_node_t* create_tree_node_id(char* string, int line_number, int /*file_number*/) |
| { |
| ast_node_t* new_node = create_node_w_type(IDENTIFIERS, line_number, current_parse_file); |
| new_node->types.identifier = string; |
| |
| return new_node; |
| } |
| |
| /*--------------------------------------------------------------------------------------------- |
| * (function: create_tree_node_number) |
| *-------------------------------------------------------------------------------------------*/ |
| ast_node_t *create_tree_node_number(char *input_number, int line_number, int /* file_number */) |
| { |
| ast_node_t* new_node = create_node_w_type(NUMBERS, line_number, current_parse_file); |
| new_node->types.vnumber = new VNumber(input_number); |
| |
| return new_node; |
| |
| } |
| |
| /*--------------------------------------------------------------------------------------------- |
| * (function: create_tree_node_number) |
| *-------------------------------------------------------------------------------------------*/ |
| ast_node_t *create_tree_node_number(VNumber& input_number, int line_number, int /* file_number */) |
| { |
| ast_node_t* new_node = create_node_w_type(NUMBERS, line_number, current_parse_file); |
| new_node->types.vnumber = new VNumber(input_number); |
| |
| return new_node; |
| |
| } |
| |
| /*--------------------------------------------------------------------------------------------- |
| * (function: create_tree_node_number) |
| *-------------------------------------------------------------------------------------------*/ |
| ast_node_t *create_tree_node_number(long input_number, int line_number, int /* file_number */) |
| { |
| ast_node_t* new_node = create_node_w_type(NUMBERS, line_number, current_parse_file); |
| new_node->types.vnumber = new VNumber(input_number); |
| |
| return new_node; |
| |
| } |
| |
| /*--------------------------------------------------------------------------- |
| * (function: allocate_children_to_node) |
| *-------------------------------------------------------------------------*/ |
| void allocate_children_to_node(ast_node_t* node, std::vector<ast_node_t *> children_list) |
| { |
| /* allocate space for the children */ |
| node->num_children = children_list.size(); |
| node->children = (ast_node_t**)vtr::malloc(sizeof(ast_node_t*) * node->num_children ); |
| |
| for (size_t i = 0; i < node->num_children; i++) |
| { |
| node->children[i] = children_list[i]; |
| } |
| } |
| |
| /*--------------------------------------------------------------------------------------------- |
| * (function: add_child_to_node) |
| *-------------------------------------------------------------------------------------------*/ |
| void add_child_to_node(ast_node_t* node, ast_node_t *child) |
| { |
| /* Handle case where we have an empty statement. */ |
| if (child == NULL) |
| return; |
| |
| /* allocate space for the children */ |
| node->children = (ast_node_t**)vtr::realloc(node->children, sizeof(ast_node_t*)*(node->num_children+1)); |
| node->num_children ++; |
| node->children[node->num_children-1] = child; |
| } |
| |
| /*--------------------------------------------------------------------------------------------- |
| * (function: add_child_to_node_at_index) |
| *-------------------------------------------------------------------------------------------*/ |
| void add_child_to_node_at_index(ast_node_t* node, ast_node_t *child, int index) |
| { |
| if (index < 0 || index > node->num_children) |
| return; |
| |
| node->children = (ast_node_t **)vtr::realloc(node->children, sizeof(ast_node_t *)*(node->num_children+1)); |
| for (int i = node->num_children; i > index; i--) |
| { |
| node->children[i] = node->children[i-1]; |
| } |
| |
| node->children[index] = child; |
| node->num_children ++; |
| } |
| |
| /*--------------------------------------------------------------------------------------------- |
| * (function: remove_child_from_node_at_index) |
| *-------------------------------------------------------------------------------------------*/ |
| void remove_child_from_node_at_index(ast_node_t* node, int index) |
| { |
| if (index < 0 || index >= node->num_children) |
| return; |
| |
| if (node->children[index]) |
| { |
| node->children[index] = free_whole_tree(node->children[index]); |
| node->children[index] = NULL; |
| } |
| |
| for (int i = index; i < (node->num_children - 1); i++) |
| { |
| node->children[i] = node->children[i+1]; |
| node->children[i+1] = NULL; |
| } |
| |
| node->num_children --; |
| } |
| |
| /*--------------------------------------------------------------------------------------------- |
| * (function: expand_node_list_at) |
| *-------------------------------------------------------------------------------------------*/ |
| ast_node_t **expand_node_list_at(ast_node_t **list, long old_size, long to_add, long start_idx) |
| { |
| if (list) |
| { |
| long new_size = old_size + to_add; |
| list = (ast_node_t **)vtr::realloc(list, sizeof(ast_node_t*) * new_size); |
| |
| long i; |
| for (i = new_size-1; i >= (start_idx + to_add); i--) |
| { |
| list[i] = list[i-to_add]; |
| } |
| return list; |
| } |
| return NULL; |
| } |
| |
| /*--------------------------------------------------------------------------------------------- |
| * (function: make_concat_into_list_of_strings) |
| * 0th idx will be the MSbit |
| *-------------------------------------------------------------------------------------------*/ |
| void make_concat_into_list_of_strings(ast_node_t *concat_top, char *instance_name_prefix, sc_hierarchy *local_ref) |
| { |
| long i; |
| int j; |
| ast_node_t *rnode[3] = { 0 }; |
| |
| concat_top->types.concat.num_bit_strings = 0; |
| concat_top->types.concat.bit_strings = NULL; |
| |
| /* recursively do all embedded concats */ |
| for (i = 0; i < concat_top->num_children; i++) |
| { |
| if (concat_top->children[i]->type == CONCATENATE) |
| { |
| make_concat_into_list_of_strings(concat_top->children[i], instance_name_prefix, local_ref); |
| } |
| } |
| |
| for (i = 0; i < concat_top->num_children; i++) |
| { |
| if (concat_top->children[i]->type == IDENTIFIERS) |
| { |
| char *temp_string = make_full_ref_name(NULL, NULL, NULL, concat_top->children[i]->types.identifier, -1); |
| ast_node_t *var_declare = resolve_hierarchical_name_reference(local_ref, temp_string); |
| if (var_declare == NULL) |
| { |
| error_message(NETLIST_ERROR, concat_top->line_number, concat_top->file_number, "Missing declaration of this symbol %s\n", temp_string); |
| } |
| else |
| { |
| if (var_declare->children[1] == NULL) |
| { |
| concat_top->types.concat.num_bit_strings ++; |
| concat_top->types.concat.bit_strings = (char**)vtr::realloc(concat_top->types.concat.bit_strings, sizeof(char*)*(concat_top->types.concat.num_bit_strings)); |
| concat_top->types.concat.bit_strings[concat_top->types.concat.num_bit_strings-1] = get_name_of_pin_at_bit(concat_top->children[i], -1, instance_name_prefix, local_ref); |
| } |
| else if (var_declare->children[3] == NULL) |
| { |
| /* reverse thorugh the range since highest bit in index will be lower in the string indx */ |
| rnode[1] = var_declare->children[1]; |
| rnode[2] = var_declare->children[2]; |
| oassert(rnode[1]->type == NUMBERS && rnode[2]->type == NUMBERS); |
| |
| for (j = rnode[1]->types.vnumber->get_value() - rnode[2]->types.vnumber->get_value(); j >= 0; j--) |
| { |
| concat_top->types.concat.num_bit_strings ++; |
| concat_top->types.concat.bit_strings = (char**)vtr::realloc(concat_top->types.concat.bit_strings, sizeof(char*)*(concat_top->types.concat.num_bit_strings)); |
| concat_top->types.concat.bit_strings[concat_top->types.concat.num_bit_strings-1] = get_name_of_pin_at_bit(concat_top->children[i], j, instance_name_prefix, local_ref); |
| } |
| } |
| else if (var_declare->children[3] != NULL) |
| { |
| oassert(false); |
| } |
| } |
| vtr::free(temp_string); |
| } |
| else if (concat_top->children[i]->type == ARRAY_REF) |
| { |
| concat_top->types.concat.num_bit_strings ++; |
| concat_top->types.concat.bit_strings = (char**)vtr::realloc(concat_top->types.concat.bit_strings, sizeof(char*)*(concat_top->types.concat.num_bit_strings)); |
| concat_top->types.concat.bit_strings[concat_top->types.concat.num_bit_strings-1] = get_name_of_pin_at_bit(concat_top->children[i], 0, instance_name_prefix, local_ref); |
| } |
| else if (concat_top->children[i]->type == RANGE_REF) |
| { |
| rnode[1] = concat_top->children[i]->children[1]; |
| rnode[2] = concat_top->children[i]->children[2]; |
| oassert(rnode[1]->type == NUMBERS && rnode[2]->type == NUMBERS); |
| oassert(rnode[1]->types.vnumber->get_value() >= rnode[2]->types.vnumber->get_value()); |
| int width = abs(rnode[1]->types.vnumber->get_value() - rnode[2]->types.vnumber->get_value()) + 1; |
| |
| //for (j = rnode[1]->types.vnumber->get_value() - rnode[2]->types.vnumber->get_value(); j >= 0; j--) |
| // Changed to forward to fix concatenation bug. |
| for (j = 0; j < width; j++) |
| { |
| concat_top->types.concat.num_bit_strings ++; |
| concat_top->types.concat.bit_strings = (char**)vtr::realloc(concat_top->types.concat.bit_strings, sizeof(char*)*(concat_top->types.concat.num_bit_strings)); |
| concat_top->types.concat.bit_strings[concat_top->types.concat.num_bit_strings-1] = |
| get_name_of_pin_at_bit(concat_top->children[i], ((rnode[1]->types.vnumber->get_value() - rnode[2]->types.vnumber->get_value()))-j, instance_name_prefix, local_ref); |
| } |
| } |
| else if (concat_top->children[i]->type == NUMBERS) |
| { |
| if (concat_top->children[i]->types.vnumber->is_defined_size()) |
| { |
| // Changed to reverse to fix concatenation bug. |
| for (j = concat_top->children[i]->types.vnumber->size()-1; j>= 0; j--) |
| { |
| concat_top->types.concat.num_bit_strings ++; |
| concat_top->types.concat.bit_strings = (char**)vtr::realloc(concat_top->types.concat.bit_strings, sizeof(char*)*(concat_top->types.concat.num_bit_strings)); |
| concat_top->types.concat.bit_strings[concat_top->types.concat.num_bit_strings-1] = get_name_of_pin_at_bit(concat_top->children[i], j, instance_name_prefix, local_ref); |
| |
| } |
| } |
| else |
| { |
| error_message(NETLIST_ERROR, concat_top->line_number, concat_top->file_number, "%s", "Unsized constants cannot be concatenated.\n"); |
| } |
| } |
| else if (concat_top->children[i]->type == CONCATENATE) |
| { |
| /* forward through list since we build concatenate list in idx order of MSB at index 0 and LSB at index list_size */ |
| for (j = 0; j < concat_top->children[i]->types.concat.num_bit_strings; j++) |
| { |
| concat_top->types.concat.num_bit_strings ++; |
| concat_top->types.concat.bit_strings = (char**)vtr::realloc(concat_top->types.concat.bit_strings, sizeof(char*)*(concat_top->types.concat.num_bit_strings)); |
| concat_top->types.concat.bit_strings[concat_top->types.concat.num_bit_strings-1] = get_name_of_pin_at_bit(concat_top->children[i], j, instance_name_prefix, local_ref); |
| } |
| } |
| else |
| { |
| error_message(NETLIST_ERROR, concat_top->line_number, concat_top->file_number, "%s", "Unsupported operation within a concatenation.\n"); |
| } |
| } |
| } |
| |
| /*--------------------------------------------------------------------------- |
| * (function: change_to_number_node) |
| * change the original AST node to a NUMBER node or change the value of the node |
| * originate from the function: create_tree_node_number() in ast_util.c |
| *-------------------------------------------------------------------------*/ |
| void change_to_number_node(ast_node_t *node, long value) |
| { |
| return change_to_number_node(node, VNumber(value)); |
| } |
| |
| /*--------------------------------------------------------------------------- |
| * (function: change_to_number_node) |
| * change the original AST node to a NUMBER node or change the value of the node |
| * originate from the function: create_tree_node_number() in ast_util.c |
| *-------------------------------------------------------------------------*/ |
| void change_to_number_node(ast_node_t *node, VNumber number) |
| { |
| char *temp_ident = NULL; |
| if (node->types.identifier != NULL) |
| { |
| temp_ident = strdup(node->types.identifier); |
| } |
| free_assignement_of_node_keep_tree(node); |
| free_all_children(node); |
| |
| node->type = NUMBERS; |
| node->types.identifier = temp_ident; |
| node->types.vnumber = new VNumber(number); |
| } |
| |
| /*--------------------------------------------------------------------------------------------- |
| * (function: get_name of_port_at_bit) |
| * Assume module connections can be one of: Array entry, Concat, Signal, Array range reference |
| *-------------------------------------------------------------------------------------------*/ |
| char *get_name_of_var_declare_at_bit(ast_node_t *var_declare, int bit) |
| { |
| char *return_string = NULL; |
| |
| /* calculate the port details */ |
| if (var_declare->children[1] == NULL) |
| { |
| oassert(bit == 0); |
| return_string = make_full_ref_name(NULL, NULL, NULL, var_declare->children[0]->types.identifier, -1); |
| } |
| else if (var_declare->children[3] == NULL) |
| { |
| oassert(var_declare->children[2]->type == NUMBERS); |
| return_string = make_full_ref_name(NULL, NULL, NULL, var_declare->children[0]->types.identifier, var_declare->children[2]->types.vnumber->get_value()+bit); |
| } |
| else if (var_declare->children[3] != NULL) |
| { |
| /* MEMORY output */ |
| oassert(false); |
| } |
| |
| return return_string; |
| } |
| |
| /*--------------------------------------------------------------------------------------------- |
| * (function: get_name of_port_at_bit) |
| * Assume module connections can be one of: Array entry, Concat, Signal, Array range reference |
| *-------------------------------------------------------------------------------------------*/ |
| char *get_name_of_pin_at_bit(ast_node_t *var_node, int bit, char *instance_name_prefix, sc_hierarchy *local_ref) |
| { |
| char *return_string = NULL; |
| ast_node_t *rnode[3] = { 0 }; |
| |
| // STRING_CACHE *local_symbol_table_sc = local_ref->local_symbol_table_sc; |
| |
| if (var_node->type == ARRAY_REF) |
| { |
| oassert(var_node->children[0]->type == IDENTIFIERS); |
| oassert(var_node->children[1]->type == NUMBERS); |
| return_string = make_full_ref_name(NULL, NULL, NULL, var_node->children[0]->types.identifier, (int)var_node->children[1]->types.vnumber->get_value()); |
| } |
| else if (var_node->type == RANGE_REF) |
| { |
| oassert(bit >= 0); |
| |
| rnode[1] = var_node->children[1]; |
| rnode[2] = var_node->children[2]; |
| |
| oassert(var_node->children[0]->type == IDENTIFIERS); |
| oassert(rnode[1]->type == NUMBERS); |
| oassert(rnode[2]->type == NUMBERS); |
| oassert(rnode[1]->types.vnumber->get_value() >= rnode[2]->types.vnumber->get_value()+bit); |
| |
| return_string = make_full_ref_name(NULL, NULL, NULL, var_node->children[0]->types.identifier, rnode[2]->types.vnumber->get_value()+bit); |
| } |
| else if ((var_node->type == IDENTIFIERS) && (bit == -1)) |
| { |
| return_string = make_full_ref_name(NULL, NULL, NULL, var_node->types.identifier, -1); |
| } |
| else if (var_node->type == IDENTIFIERS) |
| { |
| ast_node_t *symbol_node; |
| int pin_index = 0; |
| |
| if ((symbol_node = resolve_hierarchical_name_reference(local_ref, var_node->types.identifier)) == NULL) |
| { |
| error_message(NETLIST_ERROR, var_node->line_number, var_node->file_number, "Missing declaration of this symbol %s\n", var_node->types.identifier); |
| } |
| |
| if (symbol_node->children[1] == NULL) |
| { |
| pin_index = bit; |
| } |
| else if (symbol_node->children[3] == NULL) |
| { |
| oassert(symbol_node->children[2]->type == NUMBERS); |
| pin_index = symbol_node->children[2]->types.vnumber->get_value() + bit; |
| } |
| else |
| oassert(false); |
| |
| return_string = make_full_ref_name(NULL, NULL, NULL, var_node->types.identifier, pin_index); |
| } |
| else if (var_node->type == NUMBERS) |
| { |
| return_string = get_name_of_pin_number(var_node, bit); |
| } |
| else if (var_node->type == CONCATENATE && bit >= 0) |
| { |
| if (var_node->types.concat.num_bit_strings == 0) |
| { |
| return_string = NULL; |
| oassert(false); |
| } |
| else |
| { |
| ast_node_t *temp = var_node; |
| if (var_node->types.concat.num_bit_strings == -1) |
| { |
| /* If this hasn't been made into a string list then do it */ |
| make_concat_into_list_of_strings(var_node, instance_name_prefix, local_ref); |
| } |
| |
| return_string = (char*)vtr::malloc(sizeof(char)*strlen(var_node->types.concat.bit_strings[bit])+1); |
| odin_sprintf(return_string, "%s", var_node->types.concat.bit_strings[bit]); |
| |
| if(var_node != temp) |
| { |
| var_node = free_whole_tree(var_node); |
| } |
| } |
| } |
| else |
| { |
| return_string = NULL; |
| |
| error_message(NETLIST_ERROR, var_node->line_number, var_node->file_number, "Unsupported variable type. var_node->type = %s\n", ast_node_name_based_on_ids(var_node)); |
| } |
| |
| return return_string; |
| } |
| |
| char **get_name_of_pins_number(ast_node_t *var_node, int /*start*/, int width) |
| { |
| char **return_string; |
| oassert(var_node->type == NUMBERS); |
| |
| return_string = (char**)vtr::malloc(sizeof(char*)*width); |
| int i; |
| for (i = 0; i < width; i++) |
| { |
| return_string[i] = get_name_of_pin_number(var_node, i); |
| } |
| return return_string; |
| } |
| |
| char *get_name_of_pin_number(ast_node_t *var_node, int bit) |
| { |
| oassert(var_node->type == NUMBERS); |
| char *return_string = NULL; |
| |
| if (bit == -1) |
| bit = 0; |
| |
| BitSpace::bit_value_t c = var_node->types.vnumber->get_bit_from_lsb(bit); |
| switch(c) |
| { |
| case BitSpace::_1: return_string = vtr::strdup(ONE_VCC_CNS); break; |
| case BitSpace::_0: return_string = vtr::strdup(ZERO_GND_ZERO); break; |
| case BitSpace::_x: return_string = vtr::strdup(ZERO_GND_ZERO); break; |
| case BitSpace::_z: return_string = vtr::strdup(ZERO_PAD_ZERO); break; |
| default: |
| error_message(NETLIST_ERROR, var_node->line_number, var_node->file_number, "Unrecognised character %c in binary string \"%s\"!\n", c, var_node->types.vnumber->to_bit_string().c_str()); |
| break; |
| } |
| |
| return return_string; |
| } |
| |
| /*--------------------------------------------------------------------------------------------- |
| * (function: get_name_of_pins |
| * Assume module connections can be one of: Array entry, Concat, Signal, Array range reference |
| * Return a list of strings |
| *-------------------------------------------------------------------------------------------*/ |
| char_list_t *get_name_of_pins(ast_node_t *var_node, char *instance_name_prefix, sc_hierarchy *local_ref) |
| { |
| char **return_string = NULL; |
| char_list_t *return_list = (char_list_t*)vtr::malloc(sizeof(char_list_t)); |
| ast_node_t *rnode[3] = { 0 }; |
| int i; |
| int width = 0; |
| |
| if (var_node->type == ARRAY_REF) |
| { |
| width = 1; |
| return_string = (char**)vtr::malloc(sizeof(char*)); |
| |
| rnode[1] = var_node->children[1]; |
| oassert(rnode[1] && rnode[1]->type == NUMBERS); |
| oassert(var_node->children[0]->type == IDENTIFIERS); |
| |
| return_string[0] = make_full_ref_name(NULL, NULL, NULL, var_node->children[0]->types.identifier, rnode[1]->types.vnumber->get_value()); |
| } |
| else if (var_node->type == RANGE_REF) |
| { |
| rnode[0] = var_node->children[0]; |
| rnode[1] = var_node->children[1]; |
| rnode[2] = var_node->children[2]; |
| |
| oassert(rnode[1]->type == NUMBERS && rnode[2]->type == NUMBERS); |
| width = abs(rnode[1]->types.vnumber->get_value() - rnode[2]->types.vnumber->get_value()) + 1; |
| if (rnode[0]->type == IDENTIFIERS) |
| { |
| return_string = (char**)vtr::malloc(sizeof(char*)*width); |
| for (i = 0; i < width; i++) |
| return_string[i] = make_full_ref_name(NULL, NULL, NULL, rnode[0]->types.identifier, rnode[2]->types.vnumber->get_value()+i); |
| } |
| else |
| { |
| oassert(rnode[0]->type == NUMBERS); |
| return_string = get_name_of_pins_number(rnode[0], rnode[2]->types.vnumber->get_value(), width); |
| } |
| } |
| else if (var_node->type == IDENTIFIERS) |
| { |
| /* need to look in the symbol table for details about this identifier (i.e. is it a port) */ |
| |
| char *temp_string = make_full_ref_name(NULL, NULL, NULL, var_node->types.identifier, -1); |
| ast_node_t *sym_node = resolve_hierarchical_name_reference(local_ref, temp_string); |
| |
| if (sym_node == NULL) |
| { |
| error_message(NETLIST_ERROR, var_node->line_number, var_node->file_number, "Missing declaration of this symbol %s\n", temp_string); |
| } |
| |
| vtr::free(temp_string); |
| |
| if (sym_node && sym_node->children && sym_node->type) |
| { |
| if (sym_node->children[1] == NULL || sym_node->type == BLOCKING_STATEMENT) |
| { |
| width = 1; |
| return_string = (char**)vtr::malloc(sizeof(char*)*width); |
| return_string[0] = make_full_ref_name(NULL, NULL, NULL, var_node->types.identifier, -1); |
| } |
| else if (sym_node->children[2] != NULL && sym_node->children[3] == NULL) |
| { |
| int index = 0; |
| |
| rnode[1] = sym_node->children[1]; |
| rnode[2] = sym_node->children[2]; |
| oassert(rnode[1]->type == NUMBERS && rnode[2]->type == NUMBERS); |
| |
| width = (rnode[1]->types.vnumber->get_value() - rnode[2]->types.vnumber->get_value() + 1); |
| return_string = (char**)vtr::malloc(sizeof(char*)*width); |
| |
| for (i = 0; i < width; i++) |
| { |
| return_string[index] = make_full_ref_name(NULL, NULL, NULL, var_node->types.identifier, |
| i+rnode[2]->types.vnumber->get_value()); |
| index++; |
| } |
| } |
| |
| else if (sym_node->children[3] != NULL) |
| { |
| oassert(false); |
| } |
| } |
| } |
| else if (var_node->type == NUMBERS) |
| { |
| width = var_node->types.vnumber->size(); |
| return_string = get_name_of_pins_number(var_node, 0, width); |
| } |
| else if (var_node->type == CONCATENATE) |
| { |
| if (var_node->types.concat.num_bit_strings == 0) |
| { |
| oassert(false); |
| } |
| else |
| { |
| if (var_node->types.concat.num_bit_strings == -1) |
| { |
| make_concat_into_list_of_strings(var_node, instance_name_prefix, local_ref); |
| } |
| |
| width = var_node->types.concat.num_bit_strings; |
| return_string = (char**)vtr::malloc(sizeof(char*)*width); |
| for (i = 0; i < width; i++) // 0th bit is MSB so need to access reverse |
| { |
| return_string[i] = (char*)vtr::malloc(sizeof(char)*strlen(var_node->types.concat.bit_strings[var_node->types.concat.num_bit_strings-i-1])+1); |
| odin_sprintf(return_string[i], "%s", var_node->types.concat.bit_strings[var_node->types.concat.num_bit_strings-i-1]); |
| } |
| } |
| } |
| else |
| { |
| oassert(false); |
| } |
| |
| return_list->strings = return_string; |
| return_list->num_strings = width; |
| |
| return return_list; |
| } |
| |
| /*--------------------------------------------------------------------------------------------- |
| * (function: get_name_of_pins_with_prefix |
| *-------------------------------------------------------------------------------------------*/ |
| char_list_t *get_name_of_pins_with_prefix(ast_node_t *var_node, char *instance_name_prefix, sc_hierarchy *local_ref) |
| { |
| int i; |
| char_list_t *return_list; |
| char *temp_str; |
| |
| /* get the list */ |
| return_list = get_name_of_pins(var_node, instance_name_prefix, local_ref); |
| |
| for (i = 0; i < return_list->num_strings; i++) |
| { |
| temp_str = vtr::strdup(return_list->strings[i]); |
| vtr::free(return_list->strings[i]); |
| return_list->strings[i] = make_full_ref_name(instance_name_prefix, NULL, NULL, temp_str, -1); |
| vtr::free(temp_str); |
| } |
| |
| return return_list; |
| } |
| |
| /*---------------------------------------------------------------------------- |
| * (function: get_size_of_variable) |
| *--------------------------------------------------------------------------*/ |
| long get_size_of_variable(ast_node_t *node, sc_hierarchy *local_ref) |
| { |
| long assignment_size = 0; |
| long sc_spot = 0; |
| ast_node_t *var_declare = NULL; |
| |
| STRING_CACHE *local_param_table_sc = local_ref->local_param_table_sc; |
| |
| switch(node->type) |
| { |
| case IDENTIFIERS: |
| { |
| sc_spot = sc_lookup_string(local_param_table_sc, node->types.identifier); |
| if (sc_spot > -1) |
| { |
| var_declare = ast_node_deep_copy((ast_node_t *)local_param_table_sc->data[sc_spot]); |
| |
| if (node_is_constant(var_declare)) |
| { |
| assignment_size = var_declare->types.vnumber->size(); |
| } |
| else |
| { |
| error_message(NETLIST_ERROR, node->line_number, node->file_number, "Parameter %s is not a constant expression\n", node->types.identifier); |
| } |
| |
| free_whole_tree(var_declare); |
| return assignment_size; |
| } |
| |
| ast_node_t *sym_node = resolve_hierarchical_name_reference(local_ref, node->types.identifier); |
| if (sym_node != NULL) |
| { |
| var_declare = sym_node; // (ast_node_t *)local_symbol_table_sc->data[sc_spot]; |
| break; |
| } |
| |
| error_message(NETLIST_ERROR, node->line_number, node->file_number, "Missing declaration of this symbol %s\n", node->types.identifier); |
| } |
| break; |
| |
| case ARRAY_REF: |
| { |
| ast_node_t *sym_node = resolve_hierarchical_name_reference(local_ref, node->children[0]->types.identifier); |
| if (sym_node != NULL) |
| { |
| var_declare = sym_node; |
| break; |
| } |
| |
| error_message(NETLIST_ERROR, node->children[0]->line_number, node->children[0]->file_number, "Missing declaration of this symbol %s\n", node->children[0]->types.identifier); |
| } |
| break; |
| |
| case RANGE_REF: |
| { |
| var_declare = node; |
| } |
| break; |
| |
| case CONCATENATE: |
| { |
| assignment_size = resolve_concat_sizes(node, local_ref); |
| return assignment_size; |
| } |
| |
| default: |
| oassert(false); |
| break; |
| } |
| |
| |
| if (var_declare && !(var_declare->children[1])) |
| { |
| assignment_size = 1; |
| } |
| else if (var_declare && var_declare->children[1] && var_declare->children[2]) |
| { |
| ast_node_t *node_max = var_declare->children[1]; |
| ast_node_t *node_min = var_declare->children[2]; |
| |
| oassert(node_min->type == NUMBERS && node_max->type == NUMBERS); |
| long range_max = node_max->types.vnumber->get_value(); |
| long range_min = node_min->types.vnumber->get_value(); |
| |
| assignment_size = (range_max - range_min) + 1; |
| } |
| |
| oassert(assignment_size != 0); |
| return assignment_size; |
| } |
| |
| /*--------------------------------------------------------------------------------------------- |
| * (function: move_ast_node) |
| * move node from src to dest |
| *-------------------------------------------------------------------------------------------*/ |
| void move_ast_node(ast_node_t *src, ast_node_t *dest, ast_node_t *node) |
| { |
| int i, j; |
| int number; |
| number = src->num_children; |
| for(i = 0; i < number; i++) |
| { |
| if(src->children[i]->unique_count == node->unique_count) |
| { |
| number = number - 1; |
| src->num_children = number; |
| for(j = i; j < number; j++) |
| { |
| src->children[j] = src->children[j + 1]; |
| } |
| } |
| } |
| add_child_to_node(dest, node); |
| } |
| |
| /*--------------------------------------------------------------------------------------------- |
| * (function: ast_node_deep_copy) |
| * copy node and its children recursively; return new subtree |
| *-------------------------------------------------------------------------------------------*/ |
| ast_node_t *ast_node_deep_copy(ast_node_t *node){ |
| ast_node_t *node_copy = ast_node_copy(node); |
| |
| if (node && node_copy) |
| { |
| //Create a new child list; |
| node_copy->children = (ast_node_t**)vtr::calloc(node->num_children, sizeof(ast_node_t*)); |
| |
| //Recursively copy its children |
| for(long i = 0; i < node->num_children; i++) |
| { |
| oassert(node != node->children[i]); |
| node_copy->children[i] = ast_node_deep_copy(node->children[i]); |
| } |
| } |
| |
| return node_copy; |
| } |
| |
| /*--------------------------------------------------------------------------------------------- |
| * (function: ast_node_copy) |
| * copy node; return new node |
| *-------------------------------------------------------------------------------------------*/ |
| ast_node_t *ast_node_copy(ast_node_t *node){ |
| ast_node_t *node_copy; |
| |
| if(node == NULL){ |
| return NULL; |
| } |
| |
| //Copy node |
| node_copy = (ast_node_t *)vtr::calloc(1, sizeof(ast_node_t)); |
| memcpy(node_copy, node, sizeof(ast_node_t)); |
| |
| //Copy contents |
| if (node->type == NUMBERS && node->types.vnumber) |
| node_copy->types.vnumber = new VNumber((*node->types.vnumber)); |
| |
| node_copy->types.identifier = vtr::strdup(node->types.identifier); |
| node_copy->children = NULL; |
| |
| return node_copy; |
| } |
| |
| /*--------------------------------------------------------------------------- |
| * (function: expand_power) |
| * expand power operation into multiplication |
| *-------------------------------------------------------------------------*/ |
| static void expand_power(ast_node_t **node) |
| { |
| /* create a node for this array reference */ |
| ast_node_t* new_node = NULL; |
| |
| ast_node_t *expression1 = (*node)->children[0]; |
| ast_node_t *expression2 = (*node)->children[1]; |
| |
| /* allocate child nodes to this node */ |
| int len = expression2->types.vnumber->get_value(); |
| if (expression1->type == NUMBERS) |
| { |
| int len1 = expression1->types.vnumber->get_value(); |
| long powRes = pow(len1, len); |
| new_node = create_tree_node_number(powRes, (*node)->line_number, (*node)->file_number); |
| } |
| else |
| { |
| if (len == 0) |
| { |
| new_node = create_tree_node_number(1L, (*node)->line_number, (*node)->file_number); |
| } |
| else |
| { |
| new_node = ast_node_deep_copy(expression1); |
| for (int i=1; i < len; i++) |
| { |
| ast_node_t *temp_node = create_node_w_type(BINARY_OPERATION, (*node)->line_number, (*node)->file_number); |
| temp_node->types.operation.op = MULTIPLY; |
| |
| allocate_children_to_node(temp_node, { ast_node_deep_copy(expression1), new_node } ); |
| new_node = temp_node; |
| } |
| } |
| } |
| free_whole_tree(*node); |
| *node = new_node; |
| } |
| |
| /*--------------------------------------------------------------------------- |
| * (function: change_ast_node) |
| * check if the number is the power of 2 |
| *-------------------------------------------------------------------------*/ |
| static void check_node_number(ast_node_t *parent, ast_node_t *child, int flag) |
| { |
| long power = 0; |
| long number = child->types.vnumber->get_value(); |
| if (number <= 1) |
| return; |
| while (((number % 2) == 0) && number > 1) // While number is even and > 1 |
| { |
| number >>= 1; |
| power++; |
| } |
| if (number == 1) // the previous number is a power of 2 |
| { |
| change_to_number_node(child, power); |
| if (flag == 1) // multiply |
| parent->types.operation.op = SL; |
| else if (flag == 2) // multiply and needs to move children nodes |
| { |
| parent->types.operation.op = SL; |
| parent->children[0] = parent->children[1]; |
| parent->children[1] = child; |
| } |
| else if (flag == 3) // divide |
| parent->types.operation.op = SR; |
| } |
| } |
| |
| /*--------------------------------------------------------------------------- |
| * (function: change_ast_node) |
| * check the children nodes of an operation node |
| *-------------------------------------------------------------------------*/ |
| static void check_binary_operation(ast_node_t **node) |
| { |
| if((*node) && (*node)->type == BINARY_OPERATION){ |
| switch((*node)->types.operation.op){ |
| case MULTIPLY: |
| if ((*node)->children[0]->type == IDENTIFIERS && (*node)->children[1]->type == NUMBERS) |
| check_node_number((*node), (*node)->children[1], 1); // 1 means multiply and don't need to move children nodes |
| if ((*node)->children[0]->type == NUMBERS && (*node)->children[1]->type == IDENTIFIERS) |
| check_node_number((*node), (*node)->children[0], 2); // 2 means multiply and needs to move children nodes |
| break; |
| case DIVIDE: |
| if (!node_is_constant((*node)->children[1])) |
| error_message(NETLIST_ERROR, (*node)->line_number, (*node)->file_number, "%s", "Odin only supports constant expressions as divisors\n"); |
| if ((*node)->children[0]->type == IDENTIFIERS && (*node)->children[1]->type == NUMBERS) |
| check_node_number((*node), (*node)->children[1], 3); // 3 means divide |
| break; |
| case POWER: |
| if (!node_is_constant((*node)->children[1])) |
| error_message(NETLIST_ERROR, (*node)->line_number, (*node)->file_number, "%s", "Odin only supports constant expressions as exponents\n"); |
| expand_power(node); |
| break; |
| default: |
| break; |
| } |
| } |
| } |
| |
| /*--------------------------------------------------------------------------------------------- |
| * (function: calculate_unary) |
| * TODO ! what does verilog say about !d'00001 ?? |
| * we currently make it as small as possible(+1) such that d'00001 becomes (in bin) 01 |
| * so it would become 10, is that what is defined? |
| *-------------------------------------------------------------------------------------------*/ |
| ast_node_t *fold_unary(ast_node_t **node) |
| { |
| if(!node || !(*node)) |
| return NULL; |
| |
| operation_list op_id = (*node)->types.operation.op; |
| ast_node_t *child_0 = (*node)->children[0]; |
| |
| if(node_is_constant(child_0)) |
| { |
| bool success = false; |
| VNumber voperand_0 = *(child_0->types.vnumber); |
| VNumber vresult; |
| |
| switch (op_id){ |
| case LOGICAL_NOT: |
| vresult = V_LOGICAL_NOT(voperand_0); |
| success = true; |
| break; |
| |
| case BITWISE_NOT: |
| vresult = V_BITWISE_NOT(voperand_0); |
| success = true; |
| break; |
| |
| case MINUS: |
| vresult = V_MINUS(voperand_0); |
| success = true; |
| break; |
| |
| case ADD: |
| vresult = V_ADD(voperand_0); |
| success = true; |
| break; |
| |
| case BITWISE_OR: |
| vresult = V_BITWISE_OR(voperand_0); |
| success = true; |
| break; |
| |
| case BITWISE_NAND: |
| vresult = V_BITWISE_NAND(voperand_0); |
| success = true; |
| break; |
| |
| case BITWISE_NOR: |
| vresult = V_BITWISE_NOR(voperand_0); |
| success = true; |
| break; |
| |
| case BITWISE_XNOR: |
| vresult = V_BITWISE_XNOR(voperand_0); |
| success = true; |
| break; |
| |
| case BITWISE_XOR: |
| vresult = V_BITWISE_XOR(voperand_0); |
| success = true; |
| break; |
| |
| case CLOG2: |
| if(voperand_0.size() > ODIN_STD_BITWIDTH) |
| warning_message(PARSE_ERROR, (*node)->line_number, (*node)->file_number, "argument is %ld-bits but ODIN limit is %lu-bits \n",voperand_0.size(),ODIN_STD_BITWIDTH); |
| |
| vresult = VNumber(clog2(voperand_0.get_value(), voperand_0.size())); |
| success = true; |
| break; |
| |
| case UNSIGNED: |
| vresult = V_UNSIGNED(voperand_0); |
| success = true; |
| break; |
| |
| case SIGNED: |
| vresult = V_SIGNED(voperand_0); |
| success = true; |
| break; |
| |
| default: |
| break; |
| } |
| |
| if(success) |
| { |
| ast_node_t *new_num = create_tree_node_number(vresult, (*node)->line_number, (*node)->file_number); |
| return new_num; |
| } |
| } |
| else if (op_id == CLOG2) |
| { |
| /* $clog2() argument must be a constant expression */ |
| error_message(PARSE_ERROR, (*node)->line_number, current_parse_file, "%s", "Argument must be constant\n"); |
| } |
| |
| return NULL; |
| } |
| |
| /*--------------------------------------------------------------------------------------------- |
| * (function: calculate_binary) |
| *-------------------------------------------------------------------------------------------*/ |
| ast_node_t *fold_binary(ast_node_t **node) |
| { |
| if(!node || !(*node)) |
| return NULL; |
| |
| operation_list op_id = (*node)->types.operation.op; |
| ast_node_t *child_0 = (*node)->children[0]; |
| ast_node_t *child_1 = (*node)->children[1]; |
| |
| if(node_is_constant(child_0) && node_is_constant(child_1)) |
| { |
| bool success = false; |
| VNumber voperand_0 = *(child_0->types.vnumber); |
| VNumber voperand_1 = *(child_1->types.vnumber); |
| VNumber vresult; |
| |
| switch (op_id){ |
| case ADD: |
| vresult = V_ADD(voperand_0, voperand_1); |
| success = true; |
| break; |
| |
| case MINUS: |
| vresult = V_MINUS(voperand_0, voperand_1); |
| success = true; |
| break; |
| |
| case MULTIPLY: |
| vresult = V_MULTIPLY(voperand_0, voperand_1); |
| success = true; |
| break; |
| |
| case POWER: |
| vresult = V_POWER(voperand_0, voperand_1); |
| success = true; |
| break; |
| |
| case DIVIDE: |
| vresult = V_DIV(voperand_0, voperand_1); |
| success = true; |
| break; |
| |
| case BITWISE_XOR: |
| vresult = V_BITWISE_XOR(voperand_0, voperand_1); |
| success = true; |
| break; |
| |
| case BITWISE_XNOR: |
| vresult = V_BITWISE_XNOR(voperand_0, voperand_1); |
| success = true; |
| break; |
| |
| case BITWISE_AND: |
| vresult = V_BITWISE_AND(voperand_0, voperand_1); |
| success = true; |
| break; |
| |
| case BITWISE_NAND: |
| vresult = V_BITWISE_NAND(voperand_0, voperand_1); |
| success = true; |
| break; |
| |
| case BITWISE_OR: |
| vresult = V_BITWISE_OR(voperand_0, voperand_1); |
| success = true; |
| break; |
| |
| case BITWISE_NOR: |
| vresult = V_BITWISE_NOR(voperand_0, voperand_1); |
| success = true; |
| break; |
| |
| case SL: |
| vresult = V_SHIFT_LEFT(voperand_0, voperand_1); |
| success = true; |
| break; |
| |
| case SR: |
| vresult = V_SHIFT_RIGHT(voperand_0, voperand_1); |
| success = true; |
| break; |
| |
| case ASR: |
| { |
| vresult = V_SIGNED_SHIFT_RIGHT(voperand_0, voperand_1); |
| success = true; |
| break; |
| } |
| case LOGICAL_AND: |
| vresult = V_LOGICAL_AND(voperand_0, voperand_1); |
| success = true; |
| break; |
| |
| case LOGICAL_OR: |
| vresult = V_LOGICAL_OR(voperand_0, voperand_1); |
| success = true; |
| break; |
| |
| case MODULO: |
| vresult = V_MOD(voperand_0, voperand_1); |
| success = true; |
| break; |
| |
| case LT: |
| vresult = V_LT(voperand_0, voperand_1); |
| success = true; |
| break; |
| |
| case GT: |
| vresult = V_GT(voperand_0, voperand_1); |
| success = true; |
| break; |
| |
| case LOGICAL_EQUAL: |
| vresult = V_EQUAL(voperand_0, voperand_1); |
| success = true; |
| break; |
| |
| case NOT_EQUAL: |
| vresult = V_NOT_EQUAL(voperand_0, voperand_1); |
| success = true; |
| break; |
| |
| case LTE: |
| vresult = V_LE(voperand_0, voperand_1); |
| success = true; |
| break; |
| |
| case GTE: |
| vresult = V_GE(voperand_0, voperand_1); |
| success = true; |
| break; |
| |
| case CASE_EQUAL: |
| vresult = V_CASE_EQUAL(voperand_0, voperand_1); |
| success = true; |
| break; |
| |
| case CASE_NOT_EQUAL: |
| vresult = V_CASE_NOT_EQUAL(voperand_0, voperand_1); |
| success = true; |
| break; |
| |
| default: |
| break; |
| } |
| |
| if(success) |
| { |
| ast_node_t *new_num = create_tree_node_number(vresult, (*node)->line_number, (*node)->file_number); |
| return new_num; |
| } |
| } |
| else |
| { |
| check_binary_operation(node); |
| oassert(!((*node)->type == BINARY_OPERATION && (*node)->types.operation.op == POWER)); |
| } |
| return NULL; |
| } |
| |
| /*--------------------------------------------------------------------------------------------- |
| * (function: node_is_constant) |
| *-------------------------------------------------------------------------------------------*/ |
| bool node_is_constant(ast_node_t *node) |
| { |
| if (node && |
| node->type == NUMBERS && |
| node->types.vnumber != nullptr) |
| { |
| return true; |
| } |
| return false; |
| } |
| |
| /*--------------------------------------------------------------------------- |
| * (function: initial_node) |
| *-------------------------------------------------------------------------*/ |
| void initial_node(ast_node_t *new_node, ids id, int line_number, int file_number, int unique_counter) |
| { |
| new_node->type = id; |
| new_node->children = NULL; |
| new_node->num_children = 0; |
| new_node->unique_count = unique_counter; //++count_id; |
| new_node->line_number = line_number; |
| new_node->file_number = file_number; |
| new_node->far_tag = 0; |
| new_node->high_number = 0; |
| new_node->hb_port = 0; |
| new_node->net_node = 0; |
| new_node->types.vnumber = nullptr; |
| new_node->types.identifier = NULL; |
| new_node->types.hierarchy = NULL; |
| new_node->chunk_size = 1; |
| } |
| |
| /*--------------------------------------------------------------------------- |
| * (function: clog2) |
| *-------------------------------------------------------------------------*/ |
| long clog2(long value_in, int length) |
| { |
| if (value_in == 0) return 0; |
| |
| long result; |
| |
| /* negative numbers may be larger than they need to be */ |
| if (value_in < 0 && value_in >= std::numeric_limits<int32_t>::min()) return 32; |
| |
| if (length > 32) |
| { |
| uint64_t unsigned_val = (uint64_t) value_in; |
| result = (long) ceil(log2((double) unsigned_val)); |
| } |
| else |
| { |
| uint32_t unsigned_val = (uint32_t) value_in; |
| result = (long) ceil(log2((double) unsigned_val)); |
| } |
| |
| return result; |
| } |
| |
| /*--------------------------------------------------------------------------- |
| * (function: resolve_concat_sizes) |
| *-------------------------------------------------------------------------*/ |
| long resolve_concat_sizes(ast_node_t *node_top, sc_hierarchy *local_ref) |
| { |
| long concatenation_size = 0; |
| |
| if (node_top) |
| { |
| switch (node_top->type) |
| { |
| case CONCATENATE: |
| { |
| for (int i = 0; i < node_top->num_children; i++) |
| { |
| concatenation_size += resolve_concat_sizes(node_top->children[i], local_ref); |
| } |
| } |
| break; |
| |
| case IDENTIFIERS: |
| case ARRAY_REF: |
| case RANGE_REF: |
| { |
| concatenation_size += get_size_of_variable(node_top, local_ref); |
| } |
| break; |
| |
| case BINARY_OPERATION: |
| case UNARY_OPERATION: |
| { |
| long max_size = 0; |
| for (int i = 0; i < node_top->num_children; i++) |
| { |
| long this_size = resolve_concat_sizes(node_top->children[i], local_ref); |
| if (this_size > max_size) max_size = this_size; |
| } |
| concatenation_size += max_size; |
| } |
| break; |
| |
| case IF_Q: |
| { |
| /* check true/false expressions */ |
| long true_length = resolve_concat_sizes(node_top->children[1], local_ref); |
| long false_length = resolve_concat_sizes(node_top->children[2], local_ref); |
| concatenation_size += (true_length > false_length) ? true_length : false_length; |
| } |
| break; |
| |
| case NUMBERS: |
| { |
| /* verify that the number that this represents is sized */ |
| if (!(node_top->types.vnumber->is_defined_size())) |
| { |
| error_message(NETLIST_ERROR, node_top->line_number, node_top->file_number, "%s", "Unsized constants cannot be concatenated.\n"); |
| } |
| concatenation_size += node_top->types.vnumber->size(); |
| } |
| break; |
| |
| default: |
| { |
| error_message(NETLIST_ERROR, node_top->line_number, node_top->file_number, "%s", "Unsupported operation within a concatenation.\n"); |
| } |
| } |
| } |
| |
| return concatenation_size; |
| } |