;File name: IF.asm
;File name: AIC23int_01.asm
;
;  EECS 452 buffered AIC23 codec support for the C5510DSK
;
;   
;  11Oct2003 .. initial version .. K.Metzger
;  11Apr2004 .. made small/large model independent .. KM
;   8Feb2005 .. move no_isr to its own file .. KM
;  24Nov2005 .. renamed fns, improved buffering .. eric williams
;  20Feb2006 .. documentation .. eric williams
;
;
;  /* IF.asm prototypes */
;  short ifRecvCount();
;  void ifRecv(short *buffer, short count, short stride);
;  void ifRecvSetup(short *buffer, short length);
;  short *ifRecvLinearize(short length);
;  short ifSendCount();
;  void ifSend(short *buffer, short count, short stride);
;  void ifSendSetup(short *buffer, short length);
;

        .c54cm_off                      ;don't want compatible with c54
        .ARMS_on                        ;enable assembler for ARMS=1
        .CPL_on                         ;enable assembler for CPL=1
        .mmregs                         ;enable mem mapped register names
    
        
        .global _startup, _no_isr, _resetv, _c_int00
        .global Mc2R_int, Mc2X_int
        .global _AD_flag, _DA_flag
        .global _ifRecv, _ifRecvCount, _ifSend, _ifSendCount, _ifRecvDiscard, _ifRecvLinearize
        .global _ifRecvSetup, _ifSendSetup
        .global _ftvR, _DDSaccumR, _ftvS, _DDSaccumS
         
        .data
                        
        .bss    Mc2X_buf_adr,2,1,4     ; aligned
        .bss    Mc2X_app_buf_off,1
        .bss    Mc2X_int_buf_off,1
        .bss    Mc2X_buf_size,1
        .bss    Mc2X_counter,1
        .bss    Mc2X_running_flag,1
        
        .bss    Mc2R_buf_adr,2,1,4     ; aligned
        .bss    Mc2R_app_buf_off,1
        .bss    Mc2R_int_buf_off,1
        .bss    Mc2R_buf_size,1
        .bss    Mc2R_counter,1

        .bss    _ftvR,2,1,2
        .bss    _DDSaccumR,2,1,2
        .bss    _ftvS,2,1,2
        .bss    _DDSaccumS,2,1,2

        .text
        
        .asg    0001100000000000b,my_ST0_55
        .asg    0110100100000000b,my_ST1_55
        .asg    1001000000000000b,my_ST2_55
        .asg    0001000000000010b,my_ST3_55 ; ROM access is enabled
        .asg    (0xFFFA00>>1),SINE_TABLE
                 
            
; Setup McBSP channel 2 codec interrupt support 
;
;  for now assumes setup_codec() has been called
;
          
_startup:
            pshboth xar0
            mov     #_resetv >> 8, ac0      ; get int vector address page
            mov     ac0,mmap(ivpd)          ; set up DSP int address
            mov     ac0,mmap(ivph)          ; set up host int address
            amov    #Mc2R_int,xar0          ; set up McB port 2 rcvr addr 
            mov     xar0,dbl(*((_resetv+0x60)/2))
            amov    #Mc2X_int,xar0          ; set up McB port 2 xmtr addr
            mov     xar0,dbl(*((_resetv+0x68)/2))
            or      #0x3000,mmap(ifr0)      ; clear Mc2 interrupt flags
            or      #0x3000,mmap(ier0)      ; enable Mc2TX and Mc2RX interrupts
            mov     #0,port(#0x3003)        ; start Mc transmitter running         
            popboth xar0
            ret  

    
; Support for codec interrupt driven data transfers

Mc2R_int:   
            psh     mmap(st3_55)
            psh     mmap(T0)
            psh     mmap(T1)
            pshboth xar0
            pshboth xar1
            ;pshboth ac0
            mov     #my_ST0_55,mmap(st0_55) ; now configure the machine
            mov     #my_ST1_55,mmap(st1_55)
            mov     #my_ST2_55,mmap(st2_55)
            mov     #my_ST3_55,mmap(st3_55)

        ; run the DDS to get cos and sin values
        
;            mov     dbl(*(#_DDSaccumR)),ac0  ; get DDS phase accumulator
;            add     dbl(*(#_ftvR)),ac0       ; add the frequency tuning value
;            mov     ac0,dbl(*(#_DDSaccumR))  ; and update the accumulator
;            amov    #SINE_TABLE,xar0        ; ac0 now points to sine table
;            mov     hi(ac0<<#-8),mmap(t0)   ; get top 8 bits of phase accumulator
;            and     #0x00FF,t0              ; make sure it is  8-bit value
;            mov     *ar0(t0),ac0            ; fetch sine value
             
         ; end of the DDS support
         
;			amov	#0x300000,xar1
;			mov		#0x03,*ar1
            amov    #Mc2R_buf_adr,xar1      ; get buffer address address
            mov     *ar1(Mc2R_counter-Mc2R_buf_adr),T0      ; get # L&R values in buffer
            mov     *ar1(Mc2R_buf_size-Mc2R_buf_adr),T1     ; get number allowed
            cmp     T0==T1,TC1              ; if equal full
            bcc     R2I_LA,!TC1             ; branch if room
            mov     port(#0x3001),T0        ; clears the receive flag
            b       Mc2R_exit               ; and exits...samples onto the floor
R2I_LA:
            mov     dbl(*ar1), xar0         ; get buffer address
            add     *ar1(Mc2R_int_buf_off-Mc2R_buf_adr),ar0 ; and calculate where to place values
            mov     port(#0x3000),T0        ; get left value
            mov     T0,*ar0                 ; and place into buffer
            ;;;;mpy     T0,ac0
            ;;;;mov     hi(ac0),T0
            mov     port(#0x3001),T0        ; get right value...and clear flag
            ;mov     T0,*ar0                 ; place into buffer
            add     #1,*ar1(Mc2R_counter-Mc2R_buf_adr)      ; increment count of pairs present
            mov     *ar1(Mc2R_int_buf_off-Mc2R_buf_adr),T0  ; now update offset circularly
            add     #1,T0                   ; increment
            cmp     T0==T1,TC1              ; see if needs to be reset to buffer start
            bcc     R2I_LB,!TC1             ; branch if not
            mov     #0,T0                   ; reset to buffer start
R2I_LB:
            mov     T0,*ar1(Mc2R_int_buf_off-Mc2R_buf_adr)  ; and update in memory
Mc2R_exit:         
;			amov	#0x300000,xar1
;			mov		#0xC,*ar1
            ;popboth ac0
            popboth xar1                         
            popboth xar0
            pop     mmap(T1)
            pop     mmap(T0)
            pop     mmap(st3_55)
            nop                             ; 6 nops stops remarks 99 and 100
            nop
            nop
            nop
            nop
            nop
            reti
            

; Get count of samples currently in buffer
; short ifRecvCount(void);
_ifRecvCount:   
            pshboth xar3                    ; use it, save it
            amov    #Mc2R_buf_adr,xar3      ; get in sample buffer address address
            mov     *ar3(Mc2R_counter-Mc2R_buf_adr),T0 ; get count of pairs in buffer
            popboth xar3 
            ret


; Support to fetch codec sample values
; void ifRecv(short *samples, short count, short stride);
_ifRecv:   
            pshboth xar2                    ; use it, save it
            pshboth xar3                    ; use it, save it
            amov    #Mc2R_buf_adr,xar3      ; get in sample buffer address address
Mc2R_wait:            
            mov     *ar3(Mc2R_counter-Mc2R_buf_adr),T2 ; get count of pairs in buffer
            sub     T0,T2
            bcc     Mc2R_wait,T2<#0         ; wait if there aren't any
            mov     dbl(*ar3),xar2          ; set up buffer address
            ;;;;;;;;add     dbl(*ar3),ar2
            sub     #1,T0
            mov     T0,brc0
            mov     *ar3(Mc2R_app_buf_off-Mc2R_buf_adr),T0
            mov     *ar3(Mc2R_buf_size-Mc2R_buf_adr),T2     ; get limiting value
            rptb    RCOPY_LOOP-1
            mov     *ar2(T0),*(ar0+T1)          ; and place in caller's location
;           mov     *ar2,T0                 ; fetch R value
;           mov     T0,*ar1                 ; and place in caller's location
            sub     #1,*ar3(Mc2R_counter-Mc2R_buf_adr)      ; indivisible decrement of count
            add     #1,T0                   ; increment
            cmp     T0==T2,TC1              ; if equal need to reset to 0
            bcc     R2_LA,!TC1              ; branch if not equal
            mov     #0,T0                   ; zero to start of buffer
R2_LA:
            nop
RCOPY_LOOP:
            mov     T0,*ar3(Mc2R_app_buf_off-Mc2R_buf_adr)  ; and update in memory 
            popboth xar3 
            popboth xar2
            ret
            


; short *ifRecvLinearize(short count);
_ifRecvLinearize:   
            pshboth xar2                    ; use it, save it
            pshboth xar3                    ; use it, save it
            amov    #Mc2R_buf_adr,xar3      ; get in sample buffer address address
RL_wait:            
            mov     *ar3(Mc2R_counter-Mc2R_buf_adr),T2 ; get count of pairs in buffer
            sub     T0,T2
            bcc     RL_wait,T2<#0         ; wait if there aren't any
            mov     dbl(*ar3),xar2          ; set up buffer address

            mov     *ar3(Mc2R_buf_size-Mc2R_buf_adr),T1     ; get limiting value
            sub     *ar3(Mc2R_app_buf_off-Mc2R_buf_adr),T1
            
            cmp		T1>=T0,TC1
            bcc		RL_END,TC1

			sub		T1,T0

            mov     *ar3(Mc2R_buf_size-Mc2R_buf_adr),T1     ; get limiting value
            MOV		dbl(*ar3),xar2
            MOV		xar2,xar3
            add		T1,ar2

            sub		#1,T0
            MOV		T0,BRC0
            RPTB	RL_END-1
			MOV		*ar3+,*ar2+            
RL_END:
            amov    #Mc2R_buf_adr,xar3      ; get in sample buffer address address
            amov    #Mc2R_buf_adr,xar0
            mov		dbl(*ar0),xar0
            add		*ar3(Mc2R_app_buf_off-Mc2R_buf_adr),ar0
            popboth xar3 
            popboth xar2
            ret

            
; ifRecvSetup(*buffer, size);    
_ifRecvSetup:
            amov    #Mc2R_buf_adr,xar1
            mov     xar0,dbl(*ar1)                         ; get the A/D in buffer address address
            mov     T0,*ar1(Mc2R_buf_size-Mc2R_buf_adr)    ; get the L&R pair count
            mov     #0,*ar1(Mc2R_app_buf_off-Mc2R_buf_adr) ; initialize application level buffer offset
            mov     #0,*ar1(Mc2R_int_buf_off-Mc2R_buf_adr) ; initialize interrupt level buffer offset
            mov     #0,*ar1(Mc2R_counter-Mc2R_buf_adr)     ; nothing present yet            
            ret
            

; Support to fetch codec sample values
; void ifRecvDiscard(short count);
_ifRecvDiscard:   
            pshboth xar2                    ; use it, save it
            pshboth xar3                    ; use it, save it
            amov    #Mc2R_buf_adr,xar3      ; get in sample buffer address address
IFRD_WAIT:            
            mov     *ar3(Mc2R_counter-Mc2R_buf_adr),T2 ; get count of pairs in buffer
            sub     T0,T2
            bcc     IFRD_WAIT,T2<#0         ; wait if there aren't any
            mov     dbl(*ar3),xar2          ; set up buffer address
            mov     *ar3(Mc2R_app_buf_off-Mc2R_buf_adr),T1  ; now update offset circularly
            add     T1,T0                   ; increment
            mov     *ar3(Mc2R_buf_size-Mc2R_buf_adr),T2     ; get limiting value
            cmp     T1>=T2,TC1              ; if equal need to reset to 0
            bcc     IFRD_NOP,!TC1           ; branch if not equal
            sub		T2,T1
IFRD_NOP:
            mov     T1,*ar3(Mc2R_app_buf_off-Mc2R_buf_adr)  ; and update in memory 
            mov		*ar3(Mc2R_counter-Mc2R_buf_adr),T1
            sub		T0,T1
            mov     T0,*ar3(Mc2R_counter-Mc2R_buf_adr)      ; indivisible decrement of count

            popboth xar3 
            popboth xar2
            ret
            
            

;---------------------------------------------------------------------------------------
;
;   Support to send L&R sample values to the AIC23 codec
            
Mc2X_int:   
            psh     mmap(st3_55)
            psh     mmap(T0)
            psh     mmap(T1)
            pshboth xar0
            pshboth xar1
            ;pshboth ac0
            mov     #my_ST0_55,mmap(st0_55) ; now configure the machine
            mov     #my_ST1_55,mmap(st1_55)
            mov     #my_ST2_55,mmap(st2_55)
            mov     #my_ST3_55,mmap(st3_55)

        ; run the DDS to get cos and sin values
        
            ;mov     dbl(*(#_DDSaccumS)),ac0  ; get DDS phase accumulator
            ;add     dbl(*(#_ftvS)),ac0       ; add the frequency tuning value
            ;mov     ac0,dbl(*(#_DDSaccumS))  ; and update the accumulator
            ;amov    #SINE_TABLE,xar0        ; ac0 now points to sine table
            ;mov     hi(ac0<<#-8),mmap(t0)   ; get top 8 bits of phase accumulator
            ;and     #0x00FF,t0              ; make sure it is  8-bit value
            ;mov     *ar0(t0),ac0            ; fetch sine value
             
         ; end of the DDS support

            amov    #Mc2X_buf_adr,xar1      ; get TX buffer address address
            mov     dbl(*ar1),xar0          ; get TX buffer address
            mov     *ar1(Mc2X_counter-Mc2X_buf_adr),T0  ; get count of pairs pesent in buffer
            bcc     X2I_LA,T0==0            ; if none nothing to do
            sub     #1,*ar1(Mc2X_counter-Mc2X_buf_adr) ; we will send a LR pair reducing the count
            add     *ar1(Mc2X_int_buf_off-Mc2X_buf_adr),ar0 ; and add in offset
            mov     *ar0,T0                 ; get L value from buffer
            ;mpy     T0,ac0
            ;mov     hi(ac0),T0
            mov     T0,port(#0x3002)        ; and send to L in TX
            mov     #0,port(#0x3003)        ; and send to R in TX and clear flag
            mov     #1,*ar1(Mc2X_running_flag-Mc2X_buf_adr) ; note we expecting an interrupt
            mov     *ar1(Mc2X_int_buf_off-Mc2X_buf_adr),T0  ; now need to up interrupt buffer offset
            add     #1,T0                   ; circularly
            mov     *ar1(Mc2X_buf_size-Mc2X_buf_adr),T1     ; compare offset with buffer size
            cmp     T0==T1,TC1              ; if equal need to reset to 0
            bcc     X2I_LB,!TC1             ; branch if not needed to reset to 0
            mov     #0,T0                   ; get the zero
X2I_LB:     
            mov     T0,*ar1(Mc2X_int_buf_off-Mc2X_buf_adr)  ; and update the value in memory
            b       X2I_exit                ; all done so exit
X2I_LA:     
            mov     #0,*ar1(Mc2X_running_flag-Mc2X_buf_adr) ; note we are not expecting an interrupt                    
            mov     #0,port(#0x3002)        ; 
            mov     #0,port(#0x3003)        ; 
X2I_exit:           
            ;popboth ac0
            popboth xar1
            popboth xar0
            pop     mmap(T1)
            pop     mmap(T0)
            pop     mmap(st3_55)
            nop                             ; 6 nops stop remarks 99 and 100
            nop
            nop
            nop
            nop
            nop
            reti
            

; Get count of unused sample spots currently in buffer
; short ifSendCount(void);
_ifSendCount:   
            pshboth xar3                    ; use it, save it
            amov    #Mc2X_buf_adr,xar3      ; get in sample buffer address address
            mov     *ar3(Mc2X_buf_size-Mc2X_buf_adr),T0 ; number of spaces available
            sub     *ar3(Mc2X_counter-Mc2X_buf_adr),T0  ; number values present
            popboth xar3 
            ret

; Application level function to send samples to DAC
; void ifSend(short *samples, short count, short stride);
_ifSend:  
XL2_LC:         
            amov    #Mc2X_buf_adr,xar1      ; point to buffer address address
            mov     *ar1(Mc2X_buf_size-Mc2X_buf_adr),T2 ; number of spaces available
            sub     *ar1(Mc2X_counter-Mc2X_buf_adr),T2  ; number values present
            cmp     T2<=T0,TC1              ; see if they are equal
            bcc     XL2_LC,TC1              ; wait if no room
            mov     dbl(*ar1),xar2          ; get buffer address
            ;;;;;add     *ar1(Mc2X_app_buf_off-Mc2X_buf_adr),ar2
            psh     T0
            sub     #1,T0
            mov     T0,brc0
            mov     *ar1(Mc2X_buf_size-Mc2X_buf_adr),T2 ; number of spaces available
            mov     *ar1(Mc2X_app_buf_off-Mc2X_buf_adr),T0
            ;;;;;add     #1,T0                   ; increment
            rptb    SCOPY_LOOP-1
            mov     *(ar0+T1),*ar2(T0)      ; store left value into buffer
            add     #1,T0                   ; increment
            cmp     T0==T2,TC1              ; may need to reset
            bcc     X2_LB,!TC1              ; not yet
            mov     #0,T0                   ; put back to buffer start
X2_LB
            nop
SCOPY_LOOP:
            bset    intm                    ; disable interrupts
            mov     T0,*ar1(Mc2X_app_buf_off-Mc2X_buf_adr) ; update the putting offset             
            pop     T0
            mov		*ar1(Mc2X_counter-Mc2X_buf_adr),T1
            add		T0,T1
            mov     T1,*ar1(Mc2X_counter-Mc2X_buf_adr) ; increment count
            mov     *ar1(Mc2X_running_flag-Mc2X_buf_adr),T0
            bcc     X2_LA,T0!=0             ; branch if xmtr running
            intr    #0xD                    ; trigger the interrupt if not
X2_LA:      
            bclr    intm                    ; reenable interrupts
X2_exit:            
            ret
                        
    
; ifSendSetup(*buffer, size);    
    
_ifSendSetup:
            amov    #Mc2X_buf_adr,xar1                      ; point to buffer address address
            mov     xar0,dbl(*ar1)                          ; save address of L&R output buffer
            mov     T0,*ar1(Mc2X_buf_size-Mc2X_buf_adr)     ; save number of L&R pairs
            mov     #0,*ar1(Mc2X_app_buf_off-Mc2X_buf_adr)  ; initialize application level offset value
            mov     #0,*ar1(Mc2X_int_buf_off-Mc2X_buf_adr)  ; initialize interrupt level offset value
            mov     #0,*ar1(Mc2X_counter-Mc2X_buf_adr)      ; nothing in the buffer yet
            mov     #0,*ar1(Mc2X_running_flag-Mc2X_buf_adr) ; and the TX is not going to interrupt us yet
            ret
