This document is to help you build your own work within SIS environment. In this document, I will try to provide *a* solution for each of the problem: how to access the network created by SIS; how to build your work on top of SIS. Obviously, there may be many other approaches for them. Please refer to the relevant documents of SIS for your own purpose. Should you have any question concerning this document or SIS utilities, please feel free to send me email at demingc@cs.ucla.edu. Section 1. BLIF Format Before going on the programming details, I will give a brief introduction of the BLIF format for multi-level combinational circuits. All the test cases are in BLIF format. BLIF Format: A typical blif file includes circuit name, I/O description, gates and file end. The circuit name is at the first line as: .model circuit The following lines are I/O description: .inputs i1 i2 i3 .. .outputs o1 o2 .. The gate information includes inputs/outputs and functionality: .names input1 input2 output followed by the cover table of cubes: 10 1 01 1 The file must ended with: .end Section 2. Link Your Program with SIS Now, let us talk about the programming issues. First, you would make your own functions which can be called by sis, like main() which can be called by shell/operating-system. One sample is: int com_myproj(network, argc, argv) network_t **network; int argc; char **argv; { extern char *util_optarg; extern int util_optind; printf("Hello, this is the project for CS258G\n"); return (0); } The argc and argv have the same meaning as main(argc, argv) in C. The network points to the input network for your operation. Now, you would add your function to the SIS environment by the following: 1. make an initialization function as: int init_myproj() { com_add_command("myproj", com_myproj, 1); com_add_command("name", function, 1); ... ... ... return(0); } which adds your commands to SIS. The above example tells SIS that command "myproj" corresponds to com_myproj(). 2. add init_myproj() to init_sis() in sis/main/sis_init.c I have done this for you for your convenience. However, you must use init_myproj() as your initialization function. Now, you would be able to add commands like myproj or any other command you like to sis. To run your command, first run sis. Sis runs like a simple shell with prompt sis>. The following is the running result: > > sis UC Berkeley, SIS 1.3 (compiled 21-Feb-03 at 12:15 AM) sis> read_blif simple.blif sis> myproj Hello, this is the project for CS258G Print out the number of fanouts for each node: 2 1 2 1 2 1 0 1 0 Done!! The total number of literals (SOP) in the network top is 8 (0.888889 per node). The total number of connections in the network top is 8. sis> quit > The following paragraph is about how to parse the parameters and options within SIS environment. 1. parameters: like main(argc, argv) in C environment, argc is the number of fields in the input command, argv is the array of all the fields. The argv[0] is the command name. The rest are the parameters and options. All the parameters must be put before the options. So it can get directly through argv[i]. 2. options: the options are specified as -key [value]; key is a single character from a to z or A to Z; value can be number or symbol. The following program shows how to parse the options within SIS: util_getopt_reset(); /* initialization */ util_optind = 1; /* skip the first parameter */ while ((cc = util_getopt(argc, argv, "aAb:B:")) != -1) switch (cc) { case 'a': /* no value option, no ':' followed */ case 'A': /* no value option, no ':' followed */ set flag for A; break; case 'b': /* option with value, followed by ':' */ case 'B': /* option with value, followed by ':' */ k = atoi(util_optarg); /* util_optarg stores the value */ break; default: printf("Unknown option.\n"); break; } The order of options is irrelevant. Section 3. Expand SIS's Data Structure IMPORTENT!!! Now, we already know how to add new commands/functions within SIS and how to parse the command parameters and options. The only thing left for us is how to use the SIS data structure and utilities for our own purpose. 1. Expanded data structure First, you need to expand the SIS data structure for your own work. The network_t is the data structure for combination circuits which consists of nodes and their connections. The node_t is the date structure for nodes. It has a field (char *undef1) for you to point to your own data structure. First, you must define your own auxiliary data structure for nodes as: typedef struct { int label; ... ... } proj_aux_t; In this project, I have defined an initial proj_aux_t structure in /u/class/CS258G/project_template/myproj/com_myproj.h. You are required to use this as your program base because it includes expanded fields for the vqm dumper to use. I defined macros in the header file for your convenience. 2. Then, you would allocate the memory space for every node as: nodevec = network_dfs(*network); /* DFS traversal to get all nodes */ num_nodes = array_n(nodevec); /* get the number of nodes */ p = (proj_aux_t*)malloc(num_nodes*sizeof(proj_aux_t)); /* memory allocation */ (void)memset((char*)p, 0, num_nodes*sizeof(proj_aux_t)); for (i = 0; i < num_nodes; i++) { node = array_fetch(node_t*, nodevec, i); /* get a node */ node->undef1 = (char*)(p+i); /* connect your data structure with sis */ /* initialize these two fields. PLEASE DO NOT TOUCH THESE TWO LINES */ PROJ_DUMPED(node) = FALSE; PROJ_PAIR_ID(node) = -1; /* ******************************* */ .... .... } This piece of code is included in /u/class/CS258G/project_template/myproj/com_myproj.c. You will need to always include this piece of code in your work. I also include a small routine to pair two nodes together. The vqm dumper will use the pairing info to pack two LUTs into one ALM. Please follow the pairing format as written in the routine. Section 4. Relevant SIS Utilities This section includes SIS utilities you are expected to use for your project, which includes network operations, node operations and array operations. 4.1. Network Operations The following is a set of functions relevant to network. You can find a complete reference in SIS/network/network.doc and the data structures in SIS/network/network.h int network_num_pi(network) network_t *network; Return the number of primary inputs for the network. int network_num_po(network) network_t *network; Return the number of primary outputs for the network. int network_num_internal(network) network_t *network; Return the number of internal nodes in the network. foreach_primary_input(network, gen, pi) network_t *network; lsGen gen; node_t *pi; Generates over the primary inputs of a network. foreach_primary_output(network, gen, po) network_t *network; lsGen gen; node_t *po; Generates over the primary outputs of a network. array_t * network_dfs(network) network_t *network; Returns a vector of nodes ordered in a depth-first manner from the outputs. Includes PRIMARY_INPUT, PRIMARY_OUTPUT and INTERNAL nodes. (The nodes are ordered such that every node appears somewhere after all of its transitive fanin nodes.) 4.2. Node Operations Please refer to SIS/node/node.doc for a complete reference and SIS/node/node.h for data structures. int node_num_fanin(node) node_t *node; Returns the number of inputs to node. int node_num_fanout(node) node_t *node; Returns the number of fanouts of node. foreach_fanin(node, i, fanin) node_t *node; int i; node_t *fanin; Generates all of the inputs to a node. foreach_fanout(node, gen, fanout) node_t *node; lsGen gen; node_t *fanin; Generates all of the fanouts of a node. node_type_t { /* define node types */ PRIMARY_OUTPUT, PRIMARY_INPUT, INTERNAL }; node_type_t node_type(n) node_t *n; Returns the type of node n. node_function_t { NODE_PI, NODE_PO, NODE_0, NODE_1, NODE_BUF, NODE_INV, NODE_AND, NODE_OR, NODE_COMPLEX, NODE_UNDEFINED }; node_function_t node_function(f) node_t *f; Returns the type of the logic function for f. NODE_PI and NODE_PO indicate the node is a primary input or a primary output of a network. NODE_0 and NODE_1 indicate a constant-valued function. NODE_INV and NODE_BUF indicate a single literal function (either positive for negative). NODE_AND indicates a single-product term in the function, and NODE_OR indicates many product terms, each with a single literal. NODE_COMPLEX means the logic function is some other more complex function. Note that NODE_AND or NODE_OR are returned even if variables are used in their complemented form. Also, not that NODE_AND or NODE_OR requires 2 or more inputs (if there is only a single input, the function must be NODE_0, NODE_1, NODE_INV, or NODE_BUF). NODE_UNDEFINED means the node has not been given a logic function yet. node_t * node_and(f, g) node_t *f, *g; Computes f * g for two nodes. node_t * node_or(f, g) node_t *f, *g; Computes f + g for two nodes. node_t * node_not(f) node_t *f; Computes the complement of a node f. Potentially very efficient if the complement of f is already computed and stored. node_t * node_simplify(F, D, mode) node_t *F; node_t *D; node_sim_type_t mode; Minimize the function 'F' using 'D' as a don't-care set. 'D' may be NIL(node_t) which implies no don't-care set. 'mode' is one of NODE_SIM_SCC, NODE_SIM_SIMPCOMP, or NODE_SIM_ESPRESSO to choose the minimization algorithm for simplifying the function 'F'. Note that NODE_SIM_SCC and NODE_SIM_SIMPCOMP ignore any don't-care set which is given. Refer to node.c in sis/node for more mode description (including the exact minimization.) int node_num_cube(node) node_t *node; Returns the number of cubes in the sum-of-products form for the function. Note that the 0 function has no cubes, and the 1 function has 1 cube. 4.3. Array Operations This array package is intended for generic objects (i.e., an array of int, array of char, array of double, array of struct foo *, or even array of struct foo) which is very useful to organize data. An array_t is a dynamically allocated array. As elements are inserted, the array is automatically grown to accommodate the new elements. The first element of the array is always element 0, and the last element is element n-1 (if the array contains n elements). Please refer to SIS/array/array.doc and SIS/array/array.h for more detail. array_t * array_alloc(type, number) typeof type; int number; Allocate and initialize an array of objects of type `type'. Polymorphic arrays are okay as long as the type of largest object is used for initialization. The array can initially hold `number' objects. Typical use sets `number' to 0, and allows the array to grow dynamically. void array_free(array) array_t *array; Deallocate an array. Freeing the individual elements of the array is the responsibility of the user. int array_n(array) array_t *array; Returns the number of elements stored in the array. If this is `n', then the last element of the array is at position `n' - 1. array_t * array_dup(array) array_t *array; Create a duplicate copy of an array. void array_insert(type, array, position, object) typeof type; array_t *array; int position; type object; Insert a new element into an array at the given position. The array is dynamically extended if necessary to accommodate the new item. It is a serious error if sizeof(type) is not the same as the type used when the array was allocated. It is also a serious error for 'position' to be less than zero. void array_insert_last(type, array, object) typeof type; array_t *array; type object; Insert a new element at the end of the array. Equivalent to: array_insert(type, array, array_n(array), object). type array_fetch(type, array, position) typeof type; array_t *array; int position; Fetch an element from an array. A runtime error occurs on an attempt to reference outside the bounds of the array. There is no type-checking that the value at the given position is actually of the type used when dereferencing the array. type array_fetch_last(type, array) typeof type; array_t *array; Fetch the last element from an array. A runtime error occurs if there are no elements in the array. There is no type-checking that the value at the given position is actually of the type used when dereferencing the array. Equivalent to: array_fetch(type, array, array_n(array)) void array_sort(array, compare) array_t *array; int (*compare)(); Sort the elements of an array. `compare' is defined as: int compare(obj1, obj2) char *obj1; char *obj2; and should return -1 if obj1 < obj2, 0 if obj1 == obj2, or 1 if obj1 > obj2. At the end, you need to verify your program by comparing the original BLIF netlist with the mapped netlist. SIS provides the following utility to do the verification: verify [-m method] [-v] file1 [file2] For our project, you can carry out the verification as follows: sis> read_blif example.blif2 sis> verify example_mapped.blif