@ -1,10 +1,10 @@
@@ -1,10 +1,10 @@
""" High-T hroughput combinational logic timing simulators.
""" High-t hroughput combinational logic timing simulators.
These simulators work similarly to : py : class : ` ~ kyupy . logic_sim . LogicSim ` .
They propagate values through the combinational circuit from ( pseudo ) primary inputs to ( pseudo ) primary outputs .
Instead of propagating logic values , these simulators propagate signal histories ( waveforms ) .
They are designed to run many simulations in parallel and while their latencies are quite high , they achieve
high throughput performance .
They are designed to run many simulations in parallel and while their latencies are quite high , they can achieve
high throughput .
The simulators are not event - based and are not capable of simulating sequential circuits directly .
@ -20,9 +20,13 @@ import numpy as np
@@ -20,9 +20,13 @@ import numpy as np
from . import numba , cuda , hr_bytes
TMAX = np . float32 ( 2 * * 127 ) # almost np.PINF for 32-bit floating point values
TMAX_OVL = np . float32 ( 1.1 * 2 * * 127 ) # almost np.PINF with overflow mark
TMIN = np . float32 ( - 2 * * 127 ) # almost np.NINF for 32-bit floating point values
TMAX = np . float32 ( 2 * * 127 )
""" A large 32-bit floating point value used to mark the end of a waveform. """
TMAX_OVL = np . float32 ( 1.1 * 2 * * 127 )
""" A large 32-bit floating point value used to mark the end of a waveform that
may be incomplete due to an overflow . """
TMIN = np . float32 ( - 2 * * 127 )
""" A large negative 32-bit floating point value used at the beginning of waveforms that start with logic-1. """
class Heap :
@ -92,7 +96,23 @@ class Heap:
@@ -92,7 +96,23 @@ class Heap:
class WaveSim :
""" A waveform-based combinational logic timing simulator. """
""" A waveform-based combinational logic timing simulator running on CPU.
: param circuit : The circuit to simulate .
: param timing : The timing annotation of the circuit ( see : py : func : ` kyupy . sdf . DelayFile . annotation ` for details )
: param sims : The number of parallel simulations .
: param wavecaps : The number of floats available in each waveform . Waveforms are encoding the signal switching
history by storing transition times . The waveform capacity roughly corresponds to the number of transitions
that can be stored . A capacity of ` ` n ` ` can store at least ` ` n - 2 ` ` transitions . If more transitions are
generated during simulation , the latest glitch is removed ( freeing up two transition times ) and an overflow
flag is set . If an integer is given , all waveforms are set to that same capacity . With an array of length
` ` len ( circuit . lines ) ` ` the capacity can be controlled for each intermediate waveform individually .
: param strip_forks : If enabled , the simulator will not evaluate fork nodes explicitly . This saves simulation time
by reducing the number of nodes to simulate , but ( interconnect ) delay annotations of lines read by fork nodes
are ignored .
: param keep_waveforms : If disabled , memory of intermediate signal waveforms will be re - used . This greatly reduces
memory footprint , but intermediate signal waveforms become unaccessible after a propagation .
"""
def __init__ ( self , circuit , timing , sims = 8 , wavecaps = 16 , strip_forks = False , keep_waveforms = True ) :
self . circuit = circuit
self . sims = sims
@ -258,12 +278,24 @@ class WaveSim:
@@ -258,12 +278,24 @@ class WaveSim:
f ' levels= { len ( self . level_starts ) } mem= { hr_bytes ( total_mem ) } > '
def get_line_delay ( self , line , polarity ) :
""" Returns the current delay of the given ``line`` and ``polarity`` in the simulation model. """
return self . timing [ line , 0 , polarity ]
def set_line_delay ( self , line , polarity , delay ) :
""" Sets a new ``delay`` for the given ``line`` and ``polarity`` in the simulation model. """
self . timing [ line , 0 , polarity ] = delay
def assign ( self , vectors , time = 0.0 , offset = 0 ) :
""" Assigns new values to the primary inputs and state-elements.
: param vectors : The values to assign preferably in 8 - valued logic . The values are converted to
appropriate waveforms with or one transition ( ` ` RISE ` ` , ` ` FALL ` ` ) no transitions
( ` ` ZERO ` ` , ` ` ONE ` ` , and others ) .
: type vectors : : py : class : ` ~ kyupy . logic . BPArray `
: param time : The transition time of the generated waveforms .
: param offset : The offset into the vector set . The vector assigned to the first simulator is
` ` vectors [ offset ] ` ` .
"""
nvectors = min ( len ( vectors ) - offset , self . sims )
for i in range ( len ( self . interface ) ) :
ppi_loc = self . sat [ self . ppi_offset + i , 0 ]
@ -287,6 +319,12 @@ class WaveSim:
@@ -287,6 +319,12 @@ class WaveSim:
self . state [ ppi_loc + toggle , p ] = TMAX
def propagate ( self , sims = None , sd = 0.0 , seed = 1 ) :
""" 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 sd : Standard deviation for injection of random delay variation . Active , if value is positive .
: param seed : Random seed for delay variations .
"""
sims = min ( sims or self . sims , self . sims )
for op_start , op_stop in zip ( self . level_starts , self . level_stops ) :
self . overflows + = level_eval ( self . ops , op_start , op_stop , self . state , self . sat , 0 , sims ,
@ -294,6 +332,8 @@ class WaveSim:
@@ -294,6 +332,8 @@ class WaveSim:
self . lst_eat_valid = False
def wave ( self , line , vector ) :
""" Returns the desired waveform from the simulation state. Only valid, if simulator was
instanciated with ` ` keep_waveforms = True ` ` . """
if line < 0 :
return [ TMAX ]
mem , wcap , _ = self . sat [ line ]
@ -307,7 +347,34 @@ class WaveSim:
@@ -307,7 +347,34 @@ class WaveSim:
def wave_ppo ( self , o , vector ) :
return self . wave ( self . ppo_offset + o , vector )
def capture ( self , time = TMAX , sd = 0 , seed = 1 , cdata = None , offset = 0 ) :
def capture ( self , time = TMAX , sd = 0.0 , seed = 1 , cdata = None , offset = 0 ) :
""" Simulates a capture operation at all state-elements and primary outputs.
The capture analyzes the propagated waveforms at and around the given capture time and returns
various results for each capture operation .
: param time : The desired capture time . By default , a capture of the settled value is performed .
: param sd : A standard deviation for uncertainty in the actual capture time .
: param seed : The random seed for a capture with uncertainty .
: param cdata : An array to copy capture data into ( optional ) . See the return value for details .
: param offset : An offset into the supplied capture data array .
: return : The capture data as numpy array .
The 3 - dimensional capture data array contains for each interface node ( axis 0 ) ,
and each test ( axis 1 ) , seven values :
0. Probability of capturing a 1 at the given capture time ( same as next value , if no
standard deviation given ) .
1. A capture value decided by random sampling according to above probability and given seed .
2. The final value ( assume a very late capture time ) .
3. True , if there was a premature capture ( capture error ) , i . e . final value is different
from captured value .
4. Earliest arrival time . The time at which the output transitioned from its initial value .
5. Latest stabilization time . The time at which the output transitioned to its final value .
6. Overflow indicator . If non - zero , some signals in the input cone of this output had more
transitions than specified in ` ` wavecaps ` ` . Some transitions have been discarded , the
final values in the waveforms are still valid .
"""
for i , node in enumerate ( self . interface ) :
if len ( node . ins ) == 0 : continue
for p in range ( self . sims ) :
@ -320,6 +387,14 @@ class WaveSim:
@@ -320,6 +387,14 @@ class WaveSim:
return self . cdata
def reassign ( self , time = 0.0 ) :
""" Re-assigns the last capture to the appropriate pseudo-primary inputs. Generates a new set of
waveforms at the PPIs that start with the previous final value of that PPI , and transitions at the
given time to the value captured in a previous simulation . : py : func : ` ~ WaveSim . capture ` must be called
prior to this function . The final value of each PPI is taken from the randomly sampled concrete logic
values in the capture data .
: param time : The transition time at the inputs ( usually 0.0 ) .
"""
for i in range ( len ( self . interface ) ) :
ppi_loc = self . sat [ self . ppi_offset + i , 0 ]
ppo_loc = self . sat [ self . ppo_offset + i , 0 ]
@ -544,7 +619,12 @@ def wave_eval(op, state, sat, st_idx, line_times, sd=0.0, seed=0):
@@ -544,7 +619,12 @@ def wave_eval(op, state, sat, st_idx, line_times, sd=0.0, seed=0):
class WaveSimCuda ( WaveSim ) :
""" A GPU-accelerated waveform-based combinational logic timing simulator. """
""" A GPU-accelerated waveform-based combinational logic timing simulator.
The API is the same as for : py : class : ` WaveSim ` .
All internal memories are mirrored into GPU memory upon construction .
Some operations like access to single waveforms can involve large communication overheads .
"""
def __init__ ( self , circuit , timing , sims = 8 , wavecaps = 16 , strip_forks = False , keep_waveforms = True ) :
super ( ) . __init__ ( circuit , timing , sims , wavecaps , strip_forks , keep_waveforms )
@ -602,10 +682,10 @@ class WaveSimCuda(WaveSim):
@@ -602,10 +682,10 @@ class WaveSimCuda(WaveSim):
def wave ( self , line , vector ) :
if line < 0 :
return None
return [ TMAX ]
mem , wcap , _ = self . sat [ line ]
if mem < 0 :
return None
return [ TMAX ]
return self . d_state [ mem : mem + wcap , vector ]
def capture ( self , time = TMAX , sd = 0 , seed = 1 , cdata = None , offset = 0 ) :