better circuit statsu, 2v logic sim
This commit is contained in:
1 parent
753ce566e4
commit
89f317b463
3 files changed
+62
-17
No files matched your search
+28
-6
@@ -235,6 +235,10 @@ class Circuit:
|
||||
"""A dictionary to access forks by name.
|
||||
"""
|
||||
|
||||
@property
|
||||
def s_nodes(self):
|
||||
return list(self.io_nodes) + [n for n in self.nodes if 'dff' in n.kind.lower()] + [n for n in self.nodes if 'latch' in n.kind.lower()]
|
||||
|
||||
def get_or_add_fork(self, name):
|
||||
return self.forks[name] if name in self.forks else Node(self, name)
|
||||
|
||||
@@ -294,11 +298,23 @@ class Circuit:
|
||||
f'lines={len(self.lines)} ports={len(self.io_nodes)}>'
|
||||
|
||||
@property
|
||||
def cell_counts(self):
|
||||
counts = defaultdict(int)
|
||||
def stats(self):
|
||||
stats = defaultdict(int)
|
||||
stats['__node__'] = len(self.nodes)
|
||||
stats['__cell__'] = len(self.cells)
|
||||
stats['__fork__'] = len(self.forks)
|
||||
stats['__port__'] = len(self.io_nodes)
|
||||
stats['__line__'] = len(self.lines)
|
||||
for n in self.cells.values():
|
||||
counts[n.kind] += 1
|
||||
return counts
|
||||
stats[n.kind] += 1
|
||||
if 'dff' in n.kind.lower():
|
||||
stats['__dff__'] += 1
|
||||
elif 'latch' in n.kind.lower():
|
||||
stats['__latch__'] += 1
|
||||
elif 'put' not in n.kind.lower(): # no input or output
|
||||
stats['__comb__'] += 1
|
||||
stats['__seq__'] = stats['__dff__'] + stats['__latch__']
|
||||
return stats
|
||||
|
||||
def topological_order(self):
|
||||
"""Generator function to iterate over all nodes in topological order.
|
||||
@@ -380,9 +396,15 @@ class Circuit:
|
||||
region.append(n)
|
||||
yield stem, region
|
||||
|
||||
def io_loc(self, prefix):
|
||||
def io_locs(self, prefix):
|
||||
return self._locs(prefix, list(self.io_nodes))
|
||||
|
||||
def s_locs(self, prefix):
|
||||
return self._locs(prefix, self.s_nodes)
|
||||
|
||||
def _locs(self, prefix, nodes):
|
||||
d_top = dict()
|
||||
for i, n in enumerate(list(self.io_nodes) + [n for n in self.nodes if 'dff' in n.kind.lower()]):
|
||||
for i, n in enumerate(nodes):
|
||||
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
|
||||
|
||||
+12
-9
@@ -1,4 +1,4 @@
|
||||
"""This module contains definitions and data structures for 2-, 4-, and 8-valued logic operations.
|
||||
"""This module contains definitions and utilities for 2-, 4-, and 8-valued logic operations.
|
||||
|
||||
8 logic values are defined as integer constants.
|
||||
|
||||
@@ -6,18 +6,22 @@
|
||||
* 4-valued logic adds: ``UNASSIGNED`` and ``UNKNOWN``
|
||||
* 8-valued logic adds: ``RISE``, ``FALL``, ``PPULSE``, and ``NPULSE``.
|
||||
|
||||
The bits in these constants have the following meaning:
|
||||
In general, the bits in these constants have the following meaning:
|
||||
|
||||
* bit0: Final/settled binary value of a signal
|
||||
* bit1: Initial binary value of a signal
|
||||
* bit2: Activity or transitions are present on a signal
|
||||
|
||||
Special meaning is given to values where bits 0 and 1 differ, but bit 2 (activity) is 0.
|
||||
These values are interpreted as ``UNKNOWN`` or ``UNASSIGNED`` in 4-valued and 8-valued logic.
|
||||
Except when bit0 differs from bit1, but bit2 (activity) is 0:
|
||||
|
||||
* bit0 = 1, bit1 = 0, bit2 = 0 means ``UNKNOWN`` in 4-valued and 8-valued logic.
|
||||
* bit0 = 0, bit1 = 1, bit2 = 0 means ``UNASSIGNED`` in 4-valued and 8-valued logic.
|
||||
|
||||
2-valued logic only considers bit0, but should store logic one as ``ONE=0b011`` for interoerability.
|
||||
4-valued logic only considers bit0 and bit1.
|
||||
8-valued logic considers all 3 bits.
|
||||
|
||||
|
||||
In general, 2-valued logic only considers bit 0, 4-valued logic considers bits 0 and 1, and 8-valued logic
|
||||
considers all 3 bits.
|
||||
The only exception is constant ``ONE=0b11`` which has two bits set for all logics including 2-valued logic.
|
||||
"""
|
||||
|
||||
import math
|
||||
@@ -279,8 +283,7 @@ def mv_transition(init, final, out=None):
|
||||
|
||||
|
||||
def bp_buf(out, inp):
|
||||
unknown = inp[..., 0, :] ^ inp[..., 1, :]
|
||||
unknown &= ~inp[..., 2, :]
|
||||
unknown = (inp[..., 0, :] ^ inp[..., 1, :]) & ~inp[..., 2, :]
|
||||
out[..., 0, :] = inp[..., 0, :] | unknown
|
||||
out[..., 1, :] = inp[..., 1, :] & ~unknown
|
||||
out[..., 2, :] = inp[..., 2, :] & ~unknown
|
||||
|
||||
+22
-2
@@ -95,7 +95,7 @@ class LogicSim(SimOps):
|
||||
:type stimuli: :py:class:`~kyupy.logic.BPArray`
|
||||
:returns: The given stimuli object.
|
||||
"""
|
||||
self.c[self.pippi_c_locs] = self.s[0, self.pippi_s_locs]
|
||||
self.c[self.pippi_c_locs] = self.s[0, self.pippi_s_locs, :self.mdim]
|
||||
# for node, stim in zip(self.interface, stimuli.data if hasattr(stimuli, 'data') else stimuli):
|
||||
# if len(node.outs) == 0: continue
|
||||
# if node.index in self.latch_dict:
|
||||
@@ -125,7 +125,10 @@ class LogicSim(SimOps):
|
||||
(the currently assigned pattern) and the new state.
|
||||
:returns: The given responses object.
|
||||
"""
|
||||
self.s[1, self.poppo_s_locs] = self.c[self.poppo_c_locs]
|
||||
self.s[1, self.poppo_s_locs, :self.mdim] = self.c[self.poppo_c_locs]
|
||||
if self.mdim == 1:
|
||||
self.s[1, self.poppo_s_locs, 1:2] = self.c[self.poppo_c_locs]
|
||||
|
||||
# for node, resp in zip(self.interface, responses.data if hasattr(responses, 'data') else responses):
|
||||
# if len(node.ins) == 0: continue
|
||||
# if node.index in self.latch_dict:
|
||||
@@ -165,6 +168,23 @@ class LogicSim(SimOps):
|
||||
resumes with the manipulated values after the callback returns.
|
||||
:type inject_cb: ``f(Line, ndarray)``
|
||||
"""
|
||||
if self.m == 2:
|
||||
for op, o0, i0, i1, i2, i3 in self.ops:
|
||||
o0, i0, i1, i2, i3 = [self.vat[x,0] for x in (o0, i0, i1, i2, i3)]
|
||||
if op == SimPrim.BUF1: self.c[o0]=self.c[i0]
|
||||
elif op == SimPrim.INV1: self.c[o0] = ~self.c[i0]
|
||||
elif op == SimPrim.AND2: self.c[o0] = self.c[i0] & self.c[i1]
|
||||
elif op == SimPrim.NAND2: self.c[o0] = ~(self.c[i0] & self.c[i1])
|
||||
elif op == SimPrim.OR2: self.c[o0] = self.c[i0] | self.c[i1]
|
||||
elif op == SimPrim.NOR2: self.c[o0] = ~(self.c[i0] | self.c[i1])
|
||||
elif op == SimPrim.XOR2: self.c[o0] = self.c[i0] ^ self.c[i1]
|
||||
elif op == SimPrim.XNOR2: self.c[o0] = ~(self.c[i0] ^ self.c[i1])
|
||||
else: print(f'unknown SimPrim {op}')
|
||||
if inject_cb is not None: inject_cb(o0, self.s[o0])
|
||||
pass
|
||||
elif self.m == 4:
|
||||
pass
|
||||
else:
|
||||
for op, o0, i0, i1, i2, i3 in self.ops:
|
||||
o0, i0, i1, i2, i3 = [self.vat[x,0] for x in (o0, i0, i1, i2, i3)]
|
||||
if op == SimPrim.BUF1: self.c[o0]=self.c[i0]
|
||||
|
||||
Reference in new issue
Block a user