First commit

This commit is contained in:
Dave Lacey
2011-07-07 20:15:51 +01:00
commit 02b07ed9f3
70 changed files with 15434 additions and 0 deletions

View File

@@ -0,0 +1 @@
Shared USB Audio Files

View File

@@ -0,0 +1,18 @@
#ifndef __audio_h__
#define __audio_h__
/** The audio driver thread.
*
* This function drives I2S ports and handles samples to/from other digital
* I/O threads.
*
* \param c_in Audio sample channel connected to the mixer() thread or the
* decouple() thread
* \param c_dig channel connected to the clockGen() thread for
* receiving/transmitting samples
* \param c_config An optional channel that will be passed on to the
* CODEC configuration functions.
*/
void audio(chanend c_in, chanend ?c_dig, chanend ?c_config);
#endif // __audio_h__

621
module_usb_aud_shared/audio.xc Executable file
View File

@@ -0,0 +1,621 @@
/**
* @file audio.xc
* @brief XMOS L1/L2 USB 2,0 Audio Reference Design. Audio Functions.
* @author Ross Owen, XMOS Semiconductor Ltd
*
* This thread handles I2S and pars an additional SPDIF Tx thread. It forwards samples to the SPDIF Tx thread.
* Additionally this thread handles clocking and CODEC/DAC/ADC config.
**/
#include <syscall.h>
#include <platform.h>
#include <xs1.h>
#include <xclib.h>
#include <print.h>
#include "clocking.h"
#include "audioports.h"
#include "codec.h"
#include "devicedefines.h"
#include "SpdifTransmit.h"
//#define RAMP_CHECK 1
//#pragma xta command "analyse path i2s_output_l i2s_output_r"
//#pragma xta command "set required - 2000 ns"
//#pragma xta command "analyse path i2s_output_r i2s_output_l"
//#pragma xta command "set required - 2000 ns"
/* I2S Data I/O*/
#if (I2S_CHANS_DAC != 0)
extern buffered out port:32 p_i2s_dac[I2S_WIRES_DAC];
#endif
#if (I2S_CHANS_ADC != 0)
extern buffered in port:32 p_i2s_adc[I2S_WIRES_ADC];
#endif
/* I2S LR/Bit clock I/O */
#ifdef CODEC_SLAVE
extern buffered out port:32 p_lrclk;
extern buffered out port:32 p_bclk;
#else
extern in port p_lrclk;
extern in port p_bclk;
#endif
/* Master clock input */
extern port p_mclk;
#ifdef SPDIF
extern buffered out port:32 p_spdif_tx;
#endif
extern clock clk_audio_mclk;
extern clock clk_audio_bclk;
extern clock clk_mst_spd;
extern void device_reboot(void);
/* I2S delivery thread */
#pragma unsafe arrays
unsigned deliver(chanend c_out, chanend c_spd_out, unsigned divide, chanend ?c_dig_rx)
{
unsigned sample;
#if NUM_USB_CHAN_OUT > 0
unsigned samplesOut[NUM_USB_CHAN_OUT];
#endif
#if NUM_USB_CHAN_IN > 0
unsigned samplesIn[NUM_USB_CHAN_IN];
unsigned samplesInPrev[NUM_USB_CHAN_IN];
#endif
unsigned tmp;
unsigned index;
#ifdef RAMP_CHECK
unsigned prev=0;
int started = 0;
#endif
#if NUM_USB_CHAN_IN > 0
for (int i=0;i<NUM_USB_CHAN_IN;i++)
{
samplesIn[i] = 0;
samplesInPrev[i] = 0;
}
#endif
outuint(c_out, 0);
/* Check for sample freq change or new samples from mixer*/
if(testct(c_out))
{
inct(c_out);
return inuint(c_out);
}
else
{
#ifndef MIXER // Interfaces straight to decouple()
(void) inuint(c_out);
#if NUM_USB_CHAN_IN > 0
#pragma loop unroll
for(int i = 0; i < NUM_USB_CHAN_IN; i++)
{
outuint(c_out, samplesIn[i]);
}
#endif
#if NUM_USB_CHAN_OUT > 0
#pragma loop unroll
for(int i = 0; i < NUM_USB_CHAN_OUT; i++)
{
samplesOut[i] = inuint(c_out);
}
#endif
#else
#pragma loop unroll
for(int i = 0; i < NUM_USB_CHAN_OUT; i++)
{
int tmp = inuint(c_out);
#if defined(OUT_VOLUME_IN_MIXER) && defined(OUT_VOLUME_AFTER_MIX)
tmp<<=3;
#endif
samplesOut[i] = tmp;
}
#pragma loop unroll
for(int i = 0; i < NUM_USB_CHAN_IN; i++)
{
outuint(c_out, samplesIn[i]);
}
#endif
}
#ifdef CODEC_SLAVE
/* Clear I2S port buffers */
clearbuf(p_lrclk);
#if (I2S_CHANS_DAC != 0)
for(int i = 0; i < I2S_WIRES_DAC; i++)
{
clearbuf(p_i2s_dac[i]);
}
#endif
#if (I2S_CHANS_ADC != 0)
for(int i = 0; i < I2S_WIRES_ADC; i++)
{
clearbuf(p_i2s_adc[i]);
}
#endif
if(divide == 1)
{
p_lrclk <: 0 @ tmp;
tmp += 30;
/* Prefill the ports so data starts to be input */
#if (I2S_CHANS_DAC != 0)
#pragma loop unroll
for(int i = 0; i < I2S_WIRES_DAC; i++)
{
p_i2s_dac[i] @ tmp <: 0;
}
#endif
p_lrclk @ tmp <: 0x7FFFFFFF;
#if (I2S_CHANS_ADC != 0)
p_i2s_adc[0] @ (tmp - 1) :> void;
#endif
#if (I2S_CHANS_ADC != 0)
#pragma loop unroll
for(int i = 0; i < I2S_WIRES_ADC; i++)
{
clearbuf(p_i2s_adc[i]);
}
#endif
}
else
{
clearbuf(p_bclk);
#if (I2S_CHANS_DAC != 0)
/* Prefill the ports so data is input in advance */
for(int i = 0; i < I2S_WIRES_DAC; i++)
{
p_i2s_dac[i] <: 0;
}
#endif
p_lrclk <: 0x7FFFFFFF;
p_bclk <: 0xAAAAAAAA;
p_bclk <: 0xAAAAAAAA;
}
#else
/* CODEC is master */
/* Wait for LRCLK edge */
p_lrclk when pinseq(0) :> void;
p_lrclk when pinseq(1) :> void;
p_lrclk when pinseq(0) :> void;
p_lrclk when pinseq(1) :> void;
p_lrclk when pinseq(0) :> void @ tmp;
tmp += 33;
#if (I2S_CHANS_DAC != 0)
#pragma loop unroll
for(int i = 0; i < I2S_WIRES_DAC; i++)
{
p_i2s_dac[i] @ tmp <: 0;
}
#endif
p_i2s_adc[0] @ tmp - 1 :> void;
#pragma loop unroll
for(int i = 0; i < I2S_WIRES_ADC; i++)
{
clearbuf(p_i2s_adc[i]);
}
/* TODO In master mode, the i/o loop assumes L/RCLK = 32bit clocks. We should check this every interation
* and resync if we got a bclk glitch */
#endif
/* Main Audio I/O loop */
while (1)
{
outuint(c_out, 0);
/* Check for sample freq change or new samples from mixer*/
if(testct(c_out))
{
inct(c_out);
return inuint(c_out);
}
else
{
#ifndef MIXER // Interfaces straight to decouple()
(void) inuint(c_out);
#if NUM_USB_CHAN_IN > 0
#pragma loop unroll
for(int i = 0; i < NUM_USB_CHAN_IN; i++)
{
outuint(c_out, samplesIn[i]);
}
#endif
#if NUM_USB_CHAN_OUT > 0
#pragma loop unroll
for(int i = 0; i < NUM_USB_CHAN_OUT; i++)
{
samplesOut[i] = inuint(c_out);
}
#endif
#else
#pragma loop unroll
for(int i = 0; i < NUM_USB_CHAN_OUT; i++)
{
int tmp = inuint(c_out);
#if defined(OUT_VOLUME_IN_MIXER) && defined(OUT_VOLUME_AFTER_MIX)
tmp<<=3;
#endif
samplesOut[i] = tmp;
}
#pragma loop unroll
for(int i = 0; i < NUM_USB_CHAN_IN; i++)
{
outuint(c_out, samplesIn[i]);
}
#endif
}
#if defined(SPDIF_RX) || defined(ADAT_RX)
inuint(c_dig_rx);
#endif
#ifdef SPDIF_RX
asm("ldw %0, dp[g_digData]":"=r"(samplesIn[SPDIF_RX_INDEX + 0]));
asm("ldw %0, dp[g_digData+4]":"=r"(samplesIn[SPDIF_RX_INDEX + 1]));
#endif
#ifdef ADAT_RX
asm("ldw %0, dp[g_digData+8]":"=r"(samplesIn[ADAT_RX_INDEX + 0]));
asm("ldw %0, dp[g_digData+12]":"=r"(samplesIn[ADAT_RX_INDEX+ 1]));
asm("ldw %0, dp[g_digData+16]":"=r"(samplesIn[ADAT_RX_INDEX + 2]));
asm("ldw %0, dp[g_digData+20]":"=r"(samplesIn[ADAT_RX_INDEX + 3]));
asm("ldw %0, dp[g_digData+24]":"=r"(samplesIn[ADAT_RX_INDEX + 4]));
asm("ldw %0, dp[g_digData+28]":"=r"(samplesIn[ADAT_RX_INDEX + 5]));
asm("ldw %0, dp[g_digData+32]":"=r"(samplesIn[ADAT_RX_INDEX + 6]));
asm("ldw %0, dp[g_digData+36]":"=r"(samplesIn[ADAT_RX_INDEX + 7]));
#endif
#if defined(SPDIF_RX) || defined(ADAT_RX)
/* Request digital data (with prefill) */
outuint(c_dig_rx, 0);
#endif
tmp = 0;
#pragma xta endpoint "i2s_output_l"
#if (I2S_CHANS_DAC != 0) && (NUM_USB_CHAN_OUT != 0)
#pragma loop unroll
for(int i = 0; i < I2S_CHANS_DAC; i+=2)
{
p_i2s_dac[tmp++] <: bitrev(samplesOut[i]); /* Output LEFT sample to DAC */
}
#endif
#ifdef CODEC_SLAVE
/* Generate clocks LR Clock low - LEFT */
switch (divide)
{
case 8:
/* LR clock delayed by one clock, This is so MSB is output on the falling edge of BCLK
* after the falling edge on which LRCLK was toggled. (see I2S spec) */
p_lrclk <: 0x80000000;
p_bclk <: 0xF0F0F0F0;
p_bclk <: 0xF0F0F0F0;
p_bclk <: 0xF0F0F0F0;
p_bclk <: 0xF0F0F0F0;
p_bclk <: 0xF0F0F0F0;
p_bclk <: 0xF0F0F0F0;
p_bclk <: 0xF0F0F0F0;
p_bclk <: 0xF0F0F0F0;
break;
case 4:
p_lrclk <: 0x80000000;
p_bclk <: 0xCCCCCCCC;
p_bclk <: 0xCCCCCCCC;
p_bclk <: 0xCCCCCCCC;
p_bclk <: 0xCCCCCCCC;
break;
case 2:
p_lrclk <: 0x80000000;
p_bclk <: 0xAAAAAAAA;
p_bclk <: 0xAAAAAAAA;
break;
case 1:
p_lrclk <: 0x80000000;
break;
}
#endif
#if (I2S_CHANS_ADC != 0)
/* Input prevous R sample into R in buffer */
index = 0;
#pragma loop unroll
for(int i = 1; i < I2S_CHANS_ADC; i += 2)
{
p_i2s_adc[index++] :> sample;
#if NUM_USB_CHAN_IN > 0
samplesIn[i] = bitrev(sample);
/* Store the previous left in left */
samplesIn[i-1] = samplesInPrev[i];
#endif
}
#endif
#if defined(SPDIF) && (NUM_USB_CHAN_OUT > 0)
outuint(c_spd_out, samplesOut[SPDIF_TX_INDEX]); /* Forward sample to SPDIF txt thread */
sample = samplesOut[SPDIF_TX_INDEX + 1];
outuint(c_spd_out, sample); /* Forward sample to SPDIF txt thread */
#ifdef RAMP_CHECK
sample >>= 8;
if (started<10000) {
if (sample == prev+1)
started++;
}
else
if (sample != prev+1 && sample != 0) {
printintln(prev);
printintln(sample);
printintln(prev-sample+1);
}
prev = sample;
#endif
#endif
tmp = 0;
#pragma xta endpoint "i2s_output_r"
#if (I2S_CHANS_DAC != 0) && (NUM_USB_CHAN_OUT != 0)
#pragma loop unroll
for(int i = 1; i < I2S_CHANS_DAC; i+=2)
{
p_i2s_dac[tmp++] <: bitrev(samplesOut[i]); /* Output RIGHT sample to DAC */
}
#endif
#ifdef CODEC_SLAVE
/* Clock out data (and LR clock) */
switch (divide)
{
case 8:
p_lrclk <: 0x7FFFFFFF;
p_bclk <: 0xF0F0F0F0;
p_bclk <: 0xF0F0F0F0;
p_bclk <: 0xF0F0F0F0;
p_bclk <: 0xF0F0F0F0;
p_bclk <: 0xF0F0F0F0;
p_bclk <: 0xF0F0F0F0;
p_bclk <: 0xF0F0F0F0;
p_bclk <: 0xF0F0F0F0;
break;
case 4:
p_lrclk <: 0x7FFFFFFF;
p_bclk <: 0xCCCCCCCC;
p_bclk <: 0xCCCCCCCC;
p_bclk <: 0xCCCCCCCC;
p_bclk <: 0xCCCCCCCC;
break;
case 2:
p_lrclk <: 0x7FFFFFFF;
p_bclk <: 0xAAAAAAAA;
p_bclk <: 0xAAAAAAAA;
break;
case 1:
p_lrclk <: 0x7FFFFFFF;
break;
}
#endif
#if (I2S_CHANS_ADC != 0)
/* Input previous L ADC sample */
index = 0;
#pragma loop unroll
for(int i = 1; i < I2S_CHANS_ADC; i += 2)
{
p_i2s_adc[index++] :> sample;
#if NUM_USB_CHAN_IN > 0
samplesInPrev[i] = bitrev(sample);
#endif
}
#endif
}
return 0;
}
/* This function is a dummy version of the deliver thread that does not
connect to the codec ports. It is used during DFU reset. */
static unsigned dummy_deliver(chanend c_out) {
while (1)
{
outuint(c_out, 0);
/* Check for sample freq change or new samples from mixer*/
if(testct(c_out))
{
inct(c_out);
return inuint(c_out);
}
else
{
#ifndef MIXER // Interfaces straight to decouple()
(void) inuint(c_out);
#pragma loop unroll
for(int i = 0; i < NUM_USB_CHAN_IN; i++)
{
outuint(c_out, 0);
}
#pragma loop unroll
for(int i = 0; i < NUM_USB_CHAN_OUT; i++)
{
(void) inuint(c_out);
}
#else
#pragma loop unroll
for(int i = 0; i < NUM_USB_CHAN_OUT; i++)
{
(void) inuint(c_out);
}
#pragma loop unroll
for(int i = 0; i < NUM_USB_CHAN_IN; i++)
{
outuint(c_out, 0);
}
#endif
}
}
return 0;
}
void audio(chanend c_mix_out, chanend ?c_dig_rx, chanend ?c_config)
{
chan c_spdif_out;
unsigned curSamFreq = DEFAULT_FREQ;
unsigned mClk;
unsigned divide;
unsigned firstRun = 1;
#ifdef SPDIF
SpdifTransmitPortConfig(p_spdif_tx, clk_mst_spd, p_mclk);
#endif
/* Initialise master clock generation */
ClockingInit();
/* Perform required CODEC/ADC/DAC initialisation */
CodecInit(c_config);
while(1)
{
/* Calculate what master clock we should be using */
if ((curSamFreq % 22050) == 0)
{
mClk = MCLK_441;
}
else if ((curSamFreq % 24000) == 0)
{
mClk = MCLK_48;
}
/* Calculate divide required for bit clock e.g. 11.289600 / (176400 * 64) = 1 */
divide = mClk / ( curSamFreq * 64 );
/* Configure clocking for required master clock */
ClockingConfig(mClk);
if(!firstRun)
{
/* TODO wait for good mclk instead of delay */
/* No delay for DFU modes */
if ((curSamFreq != AUDIO_REBOOT_FROM_DFU) && (curSamFreq != AUDIO_STOP_FOR_DFU))
{
timer t;
unsigned time;
t :> time;
t when timerafter(time+AUDIO_PLL_LOCK_DELAY) :> void;
/* Handshake back */
outct(c_mix_out, XS1_CT_END);
}
}
firstRun = 0;
/* Configure CODEC/DAC/ADC for SampleFreq/MClk */
CodecConfig(curSamFreq, mClk, c_config);
/* Configure audio ports */
ConfigAudioPorts(divide);
par
{
#ifdef SPDIF
{ //set_thread_fast_mode_on();
SpdifTransmit(p_spdif_tx, c_spdif_out);
}
#endif
{
#ifdef SPDIF
/* Communicate master clock and sample freq to S/PDIF thread */
outuint(c_spdif_out, curSamFreq);
outuint(c_spdif_out, mClk);
#endif
curSamFreq = deliver(c_mix_out, c_spdif_out, divide, c_dig_rx);
// Currently no more audio will happen after this point
if (curSamFreq == AUDIO_STOP_FOR_DFU)
{
outct(c_mix_out, XS1_CT_END);
while (1)
{
curSamFreq = dummy_deliver(c_mix_out);
if (curSamFreq == AUDIO_START_FROM_DFU)
{
outct(c_mix_out, XS1_CT_END);
break;
}
}
}
#ifdef SPDIF
/* Notify S/PDIF thread of impending new freq... */
outct(c_spdif_out, XS1_CT_END);
#endif
}
}
}
}

View File

@@ -0,0 +1,17 @@
#ifndef _AUDIOSTREAM_H_
#define _AUDIOSTREAM_H_
/* Functions that handle functions that must occur on stream start/stop e.g. DAC mute/un-mute
*
* THESE NEED IMPLEMENTING FOR A SPECIFIC DESIGN
*
* */
/* Any actions required for stream start e.g. DAC un-mute - run every stream start */
void AudioStreamStart(void);
/* Any actions required on stream stop e.g. DAC mute - run every steam stop */
void AudioStreamStop(void);
#endif

View File

@@ -0,0 +1,30 @@
#include "devicedefines.h"
/* Clocking commands - c_clk_ctl */
#define GET_SEL 0 /* Get value of clock selector */
#define SET_SEL 1 /* Set value of clock selector */
#define GET_FREQ 2 /* Get current freq */
#define GET_VALID 3 /* Get current validity */
#define CLOCK_INTERNAL 1
#define CLOCK_SPDIF 2
#ifdef SPDIF_RX
#define CLOCK_ADAT 3
#else
#define CLOCK_ADAT 2
#endif
#define CLOCK_INTERNAL_INDEX (CLOCK_INTERNAL - 1)
#define CLOCK_ADAT_INDEX (CLOCK_ADAT - 1)
#define CLOCK_SPDIF_INDEX (CLOCK_SPDIF - 1)
#define SET_SMUX 7
/* c_audioControl */
#define SET_SAMPLE_FREQ 4
#define SET_CHAN_COUNT_IN 5
#define SET_CHAN_COUNT_OUT 6

View File

@@ -0,0 +1,797 @@
#include <xs1.h>
#include <assert.h>
#include <print.h>
#include "devicedefines.h"
#include "clockcmds.h"
#include "SpdifReceive.h"
#ifdef SPDIF_RX
#pragma xta command "analyse path digital_out digital_out"
#pragma xta command "set required - 5200 ns" /* 192kHz */
#endif
#define LOCAL_CLOCK_INCREMENT 166667
#define LOCAL_CLOCK_MARGIN 1666
#define MAX_SAMPLES 64 /* Must be power of 2 */
#define MAX_SPDIF_SAMPLES (2 * MAX_SAMPLES) /* Must be power of 2 */
#define MAX_ADAT_SAMPLES (8 * MAX_SAMPLES) /* Must be power of 2 */
#define SPDIF_FRAME_ERRORS_THRESH 40
unsigned g_digData[10];
typedef struct
{
int receivedSamples;
int samples;
int savedSamples;
int lastDiff;
unsigned identicaldiffs;
int samplesPerTick;
} Counter;
static int clockFreq[NUM_CLOCKS]; /* Store current clock freq for each clock unit */
static int clockValid[NUM_CLOCKS]; /* Store current validity of each clock unit */
static int clockInt[NUM_CLOCKS]; /* Interupt flag for clocks */
static int clockId[NUM_CLOCKS];
int abs(int x)
{
if (x < 0) return -x;
return x;
}
int channelContainsControlToken(chanend x)
{
unsigned char tmpc;
select
{
case inct_byref(x, tmpc):
return 1;
default:
return 0;
}
}
void outInterrupt(chanend c_interruptControl, int value)
{
/* Non-blocking check for control token */
//if (channelContainsControlToken(c_interruptControl))
{
outuint(c_interruptControl, value);
outct(c_interruptControl, XS1_CT_END);
}
}
#ifdef CLOCK_VALIDITY_CALL
void VendorClockValidity(int valid);
#endif
#if defined(SPDIF_RX) || defined(ADAT_RX)
static inline void setClockValidity(chanend c_interruptControl, int clkIndex, int valid, int currentClkMode)
{
if (clockValid[clkIndex] != valid)
{
clockValid[clkIndex] = valid;
outInterrupt(c_interruptControl, clockId[clkIndex]);
#ifdef CLOCK_VALIDITY_CALL
#ifdef ADAT_RX
if (currentClkMode == CLOCK_ADAT && clkIndex == CLOCK_ADAT_INDEX)
{
VendorClockValidity(valid);
}
#endif
#ifdef SPDIF_RX
if (currentClkMode == CLOCK_SPDIF && clkIndex == CLOCK_SPDIF_INDEX)
{
VendorClockValidity(valid);
}
#endif
#endif
}
}
/* Returns 1 for valid clock found else 0 */
static inline int validSamples(Counter &counter, int clockIndex)
{
int diff = counter.samples - counter.savedSamples;
counter.savedSamples = counter.samples;
/* Check for stable sample rate (with some small margin) */
if (diff != 0 && abs( diff - counter.lastDiff ) < 5 )
{
counter.identicaldiffs++;
if (counter.identicaldiffs > 10)
{
/* Detect current sample rate (round to nearest) */
int s = -1;
if (diff > 137 && diff < 157)
{
s = 147;
}
else if (diff > 150 && diff < 170)
{
s = 160;
}
else if(diff > 284 && diff < 304)
{
s = 294;
}
else if (diff > 310 && diff < 330)
{
s = 320;
}
else if (diff > 578 && diff < 598)
{
s = 588;
}
else if (diff > 630 && diff < 650)
{
s = 640;
}
/* Check if we found a valid freq */
if (s != -1)
{
/* Update expected samples per tick */
counter.samplesPerTick = s;
/* Update record of external clock source sample frequency */
s *= 300;
if (clockFreq[clockIndex] != s)
{
clockFreq[clockIndex] = s;
}
return 1;
}
else
{
/* Not a valid frequency - Reset counter and find another run of samples */
counter.identicaldiffs = 0;
}
}
}
else
{
counter.identicaldiffs = 0;
counter.lastDiff = diff;
}
return 0;
}
#endif
#ifdef SPDIF_RX
//:badParity
/* Returns 1 for bad parity, else 0 */
static inline int badParity(unsigned x)
{
unsigned X = (x>>4);
crc32(X, 0, 1);
return X & 1;
}
//:
#endif
#ifdef LEVEL_METER_LEDS
void VendorLedRefresh(unsigned levelData[]);
unsigned g_inputLevelData[NUM_USB_CHAN_IN];
extern int samples_to_host_inputs[NUM_USB_CHAN_IN];
extern int samples_to_host_inputs_buff[NUM_USB_CHAN_IN]; /* Audio transmitted to host i.e. dev inputs */
#endif
int VendorAudCoreReqs(unsigned cmd, chanend c);
#pragma unsafe arrays
void clockGen (streaming chanend c_spdif_rx, chanend c_adat_rx, out port p, chanend c_dig_rx, chanend c_clk_ctl, chanend c_clk_int)
{
timer t_local;
unsigned timeNextEdge, timeLastEdge, timeNextClockDetection;
unsigned pinVal = 0;
unsigned short pinTime;
unsigned clkMode = CLOCK_INTERNAL; /* Current clocking mode in operation */
unsigned tmp;
/* start in no-SMUX (8-channel) mode */
int smux = 0;
#ifdef LEVEL_METER_LEDS
timer t_level;
unsigned levelTime;
#endif
#if defined(SPDIF_RX) || defined(ADAT_RX)
timer t_external;
#endif
#ifdef SPDIF_RX
/* S/PDIF buffer state */
int spdifSamples[MAX_SPDIF_SAMPLES]; /* S/PDIF sample buffer */
int spdifWr = 0; /* Write index */
int spdifRd = 0; /* Read index */ //(spdifWriteIndex ^ (MAX_SPDIF_SAMPLES >> 1)) & ~1; // Start in middle
int spdifOverflow = 0; /* Overflow/undeflow flags */
int spdifUnderflow = 1;
int spdifSamps = 0; /* Number of samples in buffer */
Counter spdifCounters;
int spdifReceivedTime;
unsigned tmp2;
unsigned spdifLeft = 0;
#endif
#ifdef ADAT_RX
/* ADAT buffer state */
int adatSamples[MAX_ADAT_SAMPLES];
int adatWr = 0;
int adatRd = 0;
int adatOverflow = 0;
int adatUnderflow = 1;
//int adatFrameErrors = 0;
int adatSamps = 0;
Counter adatCounters;
int adatReceivedTime;
unsigned adatFrame[8];
int adatChannel = 0;
int adatSamplesEver = 0;
#endif
for(int i = 0; i < 10; i++)
{
g_digData[i] = 0;
}
/* Init clock unit state */
#ifdef SPDIF_RX
clockFreq[CLOCK_SPDIF_INDEX] = 0;
clockValid[CLOCK_SPDIF_INDEX] = 0;
clockInt[CLOCK_SPDIF_INDEX] = 0;
clockId[CLOCK_SPDIF_INDEX] = ID_CLKSRC_EXT;
#endif
clockFreq[CLOCK_INTERNAL_INDEX] = 0;
clockId[CLOCK_INTERNAL_INDEX] = ID_CLKSRC_INT;
clockValid[CLOCK_INTERNAL_INDEX] = 0;
clockInt[CLOCK_INTERNAL_INDEX] = 0;
#ifdef ADAT_RX
clockFreq[CLOCK_ADAT_INDEX] = 0;
clockInt[CLOCK_ADAT_INDEX] = 0;
clockValid[CLOCK_ADAT_INDEX] = 0;
clockId[CLOCK_ADAT_INDEX] = ID_CLKSRC_ADAT;
#endif
#ifdef SPDIF_RX
spdifCounters.receivedSamples = 0;
spdifCounters.samples = 0;
spdifCounters.savedSamples = 0;
spdifCounters.lastDiff = 0;
spdifCounters.identicaldiffs = 0;
spdifCounters.samplesPerTick = 0;
#endif
#ifdef ADAT_RX
adatCounters.receivedSamples = 0;
adatCounters.samples = 0;
adatCounters.savedSamples = 0;
adatCounters.lastDiff = 0;
adatCounters.identicaldiffs = 0;
adatCounters.samplesPerTick = 0;
#endif
t_local :> timeNextEdge;
timeLastEdge = timeNextEdge;
timeNextClockDetection = timeNextEdge + (LOCAL_CLOCK_INCREMENT / 2);
timeNextEdge += LOCAL_CLOCK_INCREMENT;
#ifdef LEVEL_METER_LEDS
t_level :> levelTime;
levelTime+= LEVEL_UPDATE_RATE;
#endif
#if defined(SPDIF_RX) || defined(ADAT_RX)
/* Fill channel */
outuint(c_dig_rx, 1);
#endif
/* Initial ref clock output and get timestamp */
p <: pinVal @ pinTime;
pinTime += (unsigned short)(LOCAL_CLOCK_INCREMENT - (LOCAL_CLOCK_INCREMENT/2));
p @ pinTime <: pinVal;
while(1)
{
select
{
#ifdef LEVEL_METER_LEDS
#warning Level metering enabled
case t_level when timerafter(levelTime) :> void:
levelTime += LEVEL_UPDATE_RATE;
/* Copy over level data and reset */
for(int i = 0; i< NUM_USB_CHAN_IN; i++)
{
int tmp;
//g_inputLevelData[i] = samples_to_host_inputs[i];
asm("ldw %0, %1[%2]":"=r"(tmp):"r"(samples_to_host_inputs),"r"(i));
g_inputLevelData[i] = tmp;
//samples_to_host_inputs[i] = 0;
asm("stw %0, %1[%2]"::"r"(0),"r"(samples_to_host_inputs),"r"(i));
/* Guard against host polling slower than timer and missing peaks */
if(g_inputLevelData[i] > samples_to_host_inputs_buff[i])
{
samples_to_host_inputs_buff[i] = g_inputLevelData[i];
}
}
/* Call user LED refresh */
VendorLedRefresh(g_inputLevelData);
break;
#endif
/* Updates to clock settings from endpoint 0 */
case inuint_byref(c_clk_ctl, tmp):
switch(tmp)
{
case GET_SEL:
chkct(c_clk_ctl, XS1_CT_END);
/* Send back current clock mode */
outuint(c_clk_ctl, clkMode);
outct(c_clk_ctl, XS1_CT_END);
break;
case SET_SEL:
/* Update clock mode */
tmp = inuint(c_clk_ctl);
chkct(c_clk_ctl, XS1_CT_END);
if(tmp!=0)
{
clkMode = tmp;
}
#ifdef CLOCK_VALIDITY_CALL
switch(clkMode)
{
case CLOCK_INTERNAL:
VendorClockValidity(1);
break;
#ifdef ADAT_RX
case CLOCK_ADAT:
VendorClockValidity(clockValid[CLOCK_ADAT_INDEX]);
break;
#endif
#ifdef SPDIF_RX
case CLOCK_SPDIF:
VendorClockValidity(clockValid[CLOCK_SPDIF_INDEX]);
break;
#endif
}
#endif
break;
case GET_VALID:
/* Clock Unit Index */
tmp = inuint(c_clk_ctl);
chkct(c_clk_ctl, XS1_CT_END);
outuint(c_clk_ctl, clockValid[tmp]);
outct(c_clk_ctl, XS1_CT_END);
break;
case GET_FREQ:
tmp = inuint(c_clk_ctl);
chkct(c_clk_ctl, XS1_CT_END);
outuint(c_clk_ctl, clockFreq[tmp]);
outct(c_clk_ctl, XS1_CT_END);
break;
case SET_SMUX:
smux = inuint(c_clk_ctl);
#ifdef ADAT_RX
adatRd = 0; /* Reset adat FIFO */
adatWr = 0;
adatSamps = 0;
#endif
chkct(c_clk_ctl, XS1_CT_END);
break;
default:
#ifdef VENDOR_AUDCORE_REQS
if(VendorAudCoreReqs(tmp, c_clk_ctl))
#endif
printstrln("ERR: Bad req in clockgen\n");
break;
}
break;
/* Generate local clock from timer */
case t_local when timerafter(timeNextEdge) :> void:
/* Setup next local clock edge */
pinTime += (short) LOCAL_CLOCK_INCREMENT;
pinVal = !pinVal;
p @ pinTime <: pinVal;
/* Record time of edge */
timeLastEdge = timeNextEdge;
/* Setup for next edge */
timeNextClockDetection = timeNextEdge + (LOCAL_CLOCK_INCREMENT/2);
timeNextEdge += LOCAL_CLOCK_INCREMENT;
/* If we are in an external clock mode and this fire, then clock invalid */
#ifdef SPDIF_RX
// if(clkMode == CLOCK_SPDIF)
{
/* We must have lost valid S/PDIF stream, reset counters, so we dont produce a double edge */
spdifCounters.receivedSamples = 0;
}
#endif
#ifdef ADAT_RX
//if(clkMode == CLOCK_ADAT)
{
adatCounters.receivedSamples = 0;
}
#endif
#ifdef CLOCK_VALIDITY_CALL
if(clkMode == CLOCK_INTERNAL)
{
/* Internal clock always valid */
VendorClockValidity(1);
}
#endif
break;
#if defined(SPDIF_RX) || defined(ADAT_RX)
case t_external when timerafter(timeNextClockDetection) :> void:
timeNextClockDetection += (LOCAL_CLOCK_INCREMENT);
#ifdef SPDIF_RX
tmp = spdifCounters.samplesPerTick;
/* Returns 1 if valid clock found */
tmp = validSamples(spdifCounters, CLOCK_SPDIF_INDEX);
setClockValidity(c_clk_int, CLOCK_SPDIF_INDEX, tmp, clkMode);
#endif
#ifdef ADAT_RX
tmp = validSamples(adatCounters, CLOCK_ADAT_INDEX);
setClockValidity(c_clk_int, CLOCK_ADAT_INDEX, tmp, clkMode);
#endif
break;
#endif
#ifdef SPDIF_RX
/* Receive sample from S/PDIF RX thread (steaming chan) */
case c_spdif_rx :> tmp:
/* Record time of sample */
t_local :> spdifReceivedTime;
/* Check parity and ignore if bad */
if(badParity(tmp))
continue;
/* Get pre-amble */
tmp2 = tmp & 0xF;
switch(tmp2)
{
/* LEFT */
case FRAME_X:
case FRAME_Z:
spdifLeft = tmp << 4;
break;
/* RIGHT */
case FRAME_Y:
/* Only store sample if not in overflow and stream is reasonably valid */
if(!spdifOverflow && clockValid[CLOCK_SPDIF_INDEX])
{
/* Store left and right sample pair to buffer */
spdifSamples[spdifWr] = spdifLeft;
spdifSamples[spdifWr+1] = tmp << 4;
spdifWr = (spdifWr + 2) & (MAX_SPDIF_SAMPLES - 1);
spdifSamps += 2;
/* Check for over flow */
if(spdifSamps > MAX_SPDIF_SAMPLES-1)
{
spdifOverflow = 1;
}
/* Check for coming out of under flow */
if(spdifUnderflow && (spdifSamps >= (MAX_SPDIF_SAMPLES >> 1)))
{
spdifUnderflow = 0;
}
}
break;
default:
/* Bad sample, skip */
continue;
break;
}
spdifCounters.samples += 1;
if(clkMode == CLOCK_SPDIF && clockValid[CLOCK_SPDIF_INDEX])
{
spdifCounters.receivedSamples+=1;
/* Inspect for if we need to produce an edge */
if((spdifCounters.receivedSamples >= spdifCounters.samplesPerTick))
{
/* Check edge is about right... S/PDIF may have changed freq... */
if(timeafter(spdifReceivedTime, (timeLastEdge + LOCAL_CLOCK_INCREMENT - LOCAL_CLOCK_MARGIN)))
{
/* Record edge time */
timeLastEdge = spdifReceivedTime;
/* Setup for next edge */
timeNextEdge = spdifReceivedTime + LOCAL_CLOCK_INCREMENT + LOCAL_CLOCK_MARGIN;
/* Toggle edge */
p <: pinVal @ pinTime;
pinTime += (short) LOCAL_CLOCK_INCREMENT;
pinVal = !pinVal;
p @ pinTime <: pinVal;
/* Reset counters */
spdifCounters.receivedSamples = 0;
}
}
}
break;
#endif
#ifdef ADAT_RX
/* receive sample from ADAT rx thread (streaming channel with CT_END) */
case inuint_byref(c_adat_rx, tmp):
/* record time of sample */
t_local :> adatReceivedTime;
/* Sync is: 1 | (user_byte << 4) */
if(tmp&1)
{
/* user bits - start of frame */
adatChannel = 0;
continue;
}
else
{
/* audio sample */
adatSamplesEver++;
adatFrame[adatChannel] = tmp;
adatChannel++;
if (adatChannel == 8)
{
/* only store left samples if not in overflow and stream is reasonably valid */
if (!adatOverflow && clockValid[CLOCK_ADAT_INDEX])
{
if(smux)
{
adatSamples[adatWr + 0] = adatFrame[0];
adatSamples[adatWr + 4] = adatFrame[1];
adatSamples[adatWr + 1] = adatFrame[2];
adatSamples[adatWr + 5] = adatFrame[3];
adatSamples[adatWr + 2] = adatFrame[4];
adatSamples[adatWr + 6] = adatFrame[5];
adatSamples[adatWr + 3] = adatFrame[6];
adatSamples[adatWr + 7] = adatFrame[7];
}
else
{
adatSamples[adatWr + 0] = adatFrame[0];
adatSamples[adatWr + 1] = adatFrame[1];
adatSamples[adatWr + 2] = adatFrame[2];
adatSamples[adatWr + 3] = adatFrame[3];
adatSamples[adatWr + 4] = adatFrame[4];
adatSamples[adatWr + 5] = adatFrame[5];
adatSamples[adatWr + 6] = adatFrame[6];
adatSamples[adatWr + 7] = adatFrame[7];
}
adatWr = (adatWr + 8) & (MAX_ADAT_SAMPLES - 1);
adatSamps += 8;
/* check for overflow */
if (adatSamps > MAX_ADAT_SAMPLES - 1)
{
adatOverflow = 1;
}
/* check for coming out of underflow */
if (adatUnderflow && (adatSamps >= (MAX_ADAT_SAMPLES >> 1)))
{
adatUnderflow = 0;
}
}
}
if(adatChannel == 4 || adatChannel == 8)
{
adatCounters.samples += 1;
if (clkMode == CLOCK_ADAT && clockValid[CLOCK_ADAT_INDEX])
{
adatCounters.receivedSamples += 1;
/* Inspect for if we need to produce an edge */
if ((adatCounters.receivedSamples >= adatCounters.samplesPerTick))
{
/* Check edge is about right... S/PDIF may have changed freq... */
if (timeafter(adatReceivedTime, (timeLastEdge + LOCAL_CLOCK_INCREMENT - LOCAL_CLOCK_MARGIN)))
{
/* Record edge time */
timeLastEdge = adatReceivedTime;
/* Setup for next edge */
timeNextEdge = adatReceivedTime + LOCAL_CLOCK_INCREMENT + LOCAL_CLOCK_MARGIN;
/* Toggle edge */
p <: pinVal @ pinTime;
pinTime += LOCAL_CLOCK_INCREMENT;
pinVal = !pinVal;
p @ pinTime <: pinVal;
/* Reset counters */
adatCounters.receivedSamples = 0;
}
}
}
}
if (adatChannel == 8)
adatChannel = 0;
}
break;
#endif
#if defined(SPDIF_RX) || defined(ADAT_RX)
/* Mixer requests data */
case inuint_byref(c_dig_rx, tmp):
#ifdef SPDIF_RX
if(spdifUnderflow)
{
/* S/PDIF underflowing, send out zero samples */
g_digData[0] = 0;
g_digData[1] = 0;
}
else
{
/* Read out samples from S/PDIF buffer and send... */
tmp = spdifSamples[spdifRd];
tmp2 = spdifSamples[spdifRd + 1];
spdifRd += 2;
spdifRd &= (MAX_SPDIF_SAMPLES - 1);
#pragma xta endpoint "digital_out"
g_digData[0] = tmp;
g_digData[1] = tmp2;
spdifSamps -= 2;
/* spdifSamps could go to -1 */
if(spdifSamps < 0)
{
/* We're out of S/PDIF samples, mark underflow condition */
spdifUnderflow = 1;
spdifLeft = 0;
}
/* If we are in over flow condition and we have a sensible number of samples
* come out of overflow condition */
if(spdifOverflow && (spdifSamps < (MAX_SPDIF_SAMPLES>>1)))
{
spdifOverflow = 0;
}
}
#endif
#ifdef ADAT_RX
if (adatUnderflow)
{
/* ADAT underflowing, send out zero samples */
g_digData[2] = 0;
g_digData[3] = 0;
g_digData[4] = 0;
g_digData[5] = 0;
g_digData[6] = 0;
g_digData[7] = 0;
g_digData[8] = 0;
g_digData[9] = 0;
}
else
{
/* TODO SMUX II mode */
/* read out samples from the ADAT buffer and send */
/* always return 8 samples */
if (smux)
{
/* SMUX mode - 4 samples from fifo and 4 zero samples */
g_digData[2] = adatSamples[adatRd + 0];
g_digData[3] = adatSamples[adatRd + 1];
g_digData[4] = adatSamples[adatRd + 2];
g_digData[5] = adatSamples[adatRd + 3];
g_digData[6] = 0;
g_digData[7] = 0;
g_digData[8] = 0;
g_digData[9] = 0;
adatRd = (adatRd + 4) & (MAX_ADAT_SAMPLES - 1);
adatSamps -= 4;
}
else
{
/* no SMUX mode - 8 samples from fifo */
g_digData[2] = adatSamples[adatRd + 0];
g_digData[3] = adatSamples[adatRd + 1];
g_digData[4] = adatSamples[adatRd + 2];
g_digData[5] = adatSamples[adatRd + 3];
g_digData[6] = adatSamples[adatRd + 4];
g_digData[7] = adatSamples[adatRd + 5];
g_digData[8] = adatSamples[adatRd + 6];
g_digData[9] = adatSamples[adatRd + 7];
adatRd = (adatRd + 8) & (MAX_ADAT_SAMPLES - 1);
adatSamps -= 8;
}
/* adatSamps could go to -1 */
if (adatSamps < 0)
{
/* we're out of ADAT samples, mark underflow condition */
adatUnderflow = 1;
}
/* if we are in overflow condition and have a sensible number of samples
come out of overflow condition */
if (adatOverflow && adatSamps < (MAX_ADAT_SAMPLES >> 1))
{
adatOverflow = 0;
}
}
#endif
outuint(c_dig_rx, 1);
break;
#endif
}
}
}

View File

@@ -0,0 +1,27 @@
#ifndef _CLOCKING_H_
#define _CLOCKING_H_
/* Functions that handle master clock generation. These need modifying for an existing design */
/* Any initialisation required for master clock generation - run once at start up */
void ClockingInit(void);
/* Configuration for a specific master clock frequency - run every sample frequency change */
void ClockingConfig(unsigned mClkFreq);
/** Clock generation and digital audio I/O handling.
*
* \param c_spdif_rx channel connected to S/PDIF receive thread
* \param c_adat_rx channel connect to ADAT receive thread
* \param p port to output clock signal to drive external frequency synthesizer
* \param c_audio channel connected to the audio() thread
* \param c_clk_ctl channel connected to Endpoint0() for configuration of the
* clock
* \param c_clk_int channel connected to the decouple() thread for clock
interrupts
*/
void clockGen (streaming chanend c_spdif_rx, chanend c_adat_rx, out port p, chanend c_audio, chanend c_clk_ctl, chanend c_clk_int);
#endif

View File

@@ -0,0 +1,14 @@
#ifndef _CODEC_H_
#define _CODEC_H_
/* These functions must be implemented for the CODEC/ADC/DAC arrangement of a specific design */
/* TODO Are the channel args required? */
/* Any required CODEC initialisation - run once at start up */
void CodecInit(chanend ?c_codec);
/* Configure condec for a specific mClk/Sample frquency - run on every sample frequency change */
void CodecConfig(unsigned samFreq, unsigned mClk, chanend ?c_codec);
#endif

View File

@@ -0,0 +1,144 @@
/**
* @file dbtable.h
* @brief 128 entry + neg inf db table from -inf to 0xffffffff
* @author Ross Owen, XMOS Semiconductor
* @version 1.0
*/
#ifndef _DBTABLE_
#define _DBTABLE_
static unsigned dbTable[129] =
{
4294967295, /* 0 -> 0xffffffff */
3827893631,
3411613790,
3040603991,
2709941159,
2415237600,
2152582777,
1918491420,
1709857277,
1523911903,
1358187913,
1210486251,
1078847007,
961523407,
856958639,
763765191,
680706443,
606680256,
540704347,
481903257,
429496729,
382789363,
341161379,
304060399,
270994116,
241523760,
215258278,
191849142,
170985728,
152391190,
135818791,
121048625,
107884701,
96152341,
85695864,
76376519,
68070644,
60668026,
54070435,
48190326,
42949673,
38278936,
34116138,
30406040,
27099412,
24152376,
21525828,
19184914,
17098573,
15239119,
13581879,
12104863,
10788470,
9615234,
8569586,
7637652,
6807064,
6066803,
5407043,
4819033,
4294967,
3827894,
3411614,
3040604,
2709941,
2415238,
2152583,
1918491,
1709857,
1523912,
1358188,
1210486,
1078847,
961523,
856959,
763765,
680706,
606680,
540704,
481903,
429497,
382789,
341161,
304060,
270994,
241524,
215258,
191849,
170986,
152391,
135819,
121049,
107885,
96152,
85696,
76377,
68071,
60668,
54070,
48190,
42950,
38279,
34116,
30406,
27099,
24152,
21526,
19185,
17099,
15239,
13582,
12105,
10788,
9615,
8570,
7638,
6807,
6067,
5407,
4819,
4295,
3828,
3412,
3041,
2710,
2415,
2153,
1918,
0 // -0x8000
};
#endif

View File

@@ -0,0 +1,343 @@
/**
* @file internaldefines.h
* @brief Defines relating to device configuration and customisation.
* @author Ross Owen, XMOS Limited
*/
#ifndef _DEVICEDEFINES_H_
#define _DEVICEDEFINES_H_
#include "customdefines.h"
/* Tidy up historical INPUT/OUTPUT defines. INPUT/OUTPUT now enabled based on channel count defines */
#if !defined(NUM_USB_CHAN_IN)
#error NUM_USB_CHAN_IN must be defined!
#else
#if (NUM_USB_CHAN_IN == 0)
#undef INPUT
#else
#define INPUT 1
#endif
#endif
#if !defined(NUM_USB_CHAN_OUT)
#error NUM_USB_CHAN_OUT must be defined!
#else
#if (NUM_USB_CHAN_OUT == 0)
#undef OUTPUT
#else
#define OUTPUT 1
#endif
#endif
#if defined(MIDI) && (MIDI == 0)
#undef MIDI
#endif
#if defined(SPDIF) && (SPDIF == 0)
#undef SPDIF
#endif
#if defined(INPUT) && (INPUT == 0)
#undef INPUT
#endif
#if defined(OUTPUT) && (OUTPUT == 0)
#undef OUTPUT
#endif
#if defined(SPDIF_RX) && (SPDIF_RX == 0)
#undef SPDIF_RX
#endif
#if defined(ADAT_RX) && (ADAT_RX == 0)
#undef ADAT_RX
#endif
#if defined(DFU) && (DFU == 0)
#undef DFU
#endif
#if defined(CODEC_SLAVE) && (CODEC_SLAVE == 0)
#undef CODEC_SLAVE
#endif
#if defined(LEVEL_METER_LEDS) && !defined(LEVEL_UPDATE_RATE)
#define LEVEL_UPDATE_RATE 400000
#endif
#if(AUDIO_CLASS != 1) && (AUDIO_CLASS != 2)
#warning AUDIO_CLASS not defined, using 2
#define AUDIO_CLASS 2
#endif
/* Number of IS2 chans to DAC */
#ifndef I2S_CHANS_DAC
#error I2S_CHANS_DAC not defined
#else
#define I2S_WIRES_DAC (I2S_CHANS_DAC >> 1)
#endif
/* Number of I2S chans from ADC */
#ifndef I2S_CHANS_ADC
#error I2S_CHANS_ADC not defined
#else
#define I2S_WIRES_ADC (I2S_CHANS_ADC >> 1)
#endif
/* SPDIF and ADAT first input chan indices */
#ifdef SPDIF_RX
#ifndef SPDIF_RX_INDEX
#error SPDIF_RX_INDEX not defined and SPDIF_RX defined
#endif
#endif
#ifdef ADAT_RX
#ifndef ADAT_RX_INDEX
#error ADAT_RX_INDEX not defined and ADAT_RX defined
#endif
#endif
#ifndef SPDIF_TX_INDEX
#warning SPDIF_TX_INDEX not defined! Using 0
#define SPDIF_TX_INDEX (0)
#endif
/* Max supported freq for device */
#ifndef MAX_FREQ
#warning MAX_FREQ not defined! Using 48000
#define MAX_FREQ (48000)
#endif
/* Default device freq */
#ifndef DEFAULT_FREQ
#warning DEFAULT not defined! Using MAX_FREQ
#define DEFAULT_FREQ (MAX_FREQ)
#endif
/* Master clock defines (in Hz) */
#ifndef MCLK_441
#error MCLK_441 not defined
#endif
#ifndef MCLK_48
#error MCLK_441 not defined
#endif
/* The number of clock ticks to wait for the audio PLL to lock */
#define AUDIO_PLL_LOCK_DELAY (40000000)
/* Vendor/Product strings */
#ifndef VENDOR_STR
#define VENDOR_STR "XMOS "
//#warning VENDOR_STR not defined. Using XMOS
#endif
#ifndef VENDOR_ID
#warning VENDOR_ID not defined. Using XMOS vendor ID
#define VENDOR_ID (0x20B1) /* XMOS VID */
#endif
#ifndef PID_AUDIO_1
#define PID_AUDIO_1 (0x0001)
#warning PRODUCT_ID not defined. Using 0x0001
#endif
#ifndef PID_AUDIO_2
#define PID_AUDIO_2 (0x0001)
#warning PRODUCT_ID not defined. Using 0x0001
#endif
/* Device release number in BCD: 0xJJMNi */
#ifndef BCD_DEVICE
#define BCD_DEVICE (0x0000)
#warning BCD_DEVICE not defined. Using 0x0000
#endif
/* Addition interfaces based on defines */
#if defined(DFU) && DFU != 0
#define DFU_INTERFACES (1) /* DFU interface count */
#else
#define DFU_INTERFACES (0)
#endif
#ifdef INPUT
#define INPUT_INTERFACES (1)
#else
#define INPUT_INTERFACES (0)
#endif
#if defined(OUTPUT) && OUTPUT != 0
#define OUTPUT_INTERFACES (1)
#else
#define OUTPUT_INTERFACES (0)
#endif
#if defined(MIDI)
#define MIDI_INTERFACES (2)
#else
#define MIDI_INTERFACES (0)
#endif
#define AUDIO_STOP_FOR_DFU (0x12345678)
#define AUDIO_START_FROM_DFU (0x87654321)
#define AUDIO_REBOOT_FROM_DFU (0xa5a5a5a5)
#define MAX_VOL (0x20000000)
#define NUM_EP_OUT 3 /* Max number of device endpoints used */
#define NUM_EP_IN 5
/* Length of clock unit/clock-selector units */
#if defined(SPDIF_RX) && defined(ADAT_RX)
#define NUM_CLOCKS 3
#elif defined(SPDIF_RX) || defined(ADAT_RX)
#define NUM_CLOCKS 2
#else
#define NUM_CLOCKS 1
#endif
/* Total number of USB interfaces this device implements (+1 for required control interface) */
#define NUM_INTERFACES INPUT_INTERFACES + OUTPUT_INTERFACES + DFU_INTERFACES + MIDI_INTERFACES + 1
/* Audio Unit ID defines */
#define FU_USBIN 11 /* Feature Unit: USB Audio device -> host */
#define FU_USBOUT 10 /* Feature Unit: USB Audio host -> device*/
#define ID_IT_USB 2 /* Input terminal: USB streaming */
#define ID_IT_AUD 1 /* Input terminal: Analogue input */
#define ID_OT_USB 22 /* Output terminal: USB streaming */
#define ID_OT_AUD 20 /* Output terminal: Analogue output */
#define ID_CLKSEL 40 /* Clock selector ID */
#define ID_CLKSRC_INT 41 /* Clock source ID (internal) */
#define ID_CLKSRC_EXT 42 /* Clock source ID (external) */
#define ID_CLKSRC_ADAT 43 /* Clock source ID (external) */
#define ID_XU_MIXSEL 50
#define ID_XU_OUT 51
#define ID_XU_IN 52
#define ID_MIXER_1 60
#ifndef SERIAL_STR
#define SERIAL_STR "0000" /* Serial number string */
#endif
#define SERIAL_STR_INDEX 0x03
#define MANUFACTURER_STR_INDEX 0x01
#define PRODUCT_STR_INDEX 0x02
/* Mixer defines */
#ifndef MIX_INPUTS
#define MIX_INPUTS 18
#endif
#ifndef MAX_MIX_COUNT
#define MAX_MIX_COUNT 8
#endif
/* Volume defines */
#ifndef MIN_VOLUME
/* The minimum volume setting above -inf. This is a signed 8.8 fixed point
number that must be strictly greater than -128 (0x8000) */
/* Default min volume is -127db */
#define MIN_VOLUME (0x8100)
#endif
#ifndef MAX_VOLUME
/* The maximum volume setting. This is a signed 8.8 fixed point number. */
/* Default max volume is 0db */
#define MAX_VOLUME (0x0000)
#endif
#ifndef VOLUME_RES
/* The resolution of the volume control in db as a 8.8 fixed point number */
/* Default volume resolution 1db */
#define VOLUME_RES (0x100)
#endif
#ifndef MIN_MIXER_VOLUME
/* The minimum volume setting for the mixer unit above -inf.
This is a signed 8.8 fixed point
number that must be strictly greater than -128 (0x8000) */
/* Default min volume is -127db */
#define MIN_MIXER_VOLUME (0x8100)
#endif
#ifndef MAX_MIXER_VOLUME
/* The maximum volume setting for the mixer.
This is a signed 8.8 fixed point number. */
/* Default max volume is 0db */
#define MAX_MIXER_VOLUME (0x0000)
#endif
#ifndef VOLUME_RES_MIXER
/* The resolution of the volume control in db as a 8.8 fixed point number */
/* Default volume resolution 1db */
#define VOLUME_RES_MIXER (0x100)
#endif
/* Handle out volume control in the mixer */
#if defined(OUT_VOLUME_IN_MIXER) && (OUT_VOLUME_IN_MIXER==0)
#undef OUT_VOLUME_IN_MIXER
#else
#if defined(MIXER)
// Enabled by default
#define OUT_VOLUME_IN_MIXER
#endif
#endif
/* Apply out volume controls after the mix */
#if defined(OUT_VOLUME_AFTER_MIX) && (OUT_VOLUME_AFTER_MIX==0)
#undef OUT_VOLUME_AFTER_MIX
#else
#if defined(MIXER) && defined(OUT_VOLUME_IN_MIXER)
// Enabled by default
#define OUT_VOLUME_AFTER_MIX
#endif
#endif
/* Define for reporting as self or bus-powered to the host */
#if defined(SELF_POWERED) && (SELF_POWERED==0)
#undef SELF_POWERED
#endif
/* Handle in volume control in the mixer */
#if defined(IN_VOLUME_IN_MIXER) && (IN_VOLUME_IN_MIXER==0)
#undef IN_VOLUME_IN_MIXER
#else
#if defined(MIXER)
/* Enabled by default */
#define IN_VOLUME_IN_MIXER
#endif
#endif
/* Apply in volume controls after the mix */
#if defined(IN_VOLUME_AFTER_MIX) && (IN_VOLUME_AFTER_MIX==0)
#undef IN_VOLUME_AFTER_MIX
#else
#if defined(MIXER) && defined(IN_VOLUME_IN_MIXER)
// Enabled by default
#define IN_VOLUME_AFTER_MIX
#endif
#endif
#if defined(AUDIO_CLASS_FALLBACK) && (AUDIO_CLASS_FALLBACK==0)
#undef AUDIO_CLASS_FALLBACK
#endif
/* Defines for DFU */
#ifndef PID_DFU
#define PID_DFU PID_AUDIO_2
#endif
#define DFU_VENDOR_ID VENDOR_ID
#define DFU_BCD_DEVICE BCD_DEVICE
#define DFU_SERIAL_STR_INDEX SERIAL_STR_INDEX
#define DFU_MANUFACTURER_INDEX MANUFACTURER_STR_INDEX
#define DFU_PRODUCT_INDEX PRODUCT_STR_INDEX
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,20 @@
#ifndef __dbcalc_h__
#define __dbcalc_h__
/* Function: db_to_mult
This function converts decibels into a volume multiplier. It uses a fixed-point polynomial approximation
to 10^(db/10).
Parameters:
db - The db value to convert.
db_frac_bits - The number of binary fractional bits in the supplied decibel value
result_frac_bits - The number of required fractional bits in the result.
Returns:
The multiplier value as a fixed point value with the number of fractional bits as specified by
the result_frac_bits parameter.
*/
unsigned db_to_mult(int db, int db_frac_bits, int result_frac_bits);
#endif // __dbcalc_h__

View File

@@ -0,0 +1,127 @@
#include <xs1.h>
#include <print.h>
/* The coefficients of the chebychev polynomial to approximate 10^x in the interval [-1,1].
This polynomial was calculated using the mpmath library in Python:
from mpmath import *
mp.dps = 15
mp.pretty = True
poly, err = chebyfit(lambda x: pow(10,x), [-1,1], 14, error=True)
nprint([int(x * pow(2,28)) for x in poly])
*/
#define COEF_PREC 28
static unsigned coef[14] = {2407, 13778, 64588, 308051, 1346110, 5261991, 18277531, 55564576, 144789513, 314406484, 546179875, 711608713, 618095479, 268435456};
#define DB_CALC_PREC 28
/* Function: db_to_mult
This function converts decibels into a volume multiplier. It uses a fixed-point polynomial approximation
to 10^(db/10).
Parameters:
db - The db value to convert.
db_frac_bits - The number of binary fractional bits in the supplied decibel value
result_frac_bits - The number of required fractional bits in the result.
Returns:
The multiplier value as a fixed point value with the number of fractional bits as specified by
the result_frac_bits parameter.
*/
unsigned db_to_mult(int db, int db_frac_bits, int result_frac_bits)
{
int intpart;
int val = 0;
int val0=0;
unsigned ret;
unsigned mask = ~((1<<DB_CALC_PREC)-1);
/* Make sure we get 0db bang on */
if (db == 0)
return (1 << result_frac_bits);
/* First scale the decibal value to the required precision and divide by 10
We scale to DB_CALC_PREC - 4 before the division with to make sure we don't overflow */
db = db << (DB_CALC_PREC - 4 - 1 - db_frac_bits);
db = db / 10;
db = db << 4;
/* Extract the integer part of the exponent and calculate the integer power */
/* This could have been done a bit more efficiently by extracting the largest multiple log_10(2)
and then calculating a power of 2 (with the polynomial calc in the range [-log_10(2),log_10(2)].
But we have something that works here and ultra-fast performance is not a requirement */
if (db < 0) {
intpart = ((-db) & mask);
db = db + intpart;
intpart = intpart >> DB_CALC_PREC;
if (intpart) {
val0 = 1 << DB_CALC_PREC;
for (int i=0;i<intpart;i++)
val0 = val0/10;
}
}
else {
intpart = (db & mask);
db = db - intpart;
intpart = intpart >> DB_CALC_PREC;
if (intpart) {
val0 = 1 << DB_CALC_PREC;
for (int i=0;i<intpart;i++)
val0 = val0*10;
}
}
/* db is now just the fractional part in the interval [-1,1] so we can approximate using
the chebychev polynomial */
for (int i=0;i<14;i++)
{
int hi=0;
unsigned lo=0;
{hi, lo} = macs(db,val,hi,lo);
val = (hi << (32-DB_CALC_PREC)) | (lo >> DB_CALC_PREC);
val += coef[i] >> (COEF_PREC - DB_CALC_PREC);
}
/* Finally multiply by the integer power (if there was an integer part) */
if (val0) {
int hi=0;
unsigned lo=0;
{hi, lo} = macs(val0,val,hi,lo);
val = (hi << (32-DB_CALC_PREC)) | (lo >> DB_CALC_PREC);
}
/* We now have the result, just need to scale it to the required precision */
ret = val;
if (result_frac_bits > DB_CALC_PREC) {
return ret<<(result_frac_bits-DB_CALC_PREC);
}
else {
return ret>>(DB_CALC_PREC-result_frac_bits);
}
}
#ifdef TEST_DBCALC
#include <print.h>
int main() {
/* Check that we don't overflow up to 9db
Should give a value just under 0x80000 */
printhexln(db_to_mult(9,0,16));
/* This test recreates the old db lookup table */
printuintln(0xffffffff);
for (int i=1;i<128;i++) {
printuintln(db_to_mult(-i,0,32));
}
return 0;
}
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,58 @@
Descriptors in XMOS USB Audio
=============================
ADAT Alternate Settings
-----------------------
6 interfaces
endpoint can only be shared between alternate settings of the same interface (not between interfaces)
change alternate settings via SET_INTERFACE request
an alternate setting has its' own interface and endpoint descriptors
+-----------+------+-------+----------------+--------------------------------------------------+
| interface | type | alt. | endps. | note |
+-----------+------+-------+----------------+--------------------------------------------------+
| 0 | AC | irq_in | |
+-----------+------+-------+----------------+--------------------------------------------------+
| 1 | AS | 0 | | null interface |
| | +-------+----------------+--------------------------------------------------+
| | | 1 | iso_out iso_in | 18 channels, host -> device, iso_in is feedback |
| | +-------+----------------+--------------------------------------------------+
| | | 2 | shared | 18 channels |
+-----------+------+-------+----------------+--------------------------------------------------+
| 2 | AS | 0 | | null interface |
| | +-------+----------------+--------------------------------------------------+
| | | 1 | iso_in | 18 channels, device -> host |
| | +-------+----------------+--------------------------------------------------+
| | | 2 | shared | 14 channels |
+-----------+------+-------+----------------+--------------------------------------------------+
| 3 | AC | | MIDI |
+-----------+------+-------+----------------+--------------------------------------------------+
| 4 | MS | bul_out bul_in | |
+-----------+------+-------+----------------+--------------------------------------------------+
| 5 | DFU | | |
+-----------+------+-------+----------------+--------------------------------------------------+
Interface 1: host -> device
Interface 2: device -> host
Structure of defines::
alt 0
alt 1
18 ch
#ifdef ADAT
alt 2
14 ch
#endif
Inconsistencies
---------------
- is MIDI AC interface is required? spec says 1 AC interface per function
- interface association descriptor specifies 3 interfaces, but there are 6

View File

@@ -0,0 +1,23 @@
#ifndef _ENDPOINT0_H_
#define _ENDPOINT0_H_
/** Function implementing Endpoint 0 for enumeration, control and configuration
* of USB audio devices. It uses the descriptors defined in ``descriptors_2.h``.
*
* \param c_ep0_out Chanend connected to the XUD_Manager() out endpoint array
* \param c_ep0_in Chanend connected to the XUD_Manager() in endpoint array
* \param c_audioCtrl Chanend connected to the decouple thread for control
* audio (sample rate changes etc.)
* \param c_mix_ctl Optional chanend to be connected to the mixer thread if
* present
* \param c_clk_ctl Optional chanend to be connected to the clockgen thread if
* present.
*/
void Endpoint0( chanend c_ep0_out, chanend c_ep0_in, chanend c_audioCtrl, chanend ?c_mix_ctl,chanend ?c_clk_ctl
#ifdef EP0_THREAD_COMBINED_WITH_SPI
, chanend c_spi, chanend c_spi_ss
#endif
);
#endif

View File

@@ -0,0 +1,840 @@
/**
* @file endpoint0.xc
* @brief Implements endpoint zero for an USB Audio 1.0/2.0 device
* @author Ross Owen, XMOS Semiconductor
*/
#include <xs1.h>
#include <print.h>
#include <safestring.h>
#include "xud.h" /* XUD user defines and functions */
#include "usb.h" /* Defines from USB 2.0 Spec */
#include "usbaudio20.h" /* Defines from USB Audio 2.0 spec */
#include "devicedefines.h"
#include "DescriptorRequests.h" /* This device's descriptors */
#include "descriptors_2.h" /* Descriptors */
#include "clockcmds.h"
#include "audiostream.h"
#include "vendorrequests.h"
#include "dfu_types.h"
/* Windows does not have a built in DFU driver (windows will prompt), so warn that DFU will not be functional in Audio 1.0 mode.Udi
* Of course, OSX is unaffected.
*/
#if ((AUDIO_CLASS==1) || defined(AUDIO_CLASS_FALLBACK)) && defined(DFU)
#warning DFU will require a seperate driver (but will be enabled) in AUDIO 1.0 mode
#endif
/* MIDI not supported in Audio 1.0 mode */
#if ((AUDIO_CLASS==1) || defined(AUDIO_CLASS_FALLBACK)) && defined(MIDI)
#warning MIDI is not supported and will not be enabled in AUDIO 1.0 mode
#endif
#ifndef PID_DFU
#warning PID_DFU not defined, Using PID_AUDIO_2. This is probably fine!
#endif
#ifdef DFU
#include "dfu.h"
#define DFU_IF_NUM INPUT_INTERFACES + OUTPUT_INTERFACES + MIDI_INTERFACES + 1
unsigned int DFU_mode_active = 0; // 0 - App active, 1 - DFU active
extern void device_reboot(void);
#endif
/* Handles Audio Class requests */
int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, SetupPacket &sp, chanend c_audioControl, chanend ?c_mix_ctl, chanend ?c_clk_ctl);
int AudioClassRequests_1(XUD_ep ep0_out, XUD_ep ep0_in, SetupPacket &sp, chanend c_audioControl, chanend ?c_mix_ctl, chanend ?c_clk_ctl);
/* Global var for current frequency, set to default freq */
unsigned int g_curSamFreq = DEFAULT_FREQ;
unsigned int g_curSamFreq48000Family = DEFAULT_FREQ % 48000 == 0;
unsigned int g_curSamFreqMultiplier = DEFAULT_FREQ / 48000;
/* Global volume and mute tables */
int volsOut[NUM_USB_CHAN_OUT + 1];
unsigned int mutesOut[NUM_USB_CHAN_OUT + 1];
//unsigned int multOut[NUM_USB_CHAN_OUT + 1];
int volsIn[NUM_USB_CHAN_IN + 1];
unsigned int mutesIn[NUM_USB_CHAN_IN + 1];
//unsigned int multIn[NUM_USB_CHAN_IN + 1];
unsigned char mixer1Crossbar[18];
short mixer1Weights[18*8];
//#define MAX_MIX_COUNT 8
unsigned char channelMap[NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + MAX_MIX_COUNT];
#if NUM_USB_CHAN_OUT > 0
unsigned char channelMapAud[NUM_USB_CHAN_OUT];
#endif
#if NUM_USB_CHAN_IN > 0
unsigned char channelMapUsb[NUM_USB_CHAN_IN];
#endif
unsigned char mixSel[MIX_INPUTS];
int min(int x, int y);
/* Records alt setting for each interface */
int interfaceAlt[NUM_INTERFACES] = {0, 0, 0, 0};
/* Global current device config var*/
unsigned g_config = 0;
/* Global endpoint status arrays */
unsigned g_epStatusOut[NUM_EP_OUT];
unsigned g_epStatusIn[NUM_EP_IN];
/* Global variable for current USB bus speed (i.e. FS/HS) */
unsigned g_curUsbSpeed = 0;
#ifdef HOST_ACTIVE_CALL
void VendorHostActive(int active);
#endif
/* Used when setting/clearing EP halt */
void SetEndpointStatus(unsigned epNum, unsigned status)
{
/* Inspect for IN bit */
if( epNum & 0x80 )
{
epNum &= 0x7f;
/* Range check */
if(epNum < NUM_EP_IN)
{
g_epStatusIn[ epNum & 0x7F ] = status;
}
}
else
{
if(epNum < NUM_EP_OUT)
{
g_epStatusOut[ epNum ] = status;
}
}
}
#define STR_USENG 0x0409
#define DESC_STR_LANGIDS \
{ \
STR_USENG & 0xff, /* 2 wLangID[0] */ \
STR_USENG>>8, /* 3 wLangID[0] */ \
'\0' \
}
/* String descriptors */
static unsigned char strDesc_langIDs[] = DESC_STR_LANGIDS;
void VendorAudioRequestsInit(chanend c_audioControl, chanend ?c_mix_ctl, chanend ?c_clk_ctl);
/* Endpoint 0 function. Handles all requests to the device */
void Endpoint0( chanend c_ep0_out, chanend c_ep0_in, chanend c_audioControl, chanend ?c_mix_ctl, chanend ?c_clk_ctl
)
{
unsigned char buffer[512];
SetupPacket sp;
XUD_ep ep0_out = XUD_Init_Ep(c_ep0_out);
XUD_ep ep0_in = XUD_Init_Ep(c_ep0_in);
/* Init endpoint status tables */
for (int i = 0; i++; i < NUM_EP_OUT)
g_epStatusOut[i] = 0;
for (int i = 0; i++; i < NUM_EP_IN)
g_epStatusIn[i] = 0;
/* Init tables for volumes (+ 1 for master) */
for(int i = 0; i < NUM_USB_CHAN_OUT + 1; i++)
{
volsOut[i] = 0;
mutesOut[i] = 0;
}
for(int i = 0; i < NUM_USB_CHAN_IN + 1; i++)
{
volsIn[i] = 0;
mutesIn[i] = 0;
}
/* Set up mixer default state */
for (int i = 0; i < 18*8; i++) {
mixer1Weights[i] = 0x8001; //-inf
}
/* Configure default connections */
mixer1Weights[0] = 0;
mixer1Weights[9] = 0;
mixer1Weights[18] = 0;
mixer1Weights[27] = 0;
mixer1Weights[36] = 0;
mixer1Weights[45] = 0;
mixer1Weights[54] = 0;
mixer1Weights[63] = 0;
#if NUM_USB_CHAN_OUT > 0
/* Setup up audio output channel mapping */
for(int i = 0; i < NUM_USB_CHAN_OUT; i++)
{
channelMapAud[i] = i;
}
#endif
#if NUM_USB_CHAN_IN > 0
for(int i = 0; i < NUM_USB_CHAN_IN; i++)
{
channelMapUsb[i] = i + NUM_USB_CHAN_OUT;
}
#endif
/* Set up channel mapping default */
for (int i = 0; i < NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN; i++)
{
channelMap[i] = i;
}
#if MAX_MIX_COUNT > 0
/* Mixer outputs mapping defaults */
for (int i = 0; i < MAX_MIX_COUNT; i++)
{
channelMap[NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + i] = i;
}
#endif
/* Init mixer inputs */
for(int i = 0; i < MIX_INPUTS; i++)
{
mixSel[i] = i;
}
/* Copy langIDs string desc into string[0] */
/* TODO: Macro? */
#if defined(AUDIO_CLASS_FALLBACK) || (AUDIO_CLASS == 1)
safememcpy(strDescs_Audio1[0], strDesc_langIDs, sizeof(strDesc_langIDs));
#endif
safememcpy(strDescs_Audio2[0], strDesc_langIDs, sizeof(strDesc_langIDs));
/* Build up channel string table - By default all channels are marked as analogue
* TODO We really want to do this an build time... */
#if defined(SPDIF_RX) && (SPDIF_RX_INDEX != 0)
safestrcpy(strDescs_Audio2[SPDIF_RX_INDEX + 33], "S/PDIF 1");
safestrcpy(strDescs_Audio2[SPDIF_RX_INDEX + 34], "S/PDIF 2");
#endif
#if defined(ADAT_RX) && (ADAT_RX_INDEX != 0)
safestrcpy(strDescs_Audio2[ADAT_RX_INDEX + 33], "ADAT 1");
safestrcpy(strDescs_Audio2[ADAT_RX_INDEX + 34], "ADAT 2");
safestrcpy(strDescs_Audio2[ADAT_RX_INDEX + 35], "ADAT 3");
safestrcpy(strDescs_Audio2[ADAT_RX_INDEX + 36], "ADAT 4");
safestrcpy(strDescs_Audio2[ADAT_RX_INDEX + 37], "ADAT 5");
safestrcpy(strDescs_Audio2[ADAT_RX_INDEX + 38], "ADAT 6");
safestrcpy(strDescs_Audio2[ADAT_RX_INDEX + 39], "ADAT 7");
safestrcpy(strDescs_Audio2[ADAT_RX_INDEX + 40], "ADAT 8");
#endif
#if defined(SPDIF) && (SPDIF_TX_INDEX != 0) /* "Analogue naming gets priority */
safestrcpy(strDescs_Audio2[SPDIF_TX_INDEX + 15], "S/PDIF 1");
safestrcpy(strDescs_Audio2[SPDIF_TX_INDEX + 16], "S/PDIF 2");
#endif
#if defined(ADAT_TX) && (ADAT_TX_INDEX != 0)
safestrcpy(strDescs_Audio2[ADAT_TX_INDEX + 15], "ADAT 1");
safestrcpy(strDescs_Audio2[ADAT_TX_INDEX + 16], "ADAT 2");
safestrcpy(strDescs_Audio2[ADAT_TX_INDEX + 17], "ADAT 3");
safestrcpy(strDescs_Audio2[ADAT_TX_INDEX + 18], "ADAT 4");
safestrcpy(strDescs_Audio2[ADAT_TX_INDEX + 19], "ADAT 5");
safestrcpy(strDescs_Audio2[ADAT_TX_INDEX + 20], "ADAT 6");
safestrcpy(strDescs_Audio2[ADAT_TX_INDEX + 21], "ADAT 7");
safestrcpy(strDescs_Audio2[ADAT_TX_INDEX + 22], "ADAT 8");
#endif
#ifdef VENDOR_AUDIO_REQS
VendorAudioRequestsInit(c_audioControl, c_mix_ctl, c_clk_ctl);
#endif
#ifdef DFU
/* Check if device has started in DFU mode */
if (DFUReportResetState(null))
{
/* Stop audio */
outuint(c_audioControl, SET_SAMPLE_FREQ);
outuint(c_audioControl, AUDIO_STOP_FOR_DFU);
// No Handshake
//chkct(c_audioControl, XS1_CT_END);
DFU_mode_active = 1;
}
#endif
while(1)
{
int retVal = 1;
/* Do standard enumeration requests */
#ifndef DFU
if(g_curUsbSpeed == XUD_SPEED_HS)
{
#ifdef AUDIO_CLASS_FALLBACK
/* Return Audio 2.0 Descriptors with Audio 1.0 as fallback */
cfgDesc_Audio2[1] = CONFIGURATION;
cfgDesc_Audio1[1] = OTHER_SPEED_CONFIGURATION;
retVal = DescriptorRequests(ep0_out, ep0_in,
devDesc_Audio2, sizeof(devDesc_Audio2),
cfgDesc_Audio2, sizeof(cfgDesc_Audio2),
devQualDesc_Audio1, sizeof(devQualDesc_Audio1),
cfgDesc_Audio1, sizeof(cfgDesc_Audio1),
strDescs_Audio2, sp);
#else
/* Return Audio 2.0 Descriptors */
cfgDesc_Audio2[1] = CONFIGURATION;
cfgDesc_Null[1] = OTHER_SPEED_CONFIGURATION;
retVal = DescriptorRequests(ep0_out, ep0_in,
devDesc_Audio2, sizeof(devDesc_Audio2),
cfgDesc_Audio2, sizeof(cfgDesc_Audio2),
devQualDesc_Null, sizeof(devQualDesc_Null),
cfgDesc_Null, sizeof(cfgDesc_Null),
strDescs_Audio2, sp);
#endif
}
else
{
/* Return descriptors for full-speed - Audio 1.0? */
#ifdef AUDIO_CLASS_FALLBACK
cfgDesc_Audio1[1] = CONFIGURATION;
cfgDesc_Audio2[1] = OTHER_SPEED_CONFIGURATION;
retVal = DescriptorRequests(ep0_out, ep0_in,
devDesc_Audio1, sizeof(devDesc_Audio1),
cfgDesc_Audio1, sizeof(cfgDesc_Audio1),
devQualDesc_Audio2, sizeof(devQualDesc_Audio2),
cfgDesc_Audio2, sizeof(cfgDesc_Audio2),
strDescs_Audio1, sp);
#else
cfgDesc_Null[1] = CONFIGURATION;
cfgDesc_Audio2[1] = OTHER_SPEED_CONFIGURATION;
retVal = DescriptorRequests(ep0_out, ep0_in,
devDesc_Null, sizeof(devDesc_Null),
cfgDesc_Null, sizeof(cfgDesc_Null),
devQualDesc_Audio2, sizeof(devQualDesc_Audio2),
cfgDesc_Audio2, sizeof(cfgDesc_Audio2),
strDescs_Audio2, sp);
#endif
}
#else /* ifndef DFU */
if (!DFU_mode_active)
{
if(g_curUsbSpeed == XUD_SPEED_HS)
{
#ifdef AUDIO_CLASS_FALLBACK
/* Return Audio 2.0 Descriptors with Audio 1.0 as fallback */
cfgDesc_Audio2[1] = CONFIGURATION;
cfgDesc_Audio1[1] = OTHER_SPEED_CONFIGURATION;
retVal = DescriptorRequests(ep0_out, ep0_in,
devDesc_Audio2, sizeof(devDesc_Audio2),
cfgDesc_Audio2, sizeof(cfgDesc_Audio2),
devQualDesc_Audio1, sizeof(devQualDesc_Audio1),
cfgDesc_Audio1, sizeof(cfgDesc_Audio1),
strDescs_Audio2, sp);
#else
/* Return Audio 2.0 Descriptors with Null device as fallback */
cfgDesc_Audio2[1] = CONFIGURATION;
cfgDesc_Null[1] = OTHER_SPEED_CONFIGURATION;
retVal = DescriptorRequests(ep0_out, ep0_in,
devDesc_Audio2, sizeof(devDesc_Audio2),
cfgDesc_Audio2, sizeof(cfgDesc_Audio2),
devQualDesc_Null, sizeof(devQualDesc_Null),
cfgDesc_Null, sizeof(cfgDesc_Null),
strDescs_Audio2, sp);
#endif
}
else
{
/* Return descriptors for full-speed - Audio 1.0? */
#ifdef AUDIO_CLASS_FALLBACK
cfgDesc_Audio1[1] = CONFIGURATION;
cfgDesc_Audio2[1] = OTHER_SPEED_CONFIGURATION;
retVal = DescriptorRequests(ep0_out, ep0_in,
devDesc_Audio1, sizeof(devDesc_Audio1),
cfgDesc_Audio1, sizeof(cfgDesc_Audio1),
devQualDesc_Audio2, sizeof(devQualDesc_Audio2),
cfgDesc_Audio2, sizeof(cfgDesc_Audio2),
strDescs_Audio1, sp);
#else
cfgDesc_Null[1] = CONFIGURATION;
cfgDesc_Audio2[1] = OTHER_SPEED_CONFIGURATION;
retVal = DescriptorRequests(ep0_out, ep0_in,
devDesc_Null, sizeof(devDesc_Null),
cfgDesc_Null, sizeof(cfgDesc_Null),
devQualDesc_Audio2, sizeof(devQualDesc_Audio2),
cfgDesc_Audio2, sizeof(cfgDesc_Audio2),
strDescs_Audio2, sp);
#endif
}
}
else
{
/* Running in DFU mode - always return same descs for DFU whether HS or FS */
retVal = DescriptorRequests(ep0_out, ep0_in,
DFUdevDesc, sizeof(DFUdevDesc),
DFUcfgDesc, sizeof(DFUcfgDesc),
DFUdevQualDesc, sizeof(DFUdevQualDesc),
DFUoSpeedCfgDesc, sizeof(DFUoSpeedCfgDesc),
strDescs_Audio2, sp);
}
#endif
if (retVal == 1)
{
/* Request not covered by XUD_DoEnumReqs() so decode ourselves */
/* Inspect Request type and Receipient */
switch( (sp.bmRequestType.Recipient ) | (sp.bmRequestType.Type << 5) )
{
case STANDARD_INTERFACE_REQUEST:
switch(sp.bRequest)
{
/* Set Interface */
case SET_INTERFACE:
#if defined(OUTPUT) && defined(INPUT)
/* Check for stream start stop on output and input audio interfaces */
if(sp.wValue && !interfaceAlt[1] && !interfaceAlt[2])
{
/* If start and input AND output not currently running */
AudioStreamStart();
}
else if(((sp.wIndex == 1)&& (!sp.wValue)) && interfaceAlt[1] && (!interfaceAlt[2]))
{
/* if output stop and output running and input not running */
AudioStreamStop();
}
else if(((sp.wIndex == 2) && (!sp.wValue)) && interfaceAlt[2] && (!interfaceAlt[1]))
{
/* if input stop and input running and output not running */
AudioStreamStop();
}
#elif defined(OUTPUT) || defined(INPUT)
if(sp.wValue && (!interfaceAlt[1]))
{
/* if start and not currently running */
AudioStreamStart();
}
else if (!sp.wValue && interfaceAlt[1])
{
/* if stop and currently running */
AudioStreamStop();
}
#endif
/* Record interface change */
if( sp.wIndex < NUM_INTERFACES )
interfaceAlt[sp.wIndex] = sp.wValue;
#if 1
/* Check for audio stream from host start/stop */
if(sp.wIndex == 2) // Input interface
{
switch(sp.wValue)
{
case 0:
break;
case 1:
/* Stream active + 0 chans */
outuint(c_audioControl, SET_CHAN_COUNT_IN);
outuint(c_audioControl, NUM_USB_CHAN_IN);
#ifdef ADAT_RX
outuint(c_clk_ctl, SET_SMUX);
outuint(c_clk_ctl, 0);
outct(c_clk_ctl, XS1_CT_END);
#endif
break;
#ifdef ADAT_RX
case 2:
/* Stream active + 8 chans */
outuint(c_audioControl, SET_CHAN_COUNT_IN);
outuint(c_audioControl, NUM_USB_CHAN_IN-4);
outuint(c_clk_ctl, SET_SMUX);
outuint(c_clk_ctl, 1);
outct(c_clk_ctl, XS1_CT_END);
break;
case 3:
outuint(c_audioControl, SET_CHAN_COUNT_IN);
outuint(c_audioControl, NUM_USB_CHAN_IN-6);
outuint(c_clk_ctl, SET_SMUX);
outuint(c_clk_ctl, 1);
outct(c_clk_ctl, XS1_CT_END);
/* Stream active + 8 chans */
//outuint(c_audioControl, 8);
// Handshake
//chkct(c_audioControl, XS1_CT_END);
break;
#endif
}
}
#endif
/* No data stage for this request, just do data stage */
retVal = XUD_DoSetRequestStatus(ep0_in, 0);
break;
/* A device must support the GetInterface request if it has alternate setting for that interface */
case GET_INTERFACE:
buffer[0] = 0;
/* Bounds check */
if( sp.wIndex < NUM_INTERFACES )
buffer[0] = interfaceAlt[sp.wIndex];
retVal = XUD_DoGetRequest(ep0_out, ep0_in, buffer, 1, sp.wLength);
break;
default:
printstr("Unknown Standard Interface Request: ");
printhexln(sp.bRequest);
printhexln(sp.bmRequestType.Type);
printhexln(sp.bmRequestType.Recipient);
printhexln(sp.bmRequestType.Recipient | (sp.bmRequestType.Type << 5));
break;
}
break;
/* Recipient: Device */
case STANDARD_DEVICE_REQUEST:
/* Standard Device requests (8) */
switch( sp.bRequest )
{
/* Set Device Address: This is a unique set request. */
case SET_ADDRESS:
/* Status stage: Send a zero length packet */
retVal = XUD_SetBuffer_ResetPid(ep0_in, buffer, 0, PIDn_DATA1);
/* TODO We should wait until ACK is received for status stage before changing address */
//XUD_Sup_Delay(50000);
{
timer t;
unsigned time;
t :> time;
t when timerafter(time+50000) :> void;
}
/* Set device address in XUD */
XUD_SetDevAddr(sp.wValue);
break;
/* TODO Check direction */
/* Standard request: SetConfiguration */
case SET_CONFIGURATION:
g_config = sp.wValue;
#ifdef HOST_ACTIVE_CALL
if(g_config == 1)
{
/* Consider host active with valid driver at this point */
VendorHostActive(1);
}
#endif
/* No data stage for this request, just do status stage */
retVal = XUD_DoSetRequestStatus(ep0_in, 0);
break;
case GET_CONFIGURATION:
buffer[0] = g_config;
retVal = XUD_DoGetRequest(ep0_out, ep0_in, buffer, 1, sp.wLength);
break;
/* Get Status request */
case GET_STATUS:
buffer[0] = 0; // bus powered
buffer[1] = 0; // remote wakeup not supported
retVal = XUD_DoGetRequest(ep0_out, ep0_in, buffer, 2, sp.wLength);
break;
default:
XUD_Error("Unknown device request");
break;
}
break;
/* Receipient: Endpoint */
case STANDARD_ENDPOINT_REQUEST:
/* Standard endpoint requests */
switch ( sp.bRequest )
{
/* ClearFeature */
case CLEAR_FEATURE:
switch ( sp.wValue )
{
case ENDPOINT_HALT:
/* Mark the endpoint status */
SetEndpointStatus(sp.wIndex, 0);
/* No data stage for this request, just do status stage */
retVal = XUD_DoSetRequestStatus(ep0_in, 0);
break;
default:
XUD_Error( "Unknown request in Endpoint ClearFeature" );
break;
}
break; /* B_REQ_CLRFEAR */
/* SetFeature */
case SET_FEATURE:
switch( sp.wValue )
{
case ENDPOINT_HALT:
/* Check request is in range */
SetEndpointStatus(sp.wIndex, 1);
break;
default:
XUD_Error("Unknown feature in SetFeature Request");
break;
}
retVal = XUD_DoSetRequestStatus(ep0_in, 0);
break;
/* Endpoint GetStatus Request */
case GET_STATUS:
buffer[0] = 0;
buffer[1] = 0;
if( sp.wIndex & 0x80 )
{
/* IN Endpoint */
if((sp.wIndex&0x7f) < NUM_EP_IN)
{
buffer[0] = ( g_epStatusIn[ sp.wIndex & 0x7F ] & 0xff );
buffer[1] = ( g_epStatusIn[ sp.wIndex & 0x7F ] >> 8 );
}
}
else
{
/* OUT Endpoint */
if(sp.wIndex < NUM_EP_OUT)
{
buffer[0] = ( g_epStatusOut[ sp.wIndex ] & 0xff );
buffer[1] = ( g_epStatusOut[ sp.wIndex ] >> 8 );
}
}
retVal = XUD_DoGetRequest(ep0_out, ep0_in, buffer, 2, sp.wLength);
break;
default:
//printstrln("Unknown Standard Endpoint Request");
break;
}
break;
case CLASS_INTERFACE_REQUEST:
case CLASS_ENDPOINT_REQUEST:
{
unsigned interfaceNum = sp.wIndex & 0xff;
unsigned request = (sp.bmRequestType.Recipient ) | (sp.bmRequestType.Type << 5);
/* TODO Check interface number */
/* TODO Check on return value retval = */
#ifdef DFU
unsigned DFU_IF = DFU_IF_NUM;
/* DFU interface number changes based on which mode we are currently running in */
if (DFU_mode_active)
{
DFU_IF = 0;
}
if (interfaceNum == DFU_IF)
{
/* If running in application mode stop audio */
/* Don't interupt audio for save and restore cmds */
if ((DFU_IF == DFU_IF_NUM) && (sp.bRequest != XMOS_DFU_SAVESTATE) && (sp.bRequest != XMOS_DFU_RESTORESTATE))
{
// Stop audio
outuint(c_audioControl, SET_SAMPLE_FREQ);
outuint(c_audioControl, AUDIO_STOP_FOR_DFU);
// Handshake
chkct(c_audioControl, XS1_CT_END);
}
/* This will return 1 if reset requested */
if (DFUDeviceRequests(ep0_out, ep0_in, sp, null, interfaceAlt[sp.wIndex], 1))
{
timer tmr;
unsigned s;
/* Send reboot command */
//outuint(c_audioControl, SET_SAMPLE_FREQ);
//outuint(c_audioControl, AUDIO_REBOOT_FROM_DFU);
tmr :> s;
tmr when timerafter(s + 50000000) :> s;
device_reboot();
}
/* TODO we should not make the assumption that all DFU requests are handled */
retVal = 0;
}
/* Check for: Audio interface request - always 0, note we check for DFU first
* Audio endpoint request */
else if(((request == CLASS_INTERFACE_REQUEST) && (interfaceNum == 0))
|| (request == CLASS_ENDPOINT_REQUEST && ((interfaceNum == 0x82) || (interfaceNum == 0x01))))
{
#endif
#if (AUDIO_CLASS == 2) && defined(AUDIO_CLASS_FALLBACK)
if(g_curUsbSpeed == XUD_SPEED_HS)
{
retVal = AudioClassRequests_2(ep0_out, ep0_in, sp, c_audioControl, c_mix_ctl, c_clk_ctl);
}
else
{
retVal = AudioClassRequests_1(ep0_out, ep0_in, sp, c_audioControl, c_mix_ctl, c_clk_ctl);
}
#elif (AUDIO_CLASS==2)
retVal = AudioClassRequests_2(ep0_out, ep0_in, sp, c_audioControl, c_mix_ctl, c_clk_ctl);
#else
retVal = AudioClassRequests_1(ep0_out, ep0_in, sp, c_audioControl, c_mix_ctl, c_clk_ctl);
#endif
#ifdef VENDOR_AUDIO_REQS
/* If retVal is 1 at this point, then request to audio interface not handled - handle vendor audio reqs */
if(retVal == 1)
{
retVal = VendorAudioRequests(ep0_out, ep0_in, sp.bRequest,
sp.wValue >> 8, sp.wValue & 0xff,
sp.wIndex >> 8, sp.bmRequestType.Direction,
c_audioControl, c_mix_ctl, c_clk_ctl);
}
#endif
#ifdef DFU
}
#endif
}
break;
default:
//printstr("unrecognised request\n");
//printhexln(sp.bRequest);
//printhexln(sp.bmRequestType.Type);
//printhexln(sp.bmRequestType.Recipient);
//printhexln(sp.bmRequestType.Recipient | (sp.bmRequestType.Type << 5));
break;
}
} /* if(retVal == 0) */
if(retVal == 1)
{
/* Did not handle request - Protocol Stall Secion 8.4.5 of USB 2.0 spec
* Detailed in Section 8.5.3. Protocol stall is unique to control pipes.
Protocol stall differs from functional stall in meaning and duration.
A protocol STALL is returned during the Data or Status stage of a control
transfer, and the STALL condition terminates at the beginning of the
next control transfer (Setup). The remainder of this section refers to
the general case of a functional stall */
XUD_SetStall_Out(0);
XUD_SetStall_In(0);
}
if (retVal < 0)
{
g_curUsbSpeed = XUD_ResetEndpoint(ep0_in, ep0_out);
g_config = 0;
#ifdef DFU
if (DFUReportResetState(null))
{
if (!DFU_mode_active)
{
timer tmr;
unsigned s;
DFU_mode_active = 1;
//tmr :> s;
//tmr when timerafter(s + 500000) :> s;
}
}
else
{
if (DFU_mode_active)
{
timer tmr;
unsigned s;
// Restart audio
//outuint(c_audioControl, AUDIO_START_FROM_DFU);
DFU_mode_active = 0;
// Send reboot command
//outuint(c_audioControl, SET_SAMPLE_FREQ);
//outuint(c_audioControl, AUDIO_REBOOT_FROM_DFU);
// No handshake on reboot
tmr :> s;
tmr when timerafter(s + 5000000) :> s;
device_reboot();
}
}
#endif
}
}
}

View File

@@ -0,0 +1,16 @@
#ifndef _VENDORREQUESTS_H_
#define _VENDORREQUESTS_H_
/* Functions that handle vustomer vendor requests.
*
* THESE NEED IMPLEMENTING FOR A SPECIFIC DESIGN
*
* Should return 0 if handled sucessfully, else return 0 (-1 for passing up reset/suspend)
*
* */
int VendorAudioRequests(XUD_ep ep0_out, XUD_ep ep0_in, unsigned char bRequest, unsigned char cs, unsigned char cn,
unsigned short unitId, unsigned char direction, chanend c_audioControl, chanend ?c_mix_ctl, chanend ?c_clk_ctL);
#endif

View File

@@ -0,0 +1,4 @@
void I2cRegWrite(int deviceAdrs, int Adrs, int WrData, port AUD_SCLK, port AUD_SDIN);
int I2cRegRead(int deviceAdrs, int Adrs, port AUD_SCLK, port AUD_SDIN);

321
module_usb_aud_shared/i2c/i2c.xc Executable file
View File

@@ -0,0 +1,321 @@
#include <xs1.h>
#include <print.h>
int I2cRegRead(int device, int addr, port scl, port sda)
{
//int Result;
timer gt;
unsigned time;
int Temp, CtlAdrsData, i;
// three device ACK
int ack[3];
int rdData;
// initial values.
scl <: 1;
sda <: 1;
sync(sda);
gt :> time;
time += 1000 + 1000;
gt when timerafter(time) :> int _;
// start bit on SDI
scl <: 1;
sda <: 0;
gt :> time;
time += 1000;
gt when timerafter(time) :> int _;
scl <: 0;
// shift 7bits of address and 1bit R/W (fixed to write).
// WARNING: Assume MSB first.
for (i = 0; i < 8; i += 1)
{
Temp = (device >> (7 - i)) & 0x1;
sda <: Temp;
gt :> time;
time += 1000;
gt when timerafter(time) :> int _;
scl <: 1;
gt :> time;
time += 1000;
gt when timerafter(time) :> int _;
scl <: 0;
}
// turn the data to input
sda :> Temp;
gt :> time;
time += 1000;
gt when timerafter(time) :> int _;
scl <: 1;
// sample first ACK.
sda :> ack[0];
gt :> time;
time += 1000;
gt when timerafter(time) :> int _;
scl <: 0;
CtlAdrsData = (addr & 0xFF);
// shift first 8 bits.
for (i = 0; i < 8; i += 1)
{
Temp = (CtlAdrsData >> (7 - i)) & 0x1;
sda <: Temp;
gt :> time;
time += 1000;
gt when timerafter(time) :> int _;
scl <: 1;
gt :> time;
time += 1000;
gt when timerafter(time) :> int _;
scl <: 0;
}
// turn the data to input
sda :> Temp;
gt :> time;
time += 1000;
gt when timerafter(time) :> int _;
scl <: 1;
// sample second ACK.
sda :> ack[1];
gt :> time;
time += 1000;
gt when timerafter(time) :> int _;
scl <: 0;
// stop bit
gt :> time;
time += 1000 + 1000;
gt when timerafter(time) :> int _;
// start bit on SDI
scl <: 1;
sda <: 1;
time += 1000 + 1000;
gt when timerafter(time) :> int _;
scl <: 0;
time += 1000 + 1000;
gt when timerafter(time) :> int _;
// send address and read
scl <: 1;
sda <: 1;
sync(sda);
gt :> time;
time += 1000 + 1000;
gt when timerafter(time) :> int _;
// start bit on SDI
scl <: 1;
sda <: 0;
gt :> time;
time += 1000;
gt when timerafter(time) :> int _;
scl <: 0;
// shift 7bits of address and 1bit R/W (fixed to write).
// WARNING: Assume MSB first.
for (i = 0; i < 8; i += 1)
{
int deviceAddr = device | 1;
Temp = (deviceAddr >> (7 - i)) & 0x1;
sda <: Temp;
gt :> time;
time += 1000;
gt when timerafter(time) :> int _;
scl <: 1;
gt :> time;
time += 1000;
gt when timerafter(time) :> int _;
scl <: 0;
}
// turn the data to input
sda :> Temp;
gt :> time;
time += 1000;
gt when timerafter(time) :> int _;
scl <: 1;
// sample first ACK.
sda :> ack[0];
gt :> time;
time += 1000;
gt when timerafter(time) :> int _;
scl <: 0;
rdData = 0;
// shift second 8 bits.
for (i = 0; i < 8; i += 1)
{
gt :> time;
time += 1000;
gt when timerafter(time) :> int _;
scl <: 1;
sda :> Temp;
rdData = (rdData << 1) | (Temp & 1);
gt :> time;
time += 1000;
gt when timerafter(time) :> int _;
scl <: 0;
}
// turn the data to input
sda :> Temp;
gt :> time;
time += 1000;
gt when timerafter(time) :> int _;
scl <: 1;
// sample second ACK.
sda :> ack[2];
gt :> time;
time += 1000;
gt when timerafter(time) :> int _;
scl <: 0;
gt :> time;
time += 1000;
gt when timerafter(time) :> int _;
scl <: 1;
// put the data to a good value for next round.
sda <: 1;
// validate all items are ACK properly.
//Result = 0;
//for (i = 0; i < 3; i += 1)
//{
//if ((ack[i]&1) != 0)
//{
//Result = Result | (1 << i);
//}
//}
return rdData;
}
void I2cRegWrite(int device, int addr, int data, port scl, port sda)
{
//int Result;
timer gt;
unsigned time;
int Temp, CtlAdrsData, i;
// three device ACK
int ack[3];
// initial values.
scl <: 1;
sda <: 1;
sync(sda);
gt :> time;
time += 1000 + 1000;
gt when timerafter(time) :> void;
// start bit on SDI
scl <: 1;
sda <: 0;
gt :> time;
time += 1000;
gt when timerafter(time) :> void;
scl <: 0;
// shift 7bits of address and 1bit R/W (fixed to write).
// WARNING: Assume MSB first.
for (i = 0; i < 8; i += 1)
{
Temp = (device >> (7 - i)) & 0x1;
sda <: Temp;
gt :> time;
time += 1000;
gt when timerafter(time) :> void;
scl <: 1;
gt :> time;
time += 1000;
gt when timerafter(time) :> void;
scl <: 0;
}
// turn the data to input
sda :> Temp;
gt :> time;
time += 1000;
gt when timerafter(time) :> void;
scl <: 1;
// sample first ACK.
sda :> ack[0];
gt :> time;
time += 1000;
gt when timerafter(time) :> void;
scl <: 0;
CtlAdrsData = (addr & 0xFF);
// shift first 8 bits.
for (i = 0; i < 8; i += 1)
{
Temp = (CtlAdrsData >> (7 - i)) & 0x1;
sda <: Temp;
gt :> time;
time += 1000;
gt when timerafter(time) :> void;
scl <: 1;
gt :> time;
time += 1000;
gt when timerafter(time) :> void;
scl <: 0;
}
// turn the data to input
sda :> Temp;
gt :> time;
time += 1000;
gt when timerafter(time) :> void;
scl <: 1;
// sample second ACK.
sda :> ack[1];
gt :> time;
time += 1000;
gt when timerafter(time) :> void;
scl <: 0;
CtlAdrsData = (data & 0xFF);
// shift second 8 bits.
for (i = 0; i < 8; i += 1)
{
Temp = (CtlAdrsData >> (7 - i)) & 0x1;
sda <: Temp;
gt :> time;
time += 1000;
gt when timerafter(time) :> void;
scl <: 1;
gt :> time;
time += 1000;
gt when timerafter(time) :> void;
scl <: 0;
}
// turn the data to input
sda :> Temp;
gt :> time;
time += 1000;
gt when timerafter(time) :> void;
scl <: 1;
// sample second ACK.
sda :> ack[2];
gt :> time;
time += 1000;
gt when timerafter(time) :> void;
scl <: 0;
gt :> time;
time += 1000;
gt when timerafter(time) :> void;
scl <: 1;
// put the data to a good value for next round.
sda <: 1;
// validate all items are ACK properly.
//Result = 0;
//for (i = 0; i < 3; i += 1)
//{
//if ((ack[i]&1) != 0)
//{
//Result = Result | (1 << i);
//}
//}
//return(Result);
}

View File

@@ -0,0 +1,167 @@
//#include "devicedefines.h"
#define MAX_MIX_COUNT 8
#define MIX_INPUTS 18
#define DOMIX_TOP(i) \
.cc_top doMix##i.function,doMix##i; \
.align 4 ;\
.globl doMix##i ;\
.globl doMix##i##.nstackwords ;\
.globl doMix##i##.maxthreads ; \
.globl doMix##i##.maxtimers ; \
.globl doMix##i##.maxchanends ; \
.globl doMix##i##.maxsync ;\
.linkset doMix##i##.locnoside, 1; \
.linkset doMix##i##.locnochandec, 1;\
.linkset doMix##i##.nstackwords, 0 ;\
.linkset doMix##i##.maxchanends, 0 ;\
.linkset doMix##i##.maxtimers, 0 ;\
.linkset doMix##i##.maxthreads, 1; \
doMix##i##: ;\
set cp, r0; \
set dp, r1; \
lsub r0, r1, r0, r0, r0;\
.label_##i##:
#define DOMIX_BOT(i) \
ldap r11, _dp; \
set dp, r11;\
ldap r11, _cp;\
set cp, r11;\
\
mov r0, r1;\
ldc r2, 0x19;\
sext r0, r2;\
eq r0, r0, r1;\
bf r0, .L20; \
\
shl r0, r1, 0x7;\
retsp 0x0;\
\
\
.cc_bottom doMix##i##.function;
#define N MIX_INPUTS
#define BODY(i) \
ldw r2,cp[i]; \
ldw r11, dp[i]; \
maccs r1, r0, r2, r11;
.text
.L20:\
lss r0, r1, r3;\
bt r0, .L16; \
ldw r0, cp[.LC0];\
retsp 0x0; \
.L16:\
ldw r0, cp[.LC1];\
retsp 0x0; \
#if(MAX_MIX_COUNT > 0)
DOMIX_TOP(0)
#include "repeat.h"
DOMIX_BOT(0)
#endif
#if(MAX_MIX_COUNT > 1)
DOMIX_TOP(1)
#include "repeat.h"
DOMIX_BOT(1)
#endif
#if(MAX_MIX_COUNT > 2)
DOMIX_TOP(2)
#include "repeat.h"
DOMIX_BOT(2)
#endif
#if(MAX_MIX_COUNT > 3)
DOMIX_TOP(3)
#include "repeat.h"
DOMIX_BOT(3)
#endif
#if(MAX_MIX_COUNT > 4)
DOMIX_TOP(4)
#include "repeat.h"
DOMIX_BOT(4)
#endif
#if(MAX_MIX_COUNT > 5)
DOMIX_TOP(5)
#include "repeat.h"
DOMIX_BOT(5)
#endif
#if(MAX_MIX_COUNT > 6)
DOMIX_TOP(6)
#include "repeat.h"
DOMIX_BOT(6)
#endif
#if(MAX_MIX_COUNT > 7)
DOMIX_TOP(7)
#include "repeat.h"
DOMIX_BOT(7)
#endif
#if(MAX_MIX_COUNT>8)
#error MAX_MIX_COUNT>7
#endif
/* We need MIX_OUTPUT x setPtr functions */
#undef N
#undef BODY
#define N MAX_MIX_COUNT
.cc_top setPtr.function,setPtr;
.align 4 ;
.globl setPtr.nstackwords;
.globl setPtr;
.globl setPtr.maxthreads;
.globl setPtr.maxtimers;
.globl setPtr.maxchanends;
.globl setPtr.maxsync;
.linkset setPtr.locnoside, 1;
.linkset setPtr.locnochandec, 1;
.linkset setPtr.nstackwords, 0;
.linkset setPtr.maxchanends, 0;
.linkset setPtr.maxtimers, 0;
.linkset setPtr.maxthreads, 1;
setPtr:
shl r2, r2, 1
.xtabranch .label_0
bru r2
#define BODY(i) \
ldap r11, .label_##i; \
bu setPtr_go
#include "repeat.h"
setPtr_go:
shl r0, r0, 3;
ldc r2, 0x80;
add r1, r1, r2;
st8 r1, r11[r0];
retsp 0;
.cc_bottom setPtr.function
.section .cp.const4, "acM", @progbits, 4
.LC0:
.align 4
.int 0x7fffff00
.LC1:
.int 0x80000000
#undef N
#undef BODY

View File

@@ -0,0 +1,32 @@
#ifndef __mixer_h__
#define __mixer_h__
enum mix_ctl_cmd {
SET_SAMPLES_TO_HOST_MAP,
SET_SAMPLES_TO_DEVICE_MAP,
SET_MIX_MULT,
SET_MIX_MAP,
SET_MIX_IN_VOL,
SET_MIX_OUT_VOL,
GET_INPUT_LEVELS,
GET_STREAM_LEVELS,
GET_OUTPUT_LEVELS
};
/** Digital sample mixer.
*
* This thread mixes audio streams between the decouple() thread and
* the audio() thread.
*
* \param c_to_host a chanend connected to the decouple() thread for
* receiving/transmitting samples
* \param c_to_audio a chanend connected to the audio() thread for
* receiving/transmitting samples
* \param c_mix_ctl a chanend connected to the Endpoint0() thread for
* receiving control commands
*
*/
void mixer(chanend c_to_host, chanend c_to_audio, chanend c_mix_ctl);
#endif

View File

@@ -0,0 +1,669 @@
#include <xs1.h>
#include <print.h>
#include "mixer.h"
#include "devicedefines.h"
#ifdef MIXER
#define FAST_MIXER 1
#warning USING FAST MIXER
#ifdef OUT_VOLUME_IN_MIXER
static unsigned int multOut[NUM_USB_CHAN_OUT + 1];
#endif
#ifdef IN_VOLUME_IN_MIXER
unsigned int multIn[NUM_USB_CHAN_IN + 1];
#endif
#if defined (LEVEL_METER_LEDS) || defined (LEVEL_METER_HOST)
static unsigned abs(int x)
{
#if 0
if (x < 0)
return x*-1;
return x;
#else
int const mask = x >> sizeof(int) * 8 - 1;
return (x + mask) ^ mask;
#endif
}
#endif
int samples[NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + MAX_MIX_COUNT + 1]; /* One larger for an "off" channel for mixer sources" */
int savedsamples2[NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + MAX_MIX_COUNT];
int samples_to_host_map[NUM_USB_CHAN_IN];
int samples_to_device_map[NUM_USB_CHAN_OUT];
#if MAX_MIX_COUNT > 0
int mix_mult[MAX_MIX_COUNT][MIX_INPUTS];
#ifndef FAST_MIXER
int mix_map[MAX_MIX_COUNT][MIX_INPUTS];
#endif
#endif
/* Arrays for level data */
int samples_to_host_inputs[NUM_USB_CHAN_IN]; /* Audio transmitted to host i.e. dev inputs */
#ifdef LEVEL_METER_LEDS
int samples_to_host_inputs_buff[NUM_USB_CHAN_IN]; /* Audio transmitted to host i.e. dev inputs */
#endif
static int samples_to_host_streams[NUM_USB_CHAN_OUT]; /* Audio stream to host from host */
static int samples_to_host_outputs[NUM_USB_CHAN_OUT]; /* Device outputs */
#if 0
#pragma xta command "add exclusion mixer1_rate_change"
#pragma xta command "analyse path mixer1_req mixer1_req"
#pragma xta command "set required - 10400 ns" /* 96kHz */
#endif
#if 0
#pragma xta command "add exclusion mixer2_rate_change"
#pragma xta command "analyse path mixer2_req mixer2_req"
#pragma xta command "set required - 10400 ns" /* 96kHz */
#endif
#if defined (LEVEL_METER_LEDS) || defined (LEVEL_METER_HOST)
static inline void ComputeMixerLevel(int sample, int i)
{
int x;
int y;
unsigned ptr;
x = abs(sample);
/* y = samples_to_host_outputs[i] */
asm("ldaw %0, dp[samples_to_host_outputs]":"=r"(ptr):); /* Might want to hoist this */
asm("ldw %0, %1[%2]":"=r"(y):"r"(ptr),"r"(i));
if(x > y)
{
/* samples_to_host_outputs[i] = x; */
asm("stw %0, %1[%2]"::"r"(y),"r"(ptr),"r"(i));
}
}
#endif
#ifdef FAST_MIXER
void setPtr(int src, int dst, int mix);
int doMix0(const int samples[], int mult[]);
int doMix1(const int samples[], int mult[]);
int doMix2(const int samples[], int mult[]);
int doMix3(const int samples[], int mult[]);
int doMix4(const int samples[], int mult[]);
int doMix5(const int samples[], int mult[]);
int doMix6(const int samples[], int mult[]);
int doMix7(const int samples[], int mult[]);
int doMix8(const int samples[], int mult[]);
#else
/* DO NOT inline, causes 10.4.2 tools to add extra loads in loop */
/* At 18 x 12dB we could get 64 x bigger */
#pragma unsafe arrays
int doMix(const int samples[], const int ptr[], int mult[])
{
int h=0;
int l=0;
/* By breaking up the loop we keep things in the encoding for ldw (0-11) */
#pragma loop unroll
for (int i=0; i<MIX_INPUTS; i++)
{
{h,l} = macs(samples[ptr[i]], mult[i], h, l);
}
#if 1
/* Perform saturation */
l = sext(h, 25);
if(l != h)
{
//if(h < 0)
if(h>>32)
h = (0x80000000>>7);
else
h = (0x7fffff00>>7);
}
#endif
return h<<7;
}
#endif
#pragma unsafe arrays
void giveSamplesToHost(chanend c, const int samples[], const int ptr[], const unsigned multIn[])
{
#if defined(IN_VOLUME_IN_MIXER) && defined(IN_VOLUME_AFTER_MIX)
int mult;
int h;
unsigned l;
#endif
#pragma loop unroll
for (int i=0;i<NUM_USB_CHAN_IN;i++)
{
int sample;
sample = samples[ptr[i]];
#if defined(IN_VOLUME_IN_MIXER) && defined(IN_VOLUME_AFTER_MIX)
#warning IN Vols in mixer, AFTER mix & map
//asm("ldw %0, %1[%2]":"=r"(mult):"r"(multIn),"r"(i));
mult = multIn[i];
{h, l} = macs(mult, sample, 0, 0);
//h <<= 3 done on other side */
outuint(c, h);
#else
outuint(c,sample);
#endif
}
}
#pragma unsafe arrays
static void getSamplesFromHost(chanend c, const int samples[], int base)
{
#pragma loop unroll
for (int i=0;i<NUM_USB_CHAN_OUT;i++)
{
int sample, x;
#if defined(OUT_VOLUME_IN_MIXER) && !defined(OUT_VOLUME_AFTER_MIX)
int mult;
int h;
unsigned l;
#endif
/* Receive sample from decouple */
sample = inuint(c);
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
/* Compute peak level data */
x = abs(sample);
if(x > samples_to_host_streams[i])
samples_to_host_streams[i] = x;
#endif
#if defined(OUT_VOLUME_IN_MIXER) && !defined(OUT_VOLUME_AFTER_MIX)
#warning OUT Vols in mixer, BEFORE mix & map
asm("ldw %0, %1[%2]":"=r"(mult):"r"(multOut),"r"(i));
{h, l} = macs(mult, sample, 0, 0);
h<<=3;
asm("stw %0, %1[%2]"::"r"(h),"r"(samples),"r"(base+i));
#else
asm("stw %0, %1[%2]"::"r"(sample),"r"(samples),"r"(base+i));
#endif
}
}
#pragma unsafe arrays
void giveSamplesToDevice(chanend c, const int samples[],const int ptr[], const unsigned multOut[])
{
#pragma loop unroll
for (int i=0;i<NUM_USB_CHAN_OUT;i++)
{
int sample,x;
#if defined(OUT_VOLUME_IN_MIXER) && defined(OUT_VOLUME_AFTER_MIX)
int mult;
int h;
unsigned l;
#endif
sample = samples[ptr[i]];
#if defined(OUT_VOLUME_IN_MIXER) && defined(OUT_VOLUME_AFTER_MIX)
#warning OUT Vols in mixer, AFTER mix & map
mult = multOut[i];
//asm("ldw %0, %1[%2]":"=r"(mult):"r"(multOut),"r"(i));
{h, l} = macs(mult, sample, 0, 0);
//h <<= 3 done in audio thread
outuint(c, h);
#else
outuint(c, sample);
#endif
}
}
#pragma unsafe arrays
void getSamplesFromDevice(chanend c, const int samples[], int base)
{
#if defined(IN_VOLUME_IN_MIXER) && !defined(IN_VOLUME_AFTER_MIX)
int mult;
int h;
unsigned l;
#endif
#pragma loop unroll
for (int i=0;i<NUM_USB_CHAN_IN;i++)
{
int sample;
int x;
sample = inuint(c);
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
/* Compute peak level data */
x = abs(sample);
if(x > samples_to_host_inputs[i])
samples_to_host_inputs[i] = x;
#endif
#if defined(IN_VOLUME_IN_MIXER) && !defined(IN_VOLUME_AFTER_MIX)
asm("ldw %0, %1[%2]":"=r"(mult):"r"(multIn),"r"(i));
{h, l} = macs(mult, sample, 0, 0);
h <<=3;
asm("stw %0, %1[%2]"::"r"(h),"r"(samples),"r"(base+i));
#else
asm("stw %0, %1[%2]"::"r"(sample),"r"(samples),"r"(base+i));
#endif
}
}
int mixer1_mix2_flag = (DEFAULT_FREQ > 96000);
#pragma unsafe arrays
void mixer1(chanend c_host, chanend c_mix_ctl, chanend c_mixer2)
{
int mixed;
unsigned cmd;
while (1)
{
#pragma xta endpoint "mixer1_req"
inuint(c_mixer2);
/* Request data from decouple thread */
outuint(c_host, 0);
/* Between request to decouple and respose ~ 400nS latency for interrupt to fire */
select
{
case inuint_byref(c_mix_ctl, cmd):
{
int mix, index, val;
switch (cmd)
{
#if MAX_MIX_COUNT > 0
case SET_SAMPLES_TO_HOST_MAP:
index = inuint(c_mix_ctl);
val = inuint(c_mix_ctl);
inct(c_mix_ctl);
asm("stw %0, %1[%2]"::"r"(val),"r"(samples_to_host_map),"r"(index));
break;
case SET_SAMPLES_TO_DEVICE_MAP:
index = inuint(c_mix_ctl);
val = inuint(c_mix_ctl);
inct(c_mix_ctl);
asm("stw %0, %1[%2]"::"r"(val),"r"(samples_to_device_map),"r"(index));
break;
case SET_MIX_MULT:
mix = inuint(c_mix_ctl);
index = inuint(c_mix_ctl);
val = inuint(c_mix_ctl);
inct(c_mix_ctl);
asm("stw %0, %1[%2]"::"r"(val),"r"(mix_mult[mix]),"r"(index));
break;
case SET_MIX_MAP:
mix = inuint(c_mix_ctl);
index = inuint(c_mix_ctl); /* mixer input */
val = inuint(c_mix_ctl); /* source */
inct(c_mix_ctl);
#ifdef FAST_MIXER
setPtr(index, val, mix);
#else
asm("stw %0, %1[%2]"::"r"(val),"r"(mix_map[mix]),"r"(index));
#endif
break;
#endif /* if MAX_MIX_COUNT > 0 */
#ifdef IN_VOLUME_IN_MIXER
case SET_MIX_IN_VOL:
index = inuint(c_mix_ctl);
val = inuint(c_mix_ctl);
inct(c_mix_ctl);
asm("stw %0, %1[%2]"::"r"(val),"r"(multIn),"r"(index));
break;
#endif
#ifdef OUT_VOLUME_IN_MIXER
case SET_MIX_OUT_VOL:
index = inuint(c_mix_ctl);
val = inuint(c_mix_ctl);
inct(c_mix_ctl);
asm("stw %0, %1[%2]"::"r"(val),"r"(multOut),"r"(index));
break;
#endif
case GET_STREAM_LEVELS:
index = inuint(c_mix_ctl);
chkct(c_mix_ctl, XS1_CT_END);
outuint(c_mix_ctl, samples_to_host_streams[index]);
outct(c_mix_ctl, XS1_CT_END);
samples_to_host_streams[index] = 0;
break;
case GET_INPUT_LEVELS:
index = inuint(c_mix_ctl);
chkct(c_mix_ctl, XS1_CT_END);
#ifdef LEVEL_METER_LEDS
/* Level LEDS process reseting samples_to_host_inputs
* Other side makes sure we don't miss a peak */
asm("ldw %0, %1[%2]":"=r"(val):"r"(samples_to_host_inputs_buff),"r"(index));
asm("stw %0, %1[%2]"::"r"(0),"r"(samples_to_host_inputs_buff),"r"(index));
#else
/* We dont have a level LEDs process, so reset ourselves */
asm("ldw %0, %1[%2]":"=r"(val):"r"(samples_to_host_inputs),"r"(index));
asm("stw %0, %1[%2]"::"r"(0),"r"(samples_to_host_inputs),"r"(index));
#endif
outuint(c_mix_ctl, val);
outct(c_mix_ctl, XS1_CT_END);
break;
#if MAX_MIX_COUNT > 0
case GET_OUTPUT_LEVELS:
index = inuint(c_mix_ctl);
chkct(c_mix_ctl, XS1_CT_END);
asm("ldw %0, %1[%2]":"=r"(val):"r"(samples_to_host_outputs),"r"(index));
asm("stw %0, %1[%2]"::"r"(mix),"r"(samples_to_host_outputs),"r"(index));
outuint(c_mix_ctl, val);
outct(c_mix_ctl, XS1_CT_END);
break;
#endif
}
break;
}
default:
/* Select default */
break;
}
/* Get response from decouple */
if(testct(c_host))
{
int sampFreq;
#pragma xta endpoint "mixer1_rate_change"
inct(c_host);
sampFreq = inuint(c_host);
mixer1_mix2_flag = sampFreq > 96000;
#pragma loop unroll
for (int i=0;i<MAX_MIX_COUNT;i++)
{
asm("stw %0, %1[%2]"::"r"(0),"r"(samples),"r"(NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + i));
}
/* Inform mixer 2 about freq change */
outct(c_mixer2, XS1_CT_END);
outuint(c_mixer2, sampFreq);
/* Wait for handshake and pass on */
chkct(c_mixer2, XS1_CT_END);
outct(c_host, XS1_CT_END);
}
else
{
inuint(c_host);
#if MAX_MIX_COUNT > 0
outuint(c_mixer2, 0);
giveSamplesToHost(c_host, samples, samples_to_host_map, multIn);
outuint(c_mixer2, 0);
inuint(c_mixer2);
getSamplesFromHost(c_host, samples, 0);
outuint(c_mixer2, 0);
inuint(c_mixer2);
#ifdef FAST_MIXER
mixed = doMix0(samples, mix_mult[0]);
#else
mixed = doMix(samples,mix_map[0],mix_mult[0]);
#endif
asm("stw %0, %1[%2]"::
"r"(mixed),"r"(samples),
"r"(NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 0));
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
ComputeMixerLevel(mixed, 0);
#endif
#if (MAX_FREQ > 96000)
if (!mixer1_mix2_flag)
#endif
{
#if MAX_MIX_COUNT > 2
#ifdef FAST_MIXER
mixed = doMix2(samples, mix_mult[2]);
#else
mixed = doMix(samples,mix_map[2],mix_mult[2]);
#endif
asm("stw %0, %1[%2]"::
"r"(mixed),"r"(samples),
"r"(NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 2));
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
ComputeMixerLevel(mixed, 2);
#endif
#endif
#if MAX_MIX_COUNT > 4
#ifdef FAST_MIXER
mixed = doMix4(samples, mix_mult[4]);
#else
mixed = doMix(samples,mix_map[4],mix_mult[4]);
#endif
asm("stw %0, %1[%2]"::
"r"(mixed),"r"(samples),
"r"(NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 4));
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
ComputeMixerLevel(mixed, 4);
#endif
#endif
#if MAX_MIX_COUNT > 6
#ifdef FAST_MIXER
mixed = doMix6(samples, mix_mult[6]);
#else
mixed = doMix(samples,mix_map[6],mix_mult[6]);
#endif
asm("stw %0, %1[%2]"::
"r"(mixed),"r"(samples),
"r"(NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 6));
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
ComputeMixerLevel(mixed, 6);
#endif
#endif
}
#else /* IF MAX_MIX_COUNT > 0 */
/* No mixes, this thread runs on its own doing just volume */
giveSamplesToDevice(c_mixer2, samples, samples_to_device_map, multOut);
getSamplesFromDevice(c_mixer2, samples, NUM_USB_CHAN_OUT);
giveSamplesToHost(c_host, samples, samples_to_host_map, multIn);
getSamplesFromHost(c_host, samples, 0);
#endif
}
}
}
int mixer2_mix2_flag = (DEFAULT_FREQ > 96000);
#pragma unsafe arrays
void mixer2(chanend c_mixer1, chanend c_audio)
{
int mixed;
while (1) {
outuint(c_mixer1, 0);
#pragma xta endpoint "mixer2_req"
inuint(c_audio);
if(testct(c_mixer1))
{
int sampFreq;
#pragma xta endpoint "mixer2_rate_change"
inct(c_mixer1);
sampFreq = inuint(c_mixer1);
mixer2_mix2_flag = sampFreq > 96000;
for (int i=0;i<MAX_MIX_COUNT;i++)
{
asm("stw %0, %1[%2]":: "r"(0),"r"(samples),"r"(NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + i));
}
/* Inform audio thread about freq change */
outct(c_audio, XS1_CT_END);
outuint(c_audio, sampFreq);
/* Wait for handshake and pass on */
chkct(c_audio, XS1_CT_END);
outct(c_mixer1, XS1_CT_END);
}
else {
(void) inuint(c_mixer1);
giveSamplesToDevice(c_audio, samples, samples_to_device_map, multOut);
inuint(c_mixer1);
outuint(c_mixer1, 0);
getSamplesFromDevice(c_audio, samples, NUM_USB_CHAN_OUT);
inuint(c_mixer1);
outuint(c_mixer1, 0);
#if MAX_MIX_COUNT > 1
#ifdef FAST_MIXER
mixed = doMix1(samples, mix_mult[1]);
#else
mixed = doMix(samples,mix_map[1],mix_mult[1]);
#endif
asm("stw %0, %1[%2]"::
"r"(mixed),"r"(samples),
"r"(NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 1));
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
ComputeMixerLevel(mixed, 1);
#endif
#endif
#if (MAX_FREQ > 96000)
if (!mixer2_mix2_flag)
#endif
{
#if MAX_MIX_COUNT > 3
#ifdef FAST_MIXER
mixed = doMix3(samples, mix_mult[3]);
#else
mixed = doMix(samples,mix_map[3],mix_mult[3]);
#endif
asm("stw %0, %1[%2]"::
"r"(mixed),"r"(samples),
"r"(NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 3));
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
ComputeMixerLevel(mixed, 3);
#endif
#endif
#if MAX_MIX_COUNT > 5
#ifdef FAST_MIXER
mixed = doMix5(samples, mix_mult[5]);
#else
mixed = doMix(samples,mix_map[5],mix_mult[5]);
#endif
asm("stw %0, %1[%2]"::
"r"(mixed),"r"(samples),
"r"(NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 5));
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
ComputeMixerLevel(mixed, 5);
#endif
#endif
#if MAX_MIX_COUNT > 7
#ifdef FAST_MIXER
mixed = doMix7(samples, mix_mult[7]);
#else
mixed = doMix(samples,mix_map[7],mix_mult[7]);
#endif
asm("stw %0, %1[%2]"::
"r"(mixed),"r"(samples),
"r"(NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 7));
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
ComputeMixerLevel(mixed, 7);
#endif
#endif
}
}
}
}
void mixer(chanend c_mix_in, chanend c_mix_out, chanend c_mix_ctl)
{
chan c;
for (int i=0;i<NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + MAX_MIX_COUNT;i++)
{
samples[i] = 0;
}
{
int num_mixes = DEFAULT_FREQ > 96000 ? 2 : MAX_MIX_COUNT;
for (int i=0;i<NUM_USB_CHAN_OUT;i++)
{
asm("stw %0, %1[%2]"::
"r"(i),
"r"(samples_to_device_map),
"r"(i));
}
}
#ifdef OUT_VOLUME_IN_MIXER
for (int i=0;i<NUM_USB_CHAN_OUT;i++)
{
multOut[i] = MAX_VOL;
}
#endif
#ifdef IN_VOLUME_IN_MIXER
for (int i=0;i<NUM_USB_CHAN_IN;i++)
{
multIn[i] = MAX_VOL;
}
#endif
for (int i=0;i<NUM_USB_CHAN_IN;i++)
{
samples_to_host_map[i] = NUM_USB_CHAN_OUT + i;
}
#if MAX_MIX_COUNT> 0
for (int i=0;i<MAX_MIX_COUNT;i++)
for (int j=0;j<MIX_INPUTS;j++)
{
#ifndef FAST_MIXER
mix_map[i][j] = j < 16 ? j : j + 2;
#endif
mix_mult[i][j] = i==j ? MAX_VOL >> 3 : 0;
}
#endif
par
{
#if (MAX_MIX_COUNT > 0)
mixer1(c_mix_in, c_mix_ctl, c);
mixer2(c, c_mix_out);
#else
mixer1(c_mix_in, c_mix_ctl, c_mix_out);
#endif
}
}
#endif

View File

@@ -0,0 +1,777 @@
#ifndef N
#error "N must be defined before including repeat.h"
#endif
#if N > 256
#error "N cannot be larger than 256"
#endif
#ifndef BODY
#error "BODY must be defined before including repeat.h"
#endif
#if N > 0
BODY(0)
#endif
#if N > 1
BODY(1)
#endif
#if N > 2
BODY(2)
#endif
#if N > 3
BODY(3)
#endif
#if N > 4
BODY(4)
#endif
#if N > 5
BODY(5)
#endif
#if N > 6
BODY(6)
#endif
#if N > 7
BODY(7)
#endif
#if N > 8
BODY(8)
#endif
#if N > 9
BODY(9)
#endif
#if N > 10
BODY(10)
#endif
#if N > 11
BODY(11)
#endif
#if N > 12
BODY(12)
#endif
#if N > 13
BODY(13)
#endif
#if N > 14
BODY(14)
#endif
#if N > 15
BODY(15)
#endif
#if N > 16
BODY(16)
#endif
#if N > 17
BODY(17)
#endif
#if N > 18
BODY(18)
#endif
#if N > 19
BODY(19)
#endif
#if N > 20
BODY(20)
#endif
#if N > 21
BODY(21)
#endif
#if N > 22
BODY(22)
#endif
#if N > 23
BODY(23)
#endif
#if N > 24
BODY(24)
#endif
#if N > 25
BODY(25)
#endif
#if N > 26
BODY(26)
#endif
#if N > 27
BODY(27)
#endif
#if N > 28
BODY(28)
#endif
#if N > 29
BODY(29)
#endif
#if N > 30
BODY(30)
#endif
#if N > 31
BODY(31)
#endif
#if N > 32
BODY(32)
#endif
#if N > 33
BODY(33)
#endif
#if N > 34
BODY(34)
#endif
#if N > 35
BODY(35)
#endif
#if N > 36
BODY(36)
#endif
#if N > 37
BODY(37)
#endif
#if N > 38
BODY(38)
#endif
#if N > 39
BODY(39)
#endif
#if N > 40
BODY(40)
#endif
#if N > 41
BODY(41)
#endif
#if N > 42
BODY(42)
#endif
#if N > 43
BODY(43)
#endif
#if N > 44
BODY(44)
#endif
#if N > 45
BODY(45)
#endif
#if N > 46
BODY(46)
#endif
#if N > 47
BODY(47)
#endif
#if N > 48
BODY(48)
#endif
#if N > 49
BODY(49)
#endif
#if N > 50
BODY(50)
#endif
#if N > 51
BODY(51)
#endif
#if N > 52
BODY(52)
#endif
#if N > 53
BODY(53)
#endif
#if N > 54
BODY(54)
#endif
#if N > 55
BODY(55)
#endif
#if N > 56
BODY(56)
#endif
#if N > 57
BODY(57)
#endif
#if N > 58
BODY(58)
#endif
#if N > 59
BODY(59)
#endif
#if N > 60
BODY(60)
#endif
#if N > 61
BODY(61)
#endif
#if N > 62
BODY(62)
#endif
#if N > 63
BODY(63)
#endif
#if N > 64
BODY(64)
#endif
#if N > 65
BODY(65)
#endif
#if N > 66
BODY(66)
#endif
#if N > 67
BODY(67)
#endif
#if N > 68
BODY(68)
#endif
#if N > 69
BODY(69)
#endif
#if N > 70
BODY(70)
#endif
#if N > 71
BODY(71)
#endif
#if N > 72
BODY(72)
#endif
#if N > 73
BODY(73)
#endif
#if N > 74
BODY(74)
#endif
#if N > 75
BODY(75)
#endif
#if N > 76
BODY(76)
#endif
#if N > 77
BODY(77)
#endif
#if N > 78
BODY(78)
#endif
#if N > 79
BODY(79)
#endif
#if N > 80
BODY(80)
#endif
#if N > 81
BODY(81)
#endif
#if N > 82
BODY(82)
#endif
#if N > 83
BODY(83)
#endif
#if N > 84
BODY(84)
#endif
#if N > 85
BODY(85)
#endif
#if N > 86
BODY(86)
#endif
#if N > 87
BODY(87)
#endif
#if N > 88
BODY(88)
#endif
#if N > 89
BODY(89)
#endif
#if N > 90
BODY(90)
#endif
#if N > 91
BODY(91)
#endif
#if N > 92
BODY(92)
#endif
#if N > 93
BODY(93)
#endif
#if N > 94
BODY(94)
#endif
#if N > 95
BODY(95)
#endif
#if N > 96
BODY(96)
#endif
#if N > 97
BODY(97)
#endif
#if N > 98
BODY(98)
#endif
#if N > 99
BODY(99)
#endif
#if N > 100
BODY(100)
#endif
#if N > 101
BODY(101)
#endif
#if N > 102
BODY(102)
#endif
#if N > 103
BODY(103)
#endif
#if N > 104
BODY(104)
#endif
#if N > 105
BODY(105)
#endif
#if N > 106
BODY(106)
#endif
#if N > 107
BODY(107)
#endif
#if N > 108
BODY(108)
#endif
#if N > 109
BODY(109)
#endif
#if N > 110
BODY(110)
#endif
#if N > 111
BODY(111)
#endif
#if N > 112
BODY(112)
#endif
#if N > 113
BODY(113)
#endif
#if N > 114
BODY(114)
#endif
#if N > 115
BODY(115)
#endif
#if N > 116
BODY(116)
#endif
#if N > 117
BODY(117)
#endif
#if N > 118
BODY(118)
#endif
#if N > 119
BODY(119)
#endif
#if N > 120
BODY(120)
#endif
#if N > 121
BODY(121)
#endif
#if N > 122
BODY(122)
#endif
#if N > 123
BODY(123)
#endif
#if N > 124
BODY(124)
#endif
#if N > 125
BODY(125)
#endif
#if N > 126
BODY(126)
#endif
#if N > 127
BODY(127)
#endif
#if N > 128
BODY(128)
#endif
#if N > 129
BODY(129)
#endif
#if N > 130
BODY(130)
#endif
#if N > 131
BODY(131)
#endif
#if N > 132
BODY(132)
#endif
#if N > 133
BODY(133)
#endif
#if N > 134
BODY(134)
#endif
#if N > 135
BODY(135)
#endif
#if N > 136
BODY(136)
#endif
#if N > 137
BODY(137)
#endif
#if N > 138
BODY(138)
#endif
#if N > 139
BODY(139)
#endif
#if N > 140
BODY(140)
#endif
#if N > 141
BODY(141)
#endif
#if N > 142
BODY(142)
#endif
#if N > 143
BODY(143)
#endif
#if N > 144
BODY(144)
#endif
#if N > 145
BODY(145)
#endif
#if N > 146
BODY(146)
#endif
#if N > 147
BODY(147)
#endif
#if N > 148
BODY(148)
#endif
#if N > 149
BODY(149)
#endif
#if N > 150
BODY(150)
#endif
#if N > 151
BODY(151)
#endif
#if N > 152
BODY(152)
#endif
#if N > 153
BODY(153)
#endif
#if N > 154
BODY(154)
#endif
#if N > 155
BODY(155)
#endif
#if N > 156
BODY(156)
#endif
#if N > 157
BODY(157)
#endif
#if N > 158
BODY(158)
#endif
#if N > 159
BODY(159)
#endif
#if N > 160
BODY(160)
#endif
#if N > 161
BODY(161)
#endif
#if N > 162
BODY(162)
#endif
#if N > 163
BODY(163)
#endif
#if N > 164
BODY(164)
#endif
#if N > 165
BODY(165)
#endif
#if N > 166
BODY(166)
#endif
#if N > 167
BODY(167)
#endif
#if N > 168
BODY(168)
#endif
#if N > 169
BODY(169)
#endif
#if N > 170
BODY(170)
#endif
#if N > 171
BODY(171)
#endif
#if N > 172
BODY(172)
#endif
#if N > 173
BODY(173)
#endif
#if N > 174
BODY(174)
#endif
#if N > 175
BODY(175)
#endif
#if N > 176
BODY(176)
#endif
#if N > 177
BODY(177)
#endif
#if N > 178
BODY(178)
#endif
#if N > 179
BODY(179)
#endif
#if N > 180
BODY(180)
#endif
#if N > 181
BODY(181)
#endif
#if N > 182
BODY(182)
#endif
#if N > 183
BODY(183)
#endif
#if N > 184
BODY(184)
#endif
#if N > 185
BODY(185)
#endif
#if N > 186
BODY(186)
#endif
#if N > 187
BODY(187)
#endif
#if N > 188
BODY(188)
#endif
#if N > 189
BODY(189)
#endif
#if N > 190
BODY(190)
#endif
#if N > 191
BODY(191)
#endif
#if N > 192
BODY(192)
#endif
#if N > 193
BODY(193)
#endif
#if N > 194
BODY(194)
#endif
#if N > 195
BODY(195)
#endif
#if N > 196
BODY(196)
#endif
#if N > 197
BODY(197)
#endif
#if N > 198
BODY(198)
#endif
#if N > 199
BODY(199)
#endif
#if N > 200
BODY(200)
#endif
#if N > 201
BODY(201)
#endif
#if N > 202
BODY(202)
#endif
#if N > 203
BODY(203)
#endif
#if N > 204
BODY(204)
#endif
#if N > 205
BODY(205)
#endif
#if N > 206
BODY(206)
#endif
#if N > 207
BODY(207)
#endif
#if N > 208
BODY(208)
#endif
#if N > 209
BODY(209)
#endif
#if N > 210
BODY(210)
#endif
#if N > 211
BODY(211)
#endif
#if N > 212
BODY(212)
#endif
#if N > 213
BODY(213)
#endif
#if N > 214
BODY(214)
#endif
#if N > 215
BODY(215)
#endif
#if N > 216
BODY(216)
#endif
#if N > 217
BODY(217)
#endif
#if N > 218
BODY(218)
#endif
#if N > 219
BODY(219)
#endif
#if N > 220
BODY(220)
#endif
#if N > 221
BODY(221)
#endif
#if N > 222
BODY(222)
#endif
#if N > 223
BODY(223)
#endif
#if N > 224
BODY(224)
#endif
#if N > 225
BODY(225)
#endif
#if N > 226
BODY(226)
#endif
#if N > 227
BODY(227)
#endif
#if N > 228
BODY(228)
#endif
#if N > 229
BODY(229)
#endif
#if N > 230
BODY(230)
#endif
#if N > 231
BODY(231)
#endif
#if N > 232
BODY(232)
#endif
#if N > 233
BODY(233)
#endif
#if N > 234
BODY(234)
#endif
#if N > 235
BODY(235)
#endif
#if N > 236
BODY(236)
#endif
#if N > 237
BODY(237)
#endif
#if N > 238
BODY(238)
#endif
#if N > 239
BODY(239)
#endif
#if N > 240
BODY(240)
#endif
#if N > 241
BODY(241)
#endif
#if N > 242
BODY(242)
#endif
#if N > 243
BODY(243)
#endif
#if N > 244
BODY(244)
#endif
#if N > 245
BODY(245)
#endif
#if N > 246
BODY(246)
#endif
#if N > 247
BODY(247)
#endif
#if N > 248
BODY(248)
#endif
#if N > 249
BODY(249)
#endif
#if N > 250
BODY(250)
#endif
#if N > 251
BODY(251)
#endif
#if N > 252
BODY(252)
#endif
#if N > 253
BODY(253)
#endif
#if N > 254
BODY(254)
#endif
#if N > 255
BODY(255)
#endif

View File

@@ -0,0 +1,32 @@
# This file describes how this module will affect the application
# using it. The file is included in the Makefile of the main application.
#
# The module contributes to the build of the application by extending
# the following variables:
#
# SOURCE_DIRS - directories with source files to be included in the build
# INCLUDE_DIRS - directories to be added to the include path during the build
# LIB_DIRS - directories containing libraries to be linked into the build
#
# Note that all the source files in each directory in SOURCE_DIRS
# will be compiled (you do not need to name the files individually).
#
# You can change the flags of a set of files using the SET_XCC_[lang]_FLAGS
# functions. The first argument is a list of directories and the
# second argument is the value to set the compile flags to. e.g.
#
# $(call SET_XCC_C_FLAGS, mydir1 mydir2, $(XCC_FLAGS) -g -O3)
# You can change the flags of an individual file by setting the
# XCC_FLAGS_[filename] variable. e.g.
#
# XCC_FLAGS_myfile.xc = $(XCC_FLAGS) -fsubword-select
# You can exclude particular files from the build even if they occur
# within SOURCE_DIRS by adding the file name (with no path) to the
# EXCLUDE_FILES variable e..g
#
EXCLUDE_FILES += descriptors_2.rst

View File

@@ -0,0 +1 @@
Common USB Audio source files/headers.

View File

@@ -0,0 +1,4 @@
void PllInit(void);
void PllMult(unsigned mult);

View File

@@ -0,0 +1,6 @@
#ifndef _AUDIOPORTS_H_
#define _AUDIOPORTS_H_
void ConfigAudioPorts(unsigned int divide);
#endif

View File

@@ -0,0 +1,138 @@
#include <xs1.h>
#include "devicedefines.h"
#include "audioports.h"
/* Audio IOs */
#if (I2S_CHANS_DAC != 0)
extern buffered out port:32 p_i2s_dac[I2S_WIRES_DAC];
#endif
#if (I2S_CHANS_ADC != 0)
extern buffered in port:32 p_i2s_adc[I2S_WIRES_ADC];
#endif
#if (I2S_CHANS_DAC != 0) || (I2S_CHANS_ADC != 0)
#ifdef CODEC_SLAVE
extern buffered out port:32 p_lrclk;
extern buffered out port:32 p_bclk;
#else
extern in port p_lrclk;
extern in port p_bclk;
#endif
#endif
extern port p_mclk;
extern clock clk_audio_mclk;
extern clock clk_audio_bclk;
void ConfigAudioPorts(unsigned int divide)
{
#ifdef CODEC_SLAVE
/* Output 0 on BCLK to ensure clock is low
* Required as stop_clock will only complete when the clock is low
*/
configure_out_port_no_ready(p_bclk, clk_audio_mclk, 0);
p_bclk <: 0;
/* Stop bit and master clock blocks and clear port buffers */
stop_clock(clk_audio_bclk);
stop_clock(clk_audio_mclk);
clearbuf(p_lrclk);
clearbuf(p_bclk);
#if (I2S_CHANS_ADC != 0)
for(int i = 0; i < I2S_WIRES_ADC; i++)
{
clearbuf(p_i2s_adc[i]);
}
#endif
#if (I2S_CHANS_DAC != 0)
for(int i = 0; i < I2S_WIRES_DAC; i++)
{
clearbuf(p_i2s_dac[i]);
}
#endif
/* Clock master clock-block from master-clock port */
configure_clock_src(clk_audio_mclk, p_mclk);
/* For a divide of one (i.e. bitclock == master-clock) BClk is set to clock_output mode.
* In this mode it outputs an edge clock on every tick of itsassociated clock_block.
*
* For all other divides, BClk is clocked by the master clock and data
* will be output to p_bclk to generate the bit clock.
*/
if (divide == 1) /* e.g. 176.4KHz from 11.2896 */
{
configure_port_clock_output(p_bclk, clk_audio_mclk);
}
else
{
/* bit clock port from master clock clock-clock block */
configure_out_port_no_ready(p_bclk, clk_audio_mclk, 0);
}
/* Generate bit clock block from pin */
configure_clock_src(clk_audio_bclk, p_bclk);
#if (I2S_CHANS_DAC != 0)
/* Clock I2S output data ports from clock block */
for(int i = 0; i < I2S_WIRES_DAC; i++)
{
configure_out_port_no_ready(p_i2s_dac[i], clk_audio_bclk, 0);
}
#endif
#if (I2S_CHANS_ADC != 0)
/* Clock I2S input data ports from clock block */
for(int i = 0; i < I2S_WIRES_ADC; i++)
{
configure_in_port_no_ready(p_i2s_adc[i], clk_audio_bclk);
}
#endif
/* Clock LR clock from bit clock-block */
configure_out_port_no_ready(p_lrclk, clk_audio_bclk, 0);
/* Start clock blocks ticking */
start_clock(clk_audio_mclk);
start_clock(clk_audio_bclk);
/* bclk initial state needs to be high */
p_bclk <: 0xFFFFFFFF;
/* Pause until output completes */
sync(p_bclk);
#else
/* Stop bit and master clock blocks and clear port buffers */
stop_clock(clk_audio_bclk);
stop_clock(clk_audio_mclk);
/* Clock bclk clock-block from bclk pin */
configure_clock_src(clk_audio_bclk, p_bclk);
/* Clock I2S output data ports from b-clock clock block */
for(int i = 0; i < I2S_WIRES_DAC; i++)
{
configure_out_port_no_ready(p_i2s_dac[i], clk_audio_bclk, 0);
}
/* Clock I2S input data ports from clock block */
for(int i = 0; i < I2S_WIRES_ADC; i++)
{
configure_in_port_no_ready(p_i2s_adc[i], clk_audio_bclk);
}
configure_in_port_no_ready(p_lrclk, clk_audio_bclk);
start_clock(clk_audio_bclk);
#endif
}

View File

@@ -0,0 +1,15 @@
#include <xs1.h>
#include <print.h>
int write_sswitch_reg_blind(unsigned coreid, unsigned reg, unsigned data);
/* Reboots XMOS device by writing to the PLL config register */
void device_reboot(void)
{
unsigned int pllVal;
unsigned int core_id = get_core_id();
read_sswitch_reg(core_id, 6, &pllVal);
write_sswitch_reg_blind(core_id^0x8000, 6, pllVal);
write_sswitch_reg_blind(core_id, 6, pllVal);
}

View File

@@ -0,0 +1,18 @@
#ifndef __decouple_h__
#define __decouple_h__
/** Manage the data transfer between the USB audio buffer and the
* Audio I/O driver.
*
* \param c_audio_out Channel connected to the audio() or mixer() threads
* \param c_led Optional chanend connected to an led driver thread for
* debugging purposes
* \param c_midi Optional chanend connect to usb_midi() thread if present
* \param c_clk_int Optional chanend connected to the clockGen() thread if present
*/
void decouple(chanend c_audio_out,
chanend ?c_led,
chanend ?c_midi, chanend ?c_clk_int);
#endif // __decouple_h__

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,24 @@
extern unsigned int g_curUsbSpeed;
#define XUD_SPEED_HS 2
void GetADCCounts(unsigned samFreq, int *min, int *mid, int *max)
{
unsigned frameTime;
int usb_speed;
usb_speed = g_curUsbSpeed;
if (usb_speed == XUD_SPEED_HS)
frameTime = 8000;
else
frameTime = 1000;
*min = samFreq / frameTime;
*max = *min + 1;
*mid = *min;
/* Check for INT(SampFreq/8000) == SampFreq/8000 */
if((samFreq % frameTime) == 0)
{
*min -= 1;
}
}

View File

@@ -0,0 +1,198 @@
#ifndef __interrupt_h__
#define __interrupt_h__
#define store_args0(c) \
asm("kentsp 19; stw %0, sp[1]; krestsp 19"::"r"(c));
#define store_args1(c,x) \
asm("kentsp 20; stw %0, sp[1]; stw %1, sp[2]; krestsp 20"::"r"(c),"r"(x));
#define store_args2(c,x0,x1) \
asm("kentsp 21; stw %0, sp[1];" \
"stw %1, sp[2];" \
"stw %2, sp[3];" \
" krestsp 21"::"r"(c),"r"(x0),"r"(x1));
#define store_args3(c,x0,x1,x2) \
asm("kentsp 22; stw %0, sp[1];" \
"stw %1, sp[2];" \
"stw %2, sp[3];" \
"stw %3, sp[4];" \
" krestsp 22"::"r"(c),"r"(x0),"r"(x1),"r"(x2));
#define store_args4(c,x0,x1,x2,x3) \
asm("kentsp 23; stw %4, sp[1];" \
"stw %0, sp[2];" \
"stw %1, sp[3];" \
"stw %2, sp[4];" \
"stw %3, sp[5];" \
" krestsp 23"::"r"(c),"r"(x0),"r"(x1),"r"(x2),"r"(x3));
#define store_args5(c,x0,x1,x2,x3,x4) \
asm("kentsp 24;" \
"stw %4, sp[1];" \
"stw %5, sp[2];" \
"stw %0, sp[3];" \
"stw %1, sp[4];" \
"stw %2, sp[5];" \
"stw %3, sp[6];" \
" krestsp 24"::"r"(c),"r"(x0),"r"(x1),"r"(x2),"r"(x3),"r"(x4));
#define store_args6(c,x0,x1,x2,x3,x4,x5) \
asm("kentsp 25;" \
"stw %4, sp[1];" \
"stw %5, sp[2];" \
"stw %6, sp[3];" \
"stw %0, sp[4];" \
"stw %1, sp[5];" \
"stw %2, sp[6];" \
"stw %3, sp[7];" \
" krestsp 25"::"r"(c),"r"(x0),"r"(x1),"r"(x2),"r"(x3),"r"(x4),"r"(x5));
#define store_args7(c,x0,x1,x2,x3,x4,x5,x6) \
asm("kentsp 26;" \
"stw %4, sp[1];" \
"stw %5, sp[2];" \
"stw %6, sp[3];" \
"stw %7, sp[4];" \
"stw %0, sp[5];" \
"stw %1, sp[6];" \
"stw %2, sp[7];" \
"stw %3, sp[8];" \
" krestsp 26"::"r"(c),"r"(x0),"r"(x1),"r"(x2),"r"(x3),"r"(x4),"r"(x5),"r"(x6));
#define store_args8(c,x0,x1,x2,x3,x4,x5,x6,x7) \
asm("kentsp 27;" \
"stw %4, sp[1];" \
"stw %5, sp[2];" \
"stw %6, sp[3];" \
"stw %7, sp[4];" \
"stw %8, sp[5];" \
"stw %0, sp[6];" \
"stw %1, sp[7];" \
"stw %2, sp[8];" \
"stw %3, sp[9];" \
" krestsp 27"::"r"(c),"r"(x0),"r"(x1),"r"(x2),"r"(x3),"r"(x4),"r"(x5),"r"(x6),"r"(x7));
#define load_args0(f) \
"ldw r0, sp[1]\n"
#define load_args1(f)\
"ldw r0, sp[1]\n" \
"ldw r1, sp[2]\n"
#define load_args2(f)\
"ldw r0, sp[1]\n" \
"ldw r1, sp[2]\n" \
"ldw r2, sp[3]\n"
#define load_args3(f)\
"ldw r0, sp[1]\n" \
"ldw r1, sp[2]\n" \
"ldw r2, sp[3]\n" \
"ldw r3, sp[4]\n"
#define load_argsn(f, args) \
".linkset __"#f"_handler_arg0, "#args"-2\n"\
"ldw r0, sp[" "__"#f"_handler_arg0" "]\n" \
".linkset __"#f"_handler_arg1, "#args"-1\n"\
"ldw r1, sp[" "__"#f"_handler_arg1" "]\n" \
".linkset __"#f"_handler_arg2, "#args"-0\n"\
"ldw r2, sp[" "__"#f"_handler_arg2" "]\n" \
".linkset __"#f"_handler_arg3, "#args"+1\n"\
"ldw r3, sp[" "__"#f"_handler_arg3" "]\n"
#define load_args4(f) load_argsn(f,4)
#define load_args5(f) load_argsn(f,5)
#define load_args6(f) load_argsn(f,6)
#define load_args7(f) load_argsn(f,7)
#define load_args8(f) load_argsn(f,8)
#define save_state(f,args) \
".linkset __"#f"_handler_r0_save, "#args"+12\n" \
"stw r0, sp[" "__"#f"_handler_r0_save" "]\n" \
".linkset __"#f"_handler_r1_save, "#args"+13\n" \
"stw r1, sp[" "__"#f"_handler_r1_save" "]\n" \
".linkset __"#f"_handler_r2_save, "#args"+2\n" \
"stw r2, sp[" "__"#f"_handler_r2_save" "]\n" \
".linkset __"#f"_handler_r3_save, "#args"+3\n" \
"stw r3, sp[" "__"#f"_handler_r3_save" "]\n" \
".linkset __"#f"_handler_r4_save, "#args"+4\n" \
"stw r4, sp[" "__"#f"_handler_r4_save" "]\n" \
".linkset __"#f"_handler_r5_save, "#args"+5\n" \
"stw r5, sp[" "__"#f"_handler_r5_save" "]\n" \
".linkset __"#f"_handler_r6_save, "#args"+6\n" \
"stw r6, sp[" "__"#f"_handler_r6_save" "]\n" \
".linkset __"#f"_handler_r7_save, "#args"+7\n" \
"stw r7, sp[" "__"#f"_handler_r7_save" "]\n" \
".linkset __"#f"_handler_r8_save, "#args"+8\n" \
"stw r8, sp[" "__"#f"_handler_r8_save" "]\n" \
".linkset __"#f"_handler_r9_save, "#args"+9\n" \
"stw r9, sp[" "__"#f"_handler_r9_save" "]\n" \
".linkset __"#f"_handler_r10_save, "#args"+10\n" \
"stw r10, sp[" "__"#f"_handler_r10_save" "]\n" \
".linkset __"#f"_handler_r11_save, "#args"+11\n" \
"stw r11, sp[" "__"#f"_handler_r11_save" "]\n" \
".linkset __"#f"_handler_lr_save, "#args"+14\n" \
"stw lr, sp[" "__"#f"_handler_lr_save" "]\n"
#define restore_state(f,args) \
"ldw r0, sp[" "__"#f"_handler_r0_save" "]\n" \
"ldw r1, sp[" "__"#f"_handler_r1_save" "]\n" \
"ldw r2, sp[" "__"#f"_handler_r2_save" "]\n" \
"ldw r3, sp[" "__"#f"_handler_r3_save" "]\n" \
"ldw r4, sp[" "__"#f"_handler_r4_save" "]\n" \
"ldw r5, sp[" "__"#f"_handler_r5_save" "]\n" \
"ldw r6, sp[" "__"#f"_handler_r6_save" "]\n" \
"ldw r7, sp[" "__"#f"_handler_r7_save" "]\n" \
"ldw r8, sp[" "__"#f"_handler_r8_save" "]\n" \
"ldw r9, sp[" "__"#f"_handler_r9_save" "]\n" \
"ldw r10, sp[" "__"#f"_handler_r10_save" "]\n" \
"ldw r11, sp[" "__"#f"_handler_r11_save" "]\n" \
"ldw lr, sp[" "__"#f"_handler_lr_save" "]\n"
#define STRINGIFY0(x) #x
#define STRINGIFY(x) STRINGIFY0(x)
#define ENABLE_INTERRUPTS() asm("setsr " STRINGIFY(XS1_SR_IEBLE_SET(0, 1)))
#define DISABLE_INTERRUPTS() asm("clrsr " STRINGIFY(XS1_SR_IEBLE_SET(0, 1)))
//int ksp_enter, ksp_exit, r11_store;
#define do_interrupt_handler(f,args) \
asm("bu .L__" #f "_handler_skip;\n" \
"__" #f "_handler:\n" \
"kentsp " #args " + 19\n" \
"__kent:" \
save_state(f,args) \
load_args ## args (f) \
"bl " #f "\n" \
restore_state(f,args) \
"krestsp " #args " + 19 \n" \
"__kret:\n" \
"kret\n" \
".L__" #f "_handler_skip:\n");
#define set_interrupt_handler(f, nstackwords, args, c, ...) \
asm (" .section .dp.data, \"adw\", @progbits\n" \
" .align 4\n" \
"__" #f "_kernel_stack:\n" \
" .space " #nstackwords ", 0\n" \
" .text\n"); \
asm("mov r10, %0; ldaw r11, dp[__" #f "_kernel_stack];add r11, r11, r10;ldaw r10, sp[0]; "\
"set sp,r11;stw r10, sp[0]; krestsp 0"::"r"(nstackwords-8):"r10","r11"); \
store_args ## args(c, __VA_ARGS__) \
do_interrupt_handler(f, args) \
asm("ldap r11, __" #f "_handler; setv res[%0],r11"::"r"(c):"r11"); \
asm("setc res[%0], 0xa; eeu res[%0]"::"r"(c)); \
asm("setsr (((0) & ~(((1 << 0x1) - 1) << 0x1)) | (((1) << 0x1) & (((1 << 0x1) - 1) << 0x1)))");
#endif

View File

@@ -0,0 +1,2 @@
#pragma select handler
void testct_byref(chanend c, unsigned &isCt) ;

View File

@@ -0,0 +1,15 @@
#include <xs1.h>
/* TODO Currently complier does not support inline select functions, hense this is in a seperate file to ensure this is not the case */
#pragma select handler
void testct_byref(chanend c, unsigned &isCt)
{
if (testct(c))
{
isCt = 1;
}
else
{
isCt = 0;
}
}

View File

@@ -0,0 +1,14 @@
#if 0
{
tmr :> sof_time;
if (last_sof_time && ((sof_time - last_sof_time) > 20000)) {
missed_sofcount = sofCount;
missed_count--;
if (!missed_count) {
asm("ecallf %0"::"r"(0));
}
}
last_sof_time = sof_time;
}
#endif

View File

@@ -0,0 +1,28 @@
#ifndef __usb_buffer_h__
#define __usb_buffer_h__
/** USB Audio Buffering Thread.
*
* This function buffers USB audio data between the XUD layer and the decouple
* thread. Most of the chanend parameters to the function should be connected to
* XUD_Manager()
*
* \param c_aud_out Audio OUT endpoint channel connected to the XUD
* \param c_aud_in Audio IN endpoint channel connected to the XUD
* \param c_aud_fb Audio feedback endpoint channel connected to the XUD
* \param c_midi_from_host MIDI OUT endpoint channel connected to the XUD
* \param c_midi_to_host MIDI IN endpoint channel connected to the XUD
* \param c_int Audio clocking interrupt endpoint channel connected to the XUD
* \param c_sof Start of frame channel connected to the XUD
* \param c_aud_ctl Audio control channel connected to Endpoint0()
* \param p_off_mclk A port that is clocked of the MCLK input (not the MCLK input itself)
*/
void buffer(chanend c_aud_out, chanend c_aud_in, chanend c_aud_fb,
chanend c_midi_from_host,
chanend c_midi_to_host,
chanend c_int,
chanend c_sof,
chanend c_aud_ctl,
in port p_off_mclk);
#endif

View File

@@ -0,0 +1,508 @@
#include <xs1.h>
#include <print.h>
//In this file xud.h is not included since we are interpreting the
//assembly functions GetData/SetData as taking xc_ptrs
//#include "xud.h"
#define XUD_SPEED_HS 2
#include "usb.h"
#include "devicedefines.h"
#include "usb_midi.h"
#include "xc_ptr.h"
#include "clockcmds.h"
#include "xud.h"
//typedef unsigned int XUD_ep;
//int XUD_GetData_NoReq(chanend c, xc_ptr buffer);
//int XUD_SetData_NoReq(chanend c, xc_ptr buffer, unsigned datalength, unsigned startIndex);
XUD_ep XUD_Init_Ep(chanend c_ep);
inline void XUD_SetNotReady(XUD_ep e)
{
int chan_array_ptr;
asm ("ldw %0, %1[0]":"=r"(chan_array_ptr):"r"(e));
asm ("stw %0, %1[0]"::"r"(0),"r"(chan_array_ptr));
}
void GetADCCounts(unsigned samFreq, int &min, int &mid, int &max);
#define BUFFER_SIZE_OUT (1028 >> 2)
#define BUFFER_SIZE_IN (1028 >> 2)
/* Packet buffers for audio data */
extern unsigned int g_curSamFreqMultiplier;
/* Global var for speed. Related to feedback. Used by input stream to determine IN packet size */
unsigned g_speed;
unsigned g_freqChange = 0;
/* Interrupt EP data */
unsigned char g_intData[8];
#ifdef MIDI
static inline void swap(xc_ptr &a, xc_ptr &b)
{
xc_ptr tmp;
tmp = a;
a = b;
b = tmp;
return;
}
#endif
unsigned char fb_clocks[16];
//#define FB_TOLERANCE_TEST
#define FB_TOLERANCE 0x100
extern unsigned inZeroBuff[];
extern unsigned g_numUsbChanIn;
/**
* Buffers data from audio endpoints
* @param c_aud_out chanend for audio from xud
* @param c_aud_in chanend for audio to xud
* @param c_aud_fb chanend for feeback to xud
* @return void
*/
void buffer(register chanend c_aud_out, register chanend c_aud_in, chanend c_aud_fb,
chanend c_midi_from_host,
chanend c_midi_to_host,
chanend c_int, chanend c_sof,
chanend c_aud_ctl,
in port p_off_mclk
)
{
XUD_ep ep_aud_out = XUD_Init_Ep(c_aud_out);
XUD_ep ep_aud_in = XUD_Init_Ep(c_aud_in);
XUD_ep ep_aud_fb = XUD_Init_Ep(c_aud_fb);
#ifdef MIDI
XUD_ep ep_midi_from_host = XUD_Init_Ep(c_midi_from_host);
XUD_ep ep_midi_to_host = XUD_Init_Ep(c_midi_to_host);
#endif
XUD_ep ep_int = XUD_Init_Ep(c_int);
unsigned datalength;
unsigned tmp;
unsigned sampleFreq = 0;
unsigned lastClock;
unsigned clocks = 0;
unsigned bufferIn = 1;
unsigned remnant = 0, cycles;
unsigned sofCount = 0;
unsigned freqChange = 0;
//unsigned expected = (DEFAULT_FREQ/8000)<<16;
#ifdef FB_TOLERANCE_TEST
unsigned expected_fb = 0;
#endif
xc_ptr aud_from_host_buffer = 0;
#ifdef MIDI
xc_ptr midi_from_host_buffer = 0;
xc_ptr midi_to_host_buffer = 0;
xc_ptr midi_to_host_waiting_buffer = 0;
#endif
set_thread_fast_mode_on();
asm("stw %0, dp[int_usb_ep]"::"r"(ep_int));
asm("stw %0, dp[aud_from_host_usb_ep]"::"r"(ep_aud_out));
asm("stw %0, dp[aud_to_host_usb_ep]"::"r"(ep_aud_in));
asm("stw %0, dp[buffer_aud_ctl_chan]"::"r"(c_aud_ctl));
/* Wait for USB connect then setup our first packet */
{
int min, mid, max;
int usb_speed = 0;
int frameTime;
while(usb_speed == 0)
asm("ldw %0, dp[g_curUsbSpeed]" : "=r" (usb_speed) :);
GetADCCounts(DEFAULT_FREQ, min, mid, max);
asm("stw %0, dp[g_speed]"::"r"(mid << 16));
if (usb_speed == XUD_SPEED_HS)
mid*=NUM_USB_CHAN_IN*4;
else
mid*=NUM_USB_CHAN_IN*3;
asm("stw %0, %1[0]"::"r"(mid),"r"(inZeroBuff));
#ifdef FB_TOLERANCE_TEST
expected_fb = ((DEFAULT_FREQ * 0x2000) / 1000);
#endif
}
#ifdef MIDI
// get the two buffers to use for midi device->host
asm("ldaw %0, dp[g_midi_to_host_buffer_A]":"=r"(midi_to_host_buffer));
asm("ldaw %0, dp[g_midi_to_host_buffer_B]":"=r"(midi_to_host_waiting_buffer));
asm("ldaw %0, dp[g_midi_from_host_buffer]":"=r"(midi_from_host_buffer));
// pass the midi->XUD chanends to decouple so that thread can
// initialize comm with XUD
asm("stw %0, dp[midi_to_host_usb_ep]"::"r"(ep_midi_to_host));
asm("stw %0, dp[midi_from_host_usb_ep]"::"r"(ep_midi_from_host));
swap(midi_to_host_buffer, midi_to_host_waiting_buffer);
SET_SHARED_GLOBAL(g_midi_from_host_flag, 1);
#endif
#ifdef OUTPUT
SET_SHARED_GLOBAL(g_aud_from_host_flag, 1);
#endif
#ifdef INPUT
SET_SHARED_GLOBAL(g_aud_to_host_flag, 1);
#endif
(fb_clocks, unsigned[])[0] = 0;
{
int usb_speed;
int x;
asm("ldaw %0, dp[fb_clocks]":"=r"(x));
asm("ldw %0, dp[g_curUsbSpeed]" : "=r" (usb_speed) :);
if (usb_speed == XUD_SPEED_HS)
{
XUD_SetReady_In(ep_aud_fb, PIDn_DATA0, x, 4);
}
else
{
XUD_SetReady_In(ep_aud_fb, PIDn_DATA0, x, 3);
}
}
while(1)
{
/* Wait for response from XUD and service relevant EP */
select
{
/* Interrupt EP, send back interrupt data. Note, request made from decouple */
case inuint_byref(c_int, tmp):
{
int sent_ok = 0;
/* Start XUD_SetData */
XUD_SetData_Inline(ep_int, c_int);
#if 0
while (!sent_ok)
{
outct(c_int, 64);
asm("ldw %0, dp[g_intData]":"=r"(tmp));
outuint(c_int, tmp);
asm("ldw %0, dp[g_intData+4]":"=r"(tmp));
outct(c_int, 64);
outuint(c_int, tmp);
sent_ok = inuint(c_int);
/* End XUD_SetData */
}
#endif
asm("stw %0, dp[g_intFlag]" :: "r" (0) );
XUD_SetNotReady(ep_int);
break;
}
/* Sample Freq our chan count update from ep 0 */
case inuint_byref(c_aud_ctl, tmp):
{
int min, mid, max;
int usb_speed;
int frameTime;
asm("ldw %0, dp[g_curUsbSpeed]" : "=r" (usb_speed) :);
if(tmp == SET_SAMPLE_FREQ)
{
sampleFreq = inuint(c_aud_ctl);
/* Tidy up double buffer, note we can do better than this for 44.1 etc but better
* than sending two packets at old speed! */
if (usb_speed == XUD_SPEED_HS)
frameTime = 8000;
else
frameTime = 1000;
min = sampleFreq / frameTime;
max = min + 1;
mid = min;
/* Check for INT(SampFreq/8000) == SampFreq/8000 */
if((sampleFreq % frameTime) == 0)
{
min -= 1;
}
#ifdef FB_TOLERANCE_TEST
expected_fb = ((sampleFreq * 0x2000) / frametime);
#endif
asm("stw %0, dp[g_speed]"::"r"(mid << 16));
if (usb_speed == XUD_SPEED_HS)
mid *= NUM_USB_CHAN_IN*4;
else
mid *= NUM_USB_CHAN_IN*3;
asm("stw %0, %1[0]"::"r"(mid),"r"(inZeroBuff));
/* Reset FB */
/* Note, Endpoint 0 will hold off host for a sufficient period to allow out feedback
* to stabilise (i.e. sofCount == 128 to fire) */
sofCount = 0;
clocks = 0;
remnant = 0;
/* Ideally we want to wait for handshake (and pass back up) here. But we cannot keep this
* thread locked, it must stay responsive to packets/SOFs. So, set a flag and check for
* handshake elsewhere */
/* Pass on sample freq change to decouple */
SET_SHARED_GLOBAL(g_freqChange, SET_SAMPLE_FREQ);
SET_SHARED_GLOBAL(g_freqChange_sampFreq, sampleFreq);
SET_SHARED_GLOBAL(g_freqChange_flag, SET_SAMPLE_FREQ);
}
else
{
sampleFreq = inuint(c_aud_ctl);
SET_SHARED_GLOBAL(g_freqChange, tmp); /* Set command */
SET_SHARED_GLOBAL(g_freqChange_sampFreq, sampleFreq); /* Set flag */
SET_SHARED_GLOBAL(g_freqChange_flag, tmp);
}
break;
}
#define MASK_16_13 (7) // Bits that should not be transmitted as part of feedback.
#define MASK_16_10 (127) //(63) /* For Audio 1.0 we use a mask 1 bit longer than expected to avoid Windows LSB isses */
case inuint_byref(c_sof, tmp):
/* NOTE our feedback will be wrong for a couple of SOF's after a SF change due to
* lastClock being incorrect */
asm("#sof");
/* Get MCLK count */
asm (" getts %0, res[%1]" : "=r" (tmp) : "r" (p_off_mclk));
GET_SHARED_GLOBAL(freqChange, g_freqChange);
if(freqChange == SET_SAMPLE_FREQ)
{
/* Keep getting MCLK counts */
lastClock = tmp;
}
else
{
unsigned mask = MASK_16_13, usb_speed;
asm("ldw %0, dp[g_curUsbSpeed]" : "=r" (usb_speed) :);
if(usb_speed != XUD_SPEED_HS)
mask = MASK_16_10;
/* Number of MCLKS this SOF, approx 125 * 24 (3000), sample by sample rate */
asm("ldw %0, dp[g_curSamFreqMultiplier]":"=r"(cycles));
cycles = ((int)((short)(tmp - lastClock))) * cycles;
/* Any odd bits (lower than 16.23) have to be kept seperate */
remnant += cycles & mask;
/* Add 16.13 bits into clock count */
clocks += (cycles & ~mask) + (remnant & ~mask);
/* and overflow from odd bits. Remove overflow from odd bits. */
remnant &= mask;
/* Store MCLK for next time around... */
lastClock = tmp;
/* Reset counts based on SOF counting. Expect 16ms (128 HS SOFs/16 FS SOFS) per feedback poll
* We always could 128 sofs, so 16ms @ HS, 128ms @ FS */
if(sofCount == 128)
{
sofCount = 0;
#ifdef FB_TOLERANCE_TEST
if (clocks > (expected_fb - FB_TOLERANCE) &&
clocks < (expected_fb + FB_TOLERANCE))
#endif
{
int usb_speed;
asm("stw %0, dp[g_speed]"::"r"(clocks)); // g_speed = clocks
//fb_clocks = clocks;
asm("ldw %0, dp[g_curUsbSpeed]" : "=r" (usb_speed) :);
if (usb_speed == XUD_SPEED_HS)
{
(fb_clocks, unsigned[])[0] = clocks;
}
else
{
(fb_clocks, unsigned[])[0] = clocks>>2;
}
}
#ifdef FB_TOLERANCE_TEST
else {
}
#endif
clocks = 0;
}
sofCount++;
}
break;
#ifdef OUTPUT
/* Audio HOST -> DEVICE */
case inuint_byref(c_aud_out, tmp):
asm("#h->d aud data");
GET_SHARED_GLOBAL(aud_from_host_buffer, g_aud_from_host_buffer);
// XUD_GetData
{
xc_ptr p = aud_from_host_buffer+4;
xc_ptr p0 = p;
int tail;
while (!testct(c_aud_out))
{
unsigned int datum = inuint(c_aud_out);
write_via_xc_ptr(p, datum);
p += 4;
}
tail = inct(c_aud_out);
datalength = p - p0 - 4;
switch (tail)
{
case 10:
// the tail is 0 which means
datalength -= 2;
break;
default:
// the tail is 2 which means the input was word aligned
break;
}
}
XUD_SetNotReady(ep_aud_out);
write_via_xc_ptr(aud_from_host_buffer, datalength);
/* Sync with audio thread */
SET_SHARED_GLOBAL(g_aud_from_host_flag, 1);
break;
#endif
#ifdef INPUT
/* DEVICE -> HOST */
case inuint_byref(c_aud_in, tmp):
{
XUD_SetData_Inline(ep_aud_in, c_aud_in);
XUD_SetNotReady(ep_aud_in);
/* Inform stream that buffer sent */
SET_SHARED_GLOBAL(g_aud_to_host_flag, bufferIn+1);
}
break;
#endif
#ifdef OUTPUT
/* Feedback Pipe */
case inuint_byref(c_aud_fb, tmp):
{
int usb_speed;
int x;
asm("#aud fb");
XUD_SetData_Inline(ep_aud_fb, c_aud_fb);
asm("ldaw %0, dp[fb_clocks]":"=r"(x));
asm("ldw %0, dp[g_curUsbSpeed]" : "=r" (usb_speed) :);
if (usb_speed == XUD_SPEED_HS)
{
XUD_SetReady_In(ep_aud_fb, PIDn_DATA0, x, 4);
}
else
{
XUD_SetReady_In(ep_aud_fb, PIDn_DATA0, x, 3);
}
}
break;
#endif
#ifdef MIDI
case inuint_byref(c_midi_from_host, tmp):
asm("#midi h->d");
/* Get buffer data from host - MIDI OUT from host always into a single buffer */
{
xc_ptr p = midi_from_host_buffer + 4;
xc_ptr p0 = p;
xc_ptr p1 = p + MAX_USB_MIDI_PACKET_SIZE;
while (!testct(c_midi_from_host))
{
unsigned int datum = inuint(c_midi_from_host);
write_via_xc_ptr(p, datum);
p += 4;
}
(void) inct(c_midi_from_host);
datalength = p - p0 - 4;
}
XUD_SetNotReady(ep_midi_from_host);
write_via_xc_ptr(midi_from_host_buffer, datalength);
/* release the buffer */
SET_SHARED_GLOBAL(g_midi_from_host_flag, 1);
break;
/* MIDI IN to host */
case inuint_byref(c_midi_to_host, tmp):
asm("#midi d->h");
// fill in the data
XUD_SetData_Inline(ep_midi_to_host, c_midi_to_host);
XUD_SetNotReady(ep_midi_to_host);
// ack the decouple thread to say it has been sent to host
SET_SHARED_GLOBAL(g_midi_to_host_flag, 1);
swap(midi_to_host_buffer, midi_to_host_waiting_buffer);
break;
#endif
}
}
set_thread_fast_mode_off();
}

View File

@@ -0,0 +1,23 @@
#ifndef __xc_ptr__
#define __xc_ptr__
typedef unsigned int xc_ptr;
inline xc_ptr array_to_xc_ptr(unsigned a[]) {
xc_ptr x;
asm("mov %0, %1":"=r"(x):"r"(a));
return x;
}
#define write_via_xc_ptr(p,x) asm("stw %0, %1[0]"::"r"(x),"r"(p))
#define write_via_xc_ptr_indexed(p,i,x) asm("stw %0, %1[%2]"::"r"(x),"r"(p),"r"(i))
#define read_via_xc_ptr(x,p) asm("ldw %0, %1[0]":"=r"(x):"r"(p));
#define read_via_xc_ptr_indexed(x,p,i) asm("ldw %0, %1[%2]":"=r"(x):"r"(p),"r"(i));
#define GET_SHARED_GLOBAL(x, g) asm("ldw %0, dp[" #g "]":"=r"(x))
#define SET_SHARED_GLOBAL(g, v) asm("stw %0, dp[" #g "]"::"r"(v))
#endif

View File

@@ -0,0 +1,59 @@
#include "xs1_kernel.h"
#include "xs1_user.h"
.global write_sswitch_reg_blind, "f{si}(ui,ui,ui)"
.global write_sswitch_reg_blind.nstackwords
.linkset write_sswitch_reg_blind.nstackwords, 0
//.type read_sswitch_reg, @function
// r0 - coreid
// r1 - reg
// r2 - data
.cc_top write_sswitch_reg_blind.function, write_sswitch_reg_blind
.align 2
write_sswitch_reg_blind:
// Check range of coreid
shr r3, r0, XS1_CHAN_ID_PROCESSOR_SIZE + XS1_CHAN_ID_NODE_SIZE
bt r3, write_switch_reg_fail
// Check range of reg
shr r3, r1, 16
bt r3, write_switch_reg_fail
// Allocate channel end
getr r3, XS1_RES_TYPE_CHANEND
// Set destination
ldc r11, XS1_RES_TYPE_CONFIG | (XS1_CT_SSCTRL << XS1_CHAN_ID_CHANNUM_SHIFT)
// r0 - l
// r1 - reg
// r2 - data
// r3 - chanend
// r11 - low half of dest
write_switch_reg:
shl r0, r0, XS1_CHAN_ID_PROCESSOR_SHIFT
or r0, r0, r11
setd res[r3], r0
// Send packet
ldc r11, XS1_CT_WRITEC // Too big for outct immediate
outct res[r3], r11
mkmsk r0, 32
shl r0, r0, 8
shr r11, r1, 8
or r0, r0, r11
out res[r3], r0 // (0xffffff00) | (reg >> 8)
outt res[r3], r1 // reg & 0xff
out res[r3], r2
outct res[r3], XS1_CT_END
// Receive response
freer res[r3]
retsp 0
write_switch_reg_fail:
ldc r0, 0
retsp 0
.cc_bottom write_sswitch_reg_blind.function

View File

@@ -0,0 +1,23 @@
#include "devicedefines.h"
#ifdef HOST_ACTIVE_CALL
void VendorHostActive(int valid);
void XUD_UserSuspend(void)
{
VendorHostActive(0);
}
void XUD_UserResume(void)
{
unsigned config;
asm("ldw %0, dp[g_config]" : "=r" (config):);
if(config == 1)
{
VendorHostActive(1);
}
}
#endif