| 
						
						
							
								
							
						
						
					 | 
					 | 
					@ -11,18 +11,18 @@ import math | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					import numpy as np | 
					 | 
					 | 
					 | 
					import numpy as np | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					from . import numba, logic, hr_bytes, sim | 
					 | 
					 | 
					 | 
					from . import numba, logic, hr_bytes, sim | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					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. | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    :param circuit: The circuit to simulate. | 
					 | 
					 | 
					 | 
					    :param circuit: The circuit to simulate. | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    :type circuit: :py:class:`~kyupy.circuit.Circuit` | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    :param sims: The number of parallel logic simulations to perform. | 
					 | 
					 | 
					 | 
					    :param sims: The number of parallel logic simulations to perform. | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    :type sims: int | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    :param m: The arity of the logic, must be 2, 4, or 8. | 
					 | 
					 | 
					 | 
					    :param m: The arity of the logic, must be 2, 4, or 8. | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    :type m: int | 
					 | 
					 | 
					 | 
					    :param c_reuse: If True, intermediate signal values may get overwritten when not needed anymore. | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					    :param strip_forks: If True, forks are not included in the simulation model. | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    """ | 
					 | 
					 | 
					 | 
					    """ | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    def __init__(self, circuit, sims=8, m=8, c_reuse=False, strip_forks=False): | 
					 | 
					 | 
					 | 
					    def __init__(self, circuit: Circuit, sims: int = 8, m: int = 8, c_reuse: bool = False, strip_forks: bool = False): | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        assert m in [2, 4, 8] | 
					 | 
					 | 
					 | 
					        assert m in [2, 4, 8] | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        super().__init__(circuit, c_reuse=c_reuse, strip_forks=strip_forks) | 
					 | 
					 | 
					 | 
					        super().__init__(circuit, c_reuse=c_reuse, strip_forks=strip_forks) | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        self.m = m | 
					 | 
					 | 
					 | 
					        self.m = m | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					 | 
					@ -32,26 +32,25 @@ class LogicSim(sim.SimOps): | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        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) | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					        """Logic values of the sequential elements (flip-flops) and ports. | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					        The elements are as follows: | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					        * ``s[0]`` Assigned values. Simulator will read (P)PI value from here. | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					        * ``s[1]`` Result values. Simulator will write (P)PO values here. | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					        """ | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        self.s[:,:,1,:] = 255  # unassigned | 
					 | 
					 | 
					 | 
					        self.s[:,:,1,:] = 255  # unassigned | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    def __repr__(self): | 
					 | 
					 | 
					 | 
					    def __repr__(self): | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        return f'<LogicSim {self.circuit.name} sims={self.sims} m={self.m} state_mem={hr_bytes(self.c.nbytes)}>' | 
					 | 
					 | 
					 | 
					        return f'{{name: "{self.circuit.name}", sims: {self.sims}, m: {self.m}, c_bytes: {self.c.nbytes}}}' | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    def s_to_c(self): | 
					 | 
					 | 
					 | 
					    def s_to_c(self): | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        """Assign stimuli to the primary inputs and state-elements (flip-flops). | 
					 | 
					 | 
					 | 
					        """Copies the values from ``s[0]`` the inputs of the combinational portion. | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        :param stimuli: The input data to assign. Must be in bit-parallel storage format and in a compatible shape. | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        :type stimuli: :py:class:`~kyupy.logic.BPArray` | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        :returns: The given stimuli object. | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        """ | 
					 | 
					 | 
					 | 
					        """ | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        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_to_s(self): | 
					 | 
					 | 
					 | 
					    def c_to_s(self): | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        """Capture the current values at the primary outputs and in the state-elements (flip-flops). | 
					 | 
					 | 
					 | 
					        """Copies the results of the combinational portion to ``s[1]``. | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        For primary outputs, the logic value is stored unmodified in the given target array. | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        For flip-flops, the logic value is either stored unmodified (`ff_transitions=False`) | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        or constructed from the previous state and the new state (`ff_transitions=True`). | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        """ | 
					 | 
					 | 
					 | 
					        """ | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        self.s[1, self.poppo_s_locs, :self.mdim] = self.c[self.poppo_c_locs] | 
					 | 
					 | 
					 | 
					        self.s[1, self.poppo_s_locs, :self.mdim] = self.c[self.poppo_c_locs] | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        if self.mdim == 1: | 
					 | 
					 | 
					 | 
					        if self.mdim == 1: | 
				
			
			
		
	
	
		
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
					 | 
					@ -103,22 +102,27 @@ class LogicSim(sim.SimOps): | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					                if inject_cb is not None: inject_cb(o0, self.s[o0]) | 
					 | 
					 | 
					 | 
					                if inject_cb is not None: inject_cb(o0, self.s[o0]) | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    def s_ppo_to_ppi(self): | 
					 | 
					 | 
					 | 
					    def s_ppo_to_ppi(self): | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					        """Constructs a new assignment based on the current data in ``s``. | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					        Use this function for simulating consecutive clock cycles. | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					        For 2-valued or 4-valued simulations, all valued from PPOs (in ``s[1]``) and copied to the PPIs (in ``s[0]). | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					        For 8-valued simulations, PPI transitions are constructed from the initial values of the assignment and the | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					        final values of the results. | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					        """ | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        # TODO: handle latches correctly | 
					 | 
					 | 
					 | 
					        # TODO: handle latches correctly | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        if self.m == 2: | 
					 | 
					 | 
					 | 
					        if self.mdim < 3: | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            self.s[0, self.ppio_s_locs, 0] = self.s[1, self.ppio_s_locs, 0] | 
					 | 
					 | 
					 | 
					            self.s[0, self.ppio_s_locs] = self.s[1, self.ppio_s_locs] | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        else: | 
					 | 
					 | 
					 | 
					        else: | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            self.s[0, self.ppio_s_locs, 1] = self.s[0, self.ppio_s_locs, 0]  # initial value is previously assigned final value | 
					 | 
					 | 
					 | 
					            self.s[0, self.ppio_s_locs, 1] = self.s[0, self.ppio_s_locs, 0]  # initial value is previously assigned final value | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            self.s[0, self.ppio_s_locs, 0] = self.s[1, self.ppio_s_locs, 0]  # final value is newly captured final value | 
					 | 
					 | 
					 | 
					            self.s[0, self.ppio_s_locs, 0] = self.s[1, self.ppio_s_locs, 0]  # final value is newly captured final value | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            self.s[0, self.ppio_s_locs, 2] = self.s[0, self.ppio_s_locs, 0] ^ self.s[0, self.ppio_s_locs, 1]  # TODO: not correct for X, - | 
					 | 
					 | 
					 | 
					            self.s[0, self.ppio_s_locs, 2] = self.s[0, self.ppio_s_locs, 0] ^ self.s[0, self.ppio_s_locs, 1]  # TODO: not correct for X, - | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    def cycle(self, cycles=1, inject_cb=None): | 
					 | 
					 | 
					 | 
					    def cycle(self, cycles: int = 1, inject_cb=None): | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        """Assigns the given state, propagates it and captures the new state. | 
					 | 
					 | 
					 | 
					        """Assigns the given state, propagates it and captures the new state. | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        :param state: A bit-parallel array in a compatible shape holding the current circuit state. | 
					 | 
					 | 
					 | 
					        :param cycles: The number of cycles to simulate. | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            The contained data is assigned to the PI and PPI and overwritten by data at the PO and PPO after | 
					 | 
					 | 
					 | 
					        :param inject_cb: A callback function for manipulating intermediate signal values. See :py:func:`c_prop`. | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            propagation. | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        :type state: :py:class:`~kyupy.logic.BPArray` | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        :param inject_cb: A callback function for manipulating intermediate signal values. See :py:func:`propagate`. | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        :returns: The given state object. | 
					 | 
					 | 
					 | 
					        :returns: The given state object. | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        """ | 
					 | 
					 | 
					 | 
					        """ | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        for _ in range(cycles): | 
					 | 
					 | 
					 | 
					        for _ in range(cycles): | 
				
			
			
		
	
	
		
		
			
				
					| 
						
							
								
							
						
						
						
					 | 
					 | 
					
  |