}
#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)
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], 20, 21);
+ return ok;
+}
+
static int t_tim_hblank_h40(void)
{
const u8 *r = (u8 *)0xff0000;
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 v = test_ym_ab_sync();
+ int ok = 1;
+ expect(ok, v, 3);
+ return ok;
+}
+
struct irq_test {
u16 cnt;
union {
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;
{ 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" },
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 */;
}
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);
{