1 /* Name: usbdrvasm15.inc
 
   2  * Project: V-USB, virtual USB port for Atmel's(r) AVR(r) microcontrollers
 
   3  * Author: contributed by V. Bosch
 
   4  * Creation Date: 2007-08-06
 
   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 15 MHz version of the asssembler part of the USB driver. It
 
  18 requires a 15 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 ;max stack usage: [ret(2), YL, SREG, YH, bitcnt, shift, x1, x2, x3, x4, cnt] = 12 bytes
 
  29 ;nominal frequency: 15 MHz -> 10.0 cycles per bit, 80.0 cycles per byte
 
  30 ; Numbers in brackets are clocks counted from center of last sync bit
 
  31 ; when instruction starts
 
  33 ;----------------------------------------------------------------------------
 
  34 ; order of registers pushed: 
 
  35 ;       YL, SREG [sofError] YH, shift, x1, x2, x3, bitcnt, cnt, x4
 
  36 ;----------------------------------------------------------------------------
 
  38     push    YL                   ;2     push only what is necessary to sync with edge ASAP
 
  41 ;----------------------------------------------------------------------------
 
  42 ; Synchronize with sync pattern:
 
  44 ;   sync byte (D-) pattern LSb to MSb: 01010100 [1 = idle = J, 0 = K]
 
  45 ;   sync up with J to K edge during sync pattern -- use fastest possible loops
 
  46 ;The first part waits at most 1 bit long since we must be in sync pattern.
 
  47 ;YL is guarenteed to be < 0x80 because I flag is clear. When we jump to
 
  48 ;waitForJ, ensure that this prerequisite is met.
 
  52     brne    waitForJ        ; just make sure we have ANY timeout
 
  53 ;-------------------------------------------------------------------------------
 
  54 ; The following code results in a sampling window of < 1/4 bit 
 
  55 ;       which meets the spec.
 
  56 ;-------------------------------------------------------------------------------
 
  58     sbis    USBIN, USBMINUS      ;1 [00] <-- sample
 
  60     sbis    USBIN, USBMINUS      ;       <-- sample
 
  62     sbis    USBIN, USBMINUS      ;       <-- sample
 
  64     sbis    USBIN, USBMINUS      ;       <-- sample
 
  66     sbis    USBIN, USBMINUS      ;       <-- sample
 
  68     sbis    USBIN, USBMINUS      ;       <-- sample
 
  74 #endif  /* USB_COUNT_SOF */
 
  79 ;------------------------------------------------------------------------------
 
  80 ; {3, 5} after falling D- edge, average delay: 4 cycles [we want 5 for 
 
  82 ;       we have 1 bit time for setup purposes, then sample again. 
 
  83 ;       Numbers in brackets are cycles from center of first sync (double K) 
 
  84 ;       bit after the instruction
 
  85 ;------------------------------------------------------------------------------
 
  87     lds     YL, usbInputBufOffset;2 [03+04]     tx loop
 
  90     subi    YL, lo8(-(usbRxBuf)) ;1 [08]        [rx loop init]
 
  91     sbci    YH, hi8(-(usbRxBuf)) ;1 [09]        [rx loop init]
 
  94     sbis    USBIN, USBMINUS      ;1 [-1] [13] <--sample:we want two bits K (sample 1 cycle too early)
 
  95     rjmp    haveTwoBitsK         ;2 [00] [14]
 
  96     pop     shift                ;2      [15+16] undo the push from before
 
  97     pop     YH                   ;2      [17+18] undo the push from before
 
  98     rjmp    waitForK             ;2      [19+20] this was not the end of sync, retry
 
  99 ; The entire loop from waitForK until rjmp waitForK above must not exceed two
 
 100 ; bit times (= 20 cycles).
 
 102 ;----------------------------------------------------------------------------
 
 103 ; push more registers and initialize values while we sample the first bits:
 
 104 ;----------------------------------------------------------------------------
 
 105 haveTwoBitsK:                   ;- [01]
 
 109     push    bitcnt              ;2 [08+09]      
 
 110     in      x1, USBIN           ;1 [00] [10] <-- sample bit 0
 
 111     bst     x1, USBMINUS        ;1 [01]
 
 114     ldi     cnt, USB_BUFSIZE    ;1 [05] 
 
 115     push    x4                  ;2 [06+07] tx loop
 
 117 ;----------------------------------------------------------------------------
 
 118 ; Receiver loop (numbers in brackets are cycles within byte after instr)
 
 119 ;----------------------------------------------------------------------------
 
 120 unstuff0:                       ;- [07] (branch taken)
 
 121     andi    x3, ~0x01           ;1 [08]
 
 122     mov     x1, x2              ;1 [09] x2 contains last sampled (stuffed) bit
 
 123     in      x2, USBIN           ;1 [00] [10] <-- sample bit 1 again
 
 124     andi    x2, USBMASK         ;1 [01]
 
 125     breq    se0Hop              ;1 [02] SE0 check for bit 1 
 
 126     ori     shift, 0x01         ;1 [03] 0b00000001
 
 128     rjmp    didUnstuff0         ;2 [05]
 
 129 ;-----------------------------------------------------
 
 130 unstuff1:                       ;- [05] (branch taken)
 
 131     mov     x2, x1              ;1 [06] x1 contains last sampled (stuffed) bit
 
 132     andi    x3, ~0x02           ;1 [07]
 
 133     ori     shift, 0x02         ;1 [08] 0b00000010
 
 135     in      x1, USBIN           ;1 [00] [10] <-- sample bit 2 again
 
 136     andi    x1, USBMASK         ;1 [01]
 
 137     breq    se0Hop              ;1 [02] SE0 check for bit 2 
 
 138     rjmp    didUnstuff1         ;2 [03]
 
 139 ;-----------------------------------------------------
 
 140 unstuff2:                       ;- [05] (branch taken)
 
 141     andi    x3, ~0x04           ;1 [06]
 
 142     ori     shift, 0x04         ;1 [07] 0b00000100
 
 143     mov     x1, x2              ;1 [08] x2 contains last sampled (stuffed) bit
 
 145     in      x2, USBIN           ;1 [00] [10] <-- sample bit 3
 
 146     andi    x2, USBMASK         ;1 [01]
 
 147     breq    se0Hop              ;1 [02] SE0 check for bit 3 
 
 148     rjmp    didUnstuff2         ;2 [03]
 
 149 ;-----------------------------------------------------
 
 150 unstuff3:                       ;- [00] [10]  (branch taken)
 
 151     in      x2, USBIN           ;1 [01] [11] <-- sample stuffed bit 3 one cycle too late
 
 152     andi    x2, USBMASK         ;1 [02]
 
 153     breq    se0Hop              ;1 [03] SE0 check for stuffed bit 3 
 
 154     andi    x3, ~0x08           ;1 [04]
 
 155     ori     shift, 0x08         ;1 [05] 0b00001000
 
 156     rjmp    didUnstuff3         ;2 [06]
 
 157 ;----------------------------------------------------------------------------
 
 158 ; extra jobs done during bit interval:
 
 160 ; bit 0:    store, clear [SE0 is unreliable here due to bit dribbling in hubs], 
 
 161 ;               overflow check, jump to the head of rxLoop
 
 163 ; bit 2:    SE0 check, recovery from delay [bit 0 tasks took too long]
 
 164 ; bit 3:    SE0 check, recovery from delay [bit 0 tasks took too long]
 
 165 ; bit 4:    SE0 check, none
 
 166 ; bit 5:    SE0 check, none
 
 167 ; bit 6:    SE0 check, none
 
 168 ; bit 7:    SE0 check, reconstruct: x3 is 0 at bit locations we changed, 1 at others
 
 169 ;----------------------------------------------------------------------------
 
 171     in      x2, USBIN           ;1 [00] [10] <-- sample bit 1 (or possibly bit 0 stuffed)
 
 172     andi    x2, USBMASK         ;1 [01]
 
 173     brne    SkipSe0Hop          ;1 [02]
 
 175     rjmp    se0                 ;2 [03] SE0 check for bit 1 
 
 178     andi    shift, 0xf9         ;1 [05] 0b11111001
 
 179     breq    unstuff0            ;1 [06]
 
 182     bst     x1, USBMINUS        ;1 [08]
 
 184     in      x1, USBIN           ;1 [00] [10] <-- sample bit 2 (or possibly bit 1 stuffed)
 
 185     andi    x1, USBMASK         ;1 [01]
 
 186     breq    se0Hop              ;1 [02] SE0 check for bit 2 
 
 187     andi    shift, 0xf3         ;1 [03] 0b11110011
 
 188     breq    unstuff1            ;1 [04] do remaining work for bit 1
 
 191     bst     x2, USBMINUS        ;1 [06]
 
 194     in      x2, USBIN           ;1 [00] [10] <-- sample bit 3 (or possibly bit 2 stuffed)
 
 195     andi    x2, USBMASK         ;1 [01]
 
 196     breq    se0Hop              ;1 [02] SE0 check for bit 3 
 
 197     andi    shift, 0xe7         ;1 [03] 0b11100111
 
 198     breq    unstuff2            ;1 [04]
 
 201     bst     x1, USBMINUS        ;1 [06]
 
 204     andi    shift, 0xcf         ;1 [08] 0b11001111
 
 205     breq    unstuff3            ;1 [09]
 
 206     in      x1, USBIN           ;1 [00] [10] <-- sample bit 4
 
 207     andi    x1, USBMASK         ;1 [01]
 
 208     breq    se0Hop              ;1 [02] SE0 check for bit 4
 
 210     bst     x2, USBMINUS        ;1 [04]
 
 213     andi    shift, 0x9f         ;1 [06] 0b10011111
 
 214     breq    unstuff4            ;1 [07]
 
 216     in      x2, USBIN           ;1 [00] [10] <-- sample bit 5
 
 217     andi    x2, USBMASK         ;1 [01]
 
 218     breq    se0                 ;1 [02] SE0 check for bit 5
 
 220     bst     x1, USBMINUS        ;1 [04]
 
 223     andi    shift, 0x3f         ;1 [06] 0b00111111
 
 224     breq    unstuff5            ;1 [07]
 
 226     in      x1, USBIN           ;1 [00] [10] <-- sample bit 6
 
 227     andi    x1, USBMASK         ;1 [01]
 
 228     breq    se0                 ;1 [02] SE0 check for bit 6
 
 230     bst     x2, USBMINUS        ;1 [04]
 
 233     cpi     shift, 0x02         ;1 [06] 0b00000010
 
 234     brlo    unstuff6            ;1 [07]
 
 236     in      x2, USBIN           ;1 [00] [10] <-- sample bit 7
 
 237     andi    x2, USBMASK         ;1 [01]
 
 238     breq    se0                 ;1 [02] SE0 check for bit 7
 
 240     bst     x1, USBMINUS        ;1 [04]
 
 243     cpi     shift, 0x04         ;1 [06] 0b00000100
 
 244     brlo    unstuff7            ;1 [07]
 
 245     eor     x3, shift           ;1 [08] reconstruct: x3 is 0 at bit locations we changed, 1 at others
 
 247     in      x1, USBIN           ;1 [00] [10] <-- sample bit 0
 
 248     st      y+, x3              ;2 [01+02] store data
 
 250     bst     x2, USBMINUS        ;1 [04]
 
 253     brcs    overflow    ;1 [07]
 
 255 ;-----------------------------------------------------
 
 257     andi    x3, ~0x10           ;1 [09]
 
 258     in      x1, USBIN           ;1 [00] [10] <-- sample stuffed bit 4
 
 259     andi    x1, USBMASK         ;1 [01]
 
 260     breq    se0                 ;1 [02] SE0 check for stuffed bit 4
 
 261     ori     shift, 0x10         ;1 [03]
 
 262     rjmp    didUnstuff4         ;2 [04]
 
 263 ;-----------------------------------------------------
 
 265     ori     shift, 0x20         ;1 [09]
 
 266     in      x2, USBIN           ;1 [00] [10] <-- sample stuffed bit 5
 
 267     andi    x2, USBMASK         ;1 [01]
 
 268     breq    se0                 ;1 [02] SE0 check for stuffed bit 5
 
 269     andi    x3, ~0x20           ;1 [03]
 
 270     rjmp    didUnstuff5         ;2 [04]
 
 271 ;-----------------------------------------------------
 
 273     andi    x3, ~0x40           ;1 [09]
 
 274     in      x1, USBIN           ;1 [00] [10] <-- sample stuffed bit 6
 
 275     andi    x1, USBMASK         ;1 [01]
 
 276     breq    se0                 ;1 [02] SE0 check for stuffed bit 6
 
 277     ori     shift, 0x40         ;1 [03]
 
 278     rjmp    didUnstuff6         ;2 [04]
 
 279 ;-----------------------------------------------------
 
 281     andi    x3, ~0x80           ;1 [09]
 
 282     in      x2, USBIN           ;1 [00] [10] <-- sample stuffed bit 7
 
 283     andi    x2, USBMASK         ;1 [01]
 
 284     breq    se0                 ;1 [02] SE0 check for stuffed bit 7
 
 285     ori     shift, 0x80         ;1 [03]
 
 286     rjmp    didUnstuff7         ;2 [04]
 
 288 macro POP_STANDARD ; 16 cycles
 
 298 macro POP_RETI     ; 5 cycles
 
 304 #include "asmcommon.inc"
 
 306 ;---------------------------------------------------------------------------
 
 309 ; J = (D+ = 0), (D- = 1)
 
 310 ; K = (D+ = 1), (D- = 0)
 
 311 ; Spec allows 7.5 bit times from EOP to SOP for replies
 
 312 ;---------------------------------------------------------------------------
 
 317     rjmp    didStuffN           ;1 [08]
 
 318 ;---------------------------------------------------------------------------    
 
 322     rjmp    didStuff6           ;1 [07]
 
 323 ;---------------------------------------------------------------------------
 
 328     rjmp    didStuff7           ;1 [06]
 
 329 ;---------------------------------------------------------------------------
 
 330 sendNakAndReti:                 ;- [-19]
 
 331     ldi     x3, USBPID_NAK      ;1 [-18]
 
 332     rjmp    sendX3AndReti       ;1 [-17]
 
 333 ;---------------------------------------------------------------------------
 
 334 sendAckAndReti:                 ;- [-17]
 
 335     ldi     cnt, USBPID_ACK     ;1 [-16]
 
 336 sendCntAndReti:                 ;- [-16]
 
 338 sendX3AndReti:                  ;- [-15]
 
 339     ldi     YL, 20              ;1 [-14] x3==r20 address is 20
 
 342 ;   rjmp    usbSendAndReti      fallthrough
 
 343 ;---------------------------------------------------------------------------
 
 345 ;pointer to data in 'Y'
 
 346 ;number of bytes in 'cnt' -- including sync byte [range 2 ... 12]
 
 347 ;uses: x1...x4, btcnt, shift, cnt, Y
 
 348 ;Numbers in brackets are time since first bit of sync pattern is sent
 
 349 ;We need not to match the transfer rate exactly because the spec demands 
 
 350 ;only 1.5% precision anyway.
 
 351 usbSendAndReti:                 ;- [-13] 13 cycles until SOP
 
 352     in      x2, USBDDR          ;1 [-12]
 
 353     ori     x2, USBMASK         ;1 [-11]
 
 354     sbi     USBOUT, USBMINUS    ;2 [-09-10] prepare idle state; D+ and D- must have been 0 (no pullups)
 
 355     in      x1, USBOUT          ;1 [-08] port mirror for tx loop
 
 356     out     USBDDR, x2          ;1 [-07] <- acquire bus
 
 357         ; need not init x2 (bitstuff history) because sync starts with 0 
 
 358     ldi     x4, USBMASK         ;1 [-06]        exor mask
 
 359     ldi     shift, 0x80         ;1 [-05]        sync byte is first byte sent
 
 360     ldi     bitcnt, 6           ;1 [-04] 
 
 361 txBitLoop:                      ;- [-04] [06]
 
 362     sbrs    shift, 0            ;1 [-03] [07]
 
 363     eor     x1, x4              ;1 [-02] [08] 
 
 364     ror     shift               ;1 [-01] [09]  
 
 366     out     USBOUT, x1          ;1 [00]  [10] <-- out N
 
 369     brcc    bitstuffN           ;1 [03]
 
 371     brne    txBitLoop           ;1 [05]
 
 372     sbrs    shift, 0            ;1 [06]
 
 377     out     USBOUT, x1          ;1 [00] [10] <-- out 6
 
 380     brcc    bitstuff6           ;1 [03]
 
 381     sbrs    shift, 0            ;1 [04]
 
 386     ldi     bitcnt, 6           ;1 [08]
 
 388     out     USBOUT, x1          ;1 [00] [10] <-- out 7
 
 389     brcc    bitstuff7           ;1 [01]
 
 390     ld      shift, y+           ;2 [02+03]
 
 392     brne    txBitLoop           ;1 [05]
 
 394     cbr     x1, USBMASK         ;1 [06]         prepare SE0 [spec says EOP may be 19 to 23 cycles]
 
 395     lds     x2, usbNewDeviceAddr;2 [07+08]
 
 396     lsl     x2                  ;1 [09] we compare with left shifted address
 
 397 ;2006-03-06: moved transfer of new address to usbDeviceAddr from C-Code to asm:
 
 398 ;set address only after data packet was sent, not after handshake
 
 399     out     USBOUT, x1          ;1 [00] [10] <-- out SE0-- from now 2 bits==20 cycl. until bus idle
 
 400     subi    YL, 20 + 2          ;1 [01] Only assign address on data packets, not ACK/NAK in x3
 
 402     breq    skipAddrAssign      ;1 [03]
 
 403     sts     usbDeviceAddr, x2   ;2 [04+05] if not skipped: SE0 is one cycle longer
 
 404 ;----------------------------------------------------------------------------
 
 405 ;end of usbDeviceAddress transfer
 
 406 skipAddrAssign:                         ;- [03/04]
 
 407     ldi     x2, 1<<USB_INTR_PENDING_BIT ;1 [05] int0 occurred during TX -- clear pending flag
 
 408     USB_STORE_PENDING(x2)           ;1 [06]
 
 409     ori     x1, USBIDLE                 ;1 [07]
 
 410     in      x2, USBDDR                  ;1 [08]
 
 411     cbr     x2, USBMASK                 ;1 [09] set both pins to input
 
 413     cbr     x3, USBMASK                 ;1 [11] configure no pullup on both pins
 
 415 se0Delay:                               ;- [12] [15] 
 
 417     brne    se0Delay                    ;1 [14] [17] 
 
 419     out     USBOUT, x1                  ;1      [20] <--out J (idle) -- end of SE0 (EOP sig.)
 
 420     out     USBDDR, x2                  ;1      [21] <--release bus now
 
 421     out     USBOUT, x3                  ;1      [22] <--ensure no pull-up resistors are active
 
 422     rjmp    doReturn                    ;1      [23]
 
 423 ;---------------------------------------------------------------------------