docs, fix stil unassigned, fix io_locs for busses
This commit is contained in:
1 parent
947df89434
commit
0968cb451e
6 files changed
+45
-13
No files matched your search
@@ -1,3 +1,5 @@
|
|||||||
|
# pip install sphinx sphinx-rtd-theme
|
||||||
|
#
|
||||||
# Minimal makefile for Sphinx documentation
|
# Minimal makefile for Sphinx documentation
|
||||||
#
|
#
|
||||||
|
|
||||||
|
|||||||
+27
-1
@@ -291,6 +291,15 @@ class Circuit:
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def stats(self):
|
def stats(self):
|
||||||
|
"""Generates a dictionary with the number of all different elements in the circuit.
|
||||||
|
|
||||||
|
The dictionary contains the number of all different kinds of nodes, the number
|
||||||
|
of lines, as well various sums like number of combinational gates, number of
|
||||||
|
primary I/Os, number of sequential elements, and so on.
|
||||||
|
|
||||||
|
The count of regular cells use their `Node.kind` as key, other statistics use
|
||||||
|
dunder-keys like: `__comb__`, `__io__`, `__seq__`, and so on.
|
||||||
|
"""
|
||||||
stats = defaultdict(int)
|
stats = defaultdict(int)
|
||||||
stats['__node__'] = len(self.nodes)
|
stats['__node__'] = len(self.nodes)
|
||||||
stats['__cell__'] = len(self.cells)
|
stats['__cell__'] = len(self.cells)
|
||||||
@@ -386,15 +395,31 @@ class Circuit:
|
|||||||
yield stem, region
|
yield stem, region
|
||||||
|
|
||||||
def io_locs(self, prefix):
|
def io_locs(self, prefix):
|
||||||
|
"""Returns the indices of primary I/Os that start with given name prefix.
|
||||||
|
|
||||||
|
The returned values are used to index into the :py:attr:`io_nodes` array.
|
||||||
|
If only one I/O cell matches the given prefix, a single integer is returned.
|
||||||
|
If a bus matches the given prefix, a sorted list of indices is returned.
|
||||||
|
Busses are identified by integers in the cell names following the given prefix.
|
||||||
|
Lists for bus indices are sorted from LSB (e.g. `data[0]`) to MSB (e.g. `data[31]`).
|
||||||
|
If a prefix matches multiple different signals or busses, alphanumerically sorted
|
||||||
|
lists of lists are returned. Therefore, higher-dimensional busses
|
||||||
|
(e.g. `data0[0], data0[1], ...`, `data1[0], data1[1], ...`) are supported as well.
|
||||||
|
"""
|
||||||
return self._locs(prefix, list(self.io_nodes))
|
return self._locs(prefix, list(self.io_nodes))
|
||||||
|
|
||||||
def s_locs(self, prefix):
|
def s_locs(self, prefix):
|
||||||
|
"""Returns the indices of I/Os and sequential elements that start with given name prefix.
|
||||||
|
|
||||||
|
The returned values are used to index into the :py:attr:`s_nodes` array.
|
||||||
|
It works the same as :py:attr:`io_locs`. See there for more details.
|
||||||
|
"""
|
||||||
return self._locs(prefix, self.s_nodes)
|
return self._locs(prefix, self.s_nodes)
|
||||||
|
|
||||||
def _locs(self, prefix, nodes):
|
def _locs(self, prefix, nodes):
|
||||||
d_top = dict()
|
d_top = dict()
|
||||||
for i, n in enumerate(nodes):
|
for i, n in enumerate(nodes):
|
||||||
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]:
|
||||||
@@ -402,6 +427,7 @@ class Circuit:
|
|||||||
d = d[j]
|
d = d[j]
|
||||||
d[path[-1]] = i
|
d[path[-1]] = i
|
||||||
|
|
||||||
|
# sort recursively for multi-dimensional lists.
|
||||||
def sorted_values(d): return [sorted_values(v) for k, v in sorted(d.items())] if isinstance(d, dict) else d
|
def sorted_values(d): return [sorted_values(v) for k, v in sorted(d.items())] if isinstance(d, dict) else d
|
||||||
l = sorted_values(d_top)
|
l = sorted_values(d_top)
|
||||||
while isinstance(l, list) and len(l) == 1: l = l[0]
|
while isinstance(l, list) and len(l) == 1: l = l[0]
|
||||||
|
|||||||
+1
-1
@@ -17,7 +17,7 @@ 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 = 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.
|
* 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.
|
2-valued logic only considers bit0, but should store logic one as ``ONE=0b011`` for interoperability.
|
||||||
4-valued logic only considers bit0 and bit1.
|
4-valued logic only considers bit0 and bit1.
|
||||||
8-valued logic considers all 3 bits.
|
8-valued logic considers all 3 bits.
|
||||||
|
|
||||||
|
|||||||
@@ -46,17 +46,12 @@ class LogicSim(sim.SimOps):
|
|||||||
"""
|
"""
|
||||||
self.c[self.pippi_c_locs] = self.s[0, self.pippi_s_locs, :self.mdim]
|
self.c[self.pippi_c_locs] = self.s[0, self.pippi_s_locs, :self.mdim]
|
||||||
|
|
||||||
def c_to_s(self): #, responses, ff_transitions=False):
|
def c_to_s(self):
|
||||||
"""Capture the current values at the primary outputs and in the state-elements (flip-flops).
|
"""Capture the current values at the primary outputs and in the state-elements (flip-flops).
|
||||||
|
|
||||||
For primary outputs, the logic value is stored unmodified in the given target array.
|
For primary outputs, the logic value is stored unmodified in the given target array.
|
||||||
For flip-flops, the logic value is either stored unmodified (`ff_transitions=False`)
|
For flip-flops, the logic value is either stored unmodified (`ff_transitions=False`)
|
||||||
or constructed from the previous state and the new state (`ff_transitions=True`).
|
or constructed from the previous state and the new state (`ff_transitions=True`).
|
||||||
|
|
||||||
:param responses: A bit-parallel storage target for the responses in a compatible shape.
|
|
||||||
:type responses: :py:class:`~kyupy.logic.BPArray`
|
|
||||||
:param ff_transitions: If true, calculate and store the transitions between the previous state
|
|
||||||
(the currently assigned pattern) and the new state.
|
|
||||||
:returns: The given responses object.
|
|
||||||
"""
|
"""
|
||||||
self.s[1, self.poppo_s_locs, :self.mdim] = 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:
|
if self.mdim == 1:
|
||||||
|
|||||||
+11
-3
@@ -95,12 +95,15 @@ class StilFile:
|
|||||||
tests = np.full((len(interface), len(self.patterns)), logic.UNASSIGNED)
|
tests = np.full((len(interface), len(self.patterns)), logic.UNASSIGNED)
|
||||||
for i, p in enumerate(self.patterns):
|
for i, p in enumerate(self.patterns):
|
||||||
for si_port in self.si_ports.keys():
|
for si_port in self.si_ports.keys():
|
||||||
pattern = logic.mv_xor(logic.mvarray(p.load[si_port]), scan_inversions[si_port])
|
pattern = logic.mvarray(p.load[si_port])
|
||||||
|
inversions = np.choose((pattern == logic.UNASSIGNED) | (pattern == logic.UNKNOWN),
|
||||||
|
[scan_inversions[si_port], logic.ZERO]).astype(np.uint8)
|
||||||
|
np.bitwise_xor(pattern, inversions, out=pattern)
|
||||||
tests[scan_maps[si_port], i] = pattern
|
tests[scan_maps[si_port], i] = pattern
|
||||||
tests[pi_map, i] = logic.mvarray(p.capture['_pi'])
|
tests[pi_map, i] = logic.mvarray(p.capture['_pi'])
|
||||||
return tests
|
return tests
|
||||||
|
|
||||||
def tests_loc(self, circuit):
|
def tests_loc(self, circuit, init_filter=None, launch_filter=None):
|
||||||
"""Assembles and returns a LoC scan test pattern set for given circuit.
|
"""Assembles and returns a LoC scan test pattern set for given circuit.
|
||||||
|
|
||||||
This function assumes a launch-on-capture (LoC) delay test.
|
This function assumes a launch-on-capture (LoC) delay test.
|
||||||
@@ -112,9 +115,13 @@ class StilFile:
|
|||||||
for i, p in enumerate(self.patterns):
|
for i, p in enumerate(self.patterns):
|
||||||
# init.set_values(i, '0' * len(interface))
|
# init.set_values(i, '0' * len(interface))
|
||||||
for si_port in self.si_ports.keys():
|
for si_port in self.si_ports.keys():
|
||||||
pattern = logic.mv_xor(logic.mvarray(p.load[si_port]), scan_inversions[si_port])
|
pattern = logic.mvarray(p.load[si_port])
|
||||||
|
inversions = np.choose((pattern == logic.UNASSIGNED) | (pattern == logic.UNKNOWN),
|
||||||
|
[scan_inversions[si_port], logic.ZERO]).astype(np.uint8)
|
||||||
|
np.bitwise_xor(pattern, inversions, out=pattern)
|
||||||
init[scan_maps[si_port], i] = pattern
|
init[scan_maps[si_port], i] = pattern
|
||||||
init[pi_map, i] = logic.mvarray(p.launch['_pi'] if '_pi' in p.launch else p.capture['_pi'])
|
init[pi_map, i] = logic.mvarray(p.launch['_pi'] if '_pi' in p.launch else p.capture['_pi'])
|
||||||
|
if init_filter: init = init_filter(init)
|
||||||
sim8v = LogicSim(circuit, init.shape[-1], m=8)
|
sim8v = LogicSim(circuit, init.shape[-1], m=8)
|
||||||
sim8v.s[0] = logic.mv_to_bp(init)
|
sim8v.s[0] = logic.mv_to_bp(init)
|
||||||
sim8v.s_to_c()
|
sim8v.s_to_c()
|
||||||
@@ -130,6 +137,7 @@ class StilFile:
|
|||||||
if '_pi' in p.capture and 'P' in p.capture['_pi']:
|
if '_pi' in p.capture and 'P' in p.capture['_pi']:
|
||||||
launch[pi_map, i] = logic.mvarray(p.capture['_pi'])
|
launch[pi_map, i] = logic.mvarray(p.capture['_pi'])
|
||||||
launch[po_map, i] = logic.UNASSIGNED
|
launch[po_map, i] = logic.UNASSIGNED
|
||||||
|
if launch_filter: launch = launch_filter(launch)
|
||||||
|
|
||||||
return logic.mv_transition(init, launch)
|
return logic.mv_transition(init, launch)
|
||||||
|
|
||||||
|
|||||||
@@ -44,12 +44,13 @@ class WaveSim(sim.SimOps):
|
|||||||
:param strip_forks: If enabled, the simulator will not evaluate fork nodes explicitly. This saves simulation time
|
:param strip_forks: If enabled, the simulator will not evaluate fork nodes explicitly. This saves simulation time
|
||||||
by reducing the number of nodes to simulate, but (interconnect) delay annotations of lines read by fork nodes
|
by reducing the number of nodes to simulate, but (interconnect) delay annotations of lines read by fork nodes
|
||||||
are ignored.
|
are ignored.
|
||||||
:param keep_waveforms: If disabled, memory of intermediate signal waveforms will be re-used. This greatly reduces
|
:param c_reuse: If enabled, memory of intermediate signal waveforms will be re-used. This greatly reduces
|
||||||
memory footprint, but intermediate signal waveforms become unaccessible after a propagation.
|
memory footprint, but intermediate signal waveforms become unaccessible after a propagation.
|
||||||
"""
|
"""
|
||||||
def __init__(self, circuit, delays, sims=8, c_caps=16, c_reuse=False, strip_forks=False):
|
def __init__(self, circuit, delays, sims=8, c_caps=16, c_reuse=False, strip_forks=False):
|
||||||
super().__init__(circuit, c_caps=c_caps, c_caps_min=4, c_reuse=c_reuse, strip_forks=strip_forks)
|
super().__init__(circuit, c_caps=c_caps, c_caps_min=4, c_reuse=c_reuse, strip_forks=strip_forks)
|
||||||
self.sims = sims
|
self.sims = sims
|
||||||
|
if delays.ndim == 3: delays = np.expand_dims(delays, axis=0)
|
||||||
self.delays = np.zeros((len(delays), self.c_locs_len, 2, 2), dtype=delays.dtype)
|
self.delays = np.zeros((len(delays), self.c_locs_len, 2, 2), dtype=delays.dtype)
|
||||||
self.delays[:, :delays.shape[1]] = delays
|
self.delays[:, :delays.shape[1]] = delays
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user