Examples of using cocotb for functional verification of VHDL designs with GHDL.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

126 lines
3.4 KiB

  1. import logging
  2. from cocotb.triggers import FallingEdge, RisingEdge, Timer
  3. class Uart:
  4. """UART base class"""
  5. def __init__(self, txrx, clock, div, bits, parity, *args, **kwargs):
  6. self._version = "0.0.1"
  7. self.log = logging.getLogger(f"cocotb.{txrx._path}")
  8. self._txrx = txrx
  9. self._clock = clock
  10. self._div = div
  11. self._bits = bits
  12. self._par = parity
  13. self._clkedge = RisingEdge(self._clock)
  14. async def _wait_cycle(self):
  15. for x in range(self._div):
  16. await self._clkedge
  17. @staticmethod
  18. def odd_parity(data):
  19. parity = True
  20. while data:
  21. parity = not parity
  22. data = data & (data - 1)
  23. return int(parity)
  24. class UartReceiver(Uart):
  25. def __init__(self, txrx, clock, div, bits, parity, *args, **kwargs):
  26. super().__init__(txrx, clock, div, bits, parity, *args, **kwargs)
  27. self.log.info("UART receiver")
  28. self.log.info(" cocotbext-uart version %s", self._version)
  29. self.log.info(" Copyright (c) 2022 Torsten Meissner")
  30. async def receive(self):
  31. """Receive and return one UART frame"""
  32. # Wait for frame start
  33. await FallingEdge(self._txrx)
  34. # Consume start bit
  35. await self._get_start_bit()
  36. # Receive data bits
  37. self._rec = 0
  38. for x in range(self._bits):
  39. await self._wait_cycle()
  40. self._rec |= bool(self._txrx.value.integer) << x
  41. if self._par:
  42. # Consume parity bit
  43. await self._get_parity_bit()
  44. # Consume stop bit
  45. await self._get_stop_bit()
  46. self.log.info("Received data: %s", hex(self._rec))
  47. return self._rec
  48. async def _get_start_bit(self):
  49. """Consume and check start bit"""
  50. for x in range(int(self._div/2)):
  51. await self._clkedge
  52. if self._txrx.value == 1:
  53. self.log.warning("Start bit set")
  54. async def _get_stop_bit(self):
  55. """Consume and check stop bit"""
  56. await self._wait_cycle()
  57. if self._txrx.value == 0:
  58. self.log.warning("Stop bit not set")
  59. async def _get_parity_bit(self):
  60. """Consume and check parity bit"""
  61. await self._wait_cycle()
  62. if self.odd_parity(self._rec) != self._txrx.value:
  63. self.log.warning("Parity wrong")
  64. class UartDriver(Uart):
  65. def __init__(self, txrx, clock, div, bits, parity, *args, **kwargs):
  66. super().__init__(txrx, clock, div, bits, parity, *args, **kwargs)
  67. self.log.info("UART sender")
  68. self.log.info(" cocotbext-uart version %s", self._version)
  69. self.log.info(" Copyright (c) 2022 Torsten Meissner")
  70. # Drive input defaults (setimmediatevalue to avoid x asserts)
  71. self._txrx.setimmediatevalue(1)
  72. async def send(self, data):
  73. """Send one UART frame"""
  74. self._data = data;
  75. self.log.info("Sending data: %s", hex(self._data))
  76. # Send start bit
  77. await self._send_bit(0)
  78. # Send data bits
  79. for x in range(self._bits):
  80. self._txrx.value = (self._data >> x) & 1
  81. await self._wait_cycle()
  82. if self._par:
  83. # Send parity bit
  84. await self._send_bit(self.odd_parity(self._data))
  85. # Consume stop bit
  86. await self._send_bit(1)
  87. async def _send_bit(self, data):
  88. self._txrx.value = data
  89. await self._wait_cycle()