diff options
| author | 2026-05-16 13:00:54 +0100 | |
|---|---|---|
| committer | 2026-05-16 13:02:19 +0100 | |
| commit | f061a1ee1c1fb705f8665f8c8a34319b801b2ee6 (patch) | |
| tree | 559f3f797c5bbfa7da635a080b37aa8ec6226be5 /src | |
| parent | 80168132d950d25992518dfbcac62cda9ef54713 (diff) | |
sound/pcd3311.cpp: Implemented DTMF tone generator, and I2C interface.
psion/psion3.cpp: DTMF tone generator is now working, removed MACHINE_IMPERFECT_SOUND flag.
atari/pofo.cpp: DTMF tone generator is now working, removed MACHINE_IMPERFECT_SOUND flag.
Diffstat (limited to 'src')
| -rw-r--r-- | src/devices/sound/pcd3311.cpp | 266 | ||||
| -rw-r--r-- | src/devices/sound/pcd3311.h | 40 | ||||
| -rw-r--r-- | src/mame/acorn/accomm.cpp | 5 | ||||
| -rw-r--r-- | src/mame/atari/pofo.cpp | 7 | ||||
| -rw-r--r-- | src/mame/psion/psion3.cpp | 10 |
5 files changed, 305 insertions, 23 deletions
diff --git a/src/devices/sound/pcd3311.cpp b/src/devices/sound/pcd3311.cpp index 03e5cd2aa81..6943b71277b 100644 --- a/src/devices/sound/pcd3311.cpp +++ b/src/devices/sound/pcd3311.cpp @@ -4,11 +4,19 @@ PCD3311 DTMF/modem/musical tone generator emulation + TODO: + - derive tone frequencies from clock (ROM dividers need extracting) + **********************************************************************/ #include "emu.h" #include "pcd3311.h" +#define LOG_DATA (1U << 1) +#define LOG_LINE (1U << 2) + +#define VERBOSE (0) +#include "logmacro.h" //************************************************************************** @@ -18,7 +26,6 @@ DEFINE_DEVICE_TYPE(PCD3311, pcd3311_device, "pcd3311", "PCD3311") - //************************************************************************** // LIVE DEVICE //************************************************************************** @@ -28,8 +35,16 @@ DEFINE_DEVICE_TYPE(PCD3311, pcd3311_device, "pcd3311", "PCD3311") //------------------------------------------------- pcd3311_device::pcd3311_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : - device_t(mconfig, PCD3311, tag, owner, clock), - device_sound_interface(mconfig, *this) + device_t(mconfig, PCD3311, tag, owner, clock) + , device_sound_interface(mconfig, *this) + , m_slave_address(PCD3311_SLAVE_ADDRESS) + , m_scl(0) + , m_sdaw(0) + , m_sdar(1) + , m_state(STATE_IDLE) + , m_bits(0) + , m_shift(0) + , m_devsel(0) { } @@ -40,10 +55,31 @@ pcd3311_device::pcd3311_device(const machine_config &mconfig, const char *tag, d void pcd3311_device::device_start() { - save_item(NAME(m_a0)); + m_stream = stream_alloc(0, 1, SAMPLE_RATE_OUTPUT_ADAPTIVE); + + m_mode = 0; + m_strobe = 0; + m_data = 0; + + m_freq[0] = m_freq[1] = 0; + m_incr[0] = m_incr[1] = 0; + m_signal[0] = m_signal[1] = 1.0; + save_item(NAME(m_mode)); save_item(NAME(m_strobe)); save_item(NAME(m_data)); + + save_item(NAME(m_scl)); + save_item(NAME(m_sdaw)); + save_item(NAME(m_sdar)); + save_item(NAME(m_state)); + save_item(NAME(m_bits)); + save_item(NAME(m_shift)); + save_item(NAME(m_devsel)); + + save_item(NAME(m_freq)); + save_item(NAME(m_incr)); + save_item(NAME(m_signal)); } @@ -54,4 +90,226 @@ void pcd3311_device::device_start() void pcd3311_device::sound_stream_update(sound_stream &stream) { + if (m_freq[0] == 0) + return; + + // fill in the sample + for (int sampindex = 0; sampindex < stream.samples(); sampindex++) + { + for (int dac = 0; dac < 2; dac++) + { + m_incr[dac] -= m_freq[dac]; + while (m_incr[dac] < 0) + { + m_incr[dac] += stream.sample_rate() / 2; + m_signal[dac] = -m_signal[dac]; + } + stream.add(0, sampindex, m_signal[dac]); + } + } +} + + +void pcd3311_device::load_data(uint8_t data) +{ + m_stream->update(); + + static const float dtmf_tones[12] { 697.90, 770.46, 850.45, 943.23, 1206.45, 1341.66, 1482.21, 1638.24, 1875.1, 1970.0, 2358.1, 2470.4 }; + static const float modem_tones[12] { 1296.94, 2103.14, 1197.17, 2192.01, 978.82, 1179.03, 1073.33, 1265.30, 1655.66, 1852.77, 2021.20, 2223.32 }; + static const float music_tones[16] { 622.5, 659.5, 697.9, 741.1, 782.1, 832.3, 879.3, 931.9, 985.0, 1044.5, 1111.7, 1245.1, 1318.9, 1402.1, 1572.0, 1768.5 }; + + m_freq[0] = m_freq[1] = 0; + + switch (data & 0x30) + { + case 0x00: // DTMF single tones; musical tones + switch (data & 0x0f) + { + case 0x04: m_freq[0] = dtmf_tones[8]; break; + case 0x05: m_freq[0] = dtmf_tones[9]; break; + case 0x06: m_freq[0] = dtmf_tones[10]; break; + case 0x07: m_freq[0] = dtmf_tones[11]; break; + case 0x08: m_freq[0] = dtmf_tones[0]; break; + case 0x09: m_freq[0] = dtmf_tones[1]; break; + case 0x0a: m_freq[0] = dtmf_tones[2]; break; + case 0x0b: m_freq[0] = dtmf_tones[3]; break; + case 0x0c: m_freq[0] = dtmf_tones[4]; break; + case 0x0d: m_freq[0] = dtmf_tones[5]; break; + case 0x0e: m_freq[0] = dtmf_tones[6]; break; + case 0x0f: m_freq[0] = dtmf_tones[7]; break; + } + break; + case 0x10: // DTMF dual tones + switch (data & 0x0f) + { + case 0x00: m_freq[0] = dtmf_tones[3]; m_freq[1] = dtmf_tones[5]; break; + case 0x01: m_freq[0] = dtmf_tones[0]; m_freq[1] = dtmf_tones[4]; break; + case 0x02: m_freq[0] = dtmf_tones[0]; m_freq[1] = dtmf_tones[5]; break; + case 0x03: m_freq[0] = dtmf_tones[0]; m_freq[1] = dtmf_tones[6]; break; + case 0x04: m_freq[0] = dtmf_tones[1]; m_freq[1] = dtmf_tones[4]; break; + case 0x05: m_freq[0] = dtmf_tones[1]; m_freq[1] = dtmf_tones[5]; break; + case 0x06: m_freq[0] = dtmf_tones[1]; m_freq[1] = dtmf_tones[6]; break; + case 0x07: m_freq[0] = dtmf_tones[2]; m_freq[1] = dtmf_tones[4]; break; + case 0x08: m_freq[0] = dtmf_tones[2]; m_freq[1] = dtmf_tones[5]; break; + case 0x09: m_freq[0] = dtmf_tones[2]; m_freq[1] = dtmf_tones[6]; break; + case 0x0a: m_freq[0] = dtmf_tones[0]; m_freq[1] = dtmf_tones[7]; break; + case 0x0b: m_freq[0] = dtmf_tones[1]; m_freq[1] = dtmf_tones[7]; break; + case 0x0c: m_freq[0] = dtmf_tones[2]; m_freq[1] = dtmf_tones[7]; break; + case 0x0d: m_freq[0] = dtmf_tones[3]; m_freq[1] = dtmf_tones[7]; break; + case 0x0e: m_freq[0] = dtmf_tones[3]; m_freq[1] = dtmf_tones[4]; break; + case 0x0f: m_freq[0] = dtmf_tones[3]; m_freq[1] = dtmf_tones[6]; break; + } + break; + case 0x20: // modem tones + switch (data & 0x0f) + { + case 0x04: m_freq[0] = modem_tones[0]; break; + case 0x05: m_freq[0] = modem_tones[1]; break; + case 0x06: m_freq[0] = modem_tones[2]; break; + case 0x07: m_freq[0] = modem_tones[3]; break; + case 0x08: m_freq[0] = modem_tones[4]; break; + case 0x09: m_freq[0] = modem_tones[5]; break; + case 0x0a: m_freq[0] = modem_tones[6]; break; + case 0x0b: m_freq[0] = modem_tones[7]; break; + case 0x0c: m_freq[0] = modem_tones[8]; break; + case 0x0d: m_freq[0] = modem_tones[9]; break; + case 0x0e: m_freq[0] = modem_tones[10]; break; + case 0x0f: m_freq[0] = modem_tones[11]; break; + } + break; + case 0x30: // musical tones + m_freq[0] = music_tones[data & 0x0f]; + break; + } + + // restart waves from beginning + m_incr[0] = m_incr[1] = 0; + m_signal[0] = m_signal[1] = 1.0; +} + + +void pcd3311_device::a0_w(int state) +{ + state &= 1; + if (BIT(m_slave_address, 1) != state) + { + LOGMASKED(LOG_LINE, "set a0 %d\n", state ); + m_slave_address = (m_slave_address & 0xfd) | (state << 1); + } +} + + +void pcd3311_device::strobe_w(int state) +{ + if (m_strobe && !state) + load_data(m_data); + + m_strobe = state; +} + + +void pcd3311_device::scl_w(int state) +{ + if (m_scl != state) + { + m_scl = state; + LOGMASKED(LOG_LINE, "set_scl_line %d\n", m_scl); + + switch (m_state) + { + case STATE_DEVSEL: + case STATE_DATAIN: + if (m_bits < 8) + { + if (m_scl) + { + m_shift = ((m_shift << 1) | m_sdaw) & 0xff; + m_bits++; + } + } + else + { + if (m_scl) + { + m_bits++; + } + else + { + if (m_bits == 8) + { + switch (m_state) + { + case STATE_DEVSEL: + m_devsel = m_shift; + + if ((m_devsel & 0xfe) != m_slave_address) + { + LOGMASKED(LOG_DATA, "devsel %02x: not this device\n", m_devsel); + m_state = STATE_IDLE; + } + else if ((m_devsel & 1) == 0) + { + LOGMASKED(LOG_DATA, "devsel %02x: write\n", m_devsel); + m_state = STATE_DATAIN; + } + break; + + case STATE_DATAIN: + load_data(m_shift); + + LOGMASKED(LOG_DATA, "data %02x\n", m_shift); + break; + } + + if( m_state != STATE_IDLE ) + { + m_sdar = 0 ; + } + } + else + { + m_bits = 0; + m_sdar = 1; + } + } + } + break; + } + } +} + +void pcd3311_device::sda_w(int state) +{ + state &= 1; + if (m_sdaw != state) + { + LOGMASKED(LOG_LINE, "set sda %d\n", state); + m_sdaw = state; + + if (m_scl) + { + if (m_sdaw) + { + LOGMASKED(LOG_DATA, "stop\n"); + m_state = STATE_IDLE; + } + else + { + LOGMASKED(LOG_DATA, "start\n"); + m_state = STATE_DEVSEL; + m_bits = 0; + } + + m_sdar = 1; + } + } +} + +int pcd3311_device::sda_r() +{ + int res = m_sdar & 1; + + LOGMASKED(LOG_LINE, "read sda %d\n", res); + + return res; } diff --git a/src/devices/sound/pcd3311.h b/src/devices/sound/pcd3311.h index 840b9da69ad..f3e904b5116 100644 --- a/src/devices/sound/pcd3311.h +++ b/src/devices/sound/pcd3311.h @@ -23,38 +23,60 @@ #pragma once - - //************************************************************************** // TYPE DEFINITIONS //************************************************************************** // ======================> pcd3311_device -class pcd3311_device : public device_t, - public device_sound_interface +class pcd3311_device : public device_t, public device_sound_interface { public: // construction/destruction pcd3311_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); void write(uint8_t data) { m_data = data; } - void strobe_w(int state) { m_strobe = state; } + void strobe_w(int state); void mode_w(int state) { m_mode = state; } - void a0_w(int state) { m_a0 = state; } + void a0_w(int state); + + void scl_w(int state); + void sda_w(int state); + int sda_r(); + + // use in memory maps to avoid strobe logic. + void write_direct(uint8_t data) { load_data(data); } protected: - // device-level overrides + // device_t overrides virtual void device_start() override ATTR_COLD; - // internal callbacks virtual void sound_stream_update(sound_stream &stream) override; private: - int m_a0; + static constexpr uint8_t PCD3311_SLAVE_ADDRESS = 0x48; + + enum { STATE_IDLE, STATE_DEVSEL, STATE_DATAIN }; + + void load_data(uint8_t data); + int m_mode; int m_strobe; uint8_t m_data; + + int m_slave_address; + int m_scl; + int m_sdaw; + int m_sdar; + int m_state; + int m_bits; + int m_shift; + int m_devsel; + + sound_stream *m_stream; // stream number + uint32_t m_freq[2]; // current frequencies + int32_t m_incr[2]; // initial wave state + sound_stream::sample_t m_signal[2]; // current signals }; diff --git a/src/mame/acorn/accomm.cpp b/src/mame/acorn/accomm.cpp index 2aa4bbfef72..51f66f626ad 100644 --- a/src/mame/acorn/accomm.cpp +++ b/src/mame/acorn/accomm.cpp @@ -205,7 +205,7 @@ void accomm_state::ram_w(offs_t offset, uint8_t data) uint8_t accomm_state::via_pb_r() { - return 0xfe | (m_rtc->sda_r() & m_cct->read_sda()); + return 0xfe | (m_rtc->sda_r() & m_dtmf->sda_r() & m_cct->read_sda()); } void accomm_state::via_pb_w(uint8_t data) @@ -215,6 +215,9 @@ void accomm_state::via_pb_w(uint8_t data) m_rtc->sda_w(BIT(data, 1)); m_rtc->scl_w(BIT(data, 2)); + m_dtmf->sda_w(BIT(data, 1)); + m_dtmf->scl_w(BIT(data, 2)); + m_cct->write_sda(BIT(data, 1)); m_cct->write_scl(BIT(data, 2)); diff --git a/src/mame/atari/pofo.cpp b/src/mame/atari/pofo.cpp index d3ddd03c655..ddd3979479c 100644 --- a/src/mame/atari/pofo.cpp +++ b/src/mame/atari/pofo.cpp @@ -10,7 +10,7 @@ http://www.atari-portfolio.co.uk/pfnews/pf9.txt Command line for dual RAM expansion with A: File Manager ROM card and B: RAM card - ./mess64 pofo -exp ram -exp:ram:exp ram2 -cart1 fileman -exp:ram:ccmb ram + ./mame pofo -exp ram -exp:ram:exp ram2 -cart1 fileman -exp:ram:ccmb ram */ @@ -27,7 +27,6 @@ - HD61830A00 - 5816 2Kx8 RAM - 27C256 32Kx8 EPROM - - PCD3311T DTMF generator @ 3.578640MHz */ @@ -1051,5 +1050,5 @@ ROM_END //************************************************************************** // YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS -COMP( 1989, pofo, 0, 0, portfolio, portfolio, portfolio_state, empty_init, "Atari", "Portfolio", MACHINE_IMPERFECT_GRAPHICS | MACHINE_IMPERFECT_SOUND | MACHINE_SUPPORTS_SAVE ) -COMP( 1990, pofo2, pofo, 0, portfolio2, portfolio, portfolio_state, empty_init, "Atari", "Portfolio 2", MACHINE_IMPERFECT_GRAPHICS | MACHINE_IMPERFECT_SOUND | MACHINE_SUPPORTS_SAVE ) +COMP( 1989, pofo, 0, 0, portfolio, portfolio, portfolio_state, empty_init, "Atari", "Portfolio", MACHINE_IMPERFECT_GRAPHICS | MACHINE_SUPPORTS_SAVE ) +COMP( 1990, pofo2, pofo, 0, portfolio2, portfolio, portfolio_state, empty_init, "Atari", "Portfolio 2", MACHINE_IMPERFECT_GRAPHICS | MACHINE_SUPPORTS_SAVE ) diff --git a/src/mame/psion/psion3.cpp b/src/mame/psion/psion3.cpp index 022bb993e8f..25cd0fdb5c6 100644 --- a/src/mame/psion/psion3.cpp +++ b/src/mame/psion/psion3.cpp @@ -101,7 +101,7 @@ void psion3_state::io_map(address_map &map) map(0x0000, 0x001f).rw(m_asic1, FUNC(psion_asic1_device::io_r), FUNC(psion_asic1_device::io_w)); map(0x0080, 0x008f).rw(m_asic2, FUNC(psion_asic2_device::io_r), FUNC(psion_asic2_device::io_w)).umask16(0x00ff); //map(0x0100, 0x01ff).lr8(NAME([]() { return 0xff; })); // w: enable Vcc lines? - map(0x0200, 0x02ff).w(m_dtmf, FUNC(pcd3311_device::write)); + map(0x0200, 0x02ff).w(m_dtmf, FUNC(pcd3311_device::write_direct)); } void psion3_state::asic1_map(address_map &map) @@ -322,7 +322,7 @@ void psion3_state::psion3(machine_config &config) SPEAKER(config, "mono").front_center(); SPEAKER_SOUND(config, m_speaker).add_route(ALL_OUTPUTS, "mono", 1.00); // Piezo buzzer - PCD3311(config, m_dtmf, 3'580'000).add_route(ALL_OUTPUTS, "mono", 0.25); // PCD3311CT + PCD3311(config, m_dtmf, 3.58_MHz_XTAL).add_route(ALL_OUTPUTS, "mono", 0.25); // PCD3311CT PSION_SSD(config, m_ssd[0]); m_ssd[0]->door_cb().set(m_asic2, FUNC(psion_asic2_device::dnmi_w)); @@ -374,6 +374,6 @@ ROM_END // YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS -COMP( 1991, psion3, 0, 0, psion3, psion3, psion3_state, empty_init, "Psion", "Series 3", MACHINE_SUPPORTS_SAVE | MACHINE_IMPERFECT_SOUND ) -COMP( 1992, pocketbk, psion3, 0, psion3s, pocketbk, psion3_state, empty_init, "Acorn Computers", "Pocket Book", MACHINE_SUPPORTS_SAVE | MACHINE_IMPERFECT_SOUND ) -COMP( 1994, psion3s, psion3, 0, psion3s, psion3s, psion3_state, empty_init, "Psion", "Series 3s", MACHINE_SUPPORTS_SAVE | MACHINE_IMPERFECT_SOUND ) +COMP( 1991, psion3, 0, 0, psion3, psion3, psion3_state, empty_init, "Psion", "Series 3", MACHINE_SUPPORTS_SAVE ) +COMP( 1992, pocketbk, psion3, 0, psion3s, pocketbk, psion3_state, empty_init, "Acorn Computers", "Pocket Book", MACHINE_SUPPORTS_SAVE ) +COMP( 1994, psion3s, psion3, 0, psion3s, psion3s, psion3_state, empty_init, "Psion", "Series 3s", MACHINE_SUPPORTS_SAVE ) |
