⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 usbdrvasm.s

📁 采用atmel公司的mega8芯片设计的USB cdc类
💻 S
📖 第 1 页 / 共 2 页
字号:
isData:
    lds     x2, usbCurrentTok   ;2
    tst     x2                  ;1
    breq    rxDoReturn          ;1 for other device or spontaneous data -- ignore
    lds     x1, usbRxLen        ;2
    cpi     x1, 0               ;1
    brne    sendNakAndReti      ;1 no buffer space available / {30, 38} from SE0 end
; 2006-03-11: The following two lines fix a problem where the device was not
; recognized if usbPoll() was called less frequently than once every 4 ms.
    cpi     cnt, 4              ;1 zero sized data packets are status phase only -- ignore and ack
    brmi    sendAckAndReti      ;1 keep rx buffer clean -- we must not NAK next SETUP
    sts     usbRxLen, cnt       ;2 store received data, swap buffers
    sts     usbRxToken, x2      ;2
    lds     x1, usbAppBuf       ;2
    sts     usbAppBuf, YL       ;2
    sts     usbInputBuf, x1     ;2 buffers now swapped
    rjmp    sendAckAndReti      ;2 -> {43, 51} from SE0 end

handleIn:                       ; {18, 26} from SE0 end
    cp      x2, shift           ;1 shift contains our device addr
    brne    rxDoReturn          ;1 other device
#if USB_CFG_HAVE_INTRIN_ENDPOINT
    sbrc    x3, 7               ;2 x3 contains addr + endpoint
    rjmp    handleIn1           ;0
#endif
    lds     cnt, usbTxLen       ;2
    cpi     cnt, -1             ;1
    breq    sendNakAndReti      ;1 -> {27, 35} from SE0 end
    ldi     x1, -1              ;1
    sts     usbTxLen, x1        ;2 buffer is now free
    ldi     YL, lo8(usbTxBuf)   ;1
    ldi     YH, hi8(usbTxBuf)   ;1
    rjmp    usbSendAndReti      ;2 -> {34, 43} from SE0 end

; Comment about when to set usbTxLen to -1:
; We should set it back to -1 when we receive the ACK from the host. This would
; be simple to implement: One static variable which stores whether the last
; tx was for endpoint 0 or 1 and a compare in the receiver to distinguish the
; ACK. However, we set it back to -1 immediately when we send the package,
; assuming that no error occurs and the host sends an ACK. We save one byte
; RAM this way and avoid potential problems with endless retries. The rest of
; the driver assumes error-free transfers anyway.

otherOutOrSetup:
    clr     x1
    sts     usbCurrentTok, x1
rxDoReturn:
    pop     x3                  ;2
    pop     YL                  ;2
    pop     YH                  ;2
    rjmp    sofError            ;2

isSetupOrOut:                   ; we must be fast here -- a data package may follow / {,24} into next frame
    cp      x2, shift           ;1 shift contains our device addr
    brne    otherOutOrSetup     ;1 other device -- ignore
#if USB_CFG_IMPLEMENT_FN_WRITEOUT   /* if we need second OUT endpoint, store endpoint address */
    andi    x1, 0x7f            ;1 mask out MSb in token
    andi    x3, 0x80            ;1 mask out all but endpoint address
    or      x1, x3              ;1 merge endpoint into currentToken
    sts     usbCurrentTok, x1   ;2
    brmi    dontResetEP0        ;1 endpoint 1 -> don't reset endpoint 0 input
#else
    sts     usbCurrentTok, x1   ;2
#endif
;A transmission can still have data in the output buffer while we receive a
;SETUP package with an IN phase. To avoid that the old data is sent as a reply,
;we abort transmission.
    ldi     x1, -1              ;1
    sts     usbMsgLen, x1       ;2
    sts     usbTxLen, x1        ;2 abort transmission
dontResetEP0:
    pop     x3                  ;2
    pop     YL                  ;2
    in      x1, USB_INTR_PENDING;1
    sbrc    x1, USB_INTR_PENDING_BIT;1 check whether data is already arriving {,41} into next frame
    rjmp    shortcutToStart     ;2 save the pops and pushes -- a new interrupt is aready pending
;If the jump above was not taken, we can be at {,2} into the next frame here
    pop     YH                  ;2
txDoReturn:
sofError:                       ; error in start of frame -- ignore frame
    ldi     x1, 1<<USB_INTR_PENDING_BIT;1 many int0 events occurred during our processing -- clear pending flag
    out     USB_INTR_PENDING, x1;1
    pop     shift               ;2
    pop     cnt                 ;2
    pop     x2                  ;2
    pop     x1                  ;2
    out     SREG, x1            ;1
    pop     x1                  ;2
    reti                        ;4 -> {,21} into next frame -> up to 3 sync bits missed


sendNakAndReti:                 ; 21 cycles until SOP
    ldi     YL, lo8(usbNakBuf)  ;1
    ldi     YH, hi8(usbNakBuf)  ;1
    rjmp    usbSendToken        ;2

sendAckAndReti:                 ; 19 cycles until SOP
    ldi     YL, lo8(usbAckBuf)  ;1
    ldi     YH, hi8(usbAckBuf)  ;1
usbSendToken:
    ldi     cnt, 2              ;1
;;;;rjmp    usbSendAndReti      fallthrough

; USB spec says:
; idle = J
; J = (D+ = 0), (D- = 1) or USBOUT = 0x01
; K = (D+ = 1), (D- = 0) or USBOUT = 0x02
; Spec allows 7.5 bit times from EOP to SOP for replies (= 60 cycles)

;usbSend:
;pointer to data in 'Y'
;number of bytes in 'cnt' -- including sync byte
;uses: x1...x4, shift, cnt, Y
usbSendAndReti:             ; SOP starts 16 cycles after call
    push    x4              ;2
    in      x1, USBOUT      ;1
    cbr     x1, USBMASK     ;1 mask out data bits
    ori     x1, USBIDLE     ;1 idle
    out     USBOUT, x1      ;1 prepare idle state
    ldi     x4, USBMASK     ;1 exor mask
    in      x2, USBDDR      ;1
    ori     x2, USBMASK     ;1 set both pins to output
    out     USBDDR, x2      ;1 <-- acquire bus now
; need not init x2 (bitstuff history) because sync starts with 0
    ldi     shift, 0x80     ;1 sync byte is first byte sent
    rjmp    txLoop          ;2 -> 13 + 3 = 16 cycles until SOP

#if USB_CFG_HAVE_INTRIN_ENDPOINT    /* placed here due to relative jump range */
handleIn1:                  ;{23, 31} from SE0
    ldi     x1, -1          ;1
#if USB_CFG_HAVE_INTRIN_ENDPOINT3
; 2006-06-10 as suggested by O.Tamura: support second INTR IN / BULK IN endpoint
    ldd     x2, y+2         ;2
    sbrc    x2, 0           ;2 1
    rjmp    handleIn3       ;0 2
#endif
    lds     cnt, usbTxLen1  ;2
    cpi     cnt, -1         ;1
    breq    sendNakAndReti  ;1
    sts     usbTxLen1, x1   ;2
    ldi     YL, lo8(usbTxBuf1);1
    ldi     YH, hi8(usbTxBuf1);1
    rjmp    usbSendAndReti  ;2 -> arrives at usbSendAndReti {34, 42} from SE0

#if USB_CFG_HAVE_INTRIN_ENDPOINT3
handleIn3:
    lds     cnt, usbTxLen3  ;2
    cpi     cnt, -1         ;1
    breq    sendNakAndReti  ;1
    sts     usbTxLen3, x1   ;2
    ldi     YL, lo8(usbTxBuf3);1
    ldi     YH, hi8(usbTxBuf3);1
    rjmp    usbSendAndReti  ;2 -> arrives at usbSendAndReti {39, 47} from SE0
#endif
#endif

bitstuff0:                  ;1 (for branch taken)
    eor     x1, x4          ;1
    ldi     x2, 0           ;1
    out     USBOUT, x1      ;1 <-- out
    rjmp    didStuff0       ;2 branch back 2 cycles earlier
bitstuff1:                  ;1 (for branch taken)
    eor     x1, x4          ;1
    ldi     x2, 0           ;1
    sec                     ;1 set carry so that brsh will not jump
    out     USBOUT, x1      ;1 <-- out
    rjmp    didStuff1       ;2 jump back 1 cycle earler
bitstuff2:                  ;1 (for branch taken)
    eor     x1, x4          ;1
    ldi     x2, 0           ;1
    rjmp    didStuff2       ;2 jump back 3 cycles earlier and do out
bitstuff3:                  ;1 (for branch taken)
    eor     x1, x4          ;1
    ldi     x2, 0           ;1
    rjmp    didStuff3       ;2 jump back earlier

txLoop:
    sbrs    shift, 0        ;1
    eor     x1, x4          ;1
    out     USBOUT, x1      ;1 <-- out
    ror     shift           ;1
    ror     x2              ;1
didStuff0:
    cpi     x2, 0xfc        ;1
    brsh    bitstuff0       ;1
    sbrs    shift, 0        ;1
    eor     x1, x4          ;1
    ror     shift           ;1
    out     USBOUT, x1      ;1 <-- out
    ror     x2              ;1
    cpi     x2, 0xfc        ;1
didStuff1:
    brsh    bitstuff1       ;1
    sbrs    shift, 0        ;1
    eor     x1, x4          ;1
    ror     shift           ;1
    ror     x2              ;1
didStuff2:
    out     USBOUT, x1      ;1 <-- out
    cpi     x2, 0xfc        ;1
    brsh    bitstuff2       ;1
    sbrs    shift, 0        ;1
    eor     x1, x4          ;1
    ror     shift           ;1
    ror     x2              ;1
didStuff3:
    cpi     x2, 0xfc        ;1
    out     USBOUT, x1      ;1 <-- out
    brsh    bitstuff3       ;1
    nop2                    ;2
    ld      x3, y+          ;2
    sbrs    shift, 0        ;1
    eor     x1, x4          ;1
    out     USBOUT, x1      ;1 <-- out
    ror     shift           ;1
    ror     x2              ;1
didStuff4:
    cpi     x2, 0xfc        ;1
    brsh    bitstuff4       ;1
    sbrs    shift, 0        ;1
    eor     x1, x4          ;1
    ror     shift           ;1
    out     USBOUT, x1      ;1 <-- out
    ror     x2              ;1
    cpi     x2, 0xfc        ;1
didStuff5:
    brsh    bitstuff5       ;1
    sbrs    shift, 0        ;1
    eor     x1, x4          ;1
    ror     shift           ;1
    ror     x2              ;1
didStuff6:
    out     USBOUT, x1      ;1 <-- out
    cpi     x2, 0xfc        ;1
    brsh    bitstuff6       ;1
    sbrs    shift, 0        ;1
    eor     x1, x4          ;1
    ror     shift           ;1
    ror     x2              ;1
didStuff7:
    cpi     x2, 0xfc        ;1
    out     USBOUT, x1      ;1 <-- out
    brsh    bitstuff7       ;1
    mov     shift, x3       ;1
    dec     cnt             ;1
    brne    txLoop          ;2 | 1
    cbr     x1, USBMASK     ;1 prepare SE0 [spec says EOP may be 15 to 18 cycles]
    pop     x4              ;2
    out     USBOUT, x1      ;1 <-- out SE0 -- from now 2 bits = 16 cycles until bus idle
    ldi     cnt, 2          ;| takes cnt * 3 cycles
se0Delay:                   ;|
    dec     cnt             ;|
    brne    se0Delay        ;| -> 2 * 3 = 6 cycles
;2006-03-06: moved transfer of new address to usbDeviceAddr from C-Code to asm:
    lds     x2, usbNewDeviceAddr    ;2
    subi    YL, lo8(usbNakBuf + 2)  ;1
    sbci    YH, hi8(usbNakBuf + 2)  ;1
    breq    skipAddrAssign          ;2
    sts     usbDeviceAddr, x2       ;0  if not skipped: SE0 is one cycle longer
skipAddrAssign:
;end of usbDeviceAddress transfer
    ori     x1, USBIDLE     ;1
    in      x2, USBDDR      ;1
    cbr     x2, USBMASK     ;1 set both pins to input
    out     USBOUT, x1      ;1 <-- out J (idle) -- end of SE0 (EOP signal)
    cbr     x1, USBMASK     ;1 configure no pullup on both pins
    pop     x3              ;2
    pop     YL              ;2
    out     USBDDR, x2      ;1 <-- release bus now
    out     USBOUT, x1      ;1 set pullup state
    pop     YH              ;2
    rjmp    txDoReturn      ;2 [we want to jump to rxDoReturn, but this saves cycles]


bitstuff4:                  ;1 (for branch taken)
    eor     x1, x4          ;1
    ldi     x2, 0           ;1
    out     USBOUT, x1      ;1 <-- out
    rjmp    didStuff4       ;2 jump back 2 cycles earlier
bitstuff5:                  ;1 (for branch taken)
    eor     x1, x4          ;1
    ldi     x2, 0           ;1
    sec                     ;1 set carry so that brsh is not taken
    out     USBOUT, x1      ;1 <-- out
    rjmp    didStuff5       ;2 jump back 1 cycle earlier
bitstuff6:                  ;1 (for branch taken)
    eor     x1, x4          ;1
    ldi     x2, 0           ;1
    rjmp    didStuff6       ;2 jump back 3 cycles earlier and do out there
bitstuff7:                  ;1 (for branch taken)
    eor     x1, x4          ;1
    ldi     x2, 0           ;1
    rjmp    didStuff7       ;2 jump back 4 cycles earlier

; ######################## utility functions ########################

#ifdef __IAR_SYSTEMS_ASM__
/* Register assignments for usbCrc16 on IAR cc */
/* Calling conventions on IAR:
 * First parameter passed in r16/r17, second in r18/r19 and so on.
 * Callee must preserve r4-r15, r24-r29 (r28/r29 is frame pointer)
 * Result is passed in r16/r17
 * In case of the "tiny" memory model, pointers are only 8 bit with no
 * padding. We therefore pass argument 1 as "16 bit unsigned".
 */
RTMODEL "__rt_version", "3"
/* The line above will generate an error if cc calling conventions change.
 * The value "3" above is valid for IAR 4.10B/W32
 */
#   define argLen   r18 /* argument 2 */
#   define argPtrL  r16 /* argument 1 */
#   define argPtrH  r17 /* argument 1 */

#   define resCrcL  r16 /* result */
#   define resCrcH  r17 /* result */

#   define ptrL     ZL
#   define ptrH     ZH
#   define ptr      Z
#   define byte     r22
#   define bitCnt   r19
#   define polyL    r20
#   define polyH    r21
#   define scratch  r23

#else  /* __IAR_SYSTEMS_ASM__ */ 
/* Register assignments for usbCrc16 on gcc */
/* Calling conventions on gcc:
 * First parameter passed in r24/r25, second in r22/23 and so on.
 * Callee must preserve r1-r17, r28/r29
 * Result is passed in r24/r25
 */
#   define argLen   r22 /* argument 2 */
#   define argPtrL  r24 /* argument 1 */
#   define argPtrH  r25 /* argument 1 */

#   define resCrcL  r24 /* result */
#   define resCrcH  r25 /* result */

#   define ptrL     XL
#   define ptrH     XH
#   define ptr      x
#   define byte     r18
#   define bitCnt   r19
#   define polyL    r20
#   define polyH    r21
#   define scratch  r23

#endif

; extern unsigned usbCrc16(unsigned char *data, unsigned char len);
; data: r24/25
; len: r22
; temp variables:
;   r18: data byte
;   r19: bit counter
;   r20/21: polynomial
;   r23: scratch
;   r24/25: crc-sum
;   r26/27=X: ptr
usbCrc16:
    mov     ptrL, argPtrL
    mov     ptrH, argPtrH
    ldi     resCrcL, 0xff
    ldi     resCrcH, 0xff
    ldi     polyL, lo8(0xa001)
    ldi     polyH, hi8(0xa001)
crcByteLoop:
    subi    argLen, 1
    brcs    crcReady
    ld      byte, ptr+
    ldi     bitCnt, 8
crcBitLoop:
    mov     scratch, byte
    eor     scratch, resCrcL
    lsr     resCrcH
    ror     resCrcL
    lsr     byte
    sbrs    scratch, 0
    rjmp    crcNoXor
    eor     resCrcL, polyL
    eor     resCrcH, polyH
crcNoXor:
    dec     bitCnt
    brne    crcBitLoop
    rjmp    crcByteLoop
crcReady:
    com     resCrcL
    com     resCrcH
    ret

; extern unsigned usbCrc16Append(unsigned char *data, unsigned char len);
usbCrc16Append:
    rcall   usbCrc16
    st      ptr+, resCrcL
    st      ptr+, resCrcH
    ret

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -