Module circuitgraph.io
Functions for reading/writing CircuitGraphs
Expand source code
"""Functions for reading/writing CircuitGraphs"""
import re
import os
from glob import glob
import tempfile
from pyeda.parsing import boolexpr
import pyverilog
from pyverilog.vparser.parser import VerilogParser
from pyverilog.vparser import ast as ast_types
from circuitgraph import Circuit
class SequentialElement:
"""Defines a representation of a sequential element for reading/writing
sequential circuits."""
def __init__(self, name, seq_type, io, code_def):
"""
Parameters
----------
name: str
Name of the element (the module name)
type: str
The type of sequential element, either 'ff' or 'lat'
io: dict of str:str
The mapping the 'd', 'q', 'clk', and potentially 'r', 's'
ports to the names of the ports on the module
code_def:
The code defining the module, used for writing the circuit
to verilog
"""
self.name = name
self.seq_type = seq_type
self.io = io
self.code_def = code_def
default_seq_types = [
SequentialElement(
name="fflopd",
seq_type="ff",
io={"d": "D", "q": "Q", "clk": "CK"},
code_def="module fflopd(CK, D, Q);\n"
" input CK, D;\n"
" output Q;\n"
" wire CK, D;\n"
" wire Q;\n"
" wire next_state;\n"
" reg qi;\n"
" assign #1 Q = qi;\n"
" assign next_state = D;\n"
" always\n"
" @(posedge CK)\n"
" qi <= next_state;\n"
" initial\n"
" qi <= 1'b0;\n"
"endmodule",
),
SequentialElement(
name="latchdrs",
seq_type="lat",
io={"d": "D", "q": "Q", "clk": "ENA", "r": "R", "s": "S"},
code_def="",
),
]
cadence_seq_types = [
# Note that this is a modified version of CDN_flop with only a synchronous
# reset that always resets to 0
SequentialElement(
name="CDN_flop",
seq_type="ff",
io={"d": "d", "q": "q", "clk": "clk", "r": "srl"},
code_def="module CDN_flop(clk, d, srl, q);\n"
" input clk, d, srl;\n"
" output q;\n"
" wire clk, d, srl;\n"
" wire q;\n"
" reg qi;\n"
" assign #1 q = qi;\n"
" always\n"
" @(posedge clk)\n"
" if (srl)\n"
" qi <= 1'b0;\n"
" else if (sena)\n"
" qi <= d;\n"
" end\n"
" initial\n"
" qi <= 1'b0;\n"
"endmodule",
)
]
def from_file(path, name=None, seq_types=None):
"""
Creates a new `Circuit` from a verilog file.
Parameters
----------
path: str
the path to the file to read from.
name: str
the name of the module to read if different from the filename.
seq_types: list of dicts of str:str
the types of sequential elements in the file.
Returns
-------
Circuit
the parsed circuit.
"""
ext = path.split(".")[-1]
if name is None:
name = path.split("/")[-1].replace(f".{ext}", "")
with open(path, "r") as f:
netlist = f.read()
if ext == "v":
return verilog_to_circuit(netlist, name, seq_types)
elif ext == "bench":
return bench_to_circuit(netlist, name)
else:
raise ValueError(f"extension {ext} not supported")
def from_lib(circuit, name=None):
"""
Creates a new `Circuit` from a netlist in the `netlists`
folder
Parameters
----------
circuit: the name of the netlist.
name: the module name, if different from the netlist name.
Returns
-------
Circuit
the parsed circuit.
"""
path = glob(f"{os.path.dirname(__file__)}/netlists/{circuit}.*")[0]
return from_file(path, name)
def bench_to_circuit(bench, name):
"""
Creates a new Circuit from a bench string.
Parameters
----------
bench: str
bench code.
name: str
the module name.
Returns
-------
Circuit
the parsed circuit.
"""
# create circuit
c = Circuit(name=name)
# get inputs
in_regex = r"(?:INPUT|input)\s*\((.+?)\)"
for net_str in re.findall(in_regex, bench, re.DOTALL):
nets = net_str.replace(" ", "").replace("\n", "").replace("\t", "").split(",")
for n in nets:
c.add(n, "input")
# handle gates
regex = r"(\S+)\s*=\s*(NOT|OR|NOR|AND|NAND|XOR|XNOR|not|or|nor|and|nand|not|xor|xnor)\((.+?)\)"
for net, gate, input_str in re.findall(regex, bench):
# parse all nets
inputs = (
input_str.replace(" ", "").replace("\n", "").replace("\t", "").split(",")
)
# get outputs
in_regex = r"(?:OUTPUT|output)\s*\((.+?)\)"
for net_str in re.findall(in_regex, bench, re.DOTALL):
nets = net_str.replace(" ", "").replace("\n", "").replace("\t", "").split(",")
for n in nets:
c.set_output(n)
return c
def verilog_to_circuit(verilog, name, seq_types=None):
"""
Creates a new Circuit from a verilog file.
Parameters
----------
path: str
verilog code.
name: str
the module name.
seq_types: list of dicts of str:str
the sequential element types.
Returns
-------
Circuit
the parsed circuit.
"""
if seq_types is None:
seq_types = default_seq_types
c = Circuit(name=name)
with tempfile.TemporaryDirectory(prefix="circuitgraph") as d:
codeparser = VerilogParser(outputdir=d, debug=False)
ast = codeparser.parse(verilog, debug=False)
description = ast.children()[0]
module_def = [d for d in description.children() if d.name == name]
if not module_def:
raise ValueError(f"Module {name} not found")
module_def = module_def[0]
outputs = set()
widths = dict()
for child in module_def.children():
if type(child) == ast_types.Paramlist:
if child.children():
raise ValueError(
f"circuitgraph cannot parse parameters (line {child.lineno})"
)
# Parse portlist
elif type(child) == ast_types.Portlist:
for cip in [i for i in child.children() if type(i) == ast_types.Ioport]:
for ci in cip.children():
parse_io(c, ci, outputs)
# Parse declarations
elif type(child) == ast_types.Decl:
if ast_types.Parameter in [type(i) for i in child.children()]:
raise ValueError(
f"circuitgraph cannot parse parameters (line {child.lineno})"
)
for ci in [
i
for i in child.children()
if type(i) in [ast_types.Input, ast_types.Output]
]:
parse_io(c, ci, outputs)
# Parse instances
elif type(child) == ast_types.InstanceList:
for instance in child.instances:
if instance.module in [
"buf",
"not",
"and",
"nand",
"or",
"nor",
"xor",
"xnor",
]:
gate = instance.module
dest = parse_argument(instance.portlist[0].argname, c)
sources = [
parse_argument(i.argname, c) for i in instance.portlist[1:]
]
c.add(dest, gate, fanin=sources, output=dest in outputs)
elif instance.module in [i.name for i in seq_types]:
if instance.portlist[0].portname is None:
raise ValueError(
"circuitgraph can only parse "
"sequential instances declared "
"with port argument notation "
f"(line {instance.lineno})"
)
seq_type = [i for i in seq_types if i.name == instance.module][
0
]
ports = {
p.portname: parse_argument(p.argname, c)
for p in instance.portlist
}
c.add(
ports.get(seq_type.io.get("q")),
seq_type.seq_type,
fanin=ports.get(seq_type.io.get("d")),
clk=ports.get(seq_type.io.get("clk")),
r=ports.get(seq_type.io.get("r")),
s=ports.get(seq_type.io.get("s")),
output=ports.get(seq_type.io.get("q")) in outputs,
)
else:
raise ValueError(
"circuitgraph cannot parse instance of "
f"type {instance.module} (line "
f"{instance.lineno})"
)
# Parse assigns
elif type(child) == ast_types.Assign:
dest = child.left.var
dest = parse_argument(dest, c)
if type(child.right.var) == ast_types.IntConst:
c.add(
dest, f"{child.right.var.value[-1]}", output=dest in outputs,
)
elif issubclass(type(child.right.var), ast_types.Operator):
parse_operator(child.right.var, c, outputs, dest=dest)
elif issubclass(type(child.right.var), ast_types.Concat):
raise ValueError(
"circuitgraph cannot parse concatenations "
f"(line {child.right.var.lineno})"
)
elif type(child.right.var) == ast_types.Identifier:
c.add(
dest, "buf", output=dest in outputs, fanin=child.right.var.name
)
else:
raise ValueError(
"circuitgraph cannot parse statements of type "
f"{type(child)} (line {child.lineno})"
)
return c
def parse_io(c, ci, outputs):
if ci.width:
cis = [
f"{ci.name}[{i}]"
for i in range(int(ci.width.lsb.value), int(ci.width.msb.value) + 1)
]
if not ci.name.startswith("\\"):
cis = [f"\{i}" for i in cis]
else:
cis = [ci.name]
if type(ci) == ast_types.Input:
for i in cis:
c.add(i, "input")
elif type(ci) == ast_types.Output:
outputs.update(set(cis))
def parse_argument(argname, circuit):
if type(argname) == ast_types.Pointer:
if argname.var.name.startswith("\\"):
return f"{argname.var}[{argname.ptr}]"
else:
return f"\\{argname.var}[{argname.ptr}]"
elif type(argname) == ast_types.IntConst:
circuit.add(f"tie_{argname.value[-1]}", argname.value[-1])
return f"tie_{argname.value[-1]}"
elif issubclass(type(argname), ast_types.Concat):
raise ValueError(
f"circuitgraph cannot parse concatenations (line {argname.lineno})"
)
elif type(argname) == ast_types.Partselect:
raise ValueError(
"circuitgrpah cannot parse part select "
f"statements (line {argname.lineno})"
)
return argname.name
def parse_operator(operator, circuit, outputs, dest=None):
if type(operator) == ast_types.IntConst:
circuit.add(f"tie_{operator.value[-1]}", operator.value[-1])
return f"tie_{operator.value[-1]}"
elif not issubclass(type(operator), ast_types.Operator):
return parse_argument(operator, circuit)
fanin = [parse_operator(o, circuit, outputs) for o in operator.children()]
op = str(operator)[1:].split()[0].lower()
# pyverilog parses `~` as 'unot'
if op == "unot":
op = "not"
# multibit operators (not yet parsable)
if op.startswith("l"):
raise ValueError(
f"circuitgraph cannot parse multibit operators (line {operator.lineno})"
)
if dest is None:
dest = f"{op}_{'_'.join(fanin)}"
if any(i.startswith("\\") for i in fanin):
dest = dest.replace("\\", "")
dest = f"\\{dest}"
circuit.add(dest, op, fanin=fanin, output=dest in outputs)
return dest
def to_file(c, path, seq_types=None):
"""
Writes a `Circuit` to a verilog file.
Parameters
----------
c: Circut
the circuit
path: str
the path to the file to read from.
seq_types: list of dicts of str:str
the types of sequential elements in the file.
"""
with open(path, "w") as f:
f.write(circuit_to_verilog(c, seq_types))
def circuit_to_verilog(c, seq_types=None):
"""
Generates a str of verilog code from a `CircuitGraph`.
Parameters
----------
c: Circuit
the circuit to turn into verilog.
seq_types: list of dicts of str:str
the sequential element types.
Returns
-------
str
verilog code.
"""
inputs = []
outputs = []
insts = []
wires = []
defs = set()
if seq_types is None:
seq_types = default_seq_types
def sanitize_name(n):
if n.startswith("\\"):
return f"{n} "
return n
def sanitize_instance(n):
if n.startswith("\\"):
n_gate = n.replace("\\", "")
return f"\\g_{n_gate}"
else:
return f"g_{n}"
for n in c.nodes():
if c.type(n) in ["xor", "xnor", "buf", "not", "nor", "or", "and", "nand"]:
fanin = ", ".join(sanitize_name(p) for p in c.fanin(n))
insts.append(
f"{c.type(n)} {sanitize_instance(n)} " f"({sanitize_name(n)}, {fanin})"
)
if not c.output(n):
wires.append(n)
elif c.type(n) in ["0", "1"]:
insts.append(f"assign {sanitize_name(n)} = 1'b{c.type(n)}")
elif c.type(n) in ["input"]:
inputs.append(n)
elif c.type(n) in ["ff", "lat"]:
if not c.output(n):
wires.append(n)
# get template
for s in seq_types:
if s.seq_type == c.type(n):
seq = s
defs.add(s.code_def)
break
# connect
io = []
if c.d(n):
d = sanitize_name(c.d(n))
io.append(f".{seq.io['d']}({d})")
if c.r(n):
r = sanitize_name(c.r(n))
io.append(f".{seq.io['r']}({r})")
if c.s(n):
s = sanitize_name(c.s(n))
io.append(f".{seq.io['s']}({s})")
if c.clk(n):
clk = sanitize_name(c.clk(n))
io.append(f".{seq.io['clk']}({clk})")
io.append(f".{seq.io['q']}({sanitize_name(n)})")
insts.append(f"{seq.name} {sanitize_instance(n)} ({', '.join(io)})")
else:
raise ValueError(f"unknown gate type: {c.type(n)}")
if c.output(n):
outputs.append(n)
verilog = f"module {c.name} ("
verilog += ", ".join(sanitize_name(i) for i in inputs + outputs)
verilog += ");\n"
verilog += "".join(f" input {sanitize_name(inp)};\n" for inp in inputs)
verilog += "".join(f" output {sanitize_name(out)};\n" for out in outputs)
verilog += "\n"
verilog += "".join(f" wire {sanitize_name(wire)};\n" for wire in wires)
verilog += "\n"
verilog += "".join(f" {inst};\n" for inst in insts)
verilog += "endmodule\n"
verilog += "\n"
verilog += "\n".join(defs)
return verilog
Functions
def bench_to_circuit(bench, name)
-
Creates a new Circuit from a bench string.
Parameters
bench
:str
- bench code.
name
:str
- the module name.
Returns
Circuit
- the parsed circuit.
Expand source code
def bench_to_circuit(bench, name): """ Creates a new Circuit from a bench string. Parameters ---------- bench: str bench code. name: str the module name. Returns ------- Circuit the parsed circuit. """ # create circuit c = Circuit(name=name) # get inputs in_regex = r"(?:INPUT|input)\s*\((.+?)\)" for net_str in re.findall(in_regex, bench, re.DOTALL): nets = net_str.replace(" ", "").replace("\n", "").replace("\t", "").split(",") for n in nets: c.add(n, "input") # handle gates regex = r"(\S+)\s*=\s*(NOT|OR|NOR|AND|NAND|XOR|XNOR|not|or|nor|and|nand|not|xor|xnor)\((.+?)\)" for net, gate, input_str in re.findall(regex, bench): # parse all nets inputs = ( input_str.replace(" ", "").replace("\n", "").replace("\t", "").split(",") ) # get outputs in_regex = r"(?:OUTPUT|output)\s*\((.+?)\)" for net_str in re.findall(in_regex, bench, re.DOTALL): nets = net_str.replace(" ", "").replace("\n", "").replace("\t", "").split(",") for n in nets: c.set_output(n) return c
def circuit_to_verilog(c, seq_types=None)
-
Generates a str of verilog code from a
CircuitGraph
.Parameters
c
:Circuit
- the circuit to turn into verilog.
seq_types
:list
ofdicts
ofstr:str
- the sequential element types.
Returns
str
- verilog code.
Expand source code
def circuit_to_verilog(c, seq_types=None): """ Generates a str of verilog code from a `CircuitGraph`. Parameters ---------- c: Circuit the circuit to turn into verilog. seq_types: list of dicts of str:str the sequential element types. Returns ------- str verilog code. """ inputs = [] outputs = [] insts = [] wires = [] defs = set() if seq_types is None: seq_types = default_seq_types def sanitize_name(n): if n.startswith("\\"): return f"{n} " return n def sanitize_instance(n): if n.startswith("\\"): n_gate = n.replace("\\", "") return f"\\g_{n_gate}" else: return f"g_{n}" for n in c.nodes(): if c.type(n) in ["xor", "xnor", "buf", "not", "nor", "or", "and", "nand"]: fanin = ", ".join(sanitize_name(p) for p in c.fanin(n)) insts.append( f"{c.type(n)} {sanitize_instance(n)} " f"({sanitize_name(n)}, {fanin})" ) if not c.output(n): wires.append(n) elif c.type(n) in ["0", "1"]: insts.append(f"assign {sanitize_name(n)} = 1'b{c.type(n)}") elif c.type(n) in ["input"]: inputs.append(n) elif c.type(n) in ["ff", "lat"]: if not c.output(n): wires.append(n) # get template for s in seq_types: if s.seq_type == c.type(n): seq = s defs.add(s.code_def) break # connect io = [] if c.d(n): d = sanitize_name(c.d(n)) io.append(f".{seq.io['d']}({d})") if c.r(n): r = sanitize_name(c.r(n)) io.append(f".{seq.io['r']}({r})") if c.s(n): s = sanitize_name(c.s(n)) io.append(f".{seq.io['s']}({s})") if c.clk(n): clk = sanitize_name(c.clk(n)) io.append(f".{seq.io['clk']}({clk})") io.append(f".{seq.io['q']}({sanitize_name(n)})") insts.append(f"{seq.name} {sanitize_instance(n)} ({', '.join(io)})") else: raise ValueError(f"unknown gate type: {c.type(n)}") if c.output(n): outputs.append(n) verilog = f"module {c.name} (" verilog += ", ".join(sanitize_name(i) for i in inputs + outputs) verilog += ");\n" verilog += "".join(f" input {sanitize_name(inp)};\n" for inp in inputs) verilog += "".join(f" output {sanitize_name(out)};\n" for out in outputs) verilog += "\n" verilog += "".join(f" wire {sanitize_name(wire)};\n" for wire in wires) verilog += "\n" verilog += "".join(f" {inst};\n" for inst in insts) verilog += "endmodule\n" verilog += "\n" verilog += "\n".join(defs) return verilog
def from_file(path, name=None, seq_types=None)
-
Creates a new
Circuit
from a verilog file.Parameters
path
:str
- the path to the file to read from.
name
:str
- the name of the module to read if different from the filename.
seq_types
:list
ofdicts
ofstr:str
- the types of sequential elements in the file.
Returns
Circuit
- the parsed circuit.
Expand source code
def from_file(path, name=None, seq_types=None): """ Creates a new `Circuit` from a verilog file. Parameters ---------- path: str the path to the file to read from. name: str the name of the module to read if different from the filename. seq_types: list of dicts of str:str the types of sequential elements in the file. Returns ------- Circuit the parsed circuit. """ ext = path.split(".")[-1] if name is None: name = path.split("/")[-1].replace(f".{ext}", "") with open(path, "r") as f: netlist = f.read() if ext == "v": return verilog_to_circuit(netlist, name, seq_types) elif ext == "bench": return bench_to_circuit(netlist, name) else: raise ValueError(f"extension {ext} not supported")
def from_lib(circuit, name=None)
-
Creates a new
Circuit
from a netlist in thenetlists
folderParameters
circuit: the name of the netlist. name: the module name, if different from the netlist name.
Returns
Circuit
- the parsed circuit.
Expand source code
def from_lib(circuit, name=None): """ Creates a new `Circuit` from a netlist in the `netlists` folder Parameters ---------- circuit: the name of the netlist. name: the module name, if different from the netlist name. Returns ------- Circuit the parsed circuit. """ path = glob(f"{os.path.dirname(__file__)}/netlists/{circuit}.*")[0] return from_file(path, name)
def parse_argument(argname, circuit)
-
Expand source code
def parse_argument(argname, circuit): if type(argname) == ast_types.Pointer: if argname.var.name.startswith("\\"): return f"{argname.var}[{argname.ptr}]" else: return f"\\{argname.var}[{argname.ptr}]" elif type(argname) == ast_types.IntConst: circuit.add(f"tie_{argname.value[-1]}", argname.value[-1]) return f"tie_{argname.value[-1]}" elif issubclass(type(argname), ast_types.Concat): raise ValueError( f"circuitgraph cannot parse concatenations (line {argname.lineno})" ) elif type(argname) == ast_types.Partselect: raise ValueError( "circuitgrpah cannot parse part select " f"statements (line {argname.lineno})" ) return argname.name
def parse_io(c, ci, outputs)
-
Expand source code
def parse_io(c, ci, outputs): if ci.width: cis = [ f"{ci.name}[{i}]" for i in range(int(ci.width.lsb.value), int(ci.width.msb.value) + 1) ] if not ci.name.startswith("\\"): cis = [f"\{i}" for i in cis] else: cis = [ci.name] if type(ci) == ast_types.Input: for i in cis: c.add(i, "input") elif type(ci) == ast_types.Output: outputs.update(set(cis))
def parse_operator(operator, circuit, outputs, dest=None)
-
Expand source code
def parse_operator(operator, circuit, outputs, dest=None): if type(operator) == ast_types.IntConst: circuit.add(f"tie_{operator.value[-1]}", operator.value[-1]) return f"tie_{operator.value[-1]}" elif not issubclass(type(operator), ast_types.Operator): return parse_argument(operator, circuit) fanin = [parse_operator(o, circuit, outputs) for o in operator.children()] op = str(operator)[1:].split()[0].lower() # pyverilog parses `~` as 'unot' if op == "unot": op = "not" # multibit operators (not yet parsable) if op.startswith("l"): raise ValueError( f"circuitgraph cannot parse multibit operators (line {operator.lineno})" ) if dest is None: dest = f"{op}_{'_'.join(fanin)}" if any(i.startswith("\\") for i in fanin): dest = dest.replace("\\", "") dest = f"\\{dest}" circuit.add(dest, op, fanin=fanin, output=dest in outputs) return dest
def to_file(c, path, seq_types=None)
-
Writes a
Circuit
to a verilog file.Parameters
c
:Circut
- the circuit
path
:str
- the path to the file to read from.
seq_types
:list
ofdicts
ofstr:str
- the types of sequential elements in the file.
Expand source code
def to_file(c, path, seq_types=None): """ Writes a `Circuit` to a verilog file. Parameters ---------- c: Circut the circuit path: str the path to the file to read from. seq_types: list of dicts of str:str the types of sequential elements in the file. """ with open(path, "w") as f: f.write(circuit_to_verilog(c, seq_types))
def verilog_to_circuit(verilog, name, seq_types=None)
-
Creates a new Circuit from a verilog file.
Parameters
path
:str
- verilog code.
name
:str
- the module name.
seq_types
:list
ofdicts
ofstr:str
- the sequential element types.
Returns
Circuit
- the parsed circuit.
Expand source code
def verilog_to_circuit(verilog, name, seq_types=None): """ Creates a new Circuit from a verilog file. Parameters ---------- path: str verilog code. name: str the module name. seq_types: list of dicts of str:str the sequential element types. Returns ------- Circuit the parsed circuit. """ if seq_types is None: seq_types = default_seq_types c = Circuit(name=name) with tempfile.TemporaryDirectory(prefix="circuitgraph") as d: codeparser = VerilogParser(outputdir=d, debug=False) ast = codeparser.parse(verilog, debug=False) description = ast.children()[0] module_def = [d for d in description.children() if d.name == name] if not module_def: raise ValueError(f"Module {name} not found") module_def = module_def[0] outputs = set() widths = dict() for child in module_def.children(): if type(child) == ast_types.Paramlist: if child.children(): raise ValueError( f"circuitgraph cannot parse parameters (line {child.lineno})" ) # Parse portlist elif type(child) == ast_types.Portlist: for cip in [i for i in child.children() if type(i) == ast_types.Ioport]: for ci in cip.children(): parse_io(c, ci, outputs) # Parse declarations elif type(child) == ast_types.Decl: if ast_types.Parameter in [type(i) for i in child.children()]: raise ValueError( f"circuitgraph cannot parse parameters (line {child.lineno})" ) for ci in [ i for i in child.children() if type(i) in [ast_types.Input, ast_types.Output] ]: parse_io(c, ci, outputs) # Parse instances elif type(child) == ast_types.InstanceList: for instance in child.instances: if instance.module in [ "buf", "not", "and", "nand", "or", "nor", "xor", "xnor", ]: gate = instance.module dest = parse_argument(instance.portlist[0].argname, c) sources = [ parse_argument(i.argname, c) for i in instance.portlist[1:] ] c.add(dest, gate, fanin=sources, output=dest in outputs) elif instance.module in [i.name for i in seq_types]: if instance.portlist[0].portname is None: raise ValueError( "circuitgraph can only parse " "sequential instances declared " "with port argument notation " f"(line {instance.lineno})" ) seq_type = [i for i in seq_types if i.name == instance.module][ 0 ] ports = { p.portname: parse_argument(p.argname, c) for p in instance.portlist } c.add( ports.get(seq_type.io.get("q")), seq_type.seq_type, fanin=ports.get(seq_type.io.get("d")), clk=ports.get(seq_type.io.get("clk")), r=ports.get(seq_type.io.get("r")), s=ports.get(seq_type.io.get("s")), output=ports.get(seq_type.io.get("q")) in outputs, ) else: raise ValueError( "circuitgraph cannot parse instance of " f"type {instance.module} (line " f"{instance.lineno})" ) # Parse assigns elif type(child) == ast_types.Assign: dest = child.left.var dest = parse_argument(dest, c) if type(child.right.var) == ast_types.IntConst: c.add( dest, f"{child.right.var.value[-1]}", output=dest in outputs, ) elif issubclass(type(child.right.var), ast_types.Operator): parse_operator(child.right.var, c, outputs, dest=dest) elif issubclass(type(child.right.var), ast_types.Concat): raise ValueError( "circuitgraph cannot parse concatenations " f"(line {child.right.var.lineno})" ) elif type(child.right.var) == ast_types.Identifier: c.add( dest, "buf", output=dest in outputs, fanin=child.right.var.name ) else: raise ValueError( "circuitgraph cannot parse statements of type " f"{type(child)} (line {child.lineno})" ) return c
Classes
class SequentialElement (name, seq_type, io, code_def)
-
Defines a representation of a sequential element for reading/writing sequential circuits.
Parameters
name
:str
- Name of the element (the module name)
type
:str
- The type of sequential element, either 'ff' or 'lat'
io
:dict
ofstr:str
- The mapping the 'd', 'q', 'clk', and potentially 'r', 's' ports to the names of the ports on the module
code_def: The code defining the module, used for writing the circuit to verilog
Expand source code
class SequentialElement: """Defines a representation of a sequential element for reading/writing sequential circuits.""" def __init__(self, name, seq_type, io, code_def): """ Parameters ---------- name: str Name of the element (the module name) type: str The type of sequential element, either 'ff' or 'lat' io: dict of str:str The mapping the 'd', 'q', 'clk', and potentially 'r', 's' ports to the names of the ports on the module code_def: The code defining the module, used for writing the circuit to verilog """ self.name = name self.seq_type = seq_type self.io = io self.code_def = code_def