Module circuitgraph.transform
Functions for transforming circuits
Expand source code
"""Functions for transforming circuits"""
import math
import code
from subprocess import PIPE, Popen
import subprocess
from tempfile import NamedTemporaryFile
from random import sample
import os
import shutil
import networkx as nx
from circuitgraph import Circuit
from circuitgraph.utils import clog2, lint
from circuitgraph.io import verilog_to_circuit, circuit_to_verilog
def copy(c):
"""
Returns copy of a circuit.
Parameters
----------
c: Circuit
circuit to rename
Returns
-------
Circuit
Relabeled circuit.
"""
return Circuit(graph=c.graph.copy(), name=c.name)
def relabel(c, mapping):
"""
Returns renamed copy of a circuit.
Parameters
----------
c: Circuit
circuit to rename
mapping : dict of str:str
mapping of old to new names
Returns
-------
Circuit
Relabeled circuit.
"""
return Circuit(graph=nx.relabel_nodes(c.graph, mapping), name=c.name)
def strip_io(c):
"""
Removes a circuit's outputs and converts inputs to buffers for easy
instantiation.
Parameters
----------
c : Circuit
circuit to strip io from
Returns
-------
Circuit
Circuit with removed io
"""
g = c.graph.copy()
for o in c.outputs():
g.nodes[o]["output"] = False
for i in c.inputs():
g.nodes[i]["type"] = "buf"
return Circuit(graph=g, name=c.name)
def strip_outputs(c):
"""
Removes a circuit's outputs for easy
instantiation.
Parameters
----------
c : Circuit
circuit to strip io from
Returns
-------
Circuit
Circuit with removed io
"""
g = c.graph.copy()
for o in c.outputs():
g.nodes[o]["output"] = False
return Circuit(graph=g, name=c.name)
def strip_inputs(c):
"""
Converts inputs to buffers for easy
instantiation.
Parameters
----------
c : Circuit
circuit to strip inputs from
Returns
-------
Circuit
Circuit with removed io
"""
g = c.graph.copy()
for i in c.inputs():
g.nodes[i]["type"] = "buf"
return Circuit(graph=g, name=c.name)
def seq_graph(c):
"""
Creates a Circuit of the sequential elements and IO.
Parameters
----------
c: Circuit
Returns
-------
Circuit
Sequential circuit.
"""
s = Circuit(name=f"{c.name}_seq")
# add nodes
for n in c.inputs() | c.seq():
s.add(n, c.type(n), output=c.output(n))
# add edges
for n in c.seq():
s.connect(c.startpoints(c.d(n)), n)
# add outputs
for n in s:
if c.endpoints(n) & c.outputs():
s.set_output(n, True)
return s
def syn(c, engine, print_output=False):
"""
Synthesizes the circuit using Genus.
Parameters
----------
c : Circuit
Circuit to synthesize.
engine : str
Synthesis tool to use ('Genus' or 'Yosys')
print_output : bool
Option to print synthesis log
Returns
-------
Circuit
Synthesized circuit.
"""
verilog = circuit_to_verilog(c)
with NamedTemporaryFile(prefix="circuitgraph_syn_genus_input") as tmp_in:
tmp_in.write(bytes(verilog, "ascii"))
tmp_in.flush()
with NamedTemporaryFile(prefix="circuitgraph_syn_genus_output") as tmp_out:
if engine == "Genus":
cmd = [
"genus",
"-no_gui",
"-execute",
"set_db / .library "
f"{os.environ['CIRCUITGRAPH_GENUS_LIBRARY_PATH']};\n"
f"read_hdl -sv {tmp_in.name};\n"
"elaborate;\n"
"set_db syn_generic_effort high;\n"
"syn_generic;\n"
"syn_map;\n"
"syn_opt;\n"
f'redirect {tmp_out.name} "write_hdl -generic";\n'
"exit;",
]
elif engine == "Yosys":
cmd = [
"yosys",
"-p",
f"read_verilog {tmp_in.name}; "
"proc; opt; fsm; opt; memory; opt; clean; "
f"write_verilog -noattr {tmp_out.name}",
]
else:
raise ValueError("synthesis engine must be Yosys or Genus")
process = Popen(cmd, stdout=PIPE, stderr=PIPE, universal_newlines=True)
while True:
line = process.stdout.readline()
if line == "" and process.poll() is not None:
break
if line:
if print_output:
print(line.strip())
output = tmp_out.read().decode("utf-8")
if print_output:
print(output)
return verilog_to_circuit(output, c.name)
def ternary(c):
"""
Encodes the circuit with ternary values
Parameters
----------
c : Circuit
Circuit to encode.
Returns
-------
Circuit
Encoded circuit.
"""
t = copy(c)
# add dual nodes
for n in c:
if c.type(n) in ["and", "nand"]:
t.add(f"{n}_x", "and", output=c.output(n))
t.add(
f"{n}_x_in_fi",
"or",
fanout=f"{n}_x",
fanin=[f"{p}_x" for p in c.fanin(n)],
)
t.add(f"{n}_0_not_in_fi", "nor", fanout=f"{n}_x")
for p in c.fanin(n):
t.add(
f"{p}_is_0", "nor", fanout=f"{n}_0_not_in_fi", fanin=[p, f"{p}_x"]
)
elif c.type(n) in ["or", "nor"]:
t.add(f"{n}_x", "and", output=c.output(n))
t.add(
f"{n}_x_in_fi",
"or",
fanout=f"{n}_x",
fanin=[f"{p}_x" for p in c.fanin(n)],
)
t.add(f"{n}_1_not_in_fi", "nor", fanout=f"{n}_x")
for p in c.fanin(n):
t.add(f"{p}_is_1", "and", fanout=f"{n}_1_not_in_fi", fanin=p)
t.add(f"{p}_not_x", "not", fanout=f"{p}_is_1", fanin=f"{p}_x")
elif c.type(n) in ["buf", "not"]:
p = c.fanin(n).pop()
t.add(f"{n}_x", "buf", output=c.output(n), fanin=f"{p}_x")
elif c.type(n) in ["xor", "xnor"]:
t.add(
f"{n}_x", "or", output=c.output(n), fanin=(f"{p}_x" for p in c.fanin(n))
)
elif c.type(n) in ["0", "1"]:
t.add(f"{n}_x", "0", output=c.output(n))
elif c.type(n) in ["input"]:
t.add(f"{n}_x", "input", output=c.output(n))
elif c.type(n) in ["ff", "lat"]:
t.add(
f"{n}_x",
c.type(n),
output=c.output(n),
clk=f"{c.clk(n)}_x",
r=f"{c.r(n)}_x",
s=f"{c.s(n)}_x",
fanin=f"{c.fanin(n).pop()}_x",
)
elif c.type(n) in ["0", "1"]:
continue
return t
def miter(c0, c1=None, startpoints=None, endpoints=None):
"""
Creates a miter circuit
Parameters
----------
c0 : Circuit
First circuit.
c1 : Circuit
Optional second circuit, if None c0 is mitered with itself.
startpoints : set of str
Nodes to be tied together, must exist in both circuits.
endpoints : set of str
Nodes to be compared, must exist in both circuits.
Returns
-------
Circuit
Miter circuit.
"""
# clean inputs
if not c1:
c1 = c0
if not startpoints:
startpoints = c0.startpoints() & c1.startpoints()
if not endpoints:
endpoints = c0.endpoints() & c1.endpoints()
# create miter, relabel
m = relabel(c0, {n: f"c0_{n}" for n in c0.nodes() - startpoints})
m.extend(relabel(c1, {n: f"c1_{n}" for n in c1.nodes() - startpoints}))
strip_outputs(m)
# compare endpoints
m.add("sat", "or", output=True)
for o in endpoints - startpoints:
m.add(f"miter_{o}", "xor", fanout=["sat"], fanin=[f"c0_{o}", f"c1_{o}"])
return m
def comb(c):
"""
Creates combinational version of the circuit.
Parameters
----------
c : Circuit
Sequential circuit to make combinational.
Returns
-------
Circuit
Combinational circuit.
"""
import circuitgraph.logic as logic
c_comb = copy(c)
lat_model = logic.comb_lat()
ff_model = logic.comb_ff()
for s in c.seq():
model = lat_model if c.type(s) == "lat" else ff_model
relabeled_model = relabel(model, {n: f"{s}_{n}" for n in model})
c_comb.extend(relabeled_model)
c_comb.connect(f"{s}_q", c_comb.fanout(s))
c_comb.connect(c_comb.fanin(s), f"{s}_d")
if c.clk(s):
c_comb.connect(c.clk(s), f"{s}_clk")
if c.r(s):
c_comb.connect(c.r(s), f"{s}_rst")
if c.s(s):
c_comb.connect(c.s(s), f"{s}_set")
c_comb.remove(s)
return c_comb
def unroll(c, cycles):
"""
Creates combinational unrolling of the circuit.
Parameters
----------
c : Circuit
Sequential circuit to unroll.
cycles : int
Number of cycles to unroll
Returns
-------
Circuit
Unrolled circuit.
"""
u = Circuit()
c_comb = comb(c)
for i in range(cycles):
u.extend(c_comb, {n: f"{n}_{i}" for n in c_comb})
if i == 0:
# convert si to inputs
for n in c:
if c.type(n) in ["lat", "ff"]:
u.set_type(f"{n}_si_{i}", "input")
else:
# connect prev si
for n in c:
if c.type(n) in ["lat", "ff"]:
u.connect(f"{n}_si_{i-1}", f"{n}_si_{i}")
return u
def influence_transform(c, n, s):
"""
Creates a circuit to compute sensitivity.
Parameters
----------
c : Circuit
Sequential circuit to unroll.
n : str
Node to compute influence at.
s : str
Startpoint to compute influence for.
Returns
-------
Circuit
Influence circuit.
"""
# check if s is in startpoints
sp = c.startpoints(n)
if s not in sp:
raise ValueError(f"{s} is not in startpoints of {n}")
# get input cone
fiNodes = c.transitive_fanin(n) | set([n])
sub_c = Circuit(c.graph.subgraph(fiNodes).copy())
# remove outs, convert startpoints
sub_c.set_output(sub_c.outputs(), False)
sub_c.set_type(sub_c.startpoints(), "input")
# create two copies of sub circuit
infl = Circuit(name=f"infl_{s}_on_{n}")
infl.extend(sub_c)
infl.extend(relabel(sub_c, {g: f"s1_{g}" for g in sub_c if g not in sp - set([s])}))
infl.add("sat", "xor", fanin=[n, f"s1_{n}"], output=True)
infl.add(f"not_{s}", "not", fanin=s, fanout=f"s1_{s}")
return infl
def sensitivity_transform(c, n, startpoints=None):
"""
Creates a circuit to compute sensitivity.
Parameters
----------
c : Circuit
Sequential circuit to unroll.
n : str
Node to compute sensitivity at.
startpoints : iterable of str
startpoints of n to flip.
Returns
-------
Circuit
Sensitivity circuit.
"""
import circuitgraph.logic as logic
# choose all startpoints if not specified
if startpoints is None:
startpoints = c.startpoints(n)
all_startpoints = c.startpoints(n)
# get fanin cone of node
if n in c.startpoints():
raise ValueError(f"{n} is in startpoints")
# get input cone
fiNodes = c.transitive_fanin(n) | set([n])
sub_c = Circuit(c.graph.subgraph(fiNodes).copy())
# remove outs, convert startpoints
sub_c.set_output(sub_c.outputs(), False)
sub_c.set_type(sub_c.startpoints(), "input")
sub_c.disconnect(sub_c.nodes(), sub_c.startpoints())
# create sensitivity circuit and add first copy of subcircuit
sen = Circuit()
sen.extend(sub_c)
# instantiate population count
p = strip_io(logic.popcount(len(startpoints)))
p = relabel(p, {g: f"pop_{g}" for g in p})
sen.extend(p)
for o in range(clog2(len(startpoints) + 1)):
sen.add(f"out_{o}", "buf", fanin=f"pop_out_{o}", output=True)
# stamp out a copies of the circuit with s inverted
for i, s in enumerate(startpoints):
mapping = {
g: f"sen_{s}_{g}" for g in sub_c if g not in all_startpoints - set([s])
}
sen.extend(relabel(sub_c, mapping))
# connect inverted input
sen.set_type(f"sen_{s}_{s}", "not")
sen.connect(s, f"sen_{s}_{s}")
# compare to first copy
sen.add(
f"difference_{s}",
"xor",
fanin=[n, f"sen_{s}_{n}"],
fanout=f"pop_in_{i}",
output=True,
)
return sen
def sensitization_transform(c, n):
"""
Creates a circuit to sensitize a node to an endpoint.
Parameters
----------
c : Circuit
Input circuit.
n : str
Node to sensitize.
Returns
-------
Circuit
Output circuit.
"""
# create miter, relabel
s = copy(c)
s.extend(relabel(c, {n: f"c1_{n}" for n in c}))
strip_outputs(s)
# connect startpoints
for g in c.startpoints():
s.set_type(f"c1_{g}", "buf")
s.disconnect(s.fanin(f"c1_{g}"), f"c1_{g}")
s.connect(g, f"c1_{g}")
# compare endpoints
s.add("sat", "or", output=True)
for o in c.endpoints():
s.add(f"miter_{o}", "xor", fanout=["sat"], fanin=[o, f"c1_{o}"])
# flip node in c1
s.disconnect(s.fanin(f"c1_{n}"), f"c1_{n}")
s.set_type(f"c1_{n}", "not")
s.connect(n, f"c1_{n}")
return s
Functions
def comb(c)
-
Creates combinational version of the circuit.
Parameters
c
:Circuit
- Sequential circuit to make combinational.
Returns
Circuit
- Combinational circuit.
Expand source code
def comb(c): """ Creates combinational version of the circuit. Parameters ---------- c : Circuit Sequential circuit to make combinational. Returns ------- Circuit Combinational circuit. """ import circuitgraph.logic as logic c_comb = copy(c) lat_model = logic.comb_lat() ff_model = logic.comb_ff() for s in c.seq(): model = lat_model if c.type(s) == "lat" else ff_model relabeled_model = relabel(model, {n: f"{s}_{n}" for n in model}) c_comb.extend(relabeled_model) c_comb.connect(f"{s}_q", c_comb.fanout(s)) c_comb.connect(c_comb.fanin(s), f"{s}_d") if c.clk(s): c_comb.connect(c.clk(s), f"{s}_clk") if c.r(s): c_comb.connect(c.r(s), f"{s}_rst") if c.s(s): c_comb.connect(c.s(s), f"{s}_set") c_comb.remove(s) return c_comb
def copy(c)
-
Returns copy of a circuit.
Parameters
c
:Circuit
- circuit to rename
Returns
Circuit
- Relabeled circuit.
Expand source code
def copy(c): """ Returns copy of a circuit. Parameters ---------- c: Circuit circuit to rename Returns ------- Circuit Relabeled circuit. """ return Circuit(graph=c.graph.copy(), name=c.name)
def influence_transform(c, n, s)
-
Creates a circuit to compute sensitivity.
Parameters
c
:Circuit
- Sequential circuit to unroll.
n
:str
- Node to compute influence at.
s
:str
- Startpoint to compute influence for.
Returns
Circuit
- Influence circuit.
Expand source code
def influence_transform(c, n, s): """ Creates a circuit to compute sensitivity. Parameters ---------- c : Circuit Sequential circuit to unroll. n : str Node to compute influence at. s : str Startpoint to compute influence for. Returns ------- Circuit Influence circuit. """ # check if s is in startpoints sp = c.startpoints(n) if s not in sp: raise ValueError(f"{s} is not in startpoints of {n}") # get input cone fiNodes = c.transitive_fanin(n) | set([n]) sub_c = Circuit(c.graph.subgraph(fiNodes).copy()) # remove outs, convert startpoints sub_c.set_output(sub_c.outputs(), False) sub_c.set_type(sub_c.startpoints(), "input") # create two copies of sub circuit infl = Circuit(name=f"infl_{s}_on_{n}") infl.extend(sub_c) infl.extend(relabel(sub_c, {g: f"s1_{g}" for g in sub_c if g not in sp - set([s])})) infl.add("sat", "xor", fanin=[n, f"s1_{n}"], output=True) infl.add(f"not_{s}", "not", fanin=s, fanout=f"s1_{s}") return infl
def miter(c0, c1=None, startpoints=None, endpoints=None)
-
Creates a miter circuit
Parameters
c0
:Circuit
- First circuit.
c1
:Circuit
- Optional second circuit, if None c0 is mitered with itself.
startpoints
:set
ofstr
- Nodes to be tied together, must exist in both circuits.
endpoints
:set
ofstr
- Nodes to be compared, must exist in both circuits.
Returns
Circuit
- Miter circuit.
Expand source code
def miter(c0, c1=None, startpoints=None, endpoints=None): """ Creates a miter circuit Parameters ---------- c0 : Circuit First circuit. c1 : Circuit Optional second circuit, if None c0 is mitered with itself. startpoints : set of str Nodes to be tied together, must exist in both circuits. endpoints : set of str Nodes to be compared, must exist in both circuits. Returns ------- Circuit Miter circuit. """ # clean inputs if not c1: c1 = c0 if not startpoints: startpoints = c0.startpoints() & c1.startpoints() if not endpoints: endpoints = c0.endpoints() & c1.endpoints() # create miter, relabel m = relabel(c0, {n: f"c0_{n}" for n in c0.nodes() - startpoints}) m.extend(relabel(c1, {n: f"c1_{n}" for n in c1.nodes() - startpoints})) strip_outputs(m) # compare endpoints m.add("sat", "or", output=True) for o in endpoints - startpoints: m.add(f"miter_{o}", "xor", fanout=["sat"], fanin=[f"c0_{o}", f"c1_{o}"]) return m
def relabel(c, mapping)
-
Returns renamed copy of a circuit.
Parameters
c
:Circuit
- circuit to rename
mapping
:dict
ofstr:str
- mapping of old to new names
Returns
Circuit
- Relabeled circuit.
Expand source code
def relabel(c, mapping): """ Returns renamed copy of a circuit. Parameters ---------- c: Circuit circuit to rename mapping : dict of str:str mapping of old to new names Returns ------- Circuit Relabeled circuit. """ return Circuit(graph=nx.relabel_nodes(c.graph, mapping), name=c.name)
def sensitivity_transform(c, n, startpoints=None)
-
Creates a circuit to compute sensitivity.
Parameters
c
:Circuit
- Sequential circuit to unroll.
n
:str
- Node to compute sensitivity at.
startpoints
:iterable
ofstr
- startpoints of n to flip.
Returns
Circuit
- Sensitivity circuit.
Expand source code
def sensitivity_transform(c, n, startpoints=None): """ Creates a circuit to compute sensitivity. Parameters ---------- c : Circuit Sequential circuit to unroll. n : str Node to compute sensitivity at. startpoints : iterable of str startpoints of n to flip. Returns ------- Circuit Sensitivity circuit. """ import circuitgraph.logic as logic # choose all startpoints if not specified if startpoints is None: startpoints = c.startpoints(n) all_startpoints = c.startpoints(n) # get fanin cone of node if n in c.startpoints(): raise ValueError(f"{n} is in startpoints") # get input cone fiNodes = c.transitive_fanin(n) | set([n]) sub_c = Circuit(c.graph.subgraph(fiNodes).copy()) # remove outs, convert startpoints sub_c.set_output(sub_c.outputs(), False) sub_c.set_type(sub_c.startpoints(), "input") sub_c.disconnect(sub_c.nodes(), sub_c.startpoints()) # create sensitivity circuit and add first copy of subcircuit sen = Circuit() sen.extend(sub_c) # instantiate population count p = strip_io(logic.popcount(len(startpoints))) p = relabel(p, {g: f"pop_{g}" for g in p}) sen.extend(p) for o in range(clog2(len(startpoints) + 1)): sen.add(f"out_{o}", "buf", fanin=f"pop_out_{o}", output=True) # stamp out a copies of the circuit with s inverted for i, s in enumerate(startpoints): mapping = { g: f"sen_{s}_{g}" for g in sub_c if g not in all_startpoints - set([s]) } sen.extend(relabel(sub_c, mapping)) # connect inverted input sen.set_type(f"sen_{s}_{s}", "not") sen.connect(s, f"sen_{s}_{s}") # compare to first copy sen.add( f"difference_{s}", "xor", fanin=[n, f"sen_{s}_{n}"], fanout=f"pop_in_{i}", output=True, ) return sen
def sensitization_transform(c, n)
-
Creates a circuit to sensitize a node to an endpoint.
Parameters
c
:Circuit
- Input circuit.
n
:str
- Node to sensitize.
Returns
Circuit
- Output circuit.
Expand source code
def sensitization_transform(c, n): """ Creates a circuit to sensitize a node to an endpoint. Parameters ---------- c : Circuit Input circuit. n : str Node to sensitize. Returns ------- Circuit Output circuit. """ # create miter, relabel s = copy(c) s.extend(relabel(c, {n: f"c1_{n}" for n in c})) strip_outputs(s) # connect startpoints for g in c.startpoints(): s.set_type(f"c1_{g}", "buf") s.disconnect(s.fanin(f"c1_{g}"), f"c1_{g}") s.connect(g, f"c1_{g}") # compare endpoints s.add("sat", "or", output=True) for o in c.endpoints(): s.add(f"miter_{o}", "xor", fanout=["sat"], fanin=[o, f"c1_{o}"]) # flip node in c1 s.disconnect(s.fanin(f"c1_{n}"), f"c1_{n}") s.set_type(f"c1_{n}", "not") s.connect(n, f"c1_{n}") return s
def seq_graph(c)
-
Creates a Circuit of the sequential elements and IO.
Parameters
c
:Circuit
Returns
Circuit
- Sequential circuit.
Expand source code
def seq_graph(c): """ Creates a Circuit of the sequential elements and IO. Parameters ---------- c: Circuit Returns ------- Circuit Sequential circuit. """ s = Circuit(name=f"{c.name}_seq") # add nodes for n in c.inputs() | c.seq(): s.add(n, c.type(n), output=c.output(n)) # add edges for n in c.seq(): s.connect(c.startpoints(c.d(n)), n) # add outputs for n in s: if c.endpoints(n) & c.outputs(): s.set_output(n, True) return s
def strip_inputs(c)
-
Converts inputs to buffers for easy instantiation.
Parameters
c
:Circuit
- circuit to strip inputs from
Returns
Circuit
- Circuit with removed io
Expand source code
def strip_inputs(c): """ Converts inputs to buffers for easy instantiation. Parameters ---------- c : Circuit circuit to strip inputs from Returns ------- Circuit Circuit with removed io """ g = c.graph.copy() for i in c.inputs(): g.nodes[i]["type"] = "buf" return Circuit(graph=g, name=c.name)
def strip_io(c)
-
Removes a circuit's outputs and converts inputs to buffers for easy instantiation.
Parameters
c
:Circuit
- circuit to strip io from
Returns
Circuit
- Circuit with removed io
Expand source code
def strip_io(c): """ Removes a circuit's outputs and converts inputs to buffers for easy instantiation. Parameters ---------- c : Circuit circuit to strip io from Returns ------- Circuit Circuit with removed io """ g = c.graph.copy() for o in c.outputs(): g.nodes[o]["output"] = False for i in c.inputs(): g.nodes[i]["type"] = "buf" return Circuit(graph=g, name=c.name)
def strip_outputs(c)
-
Removes a circuit's outputs for easy instantiation.
Parameters
c
:Circuit
- circuit to strip io from
Returns
Circuit
- Circuit with removed io
Expand source code
def strip_outputs(c): """ Removes a circuit's outputs for easy instantiation. Parameters ---------- c : Circuit circuit to strip io from Returns ------- Circuit Circuit with removed io """ g = c.graph.copy() for o in c.outputs(): g.nodes[o]["output"] = False return Circuit(graph=g, name=c.name)
def syn(c, engine, print_output=False)
-
Synthesizes the circuit using Genus.
Parameters
c
:Circuit
- Circuit to synthesize.
engine
:str
- Synthesis tool to use ('Genus' or 'Yosys')
print_output
:bool
- Option to print synthesis log
Returns
Circuit
- Synthesized circuit.
Expand source code
def syn(c, engine, print_output=False): """ Synthesizes the circuit using Genus. Parameters ---------- c : Circuit Circuit to synthesize. engine : str Synthesis tool to use ('Genus' or 'Yosys') print_output : bool Option to print synthesis log Returns ------- Circuit Synthesized circuit. """ verilog = circuit_to_verilog(c) with NamedTemporaryFile(prefix="circuitgraph_syn_genus_input") as tmp_in: tmp_in.write(bytes(verilog, "ascii")) tmp_in.flush() with NamedTemporaryFile(prefix="circuitgraph_syn_genus_output") as tmp_out: if engine == "Genus": cmd = [ "genus", "-no_gui", "-execute", "set_db / .library " f"{os.environ['CIRCUITGRAPH_GENUS_LIBRARY_PATH']};\n" f"read_hdl -sv {tmp_in.name};\n" "elaborate;\n" "set_db syn_generic_effort high;\n" "syn_generic;\n" "syn_map;\n" "syn_opt;\n" f'redirect {tmp_out.name} "write_hdl -generic";\n' "exit;", ] elif engine == "Yosys": cmd = [ "yosys", "-p", f"read_verilog {tmp_in.name}; " "proc; opt; fsm; opt; memory; opt; clean; " f"write_verilog -noattr {tmp_out.name}", ] else: raise ValueError("synthesis engine must be Yosys or Genus") process = Popen(cmd, stdout=PIPE, stderr=PIPE, universal_newlines=True) while True: line = process.stdout.readline() if line == "" and process.poll() is not None: break if line: if print_output: print(line.strip()) output = tmp_out.read().decode("utf-8") if print_output: print(output) return verilog_to_circuit(output, c.name)
def ternary(c)
-
Encodes the circuit with ternary values
Parameters
c
:Circuit
- Circuit to encode.
Returns
Circuit
- Encoded circuit.
Expand source code
def ternary(c): """ Encodes the circuit with ternary values Parameters ---------- c : Circuit Circuit to encode. Returns ------- Circuit Encoded circuit. """ t = copy(c) # add dual nodes for n in c: if c.type(n) in ["and", "nand"]: t.add(f"{n}_x", "and", output=c.output(n)) t.add( f"{n}_x_in_fi", "or", fanout=f"{n}_x", fanin=[f"{p}_x" for p in c.fanin(n)], ) t.add(f"{n}_0_not_in_fi", "nor", fanout=f"{n}_x") for p in c.fanin(n): t.add( f"{p}_is_0", "nor", fanout=f"{n}_0_not_in_fi", fanin=[p, f"{p}_x"] ) elif c.type(n) in ["or", "nor"]: t.add(f"{n}_x", "and", output=c.output(n)) t.add( f"{n}_x_in_fi", "or", fanout=f"{n}_x", fanin=[f"{p}_x" for p in c.fanin(n)], ) t.add(f"{n}_1_not_in_fi", "nor", fanout=f"{n}_x") for p in c.fanin(n): t.add(f"{p}_is_1", "and", fanout=f"{n}_1_not_in_fi", fanin=p) t.add(f"{p}_not_x", "not", fanout=f"{p}_is_1", fanin=f"{p}_x") elif c.type(n) in ["buf", "not"]: p = c.fanin(n).pop() t.add(f"{n}_x", "buf", output=c.output(n), fanin=f"{p}_x") elif c.type(n) in ["xor", "xnor"]: t.add( f"{n}_x", "or", output=c.output(n), fanin=(f"{p}_x" for p in c.fanin(n)) ) elif c.type(n) in ["0", "1"]: t.add(f"{n}_x", "0", output=c.output(n)) elif c.type(n) in ["input"]: t.add(f"{n}_x", "input", output=c.output(n)) elif c.type(n) in ["ff", "lat"]: t.add( f"{n}_x", c.type(n), output=c.output(n), clk=f"{c.clk(n)}_x", r=f"{c.r(n)}_x", s=f"{c.s(n)}_x", fanin=f"{c.fanin(n).pop()}_x", ) elif c.type(n) in ["0", "1"]: continue return t
def unroll(c, cycles)
-
Creates combinational unrolling of the circuit.
Parameters
c
:Circuit
- Sequential circuit to unroll.
cycles
:int
- Number of cycles to unroll
Returns
Circuit
- Unrolled circuit.
Expand source code
def unroll(c, cycles): """ Creates combinational unrolling of the circuit. Parameters ---------- c : Circuit Sequential circuit to unroll. cycles : int Number of cycles to unroll Returns ------- Circuit Unrolled circuit. """ u = Circuit() c_comb = comb(c) for i in range(cycles): u.extend(c_comb, {n: f"{n}_{i}" for n in c_comb}) if i == 0: # convert si to inputs for n in c: if c.type(n) in ["lat", "ff"]: u.set_type(f"{n}_si_{i}", "input") else: # connect prev si for n in c: if c.type(n) in ["lat", "ff"]: u.connect(f"{n}_si_{i-1}", f"{n}_si_{i}") return u