microcode.py 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441
  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. # "Assume" success
  175. EP(bd_state=BD_DONE_OK, bdi_flip=True, dt_flip=False, wb=True),
  176. NOTIFY(NOTIFY_SUCCESS),
  177. JMP('IDLE'),
  178. # Transmit empty packet
  179. L('_DO_IN_ISOC_NO_DATA'),
  180. ZL(),
  181. TX(PID_DATA0),
  182. JMP('IDLE'),
  183. # SETUP Transactions
  184. # ------------------
  185. L('DO_SETUP'),
  186. # Check the endpoint is 'control' and CEL is not asserted
  187. LD('ep_type'),
  188. JNE('RX_DISCARD_NEXT', EP_TYPE_CTRL, EP_TYPE_MSK2 | EP_TYPE_CEL),
  189. # For Setup, if no-space, don't NAK, just ignore
  190. LD('bd_state'),
  191. JNE('RX_DISCARD_NEXT', BD_RDY_DATA),
  192. # Wait for packet
  193. EVT_RTO(TIMEOUT),
  194. L('_DO_SETUP_WAIT_DATA'),
  195. LD('evt'),
  196. JEQ('_DO_SETUP_WAIT_DATA', 0, EVT_TIMEOUT | EVT_RX_ERR | EVT_RX_OK),
  197. # Did it work ?
  198. JEQ('_DO_SETUP_FAIL', 0, EVT_RX_OK),
  199. LD('pkt_pid'),
  200. JNE('_DO_SETUP_FAIL', PID_DATA0),
  201. # Success !
  202. EP(bd_state=BD_DONE_OK, bdi_flip=True, dt_flip=True, wb=True, cel_set=True),
  203. NOTIFY(NOTIFY_SUCCESS),
  204. JMP('TX_ACK'),
  205. # Setup RX handler
  206. L('_DO_SETUP_FAIL'),
  207. EP(bd_state=BD_DONE_ERR, bdi_flip=True, dt_flip=False, wb=True),
  208. NOTIFY(NOTIFY_RX_FAIL),
  209. JMP('IDLE'),
  210. # OUT Transactions
  211. # ----------------
  212. L('DO_OUT'),
  213. # Check endpoint type
  214. LD('ep_type'),
  215. JEQ('DO_OUT_ISOC', EP_TYPE_ISOC, EP_TYPE_MSK1), # isochronous is special
  216. JEQ('IDLE', EP_TYPE_NONE, EP_TYPE_MSK1), # endpoint doesn't exist, ignore packet
  217. # Bulk/Control/Interrupt
  218. # - - - - - - - - - - - -
  219. # If EP is halted, we drop the packet and respond with STALL
  220. JEQ('_DO_OUT_BCI_DROP_DATA', EP_TYPE_HALT, EP_TYPE_HALT),
  221. # If it's a Control endpoint and Lock is active, NAK
  222. JEQ('_DO_OUT_BCI_DROP_DATA', EP_TYPE_CEL | EP_TYPE_CTRL, EP_TYPE_CEL | EP_TYPE_MSK2),
  223. # Check we have space, if not prevent data writes
  224. LD('bd_state'),
  225. JNE('_DO_OUT_BCI_DROP_DATA', BD_RDY_DATA),
  226. # Wait for packet
  227. EVT_RTO(TIMEOUT),
  228. L('_DO_OUT_BCI_WAIT_DATA'),
  229. LD('evt'),
  230. JEQ('_DO_OUT_BCI_WAIT_DATA', 0, EVT_TIMEOUT | EVT_RX_ERR | EVT_RX_OK),
  231. # We got a packet (and possibly stored the data), now we need to respond !
  232. # Not a valid packet at all, or timeout, or not DATAx -> No response
  233. JEQ('_DO_OUT_BCI_FAIL', 0, EVT_RX_OK),
  234. LD('pkt_pid_chk'),
  235. JNE('_DO_OUT_BCI_FAIL', PID_DATA_VAL, PID_DATA_MSK), # Accept DATA0/DATA1 only
  236. # If EP is halted, TX STALL
  237. LD('ep_type'),
  238. JEQ('TX_STALL_HALT', EP_TYPE_HALT, EP_TYPE_HALT),
  239. # If it's a Control endpoint and Lock is active, NAK
  240. JEQ('TX_NAK', EP_TYPE_CEL | EP_TYPE_CTRL, EP_TYPE_CEL | EP_TYPE_MSK2),
  241. # Wrong Data Toggle -> Ignore new data, just re-tx a ACK
  242. LD('pkt_pid_chk'),
  243. JEQ('TX_ACK', PID_DATA1), # With pid_chk, DATA1 means wrong DT
  244. # We didn't have space -> NAK
  245. LD('bd_state'),
  246. JNE('TX_NAK', BD_RDY_VAL, BD_RDY_MSK),
  247. # Explicitely asked for stall ?
  248. JEQ('TX_STALL_BD', BD_RDY_STALL),
  249. # We're all good !
  250. EP(bd_state=BD_DONE_OK, bdi_flip=True, dt_flip=True, wb=True),
  251. NOTIFY(NOTIFY_SUCCESS),
  252. JMP('TX_ACK'),
  253. # Fail handler: Prepare to drop data
  254. L('_DO_OUT_BCI_DROP_DATA'),
  255. ZL(),
  256. JMP('_DO_OUT_BCI_WAIT_DATA'),
  257. # Fail hander: Packet reception failed
  258. L('_DO_OUT_BCI_FAIL'),
  259. # Check we actually had a BD at all
  260. LD('bd_state'),
  261. JNE('IDLE', BD_RDY_VAL, BD_RDY_MSK),
  262. # We had a BD, so report the error
  263. EP(bd_state=BD_DONE_ERR, bdi_flip=True, dt_flip=False, wb=True),
  264. NOTIFY(NOTIFY_RX_FAIL),
  265. JMP('IDLE'),
  266. # Isochronous
  267. # - - - - - -
  268. L('DO_OUT_ISOC'),
  269. # Do we have space to RX ?
  270. LD('bd_state'),
  271. JNE('_DO_OUT_ISOC_NO_SPACE', BD_RDY_DATA),
  272. # Wait for packet RX
  273. EVT_RTO(TIMEOUT),
  274. L('_DO_OUT_ISOC_WAIT_DATA'),
  275. LD('evt'),
  276. JEQ('_DO_OUT_ISOC_WAIT_DATA', 0, EVT_TIMEOUT | EVT_RX_ERR | EVT_RX_OK),
  277. # Did it work ?
  278. JEQ('_DO_OUT_ISOC_FAIL', 0, EVT_RX_OK),
  279. LD('pkt_pid'),
  280. JNE('_DO_OUT_ISOC_FAIL', PID_DATA_VAL, PID_DATA_MSK), # Accept DATA0/DATA1
  281. # Success !
  282. EP(bd_state=BD_DONE_OK, bdi_flip=True, dt_flip=False, wb=True),
  283. NOTIFY(NOTIFY_SUCCESS),
  284. JMP('IDLE'),
  285. # RX fail handler, mark error in the BD, notify host
  286. L('_DO_OUT_ISOC_FAIL'),
  287. EP(bd_state=BD_DONE_ERR, bdi_flip=True, dt_flip=False, wb=True),
  288. NOTIFY(NOTIFY_RX_FAIL),
  289. JMP('IDLE'),
  290. # RX no-space handler, just discard packet :(
  291. L('_DO_OUT_ISOC_NO_SPACE'),
  292. # Notify host ?
  293. # Discard
  294. JMP('RX_DISCARD_NEXT'),
  295. # Common shared utility
  296. # ---------------------
  297. # Transmit STALL as asked in a Buffer Descriptor
  298. L('TX_STALL_BD'),
  299. EP(bd_state=BD_DONE_OK, bdi_flip=True, dt_flip=False, wb=True),
  300. NOTIFY(NOTIFY_SUCCESS),
  301. # fall-thru
  302. # Transmit STALL because of halted End Point
  303. L('TX_STALL_HALT'),
  304. ZL(),
  305. TX(PID_STALL),
  306. JMP('IDLE'),
  307. # Transmit NAK handshake
  308. L('TX_NAK'),
  309. ZL(),
  310. TX(PID_NAK),
  311. JMP('IDLE'),
  312. # Transmit ACK handshake
  313. L('TX_ACK'),
  314. ZL(),
  315. TX(PID_ACK),
  316. JMP('IDLE'),
  317. # Discard the next packet (if any)
  318. L('RX_DISCARD_NEXT'),
  319. # Zero-length to prevent store of data
  320. ZL(),
  321. # Wait for a packet
  322. EVT_RTO(TIMEOUT),
  323. L('_RX_DISCARD_WAIT'),
  324. LD('evt'),
  325. JEQ('_RX_DISCARD_WAIT', 0, EVT_TIMEOUT | EVT_RX_ERR | EVT_RX_OK),
  326. # Done
  327. JMP('IDLE'),
  328. ]
  329. if __name__ == '__main__':
  330. code, labels = assemble(mc)
  331. ilabel = dict([(v,k) for k,v in labels.items()])
  332. for i, v in enumerate(code):
  333. if (len(sys.argv) > 1) and (sys.argv[1] == 'debug'):
  334. print("%02x %04x\t%s" % (i, v,ilabel.get(i,'')))
  335. else:
  336. print("%04x" % (v,))