| /* |
| 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> |
| #include <sstream> |
| #include <string.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <ctype.h> |
| #include <limits.h> |
| #include <errno.h> |
| #include "odin_types.h" |
| #include "odin_globals.h" |
| #include <cstdarg> |
| |
| #include "odin_util.h" |
| #include "vtr_util.h" |
| #include "vtr_memory.h" |
| #include <regex> |
| #include <stdbool.h> |
| |
| // for mkdir |
| #ifdef WIN32 |
| #include <direct.h> |
| #else |
| #include <sys/stat.h> |
| #endif |
| |
| long shift_left_value_with_overflow_check(long input_value, long shift_by) |
| { |
| if(shift_by < 0) |
| error_message(NETLIST_ERROR, -1, -1, "requesting a shift left that is negative [%ld]\n",shift_by); |
| else if(shift_by >= ODIN_STD_BITWIDTH-1 ) |
| warning_message(NETLIST_ERROR, -1, -1, "requesting a shift left that will overflow the maximum size of %ld [%ld]\n", shift_by, ODIN_STD_BITWIDTH-1); |
| |
| return input_value << shift_by; |
| } |
| |
| std::string get_file_extension(std::string input_file) |
| { |
| auto dot_location = input_file.find_last_of('.'); |
| if( dot_location != std::string::npos ) |
| { |
| return input_file.substr(dot_location); |
| } |
| else |
| { |
| return ""; |
| } |
| } |
| |
| void create_directory(std::string path) |
| { |
| // CREATE OUTPUT DIRECTORY |
| int error_code = 0; |
| #ifdef WIN32 |
| error_code = mkdir(path.c_str()); |
| #else |
| error_code = mkdir(path.c_str(), 0755); |
| #endif |
| |
| if(error_code && errno != EEXIST) |
| { |
| error_message(PARSE_ERROR, -1, -1, "Odin Failed to create directory :%s with exit code%d\n", path.c_str(), errno); |
| } |
| } |
| |
| void assert_supported_file_extension(std::string input_file, int line_number, int file_number) |
| { |
| bool supported = false; |
| std::string extension = get_file_extension(input_file); |
| for(int i = 0; i< file_extension_supported_END && ! supported; i++) |
| { |
| supported = (extension == std::string(file_extension_supported_STR[i]) ); |
| } |
| |
| if(! supported) |
| { |
| std::string supported_extension_list = ""; |
| for(int i=0; i<file_extension_supported_END; i++) |
| { |
| supported_extension_list += " "; |
| supported_extension_list += file_extension_supported_STR[i]; |
| } |
| |
| possible_error_message(ARG_ERROR, line_number, file_number, |
| "File (%s) has an unsupported extension (%s), Odin only supports { %s }", |
| input_file.c_str(), |
| extension.c_str(), |
| supported_extension_list.c_str() |
| ); |
| } |
| } |
| |
| FILE *open_file(const char *file_name, const char *open_type) |
| { |
| FILE *opened_file = fopen(file_name, open_type); |
| if (opened_file == NULL) |
| { |
| error_message(ARG_ERROR, -1, -1, "cannot open file: %s\n", file_name); |
| } |
| return opened_file; |
| } |
| |
| /*--------------------------------------------------------------------------------------------- |
| * (function: name_based_on_op) |
| * Get the string version of an operation |
| *-------------------------------------------------------------------------------------------*/ |
| const char *name_based_on_op(operation_list op) |
| { |
| oassert(op < operation_list_END && |
| "OUT OF BOUND operation_list!"); |
| |
| return operation_list_STR[op][ODIN_STRING_TYPE]; |
| } |
| |
| /*--------------------------------------------------------------------------------------------- |
| * (function: name_based_on_ids) |
| * Get the string version of an operation |
| *-------------------------------------------------------------------------------------------*/ |
| const char *name_based_on_ids(ids op) |
| { |
| oassert(op < ids_END && |
| "OUT OF BOUND ids!"); |
| |
| return ids_STR[op]; |
| } |
| |
| /*--------------------------------------------------------------------------------------------- |
| * (function: node_name_based_on_op) |
| * Get the string version of a node |
| *-------------------------------------------------------------------------------------------*/ |
| const char *node_name_based_on_op(nnode_t *node) |
| { |
| return name_based_on_op(node->type); |
| } |
| |
| /*--------------------------------------------------------------------------------------------- |
| * (function: node_name_based_on_ids) |
| * Get the string version of a ast node |
| *-------------------------------------------------------------------------------------------*/ |
| const char *ast_node_name_based_on_ids(ast_node_t *node) |
| { |
| return name_based_on_ids(node->type); |
| } |
| |
| |
| /*-------------------------------------------------------------------------- |
| * (function: make_signal_name) |
| // return signal_name-bit |
| *------------------------------------------------------------------------*/ |
| char *make_signal_name(char *signal_name, int bit) |
| { |
| oassert(signal_name); |
| std::stringstream return_string; |
| return_string << signal_name; |
| if (bit != -1) |
| return_string << "-" << std::dec << bit; |
| |
| return vtr::strdup(return_string.str().c_str()); |
| } |
| |
| /*--------------------------------------------------------------------------------------------- |
| * (function: make_full_ref_name) |
| // {previous_string}.instance_name |
| // {previous_string}.instance_name^signal_name |
| // {previous_string}.instance_name^signal_name~bit |
| *-------------------------------------------------------------------------------------------*/ |
| char *make_full_ref_name(const char *previous, const char */*module_name*/, const char *module_instance_name, const char *signal_name, long bit) |
| { |
| |
| std::stringstream return_string; |
| if(previous) |
| return_string << previous; |
| |
| if(module_instance_name) |
| return_string << "." << module_instance_name; |
| |
| if(signal_name && (previous || module_instance_name)) |
| return_string << "^"; |
| |
| if(signal_name) |
| return_string << signal_name; |
| |
| if(bit != -1) |
| { |
| oassert(signal_name); |
| return_string << "~" << std::dec << bit ; |
| } |
| return vtr::strdup(return_string.str().c_str()); |
| } |
| |
| /*--------------------------------------------------------------------------------------------- |
| * (function: make_full_name_w_o_array_ref) |
| // {previous_string}.module_name+instance_name |
| *-------------------------------------------------------------------------------------------*/ |
| char *make_full_name_w_o_array_ref(const char *previous, const char */*module_name*/, const char *module_instance_name) |
| { |
| |
| std::stringstream return_string; |
| if(previous) |
| return_string << previous; |
| |
| if(module_instance_name) |
| return_string << "." << module_instance_name; |
| |
| |
| std::string name = return_string.str(); |
| |
| size_t idx = name.find_first_of('[', 0); |
| if (idx != std::string::npos) |
| { |
| // delete array refs |
| name.erase(idx, std::string::npos); |
| } |
| |
| return vtr::strdup(name.c_str()); |
| } |
| |
| /*--------------------------------------------------------------------------------------------- |
| * (function: twos_complement) |
| * Changes a bit string to its twos complement value |
| *-------------------------------------------------------------------------------------------*/ |
| char *twos_complement(char *str) |
| { |
| int length = strlen(str) - 1; |
| int i; |
| int flag = 0; |
| |
| for (i = length; i >= 0; i--) |
| { |
| if (flag) |
| str[i] = (str[i] == '1') ? '0' : '1'; |
| |
| if ((str[i] == '1') && (flag == 0)) |
| flag = 1; |
| } |
| return str; |
| } |
| |
| /* |
| * A wrapper for the other string to bit string conversion functions. |
| * Converts an arbitrary length string of base 16, 10, 8, or 2 to a |
| * string of 1s and 0s of the given length, padding or truncating |
| * the higher accordingly. The returned string will be little |
| * endian. Null will be returned if the radix is invalid. |
| * |
| * Base 10 strings will be limited in length to a long, but |
| * an error will be issued if the number will be truncated. |
| * |
| */ |
| char *convert_string_of_radix_to_bit_string(char *string, int radix, int binary_size) |
| { |
| if (radix == 16) |
| { |
| return convert_hex_string_of_size_to_bit_string(0, string, binary_size); |
| } |
| else if (radix == 10) |
| { |
| long number = convert_dec_string_of_size_to_long(string, binary_size); |
| return convert_long_to_bit_string(number, binary_size); |
| } |
| else if (radix == 8) |
| { |
| return convert_oct_string_of_size_to_bit_string(string, binary_size); |
| } |
| else if (radix == 2) |
| { |
| return convert_binary_string_of_size_to_bit_string(0, string, binary_size); |
| } |
| else |
| { |
| return NULL; |
| } |
| } |
| |
| /*--------------------------------------------------------------------------------------------- |
| * (function: convert_long_to_bit_string) |
| * Outputs a string msb to lsb. For example, 3 becomes "011" |
| *-------------------------------------------------------------------------------------------*/ |
| char *convert_long_to_bit_string(long orig_long, int num_bits) |
| { |
| int i; |
| char *return_val = (char*)malloc(sizeof(char)*(num_bits+1)); |
| int mask = 1; |
| |
| for (i = num_bits-1; i >= 0; i--) |
| { |
| if((mask & orig_long) > 0) { return_val[i] = '1'; } |
| else { return_val[i] = '0'; } |
| mask = mask << 1; |
| } |
| return_val[num_bits] = '\0'; |
| |
| return return_val; |
| } |
| |
| /* |
| * Turns the given little endian decimal string into a long. Throws an error if the |
| * string contains non-digits or is larger or smaller than the allowable range of long. |
| */ |
| long convert_dec_string_of_size_to_long(char *orig_string, int /*size*/) |
| { |
| if (!is_decimal_string(orig_string)) |
| error_message(PARSE_ERROR, -1, -1, "Invalid decimal number: %s.\n", orig_string); |
| |
| errno = 0; |
| long number = strtoll(orig_string, NULL, 10); |
| if (errno == ERANGE) |
| error_message(PARSE_ERROR, -1, -1, "This suspected decimal number (%s) is too long for Odin\n", orig_string); |
| |
| return number; |
| } |
| |
| long convert_string_of_radix_to_long(char *orig_string, int radix) |
| { |
| if (!is_string_of_radix(orig_string, radix)) |
| error_message(PARSE_ERROR, -1, -1, "Invalid base %d number: %s.\n", radix, orig_string); |
| |
| long number = strtoll(orig_string, NULL, radix); |
| if (number == LLONG_MAX || number == LLONG_MIN) |
| error_message(PARSE_ERROR, -1, -1, "This base %d number (%s) is too long for Odin\n", radix, orig_string); |
| |
| return number; |
| } |
| |
| int is_string_of_radix(char *string, int radix) |
| { |
| if (radix == 16) |
| return is_hex_string(string); |
| else if (radix == 10) |
| return is_decimal_string(string); |
| else if (radix == 8) |
| return is_octal_string(string); |
| else if (radix == 2) |
| return is_binary_string(string); |
| else |
| return false; |
| } |
| |
| /* |
| * Parses the given little endian hex string into a little endian bit string padded or truncated to |
| * binary_size bits. Throws an error if there are non-hex characters in the input string. |
| */ |
| char *convert_hex_string_of_size_to_bit_string(short is_dont_care_number, char *orig_string, int binary_size) |
| { |
| char *return_string = NULL; |
| if(is_dont_care_number == 0){ |
| if (!is_hex_string(orig_string)) |
| error_message(PARSE_ERROR, -1, -1, "Invalid hex number: %s.\n", orig_string); |
| |
| char *bit_string = (char *)vtr::calloc(1,sizeof(char)); |
| char *string = vtr::strdup(orig_string); |
| int size = strlen(string); |
| |
| // Change to big endian. (We want to add higher order bits at the end.) |
| reverse_string(string, size); |
| |
| int count = 0; |
| int i; |
| for (i = 0; i < size; i++) |
| { |
| char temp[] = {string[i],'\0'}; |
| |
| unsigned long value = strtoul(temp, NULL, 16); |
| int k; |
| for (k = 0; k < 4; k++) |
| { |
| char bit = value % 2; |
| value /= 2; |
| bit_string = (char *)vtr::realloc(bit_string, sizeof(char) * (count + 2)); |
| bit_string[count++] = '0' + bit; |
| bit_string[count] = '\0'; |
| } |
| } |
| vtr::free(string); |
| |
| // Pad with zeros to binary_size. |
| while (count < binary_size) |
| { |
| bit_string = (char *)vtr::realloc(bit_string, sizeof(char) * (count + 2)); |
| bit_string[count++] = '0'; |
| bit_string[count] = '\0'; |
| } |
| |
| // Truncate to binary_size |
| bit_string[binary_size] = '\0'; |
| // Change to little endian |
| reverse_string(bit_string, binary_size); |
| // Copy out only the bits before the truncation. |
| return_string = vtr::strdup(bit_string); |
| vtr::free(bit_string); |
| |
| } |
| else if(is_dont_care_number == 1){ |
| char *string = vtr::strdup(orig_string); |
| int size = strlen(string); |
| char *bit_string = (char *)vtr::calloc(1,sizeof(char)); |
| int count = 0; |
| int i; |
| for (i = 0; i < size; i++) |
| { |
| //char temp[] = {string[i],'\0'}; |
| |
| //unsigned long value = strtoul(temp, NULL, 16); |
| int k; |
| for (k = 0; k < 4; k++) |
| { |
| //char bit = value % 2; |
| //value /= 2; |
| bit_string = (char *)vtr::realloc(bit_string, sizeof(char) * (count + 2)); |
| bit_string[count++] = string[i]; |
| bit_string[count] = '\0'; |
| } |
| } |
| |
| vtr::free(string); |
| |
| while (count < binary_size) |
| { |
| bit_string = (char *)vtr::realloc(bit_string, sizeof(char) * (count + 2)); |
| bit_string[count++] = '0'; |
| bit_string[count] = '\0'; |
| } |
| |
| bit_string[binary_size] = '\0'; |
| |
| reverse_string(bit_string, binary_size); |
| |
| return_string = vtr::strdup(bit_string); |
| vtr::free(bit_string); |
| |
| |
| |
| // printf("bit_string %s",bit_string); |
| // getchar(); |
| |
| //printf("return_string %s", return_string); |
| //getchar(); |
| //return return_string; |
| |
| } |
| |
| return return_string; |
| } |
| |
| /* |
| * Parses the given little endian octal string into a little endian bit string padded or truncated to |
| * binary_size bits. Throws an error if the string contains non-octal digits. |
| */ |
| char *convert_oct_string_of_size_to_bit_string(char *orig_string, int binary_size) |
| { |
| if (!is_octal_string(orig_string)) |
| error_message(PARSE_ERROR, -1, -1, "Invalid octal number: %s.\n", orig_string); |
| |
| char *bit_string = (char *)vtr::calloc(1,sizeof(char)); |
| char *string = vtr::strdup(orig_string); |
| int size = strlen(string); |
| |
| // Change to big endian. (We want to add higher order bits at the end.) |
| reverse_string(string, size); |
| |
| int count = 0; |
| int i; |
| for (i = 0; i < size; i++) |
| { |
| char temp[] = {string[i],'\0'}; |
| |
| unsigned long value = strtoul(temp, NULL, 8); |
| int k; |
| for (k = 0; k < 3; k++) |
| { |
| char bit = value % 2; |
| value /= 2; |
| bit_string = (char *)vtr::realloc(bit_string, sizeof(char) * (count + 2)); |
| bit_string[count++] = '0' + bit; |
| bit_string[count] = '\0'; |
| } |
| } |
| vtr::free(string); |
| |
| // Pad with zeros to binary_size. |
| while (count < binary_size) |
| { |
| bit_string = (char *)vtr::realloc(bit_string, sizeof(char) * (count + 2)); |
| bit_string[count++] = '0'; |
| bit_string[count] = '\0'; |
| } |
| |
| // Truncate to binary_size |
| bit_string[binary_size] = '\0'; |
| // Change to little endian |
| reverse_string(bit_string, binary_size); |
| // Copy out only the bits before the truncation. |
| char *return_string = vtr::strdup(bit_string); |
| vtr::free(bit_string); |
| return return_string; |
| } |
| |
| /* |
| * Parses the given little endian bit string into a bit string padded or truncated to |
| * binary_size bits. |
| */ |
| char *convert_binary_string_of_size_to_bit_string(short is_dont_care_number, char *orig_string, int binary_size) |
| { |
| if (!is_binary_string(orig_string) && !is_dont_care_number) |
| error_message(PARSE_ERROR, -1, -1, "Invalid binary number: %s.\n", orig_string); |
| |
| int count = strlen(orig_string); |
| char *bit_string = (char *)vtr::calloc(count + 1, sizeof(char)); |
| |
| // Copy the original string into the buffer. |
| strcat(bit_string, orig_string); |
| |
| // Change to big endian. |
| reverse_string(bit_string, count); |
| |
| // Pad with zeros to binary_size. |
| while (count < binary_size) |
| { |
| bit_string = (char *)vtr::realloc(bit_string, sizeof(char) * (count + 2)); |
| bit_string[count++] = '0'; |
| bit_string[count] = '\0'; |
| } |
| |
| // Truncate to binary_size |
| bit_string[binary_size] = '\0'; |
| // Change to little endian |
| reverse_string(bit_string, binary_size); |
| // Copy out only the bits before the truncation. |
| char *return_string = vtr::strdup(bit_string); |
| vtr::free(bit_string); |
| return return_string; |
| } |
| |
| /* |
| * Returns true if the given string contains only '0' to '9' and 'a' through 'f' |
| */ |
| int is_hex_string(char *string) |
| { |
| unsigned int i; |
| for (i = 0; i < strlen(string); i++) |
| if (!((string[i] >= '0' && string[i] <= '9') || (tolower(string[i]) >= 'a' && tolower(string[i]) <= 'f'))) |
| return false; |
| |
| return true; |
| } |
| |
| /* |
| * Returns true if the given string contains only '0' to '9' and 'a' through 'f' |
| */ |
| int is_dont_care_string(char *string) |
| { |
| unsigned int i; |
| for (i = 0; i < strlen(string); i++) |
| if(string[i] != 'x') return false; |
| //if (!((string[i] >= '0' && string[i] <= '9') || (tolower(string[i]) >= 'a' && tolower(string[i]) <= 'f'))) |
| // return false; |
| |
| return true; |
| } |
| /* |
| * Returns true if the string contains only '0' to '9' |
| */ |
| int is_decimal_string(char *string) |
| { |
| unsigned int i; |
| for (i = 0; i < strlen(string); i++) |
| if (!(string[i] >= '0' && string[i] <= '9')) |
| return false; |
| |
| return true; |
| } |
| |
| /* |
| * Returns true if the string contains only '0' to '7' |
| */ |
| int is_octal_string(char *string) |
| { |
| unsigned int i; |
| for (i = 0; i < strlen(string); i++) |
| if (!(string[i] >= '0' && string[i] <= '7')) |
| return false; |
| |
| return true; |
| } |
| |
| /* |
| * Returns true if the string contains only '0's and '1's. |
| */ |
| int is_binary_string(char *string) |
| { |
| unsigned int i; |
| for (i = 0; i < strlen(string); i++) |
| if (!(string[i] >= '0' && string[i] <= '1')) |
| return false; |
| |
| return true; |
| } |
| |
| /* |
| * Gets the port name (everything after the ^ character) |
| * from the given name. Leaves the original name intact. |
| * Returns a copy of the original name if there is no |
| * ^ character present in the name. |
| */ |
| char *get_pin_name(char *name) |
| { // Remove everything before the ^ |
| if (strchr(name, '^')) |
| return vtr::strdup(strchr(name, '^') + 1); |
| else |
| return vtr::strdup(name); |
| } |
| |
| |
| /* |
| * Gets the port name (everything after the ^ and before the ~) |
| * from the given name. |
| */ |
| char *get_port_name(char *name) |
| { |
| // Remove everything before the ^ |
| char *port_name = get_pin_name(name); |
| // Find out if there is a ~ and remove everything after it. |
| char *tilde = strchr(port_name, '~'); |
| if (tilde) |
| *tilde = '\0'; |
| return port_name; |
| } |
| |
| /* |
| * Gets the pin number (the number after the ~) |
| * from the given name. |
| * |
| * Returns -1 if there is no ~. |
| */ |
| int get_pin_number(char *name) |
| { |
| // Grab the portion of the name ater the ^ |
| char *pin_name = get_pin_name(name); |
| char *tilde = strchr(pin_name, '~'); |
| // The pin number is everything after the ~ |
| int pin_number; |
| if (tilde) pin_number = strtol(tilde+1,NULL,10); |
| else pin_number = -1; |
| |
| vtr::free(pin_name); |
| return pin_number; |
| } |
| |
| /*--------------------------------------------------------------------------------------------- |
| * (function: my_power) |
| * My own simple power function |
| *-------------------------------------------------------------------------------------------*/ |
| long int my_power(long int x, long int y) |
| { |
| if (y == 0) |
| return 1; |
| |
| long int value = x; |
| int i; |
| for (i = 1; i < y; i++) |
| value *= x; |
| |
| return value; |
| } |
| |
| /*--------------------------------------------------------------------------------------------- |
| * (function: make_string_based_on_id ) |
| *-------------------------------------------------------------------------------------------*/ |
| char *make_string_based_on_id(nnode_t *node) |
| { |
| // any unique id greater than 20 characters means trouble |
| std::string return_string = std::string ("n") + std::to_string(node->unique_id); |
| |
| return vtr::strdup(return_string.c_str()); |
| } |
| |
| /*--------------------------------------------------------------------------------------------- |
| * (function: make_simple_name ) |
| *-------------------------------------------------------------------------------------------*/ |
| std::string make_simple_name(char *input, const char *flatten_string, char flatten_char) |
| { |
| oassert(input); |
| oassert(flatten_string); |
| |
| std::string input_str = input; |
| std::string flatten_str = flatten_string; |
| |
| for (int i = 0; i < flatten_str.length(); i++) |
| std::replace( input_str.begin(), input_str.end(), flatten_str[i], flatten_char); |
| |
| return input_str; |
| } |
| |
| /*----------------------------------------------------------------------- |
| * (function: my_malloc_struct ) |
| *-----------------------------------------------------------------*/ |
| void *my_malloc_struct(long bytes_to_alloc) |
| { |
| void *allocated = vtr::calloc(1, bytes_to_alloc); |
| static long int m_id = 0; |
| |
| // ways to stop the execution at the point when a specific structure is built...note it needs to be m_id - 1 ... it's unique_id in most data structures |
| //oassert(m_id != 193); |
| |
| if(allocated == NULL) |
| { |
| fprintf(stderr,"MEMORY FAILURE\n"); |
| oassert (0); |
| } |
| |
| /* mark the unique_id */ |
| *((long int*)allocated) = m_id++; |
| |
| return allocated; |
| } |
| |
| /*--------------------------------------------------------------------------------------------- |
| * (function: pow2 ) |
| *-------------------------------------------------------------------------------------------*/ |
| long int pow2(int to_the_power) |
| { |
| int i; |
| long int return_val = 1; |
| |
| for (i = 0; i < to_the_power; i++) |
| { |
| return_val = return_val << 1; |
| } |
| |
| return return_val; |
| } |
| |
| /* |
| * Changes the given string to upper case. |
| */ |
| void string_to_upper(char *string) |
| { |
| if (string) |
| { |
| unsigned int i; |
| for (i = 0; i < strlen(string); i++) |
| { |
| string[i] = toupper(string[i]); |
| } |
| } |
| } |
| |
| /* |
| * Changes the given string to lower case. |
| */ |
| void string_to_lower(char *string) |
| { |
| if (string) |
| { |
| unsigned int i; |
| for (i = 0; i < strlen(string); i++) |
| { |
| string[i] = tolower(string[i]); |
| } |
| } |
| } |
| |
| /* |
| * Returns a new string consisting of the original string |
| * plus the appendage. Leaves the original string |
| * intact. |
| * |
| * Handles format strings as well. |
| */ |
| char *append_string(const char *string, const char *appendage, ...) |
| { |
| char buffer[vtr::bufsize]; |
| |
| va_list ap; |
| |
| va_start(ap, appendage); |
| vsnprintf(buffer, vtr::bufsize * sizeof(char), appendage, ap); |
| va_end(ap); |
| |
| std::string new_string = std::string(string) + std::string(buffer); |
| return vtr::strdup(new_string.c_str()); |
| } |
| |
| /* |
| * Reverses the given string. (Reverses only 'length' |
| * chars from index 0 to length-1.) |
| */ |
| void reverse_string(char *string, int length) |
| { |
| int i = 0; |
| int j = length - 1; |
| while(i < j) |
| { |
| char temp = string[i]; |
| string[i++] = string [j]; |
| string[j--] = temp; |
| } |
| } |
| |
| /*--------------------------------------------------------------------------------------------- |
| * (function: to_bit) |
| *-------------------------------------------------------------------------------------------*/ |
| short get_bit(char in){ |
| if(in == 48 || in == 49) |
| return (short)in-48; |
| fprintf(stderr,"not a valid bit\n"); |
| return -1; |
| } |
| |
| /*--------------------------------------------------------------------------------------------- |
| * (function: to_bit) |
| *-------------------------------------------------------------------------------------------*/ |
| short get_bit(short in){ |
| if(in == 0 || in == 1) |
| return in; |
| fprintf(stderr,"not a valid bit\n"); |
| return -1; |
| } |
| |
| |
| void passed_verify_i_o_availabilty(nnode_t *node, int expected_input_size, int expected_output_size, const char *current_src, int line_src) { |
| if(!node) |
| error_message(SIMULATION_ERROR, -1, -1, "node unavailable @%s::%d", current_src, line_src); |
| |
| std::stringstream err_message; |
| int error=0; |
| |
| if(expected_input_size != -1 |
| && node->num_input_pins != expected_input_size) { |
| err_message << " input size is " << std::to_string(node->num_input_pins) << " expected 3:\n"; |
| for(int i=0; i< node->num_input_pins; i++) |
| err_message << "\t" << node->input_pins[0]->name << "\n"; |
| |
| error=1; |
| } |
| |
| if(expected_output_size != -1 |
| && node->num_output_pins != expected_output_size) { |
| err_message << " output size is " << std::to_string(node->num_output_pins) << " expected 1:\n"; |
| for(int i=0; i< node->num_output_pins; i++) |
| err_message << "\t" << node->output_pins[0]->name << "\n"; |
| |
| error=1; |
| } |
| |
| if(error) |
| error_message(SIMULATION_ERROR, -1, -1, "failed for %s:%s %s\n",node_name_based_on_op(node), node->name, err_message.str().c_str()); |
| } |
| |
| |
| /* |
| Search and replace a string keeping original string intact |
| */ |
| char *search_replace(char *src, const char *sKey, const char *rKey, int flag) |
| { |
| std::string tmp; |
| char *line; |
| line = vtr::strdup(src); |
| tmp = line; |
| switch(flag) |
| { |
| case 1: |
| tmp = vtr::replace_first(tmp,sKey,rKey); |
| odin_sprintf(line,"%s",tmp.c_str()); |
| break; |
| case 2: |
| tmp = vtr::replace_all(tmp,sKey,rKey); |
| odin_sprintf(line,"%s",tmp.c_str()); |
| break; |
| default: |
| return line; |
| } |
| return line; |
| } |
| std::string find_substring(char *src,const char *sKey,int flag) |
| { |
| // flag == 1 first half, flag == 2 second half |
| |
| std::string tmp(src); |
| std::string key(sKey); |
| long found = tmp.find(key); |
| switch(flag) |
| { |
| case 1: |
| return tmp.substr(0,found-1); |
| |
| case 2: |
| return tmp.substr(found,tmp.length()); |
| |
| default: |
| return tmp; |
| } |
| } |
| |
| /* |
| * Prints the time in appropriate units. |
| */ |
| void print_time(double time) |
| { |
| if (time > 24*3600) printf("%.1fd", time/(24*3600.0)); |
| else if (time > 3600) printf("%.1fh", time/3600.0); |
| else if (time > 60) printf("%.1fm", time/60.0); |
| else if (time > 1) printf("%.1fs", time); |
| else printf("%.1fms", time*1000); |
| } |
| |
| /* |
| * Gets the current time in seconds. |
| */ |
| double wall_time() |
| { |
| auto time_point = std::chrono::system_clock::now(); |
| std::chrono::duration<double> time_since_epoch = time_point.time_since_epoch(); |
| |
| return time_since_epoch.count(); |
| } |
| |
| /* |
| * Prints/updates an ASCII progress bar of length "length" to position length * completion |
| * from previous position "position". Updates ETA based on the elapsed time "time". |
| * Returns the new position. If the position is unchanged the bar is not redrawn. |
| * |
| * Call with position = -1 to draw for the first time. Returns the new |
| * position, calculated based on completion. |
| */ |
| int print_progress_bar(double completion, int position, int length, double time) |
| { |
| if (position == -1 || ((int)(completion * length)) > position) |
| { |
| printf("%3.0f%%|", completion * (double)100); |
| |
| position = completion * length; |
| |
| int i; |
| for (i = 0; i < position; i++) |
| printf("="); |
| |
| printf(">"); |
| |
| for (; i < length; i++) |
| printf("-"); |
| |
| if (completion < 1.0) |
| { |
| printf("| Remaining: "); |
| double remaining_time = time/(double)completion - time; |
| print_time(remaining_time); |
| } |
| else |
| { |
| printf("| Total time: "); |
| print_time(time); |
| } |
| |
| printf(" \r"); |
| |
| if (position == length) |
| printf("\n"); |
| |
| fflush(stdout); |
| } |
| return position; |
| } |
| |
| /* |
| * Trims characters in the given "chars" string |
| * from the end of the given string. |
| */ |
| void trim_string(char* string, const char *chars) |
| { |
| if (string) |
| { |
| int length; |
| while((length = strlen(string))) |
| { |
| bool trimmed = false; |
| unsigned int i; |
| for (i = 0; i < strlen(chars); i++) |
| { |
| if (string[length-1] == chars[i]) |
| { |
| trimmed = true; |
| string[length-1] = '\0'; |
| break; |
| } |
| } |
| |
| if (!trimmed) |
| break; |
| } |
| } |
| } |
| |
| /** |
| * verifies only one condition evaluates to true |
| */ |
| bool only_one_is_true(std::vector<bool> tested) |
| { |
| bool previous_value = false; |
| for(bool next_value: tested) |
| { |
| if(!previous_value && next_value) |
| previous_value = true; |
| else if(previous_value && next_value) |
| return false; |
| } |
| return previous_value; |
| } |
| |
| /** |
| * This overrides default sprintf since odin uses sprintf to concatenate strings |
| * sprintf has undefined behavior for such and this prevents string overriding if |
| * it is also given as an input |
| */ |
| int odin_sprintf (char *s, const char *format, ...) |
| { |
| va_list args, args_copy ; |
| va_start( args, format ) ; |
| va_copy( args_copy, args ) ; |
| |
| const auto sz = std::vsnprintf( nullptr, 0, format, args ) + 1 ; |
| |
| try |
| { |
| std::string temp( sz, ' ' ) ; |
| std::vsnprintf( &temp.front(), sz, format, args_copy ) ; |
| va_end(args_copy) ; |
| va_end(args) ; |
| |
| s = strncpy(s, temp.c_str(),temp.length()); |
| |
| return temp.length(); |
| |
| } |
| catch( const std::bad_alloc& ) |
| { |
| va_end(args_copy) ; |
| va_end(args) ; |
| return -1; |
| } |
| |
| } |
| |