updated usbdux firmware from Bernd Porr:
authorFrank Mori Hess <fmhess@speakeasy.net>
Sun, 1 Aug 2004 22:24:01 +0000 (22:24 +0000)
committerFrank Mori Hess <fmhess@speakeasy.net>
Sun, 1 Aug 2004 22:24:01 +0000 (22:24 +0000)
Firmware now only measures as many channels as are in the channel list. If
there's only one channel in the list we can manage to measure within one
microframe. This makes it possible to measure with 8kHz max.
Added a counter. The counter is called every 2ms from an FX2 timer inerrupt. Low
priority so that measurements are not disturbed.
The bulk transfers are now two times faster (insn). Reading an A/D value or an
DIO takes now only 2ms or less. The trick is that the in endpoint is already
filled when the request is issued.
Fixed a bug in the FIFO resets.

Second counter did not count properly. That's fixed. Also
found two missing syncdelays.

etc/hotplug/usb/usbdux/usbdux_firmware.asm
etc/hotplug/usb/usbdux/usbdux_firmware.hex

index e9aa88bd3258b5bfc475f169886ed05df6b54c80..3513b1cf6bd57ff117ea2a689b582224bcd1cfc5 100644 (file)
@@ -1,5 +1,6 @@
 ;   usbdux_firmware.asm
-;   Copyright (C) 2004 Bernd Porr, Bernd.Porr@cn.stir.ac.uk
+;   Copyright (C) 2004 Bernd Porr, Bernd.Porr@f2s.com
+;   For usbdux.c 1.00pre2
 ;
 ;   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
@@ -19,8 +20,8 @@
 ; Firmware: usbdux_firmware.asm for usbdux.c
 ; Description: University of Stirling USB DAQ & INCITE Technology Limited
 ; Devices: [ITL] USB-DUX (usbdux.o)
-; Author: Bernd Porr <Bernd.Porr@cn.stir.ac.uk>
-; Updated: 25 Jan 2004
+; Author: Bernd Porr <Bernd.Porr@f2s.com>
+; Updated: 23 Jul 2004
 ; Status: testing
 ;
 ;;;
 
        .equ    CHANNELLIST,80h ; channellist in indirect memory
        
-       .equ    DIOFLAG,90h     ; flag if next IN transf is DIO
-               
+       .equ    CMD_FLAG,90h    ; flag if next IN transf is DIO
+       .equ    SGLCHANNEL,91h  ; channel for INSN
+       
+       .equ    DIOSTAT0,98h    ; last status of the digital port
+       .equ    DIOSTAT1,99h    ; same for the second counter
+       
+       .equ    CTR0,0A0H       ; counter 0
+       .equ    CTR1,0A2H       ; counter 1
+                       
        .org    0000h           ; after reset the processor starts here
        ljmp    main            ; jump to the main loop
 
+       .org    000bh           ; timer 0 irq
+       ljmp    timer0_isr
+
        .org    0043h           ; the IRQ2-vector
        ljmp    jmptbl          ; irq service-routine
        
@@ -164,18 +175,25 @@ ep2_isr:
 main:
        mov     DPTR,#CPUCS     ; CPU control register
        mov     a,#00010000b    ; 48Mhz
-       movx    @DPTR,a         ; do it
-       lcall   syncdelay
+       lcall   syncdelaywr
 
+        mov     dptr,#REVCTL
+        mov     a,#00000011b    ; allows skip
+        lcall   syncdelaywr
+
+       mov     IP,#0           ; all std 8051 int have low priority
+       mov     EIP,#0FFH       ; all FX2 interrupts have high priority
+       
        mov     dptr,#INTSETUP  ; IRQ setup register
        mov     a,#08h          ; enable autovector
-       movx    @DPTR,a         ; do it
-       lcall   syncdelay
+       lcall   syncdelaywr
 
        lcall   initAD          ; init the ports to the converters
 
        lcall   initeps         ; init the isochronous data-transfer
 
+       lcall   init_timer
+       
 mloop2:        nop
        nop
        nop
@@ -184,7 +202,7 @@ mloop2:     nop
        nop
        nop
 
-       sjmp    mloop2          ; do nothing. The rest is done by the IRQs
+       sjmp    mloop2          ; loop for ever
 
 
 ;;; initialise the ports for the AD-converter
@@ -194,6 +212,16 @@ initAD:
        ret
 
 
+;;; init the timer for the soft counters
+init_timer:
+       ;; init the timer for 2ms sampling rate
+       mov     CKCON,#00000001b; CLKOUT/12 for timer
+       mov     TL0,#010H       ; 16
+       mov     TH0,#0H         ; 256
+       mov     IE,#82H         ; switch on timer interrupt (80H for all IRQs)
+       mov     TMOD,#00000000b ; 13 bit counters
+       setb    TCON.4          ; enable timer 0
+       ret
 
 
 ;;; from here it's only IRQ handling...
@@ -264,82 +292,27 @@ zerob2:   mov     a,r5            ; get r5 in order to shift the mask
        
 
        
-;;; aquires data from all 8 channels and stores it in the EP6 buffer
-convlo:        ;;
-       mov     AUTOPTRH1,#0F8H ; EP6
+;;; aquires data from A/D channels and stores them in the EP6 buffer
+conv_ad:
+       mov     AUTOPTRH1,#0F8H ; auto pointer on EP6
        mov     AUTOPTRL1,#00H
        mov     AUTOPTRSETUP,#7
        mov     r0,#CHANNELLIST ; points to the channellist
-       mov     a,@r0           ;Ch0
-       lcall   readAD
-       mov     a,R3            ;
-       mov     DPTR,#XAUTODAT1
-       movx    @DPTR,A
-       mov     a,R4            ;
-       movx    @DPTR,A
-
-       inc     r0              ; next channel
-       mov     a,@r0           ;Ch1
-       lcall   readAD
-       mov     a,R3            ;
-       mov     DPTR,#XAUTODAT1
-       movx    @DPTR,A
-       mov     a,R4            ;
-       movx    @DPTR,A
-
-       inc     r0
-       mov     a,@r0           ;Ch2
-       lcall   readAD
-       mov     a,R3            ;
-       mov     DPTR,#XAUTODAT1
-       movx    @DPTR,A
-       mov     a,R4            ;
-       movx    @DPTR,A
 
-       inc     r0
-       mov     a,@r0           ;Ch3
-       lcall   readAD
-       mov     a,R3            ;
-       mov     DPTR,#XAUTODAT1
-       movx    @DPTR,A
-       mov     a,R4            ;
-       movx    @DPTR,A
+       mov     a,@r0           ; number of channels
+       mov     r1,a            ; counter
 
+       mov     DPTR,#XAUTODAT1 ; auto pointer
+convloop:
        inc     r0
-       mov     a,@r0           ;Ch4
+       mov     a,@r0           ; Channel
        lcall   readAD
        mov     a,R3            ;
-       mov     DPTR,#XAUTODAT1
        movx    @DPTR,A
        mov     a,R4            ;
        movx    @DPTR,A
+       djnz    r1,convloop
 
-       inc     r0
-       mov     a,@r0           ;Ch5
-       lcall   readAD
-       mov     a,R3            ;
-       mov     DPTR,#XAUTODAT1
-       movx    @DPTR,A
-       mov     a,R4            ;
-       movx    @DPTR,A
-
-       inc     r0
-       mov     a,@r0           ;Ch6
-       lcall   readAD
-       mov     a,R3            ;
-       mov     DPTR,#XAUTODAT1
-       movx    @DPTR,A
-       mov     a,R4            ;
-       movx    @DPTR,A
-
-       inc     r0
-       mov     a,@r0           ;Ch7
-       lcall   readAD
-       mov     a,R3            ;
-       mov     DPTR,#XAUTODAT1
-       movx    @DPTR,A
-       mov     a,R4            ;
-       movx    @DPTR,A
        ret
 
 
@@ -349,9 +322,17 @@ convlo:    ;;
 ;;; It is assumed that the USB interface is in alternate setting 3
 initeps:
        mov     dptr,#FIFORESET
-       mov     a,#0fh          
+       mov     a,#80H          
        movx    @dptr,a         ; reset all fifos
-       mov     a,#00h          
+       mov     a,#2    
+       movx    @dptr,a         ; 
+       mov     a,#4            
+       movx    @dptr,a         ; 
+       mov     a,#6            
+       movx    @dptr,a         ; 
+       mov     a,#8            
+       movx    @dptr,a         ; 
+       mov     a,#0            
        movx    @dptr,a         ; normal operat
        
        mov     DPTR,#EP2CFG
@@ -363,7 +344,7 @@ initeps:
        movx    @dptr,a
 
        mov     dptr,#EP2BCL    ; "arm" it
-       mov     a,#80h
+       mov     a,#00h
        movx    @DPTR,a         ; can receive data
        lcall   syncdelay       ; wait to sync
        movx    @DPTR,a         ; can receive data
@@ -380,7 +361,7 @@ initeps:
        movx    @dptr,a
 
        mov     dptr,#EP4BCL    ; "arm" it
-       mov     a,#80h
+       mov     a,#00h
        movx    @DPTR,a         ; can receive data
        lcall   syncdelay       ; wait until we can write again
        movx    @dptr,a         ; make shure its really empty
@@ -410,11 +391,103 @@ initeps:
        mov     EIE,#00000001b  ; enable INT2 in the 8051's SFR
        mov     IE,#80h         ; IE, enable all interrupts
 
-       lcall   ep8_arm         ; 
-       
        ret
 
 
+;;; counter
+;;; r0: DIOSTAT
+;;; r1:        counter address
+;;; r2:        up/down-mask
+;;; r3:        reset-mask
+;;; r4:        clock-mask
+counter:       
+       mov     a,IOB           ; actual IOB input state
+       mov     r5,a            ; save in r5
+       anl     a,r3            ; bit mask for reset
+       jz      no_reset        ; reset if one
+       clr     a               ; set counter to zero
+       mov     @r1,a
+       inc     r4
+       mov     @r1,a
+       sjmp    ctr_end
+no_reset:      
+       mov     a,@r0           ; get last state
+       xrl     a,r5            ; has it changed?
+       anl     a,r5            ; is it now on?
+       anl     a,r4            ; mask out the port
+       jz      ctr_end         ; no rising edge
+       mov     a,r5            ; get port B again
+       anl     a,r2            ; test if up or down
+       jnz     ctr_up          ; count up
+       mov     a,@r1
+       dec     a
+       mov     @r1,a
+       cjne    a,#0ffh,ctr_end ; underflow?
+       inc     r1              ; high byte
+       mov     a,@r1
+       dec     a
+       mov     @r1,a
+       sjmp    ctr_end
+ctr_up:                                ; count up
+       mov     a,@r1
+       inc     a
+       mov     @r1,a
+       jnz     ctr_end
+       inc     r1              ; high byte
+       mov     a,@r1
+       inc     a
+       mov     @r1,a
+ctr_end:
+       mov     a,r5
+       mov     @r0,a
+       ret
+
+;;; implements two soft counters with up/down and reset
+timer0_isr:
+       push    dps
+       push    acc
+       push    psw
+       push    00h             ; R0
+       push    01h             ; R1
+       push    02h             ; R2
+       push    03h             ; R3
+       push    04h             ; R4
+       push    05h             ; R5
+               
+       mov     r0,#DIOSTAT0    ; status of port
+       mov     r1,#CTR0        ; address of counter0
+       mov     a,#00000001b    ; bit 0
+       mov     r4,a            ; clock
+       rl      a               ; bit 1
+       mov     r2,a            ; up/down
+       rl      a               ; bit 2
+       mov     r3,a            ; reset mask
+       lcall   counter
+       inc     r0              ; to DISTAT1
+       inc     r1              ; to CTR1
+       inc     r1
+       mov     a,r3
+       rl      a               ; bit 3
+       rl      a               ; bit 4
+       mov     r4,a            ; clock
+       rl      a               ; bit 5
+       mov     r2,a            ; up/down
+       rl      a               ; bit 6
+       mov     r3,a            ; reset
+       lcall   counter
+       
+       pop     05h             ; R5
+       pop     04h             ; R4
+       pop     03h             ; R3
+       pop     02h             ; R2
+       pop     01h             ; R1
+       pop     00h             ; R0
+       pop     psw
+       pop     acc 
+       pop     dps
+
+       reti
+
 ;;; interrupt-routine for SOF
 ;;; is for full speed
 sof_isr:
@@ -438,17 +511,15 @@ sof_isr:
        anl     a,#20H          ; full?
        jnz     epfull          ; EP6-buffer is full
 
-       lcall   convlo          ; conversion
+       lcall   conv_ad         ; conversion
 
        mov     DPTR,#EP6BCH    ; byte count H
        mov     a,#0            ; is zero
-       movx    @DPTR,a
-       lcall   syncdelay       ; wait until we can write again
+       lcall   syncdelaywr     ; wait until we can write again
        
        mov     DPTR,#EP6BCL    ; byte count L
        mov     a,#10H          ; is 8x word = 16 bytes
-       movx    @DPTR,a
-       lcall   syncdelay       ; wait until we can write again
+       lcall   syncdelaywr     ; wait until we can write again
        
 epfull:
        ;; do the D/A conversion
@@ -460,11 +531,9 @@ epfull:
        lcall   dalo            ; conversion
 
        mov     dptr,#EP2BCL    ; "arm" it
-       mov     a,#80h
-       movx    @DPTR,a         ; can receive data
-       lcall   syncdelay       ; wait for the rec to sync
-       movx    @dptr,a         ; just to make sure that it's empty
-       lcall   syncdelay       ; wait for the rec to sync
+       mov     a,#00h
+       lcall   syncdelaywr     ; wait for the rec to sync
+       lcall   syncdelaywr     ; wait for the rec to sync
 
 epempty:       
        ;; clear INT2
@@ -495,9 +564,34 @@ nosof:
        reti
 
 
+reset_ep8:
+       ;; erase all data in ep8
+       mov     dptr,#FIFORESET
+       mov     a,#80H          ; NAK
+       lcall   syncdelaywr
+       mov     dptr,#FIFORESET
+       mov     a,#8            ; reset EP8
+       lcall   syncdelaywr
+       mov     dptr,#FIFORESET
+       mov     a,#0            ; normal operation
+       lcall   syncdelaywr
+       ret
 
 
+reset_ep6:
+       ;; throw out old data
+       mov     dptr,#FIFORESET
+       mov     a,#80H          ; NAK
+       lcall   syncdelaywr
+       mov     dptr,#FIFORESET
+       mov     a,#6            ; reset EP6
+       lcall   syncdelaywr
+       mov     dptr,#FIFORESET
+       mov     a,#0            ; normal operation
+       lcall   syncdelaywr
+       ret
 
+       
 ;;; interrupt-routine for ep4
 ;;; receives the channel list and other commands
 ep4_isr:
@@ -519,25 +613,74 @@ ep4_isr:
                
        mov     dptr,#0f400h    ; FIFO buffer of EP4
        movx    a,@dptr         ; get the first byte
+       mov     r0,#CMD_FLAG    ; pointer to the command byte
+       mov     @r0,a           ; store the command byte for ep8
 
        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
+       ;; jump table, corresponds to the command bytes defined
+       ;; in usbdux.c
 ep4_jmp:
        sjmp    storechannellist; a=0
        sjmp    single_da       ; a=1
        sjmp    config_digital_b; a=2
        sjmp    write_digital_b ; a=3
+       sjmp    storesglchannel ; a=4
+       sjmp    readcounter     ; a=5
+       sjmp    writecounter    ; a=6
+
+       ;; read the counter
+readcounter:
+       lcall   reset_ep8       ; reset ep8
+       lcall   ep8_ops         ; fill the counter data in there
+       sjmp    over_da         ; jump to the end
+
+       ;; write zeroes to the counters
+writecounter:
+       mov     dptr,#0f401h    ; buffer
+       mov     r0,#CTR0        ; r0 points to counter 0
+       movx    a,@dptr         ; channel number
+       jz      wrctr0          ; first channel
+       mov     r1,a            ; counter
+wrctrl:
+       inc     r0              ; next counter
+       inc     r0              ; next counter
+       djnz    r1,wrctrl       ; advance to the right counter
+wrctr0:
+       inc     dptr            ; get to the value
+       movx    a,@dptr         ; get value
+       mov     @r0,a           ; save in ctr
+       inc     r0              ; next byte
+       inc     dptr
+       movx    a,@dptr         ; get value
+       mov     @r0,a           ; save in ctr
+       sjmp    over_da         ; jump to the end
 
+storesglchannel:
+       mov     r0,#SGLCHANNEL  ; the conversion bytes are now stored in 80h
+       mov     dptr,#0f401h    ; FIFO buffer of EP4
+       movx    a,@dptr         ; 
+       mov     @r0,a
 
-;;; Channellist:       
+       lcall   reset_ep8       ; reset FIFO
+       ;; Save new A/D data in EP8. This is the first byte
+       ;; the host will read during an INSN. If there are
+       ;; more to come they will be handled by the ISR of
+       ;; ep8.
+       lcall   ep8_ops         ; get A/D data
+               
+       sjmp    over_da
+
+       
+;;; Channellist:
 ;;; the first byte is zero:
 ;;; we've just received the channel list
-;;; the channel list is stored in the addresses from 80H which
+;;; the channel list is stored in the addresses from CHANNELLIST which
 ;;; are _only_ reachable by indirect addressing
 storechannellist:
        mov     r0,#CHANNELLIST ; the conversion bytes are now stored in 80h
-       mov     r2,#8           ; counter
+       mov     r2,#9           ; counter
        mov     dptr,#0f401h    ; FIFO buffer of EP4
 chanlloop:     
        movx    a,@dptr         ; 
@@ -545,9 +688,15 @@ chanlloop:
        inc     dptr
        inc     r0
        djnz    r2,chanlloop
-       clr     a               ; announce analogue transaction
-       mov     r0,#DIOFLAG     ; pointer to the command byte
-       mov     @r0,a           ; set the command byte
+
+       lcall   reset_ep6       ; reset FIFO
+       
+       ;; load new A/D data into EP6
+       ;; This must be done. Otherwise the ISR is never called.
+       ;; The ISR is only called when data has _left_ the
+       ;; ep buffer here it has to be refilled.
+       lcall   ep6_arm         ; fill with the first data byte
+       
        sjmp    over_da
 
 ;;; Single DA conversion. The 2 bytes are in the FIFO buffer
@@ -556,7 +705,7 @@ single_da:
        lcall   dalo            ; conversion
        sjmp    over_da
 
-;;; configure the port B
+;;; configure the port B as input or output (bitwise)
 config_digital_b:
        mov     dptr,#0f401h    ; FIFO buffer of EP4
        movx    a,@dptr         ; get the second byte
@@ -572,22 +721,25 @@ write_digital_b:
        inc     dptr            ; next byte
        movx    a,@dptr         ; bits
        mov     IOB,a           ; send the byte to the I/O port
-       mov     a,#0ffh         ; announce DIO transaction
-       mov     r0,#DIOFLAG     ; pointer to the command byte
-       mov     @r0,a           ; set the command byte
-       sjmp    over_da
 
-;;; more things here to come...
-       
+       lcall   reset_ep8       ; reset FIFO of ep 8
+
+       ;; fill ep8 with new data from port B
+       ;; When the host requests the data it's already there.
+       ;; This must be so. Otherwise the ISR is not called.
+       ;; The ISR is only called when a packet has been delivered
+       ;; to the host. Thus, we need a packet here in the
+       ;; first instance.
+       lcall   ep8_ops         ; get digital data
+
+       ;; 
+       ;; for all commands the same
 over_da:       
        mov     dptr,#EP4BCL
-       mov     a,#80h
-       movx    @DPTR,a         ; arm it
-       lcall   syncdelay       ; wait
-       movx    @DPTR,a         ; arm it
-       lcall   syncdelay       ; wait
-       movx    @DPTR,a         ; arm it
-       lcall   syncdelay       ; wait
+       mov     a,#00h
+       lcall   syncdelaywr     ; arm
+       lcall   syncdelaywr     ; arm
+       lcall   syncdelaywr     ; arm
 
        ;; clear INT2
        mov     a,EXIF          ; FIRST clear the USB (INT2) interrupt request
@@ -678,29 +830,57 @@ noDA:     ret
 
 ;;; arm ep6
 ep6_arm:
-       lcall   convlo
+       lcall   conv_ad
        
        mov     DPTR,#EP6BCH    ; byte count H
        mov     a,#0            ; is zero
-       movx    @DPTR,a
-       lcall   syncdelay       ; wait until the length has arrived
+       lcall   syncdelaywr     ; wait until the length has arrived
        
        mov     DPTR,#EP6BCL    ; byte count L
        mov     a,#10H          ; is one
-       movx    @DPTR,a
-       lcall   syncdelay       ; wait until the length has been proc
+       lcall   syncdelaywr     ; wait until the length has been proc
        ret
        
 
 
 ;;; converts one analog/digital channel and stores it in EP8
-;;; also gets the content of the digital ports B and D
-ep8_adc:
-       mov     r0,#DIOFLAG     ; pointer to the DIO flag
-       mov     a,@r0           ; get the flag
-       jnz     ep8_dio         ; nonzero means DIO
+;;; also gets the content of the digital ports B and D depending on
+;;; the COMMAND flag
+ep8_ops:
+       mov     r0,#CMD_FLAG
+       mov     a,@r0
 
-       mov     r0,#CHANNELLIST ; points to the channellist
+       mov     dptr,#ep8_jmp   ; jump table for the different functions
+       rl      a               ; multiply by 2: sizeof sjmp
+       jmp     @a+dptr         ; jump to the jump table
+       ;; jump table, corresponds to the command bytes defined
+       ;; in usbdux.c
+ep8_jmp:
+       sjmp    ep8_err         ; a=0, err
+       sjmp    ep8_err         ; a=1, err
+       sjmp    ep8_err         ; a=2, err
+       sjmp    ep8_dio         ; a=3, digital read
+       sjmp    ep8_sglchannel  ; a=4, analog A/D
+       sjmp    ep8_readctr     ; a=5, read counter
+       sjmp    ep8_err         ; a=6, write counter
+
+       ;; reads all counters
+ep8_readctr:
+       mov     r0,#CTR0        ; points to counter0
+       mov     dptr,#0fc00h    ; ep8 fifo buffer
+       mov     r1,#8           ; transfer 4 16bit counters
+ep8_ctrlp:
+       mov     a,@r0           ; get the counter
+       movx    @dptr,a         ; save in the fifo buffer
+       inc     r0              ; inc pointer to the counters
+       inc     dptr            ; inc pointer to the fifo buffer
+       djnz    r1,ep8_ctrlp    ; loop until ready
+       
+       sjmp    ep8_send        ; send the data
+       
+       ;; read one A/D channel
+ep8_sglchannel:                
+       mov     r0,#SGLCHANNEL  ; points to the channel
        mov     a,@r0           ; Ch0
        
        lcall   readAD          ; start the conversion
@@ -714,6 +894,7 @@ ep8_adc:
 
        sjmp    ep8_send        ; send the data
 
+       ;; read the digital lines
 ep8_dio:       
        mov     DPTR,#0fc00h    ; store the contents of port B
        mov     a,IOB           ; in the next
@@ -726,27 +907,14 @@ ep8_dio:
 ep8_send:      
        mov     DPTR,#EP8BCH    ; byte count H
        mov     a,#0            ; is zero
-       movx    @DPTR,a
+       lcall   syncdelaywr
        
        mov     DPTR,#EP8BCL    ; byte count L
        mov     a,#10H          ; 16 bytes
-       movx    @DPTR,a         ; send the data over to the host
-       ret
-
+       lcall   syncdelaywr     ; send the data over to the host
 
-       
-;;; arms EP8 with one byte. This signals the Linux driver that
-;;; the EP has been armed only with a dummy byte to make the
-;;; IRQ work. The byte is not processed by the driver.
-ep8_arm:       
-       mov     DPTR,#EP8BCH    ; byte count H
-       mov     a,#0            ; is zero
-       movx    @DPTR,a
-       
-       mov     DPTR,#EP8BCL    ; byte count L
-       mov     a,#1            ; 1 byte
-       movx    @DPTR,a
-       ret     
+ep8_err:       
+       ret
 
 
 
@@ -770,7 +938,7 @@ ep8_isr:
        push    06h             ; R6
        push    07h             ; R7
                
-       lcall   ep8_adc
+       lcall   ep8_ops
        
        ;; clear INT2
        mov     a,EXIF          ; FIRST clear the USB (INT2) interrupt request
@@ -807,6 +975,16 @@ syncdelay:
        nop
        nop
        nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       ret
+
+syncdelaywr:
+       movx    @dptr,a
+       lcall   syncdelay
        ret
 
 
index bb3da3e731070f9b717bfa659bb86fcc4a676505..366bff43dbb7473f883d8ba58cd8f9d4be3a88df 100644 (file)
@@ -1,66 +1,80 @@
 :030000000201A258
+:03000B000202F8F6
 :03004300020100B7
-:1001000002017F000202EF0002017F0002017F0076
+:1001000002017F000203390002017F0002017F002B
 :1001100002017F0002017F0002017F0002017F00D7
 :1001200002017F0002017F0002017F0002017F00C7
-:1001300002017F0002036C0002017F0002049900AB
+:1001300002017F000203E40002017F0002055A0071
 :1001400002017F0002017F0002017F0002017F00A7
 :1001500002017F0002017F0002017F0002017F0097
 :1001600002017F0002017F0002017F0002017F0087
 :1001700002017F0002017F0002017F0002017FC0B7
 :1001800086C082C083C084C085C0E0C0D0E591C273
 :10019000E4F591D0D0D0E0D085D084D083D082D087
-:1001A000863290E6007410F01204E590E668740858
-:1001B000F01204E51201C3120288000000000000E2
-:1001C0000080F775B22775802222547C4481C28159
-:1001D0007A0830E704D2828002C282D280C28023B1
-:1001E000DAF0C2827A05D280C280DAFA7C007A0420
-:1001F0007D08D280C280E58030E403EC4DFCED0345
-:10020000FDDAEF7B007A087D80D280C280E5803005
-:10021000E403EB4DFBED03FDDAEFD28122759AF892
-:10022000759B0075AF077880E61201CAEB90E67BFC
-:10023000F0ECF008E61201CAEB90E67BF0ECF00877
-:10024000E61201CAEB90E67BF0ECF008E61201CA78
-:10025000EB90E67BF0ECF008E61201CAEB90E67B4F
-:10026000F0ECF008E61201CAEB90E67BF0ECF00847
-:10027000E61201CAEB90E67BF0ECF008E61201CA48
-:10028000EB90E67BF0ECF02290E604740FF0740043
-:10029000F090E6127492F090E6187400F090E691F7
-:1002A0007480F01204E5F01204E5F01204E590E623
-:1002B0001374A0F090E6197400F090E6957480F045
-:1002C0001204E5F01204E590E61474D2F090E615FD
-:1002D00074E0F090E65E74A0F090E65F74A0F09099
-:1002E000E65C7402F075E80175A88012048C22C0E7
-:1002F00086C082C083C084C085C0E0C0D0C000C0BA
-:1003000001C002C003C004C005C006C007E5AA546E
-:1003100020701512021D90E6987400F01204E5900A
-:10032000E6997410F01204E5E5AA5401701390F0F8
-:100330000012040B90E6917480F01204E5F01204B0
-:10034000E5E591C2E4F59190E65D7402F0D007D046
-:1003500006D005D004D003D002D001D000D0D0D038
-:10036000E0D085D084D083D082D08632C086C0824F
-:10037000C083C084C085C0E0C0D0C000C001C0023E
-:10038000C003C004C005C006C00790F400E090039D
-:1003900093237380068017801D802378807A0890CD
-:1003A000F401E0F6A308DAFAE47890F6802190F4FC
-:1003B0000112040B801990F401E0F5B3801190F460
-:1003C00001E0F5B3A3E0F59074FF7890F68000901B
-:1003D000E6957480F01204E5F01204E5F01204E5ED
-:1003E000E591C2E4F59190E65F7420F0D007D00665
-:1003F000D005D004D003D002D001D000D0D0D0E0BE
-:10040000D085D084D083D082D08632E0A3F8E0FBC0
-:10041000A3E0FCA3E0A312041CD8F32254C0443090
-:100420004CC2857A0830E704D2828002C282D28030
-:10043000C28023DAF0EB7A0830E704D2828002C26D
-:1004400082D280C28023DAF0D2852212021D90E689
-:10045000987400F01204E590E6997410F01204E527
-:10046000227890E670107880E61201CA90FC00EBCA
-:10047000F0A3ECF0800990FC00E590F0A3E4F0908C
-:10048000E69C7400F090E69D7410F02290E69C7457
-:1004900000F090E69D7401F022C086C082C083C047
-:1004A00084C085C0E0C0D0C000C001C002C003C08D
-:1004B00004C005C006C007120461E591C2E4F591CD
-:1004C00090E65F7480F0D007D006D005D004D0034A
-:1004D000D002D001D000D0D0D0E0D085D084D0835D
-:0A04E000D082D08632000000002216
+:1001A000863290E60074101205B090E60B740312CC
+:1001B00005B075B80075F8FF90E66874081205B0D0
+:1001C0001201D212025A1201D900000000000000F0
+:1001D00080F775B22775802222758E01758A107599
+:1001E0008C0075A882758900D28C22547C4481C20F
+:1001F000817A0830E704D2828002C282D280C28033
+:1002000023DAF0C2827A05D280C280DAFA7C007AE0
+:10021000047D08D280C280E58030E403EC4DFCED23
+:1002200003FDDAEF7B007A087D80D280C280E58012
+:1002300030E403EB4DFBED03FDDAEFD28122759A3A
+:10024000F8759B0075AF077880E6F990E67B08E6C5
+:100250001201EBEBF0ECF0D9F52290E6047480F09B
+:100260007402F07404F07406F07408F07400F090F6
+:10027000E6127492F090E6187400F090E691740023
+:10028000F01205A6F01205A6F01205A690E613746A
+:10029000A0F090E6197400F090E6957400F0120555
+:1002A000A6F01205A690E61474D2F090E61574E05C
+:1002B000F090E65E74A0F090E65F74A0F090E65CCB
+:1002C0007402F075E80175A88022E590FD5B600678
+:1002D000E4F70CF7801FE66D5D5C6019ED5A700C59
+:1002E000E714F7B4FF0F09E714F78009E704F77084
+:1002F0000409E704F7EDF622C086C0E0C0D0C000D4
+:10030000C001C002C003C004C005789879A0740180
+:10031000FC23FA23FB1202CA080909EB2323FC235E
+:10032000FA23FB1202CAD005D004D003D002D001B8
+:10033000D000D0D0D0E0D08632C086C082C083C08A
+:1003400084C085C0E0C0D0C000C001C002C003C0EE
+:1003500004C005C006C007E5AA5420701312023E6F
+:1003600090E69874001205B090E69974101205B0EA
+:10037000E5AA5401701190F0001204B790E6917450
+:10038000001205B01205B0E591C2E4F59190E65D6A
+:100390007402F0D007D006D005D004D003D002D02C
+:1003A00001D000D0D0D0E0D085D084D083D082D00E
+:1003B000863290E60474801205B090E60474081248
+:1003C00005B090E60474001205B02290E604748033
+:1003D0001205B090E60474061205B090E6047400AD
+:1003E0001205B022C086C082C083C084C085C0E030
+:1003F000C0D0C000C001C002C003C004C005C00618
+:10040000C00790F400E07890F690040E23738039D2
+:10041000804C805280588022800280081203B212E1
+:10042000050B805A90F40178A0E06005F90808D91E
+:10043000FCA3E0F608A3E0F68044789190F401E094
+:10044000F61203B212050B803578807A0990F40118
+:10045000E0F6A308DAFA1203CB1204F7802090F436
+:10046000011204B7801890F401E0F5B3801090F405
+:1004700001E0F5B3A3E0F5901203B212050B90E68C
+:100480009574001205B01205B01205B0E591C2E4F2
+:10049000F59190E65F7420F0D007D006D005D00427
+:1004A000D003D002D001D000D0D0D0E0D085D0840D
+:1004B000D083D082D08632E0A3F8E0FBA3E0FCA397
+:1004C000E0A31204C8D8F32254C044304CC2857A49
+:1004D0000830E704D2828002C282D280C28023DA4E
+:1004E000F0EB7A0830E704D2828002C282D280C266
+:1004F0008023DAF0D2852212023E90E69874001230
+:1005000005B090E69974101205B0227890E6900537
+:1005100013237380448042804080258013800280B2
+:100520003878A090FC007908E6F008A3D9FA801981
+:100530007891E61201EB90FC00EBF0A3ECF080095F
+:1005400090FC00E590F0A3E4F090E69C74001205A6
+:10055000B090E69D74101205B022C086C082C083A0
+:10056000C084C085C0E0C0D0C000C001C002C003CC
+:10057000C004C005C006C00712050BE591C2E4F532
+:100580009190E65F7480F0D007D006D005D004D0FB
+:1005900003D002D001D000D0D0D0E0D085D084D01C
+:1005A00083D082D0863200000000000000000022CC
+:0505B000F01205A62277
 :00000001FF