manueller import aus nem CVS checkout (ist eh nur zum testen)
[ds1820tousb.git] / usbdrv / asmcommon.inc
1 /* Name: asmcommon.inc
2  * Project: AVR USB driver
3  * Author: Christian Starkjohann
4  * Creation Date: 2007-11-05
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$
9  */
10
11 /* Do not link this file! Link usbdrvasm.S instead, which includes the
12  * appropriate implementation!
13  */
14
15 /*
16 General Description:
17 This file contains assembler code which is shared among the USB driver
18 implementations for different CPU cocks. Since the code must be inserted
19 in the middle of the module, it's split out into this file and #included.
20
21 Jump destinations called from outside:
22     sofError: Called when no start sequence was found.
23     se0: Called when a package has been successfully received.
24     overflow: Called when receive buffer overflows.
25     doReturn: Called after sending data.
26
27 Outside jump destinations used by this module:
28     waitForJ: Called to receive an already arriving packet.
29     sendAckAndReti:
30     sendNakAndReti:
31     sendCntAndReti:
32     usbSendAndReti:
33
34 The following macros must be defined before this file is included:
35     .macro POP_STANDARD
36     .endm
37     .macro POP_RETI
38     .endm
39 */
40
41 #define token   x1
42
43 overflow:
44     ldi     x2, 1<<USB_INTR_PENDING_BIT
45     USB_STORE_PENDING(x2)       ; clear any pending interrupts
46 ignorePacket:
47     clr     token
48     rjmp    storeTokenAndReturn
49
50 ;----------------------------------------------------------------------------
51 ; Processing of received packet (numbers in brackets are cycles after center of SE0)
52 ;----------------------------------------------------------------------------
53 ;This is the only non-error exit point for the software receiver loop
54 ;we don't check any CRCs here because there is no time left.
55 se0:
56     subi    cnt, USB_BUFSIZE    ;[5]
57     neg     cnt                 ;[6]
58     sub     YL, cnt             ;[7]
59     sbci    YH, 0               ;[8]
60     ldi     x2, 1<<USB_INTR_PENDING_BIT ;[9]
61     USB_STORE_PENDING(x2)       ;[10] clear pending intr and check flag later. SE0 should be over.
62     ld      token, y            ;[11]
63     cpi     token, USBPID_DATA0 ;[13]
64     breq    handleData          ;[14]
65     cpi     token, USBPID_DATA1 ;[15]
66     breq    handleData          ;[16]
67     lds     shift, usbDeviceAddr;[17]
68     ldd     x2, y+1             ;[19] ADDR and 1 bit endpoint number
69     lsl     x2                  ;[21] shift out 1 bit endpoint number
70     cpse    x2, shift           ;[22]
71     rjmp    ignorePacket        ;[23]
72 /* only compute endpoint number in x3 if required later */
73 #if USB_CFG_HAVE_INTRIN_ENDPOINT || USB_CFG_IMPLEMENT_FN_WRITEOUT
74     ldd     x3, y+2             ;[24] endpoint number + crc
75     rol     x3                  ;[26] shift in LSB of endpoint
76 #endif
77     cpi     token, USBPID_IN    ;[27]
78     breq    handleIn            ;[28]
79     cpi     token, USBPID_SETUP ;[29]
80     breq    handleSetupOrOut    ;[30]
81     cpi     token, USBPID_OUT   ;[31]
82     brne    ignorePacket        ;[32] must be ack, nak or whatever
83 ;   rjmp    handleSetupOrOut    ; fallthrough
84
85 ;Setup and Out are followed by a data packet two bit times (16 cycles) after
86 ;the end of SE0. The sync code allows up to 40 cycles delay from the start of
87 ;the sync pattern until the first bit is sampled. That's a total of 56 cycles.
88 handleSetupOrOut:               ;[32]
89 #if USB_CFG_IMPLEMENT_FN_WRITEOUT   /* if we have data for endpoint != 0, set usbCurrentTok to address */
90     andi    x3, 0xf             ;[32]
91     breq    storeTokenAndReturn ;[33]
92     mov     token, x3           ;[34] indicate that this is endpoint x OUT
93 #endif
94 storeTokenAndReturn:
95     sts     usbCurrentTok, token;[35]
96 doReturn:
97     POP_STANDARD                ;[37] 12...16 cycles
98     USB_LOAD_PENDING(YL)        ;[49]
99     sbrc    YL, USB_INTR_PENDING_BIT;[50] check whether data is already arriving
100     rjmp    waitForJ            ;[51] save the pops and pushes -- a new interrupt is already pending
101 sofError:
102     POP_RETI                    ;macro call
103     reti
104
105 handleData:
106     lds     shift, usbCurrentTok;[18]
107     tst     shift               ;[20]
108     breq    doReturn            ;[21]
109     lds     x2, usbRxLen        ;[22]
110     tst     x2                  ;[24]
111     brne    sendNakAndReti      ;[25]
112 ; 2006-03-11: The following two lines fix a problem where the device was not
113 ; recognized if usbPoll() was called less frequently than once every 4 ms.
114     cpi     cnt, 4              ;[26] zero sized data packets are status phase only -- ignore and ack
115     brmi    sendAckAndReti      ;[27] keep rx buffer clean -- we must not NAK next SETUP
116 #if USB_CFG_CHECK_DATA_TOGGLING
117     sts     usbCurrentDataToken, token  ; store for checking by C code
118 #endif
119     sts     usbRxLen, cnt       ;[28] store received data, swap buffers
120     sts     usbRxToken, shift   ;[30]
121     lds     x2, usbInputBufOffset;[32] swap buffers
122     ldi     cnt, USB_BUFSIZE    ;[34]
123     sub     cnt, x2             ;[35]
124     sts     usbInputBufOffset, cnt;[36] buffers now swapped
125     rjmp    sendAckAndReti      ;[38] 40 + 17 = 57 until SOP
126
127 handleIn:
128 ;We don't send any data as long as the C code has not processed the current
129 ;input data and potentially updated the output data. That's more efficient
130 ;in terms of code size than clearing the tx buffers when a packet is received.
131     lds     x1, usbRxLen        ;[30]
132     cpi     x1, 1               ;[32] negative values are flow control, 0 means "buffer free"
133     brge    sendNakAndReti      ;[33] unprocessed input packet?
134     ldi     x1, USBPID_NAK      ;[34] prepare value for usbTxLen
135 #if USB_CFG_HAVE_INTRIN_ENDPOINT
136     andi    x3, 0xf             ;[35] x3 contains endpoint
137 #if USB_CFG_SUPPRESS_INTR_CODE
138     brne    sendNakAndReti      ;[36]
139 #else
140     brne    handleIn1           ;[36]
141 #endif
142 #endif
143     lds     cnt, usbTxLen       ;[37]
144     sbrc    cnt, 4              ;[39] all handshake tokens have bit 4 set
145     rjmp    sendCntAndReti      ;[40] 42 + 16 = 58 until SOP
146     sts     usbTxLen, x1        ;[41] x1 == USBPID_NAK from above
147     ldi     YL, lo8(usbTxBuf)   ;[43]
148     ldi     YH, hi8(usbTxBuf)   ;[44]
149     rjmp    usbSendAndReti      ;[45] 57 + 12 = 59 until SOP
150
151 ; Comment about when to set usbTxLen to USBPID_NAK:
152 ; We should set it back when we receive the ACK from the host. This would
153 ; be simple to implement: One static variable which stores whether the last
154 ; tx was for endpoint 0 or 1 and a compare in the receiver to distinguish the
155 ; ACK. However, we set it back immediately when we send the package,
156 ; assuming that no error occurs and the host sends an ACK. We save one byte
157 ; RAM this way and avoid potential problems with endless retries. The rest of
158 ; the driver assumes error-free transfers anyway.
159
160 #if !USB_CFG_SUPPRESS_INTR_CODE && USB_CFG_HAVE_INTRIN_ENDPOINT /* placed here due to relative jump range */
161 handleIn1:                      ;[38]
162 #if USB_CFG_HAVE_INTRIN_ENDPOINT3
163 ; 2006-06-10 as suggested by O.Tamura: support second INTR IN / BULK IN endpoint
164     cpi     x3, USB_CFG_EP3_NUMBER;[38]
165     breq    handleIn3           ;[39]
166 #endif
167     lds     cnt, usbTxLen1      ;[40]
168     sbrc    cnt, 4              ;[42] all handshake tokens have bit 4 set
169     rjmp    sendCntAndReti      ;[43] 47 + 16 = 63 until SOP
170     sts     usbTxLen1, x1       ;[44] x1 == USBPID_NAK from above
171     ldi     YL, lo8(usbTxBuf1)  ;[46]
172     ldi     YH, hi8(usbTxBuf1)  ;[47]
173     rjmp    usbSendAndReti      ;[48] 50 + 12 = 62 until SOP
174
175 #if USB_CFG_HAVE_INTRIN_ENDPOINT3
176 handleIn3:
177     lds     cnt, usbTxLen3      ;[41]
178     sbrc    cnt, 4              ;[43]
179     rjmp    sendCntAndReti      ;[44] 49 + 16 = 65 until SOP
180     sts     usbTxLen3, x1       ;[45] x1 == USBPID_NAK from above
181     ldi     YL, lo8(usbTxBuf3)  ;[47]
182     ldi     YH, hi8(usbTxBuf3)  ;[48]
183     rjmp    usbSendAndReti      ;[49] 51 + 12 = 63 until SOP
184 #endif
185 #endif
This page took 0.081074 seconds and 3 git commands to generate.