178 lines
4.9 KiB
C
178 lines
4.9 KiB
C
|
/* This file is included into vb.c and cannot be compiled on its own. */
|
||
|
#ifdef VBAPI
|
||
|
|
||
|
|
||
|
|
||
|
/********************************* Constants *********************************/
|
||
|
|
||
|
/* Pseudo-halt operations */
|
||
|
#define PH_NEVER 0 /* Must be zero */
|
||
|
#define PH_XPSTTS 1
|
||
|
|
||
|
|
||
|
|
||
|
/***************************** Module Functions ******************************/
|
||
|
|
||
|
/* Activate pseudo-halt */
|
||
|
static void phActivate(VB *sim, uint32_t address, int type) {
|
||
|
int range; /* Memory address range by component */
|
||
|
|
||
|
(void) type;
|
||
|
|
||
|
/* Working variables */
|
||
|
address = 0x07FFFFFF;
|
||
|
range = address >> 24;
|
||
|
|
||
|
/* Configure CPU */
|
||
|
sim->cpu.operation = CPU_PHALT;
|
||
|
sim->ph.operation = PH_NEVER;
|
||
|
|
||
|
/* VIP */
|
||
|
if (range == 0) {
|
||
|
address &= 0x0007FFFF;
|
||
|
|
||
|
/* I/O register */
|
||
|
switch (address) {
|
||
|
case 0x5F840: /* XPSTTS */
|
||
|
if (sim->vip.dp.disp && sim->vip.xp.xpen)
|
||
|
sim->ph.operation = PH_XPSTTS;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
/* Configure CPU */
|
||
|
sim->cpu.clocks = phUntil(sim);
|
||
|
}
|
||
|
|
||
|
/* Test whether the current memory access matches the monitored access */
|
||
|
static int phMatches(VB *sim, uint32_t address, int type, int32_t value) {
|
||
|
int match; /* Parameter match */
|
||
|
int x; /* Iterator */
|
||
|
|
||
|
/* New memory access */
|
||
|
if (sim->ph.step == 0)
|
||
|
return 0;
|
||
|
|
||
|
/* Check memory access parameters */
|
||
|
match =
|
||
|
address == sim->ph.address &&
|
||
|
sim->cpu.pc == sim->ph.pc &&
|
||
|
type == sim->ph.type &&
|
||
|
value == sim->ph.value
|
||
|
;
|
||
|
if (!match || sim->ph.step != 3)
|
||
|
return match;
|
||
|
|
||
|
/* Check full CPU state */
|
||
|
for (x = 1; x < 32; x++) {
|
||
|
if (sim->ph.program[x - 1] != sim->cpu.program[x])
|
||
|
return 0;
|
||
|
}
|
||
|
return
|
||
|
sim->ph.adtre == sim->cpu.adtre &&
|
||
|
sim->ph.chcw == cpuGetSystemRegister(sim, VB_CHCW) &&
|
||
|
sim->ph.eipc == sim->cpu.eipc &&
|
||
|
sim->ph.eipsw == sim->cpu.eipsw &&
|
||
|
sim->ph.fepc == sim->cpu.fepc &&
|
||
|
sim->ph.fepsw == sim->cpu.fepsw &&
|
||
|
sim->ph.psw == cpuGetSystemRegister(sim, VB_PSW)
|
||
|
;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/****************************** Clock Measurers ******************************/
|
||
|
|
||
|
/* XPSTTS */
|
||
|
static uint32_t phXPSTTS(VB *sim) {
|
||
|
uint32_t clocks; /* Return value */
|
||
|
uint16_t *halfwords; /* Drawing clocks this SBCOUNT */
|
||
|
uint32_t x; /* Iterator */
|
||
|
|
||
|
/* Drawing is underway */
|
||
|
if (sim->vip.xp.f0bsy || sim->vip.xp.f1bsy) {
|
||
|
clocks = 0;
|
||
|
halfwords = &sim->vip.halfwords[
|
||
|
(uint32_t) sim->vip.xp.sbcount * 384 + sim->vip.xp.column];
|
||
|
for (x = sim->vip.xp.column; x < 384; x++, halfwords++)
|
||
|
clocks += *halfwords;
|
||
|
return clocks;
|
||
|
}
|
||
|
|
||
|
/* Drawing is idle */
|
||
|
switch (sim->vip.dp.step) {
|
||
|
case 0: /* 0ms - FCLK rising edge */
|
||
|
return sim->vip.dp.until;
|
||
|
case 1: /* 3ms - L*BSY rising edge */
|
||
|
case 2: /* 3ms-8ms - Display left frame buffer */
|
||
|
case 3: /* 8ms - L*BSY falling edge */
|
||
|
return sim->vip.dp.until + vipClocksMs(12);
|
||
|
}
|
||
|
/* case 4: 10ms - FCLK falling edge */
|
||
|
/* case 5: 13ms - R*BSY rising edge */
|
||
|
/* case 6: 13ms-18ms - Display right frame buffer */
|
||
|
/* case 7: 18ms - R*BSY falling edge */
|
||
|
return sim->vip.dp.until + vipClocksMs(2);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/***************************** Library Functions *****************************/
|
||
|
|
||
|
/* Test whether to activate pseudo-halt */
|
||
|
static int phAssess(VB *sim, uint32_t address, int type, int32_t value) {
|
||
|
int x; /* Iterator */
|
||
|
|
||
|
/* Memory access does not match last time */
|
||
|
if (!phMatches(sim, address, type, value))
|
||
|
sim->ph.step = 0;
|
||
|
|
||
|
/* New memory access */
|
||
|
if (sim->ph.step == 0) {
|
||
|
sim->ph.address = address;
|
||
|
sim->ph.pc = sim->cpu.pc;
|
||
|
sim->ph.step = 1;
|
||
|
sim->ph.type = type;
|
||
|
sim->ph.value = value;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/* Repeated memory access, not checking full CPU state */
|
||
|
if (sim->ph.step < 2) {
|
||
|
sim->ph.step++;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/* Take a snapshot of the full CPU state */
|
||
|
if (sim->ph.step == 2) {
|
||
|
for (x = 1; x < 32; x++)
|
||
|
sim->ph.program[x - 1] = sim->cpu.program[x];
|
||
|
sim->ph.adtre = sim->cpu.adtre;
|
||
|
sim->ph.chcw = cpuGetSystemRegister(sim, VB_CHCW);
|
||
|
sim->ph.eipc = sim->cpu.eipc;
|
||
|
sim->ph.eipsw = sim->cpu.eipsw;
|
||
|
sim->ph.fepc = sim->cpu.fepc;
|
||
|
sim->ph.fepsw = sim->cpu.fepsw;
|
||
|
sim->ph.psw = cpuGetSystemRegister(sim, VB_PSW);
|
||
|
sim->ph.step = 3;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/* Activate pseudo-halt */
|
||
|
phActivate(sim, address, type);
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
/* Determine how long the CPU should wait before checking the monitor value */
|
||
|
static uint32_t phUntil(VB *sim) {
|
||
|
switch (sim->ph.operation) {
|
||
|
case PH_XPSTTS: return phXPSTTS(sim);
|
||
|
}
|
||
|
return 0; /* PH_NEVER */
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
#endif /* VBAPI */
|