@ -10,7 +10,7 @@ import math
@@ -10,7 +10,7 @@ import math
import numpy as np
from . import numba , logic , hr_bytes , sim , eng , cdiv , batchrange
from . import numba , logic , hr_bytes , sim , eng , cdiv
from . circuit import Circuit
@ -43,7 +43,6 @@ class LogicSim(sim.SimOps):
@@ -43,7 +43,6 @@ class LogicSim(sim.SimOps):
Access this array to assign new values to the ( P ) PIs or read values from the ( P ) POs .
"""
self . s [ : , : , 1 , : ] = 255 # unassigned
self . _full_mask = np . full ( self . c . shape [ - 1 ] , 255 , dtype = np . uint8 )
def __repr__ ( self ) :
return f ' {{ name: " { self . circuit . name } " , sims: { self . sims } , m: { self . m } , c_bytes: { eng ( self . c . nbytes ) } }} '
@ -62,22 +61,20 @@ class LogicSim(sim.SimOps):
@@ -62,22 +61,20 @@ class LogicSim(sim.SimOps):
: param inject_cb : A callback function for manipulating intermediate signal values .
This function is called with a line and its new logic values ( in bit - parallel format ) after
evaluation of a node . The callback may manipulate the given values in - place , the simulation
resumes with the manipulated values after the callback returns . Specifying this callback
may reduce performance as it disables jit compilation .
resumes with the manipulated values after the callback returns .
: type inject_cb : ` ` f ( Line , ndarray ) ` `
"""
fault_line = int ( fault_line )
t0 = self . c_locs [ self . tmp_idx ]
t1 = self . c_locs [ self . tmp2_idx ]
if self . m == 2 :
if inject_cb is None :
if fault_mask is None :
fault_mask = self . _full_mask # default: full mask
fault_mask = np . full ( self . c . shape [ - 1 ] , 255 , dtype = np . uint8 )
else :
if len ( fault_mask ) < self . c . shape [ - 1 ] : # pad mask with 0's if necessary
if len ( fault_mask ) < self . c . shape [ - 1 ] :
fault_mask2 = np . full ( self . c . shape [ - 1 ] , 0 , dtype = np . uint8 )
fault_mask2 [ : len ( fault_mask ) ] = fault_mask
fault_mask = fault_mask2
t0 = self . c_locs [ self . tmp_idx ]
t1 = self . c_locs [ self . tmp2_idx ]
if self . m == 2 :
if inject_cb is None :
_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 ] :
@ -193,15 +190,6 @@ class LogicSim(sim.SimOps):
@@ -193,15 +190,6 @@ class LogicSim(sim.SimOps):
logic . bp4v_or ( self . c [ o0 ] , self . c [ t0 ] , self . c [ t1 ] )
else : print ( f ' unknown op { op } ' )
if inject_cb is not None : inject_cb ( o0l , self . c [ o0 ] )
if fault_line > = 0 and o0l == fault_line :
if fault_model == 0 :
self . c [ o0 ] = self . c [ o0 ] & ~ fault_mask [ np . newaxis ]
elif fault_model == 1 :
self . c [ o0 ] = self . c [ o0 ] | fault_mask [ np . newaxis ]
else :
self . c [ t0 , 0 ] = ~ ( self . c [ o0 , 0 ] & self . c [ o0 , 1 ] & fault_mask )
self . c [ o0 , 1 ] = ~ self . c [ o0 , 0 ] & ~ self . c [ o0 , 1 ] & fault_mask
self . c [ o0 , 0 ] = self . c [ t0 , 0 ]
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 ) ]
@ -355,6 +343,7 @@ def _prop_cpu(ops, c_locs, c, fault_line, fault_mask, fault_model):
@@ -355,6 +343,7 @@ def _prop_cpu(ops, c_locs, c, fault_line, fault_mask, fault_model):
elif op == sim . MUX21 : c [ o0 ] = ( c [ i0 ] & ~ c [ i2 ] ) | ( c [ i1 ] & c [ i2 ] )
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 :
@ -363,90 +352,6 @@ def _prop_cpu(ops, c_locs, c, fault_line, fault_mask, fault_model):
@@ -363,90 +352,6 @@ def _prop_cpu(ops, c_locs, c, fault_line, fault_mask, fault_model):
c [ o0 ] = c [ o0 ] ^ fault_mask
class LogicSim2V ( sim . SimOps ) :
""" A bit-parallel naïve combinational simulator for 2-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 .
Caveat : faults on fanout branches will not be injected if forks are stripped .
"""
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 , 1 , nbytes ) , dtype = np . uint8 )
""" Logic values within the combinational portion of the circuit.
In bit - parallel ( bp ) storage format .
Storage locations are indirectly addressed .
Data for line ` l ` is in ` self . c [ self . c_locs [ l ] ] ` .
"""
self . s_assign = np . zeros ( ( self . s_len , self . sims ) , dtype = np . uint8 )
""" Logic values assigned to the ports and flip-flops of the circuit.
The simulator reads ( P ) PI values from here .
Values assigned to PO positions are ignored .
This field is a 2 - dimensional array and expects values in the mv storage format .
First index is the port position ( defined by ` self . circuit . s_nodes ` ) , second index is the pattern index ( 0 . . . ` self . sims - 1 ` ) .
"""
self . s_result = np . zeros ( ( self . s_len , self . sims ) , dtype = np . uint8 )
""" Logic values at the ports and flip-flops of the circuit after simulation.
The simulator writes ( P ) PO values here .
Values assigned to PI positions are ignored .
This field is a 2 - dimensional array and expects values in the mv storage format .
First index is the port position ( defined by ` self . circuit . s_nodes ` ) , second index is the pattern index ( 0 . . . ` self . sims - 1 ` ) .
"""
self . _full_mask = np . full ( self . c . shape [ - 1 ] , 255 , dtype = np . uint8 )
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 ``self.s_assign`` to the inputs of the combinational portion.
"""
self . c [ self . pippi_c_locs ] = logic . mv_to_bp ( self . s_assign [ self . pippi_s_locs ] ) [ : , : 1 , : ]
def c_prop ( self , fault_line = - 1 , fault_model = 2 , fault_mask = None ) :
if fault_mask is None :
fault_mask = self . _full_mask # default: full mask
else :
if len ( fault_mask ) < self . c . shape [ - 1 ] : # pad mask with 0's if necessary
fault_mask2 = np . full ( self . c . shape [ - 1 ] , 0 , dtype = np . uint8 )
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 ) )
def c_to_s ( self ) :
""" Captures the results of the combinational portion into ``self.s_result``.
"""
self . s_result [ self . poppo_s_locs ] = logic . bp_to_mv ( self . c [ self . poppo_c_locs ] ) [ : , : self . sims ] * logic . ONE
def c_ppo_to_ppi ( self ) :
""" Copies the result data for all PPOs (flip-flops) to PPIs for a next simulation cycle.
"""
self . c [ self . ppi_c_locs ] = self . c [ self . ppo_c_locs ] . copy ( ) # copy prevents undefined behavior if (P)PIs are connected directly to (P)POs
def allocate ( self ) :
""" Allocates a new pattern array with appropriate dimensions ``(self.s_len, self.sims)`` for one-pass simulation.
"""
return np . full ( ( self . s_len , self . sims ) , logic . ZERO , dtype = np . uint8 )
def simulate ( self , patterns , cycles : int = 1 , fault_line = - 1 , fault_model = 2 , fault_mask = None ) :
assert cycles > = 1
for bo , bs in batchrange ( patterns . shape [ - 1 ] , self . sims ) :
self . s_assign [ self . pippi_s_locs , : bs ] = patterns [ self . pippi_s_locs , bo : bo + bs ]
self . s_to_c ( )
for cycle in range ( cycles ) :
self . c_prop ( fault_line = fault_line , fault_model = fault_model , fault_mask = fault_mask )
if cycle < ( cycles - 1 ) : self . c_ppo_to_ppi ( )
self . c_to_s ( )
patterns [ self . poppo_s_locs , bo : bo + bs ] = self . s_result [ self . poppo_s_locs , : bs ]
class LogicSim6V ( sim . SimOps ) :
""" A bit-parallel naïve combinational simulator for 6-valued logic.