示例#1
0
    async def valid_cycle(self) -> None:

        self.log.debug(f"{str(self)} in valid_cycle")
        channel = self.itf['channel'].capture(
        ) if self.itf['channel'].instantiated else None
        data = self.itf['data'].capture(
        ) if self.itf['data'].instantiated else None
        empty = self.itf['empty'].capture(
        ) if self.itf['empty'].instantiated else None
        error = self.itf['error'].capture(
        ) if self.itf['error'].instantiated else None
        sop = self.itf['startofpacket'].capture(
        ) if self.itf['startofpacket'].instantiated else None
        eop = self.itf['endofpacket'].capture(
        ) if self.itf['endofpacket'].instantiated else None

        # Packet signal checks
        if self.itf.packets:
            if sop:
                if self.in_pkt:
                    raise ci.InterfaceProtocolError(
                        f"Duplicate startofpacket signal ({str(self.itf['startofpacket'])})"
                    )

                self.in_pkt = True

            if not self.in_pkt:
                raise ci.InterfaceProtocolError(
                    f"Attempted transfer outside of packet")

            if self.prev_channel is not None and channel != self.prev_channel:
                raise ci.InterfaceProtocolError(
                    f"Channel changed within packet ({self.prev_channel}->{channel})"
                )

        self.prev_channel = channel
        #     if not self._properties['maxChannel'] >= channel.integer >= 0:
        #         raise ProtocolError(
        #             f"Channel ({channel.integer}) out of valid range "
        #             f"({0}-{self._properties['maxChannel']})"
        #         )

        if data is not None:
            # Apply empty signal if supported
            if self.in_pkt and (self.itf.empty_within_packet or eop):
                data = self.itf.mask_data(data, empty)
            self.buff['data'].append(data)

        if error is not None:
            self.buff['error'].append(error)

        # Transaction completed
        if not self.itf.packets or eop:

            if self.prev_channel is not None:
                self.buff['channel'].append(self.prev_channel)

            self._release()
示例#2
0
    async def _event_loop(self) -> None:
        """
        Main event loop for behavioral models.
        """
        # TODO: (redd@) clean; use asyncio.get_event_loop ?
        # TODO: (redd@) don't block until a reaction is available?
        self.log.debug(f"{str(self)} looping...")

        #await ReadOnly() # Stabilize signals prior to sampling
        await self.trigger('advance')

        # TODO: (redd@) Reimplement to consider source (shouldn't error out in beginning of sim w/ lots of undefined signals)
        if self.state == 'TOP_NULL':
            raise ci.InterfaceProtocolError(
                f"Control context invariant was violated")

        # Delete cached values of influences, execute reactions TODO (redd@): revisit
        # for c in self.get_state(self.state).influences:
        #     self.itf[c].clear()

        for fn in self.get_state(self.state).reactions:
            # if fn.smode != ReadOnly:
            #     await NextTimeStep()
            #     await fn.smode()

            await fn(self)  # TODO: (redd@) fix method binding

        self.log.debug(f"{str(self)} looped!")
示例#3
0
 def mask_data(self, data: BinaryValue, empty: int) -> BinaryValue:
     """Returns data signal masked according to empty signal. """
     be = self.first_symbol_in_higher_order_bits
     vec = BinaryValue(bigEndian=be)
     val = data.value.binstr[:-empty] if be else data.value.binstr[empty:]
     vec.assign(val)
     if not vec.is_resolvable:
         raise ci.InterfaceProtocolError(
             f"Signal ({str(self['data'])} is unresolvable.")
     return vec
示例#4
0
    async def _process(self, trig: Awaitable) -> None:
        if not self.busy:
            raise ci.InterfaceProtocolError(f"{str(self)} not busy")

        self.log.debug(f"{str(self)} processing (trig={trig})...")

        while self.busy:
            await trig
            await self._event_loop()

        self.log.debug(f"{str(self)} processed!")
示例#5
0
 def _release(self, data: Optional[Dict] = None) -> None:
     """
     Relinquishes control of `self.lock`; optionally pass data to downstream coroutines.
     This assumes that the calling task is the current owner of lock.
     """
     if not self.busy:
         raise ci.InterfaceProtocolError(
             f"{str(self)} attempted release of non-existent busy-lock")
     self._busy = False
     self.lock.set(data)
     self.log.debug(f"{str(self)} released lock (data={data})")
示例#6
0
    def _specify(self, spec: Set[ci.signal.Signal],
                 precedes: bool = False,
                 bus_name: Optional[str] = None,
                 bus_separator: str = "_"):
        """
        Incorporate specifications into interface.

        Args:
            spec: `Signal` instances to add to interface specification.
            precedes: Asserted if `Control` instances within `spec` behaviorally-precede those
            currently specified in self.controls.
        """

        # TODO: (redd@) array_idx; account for naming variations e.g. w/ _n suffix
        def alias(s: ci.signal.Signal):
            return f"{bus_name}{bus_separator}{s.name}" if bus_name else s.name

        if not hasattr(self, '_signals'):
            self._signals = set()

        if any(any(s.name == t.name for t in spec) for s in self.signals):
            raise ValueError(f"Duplicate signals specified: {repr(spec)}")

        # Consider relative precedence for new Controls
        if any(isinstance(s, ci.signal.Control) for s in spec):
            offset = max(c for c in spec if isinstance(c, ci.signal.Control)).precedence if precedes else self.pmax
            if precedes:
                for c in self.controls:
                    if offset is not None:
                        c.precedence += (offset + 1)
            else:
                for c in spec:
                    if isinstance(c, ci.signal.Control):
                        if offset is not None:
                            c.precedence += (offset + 1)

        # Instantiate signals, bind filters
        for s in spec:
            if not hasattr(self.entity, alias(s)):
                if s.required:
                    raise ci.InterfaceProtocolError(f"{str(self)} missing required signal: {str(s)}")

                self.log.info(f"{str(self)} ignoring optional: {str(s)}")
            elif not s.instantiated:
                s.handle = getattr(self.entity, alias(s))

                for f in self._filters:
                    if f.cname == s.name:
                        s.filter = f

            self._signals.add(s)
            self.log.debug(f"{str(self)} applied: {str(spec)}")
示例#7
0
    def capture(self) -> _allowed:

        if not self.instantiated:
            raise AttributeError(f"Signal ({str(self)}) not instantiated")

        val = self.handle.value
        if not val.is_resolvable:
            raise ci.InterfaceProtocolError(
                f"Signal ({str(self)}) is unresolvable")

        if not self.logic_active_high:
            val.assign(~val.integer & len(self.handle))

        if self.filter is not None:
            self.filter(val)

        if self.logical_type == int:
            val = val.integer
        elif self.logical_type == bool:
            val = bool(val.integer)

        self.log.debug(f"{str(self)} captured sample: {repr(val)}")
        return val