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
14 changed files with 238 additions and 511 deletions

No files matched your search

-5
View File
@@ -4,17 +4,12 @@ build:
os: "ubuntu-20.04" os: "ubuntu-20.04"
tools: tools:
python: "3.8" python: "3.8"
jobs:
post_create_environment:
- python -m pip install sphinx_rtd_theme
sphinx: sphinx:
fail_on_warning: true fail_on_warning: true
configuration: docs/conf.py
python: python:
# Install our python package before building the docs # Install our python package before building the docs
install: install:
- method: pip - method: pip
path: . path: .
-32
View File
@@ -1,32 +0,0 @@
[project]
name = "kyupy"
version = "0.0.5"
authors = [
{ name="Stefan Holst", email="mail@s-holst.de" },
]
description = 'High-performance processing and analysis of non-hierarchical VLSI designs'
readme = "README.rst"
requires_python = ">=3.8"
dependencies = [
"numpy>=1.17.0",
"lark-parser>=0.8.0",
]
classifiers = [
"Development Status :: 3 - Alpha",
"Environment :: GPU :: NVIDIA CUDA",
"Intended Audience :: Science/Research",
"Topic :: Scientific/Engineering :: Electronic Design Automation (EDA)",
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
"Programming Language :: Python :: 3",
]
license = "MIT"
license-files = ["LICENSE.txt"]
[project.urls]
homepage = "https://github.com/s-holst/kyupy"
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
+40
View File
@@ -0,0 +1,40 @@
from setuptools import setup, find_packages
with open('README.rst', 'r') as f:
long_description = f.read()
setup(
name='kyupy',
version='0.0.5',
description='High-performance processing and analysis of non-hierarchical VLSI designs',
long_description=long_description,
long_description_content_type='text/x-rst',
packages=find_packages(where='src'),
package_dir={'': 'src'},
url='https://github.com/s-holst/kyupy',
author='Stefan Holst',
author_email='mail@s-holst.de',
python_requires='>=3.8',
install_requires=[
'numpy>=1.17.0',
'lark-parser>=0.8.0'
],
extras_requires={
'dev': [
'pytest>=6.1',
],
},
classifiers=[
'Development Status :: 3 - Alpha',
'Environment :: GPU :: NVIDIA CUDA',
'Intended Audience :: Science/Research',
'Topic :: Scientific/Engineering :: Electronic Design Automation (EDA)',
'License :: OSI Approved :: MIT License',
'Operating System :: OS Independent',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3 :: Only',
'Programming Language :: Python :: 3.8',
'Programming Language :: Python :: 3.9',
'Programming Language :: Python :: 3.10',
],
)
+1 -1
View File
@@ -183,7 +183,7 @@ class Log:
return return
t = time.perf_counter() - self.start t = time.perf_counter() - self.start
self.logfile.write(f'# {t:011.3f} {level} {message}\n') self.logfile.write(f'# {t:011.3f} {level} {message}\n')
#self.logfile.flush() self.logfile.flush()
self._limit -= 1 self._limit -= 1
def info(self, message): def info(self, message):
+3 -23
View File
@@ -40,11 +40,6 @@ class GrowingList(list):
self.has_nones = fi < len(self) self.has_nones = fi < len(self)
return fi return fi
def without_nones(self):
for item in self:
if item is not None:
yield item
class IndexList(list): class IndexList(list):
def __delitem__(self, index): def __delitem__(self, index):
@@ -96,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[Line] = 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[Line] = GrowingList() self.outs: list[Line] = GrowingList()
"""A list of output connections (:class:`Line` objects). """A list of output connections (:class:`Line` objects).
""" """
@@ -312,7 +307,7 @@ class Circuit:
def _locs(self, prefix, nodes): def _locs(self, prefix, nodes):
d_top = dict() d_top = dict()
for i, n in enumerate(nodes): for i, n in enumerate(nodes):
if m := re.match(fr'({re.escape(prefix)}.*?)((?:[\d_\[\]])*$)', n.name): if m := re.match(fr'({prefix}.*?)((?:[\d_\[\]])*$)', n.name):
path = [m[1]] + [int(v) for v in re.split(r'[_\[\]]+', m[2]) if len(v) > 0] path = [m[1]] + [int(v) for v in re.split(r'[_\[\]]+', m[2]) if len(v) > 0]
d = d_top d = d_top
for j in path[:-1]: for j in path[:-1]:
@@ -615,21 +610,6 @@ class Circuit:
if marks[n]: if marks[n]:
yield n yield n
def fanout(self, origin_nodes):
"""Generator function to iterate over the fan-out cone of a given list of origin nodes.
Nodes are yielded in topological order.
"""
marks = [False] * len(self.nodes)
for n in origin_nodes:
marks[n] = True
for n in self.topological_order():
if not marks[n]:
for line in n.ins.without_nones():
marks[n] |= marks[line.driver]
if marks[n]:
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():
if len(stem.outs) == 1 and 'dff' not in stem.kind.lower(): continue if len(stem.outs) == 1 and 'dff' not in stem.kind.lower(): continue
-12
View File
@@ -269,18 +269,6 @@ def mv_to_bp(mva):
return np.packbits(unpackbits(mva)[...,:3], axis=-2, bitorder='little').swapaxes(-1,-2) return np.packbits(unpackbits(mva)[...,:3], axis=-2, bitorder='little').swapaxes(-1,-2)
def mv_init(mva):
"""Returns the initial binary values for mva.
"""
return (mva>>1) & ((mva>>2)|mva) & 1
def mv_final(mva):
"""Returns the final binary value of mva.
"""
return mva & ((mva>>2)|(mva>>1)) & 1
def bparray(*a): def bparray(*a):
"""Converts (lists of) Boolean values or strings into a bit-parallel array. """Converts (lists of) Boolean values or strings into a bit-parallel array.
+16 -150
View File
@@ -10,10 +10,9 @@ import math
import numpy as np import numpy as np
from . import numba, logic, hr_bytes, sim, eng, cdiv from . import numba, logic, hr_bytes, sim, eng
from .circuit import Circuit from .circuit import Circuit
class LogicSim(sim.SimOps): class LogicSim(sim.SimOps):
"""A bit-parallel naïve combinational simulator for 2-, 4-, or 8-valued logic. """A bit-parallel naïve combinational simulator for 2-, 4-, or 8-valued logic.
@@ -29,7 +28,7 @@ class LogicSim(sim.SimOps):
self.m = m self.m = m
self.mdim = math.ceil(math.log2(m)) self.mdim = math.ceil(math.log2(m))
self.sims = sims self.sims = sims
nbytes = cdiv(sims, 8) nbytes = (sims - 1) // 8 + 1
self.c = np.zeros((self.c_len, self.mdim, nbytes), dtype=np.uint8) self.c = np.zeros((self.c_len, self.mdim, nbytes), dtype=np.uint8)
self.s = np.zeros((2, self.s_len, 3, nbytes), dtype=np.uint8) self.s = np.zeros((2, self.s_len, 3, nbytes), dtype=np.uint8)
@@ -52,7 +51,7 @@ class LogicSim(sim.SimOps):
""" """
self.c[self.pippi_c_locs] = self.s[0, self.pippi_s_locs, :self.mdim] self.c[self.pippi_c_locs] = self.s[0, self.pippi_s_locs, :self.mdim]
def c_prop(self, sims=None, inject_cb=None, fault_line=-1, fault_mask=None, fault_model=2): def c_prop(self, inject_cb=None):
"""Propagate the input values through the combinational circuit towards the outputs. """Propagate the input values through the combinational circuit towards the outputs.
Performs all logic operations in topological order. Performs all logic operations in topological order.
@@ -68,17 +67,10 @@ class LogicSim(sim.SimOps):
t1 = self.c_locs[self.tmp2_idx] t1 = self.c_locs[self.tmp2_idx]
if self.m == 2: if self.m == 2:
if inject_cb is None: if inject_cb is None:
if fault_mask is None: _prop_cpu(self.ops, self.c_locs, self.c)
fault_mask = np.full(self.c.shape[-1], 255, dtype=np.uint8)
else: else:
if len(fault_mask) < self.c.shape[-1]: for op, o0, i0, i1, i2, i3 in self.ops[:,:6]:
fault_mask2 = np.full(self.c.shape[-1], 0, dtype=np.uint8) o0, i0, i1, i2, i3 = [self.c_locs[x] for x in (o0, i0, i1, i2, i3)]
fault_mask2[:len(fault_mask)] = fault_mask
fault_mask = fault_mask2
_prop_cpu(self.ops, self.c_locs, self.c, int(fault_line), fault_mask, int(fault_model))
else:
for op, o0l, i0l, i1l, i2l, i3l in self.ops[:,:6]:
o0, i0, i1, i2, i3 = [self.c_locs[x] for x in (o0l, i0l, i1l, i2l, i3l)]
if op == sim.BUF1: self.c[o0]=self.c[i0] if op == sim.BUF1: self.c[o0]=self.c[i0]
elif op == sim.INV1: self.c[o0] = ~self.c[i0] elif op == sim.INV1: self.c[o0] = ~self.c[i0]
elif op == sim.AND2: self.c[o0] = self.c[i0] & self.c[i1] elif op == sim.AND2: self.c[o0] = self.c[i0] & self.c[i1]
@@ -113,10 +105,10 @@ 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(o0l, self.c[o0]) inject_cb(o0, self.c[o0])
elif self.m == 4: elif self.m == 4:
for op, o0l, i0l, i1l, i2l, i3l 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 (o0l, i0l, i1l, i2l, i3l)] o0, i0, i1, i2, i3 = [self.c_locs[x] for x in (o0, i0, i1, i2, i3)]
if op == sim.BUF1: self.c[o0]=self.c[i0] if op == sim.BUF1: self.c[o0]=self.c[i0]
elif op == sim.INV1: logic.bp4v_not(self.c[o0], self.c[i0]) elif op == sim.INV1: logic.bp4v_not(self.c[o0], self.c[i0])
elif op == sim.AND2: logic.bp4v_and(self.c[o0], self.c[i0], self.c[i1]) elif op == sim.AND2: logic.bp4v_and(self.c[o0], self.c[i0], self.c[i1])
@@ -189,10 +181,10 @@ 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(o0l, self.c[o0]) if inject_cb is not None: inject_cb(o0, self.c[o0])
else: else:
for op, o0l, i0l, i1l, i2l, i3l 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 (o0l, i0l, i1l, i2l, i3l)] o0, i0, i1, i2, i3 = [self.c_locs[x] for x in (o0, i0, i1, i2, i3)]
if op == sim.BUF1: self.c[o0]=self.c[i0] if op == sim.BUF1: self.c[o0]=self.c[i0]
elif op == sim.INV1: logic.bp8v_not(self.c[o0], self.c[i0]) elif op == sim.INV1: logic.bp8v_not(self.c[o0], self.c[i0])
elif op == sim.AND2: logic.bp8v_and(self.c[o0], self.c[i0], self.c[i1]) elif op == sim.AND2: logic.bp8v_and(self.c[o0], self.c[i0], self.c[i1])
@@ -265,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(o0l, self.c[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]``.
@@ -305,9 +297,9 @@ class LogicSim(sim.SimOps):
@numba.njit @numba.njit
def _prop_cpu(ops, c_locs, c, fault_line, fault_mask, fault_model): def _prop_cpu(ops, c_locs, c):
for op, o0l, i0l, i1l, i2l, i3l in ops[:,:6]: for op, o0, i0, i1, i2, i3 in ops[:,:6]:
o0, i0, i1, i2, i3 = [c_locs[x] for x in (o0l, i0l, i1l, i2l, i3l)] o0, i0, i1, i2, i3 = [c_locs[x] for x in (o0, i0, i1, i2, i3)]
if op == sim.BUF1: c[o0]=c[i0] if op == sim.BUF1: c[o0]=c[i0]
elif op == sim.INV1: c[o0] = ~c[i0] elif op == sim.INV1: c[o0] = ~c[i0]
elif op == sim.AND2: c[o0] = c[i0] & c[i1] elif op == sim.AND2: c[o0] = c[i0] & c[i1]
@@ -342,129 +334,3 @@ def _prop_cpu(ops, c_locs, c, fault_line, fault_mask, fault_model):
elif op == sim.OAI211: c[o0] = ~((c[i0] | c[i1]) & c[i2] & c[i3]) elif op == sim.OAI211: c[o0] = ~((c[i0] | c[i1]) & c[i2] & c[i3])
elif op == sim.MUX21: c[o0] = (c[i0] & ~c[i2]) | (c[i1] & c[i2]) elif op == sim.MUX21: c[o0] = (c[i0] & ~c[i2]) | (c[i1] & c[i2])
else: print(f'unknown op {op}') else: print(f'unknown op {op}')
if fault_line >= 0 and o0l == fault_line:
#n = len(fault_mask)
if fault_model == 0:
c[o0] = c[o0] & ~fault_mask
elif fault_model == 1:
c[o0] = c[o0] | fault_mask
else:
c[o0] = c[o0] ^ fault_mask
class LogicSim6V(sim.SimOps):
"""A bit-parallel naïve combinational simulator for 6-valued logic.
:param circuit: The circuit to simulate.
:param sims: The number of parallel logic simulations to perform.
:param c_reuse: If True, intermediate signal values may get overwritten when not needed anymore to save memory.
:param strip_forks: If True, forks are not included in the simulation model to save memory and simulation time.
"""
def __init__(self, circuit: Circuit, sims: int = 8, c_reuse: bool = False, strip_forks: bool = False):
super().__init__(circuit, c_reuse=c_reuse, strip_forks=strip_forks)
self.sims = sims
nbytes = cdiv(sims, 8)
self.c = np.zeros((self.c_len, 3, nbytes), dtype=np.uint8)
self.s = np.zeros((2, self.s_len, self.sims), dtype=np.uint8)
"""Logic values of the sequential elements (flip-flops) and ports.
It is a pair of arrays in mv storage format:
* ``s[0]`` Assigned values. Simulator will read (P)PI value from here.
* ``s[1]`` Result values. Simulator will write (P)PO values here.
Access this array to assign new values to the (P)PIs or read values from the (P)POs.
"""
def __repr__(self):
return f'{{name: "{self.circuit.name}", sims: {self.sims}, c_bytes: {eng(self.c.nbytes)}}}'
def s_to_c(self):
"""Assigns the values from ``s[0]`` to the inputs of the combinational portion.
"""
self.c[self.pippi_c_locs] = logic.mv_to_bp(self.s[0, self.pippi_s_locs])
def c_prop(self):
c_prop_cpu(self.ops, self.c, self.c_locs, self.tmp_idx, self.tmp2_idx)
def c_to_s(self):
"""Captures the results of the combinational portion into ``s[1]``.
"""
self.s[1, self.poppo_s_locs] = logic.bp_to_mv(self.c[self.poppo_c_locs])[:,:self.sims]
@numba.njit
def c_prop_cpu(ops, c, c_locs, tmp_idx, tmp2_idx):
t0 = c[c_locs[tmp_idx]]
t1 = c[c_locs[tmp2_idx]]
inv_op = np.array([255, 255, 0], dtype=np.uint8)[np.newaxis, :, np.newaxis]
for op, o0l, i0l, i1l, i2l, i3l in ops[:,:6]:
o0, i0, i1, i2, i3 = [c[c_locs[x]] for x in (o0l, i0l, i1l, i2l, i3l)]
if op == sim.BUF1 or op == sim.INV1:
o0[...] = i0
elif op == sim.AND2 or op == sim.NAND2:
o0[0] = i0[0] & i1[0]
o0[1] = i0[1] & i1[1]
o0[2] = (i0[2]&(i1[0]|i1[1]|i1[2])|
i1[2]&(i0[0]|i0[1]|i0[2]))
elif op == sim.AND3 or op == sim.NAND3:
o0[0] = i0[0] & i1[0] & i2[0]
o0[1] = i0[1] & i1[1] & i2[1]
o0[2] = (i0[2]&(i1[0]|i1[1]|i1[2])&(i2[0]|i2[1]|i2[2])|
i1[2]&(i0[0]|i0[1]|i0[2])&(i2[0]|i2[1]|i2[2])|
i2[2]&(i0[0]|i0[1]|i0[2])&(i1[0]|i1[1]|i1[2]))
elif op == sim.AND4 or op == sim.NAND4:
o0[0] = i0[0] & i1[0] & i2[0] & i3[0]
o0[1] = i0[1] & i1[1] & i2[1] & i3[1]
o0[2] = (i0[2]&(i1[0]|i1[1]|i1[2])&(i2[0]|i2[1]|i2[2])&(i3[0]|i3[1]|i3[2])|
i1[2]&(i0[0]|i0[1]|i0[2])&(i2[0]|i2[1]|i2[2])&(i3[0]|i3[1]|i3[2])|
i2[2]&(i0[0]|i0[1]|i0[2])&(i1[0]|i1[1]|i1[2])&(i3[0]|i3[1]|i3[2])|
i3[2]&(i0[0]|i0[1]|i0[2])&(i1[0]|i1[1]|i1[2])&(i2[0]|i2[1]|i2[2]))
elif op == sim.OR2 or op == sim.NOR2:
o0[0] = i0[0] | i1[0]
o0[1] = i0[1] | i1[1]
o0[2] = (i0[2]&(~i1[0]|~i1[1]|i1[2])|
i1[2]&(~i0[0]|~i0[1]|i0[2]))
elif op == sim.OR3 or op == sim.NOR3:
o0[0] = i0[0] | i1[0] | i2[0]
o0[1] = i0[1] | i1[1] | i2[1]
o0[2] = (i0[2]&(~i1[0]|~i1[1]|i1[2])&(~i2[0]|~i2[1]|i2[2])|
i1[2]&(~i0[0]|~i0[1]|i0[2])&(~i2[0]|~i2[1]|i2[2])|
i2[2]&(~i0[0]|~i0[1]|i0[2])&(~i1[0]|~i1[1]|i1[2]))
elif op == sim.OR4 or op == sim.NOR4:
o0[0] = i0[0] | i1[0] | i2[0] | i3[0]
o0[1] = i0[1] | i1[1] | i2[1] | i3[1]
o0[2] = (i0[2]&(~i1[0]|~i1[1]|i1[2])&(~i2[0]|~i2[1]|i2[2])&(~i3[0]|~i3[1]|i3[2])|
i1[2]&(~i0[0]|~i0[1]|i0[2])&(~i2[0]|~i2[1]|i2[2])&(~i3[0]|~i3[1]|i3[2])|
i2[2]&(~i0[0]|~i0[1]|i0[2])&(~i1[0]|~i1[1]|i1[2])&(~i3[0]|~i3[1]|i3[2])|
i3[2]&(~i0[0]|~i0[1]|i0[2])&(~i1[0]|~i1[1]|i1[2])&(~i2[0]|~i2[1]|i2[2]))
elif op == sim.XOR2 or op == sim.XNOR2:
o0[0] = i0[0] ^ i1[0]
o0[1] = i0[1] ^ i1[1]
o0[2] = i0[2] | i1[2]
elif op == sim.MUX21:
# t1 = ~i2
t1[...] = i2 ^ inv_op
# t0 = i0 & t1
t0[0] = i0[0] & t1[0]
t0[1] = i0[1] & t1[1]
t0[2] = (i0[2]&(t1[0]|t1[1]|t1[2])|
t1[2]&(i0[0]|i0[1]|i0[2]))
# t1 = i1 & i2
t1[0] = i1[0] & i2[0]
t1[1] = i1[1] & i2[1]
t1[2] = (i1[2]&(i2[0]|i2[1]|i2[2])|
i2[2]&(i1[0]|i1[1]|i1[2]))
# o0 = t0 | t1
o0[0] = t0[0] | t1[0]
o0[1] = t0[1] | t1[1]
o0[2] = (t0[2]&(~t1[0]|~t1[1]|t1[2])|
t1[2]&(~t0[0]|~t0[1]|t0[2]))
else: print(f'unknown op {op}')
if (op == sim.INV1 or
op == sim.NAND2 or op == sim.NAND3 or op == sim.NAND4 or
op == sim.NOR2 or op == sim.NOR3 or op == sim.NOR4 or
op == sim.XNOR2):
o0[...] = o0 ^ inv_op
+9 -18
View File
@@ -103,12 +103,11 @@ 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.
nonfork_annotations = 0
for n1, n2, *delvals in self._interconnects: for n1, n2, *delvals in self._interconnects:
delvals = [d if len(d) > 0 else [0, 0, 0] for d in delvals] delvals = [d if len(d) > 0 else [0, 0, 0] for d in delvals]
if max(max(delvals)) == 0: continue if max(max(delvals)) == 0: continue
cn1, pn1 = (n1, None) if (slash := n1.rfind('/')) < 0 else (n1[:slash], n1[slash+1:]) cn1, pn1 = n1.split('/') if '/' in n1 else (n1, None)
cn2, pn2 = (n2, None) if (slash := n2.rfind('/')) < 0 else (n2[:slash], n2[slash+1:]) cn2, pn2 = n2.split('/') if '/' in n2 else (n2, None)
cn1 = cn1.replace('\\','') cn1 = cn1.replace('\\','')
cn2 = cn2.replace('\\','') cn2 = cn2.replace('\\','')
c1, c2 = circuit.cells[cn1], circuit.cells[cn2] c1, c2 = circuit.cells[cn1], circuit.cells[cn2]
@@ -121,27 +120,19 @@ class DelayFile:
log.warn(f'No line to annotate pin {pn2} of {c2}') log.warn(f'No line to annotate pin {pn2} of {c2}')
continue continue
f1, f2 = c1.outs[p1].reader, c2.ins[p2].driver # find the forks between cells. f1, f2 = c1.outs[p1].reader, c2.ins[p2].driver # find the forks between cells.
if f1 == c2 and f2 == c1:
nonfork_annotations += 1
if nonfork_annotations < 10:
log.warn(f'No fork between {c1.name}/{p1} and {c2.name}/{p2}, using {c2.name}/{p2}')
line = c2.ins[p2]
else:
assert f1.kind == '__fork__' assert f1.kind == '__fork__'
assert f2.kind == '__fork__' assert f2.kind == '__fork__'
if len(f2.outs) == 1: if f1 != f2: # at least two forks, make sure f2 is a branchfork connected to f1
assert f1 == f2 or f1.outs[f2.ins[0].driver_pin] == f2.ins[0] assert len(f2.outs) == 1
assert f1.outs[f2.ins[0].driver_pin] == f2.ins[0]
line = f2.ins[0]
elif len(f2.outs) == 1: # f1==f2, only OK when there is no fanout.
line = f2.ins[0] line = f2.ins[0]
else: else:
nonfork_annotations += 1 log.warn(f'No branchfork to annotate interconnect delay {c1.name}/{p1}->{c2.name}/{p2}')
if nonfork_annotations < 10: continue
log.warn(f'No branchfork between {c1.name}/{p1} and {c2.name}/{p2}, using {c2.name}/{p2}')
line = c2.ins[p2]
delays[line, :] = delvals delays[line, :] = delvals
if nonfork_annotations > 0:
log.warn(f'{nonfork_annotations} interconnect annotations were moved to gate inputs due to missing forks.')
return np.moveaxis(delays, -1, 0) return np.moveaxis(delays, -1, 0)
+44 -8
View File
@@ -11,6 +11,50 @@ from itertools import product
from . import bench from . import bench
class TechLibOld:
@staticmethod
def pin_index(kind, pin):
if isinstance(pin, int):
return max(0, pin-1)
if kind[:3] in ('OAI', 'AOI'):
if pin[0] == 'A': return int(pin[1]) - 1
if pin == 'B': return int(kind[3])
if pin[0] == 'B': return int(pin[1]) - 1 + int(kind[3])
for prefix, pins, index in [('HADD', ('B0', 'SO'), 1),
('HADD', ('A0', 'C1'), 0),
('MUX21', ('S', 'S0'), 2),
('MX2', ('S0',), 2),
('TBUF', ('OE',), 1),
('TINV', ('OE',), 1),
('LATCH', ('D',), 0),
('LATCH', ('QN',), 1),
('DFF', ('D',), 0),
('DFF', ('QN',), 1),
('SDFF', ('D',), 0),
('SDFF', ('QN',), 1),
('SDFF', ('CLK',), 3),
('SDFF', ('RSTB', 'RN'), 4),
('SDFF', ('SETB',), 5),
('ISOL', ('ISO',), 0),
('ISOL', ('D',), 1)]:
if kind.startswith(prefix) and pin in pins: return index
for index, pins in enumerate([('A1', 'IN1', 'A', 'S', 'INP', 'I', 'Q', 'QN', 'Y', 'Z', 'ZN'),
('A2', 'IN2', 'B', 'CK', 'CLK', 'CO', 'SE'),
('A3', 'IN3', 'C', 'RN', 'RSTB', 'CI', 'SI'),
('A4', 'IN4', 'D', 'SN', 'SETB'),
('A5', 'IN5', 'E'),
('A6', 'IN6', 'F')]):
if pin in pins: return index
raise ValueError(f'Unknown pin index for {kind}.{pin}')
@staticmethod
def pin_is_output(kind, pin):
if isinstance(pin, int):
return pin == 0
if 'MUX' in kind and pin == 'S': return False
return pin in ('Q', 'QN', 'Z', 'ZN', 'Y', 'CO', 'S', 'SO', 'C1')
class TechLib: class TechLib:
"""Class for standard cell library definitions. """Class for standard cell library definitions.
@@ -49,14 +93,6 @@ class TechLib:
assert pin in self.cells[kind][1], f'Unknown pin: {pin} for cell {kind}' assert pin in self.cells[kind][1], f'Unknown pin: {pin} for cell {kind}'
return self.cells[kind][1][pin][0] return self.cells[kind][1][pin][0]
def pin_name(self, kind, pos, output=False):
"""Returns the pin name for a given node kind, list position, and direction."""
assert kind in self.cells, f'Unknown cell: {kind}'
for name, (ppos, isout) in self.cells[kind][1].items():
if isout == output and ppos == pos:
return name
return None
def pin_is_output(self, kind, pin): def pin_is_output(self, kind, pin):
"""Returns True, if given pin name of a node kind is an output.""" """Returns True, if given pin name of a node kind is an output."""
assert kind in self.cells, f'Unknown cell: {kind}' assert kind in self.cells, f'Unknown cell: {kind}'
+4 -31
View File
@@ -73,7 +73,7 @@ class VerilogTransformer(Transformer):
elif "'" in args[0]: elif "'" in args[0]:
width, rest = args[0].split("'") width, rest = args[0].split("'")
width = int(width) width = int(width)
base, const = rest[0], rest[1:].replace('x','0') base, const = rest[0], rest[1:]
const = int(const, {'b': 2, 'd':10, 'h':16}[base.lower()]) const = int(const, {'b': 2, 'd':10, 'h':16}[base.lower()])
l = [] l = []
for _ in range(width): for _ in range(width):
@@ -92,14 +92,6 @@ class VerilogTransformer(Transformer):
sigs.append(a) sigs.append(a)
return sigs return sigs
def ternaryif(self, args):
sel = args[0]
ctrue = args[1]
cfalse = args[2]
print(f"got ternary if {args[0]} {args[1]}")
return args[1]
def declaration(self, kind, args): def declaration(self, kind, args):
rnge = None rnge = None
if isinstance(args[0], range): if isinstance(args[0], range):
@@ -131,9 +123,6 @@ class VerilogTransformer(Transformer):
assignments = [] assignments = []
for stmt in args[2:]: # pass 1: instantiate cells and driven signals for stmt in args[2:]: # pass 1: instantiate cells and driven signals
if isinstance(stmt, Instantiation): if isinstance(stmt, Instantiation):
if stmt.type not in self.tlib.cells:
log.warn(f'Ignoring cell of unknown kind "{stmt.type}"')
continue
n = Node(c, stmt.name, kind=stmt.type) n = Node(c, stmt.name, kind=stmt.type)
for p, s in stmt.pins.items(): for p, s in stmt.pins.items():
if self.tlib.pin_is_output(n.kind, p): if self.tlib.pin_is_output(n.kind, p):
@@ -152,10 +141,6 @@ class VerilogTransformer(Transformer):
c.io_nodes[positions[name]] = n c.io_nodes[positions[name]] = n
if sd.kind == 'input': if sd.kind == 'input':
Line(c, n, Node(c, name)) Line(c, n, Node(c, name))
deferred_assignments = set()
ignored = 0
while len(assignments) > 0:
more_assignments = []
for target, source in assignments: # pass 1.5: process signal assignments for target, source in assignments: # pass 1.5: process signal assignments
target_sigs = [] target_sigs = []
if not isinstance(target, list): target = [target] if not isinstance(target, list): target = [target]
@@ -173,7 +158,7 @@ class VerilogTransformer(Transformer):
source_sigs.append(s) source_sigs.append(s)
for t, s in zip(target_sigs, source_sigs): for t, s in zip(target_sigs, source_sigs):
if t in c.forks: if t in c.forks:
assert s not in c.forks, f'assignment between two driven signals: source={s} target={t}' assert s not in c.forks, 'assignment between two driven signals'
Line(c, c.forks[t], Node(c, s)) Line(c, c.forks[t], Node(c, s))
elif s in c.forks: elif s in c.forks:
assert t not in c.forks, 'assignment between two driven signals' assert t not in c.forks, 'assignment between two driven signals'
@@ -182,20 +167,9 @@ class VerilogTransformer(Transformer):
cnode = Node(c, f'__const{s[3]}_{const_count}__', f'__const{s[3]}__') cnode = Node(c, f'__const{s[3]}_{const_count}__', f'__const{s[3]}__')
const_count += 1 const_count += 1
Line(c, cnode, Node(c, t)) Line(c, cnode, Node(c, t))
else:
if (t, s) in deferred_assignments:
#log.info(f'ignoring: assign {t} = {s}')
ignored += 1
else:
more_assignments.append((t, s))
deferred_assignments.add((t, s))
assignments = more_assignments
if ignored > 0:
log.warn(f'ignored {ignored} assignments')
for stmt in args[2:]: # pass 2: connect signals to readers for stmt in args[2:]: # pass 2: connect signals to readers
if isinstance(stmt, Instantiation): if isinstance(stmt, Instantiation):
for p, s in stmt.pins.items(): for p, s in stmt.pins.items():
if stmt.name not in c.cells: continue
n = c.cells[stmt.name] n = c.cells[stmt.name]
if self.tlib.pin_is_output(n.kind, p): continue if self.tlib.pin_is_output(n.kind, p): continue
if s.startswith("1'b"): if s.startswith("1'b"):
@@ -247,11 +221,10 @@ GRAMMAR = r"""
pin: namedpin | sigsel pin: namedpin | sigsel
namedpin: "." name "(" sigsel? ")" namedpin: "." name "(" sigsel? ")"
range: "[" /[0-9]+/ (":" /[0-9]+/)? "]" range: "[" /[0-9]+/ (":" /[0-9]+/)? "]"
sigsel: name range? | concat | ternaryif sigsel: name range? | concat
concat: "{" sigsel ( "," sigsel )* "}" concat: "{" sigsel ( "," sigsel )* "}"
ternaryif: sigsel "?" sigsel ":" sigsel
_namelist: name ( "," name )* _namelist: name ( "," name )*
name: ( /[a-z_][a-z0-9_]*/i | /\\[^\t \r\n]+[\t \r\n]/i | /[0-9]+'[bdh][x0-9a-f]+/i ) name: ( /[a-z_][a-z0-9_]*/i | /\\[^\t \r\n]+[\t \r\n]/i | /[0-9]+'[bdh][0-9a-f]+/i )
%import common.NEWLINE %import common.NEWLINE
COMMENT: /\/\*(\*(?!\/)|[^*])*\*\// | /\(\*(\*(?!\))|[^*])*\*\)/ | "//" /(.)*/ NEWLINE COMMENT: /\/\*(\*(?!\/)|[^*])*\*\// | /\(\*(\*(?!\))|[^*])*\*\)/ | "//" /(.)*/ NEWLINE
%ignore ( /\r?\n/ | COMMENT )+ %ignore ( /\r?\n/ | COMMENT )+
+91 -134
View File
@@ -99,19 +99,26 @@ 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.simctl_float = np.zeros((1, sims), dtype=np.float32) + 1 # flat array for line use information
"""Float array for per-simulation delay configuration. 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)
* ``simctl_float[0]`` factor to be multiplied with each delay (default=1.0). 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.e = np.zeros((self.c_locs_len, sims, 2), dtype=np.uint8) # aux data for each line and sim 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.error_counts = np.zeros(self.s_len, dtype=np.uint32) # number of capture errors by PPO
self.lsts = np.zeros(self.s_len, dtype=np.float32) # LST by PPO
self.overflows = np.zeros(self.s_len, dtype=np.uint32) # Overflows by PPO
self.nbytes = sum([a.nbytes for a in (self.c, self.s, self.e, self.c_locs, self.c_caps, self.ops, self.simctl_int, self.simctl_float)]) 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'
@@ -129,7 +136,7 @@ class WaveSim(sim.SimOps):
self.c[self.pippi_c_locs+1] = np.choose(cond, [TMAX, TMAX, sins[1], TMAX]) self.c[self.pippi_c_locs+1] = np.choose(cond, [TMAX, TMAX, sins[1], TMAX])
self.c[self.pippi_c_locs+2] = TMAX self.c[self.pippi_c_locs+2] = TMAX
def c_prop(self, sims=None, seed=1, delta=0): def c_prop(self, sims=None, seed=1):
"""Propagates all waveforms from the (pseudo) primary inputs to the (pseudo) primary outputs. """Propagates all waveforms from the (pseudo) primary inputs to the (pseudo) primary outputs.
:param sims: Number of parallel simulations to execute. If None, all available simulations are performed. :param sims: Number of parallel simulations to execute. If None, all available simulations are performed.
@@ -137,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.e, self.abuf, 0, sims, self.delays, self.simctl_int, self.simctl_float, seed, delta) 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.
@@ -165,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, ebuf, sim, delays, simctl_int, simctl_float, seed, delta): 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]
@@ -175,18 +182,6 @@ def _wave_eval(op, cbuf, c_locs, c_caps, ebuf, sim, delays, simctl_int, simctl_f
c_idx = op[4] c_idx = op[4]
d_idx = op[5] d_idx = op[5]
input_epoch = (ebuf[a_idx, sim, 1]|
ebuf[b_idx, sim, 1]|
ebuf[c_idx, sim, 1]|
ebuf[d_idx, sim, 1])
output_epoch = ebuf[z_idx, sim, 1]
if (delta):
if input_epoch == 0 and output_epoch == 0: return 0, 0
#out_changed = output_epoch
if len(delays) > 1: if len(delays) > 1:
if simctl_int[1] == 0: if simctl_int[1] == 0:
delays = delays[seed] delays = delays[seed]
@@ -200,8 +195,6 @@ def _wave_eval(op, cbuf, c_locs, c_caps, ebuf, sim, delays, simctl_int, simctl_f
else: else:
delays = delays[0] delays = delays[0]
a_mem = c_locs[a_idx] a_mem = c_locs[a_idx]
b_mem = c_locs[b_idx] b_mem = c_locs[b_idx]
c_mem = c_locs[c_idx] c_mem = c_locs[c_idx]
@@ -209,6 +202,8 @@ def _wave_eval(op, cbuf, c_locs, c_caps, ebuf, sim, delays, simctl_int, simctl_f
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)
@@ -219,10 +214,10 @@ def _wave_eval(op, cbuf, c_locs, c_caps, ebuf, sim, delays, simctl_int, simctl_f
z_val = z_cur z_val = z_cur
a = cbuf[a_mem + a_cur, sim] + delays[a_idx, 0, z_val] * simctl_float[0] a = cbuf[a_mem + a_cur, sim] + delays[a_idx, 0, z_val]
b = cbuf[b_mem + b_cur, sim] + delays[b_idx, 0, z_val] * simctl_float[0] b = cbuf[b_mem + b_cur, sim] + delays[b_idx, 0, z_val]
c = cbuf[c_mem + c_cur, sim] + delays[c_idx, 0, z_val] * simctl_float[0] c = cbuf[c_mem + c_cur, sim] + delays[c_idx, 0, z_val]
d = cbuf[d_mem + d_cur, sim] + delays[d_idx, 0, z_val] * simctl_float[0] d = cbuf[d_mem + d_cur, sim] + delays[d_idx, 0, z_val]
previous_t = TMIN previous_t = TMIN
@@ -233,37 +228,36 @@ def _wave_eval(op, cbuf, c_locs, c_caps, ebuf, sim, delays, simctl_int, simctl_f
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 ^ 1, z_val] * simctl_float[0] 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] * simctl_float[0] 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] * simctl_float[0] 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 ^ 1, z_val] * simctl_float[0] 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] * simctl_float[0] 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] * simctl_float[0] 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 ^ 1, z_val] * simctl_float[0] 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] * simctl_float[0] 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] * simctl_float[0] 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 ^ 1, z_val] * simctl_float[0] 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] * simctl_float[0] 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] * simctl_float[0] 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) ...
or (current_t - previous_t) > thresh # -OR- the generated hazard is wider than pulse threshold. or (current_t - previous_t) > thresh # -OR- the generated hazard is wider than pulse threshold.
): ):
if z_cur < (z_cap - 1): # enough space in z_mem? if z_cur < (z_cap - 1): # enough space in z_mem?
#if delta and (cbuf[z_mem + z_cur, sim] != current_t):
# out_changed = 1
cbuf[z_mem + z_cur, sim] = current_t cbuf[z_mem + z_cur, sim] = current_t
previous_t = current_t previous_t = current_t
z_cur += 1 z_cur += 1
@@ -277,30 +271,21 @@ def _wave_eval(op, cbuf, c_locs, c_caps, ebuf, sim, delays, simctl_int, simctl_f
# output value of cell changed. update all delayed inputs. # output value of cell changed. update all delayed inputs.
z_val = z_val ^ 1 z_val = z_val ^ 1
a = cbuf[a_mem + a_cur, sim] + delays[a_idx, a_cur & 1, z_val] * simctl_float[0] a = cbuf[a_mem + a_cur, sim] + delays[a_idx, a_cur & 1, z_val]
b = cbuf[b_mem + b_cur, sim] + delays[b_idx, b_cur & 1, z_val] * simctl_float[0] b = cbuf[b_mem + b_cur, sim] + delays[b_idx, b_cur & 1, z_val]
c = cbuf[c_mem + c_cur, sim] + delays[c_idx, c_cur & 1, z_val] * simctl_float[0] c = cbuf[c_mem + c_cur, sim] + delays[c_idx, c_cur & 1, z_val]
d = cbuf[d_mem + d_cur, sim] + delays[d_idx, d_cur & 1, z_val] * simctl_float[0] d = cbuf[d_mem + d_cur, sim] + delays[d_idx, d_cur & 1, z_val]
current_t = min(a, b, c, d) current_t = min(a, b, c, d)
#if delta and (cbuf[z_mem + z_cur, sim] != TMAX):
# out_changed = 1
# 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
e = int(((cbuf[z_mem, sim] == TMIN) << 1) & 2) # initial value
e |= z_val # final value
e |= (nrise + nfall)<<2 # number of transitions
ebuf[z_idx, sim, 0] = e
ebuf[z_idx, sim, 1] = input_epoch #& out_changed
return nrise, nfall return nrise, nfall
@@ -308,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, ebuf, abuf, sim_start, sim_stop, delays, simctl_int, simctl_float, seed, delta): 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, ebuf, sim, delays, simctl_int[:, sim], simctl_float[:, sim], seed, delta) 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]
@@ -384,14 +369,13 @@ class WaveSimCuda(WaveSim):
self.c_caps = cuda.to_device(self.c_caps) self.c_caps = cuda.to_device(self.c_caps)
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.simctl_float = cuda.to_device(self.simctl_float)
self.abuf = cuda.to_device(self.abuf) self.abuf = cuda.to_device(self.abuf)
self.e = cuda.to_device(self.e) 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.error_counts = cuda.to_device(self.error_counts)
self.lsts = cuda.to_device(self.lsts)
self.overflows = cuda.to_device(self.overflows)
self.aux = cuda.to_device(np.zeros(8*1024, dtype=np.int32)) self.retval_int = cuda.to_device(np.array([0], dtype=np.int32))
self._block_dim = (32, 16) self._block_dim = (32, 16)
@@ -404,13 +388,12 @@ class WaveSimCuda(WaveSim):
state['c_caps'] = np.array(self.c_caps) state['c_caps'] = np.array(self.c_caps)
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['simctl_float'] = np.array(self.simctl_float)
state['abuf'] = np.array(self.abuf) state['abuf'] = np.array(self.abuf)
state['e'] = np.array(self.e) 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['error_counts'] = np.array(self.error_counts)
state['lsts'] = np.array(self.lsts) state['retval_int'] = np.array(self.retval_int)
state['overflows'] = np.array(self.overflows)
state['aux'] = np.array(self.aux)
return state return state
def __setstate__(self, state): def __setstate__(self, state):
@@ -422,13 +405,12 @@ class WaveSimCuda(WaveSim):
self.c_caps = cuda.to_device(self.c_caps) self.c_caps = cuda.to_device(self.c_caps)
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.simctl_float = cuda.to_device(self.simctl_float)
self.abuf = cuda.to_device(self.abuf) self.abuf = cuda.to_device(self.abuf)
self.e = cuda.to_device(self.e) 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.error_counts = cuda.to_device(self.error_counts)
self.lsts = cuda.to_device(self.lsts) self.retval_int = cuda.to_device(self.retval_int)
self.overflows = cuda.to_device(self.overflows)
self.aux = cuda.to_device(self.aux)
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)
@@ -436,23 +418,23 @@ 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, op_from=0, op_to=None, delta=0): 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_from > op_start: continue
if op_to is not None and op_to <= op_start: break 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.e, 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, self.simctl_float, seed, delta) sims, self.delays, self.simctl_int, seed)
cuda.synchronize() cuda.synchronize()
def c_prop_level(self, level, sims=None, seed=1, delta=0): def c_prop_level(self, level, sims=None, seed=1):
sims = min(sims or self.sims, self.sims) sims = min(sims or self.sims, self.sims)
op_start = self.level_starts[level] op_start = self.level_starts[level]
op_stop = self.level_stops[level] op_stop = self.level_stops[level]
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.e, 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, self.simctl_float, seed, delta) 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)
@@ -463,39 +445,24 @@ 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 acc_error_counts(self, sims=None): 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) sims = min(sims or self.sims, self.sims)
grid_dim = cdiv(self.s_len, 256) grid_dim = cdiv(self.s_len, 256)
acc_error_counts_gpu[grid_dim, 256](self.s, sims, self.error_counts) calc_error_counts_gpu[grid_dim, 256](self.s, sims, self.error_counts)
def reset_error_counts(self):
self.error_counts[:] = 0
def get_error_counts(self):
return np.array(self.error_counts) return np.array(self.error_counts)
def acc_overflows(self, sims=None):
sims = min(sims or self.sims, self.sims)
grid_dim = cdiv(self.s_len, 256)
acc_overflows_gpu[grid_dim, 256](self.s, sims, self.overflows)
def reset_overflows(self):
self.overflows[:] = 0
def get_overflows(self):
return np.array(self.overflows)
def acc_lsts(self, sims=None):
sims = min(sims or self.sims, self.sims)
grid_dim = cdiv(self.s_len, 256)
acc_lsts_gpu[grid_dim, 256](self.s, sims, self.lsts)
def reset_lsts(self):
self.lsts[:] = 0.0
def get_lsts(self):
return np.array(self.lsts)
@cuda.jit() @cuda.jit()
def memcpy_gpu (src, dst, nitems): def memcpy_gpu (src, dst, nitems):
@@ -506,33 +473,23 @@ def memcpy_gpu (src, dst, nitems):
@cuda.jit() @cuda.jit()
def acc_error_counts_gpu(s, sims, error_counts): 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) x = cuda.grid(1)
if x >= s.shape[1]: return if x >= s.shape[1]: return
cnt = 0 cnt = 0
for i in range(sims): for i in range(sims):
cnt += (s[6,x,i] != s[8,x,i]) cnt += (s[6,x,i] != s[8,x,i])
error_counts[x] += cnt error_counts[x] = cnt
@cuda.jit()
def acc_overflows_gpu(s, sims, overflows):
x = cuda.grid(1)
if x >= s.shape[1]: return
cnt = 0
for i in range(sims):
cnt += s[10,x,i]
overflows[x] += cnt
@cuda.jit()
def acc_lsts_gpu(s, sims, lsts):
x = cuda.grid(1)
if x >= s.shape[1]: return
lst = 0
for i in range(sims):
lst = max(lst, s[5,x,i])
lsts[x] = max(lsts[x], lst)
@cuda.jit() @cuda.jit()
@@ -563,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, ebuf, abuf, sim_start, sim_stop, delays, simctl_int, simctl_float, seed, delta): 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
@@ -575,7 +532,7 @@ def wave_eval_gpu(ops, op_start, op_stop, cbuf, c_locs, c_caps, ebuf, abuf, sim_
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, ebuf, sim, delays, simctl_int[:, sim], simctl_float[:, sim], seed, delta) 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:
-29
View File
@@ -20,37 +20,8 @@ def b15_2ig_circuit_resolved(b15_2ig_circuit):
cr.resolve_tlib_cells(SAED32) cr.resolve_tlib_cells(SAED32)
return cr return cr
@pytest.fixture(scope='session')
def b15_4ig_circuit(mydir):
from kyupy import verilog
from kyupy.techlib import SAED32
return verilog.load(mydir / 'b15_4ig.v.gz', branchforks=True, tlib=SAED32)
@pytest.fixture(scope='session')
def b15_4ig_circuit_resolved(b15_4ig_circuit):
from kyupy.techlib import SAED32
cr = b15_4ig_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
from kyupy.techlib import SAED32 from kyupy.techlib import SAED32
return sdf.load(mydir / 'b15_2ig.sdf.gz').iopaths(b15_2ig_circuit, tlib=SAED32)[1:2] return sdf.load(mydir / 'b15_2ig.sdf.gz').iopaths(b15_2ig_circuit, tlib=SAED32)[1:2]
@pytest.fixture(scope='session')
def b15_2ig_sa_nf_test_resp(mydir, b15_2ig_circuit_resolved):
from kyupy import stil
s = stil.load(mydir / 'b15_2ig.sa_nf.stil.gz')
tests = s.tests(b15_2ig_circuit_resolved)[:,1:]
resp = s.responses(b15_2ig_circuit_resolved)[:,1:]
return (tests, resp)
@pytest.fixture(scope='session')
def b15_4ig_sa_rf_test_resp(mydir, b15_4ig_circuit_resolved):
from kyupy import stil
s = stil.load(mydir / 'b15_4ig.sa_rf.stil.gz')
tests = s.tests(b15_4ig_circuit_resolved)[:,1:]
resp = s.responses(b15_4ig_circuit_resolved)[:,1:]
return (tests, resp)
+22 -60
View File
@@ -1,6 +1,6 @@
import numpy as np import numpy as np
from kyupy.logic_sim import LogicSim, LogicSim6V from kyupy.logic_sim import LogicSim
from kyupy import bench, logic, sim from kyupy import bench, logic, sim
from kyupy.logic import mvarray, bparray, bp_to_mv, mv_to_bp from kyupy.logic import mvarray, bparray, bp_to_mv, mv_to_bp
@@ -94,30 +94,6 @@ def test_4v():
'--0XX', '--X1X', '--XXX', '--XXX')) '--0XX', '--X1X', '--XXX', '--XXX'))
def test_6v():
c = bench.parse('input(x, y) output(a, o, n, xo, no) a=AND2(x,y) o=OR2(x,y) n=INV1(x) xo=XOR2(x,y) no=NOR2(x,y)')
s = LogicSim6V(c, 36)
assert s.s_len == 7
mva = mvarray(
'0000101', '0101110', '0R0R1RF', '0F0F1FR', '0P0P1PN', '0N0N1NP',
'1001010', '1111000', '1RR10F0', '1FF10R0', '1PP10N0', '1NN10P0',
'R00RFRF', 'R1R1FF0', 'RRRRFPF', 'RFPNFNP', 'RPPRFRF', 'RNRNFFP',
'F00FRFR', 'F1F1RR0', 'FRPNRNP', 'FFFFRPR', 'FPPFRFR', 'FNFNRRP',
'P00PNPN', 'P1P1NN0', 'PRPRNRF', 'PFPFNFR', 'PPPPNPN', 'PNPNNNP',
'N00NPNP', 'N1N1PP0', 'NRRNPFP', 'NFFNPRP', 'NPPNPNP', 'NNNNPPP')
tests = np.copy(mva)
tests[2:] = logic.ZERO
s.s[0] = tests
s.s_to_c()
s.c_prop()
s.c_to_s()
resp = s.s[1].copy()
exp_resp = np.copy(mva)
exp_resp[:2] = logic.ZERO
np.testing.assert_allclose(resp, exp_resp)
def test_8v(): def test_8v():
c = bench.parse('input(x, y) output(a, o, n, xo) a=and(x,y) o=or(x,y) n=not(x) xo=xor(x,y)') c = bench.parse('input(x, y) output(a, o, n, xo) a=and(x,y) o=or(x,y) n=not(x) xo=xor(x,y)')
s = LogicSim(c, 64, m=8) s = LogicSim(c, 64, m=8)
@@ -199,8 +175,14 @@ def test_b01(mydir):
bp_to_mv(s.s[1]) bp_to_mv(s.s[1])
def sim_and_compare(c, test_resp, m=8): def sim_and_compare(v_file, stil_file, m=8):
tests, resp = test_resp 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 = LogicSim(c, m=m, sims=tests.shape[1])
lsim.s[0] = logic.mv_to_bp(tests) lsim.s[0] = logic.mv_to_bp(tests)
lsim.s_to_c() lsim.s_to_c()
@@ -215,46 +197,26 @@ def sim_and_compare(c, test_resp, m=8):
print(f'mismatch pattern:{pat} ppio:{idx} exp:{logic.mv_str(resp[idx,pat])} act:{logic.mv_str(resp_sim[idx,pat])}') 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 assert len(idxs) == 0
def sim_and_compare_6v(c, test_resp):
tests, resp = test_resp def test_b15_2ig_sa_2v(mydir):
lsim = LogicSim6V(c, sims=tests.shape[1]) sim_and_compare(mydir / 'b15_2ig.v.gz', mydir / 'b15_2ig.sa_nf.stil.gz', m=2)
lsim.s[0] = tests
lsim.s_to_c()
lsim.c_prop()
lsim.c_to_s()
resp_sim = lsim.s[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(b15_2ig_circuit_resolved, b15_2ig_sa_nf_test_resp): def test_b15_2ig_sa_4v(mydir):
sim_and_compare(b15_2ig_circuit_resolved, b15_2ig_sa_nf_test_resp, m=2) sim_and_compare(mydir / 'b15_2ig.v.gz', mydir / 'b15_2ig.sa_nf.stil.gz', m=4)
def test_b15_2ig_sa_4v(b15_2ig_circuit_resolved, b15_2ig_sa_nf_test_resp): def test_b15_2ig_sa_8v(mydir):
sim_and_compare(b15_2ig_circuit_resolved, b15_2ig_sa_nf_test_resp, m=4) sim_and_compare(mydir / 'b15_2ig.v.gz', mydir / 'b15_2ig.sa_nf.stil.gz', m=8)
def test_b15_2ig_sa_6v(b15_2ig_circuit_resolved, b15_2ig_sa_nf_test_resp): def test_b15_4ig_sa_2v(mydir):
sim_and_compare_6v(b15_2ig_circuit_resolved, b15_2ig_sa_nf_test_resp) sim_and_compare(mydir / 'b15_4ig.v.gz', mydir / 'b15_4ig.sa_rf.stil.gz', m=2)
def test_b15_2ig_sa_8v(b15_2ig_circuit_resolved, b15_2ig_sa_nf_test_resp): def test_b15_4ig_sa_4v(mydir):
sim_and_compare(b15_2ig_circuit_resolved, b15_2ig_sa_nf_test_resp, m=8) sim_and_compare(mydir / 'b15_4ig.v.gz', mydir / 'b15_4ig.sa_rf.stil.gz', m=4)
def test_b15_4ig_sa_2v(b15_4ig_circuit_resolved, b15_4ig_sa_rf_test_resp): def test_b15_4ig_sa_8v(mydir):
sim_and_compare(b15_4ig_circuit_resolved, b15_4ig_sa_rf_test_resp, m=2) sim_and_compare(mydir / 'b15_4ig.v.gz', mydir / 'b15_4ig.sa_rf.stil.gz', m=8)
def test_b15_4ig_sa_4v(b15_4ig_circuit_resolved, b15_4ig_sa_rf_test_resp):
sim_and_compare(b15_4ig_circuit_resolved, b15_4ig_sa_rf_test_resp, m=4)
def test_b15_4ig_sa_8v(b15_4ig_circuit_resolved, b15_4ig_sa_rf_test_resp):
sim_and_compare(b15_4ig_circuit_resolved, b15_4ig_sa_rf_test_resp, m=8)
+8 -8
View File
@@ -11,7 +11,7 @@ def test_xnor2_delays():
c = np.full((4*16, 1), TMAX, dtype=np.float32) # 4 waveforms of capacity 16 c = np.full((4*16, 1), TMAX, dtype=np.float32) # 4 waveforms of capacity 16
c_locs = np.zeros((4,), dtype='int') c_locs = np.zeros((4,), dtype='int')
c_caps = np.zeros((4,), dtype='int') c_caps = np.zeros((4,), dtype='int')
ebuf = np.zeros((4, 1, 2), dtype=np.int32) 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 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 = np.zeros((1, 4, 2, 2))
@@ -28,7 +28,7 @@ def test_xnor2_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, ebuf, 0, delays, simctl_int, 0, 0) 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) 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([[TMIN,TMAX],[TMIN,TMAX]], [TMIN,TMAX]) # XNOR(1,1) => 1
@@ -44,17 +44,17 @@ def test_nand_delays():
c = np.full((5*16, 1), TMAX, dtype=np.float32) # 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')
ebuf = np.zeros((4, 1, 2), dtype=np.int32) 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
# SDF specifies IOPATH delays with respect to output polarity # SDF specifies IOPATH delays with respect to output polarity
# SDF pulse rejection value is determined by IOPATH causing last transition and polarity of last transition # SDF pulse rejection value is determined by IOPATH causing last transition and polarity of last transition
delays = np.zeros((1, 5, 2, 2)) delays = np.zeros((1, 5, 2, 2))
delays[0, 0, 0, 0] = 0.1 # A rise -> Z rise delays[0, 0, 0, 0] = 0.1 # A -> Z rise delay
delays[0, 0, 0, 1] = 0.2 # A rise -> Z fall delays[0, 0, 0, 1] = 0.2 # A -> Z fall delay
delays[0, 0, 1, 0] = 0.1 # A fall -> Z rise delays[0, 0, 1, 0] = 0.1 # A -> Z negative pulse limit (terminate in rising Z)
delays[0, 0, 1, 1] = 0.2 # A fall -> Z fall delays[0, 0, 1, 1] = 0.2 # A -> Z positive pulse limit
delays[0, 1, :, 0] = 0.3 # as above for B -> Z delays[0, 1, :, 0] = 0.3 # as above for B -> Z
delays[0, 1, :, 1] = 0.4 delays[0, 1, :, 1] = 0.4
delays[0, 2, :, 0] = 0.5 # as above for C -> Z delays[0, 2, :, 0] = 0.5 # as above for C -> Z
@@ -66,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, ebuf, 0, delays, simctl_int, 0, 0) 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