diff --git a/src/mame/sega/m1comm.cpp b/src/mame/sega/m1comm.cpp index 0b690e8d3e803..0a3f6f1e51e3a 100644 --- a/src/mame/sega/m1comm.cpp +++ b/src/mame/sega/m1comm.cpp @@ -6,6 +6,7 @@ Comm PCB -------- MODEL-1 COMMUNICATION BD 837-8842 171-6293B (C) SEGA 1992 +( http://images.arianchen.de/sega-comm/model1-front.jpg / http://images.arianchen.de/sega-comm/model1-back.jpg ) |--------------------------------------------------------------------------------| | | | MB89237A MB89374 | @@ -53,30 +54,410 @@ MODEL-1 COMMUNICATION BD 837-8842 171-6293B (C) SEGA 1992 #include "emu.h" #include "m1comm.h" + #include "emuopts.h" -#define Z80_TAG "commcpu" +#include "asio.h" + +#include + +#define VERBOSE 0 +#include "logmacro.h" + +#define Z80_TAG "commcpu" + +#ifdef M1COMM_SIMULATION +class sega_m1comm_device::context +{ +public: + context() : + m_acceptor(m_ioctx), + m_sock_rx(m_ioctx), + m_sock_tx(m_ioctx), + m_timeout_tx(m_ioctx), + m_state_rx(0U), + m_state_tx(0U) + { + } + + void start() + { + } + + void reset(std::string localhost, std::string localport, std::string remotehost, std::string remoteport) + { + std::error_code err; + if (m_acceptor.is_open()) + m_acceptor.close(err); + if (m_sock_rx.is_open()) + m_sock_rx.close(err); + if (m_sock_tx.is_open()) + m_sock_tx.close(err); + m_timeout_tx.cancel(); + m_state_rx.store(0); + m_state_tx.store(0); + + asio::ip::tcp::resolver resolver(m_ioctx); + + for (auto &&resolveIte : resolver.resolve(localhost, localport, asio::ip::tcp::resolver::flags::address_configured, err)) + { + m_localaddr = resolveIte.endpoint(); + LOG("M1COMM: localhost = %s\n", *m_localaddr); + } + if (err) + { + LOG("M1COMM: localhost resolve error: %s\n", err.message()); + } + + for (auto &&resolveIte : resolver.resolve(remotehost, remoteport, asio::ip::tcp::resolver::flags::address_configured, err)) + { + m_remoteaddr = resolveIte.endpoint(); + LOG("M1COMM: remotehost = %s\n", *m_remoteaddr); + } + if (err) + { + LOG("M1COMM: remotehost resolve error: %s\n", err.message()); + } + } + + void stop() + { + std::error_code err; + if (m_acceptor.is_open()) + m_acceptor.close(err); + if (m_sock_rx.is_open()) + m_sock_rx.close(err); + if (m_sock_tx.is_open()) + m_sock_tx.close(err); + m_timeout_tx.cancel(); + m_state_rx.store(0); + m_state_tx.store(0); + m_ioctx.stop(); + } + + void check_sockets() + { + // if async operation in progress, poll context + if ((m_state_rx > 0) || (m_state_tx > 0)) + m_ioctx.poll(); + + // start acceptor if needed + if (m_localaddr && m_state_rx.load() == 0) + { + start_accept(); + } + + // connect socket if needed + if (m_remoteaddr && m_state_tx.load() == 0) + { + start_connect(); + } + } + + bool connected() + { + return m_state_rx.load() == 2 && m_state_tx.load() == 2; + } + + unsigned receive(uint8_t *buffer, unsigned data_size) + { + if (m_state_rx.load() < 2) + return UINT_MAX; + + m_ioctx.poll(); + + if (data_size > m_fifo_rx.used()) + return 0; + + return m_fifo_rx.read(&buffer[0], data_size, false); + } + + unsigned send(uint8_t *buffer, unsigned data_size) + { + if (m_state_tx.load() < 2) + return UINT_MAX; + + if (data_size > m_fifo_tx.free()) + { + LOG("M1COMM: TX buffer overflow\n"); + return UINT_MAX; + } + + bool const sending = m_fifo_tx.used(); + m_fifo_tx.write(&buffer[0], data_size); + if (!sending) + start_send_tx(); + + m_ioctx.poll(); + + return data_size; + } + +private: + class fifo + { + public: + unsigned write(uint8_t *buffer, unsigned data_size) + { + unsigned used = 0; + if (m_wp >= m_rp) + { + used = std::min(m_buffer.size() - m_wp, data_size); + std::copy_n(&buffer[0], used, &m_buffer[m_wp]); + m_wp = (m_wp + used) % m_buffer.size(); + } + unsigned const block = std::min(data_size - used, m_rp - m_wp); + if (block) + { + std::copy_n(&buffer[used], block, &m_buffer[m_wp]); + used += block; + m_wp += block; + } + m_used += used; + return used; + } + + unsigned read(uint8_t *buffer, unsigned data_size, bool peek) + { + unsigned rp = m_rp; + unsigned used = 0; + if (rp >= m_wp) + { + used = std::min(m_buffer.size() - rp, data_size); + std::copy_n(&m_buffer[rp], used, &buffer[0]); + rp = (rp + used) % m_buffer.size(); + } + unsigned const block = std::min(data_size - used, m_wp - rp); + if (block) + { + std::copy_n(&m_buffer[rp], block, &buffer[used]); + used += block; + rp += block; + } + if (!peek) + { + m_rp = (m_rp + used) % m_buffer.size(); + m_used -= used; + } + return used; + } + + void consume(unsigned data_size) + { + m_rp = (m_rp + data_size) % m_buffer.size(); + m_used -= data_size; + } + + unsigned used() + { + return m_used; + } + + unsigned free() + { + return m_buffer.size() - m_used; + } + + void clear() + { + m_wp = m_rp = m_used = 0; + } + + + private: + unsigned m_wp = 0; + unsigned m_rp = 0; + unsigned m_used = 0; + std::array m_buffer; + }; + + void start_accept() + { + std::error_code err; + m_acceptor.open(m_localaddr->protocol(), err); + m_acceptor.set_option(asio::ip::tcp::acceptor::reuse_address(true)); + if (!err) + { + m_acceptor.bind(*m_localaddr, err); + if (!err) + { + m_acceptor.listen(1, err); + if (!err) + { + osd_printf_verbose("M1COMM: RX listen on %s\n", *m_localaddr); + m_acceptor.async_accept( + [this] (std::error_code const &err, asio::ip::tcp::socket sock) + { + if (err) + { + LOG("M1COMM: RX error accepting - %d %s\n", err.value(), err.message()); + std::error_code e; + m_acceptor.close(e); + m_state_rx.store(0); + } + else + { + LOG("M1COMM: RX connection from %s\n", sock.remote_endpoint()); + std::error_code e; + m_acceptor.close(e); + m_sock_rx = std::move(sock); + m_sock_rx.set_option(asio::socket_base::keep_alive(true)); + m_state_rx.store(2); + start_receive_rx(); + } + }); + m_state_rx.store(1); + } + } + } + if (err) + { + LOG("M1COMM: RX failed - %d %s\n", err.value(), err.message()); + } + } + + void start_connect() + { + std::error_code err; + if (m_sock_tx.is_open()) + m_sock_tx.close(err); + m_sock_tx.open(m_remoteaddr->protocol(), err); + if (!err) + { + m_sock_tx.set_option(asio::ip::tcp::no_delay(true)); + m_sock_tx.set_option(asio::socket_base::keep_alive(true)); + osd_printf_verbose("M1COMM: TX connecting to %s\n", *m_remoteaddr); + m_timeout_tx.expires_after(std::chrono::seconds(10)); + m_timeout_tx.async_wait( + [this] (std::error_code const &err) + { + if (!err && m_state_tx.load() == 1) + { + osd_printf_verbose("M1COMM: TX connect timed out\n"); + std::error_code e; + m_sock_tx.close(e); + m_state_tx.store(0); + } + }); + m_sock_tx.async_connect( + *m_remoteaddr, + [this] (std::error_code const &err) + { + m_timeout_tx.cancel(); + if (err) + { + osd_printf_verbose("M1COMM: TX connect error - %d %s\n", err.value(), err.message()); + std::error_code e; + m_sock_tx.close(e); + m_state_tx.store(0); + } + else + { + LOG("M1COMM: TX connection established\n"); + m_state_tx.store(2); + } + }); + m_state_tx.store(1); + } + } + + void start_send_tx() + { + unsigned used = m_fifo_tx.read(&m_buffer_tx[0], std::min(m_fifo_tx.used(), m_buffer_tx.size()), true); + m_sock_tx.async_write_some( + asio::buffer(&m_buffer_tx[0], used), + [this] (std::error_code const &err, std::size_t length) + { + m_fifo_tx.consume(length); + if (err) + { + LOG("M1COMM: TX connection error: %s\n", err.message().c_str()); + m_sock_tx.close(); + m_state_tx.store(0); + m_fifo_tx.clear(); + } + else if (m_fifo_tx.used()) + { + start_send_tx(); + } + }); + } + + void start_receive_rx() + { + m_sock_rx.async_read_some( + asio::buffer(m_buffer_rx), + [this] (std::error_code const &err, std::size_t length) + { + if (err || !length) + { + if (err) + LOG("M1COMM: RX connection error: %s\n", err.message()); + else + LOG("M1COMM: RX connection lost\n"); + m_sock_rx.close(); + m_state_rx.store(0); + m_fifo_rx.clear(); + } + else + { + if (UINT_MAX == m_fifo_rx.write(&m_buffer_rx[0], length)) + { + LOG("M1COMM: RX buffer overflow\n"); + m_sock_rx.close(); + m_state_rx.store(0); + m_fifo_rx.clear(); + } + start_receive_rx(); + } + }); + } + + template + void logerror(Format &&fmt, Params &&... args) const + { + util::stream_format( + std::cerr, + "%s", + util::string_format(std::forward(fmt), std::forward(args)...)); + } + + asio::io_context m_ioctx; + std::optional m_localaddr; + std::optional m_remoteaddr; + asio::ip::tcp::acceptor m_acceptor; + asio::ip::tcp::socket m_sock_rx; + asio::ip::tcp::socket m_sock_tx; + asio::steady_timer m_timeout_tx; + std::atomic_uint m_state_rx; + std::atomic_uint m_state_tx; + fifo m_fifo_rx; + fifo m_fifo_tx; + std::array m_buffer_rx; + std::array m_buffer_tx; +}; +#endif /************************************* * M1COMM Memory Map *************************************/ -void m1comm_device::m1comm_mem(address_map &map) +void sega_m1comm_device::m1comm_mem(address_map &map) { map(0x0000, 0x7fff).rom(); map(0x8000, 0x9fff).ram(); - map(0xc000, 0xffff).mask(0x0fff).rw(FUNC(m1comm_device::share_r), FUNC(m1comm_device::share_w)); + map(0xc000, 0xffff).mask(0x0fff).rw(FUNC(sega_m1comm_device::share_r), FUNC(sega_m1comm_device::share_w)); } /************************************* * M1COMM I/O Map *************************************/ -void m1comm_device::m1comm_io(address_map &map) +void sega_m1comm_device::m1comm_io(address_map &map) { map.global_mask(0x7f); map(0x00, 0x1f).rw(m_dlc, FUNC(mb89374_device::read), FUNC(mb89374_device::write)); map(0x20, 0x2f).rw(m_dma, FUNC(am9517a_device::read), FUNC(am9517a_device::write)); - map(0x40, 0x5f).mask(0x01).rw(FUNC(m1comm_device::syn_r), FUNC(m1comm_device::syn_w)); - map(0x60, 0x7f).mask(0x01).rw(FUNC(m1comm_device::zfg_r), FUNC(m1comm_device::zfg_w)); + map(0x40, 0x5f).mask(0x01).rw(FUNC(sega_m1comm_device::syn_r), FUNC(sega_m1comm_device::syn_w)); + map(0x60, 0x7f).mask(0x01).rw(FUNC(sega_m1comm_device::zfg_r), FUNC(sega_m1comm_device::zfg_w)); } ROM_START( m1comm ) @@ -96,38 +477,38 @@ ROM_END // GLOBAL VARIABLES //************************************************************************** -DEFINE_DEVICE_TYPE(M1COMM, m1comm_device, "m1comm", "Model-1 Communication Board") +DEFINE_DEVICE_TYPE(SEGA_MODEL1_COMM, sega_m1comm_device, "m1comm", "Sega Model-1 Communication Board") //------------------------------------------------- // device_add_mconfig - add device configuration //------------------------------------------------- -void m1comm_device::device_add_mconfig(machine_config &config) +void sega_m1comm_device::device_add_mconfig(machine_config &config) { - Z80(config, m_cpu, 8000000); // 32 MHz / 4 - m_cpu->set_memory_map(&m1comm_device::m1comm_mem); - m_cpu->set_io_map(&m1comm_device::m1comm_io); - - AM9517A(config, m_dma, 8000000); // 32 MHz / 4 - m_dma->out_hreq_callback().set(FUNC(m1comm_device::dma_hreq_w)); - m_dma->in_memr_callback().set(FUNC(m1comm_device::dma_mem_r)); - m_dma->out_memw_callback().set(FUNC(m1comm_device::dma_mem_w)); + Z80(config, m_cpu, 32_MHz_XTAL / 4); + m_cpu->set_memory_map(&sega_m1comm_device::m1comm_mem); + m_cpu->set_io_map(&sega_m1comm_device::m1comm_io); + + AM9517A(config, m_dma, 32_MHz_XTAL / 4); + m_dma->out_hreq_callback().set(FUNC(sega_m1comm_device::dma_hreq_w)); + m_dma->in_memr_callback().set(FUNC(sega_m1comm_device::dma_mem_r)); + m_dma->out_memw_callback().set(FUNC(sega_m1comm_device::dma_mem_w)); m_dma->out_dack_callback<2>().set(m_dlc, FUNC(mb89374_device::pi3_w)); m_dma->out_dack_callback<3>().set(m_dlc, FUNC(mb89374_device::pi2_w)); m_dma->out_eop_callback().set(m_dlc, FUNC(mb89374_device::ci_w)); m_dma->in_ior_callback<2>().set(m_dlc, FUNC(mb89374_device::dma_r)); m_dma->out_iow_callback<3>().set(m_dlc, FUNC(mb89374_device::dma_w)); - MB89374(config, m_dlc, 8000000); // 32 MHz / 4 + MB89374(config, m_dlc, 32_MHz_XTAL / 4); m_dlc->out_po_callback<2>().set(m_dma, FUNC(am9517a_device::dreq3_w)); m_dlc->out_po_callback<3>().set(m_dma, FUNC(am9517a_device::dreq2_w)); - m_dlc->out_irq_callback().set(FUNC(m1comm_device::dlc_int7_w)); + m_dlc->out_irq_callback().set(FUNC(sega_m1comm_device::dlc_int7_w)); } //------------------------------------------------- // rom_region - device-specific ROM region //------------------------------------------------- -const tiny_rom_entry *m1comm_device::device_rom_region() const +const tiny_rom_entry *sega_m1comm_device::device_rom_region() const { return ROM_NAME( m1comm ); } @@ -137,30 +518,16 @@ const tiny_rom_entry *m1comm_device::device_rom_region() const //************************************************************************** //------------------------------------------------- -// m1comm_device - constructor +// sega_m1comm_device - constructor //------------------------------------------------- -m1comm_device::m1comm_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : - device_t(mconfig, M1COMM, tag, owner, clock), +sega_m1comm_device::sega_m1comm_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : + device_t(mconfig, SEGA_MODEL1_COMM, tag, owner, clock), m_cpu(*this, Z80_TAG), m_dma(*this, "commdma"), m_dlc(*this, "commdlc") { #ifdef M1COMM_SIMULATION - // prepare localhost "filename" - m_localhost[0] = 0; - strcat(m_localhost, "socket."); - strcat(m_localhost, mconfig.options().comm_localhost()); - strcat(m_localhost, ":"); - strcat(m_localhost, mconfig.options().comm_localport()); - - // prepare remotehost "filename" - m_remotehost[0] = 0; - strcat(m_remotehost, "socket."); - strcat(m_remotehost, mconfig.options().comm_remotehost()); - strcat(m_remotehost, ":"); - strcat(m_remotehost, mconfig.options().comm_remoteport()); - m_framesync = mconfig.options().comm_framesync() ? 0x01 : 0x00; #endif } @@ -169,86 +536,112 @@ m1comm_device::m1comm_device(const machine_config &mconfig, const char *tag, dev // device_start - device-specific startup //------------------------------------------------- -void m1comm_device::device_start() +void sega_m1comm_device::device_start() { +#ifdef M1COMM_SIMULATION + auto ctx = std::make_unique(); + m_context = std::move(ctx); + m_context->start(); +#endif } //------------------------------------------------- // device_reset - device-specific reset //------------------------------------------------- -void m1comm_device::device_reset() +void sega_m1comm_device::device_reset() { + std::fill(std::begin(m_shared), std::end(m_shared), 0); m_syn = 0; m_zfg = 0; m_cn = 0; m_fg = 0; +#ifdef M1COMM_SIMULATION + std::fill(std::begin(m_buffer), std::end(m_buffer), 0); + + auto const &opts = mconfig().options(); + m_context->reset(opts.comm_localhost(), opts.comm_localport(), opts.comm_remotehost(), opts.comm_remoteport()); + + m_linkenable = 0; + m_linktimer = 0; + m_linkalive = 0; + m_linkid = 0; + m_linkcount = 0; +#endif +} + +void sega_m1comm_device::device_stop() +{ +#ifdef M1COMM_SIMULATION + m_context->stop(); + m_context.reset(); +#endif } -void m1comm_device::device_reset_after_children() +void sega_m1comm_device::device_reset_after_children() { m_cpu->set_input_line(INPUT_LINE_RESET, ASSERT_LINE); m_dma->set_input_line(INPUT_LINE_RESET, ASSERT_LINE); m_dlc->set_input_line(INPUT_LINE_RESET, ASSERT_LINE); } -void m1comm_device::dma_hreq_w(int state) +void sega_m1comm_device::dma_hreq_w(int state) { m_cpu->set_input_line(INPUT_LINE_HALT, state ? ASSERT_LINE : CLEAR_LINE); m_dma->hack_w(state); } -uint8_t m1comm_device::dma_mem_r(offs_t offset) +uint8_t sega_m1comm_device::dma_mem_r(offs_t offset) { return m_cpu->space(AS_PROGRAM).read_byte(offset); } -void m1comm_device::dma_mem_w(offs_t offset, uint8_t data) +void sega_m1comm_device::dma_mem_w(offs_t offset, uint8_t data) { m_cpu->space(AS_PROGRAM).write_byte(offset, data); } -void m1comm_device::dlc_int7_w(int state) +void sega_m1comm_device::dlc_int7_w(int state) { m_cpu->set_input_line_and_vector(0, state ? ASSERT_LINE : CLEAR_LINE, 0xff); // Z80 } -uint8_t m1comm_device::syn_r() +uint8_t sega_m1comm_device::syn_r() { return m_syn | 0xfc; } -void m1comm_device::syn_w(uint8_t data) +void sega_m1comm_device::syn_w(uint8_t data) { m_syn = data & 0x03; } -uint8_t m1comm_device::zfg_r() +uint8_t sega_m1comm_device::zfg_r() { return m_zfg | (~m_fg << 7) | 0x7e; } -void m1comm_device::zfg_w(uint8_t data) +void sega_m1comm_device::zfg_w(uint8_t data) { m_zfg = data & 0x01; } -uint8_t m1comm_device::share_r(offs_t offset) +uint8_t sega_m1comm_device::share_r(offs_t offset) { return m_shared[offset]; } -void m1comm_device::share_w(offs_t offset, uint8_t data) +void sega_m1comm_device::share_w(offs_t offset, uint8_t data) { m_shared[offset] = data; } -uint8_t m1comm_device::cn_r() +uint8_t sega_m1comm_device::cn_r() { return m_cn | 0xfe; } -void m1comm_device::cn_w(uint8_t data) +void sega_m1comm_device::cn_w(uint8_t data) { m_cn = data & 0x01; @@ -285,12 +678,12 @@ void m1comm_device::cn_w(uint8_t data) #endif } -uint8_t m1comm_device::fg_r() +uint8_t sega_m1comm_device::fg_r() { return m_fg | (~m_zfg << 7) | 0x7e; } -void m1comm_device::fg_w(uint8_t data) +void sega_m1comm_device::fg_w(uint8_t data) { if (!m_cn) return; @@ -298,7 +691,7 @@ void m1comm_device::fg_w(uint8_t data) m_fg = data & 0x01; } -void m1comm_device::check_vint_irq() +void sega_m1comm_device::check_vint_irq() { #ifndef M1COMM_SIMULATION if (m_syn & 0x02) @@ -311,20 +704,18 @@ void m1comm_device::check_vint_irq() } #ifdef M1COMM_SIMULATION -void m1comm_device::comm_tick() +void sega_m1comm_device::comm_tick() { + m_context->check_sockets(); + if (m_linkenable == 0x01) { - int frameStart = 0x0010; - int frameOffset = 0x0000; - int frameSize = 0x01c4; - int dataSize = frameSize + 1; - int recv = 0; - int idx = 0; + unsigned frame_size = 0x01c4; + unsigned data_size = frame_size + 1; - bool isMaster = (m_shared[1] == 0x01); - bool isSlave = (m_shared[1] == 0x02); - bool isRelay = (m_shared[1] == 0x00); + bool is_master = (m_shared[1] == 0x01); + bool is_slave = (m_shared[1] == 0x02); + bool is_relay = (m_shared[1] == 0x00); if (m_linkalive == 0x02) { @@ -337,69 +728,53 @@ void m1comm_device::comm_tick() // link not yet established... m_shared[0] = 0x05; - // check rx socket - if (!m_line_rx) - { - osd_printf_verbose("M1COMM: listen on %s\n", m_localhost); - uint64_t filesize; // unused - osd_file::open(m_localhost, OPEN_FLAG_CREATE, m_line_rx, filesize); - } - - // check tx socket - if (!m_line_tx) - { - osd_printf_verbose("M1COMM: connect to %s\n", m_remotehost); - uint64_t filesize; // unused - osd_file::open(m_remotehost, 0, m_line_tx, filesize); - } - // if both sockets are there check ring - if (m_line_rx && m_line_tx) + if (m_context->connected()) { // try to read one message - recv = read_frame(dataSize); + unsigned recv = read_frame(data_size); while (recv > 0) { // check message id - idx = m_buffer0[0]; + uint8_t idx = m_buffer[0]; // 0xFF - link id if (idx == 0xff) { - if (isMaster) + if (is_master) { // master gets first id and starts next state m_linkid = 0x01; - m_linkcount = m_buffer0[1]; + m_linkcount = m_buffer[1]; m_linktimer = 0x00; } else { // slave get own id, relay does nothing - if (isSlave) + if (is_slave) { - m_buffer0[1]++; - m_linkid = m_buffer0[1]; + m_buffer[1]++; + m_linkid = m_buffer[1]; } // forward message to other nodes - send_frame(dataSize); + send_frame(data_size); } } // 0xFE - link size else if (idx == 0xfe) { - if (isSlave || isRelay) + if (is_slave || is_relay) { - m_linkcount = m_buffer0[1]; + m_linkcount = m_buffer[1]; // forward message to other nodes - send_frame(dataSize); + send_frame(data_size); } // consider it done - osd_printf_verbose("M1COMM: link established - id %02x of %02x\n", m_linkid, m_linkcount); + LOG("M1COMM: link established - id %02x of %02x\n", m_linkid, m_linkcount); m_linkalive = 0x01; m_zfg = 0x01; @@ -409,33 +784,32 @@ void m1comm_device::comm_tick() m_shared[3] = m_linkcount; } - if (m_linkalive == 0x00) - recv = read_frame(dataSize); + recv = read_frame(data_size); else recv = 0; } // if we are master and link is not yet established - if (isMaster && (m_linkalive == 0x00)) + if (is_master && (m_linkalive == 0x00)) { // send first packet if (m_linktimer == 0x01) { - m_buffer0[0] = 0xff; - m_buffer0[1] = 0x01; - send_frame(dataSize); + m_buffer[0] = 0xff; + m_buffer[1] = 0x01; + send_frame(data_size); } // send second packet else if (m_linktimer == 0x00) { - m_buffer0[0] = 0xfe; - m_buffer0[1] = m_linkcount; - send_frame(dataSize); + m_buffer[0] = 0xfe; + m_buffer[1] = m_linkcount; + send_frame(data_size); // consider it done - osd_printf_verbose("M1COMM: link established - id %02x of %02x\n", m_linkid, m_linkcount); + LOG("M1COMM: link established - id %02x of %02x\n", m_linkid, m_linkcount); m_linkalive = 0x01; m_zfg = 0x01; @@ -457,28 +831,26 @@ void m1comm_device::comm_tick() if (m_linkalive == 0x01) { // link established + unsigned frame_start = 0x0010; + do { // try to read a message - recv = read_frame(dataSize); + unsigned recv = read_frame(data_size); while (recv > 0) { // check if valid id - idx = m_buffer0[0]; + uint8_t idx = m_buffer[0]; if (idx > 0 && idx <= m_linkcount) { // if not own message if (idx != m_linkid) { // save message to "ring buffer" - frameOffset = frameStart + (idx * frameSize); - for (int j = 0x00 ; j < frameSize ; j++) - { - m_shared[frameOffset + j] = m_buffer0[1 + j]; - } + std::copy_n(&m_buffer[1], frame_size, &m_shared[frame_start + (idx * frame_size)]); // forward message to other nodes - send_frame(dataSize); + send_frame(data_size); } } else @@ -487,30 +859,26 @@ void m1comm_device::comm_tick() { // 0xFC - VSYNC m_linktimer = 0x00; - if (!isMaster) + if (!is_master) // forward message to other nodes - send_frame(dataSize); + send_frame(data_size); } if (idx == 0xfd) { // 0xFD - master addional bytes - if (!isMaster) + if (!is_master) { // save message to "ring buffer" - frameOffset = 0x06; - for (int j = 0x00 ; j < 0x0a ; j++) - { - m_shared[frameOffset + j] = m_buffer0[1 + j]; - } + std::copy_n(&m_buffer[1], 0x0a, &m_shared[0x06]); // forward message to other nodes - send_frame(dataSize); + send_frame(data_size); } } } // try to read another message - recv = read_frame(dataSize); + recv = read_frame(data_size); } } while (m_linktimer == 0x01); @@ -525,25 +893,21 @@ void m1comm_device::comm_tick() // check ready-to-send flag if (m_shared[4] != 0x00) { - send_data(m_linkid, frameStart, frameSize, dataSize); + send_data(m_linkid, frame_start, frame_size, data_size); // save message to "ring buffer" - frameOffset = frameStart + (m_linkid * frameSize); - for (int j = 0x00 ; j < frameSize ; j++) - { - m_shared[frameOffset + j] = m_buffer0[1 + j]; - } + std::copy_n(&m_buffer[1], frame_size, &m_shared[frame_start + (m_linkid * frame_size)]); } - if (isMaster) + if (is_master) { // master sends additional status bytes - send_data(0xfd, 0x06, 0x0a, dataSize); + send_data(0xfd, 0x06, 0x0a, data_size); // send vsync - m_buffer0[0] = 0xfc; - m_buffer0[1] = 0x01; - send_frame(dataSize); + m_buffer[0] = 0xfc; + m_buffer[1] = 0x01; + send_frame(data_size); } } @@ -553,88 +917,39 @@ void m1comm_device::comm_tick() } } -int m1comm_device::read_frame(int dataSize) +unsigned sega_m1comm_device::read_frame(unsigned data_size) { - if (!m_line_rx) - return 0; - - // try to read a message - std::uint32_t recv = 0; - std::error_condition filerr = m_line_rx->read(m_buffer0, 0, dataSize, recv); - if (recv > 0) - { - // check if message complete - if (recv != dataSize) - { - // only part of a message - read on - std::uint32_t togo = dataSize - recv; - int offset = recv; - while (togo > 0) - { - filerr = m_line_rx->read(m_buffer1, 0, togo, recv); - if (recv > 0) - { - for (int i = 0 ; i < recv ; i++) - { - m_buffer0[offset + i] = m_buffer1[i]; - } - togo -= recv; - offset += recv; - } - else if (!filerr && recv == 0) - { - togo = 0; - } - } - } - } - else if (!filerr && recv == 0) + unsigned bytes_read = m_context->receive(&m_buffer[0], data_size); + if (bytes_read == UINT_MAX) { if (m_linkalive == 0x01) { - osd_printf_verbose("M1COMM: rx connection lost\n"); + LOG("M1COMM: link lost\n"); m_linkalive = 0x02; m_linktimer = 0x00; - - m_shared[0] = 0xff; - - m_line_rx.reset(); - m_line_tx.reset(); } + return 0; } - return recv; + return bytes_read; } -void m1comm_device::send_data(uint8_t frameType, int frameStart, int frameSize, int dataSize) +void sega_m1comm_device::send_data(uint8_t frame_type, unsigned frame_start, unsigned frame_size, unsigned data_size) { - m_buffer0[0] = frameType; - for (int i = 0x00 ; i < frameSize ; i++) - { - m_buffer0[1 + i] = m_shared[frameStart + i]; - } - send_frame(dataSize); + m_buffer[0] = frame_type; + std::copy_n(&m_shared[frame_start], frame_size, &m_buffer[1]); + send_frame(data_size); } -void m1comm_device::send_frame(int dataSize){ - if (!m_line_tx) - return; - - std::error_condition filerr; - std::uint32_t written; - - filerr = m_line_tx->write(&m_buffer0, 0, dataSize, written); - if (filerr) +void sega_m1comm_device::send_frame(unsigned data_size) +{ + unsigned bytes_sent = m_context->send(&m_buffer[0], data_size); + if (bytes_sent == UINT_MAX) { if (m_linkalive == 0x01) { - osd_printf_verbose("M1COMM: tx connection lost\n"); + LOG("M1COMM: link lost\n"); m_linkalive = 0x02; m_linktimer = 0x00; - - m_shared[0] = 0xff; - - m_line_rx.reset(); - m_line_tx.reset(); } } } diff --git a/src/mame/sega/m1comm.h b/src/mame/sega/m1comm.h index a0ee2fdd831e6..c113cd47a8bd3 100644 --- a/src/mame/sega/m1comm.h +++ b/src/mame/sega/m1comm.h @@ -7,7 +7,6 @@ #define M1COMM_SIMULATION -#include "osdfile.h" #include "cpu/z80/z80.h" #include "machine/am9517a.h" #include "machine/mb89374.h" @@ -16,12 +15,10 @@ //************************************************************************** // TYPE DEFINITIONS //************************************************************************** - -class m1comm_device : public device_t +class sega_m1comm_device : public device_t { public: - // construction/destruction - m1comm_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + sega_m1comm_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); // public API - stuff that gets called from the model1 // shared memory 4k @@ -40,18 +37,14 @@ class m1comm_device : public device_t // IRQ logic - 5 = VINT, 7 = DLC void check_vint_irq(); - - void m1comm_io(address_map &map) ATTR_COLD; - void m1comm_mem(address_map &map) ATTR_COLD; protected: - // device-level overrides virtual void device_start() override ATTR_COLD; + virtual void device_stop() override ATTR_COLD; virtual void device_reset() override ATTR_COLD; virtual void device_reset_after_children() override; virtual const tiny_rom_entry *device_rom_region() const override ATTR_COLD; - // optional information overrides virtual void device_add_mconfig(machine_config &config) override ATTR_COLD; private: @@ -59,6 +52,9 @@ class m1comm_device : public device_t required_device m_dma; required_device m_dlc; + void m1comm_io(address_map &map) ATTR_COLD; + void m1comm_mem(address_map &map) ATTR_COLD; + // MB89374 handler void dlc_int7_w(int state); @@ -78,35 +74,33 @@ class m1comm_device : public device_t // - share_r // - share_w - uint8_t m_shared[0x1000]{}; // 2x 2k = 4k; model1 accesses this with 16bit data and 11bit address (A0 to A10) - uint8_t m_syn = 0; // bit0 is used to trigger DOP line on VINT, bit1 is used to enable/disable VINT/IRQ5 - uint8_t m_zfg = 0; // z80 flip gate, bit0 is stored - uint8_t m_cn = 0; // bit0 is used to enable/disable the comm board - uint8_t m_fg = 0; // flip gate, bit0 is stored, bit7 is connected to ZFG bit 0 + uint8_t m_shared[0x1000]; // 2x 2k = 4k; model1 accesses this with 16bit data and 11bit address (A0 to A10) + uint8_t m_syn; // bit0 is used to trigger DOP line on VINT, bit1 is used to enable/disable VINT/IRQ5 + uint8_t m_zfg; // z80 flip gate, bit0 is stored + uint8_t m_cn; // bit0 is used to enable/disable the comm board + uint8_t m_fg; // flip gate, bit0 is stored, bit7 is connected to ZFG bit 0 #ifdef M1COMM_SIMULATION - osd_file::ptr m_line_rx; // rx line - can be either differential, simple serial or toslink - osd_file::ptr m_line_tx; // tx line - is differential, simple serial and toslink - char m_localhost[256]{}; - char m_remotehost[256]{}; - uint8_t m_buffer0[0x200]{}; - uint8_t m_buffer1[0x200]{}; + class context; + std::unique_ptr m_context; + + uint8_t m_buffer[0x200]; uint8_t m_framesync; - uint8_t m_linkenable = 0; - uint16_t m_linktimer = 0; - uint8_t m_linkalive = 0; - uint8_t m_linkid = 0; - uint8_t m_linkcount = 0; + uint8_t m_linkenable; + uint16_t m_linktimer; + uint8_t m_linkalive; + uint8_t m_linkid; + uint8_t m_linkcount; void comm_tick(); - int read_frame(int dataSize); - void send_data(uint8_t frameType, int frameStart, int frameSize, int dataSize); - void send_frame(int dataSize); + unsigned read_frame(unsigned data_size); + void send_data(uint8_t frame_type, unsigned frame_start, unsigned frame_size, unsigned data_size); + void send_frame(unsigned data_size); #endif }; // device type definition -DECLARE_DEVICE_TYPE(M1COMM, m1comm_device) +DECLARE_DEVICE_TYPE(SEGA_MODEL1_COMM, sega_m1comm_device) #endif // MAME_SEGA_M1COMM_H diff --git a/src/mame/sega/model1.cpp b/src/mame/sega/model1.cpp index 308982c50be6c..90f6a2c307039 100644 --- a/src/mame/sega/model1.cpp +++ b/src/mame/sega/model1.cpp @@ -946,9 +946,9 @@ void model1_state::model1_comm_mem(address_map &map) { model1_mem(map); - map(0xb00000, 0xb00fff).rw(m_m1comm, FUNC(m1comm_device::share_r), FUNC(m1comm_device::share_w)); - map(0xb01000, 0xb01000).rw(m_m1comm, FUNC(m1comm_device::cn_r), FUNC(m1comm_device::cn_w)); - map(0xb01002, 0xb01002).rw(m_m1comm, FUNC(m1comm_device::fg_r), FUNC(m1comm_device::fg_w)); + map(0xb00000, 0xb00fff).rw(m_m1comm, FUNC(sega_m1comm_device::share_r), FUNC(sega_m1comm_device::share_w)); + map(0xb01000, 0xb01000).rw(m_m1comm, FUNC(sega_m1comm_device::cn_r), FUNC(sega_m1comm_device::cn_w)); + map(0xb01002, 0xb01002).rw(m_m1comm, FUNC(sega_m1comm_device::fg_r), FUNC(sega_m1comm_device::fg_w)); } static INPUT_PORTS_START( ioboard_dipswitches ) @@ -1784,7 +1784,7 @@ void model1_state::vr(machine_config &config) ioboard.output_callback().set(FUNC(model1_state::vr_outputs_w)); ioboard.output_callback().append(FUNC(model1_state::gen_outputs_w)); - M1COMM(config, "m1comm", 0).set_default_bios_tag("epr15112"); + SEGA_MODEL1_COMM(config, m_m1comm, 0U).set_default_bios_tag("epr15112"); } void model1_state::vformula(machine_config &config) @@ -1801,7 +1801,7 @@ void model1_state::vformula(machine_config &config) ioboard.output_callback().set(FUNC(model1_state::vr_outputs_w)); ioboard.output_callback().append(FUNC(model1_state::gen_outputs_w)); - M1COMM(config, "m1comm", 0).set_default_bios_tag("epr15624"); + SEGA_MODEL1_COMM(config, m_m1comm, 0U).set_default_bios_tag("epr15624"); } void model1_state::swa(machine_config &config) @@ -1848,7 +1848,7 @@ void model1_state::wingwar(machine_config &config) config.set_default_layout(layout_model1io2); - M1COMM(config, "m1comm", 0).set_default_bios_tag("epr15112"); + SEGA_MODEL1_COMM(config, m_m1comm, 0U).set_default_bios_tag("epr15112"); } void model1_state::wingwar360(machine_config &config) diff --git a/src/mame/sega/model1.h b/src/mame/sega/model1.h index cfaa1b0d664cb..7902991119cd6 100644 --- a/src/mame/sega/model1.h +++ b/src/mame/sega/model1.h @@ -218,7 +218,7 @@ class model1_state : public driver_device required_device m_dpram; required_device m_m1audio; // Model 1 standard sound board required_device m_m1uart; - optional_device m_m1comm; // Model 1 communication board + optional_device m_m1comm; // Model 1 communication board optional_device m_dsbz80; // Digital Sound Board optional_device m_tgp_copro; required_device m_screen;