#include "usf/usf.h"
#include "usf/usf_internal.h"
#include "mi_controller.h"
#include "r4300.h"
#include "r4300_core.h"
#include "cp0.h"
#include "interupt.h"
#include <string.h>
static int update_mi_init_mode(uint32_t* mi_init_mode, uint32_t w)
{
int clear_dp = 0;
*mi_init_mode &= ~0x7f;
*mi_init_mode |= w & 0x7f;
if (w & 0x80) *mi_init_mode &= ~0x80;
if (w & 0x100) *mi_init_mode |= 0x80;
if (w & 0x200) *mi_init_mode &= ~0x100;
if (w & 0x400) *mi_init_mode |= 0x100;
if (w & 0x800) clear_dp = 1;
if (w & 0x1000) *mi_init_mode &= ~0x200;
if (w & 0x2000) *mi_init_mode |= 0x200;
return clear_dp;
}
static void update_mi_intr_mask(uint32_t* mi_intr_mask, uint32_t w)
{
if (w & 0x1) *mi_intr_mask &= ~0x1; if (w & 0x2) *mi_intr_mask |= 0x1; if (w & 0x4) *mi_intr_mask &= ~0x2; if (w & 0x8) *mi_intr_mask |= 0x2; if (w & 0x10) *mi_intr_mask &= ~0x4; if (w & 0x20) *mi_intr_mask |= 0x4; if (w & 0x40) *mi_intr_mask &= ~0x8; if (w & 0x80) *mi_intr_mask |= 0x8; if (w & 0x100) *mi_intr_mask &= ~0x10; if (w & 0x200) *mi_intr_mask |= 0x10; if (w & 0x400) *mi_intr_mask &= ~0x20; if (w & 0x800) *mi_intr_mask |= 0x20; }
void init_mi(struct mi_controller* mi)
{
memset(mi->regs, 0, MI_REGS_COUNT*sizeof(uint32_t));
mi->regs[MI_VERSION_REG] = 0x02020102;
mi->AudioIntrReg = 0;
}
int read_mi_regs(void* opaque, uint32_t address, uint32_t* value)
{
struct r4300_core* r4300 = (struct r4300_core*)opaque;
uint32_t reg = mi_reg(address);
*value = r4300->mi.regs[reg];
return 0;
}
int write_mi_regs(void* opaque, uint32_t address, uint32_t value, uint32_t mask)
{
struct r4300_core* r4300 = (struct r4300_core*)opaque;
uint32_t reg = mi_reg(address);
switch(reg)
{
case MI_INIT_MODE_REG:
if (update_mi_init_mode(&r4300->mi.regs[MI_INIT_MODE_REG], value & mask) != 0)
{
clear_rcp_interrupt(r4300, MI_INTR_DP);
}
break;
case MI_INTR_MASK_REG:
update_mi_intr_mask(&r4300->mi.regs[MI_INTR_MASK_REG], value & mask);
check_interupt(r4300->state);
update_count(r4300->state);
if (r4300->state->next_interupt <= r4300->state->g_cp0_regs[CP0_COUNT_REG]) gen_interupt(r4300->state);
break;
}
return 0;
}
void raise_rcp_interrupt(struct r4300_core* r4300, uint32_t mi_intr)
{
r4300->mi.regs[MI_INTR_REG] |= mi_intr;
if (r4300->mi.regs[MI_INTR_REG] & r4300->mi.regs[MI_INTR_MASK_REG])
raise_maskable_interrupt(r4300->state, 0x400);
}
void signal_rcp_interrupt(struct r4300_core* r4300, uint32_t mi_intr)
{
r4300->mi.regs[MI_INTR_REG] |= mi_intr;
check_interupt(r4300->state);
}
void clear_rcp_interrupt(struct r4300_core* r4300, uint32_t mi_intr)
{
r4300->mi.regs[MI_INTR_REG] &= ~mi_intr;
check_interupt(r4300->state);
}