/****************************************************************************** PeT mess@utanet.at march 2008 vadem vg230 (single chip pc) based handheld although it is very related to standard pc hardware, it is different enough to make the standard pc driver one level more complex, so own driver ******************************************************************************/ #include "emu.h" #include "cpu/i86/i86.h" #include "imagedev/cartslot.h" #include "machine/pic8259.h" #include "machine/pit8253.h" /* rtc interrupt irq 2 */ struct vg230_t { UINT8 index; UINT8 data[0x100]; struct { UINT16 data; } bios_timer; // 1.19 MHz tclk signal struct { int seconds, minutes, hours, days; int alarm_seconds, alarm_minutes, alarm_hours, alarm_days; int onehertz_interrupt_on; int onehertz_interrupt_request; int alarm_interrupt_on; int alarm_interrupt_request; } rtc; struct { int write_protected; } pmu; }; struct ems_t { UINT8 data; int index; struct { UINT8 data[2]; int address; int type; int on; } mapper[26]; }; class pasogo_state : public driver_device { public: pasogo_state(const machine_config &mconfig, device_type type, const char *tag) : driver_device(mconfig, type, tag), m_maincpu(*this, "maincpu") { } required_device m_maincpu; DECLARE_READ8_MEMBER(ems_r); DECLARE_WRITE8_MEMBER(ems_w); DECLARE_READ8_MEMBER(vg230_io_r); DECLARE_WRITE8_MEMBER(vg230_io_w); vg230_t m_vg230; ems_t m_ems; DECLARE_DRIVER_INIT(pasogo); virtual void machine_reset(); virtual void palette_init(); UINT32 screen_update_pasogo(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); INTERRUPT_GEN_MEMBER(pasogo_interrupt); TIMER_DEVICE_CALLBACK_MEMBER(vg230_timer); DECLARE_WRITE_LINE_MEMBER(pasogo_pic8259_set_int_line); IRQ_CALLBACK_MEMBER(pasogo_irq_callback); void vg230_reset(); void vg230_init(); }; TIMER_DEVICE_CALLBACK_MEMBER(pasogo_state::vg230_timer) { vg230_t *vg230 = &m_vg230; vg230->rtc.seconds+=1; if (vg230->rtc.seconds>=60) { vg230->rtc.seconds=00; vg230->rtc.minutes+=1; if (vg230->rtc.minutes>=60) { vg230->rtc.minutes=0; vg230->rtc.hours+=1; if (vg230->rtc.hours>=24) { vg230->rtc.hours=0; vg230->rtc.days=(vg230->rtc.days+1)&0xfff; } } } if (vg230->rtc.seconds==vg230->rtc.alarm_seconds && vg230->rtc.minutes==vg230->rtc.alarm_minutes && vg230->rtc.hours==vg230->rtc.alarm_hours && (vg230->rtc.days&0x1f)==vg230->rtc.alarm_hours) { // generate alarm } } void pasogo_state::vg230_reset() { vg230_t *vg230 = &m_vg230; system_time systime; memset(vg230, 0, sizeof(*vg230)); vg230->pmu.write_protected=TRUE; machine().base_datetime(systime); vg230->rtc.seconds= systime.local_time.second; vg230->rtc.minutes= systime.local_time.minute; vg230->rtc.hours = systime.local_time.hour; vg230->rtc.days = 0; vg230->bios_timer.data=0x7200; // HACK } void pasogo_state::vg230_init() { vg230_reset(); } READ8_MEMBER( pasogo_state::vg230_io_r ) { vg230_t *vg230 = &m_vg230; int log=TRUE; UINT8 data=0; vg230->bios_timer.data+=0x100; //HACK if (offset&1) { data=vg230->data[vg230->index]; switch (vg230->index) { case 0x09: break; case 0x0a: if (vg230->data[9]&1) data=ioport("JOY")->read(); else data=0xff; break; case 0x30: data=vg230->bios_timer.data&0xff; break; case 0x31: data=vg230->bios_timer.data>>8; log=FALSE; break; case 0x70: data=vg230->rtc.seconds; log=FALSE; break; case 0x71: data=vg230->rtc.minutes; log=FALSE; break; case 0x72: data=vg230->rtc.hours; log=FALSE; break; case 0x73: data=vg230->rtc.days; break; case 0x74: data=vg230->rtc.days>>8; break; case 0x79: /*rtc status*/log=FALSE; break; case 0x7a: data&=~3; if (vg230->rtc.alarm_interrupt_request) data|=1<<1; if (vg230->rtc.onehertz_interrupt_request) data|=1<<0; break; case 0xc1: data&=~1; if (vg230->pmu.write_protected) data|=1; vg230->pmu.write_protected=FALSE; log=FALSE; break; } if (log) logerror("%.5x vg230 %02x read %.2x\n",(int) m_maincpu->pc(),vg230->index,data); // data=machine.root_device().memregion("maincpu")->base()[0x4000+offset]; } else data=vg230->index; return data; } WRITE8_MEMBER( pasogo_state::vg230_io_w ) { vg230_t *vg230 = &m_vg230; int log=TRUE; if (offset&1) { // machine.root_device().memregion("maincpu")->base()[0x4000+offset]=data; vg230->data[vg230->index]=data; switch (vg230->index) { case 0x09: break; case 0x70: vg230->rtc.seconds=data&0x3f; break; case 0x71: vg230->rtc.minutes=data&0x3f; break; case 0x72: vg230->rtc.hours=data&0x1f;break; case 0x73: vg230->rtc.days=(vg230->rtc.days&~0xff)|data; break; case 0x74: vg230->rtc.days=(vg230->rtc.days&0xff)|((data&0xf)<<8); break; case 0x75: vg230->rtc.alarm_seconds=data&0x3f; break; case 0x76: vg230->rtc.alarm_minutes=data&0x3f; break; case 0x77: vg230->rtc.alarm_hours=data&0x1f; break; case 0x78: vg230->rtc.days=data&0x1f; break; case 0x79: vg230->rtc.onehertz_interrupt_on=data&1; vg230->rtc.alarm_interrupt_on=data&2; log=FALSE; break; case 0x7a: if (data&2) { vg230->rtc.alarm_interrupt_request=FALSE; vg230->rtc.onehertz_interrupt_request=FALSE; /* update interrupt */ } break; } if (log) logerror("%.5x vg230 %02x write %.2x\n",(int)m_maincpu->pc(),vg230->index,data); } else vg230->index=data; } READ8_MEMBER( pasogo_state::ems_r ) { ems_t *ems = &m_ems; UINT8 data=0; switch (offset) { case 0: data=ems->data; break; case 2: case 3: data=ems->mapper[ems->index].data[offset&1]; break; } return data; } WRITE8_MEMBER( pasogo_state::ems_w ) { ems_t *ems = &m_ems; char bank[10]; switch (offset) { case 0: ems->data=data; switch (data&~3) { case 0x80: ems->index=0; break; case 0x84: ems->index=1; break; case 0x88: ems->index=2; break; case 0x8c: ems->index=3; break; case 0x90: ems->index=4; break; case 0x94: ems->index=5; break; case 0x98: ems->index=6; break; case 0x9c: ems->index=7; break; case 0xa0: ems->index=8; break; case 0xa4: ems->index=9; break; case 0xa8: ems->index=10; break; case 0xac: ems->index=11; break; case 0xb0: ems->index=12; break; case 0xb4: ems->index=13; break; // case 0xb8: ems->index=14; break; // case 0xbc: ems->index=15; break; case 0xc0: ems->index=14; break; case 0xc4: ems->index=15; break; case 0xc8: ems->index=16; break; case 0xcc: ems->index=17; break; case 0xd0: ems->index=18; break; case 0xd4: ems->index=19; break; case 0xd8: ems->index=20; break; case 0xdc: ems->index=21; break; case 0xe0: ems->index=22; break; case 0xe4: ems->index=23; break; case 0xe8: ems->index=24; break; case 0xec: ems->index=25; break; } break; case 2: case 3: ems->mapper[ems->index].data[offset&1]=data; ems->mapper[ems->index].address=(ems->mapper[ems->index].data[0]<<14)|((ems->mapper[ems->index].data[1]&0xf)<<22); ems->mapper[ems->index].on=ems->mapper[ems->index].data[1]&0x80; ems->mapper[ems->index].type=(ems->mapper[ems->index].data[1]&0x70)>>4; logerror("%.5x ems mapper %d(%05x)on:%d type:%d address:%07x\n",(int)m_maincpu->pc(),ems->index, ems->data<<12, ems->mapper[ems->index].on, ems->mapper[ems->index].type, ems->mapper[ems->index].address ); switch (ems->mapper[ems->index].type) { case 0: /*external*/ case 1: /*ram*/ sprintf(bank,"bank%d",ems->index+1); membank( bank )->set_base( memregion("maincpu")->base() + (ems->mapper[ems->index].address&0xfffff) ); break; case 3: /* rom 1 */ case 4: /* pc card a */ case 5: /* pc card b */ default: break; case 2: sprintf(bank,"bank%d",ems->index+1); membank( bank )->set_base( memregion("user1")->base() + (ems->mapper[ems->index].address&0xfffff) ); break; } break; } } static ADDRESS_MAP_START(pasogo_mem, AS_PROGRAM, 8, pasogo_state) // AM_RANGE(0x00000, 0xfffff) AM_UNMAP AM_MASK(0xfffff) // AM_RANGE( 0x4000, 0x7fff) AM_READWRITE(gmaster_io_r, gmaster_io_w) ADDRESS_MAP_GLOBAL_MASK(0xffFFF) AM_RANGE(0x00000, 0x7ffff) AM_RAM AM_RANGE(0x80000, 0x83fff) AM_RAMBANK("bank1") AM_RANGE(0x84000, 0x87fff) AM_RAMBANK("bank2") AM_RANGE(0x88000, 0x8bfff) AM_RAMBANK("bank3") AM_RANGE(0x8c000, 0x8ffff) AM_RAMBANK("bank4") AM_RANGE(0x90000, 0x93fff) AM_RAMBANK("bank5") AM_RANGE(0x94000, 0x97fff) AM_RAMBANK("bank6") AM_RANGE(0x98000, 0x9bfff) AM_RAMBANK("bank7") AM_RANGE(0x9c000, 0x9ffff) AM_RAMBANK("bank8") AM_RANGE(0xa0000, 0xa3fff) AM_RAMBANK("bank9") AM_RANGE(0xa4000, 0xa7fff) AM_RAMBANK("bank10") AM_RANGE(0xa8000, 0xabfff) AM_RAMBANK("bank11") AM_RANGE(0xac000, 0xaffff) AM_RAMBANK("bank12") AM_RANGE(0xb0000, 0xb3fff) AM_RAMBANK("bank13") AM_RANGE(0xb4000, 0xb7fff) AM_RAMBANK("bank14") // AM_RANGE(0xb8000, 0xbffff) AM_RAM AM_RANGE(0xb8000, 0xbffff) AM_RAMBANK("bank28") AM_RANGE(0xc0000, 0xc3fff) AM_RAMBANK("bank15") AM_RANGE(0xc4000, 0xc7fff) AM_RAMBANK("bank16") AM_RANGE(0xc8000, 0xcbfff) AM_RAMBANK("bank17") AM_RANGE(0xcc000, 0xcffff) AM_RAMBANK("bank18") AM_RANGE(0xd0000, 0xd3fff) AM_RAMBANK("bank19") AM_RANGE(0xd4000, 0xd7fff) AM_RAMBANK("bank20") AM_RANGE(0xd8000, 0xdbfff) AM_RAMBANK("bank21") AM_RANGE(0xdc000, 0xdffff) AM_RAMBANK("bank22") AM_RANGE(0xe0000, 0xe3fff) AM_RAMBANK("bank23") AM_RANGE(0xe4000, 0xe7fff) AM_RAMBANK("bank24") AM_RANGE(0xe8000, 0xebfff) AM_RAMBANK("bank25") AM_RANGE(0xec000, 0xeffff) AM_RAMBANK("bank26") AM_RANGE(0xf0000, 0xfffff) AM_ROMBANK("bank27") ADDRESS_MAP_END static ADDRESS_MAP_START(pasogo_io, AS_IO, 8, pasogo_state) // ADDRESS_MAP_GLOBAL_MASK(0xfFFF) AM_RANGE(0x0020, 0x0021) AM_DEVREADWRITE_LEGACY("pic8259", pic8259_r, pic8259_w) AM_RANGE(0x26, 0x27) AM_READWRITE(vg230_io_r, vg230_io_w ) AM_RANGE(0x0040, 0x0043) AM_DEVREADWRITE_LEGACY("pit8254", pit8253_r, pit8253_w) AM_RANGE(0x6c, 0x6f) AM_READWRITE(ems_r, ems_w ) ADDRESS_MAP_END static INPUT_PORTS_START( pasogo ) PORT_START("JOY") // PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_SELECT) PORT_NAME("select") // PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_START) PORT_NAME("start") PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_BUTTON1) PORT_NAME("O") /*?*/ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_BUTTON2) PORT_NAME("X") /*?*/ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT) PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("a") PORT_CODE(KEYCODE_A) PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("b") PORT_CODE(KEYCODE_B) INPUT_PORTS_END /* palette in red, green, blue tribles */ static const unsigned char pasogo_palette[][3] = { { 0, 0, 0 }, { 45,45,43 }, { 130, 159, 166 }, { 255,255,255 } }; void pasogo_state::palette_init() { int i; for ( i = 0; i < ARRAY_LENGTH(pasogo_palette); i++ ) { palette_set_color_rgb(machine(), i, pasogo_palette[i][0], pasogo_palette[i][1], pasogo_palette[i][2]); } } UINT32 pasogo_state::screen_update_pasogo(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) { //static int width=-1,height=-1; UINT8 *rom = memregion("maincpu")->base()+0xb8000; static const UINT16 c[]={ 3, 0 }; int x,y; // plot_box(bitmap, 0, 0, 64/*bitmap.width*/, bitmap.height, 0); int w=640; int h=240; if (0) { w=320; h=240; for (y=0;y>6)&3; *line++=(d>>4)&3; *line++=(d>>2)&3; *line++=(d>>0)&3; } } } else { for (y=0;y>7)&1]; *line++=c[(d>>6)&1]; *line++=c[(d>>5)&1]; *line++=c[(d>>4)&1]; *line++=c[(d>>3)&1]; *line++=c[(d>>2)&1]; *line++=c[(d>>1)&1]; *line++=c[(d>>0)&1]; } } } #if 0 if (w!=width || h!=height) { width=w; height=h; // machine().primary_screen->set_visible_area(0, width-1, 0, height-1); screen.set_visible_area(0, width-1, 0, height-1); } #endif return 0; } INTERRUPT_GEN_MEMBER(pasogo_state::pasogo_interrupt) { // m_maincpu->set_input_line(UPD7810_INTFE1, PULSE_LINE); } IRQ_CALLBACK_MEMBER(pasogo_state::pasogo_irq_callback) { return pic8259_acknowledge( machine().device("pic8259")); } void pasogo_state::machine_reset() { m_maincpu->set_irq_acknowledge_callback(device_irq_acknowledge_delegate(FUNC(pasogo_state::pasogo_irq_callback),this)); } //static const unsigned i86_address_mask = 0x000fffff; static const pit8253_config pc_pit8254_config = { { { 4772720/4, /* heartbeat IRQ */ DEVCB_NULL, DEVCB_DEVICE_LINE_MEMBER("pic8259", pic8259_device, ir0_w) }, { 4772720/4, /* dram refresh */ DEVCB_NULL, DEVCB_NULL }, { 4772720/4, /* pio port c pin 4, and speaker polling enough */ DEVCB_NULL, DEVCB_NULL } } }; WRITE_LINE_MEMBER(pasogo_state::pasogo_pic8259_set_int_line) { m_maincpu->set_input_line(0, state ? HOLD_LINE : CLEAR_LINE); } static const pic8259_interface pasogo_pic8259_config = { DEVCB_DRIVER_LINE_MEMBER(pasogo_state, pasogo_pic8259_set_int_line), DEVCB_LINE_VCC, DEVCB_NULL }; static MACHINE_CONFIG_START( pasogo, pasogo_state ) MCFG_CPU_ADD("maincpu", I80188/*V30HL in vadem vg230*/, 10000000/*?*/) MCFG_CPU_PROGRAM_MAP(pasogo_mem) MCFG_CPU_IO_MAP( pasogo_io) MCFG_CPU_VBLANK_INT_DRIVER("screen", pasogo_state, pasogo_interrupt) // MCFG_CPU_CONFIG(i86_address_mask) MCFG_PIT8254_ADD( "pit8254", pc_pit8254_config ) MCFG_PIC8259_ADD( "pic8259", pasogo_pic8259_config ) MCFG_SCREEN_ADD("screen", LCD) MCFG_SCREEN_REFRESH_RATE(60) MCFG_SCREEN_SIZE(640, 400) MCFG_SCREEN_VISIBLE_AREA(0, 640-1, 0, 400-1) MCFG_SCREEN_UPDATE_DRIVER(pasogo_state, screen_update_pasogo) MCFG_PALETTE_LENGTH(ARRAY_LENGTH(pasogo_palette)) #if 0 MCFG_SPEAKER_STANDARD_MONO("gmaster") MCFG_SOUND_ADD("custom", CUSTOM, 0) MCFG_SOUND_CONFIG(gmaster_sound_interface) MCFG_SOUND_ROUTE(0, "gmaster", 0.50) #endif MCFG_CARTSLOT_ADD("cart") MCFG_CARTSLOT_EXTENSION_LIST("bin") MCFG_CARTSLOT_MANDATORY MCFG_CARTSLOT_INTERFACE("pasogo_cart") MCFG_SOFTWARE_LIST_ADD("cart_list","pasogo") MCFG_TIMER_DRIVER_ADD_PERIODIC("vg230_timer", pasogo_state, vg230_timer, attotime::from_hz(1)) MACHINE_CONFIG_END ROM_START(pasogo) ROM_REGION(0x100000,"maincpu", ROMREGION_ERASEFF) // 1 megabyte dram? ROM_REGION(0x100000,"user1", ROMREGION_ERASEFF) ROM_CART_LOAD("cart", 0, 0x100000, ROM_NOMIRROR) ROM_END DRIVER_INIT_MEMBER(pasogo_state,pasogo) { vg230_init(); memset(&m_ems, 0, sizeof(m_ems)); membank( "bank27" )->set_base( memregion("user1")->base() + 0x00000 ); membank( "bank28" )->set_base( memregion("maincpu")->base() + 0xb8000/*?*/ ); } // YEAR NAME PARENT COMPAT MACHINE INPUT INIT COMPANY FULLNAME FLAGS CONS( 1996, pasogo, 0, 0, pasogo, pasogo, pasogo_state, pasogo, "KOEI", "PasoGo", GAME_NO_SOUND|GAME_NOT_WORKING)