548 lines
9.2 KiB
NASM
548 lines
9.2 KiB
NASM
; 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
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|