|
|
- import logging
- from cocotb.triggers import FallingEdge, RisingEdge, Timer, ReadOnly
-
-
- class Uart:
- """UART base class"""
-
- def __init__(self, txrx, clock, div, bits, parity, *args, **kwargs):
- self._version = "0.0.1"
-
- self.log = logging.getLogger(f"cocotb.{txrx._path}")
-
- self._txrx = txrx
- self._clock = clock
- self._div = div
- self._bits = bits
- self._par = parity
-
- self._clkedge = RisingEdge(self._clock)
-
- async def _wait_cycle(self):
- for x in range(self._div):
- await self._clkedge
-
- @staticmethod
- def odd_parity(data):
- parity = True
- while data:
- parity = not parity
- data = data & (data - 1)
- return int(parity)
-
-
- class UartReceiver(Uart):
-
- def __init__(self, txrx, clock, div, bits, parity, *args, **kwargs):
- super().__init__(txrx, clock, div, bits, parity, *args, **kwargs)
-
- self.log.info("UART receiver")
- self.log.info(" cocotbext-uart version %s", self._version)
- self.log.info(" Copyright (c) 2022 Torsten Meissner")
-
- async def receive(self):
- """Receive and return one UART frame"""
-
- # Wait for frame start
- await FallingEdge(self._txrx)
-
- # Consume start bit
- await self._get_start_bit()
-
- # Receive data bits
- self._rec = 0
- for x in range(self._bits):
- await self._wait_cycle()
- await ReadOnly()
- self._rec |= bool(self._txrx.value.integer) << x
-
- if self._par:
- # Consume parity bit
- await self._get_parity_bit()
-
- # Consume stop bit
- await self._get_stop_bit()
-
- self.log.info("Received data: %s", hex(self._rec))
- return self._rec
-
- async def _get_start_bit(self):
- """Consume and check start bit"""
- for x in range(int(self._div/2)):
- await self._clkedge
- await ReadOnly()
- if self._txrx.value == 1:
- self.log.warning("Start bit set")
-
- async def _get_stop_bit(self):
- """Consume and check stop bit"""
- await self._wait_cycle()
- await ReadOnly()
- if self._txrx.value == 0:
- self.log.warning("Stop bit not set")
-
- async def _get_parity_bit(self):
- """Consume and check parity bit"""
- await self._wait_cycle()
- await ReadOnly()
- if self.odd_parity(self._rec) != self._txrx.value:
- self.log.warning("Parity wrong")
-
-
- class UartDriver(Uart):
-
- def __init__(self, txrx, clock, div, bits, parity, *args, **kwargs):
- super().__init__(txrx, clock, div, bits, parity, *args, **kwargs)
-
- self.log.info("UART sender")
- self.log.info(" cocotbext-uart version %s", self._version)
- self.log.info(" Copyright (c) 2022 Torsten Meissner")
-
- # Drive input defaults (setimmediatevalue to avoid x asserts)
- self._txrx.setimmediatevalue(1)
-
- async def send(self, data):
- """Send one UART frame"""
-
- self._data = data;
-
- self.log.info("Sending data: %s", hex(self._data))
-
- # Send start bit
- await self._send_bit(0)
-
- # Send data bits
- for x in range(self._bits):
- self._txrx.value = (self._data >> x) & 1
- await self._wait_cycle()
-
-
- if self._par:
- # Send parity bit
- await self._send_bit(self.odd_parity(self._data))
-
- # Consume stop bit
- await self._send_bit(1)
-
- async def _send_bit(self, data):
- self._txrx.value = data
- await self._wait_cycle()
-
|