1 /* Name: usbdrvasm12.inc
 
   2  * Project: V-USB, virtual USB port for Atmel's(r) AVR(r) microcontrollers
 
   3  * Author: Christian Starkjohann
 
   4  * Creation Date: 2004-12-29
 
   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 12 MHz version of the asssembler part of the USB driver. It
 
  18 requires a 12 MHz crystal (not a ceramic resonator and not a calibrated RC
 
  21 See usbdrv.h for a description of the entire driver.
 
  23 Since almost all of this code is timing critical, don't change unless you
 
  24 really know what you are doing! Many parts require not only a maximum number
 
  25 of CPU cycles, but even an exact number of cycles!
 
  28 Timing constraints according to spec (in bit times):
 
  29 timing subject                                      min max    CPUcycles
 
  30 ---------------------------------------------------------------------------
 
  31 EOP of OUT/SETUP to sync pattern of DATA0 (both rx) 2   16     16-128
 
  32 EOP of IN to sync pattern of DATA0 (rx, then tx)    2   7.5    16-60
 
  33 DATAx (rx) to ACK/NAK/STALL (tx)                    2   7.5    16-60
 
  36 ;Software-receiver engine. Strict timing! Don't change unless you can preserve timing!
 
  37 ;interrupt response time: 4 cycles + insn running = 7 max if interrupts always enabled
 
  38 ;max allowable interrupt latency: 34 cycles -> max 25 cycles interrupt disable
 
  39 ;max stack usage: [ret(2), YL, SREG, YH, shift, x1, x2, x3, cnt, x4] = 11 bytes
 
  40 ;Numbers in brackets are maximum cycles since SOF.
 
  42 ;order of registers pushed: YL, SREG [sofError], YH, shift, x1, x2, x3, cnt
 
  43     push    YL              ;2 [35] push only what is necessary to sync with edge ASAP
 
  46 ;----------------------------------------------------------------------------
 
  47 ; Synchronize with sync pattern:
 
  48 ;----------------------------------------------------------------------------
 
  49 ;sync byte (D-) pattern LSb to MSb: 01010100 [1 = idle = J, 0 = K]
 
  50 ;sync up with J to K edge during sync pattern -- use fastest possible loops
 
  51 ;The first part waits at most 1 bit long since we must be in sync pattern.
 
  52 ;YL is guarenteed to be < 0x80 because I flag is clear. When we jump to
 
  53 ;waitForJ, ensure that this prerequisite is met.
 
  57     brne    waitForJ        ; just make sure we have ANY timeout
 
  59 ;The following code results in a sampling window of 1/4 bit which meets the spec.
 
  74 #endif  /* USB_COUNT_SOF */
 
  80 ;{3, 5} after falling D- edge, average delay: 4 cycles [we want 4 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
 
  84     lds     YL, usbInputBufOffset;2 [4]
 
  86     subi    YL, lo8(-(usbRxBuf));1 [6]
 
  87     sbci    YH, hi8(-(usbRxBuf));1 [7]
 
  89     sbis    USBIN, USBMINUS ;1 [8] we want two bits K [sample 1 cycle too early]
 
  90     rjmp    haveTwoBitsK    ;2 [10]
 
  91     pop     YH              ;2 [11] undo the push from before
 
  92     rjmp    waitForK        ;2 [13] this was not the end of sync, retry
 
  94 ;----------------------------------------------------------------------------
 
  95 ; push more registers and initialize values while we sample the first bits:
 
  96 ;----------------------------------------------------------------------------
 
 101     in      x1, USBIN       ;1 [17] <-- sample bit 0
 
 102     ldi     shift, 0xff     ;1 [18]
 
 103     bst     x1, USBMINUS    ;1 [19]
 
 108     in      x2, USBIN       ;1 [25] <-- sample bit 1
 
 109     ser     x3              ;1 [26] [inserted init instruction]
 
 111     bst     x1, USBMINUS    ;1 [28]
 
 113     ldi     cnt, USB_BUFSIZE;1 [30] [inserted init instruction]
 
 116 ;----------------------------------------------------------------------------
 
 117 ; Receiver loop (numbers in brackets are cycles within byte after instr)
 
 118 ;----------------------------------------------------------------------------
 
 120 unstuff0:               ;1 (branch taken)
 
 121     andi    x3, ~0x01   ;1 [15]
 
 122     mov     x1, x2      ;1 [16] x2 contains last sampled (stuffed) bit
 
 123     in      x2, USBIN   ;1 [17] <-- sample bit 1 again
 
 124     ori     shift, 0x01 ;1 [18]
 
 125     rjmp    didUnstuff0 ;2 [20]
 
 127 unstuff1:               ;1 (branch taken)
 
 128     mov     x2, x1      ;1 [21] x1 contains last sampled (stuffed) bit
 
 129     andi    x3, ~0x02   ;1 [22]
 
 130     ori     shift, 0x02 ;1 [23]
 
 132     in      x1, USBIN   ;1 [25] <-- sample bit 2 again
 
 133     rjmp    didUnstuff1 ;2 [27]
 
 135 unstuff2:               ;1 (branch taken)
 
 136     andi    x3, ~0x04   ;1 [29]
 
 137     ori     shift, 0x04 ;1 [30]
 
 138     mov     x1, x2      ;1 [31] x2 contains last sampled (stuffed) bit
 
 140     in      x2, USBIN   ;1 [33] <-- sample bit 3
 
 141     rjmp    didUnstuff2 ;2 [35]
 
 143 unstuff3:               ;1 (branch taken)
 
 144     in      x2, USBIN   ;1 [34] <-- sample stuffed bit 3 [one cycle too late]
 
 145     andi    x3, ~0x08   ;1 [35]
 
 146     ori     shift, 0x08 ;1 [36]
 
 147     rjmp    didUnstuff3 ;2 [38]
 
 149 unstuff4:               ;1 (branch taken)
 
 150     andi    x3, ~0x10   ;1 [40]
 
 151     in      x1, USBIN   ;1 [41] <-- sample stuffed bit 4
 
 152     ori     shift, 0x10 ;1 [42]
 
 153     rjmp    didUnstuff4 ;2 [44]
 
 155 unstuff5:               ;1 (branch taken)
 
 156     andi    x3, ~0x20   ;1 [48]
 
 157     in      x2, USBIN   ;1 [49] <-- sample stuffed bit 5
 
 158     ori     shift, 0x20 ;1 [50]
 
 159     rjmp    didUnstuff5 ;2 [52]
 
 161 unstuff6:               ;1 (branch taken)
 
 162     andi    x3, ~0x40   ;1 [56]
 
 163     in      x1, USBIN   ;1 [57] <-- sample stuffed bit 6
 
 164     ori     shift, 0x40 ;1 [58]
 
 165     rjmp    didUnstuff6 ;2 [60]
 
 167 ; extra jobs done during bit interval:
 
 168 ; bit 0:    store, clear [SE0 is unreliable here due to bit dribbling in hubs]
 
 170 ; bit 2:    overflow check
 
 171 ; bit 3:    recovery from delay [bit 0 tasks took too long]
 
 177     eor     x3, shift   ;1 [0] reconstruct: x3 is 0 at bit locations we changed, 1 at others
 
 178     in      x1, USBIN   ;1 [1] <-- sample bit 0
 
 179     st      y+, x3      ;2 [3] store data
 
 183     bst     x2, USBMINUS;1 [7]
 
 185     in      x2, USBIN   ;1 [9] <-- sample bit 1 (or possibly bit 0 stuffed)
 
 186     andi    x2, USBMASK ;1 [10]
 
 187     breq    se0         ;1 [11] SE0 check for bit 1
 
 188     andi    shift, 0xf9 ;1 [12]
 
 190     breq    unstuff0    ;1 [13]
 
 192     bst     x1, USBMINUS;1 [15]
 
 195     in      x1, USBIN   ;1 [17] <-- sample bit 2 (or possibly bit 1 stuffed)
 
 196     andi    shift, 0xf3 ;1 [18]
 
 197     breq    unstuff1    ;1 [19] do remaining work for bit 1
 
 200     brcs    overflow    ;1 [21] loop control
 
 202     bst     x2, USBMINUS;1 [23]
 
 204     in      x2, USBIN   ;1 [25] <-- sample bit 3 (or possibly bit 2 stuffed)
 
 205     andi    shift, 0xe7 ;1 [26]
 
 206     breq    unstuff2    ;1 [27]
 
 209     bst     x1, USBMINUS;1 [29]
 
 212     andi    shift, 0xcf ;1 [31]
 
 213     breq    unstuff3    ;1 [32]
 
 214     in      x1, USBIN   ;1 [33] <-- sample bit 4
 
 216     bst     x2, USBMINUS;1 [35]
 
 219     andi    shift, 0x9f ;1 [37]
 
 220     breq    unstuff4    ;1 [38]
 
 222     in      x2, USBIN   ;1 [41] <-- sample bit 5
 
 224     bst     x1, USBMINUS;1 [43]
 
 227     andi    shift, 0x3f ;1 [45]
 
 228     breq    unstuff5    ;1 [46]
 
 230     in      x1, USBIN   ;1 [49] <-- sample bit 6
 
 232     bst     x2, USBMINUS;1 [51]
 
 235     cpi     shift, 0x02 ;1 [53]
 
 236     brlo    unstuff6    ;1 [54]
 
 238     in      x2, USBIN   ;1 [57] <-- sample bit 7
 
 240     bst     x1, USBMINUS;1 [59]
 
 243     cpi     shift, 0x04 ;1 [61]
 
 244     brsh    rxLoop      ;2 [63] loop control
 
 246     andi    x3, ~0x80   ;1 [63]
 
 247     ori     shift, 0x80 ;1 [64]
 
 248     in      x2, USBIN   ;1 [65] <-- sample stuffed bit 7
 
 250     rjmp    didUnstuff7 ;2 [68]
 
 252 macro POP_STANDARD ; 12 cycles
 
 260 macro POP_RETI     ; 5 cycles
 
 266 #include "asmcommon.inc"
 
 268 ;----------------------------------------------------------------------------
 
 270 ;----------------------------------------------------------------------------
 
 275     ror     shift               ;[-5] [11] [59]
 
 276     brcc    doExorN1            ;[-4]      [60]
 
 279     lsl     shift               ;[-1] compensate ror after rjmp stuffDelay
 
 280     nop                         ;[00] stuffing consists of just waiting 8 cycles
 
 281     rjmp    stuffN1Delay        ;[01] after ror, C bit is reliably clear
 
 283 sendNakAndReti:                 ;0 [-19] 19 cycles until SOP
 
 284     ldi     x3, USBPID_NAK      ;1 [-18]
 
 285     rjmp    usbSendX3           ;2 [-16]
 
 286 sendAckAndReti:                 ;0 [-19] 19 cycles until SOP
 
 287     ldi     x3, USBPID_ACK      ;1 [-18]
 
 288     rjmp    usbSendX3           ;2 [-16]
 
 289 sendCntAndReti:                 ;0 [-17] 17 cycles until SOP
 
 292     ldi     YL, 20              ;1 [-15] 'x3' is R20
 
 295 ;   rjmp    usbSendAndReti      fallthrough
 
 299 ; J = (D+ = 0), (D- = 1) or USBOUT = 0x01
 
 300 ; K = (D+ = 1), (D- = 0) or USBOUT = 0x02
 
 301 ; Spec allows 7.5 bit times from EOP to SOP for replies (= 60 cycles)
 
 304 ;pointer to data in 'Y'
 
 305 ;number of bytes in 'cnt' -- including sync byte
 
 306 ;uses: x1...x2, x4, shift, cnt, Y [x1 = mirror USBOUT, x2 = USBMASK, x4 = bitstuff cnt]
 
 307 ;Numbers in brackets are time since first bit of sync pattern is sent (start of instruction)
 
 309     in      x2, USBDDR          ;[-12] 12 cycles until SOP
 
 310     ori     x2, USBMASK         ;[-11]
 
 311     sbi     USBOUT, USBMINUS    ;[-10] prepare idle state; D+ and D- must have been 0 (no pullups)
 
 312     out     USBDDR, x2          ;[-8] <--- acquire bus
 
 313     in      x1, USBOUT          ;[-7] port mirror for tx loop
 
 314     ldi     shift, 0x40         ;[-6] sync byte is first byte sent (we enter loop after ror)
 
 315     ldi     x2, USBMASK         ;[-5]
 
 318     eor     x1, x2              ;[-2] [06] [62]
 
 319     ldi     x4, 6               ;[-1] [07] [63]
 
 322     out     USBOUT, x1          ;[00] [08] [64] <--- set bit
 
 327     lsl     shift               ;[05] compensate ror after rjmp stuffDelay
 
 328     rjmp    stuffN2Delay        ;[06] after ror, C bit is reliably clear
 
 330     eor     x1, x2              ;[04] [12]
 
 334     subi    cnt, 171            ;[07] [15] trick: (3 * 171) & 0xff = 1
 
 335     out     USBOUT, x1          ;[08] [16] <--- set bit
 
 336     brcs    txBitloop           ;[09]      [25] [41]
 
 343     lsl     shift               ;[46] compensate ror after rjmp stuffDelay
 
 344     nop                         ;[47] stuffing consists of just waiting 8 cycles
 
 345     rjmp    stuff6Delay         ;[48] after ror, C bit is reliably clear
 
 347     eor     x1, x2              ;[45] [53]
 
 352     out     USBOUT, x1          ;[48] <--- set bit
 
 356     lsl     shift               ;[52] compensate ror after rjmp stuffDelay
 
 357     rjmp    stuff7Delay         ;[53] after ror, C bit is reliably clear
 
 359     eor     x1, x2              ;[51] [59]
 
 364     out     USBOUT, x1          ;[56] <--- set bit
 
 365     brne    txByteLoop          ;[57]
 
 368     cbr     x1, USBMASK         ;[58] prepare SE0 [spec says EOP may be 15 to 18 cycles]
 
 369     lds     x2, usbNewDeviceAddr;[59]
 
 370     lsl     x2                  ;[61] we compare with left shifted address
 
 371     subi    YL, 2 + 20          ;[62] Only assign address on data packets, not ACK/NAK in x3
 
 373     out     USBOUT, x1          ;[00] <-- out SE0 -- from now 2 bits = 16 cycles until bus idle
 
 374 ;2006-03-06: moved transfer of new address to usbDeviceAddr from C-Code to asm:
 
 375 ;set address only after data packet was sent, not after handshake
 
 376     breq    skipAddrAssign      ;[01]
 
 377     sts     usbDeviceAddr, x2   ; if not skipped: SE0 is one cycle longer
 
 379 ;end of usbDeviceAddress transfer
 
 380     ldi     x2, 1<<USB_INTR_PENDING_BIT;[03] int0 occurred during TX -- clear pending flag
 
 381     USB_STORE_PENDING(x2)       ;[04]
 
 382     ori     x1, USBIDLE         ;[05]
 
 384     cbr     x2, USBMASK         ;[07] set both pins to input
 
 386     cbr     x3, USBMASK         ;[09] configure no pullup on both pins
 
 390     out     USBOUT, x1          ;[16] <-- out J (idle) -- end of SE0 (EOP signal)
 
 391     out     USBDDR, x2          ;[17] <-- release bus now
 
 392     out     USBOUT, x3          ;[18] <-- ensure no pull-up resistors are active