/****************************************************************************** CD-i MCD212 video emulation ------------------- MESS implementation by Harmony ******************************************************************************* STATUS: - Just enough for the Mono-I CD-i board to work somewhat properly. TODO: - Unknown yet. *******************************************************************************/ #include "emu.h" #include "cpu/m68000/m68000.h" #include "video/mcd212.h" #include "includes/cdi.h" #if ENABLE_VERBOSE_LOG INLINE void verboselog(running_machine &machine, int n_level, const char *s_fmt, ...) { if( VERBOSE_LEVEL >= n_level ) { va_list v; char buf[ 32768 ]; va_start( v, s_fmt ); vsprintf( buf, s_fmt, v ); va_end( v ); logerror( "%08x: %s", cpu_get_pc(machine.device("maincpu")), buf ); } } #else #define verboselog(x,y,z,...) #endif static void cdi220_draw_lcd(running_machine &machine, int y); static void mcd212_update_region_arrays(mcd212_regs_t *mcd212); static void mcd212_set_display_parameters(mcd212_regs_t *mcd212, int channel, UINT8 value); static void mcd212_update_visible_area(running_machine &machine); static void mcd212_set_vsr(mcd212_regs_t *mcd212, int channel, UINT32 value); static void mcd212_set_dcp(mcd212_regs_t *mcd212, int channel, UINT32 value); static UINT32 mcd212_get_vsr(mcd212_regs_t *mcd212, int channel); static UINT32 mcd212_get_dcp(mcd212_regs_t *mcd212, int channel); static UINT32 mcd212_get_screen_width(mcd212_regs_t *mcd212); static void mcd212_set_register(running_machine &machine, int channel, UINT8 reg, UINT32 value); static void mcd212_process_ica(mcd212_regs_t *mcd212, int channel); static void mcd212_process_dca(mcd212_regs_t *mcd212, int channel); static void mcd212_process_vsr(mcd212_regs_t *mcd212, int channel, UINT8 *pixels_r, UINT8 *pixels_g, UINT8 *pixels_b); static void mcd212_mix_lines(mcd212_regs_t *mcd212, UINT8 *plane_a_r, UINT8 *plane_a_g, UINT8 *plane_a_b, UINT8 *plane_b_r, UINT8 *plane_b_g, UINT8 *plane_b_b, UINT32 *out); static void mcd212_draw_cursor(mcd212_regs_t *mcd212, UINT32 *scanline, int y); static void mcd212_draw_scanline(mcd212_regs_t *mcd212, int y); static const UINT16 cdi220_lcd_char[20*22] = { 0x2000, 0x2000, 0x2000, 0x2000, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0200, 0x0200, 0x0200, 0x0200, 0x2000, 0x2000, 0x2000, 0x2000, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0200, 0x0200, 0x0200, 0x0200, 0x2000, 0x2000, 0x2000, 0x2000, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0200, 0x0200, 0x0200, 0x0200, 0x2000, 0x2000, 0x2000, 0x2000, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0200, 0x0200, 0x0200, 0x0200, 0x2000, 0x2000, 0x2000, 0x2000, 0x8000, 0x8000, 0x0000, 0x0000, 0x0001, 0x0001, 0x0001, 0x0001, 0x0000, 0x0000, 0x0002, 0x0002, 0x0200, 0x0200, 0x0200, 0x0200, 0x2000, 0x2000, 0x2000, 0x2000, 0x8000, 0x8000, 0x8000, 0x0000, 0x0001, 0x0001, 0x0001, 0x0001, 0x0000, 0x0002, 0x0002, 0x0002, 0x0200, 0x0200, 0x0200, 0x0200, 0x2000, 0x2000, 0x2000, 0x2000, 0x8000, 0x8000, 0x8000, 0x8000, 0x0001, 0x0001, 0x0001, 0x0001, 0x0002, 0x0002, 0x0002, 0x0002, 0x0200, 0x0200, 0x0200, 0x0200, 0x2000, 0x2000, 0x2000, 0x2000, 0x0000, 0x8000, 0x8000, 0x8000, 0x0001, 0x0001, 0x0001, 0x0001, 0x0002, 0x0002, 0x0002, 0x0000, 0x0200, 0x0200, 0x0200, 0x0200, 0x2000, 0x2000, 0x2000, 0x2000, 0x0000, 0x0000, 0x8000, 0x8000, 0x0001, 0x0001, 0x0001, 0x0001, 0x0002, 0x0002, 0x0000, 0x0000, 0x0200, 0x0200, 0x0200, 0x0200, 0x2000, 0x2000, 0x2000, 0x2000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x0200, 0x0200, 0x0200, 0x0200, 0x2000, 0x2000, 0x2000, 0x2000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x0200, 0x0200, 0x0200, 0x0200, 0x1000, 0x1000, 0x1000, 0x1000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x0400, 0x0400, 0x0400, 0x0400, 0x1000, 0x1000, 0x1000, 0x1000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x0400, 0x0400, 0x0400, 0x0400, 0x1000, 0x1000, 0x1000, 0x1000, 0x0000, 0x0000, 0x0010, 0x0010, 0x0001, 0x0001, 0x0001, 0x0001, 0x0008, 0x0008, 0x0000, 0x0000, 0x0400, 0x0400, 0x0400, 0x0400, 0x1000, 0x1000, 0x1000, 0x1000, 0x0000, 0x0010, 0x0010, 0x0010, 0x0001, 0x0001, 0x0001, 0x0001, 0x0008, 0x0008, 0x0008, 0x0000, 0x0400, 0x0400, 0x0400, 0x0400, 0x1000, 0x1000, 0x1000, 0x1000, 0x0010, 0x0010, 0x0010, 0x0010, 0x0001, 0x0001, 0x0001, 0x0001, 0x0008, 0x0008, 0x0008, 0x0008, 0x0400, 0x0400, 0x0400, 0x0400, 0x1000, 0x1000, 0x1000, 0x1000, 0x0010, 0x0010, 0x0010, 0x0000, 0x0001, 0x0001, 0x0001, 0x0001, 0x0000, 0x0008, 0x0008, 0x0008, 0x0400, 0x0400, 0x0400, 0x0400, 0x1000, 0x1000, 0x1000, 0x1000, 0x0010, 0x0010, 0x0000, 0x0000, 0x0001, 0x0001, 0x0001, 0x0001, 0x0000, 0x0000, 0x0008, 0x0008, 0x0400, 0x0400, 0x0400, 0x0400, 0x1000, 0x1000, 0x1000, 0x1000, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0400, 0x0400, 0x0400, 0x0400, 0x1000, 0x1000, 0x1000, 0x1000, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0400, 0x0400, 0x0400, 0x0400, 0x1000, 0x1000, 0x1000, 0x1000, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0400, 0x0400, 0x0400, 0x0400, 0x1000, 0x1000, 0x1000, 0x1000, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0400, 0x0400, 0x0400, 0x0400 }; static void cdi220_draw_lcd(running_machine &machine, int y) { cdi_state *state = machine.driver_data(); bitmap_t *bitmap = state->m_lcdbitmap; UINT32 *scanline = BITMAP_ADDR32(bitmap, y, 0); int x = 0; int lcd = 0; for(lcd = 0; lcd < 8; lcd++) { cdislave_device *slave = downcast(machine.device("slave")); UINT16 data = (slave->get_lcd_state()[lcd*2] << 8) | slave->get_lcd_state()[lcd*2 + 1]; for(x = 0; x < 20; x++) { if(data & cdi220_lcd_char[y*20 + x]) { scanline[(7 - lcd)*24 + x] = 0x00ffffff; } else { scanline[(7 - lcd)*24 + x] = 0; } } } } static void mcd212_update_region_arrays(mcd212_regs_t *mcd212) { int x = 0; int latched_rf0 = 0; int latched_rf1 = 0; int latched_wfa = mcd212->channel[0].weight_factor_a[0]; int latched_wfb = mcd212->channel[1].weight_factor_b[0]; int reg = 0; for(x = 0; x < 768; x++) { if(mcd212->channel[0].image_coding_method & MCD212_ICM_NR) { int reg_ = 0; int flag = 0; for(flag = 0; flag < 2; flag++) { for(reg_ = 0; reg_ < 4; reg_++) { if(mcd212->channel[0].region_control[reg_] == 0) { break; } if(x == (mcd212->channel[0].region_control[flag*4 + reg_] & MCD212_RC_X)) { switch((mcd212->channel[0].region_control[flag*4 + reg_] & MCD212_RC_OP) >> MCD212_RC_OP_SHIFT) { case 0: // End of region control for line break; case 1: case 2: case 3: // Not used break; case 4: // Change weight of plane A latched_wfa = (mcd212->channel[0].region_control[flag*4 + reg_] & MCD212_RC_WF) >> MCD212_RC_WF_SHIFT; break; case 5: // Not used break; case 6: // Change weight of plane B latched_wfb = (mcd212->channel[0].region_control[flag*4 + reg_] & MCD212_RC_WF) >> MCD212_RC_WF_SHIFT; break; case 7: // Not used break; case 8: // Reset region flag if(flag) { latched_rf1 = 0; } else { latched_rf0 = 0; } break; case 9: // Set region flag if(flag) { latched_rf1 = 1; } else { latched_rf0 = 1; } break; case 10: // Not used case 11: // Not used break; case 12: // Reset region flag and change weight of plane A latched_wfa = (mcd212->channel[0].region_control[flag*4 + reg_] & MCD212_RC_WF) >> MCD212_RC_WF_SHIFT; if(flag) { latched_rf1 = 0; } else { latched_rf0 = 0; } break; case 13: // Set region flag and change weight of plane A latched_wfa = (mcd212->channel[0].region_control[flag*4 + reg_] & MCD212_RC_WF) >> MCD212_RC_WF_SHIFT; if(flag) { latched_rf1 = 1; } else { latched_rf0 = 1; } break; case 14: // Reset region flag and change weight of plane B latched_wfb = (mcd212->channel[0].region_control[flag*4 + reg_] & MCD212_RC_WF) >> MCD212_RC_WF_SHIFT; if(flag) { latched_rf1 = 0; } else { latched_rf0 = 0; } break; case 15: // Set region flag and change weight of plane B latched_wfb = (mcd212->channel[0].region_control[flag*4 + reg_] & MCD212_RC_WF) >> MCD212_RC_WF_SHIFT; if(flag) { latched_rf1 = 1; } else { latched_rf0 = 1; } break; } } } } } else { if(reg < 8) { int flag = (mcd212->channel[0].region_control[reg] & MCD212_RC_RF) >> MCD212_RC_RF_SHIFT; if(!(mcd212->channel[0].region_control[reg] & MCD212_RC_OP)) { for(; x < 768; x++) { mcd212->channel[0].weight_factor_a[x] = latched_wfa; mcd212->channel[1].weight_factor_b[x] = latched_wfb; mcd212->region_flag_0[x] = latched_rf0; mcd212->region_flag_1[x] = latched_rf1; } break; } if(x == (mcd212->channel[0].region_control[reg] & MCD212_RC_X)) { switch((mcd212->channel[0].region_control[reg] & MCD212_RC_OP) >> MCD212_RC_OP_SHIFT) { case 0: // End of region control for line break; case 1: case 2: case 3: // Not used break; case 4: // Change weight of plane A latched_wfa = (mcd212->channel[0].region_control[reg] & MCD212_RC_WF) >> MCD212_RC_WF_SHIFT; break; case 5: // Not used break; case 6: // Change weight of plane B latched_wfb = (mcd212->channel[0].region_control[reg] & MCD212_RC_WF) >> MCD212_RC_WF_SHIFT; break; case 7: // Not used break; case 8: // Reset region flag if(flag) { latched_rf1 = 0; } else { latched_rf0 = 0; } break; case 9: // Set region flag if(flag) { latched_rf1 = 1; } else { latched_rf0 = 1; } break; case 10: // Not used case 11: // Not used break; case 12: // Reset region flag and change weight of plane A latched_wfa = (mcd212->channel[0].region_control[reg] & MCD212_RC_WF) >> MCD212_RC_WF_SHIFT; if(flag) { latched_rf1 = 0; } else { latched_rf0 = 0; } break; case 13: // Set region flag and change weight of plane A latched_wfa = (mcd212->channel[0].region_control[reg] & MCD212_RC_WF) >> MCD212_RC_WF_SHIFT; if(flag) { latched_rf1 = 1; } else { latched_rf0 = 1; } break; case 14: // Reset region flag and change weight of plane B latched_wfb = (mcd212->channel[0].region_control[reg] & MCD212_RC_WF) >> MCD212_RC_WF_SHIFT; if(flag) { latched_rf1 = 0; } else { latched_rf0 = 0; } break; case 15: // Set region flag and change weight of plane B latched_wfb = (mcd212->channel[0].region_control[reg] & MCD212_RC_WF) >> MCD212_RC_WF_SHIFT; if(flag) { latched_rf1 = 1; } else { latched_rf0 = 1; } break; } reg++; } } } mcd212->channel[0].weight_factor_a[x] = latched_wfa; mcd212->channel[1].weight_factor_b[x] = latched_wfb; mcd212->region_flag_0[x] = latched_rf0; mcd212->region_flag_1[x] = latched_rf1; } } static void mcd212_set_vsr(mcd212_regs_t *mcd212, int channel, UINT32 value) { mcd212->channel[channel].vsr = value & 0x0000ffff; mcd212->channel[channel].dcr &= 0xffc0; mcd212->channel[channel].dcr |= (value >> 16) & 0x003f; } static void mcd212_set_register(running_machine &machine, int channel, UINT8 reg, UINT32 value) { cdi_state *state = machine.driver_data(); mcd212_regs_t *mcd212 = &state->m_mcd212_regs; switch(reg) { case 0x80: case 0x81: case 0x82: case 0x83: case 0x84: case 0x85: case 0x86: case 0x87: // CLUT 0 - 63 case 0x88: case 0x89: case 0x8a: case 0x8b: case 0x8c: case 0x8d: case 0x8e: case 0x8f: case 0x90: case 0x91: case 0x92: case 0x93: case 0x94: case 0x95: case 0x96: case 0x97: case 0x98: case 0x99: case 0x9a: case 0x9b: case 0x9c: case 0x9d: case 0x9e: case 0x9f: case 0xa0: case 0xa1: case 0xa2: case 0xa3: case 0xa4: case 0xa5: case 0xa6: case 0xa7: case 0xa8: case 0xa9: case 0xaa: case 0xab: case 0xac: case 0xad: case 0xae: case 0xaf: case 0xb0: case 0xb1: case 0xb2: case 0xb3: case 0xb4: case 0xb5: case 0xb6: case 0xb7: case 0xb8: case 0xb9: case 0xba: case 0xbb: case 0xbc: case 0xbd: case 0xbe: case 0xbf: verboselog(machine, 11, " %04xxxxx: %d: CLUT[%d] = %08x\n", channel * 0x20, channel, mcd212->channel[channel].clut_bank * 0x40 + (reg - 0x80), value ); mcd212->channel[0].clut_r[mcd212->channel[channel].clut_bank * 0x40 + (reg - 0x80)] = (UINT8)(value >> 16) & 0xfc; mcd212->channel[0].clut_g[mcd212->channel[channel].clut_bank * 0x40 + (reg - 0x80)] = (UINT8)(value >> 8) & 0xfc; mcd212->channel[0].clut_b[mcd212->channel[channel].clut_bank * 0x40 + (reg - 0x80)] = (UINT8)(value >> 0) & 0xfc; break; case 0xc0: // Image Coding Method if(channel == 0) { verboselog(machine, 6, " %04xxxxx: %d: Image Coding Method = %08x\n", channel * 0x20, channel, value ); mcd212->channel[channel].image_coding_method = value; } break; case 0xc1: // Transparency Control if(channel == 0) { verboselog(machine, 6, " %04xxxxx: %d: Transparency Control = %08x\n", channel * 0x20, channel, value ); mcd212->channel[channel].transparency_control = value; } break; case 0xc2: // Plane Order if(channel == 0) { verboselog(machine, 6, " %04xxxxx: %d: Plane Order = %08x\n", channel * 0x20, channel, value & 7); mcd212->channel[channel].plane_order = value & 0x00000007; } break; case 0xc3: // CLUT Bank Register verboselog(machine, 6, " %04xxxxx: %d: CLUT Bank Register = %08x\n", channel * 0x20, channel, value & 3); mcd212->channel[channel].clut_bank = channel ? (2 | (value & 0x00000001)) : (value & 0x00000003); break; case 0xc4: // Transparent Color A if(channel == 0) { verboselog(machine, 6, " %04xxxxx: %d: Transparent Color A = %08x\n", channel * 0x20, channel, value ); mcd212->channel[channel].transparent_color_a = value & 0xfcfcfc; } break; case 0xc6: // Transparent Color B if(channel == 1) { verboselog(machine, 6, " %04xxxxx: %d: Transparent Color B = %08x\n", channel * 0x20, channel, value ); mcd212->channel[channel].transparent_color_b = value & 0xfcfcfc; } break; case 0xc7: // Mask Color A if(channel == 0) { verboselog(machine, 6, " %04xxxxx: %d: Mask Color A = %08x\n", channel * 0x20, channel, value ); mcd212->channel[channel].mask_color_a = value & 0xfcfcfc; } break; case 0xc9: // Mask Color B if(channel == 1) { verboselog(machine, 6, " %04xxxxx: %d: Mask Color B = %08x\n", channel * 0x20, channel, value ); mcd212->channel[channel].mask_color_b = value & 0xfcfcfc; } break; case 0xca: // Delta YUV Absolute Start Value A if(channel == 0) { verboselog(machine, 6, " %04xxxxx: %d: Delta YUV Absolute Start Value A = %08x\n", channel * 0x20, channel, value ); mcd212->channel[channel].dyuv_abs_start_a = value; } break; case 0xcb: // Delta YUV Absolute Start Value B if(channel == 1) { verboselog(machine, 6, " %04xxxxx: %d: Delta YUV Absolute Start Value B = %08x\n", channel * 0x20, channel, value ); mcd212->channel[channel].dyuv_abs_start_b = value; } break; case 0xcd: // Cursor Position if(channel == 0) { verboselog(machine, 6, " %04xxxxx: %d: Cursor Position = %08x\n", channel * 0x20, channel, value ); mcd212->channel[channel].cursor_position = value; } break; case 0xce: // Cursor Control if(channel == 0) { verboselog(machine, 11, " %04xxxxx: %d: Cursor Control = %08x\n", channel * 0x20, channel, value ); mcd212->channel[channel].cursor_control = value; } break; case 0xcf: // Cursor Pattern if(channel == 0) { verboselog(machine, 11, " %04xxxxx: %d: Cursor Pattern[%d] = %04x\n", channel * 0x20, channel, (value >> 16) & 0x000f, value & 0x0000ffff); mcd212->channel[channel].cursor_pattern[(value >> 16) & 0x000f] = value & 0x0000ffff; } break; case 0xd0: // Region Control 0-7 case 0xd1: case 0xd2: case 0xd3: case 0xd4: case 0xd5: case 0xd6: case 0xd7: verboselog(machine, 6, " %04xxxxx: %d: Region Control %d = %08x\n", channel * 0x20, channel, reg & 7, value ); mcd212->channel[0].region_control[reg & 7] = value; mcd212_update_region_arrays(mcd212); break; case 0xd8: // Backdrop Color if(channel == 0) { verboselog(machine, 6, " %04xxxxx: %d: Backdrop Color = %08x\n", channel * 0x20, channel, value ); mcd212->channel[channel].backdrop_color = value; } break; case 0xd9: // Mosaic Pixel Hold Factor A if(channel == 0) { verboselog(machine, 6, " %04xxxxx: %d: Mosaic Pixel Hold Factor A = %08x\n", channel * 0x20, channel, value ); mcd212->channel[channel].mosaic_hold_a = value; } break; case 0xda: // Mosaic Pixel Hold Factor B if(channel == 1) { verboselog(machine, 6, " %04xxxxx: %d: Mosaic Pixel Hold Factor B = %08x\n", channel * 0x20, channel, value ); mcd212->channel[channel].mosaic_hold_b = value; } break; case 0xdb: // Weight Factor A if(channel == 0) { verboselog(machine, 6, " %04xxxxx: %d: Weight Factor A = %08x\n", channel * 0x20, channel, value ); memset(mcd212->channel[channel].weight_factor_a, value & 0x000000ff, 768); mcd212_update_region_arrays(mcd212); } break; case 0xdc: // Weight Factor B if(channel == 1) { verboselog(machine, 6, " %04xxxxx: %d: Weight Factor B = %08x\n", channel * 0x20, channel, value ); memset(mcd212->channel[channel].weight_factor_b, value & 0x000000ff, 768); mcd212_update_region_arrays(mcd212); } break; } } static UINT32 mcd212_get_vsr(mcd212_regs_t *mcd212, int channel) { return ((mcd212->channel[channel].dcr & 0x3f) << 16) | mcd212->channel[channel].vsr; } static void mcd212_set_dcp(mcd212_regs_t *mcd212, int channel, UINT32 value) { mcd212->channel[channel].dcp = value & 0x0000ffff; mcd212->channel[channel].ddr &= 0xffc0; mcd212->channel[channel].ddr |= (value >> 16) & 0x003f; } static UINT32 mcd212_get_dcp(mcd212_regs_t *mcd212, int channel) { return ((mcd212->channel[channel].ddr & 0x3f) << 16) | mcd212->channel[channel].dcp; } static void mcd212_set_display_parameters(mcd212_regs_t *mcd212, int channel, UINT8 value) { mcd212->channel[channel].ddr &= 0xf0ff; mcd212->channel[channel].ddr |= (value & 0x0f) << 8; mcd212->channel[channel].dcr &= 0xf7ff; mcd212->channel[channel].dcr |= (value & 0x10) << 7; } static void mcd212_update_visible_area(running_machine &machine) { cdi_state *state = machine.driver_data(); mcd212_regs_t *mcd212 = &state->m_mcd212_regs; const rectangle &visarea = machine.primary_screen->visible_area(); rectangle visarea1; attoseconds_t period = machine.primary_screen->frame_period().attoseconds; int width = 0; if((mcd212->channel[0].dcr & (MCD212_DCR_CF | MCD212_DCR_FD)) && (mcd212->channel[0].csrw & MCD212_CSR1W_ST)) { width = 360; } else { width = 384; } visarea1.max_x = width-1; visarea1.min_x = visarea.min_x; visarea1.min_y = visarea.min_y; visarea1.max_y = visarea.max_y; machine.primary_screen->configure(width, 302, visarea1, period); } static UINT32 mcd212_get_screen_width(mcd212_regs_t *mcd212) { if((mcd212->channel[0].dcr & (MCD212_DCR_CF | MCD212_DCR_FD)) && (mcd212->channel[0].csrw & MCD212_CSR1W_ST)) { return 720; } return 768; } static void mcd212_process_ica(mcd212_regs_t *mcd212, int channel) { running_machine &machine = mcd212->machine(); cdi_state *state = machine.driver_data(); UINT16 *ica = channel ? state->m_planeb : state->m_planea; UINT32 addr = 0x000400/2; UINT32 cmd = 0; while(1) { UINT8 stop = 0; cmd = ica[addr++] << 16; cmd |= ica[addr++]; switch((cmd & 0xff000000) >> 24) { case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: // STOP case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: verboselog(machine, 11, "%08x: %08x: ICA %d: STOP\n", addr * 2 + channel * 0x200000, cmd, channel ); stop = 1; break; case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: // NOP case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f: verboselog(machine, 12, "%08x: %08x: ICA %d: NOP\n", addr * 2 + channel * 0x200000, cmd, channel ); break; case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27: // RELOAD DCP case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f: verboselog(machine, 11, "%08x: %08x: ICA %d: RELOAD DCP\n", addr * 2 + channel * 0x200000, cmd, channel ); mcd212_set_dcp(mcd212, channel, cmd & 0x001fffff); break; case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37: // RELOAD DCP and STOP case 0x38: case 0x39: case 0x3a: case 0x3b: case 0x3c: case 0x3d: case 0x3e: case 0x3f: verboselog(machine, 11, "%08x: %08x: ICA %d: RELOAD DCP and STOP\n", addr * 2 + channel * 0x200000, cmd, channel ); mcd212_set_dcp(mcd212, channel, cmd & 0x001fffff); stop = 1; break; case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47: // RELOAD ICA case 0x48: case 0x49: case 0x4a: case 0x4b: case 0x4c: case 0x4d: case 0x4e: case 0x4f: verboselog(machine, 11, "%08x: %08x: ICA %d: RELOAD ICA\n", addr * 2 + channel * 0x200000, cmd, channel ); addr = (cmd & 0x001fffff) / 2; break; case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57: // RELOAD VSR and STOP case 0x58: case 0x59: case 0x5a: case 0x5b: case 0x5c: case 0x5d: case 0x5e: case 0x5f: verboselog(machine, 11, "%08x: %08x: ICA %d: RELOAD VSR and STOP\n", addr * 2 + channel * 0x200000, cmd, channel ); mcd212_set_vsr(mcd212, channel, cmd & 0x001fffff); stop = 1; break; case 0x60: case 0x61: case 0x62: case 0x63: case 0x64: case 0x65: case 0x66: case 0x67: // INTERRUPT case 0x68: case 0x69: case 0x6a: case 0x6b: case 0x6c: case 0x6d: case 0x6e: case 0x6f: verboselog(machine, 11, "%08x: %08x: ICA %d: INTERRUPT\n", addr * 2 + channel * 0x200000, cmd, channel ); mcd212->channel[1].csrr |= 1 << (2 - channel); if(mcd212->channel[1].csrr & (MCD212_CSR2R_IT1 | MCD212_CSR2R_IT2)) { UINT8 interrupt = (state->m_scc68070_regs.lir >> 4) & 7; if(interrupt) { device_set_input_line_vector(machine.device("maincpu"), M68K_IRQ_1 + (interrupt - 1), 56 + interrupt); cputag_set_input_line(machine, "maincpu", M68K_IRQ_1 + (interrupt - 1), ASSERT_LINE); } } #if 0 if(mcd212->channel[1].csrr & MCD212_CSR2R_IT2) { UINT8 interrupt = state->m_scc68070_regs.lir & 7; if(interrupt) { device_set_input_line_vector(machine.device("maincpu"), M68K_IRQ_1 + (interrupt - 1), 24 + interrupt); cputag_set_input_line(machine, "maincpu", M68K_IRQ_1 + (interrupt - 1), ASSERT_LINE); } } #endif break; case 0x78: case 0x79: case 0x7a: case 0x7b: case 0x7c: case 0x7d: case 0x7e: case 0x7f: // RELOAD DISPLAY PARAMETERS verboselog(machine, 6, "%08x: %08x: ICA %d: RELOAD DISPLAY PARAMETERS\n", addr * 2 + channel * 0x200000, cmd, channel ); mcd212_set_display_parameters(mcd212, channel, cmd & 0x1f); break; default: mcd212_set_register(machine, channel, cmd >> 24, cmd & 0x00ffffff); break; } if(stop) { break; } } } static void mcd212_process_dca(mcd212_regs_t *mcd212, int channel) { running_machine &machine = mcd212->machine(); cdi_state *state = machine.driver_data(); UINT16 *dca = channel ? state->m_planeb : state->m_planea; UINT32 addr = (mcd212->channel[channel].dca & 0x0007ffff) / 2; //(mcd212_get_dcp(mcd212, channel) & 0x0007ffff) / 2; // mcd212->channel[channel].dca / 2; UINT32 cmd = 0; UINT32 count = 0; UINT32 max = 64; UINT8 addr_changed = 0; //printf( "max = %d\n", max ); while(1) { UINT8 stop = 0; cmd = dca[addr++] << 16; cmd |= dca[addr++]; count += 4; switch((cmd & 0xff000000) >> 24) { case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: // STOP case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: verboselog(machine, 11, "%08x: %08x: DCA %d: STOP\n", addr * 2 + channel * 0x200000, cmd, channel ); stop = 1; break; case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: // NOP case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f: verboselog(machine, 12, "%08x: %08x: DCA %d: NOP\n", addr * 2 + channel * 0x200000, cmd, channel ); break; case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27: // RELOAD DCP case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f: verboselog(machine, 11, "%08x: %08x: DCA %d: RELOAD DCP (NOP)\n", addr * 2 + channel * 0x200000, cmd, channel ); break; case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37: // RELOAD DCP and STOP case 0x38: case 0x39: case 0x3a: case 0x3b: case 0x3c: case 0x3d: case 0x3e: case 0x3f: verboselog(machine, 11, "%08x: %08x: DCA %d: RELOAD DCP and STOP\n", addr * 2 + channel * 0x200000, cmd, channel ); mcd212_set_dcp(&state->m_mcd212_regs, channel, cmd & 0x001fffff); addr = (cmd & 0x0007ffff) / 2; addr_changed = 1; stop = 1; break; case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47: // RELOAD VSR case 0x48: case 0x49: case 0x4a: case 0x4b: case 0x4c: case 0x4d: case 0x4e: case 0x4f: verboselog(machine, 11, "%08x: %08x: DCA %d: RELOAD VSR\n", addr * 2 + channel * 0x200000, cmd, channel ); mcd212_set_vsr(&state->m_mcd212_regs, channel, cmd & 0x001fffff); break; case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57: // RELOAD VSR and STOP case 0x58: case 0x59: case 0x5a: case 0x5b: case 0x5c: case 0x5d: case 0x5e: case 0x5f: verboselog(machine, 11, "%08x: %08x: DCA %d: RELOAD VSR and STOP\n", addr * 2 + channel * 0x200000, cmd, channel ); mcd212_set_vsr(&state->m_mcd212_regs, channel, cmd & 0x001fffff); stop = 1; break; case 0x60: case 0x61: case 0x62: case 0x63: case 0x64: case 0x65: case 0x66: case 0x67: // INTERRUPT case 0x68: case 0x69: case 0x6a: case 0x6b: case 0x6c: case 0x6d: case 0x6e: case 0x6f: verboselog(machine, 11, "%08x: %08x: DCA %d: INTERRUPT\n", addr * 2 + channel * 0x200000, cmd, channel ); mcd212->channel[1].csrr |= 1 << (2 - channel); if(mcd212->channel[1].csrr & (MCD212_CSR2R_IT1 | MCD212_CSR2R_IT2)) { UINT8 interrupt = (state->m_scc68070_regs.lir >> 4) & 7; if(interrupt) { device_set_input_line_vector(machine.device("maincpu"), M68K_IRQ_1 + (interrupt - 1), 56 + interrupt); cputag_set_input_line(machine, "maincpu", M68K_IRQ_1 + (interrupt - 1), ASSERT_LINE); } } #if 0 if(mcd212->channel[1].csrr & MCD212_CSR2R_IT2) { UINT8 interrupt = state->m_scc68070_regs.lir & 7; if(interrupt) { device_set_input_line_vector(machine.device("maincpu"), M68K_IRQ_1 + (interrupt - 1), 24 + interrupt); cputag_set_input_line(machine, "maincpu", M68K_IRQ_1 + (interrupt - 1), ASSERT_LINE); } } #endif break; case 0x78: case 0x79: case 0x7a: case 0x7b: case 0x7c: case 0x7d: case 0x7e: case 0x7f: // RELOAD DISPLAY PARAMETERS verboselog(machine, 6, "%08x: %08x: DCA %d: RELOAD DISPLAY PARAMETERS\n", addr * 2 + channel * 0x200000, cmd, channel ); mcd212_set_display_parameters(&state->m_mcd212_regs, channel, cmd & 0x1f); break; default: mcd212_set_register(machine, channel, cmd >> 24, cmd & 0x00ffffff); break; } if(stop != 0 || count == max) { break; } } if(!addr_changed) { if(count < max) { addr += (max - count) >> 1; } } mcd212->channel[channel].dca = addr * 2; } INLINE UINT8 MCD212_LIM(INT32 in) { if(in < 0) { return 0; } else if(in > 255) { return 255; } return (UINT8)in; } INLINE UINT8 BYTE_TO_CLUT(int channel, int icm, UINT8 byte) { switch(icm) { case 1: return byte; case 3: if(channel) { return 0x80 + (byte & 0x7f); } else { return byte & 0x7f; } case 4: if(!channel) { return byte & 0x7f; } break; case 11: if(channel) { return 0x80 + (byte & 0x0f); } else { return byte & 0x0f; } default: break; } return 0; } static void mcd212_process_vsr(mcd212_regs_t *mcd212, int channel, UINT8 *pixels_r, UINT8 *pixels_g, UINT8 *pixels_b) { running_machine &machine = mcd212->machine(); cdi_state *state = machine.driver_data(); UINT8 *data = channel ? (UINT8*)state->m_planeb : (UINT8*)state->m_planea; UINT32 vsr = mcd212_get_vsr(mcd212, channel) & 0x0007ffff; UINT8 done = 0; UINT32 x = 0; UINT32 icm_mask = channel ? MCD212_ICM_MODE2 : MCD212_ICM_MODE1; UINT32 icm_shift = channel ? MCD212_ICM_MODE2_SHIFT : MCD212_ICM_MODE1_SHIFT; UINT8 icm = (mcd212->channel[0].image_coding_method & icm_mask) >> icm_shift; UINT8 *clut_r = mcd212->channel[0].clut_r; UINT8 *clut_g = mcd212->channel[0].clut_g; UINT8 *clut_b = mcd212->channel[0].clut_b; UINT8 mosaic_enable = ((mcd212->channel[channel].ddr & MCD212_DDR_FT) == MCD212_DDR_FT_MOSAIC); UINT8 mosaic_factor = 1 << (((mcd212->channel[channel].ddr & MCD212_DDR_MT) >> MCD212_DDR_MT_SHIFT) + 1); int mosaic_index = 0; UINT32 width = mcd212_get_screen_width(mcd212); //printf( "vsr before: %08x: ", vsr ); //fflush(stdout); if(!icm || !vsr) { memset(pixels_r, 0x10, width); memset(pixels_g, 0x10, width); memset(pixels_b, 0x10, width); return; } while(!done) { UINT8 byte = data[(vsr & 0x0007ffff) ^ 1]; vsr++; switch(mcd212->channel[channel].ddr & MCD212_DDR_FT) { case MCD212_DDR_FT_BMP: case MCD212_DDR_FT_BMP2: case MCD212_DDR_FT_MOSAIC: if(mcd212->channel[channel].dcr & MCD212_DCR_CM) { // 4-bit Bitmap verboselog(machine, 0, "Unsupported display mode: 4-bit Bitmap\n" ); } else { // 8-bit Bitmap if(icm == 5) { BYTE68K bY; BYTE68K bU; BYTE68K bV; switch(channel) { case 0: bY = (mcd212->channel[0].dyuv_abs_start_a >> 16) & 0x000000ff; bU = (mcd212->channel[0].dyuv_abs_start_a >> 8) & 0x000000ff; bV = (mcd212->channel[0].dyuv_abs_start_a >> 0) & 0x000000ff; break; case 1: bY = (mcd212->channel[1].dyuv_abs_start_b >> 16) & 0x000000ff; bU = (mcd212->channel[1].dyuv_abs_start_b >> 8) & 0x000000ff; bV = (mcd212->channel[1].dyuv_abs_start_b >> 0) & 0x000000ff; break; default: bY = bU = bV = 0x80; break; } for(; x < width; x += 2) { BYTE68K b0 = byte; BYTE68K bU1 = bU + state->m_mcd212_ab.deltaUV[b0]; BYTE68K bY0 = bY + state->m_mcd212_ab.deltaY[b0]; BYTE68K b1 = data[(vsr & 0x0007ffff) ^ 1]; BYTE68K bV1 = bV + state->m_mcd212_ab.deltaUV[b1]; BYTE68K bY1 = bY0 + state->m_mcd212_ab.deltaY[b1]; BYTE68K bU0 = (bU + bU1) >> 1; BYTE68K bV0 = (bV + bV1) >> 1; BYTE68K *pbLimit; vsr++; bY = bY0; bU = bU0; bV = bV0; pbLimit = state->m_mcd212_ab.limit + bY + BYTE68K_MAX; pixels_r[x + 0] = pixels_r[x + 1] = pbLimit[state->m_mcd212_ab.matrixVR[bV]]; pixels_g[x + 0] = pixels_g[x + 1] = pbLimit[state->m_mcd212_ab.matrixUG[bU] + state->m_mcd212_ab.matrixVG[bV]]; pixels_b[x + 0] = pixels_b[x + 1] = pbLimit[state->m_mcd212_ab.matrixUB[bU]]; if(mosaic_enable) { for(mosaic_index = 0; mosaic_index < mosaic_factor; mosaic_index++) { pixels_r[x + 0 + mosaic_index*2] = pixels_r[x + 0]; pixels_g[x + 0 + mosaic_index*2] = pixels_g[x + 0]; pixels_b[x + 0 + mosaic_index*2] = pixels_b[x + 0]; pixels_r[x + 1 + mosaic_index*2] = pixels_r[x + 1]; pixels_g[x + 1 + mosaic_index*2] = pixels_g[x + 1]; pixels_b[x + 1 + mosaic_index*2] = pixels_b[x + 1]; } x += mosaic_factor * 2; } else { x += 2; } bY = bY1; bU = bU1; bV = bV1; pbLimit = state->m_mcd212_ab.limit + bY + BYTE68K_MAX; pixels_r[x + 0] = pixels_r[x + 1] = pbLimit[state->m_mcd212_ab.matrixVR[bV]]; pixels_g[x + 0] = pixels_g[x + 1] = pbLimit[state->m_mcd212_ab.matrixUG[bU] + state->m_mcd212_ab.matrixVG[bV]]; pixels_b[x + 0] = pixels_b[x + 1] = pbLimit[state->m_mcd212_ab.matrixUB[bU]]; if(mosaic_enable) { for(mosaic_index = 0; mosaic_index < mosaic_factor; mosaic_index++) { pixels_r[x + 0 + mosaic_index*2] = pixels_r[x + 0]; pixels_g[x + 0 + mosaic_index*2] = pixels_g[x + 0]; pixels_b[x + 0 + mosaic_index*2] = pixels_b[x + 0]; pixels_r[x + 1 + mosaic_index*2] = pixels_r[x + 1]; pixels_g[x + 1 + mosaic_index*2] = pixels_g[x + 1]; pixels_b[x + 1 + mosaic_index*2] = pixels_b[x + 1]; } x += (mosaic_factor * 2) - 2; } byte = data[(vsr & 0x0007ffff) ^ 1]; vsr++; } mcd212_set_vsr(&state->m_mcd212_regs, channel, (vsr - 1) & 0x0007ffff); } else if(icm == 1 || icm == 3 || icm == 4) { for(; x < width; x += 2) { UINT8 clut_entry = BYTE_TO_CLUT(channel, icm, byte); pixels_r[x + 0] = clut_r[clut_entry]; pixels_g[x + 0] = clut_g[clut_entry]; pixels_b[x + 0] = clut_b[clut_entry]; pixels_r[x + 1] = clut_r[clut_entry]; pixels_g[x + 1] = clut_g[clut_entry]; pixels_b[x + 1] = clut_b[clut_entry]; if(mosaic_enable) { for(mosaic_index = 0; mosaic_index < mosaic_factor; mosaic_index++) { pixels_r[x + 0 + mosaic_index*2] = pixels_r[x + 0]; pixels_g[x + 0 + mosaic_index*2] = pixels_g[x + 0]; pixels_b[x + 0 + mosaic_index*2] = pixels_b[x + 0]; pixels_r[x + 1 + mosaic_index*2] = pixels_r[x + 1]; pixels_g[x + 1 + mosaic_index*2] = pixels_g[x + 1]; pixels_b[x + 1 + mosaic_index*2] = pixels_b[x + 1]; } x += (mosaic_factor * 2) - 2; } byte = data[(vsr & 0x0007ffff) ^ 1]; vsr++; } mcd212_set_vsr(&state->m_mcd212_regs, channel, (vsr - 1) & 0x0007ffff); } else if(icm == 11) { for(; x < width; x += 2) { UINT8 even_entry = BYTE_TO_CLUT(channel, icm, byte >> 4); UINT8 odd_entry = BYTE_TO_CLUT(channel, icm, byte); if(mosaic_enable) { for(mosaic_index = 0; mosaic_index < mosaic_factor; mosaic_index++) { pixels_r[x + mosaic_index] = clut_r[even_entry]; pixels_g[x + mosaic_index] = clut_g[even_entry]; pixels_b[x + mosaic_index] = clut_b[even_entry]; } for(mosaic_index = 0; mosaic_index < mosaic_factor; mosaic_index++) { pixels_r[x + mosaic_factor + mosaic_index] = clut_r[odd_entry]; pixels_g[x + mosaic_factor + mosaic_index] = clut_g[odd_entry]; pixels_b[x + mosaic_factor + mosaic_index] = clut_b[odd_entry]; } x += (mosaic_factor * 2) - 2; } else { pixels_r[x + 0] = clut_r[even_entry]; pixels_g[x + 0] = clut_g[even_entry]; pixels_b[x + 0] = clut_b[even_entry]; pixels_r[x + 1] = clut_r[odd_entry]; pixels_g[x + 1] = clut_g[odd_entry]; pixels_b[x + 1] = clut_b[odd_entry]; } byte = data[(vsr & 0x0007ffff) ^ 1]; vsr++; } mcd212_set_vsr(&state->m_mcd212_regs, channel, (vsr - 1) & 0x0007ffff); } else { for(; x < width; x++) { pixels_r[x] = 0x10; pixels_g[x] = 0x10; pixels_b[x] = 0x10; } } } done = 1; break; case MCD212_DDR_FT_RLE: if(mcd212->channel[channel].dcr & MCD212_DCR_CM) { verboselog(machine, 0, "Unsupported display mode: 4-bit RLE\n" ); done = 1; } else { if(byte & 0x80) { // Run length UINT8 length = data[((vsr++) & 0x0007ffff) ^ 1]; if(!length) { UINT8 clut_entry = BYTE_TO_CLUT(channel, icm, byte); UINT8 r = clut_r[clut_entry]; UINT8 g = clut_g[clut_entry]; UINT8 b = clut_b[clut_entry]; // Go to the end of the line for(; x < width; x++) { pixels_r[x] = r; pixels_g[x] = g; pixels_b[x] = b; x++; pixels_r[x] = r; pixels_g[x] = g; pixels_b[x] = b; } done = 1; mcd212_set_vsr(&state->m_mcd212_regs, channel, vsr); } else { int end = x + (length * 2); UINT8 clut_entry = BYTE_TO_CLUT(channel, icm, byte); UINT8 r = clut_r[clut_entry]; UINT8 g = clut_g[clut_entry]; UINT8 b = clut_b[clut_entry]; for(; x < end && x < width; x++) { pixels_r[x] = r; pixels_g[x] = g; pixels_b[x] = b; x++; pixels_r[x] = r; pixels_g[x] = g; pixels_b[x] = b; } if(x >= width) { done = 1; mcd212_set_vsr(&state->m_mcd212_regs, channel, vsr); } } } else { // Single pixel UINT8 clut_entry = BYTE_TO_CLUT(channel, icm, byte); pixels_r[x] = clut_r[clut_entry]; pixels_g[x] = clut_g[clut_entry]; pixels_b[x] = clut_b[clut_entry]; x++; pixels_r[x] = clut_r[clut_entry]; pixels_g[x] = clut_g[clut_entry]; pixels_b[x] = clut_b[clut_entry]; x++; if(x >= width) { done = 1; mcd212_set_vsr(&state->m_mcd212_regs, channel, vsr); } } } break; } } //printf( ": vsr after: %08x\n", vsr); //mcd212_set_vsr(&state->m_mcd212_regs, channel, vsr); } static const UINT32 mcd212_4bpp_color[16] = { 0x00101010, 0x0010107a, 0x00107a10, 0x00107a7a, 0x007a1010, 0x007a107a, 0x007a7a10, 0x007a7a7a, 0x00101010, 0x001010e6, 0x0010e610, 0x0010e6e6, 0x00e61010, 0x00e610e6, 0x00e6e610, 0x00e6e6e6 }; static void mcd212_mix_lines(mcd212_regs_t *mcd212, UINT8 *plane_a_r, UINT8 *plane_a_g, UINT8 *plane_a_b, UINT8 *plane_b_r, UINT8 *plane_b_g, UINT8 *plane_b_b, UINT32 *out) { running_machine &machine = mcd212->machine(); int x = 0; UINT8 debug_mode = input_port_read(machine, "DEBUG"); UINT8 global_plane_a_disable = debug_mode & 1; UINT8 global_plane_b_disable = debug_mode & 2; UINT8 debug_backdrop_enable = debug_mode & 4; UINT8 debug_backdrop_index = debug_mode >> 4; UINT32 backdrop = debug_backdrop_enable ? mcd212_4bpp_color[debug_backdrop_index] : mcd212_4bpp_color[mcd212->channel[0].backdrop_color]; UINT8 transparency_mode_a = (mcd212->channel[0].transparency_control >> 0) & 0x0f; UINT8 transparency_mode_b = (mcd212->channel[0].transparency_control >> 8) & 0x0f; UINT8 transparent_color_a_r = (UINT8)(mcd212->channel[0].transparent_color_a >> 16); UINT8 transparent_color_a_g = (UINT8)(mcd212->channel[0].transparent_color_a >> 8); UINT8 transparent_color_a_b = (UINT8)(mcd212->channel[0].transparent_color_a >> 0); UINT8 transparent_color_b_r = (UINT8)(mcd212->channel[1].transparent_color_b >> 16); UINT8 transparent_color_b_g = (UINT8)(mcd212->channel[1].transparent_color_b >> 8); UINT8 transparent_color_b_b = (UINT8)(mcd212->channel[1].transparent_color_b >> 0); UINT8 image_coding_method_a = mcd212->channel[0].image_coding_method & 0x0000000f; UINT8 image_coding_method_b = (mcd212->channel[0].image_coding_method >> 8) & 0x0000000f; UINT8 dyuv_enable_a = (image_coding_method_a == 5); UINT8 dyuv_enable_b = (image_coding_method_b == 5); UINT8 mosaic_enable_a = (mcd212->channel[0].mosaic_hold_a & 0x800000) >> 23; UINT8 mosaic_enable_b = (mcd212->channel[1].mosaic_hold_b & 0x800000) >> 23; UINT8 mosaic_count_a = (mcd212->channel[0].mosaic_hold_a & 0x0000ff) << 1; UINT8 mosaic_count_b = (mcd212->channel[1].mosaic_hold_b & 0x0000ff) << 1; for(x = 0; x < 768; x++) { out[x] = backdrop; if(!(mcd212->channel[0].transparency_control & MCD212_TCR_DISABLE_MX)) { UINT8 abr = MCD212_LIM(((MCD212_LIM((INT32)plane_a_r[x] - 16) * mcd212->channel[0].weight_factor_a[x]) >> 6) + ((MCD212_LIM((INT32)plane_b_r[x] - 16) * mcd212->channel[1].weight_factor_b[x]) >> 6) + 16); UINT8 abg = MCD212_LIM(((MCD212_LIM((INT32)plane_a_g[x] - 16) * mcd212->channel[0].weight_factor_a[x]) >> 6) + ((MCD212_LIM((INT32)plane_b_g[x] - 16) * mcd212->channel[1].weight_factor_b[x]) >> 6) + 16); UINT8 abb = MCD212_LIM(((MCD212_LIM((INT32)plane_a_b[x] - 16) * mcd212->channel[0].weight_factor_a[x]) >> 6) + ((MCD212_LIM((INT32)plane_b_b[x] - 16) * mcd212->channel[1].weight_factor_b[x]) >> 6) + 16); out[x] = (abr << 16) | (abg << 8) | abb; } else { UINT8 plane_enable_a = 0; UINT8 plane_enable_b = 0; UINT8 plane_a_r_cur = mosaic_enable_a ? plane_a_r[x - (x % mosaic_count_a)] : plane_a_r[x]; UINT8 plane_a_g_cur = mosaic_enable_a ? plane_a_g[x - (x % mosaic_count_a)] : plane_a_g[x]; UINT8 plane_a_b_cur = mosaic_enable_a ? plane_a_b[x - (x % mosaic_count_a)] : plane_a_b[x]; UINT8 plane_b_r_cur = mosaic_enable_b ? plane_b_r[x - (x % mosaic_count_b)] : plane_b_r[x]; UINT8 plane_b_g_cur = mosaic_enable_b ? plane_b_g[x - (x % mosaic_count_b)] : plane_b_g[x]; UINT8 plane_b_b_cur = mosaic_enable_b ? plane_b_b[x - (x % mosaic_count_b)] : plane_b_b[x]; switch(transparency_mode_a) { case 0: plane_enable_a = 0; break; case 1: plane_enable_a = (plane_a_r_cur != transparent_color_a_r || plane_a_g_cur != transparent_color_a_g || plane_a_b_cur != transparent_color_a_b); break; case 3: plane_enable_a = !mcd212->region_flag_0[x]; break; case 4: plane_enable_a = !mcd212->region_flag_1[x]; break; case 5: plane_enable_a = (plane_a_r_cur != transparent_color_a_r || plane_a_g_cur != transparent_color_a_g || plane_a_b_cur != transparent_color_a_b) && (dyuv_enable_a || mcd212->region_flag_0[x] == 0); break; case 6: plane_enable_a = (plane_a_r_cur != transparent_color_a_r || plane_a_g_cur != transparent_color_a_g || plane_a_b_cur != transparent_color_a_b) && (dyuv_enable_a || mcd212->region_flag_1[x] == 0); break; case 8: plane_enable_a = 1; break; case 9: plane_enable_a = (plane_a_r_cur == transparent_color_a_r && plane_a_g_cur == transparent_color_a_g && plane_a_b_cur == transparent_color_a_b); break; case 11: plane_enable_a = mcd212->region_flag_0[x]; break; case 12: plane_enable_a = mcd212->region_flag_1[x]; break; case 13: plane_enable_a = (plane_a_r_cur == transparent_color_a_r && plane_a_g_cur == transparent_color_a_g && plane_a_b_cur == transparent_color_a_b) || dyuv_enable_a || mcd212->region_flag_0[x] == 1; break; case 14: plane_enable_a = (plane_a_r_cur == transparent_color_a_r && plane_a_g_cur == transparent_color_a_g && plane_a_b_cur == transparent_color_a_b) || dyuv_enable_a || mcd212->region_flag_1[x] == 1; break; default: verboselog(machine, 0, "Unhandled transparency mode for plane A: %d\n", transparency_mode_a); plane_enable_a = 1; break; } switch(transparency_mode_b) { case 0: plane_enable_b = 0; break; case 1: plane_enable_b = (plane_b_r_cur != transparent_color_b_r || plane_b_g_cur != transparent_color_b_g || plane_b_b_cur != transparent_color_b_b); break; case 3: plane_enable_b = !mcd212->region_flag_0[x]; break; case 4: plane_enable_b = !mcd212->region_flag_1[x]; break; case 5: plane_enable_b = (plane_b_r_cur != transparent_color_b_r || plane_b_g_cur != transparent_color_b_g || plane_b_b_cur != transparent_color_b_b) && (dyuv_enable_b || mcd212->region_flag_0[x] == 0); break; case 6: plane_enable_b = (plane_b_r_cur != transparent_color_b_r || plane_b_g_cur != transparent_color_b_g || plane_b_b_cur != transparent_color_b_b) && (dyuv_enable_b || mcd212->region_flag_1[x] == 0); break; case 8: plane_enable_b = 1; break; case 9: plane_enable_b = (plane_b_r_cur == transparent_color_b_r && plane_b_g_cur == transparent_color_b_g && plane_b_b_cur == transparent_color_b_b); break; case 11: plane_enable_b = mcd212->region_flag_0[x]; break; case 12: plane_enable_b = mcd212->region_flag_1[x]; break; case 13: plane_enable_b = (plane_b_r_cur == transparent_color_b_r && plane_b_g_cur == transparent_color_b_g && plane_b_b_cur == transparent_color_b_b) || dyuv_enable_b || mcd212->region_flag_0[x] == 1; break; case 14: plane_enable_b = (plane_b_r_cur == transparent_color_b_r && plane_b_g_cur == transparent_color_b_g && plane_b_b_cur == transparent_color_b_b) || dyuv_enable_b || mcd212->region_flag_1[x] == 1; break; default: verboselog(machine, 0, "Unhandled transparency mode for plane B: %d\n", transparency_mode_b); plane_enable_b = 1; break; } if(global_plane_a_disable) { plane_enable_a = 0; } if(global_plane_b_disable) { plane_enable_b = 0; } plane_a_r_cur = MCD212_LIM(((MCD212_LIM((INT32)plane_a_r_cur - 16) * mcd212->channel[0].weight_factor_a[x]) >> 6) + 16); plane_a_g_cur = MCD212_LIM(((MCD212_LIM((INT32)plane_a_g_cur - 16) * mcd212->channel[0].weight_factor_a[x]) >> 6) + 16); plane_a_b_cur = MCD212_LIM(((MCD212_LIM((INT32)plane_a_b_cur - 16) * mcd212->channel[0].weight_factor_a[x]) >> 6) + 16); plane_b_r_cur = MCD212_LIM(((MCD212_LIM((INT32)plane_b_r_cur - 16) * mcd212->channel[1].weight_factor_b[x]) >> 6) + 16); plane_b_g_cur = MCD212_LIM(((MCD212_LIM((INT32)plane_b_g_cur - 16) * mcd212->channel[1].weight_factor_b[x]) >> 6) + 16); plane_b_b_cur = MCD212_LIM(((MCD212_LIM((INT32)plane_b_b_cur - 16) * mcd212->channel[1].weight_factor_b[x]) >> 6) + 16); switch(mcd212->channel[0].plane_order) { case MCD212_POR_AB: if(plane_enable_a) { out[x] = (plane_a_r_cur << 16) | (plane_a_g_cur << 8) | plane_a_b_cur; } else if(plane_enable_b) { out[x] = (plane_b_r_cur << 16) | (plane_b_g_cur << 8) | plane_b_b_cur; } break; case MCD212_POR_BA: if(plane_enable_b) { out[x] = (plane_b_r_cur << 16) | (plane_b_g_cur << 8) | plane_b_b_cur; } else if(plane_enable_a) { out[x] = (plane_a_r_cur << 16) | (plane_a_g_cur << 8) | plane_a_b_cur; } break; } } } } static void mcd212_draw_cursor(mcd212_regs_t *mcd212, UINT32 *scanline, int y) { if(mcd212->channel[0].cursor_control & MCD212_CURCNT_EN) { UINT16 curx = mcd212->channel[0].cursor_position & 0x3ff; UINT16 cury = ((mcd212->channel[0].cursor_position >> 12) & 0x3ff) + 22; UINT32 x = 0; if(y >= cury && y < (cury + 16)) { UINT32 color = mcd212_4bpp_color[mcd212->channel[0].cursor_control & MCD212_CURCNT_COLOR]; y -= cury; if(mcd212->channel[0].cursor_control & MCD212_CURCNT_CUW) { for(x = curx; x < curx + 64 && x < 768; x++) { if(mcd212->channel[0].cursor_pattern[y] & (1 << (15 - ((x - curx) >> 2)))) { scanline[(x++)/2] = color; scanline[(x++)/2] = color; scanline[(x++)/2] = color; scanline[(x/2)] = color; } else { } } } else { for(x = curx; x < curx + 32 && x < 768; x++) { if(mcd212->channel[0].cursor_pattern[y] & (1 << (15 - ((x - curx) >> 1)))) { scanline[(x++)/2] = color; scanline[x/2] = color; } else { } } } } } } static void mcd212_draw_scanline(mcd212_regs_t *mcd212, int y) { running_machine &machine = mcd212->machine(); bitmap_t *bitmap = machine.generic.tmpbitmap; UINT8 plane_a_r[768], plane_a_g[768], plane_a_b[768]; UINT8 plane_b_r[768], plane_b_g[768], plane_b_b[768]; UINT32 out[768]; UINT32 *scanline = BITMAP_ADDR32(bitmap, y, 0); int x; mcd212_process_vsr(mcd212, 0, plane_a_r, plane_a_g, plane_a_b); mcd212_process_vsr(mcd212, 1, plane_b_r, plane_b_g, plane_b_b); mcd212_mix_lines(mcd212, plane_a_r, plane_a_g, plane_a_b, plane_b_r, plane_b_g, plane_b_b, out); for(x = 0; x < 384; x++) { scanline[x] = out[x*2]; } mcd212_draw_cursor(mcd212, scanline, y); } READ16_HANDLER( mcd212_r ) { cdi_state *state = space->machine().driver_data(); mcd212_regs_t *mcd212 = &state->m_mcd212_regs; UINT8 channel = 1 - (offset / 8); switch(offset) { case 0x00/2: case 0x10/2: if(ACCESSING_BITS_0_7) { verboselog(space->machine(), 12, "mcd212_r: Status Register %d: %02x & %04x\n", channel + 1, mcd212->channel[1 - (offset / 8)].csrr, mem_mask); if(channel == 0) { return mcd212->channel[0].csrr; } else { UINT8 old_csr = mcd212->channel[1].csrr; UINT8 interrupt1 = (state->m_scc68070_regs.lir >> 4) & 7; //UINT8 interrupt2 = state->m_scc68070_regs.lir & 7; mcd212->channel[1].csrr &= ~(MCD212_CSR2R_IT1 | MCD212_CSR2R_IT2); if(interrupt1) { cputag_set_input_line(space->machine(), "maincpu", M68K_IRQ_1 + (interrupt1 - 1), CLEAR_LINE); } //if(interrupt2) //{ // cputag_set_input_line(space->machine(), "maincpu", M68K_IRQ_1 + (interrupt2 - 1), CLEAR_LINE); //} return old_csr; } } else { verboselog(space->machine(), 2, "mcd212_r: Unknown Register %d: %04x\n", channel + 1, mem_mask); } break; case 0x02/2: case 0x12/2: verboselog(space->machine(), 2, "mcd212_r: Display Command Register %d: %04x & %04x\n", (1 - (offset / 8)) + 1, mcd212->channel[1 - (offset / 8)].dcr, mem_mask); return mcd212->channel[1 - (offset / 8)].dcr; case 0x04/2: case 0x14/2: verboselog(space->machine(), 2, "mcd212_r: Video Start Register %d: %04x & %04x\n", (1 - (offset / 8)) + 1, mcd212->channel[1 - (offset / 8)].vsr, mem_mask); return mcd212->channel[1 - (offset / 8)].vsr; case 0x08/2: case 0x18/2: verboselog(space->machine(), 2, "mcd212_r: Display Decoder Register %d: %04x & %04x\n", (1 - (offset / 8)) + 1, mcd212->channel[1 - (offset / 8)].ddr, mem_mask); return mcd212->channel[1 - (offset / 8)].ddr; case 0x0a/2: case 0x1a/2: verboselog(space->machine(), 2, "mcd212_r: DCA Pointer Register %d: %04x & %04x\n", (1 - (offset / 8)) + 1, mcd212->channel[1 - (offset / 8)].dcp, mem_mask); return mcd212->channel[1 - (offset / 8)].dcp; default: verboselog(space->machine(), 2, "mcd212_r: Unknown Register %d & %04x\n", (1 - (offset / 8)) + 1, mem_mask); break; } return 0; } WRITE16_HANDLER( mcd212_w ) { cdi_state *state = space->machine().driver_data(); mcd212_regs_t *mcd212 = &state->m_mcd212_regs; switch(offset) { case 0x00/2: case 0x10/2: verboselog(space->machine(), 2, "mcd212_w: Status Register %d: %04x & %04x\n", (1 - (offset / 8)) + 1, data, mem_mask); COMBINE_DATA(&mcd212->channel[1 - (offset / 8)].csrw); mcd212_update_visible_area(space->machine()); break; case 0x02/2: case 0x12/2: verboselog(space->machine(), 2, "mcd212_w: Display Command Register %d: %04x & %04x\n", (1 - (offset / 8)) + 1, data, mem_mask); COMBINE_DATA(&mcd212->channel[1 - (offset / 8)].dcr); mcd212_update_visible_area(space->machine()); break; case 0x04/2: case 0x14/2: verboselog(space->machine(), 2, "mcd212_w: Video Start Register %d: %04x & %04x\n", (1 - (offset / 8)) + 1, data, mem_mask); COMBINE_DATA(&mcd212->channel[1 - (offset / 8)].vsr); break; case 0x08/2: case 0x18/2: verboselog(space->machine(), 2, "mcd212_w: Display Decoder Register %d: %04x & %04x\n", (1 - (offset / 8)) + 1, data, mem_mask); COMBINE_DATA(&mcd212->channel[1 - (offset / 8)].ddr); break; case 0x0a/2: case 0x1a/2: verboselog(space->machine(), 2, "mcd212_w: DCA Pointer Register %d: %04x & %04x\n", (1 - (offset / 8)) + 1, data, mem_mask); COMBINE_DATA(&mcd212->channel[1 - (offset / 8)].dcp); break; default: verboselog(space->machine(), 2, "mcd212_w: Unknown Register %d: %04x & %04x\n", (1 - (offset / 8)) + 1, data, mem_mask); break; } } TIMER_CALLBACK( mcd212_perform_scan ) { cdi_state *state = machine.driver_data(); mcd212_regs_t *mcd212 = &state->m_mcd212_regs; int scanline = machine.primary_screen->vpos(); if(/*mcd212->channel[0].dcr & MCD212_DCR_DE*/1) { if(scanline == 0) { // Process ICA int index = 0; verboselog(machine, 6, "Frame Start\n" ); mcd212->channel[0].csrr &= 0x7f; for(index = 0; index < 2; index++) { if(mcd212->channel[index].dcr & MCD212_DCR_ICA) { mcd212_process_ica(mcd212, index); } } cdi220_draw_lcd(machine, scanline); } else if(scanline < 22) { cdi220_draw_lcd(machine, scanline); } else if(scanline >= 22) { int index = 0; mcd212->channel[0].csrr |= 0x80; // Process VSR mcd212_draw_scanline(mcd212, scanline); // Process DCA for(index = 0; index < 2; index++) { if(mcd212->channel[index].dcr & MCD212_DCR_DCA) { if(scanline == 22) { mcd212->channel[index].dca = mcd212_get_dcp(mcd212, index); } mcd212_process_dca(mcd212, index); } } if(scanline == 301) { mcd212->channel[0].csrr ^= 0x20; } } } mcd212->scan_timer->adjust(machine.primary_screen->time_until_pos(( scanline + 1 ) % 302, 0)); } void mcd212_init(running_machine &machine, mcd212_regs_t *mcd212) { mcd212->m_machine = &machine; int index = 0; for(index = 0; index < 2; index++) { mcd212->channel[index].csrr = 0; mcd212->channel[index].csrw = 0; mcd212->channel[index].dcr = 0; mcd212->channel[index].vsr = 0; mcd212->channel[index].ddr = 0; mcd212->channel[index].dcp = 0; mcd212->channel[index].dca = 0; memset(mcd212->channel[index].clut_r, 0, 768); memset(mcd212->channel[index].clut_g, 0, 768); memset(mcd212->channel[index].clut_b, 0, 768); mcd212->channel[index].image_coding_method = 0; mcd212->channel[index].transparency_control = 0; mcd212->channel[index].plane_order = 0; mcd212->channel[index].clut_bank = 0; mcd212->channel[index].transparent_color_a = 0; mcd212->channel[index].transparent_color_b = 0; mcd212->channel[index].mask_color_a = 0; mcd212->channel[index].mask_color_b = 0; mcd212->channel[index].dyuv_abs_start_a = 0; mcd212->channel[index].dyuv_abs_start_b = 0; mcd212->channel[index].cursor_position = 0; mcd212->channel[index].cursor_control = 0; memset((UINT8*)&mcd212->channel[index].cursor_pattern, 0, 16 * sizeof(UINT32)); memset((UINT8*)&mcd212->channel[index].region_control, 0, 8 * sizeof(UINT32)); mcd212->channel[index].backdrop_color = 0; mcd212->channel[index].mosaic_hold_a = 0; mcd212->channel[index].mosaic_hold_b = 0; memset(mcd212->channel[index].weight_factor_a, 0, 768); memset(mcd212->channel[index].weight_factor_b, 0, 768); } memset(mcd212->region_flag_0, 0, 768); memset(mcd212->region_flag_1, 0, 768); state_save_register_global_array(machine, mcd212->region_flag_0); state_save_register_global_array(machine, mcd212->region_flag_1); state_save_register_global(machine, mcd212->channel[0].csrr); state_save_register_global(machine, mcd212->channel[0].csrw); state_save_register_global(machine, mcd212->channel[0].dcr); state_save_register_global(machine, mcd212->channel[0].vsr); state_save_register_global(machine, mcd212->channel[0].ddr); state_save_register_global(machine, mcd212->channel[0].dcp); state_save_register_global(machine, mcd212->channel[0].dca); state_save_register_global_array(machine, mcd212->channel[0].clut_r); state_save_register_global_array(machine, mcd212->channel[0].clut_g); state_save_register_global_array(machine, mcd212->channel[0].clut_b); state_save_register_global(machine, mcd212->channel[0].image_coding_method); state_save_register_global(machine, mcd212->channel[0].transparency_control); state_save_register_global(machine, mcd212->channel[0].plane_order); state_save_register_global(machine, mcd212->channel[0].clut_bank); state_save_register_global(machine, mcd212->channel[0].transparent_color_a); state_save_register_global(machine, mcd212->channel[0].transparent_color_b); state_save_register_global(machine, mcd212->channel[0].mask_color_a); state_save_register_global(machine, mcd212->channel[0].mask_color_b); state_save_register_global(machine, mcd212->channel[0].dyuv_abs_start_a); state_save_register_global(machine, mcd212->channel[0].dyuv_abs_start_b); state_save_register_global(machine, mcd212->channel[0].cursor_position); state_save_register_global(machine, mcd212->channel[0].cursor_control); state_save_register_global_array(machine, mcd212->channel[0].cursor_pattern); state_save_register_global_array(machine, mcd212->channel[0].region_control); state_save_register_global(machine, mcd212->channel[0].backdrop_color); state_save_register_global(machine, mcd212->channel[0].mosaic_hold_a); state_save_register_global(machine, mcd212->channel[0].mosaic_hold_b); state_save_register_global_array(machine, mcd212->channel[0].weight_factor_a); state_save_register_global_array(machine, mcd212->channel[0].weight_factor_b); state_save_register_global(machine, mcd212->channel[1].csrr); state_save_register_global(machine, mcd212->channel[1].csrw); state_save_register_global(machine, mcd212->channel[1].dcr); state_save_register_global(machine, mcd212->channel[1].vsr); state_save_register_global(machine, mcd212->channel[1].ddr); state_save_register_global(machine, mcd212->channel[1].dcp); state_save_register_global(machine, mcd212->channel[1].dca); state_save_register_global_array(machine, mcd212->channel[1].clut_r); state_save_register_global_array(machine, mcd212->channel[1].clut_g); state_save_register_global_array(machine, mcd212->channel[1].clut_b); state_save_register_global(machine, mcd212->channel[1].image_coding_method); state_save_register_global(machine, mcd212->channel[1].transparency_control); state_save_register_global(machine, mcd212->channel[1].plane_order); state_save_register_global(machine, mcd212->channel[1].clut_bank); state_save_register_global(machine, mcd212->channel[1].transparent_color_a); state_save_register_global(machine, mcd212->channel[1].transparent_color_b); state_save_register_global(machine, mcd212->channel[1].mask_color_a); state_save_register_global(machine, mcd212->channel[1].mask_color_b); state_save_register_global(machine, mcd212->channel[1].dyuv_abs_start_a); state_save_register_global(machine, mcd212->channel[1].dyuv_abs_start_b); state_save_register_global(machine, mcd212->channel[1].cursor_position); state_save_register_global(machine, mcd212->channel[1].cursor_control); state_save_register_global_array(machine, mcd212->channel[1].cursor_pattern); state_save_register_global_array(machine, mcd212->channel[1].region_control); state_save_register_global(machine, mcd212->channel[1].backdrop_color); state_save_register_global(machine, mcd212->channel[1].mosaic_hold_a); state_save_register_global(machine, mcd212->channel[1].mosaic_hold_b); state_save_register_global_array(machine, mcd212->channel[1].weight_factor_a); state_save_register_global_array(machine, mcd212->channel[1].weight_factor_b); } void mcd212_ab_init(mcd212_ab_t *mcd212_ab) { WORD68K w = 0; SWORD68K sw = 0; WORD68K d = 0; //* Delta decoding array. static const BYTE68K mcd212_abDelta[16] = { 0, 1, 4, 9, 16, 27, 44, 79, 128, 177, 212, 229, 240, 247, 252, 255 }; // Initialize delta decoding arrays for each unsigned byte value b. for (d = 0; d < BYTE68K_MAX + 1; d++) { mcd212_ab->deltaY[d] = mcd212_abDelta[d & 15]; } // Initialize delta decoding arrays for each unsigned byte value b. for (d = 0; d < (BYTE68K_MAX + 1); d++) { mcd212_ab->deltaUV[d] = mcd212_abDelta[d >> 4]; } // Initialize color limit and clamp arrays. for (w = 0; w < 3 * BYTE68K_MAX; w++) { mcd212_ab->limit[w] = (w < BYTE68K_MAX + 16) ? 0 : w <= 16 + 2 * BYTE68K_MAX ? w - BYTE68K_MAX - 16 : BYTE68K_MAX; mcd212_ab->clamp[w] = (w < BYTE68K_MAX + 32) ? 16 : w <= 16 + 2 * BYTE68K_MAX ? w - BYTE68K_MAX - 16 : BYTE68K_MAX; } for (sw = 0; sw < 0x100; sw++) { mcd212_ab->matrixUB[sw] = (444 * (sw - 128)) / 256; mcd212_ab->matrixUG[sw] = - (86 * (sw - 128)) / 256; mcd212_ab->matrixVG[sw] = - (179 * (sw - 128)) / 256; mcd212_ab->matrixVR[sw] = (351 * (sw - 128)) / 256; } } VIDEO_START( cdimono1 ) { cdi_state *state = machine.driver_data(); VIDEO_START_CALL(generic_bitmapped); mcd212_ab_init(&state->m_mcd212_ab); mcd212_init(machine, &state->m_mcd212_regs); state->m_mcd212_regs.scan_timer = machine.scheduler().timer_alloc(FUNC(mcd212_perform_scan)); state->m_mcd212_regs.scan_timer->adjust(machine.primary_screen->time_until_pos(0, 0)); state->m_lcdbitmap = downcast(machine.device("lcd"))->alloc_compatible_bitmap(); } SCREEN_UPDATE( cdimono1 ) { copybitmap(bitmap, screen->machine().generic.tmpbitmap, 0, 0, 0, 0, cliprect); return 0; } SCREEN_UPDATE( cdimono1_lcd ) { cdi_state *state = screen->machine().driver_data(); copybitmap(bitmap, state->m_lcdbitmap, 0, 0, 0, 0, cliprect); return 0; }