diff options
Diffstat (limited to 'src/mame/drivers/gamate.c')
-rw-r--r-- | src/mame/drivers/gamate.c | 408 |
1 files changed, 408 insertions, 0 deletions
diff --git a/src/mame/drivers/gamate.c b/src/mame/drivers/gamate.c new file mode 100644 index 00000000000..ad1e129e60c --- /dev/null +++ b/src/mame/drivers/gamate.c @@ -0,0 +1,408 @@ +// license:GPL-2.0+ +// copyright-holders:Peter Trauner +/****************************************************************************** + PeT mess@utanet.at 2007, 2014 + Peter Wilhelmsen peter.wilhelmsen@gmail.com + Morten Shearman Kirkegaard morten+gamate@afdelingp.dk + Juan F??lix Mateos vectrex@hackermesh.org + + nmi unknown + bomb blast top status line missing + ******************************************************************************/ + +#include "emu.h" +#include "includes/gamate.h" +#include "ui/ui.h" + +class gamate_state : public driver_device +{ +public: + gamate_state(const machine_config &mconfig, device_type type, const char *tag) + : driver_device(mconfig, type, tag) + , m_maincpu(*this, "maincpu") + , m_sound(*this, "custom") + , m_cart(*this, "cartslot") + , m_io_joy(*this, "JOY") + , m_palette(*this, "palette") + , m_bios(*this, "bios") + , m_bank(*this, "bank") + , m_bankmulti(*this, "bankmulti") + { } + + DECLARE_PALETTE_INIT(gamate); + DECLARE_READ8_MEMBER(protection_r); + DECLARE_READ8_MEMBER(newer_protection_set); + DECLARE_WRITE8_MEMBER(protection_reset); + DECLARE_READ8_MEMBER(gamate_cart_protection_r); + DECLARE_WRITE8_MEMBER(gamate_cart_protection_w); + DECLARE_WRITE8_MEMBER(cart_bankswitchmulti_w); + DECLARE_WRITE8_MEMBER(cart_bankswitch_w); + DECLARE_READ8_MEMBER(gamate_video_r); + DECLARE_READ8_MEMBER(gamate_nmi_r); + DECLARE_WRITE8_MEMBER(gamate_video_w); + DECLARE_WRITE8_MEMBER(gamate_bios_w); + DECLARE_DRIVER_INIT(gamate); + UINT32 screen_update_gamate(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); + INTERRUPT_GEN_MEMBER(gamate_interrupt); + TIMER_CALLBACK_MEMBER(gamate_timer); + TIMER_CALLBACK_MEMBER(gamate_timer2); + +private: + virtual void machine_start(); + + struct + { + UINT8 reg[8]; + struct + { + bool page2; // else page1 + UINT8 ypos, xpos/*tennis*/; + UINT8 data[2][0x100][0x20]; + } bitmap; + UINT8 x, y; + bool y_increment; + } video; + + struct + { + bool set; + int bit_shifter; + UINT8 cartridge_byte; + UINT16 address; // in reality something more like short local cartridge address offset + bool unprotected; + bool failed; + } card_protection; + + required_device<cpu_device> m_maincpu; + required_device<gamate_sound_device> m_sound; + required_device<generic_slot_device> m_cart; + required_ioport m_io_joy; + required_device<palette_device> m_palette; + required_shared_ptr<UINT8> m_bios; + required_memory_bank m_bank; + required_memory_bank m_bankmulti; + emu_timer *timer1; + emu_timer *timer2; + UINT8 bank_multi; + UINT8 *m_cart_ptr; +}; + +WRITE8_MEMBER( gamate_state::gamate_cart_protection_w ) +{ + logerror("%.6f protection write %x %x address:%x data:%x shift:%d\n",machine().time().as_double(), offset, data, card_protection.address, card_protection.cartridge_byte, card_protection.bit_shifter); + + switch (offset) + { + case 0: + card_protection.failed= card_protection.failed || ((card_protection.cartridge_byte&0x80)!=0) != ((data&4)!=0); + card_protection.bit_shifter++; + if (card_protection.bit_shifter>=8) + { + card_protection.cartridge_byte=m_cart_ptr[card_protection.address++]; + card_protection.bit_shifter=0; + } + break; + } +} + +READ8_MEMBER( gamate_state::gamate_cart_protection_r ) +{ + UINT8 ret=1; + if (card_protection.bit_shifter==7 && card_protection.unprotected) + { + ret=m_cart_ptr[bank_multi*0x4000]; + } + else + { + card_protection.bit_shifter++; + if (card_protection.bit_shifter==8) + { + card_protection.bit_shifter=0; + card_protection.cartridge_byte='G'; + card_protection.unprotected=true; + } + ret=(card_protection.cartridge_byte&0x80) ? 2 : 0; + if (card_protection.bit_shifter==7 && !card_protection.failed) + { // now protection chip on cartridge activates cartridge chip select on cpu accesses +// m_maincpu->space(AS_PROGRAM).install_read_handler(0x6000, 0x6000, READ8_DELEGATE(gamate_state, gamate_cart_protection_r)); // next time I will try to get this working + } + card_protection.cartridge_byte<<=1; + } + logerror("%.6f protection read %x %x address:%x data:%x shift:%d\n",machine().time().as_double(), offset, ret, card_protection.address, card_protection.cartridge_byte, card_protection.bit_shifter); + return ret; +} + +READ8_MEMBER( gamate_state::protection_r ) +{ + return card_protection.set? 3: 1; +} // bits 0 and 1 checked + +WRITE8_MEMBER( gamate_state::protection_reset ) +{ +// writes 0x20 + card_protection.address=0x6005-0x6001; + card_protection.bit_shifter=0; + card_protection.cartridge_byte=m_cart_ptr[card_protection.address++]; //m_cart_rom[card_protection.address++]; + card_protection.failed=false; + card_protection.unprotected=false; +} + +READ8_MEMBER( gamate_state::newer_protection_set ) +{ + card_protection.set=true; + return 0; +} + +WRITE8_MEMBER( gamate_state::gamate_video_w ) +{ + video.reg[offset]=data; + switch (offset) + { + case 1: + if (data&0xf) + printf("lcd mode %x\n", data); + video.y_increment=data&0x40; + break; + case 2: + video.bitmap.xpos=data; + break; + case 3: + if (data>=200) + printf("lcd ypos: %x\n", data); + video.bitmap.ypos=data; + break; + case 4: + video.bitmap.page2=data&0x80; + video.x=data&0x1f; + break; + case 5: + video.y=data; + break; + case 7: + video.bitmap.data[video.bitmap.page2][video.y][video.x&(ARRAY_LENGTH(video.bitmap.data[0][0])-1)]=data; + if (video.y_increment) + video.y++; + else + video.x++; // overruns + } +} + +WRITE8_MEMBER( gamate_state::cart_bankswitchmulti_w ) +{ + bank_multi=data; + m_bankmulti->set_base(m_cart_ptr+0x4000*data+1); +} + +WRITE8_MEMBER( gamate_state::cart_bankswitch_w ) +{ + m_bank->set_base(m_cart_ptr+0x4000*data); +} + +READ8_MEMBER( gamate_state::gamate_video_r ) +{ + if (offset!=6) + return 0; + UINT8 data = video.bitmap.data[video.bitmap.page2][video.y][video.x&(ARRAY_LENGTH(video.bitmap.data[0][0])-1)]; +// if (m_maincpu->pc()<0xf000) +// machine().ui().popup_time(2, "lcd read x:%x y:%x mode:%x data:%x\n", video.x, video.y, video.reg[1], data); + if (video.y_increment) + video.y++; + else + video.x++; // overruns? + + return data; +} + +READ8_MEMBER( gamate_state::gamate_nmi_r ) +{ + UINT8 data=0; + machine().ui().popup_time(2, "nmi/4800 read\n"); + return data; +} + +static ADDRESS_MAP_START( gamate_mem, AS_PROGRAM, 8, gamate_state ) + AM_RANGE(0x0000, 0x03ff) AM_RAM + AM_RANGE(0x4000, 0x400d) AM_DEVREADWRITE("custom", gamate_sound_device, device_r, device_w) + AM_RANGE(0x4400, 0x4400) AM_READ_PORT("JOY") + AM_RANGE(0x4800, 0x4800) AM_READ(gamate_nmi_r) + AM_RANGE(0x5000, 0x5007) AM_READWRITE(gamate_video_r, gamate_video_w) + AM_RANGE(0x5800, 0x5800) AM_READ(newer_protection_set) + AM_RANGE(0x5900, 0x5900) AM_WRITE(protection_reset) + AM_RANGE(0x5a00, 0x5a00) AM_READ(protection_r) + AM_RANGE(0x6001, 0x9fff) AM_READ_BANK("bankmulti") + AM_RANGE(0xa000, 0xdfff) AM_READ_BANK("bank") + AM_RANGE(0x6000, 0x6000) AM_READWRITE(gamate_cart_protection_r, gamate_cart_protection_w) + AM_RANGE(0x8000, 0x8000) AM_WRITE(cart_bankswitchmulti_w) + AM_RANGE(0xc000, 0xc000) AM_WRITE(cart_bankswitch_w) + AM_RANGE(0xf000, 0xffff) AM_ROM AM_SHARE("bios") +ADDRESS_MAP_END + + +static INPUT_PORTS_START( gamate ) + PORT_START("JOY") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_JOYSTICK_UP) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_BUTTON2) PORT_NAME("A") + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_BUTTON1) PORT_NAME("B") + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_START) PORT_NAME("Start/Pause") + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_SELECT) PORT_NAME("Select") +INPUT_PORTS_END + +/* palette in red, green, blue tribles */ +static const unsigned char gamate_colors[4][3] = +{ + { 255,255,255 }, + { 0xa0, 0xa0, 0xa0 }, + { 0x60, 0x60, 0x60 }, + { 0, 0, 0 } +}; + +PALETTE_INIT_MEMBER(gamate_state, gamate) +{ + int i; + + for (i = 0; i < 4; i++) + { + palette.set_pen_color(i, gamate_colors[i][0], gamate_colors[i][1], gamate_colors[i][2]); + } +} + +static void BlitPlane(UINT16* line, UINT8 plane1, UINT8 plane2) +{ + line[3]=(plane1&1)|((plane2<<1)&2); + line[2]=((plane1>>1)&1)|((plane2<<0)&2); + line[1]=((plane1>>2)&1)|((plane2>>1)&2); + line[0]=((plane1>>3)&1)|((plane2>>2)&2); +} + +UINT32 gamate_state::screen_update_gamate(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) +{ + int x, y, j; + for (y=0;y<152;y++) + { + for (x=-(video.bitmap.xpos&7), j=0;x<160;x+=8, j++) + { + UINT8 d1, d2; + if (video.bitmap.ypos<200) + { + d1=video.bitmap.data[0][(y+video.bitmap.ypos)%200][(j+video.bitmap.xpos/8)&0x1f]; + d2=video.bitmap.data[1][(y+video.bitmap.ypos)%200][(j+video.bitmap.xpos/8)&0x1f]; + } + else + if ((video.bitmap.ypos&0xf)<8) + { // lcdtest, of course still some registers not known, my gamate doesn't display bottom lines; most likely problematic 200 warp around hardware! no real usage + int yi=(y+(video.bitmap.ypos&0xf)-8); + if (yi<0) + yi=video.bitmap.ypos+y; // in this case only 2nd plane used!?, source of first plane? + d1=video.bitmap.data[0][yi][(j+video.bitmap.xpos/8)&0x1f]; // value of lines bevor 0 chaos + d2=video.bitmap.data[1][yi][(j+video.bitmap.xpos/8)&0x1f]; + } + else + { + d1=video.bitmap.data[0][y][(j+video.bitmap.xpos/8)&0x1f]; + d2=video.bitmap.data[1][y][(j+video.bitmap.xpos/8)&0x1f]; + } + BlitPlane(&bitmap.pix16(y, x+4), d1, d2); + BlitPlane(&bitmap.pix16(y, x), d1>>4, d2>>4); + } + } + return 0; +} + +DRIVER_INIT_MEMBER(gamate_state,gamate) +{ + memset(&video, 0, sizeof(video));/* memset(m_ram, 0, sizeof(m_ram));*/ + timer1 = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(gamate_state::gamate_timer),this)); + timer2 = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(gamate_state::gamate_timer2),this)); +} + + +void gamate_state::machine_start() +{ + m_cart_ptr = memregion("maincpu")->base() + 0x6000; + if (m_cart->exists()) + { +// m_maincpu->space(AS_PROGRAM).install_read_handler(0x6000, 0x6000, READ8_DELEGATE(gamate_state, gamate_cart_protection_r)); + m_cart_ptr = m_cart->get_rom_base(); + m_bankmulti->set_base(m_cart->get_rom_base()+1); + m_bank->set_base(m_cart->get_rom_base()+0x4000); // bankswitched games in reality no offset + } +// m_bios[0xdf1]=0xea; m_bios[0xdf2]=0xea; // default bios: $47 protection readback + card_protection.set=false; + bank_multi=0; + card_protection.unprotected=false; + timer2->enable(TRUE); + timer2->reset(m_maincpu->cycles_to_attotime(1000)); +#if 0 + save_item(NAME(m_video.data)); + save_item(NAME(m_video.index)); + save_item(NAME(m_video.x)); + save_item(NAME(m_video.y)); + save_item(NAME(m_video.mode)); + save_item(NAME(m_video.delayed)); + save_item(NAME(m_video.pixels)); + save_item(NAME(m_ports)); + save_item(NAME(m_ram)); +#endif +} + +TIMER_CALLBACK_MEMBER(gamate_state::gamate_timer) +{ + m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE); + timer1->enable(FALSE); +} + +TIMER_CALLBACK_MEMBER(gamate_state::gamate_timer2) +{ + m_maincpu->set_input_line(M6502_IRQ_LINE, ASSERT_LINE); + timer1->enable(TRUE); + timer1->reset(m_maincpu->cycles_to_attotime(10/* cycles short enought to clear irq line early enough*/)); + timer2->enable(TRUE); + timer2->reset(m_maincpu->cycles_to_attotime(32768/2)); +} + + +INTERRUPT_GEN_MEMBER(gamate_state::gamate_interrupt) +{ +} + +static MACHINE_CONFIG_START( gamate, gamate_state ) + MCFG_CPU_ADD("maincpu", M6502, 4433000/2) + MCFG_CPU_PROGRAM_MAP(gamate_mem) + MCFG_CPU_VBLANK_INT_DRIVER("screen", gamate_state, gamate_interrupt) + + MCFG_SCREEN_ADD("screen", LCD) + MCFG_SCREEN_REFRESH_RATE(60) + MCFG_SCREEN_SIZE(160, 152) + MCFG_SCREEN_VISIBLE_AREA(0, 160-1, 0, 152-1) + MCFG_SCREEN_UPDATE_DRIVER(gamate_state, screen_update_gamate) + MCFG_SCREEN_PALETTE("palette") + + MCFG_PALETTE_ADD("palette", ARRAY_LENGTH(gamate_colors)) + MCFG_PALETTE_INIT_OWNER(gamate_state, gamate) + MCFG_DEFAULT_LAYOUT(layout_lcd) + + /* sound hardware */ + MCFG_SPEAKER_STANDARD_STEREO("lspeaker", "rspeaker") + MCFG_SOUND_ADD("custom", GAMATE_SND, 4433000/2) + MCFG_SOUND_ROUTE(0, "lspeaker", 0.50) + MCFG_SOUND_ROUTE(1, "rspeaker", 0.50) + + MCFG_GENERIC_CARTSLOT_ADD("cartslot", generic_linear_slot, "gamate_cart") + MCFG_SOFTWARE_LIST_ADD("cart_list","gamate") +MACHINE_CONFIG_END + + +ROM_START(gamate) + ROM_REGION(0x10000,"maincpu", 0) + ROM_SYSTEM_BIOS(0, "default", "DEFAULT") + ROMX_LOAD("gamate_bios_umc.bin", 0xf000, 0x1000, CRC(07090415) SHA1(ea449dc607601f9a68d855ad6ab53800d2e99297), ROM_BIOS(1) ) + ROM_SYSTEM_BIOS(1, "newer", "NEWER") + ROMX_LOAD("gamate_bios_9130__unknown__bit_icasc00001_9130-bs_r32261.bin", 0xf000, 0x1000, CRC(03a5f3a7) SHA1(4e9dfbfe916ca485530ef4221593ab68738e2217), ROM_BIOS(2) ) +ROM_END + + +/* YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME */ +CONS( 19??, gamate, 0, 0, gamate, gamate, gamate_state, gamate, "Bit Corp", "Gamate", 0) |