
;*****************************************************************************
;*                           *** FFT ***                                     *
;*                                                                           *
;*  Dieses Romeo-Programm fllt den Speicherbereich X,Y:InpDt mit N*2        *
;*  reellen Eingangssampels und berechnet danach die FFT des Blocks.         *
;*  Die verschachtelten Ergebniswerte liegen dann in X,Y:OutDt.              *
;*  Danach werden die Werte entschachtelt und gleichzeitig der Betrag        *
;*  gebildet, der dann in X:BtrDt geschrieben wird. Auf eine Wurzelbildung   *
;*  wird verzichtet. x:BtrDt wird nun durch das Host-Interface zum PC        *
;*  bertragen. Hier muá ein Auswerteprogramm N Werte entgegennehmen und     *
;*  weiterverarbeiten (z.B. darstellen).                                     *
;*                                                                           *
;*                                                              j.stelkens 94*
;*****************************************************************************

 page 255,24

;******************************* Peripherie-Adressen **************************

IPR	 EQU $FFFF           ; INTERRUPT-PRIORITY-REGISTER
BCR	 EQU $FFFE           ; BUS-CONTROL-REGISTER
CRA	 EQU $FFEC           ; SSI-CONTROL-REGISTER A
CRB	 EQU $FFED           ; SSI-CONTROL-REGISTER B
PCC	 EQU $FFE1           ; PORT_C-CONTROL-REGISTER
PCDDR    EQU $FFE3	     ; PORT_C-DATA-DIRECTION-REGISTER
PCD      EQU $FFE5	     ; PORT_C-DATA-REGISTER
SSISR	 EQU $FFEE           ; SSI-STATUS-REGISTER
SSITX	 EQU $FFEF           ; SSI-TRANSMIT-REGISTER
SSIRX	 EQU $FFEF           ; SSI-RECEIVE-REGISTER
HRX      equ $FFEB           ; Host-Empfangsregister
HTX      equ $FFEB           ; Host-Senderegister
PBC      equ $FFE0
HCR      equ $FFE8           ; Host-Control/Interruptregister
HSR      equ $FFE9           ; Host-Statusregister
SCR      equ $FFF0           ; SSI Controlregister


PERIPORT equ $FFC8           ; Peripherieport, der von Romeo

;******************************* FFT-Konstanten *****************************

pi       equ 3.141592654

N        equ 2048                              ;N=2^ç
                                               ;N = Anzahl Frequenzlinien (output)
Gamma   equ @cvi(@log(@cvf(N))/@log(2.0)+0.5)  ;Gamma=ld(N)
InpDt   equ $4000                              ;X,Y FFT Input-Buffer
OutDt   equ InpDt+N                            ;X,Y FFT Output-Buffer
BtrDt   equ OutDt+N                            ;X   Quadrat der Betragslinien
SCTabl  equ BtrDt+N                            ;X -cos(ã/N*k)
                                               ;Y -sin(ã/N*k)
;***************************** Flags ****************************************

FBLOCK  equ 0                   ; 1= InpDt ist gefllt und darf berechnet werden
                                ; 0= Neue Daten rein
FTOGGEL equ 1                   ; 0= Input-Data in X:InpDt
                                ; 1= Input-Data in Y:InpDt

;****************************** X-Variablen *********************************

 org x:0
FLAGS  	  dc  $0                ; Flag-Register
DATAM     dc  $0                ; Datenmlleimer fr Adda
SFakt     dc  @frc(@pow(2.0,-Gamma))
NULL      dc  $0
InpDtEND  dc  InpDt+N
x0SAVE    dc  $0
a10SAVE   dc  $0
a2SAVE    dc  $0


;****************************** sin/cos-Tabelle *****************************

        org x:SCTabl
k       set 0
        dup N
        dc @frc(-@cos(pi/@cvf(N)*@cvf(k)))
k       set k+1
        endm

        org y:SCTabl
k       set 0
        dup N
        dc  @frc(-@sin(pi/@cvf(N)*@cvf(k)))
k       set k+1
        endm


        org p:$0           ; Assembler auf Null setzen
;****************************************************************************
;*                             Reset-Vektor                                 *
;****************************************************************************

        jmp START
;****************************************************************************
;*                               SSI-Vektor                                 *
;****************************************************************************
         org p:$C
        jsr   <Adda

;****************************************************************************
;*               SSI Receive Data Overflow Exception Interrupt              *
;****************************************************************************
         org p:$E

         jsr  <Adda


         org p:$40


;****************************************************************************
;*               SSI Receive Data  Interrupt                                *
;****************************************************************************


Adda     movep  x:SSIRX,x:DATAM          ; SSI-Daten vom AD-Wandler nach x1
         jset    #3,x:SSISR,Frame1       ; jmp Ä> 1. Frame erkannt
         jmp (r3)


Frame2   move  #<Frame3,r3
ADLlo    movep x:NULL,x:SSITX            ; Bit 17+18 DA = 0
         rti

Frame4
ADRlo    movep x:NULL,x:SSITX            ; Bit 17+18 DA =0
         rti

Frame1
ADLhi    move  #<Frame2,r3
         movep x:NULL,x:SSITX
         jset  #FBLOCK,x:FLAGS,ADLrti    ; Wenn ein Block gerade
                                         ; berechnet wird, dann wars das
         move x0,x:x0SAVE                ; x0 sichern
         move a10,l:a10SAVE              ; a sichern
         move a2,x:a2SAVE

         move x:DATAM,x0                 ; Input in x0
         bchg #FTOGGEL,x:FLAGS           ; Eins ins
         jcs  <ADLinX
         move x0,y:(r2)+                 ; Tpfchen (Y)
         jmp  <ADLPrf
ADLinX   move x0,x:(r2)                  ; Krpfchen (X)
ADLPrf   move x:InpDtEND,x0              ; Ende
         move r2,a
         cmp  x0,a
         jne  <ADLRest
         bset #FBLOCK,x:FLAGS            ; Neuer Block ist OK

ADLRest  move x:x0SAVE,x0
         move l:a10SAVE,a10
         move x:a2SAVE,a2

ADLrti   rti

Frame3   move #<Frame4,r3
ADRhi    movep x:NULL,x:SSITX
         rti




;******************************** FFT ****************************************

FFT	move #N/2,n0
	move #1,n2
	move #N/2,n6
	move #SCTabl,r6
	move #0,m6
	move #InpDt,r0
	move #N-1,m0
	move r0,r4
	move m0,m4
	lua (r0)+n0,r1
	move m0,m1
	move m0,m5
	lua (r1)-,r5


;***************************** 1. Durchlauf **********************************

        move x:SFakt,y0
	move x:(r0),x1  y:(r5),b

	do #(N/2),Durchlf1
        mpy x1,y0,a  x:(r1),x1  b,y:(r5)+
        macr x1,y0,a     a,b
        subl a,b     a,x:(r4)   y:(r0)+,y1
        mpy y1,y0,a  b,x:(r5)   y:(r1)+,y1
        macr y1,y0,a    a,b
        subl a,b        a,y:(r4)+       x:(r0),x1
Durchlf1

;******************************* normaler Durchlauf *************************

	move b,y:(r5)
        move #N/4,n0
        move #2,n2
	do #Gamma-2,Durchlf
	move #InpDt,r0
	move n0,n4
	move r0,r4
	lua (r0)+n0,r1
	move #SCTabl,r6
	lua (r1)-,r5
	move n0,n1
	move n0,n5
	do n2,Gruppe
	move x:(r1),x1  y:(r6),y0
	move x:(r6)+n6,x0
	move x:(r5),a    y:(r0),b

	do n0,Buttfly
	mac x1,y0,b     y:(r1)+,y1
	macr -x0,y1,b   a,x:(r5)+  y:(r0),a
	subl b,a     x:(r0),b   b,y:(r4)
	mac -x1,x0,b x:(r0)+,a  a,y:(r5)
	macr -y1,y0,b   x:(r1),x1
	subl b,a     b,x:(r4)+    y:(r0),b
Buttfly

	move a,x:(r5)+n5   y:(r1)+n1,y1
	move x:(r0)+n0,x1  y:(r4)+n4,y1
Gruppe

	move n0,b
	lsr b           n2,a
	lsl a           b,n0
	move a,n2
Durchlf

;***************************** Letzter Durchlauf *******************************

	move #InpDt,r0
	move #2,n0
	lua (r0)+,r1
	move n0,n1

        move #OutDt,r4
	move #N/4,n4
	move m6,m4

	move #OutDt+N-1,r5
	move n4,n5
	move m4,m5
	move #SCTabl,r6
	move x:(r5),a   y:(r0),b
	move x:(r1),x1  y:(r6),y0


	do #N/2,LDurchlf
	mac x1,y0,b x:(r6)+n6,x0  y:(r1)+n1,y1
	macr -x0,y1,b a,x:(r5)+n5  y:(r0),a
	subl b,a  x:(r0),b      b,y:(r4)
	mac -x1,x0,b  x:(r0)+n0,a  a,y:(r5)
	macr -y1,y0,b x:(r1),x1    y:(r6),y0
        subl b,a        b,x:(r4)+n4       y:(r0),b
LDurchlf
	move a,x:(r5)

        jsr  <StartIn       ; Werte drfen wieder eingelesen werden

; ******************************** Betragsbildung **************************

	move #OutDt+1,r0
	move #OutDt+N-1,r4
	move m0,m4
	move #BtrDt,r1
	move #SCTabl+1,r6
	move m1,m6

        clr a
        move y:(r4),y1
	move x:(r4)-,x1      y:(r0),b

	do #(N-1),betrag
	sub y1,b        a,x:(r1)+      y:(r6),y0
	mac y0,y1,b      x:(r0),a
	add x1,a        x:(r6)+,x0
	mac -x0,x1,b
	mac -x0,y1,a    y:(r0),y1
	mac -y0,x1,a    x:(r0)+,x1
	mac -x0,y1,a
	mac y0,x1,a
	asr a
	mac y0,y1,b     y:(r4),y1
	mac x0,x1,b     a,x0
	asr b
	mpy x0,x0,a     b,x0
	macr x0,x0,a    x:(r4)-,x1      y:(r0),b
betrag
	move a,x:(r1)
	rts

;****************************************************************************
;*               Betrag zum FFT-Programm                                    *
;****************************************************************************

BetrSend  move   #BtrDt,r7
          movep  #16+4,x:HCR          ; HRIE,HTIE,HF3 = 1, HCIE,HF2=0
          do #N,SendLoop
          jclr   #1,x:HSR,*           ; Warten, bis letzter Transfer zuende
          movep  x:(r7)+,x:HTX        ; Werte verschicken
SendLoop  movep  #4,x:HCR             ; Flagge wieder einholen
          rts



;****************************************************************************
;*               Hauptschleife                                              *
;****************************************************************************

HpLoop    jclr #FBLOCK,x:FLAGS,*      ; auf neuen Block warten
          jsr  <FFT                   ; FFT berechnen und neu starten
          jsr  <BetrSend              ; Betrag zum PC senden
          jsr  <Lampe                 ; lustig blinken
          jmp  <HpLoop                ; und nochmal

Lampe    movep   #$1ef,x:PCC
	 movep   #$fff,x:PCDDR
         bchg    #4,x:PCD
         rts

StartIn  move #InpDt,r2              ; Einlesezeiger setzen
         bclr #FTOGGEL,x:FLAGS       ; Mit X gehts los
         bclr #FBLOCK,x:FLAGS        ; Werte drfen wieder eingelesen werden
         rts


;****************************************************************************
;******************* Initialisierung bei Programmstart **********************
;****************************************************************************

START    movep   #$0001,x:BCR           ; 0 Waitstates fr X,Y,P,IO
         ori     #$03,MR                ; Maskiere Interrupts
         andi    #$FF-4,omr             ; Blendet Sinustabelle aus

	 movep   #$4300,x:CRA           ; SSI WORD LENGTH = 16 4-Frames
	 movep   #$3A00,x:CRB           ; SSI = SYNCHRONOUS,ENABLE, RE, TE

	 movep   #$01ef,x:PCC           ; SSI-PORT an, SCI=GENERAL PURPOSE I/O
	 movep   #$fff,x:PCDDR          ; PC0,1,2 CONFIGURED AS AN OutPut

         movep   #$3A00,x:IPR           ; SSI : IPL 2, Host : IPL 1
         movep   #$BA00,x:CRB		; SSI-Interrupts erlauben

         movep   #1,x:PBC               ; Host interface an
         movep   #>4,x:HCR              ; HRIE=0,HTIE=0,HF2,HF3 = 0, HCIE=1

         ; movep   #$1F0000,y:PERIPORT  ; eventuell Julia einstellen

         jsr  <StartIn                  ; Werteeingabe triggern

         andi    #$fc,MR                ; alle Interrupts erlauben
         jmp     <HpLoop                ; in die Hauptprogrammschleife


       end START
