]> spindle.queued.net Git - linux-firmware/blobdiff - usbdux/usbduxfast_firmware.asm
Add the source code for the usbdux firmware
[linux-firmware] / usbdux / usbduxfast_firmware.asm
diff --git a/usbdux/usbduxfast_firmware.asm b/usbdux/usbduxfast_firmware.asm
new file mode 100644 (file)
index 0000000..0d8e7f8
--- /dev/null
@@ -0,0 +1,547 @@
+;   usbduxfast_firmware.asm
+;   Copyright (C) 2004,2009 Bernd Porr, Bernd.Porr@f2s.com
+;
+;   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 2 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, write to the Free Software
+;   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+;
+;
+; Firmware: usbduxfast_firmware.asm for usbdux.c
+; Description: Firmware for usbduxfast
+; Devices: [ITL] USB-DUX (usbdux.o)
+; Author: Bernd Porr <Bernd.Porr@f2s.com>
+; Updated: 17 Apr 2009
+; Status: stable
+;
+;;;
+;;;
+;;;
+
+       .inc    fx2-include.asm
+
+       .equ    WFLOADED,70H    ; waveform is loaded
+
+       .org    0000h           ; after reset the processor starts here
+       ljmp    main            ; jump to the main loop
+
+       .org    0043h           ; the IRQ2-vector
+       ljmp    jmptbl          ; irq service-routine
+
+       .org    0100h           ; start of the jump table
+
+jmptbl:        ljmp    sudav_isr
+       nop
+       ljmp    sof_isr
+       nop
+       ljmp    sutok_isr
+       nop
+       ljmp    suspend_isr
+       nop
+       ljmp    usbreset_isr
+       nop
+       ljmp    hispeed_isr
+       nop
+       ljmp    ep0ack_isr
+       nop
+       ljmp    spare_isr
+       nop
+       ljmp    ep0in_isr
+       nop
+       ljmp    ep0out_isr
+       nop
+       ljmp    ep1in_isr
+       nop
+       ljmp    ep1out_isr
+       nop
+       ljmp    ep2_isr
+       nop
+       ljmp    ep4_isr
+       nop
+       ljmp    ep6_isr
+       nop
+       ljmp    ep8_isr
+       nop
+       ljmp    ibn_isr
+       nop
+       ljmp    spare_isr
+       nop
+       ljmp    ep0ping_isr
+       nop
+       ljmp    ep1ping_isr
+       nop
+       ljmp    ep2ping_isr
+       nop
+       ljmp    ep4ping_isr
+       nop
+       ljmp    ep6ping_isr
+       nop
+       ljmp    ep8ping_isr
+       nop
+       ljmp    errlimit_isr
+       nop
+       ljmp    spare_isr
+       nop
+       ljmp    spare_isr
+       nop
+       ljmp    spare_isr
+       nop
+       ljmp    ep2isoerr_isr
+       nop
+       ljmp    ep4isoerr_isr
+       nop
+       ljmp    ep6isoerr_isr
+       nop
+       ljmp    ep8isoerr_isr
+
+       
+       ;; dummy isr
+sof_isr:
+sudav_isr:     
+sutok_isr:     
+suspend_isr:   
+usbreset_isr:  
+hispeed_isr:   
+ep0ack_isr:    
+spare_isr:     
+ep0in_isr:     
+ep0out_isr:    
+ep1out_isr:
+ep1in_isr:     
+ibn_isr:       
+ep0ping_isr:   
+ep1ping_isr:   
+ep2ping_isr:   
+ep4ping_isr:   
+ep6ping_isr:   
+ep8ping_isr:   
+errlimit_isr:  
+ep2isoerr_isr: 
+ep4isoerr_isr: 
+ep6isoerr_isr: 
+ep8isoerr_isr:
+ep6_isr:
+ep2_isr:
+ep8_isr:
+
+       push    dps
+       push    dpl
+       push    dph
+       push    dpl1
+       push    dph1
+       push    acc
+       push    psw
+
+       ;; clear the USB2 irq bit and return
+       mov     a,EXIF
+       clr     acc.4
+       mov     EXIF,a
+
+       pop     psw
+       pop     acc 
+       pop     dph1 
+       pop     dpl1
+       pop     dph 
+       pop     dpl 
+       pop     dps
+       
+       reti
+
+               
+;;; main program
+;;; basically only initialises the processor and
+;;; then engages in an endless loop
+main:
+       mov     dptr,#REVCTL
+       mov     a,#00000011b    ; allows skip
+       lcall   syncdelaywr
+
+       mov     DPTR,#CPUCS     ; CPU control register
+       mov     a,#00010000b    ; 48Mhz
+       lcall   syncdelaywr
+
+       mov     dptr,#IFCONFIG  ; switch on IFCLK signal
+       mov     a,#10100010b    ; gpif, 30MHz
+       lcall   syncdelaywr
+
+       mov     dptr,#FIFORESET
+       mov     a,#80h
+       lcall   syncdelaywr
+       mov     a,#8
+       lcall   syncdelaywr
+       mov     a,#2            
+       lcall   syncdelaywr
+       mov     a,#4            
+       lcall   syncdelaywr
+       mov     a,#6            
+       lcall   syncdelaywr
+       mov     a,#0            
+       lcall   syncdelaywr
+
+       mov     dptr,#INTSETUP  ; IRQ setup register
+       mov     a,#08h          ; enable autovector
+       lcall   syncdelaywr
+
+       lcall   initeps         ; init the isochronous data-transfer
+
+       lcall   initGPIF
+
+;;; main loop
+
+mloop2:
+       lcall   gpif_run
+       sjmp    mloop2          ; do nothing. The rest is done by the IRQs
+
+
+gpif_run:
+       mov     a,WFLOADED
+       jz      no_trig         ; do not trigger
+       mov     a,GPIFTRIG      ; GPIF status
+       anl     a,#80h          ; done bit
+       jz      no_trig         ; GPIF busy
+
+;;; gpif has stopped
+       mov     a,#06h          ; RD,EP6
+       mov     GPIFTRIG,a
+no_trig:
+       ret
+
+       
+
+initGPIF:
+       mov     DPTR,#EP6CFG    ; BLK data from here to the host
+       mov     a,#11100000b    ; Valid, quad buffering
+       lcall   syncdelaywr     ; write
+
+       mov     dptr,#EP6FIFOCFG
+       mov     a,#00001001b    ; autoin, wordwide
+       lcall   syncdelaywr
+
+       mov     dptr,#EP6AUTOINLENH
+       mov     a,#00000010b    ; 512 bytes
+       lcall   syncdelaywr     ; write
+
+       mov     dptr,#EP6AUTOINLENL
+       mov     a,#00000000b    ; 0
+       lcall   syncdelaywr     ; write
+
+       mov     dptr,#GPIFWFSELECT
+       mov     a,#11111100b    ; waveform 0 for FIFO RD
+       lcall   syncdelaywr
+
+       mov     dptr,#GPIFCTLCFG
+       mov     a,#10000000b    ; tri state for CTRL
+       lcall   syncdelaywr
+
+       mov     dptr,#GPIFIDLECTL
+       mov     a,#11111111b    ; all CTL outputs high
+       lcall   syncdelaywr
+       mov     a,#11111101b    ; reset counter
+       lcall   syncdelaywr
+       mov     a,#11111111b    ; reset to high again
+       lcall   syncdelaywr
+
+       mov     a,#00000010b    ; abort when full
+       mov     dptr,#EP6GPIFFLGSEL
+       lcall   syncdelaywr
+
+       mov     a,#00000001b    ; stop when buffer overfl
+       mov     dptr,#EP6GPIFPDFSTOP
+       lcall   syncdelaywr
+
+       mov     a,#0
+       mov     dptr,#GPIFREADYCFG
+       lcall   syncdelaywr
+
+       mov     a,#0
+       mov     dptr,#GPIFIDLECS
+       lcall   syncdelaywr
+
+; waveform 1
+; this is a dummy waveform which is used
+; during the upload of another waveform into
+; wavefrom 0
+; it branches directly into the IDLE state
+       mov     dptr,#0E420H
+       mov     a,#00111111b    ; branch to IDLE
+       lcall   syncdelaywr
+
+       mov     dptr,#0E428H    ; opcode
+       mov     a,#00000001b    ; deceision point
+       lcall   syncdelaywr
+
+       mov     dptr,#0E430H
+       mov     a,#0FFH         ; output is high
+       lcall   syncdelaywr
+
+       mov     dptr,#0E438H
+       mov     a,#0FFH         ; logic function
+       lcall   syncdelaywr
+
+; signals that no waveform 0 is loaded so far
+       mov     WFLOADED,#0     ; waveform flag
+
+       ret
+
+
+
+;;; initilise the transfer
+;;; It is assumed that the USB interface is in alternate setting 1
+initeps:
+       mov     DPTR,#EP4CFG
+       mov     a,#10100000b    ; valid, bulk, out
+       lcall   syncdelaywr
+
+       mov     dptr,#EP4BCL    ; "arm" it
+       mov     a,#00h
+       lcall   syncdelaywr     ; wait until we can write again
+       lcall   syncdelaywr     ; wait
+       lcall   syncdelaywr     ; wait
+
+       mov     DPTR,#EP8CFG
+       mov     a,#0            ; disable EP8, it overlaps with EP6!!
+       lcall   syncdelaywr
+
+       mov     dptr,#EPIE      ; interrupt enable
+       mov     a,#00100000b    ; enable irq for ep4
+       lcall   syncdelaywr     ; do it
+
+       mov     dptr,#EPIRQ     ; clear IRQs
+       mov     a,#00100100b
+       movx    @dptr,a
+
+        mov     DPTR,#USBIE    ; USB int enable register
+        mov     a,#0            ; SOF etc
+        movx    @DPTR,a         ;
+
+        mov     DPTR,#GPIFIE   ; GPIF int enable register
+        mov     a,#0            ; done IRQ
+        movx    @DPTR,a         ;
+
+       mov     EIE,#00000001b  ; enable INT2 in the 8051's SFR
+       mov     IE,#80h         ; IE, enable all interrupts
+
+       ret
+
+
+;;; interrupt-routine for ep4
+;;; receives the channel list and other commands
+ep4_isr:
+       push    dps
+       push    dpl
+       push    dph
+       push    dpl1
+       push    dph1
+       push    acc
+       push    psw
+       push    00h             ; R0
+       push    01h             ; R1
+       push    02h             ; R2
+       push    03h             ; R3
+       push    04h             ; R4
+       push    05h             ; R5
+       push    06h             ; R6
+       push    07h             ; R7
+               
+       mov     dptr,#0f400h    ; FIFO buffer of EP4
+       movx    a,@dptr         ; get the first byte
+
+       mov     dptr,#ep4_jmp   ; jump table for the different functions
+       rl      a               ; multiply by 2: sizeof sjmp
+       jmp     @a+dptr         ; jump to the jump table
+
+ep4_jmp:
+       sjmp    storewaveform   ; a=0
+       sjmp    init_ep6        ; a=1
+       
+init_ep6:
+       ; stop ep6
+       ; just now do nothing
+
+       ljmp    over_wf
+
+
+storewaveform:
+       mov     WFLOADED,#0     ; waveform flag
+
+       mov     dptr,#EP6FIFOCFG
+       mov     a,#00000000b    ;
+       lcall   syncdelaywr
+
+       mov     dptr,#GPIFABORT
+       mov     a,#0ffh         ; abort all transfers
+       lcall   syncdelaywr
+
+wait_f_abort:
+       mov     a,GPIFTRIG      ; GPIF status
+       anl     a,#80h          ; done bit
+       jz      wait_f_abort    ; GPIF busy
+
+       mov     dptr,#GPIFWFSELECT
+       mov     a,#11111101b    ; select dummy waveform
+       movx    @dptr,a
+       lcall   syncdelay
+
+       mov     dptr,#FIFORESET
+       mov     a,#80h          ; NAK
+       lcall   syncdelaywr
+       mov     a,#6            ; reset EP6
+       lcall   syncdelaywr
+       mov     a,#0            ; normal op
+       lcall   syncdelaywr
+
+; change to dummy waveform 1
+       mov     a,#06h          ; RD,EP6
+       mov     GPIFTRIG,a
+
+; wait a bit
+       mov     r2,255
+loopx:
+       djnz    r2,loopx
+
+; abort waveform if not already so
+       mov     dptr,#GPIFABORT
+       mov     a,#0ffh         ; abort all transfers
+       lcall   syncdelaywr
+
+; wait again
+       mov     r2,255
+loopx2:
+       djnz    r2,loopx2
+
+; check for DONE
+wait_f_abort2:
+       mov     a,GPIFTRIG      ; GPIF status
+       anl     a,#80h          ; done bit
+       jz      wait_f_abort2   ; GPIF busy
+
+; upload the new waveform into waveform 0
+       mov     AUTOPTRH2,#0E4H ; XDATA0H
+       lcall   syncdelay
+       mov     AUTOPTRL2,#00H  ; XDATA0L
+       lcall   syncdelay
+
+       mov     AUTOPTRH1,#0F4H ; EP4 high
+       lcall   syncdelay
+       mov     AUTOPTRL1,#01H  ; EP4 low
+       lcall   syncdelay
+
+       mov     AUTOPTRSETUP,#7 ; autoinc and enable
+       lcall   syncdelay
+
+       mov     r2,#20H         ; 32 bytes to transfer
+
+wavetr:
+       mov     dptr,#XAUTODAT1
+       movx    a,@dptr
+       lcall   syncdelay
+       mov     dptr,#XAUTODAT2
+       movx    @dptr,a
+       lcall   syncdelay
+       djnz    r2,wavetr
+
+       mov     dptr,#EP6FIFOCFG
+       mov     a,#00001001b    ; autoin, wordwide
+       lcall   syncdelaywr
+
+       mov     dptr,#GPIFWFSELECT
+       mov     a,#11111100b
+       movx    @dptr,a
+       lcall   syncdelay
+
+       mov     dptr,#FIFORESET
+       mov     a,#80h          ; NAK
+       lcall   syncdelaywr
+       mov     a,#6            ; reset EP6
+       lcall   syncdelaywr
+       mov     a,#0            ; normal op
+       lcall   syncdelaywr
+
+       mov     dptr,#0E400H+10H; waveform 0: first CTL byte
+       movx    a,@dptr         ; get it
+       orl     a,#11111011b    ; force all bits to one except the range bit
+       mov     dptr,#GPIFIDLECTL
+       lcall   syncdelaywr
+
+       mov     WFLOADED,#1     ; waveform flag
+
+; do the common things here    
+over_wf:       
+       mov     dptr,#EP4BCL
+       mov     a,#00h
+       movx    @DPTR,a         ; arm it
+       lcall   syncdelay       ; wait
+       movx    @DPTR,a         ; arm it
+       lcall   syncdelay       ; wait
+
+       ;; clear INT2
+       mov     a,EXIF          ; FIRST clear the USB (INT2) interrupt request
+       clr     acc.4
+       mov     EXIF,a          ; Note: EXIF reg is not 8051 bit-addressable
+
+       mov     DPTR,#EPIRQ     ; 
+       mov     a,#00100000b    ; clear the ep4irq
+       movx    @DPTR,a
+
+       pop     07h
+       pop     06h
+       pop     05h
+       pop     04h             ; R4
+       pop     03h             ; R3
+       pop     02h             ; R2
+       pop     01h             ; R1
+       pop     00h             ; R0
+       pop     psw
+       pop     acc 
+       pop     dph1 
+       pop     dpl1
+       pop     dph 
+       pop     dpl 
+       pop     dps
+       reti
+
+
+;; need to delay every time the byte counters
+;; for the EPs have been changed.
+
+syncdelay:
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       ret
+
+
+syncdelaywr:
+       lcall   syncdelay
+       movx    @dptr,a
+       ret
+
+
+.End
+
+
+
+
+
+
+
+
+
+
+
+