memtest.py 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799
  1. #!/usr/bin/env python3
  2. #
  3. # memtest.py
  4. #
  5. # Base utiity/driver classes for the various control software variants
  6. #
  7. # Copyright (C) 2020-2021 Sylvain Munaut <tnt@246tNt.com>
  8. # SPDX-License-Identifier: MIT
  9. #
  10. import binascii
  11. import random
  12. import serial
  13. import sys
  14. # ----------------------------------------------------------------------------
  15. # Serial commands
  16. # ----------------------------------------------------------------------------
  17. class WishboneInterface(object):
  18. COMMANDS = {
  19. 'SYNC' : 0,
  20. 'REG_ACCESS' : 1,
  21. 'DATA_SET' : 2,
  22. 'DATA_GET' : 3,
  23. 'AUX_CSR' : 4,
  24. }
  25. def __init__(self, port):
  26. self.ser = ser = serial.Serial()
  27. ser.port = port
  28. ser.baudrate = 2000000
  29. ser.stopbits = 2
  30. ser.timeout = 0.1
  31. ser.open()
  32. if not self.sync():
  33. raise RuntimeError("Unable to sync")
  34. def sync(self):
  35. for i in range(10):
  36. self.ser.write(b'\x00')
  37. d = self.ser.read(4)
  38. if (len(d) == 4) and (d == b'\xca\xfe\xba\xbe'):
  39. return True
  40. return False
  41. def write(self, addr, data):
  42. cmd_a = ((self.COMMANDS['DATA_SET'] << 36) | data).to_bytes(5, 'big')
  43. cmd_b = ((self.COMMANDS['REG_ACCESS'] << 36) | addr).to_bytes(5, 'big')
  44. self.ser.write(cmd_a + cmd_b)
  45. def read(self, addr):
  46. cmd_a = ((self.COMMANDS['REG_ACCESS'] << 36) | (1<<20) | addr).to_bytes(5, 'big')
  47. cmd_b = ((self.COMMANDS['DATA_GET'] << 36)).to_bytes(5, 'big')
  48. self.ser.write(cmd_a + cmd_b)
  49. d = self.ser.read(4)
  50. if len(d) != 4:
  51. raise RuntimeError('Comm error')
  52. return int.from_bytes(d, 'big')
  53. def aux_csr(self, value):
  54. cmd = ((self.COMMANDS['AUX_CSR'] << 36) | value).to_bytes(5, 'big')
  55. self.ser.write(cmd)
  56. # ----------------------------------------------------------------------------
  57. # QSPI controller
  58. # ----------------------------------------------------------------------------
  59. class QSPIController(object):
  60. CORE_REGS = {
  61. 'csr': 0,
  62. 'rf': 3,
  63. }
  64. def __init__(self, intf, base, cs=0):
  65. self.intf = intf
  66. self.base = base
  67. self.cs = cs
  68. self._end()
  69. def _write(self, reg, val):
  70. self.intf.write(self.base + self.CORE_REGS.get(reg, reg), val)
  71. def _read(self, reg):
  72. return self.intf.read(self.base + self.CORE_REGS.get(reg, reg))
  73. def _begin(self):
  74. # Request external control
  75. self._write('csr', 0x00000004 | (self.cs << 4))
  76. self._write('csr', 0x00000002 | (self.cs << 4))
  77. def _end(self):
  78. # Release external control
  79. self._write('csr', 0x00000004)
  80. def spi_xfer(self, tx_data, dummy_len=0, rx_len=0):
  81. # Start transaction
  82. self._begin()
  83. # Total length
  84. l = len(tx_data) + rx_len + dummy_len
  85. # Prep buffers
  86. tx_data = tx_data + bytes( ((l + 3) & ~3) - len(tx_data) )
  87. rx_data = b''
  88. # Run
  89. while l > 0:
  90. # Word and command
  91. w = int.from_bytes(tx_data[0:4], 'big')
  92. c = 0x13 if l >= 4 else (0x10 + l - 1)
  93. s = 0 if l >= 4 else 8*(4-l)
  94. # Issue
  95. self._write(c, w);
  96. w = self._read('rf')
  97. # Get RX
  98. rx_data = rx_data + ((w << s) & 0xffffffff).to_bytes(4, 'big')
  99. # Next
  100. l = l - 4
  101. tx_data = tx_data[4:]
  102. # End transaction
  103. self._end()
  104. # Return interesting part
  105. return rx_data[-rx_len:]
  106. def _qpi_tx(self, data, command=False):
  107. while len(data):
  108. # Base command
  109. cmd = 0x1c if command else 0x18
  110. # Grab chunk
  111. word = data[0:4]
  112. data = data[4:]
  113. cmd |= len(word) - 1
  114. word = word + bytes(-len(word) & 3)
  115. # Transmit
  116. self._write(cmd, int.from_bytes(word, 'big'));
  117. def _qpi_rx(self, l):
  118. data = b''
  119. while l > 0:
  120. # Issue read
  121. wl = 4 if l >= 4 else l
  122. cmd = 0x14 | (wl-1)
  123. self._write(cmd, 0)
  124. word = self._read('rf')
  125. # Accumulate
  126. data = data + (word & (0xffffffff >> (8*(4-wl)))).to_bytes(wl, 'big')
  127. # Next
  128. l = l - 4
  129. return data
  130. def qpi_xfer(self, cmd=b'', payload=b'', dummy_len=0, rx_len=0):
  131. # Start transaction
  132. self._begin()
  133. # TX command
  134. if cmd:
  135. self._qpi_tx(cmd, True)
  136. # TX payload
  137. if payload:
  138. self._qpi_tx(payload, False)
  139. # Dummy
  140. if dummy_len:
  141. self._qpi_rx(dummy_len)
  142. # RX payload
  143. if rx_len:
  144. rv = self._qpi_rx(rx_len)
  145. else:
  146. rv = None
  147. # End transaction
  148. self._end()
  149. return rv
  150. # ----------------------------------------------------------------------------
  151. # HyperRAM controller
  152. # ----------------------------------------------------------------------------
  153. class HyperRAMController(object):
  154. CORE_REGS = {
  155. 'csr': 0,
  156. 'cmd': 1,
  157. 'wq0': 2,
  158. 'wq1': 3,
  159. }
  160. CSR_RUN = (1 << 0)
  161. CSR_RESET = (1 << 1)
  162. CSR_IDLE_CFG = (1 << 2)
  163. CSR_IDLE_RUN = (1 << 3)
  164. CSR_CMD_LAT = lambda self, x: ((x-1) & 15) << 8
  165. CSR_CAP_LAT = lambda self, x: ((x-1) & 15) << 12
  166. CSR_PHY_DELAY = lambda self, x: (x & 15) << 16
  167. CSR_PHY_PHASE = lambda self, x: (x & 3) << 20
  168. CSR_PHY_EDGE = lambda self, x: (x & 1) << 22
  169. CMD_LEN = lambda self, x: ((x-1) & 15) << 8
  170. CMD_LAT = lambda self, x: ((x-1) & 15) << 4
  171. CMD_CS = lambda self, x: (x & 3) << 2
  172. CMD_REG = (1 << 1)
  173. CMD_MEM = (0 << 1)
  174. CMD_READ = (1 << 0)
  175. CMD_WRITE = (0 << 0)
  176. # Selected so:
  177. # - each byte is unique
  178. # - ORing all bytes in a single word == 255
  179. # - ANDing all bytes in a single word == 0
  180. CAL_WORDS = [ 0x600dbabe, 0xb16b00b5 ]
  181. # Register addresses
  182. HYPERRAM_REGS = {
  183. 'id0': 0,
  184. 'id1': 1,
  185. 'cr0': 0 | (1 << 11),
  186. 'cr1': 1 | (1 << 11),
  187. }
  188. def __init__(self, intf, base, latency=3, csm=0xf, burst_len=128):
  189. self.intf = intf
  190. self.base = base
  191. self.latency = latency
  192. self.csm = csm
  193. self.burst_len = burst_len
  194. # We're always in 2x latency mode, also the location where
  195. # latency start and the 1 cycle added by the core because it works
  196. # 32 bit at a time means we can remove 2 cycles of the latency
  197. self._cmd_latency = (2 * latency - 2) // 2
  198. def _write(self, reg, val):
  199. self.intf.write(self.base + self.CORE_REGS[reg], val)
  200. def _read(self, reg):
  201. return self.intf.read(self.base + self.CORE_REGS[reg])
  202. def _cr0(self, dpd=False, drive_strength=None, latency=6, fixed_latency=True, hybrid_burst=True, burst_len=32):
  203. DRIVE = {
  204. None: 0,
  205. 115: 1,
  206. 67: 2,
  207. 46: 3,
  208. 34: 4,
  209. 27: 5,
  210. 22: 6,
  211. 19: 7,
  212. }
  213. LATENCY = {
  214. 3: 14,
  215. 4: 15,
  216. 5: 0,
  217. 6: 1,
  218. }
  219. BURST_LEN = {
  220. 128: 0,
  221. 64: 1,
  222. 32: 3,
  223. 16: 2,
  224. }
  225. return (
  226. ((dpd ^ 1) << 15) |
  227. (DRIVE[drive_strength] << 12) |
  228. (0xf << 8) |
  229. (LATENCY[latency] << 4) |
  230. (fixed_latency << 3) |
  231. (hybrid_burst << 2) |
  232. (BURST_LEN[burst_len] << 0)
  233. )
  234. def _cr1(self, dri=None):
  235. DRI = {
  236. None: 2,
  237. "1x": 2 ,
  238. "1.5x": 3,
  239. "2x": 0,
  240. "4x": 1,
  241. }
  242. return DRI[dri]
  243. def _ca(self, addr, rwn=0, reg=0, linear=0):
  244. return (
  245. (rwn << 47) |
  246. (reg << 46) |
  247. ((linear | reg) << 45) |
  248. ((addr >> 3) << 16) |
  249. ((addr & 7) << 0)
  250. )
  251. def _wait_idle(self):
  252. # Wait until it's in IDLE Config mode
  253. for i in range(10):
  254. if self._read('csr') & self.CSR_IDLE_CFG:
  255. break
  256. else:
  257. raise RuntimeError('HyperRAM controller timeout')
  258. def _reg_write(self, cs, reg, val):
  259. ca = self._ca(self.HYPERRAM_REGS[reg], rwn=0, reg=1)
  260. self._write('wq1', 0x30)
  261. self._write('wq0', ca >> 16)
  262. self._write('wq0', ((ca & 0xffff) << 16) | val)
  263. self._write('wq0', 0)
  264. self._write('cmd',
  265. self.CMD_CS(cs) |
  266. self.CMD_REG |
  267. self.CMD_WRITE
  268. )
  269. self._wait_idle()
  270. def _reg_read(self, cs, reg):
  271. ca = self._ca(self.HYPERRAM_REGS[reg], rwn=1, reg=1)
  272. self._write('wq1', 0x30)
  273. self._write('wq0', ca >> 16)
  274. self._write('wq1', 0x20)
  275. self._write('wq0', (ca & 0xffff) << 16)
  276. self._write('wq1', 0x00)
  277. self._write('wq0', 0)
  278. self._write('cmd',
  279. self.CMD_LAT(self._cmd_latency) |
  280. self.CMD_CS(cs) |
  281. self.CMD_REG |
  282. self.CMD_READ
  283. )
  284. self._wait_idle()
  285. rv = []
  286. for i in range(3):
  287. w1 = self._read('wq1')
  288. w0 = self._read('wq0')
  289. rv.append( (w0, w1) )
  290. return rv[-1][0] >> 16
  291. def _mem_write(self, cs, addr, val, count=1, mask=0x0):
  292. ca = self._ca(addr, rwn=0, reg=0)
  293. self._write('wq1', 0x30)
  294. self._write('wq0', ca >> 16)
  295. self._write('wq1', 0x20)
  296. self._write('wq0', (ca & 0xffff) << 16)
  297. self._write('wq1', 0x30 | mask)
  298. self._write('wq0', val)
  299. self._write('cmd',
  300. self.CMD_LEN(count) |
  301. self.CMD_LAT(self._cmd_latency) |
  302. self.CMD_CS(cs) |
  303. self.CMD_MEM |
  304. self.CMD_WRITE
  305. )
  306. self._wait_idle()
  307. def _mem_read(self, cs, addr, count=3):
  308. if count > 3:
  309. raise ValueError('Unable to read more than 3 words at a time')
  310. ca = self._ca(addr, rwn=1, reg=0)
  311. self._write('wq1', 0x30)
  312. self._write('wq0', ca >> 16)
  313. self._write('wq1', 0x20)
  314. self._write('wq0', (ca & 0xffff) << 16)
  315. self._write('wq1', 0x00)
  316. self._write('wq0', 0)
  317. self._write('cmd',
  318. self.CMD_LEN(count) |
  319. self.CMD_LAT(self._cmd_latency) |
  320. self.CMD_CS(cs) |
  321. self.CMD_MEM |
  322. self.CMD_READ
  323. )
  324. self._wait_idle()
  325. rv = []
  326. for i in range(3):
  327. w1 = self._read('wq1')
  328. w0 = self._read('wq0')
  329. rv.append( (w0, w1) )
  330. return rv[-count:]
  331. def _train_check_edge_delay(self, cs, edge, delay):
  332. # Configure for base capture latency and phase
  333. self._write('csr',
  334. self.CSR_PHY_EDGE(edge) |
  335. self.CSR_PHY_PHASE(0) |
  336. self.CSR_PHY_DELAY(delay) |
  337. self.CSR_CMD_LAT(self._cmd_latency) |
  338. self.CSR_CAP_LAT(3)
  339. )
  340. # Find the capture latency and phase
  341. data = self._mem_read(cs, 0, count=3)
  342. for w,a in data:
  343. print(f"{bin(a)} {w:08x}")
  344. for i in range(3):
  345. if (data[i][1] & 0xf):
  346. break
  347. else:
  348. return None
  349. for j in range(4):
  350. if data[i][1] & (8 >> j):
  351. break
  352. cap_latency = 3 + i + (j > 0)
  353. phase = (4 - j) % 4
  354. # Re-configure core
  355. self._write('csr',
  356. self.CSR_PHY_EDGE(edge) |
  357. self.CSR_PHY_PHASE(phase) |
  358. self.CSR_PHY_DELAY(delay) |
  359. self.CSR_CMD_LAT(self._cmd_latency) |
  360. self.CSR_CAP_LAT(cap_latency)
  361. )
  362. # Confirm data
  363. data = self._mem_read(cs, 0, count=3)
  364. ref = [
  365. (self.CAL_WORDS[0], 0x3a),
  366. (self.CAL_WORDS[1], 0x3a),
  367. (self.CAL_WORDS[0], 0x3a),
  368. ]
  369. if data != ref:
  370. return None
  371. return (cap_latency, phase)
  372. def _train_consolidate(self, train):
  373. # Checks combination valid for all chips
  374. rv = {}
  375. for delay, results in train.items():
  376. r = [v for k,v in results.items() if self.csm & (1 << k)]
  377. for x in r:
  378. if (x is None) or (x != r[0]):
  379. print("[.] delay=%2d -> Invalid" % delay)
  380. rv[delay] = None
  381. break
  382. else:
  383. print("[.] delay=%2d -> cap_latency=%d, phase=%d" % (delay, *r[0]))
  384. rv[delay] = r[0]
  385. return rv
  386. def _train_group(self, train):
  387. groups = []
  388. c_v = None
  389. c_d = []
  390. c_first = False
  391. c_last = False
  392. for idx, (delay, result) in enumerate(sorted(train.items())):
  393. # First / Last checks
  394. is_first = idx == 0
  395. is_last = idx == (len(train) - 1)
  396. # Continue ?
  397. if result and (c_v == result):
  398. c_d.append(delay)
  399. c_first |= is_first
  400. c_last |= is_last
  401. # Or not ...
  402. else:
  403. # Flush current
  404. if c_v is not None:
  405. groups.append( (c_v, c_d, c_first, c_last) )
  406. # New item
  407. c_v = result
  408. c_d = [ delay ]
  409. c_first = is_first
  410. c_last = is_last
  411. if c_v is not None:
  412. groups.append( (c_v, c_d, c_first, c_last) )
  413. return groups
  414. def _train_pick_params(self, best):
  415. # Pick delay
  416. if best[2] and best[3]:
  417. d = (best[1][0] + best[1][-1]) // 2
  418. elif best[2]:
  419. d = min(best[1])
  420. elif best[3]:
  421. d = max(best[1])
  422. else:
  423. d = int(round(sum(best[1]) / len(best[1])))
  424. # If the group is only a single value 'wide', print warning it might be marginal
  425. if len(best[1]) == 1:
  426. print("[w] Training results might be marginal. Consider switching capture clock phase by 90 deg")
  427. # Return delay and params
  428. return d, best[0][0], best[0][1]
  429. def init(self):
  430. # Reset HyperRAM and controller
  431. self._write('csr', self.CSR_RESET)
  432. self._wait_idle()
  433. self._write('csr', 0)
  434. self._wait_idle()
  435. # Chip config
  436. self.cr0 = self._cr0(latency=self.latency, burst_len=self.burst_len)
  437. self.cr1 = self._cr1()
  438. # DEBUG
  439. if False:
  440. cs = 0
  441. for i in range(5):
  442. print(hex(self.cr0))
  443. self._reg_write(cs, 'cr0', self.cr0)
  444. self._mem_write(cs, 0, self.CAL_WORDS[0], count=3)
  445. self._mem_write(cs, 2, self.CAL_WORDS[1], count=1)
  446. self._write('csr',
  447. self.CSR_PHY_EDGE(1) |
  448. self.CSR_PHY_PHASE(0) |
  449. self.CSR_PHY_DELAY(0) |
  450. self.CSR_CMD_LAT(self._cmd_latency) |
  451. self.CSR_CAP_LAT(3)
  452. )
  453. print(f"{self._read('csr'):08x}")
  454. for w,a in self._mem_read(cs, 0, count=3):
  455. print(f"{bin(a)} {w:08x}")
  456. return False
  457. # Execute configuration and training on all chips
  458. edge = 1
  459. train = {}
  460. for cs in range(4):
  461. if not self.csm & (1 << cs):
  462. continue
  463. # Debug
  464. print("[+] Training CS=%d" % cs)
  465. # CR write
  466. self._reg_write(cs, 'cr0', self.cr0)
  467. self._reg_write(cs, 'cr1', self.cr1)
  468. # Write the calibration words
  469. self._mem_write(cs, 0, self.CAL_WORDS[0], count=3)
  470. self._mem_write(cs, 2, self.CAL_WORDS[1], count=1)
  471. # Scan delays
  472. any_valid = False
  473. for delay in [0, 5, 10, 15]:
  474. d = self._train_check_edge_delay(cs, edge, delay)
  475. print("[.] delay=%2d -> %s" % (delay, "Failed" if (d is None) else ("cap_latency=%d, phase=%d" % d)))
  476. train.setdefault(delay, {})[cs] = d
  477. any_valid |= d is not None
  478. # If nothing valid found, assume chip is missing
  479. if not any_valid:
  480. print("[w] No working delay found, assuming chip is missing: disabling it !")
  481. self.csm &= ~(1 << cs)
  482. # Are any chips still enabled ?
  483. if not self.csm:
  484. print("[!] All chips disabled, somethins is wrong ...")
  485. return False
  486. # Find the best combination
  487. print("[+] Compiling training results")
  488. # Check what works for all chips
  489. train = self._train_consolidate(train)
  490. if not any(train.values()):
  491. print("[!] Unable to find single valid combination for all chips :(")
  492. return False
  493. # Group them
  494. groups = self._train_group(train)
  495. # Pick best group
  496. best = sorted(groups, key=lambda x: len(x[1]) + 2 * (x[2] + x[3]), reverse=True)[0]
  497. # Select delay
  498. self._delay, self._cap_latency, self._phase = self._train_pick_params(best)
  499. # Load final configuration
  500. print("[+] Core configured for cmd_latency=%d, capture_latency=%d, phase=%d, delay=%d" % (
  501. self._cmd_latency, self._cap_latency, self._phase, self._delay
  502. ))
  503. self._csr = (
  504. self.CSR_PHY_EDGE(edge) |
  505. self.CSR_PHY_PHASE(self._phase) |
  506. self.CSR_PHY_DELAY(self._delay) |
  507. self.CSR_CMD_LAT(self._cmd_latency) |
  508. self.CSR_CAP_LAT(self._cap_latency)
  509. )
  510. self._write('csr', self._csr)
  511. # Success
  512. return True
  513. def set_runtime(self, runtime):
  514. self._write('csr', self._csr | (self.CSR_RUN if runtime else 0))
  515. # ----------------------------------------------------------------------------
  516. # Memory tester
  517. # ----------------------------------------------------------------------------
  518. class MemoryTester(object):
  519. CORE_REGS = {
  520. 'cmd': 0,
  521. 'addr': 1,
  522. }
  523. CMD_DUAL = 1 << 18
  524. CMD_CHECK_RST = 1 << 17
  525. CMD_READ = 1 << 16
  526. CMD_WRITE = 0 << 16
  527. CMD_BUF_ADDR = lambda self, addr: addr << 8
  528. CMD_LEN = lambda self, l: (l-1) << 0
  529. def __init__(self, intf, base):
  530. self.intf = intf
  531. self.base = base
  532. def _write(self, reg, val):
  533. self.intf.write(self.base + self.CORE_REGS[reg], val)
  534. def _read(self, reg):
  535. return self.intf.read(self.base + self.CORE_REGS[reg])
  536. def ram_write(self, addr, val):
  537. self.intf.write(self.base + 0x100 + addr, val)
  538. def ram_read(self, addr):
  539. return self.intf.read(self.base + 0x100 + addr)
  540. def cmd_write(self, ram_addr, buf_addr, xfer_len):
  541. self._write('addr', ram_addr)
  542. self._write('cmd',
  543. self.CMD_WRITE |
  544. self.CMD_BUF_ADDR(buf_addr) |
  545. self.CMD_LEN(xfer_len)
  546. )
  547. def cmd_read(self, ram_addr, buf_addr, xfer_len, check_reset=False, dual=False):
  548. self._write('addr', ram_addr)
  549. self._write('cmd',
  550. (self.CMD_DUAL if dual else 0) |
  551. (self.CMD_CHECK_RST if check_reset else 0) |
  552. self.CMD_READ |
  553. self.CMD_BUF_ADDR(buf_addr) |
  554. self.CMD_LEN(xfer_len)
  555. )
  556. def load_data(self, addr, data):
  557. for base in range(0, len(data), 128):
  558. # Upload chunk to RAM (128 bytes = max burst len)
  559. for j in range(0, 128, 4):
  560. b = (data[base+j:base+j+4] + b'\x00\x00\x00\x00')[0:4]
  561. w = int.from_bytes(b, 'big')
  562. self.ram_write(j // 4, w)
  563. # Issue command to write chunk to RAM
  564. self.cmd_write(addr + (base // 4), 0, 32)
  565. def run(self, base, size):
  566. # Check alignement
  567. if (base & 31) or (size & 31):
  568. raise ValueError('Base Address and Size argument for memory testing must be aligned on 32-words')
  569. # Load random block of data
  570. ref_data = [
  571. random.randint(0, (1<<32)-1)
  572. for i in range(256)
  573. ]
  574. for i in range(256):
  575. self.ram_write(i, ref_data[i])
  576. # Fill memory
  577. for addr in range(base, base+size, 32):
  578. print(" . Writing block @ %08x\r" % (addr,), end='')
  579. self.cmd_write(addr, addr & 0xff, 32)
  580. # Validate all blocks
  581. all_good = True
  582. for addr in range(base, base+size, 32):
  583. blk_first = (addr & 0xfff) == 0x000
  584. blk_last = (addr & 0xfff) == 0xfe0
  585. print(" . Reading block @ %08x\r" % (addr,), end='')
  586. self.cmd_read(addr, addr & 0xff, 32, check_reset=blk_first)
  587. if blk_last:
  588. if not (self._read('cmd') & 2):
  589. print(" ! Failed at block %08x" % (addr,))
  590. all_good = False
  591. print(" \r", end='')
  592. return all_good
  593. # ----------------------------------------------------------------------------
  594. # HDMI Output
  595. # ----------------------------------------------------------------------------
  596. class HDMIOutput(object):
  597. def __init__(self, intf, base):
  598. self.intf = intf
  599. self.base = base
  600. def _write(self, reg, val):
  601. self.intf.write(self.base + self.CORE_REGS[reg], val)
  602. def _read(self, reg):
  603. return self.intf.read(self.base + self.CORE_REGS[reg])
  604. def pal_write(self, addr, val):
  605. self.intf.write(self.base + (1<<6) + addr, val)
  606. def enable(self, fb_addr, burst_len):
  607. # Frame Buffer address
  608. self.intf.write(self.base + 1, fb_addr)
  609. # Burst Config
  610. bn_cnt = ((1920 // 8) - 1) // burst_len
  611. bn_len = burst_len - 1
  612. bl_len = (1920 // 8) - (burst_len * bn_cnt) - 1
  613. bl_inc = bl_len
  614. self.intf.write(self.base + 0,
  615. (1 << 31) |
  616. (bn_cnt << 24) |
  617. (bn_len << 16) |
  618. (bl_len << 8) |
  619. (bl_inc << 0)
  620. )
  621. def disable(self):
  622. self.intf.write(self.base + 0, 0)