Browse Source

interface -> io_nodes, io_loc fix

devel
Stefan Holst 2 years ago
parent
commit
f0dac36ac7
  1. 16
      Demo.ipynb
  2. 2
      src/kyupy/bench.py
  3. 43
      src/kyupy/circuit.py
  4. 2
      src/kyupy/logic_sim.py
  5. 7
      src/kyupy/schedule.py
  6. 2
      src/kyupy/stil.py
  7. 2
      src/kyupy/verilog.py
  8. 2
      src/kyupy/wave_sim.py
  9. 2
      src/kyupy/wave_sim_4ig.py
  10. 2
      tests/test_bench.py
  11. 6
      tests/test_circuit.py

16
Demo.ipynb

@ -115,6 +115,7 @@
] ]
}, },
{ {
"attachments": {},
"cell_type": "markdown", "cell_type": "markdown",
"metadata": {}, "metadata": {},
"source": [ "source": [
@ -125,7 +126,7 @@
"\n", "\n",
"A line in the circuit has a unique ID, a driver node and a receiver node. The connections in the dump show the direction (\">\" for output, \"<\" for input) and the line-ID. For example in `mycircuit`: Node-0 has one output connected to Line-1, and this Line-1 is connected to the input of Node-5.\n", "A line in the circuit has a unique ID, a driver node and a receiver node. The connections in the dump show the direction (\">\" for output, \"<\" for input) and the line-ID. For example in `mycircuit`: Node-0 has one output connected to Line-1, and this Line-1 is connected to the input of Node-5.\n",
"\n", "\n",
"The `interface` is the list of nodes forming the ports (inputs and outputs):" "The `io_nodes` is the list of nodes forming the ports (inputs and outputs):"
] ]
}, },
{ {
@ -149,7 +150,7 @@
} }
], ],
"source": [ "source": [
"mycircuit.interface" "mycircuit.io_nodes"
] ]
}, },
{ {
@ -1326,9 +1327,9 @@
], ],
"metadata": { "metadata": {
"kernelspec": { "kernelspec": {
"display_name": "worker", "display_name": "Python 3",
"language": "python", "language": "python",
"name": "worker" "name": "python3"
}, },
"language_info": { "language_info": {
"codemirror_mode": { "codemirror_mode": {
@ -1340,7 +1341,12 @@
"name": "python", "name": "python",
"nbconvert_exporter": "python", "nbconvert_exporter": "python",
"pygments_lexer": "ipython3", "pygments_lexer": "ipython3",
"version": "3.6.13" "version": "3.6.8"
},
"vscode": {
"interpreter": {
"hash": "31f2aee4e71d21fbe5cf8b01ff0e069b9275f58929596ceb00d14d90e3e16cd6"
}
} }
}, },
"nbformat": 4, "nbformat": 4,

2
src/kyupy/bench.py

@ -23,7 +23,7 @@ class BenchTransformer(Transformer):
def parameters(self, args): return [self.c.get_or_add_fork(name) for name in args] def parameters(self, args): return [self.c.get_or_add_fork(name) for name in args]
def interface(self, args): self.c.interface.extend(args[0]) def interface(self, args): self.c.io_nodes.extend(args[0])
def assignment(self, args): def assignment(self, args):
name, cell_type, drivers = args name, cell_type, drivers = args

43
src/kyupy/circuit.py

@ -5,7 +5,7 @@ A node is an instance of class :class:`Node`,
and a line is an instance of class :class:`Line`. and a line is an instance of class :class:`Line`.
""" """
from collections import deque from collections import deque, defaultdict
import re import re
@ -203,7 +203,7 @@ class Circuit:
to enforce consecutiveness. to enforce consecutiveness.
A subset of nodes can be designated as primary input- or output-ports of the circuit. A subset of nodes can be designated as primary input- or output-ports of the circuit.
This is done by adding them to the :py:attr:`interface` list. This is done by adding them to the :py:attr:`io_nodes` list.
""" """
def __init__(self, name=None): def __init__(self, name=None):
self.name = name self.name = name
@ -219,13 +219,13 @@ class Circuit:
The position of a line in this list equals its index :code:`self.lines[42].index == 42`. The position of a line in this list equals its index :code:`self.lines[42].index == 42`.
""" """
self.interface = GrowingList() self.io_nodes = GrowingList()
"""A list of nodes that are designated as primary input- or output-ports. """A list of nodes that are designated as primary input- or output-ports.
Port-nodes are contained in :py:attr:`nodes` as well as :py:attr:`interface`. Port-nodes are contained in :py:attr:`nodes` as well as :py:attr:`io_nodes`.
The position of a node in the interface list corresponds to positions of logic values in test vectors. The position of a node in the io_nodes list corresponds to positions of logic values in test vectors.
The port direction is not stored explicitly. The port direction is not stored explicitly.
Usually, nodes in the interface list without any lines in their :py:attr:`Node.ins` list are primary inputs, Usually, nodes in the io_nodes list without any lines in their :py:attr:`Node.ins` list are primary inputs,
and nodes without any lines in their :py:attr:`Node.outs` list are regarded as primary outputs. and nodes without any lines in their :py:attr:`Node.outs` list are regarded as primary outputs.
""" """
self.cells = {} self.cells = {}
@ -248,50 +248,57 @@ class Circuit:
d = c.forks[line.driver.name] if line.driver.kind == '__fork__' else c.cells[line.driver.name] d = c.forks[line.driver.name] if line.driver.kind == '__fork__' else c.cells[line.driver.name]
r = c.forks[line.reader.name] if line.reader.kind == '__fork__' else c.cells[line.reader.name] r = c.forks[line.reader.name] if line.reader.kind == '__fork__' else c.cells[line.reader.name]
Line(c, (d, line.driver_pin), (r, line.reader_pin)) Line(c, (d, line.driver_pin), (r, line.reader_pin))
for node in self.interface: for node in self.io_nodes:
if node.kind == '__fork__': if node.kind == '__fork__':
n = c.forks[node.name] n = c.forks[node.name]
else: else:
n = c.cells[node.name] n = c.cells[node.name]
c.interface.append(n) c.io_nodes.append(n)
return c return c
def __getstate__(self): def __getstate__(self):
nodes = [(node.name, node.kind) for node in self.nodes] nodes = [(node.name, node.kind) for node in self.nodes]
lines = [(line.driver.index, line.driver_pin, line.reader.index, line.reader_pin) for line in self.lines] lines = [(line.driver.index, line.driver_pin, line.reader.index, line.reader_pin) for line in self.lines]
interface = [n.index for n in self.interface] io_nodes = [n.index for n in self.io_nodes]
return {'name': self.name, return {'name': self.name,
'nodes': nodes, 'nodes': nodes,
'lines': lines, 'lines': lines,
'interface': interface } 'io_nodes': io_nodes }
def __setstate__(self, state): def __setstate__(self, state):
self.name = state['name'] self.name = state['name']
self.nodes = IndexList() self.nodes = IndexList()
self.lines = IndexList() self.lines = IndexList()
self.interface = GrowingList() self.io_nodes = GrowingList()
self.cells = {} self.cells = {}
self.forks = {} self.forks = {}
for s in state['nodes']: for s in state['nodes']:
Node(self, *s) Node(self, *s)
for driver, driver_pin, reader, reader_pin in state['lines']: for driver, driver_pin, reader, reader_pin in state['lines']:
Line(self, (self.nodes[driver], driver_pin), (self.nodes[reader], reader_pin)) Line(self, (self.nodes[driver], driver_pin), (self.nodes[reader], reader_pin))
for n in state['interface']: for n in state['io_nodes']:
self.interface.append(self.nodes[n]) self.io_nodes.append(self.nodes[n])
def __eq__(self, other): def __eq__(self, other):
return self.nodes == other.nodes and self.lines == other.lines and self.interface == other.interface return self.nodes == other.nodes and self.lines == other.lines and self.io_nodes == other.io_nodes
def dump(self): def dump(self):
"""Returns a string representation of the circuit and all its nodes. """Returns a string representation of the circuit and all its nodes.
""" """
header = f'{self.name}({",".join([str(n.index) for n in self.interface])})\n' header = f'{self.name}({",".join([str(n.index) for n in self.io_nodes])})\n'
return header + '\n'.join([str(n) for n in self.nodes]) return header + '\n'.join([str(n) for n in self.nodes])
def __repr__(self): def __repr__(self):
name = f' {self.name}' if self.name else '' name = f' {self.name}' if self.name else ''
return f'<Circuit{name} cells={len(self.cells)} forks={len(self.forks)} ' + \ return f'<Circuit{name} cells={len(self.cells)} forks={len(self.forks)} ' + \
f'lines={len(self.lines)} ports={len(self.interface)}>' f'lines={len(self.lines)} ports={len(self.io_nodes)}>'
@property
def cell_counts(self):
counts = defaultdict(int)
for n in self.cells.values():
counts[n.kind] += 1
return counts
def topological_order(self): def topological_order(self):
"""Generator function to iterate over all nodes in topological order. """Generator function to iterate over all nodes in topological order.
@ -375,8 +382,8 @@ class Circuit:
def io_loc(self, prefix): def io_loc(self, prefix):
d_top = dict() d_top = dict()
for i, n in enumerate(list(self.interface) + [n for n in self.nodes if 'dff' in n.kind.lower()]): for i, n in enumerate(list(self.io_nodes) + [n for n in self.nodes if 'dff' in n.kind.lower()]):
if m := re.match(fr'({prefix}.*?)((?:[_\[\]]\d+)*[_\[\]]*$)', n.name): if m := re.match(fr'({prefix}.*?)((?:\d+[_\[\]])*$)', n.name):
path = [m[1]] + [int(v) for v in re.split(r'[_\[\]]+', m[2]) if len(v) > 0] path = [m[1]] + [int(v) for v in re.split(r'[_\[\]]+', m[2]) if len(v) > 0]
d = d_top d = d_top
for j in path[:-1]: for j in path[:-1]:

2
src/kyupy/logic_sim.py

@ -32,7 +32,7 @@ class LogicSim:
nbytes = (sims - 1) // 8 + 1 nbytes = (sims - 1) // 8 + 1
dffs = [n for n in circuit.nodes if 'dff' in n.kind.lower()] dffs = [n for n in circuit.nodes if 'dff' in n.kind.lower()]
latches = [n for n in circuit.nodes if 'latch' in n.kind.lower()] latches = [n for n in circuit.nodes if 'latch' in n.kind.lower()]
self.interface = list(circuit.interface) + dffs + latches self.interface = list(circuit.io_nodes) + dffs + latches
self.width = len(self.interface) self.width = len(self.interface)
"""The number of bits in the circuit state (number of ports + number of state-elements).""" """The number of bits in the circuit state (number of ports + number of state-elements)."""

7
src/kyupy/schedule.py

@ -157,7 +157,7 @@ class Schedule:
""" """
def __init__(self, circuit, strip_forks=False, keep_signals=True, signal_caps=1): def __init__(self, circuit, strip_forks=False, keep_signals=True, signal_caps=1):
self.circuit = circuit self.circuit = circuit
self.interface = list(circuit.interface) + [n for n in circuit.nodes if 'dff' in n.kind.lower()] self.interface = list(circuit.io_nodes) + [n for n in circuit.nodes if 'dff' in n.kind.lower()]
if isinstance(signal_caps, int): if isinstance(signal_caps, int):
signal_caps = [signal_caps] * len(circuit.lines) signal_caps = [signal_caps] * len(circuit.lines)
@ -303,3 +303,8 @@ class Schedule:
self.vat[self.ppo_offset + i] = self.vat[n.ins[0]] self.vat[self.ppo_offset + i] = self.vat[n.ins[0]]
self.state_length = h.max_size self.state_length = h.max_size
from collections import defaultdict
self.prim_counts = defaultdict(int)
names_dict = SimPrim.names()
for op, _, _, _, _, _ in self.ops: self.prim_counts[names_dict[op]] += 1

2
src/kyupy/stil.py

@ -55,7 +55,7 @@ class StilFile:
capture = dict((k, v.replace('\n', '').replace('N', '-')) for k, v in call.parameters.items()) capture = dict((k, v.replace('\n', '').replace('N', '-')) for k, v in call.parameters.items())
def _maps(self, c): def _maps(self, c):
interface = list(c.interface) + [n for n in c.nodes if 'DFF' in n.kind] interface = list(c.io_nodes) + [n for n in c.nodes if 'DFF' in n.kind]
intf_pos = dict((n.name, i) for i, n in enumerate(interface)) intf_pos = dict((n.name, i) for i, n in enumerate(interface))
pi_map = [intf_pos[n] for n in self.signal_groups['_pi']] pi_map = [intf_pos[n] for n in self.signal_groups['_pi']]
po_map = [intf_pos[n] for n in self.signal_groups['_po']] po_map = [intf_pos[n] for n in self.signal_groups['_po']]

2
src/kyupy/verilog.py

@ -96,7 +96,7 @@ class VerilogTransformer(Transformer):
for name in sd.names: for name in sd.names:
n = Node(c, name, kind=sd.kind) n = Node(c, name, kind=sd.kind)
if name in positions: if name in positions:
c.interface[positions[name]] = n c.io_nodes[positions[name]] = n
if sd.kind == 'input': if sd.kind == 'input':
Line(c, n, Node(c, name)) Line(c, n, Node(c, name))
for s1, s2 in assignments: # pass 1.5: process signal assignments for s1, s2 in assignments: # pass 1.5: process signal assignments

2
src/kyupy/wave_sim.py

@ -117,7 +117,7 @@ class WaveSim:
self.circuit = circuit self.circuit = circuit
self.sims = sims self.sims = sims
self.overflows = 0 self.overflows = 0
self.interface = list(circuit.interface) + [n for n in circuit.nodes if 'dff' in n.kind.lower()] self.interface = list(circuit.io_nodes) + [n for n in circuit.nodes if 'dff' in n.kind.lower()]
self.lst_eat_valid = False self.lst_eat_valid = False

2
src/kyupy/wave_sim_4ig.py

@ -117,7 +117,7 @@ class WaveSim:
self.circuit = circuit self.circuit = circuit
self.sims = sims self.sims = sims
self.overflows = 0 self.overflows = 0
self.interface = list(circuit.interface) + [n for n in circuit.nodes if 'dff' in n.kind.lower()] self.interface = list(circuit.io_nodes) + [n for n in circuit.nodes if 'dff' in n.kind.lower()]
self.lst_eat_valid = False self.lst_eat_valid = False

2
tests/test_bench.py

@ -12,4 +12,4 @@ def test_b01(mydir):
def test_simple(): def test_simple():
c = bench.parse('input(a, b) output(z) z=and(a,b)') c = bench.parse('input(a, b) output(z) z=and(a,b)')
assert len(c.nodes) == 4 assert len(c.nodes) == 4
assert len(c.interface) == 3 assert len(c.io_nodes) == 3

6
tests/test_circuit.py

@ -57,9 +57,9 @@ def test_circuit():
assert 'in1' in c.cells assert 'in1' in c.cells
assert 'and1' not in c.cells assert 'and1' not in c.cells
c.interface[0] = in1 c.io_nodes[0] = in1
c.interface[1] = in2 c.io_nodes[1] = in2
c.interface[2] = out1 c.io_nodes[2] = out1
and1 = Node(c, 'and1', kind='and') and1 = Node(c, 'and1', kind='and')
Line(c, in1, and1) Line(c, in1, and1)

Loading…
Cancel
Save