{******************************************************************************
 *
 *  Abwandlung des Programms MIC2OUT.DSP
 *  aus der Beispielsammlung des EZ-Kit Lite
 *
 *  Assemblieren mit > make EZKIT_IO
 *  (evtl. Root-Verzeichnis in make.bat ndern)
 *
 *  Dieses Programm macht folgendes:
 *  1. Signaldaten vom rechten Kanal werden in einen
 *     Buffer geschrieben, von wo aus sie vom PC
 *     ausgelesen werden knnen (z.B. fr Darstellung)
 *  2. Das gepufferte Signal wird ber den rechten Kanal
 *     kontiunuierlich wieder ausgegeben
 *  3. Ein Sinus der Frequenz fs/12 (fs = Abtastrate)
 *     wird auf dem linken Kanal kontinuierlich ausgegeben
 *
 *  Die wesentlichen nderungen gegenber der ursprnglichen
 *  Version dieses DSP-Programms betreffen die Funktion des
 *  Timers (LED FL1 wird getoggelt) und die Interrupt-Prozedur
 *  "input_samples", die jetzt zustzlich die Generatorroutine
 *  und die Pufferung realisiert
 *
 *  A.R.Bayer Ing.-Bro Bayer Neuss July 13,1996
 *
 ******************************************************************************}



.module/RAM/ABS=0 ezkit_io;



{******************************************************************************
 *
 *  Assemble time constants
 *
 ******************************************************************************}

.const  IDMA=                   0x3fe0;
.const  BDMA_BIAD=              0x3fe1;
.const  BDMA_BEAD=              0x3fe2;
.const  BDMA_BDMA_Ctrl=         0x3fe3;
.const  BDMA_BWCOUNT=           0x3fe4;
.const  PFDATA=                 0x3fe5;
.const  PFTYPE=                 0x3fe6;

.const  SPORT1_Autobuf=         0x3fef;
.const  SPORT1_RFSDIV=          0x3ff0;
.const  SPORT1_SCLKDIV=         0x3ff1;
.const  SPORT1_Control_Reg=     0x3ff2;
.const  SPORT0_Autobuf=         0x3ff3;
.const  SPORT0_RFSDIV=          0x3ff4;
.const  SPORT0_SCLKDIV=         0x3ff5;
.const  SPORT0_Control_Reg=     0x3ff6;
.const  SPORT0_TX_Channels0=    0x3ff7;
.const  SPORT0_TX_Channels1=    0x3ff8;
.const  SPORT0_RX_Channels0=    0x3ff9;
.const  SPORT0_RX_Channels1=    0x3ffa;
.const  TSCALE=                 0x3ffb;
.const  TCOUNT=                 0x3ffc;
.const  TPERIOD=                0x3ffd;
.const  DM_Wait_Reg=            0x3ffe;
.const  System_Control_Reg=     0x3fff;


.const	sample_cnt=600;

.var/dm/ram/abs=0		io_flag;

.var/dm/ram/circ                rx_buf[3];      /* Status + L data + R data */
.var/dm/ram/circ                tx_buf[3];      /* Cmd + L data + R data    */
.var/dm/ram/circ                init_cmds[13];
.var/dm                         stat_flag;

.init tx_buf:   0xc000, 0x0000, 0x0000; 	/* Initially set MCE        */

.init init_cmds:
        0xc002,     {
                        Left input control reg
                        b7-6: 0=left line 1
                              1=left aux 1
                              2=left line 2
                              3=left line 1 post-mixed loopback
                        b5-4: res
                        b3-0: left input gain x 1.5 dB
                    }
        0xc102,     {
                        Right input control reg
                        b7-6: 0=right line 1
                              1=right aux 1
                              2=right line 2
                              3=right line 1 post-mixed loopback
                        b5-4: res
                        b3-0: right input gain x 1.5 dB
                    }
        0xc288,     {
                        left aux 1 control reg
                        b7  : 1=left aux 1 mute
                        b6-5: res
                        b4-0: gain/atten x 1.5, 08= 0dB, 00= 12dB
                    }
        0xc388,     {
                        right aux 1 control reg
                        b7  : 1=right aux 1 mute
                        b6-5: res
                        b4-0: gain/atten x 1.5, 08= 0dB, 00= 12dB
                    }
        0xc488,     {
                        left aux 2 control reg
                        b7  : 1=left aux 2 mute
                        b6-5: res
                        b4-0: gain/atten x 1.5, 08= 0dB, 00= 12dB
                    }
        0xc588,     {
                        right aux 2 control reg
                        b7  : 1=right aux 2 mute
                        b6-5: res
                        b4-0: gain/atten x 1.5, 08= 0dB, 00= 12dB
                    }
        0xc680,     {
                        left DAC control reg
                        b7  : 1=left DAC mute
                        b6  : res
                        b5-0: attenuation x 1.5 dB
                    }
        0xc780,     {
                        right DAC control reg
                        b7  : 1=right DAC mute
                        b6  : res
                        b5-0: attenuation x 1.5 dB
                    }
        0xc85c,     {
                        data format register
                        b7  : res
                        b5-6: 0=8-bit unsigned linear PCM
                              1=8-bit u-law companded
                              2=16-bit signed linear PCM
                              3=8-bit A-law companded
                        b4  : 0=mono, 1=stereo
                        b0-3: 0=  8.
                              1=  5.5125
                              2= 16.
                              3= 11.025
                              4= 27.42857
                              5= 18.9
                              6= 32.
                              7= 22.05
                              8=   .
                              9= 37.8
                              a=   .
                              b= 44.1
                              c= 48.
                              d= 33.075
                              e=  9.6
                              f=  6.615
                       (b0) : 0=XTAL1 24.576 MHz; 1=XTAL2 16.9344 MHz
                    }
        0xc909,     {
                        interface configuration reg
                        b7-4: res
                        b3  : 1=autocalibrate
                        b2-1: res
                        b0  : 1=playback enabled
                    }
        0xca00,     {
                        pin control reg
                        b7  : logic state of pin XCTL1
                        b6  : logic state of pin XCTL0
                        b5  : master - 1=tri-state CLKOUT
                              slave  - x=tri-state CLKOUT
                        b4-0: res
                    }
        0xcc40,     {
                        miscellaneous information reg
                        b7  : 1=16 slots per frame, 0=32 slots per frame
                        b6  : 1=2-wire system, 0=1-wire system
                        b5-0: res
                    }
        0xcd00;     {
                        digital mix control reg
                        b7-2: attenuation x 1.5 dB
                        b1  : res
                        b0  : 1=digital mix enabled
                    }

.VAR/DM/RAM				count,triggered;

.VAR/DM/RAM				re, im;
.VAR/PM/RAM/abs=0x1000+sample_cnt	cos_delta_phi, sin_delta_phi, A_squared;

.VAR/PM/RAM/abs=0x1000			buffer[sample_cnt];


.INIT			cos_delta_phi : 0x6ed9eb;	{ phi = 30ř }
.INIT			sin_delta_phi : 0x400000;	{ f = fs/12  }
.INIT			A_squared     : 0x7ffe00;	{ A = MaxInt }


{******************************************************************************
 *
 *  Interrupt vector table
 *
 ******************************************************************************}

	jump start;  	rti; rti; rti;  {00: reset }
	rti;         	rti; rti; rti;  {04: IRQ2 }
	rti;         	rti; rti; rti;  {08: IRQL1 }
	rti;         	rti; rti; rti;  {0c: IRQL0 }
        ar = dm(stat_flag);             {10: SPORT0 tx }
        ar = pass ar;
        if eq rti;
        jump next_cmd;
	jump input_samples;           	{14: SPORT0 rx }
			rti; rti; rti;
	rti;		rti; rti; rti;  {18: IRQE }
	rti;         	rti; rti; rti;  {1c: BDMA }
	rti;         	rti; rti; rti;  {20: SPORT1 tx or IRQ1 }
	rti;         	rti; rti; rti;  {24: SPORT1 rx or IRQ0 }
	toggle FL1;    	rti; rti; rti;  {28: timer }
	rti;         	rti; rti; rti;  {2c: power down }


{******************************************************************************
 *
 *  ADSP 2181 intialization
 *
 ******************************************************************************}

start:  i0 = ^rx_buf;
        l0 = %rx_buf;
        i1 = ^tx_buf;
        l1 = %tx_buf;
        i3 = ^init_cmds;
        l3 = %init_cmds;

        m1 = 1;


{================== S E R I A L   P O R T   #0   S T U F F ==================}

	ax0 = b#0000001010000111;   dm (SPORT0_Autobuf) = ax0;
            {   |||!|-/!/|-/|/|+- receive autobuffering 0=off, 1=on
                |||!|  ! |  | +-- transmit autobuffering 0=off, 1=on
                |||!|  ! |  +---- | receive m?
                |||!|  ! |        | m1
                |||!|  ! +------- ! receive i?
                |||!|  !          ! i0
                |||!|  !          !
                |||!|  +========= | transmit m?
                |||!|             | m1
                |||!+------------ ! transmit i?
                |||!              ! i1
                |||!              !
                |||+============= | BIASRND MAC biased rounding control bit
                ||+-------------- 0
                |+--------------- | CLKODIS CLKOUT disable control bit
                +---------------- 0
            }

        ax0 = 0;    dm (SPORT0_RFSDIV) = ax0;
            {   RFSDIV = SCLK Hz/RFS Hz - 1 }
        ax0 = 0;    dm (SPORT0_SCLKDIV) = ax0;
            {   SCLK = CLKOUT / (2  (SCLKDIV + 1) }
        ax0 = b#1000011000001111;   dm (SPORT0_Control_Reg) = ax0;
            {   multichannel
                ||+--/|!||+/+---/ | number of bit per word - 1
                |||   |!|||       | = 15
                |||   |!|||       |
                |||   |!|||       |
                |||   |!||+====== ! 0=right just, 0-fill; 1=right just, signed
                |||   |!||        ! 2=compand u-law; 3=compand A-law
                |||   |!|+------- receive framing logic 0=pos, 1=neg
                |||   |!+-------- transmit data valid logic 0=pos, 1=neg
                |||   |+========= RFS 0=ext, 1=int
                |||   +---------- multichannel length 0=24, 1=32 words
                ||+-------------- | frame sync to occur this number of clock
                ||                | cycle before first bit
                ||                |
                ||                |
                |+--------------- ISCLK 0=ext, 1=int
                +---------------- multichannel 0=disable, 1=enable
            }
            {   non-multichannel
                |||!|||!|||!+---/ | number of bit per word - 1
                |||!|||!|||!      | = 15
                |||!|||!|||!      |
                |||!|||!|||!      |
                |||!|||!|||+===== ! 0=right just, 0-fill; 1=right just, signed
                |||!|||!||+------ ! 2=compand u-law; 3=compand A-law
                |||!|||!|+------- receive framing logic 0=pos, 1=neg
                |||!|||!+-------- transmit framing logic 0=pos, 1=neg
                |||!|||+========= RFS 0=ext, 1=int
                |||!||+---------- TFS 0=ext, 1=int
                |||!|+----------- TFS width 0=FS before data, 1=FS in sync
                |||!+------------ TFS 0=no, 1=required
                |||+============= RFS width 0=FS before data, 1=FS in sync
                ||+-------------- RFS 0=no, 1=required
                |+--------------- ISCLK 0=ext, 1=int
                +---------------- multichannel 0=disable, 1=enable
            }


        ax0 = b#0000000000000111;   dm (SPORT0_TX_Channels0) = ax0;
            {   ^15          00^   transmit word enables: channel # == bit # }
        ax0 = b#0000000000000111;   dm (SPORT0_TX_Channels1) = ax0;
            {   ^31          16^   transmit word enables: channel # == bit # }
        ax0 = b#0000000000000111;   dm (SPORT0_RX_Channels0) = ax0;
            {   ^15          00^   receive word enables: channel # == bit # }
        ax0 = b#0000000000000111;   dm (SPORT0_RX_Channels1) = ax0;
            {   ^31          16^   receive word enables: channel # == bit # }


{============== S Y S T E M   A N D   M E M O R Y   S T U F F ==============}

	ax0 = b#0000111111111111;   dm (DM_Wait_Reg) = ax0;
            {   |+-/+-/+-/+-/+-/- ! IOWAIT0
                ||  |  !  |       !
                ||  |  !  |       !
                ||  |  !  +------ | IOWAIT1
                ||  |  !          |
                ||  |  !          |
                ||  |  +--------- ! IOWAIT2
                ||  |             !
                ||  |             !
                ||  +------------ | IOWAIT3
                ||                |
                ||                |
                |+=============== ! DWAIT
                |                 !
                |                 !
                +---------------- 0
            }

        ax0 = b#0001000000000000;   dm (System_Control_Reg) = ax0;
            {   +-/!||+-----/+-/- | program memory wait states
                |  !|||           | 0
                |  !|||           |
                |  !||+---------- 0
                |  !||            0
                |  !||            0
                |  !||            0
                |  !||            0
                |  !||            0
                |  !||            0
                |  !|+----------- SPORT1 1=serial port, 0=FI, FO, IRQ0, IRQ1,..
                |  !+------------ SPORT1 1=enabled, 0=disabled
                |  +============= SPORT0 1=enabled, 0=disabled
                +---------------- 0
                                  0
                                  0
            }



        ifc = b#00000011111111;         { clear pending interrupt }
        nop;


        icntl = b#00000;
            {     ||||+- | IRQ0: 0=level, 1=edge
                  |||+-- | IRQ1: 0=level, 1=edge
                  ||+--- | IRQ2: 0=level, 1=edge
                  |+---- 0
                  |----- | IRQ nesting: 0=disabled, 1=enabled
            }


        mstat = b#1000000;
            {     ||||||+- | Data register bank select
                  |||||+-- | FFT bit reverse mode (DAG1)
                  ||||+--- | ALU overflow latch mode, 1=sticky
                  |||+---- | AR saturation mode, 1=saturate, 0=wrap
                  ||+----- | MAC result, 0=fractional, 1=integer
                  |+------ | timer enable
                  +------- | GO MODE
            }



{******************************************************************************
 *
 *  ADSP 1847 Codec intialization
 *
 ******************************************************************************}






        {   clear flag }
        ax0 = 1;
        dm(stat_flag) = ax0;

	{   enable S0 Tx and timer interrupt }
	imask = b#0001000001;
            {     |||||||||+ | timer
                  ||||||||+- | SPORT1 rec or IRQ0
                  |||||||+-- | SPORT1 trx or IRQ1
                  ||||||+--- | BDMA
                  |||||+---- | IRQE
                  ||||+----- | SPORT0 rec
                  |||+------ | SPORT0 trx
                  ||+------- | IRQL0
                  |+-------- | IRQL1
                  +--------- | IRQ2
            }


        ax0 = dm (i1, m1);          { start interrupt }
        tx0 = ax0;

check_init:
        ax0 = dm (stat_flag);       { wait for entire init }
        af = pass ax0;              { buffer to be sent to }
        if ne jump check_init;      { the codec            }

        ay0 = 2;
check_aci1:
        ax0 = dm (rx_buf);          { once initialized, wait for codec }
        ar = ax0 and ay0;           { to come out of autocalibration }
        if eq jump check_aci1;      { wait for bit set }

check_aci2:
        ax0 = dm (rx_buf);          { wait for bit clear }
        ar = ax0 and ay0;
        if ne jump check_aci2;
        idle;

        ay0 = 0xbf3f;               { unmute left DAC }
        ax0 = dm (init_cmds + 6);
        ar = ax0 AND ay0;
        dm (tx_buf) = ar;
        idle;

        ax0 = dm (init_cmds + 7);   { unmute right DAC }
        ar = ax0 AND ay0;
        dm (tx_buf) = ar;
        idle;


        ifc = b#00000011111111;     { clear any pending interrupt }
        nop;

	imask = b#0000110001;       { enable rx0 interrupt }
            {     |||||||||+ | timer
                  ||||||||+- | SPORT1 rec or IRQ0
                  |||||||+-- | SPORT1 trx or IRQ1
                  ||||||+--- | BDMA
                  |||||+---- | IRQE
                  ||||+----- | SPORT0 rec
                  |||+------ | SPORT0 trx
                  ||+------- | IRQL0
                  |+-------- | IRQL1
                  +--------- | IRQ2
            }




	ax0=0xff;
	dm(TSCALE)=ax0;
	ax0=0x3fff;
	dm(TCOUNT)=ax0;
	dm(TPERIOD)=ax0;

	ena TIMER;


	ax0 = 0x7fff;			{ set initial phi = 0 }
	dm(re) = ax0;			{ re = cos(phi) = 1 }
	ax0 = 0;                        { im = sin(phi) = 0 }
	dm(im) = ax0;
	ax0=sample_cnt;
	dm(count) = ax0;
	ax0=0;
	dm(triggered)=ax0;
	dm(io_flag)=ax0;

	l4 = 0;
	m2 = 1;
	l2 = 0;
	m3 = -1;
	i5=^buffer;
	l5=%buffer;
	m5=1;

{------------------------------------------------------------------------------
 -
 -  wait for interrupt and loop forever
 -
 ------------------------------------------------------------------------------}

talkthru:
	idle;
        jump talkthru;




{******************************************************************************
 *
 *  Interrupt service routines
 *
 ******************************************************************************}

{------------------------------------------------------------------------------
 -
 -  receive interrupt
 -
 ------------------------------------------------------------------------------}
input_samples:
	ena sec_reg;                	{ use shadow register bank }

	mr0 = dm (rx_buf + 1);      	{ mr0 = left input }

	mr1 = dm (rx_buf + 2);          { mr1 = right input }

test_trigger:
	ar=dm(triggered);
	ar=pass ar;
	if ne jump trigger_OK;

	ar=dm(tx_buf+2);      		{ old sample }
	ar = - ar;
	if lt jump set_cnt;		{ if pos -> no trigger }

	ay0 = mr1;			{ current sample }
	ar = pass ay0;
	if lt jump set_cnt;		{ if neg -> no trigger }

	ar=sample_cnt;
	dm(triggered)=ar;
set_cnt:dm(count)=ar;

trigger_OK:
	ar=dm(count);
	ar=ar-1;
	if lt jump no_store;

	pm(i5,m5)=mr1;			{ copy sample to buffer }

no_store:

	dm (tx_buf + 2) = mr1;		{ R-In --> R_Out }



/* Diese Routine stammt aus ELRAD 5/95 : Turbo-Sinus */


	i2 = ^re;       		{ setup RAM pointers }
	i4 = ^cos_delta_phi;		{ point at constant delta phi }
			     mx0 = dm(i2,m2), my0 = pm(i4,m5);	{ mx0 = re, my0 = cos }
	mr = mx0 * my0(ss),  mx1 = dm(i2,m3), my1 = pm(i4,m5);	{ mr = re * cos, mx1 = im, my1 = cos }
	mr = mr - mx1 * my1(rnd);				{ mr = re' = re * cos - im * sin }
	sr1 = mr1;						{ sr1 = re' }
	mr = mx0 * my1(ss),  my1 = sr1;				{ mr = re * sin }
	mr = mr + mx1 * my0(rnd);				{ mr = im' = re * sin + im * cos }
	my0 = mr1;						{ my0 = im' }
	mr = mr1 * my0(ss);
	mr = mr + sr1 * my1(rnd),	      ay0 = pm(i4,m5);	{ mr = re'^2 + im'^2 , ay0 = 1.0 }
	ar = ay0 - mr1;						{ ar = 2*e, my0 = re' }
	sr = ashift ar by -1(lo);				{ sr0 = e }
	mr = sr0 * my1(rnd), ay0 = my1;				{ mr1 = e * re'}
	ar = mr1 + ay0,      ay0 = my0;				{ ar = (1+e) * re' }
	mr = sr0 * my0(rnd), dm(i2,m2) = ar;			{ mr1 = e * im', replace old re}
	ar = mr1 + ay0;						{ ar = (1+e) * im' }
			     dm(i2,m3) = ar;                    { replace old im (sin) }

	dm (tx_buf + 1) = ar;		{ Sinussignal mit f=fs/12 an L-Out }

	ar=dm(count);
	ar=ar-1;
	if ge jump down_count;

	ar=dm(io_flag);
	ar=pass ar;
	if ne rti;			{ while host not ready do not fill buffer }

	dm(triggered)=ar;		{ triggered = 0 }

	ar=sample_cnt;
	dm(io_flag)=ar;
down_count:
	dm(count)=ar;

        rti;



{------------------------------------------------------------------------------
 -
 -  transmit interrupt used for Codec initialization
 -
 ------------------------------------------------------------------------------}
next_cmd:
        ena sec_reg;
        ax0 = dm (i3, m1);          { fetch next control word and }
        dm (tx_buf) = ax0;          { place in transmit slot 0    }
        ax0 = i3;
        ay0 = ^init_cmds;
        ar = ax0 - ay0;
        if gt rti;                  { rti if more control words still waiting }
        ax0 = 0xaf00;               { else set done flag and }
        dm (tx_buf) = ax0;          { remove MCE if done initialization }
        ax0 = 0;
        dm (stat_flag) = ax0;       { reset status flag }
        rti;


.endmod;

