void write_ai_regs(void* opaque, uint32_t address, uint32_t value, uint32_t mask)
{
    struct ai_controller* ai = (struct ai_controller*)opaque;
    uint32_t reg = ai_reg(address);

    switch (reg)
    {
    case AI_LEN_REG:
        masked_write(&ai->regs[AI_LEN_REG], value, mask);
        if (ai->regs[AI_LEN_REG] != 0) {
            fifo_push(ai);
        }
        else {
            /* stop sound */
        }
        return;

    case AI_STATUS_REG:
        clear_rcp_interrupt(ai->mi, MI_INTR_AI);
        return;

    case AI_BITRATE_REG:
    case AI_DACRATE_REG:
        /* lazy audio format setting */
        if ((ai->regs[reg]) != (value & mask))
            ai->samples_format_changed = 1;

        masked_write(&ai->regs[reg], value, mask);
        return;
    }

    masked_write(&ai->regs[reg], value, mask);
}
int write_ai_regs(void* opaque, uint32_t address, uint32_t value, uint32_t mask)
{
    struct ai_controller* ai = (struct ai_controller*)opaque;
    uint32_t reg = ai_reg(address);

    unsigned int freq,delay=0;
    switch (reg)
    {
    case AI_LEN_REG:
        masked_write(&ai->regs[AI_LEN_REG], value, mask);
        audio.aiLenChanged();

        freq = ROM_PARAMS.aidacrate / (ai->regs[AI_DACRATE_REG]+1);
        if (freq)
            delay = (unsigned int) (((unsigned long long)ai->regs[AI_LEN_REG]*ai->vi->delay*ROM_PARAMS.vilimit)/(freq*4));

        if (ai->regs[AI_STATUS_REG] & 0x40000000) // busy
        {
            ai->fifo[1].delay = delay;
            ai->fifo[1].length = ai->regs[AI_LEN_REG];
            ai->regs[AI_STATUS_REG] |= 0x80000000;
        }
        else
        {
            ai->fifo[0].delay = delay;
            ai->fifo[0].length = ai->regs[AI_LEN_REG];
            update_count();
            add_interupt_event(AI_INT, delay);
            ai->regs[AI_STATUS_REG] |= 0x40000000;
        }
        return 0;

    case AI_STATUS_REG:
        clear_rcp_interrupt(ai->r4300, MI_INTR_AI);
        return 0;

    case AI_DACRATE_REG:
        if ((ai->regs[AI_DACRATE_REG] & mask) != (value & mask))
        {
            masked_write(&ai->regs[AI_DACRATE_REG], value, mask);
            audio.aiDacrateChanged(ROM_PARAMS.systemtype);
        }
        return 0;
    }

    masked_write(&ai->regs[reg], value, mask);

    return 0;
}
void read_ai_regs(void* opaque, uint32_t address, uint32_t* value)
{
    struct ai_controller* ai = (struct ai_controller*)opaque;
    uint32_t reg = ai_reg(address);

    if (reg == AI_LEN_REG)
    {
        *value = get_remaining_dma_length(ai);
        if (*value < ai->last_read)
        {
            unsigned int diff = ai->fifo[0].length - ai->last_read;
            unsigned char *p = (unsigned char*)&ai->ri->rdram->dram[ai->fifo[0].address/4];
            ai->iaout->push_samples(ai->aout, p + diff, ai->last_read - *value);
            ai->last_read = *value;
        }
    }
    else
    {
        *value = ai->regs[reg];
    }
}
int read_ai_regs(void* opaque, uint32_t address, uint32_t* value)
{
    struct ai_controller* ai = (struct ai_controller*)opaque;
    uint32_t reg = ai_reg(address);

    if (reg == AI_LEN_REG)
    {
        update_count();
        if (ai->fifo[0].delay != 0 && get_event(AI_INT) != 0 && (get_event(AI_INT)-g_cp0_regs[CP0_COUNT_REG]) < 0x80000000)
            *value = ((get_event(AI_INT)-g_cp0_regs[CP0_COUNT_REG])*(long long)ai->fifo[0].length)/
                      ai->fifo[0].delay;
        else
            *value = 0;
    }
    else
    {
        *value = ai->regs[reg];
    }

    return 0;
}