From 5449df7dc57e26a7f0fab3ec8e392d54292eec90 Mon Sep 17 00:00:00 2001 From: Vincent Bousquet Date: Sat, 31 Aug 2024 15:48:08 +0200 Subject: [PATCH] DMD: generic PWM support, Data East 128x32 support, Alvin G support, GTS3 & WPC cleanups, --- src/vidhrdw/crtc6845.c | 10 ++ src/vidhrdw/crtc6845.h | 4 + src/wpc/alvg.c | 6 +- src/wpc/alvgdmd.c | 277 ++++++++++++++--------------------------- src/wpc/alvgdmd.h | 2 - src/wpc/alvggames.c | 19 +-- src/wpc/core.c | 233 +++++++++++++++++++++++++++++++--- src/wpc/core.h | 25 ++++ src/wpc/dedmd.c | 134 ++++++++++---------- src/wpc/dedmd.h | 1 - src/wpc/degames.c | 50 ++++---- src/wpc/dmddevice.cpp | 4 +- src/wpc/gts3.c | 35 ++++-- src/wpc/gts3.h | 2 +- src/wpc/gts3dmd.c | 79 +----------- src/wpc/gts3dmd.h | 2 - src/wpc/s11.c | 11 -- src/wpc/s11.h | 1 - src/wpc/wpc.c | 90 ++++--------- 19 files changed, 498 insertions(+), 487 deletions(-) diff --git a/src/vidhrdw/crtc6845.c b/src/vidhrdw/crtc6845.c index 843de7262..4b00c2601 100644 --- a/src/vidhrdw/crtc6845.c +++ b/src/vidhrdw/crtc6845.c @@ -260,7 +260,17 @@ int crtc6845_start_address_r(int offset) { return crtc6845[offset].start_addr; } +//Return rasterization size +int crtc6845_get_rasterized_height(int offset) +{ + // height in scanlines is the number of displayed character line * number of scanlines per character + return crtc6845[offset].vert_disp * (crtc6845[offset].max_ras_addr + 1); +} +int crtc6845_get_rasterized_width(int offset) +{ + return crtc6845[offset].horiz_disp; +} diff --git a/src/vidhrdw/crtc6845.h b/src/vidhrdw/crtc6845.h index 49d188751..91e00d629 100644 --- a/src/vidhrdw/crtc6845.h +++ b/src/vidhrdw/crtc6845.h @@ -23,6 +23,10 @@ WRITE_HANDLER( crtc6845_register_w ); //Return current video start address int crtc6845_start_address_r(int offset); +//Return rasterization size +int crtc6845_get_rasterized_height(int offset); +int crtc6845_get_rasterized_width(int offset); + /*Convenience handlers*/ READ_HANDLER( crtc6845_register_0_r ); WRITE_HANDLER( crtc6845_address_0_w ); diff --git a/src/wpc/alvg.c b/src/wpc/alvg.c index 69de15ba3..f95ad9076 100644 --- a/src/wpc/alvg.c +++ b/src/wpc/alvg.c @@ -394,7 +394,7 @@ void UpdateLampCol(void) { Second, it writes the lamp column data first, then the lamp data itself. The other games write the lamp data first, then the lamp column data. - */ WRITE_HANDLER(u14_porta_w) { - if (core_gameData->hw.gameSpecific1) + if (core_gameData->hw.gameSpecific1 == 1) alvglocals.lampColumn = (alvglocals.lampColumn&0x0f01) | ((data & 0x7f)<<1); else { alvglocals.lampColumn = (alvglocals.lampColumn&0x0f80) | (data & 0x7f); @@ -403,7 +403,7 @@ WRITE_HANDLER(u14_porta_w) { //printf("LAMP STROBE(1-7): data = %x\n",data&0x7f); } WRITE_HANDLER(u14_portb_w) { - if (core_gameData->hw.gameSpecific1) + if (core_gameData->hw.gameSpecific1 == 1) alvglocals.lampColumn = (alvglocals.lampColumn&0x00fe) | ((data & 0x0f)<<8) | ((data & 0x10)>>4); else { alvglocals.lampColumn = (alvglocals.lampColumn&0x007f) | ((data & 0x1f)<<7); @@ -413,7 +413,7 @@ WRITE_HANDLER(u14_portb_w) { } WRITE_HANDLER(u14_portc_w) { alvglocals.lampRow = data; - if (core_gameData->hw.gameSpecific1) + if (core_gameData->hw.gameSpecific1 == 1) UpdateLampCol(); //printf("LAMP RETURN: data = %x\n",data); } diff --git a/src/wpc/alvgdmd.c b/src/wpc/alvgdmd.c index 8515b0aa8..64401cb28 100644 --- a/src/wpc/alvgdmd.c +++ b/src/wpc/alvgdmd.c @@ -15,31 +15,30 @@ /*ALVIN G 128x32 DMD Handling*/ /*---------------------------*/ #define DMD32_BANK0 1 -#define DMD32_FIRQFREQ 481 //no idea on this one, just a wild guess /*static vars*/ static UINT8 *dmd32RAM; -static UINT8 level[5] = { 0, 3, 7, 11, 15 }; // brightness mapping 0,25,50,75,100% - -#if defined(VPINMAME) || defined(LIBPINMAME) -extern UINT8 g_raw_gtswpc_dmd[]; -extern UINT32 g_raw_gtswpc_dmdframes; -#endif static struct { struct sndbrdData brdData; - int cmd, planenable, disenable, setsync; + int cmd, plans_enable, disenable; + int selsync; // SELSYNC signal on PCA020A board (Mystery Castle, Pistol Poker). Enable/Disable rasterization VCLOCK. Not present on PCA020 board (Al's Garage Band). + int rowstart, colstart; int vid_page; - int last; + core_tDMDPWMState pwm_state; } dmdlocals; +// Identify PCA020 (Al's Garage Band) vs PCA020A board (Pistol Poker & Mystery Castle) +#define IS_PCA020 (core_gameData->hw.gameSpecific1 == 0) + /*declarations*/ static WRITE_HANDLER(dmd32_bank_w); static READ_HANDLER(dmd32_latch_r); static INTERRUPT_GEN(dmd32_firq); static WRITE_HANDLER(dmd32_data_w); static void dmd32_init(struct sndbrdData *brdData); +static void dmd32_exit(int boardNo); static WRITE_HANDLER(dmd32_ctrl_w); static WRITE_HANDLER(control_w); static READ_HANDLER(control_r); @@ -48,16 +47,10 @@ static READ_HANDLER(port_r); /*Interface*/ const struct sndbrdIntf alvgdmdIntf = { - NULL, dmd32_init, NULL, NULL,NULL, + NULL, dmd32_init, dmd32_exit, NULL,NULL, dmd32_data_w, NULL, dmd32_ctrl_w, NULL, SNDBRD_NOTSOUND }; - -/*Main CPU sends command to DMD*/ -static WRITE_HANDLER(dmd32_data_w) { - dmdlocals.cmd = data; -} - static WRITE_HANDLER(control_w) { UINT16 tmpoffset = offset; @@ -65,50 +58,62 @@ static WRITE_HANDLER(control_w) tmpoffset &= 0xf000; //Remove bits 0-11 (in other words, treat 0x8fff the same as 0x8000!) switch (tmpoffset) { - //Read Main CPU DMD Command + //Read Main CPU DMD Command [PORTIN signal] case 0x8000: LOG(("WARNING! Writing to address 0x8000 - DMD Latch, data=%x!\n",data)); + dmdlocals.selsync = 1; break; - //Send Data to the Main CPU + //Send Data to the Main CPU [PORTOUT signal] case 0x9000: sndbrd_ctrl_cb(dmdlocals.brdData.boardNo, data); + dmdlocals.selsync = 1; break; - //ROM Bankswitching + //ROM Bankswitching [CODEPAGE signal] case 0xa000: dmd32_bank_w(0,data); + dmdlocals.selsync = 1; break; - //ROWSTART Line + //ROWSTART Line [ROWSTART signal] case 0xb000: LOG(("rowstart = %x\n",data)); + dmdlocals.selsync = 1; + if (IS_PCA020) + dmdlocals.rowstart = data & 0x7F; // PCA020: GPLAN0 and GPLAN1 can be freely defined + else + dmdlocals.rowstart = (data & 0x1F) | 0x20; // PCA020A: GPLAN0 is hardwired to 1 and GPLAN1 is hardwired to 0 break; - //COLSTART Line + //COLSTART Line [COLSTART signal] case 0xc000: LOG(("colstart = %x\n",data)); + dmdlocals.selsync = 1; + dmdlocals.colstart = data; break; //NC case 0xd000: case 0xe000: LOG(("writing to not connected address: %x data=%x\n",offset,data)); + dmdlocals.selsync = 1; break; - //SETSYNC Line + //SELSYNC Line [SELSYNC signal on PCA020A, not wired on PCA020] + //SelSync suspend rasterization (stops rasterization clock) if written to, only the address bus is used, so writing to any other address in 0x8000 - 0xE000 will reset it + //it doesn't seem to be used (didn't find a write to it on Pistol Poker & Mystery Castle) + // FIXME remove for hardware without it case 0xf000: - dmdlocals.setsync=data; - LOG(("setsync=%x\n",data)); + LOG(("setsync=%x\n", data)); + dmdlocals.selsync = 0; + printf("%8.5f selsync off\n", timer_get_time()); break; + default: LOG(("WARNING! Reading invalid control address %x\n", offset)); break; } - //Setsync line goes hi for all address except it's own(0xf000) - if(offset != 0xf000) { - dmdlocals.setsync=1; - } } static READ_HANDLER(control_r) @@ -121,18 +126,25 @@ static READ_HANDLER(control_r) //Read Main CPU DMD Command case 0x8000: { int data = dmd32_latch_r(0); + dmdlocals.selsync = 1; return data; } - //While unlikely, a READ to these addresses, can actually trigger control lines, so we call control_w() + case 0x9000: case 0xa000: case 0xb000: case 0xc000: case 0xd000: case 0xe000: + // undefined behavior as data is not set + dmdlocals.selsync = 1; + break; + + // see control_w (data is unused so it has the same effect) case 0xf000: - control_w(offset,0); + dmdlocals.selsync = 0; break; + default: LOG(("WARNING! Reading invalid control address %x\n", offset)); } @@ -167,7 +179,7 @@ static WRITE_HANDLER(port_w) LOG(("writing to port %x data = %x\n",offset,data)); break; /*PORT 3: - P3.0 = PLANENABLE (Plane Enable) + P3.0 = PLANS ENABLE P3.1 = LED P3.2 = INT0 (Not used as output) P3.3 = INT1 (Not used as output) @@ -176,7 +188,7 @@ static WRITE_HANDLER(port_w) P3.6 = /WR (Used Internally only?) P3.7 = /RD (Used Internally only?) */ case 3: - dmdlocals.planenable = data & 0x01; + dmdlocals.plans_enable = data & 0x01; alvg_UpdateSoundLEDS(1,(data&0x02)>>1); dmdlocals.disenable = ((data & 0x20) >> 5); break; @@ -218,29 +230,32 @@ static PORT_WRITE_START( alvgdmd_writeport ) PORT_END // Al's Garage Band Goes On A World Tour +// CPU Clock, directly drives VCLOCK, then divided by 640 (ROWCLOCK = 512 for DOTCLOCK [U26/U21] + 128 for COLLATCH [U23]), then by 256 for INT1 [U22]) MACHINE_DRIVER_START(alvgdmd1) MDRV_CPU_ADD(I8051, 12000000) /*12 Mhz*/ MDRV_CPU_MEMORY(alvgdmd_readmem, alvgdmd_writemem) MDRV_CPU_PORTS(alvgdmd_readport, alvgdmd_writeport) - MDRV_CPU_PERIODIC_INT(dmd32_firq, DMD32_FIRQFREQ) + MDRV_CPU_PERIODIC_INT(dmd32_firq, 12000000./(640.*256.)) MDRV_INTERLEAVE(50) MACHINE_DRIVER_END -// Pistol Poker +// Pistol Poker & Mystery Castle +// CPU Clock, divided by 4 (VCLOCK), then by 640 (ROWCLOCK = 512 for DOTCLOCK [U26/U21] + 128 for COLLATCH [U23]), then by 256 for INT1 [U22]) +// This leads to fairly slow animation, but seems ot match the real pin (f.e. see https://www.youtube.com/watch?v=KY_spGpQC-Q) MACHINE_DRIVER_START(alvgdmd2) MDRV_CPU_ADD(I8051, 12000000) /*12 Mhz*/ MDRV_CPU_MEMORY(alvgdmd_readmem, alvgdmd_writemem) MDRV_CPU_PORTS(alvgdmd_readport, alvgdmd_writeport) - MDRV_CPU_PERIODIC_INT(dmd32_firq, DMD32_FIRQFREQ) + //MDRV_CPU_PERIODIC_INT(dmd32_firq, 12000000./(4.*640.*256.)) + MDRV_CPU_PERIODIC_INT(dmd32_firq, 12000000./(640.*256.)) // HACK: U36 divide main clock by 4 but this leads to slow animation, so skipped here MDRV_INTERLEAVE(50) MACHINE_DRIVER_END - -// HACK: Mystery Castle is clocked at 24MHz instead of 12MHz to enhance DMD animations, otherwise all the same as Pistol Poker MACHINE_DRIVER_START(alvgdmd3) - MDRV_CPU_ADD(I8051, 24000000) /*24 Mhz*/ // retweak? + MDRV_CPU_ADD(I8051, 12000000) /*12 Mhz*/ MDRV_CPU_MEMORY(alvgdmd_readmem, alvgdmd_writemem) MDRV_CPU_PORTS(alvgdmd_readport, alvgdmd_writeport) - MDRV_CPU_PERIODIC_INT(dmd32_firq, DMD32_FIRQFREQ) + //MDRV_CPU_PERIODIC_INT(dmd32_firq, 12000000./(4.*640.*256.)) + MDRV_CPU_PERIODIC_INT(dmd32_firq, 12000000./(640.*256.)) // HACK: U36 divide main clock by 4 but this leads to slow animation, so skipped here MDRV_INTERLEAVE(50) MACHINE_DRIVER_END @@ -251,7 +266,7 @@ MACHINE_DRIVER_START(test8031) MDRV_CPU_ADD(I8051, 12000000) /*12 Mhz*/ MDRV_CPU_MEMORY(alvgdmd_readmem, alvgdmd_writemem) MDRV_CPU_PORTS(alvgdmd_readport, alvgdmd_writeport) - MDRV_CPU_PERIODIC_INT(dmd32_firq, DMD32_FIRQFREQ) + MDRV_CPU_PERIODIC_INT(dmd32_firq, 12000000. / (640. * 256.)) MACHINE_DRIVER_END #endif @@ -259,7 +274,18 @@ static void dmd32_init(struct sndbrdData *brdData) { memset(&dmdlocals, 0, sizeof(dmdlocals)); dmdlocals.brdData = *brdData; dmd32_bank_w(0,0); //Set DMD Bank to 0 - dmdlocals.setsync = 1; //Start Sync @ 1 + dmdlocals.selsync = 1; //Start Sync @ 1 + // Init PWM shading + core_dmd_pwm_init(&dmdlocals.pwm_state, 128, 32, CORE_DMD_PWM_FILTER_ALVG); +} + +static void dmd32_exit(int boardNo) { + core_dmd_pwm_exit(&dmdlocals.pwm_state); +} + +// Main CPU sends command to DMD +static WRITE_HANDLER(dmd32_data_w) { + dmdlocals.cmd = data; } //Send data from Main CPU to latch - Set's the INT0 Line @@ -275,152 +301,37 @@ static READ_HANDLER(dmd32_latch_r) { return dmdlocals.cmd; } -//Pulse the INT1 Line +// PCA020A rasterize 128 rows at once (so 4 frames), with a main VCLOCK of 3MHz (Pistol Poker and Mystery Castle) static INTERRUPT_GEN(dmd32_firq) { - if(dmdlocals.setsync) { - LOG(("INT1 Pulse\n")); - cpu_set_irq_line(dmdlocals.brdData.cpuNo, I8051_INT1_LINE, PULSE_LINE); - } - else { - LOG(("Skipping INT1\n")); - } -} - -#if defined(VPINMAME) || defined(LIBPINMAME) -static const unsigned char lookup[16] = { -0x0, 0x8, 0x4, 0xc, 0x2, 0xa, 0x6, 0xe, -0x1, 0x9, 0x5, 0xd, 0x3, 0xb, 0x7, 0xf, }; - -INLINE UINT8 reverse(UINT8 n) { - // Reverse the top and bottom nibble then swap them. - return (lookup[n & 0x0f] << 4) | lookup[n >> 4]; -} -#endif - -PINMAME_VIDEO_UPDATE(alvgdmd_update) { -#ifdef MAME_DEBUG - static int offset = 0; -#endif - UINT8 *RAM = ((UINT8 *)dmd32RAM); - UINT8 *RAM2; - int ii,jj; - RAM += dmdlocals.vid_page << 11; - RAM2 = RAM + dmdlocals.planenable*0x200; - -#ifdef MAME_DEBUG -// core_textOutf(50,20,1,"offset=%08x", offset); -// memset(coreGlobals.dotCol,0,sizeof(coreGlobals.dotCol)); - - if (!debugger_focus) { -// if (keyboard_pressed_memory_repeat(KEYCODE_Z,2)) -// offset+=1; -// if (keyboard_pressed_memory_repeat(KEYCODE_X,2)) -// offset-=1; -// if (keyboard_pressed_memory_repeat(KEYCODE_C,2)) -// offset=0; -// if (keyboard_pressed_memory_repeat(KEYCODE_V,2)) -// offset+=0x200; -// if (keyboard_pressed_memory_repeat(KEYCODE_B,2)) -// offset-=0x200; -// if (keyboard_pressed_memory_repeat(KEYCODE_N,2)) -// offset=0xc3; - if (keyboard_pressed_memory_repeat(KEYCODE_M,2)) { - dmd32_data_w(0,offset); - dmd32_ctrl_w(0,0); - } + if (!IS_PCA020 && (dmdlocals.selsync == 0)) { // VCLOCK is disabled so FIRQ may not happen [not present on Al's Garage Band Hardware] + LOG(("Skipping INT1\n")); + return; } - RAM += offset; - RAM2 += offset; -#endif - - for (ii = 1; ii <= 32; ii++) { - UINT8 *line = &coreGlobals.dotCol[ii][0]; - for (jj = 0; jj < (128/8); jj++) { - *line++ = ((RAM[0]>>7 & 0x01) | (RAM2[0]>>6 & 0x02)); - *line++ = ((RAM[0]>>6 & 0x01) | (RAM2[0]>>5 & 0x02)); - *line++ = ((RAM[0]>>5 & 0x01) | (RAM2[0]>>4 & 0x02)); - *line++ = ((RAM[0]>>4 & 0x01) | (RAM2[0]>>3 & 0x02)); - *line++ = ((RAM[0]>>3 & 0x01) | (RAM2[0]>>2 & 0x02)); - *line++ = ((RAM[0]>>2 & 0x01) | (RAM2[0]>>1 & 0x02)); - *line++ = ((RAM[0]>>1 & 0x01) | (RAM2[0]>>0 & 0x02)); - *line++ = ((RAM[0]>>0 & 0x01) | (RAM2[0]<<1 & 0x02)); - RAM += 1; RAM2 += 1; - } - *line = 0; - } - video_update_core_dmd(bitmap, cliprect, layout); - return 0; -} - -static void pistol_poker__mystery_castle_dmd(void) { - UINT8 *RAM = ((UINT8 *)dmd32RAM); - int ii,jj; - -#if defined(VPINMAME) || defined(LIBPINMAME) - int i = 0; - g_raw_gtswpc_dmdframes = 4; -#endif - - RAM += dmdlocals.vid_page << 11; - - if (dmdlocals.planenable) { - - for (ii = 1; ii <= 32; ii++) { - UINT8 *line = &coreGlobals.dotCol[ii][0]; - for (jj = 0; jj < (128/8); jj++) { - *line++ = level[((RAM[0] >> 7 & 0x01) + (RAM[0x200] >> 7 & 0x01) + (RAM[0x400] >> 7 & 0x01) + (RAM[0x600] >> 7 & 0x01))]; - *line++ = level[((RAM[0] >> 6 & 0x01) + (RAM[0x200] >> 6 & 0x01) + (RAM[0x400] >> 6 & 0x01) + (RAM[0x600] >> 6 & 0x01))]; - *line++ = level[((RAM[0] >> 5 & 0x01) + (RAM[0x200] >> 5 & 0x01) + (RAM[0x400] >> 5 & 0x01) + (RAM[0x600] >> 5 & 0x01))]; - *line++ = level[((RAM[0] >> 4 & 0x01) + (RAM[0x200] >> 4 & 0x01) + (RAM[0x400] >> 4 & 0x01) + (RAM[0x600] >> 4 & 0x01))]; - *line++ = level[((RAM[0] >> 3 & 0x01) + (RAM[0x200] >> 3 & 0x01) + (RAM[0x400] >> 3 & 0x01) + (RAM[0x600] >> 3 & 0x01))]; - *line++ = level[((RAM[0] >> 2 & 0x01) + (RAM[0x200] >> 2 & 0x01) + (RAM[0x400] >> 2 & 0x01) + (RAM[0x600] >> 2 & 0x01))]; - *line++ = level[((RAM[0] >> 1 & 0x01) + (RAM[0x200] >> 1 & 0x01) + (RAM[0x400] >> 1 & 0x01) + (RAM[0x600] >> 1 & 0x01))]; - *line++ = level[((RAM[0]/*>>0*/&0x01) + (RAM[0x200]/*>>0*/&0x01) + (RAM[0x400]/*>>0*/&0x01) + (RAM[0x600]/*>>0*/&0x01))]; -#if defined(VPINMAME) || defined(LIBPINMAME) - g_raw_gtswpc_dmd[ i] = reverse(RAM[0]); - g_raw_gtswpc_dmd[0x200 + i] = reverse(RAM[0x200]); - g_raw_gtswpc_dmd[0x400 + i] = reverse(RAM[0x400]); - g_raw_gtswpc_dmd[0x600 + i] = reverse(RAM[0x600]); - i++; -#endif - RAM += 1; - } - *line = 0; - } + //static double prev; printf("DMD VBlank %8.5fms => %8.5fHz for 4 frames so %8.5fHz\n", timer_get_time() - prev, 1. / (timer_get_time() - prev), 4. / (timer_get_time() - prev)); prev = timer_get_time(); + //Pulse the INT1 Line (wired to /ROWDATA so pulsed when vertical blanking after a sequence of PWM frames) + LOG(("INT1 Pulse\n")); + cpu_set_irq_line(dmdlocals.brdData.cpuNo, I8051_INT1_LINE, PULSE_LINE); + assert((dmdlocals.colstart & 0x07) == 0); // Lowest 3 bits are actually loaded to the shift register, so it is possible to perform a dot shift, but we don't support it + const UINT8* RAM = (UINT8*)dmd32RAM + (dmdlocals.vid_page << 11) + ((dmdlocals.colstart >> 3) & 0x0F); + const unsigned int plan_mask = dmdlocals.plans_enable ? 0x7F : 0x1F; // either render 4 different frames or 4 times the same + if (dmdlocals.pwm_state.legacyColorization) { + // For backward compatibility regarding colorization, previous implementation: + // - for Al's Garage submited first frame with a weight of 1, and second (same as first if plans_enable = 0) with a weight of 2 => 4 shades (with unbalanced luminance between frames) + // - for PP & MC submited a 16 shade frame made up of the 4 frames (if plans_enable = 0, four time the same frame) => 16 shades (with balanced luminance between frames) + assert(IS_PCA020); // PCA020A doe snot need this and is not supported + core_dmd_submit_frame(&dmdlocals.pwm_state, RAM + (((dmdlocals.rowstart + 0x00) & plan_mask) << 4)); + core_dmd_submit_frame(&dmdlocals.pwm_state, RAM + (((dmdlocals.rowstart + 0x20) & plan_mask) << 4)); + core_dmd_submit_frame(&dmdlocals.pwm_state, RAM + (((dmdlocals.rowstart + 0x20) & plan_mask) << 4)); } else { - for (ii = 1; ii <= 32; ii++) { - UINT8 *line = &coreGlobals.dotCol[ii][0]; - for (jj = 0; jj < (128/8); jj++) { - *line++ = level[(RAM[0] >> 5 & 0x04)]; - *line++ = level[(RAM[0] >> 4 & 0x04)]; - *line++ = level[(RAM[0] >> 3 & 0x04)]; - *line++ = level[(RAM[0] >> 2 & 0x04)]; - *line++ = level[(RAM[0] >> 1 & 0x04)]; - *line++ = level[(RAM[0]/*>>0*/&0x04)]; - *line++ = level[(RAM[0] << 1 & 0x04)]; - *line++ = level[(RAM[0] << 2 & 0x04)]; -#if defined(VPINMAME) || defined(LIBPINMAME) - g_raw_gtswpc_dmd[ i] = - g_raw_gtswpc_dmd[0x200 + i] = - g_raw_gtswpc_dmd[0x400 + i] = - g_raw_gtswpc_dmd[0x600 + i] = reverse(RAM[0]); - i++; -#endif - RAM += 1; - } - *line = 0; - } + core_dmd_submit_frame(&dmdlocals.pwm_state, RAM + (((dmdlocals.rowstart + 0x00) & plan_mask) << 4)); + core_dmd_submit_frame(&dmdlocals.pwm_state, RAM + (((dmdlocals.rowstart + 0x20) & plan_mask) << 4)); + core_dmd_submit_frame(&dmdlocals.pwm_state, RAM + (((dmdlocals.rowstart + 0x40) & plan_mask) << 4)); + core_dmd_submit_frame(&dmdlocals.pwm_state, RAM + (((dmdlocals.rowstart + 0x60) & plan_mask) << 4)); } } -PINMAME_VIDEO_UPDATE(alvgdmd_update2) { - pistol_poker__mystery_castle_dmd(); - video_update_core_dmd(bitmap, cliprect, layout); - return 0; -} - -PINMAME_VIDEO_UPDATE(alvgdmd_update3) { - pistol_poker__mystery_castle_dmd(); - video_update_core_dmd(bitmap, cliprect, layout); - return 0; +PINMAME_VIDEO_UPDATE(alvgdmd_update) { + core_dmd_update_pwm(&dmdlocals.pwm_state); + video_update_core_dmd(bitmap, cliprect, layout); + return 0; } diff --git a/src/wpc/alvgdmd.h b/src/wpc/alvgdmd.h index 95b215ee0..0d080ccf2 100644 --- a/src/wpc/alvgdmd.h +++ b/src/wpc/alvgdmd.h @@ -12,8 +12,6 @@ extern MACHINE_DRIVER_EXTERN(test8031); #endif extern PINMAME_VIDEO_UPDATE(alvgdmd_update); -extern PINMAME_VIDEO_UPDATE(alvgdmd_update2); -extern PINMAME_VIDEO_UPDATE(alvgdmd_update3); /* HELPER MACROS */ diff --git a/src/wpc/alvggames.c b/src/wpc/alvggames.c index 438eb9151..898e67919 100644 --- a/src/wpc/alvggames.c +++ b/src/wpc/alvggames.c @@ -13,16 +13,7 @@ /* Dot-Matrix display (128 x 32) */ static struct core_dispLayout alvg_dispDMD[] = { - {0,0,32,128,CORE_DMD,(genf *)alvgdmd_update,NULL}, {0} -}; -/* Dot-Matrix display (128 x 32) with 16 possible shades */ -static struct core_dispLayout alvg_dispDMD2[] = { - {0,0,32,128,CORE_DMD|CORE_DMDNOAA,(genf *)alvgdmd_update2,NULL}, {0} -}; - -/* Dot-Matrix display (128 x 32) with 16 possible shades inverted frame order*/ -static struct core_dispLayout alvg_dispDMD3[] = { - {0,0,32,128,CORE_DMD|CORE_DMDNOAA,(genf *)alvgdmd_update3,NULL}, {0} + {0,0,32,128,CORE_DMD|CORE_DMDNOAA,(genf *)alvgdmd_update,NULL}, {0} }; /* Alpha Numeric Display (2 X 20 Alpha-Numeric) */ @@ -166,7 +157,7 @@ CORE_CLONEDEFNV(usafoota,usafootb,"U.S.A. Football (R01u)",1992,"Alvin G",mALVGS /*------------------------------------------------------------------- / Mystery Castle (AG08) /-------------------------------------------------------------------*/ -INITGAME2(mystcast, DMD3, FLIP78, 3/*?*/, SNDBRD_ALVGS2, SNDBRD_ALVGDMD, 0) +INITGAME2(mystcast, DMD, FLIP78, 3/*?*/, SNDBRD_ALVGS2, SNDBRD_ALVGDMD, 2) ALVGROMSTART(mystcast, "mcastle.cpu", CRC(936e6799) SHA1(aa29fb5f12f34c695d1556232744f65cd576a2b1)) ALVGS_SOUNDROM( "mcastle.102", CRC(752822d0) SHA1(36461ef03cac5aefa0c03dfdc63c3d294a3b9c09), "mcastle.sr0", CRC(0855cc73) SHA1(c46e08432bcff24594c33171f20669ba63828931), @@ -179,7 +170,7 @@ ALVG_ROMEND CORE_GAMEDEFNV(mystcast,"Mystery Castle (R02)",1993,"Alvin G",mALVGS2DMD3,0) // R03 has game ID EPC081 -INITGAME2(mystcasa, DMD3, FLIP78, 3/*?*/, SNDBRD_ALVGS2, SNDBRD_ALVGDMD, 0) +INITGAME2(mystcasa, DMD, FLIP78, 3/*?*/, SNDBRD_ALVGS2, SNDBRD_ALVGDMD, 2) ALVGROMSTART(mystcasa, "cpu_103.bin", CRC(70ab8ece) SHA1(2bf8cd042450968b7500552419a9af5df2589c13)) ALVGS_SOUNDROM( "mcastle.103", CRC(bd4849ac) SHA1(f477ea369539a65c0960be1f1c3b4c5503dd6b75), "mcastle.sr0", CRC(0855cc73) SHA1(c46e08432bcff24594c33171f20669ba63828931), @@ -195,7 +186,7 @@ CORE_CLONEDEFNV(mystcasa,mystcast,"Mystery Castle (R03)",199?,"Alvin G",mALVGS2D /*------------------------------------------------------------------- / Pistol Poker (AG10) /-------------------------------------------------------------------*/ -INITGAME2(pstlpkr, DMD2, FLIP78, 3/*?*/, SNDBRD_ALVGS2, SNDBRD_ALVGDMD, 1) +INITGAME2(pstlpkr, DMD, FLIP78, 3/*?*/, SNDBRD_ALVGS2, SNDBRD_ALVGDMD, 1) ALVGROMSTART(pstlpkr, "p_peteu2.512", CRC(490a1e2d) SHA1(907dd858ed948681e7366a64a0e7537ebe301d6b)) ALVGS_SOUNDROM( "p_pu102.512" , CRC(b8fb806e) SHA1(c2dc19820ea22bbcf5808db2fb4be76a4033d6ea), "p_parom0.c20", CRC(99986af2) SHA1(52fa7d2979f7f2d6d65ab6d4f7bbfbed16303991), @@ -208,7 +199,7 @@ ALVGDMD_ROM( "p_peteu4.512", CRC(caa0cabd) SHA1(caff6ca4a9cce4e3d846502696c883 ALVG_ROMEND CORE_GAMEDEFNV(pstlpkr,"Pistol Poker (R02)",1993,"Alvin G",mALVGS2DMD2,0) -INITGAME2(pstlpkr1, DMD2, FLIP78, 3/*?*/, SNDBRD_ALVGS2, SNDBRD_ALVGDMD, 1) +INITGAME2(pstlpkr1, DMD, FLIP78, 3/*?*/, SNDBRD_ALVGS2, SNDBRD_ALVGDMD, 1) ALVGROMSTART(pstlpkr1, "u2-ddff.512", CRC(83fa0595) SHA1(d6ebb0e63fd964ccaee3979a7fc13b6adf7b837c)) ALVGS_SOUNDROM( "p_pu102.512" , CRC(b8fb806e) SHA1(c2dc19820ea22bbcf5808db2fb4be76a4033d6ea), "p_parom0.c20", CRC(99986af2) SHA1(52fa7d2979f7f2d6d65ab6d4f7bbfbed16303991), diff --git a/src/wpc/core.c b/src/wpc/core.c index 6decb61a2..ead904083 100644 --- a/src/wpc/core.c +++ b/src/wpc/core.c @@ -54,9 +54,9 @@ static UINT32 raw_dmdoffs = 0; static UINT8 has_DMD_Video = 0; - #include "gts3dmd.h" - UINT8 g_raw_gtswpc_dmd[GTS3DMD_FRAMES*0x200]; - UINT32 g_raw_gtswpc_dmdframes = 0; +#define CORE_MAX_RAW_DMD_FRAMES 5 + UINT8 raw_dmd_frames[CORE_MAX_RAW_DMD_FRAMES * DMD_MAXX * DMD_MAXY / 8]; + UINT32 raw_dmd_frame_count = 0; UINT8 g_needs_DMD_update = 1; #endif @@ -854,7 +854,7 @@ void video_update_core_dmd(struct mame_bitmap *bitmap, const struct rectangle *c int ii, jj; // prepare all brightness & color/palette tables for mappings from internal DMD representation: - const int shade_16_enabled = (core_gameData->gen & (GEN_SAM|GEN_SPA|GEN_ALVG_DMD2|GEN_GTS3)) != 0; + const int shade_16_enabled = (core_gameData->gen & (GEN_SAM|GEN_SPA|GEN_ALVG|GEN_ALVG_DMD2|GEN_GTS3)) != 0; #if defined(VPINMAME) || defined(LIBPINMAME) @@ -940,7 +940,8 @@ 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; 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++) { @@ -948,7 +949,7 @@ void video_update_core_dmd(struct mame_bitmap *bitmap, const struct rectangle *c coreGlobals.dotCol[ii][layout->length] = 0; if (ii > 0) { for (jj = 0; jj < layout->length; jj++) { - const UINT8 col = coreGlobals.dotCol[ii][jj]; + const UINT8 col = coreGlobals.dotCol[ii][jj] >> shift; #if defined(VPINMAME) || defined(LIBPINMAME) const int offs = (ii-1)*layout->length + jj; currbuffer[offs] = col; @@ -963,14 +964,14 @@ void video_update_core_dmd(struct mame_bitmap *bitmap, const struct rectangle *c #endif *line++ = shade_16_enabled ? dmdColor[col+63] : dmdColor[col]; if (locals.displaySize > 1 && jj < layout->length-1) - *line++ = noaa ? 0 : aaColor[col + coreGlobals.dotCol[ii][jj+1]]; + *line++ = noaa ? 0 : aaColor[col + (coreGlobals.dotCol[ii][jj+1] >> shift)]; } } if (locals.displaySize > 1) { - int col1 = coreGlobals.dotCol[ii][0] + coreGlobals.dotCol[ii+1][0]; + int col1 = (coreGlobals.dotCol[ii][0] >> shift) + (coreGlobals.dotCol[ii+1][0] >> shift); line = (*lines++) + (layout->left*locals.displaySize); for (jj = 0; jj < layout->length; jj++) { - int col2 = coreGlobals.dotCol[ii][jj+1] + coreGlobals.dotCol[ii+1][jj+1]; + int col2 = (coreGlobals.dotCol[ii][jj+1] >> shift) + (coreGlobals.dotCol[ii+1][jj+1] >> shift); *line++ = noaa ? 0 : aaColor[col1]; if (jj < layout->length-1) *line++ = noaa ? 0 : aaColor[2*(col1 + col2)/5]; @@ -987,12 +988,12 @@ void video_update_core_dmd(struct mame_bitmap *bitmap, const struct rectangle *c if (strncasecmp(Machine->gamedrv->name, "snspare", 7) == 0) { if (layout->top != 0) - renderDMDFrame(core_gameData->gen, layout->length, layout->start, currbuffer, g_fDumpFrames, Machine->gamedrv->name, g_raw_gtswpc_dmdframes, g_raw_gtswpc_dmd); + renderDMDFrame(core_gameData->gen, layout->length, layout->start, currbuffer, g_fDumpFrames, Machine->gamedrv->name, raw_dmd_frame_count, raw_dmd_frames); else - render2ndDMDFrame(core_gameData->gen, layout->length, layout->start, currbuffer, g_fDumpFrames, Machine->gamedrv->name, g_raw_gtswpc_dmdframes, g_raw_gtswpc_dmd); + render2ndDMDFrame(core_gameData->gen, layout->length, layout->start, currbuffer, g_fDumpFrames, Machine->gamedrv->name, raw_dmd_frame_count, raw_dmd_frames); } else { - renderDMDFrame(core_gameData->gen, layout->length, layout->start, currbuffer, g_fDumpFrames, Machine->gamedrv->name, g_raw_gtswpc_dmdframes, g_raw_gtswpc_dmd); - render2ndDMDFrame(core_gameData->gen, layout->length, layout->start, currbuffer, g_fDumpFrames, Machine->gamedrv->name, g_raw_gtswpc_dmdframes, g_raw_gtswpc_dmd); + renderDMDFrame(core_gameData->gen, layout->length, layout->start, currbuffer, g_fDumpFrames, Machine->gamedrv->name, raw_dmd_frame_count, raw_dmd_frames); + render2ndDMDFrame(core_gameData->gen, layout->length, layout->start, currbuffer, g_fDumpFrames, Machine->gamedrv->name, raw_dmd_frame_count, raw_dmd_frames); } } @@ -1018,7 +1019,7 @@ void video_update_core_dmd(struct mame_bitmap *bitmap, const struct rectangle *c strcpy_s(ptr + 1, 11, "DmdDump\\"); strcat_s(DumpFilename, MAX_PATH, Machine->gamedrv->name); - if (g_raw_gtswpc_dmdframes != 0) { + if (raw_dmd_frame_count != 0) { FILE* fr; char RawFilename[MAX_PATH]; strcpy_s(RawFilename, MAX_PATH, DumpFilename); @@ -1039,13 +1040,13 @@ void video_update_core_dmd(struct mame_bitmap *bitmap, const struct rectangle *c fputc(0x01, fr); fputc(layout->length, fr); fputc(layout->start, fr); - fputc(g_raw_gtswpc_dmdframes, fr); + fputc(raw_dmd_frame_count, fr); } } if(fr) { fwrite(&tick, 1, 4, fr); - fwrite(g_raw_gtswpc_dmd, 1, (layout->length * layout->start / 8 * g_raw_gtswpc_dmdframes), fr); + fwrite(raw_dmd_frames, 1, (layout->length * layout->start / 8 * raw_dmd_frame_count), fr); fclose(fr); } } @@ -1069,7 +1070,7 @@ void video_update_core_dmd(struct mame_bitmap *bitmap, const struct rectangle *c } } - g_raw_gtswpc_dmdframes = 0; + raw_dmd_frame_count = 0; // swap buffers if (currbuffer == buffer1) { @@ -2297,7 +2298,7 @@ static MACHINE_STOP(core) { raw_dmdoffs = 0; has_DMD_Video = 0; - g_raw_gtswpc_dmdframes = 0; + raw_dmd_frame_count = 0; g_needs_DMD_update = 1; #endif @@ -2942,6 +2943,202 @@ void core_write_pwm_output_lamp_matrix(int startIndex, UINT8 columns, UINT8 rows } } + +// +// +// + +/* Generic DMD PWM integration. + + All hardware so far (Alvin G, Data East, Sega/Stern Whitestar, GTS3, WPC, SAM, Capcom, Sleic (Spain), Spinball) + creates shades using PWM on a plasma or LED display (later Stern games). Therefore, PinMame offers access to the + raw high frequency frames (f.e. for coloring) or to a PWM integrated view (f.e. for rendering). Sadly some colorization + plugins used the legacy preshaded frames to identify and color frame, so access to these legacy shades is also provided + for backward compatibility. + + Unlike lamps which have varying strobe periods, DMD are rasterized at a fixed frequency. Therefore, the implementation + simply stores the frames at this frequency and apply a (simple) low pass filter to account for the eye flicker-fusion limit. + The integration period (number of frame to store) and cut-off frequency are selected from the observed PWM pattern of + common hardware: WPC is 122/3 = 40.7Hz, GTS3 is 376/10 = 37.6Hz, so an overall plasma inertia & flicker fusion period + of around 40ms (25Hz). + + Filters are computed using the following script in GNU Octave: + +pkg load signal + +fc = 15; % Cut-off frequency (Hz), PWM patterns/frequency suggests something below 35Hz +int_factor = 65000; % Integer arithmetic fixed point scaling + + +% Data East DMD 32 +n = 16 +fs = 2*236.68; % Sampling rate (Hz) = DMD VBlank +data=[repmat([0;1],100,1), repmat([0;1;0;0],50,1), repmat([0;1;0;0;0;0;0;1],25,1)]; + +% GTS3 +n = 24 +fs = 376; % Sampling rate (Hz) = DMD VBlank +data=[repmat([0;0;0;0;0;0;0;1],30,1), repmat([0;0;0;0;0;1;1;1],30,1)]; + +% WPC +n = 8 +fs = 122.1; % Sampling rate (Hz) = DMD VBlank +data=[repmat([0;0;1],100,1),repmat([0;1;1],100,1)]; + +% Alvin G +n = 8 +fs = 293.; % Sampling rate (Hz) = DMD VBlank +data=[repmat([0;0;0;1],100,1),repmat([0;1;0;1],100,1),repmat([0;0;1;1],100,1),repmat([0;1;1;1],100,1)]; + +b = fir1(n, fc/(fs/2)); +b = round(int_factor * b) / int_factor + +filtered = filter(b,1,data); + +clf +x = (0:(max(size(data))-1)) / fs; +filtered = round(255*filtered) +for i_plot = 1:size(data,2) + subplot ( columns ( filtered ), 1, i_plot) + stairs(x, filtered(:,i_plot),";PWM Pattern;") +endfor + +fprintf('n=%i (suggested n=%i from fs/fc)\n', n+1, round(fs/fc)); +fprintf('filter=['); +fprintf('%i, ', int_factor * b); +fprintf(']\n'); +fprintf('sum=%i\n', sum(int_factor * b)); +*/ + +// TODO for the time being, DMD are always updated from core/updateDisplay, running at a fixed 60Hz. This may lead to stutters +// as it is not aligned with real display refresh rate. We should update DMD on request but this needs to make these functions +// thread safe. + +void core_dmd_pwm_init(core_tDMDPWMState* dmd_state, const int width, const int height, const int filter) { + dmd_state->width = width; + dmd_state->height = height; + dmd_state->rawFrameSize = width * height / 8; + assert(dmd_state->rawFrameSize * 8 == width * height); + 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) + 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_sum = 60000; + dmd_state->fir_size = dmd_state->nFrames = sizeof(fir_colorization_2_frames) / sizeof(UINT16); + } else { + static const UINT16 fir_473_15[] = { 460, 765, 1614, 2962, 4619, 6291, 7648, 8408, 8409, 7648, 6291, 4619, 2962, 1614, 765, 460 }; + dmd_state->fir_weights = fir_473_15; + dmd_state->fir_sum = 65535; + dmd_state->fir_size = dmd_state->nFrames = sizeof(fir_473_15) / sizeof(UINT16); + } + break; + case CORE_DMD_PWM_FILTER_GTS3: // GTS3: 376Hz refresh rate / 15Hz low pass filter / 1,3,6,8,10 frames PWM pattern + { + static const UINT16 fir_376_15[] = { 233, 321, 544, 921, 1452, 2115, 2868, 3651, 4396, 5032, 5495, 5739, 5740, 5495, 5032, 4396, 3651, 2868, 2115, 1452, 921, 544, 321, 233 }; + dmd_state->fir_weights = fir_376_15; + dmd_state->fir_sum = 65535; + dmd_state->fir_size = dmd_state->nFrames = sizeof(fir_376_15) / sizeof(UINT16); + } + break; + case CORE_DMD_PWM_FILTER_WPC: // WPC: 122Hz refresh rate / 15Hz low pass filter / 3 frames PWM pattern (there seems to be longer PWM patterns, see T2 gun animation sequence) + { + static const UINT16 fir_122_15[] = { 269, 2570, 10580, 19348, 19349, 10580, 2570, 269 }; + dmd_state->fir_weights = fir_122_15; + dmd_state->fir_sum = 65535; + dmd_state->fir_size = dmd_state->nFrames = sizeof(fir_122_15) / sizeof(UINT16); + } + break; + case CORE_DMD_PWM_FILTER_ALVG: // Alvin G.: 293Hz refresh rate / 15Hz low pass filter / 4 frames PWM pattern + if (dmd_state->legacyColorization) + { + // Al's Garage Band previous implementation would weight the first rasterized frame half less 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_sum = 60000; + dmd_state->fir_size = dmd_state->nFrames = sizeof(fir_colorization_2_frames) / sizeof(UINT16); + } else { + static const UINT16 fir_293_15[] = { 1258, 4169, 10900, 16440, 16440, 10900, 4169, 1258 }; + dmd_state->fir_weights = fir_293_15; + dmd_state->fir_sum = 65534; + dmd_state->fir_size = dmd_state->nFrames = sizeof(fir_293_15) / sizeof(UINT16); + } + break; + default: + assert(0); // Unsupported filter + } + dmd_state->rawFrames = malloc(dmd_state->nFrames * dmd_state->rawFrameSize); + dmd_state->shadedFrame = malloc(dmd_state->width * dmd_state->height * sizeof(UINT16)); + assert(dmd_state->rawFrames != NULL && dmd_state->shadedFrame != NULL); + memset(dmd_state->rawFrames, 0, dmd_state->nFrames * dmd_state->rawFrameSize); + memset(dmd_state->shadedFrame, 0, dmd_state->width * dmd_state->height * sizeof(UINT16)); + dmd_state->nextFrame = 0; +} + +void core_dmd_pwm_exit(core_tDMDPWMState* dmd_state) { + free(dmd_state->rawFrames); + dmd_state->rawFrames = NULL; + free(dmd_state->shadedFrame); + dmd_state->shadedFrame = NULL; +} + +void core_dmd_submit_frame(core_tDMDPWMState* dmd_state, const UINT8* frame) { + memcpy(dmd_state->rawFrames + dmd_state->nextFrame * dmd_state->rawFrameSize, frame, dmd_state->rawFrameSize); + dmd_state->nextFrame = (dmd_state->nextFrame + 1) % dmd_state->nFrames; + dmd_state->frame_index++; +} + +void core_dmd_update_pwm(core_tDMDPWMState* dmd_state) { + int ii, jj, kk; + + // Store raw frames for colorization (TODO strangely, this is only done for GTS3, WPC and Alvin G => cleanup & extend to all ? at least DE and Whitestar ?) + #if defined(VPINMAME) || defined(LIBPINMAME) + if (core_gameData->gen & (GEN_ALLWPC | GEN_GTS3 | GEN_ALVG | GEN_ALVG_DMD2)) { + raw_dmd_frame_count = dmd_state->nFrames > CORE_MAX_RAW_DMD_FRAMES ? CORE_MAX_RAW_DMD_FRAMES : dmd_state->nFrames; + UINT8* rawData = &raw_dmd_frames[0]; + for (int frame = 0; frame < (int)raw_dmd_frame_count; frame++) { + UINT8* frameData = dmd_state->rawFrames + ((dmd_state->nextFrame + (dmd_state->nFrames - 1) + (dmd_state->nFrames - frame)) % dmd_state->nFrames) * dmd_state->rawFrameSize; + for (int jj = 0; jj < dmd_state->rawFrameSize; jj++) { + *rawData = dmd_state->revByte ? (*frameData++) : core_revbyte(*frameData++); + rawData++; + } + } + } + #endif + + // Apply low pass filter over stored frames + memset(dmd_state->shadedFrame, 0, dmd_state->width * dmd_state->height * sizeof(UINT16)); + for (ii = 0; ii < dmd_state->fir_size; ii++) { + const UINT16 frame_weight = dmd_state->fir_weights[ii]; + UINT16* line = dmd_state->shadedFrame; + UINT8* frameData = dmd_state->rawFrames + ((dmd_state->nextFrame + (dmd_state->nFrames - 1) + (dmd_state->nFrames - ii)) % dmd_state->nFrames) * dmd_state->rawFrameSize; + for (jj = 0; jj < dmd_state->rawFrameSize; jj++) { + UINT8 data = *frameData++; + if (dmd_state->revByte) { + for (kk = 0; kk < 8; kk++, data >>= 1, line++) + if (data & 0x01) (*line) += frame_weight; + } else { + for (kk = 0; kk < 8; kk++, data <<= 1, line++) + if (data & 0x80) (*line) += frame_weight; + } + } + } + + // Scale down to final shades + UINT16* line = dmd_state->shadedFrame; + for (ii = 1; ii <= dmd_state->height; ii++) + for (jj = 0; jj < dmd_state->width; jj++) { + unsigned int data = (unsigned int) (*line++); // unsigned int precision is needed here + coreGlobals.dotCol[ii][jj] = (UINT8)((255u * data) / dmd_state->fir_sum); + } +} + + // // // diff --git a/src/wpc/core.h b/src/wpc/core.h index b19ad8a27..4dbf41614 100644 --- a/src/wpc/core.h +++ b/src/wpc/core.h @@ -598,6 +598,31 @@ extern void core_write_masked_pwm_output_8b(int startIndex, UINT8 bitStates, UIN extern void core_write_pwm_output_lamp_matrix(int startIndex, UINT8 columns, UINT8 rows, int nCols); INLINE void core_zero_cross(void) { coreGlobals.lastACZeroCrossTimeStamp = timer_get_time(); } +/*-- DMD PWM integration --*/ +typedef struct { + int width; // DMD width + int height; // DMD height + int revByte; // Is bitset reversed ? + int legacyColorization; // Is legacy coloriation backward compatibility enabled ? + int rawFrameSize; // Size of a raw DMD frame in bytes (width * height / 8) + UINT8* rawFrames; // Buffer for raw frames + UINT16* shadedFrame; // Shaded frame computed from raw frames + int nextFrame; // Position in circular buffer to store next raw frame + int nFrames; // Number of frames to store and consider to create shades (depends on hardware refresh frequency and used PWM patterns) + int fir_size; // Selected filter (depends on hardware refresh frequency and number of stored frames) + UINT16* fir_weights; // Selected filter (depends on hardware refresh frequency and number of stored frames) + 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_ALVG 3 +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); +extern void core_dmd_update_pwm(core_tDMDPWMState* dmd_state); + extern void core_sound_throttle_adj(int sIn, int *sOut, int buffersize, double samplerate); /*-- nvram handling --*/ diff --git a/src/wpc/dedmd.c b/src/wpc/dedmd.c index fa75dfec9..cbd866705 100644 --- a/src/wpc/dedmd.c +++ b/src/wpc/dedmd.c @@ -13,12 +13,14 @@ static struct { struct sndbrdData brdData; int cmd, ncmd, busy, status, ctrl, bank; - UINT32 *framedata; // dmd16 stuff + UINT32* framedata; UINT32 hv5408, hv5408s, hv5308, hv5308s, hv5222, lasthv5222; int blnk, rowdata, rowclk, frame; - int laststat; + // dmd32 frame shading + int frame_counter; + core_tDMDPWMState pwm_state; } dmdlocals; static UINT16 *dmd64RAM; @@ -32,15 +34,13 @@ static READ_HANDLER(dmd_busy_r) { return dmdlocals.busy; } /*Data East, Sega, Stern 128x32 DMD Handling*/ /*------------------------------------------*/ #define DMD32_BANK0 2 -#define DMD32_FIRQFREQ_HACK 86.20689655172414 // real DE HW 78.07 (measured on LW3), Whitestar 77.77, but this leads to (at least?) LW3 and R&B and SW glitching, thus use the old/working 80Hz * the changes to IRQ freq in Sys11 for these (and Aaron Spelling & Michael Jordan, //!! although (at least) these 2 show the display version screen from time to time) -#define DMD32_FIRQFREQ_DE 78.07 // real DE HW (measured on LW3) -#define DMD32_FIRQFREQ_SE 77.77 // real Whitestar HW static WRITE_HANDLER(dmd32_ctrl_w); static void dmd32_init(struct sndbrdData *brdData); +static void dmd32_exit(int boardNo); const struct sndbrdIntf dedmd32Intf = { - NULL, dmd32_init, NULL, NULL,NULL, + NULL, dmd32_init, dmd32_exit, NULL,NULL, dmd_data_w, dmd_busy_r, dmd32_ctrl_w, dmd_status_r, SNDBRD_NOTSOUND }; @@ -71,26 +71,36 @@ static MEMORY_WRITE_START(dmd32_writemem) { 0x4001, 0xffff, MWA_NOP }, MEMORY_END -MACHINE_DRIVER_START(de_dmd32_hack) +MACHINE_DRIVER_START(de_dmd32) // Board Part 520-5055-00 MDRV_CPU_ADD(M6809, 2000000) // 8000000/4 MDRV_CPU_MEMORY(dmd32_readmem, dmd32_writemem) - MDRV_CPU_PERIODIC_INT(dmd32_firq, DMD32_FIRQFREQ_HACK) MDRV_INTERLEAVE(50) MACHINE_DRIVER_END -MACHINE_DRIVER_START(de_dmd32) +MACHINE_DRIVER_START(se_dmd32) // Board Part 520-5055-01 to 520-5055-03 MDRV_CPU_ADD(M6809, 2000000) // 8000000/4 MDRV_CPU_MEMORY(dmd32_readmem, dmd32_writemem) - MDRV_CPU_PERIODIC_INT(dmd32_firq, DMD32_FIRQFREQ_DE) MDRV_INTERLEAVE(50) MACHINE_DRIVER_END -MACHINE_DRIVER_START(se_dmd32) - MDRV_CPU_ADD(M6809, 2000000) // 8000000/4 - MDRV_CPU_MEMORY(dmd32_readmem, dmd32_writemem) - MDRV_CPU_PERIODIC_INT(dmd32_firq, DMD32_FIRQFREQ_SE) - MDRV_INTERLEAVE(50) -MACHINE_DRIVER_END +static void dmd32_vblank(int which) { + //static double prev; printf("DMD VBlank %8.5fms => %8.5fHz for 2 frames so %8.5fHz\n", timer_get_time() - prev, 1. / (timer_get_time() - prev), 2. / (timer_get_time() - prev)); prev = timer_get_time(); + // Store 2 next rasterized frame, as the CRTC is setup to render 2 contiguous full frames for each VBLANK + assert(crtc6845_get_rasterized_height(0) == 64); + core_dmd_submit_frame(&dmdlocals.pwm_state, ((UINT8*)dmd32RAM) + ((crtc6845_start_address_r(0) & 0x0100) << 2)); + // 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 this here for backward compatibility by submitting + // the first frame twice. + if (dmdlocals.pwm_state.legacyColorization) + core_dmd_submit_frame(&dmdlocals.pwm_state, ((UINT8*)dmd32RAM) + ((crtc6845_start_address_r(0) & 0x0100) << 2)); + core_dmd_submit_frame(&dmdlocals.pwm_state, ((UINT8*)dmd32RAM) + ((crtc6845_start_address_r(0) & 0x0100) << 2) + 0x200); + // FIRQ is generated by the custom PAL16R4 chip. It is guessed to be a divider around HSYNC to perform PWM shading as it nearly matches real hardware measures (so every 6 rasterized frames) + // This leads to 78.89Hz (473,37Hz core rasterization FPS, /2 to give CRTC6845 VSYNC, /3 by PAL to generate FIRQ) + // Previous implementation used real hardware measures of 78.07 for Data East (measured on LW3), and 77.77 for Whitestar, and a hacked 86.20689655172414 Hz to account for glitches for LW3/AS/R&B/SW. + dmdlocals.frame_counter = (dmdlocals.frame_counter + 1) % 3; + if (dmdlocals.frame_counter == 0) + cpu_set_irq_line(dmdlocals.brdData.cpuNo, M6809_FIRQ_LINE, HOLD_LINE); +} static void dmd32_init(struct sndbrdData *brdData) { memset(&dmdlocals, 0, sizeof(dmdlocals)); @@ -99,8 +109,16 @@ static void dmd32_init(struct sndbrdData *brdData) { /* copy last 16K of ROM into last 16K of CPU region*/ memcpy(memory_region(DE_DMD32CPUREGION) + 0x8000, memory_region(DE_DMD32ROMREGION) + memory_region_length(DE_DMD32ROMREGION)-0x8000,0x8000); - //Init 6845 + // Init 6845 crtc6845_init(0); + crtc6845_set_vsync(0, 2000000 /* 8000000/4 from 6809 E clock output */, dmd32_vblank); + // Init PWM shading + dmdlocals.pwm_state.legacyColorization = 1; // Needed to avoid breaking colorization, but breaks DMD shading + core_dmd_pwm_init(&dmdlocals.pwm_state, 128, 32, CORE_DMD_PWM_FILTER_DE); +} + +static void dmd32_exit(int boardNo) { + core_dmd_pwm_exit(&dmdlocals.pwm_state); } static WRITE_HANDLER(dmd32_ctrl_w) { @@ -137,54 +155,32 @@ static INTERRUPT_GEN(dmd32_firq) { } PINMAME_VIDEO_UPDATE(dedmd32_update) { - const UINT8 *RAM = ((UINT8 *)dmd32RAM) + ((crtc6845_start_address_r(0) & 0x0100)<<2); - const UINT8 *RAM2 = RAM + 0x200; - int ii; - -#ifdef PROC_SUPPORT + #ifdef PROC_SUPPORT if (coreGlobals.p_rocEn) { - /* Whitestar games drive 4 colors using 2 subframes, which the P-ROC - has 4 subframes for up to 16 colors. Experimentation has showed - using P-ROC subframe 2 and 3 provides a pretty good color match. */ - const int procSubFrame0 = 2; - const int procSubFrame1 = 3; - - /* Start with an empty frame buffer */ - procClearDMD(); - - /* Fill the P-ROC subframes from the video RAM */ - procFillDMDSubFrame(procSubFrame0, RAM, 0x200); - procFillDMDSubFrame(procSubFrame1, RAM2, 0x200); - - /* Each byte is reversed in the video RAM relative to the bit order the P-ROC - expects. So reverse each byte. */ - procReverseSubFrameBytes(procSubFrame0); - procReverseSubFrameBytes(procSubFrame1); - procUpdateDMD(); - /* Don't explicitly update the DMD from here. The P-ROC code - will update after the next DMD event. */ + /* Whitestar games drive 4 colors using 2 subframes, which the P-ROC + has 4 subframes for up to 16 colors. Experimentation has showed + using P-ROC subframe 2 and 3 provides a pretty good color match. */ + const int procSubFrame0 = 2; + const int procSubFrame1 = 3; + + /* Start with an empty frame buffer */ + procClearDMD(); + + /* Fill the P-ROC subframes from the video RAM */ + const UINT8* RAM = ((UINT8*)dmd32RAM) + ((crtc6845_start_address_r(0) & 0x0100) << 2); + procFillDMDSubFrame(procSubFrame0, RAM , 0x200); + procFillDMDSubFrame(procSubFrame1, RAM + 0x200, 0x200); + + /* Each byte is reversed in the video RAM relative to the bit order the P-ROC + expects. So reverse each byte. */ + procReverseSubFrameBytes(procSubFrame0); + procReverseSubFrameBytes(procSubFrame1); + procUpdateDMD(); + /* Don't explicitly update the DMD from here. The P-ROC code + will update after the next DMD event. */ } -#endif - - for (ii = 1; ii <= 32; ii++) { - UINT8 *line = &coreGlobals.dotCol[ii][0]; - int jj; - for (jj = 0; jj < (128/8); jj++) { - const UINT8 intens1 = 2*(*RAM & 0x55) + (*RAM2 & 0x55); - const UINT8 intens2 = (*RAM & 0xaa) + (*RAM2 & 0xaa)/2; - *line++ = (intens2>>6) & 0x03; - *line++ = (intens1>>6) & 0x03; - *line++ = (intens2>>4) & 0x03; - *line++ = (intens1>>4) & 0x03; - *line++ = (intens2>>2) & 0x03; - *line++ = (intens1>>2) & 0x03; - *line++ = (intens2) & 0x03; - *line++ = (intens1) & 0x03; - RAM++; RAM2++; - } - *line = 0; - } - + #endif + core_dmd_update_pwm(&dmdlocals.pwm_state); video_update_core_dmd(bitmap, cliprect, layout); return 0; } @@ -224,7 +220,7 @@ static MEMORY_WRITE16_START(dmd64_writemem) { 0x00c00020, 0x00c00021, dmd64_status_w},/* Set the Status Line*/ MEMORY_END -MACHINE_DRIVER_START(de_dmd64) +MACHINE_DRIVER_START(de_dmd64) // Board part 520-5075-00 MDRV_CPU_ADD(M68000, 12000000) // schematics MDRV_CPU_MEMORY(dmd64_readmem, dmd64_writemem) MDRV_CPU_PERIODIC_INT(dmd64_irq2, DMD64_IRQ2FREQ) @@ -305,10 +301,8 @@ 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 2000 +// 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 @@ -327,7 +321,7 @@ static READ_HANDLER(dmd16_port_r); static WRITE_HANDLER(dmd16_port_w); static MEMORY_READ_START(dmd16_readmem) - { 0x0000, 0x3fff, MRA_ROM }, /* Z80 ROM CODE*/ + { 0x0000, 0x3fff, MRA_ROM }, /* Z80 ROM CODE*/ { 0x4000, 0x7fff, MRA_BANKNO(DMD16_BANK0) }, /* ROM BANK*/ { 0x8000, 0x9fff, MRA_RAM }, MEMORY_END @@ -346,7 +340,7 @@ static PORT_WRITE_START(dmd16_writeport) { 0x00, 0xff, dmd16_port_w }, PORT_END -MACHINE_DRIVER_START(de_dmd16) +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) diff --git a/src/wpc/dedmd.h b/src/wpc/dedmd.h index 5afe02243..819c38fc1 100644 --- a/src/wpc/dedmd.h +++ b/src/wpc/dedmd.h @@ -8,7 +8,6 @@ #define DE_DMD32CPUNO 2 #define DE_DMD32CPUREGION (REGION_CPU1 + DE_DMD32CPUNO) #define DE_DMD32ROMREGION (REGION_GFX1 + DE_DMD32CPUNO) -extern MACHINE_DRIVER_EXTERN(de_dmd32_hack); extern MACHINE_DRIVER_EXTERN(de_dmd32); extern MACHINE_DRIVER_EXTERN(se_dmd32); extern PINMAME_VIDEO_UPDATE(dedmd32_update); diff --git a/src/wpc/degames.c b/src/wpc/degames.c index f7e460745..3a709c674 100644 --- a/src/wpc/degames.c +++ b/src/wpc/degames.c @@ -706,7 +706,7 @@ DE2S_SOUNDROM022( "lw3u7.dat" ,CRC(ba845ac3) SHA1(bb50413ace1885870cb3817edae "lw3u21.dat" ,CRC(82bed051) SHA1(49ddc4190762d9b473fda270e0d6d88a4422d5d7)) DE_ROMEND #define input_ports_lw3 input_ports_des11 -CORE_GAMEDEF(lw3,208,"Lethal Weapon 3 (2.08)",1992,"Data East",de_mDEDMD32S2A_hack,0) +CORE_GAMEDEF(lw3,208,"Lethal Weapon 3 (2.08)",1992,"Data East",de_mDEDMD32S2A,0) DE_ROMSTARTx0(lw3_208p,"lw3cpuu.208",CRC(a3041f8a) SHA1(3c5b8525b8e9b924590648429c56aaf97adee460)) DE_DMD32ROM44( "lw3drom1.a26",CRC(44a4cf81) SHA1(c7f3e3d5fbe930650e48423c8ba0ac484ce0640c), @@ -715,7 +715,7 @@ DE2S_SOUNDROM022( "lw3u7.dat" ,CRC(ba845ac3) SHA1(bb50413ace1885870cb3817edae "lw3u17_vm.dat",CRC(5168dbbd) SHA1(e5f91650e613350c542ac93d0d4be64b25333186), "lw3u21_vm.dat",CRC(7ec96750) SHA1(13e41833d43396e370b817928618f72f928d9ba0)) DE_ROMEND -CORE_CLONEDEF(lw3,208p,208,"Lethal Weapon 3 (2.08p, Voices Mod)",2013,"Data East",de_mDEDMD32S2A_hack,0) +CORE_CLONEDEF(lw3,208p,208,"Lethal Weapon 3 (2.08p, Voices Mod)",2013,"Data East",de_mDEDMD32S2A,0) DE_ROMSTARTx0(lw3_207,"lw3gc5.207",CRC(27aeaea9) SHA1(f8c40cbc37edac20187ac880be281dd45d8ad614)) DE_DMD32ROM44( "lw3drom1.a26",CRC(44a4cf81) SHA1(c7f3e3d5fbe930650e48423c8ba0ac484ce0640c), @@ -724,7 +724,7 @@ DE2S_SOUNDROM022( "lw3u7.dat" ,CRC(ba845ac3) SHA1(bb50413ace1885870cb3817edae4 "lw3u17.dat" ,CRC(e34cf2fc) SHA1(417c83ded6637f891c8bb42b32d6898c90a0e5cf), "lw3u21.dat" ,CRC(82bed051) SHA1(49ddc4190762d9b473fda270e0d6d88a4422d5d7)) DE_ROMEND -CORE_CLONEDEF(lw3,207,208,"Lethal Weapon 3 (2.07 Canadian)",1992,"Data East",de_mDEDMD32S2A_hack,0) +CORE_CLONEDEF(lw3,207,208,"Lethal Weapon 3 (2.07 Canadian)",1992,"Data East",de_mDEDMD32S2A,0) DE_ROMSTARTx0(lw3_205,"lw3gc5.205",CRC(5ad8ff4a) SHA1(6a01a2195543c0c57ce4ce78703c91500835a2da)) DE_DMD32ROM44( "lw3dsp1.205",CRC(9dfeffb4) SHA1(f62f2a884da68b4dbfe7da071058dc8cd1766c36), @@ -733,7 +733,7 @@ DE2S_SOUNDROM022( "lw3u7.dat" ,CRC(ba845ac3) SHA1(bb50413ace1885870cb3817edae4 "lw3u17.dat" ,CRC(e34cf2fc) SHA1(417c83ded6637f891c8bb42b32d6898c90a0e5cf), "lw3u21.dat" ,CRC(82bed051) SHA1(49ddc4190762d9b473fda270e0d6d88a4422d5d7)) DE_ROMEND -CORE_CLONEDEF(lw3,205,208,"Lethal Weapon 3 (2.05)",1992,"Data East",de_mDEDMD32S2A_hack,0) +CORE_CLONEDEF(lw3,205,208,"Lethal Weapon 3 (2.05)",1992,"Data East",de_mDEDMD32S2A,0) DE_ROMSTARTx0(lw3_e204,"lw3cpue.204",CRC(33cb9197) SHA1(c6b25dfd93bb5c425a606ae21f757a87a07dc320)) DE_DMD32ROM44( "lw3dsp1a.202",CRC(4920f84f) SHA1(928e4aefdcf9462201001f4ac03d56a0cda25ec1), @@ -742,7 +742,7 @@ DE2S_SOUNDROM022( "lw3u7.dat" ,CRC(ba845ac3) SHA1(bb50413ace1885870cb3817edae "lw3u17.dat" ,CRC(e34cf2fc) SHA1(417c83ded6637f891c8bb42b32d6898c90a0e5cf), "lw3u21.dat" ,CRC(82bed051) SHA1(49ddc4190762d9b473fda270e0d6d88a4422d5d7)) DE_ROMEND -CORE_CLONEDEF(lw3,e204,208,"Lethal Weapon 3 (2.04 English)",1992,"Data East",de_mDEDMD32S2A_hack,0) +CORE_CLONEDEF(lw3,e204,208,"Lethal Weapon 3 (2.04 English)",1992,"Data East",de_mDEDMD32S2A,0) DE_ROMSTARTx0(lw3_203,"lw3cpuu.203",CRC(0cfa38d4) SHA1(11d2e101a574c2dfec49ec701f480173b84c842e)) DE_DMD32ROM44( "lw3dsp1.204",CRC(1ba79363) SHA1(46d489a1190533c73370acd8a48cef60d12f87ce), @@ -751,7 +751,7 @@ DE2S_SOUNDROM022( "lw3u7.dat" ,CRC(ba845ac3) SHA1(bb50413ace1885870cb3817edae4 "lw3u17.dat" ,CRC(e34cf2fc) SHA1(417c83ded6637f891c8bb42b32d6898c90a0e5cf), "lw3u21.dat" ,CRC(82bed051) SHA1(49ddc4190762d9b473fda270e0d6d88a4422d5d7)) DE_ROMEND -CORE_CLONEDEF(lw3,203,208,"Lethal Weapon 3 (2.03)",1992,"Data East",de_mDEDMD32S2A_hack,0) +CORE_CLONEDEF(lw3,203,208,"Lethal Weapon 3 (2.03)",1992,"Data East",de_mDEDMD32S2A,0) DE_ROMSTARTx0(lw3_200,"lw3cpu.200",CRC(ddb6e7a7) SHA1(d48309e1984ef9a7682dfde190cf457632044657)) DE_DMD32ROM44( "lw3dsp1.204",CRC(1ba79363) SHA1(46d489a1190533c73370acd8a48cef60d12f87ce), @@ -760,7 +760,7 @@ DE2S_SOUNDROM022( "lw3u7.dat" ,CRC(ba845ac3) SHA1(bb50413ace1885870cb3817edae4 "lw3u17.dat" ,CRC(e34cf2fc) SHA1(417c83ded6637f891c8bb42b32d6898c90a0e5cf), "lw3u21.dat" ,CRC(82bed051) SHA1(49ddc4190762d9b473fda270e0d6d88a4422d5d7)) DE_ROMEND -CORE_CLONEDEF(lw3,200,208,"Lethal Weapon 3 (2.00)",1992,"Data East",de_mDEDMD32S2A_hack,0) +CORE_CLONEDEF(lw3,200,208,"Lethal Weapon 3 (2.00)",1992,"Data East",de_mDEDMD32S2A,0) DE_ROMSTARTx0(lw3_300,"LW3CPUU.300",CRC(1ebcf869) SHA1(f708635bd3dedca0979a31de4151a2569e040639)) DE_DMD32ROM44( "lw3drom1.300",CRC(38f0ab03) SHA1(6ab549c6388aacedadd5a16e937ec0612475a0ac), @@ -769,7 +769,7 @@ DE2S_SOUNDROM022( "lw3u7.dat" ,CRC(ba845ac3) SHA1(bb50413ace1885870cb3817edae4 "lw3u17.dat" ,CRC(e34cf2fc) SHA1(417c83ded6637f891c8bb42b32d6898c90a0e5cf), "lw3u21.dat" ,CRC(82bed051) SHA1(49ddc4190762d9b473fda270e0d6d88a4422d5d7)) DE_ROMEND -CORE_CLONEDEF(lw3,300,208,"Lethal Weapon 3 (3.00 unofficial MOD)",2020,"Data East",de_mDEDMD32S2A_hack,0) +CORE_CLONEDEF(lw3,300,208,"Lethal Weapon 3 (3.00 unofficial MOD)",2020,"Data East",de_mDEDMD32S2A,0) DE_ROMSTARTx0(lw3_301,"LW3CPUU.301",CRC(e6a44d10) SHA1(0da68cfaa2667bc34493ae7ba703c06b60171989)) DE_DMD32ROM44( "lw3drom1.300",CRC(38f0ab03) SHA1(6ab549c6388aacedadd5a16e937ec0612475a0ac), @@ -778,7 +778,7 @@ DE2S_SOUNDROM022( "lw3u7.dat" ,CRC(ba845ac3) SHA1(bb50413ace1885870cb3817edae4 "lw3u17.dat" ,CRC(e34cf2fc) SHA1(417c83ded6637f891c8bb42b32d6898c90a0e5cf), "lw3u21.dat" ,CRC(82bed051) SHA1(49ddc4190762d9b473fda270e0d6d88a4422d5d7)) DE_ROMEND -CORE_CLONEDEF(lw3,301,208,"Lethal Weapon 3 (3.01 unofficial MOD)",2020,"Data East",de_mDEDMD32S2A_hack,0) +CORE_CLONEDEF(lw3,301,208,"Lethal Weapon 3 (3.01 unofficial MOD)",2020,"Data East",de_mDEDMD32S2A,0) /*------------------------------------------------------------- / Aaron Spelling - CPU Rev 3 /DMD Type 2 512K Rom - 64K CPU Rom @@ -792,7 +792,7 @@ DE2S_SOUNDROM144( "assndu7.bin" ,CRC(f0414a0d) SHA1(b1f940be05426a39f4e5ea08 "assndu21.bin",CRC(7d69e917) SHA1(73e21e65bc194c063933288cb617127b41593466)) DE_ROMEND #define input_ports_aar input_ports_des11 -CORE_GAMEDEF(aar,101,"Aaron Spelling (1.01)",1992,"Data East",de_mDEDMD32S2A_hack,0) +CORE_GAMEDEF(aar,101,"Aaron Spelling (1.01)",1992,"Data East",de_mDEDMD32S2A,0) /*------------------------------------------------------------- / Michael Jordan - CPU Rev 3 /DMD Type 2 512K Rom - 64K CPU Rom @@ -805,7 +805,7 @@ DE2S_SOUNDROM144( "MJsndu7.bin" ,CRC(a32237f5) SHA1(0fc106429af320c4a30a99c67 "MJsndu21.bin",CRC(addfe20e) SHA1(3a6862640f81493da1beddca11011090d8b7cab0)) DE_ROMEND #define input_ports_mj input_ports_des11 -CORE_GAMEDEF(mj,130,"Michael Jordan (1.30)",1992,"Data East",de_mDEDMD32S2A_hack,0) +CORE_GAMEDEF(mj,130,"Michael Jordan (1.30)",1992,"Data East",de_mDEDMD32S2A,0) /*------------------------------------------------------------- / Star Wars - CPU Rev 3 /DMD Type 2 512K Rom - 64K CPU Rom @@ -818,7 +818,7 @@ DE2S_SOUNDROM042( "s-wars.u7" ,CRC(cefa19d5) SHA1(7ddf9cc85ab601514305bc460 "s-wars.u21" ,CRC(7b08fdf1) SHA1(489d21a10e97e886f948d81dedd7f8de3acecd2b)) DE_ROMEND #define input_ports_stwr input_ports_des11 -CORE_GAMEDEF(stwr,104,"Star Wars (1.04 20th Anniversary)",2012,"Data East",de_mDEDMD32S2A_hack,0) +CORE_GAMEDEF(stwr,104,"Star Wars (1.04 20th Anniversary)",2012,"Data East",de_mDEDMD32S2A,0) DE_ROMSTARTx0(stwr_106,"starcpua.106",CRC(35d3cfd9) SHA1(14d8960f3657d7cd977b0a749e995aadb3fd4c7c)) DE_DMD32ROM8x( "sw4mrom.a15",CRC(00c87952) SHA1(cd2f491f03fcb3e3ceff7ee7f678aa1957a5d14b)) @@ -826,7 +826,7 @@ DE2S_SOUNDROM042( "s-wars.u7" ,CRC(cefa19d5) SHA1(7ddf9cc85ab601514305bc460 "s-wars.u17" ,CRC(7950a147) SHA1(f5bcd5cf6b35f9e4f14d62b084495c3a743d92a1), "s-wars.u21" ,CRC(7b08fdf1) SHA1(489d21a10e97e886f948d81dedd7f8de3acecd2b)) DE_ROMEND -CORE_CLONEDEF(stwr,106,104,"Star Wars (1.06 20th Anniversary)",2016,"Data East",de_mDEDMD32S2A_hack,0) +CORE_CLONEDEF(stwr,106,104,"Star Wars (1.06 20th Anniversary)",2016,"Data East",de_mDEDMD32S2A,0) DE_ROMSTARTx0(stwr_107s,"starcpua.107",CRC(1a801b7e) SHA1(fef567126dff87a2cb31401b029c3050438072b7)) DE_DMD32ROM8x( "sw4mrom.s15",CRC(158867b9) SHA1(45a0f4d26c21e2259aeb2a726a1eac23744213a2)) @@ -834,7 +834,7 @@ DE2S_SOUNDROM042( "s-wars.u7" ,CRC(cefa19d5) SHA1(7ddf9cc85ab601514305bc460 "s-wars.u17" ,CRC(7950a147) SHA1(f5bcd5cf6b35f9e4f14d62b084495c3a743d92a1), "s-wars.u21" ,CRC(7b08fdf1) SHA1(489d21a10e97e886f948d81dedd7f8de3acecd2b)) DE_ROMEND -CORE_CLONEDEF(stwr,107s,104,"Star Wars (1.07 20th Anniversary, Spanish)",2016,"Data East",de_mDEDMD32S2A_hack,0) +CORE_CLONEDEF(stwr,107s,104,"Star Wars (1.07 20th Anniversary, Spanish)",2016,"Data East",de_mDEDMD32S2A,0) DE_ROMSTARTx0(stwr_107,"starcpua.107",CRC(1a801b7e) SHA1(fef567126dff87a2cb31401b029c3050438072b7)) DE_DMD32ROM8x( "sw4mrom.a15",CRC(00c87952) SHA1(cd2f491f03fcb3e3ceff7ee7f678aa1957a5d14b)) @@ -842,7 +842,7 @@ DE2S_SOUNDROM042( "s-wars.u7" ,CRC(cefa19d5) SHA1(7ddf9cc85ab601514305bc460 "s-wars.u17" ,CRC(7950a147) SHA1(f5bcd5cf6b35f9e4f14d62b084495c3a743d92a1), "s-wars.u21" ,CRC(7b08fdf1) SHA1(489d21a10e97e886f948d81dedd7f8de3acecd2b)) DE_ROMEND -CORE_CLONEDEF(stwr,107,104,"Star Wars (1.07 20th Anniversary)",2016,"Data East",de_mDEDMD32S2A_hack,0) +CORE_CLONEDEF(stwr,107,104,"Star Wars (1.07 20th Anniversary)",2016,"Data East",de_mDEDMD32S2A,0) DE_ROMSTARTx0(stwr_103,"starcpua.103",CRC(318085ca) SHA1(7c35bdee52e8093fe05f0624615baabe559a1917)) DE_DMD32ROM8x( "sw4mrom.a15",CRC(00c87952) SHA1(cd2f491f03fcb3e3ceff7ee7f678aa1957a5d14b)) @@ -850,7 +850,7 @@ DE2S_SOUNDROM042( "s-wars.u7" ,CRC(cefa19d5) SHA1(7ddf9cc85ab601514305bc460 "s-wars.u17" ,CRC(7950a147) SHA1(f5bcd5cf6b35f9e4f14d62b084495c3a743d92a1), "s-wars.u21" ,CRC(7b08fdf1) SHA1(489d21a10e97e886f948d81dedd7f8de3acecd2b)) DE_ROMEND -CORE_CLONEDEF(stwr,103,104,"Star Wars (1.03, Display 1.05)",1992,"Data East",de_mDEDMD32S2A_hack,0) +CORE_CLONEDEF(stwr,103,104,"Star Wars (1.03, Display 1.05)",1992,"Data East",de_mDEDMD32S2A,0) DE_ROMSTARTx0(stwr_a14,"starcpua.103",CRC(318085ca) SHA1(7c35bdee52e8093fe05f0624615baabe559a1917)) DE_DMD32ROM44( "swrom1.a14", CRC(4d577828) SHA1(8b1f302621fe2ee13a067b9c97e3dc33f4519cea), @@ -859,7 +859,7 @@ DE2S_SOUNDROM042( "s-wars.u7" ,CRC(cefa19d5) SHA1(7ddf9cc85ab601514305bc460 "s-wars.u17" ,CRC(7950a147) SHA1(f5bcd5cf6b35f9e4f14d62b084495c3a743d92a1), "s-wars.u21" ,CRC(7b08fdf1) SHA1(489d21a10e97e886f948d81dedd7f8de3acecd2b)) DE_ROMEND -CORE_CLONEDEF(stwr,a14,104,"Star Wars (1.03, Display 1.04)",1992,"Data East",de_mDEDMD32S2A_hack,0) +CORE_CLONEDEF(stwr,a14,104,"Star Wars (1.03, Display 1.04)",1992,"Data East",de_mDEDMD32S2A,0) DE_ROMSTARTx0(stwr_a046,"starcpua.103",CRC(318085ca) SHA1(7c35bdee52e8093fe05f0624615baabe559a1917)) DE_DMD32ROM44( "swrom1.a046",CRC(5ceac219) SHA1(76b7acf378f83bacf6c4adb020d6e544eacbac7a), @@ -868,7 +868,7 @@ DE2S_SOUNDROM042( "s-wars.u7" ,CRC(cefa19d5) SHA1(7ddf9cc85ab601514305bc460 "s-wars.u17" ,CRC(7950a147) SHA1(f5bcd5cf6b35f9e4f14d62b084495c3a743d92a1), "s-wars.u21" ,CRC(7b08fdf1) SHA1(489d21a10e97e886f948d81dedd7f8de3acecd2b)) DE_ROMEND -CORE_CLONEDEF(stwr,a046,104,"Star Wars (1.03, Display A0.46)",1992,"Data East",de_mDEDMD32S2A_hack,0) +CORE_CLONEDEF(stwr,a046,104,"Star Wars (1.03, Display A0.46)",1992,"Data East",de_mDEDMD32S2A,0) /* USA CPU 1.02 (11/20/92) */ DE_ROMSTARTx0(stwr_102,"starcpua.102",CRC(8b9d90d6) SHA1(2fb7594e6f4aae1dc3a07192546fabd2901acbed)) @@ -877,7 +877,7 @@ DE2S_SOUNDROM042( "s-wars.u7" ,CRC(cefa19d5) SHA1(7ddf9cc85ab601514305bc460 "s-wars.u17" ,CRC(7950a147) SHA1(f5bcd5cf6b35f9e4f14d62b084495c3a743d92a1), "s-wars.u21" ,CRC(7b08fdf1) SHA1(489d21a10e97e886f948d81dedd7f8de3acecd2b)) DE_ROMEND -CORE_CLONEDEF(stwr,102,104,"Star Wars (1.02)",1992,"Data East",de_mDEDMD32S2A_hack,0) +CORE_CLONEDEF(stwr,102,104,"Star Wars (1.02)",1992,"Data East",de_mDEDMD32S2A,0) /* England CPU 1.02 (11/20/92) */ DE_ROMSTARTx0(stwr_e12,"starcpue.102",CRC(b441abd3) SHA1(42cab6e16be8e25a68b2db30f53ba516bbb8741d)) @@ -886,7 +886,7 @@ DE2S_SOUNDROM042( "s-wars.u7" ,CRC(cefa19d5) SHA1(7ddf9cc85ab601514305bc460 "s-wars.u17" ,CRC(7950a147) SHA1(f5bcd5cf6b35f9e4f14d62b084495c3a743d92a1), "s-wars.u21" ,CRC(7b08fdf1) SHA1(489d21a10e97e886f948d81dedd7f8de3acecd2b)) DE_ROMEND -CORE_CLONEDEF(stwr,e12,104,"Star Wars (1.02 English)",1992,"Data East",de_mDEDMD32S2A_hack,0) +CORE_CLONEDEF(stwr,e12,104,"Star Wars (1.02 English)",1992,"Data East",de_mDEDMD32S2A,0) DE_ROMSTARTx0(stwr_101,"starcpu.101",CRC(6efc7b14) SHA1(f669669fbd8733d06b386ea352fdb2041bf98362)) DE_DMD32ROM44( "stardisp_u14.102", CRC(f8087364) SHA1(4cd66b72cf430018cfb7ac8306b96a8499d41896), @@ -895,7 +895,7 @@ DE2S_SOUNDROM042( "s-wars.u7" ,CRC(cefa19d5) SHA1(7ddf9cc85ab601514305bc460 "s-wars.u17" ,CRC(7950a147) SHA1(f5bcd5cf6b35f9e4f14d62b084495c3a743d92a1), "s-wars.u21" ,CRC(7b08fdf1) SHA1(489d21a10e97e886f948d81dedd7f8de3acecd2b)) DE_ROMEND -CORE_CLONEDEF(stwr,101,104,"Star Wars (1.01)",1992,"Data East",de_mDEDMD32S2A_hack,0) +CORE_CLONEDEF(stwr,101,104,"Star Wars (1.01)",1992,"Data East",de_mDEDMD32S2A,0) DE_ROMSTARTx0(stwr_g11,"starcpug.101",CRC(c74b4576) SHA1(67db9294cd802be8d62102fe756648f750821960)) DE_DMD32ROM8x( "swdsp_g.102",CRC(afdfbfc4) SHA1(1c3cd90b9cd4f88ee2b556abef863a0ae9a10056)) @@ -903,7 +903,7 @@ DE2S_SOUNDROM042( "s-wars.u7" ,CRC(cefa19d5) SHA1(7ddf9cc85ab601514305bc460 "s-wars.u17" ,CRC(7950a147) SHA1(f5bcd5cf6b35f9e4f14d62b084495c3a743d92a1), "s-wars.u21" ,CRC(7b08fdf1) SHA1(489d21a10e97e886f948d81dedd7f8de3acecd2b)) DE_ROMEND -CORE_CLONEDEF(stwr,g11,104,"Star Wars (1.01 German)",1992,"Data East",de_mDEDMD32S2A_hack,0) +CORE_CLONEDEF(stwr,g11,104,"Star Wars (1.01 German)",1992,"Data East",de_mDEDMD32S2A,0) /*------------------------------------------------------------- / The Adventures of Rocky and Bullwinkle and Friends - CPU Rev 3b /DMD Type 2 512K Rom - 64K CPU Rom @@ -916,7 +916,7 @@ DE2S_SOUNDROM142( "rab.u7" ,CRC(b232e630) SHA1(880fffc395d7c24bdea4e7e8000afba "rab.u21" ,CRC(3de1b375) SHA1(a48bb80483ca03cd7c3bf0b5f2930a6ee9cc448d)) DE_ROMEND #define input_ports_rab input_ports_des11 -CORE_GAMEDEF(rab,320,"Adventures of Rocky and Bullwinkle and Friends, The (3.20)",1993,"Data East",de_mDEDMD32S2A_hack,0) +CORE_GAMEDEF(rab,320,"Adventures of Rocky and Bullwinkle and Friends, The (3.20)",1993,"Data East",de_mDEDMD32S2A,0) DE_ROMSTARTx0(rab_130,"rabcpua.130",CRC(f59b1a53) SHA1(046cd0eaee6e646286f3dfa73eeacfd93c2be273)) DE_DMD32ROM8x( "rbdspa.130",CRC(b6e2176e) SHA1(9ccbb30dc0f386fcf5e5255c9f80c720e601565f)) @@ -924,7 +924,7 @@ DE2S_SOUNDROM142( "rab.u7" ,CRC(b232e630) SHA1(880fffc395d7c24bdea4e7e8000afba "rab.u17" ,CRC(7f2b53b8) SHA1(fd4f4ed1ed343069ffc534fe4b20026fe7403220), "rab.u21" ,CRC(3de1b375) SHA1(a48bb80483ca03cd7c3bf0b5f2930a6ee9cc448d)) DE_ROMEND -CORE_CLONEDEF(rab,130,320,"Adventures of Rocky and Bullwinkle and Friends, The (1.30)",1993,"Data East",de_mDEDMD32S2A_hack,0) +CORE_CLONEDEF(rab,130,320,"Adventures of Rocky and Bullwinkle and Friends, The (1.30)",1993,"Data East",de_mDEDMD32S2A,0) DE_ROMSTARTx0(rab_103,"rabcpu.103",CRC(d5fe3184) SHA1(dc1ca938f15240d1c15ee5724d29a3538418f8de)) DE_DMD32ROM8x( "rabdspsp.103",CRC(02624948) SHA1(069ef69d6ce193d73954935b378230c05b83b8fc)) @@ -932,7 +932,7 @@ DE2S_SOUNDROM142( "rab.u7" ,CRC(b232e630) SHA1(880fffc395d7c24bdea4e7e8000afba "rab.u17" ,CRC(7f2b53b8) SHA1(fd4f4ed1ed343069ffc534fe4b20026fe7403220), "rab.u21" ,CRC(3de1b375) SHA1(a48bb80483ca03cd7c3bf0b5f2930a6ee9cc448d)) DE_ROMEND -CORE_CLONEDEF(rab,103,320,"Adventures of Rocky and Bullwinkle and Friends, The (1.03 Spanish)",1993,"Data East",de_mDEDMD32S2A_hack,0) +CORE_CLONEDEF(rab,103,320,"Adventures of Rocky and Bullwinkle and Friends, The (1.03 Spanish)",1993,"Data East",de_mDEDMD32S2A,0) /*------------------------------------------------------------- / Jurassic Park - CPU Rev 3b /DMD Type 2 512K Rom - 64K CPU Rom diff --git a/src/wpc/dmddevice.cpp b/src/wpc/dmddevice.cpp index 20509f85a..8781520a1 100644 --- a/src/wpc/dmddevice.cpp +++ b/src/wpc/dmddevice.cpp @@ -285,7 +285,7 @@ void renderDMDFrame(UINT64 gen, UINT16 width, UINT16 height, UINT8 *currbuffer, dmd_height = height; dmd_hasDMD = true; - if ((gen & (GEN_SAM | GEN_SPA | GEN_ALVG_DMD2 | GEN_GTS3)) != 0) { + if ((gen & (GEN_SAM | GEN_SPA | GEN_ALVG | GEN_ALVG_DMD2 | GEN_GTS3)) != 0) { if (noOfRawFrames != 0) { if (DmdDev_Render_16_Shades_with_Raw) { DmdDev_Render_16_Shades_with_Raw(width, height, currbuffer, noOfRawFrames, rawbuffer); @@ -322,7 +322,7 @@ void render2ndDMDFrame(UINT64 gen, UINT16 width, UINT16 height, UINT8* currbuffe dmd_height = height; dmd_hasDMD = true; - if ((gen & (GEN_SAM | GEN_SPA | GEN_ALVG_DMD2 | GEN_GTS3)) != 0) { + if ((gen & (GEN_SAM | GEN_SPA | GEN_ALVG | GEN_ALVG_DMD2 | GEN_GTS3)) != 0) { if (noOfRawFrames != 0) { if (DmdScr_Render_16_Shades_with_Raw) { DmdScr_Render_16_Shades_with_Raw(width, height, currbuffer, noOfRawFrames, rawbuffer); diff --git a/src/wpc/gts3.c b/src/wpc/gts3.c index caa29459f..c9f80abe0 100644 --- a/src/wpc/gts3.c +++ b/src/wpc/gts3.c @@ -25,9 +25,6 @@ #include "gts3dmd.h" #include "gts80s.h" -UINT8 DMDFrames [GTS3DMD_FRAMES][0x200]; -UINT8 DMDFrames2[GTS3DMD_FRAMES][0x200]; //2nd DMD Display for Strikes N Spares - #define GTS3_INTERFACE_UPD_PER_FRAME 1 /* interface update frequency per 60Hz frame */ #define GTS3_IRQFREQ 1500 /* IRQ Frequency (Guessed) */ #define GTS3_ALPHANMIFREQ 1000 /* Alpha NMI Frequency (Guessed)*/ @@ -584,7 +581,6 @@ static MACHINE_INIT(gts3b) { static void gts3dmd_init(void) { memset(>S3locals, 0, sizeof(GTS3locals)); memset(>S3_dmdlocals[0], 0, sizeof(GTS3_DMDlocals)); - memset(&DMDFrames, 0, sizeof(DMDFrames)); via_config(0, &via_0_interface); via_config(1, &via_1_interface); @@ -594,6 +590,9 @@ static void gts3dmd_init(void) { crtc6845_init(0); crtc6845_set_vsync(0, 3579545. / 2., dmd_vblank); + // Setup PWM shading + core_dmd_pwm_init(>S3_dmdlocals[0].pwm_state, 128, 32, CORE_DMD_PWM_FILTER_GTS3); + /*DMD*/ /*copy last 32K of ROM into last 32K of CPU region*/ /*Setup ROM Swap so opcode will work*/ @@ -726,13 +725,15 @@ static MACHINE_INIT(gts3dmd) { static MACHINE_INIT(gts3dmd2) { gts3dmd_init(); memset(>S3_dmdlocals[1], 0, sizeof(GTS3_DMDlocals)); - memset(&DMDFrames2, 0, sizeof(DMDFrames2)); GTS3_dmdlocals[0].has2DMD = 1; //Init 2nd 6845 crtc6845_init(1); crtc6845_set_vsync(1, 3579545. / 2., dmd_vblank); + // Setup PWM shading + core_dmd_pwm_init(>S3_dmdlocals[1].pwm_state, 128, 32, CORE_DMD_PWM_FILTER_GTS3); + /*copy last 32K of DMD ROM into last 32K of CPU region*/ if (memory_region(GTS3_MEMREG_DCPU2)) { memcpy(memory_region(GTS3_MEMREG_DCPU2) + 0x8000, @@ -744,6 +745,17 @@ static MACHINE_STOP(gts3) { sndbrd_0_exit(); } +static MACHINE_STOP(gts3dmd) { + sndbrd_0_exit(); + core_dmd_pwm_exit(>S3_dmdlocals[0].pwm_state); +} + +static MACHINE_STOP(gts3dmd2) { + sndbrd_0_exit(); + core_dmd_pwm_exit(>S3_dmdlocals[0].pwm_state); + core_dmd_pwm_exit(>S3_dmdlocals[1].pwm_state); +} + /*Solenoids - Need to verify correct solenoid # here!*/ static WRITE_HANDLER(solenoid_w) { @@ -946,13 +958,10 @@ static WRITE_HANDLER(dmd_aux) { //Update the DMD Frames during the DMD VBLANK generated by the CRTC6845 - Supports 2 DMD Displays static void dmd_vblank(int which) { - int offset = crtc6845_start_address_r(which) >> 2; - if (which) - memcpy(DMDFrames2[GTS3_dmdlocals[1].nextDMDFrame],memory_region(GTS3_MEMREG_DCPU2)+0x1000+offset,0x200); - else - memcpy(DMDFrames[GTS3_dmdlocals[0].nextDMDFrame],memory_region(GTS3_MEMREG_DCPU1)+0x1000+offset,0x200); + const UINT8* RAM = memory_region(which ? GTS3_MEMREG_DCPU2 : GTS3_MEMREG_DCPU1) + 0x1000 + (crtc6845_start_address_r(which) >> 2); + //static double prev; printf("DMD VBlank %6.2fHz: %02x %02x %02x %02x\n", 1. / (timer_get_time() - prev), RAM[20 * 16 + 2], RAM[20 * 16 + 6], RAM[20 * 16 + 10], RAM[20 * 16 + 14]); prev = timer_get_time(); + core_dmd_submit_frame(>S3_dmdlocals[which].pwm_state, RAM); cpu_set_nmi_line(which ? GTS3_DCPUNO2 : GTS3_DCPUNO, PULSE_LINE); - GTS3_dmdlocals[which].nextDMDFrame = (GTS3_dmdlocals[which].nextDMDFrame + 1) % GTS3DMD_FRAMES; } /* Printer connector */ @@ -1134,7 +1143,7 @@ MACHINE_DRIVER_START(gts3_21) MDRV_IMPORT_FROM(gts3) MDRV_CPU_ADD(M65C02, 3579545./2.) MDRV_CPU_MEMORY(GTS3_dmdreadmem, GTS3_dmdwritemem) - MDRV_CORE_INIT_RESET_STOP(gts3dmd,NULL,gts3) + MDRV_CORE_INIT_RESET_STOP(gts3dmd,NULL,gts3dmd) MDRV_IMPORT_FROM(gts80s_s3) MACHINE_DRIVER_END @@ -1154,7 +1163,7 @@ MACHINE_DRIVER_START(gts3_22) MDRV_CORE_INIT_RESET_STOP(gts3dmd,NULL,gts3) MDRV_CPU_ADD(M65C02, 3579545./2.) MDRV_CPU_MEMORY(GTS3_dmdreadmem2, GTS3_dmdwritemem2) - MDRV_CORE_INIT_RESET_STOP(gts3dmd2,NULL,gts3) + MDRV_CORE_INIT_RESET_STOP(gts3dmd2,NULL,gts3dmd2) MDRV_SOUND_ADD(OKIM6295, sns_okim6295_interface) MDRV_DIAGNOSTIC_LEDH(3) MACHINE_DRIVER_END diff --git a/src/wpc/gts3.h b/src/wpc/gts3.h index b10134427..1ac96eb2c 100644 --- a/src/wpc/gts3.h +++ b/src/wpc/gts3.h @@ -227,7 +227,7 @@ typedef struct { UINT8 status2; // bool UINT8 dstrb; // bool UINT8 dmd_visible_addr; - UINT8 nextDMDFrame; + core_tDMDPWMState pwm_state; } GTS3_DMDlocals; typedef struct { diff --git a/src/wpc/gts3dmd.c b/src/wpc/gts3dmd.c index ccaed7fe7..fb5806f69 100644 --- a/src/wpc/gts3dmd.c +++ b/src/wpc/gts3dmd.c @@ -3,22 +3,12 @@ #include "gts3.h" #include "gts3dmd.h" -extern UINT8 DMDFrames [GTS3DMD_FRAMES][0x200]; -extern UINT8 DMDFrames2[GTS3DMD_FRAMES][0x200]; extern GTS3_DMDlocals GTS3_dmdlocals[2]; -// Shaded frame computed from stored PWMed DMD frames -UINT16 GTS3_accumulatedFrame[32][128]; - -#if defined(VPINMAME) || defined(LIBPINMAME) -extern UINT8 g_raw_gtswpc_dmd[GTS3DMD_FRAMES*0x200]; -extern UINT32 g_raw_gtswpc_dmdframes; -#endif - // GTS3 hardware creates shades by quickly switching frames (PWM). // It uses pattern of 3, 6, 8 or 10 frames at 376Hz to create the // PWM pattern. We store the last 24 frames and apply a FIR low pass -// filter computed with GNU Octave (script is given below). +// filter computed with GNU Octave (script is given in core.c). // // Previous version had an optimized implementation, storing as little frames as // possible for each GTS3 game (see commit 9b9ac9a5c2bfedac13ca382ff6669837882c129d). @@ -26,74 +16,9 @@ extern UINT32 g_raw_gtswpc_dmdframes; // This lead to better performance since less frames were accumulated but had 2 side effects: // - there were some occasional residual flickers, // - DMD luminance were not fully coherent between GTS3 games (some 4 shades, some other 5 shades). - -/* The following script allows to compute and display the filter applied to some PWM pattern in GNU Octave: -pkg load signal -fc = 15; % Cut-off frequency (Hz) -fs = 376; % Sampling rate (Hz) -data=[repmat([0;0;1],100,1),repmat([0;0;0;1;1;1],50,1),repmat([0;0;0;0;1;1;1;1;1;1],30,1),repmat([0;0;0;0;0;0;0;0;0;1],30,1)]; -b = fir1(23, fc/(fs/2)); -filtered = filter(b,1,data); -clf -subplot ( columns ( filtered ), 1, 1) -plot(filtered(:,1),";1/3 - 3;") -subplot ( columns ( filtered ), 1, 2 ) -plot(filtered(:,2),";1/2 - 6;") -subplot ( columns ( filtered ), 1, 3 ) -plot(filtered(:,3),";6/10 - 10;") -subplot ( columns ( filtered ), 1, 4 ) -plot(filtered(:,4),";1/10 - 10;") -bp = 10000 * b; % scaled filter used for PinMame integer math -*/ - int gts3_dmd128x32(int which, struct mame_bitmap* bitmap, const struct rectangle* cliprect, const struct core_dispLayout* layout) { - static const UINT16 fir_weights[] = { 8, 19, 44, 91, 168, 274, 405, 552, // Octave: b = fir1(23, fc/(fs/2)); with fc = 15; and fs = 376; - 699, 830, 928, 981, 981, 928, 830, 699, - 552, 405, 274, 168, 91, 44, 19, 8 }; - const UINT16 fir_sum = 9998; - - int ii,jj,kk,ll; - UINT8* dmdFrames = which == 0 ? &DMDFrames[0][0] : &DMDFrames2[0][0]; - - #if defined(VPINMAME) || defined(LIBPINMAME) - int i = 0; - g_raw_gtswpc_dmdframes = 5; // Only send the last 5 raw frames - UINT8* rawData = &g_raw_gtswpc_dmd[0]; - for (ii = 0; ii < (int)g_raw_gtswpc_dmdframes; ii++) { - UINT8* frameData = dmdFrames + ((GTS3_dmdlocals[0].nextDMDFrame + (GTS3DMD_FRAMES - 1) + (GTS3DMD_FRAMES - ii)) % GTS3DMD_FRAMES) * 0x200; - for (jj = 0; jj < 32 * 16; jj++) { // 32 lines of 16 columns of 8 pixels - UINT8 data = *frameData++; - *rawData = core_revbyte(data); - rawData++; - } - } - #endif - - // Apply low pass filter over 24 frames - memset(GTS3_accumulatedFrame, 0, sizeof(GTS3_accumulatedFrame)); - for (ii = 0; ii < sizeof(fir_weights)/sizeof(fir_weights[0]); ii++) { - const UINT16 frame_weight = fir_weights[ii]; - UINT8* frameData = dmdFrames + ((GTS3_dmdlocals[0].nextDMDFrame + (GTS3DMD_FRAMES - 1) + (GTS3DMD_FRAMES - ii)) % GTS3DMD_FRAMES) * 0x200; - for (jj = 1; jj <= 32; jj++) { // 32 lines - UINT16* line = >S3_accumulatedFrame[jj - 1][0]; - for (kk = 0; kk < 16; kk++) { // 16 columns/line - UINT8 data = *frameData++; - for (ll = 0; ll < 8; ll++) { // 8 pixels/column - (*line++) += frame_weight * (UINT16)(data>>7); - data <<= 1; - } - } - } - } - - // Scale down to 16 shades (note that precision matters and is needed to avoid flickering) - for (ii = 1; ii <= 32; ii++) // 32 lines - for (jj = 0; jj < 128; jj++) { // 128 pixels/line - UINT16 data = GTS3_accumulatedFrame[ii-1][jj]; - coreGlobals.dotCol[ii][jj] = ((UINT8)((255 * (unsigned int) data) / fir_sum)) >> 4; - } - + core_dmd_update_pwm(>S3_dmdlocals[which].pwm_state); video_update_core_dmd(bitmap, cliprect, layout); return 0; } diff --git a/src/wpc/gts3dmd.h b/src/wpc/gts3dmd.h index cbde793b8..39fcc67ee 100644 --- a/src/wpc/gts3dmd.h +++ b/src/wpc/gts3dmd.h @@ -4,8 +4,6 @@ #pragma once #endif -#define GTS3DMD_FRAMES 24 //# of Frames to capture - VIDEO_UPDATE(gts3_dmd128x32a); VIDEO_UPDATE(gts3_dmd128x32b); diff --git a/src/wpc/s11.c b/src/wpc/s11.c index 212036eeb..44e0b0d6e 100644 --- a/src/wpc/s11.c +++ b/src/wpc/s11.c @@ -1388,17 +1388,6 @@ MACHINE_DRIVER_START(de_dmd162aS) MDRV_SOUND_CMDHEADING("DE") MACHINE_DRIVER_END -/* DE 128x32 Sound 2a with hacky/tweaked DMD IRQ (LW3/AS/R&B/SW) */ -MACHINE_DRIVER_START(de_dmd322aS_hack) - MDRV_IMPORT_FROM(s11) - MDRV_IMPORT_FROM(de2aas) - MDRV_IMPORT_FROM(de_dmd32_hack) - MDRV_NVRAM_HANDLER(de) - MDRV_DIAGNOSTIC_LEDH(1) - MDRV_SOUND_CMD(de_sndCmd_w) - MDRV_SOUND_CMDHEADING("DE") -MACHINE_DRIVER_END - /* DE 128x32 Sound 2a */ MACHINE_DRIVER_START(de_dmd322aS) MDRV_IMPORT_FROM(s11) diff --git a/src/wpc/s11.h b/src/wpc/s11.h index 49ec170a1..4ce7b7e59 100644 --- a/src/wpc/s11.h +++ b/src/wpc/s11.h @@ -222,7 +222,6 @@ extern MACHINE_DRIVER_EXTERN(de_dmd642aS); #define de_mDEAS1 de_a1S #define de_mDEDMD16S1 de_dmd161S #define de_mDEDMD16S2A de_dmd162aS -#define de_mDEDMD32S2A_hack de_dmd322aS_hack #define de_mDEDMD32S2A de_dmd322aS #define de_mDEDMD64S2A de_dmd642aS diff --git a/src/wpc/wpc.c b/src/wpc/wpc.c index faa54cf28..2248e2cec 100644 --- a/src/wpc/wpc.c +++ b/src/wpc/wpc.c @@ -29,9 +29,6 @@ #else #define WPC_INTERFACE_UPD_PER_FRAME 1 // For regular lib/V/PinMame, one interface update at 60Hz should be enough (it's what most other drivers do) #endif -/*-- no of DMD frames to add together to create shades --*/ -/*-- (hardcoded, do not change) --*/ -#define DMD_FRAMES 8 /* Some early machines like T2 could in some few animations (like T2 attract mode) profit from more shades, but very tricky to get right without flicker ! */ /*-- Smoothing values --*/ #if defined(PROC_SUPPORT) || defined(PPUC_SUPPORT) @@ -93,11 +90,6 @@ static INTERRUPT_GEN(wpc_interface_update); /---------------------*/ UINT8 *wpc_data; /* WPC registers */ -#if defined(VPINMAME) || defined(LIBPINMAME) -extern UINT8 g_raw_gtswpc_dmd[]; -extern UINT32 g_raw_gtswpc_dmdframes; -#endif - const struct core_dispLayout wpc_dispAlpha[] = { {0,0, 0,13,CORE_SEG16R},{0,26,13,2,CORE_SEG16D},{0,30,15,1,CORE_SEG16N}, {4,0,20,13,CORE_SEG16R},{4,26,33,2,CORE_SEG16D},{4,30,35,1,CORE_SEG16N}, @@ -150,9 +142,7 @@ static struct { int visiblePage; // rasterized memory page int row; // Rasterizer row position int firq; // State of FIRQ output line to CPU - UINT8 DMDFrames[DMD_FRAMES][0x400]; // Buffer for raw frames - UINT16 accumulatedFrame[64][128]; // Shaded frame computed from stored PWMed DMD frames - int nextDMDFrame; + core_tDMDPWMState pwm_state; } dmdlocals; /*-- pointers --*/ @@ -1196,6 +1186,13 @@ static MACHINE_INIT(wpc) { sndbrd_0_init(core_gameData->gen == GEN_WPC95DCS ? SNDBRD_DCS : SNDBRD_DCS95, 1, memory_region(DCS_ROMREGION),NULL,NULL); } + // Init DMD PWM shading + if (core_gameData->gen & (GEN_WPCDMD | GEN_WPCFLIPTRON | GEN_WPCDCS | GEN_WPCSECURITY | GEN_WPC95DCS | GEN_WPC95)) + { + core_dmd_pwm_init(&dmdlocals.pwm_state, 128, (core_gameData->hw.gameSpecific2 == WPC_PH) ? 64 : 32, CORE_DMD_PWM_FILTER_WPC); + dmdlocals.pwm_state.revByte = 1; + } + #ifdef PINMAME_HOST_UART if (pmoptions.serial_device != NULL) { // use default baud rate; game will set a baud rate at startup @@ -1513,6 +1510,8 @@ static MACHINE_INIT(wpc) { static MACHINE_STOP(wpc) { sndbrd_0_exit(); + if (core_gameData->gen & (GEN_WPCDMD | GEN_WPCFLIPTRON | GEN_WPCDCS | GEN_WPCSECURITY | GEN_WPC95DCS | GEN_WPC95)) + core_dmd_pwm_exit(&dmdlocals.pwm_state); if (wpc_printfile) { mame_fclose(wpc_printfile); wpc_printfile = NULL; } } @@ -1591,23 +1590,29 @@ static void wpc_dmd_hsync(int param) { { if (core_gameData->hw.gameSpecific2 == WPC_PH) { // PH: DMD is toggled between half and full page size using WPC_DMD_FIRQLINE register bit if (wpc_data[WPC_DMD_FIRQLINE] & 0x20) { // half page (used by menu system) - memcpy(dmdlocals.DMDFrames[dmdlocals.nextDMDFrame], memory_region(WPC_DMDREGION) + (dmdlocals.visiblePage & 0x0f) * 0x200 + (dmdlocals.visiblePage % 2) * 0x200, 0x200); + UINT8 full_frame[0x400]; // Somewhat overkill (2 copies) + memcpy(full_frame, memory_region(WPC_DMDREGION) + (dmdlocals.visiblePage & 0x0f) * 0x200 + (dmdlocals.visiblePage % 2) * 0x200, 0x200); + memset(&full_frame[0x200], 0, 0x200); + core_dmd_submit_frame(&dmdlocals.pwm_state, full_frame); + #ifdef PROC_SUPPORT + if (coreGlobals.p_rocEn) // PH: reasonable guess on how to handle two frames only + procFillDMDSubFrame(dmd_state->frame_index % 3, full_frame, 0x400); + #endif } else { // full page - memcpy(dmdlocals.DMDFrames[dmdlocals.nextDMDFrame], memory_region(WPC_DMDREGION) + dmdlocals.visiblePage * 0x400, 0x400); + core_dmd_submit_frame(&dmdlocals.pwm_state, memory_region(WPC_DMDREGION) + dmdlocals.visiblePage * 0x400); + #ifdef PROC_SUPPORT + if (coreGlobals.p_rocEn) // PH: reasonable guess on how to handle two frames only + procFillDMDSubFrame(dmd_state->frame_index % 3, memory_region(WPC_DMDREGION) + dmdlocals.visiblePage * 0x400, 0x400); + #endif } - #ifdef PROC_SUPPORT - if (coreGlobals.p_rocEn) // PH: reasonable guess on how to handle two frames only - procFillDMDSubFrame(dmdlocals.nextDMDFrame + 1, dmdlocals.DMDFrames[dmdlocals.nextDMDFrame], 0x400); - #endif } else { - memcpy(dmdlocals.DMDFrames[dmdlocals.nextDMDFrame], memory_region(WPC_DMDREGION) + (dmdlocals.visiblePage & 0x0f) * 0x200, 0x200); + core_dmd_submit_frame(&dmdlocals.pwm_state, memory_region(WPC_DMDREGION) + (dmdlocals.visiblePage & 0x0f) * 0x200); #ifdef PROC_SUPPORT if (coreGlobals.p_rocEn) /* looks like P-ROC uses the last 3 subframes sent rather than the first 3 */ - procFillDMDSubFrame(dmdlocals.nextDMDFrame + 1, dmdlocals.DMDFrames[dmdlocals.nextDMDFrame], 0x200); + procFillDMDSubFrame(dmd_state->frame_index % 3, memory_region(WPC_DMDREGION) + (dmdlocals.visiblePage & 0x0f) * 0x200, 0x200); /* Don't explicitly update the DMD from here. The P-ROC code will update after the next DMD event. */ #endif } - dmdlocals.nextDMDFrame = (dmdlocals.nextDMDFrame + 1) % DMD_FRAMES; // Move to next page (latched while rasterizing this page) dmdlocals.visiblePage = wpc_data[WPC_DMD_SHOWPAGE]; } @@ -1619,50 +1624,7 @@ static void wpc_dmd_hsync(int param) { } int wpcdmd_update(int height, struct mame_bitmap* bitmap, const struct rectangle* cliprect, const struct core_dispLayout* layout) { - int ii,jj,kk,ll; - UINT8* dmdFrames = &dmdlocals.DMDFrames[0][0]; - - static const UINT16 fir_weights[] = { 4, 39, 161, 295, 295, 161, 39, 4 }; // 15Hz low pass filter - static const UINT16 fir_sum = 1000; - - #if defined(VPINMAME) || defined(LIBPINMAME) - int i = 0; - g_raw_gtswpc_dmdframes = 5; // Only send the last 5 raw frames - UINT8* rawData = &g_raw_gtswpc_dmd[0]; - for (ii = 0; ii < (int)g_raw_gtswpc_dmdframes; ii++) { - UINT8* frameData = dmdFrames + ((dmdlocals.nextDMDFrame + (DMD_FRAMES - 1) + (DMD_FRAMES - ii)) % DMD_FRAMES) * 0x400; - for (jj = 0; jj < height * 16; jj++) { // 32 or 64 lines of 16 columns of 8 pixels - UINT8 data = *frameData++; - *rawData = data; - rawData++; - } - } - #endif - - // Apply low pass filter over 24 frames - memset(dmdlocals.accumulatedFrame, 0, sizeof(dmdlocals.accumulatedFrame)); - for (ii = 0; ii < sizeof(fir_weights)/sizeof(fir_weights[0]); ii++) { - const UINT16 frame_weight = fir_weights[ii]; - UINT8* frameData = dmdFrames + ((dmdlocals.nextDMDFrame + (DMD_FRAMES - 1) + (DMD_FRAMES - ii)) % DMD_FRAMES) * 0x400; - for (jj = 1; jj <= height; jj++) { // 32 or 64 lines - UINT16* line = &dmdlocals.accumulatedFrame[jj - 1][0]; - for (kk = 0; kk < 16; kk++) { // 16 columns/line - UINT8 data = core_revbyte(*frameData++); - for (ll = 0; ll < 8; ll++) { // 8 pixels/column - (*line++) += frame_weight * (UINT16)(data>>7); - data <<= 1; - } - } - } - } - - // Scale down to 4 shades (note that precision matters and is needed to avoid flickering) - for (ii = 1; ii <= height; ii++) // 32 or 64 lines - for (jj = 0; jj < 128; jj++) { // 128 pixels/line - UINT16 data = dmdlocals.accumulatedFrame[ii-1][jj]; - coreGlobals.dotCol[ii][jj] = ((UINT8)((255 * (unsigned int) data) / fir_sum)) >> 6; - } - + core_dmd_update_pwm(&dmdlocals.pwm_state); video_update_core_dmd(bitmap, cliprect, layout); return 0; }