#include <sys/param.h>
#include <sys/systm.h>
#include <machine/asm_macro.h>
#include <m88k/m88100.h>
#ifdef MULTIPROCESSOR
uint32_t m88100_mp_atomic_begin(__cpu_simple_lock_t *, uint *);
void m88100_mp_atomic_end(uint32_t, __cpu_simple_lock_t *, uint);
#endif
#define DMT_BYTE 1
#define DMT_HALF 2
#define DMT_WORD 4
const struct {
unsigned char offset;
unsigned char size;
} dmt_en_info[16] = {
{0, 0},
{3, DMT_BYTE},
{2, DMT_BYTE},
{2, DMT_HALF},
{1, DMT_BYTE},
{0, 0},
{0, 0},
{0, 0},
{0, DMT_BYTE},
{0, 0},
{0, 0},
{0, 0},
{0, DMT_HALF},
{0, 0},
{0, 0},
{0, DMT_WORD}
};
#ifdef DATA_DEBUG
int data_access_emulation_debug = 0;
#define DAE_DEBUG(stuff) \
do { \
if (data_access_emulation_debug != 0) { \
stuff; \
} \
} while (0)
#else
#define DAE_DEBUG(stuff)
#endif
void dae_print_one(u_int, u_int, u_int, u_int);
void dae_process(struct trapframe *, u_int, u_int, u_int, u_int);
void
dae_print(u_int *f)
{
struct trapframe *eframe = (void *)f;
if (!ISSET(eframe->tf_dmt0, DMT_VALID))
return;
dae_print_one(0, eframe->tf_dma0, eframe->tf_dmd0, eframe->tf_dmt0);
dae_print_one(1, eframe->tf_dma1, eframe->tf_dmd1, eframe->tf_dmt1);
dae_print_one(2, eframe->tf_dma2, eframe->tf_dmd2, eframe->tf_dmt2);
}
void
dae_print_one(u_int x, u_int dmax, u_int dmdx, u_int dmtx)
{
u_int enbits;
const char *width, *usr, *xmem;
if (!ISSET(dmtx, DMT_VALID))
return;
enbits = DMT_ENBITS(dmtx);
dmax += dmt_en_info[enbits].offset;
if (dmtx & DMT_DOUB1)
width = ".d";
else {
switch (dmt_en_info[enbits].size) {
case DMT_BYTE:
if (dmtx & DMT_SIGNED)
width = ".b";
else
width = ".bu";
break;
case DMT_HALF:
if (dmtx & DMT_SIGNED)
width = ".h";
else
width = ".hu";
break;
case DMT_WORD:
width = "";
break;
default:
width = ".???";
break;
}
}
if (dmtx & DMT_DAS)
usr = "";
else
usr = ".usr";
if (dmtx & DMT_LOCKBAR)
xmem = "(xmem)";
else
xmem = "";
if (ISSET(dmtx, DMT_WRITE))
printf("[DMT%d=%x: %sst%s%s %08x to %08x]\n",
x, dmtx, xmem, width, usr, dmdx, dmax);
else
printf("[DMT%d=%x: %sld%s%s r%d <- %x]\n",
x, dmtx, xmem, width, usr, DMT_DREGBITS(dmtx), dmax);
}
void
data_access_emulation(u_int *f)
{
struct trapframe *eframe = (void *)f;
if (!ISSET(eframe->tf_dmt0, DMT_VALID))
return;
dae_process(eframe, 0,
eframe->tf_dma0, eframe->tf_dmd0, eframe->tf_dmt0);
dae_process(eframe, 1,
eframe->tf_dma1, eframe->tf_dmd1, eframe->tf_dmt1);
dae_process(eframe, 2,
eframe->tf_dma2, eframe->tf_dmd2, eframe->tf_dmt2);
eframe->tf_dmt0 = 0;
}
void
dae_process(struct trapframe *eframe, u_int x,
u_int dmax, u_int dmdx, u_int dmtx)
{
u_int v, reg, enbits;
if (!ISSET(dmtx, DMT_VALID))
return;
DAE_DEBUG(dae_print_one(x, dmax, dmdx, dmtx));
enbits = DMT_ENBITS(dmtx);
dmax += dmt_en_info[enbits].offset;
reg = DMT_DREGBITS(dmtx);
if (!ISSET(dmtx, DMT_LOCKBAR)) {
if (x == 2 && ISSET(dmtx, DMT_DOUB1)) {
if (ISSET(dmtx, DMT_WRITE)) {
} else {
v = do_load_word(dmax, dmtx & DMT_DAS);
if (reg != 0)
eframe->tf_r[reg] = v;
v = do_load_word(dmax ^ 4, dmtx & DMT_DAS);
if (reg != 31)
eframe->tf_r[reg + 1] = v;
}
} else {
if (dmtx & DMT_WRITE) {
switch (dmt_en_info[enbits].size) {
case DMT_BYTE:
DAE_DEBUG(
printf("[byte %x -> %08x(%c)]\n",
dmdx & 0xff, dmax,
ISSET(dmtx, DMT_DAS) ? 's' : 'u')
);
do_store_byte(dmax, dmdx,
dmtx & DMT_DAS);
break;
case DMT_HALF:
DAE_DEBUG(
printf("[half %x -> %08x(%c)]\n",
dmdx & 0xffff, dmax,
ISSET(dmtx, DMT_DAS) ? 's' : 'u')
);
do_store_half(dmax, dmdx,
dmtx & DMT_DAS);
break;
case DMT_WORD:
DAE_DEBUG(
printf("[word %x -> %08x(%c)]\n",
dmdx, dmax,
ISSET(dmtx, DMT_DAS) ? 's' : 'u')
);
do_store_word(dmax, dmdx,
dmtx & DMT_DAS);
break;
}
} else {
switch (dmt_en_info[enbits].size) {
case DMT_BYTE:
v = do_load_byte(dmax, dmtx & DMT_DAS);
if (!ISSET(dmtx, DMT_SIGNED))
v &= 0x000000ff;
break;
case DMT_HALF:
v = do_load_half(dmax, dmtx & DMT_DAS);
if (!ISSET(dmtx, DMT_SIGNED))
v &= 0x0000ffff;
break;
case DMT_WORD:
v = do_load_word(dmax, dmtx & DMT_DAS);
break;
}
DAE_DEBUG(
if (reg == 0)
printf("[no write to r0 done]\n");
else
printf("[r%d <- %08x]\n", reg, v);
);
if (reg != 0)
eframe->tf_r[reg] = v;
}
}
} else {
if (!ISSET(dmtx, DMT_WRITE)) {
if (x < 2) {
dmdx =
x == 0 ? eframe->tf_dmd1 : eframe->tf_dmd2;
} else {
}
if (dmt_en_info[enbits].size == DMT_WORD) {
v = do_xmem_word(dmax, dmdx, dmtx & DMT_DAS);
} else {
v = do_xmem_byte(dmax, dmdx, dmtx & DMT_DAS);
}
DAE_DEBUG(
if (reg == 0)
printf("[no write to r0 done]\n");
else
printf("[r%d <- %08x]\n", reg, v);
);
if (reg != 0)
eframe->tf_r[reg] = v;
} else {
if (x == 0) {
if (reg != 0)
eframe->tf_r[reg] = dmdx;
m88100_rewind_insn(&(eframe->tf_regs));
eframe->tf_dmt0 = 0;
return;
}
}
}
}
void
m88100_apply_patches()
{
#ifdef ERRATA__XXX_USR
if (((get_cpu_pid() & PID_VN) >> VN_SHIFT) > 10) {
((u_int32_t *)(do_load_word))[1] = 0xf400c401;
((u_int32_t *)(do_load_half))[1] = 0xf400c401;
((u_int32_t *)(do_load_byte))[1] = 0xf400c401;
((u_int32_t *)(do_store_word))[1] = 0xf400c401;
((u_int32_t *)(do_store_half))[1] = 0xf400c401;
((u_int32_t *)(do_store_byte))[1] = 0xf400c401;
}
#endif
}
#ifdef MULTIPROCESSOR
void
m88100_smp_setup(struct cpu_info *ci)
{
ci->ci_mp_atomic_begin = m88100_mp_atomic_begin;
ci->ci_mp_atomic_end = m88100_mp_atomic_end;
}
uint32_t
m88100_mp_atomic_begin(__cpu_simple_lock_t *lock, uint *csr)
{
uint32_t psr;
psr = get_psr();
set_psr(psr | PSR_IND);
__cpu_simple_lock(lock);
return psr;
}
void
m88100_mp_atomic_end(uint32_t psr, __cpu_simple_lock_t *lock, uint csr)
{
__cpu_simple_unlock(lock);
set_psr(psr);
}
#endif