These forums are read only, please use our new forums here.

Main :: ToneCore Development Kit



Delay effect
by mikekulesza on 2012-04-21 07:03:35

Hi,

I'm trying to make a clean digital delay as a starting point for some other effects. To do this, I am trying to set up a circular buffer using modulo addressing. However, in the modulus (ie: m0, m1... m7) can have a max value of 32768, meaning I am limited to about 0.8 s of delay.

Does anyone know how to use the Address Generation Unit (AGU) with a larger modulo or perhaps stacking several modulo buffers or if there is another approach altogether? Any example code too would be great.

Thanks!

Mike

In the 56300 family manual, section 4 is about the Address Generation Unit (AGU) and 4.5.3 explains modulo addressing.



Re: Delay effect
by clangen on 2012-04-24 13:00:50

Hi Mike,

the short answer is: yes, its possible. The long answer: its not that easy. You can't take benefit of the AGU directly since you cant't use the modifier registers for modulo adressing as you said since they are limited to 15-bit word length. I thought about that for a minute and got this simple idea:

1.) Use linear adressing - set the modifier to $xxFFFF

2.) You have to create your own modulo buffer. To do so you have to manage the pointer administration overhead by yourself - the classic approach.

3.) You can use a single pointer (any Rx corresponding to the Mx modifier) and read an old sample before overwriting it by the actual one.

4.) After each read/write procedure, increment the pointer and check if it has reached the end position (delay offset) for your delay buffer depth.

5.) If so reset the pointer to the original address

Here an idea for a code snippet (not tested)

bufstart  equ $1000

delay      equ $FFFF

bufend    equ (bufstart + delay)

     org x;

test     ds 1

     org p:

...

     ; initialization

     move #bufstart,r1

     move #$FFFFFF,m1

...

    ; this goes to loop

...

; get input value to x0

    move x:(r1),x1     ; read sample out of delay buffer

    move x0,x(r1)+    ; write input sample to delay line

; all the following is buffer management overhead - get your modulo addressing by hand.

    move #bufend,x1 ; get buffer end address

    move r1,a            ; get the current delay line address for test

    cmp  x1,a            ; see if pointer has reached the buffer end address - essentially the comparison (cmp) is a subtraction by x1 of a

    brpl   noreset       ; if not, do not reset pointer - check if the result is positiv (pl). If so don't reset the pointer.

                                ; You may also try brnz (branch is not zero) to match the buffer end point more exactly

    move #bufstart,r1 ; if yes, set pointer to #bufstart

noreset

...                              ; more code goes here

Please give feedback if you could solve the problem. A good idea might be to check the code using the simulator. I will do so soon...

Best regards

Christian



Re: Delay effect
by clangen on 2012-04-28 00:50:50

Hi Mike,

now I've checked my 'homebrewn' modulo and removed some bugs. The following code is to be tested by the simulator:

; Assembler directives

bufstart  equ $1000

delay     equ $000F

bufend    equ bufstart+delay

     org p:$0                         ; Look for proper code memory base address on real silicon

; This code goes to initialization

     move #bufstart,r1             ; Here the pointer to the arbitrary length modulo buffer is placed.

                                               ; The restrictive rules for modulo addressing are no longer valid...

     move #$FFFFFF,m1         ; ..since we use the linear addressing mode

; This code goes to main loop

loop

; Get input value to x0 in advance - this code isn't listed here!

    move x:(r1),x1                    ; read sample out of delay buffer

    move x0,x:(r1)+                  ; write new input sample to delay line

; all the following is buffer management overhead - get your modulo addressing by hand.

; Anyway this isn't too much overhead compared to the strong modulo addressing rules! 

; We just check if the pointer r1 has reached the 'modulo' buffer end

; - if so, we just reset it to the original address location

    move #bufend,x1               ; get buffer end address

    move r1,a                          ; get the current delay line address for test if modulo buffer end is reached now

    cmp  x1,a                          ; see if pointer has reached the buffer end address

                                              ; - essentially the comparison (cmp) is a subtraction by x1 of a

    jne  noreset                       ; if not, do not reset pointer - check if the result is not equal (ne).

                                              ; If not so don't reset the pointer by jumping over the next instruction.

    move #bufstart,r1              ; if so, reset pointer to #bufstart

noreset

    jmp    loop

; more code goes here



Re: Delay effect
by mikekulesza on 2012-05-19 16:29:02

Hi Christian,

I just got around to trying this today and this approach works great, thanks. I took Flange 0.95 from Luke Durback as the base code and implemented the manual buffer pointer management. This resulted in a flanger with a really long predelay - long enough to make it distinct like in a delay pedal. The flange effect with the very short oscillating delay is still applied to the repeats. I'll have to post some code once it's cleaned up.

Cheers,

Mike



Re: Delay effect
by mikekulesza on 2012-07-05 19:10:56

                page    132,60
                include "..\Ioequ.inc"
                include "..\vectors4.inc"               
                list
               
;---------------------------------------------------------------------------------------------------
;This is a modification of Luke Durback's Flange 0.95 to extend the parameter "minimum delay",
;set by knob 4 in order to achieve a standard guitar delay effect (A flanger is also a delay
;but with a very short (order of ms) modulating delay time creating a comb filter as a result.
;To make the normal delay, I extend this minimum delay time into the order of seconds.
;The problem was that simply increasing the size of constant "MinDelayLimit" beyond a certain
;point does not work as modulo buffer addressing can have a max value of 32768, limiting delay
;time to about 0.8 s. The solution in this code is circular buffer management that is implemented manually as overhead code.
;Nested three times (read after main delay, read after flange delay, write) between the lines
;"mk buffer management" and "mk end buffer management" is this code. The constants section has also changed to reflect
;the longer delay times and additional buffer allocation.
;The multiple voice loop has been disabled. What occurs is the minimum delay (first read) offers
;the perceptible digital delay, followed by the second short flange delay applied to the repeat
;of the main delay. The flange delay depth is set by knob 5, and its oscillation frequency by knob 1.
;You'll hear what I mean.
;
;Start of Luke's code:
;
;   Flanger 0.95
;       This file is setup to work with the Line 6 / Freescale Tone Core Developer s Kit.
;  This effect is a simple multi-voice flange/chorus.  The code is based on Line 6 s 2 Band Stereo EQ.
;
;
; Knobs
; *1st knob sets the lfo frequency
; *2nd knob sets the depth (how much of the delayed sample is added to the current sample)
; *3rd knob sets the feedback (how much of the processed sample is added into the delay buffer)
; *4th knob sets the minimum delay
; *5th knob sets the delay width
; *6th knob sets the separation between voices
;
; Switch 1 the number of voices: 1, 2, or 3
;
; Switch 2 sets the lfo shape
; *position 0 - sine
; *position 1 - exponential
; *position 2 - linear
;
; Flange 0.95:
; Luke Durback,  March 14, 2009

;
; 2 Band Stereo EQ:   
;   Line 6,  November 30, 2007     
;  Copyright (c) 2008 Line 6 Inc
;  Line 6 Confidential Information


;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
; Constants
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

BufferSize    equ 35000  ; the buffer size, originally 4096
DelayLimit    equ 300   ; the limit on the delay length, originally 300
MinDelayLimit   equ 30000   ; the limit on the delay offst, originally 600
SeperationLimit   equ 600   ; the limit on the seperation between voices, originally 600
          ; make sure that
          ; BufferSize > DelayLimit + MinDelayLimit + 2*SeperationLimit, and then some (increase till it works)
LFOIncMin    equ $0   ;originally $40
LFOIncLimit    equ $2000  ;originally $2000


AccessSRAMWord0   equ $982245 ; 1 0 011 00 0 00100 0 100100 01 01
; DMA Control Register for channel 0
; bit(s)value description
; [23] = DE = 1 DMA Operation disabled (Trigger DMA transfer)
; [22] = DIE = 0 DMA Interrupt disabled
; [21:19] = DTM[2:0] = 011 triggered by DE, DE=0 after done
; [18:17] = DPR[1:0] = 00 priority level 0
; [16] = DCON = 0 Continuous mode disabled
; [15:11] = DRS[4:0] = 00100 Transfer done from channel 0
; [10] = D3D = 0 non 3-d mode
; [9:4] = DAM[5:0] = 100100 no update s/d
; [3:2] = DDS[1:0] = 01 Y memory destination
; [1:0] = DSS[1:0] = 01 Y memory source

AccessSRAMWord1   equ $982A45 ; 1 0 011 00 0 00101 0 100100 01 01
; DMA Control Register for channel 0
; bit(s)value description
; [23] = DE = 1 DMA Operation disabled (Trigger DMA transfer)
; [22] = DIE = 0 DMA Interrupt disabled
; [21:19] = DTM[2:0] = 011 triggered by DE, DE=0 after done
; [18:17] = DPR[1:0] = 00 priority level 0
; [16] = DCON = 0 Continuous mode disabled
; [15:11] = DRS[4:0] = 00101 Transfer done from channel 1
; [10] = D3D = 0 non 3-d mode
; [9:4] = DAM[5:0] = 100100 no update s/d
; [3:2] = DDS[1:0] = 01 Y memory destination
; [1:0] = DSS[1:0] = 01 Y memory source

;**************************************************************************

;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
; Variables
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

        org     x:$000
;...Knob registers expect a value of 0x000000 thru 0x7FFFFF from the microcontroller
Knob_1                  ds  1       ; 00h
Knob_2                  ds  1       ; 01h
Knob_3                  ds  1       ; 02h
Knob_4                  ds  1       ; 03h
Knob_5                  ds  1       ; 04h
Knob_6                  ds  1       ; 05h

;...Switch registers expect a value of 0,1, or 2 from the microcontroller
Switch_1                ds  1       ; 06h
Switch_2                ds  1       ; 07h

;...FootSwitch registers expect a value of 0x000000 or 0x000001 from the microcontroller
FootSwitch_TopLayer     ds  1       ; 08h
FootSwitch_BottomLayer  ds  1       ; 09h

;...LED registers are read by the micro and should be set to 0x000000 or 0x000001  (off and on)
LED_Red                 ds  1       ; 0ah
LED_Green               ds  1       ; 0bh

;...RX and TX registers
LeftRx                  ds  1       ; 0ch   Left received sample
RightRx                 ds  1       ; 0dh   Right received sample
LeftTx                  ds  1       ; 0eh   Left sample to transmit
RightTx                 ds  1       ; 0fh   Right sample to transmit
SHI_StateMachine        ds  1       ; 10h   current state of the serial host interface
HostCommand             ds  1       ; 11h   current SHI command

;...Debug registers
Debug_Write_to_DSP_1    ds  1       ; 12h   recieves data from the ToneCoreGUI application
Debug_Write_to_DSP_2    ds  1       ; 13h   recieves data from the ToneCoreGUI application
Debug_Write_to_DSP_3    ds  1       ; 14h   recieves data from the ToneCoreGUI application
Debug_Write_to_DSP_4    ds  1       ; 15h   recieves data from the ToneCoreGUI application
Debug_Read_from_DSP_1   ds  1       ; 16h   send data to the ToneCoreGUI application
Debug_Read_from_DSP_2   ds  1       ; 17h   send data to the ToneCoreGUI application
Debug_Read_from_DSP_3   ds  1       ; 18h   send data to the ToneCoreGUI application
Debug_Read_from_DSP_4   ds  1       ; 19h   send data to the ToneCoreGUI application

;...FootLatch says whether the simulated latch is up or down
;...FootLatchMem is compared to the current state of FootSwitch_BottomLayer to decide
; whether the simulated latch is up or down
FootLatch               ds  1       ; 1Ah
FootLatchMem            ds  1       ; 1Bh

LeftInput               ds  1       ; 00h
LeftOutput    ds 1

Depth     ds 1
LFOPhase    ds 1
LFOInc     ds  1
Delay     ds 1
MinDelay    ds 1
Feedback    ds 1
MaxDelayLength   ds 1

Voices     ds 1
VoiceSeperation   ds 1

Temp     ds 16

        org     y:$000
;...Chan0 is for reading from SRAM
Chan0IO     ds 16  ; 04h
;...Chan1 is for writing to SRAM
Chan1IO     ds 16  ; 14h

  org  y:$200000
Buffer     dsm (BufferSize)

;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
; Macros
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

HandleFootSwitch MACRO
;Handles the foot switch, turns on/off bypass if need be
;Use Bottom layer of FootSwitch to turn on/off analog bypass
;
; Uses b, x0, and x1
;
    ;   take the momentary footswitch signal (pulse) and generate a latched (step) control signal
        move    x:FootSwitch_BottomLayer,b      ; load unmodified footswitch input
        move    x:FootSwitch_BottomLayer,x1     ; load unmodified footswitch input
        not     b       x:FootLatchMem,x0       ; not a  (also, load the previous momentary signal into x0)
        and     x0,b    x1,x:FootLatchMem       ; x0 & a (also, store current momentary signal for next iteration)
        move    x:FootLatch,x0                  ; load previous latched value
        eor     x0,b                            ; generate current latched (step) control signal
        move    b1,x:FootLatch                  ; store latched footswitch signal created from momentary footswitch
       
        move    x:FootLatch,b           ; load latching footswitch signal
        jclr    #0,b,_ANALOG_BYPASS      ; bit clear = bypass
        movep   #>$000008,x:M_PDRB      ; bit 3 on  = FX_ON  Also Pre-Emph, Post-DeEmph Off, Direct Off
        bset    #0,x:LED_Green          ; turn led on to indicate effect on
        jmp     _END_ANALOG_BYPASS
_ANALOG_BYPASS:           
        movep   #>$000004,x:M_PDRB      ; bit 2 on  = DIRECT_ON, All else off
        bclr    #0,x:LED_Green          ; turn led off to indicate effect off
_END_ANALOG_BYPASS:
  ENDM

TransferYData0 MACRO SRC,DEST
; Transfer data y:(SRC) into y:(DEST) using Chan0
;;;Primarily used for reading from SRAM
  move SRC,x:M_DSR0    ; Set chan1 source
     move DEST,x:M_DDR0    ; Set chan1 dest
     jclr #0,x:M_DSTR,*    ; Wait until previous transfers are finished
  movep #AccessSRAMWord0,x:M_DCR0 ; Initiate transfer for next sample
  ENDM

WriteToSRAM  MACRO DATA,DEST
; Store data in SRAM at y:(DEST) using Chan1
; DATA - register where sample is stored (a,b,x,y,a1,a0,b1,b0,x1,x0,y1,y0)
; DEST - r[0-5] where to store sample
;----------------
;-Uses first word of Chan1IO
;----------------
     move DATA,y:Chan1IO    ; Put data in Chan0IO
     movep DEST,x:M_DDR1    ; Set chan0 dest
     jclr  #1,x:M_DSTR,*    ; Wait until previous writes are finished
  movep #AccessSRAMWord1,x:M_DCR1 ; Initiate write
  ENDM
 
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
; Code Start
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

        org     p:$4E
START
        ori     #$03,mr                 ; mask interrupts
        movep   #$2D0063,X:M_PCTL       ; Set PLL Control Register
                                        ; Fosc = 100 MHz = (100)(3 MHz)/3
       
        bset    #14,omr                 ; allow address attributes line to function independently
       
        movep   #>$000040,x:M_SAICR    ; 4x4 Synchronous mode (use TX frame and bit clks)

        movep   #$FCC304,x:M_TCCR                          
                ;THCKD -1- HCKT is an output                          (bit  23)
                ;TFSD  -1- FST is output                              (bit  22)
                ;TCKD  -1- internal clock source drives SCKT          (bit  21)
                ;THCKP -1- Transmitter High Freq Clock Polarity       (bit  20)
                ;TFSP  -1- negative FST polarity                      (bit  19)
                ;TCKP  -1- data & FST clocked out on falling edge     (bit  18)
                ;TFP   -3- TFP3..0 = Divide by 4                      (bits 17:14)
                ;TDC   -1- 2 words per frame                          (bits 13:9)
                ;TPSR  -1- Bypass Fixed /8 Prescaler                  (bit  8)
                ;TPM   -4- TPM7-0 = Divide by 5                       (bits 7:0)

         movep  #$FCC304,x:M_RCCR                         
                ;RHCKD -1- HCKR is an output  Flag 2                  (bit  23)
                ;RFSD  -1- FSR is output      Flag 1                  (bit  22)
                ;RCKD  -1- SCKR is output     Flag 0                  (bit  21)
                ;RHCKP -1- Pos. High Freq Clock Polarity              (bit  20)
                ;RFSP  -1- negative FSR polarity                      (bit  19)
                ;RCKP  -1- data & FSR clocked in on falling edge      (bit  18)
                ;RFP   -3- RFP3..0 = Divide by 4                      (bits 17:14)
                ;RDC   -1- 2 words per frame                          (bit  13:9)
                ;RPSR  -1- Bypass Fixed /8 Prescaler                  (bit  8)
                ;RPM   -4- RPM7-0 = Divide by 5                       (bits 7:0)

        movep   #$707d00,x:M_RCR                           
                ;RE    --- RX0, RX1, RX2, RX3 disabled                (bit3:0=0000)
                ;RSHFD -0- MSB shifted first                          (bit6=0)
                ;RWA   -0- word left-aligned                          (bit7=0)
                ;RMOD  -1- network mode                               (bit9:8=01)
                ;RSWS  1F- 32-bit slot length, 24-bit word length     (bit14:10=11111)
                ;RFSL  -0- word-length frame sync                     (bit15=0)
                ;RFSR  -0- frame sync occurs 1 clock cycle earlier    (bit16=1)
                ;          reserved                                   (bit18:17=00)
                ;RPR   ?-0- transmit normally, not personal reset      (bit19=0)
                ;          RIE, REDIE, REIE enabled                  (bit23:20=0111)
                ;RLIE  --- bit23 RLIE
                ;RIE   --- bit22 RIE
                ;REDIE --- bit21 REDIE
                ;REIE  --- bit20 REIE

        movep   #$027D80,x:M_TCR                           
                ;TE    --- Start w/ TX0-TX5 disabled                  (bit5:0=000000)
                ;TSHFD -0- MSB shifted first                          (bit6=0)
                ;TWA   -1- word left-aligned                          (bit7=0)
                ;TMOD  -1- network mode                               (bit9:8=01)
                ;TSWS  1F- 32-bit slot length, 24-bit word length     (bit14:10=11111)
                ;TFSL  -0- word length frame sync                     (bit15=0)
                ;TFSR  -0- frame sync occurs 1 clock cycle earlier    (bit16=1)
                ;PADC  -1- zero padding enabled                       (bit17=1)
                ;          reserved                                   (bit18)
                ;TRP   ?-0- transmit normally, not personal reset      (bit19=0)
                ;          TLIE, TIE, TEIE disabled                   (bit23:20=0000)
                ;TLIE  --- bit23 TLIE
                ;TIE   --- bit22 TIE
                ;TEDIE --- bit21 TEDIE
                ;TEIE  --- bit20 TEIE

       
        movep   #>$000000,x:M_PDRC      ; Clear Port C data
        movep   #>$000BF8,x:M_PCRC      ; Set appropriate Port C GPIO pins for ESAI .
        movep   #>$000C7E,x:M_PRRC      ; Set pin direction of PORT C
        ;sdo0     sdo1         sdo2         sdo3    sdo4    sdo5        hckt        fst         sckt    hckr            fsr         sckr
        ;ESAI     GPO          GPI          GPI     GPI     ESAI        ESAI        ESAI        ESAI    GPO             GPO         NC
        ;DAC Data Inhibit IRQA Stereo/Mono  A_In    B_In    ADC_Data    256FS_CLK0  FS_CLK  64FS_CLK    Gain Switching  Codec_Reset SS_Module


        movep   #>$000000,x:M_PCRB      ; Set up Port B for output
        movep   #>$00000F,x:M_PRRB      ; Set up Port B for output
        movep   #>$000008,x:M_PDRB      ; bit 0 = In_EMPH
                                        ; bit 1 = OUT_DE_EMPH
                                        ; bit 2 = DIRECT_ON
                                        ; bit 3 = FX_ON

        movep   #>$000003,x:M_RSMA      ; Enable first 2 time slots for receive.
        movep   #>$000000,x:M_RSMB      ;
        movep   #>$000003,x:M_TSMA      ; Enable first 2 time slots for transmit.
        movep   #>$000000,x:M_TSMB     
        movep   #>$000000,x:M_TX0       ; zero out transmitter 0

        ;ENABLE ESAI
        bset    #0,x:M_RCR              ; now enable RX0
        bset    #0,x:M_TCR              ; now enable TX0

;...Setup Expansion Port A for SRAM...
        movep   #$2406B5,x:M_AAR0               
                 ; [23:12] = 0x240 Address used to assert chip select
                 ; [11:8]  = 0110  Number of address bits to compare = 6
                 ; [7]     = 1     Bit Packing Enabled
                 ; [6]     = 0     Address Mux Disabled
                 ; [5]     = 1     Y Space Enabled
                 ; [4]     = 1     X Space Enabled
                 ; [3]     = 0     P Space Disabled
                 ; [2]     = 1     Active High for Address Line 
                 ; [1:0]   = 01    SRAM Mode
                
        movep   #$2003B1,x:M_AAR1
                 ; [23:12] = 0x200 Address used to assert chip select
                 ; [11:8]  = 0011  Number of address bits to compare = 3
                 ; [7]     = 1     Bit Packing Enabled
                 ; [6]     = 0     Address Mux Disabled
                 ; [5]     = 1     Y Space Enabled
                 ; [4]     = 1     X Space Enabled
                 ; [3]     = 0     P Space Disabled
                 ; [2]     = 0     Active Low for Chip Select
                 ; [1:0]   = 01    SRAM Mode


;...Bus Control Register for SRAM...
        movep   #$0124A5,x:M_BCR                ;        0001 0010 0100 0110 0011
                ;bus request hold off           (bit23=0)
                ;bus lock hold off              (bit22=0)
                ;bus state                      (bit21=0)
                ;default area wait states       (bit20:16=00001)
                ;area 3 wait states             (bit15:13=001)
                ;area 2 wait states             (bit12:10=001)
                ;area 1 wait states             (bit9:5=00011)
                ;area 0 wait states             (bit4:0=00011)


;...Set up SHI (Serial Host Interface to the MCU)...
        movep   #>$003001,x:M_HCKR      ; Turn Data/Clk Line Filter to max, wide spike tolerance (100ns glitch)
                                        ; CPHA=1, CPOL=0 : => same as reset/power-on.
        movep   #>$001189,x:M_HCSR      ;

;...Initialize registers
        move    #>$000000,x0
        move    x0,r0
        rep     #26
        move    x0,x:(r0)+              ; clear start of x:mem

        move    #>$400000,x0   ; Intialize the knob registers
        move    x0,x:Knob_1    
        move    x0,x:Knob_2    
        move    x0,x:Knob_3    
        move    x0,x:Knob_4    
        move    x0,x:Knob_5    
        move    x0,x:Knob_6
       
       
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
; Setup
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Setup:
; Initialize the DMA counter register, only needs to be done once
  move #>$000000,x0
  nop
  movep x0,x:M_DCO0 ; set the number of transfers to 1 for a single word read/write
  movep x0,x:M_DCO1

; Dedicate Chan0 to read from buffer & write to y:Chan0IO
  movep #Chan0IO,x:M_DDR0
; Dedicate Chan1 to read from y:Chan1IO & write to buffer
  movep #Chan1IO,x:M_DSR1

  move #0,x0
  move x0,x:LFOPhase
  move x0,x:LFOInc
  move x0,x:Delay
  move x0,x:MinDelay
 
  move #>DelayLimit,y0
  move y0,x:MaxDelayLength
 
  move #$000001,y0
  move y0,x:Voices
 
  move #$000010,y0
  move y0,x:VoiceSeperation

  move #>Buffer,r0
  move #>Buffer,r1
       
        move #>$0001ff,m3
       
  ;mkout move #>(3*BufferSize-1),m0
  move #$FFFFFF,m0
  ;mkout move #>(3*BufferSize-1),m1
  move #$FFFFFF,m1
 
 
  move #>$00ffff,m2
  move #>(3*BufferSize),y0
 
 
  move #>3,n0
  move #>Chan0IO,r6
      

        move    #>$000000,x0
        move    #$00ffff,m5             ; Use r5 for the MCU parameter updates.
        movep   x0,x:M_HTX              ; Assert HREQ* pin for the MCU.


;...Initialize Peripheral Interrupt Priority Register for Audio Interrupts and SHI.
        movep   #$000007,x:M_IPRP       ; ESAI int enabled and top Priority
                                        ; SHI int enabled and lowest Priority.

        andi    #$FC,mr                 ;enable all interrupt levels
                                        ;clear scaling bits

        movep   #>$000002,x:M_PDRC      ; Take CODEC out of power down mode.


;------------------------------------------------------------
; Main loop
;------------------------------------------------------------
  nop
  nop
  dor forever,LOOP
        wait
        nop
        nop
        nop  
        
LOOP                 
                                 

;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
;   4x4 Interrupt Service Routines
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

;-----------------------------
; Host Interrupt
;-----------------------------

shi_receive
        movep   x:M_HRX,x:HostCommand ; Get word from 8031.
        movep   #000000,x:M_HTX   ; Assert HREQ* pin for 8031.
        btst    #0,x:HostCommand        ; $000001 = Write 1 DSP word to X:mem.
        bcs     DoWriteCommand          ;
        btst    #3,x:HostCommand        ; $000008 = Send word to the 8031.
        bcs     DoReadCommand           ;

DoWriteCommand
        jclr    #M_HRNE,x:M_HCSR,*      ; Wait for address.
        movep   x:M_HRX,r5              ; Store address to write to.
        movep   #>000000,x:M_HTX        ; Assert HREQ* pin for 8031.

        jclr    #M_HRNE,x:M_HCSR,*      ; Wait for data
        movep   x:M_HRX,x:(r5)          ; Write data.
        movep   #000000,x:M_HTX         ; Assert HREQ* pin for 8031.
  rti

DoReadCommand
        jclr    #M_HRNE,x:M_HCSR,*
        movep   x:M_HRX,r5              ; Store Address to read from
        movep   #>000000,x:M_HTX
       
        jclr    #M_HRNE,x:M_HCSR,*
        movep   x:M_HRX,n5               
        movep   x:(r5),x:<<M_HTX        ; Send Data at specified address to the 8031
       
        jclr    #M_HRNE,x:M_HCSR,*
        movep   x:M_HRX,n5
        movep   #>000000,x:<<M_HTX
  rti


;-----------------------------
; Receive Exception Interrupt
;-----------------------------
esai_rxe_isr                            ; ESAI RECEIVE ISR

        bclr    #7,x:M_SAISR            ; Read SAISR to clear receive
                                        ; overrun error flag
        bclr    #14,x:M_SAISR           ; Read SAISR to clear transmit
                                        ; underrun error flag
        movep   x:M_RX0,x:RightRx       ;
        movep   x:RightTx,x:M_TX0       ;

        rti

;-----------------------------
; Receive Interrupt
;-----------------------------
esai_rx_isr
        movep   x:M_RX0,x:RightRx      
        movep   x:RightTx,x:M_TX0      
        rti


;-----------------------------
; Receive Even Slot Interrupt
;-----------------------------

esai_rxeven_isr
; Mono effect, so no right line
        movep   x:M_RX0,x:LeftRx 
        move    x:LeftOutput,x0         ;
        move    x0,x:LeftTx             ; Transmit the output from the last sample period.     
        movep   x:LeftTx,x:M_TX0       

        move    x:LeftRx,a              ; receive left
        move    a,x:LeftInput           ; Save Current LeftInput sample
       
    ;Note: r5 and n5 are currently reserved for Host Interrupts

;Get some values from the knobs

  ;LFOInc = (Knob_1)^2 * (LFOIncLimit-LFOIncMin) + LFOIncMin
  move x:Knob_1,x0
  move x0,y0
  mpy  x0,y0,a
  move a,x0
  move #>(LFOIncLimit-LFOIncMin),y0
  mpy  x0,y0,a
  move #>LFOIncMin,x0
  add  x0,a
     move a,x:LFOInc
    
     ;Depth = Knob_2
     move x:Knob_2,x0
     move x0,x:Depth
    
     ;Feedback = Knob_3
     move x:Knob_3,x0
      move x0,x:Feedback
         
     ;MinDelay = Knob_4*MinDelayLimit + 1
     move x:Knob_4,x0
     move #>MinDelayLimit,y0
     mpy  x0,y0,a
     add  #>$000001,a
     move a,x:MinDelay
    
     ;MaxDelay = Knob_5 * DelayLimit
     move x:Knob_5,x0
     move #>DelayLimit,y0
     mpy  x0,y0,a
     move a,x:MaxDelayLength
    
     ;VoiceSeperation = Knob_6 * SeperationLimit
     move x:Knob_6,x0
     move #>SeperationLimit,y0
     mpy  x0,y0,a
     move a,x:VoiceSeperation
    
     ;Voices = Switch_1 + 1
     move x:Switch_1,a
     move #>$0000001,x0
     add  x0,a
     move a,x:Voices
    

  move x:LeftInput,a ; a = x[n] = newest input sample
  jsr  ProcessSample
  move a,x0 ;double output amplitude
  add  x0,a 
  move a,x:LeftOutput ; write the output, note by choosing a here it will round as appropriate
 
    
;increase lfo
  move x:LFOInc,n2
  move x:LFOPhase,r2
  lua  (r2)+n2,r2
  move r2,x:LFOPhase

;update delay
  jsr  CalculateDelay
 

     HandleFootSwitch
     
        rti
       
ProcessSample:
; sample in a
;
;
;READ FIRST VOICE
  move a,y:(r0) ; overwrite sample at y:(r0) with current input (only matters when delay = 0)
       ; which may not ever happen
  move a,x1  ; put copy of sample into x1 so I can later add it back for feedback
  
  move  r0,r1  ; r0 & r1 now hold the buffer index
   
  move x:Delay,x0 ; load delay amount in samples 
  move x0,b
  add  x0,b
  add  x0,b
  move b,n1
 
  lua  (r1)-n1,r1 ; load delayed sample into y0
  ;mk buffer management
  move #>Buffer,b
  move r1,x0 ;get current delay address pointer to see if at modulo end of buffer
  cmp  x0,b ;see if pointer has reached buffer end address
  jle  noreset1 ;if not, do not reset pointer - check result is less than
      ;if not, do not reset point by jumping over next address
  move #>(3*BufferSize),b
  move r1,x0
  add  x0,b
  move b,r1
 
noreset1

  ;move r1,x:Debug_Read_from_DSP_3
  ;move n1,x:Debug_Read_from_DSP_4
  ;mk end buffer management
 
 
; this line is new
;READ NEXT VOICE(S)
  move x:VoiceSeperation,x0
  move x0,b
  add  x0,b
  add  x0,b
  move b,n1
   
  move x:Depth,x0 ; x0 = Depth
  ;replace sample with (1-depth)*sample
  move #>$7fffff,b
 
  sub  x0,b
  move b,x0
  move x0,x:Debug_Read_from_DSP_2
  move a,y0

  mpy  x0,y0,a
 

 
;;;;;;;;;;;;;;;;;;;
;  move y:(r1),y0
 
  ;new code for multiple voices
  ;move x:Voices,y1
  ;dor  y1,_ProcessVoice
  TransferYData0 r1,r6
  jclr #0,x:M_DSTR,*    ; Wait until previous transfers are finished
  move y:Chan0IO,y0
 
  lua  (r1)-n1,r1 ; load delayed sample into y0
  ;mk buffer management
  move #>Buffer,b
  move r1,x0 ;get current delay address pointer to see if at modulo end of buffer
  cmp  x0,b ;see if pointer has reached buffer end address
  jle  noreset2 ;if not, do not reset pointer - check result is less than
      ;if not, do not reset point by jumping over next address
  move #>(3*BufferSize),b
  move r1,x0
  add  x0,b
  move b,r1

noreset2

  ;mk end buffer management
  ; put depth back into x0 (since it had 1-depth a second ago)

   
;_ProcessVoice
;WRITE TO BUFFER 

 
 
  add  y0,a
 
  move x:Feedback,x0 ; put feedback multiplier into x0
  move x0,x:Debug_Read_from_DSP_4
 
  mpy  x0,y0,b
 
  move x:Depth,x0
  move x0,x:Debug_Read_from_DSP_3
 
  mac  x0,x1,b   
  
  WriteToSRAM b,r0  ; put b into delay buffer
  ;WriteToSRAM a,r0
  ;lua  (r0)+n0,r0  ; update delay buffer address
  lua  (r0)+n0,r0 ; load delayed sample into y0
  ;mk buffer management
  move #>Buffer,x0
  move #>(3*BufferSize),b ;move buffer length into b
  add  x0,b
  move b,x0
  move r0,b ;get current delay address pointer to see if at modulo end of buffer
  cmp  x0,b ;see if pointer has reached buffer end address
  jlt  noreset3 ;if not, do not reset pointer - check result is less than
      ;if not, do not reset point by jumping over next address
  sub  x0,b ;determine difference outstanding to add to bottom of buffer
  move #>Buffer,x0 ;if so, reset the pointer to Buffer start location
  add  x0,b
  move b,r0

noreset3

  ;mk end buffer management
  ;move n0,x:Debug_Read_from_DSP_2
  ;move r0,x:Debug_Read_from_DSP_1
  rts
 
 
CalculateDelay:
; use LFOPhase to calculate the current Delay
; no register inputs, modifies x:Delay
; using x:LFOPhase
; Switch_2 selects which function to use for the lfo

  move x:LFOPhase,a ; put LFOPhase into a, will be passed
        ; to another function
   
  move x:Switch_2,b
  cmp  #1,b
  jlt  _Sine
  jeq  _Exp
  jgt  _LinearTriangle
_Sine
  jsr  SineVal
  jmp  _DoneCalculating 
_Exp
  jsr  ExpVal
  jmp  _DoneCalculating
_LinearTriangle:
  jsr  AbsVal
  jmp  _DoneCalculating
_DoneCalculating:
 
  ; output of the previous function is a number between 0 and 1
  ; multiply this by x:MaxDelay and then add MinDelay to get the current
  ; delay amount
 
  move x:MaxDelayLength,x0
  move a,y0
  move x:MinDelay,a
  mac  x0,y0,a
  move a,x:Delay
  rts

SineVal:
; returns a Bezier approximation of 1/2(Sin(a*PI)+1)
; 2(x(1-|x|)+1/2)
; let us call the input x
  move a,y0   ; y0 = x
  abs  a    ; a = |x|
  move a,x0   ; x0 = |x|
  move #>$7fffff,a  ; a = 1
  sub  x0,a   ; a = 1-|x|
  move a,x0   ; x0 = 1-|x|
  mpy  x0,y0,a   ; a = x*(1-|x|)
  add  #>$200000,a  ; a = x*(1-|x|)+1/2
  move a,x0   ; x0 = x*(1-|x|)+1/2
  add  x0,a   ; a = a+x0 = 2(x(1-|x|)+1/2) and we are done

  rts

ExpVal:
; calculates a 3rd order taylor approximation of (e^x-1)/(e-1)
  ; 9/15 = 0x4ccccc.ccccc
  ; 1/6 = 0x155555.55555
  ; formula = 9/15*(x+x^2/2+x^3/6)
  abs  a
 
  move #$4ccccd,x0
  move a,y0
  mpy  x0,y0,b
 
  move b,x:Temp
 
  mpy  y0,y0,b
  move b,y0
  mpy  x0,y0,b  ; b = x^2
  asr  #1,b,b  ; b = x^2/2
  move #$4ccccd,x0
  move b,y0
  mpy  x0,y0,b  ; b = 9/15*x^2/2
   
  move b,x:(Temp+1)
 
 
  move a,y0
  mpy  y0,y0,b
  move b,x0
  mpy  x0,y0,b  ; b = x^3
  move b,y0
  move #$155555,x0
  mpy  x0,y0,b  ; b = x^3/6
  move #$4ccccd,x0
  move b,y0
  mpy  x0,y0,a  ; a = 9/15*x^3/6
 
  move x:Temp,x0 ; add up previous numbers
  move x:Temp,y0
  add  x0,a
  add  y0,a
 
  rts

AbsVal:
  abs  a
  rts


;SquareVal:
; calculate 2^a/2^0x7fffff
;  move a,x0
;  move a,y0
;  mpy  x0,y0,a
;  rts




The information above may not be current, and you should direct questions to the current forum or review the manual.