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
4.0 KiB

  1. import logging
  2. import cocotb
  3. from cocotb.utils import get_sim_time
  4. from cocotb.triggers import FallingEdge, RisingEdge, Timer, ReadOnly
  5. class Sram:
  6. def __init__(self, clk, wen, ren, adr, din, dout, mem, *args, **kwargs):
  7. self._version = "0.0.1"
  8. self.log = logging.getLogger(f"cocotb.{clk._path}")
  9. self._clk = clk
  10. self._wen = wen
  11. self._ren = ren
  12. self._adr = adr
  13. self._din = din
  14. self._dout = dout
  15. self._mem = mem
  16. self._clkedge = RisingEdge(self._clk)
  17. class SramRead(Sram):
  18. def __init__(self, clk, ren, adr, din, mem, *args, **kwargs):
  19. super().__init__(clk, None, ren, adr, din, None, mem, *args, **kwargs)
  20. self.log.info("SRAM read")
  21. self.log.info(" cocotbext-sram version %s", self._version)
  22. self.log.info(" Copyright (c) 2022 Torsten Meissner")
  23. self._active = None
  24. self._restart()
  25. def _restart(self):
  26. self.log.debug("SramRead._restart()")
  27. if self._active is not None:
  28. self._active.kill()
  29. # Schedule SRAM read to run concurrently
  30. self._active = cocotb.start_soon(self._read())
  31. async def _read(self):
  32. self.log.debug("SramRead._read()")
  33. while True:
  34. await self._clkedge
  35. if self._ren.value == 1:
  36. _data = self._mem[str(self._adr.value)]
  37. self._din.value = _data
  38. self.log.info("Read data: %s from adr: %s", hex(_data), hex(self._adr.value))
  39. class SramWrite(Sram):
  40. def __init__(self, clk, wen, adr, dout, mem, *args, **kwargs):
  41. super().__init__(clk, wen, None, adr, None, dout, mem, *args, **kwargs)
  42. self.log.info("SRAM write")
  43. self.log.info(" cocotbext-sram version %s", self._version)
  44. self.log.info(" Copyright (c) 2022 Torsten Meissner")
  45. self._active = None
  46. self._restart()
  47. def _restart(self):
  48. self.log.debug("SramWrite._restart()")
  49. if self._active is not None:
  50. self._active.kill()
  51. # Schedule SRAM write to run concurrently
  52. self._active = cocotb.start_soon(self._write())
  53. async def _write(self):
  54. self.log.debug("SramWrite._write()")
  55. while True:
  56. await self._clkedge
  57. if self._wen.value == 1:
  58. self._mem[str(self._adr.value)] = self._dout.value
  59. self.log.info("Wrote data: %s to adr: %s", hex(self._dout.value), hex(self._adr.value))
  60. class SramMonitor(Sram):
  61. def __init__(self, clk, wen, ren, adr, din, dout, *args, **kwargs):
  62. super().__init__(clk, wen, ren, adr, din, dout, None, *args, **kwargs)
  63. self.log.info("SRAM monitor")
  64. self.log.info(" cocotbext-sram version %s", self._version)
  65. self.log.info(" Copyright (c) 2022 Torsten Meissner")
  66. self._active = None
  67. self._transactions = {}
  68. self._restart()
  69. def _restart(self):
  70. self.log.debug("SramMonitor._restart()")
  71. if self._active is not None:
  72. self._active.kill()
  73. # Schedule SRAM read to run concurrently
  74. self._active = cocotb.start_soon(self._read())
  75. async def _read(self):
  76. self.log.debug("SramMonitor._read()")
  77. while True:
  78. await self._clkedge
  79. if self._wen.value:
  80. self._transactions[str(get_sim_time('ns'))] = {
  81. "type" : "write",
  82. "adr" : self._adr.value,
  83. "data" : self._dout.value}
  84. elif self._ren.value:
  85. _adr = self._adr.value
  86. await self._clkedge
  87. await ReadOnly()
  88. self._transactions[str(get_sim_time('ns'))] = {
  89. "type" : "read",
  90. "adr" : _adr,
  91. "data" : self._din.value}
  92. @property
  93. def transactions(self, index=None):
  94. if index:
  95. key = list(self._transactions.keys())[index]
  96. return {key: self._transactions[key]}
  97. else:
  98. return self._transactions