;
;    Mecrimus - A firmware-only USB implementation for MSP430 microcontrollers
;    Copyright (C) 2012  Matthias Koch
;
;    This program is free software: you can redistribute it and/or modify
;    it under the terms of the GNU General Public License as published by
;    the Free Software Foundation, either version 3 of the License, or
;    (at your option) any later version.
;
;    This program is distributed in the hope that it will be useful,
;    but WITHOUT ANY WARRANTY; without even the implied warranty of
;    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;    GNU General Public License for more details.
;
;    You should have received a copy of the GNU General Public License
;    along with this program.  If not, see <http://www.gnu.org/licenses/>.
;  


; Empfangsroutine für 15 MHz, 10 Takte/Bit 
; Receiver for 15 MHz, 10 cycles/bit

  ; ---------------------------------------------------------------------------
  ; Leitungen und Konstanten definieren
  ; Definitions of connections and constants
  ; ---------------------------------------------------------------------------


; USB PID values
USB_PID_SETUP   equ 02dh
USB_PID_OUT     equ 0e1h
USB_PID_IN      equ 069h
USB_PID_DATA0   equ 0c3h
USB_PID_DATA1   equ 04bh
USB_PID_ACK     equ 0d2h
USB_PID_NAK     equ 05ah
USB_PID_STALL   equ 01eh


usb_paket_ack:
  .byte 1, usb_pid_ack

usb_paket_nak:
  .byte 1, usb_pid_nak


  ; Signal for Sync pattern

  ; Signal: 
  ; D-:   normally high, Sync: 01 01 01 00 
  ; D+:            low         10 10 10 11
  ; Idea: Search 1-->0 transtition, sample it precisely and look if double zero follows, else repeat.
  ; As initialisation after IRQ (after bit.b for zero) needs some time, we will normally not see the first zero here.


  ; New Sync, with timeouts.
  
usb_sync_error:  ; Error happened
  pop r11
  pop r10
  pop r9

  clrc    ; Cleared Carry means: No packet catched.
  ret
    
  
  ; ---------------------------------------------------------------------------
USB_Sync: ; Einsprung direkt nach Interrupt.  ; Entry Point

  push r9  ; <3> Contains address of P2IN  Enthält die ganze Zeit die Adresse von P2IN
  push r10 ; <3> For sampling the transtition 
  push r11 ; <3> like r11... Because of the duration of this prepatarions we will not run into first Zero of syncpattern in D-

usb_resync: ; Jump in again here for fast catching of following second packets.
  ; ----------------------------------------------- Sync !      
  bit.b #usbminus, &P2IN    ; Wait for Zero
  ;
  ; <-- Sampling
  jnc +
  ;
  bit.b #usbminus, &P2IN    ; Wait for Zero
  ;
  ; <-- Sampling
  jnc +
  ;
  bit.b #usbminus, &P2IN    ; Wait for Zero
  ;
  ; <-- Sampling
  jnc +
  ;
  jmp usb_sync_error
  ;
  ; ----------------------- ;    
+ bit.b #usbminus, &P2IN    ; Wait for One
  ;
  ; <-- Sampling
  jc +
  ;
  bit.b #usbminus, &P2IN    ; Wait for One
  ;
  ; <-- Sampling
  jc +
  ;
  bit.b #usbminus, &P2IN    ; Wait for One
  ;
  ; <-- Sampling
  jc +
  ;
  jmp usb_sync_error
  ;
  ; ----------------------- ; Found transtition, synced within 5 cycles. First try to sync precisely
+ mov #P2IN, r9             ; (               4H 5H 6H 7H 8H)
  ;                         ; (               5H 6H 7H 8H 9H)
  mov.b @r9, r10            ; (               6H 7H 8H 9H 0H)       Sample 1-->0 transtition two times as fast as possible
  ; <-- Sampling            ; (               7H 8H 9H 0H 1L) <--  
  mov.b @r9, r11            ; (               8H 9H 0H 1L 2L)       Could use mov.b @r9, r9 instead and push r11 later,
  ; <-- Sampling            ; (               9H 0H 1L 2L 3L) <--   but the cycles for that are taken by xor syncled.
  ; ----------------------- ;                  |  |  |  |  | 
  bit #usbminus, r10        ; (               0H 1L 2L 3L 4L)       Depending on phase towards host clock,
  jnc +                     ; (               1L 2L 3L 4L 5L)       wait a fitting amount of cycles to get in sync.
  ;                         ; (               2L 3L 4L 5L 6L)
  bit #usbminus, r11        ; (               3L 4L 5L 6L  |)    
  jnc ++                    ; (               4L 5L 6L 7L  |)    
  ;                         ; (               5L 6L 7L 8L  |)
+ nop2                      ; (               6L 7L  |  | 7L)  
  ;nop                      ; (               7L 8L  |  | 8L)
+ nop2                      ; (               8L 9L 8L 9L 9L)  Arrived. Sync within within two clocks.
  ;nop                      ; (               9L 0L         )
  nop                       ; (               0L 1D         )  D may be the second of the double zero OR a one, D kann Doppelnull, zweite Null ODER Eins sein, falls Einlauf zu früh.  
  bit.b #usbminus, &P2IN    ; (               1D 2D         )  if we catched one transtition too early.
  ;                         ; (               2D 3D         )  
  ; <-- Sampling            ; (               3D 4D         )  If here is the one, I just detected a 0->1 transtition
  jnc usb_sync_done         ; (               4D 5D         )  try a second sync on the following 1->0.
  ;                         ; (               5D 6D         )  Else sync is done. Start !
  ; ----------------------- ;                  |  |            
                            ;                  v  v
    
  ; ----------------------- ; Second try to sync, if first attemp did not end on Double-Zero.
  mov #P2IN, r9             ; (               4H 5H 6H 7H 8H)  Kantensampling für höhere Genauigkeit
  ;                         ; (               5H 6H 7H 8H 9H)
  mov.b @r9, r10            ; (               6H 7H 8H 9H 0H)
  ; <-- Sampling            ; (               7H 8H 9H 0H 1L) <--
  mov.b @r9, r11            ; (               8H 9H 0H 1L 2L)       Könnte hier auch mov.b @r9, r9 verwenden und r11 später sichern. 
  ; <-- Sampling            ; (               9H 0H 1L 2L 3L) <--   Brauche den Platz aber momentan für "xor syncled".
  ; ----------------------- ;                  |  |  |  |  | 
  bit #usbminus, r10        ; (               0H 1L 2L 3L 4L)
  jnc +                     ; (               1L 2L 3L 4L 5L)
  ;                         ; (               2L 3L 4L 5L 6L)
  bit #usbminus, r11        ; (               3L 4L 5L 6L  |)
  jnc ++                    ; (               4L 5L 6L 7L  |)
  ;                         ; (               5L 6L 7L 8L  |)
+ nop2                      ; (               6L 7L  |  | 7L)  
  ;nop                      ; (               7L 8L  |  | 8L)
+ nop2                      ; (               8L 9L 8L 9L 9L)  Angekommen. Auf zwei Takte synchronisiert.
  ;nop                      ; (               9L 0L         )
  nop                       ; (               0L 1D         )  D kann Doppelnull, zweite Null ODER Eins sein, falls Einlauf zu früh.  
  bit.b #usbminus, &P2IN    ; (               1D 2D         )  Normaler Durchlauf in der Doppelnull.
  ;                         ; (               2D 3D         )  Falls hier Eins auftaucht, bin ich zu früh im Sync-Byte; 
  ; <-- Sampling            ; (               3D 4D         )    habe gerade 0->1 Flanke detektiert.
  jnc usb_sync_done         ; (               4D 5D         )  Nochmal Eins an dieser Stelle ? Synchronisation ungültig.
  ;                         ; (               5D 6D         )  3, 4, 5, 6, 7 sind gültige Einsprungtakte. 6/7 ist ein guter Rücksprung, 
  ; ----------------------- ;                  |  |            weil dann alle auf 9 synchronisiert werden.  Einlauf !
    
    
  ; ----------------------- ; Third try to sync, if resyncing really let us catch the first 0 of sync pattern.    
  mov #P2IN, r9             ; (               4H 5H 6H 7H 8H)  Kantensampling für höhere Genauigkeit
  ;                         ; (               5H 6H 7H 8H 9H)
  mov.b @r9, r10            ; (               6H 7H 8H 9H 0H)
  ; <-- Sampling            ; (               7H 8H 9H 0H 1L) <--
  mov.b @r9, r11            ; (               8H 9H 0H 1L 2L)       Könnte hier auch mov.b @r9, r9 verwenden und r11 später sichern. 
  ; <-- Sampling            ; (               9H 0H 1L 2L 3L) <--   Brauche den Platz aber momentan für "xor syncled".
  ; ----------------------- ;                  |  |  |  |  | 
  bit #usbminus, r10        ; (               0H 1L 2L 3L 4L)
  jnc +                     ; (               1L 2L 3L 4L 5L)
  ;                         ; (               2L 3L 4L 5L 6L)
  bit #usbminus, r11        ; (               3L 4L 5L 6L  |)
  jnc ++                    ; (               4L 5L 6L 7L  |)
  ;                         ; (               5L 6L 7L 8L  |)
+ nop2                      ; (               6L 7L  |  | 7L)  
  ;nop                      ; (               7L 8L  |  | 8L)
+ nop2                      ; (               8L 9L 8L 9L 9L)  Angekommen. Auf zwei Takte synchronisiert.
  ;nop                      ; (               9L 0L         )
  nop                       ; (               0L 1D         )  D kann Doppelnull, zweite Null ODER Eins sein, falls Einlauf zu früh.  
  bit.b #usbminus, &P2IN    ; (               1D 2D         )  Normaler Durchlauf in der Doppelnull.
  ;                         ; (               2D 3D         )  Falls hier Eins auftaucht, bin ich zu früh im Sync-Byte; 
  ; <-- Sampling            ; (               3D 4D         )    habe gerade 0->1 Flanke detektiert.
  jc usb_sync_error         ; (               4D 5D         )  Nochmal Eins an dieser Stelle ? Synchronisation ungültig.
  ;                         ; (               5D 6D         )  3, 4, 5, 6, 7 sind gültige Einsprungtakte. 6/7 ist ein guter Rücksprung, 
  ; ----------------------- ;                  |  |            weil dann alle auf 9 synchronisiert werden.  Einlauf !
    
    
    
usb_sync_done:              ;                  v  v            Arrived in Sync !
  ; ----------------------- ;                  |  |
  xor.b #syncled, &P2OUT    ; (               6D 7D         )  xor mit Konstantengenerator zu Port braucht 4 Takte.
  ;                         ; (               7D 8D         )   Habe mit Oszilloskop geprüft: Die Xor-Flanke liegt genau auf             
  ;                         ; (               8D 9D         )  oder ganz kurz NACH Beginn des ersten Datenbits !
  ; <-- Wechsel             ; (               9D 0B         )  1. Datenbit beginnt hier (wahrscheinlicher)  Start of first bit here
  push r12                  ; (               0B 1B         )                         (unwahrscheinlicher)  or here
  ;                         ; (               1B 2B         )
  ;                         ; (               2B 3B         )  xor transtition on syncled seems on oscilloscope exactly on or 
  ; ---------------------------------------------------------  slightly later than start of first databit

  
 
  
  
  
  ; ---------------------------------------------------------------------------
  ; Fertig synchronisiert, lege los ! Sync is ok, lets start !
  ; ---------------------------------------------------------------------------
  
  ; r12 muss für die Stopferkennung passend initialisiert werden !
  ; r13 = Stopfmaske wird ausgenullt
  ; r15 = Pufferzeiger setzen

  ; Habe beim ersten Einlauf Zeit, da ganz am Anfang kein Stopfen möglich ist.


  ; Register usage:
  ;push r8   ; Vergleichs-Stopfmaskenmuster #11111100b    Mask for detect stuffing
  ;push r9   ; P2IN-Adresse                               Address of P2IN

  ;push r10  ; NRZI-Pinzustand                            Buffer for NRZI pin state
  ;push r11  ; NRZI-Pinzustand                            --

  ;push r12  ; Datenempfangsregister                      Data input shift register, has to be initialized to sync-pattern not($80)
  ;push r13  ; Stopfmaske                                 Stuffing mask, has to be cleared

  ;push r14  ; Datensicherung                             Data backup register
  ;push r15  ; Pointer                                    Pointer to write into receive buffer
  
  ; Note: Data is inverted because of clever use of flags and side-effects to save cycles
  ;       Stuffing mask holds those bits that have been inverted, so that stuffing detection 
  ;       will not detect stuffing on the same bits more than one time.

  ; We have some time in the first byte of data, as stuffing cannot occour the first 5 bits.
  ; D- is used for sync and input, D+ is only used to detect packet end SE0.

  ; ---------------------------------------------------------------------------
  ; Einlauf, Erstes Bit: (0)
  ; ---------------------------------------------------------------------------

  mov.b @r9, r10     ; [1]  NRZI             ( 3  4)  Chance counting here so that mov.b @r9 always counts on one.
  ;                  ; [2]  <--- Sampling    ( 4  5)  Center-Sampling on 5 or 6 !
  mov #7Fh, r12      ; [3]  not($80)         ( 5  6)  Initialize data, as last bit of Syncpattern may take part in stuffing.
  ;                  ; [4]                            Syncbyte spielt beim Stopfen mit !Präparation des Datenregisters für Stopferkennung.
  and #usbminus, r10 ; [5] statt bit einleiten        Wechsele hier die Zählweise !              Eine davon müsste direkt den Wert des ersten Bits liefern. Hängt vom Sync-Byte-Endzustand ab. Dort ist D- low. Wechsel --> Carry gesetzt. Kommt hin :-)
  rrc.b r12          ; [6]  und rotieren              Der Mov-Befehl kommt so immer auf [1] :-)  Erstes Datenbit aufnehmen ! Usbminus enthält das erste Datenbit invertiert. Passt :-)
                     ;      Catch first data bit, use only AND here, as last state out of sync pattern is always the same.
  push r13           ; [7]  Weitere Register sichern  Save more registers
  ;                  ; [8] 
  ;                  ; [9] 
  clr r13            ; [10]  Stopfmaske löschen   Clear stuffing mask

  ; ---------------------------------------------------------------------------
  ; Einlauf, Zweites Bit: (1)  Dies Bit ist immer Null. Warum ? Aah ! Habe keine Maske auf r10 angewendet. muss noch ein and #usbminus, r10 unterbringen.
  ; ---------------------------------------------------------------------------

  mov.b @r9, r11     ; [1]  NRZI einleiten mit Sampling
  ;                  ; [2]  <--- Sampling

  and #usbminus, r11 ; [3]  NRZI ab jetzt normal durchführen  
  xor r11, r10       ; [4]  From now on, do NRZI decoding as usual with XORing the last two samplings of D-
  rrc.b r12          ; [5]

  push r15           ; [6]  Der Pointer für Empfangenes.
  ;                  ; [7]  Pointer to write reveived data, has to be initialized.
  ;                  ; [8]  
  mov #Receivebufferpointer, r15 ; [9]  Fetch the Pointer in two steps, could be in one step @ 18 MHz/12 cycles.
                     ; [10]

  ; ---------------------------------------------------------------------------
  ; Einlauf, Drittes Bit: (2)  
  ; ---------------------------------------------------------------------------

  mov.b @r9, r10     ; [1]  NRZI einleiten mit Sampling
                     ; [2]  <--- Sampling Flags bleiben dabei erhalten !

  and #usbminus, r10 ; [3]  NRZI durchführen
  xor r10, r11       ; [4]
  rrc.b r12          ; [5]

  push r14           ; [6]  "Datensicherung" braucht keine Initialisierung.
                     ; [7]  The data backup register doesn't need initialisation.
                     ; [8]
  mov @r15, r15      ; [9]  Pufferadresse in Pointer laden
                     ; [10]  Second step of fetching buffer pointer

  ; ---------------------------------------------------------------------------
  ; Einlauf, Viertes Bit: (3)
  ; ---------------------------------------------------------------------------

  mov.b @r9, r11     ; [1]  NRZI einleiten mit Sampling
                     ; [2]  <--- Sampling
 
  and #usbminus, r11 ; [3]  NRZI durchführen
  xor r11, r10       ; [4]
  rrc.b r12          ; [5]

  push r8            ; [6]  Stopfmaskenregister sichern
                     ; [7]
                     ; [8]
  mov #11111100b, r8 ; [9]  und Stopfmaske bereitlegen.    Prepare mask to quickly detect last 6 bits for stuffing
                     ; [10]

  ; ---------------------------------------------------------------------------
  ; Einlauf, Fünftes Bit: (4)  Hier kann bereits die erste Stopfung auftreten !  
  ;                            First stuffing may happen here... 
  ;                            OK, valid PID values shouldn't let this happen, but just in case...
  ; ---------------------------------------------------------------------------

  mov.b @r9, r10     ; [1]  NRZI einleiten mit Sampling
                     ; [2]  <--- Sampling                    

  and #usbminus, r10 ; [3]  NRZI durchführen
  xor r10, r11       ; [4]
  rrc.b r12          ; [5]




  bit r8, r12             ; [6]  Stopferkennung, 6 Bits nacheinander kein Wechsel !   
  jnz +                   ; [7]  Check for stuffing: 6 following bits no change in line. Remember: Data bits are inverted in r12 !
  ;                       ; [8]

        nop2                          ; [e 9]
        ;nop                          ; [e 10]
        mov.b @r9, r10                ; [e 1]  Für die NRZI-Dekodierung Zustand wechseln.    Resample...
                                      ; [e 2]  <--- Sampling Zustand einfach nochmal lesen
        and #usbminus, r10            ; [e 3]
        bis #80h, r12                 ; [e 4]  Oberstes Bit in Daten setzen  Set top Bit in Data register, will be shifted further
                                      ; [e 5]
        bis #00010000b, r13           ; [e 6] Entsprechende Stelle           Note the occurence of stuffing in that bit
        ; (nop) je nach Bitstelle     ; [e 7]   in Stopfmaske merken           so that it can be undone later. Mask will not be shifted.
        nop                           ; [e 8]

 
+ jmp Sechstes_Bit   ; [9]  Einsprung ins reguläre Schema  Jump into regular cycle
                     ; [10]




USB_ReceiverLoop:  
  ; ---------------------------------------------------------------------------
  ; Erstes Bit: (0)  Sonderaufgabe: Stopfmaske leeren, Daten invertieren  Special task: Clear stuffmask, invert data
  ; ---------------------------------------------------------------------------

  mov.b @r9, r10          ; [1]  NRZI
                          ; [2]  <--- Sampling

  and #usbminus, r10      ; [3]
  xor r10, r11            ; [4]
  rrc.b r12               ; [5]

  clr r13                 ; [6] Sonderaufgabe: Stopfmaske leeren !  Clear stuffing mask. Relevant information is still in r12 and gets shifted out by the way.
  inv r14                 ; [7] Gesichertes Datenbyte invertieren.  Invert saved data byte.

  bit r8, r12             ; [8]   Stopferkennung, 6 Bits nacheinander kein Wechsel !  Detect stuffing...
  jnz +                   ; [9]   Datenbits hier invertiert !
                          ; [10]


        mov.b @r9, r10                ; [e 1]  Für die NRZI-Dekodierung Zustand wechseln.
                                      ; [e 2]  <--- Sampling Zustand einfach nochmal lesen
        and #usbminus, r10            ; [e 3]
        bis #80h, r12                 ; [e 4]  Oberstes Bit in Daten setzen   Set top Bit in Data register, will be shifted further
                                      ; [e 5]
        bis #00000001b, r13           ; [e 6] Entsprechende Stelle      Note the occurence of stuffing in that bit
        nop2 ;(nop) je nach Bitstelle ; [e 7]   in Stopfmaske merken      so that it can be undone later. Mask will not be shifted.
        ;nop                          ; [e 8]  Note: We are using constant generator here, this results in one more nop depending on value !
        nop2                          ; [e 9]
        ;nop                          ; [e 10]

  ; ---------------------------------------------------------------------------
  ; Zweites Bit: (1)  Sonderaufgabe: SE0-Check  Special task: Detect SE0
  ; ---------------------------------------------------------------------------

+ mov.b @r9, r11             ; [1]  NRZI einleiten mit Sampling
                             ; [2]   <--- Sampling

  and #usbplus+usbminus, r11 ; [s3] ; SE0-Check im zweiten Bit !  Check for SE0 
                             ; [s4]
  jz usb_se0                 ; [s5]                               which occours as low low in both USB lines
                             ; [s6]                               Unfortunately this takes whole 4 cycles...

  and #usbminus, r11         ; [7]  NRZI durchführen
  xor r11, r10               ; [8]
  rrc.b r12                  ; [9]

  bit r8, r12                ; [10]  Stopferkennung, 6 Bits nacheinander kein Wechsel !

  ; ---------------------------------------------------------------------------
  ; Drittes Bit: (2)  Sonderaufgabe: Aufholen !  Special task: Hurry up !
  ; ---------------------------------------------------------------------------

  mov.b @r9, r10          ; [1]  NRZI einleiten mit Sampling
                          ; [2]  <--- Sampling Flags bleiben dabei erhalten !

  jnz +                   ; [3 noch vorheriges Bit]  ; Bezieht sich auf die Entstopfung im letzten Bit !
                          ; [4 noch vorheriges Bit]


        mov r10, r11                  ; [es 5]  In r10 ist der Entstopf-Bit-Pinzustand. Lege ihn als Basis für die letzte Messung bereit.
        and #usbminus, r11            ; [es 6]
        bis #80h, r12                 ; [es 7]  Oberstes Bit in Daten setzen
                                      ; [es 8]
        bis #00000010b, r13           ; [es 9] Entsprechende Stelle für das vorhergehende Bit 
        nop ; (nop) je nach Bitstelle ; [es 10]   in Stopfmaske merken
        mov.b @r9, r10                ; [es 1]  Hatte in r10 das Entstopf-Bit einkassiert. Muss es ersetzen.
                                      ; [es 2] <--- Sampling !
        nop2                          ; [es 3]
        ;nop                          ; [es 4]  Because of this detects for unstuffing in the LAST bit, we have to juggle around registers here.


+ and #usbminus, r10      ; [5]  NRZI 2 Takte später durchführen. Neues Sampling in Entstopfung !
  xor r10, r11            ; [6]
  rrc.b r12               ; [7]

  bit r8, r12             ; [8]   Stopferkennung, 6 Bits nacheinander kein Wechsel !                        
  jnz +                   ; [9]
                          ; [10]


        mov.b @r9, r10                ; [e 1]  Für die NRZI-Dekodierung Zustand wechseln.
                                      ; [e 2]  <--- Sampling Zustand einfach nochmal lesen
        and #usbminus, r10            ; [e 3]      
        bis #80h, r12                 ; [e 4]  Oberstes Bit in Daten setzen
                                      ; [e 5]
        bis #00000100b, r13           ; [e 6] Entsprechende Stelle 
        nop2 ;(nop) je nach Bitstelle ; [e 7]   in Stopfmaske merken
        ;nop                          ; [e 8]
        nop2                          ; [e 9]
        ;nop                          ; [e 10]  Unstuff-Detection for the current bit.

  ; ---------------------------------------------------------------------------
  ; Viertes Bit: (3)  Sonderaufgabe: Daten in Puffer schreiben  Special task: Write data into buffer
  ; ---------------------------------------------------------------------------

+ mov.b @r9, r11          ; [1]  NRZI einleiten mit Sampling
                          ; [2]  <--- Sampling

  inc r15                 ; [p3]  Zeiger erhöhen                Increase Pointer
  mov.b r14, @r15         ; [p4]  Daten in den Puffer legen !     and put freshly prepared data into.
                          ; [p5]
                          ; [p6]  

  and #usbminus, r11      ; [7]  NRZI durchführen
  xor r11, r10            ; [8]
  rrc.b r12               ; [9]

  bit r8, r12             ; [10]  Stopferkennung, 6 Bits nacheinander kein Wechsel ! Detection in next bit, sampling witg mov preserves flags.

  ; ---------------------------------------------------------------------------
  ; Fünftes Bit: (4)  Sonderaufgabe: Aufholen !   Special task: Hurry up !
  ; ---------------------------------------------------------------------------

  mov.b @r9, r10          ; [1]  NRZI einleiten mit Sampling
                          ; [2]  <--- Sampling Flags bleiben dabei erhalten !

  jnz +                   ; [3 noch vorheriges Bit]  ; Bezieht sich auf die Entstopfung im letzten Bit !
                          ; [4 noch vorheriges Bit]

        mov r10, r11                  ; [es 5]  In r10 ist der Entstopf-Bit-Pinzustand. Lege ihn als Basis für die letzte Messung bereit.
        and #usbminus, r11            ; [es 6]
        bis #80h, r12                 ; [es 7]  Oberstes Bit in Daten setzen
                                      ; [es 8]
        bis #00001000b, r13           ; [es 9] Entsprechende Stelle für das vorhergehende Bit 
        nop ; (nop) je nach Bitstelle ; [es 10]   in Stopfmaske merken                                        Last use for constant generator
        mov.b @r9, r10                ; [es 1] Hatte in r10 das Entstopf-Bit einkassiert. Muss es ersetzen.                            
                                      ; [es 2] <--- Sampling !
        nop2                          ; [es 3]
        ;nop                          ; [es 4]  Unstuffing for the LAST bit

+ and #usbminus, r10      ; [5]  NRZI 2 Takte später durchführen. Neues Sampling in Entstopfung !
  xor r10, r11            ; [6]
  rrc.b r12               ; [7]

  bit r8, r12             ; [8]  Stopferkennung, 6 Bits nacheinander kein Wechsel !
  jnz +                   ; [9]
                          ; [10]


        mov.b @r9, r10                ; [e 1]  Für die NRZI-Dekodierung Zustand wechseln.
                                      ; [e 2]  <--- Sampling Zustand einfach nochmal lesen
        and #usbminus, r10            ; [e 3]
        bis #80h, r12                 ; [e 4]  Oberstes Bit in Daten setzen
                                      ; [e 5]
        bis #00010000b, r13           ; [e 6] Entsprechende Stelle 
        ; (nop) je nach Bitstelle     ; [e 7]   in Stopfmaske merken              Outside of constant generator, no extra nop anymore
        nop                           ; [e 8]
        nop2                          ; [e 9]
        ;nop                          ; [e 10]  Unstuffing for current bit

  ; ---------------------------------------------------------------------------
  ; Sechstes Bit: (5)  Frei  Free of special tasks
Sechstes_Bit:
  ; ---------------------------------------------------------------------------

+ mov.b @r9, r11          ; [1]  NRZI                         
                          ; [2]  <--- Sampling

  and #usbminus, r11      ; [3]
  xor r11, r10            ; [4]
  rrc.b r12               ; [5]

  nop2                    ; [6] Platz für Sonderfunktionen  Holidays :-)
  ;nop                    ; [7]

  bit r8, r12             ; [8]   Stopferkennung, 6 Bits nacheinander kein Wechsel !
  jnz +                   ; [9]
                          ; [10]

        mov.b @r9, r11                ; [e 1]  Für die NRZI-Dekodierung Zustand wechseln.
                                      ; [e 2]  <--- Sampling  Zustand einfach nochmal lesen
        and #usbminus, r11            ; [e 3]      
        bis #80h, r12                 ; [e 4]  Oberstes Bit in Daten setzen
                                      ; [e 5]
        bis #00100000b, r13           ; [e 6] Entsprechende Stelle 
        ; (nop) je nach Bitstelle     ; [e 7]   in Stopfmaske merken
        nop                           ; [e 8]
        nop2                          ; [e 9]
        ;nop                          ; [e 10]

  ; ---------------------------------------------------------------------------
  ; Siebtes Bit: (6)  Frei
  ; ---------------------------------------------------------------------------

+ mov.b @r9, r10          ; [1]  NRZI
                          ; [2]  <--- Sampling

  and #usbminus, r10      ; [3]
  xor r10, r11            ; [4]
  rrc.b r12               ; [5]

  nop2                    ; [6] Platz für Sonderfunktionen  Holidays :-)
  ;nop                    ; [7]

  bit r8, r12             ; [8]   Stopferkennung, 6 Bits nacheinander kein Wechsel !
  jnz +                   ; [9]
                          ; [10]

        mov.b @r9, r10                ; [e 1]  Für die NRZI-Dekodierung Zustand wechseln.
                                      ; [e 2]  <--- Sampling Zustand einfach nochmal lesen
        and #usbminus, r10            ; [e 3]      
        bis #80h, r12                 ; [e 4]  Oberstes Bit in Daten setzen
                                      ; [e 5]
        bis #01000000b, r13           ; [e 6] Entsprechende Stelle 
        ; (nop) je nach Bitstelle     ; [e 7]   in Stopfmaske merken
        nop                           ; [e 8]
        nop2                          ; [e 9]
        ;nop                          ; [e 10]

  ; ---------------------------------------------------------------------------
  ; Achtes Bit: (7)  Sonderaufgabe: Daten sichern und Stopfmaske anwenden !  
  ;                  Rücksprung via Stopfsprung.   Special task: Save data for later preparation and apply stuffmask.
  ; ---------------------------------------------------------------------------

+ mov.b @r9, r11          ; [1]  NRZI
                          ; [2]  <--- Sampling

  and #usbminus, r11      ; [3]
  xor r11, r10            ; [4]
  rrc.b r12               ; [5]

  mov r12, r14            ; [6] Datenbyte ist fertig ! Hole es ab.     Backup of Data
  bic r13, r14            ; [7] Stopfmaske darauf anwenden.            Apply stuffmask

  bit r8, r12             ; [8]  Stopferkennung, 6 Bits nacheinander kein Wechsel !                         
  jnz USB_ReceiverLoop    ; [9]  Return with stuff-detect-jump
                          ; [10]


        ; Noch experimentell ! Enstopfung für letztes Bit.
        mov.b @r9, r11                ; [e 1]  Für die NRZI-Dekodierung Zustand wechseln.
                                      ; [e 2]  <--- Sampling  Zustand einfach nochmal lesen
        and #usbminus, r11            ; [e 3]
        bis #80h, r12                 ; [e 4]  Oberstes Bit in Daten setzen, Datenregister ist 16 Bits breit und läuft durch !
                                      ; [e 5]    
        nop                           ; [e 6]    Nicht in Stopfmaske vermerken,
        nop2                          ; [e 7]    da dieses Bit komplett herausgeschoben wird
        ;nop                          ; [e 8]    und die Stopfmaske sowieso gelöscht wird.
        jmp USB_ReceiverLoop          ; [e 9]
                                      ; [e 10]  In the last bit there is no need to update stuffmask, as data byte is already saved,
                                      ;         but it is necessary to set the bit in data register, as stuffing continues over byte boundaries.
                                      ;         It will be shifted out later anyway... 

  ; ---------------------------------------------------------------------------
  ; Paketende SE0:  End of packet detected.
  ; ---------------------------------------------------------------------------
usb_se0:  ; Komme mit [7] hier an !

  inc r15           ; [7] Damit die Zählung stimmt !                 Store last Databyte
  mov.b r14, 0(r15) ; [8] :-)  Das letzte Datenbyte vermerken !!     in Buffer
                    ; [9]
                    ;[10]

  mov &Receivebufferpointer, r14            ;  [1]    Fetch bufferpointer
  ;                                         ;  [2]
  ;                                         ;  [3]
  sub r14, r15  ; Paketlänge bestimmen      ;  [4]    Calculate length of received packet
  mov.b r15, @r14                           ;  [5]    Store length like in a counted string
  ;                                         ;  [6]
  ;                                         ;  [7]
  
  xor.b #syncled, &P2OUT ; Finished. Toggle syncled again, to see on oscilloscope if SE0 detection missed its job due to wrong sync.
  mov.b 1(r14), r10  ; PID holen    Fetch PID of packet for further investigation.
 
          ; Cycle numbers may be shifted further...
  
  pop r8  ; [8]  We have to get back those registers BEFORE we Resync, because their pushes cannot be bypssed.
          ; [9]

  pop r14 ;[10]    Vertauscht   r14 and r15 interchanged due to tight timing in initialisation.
          ; [1]                 Should change r14 and r15, but to historic reasons I don't want to confuse myself ;-)
  pop r15 ; [2]
          ; [3]
  pop r13 ; [4]
          ; [5]
  pop r12 ; [6]
          ; [7]
          
          ; Rücksprung in die Synchronisation ! Das neue Paket beginnt ziemlich bald.
          ; Mindestwartezeit: 2 Bitzeiten = 20 Takte. Weiterhin kann ich die ersten Bits des Syncs überspringen...
          ; Muss hier noch Proben einfügen, ob gleich ein nächstes Paket kommt, was bei Setup und Out der Fall ist.
          ; Bei IN habe ich 6.5 oder 7.5 Bitzeiten Ruhe, und somit noch ein bisschen Luft.

          ; Next paket may follow in 2 bittimes = 20 cycles.
          ; If I have to reply, I have 6.5 to 7.5 bittimes maximum until I have to transmit my answer.
          ; So I should check first if I have to receive some more...
          ; Note that we can take up some time of the sync pattern, as we need only the second half "0100" of it...
          

   ; ifdef 0                                         ; Experimental: Catch next packet ?  Send replies ?
  mov #Buffer2, &Receivebufferpointer      
  ; Checke den PID-Wert;  
  
  cmp.b #usb_pid_setup, r10  ; If this was a SETUP or OUT packet, the next is coming soon...
  je +
  cmp.b #usb_pid_out, r10
  jne ++
  
  
/ bit.b #usbminus, &P2IN  ; Warte auf Null in der Leitung   Wait for Zero in D-
  jc -                    ; Did you mention the "+" and "-" labels everywhere :-) ? The "/" is a + and a - in one.
  jmp usb_resync          ; I really like this feature of Alfred Arnolds assembler a lot.
                   
+ mov #Buffer1, &Receivebufferpointer 
  

  cmp.b #usb_pid_data0, r10
  je +
              
  cmp.b #usb_pid_data1, r10
  jne ++
              
+ mov #usb_paket_ack, &Transmitbufferpointer                       ; Set Transmitbufferpointer to ACK-Packet
  call #USB_Transmit  ; Sendet ein Paket ab.
              
+

; 03 2D 00 10 FD FF FF FF FF FF FF FF FF FF FF FF  | DE C3 80 06 00 01 10 00 20 80 6E CA FD FF FF FF  | FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF  .
; 03 2D 00 10 FD FF FF FF FF FF FF FF FF FF FF FF  | 41 C3 80 06 00 11 00 00 20 80 6E CA FD FF FF FF  | FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF  .
; 03 2D 00 10 FD FF FF FF FF FF FF FF FF FF FF FF  | 99 C3 80 06 90 00 00 00 20 80 6E CA FD FF FF FF  | FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF  .
; 03 2D 00 10 FD FF FF FF FF FF FF FF FF FF FF FF  | 41 C3 00 85 19 00 00 00 00 00 77 C0 FD FF FF FF  | FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF  .
; 03 2D 00 10 FD FF FF FF FF FF FF FF FF FF FF FF  | 41 C3 00 05 14 00 00 00 00 00 77 C0 FD FF FF FF  | FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF  .
; 03 2D 00 10 FD FF FF FF FF FF FF FF FF FF FF FF  | 15 C3 00 05 35 00 10 00 00 80 F7 A8 FD FF FF FF  | FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF  .
; 03 2D 00 10 FD FF FF FF FF FF FF FF FF FF FF FF  | 41 C3 00 05 35 10 00 00 00 80 F7 A8 FD FF FF FF  | FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF  .

; If activated, you get something like this: 2D is Setup, C3 is DATA0, and last USB Adress reported by dmesg is 53=$35, ok.
; usb 1-1: new low speed USB device using uhci_hcd and address 50
; usb 1-1: device descriptor read/64, error -71
; usb 1-1: device descriptor read/64, error -71
; usb 1-1: new low speed USB device using uhci_hcd and address 51
; usb 1-1: device descriptor read/64, error -71
; usb 1-1: device descriptor read/64, error -71
; usb 1-1: new low speed USB device using uhci_hcd and address 52
; usb 1-1: device not accepting address 52, error -71
; usb 1-1: new low speed USB device using uhci_hcd and address 53
; usb 1-1: device not accepting address 53, error -71


   ; endif  End of experimental part.
                        
            
  pop r11 ; [8]  Those three registers can be bypassed for jump back to resync, so pop them back at lately.
          ; [9]
  pop r10 ;[10]
          ; [1]
  pop r9  ; [2]
          ; [3]
          
  setc    ; [4] Paket erfolgreich empfangen !  Successful return. Of course, this will be a reti later without signaling in Flags...
  ret



  
  
  
  
  
  
  
  
  
    ; Outtakes !
  
    ifdef 0 ; Old sync without timeout, fails often.
  


USB_Sync: ; Einsprung direkt nach Interrupt.
  
  ; ---------------------------------------------------------------------------  
  ;  Signal an D-: Ruheeins - 01 01 01 00
  ; ---------------------------------------------------------
  
  push r9  ; <3> Enthält die ganze Zeit die Adresse von P2IN
  push r10 ; <3>
  push r11 ; <3>
  ; ----------------------------------------------- Sync !
- bit.b #usbminus, &P2IN    ; Warte auf Null                        This 5-cycle-test can pin down usb clock within 5 cylces.
  ;                         ;                                       On this cycle counts here the new sync is based on,
  ; <-- Sampling            ; (1L 2L 3L 4L 5L 6L 7L 8L 9L 0L)       in which the loop is unrolled 3 times to get a timeout behaviour.
  jc -                      ; (2L 3L 4L 5L 6L 7L 8L 9L 0L 1H)       Strangely, there seems to be something like noise on USB lines that causes false syncs.
  ;                         ; (3L 4L 5L 6L 7L 8L 9L 0L 1H 2H)
- bit.b #usbminus, &P2IN    ; (4L 5L 6L 7L 8L 9L 0L 1H 2H 3H)  (9L 0L 1H 2H 3H) Warte auf Eins
  ;                         ; (5L 6L 7L 8L 9L 0L 1H 2H 3H 4H)  (0L 1H 2H 3H 4H)
  ; <-- Sampling            ; (6L 7L 8L 9L 0L 1H 2H 3H 4H 5H)  (1H 2H 3H 4H 5H)
  jnc -                     ; (7L 8L 9L 0L 1H 2H 3H 4H 5H 6H)  (2H 3H 4H 5H 6H)
  ;                         ; (8L 9L 0L 1H 2H 3H 4H 5H 6H 7H)  (3H 4H 5H 6H 7H)
  ; ----------------------- ;                  |  |  |  |  | 
- mov #P2IN, r9             ; (               4H 5H 6H 7H 8H)  Kantensampling für höhere Genauigkeit
  ;                         ; (               5H 6H 7H 8H 9H)
  mov.b @r9, r10            ; (               6H 7H 8H 9H 0H)
  ; <-- Sampling            ; (               7H 8H 9H 0H 1L) <--
  mov.b @r9, r11            ; (               8H 9H 0H 1L 2L)       Könnte hier auch mov.b @r9, r9 verwenden und r11 später sichern. 
  ; <-- Sampling            ; (               9H 0H 1L 2L 3L) <--   Brauche den Platz aber momentan für "xor syncled".
  ; ----------------------- ;                  |  |  |  |  | 
  bit #usbminus, r10        ; (               0H 1L 2L 3L 4L)
  jnc +                     ; (               1L 2L 3L 4L 5L)
  ;                         ; (               2L 3L 4L 5L 6L)
  bit #usbminus, r11        ; (               3L 4L 5L 6L  |)
  jnc ++                    ; (               4L 5L 6L 7L  |)
  ;                         ; (               5L 6L 7L 8L  |)
+ nop2                      ; (               6L 7L  |  | 7L)  
  ;nop                      ; (               7L 8L  |  | 8L)
+ nop2                      ; (               8L 9L 8L 9L 9L)  Angekommen. Auf zwei Takte synchronisiert.
  ;nop                      ; (               9L 0L         )
  nop                       ; (               0L 1D         )  D kann Doppelnull, zweite Null ODER Eins sein, falls Einlauf zu früh.  
  bit.b #usbminus, &P2IN    ; (               1D 2D         )  Normaler Durchlauf in der Doppelnull.
  ;                         ; (               2D 3D         )  Falls hier Eins auftaucht, bin ich zu früh im Sync-Byte; 
  ; <-- Sampling            ; (               3D 4D         )    habe gerade 0->1 Flanke detektiert.
  jc -                      ; (               4D 5D         )  Rückeinsprung nach 1-Detektion. Synchronisiere auf 1 Takt genau.
  ;                         ; (               5D 6D         )  3, 4, 5, 6, 7 sind gültige Einsprungtakte. 6/7 ist ein guter Rücksprung, 
  ; ----------------------- ;                  |  |            weil dann alle auf 9 synchronisiert werden.  Einlauf !
  xor.b #syncled, &P2OUT    ; (               6D 7D         )  xor mit Konstantengenerator zu Port braucht 4 Takte.
  ;                         ; (               7D 8D         )   Habe mit Oszilloskop geprüft: Die Xor-Flanke liegt genau auf
  ;                         ; (               8D 9D         )  oder ganz kurz NACH Beginn des ersten Datenbits ! **********************
  ; <-- Wechsel             ; (               9D 0B         )  1. Datenbit beginnt hier (wahrscheinlicher)
  push r12                  ; (               0B 1B         )                         (unwahrscheinlicher)
  ;                         ; (               1B 2B         )
  ;                         ; (               2B 3B         )
  ; ---------------------------------------------------------
  
  endif ; Altes Sync
