From deec658426a17765c4ebeb87466772d0d5a4330d Mon Sep 17 00:00:00 2001 From: hap Date: Mon, 17 Aug 2020 19:16:06 +0200 Subject: [PATCH] ef9340: add support for double width/height characters --- hash/g7400.xml | 2 +- src/devices/video/ef9340_1.cpp | 213 +++++---- src/devices/video/ef9340_1.h | 10 +- src/mame/drivers/odyssey2.cpp | 643 +++++++++++++++------------ src/mame/drivers/saitek_intchess.cpp | 1 + 5 files changed, 485 insertions(+), 384 deletions(-) diff --git a/hash/g7400.xml b/hash/g7400.xml index 90eed54b6bc..1077e6df343 100644 --- a/hash/g7400.xml +++ b/hash/g7400.xml @@ -368,7 +368,7 @@ The C7420 Home Computer Module contains a Z80, 16K RAM and 16K ROM. - + Helicopter Rescue (Euro) 1983 Philips diff --git a/src/devices/video/ef9340_1.cpp b/src/devices/video/ef9340_1.cpp index aea6587e4a4..afaffddac1b 100644 --- a/src/devices/video/ef9340_1.cpp +++ b/src/devices/video/ef9340_1.cpp @@ -2,11 +2,21 @@ // copyright-holders:Wilbert Pol, hap /*************************************************************************** -Thomson EF9340 + EF9341 teletext graphics chips with 1KB external character ram. +Thomson EF9340 + EF9341 teletext graphics, this device is a combination of chips. + +Minimal components: +- Thomson EF9340 "VIN" +- Thomson EF9341 "GEN" +- 2*1KB RAM, A for attributes, B for character codes + +There's also an optional extended character memory, it can be RAM or ROM. +This is implemented with a callback. The datasheet explains how to hook up +1KB RAM, but it's possible to have more. TODO: - busy state (right now it is immediate) -- character width/height doubling +- internal display timing (on g7400, most of it is done externally) +- read slice from internal ROM - window boxing - Y zoom @@ -29,6 +39,8 @@ ef9340_1_device::ef9340_1_device(const machine_config &mconfig, const char *tag, : device_t(mconfig, EF9340_1, tag, owner, clock) , device_video_interface(mconfig, *this) , m_charset(*this, "ef9340_1") + , m_write_exram(*this) + , m_read_exram(*this) { } @@ -47,6 +59,9 @@ const tiny_rom_entry *ef9340_1_device::device_rom_region() const void ef9340_1_device::device_start() { + m_write_exram.resolve_safe(); + m_read_exram.resolve_safe(0xff); + // Let the screen create our temporary bitmap with the screen's dimensions screen().register_screen_bitmap(m_tmp_bitmap); @@ -68,10 +83,10 @@ void ef9340_1_device::device_start() m_ef9340.M = 0; m_ef9340.blink = false; m_ef9340.blink_prescaler = 0; + m_ef9340.h_parity = false; memset(m_ram_a, 0, sizeof(m_ram_a)); memset(m_ram_b, 0, sizeof(m_ram_b)); - memset(m_ram_b, 0, sizeof(m_ef934x_ext_char_ram)); // register our state save_item(NAME(m_ef9341.TA)); @@ -85,10 +100,10 @@ void ef9340_1_device::device_start() save_item(NAME(m_ef9340.M)); save_item(NAME(m_ef9340.blink)); save_item(NAME(m_ef9340.blink_prescaler)); + save_item(NAME(m_ef9340.h_parity)); save_item(NAME(m_ram_a)); save_item(NAME(m_ram_b)); - save_item(NAME(m_ef934x_ext_char_ram)); } @@ -143,20 +158,6 @@ void ef9340_1_device::ef9340_inc_c() } -uint16_t ef9340_1_device::external_chargen_address(uint8_t b, uint8_t slice) -{ - uint8_t cc = b & 0x7f; - - if ( slice & 8 ) - { - // 0 0 CCE4 CCE3 CCE2 CCE1 CCE0 CCE6 CCE5 ADR0 - return ( ( cc << 3 ) & 0xf8 ) | ( ( cc >> 4 ) & 0x06) | ( slice & 0x01 ); - } - // CCE6 CCE5 CCE4 CCE3 CCE2 CCE1 CCE0 ADR2 ADR1 ADR0 - return ( cc << 3 ) | ( slice & 0x07 ); -} - - void ef9340_1_device::ef9341_write( uint8_t command, uint8_t b, uint8_t data ) { LOG("ef9341 %s write, t%s, data %02X\n", command ? "command" : "data", b ? "B" : "A", data ); @@ -226,12 +227,10 @@ void ef9340_1_device::ef9341_write( uint8_t command, uint8_t b, uint8_t data ) { uint8_t a = m_ram_a[addr]; uint8_t b = m_ram_b[addr]; - uint8_t slice = ( m_ef9340.M & 0x0f ) % 10; + uint8_t slice = m_ef9340.M & 0x0f; - if ( b >= 0xa0 ) - { - m_ef934x_ext_char_ram[ ( ( a & 0x80 ) << 3 ) | external_chargen_address( b, slice ) ] = m_ef9341.TA; - } + if (b >= 0xa0) + m_write_exram(a << 12 | b << 4 | slice, m_ef9341.TA); // Increment slice number m_ef9340.M = ( m_ef9340.M & 0xf0) | ( ( slice + 1 ) % 10 ); @@ -293,13 +292,15 @@ uint8_t ef9340_1_device::ef9341_read( uint8_t command, uint8_t b ) { uint8_t a = m_ram_a[addr]; uint8_t b = m_ram_b[addr]; - uint8_t slice = ( m_ef9340.M & 0x0f ) % 10; + uint8_t slice = m_ef9340.M & 0x0f; - if ( b >= 0xa0 ) - { - m_ef9341.TA = m_ef934x_ext_char_ram[ ( ( a & 0x80 ) << 3 ) | external_chargen_address( b, slice ) ]; - m_ef9341.TB = 0; - } + m_ef9341.TA = 0xff; + m_ef9341.TB = 0xff; + + if (b >= 0xa0) + m_ef9341.TA = m_read_exram(a << 12 | b << 4 | slice); + else + logerror("ef9341 read slice from internal\n"); // Increment slice number m_ef9340.M = ( m_ef9340.M & 0xf0) | ( ( slice + 1 ) % 10 ); @@ -329,26 +330,32 @@ void ef9340_1_device::ef9340_scanline(int vpos) if (vpos < 0) return; - // display automaton active at 40-290, or 32-242 - int max_vpos = ( m_ef9340.R & 0x40 ) ? 250 : 210; + int slice = vpos % 10; + bool dh = false; + if (vpos == 0) + m_ef9340.h_parity = false; - if ( m_ef9340.R & 0x01 && vpos < max_vpos ) + // display automaton active at 40-290, or 32-242 + int max_vpos = (m_ef9340.R & 0x40) ? 250 : 210; + + if (m_ef9340.R & 0x01 && vpos < max_vpos) { - int y = vpos; - int y_row, slice; + int y_row = 0; + uint16_t char_data = 0x00; uint8_t fg = 0; uint8_t bg = 0; + bool del = false; bool underline = false; bool blank = false; + bool w_parity = false; - if ( y < 10 ) + if ( vpos < 10 ) { // Service row - if ( m_ef9340.R & 0x08 ) + if (m_ef9340.R & 0x08) { // Service row is enabled y_row = 31; - slice = y; } else { @@ -361,101 +368,129 @@ void ef9340_1_device::ef9340_scanline(int vpos) else { // Displaying regular row - y_row = ((m_ef9340.Y0 & 0x1f) + (y - 10) / 10) % 24; - slice = (y - 10) % 10; + y_row = ((m_ef9340.Y0 & 0x1f) + (vpos - 10) / 10) % 24; } - for ( int x = 0; x < 40; x++ ) + for (int x = 0; x < 40; x++) { - uint16_t addr = ef9340_get_c_addr( x, y_row ); + int s = slice; + uint16_t addr = ef9340_get_c_addr(x, y_row); uint8_t a = m_ram_a[addr]; uint8_t b = m_ram_b[addr]; - uint8_t char_data = 0x00; bool blink = m_ef9340.R & 0x80 && m_ef9340.blink; bool cursor = m_ef9340.R & 0x10 && x == m_ef9340.X && y_row == m_ef9340.Y; bool invert = cursor && !blink; - bool alpha = !bool(a & 0x80); + bool dw = false; - if (alpha) + if (a & 0x80) { - // Alphanumeric - if ( b & 0x80 ) + // graphics + if ((b & 0xe0) != 0x80) { - if ( b & 0x60 ) - { - // Extension - char_data = m_ef934x_ext_char_ram[ external_chargen_address( b & 0x7f, slice ) ]; - fg = a & 0x07; - } - else - { - // Deliminator - alpha = false; - blank = m_ef9340.R & 0x04 && b & 0x01; - underline = bool(b & 0x04); - char_data = 0xff; - fg = a & 0x07; - bg = a >> 4 & 0x07; - } - } - else - { - // Normal - if (slice == 9 && underline) - char_data = 0xff; - else - char_data = m_charset[((b & 0x7f) * 10) + slice]; fg = a & 0x07; + bg = a >> 4 & 0x07; + + if (b & 0x80) + char_data = m_read_exram(a << 12 | b << 4 | s); + else + char_data = m_charset[((b | 0x80) * 10) + s]; } - // Inverted - if (alpha && a & 0x40) - { - invert = !invert; - blink = m_ef9340.R & 0x80 && !m_ef9340.blink; - } + // illegal + else + char_data = 0xff; } else { - // Graphics - if ( b & 0x80 ) + // alphanumeric + if ((b & 0xe0) != 0x80) { - if ( b & 0x60 ) + // double height + if (a & 0x10) { - // Extension - char_data = m_ef934x_ext_char_ram[ 0x400 | external_chargen_address( b & 0x7f, slice ) ]; - fg = a & 0x07; - bg = a >> 4 & 0x07; + dh = true; + if (m_ef9340.h_parity) + s += 10; + if (s > 0) + s = (s - 1) / 2; + } + + fg = a & 0x07; + u16 c = 0; + + if (b & 0x80) + c = m_read_exram(a << 12 | b << 4 | s); + else if (s == 9 && underline) + c = 0xff; + else + c = m_charset[((b & 0x7f) * 10) + s]; + + // double width + dw = bool(a & 0x20); + if (dw) + { + if (!w_parity) + char_data = bitswap<16>(c,7,7,6,6,5,5,4,4,3,3,2,2,1,1,0,0); } else + char_data = c; + + // inverted + if (a & 0x40) { - // Illegal + invert = !invert; + blink = m_ef9340.R & 0x80 && !m_ef9340.blink; } } + + // deliminator else { - // Normal - char_data = m_charset[((b | 0x80) * 10) + slice]; fg = a & 0x07; bg = a >> 4 & 0x07; + char_data = 0xff; + + del = true; } } // blink character if (blink && !cursor && (b & 0xe0) != 0x80 && ~a & 0x08) - char_data = 0; + char_data &= ~0xff; if (invert) char_data ^= 0xff; - for ( int i = 0; i < 8; i++ ) + if (dw) + w_parity = !w_parity; + else + w_parity = false; + + for (int i = 0; i < 8; i++) { uint16_t d = blank ? 0 : (char_data & 1) ? fg : bg; - m_tmp_bitmap.pix16(m_offset_y + vpos, m_offset_x + x*8 + i ) = d | 8; + m_tmp_bitmap.pix16(m_offset_y + vpos, m_offset_x + x*8 + i) = d | 8; char_data >>= 1; } + + if (del) + { + blank = m_ef9340.R & 0x04 && b & 0x01; + underline = bool(b & 0x04); + + del = false; + } } } + + // determine next h parity + if (vpos >= 10 && slice == 9) + { + if (dh) + m_ef9340.h_parity = !m_ef9340.h_parity; + else + m_ef9340.h_parity = false; + } } diff --git a/src/devices/video/ef9340_1.h b/src/devices/video/ef9340_1.h index 115ce51d25b..61d1eb6d584 100644 --- a/src/devices/video/ef9340_1.h +++ b/src/devices/video/ef9340_1.h @@ -26,6 +26,8 @@ public: // configuration helpers ef9340_1_device &set_offsets(int x, int y) { m_offset_x = x; m_offset_y = y; return *this; } // when used with overlay chip + auto write_exram() { return m_write_exram.bind(); } // ADR0-ADR3 in a0-a3, B in a4-a11, A in a12-a19 + auto read_exram() { return m_read_exram.bind(); } // " ef9340_1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); @@ -44,9 +46,6 @@ protected: inline uint16_t ef9340_get_c_addr(uint8_t x, uint8_t y); inline void ef9340_inc_c(); - // Calculate the external chargen address for a character and slice - inline uint16_t external_chargen_address(uint8_t b, uint8_t slice); - void ef9340_scanline(int vpos); /* timers */ @@ -79,11 +78,14 @@ protected: uint8_t M; bool blink; int blink_prescaler; + bool h_parity; } m_ef9340; uint8_t m_ram_a[0x400]; uint8_t m_ram_b[0x400]; - uint8_t m_ef934x_ext_char_ram[0x800]; // The G7400 has 2KB of external ram hooked up. The datasheet only describes how to hookup 1KB. + + devcb_write8 m_write_exram; + devcb_read8 m_read_exram; }; diff --git a/src/mame/drivers/odyssey2.cpp b/src/mame/drivers/odyssey2.cpp index fafb574e27f..e0cad9d5546 100644 --- a/src/mame/drivers/odyssey2.cpp +++ b/src/mame/drivers/odyssey2.cpp @@ -33,9 +33,6 @@ XTAL notes (differs per model): - G7400: 5.911MHz + 8.867MHz TODO: -- verify odyssey3 cpu/video clocks -- odyssey sets 210 line mode in plus graphics, which cuts off the bottom part - of the screen - backgamm doesn't draw all the sprites, what causes it? It doesn't seem like it's a 824x bug since it does properly write data in the partial screen updates - 824x screen resolution is not strictly defined, height(243) is correct, but @@ -48,8 +45,20 @@ TODO: be correct - ppp(the tetris game) does not work properly on PAL, is this homebrew NTSC-only, or is it due to PAL video timing? The game does mid-scanline updates +- g7400 helicopt sometimes locks up at the sea level, timing related? - g7400 probably has different video timing too (not same as g7000) -- g7400 graphics problems, mostly due to missing features in ef934x +- 4in1 and musician are not supposed to work on g7400, but work fine on MAME, + reason they shouldn't work is probably because they write to P2 +- verify odyssey3 cpu/video clocks +- odyssey3 keyboard layout is not the same as g7400, but there is no software + to test the scancodes + +BTANB: +- a lot of PAL games have problems on NTSC (the other way around, not so much) +- g7400 games don't look correct on odyssey3: ef934x graphics are placed lower +- Blackjack (Videopac 5) does not work on G7400 + +Plenty games have minor bugs not worth mentioning here. ***************************************************************************/ @@ -68,6 +77,8 @@ TODO: #include "speaker.h" +namespace { + class odyssey2_state : public driver_device { public: @@ -88,6 +99,8 @@ public: void videopac(machine_config &config); void videopacf(machine_config &config); + void odyssey2_palette(palette_device &palette) const; + protected: required_device m_maincpu; required_device m_i8244; @@ -99,7 +112,6 @@ protected: uint8_t m_p2 = 0xff; DECLARE_READ_LINE_MEMBER(t1_read); - void odyssey2_palette(palette_device &palette) const; void odyssey2_io(address_map &map); void odyssey2_mem(address_map &map); @@ -109,8 +121,8 @@ protected: required_ioport_array<8> m_keyboard; required_ioport_array<2> m_joysticks; - uint8_t io_read(offs_t offset); - void io_write(offs_t offset, uint8_t data); + virtual uint8_t io_read(offs_t offset); + virtual void io_write(offs_t offset, uint8_t data); uint8_t bus_read(); void bus_write(uint8_t data); uint8_t p1_read(); @@ -128,7 +140,7 @@ public: g7400_state(const machine_config &mconfig, device_type type, const char *tag) : odyssey2_state(mconfig, type, tag) , m_i8243(*this, "i8243") - , m_ef9340_1(*this, "ef9340_1") + , m_ef934x(*this, "ef934x") { } void g7400(machine_config &config); @@ -137,24 +149,311 @@ public: protected: virtual void machine_start() override; + virtual uint8_t io_read(offs_t offset) override; + virtual void io_write(offs_t offset, uint8_t data) override; + private: required_device m_i8243; - required_device m_ef9340_1; + required_device m_ef934x; uint32_t screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); void p2_write(uint8_t data); uint8_t io_vpp(offs_t offset, uint8_t data); - uint8_t io_read(offs_t offset); - void io_write(offs_t offset, uint8_t data); template void i8243_port_w(uint8_t data); - void g7400_io(address_map &map); + inline offs_t ef934x_extram_address(offs_t offset); + uint8_t ef934x_extram_r(offs_t offset); + void ef934x_extram_w(offs_t offset, uint8_t data); - uint8_t m_mix_in = 0xff; - uint8_t m_mix_out = 0xff; + uint8_t m_mix_i8244 = 0xff; + uint8_t m_mix_ef934x = 0xff; + uint8_t m_ef934x_extram[0x800]; }; +void odyssey2_state::machine_start() +{ + memset(m_ram, 0, sizeof(m_ram)); + + save_item(NAME(m_ram)); + save_item(NAME(m_p1)); + save_item(NAME(m_p2)); +} + +void g7400_state::machine_start() +{ + odyssey2_state::machine_start(); + memset(m_ef934x_extram, 0, sizeof(m_ef934x_extram)); + + save_item(NAME(m_mix_i8244)); + save_item(NAME(m_mix_ef934x)); + save_item(NAME(m_ef934x_extram)); +} + + + +/****************************************************************************** + Video +******************************************************************************/ + +constexpr rgb_t odyssey2_colors[] = +{ + // Background,Grid Dim + { 0x00, 0x00, 0x00 }, /* Black */ // i r g b + { 0x79, 0x00, 0x00 }, /* Red - Calibrated To Real VideoPac */ // i R g b + { 0x00, 0x6d, 0x07 }, /* Green - Calibrated To Real VideoPac */ // i r G b + { 0x77, 0x67, 0x0b }, /* Khaki - Calibrated To Real VideoPac */ // i R g B + { 0x1a, 0x37, 0xbe }, /* Blue - Calibrated To Real VideoPac */ // i r g B + { 0x94, 0x30, 0x9f }, /* Violet - Calibrated To Real VideoPac */ // i R g B + { 0x2a, 0xaa, 0xbe }, /* Blue-Green - Calibrated To Real VideoPac */ // i r G B + { 0xce, 0xce, 0xce }, /* Lt Grey */ // i R G B + + // Background,Grid Bright + { 0x67, 0x67, 0x67 }, /* Grey - Calibrated To Real VideoPac */ // I R g B + { 0xc7, 0x51, 0x51 }, /* Lt Red - Calibrated To Real VideoPac */ // I R g b + { 0x56, 0xc4, 0x69 }, /* Lt Green - Calibrated To Real VideoPac */ // I R g B + { 0xc6, 0xb8, 0x6a }, /* Lt Yellow - Calibrated To Real VideoPac */ // I R G b + { 0x5c, 0x80, 0xf6 }, /* Lt Blue - Calibrated To Real VideoPac */ // I R g B + { 0xdc, 0x84, 0xe8 }, /* Lt Violet - Calibrated To Real VideoPac */ // I R g B + { 0x77, 0xe6, 0xeb }, /* Lt Blue-Green - Calibrated To Real VideoPac */ // I R g b + { 0xff, 0xff, 0xff } /* White */ // I R G B +}; + +void odyssey2_state::odyssey2_palette(palette_device &palette) const +{ + palette.set_pen_colors(0, odyssey2_colors); +} + + +uint32_t odyssey2_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) +{ + m_i8244->screen_update(screen, bitmap, cliprect); + + u8 lum = ~m_p1 >> 4 & 0x08; + + // apply external LUM setting + for (int y = cliprect.min_y; y <= cliprect.max_y; y++) + for (int x = cliprect.min_x; x <= cliprect.max_x; x++) + bitmap.pix16(y, x) |= lum; + + return 0; +} + +uint32_t g7400_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) +{ + u8 lum = ~m_p1 >> 4 & 0x08; + bitmap_ind16 *ef934x_bitmap = m_ef934x->get_bitmap(); + + // apply external LUM setting + for (int y = cliprect.min_y; y <= cliprect.max_y; y++) + { + rectangle clip = cliprect; + clip.min_y = clip.max_y = y; + + m_i8244->screen_update(screen, bitmap, clip); + + for (int x = clip.min_x; x <= clip.max_x; x++) + { + uint16_t d = bitmap.pix16(y, x); + uint16_t e = ef934x_bitmap->pix16(y, x); + + // I outputs to CX + bool i2 = !BIT(m_mix_ef934x, e & 0x07); + m_i8244->write_cx(x, i2); + + if (m_mix_i8244 == 0xff || ((e & 0x08) && BIT(m_mix_i8244, d & 0x07))) + { + // Use i8245 input + bitmap.pix16(y, x) |= lum; + } + else + { + // Use EF934x input + bitmap.pix16(y, x) = i2 ? e | 0x08 : e & 0x07; + } + } + } + + return 0; +} + + + +/****************************************************************************** + I/O +******************************************************************************/ + +uint8_t odyssey2_state::io_read(offs_t offset) +{ + u8 data = m_cart->io_read(offset); + if (!(m_p1 & 0x10) && ~offset & 0x80) + data &= m_ram[offset]; + + if ((m_p1 & 0x48) == 0) + data &= m_i8244->read(offset); + + return data; +} + +void odyssey2_state::io_write(offs_t offset, uint8_t data) +{ + if (!(m_p1 & 0x40)) + { + m_cart->io_write(offset, data); + if (!(m_p1 & 0x10) && ~offset & 0x80) + m_ram[offset] = data; + } + + if (!(m_p1 & 0x08)) + m_i8244->write(offset, data); +} + +uint8_t odyssey2_state::p1_read() +{ + return 0xff; +} + + +// 8048 ports + +void odyssey2_state::p1_write(uint8_t data) +{ + // LUM changed + if ((m_p1 ^ data) & 0x80) + m_screen->update_now(); + + m_p1 = data; + m_cart->write_p1(m_p1 & 0x13); +} + +uint8_t odyssey2_state::p2_read() +{ + u8 data = 0xff; + + if (!(m_p1 & 0x04)) + { + // 74148 priority encoder, GS to P24, outputs to P25-P27 + u8 inp = count_leading_zeros(m_keyboard[m_p2 & 0x07]->read()) - 24; + if (inp < 8) + data &= inp << 5 | 0xf; + } + + return data; +} + +void odyssey2_state::p2_write(uint8_t data) +{ + m_p2 = data; + m_cart->write_p2(m_p2 & 0x0f); +} + +uint8_t odyssey2_state::bus_read() +{ + u8 data = 0xff; + + if (!(m_p1 & 0x04)) + { + u8 sel = m_p2 & 0x07; + if (sel < 2) + data &= ~m_joysticks[sel]->read(); + } + + return data; +} + +void odyssey2_state::bus_write(uint8_t data) +{ +} + +READ_LINE_MEMBER(odyssey2_state::t1_read) +{ + return m_i8244->vblank() | m_i8244->hblank(); +} + + +// G7400-specific + +uint8_t g7400_state::io_read(offs_t offset) +{ + u8 data = odyssey2_state::io_read(offset); + return io_vpp(offset, data); +} + +void g7400_state::io_write(offs_t offset, uint8_t data) +{ + odyssey2_state::io_write(offset, data); + io_vpp(offset, data); +} + +uint8_t g7400_state::io_vpp(offs_t offset, uint8_t data) +{ + if (!(m_p1 & 0x20)) + { + // A2 to R/W pin + if (offset & 4) + data &= m_ef934x->ef9341_read( offset & 0x02, offset & 0x01 ); + else + m_ef934x->ef9341_write( offset & 0x02, offset & 0x01, data ); + } + + return data; +} + +void g7400_state::p2_write(uint8_t data) +{ + odyssey2_state::p2_write(data); + m_i8243->p2_w(m_p2 & 0x0f); +} + +template +void g7400_state::i8243_port_w(uint8_t data) +{ + // P4,P5: color mix I8244 side (IC674) + // P6,P7: color mix EF9340 side (IC678) + u8 mask = 0xf; + if (~P & 1) + { + data <<= 4; + mask <<= 4; + } + + m_screen->update_now(); + + if (P & 2) + m_mix_i8244 = (m_mix_i8244 & ~mask) | (data & mask); + else + m_mix_ef934x = (m_mix_ef934x & ~mask) | (data & mask); +} + + +// EF9341 extended RAM + +offs_t g7400_state::ef934x_extram_address(offs_t offset) +{ + u8 latch = (offset >> 12 & 0x80) | (offset >> 4 & 0x7f); + u16 address = (latch & 0x1f) | (offset << 9 & 0x200) | (latch << 3 & 0x400); + + if (offset & 8) + return address | (latch & 0x60); + else + return address | (offset << 4 & 0x60) | (latch << 2 & 0x180); +} + +uint8_t g7400_state::ef934x_extram_r(offs_t offset) +{ + return m_ef934x_extram[ef934x_extram_address(offset)]; +} + +void g7400_state::ef934x_extram_w(offs_t offset, uint8_t data) +{ + m_ef934x_extram[ef934x_extram_address(offset)] = data; +} + + + +/****************************************************************************** + Address Maps +******************************************************************************/ void odyssey2_state::odyssey2_mem(address_map &map) { @@ -163,18 +462,16 @@ void odyssey2_state::odyssey2_mem(address_map &map) map(0x0c00, 0x0fff).r(m_cart, FUNC(o2_cart_slot_device::read_rom0c)); } - void odyssey2_state::odyssey2_io(address_map &map) { map(0x00, 0xff).rw(FUNC(odyssey2_state::io_read), FUNC(odyssey2_state::io_write)); } -void g7400_state::g7400_io(address_map &map) -{ - map(0x00, 0xff).rw(FUNC(g7400_state::io_read), FUNC(g7400_state::io_write)); -} +/****************************************************************************** + Input Ports +******************************************************************************/ static INPUT_PORTS_START( odyssey2 ) PORT_START("KEY.0") @@ -335,269 +632,14 @@ static INPUT_PORTS_START( g7400 ) PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Shift") PORT_CODE(KEYCODE_LSHIFT) PORT_CODE(KEYCODE_RSHIFT) PORT_CHAR(UCHAR_SHIFT_1) PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Break") PORT_CODE(KEYCODE_END) PORT_CHAR(UCHAR_MAMEKEY(PAUSE)) PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Cntl") PORT_CODE(KEYCODE_LCONTROL) PORT_CODE(KEYCODE_RCONTROL) PORT_CHAR(UCHAR_SHIFT_2) - PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_UNUSED) - PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_UNUSED) - PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_UNUSED) - PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Esc") PORT_CODE(KEYCODE_ESC) PORT_CHAR(27) INPUT_PORTS_END -constexpr rgb_t odyssey2_colors[] = -{ - // Background,Grid Dim - { 0x00, 0x00, 0x00 }, /* Black */ // i r g b - { 0x79, 0x00, 0x00 }, /* Red - Calibrated To Real VideoPac */ // i R g b - { 0x00, 0x6d, 0x07 }, /* Green - Calibrated To Real VideoPac */ // i r G b - { 0x77, 0x67, 0x0b }, /* Khaki - Calibrated To Real VideoPac */ // i R g B - { 0x1a, 0x37, 0xbe }, /* Blue - Calibrated To Real VideoPac */ // i r g B - { 0x94, 0x30, 0x9f }, /* Violet - Calibrated To Real VideoPac */ // i R g B - { 0x2a, 0xaa, 0xbe }, /* Blue-Green - Calibrated To Real VideoPac */ // i r G B - { 0xce, 0xce, 0xce }, /* Lt Grey */ // i R G B - - // Background,Grid Bright - { 0x67, 0x67, 0x67 }, /* Grey - Calibrated To Real VideoPac */ // I R g B - { 0xc7, 0x51, 0x51 }, /* Lt Red - Calibrated To Real VideoPac */ // I R g b - { 0x56, 0xc4, 0x69 }, /* Lt Green - Calibrated To Real VideoPac */ // I R g B - { 0xc6, 0xb8, 0x6a }, /* Lt Yellow - Calibrated To Real VideoPac */ // I R G b - { 0x5c, 0x80, 0xf6 }, /* Lt Blue - Calibrated To Real VideoPac */ // I R g B - { 0xdc, 0x84, 0xe8 }, /* Lt Violet - Calibrated To Real VideoPac */ // I R g B - { 0x77, 0xe6, 0xeb }, /* Lt Blue-Green - Calibrated To Real VideoPac */ // I R g b - { 0xff, 0xff, 0xff } /* White */ // I R G B -}; - - -void odyssey2_state::odyssey2_palette(palette_device &palette) const -{ - palette.set_pen_colors(0, odyssey2_colors); -} - - -void odyssey2_state::machine_start() -{ - memset(m_ram, 0, sizeof(m_ram)); - - save_item(NAME(m_ram)); - save_item(NAME(m_p1)); - save_item(NAME(m_p2)); -} - - -void g7400_state::machine_start() -{ - odyssey2_state::machine_start(); - - save_item(NAME(m_mix_in)); - save_item(NAME(m_mix_out)); -} - - -/****** External RAM ******************************/ - -uint8_t odyssey2_state::io_read(offs_t offset) -{ - u8 data = m_cart->io_read(offset); - if (!(m_p1 & 0x10) && ~offset & 0x80) - data &= m_ram[offset]; - - if ((m_p1 & 0x48) == 0) - data &= m_i8244->read(offset); - - return data; -} - - -void odyssey2_state::io_write(offs_t offset, uint8_t data) -{ - if (!(m_p1 & 0x40)) - { - m_cart->io_write(offset, data); - if (!(m_p1 & 0x10) && ~offset & 0x80) - m_ram[offset] = data; - } - - if (!(m_p1 & 0x08)) - m_i8244->write(offset, data); -} - - -uint8_t g7400_state::io_vpp(offs_t offset, uint8_t data) -{ - if (!(m_p1 & 0x20)) - { - // A2 to R/W pin - if (offset & 4) - data &= m_ef9340_1->ef9341_read( offset & 0x02, offset & 0x01 ); - else - m_ef9340_1->ef9341_write( offset & 0x02, offset & 0x01, data ); - } - - return data; -} - - -uint8_t g7400_state::io_read(offs_t offset) -{ - u8 data = odyssey2_state::io_read(offset); - return io_vpp(offset, data); -} - - -void g7400_state::io_write(offs_t offset, uint8_t data) -{ - odyssey2_state::io_write(offset, data); - io_vpp(offset, data); -} - - -uint32_t odyssey2_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) -{ - m_i8244->screen_update(screen, bitmap, cliprect); - - u8 lum = ~m_p1 >> 4 & 0x08; - - // apply external LUM setting - for (int y = cliprect.min_y; y <= cliprect.max_y; y++) - for (int x = cliprect.min_x; x <= cliprect.max_x; x++) - bitmap.pix16(y, x) |= lum; - - return 0; -} - - -uint32_t g7400_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) -{ - u8 lum = ~m_p1 >> 4 & 0x08; - bitmap_ind16 *ef934x_bitmap = m_ef9340_1->get_bitmap(); - - // apply external LUM setting - for (int y = cliprect.min_y; y <= cliprect.max_y; y++) - { - rectangle clip = cliprect; - clip.min_y = clip.max_y = y; - - m_i8244->screen_update(screen, bitmap, clip); - - for (int x = clip.min_x; x <= clip.max_x; x++) - { - uint16_t d = bitmap.pix16(y, x); - uint16_t e = ef934x_bitmap->pix16(y, x); - - // I outputs to CX - bool i2 = !BIT(m_mix_out, e & 0x07); - m_i8244->write_cx(x, i2); - - if (m_mix_in == 0xff || ((e & 0x08) && BIT(m_mix_in, d & 0x07))) - { - // Use i8245 input - bitmap.pix16(y, x) |= lum; - } - else - { - // Use EF934x input - bitmap.pix16(y, x) = i2 ? e | 0x08 : e & 0x07; - } - } - } - - return 0; -} - - -READ_LINE_MEMBER(odyssey2_state::t1_read) -{ - return m_i8244->vblank() | m_i8244->hblank(); -} - - -uint8_t odyssey2_state::p1_read() -{ - return 0xff; -} - - -void odyssey2_state::p1_write(uint8_t data) -{ - // LUM changed - if ((m_p1 ^ data) & 0x80) - m_screen->update_now(); - - m_p1 = data; - m_cart->write_p1(m_p1 & 0x13); -} - - -uint8_t odyssey2_state::p2_read() -{ - u8 data = 0xff; - - if (!(m_p1 & 0x04)) - { - // 74148 priority encoder, GS to P24, outputs to P25-P27 - u8 inp = count_leading_zeros(m_keyboard[m_p2 & 0x07]->read()) - 24; - if (inp < 8) - data &= inp << 5 | 0xf; - } - - return data; -} - - -void odyssey2_state::p2_write(uint8_t data) -{ - m_p2 = data; - m_cart->write_p2(m_p2 & 0x0f); -} - - -void g7400_state::p2_write(uint8_t data) -{ - odyssey2_state::p2_write(data); - m_i8243->p2_w(m_p2 & 0x0f); -} - - -uint8_t odyssey2_state::bus_read() -{ - u8 data = 0xff; - - if (!(m_p1 & 0x04)) - { - u8 sel = m_p2 & 0x07; - if (sel < 2) - data &= ~m_joysticks[sel]->read(); - } - - return data; -} - - -void odyssey2_state::bus_write(uint8_t data) -{ -} - - -template -void g7400_state::i8243_port_w(uint8_t data) -{ - // P4,P5: color mix out (IC674) - // P6,P7: color mix in (IC678) - u8 mask = 0xf; - if (~P & 1) - { - data <<= 4; - mask <<= 4; - } - - m_screen->update_now(); - - if (P & 2) - m_mix_in = (m_mix_in & ~mask) | (data & mask); - else - m_mix_out = (m_mix_out & ~mask) | (data & mask); -} - +/****************************************************************************** + Machine Configs +******************************************************************************/ void odyssey2_state::odyssey2(machine_config &config) { @@ -622,13 +664,14 @@ void odyssey2_state::odyssey2(machine_config &config) PALETTE(config, "palette", FUNC(odyssey2_state::odyssey2_palette), 16); - SPEAKER(config, "mono").front_center(); I8244(config, m_i8244, XTAL(7'159'090) / 2); m_i8244->set_screen("screen"); m_i8244->set_screen_size(356, 243); m_i8244->irq_cb().set_inputline(m_maincpu, MCS48_INPUT_IRQ); m_i8244->add_route(ALL_OUTPUTS, "mono", 0.40); + SPEAKER(config, "mono").front_center(); + /* cartridge */ O2_CART_SLOT(config, m_cart, o2_cart, nullptr); SOFTWARE_LIST(config, "cart_list").set_original("odyssey2"); @@ -664,7 +707,7 @@ void g7400_state::g7400(machine_config &config) /* basic machine hardware */ I8048(config, m_maincpu, XTAL(5'911'000)); m_maincpu->set_addrmap(AS_PROGRAM, &g7400_state::odyssey2_mem); - m_maincpu->set_addrmap(AS_IO, &g7400_state::g7400_io); + m_maincpu->set_addrmap(AS_IO, &g7400_state::odyssey2_io); m_maincpu->p1_in_cb().set(FUNC(g7400_state::p1_read)); m_maincpu->p1_out_cb().set(FUNC(g7400_state::p1_write)); m_maincpu->p2_in_cb().set(FUNC(g7400_state::p2_read)); @@ -689,16 +732,19 @@ void g7400_state::g7400(machine_config &config) m_i8243->p6_out_cb().set(FUNC(g7400_state::i8243_port_w<2>)); m_i8243->p7_out_cb().set(FUNC(g7400_state::i8243_port_w<3>)); - EF9340_1(config, m_ef9340_1, XTAL(8'867'000)/5 * 2, "screen"); - m_ef9340_1->set_offsets(15, 5); + EF9340_1(config, m_ef934x, XTAL(8'867'000)/5 * 2, "screen"); + m_ef934x->set_offsets(15, 5); + m_ef934x->read_exram().set(FUNC(g7400_state::ef934x_extram_r)); + m_ef934x->write_exram().set(FUNC(g7400_state::ef934x_extram_w)); - SPEAKER(config, "mono").front_center(); I8245(config, m_i8244, XTAL(8'867'000)/5 * 2); m_i8244->set_screen("screen"); m_i8244->set_screen_size(356, 243); m_i8244->irq_cb().set_inputline(m_maincpu, MCS48_INPUT_IRQ); m_i8244->add_route(ALL_OUTPUTS, "mono", 0.40); + SPEAKER(config, "mono").front_center(); + /* cartridge */ O2_CART_SLOT(config, m_cart, o2_cart, nullptr); SOFTWARE_LIST(config, "cart_list").set_original("g7400"); @@ -716,11 +762,21 @@ void g7400_state::odyssey3(machine_config &config) m_i8244->irq_cb().set_inputline(m_maincpu, MCS48_INPUT_IRQ); m_i8244->add_route(ALL_OUTPUTS, "mono", 0.40); - m_ef9340_1->set_clock(XTAL(7'159'090) / 2); + m_ef934x->set_clock(XTAL(7'159'090) / 2); + m_ef934x->set_offsets(15, 15); + m_maincpu->set_clock((XTAL(7'159'090) * 3) / 4); + + // same color encoder as O2 (no RGB port) + PALETTE(config.replace(), "palette", FUNC(odyssey2_state::odyssey2_palette), 16); } + +/****************************************************************************** + ROM Definitions +******************************************************************************/ + ROM_START (odyssey2) ROM_REGION(0x0400,"maincpu",0) ROM_LOAD ("o2bios.rom", 0x0000, 0x0400, CRC(8016a315) SHA1(b2e1955d957a475de2411770452eff4ea19f4cee)) @@ -752,12 +808,19 @@ ROM_START (odyssey3) ROM_LOAD ("odyssey3.bin", 0x0000, 0x0400, CRC(e2b23324) SHA1(0a38c5f2cea929d2fe0a23e5e1a60de9155815dc)) ROM_END +} // anonymous namespace -/* YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY, FULLNAME, FLAGS */ -COMP( 1979, odyssey2, 0, 0, odyssey2, odyssey2, odyssey2_state, empty_init, "Magnavox", "Odyssey 2 (US)", MACHINE_SUPPORTS_SAVE ) -COMP( 1978, videopac, odyssey2, 0, videopac, odyssey2, odyssey2_state, empty_init, "Philips", "Videopac G7000 (Europe)", MACHINE_SUPPORTS_SAVE ) -COMP( 1979, videopacf, odyssey2, 0, videopacf, odyssey2, odyssey2_state, empty_init, "Philips", "Videopac C52 (France)", MACHINE_SUPPORTS_SAVE ) -COMP( 1983, g7400, 0, 0, g7400, g7400, g7400_state, empty_init, "Philips", "Videopac+ G7400 (Europe)", MACHINE_SUPPORTS_SAVE | MACHINE_IMPERFECT_GRAPHICS ) -COMP( 1983, jopac, g7400, 0, g7400, g7400, g7400_state, empty_init, "Philips (Brandt license)", "Jopac JO7400 (France)", MACHINE_SUPPORTS_SAVE | MACHINE_IMPERFECT_GRAPHICS ) -COMP( 1983, odyssey3, g7400, 0, odyssey3, g7400, g7400_state, empty_init, "Magnavox", "Odyssey 3 Command Center (US, prototype)", MACHINE_SUPPORTS_SAVE | MACHINE_IMPERFECT_GRAPHICS ) + +/****************************************************************************** + Drivers +******************************************************************************/ + +// YEAR NAME PARENT CMP MACHINE INPUT STATE INIT COMPANY, FULLNAME, FLAGS +COMP( 1979, odyssey2, 0, 0, odyssey2, odyssey2, odyssey2_state, empty_init, "Magnavox", "Odyssey 2 (US)", MACHINE_SUPPORTS_SAVE ) +COMP( 1978, videopac, odyssey2, 0, videopac, odyssey2, odyssey2_state, empty_init, "Philips", "Videopac G7000 (Europe)", MACHINE_SUPPORTS_SAVE ) +COMP( 1979, videopacf, odyssey2, 0, videopacf, odyssey2, odyssey2_state, empty_init, "Philips", "Videopac C52 (France)", MACHINE_SUPPORTS_SAVE ) + +COMP( 1983, g7400, 0, 0, g7400, g7400, g7400_state, empty_init, "Philips", "Videopac+ G7400 (Europe)", MACHINE_SUPPORTS_SAVE ) +COMP( 1983, jopac, g7400, 0, g7400, g7400, g7400_state, empty_init, "Philips (Brandt license)", "Jopac JO7400 (France)", MACHINE_SUPPORTS_SAVE ) +COMP( 1983, odyssey3, g7400, 0, odyssey3, g7400, g7400_state, empty_init, "Magnavox", "Odyssey 3 Command Center (US, prototype)", MACHINE_SUPPORTS_SAVE ) diff --git a/src/mame/drivers/saitek_intchess.cpp b/src/mame/drivers/saitek_intchess.cpp index 13330fe4429..7a65f4aa0f7 100644 --- a/src/mame/drivers/saitek_intchess.cpp +++ b/src/mame/drivers/saitek_intchess.cpp @@ -164,6 +164,7 @@ void intchess_state::vram_w(offs_t offset, u8 data) } + /****************************************************************************** I/O ******************************************************************************/