diff --git a/src/devices/machine/ldp1450hle.cpp b/src/devices/machine/ldp1450hle.cpp index ad48d4379c0fc..3129780344f19 100644 --- a/src/devices/machine/ldp1450hle.cpp +++ b/src/devices/machine/ldp1450hle.cpp @@ -1,4 +1,5 @@ // license:BSD-3-Clause +// copyright-holders:J.Wallace /************************************************************************* @@ -12,7 +13,7 @@ To do: - * On-screen display support (we just popmessage the data) + * On-screen display support needs aligning with real hardware * Better CLV support * Chapter-search support * Repeat support (we only store the command) @@ -23,12 +24,13 @@ - Leadout Symbol - OSD - Status Requests - - UI text display (Nova games, DL2 need this) * Repeat behaviour for reverse play should restart in reverse * Delay timing of queue is a guess based on LDP1000A guide * Not all features are fully hooked up * Still step back and forth in Time Traveler glitches - (level select doesn't stay in place) + * resizing, positioning of OSD bitmaps is not optimal + - 16x16 is supported, but native size and location may be wrong *************************************************************************/ #include "emu.h" @@ -47,7 +49,7 @@ #define LOG_ALL (LOG_COMMAND_BYTES | LOG_COMMANDS | LOG_COMMAND_BUFFERS | LOG_REPLY_BYTES | LOG_SEARCHES | LOG_STOPS | LOG_SQUELCHES | LOG_FRAMES) -#define VERBOSE 0 +#define VERBOSE (LOG_COMMANDS) #include "logmacro.h" @@ -91,6 +93,244 @@ sony_ldp1450hle_device::sony_ldp1450hle_device(const machine_config &mconfig, co { } +static const u8 text_size[0x04] = +{ + 16, + 32, + 48, + 64 +}; + +// bitmaps for the characters +static const u16 text_bitmap[0x60][0x10] = +{ + { 0 }, + { 0 }, + { 0 }, + { 0 }, + { 0 }, + { 0 }, + { 0 }, + { 0 }, + { 0 }, + { 0 }, + { 0 }, + { 0 }, + { 0 }, + { 0 }, + { 0 }, + { 0 }, + { 0 }, + { 0 }, + { 0 }, + { 0 }, + { 0 }, + { 0 }, + { 0 }, + { 0 }, + { 0 }, + { 0 }, + { 0 }, + { 0 }, + { 0 }, + { 0 }, + { 0 }, + { 0 }, + { 0 }, // + {0x0000,0x0000,0x00c0,0x00c0,0x00c0,0x00c0,0x00c0,0x00c0,0x00c0,0x00c0,0x00c0,0x00c0,0x0000,0x0000,0x00c0,0x00c0},// ! + { 0 }, + { 0 }, + { 0 }, + { 0 }, + {0x0000,0x0000,0x00f0,0x01f8,0x039c,0x038c,0x01cc,0x00fc,0x30fc,0x3878,0x1cf8,0x0fcc,0x0786,0x0787,0x3ffe,0x3cfc}, // & + {0x0000,0x0000,0x03c0,0x03c0,0x0300,0x0380,0x01c0,0x00c0,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000}, // ' + {0x0000,0x0000,0x3000,0x3800,0x1c00,0x0c00,0x0c00,0x0c00,0x0c00,0x0c00,0x0c00,0x0c00,0x0c00,0x1c00,0x3800,0x3000}, // ( + {0x0000,0x0000,0x00c0,0x01c0,0x0380,0x0300,0x0300,0x0300,0x0300,0x0300,0x0300,0x0300,0x0300,0x0380,0x01c0,0x00c0}, // ) + {0x0000,0x0000,0x0000,0x0000,0x0c00,0x0c00,0xccc0,0xedc0,0x7f80,0x3f00,0x3f00,0x7f80,0xedc0,0xccc0,0x0c00,0x0c00}, // * + {0x0000,0x0000,0x0000,0x0000,0x0300,0x0300,0x0300,0x0300,0x3ff0,0x3ff0,0x0300,0x0300,0x0300,0x0300,0x0000,0x0000}, // + + {0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x03c0,0x03c0,0x0300,0x0380,0x01c0,0x00c0}, // , + {0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x1ff8,0x1ff8,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000}, // - + {0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x03c0,0x03c0,0x03c0,0x03c0}, // . + {0x0000,0x0000,0xc000,0xe000,0x7000,0x3800,0x1c00,0x0e00,0x0700,0x0380,0x01c0,0x00e0,0x0070,0x0038,0x001c,0x000c}, // / + {0x0000,0x0000,0x3fc0,0x7fe0,0xe070,0xc030,0xc030,0xc030,0xc030,0xc030,0xc030,0xc030,0xc030,0xe070,0x7fe0,0x3fc0}, // 0 + {0x0000,0x0000,0x0c00,0x0c00,0x0fc0,0x0fc0,0x0c00,0x0c00,0x0c00,0x0c00,0x0c00,0x0c00,0x0c00,0x0c00,0x0c00,0x0c00}, // 1 + {0x0000,0x0000,0x0ff0,0x1ff8,0x381c,0x300c,0x3000,0x3800,0x1fc0,0x0fe0,0x0070,0x0038,0x001c,0x000c,0x3ffc,0x3ffc}, // 2 + {0x0000,0x0000,0x0ff0,0x1ff8,0x381c,0x300c,0x3000,0x3800,0x1fc0,0x1fc0,0x3800,0x3000,0x300c,0x381c,0x1ff8,0x0ff0}, // 3 + {0x0000,0x0000,0x0f00,0x0f80,0x0dc0,0x0ce0,0x0c70,0x0c38,0x0c1c,0x0c0c,0x0c0c,0x0c0c,0x3ffc,0x3ffc,0x0c00,0x0c00}, // 4 + {0x0000,0x0000,0x3ffc,0x3ffc,0x000c,0x000c,0x0ffc,0x1ffc,0x3800,0x3000,0x3000,0x3000,0x300c,0x381c,0x1ff8,0x0ff0}, // 5 + {0x0000,0x0000,0x0ff0,0x1ff8,0x381c,0x300c,0x000c,0x000c,0x0ffc,0x1ffc,0x300c,0x300c,0x300c,0x381c,0x1ff8,0x0ff0}, // 6 + {0x0000,0x0000,0x3ffc,0x3ffc,0x3000,0x3800,0x1c00,0x0e00,0x0700,0x0300,0x0300,0x0300,0x0300,0x0300,0x0300,0x0300}, // 7 + {0x0000,0x0000,0x0ff0,0x1ff8,0x381c,0x300c,0x300c,0x381c,0x1ff8,0x1ff8,0x381c,0x300c,0x300c,0x381c,0x1ff8,0x0ff0}, // 8 + {0x0000,0x0000,0x0ff0,0x1ff8,0x381c,0x300c,0x300c,0x301c,0x3ff8,0x3ff0,0x3000,0x3000,0x300c,0x381c,0x1ff8,0x0ff0}, // 9 + {0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0180,0x0180,0x0000,0x0000,0x0180,0x0180,0x0000,0x0000,0x0000,0x0000}, // : + { 0 }, + { 0 }, + {0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x1ff8,0x1ff8,0x0000,0x1ff8,0x1ff8,0x0000,0x0000,0x0000,0x0000}, // = + { 0 }, + {0x0000,0x0000,0x0ff0,0x1ff8,0x381c,0x300c,0x3000,0x3800,0x1c00,0x0e00,0x0700,0x0300,0x0000,0x0000,0x0300,0x0300}, // ? + { 0 }, + {0x0000,0x0000,0x03c0,0x07e0,0x0e70,0x1c38,0x381c,0x300c,0x300c,0x300c,0x3ffc,0x3ffc,0x300c,0x300c,0x300c,0x300c}, // A + {0x0000,0x0000,0x1ffe,0x3ffe,0x7018,0x6018,0x6018,0x7018,0x3ff8,0x3ff8,0x7018,0x6018,0x6018,0x7018,0x3ffe,0x1ffe}, // B + {0x0000,0x0000,0x3fc0,0x7fe0,0xe070,0xc030,0x0030,0x0030,0x0030,0x0030,0x0030,0x0030,0xc030,0xe070,0x7fe0,0x3fc0}, // C + {0x0000,0x0000,0x1ffe,0x3ffe,0x7018,0x6018,0x6018,0x6018,0x6018,0x6018,0x6018,0x6018,0x6018,0x7018,0x3ffe,0x1ffe}, // D + {0x0000,0x0000,0x3ffc,0x3ffc,0x000c,0x000c,0x000c,0x000c,0x0ffc,0x0ffc,0x000c,0x000c,0x000c,0x000c,0x3ffc,0x3ffc}, // E + {0x0000,0x0000,0x3ffc,0x3ffc,0x000c,0x000c,0x000c,0x000c,0x0ffc,0x0ffc,0x000c,0x000c,0x000c,0x000c,0x000c,0x000c}, // F + {0x0000,0x0000,0x3fc0,0x7fe0,0xe070,0xc030,0x0030,0x0030,0xfc30,0xfc30,0xc030,0xc030,0xc030,0xe070,0x7fe0,0x3fc0}, // G + {0x0000,0x0000,0x300c,0x300c,0x300c,0x300c,0x300c,0x300c,0x3ffc,0x3ffc,0x300c,0x300c,0x300c,0x300c,0x300c,0x300c}, // H + {0x0000,0x0000,0x07e0,0x07e0,0x0180,0x0180,0x0180,0x0180,0x0180,0x0180,0x0180,0x0180,0x0180,0x0180,0x07e0,0x07e0}, // I + {0x0000,0x0000,0x3f00,0x3f00,0x0c00,0x0c00,0x0c00,0x0c00,0x0c00,0x0c00,0x0c0c,0x0c0c,0x0c0c,0x0e1c,0x07f8,0x03f0}, // J + {0x0000,0x0000,0x300c,0x380c,0x1c0c,0x0e0c,0x070c,0x038c,0x01fc,0x01fc,0x038c,0x070c,0x0e0c,0x1c0c,0x380c,0x300c}, // K + {0x0000,0x0000,0x000c,0x000c,0x000c,0x000c,0x000c,0x000c,0x000c,0x000c,0x000c,0x000c,0x000c,0x000c,0x3ffc,0x3ffc}, // L + {0x0000,0x0000,0x6006,0x6006,0x781e,0x7c3e,0x6e76,0x67e6,0x63c6,0x6186,0x6186,0x6186,0x6006,0x6006,0x6006,0x6006}, // M + {0x0000,0x0000,0x300c,0x300c,0x301c,0x303c,0x307c,0x30ec,0x31cc,0x338c,0x370c,0x3e0c,0x3c0c,0x380c,0x300c,0x300c}, // N + {0x0000,0x0000,0x3fc0,0x7fe0,0xe070,0xc030,0xc030,0xc030,0xc030,0xc030,0xc030,0xc030,0xc030,0xe070,0x7fe0,0x3fc0}, // O + {0x0000,0x0000,0x0ffc,0x1ffc,0x380c,0x300c,0x300c,0x380c,0x1ffc,0x0ffc,0x000c,0x000c,0x000c,0x000c,0x000c,0x000c}, // P + {0x0000,0x0000,0x0ff0,0x1ff8,0x381c,0x300c,0x300c,0x300c,0x300c,0x300c,0x330c,0x3f0c,0x1e0c,0x1e1c,0x3ff8,0x33f0}, // Q + {0x0000,0x0000,0x0ffc,0x1ffc,0x380c,0x300c,0x300c,0x380c,0x1ffc,0x0ffc,0x030c,0x070c,0x0e0c,0x1c0c,0x380c,0x300c}, // R + {0x0000,0x0000,0x0ff0,0x1ff8,0x381c,0x300c,0x000c,0x001c,0x0ff8,0x1ff0,0x3800,0x3000,0x300c,0x381c,0x1ff8,0x0ff0}, // S + {0x0000,0x0000,0x7ffe,0x7ffe,0x0180,0x0180,0x0180,0x0180,0x0180,0x0180,0x0180,0x0180,0x0180,0x0180,0x0180,0x0180}, // T + {0x0000,0x0000,0x300c,0x300c,0x300c,0x300c,0x300c,0x300c,0x300c,0x300c,0x300c,0x300c,0x300c,0x300c,0x1ff8,0x0ff0}, // U + {0x0000,0x0000,0x300c,0x300c,0x300c,0x300c,0x300c,0x300c,0x300c,0x300c,0x300c,0x381c,0x1c38,0x0e70,0x07e0,0x03c0}, // V + {0x0000,0x0000,0x6006,0x6006,0x6006,0x6006,0x6006,0x6186,0x6186,0x6186,0x6186,0x63c6,0x67e6,0x7e7e,0x3c3c,0x1818}, // W + {0x0000,0x0000,0x6006,0x700e,0x381c,0x1c38,0x0e70,0x07e0,0x03c0,0x03c0,0x07e0,0x0e70,0x1c38,0x381c,0x700e,0x6006}, // X + {0x0000,0x0000,0x6006,0x700e,0x381c,0x1c38,0x0e70,0x07e0,0x03c0,0x0180,0x0180,0x0180,0x0180,0x0180,0x0180,0x0180}, // Y + {0x0000,0x0000,0x3ffc,0x3ffc,0x1c00,0x0e00,0x0700,0x0380,0x01c0,0x00e0,0x0070,0x0038,0x001c,0x000c,0x3ffc,0x3ffc}, // Z + { 0 }, // + { 0 }, // + { 0 }, // + { 0 }, // + {0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x1ff8,0x1ff8,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000}, // - +}; + +#define OVERLAY_PIXEL_WIDTH 1+(1.3f / 720.0f) +#define OVERLAY_PIXEL_HEIGHT 1 + +//------------------------------------------------- +// overlay_draw_group - draw a single group of +// characters +//------------------------------------------------- + +void sony_ldp1450hle_device::overlay_fill(bitmap_yuy16 &bitmap, uint8_t yval, uint8_t cr, uint8_t cb) +{ + uint16_t color0 = (yval << 8) | cb; + uint16_t color1 = (yval << 8) | cr; + + // write 32 bits of color (2 pixels at a time) + for (int y = 0; y < bitmap.height(); y++) + { + uint16_t *dest = &bitmap.pix(y); + for (int x = 0; x < bitmap.width() / 2; x++) + { + *dest++ = color0; + *dest++ = color1; + } + } +} + +void sony_ldp1450hle_device::overlay_draw_group(bitmap_yuy16 &bitmap, const uint8_t *text, int start, int xstart, int ystart, int mode) +{ + u8 char_width = text_size[m_user_index_mode & 0x03]; + + u8 char_height = text_size[(m_user_index_mode >> 2) & 0x03]; + + float xstart_normalised = (bitmap.width()/2/ 64) * xstart; + float ystart_normalised = (bitmap.height()/ 64) * ystart; + + if (m_user_index_mode & 0x80) //blue screen + { + overlay_fill(bitmap, 0x28, 0x6d, 0xf0); + } + + u8 count; + if (m_user_index_mode & 0x10) // 3 line mode + { + LOGMASKED(LOG_COMMANDS, "3 Line\n"); + int x = 0; + for (int y = 0; y < 3; y++) + { + bool eos = false; + for (int char_idx = x; char_idx < (x+10); char_idx++) + { + if (text[char_idx] == 0x1a || eos) + { + eos = true; + x -= 9;// adjust pointer to account for the + 10 we do automatically + break; + } + else + { + overlay_draw_char(bitmap, text[char_idx], xstart_normalised + (char_width * (char_idx %10)), ystart_normalised + (y*char_height), char_width, char_height); + } + } + x += 10; + } + } + else + { + count = 0x20 - start; + LOGMASKED(LOG_COMMANDS, "1 Line\n"); + + for (int x = start; x < count; x++) + { + if (text[x] == 0x1a) + { + break; + } + else + { + overlay_draw_char(bitmap, text[x], xstart_normalised + ((char_width) * x), ystart_normalised, char_width, char_height); + } + } + } +} + + +//------------------------------------------------- +// overlay_draw_char - draw a single character +// of the text overlay +//------------------------------------------------- + +void sony_ldp1450hle_device::overlay_draw_char(bitmap_yuy16 &bitmap, uint8_t ch, float xstart, int ystart, int char_width, int char_height) +{ + + // m_user_index_mode >> 5 & 0x04: 0,2 = normal, 1 = 1px shadow, 3 = grey box + uint16_t black = 0x0080; + + u8 modeval= (m_user_index_mode >> 5) & 0x04; + + for (u32 y = 0; y < char_height; y++) + { + for (u8 x = 0; x < char_width; x++) + { + u32 xmin = xstart + x; + for (u32 yy = 0; yy < OVERLAY_PIXEL_HEIGHT; yy++) + { + + for (u32 xx = 0; xx < OVERLAY_PIXEL_WIDTH; xx++) + { + if (modeval==0x03) + { + //fill with grey + } + + if (m_osd_font[ch].pix(y,x) != black) + { + bitmap.pix(ystart + (y + 1) * OVERLAY_PIXEL_HEIGHT + yy, xmin+xx) = m_osd_font[ch].pix(y,x); + } + } + } + } + } +} + +void sony_ldp1450hle_device::player_overlay(bitmap_yuy16 &bitmap) +{ + if (m_user_index_flag) + { + overlay_draw_group(bitmap, m_user_index_chars, m_user_index_window_idx, m_user_index_x, m_user_index_y, m_user_index_mode); + } +} + void sony_ldp1450hle_device::queue_reply(u8 reply, float delay) { @@ -148,93 +388,109 @@ void sony_ldp1450hle_device::add_command_byte(u8 command) { switch (m_submode) { - case SUBMODE_USER_INDEX: - switch (command) + case SUBMODE_USER_INDEX: { - case 0x00: - m_submode = SUBMODE_USER_INDEX_MODE_1; - queue_reply(0x0a, 4.3); + switch (command) + { + case 0x00: + { + m_submode = SUBMODE_USER_INDEX_MODE_1; + queue_reply(0x0a, 4.3); + break; + } + case 0x01: + { + m_submode = SUBMODE_USER_INDEX_STRING_1; + queue_reply(0x0a, 4.3); + break; + } + case 0x02: + { + m_submode = SUBMODE_USER_INDEX_WINDOW; + queue_reply(0x0a, 4.3); + break; + } + } break; - case 0x01: - m_submode = SUBMODE_USER_INDEX_STRING_1; + } + case SUBMODE_USER_INDEX_MODE_1: + { + m_user_index_x = (command & 0x3f); + + LOGMASKED(LOG_COMMANDS, "User Index X: %02x\n", m_user_index_x); + + m_submode = SUBMODE_USER_INDEX_MODE_2; queue_reply(0x0a, 4.3); break; - case 0x02: - m_submode = SUBMODE_USER_INDEX_WINDOW; + } + case SUBMODE_USER_INDEX_MODE_2: + { + m_user_index_y = (command & 0x3f); + LOGMASKED(LOG_COMMANDS, "User Index Y: %02x\n", m_user_index_y); + m_submode = SUBMODE_USER_INDEX_MODE_3; queue_reply(0x0a, 4.3); break; } - break; - - case SUBMODE_USER_INDEX_MODE_1: - m_user_index_x = (command & 0x3f); - m_submode = SUBMODE_USER_INDEX_MODE_2; - queue_reply(0x0a, 4.3); - break; - - case SUBMODE_USER_INDEX_MODE_2: - m_user_index_y = (command & 0x3f); - m_submode = SUBMODE_USER_INDEX_MODE_3; - queue_reply(0x0a, 4.3); - break; - - case SUBMODE_USER_INDEX_MODE_3: - m_user_index_mode = command; - m_submode = SUBMODE_NORMAL; - queue_reply(0x0a, 4.3); - break; - - case SUBMODE_USER_INDEX_STRING_1: - m_user_index_char_idx = (command & 0x1f); - m_submode = SUBMODE_USER_INDEX_STRING_2; - queue_reply(0x0a, 4.3); - break; - - case SUBMODE_USER_INDEX_STRING_2: - m_user_index_chars[m_user_index_char_idx] = (char)(command & 0x5f); - if (command == 0x1a) + case SUBMODE_USER_INDEX_MODE_3: { + m_user_index_mode = command; + LOGMASKED(LOG_COMMANDS, "User Index Mode: %02x\n", m_user_index_mode); m_submode = SUBMODE_NORMAL; + queue_reply(0x0a, 4.3); + break; } - else + case SUBMODE_USER_INDEX_STRING_1: + { + m_user_index_char_idx = (command & 0x1f); + LOGMASKED(LOG_COMMANDS, "User Index Charpos: %02x\n", m_user_index_char_idx); + m_submode = SUBMODE_USER_INDEX_STRING_2; + queue_reply(0x0a, 4.3); + break; + } + case SUBMODE_USER_INDEX_STRING_2: { - m_user_index_char_idx++; - if (m_user_index_char_idx > 32) + m_user_index_chars[m_user_index_char_idx] = (command); + LOGMASKED(LOG_COMMANDS, "User Index char idx %x: %02x ('%c')\n", m_user_index_char_idx, command, command); + + if (command == 0x1a) { - m_user_index_char_idx = 0; + m_submode = SUBMODE_NORMAL; } + else + { + m_user_index_char_idx++; + if (m_user_index_char_idx > 32) + { + m_user_index_char_idx = 0; + } + } + queue_reply(0x0a, 4.3); + break; + } + case SUBMODE_USER_INDEX_WINDOW: + { + m_user_index_window_idx = (command & 0x1f); + LOGMASKED(LOG_COMMANDS, "User Index Window idx: %02x\n", m_user_index_window_idx); + m_submode = SUBMODE_NORMAL; + queue_reply(0x0a, 4.3); + break; } - queue_reply(0x0a, 4.3); - break; - - case SUBMODE_USER_INDEX_WINDOW: - m_user_index_window_idx = (command & 0x1f); - m_submode = SUBMODE_NORMAL; - queue_reply(0x0a, 4.3); - break; default: if (command >= 0x30 && command <=0x39) { - if (m_mode == MODE_SEARCH_CMD || m_mode == MODE_REPEAT_CMD_MARK || m_mode == MODE_REPEAT_CMD_REPS || m_mode == MODE_MS_FORWARD || m_mode == MODE_MS_REVERSE) + // Reset flags + if (m_cmd_buffer == -2) { - // Reset flags - if (m_cmd_buffer == -2) - { - m_cmd_buffer = 0; - } - - if (m_cmd_buffer != 0) - { - m_cmd_buffer *= 10; - } - m_cmd_buffer += (command - 0x30); - queue_reply(0x0a, 4.3); + m_cmd_buffer = 0; } - else + + if (m_cmd_buffer != 0) { - queue_reply(0x0b, 4.3); + m_cmd_buffer *= 10; } + m_cmd_buffer += (command - 0x30); + queue_reply(0x0a, 4.3); } else { @@ -451,16 +707,18 @@ void sony_ldp1450hle_device::add_command_byte(u8 command) case CMD_CLEAR_ALL: m_cmd_buffer = 0; - m_search_frame = 0; + m_search_frame = m_curr_frame; m_search_chapter = 0; m_repeat_chapter_start = 0; m_repeat_frame_start = 0; m_repeat_chapter_end = 0; m_repeat_frame_end = 0; m_repeat_repetitions = 0; + m_speed = m_base_speed; - m_mode = MODE_STILL; - queue_reply(0x0a, 5.5); + m_submode = SUBMODE_NORMAL; + m_mode = MODE_PLAY; + queue_reply(0x0a, 5.5); break; case CMD_CH1_ON: @@ -536,6 +794,11 @@ void sony_ldp1450hle_device::add_command_byte(u8 command) } break; + case CMD_MOTOR_ON: + //Presume we're already running + queue_reply(0x0b, 0.4); + break; + case CMD_STATUS_INQ: { u8 status_buffer[5] = { 0x80, 0x00, 0x10, 0x00, 0xff}; @@ -558,13 +821,18 @@ void sony_ldp1450hle_device::add_command_byte(u8 command) break; case CMD_USER_INDEX_ON: - popmessage("X %x Y %x M%x T%s (Start %x)", m_user_index_x, m_user_index_y, m_user_index_mode, m_user_index_chars,m_user_index_window_idx); - queue_reply(0x0a, 0.4); - break; + { + m_user_index_flag = true; + queue_reply(0x0a, 0.4); + break; + } case CMD_USER_INDEX_OFF: - queue_reply(0x0a, 0.4); - break; + { + m_user_index_flag = false; + queue_reply(0x0a, 0.4); + break; + } default: popmessage("no implementation cmd %x", command); @@ -573,6 +841,7 @@ void sony_ldp1450hle_device::add_command_byte(u8 command) } } LOGMASKED(LOG_SEARCHES, "Command %x\n", command); + } } @@ -627,6 +896,35 @@ void sony_ldp1450hle_device::update_video_enable() } +bitmap_yuy16 sony_ldp1450hle_device::osd_char_gen(uint8_t idx) +{ + uint16_t white = 0xeb80; + uint16_t black = 0x0080; + + // iterate over pixels + const u16 *chdataptr = &text_bitmap[idx][0]; + + bitmap_yuy16 char_bmp = bitmap_yuy16(16,16); + for (u8 y = 0; y < 16; y++) + { + u16 chdata = *chdataptr++; + + for (u8 x = 0; x < 16; x++, chdata >>= 1) + { + if (chdata & 0x01) + { + char_bmp.pix(y, x) = white; + } + else + { + char_bmp.pix(y, x) = black; + } + } + } + return char_bmp; +} + + //------------------------------------------------- // device_start - device initialization //------------------------------------------------- @@ -669,6 +967,21 @@ void sony_ldp1450hle_device::device_start() save_item(NAME(m_repeat_chapter_end)); save_item(NAME(m_repeat_frame_start)); save_item(NAME(m_repeat_frame_end)); + + save_item(NAME(m_user_index_flag)); + save_item(NAME(m_user_index_x)); + save_item(NAME(m_user_index_y)); + save_item(NAME(m_user_index_mode)); + save_item(NAME(m_user_index_char_idx)); + save_item(NAME(m_user_index_window_idx)); + save_item(NAME(m_user_index_chars)); + + + for (u8 chr_idx = 0; chr_idx < 96; chr_idx ++) + { + m_osd_font[chr_idx] = osd_char_gen(chr_idx); + } + } @@ -715,6 +1028,7 @@ void sony_ldp1450hle_device::device_reset() m_base_speed = 60; m_speed = m_base_speed; m_speed_accum = 0; + m_user_index_flag = false; video_enable(true); set_audio_squelch(true, true); @@ -740,10 +1054,10 @@ TIMER_CALLBACK_MEMBER(sony_ldp1450hle_device::process_vbi_data) m_curr_frame = bcd_to_literal(line & 0x7ffff); LOGMASKED(LOG_FRAMES, "Current frame is %d (VBI 16: %06x, VBI 17: %06x, VBI 18: %06x, VBI 1718: %06x\n", m_curr_frame, - get_field_code(LASERDISC_CODE_LINE16, false), - get_field_code(LASERDISC_CODE_LINE17, false), - get_field_code(LASERDISC_CODE_LINE18, false), - line); + get_field_code(LASERDISC_CODE_LINE16, false), + get_field_code(LASERDISC_CODE_LINE17, false), + get_field_code(LASERDISC_CODE_LINE18, false), + line); if (m_mode != MODE_STILL && m_mode != MODE_PAUSE) { diff --git a/src/devices/machine/ldp1450hle.h b/src/devices/machine/ldp1450hle.h index 22f71ce6a544e..d5c07bd8a366b 100644 --- a/src/devices/machine/ldp1450hle.h +++ b/src/devices/machine/ldp1450hle.h @@ -1,4 +1,5 @@ // license:BSD-3-Clause +// copyright-holders:J.Wallace /************************************************************************* @@ -50,7 +51,7 @@ class sony_ldp1450hle_device : public laserdisc_device, public device_serial_int // laserdisc_device implementation virtual void player_vsync(const vbi_metadata &vbi, int fieldnum, const attotime &curtime) override; virtual s32 player_update(const vbi_metadata &vbi, int fieldnum, const attotime &curtime) override; - virtual void player_overlay(bitmap_yuy16 &bitmap) override { } + virtual void player_overlay(bitmap_yuy16 &bitmap) override; // device_serial_interface implementation virtual void rcv_complete() override; @@ -60,6 +61,12 @@ class sony_ldp1450hle_device : public laserdisc_device, public device_serial_int TIMER_CALLBACK_MEMBER(process_vbi_data); TIMER_CALLBACK_MEMBER(process_queue); + // internal overlay helpers + void overlay_draw_group(bitmap_yuy16 &bitmap, const uint8_t *text, int start, int xstart, int ystart, int mode); + void overlay_draw_char(bitmap_yuy16 &bitmap, uint8_t ch, float xstart, int ystart, int char_width, int char_height); + void overlay_fill(bitmap_yuy16 &bitmap, uint8_t yval, uint8_t cr, uint8_t cb); + bitmap_yuy16 osd_char_gen(uint8_t idx); + private: enum player_command : u16 { @@ -98,6 +105,7 @@ class sony_ldp1450hle_device : public laserdisc_device, public device_serial_int CMD_FRAME_SET =0x55, CMD_CLEAR_ALL =0x56, CMD_ADDR_INQ =0x60, + CMD_MOTOR_ON =0x62, CMD_STATUS_INQ =0x67, CMD_CHAPTER_SET =0x69, CMD_USER_INDEX_CTRL =0x80, @@ -186,13 +194,15 @@ class sony_ldp1450hle_device : public laserdisc_device, public device_serial_int u32 m_speed_accum; u32 m_curr_frame; - u8 m_user_index_x; - u8 m_user_index_y; - u8 m_user_index_mode; - u8 m_user_index_char_idx; - u8 m_user_index_window_idx; - char m_user_index_chars[32]; - + bool m_user_index_flag; + u8 m_user_index_x=0; + u8 m_user_index_y=0; + u8 m_user_index_mode=0; + u8 m_user_index_char_idx=0; + u8 m_user_index_window_idx=0; + u8 m_user_index_chars[32]; + bitmap_yuy16 m_osd_font[96]; + }; #endif // MAME_MACHINE_LDP1450HLE_H diff --git a/src/mame/atari/cops.cpp b/src/mame/atari/cops.cpp index b2e1c54dcba85..8cb313bd83c18 100644 --- a/src/mame/atari/cops.cpp +++ b/src/mame/atari/cops.cpp @@ -11,10 +11,10 @@ where the laserdisc audio is muted. The different games here have subtly different control PCBs. COPS has an Atari - part number (58-12B), while Revelations simply refers to a Lasermax control PCB + part number (58-12B), while Revelations and Vision Quest simply refers to a Lasermax control PCB (Lasermax being the consumer name for the LDP series). COPS, Street Viper and all other Nova Productions laserdisc games run on forms of this - hardware. + hardware, with Vision Quest being the earliest we emulate. NOTES: To init NVRAM on Revelations at first boot, turn the refill key (R) and press any button. A and B adjust date/time (clock is not Y2K compliant), C selects. @@ -22,10 +22,7 @@ Let it boot up to REFILL mode, and then turn the refill key off. TODO: There are probably more ROMs for Revelations and related, the disc - contains full data for a non-payout US release of the game called 'Vision Quest'. - However, the Vision Quest Laserdisc for the USA is slightly different, with - Revelations specific data seemingly replaced with black level. - We have a disc image for Vision Quest in full, but no ROM + contains full data for a memory based quiz BTANB for Revelations: Game options cannot be adjusted, any attempt to do so resets the machine (seen on real hardware) @@ -45,6 +42,7 @@ #include "machine/meters.h" #include "machine/msm6242.h" #include "machine/nvram.h" +#include "machine/mos6551.h" #include "machine/r65c52.h" #include "machine/watchdog.h" #include "sound/sn76496.h" @@ -53,6 +51,7 @@ #include "cops.lh" #include "revlatns.lh" +#include "visnqust.lh" #define LOG_CDROM (1U << 1) @@ -64,6 +63,7 @@ namespace { #define MAIN_CLOCK 4_MHz_XTAL #define DACIA_CLOCK 3.6864_MHz_XTAL +#define ACIA_CLOCK 1.8432_MHz_XTAL class cops_state : public driver_device { @@ -75,6 +75,7 @@ class cops_state : public driver_device , m_sn(*this, "snsnd") , m_ld(*this, "laserdisc") , m_dacia(*this, "dacia") + , m_acia(*this, "acia") , m_watchdog(*this, "watchdog") , m_meters(*this, "meters") , m_switches(*this, "SW%u", 0U) @@ -87,12 +88,17 @@ class cops_state : public driver_device { } void revlatns(machine_config &config); + void visnqust(machine_config &config); void base(machine_config &config); + void acia_comms(machine_config &config); + void dacia_comms(machine_config &config); void cops(machine_config &config); void cops_map(address_map &map) ATTR_COLD; void revlatns_map(address_map &map) ATTR_COLD; + void visnqust_map(address_map &map) ATTR_COLD; void init_cops(); + void init_vquest(); protected: // driver_device overrides @@ -111,6 +117,7 @@ class cops_state : public driver_device uint8_t io2_r(offs_t offset); void acia1_irq(int state); void acia2_irq(int state); + void vqacia_irq(int state); void dacia_irq(); void via1_irq(int state); void via2_irq(int state); @@ -127,7 +134,8 @@ class cops_state : public driver_device required_shared_ptr m_nvram; required_device m_sn; required_device m_ld; - required_device m_dacia; + optional_device m_dacia; + optional_device m_acia; required_device m_watchdog; optional_device m_meters; @@ -182,6 +190,18 @@ uint8_t cops_state::cdrom_data_r() return machine().rand()&0xff; } +/************************************* + * + * 6551 ACIA - IRQ is normal + * + *************************************/ +void cops_state::vqacia_irq(int state) +{ + m_acia1_irq = state; + dacia_irq(); +} + + /************************************* * * 6552 DACIA - IRQs are inverted @@ -190,7 +210,7 @@ uint8_t cops_state::cdrom_data_r() void cops_state::acia1_irq(int state) { - m_acia1_irq =! state; + m_acia1_irq = !state; dacia_irq(); } @@ -202,6 +222,7 @@ void cops_state::acia2_irq(int state) inline void cops_state::dacia_irq() { + logerror("IRQ %x\n", m_acia1_irq); m_maincpu->set_input_line(INPUT_LINE_NMI, (m_acia1_irq | m_acia2_irq) ? ASSERT_LINE : CLEAR_LINE); } @@ -231,10 +252,11 @@ uint8_t cops_state::io1_cops_r(offs_t offset) uint8_t cops_state::io1_r(offs_t offset) { + // logerror("io1_r, offset = %03x\n", offset); switch( offset & 0x0f ) { - case 0x01: /* SW0 */ - return m_switches[0]->read(); + // case 0x01: /* SW0 */ + // return m_switches[0]->read(); case 0x07: /* WOP7 - watchdog*/ return 1; case 0x08: /* SW0 */ @@ -301,6 +323,7 @@ void cops_state::io1_cops_w(offs_t offset, uint8_t data) break; case 0x07: /* WOP7 - watchdog*/ m_watchdog->reset_w(data); + break; default: logerror("Unknown io1_w, offset = %03x, data = %02x\n", offset, data); @@ -526,6 +549,17 @@ void cops_state::revlatns_map(address_map &map) map(0xe000, 0xffff).bankr("sysbank1"); } +void cops_state::visnqust_map(address_map &map) +{ + map(0x0000, 0x1fff).ram().share(m_nvram); + map(0x2000, 0x9fff).rom().region("program", 0); + map(0xa000, 0xafff).rw(FUNC(cops_state::io1_r), FUNC(cops_state::io1_w)); + map(0xb000, 0xb00f).m("via6522_1", FUNC(via6522_device::map)); + map(0xc000, 0xc00f).noprw(); //Still writes to RTC, but doesn't seem to use it + map(0xd000, 0xd003).m(m_acia, FUNC(mos6551_device::map)); + map(0xe000, 0xffff).bankr("sysbank1"); +} + static INPUT_PORTS_START( cops ) PORT_START("SW0") PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_OTHER ) PORT_NAME("Switch A") PORT_CODE(KEYCODE_A) PORT_IMPULSE(1) @@ -585,6 +619,38 @@ static INPUT_PORTS_START( revlatns ) PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_UNUSED ) //Left floating, games will fail to boot if this is low INPUT_PORTS_END +static INPUT_PORTS_START( visnqust ) + PORT_START("SW0") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_NAME("A") + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_NAME("C") + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_COIN1 ) //COIN5 + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_SERVICE ) PORT_IMPULSE(1) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_COIN2 ) // COIN6 + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_NAME("B") + + PORT_START("SW1") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_BUTTON5 ) PORT_NAME("*") + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_INTERLOCK) PORT_NAME("Back Door") PORT_CODE(KEYCODE_W) PORT_TOGGLE + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNUSED ) + + PORT_START("SW2") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNUSED ) +INPUT_PORTS_END + void cops_state::machine_start() { m_digits.resolve(); @@ -627,20 +693,35 @@ void cops_state::base(machine_config &config) SPEAKER(config, "mspeaker").front_center(); - R65C52(config, m_dacia, DACIA_CLOCK); - m_dacia->txd1_handler().set("laserdisc", FUNC(sony_ldp1450hle_device::rx_w)); - m_dacia->irq1_handler().set(FUNC(cops_state::acia1_irq)); - m_dacia->irq2_handler().set(FUNC(cops_state::acia2_irq)); - SN76489(config, m_sn, MAIN_CLOCK/2); m_sn->add_route(ALL_OUTPUTS, "mspeaker", 0.30); WATCHDOG_TIMER(config, "watchdog").set_time(attotime::from_msec(1600)); } +void cops_state::acia_comms(machine_config &config) +{ + MOS6551(config, m_acia, 0).set_xtal(ACIA_CLOCK); + m_acia->txd_handler().set("laserdisc", FUNC(sony_ldp1450hle_device::rx_w)); + m_acia->rts_handler().set("acia", FUNC(mos6551_device::write_cts)); + m_acia->irq_handler().set(FUNC(cops_state::vqacia_irq)); + m_ld->serial_tx().set("acia", FUNC(mos6551_device::write_rxd)); +} + +void cops_state::dacia_comms(machine_config &config) +{ + R65C52(config, m_dacia, DACIA_CLOCK); + m_dacia->txd1_handler().set("laserdisc", FUNC(sony_ldp1450hle_device::rx_w)); + m_dacia->rts1_handler().set("dacia", FUNC(r65c52_device::write_cts1)); + m_dacia->irq1_handler().set(FUNC(cops_state::acia1_irq)); + m_dacia->irq2_handler().set(FUNC(cops_state::acia2_irq)); + m_ld->serial_tx().set("dacia", FUNC(r65c52_device::write_rxd1)); +} + void cops_state::cops(machine_config &config) { base(config); + dacia_comms(config); m_maincpu->set_addrmap(AS_PROGRAM, &cops_state::cops_map); @@ -663,10 +744,10 @@ void cops_state::cops(machine_config &config) void cops_state::revlatns(machine_config &config) { base(config); + dacia_comms(config); m_maincpu->set_addrmap(AS_PROGRAM, &cops_state::revlatns_map); - /* via */ via6522_device &via1(MOS6522(config, "via6522_1", MAIN_CLOCK/4)); via1.irq_handler().set(FUNC(cops_state::via1_irq)); @@ -677,7 +758,6 @@ void cops_state::revlatns(machine_config &config) bacta_datalogger_device &bacta(BACTA_DATALOGGER(config, "bacta", 0)); - m_dacia->txd1_handler().set("laserdisc", FUNC(sony_ldp1450hle_device::rx_w)); m_dacia->txd2_handler().set("bacta", FUNC(bacta_datalogger_device::write_txd)); bacta.rxd_handler().set("dacia", FUNC(r65c52_device::write_rxd2)); @@ -685,6 +765,23 @@ void cops_state::revlatns(machine_config &config) MSM6242(config, "rtc", 32.768_kHz_XTAL); } +void cops_state::visnqust(machine_config &config) +{ + base(config); + acia_comms(config); + + m_maincpu->set_addrmap(AS_PROGRAM, &cops_state::visnqust_map); + + /* via */ + via6522_device &via1(MOS6522(config, "via6522_1", MAIN_CLOCK/4)); + via1.irq_handler().set(FUNC(cops_state::via1_irq)); + via1.writepb_handler().set(FUNC(cops_state::via1_b_w)); + via1.cb1_handler().set(FUNC(cops_state::via1_cb1_w)); + + METERS(config, m_meters, 0).set_number(2); + +} + /*************************************************************************** Game driver(s) @@ -733,9 +830,24 @@ ROM_START( revlatns ) ROM_LOAD( "default_nvram", 0x0000, 0x2000, CRC(339f4e00) SHA1(3d5e4be30e3b21d3e34b2fa97d9ef19f597890eb) ) ROM_END +ROM_START( visnqust ) + ROM_REGION( 0x8000, "program", 0 ) + ROM_LOAD( "visionquest.u33", 0x0000, 0x8000, CRC(12cef48f) SHA1(32e8b1dd6664d34a4531a5775166e05547a7d438) ) + + ROM_REGION( 0x8000, "system", 0 ) + ROM_LOAD( "visionquest.u14", 0x0000, 0x2000, CRC(561ee492) SHA1(751226145b21c836dbbaf4868c516355f6f13df3) ) + ROM_RELOAD(0x2000, 0x2000) + ROM_RELOAD(0x4000, 0x2000) + ROM_RELOAD(0x6000, 0x2000) + + DISK_REGION( "laserdisc" ) + DISK_IMAGE_READONLY( "visionquest", 0, BAD_DUMP SHA1(d5039c5390894faeb48098216e892e6fb4bb7ca2)) //one disc, no correction, old method +ROM_END + } // Anonymous namespace -GAMEL( 1994, cops, 0, cops, cops, cops_state, init_cops, ROT0, "Atari Games", "Cops (USA)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND, layout_cops ) -GAMEL( 1994, copsuk, cops, cops, cops, cops_state, init_cops, ROT0, "Nova Productions Ltd./ Deith Leisure", "Cops (UK)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND, layout_cops ) -GAMEL( 1991, revlatns, 0, revlatns, revlatns, cops_state, init_cops, ROT0, "Nova Productions Ltd.", "Revelations", MACHINE_SUPPORTS_SAVE, layout_revlatns ) +GAMEL( 1994, cops, 0, cops, cops, cops_state, init_cops, ROT0, "Atari Games", "Cops (USA)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND, layout_cops ) +GAMEL( 1994, copsuk, cops, cops, cops, cops_state, init_cops, ROT0, "Nova Productions Ltd./ Deith Leisure", "Cops (UK)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND, layout_cops ) +GAMEL( 1991, revlatns, 0, revlatns, revlatns, cops_state, init_cops, ROT0, "Nova Productions Ltd.", "Revelations", MACHINE_SUPPORTS_SAVE, layout_revlatns ) +GAMEL( 1992, visnqust, 0, visnqust, visnqust, cops_state, init_cops, ROT0, "Kramer Manufacturing / Nova Productions Ltd.","Vision Quest", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_GRAPHICS | MACHINE_SUPPORTS_SAVE, layout_visnqust ) diff --git a/src/mame/layout/visnqust.lay b/src/mame/layout/visnqust.lay new file mode 100644 index 0000000000000..cb521b50f7c54 --- /dev/null +++ b/src/mame/layout/visnqust.lay @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/mame/mame.lst b/src/mame/mame.lst index 016832941e860..107f41cd43f5d 100644 --- a/src/mame/mame.lst +++ b/src/mame/mame.lst @@ -1908,9 +1908,10 @@ cmmb162 cmmb103 @source:atari/cops.cpp -cops -copsuk -revlatns +cops // (c) 1994 +copsuk // (c) 1994 (Nova/Deith Leisure) +revlatns // (c) 1991 +visnqust // (c) 1992 (Kramer/Nova) @source:atari/copsnrob.cpp copsnrob