13.07.2015 Views

Parsing a Spice netlist

Parsing a Spice netlist

Parsing a Spice netlist

SHOW MORE
SHOW LESS

Create successful ePaper yourself

Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.

C Assignment: <strong>Parsing</strong> a text fileOctober 19, 2009AbstractIn this experiment, you will begin to write a program that will parse a simplespice control file, construct the circuit to be simulated, and solve the circuit equations.The circuit has only simple devices. The full code will be developed over afew weeks. This week we read in a control file, analyse it and save the informationin a linked list.1 IntroductionA spice <strong>netlist</strong> consists of lines of the following forms:n1 n2 type valuen1 n2 n3 n4 type valuewhere n1, n2, n3 and n4 are symbolic names representing nodes, type is either “R”,“L”, “C”, “I” or “V” for the first type of line, representing impedences or sources. typeis one of “VCVS”, “VCCS”, “CCVS”, “CCCS” for the second type of line. Value isthe value of the element in Ω, H, F, Amps or Volts, respectively.Each impedence line in the file translates into an equation:Each source line in the file becomesV n1 −V n2 = I n1,n2 R n1,n2V n1 −V n2 = L n1,n2dI n1,n2dtI n1,n2 = C n1,n2d(V n1 −V n2 )dtV n1 −V n2 = ε n1,n2I n1,n2 = I n1,n2V n1 −V n2 = E (V n3 −V n4 )V n1 −V n2 = FI n3,n4I n1,n2 = G(V n3 −V n4 )I n1,n2 = HI n3,n41


2 Coding Details2.1 Getting the File NameThe file name is given on the command line. We have to open it for reading.Commandline arguments in C are passed to the program through the ARGV pointer.Another variable is also passed to the program, namely argc, It is an int, and containsthe number of arguments. Let us see how this works in a simple program.2 〈eg1 2〉≡#include #include int main(int argc,char **argv); // declare mainint main(int argc,char **argv){float ans=0.0; // holds sum of valuesint i;// index variablefor( i=1 ; i


This program adds the numbers entered on the command line and prints out thesum. No error checking is done here. See what happens if you enter non-numbers andout of range numbers.Note that the for loop starts with i = 1. That is because the first element of argv isthe name of the executable.2.2 File I/OFiles are managed by the fopen and the fclose system functions. Look at the followingprogram. It computesy = 1 + 2cost + 4cos3t − 0.5sin3tfor values of t ranging from 0 to 2π. It writes out these values to a file called sample.dat.The equivalent Scilab code would have been:t=(0:0.1:2*%pi)';y=1+2*cos(t)+4*cos(3*t)-0.5*sin(3*t);fprintfMat(sample.dat,[t y]);The C code is not much bigger than the scilab code:3 〈eg2 3〉≡#include#include // required for cos functionint main(void){FILE *fp;float t,y;fp=fopen("sample.dat","w"); // open for writingfor(t=0;t


Note that fprintf has the same syntax as printf except that you additionallyhave to give the FILE pointer fp.Reading in from a file is quite a bit harder. The main reason is that you don’t knowhow much data there is and in what order. Let us say that an array has been written outby Scilab with the following code:A=rand(10,10);fprintfMat(sample.dat,A,%f,# Sample Matrix)We want to read in this file into C. Let us look at the steps involved:• Get the file name (sent via the command line)• Open the file for reading• read in line by line.• truncate every line by discarding characters following a ’#’ character.• skip blank lines.• read in as many numbers as there are in a line, and store them in a vector.• allocate memory for the row and save the contents of vector.• close the file and exit when end of file is encountered.There are some problems here. Scilab can write out a line containing 256 numbers aseasily as it can a line containing 10 numbers. So how do we know how large a vector toallocate? Additionally, when we read in a line, how do we know how many charactersto read?If we try reading more characters than we have space for, we will get a buffer overflowand our program will do arbitrary things. This is the primary source of most bugsin programs that hackers use to break into systems. A famous example was the fingercommand. You can find out if someone is online, and when they last logged in by givingtheir userid as an argument to finger. Unfortunately, the command read whateverthe user typed in without checking for buffer overflow. The result? A carefully crafted“username” could overwrite crucial data within the finger executable, so that the userwas given access to root privileges.Here is code to read in one row at a time from the Scilab output and and shadowprint it. I am assuming no embedded comments4 〈eg3 4〉≡#include #include // max length allowed for a read buffer#define BUFLEN 256// max number of columns allowed#define Ncol 20int main(int argc,char **argv); // declare main4


int main(int argc,char **argv){FILE *fp;char buf[BUFLEN];// holds linechar *word; // holds single numberchar *pbuf; // pointer used by strtokfloat vec[Ncol]; // array to hold one rowint i,n,row;if( argc


3 Memory allocationTo store the vector as a row of a matrix, we must allocate memory. We define our arrayas a “column” vector of pointers, each pointer pointing to a row vector.• To allocate N floating point numbersfloat *c;c=(float *)malloc(N*sizeof(float));• To free the arrayfree(c);Our code now becomes.6 〈eg4 6〉≡#include #include // max length allowed for a read buffer#define BUFLEN 256// max number of columns allowed#define Ncol 20int main(int argc,char **argv); // declare mainint main(int argc,char **argv){FILE *fp;char buf[BUFLEN];// holds linechar *word; // holds single numberchar *pbuf; // pointer used by strtokfloat **array; // will hold the array in which A is storedfloat *currow;float vec[Ncol]; // array to hold one rowint i,j,n,row;if( argc


Look at the nature of the malloc command. We are allocating a vector of pointers.Each element of the vector is a pointer to float. Hence sizeof(float *). The finalpointer, array, is a pointer to pointer to float. Hence the (float **).7 〈eg4 6〉+≡// read lines in row by row. Note that first row has// already been read in.for( row=0 ; ; row++ ){// read in numbers one by one till eol occurs.for( n=0,pbuf=buf ; n


vec is a fixed buffer. It will get overwritten every row. So we must copy over thedata into a freshly allocated memory area. That is what the malloc does. The copycan also be done via memmove as follows:memmove((void)currow, (void)vec, n*sizeof(float));This just moves memory. But the code above moves numbers and is probably slightlyslower. But it makes more sense.It is important to understand the way pointers are used here.• currow and j-1 th pointer of array both point to same memory vector.• We allocate memory and point currow to it. The old memory is still there, butcurrow has forgotten about it. The j-1 th pointer of array is still pointing tothat old memory.• Fill currow with data• Point the j th pointer of array to the new memory. Which brings us to thesituation at the start of the loop.8 〈eg4 6〉+≡// read next lineif( fgets(buf,BUFLEN-1,fp)==NULL )break;}fclose(fp);}// now print out the arrayfor( j=0 ; j


Note that you must free the rows before freeing array itself. If you change theorder, the program will have forgotten the location of the rows and will be unable todeallocate them. The rows will remain allocated without anything pointing to them.In simple cases like the above, you can leave it to the C compiler to add the freecommands. But it is good practice to put them in explicitely.The difficulty with this example code is the need to know how many rows andcolumns can be there in the array. There are situations (such as this assignment) wherethis number is not known ahead of time. Then, allocating an array is not the way to go.We should instead use linked lists. An alternate way is to scan the file twice, once tocompute the number of elements present, and the second to read in the elements intoan allocated array. The best way is for Scilab to write out the dimensions of the matrixin the header data (i.e., in the comment lines). That way the C program can parse thatline and pull out the size of the array to be allocated.Incidentally, the scilab code to read in the file is:A=fscanfMat(sample.dat);disp([(1:size(A,'r'))' A]);Clearly somewhat easier to code! That is because all the allocation magic is handledby Scilab/Matlab/Octave which is why they are so extensively used.3.1 <strong>Parsing</strong> the FileIn the above sections we read in numbers from the file. Now what we need to do is toread in a mix of numbers and strings.1. First read in the file, line by line.2. For each line, you need to extract words that are separated by “whitespace”, i.e.,an arbitrary combination of blanks, tabs and new lines. For eg, the following arevalid lines:2 3 R 1.5k6 9 R 3megThe following is illegal:3 ; 2 R 55Note: Two types of lines are expected: lines with four tokens of the formnode1 node2 type valuenode1 node2 node3 node4 type valueThe second type is found when we have dependent sources (eg. amplifiers).3. Determine if the type is “r”, “l”, “c”, “i”, “v”, “vcvs”, “vccs”, “ccvs”, “cccs”.The first five use four tokens to define the line, while the last four use six tokens.9


Note that the type field is the second last in both types of rows.4. Extract the trailing alphabets from the last field and classify it. Convert the restto a floating point number. Multiply by the modifier5. Allocate a link and store the data.6. After end of file, traverse through the list and print out the data.3.2 TokensThe process of converting a line into words is called tokenization. This is how the OStakes your command line and sends an array of words to the program in argv.Use the method in the example above to tokenize the line. If the number of tokensis not consistent with the type of branch, declare an error and stop.3.3 Classifying tokensEach token has a certain type based on its position. This is an extremely simple situation,compared to the parser we write to analyse a C program, for instance. There,we have no idea what any token should be till we have understood the logic of thestatement. Here, the position of the token defines its allowed values.• Token 1: Should be an node id (from node id)• Token 2: Should be an node id (to node id)Note: These are names. Should be a combination of letters and numbers. Hyphensand underscores allowed.• Token 3 onwards: Two cases are present:– Atotal of four tokens are present. Then parse token 3 for the type and token4 for the value.– A total of six tokens are present. Parse token 5 for the type and token 6 forthe value. extract node information from tokens 3 and 4.• Constructing the value: This field is in the form of a number, optionally followedby a modifier:Modifier Meaningn ×10 −9u ×10 −6m ×10 −3k ×10 3meg ×10 610


Note: There is a “right” way to do this, which is to build up a number using therules of what a number is. But we take the easy way out. Use sscanf to dothe job for you. It is not fast, but that does not matter for our lab.sscanf returns the number of fields it successfully read. Use that to determine(a) if no numeric value was present at all (zero fields read), (b) only a numericvalue was present (one field read) or (c) both numeric and modifier were read(two fields read). Use this to handle this field.Note: It is important to understand the return value of sscanf to know whenthings did not work correctly. How will you handle the following cases?– 4.4.3e16k– meg– node1– 4.5k3The parsing over, you should have four (or six) pieces of information. They need tobe stored somewhere. Since you don’t know how many lines there are, you need toallocate memory for every line and store it in there. That requires a data structurecalled a linked list.3.4 Linked ListsAt the end of this part of the experiment you should be able to allocate memory to storethe information in a linked list. The linked list should have the following structure (Iassume you know what structures are):Prev Link Next Link n1 n2 n3 n4 type valueIt should be allocated whenever needed. The “Prev Link” should point to the previouselement in the linked list, and the “Prev Link” of the first link should be NULL.The “Next Link” should be NULL for the last link and should point to the next linkotherwise. Consider and define the data structure, and carry out the allocationand setting of the values of the records.Note: Read up on structures, pointers and linked lists. Note that you will work withpointers to the structure. So revise the syntax to access fields given the pointerto a structure.Note: To create a new link, you need the following steps:• Allocate memory for the new link• Set the “Next Link” in the new link to NULL• Point current link’s “Next Link” to the new link.• Point the new links “Prev Link” to the current link.• Set pointer to current link to point to new link.11


• Enter the data in the new link (from the file)As proof of the correctness of your code, travel through the linked list and print out thedata one by one.Write pseudo code to traverse the linked list from beginning to end. What willyour stopping condition be?3.5 Final CodeThe final code should, when run• Take the name of the data file from the command line arguments• Read in the lines one by one, verify and store into the linked list– If an error is present, the code should give the right error message and stop.• After the file is read, the code should travel through the linked list in reverseorder and print out the information, link by link.In the lab, the bold items should have been completed. Take help from the TAs ifyou have problems with pointers and allocation, because unless you can do thoseitems, you will not be able to complete the assignment on your own.3.6 Scilab Code to parse the file12 〈eg5 12〉≡// script to parse an input spice filefunction v=modifier(mod)if mod=="u"v=1e-6;elseif mod=="m"v=1e-3;elseif mod=="k"v=1e3;elseif mod=="meg"v=1e6;endendfunction// read in the file into string vector lineslines=read("test.spc",-1,1,'(a)');// tokenize each row of linesN=size(lines,'r');fields=emptystr(N,6);for i=1:Nwords=tokens(lines(i))';if size(words,'c')==4fields(i,[1 2 5 6])=words;12


13 〈* 13〉≡〈eg5 12〉elseif size(words,'c')==6fields(i,:)=words;elseprintf("%d: wrong number of tokens\n",i);abortendend// convert column 6 to a valuefor i=1:N[n,val,mod]=msscanf(fields(i,6),"%f%s");if n==0printf("%d: illegal value\n",i);elseif n==1value(i)=val;elsevalue(i)=val*modifier(mod);endendNot sure how the for loops can be eliminated. Even though tokens and msscanfsay that they take string vectors as arguments, they only seem to work on individualstrings.13

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!