;
;    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 15 MHz, 10 Takte/Bit
; Transmitter  for 15 MHz, 10 cycles/bit


; ---------------------------------------------------------------------------
usb_tx_bit macro ; Benötigt 7 Takte; Gibt Carry-Flag nach USB-Art aus.  Needs 7 cycles, transmits Carry in style of usb.
; ---------------------------------------------------------------------------
  jnc +                           ; [1] Wechsel bei 0 !
                                  ; [2]

  inc r13                               ; [3] Kein Leitungswechsel durchführen...
  cmp #6, r13                           ; [4] Prüfe, ob die maximale Zahl von Bits ohne Wechsel durchgelaufen ist.  Check whether we had 6 bits without change...
                                        ; [5] Wenn ja, füge einen Extrawechsel ein, so aber mache normal weiter.    --> Insert a stuff-bit
  jne ++                                ; [6] 
                                        ; [7] Wenn kein Stopfen anliegt, mache einfach normal bei [8] weiter.
  
  nop2                                        ; [8] Stopfbit präparieren !
  ;nop                                        ; [9]
  nop2                                        ; [10]
  ;nop                                        ; [1]
  nop                                         ; [2]

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

+ 
  endm

; ---------------------------------------------------------------------------
usb_tx_bit_later macro ; Benötigt 7 Takte; Gibt Carry-Flag nach USB-Art aus.  Needs 7 cycles, transmits Carry in style of usb.
                         ; Wechsel erfolgt einen Takt später !                  Change in line one cycle later.
; ---------------------------------------------------------------------------
  jnc +                           ; [1] Wechsel bei 0 !
                                  ; [2]

  inc r13                               ; [3] Kein Leitungswechsel durchführen...
  cmp #6, r13                           ; [4] Prüfe, ob die maximale Zahl von Bits ohne Wechsel durchgelaufen ist.
                                        ; [5] Wenn ja, füge einen Extrawechsel ein, so aber mache normal weiter.
  jne ++                                ; [6] 
                                        ; [7] Wenn kein Stopfen anliegt, mache einfach normal bei [8] weiter.
  
  nop2                                        ; [8] Stopfbit präparieren !
  ;nop                                        ; [9]
  nop2                                        ; [10]
  ;nop                                        ; [1]
  nop                                         ; [2]

+ clr r13                         ; [3] Stopfzähler löschen                       Here clr and xor are interchanged.
  xor.b r11, &usbout              ; [4] Leitungswechsel durchführen !
                                  ; [5] (4 Takte)
                                  ; [6] 
                                  ; [7]  <--- Wechsel !

+ 
  endm


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

  ; r10  : Spare data register
  ; r11  : Mask for XORing, usbplus+usbminus
  ; 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.

  mov #usbplus+usbminus, r11 ; (2)  ; Maske präparieren       Prepare mask for fast xor access
  bis.b r11, &usbdir ; (4) Ü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                        ; [10*] Daten weiterrotieren  Rotate Data
  ; ---------------------------------------------------------------------------
  ; Erstes Bit (0) verschicken:
  ; ---------------------------------------------------------------------------
  usb_tx_bit                     ; [1-7] Bit ausgeben                Transmit one Bit (with stuffing, if necessary)
  nop2                           ; [8]   Platz für Sonderaufgaben !  Holidays 
  ;                              ; [9]   Platz für Sonderaufgaben !
  rra r12                        ; [10]  Daten weiterrotieren        Rotate Data
  ; ---------------------------------------------------------------------------
  ; Zweites Bit (1) verschicken:
  ; ---------------------------------------------------------------------------
  usb_tx_bit                     ; [1-7] Bit ausgeben
  nop2                           ; [8]   Platz für Sonderaufgaben !
  ;                              ; [9]   Platz für Sonderaufgaben !
  rra r12                        ; [10]  Daten weiterrotieren
  ; ---------------------------------------------------------------------------
  ; Drittes Bit (2) verschicken:
  ; ---------------------------------------------------------------------------
  usb_tx_bit                     ; [1-7] Bit ausgeben
  nop2                           ; [8]   Platz für Sonderaufgaben !
  ;                              ; [9]   Platz für Sonderaufgaben !
  rra r12                        ; [10]  Daten weiterrotieren
  ; ---------------------------------------------------------------------------
  ; Viertes Bit (3) verschicken:
  ; ---------------------------------------------------------------------------
  usb_tx_bit                     ; [1-7] Bit ausgeben
  nop2                           ; [8]   Platz für Sonderaufgaben !
  ;                              ; [9]   Platz für Sonderaufgaben !
  rra r12                        ; [10]  Daten weiterrotieren
  ; ---------------------------------------------------------------------------
  ; Fünftes Bit (4) verschicken:
  ; ---------------------------------------------------------------------------
  usb_tx_bit                     ; [1-7] Bit ausgeben
  nop2                           ; [8]   Platz für Sonderaufgaben !
  ;                              ; [9]   Platz für Sonderaufgaben !
  rra r12                        ; [10]  Daten weiterrotieren
  ; ---------------------------------------------------------------------------
  ; Sechstes Bit (5) verschicken:
  ; ---------------------------------------------------------------------------
  usb_tx_bit                     ; [1-7] Bit ausgenben
  mov.b @r15+, r10               ; [8]   Nächstes Byte bereitlegen                Fetch next data byte into r10
  ;                              ; [9]
  rra r12                        ; [10]  Daten weiterrotieren           
  ; ---------------------------------------------------------------------------
  ; Siebstes Bit (6) verschicken:
  ; ---------------------------------------------------------------------------
  usb_tx_bit                     ; [1-7] Bit ausgenben
  rra r12                        ; [8]   Letztes Datenbit aus altem Byte holen         Rotate last Bit
  mov r10, r12                   ; [9]   Nächstes Byte an die richtige Stelle schieben.  Put next byte in place
  ; ---------------------------------------------------------------------------          One cycle less than usual to have enough time in next bit !
  ; Achtes Bit (7) verschicken:
  ; ---------------------------------------------------------------------------
  usb_tx_bit_later               ; [10-6] Bit ausgeben                                   This handles the lines one cycle later... So timing is preserved.
  dec r14                        ; [7]    Kommt noch etwas ?                             Decrement length
  jnz USB_Sendeschleife          ; [8]    Wenn ja, weitermachen.                          Anything left ? Jump back quickly !
  ;                              ; [9]                    
  nop                            ; [10]   Ansonsten SE0 präparieren. 
  ; --------------------------------------------------------------------------- 
  ; SE0 ausgeben, Ende                                                          
  ; --------------------------------------------------------------------------- 
  nop                            ; [1]
  bic.b #usbplus+usbminus, &usbout ; [2] SE0 bereitlegen und zwei Bitzeiten lang halten.
                                 ; [3]   Prepare SE0 and hold for two bit times
                                 ; [4]
                                 ; [5]
                                 ; [6] <--- hier ! Electrical action takes place here
  pop r8                         ; [7]  Könnte wunderbar all die Register zurückholen ;-)
                                 ; [8]  Wonderful place to pop back all registers
  pop r15                        ; [9]  
                                 ; [10]
  pop r14                        ; [1]
                                 ; [2]
  pop r13                        ; [3]
                                 ; [4]
  pop r12                        ; [5]
                                 ; [6]
  pop r11                        ; [7]
                                 ; [8]
  pop r10                        ; [9]
                                 ; [10]
  pop r9                         ; [1]
                                 ; [2]
  bis.b #usbminus, &usbout       ; [3] Idle - J in die Leitung legen, Signal für EOP
  ;                              ; [4] Idle - J into line, required for EOP
  ;                              ; [5]
  ;                              ; [6] <-- hier !
  
  nop4 ; [7, 8, 9, 10]
  nop  ; [1]
  
  bic.b #usbplus+usbminus, &usbdir ; [2] EOP zurücknehmen, Leitungen loslassen Release lines
                                 ; [3]
                                 ; [4]
                                 ; [5]
                                 ; [6] <--- hier !
                                 
  bic.b #usbplus, &usbifg ; Interrupt-Pending-Flag löschen. Gleich nach SE0 und nach dem Senden.
                          ; Clear interrupt pending flag.
  
  reti  ; Fertig. So schnell kommt kein neues Paket nach dem SE0. Kann Antworten im nächsten Interrupt bearbeiten.
