| #include <string.h> |
| #include <assert.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <stdarg.h> |
| #include <errno.h> |
| #include "util.h" |
| #include "log.h" |
| |
| /* This file contains utility functions widely used in * |
| * my programs. Many are simply versions of file and * |
| * memory grabbing routines that take the same * |
| * arguments as the standard library ones, but exit * |
| * the program if they find an error condition. */ |
| |
| static int file_line_number = 0; /* file in line number being parsed */ |
| char *out_file_prefix = NULL; |
| vpr_PrintHandlerInfo vpr_printf_info = log_print_info; |
| vpr_PrintHandlerWarning vpr_printf_warning = log_print_warning; |
| vpr_PrintHandlerError vpr_printf_error = log_print_error; |
| vpr_PrintHandlerDirect vpr_printf_direct = log_print_direct; |
| |
| static int cont; /* line continued? */ |
| |
| /* Returns the min of cur and max. If cur > max, a warning |
| * is emitted. */ |
| int limit_value(int cur, int max, const char *name) { |
| if (cur > max) { |
| vpr_printf_warning(__FILE__, __LINE__, |
| "%s is being limited from [%d] to [%d]\n", name, cur, max); |
| return max; |
| } |
| return cur; |
| } |
| |
| /* An alternate for strncpy since strncpy doesn't work as most |
| * people would expect. This ensures null termination */ |
| char *my_strncpy(char *dest, const char *src, size_t size) { |
| /* Find string's length */ |
| size_t len = strlen(src); |
| |
| /* Cap length at (num - 1) to leave room for \0 */ |
| if (size <= len) |
| len = (size - 1); |
| |
| /* Copy as much of string as we can fit */ |
| memcpy(dest, src, len); |
| |
| /* explicit null termination */ |
| dest[len] = '\0'; |
| |
| return dest; |
| } |
| |
| /* Uses global var 'out_file_prefix' */ |
| FILE *my_fopen(const char *fname, const char *flag, int prompt) { |
| FILE *fp; |
| size_t Len; |
| char *new_fname = NULL; |
| char prompt_filename[256]; |
| |
| file_line_number = 0; |
| |
| /* Appends a prefix string for output files */ |
| if (out_file_prefix) { |
| if (strchr(flag, 'w')) { |
| Len = 1; /* NULL char */ |
| Len += strlen(out_file_prefix); |
| Len += strlen(fname); |
| new_fname = (char *) my_malloc(Len * sizeof(char)); |
| strcpy(new_fname, out_file_prefix); |
| strcat(new_fname, fname); |
| fname = new_fname; |
| } |
| } |
| |
| if (prompt) { |
| int check_num_of_entered_values = scanf("%s", prompt_filename); |
| while (getchar() != '\n') |
| ; |
| |
| while (check_num_of_entered_values != 1) { |
| vpr_printf_error(__FILE__, __LINE__, |
| "Was expecting one file name to be entered, with no spaces. You have entered %d parameters. Please try again: \n", |
| check_num_of_entered_values); |
| check_num_of_entered_values = scanf("%s", prompt_filename); |
| } |
| fname = prompt_filename; |
| } |
| |
| if (NULL == (fp = fopen(fname, flag))) { |
| vpr_throw(VPR_ERROR_UNKNOWN, __FILE__, __LINE__, |
| "Error opening file %s for %s access: %s.\n", fname, flag, strerror(errno)); |
| } |
| |
| if (new_fname) |
| free(new_fname); |
| |
| return (fp); |
| } |
| |
| char *my_strdup(const char *str) { |
| size_t Len; |
| char *Dst; |
| |
| if (str == NULL ) { |
| return NULL ; |
| } |
| |
| Len = 1 + strlen(str); |
| Dst = (char *) my_malloc(Len * sizeof(char)); |
| memcpy(Dst, str, Len); |
| |
| return Dst; |
| } |
| |
| int my_atoi(const char *str) { |
| |
| /* Returns the integer represented by the first part of the character * |
| * string. */ |
| |
| if (str[0] < '0' || str[0] > '9') { |
| if (!(str[0] == '-' && str[1] >= '0' && str[1] <= '9')) { |
| vpr_throw(VPR_ERROR_UNKNOWN, __FILE__, __LINE__, |
| "expected number instead of '%s'.\n", str); |
| } |
| } |
| return (atoi(str)); |
| } |
| |
| void *my_calloc_impl(size_t nelem, size_t size, const char* const file, const int line) { |
| void *ret; |
| if (nelem == 0) { |
| return NULL ; |
| } |
| |
| if ((ret = calloc(nelem, size)) == NULL ) { |
| vpr_throw(VPR_ERROR_UNKNOWN, file, line, |
| "Error: Unable to calloc memory. Aborting.\n"); |
| } |
| return (ret); |
| } |
| |
| void *my_malloc_impl(size_t size, const char* const file, const int line) { |
| void *ret; |
| if (size == 0) { |
| return NULL ; |
| } |
| |
| if ((ret = malloc(size)) == NULL ) { |
| vpr_throw(VPR_ERROR_UNKNOWN, file, line, |
| "Error: Unable to malloc memory. Aborting.\n"); |
| } |
| return (ret); |
| } |
| |
| void *my_realloc_impl(void *ptr, size_t size, const char* const file, const int line) { |
| void *ret; |
| |
| if (size <= 0) { |
| vpr_printf_warning(file, line, |
| "reallocating of size <= 0.\n"); |
| } |
| |
| ret = realloc(ptr, size); |
| if (NULL == ret) { |
| vpr_printf_error(file, line, |
| "Unable to realloc memory. Aborting. " |
| "ptr=%p, Size=%d.\n", ptr, (int) size); |
| if (ptr == NULL ) { |
| vpr_printf_error(file, line, |
| "my_realloc: ptr == NULL. Aborting.\n"); |
| } |
| vpr_throw(VPR_ERROR_UNKNOWN, file, line, |
| "Unable to realloc memory. Aborting. ptr=%p, Size=%d.\n", ptr, (int) size); |
| } |
| return (ret); |
| } |
| |
| void *my_chunk_malloc(size_t size, t_chunk *chunk_info) { |
| |
| /* This routine should be used for allocating fairly small data * |
| * structures where memory-efficiency is crucial. This routine allocates * |
| * large "chunks" of data, and parcels them out as requested. Whenever * |
| * it mallocs a new chunk it adds it to the linked list pointed to by * |
| * chunk_info->chunk_ptr_head. This list can be used to free the * |
| * chunked memory. * |
| * Information about the currently open "chunk" must be stored by the * |
| * user program. chunk_info->mem_avail_ptr points to an int storing * |
| * how many bytes are left in the current chunk, while * |
| * chunk_info->next_mem_loc_ptr is the address of a pointer to the * |
| * next free bytes in the chunk. To start a new chunk, simply set * |
| * chunk_info->mem_avail_ptr = 0. Each independent set of data * |
| * structures should use a new chunk. */ |
| |
| /* To make sure the memory passed back is properly aligned, I must * |
| * only send back chunks in multiples of the worst-case alignment * |
| * restriction of the machine. On most machines this should be * |
| * a long, but on 64-bit machines it might be a long long or a * |
| * double. Change the typedef below if this is the case. */ |
| |
| typedef long Align; |
| |
| #define CHUNK_SIZE 32768 |
| #define FRAGMENT_THRESHOLD 100 |
| |
| char *tmp_ptr; |
| int aligned_size; |
| |
| assert(chunk_info->mem_avail >= 0); |
| |
| if ((size_t) (chunk_info->mem_avail) < size) { /* Need to malloc more memory. */ |
| if (size > CHUNK_SIZE) { /* Too big, use standard routine. */ |
| tmp_ptr = (char *) my_malloc(size); |
| |
| /* When debugging, uncomment the code below to see if memory allocation size */ |
| /* makes sense */ |
| /*#ifdef DEBUG |
| vpr_printf("NB: my_chunk_malloc got a request for %d bytes.\n", size); |
| vpr_printf("You should consider using my_malloc for such big requests.\n"); |
| #endif */ |
| |
| assert(chunk_info != NULL); |
| chunk_info->chunk_ptr_head = insert_in_vptr_list( |
| chunk_info->chunk_ptr_head, tmp_ptr); |
| return (tmp_ptr); |
| } |
| |
| if (chunk_info->mem_avail < FRAGMENT_THRESHOLD) { /* Only a small scrap left. */ |
| chunk_info->next_mem_loc_ptr = (char *) my_malloc(CHUNK_SIZE); |
| chunk_info->mem_avail = CHUNK_SIZE; |
| assert(chunk_info != NULL); |
| chunk_info->chunk_ptr_head = insert_in_vptr_list( |
| chunk_info->chunk_ptr_head, chunk_info->next_mem_loc_ptr); |
| } |
| |
| /* Execute else clause only when the chunk we want is pretty big, * |
| * and would leave too big an unused fragment. Then we use malloc * |
| * to allocate normally. */ |
| |
| else { |
| tmp_ptr = (char *) my_malloc(size); |
| assert(chunk_info != NULL); |
| chunk_info->chunk_ptr_head = insert_in_vptr_list( |
| chunk_info->chunk_ptr_head, tmp_ptr); |
| return (tmp_ptr); |
| } |
| } |
| |
| /* Find the smallest distance to advance the memory pointer and keep * |
| * everything aligned. */ |
| |
| if (size % sizeof(Align) == 0) { |
| aligned_size = size; |
| } else { |
| aligned_size = size + sizeof(Align) - size % sizeof(Align); |
| } |
| |
| tmp_ptr = chunk_info->next_mem_loc_ptr; |
| chunk_info->next_mem_loc_ptr += aligned_size; |
| chunk_info->mem_avail -= aligned_size; |
| return (tmp_ptr); |
| } |
| |
| void free_chunk_memory(t_chunk *chunk_info) { |
| |
| /* Frees the memory allocated by a sequence of calls to my_chunk_malloc. */ |
| |
| struct s_linked_vptr *curr_ptr, *prev_ptr; |
| |
| curr_ptr = chunk_info->chunk_ptr_head; |
| |
| while (curr_ptr != NULL ) { |
| free(curr_ptr->data_vptr); /* Free memory "chunk". */ |
| prev_ptr = curr_ptr; |
| curr_ptr = curr_ptr->next; |
| free(prev_ptr); /* Free memory used to track "chunk". */ |
| } |
| chunk_info->chunk_ptr_head = NULL; |
| chunk_info->mem_avail = 0; |
| chunk_info->next_mem_loc_ptr = NULL; |
| } |
| |
| struct s_linked_vptr *insert_in_vptr_list(struct s_linked_vptr *head, void *vptr_to_add) { |
| |
| /* Inserts a new element at the head of a linked list of void pointers. * |
| * Returns the new head of the list. */ |
| |
| struct s_linked_vptr *linked_vptr; |
| |
| linked_vptr = (struct s_linked_vptr *) my_malloc( |
| sizeof(struct s_linked_vptr)); |
| |
| linked_vptr->data_vptr = vptr_to_add; |
| linked_vptr->next = head; |
| return (linked_vptr); /* New head of the list */ |
| } |
| |
| /* Deletes the element at the head of a linked list of void pointers. * |
| * Returns the new head of the list. */ |
| struct s_linked_vptr *delete_in_vptr_list(struct s_linked_vptr *head) { |
| struct s_linked_vptr *linked_vptr; |
| |
| if (head == NULL ) |
| return NULL ; |
| linked_vptr = head->next; |
| free(head); |
| return linked_vptr; /* New head of the list */ |
| } |
| |
| t_linked_int *insert_in_int_list(t_linked_int * head, int data, |
| t_linked_int ** free_list_head_ptr) { |
| |
| /* Inserts a new element at the head of a linked list of integers. Returns * |
| * the new head of the list. One argument is the address of the head of * |
| * a list of free ilist elements. If there are any elements on this free * |
| * list, the new element is taken from it. Otherwise a new one is malloced. */ |
| |
| t_linked_int *linked_int; |
| |
| if (*free_list_head_ptr != NULL ) { |
| linked_int = *free_list_head_ptr; |
| *free_list_head_ptr = linked_int->next; |
| } else { |
| linked_int = (t_linked_int *) my_malloc(sizeof(t_linked_int)); |
| } |
| |
| linked_int->data = data; |
| linked_int->next = head; |
| return (linked_int); |
| } |
| |
| void free_int_list(t_linked_int ** int_list_head_ptr) { |
| |
| /* This routine truly frees (calls free) all the integer list elements * |
| * on the linked list pointed to by *head, and sets head = NULL. */ |
| |
| t_linked_int *linked_int, *next_linked_int; |
| |
| linked_int = *int_list_head_ptr; |
| |
| while (linked_int != NULL ) { |
| next_linked_int = linked_int->next; |
| free(linked_int); |
| linked_int = next_linked_int; |
| } |
| |
| *int_list_head_ptr = NULL; |
| } |
| |
| void alloc_ivector_and_copy_int_list(t_linked_int ** list_head_ptr, |
| int num_items, struct s_ivec *ivec, t_linked_int ** free_list_head_ptr) { |
| |
| /* Allocates an integer vector with num_items elements and copies the * |
| * integers from the list pointed to by list_head (of which there must be * |
| * num_items) over to it. The int_list is then put on the free list, and * |
| * the list_head_ptr is set to NULL. */ |
| |
| t_linked_int *linked_int, *list_head; |
| int i, *list; |
| |
| list_head = *list_head_ptr; |
| |
| if (num_items == 0) { /* Empty list. */ |
| ivec->nelem = 0; |
| ivec->list = NULL; |
| |
| if (list_head != NULL ) { |
| vpr_throw(VPR_ERROR_UNKNOWN, __FILE__, __LINE__, |
| "alloc_ivector_and_copy_int_list: Copied %d elements, " |
| "but list at %p contains more.\n", num_items, |
| (void *) list_head); |
| } |
| return; |
| } |
| |
| ivec->nelem = num_items; |
| list = (int *) my_malloc(num_items * sizeof(int)); |
| ivec->list = list; |
| linked_int = list_head; |
| |
| for (i = 0; i < num_items - 1; i++) { |
| list[i] = linked_int->data; |
| linked_int = linked_int->next; |
| } |
| |
| list[num_items - 1] = linked_int->data; |
| |
| if (linked_int->next != NULL ) { |
| vpr_throw(VPR_ERROR_UNKNOWN, __FILE__, __LINE__, |
| "Error in alloc_ivector_and_copy_int_list:\n Copied %d elements, " |
| "but list at %p contains more.\n", num_items, |
| (void *) list_head); |
| } |
| |
| linked_int->next = *free_list_head_ptr; |
| *free_list_head_ptr = list_head; |
| *list_head_ptr = NULL; |
| } |
| |
| char *my_fgets(char *buf, int max_size, FILE * fp) { |
| /* Get an input line, update the line number and cut off * |
| * any comment part. A \ at the end of a line with no * |
| * comment part (#) means continue. my_fgets should give * |
| * identical results for Windows (\r\n) and Linux (\n) * |
| * newlines, since it replaces each carriage return \r * |
| * by a newline character \n. Returns NULL after EOF. */ |
| |
| char ch; |
| int i; |
| |
| cont = 0; /* line continued? */ |
| file_line_number++; /* global variable */ |
| |
| for (i = 0; i < max_size - 1; i++) { /* Keep going until the line finishes or the buffer is full */ |
| |
| ch = fgetc(fp); |
| |
| if (feof(fp)) { /* end of file */ |
| if (i == 0) { |
| return NULL ; /* required so we can write while (my_fgets(...) != NULL) */ |
| } else { /* no newline before end of file - last line must be returned */ |
| buf[i] = '\0'; |
| return buf; |
| } |
| } |
| |
| if (ch == '#') { /* comment */ |
| buf[i] = '\0'; |
| while ((ch = fgetc(fp)) != '\n' && !feof(fp)) |
| ; /* skip the rest of the line */ |
| return buf; |
| } |
| |
| if (ch == '\r' || ch == '\n') { /* newline (cross-platform) */ |
| if (i != 0 && buf[i - 1] == '\\') { /* if \ at end of line, line continued */ |
| cont = 1; |
| buf[i - 1] = '\n'; /* May need this for tokens */ |
| buf[i] = '\0'; |
| } else { |
| buf[i] = '\n'; |
| buf[i + 1] = '\0'; |
| } |
| return buf; |
| } |
| |
| buf[i] = ch; /* copy character into the buffer */ |
| |
| } |
| |
| /* Buffer is full but line has not terminated, so error */ |
| vpr_throw(VPR_ERROR_UNKNOWN, __FILE__, __LINE__, |
| "Error on line %d -- line is too long for input buffer.\n" |
| "All lines must be at most %d characters long.\n", |
| file_line_number, BUFSIZE - 2); |
| return NULL; |
| } |
| |
| char *my_strtok(char *ptr, const char *tokens, FILE * fp, char *buf) { |
| |
| /* Get next token, and wrap to next line if \ at end of line. * |
| * There is a bit of a "gotcha" in strtok. It does not make a * |
| * copy of the character array which you pass by pointer on the * |
| * first call. Thus, you must make sure this array exists for * |
| * as long as you are using strtok to parse that line. Don't * |
| * use local buffers in a bunch of subroutines calling each * |
| * other; the local buffer may be overwritten when the stack is * |
| * restored after return from the subroutine. */ |
| |
| char *val; |
| |
| val = strtok(ptr, tokens); |
| for (;;) { |
| if (val != NULL || cont == 0) |
| return (val); |
| |
| /* return unless we have a null value and a continuation line */ |
| if (my_fgets(buf, BUFSIZE, fp) == NULL ) |
| return (NULL ); |
| |
| val = strtok(buf, tokens); |
| } |
| } |
| |
| void free_ivec_vector(struct s_ivec *ivec_vector, int nrmin, int nrmax) { |
| |
| /* Frees a 1D array of integer vectors. */ |
| |
| int i; |
| |
| for (i = nrmin; i <= nrmax; i++) |
| if (ivec_vector[i].nelem != 0) |
| free(ivec_vector[i].list); |
| |
| free(ivec_vector + nrmin); |
| } |
| |
| void free_ivec_matrix(struct s_ivec **ivec_matrix, int nrmin, int nrmax, |
| int ncmin, int ncmax) { |
| |
| /* Frees a 2D matrix of integer vectors (ivecs). */ |
| |
| int i, j; |
| |
| for (i = nrmin; i <= nrmax; i++) { |
| for (j = ncmin; j <= ncmax; j++) { |
| if (ivec_matrix[i][j].nelem != 0) { |
| free(ivec_matrix[i][j].list); |
| } |
| } |
| } |
| |
| free_matrix(ivec_matrix, nrmin, nrmax, ncmin, sizeof(struct s_ivec)); |
| } |
| |
| void free_ivec_matrix3(struct s_ivec ***ivec_matrix3, int nrmin, int nrmax, |
| int ncmin, int ncmax, int ndmin, int ndmax) { |
| |
| /* Frees a 3D matrix of integer vectors (ivecs). */ |
| |
| int i, j, k; |
| |
| for (i = nrmin; i <= nrmax; i++) { |
| for (j = ncmin; j <= ncmax; j++) { |
| for (k = ndmin; k <= ndmax; k++) { |
| if (ivec_matrix3[i][j][k].nelem != 0) { |
| free(ivec_matrix3[i][j][k].list); |
| } |
| } |
| } |
| } |
| |
| free_matrix3(ivec_matrix3, nrmin, nrmax, ncmin, ncmax, ndmin, |
| sizeof(struct s_ivec)); |
| } |
| |
| void **alloc_matrix(int nrmin, int nrmax, int ncmin, int ncmax, size_t elsize) { |
| |
| /* allocates an generic matrix with nrmax-nrmin + 1 rows and ncmax - * |
| * ncmin + 1 columns, with each element of size elsize. i.e. * |
| * returns a pointer to a storage block [nrmin..nrmax][ncmin..ncmax].* |
| * Simply cast the returned array pointer to the proper type. */ |
| |
| int i; |
| char **cptr; |
| |
| cptr = (char **) my_malloc((nrmax - nrmin + 1) * sizeof(char *)); |
| cptr -= nrmin; |
| for (i = nrmin; i <= nrmax; i++) { |
| cptr[i] = (char *) my_malloc((ncmax - ncmin + 1) * elsize); |
| cptr[i] -= ncmin * elsize / sizeof(char); /* sizeof(char) = 1 */ |
| } |
| return ((void **) cptr); |
| } |
| |
| void ***alloc_matrix3(int nrmin, int nrmax, int ncmin, int ncmax, int ndmin, int ndmax, |
| size_t elsize) { |
| |
| /* allocates a 3D generic matrix with nrmax-nrmin + 1 rows, ncmax - * |
| * ncmin + 1 columns, and a depth of ndmax-ndmin + 1, with each * |
| * element of size elsize. i.e. returns a pointer to a storage block * |
| * [nrmin..nrmax][ncmin..ncmax][ndmin..ndmax]. Simply cast the * |
| * returned array pointer to the proper type. */ |
| |
| int i, j; |
| char ***cptr; |
| |
| cptr = (char ***) my_malloc((nrmax - nrmin + 1) * sizeof(char **)); |
| cptr -= nrmin; |
| for (i = nrmin; i <= nrmax; i++) { |
| cptr[i] = (char **) my_malloc((ncmax - ncmin + 1) * sizeof(char *)); |
| cptr[i] -= ncmin; |
| for (j = ncmin; j <= ncmax; j++) { |
| cptr[i][j] = (char *) my_malloc((ndmax - ndmin + 1) * elsize); |
| cptr[i][j] -= ndmin * elsize / sizeof(char); /* sizeof(char) = 1) */ |
| } |
| } |
| return ((void ***) cptr); |
| } |
| |
| void ****alloc_matrix4(int nrmin, int nrmax, int ncmin, int ncmax, int ndmin, int ndmax, |
| int nemin, int nemax, size_t elsize) { |
| |
| /* allocates a 3D generic matrix with nrmax-nrmin + 1 rows, ncmax - * |
| * ncmin + 1 columns, and a depth of ndmax-ndmin + 1, with each * |
| * element of size elsize. i.e. returns a pointer to a storage block * |
| * [nrmin..nrmax][ncmin..ncmax][ndmin..ndmax]. Simply cast the * |
| * returned array pointer to the proper type. */ |
| |
| int i; |
| char ****cptr; |
| |
| cptr = (char ****) my_malloc((nrmax - nrmin + 1) * sizeof(char ***)); |
| cptr -= nrmin; |
| for (i = nrmin; i <= nrmax; i++) { |
| cptr[i] = (char ***) alloc_matrix3 (ncmin, ncmax, ndmin, ndmax, nemin, nemax, elsize); |
| } |
| return ((void ****) cptr); |
| } |
| |
| void *****alloc_matrix5(int nrmin, int nrmax, int ncmin, int ncmax, int ndmin, int ndmax, |
| int nemin, int nemax, int nfmin, int nfmax, size_t elsize) { |
| |
| int i; |
| char *****cptr; |
| |
| cptr = (char *****) my_malloc((nrmax - nrmin + 1) * sizeof(char ***)); |
| cptr -= nrmin; |
| for (i = nrmin; i <= nrmax; i++) { |
| cptr[i] = (char ****) alloc_matrix4 (ncmin, ncmax, ndmin, ndmax, nemin, nemax, nfmin, nfmax, elsize); |
| } |
| return ((void *****) cptr); |
| } |
| |
| void print_int_matrix3(int ***vptr, int nrmin, int nrmax, int ncmin, int ncmax, |
| int ndmin, int ndmax, char *file) { |
| FILE *outfile; |
| int i, j, k; |
| |
| outfile = my_fopen(file, "w", 0); |
| |
| for (k = nrmin; k <= nrmax; ++k) { |
| fprintf(outfile, "Plane %d\n", k); |
| for (j = ncmin; j <= ncmax; ++j) { |
| for (i = ndmin; i <= ndmax; ++i) { |
| fprintf(outfile, "%d ", vptr[k][j][i]); |
| } |
| fprintf(outfile, "\n"); |
| } |
| fprintf(outfile, "\n"); |
| } |
| |
| fclose(outfile); |
| } |
| |
| /* NB: need to make the pointer type void * instead of void ** to allow * |
| * any pointer to be passed in without a cast. */ |
| |
| void free_matrix(void *vptr, int nrmin, int nrmax, int ncmin, size_t elsize) { |
| int i; |
| char **cptr; |
| |
| cptr = (char **) vptr; |
| |
| for (i = nrmin; i <= nrmax; i++) |
| free(cptr[i] + ncmin * elsize / sizeof(char)); |
| free(cptr + nrmin); |
| } |
| |
| void free_matrix3(void *vptr, int nrmin, int nrmax, int ncmin, int ncmax, |
| int ndmin, size_t elsize) { |
| int i, j; |
| char ***cptr; |
| |
| cptr = (char ***) vptr; |
| |
| for (i = nrmin; i <= nrmax; i++) { |
| for (j = ncmin; j <= ncmax; j++) |
| free(cptr[i][j] + ndmin * elsize / sizeof(char)); |
| free(cptr[i] + ncmin); |
| } |
| free(cptr + nrmin); |
| } |
| |
| void free_matrix4(void *vptr, int nrmin, int nrmax, int ncmin, int ncmax, |
| int ndmin, int ndmax, int nemin, size_t elsize) { |
| int i; |
| char ****cptr; |
| |
| cptr = (char ****) vptr; |
| |
| for (i = nrmin; i <= nrmax; i++) { |
| free_matrix3 (cptr[i], ncmin, ncmax, ndmin, ndmax, nemin, elsize); |
| } |
| free(cptr + nrmin); |
| } |
| |
| void free_matrix5(void *vptr, int nrmin, int nrmax, int ncmin, int ncmax, |
| int ndmin, int ndmax, int nemin, int nemax, int nfmin, size_t elsize) { |
| int i; |
| char ****cptr; |
| |
| cptr = (char ****) vptr; |
| |
| for (i = nrmin; i <= nrmax; i++) { |
| free_matrix4 (cptr[i], ncmin, ncmax, ndmin, ndmax, nemin, nemax, nfmin, elsize); |
| } |
| free(cptr + nrmin); |
| } |
| |
| /* Portable random number generator defined below. Taken from ANSI C by * |
| * K & R. Not a great generator, but fast, and good enough for my needs. */ |
| |
| #define IA 1103515245u |
| #define IC 12345u |
| #define IM 2147483648u |
| #define CHECK_RAND |
| |
| static unsigned int current_random = 0; |
| |
| void my_srandom(int seed) { |
| current_random = (unsigned int) seed; |
| } |
| |
| /* returns the current_random value */ |
| unsigned int get_current_random(){ |
| unsigned int result = current_random; |
| return result; |
| } |
| |
| int my_irand(int imax) { |
| |
| /* Creates a random integer between 0 and imax, inclusive. i.e. [0..imax] */ |
| |
| int ival; |
| |
| /* current_random = (current_random * IA + IC) % IM; */ |
| current_random = current_random * IA + IC; /* Use overflow to wrap */ |
| ival = current_random & (IM - 1); /* Modulus */ |
| ival = (int) ((float) ival * (float) (imax + 0.999) / (float) IM); |
| |
| #ifdef CHECK_RAND |
| if ((ival < 0) || (ival > imax)) { |
| if (ival == imax + 1) { |
| /* Due to random floating point rounding, sometimes above calculation gives number greater than ival by 1 */ |
| ival = imax; |
| } else { |
| vpr_throw(VPR_ERROR_UNKNOWN, __FILE__, __LINE__, |
| "Bad value in my_irand, imax = %d ival = %d\n", imax, ival); |
| } |
| } |
| #endif |
| |
| return (ival); |
| } |
| |
| float my_frand(void) { |
| |
| /* Creates a random float between 0 and 1. i.e. [0..1). */ |
| |
| float fval; |
| int ival; |
| |
| current_random = current_random * IA + IC; /* Use overflow to wrap */ |
| ival = current_random & (IM - 1); /* Modulus */ |
| fval = (float) ival / (float) IM; |
| |
| #ifdef CHECK_RAND |
| if ((fval < 0) || (fval > 1.)) { |
| vpr_throw(VPR_ERROR_UNKNOWN, __FILE__, __LINE__, |
| "Bad value in my_frand, fval = %g\n", fval); |
| } |
| #endif |
| |
| return (fval); |
| } |
| |
| bool file_exists(const char * filename) { |
| FILE * file; |
| |
| if (filename == NULL ) { |
| return false; |
| } |
| |
| file = fopen(filename, "r"); |
| if (file) { |
| fclose(file); |
| return true; |
| } |
| return false; |
| } |
| |
| int ipow(int base, int exp) { |
| int result = 1; |
| |
| assert(exp >= 0); |
| |
| while (exp) { |
| if (exp & 1) |
| result *= base; |
| exp >>= 1; |
| base *= base; |
| } |
| return result; |
| } |
| |
| /* Author: Daniel Chen */ |
| /* Allocate and load partial data into t_vpr_error structure */ |
| /* Note: can also set breakpoint in this function to view callstack prior * |
| * to VPR failure */ |
| t_vpr_error* alloc_and_load_vpr_error(enum e_vpr_error type, unsigned int line, char* file_name){ |
| t_vpr_error* vpr_error; |
| |
| vpr_error = (t_vpr_error*)my_calloc(1, sizeof(t_vpr_error)); |
| vpr_error->file_name = (char*)my_calloc(strlen(file_name) + 1, sizeof(char)); |
| vpr_error->message = (char*)my_calloc(1000, sizeof(char)); |
| |
| sprintf(vpr_error->file_name, "%s", file_name); |
| vpr_error->line_num = line; |
| vpr_error->type = type; |
| |
| return vpr_error; |
| } |
| |
| /* Date:June 15th, 2013
|
| * Author: Daniel Chen
|
| * Purpose: Used to throw any internal VPR error or architecture
|
| * file error and output the appropriate file name,
|
| * line number, and the error message. Does not return
|
| * anything but throw an exception which will be caught
|
| * main.c.
|
| */ |
| void vpr_throw(enum e_vpr_error type, |
| const char* psz_file_name, |
| unsigned int line_num, |
| const char* psz_message, |
| ...) { |
| |
| // Make a variable argument list |
| va_list va_args; |
| |
| // Initialize variable argument list |
| va_start( va_args, psz_message ); |
| |
| // Generate the actual error object and throw it |
| vvpr_throw(type, psz_file_name, line_num, psz_message, va_args); |
| |
| // Reset variable argument list |
| va_end( va_args ); |
| |
| } |
| |
| /* |
| * Version of vpr_throw that takes an explicit va_list. |
| * |
| * This allows functions that have variable numbers of |
| * inputs to throw t_vpr_error objects. |
| */ |
| void vvpr_throw(enum e_vpr_error type, |
| const char* psz_file_name, |
| unsigned int line_num, |
| const char* psz_message, |
| va_list args) { |
| |
| // Allocate the error struct |
| t_vpr_error* vpr_error = alloc_and_load_vpr_error(type, |
| line_num, const_cast<char*>(psz_file_name)); |
| |
| // Extract and format message based on variable argument list |
| vsprintf(vpr_error->message, psz_message, args ); |
| |
| throw vpr_error; |
| } |
| |
| /* Date:July 17th, 2013
|
| * Author: Daniel Chen
|
| * Purpose: Checks the file extension of an file to ensure
|
| * correct file format. Returns true if format is
|
| * correct, and false otherwise.
|
| * Note: This is probably a fragile check, but at least
|
| * should prevent common problems such as swapping
|
| * architecture file and blif file on the VPR
|
| * command line.
|
| */
|
|
|
| bool check_file_name_extension(INP const char* file_name,
|
| INP const char* file_extension){
|
| const char* str;
|
| int len_extension;
|
|
|
| len_extension = strlen(file_extension);
|
| str = strstr(file_name, file_extension);
|
| if(str == NULL || (*(str + len_extension) != '\0')){
|
| return false;
|
| }
|
|
|
| return true;
|
| } |
| |
| /* |
| * Returns line number of last opened and read file |
| */ |
| int get_file_line_number_of_last_opened_file() { |
| return file_line_number; |
| } |
| |
| /* Performs linear interpolation or extrapolation on the set of (x,y) values specified by the xy_map. |
| A requested x value is passed in, and we return the interpolated/extrapolated y value at this requested value of x. |
| Meant for maps where both key and element are numbers. |
| This is specifically enforced by the explicit instantiations below this function. i.e. only templates |
| using those types listed in the explicit instantiations below are allowed */ |
| template<typename X, typename Y> Y linear_interpolate_or_extrapolate(INP std::map<X,Y> *xy_map, INP X requested_x){ |
| Y result; |
| |
| /* the intention of this function is to interpolate/extrapolate. we can't do so with less than 2 values in the xy_map */ |
| if (xy_map->size() < 2){ |
| vpr_throw(VPR_ERROR_UNKNOWN, __FILE__, __LINE__, |
| "linear_interpolate_or_extrapolate: cannot interpolate/extrapolate based on less than 2 (x,y) pairs"); |
| } |
| |
| if (xy_map->count(requested_x) == 1){ |
| /* requested x already exists in the x,y map */ |
| result = (*xy_map)[requested_x]; |
| } else { |
| /* requested x does not exist in the x,y map. need to interpolate/extrapolate */ |
| |
| typename std::map<X,Y>::const_iterator it; |
| double x_low, x_high, y_low, y_high; |
| double slope, reference_y, delta_x; |
| |
| /* get first x greater than the one requested */ |
| it = xy_map->upper_bound(requested_x); |
| |
| if(it == xy_map->end()){ |
| /* need to extrapolate to higher x. based on the y values at the two largest x values */ |
| it--; |
| x_high = (double)it->first; |
| y_high = (double)it->second; |
| it--; |
| x_low = (double)it->first; |
| y_low = (double)it->second; |
| } else if (it == xy_map->begin()){ |
| /* need to extrapolate to lower x. based on the y values at the two smallest x */ |
| x_low = (double)it->first; |
| y_low = (double)it->second; |
| it++; |
| x_high = (double)it->first; |
| y_high = (double)it->second; |
| } else { |
| /* need to interpolate. based on y values at x just above/below |
| the one we want */ |
| x_high = (double)it->first; |
| y_high = (double)it->second; |
| it--; |
| x_low = (double)it->first; |
| y_low = (double)it->second; |
| } |
| |
| slope = (y_high - y_low) / (x_high - x_low); |
| reference_y = y_low; |
| delta_x = (double)requested_x - x_low; |
| result = (Y)(reference_y + (slope * delta_x)); |
| } |
| |
| return result; |
| } |
| template double linear_interpolate_or_extrapolate(std::map<int,double> *xy_map, int requested_x); /* (int,double) */ |
| template double linear_interpolate_or_extrapolate(std::map<double,double> *xy_map, double requested_x); /* (double,double) */ |