;
;    Mecrimus-B - 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/>.
;  


; Senderoutine für 18 MHz, 12 Takte/Bit
; Transmitter  for 18 MHz, 12 cycles/bit


; ---------------------------------------------------------------------------
usb_tx_bit macro ; Benötigt 8 Takte; Gibt Carry-Flag nach USB-Art aus.
; ---------------------------------------------------------------------------
  jnc +                           ; [1] Wechsel bei 0 !  Change on zero !
                                  ; [2]

  inc r13                               ; [3] Kein Leitungswechsel durchführen...  No change
  cmp #6, r13                           ; [4] Prüfe, ob die maximale Zahl von Bits ohne Wechsel durchgelaufen ist.  Check if there have been 6 bits without change
                                        ; [5] Wenn ja, füge einen Extrawechsel ein, so aber mache normal weiter.    If yes, include one line changing stuffing bit
  nop                                   ; [6]
  jne ++                                ; [7] Wenn kein Stopfen anliegt, mache einfach normal bei [9] weiter.       No stuffing necessary ? Continue
                                        ; [8]
  
  nop2                                         ; [9] Stopfbit präparieren ! Prepare stuffing bit
  ;nop                                         ; [10]
  nop2                                         ; [11]
  ;nop                                         ; [12]
  nop2                                         ; [1]
  ;nop                                         ; [2]

+ xor.b #usbplus+usbminus, &usbout ; [3] Leitungswechsel durchführen ! Change lines
                                  ; [4] (5 Takte)
                                  ; [5]
                                  ; [6]
                                  ; [7] <--- Wechsel !
  clr r13                         ; [8] Stopfzähler löschen  Clear stuffing counter

+ 
  endm
; ---------------------------------------------------------------------------


USB_Transmit: ; Einlauf mit Paketadresse in r15
              ; Enter with address of paket in r15

  ; r12  : Data beeing transmitted
  ; r13  : Stuffing counter
  ; r14  : Length left to transmit
  ; r15  : Pointer to fetch data

  ; Komme herein und habe bereits die Register gesichert. 
  ; Schließlich wird ausschließlich direkt auf einkommende Pakete geantwortet,
  ; nie wird selbst die Initiative ergriffen.

  ; Enter with already saved registers. We have to react only, so that registers are always saved before.

  ; Leitungen präparieren Prepare lines
  bic.b #usbplus,  &usbout  ; (4/5) Welche Leitung ist in Ruhe high, welche low ?
  bis.b #usbminus, &usbout  ; (4)   Idle=J: Minus high, Plus low.

  bis.b #usbplus+usbminus, &usbdir ; (5) Übernimm die Leitungen ! Ausgänge ! Take over control of lines ! Outputs !

  ; Stopfzähler präparieren (Wegen des Sync-Feldes und dessen Wechseln eigentlich unnötig!?)
  clr r13 ; (1) Prepare stuffing counter. Is this necessary, as sync field starts with changes ?

  ; Sync-Feld präparieren
  mov #80h, r12 ; (2) Prepare sync field.
  
  ; Pointer und Länge präparieren  
  mov.b @r15+, r14                ; (2) Längenbyte holen. Fetch length to transmit
  inc r14                         ; Erstes Byte ist Sync, also die Länge um eins erhöhen. First byte is sync field, one more.

USB_Sendeschleife:
  rra r12                        ; [12*] Daten weiterrotieren  Rotate Data
  ; ---------------------------------------------------------------------------
  ; Erstes Bit (0) verschicken:
  ; ---------------------------------------------------------------------------
  usb_tx_bit                     ; [1-8] Bit ausgeben                Transmit one Bit (with stuffing, if necessary)
  nop3                           ; [9]   Platz für Sonderaufgaben !  Holidays 
  ;nop                           ; [10]  Platz für Sonderaufgaben !
  ;nop                           ; [11]  Platz für Sonderaufgaben !
  rra r12                        ; [12]  Daten weiterrotieren        Rotate Data
  ; ---------------------------------------------------------------------------
  ; Zweites Bit (1) verschicken:
  ; ---------------------------------------------------------------------------
  usb_tx_bit                     ; [1-8] Bit ausgeben
  nop3                           ; [9]   Platz für Sonderaufgaben !
  ;nop                           ; [10]  Platz für Sonderaufgaben !
  ;nop                           ; [11]  Platz für Sonderaufgaben !
  rra r12                        ; [12]  Daten weiterrotieren
  ; ---------------------------------------------------------------------------
  ; Drittes Bit (2) verschicken:
  ; ---------------------------------------------------------------------------
  usb_tx_bit                     ; [1-8] Bit ausgeben
  nop3                           ; [9]   Platz für Sonderaufgaben !
  ;nop                           ; [10]  Platz für Sonderaufgaben !
  ;nop                           ; [11]  Platz für Sonderaufgaben !
  rra r12                        ; [12]  Daten weiterrotieren
  ; ---------------------------------------------------------------------------
  ; Viertes Bit (3) verschicken:
  ; ---------------------------------------------------------------------------
  usb_tx_bit                     ; [1-8] Bit ausgeben
  nop3                           ; [9]   Platz für Sonderaufgaben !
  ;nop                           ; [10]  Platz für Sonderaufgaben !
  ;nop                           ; [11]  Platz für Sonderaufgaben !
  rra r12                        ; [12]  Daten weiterrotieren
  ; ---------------------------------------------------------------------------
  ; Fünftes Bit (4) verschicken:
  ; ---------------------------------------------------------------------------
  usb_tx_bit                     ; [1-8] Bit ausgeben
  nop3                           ; [9]   Platz für Sonderaufgaben !
  ;nop                           ; [10]  Platz für Sonderaufgaben !
  ;nop                           ; [11]  Platz für Sonderaufgaben !
  rra r12                        ; [12]  Daten weiterrotieren
  ; ---------------------------------------------------------------------------
  ; Sechstes Bit (5) verschicken:
  ; ---------------------------------------------------------------------------
  usb_tx_bit                     ; [1-8] Bit ausgeben
  nop3                           ; [9]   Platz für Sonderaufgaben !
  ;nop                           ; [10]  Platz für Sonderaufgaben !
  ;nop                           ; [11]  Platz für Sonderaufgaben !
  rra r12                        ; [12]  Daten weiterrotieren                   
  ; ---------------------------------------------------------------------------
  ; Siebstes Bit (6) verschicken:
  ; ---------------------------------------------------------------------------
  usb_tx_bit                     ; [1-8] Bit ausgeben
  rra r12                        ; [9]   Letztes Datenbit holen    Fetch last bit of current data byte
  mov.b @r15+, r12               ; [10]  Nächstes Byte bereitlegen Fetch next data byte, preserves flags
  ;                              ; [11]  
  nop                            ; [12]  Platz für Sonderaufgaben !             
  ; ---------------------------------------------------------------------------
  ; Achtes Bit (7) verschicken:
  ; ---------------------------------------------------------------------------
  usb_tx_bit                     ; [1-8] Bit ausgeben                          
  dec r14                        ; [9]   Kommt noch etwas ?        Some more data to send ?
  jnz USB_Sendeschleife          ; [10]  Wenn ja, weitermachen.    Transmit them !
                                 ; [11]                                         
  nop                            ; [12]  Ansonsten SE0 präparieren. Else prepare SE0
  ; --------------------------------------------------------------------------- 
  ; SE0 ausgeben, Ende                                                          
  ; --------------------------------------------------------------------------- 
  nop2                           ; [1]
  ;                              ; [2]
  bic.b #usbplus+usbminus, &usbout ; [3] SE0 bereitlegen und zwei Bitzeiten lang halten.
                                 ; [4]   Prepare SE0 and hold for two bit times
                                 ; [5]
                                 ; [6]
                                 ; [7] <--- hier ! Electrical action takes place here
  pop r8                         ; [8]  Könnte wunderbar all die Register zurückholen ;-)
                                 ; [9]  Wonderful place to pop back all registers
  pop r15                        ; [10]  
                                 ; [11]
  pop r14                        ; [12]

                                 ; [1]
  pop r13                        ; [2]
                                 ; [3]
  pop r12                        ; [4]
                                 ; [5]
  pop r11                        ; [6]
                                 ; [7]
  pop r10                        ; [8]
                                 ; [9]
  pop r9                         ; [10]
                                 ; [11]
  nop                            ; [12]

  nop2                           ; [1]
  ;                              ; [2]
  
  
  nop                            ; [3]
  bis.b #usbminus, &usbout       ; [4] Idle - J in die Leitung legen, Signal für EOP
  ;                              ; [5] Idle - J into line, required for EOP
  ;                              ; [6]
  ;                              ; [7] <-- hier !
  
  nop4 ; 8-11
  nop3 ; 12-2
  
  
  bic.b #usbplus+usbminus, &usbdir ; [3] EOP zurücknehmen, Leitungen loslassen Release lines
                                 ; [4]
                                 ; [5]
                                 ; [6]
                                 ; [7] <--- hier !
                                 
  bic.b #usbplus, &P2IFG ; Interrupt-Pending-Flag löschen. Gleich nach SE0 und nach dem Senden.
                         ; Clear interrupt pending flag.
  
  eint ; Reenable Interrupts, ready for next paket.
  
  call #Protokollhelferlein ; Process pakets and handle protocol - this can be done here or in main loop.
  
  reti  ; Fertig. So schnell kommt kein neues Paket nach dem SE0. Kann Antworten im nächsten Interrupt bearbeiten.
