blob: 0cf3142dd6040c9403b0c2e0b15748fc9b7d7822 [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 <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);
void update_tree_tag(ast_node_t *node, int cases, int tagged);
// 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(!strcmp(global_args.high_level_block,"if")){
type = IF;
}else if(!strcmp(global_args.high_level_block,"always")){
type = ALWAYS;
}else if(!strcmp(global_args.high_level_block,"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);
new_node->type = id;
new_node->children = NULL;
new_node->num_children = 0;
new_node->line_number = line_number;
new_node->file_number = file_number;
new_node->unique_count = unique_count;
if(update_unique_count)
unique_count += 1;
new_node->far_tag = 0;
new_node->high_number = 0;
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:
vtr::free(node->types.number.number);
vtr::free(node->types.number.binary_string);
break;
case CONCATENATE:
for(i=0; i<node->types.concat.num_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_whole_tree)
*-------------------------------------------------------------------------*/
ast_node_t *free_whole_tree(ast_node_t *node)
{
free_all_children(node);
return free_single_node(node);
}
/*---------------------------------------------------------------------------------------------
* (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_long_number)
*-------------------------------------------------------------------------------------------*/
ast_node_t *create_tree_node_long_number(long number, int constant_bit_size, int line_number, int /*file_number*/)
{
int flag = 0;
ast_node_t* new_node = create_node_w_type(NUMBERS, line_number, current_parse_file);
new_node->types.number.base = LONG;
new_node->types.number.value = number;
if (number < 0)
{
flag = 1;
number = number * -1;
}
oassert (ceil((log(number+1))/log(2)) <= constant_bit_size);
new_node->types.number.binary_size = constant_bit_size;
new_node->types.number.binary_string = convert_long_to_bit_string(number, new_node->types.number.binary_size);
if (flag == 1)
twos_complement(new_node->types.number.binary_string);
return new_node;
}
/*---------------------------------------------------------------------------------------------
* (function: create_tree_node_number)
*-------------------------------------------------------------------------------------------*/
ast_node_t *create_tree_node_number(std::string input_number, bases base, signedness sign, int line_number, int file_number)
{
oassert(sign != SIGNED && "ODIN_II does not support signed numbers" );
short flag_constant_decimal = FALSE;
ast_node_t* new_node = create_node_w_type(NUMBERS, line_number, current_parse_file);
if(base == LONG)
{
flag_constant_decimal = TRUE;
/* this is base d */
new_node->types.number.base = DEC;
new_node->types.number.size = input_number.length();
new_node->types.number.number = vtr::strdup(input_number.c_str());
/* size is for a constant that needs */
if (strcmp(new_node->types.number.number, "0") != 0)
new_node->types.number.binary_size = ceil((log(convert_dec_string_of_size_to_long(new_node->types.number.number, new_node->types.number.size)+1))/log(2));
else
new_node->types.number.binary_size = 1;
}
else
{
new_node->types.number.base = base;
//no need to check since the parser has done that
auto loc = input_number.find("\'");
std::string number = input_number.substr(loc+2,input_number.size()-(loc+2));
if(loc > 0)
{
new_node->types.number.is_full = 0;
new_node->types.number.size = std::strtol(input_number.substr(0,loc).c_str(),NULL,10);
if(new_node->types.number.size > ODIN_STD_BITWIDTH-1)
warning_message(PARSE_ERROR, line_number, file_number, "input number is %ld-bits but ODIN limit is %lu-bits \n",new_node->types.number.size,ODIN_STD_BITWIDTH-1);
}
else
{
new_node->types.number.is_full = 0;
new_node->types.number.size = ODIN_STD_BITWIDTH-1;
}
input_number = number;
new_node->types.number.binary_size = new_node->types.number.size;
new_node->types.number.number = vtr::strdup(input_number.c_str());
}
/* add in the values for all the numbers */
switch (new_node->types.number.base)
{
case DEC:
// This will have limited width.
new_node->types.number.value = convert_dec_string_of_size_to_long(new_node->types.number.number, new_node->types.number.size);
new_node->types.number.binary_string = convert_long_to_bit_string(new_node->types.number.value, new_node->types.number.binary_size);
break;
case HEX:
if(!is_dont_care_string(new_node->types.number.number)){
new_node->types.number.binary_size *= 4;
new_node->types.number.value = strtoll(new_node->types.number.number,NULL,16); // This will have limited width.
// This will have full width.
new_node->types.number.binary_string = convert_hex_string_of_size_to_bit_string(0, new_node->types.number.number, new_node->types.number.binary_size);
}
else{
new_node->types.number.binary_string = convert_hex_string_of_size_to_bit_string(1, new_node->types.number.number, new_node->types.number.binary_size);
}
break;
case OCT:
new_node->types.number.binary_size *= 3;
new_node->types.number.value = strtoll(new_node->types.number.number,NULL,8); // This will have limited width.
// This will have full width.
new_node->types.number.binary_string = convert_oct_string_of_size_to_bit_string(new_node->types.number.number, new_node->types.number.binary_size);
break;
case BIN:
if(new_node->types.number.is_full == 0){
// This will have limited width.
new_node->types.number.value = strtoll(new_node->types.number.number,NULL,2);
// This will have full width.
}
new_node->types.number.binary_string = convert_binary_string_of_size_to_bit_string(1, new_node->types.number.number, new_node->types.number.binary_size);
break;
default:
oassert(FALSE);
break;
}
return new_node;
}
/*---------------------------------------------------------------------------
* (function: allocate_children_to_node)
*-------------------------------------------------------------------------*/
void allocate_children_to_node(ast_node_t* node, int num_children, ...)
{
va_list ap;
int i;
/* allocate space for the children */
node->children = (ast_node_t**)vtr::malloc(sizeof(ast_node_t*)*num_children);
node->num_children = num_children;
/* set the virtual arguments */
va_start(ap, num_children);
for (i = 0; i < num_children; i++)
{
node->children[i] = va_arg(ap, ast_node_t*);
}
}
/*---------------------------------------------------------------------------------------------
* (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)
*-------------------------------------------------------------------------------------------*/
void add_child_at_the_beginning_of_the_node(ast_node_t* node, ast_node_t *child)
{
long i;
ast_node_t *ref, *ref1;
/* 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 ++;
ref = node->children[0];
for(i = 1; i < node->num_children; i++){
ref1 = node->children[i];
node->children[i] = ref;
ref = ref1;
}
node->children[0] = child;
}
/*---------------------------------------------------------------------------------------------
* (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)
{
long i;
int j;
ast_node_t *rnode[3];
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);
}
}
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);
long sc_spot;
if ((sc_spot = sc_lookup_string(local_symbol_table_sc, temp_string)) == -1)
{
error_message(NETLIST_ERROR, concat_top->line_number, concat_top->file_number, "Missssing declaration of this symbol %s\n", temp_string);
}
else
{
if (((ast_node_t*)local_symbol_table_sc->data[sc_spot])->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);
}
else if (((ast_node_t*)local_symbol_table_sc->data[sc_spot])->children[3] == NULL)
{
/* reverse thorugh the range since highest bit in index will be lower in the string indx */
rnode[1] = resolve_node(NULL, instance_name_prefix, ((ast_node_t*)local_symbol_table_sc->data[sc_spot])->children[1]);
rnode[2] = resolve_node(NULL, instance_name_prefix, ((ast_node_t*)local_symbol_table_sc->data[sc_spot])->children[2]);
oassert(rnode[1]->type == NUMBERS && rnode[2]->type == NUMBERS);
///TODO WHats this?? compareo bit string but uses value ??? value is honestly not the right thing to look for...
// we should restrict ODIN to use binary representation only for easier support of 'x' and 'z' value..
// or at least it's the only thing that makes sense.
// also this gives us the ability to write our own math class for binary and ave better control of what is happening and better sense of it.
// this causes bugs.. theres a patchy workaround, put in bit string but we need a better permanent fix.
for (j = rnode[1]->types.number.value - rnode[2]->types.number.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);
}
}
else if (((ast_node_t*)local_symbol_table_sc->data[sc_spot])->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);
}
else if (concat_top->children[i]->type == RANGE_REF)
{
rnode[1] = resolve_node(NULL, instance_name_prefix, concat_top->children[i]->children[1]);
rnode[2] = resolve_node(NULL, instance_name_prefix, concat_top->children[i]->children[2]);
oassert(rnode[1]->type == NUMBERS && rnode[2]->type == NUMBERS);
oassert(rnode[1]->types.number.value >= rnode[2]->types.number.value);
int width = abs(rnode[1]->types.number.value - rnode[2]->types.number.value) + 1;
//for (j = rnode[1]->types.number.value - rnode[2]->types.number.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.number.value - rnode[2]->types.number.value))-j, instance_name_prefix);
}
}
else if (concat_top->children[i]->type == NUMBERS)
{
if(concat_top->children[i]->types.number.base == DEC)
{
error_message(NETLIST_ERROR, concat_top->line_number, concat_top->file_number, "%s", "Concatenation can't include decimal numbers due to conflict on bits\n");
}
// Changed to reverse to fix concatenation bug.
for (j = concat_top->children[i]->types.number.binary_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);
}
}
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);
}
}
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)
{
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);
long len = snprintf(NULL,0,"%ld", value);
char *number = (char *)vtr::calloc(len+1,sizeof(char));
odin_sprintf(number, "%ld", value);
node->type = NUMBERS;
node->types.identifier = temp_ident;
node->types.number.base = DEC;
node->types.number.size = len;
node->types.number.number = number;
node->types.number.value = value;
if (value == 0)
{
node->types.number.binary_size = 1;
}
else
{
node->types.number.binary_size = ceil((log(convert_dec_string_of_size_to_long(node->types.number.number, node->types.number.size)+1))/log(2));
}
node->types.number.binary_string = convert_long_to_bit_string(value, node->types.number.binary_size);
}
/*---------------------------------------------------------------------------------------------
* (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.number.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)
{
char *return_string = NULL;
ast_node_t *rnode[3];
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.number.value);
}
else if (var_node->type == RANGE_REF)
{
oassert(bit >= 0);
rnode[1] = resolve_node(NULL, instance_name_prefix, var_node->children[1]);
rnode[2] = resolve_node(NULL, instance_name_prefix, 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.number.value >= rnode[2]->types.number.value+bit);
return_string = make_full_ref_name(NULL, NULL, NULL, var_node->children[0]->types.identifier, rnode[2]->types.number.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)
{
long sc_spot;
int pin_index;
if ((sc_spot = sc_lookup_string(local_symbol_table_sc, var_node->types.identifier)) == -1)
{
error_message(NETLIST_ERROR, var_node->line_number, var_node->file_number, "Missing declaration of this symbol %s\n", var_node->types.identifier);
}
if (((ast_node_t*)local_symbol_table_sc->data[sc_spot])->children[1] == NULL)
{
pin_index = bit;
}
else if (((ast_node_t*)local_symbol_table_sc->data[sc_spot])->children[3] == NULL)
{
oassert(((ast_node_t*)local_symbol_table_sc->data[sc_spot])->children[2]->type == NUMBERS);
pin_index = ((ast_node_t*)local_symbol_table_sc->data[sc_spot])->children[2]->types.number.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)
{
if (bit == -1)
bit = 0;
/* strings are msb is 0th index in string, reverse access */
if (bit < var_node->types.number.binary_size)
{
char c = var_node->types.number.binary_string[var_node->types.number.binary_size-bit-1];
switch(c)
{
case '1': return_string = vtr::strdup(ONE_VCC_CNS); break;
case '0': return_string = vtr::strdup(ZERO_GND_ZERO); break;
case 'x': return_string = vtr::strdup(ZERO_GND_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.number.binary_string);
break;
}
}
// if the index is too big for the number pad with zero
else
return_string = vtr::strdup(ZERO_GND_ZERO);
}
else if (var_node->type == CONCATENATE)
{
if (var_node->types.concat.num_bit_strings == 0)
{
return_string = NULL;
oassert(FALSE);
}
else
{
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);
}
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]);
}
}
else
{
return_string = NULL;
error_message(NETLIST_ERROR, var_node->line_number, var_node->file_number, "Unsupported variable type. var_node->type = %ld\n",var_node->type);
}
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, j;
for (i = 0, j = var_node->types.number.binary_size-1; i < width; i++, j--)
{
/* strings are msb is 0th index in string, reverse access */
if (j >= 0)
{
char c = var_node->types.number.binary_string[j];
switch(c)
{
case '1': return_string[i] = vtr::strdup(ONE_VCC_CNS); break;
case '0': return_string[i] = vtr::strdup(ZERO_GND_ZERO); break;
case 'x': return_string[i] = vtr::strdup(ZERO_GND_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.number.binary_string);
}
}
else
// if the index is too big for the number pad with zero
return_string[i] = vtr::strdup(ZERO_GND_ZERO);
}
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)
{
char **return_string = NULL;
char_list_t *return_list = (char_list_t*)vtr::malloc(sizeof(char_list_t));
ast_node_t *rnode[3];
int i;
int width = 0;
if (var_node->type == ARRAY_REF)
{
width = 1;
return_string = (char**)vtr::malloc(sizeof(char*));
rnode[1] = resolve_node(NULL, instance_name_prefix, 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.number.value);
}
else if (var_node->type == RANGE_REF)
{
rnode[0] = resolve_node(NULL, instance_name_prefix, var_node->children[0]);
rnode[1] = resolve_node(NULL, instance_name_prefix, var_node->children[1]);
rnode[2] = resolve_node(NULL, instance_name_prefix, var_node->children[2]);
oassert(rnode[1]->type == NUMBERS && rnode[2]->type == NUMBERS);
width = abs(rnode[1]->types.number.value - rnode[2]->types.number.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.number.value+i);
}
else
{
oassert(rnode[0]->type == NUMBERS);
return_string = get_name_of_pins_number(rnode[0], rnode[2]->types.number.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) */
long sc_spot;
ast_node_t *sym_node;
// try and resolve var_node
sym_node = resolve_node(NULL, instance_name_prefix, var_node);
if (sym_node == var_node)
{
char *temp_string = make_full_ref_name(NULL, NULL, NULL, var_node->types.identifier, -1);
if ((sc_spot = sc_lookup_string(function_local_symbol_table_sc, temp_string)) > -1)
{
sym_node = (ast_node_t*)function_local_symbol_table_sc->data[sc_spot];
}
else if ((sc_spot = sc_lookup_string(local_symbol_table_sc, temp_string)) > -1)
{
sym_node = (ast_node_t*)local_symbol_table_sc->data[sc_spot];
}
else
{
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->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[3] == NULL)
{
int index = 0;
rnode[1] = resolve_node(NULL, instance_name_prefix, sym_node->children[1]);
rnode[2] = resolve_node(NULL, instance_name_prefix, sym_node->children[2]);
oassert(rnode[1]->type == NUMBERS && rnode[2]->type == NUMBERS);
width = (rnode[1]->types.number.value - rnode[2]->types.number.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.number.value);
index++;
}
}
else if (sym_node->children[3] != NULL)
{
oassert(FALSE);
}
}
else
{
oassert(sym_node->type == NUMBERS);
width = sym_node->types.number.binary_size;
return_string = get_name_of_pins_number(sym_node, 0, width);
}
}
else if (var_node->type == NUMBERS)
{
width = var_node->types.number.binary_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)
{
/* If this hasn't been made into a string list then do it */
make_concat_into_list_of_strings(var_node, instance_name_prefix);
}
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)
{
int i;
char_list_t *return_list;
char *temp_str;
/* get the list */
return_list = get_name_of_pins(var_node, instance_name_prefix);
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: resolve_node)
*--------------------------------------------------------------------------*/
/**
* Recursively resolves an IDENTIFIER to a parameter into its actual value,
* by looking it up in the local_param_table_sc
* Also try and fold any BINARY_OPERATIONs now that an IDENTIFIER has been
* resolved
*/
ast_node_t *resolve_node(STRING_CACHE *local_param_table_sc, char *module_name, ast_node_t *node)
{
long sc_spot = -1;
// Not sure this should even be used.
if(local_param_table_sc == NULL
&& module_name != NULL)
{
sc_spot = sc_lookup_string(global_param_table_sc, module_name);
if (sc_spot != -1)
{
local_param_table_sc = (STRING_CACHE *)global_param_table_sc->data[sc_spot];
}
}
if (node)
{
oassert(node->type != NO_ID);
ast_node_t *node_copy;
node_copy = (ast_node_t *)vtr::calloc(1,sizeof(ast_node_t));
memcpy(node_copy, node, sizeof(ast_node_t));
node_copy->children = (ast_node_t **)vtr::calloc(node_copy->num_children,sizeof(ast_node_t*));
long i;
for (i = 0; i < node->num_children; i++)
{
node_copy->children[i] = resolve_node(local_param_table_sc, module_name, node->children[i]);
}
ast_node_t *newNode = NULL;
switch (node->type){
case IDENTIFIERS:
{
if(local_param_table_sc != NULL)
{
sc_spot = sc_lookup_string(local_param_table_sc, node->types.identifier);
if (sc_spot != -1){
newNode = ast_node_deep_copy((ast_node_t *)local_param_table_sc->data[sc_spot]);
}
}
}
break;
case UNARY_OPERATION:
newNode = fold_unary(node_copy);
break;
case BINARY_OPERATION:
newNode = fold_binary(node_copy);
break;
default:
break;
}
if (node_is_constant(newNode)){
newNode->shared_node = node->shared_node;
// /* clean up */
// if (node->type != IDENTIFIERS) {
// node = free_whole_tree(node);
// }
node = newNode;
}
vtr::free(node_copy->children);
vtr::free(node_copy);
}
return node;
}
/*----------------------------------------------------------------------------
* (function: resolve_ast_node)
*--------------------------------------------------------------------------*/
/**
* Recursively resolves an IDENTIFIER to a parameter into its actual value,
* by looking it up in the local_param_table_sc
* Also try and fold any BINARY_OPERATIONs now that an IDENTIFIER has been
* resolved
*/
ast_node_t *resolve_ast_node(STRING_CACHE *local_param_table_sc, short initial, char *module_name, ast_node_t *node)
{
if (node)
{
ast_node_t *node_copy;
node_copy = (ast_node_t *)vtr::calloc(1,sizeof(ast_node_t));
memcpy(node_copy, node, sizeof(ast_node_t));
node_copy->children = (ast_node_t **)vtr::calloc(node_copy->num_children,sizeof(ast_node_t*));
long i;
for (i = 0; i < node->num_children; i++){
node_copy->children[i] = resolve_ast_node(local_param_table_sc, initial, module_name, node->children[i]);
}
ast_node_t *newNode = NULL;
switch (node->type){
case UNARY_OPERATION:
newNode = fold_unary(node_copy);
break;
case BINARY_OPERATION:
newNode = fold_binary(node_copy);
break;
default:
break;
}
if (node_is_ast_constant(newNode, local_param_table_sc)){
newNode->shared_node = node->shared_node;
/* clean up */
if (node->type != IDENTIFIERS) {
node = free_whole_tree(node);
}
node = newNode;
}
vtr::free(node_copy->children);
vtr::free(node_copy);
}
return node;
}
/*----------------------------------------------------------------------------
* (function: make_module_param_name)
*--------------------------------------------------------------------------*/
/**
* Make a unique name for a module based on its parameter list
* e.g. for a "mod #(0,1,2,3) a(b,c,d)" instantiation you get name___0_1_2_3
*/
char *make_module_param_name(STRING_CACHE *defines_for_module_sc, ast_node_t *module_param_list, char *module_name)
{
char *module_param_name = (char*)vtr::malloc((strlen(module_name)+1024) * sizeof(char));
strcpy(module_param_name, module_name);
if (module_param_list)
{
long i;
oassert(module_param_list->num_children > 0);
strcat(module_param_name, "___");
for (i = 0; i < module_param_list->num_children; i++)
{
if (module_param_list->children[i]->children[5])
{
ast_node_t *node = resolve_node(defines_for_module_sc, module_name, module_param_list->children[i]->children[5]);
oassert(node->type == NUMBERS);
odin_sprintf(module_param_name, "%s_%ld", module_param_name, module_param_list->children[i]->children[5]->types.number.value);
}
}
}
return module_param_name;
}
/*---------------------------------------------------------------------------------------------
* (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;
long i;
if(node == NULL){
return NULL;
}
//Copy node
node_copy = (ast_node_t *)vtr::malloc(sizeof(ast_node_t));
memcpy(node_copy, node, sizeof(ast_node_t));
//Copy contents
node_copy->types.identifier = vtr::strdup(node->types.identifier);
node_copy->types.number.number = vtr::strdup(node->types.number.number);
node_copy->types.number.binary_string = vtr::strdup(node->types.number.binary_string);
//Create a new child list
node_copy->children = (ast_node_t**)vtr::malloc(sizeof(ast_node_t*)*node_copy->num_children);
//Recursively copy its children
for(i = 0; i < node->num_children; i++){
node_copy->children[i] = ast_node_deep_copy(node->children[i]);
}
return node_copy;
}
/*---------------------------------------------------------------------------------------------
* (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)
{
operation_list op_id = node->types.operation.op;
ast_node_t *child_0 = node->children[0];
if(node_is_constant(child_0))
{
long operand_0 = child_0->types.number.value;
short success = FALSE;
long result = 0;
int i=0;
int length = child_0->types.number.binary_size;
char *binary_string = vtr::strdup(child_0->types.number.binary_string);
switch (op_id){
case LOGICAL_NOT:
result = !operand_0;
success = TRUE;
break;
case BITWISE_NOT:
result = ~operand_0;
success = TRUE;
break;
case MINUS:
result = -operand_0;
success = TRUE;
break;
case ADD:
result = operand_0;
success = TRUE;
break;
case BITWISE_OR:
result = 0;
for(i=0;i<=length;i++){
if(get_bit(binary_string[i]) == 1){
result = 1;
break;
}
}
success = TRUE;
break;
case BITWISE_NAND:
result = get_bit(binary_string[0]);
for(i=1;i<length;i++){
result = !(result && get_bit(binary_string[i]));
}
success = TRUE;
break;
case BITWISE_NOR:
result = get_bit(binary_string[0]);
for(i=1;i<length;i++){
result = !(result || get_bit(binary_string[i]));
}
success = TRUE;
break;
case BITWISE_XNOR:
result = get_bit(binary_string[0]);
for(i=1;i<length;i++){
result = ( (result && get_bit(binary_string[i])) || (!result && !get_bit(binary_string[i])) );
}
success = TRUE;
break;
case BITWISE_XOR:
result = get_bit(binary_string[0]);
for(i=1;i<length;i++){
result = ( (!result && get_bit(binary_string[i])) || (result && !get_bit(binary_string[i])) );
}
success = TRUE;
break;
case CLOG2:
if(length > ODIN_STD_BITWIDTH)
warning_message(PARSE_ERROR, child_0->line_number, child_0->file_number, "argument is %ld-bits but ODIN limit is %lu-bits \n",length,ODIN_STD_BITWIDTH);
result = clog2(operand_0, length);
success = TRUE;
break;
default:
break;
}
vtr::free(binary_string);
if(success){
return create_tree_node_long_number(result, ODIN_STD_BITWIDTH, child_0->line_number, child_0->file_number);
}
}
return NULL;
}
/*---------------------------------------------------------------------------------------------
* (function: calculate_binary)
*-------------------------------------------------------------------------------------------*/
ast_node_t * fold_binary(ast_node_t *node)
{
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))
{
long operand_0 = child_0->types.number.value;
long operand_1 = child_1->types.number.value;
long result = 0;
short success = FALSE;
int length_0 = child_0->types.number.binary_size;
char *binary_string_0 = vtr::strdup(child_0->types.number.binary_string);
int length_1 = child_1->types.number.binary_size;
char *binary_string_1 = vtr::strdup(child_1->types.number.binary_string);
switch (op_id){
case ADD:
result = operand_0 + operand_1;
success = TRUE;
break;
case MINUS:
result = operand_0 - operand_1;
success = TRUE;
break;
case MULTIPLY:
result = operand_0 * operand_1;
success = TRUE;
break;
case DIVIDE:
result = operand_0 / operand_1;
success = TRUE;
break;
case BITWISE_XOR:
result = operand_0 ^ operand_1;
success = TRUE;
break;
case BITWISE_XNOR:
result = ~(operand_0 ^ operand_1);
success = TRUE;
break;
case BITWISE_AND:
result = operand_0 & operand_1;
success = TRUE;
break;
case BITWISE_NAND:
result = ~(operand_0 & operand_1);
success = TRUE;
break;
case BITWISE_OR:
result = operand_0 | operand_1;
success = TRUE;
break;
case BITWISE_NOR:
result = ~(operand_0 | operand_1);
success = TRUE;
break;
case SL:
result = shift_left_value_with_overflow_check(operand_0, operand_1);
success = TRUE;
break;
case SR:
result = operand_0 >> operand_1;
success = TRUE;
break;
case ASR:
{
long mask = 0x0L;
result = operand_0 >> operand_1;
if(operand_0 < 0)
{
for(long shift = 0; shift<operand_1; shift++){
mask |= shift_left_value_with_overflow_check(0x1L, (ODIN_STD_BITWIDTH - (shift+1)));
}
}
result |= mask;
success = TRUE;
break;
}
case LOGICAL_AND:
result = operand_0 && operand_1;
success = TRUE;
break;
case LOGICAL_OR:
result = operand_0 || operand_1;
success = TRUE;
break;
case MODULO:
result = operand_0 % operand_1;
success = TRUE;
break;
case LT:
result = operand_0 < operand_1;
success = TRUE;
break;
case GT:
result = operand_0 > operand_1;
success = TRUE;
break;
case LOGICAL_EQUAL:
result = operand_0 == operand_1;
success = TRUE;
break;
case NOT_EQUAL:
result = operand_0 != operand_1;
success = TRUE;
break;
case LTE:
result = operand_0 <= operand_1;
success = TRUE;
break;
case GTE:
result = operand_0 >= operand_1;
success = TRUE;
break;
case CASE_EQUAL:
if(length_0 != length_1){
warning_message(NETLIST_ERROR, -1, -1, "%s\n",
"the binary string to compare do not have the same length, comparison is done only on smallest of the two bit_range");
}
result =1;
for(long i0=length_0, i1=length_1; i0>=0 && i1>=0; i0--, i1--)
{
if(get_bit(binary_string_0[i0]) != get_bit(binary_string_1[i1])){
result = 0;
break;
}
}
success = TRUE;
break;
case CASE_NOT_EQUAL:
if(length_0 != length_1){
warning_message(NETLIST_ERROR, -1, -1, "%s\n",
"the binary string to compare do not have the same length, comparison is done only on smallest of the two bit_range");
}
result =0;
for(long i0=length_0, i1=length_1; i0>=0 && i1>=0; i0--, i1--)
{
if(get_bit(binary_string_0[i0]) != get_bit(binary_string_1[i1])){
result = 1;
break;
}
}
success = TRUE;
break;
default:
break;
}
vtr::free(binary_string_0);
vtr::free(binary_string_1);
if(success){
return create_tree_node_long_number(result,ODIN_STD_BITWIDTH, child_0->line_number, child_0->file_number);
}
}
return NULL;
}
/*---------------------------------------------------------------------------------------------
* (function: node_is_constant)
*-------------------------------------------------------------------------------------------*/
ast_node_t *node_is_constant(ast_node_t *node){
if (node && node->type == NUMBERS){
/* check if it's a constant depending on the number type */
switch (node->types.number.base){
case DEC: //fallthrough
case HEX: //fallthrough
case OCT: //fallthrough
case BIN:
if (node->types.number.value == -1){
break;
}
//fallthrough
case LONG:
return node;
default:
break;
}
}
return NULL;
}
/*---------------------------------------------------------------------------------------------
* (function: node_is_ast_constant)
*-------------------------------------------------------------------------------------------*/
ast_node_t *node_is_ast_constant(ast_node_t *node){
if (node &&
(node_is_constant(node)
|| (node->types.variable.is_parameter == TRUE)
|| (node->type == UNARY_OPERATION && node_is_ast_constant(node->children[0]))
|| (node->type == BINARY_OPERATION && node_is_ast_constant(node->children[0]) && node_is_ast_constant(node->children[1]))))
{
return node;
}
return NULL;
}
/*---------------------------------------------------------------------------------------------
* (function: node_is_ast_constant)
*-------------------------------------------------------------------------------------------*/
ast_node_t *node_is_ast_constant(ast_node_t *node, STRING_CACHE *defines_for_module_sc){
if (node && (node_is_constant(node)
|| (node->types.variable.is_parameter == TRUE)
|| (node->type == UNARY_OPERATION && node_is_ast_constant(node->children[0], defines_for_module_sc))
|| (node->type == BINARY_OPERATION && node_is_ast_constant(node->children[0], defines_for_module_sc) && node_is_ast_constant(node->children[1], defines_for_module_sc))))
{
return node;
}
else if (node && node->type == IDENTIFIERS) {
int sc_spot;
if ((sc_spot = sc_lookup_string(defines_for_module_sc, node->types.identifier)) != -1
&& node_is_ast_constant((ast_node_t *)defines_for_module_sc->data[sc_spot]))
{
return node;
}
}
return NULL;
}
/*---------------------------------------------------------------------------
* (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->shared_node = FALSE;
new_node->hb_port = 0;
new_node->net_node = 0;
new_node->is_read_write = 0;
}
/*---------------------------------------------------------------------------
* (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;
}