void exception(const struct exc_frame *f)
{
+ u32 *sp, sp_add;
int i;
while (read16(VDP_CTRL_PORT) & 2)
printf(" \n");
if (f->ecxnum < 4) {
- printf(" PC: %08x SR: %04x \n", f->bae.pc, f->bae.sr);
+ printf(" PC: %08x SR: %04x \n", f->bae.pc, f->bae.sr);
printf("addr: %08x IR: %04x FC: %02x \n",
f->bae.addr, f->bae.ir, f->bae.fc);
+ sp_add = 14;
}
else {
- printf(" PC: %08x SR: %04x \n", f->g.pc, f->g.sr);
+ printf(" PC: %08x SR: %04x \n", f->g.pc, f->g.sr);
+ sp_add = 6;
}
for (i = 0; i < 8; i++)
printf(" D%d: %08x A%d: %08x \n", i, f->dr[i], i, f->ar[i]);
- printf(" \n");
+ printf(" \n");
+ sp = (u32 *)(f->ar[7] + sp_add);
+ printf(" %08x %08x %08x %08x\n", sp[0], sp[1], sp[2], sp[3]);
+ printf(" %08x %08x %08x %08x\n", sp[4], sp[5], sp[6], sp[7]);
}
// ---
}
#define expect(ok_, v0_, v1_) \
-if ((v0_) != (v1_)) { \
+do { if ((v0_) != (v1_)) { \
printf("%s: %08x %08x\n", #v0_, v0_, v1_); \
ok_ = 0; \
-}
+}} while (0)
#define expect_range(ok_, v0_, vmin_, vmax_) \
-if ((v0_) < (vmin_) || (v0_) > (vmax_)) { \
+do { if ((v0_) < (vmin_) || (v0_) > (vmax_)) { \
printf("%s: %02x /%02x-%02x\n", #v0_, v0_, vmin_, vmax_); \
ok_ = 0; \
-}
+}} while (0)
#define expect_bits(ok_, v0_, val_, mask_) \
-if (((v0_) & (mask_)) != (val_)) { \
+do { if (((v0_) & (mask_)) != (val_)) { \
printf("%s: %04x & %04x != %04x\n", #v0_, v0_, mask_, val_); \
ok_ = 0; \
-}
+}} while (0)
static int t_dma_zero_wrap(void)
{
return ok;
}
-#define Z80_CP_CYCLES(b) (118 + ((b) - 1) * 21 + 26 + 17)
+#define Z80_C_DISPATCH 113 // see z80_test.s80
+#define Z80_C_END 17
+#define Z80_C_END_VCNT 67
+
+#define Z80_CYLES_TEST1(b) (Z80_C_DISPATCH + ((b) - 1) * 21 + 26 + Z80_C_END)
static int t_z80mem_vdp_r(void)
{
zram[0x1100] = zram[0x1101] = zram[0x1102] = 0x5a;
mem_barrier();
write16(0xa11100, 0x000);
- burn10(Z80_CP_CYCLES(2) * 15 / 7 * 2 / 10);
+ burn10(Z80_CYLES_TEST1(2) * 15 / 7 / 10);
write16(0xa11100, 0x100);
while (read16(0xa11100) & 0x100)
zram[0x1101] = 0x66;
mem_barrier();
write16(0xa11100, 0x000);
- burn10(Z80_CP_CYCLES(2) * 15 / 7 * 2 / 10);
+ burn10(Z80_CYLES_TEST1(2) * 15 / 7 / 10);
write16(0xa11100, 0x100);
while (read16(0xa11100) & 0x100)
return ok;
}
-#define Z80_RD_V_CYCLES(b) (132 + (b) * 38 + 50 + 17)
+static int t_tim_z80_loop(void)
+{
+ u8 pal = read8(0xa10001) & 0x40;
+ u8 *zram = (u8 *)0xa00000;
+ u16 z80_loops = pal ? 3420*(313*2+1)/15/100 : 3420*(262*2+1)/15/100; // 2fr + 1ln
+ u16 _68k_loops = pal ? 3420*(313*2+1)/7/10 : 3420*(262*2+1)/7/10;
+ int ok = 1;
+
+ zram[0x1000] = 3; // idle loop, save vcnt
+ write16_z80le(&zram[0x1002], 0); // src (unused)
+ write16_z80le(&zram[0x1004], 0x1100); // vcnt dst
+ write16_z80le(&zram[0x1006], z80_loops); // x100 cycles
+ zram[0x1100] = 0;
+ mem_barrier();
+
+ vdp_wait_for_line_0();
+ write16(0xa11100, 0x000);
+ burn10(_68k_loops + (Z80_C_DISPATCH + Z80_C_END_VCNT) * 15 / 7 / 10);
+
+ write16(0xa11100, 0x100);
+ while (read16(0xa11100) & 0x100)
+ ;
+ expect(ok, zram[0x1000], 0);
+ expect(ok, zram[0x1100], 1);
+ return ok;
+}
+
+#define Z80_CYCLES_TEST2(b) (Z80_C_DISPATCH + (b) * 38 + Z80_C_END_VCNT)
// 80 80 91 95-96
static void z80_read_loop(u8 *zram, u16 src)
vdp_wait_for_line_0();
write16(0xa11100, 0x000);
- burn10(Z80_RD_V_CYCLES(pairs) * 15 / 7 * 4 / 10);
+ burn10(Z80_CYCLES_TEST2(pairs) * 15 / 7 * 2 / 10);
write16(0xa11100, 0x100);
while (read16(0xa11100) & 0x100)
z80_read_loop(zram, 0x7f08);
expect(ok, zram[0x1000], 0);
-#ifndef PICO
expect_range(ok, zram[0x1100], 0x91, 0x91);
-#else
- expect_range(ok, zram[0x1100], 0x8e, 0x91);
-#endif
return ok;
}
z80_read_loop(zram, 0x8000);
expect(ok, zram[0x1000], 0);
-#ifndef PICO
expect_range(ok, zram[0x1100], 0x95, 0x96);
-#else
- expect_range(ok, zram[0x1100], 0x93, 0x96);
-#endif
return ok;
}
return ok;
}
+static int t_tim_vcnt_loops(void)
+{
+ const u16 *ram16 = (u16 *)0xfff004;
+ u8 pal = read8(0xa10001) & 0x40;
+ u16 i, lines = pal ? 313 : 262;
+ int ok = 1;
+
+ test_vcnt_loops();
+ expect(ok, ram16[-1*2+0], 0xff);
+ expect_range(ok, ram16[-1*2+1], 21, 22);
+ for (i = 0; i < lines; i++)
+ expect_range(ok, ram16[i*2+1], 19, 21);
+ expect(ok, ram16[lines*2+0], 0);
+ expect_range(ok, ram16[lines*2+1], 19, 21);
+ return ok;
+}
+
static int t_tim_hblank_h40(void)
{
const u8 *r = (u8 *)0xff0000;
test_hb();
VDP_setReg(VDP_MODE4, 0x81);
-#ifndef PICO
expect_bits(ok, r[0], 0, SR_HB);
-#endif
// set: 1-4
expect_bits(ok, r[4], SR_HB, SR_HB);
expect_bits(ok, r[5], SR_HB, SR_HB);
setup_default_palette();
-#ifndef PICO
expect(ok, vcnt, 112);
-#else
- expect_range(ok, vcnt, 111, 112);
-#endif
+ return ok;
+}
+
+static const u8 hcnt2tm[] =
+{
+ 0x0a, 0x1d, 0x31, 0x44, 0x58, 0x6b, 0x7f, 0x92,
+ 0xa6, 0xb9, 0xcc, 0x00, 0x00, 0x00, 0xe2, 0xf6
+};
+
+static int t_tim_ym_timer_z80(int is_b)
+{
+ u8 pal = read8(0xa10001) & 0x40;
+ u8 *zram = (u8 *)0xa00000;
+ u8 *z80 = zram;
+ u16 _68k_loops = 3420*(302+5+1)/7/10; // ~ (72*1024*2)/(3420./7)
+ u16 start, end, diff;
+ int ok = 1;
+
+ zram[0x1000] = 4 + is_b; // ym2612 timer a/b test
+ zram[0x1100] = zram[0x1101] = zram[0x1102] = zram[0x1103] = 0;
+ mem_barrier();
+
+ vdp_wait_for_line_0();
+ write16(0xa11100, 0x000);
+
+ burn10(_68k_loops + (Z80_C_DISPATCH + Z80_C_END_VCNT) * 15 / 7 / 10);
+
+ write16(0xa11100, 0x100);
+ while (read16(0xa11100) & 0x100)
+ ;
+ mem_barrier();
+ expect(ok, zram[0x1000], 0);
+ (void)hcnt2tm;
+ //start = ((u16)zram[0x1102] << 8) | hcnt2tm[zram[0x1103] >> 4];
+ //end = ((u16)zram[0x1100] << 8) | hcnt2tm[zram[0x1101] >> 4];
+ start = zram[0x1102];
+ end = zram[0x1100];
+ diff = end - start;
+ if (pal)
+ expect_range(ok, diff, 0xf4, 0xf6);
+ else
+ expect_range(ok, diff, 0x27, 0x29);
+ write8(&z80[0x4001], 0); // stop, but should keep the flag
+ mem_barrier();
+ burn10(32*6/10); // busy bit, 32 FM ticks (M/7/6)
+ if (is_b) {
+ expect(ok, z80[0x4000], 2);
+ write8(&z80[0x4001], 0x20); // reset flag (reg 0x27, set up by z80)
+ }
+ else {
+ expect(ok, z80[0x4000], 1);
+ write8(&z80[0x4001], 0x10);
+ }
+ mem_barrier();
+ burn10(32*6/10);
+ expect(ok, z80[0x4000], 0);
+ return ok;
+}
+
+static int t_tim_ym_timera_z80(void)
+{
+ return t_tim_ym_timer_z80(0);
+}
+
+static int t_tim_ym_timerb_z80(void)
+{
+ return t_tim_ym_timer_z80(1);
+}
+
+static int t_tim_ym_timerb_stop(void)
+{
+ const struct {
+ //u8 vcnt_start;
+ //u8 hcnt_start;
+ u16 vcnt_start;
+ u16 stat0;
+ //u8 vcnt_end;
+ //u8 hcnt_end;
+ u16 vcnt_end;
+ u16 stat1;
+ } *t = (void *)0xfff000;
+ u8 *z80 = (u8 *)0xa00000;
+ u16 diff;
+ int ok = 1;
+ write16(0xa11100, 0x100);
+ while (read16(0xa11100) & 0x100)
+ ;
+ test_ym_stopped_tick();
+ mem_barrier();
+ //start = ((u16)t->vcnt_start << 8) | hcnt2tm[t->hcnt_start >> 4];
+ //end = ((u16)t->vcnt_end << 8) | hcnt2tm[t->hcnt_end >> 4];
+ //diff = end - start;
+ diff = t->vcnt_end - t->vcnt_start;
+ //expect_range(ok, diff, 0x492, 0x5c2); // why so much variation?
+ expect_range(ok, diff, 4, 5);
+ expect(ok, t->stat0, 0);
+ expect(ok, t->stat1, 2);
+ expect(ok, z80[0x4000], 2);
+ write8(&z80[0x4001], 0x30);
+ return ok;
+}
+
+static int t_tim_ym_timer_ab_sync(void)
+{
+ u16 v1, v2, v3, start, line_diff;
+ int ok = 1;
+ v1 = test_ym_ab_sync();
+ start = get_line();
+ write8(0xa04001, 0x3f); // clear
+ burn10(3420*11/7/10); // ~11 scanlines
+ v2 = read8(0xa04000);
+ v3 = test_ym_ab_sync2();
+ line_diff = get_line() - start;
+ expect(ok, v1, 3);
+ expect(ok, v2, 0);
+ expect(ok, v3, 3);
+ expect_range(ok, line_diff, 18, 19);
return ok;
}
u16 hv;
u8 v;
} first, last;
+ u16 pad;
};
+// broken on fresh boot due to uknown reasons
static int t_irq_hint(void)
{
struct irq_test *it = (void *)0xfff000;
+ struct irq_test *itv = it + 1;
int ok = 1;
+ memset_(it, 0, sizeof(*it) * 2);
+ memcpy_((void *)0xff0100, test_hint, test_hint_end - test_hint);
+ memcpy_((void *)0xff0140, test_vint, test_vint_end - test_vint);
+
+ // without this, tests fail after cold boot
+ while (!(read16(VDP_CTRL_PORT) & 8))
+ /* not blanking */;
+
// for more fun, disable the display
VDP_setReg(VDP_MODE2, VDP_MODE2_MD);
- it->cnt = it->first.hv = it->last.hv = 0;
- memcpy_((void *)0xff0100, test_hint, test_hint_end - test_hint);
VDP_setReg(10, 0);
while (read8(VDP_HV_COUNTER) != 100)
;
move_sr(0x2700);
expect(ok, it->first.v, 229); // pending irq trigger
expect(ok, it->cnt, 1);
+ expect(ok, itv->cnt, 0);
// count irqs
it->cnt = it->first.hv = it->last.hv = 0;
return ok;
}
+static int t_irq_both_cpu_unmask(void)
+{
+ struct irq_test *ith = (void *)0xfff000;
+ struct irq_test *itv = ith + 1;
+ u16 s0, s1;
+ int ok = 1;
+
+ memset_(ith, 0, sizeof(*ith) * 2);
+ memcpy_((void *)0xff0100, test_hint, test_hint_end - test_hint);
+ memcpy_((void *)0xff0140, test_vint, test_vint_end - test_vint);
+ VDP_setReg(10, 0);
+ while (read8(VDP_HV_COUNTER) != 100)
+ ;
+ while (read8(VDP_HV_COUNTER) != 226)
+ ;
+ VDP_setReg(10, 99);
+ VDP_setReg(VDP_MODE1, VDP_MODE1_PS | VDP_MODE1_IE1);
+ VDP_setReg(VDP_MODE2, VDP_MODE2_MD | VDP_MODE2_IE0 | VDP_MODE2_DISP);
+ /* go to active display line 100 */
+ while (read8(VDP_HV_COUNTER) != 100)
+ ;
+ s0 = read16(VDP_CTRL_PORT);
+ s1 = move_sr_and_read(0x2000, VDP_CTRL_PORT);
+ move_sr(0x2700);
+ VDP_setReg(VDP_MODE1, VDP_MODE1_PS);
+ VDP_setReg(VDP_MODE2, VDP_MODE2_MD | VDP_MODE2_DMA | VDP_MODE2_DISP);
+
+ expect(ok, itv->cnt, 1); // vint count
+ expect(ok, itv->first.v, 100); // vint line
+ expect(ok, ith->cnt, 1); // hint count
+ expect(ok, ith->first.v, 100); // hint line
+ expect_bits(ok, s0, SR_F, SR_F);
+ expect_bits(ok, s1, 0, SR_F);
+ return ok;
+}
+
static int t_irq_ack_v_h(void)
{
- u16 *ram = (u16 *)0xfff000;
- u8 *ram8 = (u8 *)0xfff000;
+ struct irq_test *ith = (void *)0xfff000;
+ struct irq_test *itv = ith + 1;
u16 s0, s1, s2;
int ok = 1;
- ram[0] = ram[1] = ram[2] =
- ram[4] = ram[5] = ram[6] = 0;
+ memset_(ith, 0, sizeof(*ith) * 2);
memcpy_((void *)0xff0100, test_hint, test_hint_end - test_hint);
memcpy_((void *)0xff0140, test_vint, test_vint_end - test_vint);
VDP_setReg(10, 0);
VDP_setReg(VDP_MODE1, VDP_MODE1_PS);
VDP_setReg(VDP_MODE2, VDP_MODE2_MD | VDP_MODE2_DMA | VDP_MODE2_DISP);
- expect(ok, ram[4], 1); // vint count
- expect(ok, ram8[10], 226); // vint line
- expect(ok, ram[0], 1); // hint count
- expect(ok, ram8[2], 228); // hint line
+ expect(ok, itv->cnt, 1); // vint count
+ expect(ok, itv->first.v, 226); // vint line
+ expect(ok, ith->cnt, 1); // hint count
+ expect(ok, ith->first.v, 228); // hint line
expect_bits(ok, s0, SR_F, SR_F);
expect_bits(ok, s1, 0, SR_F);
expect_bits(ok, s2, 0, SR_F);
static int t_irq_ack_v_h_2(void)
{
- u16 *ram = (u16 *)0xfff000;
- u8 *ram8 = (u8 *)0xfff000;
+ struct irq_test *ith = (void *)0xfff000;
+ struct irq_test *itv = ith + 1;
u16 s0, s1;
int ok = 1;
- ram[0] = ram[1] = ram[2] =
- ram[4] = ram[5] = ram[6] = 0;
+ memset_(ith, 0, sizeof(*ith) * 2);
memcpy_((void *)0xff0100, test_hint, test_hint_end - test_hint);
memcpy_((void *)0xff0140, test_vint, test_vint_end - test_vint);
VDP_setReg(10, 0);
VDP_setReg(VDP_MODE1, VDP_MODE1_PS);
VDP_setReg(VDP_MODE2, VDP_MODE2_MD | VDP_MODE2_DMA | VDP_MODE2_DISP);
- expect(ok, ram[4], 2); // vint count
- expect(ok, ram8[10], 226); // vint line
- expect(ok, ram[0], 1); // hint count
- expect(ok, ram8[2], 227); // hint line
+ expect(ok, itv->cnt, 2); // vint count
+ expect(ok, itv->first.v, 226); // vint line
+ expect(ok, ith->cnt, 1); // hint count
+ expect(ok, ith->first.v, 227); // hint line
expect_bits(ok, s0, SR_F, SR_F);
expect_bits(ok, s1, 0, SR_F);
return ok;
expect(ok, rmb[0], 0x5a);
expect(ok, rl[0x04/4], 0x880200);
+ expect(ok, rl[0x10/4], 0x880212);
+ expect(ok, rl[0x94/4], 0x8802d8);
return ok;
}
return ok;
}
+static int t_32x_disable(void)
+{
+ void (*do_32x_disable)(void) = (void *)0xff0040;
+ u32 *r = (u32 *)0xa15100;
+ u16 *r16 = (u16 *)r;
+ u32 *rl = (u32 *)0;
+ int ok = 1;
+
+ expect(ok, r16[0x00/2], 0x83);
+
+ memcpy_(do_32x_disable, x32x_disable,
+ x32x_disable_end - x32x_disable);
+ do_32x_disable();
+
+ expect(ok, r16[0x00/2], 0x82);
+ expect(ok, r16[0x02/2], 0);
+ expect(ok, r16[0x04/2], 0);
+ expect(ok, r16[0x06/2], 1); // RV
+ expect(ok, r[0x14/4], 0);
+ expect(ok, r[0x18/4], 0);
+ expect(ok, r[0x1c/4], 0);
+ expect(ok, rl[0x04/4], 0x000800);
+
+ write16(&r16[0x06/2], 0); // can just set without ADEN
+ mem_barrier();
+ expect(ok, r16[0x06/2], 0); // RV
+ return ok;
+}
+
enum {
T_MD = 0,
T_32 = 1, // 32X
{ T_MD, t_dma_short_cmd, "dma short cmd" },
{ T_MD, t_dma_fill3_odd, "dma fill3 odd" },
{ T_MD, t_dma_fill3_even, "dma fill3 even" },
-#ifndef PICO // later
{ T_MD, t_dma_fill3_vsram, "dma fill3 vsram" },
-#endif
{ T_MD, t_dma_fill_dis, "dma fill disabled" },
{ T_MD, t_dma_fill_src, "dma fill src incr" },
{ T_MD, t_dma_128k, "dma 128k mode" },
{ T_MD, t_z80mem_vdp_r, "z80 vdp read" },
// { t_z80mem_vdp_w, "z80 vdp write" }, // hang
{ T_MD, t_tim_loop, "time loop" },
+ { T_MD, t_tim_z80_loop, "time z80 loop" },
{ T_MD, t_tim_z80_ram, "time z80 ram" },
{ T_MD, t_tim_z80_ym, "time z80 ym2612" },
{ T_MD, t_tim_z80_vdp, "time z80 vdp" },
{ T_MD, t_tim_z80_bank_rom, "time z80 bank rom" },
{ T_MD, t_tim_vcnt, "time V counter" },
+ { T_MD, t_tim_vcnt_loops, "time vcnt loops" },
{ T_MD, t_tim_hblank_h40, "time hblank h40" },
{ T_MD, t_tim_hblank_h32, "time hblank h32" },
{ T_MD, t_tim_vdp_as_vram_w, "time vdp vram w" },
{ T_MD, t_tim_vdp_as_cram_w, "time vdp cram w" },
+ { T_MD, t_tim_ym_timera_z80, "time timer a z80" },
+ { T_MD, t_tim_ym_timerb_z80, "time timer b z80" },
+ { T_MD, t_tim_ym_timerb_stop, "timer b stop" },
+ { T_MD, t_tim_ym_timer_ab_sync,"timer ab sync" },
{ T_MD, t_irq_hint, "irq4 / line" },
+ { T_MD, t_irq_both_cpu_unmask, "irq both umask" },
{ T_MD, t_irq_ack_v_h, "irq ack v-h" },
{ T_MD, t_irq_ack_v_h_2, "irq ack v-h 2" },
{ T_MD, t_irq_ack_h_v, "irq ack h-v" },
{ T_32, t_32x_md_rom, "32x md rom" },
{ T_32, t_32x_md_fb, "32x md fb" },
{ T_32, t_32x_sh_fb, "32x sh fb" },
+ { T_32, t_32x_disable, "32x disable" }, // must be last 32x
};
static void setup_z80(void)
write16(0xa11100, 0x000);
burn10(1);
write16(0xa11200, 0x100);
- burn10(1);
+
+ burn10(50 * 15 / 7 / 10); // see z80_test.s80
// take back the bus
write16(0xa11100, 0x100);
static void wait_next_vsync(void)
{
- while (read16(VDP_CTRL_PORT) & 8)
+ while (read16(VDP_CTRL_PORT) & SR_VB)
/* blanking */;
- while (!(read16(VDP_CTRL_PORT) & 8))
+ while (!(read16(VDP_CTRL_PORT) & SR_VB))
/* not blanking */;
}
int passed = 0;
int skipped = 0;
int have_32x;
+ int en_32x;
int ret;
u8 v8;
int i;
VDP_setReg(VDP_MODE2, VDP_MODE2_MD | VDP_MODE2_DMA | VDP_MODE2_DISP);
have_32x = read32(0xa130ec) == MKLONG('M','A','R','S');
+ en_32x = have_32x && (read32(0xa15100) & 1);
v8 = read8(0xa10001);
- printf("MD version: %02x %s %s %s\n", v8,
+ printf("MD version: %02x %s %s %s%s\n", v8,
(v8 & 0x80) ? "world" : "jap",
(v8 & 0x40) ? "pal" : "ntsc",
- have_32x ? "32X" : "");
+ have_32x ? "32X" : "",
+ en_32x ? "+" : "");
for (i = 0; i < ARRAY_SIZE(g_tests); i++) {
// print test number if we haven't scrolled away
printf_ypos = 0;
printf(" ");
- while (!(get_input() & BTNM_A))
+ for (i = 0; i < 60*60 && !(get_input() & BTNM_A); i++)
wait_next_vsync();
+#ifndef PICO
+ // blank due to my lame tv being burn-in prone
+ VDP_setReg(VDP_MODE2, VDP_MODE2_MD);
+#endif
+ while (!(get_input() & BTNM_A))
+ burn10(488*100/10);
+ VDP_setReg(VDP_MODE2, VDP_MODE2_MD | VDP_MODE2_DMA | VDP_MODE2_DISP);
{