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.

94 lines
3.2 KiB

  1. import logging
  2. import random
  3. import cocotb
  4. import wavedrom
  5. from collections import defaultdict
  6. from Sram import SramRead, SramWrite, SramMonitor
  7. from cocotb.clock import Clock
  8. from cocotb.triggers import RisingEdge, Timer
  9. from cocotbext.wishbone.driver import WishboneMaster, WBOp
  10. from cocotb.wavedrom import Wavedrom, trace
  11. # Reset coroutine
  12. async def reset_dut(reset_n, duration_ns):
  13. reset_n.value = 1
  14. await Timer(duration_ns, units="ns")
  15. reset_n.value = 0
  16. def wave2svg(wave, file):
  17. svg = wavedrom.render(wave)
  18. svg.saveas(file)
  19. @cocotb.test()
  20. async def test_wishbone(dut):
  21. """ First simple test """
  22. clkedge = RisingEdge(dut.wbclk_i)
  23. # Connect reset
  24. reset = dut.wbrst_i
  25. # Create empty SRAM memory
  26. memory = defaultdict()
  27. mem_read = SramRead(dut.wbclk_i, dut.localren_o,
  28. dut.localadress_o, dut.localdata_i, memory);
  29. mem_write = SramWrite(dut.wbclk_i, dut.localwen_o,
  30. dut.localadress_o, dut.localdata_o, memory);
  31. sram_monitor = SramMonitor(dut.wbclk_i, dut.localwen_o, dut.localren_o,
  32. dut.localadress_o, dut.localdata_i, dut.localdata_o);
  33. wbmaster = WishboneMaster(dut, "", dut.wbclk_i,
  34. width=16, # size of data bus
  35. timeout=10, # in clock cycle number
  36. signals_dict={"cyc": "wbcyc_i",
  37. "stb": "wbstb_i",
  38. "we": "wbwe_i",
  39. "adr": "wbadr_i",
  40. "datwr":"wbdat_i",
  41. "datrd":"wbdat_o",
  42. "ack": "wback_o" })
  43. # Drive input defaults (setimmediatevalue to avoid x asserts)
  44. dut.wbcyc_i.setimmediatevalue(0)
  45. dut.wbstb_i.setimmediatevalue(0)
  46. dut.wbwe_i.setimmediatevalue(0)
  47. dut.wbadr_i.setimmediatevalue(0)
  48. dut.wbdat_i.setimmediatevalue(0)
  49. clock = Clock(dut.wbclk_i, 10, units="ns") # Create a 10 ns period clock
  50. cocotb.start_soon(clock.start()) # Start the clock
  51. # Execution will block until reset_dut has completed
  52. await reset_dut(reset, 100)
  53. dut._log.info("Released reset")
  54. # Trace transmissions using wavedrom
  55. with trace(dut.wbcyc_i, dut.wbstb_i, dut.wbwe_i, dut.wback_o,
  56. dut.wbadr_i, dut.wbdat_i, dut.wbdat_o, clk=dut.wbclk_i) as waves:
  57. # Test 10 Wishbone transmissions
  58. for i in range(10):
  59. await clkedge
  60. adr = random.randint(0, 255)
  61. data = random.randint(0, 2**16-1)
  62. await wbmaster.send_cycle([WBOp(adr=adr, dat=data)])
  63. rec = await wbmaster.send_cycle([WBOp(adr=adr)])
  64. assert rec[0].datrd == data, \
  65. f"Read data incorrect, got {hex(rec[0].datrd)}, expected {hex(data)}"
  66. # Print out waveforms as json & svg
  67. _wave = waves.dumpj()
  68. with open('results/tb_wishbone_wave.json', 'w', encoding='utf-8') as f:
  69. f.write(_wave)
  70. wave2svg(_wave, 'results/tb_wishbone_wave.svg')
  71. # Example to print transactions collected by SRAM monitor
  72. with open('results/tb_wishbone_sram_transactions.log', 'w', encoding='utf-8') as f:
  73. f.write((f"{'Time':7}{'Type':7}{'Adr':6}{'Data'}\n"))
  74. for key, value in sram_monitor.transactions.items():
  75. f.write((f"{key:7}{value['type']:7}{hex(value['adr']):6}{hex(value['data'])}\n"))