microcode.py 8.8 KB

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