diff options
author | MooglyGuy <MooglyGuy@users.noreply.github.com> | 2021-12-25 13:49:11 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-12-25 13:49:11 +0100 |
commit | 022361c6830f6b60c050f019f8e660da9f8ce3d9 (patch) | |
tree | 2f697ed0bc3c4b3dfbde9a8432d9e51f24752d26 | |
parent | 5594736bd550264a69cef454215c8689ea3addbc (diff) |
Complete re-write of Philips CD-i CDIC handling; re-promoted to working (#9038)
* -cdi: Significantly improved compatibility and re-promoted to working. [Ryan Holtz, CD-i Fan]
-rw-r--r-- | src/mame/drivers/cdi.cpp | 108 | ||||
-rw-r--r-- | src/mame/includes/cdi.h | 3 | ||||
-rw-r--r-- | src/mame/machine/cdicdic.cpp | 1492 | ||||
-rw-r--r-- | src/mame/machine/cdicdic.h | 176 | ||||
-rw-r--r-- | src/mame/machine/cdislavehle.cpp | 119 | ||||
-rw-r--r-- | src/mame/machine/cdislavehle.h | 24 |
6 files changed, 915 insertions, 1007 deletions
diff --git a/src/mame/drivers/cdi.cpp b/src/mame/drivers/cdi.cpp index f5579cf659a..37095ebe8ac 100644 --- a/src/mame/drivers/cdi.cpp +++ b/src/mame/drivers/cdi.cpp @@ -80,63 +80,59 @@ TODO: void cdi_state::cdimono1_mem(address_map &map) { - map(0x00000000, 0x0007ffff).ram().share("mcd212:planea"); - map(0x00200000, 0x0027ffff).ram().share("mcd212:planeb"); - map(0x00300000, 0x00303bff).rw(m_cdic, FUNC(cdicdic_device::ram_r), FUNC(cdicdic_device::ram_w)); + map(0x000000, 0xffffff).rw(FUNC(cdi_state::bus_error_r), FUNC(cdi_state::bus_error_w)); + map(0x000000, 0x07ffff).ram().share("mcd212:planea"); + map(0x200000, 0x27ffff).ram().share("mcd212:planeb"); + map(0x300000, 0x303bff).rw(m_cdic, FUNC(cdicdic_device::ram_r), FUNC(cdicdic_device::ram_w)); #if ENABLE_UART_PRINTING - map(0x00301400, 0x00301403).r(m_maincpu, FUNC(scc68070_device::uart_loopback_enable)); + map(0x301400, 0x301403).r(m_maincpu, FUNC(scc68070_device::uart_loopback_enable)); #endif - map(0x00303c00, 0x00303fff).rw(m_cdic, FUNC(cdicdic_device::regs_r), FUNC(cdicdic_device::regs_w)); - map(0x00310000, 0x00317fff).rw(m_slave_hle, FUNC(cdislave_hle_device::slave_r), FUNC(cdislave_hle_device::slave_w)); - map(0x00318000, 0x0031ffff).noprw(); - map(0x00320000, 0x00323fff).rw("mk48t08", FUNC(timekeeper_device::read), FUNC(timekeeper_device::write)).umask16(0xff00); /* nvram (only low bytes used) */ - map(0x00400000, 0x0047ffff).rom().region("maincpu", 0); - map(0x004fffe0, 0x004fffff).rw(m_mcd212, FUNC(mcd212_device::regs_r), FUNC(mcd212_device::regs_w)); - map(0x00500000, 0x0057ffff).ram(); - map(0x00580000, 0x00cfffff).noprw(); - map(0x00d00000, 0x00dfffff).ram(); // DVC RAM block 1 - map(0x00e00000, 0x00e7ffff).rw(FUNC(cdi_state::dvc_r), FUNC(cdi_state::dvc_w)); - map(0x00e80000, 0x00efffff).ram(); // DVC RAM block 2 - map(0x00f00000, 0x00ffffff).noprw(); + map(0x303c00, 0x303fff).rw(m_cdic, FUNC(cdicdic_device::regs_r), FUNC(cdicdic_device::regs_w)); + map(0x310000, 0x317fff).rw(m_slave_hle, FUNC(cdislave_hle_device::slave_r), FUNC(cdislave_hle_device::slave_w)); + map(0x318000, 0x31ffff).noprw(); + map(0x320000, 0x323fff).rw("mk48t08", FUNC(timekeeper_device::read), FUNC(timekeeper_device::write)).umask16(0xff00); /* nvram (only low bytes used) */ + map(0x400000, 0x47ffff).rom().region("maincpu", 0); + map(0x4fffe0, 0x4fffff).rw(m_mcd212, FUNC(mcd212_device::regs_r), FUNC(mcd212_device::regs_w)); + map(0x500000, 0x57ffff).ram(); + map(0xd00000, 0xdfffff).ram(); // DVC RAM block 1 + map(0xe00000, 0xe7ffff).rw(FUNC(cdi_state::dvc_r), FUNC(cdi_state::dvc_w)); + map(0xe80000, 0xefffff).ram(); // DVC RAM block 2 } void cdi_state::cdimono2_mem(address_map &map) { - map(0x00000000, 0x0007ffff).ram().share("mcd212:planea"); - map(0x00200000, 0x0027ffff).ram().share("mcd212:planeb"); + map(0x000000, 0x07ffff).ram().share("mcd212:planea"); + map(0x200000, 0x27ffff).ram().share("mcd212:planeb"); #if ENABLE_UART_PRINTING - map(0x00301400, 0x00301403).r(m_maincpu, FUNC(scc68070_device::uart_loopback_enable)); + map(0x301400, 0x301403).r(m_maincpu, FUNC(scc68070_device::uart_loopback_enable)); #endif - //map(0x00300000, 0x00303bff).rw("cdic", FUNC(cdicdic_device::ram_r), FUNC(cdicdic_device::ram_w)); - //map(0x00303c00, 0x00303fff).rw("cdic", FUNC(cdicdic_device::regs_r), FUNC(cdicdic_device::regs_w)); - //map(0x00310000, 0x00317fff).rw("slave", FUNC(cdislave_hle_device::slave_r), FUNC(cdislave_hle_device::slave_w)); - //map(0x00318000, 0x0031ffff).noprw(); - map(0x00320000, 0x00323fff).rw("mk48t08", FUNC(timekeeper_device::read), FUNC(timekeeper_device::write)).umask16(0xff00); /* nvram (only low bytes used) */ - map(0x00400000, 0x0047ffff).rom().region("maincpu", 0); - map(0x004fffe0, 0x004fffff).rw(m_mcd212, FUNC(mcd212_device::regs_r), FUNC(mcd212_device::regs_w)); - //map(0x00500000, 0x0057ffff).ram(); - map(0x00500000, 0x00ffffff).noprw(); - //map(0x00e00000, 0x00efffff).ram(); + //map(0x300000, 0x303bff).rw("cdic", FUNC(cdicdic_device::ram_r), FUNC(cdicdic_device::ram_w)); + //map(0x303c00, 0x303fff).rw("cdic", FUNC(cdicdic_device::regs_r), FUNC(cdicdic_device::regs_w)); + //map(0x310000, 0x317fff).rw("slave", FUNC(cdislave_hle_device::slave_r), FUNC(cdislave_hle_device::slave_w)); + //map(0x318000, 0x31ffff).noprw(); + map(0x320000, 0x323fff).rw("mk48t08", FUNC(timekeeper_device::read), FUNC(timekeeper_device::write)).umask16(0xff00); /* nvram (only low bytes used) */ + map(0x400000, 0x47ffff).rom().region("maincpu", 0); + map(0x4fffe0, 0x4fffff).rw(m_mcd212, FUNC(mcd212_device::regs_r), FUNC(mcd212_device::regs_w)); } void cdi_state::cdi910_mem(address_map &map) { - map(0x00000000, 0x0007ffff).ram().share("mcd212:planea"); - map(0x00180000, 0x001fffff).rom().region("maincpu", 0); // boot vectors point here + map(0x000000, 0x07ffff).ram().share("mcd212:planea"); + map(0x180000, 0x1fffff).rom().region("maincpu", 0); // boot vectors point here - map(0x00200000, 0x0027ffff).ram().share("mcd212:planeb"); + map(0x200000, 0x27ffff).ram().share("mcd212:planeb"); #if ENABLE_UART_PRINTING - map(0x00301400, 0x00301403).r(m_maincpu, FUNC(scc68070_device::uart_loopback_enable)); + map(0x301400, 0x301403).r(m_maincpu, FUNC(scc68070_device::uart_loopback_enable)); #endif -// map(0x00300000, 0x00303bff).rw("cdic", FUNC(cdicdic_device::ram_r), FUNC(cdicdic_device::ram_w)); -// map(0x00303c00, 0x00303fff).rw("cdic", FUNC(cdicdic_device::regs_r), FUNC(cdicdic_device::regs_w)); -// map(0x00310000, 0x00317fff).rw("slave_hle", FUNC(cdislave_hle_device::slave_r), FUNC(cdislave_hle_device::slave_w)); -// map(0x00318000, 0x0031ffff).noprw(); - map(0x00320000, 0x00323fff).rw("mk48t08", FUNC(timekeeper_device::read), FUNC(timekeeper_device::write)).umask16(0xff00); /* nvram (only low bytes used) */ - map(0x004fffe0, 0x004fffff).rw(m_mcd212, FUNC(mcd212_device::regs_r), FUNC(mcd212_device::regs_w)); -// map(0x00500000, 0x0057ffff).ram(); - map(0x00500000, 0x00ffffff).noprw(); -// map(0x00e00000, 0x00efffff).ram(); // DVC +// map(0x300000, 0x303bff).rw("cdic", FUNC(cdicdic_device::ram_r), FUNC(cdicdic_device::ram_w)); +// map(0x303c00, 0x303fff).rw("cdic", FUNC(cdicdic_device::regs_r), FUNC(cdicdic_device::regs_w)); +// map(0x310000, 0x317fff).rw("slave_hle", FUNC(cdislave_hle_device::slave_r), FUNC(cdislave_hle_device::slave_w)); +// map(0x318000, 0x31ffff).noprw(); + map(0x320000, 0x323fff).rw("mk48t08", FUNC(timekeeper_device::read), FUNC(timekeeper_device::write)).umask16(0xff00); /* nvram (only low bytes used) */ + map(0x4fffe0, 0x4fffff).rw(m_mcd212, FUNC(mcd212_device::regs_r), FUNC(mcd212_device::regs_w)); +// map(0x500000, 0x57ffff).ram(); + map(0x500000, 0xffffff).noprw(); +// map(0xe00000, 0xefffff).ram(); // DVC } @@ -266,6 +262,32 @@ void quizard_state::machine_reset() /********************** +* BERR Handling * +**********************/ + +uint16_t cdi_state::bus_error_r(offs_t offset) +{ + if(!machine().side_effects_disabled()) + { + m_maincpu->set_buserror_details(offset*2, true, m_maincpu->get_fc()); + m_maincpu->set_input_line(M68K_LINE_BUSERROR, ASSERT_LINE); + m_maincpu->set_input_line(M68K_LINE_BUSERROR, CLEAR_LINE); + } + return 0xff; +} + +void cdi_state::bus_error_w(offs_t offset, uint16_t data) +{ + if(!machine().side_effects_disabled()) + { + m_maincpu->set_buserror_details(offset*2, false, m_maincpu->get_fc()); + m_maincpu->set_input_line(M68K_LINE_BUSERROR, ASSERT_LINE); + m_maincpu->set_input_line(M68K_LINE_BUSERROR, CLEAR_LINE); + } +} + + +/********************** * Quizard Protection * **********************/ @@ -885,7 +907,7 @@ ROM_END /* YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME */ // BIOS / System -CONS( 1991, cdimono1, 0, 0, cdimono1, cdi, cdi_state, empty_init, "Philips", "CD-i (Mono-I) (PAL)", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_GRAPHICS | MACHINE_IMPERFECT_SOUND | MACHINE_SUPPORTS_SAVE ) +CONS( 1991, cdimono1, 0, 0, cdimono1, cdi, cdi_state, empty_init, "Philips", "CD-i (Mono-I) (PAL)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_IMPERFECT_SOUND | MACHINE_SUPPORTS_SAVE ) CONS( 1991, cdimono2, 0, 0, cdimono2, cdimono2, cdi_state, empty_init, "Philips", "CD-i (Mono-II) (NTSC)", MACHINE_NOT_WORKING ) CONS( 1991, cdi910, 0, 0, cdi910, cdimono2, cdi_state, empty_init, "Philips", "CD-i 910-17P Mini-MMC (PAL)", MACHINE_NOT_WORKING ) CONS( 1991, cdi490a, 0, 0, cdimono1, cdi, cdi_state, empty_init, "Philips", "CD-i 490", MACHINE_NOT_WORKING ) diff --git a/src/mame/includes/cdi.h b/src/mame/includes/cdi.h index a77b8390b27..5b9f88e456b 100644 --- a/src/mame/includes/cdi.h +++ b/src/mame/includes/cdi.h @@ -64,6 +64,9 @@ private: uint16_t dvc_r(offs_t offset, uint16_t mem_mask = ~0); void dvc_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0); + uint16_t bus_error_r(offs_t offset); + void bus_error_w(offs_t offset, uint16_t data); + required_shared_ptr<uint16_t> m_planea; optional_device<cdislave_hle_device> m_slave_hle; optional_device<m68hc05c8_device> m_servo; diff --git a/src/mame/machine/cdicdic.cpp b/src/mame/machine/cdicdic.cpp index f7d5d6bb1bc..098b3f4769a 100644 --- a/src/mame/machine/cdicdic.cpp +++ b/src/mame/machine/cdicdic.cpp @@ -17,7 +17,7 @@ STATUS: TODO: -- Decapping and proper emulation. +- Work out more low-level functionality. *******************************************************************************/ @@ -39,196 +39,103 @@ TODO: #define LOG_RAM (1 << 9) #define LOG_ALL (LOG_DECODES | LOG_SAMPLES | LOG_COMMANDS | LOG_SECTORS | LOG_IRQS | LOG_READS | LOG_WRITES | LOG_UNKNOWNS | LOG_RAM) -#define VERBOSE (LOG_ALL) +#define VERBOSE (0) #include "logmacro.h" // device type definition DEFINE_DEVICE_TYPE(CDI_CDIC, cdicdic_device, "cdicdic", "CD-i CDIC") - //************************************************************************** -// GLOBAL VARIABLES +// STATIC MEMBERS //************************************************************************** -const int32_t cdicdic_device::s_cdic_adpcm_filter_coef[5][2] = +const int16_t cdicdic_device::s_xa_filter_coef[4][2] = { - { 0,0 }, - { 60,0 }, - { 115,-52 }, - { 98,-55 }, - { 122,-60 }, + { 0x000, 0x000 }, + { 0x0F0, 0x000 }, + { 0x1CC, -0x0D0 }, + { 0x188, -0x0DC } }; -//************************************************************************** -// INLINES -//************************************************************************** +const int32_t cdicdic_device::s_samples_per_sector = 18 * 28 * 2; -int cdicdic_device::is_valid_sample_buf(uint16_t addr) const +const uint16_t cdicdic_device::s_crc_ccitt_table[256] = { - const uint8_t *cdram8 = ((uint8_t*)m_ram.get()) + addr; - if (cdram8[10] != 0xff) - { - return 1; - } - return 0; -} - -double cdicdic_device::sample_buf_freq(uint16_t addr) const -{ - const uint8_t *cdram8 = ((uint8_t*)m_ram.get()) + addr + 8; - switch (cdram8[2] & 0x3f) - { - case 0: - case 1: - case 16: - case 17: - return clock2() / 512.0f; - - case 4: - case 5: - return clock2() / 1024.0f; - - default: - return clock2() / 1024.0f; - } -} - -int cdicdic_device::sample_buf_size(uint16_t addr) const -{ - const uint8_t *cdram8 = ((uint8_t*)m_ram.get()) + addr + 8; - switch (cdram8[2] & 0x3f) - { - case 0: - case 4: - return 4; - - case 1: - case 5: - case 16: - return 2; - - case 17: - return 1; - - default: - return 2; - } -} + 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, + 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, + 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, + 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, + 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, + 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, + 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, + 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, + 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, + 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, + 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, + 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, + 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, + 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, + 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, + 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, + 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, + 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, + 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, + 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, + 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, + 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, + 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, + 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, + 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, + 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, + 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, + 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, + 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, + 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, + 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, + 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0 +}; -static inline int16_t clamp(int16_t in) -{ - return in; -} +#define CRC_CCITT_ROUND(accum, data) (((accum << 8) | data) ^ s_crc_ccitt_table[accum >> 8]) //************************************************************************** // MEMBER FUNCTIONS //************************************************************************** -uint32_t cdicdic_device::increment_cdda_frame_bcd(uint32_t bcd) +void cdicdic_device::decode_xa_mono(int16_t *cdic_xa_last, const uint8_t *xa, int16_t *dp) { - uint8_t nybbles[6] = - { - static_cast<uint8_t>(bcd & 0x0000000f), - static_cast<uint8_t>((bcd & 0x000000f0) >> 4), - static_cast<uint8_t>((bcd & 0x00000f00) >> 8), - static_cast<uint8_t>((bcd & 0x0000f000) >> 12), - static_cast<uint8_t>((bcd & 0x000f0000) >> 16), - static_cast<uint8_t>((bcd & 0x00f00000) >> 20) - }; - nybbles[0]++; - if (nybbles[0] == 5 && nybbles[1] == 7) - { - nybbles[0] = 0; - nybbles[1] = 0; - nybbles[2]++; - } - else if (nybbles[0] == 10) - { - nybbles[1]++; - } - if (nybbles[2] == 10) - { - nybbles[3]++; - nybbles[2] = 0; - } - if (nybbles[3] == 6) - { - nybbles[4]++; - nybbles[3] = 0; - } - if (nybbles[4] == 10) - { - nybbles[5]++; - nybbles[4] = 0; - } - return (nybbles[5] << 20) | (nybbles[4] << 16) | (nybbles[3] << 12) | (nybbles[2] << 8) | (nybbles[1] << 4) | nybbles[0]; -} - -uint32_t cdicdic_device::increment_cdda_sector_bcd(uint32_t bcd) -{ - uint8_t nybbles[6] = - { - static_cast<uint8_t>(bcd & 0x0000000f), - static_cast<uint8_t>((bcd & 0x000000f0) >> 4), - static_cast<uint8_t>((bcd & 0x00000f00) >> 8), - static_cast<uint8_t>((bcd & 0x0000f000) >> 12), - static_cast<uint8_t>((bcd & 0x000f0000) >> 16), - static_cast<uint8_t>((bcd & 0x00f00000) >> 20) - }; - nybbles[2]++; - if (nybbles[2] == 10) - { - nybbles[3]++; - nybbles[2] = 0; - } - if (nybbles[3] == 6) - { - nybbles[4]++; - nybbles[3] = 0; - } - if (nybbles[4] == 10) - { - nybbles[5]++; - nybbles[4] = 0; - } - return (nybbles[5] << 20) | (nybbles[4] << 16) | (nybbles[3] << 12) | (nybbles[2] << 8) | (nybbles[1] << 4) | nybbles[0]; -} - -void cdicdic_device::decode_xa_mono(int32_t *cdic_xa_last, const uint8_t *xa, int16_t *dp) -{ - int32_t l0 = cdic_xa_last[0]; - int32_t l1 = cdic_xa_last[1]; + int16_t l0 = cdic_xa_last[0]; + int16_t l1 = cdic_xa_last[1]; for (int32_t b = 0; b < 18; b++) { for (int32_t s = 0; s < 4; s++) { - uint8_t flags = xa[(4 + (s << 1)) ^ 1]; + uint8_t flags = xa[4 + (s << 1)]; uint8_t shift = flags & 0xf; - uint8_t filter = flags >> 4; - int32_t f0 = s_cdic_adpcm_filter_coef[filter][0]; - int32_t f1 = s_cdic_adpcm_filter_coef[filter][1]; + uint8_t filter = (flags >> 4) & 3; + int16_t f0 = s_xa_filter_coef[filter][0]; + int16_t f1 = s_xa_filter_coef[filter][1]; for (int32_t i = 0; i < 28; i++) { - int16_t d = (xa[(16 + (i << 2) + s) ^ 1] & 0xf) << 12; - d = clamp((d >> shift) + (((l0 * f0) + (l1 * f1) + 32) >> 6)); + int16_t d = (xa[16 + (i << 2) + s] & 0xf) << 12; + d = (d >> shift) + (((l0 * f0) + (l1 * f1) + 128) >> 8); *dp = d; dp++; l1 = l0; l0 = d; } - flags = xa[(5 + (s << 1)) ^ 1]; + flags = xa[5 + (s << 1)]; shift = flags & 0xf; filter = flags >> 4; - f0 = s_cdic_adpcm_filter_coef[filter][0]; - f1 = s_cdic_adpcm_filter_coef[filter][1]; + f0 = s_xa_filter_coef[filter][0]; + f1 = s_xa_filter_coef[filter][1]; for (int32_t i = 0; i < 28; i++) { - int16_t d = (xa[(16 + (i << 2) + s) ^ 1] >> 4) << 12; - d = clamp((d >> shift) + (((l0 * f0) + (l1 * f1) + 32) >> 6)); + int16_t d = (xa[16 + (i << 2) + s] >> 4) << 12; + d = (d >> shift) + (((l0 * f0) + (l1 * f1) + 128) >> 8); *dp = d; dp++; l1 = l0; @@ -243,25 +150,25 @@ void cdicdic_device::decode_xa_mono(int32_t *cdic_xa_last, const uint8_t *xa, in cdic_xa_last[1] = l1; } -void cdicdic_device::decode_xa_mono8(int *cdic_xa_last, const unsigned char *xa, signed short *dp) +void cdicdic_device::decode_xa_mono8(int16_t *cdic_xa_last, const unsigned char *xa, signed short *dp) { - int32_t l0 = cdic_xa_last[0]; - int32_t l1 = cdic_xa_last[1]; + int16_t l0 = cdic_xa_last[0]; + int16_t l1 = cdic_xa_last[1]; for (int32_t b = 0; b < 18; b++) { for (int32_t s = 0; s < 4; s++) { - uint8_t flags = xa[(4 + s) ^ 1]; + uint8_t flags = xa[4 + s]; uint8_t shift = flags & 0xf; - uint8_t filter = flags >> 4; - int32_t f0 = s_cdic_adpcm_filter_coef[filter][0]; - int32_t f1 = s_cdic_adpcm_filter_coef[filter][1]; + uint8_t filter = (flags >> 4) & 3; + int16_t f0 = s_xa_filter_coef[filter][0]; + int16_t f1 = s_xa_filter_coef[filter][1]; for (int32_t i = 0; i < 28; i++) { - int16_t d = (xa[(16 + (i << 2) + s) ^ 1] << 8); - d = clamp((d >> shift) + (((l0 * f0) + (l1 * f1) + 32) >> 6)); + int16_t d = (xa[16 + (i << 2) + s] << 8); + d = (d >> shift) + (((l0 * f0) + (l1 * f1) + 128) >> 8); *dp = d; dp++; l1 = l0; @@ -276,41 +183,41 @@ void cdicdic_device::decode_xa_mono8(int *cdic_xa_last, const unsigned char *xa, cdic_xa_last[1] = l1; } -void cdicdic_device::decode_xa_stereo(int32_t *cdic_xa_last, const uint8_t *xa, int16_t *dp) +void cdicdic_device::decode_xa_stereo(int16_t *cdic_xa_last, const uint8_t *xa, int16_t *dp) { - int32_t l0 = cdic_xa_last[0]; - int32_t l1 = cdic_xa_last[1]; - int32_t l2 = cdic_xa_last[2]; - int32_t l3 = cdic_xa_last[3]; + int16_t l0 = cdic_xa_last[0]; + int16_t l1 = cdic_xa_last[1]; + int16_t l2 = cdic_xa_last[2]; + int16_t l3 = cdic_xa_last[3]; for (int32_t b = 0; b < 18; b++) { for (int32_t s = 0; s < 4; s++) { - uint8_t flags0 = xa[(4 + (s << 1)) ^ 1]; + uint8_t flags0 = xa[4 + (s << 1)]; uint8_t shift0 = flags0 & 0xf; - uint8_t filter0 = flags0 >> 4; - uint8_t flags1 = xa[(5 + (s << 1)) ^ 1]; + uint8_t filter0 = (flags0 >> 4) & 3; + uint8_t flags1 = xa[5 + (s << 1)]; uint8_t shift1 = flags1 & 0xf; - uint8_t filter1 = flags1 >> 4; + uint8_t filter1 = (flags1 >> 4) & 3; - int32_t f0 = s_cdic_adpcm_filter_coef[filter0][0]; - int32_t f1 = s_cdic_adpcm_filter_coef[filter0][1]; - int32_t f2 = s_cdic_adpcm_filter_coef[filter1][0]; - int32_t f3 = s_cdic_adpcm_filter_coef[filter1][1]; + int16_t f0 = s_xa_filter_coef[filter0][0]; + int16_t f1 = s_xa_filter_coef[filter0][1]; + int16_t f2 = s_xa_filter_coef[filter1][0]; + int16_t f3 = s_xa_filter_coef[filter1][1]; for (int32_t i = 0; i < 28; i++) { - int16_t d = xa[(16 + (i << 2) + s) ^ 1]; + int16_t d = xa[16 + (i << 2) + s]; int16_t d0 = (d & 0xf) << 12; int16_t d1 = (d >> 4) << 12; - d0 = clamp((d0 >> shift0) + (((l0 * f0) + (l1 * f1) + 32) >> 6)); + d0 = (d0 >> shift0) + (((l0 * f0) + (l1 * f1) + 128) >> 8); *dp = d0; dp++; l1 = l0; l0 = d0; - d1 = clamp((d1 >> shift1) + (((l2 * f2) + (l3 * f3) + 32) >> 6)); + d1 = (d1 >> shift1) + (((l2 * f2) + (l3 * f3) + 128) >> 8); *dp = d1; dp++; l3 = l2; @@ -327,40 +234,40 @@ void cdicdic_device::decode_xa_stereo(int32_t *cdic_xa_last, const uint8_t *xa, cdic_xa_last[3] = l3; } -void cdicdic_device::decode_xa_stereo8(int32_t *cdic_xa_last, const uint8_t *xa, int16_t *dp) +void cdicdic_device::decode_xa_stereo8(int16_t *cdic_xa_last, const uint8_t *xa, int16_t *dp) { - int32_t l0 = cdic_xa_last[0]; - int32_t l1 = cdic_xa_last[1]; - int32_t l2 = cdic_xa_last[2]; - int32_t l3 = cdic_xa_last[3]; + int16_t l0 = cdic_xa_last[0]; + int16_t l1 = cdic_xa_last[1]; + int16_t l2 = cdic_xa_last[2]; + int16_t l3 = cdic_xa_last[3]; for (int32_t b = 0; b < 18; b++) { for (int32_t s = 0; s < 4; s += 2) { - uint8_t flags0 = xa[(4 + s) ^ 1]; + uint8_t flags0 = xa[4 + s]; uint8_t shift0 = flags0 & 0xf; - uint8_t filter0 = flags0 >> 4; - uint8_t flags1 = xa[(5 + s) ^ 1]; + uint8_t filter0 = (flags0 >> 4) & 3; + uint8_t flags1 = xa[5 + s]; uint8_t shift1 = flags1 & 0xf; - uint8_t filter1 = flags1 >> 4; - int32_t f0 = s_cdic_adpcm_filter_coef[filter0][0]; - int32_t f1 = s_cdic_adpcm_filter_coef[filter0][1]; - int32_t f2 = s_cdic_adpcm_filter_coef[filter1][0]; - int32_t f3 = s_cdic_adpcm_filter_coef[filter1][1]; + uint8_t filter1 = (flags1 >> 4) & 3; + int16_t f0 = s_xa_filter_coef[filter0][0]; + int16_t f1 = s_xa_filter_coef[filter0][1]; + int16_t f2 = s_xa_filter_coef[filter1][0]; + int16_t f3 = s_xa_filter_coef[filter1][1]; for (int32_t i = 0; i < 28; i++) { - int16_t d0 = (xa[(16 + (i << 2) + s + 0) ^ 1] << 8); - int16_t d1 = (xa[(16 + (i << 2) + s + 1) ^ 1] << 8); + int16_t d0 = (xa[16 + (i << 2) + s + 0] << 8); + int16_t d1 = (xa[16 + (i << 2) + s + 1] << 8); - d0 = clamp((d0 >> shift0) + (((l0 * f0) + (l1 * f1) + 32) >> 6)); + d0 = (d0 >> shift0) + (((l0 * f0) + (l1 * f1) + 128) >> 8); *dp = d0; dp++; l1 = l0; l0 = d0; - d1 = clamp((d1 >> shift1) + (((l2 * f2) + (l3 * f3) + 32) >> 6)); + d1 = (d1 >> shift1) + (((l2 * f2) + (l3 * f3) + 128) >> 8); *dp = d1; dp++; l3 = l2; @@ -377,599 +284,528 @@ void cdicdic_device::decode_xa_stereo8(int32_t *cdic_xa_last, const uint8_t *xa, cdic_xa_last[3] = l3; } -void cdicdic_device::play_audio_sector() +void cdicdic_device::decode_8bit_xa_unit(int channel, uint8_t param, const uint8_t *data, int16_t *out_buffer) { -} + int gain_shift = 8 - (param & 0xf); -void cdicdic_device::decode_audio_sector(const uint8_t *xa, int32_t triggered) -{ - // Get XA format from sector header - const uint8_t *hdr = xa + 4; - int32_t channels; - int32_t bits = 4; + const int16_t *filter = s_xa_filter_coef[(param >> 4) & 3]; + int16_t *old_samples = &m_xa_last[channel << 1]; - if (hdr[2] == 0xff && triggered == 1) + for (int i = 0; i < 28; i++) { - return; + int32_t sample = *data; + if (sample >= 128) + sample -= 256; + data += 4; + + sample <<= gain_shift; + + sample += (filter[0] * old_samples[0] + filter[1] * old_samples[1] + 128) / 256; + + int16_t sample16 = (int16_t)sample; + if (sample < -32768) + sample16 = -32768; + else if (sample > 32767) + sample16 = 32767; + + old_samples[1] = old_samples[0]; + old_samples[0] = sample16; + + out_buffer[i] = sample16; } +} + +void cdicdic_device::decode_4bit_xa_unit(int channel, uint8_t param, const uint8_t *data, uint8_t shift, int16_t *out_buffer) +{ + int gain_shift = 12 - (param & 0xf); - int16_t *samples = &m_samples[m_decode_addr == 0x2800 ? 0 : 1][0]; - LOGMASKED(LOG_DECODES, "%s: decode_audio_sector: got header type %02x\n", machine().describe_context(), hdr[2]); + const int16_t *filter = s_xa_filter_coef[(param >> 4) & 3]; + int16_t *old_samples = &m_xa_last[channel << 1]; - switch (hdr[2] & 0x3f) // ignore emphasis and reserved bits + for (int i = 0; i < 28; i++) { - case 0: - channels = 1; - m_audio_sample_freq = clock2() / 512.0f; // / 1024.0f; - bits = 4; - m_audio_sample_size = 4; - break; + int32_t sample = (*data >> shift) & 0xf; + if (BIT(sample, 3)) + sample -= 16; + data += 4; - case 1: - channels = 2; - m_audio_sample_freq = clock2() / 512.0f; - bits = 4; - m_audio_sample_size = 2; - break; + sample <<= gain_shift; - case 4: - channels = 1; - m_audio_sample_freq = clock2() / 1024.0f; ///2.0f; - bits = 4; - m_audio_sample_size = 4; - break; + sample += (filter[0] * old_samples[0] + filter[1] * old_samples[1] + 128) / 256; - case 5: - channels = 2; - m_audio_sample_freq = clock2() / 1024.0f; //37800.0f/2.0f; - bits = 4; - m_audio_sample_size = 2; - break; + int16_t sample16 = (int16_t)(uint16_t)(sample & 0xffff); + if (sample < -32768) + sample16 = -32768; + else if (sample > 32767) + sample16 = 32767; - case 16: - channels = 1; - m_audio_sample_freq = clock2() / 512.0f; - bits = 8; - m_audio_sample_size = 2; - break; + old_samples[1] = old_samples[0]; + old_samples[0] = sample16; - case 17: - channels = 2; - m_audio_sample_freq = clock2() / 512.0f; - bits = 8; - m_audio_sample_size = 1; - break; + out_buffer[i] = sample16; + } +} - default: - fatalerror("play_xa: unhandled xa mode %08x\n", hdr[2]); +void cdicdic_device::play_raw_group(const uint8_t *data) +{ + int16_t samples[28]; + for (int i = 0; i < 28; i++) + { + samples[i] = (int16_t)((data[1] << 8) | data[0]); + data += 4; } - m_dmadac[0]->set_frequency(m_audio_sample_freq); - m_dmadac[1]->set_frequency(m_audio_sample_freq); + m_dmadac[0]->transfer(0, 1, 1, 28, samples); + m_dmadac[1]->transfer(0, 1, 1, 28, samples); +} + +void cdicdic_device::play_xa_group(const uint8_t coding, const uint8_t *data) +{ + static const uint16_t s_4bit_header_offsets[8] = { 0, 1, 2, 3, 8, 9, 10, 11 }; + static const uint16_t s_8bit_header_offsets[4] = { 0, 1, 2, 3 }; + static const uint16_t s_4bit_data_offsets[8] = { 16, 16, 17, 17, 18, 18, 19, 19 }; + static const uint16_t s_8bit_data_offsets[4] = { 16, 17, 18, 19 }; + + int16_t samples[28]; - switch (channels) + switch (coding & (CODING_BPS_MASK | CODING_CHAN_MASK)) { - case 1: - switch (bits) + case CODING_4BPS | CODING_MONO: + for (uint8_t i = 0; i < 8; i++) { - case 4: - decode_xa_mono(m_xa_last, hdr + 4, samples); - for (int32_t index = 18*28*8 - 1; index >= 0; index--) - { - samples[index*2 + 1] = samples[index]; - samples[index*2 + 0] = samples[index]; - } - samples[18*28*16 + 0] = samples[18*28*16 + 2] = samples[18*28*16 + 4] = samples[18*28*16 + 6] = samples[18*28*16 + 8] = samples[18*28*16 + 10] = samples[18*28*16 + 12] = samples[18*28*16 + 14] = samples[18*28*16 - 2]; - samples[18*28*16 + 1] = samples[18*28*16 + 3] = samples[18*28*16 + 5] = samples[18*28*16 + 7] = samples[18*28*16 + 9] = samples[18*28*16 + 11] = samples[18*28*16 + 13] = samples[18*28*16 + 15] = samples[18*28*16 - 1]; - break; - case 8: - decode_xa_mono8(m_xa_last, hdr + 4, samples); - for (int32_t index = 18*28*8 - 1; index >= 0; index--) - { - samples[index*2 + 1] = samples[index]; - samples[index*2 + 0] = samples[index]; - } - samples[18*28*8 + 0] = samples[18*28*8 + 2] = samples[18*28*8 + 4] = samples[18*28*8 + 6] = samples[18*28*8 + 8] = samples[18*28*8 + 10] = samples[18*28*8 + 12] = samples[18*28*8 + 14] = samples[18*28*8 - 2]; - samples[18*28*8 + 1] = samples[18*28*8 + 3] = samples[18*28*8 + 5] = samples[18*28*8 + 7] = samples[18*28*8 + 9] = samples[18*28*8 + 11] = samples[18*28*8 + 13] = samples[18*28*8 + 15] = samples[18*28*8 - 1]; - break; + decode_4bit_xa_unit(0, data[s_4bit_header_offsets[i]], data + s_4bit_data_offsets[i], (i & 1) ? 4 : 0, samples); + m_dmadac[0]->transfer(0, 1, 1, 28, samples); + m_dmadac[1]->transfer(0, 1, 1, 28, samples); } - break; - case 2: - switch (bits) + return; + + case CODING_4BPS | CODING_STEREO: + for (uint8_t i = 0; i < 8; i++) { - case 4: - decode_xa_stereo(m_xa_last, hdr + 4, samples); - samples[18*28*8 + 0] = samples[18*28*8 + 2] = samples[18*28*8 + 4] = samples[18*28*8 + 6] = samples[18*28*8 + 8] = samples[18*28*8 + 10] = samples[18*28*8 + 12] = samples[18*28*8 + 14] = samples[18*28*8 - 2]; - samples[18*28*8 + 1] = samples[18*28*8 + 3] = samples[18*28*8 + 5] = samples[18*28*8 + 7] = samples[18*28*8 + 9] = samples[18*28*8 + 11] = samples[18*28*8 + 13] = samples[18*28*8 + 15] = samples[18*28*8 - 1]; - //fwrite(samples, 1, 18*28*4*m_audio_sample_size, temp_adpcm); - break; - case 8: - decode_xa_stereo8(m_xa_last, hdr + 4, samples); - samples[18*28*4 + 0] = samples[18*28*4 + 2] = samples[18*28*4 + 4] = samples[18*28*4 + 6] = samples[18*28*4 + 8] = samples[18*28*4 + 10] = samples[18*28*4 + 12] = samples[18*28*4 + 14] = samples[18*28*4 - 2]; - samples[18*28*4 + 1] = samples[18*28*4 + 3] = samples[18*28*4 + 5] = samples[18*28*4 + 7] = samples[18*28*4 + 9] = samples[18*28*4 + 11] = samples[18*28*4 + 13] = samples[18*28*4 + 15] = samples[18*28*4 - 1]; - break; + decode_4bit_xa_unit(i & 1, data[s_4bit_header_offsets[i]], data + s_4bit_data_offsets[i], (i & 1) ? 4 : 0, samples); + m_dmadac[i & 1]->transfer(0, 1, 1, 28, samples); } - break; - } + return; - for (int i = 0; i < 2; i++) - { - m_dmadac[i]->enable(1); - m_dmadac[i]->transfer(i, 1, 2, 18*28*2*m_audio_sample_size, &m_samples[m_decode_addr == 0x2800 ? 0 : 1][0]); - m_dmadac[i]->flush(); + case CODING_8BPS | CODING_MONO: + for (uint8_t i = 0; i < 4; i++) + { + decode_8bit_xa_unit(0, data[s_8bit_header_offsets[i]], data + s_8bit_data_offsets[i], samples); + m_dmadac[0]->transfer(0, 1, 1, 28, samples); + m_dmadac[1]->transfer(0, 1, 1, 28, samples); + } + return; + + case CODING_8BPS | CODING_STEREO: + for (uint8_t i = 0; i < 4; i++) + { + decode_8bit_xa_unit(i & 1, data[s_8bit_header_offsets[i]], data + s_8bit_data_offsets[i], samples); + m_dmadac[i & 1]->transfer(0, 1, 1, 28, samples); + } + return; } } -TIMER_CALLBACK_MEMBER( cdicdic_device::periodic_sample_trigger ) +void cdicdic_device::play_audio_sector(const uint8_t coding, const uint8_t *data) { - // Indicate that data has been decoded - LOGMASKED(LOG_SAMPLES, "Flagging that audio data has been decoded\n"); - m_audio_buffer |= 0x8000; + if ((coding & CODING_CHAN_MASK) > CODING_STEREO || (coding & CODING_BPS_MASK) == CODING_BPS_MPEG || (coding & CODING_RATE_MASK) == CODING_RATE_RESV) + { + LOGMASKED(LOG_SECTORS, "Invalid coding (%02x), ignoring\n", coding); + return; + } + + int channels = 2; + offs_t buffer_length = 1; + if (!(coding & CODING_STEREO)) + { + channels = 1; + buffer_length *= 2; + } + + int bits = 4; + switch (coding & CODING_BPS_MASK) + { + case CODING_8BPS: + bits = 8; + break; + case CODING_16BPS: + bits = 16; + fatalerror("play_audio_sector: unhandled 16-bit coding mode\n"); + break; + default: + bits = 4; + buffer_length *= 2; + break; + } + + int32_t sample_frequency = 0; + switch (coding & CODING_RATE_MASK) + { + case CODING_37KHZ: + sample_frequency = clock2() / 512.0f; + break; + case CODING_18KHZ: + sample_frequency = clock2() / 1024.0f; + break; + case CODING_44KHZ: + fatalerror("play_audio_sector: unhandled 44KHz coding mode\n"); + break; + default: + // Can't happen due to above early-out + break; + } + + LOGMASKED(LOG_SECTORS, "Coding %02x, %d channels, %d bits, %08x frequency\n", coding, channels, bits, sample_frequency); + + m_dmadac[0]->set_frequency(sample_frequency); + m_dmadac[1]->set_frequency(sample_frequency); + m_dmadac[0]->set_volume(0x100); + m_dmadac[1]->set_volume(0x100); + + std::fill_n(&m_xa_last[0], 4, 0); - // Set the CDIC interrupt line - //LOGMASKED(LOG_SAMPLES, "Setting CDIC interrupt line for soundmap decode\n"); - //m_intreq_callback(ASSERT_LINE); + if (bits == 16 && channels == 2) + { + for (uint16_t i = 0; i < SECTOR_AUDIO_SIZE; i += 112, data += 112) + { + play_raw_group(data); + } + } + else + { + for (uint16_t i = 0; i < SECTOR_AUDIO_SIZE; i += 128, data += 128) + { + play_xa_group(coding, data); + } + } } -TIMER_CALLBACK_MEMBER( cdicdic_device::initial_sample_trigger ) +TIMER_CALLBACK_MEMBER( cdicdic_device::audio_tick ) { - // Indicate that data has been decoded - LOGMASKED(LOG_SAMPLES, "Flagging that audio data has been decoded\n"); - m_audio_buffer |= 0x8000; - - // Set the CDIC interrupt line - LOGMASKED(LOG_SAMPLES, "Setting CDIC interrupt line for soundmap decode\n"); - m_intreq_callback(ASSERT_LINE); + if (m_audio_sector_counter > 0) + { + m_audio_sector_counter--; + if (m_audio_sector_counter > 0) + { + LOGMASKED(LOG_SAMPLES, "Audio sector counter %d, deducting and skipping\n", m_audio_sector_counter); + return; + } + LOGMASKED(LOG_SAMPLES, "Audio sector counter now 0, deducting and playing\n"); + } - sample_trigger(); + if (m_decoding_audio_map) + { + process_audio_map(); + } } -TIMER_CALLBACK_MEMBER( cdicdic_device::audio_sample_trigger ) +void cdicdic_device::process_audio_map() { - if (is_valid_sample_buf(m_decode_addr)) + if (m_decode_addr == 0xffff) { - // Indicate that data has been decoded - LOGMASKED(LOG_SAMPLES, "Flagging that audio data has been decoded\n"); - m_audio_buffer |= 0x8000; + m_audio_sector_counter = 0; + m_audio_format_sectors = 0; + m_decoding_audio_map = false; + return; + } + + LOGMASKED(LOG_SAMPLES, "Procesing audio map from %04x\n", m_decode_addr); - // Set the CDIC interrupt line - LOGMASKED(LOG_SAMPLES, "Setting CDIC interrupt line for soundmap decode\n"); - m_intreq_callback(ASSERT_LINE); + uint8_t *ram = &m_ram[m_decode_addr & 0x3ffe]; + m_decode_addr ^= 0x1a00; - sample_trigger(); + const bool was_decoding = (m_audio_format_sectors != 0); + + const uint8_t coding = ram[(SECTOR_CODING2 - SECTOR_HEADER) ^ 1]; + LOGMASKED(LOG_SAMPLES, "Coding is %02x\n", coding); + if (coding != 0xff) + { + m_decoding_audio_map = true; + m_audio_format_sectors = get_sector_count_for_coding(coding); + m_audio_sector_counter = m_audio_format_sectors; + + ram += SECTOR_DATA - SECTOR_HEADER; + uint8_t swapped_data[(SECTOR_SIZE - (SECTOR_DATA - SECTOR_HEADER))]; + for (uint16_t i = 0; i < (SECTOR_SIZE - (SECTOR_DATA - SECTOR_HEADER)); i++) + { + swapped_data[i ^ 1] = ram[i]; + } + play_audio_sector(coding, swapped_data); } else { - // Indicate that data has been decoded - LOGMASKED(LOG_SAMPLES, "Flagging end of sample\n"); - m_audio_buffer |= 0x8000; + m_decode_addr = 0xffff; + } - // Set the CDIC interrupt line - //LOGMASKED(LOG_SAMPLES, "Setting CDIC interrupt line to flag that sample decoding is done\n"); - //m_intreq_callback(ASSERT_LINE); - m_z_buffer |= 1; + if (was_decoding) + { + m_audio_buffer |= 0x8000; + update_interrupt_state(); } } -void cdicdic_device::sample_trigger() +void cdicdic_device::update_interrupt_state() +{ + const bool interrupt_active = (bool)BIT(m_x_buffer | m_audio_buffer, 15); + m_intreq_callback(interrupt_active ? ASSERT_LINE : CLEAR_LINE); +} + +bool cdicdic_device::is_mode2_sector_selected(const uint8_t *buffer) { - LOGMASKED(LOG_SAMPLES, "sample_trigger with m_decode_addr == %04x\n", m_decode_addr); + if ((buffer[SECTOR_FILE2] << 8) != m_file) + { + LOGMASKED(LOG_SECTORS, "Mode 2 sector is not selected, current file: %04x, disc file: %04x\n", m_file, buffer[SECTOR_FILE2]); + return false; + } + + if (buffer[SECTOR_SUBMODE2] & SUBMODE_EOF) + { + LOGMASKED(LOG_SECTORS, "Mode 2 sector is EOF, queueing end of read\n"); + m_disc_command = 0; + } - bool decoding = true; - bool had_valid_sample = false; - m_decode_period = attotime::zero; - //const uint16_t decode_start = m_decode_addr; - do + // End-of-File, End-of-Record, or Trigger sectors skip selection beyond initial file selection. + if (buffer[SECTOR_SUBMODE2] & (SUBMODE_EOF | SUBMODE_TRIG | SUBMODE_EOR)) { - const bool valid_sample = is_valid_sample_buf(m_decode_addr & 0x3ffe); + LOGMASKED(LOG_SECTORS, "Mode 2 sector is selected due to EOF, TRIG, or EOR (%02x)\n", buffer[SECTOR_SUBMODE2]); + return true; + } - if (valid_sample) - { - had_valid_sample = true; + // Sectors with no applicable data are skipped. + if (!(buffer[SECTOR_SUBMODE2] & (SUBMODE_DATA | SUBMODE_AUDIO | SUBMODE_VIDEO))) + { + LOGMASKED(LOG_SECTORS, "Mode 2 sector is not selected due to being a message sector (%02x)\n", buffer[SECTOR_SUBMODE2]); + return false; + } - LOGMASKED(LOG_SAMPLES, "Hit audio_sample_trigger, with m_decode_addr == %04x, calling decode_audio_sector\n", m_decode_addr); + // Select based on the specified channel mask. + const bool channel_selected = (bool)BIT(m_channel, buffer[SECTOR_CHAN2]); - // Decode the data at Z+4, the same offset as a normal CD sector. - decode_audio_sector(((uint8_t*)m_ram.get()) + (m_decode_addr & 0x3ffe) + 4, 1); - play_audio_sector(); + LOGMASKED(LOG_SECTORS, "Mode 2 sector is %sselected due to channel (register %04x, buffer channel %04x)\n", channel_selected ? "" : "not ", m_channel, buffer[SECTOR_CHAN2]); - // Delay until sample completion before requesting more data - LOGMASKED(LOG_SAMPLES, "Data is valid, setting up a new callback\n"); - m_decode_period += attotime::from_hz(sample_buf_freq(m_decode_addr & 0x3ffe)) * (18*28*2*sample_buf_size(m_decode_addr & 0x3ffe)); - //m_periodic_sample_timer[m_decode_addr == 0x2800 ? 0 : 1]->adjust(m_decode_period); - m_audio_sample_timer->adjust(m_decode_period); - //dmadac_enable(&dmadac[0], 2, 0); + return channel_selected; +} - m_decode_addr ^= 0x1a00; - m_z_buffer ^= 0x1a00; - LOGMASKED(LOG_SAMPLES, "Updated m_decode_addr, new value is %04x\n", m_decode_addr); +bool cdicdic_device::is_mode2_audio_selected(const uint8_t *buffer) +{ + // Non-Mode-2, Non-Audio sectors are never selected for audio playback. + if (!(buffer[SECTOR_SUBMODE2] & SUBMODE_FORM) || !(buffer[SECTOR_SUBMODE2] & SUBMODE_AUDIO)) + { + LOGMASKED(LOG_SECTORS, "Audio is not selected; submode %02x\n", buffer[SECTOR_SUBMODE2]); + return false; + } - // Indicate that data has been decoded - //LOGMASKED(LOG_SAMPLES, "Flagging that audio data has been decoded\n"); - //m_audio_buffer |= 0x8000; + // Select based on the specified audio channel mask. + const bool channel_selected = (bool)BIT(m_audio_channel, buffer[SECTOR_CHAN2]); - // Set the CDIC interrupt line - //LOGMASKED(LOG_SAMPLES, "Setting CDIC interrupt line for soundmap decode\n"); - //m_intreq_callback(ASSERT_LINE); + LOGMASKED(LOG_SECTORS, "Mode 2 audio is %sselected due to channel (register %04x, buffer channel %04x)\n", channel_selected ? "" : "not ", m_audio_channel, buffer[SECTOR_CHAN2]); - // Swap buffer positions to indicate our new buffer position at the next read + return channel_selected; +} - //if (m_decode_addr == decode_start) - { - decoding = false; - } - } - else - { - LOGMASKED(LOG_SAMPLES, "Data is not valid, stopping playback\n"); - m_audio_sample_timer->adjust(attotime::never); - decoding = false; +TIMER_CALLBACK_MEMBER( cdicdic_device::sector_tick ) +{ + if (m_disc_command == 0) + { + return; + } - // Indicate that data has been decoded - LOGMASKED(LOG_SAMPLES, "Flagging that audio data has been decoded\n"); - //m_audio_buffer |= 0x8000; + if (m_disc_spinup_counter != 0) + { + LOGMASKED(LOG_SECTORS, "Sector tick, waiting on spinup\n"); + m_disc_spinup_counter--; + return; + } - // Set the CDIC interrupt line - LOGMASKED(LOG_SAMPLES, "Setting CDIC interrupt line for soundmap decode\n"); - m_intreq_callback(ASSERT_LINE); + LOGMASKED(LOG_SECTORS, "About to process a disc sector\n"); - m_z_buffer |= 1; - } - } while (decoding); + process_disc_sector(); - if (had_valid_sample) + if (m_disc_command == 0) { - //m_periodic_sample_timer->adjust(m_decode_period); + LOGMASKED(LOG_SECTORS, "Disc command has been reset after processing; stopping processing.\n"); + cancel_disc_read(); + return; } -} -TIMER_CALLBACK_MEMBER( cdicdic_device::trigger_readback_int ) -{ - process_delayed_command(); + m_curr_lba++; } -void cdicdic_device::process_delayed_command() +uint8_t cdicdic_device::get_sector_count_for_coding(uint8_t coding) { - switch (m_command) + uint8_t base_count = 2; + + switch (coding & CODING_BPS_MASK) { - case 0x23: // Reset Mode 1 - case 0x24: // Reset Mode 2 - case 0x29: // Read Mode 1 - case 0x2a: // Read Mode 2 - { - static const char* const s_cmds[8] = - { - "Reset Mode 1", - "Reset Mode 2", 0, 0, 0, 0, - "Read Mode 1", - "Read Mode 2" - }; - uint8_t buffer[2560] = { 0 }; - uint32_t msf = m_time >> 8; - LOGMASKED(LOG_COMMANDS, "%s: Processing Delayed Command with MSF %06x: %s\n", machine().describe_context(), msf, s_cmds[m_command - 0x23]); - uint8_t nybbles[6] = - { - static_cast<uint8_t>(msf & 0x0000000f), - static_cast<uint8_t>((msf & 0x000000f0) >> 4), - static_cast<uint8_t>((msf & 0x00000f00) >> 8), - static_cast<uint8_t>((msf & 0x0000f000) >> 12), - static_cast<uint8_t>((msf & 0x000f0000) >> 16), - static_cast<uint8_t>((msf & 0x00f00000) >> 20) - }; - if ((msf & 0x0000ff) >= 0x75) - { - LOGMASKED(LOG_COMMANDS, "%s: Weird frame timestamp detected: %02x\n", machine().describe_context(), (uint8_t)msf); - msf &= 0xffff00; - nybbles[0] = 0; - nybbles[1] = 0; - } - if (nybbles[2] >= 2) - { - nybbles[2] -= 2; - } - else - { - nybbles[2] = 8 + nybbles[2]; - if (nybbles[3] > 0) - { - nybbles[3]--; - } - else - { - nybbles[3] = 5; - if (nybbles[4] > 0) - { - nybbles[4]--; - } - else - { - nybbles[4] = 9; - nybbles[5]--; - } - } - } - uint32_t lba = nybbles[0] + nybbles[1]*10 + ((nybbles[2] + nybbles[3]*10)*75) + ((nybbles[4] + nybbles[5]*10)*75*60); + case CODING_4BPS: + // Twice as many 4bpp audio frames fit as usual + base_count *= 2; + break; + case CODING_8BPS: + case CODING_16BPS: + // No multiplier vs. base + break; + case CODING_BPS_MPEG: + // Unsupported; clear to zero for now + base_count = 0; + break; + } - LOGMASKED(LOG_COMMANDS, "%s: Reading Mode %d sector from MSF location %06x / %x%x%x%x%x%x, LBA %08x\n", machine().describe_context(), m_command - 0x28, - (m_time >> 8) - 0x200, nybbles[5], nybbles[4], nybbles[3], nybbles[2], nybbles[1], nybbles[0], lba); + switch (coding & CODING_RATE_MASK) + { + case CODING_18KHZ: + // Twice as many half-rate audio frames fit as usual + base_count *= 2; + break; + case CODING_37KHZ: + case CODING_44KHZ: + // No multiplier vs. base + break; + case CODING_RATE_RESV: + // Unsupported reserved mode; clear to zero for now + base_count = 0; + break; + } - cdrom_read_data(m_cd, lba, buffer, CD_TRACK_RAW_DONTCARE); + switch (coding & CODING_CHAN_MASK) + { + case CODING_MONO: + // Twice as many mono audio frames fit vs. stereo + base_count *= 2; + break; + case CODING_STEREO: + // No multiplier vs. base + break; + case CODING_CHAN_RESV: + case CODING_CHAN_MPEG: + // MPEG mode and reserved modes are unsupported; clear to zero for now + base_count = 0; + break; + } - m_time += 0x100; - if ((m_time & 0x00000f00) == 0x00000a00) - { - m_time &= 0xfffff0ff; - m_time += 0x00001000; - } - if ((m_time & 0x0000ff00) == 0x00007500) - { - m_time &= 0xffff00ff; - m_time += 0x00010000; - if ((m_time & 0x000f0000) == 0x000a0000) - { - m_time &= 0xfff0ffff; - m_time += 0x00100000; - } - } - if ((m_time & 0x00ff0000) == 0x00600000) - { - m_time &= 0xff00ffff; - m_time += 0x01000000; - if ((m_time & 0x0f000000) == 0x0a000000) - { - m_time &= 0xf0ffffff; - m_time += 0x10000000; - } - } + return base_count; +} - m_data_buffer &= ~0x0004; - m_data_buffer ^= 0x0001; +void cdicdic_device::process_disc_sector() +{ + const uint32_t real_lba = m_curr_lba + 150; + const uint8_t mins = real_lba / (60 * 75); + const uint8_t secs = (real_lba / 75) % 60; + const uint8_t frac = real_lba % 75; + const uint8_t mins_bcd = ((mins / 10) << 4) | (mins % 10); + const uint8_t secs_bcd = ((secs / 10) << 4) | (secs % 10); + const uint8_t frac_bcd = ((frac / 10) << 4) | (frac % 10); - const bool file_match = (buffer[CDIC_SECTOR_FILE2] << 8) == m_file; - const bool channel_match = (m_channel & (1 << buffer[CDIC_SECTOR_CHAN2])) != 0; - const bool audio_channel_match = (m_audio_channel & (1 << buffer[CDIC_SECTOR_CHAN2])) != 0; - const bool is_audio = (buffer[CDIC_SECTOR_SUBMODE2] & (CDIC_SUBMODE_FORM | CDIC_SUBMODE_DATA | CDIC_SUBMODE_AUDIO | CDIC_SUBMODE_VIDEO)) == (CDIC_SUBMODE_FORM | CDIC_SUBMODE_AUDIO); - if (file_match) - { - if (is_audio && channel_match && audio_channel_match) - { - m_x_buffer |= 0x8000; - //m_data_buffer |= 0x4000; - m_data_buffer |= 4; - - LOGMASKED(LOG_SECTORS, "%s: Audio sector into %04x\n", machine().describe_context(), (m_data_buffer & 5) * 0xa00); - - for (int index = 6; index < 2352/2; index++) - { - m_ram[(m_data_buffer & 5) * (0xa00/2) + (index - 6)] = (buffer[index*2] << 8) | buffer[index*2 + 1]; - } - - decode_audio_sector(((uint8_t*)m_ram.get()) + ((m_data_buffer & 5) * 0xa00 + 4), 0); - - LOGMASKED(LOG_IRQS, "%s: Setting CDIC interrupt line for audio sector\n", machine().describe_context()); - //} - m_intreq_callback(ASSERT_LINE); - //else - //{ - // LOGMASKED(LOG_IRQS, "%s: Setting CDIC interrupt line for ignored audio sector (m_channel %04x, m_audio_channel %04x, sector channel %04x\n", - // machine().describe_context(), m_channel, m_audio_channel, (1 << buffer[CDIC_SECTOR_CHAN2])); - // m_intreq_callback(ASSERT_LINE); - //} - } - else if ((buffer[CDIC_SECTOR_SUBMODE2] & (CDIC_SUBMODE_DATA | CDIC_SUBMODE_AUDIO | CDIC_SUBMODE_VIDEO)) == 0x00) - { - m_x_buffer |= 0x8000; - //m_data_buffer |= 0x4000; - - for (int index = 6; index < 2352/2; index++) - { - m_ram[(m_data_buffer & 5) * (0xa00/2) + (index - 6)] = (buffer[index*2] << 8) | buffer[index*2 + 1]; - } - - if ((buffer[CDIC_SECTOR_SUBMODE2] & CDIC_SUBMODE_TRIG) == CDIC_SUBMODE_TRIG || - (buffer[CDIC_SECTOR_SUBMODE2] & CDIC_SUBMODE_EOR) == CDIC_SUBMODE_EOR || - (buffer[CDIC_SECTOR_SUBMODE2] & CDIC_SUBMODE_EOF) == CDIC_SUBMODE_EOF) - { - LOGMASKED(LOG_IRQS, "%s: Setting CDIC interrupt line for message sector\n", machine().describe_context()); - m_intreq_callback(ASSERT_LINE); - } - else - { - LOGMASKED(LOG_SECTORS, "%s: Setting CDIC interrupt line for ignored message sector\n", machine().describe_context()); - m_intreq_callback(ASSERT_LINE); - } - } - else if (channel_match) - { - m_x_buffer |= 0x8000; - //m_data_buffer |= 0x4000; - - if (is_audio) - { - //m_data_buffer |= 4; - //m_z_buffer = (m_data_buffer & 5) * 0xa00; - } - - for (int index = 6; index < 2352/2; index++) - { - m_ram[(m_data_buffer & 5) * (0xa00/2) + (index - 6)] = (buffer[index*2] << 8) | buffer[index*2 + 1]; - } - - LOGMASKED(LOG_IRQS, "%s: Setting CDIC interrupt line for data sector to %04x, submode 2 flags are:\n", machine().describe_context(), (m_data_buffer & 5) * 0xa00); - LOGMASKED(LOG_IRQS, "%s: Channel reg is: %08x, versus submode channel: %08x\n", machine().describe_context(), m_channel, (1 << buffer[CDIC_SECTOR_CHAN2])); - if (!BIT(m_channel, buffer[CDIC_SECTOR_CHAN2])) - { - LOGMASKED(LOG_IRQS, "%s: Channel mismatch\n", machine().describe_context()); - m_intreq_callback(ASSERT_LINE); - } - else - { - m_intreq_callback(ASSERT_LINE); - } - const uint16_t submode2 = buffer[CDIC_SECTOR_SUBMODE2]; - if (submode2 & CDIC_SUBMODE_EOF) LOGMASKED(LOG_IRQS, "%s: CDIC_SUBMODE_EOF\n", machine().describe_context()); - if (submode2 & CDIC_SUBMODE_RT) LOGMASKED(LOG_IRQS, "%s: CDIC_SUBMODE_RT\n", machine().describe_context()); - if (submode2 & CDIC_SUBMODE_FORM) LOGMASKED(LOG_IRQS, "%s: CDIC_SUBMODE_FORM\n", machine().describe_context()); - if (submode2 & CDIC_SUBMODE_TRIG) LOGMASKED(LOG_IRQS, "%s: CDIC_SUBMODE_TRIG\n", machine().describe_context()); - if (submode2 & CDIC_SUBMODE_DATA) LOGMASKED(LOG_IRQS, "%s: CDIC_SUBMODE_DATA\n", machine().describe_context()); - if (submode2 & CDIC_SUBMODE_AUDIO) LOGMASKED(LOG_IRQS, "%s: CDIC_SUBMODE_AUDIO\n", machine().describe_context()); - if (submode2 & CDIC_SUBMODE_VIDEO) LOGMASKED(LOG_IRQS, "%s: CDIC_SUBMODE_VIDEO\n", machine().describe_context()); - if (submode2 & CDIC_SUBMODE_EOR) LOGMASKED(LOG_IRQS, "%s: CDIC_SUBMODE_EOR\n", machine().describe_context()); - } - else - { - //m_x_buffer |= 0x8000; - - LOGMASKED(LOG_IRQS, "%s: No match: m_channel %04x, m_audio_channel %04x, sector channel %04x\n", - machine().describe_context(), m_channel, m_audio_channel, (1 << buffer[CDIC_SECTOR_CHAN2])); - const uint16_t submode2 = buffer[CDIC_SECTOR_SUBMODE2]; - if (submode2 & CDIC_SUBMODE_EOF) LOGMASKED(LOG_IRQS, "%s: CDIC_SUBMODE_EOF\n", machine().describe_context()); - if (submode2 & CDIC_SUBMODE_RT) LOGMASKED(LOG_IRQS, "%s: CDIC_SUBMODE_RT\n", machine().describe_context()); - if (submode2 & CDIC_SUBMODE_FORM) LOGMASKED(LOG_IRQS, "%s: CDIC_SUBMODE_FORM\n", machine().describe_context()); - if (submode2 & CDIC_SUBMODE_TRIG) LOGMASKED(LOG_IRQS, "%s: CDIC_SUBMODE_TRIG\n", machine().describe_context()); - if (submode2 & CDIC_SUBMODE_DATA) LOGMASKED(LOG_IRQS, "%s: CDIC_SUBMODE_DATA\n", machine().describe_context()); - if (submode2 & CDIC_SUBMODE_AUDIO) LOGMASKED(LOG_IRQS, "%s: CDIC_SUBMODE_AUDIO\n", machine().describe_context()); - if (submode2 & CDIC_SUBMODE_VIDEO) LOGMASKED(LOG_IRQS, "%s: CDIC_SUBMODE_VIDEO\n", machine().describe_context()); - if (submode2 & CDIC_SUBMODE_EOR) LOGMASKED(LOG_IRQS, "%s: CDIC_SUBMODE_EOR\n", machine().describe_context()); - //m_intreq_callback(ASSERT_LINE); - } + LOGMASKED(LOG_SECTORS, "Disc sector, current LBA: %08x, MSF: %02x %02x %02x\n", real_lba, mins_bcd, secs_bcd, frac_bcd); - if ((buffer[CDIC_SECTOR_SUBMODE2] & CDIC_SUBMODE_EOF) == 0 && m_command != 0x23) - { - LOGMASKED(LOG_IRQS, "Setting CDIC processing to trigger in 75Hz due to non-EOF.\n"); - m_interrupt_timer->adjust(attotime::from_hz(75)); // 75Hz = 1x CD-ROM speed - } - else - { - LOGMASKED(LOG_IRQS, "Not setting CDIC processing, EOF is %d\n", (buffer[CDIC_SECTOR_SUBMODE2] & CDIC_SUBMODE_EOF) ? 1 : 0); - m_interrupt_timer->adjust(attotime::never); - //m_data_buffer &= ~0x4000; - //m_interrupt_timer->adjust(attotime::from_hz(75)); - } - } - else - { - LOGMASKED(LOG_IRQS, "File mismatch\n"); - } - break; - } + uint8_t buffer[2560] = { 0 }; + cdrom_read_data(m_cd, m_curr_lba, buffer, CD_TRACK_RAW_DONTCARE); - case 0x2e: // Abort - LOGMASKED(LOG_COMMANDS, "%s: Processing Delayed Command: Abort\n", machine().describe_context()); - m_interrupt_timer->adjust(attotime::never); - //m_data_buffer &= ~4; - break; + LOGMASKED(LOG_SECTORS, "Sector header data: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", + buffer[ 0], buffer[ 1], buffer[ 2], buffer[ 3], buffer[ 4], buffer[ 5], buffer[ 6], buffer[ 7], buffer[ 8], buffer[ 9], + buffer[10], buffer[11], buffer[12], buffer[13], buffer[14], buffer[15], buffer[16], buffer[17], buffer[18], buffer[19], + buffer[20], buffer[21], buffer[22], buffer[23]); - case 0x28: // Play CDDA audio + if (buffer[SECTOR_MODE] == 2 && m_disc_mode == DISC_MODE2) + { + // First, filter whether we want to process this sector at all. + if (!is_mode2_sector_selected(buffer)) { - LOGMASKED(LOG_COMMANDS, "%s: Processing Delayed Command: Play CDDA Audio\n", machine().describe_context()); - uint8_t buffer[2560] = { 0 }; - uint32_t msf = (m_time & 0xffff7f00) >> 8; - uint32_t next_msf = increment_cdda_frame_bcd((m_time & 0xffff7f00) >> 8); - uint32_t rounded_next_msf = increment_cdda_sector_bcd((m_time & 0xffff0000) >> 8); - uint8_t nybbles[6] = - { - static_cast<uint8_t>(msf & 0x0000000f), - static_cast<uint8_t>((msf & 0x000000f0) >> 4), - static_cast<uint8_t>((msf & 0x00000f00) >> 8), - static_cast<uint8_t>((msf & 0x0000f000) >> 12), - static_cast<uint8_t>((msf & 0x000f0000) >> 16), - static_cast<uint8_t>((msf & 0x00f00000) >> 20) - }; + return; + } - uint32_t lba = nybbles[0] + nybbles[1]*10 + ((nybbles[2] + nybbles[3]*10)*75) + ((nybbles[4] + nybbles[5]*10)*75*60); + // Next, determine if we want to process this sector as an audio sector. + if (is_mode2_audio_selected(buffer)) + { + LOGMASKED(LOG_SECTORS, "Audio is selected\n"); + if (m_audio_sector_counter == 0) + std::fill_n(&m_xa_last[0], 4, 0); - if (!cdrom_read_data(m_cd, lba, buffer, CD_TRACK_RAW_DONTCARE)) - { - osd_printf_verbose("Unable to read CD-ROM data.\n", machine().describe_context()); - } + m_audio_sector_counter = get_sector_count_for_coding(buffer[SECTOR_CODING2]); + m_decoding_audio_map = false; - if (!(msf & 0x0000ff)) - { - LOGMASKED(LOG_COMMANDS, "%s: Playing CDDA sector from MSF location %06x\n", machine().describe_context(), m_time | 2); - m_cdda->start_audio(lba, rounded_next_msf); - } + play_audio_sector(buffer[SECTOR_CODING2], buffer + SECTOR_DATA); + } + } - m_ram[(m_data_buffer & 5) * (0xa00/2) + 0x924/2] = 0x0001; // CTRL - m_ram[(m_data_buffer & 5) * (0xa00/2) + 0x926/2] = 0x0001; // TRACK - m_ram[(m_data_buffer & 5) * (0xa00/2) + 0x928/2] = 0x0000; // INDEX - m_ram[(m_data_buffer & 5) * (0xa00/2) + 0x92a/2] = (m_time >> 24) & 0x000000ff; // MIN - m_ram[(m_data_buffer & 5) * (0xa00/2) + 0x92c/2] = (m_time >> 16) & 0x000000ff; // SEC - m_ram[(m_data_buffer & 5) * (0xa00/2) + 0x92e/2] = (m_time >> 8) & 0x0000007f; // FRAC - m_ram[(m_data_buffer & 5) * (0xa00/2) + 0x930/2] = 0x0000; // ZERO - m_ram[(m_data_buffer & 5) * (0xa00/2) + 0x932/2] = (m_time >> 24) & 0x000000ff; // AMIN - m_ram[(m_data_buffer & 5) * (0xa00/2) + 0x934/2] = (m_time >> 16) & 0x000000ff; // ASEC - m_ram[(m_data_buffer & 5) * (0xa00/2) + 0x936/2] = (m_time >> 8) & 0x0000007f; // AFRAC - m_ram[(m_data_buffer & 5) * (0xa00/2) + 0x938/2] = 0x0000; // CRC1 - m_ram[(m_data_buffer & 5) * (0xa00/2) + 0x93a/2] = 0x0000; // CRC2 + // Calculate subcode data + uint8_t subcode_buffer[96]; + memset(subcode_buffer, 0, sizeof(subcode_buffer)); - m_time = next_msf << 8; + if (m_disc_command == DISC_TOC) + { + uint32_t entry_index = 0; + for (; buffer[entry_index * 5] != 0; entry_index++); + + uint8_t *toc_data = &buffer[(m_curr_lba % entry_index) * 5]; + + subcode_buffer[SUBCODE_Q_CONTROL] = toc_data[0]; + subcode_buffer[SUBCODE_Q_TRACK] = 0x00; + subcode_buffer[SUBCODE_Q_INDEX] = toc_data[1]; + subcode_buffer[SUBCODE_Q_MODE1_MINS] = 0xa0; + subcode_buffer[SUBCODE_Q_MODE1_SECS] = secs_bcd; + subcode_buffer[SUBCODE_Q_MODE1_FRAC] = frac_bcd; + subcode_buffer[SUBCODE_Q_MODE1_ZERO] = 0x00; + subcode_buffer[SUBCODE_Q_MODE1_AMINS] = toc_data[2]; + subcode_buffer[SUBCODE_Q_MODE1_ASECS] = toc_data[3]; + subcode_buffer[SUBCODE_Q_MODE1_AFRAC] = toc_data[4]; + subcode_buffer[SUBCODE_Q_CRC0] = 0xff; + subcode_buffer[SUBCODE_Q_CRC1] = 0xff; + } + else + { + subcode_buffer[SUBCODE_Q_CONTROL] = (m_disc_command == DISC_CDDA ? 0x01 : 0x41); + subcode_buffer[SUBCODE_Q_TRACK] = 0x01; + subcode_buffer[SUBCODE_Q_INDEX] = 0x01; + subcode_buffer[SUBCODE_Q_MODE1_MINS] = mins_bcd; + subcode_buffer[SUBCODE_Q_MODE1_SECS] = secs_bcd; + subcode_buffer[SUBCODE_Q_MODE1_FRAC] = frac_bcd; + subcode_buffer[SUBCODE_Q_MODE1_ZERO] = 0x00; + subcode_buffer[SUBCODE_Q_MODE1_AMINS] = mins_bcd; + subcode_buffer[SUBCODE_Q_MODE1_ASECS] = secs_bcd; + subcode_buffer[SUBCODE_Q_MODE1_AFRAC] = frac_bcd; + subcode_buffer[SUBCODE_Q_CRC0] = 0xff; + subcode_buffer[SUBCODE_Q_CRC1] = 0xff; + } - // the following line BREAKS 'The Apprentice', hangs when you attempt to start the game - //m_interrupt_timer->adjust(attotime::from_hz(75)); + uint16_t crc_accum = 0; + for (int i = 0; i < 12; i++) + crc_accum = CRC_CCITT_ROUND(crc_accum, subcode_buffer[SUBCODE_Q_CONTROL + i]); - m_x_buffer |= 0x8000; - //m_data_buffer |= 0x4000; + subcode_buffer[SUBCODE_Q_CRC0] = (uint8_t)(crc_accum >> 8); + subcode_buffer[SUBCODE_Q_CRC1] = (uint8_t)crc_accum; - for (int index = 6; index < 2352/2; index++) - { - m_ram[(m_data_buffer & 5) * (0xa00/2) + (index - 6)] = (buffer[index*2] << 8) | buffer[index*2 + 1]; - } + process_sector_data(buffer, subcode_buffer); +} - LOGMASKED(LOG_IRQS, "%s: Setting CDIC interrupt line for CDDA sector\n", machine().describe_context()); - m_intreq_callback(ASSERT_LINE); - break; - } - case 0x2c: // Seek - { - LOGMASKED(LOG_COMMANDS, "%s: Processing Delayed Command: Seek\n", machine().describe_context()); - uint8_t buffer[2560] = { 0 }; - uint32_t msf = (m_time & 0xffff7f00) >> 8; - uint32_t next_msf = increment_cdda_frame_bcd((m_time & 0xffff7f00) >> 8); - uint8_t nybbles[6] = - { - static_cast<uint8_t>(msf & 0x0000000f), - static_cast<uint8_t>((msf & 0x000000f0) >> 4), - static_cast<uint8_t>((msf & 0x00000f00) >> 8), - static_cast<uint8_t>((msf & 0x0000f000) >> 12), - static_cast<uint8_t>((msf & 0x000f0000) >> 16), - static_cast<uint8_t>((msf & 0x00f00000) >> 20) - }; - uint32_t lba = nybbles[0] + nybbles[1]*10 + ((nybbles[2] + nybbles[3]*10)*75) + ((nybbles[4] + nybbles[5]*10)*75*60); +void cdicdic_device::process_sector_data(const uint8_t *buffer, const uint8_t *subcode_buffer) +{ + m_data_buffer ^= 0x0001; + m_data_buffer &= ~0x0004; - m_interrupt_timer->adjust(attotime::from_hz(75)); + uint16_t *dev_buffer = (uint16_t *)&m_ram[(m_data_buffer & 0x0005) * 0xa00]; - cdrom_read_data(m_cd, lba, buffer, CD_TRACK_RAW_DONTCARE); + for (int i = SECTOR_HEADER; i < SECTOR_FILE2; i += 2) + *dev_buffer++ = ((uint16_t)buffer[i] << 8) | buffer[i + 1]; - m_data_buffer ^= 0x0001; - m_x_buffer |= 0x8000; - m_data_buffer |= 0x4000; + if (m_command == 0x2a && is_mode2_audio_selected(buffer)) + { + m_data_buffer |= 0x0004; + dev_buffer += 0x1400; + } - for (int index = 6; index < 2352/2; index++) - { - m_ram[(m_data_buffer & 5) * (0xa00/2) + (index - 6)] = (buffer[index*2] << 8) | buffer[index*2 + 1]; - } + for (int i = SECTOR_FILE2; i < SECTOR_SIZE; i += 2) + *dev_buffer++ = ((uint16_t)buffer[i] << 8) | buffer[i + 1]; - m_ram[(m_data_buffer & 5) * (0xa00/2) + 0x924/2] = 0x0041; // CTRL - m_ram[(m_data_buffer & 5) * (0xa00/2) + 0x926/2] = 0x0001; // TRACK - m_ram[(m_data_buffer & 5) * (0xa00/2) + 0x928/2] = 0x0000; // INDEX - m_ram[(m_data_buffer & 5) * (0xa00/2) + 0x92a/2] = (m_time >> 24) & 0x000000ff; // MIN - m_ram[(m_data_buffer & 5) * (0xa00/2) + 0x92c/2] = (m_time >> 16) & 0x000000ff; // SEC - m_ram[(m_data_buffer & 5) * (0xa00/2) + 0x92e/2] = (m_time >> 8) & 0x0000007f; // FRAC - m_ram[(m_data_buffer & 5) * (0xa00/2) + 0x930/2] = 0x0000; // ZERO - m_ram[(m_data_buffer & 5) * (0xa00/2) + 0x932/2] = (m_time >> 24) & 0x000000ff; // AMIN - m_ram[(m_data_buffer & 5) * (0xa00/2) + 0x934/2] = (m_time >> 16) & 0x000000ff; // ASEC - m_ram[(m_data_buffer & 5) * (0xa00/2) + 0x936/2] = (m_time >> 8) & 0x0000007f; // AFRAC - m_ram[(m_data_buffer & 5) * (0xa00/2) + 0x938/2] = 0x0000; // CRC1 - m_ram[(m_data_buffer & 5) * (0xa00/2) + 0x93a/2] = 0x0000; // CRC2 - - m_time = next_msf << 8; - - LOGMASKED(LOG_IRQS, "%s: Setting CDIC interrupt line for Seek sector\n", machine().describe_context()); - m_intreq_callback(ASSERT_LINE); - break; - } - } + for (int i = SUBCODE_Q_CONTROL; i <= SUBCODE_Q_CRC1; i++) + *dev_buffer++ = subcode_buffer[i]; + + m_x_buffer |= 0x8000; + m_data_buffer |= 0x4000; + update_interrupt_state(); + + if (m_command == 0x23) // Reset Mode 1? If so, stop. + cancel_disc_read(); } uint16_t cdicdic_device::regs_r(offs_t offset, uint16_t mem_mask) @@ -1004,10 +840,6 @@ uint16_t cdicdic_device::regs_r(offs_t offset, uint16_t mem_mask) case 0x3c0c/2: // Audio Channel register LOGMASKED(LOG_READS, "%s: cdic_r: Audio Channel Register = %04x & %04x\n", machine().describe_context(), m_audio_channel, mem_mask); - if (m_break_on_achan) - { - machine().debug_break(); - } return m_audio_channel; case 0x3ff4/2: // ABUF @@ -1015,11 +847,7 @@ uint16_t cdicdic_device::regs_r(offs_t offset, uint16_t mem_mask) uint16_t temp = m_audio_buffer; LOGMASKED(LOG_READS, "%s: cdic_r: Audio Buffer Register = %04x & %04x\n", machine().describe_context(), temp, mem_mask); m_audio_buffer &= 0x7fff; - if (!((m_audio_buffer | m_x_buffer) & 0x8000)) - { - m_intreq_callback(CLEAR_LINE); - LOGMASKED(LOG_IRQS, "%s: Clearing CDIC interrupt line\n", machine().describe_context()); - } + update_interrupt_state(); return temp; } @@ -1028,29 +856,20 @@ uint16_t cdicdic_device::regs_r(offs_t offset, uint16_t mem_mask) uint16_t temp = m_x_buffer; LOGMASKED(LOG_READS, "%s: cdic_r: X-Buffer Register = %04x & %04x\n", machine().describe_context(), temp, mem_mask); m_x_buffer &= 0x7fff; - if (!((m_audio_buffer | m_x_buffer) & 0x8000)) - { - m_intreq_callback(CLEAR_LINE); - LOGMASKED(LOG_IRQS, "%s: Clearing CDIC interrupt line\n", machine().describe_context()); - } + update_interrupt_state(); return temp; } case 0x3ffa/2: // AUDCTL - { + if (!m_decoding_audio_map) + m_z_buffer ^= 0x0001; LOGMASKED(LOG_READS, "%s: cdic_r: Z-Buffer Register Read: %04x & %04x\n", machine().describe_context(), m_z_buffer, mem_mask); - if (m_audio_playback_timer->remaining().is_never() && m_audio_sample_timer->remaining().is_never()) - { - return m_z_buffer | 1; - } return m_z_buffer; - } case 0x3ffe/2: - { LOGMASKED(LOG_READS, "%s: cdic_r: Data buffer Register = %04x & %04x\n", machine().describe_context(), m_data_buffer, mem_mask); return m_data_buffer; - } + default: LOGMASKED(LOG_READS | LOG_UNKNOWNS, "%s: cdic_r: Unknown address: %04x & %04x\n", machine().describe_context(), addr*2, mem_mask); return 0; @@ -1117,19 +936,19 @@ void cdicdic_device::regs_w(offs_t offset, uint16_t data, uint16_t mem_mask) uint32_t start = m_scc->dma().channel[0].memory_address_counter; uint32_t count = m_scc->dma().channel[0].transfer_counter; uint32_t device_index = (data & 0x3fff) >> 1; + uint16_t *ram = (uint16_t *)m_ram.get(); LOGMASKED(LOG_WRITES, "%s: cdic_w: DMA Control Register = %04x & %04x\n", machine().describe_context(), data, mem_mask); LOGMASKED(LOG_WRITES, "%s: Memory address counter: %08x\n", machine().describe_context(), m_scc->dma().channel[0].memory_address_counter); LOGMASKED(LOG_WRITES, "%s: Doing copy, transferring %04x bytes %s\n", machine().describe_context(), count * 2, (m_scc->dma().channel[0].operation_control & OCR_D) ? "to main RAM" : "to device RAM"); - printf("\n"); for (uint32_t index = start / 2; index < (start / 2 + count); index++) { if (m_scc->dma().channel[0].operation_control & OCR_D) { - m_memory_space->write_word(index * 2, m_ram[device_index++]); + m_memory_space->write_word(index * 2, ram[device_index++]); } else { - m_ram[device_index++] = m_memory_space->read_word(index * 2); + ram[device_index++] = m_memory_space->read_word(index * 2); } } m_scc->dma().channel[0].memory_address_counter += m_scc->dma().channel[0].transfer_counter * 2; @@ -1137,29 +956,21 @@ void cdicdic_device::regs_w(offs_t offset, uint16_t data, uint16_t mem_mask) } case 0x3ffa/2: - { LOGMASKED(LOG_WRITES, "%s: cdic_w: Z-Buffer Register Write: %04x & %04x\n", machine().describe_context(), data, mem_mask); COMBINE_DATA(&m_z_buffer); - if (m_z_buffer & 0x2000) + if (!(m_z_buffer & 0x2000)) { - //if (m_audio_sample_timer->remaining().is_never()) - { - m_decode_addr = m_z_buffer & 0x3a00; - LOGMASKED(LOG_WRITES, "%s: New decode address: %04x\n", machine().describe_context(), m_decode_addr); - m_audio_playback_timer->adjust(attotime::from_hz(1000)); - //m_decode_delay = 1; - //m_audio_sample_timer->adjust(attotime::from_hz(75)); - } + m_decode_addr = 0xffff; } - else + else if (!m_decoding_audio_map) { - m_decode_addr = 0xffff; - m_audio_sample_timer->adjust(attotime::never); - m_periodic_sample_timer[0]->adjust(attotime::never); - m_periodic_sample_timer[1]->adjust(attotime::never); + m_decode_addr = m_z_buffer & 0x3a00; + m_audio_format_sectors = 0; + m_audio_sector_counter = 1; + m_decoding_audio_map = true; + std::fill_n(&m_xa_last[0], 4, 0); } break; - } case 0x3ffc/2: LOGMASKED(LOG_WRITES, "%s: cdic_w: Interrupt Vector Register = %04x & %04x\n", machine().describe_context(), data, mem_mask); @@ -1167,73 +978,105 @@ void cdicdic_device::regs_w(offs_t offset, uint16_t data, uint16_t mem_mask) break; case 0x3ffe/2: - { LOGMASKED(LOG_WRITES, "%s: cdic_w: Data Buffer Register = %04x & %04x\n", machine().describe_context(), data, mem_mask); COMBINE_DATA(&m_data_buffer); if (m_data_buffer & 0x8000) { - m_audio_sample_timer->adjust(attotime::never); - m_audio_playback_timer->adjust(attotime::never); - m_periodic_sample_timer[0]->adjust(attotime::never); - m_periodic_sample_timer[1]->adjust(attotime::never); LOGMASKED(LOG_WRITES, "%s: cdic_w: Data Buffer high-bit set, beginning command processing\n", machine().describe_context()); - switch (m_command) - { - case 0x23: // Reset Mode 1 - case 0x24: // Reset Mode 2 - LOGMASKED(LOG_WRITES, "%s: cdic_w: Reset Mode %d command\n", machine().describe_context(), m_command - 0x22); - m_interrupt_timer->adjust(attotime::never); - m_dmadac[0]->enable(0); - m_dmadac[1]->enable(0); - m_data_buffer &= 0x7fff; - break; - case 0x2e: // Abort - LOGMASKED(LOG_WRITES, "%s: cdic_w: Abort command\n", machine().describe_context()); - m_interrupt_timer->adjust(attotime::never); - //m_audio_sample_timer->adjust(attotime::never); - //m_periodic_sample_timer->adjust(attotime::never); - m_dmadac[0]->enable(0); - m_dmadac[1]->enable(0); - m_data_buffer &= 0x3fff; - break; - case 0x2b: // Stop CDDA - LOGMASKED(LOG_WRITES, "%s: cdic_w: Stop CDDA\n", machine().describe_context()); - m_cdda->stop_audio(); - m_interrupt_timer->adjust(attotime::never); - m_data_buffer &= 0x7fff; - break; - case 0x29: // Read Mode 1 - case 0x2a: // Read Mode 2 - case 0x28: // Play CDDA - case 0x2c: // Seek - { - attotime period = m_interrupt_timer->remaining(); - if (!period.is_never()) - { - LOGMASKED(LOG_WRITES, "%s: cdic_w: Other command (%02x), interrupt in-flight, letting it ride\n", machine().describe_context(), m_command); - m_interrupt_timer->adjust(period); - } - else - { - LOGMASKED(LOG_WRITES, "%s: cdic_w: Other command (%02x), interrupt not in-flight, interrupting in 75Hz\n", machine().describe_context(), m_command); - m_interrupt_timer->adjust(attotime::from_hz(75)); - } - m_data_buffer &= 0x7fff; - break; - } - default: - LOGMASKED(LOG_COMMANDS, "%s: Unknown CDIC command: %02x\n", machine().describe_context(), m_command); - break; - } + handle_cdic_command(); + } + if (!(m_data_buffer & 0x4000)) + { + m_disc_command = 0; + m_disc_mode = 0; + m_disc_spinup_counter = 0; + m_curr_lba = 0; } break; - } + default: LOGMASKED(LOG_WRITES | LOG_UNKNOWNS, "%s: cdic_w: Unknown address: %04x = %04x & %04x\n", machine().describe_context(), addr*2, data, mem_mask); break; } } +void cdicdic_device::init_disc_read(uint8_t disc_mode) +{ + m_disc_command = m_command; + m_disc_mode = disc_mode; + m_curr_lba = lba_from_time(); + m_disc_spinup_counter = 1; +} + +void cdicdic_device::cancel_disc_read() +{ + m_disc_command = 0; + m_disc_mode = 0; + m_curr_lba = 0; + m_disc_spinup_counter = 0; +} + +void cdicdic_device::handle_cdic_command() +{ + switch (m_command) + { + case 0x23: // Reset Mode 1 + if (m_disc_command == 0) + init_disc_read(DISC_MODE1); + break; + case 0x24: // Reset Mode 2 + case 0x2b: // Stop CDDA + case 0x2e: // Abort + cancel_disc_read(); + break; + case 0x27: // Fetch TOC + init_disc_read(DISC_TOC); + break; + case 0x28: // Play CDDA + init_disc_read(DISC_CDDA); + break; + case 0x29: // Read Mode 1 + case 0x2c: // Seek + init_disc_read(DISC_MODE1); + break; + case 0x2a: // Read Mode 2 + init_disc_read(DISC_MODE2); + break; + } + + m_data_buffer &= ~0x8000; +} + +uint32_t cdicdic_device::lba_from_time() +{ + const uint8_t bcd_mins = (m_time >> 24) & 0xff; + const uint8_t mins_upper_digit = bcd_mins >> 4; + const uint8_t mins_lower_digit = bcd_mins & 0xf; + const uint8_t raw_mins = (mins_upper_digit * 10) + mins_lower_digit; + + const uint8_t bcd_secs = (m_time >> 16) & 0xff; + const uint8_t secs_upper_digit = bcd_secs >> 4; + const uint8_t secs_lower_digit = bcd_secs & 0xf; + const uint8_t raw_secs = (secs_upper_digit * 10) + secs_lower_digit; + + uint32_t lba = ((raw_mins * 60) + raw_secs) * 75; + + const uint8_t bcd_frac = (m_time >> 8) & 0xff; + const bool even_second = BIT(bcd_frac, 7); + if (!even_second) + { + const uint8_t frac_upper_digit = bcd_frac >> 4; + const uint8_t frac_lower_digit = bcd_frac & 0xf; + const uint8_t raw_frac = (frac_upper_digit * 10) + frac_lower_digit; + lba += raw_frac; + } + + if (lba >= 150) + lba -= 150; + + return lba; +} + //************************************************************************** // LIVE DEVICE //************************************************************************** @@ -1271,6 +1114,14 @@ void cdicdic_device::device_resolve_objects() void cdicdic_device::device_start() { + m_ram = std::make_unique<uint8_t[]>(0x4000); + m_samples[0] = std::make_unique<int16_t[]>(s_samples_per_sector * 8 + 16); + m_samples[1] = std::make_unique<int16_t[]>(s_samples_per_sector * 8 + 16); + + save_pointer(NAME(m_ram), 0x4000); + save_pointer(NAME(m_samples[0]), s_samples_per_sector * 8 + 16); + save_pointer(NAME(m_samples[1]), s_samples_per_sector * 8 + 16); + save_item(NAME(m_command)); save_item(NAME(m_time)); save_item(NAME(m_file)); @@ -1283,26 +1134,23 @@ void cdicdic_device::device_start() save_item(NAME(m_interrupt_vector)); save_item(NAME(m_data_buffer)); - save_item(NAME(m_audio_sample_freq)); - save_item(NAME(m_audio_sample_size)); - - m_interrupt_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(cdicdic_device::trigger_readback_int), this)); - m_interrupt_timer->adjust(attotime::never); + save_item(NAME(m_disc_command)); + save_item(NAME(m_disc_mode)); + save_item(NAME(m_disc_spinup_counter)); + save_item(NAME(m_curr_lba)); - m_audio_sample_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(cdicdic_device::audio_sample_trigger), this)); - m_audio_sample_timer->adjust(attotime::never); + save_item(NAME(m_audio_sector_counter)); + save_item(NAME(m_audio_format_sectors)); + save_item(NAME(m_decoding_audio_map)); + save_item(NAME(m_decode_addr)); - m_audio_playback_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(cdicdic_device::initial_sample_trigger), this)); - m_audio_playback_timer->adjust(attotime::never); + save_item(NAME(m_xa_last)); - m_periodic_sample_timer[0] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(cdicdic_device::periodic_sample_trigger), this)); - m_periodic_sample_timer[0]->adjust(attotime::never); - m_periodic_sample_timer[1] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(cdicdic_device::periodic_sample_trigger), this)); - m_periodic_sample_timer[1]->adjust(attotime::never); + m_audio_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(cdicdic_device::audio_tick), this)); + m_audio_timer->adjust(attotime::never); - m_ram = std::make_unique<uint16_t[]>(0x3c00/2); - m_samples[0] = std::make_unique<int16_t[]>(18*28*16+16); - m_samples[1] = std::make_unique<int16_t[]>(18*28*16+16); + m_sector_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(cdicdic_device::sector_tick), this)); + m_sector_timer->adjust(attotime::never); } //------------------------------------------------- @@ -1323,11 +1171,15 @@ void cdicdic_device::device_reset() m_interrupt_vector = 0x0f; m_data_buffer = 0; - m_audio_sample_freq = 0; - m_audio_sample_size = 0; + m_disc_command = 0; + m_disc_mode = 0; + m_disc_spinup_counter = 0; + m_curr_lba = 0; + m_audio_sector_counter = 0; + m_audio_format_sectors = 0; + m_decoding_audio_map = false; m_decode_addr = 0; - m_decode_delay = 0; if (m_cdrom_dev) { @@ -1342,28 +1194,28 @@ void cdicdic_device::device_reset() m_cdda->set_cdrom(m_cd); } - m_interrupt_timer->adjust(attotime::never); - m_audio_sample_timer->adjust(attotime::never); - m_audio_playback_timer->adjust(attotime::never); - m_periodic_sample_timer[0]->adjust(attotime::never); - m_periodic_sample_timer[1]->adjust(attotime::never); - - m_break_on_achan = false; - m_valid_audio_sample = false; + m_audio_timer->adjust(attotime::from_hz(75), 0, attotime::from_hz(75)); + m_sector_timer->adjust(attotime::from_hz(75), 0, attotime::from_hz(75)); m_intreq_callback(CLEAR_LINE); + + m_dmadac[0]->enable(1); + m_dmadac[1]->enable(1); + + std::fill_n(&m_xa_last[0], 4, 0); } void cdicdic_device::ram_w(offs_t offset, uint16_t data, uint16_t mem_mask) { LOGMASKED(LOG_RAM, "%s: ram_w: %04x = %04x & %04x\n", machine().describe_context(), offset << 1, data, mem_mask); - COMBINE_DATA(&m_ram[offset]); + COMBINE_DATA((uint16_t *)&m_ram[offset << 1]); } uint16_t cdicdic_device::ram_r(offs_t offset, uint16_t mem_mask) { - LOGMASKED(LOG_RAM, "%s: ram_r: %04x : %04x & %04x\n", machine().describe_context(), offset << 1, m_ram[offset], mem_mask); - return m_ram[offset]; + const uint16_t data = ((uint16_t)m_ram[(offset << 1) + 1] << 8) | m_ram[offset << 1]; + LOGMASKED(LOG_RAM, "%s: ram_r: %04x : %04x & %04x\n", machine().describe_context(), offset << 1, data, mem_mask); + return data; } uint8_t cdicdic_device::intack_r() diff --git a/src/mame/machine/cdicdic.h b/src/mame/machine/cdicdic.h index 3eafa710345..0feacafb5dc 100644 --- a/src/mame/machine/cdicdic.h +++ b/src/mame/machine/cdicdic.h @@ -32,7 +32,6 @@ TODO: #include "sound/dmadac.h" #include "cdrom.h" - //************************************************************************** // TYPE DEFINITIONS //************************************************************************** @@ -53,7 +52,6 @@ public: // non-static internal members void sample_trigger(); - void process_delayed_command(); uint16_t regs_r(offs_t offset, uint16_t mem_mask = ~0); void regs_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0); @@ -69,51 +67,86 @@ protected: virtual void device_reset() override; // internal callbacks - TIMER_CALLBACK_MEMBER( periodic_sample_trigger ); - TIMER_CALLBACK_MEMBER( audio_sample_trigger ); - TIMER_CALLBACK_MEMBER( initial_sample_trigger ); - TIMER_CALLBACK_MEMBER( trigger_readback_int ); + TIMER_CALLBACK_MEMBER(sector_tick); + TIMER_CALLBACK_MEMBER(audio_tick); private: - enum + enum : uint8_t { - CDIC_SECTOR_SYNC = 0, - - CDIC_SECTOR_HEADER = 12, - - CDIC_SECTOR_MODE = 15, - - CDIC_SECTOR_FILE1 = 16, - CDIC_SECTOR_CHAN1 = 17, - CDIC_SECTOR_SUBMODE1 = 18, - CDIC_SECTOR_CODING1 = 19, - - CDIC_SECTOR_FILE2 = 20, - CDIC_SECTOR_CHAN2 = 21, - CDIC_SECTOR_SUBMODE2 = 22, - CDIC_SECTOR_CODING2 = 23, - - CDIC_SECTOR_DATA = 24, - - CDIC_SECTOR_SIZE = 2352, - - CDIC_SECTOR_DATASIZE = 2048, - CDIC_SECTOR_AUDIOSIZE = 2304, - CDIC_SECTOR_VIDEOSIZE = 2324, - - CDIC_SUBMODE_EOF = 0x80, - CDIC_SUBMODE_RT = 0x40, - CDIC_SUBMODE_FORM = 0x20, - CDIC_SUBMODE_TRIG = 0x10, - CDIC_SUBMODE_DATA = 0x08, - CDIC_SUBMODE_AUDIO = 0x04, - CDIC_SUBMODE_VIDEO = 0x02, - CDIC_SUBMODE_EOR = 0x01 + DISC_NONE, + DISC_MODE1, + DISC_MODE2, + DISC_CDDA, + DISC_TOC }; - int is_valid_sample_buf(uint16_t addr) const; - double sample_buf_freq(uint16_t addr) const; - int sample_buf_size(uint16_t addr) const; + enum + { + SECTOR_SYNC = 0, + + SECTOR_HEADER = 12, + + SECTOR_MODE = 15, + + SECTOR_FILE1 = 16, + SECTOR_CHAN1 = 17, + SECTOR_SUBMODE1 = 18, + SECTOR_CODING1 = 19, + + SECTOR_FILE2 = 20, + SECTOR_CHAN2 = 21, + SECTOR_SUBMODE2 = 22, + SECTOR_CODING2 = 23, + + SECTOR_DATA = 24, + + SECTOR_SIZE = 2352, + SECTOR_AUDIO_SIZE = 2304, + + SECTOR_DATASIZE = 2048, + SECTOR_AUDIOSIZE = 2304, + SECTOR_VIDEOSIZE = 2324, + + SUBMODE_EOF = 0x80, + SUBMODE_RT = 0x40, + SUBMODE_FORM = 0x20, + SUBMODE_TRIG = 0x10, + SUBMODE_DATA = 0x08, + SUBMODE_AUDIO = 0x04, + SUBMODE_VIDEO = 0x02, + SUBMODE_EOR = 0x01, + + CODING_BPS_MASK = 0x30, + CODING_4BPS = 0x00, + CODING_8BPS = 0x10, + CODING_16BPS = 0x20, + CODING_BPS_MPEG = 0x30, + + CODING_RATE_MASK = 0x0c, + CODING_37KHZ = 0x00, + CODING_18KHZ = 0x04, + CODING_RATE_RESV = 0x08, + CODING_44KHZ = 0x0c, + + CODING_CHAN_MASK = 0x03, + CODING_MONO = 0x00, + CODING_STEREO = 0x01, + CODING_CHAN_RESV = 0x02, + CODING_CHAN_MPEG = 0x03, + + SUBCODE_Q_CONTROL = 12, + SUBCODE_Q_TRACK = 13, + SUBCODE_Q_INDEX = 14, + SUBCODE_Q_MODE1_MINS = 15, + SUBCODE_Q_MODE1_SECS = 16, + SUBCODE_Q_MODE1_FRAC = 17, + SUBCODE_Q_MODE1_ZERO = 18, + SUBCODE_Q_MODE1_AMINS = 19, + SUBCODE_Q_MODE1_ASECS = 20, + SUBCODE_Q_MODE1_AFRAC = 21, + SUBCODE_Q_CRC0 = 22, + SUBCODE_Q_CRC1 = 23 + }; devcb_write_line m_intreq_callback; @@ -139,36 +172,53 @@ private: uint16_t m_interrupt_vector; // CDIC Interrupt Vector Register (0x303ffc) uint16_t m_data_buffer; // CDIC Data Buffer Register (0x303ffe) - emu_timer *m_interrupt_timer; cdrom_file *m_cd; - emu_timer *m_audio_sample_timer; - emu_timer *m_audio_playback_timer; - emu_timer *m_periodic_sample_timer[2]; - int32_t m_audio_sample_freq; - int32_t m_audio_sample_size; + emu_timer *m_sector_timer; + uint8_t m_disc_command; + uint8_t m_disc_mode; + uint8_t m_disc_spinup_counter; + uint32_t m_curr_lba; + emu_timer *m_audio_timer; + uint8_t m_audio_sector_counter; + uint8_t m_audio_format_sectors; + bool m_decoding_audio_map; uint16_t m_decode_addr; - uint8_t m_decode_delay; - attotime m_decode_period; - bool m_break_on_achan; - bool m_valid_audio_sample; - int m_xa_last[4]; - std::unique_ptr<uint16_t[]> m_ram; + int16_t m_xa_last[4]; + std::unique_ptr<uint8_t[]> m_ram; std::unique_ptr<int16_t[]> m_samples[2]; - static void decode_xa_mono(int32_t *cdic_xa_last, const uint8_t *xa, int16_t *dp); - static void decode_xa_mono8(int32_t *cdic_xa_last, const uint8_t *xa, int16_t *dp); - static void decode_xa_stereo(int32_t *cdic_xa_last, const uint8_t *xa, int16_t *dp); - static void decode_xa_stereo8(int32_t *cdic_xa_last, const uint8_t *xa, int16_t *dp); + void decode_8bit_xa_unit(int channel, uint8_t param, const uint8_t *data, int16_t *out_buffer); + void decode_4bit_xa_unit(int channel, uint8_t param, const uint8_t *data, uint8_t shift, int16_t *out_buffer); + void play_raw_group(const uint8_t *data); + void play_xa_group(const uint8_t coding, const uint8_t *data); + void play_audio_sector(const uint8_t coding, const uint8_t *data); + void process_audio_map(); + + bool is_mode2_sector_selected(const uint8_t *buffer); + bool is_mode2_audio_selected(const uint8_t *buffer); + + void process_disc_sector(); + void process_sector_data(const uint8_t *buffer, const uint8_t *subcode_buffer); + void init_disc_read(uint8_t disc_mode); + void cancel_disc_read(); + void handle_cdic_command(); + + void update_interrupt_state(); + + uint32_t lba_from_time(); - static const int32_t s_cdic_adpcm_filter_coef[5][2]; + static uint8_t get_sector_count_for_coding(uint8_t coding); + static void decode_xa_mono(int16_t *cdic_xa_last, const uint8_t *xa, int16_t *dp); + static void decode_xa_mono8(int16_t *cdic_xa_last, const uint8_t *xa, int16_t *dp); + static void decode_xa_stereo(int16_t *cdic_xa_last, const uint8_t *xa, int16_t *dp); + static void decode_xa_stereo8(int16_t *cdic_xa_last, const uint8_t *xa, int16_t *dp); - uint32_t increment_cdda_frame_bcd(uint32_t bcd); - uint32_t increment_cdda_sector_bcd(uint32_t bcd); - void decode_audio_sector(const uint8_t *xa, int32_t triggered); - void play_audio_sector(); + static const int16_t s_xa_filter_coef[4][2]; + static const int32_t s_samples_per_sector; + static const uint16_t s_crc_ccitt_table[256]; }; // device type definition diff --git a/src/mame/machine/cdislavehle.cpp b/src/mame/machine/cdislavehle.cpp index c8e01d67a10..4c103f24a37 100644 --- a/src/mame/machine/cdislavehle.cpp +++ b/src/mame/machine/cdislavehle.cpp @@ -18,6 +18,8 @@ TODO: #include "emu.h" #include "machine/cdislavehle.h" +#include <algorithm> + #define LOG_IRQS (1 << 0) #define LOG_COMMANDS (1 << 1) #define LOG_READS (1 << 2) @@ -56,62 +58,57 @@ void cdislave_hle_device::prepare_readback(const attotime &delay, uint8_t channe m_interrupt_timer->adjust(delay); } -void cdislave_hle_device::perform_mouse_update() +INPUT_CHANGED_MEMBER( cdislave_hle_device::mouse_update ) { - uint16_t x = m_mousex->read(); - uint16_t y = m_mousey->read(); - uint8_t buttons = m_mousebtn->read(); - - uint16_t old_mouse_x = m_real_mouse_x; - uint16_t old_mouse_y = m_real_mouse_y; - - if (m_real_mouse_x == 0xffff) + const uint8_t button_state = m_mousebtn->read(); + uint8_t button_bits = 0x01; + if (BIT(button_state, 0)) + button_bits |= 0x02; + if (BIT(button_state, 1)) + button_bits |= 0x04; + if (BIT(button_state, 2)) + button_bits |= 0x06; + + const uint16_t x = m_mousex->read(); + const uint16_t y = m_mousey->read(); + + int16_t deltax = 0; + int16_t deltay = 0; + + if (m_input_mouse_x != 0xffff && m_input_mouse_y != 0xffff) { - old_mouse_x = x & 0x3ff; - old_mouse_y = y & 0x3ff; + deltax = -(m_input_mouse_x - x); + deltay = -(m_input_mouse_y - y); } - m_real_mouse_x = x & 0x3ff; - m_real_mouse_y = y & 0x3ff; + m_input_mouse_x = x; + m_input_mouse_y = y; - m_fake_mouse_x += (m_real_mouse_x - old_mouse_x); - m_fake_mouse_y += (m_real_mouse_y - old_mouse_y); - - while (m_fake_mouse_x > 0x3ff) - { - m_fake_mouse_x += 0x400; - } - - while (m_fake_mouse_y > 0x3ff) - { - m_fake_mouse_y += 0x400; - } - - x = m_fake_mouse_x; - y = m_fake_mouse_y; + m_device_mouse_x = std::clamp(m_device_mouse_x + deltax, 0, 767); + m_device_mouse_y = std::clamp(m_device_mouse_y + deltay, 0, 559); if (m_polling_active) { - prepare_readback(attotime::zero, 0, 4, ((x & 0x380) >> 7) | (buttons << 4), x & 0x7f, (y & 0x380) >> 7, y & 0x7f, 0xf7); + const uint8_t byte3 = ((m_device_mouse_x & 0x380) >> 7) | (button_bits << 3); + const uint8_t byte2 = m_device_mouse_x & 0x7f; + const uint8_t byte1 = (m_device_mouse_y & 0x380) >> 7; + const uint8_t byte0 = m_device_mouse_y & 0x7f; + prepare_readback(attotime::zero, 0, 4, byte3, byte2, byte1, byte0, 0xf7); } } -INPUT_CHANGED_MEMBER( cdislave_hle_device::mouse_update ) -{ - perform_mouse_update(); -} - static INPUT_PORTS_START(cdislave_mouse) PORT_START("MOUSEX") - PORT_BIT(0x3ff, 0x000, IPT_MOUSE_X) PORT_SENSITIVITY(100) PORT_MINMAX(0x000, 0x3ff) PORT_KEYDELTA(2) PORT_CHANGED_MEMBER(DEVICE_SELF, cdislave_hle_device, mouse_update, 0) + PORT_BIT(0xffff, 0x000, IPT_MOUSE_X) PORT_SENSITIVITY(100) PORT_KEYDELTA(2) PORT_CHANGED_MEMBER(DEVICE_SELF, cdislave_hle_device, mouse_update, 0) PORT_START("MOUSEY") - PORT_BIT(0x3ff, 0x000, IPT_MOUSE_Y) PORT_SENSITIVITY(100) PORT_MINMAX(0x000, 0x3ff) PORT_KEYDELTA(2) PORT_CHANGED_MEMBER(DEVICE_SELF, cdislave_hle_device, mouse_update, 0) + PORT_BIT(0xffff, 0x000, IPT_MOUSE_Y) PORT_SENSITIVITY(100) PORT_KEYDELTA(2) PORT_CHANGED_MEMBER(DEVICE_SELF, cdislave_hle_device, mouse_update, 0) PORT_START("MOUSEBTN") - PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_BUTTON1) PORT_CODE(MOUSECODE_BUTTON1) PORT_NAME("Mouse Button 1") PORT_CHANGED_MEMBER(DEVICE_SELF, cdislave_hle_device, mouse_update, 0) - PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_BUTTON2) PORT_CODE(MOUSECODE_BUTTON2) PORT_NAME("Mouse Button 2") PORT_CHANGED_MEMBER(DEVICE_SELF, cdislave_hle_device, mouse_update, 0) - PORT_BIT(0xfc, IP_ACTIVE_HIGH, IPT_UNUSED) + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_BUTTON1) PORT_CODE(MOUSECODE_BUTTON1) PORT_NAME("Button 1") PORT_CHANGED_MEMBER(DEVICE_SELF, cdislave_hle_device, mouse_update, 0) + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_BUTTON2) PORT_CODE(MOUSECODE_BUTTON2) PORT_NAME("Button 2") PORT_CHANGED_MEMBER(DEVICE_SELF, cdislave_hle_device, mouse_update, 0) + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_BUTTON3) PORT_CODE(MOUSECODE_BUTTON3) PORT_NAME("Button 3") PORT_CHANGED_MEMBER(DEVICE_SELF, cdislave_hle_device, mouse_update, 0) + PORT_BIT(0xf8, IP_ACTIVE_HIGH, IPT_UNUSED) INPUT_PORTS_END ioport_constructor cdislave_hle_device::device_input_ports() const @@ -156,20 +153,8 @@ uint16_t cdislave_hle_device::slave_r(offs_t offset) void cdislave_hle_device::set_mouse_position() { -// uint16_t x, y; - - //printf( "Set mouse position: %02x %02x %02x\n", m_in_buf[0], m_in_buf[1], m_in_buf[2] ); - - m_fake_mouse_y = ((m_in_buf[1] & 0x0f) << 6) | (m_in_buf[0] & 0x3f); - m_fake_mouse_x = ((m_in_buf[1] & 0x70) << 3) | m_in_buf[2]; - -// x = m_fake_mouse_x; -// y = m_fake_mouse_y; - - if (m_polling_active) - { - //prepare_readback(attotime::zero, 0, 4, (x & 0x380) >> 7, x & 0x7f, (y & 0x380) >> 7, y & 0x7f, 0xf7); - } + m_device_mouse_x = ((m_in_buf[1] & 0x70) << 3) | (m_in_buf[2] & 0x7f); + m_device_mouse_y = ((m_in_buf[1] & 0x0f) << 6) | (m_in_buf[0] & 0x3f); } void cdislave_hle_device::slave_w(offs_t offset, uint16_t data) @@ -290,20 +275,24 @@ void cdislave_hle_device::slave_w(offs_t offset, uint16_t data) switch (data & 0x00ff) { case 0x82: // Mute Audio + { LOGMASKED(LOG_COMMANDS, "slave_w: Channel %d: Mute Audio (0x82)\n", offset); - m_dmadac[0]->enable(0); - m_dmadac[1]->enable(0); + m_dmadac[0]->set_volume(0); + m_dmadac[1]->set_volume(0); m_in_index = 0; m_in_count = 0; //cdic->audio_sample_timer->adjust(attotime::never); break; + } case 0x83: // Unmute Audio + { LOGMASKED(LOG_COMMANDS, "slave_w: Channel %d: Unmute Audio (0x83)\n", offset); - m_dmadac[0]->enable(1); - m_dmadac[1]->enable(1); + m_dmadac[0]->set_volume(0x100); + m_dmadac[1]->set_volume(0x100); m_in_index = 0; m_in_count = 0; break; + } case 0xf0: // Set Front Panel LCD LOGMASKED(LOG_COMMANDS, "slave_w: Channel %d: Set Front Panel LCD (0xf0)\n", offset); m_in_count = 17; @@ -476,11 +465,11 @@ void cdislave_hle_device::device_start() save_item(NAME(m_lcd_state)); - save_item(NAME(m_real_mouse_x)); - save_item(NAME(m_real_mouse_y)); + save_item(NAME(m_input_mouse_x)); + save_item(NAME(m_input_mouse_y)); - save_item(NAME(m_fake_mouse_x)); - save_item(NAME(m_fake_mouse_y)); + save_item(NAME(m_device_mouse_x)); + save_item(NAME(m_device_mouse_y)); m_interrupt_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(cdislave_hle_device::trigger_readback_int), this)); m_interrupt_timer->adjust(attotime::never); @@ -513,11 +502,11 @@ void cdislave_hle_device::device_reset() memset(m_lcd_state, 0, 16); - m_real_mouse_x = 0xffff; - m_real_mouse_y = 0xffff; + m_input_mouse_x = 0xffff; + m_input_mouse_y = 0xffff; - m_fake_mouse_x = 0; - m_fake_mouse_y = 0; + m_device_mouse_x = 0; + m_device_mouse_y = 0; m_int_callback(CLEAR_LINE); } diff --git a/src/mame/machine/cdislavehle.h b/src/mame/machine/cdislavehle.h index 167437722fe..f4e31d7d117 100644 --- a/src/mame/machine/cdislavehle.h +++ b/src/mame/machine/cdislavehle.h @@ -55,6 +55,9 @@ protected: TIMER_CALLBACK_MEMBER( trigger_readback_int ); private: + void prepare_readback(const attotime &delay, uint8_t channel, uint8_t count, uint8_t data0, uint8_t data1, uint8_t data2, uint8_t data3, uint8_t cmd); + void set_mouse_position(); + devcb_write_line m_int_callback; required_device_array<dmadac_sound_device, 2> m_dmadac; @@ -63,12 +66,8 @@ private: required_ioport m_mousey; required_ioport m_mousebtn; - // internal state - class channel_state + struct channel_state { - public: - channel_state() { } - uint8_t m_out_buf[4]; uint8_t m_out_index; uint8_t m_out_count; @@ -88,18 +87,11 @@ private: uint8_t m_lcd_state[16]; - uint16_t m_real_mouse_x; - uint16_t m_real_mouse_y; + uint16_t m_input_mouse_x; + uint16_t m_input_mouse_y; - uint16_t m_fake_mouse_x; - uint16_t m_fake_mouse_y; - - // static internal members - - // non-static internal members - void prepare_readback(const attotime &delay, uint8_t channel, uint8_t count, uint8_t data0, uint8_t data1, uint8_t data2, uint8_t data3, uint8_t cmd); - void perform_mouse_update(); - void set_mouse_position(); + int16_t m_device_mouse_x; + int16_t m_device_mouse_y; }; |