1 /* Name: usbdrvasm165.inc
 
   2  * Project: V-USB, virtual USB port for Atmel's(r) AVR(r) microcontrollers
 
   3  * Author: Christian Starkjohann
 
   4  * Creation Date: 2007-04-22
 
   6  * Copyright: (c) 2007 by OBJECTIVE DEVELOPMENT Software GmbH
 
   7  * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt)
 
  11 /* Do not link this file! Link usbdrvasm.S instead, which includes the
 
  12  * appropriate implementation!
 
  17 This file is the 16.5 MHz version of the USB driver. It is intended for the
 
  18 ATTiny45 and similar controllers running on 16.5 MHz internal RC oscillator.
 
  19 This version contains a phase locked loop in the receiver routine to cope with
 
  20 slight clock rate deviations of up to +/- 1%.
 
  22 See usbdrv.h for a description of the entire driver.
 
  24 Since almost all of this code is timing critical, don't change unless you
 
  25 really know what you are doing! Many parts require not only a maximum number
 
  26 of CPU cycles, but even an exact number of cycles!
 
  29 ;Software-receiver engine. Strict timing! Don't change unless you can preserve timing!
 
  30 ;interrupt response time: 4 cycles + insn running = 7 max if interrupts always enabled
 
  31 ;max allowable interrupt latency: 59 cycles -> max 52 cycles interrupt disable
 
  32 ;max stack usage: [ret(2), r0, SREG, YL, YH, shift, x1, x2, x3, x4, cnt] = 12 bytes
 
  33 ;nominal frequency: 16.5 MHz -> 11 cycles per bit
 
  34 ; 16.3125 MHz < F_CPU < 16.6875 MHz (+/- 1.1%)
 
  35 ; Numbers in brackets are clocks counted from center of last sync bit
 
  36 ; when instruction starts
 
  40 ;order of registers pushed: YL, SREG [sofError], r0, YH, shift, x1, x2, x3, x4, cnt
 
  41     push    YL                  ;[-23] push only what is necessary to sync with edge ASAP
 
  44 ;----------------------------------------------------------------------------
 
  45 ; Synchronize with sync pattern:
 
  46 ;----------------------------------------------------------------------------
 
  47 ;sync byte (D-) pattern LSb to MSb: 01010100 [1 = idle = J, 0 = K]
 
  48 ;sync up with J to K edge during sync pattern -- use fastest possible loops
 
  49 ;The first part waits at most 1 bit long since we must be in sync pattern.
 
  50 ;YL is guarenteed to be < 0x80 because I flag is clear. When we jump to
 
  51 ;waitForJ, ensure that this prerequisite is met.
 
  55     brne    waitForJ        ; just make sure we have ANY timeout
 
  57 ;The following code results in a sampling window of < 1/4 bit which meets the spec.
 
  58     sbis    USBIN, USBMINUS     ;[-15]
 
  74 #endif  /* USB_COUNT_SOF */
 
  80 ;{3, 5} after falling D- edge, average delay: 4 cycles [we want 5 for center sampling]
 
  81 ;we have 1 bit time for setup purposes, then sample again. Numbers in brackets
 
  82 ;are cycles from center of first sync (double K) bit after the instruction
 
  87     lds     YL, usbInputBufOffset;[-8]
 
  90     subi    YL, lo8(-(usbRxBuf));[-5] [rx loop init]
 
  91     sbci    YH, hi8(-(usbRxBuf));[-4] [rx loop init]
 
  92     mov     r0, x2              ;[-3] [rx loop init]
 
  93     sbis    USBIN, USBMINUS     ;[-2] we want two bits K (sample 2 cycles too early)
 
  94     rjmp    haveTwoBitsK        ;[-1]
 
  95     pop     YH                  ;[0] undo the pushes from before
 
  97     rjmp    waitForK            ;[4] this was not the end of sync, retry
 
  98 ; The entire loop from waitForK until rjmp waitForK above must not exceed two
 
  99 ; bit times (= 22 cycles).
 
 101 ;----------------------------------------------------------------------------
 
 102 ; push more registers and initialize values while we sample the first bits:
 
 103 ;----------------------------------------------------------------------------
 
 109     ldi     shift, 0xff     ;[9] [rx loop init]
 
 110     ori     x3, 0xff        ;[10] [rx loop init] == ser x3, clear zero flag
 
 112     in      x1, USBIN       ;[11] <-- sample bit 0
 
 113     bst     x1, USBMINUS    ;[12]
 
 115     push    x4              ;[14] == phase
 
 119     ldi     phase, 0        ;[18] [rx loop init]
 
 120     ldi     cnt, USB_BUFSIZE;[19] [rx loop init]
 
 124 ;----------------------------------------------------------------------------
 
 125 ; Receiver loop (numbers in brackets are cycles within byte after instr)
 
 126 ;----------------------------------------------------------------------------
 
 128 byte oriented operations done during loop:
 
 131 bit 2: overflow check
 
 133 bit 4: rjmp to achieve conditional jump range
 
 136 bit 7: jump, fixup bitstuff
 
 138 ------------------------------------------------------------------
 
 141     in      x2, USBIN       ;[055] <-- bit 5
 
 144     sbrc    phase, USBMINUS ;[058]
 
 145     lpm                     ;[059] optional nop3; modifies r0
 
 146     in      phase, USBIN    ;[060] <-- phase
 
 148     bst     x1, USBMINUS    ;[062]
 
 150     andi    shift, 0x3f     ;[064]
 
 151     in      x1, USBIN       ;[065] <-- bit 6
 
 152     breq    unstuff5        ;[066] *** unstuff escape
 
 155     bst     x2, USBMINUS    ;[069]
 
 158     in      r0, USBIN       ;[071] <-- phase
 
 159     cpi     shift, 0x02     ;[072]
 
 160     brlo    unstuff6        ;[073] *** unstuff escape
 
 164     in      x2, USBIN       ;[076] <-- bit 7
 
 166     bst     x1, USBMINUS    ;[078]
 
 171     in      r0, USBIN       ;[082] <-- phase
 
 172     cpi     shift, 0x04     ;[083]
 
 176     andi    x3, ~0x80       ;[085]
 
 177     ori     shift, 0x80     ;[086]
 
 178     in      x2, USBIN       ;[087] <-- sample stuffed bit 7
 
 180     rjmp    didUnstuff7     ;[089]
 
 186     andi    x3, ~0x20       ;[069]
 
 187     ori     shift, 0x20     ;[070]
 
 188     in      r0, USBIN       ;[071] <-- phase
 
 193     in      x1, USBIN       ;[076] <-- bit 6
 
 197     bst     x2, USBMINUS    ;[080]
 
 198     bld     shift, 6        ;[081] no need to check bitstuffing, we just had one
 
 199     in      r0, USBIN       ;[082] <-- phase
 
 200     rjmp    didUnstuff5     ;[083]
 
 205     andi    x3, ~0x40       ;[075]
 
 206     in      x1, USBIN       ;[076] <-- bit 6 again
 
 207     ori     shift, 0x40     ;[077]
 
 210     rjmp    didUnstuff6     ;[080]
 
 217     andi    x2, USBMASK     ;[016] check for SE0
 
 218     in      r0, USBIN       ;[017] <-- phase
 
 219     breq    didUnstuff0     ;[018] direct jump to se0 would be too long
 
 220     andi    x3, ~0x01       ;[019]
 
 221     ori     shift, 0x01     ;[020]
 
 222     mov     x1, x2          ;[021] mov existing sample
 
 223     in      x2, USBIN       ;[022] <-- bit 1 again
 
 224     rjmp    didUnstuff0     ;[023]
 
 231     andi    x3, ~0x02       ;[027]
 
 232     in      r0, USBIN       ;[028] <-- phase
 
 233     ori     shift, 0x02     ;[029]
 
 235     rjmp    didUnstuff1     ;[031]
 
 242     andi    x3, ~0x04       ;[038]
 
 243     in      r0, USBIN       ;[039] <-- phase
 
 244     ori     shift, 0x04     ;[040]
 
 246     rjmp    didUnstuff2     ;[042]
 
 251     in      x2, USBIN       ;[044] <-- bit 3 again
 
 254     andi    x3, ~0x08       ;[047]
 
 255     ori     shift, 0x08     ;[048]
 
 257     in      r0, USBIN       ;[050] <-- phase
 
 258     rjmp    didUnstuff3     ;[051]
 
 263     andi    x3, ~0x10       ;[054]
 
 264     in      x1, USBIN       ;[055] <-- bit 4 again
 
 265     ori     shift, 0x10     ;[056]
 
 266     rjmp    didUnstuff4     ;[057]
 
 271     eor     x3, shift       ;[086] reconstruct: x3 is 0 at bit locations we changed, 1 at others
 
 272     in      x1, USBIN       ;[000] <-- bit 0
 
 278     in      r0, USBIN       ;[006] <-- phase
 
 280     bst     x2, USBMINUS    ;[008]
 
 282     andi    shift, 0xf9     ;[010]
 
 284     in      x2, USBIN       ;[011] <-- bit 1
 
 285     breq    unstuff0        ;[012] *** unstuff escape
 
 286     andi    x2, USBMASK     ;[013] SE0 check for bit 1
 
 287 didUnstuff0:                ;[   ] Z only set if we detected SE0 in bitstuff
 
 291     in      r0, USBIN       ;[017] <-- phase
 
 293     bst     x1, USBMINUS    ;[019]
 
 295     andi    shift, 0xf3     ;[021]
 
 297     in      x1, USBIN       ;[022] <-- bit 2
 
 298     breq    unstuff1        ;[023] *** unstuff escape
 
 301     subi    cnt, 1          ;[026] overflow check
 
 303     in      r0, USBIN       ;[028] <-- phase
 
 305     bst     x2, USBMINUS    ;[030]
 
 307     andi    shift, 0xe7     ;[032]
 
 309     in      x2, USBIN       ;[033] <-- bit 3
 
 310     breq    unstuff2        ;[034] *** unstuff escape
 
 314     bst     x1, USBMINUS    ;[038]
 
 315     in      r0, USBIN       ;[039] <-- phase
 
 317     andi    shift, 0xcf     ;[041]
 
 319     breq    unstuff3        ;[042] *** unstuff escape
 
 321     in      x1, USBIN       ;[044] <-- bit 4
 
 323     bst     x2, USBMINUS    ;[046]
 
 328     in      r0, USBIN       ;[050] <-- phase
 
 329     andi    shift, 0x9f     ;[051]
 
 330     breq    unstuff4        ;[052] *** unstuff escape
 
 331     rjmp    continueWithBit5;[053]
 
 334 macro POP_STANDARD ; 16 cycles
 
 344 macro POP_RETI     ; 5 cycles
 
 350 #include "asmcommon.inc"
 
 355 ; J = (D+ = 0), (D- = 1)
 
 356 ; K = (D+ = 1), (D- = 0)
 
 357 ; Spec allows 7.5 bit times from EOP to SOP for replies
 
 362     nop2                    ;[6] C is zero (brcc)
 
 368     lpm                     ;[7] 3 cycle NOP, modifies r0
 
 369     out     USBOUT, x1      ;[10] <-- out
 
 375     ldi     cnt, USBPID_NAK ;[-19]
 
 376     rjmp    sendCntAndReti  ;[-18]
 
 378     ldi     cnt, USBPID_ACK ;[-17]
 
 381     ldi     YL, 0           ;[-15] R0 address is 0
 
 384 ;   rjmp    usbSendAndReti      fallthrough
 
 387 ;pointer to data in 'Y'
 
 388 ;number of bytes in 'cnt' -- including sync byte [range 2 ... 12]
 
 389 ;uses: x1...x4, shift, cnt, Y
 
 390 ;Numbers in brackets are time since first bit of sync pattern is sent
 
 391 usbSendAndReti:             ; 12 cycles until SOP
 
 393     ori     x2, USBMASK     ;[-11]
 
 394     sbi     USBOUT, USBMINUS;[-10] prepare idle state; D+ and D- must have been 0 (no pullups)
 
 395     in      x1, USBOUT      ;[-8] port mirror for tx loop
 
 396     out     USBDDR, x2      ;[-7] <- acquire bus
 
 397 ; need not init x2 (bitstuff history) because sync starts with 0
 
 398     ldi     x4, USBMASK     ;[-6] exor mask
 
 399     ldi     shift, 0x80     ;[-5] sync byte is first byte sent
 
 400     ldi     bitStatus, 0xff ;[-4] init bit loop counter, works for up to 12 bytes
 
 403     sbrs    shift, 0        ;[8] [-3]
 
 405     out     USBOUT, x1      ;[10] [-1] <-- out
 
 412     subi    bitStatus, 37   ;[5] 256 / 7 ~=~ 37
 
 413     brcc    bitloop         ;[6] when we leave the loop, bitStatus has almost the initial value
 
 418     out     USBOUT, x1      ;[10] <-- out
 
 426     cbr     x1, USBMASK     ;[7] prepare SE0 [spec says EOP may be 21 to 25 cycles]
 
 427     lds     x2, usbNewDeviceAddr;[8]
 
 428     lsl     x2              ;[10] we compare with left shifted address
 
 429     out     USBOUT, x1      ;[11] <-- out SE0 -- from now 2 bits = 22 cycles until bus idle
 
 430 ;2006-03-06: moved transfer of new address to usbDeviceAddr from C-Code to asm:
 
 431 ;set address only after data packet was sent, not after handshake
 
 432     subi    YL, 2           ;[0] Only assign address on data packets, not ACK/NAK in r0
 
 434     breq    skipAddrAssign  ;[2]
 
 435     sts     usbDeviceAddr, x2; if not skipped: SE0 is one cycle longer
 
 437 ;end of usbDeviceAddress transfer
 
 438     ldi     x2, 1<<USB_INTR_PENDING_BIT;[4] int0 occurred during TX -- clear pending flag
 
 439     USB_STORE_PENDING(x2)   ;[5]
 
 442     cbr     x2, USBMASK     ;[8] set both pins to input
 
 444     cbr     x3, USBMASK     ;[10] configure no pullup on both pins
 
 447     dec     x4              ;[12] [15] [18] [21]
 
 448     brne    se0Delay        ;[13] [16] [19] [22]
 
 449     out     USBOUT, x1      ;[23] <-- out J (idle) -- end of SE0 (EOP signal)
 
 450     out     USBDDR, x2      ;[24] <-- release bus now
 
 451     out     USBOUT, x3      ;[25] <-- ensure no pull-up resistors are active