quartus_tcl.py 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. import time
  2. import re
  3. import pexpect
  4. class QuartusTCL:
  5. def __init__(self):
  6. self.tcl = pexpect.spawn('quartus_stp --shell')
  7. self.tcl.expect('tcl> ')
  8. out = self.tcl.before
  9. self.version = 'Version unknown'
  10. for line in out.split(b'\n'):
  11. line = line.replace(b'\x1b[0m', b'').replace(b'\x1b[0;32m', b'')
  12. line = line.decode().strip()
  13. if line.startswith('Info: Version'):
  14. self.version = line[6:]
  15. break
  16. def send_cmd(self, cmd, timeout=45):
  17. self.tcl.sendline(cmd)
  18. try:
  19. self.tcl.expect('tcl> ', timeout=timeout)
  20. lines = self.tcl.before.decode().split('\r\n')[1:-1]
  21. return list(filter(None, lines))
  22. except pexpect.exceptions.TIMEOUT:
  23. raise QUATUS_TCL_TIMEOUT()
  24. def get_hardware_names(self):
  25. out = self.send_cmd('get_hardware_names')
  26. return re.findall(r'{([^\{]*)}', out[0])
  27. def get_device_names(self, hardware):
  28. out = self.send_cmd(f'get_device_names -hardware_name {{{hardware}}}')
  29. return re.findall(r'{([^\{]*)}', out[0])
  30. def start_insystem_source_probe(self, device, hardware):
  31. out = self.send_cmd(f'start_insystem_source_probe -device_name {{{device}}} -hardware_name {{{hardware}}}')
  32. if len(out) > 0 and out[0].startswith('ERROR'):
  33. raise INSYS_SPI_ERROR(out[0][7:])
  34. def read_probe_data(self, index, value_in_hex=False):
  35. cmd = f'read_probe_data -instance_index {index}'
  36. if value_in_hex:
  37. cmd += ' -value_in_hex'
  38. out = self.send_cmd(cmd)
  39. if len(out) > 0 and out[0].startswith('ERROR'):
  40. raise INSYS_SPI_ERROR(out[0][7:])
  41. if len(out) == 0:
  42. return ''
  43. return out[0]
  44. def write_source_data(self, index, value, value_in_hex=False):
  45. cmd = f'write_source_data -instance_index {index} -value "{value}"'
  46. if value_in_hex:
  47. cmd += ' -value_in_hex'
  48. out = self.send_cmd(cmd)
  49. if len(out) > 0 and out[0].startswith('ERROR'):
  50. raise INSYS_SPI_ERROR(out[0][7:])
  51. def read_source_data(self, index, value_in_hex=False):
  52. cmd = f'read_source_data -instance_index {index}'
  53. if value_in_hex:
  54. cmd += ' -value_in_hex'
  55. out = self.send_cmd(cmd)
  56. if len(out) > 0 and out[0].startswith('ERROR'):
  57. raise INSYS_SPI_ERROR(out[0][7:])
  58. if len(out) == 0:
  59. return ''
  60. return out[0]
  61. def end_insystem_source_probe(self):
  62. out = self.send_cmd(f'end_insystem_source_probe')
  63. if len(out) > 0 and out[0].startswith('ERROR'):
  64. raise INSYS_SPI_ERROR(out[0][7:])
  65. def begin_memory_edit(self, device, hardware):
  66. out = self.send_cmd(f'begin_memory_edit -device_name {{{device}}} -hardware_name {{{hardware}}}')
  67. if len(out) > 0 and out[0].startswith('ERROR'):
  68. raise INSYS_MEM_ERROR(out[0][7:])
  69. def end_memory_edit(self):
  70. out = self.send_cmd(f'end_memory_edit')
  71. if len(out) > 0 and out[0].startswith('ERROR'):
  72. raise INSYS_MEM_ERROR(out[0][7:])
  73. def get_editable_mem_instances(self, device, hardware):
  74. """
  75. :param device:
  76. :param hardware:
  77. :return: list of tuple [<index> <depth> <width> <read/write mode> <instance type> <instance name>]
  78. """
  79. out = self.send_cmd(f'get_editable_mem_instances -device_name {{{device}}} -hardware_name {{{hardware}}}')
  80. res = []
  81. if len(out) == 0:
  82. return res
  83. if out[0].startswith('ERROR'):
  84. raise INSYS_MEM_ERROR(out[0][7:])
  85. for i in re.findall(r'{([^\{]*)}', out[0]):
  86. try:
  87. c = i.split(' ')
  88. res.append((int(c[0]), int(c[1]), int(c[2]), c[3], c[4], c[5]))
  89. except (IndexError, ValueError):
  90. continue
  91. return res
  92. def read_content_from_memory(self, index, start_address, word_count, content_in_hex=False):
  93. cmd = f'read_content_from_memory -instance_index {index} -start_address {start_address} ' \
  94. f'-word_count {word_count}'
  95. if content_in_hex:
  96. cmd += ' -content_in_hex'
  97. out = self.send_cmd(cmd)
  98. if len(out) == 0:
  99. return ''
  100. if out[0].startswith('ERROR'):
  101. raise INSYS_MEM_ERROR(out[0][7:])
  102. return out[0]
  103. def write_content_to_memory(self, index, start_address, word_count, content, content_in_hex=False):
  104. cmd = f'read_content_from_memory -content "{content}" -instance_index {index} ' \
  105. f'-start_address {start_address} -word_count {word_count}'
  106. if content_in_hex:
  107. cmd += ' -content_in_hex'
  108. out = self.send_cmd(cmd)
  109. if len(out) > 0 and out[0].startswith('ERROR'):
  110. raise INSYS_MEM_ERROR(out[0][7:])
  111. def get_insystem_source_probe_instance_info(self, device, hardware):
  112. """
  113. :param device:
  114. :param hardware:
  115. :return: list of tuple [<index> <source width> <probe width> <instance name>]
  116. """
  117. out = self.send_cmd(
  118. f'get_insystem_source_probe_instance_info -device_name {{{device}}} -hardware_name {{{hardware}}}')
  119. res = []
  120. if len(out) == 0:
  121. return res
  122. if out[0].startswith('ERROR'):
  123. raise INSYS_SPI_ERROR(out[0][7:])
  124. for i in re.findall(r'{([^\{]*)}', out[0]):
  125. try:
  126. c = i.split(' ')
  127. res.append((int(c[0]), int(c[1]), int(c[2]), c[3]))
  128. except (IndexError, ValueError):
  129. continue
  130. return res
  131. def disconnect(self):
  132. self.tcl.sendline('exit')
  133. time.sleep(0.1)
  134. if self.tcl.isalive():
  135. self.tcl.kill(1)
  136. class QUARTUS_TCL_EXCEPTION(Exception):
  137. pass
  138. class QUATUS_TCL_TIMEOUT(QUARTUS_TCL_EXCEPTION):
  139. pass
  140. class INSYS_SPI_ERROR(QUARTUS_TCL_EXCEPTION):
  141. def __init__(self, message):
  142. self.message = message
  143. class INSYS_MEM_ERROR(QUARTUS_TCL_EXCEPTION):
  144. def __init__(self, message):
  145. self.message = message