#include "embiosapp.h"


void main();
EMBIOS_APP_HEADER("Audiotest", 0x4000, main, 127)


struct dma_lli
{
    void* srcaddr;
    void* dstaddr;
    const struct dma_lli* nextlli;
    uint32_t control;
};
#define DMACINTSTS(d)       (*((uint32_t volatile*)(0x38200000 + 0x1700000 * (d))))
#define DMACINTTCSTS(d)     (*((uint32_t volatile*)(0x38200004 + 0x1700000 * (d))))
#define DMACINTTCCLR(d)     (*((uint32_t volatile*)(0x38200008 + 0x1700000 * (d))))
#define DMACINTERRSTS(d)    (*((uint32_t volatile*)(0x3820000c + 0x1700000 * (d))))
#define DMACINTERRCLR(d)    (*((uint32_t volatile*)(0x38200010 + 0x1700000 * (d))))
#define DMACRAWINTTCSTS(d)  (*((uint32_t volatile*)(0x38200014 + 0x1700000 * (d))))
#define DMACRAWINTERRSTS(d) (*((uint32_t volatile*)(0x38200018 + 0x1700000 * (d))))
#define DMACENABLEDCHANS(d) (*((uint32_t volatile*)(0x3820001c + 0x1700000 * (d))))
#define DMACSOFTBREQ(d)     (*((uint32_t volatile*)(0x38200020 + 0x1700000 * (d))))
#define DMACSOFTSREQ(d)     (*((uint32_t volatile*)(0x38200024 + 0x1700000 * (d))))
#define DMACSOFTLBREQ(d)    (*((uint32_t volatile*)(0x38200028 + 0x1700000 * (d))))
#define DMACSOFTLSREQ(d)    (*((uint32_t volatile*)(0x3820002c + 0x1700000 * (d))))
#define DMACCONFIG(d)       (*((uint32_t volatile*)(0x38200030 + 0x1700000 * (d))))
#define DMACSYNC(d)         (*((uint32_t volatile*)(0x38200034 + 0x1700000 * (d))))
#define DMACCLLI(d, c)      (*((struct dma_lli volatile*)(0x38200100 + 0x1700000 * (d) + 0x20 * (c))))
#define DMACCSRCADDR(d, c)  (*((const void* volatile*)(0x38200100 + 0x1700000 * (d) + 0x20 * (c))))
#define DMACCDESTADDR(d, c) (*((void* volatile*)(0x38200104 + 0x1700000 * (d) + 0x20 * (c))))
#define DMACCNEXTLLI(d, c)  (*((const void* volatile*)(0x38200108 + 0x1700000 * (d) + 0x20 * (c))))
#define DMACCCONTROL(d, c)  (*((uint32_t volatile*)(0x3820010c + 0x1700000 * (d) + 0x20 * (c))))
#define DMACCCONFIG(d, c)   (*((uint32_t volatile*)(0x38200110 + 0x1700000 * (d) + 0x20 * (c))))
#define DMAC0INTSTS         (*((uint32_t volatile*)(0x38200000)))
#define DMAC0INTTCSTS       (*((uint32_t volatile*)(0x38200004)))
#define DMAC0INTTCCLR       (*((uint32_t volatile*)(0x38200008)))
#define DMAC0INTERRSTS      (*((uint32_t volatile*)(0x3820000c)))
#define DMAC0INTERRCLR      (*((uint32_t volatile*)(0x38200010)))
#define DMAC0RAWINTTCSTS    (*((uint32_t volatile*)(0x38200014)))
#define DMAC0RAWINTERRSTS   (*((uint32_t volatile*)(0x38200018)))
#define DMAC0ENABLEDCHANS   (*((uint32_t volatile*)(0x3820001c)))
#define DMAC0SOFTBREQ       (*((uint32_t volatile*)(0x38200020)))
#define DMAC0SOFTSREQ       (*((uint32_t volatile*)(0x38200024)))
#define DMAC0SOFTLBREQ      (*((uint32_t volatile*)(0x38200028)))
#define DMAC0SOFTLSREQ      (*((uint32_t volatile*)(0x3820002c)))
#define DMAC0CONFIG         (*((uint32_t volatile*)(0x38200030)))
#define DMAC0SYNC           (*((uint32_t volatile*)(0x38200034)))
#define DMAC0CLLI(c)        (*((struct dma_lli volatile*)(0x38200100 + 0x20 * (c))))
#define DMAC0CSRCADDR(c)    (*((const void* volatile*)(0x38200100 + 0x20 * (c))))
#define DMAC0CDESTADDR(c)   (*((void* volatile*)(0x38200104 + 0x20 * (c))))
#define DMAC0CNEXTLLI(c)    (*((const void* volatile*)(0x38200108 + 0x20 * (c))))
#define DMAC0CCONTROL(c)    (*((uint32_t volatile*)(0x3820010c + 0x20 * (c))))
#define DMAC0CCONFIG(c)     (*((uint32_t volatile*)(0x38200110 + 0x20 * (c))))
#define DMAC0C0LLI          (*((struct dma_lli volatile*)(0x38200100)))
#define DMAC0C0SRCADDR      (*((const void* volatile*)(0x38200100)))
#define DMAC0C0DESTADDR     (*((void* volatile*)(0x38200104)))
#define DMAC0C0NEXTLLI      (*((const struct dma_lli* volatile*)(0x38200108)))
#define DMAC0C0CONTROL      (*((uint32_t volatile*)(0x3820010c)))
#define DMAC0C0CONFIG       (*((uint32_t volatile*)(0x38200110)))
#define DMAC0C1LLI          (*((struct dma_lli volatile*)(0x38200120)))
#define DMAC0C1SRCADDR      (*((const void* volatile*)(0x38200120)))
#define DMAC0C1DESTADDR     (*((void* volatile*)(0x38200124)))
#define DMAC0C1NEXTLLI      (*((const struct dma_lli* volatile*)(0x38200128)))
#define DMAC0C1CONTROL      (*((uint32_t volatile*)(0x3820012c)))
#define DMAC0C1CONFIG       (*((uint32_t volatile*)(0x38200130)))
#define DMAC0C2LLI          (*((struct dma_lli volatile*)(0x38200140)))
#define DMAC0C2SRCADDR      (*((const void* volatile*)(0x38200140)))
#define DMAC0C2DESTADDR     (*((void* volatile*)(0x38200144)))
#define DMAC0C2NEXTLLI      (*((const struct dma_lli* volatile*)(0x38200148)))
#define DMAC0C2CONTROL      (*((uint32_t volatile*)(0x3820014c)))
#define DMAC0C2CONFIG       (*((uint32_t volatile*)(0x38200150)))
#define DMAC0C3LLI          (*((struct dma_lli volatile*)(0x38200160)))
#define DMAC0C3SRCADDR      (*((const void* volatile*)(0x38200160)))
#define DMAC0C3DESTADDR     (*((void* volatile*)(0x38200164)))
#define DMAC0C3NEXTLLI      (*((const struct dma_lli* volatile*)(0x38200168)))
#define DMAC0C3CONTROL      (*((uint32_t volatile*)(0x3820016c)))
#define DMAC0C3CONFIG       (*((uint32_t volatile*)(0x38200170)))
#define DMAC0C4LLI          (*((struct dma_lli volatile*)(0x38200180)))
#define DMAC0C4SRCADDR      (*((const void* volatile*)(0x38200180)))
#define DMAC0C4DESTADDR     (*((void* volatile*)(0x38200184)))
#define DMAC0C4NEXTLLI      (*((const struct dma_lli* volatile*)(0x38200188)))
#define DMAC0C4CONTROL      (*((uint32_t volatile*)(0x3820018c)))
#define DMAC0C4CONFIG       (*((uint32_t volatile*)(0x38200190)))
#define DMAC0C5LLI          (*((struct dma_lli volatile*)(0x382001a0)))
#define DMAC0C5SRCADDR      (*((const void* volatile*)(0x382001a0)))
#define DMAC0C5DESTADDR     (*((void* volatile*)(0x382001a4)))
#define DMAC0C5NEXTLLI      (*((const struct dma_lli* volatile*)(0x382001a8)))
#define DMAC0C5CONTROL      (*((uint32_t volatile*)(0x382001ac)))
#define DMAC0C5CONFIG       (*((uint32_t volatile*)(0x382001b0)))
#define DMAC0C6LLI          (*((struct dma_lli volatile*)(0x382001c0)))
#define DMAC0C6SRCADDR      (*((const void* volatile*)(0x382001c0)))
#define DMAC0C6DESTADDR     (*((void* volatile*)(0x382001c4)))
#define DMAC0C6NEXTLLI      (*((const struct dma_lli* volatile*)(0x382001c8)))
#define DMAC0C6CONTROL      (*((uint32_t volatile*)(0x382001cc)))
#define DMAC0C6CONFIG       (*((uint32_t volatile*)(0x382001d0)))
#define DMAC0C7LLI          (*((struct dma_lli volatile*)(0x382001e0)))
#define DMAC0C7SRCADDR      (*((const void* volatile*)(0x382001e0)))
#define DMAC0C7DESTADDR     (*((void* volatile*)(0x382001e4)))
#define DMAC0C7NEXTLLI      (*((const struct dma_lli* volatile*)(0x382001e8)))
#define DMAC0C7CONTROL      (*((uint32_t volatile*)(0x382001ec)))
#define DMAC0C7CONFIG       (*((uint32_t volatile*)(0x382001f0)))
#define DMAC1INTSTS         (*((uint32_t volatile*)(0x39900000)))
#define DMAC1INTTCSTS       (*((uint32_t volatile*)(0x39900004)))
#define DMAC1INTTCCLR       (*((uint32_t volatile*)(0x39900008)))
#define DMAC1INTERRSTS      (*((uint32_t volatile*)(0x3990000c)))
#define DMAC1INTERRCLR      (*((uint32_t volatile*)(0x39900010)))
#define DMAC1RAWINTTCSTS    (*((uint32_t volatile*)(0x39900014)))
#define DMAC1RAWINTERRSTS   (*((uint32_t volatile*)(0x39900018)))
#define DMAC1ENABLEDCHANS   (*((uint32_t volatile*)(0x3990001c)))
#define DMAC1SOFTBREQ       (*((uint32_t volatile*)(0x39900020)))
#define DMAC1SOFTSREQ       (*((uint32_t volatile*)(0x39900024)))
#define DMAC1SOFTLBREQ      (*((uint32_t volatile*)(0x39900028)))
#define DMAC1SOFTLSREQ      (*((uint32_t volatile*)(0x3990002c)))
#define DMAC1CONFIG         (*((uint32_t volatile*)(0x39900030)))
#define DMAC1SYNC           (*((uint32_t volatile*)(0x39900034)))
#define DMAC1CLLI(c)        (*((struct dma_lli volatile*)(0x39900100 + 0x20 * (c))))
#define DMAC1CSRCADDR(c)    (*((const void* volatile*)(0x39900100 + 0x20 * (c))))
#define DMAC1CDESTADDR(c)   (*((void* volatile*)(0x39900104 + 0x20 * (c))))
#define DMAC1CNEXTLLI(c)    (*((const void* volatile*)(0x39900108 + 0x20 * (c))))
#define DMAC1CCONTROL(c)    (*((uint32_t volatile*)(0x3990010c + 0x20 * (c))))
#define DMAC1CCONFIG(c)     (*((uint32_t volatile*)(0x39900110 + 0x20 * (c))))
#define DMAC1C0LLI          (*((struct dma_lli volatile*)(0x39900100)))
#define DMAC1C0SRCADDR      (*((const void* volatile*)(0x39900100)))
#define DMAC1C0DESTADDR     (*((void* volatile*)(0x39900104)))
#define DMAC1C0NEXTLLI      (*((const struct dma_lli* volatile*)(0x39900108)))
#define DMAC1C0CONTROL      (*((uint32_t volatile*)(0x3990010c)))
#define DMAC1C0CONFIG       (*((uint32_t volatile*)(0x39900110)))
#define DMAC1C1LLI          (*((struct dma_lli volatile*)(0x39900120)))
#define DMAC1C1SRCADDR      (*((const void* volatile*)(0x39900120)))
#define DMAC1C1DESTADDR     (*((void* volatile*)(0x39900124)))
#define DMAC1C1NEXTLLI      (*((const struct dma_lli* volatile*)(0x39900128)))
#define DMAC1C1CONTROL      (*((uint32_t volatile*)(0x3990012c)))
#define DMAC1C1CONFIG       (*((uint32_t volatile*)(0x39900130)))
#define DMAC1C2LLI          (*((struct dma_lli volatile*)(0x39900140)))
#define DMAC1C2SRCADDR      (*((const void* volatile*)(0x39900140)))
#define DMAC1C2DESTADDR     (*((void* volatile*)(0x39900144)))
#define DMAC1C2NEXTLLI      (*((const struct dma_lli* volatile*)(0x39900148)))
#define DMAC1C2CONTROL      (*((uint32_t volatile*)(0x3990014c)))
#define DMAC1C2CONFIG       (*((uint32_t volatile*)(0x39900150)))
#define DMAC1C3LLI          (*((struct dma_lli volatile*)(0x39900160)))
#define DMAC1C3SRCADDR      (*((const void* volatile*)(0x39900160)))
#define DMAC1C3DESTADDR     (*((void* volatile*)(0x39900164)))
#define DMAC1C3NEXTLLI      (*((volatile void**)(0x39900168)))
#define DMAC1C3CONTROL      (*((uint32_t volatile*)(0x3990016c)))
#define DMAC1C3CONFIG       (*((uint32_t volatile*)(0x39900170)))
#define DMAC1C4LLI          (*((struct dma_lli volatile*)(0x39900180)))
#define DMAC1C4SRCADDR      (*((const void* volatile*)(0x39900180)))
#define DMAC1C4DESTADDR     (*((void* volatile*)(0x39900184)))
#define DMAC1C4NEXTLLI      (*((const struct dma_lli* volatile*)(0x39900188)))
#define DMAC1C4CONTROL      (*((uint32_t volatile*)(0x3990018c)))
#define DMAC1C4CONFIG       (*((uint32_t volatile*)(0x39900190)))
#define DMAC1C5LLI          (*((struct dma_lli volatile*)(0x399001a0)))
#define DMAC1C5SRCADDR      (*((const void* volatile*)(0x399001a0)))
#define DMAC1C5DESTADDR     (*((void* volatile*)(0x399001a4)))
#define DMAC1C5NEXTLLI      (*((const struct dma_lli* volatile*)(0x399001a8)))
#define DMAC1C5CONTROL      (*((uint32_t volatile*)(0x399001ac)))
#define DMAC1C5CONFIG       (*((uint32_t volatile*)(0x399001b0)))
#define DMAC1C6LLI          (*((struct dma_lli volatile*)(0x399001c0)))
#define DMAC1C6SRCADDR      (*((const void* volatile*)(0x399001c0)))
#define DMAC1C6DESTADDR     (*((void* volatile*)(0x399001c4)))
#define DMAC1C6NEXTLLI      (*((const struct dma_lli* volatile*)(0x399001c8)))
#define DMAC1C6CONTROL      (*((uint32_t volatile*)(0x399001cc)))
#define DMAC1C6CONFIG       (*((uint32_t volatile*)(0x399001d0)))
#define DMAC1C7LLI          (*((struct dma_lli volatile*)(0x399001e0)))
#define DMAC1C7SRCADDR      (*((const void* volatile*)(0x399001e0)))
#define DMAC1C7DESTADDR     (*((void* volatile*)(0x399001e4)))
#define DMAC1C7NEXTLLI      (*((const struct dma_lli* volatile*)(0x399001e8)))
#define DMAC1C7CONTROL      (*((uint32_t volatile*)(0x399001ec)))
#define DMAC1C7CONFIG       (*((uint32_t volatile*)(0x399001f0)))
#define I2SCLKCON           (*((volatile uint32_t*)(0x3CA00000)))
#define I2STXCON            (*((volatile uint32_t*)(0x3CA00004)))
#define I2STXCOM            (*((volatile uint32_t*)(0x3CA00008)))
#define I2STXDB0            (*((volatile uint32_t*)(0x3CA00010)))
#define I2SRXCON            (*((volatile uint32_t*)(0x3CA00030)))
#define I2SRXCOM            (*((volatile uint32_t*)(0x3CA00034)))
#define I2SRXDB             (*((volatile uint32_t*)(0x3CA00038)))
#define I2SSTATUS           (*((volatile uint32_t*)(0x3CA0003C)))
#define I2S40               (*((volatile uint32_t*)(0x3CA00040)))
#define CLKCON0C            (*((volatile uint32_t*)(0x3C50000C)))
#define PDAT(i)             (*((uint32_t volatile*)(0x3cf00004 + ((i) << 5))))


#define LLIMAX (2047)
#define CHUNKSIZE (4096)
#define WATERMARK (1024)
uint32_t dataptr;
uint32_t remaining;
uint32_t irqs;
bool running;
struct dma_lli lli[(CHUNKSIZE - WATERMARK + LLIMAX - 1) / LLIMAX + 1] __attribute__((aligned(16)));


void dmahandler()
{
    irqs++;
    DMAC0INTTCCLR = 1;
    if (!remaining)
    {
        int_dma_set_handler(0, NULL);
        running = false;
        return;
    }
    uint32_t lastsize = MIN(WATERMARK * 4, remaining);
    remaining -= lastsize;
    struct dma_lli* lastlli;
    if (remaining) lastlli = &lli[ARRAYLEN(lli) - 1];
    else lastlli = lli;
    uint32_t chunksize = MIN(CHUNKSIZE * 4 - lastsize, remaining);
    remaining -= chunksize;
    int i = 0;
    while (chunksize)
    {
        uint32_t thislli = MIN(LLIMAX * 4, chunksize);
        chunksize -= thislli;
        lli[i].srcaddr = (void*)dataptr;
        lli[i].dstaddr = (void*)((int)&I2STXDB0);
        lli[i].nextlli = chunksize ? &lli[i + 1] : lastlli;
        lli[i].control = ((chunksize || !remaining) ? 0x75249000 : 0xf5249000) | (thislli / 2);
        dataptr += thislli;
        i++;
    }
    lastlli->srcaddr = (void*)dataptr;
    lastlli->dstaddr = (void*)((int)&I2STXDB0);
    lastlli->nextlli = remaining ? lli : NULL;
    lastlli->control = (remaining ? 0x75249000 : 0xf5249000) | (lastsize / 2);
    dataptr += lastsize;
    clean_dcache();
}

void main()
{
    cputs(3, "Preparing...\n");
    dataptr = 0x08100000;
    remaining = 40135680;
    running = true;
    irqs = 0;
    CLKCON0C &= ~0xffff;
    clockgate_enable(4, true);
    clockgate_enable(39, true);
    I2S40 = 0x110;
    PDAT(3) &= ~8;
    sleep(10000);
    PDAT(3) |= 8;
    i2c_sendbyte(0, 0x94, 0x00, 0x99);
    i2c_sendbyte(0, 0x94, 0x2e, 0x30);
    i2c_sendbyte(0, 0x94, 0x32, 0x07);
    i2c_sendbyte(0, 0x94, 0x33, 0xff);
    i2c_sendbyte(0, 0x94, 0x34, 0xf8);
    i2c_sendbyte(0, 0x94, 0x35, 0xdc);
    i2c_sendbyte(0, 0x94, 0x36, 0xfc);
    i2c_sendbyte(0, 0x94, 0x37, 0xac);
    i2c_sendbyte(0, 0x94, 0x3a, 0xf8);
    i2c_sendbyte(0, 0x94, 0x3c, 0xd3);
    i2c_sendbyte(0, 0x94, 0x3d, 0x23);
    i2c_sendbyte(0, 0x94, 0x3e, 0x81);
    i2c_sendbyte(0, 0x94, 0x3f, 0x46);
    i2c_sendbyte(0, 0x94, 0x00, 0x00);
    i2c_sendbyte(0, 0x94, 0x03, 0xaa);
    i2c_sendbyte(0, 0x94, 0x04, 0x2e);
    i2c_sendbyte(0, 0x94, 0x05, 0x0b);
    i2c_sendbyte(0, 0x94, 0x07, 0x18);
    i2c_sendbyte(0, 0x94, 0x02, 0x01);
    i2c_sendbyte(0, 0x94, 0x0f, 0x80);
    i2c_sendbyte(0, 0x94, 0x0b, 0x00);
    i2c_sendbyte(0, 0x94, 0x0c, 0x00);
    i2c_sendbyte(0, 0x94, 0x1a, 0x80);
    i2c_sendbyte(0, 0x94, 0x1b, 0x80);
    i2c_sendbyte(0, 0x94, 0x1c, 0x80);
    i2c_sendbyte(0, 0x94, 0x1d, 0x80);
    i2c_sendbyte(0, 0x94, 0x02, 0x00);
    sleep(75000);
    i2c_sendbyte(0, 0x94, 0x1a, 0x00);
    i2c_sendbyte(0, 0x94, 0x1b, 0x00);
    i2c_sendbyte(0, 0x94, 0x1c, 0x00);
    i2c_sendbyte(0, 0x94, 0x1d, 0x00);
    i2c_sendbyte(0, 0x94, 0x06, 0x00);
    I2STXCON = 0xb100059;
    I2SCLKCON = 1;
    I2STXCOM = 0xe;
    int_dma_set_handler(0, dmahandler);
    dmahandler();
    DMAC0CONFIG |= 4;
    DMAC0C0LLI.srcaddr = lli[0].srcaddr;
    DMAC0C0LLI.dstaddr = lli[0].dstaddr;
    DMAC0C0LLI.nextlli = lli[0].nextlli;
    DMAC0C0LLI.control = lli[0].control;
    DMAC0C0CONFIG = 0x8a81;
    cputs(3, "Playing...\n");
}