Commit ea9b38c96cb407e5fa717fbb4f2eecc7bb5f8830

Authored by Brice Colombier
0 parents
Exists in master

Initial commit

Showing 24 changed files with 5756 additions and 0 deletions

build_bench.py View file @ ea9b38c
... ... @@ -0,0 +1,219 @@
  1 +# -*- coding: utf-8 -*-
  2 +"""
  3 +Author : Brice Colombier
  4 +Affiliation: Laboratoire Hubert Curien, UMR CNRS 5516
  5 + University of Lyon
  6 + 18 rue du Professeur Benoit Lauras
  7 + 42000 Saint-Etienne - France
  8 +Contact : b.colombier@univ-st-etienne.fr
  9 +
  10 +Title : Building the graph from the netlist
  11 +Project : Graph-based nodes selection for functional locking
  12 +
  13 +File : build_def.py
  14 +Last update: 2015-03-17
  15 +"""
  16 +
  17 +from __future__ import print_function
  18 +import igraph as ig
  19 +import pyparsing as pp
  20 +import time
  21 +import sys
  22 +import os
  23 +
  24 +def adv_add_edges(g, es, instances, **kwds):
  25 + """adv_add_edges(es, **kwds)
  26 +
  27 + Adds multiple edges to the graph with a unique set of keywords.
  28 +
  29 + Keyword arguments (except the source and target arguments) will be
  30 + assigned to added edges as attributes.
  31 + @param g : the graph where to add given edges
  32 + @param es: list of source - dest tuples to add
  33 + @param instances: list of instances names to add corresponding to edges
  34 + @param **kwds : attributes to add to all the edges
  35 +
  36 + @return result of igraph.add_edges()
  37 + """
  38 +
  39 + if len(es) != len(instances):
  40 + raise Exception('Length of es different than length of instances')
  41 + if not kwds:
  42 + return g.add_edges(es)
  43 +# Getting next edge ID
  44 + eid = g.ecount()
  45 +# Adding all the edges from es to the graphe
  46 + result = g.add_edges(es)
  47 +# Adding Keywords and instance name to all the edges
  48 + for i, _ in enumerate(es):
  49 + for key, value in kwds.iteritems():
  50 + g.es[eid + i][key] = value
  51 + g.es[eid + i]['instance'] = instances[i]
  52 + return result
  53 +
  54 +def AddIO(toks, g, prim_in, prim_out, nodes):
  55 + """AddIO(toks)
  56 +
  57 + Add Inputs and Outputs to the graph
  58 +
  59 + @param toks: pyparsing result for the edif syntax
  60 + toks[0] : Inputs/Outputs list
  61 + toks[1] : Gates list
  62 + @param g: igraph instance to complete with inputs and outputs
  63 + @param prim_in: list to fill with inputs
  64 + @param prim_out: list to fill with outputs
  65 + @param nodes: list to fill with signal which can be inputs of functions
  66 + """
  67 + print("AddIO") #Debug
  68 +# print toks
  69 +
  70 + for row in toks[0]:#toks contain the full result of the parsing
  71 + Dir = row[0]
  72 + InputOutput = row[1]
  73 + if Dir == "INPUT":
  74 + if not InputOutput in prim_in:
  75 + g.add_vertex(InputOutput,
  76 + label=InputOutput,
  77 + color="#DDDDDD",
  78 + cat="input",
  79 + locks=[],
  80 + forced=[],
  81 + size=100,
  82 + label_size=30)
  83 + prim_in.append(InputOutput)
  84 + nodes.append(InputOutput)
  85 +
  86 + elif Dir == "OUTPUT":
  87 + if (not InputOutput in prim_in) and (not InputOutput in prim_out):
  88 + prim_out.append(InputOutput)
  89 + g.add_vertex(InputOutput,
  90 + label=InputOutput,
  91 + color="#666666",
  92 + cat="output",
  93 + locks=[0, 1],#By convention
  94 + forced=[],
  95 + size=100,
  96 + label_size=30)
  97 +# else:
  98 +# g.vs.find(name=InputOutput).delete()
  99 +# nodes.remove(InputOutput)
  100 +# prim_in.remove(InputOutput)
  101 +
  102 +def AddGate(toks, g, prim_in, prim_out, nodes):
  103 + """AddGate(toks)
  104 +
  105 + Add edges to the graph
  106 +
  107 + @param toks: pyparsing result for the edif syntax
  108 + toks[0] : Inputs/Outputs list
  109 + toks[1] : Gates list
  110 + @param g: igraph instance to complete with inputs and outputs
  111 + @param prim_in: list containing inputs names
  112 + @param prim_out: list containing outputs names
  113 + @param nodes: list to complete with signal which can be inputs of functions
  114 + """
  115 + print("AddGate") #Debug
  116 +
  117 + to_add_edges = {'and':[[],[]], 'nand':[[],[]], 'xor':[[],[]], 'or':[[],[]], 'nor':[[],[]], 'not':[[],[]], 'buf':[[],[]]}
  118 + instance_counter = 0;
  119 +# Initializing progress display
  120 + nb = 0
  121 + disp_time = time.time()
  122 + nbdisp = '0'
  123 + print('-> ' + str(len(toks[1])) + '/' + nbdisp, end='')
  124 +# Reading gates list
  125 + for row in toks[1]:
  126 +# Updating progress display every 0.5s
  127 + nb += 1
  128 + if time.time() >= disp_time + 0.5:
  129 + disp_time += 0.5
  130 + for _ in nbdisp:
  131 + print('\b', end='')
  132 + nbdisp = str(nb)
  133 + print(nbdisp, end='')
  134 +# Adding internal node if needed
  135 + noeud = row[0]
  136 + function = row[1]
  137 + inputs = row[2]
  138 + if not noeud in prim_out:
  139 + g.add_vertex(noeud,
  140 + label=noeud,
  141 + color="#FFFFFF",
  142 + cat="node",
  143 + locks=[],
  144 + forced=[],
  145 + size=100,
  146 + label_size=30)
  147 + nodes.append(noeud)
  148 +# Adding edges with the right function to the list
  149 + while inputs:
  150 + dest = inputs.pop()
  151 + to_add_edges[function][0].append((dest, noeud))
  152 + to_add_edges[function][1].append('inst_{0}'.format(instance_counter))
  153 + instance_counter += 1
  154 +# displaying the last progress number
  155 + for _ in nbdisp:
  156 + print('\b', end='')
  157 + print(str(nb))
  158 +# Adding all edges to the graph ordered by function
  159 + for i in sorted(to_add_edges, key=lambda i: len(to_add_edges[i][0]), reverse=False):
  160 + if len(to_add_edges[i][0]) > 0:
  161 + print('-> Adding ' + str(len(to_add_edges[i][0])) + ' ' + i + '...')
  162 + adv_add_edges(g, to_add_edges[i][0], to_add_edges[i][1],
  163 + name=i,
  164 + label=i,
  165 + width=5,
  166 + arrow_size=2,
  167 + label_size=40,
  168 + color="#AAAAAA")
  169 +
  170 +def build(name, result=None, parsedbg=False, verbose=True):
  171 + """build(name, result=None, parsedbg=False)
  172 + Builds the graph from an EDIF netlist
  173 + @param name: name of the netlist to build
  174 + @keyword result(None): result set from the edif syntax reader. Avoid reading and use set given instead. Used mainly for debugging.
  175 + @keyword parsebg(False): Boolean used to disable graph generating and return the syntax reader set of the netlist choosen. Used mainly for debugging.
  176 +
  177 + @return a tuple of 4 elements : the graph for the netlist, the list of inputs, the list of outputs, the list of node (inputs and internal nodes)
  178 + """
  179 +
  180 + print("---- Build BENCH")
  181 + if not verbose:
  182 + sys.stdout = open(os.devnull, 'w')
  183 + prim_in = [] #primary inputs of the netlist
  184 + prim_out = [] #primary outputs of the netlist
  185 + nodes = [] #nodes of the netlist
  186 + g = ig.Graph(directed=1)
  187 +
  188 +# Defining parsing elements
  189 + Dir = pp.Or([pp.CaselessLiteral("INPUT"), pp.CaselessLiteral("OUTPUT")])
  190 + Node = pp.Word(pp.alphanums + '_')# /!\Attention aux caractères spéciaux !
  191 + Gate = pp.Or([pp.CaselessLiteral("nand"), pp.CaselessLiteral("and"), pp.CaselessLiteral("nor"), pp.CaselessLiteral("or"), pp.CaselessLiteral("xor"), pp.CaselessLiteral("not"), pp.CaselessLiteral("buf")])
  192 +
  193 +# Defining Parsing groups
  194 + IOLike = Dir + '(' + Node + ')' #Used to detect IO lines
  195 + IO = pp.ZeroOrMore(pp.Group(Dir + pp.Suppress('(') + Node + pp.Suppress(')')))
  196 + GateLink = pp.ZeroOrMore(pp.Group(Node + pp.Suppress('=') + Gate + pp.Suppress('(') + pp.Group(pp.OneOrMore(Node + pp.Optional(pp.Suppress(',')))) + pp.Suppress(')')))
  197 +# Defining full parser
  198 + FullParser = pp.Suppress(pp.SkipTo(IOLike)) + pp.Group(IO) + pp.Group(GateLink)
  199 +# Opening netlist file
  200 + path = ""
  201 + source_file = path+name+".txt"
  202 +# Parsing if no data given
  203 + if result == None:
  204 + print("Parsing...")
  205 + result = FullParser.parseFile(source_file)
  206 +# Returning data readen without generating graph if needed
  207 + if parsedbg:
  208 + if not verbose:
  209 + sys.stdout = sys.__stdout__
  210 + print('---- Done (parsedbg)\n')
  211 + return result
  212 +# Generating graph with data readen or given and returning
  213 + else:
  214 + AddIO(result, g, prim_in, prim_out, nodes)
  215 + AddGate(result, g, prim_in, prim_out, nodes)
  216 + if not verbose:
  217 + sys.stdout = sys.__stdout__
  218 + print("---- Done\n")
  219 + return g, prim_in, prim_out, nodes
build_bench.pyc View file @ ea9b38c

No preview for this file type

build_blif.py View file @ ea9b38c
... ... @@ -0,0 +1,306 @@
  1 +# -*- coding: utf-8 -*-
  2 +"""
  3 +Author : Brice Colombier
  4 +Affiliation: Laboratoire Hubert Curien, UMR CNRS 5516
  5 + University of Lyon
  6 + 18 rue du Professeur Benoit Lauras
  7 + 42000 Saint-Etienne - France
  8 +Contact : b.colombier@univ-st-etienne.fr
  9 +
  10 +Title : Building the graph from the netlist
  11 +Project : Graph-based nodes selection for functional locking
  12 +
  13 +File : build_def.py
  14 +Last update: 2015-03-17
  15 +"""
  16 +from __future__ import print_function
  17 +import igraph as ig
  18 +import pyparsing as pp
  19 +import time
  20 +import sys
  21 +import os
  22 +
  23 +def adv_add_edges(g, es, **kwds):
  24 + """adv_add_edges(es, **kwds)
  25 +
  26 + Adds multiple edges to the graph with a unique set of keywords.
  27 +
  28 + Keyword arguments (except the source and target arguments) will be
  29 + assigned to added edges as attributes.
  30 + @param g : the graph where to add given edges
  31 + @param es: list of source - dest tuples to add
  32 + @param instances: list of instances names to add corresponding to edges
  33 + @param **kwds : attributes to add to all the edges
  34 +
  35 + @return result of igraph.add_edges()
  36 + """
  37 +
  38 + if not kwds:
  39 + return g.add_edges(es)
  40 +# Getting next edge ID
  41 + eid = g.ecount()
  42 +# Adding all the edges from es to the graphe
  43 + result = g.add_edges(es)
  44 +# Adding Keywords and instance name to all the edges
  45 + for i, _ in enumerate(es):
  46 + for key, value in kwds.iteritems():
  47 + g.es[eid + i][key] = value
  48 + return result
  49 +
  50 +def AddInputs(toks, g, prim_in, nodes):
  51 + """AddInputs(toks)
  52 +
  53 + Add Inputs to the graph
  54 +
  55 + @param toks: pyparsing result for the edif syntax
  56 + toks[0] : Inputs list
  57 + toks[1] : Outputs list
  58 + toks[2] : Functions' definition list
  59 + @param g: igraph instance to complete with inputs and outputs
  60 + @param prim_in: list to fill with inputs
  61 + @param nodes: list to fill with signal which can be inputs of functions
  62 + """
  63 + print ("AddInputs")
  64 +
  65 + for Input in toks[0]:
  66 + if not Input in prim_in:
  67 + prim_in.append(Input)
  68 + nodes.append(Input)
  69 + g.add_vertex(Input,
  70 + label=Input,
  71 + color="#DDDDDD",
  72 + cat="input",
  73 + locks=[],
  74 + forced=[],
  75 + size=100,
  76 + label_size=30)
  77 +
  78 +def AddOutputs(toks, g, prim_in, prim_out):
  79 + """AddOutputs(toks)
  80 +
  81 + Add Outputs to the graph
  82 +
  83 + @param toks: pyparsing result for the edif syntax
  84 + toks[0] : Inputs list
  85 + toks[1] : Outputs list
  86 + toks[2] : Functions' definition list
  87 + @param g: igraph instance to complete with inputs and outputs
  88 + @param prim_in: list conatining inputs names
  89 + @param prim_out: list to fill with outputs
  90 + """
  91 + print("AddOutputs")
  92 +
  93 + for Output in toks[1]:
  94 + if (not Output in prim_in) and (not Output in prim_out):
  95 + prim_out.append(Output)
  96 + g.add_vertex(Output,
  97 + label=Output,
  98 + color="#666666",
  99 + cat="output",
  100 + locks=[0, 1],#By convention
  101 + forced=[],
  102 + size=100,
  103 + label_size=30)
  104 +
  105 +def AddGate(toks, g, prim_out, nodes):
  106 + """AddGate(toks)
  107 +
  108 + Add edges to the graph
  109 +
  110 + @param toks: pyparsing result for the edif syntax
  111 + toks[0] : Inputs list
  112 + toks[1] : Outputs list
  113 + toks[2] : Functions' definition list
  114 + @param g: igraph instance to complete with inputs and outputs
  115 + @param prim_out: list containing outputs names
  116 + @param nodes: list to complete with signal which can be inputs of functions
  117 + """
  118 + print("AddGates") #Debug
  119 +# Initializing vars
  120 + to_add = {'and':[[],[]], 'nand':[[],[]], 'or':[[],[]], 'not':[[],[]], 'buf':[[],[]]}
  121 + add_vertices = []
  122 + nots_list = []
  123 +
  124 +# Initializing progress display
  125 + nb = 0
  126 + disp_time = time.time()
  127 + nbdisp = '0'
  128 + print('-> ' + str(len(toks[2])) + '/' + nbdisp, end='')
  129 +# Reading all functions definitions from the netlist
  130 + for Def in toks[2]:
  131 +# Updating progress display every 0.5s
  132 + nb += 1
  133 + if time.time() >= disp_time + 0.5:
  134 + disp_time += 0.5
  135 + for _ in nbdisp:
  136 + print('\b', end='')
  137 + nbdisp = str(nb)
  138 + print(nbdisp, end='')
  139 +# Getting datas
  140 + inputs = Def[0][0]
  141 + output = Def[0][1]
  142 +# adding target node in add_vertices
  143 + if not output in prim_out:
  144 + add_vertices.append(output)
  145 + nodes.append(output)
  146 +# =°1=Check inputs number : more than 1 inputs
  147 + if len(inputs) > 1:
  148 + and_count = 0
  149 + and_nodes = []
  150 +# if there are multiple signal cover, each lines have to be combinated with an or
  151 + if len(Def[1]) > 1:
  152 + global_or = True
  153 + else:
  154 + global_or = False
  155 +
  156 +# Reading all output cover
  157 + for cover in Def[1]:
  158 +# if an or is needed, create intermediate nodes and redirect the output of the and gate
  159 + if global_or:
  160 + and_count += 1
  161 + target = "and{0}_{1}".format(output, and_count)
  162 + else:
  163 + target = output
  164 +# Initializing some vars
  165 + edges_list = []
  166 + used_signal = 0
  167 + last_state_found = ''
  168 +# reading inputs states for this cover
  169 + for j, source in enumerate(cover[0]):
  170 +# Adding direct input if as '1' source
  171 + if source == '1':
  172 + used_signal += 1
  173 + edges_list.append((inputs[j], target))
  174 + last_state_found = '1'
  175 +# Adding complemented input if as '0' source
  176 + elif source == '0':
  177 + used_signal += 1
  178 + not_source = 'interNot_{0}'.format(inputs[j])
  179 +# Creating complemented nodes for the input if doesn't exist yet
  180 + if not not_source in nots_list:
  181 + add_vertices.append(not_source)
  182 + to_add['not'][0].append((inputs[j], not_source))
  183 + nots_list.append(not_source)
  184 + edges_list.append((not_source, target))
  185 + last_state_found = '0'
  186 +# =°2=Checking the number of inputs used : more than 1 inputs used
  187 + if(used_signal > 1):
  188 +# adding the intermediate node if global or needed
  189 + if global_or:
  190 + and_nodes.append(target)
  191 + add_vertices.append(target)
  192 +# Adding edges to the list
  193 + if cover[1] == '1':
  194 + to_add['and'][0].extend(edges_list)
  195 + elif cover[1] == '0':
  196 + to_add['nand'][0].extend(edges_list)
  197 +# =°2=Checking the number of inputs used : 1 input used
  198 + elif used_signal == 1:
  199 +# Adding the inputs directly for the global or
  200 + if global_or:
  201 + and_nodes.append(edges_list[0][0])
  202 +# If no global or, adding a BUF or a NOT depending on the input state (last_state_found)
  203 + else:
  204 + if last_state_found == '1':
  205 + to_add['buf'][0].extend(edges_list)
  206 + elif last_state_found == '0':
  207 +# if complemented version added just for this, redirecting the target node to the real output
  208 + if add_vertices[-1] == edges_list[0][0]:
  209 + nots_list.pop()
  210 + to_add['not'][0][-1] = (to_add['not'][0][-1][0], target)
  211 +# if complemented version added before, adding a buf from the complemented version to the output
  212 + else:
  213 + to_add['buf'][0].extend(edges_list)
  214 +# adding the global or for the function if needed
  215 + if global_or:
  216 + edges_list = []
  217 + for int_and in and_nodes:
  218 + edges_list.append((int_and, output))
  219 + to_add['or'][0].extend(edges_list)
  220 +# =°1=Check inputs number: 1 inputs
  221 + elif len(inputs) == 1:
  222 +# input state = output state => buf
  223 + if Def[1][0][1] == Def[1][0][0][0]:
  224 + to_add['buf'][0].append((inputs[0], output))
  225 +# input state =/= output state => not
  226 + else:
  227 + to_add['not'][0].append((inputs[0], output))
  228 +# displaying the last progress number
  229 + for _ in nbdisp:
  230 + print('\b', end='')
  231 + print(str(nb))
  232 +# Adding nodes to the graphe
  233 + for vertex in add_vertices:
  234 + g.add_vertex(vertex,
  235 + label=vertex,
  236 + color="#FFFFFF",
  237 + cat="node",
  238 + locks=[],
  239 + forced=[],
  240 + size=100,
  241 + label_size=30)
  242 +# Adding all edges to the graph ordered by function
  243 + for i in sorted(to_add, key=lambda i: len(to_add[i][0]), reverse=False):
  244 + if len(to_add[i][0]) > 0:
  245 + print('-> Adding ' + str(len(to_add[i][0])) + ' ' + i + '...')
  246 + adv_add_edges(g, to_add[i][0],
  247 + name=i,
  248 + label=i,
  249 + width=5,
  250 + arrow_size=2,
  251 + label_size=40,
  252 + color="#AAAAAA")
  253 +
  254 +def build(name, result=None, parsedbg=False, verbose=True):
  255 + """build(name, result=None, parsedbg=False)
  256 + Builds the graph from an EDIF netlist
  257 + @param name: name of the netlist to build
  258 + @keyword result(None): result set from the edif syntax reader. Avoid reading and use set given instead. Used mainly for debugging.
  259 + @keyword parsebg(False): Boolean used to disable graph generating and return the syntax reader set of the netlist choosen. Used mainly for debugging.
  260 +
  261 + @return a tuple of 4 elements : the graph for the netlist, the list of inputs, the list of outputs, the list of node (inputs and internal nodes)
  262 + """
  263 + print("---- Build BLIF")
  264 + if not verbose:
  265 + sys.stdout = open(os.devnull, 'w')
  266 + prim_in = [] #primary inputs of the netlist
  267 + prim_out = [] #primary outputs of the netlist
  268 + nodes = [] #nodes of the netlist
  269 + g = ig.Graph(directed=1)
  270 +# Setting base elements
  271 + InputWord = pp.Suppress('.' + pp.CaselessLiteral("INPUTS"))
  272 + OutputWord = pp.Suppress('.' + pp.CaselessLiteral("OUTPUTS"))
  273 + Node = pp.Word(pp.alphanums + '$/_[]()<>', bodyChars = pp.alphanums + '$/_[]()<>.')# /!\Attention aux caractères spéciaux !
  274 + SignalNames = pp.Suppress('.' + pp.CaselessLiteral("names")) + pp.Group(pp.ZeroOrMore(Node + pp.NotAny(pp.LineEnd()))) + Node + pp.Suppress(pp.LineEnd())
  275 +# Setting function reading elements
  276 + SignalValues = pp.ZeroOrMore(pp.Group(pp.Group(pp.OneOrMore(pp.NotAny(pp.White(' ')) + pp.Or(['1', '0','-']))) + pp.Or(['1', '0'])))
  277 + SignalDef = pp.Group(SignalNames) + pp.Group(SignalValues)
  278 +# Setting IOreading elements
  279 + Inputs = pp.OneOrMore(InputWord + pp.OneOrMore(Node))
  280 + Outputs = pp.OneOrMore(OutputWord + pp.OneOrMore(Node))
  281 +# Setting full parser
  282 + FullParser = pp.Suppress(pp.SkipTo(Inputs)) + pp.Group(Inputs) + pp.Group(Outputs) + pp.Group(pp.OneOrMore(pp.Group(SignalDef)))
  283 +# SignalNames.ignore(pp.Regex("\(\d*\)"))
  284 + FullParser.ignore('\\' + pp.LineEnd())
  285 +# Opening netlist file
  286 + path = "./../benchmarks/blif/"
  287 + source_file = path+name+".blif"
  288 +# Parsing if no data given
  289 + if result == None:
  290 + print("Parsing...")
  291 + result = FullParser.parseFile(source_file)
  292 +# Returning data readen without generating graph if needed
  293 + if parsedbg:
  294 + if not verbose:
  295 + sys.stdout = sys.__stdout__
  296 + print('---- Done (parsedbg)\n')
  297 + return result
  298 +# Generating graph with data readen or given adn returning
  299 + else:
  300 + AddInputs(result, g, prim_in, nodes)
  301 + AddOutputs(result, g, prim_in, prim_out)
  302 + AddGate(result, g, prim_out, nodes)
  303 + if not verbose:
  304 + sys.stdout = sys.__stdout__
  305 + print("---- Done\n")
  306 + return g, prim_in, prim_out, nodes
0 307 \ No newline at end of file
build_blif.pyc View file @ ea9b38c

No preview for this file type

build_edif.py View file @ ea9b38c
... ... @@ -0,0 +1,735 @@
  1 +# -*- coding: utf-8 -*-
  2 +"""
  3 +Author : Brice Colombier
  4 +Affiliation: Laboratoire Hubert Curien, UMR CNRS 5516
  5 + University of Lyon
  6 + 18 rue du Professeur Benoit Lauras
  7 + 42000 Saint-Etienne - France
  8 +Contact : b.colombier@univ-st-etienne.fr
  9 +
  10 +Title : Building the graph from the netlist
  11 +Project : Graph-based nodes selection for functional locking
  12 +
  13 +File : build_def.py
  14 +Last update: 2015-03-17
  15 +"""
  16 +
  17 +from __future__ import print_function
  18 +import igraph as ig
  19 +import pyparsing as pp
  20 +import clean_const
  21 +from cells_dict import edif_cells
  22 +import time
  23 +import sys
  24 +import os
  25 +
  26 +#pp.ParserElement.enablePackrat()
  27 +
  28 +def adv_add_edges(g, es, instances, **kwds):
  29 + """adv_add_edges(es, **kwds)
  30 +
  31 + Adds multiple edges to the graph with a unique set of keywords.
  32 +
  33 + Keyword arguments (except the source and target arguments) will be
  34 + assigned to added edges as attributes.
  35 + @param g : the graph where to add given edges
  36 + @param es: list of source - dest tuples to add
  37 + @param instances: list of instances names to add corresponding to edges
  38 + @param **kwds : attributes to add to all the edges
  39 +
  40 + @return result of igraph.add_edges()
  41 + """
  42 +
  43 + if len(es) != len(instances):
  44 + raise Exception('Length of es different than length of instances')
  45 + if not kwds:
  46 + return g.add_edges(es)
  47 +# Getting next edge ID
  48 + eid = g.ecount()
  49 +# Adding all the edges from es to the graphe
  50 + result = g.add_edges(es)
  51 +# Adding Keywords and instance name to all the edges
  52 + for i, _ in enumerate(es):
  53 + for key, value in kwds.iteritems():
  54 + g.es[eid + i][key] = value
  55 + g.es[eid + i]['instance'] = instances[i]
  56 + return result
  57 +
  58 +def AddIO(toks, g, prim_in, prim_out, nodes):
  59 + """AddIO(toks)
  60 +
  61 + Add Inputs and Outputs to the graph
  62 +
  63 + @param toks: pyparsing result for the edif syntax
  64 + toks[0] : external libraries list
  65 + toks[1] : internal cells list
  66 + toks[2] : described cell's name
  67 + @param g: igraph instance to complete with inputs and outputs
  68 + @param prim_in: list to fill with inputs
  69 + @param prim_out: list to fill with outputs
  70 + @param nodes: list to fill with signal which can be inputs of functions
  71 + """
  72 + print("AddIO") #Debug
  73 +# Searching for global cell id in the internal lib
  74 + for ID, cell in enumerate(toks[1]):
  75 + if cell[0] == toks[2]:
  76 + global_cell_ID = ID
  77 + break
  78 +# Reading all the IO bus of the global cell
  79 + for IODecl in toks[1][global_cell_ID][1]:
  80 +# Looping for the size of the bus
  81 + for i in range(int(IODecl[1])):
  82 +# Getting direction of the port and adding id in bus if multiple ports in the same bus
  83 + Dir = IODecl[2]
  84 + if int(IODecl[1]) == 1:
  85 + InputOutput = IODecl[0]
  86 + else:
  87 + InputOutput = IODecl[0] + '_' + str(i)
  88 +# Adding ports
  89 + if Dir == "INPUT":
  90 + if not InputOutput in prim_in:
  91 + g.add_vertex(InputOutput,
  92 + label=InputOutput,
  93 + color="#DDDDDD",
  94 + cat="input",
  95 + locks=[],
  96 + forced=[],
  97 + size=100,
  98 + label_size=30)
  99 + prim_in.append(InputOutput)
  100 + nodes.append(InputOutput)
  101 +
  102 + elif Dir == "OUTPUT":
  103 + if (not InputOutput in prim_in) and (not InputOutput in prim_out):
  104 + prim_out.append(InputOutput)
  105 + g.add_vertex(InputOutput,
  106 + label=InputOutput,
  107 + color="#666666",
  108 + cat="output",
  109 + locks=[0, 1],#By convention
  110 + forced=[],
  111 + size=100,
  112 + label_size=30)
  113 +
  114 +def GateFinder(Component_name, internal_cells):
  115 + """GateFinder(Component_name)
  116 +
  117 + Dictionnary which allow to find which model associate with which cell name
  118 + If the cell isn't described, raise an Exception with the name of the gate which caused the error.
  119 +
  120 + @param Component_name: name of the edif cell to represent
  121 + @param internal_cells: dictionnary containing models of internal cells to determine internal cell's type
  122 +
  123 + @return the gate type corresponding to the name given in Component_name.
  124 + Can be:
  125 + - The name of a standard cell (not, buf, and, nand, or, nor, xor, xnor)
  126 + - A tuple containing first the library (internal or software) where the cell is described, and second the name of the cell in this library.
  127 + """
  128 +# removing useless informations before checking cell type
  129 + comp_array = Component_name.split('_')
  130 + number_del = ''
  131 + while comp_array[0][-1] in '0123456789':
  132 +# memorizing removed number for some uses
  133 + number_del = comp_array[0][-1] + number_del
  134 + comp_array[0] = comp_array[0][:-1]
  135 +# returning datas depending on the cell name
  136 + if comp_array[0].upper() == 'INV':
  137 + result = 'not'
  138 + sequential = False
  139 + elif Component_name[0:5].upper() == 'LOGIC':
  140 + result = ('const', Component_name[-1])
  141 + sequential = False
  142 + elif comp_array[0].upper() == 'DFF':
  143 + result = 'latch'
  144 + sequential = True
  145 + elif comp_array[0].upper() in ['AND','NAND', 'OR', 'NOR', 'XOR', 'XNOR', 'BUF']:
  146 + result = comp_array[0].lower()
  147 + sequential = False
  148 + elif comp_array[0].upper() in ['OAI', 'AOI', 'AO', 'OA']:
  149 + result = (comp_array[0].lower(), number_del)
  150 + sequential = False
  151 + elif Component_name.upper() == 'MUX21':
  152 + result = ('software', Component_name.upper())
  153 + sequential = False
  154 + elif comp_array[0].upper() == 'FLIP':
  155 + result = ('software', comp_array[0].upper())
  156 + sequential = True
  157 + elif Component_name in internal_cells.keys():
  158 + result = ('internal', Component_name)
  159 + sequential = False
  160 +# Raising an exception if the cell is not known
  161 + else:
  162 + raise Exception('unknown gate ' + Component_name + '. Maybe it is not yet implemented...')
  163 +# retunring datas
  164 + return sequential, result
  165 +
  166 +def BuildCell(toks, gate_dict, internal_cells, ExtSeq=False):
  167 + """BuildCell(toks)
  168 + Build a model for each cells discribed in the internal library
  169 +
  170 + Models are stored in global variable internal_cells for easy access for other function in this script
  171 +
  172 + @param toks: pyparsing result for the edif syntax
  173 + toks[0] : external libraries list
  174 + toks[1] : internal cells list
  175 + toks[2] : described cell's name
  176 + @param gate_dict: dictionnary containing ports of cells used in the file
  177 + @param internal_cells: dictionnary to fill with models builded
  178 + @keyword ExtSeq(False): indicate if the model should externalise DFF by formating connected nodes to indicate if they are inputs or outputs.
  179 + """
  180 + alpha = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
  181 +# building a dictionary containig all ports of cells
  182 + for lib in toks[0]:
  183 + for Gate in lib[1]:
  184 + IOList = []
  185 + for IOBus in Gate[1]:
  186 + for bit in range(int(IOBus[1])):
  187 + IOList.append((IOBus[0] + '_' + str(bit), IOBus[2]))
  188 + gate_dict[Gate[0]] = IOList
  189 +
  190 + print('Building Cells')
  191 +# Reading all internal cells
  192 + for cell in toks[1]:
  193 +
  194 + int_in = [] #cell's input list
  195 + int_out = [] #cell's output list
  196 + int_conv_name = {} #cell's dict of name conv
  197 +
  198 +# Checking if current cell is global cell
  199 + if cell[0] == toks[2]:
  200 +# Skip the final cell
  201 + continue
  202 +
  203 + print('-> Building cell ' + cell[0])
  204 + CellName = cell[0]
  205 + internal_cells[CellName] = [[], []]
  206 +# generating ports name from bus of the cell
  207 + for IOBus in cell[1]:
  208 +# putting inputs in int_in
  209 + if IOBus[2] == 'INPUT':
  210 + for i in range(int(IOBus[1])):
  211 + int_in.append(IOBus[0] + '_' + str(i))
  212 +# putting outputs in int_out
  213 + else:
  214 + for i in range(int(IOBus[1])):
  215 + int_out.append(IOBus[0] + '_' + str(i))
  216 +# Reading all links to build links' dictionary
  217 + for Net in cell[3]:
  218 + node_name = Net[0]
  219 +# adding the signal to the model if not an input or an output
  220 + if (not node_name in int_in) and (not node_name in int_out):
  221 + internal_cells[CellName][0].append(node_name)
  222 +# adding each port linked to the signal in the links' dictionary
  223 + for signal in Net[1:]:
  224 + signal_name = signal[0] + '_' + signal[1]
  225 +# if instance reference of the port is 'none', the port is part of IOs of the cell
  226 + if signal[2] != 'none':
  227 + int_conv_name[signal_name + '@' + signal[2]] = node_name
  228 + else:
  229 +# adding an edge between the port and the signal if the name is different
  230 + if signal_name != node_name:
  231 + if signal_name in int_in:
  232 + internal_cells[CellName][1].append([('{' + signal_name + '}', node_name), 'buf', '{' + signal_name + '}' + 'TO' + node_name])
  233 + elif signal_name in int_out:
  234 + internal_cells[CellName][1].append([(node_name, '{' + signal_name + '}'), 'buf', node_name + 'TO' + '{' + signal_name + '}'])
  235 +# If instance ref is 'none' and port is not an input nor an output, it's incoherent. Raise an exception
  236 + else:
  237 + raise Exception("alone signal " + signal_name + ' in net ' + node_name + " not an input nor an output")
  238 +# Reading all instance of the cell
  239 + for Instance in cell[2]:
  240 + Inst_name = Instance[0]
  241 + inputs = []
  242 + output = ''
  243 +# if the cell isn't modelised, spliting inputs from output
  244 + if (not Instance[1] in internal_cells.keys()) and not(Instance[1] == 'dff'):
  245 + for IO in gate_dict[Instance[1]]:
  246 + global_IO_name = IO[0] + '@' + Inst_name
  247 + if IO[1] == 'INPUT':
  248 + inputs.append(int_conv_name[global_IO_name])
  249 + else:
  250 + if output == '':
  251 + output = int_conv_name[global_IO_name]
  252 + else:
  253 + print('Warning ! : more than one Output for Gate ' + Instance[1])
  254 +# Getting datas from GateFinder
  255 + sequential, function = GateFinder(Instance[1], internal_cells)
  256 +# if instanciated cell is a DFF and flag ExtSeq as true, use special syntax in the model : [<dir_char><signal_name>]
  257 + if sequential and ExtSeq :
  258 + for IO in gate_dict[Instance[1]]:
  259 +# replacing names in nodes list
  260 + if int_conv_name.has_key(IO[0] + '@' + Inst_name):
  261 + if IO[1] == 'INPUT':
  262 + if not '[O' + int_conv_name[IO[0] + '@' + Inst_name] + ']' in internal_cells[0]:
  263 + internal_cells[0].remove(int_conv_name[IO[0] + '@' + Inst_name])
  264 + internal_cells[0].append('[O' + int_conv_name[IO[0] + '@' + Inst_name] + ']')
  265 + if IO[1] == 'OUTPUT':
  266 + if not '[I' + int_conv_name[IO[0] + '@' + Inst_name] + ']' in internal_cells[0]:
  267 + internal_cells[0].remove(int_conv_name[IO[0] + '@' + Inst_name])
  268 + internal_cells[0].append('[I' + int_conv_name[IO[0] + '@' + Inst_name] + ']')
  269 + else:
  270 +# type 'latch'
  271 + if function == 'latch':
  272 + output_linked = False
  273 +# adding edge for QB output if needed
  274 + if int_conv_name.has_key('QB_0@' + Inst_name):
  275 + output_linked = True
  276 + internal_cells[CellName][1].append([(int_conv_name['D_0@' + Inst_name], int_conv_name['QB_0@' + Inst_name]), 'not', 'not_' + Inst_name])
  277 +# adding edge for Q output if needed
  278 + if int_conv_name.has_key('Q_0@' + Inst_name):
  279 + output_linked = True
  280 + internal_cells[CellName][1].append([(int_conv_name['D_0@' + Inst_name], int_conv_name['Q_0@' + Inst_name]), 'buf', 'buf_' + Inst_name])
  281 +# raise an exception if no output linked
  282 + if not output_linked:
  283 + raise Exception('Q and Q\' of a non-reset latch not linked to a node')
  284 +# type 'const'
  285 + elif function[0] == 'const':
  286 +# adding const edge from the right const source
  287 + internal_cells[CellName][1].append([('Logic' + function[1], int_conv_name['O_0@' + Inst_name]), function[1], Inst_name])
  288 +# type ao, aoi, oa , or oai
  289 + elif function[0] in ['oai', 'aoi', 'ao', 'oa']:
  290 +# looking for functions to use
  291 + if function[0][0] == 'a':
  292 + lvl1 = 'and'
  293 + if function[0][-1] == 'i':
  294 + lvl2 = 'nor'
  295 + else:
  296 + lvl2 = 'or'
  297 + else:
  298 + lvl1 = 'or'
  299 + if function[0][-1] == 'i':
  300 + lvl2 = 'nand'
  301 + else:
  302 + lvl2 = 'and'
  303 +
  304 + to_group = []
  305 + inp_ID = 0
  306 +# reading numbers form the end of cell name
  307 + for i, group in enumerate(function[1]):
  308 +# grouping inputs with level 1 functions and adding functions outputs to 'to_group'
  309 + if not group == '1':
  310 + internal_cells[CellName][0].append(alpha[i] + '_' + Inst_name)
  311 + to_group.append(alpha[i] + '_' + Inst_name)
  312 + for _ in range(int(group)):
  313 + internal_cells[CellName][1].append([(inputs[inp_ID], alpha[i] + '_' + Inst_name), lvl1, lvl1 + str(i) + '_' + Inst_name])
  314 + inp_ID += 1
  315 +# if only one input, adding it to 'to_group'
  316 + else:
  317 + to_group.append(inputs[inp_ID])
  318 + inp_ID += 1
  319 +# grouping nodes in 'to_group' with level 2 function to the output
  320 + for node in to_group:
  321 + internal_cells[CellName][1].append([(node, output), lvl2, lvl2 + '_' + Inst_name])
  322 +# type 'software'
  323 + elif function[0] == 'software':
  324 +# getting model from software library
  325 + cell_vert = edif_cells[function[1]][0]
  326 + cell_edge = edif_cells[function[1]][1]
  327 +# adding model nodes with instance name at the end
  328 + for node in cell_vert:
  329 + internal_cells[CellName][0].append(node + '_' + Inst_name)
  330 +# adding model's edges
  331 + for edge in cell_edge:
  332 +# replacing source name between brackets '{}' by corresponding name from links' dictionary
  333 + if edge[0][0][0] == '{':
  334 + edge_source = int_conv_name[edge[0][0][1:-1] + '@' + Inst_name]
  335 + else:
  336 + edge_source = edge[0][0] + '_' + Inst_name
  337 +# replacing target name between brackets '{}' by corresponding name from links' dictionary
  338 + if edge[0][1][0] == '{':
  339 + edge_target = int_conv_name[edge[0][1][1:-1] + '@' + Inst_name]
  340 + else:
  341 + edge_target = edge[0][1] + '_' + Inst_name
  342 +# adding edge to the modelin construction
  343 + internal_cells[CellName][1].append([(edge_source, edge_target), edge[1], edge[2] + '_' + Inst_name])
  344 +# other types
  345 + else:
  346 +# adding edge from each input to output using type as function
  347 + for inp in inputs:
  348 + internal_cells[CellName][1].append([(inp, output), function, Inst_name])
  349 +
  350 +def AddGate(toks, g, gate_dict, name_conv, internal_cells, ExtSeq=False):
  351 + """AddGate(toks)
  352 +
  353 + Add edges to the graph
  354 +
  355 + @param toks: pyparsing result for the edif syntax
  356 + toks[0] : external libraries list
  357 + toks[1] : internal cells list
  358 + toks[2] : described cell's name
  359 + @param g: igraph instance to complete
  360 + @param gate_dict: dictionnary of ports for gates used in the file
  361 + @param name_conv: dictionnary of node name linked to ports (using global ports names)
  362 + @param internal_cells: dictionnary of models to use for internal cell type
  363 + @keyword ExtSeq(False): indicate if the graph should externalise sequential standards cells by putting connected nodes as input or output.
  364 + """
  365 + print("AddGates")
  366 +# adding value forcing nodes
  367 + g.add_vertex('Logic0',
  368 + label='Logic0',
  369 + color="#FF0000",
  370 + cat="const",
  371 + locks=[],
  372 + forced=[],
  373 + size=100,
  374 + label_size=30)
  375 + g.add_vertex('Logic1',
  376 + label='Logic1',
  377 + color="#FF0000",
  378 + cat="const",
  379 + locks=[],
  380 + forced=[],
  381 + size=100,
  382 + label_size=30)
  383 +# initializing vars
  384 + alpha = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
  385 + to_add_edges = {'and':[[],[]], 'nand':[[],[]], 'or':[[],[]], 'nor':[[],[]], 'xor':[[],[]], 'xnor':[[],[]], 'not':[[],[]], 'buf':[[],[]], '0':[[],[]], '1':[[],[]]}
  386 +# searching for global cell id in the internal lib
  387 + for ID, cell in enumerate(toks[1]):
  388 + if cell[0] == toks[2]:
  389 + global_cell_ID = ID
  390 + break
  391 +# Initializing progress display
  392 + nb = 0
  393 + disp_time = time.time()
  394 + nbdisp = '0'
  395 + print('-> ' + str(len(toks[1][global_cell_ID][2])) + '/' + nbdisp, end='')
  396 +# reading instances of global cell
  397 + for Instance in toks[1][global_cell_ID][2]:
  398 +# Updating progress display every 0.5s
  399 + nb += 1
  400 + if time.time() >= disp_time + 0.5:
  401 + disp_time += 0.5
  402 + for _ in nbdisp:
  403 + print('\b', end='')
  404 + nbdisp = str(nb)
  405 + print(nbdisp, end='')
  406 +
  407 + Inst_name = Instance[0]
  408 + inputs = []
  409 + output = ''
  410 +# if cell doesn't have a model, separating inputs and output
  411 + if not(Instance[1].upper() in edif_cells.keys()) and not(Instance[1] in internal_cells.keys()) and not(Instance[1] == 'dff'):
  412 + for IO in gate_dict[Instance[1]]:
  413 + global_IO_name = IO[0] + '@' + Inst_name
  414 + if IO[1] == 'INPUT':
  415 + inputs.append(name_conv[global_IO_name])
  416 + else:
  417 + if output == '':
  418 + output = name_conv[global_IO_name]
  419 + else:
  420 + print('Warning ! : more than one Output for Gate ' + Instance[1])
  421 +# gathering data from GateFinder
  422 + sequential, function = GateFinder(Instance[1], internal_cells)
  423 +# if instanciated cell is a DFF and flag ExtSeq as true, putting inputs and outputs nodes as ports of the global ports
  424 + if sequential and ExtSeq :
  425 + for IO in gate_dict[Instance[1]]:
  426 +# setting node dir depending on instantiated cell's port dir
  427 + if name_conv.has_key(IO[0] + '@' + Inst_name):
  428 + if IO[1] == 'INPUT':
  429 + direction = 'output'
  430 + if IO[1] == 'OUTPUT':
  431 + direction = 'input'
  432 +# changing categeorie of linked nodes if internal node
  433 + if g.vs.find(name=name_conv[IO[0] + '@' + Inst_name])['cat'] == 'node':
  434 + g.vs.find(name=name_conv[IO[0] + '@' + Inst_name])['cat'] = direction
  435 +
  436 + else:
  437 +# type 'latch'
  438 + if function == 'latch':
  439 + output_linked = False
  440 +# adding edge for QB output if needed
  441 + if name_conv.has_key('QB_0@' + Inst_name):
  442 + output_linked = True
  443 + to_add_edges['not'][0].append((name_conv['D_0@' + Inst_name], name_conv['QB_0@' + Inst_name]))
  444 + to_add_edges['not'][1].append('not_' + Inst_name)
  445 +# adding edge for Q output if needed
  446 + if name_conv.has_key('Q_0@' + Inst_name):
  447 + output_linked = True
  448 + to_add_edges['buf'][0].append((name_conv['D_0@' + Inst_name], name_conv['Q_0@' + Inst_name]))
  449 + to_add_edges['buf'][1].append('buf_' + Inst_name)
  450 +# raise an exception if no output linked
  451 + if not output_linked:
  452 + raise Exception('Q and Q\' of a non-reset latch not linked to a node')
  453 +# type 'const'
  454 + elif function[0] == 'const':
  455 +# adding const edge from the right const source
  456 + to_add_edges[function[1]][0].append(('Logic' + function[1], name_conv['O_0@' + Inst_name]))
  457 + to_add_edges[function[1]][1].append(Inst_name)
  458 +# type ao, aoi, oa , or oai
  459 + elif function[0] in ['oai', 'aoi', 'ao', 'oa']:
  460 +# looking for functions to use
  461 + if function[0][0] == 'a':
  462 + lvl1 = 'and'
  463 + if function[0][-1] == 'i':
  464 + lvl2 = 'nor'
  465 + else:
  466 + lvl2 = 'or'
  467 + else:
  468 + lvl1 = 'or'
  469 + if function[0][-1] == 'i':
  470 + lvl2 = 'nand'
  471 + else:
  472 + lvl2 = 'and'
  473 +
  474 + to_group = []
  475 + inp_ID = 0
  476 +# reading numbers form the end of cell name
  477 + for i, group in enumerate(function[1]):
  478 +# grouping inputs with level 1 functions and adding functions outputs to 'to_group'
  479 + if not group == '1':
  480 + g.add_vertex(alpha[i] + '_' + Inst_name,
  481 + label=alpha[i] + '_' + Inst_name,
  482 + color="#FFFFFF",
  483 + cat="node",
  484 + locks=[],
  485 + forced=[],
  486 + size=100,
  487 + label_size=30)
  488 + to_group.append(alpha[i] + '_' + Inst_name)
  489 + for _ in range(int(group)):
  490 + to_add_edges[lvl1][0].append((inputs[inp_ID], alpha[i] + '_' + Inst_name))
  491 + to_add_edges[lvl1][1].append(lvl1 + str(i) + '_' + Inst_name)
  492 + inp_ID += 1
  493 +# if only one input, adding it to 'to_group'
  494 + else:
  495 + to_group.append(inputs[inp_ID])
  496 + inp_ID += 1
  497 +# grouping nodes in 'to_group' with level 2 function to the output
  498 + for node in to_group:
  499 + to_add_edges[lvl2][0].append((node, output))
  500 + to_add_edges[lvl2][1].append(lvl2 + '_' + Inst_name)
  501 +# type 'software' and 'internal'
  502 + elif function[0] in ['internal', 'software']:
  503 +# getting model from the right library
  504 + if function[0] == 'internal':
  505 + cell_vert = internal_cells[function[1]][0]
  506 + cell_edge = internal_cells[function[1]][1]
  507 + elif function[0] == 'software':
  508 + cell_vert = edif_cells[function[1]][0]
  509 + cell_edge = edif_cells[function[1]][1]
  510 +# Adding model's nodes
  511 + for node in cell_vert:
  512 +# checking if the node should be placed as in put or output and defining attributes
  513 + if node[0] == '[':
  514 + node_name = node[2:-1]
  515 + if node[1] == 'I':
  516 + node_color = '#DDDDDD'
  517 + categorie = 'input'
  518 + if node[0] == 'O':
  519 + node_color = '#666666'
  520 + categorie = 'output'
  521 + else:
  522 + raise Exception('wrong internal IO latch def : ' + node)
  523 + else: