From bb3aa2ff4c1733aeee0f782e75332d697779666d Mon Sep 17 00:00:00 2001 From: Vincent Bousquet Date: Thu, 5 Sep 2024 20:31:43 +0200 Subject: [PATCH] DMD: fix DE 128x16 CPU-DMD com, cleanup timings, fix INT1 --- src/wpc/core.c | 25 +++- src/wpc/core.h | 12 +- src/wpc/dedmd.c | 303 +++++++++++++++++++++++++----------------------- src/wpc/dedmd.h | 3 - src/wpc/s11.c | 2 - 5 files changed, 188 insertions(+), 157 deletions(-) diff --git a/src/wpc/core.c b/src/wpc/core.c index ab2729287..2312055d2 100644 --- a/src/wpc/core.c +++ b/src/wpc/core.c @@ -941,7 +941,7 @@ void video_update_core_dmd(struct mame_bitmap *bitmap, const struct rectangle *c } #endif // The PWM DMD implementation is always returning a full byte, so we shift it down here to return the expected value to existing code - const int shift = ((core_gameData->gen & (GEN_GTS3 | GEN_ALVG | GEN_ALVG_DMD2)) != 0) ? 4 /* 256 to 16 shades */ : ((core_gameData->gen & (GEN_ALLWPC | GEN_DEDMD32 | GEN_ALLWS)) != 0) ? 6 /* 256 to 4 shades */ : 0; + const int shift = ((core_gameData->gen & (GEN_GTS3 | GEN_ALVG | GEN_ALVG_DMD2)) != 0) ? 4 /* 256 to 16 shades */ : ((core_gameData->gen & (GEN_ALLWPC | GEN_DEDMD16 | GEN_DEDMD32 | GEN_ALLWS)) != 0) ? 6 /* 256 to 4 shades */ : 0; memset(&coreGlobals.dotCol[layout->start+1][0], 0, sizeof(coreGlobals.dotCol[0][0])*layout->length+1); memset(&coreGlobals.dotCol[0][0], 0, sizeof(coreGlobals.dotCol[0][0])*layout->length+1); // clear above for (ii = 0; ii < layout->start+1; ii++) { @@ -3019,17 +3019,32 @@ void core_dmd_pwm_init(core_tDMDPWMState* dmd_state, const int width, const int dmd_state->height = height; dmd_state->rawFrameSize = width * height / 8; assert(dmd_state->rawFrameSize * 8 == width * height); + static const UINT16 fir_colorization_3_frames[] = { 20000, 20000, 20000 }; switch (filter) { - case CORE_DMD_PWM_FILTER_DE: // Data East & Whitestar: 473Hz refresh rate / 15Hz low pass filter / 2 frames PWM pattern (are we sure of that ? at least 2 frames, but maybe more) + case CORE_DMD_PWM_FILTER_DE_128x16: // Data East 128x16: 177.5Hz refresh rate / 15Hz low pass filter / 2 frames PWM pattern if (dmd_state->legacyColorization) { // Data East & Whitestar previous implementation would weight the first rasterized frame twice more than the second and would only share this // preshaded version of the frame with the colorization plugin (no raw frames), so we recreate here for backward compatibility. - static const UINT16 fir_colorization_2_frames[] = { 20000, 20000, 20000 }; - dmd_state->fir_weights = fir_colorization_2_frames; + dmd_state->fir_weights = fir_colorization_3_frames; dmd_state->fir_sum = 60000; - dmd_state->fir_size = dmd_state->nFrames = sizeof(fir_colorization_2_frames) / sizeof(UINT16); + dmd_state->fir_size = dmd_state->nFrames = sizeof(fir_colorization_3_frames) / sizeof(UINT16); + } else { + static const UINT16 fir_177_15[] = { 549, 2291, 7523, 13954, 16901, 13954, 7523, 2291, 549 }; + dmd_state->fir_weights = fir_177_15; + dmd_state->fir_sum = 65535; + dmd_state->fir_size = dmd_state->nFrames = sizeof(fir_177_15) / sizeof(UINT16); + } + break; + case CORE_DMD_PWM_FILTER_DE_128x32: // Data East & Whitestar: 473Hz refresh rate / 15Hz low pass filter / 2 frames PWM pattern (are we sure of that ? at least 2 frames, but maybe more) + if (dmd_state->legacyColorization) + { + // Data East & Whitestar previous implementation would weight the first rasterized frame twice more than the second and would only share this + // preshaded version of the frame with the colorization plugin (no raw frames), so we recreate here for backward compatibility. + dmd_state->fir_weights = fir_colorization_3_frames; + dmd_state->fir_sum = 60000; + dmd_state->fir_size = dmd_state->nFrames = sizeof(fir_colorization_3_frames) / sizeof(UINT16); } else { static const UINT16 fir_473_15[] = { 800, 2673, 7764, 13510, 16039, 13510, 7764, 2673, 800 }; dmd_state->fir_weights = fir_473_15; diff --git a/src/wpc/core.h b/src/wpc/core.h index 59e3304ab..d9a9f7abc 100644 --- a/src/wpc/core.h +++ b/src/wpc/core.h @@ -614,11 +614,13 @@ typedef struct { unsigned int fir_sum; // Sum of filter weights unsigned int frame_index; // Raw frame index } core_tDMDPWMState; -#define CORE_DMD_PWM_FILTER_DE 0 -#define CORE_DMD_PWM_FILTER_GTS3 1 -#define CORE_DMD_PWM_FILTER_WPC 2 -#define CORE_DMD_PWM_FILTER_ALVG1 3 -#define CORE_DMD_PWM_FILTER_ALVG2 4 +#define CORE_DMD_PWM_FILTER_DE_128x16 0 +#define CORE_DMD_PWM_FILTER_DE_128x32 1 +#define CORE_DMD_PWM_FILTER_DE_192x64 2 +#define CORE_DMD_PWM_FILTER_GTS3 3 +#define CORE_DMD_PWM_FILTER_WPC 4 +#define CORE_DMD_PWM_FILTER_ALVG1 5 +#define CORE_DMD_PWM_FILTER_ALVG2 6 extern void core_dmd_pwm_init(core_tDMDPWMState* dmd_state, const int width, const int height, const int filter); extern void core_dmd_pwm_exit(core_tDMDPWMState* dmd_state); extern void core_dmd_submit_frame(core_tDMDPWMState* dmd_state, const UINT8* frame); diff --git a/src/wpc/dedmd.c b/src/wpc/dedmd.c index 33df26baa..f80cc0167 100644 --- a/src/wpc/dedmd.c +++ b/src/wpc/dedmd.c @@ -13,13 +13,14 @@ static struct { struct sndbrdData brdData; int cmd, ncmd, busy, status, ctrl, bank; - // dmd16 stuff - UINT32* framedata; - UINT32 hv5408, hv5408s, hv5308, hv5308s, hv5222, lasthv5222; - int blnk, rowdata, rowclk, frame; - int laststat; - // dmd32 frame shading core_tDMDPWMState pwm_state; + + // dmd16 stuff + UINT8 framedata[2][16][2][8]; // 2 PWM frames of 16 rows of 128 bits + UINT32 row_latch, last_row_latch; + UINT64 dot_latch, dot_shift; + int blnk, rowdata, rowclk, test, laststat; + mame_timer* nmi_timer; } dmdlocals; static UINT16 *dmd64RAM; @@ -86,9 +87,9 @@ MACHINE_DRIVER_END Data East and Sega/Stern Whitestar share the (mostly) same DMD board: 520-5055-00 for Data East, 520-5055-01 to 520-5055-03 for Whitestar [Disclaimer, large parts of the following have been deduced from digital recordings and schematics analysis, so may be entirely wrong] - The board is built around a CRTC6845 [U9] which clock is driven by a custom PAL chip [U2]. This design allows to create 4 full shades: + The board is built around a CRTC6845 [U9] which clock is driven by a custom PAL chip [U2]. This design allows to create 0/25/50/75/100 shades: - Each row is rasterized twice by the CRTC6845, first with a 500KHz clock, then with a 1MHz clock. To do so, the PAL chip toggles the - clock divider on each HSYNC from the CRTC6845. RA0 is likely used to toggle the clock divider inside U2. + clock divider of the CRTC6845. RA0 is likely used to toggle the clock divider inside U2. - Data is fed from RAM at offset X for first frame (double PWM length) then at X+0x200 for second frame (single PWM length). To do so, a memory mapping is applied to the linear rasterization performed by the CRTC6845, MA is the memory address output, RA is the character output. Character is used as the PWM frame selector and wired to bit 9 of the memory address allowing to render a line of each frame @@ -130,6 +131,8 @@ static void dmd32_init(struct sndbrdData *brdData) { // and later ones (Sega/Stern Whitestar). if ((core_gameData->gen & GEN_DEDMD32) != 0) // Board 520-5055-00 { + // I can't reproduce the glitch anymore (disappearing score) so this is disabled but kept if it appears again + #if 0 // FIXME hacked 86.20689655172414 Hz from previous implementation to account for glitches for LW3/AS/R&B/SW (score disappears) const struct GameDriver* rootDrv = Machine->gamedrv; while (rootDrv->clone_of && (rootDrv->clone_of->flags & NOT_A_DRIVER) == 0) @@ -142,8 +145,9 @@ static void dmd32_init(struct sndbrdData *brdData) { || (strncasecmp(gn, "mj_", 3) == 0)) // Michael Jordan timer_pulse(1. / 86.20689655172414, 0, dmd32_vblank); else - // Measured at 78.07Hz for the 3 PWM frames (234.21Hz fps) - timer_pulse((32.*0.3921+0.2610) / 1000., 0, dmd32_vblank); + #endif + // Measured at 78.07Hz for the 3 PWM frames (234.21Hz fps) + timer_pulse((32.*0.3921+0.2610) / 1000., 0, dmd32_vblank); } else if ((core_gameData->gen & GEN_ALLWS) != 0) // Board 520-5055-01 to 520-5055-03 // Measured at 77.77Hz for the 3 PWM frames (233.31Hz fps) @@ -152,8 +156,8 @@ static void dmd32_init(struct sndbrdData *brdData) { assert(0); // Unsupported board revision // Init PWM shading - dmdlocals.pwm_state.legacyColorization = 1; // Needed to avoid breaking colorization, but somewhat breaks DMD shading - core_dmd_pwm_init(&dmdlocals.pwm_state, 128, 32, CORE_DMD_PWM_FILTER_DE); + dmdlocals.pwm_state.legacyColorization = 1; // FIXME Needed to avoid breaking colorization, but somewhat breaks DMD shading => make this an option + core_dmd_pwm_init(&dmdlocals.pwm_state, 128, 32, CORE_DMD_PWM_FILTER_DE_128x32); } static void dmd32_exit(int boardNo) { @@ -272,12 +276,12 @@ static void dmd64_init(struct sndbrdData *brdData) { } static WRITE_HANDLER(dmd64_ctrl_w) { - if (data & ~dmdlocals.ctrl & 0x01) { + if (~dmdlocals.ctrl & data & 0x01) { cpu_set_irq_line(dmdlocals.brdData.cpuNo, MC68000_IRQ_1, ASSERT_LINE); sndbrd_ctrl_cb(dmdlocals.brdData.boardNo, dmdlocals.busy = 1); dmdlocals.cmd = dmdlocals.ncmd; } - if (data & ~dmdlocals.ctrl & 0x02) + if (~dmdlocals.ctrl & data & 0x02) cpu_set_reset_line(dmdlocals.brdData.cpuNo, PULSE_LINE); dmdlocals.ctrl = data; } @@ -340,20 +344,21 @@ PINMAME_VIDEO_UPDATE(dedmd64_update) { /*Data East 128x16 DMD Handling*/ /*------------------------------*/ #define DMD16_BANK0 2 -// Steve said he measured this to 2000 on his game but that sometimes causes a new NMI to be triggered before the previous one is finished and it leads to stack overflow -#define DMD16_NMIFREQ (4000000./2048.) // Main CPU clock divided by a 14 bit binary counter, NMI being driven by a the counter value masked by 0x0F00 (U9 - 4020) -/* HC74 bits */ -#define BUSY_CLR 0x01 -#define BUSY_SET 0x02 -#define BUSY_CLK 0x04 + +#define DMD16_NMIFREQ (4000000./2048.) // Main CPU clock divided by a 14 bit binary counter with 3 disabled outputs, so 2^11 +#define DMD16_NMIFREQ_START (4000000./512.) // Initial delay to falling edge of NMI, so after a 9 bit divider +// Steve said he measured this to 2000 on his game which validates these timings. +// Note: on previous version that would sometimes causes a new NMI to be triggered before the previous one is finished and it leads to stack overflow +// Doesn't seems to happen anymore (lots of things have been fixed since, so hopefully fixed too) static void dmd16_init(struct sndbrdData *brdData); +static void dmd16_exit(int boardNo); + static WRITE_HANDLER(dmd16_ctrl_w); -static INTERRUPT_GEN(dmd16_nmi); const struct sndbrdIntf dedmd16Intf = { - NULL, dmd16_init, NULL, NULL,NULL, - dmd_data_w, dmd_busy_r, dmd16_ctrl_w, dmd_status_r, SNDBRD_NOTSOUND + NULL, dmd16_init, dmd16_exit, NULL,NULL, + dmd_data_w, dmd_busy_r, dmd16_ctrl_w, dmd_status_r, SNDBRD_NOTSOUND | SNDBRD_NODATASYNC | SNDBRD_NOCTRLSYNC | SNDBRD_NOCBSYNC }; static READ_HANDLER(dmd16_port_r); @@ -383,103 +388,157 @@ MACHINE_DRIVER_START(de_dmd16) // Board part 520-5042-00 MDRV_CPU_ADD(Z80, 4000000) MDRV_CPU_MEMORY(dmd16_readmem, dmd16_writemem) MDRV_CPU_PORTS(dmd16_readport, dmd16_writeport) - MDRV_CPU_PERIODIC_INT(dmd16_nmi, DMD16_NMIFREQ) MDRV_INTERLEAVE(50) MACHINE_DRIVER_END -static void dmd16_setbusy(int bit, int value); +/* HC74 updated events */ +#define BUSY_UPD_PRESET 0x01 /* Update output after init/reset ot TEST signal state change */ +#define BUSY_CLR_PULSE 0x02 /* CLR reversed pulse (only triggered by IDAT) */ +#define BUSY_CLK_EDGE 0x03 /* Clock edge */ + +static void dmd16_updbusy(int evt); static void dmd16_setbank(int bit, int value); +static void dmd16_nmi(int _) { cpu_set_nmi_line(dmdlocals.brdData.cpuNo, PULSE_LINE); } + +static void dmd16_reset() { + // U4 outputs + dmd16_setbank(0x07, 0x07); + dmdlocals.blnk = 0; + dmdlocals.status = 0; + dmdlocals.rowdata = 0; + dmdlocals.rowclk = 0; + dmdlocals.test = 1; // FIXME, I think this should be 0 + dmd16_updbusy(BUSY_UPD_PRESET); + // NMI counter is also reseted + timer_adjust(dmdlocals.nmi_timer, 1. / DMD16_NMIFREQ_START, 0, 1. / DMD16_NMIFREQ); + // Not really reseted but makes things cleaner + dmdlocals.last_row_latch = dmdlocals.row_latch = 0; + dmdlocals.dot_latch = dmdlocals.dot_shift = 0; +} static void dmd16_init(struct sndbrdData *brdData) { memset(&dmdlocals, 0, sizeof(dmdlocals)); dmdlocals.brdData = *brdData; - memcpy(memory_region(DE_DMD16CPUREGION), - memory_region(DE_DMD16ROMREGION) + memory_region_length(DE_DMD16ROMREGION)-0x4000,0x4000); - dmdlocals.framedata = (UINT32 *)memory_region(DE_DMD16DMDREGION); - dmd16_setbank(0x07, 0x07); - dmd16_setbusy(BUSY_SET|BUSY_CLR,0); + memcpy(memory_region(DE_DMD16CPUREGION), memory_region(DE_DMD16ROMREGION) + memory_region_length(DE_DMD16ROMREGION)-0x4000,0x4000); + dmdlocals.nmi_timer = timer_alloc(dmd16_nmi); + dmd16_reset(); + + // Init PWM shading + //dmdlocals.pwm_state.legacyColorization = 1; // FIXME Needed to avoid breaking colorization, but somewhat breaks DMD shading => make this an option + core_dmd_pwm_init(&dmdlocals.pwm_state, 128, 16, CORE_DMD_PWM_FILTER_DE_128x16); +} + +static void dmd16_exit(int boardNo) { + core_dmd_pwm_exit(&dmdlocals.pwm_state); +} + +INLINE void dmd16_interlace(UINT64 v, UINT8* row) +{ + row[7] = v & 0x00FF; + row[6] = (v >> 8) & 0x00FF; + row[5] = (v >> 16) & 0x00FF; + row[4] = (v >> 24) & 0x00FF; + row[3] = (v >> 32) & 0x00FF; + row[2] = (v >> 40) & 0x00FF; + row[1] = (v >> 48) & 0x00FF; + row[0] = (v >> 56) & 0x00FF; +} + +static void dmd16_updrow() { + if (dmdlocals.blnk && dmdlocals.row_latch) { + // row_latch always has a single bit set, the rasterized row/side, which is odd for left 64x16 panel and even for right 64x16 panel + assert(dmdlocals.row_latch == (dmdlocals.row_latch - (dmdlocals.row_latch & dmdlocals.row_latch - 1))); // check that we only have one bit set + static const int MultiplyDeBruijnBitPosition[32] = + { 0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8, 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9 }; + const int row_n_side = MultiplyDeBruijnBitPosition[((UINT32)((dmdlocals.row_latch & -dmdlocals.row_latch) * 0x077CB531U)) >> 27]; // Compute index of the first trailing set bit (0 based) + const int row = row_n_side >> 1; + const int side = row_n_side & 1; + //printf("%08x %2d %d %I64x\n", dmdlocals.row_latch, row, side, interlace(dmdlocals.hv5408, dmdlocals.hv5308)); + if (dmdlocals.last_row_latch != dmdlocals.row_latch) { // Write to a new row/side: consider it as a long row display (0.50ms) + dmd16_interlace(dmdlocals.dot_latch, &(dmdlocals.framedata[0][row][side][0])); + dmd16_interlace(dmdlocals.dot_latch, &(dmdlocals.framedata[1][row][side][0])); + } else { // Second write to the same row/side: we have 2 frames, the first of 0.13ms and second (already stored, just keep it) of 0.37ms + dmd16_interlace(dmdlocals.dot_latch, &(dmdlocals.framedata[0][row][side][0])); + } + dmdlocals.last_row_latch = dmdlocals.row_latch; + } + if (dmdlocals.blnk && dmdlocals.row_latch == 0) { + //static double prev; printf("DMD VBlank %8.5fms => %8.5fHz for 3 frames so %8.5fHz\n", timer_get_time() - prev, 1. / (timer_get_time() - prev), 3. / (timer_get_time() - prev)); prev = timer_get_time(); + core_dmd_submit_frame(&dmdlocals.pwm_state, (UINT8*) dmdlocals.framedata[0]); // First frame has been displayed 1/3 of the time + core_dmd_submit_frame(&dmdlocals.pwm_state, (UINT8*) dmdlocals.framedata[1]); // Second frame has been displayed 2/3 of the time + core_dmd_submit_frame(&dmdlocals.pwm_state, (UINT8*) dmdlocals.framedata[1]); + } } /*--- Port decoding ---- - 76543210 - 10-001-- Bank0 (stat) - 10-011-- Bank1 (stat) - 10-101-- Bank2 (stat) - 11-001-- Status (stat) - 11-111-- Test (stat) - 1----0-- IDAT (mom) - ------ - 10-111-- Blanking (stat) - 11-011-- Row Data (stat) - 11-101-- Row Clock (stat) - 0----1-- CLATCH (mom) - 0----0-- COCLK (mom) + 76543210 [Latched D0 data, reseted to 0 on reset] + 10-001-- .W Bank0 (reversed) + 10-011-- .W Bank1 (reversed) + 10-101-- .W Bank2 (reversed) + 10-111-- .W Blanking + 11-001-- .W Status (to controller board) + 11-011-- .W Row Data + 11-101-- .W Row Clock + 11-111-- .W Test + ------ [Reversed pulsed (always high unless written to, then generates a low pulse] + 0----1-- .W CLATCH + 0----0-- .W COCLK + 1----0-- R. IDAT (read incoming command and acknowledge to controller board through BUSY signal) --------------------*/ static READ_HANDLER(dmd16_port_r) { - if ((offset & 0x84) == 0x80) { - dmd16_setbusy(BUSY_CLR, 0); dmd16_setbusy(BUSY_CLR,1); + if ((offset & 0x84) == 0x80) { // IDAT reversed pulse + dmd16_updbusy(BUSY_CLR_PULSE); return dmdlocals.cmd; } + assert(0); // This would be invalid from the hardware point of view dmd16_port_w(offset,0xff); return 0xff; } -static void dmd16_dmdout(void) { - UINT32 row = dmdlocals.hv5222; - const int same = (dmdlocals.lasthv5222 == dmdlocals.hv5222); - UINT32 *frame; - - /* Swap frame when no row is selected */ - if (dmdlocals.hv5222 == 0) dmdlocals.frame = !dmdlocals.frame; - frame = &dmdlocals.framedata[dmdlocals.frame*0x80]; - - while (row) { - if (row & 0x01) { - frame[0] = dmdlocals.hv5408; frame[1] = dmdlocals.hv5308; - // low intesity is created by unlighting the dots immediatly after lighting them - if (!same) { frame[2] = frame[0]; frame[3] = frame[1]; } - } - frame += 4; row >>= 1; - } - dmdlocals.lasthv5222 = dmdlocals.hv5222; -} - static WRITE_HANDLER(dmd16_port_w) { switch (offset & 0x84) { - case 0x00: // COCLK - data = data>>((offset & 0x03)*2); - // switch in bits backwards to easy decoding - dmdlocals.hv5408s = (dmdlocals.hv5408s>>1) | ((data & 0x02)?0x80000000:0); - dmdlocals.hv5308s = (dmdlocals.hv5308s>>1) | ((data & 0x01)?0x80000000:0); + case 0x00: // COCLK pulse (32 clock pulse per row side) + data = (data >> ((offset & 0x03) * 2)) & 0x03; + dmdlocals.dot_shift = (dmdlocals.dot_shift << 2) | ((UINT64)data); + break; + case 0x04: // CLATCH pulse (1 or 2 pulse per row side, to allow PWM shading) + dmdlocals.dot_latch = dmdlocals.dot_shift; + dmd16_updrow(); break; - case 0x04: // CLATCH - dmdlocals.hv5408 = dmdlocals.hv5408s; dmdlocals.hv5308 = dmdlocals.hv5308s; - if (dmdlocals.blnk) dmd16_dmdout(); + case 0x80: // IDAT pulse + assert(0); // Invalid as this would activate both the CPU and the latch break; - case 0x80: break; // IDAT (ignored on write) - case 0x84: + case 0x84: // Latched outputs data &= 0x01; switch (offset & 0xdc) { - case 0x84: // Bank0 + case 0x84: // Bank0 (reversed) dmd16_setbank(0x01, !data); break; - case 0x8c: // Bank1 + case 0x8c: // Bank1 (reversed) dmd16_setbank(0x02, !data); break; - case 0x94: // Bank2 + case 0x94: // Bank2 (reversed) dmd16_setbank(0x04, !data); break; - case 0xc4: // Status - sndbrd_ctrl_cb(dmdlocals.brdData.boardNo, dmdlocals.status = data); break; - case 0xdc: // Test - dmd16_setbusy(BUSY_SET, data); break; case 0x9c: // Blanking - dmdlocals.blnk = data; if (data) dmd16_dmdout(); + dmdlocals.blnk = data; + dmd16_updrow(); + break; + case 0xc4: // Status + dmdlocals.status = data; + sndbrd_ctrl_cb(dmdlocals.brdData.boardNo, dmdlocals.status); break; case 0xcc: // Row data - dmdlocals.rowdata = data; break; + dmdlocals.rowdata = data; + break; case 0xd4: // Row clock - if (~data & dmdlocals.rowclk) // negative edge - dmdlocals.hv5222 = (dmdlocals.hv5222<<1) | (dmdlocals.rowdata); + if (dmdlocals.rowclk & ~data) // High to low edge + dmdlocals.row_latch = (dmdlocals.row_latch << 1) | (dmdlocals.rowdata); dmdlocals.rowclk = data; + dmd16_updrow(); + break; + case 0xdc: // Test + //printf("%8.5f Set TEST = %02x [Busy=%02x]\n", timer_get_time(), dmdlocals.test, dmdlocals.busy); + dmdlocals.test = data; + dmd16_updbusy(BUSY_UPD_PRESET); break; } // Switch break; @@ -487,46 +546,28 @@ static WRITE_HANDLER(dmd16_port_w) { } static WRITE_HANDLER(dmd16_ctrl_w) { - if ((data | dmdlocals.ctrl) & 0x01) { + if (~dmdlocals.ctrl & data & 0x01) { // J1-19 on raising edge, latch incoming command and set BUSY/INT + //printf("%8.5f Cmd %02x\n", timer_get_time(), dmdlocals.ncmd); dmdlocals.cmd = dmdlocals.ncmd; - dmd16_setbusy(BUSY_CLK, data & 0x01); + dmd16_updbusy(BUSY_CLK_EDGE); } - if (~data & dmdlocals.ctrl & 0x02) { - sndbrd_ctrl_cb(dmdlocals.brdData.boardNo, dmdlocals.status = 0); - dmd16_setbank(0x07, 0x07); dmd16_setbusy(BUSY_SET, 0); - dmdlocals.rowdata = dmdlocals.blnk = 0; + if (dmdlocals.ctrl & ~data & 0x02) { // J1-20 RESET (trigger on falling edge of signal while it should be a continuous reset state when high) cpu_set_reset_line(dmdlocals.brdData.cpuNo, PULSE_LINE); - dmdlocals.hv5408 = dmdlocals.hv5408s = dmdlocals.hv5308 = dmdlocals.hv5308s = - dmdlocals.hv5222 = dmdlocals.lasthv5222 = dmdlocals.rowclk = dmdlocals.frame = 0; + dmd16_reset(); } dmdlocals.ctrl = data; } -static void dmd16_setbusy(int bit, int value) { - const int newstat = (dmdlocals.laststat & ~bit) | (value ? bit : 0); -#if 1 - /* In the data-sheet for the HC74 flip-flop is says that SET & CLR are _not_ - edge triggered. For some strange reason, the DMD doesn't work unless we - treat the HC74 as edge-triggered. - */ - if (~newstat & dmdlocals.laststat & BUSY_CLR) dmdlocals.busy = 0; - else if (~newstat & dmdlocals.laststat & BUSY_SET) dmdlocals.busy = 1; - else if ((newstat & (BUSY_CLR|BUSY_SET)) == (BUSY_CLR|BUSY_SET)) { - if (newstat & ~dmdlocals.laststat & BUSY_CLK) dmdlocals.busy = 1; - } -#else - switch (newstat & 0x03) { - case 0x00: // CLR=0 SET=0 => CLR - case 0x02: // CLR=0 SET=1 => CLR - dmdlocals.busy = 0; break; - case 0x03: // CLR=1 SET=1 => check clock - if (!(newstat & ~laststat & BUSY_CLK)) break; - case 0x01: // CLR=1 SET=0 => SET - dmdlocals.busy = 1; break; - } -#endif - dmdlocals.laststat = newstat; - cpu_set_irq_line(dmdlocals.brdData.cpuNo, Z80_INT_REQ, dmdlocals.busy ? ASSERT_LINE : CLEAR_LINE); +static void dmd16_updbusy(int evt) { + const int prev_busy = dmdlocals.busy; + // TODO CLR_PULSE will reset the flip flop to 0 even while PRESET is pulled down. This does not match the datasheet which states + // that in this situation both output would be high (so keep BUSY at 1, but also trigger INT1). + if (evt == BUSY_CLR_PULSE) + dmdlocals.busy = 0; + else if ((dmdlocals.test == 0) || (evt == BUSY_CLK_EDGE)) + dmdlocals.busy = 1; + //if (dmdlocals.busy != prev_busy) printf("%8.5f Busy Change to %02x (cause: %02x)\n", timer_get_time(), dmdlocals.busy, evt); + cpu_set_irq_line(dmdlocals.brdData.cpuNo, Z80_INT_REQ, dmdlocals.busy ? HOLD_LINE : CLEAR_LINE); sndbrd_data_cb(dmdlocals.brdData.boardNo, dmdlocals.busy); } @@ -534,32 +575,10 @@ static void dmd16_setbank(int bit, int value) { dmdlocals.bank = (dmdlocals.bank & ~bit) | (value ? bit : 0); cpu_setbank(DMD16_BANK0, dmdlocals.brdData.romRegion + (dmdlocals.bank & 0x07)*0x4000); } -static INTERRUPT_GEN(dmd16_nmi) { cpu_set_nmi_line(dmdlocals.brdData.cpuNo, PULSE_LINE); } /*-- update display --*/ PINMAME_VIDEO_UPDATE(dedmd16_update) { - const UINT32 *frame = &dmdlocals.framedata[(!dmdlocals.frame)*0x80]; - int ii; - - for (ii = 1; ii <= 16; ii++) { - UINT8 *line = &coreGlobals.dotCol[ii][0]; - int jj; - for (jj = 0; jj < 2; jj++) { - UINT32 tmp0 = frame[0]; - UINT32 tmp1 = frame[1]; - UINT32 tmp2 = frame[2]; - UINT32 tmp3 = frame[3]; - int kk; - for (kk = 0; kk < 32; kk++) { - //If both dots are lit, we use color 3, but if only 1, we use 1. - *line++ = (tmp2 & 0x01) + (2 * (tmp0 & 0x01)); - *line++ = (tmp3 & 0x01) + (2 * (tmp1 & 0x01)); - tmp0 >>= 1; tmp1 >>= 1; tmp2 >>= 1; tmp3 >>= 1; - } - frame += 4; - } - *line++ = 0; - } + core_dmd_update_pwm(&dmdlocals.pwm_state); video_update_core_dmd(bitmap, cliprect, layout); return 0; } diff --git a/src/wpc/dedmd.h b/src/wpc/dedmd.h index 819c38fc1..08cc74332 100644 --- a/src/wpc/dedmd.h +++ b/src/wpc/dedmd.h @@ -39,21 +39,18 @@ extern PINMAME_VIDEO_UPDATE(dedmd64_update); #define DE_DMD16CPUNO 2 #define DE_DMD16CPUREGION (REGION_CPU1 + DE_DMD16CPUNO) #define DE_DMD16ROMREGION (REGION_GFX1 + DE_DMD16CPUNO) -#define DE_DMD16DMDREGION (REGION_USER1 + DE_DMD16CPUNO) extern MACHINE_DRIVER_EXTERN(de_dmd16); extern PINMAME_VIDEO_UPDATE(dedmd16_update); #define DE_DMD16ROM1(n1,chk1) \ NORMALREGION(0x10000, DE_DMD16CPUREGION) \ - NORMALREGION(0x400, DE_DMD16DMDREGION) /* 16x128x2bitsx2buffers */ \ NORMALREGION(0x20000, DE_DMD16ROMREGION) \ ROM_LOAD(n1, 0x00000, 0x10000, chk1) \ ROM_RELOAD(0x10000, 0x10000) #define DE_DMD16ROM2(n1,chk1) \ NORMALREGION(0x10000, DE_DMD16CPUREGION) \ - NORMALREGION(0x400, DE_DMD16DMDREGION) /* 16x128x2bitsx2buffers */ \ NORMALREGION(0x20000, DE_DMD16ROMREGION) \ ROM_LOAD(n1, 0x00000, 0x20000, chk1) diff --git a/src/wpc/s11.c b/src/wpc/s11.c index 391ec3cc9..b2f3dba30 100644 --- a/src/wpc/s11.c +++ b/src/wpc/s11.c @@ -617,8 +617,6 @@ static READ_HANDLER(pia4a_r) /--------*/ /*-- Sound board sound command--*/ static WRITE_HANDLER(pia5b_w) { - //Data East 128x16 games need to eat the 0xfe command (especially Hook) - if ((core_gameData->gen & GEN_DEDMD16) && (data == 0xfe)) return; locals.sndCmd = data; sndbrd_1_data_w(0,data); }