Compare commits
140
Commits
v0.0.4
...
a6d1e4099c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a6d1e4099c | ||
|
|
1654915ed6 | ||
|
|
d2a2484efa | ||
|
|
de79393dfc | ||
|
|
4bb3f3424a | ||
|
|
a6243b43f6 | ||
|
|
baeb759824 | ||
|
|
967a232b1c | ||
|
|
8096416b0e | ||
|
|
a4cce9f8c0 | ||
|
|
4f6b733eb4 | ||
|
|
371bc906b3 | ||
|
|
0ade89defa | ||
|
|
7f4026f504 | ||
|
|
e6a0d59d44 | ||
|
|
63e5f32e21 | ||
|
|
35e727e714 | ||
|
|
83445e2bbd | ||
|
|
c67148c0ee | ||
|
|
280c425486 | ||
|
|
5be82da49a | ||
|
|
b3dbe9765a | ||
|
|
5e573b0408 | ||
|
|
08d9f5a9bf | ||
|
|
b098fb219d | ||
|
|
97387e962b | ||
|
|
f4d875f7e5 | ||
|
|
cf9a98b5ce | ||
|
|
d8f605a47a | ||
|
|
ec5626b8ca | ||
|
|
5a693f7b9b | ||
|
|
19bbe2c260 | ||
|
|
d3897246c5 | ||
|
|
9bda7a4c57 | ||
|
|
2270a9eee7 | ||
|
|
ea45a326ec | ||
|
|
1e9fe7707b | ||
|
|
50a5d8a290 | ||
|
|
d97555e9e9 | ||
|
|
47ee8d5878 | ||
|
|
c32584fc76 | ||
|
|
39b8c1695b | ||
|
|
80d26b6f0b | ||
|
|
f7ef78e58d | ||
|
|
7afb13b33b | ||
|
|
153442a10a | ||
|
|
afb0a64953 | ||
|
|
c49667edc1 | ||
|
|
d921eb5048 | ||
|
|
670fb0b3fc | ||
|
|
f8bf579be2 | ||
|
|
f61e2b42e8 | ||
|
|
4aec335abb | ||
|
|
1a9cb396bf | ||
|
|
3875dc38f9 | ||
|
|
ecb7171c37 | ||
|
|
8957db48ab | ||
|
|
0b15f9fa18 | ||
|
|
dc76a9f517 | ||
|
|
0968cb451e | ||
|
|
947df89434 | ||
|
|
f17e461fdd | ||
|
|
d6d981a351 | ||
|
|
7a060b1831 | ||
|
|
03802ac9f8 | ||
|
|
70caea065e | ||
|
|
f04f1b0012 | ||
|
|
44b0c887d7 | ||
|
|
4e2022291e | ||
|
|
5566b80e52 | ||
|
|
63c0b48537 | ||
|
|
6520ee23ef | ||
|
|
1810d40959 | ||
|
|
7430ebb068 | ||
|
|
89f317b463 | ||
|
|
753ce566e4 | ||
|
|
1eb8d87884 | ||
|
|
02f3a0e1b2 | ||
|
|
fc8e65e788 | ||
|
|
d80a3ae2b1 | ||
|
|
7bfc02e683 | ||
|
|
8da4a62bce | ||
|
|
3497bfdc75 | ||
|
|
f1ebe1487c | ||
|
|
f0dac36ac7 | ||
|
|
b2953aef25 | ||
|
|
3774b14286 | ||
|
|
4847ad9c40 | ||
|
|
6801606dca | ||
|
|
faf41f0863 | ||
|
|
6430f10f73 | ||
|
|
fa19af8c31 | ||
|
|
93a0858d2f | ||
|
|
1f2808ee31 | ||
|
|
163b348a0c | ||
|
|
ecfc692edc | ||
|
|
afb7e745a1 | ||
|
|
6a8841c3c6 | ||
|
|
c530983afa | ||
|
|
775b13c694 | ||
|
|
584445f3b1 | ||
|
|
85dd02d4d7 | ||
|
|
7c03271048 | ||
|
|
8bbaaf8fae | ||
|
|
d59d6401c8 | ||
|
|
387c436207 | ||
|
|
b981b1153c | ||
|
|
87d93afb44 | ||
|
|
c3e4090f31 | ||
|
|
0251d66d28 | ||
|
|
864230b883 | ||
|
|
d05841a6a2 | ||
|
|
c5be32d7e5 | ||
|
|
8434f5e694 | ||
|
|
9ff2369a55 | ||
|
|
82a53e0171 | ||
|
|
a2df0e5682 | ||
|
|
ec37e11fef | ||
|
|
3a5a3c128b | ||
|
|
ee30898cef | ||
|
|
62cf56e98a | ||
|
|
dc003fa624 | ||
|
|
8b5a71f498 | ||
|
|
9c8dee31b9 | ||
|
|
2bbdf3ee5d | ||
|
|
35cf63cf38 | ||
|
|
ff4de6d782 | ||
|
|
c12a30328c | ||
|
|
7e6660002b | ||
|
|
dfbc35eeb9 | ||
|
|
4f531fe4cb | ||
|
|
18c17b5f76 | ||
|
|
0bad95e94e | ||
|
|
7501613951 | ||
|
|
5084f1dd8c | ||
|
|
7f035c1ac5 | ||
|
|
7bcfbf502b | ||
|
|
5830608527 | ||
|
|
cff18e0915 | ||
|
|
a77ac4a397 |
No files matched your search
+1
-1
@@ -24,7 +24,7 @@ copyright = '2020-2023, Stefan Holst'
|
||||
author = 'Stefan Holst'
|
||||
|
||||
# The full version, including alpha/beta/rc tags
|
||||
release = '0.0.4'
|
||||
release = '0.0.5'
|
||||
|
||||
|
||||
# -- General configuration ---------------------------------------------------
|
||||
|
||||
@@ -5,7 +5,7 @@ with open('README.rst', 'r') as f:
|
||||
|
||||
setup(
|
||||
name='kyupy',
|
||||
version='0.0.4',
|
||||
version='0.0.5',
|
||||
description='High-performance processing and analysis of non-hierarchical VLSI designs',
|
||||
long_description=long_description,
|
||||
long_description_content_type='text/x-rst',
|
||||
|
||||
+15
-3
@@ -57,6 +57,18 @@ def hr_bytes(nbytes):
|
||||
multiplier += 1
|
||||
return f'{nbytes:.1f}{["", "ki", "Mi", "Gi", "Ti", "Pi"][multiplier]}B'
|
||||
|
||||
def eng(number):
|
||||
"""Formats a given number using engineering notation."""
|
||||
exponent = 0
|
||||
if abs(number) < 1:
|
||||
while abs(number) >= 1000:
|
||||
number *= 1000
|
||||
exponent -= 3
|
||||
else:
|
||||
while abs(number) >= 1000:
|
||||
number /= 1000
|
||||
exponent += 3
|
||||
return f'{number:.0f}' + (f'e{exponent}' if exponent != 0 else '')
|
||||
|
||||
def hr_time(seconds):
|
||||
"""Formats a given time interval for human readability."""
|
||||
@@ -138,10 +150,10 @@ class Log:
|
||||
self._limit = limit
|
||||
|
||||
def stop_limit(self):
|
||||
if self.filtered > 0:
|
||||
log.info(f'{self.filtered} more messages (filtered).')
|
||||
self.filtered = 0
|
||||
self._limit = -1
|
||||
if self.filtered > 0:
|
||||
self.info(f'{self.filtered} more messages (filtered).')
|
||||
self.filtered = 0
|
||||
|
||||
def __getstate__(self):
|
||||
return {'elapsed': time.perf_counter() - self.start}
|
||||
|
||||
+61
-14
@@ -10,20 +10,35 @@ Circuit graphs also define an ordering of inputs, outputs and other nodes to eas
|
||||
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from collections import deque, defaultdict
|
||||
import re
|
||||
from typing import Union
|
||||
|
||||
import numpy as np
|
||||
|
||||
|
||||
class GrowingList(list):
|
||||
def __setitem__(self, index, value):
|
||||
if index >= len(self):
|
||||
self.extend([None] * (index + 1 - len(self)))
|
||||
if value is None: self.has_nones = True
|
||||
if index == len(self): return super().append(value)
|
||||
if index > len(self):
|
||||
super().extend([None] * (index + 1 - len(self)))
|
||||
self.has_nones = True
|
||||
super().__setitem__(index, value)
|
||||
|
||||
def free_index(self):
|
||||
return next((i for i, x in enumerate(self) if x is None), len(self))
|
||||
def __getitem__(self, index):
|
||||
if isinstance(index, slice): return super().__getitem__(index)
|
||||
return super().__getitem__(index) if index < len(self) else None
|
||||
|
||||
@property
|
||||
def free_idx(self):
|
||||
fi = len(self)
|
||||
if hasattr(self, 'has_nones') and self.has_nones:
|
||||
fi = next((i for i, x in enumerate(self) if x is None), len(self))
|
||||
self.has_nones = fi < len(self)
|
||||
return fi
|
||||
|
||||
|
||||
class IndexList(list):
|
||||
@@ -76,10 +91,10 @@ class Node:
|
||||
by allocating an array or list :code:`my_data` of length :code:`len(n.circuit.nodes)` and
|
||||
accessing it by :code:`my_data[n.index]` or simply by :code:`my_data[n]`.
|
||||
"""
|
||||
self.ins = GrowingList()
|
||||
self.ins: list[Line] = GrowingList()
|
||||
"""A list of input connections (:class:`Line` objects).
|
||||
"""
|
||||
self.outs = GrowingList()
|
||||
self.outs: list[Line] = GrowingList()
|
||||
"""A list of output connections (:class:`Line` objects).
|
||||
"""
|
||||
|
||||
@@ -135,7 +150,7 @@ class Line:
|
||||
Use the explicit case only if connections to specific pins are required.
|
||||
It may overwrite any previous line references in the connection list of the nodes.
|
||||
"""
|
||||
def __init__(self, circuit, driver, reader):
|
||||
def __init__(self, circuit: Circuit, driver: Union[Node, tuple[Node, int]], reader: Union[Node, tuple[Node, int]]):
|
||||
self.circuit = circuit
|
||||
"""The :class:`Circuit` object the line is part of.
|
||||
"""
|
||||
@@ -147,7 +162,7 @@ class Line:
|
||||
by allocating an array or list :code:`my_data` of length :code:`len(l.circuit.lines)` and
|
||||
accessing it by :code:`my_data[l.index]` or simply by :code:`my_data[l]`.
|
||||
"""
|
||||
if not isinstance(driver, tuple): driver = (driver, driver.outs.free_index())
|
||||
if not isinstance(driver, tuple): driver = (driver, driver.outs.free_idx)
|
||||
self.driver = driver[0]
|
||||
"""The :class:`Node` object that drives this line.
|
||||
"""
|
||||
@@ -157,7 +172,7 @@ class Line:
|
||||
This is the position in the list :py:attr:`Node.outs` of the driving node this line referenced from:
|
||||
:code:`self.driver.outs[self.driver_pin] == self`.
|
||||
"""
|
||||
if not isinstance(reader, tuple): reader = (reader, reader.ins.free_index())
|
||||
if not isinstance(reader, tuple): reader = (reader, reader.ins.free_idx)
|
||||
self.reader = reader[0]
|
||||
"""The :class:`Node` object that reads this line.
|
||||
"""
|
||||
@@ -334,15 +349,16 @@ class Circuit:
|
||||
def get_or_add_fork(self, name):
|
||||
return self.forks[name] if name in self.forks else Node(self, name)
|
||||
|
||||
def remove_dangling_nodes(self, root_node:Node):
|
||||
def remove_dangling_nodes(self, root_node:Node, keep=[]):
|
||||
if len([l for l in root_node.outs if l is not None]) > 0: return
|
||||
lines = [l for l in root_node.ins if l is not None]
|
||||
drivers = [l.driver for l in lines]
|
||||
if root_node in keep: return
|
||||
root_node.remove()
|
||||
for l in lines:
|
||||
l.remove()
|
||||
for d in drivers:
|
||||
self.remove_dangling_nodes(d)
|
||||
self.remove_dangling_nodes(d, keep=keep)
|
||||
|
||||
def eliminate_1to1_forks(self):
|
||||
"""Removes all forks that drive only one node.
|
||||
@@ -370,6 +386,21 @@ class Circuit:
|
||||
in_line.reader_pin = out_reader_pin
|
||||
in_line.reader.ins[in_line.reader_pin] = in_line
|
||||
|
||||
def remove_forks(self):
|
||||
ios = set(self.io_nodes)
|
||||
for n in list(self.forks.values()):
|
||||
if n in ios: continue
|
||||
d = None
|
||||
if (l := n.ins[0]) is not None:
|
||||
d = l.driver
|
||||
l.remove()
|
||||
for l in list(n.outs):
|
||||
if l is None: continue
|
||||
r, rp = l.reader, l.reader_pin
|
||||
l.remove()
|
||||
if d is not None: Line(self, d, (r, rp))
|
||||
n.remove()
|
||||
|
||||
def substitute(self, node, impl):
|
||||
"""Replaces a given node with the given implementation circuit.
|
||||
|
||||
@@ -428,7 +459,7 @@ class Circuit:
|
||||
for l, ll in zip(impl_out_lines, node_out_lines): # connect outputs
|
||||
if ll is None:
|
||||
if l.driver in node_map:
|
||||
self.remove_dangling_nodes(node_map[l.driver])
|
||||
self.remove_dangling_nodes(node_map[l.driver], keep=ios)
|
||||
continue
|
||||
if len(l.reader.outs) > 0: # output is also read by impl. circuit, connect to fork.
|
||||
ll.driver = node_map[l.reader]
|
||||
@@ -447,6 +478,21 @@ class Circuit:
|
||||
if n.kind in tlib.cells:
|
||||
self.substitute(n, tlib.cells[n.kind][0])
|
||||
|
||||
def remove_constants(self):
|
||||
c1gen = None
|
||||
for n in self.nodes:
|
||||
if n.kind == '__const0__': # just remove, unconnected inputs are defined 0.
|
||||
for l in n.outs:
|
||||
l.remove()
|
||||
n.remove()
|
||||
elif n.kind == '__const1__':
|
||||
if c1gen is None: c1gen = Node(self, '__const1gen__', 'INV1') # one unique const 1 generator
|
||||
for l in n.outs:
|
||||
r, rp = l.reader, l.reader_pin
|
||||
l.remove()
|
||||
Line(self, c1gen, (r, rp))
|
||||
n.remove()
|
||||
|
||||
def copy(self):
|
||||
"""Returns a deep copy of the circuit.
|
||||
"""
|
||||
@@ -501,14 +547,15 @@ class Circuit:
|
||||
substrings 'dff' or 'latch' are yielded first.
|
||||
"""
|
||||
visit_count = np.zeros(len(self.nodes), dtype=np.uint32)
|
||||
queue = deque(n for n in self.nodes if len(n.ins) == 0 or 'dff' in n.kind.lower() or 'latch' in n.kind.lower())
|
||||
start = set(n for n in self.nodes if len(n.ins) == 0 or 'dff' in n.kind.lower() or 'latch' in n.kind.lower())
|
||||
queue = deque(start)
|
||||
while len(queue) > 0:
|
||||
n = queue.popleft()
|
||||
for line in n.outs:
|
||||
if line is None: continue
|
||||
succ = line.reader
|
||||
visit_count[succ] += 1
|
||||
if visit_count[succ] == len(succ.ins) and 'dff' not in succ.kind.lower() and 'latch' not in succ.kind.lower():
|
||||
if visit_count[succ] == len(succ.ins) and succ not in start:
|
||||
queue.append(succ)
|
||||
yield n
|
||||
|
||||
|
||||
+5
-1
@@ -241,6 +241,8 @@ def mv_latch(d, t, q_prev, out=None):
|
||||
def mv_transition(init, final, out=None):
|
||||
"""Computes the logic transitions from the initial values of ``init`` to the final values of ``final``.
|
||||
Pulses in the input data are ignored. If any of the inputs are ``UNKNOWN``, the result is ``UNKNOWN``.
|
||||
If init is ``UNASSIGNED``, the result is the final value of ``final``.
|
||||
If final is ``UNASSIGNED``, the result is the initial value of ``init``.
|
||||
If both inputs are ``UNASSIGNED``, the result is ``UNASSIGNED``.
|
||||
|
||||
:param init: A multi-valued array.
|
||||
@@ -251,7 +253,9 @@ def mv_transition(init, final, out=None):
|
||||
out = out or np.empty(np.broadcast(init, final).shape, dtype=np.uint8)
|
||||
out[...] = (init & 0b010) | (final & 0b001)
|
||||
out[...] |= ((out << 1) ^ (out << 2)) & 0b100
|
||||
unknown = (init == UNKNOWN) | (init == UNASSIGNED) | (final == UNKNOWN) | (final == UNASSIGNED)
|
||||
out[...] = np.choose(init == UNASSIGNED, [out, (final & 0b001) * ONE])
|
||||
out[...] = np.choose(final == UNASSIGNED, [out, ((init & 0b010) >> 1) * ONE])
|
||||
unknown = (init == UNKNOWN) | (final == UNKNOWN)
|
||||
unassigned = (init == UNASSIGNED) & (final == UNASSIGNED)
|
||||
np.putmask(out, unknown, UNKNOWN)
|
||||
np.putmask(out, unassigned, UNASSIGNED)
|
||||
|
||||
@@ -10,7 +10,7 @@ import math
|
||||
|
||||
import numpy as np
|
||||
|
||||
from . import numba, logic, hr_bytes, sim
|
||||
from . import numba, logic, hr_bytes, sim, eng
|
||||
from .circuit import Circuit
|
||||
|
||||
class LogicSim(sim.SimOps):
|
||||
@@ -44,7 +44,7 @@ class LogicSim(sim.SimOps):
|
||||
self.s[:,:,1,:] = 255 # unassigned
|
||||
|
||||
def __repr__(self):
|
||||
return f'{{name: "{self.circuit.name}", sims: {self.sims}, m: {self.m}, c_bytes: {self.c.nbytes}}}'
|
||||
return f'{{name: "{self.circuit.name}", sims: {self.sims}, m: {self.m}, c_bytes: {eng(self.c.nbytes)}}}'
|
||||
|
||||
def s_to_c(self):
|
||||
"""Copies the values from ``s[0]`` the inputs of the combinational portion.
|
||||
@@ -105,7 +105,7 @@ class LogicSim(sim.SimOps):
|
||||
elif op == sim.OAI211:self.c[o0] = ~((self.c[i0] | self.c[i1]) & self.c[i2] & self.c[i3])
|
||||
elif op == sim.MUX21: self.c[o0] = (self.c[i0] & ~self.c[i2]) | (self.c[i1] & self.c[i2])
|
||||
else: print(f'unknown op {op}')
|
||||
inject_cb(o0, self.s[o0])
|
||||
inject_cb(o0, self.c[o0])
|
||||
elif self.m == 4:
|
||||
for op, o0, i0, i1, i2, i3 in self.ops[:,:6]:
|
||||
o0, i0, i1, i2, i3 = [self.c_locs[x] for x in (o0, i0, i1, i2, i3)]
|
||||
@@ -181,6 +181,7 @@ class LogicSim(sim.SimOps):
|
||||
logic.bp4v_and(self.c[t1], self.c[i1], self.c[i2])
|
||||
logic.bp4v_or(self.c[o0], self.c[t0], self.c[t1])
|
||||
else: print(f'unknown op {op}')
|
||||
if inject_cb is not None: inject_cb(o0, self.c[o0])
|
||||
else:
|
||||
for op, o0, i0, i1, i2, i3 in self.ops[:,:6]:
|
||||
o0, i0, i1, i2, i3 = [self.c_locs[x] for x in (o0, i0, i1, i2, i3)]
|
||||
@@ -256,7 +257,7 @@ class LogicSim(sim.SimOps):
|
||||
logic.bp8v_and(self.c[t1], self.c[i1], self.c[i2])
|
||||
logic.bp8v_or(self.c[o0], self.c[t0], self.c[t1])
|
||||
else: print(f'unknown op {op}')
|
||||
if inject_cb is not None: inject_cb(o0, self.s[o0])
|
||||
if inject_cb is not None: inject_cb(o0, self.c[o0])
|
||||
|
||||
def c_to_s(self):
|
||||
"""Copies (captures) the results of the combinational portion to ``s[1]``.
|
||||
|
||||
+9
-1
@@ -61,6 +61,7 @@ class DelayFile:
|
||||
|
||||
delays = np.zeros((len(circuit.lines), 2, 2, 3)) # dataset last during construction.
|
||||
|
||||
with log.limit(50):
|
||||
for name, iopaths in self.cells.items():
|
||||
name = name.replace('\\', '')
|
||||
if cell := circuit.cells.get(name, None):
|
||||
@@ -156,6 +157,10 @@ class SdfTransformer(Transformer):
|
||||
entries = [e for a in args if hasattr(a, 'children') for e in a.children]
|
||||
return name, entries
|
||||
|
||||
@staticmethod
|
||||
def cond(args): # ignore conditions
|
||||
return args[1]
|
||||
|
||||
@staticmethod
|
||||
def start(args):
|
||||
name = next((a for a in args if isinstance(a, str)), None)
|
||||
@@ -180,9 +185,12 @@ GRAMMAR = r"""
|
||||
| "(INSTANCE" ID? ")"
|
||||
| "(TIMINGCHECK" _ignore* ")"
|
||||
| delay )* ")"
|
||||
delay: "(DELAY" "(ABSOLUTE" (interconnect | iopath)* ")" ")"
|
||||
delay: "(DELAY" "(ABSOLUTE" (interconnect | iopath | cond)* ")" ")"
|
||||
interconnect: "(INTERCONNECT" ID ID triple* ")"
|
||||
iopath: "(IOPATH" ID_OR_EDGE ID_OR_EDGE triple* ")"
|
||||
cond: "(" "COND" cond_port_expr iopath ")"
|
||||
?cond_port_expr: ID | "(" cond_port_expr ")" | cond_port_expr BINARY_OP cond_port_expr
|
||||
BINARY_OP: /&&/ | /==/
|
||||
NAME: /[^"]+/
|
||||
ID_OR_EDGE: ( /[^() ]+/ | "(" /[^)]+/ ")" )
|
||||
ID: ( /[^"() ]+/ | "\"" /[^"]+/ "\"" )
|
||||
|
||||
+61
-61
@@ -4,9 +4,14 @@ from bisect import bisect, insort_left
|
||||
|
||||
import numpy as np
|
||||
|
||||
from .circuit import Circuit
|
||||
|
||||
BUF1 = np.uint16(0b1010_1010_1010_1010)
|
||||
INV1 = ~BUF1
|
||||
|
||||
__const0__ = BUF1
|
||||
__const1__ = INV1
|
||||
|
||||
AND2 = np.uint16(0b1000_1000_1000_1000)
|
||||
AND3 = np.uint16(0b1000_0000_1000_0000)
|
||||
AND4 = np.uint16(0b1000_0000_0000_0000)
|
||||
@@ -39,7 +44,10 @@ AOI211, OAI211 = ~AO211, ~OA211
|
||||
|
||||
MUX21 = np.uint16(0b1100_1010_1100_1010) # z = i1 if i2 else i0 (i2 is select)
|
||||
|
||||
names = dict([(v, k) for k, v in globals().items() if isinstance(v, np.uint16)])
|
||||
names = dict([(v, k) for k, v in globals().items() if isinstance(v, np.uint16) and '__' not in k])
|
||||
|
||||
prim2name = dict([(v, k) for k, v in globals().items() if isinstance(v, np.uint16) and '__' not in k])
|
||||
name2prim = dict([(k, v) for k, v in globals().items() if isinstance(v, np.uint16)])
|
||||
|
||||
kind_prefixes = {
|
||||
'nand': (NAND4, NAND3, NAND2),
|
||||
@@ -156,7 +164,7 @@ class SimOps:
|
||||
: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.
|
||||
"""
|
||||
def __init__(self, circuit, c_caps=1, c_caps_min=1, a_ctrl=None, c_reuse=False, strip_forks=False):
|
||||
def __init__(self, circuit: Circuit, c_caps=1, c_caps_min=1, a_ctrl=None, c_reuse=False, strip_forks=False):
|
||||
self.circuit = circuit
|
||||
self.s_len = len(circuit.s_nodes)
|
||||
|
||||
@@ -175,84 +183,75 @@ class SimOps:
|
||||
self.ppo_offset = self.ppi_offset + self.s_len
|
||||
self.c_locs_len = self.ppo_offset + self.s_len
|
||||
|
||||
# translate circuit structure into self.ops
|
||||
ops = []
|
||||
interface_dict = dict((n, i) for i, n in enumerate(circuit.s_nodes))
|
||||
for n in circuit.topological_order():
|
||||
if n in interface_dict:
|
||||
inp_idx = self.ppi_offset + interface_dict[n]
|
||||
if len(n.outs) > 0 and n.outs[0] is not None: # first output of a PI/PPI
|
||||
ops.append((BUF1, n.outs[0].index, inp_idx, self.zero_idx, self.zero_idx, self.zero_idx, *a_ctrl[n.outs[0]]))
|
||||
if 'dff' in n.kind.lower(): # second output of DFF is inverted
|
||||
if len(n.outs) > 1 and n.outs[1] is not None:
|
||||
ops.append((INV1, n.outs[1].index, inp_idx, self.zero_idx, self.zero_idx, self.zero_idx, *a_ctrl[n.outs[1]]))
|
||||
else: # if not DFF, no output is inverted.
|
||||
for o_line in n.outs[1:]:
|
||||
if o_line is not None:
|
||||
ops.append((BUF1, o_line.index, inp_idx, self.zero_idx, self.zero_idx, self.zero_idx, *a_ctrl[o_line]))
|
||||
continue
|
||||
# regular node, not PI/PPI or PO/PPO
|
||||
o0_idx = n.outs[0].index if len(n.outs) > 0 and n.outs[0] is not None else self.tmp_idx
|
||||
i0_idx = n.ins[0].index if len(n.ins) > 0 and n.ins[0] is not None else self.zero_idx
|
||||
i1_idx = n.ins[1].index if len(n.ins) > 1 and n.ins[1] is not None else self.zero_idx
|
||||
i2_idx = n.ins[2].index if len(n.ins) > 2 and n.ins[2] is not None else self.zero_idx
|
||||
i3_idx = n.ins[3].index if len(n.ins) > 3 and n.ins[3] is not None else self.zero_idx
|
||||
kind = n.kind.lower()
|
||||
if kind == '__fork__':
|
||||
if not strip_forks:
|
||||
for o_line in n.outs:
|
||||
if o_line is not None:
|
||||
ops.append((BUF1, o_line.index, i0_idx, i1_idx, i2_idx, i3_idx, *a_ctrl[o_line]))
|
||||
continue
|
||||
# ALAP-toposort the circuit into self.ops
|
||||
levels = []
|
||||
|
||||
ppio2idx = dict((n, i) for i, n in enumerate(circuit.s_nodes))
|
||||
pis = set([n for n in circuit.s_nodes if len(n.ins) == 0])
|
||||
ppos = set([n for n in circuit.s_nodes if len(n.ins) > 0])
|
||||
readers = np.array([1 if l.reader in ppos else len(l.reader.outs) for l in circuit.lines], dtype=np.int32) # for ref-counting forks
|
||||
|
||||
level_lines = [n.ins[0] for n in ppos] # start from PPOs
|
||||
# FIXME: Should probably instanciate buffers for PPOs and attach DFF clocks
|
||||
|
||||
while len(level_lines) > 0: # traverse the circuit level-wise back towards (P)PIs
|
||||
level_ops = []
|
||||
prev_level_lines = []
|
||||
|
||||
for l in level_lines:
|
||||
n = l.driver
|
||||
in_idxs = [n.ins[x].index if len(n.ins) > x and n.ins[x] is not None else self.zero_idx for x in [0,1,2,3]]
|
||||
if n in ppio2idx:
|
||||
in_idxs[0] = self.ppi_offset + ppio2idx[n]
|
||||
if l.driver_pin == 1 and 'dff' in n.kind.lower(): # second output of DFF is inverted
|
||||
level_ops.append((INV1, l.index, *in_idxs, *a_ctrl[l]))
|
||||
else:
|
||||
level_ops.append((BUF1, l.index, *in_idxs, *a_ctrl[l]))
|
||||
elif n.kind == '__fork__':
|
||||
readers[n.ins[0]] -= 1
|
||||
if readers[n.ins[0]] == 0: prev_level_lines.append(n.ins[0])
|
||||
if not strip_forks: level_ops.append((BUF1, l.index, *in_idxs, *a_ctrl[l]))
|
||||
else:
|
||||
prev_level_lines += n.ins
|
||||
sp = None
|
||||
kind = n.kind.lower()
|
||||
for prefix, prims in kind_prefixes.items():
|
||||
if kind.startswith(prefix):
|
||||
sp = prims[0]
|
||||
if i3_idx == self.zero_idx:
|
||||
if in_idxs[3] == self.zero_idx:
|
||||
sp = prims[1]
|
||||
if i2_idx == self.zero_idx:
|
||||
if in_idxs[2] == self.zero_idx:
|
||||
sp = prims[2]
|
||||
break
|
||||
if sp is None:
|
||||
print('unknown cell type', kind)
|
||||
else:
|
||||
ops.append((sp, o0_idx, i0_idx, i1_idx, i2_idx, i3_idx, *a_ctrl[o0_idx]))
|
||||
level_ops.append((sp, l.index, *in_idxs, *a_ctrl[l]))
|
||||
|
||||
self.ops = np.asarray(ops, dtype='int32')
|
||||
if len(level_ops) > 0: levels.append(level_ops)
|
||||
level_lines = prev_level_lines
|
||||
|
||||
self.levels = [np.asarray(lv, dtype=np.int32) for lv in levels[::-1]]
|
||||
level_sums = np.cumsum([0]+[len(lv) for lv in self.levels], dtype=np.int32)
|
||||
self.level_starts, self.level_stops = level_sums[:-1], level_sums[1:]
|
||||
self.ops = np.vstack(self.levels)
|
||||
|
||||
# create a map from fanout lines to stem lines for fork stripping
|
||||
stems = np.zeros(self.c_locs_len, dtype='int32') - 1 # default to -1: 'no fanout line'
|
||||
stems = np.full(self.c_locs_len, -1, dtype=np.int32) # default to -1: 'no fanout line'
|
||||
if strip_forks:
|
||||
for f in circuit.forks.values():
|
||||
prev_line = f.ins[0]
|
||||
while prev_line.driver.kind == '__fork__':
|
||||
prev_line = prev_line.driver.ins[0]
|
||||
stem_idx = prev_line.index
|
||||
for ol in f.outs:
|
||||
if ol is not None:
|
||||
stems[ol] = stem_idx
|
||||
stems[ol] = prev_line.index
|
||||
|
||||
# calculate level (distance from PI/PPI) and reference count for each line
|
||||
levels = np.zeros(self.c_locs_len, dtype='int32')
|
||||
ref_count = np.zeros(self.c_locs_len, dtype='int32')
|
||||
level_starts = [0]
|
||||
current_level = 1
|
||||
for i, op in enumerate(self.ops):
|
||||
# if we fork-strip, always take the stems for determining fan-in level
|
||||
i0_idx = stems[op[2]] if stems[op[2]] >= 0 else op[2]
|
||||
i1_idx = stems[op[3]] if stems[op[3]] >= 0 else op[3]
|
||||
i2_idx = stems[op[4]] if stems[op[4]] >= 0 else op[4]
|
||||
i3_idx = stems[op[5]] if stems[op[5]] >= 0 else op[5]
|
||||
if levels[i0_idx] >= current_level or levels[i1_idx] >= current_level or levels[i2_idx] >= current_level or levels[i3_idx] >= current_level:
|
||||
current_level += 1
|
||||
level_starts.append(i)
|
||||
levels[op[1]] = current_level # set level of the output line
|
||||
ref_count[i0_idx] += 1
|
||||
ref_count[i1_idx] += 1
|
||||
ref_count[i2_idx] += 1
|
||||
ref_count[i3_idx] += 1
|
||||
self.level_starts = np.asarray(level_starts, dtype='int32')
|
||||
self.level_stops = np.asarray(level_starts[1:] + [len(self.ops)], dtype='int32')
|
||||
ref_count = np.zeros(self.c_locs_len, dtype=np.int32)
|
||||
|
||||
for op in self.ops:
|
||||
for x in [2, 3, 4, 5]:
|
||||
ref_count[stems[op[x]] if stems[op[x]] >= 0 else op[x]] += 1
|
||||
|
||||
# combinational signal allocation table. maps line and interface indices to self.c memory locations
|
||||
self.c_locs = np.full((self.c_locs_len,), -1, dtype=np.int32)
|
||||
@@ -278,9 +277,9 @@ class SimOps:
|
||||
ref_count[i0_idx] += 1
|
||||
|
||||
# allocate memory for the rest of the circuit
|
||||
for op_start, op_stop in zip(self.level_starts, self.level_stops):
|
||||
for ops in self.levels:
|
||||
free_set = set()
|
||||
for op in self.ops[op_start:op_stop]:
|
||||
for op in ops:
|
||||
# if we fork-strip, always take the stems
|
||||
i0_idx = stems[op[2]] if stems[op[2]] >= 0 else op[2]
|
||||
i1_idx = stems[op[3]] if stems[op[3]] >= 0 else op[3]
|
||||
@@ -299,6 +298,7 @@ class SimOps:
|
||||
self.c_locs[o_idx], self.c_caps[o_idx] = h.alloc(cap), cap
|
||||
if c_reuse:
|
||||
for loc in free_set:
|
||||
if loc >= 0: # DFF clocks are not allocated. Ignore for now.
|
||||
h.free(loc)
|
||||
|
||||
# copy memory location and capacity from stems to fanout lines
|
||||
|
||||
+15
-17
@@ -41,7 +41,7 @@ class StilFile:
|
||||
unload = {}
|
||||
for so_port in self.so_ports:
|
||||
if so_port in call.parameters:
|
||||
unload[so_port] = call.parameters[so_port].replace('\n', '').replace('N', '-')
|
||||
unload[so_port] = call.parameters[so_port]
|
||||
if len(capture) > 0:
|
||||
self.patterns.append(ScanPattern(sload, launch, capture, unload))
|
||||
capture = {}
|
||||
@@ -49,11 +49,9 @@ class StilFile:
|
||||
sload = {}
|
||||
for si_port in self.si_ports:
|
||||
if si_port in call.parameters:
|
||||
sload[si_port] = call.parameters[si_port].replace('\n', '').replace('N', '-')
|
||||
if call.name.endswith('_launch'):
|
||||
launch = dict((k, v.replace('\n', '').replace('N', '-')) for k, v in call.parameters.items())
|
||||
if call.name.endswith('_capture'):
|
||||
capture = dict((k, v.replace('\n', '').replace('N', '-')) for k, v in call.parameters.items())
|
||||
sload[si_port] = call.parameters[si_port]
|
||||
if call.name.endswith('_launch'): launch = call.parameters
|
||||
if call.name.endswith('_capture'): capture = call.parameters
|
||||
|
||||
def _maps(self, c):
|
||||
interface = list(c.io_nodes) + [n for n in c.nodes if 'DFF' in n.kind]
|
||||
@@ -100,12 +98,12 @@ class StilFile:
|
||||
tests = np.full((len(interface), len(self.patterns)), logic.UNASSIGNED)
|
||||
for i, p in enumerate(self.patterns):
|
||||
for si_port in self.si_ports.keys():
|
||||
pattern = logic.mvarray(p.load[si_port])
|
||||
pattern = logic.mvarray(p.load[si_port][0])
|
||||
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[pi_map, i] = logic.mvarray(p.capture['_pi'])
|
||||
tests[pi_map, i] = logic.mvarray(p.capture['_pi'][0])
|
||||
return tests
|
||||
|
||||
def tests_loc(self, circuit, init_filter=None, launch_filter=None):
|
||||
@@ -134,12 +132,12 @@ class StilFile:
|
||||
for i, p in enumerate(self.patterns):
|
||||
# init.set_values(i, '0' * len(interface))
|
||||
for si_port in self.si_ports.keys():
|
||||
pattern = logic.mvarray(p.load[si_port])
|
||||
pattern = logic.mvarray(p.load[si_port][0])
|
||||
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[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'][0] if '_pi' in p.launch else p.capture['_pi'][0])
|
||||
if init_filter: init = init_filter(init)
|
||||
sim8v = LogicSim(circuit, init.shape[-1], m=8)
|
||||
sim8v.s[0] = logic.mv_to_bp(init)
|
||||
@@ -149,12 +147,12 @@ class StilFile:
|
||||
launch = logic.bp_to_mv(sim8v.s[1])[..., :init.shape[-1]]
|
||||
for i, p in enumerate(self.patterns):
|
||||
# if there was no launch cycle or launch clock, then init = launch
|
||||
if '_pi' not in p.launch or 'P' not in p.launch['_pi'] or 'P' not in p.capture['_pi']:
|
||||
if '_pi' not in p.launch or 'P' not in p.launch['_pi'][0] or 'P' not in p.capture['_pi'][0]:
|
||||
for si_port in self.si_ports.keys():
|
||||
pattern = logic.mv_xor(logic.mvarray(p.load[si_port]), scan_inversions[si_port])
|
||||
pattern = logic.mv_xor(logic.mvarray(p.load[si_port][0]), scan_inversions[si_port])
|
||||
launch[scan_maps[si_port], i] = pattern
|
||||
if '_pi' in p.capture and 'P' in p.capture['_pi']:
|
||||
launch[pi_map, i] = logic.mvarray(p.capture['_pi'])
|
||||
if '_pi' in p.capture and 'P' in p.capture['_pi'][0]:
|
||||
launch[pi_map, i] = logic.mvarray(p.capture['_pi'][0])
|
||||
launch[po_map, i] = logic.UNASSIGNED
|
||||
if launch_filter: launch = launch_filter(launch)
|
||||
|
||||
@@ -171,9 +169,9 @@ class StilFile:
|
||||
interface, _, po_map, scan_maps, scan_inversions = self._maps(circuit)
|
||||
resp = np.full((len(interface), len(self.patterns)), logic.UNASSIGNED)
|
||||
for i, p in enumerate(self.patterns):
|
||||
resp[po_map, i] = logic.mvarray(p.capture['_po'] if len(p.capture) > 0 else p.launch['_po'])
|
||||
resp[po_map, i] = logic.mvarray(p.capture['_po'][0] if len(p.capture) > 0 else p.launch['_po'][0])
|
||||
for so_port in self.so_ports.keys():
|
||||
pattern = logic.mv_xor(logic.mvarray(p.unload[so_port]), scan_inversions[so_port])
|
||||
pattern = logic.mv_xor(logic.mvarray(p.unload[so_port][0]), scan_inversions[so_port])
|
||||
resp[scan_maps[so_port], i] = pattern
|
||||
return resp
|
||||
|
||||
@@ -192,7 +190,7 @@ class StilTransformer(Transformer):
|
||||
def call(args): return Call(args[0], dict(args[1:]))
|
||||
|
||||
@staticmethod
|
||||
def call_parameter(args): return args[0], args[1].value
|
||||
def call_parameter(args): return args[0], (args[1].value.replace('\n', '').replace('N', '-'), args[1].start_pos)
|
||||
|
||||
@staticmethod
|
||||
def signal_group(args): return args[0], args[1:]
|
||||
|
||||
+76
-42
@@ -138,21 +138,92 @@ TLATX1 input(C,D) output(Q,QN) Q=LATCH(D,C) QN=INV1(Q) ;
|
||||
"""
|
||||
|
||||
|
||||
_nangate_common = r"""
|
||||
NANGATE = TechLib(r"""
|
||||
FILLTIE ;
|
||||
FILL_X{1,2,4,8,16} ;
|
||||
ANTENNA input(I) ;
|
||||
|
||||
TIEH output(Z) Z=__const1__() ;
|
||||
TIEL output(ZN) ZN=__const0__() ;
|
||||
|
||||
BUF_X{1,2,4,8,12,16} input(I) output(Z) Z=BUF1(I) ;
|
||||
INV_X{1,2,4,8,12,16} input(I) output(ZN) ZN=INV1(I) ;
|
||||
|
||||
CLKBUF_X{1,2,4,8,12,16} input(I) output(Z) Z=BUF1(I) ;
|
||||
CLKGATETST_X1 input(CLK,E,TE) output(Q) Q=OA21(CLK,E,TE) ;
|
||||
|
||||
AND2_X{1,2} input(A1,A2) output(Z) Z=AND2(A1,A2) ;
|
||||
AND3_X{1,2} input(A1,A2,A3) output(Z) Z=AND3(A1,A2,A3) ;
|
||||
AND4_X{1,2} input(A1,A2,A3,A4) output(Z) Z=AND4(A1,A2,A3,A4) ;
|
||||
NAND2_X{1,2} input(A1,A2) output(ZN) ZN=NAND2(A1,A2) ;
|
||||
NAND3_X{1,2} input(A1,A2,A3) output(ZN) ZN=NAND3(A1,A2,A3) ;
|
||||
NAND4_X{1,2} input(A1,A2,A3,A4) output(ZN) ZN=NAND4(A1,A2,A3,A4) ;
|
||||
OR2_X{1,2} input(A1,A2) output(Z) Z=OR2(A1,A2) ;
|
||||
OR3_X{1,2} input(A1,A2,A3) output(Z) Z=OR3(A1,A2,A3) ;
|
||||
OR4_X{1,2} input(A1,A2,A3,A4) output(Z) Z=OR4(A1,A2,A3,A4) ;
|
||||
NOR2_X{1,2} input(A1,A2) output(ZN) ZN=NOR2(A1,A2) ;
|
||||
NOR3_X{1,2} input(A1,A2,A3) output(ZN) ZN=NOR3(A1,A2,A3) ;
|
||||
NOR4_X{1,2} input(A1,A2,A3,A4) output(ZN) ZN=NOR4(A1,A2,A3,A4) ;
|
||||
XOR2_X1 input(A1,A2) output(Z) Z=XOR2(A1,A2) ;
|
||||
XNOR2_X1 input(A1,A2) output(ZN) ZN=XNOR2(A1,A2) ;
|
||||
|
||||
MUX2_X1 input(I0,I1,S) output(Z) Z=MUX21(I0,I1,S) ;
|
||||
|
||||
HA_X1 input(A,B) output(CO,S) CO=XOR2(A,B) S=AND2(A,B) ;
|
||||
FA_X1 input(A,B,CI) output(CO,S) AB=XOR2(A,B) CO=XOR2(AB,CI) S=AO22(CI,A,B) ;
|
||||
|
||||
AOI21_X{1,2} input(A1,A2,B) output(ZN) ZN=AOI21(A1,A2,B) ;
|
||||
OAI21_X{1,2} input(A1,A2,B) output(ZN) ZN=OAI21(A1,A2,B) ;
|
||||
AOI22_X{1,2} input(A1,A2,B1,B2) output(ZN) ZN=AOI22(A1,A2,B1,B2) ;
|
||||
OAI22_X{1,2} input(A1,A2,B1,B2) output(ZN) ZN=OAI22(A1,A2,B1,B2) ;
|
||||
|
||||
DFFRNQ_X1 input(D,RN,CLK) output(Q) DR=AND2(D,RN) Q=DFF(DR,CLK) ;
|
||||
DFFSNQ_X1 input(D,SN,CLK) output(Q) S=INV1(SN) DS=OR2(D,S) Q=DFF(DS,CLK) ;
|
||||
|
||||
SDFFRNQ_X1 input(D,RN,SE,SI,CLK) output(Q) DR=AND2(D,RN) DI=MUX21(DR,SI,SE) Q=DFF(DI,CLK) ;
|
||||
SDFFSNQ_X1 input(D,SE,SI,SN,CLK) output(Q) S=INV1(SN) DS=OR2(D,S) DI=MUX21(DS,SI,SE) Q=DFF(DI,CLK) ;
|
||||
|
||||
TBUF_X{1,2,4,8,12,16} input(EN,I) output(Z) Z=BUF1(I) ;
|
||||
|
||||
LHQ_X1 input(D,E) output(Q) Q=LATCH(D,E) ;
|
||||
""")
|
||||
"""Nangate 15nm Open Cell Library (NanGate_15nm_OCL_v0.1_2014_06.A).
|
||||
"""
|
||||
|
||||
|
||||
NANGATE45 = TechLib(r"""
|
||||
FILLCELL_X{1,2,4,8,16,32} ;
|
||||
ANTENNA_X1 input(A) ;
|
||||
|
||||
LOGIC0_X1 output(Z) Z=__const0__() ;
|
||||
LOGIC1_X1 output(Z) Z=__const1__() ;
|
||||
|
||||
BUF_X{1,2,4,8,16,32} input(A) output(Z) Z=BUF1(A) ;
|
||||
CLKBUF_X{1,2,3} input(A) output(Z) Z=BUF1(A) ;
|
||||
INV_X{1,2,4,8,16,32} input(A) output(ZN) ZN=INV1(A) ;
|
||||
|
||||
CLKBUF_X{1,2,3} input(A) output(Z) Z=BUF1(A) ;
|
||||
CLKGATETST_X{1,2,4,8} input(CK,E,SE) output(GCK) GCK=OA21(CK,E,SE) ;
|
||||
CLKGATE_X{1,2,4,8} input(CK,E) output(GCK) GCK=AND2(CK,E) ;
|
||||
|
||||
AND2_X{1,2,4} input(A1,A2) output(ZN) ZN=AND2(A1,A2) ;
|
||||
AND3_X{1,2,4} input(A1,A2,A3) output(ZN) ZN=AND3(A1,A2,A3) ;
|
||||
AND4_X{1,2,4} input(A1,A2,A3,A4) output(ZN) ZN=AND4(A1,A2,A3,A4) ;
|
||||
NAND2_X{1,2,4} input(A1,A2) output(ZN) ZN=NAND2(A1,A2) ;
|
||||
NAND3_X{1,2,4} input(A1,A2,A3) output(ZN) ZN=NAND3(A1,A2,A3) ;
|
||||
NAND4_X{1,2,4} input(A1,A2,A3,A4) output(ZN) ZN=NAND4(A1,A2,A3,A4) ;
|
||||
OR2_X{1,2,4} input(A1,A2) output(ZN) ZN=OR2(A1,A2) ;
|
||||
OR3_X{1,2,4} input(A1,A2,A3) output(ZN) ZN=OR3(A1,A2,A3) ;
|
||||
OR4_X{1,2,4} input(A1,A2,A3,A4) output(ZN) ZN=OR4(A1,A2,A3,A4) ;
|
||||
NOR2_X{1,2,4} input(A1,A2) output(ZN) ZN=NOR2(A1,A2) ;
|
||||
NOR3_X{1,2,4} input(A1,A2,A3) output(ZN) ZN=NOR3(A1,A2,A3) ;
|
||||
NOR4_X{1,2,4} input(A1,A2,A3,A4) output(ZN) ZN=NOR4(A1,A2,A3,A4) ;
|
||||
XOR2_X{1,2} input(A,B) output(Z) Z=XOR2(A,B) ;
|
||||
XNOR2_X{1,2} input(A,B) output(ZN) ZN=XNOR2(A,B) ;
|
||||
|
||||
MUX2_X{1,2} input(A,B,S) output(Z) Z=MUX21(A,B,S) ;
|
||||
|
||||
HA_X1 input(A,B) output(CO,S) CO=XOR2(A,B) S=AND2(A,B) ;
|
||||
FA_X1 input(A,B,CI) output(CO,S) AB=XOR2(A,B) CO=XOR2(AB,CI) S=AO22(CI,A,B) ;
|
||||
|
||||
AOI21_X{1,2,4} input(A,B1,B2) output(ZN) ZN=AOI21(B1,B2,A) ;
|
||||
OAI21_X{1,2,4} input(A,B1,B2) output(ZN) ZN=OAI21(B1,B2,A) ;
|
||||
@@ -162,8 +233,6 @@ OAI22_X{1,2,4} input(A1,A2,B1,B2) output(ZN) ZN=OAI22(A1,A2,B1,B2) ;
|
||||
OAI211_X{1,2,4} input(A,B,C1,C2) output(ZN) ZN=OAI211(C1,C2,A,B) ;
|
||||
AOI211_X{1,2,4} input(A,B,C1,C2) output(ZN) ZN=AOI211(C1,C2,A,B) ;
|
||||
|
||||
MUX2_X{1,2} input(A,B,S) output(Z) Z=MUX21(A,B,S) ;
|
||||
|
||||
AOI221_X{1,2,4} input(A,B1,B2,C1,C2) output(ZN) BC=AO22(B1,B2,C1,C2) ZN=NOR2(BC,A) ;
|
||||
OAI221_X{1,2,4} input(A,B1,B2,C1,C2) output(ZN) BC=OA22(B1,B2,C1,C2) ZN=NAND2(BC,A) ;
|
||||
|
||||
@@ -172,14 +241,6 @@ OAI222_X{1,2,4} input(A1,A2,B1,B2,C1,C2) output(ZN) BC=OA22(B1,B2,C1,C2) ZN=OAI2
|
||||
|
||||
OAI33_X1 input(A1,A2,A3,B1,B2,B3) output(ZN) AA=OR2(A1,A2) BB=OR2(B1,B2) ZN=OAI22(AA,A3,BB,B3) ;
|
||||
|
||||
HA_X1 input(A,B) output(CO,S) CO=XOR2(A,B) S=AND2(A,B) ;
|
||||
|
||||
FA_X1 input(A,B,CI) output(CO,S) AB=XOR2(A,B) CO=XOR2(AB,CI) S=AO22(CI,A,B) ;
|
||||
|
||||
CLKGATE_X{1,2,4,8} input(CK,E) output(GCK) GCK=AND2(CK,E) ;
|
||||
|
||||
CLKGATETST_X{1,2,4,8} input(CK,E,SE) output(GCK) GCK=OA21(CK,E,SE) ;
|
||||
|
||||
DFF_X{1,2} input(D,CK) output(Q,QN) Q=DFF(D,CK) QN=INV1(Q) ;
|
||||
DFFR_X{1,2} input(D,RN,CK) output(Q,QN) DR=AND2(D,RN) Q=DFF(DR,CK) QN=INV1(Q) ;
|
||||
DFFS_X{1,2} input(D,SN,CK) output(Q,QN) S=INV1(SN) DS=OR2(D,S) Q=DFF(DS,CK) QN=INV1(Q) ;
|
||||
@@ -191,43 +252,16 @@ SDFFS_X{1,2} input(D,SE,SI,SN,CK) output(Q,QN) S=INV1(SN) DS=OR2(D,S) DI=MU
|
||||
SDFFRS_X{1,2} input(D,RN,SE,SI,SN,CK) output(Q,QN) S=INV1(SN) DS=OR2(D,S) DRS=AND2(DS,RN) DI=MUX21(DRS,SI,SE) Q=DFF(DI,CK) QN=INV1(Q) ;
|
||||
|
||||
TBUF_X{1,2,4,8,16} input(A,EN) output(Z) Z=BUF1(A) ;
|
||||
|
||||
TINV_X1 input(I,EN) output(ZN) ZN=INV1(I) ;
|
||||
TLAT_X1 input(D,G,OE) output(Q) Q=LATCH(D,G) ;
|
||||
|
||||
DLH_X{1,2} input(D,G) output(Q) Q=LATCH(D,G) ;
|
||||
DLL_X{1,2} input(D,GN) output(Q) G=INV1(GN) Q=LATCH(D,G) ;
|
||||
"""
|
||||
|
||||
|
||||
NANGATE = TechLib(_nangate_common + r"""
|
||||
INV_X{1,2,4,8,16,32} input(I) output(ZN) ZN=INV1(I) ;
|
||||
|
||||
AND2_X{1,2,4} input(A1,A2) output(Z) Z=AND2(A1,A2) ;
|
||||
AND3_X{1,2,4} input(A1,A2,A3) output(Z) Z=AND3(A1,A2,A3) ;
|
||||
AND4_X{1,2,4} input(A1,A2,A3,A4) output(Z) Z=AND4(A1,A2,A3,A4) ;
|
||||
OR2_X{1,2,4} input(A1,A2) output(Z) Z=OR2(A1,A2) ;
|
||||
OR3_X{1,2,4} input(A1,A2,A3) output(Z) Z=OR3(A1,A2,A3) ;
|
||||
OR4_X{1,2,4} input(A1,A2,A3,A4) output(Z) Z=OR4(A1,A2,A3,A4) ;
|
||||
XOR2_X{1,2} input(A1,A2) output(Z) Z=XOR2(A1,A2) ;
|
||||
XNOR2_X{1,2} input(A1,A2) output(ZN) ZN=XNOR2(A1,A2) ;
|
||||
""")
|
||||
"""An newer NANGATE-variant that uses 'Z' as output pin names for AND and OR gates.
|
||||
"""
|
||||
|
||||
|
||||
NANGATE_ZN = TechLib(_nangate_common + r"""
|
||||
INV_X{1,2,4,8,16,32} input(A) output(ZN) ZN=INV1(A) ;
|
||||
|
||||
AND2_X{1,2,4} input(A1,A2) output(ZN) ZN=AND2(A1,A2) ;
|
||||
AND3_X{1,2,4} input(A1,A2,A3) output(ZN) ZN=AND3(A1,A2,A3) ;
|
||||
AND4_X{1,2,4} input(A1,A2,A3,A4) output(ZN) ZN=AND4(A1,A2,A3,A4) ;
|
||||
OR2_X{1,2,4} input(A1,A2) output(ZN) ZN=OR2(A1,A2) ;
|
||||
OR3_X{1,2,4} input(A1,A2,A3) output(ZN) ZN=OR3(A1,A2,A3) ;
|
||||
OR4_X{1,2,4} input(A1,A2,A3,A4) output(ZN) ZN=OR4(A1,A2,A3,A4) ;
|
||||
XOR2_X{1,2} input(A,B) output(Z) Z=XOR2(A,B) ;
|
||||
XNOR2_X{1,2} input(A,B) output(ZN) ZN=XNOR2(A,B) ;
|
||||
""")
|
||||
"""An older NANGATE-variant that uses 'ZN' as output pin names for AND and OR gates.
|
||||
"""Nangate 45nm Open Cell Library (NangateOpenCellLibrary_PDKv1_3_v2010_12).
|
||||
This NANGATE-variant that uses 'ZN' as output pin names for AND and OR gates.
|
||||
"""
|
||||
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ import math
|
||||
|
||||
import numpy as np
|
||||
|
||||
from . import numba, cuda, sim, cdiv
|
||||
from . import numba, cuda, sim, cdiv, eng
|
||||
|
||||
|
||||
TMAX = np.float32(2 ** 127)
|
||||
@@ -103,7 +103,7 @@ class WaveSim(sim.SimOps):
|
||||
def __repr__(self):
|
||||
dev = 'GPU' if hasattr(self.c, 'copy_to_host') else 'CPU'
|
||||
return f'{{name: "{self.circuit.name}", device: "{dev}", sims: {self.sims}, ops: {len(self.ops)}, ' + \
|
||||
f'levels: {len(self.level_starts)}, nbytes: {self.nbytes}}}'
|
||||
f'levels: {len(self.level_starts)}, nbytes: {eng(self.nbytes)}}}'
|
||||
|
||||
def s_to_c(self):
|
||||
"""Transfers values of sequential elements and primary inputs to the combinational portion.
|
||||
@@ -206,25 +206,25 @@ def _wave_eval(op, cbuf, c_locs, c_caps, sim, delays, simctl_int, seed=0):
|
||||
if a == current_t:
|
||||
a_cur += 1
|
||||
inputs ^= 1
|
||||
thresh = delays[a_idx, a_cur & 1, z_val]
|
||||
thresh = delays[a_idx, a_cur & 1 ^ 1, z_val]
|
||||
a = cbuf[a_mem + a_cur, sim] + delays[a_idx, a_cur & 1, z_val]
|
||||
next_t = cbuf[a_mem + a_cur, sim] + delays[a_idx, (a_cur & 1) ^ 1, z_val ^ 1]
|
||||
elif b == current_t:
|
||||
b_cur += 1
|
||||
inputs ^= 2
|
||||
thresh = delays[b_idx, b_cur & 1, z_val]
|
||||
thresh = delays[b_idx, b_cur & 1 ^ 1, z_val]
|
||||
b = cbuf[b_mem + b_cur, sim] + delays[b_idx, b_cur & 1, z_val]
|
||||
next_t = cbuf[b_mem + b_cur, sim] + delays[b_idx, (b_cur & 1) ^ 1, z_val ^ 1]
|
||||
elif c == current_t:
|
||||
c_cur += 1
|
||||
inputs ^= 4
|
||||
thresh = delays[c_idx, c_cur & 1, z_val]
|
||||
thresh = delays[c_idx, c_cur & 1 ^ 1, z_val]
|
||||
c = cbuf[c_mem + c_cur, sim] + delays[c_idx, c_cur & 1, z_val]
|
||||
next_t = cbuf[c_mem + c_cur, sim] + delays[c_idx, (c_cur & 1) ^ 1, z_val ^ 1]
|
||||
else:
|
||||
d_cur += 1
|
||||
inputs ^= 8
|
||||
thresh = delays[d_idx, d_cur & 1, z_val]
|
||||
thresh = delays[d_idx, d_cur & 1 ^ 1, z_val]
|
||||
d = cbuf[d_mem + d_cur, sim] + delays[d_idx, d_cur & 1, z_val]
|
||||
next_t = cbuf[d_mem + d_cur, sim] + delays[d_idx, (d_cur & 1) ^ 1, z_val ^ 1]
|
||||
|
||||
@@ -377,9 +377,11 @@ class WaveSimCuda(WaveSim):
|
||||
|
||||
def _grid_dim(self, x, y): return cdiv(x, self._block_dim[0]), cdiv(y, self._block_dim[1])
|
||||
|
||||
def c_prop(self, sims=None, seed=1):
|
||||
def c_prop(self, sims=None, seed=1, op_from=0, op_to=None):
|
||||
sims = min(sims or self.sims, self.sims)
|
||||
for op_start, op_stop in zip(self.level_starts, self.level_stops):
|
||||
if op_from > op_start: continue
|
||||
if op_to is not None and op_to <= op_start: break
|
||||
grid_dim = self._grid_dim(sims, op_stop - op_start)
|
||||
wave_eval_gpu[grid_dim, self._block_dim](self.ops, op_start, op_stop, self.c, self.c_locs, self.c_caps, self.abuf, int(0),
|
||||
sims, self.delays, self.simctl_int, seed)
|
||||
|
||||
Binary file not shown.
@@ -13,6 +13,13 @@ def b15_2ig_circuit(mydir):
|
||||
from kyupy.techlib import SAED32
|
||||
return verilog.load(mydir / 'b15_2ig.v.gz', branchforks=True, tlib=SAED32)
|
||||
|
||||
@pytest.fixture(scope='session')
|
||||
def b15_2ig_circuit_resolved(b15_2ig_circuit):
|
||||
from kyupy.techlib import SAED32
|
||||
cr = b15_2ig_circuit.copy()
|
||||
cr.resolve_tlib_cells(SAED32)
|
||||
return cr
|
||||
|
||||
@pytest.fixture(scope='session')
|
||||
def b15_2ig_delays(mydir, b15_2ig_circuit):
|
||||
from kyupy import sdf
|
||||
|
||||
+33
-6
@@ -7,22 +7,49 @@
|
||||
(TEMPERATURE 25.00:25.00:25.00)
|
||||
(TIMESCALE 1ns)
|
||||
(CELL
|
||||
(CELLTYPE "NAND2X1")
|
||||
(CELLTYPE "NAND2_X1")
|
||||
(INSTANCE nandgate)
|
||||
(DELAY
|
||||
(ABSOLUTE
|
||||
(IOPATH IN1 QN (0.099:0.103:0.103) (0.122:0.127:0.127))
|
||||
(IOPATH IN2 QN (0.083:0.086:0.086) (0.100:0.104:0.104))
|
||||
(IOPATH A1 ZN (0.099:0.103:0.103) (0.122:0.127:0.127))
|
||||
(IOPATH A2 ZN (0.083:0.086:0.086) (0.100:0.104:0.104))
|
||||
)
|
||||
)
|
||||
)
|
||||
(CELL
|
||||
(CELLTYPE "AND2X1")
|
||||
(CELLTYPE "AND2_X1")
|
||||
(INSTANCE andgate)
|
||||
(DELAY
|
||||
(ABSOLUTE
|
||||
(IOPATH IN1 Q (0.367:0.378:0.378) (0.351:0.377:0.377))
|
||||
(IOPATH IN2 Q (0.366:0.375:0.375) (0.359:0.370:0.370))
|
||||
(IOPATH A1 ZN (0.367:0.378:0.378) (0.351:0.377:0.377))
|
||||
(IOPATH A2 ZN (0.366:0.375:0.375) (0.359:0.370:0.370))
|
||||
)
|
||||
)
|
||||
)
|
||||
(CELL
|
||||
(CELLTYPE "OAI21_X1")
|
||||
(INSTANCE oai21gate)
|
||||
(DELAY
|
||||
(ABSOLUTE
|
||||
(IOPATH B1 ZN (0.000:0.025:0.025) (0.000:0.013:0.013))
|
||||
(IOPATH B2 ZN (0.000:0.030:0.030) (0.000:0.016:0.016))
|
||||
( COND (B1 == 1'b0) && (B2 == 1'b1) (IOPATH A ZN (0.000:0.018:0.018)))
|
||||
(COND (B1 == 1'b1) && (B2 == 1'b0) (IOPATH A ZN (0.000:0.018:0.018) (0.000:0.016:0.016)))
|
||||
(COND (B1 == 1'b1) && (B2 == 1'b1) (IOPATH A ZN (0.000:0.019:0.019) (0.000:0.014:0.014)))
|
||||
)
|
||||
)
|
||||
)
|
||||
(CELL
|
||||
(CELLTYPE "MUX2_X1")
|
||||
(INSTANCE mux2gate)
|
||||
(DELAY
|
||||
(ABSOLUTE
|
||||
(COND (B == 1'b0) && (S == 1'b0) (IOPATH A Z (0.000:0.037:0.037) (0.000:0.058:0.058)))
|
||||
(COND (B == 1'b1) && (S == 1'b0) (IOPATH A Z (0.000:0.037:0.037) (0.000:0.058:0.058)))
|
||||
(COND (A == 1'b0) && (S == 1'b1) (IOPATH B Z (0.000:0.035:0.035) (0.000:0.056:0.056)))
|
||||
(COND (A == 1'b1) && (S == 1'b1) (IOPATH B Z (0.000:0.035:0.035) (0.000:0.056:0.056)))
|
||||
(COND (A == 1'b0) && (B == 1'b1) (IOPATH S Z (0.000:0.047:0.047) (0.000:0.073:0.073)))
|
||||
(COND (A == 1'b1) && (B == 1'b0) (IOPATH S Z (0.000:0.072:0.072) (0.000:0.064:0.064)))
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
+8
-4
@@ -1,11 +1,15 @@
|
||||
module gates (a, b, o0, o1 );
|
||||
module gates (a, b, c, o0, o1, o2, o3 );
|
||||
input a;
|
||||
input b;
|
||||
input c;
|
||||
output o0;
|
||||
output o1;
|
||||
output o2;
|
||||
output o3;
|
||||
|
||||
AND2X1 andgate (.IN1 ( a ) , .IN2 ( b ) , .Q ( o0 ) ) ;
|
||||
NAND2X1 nandgate (.IN1 ( a ) , .IN2 ( b ) , .QN ( o1 ) ) ;
|
||||
|
||||
AND2_X1 andgate (.A1 ( a ) , .A2 ( b ) , .ZN ( o0 ) ) ;
|
||||
NAND2_X1 nandgate (.A1 ( a ) , .A2 ( b ) , .ZN ( o1 ) ) ;
|
||||
OAI21_X1 oai21gate (.B1(a), .B2(b), .A(c), .ZN(o2) ) ;
|
||||
MUX2_X1 mux2gate (.A(a), .B(b), .S(c), .Z(o3)) ;
|
||||
|
||||
endmodule
|
||||
+22
-1
@@ -1,9 +1,30 @@
|
||||
import pickle
|
||||
|
||||
from kyupy.circuit import Circuit, Node, Line
|
||||
from kyupy.circuit import GrowingList, Circuit, Node, Line
|
||||
from kyupy import verilog, bench
|
||||
from kyupy.techlib import SAED32
|
||||
|
||||
def test_growing_list():
|
||||
gl = GrowingList()
|
||||
assert gl.free_idx == 0
|
||||
gl[0] = 1
|
||||
assert gl.free_idx == 1
|
||||
gl[2] = 1
|
||||
assert gl.free_idx == 1
|
||||
gl[0] = None
|
||||
assert gl.free_idx == 0
|
||||
gl[0] = 1
|
||||
assert gl.free_idx == 1
|
||||
gl[1] = 1
|
||||
assert gl.free_idx == 3
|
||||
gl.append(1)
|
||||
assert gl.free_idx == 4
|
||||
gl[2] = None
|
||||
assert gl.free_idx == 2
|
||||
gl[2] = 1
|
||||
gl[1] = None
|
||||
assert gl.free_idx == 1
|
||||
|
||||
def test_lines():
|
||||
c = Circuit()
|
||||
n1 = Node(c, 'n1')
|
||||
|
||||
@@ -173,3 +173,50 @@ def test_b01(mydir):
|
||||
s.c_prop()
|
||||
s.c_to_s()
|
||||
bp_to_mv(s.s[1])
|
||||
|
||||
|
||||
def sim_and_compare(v_file, stil_file, m=8):
|
||||
from kyupy import verilog, stil
|
||||
from kyupy.techlib import SAED32
|
||||
c = verilog.load(v_file, branchforks=True, tlib=SAED32)
|
||||
c.resolve_tlib_cells(SAED32)
|
||||
s = stil.load(stil_file)
|
||||
tests = s.tests(c)[:,1:]
|
||||
resp = s.responses(c)[:,1:]
|
||||
lsim = LogicSim(c, m=m, sims=tests.shape[1])
|
||||
lsim.s[0] = logic.mv_to_bp(tests)
|
||||
lsim.s_to_c()
|
||||
lsim.c_prop()
|
||||
lsim.c_to_s()
|
||||
resp_sim = logic.bp_to_mv(lsim.s[1])[:,:tests.shape[1]]
|
||||
idxs, pats = np.nonzero(((resp == logic.ONE) & (resp_sim != logic.ONE)) | ((resp == logic.ZERO) & (resp_sim != logic.ZERO)))
|
||||
for i, (idx, pat) in enumerate(zip(idxs, pats)):
|
||||
if i >= 10:
|
||||
print(f'...')
|
||||
break
|
||||
print(f'mismatch pattern:{pat} ppio:{idx} exp:{logic.mv_str(resp[idx,pat])} act:{logic.mv_str(resp_sim[idx,pat])}')
|
||||
assert len(idxs) == 0
|
||||
|
||||
|
||||
def test_b15_2ig_sa_2v(mydir):
|
||||
sim_and_compare(mydir / 'b15_2ig.v.gz', mydir / 'b15_2ig.sa_nf.stil.gz', m=2)
|
||||
|
||||
|
||||
def test_b15_2ig_sa_4v(mydir):
|
||||
sim_and_compare(mydir / 'b15_2ig.v.gz', mydir / 'b15_2ig.sa_nf.stil.gz', m=4)
|
||||
|
||||
|
||||
def test_b15_2ig_sa_8v(mydir):
|
||||
sim_and_compare(mydir / 'b15_2ig.v.gz', mydir / 'b15_2ig.sa_nf.stil.gz', m=8)
|
||||
|
||||
|
||||
def test_b15_4ig_sa_2v(mydir):
|
||||
sim_and_compare(mydir / 'b15_4ig.v.gz', mydir / 'b15_4ig.sa_rf.stil.gz', m=2)
|
||||
|
||||
|
||||
def test_b15_4ig_sa_4v(mydir):
|
||||
sim_and_compare(mydir / 'b15_4ig.v.gz', mydir / 'b15_4ig.sa_rf.stil.gz', m=4)
|
||||
|
||||
|
||||
def test_b15_4ig_sa_8v(mydir):
|
||||
sim_and_compare(mydir / 'b15_4ig.v.gz', mydir / 'b15_4ig.sa_rf.stil.gz', m=8)
|
||||
+3
-3
@@ -2,7 +2,7 @@ import numpy as np
|
||||
|
||||
from kyupy import sdf, verilog, bench
|
||||
from kyupy.wave_sim import WaveSim, TMAX, TMIN
|
||||
from kyupy.techlib import SAED32, SAED90
|
||||
from kyupy.techlib import SAED32, NANGATE45
|
||||
|
||||
def test_parse():
|
||||
test = '''
|
||||
@@ -80,9 +80,9 @@ def test_b15(mydir):
|
||||
|
||||
|
||||
def test_gates(mydir):
|
||||
c = verilog.load(mydir / 'gates.v', tlib=SAED90)
|
||||
c = verilog.load(mydir / 'gates.v', tlib=NANGATE45)
|
||||
df = sdf.load(mydir / 'gates.sdf')
|
||||
lt = df.iopaths(c, tlib=SAED90)[1]
|
||||
lt = df.iopaths(c, tlib=NANGATE45)[1]
|
||||
nand_a = c.cells['nandgate'].ins[0]
|
||||
nand_b = c.cells['nandgate'].ins[1]
|
||||
and_a = c.cells['andgate'].ins[0]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
from kyupy import verilog
|
||||
from kyupy.techlib import SAED90, SAED32
|
||||
from kyupy.techlib import SAED90, SAED32, NANGATE45
|
||||
|
||||
def test_b01(mydir):
|
||||
with open(mydir / 'b01.v', 'r') as f:
|
||||
@@ -26,12 +26,12 @@ def test_b15(mydir):
|
||||
|
||||
|
||||
def test_gates(mydir):
|
||||
c = verilog.load(mydir / 'gates.v', tlib=SAED90)
|
||||
assert len(c.nodes) == 10
|
||||
assert len(c.lines) == 10
|
||||
c = verilog.load(mydir / 'gates.v', tlib=NANGATE45)
|
||||
assert len(c.nodes) == 18
|
||||
assert len(c.lines) == 21
|
||||
stats = c.stats
|
||||
assert stats['input'] == 2
|
||||
assert stats['output'] == 2
|
||||
assert stats['input'] == 3
|
||||
assert stats['output'] == 4
|
||||
assert stats['__seq__'] == 0
|
||||
|
||||
|
||||
|
||||
+39
-7
@@ -5,6 +5,38 @@ from kyupy.logic_sim import LogicSim
|
||||
from kyupy import logic, bench, sim
|
||||
from kyupy.logic import mvarray
|
||||
|
||||
def test_xnor2_delays():
|
||||
op = (sim.XNOR2, 2, 0, 1, 3, 3, -1, 0, 0)
|
||||
#op = (0b0111, 4, 0, 1)
|
||||
c = np.full((4*16, 1), TMAX) # 4 waveforms of capacity 16
|
||||
c_locs = np.zeros((4,), dtype='int')
|
||||
c_caps = np.zeros((4,), dtype='int')
|
||||
|
||||
for i in range(4): c_locs[i], c_caps[i] = i*16, 16 # 1:1 mapping
|
||||
delays = np.zeros((1, 4, 2, 2))
|
||||
delays[0, 0, 0, 0] = 0.031 # A rise -> Z rise
|
||||
delays[0, 0, 0, 1] = 0.027 # A rise -> Z fall
|
||||
delays[0, 0, 1, 0] = 0.033 # A fall -> Z rise
|
||||
delays[0, 0, 1, 1] = 0.037 # A fall -> Z fall
|
||||
delays[0, 1, 0, 0] = 0.032 # B rise -> Z rise
|
||||
delays[0, 1, 0, 1] = 0.030 # B rise -> Z fall
|
||||
delays[0, 1, 1, 0] = 0.038 # B fall -> Z rise
|
||||
delays[0, 1, 1, 1] = 0.036 # B fall -> Z fall
|
||||
|
||||
simctl_int = np.asarray([0], dtype=np.int32)
|
||||
|
||||
def wave_assert(inputs, output):
|
||||
for i, a in zip(inputs, c.reshape(-1,16)): a[:len(i)] = i
|
||||
wave_eval_cpu(op, c, c_locs, c_caps, 0, delays, simctl_int)
|
||||
for i, v in enumerate(output): np.testing.assert_allclose(c.reshape(-1,16)[2,i], v)
|
||||
|
||||
wave_assert([[TMIN,TMAX],[TMIN,TMAX]], [TMIN,TMAX]) # XNOR(1,1) => 1
|
||||
wave_assert([[TMAX,TMAX],[TMIN,TMAX]], [TMAX]) # XNOR(0,1) => 0
|
||||
# using Afall/Zfall for pulse length, bug: was using Arise/Zfall
|
||||
#wave_assert([[0.07, 0.10, TMAX], [0.0, TMAX]], [TMIN, 0.03, 0.101, 0.137, TMAX])
|
||||
wave_assert([[0.07, 0.10, TMAX], [0.0, TMAX]], [TMIN, 0.03, TMAX])
|
||||
wave_assert([[0.06, 0.10, TMAX], [0.0, TMAX]], [TMIN, 0.03, 0.091, 0.137, TMAX])
|
||||
|
||||
def test_nand_delays():
|
||||
op = (sim.NAND4, 4, 0, 1, 2, 3, -1, 0, 0)
|
||||
#op = (0b0111, 4, 0, 1)
|
||||
@@ -145,7 +177,7 @@ def compare_to_logic_sim(wsim: WaveSim):
|
||||
lsim.s_to_c()
|
||||
lsim.c_prop()
|
||||
lsim.c_to_s()
|
||||
exp = logic.bp_to_mv(lsim.s[1])
|
||||
exp = logic.bp_to_mv(lsim.s[1])[:,:tests.shape[-1]]
|
||||
|
||||
resp[resp == logic.PPULSE] = logic.ZERO
|
||||
resp[resp == logic.NPULSE] = logic.ONE
|
||||
@@ -156,13 +188,13 @@ def compare_to_logic_sim(wsim: WaveSim):
|
||||
np.testing.assert_allclose(resp, exp)
|
||||
|
||||
|
||||
def test_b15(b15_2ig_circuit, b15_2ig_delays):
|
||||
compare_to_logic_sim(WaveSim(b15_2ig_circuit, b15_2ig_delays, 8))
|
||||
def test_b15(b15_2ig_circuit_resolved, b15_2ig_delays):
|
||||
compare_to_logic_sim(WaveSim(b15_2ig_circuit_resolved, b15_2ig_delays, 8))
|
||||
|
||||
|
||||
def test_b15_strip_forks(b15_2ig_circuit, b15_2ig_delays):
|
||||
compare_to_logic_sim(WaveSim(b15_2ig_circuit, b15_2ig_delays, 8, strip_forks=True))
|
||||
def test_b15_strip_forks(b15_2ig_circuit_resolved, b15_2ig_delays):
|
||||
compare_to_logic_sim(WaveSim(b15_2ig_circuit_resolved, b15_2ig_delays, 8, strip_forks=True))
|
||||
|
||||
|
||||
def test_b15_cuda(b15_2ig_circuit, b15_2ig_delays):
|
||||
compare_to_logic_sim(WaveSimCuda(b15_2ig_circuit, b15_2ig_delays, 8, strip_forks=True))
|
||||
def test_b15_cuda(b15_2ig_circuit_resolved, b15_2ig_delays):
|
||||
compare_to_logic_sim(WaveSimCuda(b15_2ig_circuit_resolved, b15_2ig_delays, 8, strip_forks=True))
|
||||
Reference in new issue
Block a user