142 Commits
Author SHA1 Message Date
Stefan Holst aa7536b8b0 line use and diff 2023-12-06 16:44:17 +09:00
Stefan Holst fccf5e0d84 fix log limit 2023-12-06 16:43:42 +09:00
Stefan Holst a6d1e4099c alap toposort, improve tests 2023-11-07 12:44:19 +09:00
Stefan Holst 1654915ed6 support for partial re-sim 2023-11-03 14:26:48 +09:00
Stefan Holst d2a2484efa fix fault injection 2023-11-03 14:26:04 +09:00
Stefan Holst de79393dfc fix log limiter, use eng notation 2023-09-26 13:58:38 +09:00
Stefan Holst 4bb3f3424a cond in sdf parser. ignored for now. 2023-09-11 23:44:28 +09:00
Stefan Holst a6243b43f6 keep s_nodes 2023-09-11 23:41:51 +09:00
Stefan Holst baeb759824 types, perf op growing list, keep s_nodes 2023-08-07 21:59:08 +09:00
Stefan Holst 967a232b1c fix pulse threshold selection 2023-07-29 09:45:48 +09:00
Stefan Holst 8096416b0e save test position for each pattern 2023-07-28 17:26:28 +09:00
Stefan Holst a4cce9f8c0 Produce stable value when trans. to/from - 2023-07-28 17:20:34 +09:00
Stefan Holst 4f6b733eb4 fix NanGate variants, version bump 2023-07-26 17:18:28 +09:00
Stefan Holst 371bc906b3 Merge branch 'main' into devel
fix readthedocs
2023-07-22 17:09:46 +09:00
Stefan Holst 0ade89defa remove old test data, intro check 2023-07-22 15:58:16 +09:00
Stefan Holst 7f4026f504 def-file docs 2023-07-22 15:52:51 +09:00
Stefan Holst e6a0d59d44 def-file docs 2023-07-22 15:52:28 +09:00
Stefan Holst 63e5f32e21 better ignore 2023-07-22 13:24:25 +09:00
Stefan Holst 35e727e714 better docs, new techlib as default, fix tests 2023-07-22 13:11:11 +09:00
Stefan Holst 83445e2bbd support for newer NANGATE lib 2023-07-21 22:14:29 +09:00
Stefan Holst c67148c0ee doc fix 2023-07-21 22:13:25 +09:00
Stefan Holst 280c425486 fix test 2023-07-12 22:35:53 +09:00
Stefan Holst 5be82da49a avoid holes in forks, update intro 2023-07-12 22:32:22 +09:00
Stefan Holst b3dbe9765a fix xor in libs, remove old code 2023-07-12 21:10:27 +09:00
Stefan Holst 5e573b0408 fix substitute for inputs with fo, dot graph 2023-07-12 21:06:16 +09:00
Stefan Holst 08d9f5a9bf one-bit busses 2023-07-12 16:32:08 +09:00
Stefan Holst b098fb219d fix for unconnected named pins, double-declaration 2023-07-12 11:36:43 +09:00
Stefan Holst 97387e962b add GSC180nm 2023-07-12 11:35:15 +09:00
Stefan Holst f4d875f7e5 docs 2023-07-12 11:34:45 +09:00
Stefan Holst cf9a98b5ce del deprecated sdf code, explicit tlib use 2023-07-10 20:35:19 +09:00
Stefan Holst d8f605a47a fix double-free when fo goes to same cell 2023-07-10 20:08:48 +09:00
Stefan Holst ec5626b8ca remove old connections in substitute node reuse 2023-07-10 09:00:31 +09:00
Stefan Holst 5a693f7b9b preserve node order during resolve 2023-07-09 23:46:14 +09:00
Stefan Holst 19bbe2c260 update intro 2023-07-09 21:34:01 +09:00
Stefan Holst d3897246c5 move resolving cells to circuit, more doc 2023-07-09 19:04:22 +09:00
Stefan Holst 9bda7a4c57 capitalize tech libs 2023-07-09 19:01:31 +09:00
Stefan Holst 2270a9eee7 fix fork stripping + fork None values 2023-07-09 19:01:15 +09:00
Stefan Holst ea45a326ec add latch, fix xor delays, improve test 2023-07-09 13:42:07 +09:00
Stefan Holst 1e9fe7707b saed32nm 2023-07-09 00:29:56 +09:00
Stefan Holst 50a5d8a290 one cell inherits name in substitute, sim fix 2023-07-08 22:52:10 +09:00
Stefan Holst d97555e9e9 fix simprim cells, add saed90 2023-07-08 18:55:52 +09:00
Stefan Holst 47ee8d5878 improve substitute, update notebook output 2023-07-08 18:54:27 +09:00
Stefan Holst c32584fc76 1to1 fork optimization, fix substitute 2023-07-05 22:55:06 +09:00
Stefan Holst 39b8c1695b full constants support, fix signal declarations 2023-07-05 22:07:15 +09:00
Stefan Holst 80d26b6f0b Add AO*211 and OA*211, fix MUX21 2023-07-05 22:01:42 +09:00
Stefan Holst f7ef78e58d support for limiting log messages 2023-07-05 21:59:49 +09:00
Stefan Holst 7afb13b33b mv_str for single values, remove undue assert 2023-07-03 12:40:02 +09:00
Stefan Holst 153442a10a def file parser 2023-07-03 00:49:23 +09:00
Stefan Holst afb0a64953 wsa accumulation in wavesim 2023-07-03 00:48:58 +09:00
Stefan Holst c49667edc1 remove old code, verilog positional pins 2023-06-26 23:23:56 +09:00
Stefan Holst d921eb5048 sim support for remaining primitives 2023-06-25 22:27:19 +09:00
Stefan Holst 670fb0b3fc circuit node substitution 2023-06-25 22:26:52 +09:00
Stefan Holst f8bf579be2 support concat, bus select, ISOL cells 2023-06-24 23:41:08 +09:00
Stefan Holst f61e2b42e8 support more cells in logic sim 2023-06-24 13:34:35 +09:00
Stefan Holst 4aec335abb verilog: concat assignments, more comments 2023-06-24 13:33:55 +09:00
Stefan Holst 1a9cb396bf tweak repr, doc 2023-06-24 13:32:40 +09:00
Stefan Holst 3875dc38f9 docs 2023-06-21 23:23:01 +09:00
Stefan Holst ecb7171c37 docs 2023-06-21 23:18:17 +09:00
Stefan Holst 8957db48ab docs 2023-06-20 06:54:59 +09:00
Stefan Holst 0b15f9fa18 doc improvements 2023-06-19 17:05:39 +09:00
Stefan Holst dc76a9f517 new into demo 2023-06-19 14:01:31 +09:00
Stefan Holst 0968cb451e docs, fix stil unassigned, fix io_locs for busses 2023-06-19 13:12:17 +09:00
Stefan Holst 947df89434 add AOI21 to logic sim 2023-06-02 00:04:34 +09:00
Stefan Holst f17e461fdd fix reading directly from file handle 2023-05-19 14:57:02 +09:00
Stefan Holst d6d981a351 support for det vars 2023-04-05 18:35:55 +09:00
Stefan Holst 7a060b1831 support for static variations 2023-03-28 11:10:38 +09:00
Stefan Holst 03802ac9f8 make sims pickleable 2023-03-22 13:55:53 +09:00
Stefan Holst 70caea065e more cleanup 2023-03-20 14:14:06 +09:00
stefan f04f1b0012 cleanup 2023-03-20 10:31:55 +09:00
Stefan Holst 44b0c887d7 random sampling of delays 2023-03-19 20:30:27 +09:00
Stefan Holst 4e2022291e fix cuda ppo_to_ppi 2023-03-15 15:15:22 +09:00
Stefan Holst 5566b80e52 simprim, vat refactor, batchrange 2023-03-15 10:37:39 +09:00
stefan 63c0b48537 bump 2023-03-14 18:50:15 +09:00
stefan 6520ee23ef cleanup and new intro notebook 2023-03-14 17:40:50 +09:00
stefan 1810d40959 pytest work without cuda 2023-03-13 23:18:32 +09:00
Stefan Holst 7430ebb068 jitted logic sim 2023-03-13 23:15:20 +09:00
stefan 89f317b463 better circuit statsu, 2v logic sim 2023-03-13 10:50:44 +09:00
Stefan Holst 753ce566e4 Timer improvements, log in yaml 2023-03-13 10:45:41 +09:00
stefan 1eb8d87884 faster logic sim, removing MVArray, BPArray 2023-03-12 23:59:10 +09:00
stefan 02f3a0e1b2 correct timing padding 2023-02-28 09:39:01 +09:00
stefan fc8e65e788 bit-packing utility 2023-02-28 09:38:28 +09:00
stefan d80a3ae2b1 timer utility 2023-02-28 09:38:02 +09:00
Stefan Holst 7bfc02e683 more on-gpu code, bump python requirement 2023-02-26 22:37:15 +09:00
Stefan Holst 8da4a62bce switch to new wave_sim, silence occupancy warnings 2023-02-26 13:54:01 +09:00
stefan 3497bfdc75 first gpu-code, cached test fixtures 2023-02-26 13:09:49 +09:00
stefan f1ebe1487c new wave sim 2023-02-26 11:04:38 +09:00
stefan f0dac36ac7 interface -> io_nodes, io_loc fix 2023-02-24 21:56:29 +09:00
Stefan Holst b2953aef25 only dff 2023-02-22 13:37:15 +09:00
Stefan Holst 3774b14286 support ppi/ppo 2023-02-22 13:32:49 +09:00
Stefan Holst 4847ad9c40 locating io ports and busses by name 2023-02-21 23:26:48 +09:00
Stefan Holst 6801606dca new common scheduler for simulators 2023-02-21 19:27:54 +09:00
Stefan Holst faf41f0863 ff transitions switch 2023-02-06 09:53:44 +09:00
Stefan Holst 6430f10f73 HADD pin index fix 2023-02-06 09:52:32 +09:00
Stefan Holst fa19af8c31 4-input gate simulator 2023-01-18 14:34:17 +09:00
Stefan Holst 93a0858d2f oai and aoi pin handling fix 2023-01-16 17:37:41 +09:00
Stefan Holst 1f2808ee31 Merge branch 'main' into devel 2022-07-21 22:10:20 +09:00
Stefan Holst 163b348a0c year bump 2022-07-21 18:47:25 +09:00
Stefan Holst ecfc692edc support reset RN for scan cells 2022-07-21 17:16:59 +09:00
Stefan Holst afb7e745a1 adding aoi to logic sim 2022-07-21 17:16:59 +09:00
stefan 6a8841c3c6 revert wave_eval4 2022-07-21 16:57:20 +09:00
Stefan Holst c530983afa accept I as a first input 2022-03-17 14:57:37 +09:00
Stefan Holst 775b13c694 fix off-by-1 pin index when loading AOI and OAI cells 2022-02-02 15:05:14 +09:00
Stefan Holst 584445f3b1 wave eval for 4-input gates 2021-11-22 14:54:38 +09:00
Stefan Holst 85dd02d4d7 interpret N as unassigned in STIL 2021-11-07 18:51:41 +09:00
Stefan Holst 7c03271048 improve robustness of sdf annotation and wave sim 2021-09-01 12:57:55 +09:00
Stefan Holst 8bbaaf8fae comment change 2021-07-26 10:52:33 +09:00
Stefan Holst d59d6401c8 fix stil loading and logic sim capture 2021-07-22 17:21:58 +09:00
Stefan Holst 387c436207 fix tests, version bump 2021-07-19 14:14:35 +09:00
Stefan Holst b981b1153c add sdata to control individual sims 2021-06-17 12:05:55 +09:00
stefan 87d93afb44 fix time in unpickled log objects 2021-03-31 11:11:25 +09:00
Stefan Holst c3e4090f31 make nodes and lines hashable again 2021-03-28 19:44:19 +09:00
Stefan Holst 0251d66d28 make circuit pickable and comparable 2021-03-28 19:35:19 +09:00
Stefan Holst 864230b883 initial letch support, fix capture in logic sim 2021-03-25 10:36:55 +09:00
Stefan Holst d05841a6a2 Merge branch 'main' into devel 2021-01-31 18:32:14 +09:00
Stefan Holst c5be32d7e5 doc and indent fix 2021-01-31 18:25:09 +09:00
Stefan Holst 8434f5e694 fixes for IWLS benchmark netlists 2021-01-31 16:40:00 +09:00
Stefan Holst 9ff2369a55 fix parsing older stil files 2021-01-31 13:43:03 +09:00
Stefan Holst 82a53e0171 improve techlib for gsclib, better constant handling in verilog parser 2021-01-31 13:41:36 +09:00
Stefan Holst a2df0e5682 fix ff annotation 2021-01-22 18:03:18 +09:00
Stefan Holst ec37e11fef Merge branch 'main' into devel 2021-01-16 14:56:36 +09:00
Stefan Holst 3a5a3c128b year bump 2021-01-16 13:52:18 +09:00
Stefan Holst ee30898cef docs for numba and cuda 2021-01-16 13:35:20 +09:00
Stefan Holst 62cf56e98a TechLib class, remove unnecessary .index 2021-01-16 13:17:18 +09:00
Stefan Holst dc003fa624 documentation improvements 2021-01-16 00:04:34 +09:00
Stefan Holst 8b5a71f498 documentation improvements 2021-01-15 21:28:15 +09:00
Stefan Holst 9c8dee31b9 assign and capture return arrays, new cycle method for common use pattern 2021-01-14 20:47:22 +09:00
Stefan Holst 2bbdf3ee5d fix logic sim of DFF.QN output 2021-01-14 15:05:39 +09:00
Stefan Holst 35cf63cf38 Make Node and Line indexable, documentation. 2021-01-12 22:27:13 +09:00
Stefan Holst ff4de6d782 de-lint and repr improvements 2021-01-12 15:32:18 +09:00
Stefan Holst c12a30328c better hr_time 2021-01-12 15:18:37 +09:00
stefan 7e6660002b support ibuff in WaveSim 2021-01-06 15:58:47 +09:00
stefan dfbc35eeb9 logging range fixes 2021-01-06 13:56:03 +09:00
Stefan Holst 4f531fe4cb implement logging range 2021-01-06 12:54:14 +09:00
Stefan Holst 18c17b5f76 more docs and reprs 2021-01-06 11:32:43 +09:00
Stefan Holst 0bad95e94e LogicSim clean-up and new fault injection facility. version bump. 2020-12-22 19:01:19 +09:00
Stefan Holst 7501613951 remove comments 2020-12-21 20:23:53 +09:00
Stefan Holst 5084f1dd8c demo nb run with cuda 2020-12-21 20:13:48 +09:00
Stefan Holst 7f035c1ac5 Migration to new logic value representation 2020-12-21 19:16:52 +09:00
Stefan Holst 7bcfbf502b Documentation, cleanup, multi-valued logic 2020-12-20 17:44:04 +09:00
Stefan Holst 5830608527 Documenting circuit module 2020-12-18 21:14:00 +09:00
Stefan Holst cff18e0915 start documentation 2020-12-15 19:20:30 +09:00
Stefan Holst a77ac4a397 start designing new data structures for m-valued logic 2020-12-14 14:06:18 +09:00
20 changed files with 570 additions and 219 deletions

No files matched your search

+1 -1
View File
@@ -24,7 +24,7 @@ copyright = '2020-2023, 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.4' release = '0.0.5'
# -- General configuration --------------------------------------------------- # -- General configuration ---------------------------------------------------
+1 -1
View File
@@ -5,7 +5,7 @@ with open('README.rst', 'r') as f:
setup( setup(
name='kyupy', name='kyupy',
version='0.0.4', version='0.0.5',
description='High-performance processing and analysis of non-hierarchical VLSI designs', description='High-performance processing and analysis of non-hierarchical VLSI designs',
long_description=long_description, long_description=long_description,
long_description_content_type='text/x-rst', long_description_content_type='text/x-rst',
+17 -3
View File
@@ -57,6 +57,18 @@ def hr_bytes(nbytes):
multiplier += 1 multiplier += 1
return f'{nbytes:.1f}{["", "ki", "Mi", "Gi", "Ti", "Pi"][multiplier]}B' 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): def hr_time(seconds):
"""Formats a given time interval for human readability.""" """Formats a given time interval for human readability."""
@@ -138,10 +150,10 @@ class Log:
self._limit = limit self._limit = limit
def stop_limit(self): def stop_limit(self):
if self.filtered > 0:
log.info(f'{self.filtered} more messages (filtered).')
self.filtered = 0
self._limit = -1 self._limit = -1
if self.filtered > 0:
self.info(f'{self.filtered} more messages (filtered).')
self.filtered = 0
def __getstate__(self): def __getstate__(self):
return {'elapsed': time.perf_counter() - self.start} return {'elapsed': time.perf_counter() - self.start}
@@ -149,6 +161,8 @@ class Log:
def __setstate__(self, state): def __setstate__(self, state):
self.logfile = sys.stdout self.logfile = sys.stdout
self.indent = 0 self.indent = 0
self._limit = -1
self.filtered = 0
self.start = time.perf_counter() - state['elapsed'] self.start = time.perf_counter() - state['elapsed']
def write(self, s, indent=0): def write(self, s, indent=0):
+61 -14
View File
@@ -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 from collections import deque, defaultdict
import re import re
from typing import Union
import numpy as np import numpy as np
class GrowingList(list): class GrowingList(list):
def __setitem__(self, index, value): def __setitem__(self, index, value):
if index >= len(self): if value is None: self.has_nones = True
self.extend([None] * (index + 1 - len(self))) 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) super().__setitem__(index, value)
def free_index(self): def __getitem__(self, index):
return next((i for i, x in enumerate(self) if x is None), len(self)) 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): 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 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]`. 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). """A list of input connections (:class:`Line` objects).
""" """
self.outs = GrowingList() self.outs: list[Line] = GrowingList()
"""A list of output connections (:class:`Line` objects). """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. 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. 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 self.circuit = circuit
"""The :class:`Circuit` object the line is part of. """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 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]`. 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] self.driver = driver[0]
"""The :class:`Node` object that drives this line. """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: 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`. :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] self.reader = reader[0]
"""The :class:`Node` object that reads this line. """The :class:`Node` object that reads this line.
""" """
@@ -334,15 +349,16 @@ class Circuit:
def get_or_add_fork(self, name): def get_or_add_fork(self, name):
return self.forks[name] if name in self.forks else Node(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 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] lines = [l for l in root_node.ins if l is not None]
drivers = [l.driver for l in lines] drivers = [l.driver for l in lines]
if root_node in keep: return
root_node.remove() root_node.remove()
for l in lines: for l in lines:
l.remove() l.remove()
for d in drivers: for d in drivers:
self.remove_dangling_nodes(d) self.remove_dangling_nodes(d, keep=keep)
def eliminate_1to1_forks(self): def eliminate_1to1_forks(self):
"""Removes all forks that drive only one node. """Removes all forks that drive only one node.
@@ -370,6 +386,21 @@ class Circuit:
in_line.reader_pin = out_reader_pin in_line.reader_pin = out_reader_pin
in_line.reader.ins[in_line.reader_pin] = in_line 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): def substitute(self, node, impl):
"""Replaces a given node with the given implementation circuit. """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 for l, ll in zip(impl_out_lines, node_out_lines): # connect outputs
if ll is None: if ll is None:
if l.driver in node_map: 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 continue
if len(l.reader.outs) > 0: # output is also read by impl. circuit, connect to fork. if len(l.reader.outs) > 0: # output is also read by impl. circuit, connect to fork.
ll.driver = node_map[l.reader] ll.driver = node_map[l.reader]
@@ -447,6 +478,21 @@ class Circuit:
if n.kind in tlib.cells: if n.kind in tlib.cells:
self.substitute(n, tlib.cells[n.kind][0]) 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): def copy(self):
"""Returns a deep copy of the circuit. """Returns a deep copy of the circuit.
""" """
@@ -501,14 +547,15 @@ class Circuit:
substrings 'dff' or 'latch' are yielded first. substrings 'dff' or 'latch' are yielded first.
""" """
visit_count = np.zeros(len(self.nodes), dtype=np.uint32) 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: while len(queue) > 0:
n = queue.popleft() n = queue.popleft()
for line in n.outs: for line in n.outs:
if line is None: continue if line is None: continue
succ = line.reader succ = line.reader
visit_count[succ] += 1 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) queue.append(succ)
yield n yield n
+5 -1
View File
@@ -241,6 +241,8 @@ def mv_latch(d, t, q_prev, out=None):
def mv_transition(init, final, 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``. """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``. 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``. If both inputs are ``UNASSIGNED``, the result is ``UNASSIGNED``.
:param init: A multi-valued array. :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 = out or np.empty(np.broadcast(init, final).shape, dtype=np.uint8)
out[...] = (init & 0b010) | (final & 0b001) out[...] = (init & 0b010) | (final & 0b001)
out[...] |= ((out << 1) ^ (out << 2)) & 0b100 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) unassigned = (init == UNASSIGNED) & (final == UNASSIGNED)
np.putmask(out, unknown, UNKNOWN) np.putmask(out, unknown, UNKNOWN)
np.putmask(out, unassigned, UNASSIGNED) np.putmask(out, unassigned, UNASSIGNED)
+5 -4
View File
@@ -10,7 +10,7 @@ import math
import numpy as np import numpy as np
from . import numba, logic, hr_bytes, sim from . import numba, logic, hr_bytes, sim, eng
from .circuit import Circuit from .circuit import Circuit
class LogicSim(sim.SimOps): class LogicSim(sim.SimOps):
@@ -44,7 +44,7 @@ class LogicSim(sim.SimOps):
self.s[:,:,1,:] = 255 # unassigned self.s[:,:,1,:] = 255 # unassigned
def __repr__(self): 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): def s_to_c(self):
"""Copies the values from ``s[0]`` the inputs of the combinational portion. """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.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]) 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}') else: print(f'unknown op {op}')
inject_cb(o0, self.s[o0]) inject_cb(o0, self.c[o0])
elif self.m == 4: elif self.m == 4:
for op, o0, i0, i1, i2, i3 in self.ops[:,:6]: 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)] 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_and(self.c[t1], self.c[i1], self.c[i2])
logic.bp4v_or(self.c[o0], self.c[t0], self.c[t1]) logic.bp4v_or(self.c[o0], self.c[t0], self.c[t1])
else: print(f'unknown op {op}') else: print(f'unknown op {op}')
if inject_cb is not None: inject_cb(o0, self.c[o0])
else: else:
for op, o0, i0, i1, i2, i3 in self.ops[:,:6]: 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)] 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_and(self.c[t1], self.c[i1], self.c[i2])
logic.bp8v_or(self.c[o0], self.c[t0], self.c[t1]) logic.bp8v_or(self.c[o0], self.c[t0], self.c[t1])
else: print(f'unknown op {op}') 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): def c_to_s(self):
"""Copies (captures) the results of the combinational portion to ``s[1]``. """Copies (captures) the results of the combinational portion to ``s[1]``.
+23 -15
View File
@@ -61,20 +61,21 @@ class DelayFile:
delays = np.zeros((len(circuit.lines), 2, 2, 3)) # dataset last during construction. delays = np.zeros((len(circuit.lines), 2, 2, 3)) # dataset last during construction.
for name, iopaths in self.cells.items(): with log.limit(50):
name = name.replace('\\', '') for name, iopaths in self.cells.items():
if cell := circuit.cells.get(name, None): name = name.replace('\\', '')
for i_pin_spec, o_pin_spec, *dels in iopaths: if cell := circuit.cells.get(name, None):
if i_pin_spec.startswith('(posedge '): i_pol_idxs = [0] for i_pin_spec, o_pin_spec, *dels in iopaths:
elif i_pin_spec.startswith('(negedge '): i_pol_idxs = [1] if i_pin_spec.startswith('(posedge '): i_pol_idxs = [0]
else: i_pol_idxs = [0, 1] elif i_pin_spec.startswith('(negedge '): i_pol_idxs = [1]
i_pin_spec = re.sub(r'\((neg|pos)edge ([^)]+)\)', r'\2', i_pin_spec) else: i_pol_idxs = [0, 1]
if line := cell.ins[tlib.pin_index(cell.kind, i_pin_spec)]: i_pin_spec = re.sub(r'\((neg|pos)edge ([^)]+)\)', r'\2', i_pin_spec)
delays[line, i_pol_idxs] = [d if len(d) > 0 else [0, 0, 0] for d in dels] if line := cell.ins[tlib.pin_index(cell.kind, i_pin_spec)]:
else: delays[line, i_pol_idxs] = [d if len(d) > 0 else [0, 0, 0] for d in dels]
log.warn(f'No line to annotate in circuit: {i_pin_spec} for {cell}') else:
else: log.warn(f'No line to annotate in circuit: {i_pin_spec} for {cell}')
log.warn(f'Name from SDF not found in circuit: {name}') else:
log.warn(f'Name from SDF not found in circuit: {name}')
return np.moveaxis(delays, -1, 0) return np.moveaxis(delays, -1, 0)
@@ -156,6 +157,10 @@ class SdfTransformer(Transformer):
entries = [e for a in args if hasattr(a, 'children') for e in a.children] entries = [e for a in args if hasattr(a, 'children') for e in a.children]
return name, entries return name, entries
@staticmethod
def cond(args): # ignore conditions
return args[1]
@staticmethod @staticmethod
def start(args): def start(args):
name = next((a for a in args if isinstance(a, str)), None) name = next((a for a in args if isinstance(a, str)), None)
@@ -180,9 +185,12 @@ GRAMMAR = r"""
| "(INSTANCE" ID? ")" | "(INSTANCE" ID? ")"
| "(TIMINGCHECK" _ignore* ")" | "(TIMINGCHECK" _ignore* ")"
| delay )* ")" | delay )* ")"
delay: "(DELAY" "(ABSOLUTE" (interconnect | iopath)* ")" ")" delay: "(DELAY" "(ABSOLUTE" (interconnect | iopath | cond)* ")" ")"
interconnect: "(INTERCONNECT" ID ID triple* ")" interconnect: "(INTERCONNECT" ID ID triple* ")"
iopath: "(IOPATH" ID_OR_EDGE ID_OR_EDGE 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: /[^"]+/ NAME: /[^"]+/
ID_OR_EDGE: ( /[^() ]+/ | "(" /[^)]+/ ")" ) ID_OR_EDGE: ( /[^() ]+/ | "(" /[^)]+/ ")" )
ID: ( /[^"() ]+/ | "\"" /[^"]+/ "\"" ) ID: ( /[^"() ]+/ | "\"" /[^"]+/ "\"" )
+80 -72
View File
@@ -4,9 +4,14 @@ from bisect import bisect, insort_left
import numpy as np import numpy as np
from .circuit import Circuit
BUF1 = np.uint16(0b1010_1010_1010_1010) BUF1 = np.uint16(0b1010_1010_1010_1010)
INV1 = ~BUF1 INV1 = ~BUF1
__const0__ = BUF1
__const1__ = INV1
AND2 = np.uint16(0b1000_1000_1000_1000) AND2 = np.uint16(0b1000_1000_1000_1000)
AND3 = np.uint16(0b1000_0000_1000_0000) AND3 = np.uint16(0b1000_0000_1000_0000)
AND4 = np.uint16(0b1000_0000_0000_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) 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 = { kind_prefixes = {
'nand': (NAND4, NAND3, NAND2), '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 :param c_reuse: If enabled, memory of intermediate signal waveforms will be re-used. This greatly reduces
memory footprint, but intermediate signal waveforms become unaccessible after a propagation. memory footprint, but intermediate signal waveforms become unaccessible after a propagation.
""" """
def __init__(self, circuit, 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.circuit = circuit
self.s_len = len(circuit.s_nodes) self.s_len = len(circuit.s_nodes)
@@ -175,84 +183,74 @@ class SimOps:
self.ppo_offset = self.ppi_offset + self.s_len self.ppo_offset = self.ppi_offset + self.s_len
self.c_locs_len = self.ppo_offset + self.s_len self.c_locs_len = self.ppo_offset + self.s_len
# translate circuit structure into self.ops # ALAP-toposort the circuit into self.ops
ops = [] levels = []
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
sp = None
for prefix, prims in kind_prefixes.items():
if kind.startswith(prefix):
sp = prims[0]
if i3_idx == self.zero_idx:
sp = prims[1]
if i2_idx == 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]))
self.ops = np.asarray(ops, dtype='int32') ppio2idx = dict((n, i) for i, n in enumerate(circuit.s_nodes))
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 in_idxs[3] == self.zero_idx:
sp = prims[1]
if in_idxs[2] == self.zero_idx:
sp = prims[2]
break
if sp is None:
print('unknown cell type', kind)
else:
level_ops.append((sp, l.index, *in_idxs, *a_ctrl[l]))
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 # 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: if strip_forks:
for f in circuit.forks.values(): for f in circuit.forks.values():
prev_line = f.ins[0] prev_line = f.ins[0]
while prev_line.driver.kind == '__fork__': while prev_line.driver.kind == '__fork__':
prev_line = prev_line.driver.ins[0] prev_line = prev_line.driver.ins[0]
stem_idx = prev_line.index
for ol in f.outs: for ol in f.outs:
if ol is not None: 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 ref_count = np.zeros(self.c_locs_len, dtype=np.int32)
levels = np.zeros(self.c_locs_len, dtype='int32')
ref_count = np.zeros(self.c_locs_len, dtype='int32') for op in self.ops:
level_starts = [0] for x in [2, 3, 4, 5]:
current_level = 1 ref_count[stems[op[x]] if stems[op[x]] >= 0 else op[x]] += 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')
# combinational signal allocation table. maps line and interface indices to self.c memory locations # 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) self.c_locs = np.full((self.c_locs_len,), -1, dtype=np.int32)
@@ -278,9 +276,9 @@ class SimOps:
ref_count[i0_idx] += 1 ref_count[i0_idx] += 1
# allocate memory for the rest of the circuit # 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() free_set = set()
for op in self.ops[op_start:op_stop]: for op in ops:
# if we fork-strip, always take the stems # if we fork-strip, always take the stems
i0_idx = stems[op[2]] if stems[op[2]] >= 0 else op[2] 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] i1_idx = stems[op[3]] if stems[op[3]] >= 0 else op[3]
@@ -299,7 +297,8 @@ class SimOps:
self.c_locs[o_idx], self.c_caps[o_idx] = h.alloc(cap), cap self.c_locs[o_idx], self.c_caps[o_idx] = h.alloc(cap), cap
if c_reuse: if c_reuse:
for loc in free_set: for loc in free_set:
h.free(loc) if loc >= 0: # DFF clocks are not allocated. Ignore for now.
h.free(loc)
# copy memory location and capacity from stems to fanout lines # copy memory location and capacity from stems to fanout lines
for lidx, stem in enumerate(stems): for lidx, stem in enumerate(stems):
@@ -311,6 +310,15 @@ class SimOps:
if len(n.ins) > 0: if len(n.ins) > 0:
self.c_locs[self.ppo_offset + i], self.c_caps[self.ppo_offset + i] = self.c_locs[n.ins[0]], self.c_caps[n.ins[0]] self.c_locs[self.ppo_offset + i], self.c_caps[self.ppo_offset + i] = self.c_locs[n.ins[0]], self.c_caps[n.ins[0]]
# line use information
self.line_use_start = np.full(self.c_locs_len, -1, dtype=np.int32)
self.line_use_stop = np.full(self.c_locs_len, len(self.levels), dtype=np.int32)
for i, lv in enumerate(self.levels):
for op in lv:
self.line_use_start[op[1]] = i
for x in [2, 3, 4, 5]:
self.line_use_stop[op[x]] = i
self.c_len = h.max_size self.c_len = h.max_size
d = defaultdict(int) d = defaultdict(int)
+15 -17
View File
@@ -41,7 +41,7 @@ class StilFile:
unload = {} unload = {}
for so_port in self.so_ports: for so_port in self.so_ports:
if so_port in call.parameters: 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: if len(capture) > 0:
self.patterns.append(ScanPattern(sload, launch, capture, unload)) self.patterns.append(ScanPattern(sload, launch, capture, unload))
capture = {} capture = {}
@@ -49,11 +49,9 @@ class StilFile:
sload = {} sload = {}
for si_port in self.si_ports: for si_port in self.si_ports:
if si_port in call.parameters: if si_port in call.parameters:
sload[si_port] = call.parameters[si_port].replace('\n', '').replace('N', '-') sload[si_port] = call.parameters[si_port]
if call.name.endswith('_launch'): if call.name.endswith('_launch'): launch = call.parameters
launch = dict((k, v.replace('\n', '').replace('N', '-')) for k, v in call.parameters.items()) if call.name.endswith('_capture'): capture = call.parameters
if call.name.endswith('_capture'):
capture = dict((k, v.replace('\n', '').replace('N', '-')) for k, v in call.parameters.items())
def _maps(self, c): def _maps(self, c):
interface = list(c.io_nodes) + [n for n in c.nodes if 'DFF' in n.kind] interface = list(c.io_nodes) + [n for n in c.nodes if 'DFF' in n.kind]
@@ -100,12 +98,12 @@ class StilFile:
tests = np.full((len(interface), len(self.patterns)), logic.UNASSIGNED) tests = np.full((len(interface), len(self.patterns)), logic.UNASSIGNED)
for i, p in enumerate(self.patterns): for i, p in enumerate(self.patterns):
for si_port in self.si_ports.keys(): for si_port in self.si_ports.keys():
pattern = logic.mvarray(p.load[si_port]) pattern = logic.mvarray(p.load[si_port][0])
inversions = np.choose((pattern == logic.UNASSIGNED) | (pattern == logic.UNKNOWN), inversions = np.choose((pattern == logic.UNASSIGNED) | (pattern == logic.UNKNOWN),
[scan_inversions[si_port], logic.ZERO]).astype(np.uint8) [scan_inversions[si_port], logic.ZERO]).astype(np.uint8)
np.bitwise_xor(pattern, inversions, out=pattern) np.bitwise_xor(pattern, inversions, out=pattern)
tests[scan_maps[si_port], i] = pattern tests[scan_maps[si_port], i] = pattern
tests[pi_map, i] = logic.mvarray(p.capture['_pi']) tests[pi_map, i] = logic.mvarray(p.capture['_pi'][0])
return tests return tests
def tests_loc(self, circuit, init_filter=None, launch_filter=None): def tests_loc(self, circuit, init_filter=None, launch_filter=None):
@@ -134,12 +132,12 @@ class StilFile:
for i, p in enumerate(self.patterns): for i, p in enumerate(self.patterns):
# init.set_values(i, '0' * len(interface)) # init.set_values(i, '0' * len(interface))
for si_port in self.si_ports.keys(): for si_port in self.si_ports.keys():
pattern = logic.mvarray(p.load[si_port]) pattern = logic.mvarray(p.load[si_port][0])
inversions = np.choose((pattern == logic.UNASSIGNED) | (pattern == logic.UNKNOWN), inversions = np.choose((pattern == logic.UNASSIGNED) | (pattern == logic.UNKNOWN),
[scan_inversions[si_port], logic.ZERO]).astype(np.uint8) [scan_inversions[si_port], logic.ZERO]).astype(np.uint8)
np.bitwise_xor(pattern, inversions, out=pattern) np.bitwise_xor(pattern, inversions, out=pattern)
init[scan_maps[si_port], i] = pattern init[scan_maps[si_port], i] = pattern
init[pi_map, i] = logic.mvarray(p.launch['_pi'] if '_pi' in p.launch else p.capture['_pi']) init[pi_map, i] = logic.mvarray(p.launch['_pi'][0] if '_pi' in p.launch else p.capture['_pi'][0])
if init_filter: init = init_filter(init) if init_filter: init = init_filter(init)
sim8v = LogicSim(circuit, init.shape[-1], m=8) sim8v = LogicSim(circuit, init.shape[-1], m=8)
sim8v.s[0] = logic.mv_to_bp(init) sim8v.s[0] = logic.mv_to_bp(init)
@@ -149,12 +147,12 @@ class StilFile:
launch = logic.bp_to_mv(sim8v.s[1])[..., :init.shape[-1]] launch = logic.bp_to_mv(sim8v.s[1])[..., :init.shape[-1]]
for i, p in enumerate(self.patterns): for i, p in enumerate(self.patterns):
# if there was no launch cycle or launch clock, then init = launch # 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(): 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 launch[scan_maps[si_port], i] = pattern
if '_pi' in p.capture and 'P' in p.capture['_pi']: if '_pi' in p.capture and 'P' in p.capture['_pi'][0]:
launch[pi_map, i] = logic.mvarray(p.capture['_pi']) launch[pi_map, i] = logic.mvarray(p.capture['_pi'][0])
launch[po_map, i] = logic.UNASSIGNED launch[po_map, i] = logic.UNASSIGNED
if launch_filter: launch = launch_filter(launch) if launch_filter: launch = launch_filter(launch)
@@ -171,9 +169,9 @@ class StilFile:
interface, _, po_map, scan_maps, scan_inversions = self._maps(circuit) interface, _, po_map, scan_maps, scan_inversions = self._maps(circuit)
resp = np.full((len(interface), len(self.patterns)), logic.UNASSIGNED) resp = np.full((len(interface), len(self.patterns)), logic.UNASSIGNED)
for i, p in enumerate(self.patterns): 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(): 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 resp[scan_maps[so_port], i] = pattern
return resp return resp
@@ -192,7 +190,7 @@ class StilTransformer(Transformer):
def call(args): return Call(args[0], dict(args[1:])) def call(args): return Call(args[0], dict(args[1:]))
@staticmethod @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 @staticmethod
def signal_group(args): return args[0], args[1:] def signal_group(args): return args[0], args[1:]
+76 -42
View File
@@ -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} ; FILLCELL_X{1,2,4,8,16,32} ;
ANTENNA_X1 input(A) ;
LOGIC0_X1 output(Z) Z=__const0__() ; LOGIC0_X1 output(Z) Z=__const0__() ;
LOGIC1_X1 output(Z) Z=__const1__() ; LOGIC1_X1 output(Z) Z=__const1__() ;
BUF_X{1,2,4,8,16,32} input(A) output(Z) Z=BUF1(A) ; 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) ; 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) ; 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) ; 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) ; 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) ; 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) ; 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) ; 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) ; 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) ; 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) ; 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) ; 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) ; 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) ; 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) ; 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) ; 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) ; 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) ; 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) ; 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) ; TINV_X1 input(I,EN) output(ZN) ZN=INV1(I) ;
TLAT_X1 input(D,G,OE) output(Q) Q=LATCH(D,G) ; 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) ; 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) ; 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 45nm Open Cell Library (NangateOpenCellLibrary_PDKv1_3_v2010_12).
""" This NANGATE-variant that uses 'ZN' 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.
""" """
+117 -20
View File
@@ -13,10 +13,11 @@ Two simulators are available: :py:class:`WaveSim` runs on the CPU, and the deriv
""" """
import math import math
from collections import defaultdict
import numpy as np import numpy as np
from . import numba, cuda, sim, cdiv from . import log, numba, cuda, sim, cdiv, eng
TMAX = np.float32(2 ** 127) TMAX = np.float32(2 ** 127)
@@ -59,8 +60,8 @@ class WaveSim(sim.SimOps):
self.delays = np.zeros((len(delays), self.c_locs_len, 2, 2), dtype=delays.dtype) self.delays = np.zeros((len(delays), self.c_locs_len, 2, 2), dtype=delays.dtype)
self.delays[:, :delays.shape[1]] = delays self.delays[:, :delays.shape[1]] = delays
self.c = np.zeros((self.c_len, sims), dtype=np.float32) + TMAX self.c = np.full((self.c_len, self.sims), TMAX, dtype=np.float32)
self.s = np.zeros((11, self.s_len, sims), dtype=np.float32) self.s = np.zeros((11, self.s_len, self.sims), dtype=np.float32)
"""Information about the logic values and transitions around the sequential elements (flip-flops) and ports. """Information about the logic values and transitions around the sequential elements (flip-flops) and ports.
The first 3 values are read by :py:func:`s_to_c`. The first 3 values are read by :py:func:`s_to_c`.
@@ -98,12 +99,31 @@ class WaveSim(sim.SimOps):
self.simctl_int[0] = range(sims) # unique seed for each sim by default, zero this to pick same delays for all sims. self.simctl_int[0] = range(sims) # unique seed for each sim by default, zero this to pick same delays for all sims.
self.simctl_int[1] = 2 # random picking by default. self.simctl_int[1] = 2 # random picking by default.
self.nbytes = sum([a.nbytes for a in (self.c, self.s, self.c_locs, self.c_caps, self.ops, self.simctl_int)]) # flat array for line use information
line_use = defaultdict(list)
for lidx in range(len(self.circuit.lines)):
if self.line_use_start[lidx] < 0: continue
if self.line_use_stop[lidx] < 0:
log.warn(f'line {lidx} never read?')
for i in range(self.line_use_start[lidx], self.line_use_stop[lidx]):
line_use[i].append(lidx)
self.line_use_counts = np.array([len(line_use[i]) for i in range(len(self.levels))], dtype=np.int32)
self.line_use_offsets = np.zeros_like(self.line_use_counts)
self.line_use_offsets[1:] = self.line_use_counts.cumsum()[:-1]
self.line_use = np.hstack([line_use[i] for i in range(len(self.levels))])
self.h = np.zeros((self.c_locs_len, sims), dtype=np.float32) # hashes of generated waveforms
self.h_base = np.zeros_like(self.h) # base hashes to compare to
self.error_counts = np.zeros(self.s_len, dtype=np.uint32) # number of capture errors by PPO
self.nbytes = sum([a.nbytes for a in (self.c, self.s, self.h, self.c_locs, self.c_caps, self.ops, self.simctl_int)])
def __repr__(self): def __repr__(self):
dev = 'GPU' if hasattr(self.c, 'copy_to_host') else 'CPU' 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)}, ' + \ 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): def s_to_c(self):
"""Transfers values of sequential elements and primary inputs to the combinational portion. """Transfers values of sequential elements and primary inputs to the combinational portion.
@@ -124,7 +144,7 @@ class WaveSim(sim.SimOps):
""" """
sims = min(sims or self.sims, self.sims) sims = min(sims or self.sims, self.sims)
for op_start, op_stop in zip(self.level_starts, self.level_stops): for op_start, op_stop in zip(self.level_starts, self.level_stops):
level_eval_cpu(self.ops, op_start, op_stop, self.c, self.c_locs, self.c_caps, self.abuf, 0, sims, self.delays, self.simctl_int, seed) level_eval_cpu(self.ops, op_start, op_stop, self.c, self.c_locs, self.c_caps, self.h, self.abuf, 0, sims, self.delays, self.simctl_int, seed)
def c_to_s(self, time=TMAX, sd=0.0, seed=1): def c_to_s(self, time=TMAX, sd=0.0, seed=1):
"""Simulates a capture operation at all sequential elements and primary outputs. """Simulates a capture operation at all sequential elements and primary outputs.
@@ -152,7 +172,7 @@ class WaveSim(sim.SimOps):
self.s[2, self.ppio_s_locs] = self.s[8, self.ppio_s_locs] self.s[2, self.ppio_s_locs] = self.s[8, self.ppio_s_locs]
def _wave_eval(op, cbuf, c_locs, c_caps, sim, delays, simctl_int, seed=0): def _wave_eval(op, cbuf, c_locs, c_caps, hbuf, sim, delays, simctl_int, seed):
overflows = int(0) overflows = int(0)
lut = op[0] lut = op[0]
@@ -182,6 +202,8 @@ def _wave_eval(op, cbuf, c_locs, c_caps, sim, delays, simctl_int, seed=0):
z_mem = c_locs[z_idx] z_mem = c_locs[z_idx]
z_cap = c_caps[z_idx] z_cap = c_caps[z_idx]
h = np.float32(0)
a_cur = int(0) a_cur = int(0)
b_cur = int(0) b_cur = int(0)
c_cur = int(0) c_cur = int(0)
@@ -206,29 +228,30 @@ def _wave_eval(op, cbuf, c_locs, c_caps, sim, delays, simctl_int, seed=0):
if a == current_t: if a == current_t:
a_cur += 1 a_cur += 1
inputs ^= 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] 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] next_t = cbuf[a_mem + a_cur, sim] + delays[a_idx, (a_cur & 1) ^ 1, z_val ^ 1]
elif b == current_t: elif b == current_t:
b_cur += 1 b_cur += 1
inputs ^= 2 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] 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] next_t = cbuf[b_mem + b_cur, sim] + delays[b_idx, (b_cur & 1) ^ 1, z_val ^ 1]
elif c == current_t: elif c == current_t:
c_cur += 1 c_cur += 1
inputs ^= 4 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] 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] next_t = cbuf[c_mem + c_cur, sim] + delays[c_idx, (c_cur & 1) ^ 1, z_val ^ 1]
else: else:
d_cur += 1 d_cur += 1
inputs ^= 8 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] 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] next_t = cbuf[d_mem + d_cur, sim] + delays[d_idx, (d_cur & 1) ^ 1, z_val ^ 1]
if (z_cur & 1) != ((lut >> inputs) & 1): if (z_cur & 1) != ((lut >> inputs) & 1):
h += h*3 + max(current_t, -10) # hash based on generated transitions before filtering
# we generate an edge in z_mem, if ... # we generate an edge in z_mem, if ...
if (z_cur == 0 # it is the first edge in z_mem ... if (z_cur == 0 # it is the first edge in z_mem ...
or next_t < current_t # -OR- the next edge on SAME input is EARLIER (need current edge to filter BOTH in next iteration) ... or next_t < current_t # -OR- the next edge on SAME input is EARLIER (need current edge to filter BOTH in next iteration) ...
@@ -240,8 +263,8 @@ def _wave_eval(op, cbuf, c_locs, c_caps, sim, delays, simctl_int, seed=0):
z_cur += 1 z_cur += 1
else: else:
overflows += 1 overflows += 1
previous_t = cbuf[z_mem + z_cur - 1, sim]
z_cur -= 1 z_cur -= 1
previous_t = cbuf[z_mem + z_cur, sim]
else: else:
z_cur -= 1 z_cur -= 1
previous_t = cbuf[z_mem + z_cur - 1, sim] if z_cur > 0 else TMIN previous_t = cbuf[z_mem + z_cur - 1, sim] if z_cur > 0 else TMIN
@@ -258,6 +281,8 @@ def _wave_eval(op, cbuf, c_locs, c_caps, sim, delays, simctl_int, seed=0):
# generate or propagate overflow flag # generate or propagate overflow flag
cbuf[z_mem + z_cur, sim] = TMAX_OVL if overflows > 0 else max(a, b, c, d) cbuf[z_mem + z_cur, sim] = TMAX_OVL if overflows > 0 else max(a, b, c, d)
hbuf[z_idx, sim] = h
nrise = max(0, (z_cur+1) // 2 - (cbuf[z_mem, sim] == TMIN)) nrise = max(0, (z_cur+1) // 2 - (cbuf[z_mem, sim] == TMIN))
nfall = z_cur // 2 nfall = z_cur // 2
@@ -268,11 +293,11 @@ wave_eval_cpu = numba.njit(_wave_eval)
@numba.njit @numba.njit
def level_eval_cpu(ops, op_start, op_stop, c, c_locs, c_caps, abuf, sim_start, sim_stop, delays, simctl_int, seed): def level_eval_cpu(ops, op_start, op_stop, c, c_locs, c_caps, hbuf, abuf, sim_start, sim_stop, delays, simctl_int, seed):
for op_idx in range(op_start, op_stop): for op_idx in range(op_start, op_stop):
op = ops[op_idx] op = ops[op_idx]
for sim in range(sim_start, sim_stop): for sim in range(sim_start, sim_stop):
nrise, nfall = wave_eval_cpu(op, c, c_locs, c_caps, sim, delays, simctl_int[:, sim], seed) nrise, nfall = wave_eval_cpu(op, c, c_locs, c_caps, hbuf, sim, delays, simctl_int[:, sim], seed)
a_loc = op[6] a_loc = op[6]
a_wr = op[7] a_wr = op[7]
a_wf = op[8] a_wf = op[8]
@@ -345,12 +370,18 @@ class WaveSimCuda(WaveSim):
self.delays = cuda.to_device(self.delays) self.delays = cuda.to_device(self.delays)
self.simctl_int = cuda.to_device(self.simctl_int) self.simctl_int = cuda.to_device(self.simctl_int)
self.abuf = cuda.to_device(self.abuf) self.abuf = cuda.to_device(self.abuf)
self.h = cuda.to_device(self.h)
self.h_base = cuda.to_device(self.h_base)
self.line_use = cuda.to_device(self.line_use)
self.error_counts = cuda.to_device(self.error_counts)
self.retval_int = cuda.to_device(np.array([0], dtype=np.int32))
self._block_dim = (32, 16) self._block_dim = (32, 16)
def __getstate__(self): def __getstate__(self):
state = self.__dict__.copy() state = self.__dict__.copy()
state['c'] = np.array(self.c) del state['c']
state['s'] = np.array(self.s) state['s'] = np.array(self.s)
state['ops'] = np.array(self.ops) state['ops'] = np.array(self.ops)
state['c_locs'] = np.array(self.c_locs) state['c_locs'] = np.array(self.c_locs)
@@ -358,11 +389,16 @@ class WaveSimCuda(WaveSim):
state['delays'] = np.array(self.delays) state['delays'] = np.array(self.delays)
state['simctl_int'] = np.array(self.simctl_int) state['simctl_int'] = np.array(self.simctl_int)
state['abuf'] = np.array(self.abuf) state['abuf'] = np.array(self.abuf)
state['h'] = np.array(self.h)
state['h_base'] = np.array(self.h_base)
state['line_use'] = np.array(self.line_use)
state['error_counts'] = np.array(self.error_counts)
state['retval_int'] = np.array(self.retval_int)
return state return state
def __setstate__(self, state): def __setstate__(self, state):
self.__dict__.update(state) self.__dict__.update(state)
self.c = cuda.to_device(self.c) self.c = cuda.to_device(np.full((self.c_len, self.sims), TMAX, dtype=np.float32))
self.s = cuda.to_device(self.s) self.s = cuda.to_device(self.s)
self.ops = cuda.to_device(self.ops) self.ops = cuda.to_device(self.ops)
self.c_locs = cuda.to_device(self.c_locs) self.c_locs = cuda.to_device(self.c_locs)
@@ -370,6 +406,11 @@ class WaveSimCuda(WaveSim):
self.delays = cuda.to_device(self.delays) self.delays = cuda.to_device(self.delays)
self.simctl_int = cuda.to_device(self.simctl_int) self.simctl_int = cuda.to_device(self.simctl_int)
self.abuf = cuda.to_device(self.abuf) self.abuf = cuda.to_device(self.abuf)
self.h = cuda.to_device(self.h)
self.h_base = cuda.to_device(self.h_base)
self.line_use = cuda.to_device(self.line_use)
self.error_counts = cuda.to_device(self.error_counts)
self.retval_int = cuda.to_device(self.retval_int)
def s_to_c(self): def s_to_c(self):
grid_dim = self._grid_dim(self.sims, self.s_len) grid_dim = self._grid_dim(self.sims, self.s_len)
@@ -377,14 +418,24 @@ class WaveSimCuda(WaveSim):
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(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) sims = min(sims or self.sims, self.sims)
for op_start, op_stop in zip(self.level_starts, self.level_stops): 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) 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), wave_eval_gpu[grid_dim, self._block_dim](self.ops, op_start, op_stop, self.c, self.c_locs, self.c_caps, self.h, self.abuf, int(0),
sims, self.delays, self.simctl_int, seed) sims, self.delays, self.simctl_int, seed)
cuda.synchronize() cuda.synchronize()
def c_prop_level(self, level, sims=None, seed=1):
sims = min(sims or self.sims, self.sims)
op_start = self.level_starts[level]
op_stop = self.level_stops[level]
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.h, self.abuf, int(0),
sims, self.delays, self.simctl_int, seed)
def c_to_s(self, time=TMAX, sd=0.0, seed=1): def c_to_s(self, time=TMAX, sd=0.0, seed=1):
grid_dim = self._grid_dim(self.sims, self.s_len) grid_dim = self._grid_dim(self.sims, self.s_len)
wave_capture_gpu[grid_dim, self._block_dim](self.c, self.s, self.c_locs, self.c_caps, self.ppo_offset, wave_capture_gpu[grid_dim, self._block_dim](self.c, self.s, self.c_locs, self.c_caps, self.ppo_offset,
@@ -394,6 +445,52 @@ class WaveSimCuda(WaveSim):
grid_dim = self._grid_dim(self.sims, self.s_len) grid_dim = self._grid_dim(self.sims, self.s_len)
ppo_to_ppi_gpu[grid_dim, self._block_dim](self.s, self.c_locs, time, self.ppi_offset, self.ppo_offset) ppo_to_ppi_gpu[grid_dim, self._block_dim](self.s, self.c_locs, time, self.ppi_offset, self.ppo_offset)
def set_base_hashes(self):
nitems = self.h_base.shape[0] * self.h_base.shape[1]
grid_dim = cdiv(nitems, 256)
memcpy_gpu[grid_dim, 256](self.h, self.h_base, nitems)
def compare_hashes_level(self, lv):
self.retval_int[0] = 0
grid_dim = self._grid_dim(self.sims, self.line_use_counts[lv])
diff_hash_gpu[grid_dim, self._block_dim](self.h, self.h_base, self.line_use, self.line_use_offsets[lv],
self.line_use_counts[lv], self.retval_int)
return self.retval_int[0]
def calc_error_counts(self, sims=None):
sims = min(sims or self.sims, self.sims)
grid_dim = cdiv(self.s_len, 256)
calc_error_counts_gpu[grid_dim, 256](self.s, sims, self.error_counts)
return np.array(self.error_counts)
@cuda.jit()
def memcpy_gpu (src, dst, nitems):
tid = cuda.grid(1)
stride = cuda.gridDim.x * cuda.blockDim.x
for i in range(tid, nitems, stride):
dst.flat[i] = src.flat[i]
@cuda.jit()
def diff_hash_gpu(hbuf1, hbuf2, h_locs, h_locs_offset, h_locs_cnt, differs):
x, y = cuda.grid(2)
if x >= hbuf1.shape[1]: return
if y >= h_locs_cnt: return
h_loc = h_locs[h_locs_offset+y]
if hbuf1[h_loc, x] != hbuf2[h_loc, x]:
differs[0] = 1
@cuda.jit()
def calc_error_counts_gpu(s, sims, error_counts):
x = cuda.grid(1)
if x >= s.shape[1]: return
cnt = 0
for i in range(sims):
cnt += (s[6,x,i] != s[8,x,i])
error_counts[x] = cnt
@cuda.jit() @cuda.jit()
def wave_assign_gpu(c, s, c_locs, ppi_offset): def wave_assign_gpu(c, s, c_locs, ppi_offset):
@@ -423,7 +520,7 @@ _wave_eval_gpu = cuda.jit(_wave_eval, device=True)
@cuda.jit() @cuda.jit()
def wave_eval_gpu(ops, op_start, op_stop, cbuf, c_locs, c_caps, abuf, sim_start, sim_stop, delays, simctl_int, seed): def wave_eval_gpu(ops, op_start, op_stop, cbuf, c_locs, c_caps, hbuf, abuf, sim_start, sim_stop, delays, simctl_int, seed):
x, y = cuda.grid(2) x, y = cuda.grid(2)
sim = sim_start + x sim = sim_start + x
op_idx = op_start + y op_idx = op_start + y
@@ -435,7 +532,7 @@ def wave_eval_gpu(ops, op_start, op_stop, cbuf, c_locs, c_caps, abuf, sim_start,
a_wr = op[7] a_wr = op[7]
a_wf = op[8] a_wf = op[8]
nrise, nfall = _wave_eval_gpu(op, cbuf, c_locs, c_caps, sim, delays, simctl_int[:, sim], seed) nrise, nfall = _wave_eval_gpu(op, cbuf, c_locs, c_caps, hbuf, sim, delays, simctl_int[:, sim], seed)
# accumulate WSA into abuf # accumulate WSA into abuf
if a_loc >= 0: if a_loc >= 0:
Binary file not shown.
+7
View File
@@ -13,6 +13,13 @@ def b15_2ig_circuit(mydir):
from kyupy.techlib import SAED32 from kyupy.techlib import SAED32
return verilog.load(mydir / 'b15_2ig.v.gz', branchforks=True, tlib=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') @pytest.fixture(scope='session')
def b15_2ig_delays(mydir, b15_2ig_circuit): def b15_2ig_delays(mydir, b15_2ig_circuit):
from kyupy import sdf from kyupy import sdf
+33 -6
View File
@@ -7,22 +7,49 @@
(TEMPERATURE 25.00:25.00:25.00) (TEMPERATURE 25.00:25.00:25.00)
(TIMESCALE 1ns) (TIMESCALE 1ns)
(CELL (CELL
(CELLTYPE "NAND2X1") (CELLTYPE "NAND2_X1")
(INSTANCE nandgate) (INSTANCE nandgate)
(DELAY (DELAY
(ABSOLUTE (ABSOLUTE
(IOPATH IN1 QN (0.099:0.103:0.103) (0.122:0.127:0.127)) (IOPATH A1 ZN (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 A2 ZN (0.083:0.086:0.086) (0.100:0.104:0.104))
) )
) )
) )
(CELL (CELL
(CELLTYPE "AND2X1") (CELLTYPE "AND2_X1")
(INSTANCE andgate) (INSTANCE andgate)
(DELAY (DELAY
(ABSOLUTE (ABSOLUTE
(IOPATH IN1 Q (0.367:0.378:0.378) (0.351:0.377:0.377)) (IOPATH A1 ZN (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 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
View File
@@ -1,11 +1,15 @@
module gates (a, b, o0, o1 ); module gates (a, b, c, o0, o1, o2, o3 );
input a; input a;
input b; input b;
input c;
output o0; output o0;
output o1; output o1;
output o2;
output o3;
AND2X1 andgate (.IN1 ( a ) , .IN2 ( b ) , .Q ( o0 ) ) ; AND2_X1 andgate (.A1 ( a ) , .A2 ( b ) , .ZN ( o0 ) ) ;
NAND2X1 nandgate (.IN1 ( a ) , .IN2 ( b ) , .QN ( o1 ) ) ; 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 endmodule
+22 -1
View File
@@ -1,9 +1,30 @@
import pickle import pickle
from kyupy.circuit import Circuit, Node, Line from kyupy.circuit import GrowingList, Circuit, Node, Line
from kyupy import verilog, bench from kyupy import verilog, bench
from kyupy.techlib import SAED32 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(): def test_lines():
c = Circuit() c = Circuit()
n1 = Node(c, 'n1') n1 = Node(c, 'n1')
+47
View File
@@ -173,3 +173,50 @@ def test_b01(mydir):
s.c_prop() s.c_prop()
s.c_to_s() s.c_to_s()
bp_to_mv(s.s[1]) 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
View File
@@ -2,7 +2,7 @@ import numpy as np
from kyupy import sdf, verilog, bench from kyupy import sdf, verilog, bench
from kyupy.wave_sim import WaveSim, TMAX, TMIN from kyupy.wave_sim import WaveSim, TMAX, TMIN
from kyupy.techlib import SAED32, SAED90 from kyupy.techlib import SAED32, NANGATE45
def test_parse(): def test_parse():
test = ''' test = '''
@@ -80,9 +80,9 @@ def test_b15(mydir):
def test_gates(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') 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_a = c.cells['nandgate'].ins[0]
nand_b = c.cells['nandgate'].ins[1] nand_b = c.cells['nandgate'].ins[1]
and_a = c.cells['andgate'].ins[0] and_a = c.cells['andgate'].ins[0]
+6 -6
View File
@@ -1,5 +1,5 @@
from kyupy import verilog from kyupy import verilog
from kyupy.techlib import SAED90, SAED32 from kyupy.techlib import SAED90, SAED32, NANGATE45
def test_b01(mydir): def test_b01(mydir):
with open(mydir / 'b01.v', 'r') as f: with open(mydir / 'b01.v', 'r') as f:
@@ -26,12 +26,12 @@ def test_b15(mydir):
def test_gates(mydir): def test_gates(mydir):
c = verilog.load(mydir / 'gates.v', tlib=SAED90) c = verilog.load(mydir / 'gates.v', tlib=NANGATE45)
assert len(c.nodes) == 10 assert len(c.nodes) == 18
assert len(c.lines) == 10 assert len(c.lines) == 21
stats = c.stats stats = c.stats
assert stats['input'] == 2 assert stats['input'] == 3
assert stats['output'] == 2 assert stats['output'] == 4
assert stats['__seq__'] == 0 assert stats['__seq__'] == 0
+43 -9
View File
@@ -5,12 +5,46 @@ from kyupy.logic_sim import LogicSim
from kyupy import logic, bench, sim from kyupy import logic, bench, sim
from kyupy.logic import mvarray 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, dtype=np.float32) # 4 waveforms of capacity 16
c_locs = np.zeros((4,), dtype='int')
c_caps = np.zeros((4,), dtype='int')
h = np.zeros((4, 1), dtype=np.float32)
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, h, 0, delays, simctl_int, 0)
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(): def test_nand_delays():
op = (sim.NAND4, 4, 0, 1, 2, 3, -1, 0, 0) op = (sim.NAND4, 4, 0, 1, 2, 3, -1, 0, 0)
#op = (0b0111, 4, 0, 1) #op = (0b0111, 4, 0, 1)
c = np.full((5*16, 1), TMAX) # 5 waveforms of capacity 16 c = np.full((5*16, 1), TMAX, dtype=np.float32) # 5 waveforms of capacity 16
c_locs = np.zeros((5,), dtype='int') c_locs = np.zeros((5,), dtype='int')
c_caps = np.zeros((5,), dtype='int') c_caps = np.zeros((5,), dtype='int')
h = np.zeros((5, 1), dtype=np.float32)
for i in range(5): c_locs[i], c_caps[i] = i*16, 16 # 1:1 mapping for i in range(5): c_locs[i], c_caps[i] = i*16, 16 # 1:1 mapping
@@ -32,7 +66,7 @@ def test_nand_delays():
def wave_assert(inputs, output): def wave_assert(inputs, output):
for i, a in zip(inputs, c.reshape(-1,16)): a[:len(i)] = i 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) wave_eval_cpu(op, c, c_locs, c_caps, h, 0, delays, simctl_int, 0)
for i, v in enumerate(output): np.testing.assert_allclose(c.reshape(-1,16)[4,i], v) for i, v in enumerate(output): np.testing.assert_allclose(c.reshape(-1,16)[4,i], v)
wave_assert([[TMAX,TMAX],[TMAX,TMAX],[TMIN,TMAX],[TMIN,TMAX]], [TMIN,TMAX]) # NAND(0,0,1,1) => 1 wave_assert([[TMAX,TMAX],[TMAX,TMAX],[TMIN,TMAX],[TMIN,TMAX]], [TMIN,TMAX]) # NAND(0,0,1,1) => 1
@@ -145,7 +179,7 @@ def compare_to_logic_sim(wsim: WaveSim):
lsim.s_to_c() lsim.s_to_c()
lsim.c_prop() lsim.c_prop()
lsim.c_to_s() 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.PPULSE] = logic.ZERO
resp[resp == logic.NPULSE] = logic.ONE resp[resp == logic.NPULSE] = logic.ONE
@@ -156,13 +190,13 @@ def compare_to_logic_sim(wsim: WaveSim):
np.testing.assert_allclose(resp, exp) np.testing.assert_allclose(resp, exp)
def test_b15(b15_2ig_circuit, b15_2ig_delays): def test_b15(b15_2ig_circuit_resolved, b15_2ig_delays):
compare_to_logic_sim(WaveSim(b15_2ig_circuit, b15_2ig_delays, 8)) compare_to_logic_sim(WaveSim(b15_2ig_circuit_resolved, b15_2ig_delays, 8))
def test_b15_strip_forks(b15_2ig_circuit, b15_2ig_delays): def test_b15_strip_forks(b15_2ig_circuit_resolved, b15_2ig_delays):
compare_to_logic_sim(WaveSim(b15_2ig_circuit, b15_2ig_delays, 8, strip_forks=True)) 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): def test_b15_cuda(b15_2ig_circuit_resolved, b15_2ig_delays):
compare_to_logic_sim(WaveSimCuda(b15_2ig_circuit, b15_2ig_delays, 8, strip_forks=True)) compare_to_logic_sim(WaveSimCuda(b15_2ig_circuit_resolved, b15_2ig_delays, 8, strip_forks=True))