You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

usbdrvasm16.inc 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346
  1. /* Name: usbdrvasm16.inc
  2. * Project: V-USB, virtual USB port for Atmel's(r) AVR(r) microcontrollers
  3. * Author: Christian Starkjohann
  4. * Creation Date: 2007-06-15
  5. * Tabsize: 4
  6. * Copyright: (c) 2007 by OBJECTIVE DEVELOPMENT Software GmbH
  7. * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt)
  8. * Revision: $Id: usbdrvasm16.inc 760 2009-08-09 18:59:43Z cs $
  9. */
  10. /* Do not link this file! Link usbdrvasm.S instead, which includes the
  11. * appropriate implementation!
  12. */
  13. /*
  14. General Description:
  15. This file is the 16 MHz version of the asssembler part of the USB driver. It
  16. requires a 16 MHz crystal (not a ceramic resonator and not a calibrated RC
  17. oscillator).
  18. See usbdrv.h for a description of the entire driver.
  19. Since almost all of this code is timing critical, don't change unless you
  20. really know what you are doing! Many parts require not only a maximum number
  21. of CPU cycles, but even an exact number of cycles!
  22. */
  23. ;max stack usage: [ret(2), YL, SREG, YH, bitcnt, shift, x1, x2, x3, x4, cnt] = 12 bytes
  24. ;nominal frequency: 16 MHz -> 10.6666666 cycles per bit, 85.333333333 cycles per byte
  25. ; Numbers in brackets are clocks counted from center of last sync bit
  26. ; when instruction starts
  27. USB_INTR_VECTOR:
  28. ;order of registers pushed: YL, SREG YH, [sofError], bitcnt, shift, x1, x2, x3, x4, cnt
  29. push YL ;[-25] push only what is necessary to sync with edge ASAP
  30. in YL, SREG ;[-23]
  31. push YL ;[-22]
  32. push YH ;[-20]
  33. ;----------------------------------------------------------------------------
  34. ; Synchronize with sync pattern:
  35. ;----------------------------------------------------------------------------
  36. ;sync byte (D-) pattern LSb to MSb: 01010100 [1 = idle = J, 0 = K]
  37. ;sync up with J to K edge during sync pattern -- use fastest possible loops
  38. ;The first part waits at most 1 bit long since we must be in sync pattern.
  39. ;YL is guarenteed to be < 0x80 because I flag is clear. When we jump to
  40. ;waitForJ, ensure that this prerequisite is met.
  41. waitForJ:
  42. inc YL
  43. sbis USBIN, USBMINUS
  44. brne waitForJ ; just make sure we have ANY timeout
  45. waitForK:
  46. ;The following code results in a sampling window of < 1/4 bit which meets the spec.
  47. sbis USBIN, USBMINUS ;[-15]
  48. rjmp foundK ;[-14]
  49. sbis USBIN, USBMINUS
  50. rjmp foundK
  51. sbis USBIN, USBMINUS
  52. rjmp foundK
  53. sbis USBIN, USBMINUS
  54. rjmp foundK
  55. sbis USBIN, USBMINUS
  56. rjmp foundK
  57. sbis USBIN, USBMINUS
  58. rjmp foundK
  59. #if USB_COUNT_SOF
  60. lds YL, usbSofCount
  61. inc YL
  62. sts usbSofCount, YL
  63. #endif /* USB_COUNT_SOF */
  64. #ifdef USB_SOF_HOOK
  65. USB_SOF_HOOK
  66. #endif
  67. rjmp sofError
  68. foundK: ;[-12]
  69. ;{3, 5} after falling D- edge, average delay: 4 cycles [we want 5 for center sampling]
  70. ;we have 1 bit time for setup purposes, then sample again. Numbers in brackets
  71. ;are cycles from center of first sync (double K) bit after the instruction
  72. push bitcnt ;[-12]
  73. ; [---] ;[-11]
  74. lds YL, usbInputBufOffset;[-10]
  75. ; [---] ;[-9]
  76. clr YH ;[-8]
  77. subi YL, lo8(-(usbRxBuf));[-7] [rx loop init]
  78. sbci YH, hi8(-(usbRxBuf));[-6] [rx loop init]
  79. push shift ;[-5]
  80. ; [---] ;[-4]
  81. ldi bitcnt, 0x55 ;[-3] [rx loop init]
  82. sbis USBIN, USBMINUS ;[-2] we want two bits K (sample 2 cycles too early)
  83. rjmp haveTwoBitsK ;[-1]
  84. pop shift ;[0] undo the push from before
  85. pop bitcnt ;[2] undo the push from before
  86. rjmp waitForK ;[4] this was not the end of sync, retry
  87. ; The entire loop from waitForK until rjmp waitForK above must not exceed two
  88. ; bit times (= 21 cycles).
  89. ;----------------------------------------------------------------------------
  90. ; push more registers and initialize values while we sample the first bits:
  91. ;----------------------------------------------------------------------------
  92. haveTwoBitsK:
  93. push x1 ;[1]
  94. push x2 ;[3]
  95. push x3 ;[5]
  96. ldi shift, 0 ;[7]
  97. ldi x3, 1<<4 ;[8] [rx loop init] first sample is inverse bit, compensate that
  98. push x4 ;[9] == leap
  99. in x1, USBIN ;[11] <-- sample bit 0
  100. andi x1, USBMASK ;[12]
  101. bst x1, USBMINUS ;[13]
  102. bld shift, 7 ;[14]
  103. push cnt ;[15]
  104. ldi leap, 0 ;[17] [rx loop init]
  105. ldi cnt, USB_BUFSIZE;[18] [rx loop init]
  106. rjmp rxbit1 ;[19] arrives at [21]
  107. ;----------------------------------------------------------------------------
  108. ; Receiver loop (numbers in brackets are cycles within byte after instr)
  109. ;----------------------------------------------------------------------------
  110. ; duration of unstuffing code should be 10.66666667 cycles. We adjust "leap"
  111. ; accordingly to approximate this value in the long run.
  112. unstuff6:
  113. andi x2, USBMASK ;[03]
  114. ori x3, 1<<6 ;[04] will not be shifted any more
  115. andi shift, ~0x80;[05]
  116. mov x1, x2 ;[06] sampled bit 7 is actually re-sampled bit 6
  117. subi leap, -1 ;[07] total duration = 11 bits -> subtract 1/3
  118. rjmp didUnstuff6 ;[08]
  119. unstuff7:
  120. ori x3, 1<<7 ;[09] will not be shifted any more
  121. in x2, USBIN ;[00] [10] re-sample bit 7
  122. andi x2, USBMASK ;[01]
  123. andi shift, ~0x80;[02]
  124. subi leap, 2 ;[03] total duration = 10 bits -> add 1/3
  125. rjmp didUnstuff7 ;[04]
  126. unstuffEven:
  127. ori x3, 1<<6 ;[09] will be shifted right 6 times for bit 0
  128. in x1, USBIN ;[00] [10]
  129. andi shift, ~0x80;[01]
  130. andi x1, USBMASK ;[02]
  131. breq se0 ;[03]
  132. subi leap, -1 ;[04] total duration = 11 bits -> subtract 1/3
  133. nop2 ;[05]
  134. rjmp didUnstuffE ;[06]
  135. unstuffOdd:
  136. ori x3, 1<<5 ;[09] will be shifted right 4 times for bit 1
  137. in x2, USBIN ;[00] [10]
  138. andi shift, ~0x80;[01]
  139. andi x2, USBMASK ;[02]
  140. breq se0 ;[03]
  141. subi leap, -1 ;[04] total duration = 11 bits -> subtract 1/3
  142. nop2 ;[05]
  143. rjmp didUnstuffO ;[06]
  144. rxByteLoop:
  145. andi x1, USBMASK ;[03]
  146. eor x2, x1 ;[04]
  147. subi leap, 1 ;[05]
  148. brpl skipLeap ;[06]
  149. subi leap, -3 ;1 one leap cycle every 3rd byte -> 85 + 1/3 cycles per byte
  150. nop ;1
  151. skipLeap:
  152. subi x2, 1 ;[08]
  153. ror shift ;[09]
  154. didUnstuff6:
  155. cpi shift, 0xfc ;[10]
  156. in x2, USBIN ;[00] [11] <-- sample bit 7
  157. brcc unstuff6 ;[01]
  158. andi x2, USBMASK ;[02]
  159. eor x1, x2 ;[03]
  160. subi x1, 1 ;[04]
  161. ror shift ;[05]
  162. didUnstuff7:
  163. cpi shift, 0xfc ;[06]
  164. brcc unstuff7 ;[07]
  165. eor x3, shift ;[08] reconstruct: x3 is 1 at bit locations we changed, 0 at others
  166. st y+, x3 ;[09] store data
  167. rxBitLoop:
  168. in x1, USBIN ;[00] [11] <-- sample bit 0/2/4
  169. andi x1, USBMASK ;[01]
  170. eor x2, x1 ;[02]
  171. andi x3, 0x3f ;[03] topmost two bits reserved for 6 and 7
  172. subi x2, 1 ;[04]
  173. ror shift ;[05]
  174. cpi shift, 0xfc ;[06]
  175. brcc unstuffEven ;[07]
  176. didUnstuffE:
  177. lsr x3 ;[08]
  178. lsr x3 ;[09]
  179. rxbit1:
  180. in x2, USBIN ;[00] [10] <-- sample bit 1/3/5
  181. andi x2, USBMASK ;[01]
  182. breq se0 ;[02]
  183. eor x1, x2 ;[03]
  184. subi x1, 1 ;[04]
  185. ror shift ;[05]
  186. cpi shift, 0xfc ;[06]
  187. brcc unstuffOdd ;[07]
  188. didUnstuffO:
  189. subi bitcnt, 0xab;[08] == addi 0x55, 0x55 = 0x100/3
  190. brcs rxBitLoop ;[09]
  191. subi cnt, 1 ;[10]
  192. in x1, USBIN ;[00] [11] <-- sample bit 6
  193. brcc rxByteLoop ;[01]
  194. rjmp overflow
  195. macro POP_STANDARD ; 14 cycles
  196. pop cnt
  197. pop x4
  198. pop x3
  199. pop x2
  200. pop x1
  201. pop shift
  202. pop bitcnt
  203. endm
  204. macro POP_RETI ; 7 cycles
  205. pop YH
  206. pop YL
  207. out SREG, YL
  208. pop YL
  209. endm
  210. #include "asmcommon.inc"
  211. ; USB spec says:
  212. ; idle = J
  213. ; J = (D+ = 0), (D- = 1)
  214. ; K = (D+ = 1), (D- = 0)
  215. ; Spec allows 7.5 bit times from EOP to SOP for replies
  216. bitstuffN:
  217. eor x1, x4 ;[5]
  218. ldi x2, 0 ;[6]
  219. nop2 ;[7]
  220. nop ;[9]
  221. out USBOUT, x1 ;[10] <-- out
  222. rjmp didStuffN ;[0]
  223. bitstuff6:
  224. eor x1, x4 ;[5]
  225. ldi x2, 0 ;[6] Carry is zero due to brcc
  226. rol shift ;[7] compensate for ror shift at branch destination
  227. rjmp didStuff6 ;[8]
  228. bitstuff7:
  229. ldi x2, 0 ;[2] Carry is zero due to brcc
  230. rjmp didStuff7 ;[3]
  231. sendNakAndReti:
  232. ldi x3, USBPID_NAK ;[-18]
  233. rjmp sendX3AndReti ;[-17]
  234. sendAckAndReti:
  235. ldi cnt, USBPID_ACK ;[-17]
  236. sendCntAndReti:
  237. mov x3, cnt ;[-16]
  238. sendX3AndReti:
  239. ldi YL, 20 ;[-15] x3==r20 address is 20
  240. ldi YH, 0 ;[-14]
  241. ldi cnt, 2 ;[-13]
  242. ; rjmp usbSendAndReti fallthrough
  243. ;usbSend:
  244. ;pointer to data in 'Y'
  245. ;number of bytes in 'cnt' -- including sync byte [range 2 ... 12]
  246. ;uses: x1...x4, btcnt, shift, cnt, Y
  247. ;Numbers in brackets are time since first bit of sync pattern is sent
  248. ;We don't match the transfer rate exactly (don't insert leap cycles every third
  249. ;byte) because the spec demands only 1.5% precision anyway.
  250. usbSendAndReti: ; 12 cycles until SOP
  251. in x2, USBDDR ;[-12]
  252. ori x2, USBMASK ;[-11]
  253. sbi USBOUT, USBMINUS;[-10] prepare idle state; D+ and D- must have been 0 (no pullups)
  254. in x1, USBOUT ;[-8] port mirror for tx loop
  255. out USBDDR, x2 ;[-7] <- acquire bus
  256. ; need not init x2 (bitstuff history) because sync starts with 0
  257. ldi x4, USBMASK ;[-6] exor mask
  258. ldi shift, 0x80 ;[-5] sync byte is first byte sent
  259. txByteLoop:
  260. ldi bitcnt, 0x35 ;[-4] [6] binary 0011 0101
  261. txBitLoop:
  262. sbrs shift, 0 ;[-3] [7]
  263. eor x1, x4 ;[-2] [8]
  264. out USBOUT, x1 ;[-1] [9] <-- out N
  265. ror shift ;[0] [10]
  266. ror x2 ;[1]
  267. didStuffN:
  268. cpi x2, 0xfc ;[2]
  269. brcc bitstuffN ;[3]
  270. lsr bitcnt ;[4]
  271. brcc txBitLoop ;[5]
  272. brne txBitLoop ;[6]
  273. sbrs shift, 0 ;[7]
  274. eor x1, x4 ;[8]
  275. didStuff6:
  276. out USBOUT, x1 ;[-1] [9] <-- out 6
  277. ror shift ;[0] [10]
  278. ror x2 ;[1]
  279. cpi x2, 0xfc ;[2]
  280. brcc bitstuff6 ;[3]
  281. ror shift ;[4]
  282. didStuff7:
  283. ror x2 ;[5]
  284. sbrs x2, 7 ;[6]
  285. eor x1, x4 ;[7]
  286. nop ;[8]
  287. cpi x2, 0xfc ;[9]
  288. out USBOUT, x1 ;[-1][10] <-- out 7
  289. brcc bitstuff7 ;[0] [11]
  290. ld shift, y+ ;[1]
  291. dec cnt ;[3]
  292. brne txByteLoop ;[4]
  293. ;make SE0:
  294. cbr x1, USBMASK ;[5] prepare SE0 [spec says EOP may be 21 to 25 cycles]
  295. lds x2, usbNewDeviceAddr;[6]
  296. lsl x2 ;[8] we compare with left shifted address
  297. subi YL, 20 + 2 ;[9] Only assign address on data packets, not ACK/NAK in x3
  298. sbci YH, 0 ;[10]
  299. out USBOUT, x1 ;[11] <-- out SE0 -- from now 2 bits = 22 cycles until bus idle
  300. ;2006-03-06: moved transfer of new address to usbDeviceAddr from C-Code to asm:
  301. ;set address only after data packet was sent, not after handshake
  302. breq skipAddrAssign ;[0]
  303. sts usbDeviceAddr, x2; if not skipped: SE0 is one cycle longer
  304. skipAddrAssign:
  305. ;end of usbDeviceAddress transfer
  306. ldi x2, 1<<USB_INTR_PENDING_BIT;[2] int0 occurred during TX -- clear pending flag
  307. USB_STORE_PENDING(x2) ;[3]
  308. ori x1, USBIDLE ;[4]
  309. in x2, USBDDR ;[5]
  310. cbr x2, USBMASK ;[6] set both pins to input
  311. mov x3, x1 ;[7]
  312. cbr x3, USBMASK ;[8] configure no pullup on both pins
  313. ldi x4, 4 ;[9]
  314. se0Delay:
  315. dec x4 ;[10] [13] [16] [19]
  316. brne se0Delay ;[11] [14] [17] [20]
  317. out USBOUT, x1 ;[21] <-- out J (idle) -- end of SE0 (EOP signal)
  318. out USBDDR, x2 ;[22] <-- release bus now
  319. out USBOUT, x3 ;[23] <-- ensure no pull-up resistors are active
  320. rjmp doReturn