;---------------------------------------------------------
; FIR.ASM
; Keith Larson
; TMS320 DSP Applications
; (C) Copyright 1995,1996
; Texas Instruments Incorporated
;
; This is unsupported freeware with no implied warranties or
; liabilities.  See the disclaimer document for details
;
; The FIR filter code used in this example is taken
; from the TMS320C3x Users Guide.  The AIC setup and
; control is designed to work with the TMS320C31 DSK
;
; This example can either be loaded and run from the debugger
; or by directly loading and running from DSK3LOAD
;---------------------------------------------------------
; Define constants used by program    ;
TA        .set     8                  ; AIC timing register values
TB	  .set	   16		      ;
RA        .set     8                  ;
RB	  .set	   16		      ;
GIE       .set     0x2000             ; This bit in ST turns on interrupts
          .include "C3XMMRS.ASM"      ;
          .start   "AICTEST",0x809820 ; Start assembling here
          .sect    "AICTEST"          ;
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; 32 bit float data buffer of incoming data from the AIC
; The location in memory must be on a 2^N boundary and the
; size of the coefficeint table must be the same as the data
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ADC_recv     .float    0.0	      ;
	     .float    0.0	      ;
	     .float    0.0	      ;
	     .float    0.0	      ;
	     .float    0.0	      ;
	     .float    0.0	      ;
	     .float    0.0	      ;
	     .float    0.0	      ;
	     .float    0.0	      ;
	     .float    0.0	      ;
	     .float    0.0	      ;
	     .float    0.0	      ;
	     .float    0.0	      ;
	     .float    0.0	      ;
	     .float    0.0	      ;
	     .float    0.0	      ;
;- - - - - - - - - - - - - - - - - - - - - - - - -
; FIR filter coefficients
;- - - - - - - - - - - - - - - - - - - - - - - - -
FIR_coef     .float    1.0	      ;  FIR filter coefficients
	     .float    0.0	      ;
	     .float    0.0	      ;
	     .float    0.0	      ;
	     .float    0.0	      ; As is, these coefficients will create
	     .float    0.0	      ; a comb filter at   Hz.	By inspection
	     .float    0.0	      ; all taps are zero except for the 0th
	     .float    0.0	      ; and 15th that are set to 1 and -1
	     .float    0.0	      ; respectively.  Therefor a cancellation
	     .float    0.0	      ; will occur for any signal which is
	     .float    0.0	      ; 180' out of phase when delayed by
	     .float    0.0	      ; 15 samples.  The Z transform is...
	     .float    0.0	      ;
	     .float    0.0	      ;
	     .float    0.0	      ; 	-15
	     .float   -1.0	      ; H(z)=1-z
END_coef
;- - - - - - - - - - - - - - - - - - -
BufSz	     .set      END_coef - FIR_coef
;- - - - - - - - - - - - - - - - - - -
SIZE         .word    BufSz           ; Size of filter
ADC_first    .word    ADC_recv
ADC_end      .word    FIR_coef
ADC_last     .word    ADC_recv
FIR_coefx    .word    FIR_coef
;------------------------------------
; Define some constant storage data
;------------------------------------
A_REG        .word  (TA<<9)+(RA<<2)+0 ; A registers
B_REG        .word  (TB<<9)+(RB<<2)+2 ; B registers
C_REG	     .word  00000011b	      ; control
S0_gctrl_val .word  0x0E970300        ; Serial port control register values
S0_xctrl_val .word  0x00000111        ;
S0_rctrl_val .word  0x00000111        ;
;****************************************************
; Begin main code loop here
;****************************************************
main      or    GIE,ST          ; Turn on INTS
          ldi   0xF4,IE         ; Enable XINT/RINT/INT2
          b     main            ; Do it again!
;-------------------------------
DAC2      push  ST              ; DAC Interrupt service routine
          push  R0              ;
          pushf R0              ;
          push  R2              ;
          pushf R2              ;
          push  AR0             ;
          push  AR1             ;
          ldi   @ADC_last,AR1   ;
          ldi   @FIR_coefx,AR0  ;
          ldi   @SIZE,BK

FIR       mpyf3 *AR0++,*AR1++(1)%,R0
          ldf   0.0,R2
          ldi   @SIZE,RC
          subi  2,RC
          rptb  FIR2
          mpyf3 *AR0++,*AR1++(1)%,R0
FIR2  ||  addf3 R0,R2,R2
          addf  R2,R0

          fix   R0,R0
          andn  3,R0            ;
          sti   R0,@S0_xdata    ; Output the new DAC value
          pop   AR1             ;
          pop   AR0             ;
          popf  R2              ;
          pop   R2              ;
          popf  R0              ;
          pop   R0              ;
          pop   ST              ;
          reti                  ;
;-------------------------------
ADC2      push  ST              ;
          push  R3              ;
          pushf R3              ;
          push  AR0             ;
          ldi   @S0_rdata,R3    ;

          lsh   16,R3
          ash   -16,R3

          ldi   @ADC_last,AR0
          float R3,R3
          stf   R3,*AR0++

          cmpi  @ADC_end,AR0
          ldige @ADC_first,AR0
          sti   AR0,@ADC_last

          pop   AR0
          popf  R3              ;
          pop   R3              ;
          pop   ST              ;
          reti                  ;
;*****************************************************;
; The startup stub is used during initialization only ;
; and can be safely overwritten by the stack or data  ;
;*****************************************************;
          .entry   ST_STUB      ; Debugger starts here
ST_STUB   ldp   T0_ctrl         ; Use kernel data page and stack
          ldi   @stack,SP
          ldi   0,R0            ; Halt TIM0 & TIM1
          sti   R0,@T0_ctrl     ;
          sti   R0,@T0_count    ; Set counts to 0
          ldi   1,R0            ; Set periods to 1
          sti   R0,@T0_prd      ;
          ldi   0x2C1,R0        ; Restart both timers
          sti   R0,@T0_ctrl     ;
          ;---------------------
          ldi   @S0_xctrl_val,R0;
          sti   R0,@S0_xctrl    ; transmit control
          ldi   @S0_rctrl_val,R0;
          sti   R0,@S0_rctrl    ; receive control
          ldi   0,R0            ;
          sti   R0,@S0_xdata    ; DXR data value
          ldi   @S0_gctrl_val,R0; Setup serial port
          sti   R0,@S0_gctrl    ; global control
;======================================================;
; This section of code initializes the AIC             ;
;======================================================;
AIC_INIT  LDI   0x10,IE         ; Enable only XINT interrupt
          andn  0x34,IF         ;
          ldi   0,R0            ;
          sti   R0,@S0_xdata    ;
          RPTS  0x040           ;
          LDI   2,IOF           ; XF0=0 resets AIC
          rpts  0x40            ;
          LDI   6,IOF           ; XF0=1 runs AIC
          ;---------------------
          ldi   @C_REG,R0       ; Setup control register
          call  prog_AIC        ;
          ldi   0xfffc  ,R0     ; Program the AIC to be real slow
          call  prog_AIC        ;
          ldi   0xfffc|2,R0     ;
          call  prog_AIC        ;
          ldi   @B_REG,R0       ; Bump up the Fs to final rate
          call  prog_AIC        ; (smallest divisor should be last)
          ldi   @A_REG,R0       ;
          call  prog_AIC        ;
          b     main            ; the DRR before going to the main loop
;-------------------------------
prog_AIC  ldi   @S0_xdata,R1    ; Use original DXR data during 2 ndy
          sti   R1,@S0_xdata    ;
          idle
          ldi   @S0_xdata,R1    ; Use original DXR data during 2 ndy
          or    3,R1            ; Request 2 ndy XMIT
          sti   R1,@S0_xdata    ;
          idle                  ;
          sti   R0,@S0_xdata    ; Send register value
          idle                  ;
          andn  3,R1            ;
          sti   R1,@S0_xdata    ; Leave with original safe value in DXR
          ;---------------------
          ldi   @S0_rdata,R0    ; Fix the receiver underrun by reading
          rets                  ;
stack     .word   $             ; Put stack here
;****************************************************;
; Install the XINT/RINT ISR handler directly into    ;
; the vector RAM location it will be used for        ;
;****************************************************;
          .start   "SP0VECTS",0x809FC5
          .sect    "SP0VECTS"
          B        DAC2         ; XINT0
          B        ADC2         ; RINT0
