class Configurator(Unit):
    """Class for handling configuration dictionaries."""
    
    def __init__(self, root, conf):
#         self.conf = conf
        Unit.__init__(self, root, "cfg", conf=conf)
       
    def build(self):
        for unit in self.units:
            class_load(unit)(self._parent)
    
    def _reload_cfg_index(self):
        self.reload_index()
    
    def reload_index(self):
        self.root_index = self._parent.index()

    def apply_cfg_filt(self, filt):
        for pat in fnmatch.filter(self.conf.keys(), filt):
            name_pat, attr = pat.partition(".")[::2]
            for qname in fnmatch.filter(self.root_index.keys(), name_pat):  
                self.root_index[qname].__setattr__(attr, self.conf[pat]) class Component:
class System(Component):
    def __init__(self, name=None, parent=None, **kwargs):
    def __repr__(self):
    def __setitem__(self, key, val):
    def __getitem__(self, key):
    def inst(self, name, cls, *args, **kwargs):
    def search(self, pattern='*', of_type=None, depth=0, pattern_relative=True):
    def __init__(self, name=''):
    def __getattr__(self, name):
    def _create_index_rec(self, comp):
    def update_index(self):
    def set_config(self, config):
    def get_config(self, comp_qualified_name, attr_name):
    def get_all_attrs(self, comp_qualified_name):
    def update_params(self, comp_qualified_name, params):
def sydsys(sid = 0):
def restart_sydsys(sid = 0):
def all2kwargs(func, *args, **kwargs):
def compinit(func):
    def wrapper(self, name=None, parent=None, *args, **kwargs): class Unit(Component):
    
    def __init__(self, parent, name, **kwargs):
        Component.__init__(self, name)
        self.__dict__.update(kwargs)
        if parent:
            parent += self
            self._reload_cfg_index()
            self._apply_cfg()
        
        self.build()

    def build(self):
        pass
    
    def _reload_cfg_index(self):
        self.find('/cfg').reload_index()
        
    def _apply_cfg(self):
        self.find('/cfg').apply_cfg_filt(self.qualified_name + '*') class Channel(Component):
    """Instances of this class allow the information they carry to be read
    and written in various interfaces (by various protocols)"""

    @compinit    
    def __init__(self, name, parent, **kwargs):
        self.slaves = []
        self.master = None
        self.master_connected = False
    
    def __irshift__(self, other):
        self.drive(other)
        return self

    def __rshift__(self, other):
        self.drive(other)
        return self
    
    def sink(self, intf):
        if self.master is not None:
            raise Exception("Can only have one master per channel!")
        
        self.master = intf
        self.master_connected = True
        intf._drive(self)
        
        for s in self.slaves:
            s._connect(self.master)
        
#         self._gen_drivers()
#         intf._mch = self
    
    def __ilshift__(self, other):
        self.sink(other)
        return self
    
    def __lshift__(self, other):
        self.sink(other)
        return self
    
    def drive(self, intf):
        self.slaves.append(intf)
        intf._sink(self)

        if self.master_connected:
            intf._connect(self.master) class isig(Intf):
    _intf_type = 'isig'

    @compinit
    def __init__(self, name, parent, dtype, dflt=None):
        super().__init__(name, parent)
        
        self._mch = None
        self._sch = None
        self._sig = None
        self._sourced = False
        self._dtype = dtype
        self._dflt = self._dtype.conv(dflt)
        self._sinks = set()
#         self.inst("e", EventSet, missing_event_handle=self._missing_event)
        self.e = EventSet('e', self, missing_event_handle=self._missing_event)
        
    def con_driver(self, intf):
        pass
    
#     def _connect(self, master):
#         if not self._sourced:
#             self._conn_to_intf(master)
        
    def _from_isig(self, other):
        if self._get_dtype() is other._get_dtype():
            self._sig = other
            for event in self.e.search(of_type=Event):
                getattr(other.e, event).subscribe(event)
            
            self._sourced = True
        else:
            self.inst('_p_dtype_convgen', Process, self._pfunc_dtype_convgen, [], pargs=(other,))
   
    
    def _pfunc_dtype_convgen(self, other):
        while(1):
            data_recv = other.bpop()
            data_conv_gen = convgen(data_recv, self._dtype)
             
            try:
                while True:
                    self.bpush(next(data_conv_gen))
            except StopIteration as e:
                if e.value is not None:
                    self.bpush(e.value)

    def _drive(self, channel):
        self._mch = channel

    def _sink(self, channel):
        self._sch = channel
    
    def _prep_write(self, val):
        try:
            val = val.read()
        except AttributeError:
            pass
        
        val = self._get_dtype().conv(val)
        
        if not self._sourced:
            self._sig = Signal(val=copy.deepcopy(self._dflt), event_set = self.e)
            self._sourced = True
            
        return val
    
    def bpush(self, val):
        val = self._prep_write(val)
        self._sig.bpush(val)
        
    def push(self, val):
        val = self._prep_write(val)
        self._sig.push(val)
    
    def write(self, val):
        val = self._prep_write(val)
        self._sig.write(val)
    
    def read_next(self):
        if not self._sourced:
            return copy.deepcopy(self._dflt)
        else:
            return self._sig._next
    
    def read(self):
        if not self._sourced:
            return copy.deepcopy(self._dflt)
        else:
            return self._sig.read()
        
    def bpop(self):
        if not self._sourced:
            ddic['sim'].wait(self.e['enqueued'])
            
        return self._sig.bpop()
    
    def deref(self, key):
        return SlicedIntf(self, key)
    
    def get_queue(self):
        if not self._sourced:
            return []
        else:
            return self._sig.get_queue()
    
    def _missing_event(self, event_set, name):
        event = Event(name, self.e)
        
        if self._sourced:
            if self._sig.e is not event_set:
                getattr(self._sig.e, name).subscribe(event)

        return event def Bit(w):
def bit_normalization(self, other):
    def __init__(self, val=None, vld=None):
    def _replace(self, key, val):
    def _hdl_gen_ref(self, conv):
    def _hdl_gen_decl(cls):
    def _hdl_gen_call(cls, conv=None, node=None):
    def deref(self, key):
    def __iter__(self):
    def _rnd(cls, rnd_gen):
    def __setitem__(self, key, val):
    def __getitem__(self, key):
    def bitstr(self):
    def __str__(self):
    def __len__(self):
    def _full(self):
    def _icon(self, other):
    def __concat__(self, other):
    def __mod__(self, other):
    def _from_bit(cls, other):
    def _from_int(cls, other):
    def __bool__(self):    
    def __add__(self, other):
    def __radd__(self, other):
    def __sub__(self, other):
    def __mul__(self, other):
    def __truediv__(self, other):
    def __rshift__(self, other):
    def __lshift__(self, other):
    def __xor__(self, other):
    def __rxor__(self, other):
    def __and__(self, other):
    def __rand__(self, other):
    def __or__(self, other):
    def __ror__(self, other):
    def __neg__(self):
    def __pos__(self):
    def __abs__(self):
    def __invert__(self):
    def __int__(self):
    def __float__(self):
    def __oct__(self):
    def __hex__(self):
    def __index__(self):
    def __eq__(self, other):
    def __ne__(self, other):
    def __lt__(self, other):
    def __le__(self, other):
    def __gt__(self, other):
    def __ge__(self, other):
class bit(TypeBase): class Delay(object):
    
    """Class to model delay events."""
    def unsubscribe(self, obj):
        ddic['sim'].delay_pop(obj)
        
    def subscribe(self, obj):
        ddic['sim'].delay_add(obj, self._time)

    def toVerilog(self):
        return "#{0}".format(self._time)

    def __init__(self, val):
        """Return a delay instance.

        Required parameters:
        val -- a natural integer representing the desired delay
        """
        self._time = val def proc(self, name, senslist = None):
    proc = Process(self.name + '.' + name, getattr(self, name), senslist)
    setattr(self, name, proc)
    return proc class Module(Component):
    
#         for attr in dir(self):
#             if not attr.startswith('_'):
#                 func = getattr(self, attr)
#                 if callable(func):
#                     if hasattr(func, "_senslist"):
#                         self.add(Process(self, func, func._senslist))

    def proc(self, name, senslist = None):
        proc = Process(self.name + '.' + name, getattr(self, name), senslist)
        setattr(self, name, proc)
        return proc

    def _get_intfs(self):
        return self.findall(of_type=Intf) class Process(Component, greenlet):
    """Wrapper class for functions that implement processes in user modules.
    
    Class turns function in the greenlet task.""" 

    @compinit
    def __init__(self, name, parent, func, sim : Dependency('sim'), senslist=None, pargs = (), pkwargs = {}, **kwargs):
        self.func = func

        self.senslist = senslist
        self.pargs = pargs
        self.pkwargs = pkwargs
        self.sim = sim

        if self.senslist is None:
            if func.__self__:
#                 parent_name = '.'.join(self.name.split('.')[:-1])
#                 qname_intfs = {c.name: c for c in system.search(parent_name + '.*', of_type=Intf)}
                qname_intfs = {c.name: c for c in func.__self__.search(of_type=Intf)}
                intfs = {}
                for k,v in qname_intfs.items():
                    intfs[k.rsplit('.', 1)[1]] = v
                 
                (inputs, outputs) = getio_vars(func, intfs=intfs)
            
                self.senslist = inputs - outputs

        self._exit_func = None 
        self.sim.proc_reg(self)
        greenlet.__init__(self)
    
    def run(self):
        if self.senslist:
            while(1):
                self.sim.wait(*list(self.senslist))
                self.func(*self.pargs, **self.pkwargs)
        else:
            self.func(*self.pargs, **self.pkwargs)
            self.sim.wait()
            
    def exit_func(self):
        if self._exit_func:
            self._exit_func() class Simulator(Component):
    '''Simulator kernel.'''

    def __init__(self, sched : Dependency('scheduler'), duration = 0, max_delta_count=1000, **kwargs):
        self.delay_pool = {}
        self.trig_pool = set()
        self.update_pool = set()     
        self._ready_pool = set()
        self._proc_pool = []
        self.running = False
        self.duration = duration
        self.sched = sched
        self.max_delta_count = max_delta_count

        # Create events for Simulator extensions to hook to.
        self.events = {
                       'init_start'     : SimEvent(),
                       'run_start'      : SimEvent(),
                       'run_end'        : SimEvent(),
                       'delta_start'    : SimEvent(),
                       'post_evaluate'  : SimEvent(),
                       'delta_end'      : SimEvent(),
                       'delta_settled'  : SimEvent(),
                       'timestep_start' : SimEvent(),
                       'timestep_end'   : SimEvent(),
                       }
        
#         self.inst('top', class_load(top))
#         self.sched = Scheduler(log_task_switching=False)
#         self.inst('sched', Scheduler, log_task_switching=False)

        #         Unit.__init__(self, parent, "sim")
    
    def gen_drivers(self):
        for _, comp in sydsys().findall(self.name + '.top*').items():
            if hasattr(comp, '_gen_drivers'):
                comp._gen_drivers()

#     def find_sources(self):
#         finished_all = True
#         for comp in system.search(self.name + '.top*', of_type=Intf).items():
# #         for _, comp in system.findall(self.name + '.top*').items():
#             if hasattr(comp, '_find_sources'):
#                 finished = comp._find_sources()
#                 if not finished:
#                     finished_all = False
#                     
#         return finished_all
    
    def run(self):
        self.sched.switch(self, self.duration)
   
    def _run(self, duration=0, quiet=0):
        """Start the simulator scheduler loop."""
        
        # Instantiate the user module hierarchy
        self._initialize()
        
        if duration:
            self.duration = duration
        
        self.max_time = self.time + self.duration
 
        self.running = True
        self.events['run_start'](self)
        self._finished = False
        
        while not self._finished:
            self.delta_count = 0
            self.events['timestep_start'](self.time, self)
            # Perform delta cycle loop as long as the events are triggering
            while self._ready_pool or self.trig_pool:
                #Perform one delta cycle
                self.events['delta_start'](self.time, self.delta_count, self)
                 
                self._evaluate()
                 
                self.events['post_evaluate'](self.time, self.delta_count, self)
                 
                self._update()
                 
                self.events['delta_end'](self.time, self.delta_count, self)
                 
                self.delta_count += 1
                 
                if self.delta_count > self.max_delta_count:
                    self._finalize()
                    self.events['run_end'](self)
                    self._finished = True
                    raise greenlet.GreenletExit
                    raise Exception("Maximum number of delta cycles reached: {0}".format(self.max_delta_count))
                
                if not (self._ready_pool or self.trig_pool):
                    self.events['delta_settled'](self)
                
#                 print('-----------------------------------------')
                 
            self.events['timestep_end'](self.time, self)
             
            # All events have settled, let's advance time
            if not self._advance_time():
                self._finalize()
                self.events['run_end'](self)
                self._finished = True
                raise greenlet.GreenletExit 
    
    def _initialize(self):
        
        self.max_time = None
        self.time = 0
        
#         self.gen_drivers()
        
#         while (not self.find_sources()):
#             pass
        
#         self.top_module = self.top_module_cls('top', None)

    def _unsubscribe(self, proc):
        """Unsubscribe the process from all events from  its sensitivity list."""
        
        events = getattr(proc, 'events', None)
        if not isinstance(events, set):
            if hasattr(events, '__iter__'):
                events = set([e for e in events])
            elif events is not None:
                events = set([events])
            
        if events:
            for e in events:
                e.unsubscribe(proc)
#                 try:
#                     e.unsubscribe(proc)
#                 except:
#                     raise
#                     e.event_def.unsubscribe(proc)
    
    def _subscribe(self, proc, events):
        """Subscribe the process to all events from  its sensitivity list."""
        
        proc.events = events
        
#         for e in unif_enum(events):
        for e in events:
            e.subscribe(proc)
#             try:
#                 e.subscribe(proc)
#             except AttributeError:
#                 e.subscribe(proc)
#                 e.event_def.subscribe(proc)
   
    def _evaluate(self):
        """Run all processes scheduled for execution. Resolve all triggered events afterwards."""
         
        # Run the ready processes
        while self._ready_pool:
            proc = self._ready_pool.pop()
            self._unsubscribe(proc)
            events = proc.switch()
            if events is not None:
                self._subscribe(proc, events)
            else:
                # If process supplied no waiting events, it is to be terminated
                self._proc_pool.remove(proc)
                proc.exit_func()
        
        # Resolve all triggered events          
        while self.trig_pool:
            trig = self.trig_pool.pop()
            trig.resolve(self._ready_pool)

    def _update(self):
        """Ask all signals to _update their values, and trigger new events. """
        
        for s in self.update_pool:
            s._update()
            
        self.update_pool.clear()
        
    def _advance_time(self):
        """Advanced time to the earliest scheduled process in delay pool and 
        return True, or return False if there are no more scheduled processes"""
        
        if self.delay_pool:
            t_new = None
            
            while self.delay_pool:
                w = min(self.delay_pool, key=self.delay_pool.get)
                if not t_new:
                    t_new = self.delay_pool[w]
                elif self.delay_pool[w] > t_new:
                    break
                    
                self.delay_pool.pop(w)
                self._ready_pool.add(w)

            self.time = t_new
            self.delta_count = 0
            
            if self.time > self.max_time:
                return False
            else:
                return True
        else:
            return False
        
    def _finalize(self):
        """Call the exit functions of all processes."""
        
        for p in self._proc_pool:
            p.exit_func()
            
        self._finished = True

    def proc_reg(self, proc):
        """Register a process with simulator kernel."""
        self._ready_pool.add(proc)
        self._proc_pool.append(proc)
    
    def update (self, sig):
        self.update_pool.add(sig)
    
    def wait(self, *events):
        """Delay process execution by waiting for events."""
        self.sched.switch(events)
    
    def delay_add(self, proc, time):
        """Register process to be scheduled for execution after given time."""
        self.delay_pool[proc] = time + self.time
    
    def delay_pop(self,proc):
        """Remove process from the delay schedule."""
        self.delay_pool.pop(proc, None)

    def trigger(self, event):
        """Register event to trigger pool."""
        self.trig_pool.add(event) class Cosim(Component):
    
    def __init__(self, cosim_intf, fileset = [], module_name=None, **kwargs):
        Component.__init__(self, **kwargs)
        self.cosim_intf = sydsys()[cosim_intf]
        self.module_name = module_name
        self.fileset = fileset

        if self.module_name is None:
            self.module_name = self.name.rsplit('.', 1)[-1]
        
        self.cosim_intf.register(self)
    
    def resolve(self):
        self.intfs = {c.name: c for c in self.search(of_type=Intf)}
        self.outputs = {}
        self.inputs = {}
        
        for name, intf in self.intfs.items():
            if intf._mch is None:
                self.inputs[name.rsplit('.',1)[-1]] = intf
            else:
                self.outputs[name.rsplit('.',1)[-1]] = intf
        
        self.inst('proc', Process, self.proc, self.inputs.values())
        
    def proc(self):
        self.cosim_intf.updated(self) class XsimIntf(Component):

    state_type = {0: "S_STARTED", 1: "S_CONNECTED", 2: "S_INITIALIZED", 3:"S_IMPORT", 4:"S_EXPORT", 5:"S_DELAY"};
    cmds = {'GET_STATE': {'type': 'GET', 'params': ['state']},
            'CONTINUE': {'type': 'CONTINUE', 'params': ['state']}
            }

    @compinit
    def __init__(self, builddir='.', **kwargs):
        self.cosim_pool = []
        sydsys().sim.events['run_start'].append(sydsys().sim_run_start)
        sydsys().sim.events['run_end'].append(sydsys().sim_run_end)
        sydsys().sim.events['delta_settled'].append(sydsys().sim_delta_settled)
        sydsys().sim.events['timestep_start'].append(sydsys().sim_timestep_start)
        
    
    def render_module_inst(self, cosim):
        port_map = []
        for name, intf in itertools.chain(cosim.inputs.items(), cosim.outputs.items()):
            port_map.append(port_map_tmpl.substitute(port_name = name, signal_name = '_'.join([cosim.module_name, name]))) 
    
        return module_inst_tmpl.substitute(module_name=cosim.module_name,
                                           instance_name='i_' + cosim.module_name,
                                           port_map=',\n    '.join(port_map))
    
    def render_wrapper(self):
        module_insts = []
        for cosim in self.cosim_pool:
            module_insts.append(self.render_module_inst(cosim))
        
        ports_definition = []
        for name, intf in sorted(itertools.chain(self.inputs.items(), self.outputs.items())):
            if intf._get_dtype().w == 1:
                ports_definition.append('logic {0};'.format(name))
            else:
                ports_definition.append('logic [{0}:0] {1};'.format(intf._get_dtype().w-1,name))
        
        import_str_format  = ['%x']*len(self.inputs)
        export_str_format  = ['%x']*len(self.outputs)

        return wrapper_tmpl.substitute(
                                       port_definition='\n  '.join(ports_definition),
                                       import_str_format='"{0}"'.format(','.join(import_str_format)),
                                       in_port_list = ','.join(sorted(self.inputs.keys())),
                                       export_str_format='"{0}"'.format(','.join(export_str_format)),
                                       out_port_list = ','.join(sorted(self.outputs.keys())),
                                       module_instantiation = '\n\n'.join(module_insts)
                                       )

    def resolve_cosims(self):
        self.inputs = {}
        self.outputs = {}
        self.fileset = []
        for cosim in self.cosim_pool:
            cosim.resolve()
            self.inputs.update({'_'.join([cosim.module_name, k]):v for k,v in cosim.inputs.items()})
            self.outputs.update({'_'.join([cosim.module_name, k]):v for k,v in cosim.outputs.items()})
            self.fileset.extend(cosim.fileset)
    
    def send_command(self, type, params = []):
        msg = "$" + type
        if params:
            msg += ',' + ','.join(params)
            
        sydsys().server.send(msg)
        print(msg)

        ret = sydsys().server.recv().split(',')
        print(ret)
        if len(ret) > 1:
            params = ret[1:]
        else:
            params = []
            
        return ret[0][1:], params
    
    def get_xsim_state(self):
        cmd_type, params = self.send_command('GET', ['state'])
        
        if cmd_type != 'RESP':
            raise Exception('Error in the connection with Xsim!')
        
        return self.state_type[int(params[0])]
    
    def recv_export(self):
        ret_type, params = self.send_command('EXPORT')
        
        for intf, p in zip(sorted(self.outputs.items()), params):
            intf[1].write('0x' + p.replace('x', 'u').replace('z', 'u'))
            
        sydsys().sim._update()

                  
    def send_import(self):
        cmd_type, params = self.send_command('IMPORT', [str(intf.read())[2:].replace('U', 'x') for _, intf in sorted(self.inputs.items())])

        if cmd_type != 'RESP':
            raise Exception('Error in the connection with Xsim!')
    
    def sim_run_start(self, sim):
        self.cosim_time = 0
        self.resolve_cosims()
        os.makedirs(self.builddir, exist_ok=True)
        os.chdir(self.builddir)
        
#         print(self.render_wrapper())
        text = self.render_wrapper()
#         with open(os.path.join(self.builddir, "wrapper.sv"), "w") as text_file:
        with open("wrapper.sv", "w") as text_file:
            text_file.write(text)

#         self.fileset.append(os.path.join(self.builddir, "wrapper.sv"))
        self.fileset.append('wrapper.sv')

#         files = {'sv' : [],
#                  'v'  : [],
#                  'vhd': []
#                  }
#         
#         for f in self.fileset:
#             files[os.path.splitext(f)[1][1:]].append(f)
# 
#         if files['sv']:
#             _, _, ret = shell(cmd = ['xvlog', '-sv'] + files['sv'])
#             if ret:
#                 sydsys().server.sock.close()
#                 raise Exception('Error in HDL source compilation!') 
#          
#         if files['v']:
#             shell(cmd = ['xvlog'] + files['v'])
#          
#         if files['vhd']:
#             _,_,ret =shell(cmd = ['xvhdl'] + files['vhd'])
#             if ret:
#                 sydsys().server.sock.close()
#                 raise Exception('Error in HDL source compilation!') 
#  
#          
#         shell(cmd = ['xelab', '-m64', '-svlog', 'wrapper.sv', '-sv_root', '/home/bvukobratovic/projects/sydpy/intf/xsim/build', '-sv_lib', 'dpi', '-debug', 'all'])
# #         shell(cmd = ['xsim', 'work.wrap', '-t', '/home/bvukobratovic/projects/sydpy/tests/dpi/run.tcl'])
#         cmd = ['xsim', 'work.wrap', '--runall'] #-t', '/home/bvukobratovic/projects/sydpy/tests/dpi/run.tcl']
#         self.xsim_proc = Popen(' '.join(cmd), shell=True, stdout=PIPE, stderr=PIPE, universal_newlines=True)
        
        xsim_state = self.get_xsim_state()
        
        if xsim_state != 'S_CONNECTED':
            raise Exception('Error in the connection with Xsim!')
        
#         self.send_import()
        
        self.send_command('CONTINUE')
    
    def sim_run_end(self, sim):
        xsim_state = None
        while (xsim_state != 'S_DELAY'):
            xsim_state = self.get_xsim_state()
            if xsim_state != 'S_DELAY':
                self.send_command('CONTINUE')
            
        self.send_command('CLOSE')
#         self.xsim_proc.terminate()
    
    def sim_timestep_start(self, time, sim):
        if time > 0:
            xsim_state = self.get_xsim_state()
            # The XSIM either:
            #    - Waits at the end of the delta cycle (the always block) for new inputs
            #    - Waits to receive the timestep waiting period (delay)
            if xsim_state == 'S_EXPORT':
                # If XSIM waits at the end of the delta cycle, just send it to CONTINUE, this will affect no input signals, hence XSIM will move straight to timestep process
                self.send_command('CONTINUE')
                
            self.send_command('SET', ['delay', str(time - self.cosim_time - 1)])
            self.send_command('CONTINUE')

        self.cosim_time = time
        
        return True
    
    def sim_delta_settled(self, sim):
        # The XSIM is either in: 
        #    - initial import - This is the first finished sydpy delta cycle in the simultaion, 
        #    - timestep import - This is the first finished sydpy delta cycle in this timestep 
        #    - delta cycle import state
        self.send_import()
        self.send_command('CONTINUE')
        
        xsim_state = self.get_xsim_state()

        # The XSIM either:
        #    - Entered new delta cycle (the always block) since its outputs have changed
        #    - Entered the timestep process and is waiting for the length of the waiting period, since its outputs have settled
        if xsim_state == 'S_EXPORT':
            self.recv_export()
        elif xsim_state == 'S_DELAY':
            pass
        else:
            raise Exception('Error in the connection with Xsim!')
        
        return True
                    
    def updated(self, cosim):
#         self.update = True
        pass
    
    def register(self, cosim):
        self.cosim_pool.append(cosim)
        
    def __del__(self):
        try:
            sydsys().server.send('$CLOSE')
#             self.xsim_proc.terminate()
        except:
            pass class Server(Component):
    '''Simulator kernel.'''

    @compinit
    def __init__(self, host = '', port=60000, **kwargs):
        self.client = None
        self.sock = None
        backlog = 0
        try:
            self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            self.sock.bind((self.host,self.port))
        except Exception as e:
            raise Exception("Server port in use.")
        
#         logging.info('Socket port opened.')
        
        try:
            self.sock.listen(backlog)
#             set_keepalive_linux(self.sock)
        except:
            self.sock.close()
    
    def connect(self):
        print("Waiting for XSIM connection...")
        self.client, address = self.sock.accept()
#         logging.info('Client connected.')
#         client.send(vivhdr.encode())
#         self.client.setblocking(0)
    
    def send(self, msg):
        if not self.client:
            self.connect()
            
#         print("Sending: ", msg)
        self.client.send(msg.encode())

    def recv(self, size=1024):
        if not self.client:
            self.connect()
        
        data = None
        while not data:
            data = self.client.recv(size)
        
#         print("Receiving: ", data)
        
        return data.decode()
            
    def __del__(self):
        try:
            self.sock.close()
        except:
            pass class Profiler(Component):

    def coverage_done(self, sim):
        GreenletProfiler.stop()
        stats = GreenletProfiler.get_func_stats()
        stats.print_all(filter_in=['*sydpy*'])
        stats.save(self.out_path + '/profile.callgrind', type='callgrind')

    @compinit
    def __init__(self, out_path = '.', **kwargs):
       
        if (not os.path.isdir(self.out_path)):
            os.makedirs(self.out_path, exist_ok=True)
        
        sydsys().sim.events['run_end'].append(self.coverage_done)
        GreenletProfiler.set_clock_type('cpu')
        GreenletProfiler.start()
from sydpy.configurator import Configurator
from sydpy.component import Component, system, compinit
from sydpy.unit import Unit
from sydpy.channel import Channel
from sydpy.intfs.isig import isig
from sydpy.types import bit8, bit, bit64, bit32
from sydpy._delay import Delay
from sydpy.module import proc, Module
from sydpy.process import Process
from sydpy.simulator import Simulator
from sydpy.cosim import Cosim
from sydpy.xsim import XsimIntf
from sydpy.server import Server
from sydpy.extens.profiler import Profiler

class Generator(Component):
    
    @compinit 
    def __init__(self, chout, dtype=bit8, **kwargs):
        chout <<= self.inst('sout', isig, dtype=dtype, dflt=0)
        self.inst('p_gen', Process, self.gen, [Delay(20)])
    def gen(self):

        print("GEN : ", system['sim'].time, ': ', self.sout.read() + 1)