summaryrefslogtreecommitdiffstats
path: root/usbdux/usbduxfast_firmware.asm
blob: 0d8e7f802599229452a4479bc300b5c23db2d2b0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
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