Compare commits
206
Commits
v0.0.6
..
d3d06722c1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d3d06722c1 | ||
|
|
1f984c9bd9 | ||
|
|
0c8a2b7746 | ||
|
|
f66953f2d3 | ||
|
|
7203145a1d | ||
|
|
32e0766d41 | ||
|
|
9570161744 | ||
|
|
a594e2fb9a | ||
|
|
1bc9dc0e9d | ||
|
|
c5bdeb4a68 | ||
|
|
67db64611b | ||
|
|
7a9ed1e536 | ||
|
|
fcd9b78c24 | ||
|
|
f975765bbb | ||
|
|
3cb1b2bc86 | ||
|
|
c4aecbd6c9 | ||
|
|
25ff1fb2dc | ||
|
|
f0b55eed27 | ||
|
|
3700ae9b33 | ||
|
|
df695e0aa1 | ||
|
|
a28128830d | ||
|
|
20cf441abb | ||
|
|
5ac21edbb1 | ||
|
|
f0d74777af | ||
|
|
3848665533 | ||
|
|
541cccd756 | ||
|
|
fed66f85cb | ||
|
|
2eb10f83b0 | ||
|
|
dd4e5c861a | ||
|
|
9cebbcce8f | ||
|
|
31434cfd51 | ||
|
|
ce94210b52 | ||
|
|
09420fd72c | ||
|
|
5bcc1c1d77 | ||
|
|
df8a58f57b | ||
|
|
3dfd0cb60d | ||
|
|
21439e3595 | ||
|
|
88a5c79161 | ||
|
|
9ca437fe47 | ||
|
|
0cdaf71963 | ||
|
|
75972d7bb2 | ||
|
|
469dc18aa9 | ||
|
|
33addab141 | ||
|
|
674f3dea4a | ||
|
|
187d176cfd | ||
|
|
ba1de0bea9 | ||
|
|
5769aa3716 | ||
|
|
e97c370d39 | ||
|
|
3b7106be80 | ||
|
|
d2357859f6 | ||
|
|
53629c5c28 | ||
|
|
e64845e8c0 | ||
|
|
da98ca2db7 | ||
|
|
deb4599206 | ||
|
|
c1c9ec9aae | ||
|
|
4c55dcec60 | ||
|
|
a4b7364478 | ||
|
|
f59e97afa9 | ||
|
|
f6baf9cb5e | ||
|
|
fc030c6708 | ||
|
|
795cac0716 | ||
|
|
3a8777e0a3 | ||
|
|
68e8cb844a | ||
|
|
1a3b91c1c0 | ||
|
|
aa7536b8b0 | ||
|
|
fccf5e0d84 | ||
|
|
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
+2
-2
@@ -20,11 +20,11 @@ sys.path.insert(0, os.path.abspath('../src'))
|
|||||||
# -- Project information -----------------------------------------------------
|
# -- Project information -----------------------------------------------------
|
||||||
|
|
||||||
project = 'KyuPy'
|
project = 'KyuPy'
|
||||||
copyright = '2020-2025, Stefan Holst'
|
copyright = '2020-2026, Stefan Holst'
|
||||||
author = 'Stefan Holst'
|
author = 'Stefan Holst'
|
||||||
|
|
||||||
# The full version, including alpha/beta/rc tags
|
# The full version, including alpha/beta/rc tags
|
||||||
release = '0.0.6'
|
release = '0.0.7'
|
||||||
|
|
||||||
|
|
||||||
# -- General configuration ---------------------------------------------------
|
# -- General configuration ---------------------------------------------------
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
[project]
|
[project]
|
||||||
name = "kyupy"
|
name = "kyupy"
|
||||||
version = "0.0.6"
|
version = "0.0.7"
|
||||||
authors = [
|
authors = [
|
||||||
{ name="Stefan Holst", email="mail@s-holst.de" },
|
{ name="Stefan Holst", email="mail@s-holst.de" },
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -5,6 +5,10 @@ Historically it was first used in the
|
|||||||
`ISCAS89 benchmark set <https://people.engr.ncsu.edu/brglez/CBL/benchmarks/ISCAS89/>`_.
|
`ISCAS89 benchmark set <https://people.engr.ncsu.edu/brglez/CBL/benchmarks/ISCAS89/>`_.
|
||||||
Besides loading these benchmarks, this module is also useful for easily constructing simple circuits:
|
Besides loading these benchmarks, this module is also useful for easily constructing simple circuits:
|
||||||
``c = bench.parse('input(x, y) output(a, o, n) a=and(x,y) o=or(x,y) n=not(x)')``.
|
``c = bench.parse('input(x, y) output(a, o, n) a=and(x,y) o=or(x,y) n=not(x)')``.
|
||||||
|
|
||||||
|
This parser automatically translates gate to simulation primitives supported by kyupy.
|
||||||
|
In most cases this means just adding the number of inputs to the name: e.g. NAND -> NAND2, OR -> OR4, INV -> INV1.
|
||||||
|
Since simulators only support at most four-input-gates, gates with more than four inputs are implemented as tree.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from lark import Lark, Transformer
|
from lark import Lark, Transformer
|
||||||
|
|||||||
+16
-12
@@ -448,7 +448,7 @@ class Circuit:
|
|||||||
node_map[n] = Node(self, f'{node.name}~{n.name}', n.kind)
|
node_map[n] = Node(self, f'{node.name}~{n.name}', n.kind)
|
||||||
elif len(n.outs) > 0 and len(n.ins) > 0: # output is also read by impl. circuit, need to add a fork.
|
elif len(n.outs) > 0 and len(n.ins) > 0: # output is also read by impl. circuit, need to add a fork.
|
||||||
node_map[n] = Node(self, f'{node.name}~{n.name}')
|
node_map[n] = Node(self, f'{node.name}~{n.name}')
|
||||||
elif len(n.ins) == 0 and len(n.outs) > 1: # input is read by multiple nodes, need to add fork.
|
elif len(n.ins) == 0 and len(n.outs) != 1: # input is read by multiple nodes (or no nodes), need to add fork.
|
||||||
node_map[n] = Node(self, f'{node.name}~{n.name}')
|
node_map[n] = Node(self, f'{node.name}~{n.name}')
|
||||||
for l in impl.lines: # add all internal lines to main circuit
|
for l in impl.lines: # add all internal lines to main circuit
|
||||||
if l.reader in node_map and l.driver in node_map:
|
if l.reader in node_map and l.driver in node_map:
|
||||||
@@ -614,20 +614,24 @@ class Circuit:
|
|||||||
if marks[n]:
|
if marks[n]:
|
||||||
yield n
|
yield n
|
||||||
|
|
||||||
def fanout(self, origin_nodes):
|
def fanout(self, origin_nodes: list[Node], node_filter = lambda n: 'dff' not in n.name.lower()):
|
||||||
"""Generator function to iterate over the fan-out cone of a given list of origin nodes.
|
"""Generator function to iterate over the fan-out cone of a given list of origin nodes.
|
||||||
|
|
||||||
Nodes are yielded in topological order.
|
origin_nodes are yielded first, followed by nodes driven by them in a breadth-first manner.
|
||||||
|
The search stops at nodes for which node_filter returns False.
|
||||||
|
Only origin_nodes and nodes for which node_filter returned True are yielded.
|
||||||
|
By default, search stops at flip-flops.
|
||||||
"""
|
"""
|
||||||
marks = [False] * len(self.nodes)
|
queue = deque(origin_nodes)
|
||||||
for n in origin_nodes:
|
yielded = set()
|
||||||
marks[n] = True
|
while len(queue) > 0:
|
||||||
for n in self.topological_order():
|
n = queue.popleft()
|
||||||
if not marks[n]:
|
for line in n.outs.without_nones():
|
||||||
for line in n.ins.without_nones():
|
succ = line.reader
|
||||||
marks[n] |= marks[line.driver]
|
if succ not in yielded and node_filter(succ):
|
||||||
if marks[n]:
|
yielded.add(succ)
|
||||||
yield n
|
queue.append(succ)
|
||||||
|
yield n
|
||||||
|
|
||||||
def fanout_free_regions(self):
|
def fanout_free_regions(self):
|
||||||
for stem in self.reversed_topological_order():
|
for stem in self.reversed_topological_order():
|
||||||
|
|||||||
+42
-12
@@ -81,6 +81,29 @@ on a signal. ``'N'``, ``'n'``, and ``'v'`` are interpreted as ``NPULSE``.
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
# 0 X - 1 P R F N
|
||||||
|
_mv_xor = np.array([[0,1,1,3,4,5,6,7], # 0
|
||||||
|
[1,1,1,1,1,1,1,1], # X
|
||||||
|
[1,1,1,1,1,1,1,1], # -
|
||||||
|
[3,1,1,0,7,6,5,4], # 1
|
||||||
|
[4,1,1,7,4,5,6,7], # P
|
||||||
|
[5,1,1,6,5,4,7,6], # R
|
||||||
|
[6,1,1,5,6,7,4,5], # F
|
||||||
|
[7,1,1,4,7,6,5,4], # N
|
||||||
|
], dtype=np.uint8)
|
||||||
|
|
||||||
|
# 0 X - 1 P R F N
|
||||||
|
_mv_merge = np.array([[0,0,0,1,1,1,1,1], # 0
|
||||||
|
[0,1,1,3,4,5,6,7], # X
|
||||||
|
[0,1,2,3,4,5,6,7], # -
|
||||||
|
[1,3,3,3,1,1,1,1], # 1
|
||||||
|
[1,4,4,1,4,1,1,1], # P
|
||||||
|
[1,5,5,1,1,5,1,1], # R
|
||||||
|
[1,6,6,1,1,1,6,1], # F
|
||||||
|
[1,7,7,1,1,1,1,7], # N
|
||||||
|
], dtype=np.uint8)
|
||||||
|
|
||||||
|
|
||||||
def interpret(value):
|
def interpret(value):
|
||||||
"""Converts characters, strings, and lists of them to lists of logic constants defined above.
|
"""Converts characters, strings, and lists of them to lists of logic constants defined above.
|
||||||
|
|
||||||
@@ -191,17 +214,6 @@ def mv_and(x1, x2, out=None):
|
|||||||
return out
|
return out
|
||||||
|
|
||||||
|
|
||||||
def _mv_xor(out, *ins):
|
|
||||||
any_unknown = (ins[0] == UNKNOWN) | (ins[0] == UNASSIGNED)
|
|
||||||
for inp in ins[1:]: any_unknown |= (inp == UNKNOWN) | (inp == UNASSIGNED)
|
|
||||||
|
|
||||||
out[...] = ZERO
|
|
||||||
for inp in ins:
|
|
||||||
np.bitwise_xor(out, inp & 0b011, out=out)
|
|
||||||
np.bitwise_or(out, inp & 0b100, out=out)
|
|
||||||
np.putmask(out, any_unknown, UNKNOWN)
|
|
||||||
|
|
||||||
|
|
||||||
def mv_xor(x1, x2, out=None):
|
def mv_xor(x1, x2, out=None):
|
||||||
"""A multi-valued XOR operator.
|
"""A multi-valued XOR operator.
|
||||||
|
|
||||||
@@ -211,7 +223,25 @@ def mv_xor(x1, x2, out=None):
|
|||||||
:return: A multi-valued array with the result.
|
:return: A multi-valued array with the result.
|
||||||
"""
|
"""
|
||||||
out = out or np.empty(np.broadcast(x1, x2).shape, dtype=np.uint8)
|
out = out or np.empty(np.broadcast(x1, x2).shape, dtype=np.uint8)
|
||||||
_mv_xor(out, x1, x2)
|
out[...] = _mv_xor[x1, x2]
|
||||||
|
return out
|
||||||
|
|
||||||
|
|
||||||
|
def mv_merge(x1, x2, out=None):
|
||||||
|
"""A multi-valued merge operator.
|
||||||
|
|
||||||
|
Merging identical values ``a`` and ``a`` yields ``a``.
|
||||||
|
Merging ``X`` and ``-`` yields ``X``.
|
||||||
|
Merging any value ``a`` with ``X`` or ``-`` yields ``a``.
|
||||||
|
Merging any other values ``a != b`` yields ``X``.
|
||||||
|
|
||||||
|
:param x1: A multi-valued array.
|
||||||
|
:param x2: A multi-valued array.
|
||||||
|
:param out: An optional storage destination. If None, a new multi-valued array is returned.
|
||||||
|
:return: A multi-valued array with the result.
|
||||||
|
"""
|
||||||
|
out = out or np.empty(np.broadcast(x1, x2).shape, dtype=np.uint8)
|
||||||
|
out[...] = _mv_merge[x1, x2]
|
||||||
return out
|
return out
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -492,7 +492,7 @@ class LogicSim4V(sim.SimOps):
|
|||||||
self._full_mask = np.full(self.c.shape[-1], 255, dtype=np.uint8)
|
self._full_mask = np.full(self.c.shape[-1], 255, dtype=np.uint8)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return f'{{name: "{self.circuit.name}", sims: {self.sims}, c_bytes: {eng(self.c.nbytes)}}}'
|
return f'{{name: "{self.circuit.name}", sims: {self.sims}, s_len: {self.s_len}, c_bytes: {eng(self.c.nbytes)}}}'
|
||||||
|
|
||||||
def s_to_c(self):
|
def s_to_c(self):
|
||||||
"""Assigns the values from ``self.s_assign`` to the inputs of the combinational portion.
|
"""Assigns the values from ``self.s_assign`` to the inputs of the combinational portion.
|
||||||
|
|||||||
+2
-2
@@ -217,9 +217,9 @@ def parse(text):
|
|||||||
return Lark(GRAMMAR, parser="lalr", transformer=SdfTransformer()).parse(text)
|
return Lark(GRAMMAR, parser="lalr", transformer=SdfTransformer()).parse(text)
|
||||||
|
|
||||||
|
|
||||||
def load(file):
|
def load(file) -> DelayFile:
|
||||||
"""Parses the contents of ``file`` and returns a :class:`DelayFile` object.
|
"""Parses the contents of ``file`` and returns a :class:`DelayFile` object.
|
||||||
|
|
||||||
Files with `.gz`-suffix are decompressed on-the-fly.
|
Files with `.gz`-suffix are decompressed on-the-fly.
|
||||||
"""
|
"""
|
||||||
return parse(readtext(file))
|
return parse(readtext(file)) # type: ignore
|
||||||
+6
-1
@@ -191,7 +191,7 @@ class SimOps:
|
|||||||
root_nodes = set([n for n in circuit.s_nodes if len(n.ins) > 0] + [n for n in circuit.nodes if len(n.outs) == 0]) # start from POs, PPOs, and any dangling nodes
|
root_nodes = set([n for n in circuit.s_nodes if len(n.ins) > 0] + [n for n in circuit.nodes if len(n.outs) == 0]) # start from POs, PPOs, and any dangling nodes
|
||||||
readers = np.array([1 if l.reader in root_nodes else len(l.reader.outs) for l in circuit.lines], dtype=np.int32) # for ref-counting forks
|
readers = np.array([1 if l.reader in root_nodes 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 root_nodes]
|
level_lines = [n.ins[0] for n in root_nodes if len(n.ins) > 0 ]
|
||||||
# FIXME: Should probably instanciate buffers for PPOs and attach DFF clocks
|
# 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
|
while len(level_lines) > 0: # traverse the circuit level-wise back towards (P)PIs
|
||||||
@@ -330,11 +330,16 @@ class SimOps:
|
|||||||
self.prim_counts = dict(d)
|
self.prim_counts = dict(d)
|
||||||
|
|
||||||
self.pi_s_locs = np.flatnonzero(self.c_locs[self.ppi_offset+np.arange(len(self.circuit.io_nodes))] >= 0)
|
self.pi_s_locs = np.flatnonzero(self.c_locs[self.ppi_offset+np.arange(len(self.circuit.io_nodes))] >= 0)
|
||||||
|
"""Locations in pattern array (axis 0) of all primary inputs (excluding flip-flops)."""
|
||||||
self.po_s_locs = np.flatnonzero(self.c_locs[self.ppo_offset+np.arange(len(self.circuit.io_nodes))] >= 0)
|
self.po_s_locs = np.flatnonzero(self.c_locs[self.ppo_offset+np.arange(len(self.circuit.io_nodes))] >= 0)
|
||||||
|
"""Locations in pattern array (axis 0) of all primary outputs (excluding flip-flops)."""
|
||||||
self.ppio_s_locs = np.arange(len(self.circuit.io_nodes), self.s_len)
|
self.ppio_s_locs = np.arange(len(self.circuit.io_nodes), self.s_len)
|
||||||
|
"""Locations in pattern array (axis 0) of all flip-flops. Pseudo-primary inputs (PPI) and pseudo-primary outputs (PPO) share the same location."""
|
||||||
|
|
||||||
self.pippi_s_locs = np.concatenate([self.pi_s_locs, self.ppio_s_locs])
|
self.pippi_s_locs = np.concatenate([self.pi_s_locs, self.ppio_s_locs])
|
||||||
|
"""Locations in pattern array (axis 0) of all primary and pseudo-primary inputs (input ports and flip-flops)."""
|
||||||
self.poppo_s_locs = np.concatenate([self.po_s_locs, self.ppio_s_locs])
|
self.poppo_s_locs = np.concatenate([self.po_s_locs, self.ppio_s_locs])
|
||||||
|
"""Locations in pattern array (axis 0) of all primary and pseudo-primary outputs (output ports and flip-flops)."""
|
||||||
|
|
||||||
self.pi_c_locs = self.c_locs[self.ppi_offset+self.pi_s_locs]
|
self.pi_c_locs = self.c_locs[self.ppi_offset+self.pi_s_locs]
|
||||||
self.po_c_locs = self.c_locs[self.ppo_offset+self.po_s_locs]
|
self.po_c_locs = self.c_locs[self.ppo_offset+self.po_s_locs]
|
||||||
|
|||||||
+196
-5
@@ -128,7 +128,7 @@ OAI21X1 input(A0,A1,B0) output(Y) Y=OAI21(A0,A1,B0) ;
|
|||||||
OAI22X1 input(A0,A1,B0,B1) output(Y) Y=OAI22(A0,A1,B0,B1) ;
|
OAI22X1 input(A0,A1,B0,B1) output(Y) Y=OAI22(A0,A1,B0,B1) ;
|
||||||
OAI33X1 input(A0,A1,A2,B0,B1,B2) output(Y) AA=OR2(A0,A1) BB=OR2(B0,B1) Y=OAI22(AA,A2,BB,B2) ;
|
OAI33X1 input(A0,A1,A2,B0,B1,B2) output(Y) AA=OR2(A0,A1) BB=OR2(B0,B1) Y=OAI22(AA,A2,BB,B2) ;
|
||||||
ADDFX1 input(A,B,CI) output(CO,S) AB=XOR2(A,B) CO=XOR2(AB,CI) S=AO22(AB,CI,A,B) ;
|
ADDFX1 input(A,B,CI) output(CO,S) AB=XOR2(A,B) CO=XOR2(AB,CI) S=AO22(AB,CI,A,B) ;
|
||||||
ADDHX1 input(A,B) output(CO,S) CO=XOR2(A,B) S=AND2(A,B) ;
|
ADDHX1 input(A,B) output(CO,S) CO=AND2(A,B) S=XOR2(A,B) ;
|
||||||
|
|
||||||
DFFX1 input(CK,D) output(Q,QN) Q=DFF(D,CK) QN=INV1(Q) ;
|
DFFX1 input(CK,D) output(Q,QN) Q=DFF(D,CK) QN=INV1(Q) ;
|
||||||
DFFSRX1 input(CK,D,RN,SN) output(Q,QN) DR=AND2(D,RN) SET=INV1(SN) DRS=OR2(DR,SET) Q=DFF(DRS,CK) QN=INV1(Q) ;
|
DFFSRX1 input(CK,D,RN,SN) output(Q,QN) DR=AND2(D,RN) SET=INV1(SN) DRS=OR2(DR,SET) Q=DFF(DRS,CK) QN=INV1(Q) ;
|
||||||
@@ -172,7 +172,7 @@ XNOR2_X1 input(A1,A2) output(ZN) ZN=XNOR2(A1,A2) ;
|
|||||||
|
|
||||||
MUX2_X1 input(I0,I1,S) output(Z) Z=MUX21(I0,I1,S) ;
|
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) ;
|
HA_X1 input(A,B) output(CO,S) CO=AND2(A,B) S=XOR2(A,B) ;
|
||||||
FA_X1 input(A,B,CI) output(CO,S) AB=XOR2(A,B) CO=XOR2(AB,CI) S=AO22(CI,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) ;
|
AOI21_X{1,2} input(A1,A2,B) output(ZN) ZN=AOI21(A1,A2,B) ;
|
||||||
@@ -225,7 +225,7 @@ 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) ;
|
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) ;
|
HA_X1 input(A,B) output(CO,S) CO=AND2(A,B) S=XOR2(A,B) ;
|
||||||
FA_X1 input(A,B,CI) output(CO,S) AB=XOR2(A,B) CO=XOR2(AB,CI) S=AO22(CI,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) ;
|
AOI21_X{1,2,4} input(A,B1,B2) output(ZN) ZN=AOI21(B1,B2,A) ;
|
||||||
@@ -340,7 +340,7 @@ MUX41X{1,2}$ input(A1,A2,A3,A4,S0,S1) output(Y) A=MUX21(A1,A2,S0) B=MUX21(A3,A4,
|
|||||||
|
|
||||||
DEC24X{1,2}$ input(A0,A1) output(Y0,Y1,Y2,Y3) A0B=INV1(A0) A1B=INV1(A1) Y0=NOR2(A0,A1) Y1=AND(A0,A1B) Y2=AND(A0B,A1) Y3=AND(A0,A1) ;
|
DEC24X{1,2}$ input(A0,A1) output(Y0,Y1,Y2,Y3) A0B=INV1(A0) A1B=INV1(A1) Y0=NOR2(A0,A1) Y1=AND(A0,A1B) Y2=AND(A0B,A1) Y3=AND(A0,A1) ;
|
||||||
FADDX{1,2}$ input(A,B,CI) output(S,CO) AB=XOR2(A,B) CO=XOR2(AB,CI) S=AO22(AB,CI,A,B) ;
|
FADDX{1,2}$ input(A,B,CI) output(S,CO) AB=XOR2(A,B) CO=XOR2(AB,CI) S=AO22(AB,CI,A,B) ;
|
||||||
HADDX{1,2}$ input(A0,B0) output(SO,C1) C1=XOR2(A0,B0) SO=AND2(A0,B0) ;
|
HADDX{1,2}$ input(A0,B0) output(SO,C1) C1=AND2(A0,B0) SO=XOR2(A0,B0) ;
|
||||||
|
|
||||||
{,AO}DFFARX{1,2}$ input(D,CLK,RSTB) output(Q,QN) DR=AND2(D,RSTB) Q=DFF(DR,CLK) QN=INV1(Q) ;
|
{,AO}DFFARX{1,2}$ input(D,CLK,RSTB) output(Q,QN) DR=AND2(D,RSTB) Q=DFF(DR,CLK) QN=INV1(Q) ;
|
||||||
DFFASRX{1,2}$ input(D,CLK,RSTB,SETB) output(Q,QN) DR=AND2(D,RSTB) SET=INV1(SETB) DRS=OR2(DR,SET) Q=DFF(DRS,CLK) QN=INV1(Q) ;
|
DFFASRX{1,2}$ input(D,CLK,RSTB,SETB) output(Q,QN) DR=AND2(D,RSTB) SET=INV1(SETB) DRS=OR2(DR,SET) Q=DFF(DRS,CLK) QN=INV1(Q) ;
|
||||||
@@ -430,7 +430,7 @@ MUX41X{1,2}$ input(IN1,IN2,IN3,IN4,S0,S1) output(Q) A=MUX21(IN1,IN2,S0) B=MUX21(
|
|||||||
|
|
||||||
DEC24X{1,2}$ input(IN1,IN2) output(Q0,Q1,Q2,Q3) IN1B=INV1(IN1) IN2B=INV1(IN2) Q0=NOR2(IN1,IN2) Q1=AND(IN1,IN2B) Q2=AND(IN1B,IN2) Q3=AND(IN1,IN2) ;
|
DEC24X{1,2}$ input(IN1,IN2) output(Q0,Q1,Q2,Q3) IN1B=INV1(IN1) IN2B=INV1(IN2) Q0=NOR2(IN1,IN2) Q1=AND(IN1,IN2B) Q2=AND(IN1B,IN2) Q3=AND(IN1,IN2) ;
|
||||||
FADDX{1,2}$ input(A,B,CI) output(S,CO) AB=XOR2(A,B) CO=XOR2(AB,CI) S=AO22(AB,CI,A,B) ;
|
FADDX{1,2}$ input(A,B,CI) output(S,CO) AB=XOR2(A,B) CO=XOR2(AB,CI) S=AO22(AB,CI,A,B) ;
|
||||||
HADDX{1,2}$ input(A0,B0) output(SO,C1) C1=XOR2(A0,B0) SO=AND2(A0,B0) ;
|
HADDX{1,2}$ input(A0,B0) output(SO,C1) C1=AND2(A0,B0) SO=XOR2(A0,B0) ;
|
||||||
|
|
||||||
{,AO}DFFARX{1,2}$ input(D,CLK,RSTB) output(Q,QN) DR=AND2(D,RSTB) Q=DFF(DR,CLK) QN=INV1(Q) ;
|
{,AO}DFFARX{1,2}$ input(D,CLK,RSTB) output(Q,QN) DR=AND2(D,RSTB) Q=DFF(DR,CLK) QN=INV1(Q) ;
|
||||||
DFFASRX{1,2}$ input(D,CLK,RSTB,SETB) output(Q,QN) DR=AND2(D,RSTB) SET=INV1(SETB) DRS=OR2(DR,SET) Q=DFF(DRS,CLK) QN=INV1(Q) ;
|
DFFASRX{1,2}$ input(D,CLK,RSTB,SETB) output(Q,QN) DR=AND2(D,RSTB) SET=INV1(SETB) DRS=OR2(DR,SET) Q=DFF(DRS,CLK) QN=INV1(Q) ;
|
||||||
@@ -450,3 +450,194 @@ LATCHX{1,2}$ input(D,CLK) output(Q,QN) Q=LATCH(D,CLK) QN=INV1(Q) ;
|
|||||||
"""The SAED 90nm educational technology library.
|
"""The SAED 90nm educational technology library.
|
||||||
It defines all cells except: negative-edge flip-flops, tri-state, latches, clock gating, level shifters
|
It defines all cells except: negative-edge flip-flops, tri-state, latches, clock gating, level shifters
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
SKY130 = TechLib(r"""
|
||||||
|
$decap_{3,4,6,8,12} ;
|
||||||
|
$fill_{1,2,4,8} ;
|
||||||
|
$tap_{1,2} ;
|
||||||
|
$tapvgnd_1 ;
|
||||||
|
$tapvgnd2_1 ;
|
||||||
|
$tapvpwrvgnd_1 ;
|
||||||
|
$lpflow_decapkapwr_{3,4,6,8,12} ;
|
||||||
|
$lpflow_bleeder_1 input(SHORT) ;
|
||||||
|
|
||||||
|
$conb_1 output(HI,LO) HI=__const1__() LO=__const0__() ;
|
||||||
|
$macro_sparecell output(LO) LO=__const0__() ;
|
||||||
|
|
||||||
|
$diode_2 input(DIODE) ;
|
||||||
|
$probe_p_8 input(A) output(X) X=BUF1(A) ;
|
||||||
|
$probec_p_8 input(A) output(X) X=BUF1(A) ;
|
||||||
|
|
||||||
|
$inv_{1,2,4,6,8,12,16} input(A) output(Y) Y=INV1(A) ;
|
||||||
|
$buf_{1,2,4,6,8,12,16} input(A) output(X) X=BUF1(A) ;
|
||||||
|
$bufbuf_{8,16} input(A) output(X) X=BUF1(A) ;
|
||||||
|
$bufinv_{8,16} input(A) output(Y) Y=INV1(A) ;
|
||||||
|
$clkbuf_{1,2,4,8,16} input(A) output(X) X=BUF1(A) ;
|
||||||
|
$clkinv_{1,2,4,8,16} input(A) output(Y) Y=INV1(A) ;
|
||||||
|
$clkinvlp_{2,4} input(A) output(Y) Y=INV1(A) ;
|
||||||
|
$clkdlybuf4s15_{1,2} input(A) output(X) X=BUF1(A) ;
|
||||||
|
$clkdlybuf4s18_{1,2} input(A) output(X) X=BUF1(A) ;
|
||||||
|
$clkdlybuf4s25_{1,2} input(A) output(X) X=BUF1(A) ;
|
||||||
|
$clkdlybuf4s50_{1,2} input(A) output(X) X=BUF1(A) ;
|
||||||
|
$dlygate4sd1_1 input(A) output(X) X=BUF1(A) ;
|
||||||
|
$dlygate4sd2_1 input(A) output(X) X=BUF1(A) ;
|
||||||
|
$dlygate4sd3_1 input(A) output(X) X=BUF1(A) ;
|
||||||
|
$dlymetal6s2s_1 input(A) output(X) X=BUF1(A) ;
|
||||||
|
$dlymetal6s4s_1 input(A) output(X) X=BUF1(A) ;
|
||||||
|
$dlymetal6s6s_1 input(A) output(X) X=BUF1(A) ;
|
||||||
|
$lpflow_clkbufkapwr_{1,2,4,8,16} input(A) output(X) X=BUF1(A) ;
|
||||||
|
$lpflow_clkinvkapwr_{1,2,4,8,16} input(A) output(Y) Y=INV1(A) ;
|
||||||
|
$lpflow_lsbuf_lh_hl_isowell_tap_{1,2,4} input(A) output(X) X=BUF1(A) ;
|
||||||
|
$lpflow_lsbuf_lh_isowell_4 input(A) output(X) X=BUF1(A) ;
|
||||||
|
$lpflow_lsbuf_lh_isowell_tap_{1,2,4} input(A) output(X) X=BUF1(A) ;
|
||||||
|
|
||||||
|
$and2_{0,1,2,4} input(A,B) output(X) X=AND2(A,B) ;
|
||||||
|
$and2b_{1,2,4} input(A_N,B) output(X) AN=INV1(A_N) X=AND2(AN,B) ;
|
||||||
|
$and3_{1,2,4} input(A,B,C) output(X) X=AND3(A,B,C) ;
|
||||||
|
$and3b_{1,2,4} input(A_N,B,C) output(X) AN=INV1(A_N) X=AND3(AN,B,C) ;
|
||||||
|
$and4_{1,2,4} input(A,B,C,D) output(X) X=AND4(A,B,C,D) ;
|
||||||
|
$and4b_{1,2,4} input(A_N,B,C,D) output(X) AN=INV1(A_N) X=AND4(AN,B,C,D) ;
|
||||||
|
$and4bb_{1,2,4} input(A_N,B_N,C,D) output(X) AN=INV1(A_N) BN=INV1(B_N) X=AND4(AN,BN,C,D) ;
|
||||||
|
|
||||||
|
$or2_{0,1,2,4} input(A,B) output(X) X=OR2(A,B) ;
|
||||||
|
$or2b_{1,2,4} input(A,B_N) output(X) BN=INV1(B_N) X=OR2(A,BN) ;
|
||||||
|
$or3_{1,2,4} input(A,B,C) output(X) X=OR3(A,B,C) ;
|
||||||
|
$or3b_{1,2,4} input(A,B,C_N) output(X) CN=INV1(C_N) X=OR3(A,B,CN) ;
|
||||||
|
$or4_{1,2,4} input(A,B,C,D) output(X) X=OR4(A,B,C,D) ;
|
||||||
|
$or4b_{1,2,4} input(A,B,C,D_N) output(X) DN=INV1(D_N) X=OR4(A,B,C,DN) ;
|
||||||
|
$or4bb_{1,2,4} input(A,B,C_N,D_N) output(X) CN=INV1(C_N) DN=INV1(D_N) X=OR4(A,B,CN,DN) ;
|
||||||
|
|
||||||
|
$nand2_{1,2,4,8} input(A,B) output(Y) Y=NAND2(A,B) ;
|
||||||
|
$nand2b_{1,2,4} input(A_N,B) output(Y) AN=INV1(A_N) Y=NAND2(AN,B) ;
|
||||||
|
$nand3_{1,2,4} input(A,B,C) output(Y) Y=NAND3(A,B,C) ;
|
||||||
|
$nand3b_{1,2,4} input(A_N,B,C) output(Y) AN=INV1(A_N) Y=NAND3(AN,B,C) ;
|
||||||
|
$nand4_{1,2,4} input(A,B,C,D) output(Y) Y=NAND4(A,B,C,D) ;
|
||||||
|
$nand4b_{1,2,4} input(A_N,B,C,D) output(Y) AN=INV1(A_N) Y=NAND4(AN,B,C,D) ;
|
||||||
|
$nand4bb_{1,2,4} input(A_N,B_N,C,D) output(Y) AN=INV1(A_N) BN=INV1(B_N) Y=NAND4(AN,BN,C,D) ;
|
||||||
|
|
||||||
|
$nor2_{1,2,4,8} input(A,B) output(Y) Y=NOR2(A,B) ;
|
||||||
|
$nor2b_{1,2,4} input(A,B_N) output(Y) BN=INV1(B_N) Y=NOR2(A,BN) ;
|
||||||
|
$nor3_{1,2,4} input(A,B,C) output(Y) Y=NOR3(A,B,C) ;
|
||||||
|
$nor3b_{1,2,4} input(A,B,C_N) output(Y) CN=INV1(C_N) Y=NOR3(A,B,CN) ;
|
||||||
|
$nor4_{1,2,4} input(A,B,C,D) output(Y) Y=NOR4(A,B,C,D) ;
|
||||||
|
$nor4b_{1,2,4} input(A,B,C,D_N) output(Y) DN=INV1(D_N) Y=NOR4(A,B,C,DN) ;
|
||||||
|
$nor4bb_{1,2,4} input(A,B,C_N,D_N) output(Y) CN=INV1(C_N) DN=INV1(D_N) Y=NOR4(A,B,CN,DN) ;
|
||||||
|
|
||||||
|
$xor2_{1,2,4} input(A,B) output(X) X=XOR2(A,B) ;
|
||||||
|
$xor3_{1,2,4} input(A,B,C) output(X) X=XOR3(A,B,C) ;
|
||||||
|
$xnor2_{1,2,4} input(A,B) output(Y) Y=XNOR2(A,B) ;
|
||||||
|
$xnor3_{1,2,4} input(A,B,C) output(X) X=XNOR3(A,B,C) ;
|
||||||
|
|
||||||
|
$maj3_{1,2,4} input(A,B,C) output(X) AB=AND2(A,B) BC=AND2(B,C) AC=AND2(A,C) X=OR3(AB,BC,AC) ;
|
||||||
|
|
||||||
|
$mux2_{1,2,4,8} input(A0,A1,S) output(X) X=MUX21(A0,A1,S) ;
|
||||||
|
$mux2i_{1,2,4} input(A0,A1,S) output(Y) M=MUX21(A0,A1,S) Y=INV1(M) ;
|
||||||
|
$mux4_{1,2,4} input(A0,A1,A2,A3,S0,S1) output(X) M0=MUX21(A0,A1,S0) M1=MUX21(A2,A3,S0) X=MUX21(M0,M1,S1) ;
|
||||||
|
|
||||||
|
$ha_{1,2,4} input(A,B) output(COUT,SUM) SUM=XOR2(A,B) COUT=AND2(A,B) ;
|
||||||
|
$fa_{1,2,4} input(A,B,CIN) output(COUT,SUM) AB=XOR2(A,B) SUM=XOR2(AB,CIN) COUT=AO22(A,B,AB,CIN) ;
|
||||||
|
$fah_1 input(A,B,CI) output(COUT,SUM) AB=XOR2(A,B) SUM=XOR2(AB,CI) COUT=AO22(A,B,AB,CI) ;
|
||||||
|
$fahcin_1 input(A,B,CIN) output(COUT,SUM) AB=XOR2(A,B) SUM=XOR2(AB,CIN) COUT=AO22(A,B,AB,CIN) ;
|
||||||
|
$fahcon_1 input(A,B,CI) output(COUT_N,SUM) AB=XOR2(A,B) SUM=XOR2(AB,CI) T=AO22(A,B,AB,CI) COUT_N=INV1(T) ;
|
||||||
|
|
||||||
|
$a21o_{1,2,4} input(A1,A2,B1) output(X) X=AO21(A1,A2,B1) ;
|
||||||
|
$a21bo_{1,2,4} input(A1,A2,B1_N) output(X) BN=INV1(B1_N) X=AO21(A1,A2,BN) ;
|
||||||
|
$a22o_{1,2,4} input(A1,A2,B1,B2) output(X) X=AO22(A1,A2,B1,B2) ;
|
||||||
|
$a2bb2o_{1,2,4} input(A1_N,A2_N,B1,B2) output(X) AN1=INV1(A1_N) AN2=INV1(A2_N) X=AO22(AN1,AN2,B1,B2) ;
|
||||||
|
$a211o_{1,2,4} input(A1,A2,B1,C1) output(X) X=AO211(A1,A2,B1,C1) ;
|
||||||
|
$a221o_{1,2,4} input(A1,A2,B1,B2,C1) output(X) T=AO22(A1,A2,B1,B2) X=OR2(T,C1) ;
|
||||||
|
$a31o_{1,2,4} input(A1,A2,A3,B1) output(X) AA=AND3(A1,A2,A3) X=OR2(AA,B1) ;
|
||||||
|
$a311o_{1,2,4} input(A1,A2,A3,B1,C1) output(X) T=AND2(A1,A2) X=AO211(T,A3,B1,C1) ;
|
||||||
|
$a32o_{1,2,4} input(A1,A2,A3,B1,B2) output(X) T=AND2(A1,A2) X=AO22(T,A3,B1,B2) ;
|
||||||
|
$a41o_{1,2,4} input(A1,A2,A3,A4,B1) output(X) T1=AND2(A1,A2) T2=AND2(T1,A3) X=AO21(T2,A4,B1) ;
|
||||||
|
$a2111o_{1,2,4} input(A1,A2,B1,C1,D1) output(X) T=AO211(A1,A2,B1,C1) X=OR2(T,D1) ;
|
||||||
|
|
||||||
|
$a21oi_{1,2,4} input(A1,A2,B1) output(Y) Y=AOI21(A1,A2,B1) ;
|
||||||
|
$a21boi_{0,1,2,4} input(A1,A2,B1_N) output(Y) BN=INV1(B1_N) Y=AOI21(A1,A2,BN) ;
|
||||||
|
$a22oi_{1,2,4} input(A1,A2,B1,B2) output(Y) Y=AOI22(A1,A2,B1,B2) ;
|
||||||
|
$a2bb2oi_{1,2,4} input(A1_N,A2_N,B1,B2) output(Y) AN1=INV1(A1_N) AN2=INV1(A2_N) Y=AOI22(AN1,AN2,B1,B2) ;
|
||||||
|
$a211oi_{1,2,4} input(A1,A2,B1,C1) output(Y) Y=AOI211(A1,A2,B1,C1) ;
|
||||||
|
$a221oi_{1,2,4} input(A1,A2,B1,B2,C1) output(Y) T=AO22(A1,A2,B1,B2) Y=NOR2(T,C1) ;
|
||||||
|
$a222oi_1 input(A1,A2,B1,B2,C1,C2) output(Y) AB=AO22(A1,A2,B1,B2) Y=AOI21(C1,C2,AB) ;
|
||||||
|
$a31oi_{1,2,4} input(A1,A2,A3,B1) output(Y) AA=AND3(A1,A2,A3) Y=NOR2(AA,B1) ;
|
||||||
|
$a311oi_{1,2,4} input(A1,A2,A3,B1,C1) output(Y) T=AND2(A1,A2) Y=AOI211(T,A3,B1,C1) ;
|
||||||
|
$a32oi_{1,2,4} input(A1,A2,A3,B1,B2) output(Y) T=AND2(A1,A2) Y=AOI22(T,A3,B1,B2) ;
|
||||||
|
$a41oi_{1,2,4} input(A1,A2,A3,A4,B1) output(Y) T1=AND2(A1,A2) T2=AND2(T1,A3) Y=AOI21(T2,A4,B1) ;
|
||||||
|
$a2111oi_{0,1,2,4} input(A1,A2,B1,C1,D1) output(Y) T=AO211(A1,A2,B1,C1) Y=NOR2(T,D1) ;
|
||||||
|
|
||||||
|
$o21a_{1,2,4} input(A1,A2,B1) output(X) X=OA21(A1,A2,B1) ;
|
||||||
|
$o21ba_{1,2,4} input(A1,A2,B1_N) output(X) BN=INV1(B1_N) X=OA21(A1,A2,BN) ;
|
||||||
|
$o22a_{1,2,4} input(A1,A2,B1,B2) output(X) X=OA22(A1,A2,B1,B2) ;
|
||||||
|
$o2bb2a_{1,2,4} input(A1_N,A2_N,B1,B2) output(X) T=NAND2(A1_N,A2_N) X=OA21(B1,B2,T) ;
|
||||||
|
$o211a_{1,2,4} input(A1,A2,B1,C1) output(X) X=OA211(A1,A2,B1,C1) ;
|
||||||
|
$o221a_{1,2,4} input(A1,A2,B1,B2,C1) output(X) T=OA22(A1,A2,B1,B2) X=AND2(T,C1) ;
|
||||||
|
$o31a_{1,2,4} input(A1,A2,A3,B1) output(X) T=OR3(A1,A2,A3) X=AND2(T,B1) ;
|
||||||
|
$o311a_{1,2,4} input(A1,A2,A3,B1,C1) output(X) T=OR2(A1,A2) X=OA211(T,A3,B1,C1) ;
|
||||||
|
$o32a_{1,2,4} input(A1,A2,A3,B1,B2) output(X) T=OR3(A1,A2,A3) X=OA21(B1,B2,T) ;
|
||||||
|
$o41a_{1,2,4} input(A1,A2,A3,A4,B1) output(X) T=OR4(A1,A2,A3,A4) X=AND2(T,B1) ;
|
||||||
|
$o2111a_{1,2,4} input(A1,A2,B1,C1,D1) output(X) T=OA211(A1,A2,B1,C1) X=AND2(T,D1) ;
|
||||||
|
|
||||||
|
$o21ai_{0,1,2,4} input(A1,A2,B1) output(Y) Y=OAI21(A1,A2,B1) ;
|
||||||
|
$o21bai_{1,2,4} input(A1,A2,B1_N) output(Y) BN=INV1(B1_N) Y=OAI21(A1,A2,BN) ;
|
||||||
|
$o22ai_{1,2,4} input(A1,A2,B1,B2) output(Y) Y=OAI22(A1,A2,B1,B2) ;
|
||||||
|
$o2bb2ai_{1,2,4} input(A1_N,A2_N,B1,B2) output(Y) T=NAND2(A1_N,A2_N) Y=OAI21(B1,B2,T) ;
|
||||||
|
$o211ai_{1,2,4} input(A1,A2,B1,C1) output(Y) Y=OAI211(A1,A2,B1,C1) ;
|
||||||
|
$o221ai_{1,2,4} input(A1,A2,B1,B2,C1) output(Y) T=OA22(A1,A2,B1,B2) Y=NAND2(T,C1) ;
|
||||||
|
$o31ai_{1,2,4} input(A1,A2,A3,B1) output(Y) T=OR3(A1,A2,A3) Y=NAND2(T,B1) ;
|
||||||
|
$o311ai_{0,1,2,4} input(A1,A2,A3,B1,C1) output(Y) T=OR2(A1,A2) Y=OAI211(T,A3,B1,C1) ;
|
||||||
|
$o32ai_{1,2,4} input(A1,A2,A3,B1,B2) output(Y) T=OR3(A1,A2,A3) Y=OAI21(B1,B2,T) ;
|
||||||
|
$o41ai_{1,2,4} input(A1,A2,A3,A4,B1) output(Y) T=OR4(A1,A2,A3,A4) Y=NAND2(T,B1) ;
|
||||||
|
$o2111ai_{1,2,4} input(A1,A2,B1,C1,D1) output(Y) T=OA211(A1,A2,B1,C1) Y=NAND2(T,D1) ;
|
||||||
|
|
||||||
|
$dfxtp_{1,2,4} input(CLK,D) output(Q) Q=DFF(D,CLK) ;
|
||||||
|
$dfxbp_{1,2} input(CLK,D) output(Q,Q_N) Q=DFF(D,CLK) Q_N=INV1(Q) ;
|
||||||
|
$dfrtp_{1,2,4} input(CLK,D,RESET_B) output(Q) DR=AND2(D,RESET_B) Q=DFF(DR,CLK) ;
|
||||||
|
$dfrbp_{1,2} input(CLK,D,RESET_B) output(Q,Q_N) DR=AND2(D,RESET_B) Q=DFF(DR,CLK) Q_N=INV1(Q) ;
|
||||||
|
$dfstp_{1,2,4} input(CLK,D,SET_B) output(Q) S=INV1(SET_B) DS=OR2(D,S) Q=DFF(DS,CLK) ;
|
||||||
|
$dfsbp_{1,2} input(CLK,D,SET_B) output(Q,Q_N) S=INV1(SET_B) DS=OR2(D,S) Q=DFF(DS,CLK) Q_N=INV1(Q) ;
|
||||||
|
$dfbbp_1 input(CLK,D,SET_B,RESET_B) output(Q,Q_N) DR=AND2(D,RESET_B) S=INV1(SET_B) DRS=OR2(DR,S) Q=DFF(DRS,CLK) Q_N=INV1(Q) ;
|
||||||
|
$dfrtn_1 input(CLK_N,D,RESET_B) output(Q) CLKN=INV1(CLK_N) DR=AND2(D,RESET_B) Q=DFF(DR,CLKN) ;
|
||||||
|
$dfbbn_{1,2} input(CLK_N,D,SET_B,RESET_B) output(Q,Q_N) CLKN=INV1(CLK_N) DR=AND2(D,RESET_B) S=INV1(SET_B) DRS=OR2(DR,S) Q=DFF(DRS,CLKN) Q_N=INV1(Q) ;
|
||||||
|
|
||||||
|
$sdfxtp_{1,2,4} input(CLK,D,SCD,SCE) output(Q) DI=MUX21(D,SCD,SCE) Q=DFF(DI,CLK) ;
|
||||||
|
$sdfxbp_{1,2} input(CLK,D,SCD,SCE) output(Q,Q_N) DI=MUX21(D,SCD,SCE) Q=DFF(DI,CLK) Q_N=INV1(Q) ;
|
||||||
|
$sdfrtp_{1,2,4} input(CLK,D,SCD,SCE,RESET_B) output(Q) DR=AND2(D,RESET_B) DI=MUX21(DR,SCD,SCE) Q=DFF(DI,CLK) ;
|
||||||
|
$sdfrbp_{1,2} input(CLK,D,SCD,SCE,RESET_B) output(Q,Q_N) DR=AND2(D,RESET_B) DI=MUX21(DR,SCD,SCE) Q=DFF(DI,CLK) Q_N=INV1(Q) ;
|
||||||
|
$sdfstp_{1,2,4} input(CLK,D,SCD,SCE,SET_B) output(Q) S=INV1(SET_B) DS=OR2(D,S) DI=MUX21(DS,SCD,SCE) Q=DFF(DI,CLK) ;
|
||||||
|
$sdfsbp_{1,2} input(CLK,D,SCD,SCE,SET_B) output(Q,Q_N) S=INV1(SET_B) DS=OR2(D,S) DI=MUX21(DS,SCD,SCE) Q=DFF(DI,CLK) Q_N=INV1(Q) ;
|
||||||
|
$sdfbbp_1 input(CLK,D,SCD,SCE,SET_B,RESET_B) output(Q,Q_N) DR=AND2(D,RESET_B) S=INV1(SET_B) DRS=OR2(DR,S) DI=MUX21(DRS,SCD,SCE) Q=DFF(DI,CLK) Q_N=INV1(Q) ;
|
||||||
|
$sdfrtn_1 input(CLK_N,D,SCD,SCE,RESET_B) output(Q) CLKN=INV1(CLK_N) DR=AND2(D,RESET_B) DI=MUX21(DR,SCD,SCE) Q=DFF(DI,CLKN) ;
|
||||||
|
$sdfbbn_{1,2} input(CLK_N,D,SCD,SCE,SET_B,RESET_B) output(Q,Q_N) CLKN=INV1(CLK_N) DR=AND2(D,RESET_B) S=INV1(SET_B) DRS=OR2(DR,S) DI=MUX21(DRS,SCD,SCE) Q=DFF(DI,CLKN) Q_N=INV1(Q) ;
|
||||||
|
|
||||||
|
$edfxtp_1 input(CLK,D,DE) output(Q) GCK=AND2(CLK,DE) Q=DFF(D,GCK) ;
|
||||||
|
$edfxbp_1 input(CLK,D,DE) output(Q,Q_N) GCK=AND2(CLK,DE) Q=DFF(D,GCK) Q_N=INV1(Q) ;
|
||||||
|
$sedfxtp_{1,2,4} input(CLK,D,DE,SCD,SCE) output(Q) DI=MUX21(D,SCD,SCE) GCK=AND2(CLK,DE) Q=DFF(DI,GCK) ;
|
||||||
|
$sedfxbp_{1,2} input(CLK,D,DE,SCD,SCE) output(Q,Q_N) DI=MUX21(D,SCD,SCE) GCK=AND2(CLK,DE) Q=DFF(DI,GCK) Q_N=INV1(Q) ;
|
||||||
|
|
||||||
|
$dlxtp_1 input(D,GATE) output(Q) Q=LATCH(D,GATE) ;
|
||||||
|
$dlxtn_{1,2,4} input(D,GATE_N) output(Q) GN=INV1(GATE_N) Q=LATCH(D,GN) ;
|
||||||
|
$dlxbp_1 input(D,GATE) output(Q,Q_N) Q=LATCH(D,GATE) Q_N=INV1(Q) ;
|
||||||
|
$dlxbn_{1,2} input(D,GATE_N) output(Q,Q_N) GN=INV1(GATE_N) Q=LATCH(D,GN) Q_N=INV1(Q) ;
|
||||||
|
$dlrtp_{1,2,4} input(D,GATE,RESET_B) output(Q) DR=AND2(D,RESET_B) Q=LATCH(DR,GATE) ;
|
||||||
|
$dlrtn_{1,2,4} input(D,GATE_N,RESET_B) output(Q) GN=INV1(GATE_N) DR=AND2(D,RESET_B) Q=LATCH(DR,GN) ;
|
||||||
|
$dlrbp_{1,2} input(D,GATE,RESET_B) output(Q,Q_N) DR=AND2(D,RESET_B) Q=LATCH(DR,GATE) Q_N=INV1(Q) ;
|
||||||
|
$dlrbn_{1,2} input(D,GATE_N,RESET_B) output(Q,Q_N) GN=INV1(GATE_N) DR=AND2(D,RESET_B) Q=LATCH(DR,GN) Q_N=INV1(Q) ;
|
||||||
|
|
||||||
|
$dlclkp_{1,2,4} input(CLK,GATE) output(GCLK) GCLK=AND2(CLK,GATE) ;
|
||||||
|
$sdlclkp_{1,2,4} input(CLK,GATE,SCE) output(GCLK) G=OR2(GATE,SCE) GCLK=AND2(CLK,G) ;
|
||||||
|
|
||||||
|
$ebufn_{1,2,4,8} input(A,TE_B) output(Z) TE=INV1(TE_B) Z=AND2(A,TE) ;
|
||||||
|
$einvn_{0,1,2,4,8} input(A,TE_B) output(Z) TE=INV1(TE_B) ZI=INV1(A) Z=AND2(ZI,TE) ;
|
||||||
|
$einvp_{1,2,4,8} input(A,TE) output(Z) ZI=INV1(A) Z=AND2(ZI,TE) ;
|
||||||
|
|
||||||
|
$lpflow_inputiso0n_1 input(A,SLEEP_B) output(X) X=AND2(A,SLEEP_B) ;
|
||||||
|
$lpflow_inputiso0p_1 input(A,SLEEP) output(X) SB=INV1(SLEEP) X=AND2(A,SB) ;
|
||||||
|
$lpflow_inputiso1n_1 input(A,SLEEP_B) output(X) X=AND2(A,SLEEP_B) ;
|
||||||
|
$lpflow_inputiso1p_1 input(A,SLEEP) output(X) SB=INV1(SLEEP) X=AND2(A,SB) ;
|
||||||
|
$lpflow_isobufsrc_{1,2,4,8,16} input(A,SLEEP) output(X) AI=INV1(A) X=OR2(AI,SLEEP) ;
|
||||||
|
$lpflow_isobufsrckapwr_16 input(A,SLEEP) output(X) AI=INV1(A) X=OR2(AI,SLEEP) ;
|
||||||
|
$lpflow_inputisolatch_1 input(D,SLEEP_B) output(Q) Q=LATCH(D,SLEEP_B) ;
|
||||||
|
""".replace('$','sky130_fd_sc_hd__'))
|
||||||
|
"""SkyWater 130nm High Density Digital Standard Cells (skywater-pdk-libs-sky130_fd_sc_hd).
|
||||||
|
"""
|
||||||
@@ -0,0 +1,218 @@
|
|||||||
|
"""A simple parser for Verilog Change Dump (VCD) files.
|
||||||
|
|
||||||
|
This parser loads the changes into a ndarray of logic values.
|
||||||
|
Axis 0 is the time step, axis 1 is the variable data.
|
||||||
|
All variable values are flattened. Offsets are stored in each variable metadata.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from collections import namedtuple
|
||||||
|
from dataclasses import dataclass, field
|
||||||
|
|
||||||
|
from lark import Lark, Transformer
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
from . import readtext, logic
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Var:
|
||||||
|
type: str
|
||||||
|
width: int
|
||||||
|
idcode: str
|
||||||
|
reference: str
|
||||||
|
scope: 'Scope'
|
||||||
|
locs: list[int] = field(default_factory=list)
|
||||||
|
|
||||||
|
|
||||||
|
class Scope:
|
||||||
|
def __init__(self, parent, name='', type='module') -> None:
|
||||||
|
self.name = name
|
||||||
|
self.type = type
|
||||||
|
self.parent_scope = parent
|
||||||
|
self.sub_scopes : list[Scope] = []
|
||||||
|
self.vars : list = []
|
||||||
|
|
||||||
|
@property
|
||||||
|
def path(self) -> str:
|
||||||
|
parts = []
|
||||||
|
s = self
|
||||||
|
while s is not None and s.name:
|
||||||
|
parts.append(s.name)
|
||||||
|
s = s.parent_scope
|
||||||
|
return '/'.join(reversed(parts))
|
||||||
|
|
||||||
|
def __repr__(self) -> str:
|
||||||
|
return self.path
|
||||||
|
|
||||||
|
|
||||||
|
class VcdHeader:
|
||||||
|
def __init__(self) -> None:
|
||||||
|
self.comment: str = ''
|
||||||
|
self.date: str = ''
|
||||||
|
self.timescale: str = ''
|
||||||
|
self.version: str = ''
|
||||||
|
self.root_scope = Scope(None)
|
||||||
|
self.current_scope = self.root_scope
|
||||||
|
|
||||||
|
def scope(self, name, type):
|
||||||
|
new_scope = Scope(self.current_scope, name, type)
|
||||||
|
self.current_scope.sub_scopes.append(new_scope)
|
||||||
|
self.current_scope = new_scope
|
||||||
|
|
||||||
|
def upscope(self):
|
||||||
|
assert self.current_scope.parent_scope is not None, "root scope has no parent"
|
||||||
|
self.current_scope = self.current_scope.parent_scope
|
||||||
|
|
||||||
|
def add_var(self, type: str, width: int, idcode: str, reference: str):
|
||||||
|
self.current_scope.vars.append(Var(type, width, idcode, reference, self.current_scope))
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
lines = [
|
||||||
|
'VcdHeader(',
|
||||||
|
f' comment = {self.comment!r}',
|
||||||
|
f' date = {self.date!r}',
|
||||||
|
f' timescale = {self.timescale!r}',
|
||||||
|
f' version = {self.version!r}',
|
||||||
|
' scopes:',
|
||||||
|
]
|
||||||
|
def fmt_scope(scope, indent=4):
|
||||||
|
lines.append(f'{" " * (indent // 2)}{scope.type}:{scope.name} ({len(scope.vars)} vars)')
|
||||||
|
for sub in scope.sub_scopes:
|
||||||
|
fmt_scope(sub, indent + 2)
|
||||||
|
for sub in self.root_scope.sub_scopes:
|
||||||
|
fmt_scope(sub)
|
||||||
|
lines.append(')')
|
||||||
|
return '\n'.join(lines)
|
||||||
|
|
||||||
|
|
||||||
|
class VcdVarMap:
|
||||||
|
def __init__(self, header: VcdHeader, var_locs = lambda _: []) -> None:
|
||||||
|
self.var_list: list[Var] = []
|
||||||
|
def collect(scope):
|
||||||
|
for v in scope.vars:
|
||||||
|
v.locs = var_locs(v)
|
||||||
|
if v.locs is not None and len(v.locs) > 0:
|
||||||
|
assert len(v.locs) == v.width, f'{v.reference}: len(locs)={len(v.locs)} != width={v.width}'
|
||||||
|
self.var_list.append(v)
|
||||||
|
for sub in scope.sub_scopes:
|
||||||
|
collect(sub)
|
||||||
|
collect(header.root_scope)
|
||||||
|
self.total_width = max((max(v.locs) for v in self.var_list), default=-1) + 1
|
||||||
|
self.idcode2var = {var.idcode: var for var in self.var_list}
|
||||||
|
|
||||||
|
|
||||||
|
class VcdData:
|
||||||
|
def __init__(self, var_map: VcdVarMap, steps, data):
|
||||||
|
self.var_map = var_map
|
||||||
|
self.steps = steps
|
||||||
|
self.data = data
|
||||||
|
def __repr__(self) -> str:
|
||||||
|
return f'{{variables: {len(self.var_map.var_list)}, bits: {self.data.shape[0]}, steps: {self.data.shape[1]}}}'
|
||||||
|
|
||||||
|
|
||||||
|
class VcdHeaderTransformer(Transformer):
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
self.header = VcdHeader()
|
||||||
|
|
||||||
|
def comment(self, args): self.header.comment = args[0].value.strip()
|
||||||
|
def date(self, args): self.header.date = args[0].value.strip()
|
||||||
|
def timescale(self, args): self.header.timescale = args[0].value.strip()
|
||||||
|
def version(self, args): self.header.version = args[0].value.strip()
|
||||||
|
|
||||||
|
def scope(self, args):
|
||||||
|
type, name = args
|
||||||
|
self.header.scope(name.value, type.value)
|
||||||
|
|
||||||
|
def upscope(self, args):
|
||||||
|
self.header.upscope()
|
||||||
|
|
||||||
|
def var(self, args):
|
||||||
|
type, width, idcode, reference = args
|
||||||
|
reference = reference.value.strip()
|
||||||
|
width = int(width)
|
||||||
|
self.header.add_var(type.value, width, idcode.value, reference)
|
||||||
|
|
||||||
|
def start(self, args):
|
||||||
|
return self.header
|
||||||
|
#return tuple(args) if len(args) > 1 else (args[0], None)
|
||||||
|
|
||||||
|
|
||||||
|
GRAMMAR = r"""
|
||||||
|
start: (_declaration_command)*
|
||||||
|
_declaration_command: ( comment | date | scope | timescale | upscope | var | version ) "$end"
|
||||||
|
comment: "$comment" TEXT?
|
||||||
|
date: "$date" TEXT
|
||||||
|
scope: "$scope" /[^\s]+/ /[^\s]+/
|
||||||
|
timescale: "$timescale" TEXT
|
||||||
|
upscope: "$upscope"
|
||||||
|
var: "$var" /[^\s]+/ /[^\s]+/ /[^\s]+/ TEXT
|
||||||
|
version: "$version" TEXT
|
||||||
|
TEXT: /(?:(?!\$end)[\s\S])+/
|
||||||
|
%ignore ( /\r?\n/ )+
|
||||||
|
%ignore /[\t \f]+/
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def load(file, var_locs = lambda _: [], step_filter = lambda *_: True, s_len = None) -> VcdData:
|
||||||
|
"""Parses the contents of ``file`` as Verilog Change Dump (VCD).
|
||||||
|
|
||||||
|
:param file: A file name or a file handle. Files with `.gz`-suffix are decompressed on-the-fly.
|
||||||
|
:param var_locs: A callback ``(var) -> list[int]`` mapping each variable to ndarray column indices. Empty list drops the variable.
|
||||||
|
:param step_filter: A callback ``(time, values, var_map) -> bool`` to select which timesteps to include.
|
||||||
|
:param s_len: length of the first axis of returned pattern data.
|
||||||
|
:return: A VcdData object with metadata and an ndarray with all values.
|
||||||
|
"""
|
||||||
|
vcd = readtext(file)
|
||||||
|
header_size = vcd.find('$enddefinitions')
|
||||||
|
assert header_size > 0, "invalid VCD file: end of header not found"
|
||||||
|
vcd_header_str = vcd[:header_size]
|
||||||
|
vcd_header : VcdHeader = Lark(GRAMMAR, parser="lalr", lexer='contextual', transformer=VcdHeaderTransformer()).parse(vcd_header_str) # type: ignore
|
||||||
|
vcd_data = vcd[header_size:].splitlines()
|
||||||
|
var_map = VcdVarMap(vcd_header, var_locs)
|
||||||
|
width = s_len if s_len is not None else var_map.total_width
|
||||||
|
|
||||||
|
chunk_size = 10240
|
||||||
|
chunks = []
|
||||||
|
chunk = np.full((chunk_size, width), logic.UNASSIGNED, dtype=np.uint8)
|
||||||
|
|
||||||
|
_val_map = {'0': logic.ZERO, '1': logic.ONE,
|
||||||
|
'x': logic.UNKNOWN, 'X': logic.UNKNOWN,
|
||||||
|
'z': logic.UNASSIGNED, 'Z': logic.UNASSIGNED}
|
||||||
|
_pad_char = {'0': '0', '1': '0', 'x': 'x', 'X': 'x', 'z': 'z', 'Z': 'z'}
|
||||||
|
|
||||||
|
current_time = None
|
||||||
|
steps = []
|
||||||
|
step_idx = 0
|
||||||
|
for line in vcd_data:
|
||||||
|
if not line or line[0] == '$':
|
||||||
|
continue
|
||||||
|
if line[0] == '#':
|
||||||
|
if step_filter(current_time, chunk[step_idx], var_map):
|
||||||
|
step_idx += 1
|
||||||
|
steps.append(current_time)
|
||||||
|
if step_idx >= chunk_size:
|
||||||
|
chunks.append(chunk)
|
||||||
|
chunk = np.empty((chunk_size, width), dtype=np.uint8)
|
||||||
|
chunk[0] = chunks[-1][-1]
|
||||||
|
step_idx = 0
|
||||||
|
else:
|
||||||
|
chunk[step_idx] = chunk[step_idx - 1]
|
||||||
|
current_time = int(line[1:])
|
||||||
|
continue
|
||||||
|
if line[0] in ('b', 'B'):
|
||||||
|
value_str, idcode = line[1:].split(None, 1)
|
||||||
|
else:
|
||||||
|
value_str, idcode = line[0], line[1:]
|
||||||
|
var = var_map.idcode2var.get(idcode)
|
||||||
|
if var is None:
|
||||||
|
continue
|
||||||
|
if len(value_str) < var.width:
|
||||||
|
value_str = _pad_char.get(value_str[0], '0') * (var.width - len(value_str)) + value_str
|
||||||
|
for i, c in enumerate(value_str):
|
||||||
|
if var.locs[i] >= 0:
|
||||||
|
chunk[step_idx, var.locs[i]] = _val_map.get(c, logic.UNKNOWN)
|
||||||
|
|
||||||
|
chunks.append(chunk[:step_idx])
|
||||||
|
data = np.concatenate(chunks, axis=0).T
|
||||||
|
return VcdData(var_map, steps, data)
|
||||||
@@ -52,13 +52,14 @@ class VerilogTransformer(Transformer):
|
|||||||
@staticmethod
|
@staticmethod
|
||||||
def instantiation(args):
|
def instantiation(args):
|
||||||
pinmap = {}
|
pinmap = {}
|
||||||
for idx, pin in enumerate(args[2:]):
|
if args[2] is not None:
|
||||||
p = pin.children[0]
|
for idx, pin in enumerate(args[2:]):
|
||||||
if isinstance(p, tuple): # named pin
|
p = pin.children[0]
|
||||||
if p[1] is not None:
|
if isinstance(p, tuple): # named pin
|
||||||
pinmap[p[0]] = p[1]
|
if p[1] is not None:
|
||||||
else: # unnamed pin
|
pinmap[p[0]] = p[1]
|
||||||
pinmap[idx] = p
|
else: # unnamed pin
|
||||||
|
pinmap[idx] = p
|
||||||
return Instantiation(args[0], args[1], pinmap)
|
return Instantiation(args[0], args[1], pinmap)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
|||||||
@@ -434,7 +434,7 @@ class WaveSimCuda(WaveSim):
|
|||||||
grid_dim = self._grid_dim(self.sims, self.s_len)
|
grid_dim = self._grid_dim(self.sims, self.s_len)
|
||||||
wave_assign_gpu[grid_dim, self._block_dim](self.c, self.s, self.c_locs, self.ppi_offset)
|
wave_assign_gpu[grid_dim, self._block_dim](self.c, self.s, self.c_locs, self.ppi_offset)
|
||||||
|
|
||||||
def _grid_dim(self, x, y): return cdiv(x, self._block_dim[0]), cdiv(y, self._block_dim[1])
|
def _grid_dim(self, x, y): return cdiv(int(x), self._block_dim[0]), cdiv(int(y), self._block_dim[1])
|
||||||
|
|
||||||
def c_prop(self, sims=None, seed=1, op_from=0, op_to=None, delta=0):
|
def c_prop(self, sims=None, seed=1, op_from=0, op_to=None, delta=0):
|
||||||
sims = min(sims or self.sims, self.sims)
|
sims = min(sims or self.sims, self.sims)
|
||||||
|
|||||||
Reference in new issue
Block a user