diff --git a/Demo.ipynb b/Demo.ipynb index 6ba4c1f..dde96bc 100644 --- a/Demo.ipynb +++ b/Demo.ipynb @@ -115,6 +115,7 @@ ] }, { + "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ @@ -125,7 +126,7 @@ "\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", - "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": [ - "mycircuit.interface" + "mycircuit.io_nodes" ] }, { @@ -1326,9 +1327,9 @@ ], "metadata": { "kernelspec": { - "display_name": "worker", + "display_name": "Python 3", "language": "python", - "name": "worker" + "name": "python3" }, "language_info": { "codemirror_mode": { @@ -1340,7 +1341,12 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.6.13" + "version": "3.6.8" + }, + "vscode": { + "interpreter": { + "hash": "31f2aee4e71d21fbe5cf8b01ff0e069b9275f58929596ceb00d14d90e3e16cd6" + } } }, "nbformat": 4, diff --git a/src/kyupy/bench.py b/src/kyupy/bench.py index 21310d5..fb1ba1d 100644 --- a/src/kyupy/bench.py +++ b/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 interface(self, args): self.c.interface.extend(args[0]) + def interface(self, args): self.c.io_nodes.extend(args[0]) def assignment(self, args): name, cell_type, drivers = args diff --git a/src/kyupy/circuit.py b/src/kyupy/circuit.py index 925a51d..8310e4f 100644 --- a/src/kyupy/circuit.py +++ b/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`. """ -from collections import deque +from collections import deque, defaultdict import re @@ -203,7 +203,7 @@ class Circuit: to enforce consecutiveness. 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): 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`. """ - self.interface = GrowingList() + self.io_nodes = GrowingList() """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`. - The position of a node in the interface list corresponds to positions of logic values in test vectors. + Port-nodes are contained in :py:attr:`nodes` as well as :py:attr:`io_nodes`. + 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. - 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. """ 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] 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)) - for node in self.interface: + for node in self.io_nodes: if node.kind == '__fork__': n = c.forks[node.name] else: n = c.cells[node.name] - c.interface.append(n) + c.io_nodes.append(n) return c def __getstate__(self): 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] - interface = [n.index for n in self.interface] + io_nodes = [n.index for n in self.io_nodes] return {'name': self.name, 'nodes': nodes, 'lines': lines, - 'interface': interface } + 'io_nodes': io_nodes } def __setstate__(self, state): self.name = state['name'] self.nodes = IndexList() self.lines = IndexList() - self.interface = GrowingList() + self.io_nodes = GrowingList() self.cells = {} self.forks = {} for s in state['nodes']: Node(self, *s) for driver, driver_pin, reader, reader_pin in state['lines']: Line(self, (self.nodes[driver], driver_pin), (self.nodes[reader], reader_pin)) - for n in state['interface']: - self.interface.append(self.nodes[n]) + for n in state['io_nodes']: + self.io_nodes.append(self.nodes[n]) 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): """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]) def __repr__(self): name = f' {self.name}' if self.name else '' return f'' + 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): """Generator function to iterate over all nodes in topological order. @@ -375,8 +382,8 @@ class Circuit: def io_loc(self, prefix): d_top = dict() - for i, n in enumerate(list(self.interface) + [n for n in self.nodes if 'dff' in n.kind.lower()]): - if m := re.match(fr'({prefix}.*?)((?:[_\[\]]\d+)*[_\[\]]*$)', n.name): + 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): path = [m[1]] + [int(v) for v in re.split(r'[_\[\]]+', m[2]) if len(v) > 0] d = d_top for j in path[:-1]: diff --git a/src/kyupy/logic_sim.py b/src/kyupy/logic_sim.py index b9f7eed..e004463 100644 --- a/src/kyupy/logic_sim.py +++ b/src/kyupy/logic_sim.py @@ -32,7 +32,7 @@ class LogicSim: nbytes = (sims - 1) // 8 + 1 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()] - self.interface = list(circuit.interface) + dffs + latches + self.interface = list(circuit.io_nodes) + dffs + latches self.width = len(self.interface) """The number of bits in the circuit state (number of ports + number of state-elements).""" diff --git a/src/kyupy/schedule.py b/src/kyupy/schedule.py index f505a50..57a706a 100644 --- a/src/kyupy/schedule.py +++ b/src/kyupy/schedule.py @@ -157,7 +157,7 @@ class Schedule: """ def __init__(self, circuit, strip_forks=False, keep_signals=True, signal_caps=1): 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): 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.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 diff --git a/src/kyupy/stil.py b/src/kyupy/stil.py index 7cacc5b..3856f32 100644 --- a/src/kyupy/stil.py +++ b/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()) 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)) pi_map = [intf_pos[n] for n in self.signal_groups['_pi']] po_map = [intf_pos[n] for n in self.signal_groups['_po']] diff --git a/src/kyupy/verilog.py b/src/kyupy/verilog.py index e8a20bd..10e5baf 100644 --- a/src/kyupy/verilog.py +++ b/src/kyupy/verilog.py @@ -96,7 +96,7 @@ class VerilogTransformer(Transformer): for name in sd.names: n = Node(c, name, kind=sd.kind) if name in positions: - c.interface[positions[name]] = n + c.io_nodes[positions[name]] = n if sd.kind == 'input': Line(c, n, Node(c, name)) for s1, s2 in assignments: # pass 1.5: process signal assignments diff --git a/src/kyupy/wave_sim.py b/src/kyupy/wave_sim.py index 763e39f..fdfdd1c 100644 --- a/src/kyupy/wave_sim.py +++ b/src/kyupy/wave_sim.py @@ -117,7 +117,7 @@ class WaveSim: self.circuit = circuit self.sims = sims 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 diff --git a/src/kyupy/wave_sim_4ig.py b/src/kyupy/wave_sim_4ig.py index 056fdce..01f6a5d 100644 --- a/src/kyupy/wave_sim_4ig.py +++ b/src/kyupy/wave_sim_4ig.py @@ -117,7 +117,7 @@ class WaveSim: self.circuit = circuit self.sims = sims 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 diff --git a/tests/test_bench.py b/tests/test_bench.py index 44ddf7c..8b9a533 100644 --- a/tests/test_bench.py +++ b/tests/test_bench.py @@ -12,4 +12,4 @@ def test_b01(mydir): def test_simple(): c = bench.parse('input(a, b) output(z) z=and(a,b)') assert len(c.nodes) == 4 - assert len(c.interface) == 3 + assert len(c.io_nodes) == 3 diff --git a/tests/test_circuit.py b/tests/test_circuit.py index 446ba90..8eb4e01 100644 --- a/tests/test_circuit.py +++ b/tests/test_circuit.py @@ -57,9 +57,9 @@ def test_circuit(): assert 'in1' in c.cells assert 'and1' not in c.cells - c.interface[0] = in1 - c.interface[1] = in2 - c.interface[2] = out1 + c.io_nodes[0] = in1 + c.io_nodes[1] = in2 + c.io_nodes[2] = out1 and1 = Node(c, 'and1', kind='and') Line(c, in1, and1)