// license:BSD-3-Clause // copyright-holders:Charles MacDonald, Wilbert Pol, Angelo Salese /************************************************************ PC Engine CD HW notes: TODO: - Dragon Ball Z: ADPCM dies after the first upload; - Dragon Slayer - The Legend of Heroes: black screen; - Mirai Shonen Conan: dies at new game selection; - Snatcher: black screen after Konami logo, tries set up CD-DA while transferring data? - Steam Heart's: needs transfer ready irq to get past the gameplay hang, don't know exactly when it should fire - Steam Heart's: bad ADPCM irq, dialogue is cutted due of it; ============================================================= CD Interface Register 0x00 - CDC status x--- ---- busy signal -x-- ---- request signal ---x ---- cd signal ---- x--- i/o signal CD Interface Register 0x03 - BRAM lock / CD status -x-- ---- acknowledge signal --x- ---- done signal ---x ---- bram signal ---- x--- ADPCM 2 ---- -x-- ADPCM 1 ---- --x- CDDA left/right speaker select CD Interface Register 0x05 - CD-DA Volume low 8-bit port CD Interface Register 0x06 - CD-DA Volume high 8-bit port CD Interface Register 0x07 - BRAM unlock / CD status x--- ---- Enables BRAM CD Interface Register 0x0c - ADPCM status x--- ---- ADPCM is reading data ---- x--- ADPCM playback (0) stopped (1) currently playing ---- -x-- pending ADPCM data write ---- ---x ADPCM playback (1) stopped (0) currently playing CD Interface Register 0x0d - ADPCM address control x--- ---- ADPCM reset -x-- ---- ADPCM play --x- ---- ADPCM repeat ---x ---- ADPCM set length ---- x--- ADPCM set read address ---- --xx ADPCM set write address (note: some games reads bit 5 and wants it to be low otherwise they hangs, surely NOT an ADPCM repeat flag read because it doesn't make sense) CD Interface Register 0x0e - ADPCM playback rate CD Interface Register 0x0f - ADPCM fade in/out register ---- xxxx command setting: 0x00 ADPCM/CD-DA Fade-in 0x01 CD-DA fade-in 0x08 CD-DA fade-out (short) ADPCM fade-in 0x09 CD-DA fade-out (long) 0x0a ADPCM fade-out (long) 0x0c CD-DA fade-out (short) ADPCM fade-in 0x0d CD-DA fade-out (short) 0x0e ADPCM fade-out (short) *************************************************************/ #include "emu.h" #include "cpu/h6280/h6280.h" #include "includes/pce.h" /* joystick related data*/ #define JOY_CLOCK 0x01 #define JOY_RESET 0x02 void pce_state::init_mess_pce() { m_io_port_options = PCE_JOY_SIG | CONST_SIG; } void pce_state::init_tg16() { m_io_port_options = TG_16_JOY_SIG | CONST_SIG; } void pce_state::init_sgx() { m_io_port_options = PCE_JOY_SIG | CONST_SIG; } MACHINE_START_MEMBER(pce_state,pce) { if (m_cd) m_cd->late_setup(); // saving is only partially supported: it should be fine with cart games // OTOH CD states are saved but not correctly restored! save_item(NAME(m_io_port_options)); save_item(NAME(m_acard)); save_item(NAME(m_joystick_port_select)); save_item(NAME(m_joystick_data_select)); save_item(NAME(m_joy_6b_packet)); } MACHINE_RESET_MEMBER(pce_state,mess_pce) { for (auto & elem : m_joy_6b_packet) elem = 0; /* Note: Arcade Card BIOS contents are the same as System 3, only internal HW differs. We use a category to select between modes (some games can be run in either S-CD or A-CD modes) */ m_acard = m_a_card->read() & 1; if (m_cartslot->get_type() == PCE_CDSYS3J) { m_sys3_card = 1; m_maincpu->space(AS_PROGRAM).install_readwrite_handler(0x080000, 0x087fff, read8_delegate(*this, FUNC(pce_state::pce_cd_acard_wram_r)), write8_delegate(*this, FUNC(pce_state::pce_cd_acard_wram_w))); } if (m_cartslot->get_type() == PCE_CDSYS3U) { m_sys3_card = 3; m_maincpu->space(AS_PROGRAM).install_readwrite_handler(0x080000, 0x087fff, read8_delegate(*this, FUNC(pce_state::pce_cd_acard_wram_r)), write8_delegate(*this, FUNC(pce_state::pce_cd_acard_wram_w))); } } /* todo: how many input ports does the PCE have? */ WRITE8_MEMBER(pce_state::mess_pce_joystick_w) { int joy_i; uint8_t joy_type = m_joy_type->read(); /* bump counter on a low-to-high transition of bit 1 */ if ((!m_joystick_data_select) && (data & JOY_CLOCK)) { m_joystick_port_select = (m_joystick_port_select + 1) & 0x07; } /* do we want buttons or direction? */ m_joystick_data_select = data & JOY_CLOCK; /* clear counter if bit 2 is set */ if (data & JOY_RESET) { m_joystick_port_select = 0; for (joy_i = 0; joy_i < 5; joy_i++) { if (((joy_type >> (joy_i*2)) & 3) == 2) m_joy_6b_packet[joy_i] ^= 1; } } } READ8_MEMBER(pce_state::mess_pce_joystick_r) { uint8_t joy_type = m_joy_type->read(); uint8_t ret, data; if (m_joystick_port_select <= 4) { switch ((joy_type >> (m_joystick_port_select*2)) & 3) { case 0: //2-buttons pad data = m_joy[m_joystick_port_select]->read(); break; case 2: //6-buttons pad /* Two packets: 1st packet: directions + I, II, Run, Select 2nd packet: 6 buttons "header" (high 4 bits active low) + III, IV, V, VI Note that six buttons pad just doesn't work with (almost?) every single 2-button-only games, it's really just an after-thought and it is like this on real HW. */ data = m_joy6b[m_joystick_port_select]->read() >> (m_joy_6b_packet[m_joystick_port_select]*8); break; default: data = 0xff; break; } } else data = 0xff; if (m_joystick_data_select) data >>= 4; ret = (data & 0x0f) | m_io_port_options; #ifdef UNIFIED_PCE ret &= ~0x40; #endif return (ret); } WRITE8_MEMBER(pce_state::pce_cd_intf_w) { m_cd->update(); if (offset & 0x200 && m_sys3_card && m_acard) // route Arcade Card handling ports return m_cd->acard_w(space, offset, data); m_cd->intf_w(space, offset, data); m_cd->update(); } READ8_MEMBER(pce_state::pce_cd_intf_r) { m_cd->update(); if (offset & 0x200 && m_sys3_card && m_acard) // route Arcade Card handling ports return m_cd->acard_r(space, offset); if ((offset & 0xc0) == 0xc0 && m_sys3_card) //System 3 Card header handling { switch (offset & 0xcf) { case 0xc1: return 0xaa; case 0xc2: return 0x55; case 0xc3: return 0x00; case 0xc5: return (m_sys3_card & 2) ? 0x55 : 0xaa; case 0xc6: return (m_sys3_card & 2) ? 0xaa : 0x55; case 0xc7: return 0x03; } } return m_cd->intf_r(space, offset); } READ8_MEMBER(pce_state::pce_cd_acard_wram_r) { return pce_cd_intf_r(space, 0x200 | (offset & 0x6000) >> 9); } WRITE8_MEMBER(pce_state::pce_cd_acard_wram_w) { pce_cd_intf_w(space, 0x200 | (offset & 0x6000) >> 9, data); }