// license:BSD-3-Clause // copyright-holders:Angelo Salese /******************************************************************************************************* Photo Play (c) 199? Funworld Preliminary driver by Angelo Salese TODO: - BIOS CMOS doesn't save at all (needed for setting up the Hard Disk); - DISK BOOT FAILURE after eeprom checking (many unknown IDE cs1 reads/writes); - partition boot sector is missing from the CHD dump, protection? - Detects CPU type as "-S 16 MHz"? Sometimes it detects it as 486SX, unknown repro (after fiddling with CMOS settings anyway) - VGA BIOS reports being a Cirrus Logic GD5436 / 5446, it is unknown what exactly this game uses. - PCI hookups (no idea about what this uses), and improve/device-ify SiS85C49x; - ISA bus cards are completely guessworked; - EEPROM timings are hacked (writes mostly fail otherwise); - Eventually needs AudioDrive ES688 / ES1688 / ES1788 & ES1868 devices and serial ports "for linking" before actually booting; *******************************************************************************************************/ #include "emu.h" #include "cpu/i386/i386.h" #include "machine/eepromser.h" #include "machine/lpci.h" #include "machine/pcshare.h" #include "machine/pckeybrd.h" #include "machine/idectrl.h" #include "video/clgd542x.h" class photoply_state : public pcat_base_state { public: photoply_state(const machine_config &mconfig, device_type type, const char *tag) : pcat_base_state(mconfig, type, tag), m_eeprom(*this, "eeprom"), m_main_bios(*this, "bios"), m_video_bios(*this, "video_bios"), m_ex_bios(*this, "ex_bios") { } required_device m_eeprom; required_region_ptr m_main_bios; required_region_ptr m_video_bios; required_region_ptr m_ex_bios; uint8_t *m_shadow_ram; DECLARE_READ8_MEMBER(bios_r); DECLARE_WRITE8_MEMBER(bios_w); DECLARE_WRITE8_MEMBER(eeprom_w); uint16_t m_pci_shadow_reg; void photoply(machine_config &config); void photoply_io(address_map &map); void photoply_map(address_map &map); protected: virtual void machine_start() override; virtual void machine_reset() override; uint32_t sis_pcm_r(int function, int reg, uint32_t mem_mask); void sis_pcm_w(int function, int reg, uint32_t data, uint32_t mem_mask); }; // regs 0x00-0x3f both devices below // regs 0x40-0x7f SiS85C496 PCI & CPU Memory Controller (PCM) // regs 0x80-0xff SiS85C497 AT Bus Controller & Megacell (ATM) uint32_t photoply_state::sis_pcm_r(int function, int reg, uint32_t mem_mask) { uint32_t r = 0; //printf("PCM %02x %08x\n",reg,mem_mask); if(reg == 0) { // Device ID / Vendor ID return 0x04961039; } if(reg == 8) { // Device Class Code / Device Revision Identification return 0x06000002; } // Device Header Type if(reg == 0xc) return 0; if(reg == 0x44) { if(ACCESSING_BITS_8_15) // reg 0x45 r |= (m_pci_shadow_reg & 0xff00); if(ACCESSING_BITS_0_7) // reg 0x44 r |= (m_pci_shadow_reg & 0x00ff); } return r; } void photoply_state::sis_pcm_w(int function, int reg, uint32_t data, uint32_t mem_mask) { if(reg == 0x44) { /* * reg 0x45 * shadow RAM control * xxxx ---- * ---- x--- Internal Cache Cacheable Area Control * ---- -x-- PCI,ISA Master Access Shadow RAM Area Enable * ---- --x- Shadow RAM Read Control (1=Enable) * ---- ---x Shadow RAM Write Control (0=Enable) */ if(ACCESSING_BITS_8_15) m_pci_shadow_reg = (data & 0xff00) | (m_pci_shadow_reg & 0x00ff); /* * shadow RAM enable: * bit 7: 0xf8000-0xfffff shadow RAM enable * ... * bit 0: 0xc0000-0xc7fff shadow RAM enable */ if(ACCESSING_BITS_0_7) // reg 0x44 m_pci_shadow_reg = (data & 0x00ff) | (m_pci_shadow_reg & 0xff00); //printf("%04x\n",m_pci_shadow_reg); } } READ8_MEMBER(photoply_state::bios_r) { uint8_t bit_mask = (offset & 0x38000) >> 15; if((m_pci_shadow_reg & 0x200) == 0x200) { if(m_pci_shadow_reg & (1 << bit_mask)) return m_shadow_ram[offset]; } // TODO: this mapping is a complete guesswork // TODO: worth converting this to bankdev when PCI gets de-legacized switch(bit_mask & 7) { // cirrus logic video bios case 0: // c0000-c7fff return m_video_bios[offset & 0x7fff]; // multifunction board bios // Note: if filled with a reload on 0x4000-0x7fff it will repeat the "Combo I/O" EEPROM check (which looks unlikely) case 1: // c8000-cffff if ((offset & 0x7fff) == 0x3fff) { // other bits are unknown return m_eeprom->do_read() << 2; } return m_ex_bios[offset & 0x7fff]; case 2: // d0000-dffff case 3: return 0; } // e0000-fffff return m_main_bios[offset & 0x1ffff]; } WRITE8_MEMBER(photoply_state::bios_w) { // return m_bios[offset]; if((m_pci_shadow_reg & 0x100) == 0) { uint8_t bit_mask = (offset & 0x38000) >> 15; if(m_pci_shadow_reg & (1 << bit_mask)) m_shadow_ram[offset] = data; } } WRITE8_MEMBER(photoply_state::eeprom_w) { //logerror("Writing %X to EEPROM output port\n", data); m_eeprom->di_write(BIT(data, 0)); m_eeprom->clk_write(BIT(data, 1)); m_eeprom->cs_write(BIT(data, 2)); // Bits 2-3 also seem to be used to bank something else. // Bits 4-7 are set for some writes, but may do nothing? } void photoply_state::photoply_map(address_map &map) { map(0x00000000, 0x0009ffff).ram(); map(0x000a0000, 0x000bffff).rw("vga", FUNC(cirrus_gd5446_device::mem_r), FUNC(cirrus_gd5446_device::mem_w)); // AM_RANGE(0x000c0000, 0x000c7fff) AM_RAM AM_REGION("video_bios", 0) // AM_RANGE(0x000c8000, 0x000cffff) AM_RAM AM_REGION("ex_bios", 0) map(0x000c0000, 0x000fffff).rw(this, FUNC(photoply_state::bios_r), FUNC(photoply_state::bios_w)); map(0x00100000, 0x07ffffff).ram(); // 64MB RAM, guess! map(0xfffe0000, 0xffffffff).rom().region("bios", 0); } void photoply_state::photoply_io(address_map &map) { pcat32_io_common(map); map(0x00e8, 0x00eb).noprw(); map(0x0170, 0x0177).rw("ide2", FUNC(ide_controller_32_device::read_cs0), FUNC(ide_controller_32_device::write_cs0)); map(0x01f0, 0x01f7).rw("ide", FUNC(ide_controller_32_device::read_cs0), FUNC(ide_controller_32_device::write_cs0)); map(0x0202, 0x0202).w(this, FUNC(photoply_state::eeprom_w)); // AM_RANGE(0x0278, 0x027f) AM_RAM //parallel port 2 map(0x0370, 0x0377).rw("ide2", FUNC(ide_controller_32_device::read_cs1), FUNC(ide_controller_32_device::write_cs1)); // AM_RANGE(0x0378, 0x037f) AM_RAM //parallel port map(0x03b0, 0x03bf).rw("vga", FUNC(cirrus_gd5446_device::port_03b0_r), FUNC(cirrus_gd5446_device::port_03b0_w)); map(0x03c0, 0x03cf).rw("vga", FUNC(cirrus_gd5446_device::port_03c0_r), FUNC(cirrus_gd5446_device::port_03c0_w)); map(0x03d0, 0x03df).rw("vga", FUNC(cirrus_gd5446_device::port_03d0_r), FUNC(cirrus_gd5446_device::port_03d0_w)); map(0x03f0, 0x03f7).rw("ide", FUNC(ide_controller_32_device::read_cs1), FUNC(ide_controller_32_device::write_cs1)); map(0x0cf8, 0x0cff).rw("pcibus", FUNC(pci_bus_legacy_device::read), FUNC(pci_bus_legacy_device::write)); } #define AT_KEYB_HELPER(bit, text, key1) \ PORT_BIT( bit, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME(text) PORT_CODE(key1) static INPUT_PORTS_START( photoply ) PORT_START("pc_keyboard_0") PORT_BIT ( 0x0001, 0x0000, IPT_UNUSED ) /* unused scancode 0 */ AT_KEYB_HELPER( 0x0002, "Esc", KEYCODE_Q ) /* Esc 01 81 */ AT_KEYB_HELPER( 0x0004, "1", KEYCODE_1 ) AT_KEYB_HELPER( 0x0008, "2", KEYCODE_2 ) AT_KEYB_HELPER( 0x0010, "3", KEYCODE_3 ) AT_KEYB_HELPER( 0x0020, "4", KEYCODE_4 ) AT_KEYB_HELPER( 0x0040, "5", KEYCODE_5 ) AT_KEYB_HELPER( 0x0080, "6", KEYCODE_6 ) AT_KEYB_HELPER( 0x0100, "7", KEYCODE_7 ) AT_KEYB_HELPER( 0x0200, "8", KEYCODE_8 ) AT_KEYB_HELPER( 0x0400, "9", KEYCODE_9 ) AT_KEYB_HELPER( 0x0800, "0", KEYCODE_0 ) PORT_START("pc_keyboard_1") AT_KEYB_HELPER( 0x0020, "Y", KEYCODE_Y ) /* Y 15 95 */ AT_KEYB_HELPER( 0x1000, "Enter", KEYCODE_ENTER ) /* Enter 1C 9C */ PORT_START("pc_keyboard_2") PORT_START("pc_keyboard_3") AT_KEYB_HELPER( 0x0002, "N", KEYCODE_N ) /* N 31 B1 */ AT_KEYB_HELPER( 0x0800, "F1", KEYCODE_F1 ) /* F1 3B BB */ AT_KEYB_HELPER( 0x1000, "F2", KEYCODE_F2 ) AT_KEYB_HELPER( 0x4000, "F4", KEYCODE_F4 ) PORT_START("pc_keyboard_4") PORT_START("pc_keyboard_5") PORT_START("pc_keyboard_6") AT_KEYB_HELPER( 0x0040, "(MF2)Cursor Up", KEYCODE_UP ) /* Up 67 e7 */ AT_KEYB_HELPER( 0x0080, "(MF2)Page Up", KEYCODE_PGUP ) /* Page Up 68 e8 */ AT_KEYB_HELPER( 0x0100, "(MF2)Cursor Left", KEYCODE_LEFT ) /* Left 69 e9 */ AT_KEYB_HELPER( 0x0200, "(MF2)Cursor Right", KEYCODE_RIGHT ) /* Right 6a ea */ AT_KEYB_HELPER( 0x0800, "(MF2)Cursor Down", KEYCODE_DOWN ) /* Down 6c ec */ AT_KEYB_HELPER( 0x1000, "(MF2)Page Down", KEYCODE_PGDN ) /* Page Down 6d ed */ AT_KEYB_HELPER( 0x4000, "Del", KEYCODE_A ) /* Delete 6f ef */ PORT_START("pc_keyboard_7") INPUT_PORTS_END void photoply_state::machine_start() { m_shadow_ram = auto_alloc_array(machine(), uint8_t, 0x40000); save_pointer(NAME(m_shadow_ram),0x40000); } void photoply_state::machine_reset() { m_pci_shadow_reg = 0; } static const gfx_layout CGA_charlayout = { 8,8, 256, 1, { 0 }, { 0,1,2,3,4,5,6,7 }, { 0*8,1*8,2*8,3*8,4*8,5*8,6*8,7*8 }, 8*8 }; static GFXDECODE_START( photoply ) GFXDECODE_ENTRY( "video_bios", 0x6000+0xa5*8+7, CGA_charlayout, 0, 256 ) //there's also a 8x16 entry (just after the 8x8) GFXDECODE_END MACHINE_CONFIG_START(photoply_state::photoply) /* basic machine hardware */ MCFG_CPU_ADD("maincpu", I486DX4, 75000000) /* I486DX4, 75 or 100 Mhz */ MCFG_CPU_PROGRAM_MAP(photoply_map) MCFG_CPU_IO_MAP(photoply_io) MCFG_CPU_IRQ_ACKNOWLEDGE_DEVICE("pic8259_1", pic8259_device, inta_cb) pcat_common(config); MCFG_GFXDECODE_ADD("gfxdecode", "vga", photoply ) MCFG_IDE_CONTROLLER_32_ADD("ide", ata_devices, "hdd", nullptr, true) MCFG_ATA_INTERFACE_IRQ_HANDLER(DEVWRITELINE("pic8259_2", pic8259_device, ir6_w)) MCFG_IDE_CONTROLLER_32_ADD("ide2", ata_devices, nullptr, nullptr, true) MCFG_ATA_INTERFACE_IRQ_HANDLER(DEVWRITELINE("pic8259_2", pic8259_device, ir7_w)) MCFG_PCI_BUS_LEGACY_ADD("pcibus", 0) MCFG_PCI_BUS_LEGACY_DEVICE(5, DEVICE_SELF, photoply_state, sis_pcm_r, sis_pcm_w) MCFG_SCREEN_ADD("screen", RASTER) MCFG_SCREEN_RAW_PARAMS(XTAL(25'174'800),900,0,640,526,0,480) MCFG_SCREEN_UPDATE_DEVICE("vga", cirrus_gd5446_device, screen_update) MCFG_DEVICE_ADD("vga", CIRRUS_GD5446, 0) MCFG_VIDEO_SET_SCREEN("screen") MCFG_EEPROM_SERIAL_93C46_ADD("eeprom") MCFG_EEPROM_WRITE_TIME(attotime::from_usec(1)) MCFG_EEPROM_ERASE_ALL_TIME(attotime::from_usec(10)) MACHINE_CONFIG_END ROM_START(photoply) ROM_REGION(0x20000, "bios", 0) /* motherboard bios */ ROM_LOAD("award bootblock bios v1.0.bin", 0x000000, 0x20000, CRC(e96d1bbc) SHA1(64d0726c4e9ecee8fddf4cc39d92aecaa8184d5c) ) ROM_REGION(0x8000, "ex_bios", ROMREGION_ERASE00 ) /* multifunction board with a ESS AudioDrive chip, M27128A */ ROM_LOAD("enhanced bios.bin", 0x000000, 0x4000, CRC(a216404e) SHA1(c9067cf87d5c8106de00866bb211eae3a6c02c65) ) // ROM_RELOAD( 0x004000, 0x4000 ) // ROM_RELOAD( 0x008000, 0x4000 ) // ROM_RELOAD( 0x00c000, 0x4000 ) ROM_REGION(0x8000, "video_bios", 0 ) ROM_LOAD("vga.bin", 0x000000, 0x8000, CRC(7a859659) SHA1(ff667218261969c48082ec12aa91088a01b0cb2a) ) DISK_REGION( "ide:0:hdd:image" ) DISK_IMAGE( "pp201", 0, SHA1(23e1940d485d19401e7d0ad912ddad2cf2ea10b4) ) ROM_END // bios not provided, might be different ROM_START(photoply2k4) ROM_REGION(0x20000, "bios", 0) /* motherboard bios */ ROM_LOAD("award bootblock bios v1.0.bin", 0x000000, 0x20000, BAD_DUMP CRC(e96d1bbc) SHA1(64d0726c4e9ecee8fddf4cc39d92aecaa8184d5c) ) ROM_REGION(0x8000, "ex_bios", ROMREGION_ERASE00 ) /* multifunction board with a ESS AudioDrive chip, M27128A */ ROM_LOAD("enhanced bios.bin", 0x000000, 0x4000, BAD_DUMP CRC(a216404e) SHA1(c9067cf87d5c8106de00866bb211eae3a6c02c65) ) // ROM_RELOAD( 0x004000, 0x4000 ) // ROM_RELOAD( 0x008000, 0x4000 ) // ROM_RELOAD( 0x00c000, 0x4000 ) ROM_REGION(0x8000, "video_bios", 0 ) ROM_LOAD("vga.bin", 0x000000, 0x8000, CRC(7a859659) BAD_DUMP SHA1(ff667218261969c48082ec12aa91088a01b0cb2a) ) DISK_REGION( "ide:0:hdd:image" ) // CYLS:1023,HEADS:64,SECS:63,BPS:512. DISK_IMAGE( "pp2004", 0, SHA1(a3f8861cf91cf7e7446ec931f812e774ada20802) ) ROM_END GAME( 199?, photoply, 0, photoply, photoply, photoply_state, 0, ROT0, "Funworld", "Photo Play 2000 (v2.01)", MACHINE_NOT_WORKING|MACHINE_NO_SOUND|MACHINE_UNEMULATED_PROTECTION ) GAME( 2004, photoply2k4, 0, photoply, photoply, photoply_state, 0, ROT0, "Funworld", "Photo Play 2004", MACHINE_NOT_WORKING|MACHINE_NO_SOUND|MACHINE_UNEMULATED_PROTECTION )