microcode.py 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447
  1. #!/usr/bin/env python3
  2. import sys
  3. import types
  4. #
  5. # OpCodes
  6. #
  7. def NOP():
  8. return 0x0000
  9. def LD(src):
  10. srcs = {
  11. 'evt': 0,
  12. 'pkt_pid': 2,
  13. 'pkt_pid_chk': 3,
  14. 'ep_type': 4,
  15. 'bd_state': 6,
  16. }
  17. return 0x1000 | srcs[src]
  18. def EP(bd_state=None, bdi_flip=False, dt_flip=False, wb=False, cel_set=False):
  19. return 0x2000 | \
  20. ((1 << 0) if dt_flip else 0) | \
  21. ((1 << 1) if bdi_flip else 0) | \
  22. (((bd_state << 3) | (1 << 2)) if bd_state is not None else 0) | \
  23. ((1 << 7) if wb else 0) | \
  24. ((1 << 8) if cel_set else 0)
  25. def ZL():
  26. return 0x3000
  27. def TX(pid, set_dt=False):
  28. return 0x4000 | pid | ((1 << 4) if set_dt else 0)
  29. def NOTIFY(code):
  30. return 0x5000 | code
  31. def EVT_CLR(evts):
  32. return 0x6000 | evts
  33. def EVT_RTO(timeout):
  34. return 0x7000 | timeout
  35. def JMP(tgt, cond_val=None, cond_mask=0xf, cond_invert=False):
  36. if isinstance(tgt, str):
  37. return lambda resolve: JMP(resolve(tgt), cond_val, cond_mask, cond_invert)
  38. assert tgt & 3 == 0
  39. return (
  40. (1 << 15) |
  41. (tgt << 6) |
  42. (0 if (cond_val is None) else ((cond_mask << 4) | cond_val)) |
  43. ((1<<14) if cond_invert else 0)
  44. )
  45. def JEQ(tgt, cond_val=None, cond_mask=0xf):
  46. return JMP(tgt, cond_val, cond_mask)
  47. def JNE(tgt, cond_val=None, cond_mask=0xf):
  48. return JMP(tgt, cond_val, cond_mask, cond_invert=True)
  49. def L(label):
  50. return label
  51. #
  52. # "Assembler"
  53. #
  54. def assemble(code):
  55. flat_code = []
  56. labels = {}
  57. for elem in code:
  58. if isinstance(elem, str):
  59. assert elem not in labels
  60. while len(flat_code) & 3:
  61. flat_code.append(JMP(elem))
  62. labels[elem] = len(flat_code)
  63. else:
  64. flat_code.append(elem)
  65. for offset, elem in enumerate(flat_code):
  66. if isinstance(elem, types.LambdaType):
  67. flat_code[offset] = elem(lambda label: labels[label])
  68. return flat_code, labels
  69. #
  70. # Constants
  71. #
  72. EVT_ALL = 0xf
  73. EVT_RX_OK = (1 << 0)
  74. EVT_RX_ERR = (1 << 1)
  75. EVT_TX_DONE = (1 << 2)
  76. EVT_TIMEOUT = (1 << 3)
  77. PID_OUT = 0b0001
  78. PID_IN = 0b1001
  79. PID_SETUP = 0b1101
  80. PID_DATA0 = 0b0011
  81. PID_DATA1 = 0b1011
  82. PID_ACK = 0b0010
  83. PID_NAK = 0b1010
  84. PID_STALL = 0b1110
  85. PID_DATA_MSK = 0b0111
  86. PID_DATA_VAL = 0b0011
  87. EP_TYPE_NONE = 0b0000
  88. EP_TYPE_ISOC = 0b0001
  89. EP_TYPE_INT = 0b0010
  90. EP_TYPE_BULK = 0b0100
  91. EP_TYPE_CTRL = 0b0110
  92. EP_TYPE_MSK1 = 0b0111
  93. EP_TYPE_MSK2 = 0b0110
  94. EP_TYPE_HALT = 0b0001
  95. EP_TYPE_CEL = 0b1000
  96. BD_NONE = 0b000
  97. BD_RDY_DATA = 0b010
  98. BD_RDY_STALL = 0b011
  99. BD_RDY_MSK = 0b110
  100. BD_RDY_VAL = 0b010
  101. BD_DONE_OK = 0b100
  102. BD_DONE_ERR = 0b101
  103. NOTIFY_SUCCESS = 0x00
  104. NOTIFY_TX_FAIL = 0x08
  105. NOTIFY_RX_FAIL = 0x09
  106. TIMEOUT = 70 # Default timeout value for waiting for a packet from the host
  107. #
  108. # Microcode
  109. #
  110. mc = [
  111. # Main loop
  112. # ---------
  113. L('IDLE'),
  114. # Wait for an event we care about
  115. LD('evt'),
  116. JEQ('IDLE', 0),
  117. EVT_CLR(EVT_ALL),
  118. JEQ('IDLE', 0, EVT_RX_OK),
  119. # Dispatch to handler
  120. LD('pkt_pid'),
  121. JEQ('DO_IN', PID_IN),
  122. JEQ('DO_OUT', PID_OUT),
  123. JEQ('DO_SETUP', PID_SETUP),
  124. JMP('IDLE'), # invalid PID / not token, ignore packet
  125. # IN Transactions
  126. # ---------------
  127. L('DO_IN'),
  128. # Check endpoint type
  129. LD('ep_type'),
  130. JEQ('DO_IN_ISOC', EP_TYPE_ISOC, EP_TYPE_MSK1), # isochronous is special
  131. JEQ('IDLE', EP_TYPE_NONE, EP_TYPE_MSK1), # endpoint doesn't exist, ignore packet
  132. # Bulk/Control/Interrupt
  133. # - - - - - - - - - - - -
  134. # Is EP halted ?
  135. JEQ('TX_STALL_HALT', EP_TYPE_HALT, EP_TYPE_HALT),
  136. # If it's a Control endpoint and Lock is active, NAK
  137. JEQ('TX_NAK', EP_TYPE_CEL | EP_TYPE_CTRL, EP_TYPE_CEL | EP_TYPE_MSK2),
  138. # Anything valid in the active BD ?
  139. LD('bd_state'),
  140. JEQ('TX_STALL_BD', BD_RDY_STALL),
  141. JNE('TX_NAK', BD_RDY_DATA),
  142. # TX packet from BD
  143. TX(PID_DATA0, set_dt=True),
  144. # Wait for TX to complete
  145. L('_DO_IN_BCI_WAIT_TX'),
  146. LD('evt'),
  147. JEQ('_DO_IN_BCI_WAIT_TX', 0, EVT_TX_DONE),
  148. EVT_CLR(EVT_TX_DONE),
  149. # Wait for ACK
  150. EVT_RTO(TIMEOUT),
  151. L('_DO_IN_BCI_WAIT_ACK'),
  152. LD('evt'),
  153. JEQ('_DO_IN_BCI_WAIT_ACK', 0, EVT_TIMEOUT | EVT_RX_ERR | EVT_RX_OK),
  154. # If it's not a good packet and a ACK, we failed
  155. JEQ('_DO_IN_BCI_FAIL', 0, EVT_RX_OK),
  156. LD('pkt_pid'),
  157. JNE('_DO_IN_BCI_FAIL', PID_ACK),
  158. # Success !
  159. EP(bd_state=BD_DONE_OK, bdi_flip=True, dt_flip=True, wb=True),
  160. NOTIFY(NOTIFY_SUCCESS),
  161. JMP('IDLE'),
  162. # TX Fail handler, notify the host
  163. L('_DO_IN_BCI_FAIL'),
  164. NOTIFY(NOTIFY_TX_FAIL),
  165. JMP('IDLE'),
  166. # Isochronous
  167. # - - - - - -
  168. L('DO_IN_ISOC'),
  169. # Anything to TX ?
  170. LD('bd_state'),
  171. JNE('_DO_IN_ISOC_NO_DATA', BD_RDY_DATA),
  172. # Transmit packet (with DATA0, always)
  173. TX(PID_DATA0),
  174. # Wait for TX to complete
  175. L('_DO_IN_ISOC_WAIT_TX'),
  176. LD('evt'),
  177. JEQ('_DO_IN_ISOC_WAIT_TX', 0, EVT_TX_DONE),
  178. EVT_CLR(EVT_TX_DONE),
  179. # "Assume" success
  180. EP(bd_state=BD_DONE_OK, bdi_flip=True, dt_flip=False, wb=True),
  181. NOTIFY(NOTIFY_SUCCESS),
  182. JMP('IDLE'),
  183. # Transmit empty packet
  184. L('_DO_IN_ISOC_NO_DATA'),
  185. ZL(),
  186. TX(PID_DATA0),
  187. JMP('IDLE'),
  188. # SETUP Transactions
  189. # ------------------
  190. L('DO_SETUP'),
  191. # Check the endpoint is 'control' and CEL is not asserted
  192. LD('ep_type'),
  193. JNE('RX_DISCARD_NEXT', EP_TYPE_CTRL, EP_TYPE_MSK2 | EP_TYPE_CEL),
  194. # For Setup, if no-space, don't NAK, just ignore
  195. LD('bd_state'),
  196. JNE('RX_DISCARD_NEXT', BD_RDY_DATA),
  197. # Wait for packet
  198. EVT_RTO(TIMEOUT),
  199. L('_DO_SETUP_WAIT_DATA'),
  200. LD('evt'),
  201. JEQ('_DO_SETUP_WAIT_DATA', 0, EVT_TIMEOUT | EVT_RX_ERR | EVT_RX_OK),
  202. # Did it work ?
  203. JEQ('_DO_SETUP_FAIL', 0, EVT_RX_OK),
  204. LD('pkt_pid'),
  205. JNE('_DO_SETUP_FAIL', PID_DATA0),
  206. # Success !
  207. EP(bd_state=BD_DONE_OK, bdi_flip=True, dt_flip=True, wb=True, cel_set=True),
  208. NOTIFY(NOTIFY_SUCCESS),
  209. JMP('TX_ACK'),
  210. # Setup RX handler
  211. L('_DO_SETUP_FAIL'),
  212. EP(bd_state=BD_DONE_ERR, bdi_flip=True, dt_flip=False, wb=True),
  213. NOTIFY(NOTIFY_RX_FAIL),
  214. JMP('IDLE'),
  215. # OUT Transactions
  216. # ----------------
  217. L('DO_OUT'),
  218. # Check endpoint type
  219. LD('ep_type'),
  220. JEQ('DO_OUT_ISOC', EP_TYPE_ISOC, EP_TYPE_MSK1), # isochronous is special
  221. JEQ('IDLE', EP_TYPE_NONE, EP_TYPE_MSK1), # endpoint doesn't exist, ignore packet
  222. # Bulk/Control/Interrupt
  223. # - - - - - - - - - - - -
  224. # If EP is halted, we drop the packet and respond with STALL
  225. JEQ('_DO_OUT_BCI_DROP_DATA', EP_TYPE_HALT, EP_TYPE_HALT),
  226. # If it's a Control endpoint and Lock is active, NAK
  227. JEQ('_DO_OUT_BCI_DROP_DATA', EP_TYPE_CEL | EP_TYPE_CTRL, EP_TYPE_CEL | EP_TYPE_MSK2),
  228. # Check we have space, if not prevent data writes
  229. LD('bd_state'),
  230. JNE('_DO_OUT_BCI_DROP_DATA', BD_RDY_DATA),
  231. # Wait for packet
  232. EVT_RTO(TIMEOUT),
  233. L('_DO_OUT_BCI_WAIT_DATA'),
  234. LD('evt'),
  235. JEQ('_DO_OUT_BCI_WAIT_DATA', 0, EVT_TIMEOUT | EVT_RX_ERR | EVT_RX_OK),
  236. # We got a packet (and possibly stored the data), now we need to respond !
  237. # Not a valid packet at all, or timeout, or not DATAx -> No response
  238. JEQ('_DO_OUT_BCI_FAIL', 0, EVT_RX_OK),
  239. LD('pkt_pid_chk'),
  240. JNE('_DO_OUT_BCI_FAIL', PID_DATA_VAL, PID_DATA_MSK), # Accept DATA0/DATA1 only
  241. # If EP is halted, TX STALL
  242. LD('ep_type'),
  243. JEQ('TX_STALL_HALT', EP_TYPE_HALT, EP_TYPE_HALT),
  244. # If it's a Control endpoint and Lock is active, NAK
  245. JEQ('TX_NAK', EP_TYPE_CEL | EP_TYPE_CTRL, EP_TYPE_CEL | EP_TYPE_MSK2),
  246. # Wrong Data Toggle -> Ignore new data, just re-tx a ACK
  247. LD('pkt_pid_chk'),
  248. JEQ('TX_ACK', PID_DATA1), # With pid_chk, DATA1 means wrong DT
  249. # We didn't have space -> NAK
  250. LD('bd_state'),
  251. JNE('TX_NAK', BD_RDY_VAL, BD_RDY_MSK),
  252. # Explicitely asked for stall ?
  253. JEQ('TX_STALL_BD', BD_RDY_STALL),
  254. # We're all good !
  255. EP(bd_state=BD_DONE_OK, bdi_flip=True, dt_flip=True, wb=True),
  256. NOTIFY(NOTIFY_SUCCESS),
  257. JMP('TX_ACK'),
  258. # Fail handler: Prepare to drop data
  259. L('_DO_OUT_BCI_DROP_DATA'),
  260. ZL(),
  261. JMP('_DO_OUT_BCI_WAIT_DATA'),
  262. # Fail hander: Packet reception failed
  263. L('_DO_OUT_BCI_FAIL'),
  264. # Check we actually had a BD at all
  265. LD('bd_state'),
  266. JNE('IDLE', BD_RDY_VAL, BD_RDY_MSK),
  267. # We had a BD, so report the error
  268. EP(bd_state=BD_DONE_ERR, bdi_flip=True, dt_flip=False, wb=True),
  269. NOTIFY(NOTIFY_RX_FAIL),
  270. JMP('IDLE'),
  271. # Isochronous
  272. # - - - - - -
  273. L('DO_OUT_ISOC'),
  274. # Do we have space to RX ?
  275. LD('bd_state'),
  276. JNE('_DO_OUT_ISOC_NO_SPACE', BD_RDY_DATA),
  277. # Wait for packet RX
  278. EVT_RTO(TIMEOUT),
  279. L('_DO_OUT_ISOC_WAIT_DATA'),
  280. LD('evt'),
  281. JEQ('_DO_OUT_ISOC_WAIT_DATA', 0, EVT_TIMEOUT | EVT_RX_ERR | EVT_RX_OK),
  282. # Did it work ?
  283. JEQ('_DO_OUT_ISOC_FAIL', 0, EVT_RX_OK),
  284. LD('pkt_pid'),
  285. JNE('_DO_OUT_ISOC_FAIL', PID_DATA_VAL, PID_DATA_MSK), # Accept DATA0/DATA1
  286. # Success !
  287. EP(bd_state=BD_DONE_OK, bdi_flip=True, dt_flip=False, wb=True),
  288. NOTIFY(NOTIFY_SUCCESS),
  289. JMP('IDLE'),
  290. # RX fail handler, mark error in the BD, notify host
  291. L('_DO_OUT_ISOC_FAIL'),
  292. EP(bd_state=BD_DONE_ERR, bdi_flip=True, dt_flip=False, wb=True),
  293. NOTIFY(NOTIFY_RX_FAIL),
  294. JMP('IDLE'),
  295. # RX no-space handler, just discard packet :(
  296. L('_DO_OUT_ISOC_NO_SPACE'),
  297. # Notify host ?
  298. # Discard
  299. JMP('RX_DISCARD_NEXT'),
  300. # Common shared utility
  301. # ---------------------
  302. # Transmit STALL as asked in a Buffer Descriptor
  303. L('TX_STALL_BD'),
  304. EP(bd_state=BD_DONE_OK, bdi_flip=True, dt_flip=False, wb=True),
  305. NOTIFY(NOTIFY_SUCCESS),
  306. # fall-thru
  307. # Transmit STALL because of halted End Point
  308. L('TX_STALL_HALT'),
  309. ZL(),
  310. TX(PID_STALL),
  311. JMP('IDLE'),
  312. # Transmit NAK handshake
  313. L('TX_NAK'),
  314. ZL(),
  315. TX(PID_NAK),
  316. JMP('IDLE'),
  317. # Transmit ACK handshake
  318. L('TX_ACK'),
  319. ZL(),
  320. TX(PID_ACK),
  321. JMP('IDLE'),
  322. # Discard the next packet (if any)
  323. L('RX_DISCARD_NEXT'),
  324. # Zero-length to prevent store of data
  325. ZL(),
  326. # Wait for a packet
  327. EVT_RTO(TIMEOUT),
  328. L('_RX_DISCARD_WAIT'),
  329. LD('evt'),
  330. JEQ('_RX_DISCARD_WAIT', 0, EVT_TIMEOUT | EVT_RX_ERR | EVT_RX_OK),
  331. # Done
  332. JMP('IDLE'),
  333. ]
  334. if __name__ == '__main__':
  335. code, labels = assemble(mc)
  336. ilabel = dict([(v,k) for k,v in labels.items()])
  337. for i, v in enumerate(code):
  338. if (len(sys.argv) > 1) and (sys.argv[1] == 'debug'):
  339. print("%02x %04x\t%s" % (i, v,ilabel.get(i,'')))
  340. else:
  341. print("%04x" % (v,))