From 07b19fb3ed81878caad600ff6a52bd2668b06004 Mon Sep 17 00:00:00 2001 From: Brian Johnson Date: Mon, 23 Jan 2023 11:08:37 -0500 Subject: misc/nabupc.cpp, bus/nabupc: Added support for NABU PC and simulated host. (#10676) New working systems ------------------- NABU PC --- scripts/src/bus.lua | 28 ++ src/devices/bus/nabupc/adapter.cpp | 422 +++++++++++++++++++ src/devices/bus/nabupc/adapter.h | 153 +++++++ src/devices/bus/nabupc/fdc.cpp | 122 ++++++ src/devices/bus/nabupc/fdc.h | 54 +++ src/devices/bus/nabupc/keyboard/hlekeyboard.cpp | 372 +++++++++++++++++ src/devices/bus/nabupc/keyboard/hlekeyboard.h | 19 + src/devices/bus/nabupc/keyboard/keyboard.cpp | 147 +++++++ src/devices/bus/nabupc/keyboard/keyboard.h | 19 + src/devices/bus/nabupc/option.cpp | 132 ++++++ src/devices/bus/nabupc/option.h | 156 +++++++ src/devices/bus/rs232/rs232.h | 5 +- src/mame/layout/nabupc.lay | 90 ++++ src/mame/mame.lst | 3 + src/mame/mess.flt | 1 + src/mame/misc/nabupc.cpp | 531 ++++++++++++++++++++++++ 16 files changed, 2253 insertions(+), 1 deletion(-) create mode 100644 src/devices/bus/nabupc/adapter.cpp create mode 100644 src/devices/bus/nabupc/adapter.h create mode 100644 src/devices/bus/nabupc/fdc.cpp create mode 100644 src/devices/bus/nabupc/fdc.h create mode 100644 src/devices/bus/nabupc/keyboard/hlekeyboard.cpp create mode 100644 src/devices/bus/nabupc/keyboard/hlekeyboard.h create mode 100644 src/devices/bus/nabupc/keyboard/keyboard.cpp create mode 100644 src/devices/bus/nabupc/keyboard/keyboard.h create mode 100644 src/devices/bus/nabupc/option.cpp create mode 100644 src/devices/bus/nabupc/option.h create mode 100644 src/mame/layout/nabupc.lay create mode 100644 src/mame/misc/nabupc.cpp diff --git a/scripts/src/bus.lua b/scripts/src/bus.lua index a24282c4f4d..e2b5e559a63 100644 --- a/scripts/src/bus.lua +++ b/scripts/src/bus.lua @@ -5144,3 +5144,31 @@ if (BUSES["MTU130"]~=null) then } end +--------------------------------------------------- +-- +--@src/devices/bus/nabupc/option.h,BUSES["NABU"] = true +--------------------------------------------------- +if (BUSES["NABU"]~=null) then + files { + MAME_DIR .. "src/devices/bus/nabupc/adapter.cpp", + MAME_DIR .. "src/devices/bus/nabupc/adapter.h", + MAME_DIR .. "src/devices/bus/nabupc/fdc.cpp", + MAME_DIR .. "src/devices/bus/nabupc/fdc.h", + MAME_DIR .. "src/devices/bus/nabupc/option.cpp", + MAME_DIR .. "src/devices/bus/nabupc/option.h", + } +end + +--------------------------------------------------- +-- +--@src/devices/bus/nabupc/keyboard/keyboard.h,BUSES["NABU_KEYBOARD"] = true +--------------------------------------------------- + +if (BUSES["NABU_KEYBOARD"]~=null) then + files { + MAME_DIR .. "src/devices/bus/nabupc/keyboard/hlekeyboard.cpp", + MAME_DIR .. "src/devices/bus/nabupc/keyboard/hlekeyboard.h", + MAME_DIR .. "src/devices/bus/nabupc/keyboard/keyboard.cpp", + MAME_DIR .. "src/devices/bus/nabupc/keyboard/keyboard.h", + } +end diff --git a/src/devices/bus/nabupc/adapter.cpp b/src/devices/bus/nabupc/adapter.cpp new file mode 100644 index 00000000000..07eda4f1b83 --- /dev/null +++ b/src/devices/bus/nabupc/adapter.cpp @@ -0,0 +1,422 @@ +// license:BSD-3-Clause +// copyright-holders:Brian Johnson +/******************************************************************* + * + * NABU PC - Network Adapter Settop Box + * + *******************************************************************/ + +#include "emu.h" +#include "adapter.h" + +#include "emuopts.h" +#include "unzip.h" + +#define VERBOSE 0 +#include "logmacro.h" + + +//************************************************************************** +// NABU PC NETWORK ADAPTER DEVICE +//************************************************************************** + +DEFINE_DEVICE_TYPE(NABUPC_NETWORK_ADAPTER, bus::nabupc::network_adapter, "nabu_net_adapter", "NABU Network Adapter") + +namespace bus::nabupc { + +//************************************************************************** +// SEGMENT FILE LOADING +//************************************************************************** + +// Load segment file from disk +std::error_condition network_adapter::segment_file::read_archive(util::core_file &stream, uint32_t segment_id) +{ + segment_id &= 0xffffff; + + util::core_file::ptr proxy; + std::error_condition err = util::core_file::open_proxy(stream, proxy); + if (err) + return err; + + util::archive_file::ptr zipfile; + err = util::archive_file::open_zip(std::move(proxy), zipfile); + if (err) + return err; + + std::string segment_filename = util::string_format("%06d.nabu", segment_id); + + if (zipfile->search(segment_filename, false) < 0) + return std::errc::no_such_file_or_directory; + + // determine the uncompressed length + uint64_t uncompressed_length_uint64 = zipfile->current_uncompressed_length(); + size_t uncompressed_length = (size_t)uncompressed_length_uint64; + if (uncompressed_length != uncompressed_length_uint64) + return std::errc::not_enough_memory; + + // prepare a buffer for the segment file + std::unique_ptr segment_buffer(new (std::nothrow) char[uncompressed_length]); + if (!segment_buffer) + return std::errc::not_enough_memory; + + err = zipfile->decompress(&segment_buffer[0], uncompressed_length); + if (err) + return err; + + m_segment_id = segment_id; + return parse_segment(&segment_buffer[0], uncompressed_length); +} + +std::error_condition network_adapter::segment_file::parse_segment(char *data, size_t length) +{ + util::core_file::ptr fd; + pak current; + uint64_t offset = 0; + size_t actual; + uint16_t crc; + uint8_t npak = 0; + std::error_condition err; + + pak_list.clear(); + err = util::core_file::open_ram(data, length, OPEN_FLAG_READ, fd); + if (err) + return err; + + memset(current.data, 0, 991); + current.segment_id[0] = (m_segment_id & 0xff0000) >> 16; + current.segment_id[1] = (m_segment_id & 0x00ff00) >> 8; + current.segment_id[2] = (m_segment_id & 0x0000ff); + current.owner = 0x01; + current.tier[0] = 0x7f; + current.tier[1] = 0xff; + current.tier[2] = 0xff; + current.tier[3] = 0xff; + current.mbytes[0] = 0x7f; + current.mbytes[1] = 0x80; + err = fd->read_at(offset, current.data, 991, actual); + do { + crc = 0xffff; + if (err) { + return err; + } + if (actual > 0) { + current.packet_number = npak; + current.pak_number[0] = npak; + current.pak_number[1] = 0; + current.type = 0x20; + if (offset == 0) + current.type |= 0x81; + if (actual < 991) + current.type |= 0x10; + current.offset[0] = ((offset) >> 8) & 0xff; + current.offset[1] = offset & 0xff; + for (int i = 0; i < 1007; ++i) { + crc = update_crc(crc, ((char *)¤t)[i]); + } + crc ^= 0xffff; + current.crc[0] = (crc >> 8) & 0xff; + current.crc[1] = crc & 0xff; + pak_list.push_back(current); + offset = (++npak * 991); + memset(current.data, 0, 991); + err = fd->read_at(offset, current.data, 991, actual); + } + } while(actual > 0); + + return err; +} + +const network_adapter::segment_file::pak& network_adapter::segment_file::operator[](const int index) const +{ + assert(index >= 0 && index < size()); + + return pak_list[index]; +} + +// crc16 calculation +uint16_t network_adapter::segment_file::update_crc(uint16_t crc, uint8_t data) +{ + uint8_t bc; + + bc = (crc >> 8) ^ data; + + crc <<= 8; + crc ^= crc_table[bc]; + + return crc; +} + +//************************************************************************** +// INPUT PORTS +//************************************************************************** + +// CONFIG +static INPUT_PORTS_START( nabu_network_adapter ) + PORT_START("CONFIG") + PORT_CONFNAME(0x01, 0x00, "Prompt for channel?") + PORT_CONFSETTING(0x01, "Yes") + PORT_CONFSETTING(0x00, "No") +INPUT_PORTS_END + +//************************************************************************** +// DEVICE INITIALIZATION +//************************************************************************** + +network_adapter::network_adapter(machine_config const &mconfig, char const *tag, device_t *owner, uint32_t clock) + : device_t(mconfig, NABUPC_NETWORK_ADAPTER, tag, owner, clock) + , device_buffered_serial_interface(mconfig, *this) + , device_rs232_port_interface(mconfig, *this) + , device_image_interface(mconfig, *this) + , m_config(*this, "CONFIG") + , m_channel(0) + , m_packet(0) + , m_segment(0) + , m_state(state::START) + , m_substate(0) + , m_segment_timer(nullptr) +{ +} + +void network_adapter::device_start() +{ + m_segment_timer = timer_alloc(FUNC(network_adapter::segment_tick), this); + + machine().save().register_postload(save_prepost_delegate(FUNC(network_adapter::postload), this)); + + save_item(NAME(m_state)); + save_item(NAME(m_substate)); + save_item(NAME(m_channel)); + save_item(NAME(m_packet)); + save_item(NAME(m_segment)); +} + +void network_adapter::device_reset() +{ + m_state = state::START; + m_substate = 0; + // initialise state + clear_fifo(); + + // configure device_buffered_serial_interface + set_data_frame(START_BIT_COUNT, DATA_BIT_COUNT, PARITY, STOP_BITS); + set_rate(BAUD); + receive_register_reset(); + transmit_register_reset(); +} + +void network_adapter::postload() +{ + if (is_loaded()) { + m_cache.read_archive(image_core_file(), m_segment); + } +} + +image_init_result network_adapter::call_load() +{ + if (is_filetype("pak")) { + return image_init_result::PASS; + } + seterror(image_error::INVALIDIMAGE); + return image_init_result::FAIL; +} + +//************************************************************************** +// DEVICE CONFIGURATION +//************************************************************************** + +ioport_constructor network_adapter::device_input_ports() const +{ + return INPUT_PORTS_NAME( nabu_network_adapter ); +} + +//************************************************************************** +// SERIAL PROTOCOL +//************************************************************************** + +WRITE_LINE_MEMBER(network_adapter::input_txd) +{ + device_buffered_serial_interface::rx_w(state); +} + +void network_adapter::tra_callback() +{ + output_rxd(transmit_register_get_data_bit()); +} + +void network_adapter::received_byte(uint8_t byte) +{ + LOG("Received Byte 0x%02X\n", byte); + switch (m_state) { + case state::START: + connect(byte, bool(m_config->read() & 1)); + break; + case state::IDLE: + idle(byte); + break; + case state::CHANNEL_REQUEST: + channel_request(byte); + break; + case state::SEGMENT_REQUEST: + segment_request(byte); + break; + case state::HEX81_REQUEST: + hex81_request(byte); + break; + case state::SEND_SEGMENT: + send_segment(byte); + break; + } +} + +//************************************************************************** +// STATE MACHINE +//************************************************************************** + +void network_adapter::connect(uint8_t byte, bool channel_request = true) +{ + if (byte == 0x83 && m_substate == 0) { + transmit_byte(0x10); + transmit_byte(0x06); + transmit_byte(0xe4); + } else if (byte == 0x82 && m_substate == 1) { + transmit_byte(0x10); + transmit_byte(0x06); + } else if (byte == 0x01 && m_substate == 2) { + transmit_byte(channel_request ? 0x9f : 0x1f); + transmit_byte(0x10); + transmit_byte(0xe1); + m_state = state::IDLE; + } else { + LOG("Unexpected byte: 0x%02X (%d), restarting Adapter.\n", byte, m_substate); + m_state = state::START; + m_substate = 0; + return; + } + ++m_substate; +} + +void network_adapter::idle(uint8_t byte) +{ + m_substate = 0; + switch (byte) { + case 0x85: + transmit_byte(0x10); + transmit_byte(0x06); + m_state = state::CHANNEL_REQUEST; + break; + case 0x84: + transmit_byte(0x10); + transmit_byte(0x06); + m_state = state::SEGMENT_REQUEST; + break; + case 0x83: + transmit_byte(0x10); + transmit_byte(0x06); + break; + case 0x82: + transmit_byte(0x10); + transmit_byte(0x06); + break; + case 0x81: + transmit_byte(0x10); + transmit_byte(0x06); + m_state = state::HEX81_REQUEST; + break; + case 0x01: + transmit_byte(0x10); + transmit_byte(0x06); + break; + } + +} + +void network_adapter::hex81_request(uint8_t byte) +{ + if (m_substate == 1) { + transmit_byte(0xe4); + m_state = state::IDLE; + } + ++m_substate; + +} + +void network_adapter::channel_request(uint8_t byte) +{ + if (m_substate == 0) { + m_channel = (m_channel & 0xff00) | (byte); + } else if (m_substate == 1) { + m_channel = (m_channel & 0xff) | (byte << 8); + transmit_byte(0xe4); + LOG("Channel: 0x%04X\n", m_channel); + m_state = state::IDLE; + } + ++m_substate; +} + +void network_adapter::segment_request(uint8_t byte) +{ + if (m_substate == 0) { + m_packet = byte; + } else if (m_substate == 1) { + m_segment = (m_segment & 0xffff00) | (byte); + } else if (m_substate == 2) { + m_segment = (m_segment & 0xff00ff) | (byte << 8); + } else if (m_substate == 3) { + m_segment = (m_segment & 0xffff) | (byte << 16); + transmit_byte(0xe4); + transmit_byte(0x91); + m_state = state::SEND_SEGMENT; + m_substate = 0; + LOG("Segment: 0x%06X, Packet: 0x%02X\n", m_segment, m_packet); + return; + } + ++m_substate; +} + +void network_adapter::send_segment(uint8_t byte) +{ + if (m_substate == 0) { + if (byte != 0x10) { + LOG("Expecting byte 0x10 got %02X, restarting.\n", byte); + m_state = state::START; + m_substate = 0; + return; + } + } else if (m_substate == 1) { + if (byte != 0x06) { + LOG("Expecting byte 0x06 got %02X, restarting.\n", byte); + m_state = state::START; + m_substate = 0; + return; + } + m_pak_offset = 0; + if (is_loaded() && !m_cache.read_archive(image_core_file(), m_segment)) { + m_segment_timer->adjust(attotime::zero, 0, attotime::from_hz(1'000)); + LOG("Segment sending, returning to idle state\n"); + } else { + LOG("Failed to find segment: %06d, restarting\n", m_segment); + transmit_byte(0x10); + transmit_byte(0x06); + transmit_byte(0xe4); + } + m_state = state::IDLE; + } + + ++m_substate; +} + +TIMER_CALLBACK_MEMBER(network_adapter::segment_tick) +{ + char * data = (char*)&m_cache[m_packet]; + if (data[m_pak_offset] == 0x10) { + transmit_byte(data[m_pak_offset]); + } + transmit_byte(data[m_pak_offset++]); + if (m_pak_offset >= sizeof(segment_file::pak)) { + transmit_byte(0x10); + transmit_byte(0xe1); + m_segment_timer->reset(); + } +} + +} // bus::nabupc diff --git a/src/devices/bus/nabupc/adapter.h b/src/devices/bus/nabupc/adapter.h new file mode 100644 index 00000000000..11c7016a162 --- /dev/null +++ b/src/devices/bus/nabupc/adapter.h @@ -0,0 +1,153 @@ +// license:BSD-3-Clause +// copyright-holders:Brian Johnson +/******************************************************************* + * + * NABU PC - NABU Network Adapter + * + *******************************************************************/ + +#ifndef MAME_BUS_NABUPC_ADAPTER_H +#define MAME_BUS_NABUPC_ADAPTER_H + +#pragma once + +#include "bus/rs232/rs232.h" +#include "diserial.h" + +namespace bus::nabupc { + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +/* NABU PC Network Adapter */ + +class network_adapter + : public device_t + , public device_buffered_serial_interface<16U> + , public device_rs232_port_interface + , public device_image_interface +{ +public: + // constructor/destructor + network_adapter(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock); + + // image-level overrides + virtual bool is_readable() const noexcept override { return true; } + virtual bool is_writeable() const noexcept override { return false; } + virtual bool is_creatable() const noexcept override { return false; } + virtual bool is_reset_on_load() const noexcept override { return false; } + virtual bool core_opens_image_file() const noexcept override { return true; } + virtual const char *file_extensions() const noexcept override { return "pak"; } + virtual const char *image_type_name() const noexcept override { return "Segment Pak"; } + virtual const char *image_brief_type_name() const noexcept override { return "hcca"; } + virtual image_init_result call_load() override; + + + virtual DECLARE_WRITE_LINE_MEMBER(input_txd) override; +protected: + // device overrides + virtual ioport_constructor device_input_ports() const override; + virtual void device_start() override; + virtual void device_reset() override; + + // device_buffered_serial_interface overrides + virtual void tra_callback() override; + +private: + // Serial Parameters + static constexpr int START_BIT_COUNT = 1; + static constexpr int DATA_BIT_COUNT = 8; + static constexpr device_serial_interface::parity_t PARITY = device_serial_interface::PARITY_NONE; + static constexpr device_serial_interface::stop_bits_t STOP_BITS = device_serial_interface::STOP_BITS_1; + static constexpr int BAUD = 111'900; + + virtual void received_byte(uint8_t byte) override; + + void postload(); + + // NABU Network Segment File + class segment_file { + public: + struct pak { + uint8_t segment_id[3]; + uint8_t packet_number; + uint8_t owner; + uint8_t tier[4]; + uint8_t mbytes[2]; + uint8_t type; + uint8_t pak_number[2]; + uint8_t offset[2]; + uint8_t data[991]; + uint8_t crc[2]; + }; + public: + std::error_condition read_archive(util::core_file &stream, uint32_t segment_id); + std::error_condition load(std::string_view local_path, uint32_t segment_id); + const pak& operator[](const int index) const; + uint32_t size() { return pak_list.size(); } + private: + static constexpr uint16_t crc_table[256] = { + 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 + }; + std::error_condition parse_segment(char * buffer, size_t length); + uint16_t update_crc(uint16_t crc, uint8_t data); + + uint32_t m_segment_id; + std::vector pak_list; + }; + + // State Machine + enum state {START, IDLE, HEX81_REQUEST, CHANNEL_REQUEST, SEGMENT_REQUEST, SEND_SEGMENT}; + + TIMER_CALLBACK_MEMBER(segment_tick); + + void connect(uint8_t byte, bool channel_request); + void idle(uint8_t byte); + void channel_request(uint8_t byte); + void segment_request(uint8_t byte); + void hex81_request(uint8_t byte); + void send_segment(uint8_t byte); + void load_segment(std::string filename); + + required_ioport m_config; + + uint16_t m_channel; + uint8_t m_packet; + uint32_t m_segment; + uint8_t m_state; + uint8_t m_substate; + uint16_t m_pak_offset; + + emu_timer *m_segment_timer; + segment_file m_cache; +}; + +} // bus::nabupc + +DECLARE_DEVICE_TYPE_NS(NABUPC_NETWORK_ADAPTER, bus::nabupc, network_adapter) + +#endif // MAME_BUS_NABUPC_ADAPTER_H diff --git a/src/devices/bus/nabupc/fdc.cpp b/src/devices/bus/nabupc/fdc.cpp new file mode 100644 index 00000000000..3f6d3fc8fad --- /dev/null +++ b/src/devices/bus/nabupc/fdc.cpp @@ -0,0 +1,122 @@ +// license:BSD-3-Clause +// copyright-holders:Brian Johnson +/******************************************************************* + * + * NABU PC FDC Card + * + *******************************************************************/ + +#include "emu.h" +#include "fdc.h" + + +//************************************************************************** +// NABU PC FDC DEVICE +//************************************************************************** + +DEFINE_DEVICE_TYPE(NABUPC_OPTION_FDC, bus::nabupc::fdc_device, "nabupc_option_fdc", "NABU PC Floppy Controller") + +namespace bus::nabupc { + +static void nabu_fdc_drives(device_slot_interface &device) +{ + device.option_add("525dd", FLOPPY_525_DD); +} + +//------------------------------------------------- +// fdc_device - constructor +//------------------------------------------------- +fdc_device::fdc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : + device_t(mconfig, NABUPC_OPTION_FDC, tag, owner, clock), + device_option_expansion_interface(mconfig, *this), + m_wd2797(*this, "fdc"), + m_floppies(*this, "fdc:%u", 0) +{ +} + +//------------------------------------------------- +// device_add_mconfig - device-specific config +//------------------------------------------------- +void fdc_device::device_add_mconfig(machine_config &config) +{ + WD2797(config, m_wd2797, 4_MHz_XTAL / 4).set_force_ready(true); + FLOPPY_CONNECTOR(config, m_floppies[0], nabu_fdc_drives, "525dd", floppy_image_device::default_mfm_floppy_formats); + FLOPPY_CONNECTOR(config, m_floppies[1], nabu_fdc_drives, "525dd", floppy_image_device::default_mfm_floppy_formats); +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- +void fdc_device::device_start() +{ +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- +void fdc_device::device_reset() +{ + m_wd2797->set_floppy(nullptr); + m_wd2797->dden_w(0); +} + +//------------------------------------------------- +// ds_w - write to drive select/density register +//------------------------------------------------- +void fdc_device::ds_w(uint8_t data) +{ + m_wd2797->dden_w(BIT(data, 0)); + + floppy_image_device *floppy = nullptr; + + if (BIT(data, 1)) floppy = m_floppies[0]->get_device(); + if (BIT(data, 2)) floppy = m_floppies[1]->get_device(); + + m_wd2797->set_floppy(floppy); + + for (auto& fdd : m_floppies) + { + floppy_image_device *floppy = fdd->get_device(); + if (floppy) + { + floppy->mon_w((data & 6) ? 0 : 1); + } + } +} + +uint8_t fdc_device::read(offs_t offset) +{ + uint8_t result; + + switch(offset) { + case 0x00: + case 0x01: + case 0x02: + case 0x03: + result = m_wd2797->read(offset); + break; + case 0x0F: + result = 0x10; + break; + default: + result = 0xFF; + } + return result; +} + +void fdc_device::write(offs_t offset, uint8_t data) +{ + switch(offset) { + case 0x00: + case 0x01: + case 0x02: + case 0x03: + m_wd2797->write(offset, data); + break; + case 0x0F: + ds_w(data); + break; + } +} + +} // namespace bus::nabupc diff --git a/src/devices/bus/nabupc/fdc.h b/src/devices/bus/nabupc/fdc.h new file mode 100644 index 00000000000..49169746c79 --- /dev/null +++ b/src/devices/bus/nabupc/fdc.h @@ -0,0 +1,54 @@ +// license:BSD-3-Clause +// copyright-holders:Brian Johnson +/******************************************************************* + * + * NABU PC Floppy Controller + * + *******************************************************************/ + +#ifndef MAME_BUS_NABUPC_FDC_H +#define MAME_BUS_NABUPC_FDC_H + +#pragma once + +#include "option.h" + +#include "imagedev/floppy.h" +#include "machine/wd_fdc.h" + +namespace bus::nabupc { + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +/* NABU PC FDC Device */ + +class fdc_device : public device_t, public bus::nabupc::device_option_expansion_interface +{ +public: + // construction/destruction + fdc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + virtual uint8_t read(offs_t offset) override; + virtual void write(offs_t offset, uint8_t data) override; +protected: + // device-level overrides + virtual void device_start() override; + virtual void device_reset() override; + + // optional information overrides + virtual void device_add_mconfig(machine_config &config) override; +private: + void ds_w(uint8_t data); + + required_device m_wd2797; + required_device_array m_floppies; +}; + +} // namespace bus::nabupc + +// device type definition +DECLARE_DEVICE_TYPE_NS(NABUPC_OPTION_FDC, bus::nabupc, fdc_device) + +#endif // MAME_BUS_NABUPC_FDC_H diff --git a/src/devices/bus/nabupc/keyboard/hlekeyboard.cpp b/src/devices/bus/nabupc/keyboard/hlekeyboard.cpp new file mode 100644 index 00000000000..edd2dd0f12a --- /dev/null +++ b/src/devices/bus/nabupc/keyboard/hlekeyboard.cpp @@ -0,0 +1,372 @@ +// license:BSD-3-Clause +// copyright-holders:Brian Johnson +/***************************************************************************** + + NABU PC HLE Keyboard Interface + + *****************************************************************************/ + +#include "emu.h" +#include "hlekeyboard.h" + +#include "machine/keyboard.h" +#include "machine/keyboard.ipp" + +#include "diserial.h" + + +namespace { + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class hle_keyboard_device + : public device_t + , public device_buffered_serial_interface<16U> + , public device_rs232_port_interface + , protected device_matrix_keyboard_interface<16U> +{ +public: + // constructor/destructor + hle_keyboard_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock); + +protected: + // device overrides + virtual void device_start() override; + virtual void device_reset() override; + + virtual ioport_constructor device_input_ports() const override; + + // device_buffered_serial_interface overrides + virtual void tra_callback() override; + + // device_matrix_keyboard_interface overrides + virtual void key_make(uint8_t row, uint8_t column) override; + virtual void key_break(uint8_t row, uint8_t column) override; + virtual void scan_complete() override; + + uint8_t translate(uint8_t row, uint8_t column); + +private: + static constexpr int START_BIT_COUNT = 1; + static constexpr int DATA_BIT_COUNT = 8; + static constexpr device_serial_interface::parity_t PARITY = device_serial_interface::PARITY_NONE; + static constexpr device_serial_interface::stop_bits_t STOP_BITS = device_serial_interface::STOP_BITS_1; + static constexpr int BAUD = 6'993; + + TIMER_CALLBACK_MEMBER(watchdog_tick); + + virtual void received_byte(uint8_t byte) override {} + + required_ioport m_modifiers; + required_ioport m_gameport1; + required_ioport m_gameport2; + + emu_timer *m_watchdog_timer; + uint8_t m_prev_gameport1; + uint8_t m_prev_gameport2; +}; + +namespace { +//************************************************************************** +// TRANSLATION TABLE +//************************************************************************** + + uint8_t const TRANSLATION_TABLE[3][16][4] = + { + // unshifted + { + { 0x00, 0x38, 0x67, 0x6e }, // 0 + { 0x1b, 0x32, 0x09, 0x63 }, // 1 + { 0xe0, 0xe2, 0xe6, 0xe4 }, // 2 + { 0x70, 0x3d, 0x6c, 0x2e }, // 3 + { 0x77, 0x34, 0x61, 0x62 }, // 4 + { 0x72, 0x36, 0x64, 0x7a }, // 5 + { 0x69, 0x30, 0x6a, 0x6d }, // 6 + { 0x5d, 0xea, 0x27, 0x00 }, // 7 + { 0x75, 0x37, 0x20, 0x68 }, // 8 + { 0x71, 0x31, 0x78, 0x79 }, // 9 + { 0xe1, 0xe7, 0xe5, 0xe3 }, // 10 + { 0x5b, 0x2d, 0x2f, 0x3b }, // 11 + { 0x65, 0x33, 0x76, 0x73 }, // 12 + { 0x74, 0x35, 0x00, 0x66 }, // 13 + { 0x6f, 0x39, 0x2c, 0x6b }, // 14 + { 0x7f, 0xe9, 0xe8, 0x0d }, // 15 + }, + // shifted + { + { 0x00, 0x2a, 0x47, 0x4e }, // 0 + { 0x1b, 0x40, 0x09, 0x43 }, // 1 + { 0xe0, 0xe2, 0xe6, 0xe4 }, // 2 + { 0x50, 0x2b, 0x4c, 0x3e }, // 3 + { 0x57, 0x24, 0x41, 0x42 }, // 4 + { 0x52, 0x5e, 0x44, 0x5a }, // 5 + { 0x49, 0x29, 0x4a, 0x4d }, // 6 + { 0x7d, 0xea, 0x22, 0x00 }, // 7 + { 0x55, 0x26, 0x20, 0x48 }, // 8 + { 0x51, 0x21, 0x58, 0x59 }, // 9 + { 0xe1, 0xe7, 0xe5, 0xe3 }, // 10 + { 0x5b, 0x5f, 0x3f, 0x3a }, // 11 + { 0x45, 0x23, 0x56, 0x53 }, // 12 + { 0x54, 0x25, 0x00, 0x46 }, // 13 + { 0x4f, 0x28, 0x3c, 0x4b }, // 14 + { 0x7f, 0xe9, 0xe8, 0x0d }, // 15 + }, + // control + { + { 0x00, 0x38, 0x07, 0x0e }, // 0 + { 0x1b, 0x00, 0x09, 0x03 }, // 1 + { 0xe0, 0xe2, 0xe6, 0xe4 }, // 2 + { 0x10, 0x3d, 0x0c, 0x2e }, // 3 + { 0x17, 0x34, 0x01, 0x02 }, // 4 + { 0x12, 0x1e, 0x04, 0x1a }, // 5 + { 0x09, 0x30, 0x0a, 0x0d }, // 6 + { 0x1d, 0xea, 0x27, 0x00 }, // 7 + { 0x15, 0x37, 0x20, 0x08 }, // 8 + { 0x11, 0x31, 0x18, 0x19 }, // 9 + { 0xe1, 0xe7, 0xe5, 0xe3 }, // 10 + { 0x1b, 0x1f, 0x2f, 0x3b }, // 11 + { 0x05, 0x33, 0x16, 0x13 }, // 12 + { 0x14, 0x35, 0x00, 0x06 }, // 13 + { 0x0f, 0x39, 0x1c, 0x0b }, // 14 + { 0x7f, 0xe9, 0xe8, 0x0d }, // 15 + } + }; + +//************************************************************************** +// KEYBOARD MATRIX +//************************************************************************** + +INPUT_PORTS_START(nabu_hle_keyboard) + PORT_START("MODIFIERS") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_LCONTROL) PORT_CODE(KEYCODE_RCONTROL) PORT_NAME("Control") PORT_CHAR(UCHAR_MAMEKEY(LCONTROL)) + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_LSHIFT) PORT_CODE(KEYCODE_RSHIFT) PORT_NAME("Shift") PORT_CHAR(UCHAR_SHIFT_1) + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_CAPSLOCK) PORT_NAME("Caps Lock") PORT_TOGGLE PORT_CHAR(UCHAR_MAMEKEY(CAPSLOCK)) + PORT_START("ROW0") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_UNUSED) // "Alt Mode" + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_8) PORT_CHAR('8') PORT_CHAR('*') + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_G) PORT_CHAR('g') PORT_CHAR('G') + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_N) PORT_CHAR('n') PORT_CHAR('N') + PORT_START("ROW1") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_ESC) PORT_NAME("Esc") PORT_CHAR(UCHAR_MAMEKEY(ESC)) + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_2) PORT_CHAR('2') PORT_CHAR('2') + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_TAB) PORT_NAME("Tab") PORT_CHAR(9) + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_C) PORT_CHAR('c') PORT_CHAR('C') + PORT_START("ROW2") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_RIGHT) PORT_NAME("Right") PORT_CHAR(UCHAR_MAMEKEY(RIGHT)) + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_UP) PORT_NAME("Up") PORT_CHAR(UCHAR_MAMEKEY(UP)) + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_F2) PORT_NAME("No") PORT_CHAR(UCHAR_MAMEKEY(F2)) + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_PGDN) PORT_NAME("|||>") PORT_CHAR(UCHAR_MAMEKEY(PGDN)) + PORT_START("ROW3") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_P) PORT_CHAR('p') PORT_CHAR('P') + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_EQUALS) PORT_CHAR('=') PORT_CHAR('+') + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_L) PORT_CHAR('l') PORT_CHAR('L') + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') PORT_CHAR('>') + PORT_START("ROW4") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_W) PORT_CHAR('w') PORT_CHAR('W') + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_4) PORT_CHAR('4') PORT_CHAR('$') + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_A) PORT_CHAR('a') PORT_CHAR('A') + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_B) PORT_CHAR('b') PORT_CHAR('B') + PORT_START("ROW5") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_R) PORT_CHAR('r') PORT_CHAR('R') + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_6) PORT_CHAR('6') PORT_CHAR('^') + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_D) PORT_CHAR('d') PORT_CHAR('D') + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_Z) PORT_CHAR('z') PORT_CHAR('Z') + PORT_START("ROW6") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_I) PORT_CHAR('i') PORT_CHAR('I') + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_0) PORT_CHAR('0') PORT_CHAR(')') + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_J) PORT_CHAR('j') PORT_CHAR('J') + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_M) PORT_CHAR('m') PORT_CHAR('M') + PORT_START("ROW7") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR(']') PORT_CHAR('}') + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_F3) PORT_NAME("TV") PORT_CHAR(UCHAR_MAMEKEY(F3)) + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_QUOTE) PORT_CHAR('\'') PORT_CHAR('"') + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_UNUSED) // "Alt Mode" + PORT_START("ROW8") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_U) PORT_CHAR('u') PORT_CHAR('U') + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_7) PORT_CHAR('7') PORT_CHAR('&') + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ') + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_H) PORT_CHAR('h') PORT_CHAR('H') + PORT_START("ROW9") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_Q) PORT_CHAR('q') PORT_CHAR('Q') + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_1) PORT_CHAR('1') PORT_CHAR('!') + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_X) PORT_CHAR('x') PORT_CHAR('X') + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_Y) PORT_CHAR('y') PORT_CHAR('Y') + PORT_START("ROWA") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_LEFT) PORT_NAME("Left") PORT_CHAR(UCHAR_MAMEKEY(LEFT)) + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_F1) PORT_NAME("Yes") PORT_CHAR(UCHAR_MAMEKEY(F1)) + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_PGUP) PORT_NAME("<|||") PORT_CHAR(UCHAR_MAMEKEY(PGUP)) + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_DOWN) PORT_NAME("Down") PORT_CHAR(UCHAR_MAMEKEY(DOWN)) + PORT_START("ROWB") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR('[') PORT_CHAR('{') + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_MINUS) PORT_CHAR('-') PORT_CHAR('_') + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_SLASH) PORT_CHAR('/') PORT_CHAR('?') + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_COLON) PORT_CHAR(';') PORT_CHAR(':') + PORT_START("ROWC") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_E) PORT_CHAR('e') PORT_CHAR('E') + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_3) PORT_CHAR('3') PORT_CHAR('#') + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_V) PORT_CHAR('v') PORT_CHAR('V') + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_S) PORT_CHAR('s') PORT_CHAR('S') + PORT_START("ROWD") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_T) PORT_CHAR('t') PORT_CHAR('T') + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_5) PORT_CHAR('5') PORT_CHAR('%') + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_UNUSED) // "Alt Mode" + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_F) PORT_CHAR('f') PORT_CHAR('F') + PORT_START("ROWE") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_O) PORT_CHAR('o') PORT_CHAR('O') + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_9) PORT_CHAR('9') PORT_CHAR('(') + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',') PORT_CHAR('<') + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_K) PORT_CHAR('k') PORT_CHAR('K') + PORT_START("ROWF") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_BACKSPACE) PORT_NAME("Delete") PORT_CHAR(UCHAR_MAMEKEY(BACKSPACE)) + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_PAUSE) PORT_NAME("Pause") PORT_CHAR(UCHAR_MAMEKEY(PAUSE)) + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_F4) PORT_NAME("SYM") PORT_CHAR(UCHAR_MAMEKEY(F4)) + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_ENTER) PORT_NAME("Go") PORT_CHAR(13) + + PORT_START("JOYSTICK1") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_CODE(KEYCODE_4_PAD) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_CODE(KEYCODE_2_PAD) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_CODE(KEYCODE_6_PAD) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) PORT_CODE(KEYCODE_8_PAD) + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_CODE(KEYCODE_ENTER_PAD) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_START("JOYSTICK2") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_PLAYER(2) PORT_CODE(INPUT_CODE_INVALID) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_PLAYER(2) PORT_CODE(INPUT_CODE_INVALID) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(2) PORT_CODE(INPUT_CODE_INVALID) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) PORT_PLAYER(2) PORT_CODE(INPUT_CODE_INVALID) + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_PLAYER(2) PORT_CODE(INPUT_CODE_INVALID) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNUSED ) +INPUT_PORTS_END +} + +//************************************************************************** +// KEYBOARD DEVICE +//************************************************************************** + +//------------------------------------------------- +// keyboard_device - constructor +//------------------------------------------------- +hle_keyboard_device::hle_keyboard_device(machine_config const &mconfig, char const *tag, device_t *owner, uint32_t clock) + : device_t(mconfig, NABUPC_HLE_KEYBOARD, tag, owner, clock) + , device_buffered_serial_interface(mconfig, *this) + , device_rs232_port_interface(mconfig, *this) + , device_matrix_keyboard_interface(mconfig, *this, "ROW0", "ROW1", "ROW2", "ROW3", "ROW4", "ROW5", "ROW6", "ROW7", "ROW8", "ROW9", "ROWA", "ROWB", "ROWC", "ROWD", "ROWE", "ROWF") + , m_modifiers(*this, "MODIFIERS") + , m_gameport1(*this, "JOYSTICK1") + , m_gameport2(*this, "JOYSTICK2") + , m_watchdog_timer(nullptr) +{ +} + +ioport_constructor hle_keyboard_device::device_input_ports() const +{ + return INPUT_PORTS_NAME(nabu_hle_keyboard); +} + +void hle_keyboard_device::device_start() +{ + m_watchdog_timer = timer_alloc(FUNC(hle_keyboard_device::watchdog_tick), this); + + save_item(NAME(m_prev_gameport1)); + save_item(NAME(m_prev_gameport2)); +} + +void hle_keyboard_device::device_reset() +{ + m_prev_gameport1 = m_prev_gameport2 = 0xa0; + + // initialise state + clear_fifo(); + + // configure device_buffered_serial_interface + set_data_frame(START_BIT_COUNT, DATA_BIT_COUNT, PARITY, STOP_BITS); + set_rate(BAUD); + receive_register_reset(); + transmit_register_reset(); + + m_watchdog_timer->adjust(attotime::from_msec(500), 1, attotime::never); + + // kick the base + reset_key_state(); + start_processing(attotime::from_hz(BAUD)); +} + +TIMER_CALLBACK_MEMBER(hle_keyboard_device::watchdog_tick) +{ + if (param == 1) { + transmit_byte(0x95); + m_watchdog_timer->adjust(attotime::from_msec(500), 0, attotime::from_msec(3700)); + } else { + transmit_byte(0x94); + } +} + +void hle_keyboard_device::tra_callback() +{ + output_rxd(transmit_register_get_data_bit()); +} + +//************************************************************************** +// KEYBOARD SCANNING +//************************************************************************** + +void hle_keyboard_device::key_make(uint8_t row, uint8_t column) +{ + transmit_byte(translate(row,column)); +} + +void hle_keyboard_device::key_break(uint8_t row, uint8_t column) +{ + uint8_t key = translate(row, column); + if ((key & 0xe0) == 0xe0) { + transmit_byte(key | 0x10); + } +} + +uint8_t hle_keyboard_device::translate(uint8_t row, uint8_t column) +{ + uint8_t const modifiers(m_modifiers->read()); + + bool const ctrl(modifiers & 0x01); + bool const shift(bool(modifiers & 0x02)); + unsigned const map(ctrl ? 2 : shift ? 1 : 0); + uint8_t scancode = TRANSLATION_TABLE[map][row][column]; + + if ((scancode >= 0x61 && scancode <= 0x7a) && (modifiers & 0x04)) { + scancode -= 0x20; + } + + return scancode; +} + +void hle_keyboard_device::scan_complete() +{ + uint8_t gameport1 = m_gameport1->read(); + uint8_t gameport2 = m_gameport2->read(); + + if (gameport1 != m_prev_gameport1) { + m_prev_gameport1 = gameport1; + transmit_byte(0x80); + transmit_byte(gameport1); + } + + if (gameport2 != m_prev_gameport2) { + m_prev_gameport2 = gameport2; + transmit_byte(0x81); + transmit_byte(gameport2); + } +} + +} // anonymous namespace + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +DEFINE_DEVICE_TYPE_PRIVATE(NABUPC_HLE_KEYBOARD, device_rs232_port_interface, hle_keyboard_device, "nabu_hle_keyboard", "NABU PC Keyboard (HLE)") diff --git a/src/devices/bus/nabupc/keyboard/hlekeyboard.h b/src/devices/bus/nabupc/keyboard/hlekeyboard.h new file mode 100644 index 00000000000..103cec099f0 --- /dev/null +++ b/src/devices/bus/nabupc/keyboard/hlekeyboard.h @@ -0,0 +1,19 @@ +// license:BSD-3-Clause +// copyright-holders:Brian Johnson +/*************************************************************************** + + NABU PC HLE Keyboard Interface + +***************************************************************************/ + + +#ifndef MAME_BUS_NABU_KEYBOARD_HLE_H +#define MAME_BUS_NABU_KEYBOARD_HLE_H + +#pragma once + +#include "bus/rs232/rs232.h" + +DECLARE_DEVICE_TYPE(NABUPC_HLE_KEYBOARD, device_rs232_port_interface) + +#endif // MAME_BUS_NABU_KEYBOARD_HLE_H diff --git a/src/devices/bus/nabupc/keyboard/keyboard.cpp b/src/devices/bus/nabupc/keyboard/keyboard.cpp new file mode 100644 index 00000000000..c5a5693f52b --- /dev/null +++ b/src/devices/bus/nabupc/keyboard/keyboard.cpp @@ -0,0 +1,147 @@ +// license:BSD-3-Clause +// copyright-holders:Brian Johnson +/***************************************************************************** + * NABU PC Keyboard Interface + * + * 0x40 -> ctrl + * 0x41 -> shift? + * 0x42 -> caps? + * + * They keyboard also contains 4 read-only gameport registers with 0 meaning + * the digital contact is set (Only two ports are populated) + * 0x5000 - Port 1 + * 0x5100 - Port 2 + * 0x5200 - Port 3 + * 0x5300 - Port 4 + * + * 7 6 5 4 3 2 1 0 + * --------------------------------- + * | F | - | - | - | U | R | D | L | + * -------------------------------- + * + *****************************************************************************/ + +#include "emu.h" +#include "keyboard.h" + +#include "cpu/m6800/m6801.h" + + +namespace { + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class keyboard_device: public device_t, public device_rs232_port_interface +{ +public: + // construction/destruction + keyboard_device(machine_config const &mconfig, char const *tag, device_t *owner, uint32_t clock = 0); + +protected: + // device-level overrides + virtual void device_start() override; + virtual void device_reset() override; + virtual void device_add_mconfig(machine_config &config) override; + virtual tiny_rom_entry const *device_rom_region() const override; +private: + void nabu_kb_mem(address_map &map); + + uint8_t port1_r(); + void port1_w(uint8_t data); + + uint8_t gameport_r(offs_t offset); + + required_device m_mcu; + + uint8_t m_port1; + uint8_t m_gameport[4]; +}; + +//************************************************************************** +// KEYBOARD ROM +//************************************************************************** + +ROM_START(nabu_keyboard_rom) + ROM_REGION( 0x800, "mcu", 0 ) + ROM_LOAD( "nabukeyboard-90020070-reva-2716.bin", 0x000, 0x800, CRC(eead3abc) SHA1(2f6ff63ca2f2ac90f3e03ef4f2b79883205e8a4e) ) +ROM_END + +//************************************************************************** +// KEYBOARD DEVICE +//************************************************************************** + +//------------------------------------------------- +// keyboard_device - constructor +//------------------------------------------------- + +keyboard_device::keyboard_device(machine_config const &mconfig, char const *tag, device_t *owner, uint32_t clock) + : device_t(mconfig, NABUPC_KEYBOARD, tag, owner, clock) + , device_rs232_port_interface(mconfig, *this) + , m_mcu(*this, "mcu") + , m_port1(0) + , m_gameport{ 0xff, 0xff, 0xff, 0xff } +{ +} + +void keyboard_device::device_start() +{ + save_item(NAME(m_port1)); + save_item(NAME(m_gameport)); +} + +void keyboard_device::device_reset() +{ + m_port1 &= 0x7f; + m_gameport[0] = 0xff; + m_gameport[1] = 0xff; + m_gameport[2] = 0xff; + m_gameport[3] = 0xff; + + output_rxd(1); +} + +void keyboard_device::device_add_mconfig(machine_config &config) +{ + M6803(config, m_mcu, XTAL(3'579'545)); // Crystal verified from schematics and visual inspection + m_mcu->set_addrmap(AS_PROGRAM, &keyboard_device::nabu_kb_mem); + m_mcu->in_p1_cb().set(FUNC(keyboard_device::port1_r)); + m_mcu->out_p1_cb().set(FUNC(keyboard_device::port1_w)); + m_mcu->out_ser_tx_cb().set(FUNC(keyboard_device::output_rxd)); +} + +void keyboard_device::nabu_kb_mem(address_map &map) +{ + map(0x5000, 0x5300).r(FUNC(keyboard_device::gameport_r)); + map(0xf800, 0xffff).rom().region("mcu", 0); +} + +const tiny_rom_entry *keyboard_device::device_rom_region() const +{ + return ROM_NAME(nabu_keyboard_rom); +} + +uint8_t keyboard_device::port1_r() +{ + return m_port1; +} + +void keyboard_device::port1_w(uint8_t data) +{ + m_port1 = data & 0x7f; +} + +uint8_t keyboard_device::gameport_r(offs_t offset) +{ + uint8_t port = (offset >> 8) & 0x03; + return m_gameport[port]; +} + +} // anonymous namespace + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +DEFINE_DEVICE_TYPE_PRIVATE(NABUPC_KEYBOARD, device_rs232_port_interface, keyboard_device, "nabu_keyboard", "NABU PC keyboard") diff --git a/src/devices/bus/nabupc/keyboard/keyboard.h b/src/devices/bus/nabupc/keyboard/keyboard.h new file mode 100644 index 00000000000..2df1ed170a0 --- /dev/null +++ b/src/devices/bus/nabupc/keyboard/keyboard.h @@ -0,0 +1,19 @@ +// license:BSD-3-Clause +// copyright-holders:Brian Johnson +/*************************************************************************** + + NABU PC Keyboard Interface + +***************************************************************************/ + + +#ifndef MAME_BUS_NABUPC_KEYBOARD_H +#define MAME_BUS_NABUPC_KEYBOARD_H + +#pragma once + +#include "bus/rs232/rs232.h" + +DECLARE_DEVICE_TYPE(NABUPC_KEYBOARD, device_rs232_port_interface) + +#endif // MAME_BUS_NABUPC_KEYBOARD_H diff --git a/src/devices/bus/nabupc/option.cpp b/src/devices/bus/nabupc/option.cpp new file mode 100644 index 00000000000..cb9de8f3d67 --- /dev/null +++ b/src/devices/bus/nabupc/option.cpp @@ -0,0 +1,132 @@ +// license:BSD-3-Clause +// copyright-holders:Brian Johnson + +/******************************************************************* + * + * NABU PC Expansion Emulation + * + *******************************************************************/ +#include "emu.h" +#include "option.h" + +#include "fdc.h" + +DEFINE_DEVICE_TYPE(NABUPC_OPTION_BUS_SLOT, bus::nabupc::option_slot_device, "nabupc_option_slot", "NABU PC Option slot") +DEFINE_DEVICE_TYPE(NABUPC_OPTION_BUS, bus::nabupc::option_bus_device, "nabupc_option_bus", "NABU PC Option Bus") + +namespace bus::nabupc { +//************************************************************************** +// NABU SLOT DEVICE +//************************************************************************** + +//------------------------------------------------- +// option_bus_slot_device - constructor +//------------------------------------------------- +option_slot_device::option_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : + device_t(mconfig, NABUPC_OPTION_BUS_SLOT, tag, owner, clock), + device_single_card_slot_interface(mconfig, *this), + m_bus(*this, finder_base::DUMMY_TAG), + m_slot(-1) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- +void option_slot_device::device_start() +{ + device_option_expansion_interface *const intf(get_card_device()); + if (intf) { + intf->set_option_bus(*m_bus, m_slot); + } + m_bus->add_slot(*this); +} + + +uint8_t option_slot_device::io_read(offs_t offset) +{ + device_option_expansion_interface *const intf(get_card_device()); + if (intf) { + return intf->read(offset); + } + return 0xFF; +} + +void option_slot_device::io_write(offs_t offset, uint8_t data) +{ + device_option_expansion_interface *const intf(get_card_device()); + if (intf) { + intf->write(offset, data); + } +} + +WRITE_LINE_MEMBER(option_slot_device::int_w) { (*m_bus).set_int_line(state, m_slot); } + + +//************************************************************************** +// NABU OPTION BUS DEVICE +//************************************************************************** + +//------------------------------------------------- +// option_bus_device - constructor +//------------------------------------------------- +option_bus_device::option_bus_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : + device_t(mconfig, NABUPC_OPTION_BUS, tag, owner, clock), + m_int_cb(*this) +{ +} + +void option_bus_device::add_slot(option_slot_device &slot) +{ + m_slot_list.push_back(&slot); +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- +void option_bus_device::device_start() +{ + m_int_cb.resolve_all_safe(); +} + +//------------------------------------------------- +// device_reset - device-specific startup +//------------------------------------------------- +void option_bus_device::device_reset() +{ +} + + +//************************************************************************** +// NABU OPTION CARD INTERFACE +//************************************************************************** + +//------------------------------------------------- +// option_device_expansion_interface - constructor +//------------------------------------------------- +device_option_expansion_interface::device_option_expansion_interface(const machine_config &mconfig, device_t &device) : + device_interface(device, "nabupc_option_bus"), + m_bus(nullptr), + m_slot(-1) +{ +} + +//--------------------------------------------------- +// interface_pre_start - device-specific pre startup +//--------------------------------------------------- +void device_option_expansion_interface::interface_pre_start() +{ + if (!m_bus || m_slot == -1) + throw device_missing_dependencies(); +} + +//------------------------------------------------- +// SLOT_INTERFACE( option_bus_devices ) +//------------------------------------------------- + +void option_bus_devices(device_slot_interface &device) +{ + device.option_add("fdc", NABUPC_OPTION_FDC); +} + +} // namespace bus::nabupc diff --git a/src/devices/bus/nabupc/option.h b/src/devices/bus/nabupc/option.h new file mode 100644 index 00000000000..62316b95365 --- /dev/null +++ b/src/devices/bus/nabupc/option.h @@ -0,0 +1,156 @@ +// license:BSD-3-Clause +// copyright-holders:Brian Johnson +/* + NABU PC BUS + + 1 /INT + 2 /M1 + 3 3.58MHz SYSCLK + 4 AUDIO + 5 /CS + 6 A0 + 7 A1 + 8 A2 + 9 A3 + 10 1.79MHz PCLK + 11 /WR + 12 /RD + 13 /IORQ + 14 /WAIT + 15 /RESET + 16 D0 + 17 D1 + 18 D2 + 19 D3 + 20 D4 + 21 D5 + 22 D6 + 23 D7 + 24 +5V + 25 +5V + 26 GND + 27 GND + 28 GND + 29 +12V + 30 -12V + +*/ +#ifndef MAME_BUS_NABUPC_OPTION_H +#define MAME_BUS_NABUPC_OPTION_H + +#pragma once + +#include + +namespace bus::nabupc { + +//************************************************************************** +// FORWARD DECLARATIONS +//************************************************************************** + +class option_bus_device; +class device_option_expansion_interface; + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +/* NABU PC Slot Device */ + +class option_slot_device : public device_t, public device_single_card_slot_interface +{ +public: + // construction/destruction + template + option_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, T &&bus_tag, int slot, U &&opts, const char *dflt) + : option_slot_device(mconfig, tag, owner, bus_tag->clock()) + { + option_reset(); + opts(*this); + set_default_option(dflt); + set_fixed(false); + m_bus.set_tag(std::forward(bus_tag)); + m_slot = slot; + } + option_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + uint8_t io_read(offs_t offset); + void io_write(offs_t offset, uint8_t data); + + DECLARE_WRITE_LINE_MEMBER(int_w); +protected: + // device-level overrides + virtual void device_start() override; + + // configuration + required_device m_bus; + int m_slot; +}; + + +/* NABU PC Bus Device */ + +class option_bus_device : public device_t +{ +public: + // construction/destruction + option_bus_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + template auto out_int_callback() { return m_int_cb[Slot].bind(); } + + template uint8_t read(offs_t offset) { + option_slot_device *slot = (*this)[Slot]; + return slot->io_read(offset); + } + + template void write(offs_t offset, uint8_t data) { + option_slot_device *slot = (*this)[Slot]; + slot->io_write(offset, data); + } + + void set_int_line(uint8_t state, uint8_t slot) { m_int_cb[slot](state); } + + void add_slot(option_slot_device &slot); + option_slot_device* operator[](int index) const {assert(index < m_slot_list.size()); return m_slot_list[index]; } + +protected: + // device-level overrides + virtual void device_start() override; + virtual void device_reset() override; + + devcb_write_line::array<5> m_int_cb; + + std::vector m_slot_list; +}; + + +/* NABU PC Option Card interface */ +class device_option_expansion_interface : public device_interface +{ +public: + void set_option_bus(option_bus_device &bus, int slot) { assert(!device().started()); m_bus = &bus; m_slot = slot; } + + virtual uint8_t read(offs_t offset) = 0; + virtual void write(offs_t offset, uint8_t data) = 0; + +protected: + device_option_expansion_interface(const machine_config &mconfig, device_t &device); + + virtual void interface_pre_start() override; + option_slot_device* get_slot() { return (*m_bus)[m_slot]; } + + option_bus_device *m_bus; + int m_slot; +}; + +void option_bus_devices(device_slot_interface &device); + +} // namespace bus::nabupc + + +// device type definition +DECLARE_DEVICE_TYPE_NS(NABUPC_OPTION_BUS_SLOT, bus::nabupc, option_slot_device) +DECLARE_DEVICE_TYPE_NS(NABUPC_OPTION_BUS, bus::nabupc, option_bus_device) + +#endif // MAME_BUS_NABUPC_OPTION_H diff --git a/src/devices/bus/rs232/rs232.h b/src/devices/bus/rs232/rs232.h index 576b0797dc4..ff903f30fce 100644 --- a/src/devices/bus/rs232/rs232.h +++ b/src/devices/bus/rs232/rs232.h @@ -31,6 +31,7 @@ #define RS232_BAUD_2000 (0x13) #define RS232_BAUD_3600 (0x14) #define RS232_BAUD_7200 (0x15) +#define RS232_BAUD_111900 (0x16) #define PORT_RS232_BAUD(_tag, _default_baud, _description, _class, _write_line) \ PORT_START(_tag) \ @@ -56,6 +57,7 @@ PORT_CONFSETTING( RS232_BAUD_28800, "28800") \ PORT_CONFSETTING( RS232_BAUD_38400, "38400") \ PORT_CONFSETTING( RS232_BAUD_57600, "57600") \ + PORT_CONFSETTING( RS232_BAUD_111900, "111900") \ PORT_CONFSETTING( RS232_BAUD_115200, "115200") #define RS232_DATABITS_5 (0x00) @@ -226,7 +228,8 @@ protected: 1800, 2000, 3600, - 7200 + 7200, + 111900 }; return values[baud]; diff --git a/src/mame/layout/nabupc.lay b/src/mame/layout/nabupc.lay new file mode 100644 index 00000000000..d266ceca304 --- /dev/null +++ b/src/mame/layout/nabupc.lay @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/mame/mame.lst b/src/mame/mame.lst index 86824c8199e..1eb1ddd06ae 100644 --- a/src/mame/mame.lst +++ b/src/mame/mame.lst @@ -45183,5 +45183,8 @@ vl1 @source:ddr/sprachmg.cpp sprachmg // 1985 Institut für Kosmosforschung +@source:misc/nabupc.cpp +nabupc // + @source:skeleton/tnshc08.cpp tnshc08 // JZD Slušovice TNS HC-08 diff --git a/src/mame/mess.flt b/src/mame/mess.flt index 9a148e87cec..ec594aaf61a 100644 --- a/src/mame/mess.flt +++ b/src/mame/mess.flt @@ -524,6 +524,7 @@ multitech/mpf1.cpp multitech/mpf1_88.cpp mupid/mdisk.cpp mupid/mupid2.cpp +misc/nabupc.cpp nakajima/nakajies.cpp nascom/nascom1.cpp natsemi/ns32kdb.cpp diff --git a/src/mame/misc/nabupc.cpp b/src/mame/misc/nabupc.cpp new file mode 100644 index 00000000000..1618622dbe1 --- /dev/null +++ b/src/mame/misc/nabupc.cpp @@ -0,0 +1,531 @@ +// license:BSD-3-Clause +// copyright-holders:Brian Johnson +/************************************************************************ + * NABU PC + * + * https://nabu.ca/ + * + * TODO: + * - Original keyboard support + * + ***********************************************************************/ + +#include "emu.h" + +#include "bus/centronics/ctronics.h" +#include "bus/nabupc/adapter.h" +#include "bus/nabupc/keyboard/hlekeyboard.h" +#include "bus/nabupc/keyboard/keyboard.h" +#include "bus/nabupc/option.h" +#include "bus/rs232/null_modem.h" +#include "bus/rs232/pty.h" +#include "bus/rs232/rs232.h" +#include "cpu/z80/z80.h" +#include "machine/ay31015.h" +#include "machine/clock.h" +#include "machine/i8251.h" +#include "machine/ram.h" +#include "sound/ay8910.h" +#include "video/tms9928a.h" +#include "speaker.h" + +#include "nabupc.lh" + +//************************************************************************** +// UTILITY FUNCTIONS +//************************************************************************** + +// Bit Manipulation +namespace { + template constexpr T BIT_SHIFT(unsigned n, unsigned v) + { + return (T)v << n; + } + + template void BIT_SET(T& w , unsigned n, unsigned v) + { + T mask = ~BIT_SHIFT(n, 1); + w = (w & mask) | BIT_SHIFT(n, v); + } + +// Priority Encoder +/** @brief F9318 input lines */ +enum f9318_in { + PRIO_IN_EI = (1<<8), + PRIO_IN_I7 = (1<<7), + PRIO_IN_I6 = (1<<6), + PRIO_IN_I5 = (1<<5), + PRIO_IN_I4 = (1<<4), + PRIO_IN_I3 = (1<<3), + PRIO_IN_I2 = (1<<2), + PRIO_IN_I1 = (1<<1), + PRIO_IN_I0 = (1<<0), + /* masks */ + PRIO_I7 = PRIO_IN_I7, + PRIO_I6_I7 = (PRIO_IN_I6 | PRIO_IN_I7), + PRIO_I5_I7 = (PRIO_IN_I5 | PRIO_I6_I7), + PRIO_I4_I7 = (PRIO_IN_I4 | PRIO_I5_I7), + PRIO_I3_I7 = (PRIO_IN_I3 | PRIO_I4_I7), + PRIO_I2_I7 = (PRIO_IN_I2 | PRIO_I3_I7), + PRIO_I1_I7 = (PRIO_IN_I1 | PRIO_I2_I7), + PRIO_I0_I7 = (PRIO_IN_I0 | PRIO_I1_I7), +}; + +/** @brief F9318 output lines */ +enum f9318_out { + PRIO_OUT_Q0 = (1<<0), + PRIO_OUT_Q1 = (1<<1), + PRIO_OUT_Q2 = (1<<2), + PRIO_OUT_EO = (1<<3), + PRIO_OUT_GS = (1<<4), + /* masks */ + PRIO_OUT_QZ = (PRIO_OUT_Q0 | PRIO_OUT_Q1 | PRIO_OUT_Q2) +}; + +/** + * @brief F9318 priority encoder 8 to 3-bit + * + * Emulation of the F9318 chip (pin compatible with 74348). + * + *
+ *            F9318
+ *         +---+-+---+
+ *         |   +-+   |         +---------------------------------+----------------+
+ *    I4' -|1      16|-  Vcc   |              input              |     output     |
+ *         |         |         +---------------------------------+----------------+
+ *    I5' -|2      15|-  EO'   |      EI I0 I1 I2 I3 I4 I5 I6 I7 | GS Q0 Q1 Q2 EO |
+ *         |         |         +---------------------------------+----------------+
+ *    I6' -|3      14|-  GS'   | (a)  H  x  x  x  x  x  x  x  x  | H  H  H  H  H  |
+ *         |         |         | (b)  L  H  H  H  H  H  H  H  H  | H  H  H  H  L  |
+ *    I7' -|4      13|-  I3'   +---------------------------------+----------------+
+ *         |         |         | (c)  L  x  x  x  x  x  x  x  L  | L  L  L  L  H  |
+ *    EI' -|5      12|-  I2'   | (d)  L  x  x  x  x  x  x  L  H  | L  H  L  L  H  |
+ *         |         |         | (e)  L  x  x  x  x  x  L  H  H  | L  L  H  L  H  |
+ *    Q2' -|6      11|-  I1'   | (f)  L  x  x  x  x  L  H  H  H  | L  H  H  L  H  |
+ *         |         |         | (g)  L  x  x  x  L  H  H  H  H  | L  L  L  H  H  |
+ *    Q1' -|7      10|-  I0'   | (h)  L  x  x  L  H  H  H  H  H  | L  H  L  H  H  |
+ *         |         |         | (i)  L  x  L  H  H  H  H  H  H  | L  L  H  H  H  |
+ *   GND  -|8       9|-  Q0'   | (j)  L  L  H  H  H  H  H  H  H  | L  H  H  H  H  |
+ *         |         |         +---------------------------------+----------------+
+ *         +---------+
+ * 
+ */ +inline uint8_t f9318(uint16_t in) +{ + uint8_t out; + + if (in & PRIO_IN_EI) { + out = PRIO_OUT_EO | PRIO_OUT_GS | PRIO_OUT_QZ; + return out; + } + + if (0 == (in & PRIO_I7)) { + out = PRIO_OUT_EO; + return out; + } + + if (PRIO_I7 == (in & PRIO_I6_I7)) { + out = PRIO_OUT_EO | PRIO_OUT_Q0; + return out; + } + + if (PRIO_I6_I7 == (in & PRIO_I5_I7)) { + out = PRIO_OUT_EO | PRIO_OUT_Q1; + return out; + } + + if (PRIO_I5_I7 == (in & PRIO_I4_I7)) { + out = PRIO_OUT_EO | PRIO_OUT_Q0 | PRIO_OUT_Q1; + return out; + } + + if (PRIO_I4_I7 == (in & PRIO_I3_I7)) { + out = PRIO_OUT_EO | PRIO_OUT_Q2; + return out; + } + + if (PRIO_I3_I7 == (in & PRIO_I2_I7)) { + out = PRIO_OUT_EO | PRIO_OUT_Q0 | PRIO_OUT_Q2; + return out; + } + + if (PRIO_I2_I7 == (in & PRIO_I1_I7)) { + out = PRIO_OUT_EO | PRIO_OUT_Q1 | PRIO_OUT_Q2; + return out; + } + + if (PRIO_I1_I7 == (in & PRIO_I0_I7)) { + out = PRIO_OUT_EO | PRIO_OUT_Q0 | PRIO_OUT_Q1 | PRIO_OUT_Q2; + return out; + } + + out = PRIO_OUT_QZ | PRIO_OUT_GS; + return out; +} + +} + +//************************************************************************** +// DRIVER CLASS +//************************************************************************** + +class nabupc_state : public driver_device +{ +public: + nabupc_state(const machine_config &mconfig, device_type type, const char *tag) + : driver_device(mconfig, type, tag) + , m_maincpu(*this, "maincpu") + , m_tms9928a(*this, "tms9928a") + , m_screen(*this, "screen") + , m_ay8910(*this, "ay8910") + , m_speaker(*this, "speaker") + , m_kbduart(*this, "kbduart") + , m_hccauart(*this, "hccauart") + , m_rom_view(*this, "rom") + , m_centronics(*this, "centronics") + , m_bus(*this, "bus") + , m_rom_base(*this, "bios") + , m_bios_sel(*this, "CONFIG") + , m_leds(*this, "led%u", 0U) + , m_irq_in_prio(PRIO_I0_I7) + , m_int_lines(0) + , m_porta(0) + , m_portb(0) + , m_control(0) + { + } + + void nabupc(machine_config &config); + +protected: + virtual void machine_start() override; + virtual void machine_reset() override; + +private: + void memory_map(address_map &map); + void io_map(address_map &map); + uint8_t read_mem(offs_t offset); + + uint8_t psg_portb_r(); + void psg_porta_w(uint8_t data); + void control_w(uint8_t data); + void centronics_busy_handler(uint8_t state); + void update_irq(); + + DECLARE_WRITE_LINE_MEMBER(hcca_fe_w); + DECLARE_WRITE_LINE_MEMBER(hcca_oe_w); + + template + DECLARE_WRITE_LINE_MEMBER(int_w); + + IRQ_CALLBACK_MEMBER(int_ack_cb); + + required_device m_maincpu; + required_device m_tms9928a; + required_device m_screen; + required_device m_ay8910; + required_device m_speaker; + required_device m_kbduart; + required_device m_hccauart; + memory_view m_rom_view; + required_device m_centronics; + required_device m_bus; + required_region_ptr m_rom_base; + required_ioport m_bios_sel; + + output_finder<4> m_leds; + + uint16_t m_irq_in_prio; + uint8_t m_int_lines; + uint8_t m_porta; + uint8_t m_portb; + uint8_t m_control; + uint16_t m_bios_size; +}; + +//************************************************************************** +// INPUT PORTS +//************************************************************************** + +// CONFIG Input Port +static INPUT_PORTS_START( nabupc ) + PORT_START("CONFIG") + PORT_CONFNAME( 0x03, 0x02, "BIOS Size" ) + PORT_CONFSETTING( 0x02, "4k BIOS" ) + PORT_CONFSETTING( 0x01, "8k BIOS" ) +INPUT_PORTS_END + + +//************************************************************************** +// Peripheral Devices +//************************************************************************** + +// HCCA Devices +static void hcca_devices(device_slot_interface &device) +{ + device.option_add("pty", PSEUDO_TERMINAL); + device.option_add("null_modem", NULL_MODEM); + device.option_add("hcca_adapter", NABUPC_NETWORK_ADAPTER); +} + +// Keyboard Devices +static void keyboard_devices(device_slot_interface &device) +{ + device.option_add("nabu", NABUPC_KEYBOARD); + device.option_add("nabu_hle", NABUPC_HLE_KEYBOARD); +} + +//************************************************************************** +// MACHINE CONFIGURATION +//************************************************************************** + +void nabupc_state::nabupc(machine_config &config) +{ + // Front Panel LEDS + config.set_default_layout(layout_nabupc); + + // CPU + Z80(config, m_maincpu, 10.738635_MHz_XTAL / 3); // 3.579545 MHz + m_maincpu->set_addrmap(AS_PROGRAM, &nabupc_state::memory_map); + m_maincpu->set_addrmap(AS_IO, &nabupc_state::io_map); + m_maincpu->set_irq_acknowledge_callback(FUNC(nabupc_state::int_ack_cb)); + + // Video hardware + SCREEN(config, m_screen, SCREEN_TYPE_RASTER); + + TMS9918A(config, m_tms9928a, 10.738635_MHz_XTAL); + m_tms9928a->set_screen(m_screen); + m_tms9928a->set_vram_size(0x4000); + m_tms9928a->int_callback().set(*this, FUNC(nabupc_state::int_w<4>)); + + // Sound hardware + SPEAKER(config, m_speaker).front_center(); + + AY8910(config, m_ay8910, 10.738635_MHz_XTAL / 6); + m_ay8910->set_flags(AY8910_SINGLE_OUTPUT); + m_ay8910->port_b_read_callback().set(FUNC(nabupc_state::psg_portb_r)); + m_ay8910->port_a_write_callback().set(FUNC(nabupc_state::psg_porta_w)); + m_ay8910->add_route(ALL_OUTPUTS, m_speaker, 0.3); + + // Keyboard + I8251(config, m_kbduart, 10.738635_MHz_XTAL / 6); + m_kbduart->rxrdy_handler().set(*this, FUNC(nabupc_state::int_w<5>)); + + rs232_port_device &kbd(RS232_PORT(config, "kbd", keyboard_devices, "nabu")); + kbd.rxd_handler().set(m_kbduart, FUNC(i8251_device::write_rxd)); + + // HCCA + AY31015(config, m_hccauart); + m_hccauart->set_auto_rdav(true); + m_hccauart->write_dav_callback().set(FUNC(nabupc_state::int_w<7>)); + m_hccauart->write_tbmt_callback().set(FUNC(nabupc_state::int_w<6>)); + m_hccauart->write_fe_callback().set(FUNC(nabupc_state::hcca_fe_w)); + m_hccauart->write_or_callback().set(FUNC(nabupc_state::hcca_oe_w)); + m_hccauart->write_so_callback().set("hcca", FUNC(rs232_port_device::write_txd)); + + rs232_port_device &hcca(RS232_PORT(config, "hcca", hcca_devices, "pty")); + hcca.rxd_handler().set(m_hccauart, FUNC(ay31015_device::write_si)); + + // Printer + output_latch_device &prndata(OUTPUT_LATCH(config, "prndata")); + CENTRONICS(config, m_centronics, centronics_devices, nullptr); + m_centronics->set_output_latch(prndata); + m_centronics->busy_handler().set(FUNC(nabupc_state::centronics_busy_handler)); + + // Clocks + clock_device &sclk(CLOCK(config, "sclk", 10.738635_MHz_XTAL / 96)); // 111.9 kHz Clock + sclk.signal_handler().set(m_kbduart, FUNC(i8251_device::write_rxc)); + + clock_device &pclk(CLOCK(config, "pclk", 10.738635_MHz_XTAL / 6)); // 1.79 Mhz Clock + pclk.signal_handler().set(m_hccauart, FUNC(ay31015_device::write_rcp)); + pclk.signal_handler().append(m_hccauart, FUNC(ay31015_device::write_tcp)); + + // Bus + NABUPC_OPTION_BUS(config, m_bus, 10.738635_MHz_XTAL / 3); + m_bus->out_int_callback<0>().set(FUNC(nabupc_state::int_w<3>)).invert(); + m_bus->out_int_callback<1>().set(FUNC(nabupc_state::int_w<2>)).invert(); + m_bus->out_int_callback<2>().set(FUNC(nabupc_state::int_w<1>)).invert(); + m_bus->out_int_callback<3>().set(FUNC(nabupc_state::int_w<0>)).invert(); + NABUPC_OPTION_BUS_SLOT(config, "option1", m_bus, 0, bus::nabupc::option_bus_devices, nullptr); + NABUPC_OPTION_BUS_SLOT(config, "option2", m_bus, 1, bus::nabupc::option_bus_devices, nullptr); + NABUPC_OPTION_BUS_SLOT(config, "option3", m_bus, 2, bus::nabupc::option_bus_devices, nullptr); + NABUPC_OPTION_BUS_SLOT(config, "option4", m_bus, 3, bus::nabupc::option_bus_devices, nullptr); +} + + +//************************************************************************** +// MACHINE INITIALIZATION +//************************************************************************** + +// Machine Start +void nabupc_state::machine_start() +{ + m_leds.resolve(); + + m_hccauart->write_np(1); + m_hccauart->write_nb2(1); + m_hccauart->write_nb1(1); + m_hccauart->write_eps(0); + m_hccauart->write_tsb(0); + m_hccauart->write_cs(1); + m_hccauart->write_swe(0); + + save_item(NAME(m_irq_in_prio)); + save_item(NAME(m_int_lines)); + save_item(NAME(m_porta)); + save_item(NAME(m_portb)); + save_item(NAME(m_control)); + save_item(NAME(m_bios_size)); + +} + +// Machine Reset +void nabupc_state::machine_reset() +{ + m_irq_in_prio = PRIO_I0_I7; + m_int_lines = 0; + m_porta = 0; + m_portb &= 0x70; + m_control = 0; + m_bios_size = m_bios_sel->read() == 1 ? 0x2000 : 0x1000; + m_leds[0] = 1; // Power LED + + m_rom_view[0].install_rom(0x0000, m_bios_size - 1, m_rom_base); + m_rom_view.select(0); +} + + +//************************************************************************** +// Control/Status Ports +//************************************************************************** + +// Control Register +void nabupc_state::control_w(uint8_t data) +{ + m_control = data; + m_centronics->write_strobe(BIT(m_control, 2)); + for (int i = 3 ; i < 6 ; ++i) { + m_leds[6 - i] = BIT(m_control, i); + } + if ((m_control & 1) == 0) { + m_rom_view.select(0); + } else { + m_rom_view.disable(); + } +} + +// Status Port +uint8_t nabupc_state::psg_portb_r() +{ + return m_portb; +} + +// Interrupt Enable Port +void nabupc_state::psg_porta_w(uint8_t data) +{ + if (data != m_porta) { + m_porta = data; + update_irq(); + } +} + +// Printer Busy State +void nabupc_state::centronics_busy_handler(uint8_t state) +{ + BIT_SET(m_portb, 4, state); +} + +// HCCA Framing Error +WRITE_LINE_MEMBER(nabupc_state::hcca_fe_w) +{ + BIT_SET(m_portb, 5, state); +} + +// HCCA Overrun Error +WRITE_LINE_MEMBER(nabupc_state::hcca_oe_w) +{ + BIT_SET(m_portb, 6, state); +} + + +//************************************************************************** +// Interrupt Handling +//************************************************************************** + +template +WRITE_LINE_MEMBER(nabupc_state::int_w) +{ + BIT_SET(m_int_lines, N, state); + update_irq(); +} + +// IRQ Acknowledge +IRQ_CALLBACK_MEMBER(nabupc_state::int_ack_cb) +{ + uint32_t vector = m_portb & 0xe; + return vector; +} + +// Update CPU IRQ line +void nabupc_state::update_irq() +{ + uint8_t interrupts = ~(m_porta & m_int_lines); + m_irq_in_prio = (m_irq_in_prio & 0xff00) | interrupts; + + m_portb &= 0xf0; + uint8_t out = f9318(m_irq_in_prio); + m_portb |= bitswap(out, 2, 1, 0, 3); + m_maincpu->set_input_line(INPUT_LINE_IRQ0, !(BIT(out, 4))); +} + + +//************************************************************************** +// ADDRESS MAPS +//************************************************************************** + +// RAM/ROM +void nabupc_state::memory_map(address_map &map) +{ + map(0x0000, 0xffff).ram(); + map(0x0000, 0x2000).view(m_rom_view); +} + +// IO Memory +void nabupc_state::io_map(address_map &map) +{ + map.unmap_value_high(); + map.global_mask(0xff); + map(0x00, 0x00).w(FUNC(nabupc_state::control_w)); + map(0x40, 0x40).r(m_ay8910, FUNC(ay8910_device::data_r)); + map(0x40, 0x41).w(m_ay8910, FUNC(ay8910_device::data_address_w)); + map(0x80, 0x80).rw(m_hccauart, FUNC(ay31015_device::receive), FUNC(ay31015_device::transmit)); + map(0x90, 0x91).rw(m_kbduart, FUNC(i8251_device::read), FUNC(i8251_device::write)); + map(0xa0, 0xa1).rw(m_tms9928a, FUNC(tms9928a_device::read), FUNC(tms9928a_device::write)); + map(0xb0, 0xb0).w("prndata", FUNC(output_latch_device::write)); + map(0xc0, 0xcf).rw(m_bus, FUNC(bus::nabupc::option_bus_device::read<0>), FUNC(bus::nabupc::option_bus_device::write<0>)); + map(0xd0, 0xdf).rw(m_bus, FUNC(bus::nabupc::option_bus_device::read<1>), FUNC(bus::nabupc::option_bus_device::write<1>)); + map(0xe0, 0xef).rw(m_bus, FUNC(bus::nabupc::option_bus_device::read<2>), FUNC(bus::nabupc::option_bus_device::write<2>)); + map(0xf0, 0xff).rw(m_bus, FUNC(bus::nabupc::option_bus_device::read<3>), FUNC(bus::nabupc::option_bus_device::write<3>)); +} + +//************************************************************************** +// BIOS ROMS +//************************************************************************** + +ROM_START( nabupc ) + ROM_REGION( 0x2000, "bios", 0 ) + ROM_SYSTEM_BIOS( 0, "reva", "4k BIOS" ) + ROMX_LOAD( "nabupc-u53-90020060-reva-2732.bin", 0x0000, 0x1000, CRC(8110bde0) SHA1(57e5f34645df06d7cb6c202a6d35a442776af2cb), ROM_BIOS(0) ) + ROM_RELOAD(0x1000, 0x1000) + ROM_SYSTEM_BIOS( 1, "revb", "8k BIOS - Floppy support" ) + ROMX_LOAD( "nabupc-u53-90020060-revb-2764.bin", 0x0000, 0x2000, CRC(3088f21b) SHA1(bf2f1eb5d9f5a8e9d022ce0056f2a5a8526b830e), ROM_BIOS(1) ) +ROM_END + + +/*************************************************************************** + SYSTEM DRIVERS +***************************************************************************/ + +/* YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME */ +COMP(1982, nabupc, 0, 0, nabupc, nabupc, nabupc_state, empty_init, "NABU", "NABU PC", 0) + -- cgit v1.2.3