#include "cubes.h" #define CR '\n' #define BL ' ' /* COMMON VARIABLES The variables defined below are used in many modules and are defined external in the file cube.h */ int input_number, /* number of input variables */ output_number, /* number of outpput variables */ total_number, /* number of variables */ input_length, /* number of long int words to store inputs */ output_length, /* number of long int words to store outputs */ total_length; /* number of long int words to store a cube */ char error_buffer[132]; /* buffer to hold the error messages */ unsigned node_size, /* size in bytes of a node including the cube*/ cube_list_size; /* size of a cube_list including the cube */ struct node *spare_node; /* a node is allocated for temp usage */ /* TABLES Here are defined and initialized the tables useful for the input and output of cubes. We have the literal corresponding to each internal code for a boolean variable. */ char input_literal[4] = { 'x','X','0','1' }, /* holds the characters accepted for the input variables */ output_literal[4] = { '0','1','d','D' }; /* holds the characters accepted for output variables */ long int input_code[4], /* holds the code for the character at input */ output_code[4]; /* holds the code for the output characters */ /**************************************************************************** NAME ffind_car PURPOSE this functions skips characters in the input file until a EOF or the specified character is found. SYNOPSIS char ffind_car(fp,lineno,car_searched) FILE *fp; int *lineno; char car_searched; DESCRIPTION the characters are skipped from the file pointed by fp; EOF or the specified character is returned depending which is encountered first. The line number is updated if needed. COORDINATES McGill University Electrical Engineering VLSI Lab MONTREAL CANADA 19 june 1984 AUTHOR Michel DAGENAIS ************************************************************************/ char ffind_car(fp,lineno,car_searched) FILE *fp; int *lineno; char car_searched; { int car; /* byte to store the character read */ for(; (car = getc(fp)) > EOF ;) { if(car == CR) (*lineno)++ ; if(car == car_searched) break; } return(car); } /*************************************************************************** NAME fread_bit_string PURPOSE This function reads a string of bits and pack them in long words at the rate of 4 input bits per byte since up to 4 codes are recognized by this function. SYNOPSIS fread_bit_string(fp,lineno,word,bit_number,terminator,literal,code) FILE *fp; long int *word,code[4]; int bit_number,*lineno; char terminator,literal[4]; DESCRIPTION the characters are read from the file pointed by fp; When we encounter the terminator, we stop reading. The comments and blanks are skipped. The non-blank character are compared with the literals in the table; if the character is not in the table a message is issued. When we found the character in the table the corresponding code is placed in the long word. When a word is full, we increment the pointer. When the number of bits read is not bit_number, a message is issued to the user. We keep track of the number of lines for diagnostic purpose. The function returns 1 when a cube was read properly, -1 when a cube was read but the terminator was missing and EOF was encountered. If anything goes wrong a message is issued and the function never returns. The function returns 0 when the EOF was encountered before any bit was found. COORDINATES McGill University Electrical Engineering VLSI Lab MONTREAL CANADA 19 june 1984 AUTHOR Michel DAGENAIS ************************************************************************/ int fread_bit_string(fp,lineno,word,bit_number,terminator,literal,code) FILE *fp; long int *word,code[4]; int bit_number,*lineno; char terminator,literal[4]; { unsigned long int mask; /* mask used to pack the variables in long int */ int car; /* byte to store the character returned by functions */ int nb_bit_read, /* number of bits read */ i; /* loop counter for code determination */ /* we fill the long words right to left as the variables values are read, using the mask which is shifted left 2 bits each time to go to the next variable stored in the long word. */ nb_bit_read = 0; for(; ;) { *word = mask00; for( mask = 3 ; mask != NULL ; mask = mask << 2) /* We read characters at input until the EOF or the terminator is reached */ { for(; ;) { car = getc(fp); if(car == CR) (*lineno)++; if(car == terminator && nb_bit_read != 0) break; if(car == '/') { car = ffind_car(fp,lineno,'/'); if(car == '/') continue; } if(car <= EOF) break; if(car <= BL) continue; break; } /* The terminator is reached, we will check that the number of bits read was correct. The rest of the word is filled with the default code (code[0]). */ if(car == terminator) { if(nb_bit_read != bit_number) { sprintf(error_buffer, "wrong number of bits on line %d '%c' was reached after %d bits", *lineno,terminator,nb_bit_read); fatal_user_error(error_buffer); } for(; mask > 3 ; mask = mask << 2) *word |= code[0] & mask; return(1); } /* The end of file is reached, if a string of proper length was read the user is warned that the terminator is missing and we return -1. */ if(car <= EOF) { if(nb_bit_read == bit_number) { for(; mask > 3 ; mask = mask << 2) *word |= code[0] & mask; warning_user_error("missing terminator at end of file"); return(-1); } if(nb_bit_read == 0) return(0); sprintf(error_buffer,"EOF encountered after %d bits %d were expected" ,nb_bit_read,bit_number); fatal_user_error(error_buffer); } /* We will try to find the literal in the table */ for(i = 0 ; i < 4 ; i++) if(car == literal[i]) break; /* The literal was not found, it is an invalid character, a message is issued */ if(i == 4) { sprintf(error_buffer,"invalid character '%c' in line %d",car,*lineno); fatal_user_error(error_buffer); } /* The specified number of bits were read and the terminator is not reached a message will be issued. */ if(nb_bit_read >= bit_number) { sprintf(error_buffer,"too many bits on line %d '%c' not reached", *lineno,terminator); fatal_user_error(error_buffer); } /* it is in the table so we put it in the long word */ *word |= mask & code[i]; nb_bit_read++; } word++; } } /***************************************************************************** NAME fread_nodes PURPOSE This function reads all the cubes from the input file and store them in the proper form after allocating space for them. SYNOPSIS int fread_nodes(fp,list) FILE *fp; struct node **list; DESCRIPTION When this function is called for the first time, the variable input_number is 0; then we read one cube to determine the number of input and output bits and we compute the size of the structures needed. When the number of inputs is known, we simply read the cubes one by one from fp and allocate space for them. The list formed goes in list and the number of cubes in list is returned. Any error reading the cube will be signaled by this function or by the function fread_bit_string called to read the cubes. COORDINATES McGill University Electrical Engineering VLSI Lab MONTREAL CANADA 19 june 1984 AUTHOR Michel DAGENAIS ************************************************************************/ int fread_nodes(fp,list) FILE *fp; struct node **list; { int car; /* character read */ int list_number, /* number of cubes read and placed in the list */ line_number, /* number of lines read at input for diagnostic */ answer; /* return code of the function fread bit string */ struct node **previous; /* pointer to node.next_cube of the previous*/ /* node to link the chain while reading */ /* We will read the first cube to count the number of input and output variables. The size of the structures will be computed. */ if(input_number == 0) { line_number = 0; for(; ;) { car = getc(fp); if(car == read_interminator && input_number != 0) break; if(car <= EOF) fatal_user_error("EOF encountered on first line"); if(car <= BL) continue; if(car == '/') { car = ffind_car(fp,&line_number,'/'); if(car <= EOF) fatal_user_error("EOF encountered on first line"); } else input_number++; } for(; ;) { car = getc(fp); if(car == read_outterminator && output_number != 0) break; if(car <= EOF) break; if(car <= BL) continue; if(car == '/') { car = ffind_car(fp,&line_number,'/'); if(car <= EOF) break; } else output_number++; } /* We now have the number of input and output, so we can compute the different variables that depend on those values. */ input_length = ((input_number - 1) / var_per_word) + 1; output_length = ((output_number - 1) / var_per_word) + 1; total_length = input_length + output_length; total_number = input_number + output_number; /* The nodes already include 2 long int word which is the minimum space a cube is allowed to take. The actual length of the cube minus the 2 minimum is then added to the sizeof(node) to get the nodesize appropriate to our number of input and output. */ node_size = sizeof(struct node) + (total_length - 2) * sizeof(long int); cube_list_size = sizeof(struct cube_list) + (total_length - 2) * sizeof(long int); /* We now reset the file pointer to the beginning of the file to read all the nodes and place them in the list. Also we initialize all the constants needed to process the cubes. It is a convenient place to make this call since before any processing can be done we have to read the cubes. */ init_mask_and_codes(); rewind(fp); spare_node = alloc_node(); } /* We will now read the list of nodes from the file, the line number and the number of nodes in the list are initialized. */ previous = list; line_number = 1; list_number = 0; for(; ;) { answer = fread_bit_string(fp,&line_number,spare_node->cube,input_number, read_interminator,input_literal,input_code); /* No more cubes in the file, the EOF was encountered */ if(answer == 0) break; if(answer == -1) fatal_user_error("last cube of file has no output part"); answer = fread_bit_string(fp,&line_number,spare_node->cube + input_length, output_number,read_outterminator,output_literal,output_code); /* The EOF was encountered but the cube was not finished */ if(answer == 0) { fatal_user_error("The output of the last cube is incomplete"); } /* another node was read succesfully, place it next in the list. */ *previous = spare_node; spare_node->next_node = alloc_node(); previous = &(spare_node->next_node); spare_node = spare_node->next_node; list_number++; /* the cube read was the last one of the file */ if(answer == -1) break; } /* the last node we tried to read was not there, the eof was encountered, so we must remove it from the list */ *previous = NULL; return(list_number); }