From e49e75c1227542f04e56dcc91af8e6aa58463823 Mon Sep 17 00:00:00 2001 From: AJR Date: Fri, 14 Jun 2019 00:31:52 -0400 Subject: Add device emulation for MM5307 Baud Rate Generator --- scripts/src/machine.lua | 12 +++ scripts/target/mame/arcade.lua | 1 + scripts/target/mame/mess.lua | 1 + src/devices/machine/mm5307.cpp | 222 +++++++++++++++++++++++++++++++++++++++++ src/devices/machine/mm5307.h | 99 ++++++++++++++++++ src/mame/drivers/poly88.cpp | 13 ++- src/mame/includes/poly88.h | 14 +-- src/mame/machine/poly88.cpp | 33 +++--- 8 files changed, 366 insertions(+), 29 deletions(-) create mode 100644 src/devices/machine/mm5307.cpp create mode 100644 src/devices/machine/mm5307.h diff --git a/scripts/src/machine.lua b/scripts/src/machine.lua index a456bf31ef8..e58809b2470 100644 --- a/scripts/src/machine.lua +++ b/scripts/src/machine.lua @@ -1974,6 +1974,18 @@ if (MACHINES["MICROTOUCH"]~=null) then } end +--------------------------------------------------- +-- +--@src/devices/machine/mm5307.h,MACHINES["MM5307"] = true +--------------------------------------------------- + +if (MACHINES["MM5307"]~=null) then + files { + MAME_DIR .. "src/devices/machine/mm5307.cpp", + MAME_DIR .. "src/devices/machine/mm5307.h", + } +end + --------------------------------------------------- -- --@src/devices/machine/mm58274c.h,MACHINES["MM58274C"] = true diff --git a/scripts/target/mame/arcade.lua b/scripts/target/mame/arcade.lua index 29b374473b5..1602d1ea032 100644 --- a/scripts/target/mame/arcade.lua +++ b/scripts/target/mame/arcade.lua @@ -520,6 +520,7 @@ MACHINES["MCF5206E"] = true MACHINES["METERS"] = true MACHINES["MICROTOUCH"] = true --MACHINES["MIOT6530"] = true +--MACHINES["MM5307"] = true --MACHINES["MM58167"] = true MACHINES["MM58274C"] = true MACHINES["MM74C922"] = true diff --git a/scripts/target/mame/mess.lua b/scripts/target/mame/mess.lua index af94de5ab22..86c89d6b5be 100644 --- a/scripts/target/mame/mess.lua +++ b/scripts/target/mame/mess.lua @@ -524,6 +524,7 @@ MACHINES["MCCS1850"] = true MACHINES["MCF5206E"] = true MACHINES["MICROTOUCH"] = true MACHINES["MIOT6530"] = true +MACHINES["MM5307"] = true MACHINES["MM58167"] = true MACHINES["MM58274C"] = true MACHINES["MM74C922"] = true diff --git a/src/devices/machine/mm5307.cpp b/src/devices/machine/mm5307.cpp new file mode 100644 index 00000000000..7d97136149a --- /dev/null +++ b/src/devices/machine/mm5307.cpp @@ -0,0 +1,222 @@ +// license:BSD-3-Clause +// copyright-holders:AJR +/*************************************************************************** + + National Semiconductor MM5307 Baud Rate Generator/Programmable Divider + + The MM5307 divides the frequency of a crystal oscillator or external + clock (maximum 1 MHz, ideally 921.6 kHz) to generate a single baud + rate output. (The undivided frequency is also output on another pin, + not emulated here.) + + The four control inputs (A, B, C, D) select one of 15 mask-programmed + divisors or an independent external frequency. When the selected + divisor is 2N, the output has a duty cycle of exactly 50%. When the + selected divisor is 2N + 1, the high output is always one clock cycle + longer than the low output. When the selected divisor is 2N + 0.5, + the duty cycle varies slightly from phase to phase. + + The MM5307 resets its output frequency when the reset input is pulsed + low or the control inputs change. + +***************************************************************************/ + +#include "emu.h" +#include "mm5307.h" + +#define VERBOSE 0 +#include "logmacro.h" + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +// device type definitions +DEFINE_DEVICE_TYPE(MM5307AA, mm5307aa_device, "mm5307aa", "MM5307AA Baud Rate Generator") +DEFINE_DEVICE_TYPE(MM5307AB, mm5307ab_device, "mm5307ab", "MM5307AB Baud Rate Generator") + + +//************************************************************************** +// DIVISOR TABLES +//************************************************************************** + +const std::array mm5307aa_device::s_divisors_x2 = { + 0, // external frequency (not divided) + 2304, // 50 baud (divide by 1152) + 1536, // 75 baud (divide by 768) + 1048, // 110 baud (divide by 524) + 857, // 134.5 baud (divide by 428.5) + 768, // 150 baud (divide by 384) + 384, // 300 baud (divide by 192) + 192, // 600 baud (divide by 96) + 128, // 900 baud (divide by 64) + 96, // 1200 baud (divide by 48) + 64, // 1800 baud (divide by 32) + 48, // 2400 baud (divide by 24) + 32, // 3600 baud (divide by 16) + 24, // 4800 baud (divide by 12) + 16, // 7200 baud (divide by 8) + 12 // 9600 baud (divide by 6) +}; + + +const std::array mm5307ab_device::s_divisors_x2 = { + 0, // external frequency (not divided) + 2304, // 50 baud (divide by 1152) + 576, // 200 baud (divide by 288) + 1048, // 110 baud (divide by 524) + 857, // 134.5 baud (divide by 428.5) + 768, // 150 baud (divide by 384) + 384, // 300 baud (divide by 192) + 192, // 600 baud (divide by 96) + 128, // 900 baud (divide by 64) + 96, // 1200 baud (divide by 48) + 64, // 1800 baud (divide by 32) + 48, // 2400 baud (divide by 24) + 32, // 3600 baud (divide by 16) + 24, // 4800 baud (divide by 12) + 1536, // 75 baud (divide by 768) + 12 // 9600 baud (divide by 6) +}; + + +//************************************************************************** +// DEVICE IMPLEMENTATION +//************************************************************************** + +//------------------------------------------------- +// mm5307_device - constructor +//------------------------------------------------- + +mm5307_device::mm5307_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, const std::array &divisors_x2) + : device_t(mconfig, type, tag, owner, clock) + , m_divisors_x2(divisors_x2) + , m_output_cb(*this) + , m_ext_freq(0) + , m_freq_control(0) + , m_phase(0) + , m_periodic_timer(nullptr) +{ +} + + +//------------------------------------------------- +// mm5307aa_device - constructor +//------------------------------------------------- + +mm5307aa_device::mm5307aa_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) + : mm5307_device(mconfig, MM5307AA, tag, owner, clock, s_divisors_x2) +{ +} + + +//------------------------------------------------- +// mm5307ab_device - constructor +//------------------------------------------------- + +mm5307ab_device::mm5307ab_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) + : mm5307_device(mconfig, MM5307AB, tag, owner, clock, s_divisors_x2) +{ +} + + +//------------------------------------------------- +// device_resolve_objects - resolve objects that +// may be needed for other devices to set +// initial conditions at start time +//------------------------------------------------- + +void mm5307_device::device_resolve_objects() +{ + // Resolve callback + m_output_cb.resolve_safe(); +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void mm5307_device::device_start() +{ + // Create timer + m_periodic_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(mm5307_device::periodic_update), this)); + + // Register for saving + save_item(NAME(m_freq_control)); + save_item(NAME(m_phase)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void mm5307_device::device_reset() +{ + // Output delay from reset + m_periodic_timer->adjust(attotime::from_usec(500) + clocks_to_attotime(4)); +} + + +//------------------------------------------------- +// control_w - set frequency control +//------------------------------------------------- + +void mm5307_device::control_w(u8 data) +{ + data &= 15; + if (data != m_freq_control) + { + m_freq_control = data; + + if (m_divisors_x2[data] == 0) + LOG("%s: External frequency selected\n", machine().describe_context()); + else + LOG("%s: %.1f baud selected\n", machine().describe_context(), clock() / (8.0 * m_divisors_x2[data])); + + // Emulate access time + m_periodic_timer->adjust(attotime::from_usec(2800) + clocks_to_attotime(13)); + } +} + + +//------------------------------------------------- +// periodic_update - update output state and +// reset timer for next period +//------------------------------------------------- + +TIMER_CALLBACK_MEMBER(mm5307_device::periodic_update) +{ + // Up to four different phases + m_phase = (m_phase + 1) & 3; + m_output_cb(BIT(m_phase, 0)); + + u16 divisor = m_divisors_x2[m_freq_control]; + if (divisor == 0) + { + m_periodic_timer->adjust(m_ext_freq == 0 ? attotime::never : attotime::from_hz(m_ext_freq) / 2); + } + else switch (m_phase) + { + // First low output phase + case 0: + m_periodic_timer->adjust(clocks_to_attotime(divisor & ~2) / 2); + break; + + // First high output phase + case 1: + m_periodic_timer->adjust(clocks_to_attotime(divisor >> 1)); + break; + + // Second low output phase + case 2: + m_periodic_timer->adjust(clocks_to_attotime((divisor & ~2) >> 1 | (divisor & 1))); + break; + + // Second high output phase + case 3: + m_periodic_timer->adjust(clocks_to_attotime(divisor - ((divisor & 1) << 1)) / 2); + break; + } +} diff --git a/src/devices/machine/mm5307.h b/src/devices/machine/mm5307.h new file mode 100644 index 00000000000..d46124e89ee --- /dev/null +++ b/src/devices/machine/mm5307.h @@ -0,0 +1,99 @@ +// license:BSD-3-Clause +// copyright-holders:AJR +/*************************************************************************** + + National Semiconductor MM5307 Baud Rate Generator/Programmable Divider + +**************************************************************************** + ___ ___ + EXTERNAL FREQ 1 |* \__/ | 14 ϕOUT + NC 2 | | 13 RESET + OUTPUT 3 | | 12 Vgg + Vss 4 | MM5307 | 11 A + EXTERNAL CLOCK 5 | | 10 B + CRYSTAL 6 | | 9 C + CRYSTAL 7 |__________| 8 D + +***************************************************************************/ + +#ifndef MAME_MACHINE_MM5307_H +#define MAME_MACHINE_MM5307_H 1 + +#pragma once + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> mm5307_device + +class mm5307_device : public device_t +{ +public: + // configuration + void set_ext_freq(u32 freq) { m_ext_freq = freq; } + void set_ext_freq(const XTAL &freq) { m_ext_freq = freq.value(); } + auto output_cb() { return m_output_cb.bind(); } + + // frequency control + void control_w(u8 data); + +protected: + // base class constructor + mm5307_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, const std::array &divisors_x2); + + // device-specific overrides + virtual void device_resolve_objects() override; + virtual void device_start() override; + virtual void device_reset() override; + +private: + // timed update callback + TIMER_CALLBACK_MEMBER(periodic_update); + + // internal divisors + const std::array &m_divisors_x2; + + // callbacks + devcb_write_line m_output_cb; + + // external input frequency + u32 m_ext_freq; + + // internal state + u8 m_freq_control; + u8 m_phase; + + // timer + emu_timer *m_periodic_timer; +}; + +// ======================> mm5307aa_device + +class mm5307aa_device : public mm5307_device +{ +public: + // construction/destruction + mm5307aa_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); + +private: + static const std::array s_divisors_x2; +}; + +// ======================> mm5307ab_device + +class mm5307ab_device : public mm5307_device +{ +public: + // construction/destruction + mm5307ab_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); + +private: + static const std::array s_divisors_x2; +}; + +// device type declarations +DECLARE_DEVICE_TYPE(MM5307AA, mm5307aa_device) +DECLARE_DEVICE_TYPE(MM5307AB, mm5307ab_device) + +#endif // MAME_MACHINE_MM5307_H diff --git a/src/mame/drivers/poly88.cpp b/src/mame/drivers/poly88.cpp index f6df50ec578..180078aff0f 100644 --- a/src/mame/drivers/poly88.cpp +++ b/src/mame/drivers/poly88.cpp @@ -69,7 +69,7 @@ void poly88_state::poly88_io(address_map &map) { map.unmap_value_high(); map.global_mask(0xff); - map(0x00, 0x01).rw(m_uart, FUNC(i8251_device::read), FUNC(i8251_device::write)); + map(0x00, 0x01).rw(m_usart, FUNC(i8251_device::read), FUNC(i8251_device::write)); map(0x04, 0x04).w(FUNC(poly88_state::poly88_baud_rate_w)); map(0x08, 0x08).w(FUNC(poly88_state::poly88_intr_w)); map(0xf8, 0xf8).r(FUNC(poly88_state::poly88_keyboard_r)); @@ -201,7 +201,7 @@ GFXDECODE_END MACHINE_CONFIG_START(poly88_state::poly88) /* basic machine hardware */ - I8080A(config, m_maincpu, XTAL(16'588'800) / 9); // uses 8224 clock generator + I8080A(config, m_maincpu, 16.5888_MHz_XTAL / 9); // uses 8224 clock generator m_maincpu->set_addrmap(AS_PROGRAM, &poly88_state::poly88_mem); m_maincpu->set_addrmap(AS_IO, &poly88_state::poly88_io); m_maincpu->set_vblank_int("screen", FUNC(poly88_state::poly88_interrupt)); @@ -230,9 +230,12 @@ MACHINE_CONFIG_START(poly88_state::poly88) m_cassette->set_default_state(CASSETTE_STOPPED | CASSETTE_SPEAKER_ENABLED); /* uart */ - I8251(config, m_uart, XTAL(16'588'800) / 9); - m_uart->txd_handler().set(FUNC(poly88_state::write_cas_tx)); - m_uart->rxrdy_handler().set(FUNC(poly88_state::poly88_usart_rxready)); + I8251(config, m_usart, 16.5888_MHz_XTAL / 9); + m_usart->txd_handler().set(FUNC(poly88_state::write_cas_tx)); + m_usart->rxrdy_handler().set(FUNC(poly88_state::poly88_usart_rxready)); + + MM5307AA(config, m_brg, 16.5888_MHz_XTAL / 18); + m_brg->output_cb().set(FUNC(poly88_state::cassette_txc_rxc_w)); /* snapshot */ MCFG_SNAPSHOT_ADD("snapshot", poly88_state, poly88, "img", attotime::from_seconds(2)) diff --git a/src/mame/includes/poly88.h b/src/mame/includes/poly88.h index 22e8071d21f..29d39c049fa 100644 --- a/src/mame/includes/poly88.h +++ b/src/mame/includes/poly88.h @@ -11,6 +11,7 @@ #pragma once #include "machine/i8251.h" +#include "machine/mm5307.h" #include "imagedev/cassette.h" #include "imagedev/snapquik.h" @@ -20,15 +21,15 @@ public: enum { TIMER_USART, - TIMER_KEYBOARD, - TIMER_CASSETTE + TIMER_KEYBOARD }; poly88_state(const machine_config &mconfig, device_type type, const char *tag) : driver_device(mconfig, type, tag), m_video_ram(*this, "video_ram"), m_maincpu(*this, "maincpu"), - m_uart(*this, "uart"), + m_usart(*this, "usart"), + m_brg(*this, "brg"), m_cassette(*this, "cassette"), m_linec(*this, "LINEC"), m_line0(*this, "LINE0"), @@ -51,8 +52,8 @@ private: uint8_t m_intr; uint8_t m_last_code; uint8_t m_int_vector; - emu_timer * m_cassette_timer; emu_timer * m_usart_timer; + emu_timer * m_keyboard_timer; int m_previous_level; int m_clk_level; int m_clk_level_tape; @@ -65,7 +66,7 @@ private: INTERRUPT_GEN_MEMBER(poly88_interrupt); TIMER_CALLBACK_MEMBER(poly88_usart_timer_callback); TIMER_CALLBACK_MEMBER(keyboard_callback); - TIMER_CALLBACK_MEMBER(poly88_cassette_timer_callback); + DECLARE_WRITE_LINE_MEMBER(cassette_txc_rxc_w); DECLARE_WRITE_LINE_MEMBER(write_cas_tx); DECLARE_WRITE_LINE_MEMBER(poly88_usart_rxready); IRQ_CALLBACK_MEMBER(poly88_irq_callback); @@ -77,7 +78,8 @@ private: void poly88_mem(address_map &map); required_device m_maincpu; - required_device m_uart; + required_device m_usart; + required_device m_brg; required_device m_cassette; required_ioport m_linec; required_ioport m_line0; diff --git a/src/mame/machine/poly88.cpp b/src/mame/machine/poly88.cpp index 6b2b022a9d0..1d317a1182e 100644 --- a/src/mame/machine/poly88.cpp +++ b/src/mame/machine/poly88.cpp @@ -24,9 +24,6 @@ void poly88_state::device_timer(emu_timer &timer, device_timer_id id, int param, case TIMER_KEYBOARD: keyboard_callback(ptr, param); break; - case TIMER_CASSETTE: - poly88_cassette_timer_callback(ptr, param); - break; default: assert_always(false, "Unknown id in poly88_state::device_timer"); } @@ -42,9 +39,10 @@ TIMER_CALLBACK_MEMBER(poly88_state::poly88_usart_timer_callback) WRITE8_MEMBER(poly88_state::poly88_baud_rate_w) { logerror("poly88_baud_rate_w %02x\n",data); - m_usart_timer = timer_alloc(TIMER_USART); - m_usart_timer->adjust(attotime::zero, 0, attotime::from_hz(300)); + m_brg->control_w(data & 15); + // FIXME + m_usart_timer->adjust(attotime::zero, 0, attotime::from_hz(300)); } uint8_t poly88_state::row_number(uint8_t code) { @@ -149,8 +147,6 @@ TIMER_CALLBACK_MEMBER(poly88_state::keyboard_callback) } else { m_last_code = key_code; } - - timer_set(attotime::from_hz(24000), TIMER_KEYBOARD); } IRQ_CALLBACK_MEMBER(poly88_state::poly88_irq_callback) @@ -163,7 +159,7 @@ WRITE_LINE_MEMBER(poly88_state::write_cas_tx) m_cas_tx = state; } -TIMER_CALLBACK_MEMBER(poly88_state::poly88_cassette_timer_callback) +WRITE_LINE_MEMBER(poly88_state::cassette_txc_rxc_w) { int data; int current_level; @@ -186,13 +182,13 @@ TIMER_CALLBACK_MEMBER(poly88_state::poly88_cassette_timer_callback) { data = (!m_previous_level && current_level) ? 1 : 0; //data = current_level; - m_uart->write_rxd(data); + m_usart->write_rxd(data); m_clk_level_tape = 1; } } - m_uart->write_rxc(m_clk_level_tape); + m_usart->write_rxc(m_clk_level_tape); } /* tape writing */ @@ -203,15 +199,14 @@ TIMER_CALLBACK_MEMBER(poly88_state::poly88_cassette_timer_callback) m_cassette->output(data&0x01 ? 1 : -1); m_clk_level_tape = m_clk_level_tape ? 0 : 1; - m_uart->write_txc(m_clk_level_tape); + m_usart->write_txc(m_clk_level_tape); return; } m_clk_level_tape = 1; - m_clk_level = m_clk_level ? 0 : 1; - m_uart->write_txc(m_clk_level); + m_usart->write_txc(state); // } } @@ -219,17 +214,19 @@ TIMER_CALLBACK_MEMBER(poly88_state::poly88_cassette_timer_callback) void poly88_state::init_poly88() { m_previous_level = 0; - m_clk_level = m_clk_level_tape = 1; - m_cassette_timer = timer_alloc(TIMER_CASSETTE); - m_cassette_timer->adjust(attotime::zero, 0, attotime::from_hz(600)); + m_clk_level_tape = 1; - timer_set(attotime::from_hz(24000), TIMER_KEYBOARD); + m_usart_timer = timer_alloc(TIMER_USART); + m_keyboard_timer = timer_alloc(TIMER_KEYBOARD); + m_keyboard_timer->adjust(attotime::from_hz(24000), 0, attotime::from_hz(24000)); } void poly88_state::machine_reset() { m_intr = 0; m_last_code = 0; + + m_brg->control_w(0); } INTERRUPT_GEN_MEMBER(poly88_state::poly88_interrupt) @@ -327,6 +324,6 @@ SNAPSHOT_LOAD_MEMBER( poly88_state, poly88 ) } pos+=recordLen; } - m_uart->reset(); + m_usart->reset(); return image_init_result::PASS; } -- cgit v1.2.3