diff --git a/src/mame/drivers/twins.cpp b/src/mame/drivers/twins.cpp index f4c148b2ac4..ef550f88a7b 100644 --- a/src/mame/drivers/twins.cpp +++ b/src/mame/drivers/twins.cpp @@ -1,5 +1,5 @@ // license:BSD-3-Clause -// copyright-holders:David Haywood +// copyright-holders:David Haywood, Angelo Salese /* Twins @@ -69,10 +69,12 @@ AY3-8910 instead of YM2149 (compatible) video is not banked in this case instead palette data is sent to the ports strange palette format. -todo: -hook up eeprom (doesn't seem to work when hooked up??) -Twins set 1 takes a long time to boot (eeprom?) -Improve blitter / clear logic for Spider. +TODO: +- Proper fix for twins & twinsed2 crash after round 1 (MT #07516): + after clearing 1-5 it pings i2c for a couple times, expect it to be 0 then 1 otherwise + jumps to lalaland; +- Improve blitter / clear logic for Spider. +- Merge with hotblock.cpp; Electronic Devices was printed on rom labels 1994 date string is in ROM @@ -80,18 +82,20 @@ Electronic Devices was printed on rom labels Spider PCB appears almost identical but uses additional 'blitter' features. It is possible the Twins PCB has them too and doesn't use them. +twinsed1 is significantly changed hardware, uses a regular RAMDAC hookup for palette etc. -Twins (Electronic Devices license, set 2) is significantly changed hardware, uses a regular RAMDAC hookup for plaette etc. - - -To access Service Mode in Spider you must boot with P1 Left and P1 Right held down, -this requires the -joystick_contradictory switch on the commandline. +To access Service Mode: +- twins, twinsed2: you must boot with coin 1 and start 1 held down + (there's a test button on the PCB tho?) +- spider, twinsed1: you must boot with P1 Left and P1 Right held down, + this requires the -joystick_contradictory switch on the commandline; */ #include "emu.h" #include "cpu/nec/nec.h" #include "sound/ay8910.h" +#include "machine/bankdev.h" #include "machine/i2cmem.h" #include "video/ramdac.h" #include "emupal.h" @@ -104,87 +108,195 @@ public: twins_state(const machine_config &mconfig, device_type type, const char *tag) : driver_device(mconfig, type, tag) , m_maincpu(*this, "maincpu") - , m_paletteram(*this, "paletteram") + , m_screen(*this, "screen") , m_palette(*this, "palette") , m_i2cmem(*this, "i2cmem") + , m_overlay(*this, "overlay") , m_spritesinit(0) , m_videorambank(0) { } - void spider(machine_config &config); - void twinsed1(machine_config &config); void twins(machine_config &config); + void init_twins(); + void init_twinsed2(); + +protected: + required_device m_maincpu; + required_device m_screen; + required_device m_palette; + required_device m_i2cmem; + required_device m_overlay; + + std::unique_ptr m_bgvram; + std::unique_ptr m_fgvram; + std::unique_ptr m_paletteram; + uint16_t m_paloff; + int m_spritesinit; + int m_spriteswidth; + int m_spritesaddr; + uint16_t m_videorambank; + uint8_t* m_rom8; + + void base_config(machine_config &config); + void video_config(machine_config &config); + void sound_config(machine_config &config); + void base_map(address_map &map); + void twins_map(address_map &map); + uint32_t screen_update_twins(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); + + DECLARE_READ16_MEMBER(eeprom_r); + DECLARE_WRITE16_MEMBER(eeprom_w); + + void draw_background(bitmap_ind16 &bitmap, const rectangle &cliprect); + virtual void video_start() override; + + static constexpr u32 ram_size = 0x10000/2; + + inline u16* get_vram_base(); + DECLARE_READ16_MEMBER(vram_r); + DECLARE_WRITE16_MEMBER(vram_w); + DECLARE_WRITE16_MEMBER(vram_rmw_w); private: - required_device m_maincpu; - optional_shared_ptr m_paletteram; - required_device m_palette; - optional_device m_i2cmem; - uint16_t m_paloff; - DECLARE_READ16_MEMBER(twins_port4_r); - DECLARE_WRITE16_MEMBER(twins_port4_w); - DECLARE_WRITE16_MEMBER(twins_pal_w); - DECLARE_WRITE16_MEMBER(spider_pal_w); - DECLARE_WRITE16_MEMBER(porte_paloff0_w); - DECLARE_WRITE16_MEMBER(spider_paloff0_w); - DECLARE_WRITE16_MEMBER(spider_blitter_w); - DECLARE_READ16_MEMBER(spider_blitter_r); + DECLARE_WRITE16_MEMBER(access_w); + DECLARE_READ16_MEMBER(access_r); + virtual void machine_start() override; + + void ramdac_map(address_map &map); + void twins_io(address_map &map); +}; + +class twinsed1_state : public twins_state +{ +public: + twinsed1_state(const machine_config &mconfig, device_type type, const char *tag) + : twins_state(mconfig, type, tag) + {} + + void twinsed1(machine_config &config); + +private: + void twinsed1_io(address_map &map); + DECLARE_WRITE16_MEMBER(porte_paloff0_w); + DECLARE_WRITE16_MEMBER(twins_pal_w); +}; + +class spider_state : public twins_state +{ +public: + spider_state(const machine_config &mconfig, device_type type, const char *tag) + : twins_state(mconfig, type, tag) + {} + + void spider(machine_config &config); + +private: + uint32_t screen_update_spider(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); + + void draw_foreground(bitmap_ind16 &bitmap, const rectangle &cliprect); + + void spider_io(address_map &map); + DECLARE_WRITE16_MEMBER(spider_paloff0_w); DECLARE_READ16_MEMBER(spider_port_18_r); DECLARE_READ16_MEMBER(spider_port_1e_r); DECLARE_WRITE16_MEMBER(spider_port_1a_w); DECLARE_WRITE16_MEMBER(spider_port_1c_w); - int m_spritesinit; - int m_spriteswidth; - int m_spritesaddr; - - uint16_t m_mainram[0x10000 / 2]; - uint16_t m_videoram[0x10000 / 2]; - uint16_t m_videoram2[0x10000 / 2]; - uint16_t m_videorambank; - - uint32_t screen_update_twins(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); - uint32_t screen_update_spider(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); - - virtual void machine_start() override; - virtual void video_start() override; - uint16_t* m_rom16; - uint8_t* m_rom8; - - void ramdac_map(address_map &map); - void spider_io(address_map &map); - void twinsed1_io(address_map &map); - void twins_map(address_map &map); - void twins_io(address_map &map); + DECLARE_WRITE16_MEMBER(spider_pal_w); }; +void twins_state::video_start() +{ + m_paloff = 0; + + save_item(NAME(m_paloff)); + save_item(NAME(m_spritesinit)); + save_item(NAME(m_spriteswidth)); + save_item(NAME(m_spritesaddr)); + + m_bgvram = std::make_unique(ram_size); + std::fill_n(m_bgvram.get(), ram_size, 0); + save_pointer(NAME(m_bgvram), ram_size); + + m_fgvram = std::make_unique(ram_size); + std::fill_n(m_fgvram.get(), ram_size, 0); + save_pointer(NAME(m_fgvram), ram_size); + + const u16 palette_size = 0x100; + m_paletteram = std::make_unique(palette_size); + std::fill_n(m_paletteram.get(), palette_size, 0); + save_pointer(NAME(m_paletteram), palette_size); + + save_item(NAME(m_videorambank)); +} + +void twins_state::draw_background(bitmap_ind16 &bitmap, const rectangle &cliprect) +{ + uint8_t *videoram = (uint8_t*)m_bgvram.get(); + + for (int y = cliprect.top(); y <= cliprect.bottom(); y++) + { + int count = (y * 320) + cliprect.left(); + for(int x = cliprect.left(); x <= cliprect.right(); x++) + bitmap.pix16(y, x) = videoram[BYTE_XOR_LE(count++)]; + } +} + +uint32_t twins_state::screen_update_twins(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) +{ + bitmap.fill(m_palette->black_pen()); + draw_background(bitmap, cliprect); + return 0; +} + +void spider_state::draw_foreground(bitmap_ind16 &bitmap, const rectangle &cliprect) +{ + uint8_t *videoram = (uint8_t*)m_fgvram.get(); + + for (int y = cliprect.top(); y <= cliprect.bottom(); y++) + { + int count = (y * 320) + cliprect.left(); + for(int x = cliprect.left(); x <= cliprect.right(); x++) + { + u8 pixel = videoram[BYTE_XOR_LE(count++)]; + if (pixel) + bitmap.pix16(y, x) = pixel; + } + } +} + +uint32_t spider_state::screen_update_spider(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) +{ + bitmap.fill(m_palette->black_pen()); + draw_background(bitmap, cliprect); + draw_foreground(bitmap, cliprect); + return 0; +} void twins_state::machine_start() { - m_rom16 = (uint16_t*)memregion("maincpu")->base(); - m_rom8 = memregion("maincpu")->base(); + m_rom8 = memregion("ipl")->base(); } -/* port 4 is eeprom */ -READ16_MEMBER(twins_state::twins_port4_r) +READ16_MEMBER(twins_state::eeprom_r) { -// doesn't work?? -// printf("%08x: twins_port4_r %04x\n", m_maincpu->pc(), mem_mask); +// printf("%08x: eeprom_r %04x\n", m_maincpu->pc(), mem_mask); // return m_i2cmem->read_sda();// | 0xfffe; - - return 0x0001; + // TODO: bit 1, i2c clock readback? + + return m_i2cmem->read_sda(); } -WRITE16_MEMBER(twins_state::twins_port4_w) +WRITE16_MEMBER(twins_state::eeprom_w) { -// printf("%08x: twins_port4_w %04x %04x\n", m_maincpu->pc(), data, mem_mask); +// printf("%08x: eeprom_w %04x %04x\n", m_maincpu->pc(), data, mem_mask); int i2c_clk = BIT(data, 1); int i2c_mem = BIT(data, 0); m_i2cmem->write_scl(i2c_clk); m_i2cmem->write_sda(i2c_mem); } -WRITE16_MEMBER(twins_state::twins_pal_w) +WRITE16_MEMBER(twinsed1_state::twins_pal_w) { COMBINE_DATA(&m_paletteram[m_paloff]); @@ -202,52 +314,72 @@ WRITE16_MEMBER(twins_state::twins_pal_w) b = bitswap<8>(b,7,6,5,0,1,2,3,4); m_palette->set_pen_color(m_paloff, pal5bit(r),pal5bit(g),pal5bit(b)); - } m_paloff = (m_paloff + 1) & 0xff; } /* ??? weird ..*/ -WRITE16_MEMBER(twins_state::porte_paloff0_w) +WRITE16_MEMBER(twinsed1_state::porte_paloff0_w) { // printf("porte_paloff0_w %04x\n", data); m_paloff = 0; } -READ16_MEMBER(twins_state::spider_blitter_r) +inline u16 *twins_state::get_vram_base() { - uint16_t* vram; - if (m_videorambank & 1) - vram = m_videoram2; - else - vram = m_videoram; + return (m_videorambank & 1) ? m_fgvram.get() : m_bgvram.get(); +} - if (offset < 0x10000 / 2) +READ16_MEMBER(twins_state::vram_r) +{ + u16 *vram = get_vram_base(); + return vram[offset]; +} + +WRITE16_MEMBER(twins_state::vram_w) +{ + u16 *vram = get_vram_base(); + COMBINE_DATA(&vram[offset]); +} + +// TODO: confirm this area being present on twins versions +WRITE16_MEMBER(twins_state::vram_rmw_w) +{ + u16 *vram = get_vram_base(); + +// printf("spider_blitter_w %08x %04x %04x (previous data width %d address %08x)\n", offset * 2, data, mem_mask, m_spriteswidth, m_spritesaddr); + + for (int i = 0; i < m_spriteswidth; i++) { - return m_mainram[offset&0x7fff]; - } - else if (offset < 0x20000 / 2) - { - return vram[offset&0x7fff]; - } - else - { - uint16_t *src = m_rom16; - return src[offset]; + uint8_t data; + + data = (m_rom8[(m_spritesaddr * 2) + 1]); + + if (data) + vram[offset] = (vram[offset] & 0x00ff) | data << 8; + + data = m_rom8[(m_spritesaddr*2)]; + + if (data) + vram[offset] = (vram[offset] & 0xff00) | data; + + m_spritesaddr ++; + offset++; + + offset &= 0x7fff; } } +READ16_MEMBER(twins_state::access_r) +{ + return m_overlay->read16(offset, mem_mask); +} -WRITE16_MEMBER(twins_state::spider_blitter_w) +WRITE16_MEMBER(twins_state::access_w) { // this is very strange, we use the offset (address bits) not data bits to set values.. // I get the impression this might actually overlay the entire address range, including RAM and regular VRAM? - uint16_t* vram; - if (m_videorambank & 1) - vram = m_videoram2; - else - vram = m_videoram; if (m_spritesinit == 1) { @@ -264,239 +396,12 @@ WRITE16_MEMBER(twins_state::spider_blitter_w) m_spriteswidth = 80; m_spritesinit = 0; - } else - { - if (offset < 0x10000 / 2) - { - COMBINE_DATA(&m_mainram[offset&0x7fff]); - } - else if (offset < 0x20000 / 2) - { - COMBINE_DATA(&vram[offset&0x7fff]); - } - else if (offset < 0x30000 / 2) - { - uint8_t *src = m_rom8; - - // printf("spider_blitter_w %08x %04x %04x (previous data width %d address %08x)\n", offset * 2, data, mem_mask, m_spriteswidth, m_spritesaddr); - offset &= 0x7fff; - - for (int i = 0; i < m_spriteswidth; i++) - { - uint8_t data; - - data = (src[(m_spritesaddr * 2) + 1]); - - if (data) - vram[offset] = (vram[offset] & 0x00ff) | data << 8; - - - data = src[(m_spritesaddr*2)]; - - if (data) - vram[offset] = (vram[offset] & 0xff00) | data; - - - m_spritesaddr ++; - offset++; - - offset &= 0x7fff; - } - } - else - { - printf("spider_blitter_w unhandled RAM access %08x %04x %04x", offset * 2, data, mem_mask); - } - } + m_overlay->write16(offset, data, mem_mask); } - -void twins_state::twins_map(address_map &map) -{ - map(0x00000, 0xfffff).rw(FUNC(twins_state::spider_blitter_r), FUNC(twins_state::spider_blitter_w)); -} - -void twins_state::twinsed1_io(address_map &map) -{ - map(0x0000, 0x0003).w("aysnd", FUNC(ay8910_device::address_data_w)).umask16(0x00ff); - map(0x0002, 0x0002).r("aysnd", FUNC(ay8910_device::data_r)); - map(0x0004, 0x0005).rw(FUNC(twins_state::twins_port4_r), FUNC(twins_state::twins_port4_w)); - map(0x0006, 0x0007).w(FUNC(twins_state::twins_pal_w)).share("paletteram"); - map(0x000e, 0x000f).w(FUNC(twins_state::porte_paloff0_w)); -} - -void twins_state::video_start() -{ - m_paloff = 0; - - save_item(NAME(m_paloff)); - save_item(NAME(m_spritesinit)); - save_item(NAME(m_spriteswidth)); - save_item(NAME(m_spritesaddr)); - save_item(NAME(m_mainram)); - save_item(NAME(m_videoram)); - save_item(NAME(m_videoram2)); - save_item(NAME(m_videorambank)); -} - - -uint32_t twins_state::screen_update_twins(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) -{ - int y,x,count; - static const int xxx=320,yyy=204; - - bitmap.fill(m_palette->black_pen()); - - count=0; - uint8_t *videoram = (uint8_t*)m_videoram; - for (y=0;yblack_pen()); - - count=0; - uint8_t *videoram = (uint8_t*)m_videoram; - for (y=0;yset_addrmap(AS_PROGRAM, &twins_state::twins_map); - m_maincpu->set_addrmap(AS_IO, &twins_state::twinsed1_io); - - /* video hardware */ - screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER)); - screen.set_raw(8000000, 512, 0, 320, 312, 0, 200); // 15.625 kHz horizontal??? - screen.set_screen_update(FUNC(twins_state::screen_update_twins)); - screen.set_palette(m_palette); - screen.screen_vblank().set_inputline(m_maincpu, INPUT_LINE_NMI); - - I2C_24C02(config, m_i2cmem); - - PALETTE(config, m_palette).set_entries(0x100); - - /* sound hardware */ - SPEAKER(config, "mono").front_center(); - - ay8910_device &aysnd(AY8910(config, "aysnd", 2000000)); - aysnd.port_a_read_callback().set_ioport("P1"); - aysnd.port_b_read_callback().set_ioport("P2"); - aysnd.add_route(ALL_OUTPUTS, "mono", 1.0); -} - - -/* The Ecogames set and the Electronic Devices second set has different palette hardware - and a different port map than Electronic Devices first set */ - -void twins_state::twins_io(address_map &map) -{ - map(0x0000, 0x0000).w("ramdac", FUNC(ramdac_device::index_w)); - map(0x0002, 0x0002).w("ramdac", FUNC(ramdac_device::mask_w)); - map(0x0004, 0x0004).rw("ramdac", FUNC(ramdac_device::pal_r), FUNC(ramdac_device::pal_w)); - map(0x0008, 0x0008).w("aysnd", FUNC(ay8910_device::address_w)); - map(0x0010, 0x0010).rw("aysnd", FUNC(ay8910_device::data_r), FUNC(ay8910_device::data_w)); - map(0x0018, 0x0019).r(FUNC(twins_state::twins_port4_r)).w(FUNC(twins_state::twins_port4_w)); -} - - -void twins_state::ramdac_map(address_map &map) -{ - map(0x000, 0x3ff).rw("ramdac", FUNC(ramdac_device::ramdac_pal_r), FUNC(ramdac_device::ramdac_rgb666_w)); -} - - -void twins_state::twins(machine_config &config) -{ - /* basic machine hardware */ - V30(config, m_maincpu, XTAL(16'000'000)/2); /* verified on pcb */ - m_maincpu->set_addrmap(AS_PROGRAM, &twins_state::twins_map); - m_maincpu->set_addrmap(AS_IO, &twins_state::twins_io); - - /* video hardware */ - screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER)); - screen.set_raw(8000000, 512, 0, 320, 312, 0, 200); // 15.625 kHz horizontal??? - screen.set_screen_update(FUNC(twins_state::screen_update_twins)); - screen.set_palette(m_palette); - screen.screen_vblank().set_inputline(m_maincpu, INPUT_LINE_NMI); - - PALETTE(config, m_palette).set_entries(256); - ramdac_device &ramdac(RAMDAC(config, "ramdac", 0, m_palette)); - ramdac.set_addrmap(0, &twins_state::ramdac_map); - ramdac.set_split_read(0); - - I2C_24C02(config, m_i2cmem); - - /* sound hardware */ - SPEAKER(config, "mono").front_center(); - - ay8910_device &aysnd(AY8910(config, "aysnd", XTAL(16'000'000)/8)); /* verified on pcb */ - aysnd.port_a_read_callback().set_ioport("P1"); - aysnd.port_b_read_callback().set_ioport("P2"); - aysnd.add_route(ALL_OUTPUTS, "mono", 1.0); -} - -WRITE16_MEMBER(twins_state::spider_pal_w) +WRITE16_MEMBER(spider_state::spider_pal_w) { // ths first write doesn't appear to be a palette value if (m_paloff!=0) @@ -522,19 +427,19 @@ WRITE16_MEMBER(twins_state::spider_pal_w) } -WRITE16_MEMBER(twins_state::spider_paloff0_w) +WRITE16_MEMBER(spider_state::spider_paloff0_w) { // this seems to be video ram banking COMBINE_DATA(&m_videorambank); } -WRITE16_MEMBER(twins_state::spider_port_1a_w) +WRITE16_MEMBER(spider_state::spider_port_1a_w) { // writes 1 } -WRITE16_MEMBER(twins_state::spider_port_1c_w) +WRITE16_MEMBER(spider_state::spider_port_1c_w) { // done before the 'sprite' read / writes // might clear a buffer? @@ -544,21 +449,12 @@ WRITE16_MEMBER(twins_state::spider_port_1c_w) // data written is always 00, only seems to want the upper layer to be cleared // otherwise you get garbage sprites between rounds and the bg incorrectly wiped - uint16_t* vram; -// if (m_videorambank & 1) - vram = m_videoram2; -// else -// vram = m_videoram; - - for (int i = 0; i < 0x8000; i++) - { - vram[i] = 0x0000; - } - + for (int i = 0; i < ram_size; i++) + m_fgvram[i] = 0x0000; } -READ16_MEMBER(twins_state::spider_port_18_r) +READ16_MEMBER(spider_state::spider_port_18_r) { // read before each blitter command // seems to put the bus in a state where the next 2 bus access offsets (anywhere) are the blitter params @@ -567,75 +463,190 @@ READ16_MEMBER(twins_state::spider_port_18_r) return 0xff; } -READ16_MEMBER(twins_state::spider_port_1e_r) +READ16_MEMBER(spider_state::spider_port_1e_r) { // done before each sprite pixel 'write' // the data read is the data written, but only reads one pixel?? return 0xff; } - -void twins_state::spider_io(address_map &map) +void twins_state::twins_map(address_map &map) { - map(0x0000, 0x0003).w("aysnd", FUNC(ay8910_device::address_data_w)).umask16(0x00ff); - map(0x0002, 0x0002).r("aysnd", FUNC(ay8910_device::data_r)); - map(0x0004, 0x0005).rw(FUNC(twins_state::twins_port4_r), FUNC(twins_state::twins_port4_w)); - map(0x0008, 0x0009).w(FUNC(twins_state::spider_pal_w)).share("paletteram"); - map(0x0010, 0x0011).w(FUNC(twins_state::spider_paloff0_w)); - - map(0x0018, 0x0019).r(FUNC(twins_state::spider_port_18_r)); - map(0x001a, 0x001b).w(FUNC(twins_state::spider_port_1a_w)); - map(0x001c, 0x001d).w(FUNC(twins_state::spider_port_1c_w)); - map(0x001e, 0x001f).r(FUNC(twins_state::spider_port_1e_r)); - - + map(0x00000, 0xfffff).rw(FUNC(twins_state::access_r), FUNC(twins_state::access_w)); } - -void twins_state::spider(machine_config &config) +void twins_state::base_map(address_map &map) { - /* basic machine hardware */ - V30(config, m_maincpu, 8000000); - m_maincpu->set_addrmap(AS_PROGRAM, &twins_state::twins_map); - m_maincpu->set_addrmap(AS_IO, &twins_state::spider_io); + map(0x00000, 0x0ffff).ram(); + map(0x10000, 0x1ffff).rw(FUNC(twins_state::vram_r), FUNC(twins_state::vram_w)); + map(0x20000, 0x2ffff).w(FUNC(twins_state::vram_rmw_w)); + map(0x20000, 0xfffff).rom().region("ipl", 0x20000); +} - /* video hardware */ - screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER)); - screen.set_raw(8000000, 512, 0, 320, 312, 0, 200); // 15.625 kHz horizontal??? - screen.set_screen_update(FUNC(twins_state::screen_update_spider)); - screen.set_palette(m_palette); - screen.screen_vblank().set_inputline(m_maincpu, INPUT_LINE_NMI); +void twinsed1_state::twinsed1_io(address_map &map) +{ + map(0x0000, 0x0001).nopr(); + map(0x0000, 0x0003).w("aysnd", FUNC(ay8910_device::address_data_w)).umask16(0x00ff); + map(0x0002, 0x0002).r("aysnd", FUNC(ay8910_device::data_r)); + map(0x0004, 0x0005).rw(FUNC(twinsed1_state::eeprom_r), FUNC(twinsed1_state::eeprom_w)); + map(0x0006, 0x0007).w(FUNC(twinsed1_state::twins_pal_w)); + map(0x000e, 0x000f).w(FUNC(twinsed1_state::porte_paloff0_w)); +} - PALETTE(config, m_palette).set_entries(0x100); +/* The Ecogames set and the Electronic Devices second set has different palette hardware + and a different port map than Electronic Devices first set */ +void twins_state::twins_io(address_map &map) +{ + map(0x0000, 0x0001).nopr(); + map(0x0000, 0x0000).w("ramdac", FUNC(ramdac_device::index_w)); + map(0x0002, 0x0002).w("ramdac", FUNC(ramdac_device::mask_w)); + map(0x0004, 0x0004).rw("ramdac", FUNC(ramdac_device::pal_r), FUNC(ramdac_device::pal_w)); + map(0x0008, 0x0008).w("aysnd", FUNC(ay8910_device::address_w)); + map(0x0010, 0x0010).rw("aysnd", FUNC(ay8910_device::data_r), FUNC(ay8910_device::data_w)); + map(0x0018, 0x0019).r(FUNC(twins_state::eeprom_r)).w(FUNC(twins_state::eeprom_w)); +} + +void spider_state::spider_io(address_map &map) +{ + map(0x0000, 0x0001).nopr(); + map(0x0000, 0x0003).w("aysnd", FUNC(ay8910_device::address_data_w)).umask16(0x00ff); + map(0x0002, 0x0002).r("aysnd", FUNC(ay8910_device::data_r)); + map(0x0004, 0x0005).rw(FUNC(spider_state::eeprom_r), FUNC(spider_state::eeprom_w)); + map(0x0008, 0x0009).w(FUNC(spider_state::spider_pal_w)); + map(0x0010, 0x0011).w(FUNC(spider_state::spider_paloff0_w)); + + map(0x0018, 0x0019).r(FUNC(spider_state::spider_port_18_r)); + map(0x001a, 0x001b).w(FUNC(spider_state::spider_port_1a_w)); + map(0x001c, 0x001d).w(FUNC(spider_state::spider_port_1c_w)); + map(0x001e, 0x001f).r(FUNC(spider_state::spider_port_1e_r)); +} + +void twins_state::ramdac_map(address_map &map) +{ + map(0x000, 0x3ff).rw("ramdac", FUNC(ramdac_device::ramdac_pal_r), FUNC(ramdac_device::ramdac_rgb666_w)); +} + +static INPUT_PORTS_START(twins) + PORT_START("P1") /* 8bit */ + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_COIN1 ) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_START1 ) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_PLAYER(1) PORT_8WAY + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_PLAYER(1) PORT_8WAY + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_PLAYER(1) PORT_8WAY + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(1) PORT_8WAY + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(1) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(1) + + PORT_START("P2") /* 8bit */ + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_COIN2 ) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_START2 ) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_PLAYER(2) PORT_8WAY + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_PLAYER(2) PORT_8WAY + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_PLAYER(2) PORT_8WAY + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(2) PORT_8WAY + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(2) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(2) +INPUT_PORTS_END + +void twins_state::base_config(machine_config &config) +{ I2C_24C02(config, m_i2cmem); + + ADDRESS_MAP_BANK(config, m_overlay).set_map(&twins_state::base_map).set_options(ENDIANNESS_LITTLE, 16, 24, 0x100000); +} - /* sound hardware */ +void twins_state::video_config(machine_config &config) +{ + SCREEN(config, m_screen, SCREEN_TYPE_RASTER); + m_screen->set_raw(8000000, 512, 0, 320, 312, 0, 204); // Common PAL values, HSync of 15.625 kHz unverified + m_screen->set_palette(m_palette); + m_screen->screen_vblank().set_inputline(m_maincpu, INPUT_LINE_NMI); +} + +void twins_state::sound_config(machine_config &config) +{ SPEAKER(config, "mono").front_center(); - ay8910_device &aysnd(AY8910(config, "aysnd", 2000000)); + ay8910_device &aysnd(AY8910(config, "aysnd", XTAL(16'000'000)/8)); /* verified on pcb */ aysnd.port_a_read_callback().set_ioport("P1"); aysnd.port_b_read_callback().set_ioport("P2"); aysnd.add_route(ALL_OUTPUTS, "mono", 1.0); } +void twinsed1_state::twinsed1(machine_config &config) +{ + /* basic machine hardware */ + V30(config, m_maincpu, 8000000); + m_maincpu->set_addrmap(AS_PROGRAM, &twinsed1_state::twins_map); + m_maincpu->set_addrmap(AS_IO, &twinsed1_state::twinsed1_io); + + video_config(config); + m_screen->set_screen_update(FUNC(twinsed1_state::screen_update_twins)); + + base_config(config); + PALETTE(config, m_palette).set_entries(0x100); + + sound_config(config); +} + +void twins_state::twins(machine_config &config) +{ + /* basic machine hardware */ + V30(config, m_maincpu, XTAL(16'000'000)/2); /* verified on pcb */ + m_maincpu->set_addrmap(AS_PROGRAM, &twins_state::twins_map); + m_maincpu->set_addrmap(AS_IO, &twins_state::twins_io); + + video_config(config); + m_screen->set_screen_update(FUNC(twins_state::screen_update_twins)); + + PALETTE(config, m_palette).set_entries(256); + ramdac_device &ramdac(RAMDAC(config, "ramdac", 0, m_palette)); + ramdac.set_addrmap(0, &twins_state::ramdac_map); + ramdac.set_split_read(0); + + base_config(config); + + sound_config(config); +} + +void spider_state::spider(machine_config &config) +{ + /* basic machine hardware */ + V30(config, m_maincpu, 8000000); + m_maincpu->set_addrmap(AS_PROGRAM, &spider_state::twins_map); + m_maincpu->set_addrmap(AS_IO, &spider_state::spider_io); + + /* video hardware */ + video_config(config); + m_screen->set_screen_update(FUNC(spider_state::screen_update_spider)); + + PALETTE(config, m_palette).set_entries(0x100); + + base_config(config); + + sound_config(config); +} + /* ECOGAMES Twins */ ROM_START( twins ) - ROM_REGION( 0x100000, "maincpu", 0 ) + ROM_REGION16_LE( 0x100000, "ipl", 0 ) ROM_LOAD16_BYTE( "2.u8", 0x000000, 0x080000, CRC(1ec942b0) SHA1(627deb739c50f93c4cb61b8baf2a07213f1613b3) ) ROM_LOAD16_BYTE( "1.u9", 0x000001, 0x080000, CRC(4417ff34) SHA1(be992128fe48556a0a7c018953702b4ce9076526) ) - /* Unused */ - ROM_REGION( 0x000100, "extra", 0 ) - ROM_LOAD("24c02.u15", 0x000000, 0x000100, CRC(5ba30b14) SHA1(461f701879b76f1784705e067a5b6b31bfda4606) ) + ROM_REGION( 0x100, "i2cmem", 0 ) + ROM_LOAD("24c02.u15", 0x000, 0x100, CRC(2ff05b0e) SHA1(df6854446ba83f4a13ddf68bd2d0bc35be21be79) ) ROM_END /** Electronic Devices Twins */ ROM_START( twinsed1 ) - ROM_REGION( 0x100000, "maincpu", 0 ) + ROM_REGION16_LE( 0x100000, "ipl", 0 ) ROM_LOAD16_BYTE( "1.bin", 0x000000, 0x080000, CRC(d5ef7b0d) SHA1(7261dca5bb0aef755b4f2b85a159b356e7ac8219) ) ROM_LOAD16_BYTE( "2.bin", 0x000001, 0x080000, CRC(8a5392f4) SHA1(e6a2ecdb775138a87d27aa4ad267bdec33c26baa) ) + + ROM_REGION( 0x100, "i2cmem", 0 ) + ROM_LOAD("24c02.u15", 0x000, 0x100, CRC(2ff05b0e) SHA1(df6854446ba83f4a13ddf68bd2d0bc35be21be79) ) ROM_END /* @@ -652,24 +663,55 @@ Electronic Devices 1x jamma edge connector 1x trimmer (volume) -hmm, we're only emulating 1x ay-3-8910, is the other at port 0 on this? +=== + +Author note: we're only emulating 1x ay-3-8910, assume being unused or dumper typo (unaccessed by the game) +twinsed2 is basically the same game as twins except having nudity pics (and inps are interchangeable between the sets) */ ROM_START( twinsed2 ) - ROM_REGION( 0x100000, "maincpu", 0 ) + ROM_REGION16_LE( 0x100000, "ipl", 0 ) ROM_LOAD16_BYTE( "lp.bin", 0x000000, 0x080000, CRC(4f07862e) SHA1(fbda1973f79c6938c7f026a4db706e78781c2df8) ) ROM_LOAD16_BYTE( "hp.bin", 0x000001, 0x080000, CRC(aaf74b83) SHA1(09bd76b9fc5cb7ba6ffe1a2581ffd5633fe440b3) ) + + ROM_REGION( 0x100, "i2cmem", 0 ) + ROM_LOAD("24c02.u15", 0x000, 0x100, CRC(2ff05b0e) SHA1(df6854446ba83f4a13ddf68bd2d0bc35be21be79) ) ROM_END ROM_START( spider ) - ROM_REGION( 0x100000, "maincpu", 0 ) + ROM_REGION16_LE( 0x100000, "ipl", 0 ) ROM_LOAD16_BYTE( "20.bin", 0x000001, 0x080000, CRC(25e15f11) SHA1(b728f35c817f60a294e38d66559da8977b94a1f5) ) ROM_LOAD16_BYTE( "21.bin", 0x000000, 0x080000, CRC(ff224206) SHA1(d8d45850983542e811facc917d016841fc56a97f) ) + + ROM_REGION( 0x100, "i2cmem", 0 ) + ROM_LOAD("24c02", 0x000, 0x100, CRC(6f710d66) SHA1(1cc6d1134c5b81b7d0913f09c07d73675770d817) ) ROM_END -GAME( 1993, twins, 0, twins, twins, twins_state, empty_init, ROT0, "Ecogames", "Twins", MACHINE_SUPPORTS_SAVE ) -GAME( 1994, twinsed1, twins, twinsed1, twins, twins_state, empty_init, ROT0, "Ecogames (Electronic Devices license)", "Twins (Electronic Devices license, set 1)", MACHINE_SUPPORTS_SAVE ) -GAME( 1994, twinsed2, twins, twins, twins, twins_state, empty_init, ROT0, "Ecogames (Electronic Devices license)", "Twins (Electronic Devices license, set 2)", MACHINE_SUPPORTS_SAVE ) +void twins_state::init_twins() +{ + u8 *rom = (u8 *)memregion("ipl")->base(); + + rom[0x3497d] = 0x90; + rom[0x3497e] = 0x90; -GAME( 1994, spider, 0, spider, twins, twins_state, empty_init, ROT0, "Buena Vision", "Spider", MACHINE_IMPERFECT_GRAPHICS | MACHINE_SUPPORTS_SAVE ) + rom[0x34986] = 0x90; + rom[0x34987] = 0x90; +} + +void twins_state::init_twinsed2() +{ + u8 *rom = (u8 *)memregion("ipl")->base(); + + rom[0x349d3] = 0x90; + rom[0x349d4] = 0x90; + + rom[0x349dc] = 0x90; + rom[0x349dd] = 0x90; +} + +GAME( 1993, twins, 0, twins, twins, twins_state, init_twins, ROT0, "Ecogames", "Twins", MACHINE_SUPPORTS_SAVE ) +GAME( 1994, twinsed1, twins, twinsed1, twins, twinsed1_state, empty_init, ROT0, "Ecogames (Electronic Devices license)", "Twins (Electronic Devices license, set 1)", MACHINE_SUPPORTS_SAVE ) +GAME( 1994, twinsed2, twins, twins, twins, twins_state, init_twinsed2, ROT0, "Ecogames (Electronic Devices license)", "Twins (Electronic Devices license, set 2)", MACHINE_SUPPORTS_SAVE ) + +GAME( 1994, spider, 0, spider, twins, spider_state, empty_init, ROT0, "Buena Vision", "Spider", MACHINE_IMPERFECT_GRAPHICS | MACHINE_SUPPORTS_SAVE )