diff options
Diffstat (limited to 'src/devices')
145 files changed, 9757 insertions, 4011 deletions
diff --git a/src/devices/bus/a2bus/a2scsi.cpp b/src/devices/bus/a2bus/a2scsi.cpp index 014414e7e98..988ebfd0096 100644 --- a/src/devices/bus/a2bus/a2scsi.cpp +++ b/src/devices/bus/a2bus/a2scsi.cpp @@ -74,7 +74,7 @@ void a2bus_scsi_device::device_add_mconfig(machine_config &config) { NSCSI_BUS(config, m_scsibus); NSCSI_CONNECTOR(config, "scsibus:0", scsi_devices, nullptr, false); - NSCSI_CONNECTOR(config, "scsibus:1", scsi_devices, nullptr, false); + NSCSI_CONNECTOR(config, "scsibus:1", scsi_devices, "cdrom", false); NSCSI_CONNECTOR(config, "scsibus:2", scsi_devices, nullptr, false); NSCSI_CONNECTOR(config, "scsibus:3", scsi_devices, nullptr, false); NSCSI_CONNECTOR(config, "scsibus:4", scsi_devices, nullptr, false); diff --git a/src/devices/bus/a2bus/a2zipdrive.cpp b/src/devices/bus/a2bus/a2zipdrive.cpp index aaeb6ed6219..41034fab231 100644 --- a/src/devices/bus/a2bus/a2zipdrive.cpp +++ b/src/devices/bus/a2bus/a2zipdrive.cpp @@ -2,16 +2,19 @@ // copyright-holders:R. Belmont /********************************************************************* - a2zipdrive.c + a2zipdrive.cpp ZIP Technologies ZipDrive IDE card + Parsons Engineering Focus Drive IDE card - NOTE: No known dump exists of the formatter utility and the + These cards are very, very similar. Maybe Parsons designed both? + + NOTE: No known dump exists of the Zip formatter utility and the format of the custom partition record (block 0) that the card expects has not yet been determined, so this is largely untested and will work only with a drive dump from real h/w. - PLEASE use it only on a backup copy of said dump and contact MESSdev + PLEASE use it only on a backup copy of said dump and contact MAMEdev if you have one! Partition block format: @@ -29,6 +32,7 @@ //************************************************************************** DEFINE_DEVICE_TYPE(A2BUS_ZIPDRIVE, a2bus_zipdrive_device, "a2zipdrv", "Zip Technologies ZipDrive") +DEFINE_DEVICE_TYPE(A2BUS_FOCUSDRIVE, a2bus_focusdrive_device, "a2focdrv", "Parsons Engineering Focus Drive") #define ZIPDRIVE_ROM_REGION "zipdrive_rom" #define ZIPDRIVE_ATA_TAG "zipdrive_ata" @@ -38,6 +42,11 @@ ROM_START( zipdrive ) ROM_LOAD( "zip drive - rom.bin", 0x000000, 0x002000, CRC(fd800a40) SHA1(46636bfed88c864139e3d2826661908a8c07c459) ) ROM_END +ROM_START( focusdrive ) + ROM_REGION(0x2000, ZIPDRIVE_ROM_REGION, 0) + ROM_LOAD( "focusrom.bin", 0x001000, 0x001000, CRC(0fd0ba25) SHA1(acf414aa145fcfa1c12aca0269f1f7ada82f1c04) ) +ROM_END + /*************************************************************************** FUNCTION PROTOTYPES ***************************************************************************/ @@ -60,6 +69,11 @@ const tiny_rom_entry *a2bus_zipdrivebase_device::device_rom_region() const return ROM_NAME( zipdrive ); } +const tiny_rom_entry *a2bus_focusdrive_device::device_rom_region() const +{ + return ROM_NAME( focusdrive ); +} + //************************************************************************** // LIVE DEVICE //************************************************************************** @@ -76,6 +90,11 @@ a2bus_zipdrive_device::a2bus_zipdrive_device(const machine_config &mconfig, cons { } +a2bus_focusdrive_device::a2bus_focusdrive_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : + a2bus_zipdrivebase_device(mconfig, A2BUS_FOCUSDRIVE, tag, owner, clock) +{ +} + //------------------------------------------------- // device_start - device-specific startup //------------------------------------------------- @@ -89,9 +108,12 @@ void a2bus_zipdrivebase_device::device_start() void a2bus_zipdrivebase_device::device_reset() { - popmessage("Zip Drive partition format unknown, contact MESSdev if you have the software or a drive dump!"); } +void a2bus_focusdrive_device::device_reset() +{ + m_rom[0x1c6c] = 0x03; // eat 3 IDE words here instead of 1, fixes a bug? in the original ROM +} /*------------------------------------------------- read_c0nx - called for reads from this card's c0nx space @@ -112,7 +134,7 @@ uint8_t a2bus_zipdrivebase_device::read_c0nx(uint8_t offset) return m_ata->read_cs0(offset, 0xff); case 8: // data port - m_lastdata = m_ata->read_cs0(offset); + m_lastdata = m_ata->read_cs0(offset, 0xffff); // printf("%04x @ IDE data\n", m_lastdata); return m_lastdata&0xff; @@ -120,13 +142,42 @@ uint8_t a2bus_zipdrivebase_device::read_c0nx(uint8_t offset) return (m_lastdata>>8) & 0xff; default: - logerror("a2zipdrive: unhandled read @ C0n%x\n", offset); + logerror("unhandled read @ C0n%x\n", offset); break; } return 0xff; } +uint8_t a2bus_focusdrive_device::read_c0nx(uint8_t offset) +{ + switch (offset) + { + case 8: + case 9: + case 0xa: + case 0xb: + case 0xc: + case 0xd: + case 0xe: + case 0xf: + return m_ata->read_cs0(offset&7, 0xff); + + case 0: // data port + m_lastdata = m_ata->read_cs0(offset, 0xffff); + //printf("%04x @ IDE data\n", m_lastdata); + return m_lastdata&0xff; + + case 1: + return (m_lastdata>>8) & 0xff; + + default: + logerror("unhandled read @ C0n%x\n", offset); + break; + } + + return 0xff; +} /*------------------------------------------------- write_c0nx - called for writes to this card's c0nx space @@ -157,7 +208,7 @@ void a2bus_zipdrivebase_device::write_c0nx(uint8_t offset, uint8_t data) // printf("%02x to IDE data hi\n", data); m_lastdata &= 0x00ff; m_lastdata |= (data << 8); - m_ata->write_cs0(0, m_lastdata); + m_ata->write_cs0(0, m_lastdata, 0xffff); break; default: @@ -166,6 +217,48 @@ void a2bus_zipdrivebase_device::write_c0nx(uint8_t offset, uint8_t data) } } +void a2bus_focusdrive_device::write_c0nx(uint8_t offset, uint8_t data) +{ + switch (offset) + { + case 8: + case 9: + case 0xa: + case 0xb: + case 0xc: + case 0xd: + case 0xe: + case 0xf: + // due to a bug in the 6502 firmware, eat data if DRQ is set + #if 0 + while (m_ata->read_cs0(7, 0xff) & 0x08) + { + m_ata->read_cs0(0, 0xffff); + printf("eating 2 bytes to clear DRQ\n"); + } + #endif +// printf("%02x to IDE controller @ %x\n", data, offset); + m_ata->write_cs0(offset & 7, data, 0xff); + break; + + case 0: +// printf("%02x to IDE data lo\n", data); + m_lastdata = data; + break; + + case 1: +// printf("%02x to IDE data hi\n", data); + m_lastdata &= 0x00ff; + m_lastdata |= (data << 8); + m_ata->write_cs0(0, m_lastdata, 0xffff); + break; + + default: + printf("focus: write %02x @ unhandled C0n%x\n", data, offset); + break; + } +} + /*------------------------------------------------- read_cnxx - called for reads from this card's cnxx space -------------------------------------------------*/ diff --git a/src/devices/bus/a2bus/a2zipdrive.h b/src/devices/bus/a2bus/a2zipdrive.h index 8187e04cdd2..9e3e68e79f2 100644 --- a/src/devices/bus/a2bus/a2zipdrive.h +++ b/src/devices/bus/a2bus/a2zipdrive.h @@ -5,8 +5,9 @@ a2zipdrive.h ZIP Technologies ZipDrive IDE card + Parsons Engineering Focus Drive IDE card - See important NOTE at the top of a2zipdrive.c! + See important NOTE at the top of a2zipdrive.cpp! *********************************************************************/ @@ -44,8 +45,6 @@ protected: required_device<ata_interface_device> m_ata; uint8_t *m_rom; - -private: uint16_t m_lastdata; }; @@ -55,7 +54,20 @@ public: a2bus_zipdrive_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); }; +class a2bus_focusdrive_device : public a2bus_zipdrivebase_device +{ +public: + a2bus_focusdrive_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + +protected: + virtual void device_reset() override; + virtual const tiny_rom_entry *device_rom_region() const override; + virtual uint8_t read_c0nx(uint8_t offset) override; + virtual void write_c0nx(uint8_t offset, uint8_t data) override; +}; + // device type definition DECLARE_DEVICE_TYPE(A2BUS_ZIPDRIVE, a2bus_zipdrive_device) +DECLARE_DEVICE_TYPE(A2BUS_FOCUSDRIVE, a2bus_focusdrive_device) #endif // MAME_BUS_A2BUS_ZIPDRIVE_H diff --git a/src/devices/bus/astrocde/accessory.cpp b/src/devices/bus/astrocde/accessory.cpp new file mode 100644 index 00000000000..fe7727b855d --- /dev/null +++ b/src/devices/bus/astrocde/accessory.cpp @@ -0,0 +1,112 @@ +// license:BSD-3-Clause +// copyright-holders:Ryan Holtz + +#include "emu.h" +#include "accessory.h" + +#include <cassert> + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +DEFINE_DEVICE_TYPE(ASTROCADE_ACCESSORY_PORT, astrocade_accessory_port_device, "astrocade_accessory_port", "Bally Astrocade Accessory Port") + + +//************************************************************************** +// Bally Astrocade accessory interface +//************************************************************************** + +device_astrocade_accessory_interface::device_astrocade_accessory_interface(const machine_config &mconfig, device_t &device) + : device_slot_card_interface(mconfig, device) + , m_port(dynamic_cast<astrocade_accessory_port_device *>(device.owner())) +{ +} + +device_astrocade_accessory_interface::~device_astrocade_accessory_interface() +{ +} + +void device_astrocade_accessory_interface::interface_validity_check(validity_checker &valid) const +{ + device_slot_card_interface::interface_validity_check(valid); + + if (device().owner() && !m_port) + { + osd_printf_error("Owner device %s (%s) is not an astrocade_accessory_port_device\n", device().owner()->tag(), device().owner()->name()); + } +} + +void device_astrocade_accessory_interface::interface_pre_start() +{ + device_slot_card_interface::interface_pre_start(); + + if (m_port && !m_port->started()) + throw device_missing_dependencies(); +} + + +//************************************************************************** +// Bally Astrocade accessory port +//************************************************************************** + +astrocade_accessory_port_device::astrocade_accessory_port_device(machine_config const &mconfig, char const *tag, device_t *owner, uint32_t clock) + : device_t(mconfig, ASTROCADE_ACCESSORY_PORT, tag, owner, clock) + , device_slot_interface(mconfig, *this) + , m_ltpen(0) + , m_ltpen_handler(*this) + , m_screen(*this, finder_base::DUMMY_TAG) + , m_device(nullptr) +{ +} + +astrocade_accessory_port_device::~astrocade_accessory_port_device() +{ +} + +void astrocade_accessory_port_device::device_validity_check(validity_checker &valid) const +{ + device_t *const card(get_card_device()); + if (card && !dynamic_cast<device_astrocade_accessory_interface *>(card)) + { + osd_printf_error("Card device %s (%s) does not implement device_astrocade_accessory_interface\n", card->tag(), card->name()); + } +} + +void astrocade_accessory_port_device::device_resolve_objects() +{ + device_astrocade_accessory_interface *const card(dynamic_cast<device_astrocade_accessory_interface *>(get_card_device())); + if (card) + { + m_device = card; + m_device->set_screen(m_screen); + } + + m_ltpen_handler.resolve_safe(); +} + +void astrocade_accessory_port_device::device_start() +{ + device_t *const card(get_card_device()); + if (card) + { + if (!m_device) + { + throw emu_fatalerror("astrocade_accessory_port_device: card device %s (%s) does not implement device_astrocade_accessory_interface\n", card->tag(), card->name()); + } + } + + save_item(NAME(m_ltpen)); + + m_ltpen = 0; + + m_ltpen_handler(0); +} + +#include "lightpen.h" + +void astrocade_accessories(device_slot_interface &device) +{ + device.option_add("lightpen", ASTROCADE_LIGHTPEN); +} diff --git a/src/devices/bus/astrocde/accessory.h b/src/devices/bus/astrocde/accessory.h new file mode 100644 index 00000000000..d745e464cd2 --- /dev/null +++ b/src/devices/bus/astrocde/accessory.h @@ -0,0 +1,99 @@ +// license:BSD-3-Clause +// copyright-holders:Ryan Holtz +#ifndef MAME_BUS_ASTROCDE_ACCESSORY_H +#define MAME_BUS_ASTROCDE_ACCESSORY_H + +#pragma once + +#include "screen.h" + + +/*************************************************************************** + FORWARD DECLARATIONS + ***************************************************************************/ + +class device_astrocade_accessory_interface; + + +/*************************************************************************** + TYPE DEFINITIONS + ***************************************************************************/ + +// ======================> astrocade_accessory_port_device + +class astrocade_accessory_port_device : public device_t, public device_slot_interface +{ +public: + // construction/destruction + template <typename T, typename U> + astrocade_accessory_port_device(machine_config const &mconfig, char const *tag, device_t *owner, T &&screen_tag, U &&opts, char const *dflt) + : astrocade_accessory_port_device(mconfig, tag, owner, 0U) + { + m_screen.set_tag(std::forward<T>(screen_tag)); + option_reset(); + opts(*this); + set_default_option(dflt); + set_fixed(false); + } + astrocade_accessory_port_device(machine_config const &mconfig, char const *tag, device_t *owner, uint32_t clock = 0U); + virtual ~astrocade_accessory_port_device(); + + auto ltpen_handler() { return m_ltpen_handler.bind(); } + +protected: + // device_t implementation + virtual void device_validity_check(validity_checker &valid) const override ATTR_COLD; + virtual void device_resolve_objects() override; + virtual void device_start() override; + + int m_ltpen; + devcb_write_line m_ltpen_handler; + required_device<screen_device> m_screen; + +private: + device_astrocade_accessory_interface *m_device; + + friend class device_astrocade_accessory_interface; +}; + + +// ======================> device_astrocade_accessory_interface + +class device_astrocade_accessory_interface : public device_slot_card_interface +{ +public: + virtual ~device_astrocade_accessory_interface(); + + DECLARE_WRITE_LINE_MEMBER( write_ltpen ) { m_port->m_ltpen = state; m_port->m_ltpen_handler(state); } + +protected: + device_astrocade_accessory_interface(machine_config const &mconfig, device_t &device); + + // device_interface implementation + virtual void interface_validity_check(validity_checker &valid) const override ATTR_COLD; + virtual void interface_pre_start() override; + + void set_screen(screen_device *screen) { m_screen = screen; } + screen_device *m_screen; + +private: + astrocade_accessory_port_device *const m_port; + + friend class astrocade_accessory_port_device; +}; + + +/*************************************************************************** + FUNCTIONS + ***************************************************************************/ + +void astrocade_accessories(device_slot_interface &device); + + +/*************************************************************************** + DEVICE TYPES + ***************************************************************************/ + +DECLARE_DEVICE_TYPE(ASTROCADE_ACCESSORY_PORT, astrocade_accessory_port_device) + +#endif // MAME_BUS_ASTROCDE_ACCESSORY_H diff --git a/src/devices/bus/astrocde/cassette.cpp b/src/devices/bus/astrocde/cassette.cpp index 789b0d7e175..3e4cc80deb8 100644 --- a/src/devices/bus/astrocde/cassette.cpp +++ b/src/devices/bus/astrocde/cassette.cpp @@ -1,5 +1,8 @@ // license:BSD-3-Clause // copyright-holders:Ryan Holtz +// +// Decoding is done in hardware by an external box, and decoded bits are fed to bit 0 of the controller port, +// with sync bits being fed to bit 1. The current HLE is not remotely accurate to hardware, but works. #include "emu.h" #include "cassette.h" @@ -26,22 +29,102 @@ astrocade_cassette_device::~astrocade_cassette_device() { } +void astrocade_cassette_device::device_start() +{ + save_item(NAME(m_cass_wave)); + save_item(NAME(m_cass_delta)); + save_item(NAME(m_cass_wave_ticks)); + save_item(NAME(m_cass_cycles)); + save_item(NAME(m_cass_mark)); +} + +void astrocade_cassette_device::device_reset() +{ + m_cass_wave = 0.0; + m_cass_delta = 0.0; + m_cass_wave_ticks = 0; + m_cass_cycles = 0; + m_cass_mark = false; +} + uint8_t astrocade_cassette_device::read_handle() { - uint8_t data = m_cassette->input() > 0.0 ? 0 : 1; - logerror("%s: Cassette Handle Read: %d\n", machine().describe_context(), data); - return data; + if (m_cass_data.size()) + { + const uint8_t data = m_cass_data.front(); + m_cass_data.pop(); + return data; + } + return 0; } uint8_t astrocade_cassette_device::read_knob() { - logerror("%s: Cassette Knob Read\n", machine().describe_context()); return 0; } +TIMER_DEVICE_CALLBACK_MEMBER(astrocade_cassette_device::check_cassette_wave) +{ + if (m_cassette->get_state() & CASSETTE_MOTOR_DISABLED) + return; + + double old_cass_wave = m_cass_wave; + m_cass_wave = m_cassette->input(); + + bool cycled = false; + if (old_cass_wave != m_cass_wave) + { + double old_delta = m_cass_delta; + m_cass_delta = m_cass_wave - old_cass_wave; + if (old_delta < 0.0 && m_cass_delta > 0.0) + { + cycled = true; + } + } + + if (cycled) + { + m_cass_mark = m_cass_wave_ticks <= 30; + + m_cass_wave_ticks = 0; + + m_cass_cycles++; + if (m_cass_mark) + { + if (m_cass_cycles >= 8) + { + m_cass_data.push(1); + m_cass_cycles = 0; + } + } + else + { + if (m_cass_cycles >= 4) + { + m_cass_data.push(0); + m_cass_cycles = 0; + } + } + } + + m_cass_wave_ticks++; +} + +TIMER_DEVICE_CALLBACK_MEMBER(astrocade_cassette_device::pulse_cassette_clock) +{ + if (m_cass_data.size()) + { + write_ltpen(1); + write_ltpen(0); + } +} + void astrocade_cassette_device::device_add_mconfig(machine_config &config) { CASSETTE(config, m_cassette); m_cassette->set_default_state(CASSETTE_STOPPED); m_cassette->set_interface("astrocade_cass"); + + TIMER(config, "kcs_hle").configure_periodic(FUNC(astrocade_cassette_device::check_cassette_wave), attotime::from_hz(48000)); + TIMER(config, "kcs_clk").configure_periodic(FUNC(astrocade_cassette_device::pulse_cassette_clock), attotime::from_hz(300)); } diff --git a/src/devices/bus/astrocde/cassette.h b/src/devices/bus/astrocde/cassette.h index bcbfd697a50..d36e8a1bfd7 100644 --- a/src/devices/bus/astrocde/cassette.h +++ b/src/devices/bus/astrocde/cassette.h @@ -7,6 +7,10 @@ #include "ctrl.h" #include "imagedev/cassette.h" +#include "machine/timer.h" + +#include <queue> + /*************************************************************************** TYPE DEFINITIONS @@ -15,7 +19,7 @@ // ======================> astrocade_cassette_device class astrocade_cassette_device : public device_t, - public device_astrocade_ctrl_interface + public device_astrocade_ctrl_interface { public: static constexpr feature_type imperfect_features() { return feature::TAPE; } @@ -30,11 +34,21 @@ public: protected: // device_t implementation - virtual void device_start() override { } + virtual void device_start() override; + virtual void device_reset() override; virtual void device_add_mconfig(machine_config &config) override; + TIMER_DEVICE_CALLBACK_MEMBER(check_cassette_wave); + TIMER_DEVICE_CALLBACK_MEMBER(pulse_cassette_clock); + private: required_device<cassette_image_device> m_cassette; + double m_cass_wave; + double m_cass_delta; + uint32_t m_cass_wave_ticks; + uint32_t m_cass_cycles; + bool m_cass_mark; + std::queue<uint8_t> m_cass_data; }; diff --git a/src/devices/bus/astrocde/ctrl.cpp b/src/devices/bus/astrocde/ctrl.cpp index 16b8537eae4..89cd60ca6a5 100644 --- a/src/devices/bus/astrocde/ctrl.cpp +++ b/src/devices/bus/astrocde/ctrl.cpp @@ -54,6 +54,9 @@ void device_astrocade_ctrl_interface::interface_pre_start() astrocade_ctrl_port_device::astrocade_ctrl_port_device(machine_config const &mconfig, char const *tag, device_t *owner, uint32_t clock) : device_t(mconfig, ASTROCADE_CTRL_PORT, tag, owner, clock) , device_slot_interface(mconfig, *this) + , m_ltpen(0) + , m_ltpen_handler(*this) + , m_device(nullptr) { } @@ -75,6 +78,8 @@ void astrocade_ctrl_port_device::device_resolve_objects() device_astrocade_ctrl_interface *const card(dynamic_cast<device_astrocade_ctrl_interface *>(get_card_device())); if (card) m_device = card; + + m_ltpen_handler.resolve_safe(); } void astrocade_ctrl_port_device::device_start() @@ -87,6 +92,12 @@ void astrocade_ctrl_port_device::device_start() throw emu_fatalerror("astrocade_ctrl_port_device: card device %s (%s) does not implement device_astrocade_ctrl_interface\n", card->tag(), card->name()); } } + + save_item(NAME(m_ltpen)); + + m_ltpen = 0; + + m_ltpen_handler(0); } uint8_t astrocade_ctrl_port_device::read_handle() diff --git a/src/devices/bus/astrocde/ctrl.h b/src/devices/bus/astrocde/ctrl.h index 7ff8acbde52..0cc34ea4dcc 100644 --- a/src/devices/bus/astrocde/ctrl.h +++ b/src/devices/bus/astrocde/ctrl.h @@ -10,37 +10,13 @@ FORWARD DECLARATIONS ***************************************************************************/ -class astrocade_ctrl_port_device; +class device_astrocade_ctrl_interface; /*************************************************************************** TYPE DEFINITIONS ***************************************************************************/ -// ======================> device_astrocade_ctrl_interface - -class device_astrocade_ctrl_interface : public device_slot_card_interface -{ -public: - virtual ~device_astrocade_ctrl_interface(); - - virtual uint8_t read_handle() { return 0; } - virtual uint8_t read_knob() { return 0; } - -protected: - device_astrocade_ctrl_interface(machine_config const &mconfig, device_t &device); - - // device_interface implementation - virtual void interface_validity_check(validity_checker &valid) const override ATTR_COLD; - virtual void interface_pre_start() override; - -private: - astrocade_ctrl_port_device *const m_port; - - friend class astrocade_ctrl_port_device; -}; - - // ======================> astrocade_ctrl_port_device class astrocade_ctrl_port_device : public device_t, public device_slot_interface @@ -59,6 +35,8 @@ public: astrocade_ctrl_port_device(machine_config const &mconfig, char const *tag, device_t *owner, uint32_t clock = 0U); virtual ~astrocade_ctrl_port_device(); + auto ltpen_handler() { return m_ltpen_handler.bind(); } + uint8_t read_handle(); uint8_t read_knob(); @@ -68,6 +46,9 @@ protected: virtual void device_resolve_objects() override; virtual void device_start() override; + int m_ltpen; + devcb_write_line m_ltpen_handler; + private: device_astrocade_ctrl_interface *m_device; @@ -75,6 +56,32 @@ private: }; +// ======================> device_astrocade_ctrl_interface + +class device_astrocade_ctrl_interface : public device_slot_card_interface +{ +public: + virtual ~device_astrocade_ctrl_interface(); + + virtual uint8_t read_handle() { return 0; } + virtual uint8_t read_knob() { return 0; } + + DECLARE_WRITE_LINE_MEMBER( write_ltpen ) { m_port->m_ltpen = state; m_port->m_ltpen_handler(state); } + +protected: + device_astrocade_ctrl_interface(machine_config const &mconfig, device_t &device); + + // device_interface implementation + virtual void interface_validity_check(validity_checker &valid) const override ATTR_COLD; + virtual void interface_pre_start() override; + +private: + astrocade_ctrl_port_device *const m_port; + + friend class astrocade_ctrl_port_device; +}; + + /*************************************************************************** FUNCTIONS ***************************************************************************/ diff --git a/src/devices/bus/astrocde/exp.cpp b/src/devices/bus/astrocde/exp.cpp index 40b6fbecbc4..9fe3c9f3fda 100644 --- a/src/devices/bus/astrocde/exp.cpp +++ b/src/devices/bus/astrocde/exp.cpp @@ -74,6 +74,14 @@ READ8_MEMBER(astrocade_exp_device::read) return 0xff; } +READ8_MEMBER(astrocade_exp_device::read_io) +{ + if (m_card) + return m_card->read_io(space, offset); + else + return 0xff; +} + /*------------------------------------------------- write -------------------------------------------------*/ @@ -83,3 +91,9 @@ WRITE8_MEMBER(astrocade_exp_device::write) if (m_card) m_card->write(space, offset, data); } + +WRITE8_MEMBER(astrocade_exp_device::write_io) +{ + if (m_card) + m_card->write_io(space, offset, data); +} diff --git a/src/devices/bus/astrocde/exp.h b/src/devices/bus/astrocde/exp.h index e6c97862224..a01db130974 100644 --- a/src/devices/bus/astrocde/exp.h +++ b/src/devices/bus/astrocde/exp.h @@ -14,6 +14,8 @@ public: // reading and writing virtual DECLARE_READ8_MEMBER(read) { return 0xff; } virtual DECLARE_WRITE8_MEMBER(write) { } + virtual DECLARE_READ8_MEMBER(read_io) { return 0xff; } + virtual DECLARE_WRITE8_MEMBER(write_io) { } protected: device_astrocade_card_interface(const machine_config &mconfig, device_t &device); @@ -46,6 +48,8 @@ public: // reading and writing virtual DECLARE_READ8_MEMBER(read); virtual DECLARE_WRITE8_MEMBER(write); + virtual DECLARE_READ8_MEMBER(read_io); + virtual DECLARE_WRITE8_MEMBER(write_io); protected: bool m_card_mounted; diff --git a/src/devices/bus/astrocde/joy.h b/src/devices/bus/astrocde/joy.h index 1db02b9d28f..bb8f755c845 100644 --- a/src/devices/bus/astrocde/joy.h +++ b/src/devices/bus/astrocde/joy.h @@ -14,7 +14,7 @@ // ======================> astrocade_joy_device class astrocade_joy_device : public device_t, - public device_astrocade_ctrl_interface + public device_astrocade_ctrl_interface { public: // construction/destruction diff --git a/src/devices/bus/astrocde/lightpen.cpp b/src/devices/bus/astrocde/lightpen.cpp new file mode 100644 index 00000000000..e31eed122be --- /dev/null +++ b/src/devices/bus/astrocde/lightpen.cpp @@ -0,0 +1,87 @@ +// license:BSD-3-Clause +// copyright-holders:Ryan Holtz + +#include "emu.h" +#include "lightpen.h" + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +DEFINE_DEVICE_TYPE(ASTROCADE_LIGHTPEN, astrocade_lightpen_device, "astrocade_lightpen", "Bally Astrocade Light Pen") + + +//************************************************************************** +// Bally Astrocade light pen input +//************************************************************************** + +astrocade_lightpen_device::astrocade_lightpen_device(machine_config const &mconfig, char const *tag, device_t *owner, uint32_t clock) + : device_t(mconfig, ASTROCADE_LIGHTPEN, tag, owner, clock) + , device_astrocade_accessory_interface(mconfig, *this) + , m_trigger(*this, "TRIGGER") + , m_lightx(*this, "LIGHTX") + , m_lighty(*this, "LIGHTY") + , m_pen_timer(nullptr) +{ +} + +astrocade_lightpen_device::~astrocade_lightpen_device() +{ +} + +void astrocade_lightpen_device::device_start() +{ + m_pen_timer = timer_alloc(TIMER_TRIGGER); + + save_item(NAME(m_retrigger)); +} + +void astrocade_lightpen_device::device_reset() +{ + m_pen_timer->adjust(attotime::never); + m_retrigger = false; +} + +void astrocade_lightpen_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if (id == TIMER_TRIGGER) + { + write_ltpen(1); + write_ltpen(0); + if (m_retrigger) + m_pen_timer->adjust(m_screen->time_until_pos(m_lighty->read(), m_lightx->read())); + else + m_pen_timer->adjust(attotime::never); + } +} + +INPUT_CHANGED_MEMBER( astrocade_lightpen_device::trigger ) +{ + if (newval) + { + m_retrigger = true; + m_pen_timer->adjust(m_screen->time_until_pos(m_lighty->read(), m_lightx->read())); + } + else + { + m_retrigger = false; + m_pen_timer->adjust(attotime::never); + } +} + +static INPUT_PORTS_START( astrocade_lightpen ) + PORT_START("TRIGGER") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_CHANGED_MEMBER(DEVICE_SELF, astrocade_lightpen_device, trigger, nullptr) + PORT_BIT( 0xfe, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("LIGHTX") + PORT_BIT(0x1ff, 0x000, IPT_LIGHTGUN_X) PORT_MINMAX(0x000, 0x15f) PORT_CROSSHAIR(X, 1.0, 0.0, 0) PORT_SENSITIVITY(45) PORT_KEYDELTA(15) + + PORT_START("LIGHTY") + PORT_BIT(0x0ff, 0x000, IPT_LIGHTGUN_Y) PORT_MINMAX(0x000, 0x0f0) PORT_CROSSHAIR(Y, 1.0, 0.0, 0) PORT_SENSITIVITY(45) PORT_KEYDELTA(15) +INPUT_PORTS_END + +ioport_constructor astrocade_lightpen_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( astrocade_lightpen ); +} diff --git a/src/devices/bus/astrocde/lightpen.h b/src/devices/bus/astrocde/lightpen.h new file mode 100644 index 00000000000..a0863d5d3e8 --- /dev/null +++ b/src/devices/bus/astrocde/lightpen.h @@ -0,0 +1,51 @@ +// license:BSD-3-Clause +// copyright-holders:Ryan Holtz +#ifndef MAME_BUS_ASTROCDE_LIGHTPEN_H +#define MAME_BUS_ASTROCDE_LIGHTPEN_H + +#pragma once + +#include "accessory.h" + + +/*************************************************************************** + TYPE DEFINITIONS + ***************************************************************************/ + +// ======================> astrocade_lightpen_device + +class astrocade_lightpen_device : public device_t, + public device_astrocade_accessory_interface +{ +public: + // construction/destruction + astrocade_lightpen_device(machine_config const &mconfig, char const *tag, device_t *owner, uint32_t clock = 0U); + virtual ~astrocade_lightpen_device(); + + DECLARE_INPUT_CHANGED_MEMBER( trigger ); + +protected: + // device_t implementation + virtual void device_start() override; + virtual void device_reset() override; + virtual ioport_constructor device_input_ports() const override; + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override; + + static const device_timer_id TIMER_TRIGGER = 0; + +private: + required_ioport m_trigger; + required_ioport m_lightx; + required_ioport m_lighty; + emu_timer *m_pen_timer; + bool m_retrigger; +}; + + +/*************************************************************************** + DEVICE TYPES + ***************************************************************************/ + +DECLARE_DEVICE_TYPE(ASTROCADE_LIGHTPEN, astrocade_lightpen_device) + +#endif // MAME_BUS_ASTROCDE_LIGHTPEN_H diff --git a/src/devices/bus/astrocde/ram.cpp b/src/devices/bus/astrocde/ram.cpp index 36d1ed9ab77..8f20b0256fa 100644 --- a/src/devices/bus/astrocde/ram.cpp +++ b/src/devices/bus/astrocde/ram.cpp @@ -21,10 +21,10 @@ switch and run it as a cartridge. This is useful for cartridge development. Blue RAM -- available in 4K, 16K, and 32K. These also use an INS8154 chip, - (not yet implemented) which has an additional $80 bytes of RAM mapped - immediately after the end of the expansion address space. This memory - can't be write protected. The INS8154 has I/O features needed for loading - tape programs into Blue RAM BASIC, as well as running the Blue RAM Utility cart. + which has an additional $80 bytes of RAM mapped immediately after the end of + the expansion address space (not yet implemented). This memory can't be write + protected. The INS8154 has I/O features needed for loading tape programs into + Blue RAM BASIC, as well as running the Blue RAM Utility cart. 4K: $6000 to $6FFF (can't run VIPERSoft BASIC, because this program needs memory past this range) 16K: $6000 to $9FFF @@ -69,9 +69,11 @@ DEFINE_DEVICE_TYPE(ASTROCADE_RL64RAM, astrocade_rl64ram_device, "astroca astrocade_blueram_4k_device::astrocade_blueram_4k_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) - : device_t(mconfig, type, tag, owner, clock), - device_astrocade_card_interface(mconfig, *this), - m_write_prot(*this, "RAM_PROTECT") + : device_t(mconfig, type, tag, owner, clock) + , device_astrocade_card_interface(mconfig, *this) + , m_write_prot(*this, "RAM_PROTECT") + , m_ramio(*this, "ramio") + , m_cassette(*this, "cassette") { } @@ -163,7 +165,35 @@ WRITE8_MEMBER(astrocade_blueram_4k_device::write) m_ram[offset - 0x1000] = data; } +READ8_MEMBER(astrocade_blueram_4k_device::read_io) +{ + return m_ramio->read_io(offset & 0x7f); +} + +WRITE8_MEMBER(astrocade_blueram_4k_device::write_io) +{ + logerror("write_io: %04x = %02x\n", offset, data); + m_ramio->write_io(offset & 0x7f, data); +} + +uint8_t astrocade_blueram_4k_device::porta_r() +{ + return 0; +} + +uint8_t astrocade_blueram_4k_device::portb_r() +{ + return m_cassette->input() > 0.0 ? 1 : 0; +} + +void astrocade_blueram_4k_device::porta_w(uint8_t data) +{ +} +void astrocade_blueram_4k_device::portb_w(uint8_t data) +{ + m_cassette->output(BIT(data, 0) ? +1 : -1); +} // Viper System 1 expansion has RAM in 0x6000-0x9fff READ8_MEMBER(astrocade_viper_sys1_device::read) @@ -207,3 +237,20 @@ WRITE8_MEMBER(astrocade_rl64ram_device::write) if (!m_write_prot->read()) m_ram[offset] = data; } + +/*------------------------------------------------- + machine configuration + -------------------------------------------------*/ + +void astrocade_blueram_4k_device::device_add_mconfig(machine_config &config) +{ + CASSETTE(config, m_cassette); + m_cassette->set_default_state(CASSETTE_STOPPED); + m_cassette->set_interface("astrocade_cass"); + + INS8154(config, m_ramio); + m_ramio->out_a().set(FUNC(astrocade_blueram_4k_device::porta_w)); + m_ramio->out_b().set(FUNC(astrocade_blueram_4k_device::portb_w)); + m_ramio->in_a().set(FUNC(astrocade_blueram_4k_device::porta_r)); + m_ramio->in_b().set(FUNC(astrocade_blueram_4k_device::portb_r)); +} diff --git a/src/devices/bus/astrocde/ram.h b/src/devices/bus/astrocde/ram.h index 83f9483d2e8..ee5ed884ef4 100644 --- a/src/devices/bus/astrocde/ram.h +++ b/src/devices/bus/astrocde/ram.h @@ -6,6 +6,8 @@ #pragma once #include "exp.h" +#include "imagedev/cassette.h" +#include "machine/ins8154.h" // ======================> astrocade_blueram_4k_device @@ -22,15 +24,25 @@ public: // reading and writing virtual DECLARE_READ8_MEMBER(read) override; virtual DECLARE_WRITE8_MEMBER(write) override; + virtual DECLARE_READ8_MEMBER(read_io) override; + virtual DECLARE_WRITE8_MEMBER(write_io) override; + + uint8_t porta_r(); + uint8_t portb_r(); + void porta_w(uint8_t data); + void portb_w(uint8_t data); protected: astrocade_blueram_4k_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock); virtual void device_start() override { m_ram.resize(0x1000); save_item(NAME(m_ram)); } virtual void device_reset() override { } + virtual void device_add_mconfig(machine_config &config) override; std::vector<uint8_t> m_ram; required_ioport m_write_prot; + required_device<ins8154_device> m_ramio; + required_device<cassette_image_device> m_cassette; }; // ======================> astrocade_blueram_16k_device diff --git a/src/devices/bus/bbc/tube/tube.cpp b/src/devices/bus/bbc/tube/tube.cpp index c0ff49915a6..602ea3c845a 100644 --- a/src/devices/bus/bbc/tube/tube.cpp +++ b/src/devices/bus/bbc/tube/tube.cpp @@ -112,6 +112,7 @@ void bbc_tube_slot_device::host_w(offs_t offset, uint8_t data) // slot devices +#include "tube_32016.h" #include "tube_6502.h" #include "tube_80186.h" #include "tube_80286.h" @@ -133,7 +134,7 @@ void bbc_tube_devices(device_slot_interface &device) { device.option_add("6502", BBC_TUBE_6502); /* Acorn ANC01 6502 2nd processor */ device.option_add("z80", BBC_TUBE_Z80); /* Acorn ANC04 Z80 2nd processor */ - //device.option_add("32016", BBC_TUBE_32016); /* Acorn ANC05 32016 2nd processor */ + device.option_add("32016", BBC_TUBE_32016); /* Acorn ANC05 32016 2nd processor */ device.option_add("arm", BBC_TUBE_ARM); /* Acorn ANC13 ARM Evaluation System */ device.option_add("80286", BBC_TUBE_80286); /* Acorn 80286 2nd Processor */ //device.option_add("a500", BBC_TUBE_A500); /* Acorn A500 2nd Processor */ @@ -142,8 +143,8 @@ void bbc_tube_devices(device_slot_interface &device) //device.option_add("hdp68k", BBC_TUBE_HDP68K); /* Torch Unicorn (HDP68K) */ //device.option_add("x25", BBC_TUBE_X25); /* Econet X25 Gateway */ device.option_add("zep100", BBC_TUBE_ZEP100); /* Torch Z80 Communicator (ZEP100) (Torch) */ - //device.option_add("zep100l", BBC_TUBE_ZEP100L); /* Torch Z80 Communicator (ZEP100) (Acorn 8271) */ - //device.option_add("zep100w", BBC_TUBE_ZEP100W); /* Torch Z80 Communicator (ZEP100) (Acorn 1770) */ + //device.option_add("zep100l", BBC_TUBE_ZEP100L); /* Torch Z80 Communicator (ZEP100) (Model B) */ + //device.option_add("zep100w", BBC_TUBE_ZEP100W); /* Torch Z80 Communicator (ZEP100) (Model B+) */ /* Acorn ANC21 Universal 2nd Processor Unit */ device.option_add("65c102", BBC_TUBE_65C102); /* Acorn ADC06 65C102 co-processor */ device.option_add("80186", BBC_TUBE_80186); /* Acorn ADC08 80186 co-processor */ @@ -160,11 +161,12 @@ void bbc_extube_devices(device_slot_interface &device) { device.option_add("6502", BBC_TUBE_6502); /* Acorn ANC01 6502 2nd processor */ device.option_add("z80", BBC_TUBE_Z80); /* Acorn ANC04 Z80 2nd processor */ - //device.option_add("32016", BBC_TUBE_32016); /* Acorn ANC05 32016 2nd processor */ + device.option_add("32016", BBC_TUBE_32016); /* Acorn ANC05 32016 2nd processor */ device.option_add("arm", BBC_TUBE_ARM); /* Acorn ANC13 ARM Evaluation System */ device.option_add("80286", BBC_TUBE_80286); /* Acorn 80286 2nd Processor */ //device.option_add("a500", BBC_TUBE_A500); /* Acorn A500 2nd Processor */ //device.option_add("pmsb2p", BBC_TUBE_PMSB2P); /* PMS B2P-6502 */ + //device.option_add("zep100m", BBC_TUBE_ZEP100M); /* Torch Z80 Communicator (ZEP100) (Master) */ /* Acorn ANC21 Universal 2nd Processor Unit */ device.option_add("65c102", BBC_TUBE_65C102); /* Acorn ADC06 65C102 co-processor */ device.option_add("80186", BBC_TUBE_80186); /* Acorn ADC08 80186 co-processor */ @@ -181,7 +183,6 @@ void bbc_intube_devices(device_slot_interface &device) { device.option_add("65c102", BBC_TUBE_65C102); /* Acorn ADC06 65C102 co-processor */ device.option_add("80186", BBC_TUBE_80186); /* Acorn ADC08 80186 co-processor */ - //device.option_add("zep100m", BBC_TUBE_ZEP100M); /* Torch Z80 Communicator (ZEP100) (Master) */ //device.option_add("arm7", BBC_TUBE_ARM7); /* Sprow ARM7 co-processor */ device.option_add("rc6502", BBC_TUBE_RC6502); /* ReCo6502 (6502) */ device.option_add("rc65816", BBC_TUBE_RC65816); /* ReCo6502 (65816) */ @@ -196,6 +197,7 @@ void electron_tube_devices(device_slot_interface &device) { device.option_add("6502", BBC_TUBE_6502); /* Acorn ANC01 6502 2nd processor */ device.option_add("z80", BBC_TUBE_Z80); /* Acorn ANC04 Z80 2nd processor */ + device.option_add("32016", BBC_TUBE_32016); /* Acorn ANC05 32016 2nd processor */ device.option_add("arm", BBC_TUBE_ARM); /* Acorn ANC13 ARM Evaluation System */ device.option_add("65c102", BBC_TUBE_65C102); /* Acorn ADC06 65C102 co-processor */ device.option_add("80186", BBC_TUBE_80186); /* Acorn ADC08 80186 co-processor */ diff --git a/src/devices/bus/bbc/tube/tube_32016.cpp b/src/devices/bus/bbc/tube/tube_32016.cpp new file mode 100644 index 00000000000..7b6ac355e42 --- /dev/null +++ b/src/devices/bus/bbc/tube/tube_32016.cpp @@ -0,0 +1,210 @@ +// license:BSD-3-Clause +// copyright-holders:Nigel Barnes +/********************************************************************** + + Acorn ANC05 32016 2nd processor + + http://chrisacorns.computinghistory.org.uk/8bit_Upgrades/Acorn_ANC05_320162ndproc.html + + Acorn ANC06 Cambridge Co-Processor + + http://chrisacorns.computinghistory.org.uk/8bit_Upgrades/Acorn_ANC06_CamCoPro.html + + IC1 (ULA) TUBE + IC2 (MMU) NS32082 Not fitted + IC3 (CPU) NS32016 + IC4 (TCU) NS32201 + IC20 (FPU) NS32081 + +**********************************************************************/ + + +#include "emu.h" +#include "tube_32016.h" +#include "softlist_dev.h" + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +DEFINE_DEVICE_TYPE(BBC_TUBE_32016, bbc_tube_32016_device, "bbc_tube_32016", "Acorn 32016 2nd processor") + + +//------------------------------------------------- +// ADDRESS_MAP( tube_32016_mem ) +//------------------------------------------------- + +void bbc_tube_32016_device::tube_32016_mem(address_map &map) +{ + map(0x000000, 0xffffff).rw(FUNC(bbc_tube_32016_device::read), FUNC(bbc_tube_32016_device::write)); + map(0xf90000, 0xf90001).portr("CONFIG"); + map(0xfffff0, 0xffffff).rw("ula", FUNC(tube_device::parasite_r), FUNC(tube_device::parasite_w)).umask32(0x00ff); +} + +//------------------------------------------------- +// ROM( tube_32016 ) +//------------------------------------------------- + +ROM_START(tube_32016) + ROM_REGION(0x8000, "rom", 0) + ROM_DEFAULT_BIOS("200") + ROM_SYSTEM_BIOS(0, "200", "Pandora v2.00") + ROMX_LOAD("pan200lo.rom", 0x0000, 0x4000, CRC(b1980fd0) SHA1(8084f8896cd22953abefbd43c51e1a422b30e28d), ROM_SKIP(1) | ROM_BIOS(0)) // 0201-764-02 Pandora Lo + ROMX_LOAD("pan200hi.rom", 0x0001, 0x4000, CRC(cab98d6b) SHA1(dfad1f4180c50757a74fcfe3a0ee7d7b48eb1bee), ROM_SKIP(1) | ROM_BIOS(0)) // 0201-763-02 Pandora Hi + ROM_SYSTEM_BIOS(1, "100", "Pandora v1.00") + ROMX_LOAD("pan100.rom", 0x0000, 0x8000, BAD_DUMP CRC(75333006) SHA1(996cd120103039390c9b979b16c327bb95da72e4), ROM_BIOS(1)) // 0201-763-01, 0201-764-01 Pandora + ROM_SYSTEM_BIOS(2, "061", "Pandora v0.61") + ROMX_LOAD("pan061lo.rom", 0x0000, 0x4000, CRC(6f801b35) SHA1(ce31f7c10603f3d15a06a8e32bde40df0639e446), ROM_SKIP(1) | ROM_BIOS(2)) + ROMX_LOAD("pan061hi.rom", 0x0001, 0x4000, CRC(c00b1ab0) SHA1(e6a705232278c518340ddc69ea51af91965fa332), ROM_SKIP(1) | ROM_BIOS(2)) +ROM_END + +//------------------------------------------------- +// INPUT_PORTS( tube_32016 ) +//------------------------------------------------- + +static INPUT_PORTS_START(tube_32016) + PORT_START("CONFIG") + PORT_DIPNAME(0x80, 0x80, "H") PORT_DIPLOCATION("LKS:1") + PORT_DIPSETTING(0x80, "FPU") + PORT_DIPSETTING(0x00, "No FPU") + + PORT_DIPNAME(0x40, 0x00, "G") PORT_DIPLOCATION("LKS:2") + PORT_DIPSETTING(0x40, "MMU") + PORT_DIPSETTING(0x00, "No MMU") + + PORT_DIPNAME(0x20, 0x00, "F") PORT_DIPLOCATION("LKS:3") + PORT_DIPSETTING(0x20, "Reserved") + PORT_DIPSETTING(0x00, "Reserved") + + PORT_DIPNAME(0x10, 0x00, "E") PORT_DIPLOCATION("LKS:4") + PORT_DIPSETTING(0x10, "Reserved") + PORT_DIPSETTING(0x00, "Reserved") + + PORT_DIPNAME(0x08, 0x00, "D") PORT_DIPLOCATION("LKS:5") + PORT_DIPSETTING(0x08, "Reserved") + PORT_DIPSETTING(0x00, "Reserved") + + PORT_DIPNAME(0x04, 0x00, "C") PORT_DIPLOCATION("LKS:6") + PORT_DIPSETTING(0x04, "Reserved") + PORT_DIPSETTING(0x00, "Reserved") + + PORT_DIPNAME(0x02, 0x00, "B") PORT_DIPLOCATION("LKS:7") + PORT_DIPSETTING(0x02, "Reserved") + PORT_DIPSETTING(0x00, "Reserved") + + PORT_DIPNAME(0x01, 0x00, "A") PORT_DIPLOCATION("LKS:8") + PORT_DIPSETTING(0x01, "Reserved") + PORT_DIPSETTING(0x00, "Reserved") +INPUT_PORTS_END + +//------------------------------------------------- +// device_add_mconfig - add device configuration +//------------------------------------------------- + +void bbc_tube_32016_device::device_add_mconfig(machine_config &config) +{ + NS32016(config, m_maincpu, 12_MHz_XTAL / 2); + m_maincpu->set_addrmap(AS_PROGRAM, &bbc_tube_32016_device::tube_32016_mem); + + TUBE(config, m_ula); + m_ula->pnmi_handler().set_inputline(m_maincpu, INPUT_LINE_NMI); + m_ula->pirq_handler().set_inputline(m_maincpu, INPUT_LINE_IRQ0); + + /* internal ram */ + RAM(config, m_ram).set_default_size("1M").set_default_value(0); + + /* software lists */ + SOFTWARE_LIST(config, "flop_ls_32016").set_original("bbc_flop_32016"); +} + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const tiny_rom_entry *bbc_tube_32016_device::device_rom_region() const +{ + return ROM_NAME( tube_32016 ); +} + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor bbc_tube_32016_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( tube_32016 ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// bbc_tube_32016_device - constructor +//------------------------------------------------- + +bbc_tube_32016_device::bbc_tube_32016_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : device_t(mconfig, BBC_TUBE_32016, tag, owner, clock) + , device_bbc_tube_interface(mconfig, *this) + , m_maincpu(*this, "maincpu") + , m_ula(*this, "ula") + , m_ram(*this, "ram") + , m_rom(*this, "rom") + , m_rom_enabled(true) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void bbc_tube_32016_device::device_start() +{ +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void bbc_tube_32016_device::device_reset() +{ + m_rom_enabled = true; +} + + +//************************************************************************** +// IMPLEMENTATION +//************************************************************************** + +uint8_t bbc_tube_32016_device::host_r(offs_t offset) +{ + return m_ula->host_r(offset); +} + +void bbc_tube_32016_device::host_w(offs_t offset, uint8_t data) +{ + m_ula->host_w(offset, data); +} + + +READ8_MEMBER(bbc_tube_32016_device::read) +{ + uint16_t data = 0xffff; + + if (m_rom_enabled) + data = m_rom->base()[offset & 0x3fff]; + else if (offset < m_ram->size()) + data = m_ram->pointer()[offset]; + + return data; +} + +WRITE8_MEMBER(bbc_tube_32016_device::write) +{ + /* clear ROM select on first write */ + if (!machine().side_effects_disabled()) m_rom_enabled = false; + + if (offset < m_ram->size()) + m_ram->pointer()[offset] = data; +} diff --git a/src/devices/bus/bbc/tube/tube_32016.h b/src/devices/bus/bbc/tube/tube_32016.h new file mode 100644 index 00000000000..864b8173703 --- /dev/null +++ b/src/devices/bus/bbc/tube/tube_32016.h @@ -0,0 +1,71 @@ +// license:BSD-3-Clause +// copyright-holders:Nigel Barnes +/********************************************************************** + + Acorn ANC05 32016 2nd processor + + http://chrisacorns.computinghistory.org.uk/8bit_Upgrades/Acorn_ANC05_320162ndproc.html + + Acorn ANC06 Cambridge Co-Processor + + http://chrisacorns.computinghistory.org.uk/8bit_Upgrades/Acorn_ANC06_CamCoPro.html + +**********************************************************************/ + + +#ifndef MAME_BUS_BBC_TUBE_32016_H +#define MAME_BUS_BBC_TUBE_32016_H + +#include "tube.h" +#include "cpu/ns32000/ns32000.h" +#include "machine/ram.h" +#include "machine/tube.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> bbc_tube_32016_device + +class bbc_tube_32016_device : + public device_t, + public device_bbc_tube_interface +{ +public: + // construction/destruction + bbc_tube_32016_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + +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; + virtual const tiny_rom_entry *device_rom_region() const override; + virtual ioport_constructor device_input_ports() const override; + + virtual uint8_t host_r(offs_t offset) override; + virtual void host_w(offs_t offset, uint8_t data) override; + +private: + required_device<ns32016_cpu_device> m_maincpu; + required_device<tube_device> m_ula; + required_device<ram_device> m_ram; + required_memory_region m_rom; + + DECLARE_READ8_MEMBER(read); + DECLARE_WRITE8_MEMBER(write); + + void tube_32016_mem(address_map &map); + + bool m_rom_enabled; +}; + + + +// device type definition +DECLARE_DEVICE_TYPE(BBC_TUBE_32016, bbc_tube_32016_device) + + +#endif /* MAME_BUS_BBC_TUBE_32016_H */ diff --git a/src/devices/bus/bml3/bml3bus.h b/src/devices/bus/bml3/bml3bus.h index ddaa1c87dce..2132d376041 100644 --- a/src/devices/bus/bml3/bml3bus.h +++ b/src/devices/bus/bml3/bml3bus.h @@ -16,15 +16,6 @@ #define BML3BUS_MAX_SLOTS 6 -//************************************************************************** -// INTERFACE CONFIGURATION MACROS -//************************************************************************** - -#define MCFG_BML3BUS_SLOT_ADD(_nbtag, _tag, _slot_intf, _def_slot) \ - MCFG_DEVICE_ADD(_tag, BML3BUS_SLOT, 0) \ - MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) \ - downcast<bml3bus_slot_device &>(*device).set_bml3bus_slot(_nbtag, _tag); - //************************************************************************** // TYPE DEFINITIONS @@ -37,7 +28,18 @@ class bml3bus_slot_device : public device_t, { public: // construction/destruction - bml3bus_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + template <typename T> + bml3bus_slot_device(machine_config const &mconfig, const char *tag, device_t *owner, const char *nbtag, T &&opts, const char *dflt) + : bml3bus_slot_device(mconfig, tag, owner, (uint32_t)0) + { + option_reset(); + opts(*this); + set_default_option(dflt); + set_fixed(false); + set_bml3bus_slot(nbtag, tag); + } + + bml3bus_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0); // device-level overrides virtual void device_start() override; diff --git a/src/devices/bus/coco/coco_dcmodem.cpp b/src/devices/bus/coco/coco_dcmodem.cpp index 693b2457e51..bebd6c275d5 100644 --- a/src/devices/bus/coco/coco_dcmodem.cpp +++ b/src/devices/bus/coco/coco_dcmodem.cpp @@ -70,6 +70,11 @@ namespace return memregion("eprom")->base(); } + virtual memory_region* get_cart_memregion() override + { + return memregion("eprom"); + } + private: // internal state required_device<mos6551_device> m_uart; diff --git a/src/devices/bus/coco/coco_orch90.cpp b/src/devices/bus/coco/coco_orch90.cpp index 4023c7f2a0b..2ad8afdaae1 100644 --- a/src/devices/bus/coco/coco_orch90.cpp +++ b/src/devices/bus/coco/coco_orch90.cpp @@ -92,6 +92,11 @@ namespace return memregion("eprom")->base(); } + virtual memory_region* get_cart_memregion() override + { + return memregion("eprom"); + } + private: WRITE8_MEMBER(write_left) { m_ldac->write(data); } WRITE8_MEMBER(write_right) { m_rdac->write(data); } diff --git a/src/devices/bus/coco/coco_rs232.cpp b/src/devices/bus/coco/coco_rs232.cpp index e058a9d3f3c..5a124986792 100644 --- a/src/devices/bus/coco/coco_rs232.cpp +++ b/src/devices/bus/coco/coco_rs232.cpp @@ -68,6 +68,11 @@ namespace return memregion("eprom")->base(); } + virtual memory_region* get_cart_memregion() override + { + return memregion("eprom"); + } + private: // internal state required_device<mos6551_device> m_uart; diff --git a/src/devices/bus/coco/cococart.cpp b/src/devices/bus/coco/cococart.cpp index 93045e85230..6bf6360d24b 100644 --- a/src/devices/bus/coco/cococart.cpp +++ b/src/devices/bus/coco/cococart.cpp @@ -412,11 +412,11 @@ image_init_result cococart_slot_device::call_load() { memory_region *cart_mem = m_cart->get_cart_memregion(); uint8_t *base = cart_mem->base(); - offs_t read_length, cart_legnth = cart_mem->bytes();; + offs_t read_length, cart_length = cart_mem->bytes();; if (!loaded_through_softlist()) { - read_length = fread(base, cart_legnth); + read_length = fread(base, cart_length); } else { @@ -424,7 +424,7 @@ image_init_result cococart_slot_device::call_load() memcpy(base, get_software_region("rom"), read_length); } - while (read_length < cart_legnth) + while (read_length < cart_length) { offs_t len = std::min(read_length, m_cart->get_cart_size() - read_length); memcpy(base + read_length, base, len); diff --git a/src/devices/bus/cpc/cpc_rs232.cpp b/src/devices/bus/cpc/cpc_rs232.cpp index d4439ff1eaf..40fc0853539 100644 --- a/src/devices/bus/cpc/cpc_rs232.cpp +++ b/src/devices/bus/cpc/cpc_rs232.cpp @@ -137,12 +137,12 @@ WRITE_LINE_MEMBER(cpc_rs232_device::pit_out2_w) READ8_MEMBER(cpc_rs232_device::dart_r) { - return m_dart->ba_cd_r(space,offset); + return m_dart->ba_cd_r(offset); } WRITE8_MEMBER(cpc_rs232_device::dart_w) { - m_dart->ba_cd_w(space,offset,data); + m_dart->ba_cd_w(offset,data); } READ8_MEMBER(cpc_rs232_device::pit_r) diff --git a/src/devices/bus/cpc/playcity.cpp b/src/devices/bus/cpc/playcity.cpp index 1e6f3b0cfa6..7d444abb03b 100644 --- a/src/devices/bus/cpc/playcity.cpp +++ b/src/devices/bus/cpc/playcity.cpp @@ -87,12 +87,12 @@ void cpc_playcity_device::device_reset() READ8_MEMBER(cpc_playcity_device::ctc_r) { - return m_ctc->read(space,offset); + return m_ctc->read(offset); } WRITE8_MEMBER(cpc_playcity_device::ctc_w) { - m_ctc->write(space,offset,data); + m_ctc->write(offset,data); if(offset == 0) update_ymz_clock(); } diff --git a/src/devices/bus/hp_dio/hp98644.cpp b/src/devices/bus/hp_dio/hp98644.cpp index 004da09b55e..d3c347b6d31 100644 --- a/src/devices/bus/hp_dio/hp98644.cpp +++ b/src/devices/bus/hp_dio/hp98644.cpp @@ -193,7 +193,7 @@ READ16_MEMBER(dio16_98644_device::io_r) case 0x0d: case 0x0e: case 0x0f: - ret = m_uart->ins8250_r(space, offset & 0x07, mem_mask); + ret = m_uart->ins8250_r(offset & 0x07); break; } @@ -230,7 +230,7 @@ WRITE16_MEMBER(dio16_98644_device::io_w) case 0x0d: case 0x0e: case 0x0f: - m_uart->ins8250_w(space, offset & 0x07, data, mem_mask); + m_uart->ins8250_w(offset & 0x07, data); break; } } diff --git a/src/devices/bus/isa/3c505.cpp b/src/devices/bus/isa/3c505.cpp index 71548dcbdaa..37cd5ef346a 100644 --- a/src/devices/bus/isa/3c505.cpp +++ b/src/devices/bus/isa/3c505.cpp @@ -1644,7 +1644,9 @@ READ16_MEMBER(threecom3c505_device::read) // omit excessive logging if (data == last_data) { - uint32_t pc = space.device().state().pcbase(); + // FIXME: space.device().state().pcbase() will crash mame with SIGSEGV (since mame0197) + uint32_t pc = 0; // space.device().state().pcbase(); + if (pc == last_pc) { return data; diff --git a/src/devices/bus/isa/aha1542.cpp b/src/devices/bus/isa/aha1542.cpp deleted file mode 100644 index b044c88b171..00000000000 --- a/src/devices/bus/isa/aha1542.cpp +++ /dev/null @@ -1,201 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Darkstar -/********************************************************************** - * - * Adaptec AHA-1542{,C,CF} SCSI Controller - * - **********************************************************************/ - -/* - PCB layout - ---------- - Floppy SCSI - +-----------+ +------------------+ +- - +-----+-----------+-+------------------+--+ - | | - | DIPSW DS1 |\ - | +-----+ | | - | | | Y1 +---+ TRM TRM | | - | | U3 | |U5 | |S| - | U8 +-----+ +---+ |C| - | +---+ +------+ +-------+ |S| - | |U13| |U15 | Y2 | | |I| - | +---+ +------+ | | | | - | |U16 | |U17 | | | - | +------+ +-------+ |/ - +-----------------------------------------+ - ||||||||| ||||||||||||||||||||||||| | - - - DIPSW sw1 - sw8 - U3 Intel chip labelled "AHA-1542CF/552800-01 D/9346", probably FDC (82077) - U5 Z84C0010VEC - U8 EEPROM(?) labelled 545120A - U13 CXK5864CM-10LL (64kbit SRAM) - U15 M27C256B labelled "ADAPTEC INC/553801-00 C/MCODE 563D/(C) 1993" - U16 M27C256B labelled "ADAPTEC INC/553601-00 C/BIOS C38D/(C) 1993" - U17 AIC-7970Q - Y1 XTAL SRX4054 93-38 - Y2 XTAL SRX4053 93-40 - TRM Dallas DS2107AS (SCSI termination) - DS1 LED - -*/ - -/* - * The PCB has a couple of DIP switches: - * - * sw1 on enable termination - * off software-controlled termination - * - * sw2 sw3 sw4 I/O Port - * off off off 0x330 - 0x333 (default) - * on off off 0x334 - 0x337 - * off on off 0x230 - 0x233 - * on on off 0x234 - 0x237 - * off off on 0x130 - 0x133 - * on off on 0x134 - 0x137 - * off on on reserved - * on on on reserved - * - * sw5 on disable floppy interface - * off enable floppy interface - * - * sw6 sw7 sw8 BIOS base address - * off off off 0xdc000 (default) - * on off off 0xd8000 - * off on off 0xd4000 - * on on off 0xd0000 - * off off on 0xcc000 - * on off on 0xc8000 - * off on on reserved - * on on on BIOS disabled - * - * source: http://download.adaptec.com/pdfs/installation_guides/1540cfig.pdf - */ - -#include "emu.h" -#include "aha1542.h" -#include "cpu/z80/z80.h" - -// I/O Port interface -// READ Port x+0: STATUS -// WRITE Port x+0: CONTROL -// -// READ Port x+1: DATA -// WRITE Port x+1: COMMAND -// -// READ Port x+2: INTERRUPT STATUS -// WRITE Port x+2: (undefined?) -// -// R/W Port x+3: (undefined) - -// READ STATUS flags -#define STAT_STST 0x80 // self-test in progress -#define STAT_DIAGF 0x40 // internal diagnostic failure -#define STAT_INIT 0x20 // mailbox initialization required -#define STAT_IDLE 0x10 // HBA is idle -#define STAT_CDFULL 0x08 // Command/Data output port is full -#define STAT_DFULL 0x04 // Data input port is full -#define STAT_INVCMD 0x01 // Invalid command - -// READ INTERRUPT STATUS flags -#define INTR_ANY 0x80 // any interrupt -#define INTR_SRCD 0x08 // SCSI reset detected -#define INTR_HACC 0x04 // HA command complete -#define INTR_MBOA 0x02 // MBO empty -#define INTR_MBIF 0x01 // MBI full - -// WRITE CONTROL commands -#define CTRL_HRST 0x80 // Hard reset -#define CTRL_SRST 0x40 // Soft reset -#define CTRL_IRST 0x20 // interrupt reset -#define CTRL_SCRST 0x10 // SCSI bus reset - -// READ/WRITE DATA commands -#define CMD_NOP 0x00 // No operation -#define CMD_MBINIT 0x01 // mailbox initialization -#define CMD_START_SCSI 0x02 // Start SCSI command -#define CMD_BIOSCMD 0x03 // undocumented BIOS conmmand (shadow RAM etc.) -#define CMD_INQUIRY 0x04 // Adapter inquiry -#define CMD_EMBOI 0x05 // enable Mailbox Out Interrupt -#define CMD_SELTIMEOUT 0x06 // Set SEL timeout -#define CMD_BUSON_TIME 0x07 // set bus-On time -#define CMD_BUSOFF_TIME 0x08 // set bus-off time -#define CMD_DMASPEED 0x09 // set ISA DMA speed -#define CMD_RETDEVS 0x0a // return installed devices -#define CMD_RETCONF 0x0b // return configuration data -#define CMD_TARGET 0x0c // set HBA to target mode -#define CMD_RETSETUP 0x0d // return setup data -#define CMD_ECHO 0x1f // ECHO command data (NetBSD says it is 0x1e) - -// these are for 1541C only: -#define CMD_RETDEVSHI 0x23 // return devices 8-15 (from NetBSD) -#define CMD_EXTBIOS 0x28 // return extended BIOS information -#define CMD_MBENABLE 0x29 // set mailbox interface enable - -DEFINE_DEVICE_TYPE(AHA1542, aha1542_device, "aha1542", "AHA1542 SCSI Controller") - -#define Z84C0010_TAG "u5" - -READ8_MEMBER( aha1542_device::aha1542_r ) -{ - logerror("%s aha1542_r(): offset=%d\n", machine().describe_context(), offset); - return 0xff; -} - -WRITE8_MEMBER( aha1542_device::aha1542_w ) -{ - logerror("%s aha1542_w(): offset=%d data=0x%02x\n", machine().describe_context(), offset, data); -} - -//------------------------------------------------- -// ROM( aha1542 ) -//------------------------------------------------- - -ROM_START( aha1542 ) - ROM_REGION( 0x8000, "aha1542", 0 ) - ROM_LOAD( "553601-00.u16", 0x0000, 0x8000, CRC(ab22fc02) SHA1(f9f783e0272fc14ba3de32316997f1f6cadc67d0) ) /* Adaptec 1540CF/1542CF BIOS v2.01 */ - - ROM_REGION( 0x8000, Z84C0010_TAG, 0 ) - ROM_LOAD( "553801-00.u15", 0x0000, 0x8000, CRC(7824397e) SHA1(35bc2c8fab31aad3190a478f2dc8f3a72958cf04) ) /* ADAPTEC, INC MCODE */ -ROM_END - -void aha1542_device::z84c0010_mem(address_map &map) -{ - map(0x0000, 0x7fff).rom().region(Z84C0010_TAG, 0); - map(0x8000, 0x800f).noprw(); // something is mapped there - map(0x9000, 0xafff).ram(); // 2kb RAM chip - map(0xe000, 0xe0ff).ram(); // probably PC<->Z80 communication area - map(0xb000, 0xb000).noprw(); // something? -} - -const tiny_rom_entry *aha1542_device::device_rom_region() const -{ - return ROM_NAME( aha1542 ); -} - -void aha1542_device::device_add_mconfig(machine_config &config) -{ - z80_device &cpu(Z80(config, Z84C0010_TAG, XTAL(12'000'000))); - cpu.set_addrmap(AS_PROGRAM, &aha1542_device::z84c0010_mem); -} - -aha1542_device::aha1542_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : - device_t(mconfig, AHA1542, tag, owner, clock), - device_isa16_card_interface(mconfig, *this) -{ -} - -void aha1542_device::device_start() -{ - set_isa_device(); - m_isa->install_rom(this, 0xdc000, 0xdffff, "aha1542", "aha1542"); - m_isa->install_device(0x330, 0x333, read8_delegate(FUNC( aha1542_device::aha1542_r ), this), - write8_delegate(FUNC( aha1542_device::aha1542_w ), this) ); -} - - -void aha1542_device::device_reset() -{ -} diff --git a/src/devices/bus/isa/aha1542.h b/src/devices/bus/isa/aha1542.h deleted file mode 100644 index cc84c2ea55b..00000000000 --- a/src/devices/bus/isa/aha1542.h +++ /dev/null @@ -1,54 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Darkstar -/********************************************************************** - * - * Adaptec AHA-1542{,C,CF} SCSI Controller - * - ********************************************************************** - - - - **********************************************************************/ - -#ifndef MAME_BUS_AHA1542_H -#define MAME_BUS_AHA1542_H - -#pragma once - - -#include "isa.h" - -//********************************************************************* -// TYPE DEFINITIONS -//********************************************************************* - -// ====================> aha1542_device - -class aha1542_device : public device_t, - public device_isa16_card_interface -{ -public: - static constexpr feature_type unemulated_features() { return feature::DISK; } - // construction/destruction - aha1542_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); - - DECLARE_READ8_MEMBER( aha1542_r ); - DECLARE_WRITE8_MEMBER( aha1542_w ); - -protected: - // device-level overrides - virtual void device_start() override; - virtual void device_reset() override; - - // optional information overrides - virtual const tiny_rom_entry *device_rom_region() const override; - virtual void device_add_mconfig(machine_config &config) override; - -private: - void z84c0010_mem(address_map &map); -}; - -// device type definition -DECLARE_DEVICE_TYPE(AHA1542, aha1542_device) - -#endif // MAME_BUS_AHA1542_H diff --git a/src/devices/bus/isa/aha1542b.cpp b/src/devices/bus/isa/aha1542b.cpp new file mode 100644 index 00000000000..087f9ef9611 --- /dev/null +++ b/src/devices/bus/isa/aha1542b.cpp @@ -0,0 +1,401 @@ +// license:BSD-3-Clause +// copyright-holders:AJR +/*************************************************************************** + + Adaptec AHA-1540/42A and AHA-1540/42B SCSI controllers + + The alternate BIOSes using port 334h instead of 330h are provided due + to certain MIDI cards requiring the 330h port. + +***************************************************************************/ + +#include "emu.h" +#include "aha1542b.h" + +#include "cpu/i8085/i8085.h" +#include "machine/aic6250.h" +#include "machine/nscsi_bus.h" +#include "machine/nscsi_hd.h" + + +DEFINE_DEVICE_TYPE(AHA1542A, aha1542a_device, "aha1542a", "AHA-1542A SCSI Controller") +DEFINE_DEVICE_TYPE(AHA1542B, aha1542b_device, "aha1542b", "AHA-1542B SCSI Controller") + + +aha154x_device::aha154x_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock) + : device_t(mconfig, type, tag, owner, clock) + , device_isa16_card_interface(mconfig, *this) + , m_fdc(*this, "fdc") + , m_bios(*this, "bios") +{ +} + +aha1542a_device::aha1542a_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) + : aha154x_device(mconfig, AHA1542A, tag, owner, clock) +{ +} + +aha1542b_device::aha1542b_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) + : aha154x_device(mconfig, AHA1542B, tag, owner, clock) +{ +} + +void aha154x_device::device_start() +{ +} + +void aha154x_device::i8085_map(address_map &map) +{ + map(0x0000, 0x3fff).rom().region("mcode", 0); + map(0x8000, 0x800f).m("scsi:7:scsic", FUNC(aic6250_device::map)); + map(0xe000, 0xe7ff).ram(); +} + +static INPUT_PORTS_START(aha1542a) + PORT_START("SETUP") + PORT_DIPNAME(0x01, 0x01, "Synchronous Negotiation") PORT_DIPLOCATION("J1:1") + PORT_DIPSETTING(0x01, "Disabled") + PORT_DIPSETTING(0x00, "Enabled") + PORT_DIPNAME(0x02, 0x02, "Diagnostic Test Loop") PORT_DIPLOCATION("J1:2") + PORT_DIPSETTING(0x02, DEF_STR(Off)) + PORT_DIPSETTING(0x00, DEF_STR(On)) + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_CUSTOM) // Data accepted by host + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_UNKNOWN) + PORT_DIPNAME(0x10, 0x10, "SCSI Parity Checking") PORT_DIPLOCATION("J1:3") + PORT_DIPSETTING(0x00, "Disabled") + PORT_DIPSETTING(0x10, "Enabled") + PORT_DIPNAME(0x60, 0x60, "DMA Transfer Speed") PORT_DIPLOCATION("J1:12,13") + PORT_DIPSETTING(0x60, "5.0 MB/s") + PORT_DIPSETTING(0x40, "5.7 MB/s") + PORT_DIPSETTING(0x20, "6.7 MB/s") + PORT_DIPSETTING(0x00, "8.0 MB/s") + PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_CUSTOM) // SCSI reset + + PORT_START("CONFIG") + PORT_DIPNAME(0x07, 0x07, "SCSI Address ID") PORT_DIPLOCATION("J1:4,5,6") + PORT_DIPSETTING(0x00, "0") + PORT_DIPSETTING(0x01, "1") + PORT_DIPSETTING(0x02, "2") + PORT_DIPSETTING(0x03, "3") + PORT_DIPSETTING(0x04, "4") + PORT_DIPSETTING(0x05, "5") + PORT_DIPSETTING(0x06, "6") + PORT_DIPSETTING(0x07, "7") + PORT_DIPNAME(0x18, 0x08, "DMA Channel") PORT_DIPLOCATION("J1:7,8") + PORT_DIPSETTING(0x00, "0") + PORT_DIPSETTING(0x08, "5") + PORT_DIPSETTING(0x10, "6") + PORT_DIPSETTING(0x18, "7") + PORT_DIPNAME(0xe0, 0xa0, "Interrupt Channel") PORT_DIPLOCATION("J1:9,10,11") + PORT_DIPSETTING(0xe0, "9") + PORT_DIPSETTING(0xc0, "10") + PORT_DIPSETTING(0xa0, "11") + PORT_DIPSETTING(0x80, "12") + PORT_DIPSETTING(0x60, "14") + PORT_DIPSETTING(0x40, "15") + + PORT_START("DMAREQ") + PORT_DIPNAME(0xf, 0xd, "DMA Request") PORT_DIPLOCATION("J14:1,2,3,4") + PORT_DIPSETTING(0xe, "Channel 0") + PORT_DIPSETTING(0xd, "Channel 5") + PORT_DIPSETTING(0xb, "Channel 6") + PORT_DIPSETTING(0x7, "Channel 7") + + PORT_START("DMAACK") + PORT_DIPNAME(0xf, 0xd, "DMA Acknowledge") PORT_DIPLOCATION("J15:1,2,3,4") + PORT_DIPSETTING(0xe, "Channel 0") + PORT_DIPSETTING(0xd, "Channel 5") + PORT_DIPSETTING(0xb, "Channel 6") + PORT_DIPSETTING(0x7, "Channel 7") + + PORT_START("IRQ") + PORT_DIPNAME(0x3f, 0x3b, "Interrupt") PORT_DIPLOCATION("J16:1,2,3,4,5,6") + PORT_DIPSETTING(0x3e, "IRQ 9") + PORT_DIPSETTING(0x3d, "IRQ 10") + PORT_DIPSETTING(0x3b, "IRQ 11") + PORT_DIPSETTING(0x37, "IRQ 12") + PORT_DIPSETTING(0x2f, "IRQ 14") + PORT_DIPSETTING(0x1f, "IRQ 15") + + PORT_START("BIOSWAIT") + PORT_DIPNAME(0xf, 0xe, "BIOS Wait State") PORT_DIPLOCATION("J7:1,2,3,4") + PORT_DIPSETTING(0xe, "Disabled") + PORT_DIPSETTING(0xd, "100 ns") + PORT_DIPSETTING(0xb, "200 ns") + PORT_DIPSETTING(0x7, "300 ns") + + PORT_START("PORTADDR") + PORT_DIPNAME(0x7, 0x6, "I/O Port Address") PORT_DIPLOCATION("J6:1,2,3") + PORT_DIPSETTING(0x2, "130h") + PORT_DIPSETTING(0x3, "134h") + PORT_DIPSETTING(0x4, "230h") + PORT_DIPSETTING(0x5, "234h") + PORT_DIPSETTING(0x6, "330h") + PORT_DIPSETTING(0x7, "334h") + + PORT_START("BIOSADDR") + PORT_DIPNAME(0x3, 0x3, "BIOS Base Address") PORT_DIPLOCATION("J10:2,1") + PORT_DIPSETTING(0x0, "0C8000h") + PORT_DIPSETTING(0x1, "0CC000h") + PORT_DIPSETTING(0x2, "0D8000h") + PORT_DIPSETTING(0x3, "0DC000h") + PORT_DIPNAME(0x4, 0x0, "System BIOS") PORT_DIPLOCATION("J10:3") + PORT_DIPSETTING(0x4, "Disabled") + PORT_DIPSETTING(0x0, "Enabled") + + PORT_START("AUX") + PORT_DIPNAME(0x1, 0x1, DEF_STR(Unused)) PORT_DIPLOCATION("J9:1") + PORT_DIPSETTING(0x1, DEF_STR(Off)) + PORT_DIPSETTING(0x0, DEF_STR(On)) + PORT_DIPNAME(0x2, 0x2, DEF_STR(Unused)) PORT_DIPLOCATION("J9:2") + PORT_DIPSETTING(0x2, DEF_STR(Off)) + PORT_DIPSETTING(0x0, DEF_STR(On)) + PORT_DIPNAME(0x4, 0x4, DEF_STR(Unused)) PORT_DIPLOCATION("J9:3") + PORT_DIPSETTING(0x4, DEF_STR(Off)) + PORT_DIPSETTING(0x0, DEF_STR(On)) + PORT_DIPNAME(0x8, 0x8, "Automatic Request Sense") PORT_DIPLOCATION("J9:4") + PORT_DIPSETTING(0x0, "Disabled") + PORT_DIPSETTING(0x8, "Enabled") + + PORT_START("FDCCFG") + PORT_DIPNAME(0x1, 0x1, "FDC Secondary Address") PORT_DIPLOCATION("J12:1") + PORT_DIPSETTING(0x0, "370h-377h") + PORT_DIPSETTING(0x1, "3F0h-3F7h") + PORT_DIPNAME(0x2, 0x0, "Flexible Disk Controller") PORT_DIPLOCATION("J13:1") + PORT_DIPSETTING(0x2, DEF_STR(Off)) + PORT_DIPSETTING(0x0, DEF_STR(On)) + + PORT_START("FDCIRQ") + PORT_DIPNAME(0x7, 0x4, "FDC Interrupt") PORT_DIPLOCATION("J17:1,2,3") + PORT_DIPSETTING(0x4, "Channel 6") + PORT_DIPSETTING(0x1, "Channel 10") + + PORT_START("FDCDREQ") + PORT_DIPNAME(0x7, 0x4, "FDC DMA Request") PORT_DIPLOCATION("J18:1,2,3") + PORT_DIPSETTING(0x4, "Channel 2") + PORT_DIPSETTING(0x1, "Channel 3") + + PORT_START("FDCDACK") + PORT_DIPNAME(0x7, 0x4, "FDC DMA Acknowledge") PORT_DIPLOCATION("J19:1,2,3") + PORT_DIPSETTING(0x4, "Channel 2") + PORT_DIPSETTING(0x1, "Channel 3") +INPUT_PORTS_END + +static INPUT_PORTS_START(aha1542b) + PORT_START("SETUP") + PORT_DIPNAME(0x01, 0x01, "Synchronous Negotiation") PORT_DIPLOCATION("J5:1") + PORT_DIPSETTING(0x01, "Disabled") + PORT_DIPSETTING(0x00, "Enabled") + PORT_DIPNAME(0x02, 0x02, "Diagnostic Test Loop") PORT_DIPLOCATION("J5:2") + PORT_DIPSETTING(0x02, DEF_STR(Off)) + PORT_DIPSETTING(0x00, DEF_STR(On)) + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_UNUSED) + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_UNUSED) + PORT_DIPNAME(0x10, 0x10, "SCSI Parity Checking") PORT_DIPLOCATION("J5:3") + PORT_DIPSETTING(0x00, "Disabled") + PORT_DIPSETTING(0x10, "Enabled") + PORT_DIPNAME(0x60, 0x60, "DMA Transfer Speed") PORT_DIPLOCATION("J5:12,13") + PORT_DIPSETTING(0x60, "5.0 MB/s") + PORT_DIPSETTING(0x40, "5.7 MB/s") + PORT_DIPSETTING(0x20, "6.7 MB/s") + PORT_DIPSETTING(0x00, "8.0 MB/s") + PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_UNUSED) + + PORT_START("CONFIG") + PORT_DIPNAME(0x07, 0x07, "SCSI Address ID") PORT_DIPLOCATION("J5:4,5,6") + PORT_DIPSETTING(0x00, "0") + PORT_DIPSETTING(0x01, "1") + PORT_DIPSETTING(0x02, "2") + PORT_DIPSETTING(0x03, "3") + PORT_DIPSETTING(0x04, "4") + PORT_DIPSETTING(0x05, "5") + PORT_DIPSETTING(0x06, "6") + PORT_DIPSETTING(0x07, "7") + PORT_DIPNAME(0x18, 0x08, "DMA Channel") PORT_DIPLOCATION("J5:7,8") + PORT_DIPSETTING(0x00, "0") + PORT_DIPSETTING(0x08, "5") + PORT_DIPSETTING(0x10, "6") + PORT_DIPSETTING(0x18, "7") + PORT_DIPNAME(0xe0, 0xa0, "Interrupt Channel") PORT_DIPLOCATION("J5:9,10,11") + PORT_DIPSETTING(0xe0, "9") + PORT_DIPSETTING(0xc0, "10") + PORT_DIPSETTING(0xa0, "11") + PORT_DIPSETTING(0x80, "12") + PORT_DIPSETTING(0x60, "14") + PORT_DIPSETTING(0x40, "15") + + PORT_START("DMAREQ") + PORT_DIPNAME(0xf, 0xd, "DMA Request") PORT_DIPLOCATION("J9:1,2,3,4") + PORT_DIPSETTING(0xe, "Channel 0") + PORT_DIPSETTING(0xd, "Channel 5") + PORT_DIPSETTING(0xb, "Channel 6") + PORT_DIPSETTING(0x7, "Channel 7") + + PORT_START("DMAACK") + PORT_DIPNAME(0xf, 0xd, "DMA Acknowledge") PORT_DIPLOCATION("J9:5,6,7,8") + PORT_DIPSETTING(0xe, "Channel 0") + PORT_DIPSETTING(0xd, "Channel 5") + PORT_DIPSETTING(0xb, "Channel 6") + PORT_DIPSETTING(0x7, "Channel 7") + + PORT_START("IRQ") + PORT_DIPNAME(0x3f, 0x3b, "Interrupt") PORT_DIPLOCATION("J9:9,10,11,12,13,14") + PORT_DIPSETTING(0x3e, "IRQ 9") + PORT_DIPSETTING(0x3d, "IRQ 10") + PORT_DIPSETTING(0x3b, "IRQ 11") + PORT_DIPSETTING(0x37, "IRQ 12") + PORT_DIPSETTING(0x2f, "IRQ 14") + PORT_DIPSETTING(0x1f, "IRQ 15") + + PORT_START("BIOSWAIT") + PORT_DIPNAME(0x3, 0x3, "BIOS Wait State") PORT_DIPLOCATION("J7:5,6") + PORT_DIPSETTING(0x3, "Disabled") + PORT_DIPSETTING(0x2, "100 ns") + PORT_DIPSETTING(0x1, "200 ns") + PORT_DIPSETTING(0x0, "300 ns") + + PORT_START("PORTADDR") + PORT_DIPNAME(0x7, 0x6, "I/O Port Address") PORT_DIPLOCATION("J7:2,3,4") + PORT_DIPSETTING(0x2, "130h") + PORT_DIPSETTING(0x3, "134h") + PORT_DIPSETTING(0x4, "230h") + PORT_DIPSETTING(0x5, "234h") + PORT_DIPSETTING(0x6, "330h") + PORT_DIPSETTING(0x7, "334h") + + PORT_START("BIOSADDR") + PORT_DIPNAME(0x3, 0x3, "BIOS Base Address") PORT_DIPLOCATION("J7:8,7") + PORT_DIPSETTING(0x0, "0C8000h") + PORT_DIPSETTING(0x1, "0CC000h") + PORT_DIPSETTING(0x2, "0D8000h") + PORT_DIPSETTING(0x3, "0DC000h") + PORT_DIPNAME(0x4, 0x0, "System BIOS") PORT_DIPLOCATION("J6:1") + PORT_DIPSETTING(0x4, "Disabled") + PORT_DIPSETTING(0x0, "Enabled") + + PORT_START("AUX") + PORT_DIPNAME(0x1, 0x1, DEF_STR(Unused)) PORT_DIPLOCATION("J6:2") + PORT_DIPSETTING(0x1, DEF_STR(Off)) + PORT_DIPSETTING(0x0, DEF_STR(On)) + PORT_DIPNAME(0x2, 0x2, DEF_STR(Unused)) PORT_DIPLOCATION("J6:3") + PORT_DIPSETTING(0x2, DEF_STR(Off)) + PORT_DIPSETTING(0x0, DEF_STR(On)) + PORT_DIPNAME(0x4, 0x4, DEF_STR(Unused)) PORT_DIPLOCATION("J6:4") + PORT_DIPSETTING(0x4, DEF_STR(Off)) + PORT_DIPSETTING(0x0, DEF_STR(On)) + PORT_DIPNAME(0x8, 0x8, "Automatic Request Sense") PORT_DIPLOCATION("J6:5") + PORT_DIPSETTING(0x0, "Disabled") + PORT_DIPSETTING(0x8, "Enabled") + + PORT_START("FDCCFG") + PORT_DIPNAME(0x1, 0x1, "Floppy Secondary Address") PORT_DIPLOCATION("J7:1") + PORT_DIPSETTING(0x1, "170h-177h") + PORT_DIPSETTING(0x0, "1F0h-1F7h") + PORT_DIPNAME(0x2, 0x0, "Floppy Disk Controller") PORT_DIPLOCATION("J8:1") + PORT_DIPSETTING(0x2, DEF_STR(Off)) + PORT_DIPSETTING(0x0, DEF_STR(On)) + PORT_DIPNAME(0x4, 0x4, "Floppy Dual Channel Speed") PORT_DIPLOCATION("J8:8") + PORT_DIPSETTING(0x4, DEF_STR(Off)) + PORT_DIPSETTING(0x0, DEF_STR(On)) + + PORT_START("FDCIRQ") + PORT_DIPNAME(0x3, 0x2, "FDC Interrupt") PORT_DIPLOCATION("J8:6,7") + PORT_DIPSETTING(0x2, "Channel 6") + PORT_DIPSETTING(0x1, "Channel 10") + + PORT_START("FDCDREQ") + PORT_DIPNAME(0x3, 0x2, "FDC DMA Request") PORT_DIPLOCATION("J8:2,3") + PORT_DIPSETTING(0x2, "Channel 2") + PORT_DIPSETTING(0x1, "Channel 3") + + PORT_START("FDCDACK") + PORT_DIPNAME(0x3, 0x2, "FDC DMA Acknowledge") PORT_DIPLOCATION("J8:4,5") + PORT_DIPSETTING(0x2, "Channel 2") + PORT_DIPSETTING(0x1, "Channel 3") +INPUT_PORTS_END + +ioport_constructor aha1542a_device::device_input_ports() const +{ + return INPUT_PORTS_NAME(aha1542a); +} + +ioport_constructor aha1542b_device::device_input_ports() const +{ + return INPUT_PORTS_NAME(aha1542b); +} + +static void aha154x_scsi_devices(device_slot_interface &device) +{ + device.option_add("harddisk", NSCSI_HARDDISK); + device.option_add_internal("scsic", AIC6250); +} + +void aha154x_device::scsic_config(device_t *device) +{ + device->set_clock(20'000'000); + downcast<aic6250_device &>(*device).int_cb().set_inputline("^^localcpu", I8085_RST65_LINE); + downcast<aic6250_device &>(*device).port_a_r_cb().set_ioport("^^SETUP"); + downcast<aic6250_device &>(*device).port_b_r_cb().set_ioport("^^CONFIG"); +} + +void aha154x_device::device_add_mconfig(machine_config &config) +{ + i8085a_cpu_device &localcpu(I8085A(config, "localcpu", 10'000'000)); + localcpu.set_addrmap(AS_PROGRAM, &aha154x_device::i8085_map); + + NSCSI_BUS(config, "scsi"); + NSCSI_CONNECTOR(config, "scsi:0", aha154x_scsi_devices, nullptr); + NSCSI_CONNECTOR(config, "scsi:1", aha154x_scsi_devices, nullptr); + NSCSI_CONNECTOR(config, "scsi:2", aha154x_scsi_devices, nullptr); + NSCSI_CONNECTOR(config, "scsi:3", aha154x_scsi_devices, nullptr); + NSCSI_CONNECTOR(config, "scsi:4", aha154x_scsi_devices, nullptr); + NSCSI_CONNECTOR(config, "scsi:5", aha154x_scsi_devices, nullptr); + NSCSI_CONNECTOR(config, "scsi:6", aha154x_scsi_devices, nullptr); + NSCSI_CONNECTOR(config, "scsi:7", aha154x_scsi_devices, "scsic", true) + .set_option_machine_config("scsic", [this] (device_t *device) { scsic_config(device); }); + + DP8473(config, m_fdc, 24_MHz_XTAL); +} + + +ROM_START(aha1542a) + ROM_REGION(0x4000, "bios", 0) + ROM_LOAD("b_9700.bin", 0x0000, 0x4000, CRC(35f546e9) SHA1(f559b08f52044f53836021a83f56f628e32216bd)) + + ROM_REGION(0x4000, "mcode", 0) + ROM_LOAD("m_e7bc.bin", 0x0000, 0x4000, CRC(985b7a31) SHA1(bba0d84fa1b67ea71905953c25201fa2020cf465)) +ROM_END + +ROM_START(aha1542b) + ROM_REGION(0x4000, "bios", 0) + ROM_SYSTEM_BIOS(0, "v310", "AT/SCSI BIOS Version 3.10") + ROMX_LOAD("adaptec_inc_420412-00_b_bios_bc00_1990.bin", 0x0000, 0x4000, CRC(bd3f74e7) SHA1(c38d82fd50e5439812fa093e0d4f5fd136c63844), ROM_BIOS(0)) + ROM_SYSTEM_BIOS(1, "v310a", "AT/SCSI BIOS Version 3.10A (port 334h)") + ROMX_LOAD("154xp334.bin", 0x0000, 0x4000, CRC(4911f232) SHA1(2e24ce380c6f7694c45484019857cb919e2a9965), ROM_BIOS(1)) + ROM_SYSTEM_BIOS(2, "v311", "AT/SCSI BIOS Version 3.11") + ROMX_LOAD("bios_c900.u13", 0x0000, 0x4000, CRC(4660d0c1) SHA1(a581291de96836b6f6cc0b6244b8fa1ee333346a), ROM_BIOS(2)) + ROM_SYSTEM_BIOS(3, "v320g", "AT/SCSI BIOS Version 3.20 (> 1 GB support)") + ROMX_LOAD("b_bd00.bin", 0x0000, 0x4000, CRC(2387197b) SHA1(703e1fe1ba924c02d617ac37ec7a20e12bef1cc7), ROM_BIOS(3)) + ROM_SYSTEM_BIOS(4, "v320gt", "AT/SCSI BIOS Version 3.20 (extended timeout)") + ROMX_LOAD("b_b300.bin", 0x0000, 0x4000, CRC(4c5b07d8) SHA1(692e824f916f55519c9905839f5f6609f5e8c0a5), ROM_BIOS(4)) + ROM_SYSTEM_BIOS(5, "v320a", "AT/SCSI BIOS Version 3.20Alt (port 334h)") + ROMX_LOAD("b_ac00.bin", 0x0000, 0x4000, CRC(becd6d08) SHA1(b5e7cbdeb241c1ff57602291e87c58ac0ee72d54), ROM_BIOS(5)) + + ROM_REGION(0x4000, "mcode", 0) + ROMX_LOAD("adaptec_inc_434108-00_a_mcode_fc8a_1990.bin", 0x0000, 0x4000, CRC(6801f89e) SHA1(33d36bc93734105b950414e7c433a283032838e9), ROM_BIOS(0)) + ROMX_LOAD("adaptec_inc_434108-00_a_mcode_fc8a_1990.bin", 0x0000, 0x4000, CRC(6801f89e) SHA1(33d36bc93734105b950414e7c433a283032838e9), ROM_BIOS(1)) // assumed compatible with v310a BIOS + ROMX_LOAD("firmware_62d3.u12", 0x0000, 0x4000, CRC(6056ca33) SHA1(8dd4aaffcb107dbcc85ac87d878fa6093b904a20), ROM_BIOS(2)) + ROMX_LOAD("m_3054.bin", 0x0000, 0x4000, CRC(461b1885) SHA1(50dc49b0fd88b116b83e3c71f58c758b618d1ddf), ROM_BIOS(3)) + ROMX_LOAD("m_5d98.bin", 0x0000, 0x4000, CRC(f7d51536) SHA1(5ad1bb4bde3e8c30380b05d32ac273c781ab12a8), ROM_BIOS(4)) // also provided with v320g BIOS + ROMX_LOAD("m_3054.bin", 0x0000, 0x4000, CRC(461b1885) SHA1(50dc49b0fd88b116b83e3c71f58c758b618d1ddf), ROM_BIOS(5)) +ROM_END + +const tiny_rom_entry *aha1542a_device::device_rom_region() const +{ + return ROM_NAME(aha1542a); +} + +const tiny_rom_entry *aha1542b_device::device_rom_region() const +{ + return ROM_NAME(aha1542b); +} diff --git a/src/devices/bus/isa/aha1542b.h b/src/devices/bus/isa/aha1542b.h new file mode 100644 index 00000000000..88f18941909 --- /dev/null +++ b/src/devices/bus/isa/aha1542b.h @@ -0,0 +1,59 @@ +// license:BSD-3-Clause +// copyright-holders:AJR +/*************************************************************************** + + Adaptec AHA-1540/42A and AHA-1540/42B SCSI controllers + +***************************************************************************/ + +#ifndef MAME_BUS_ISA_AHA1542B_H +#define MAME_BUS_ISA_AHA1542B_H + +#pragma once + +#include "isa.h" +#include "machine/upd765.h" + +class aha154x_device : public device_t, public device_isa16_card_interface +{ +protected: + aha154x_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock); + + virtual void device_start() override; + virtual void device_add_mconfig(machine_config &config) override; + + void i8085_map(address_map &map); + void scsic_config(device_t *device); + + required_device<upd765_family_device> m_fdc; + required_region_ptr<u8> m_bios; +}; + +class aha1542a_device : public aha154x_device +{ +public: + aha1542a_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); + + static constexpr feature_type unemulated_features() { return feature::DISK; } + +protected: + virtual ioport_constructor device_input_ports() const override; + virtual const tiny_rom_entry *device_rom_region() const override; +}; + +class aha1542b_device : public aha154x_device +{ +public: + aha1542b_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); + + static constexpr feature_type unemulated_features() { return feature::DISK; } + +protected: + virtual ioport_constructor device_input_ports() const override; + virtual const tiny_rom_entry *device_rom_region() const override; +}; + +DECLARE_DEVICE_TYPE(AHA1542A, aha1542a_device) +DECLARE_DEVICE_TYPE(AHA1542B, aha1542b_device) + +#endif // MAME_BUS_ISA_AHA1542B_H diff --git a/src/devices/bus/isa/aha1542c.cpp b/src/devices/bus/isa/aha1542c.cpp new file mode 100644 index 00000000000..d5c35166b1f --- /dev/null +++ b/src/devices/bus/isa/aha1542c.cpp @@ -0,0 +1,387 @@ +// license:BSD-3-Clause +// copyright-holders:Darkstar +/********************************************************************** + * + * Adaptec AHA-1542{C,CF,CP} SCSI Controller + * + **********************************************************************/ + +/* +Hardware info by Guru + +Adaptec 1993 + +PCB Layout +---------- + +Adaptec AHA-1542CF/1542CF +FCC ID: FGT1542CF +FAB 545107-00 REV C +ASSY 545106-00 + +|-------|---------------|---|-------------------|--| +| J1 | FLOPPY34 | | SCSI50 | | +| |---------------| |-------------------| | +| S1 DS1 | +| | +| |------| DS2107AS DS2107AS |--| +| |PC8477| 24MHz Z84C0010 | | +| PAL |BV-1 | |S | +| | | |----------| | | +| |------| | | |C | +| 93C46.U11 20MHz | | | | +| UM6264 MCODE.U15 |ADAPTEC | |S | +| |AIC-7970Q | | | +| BIOS.U16 | | |I | +| | | | | +| |----------| |--| +| | +|-| |--| |----| + |--------------| |-------------------------| + +Notes: + J1 - 4-position header for drive activity external LED connection + S1 - 8-position DIP Switch (See Table A) + PC8477BV-1 - National Semiconductor PC8477BV-1 'SuperFDC' Advanced Floppy Disk Controller (PLCC68) + This is software compatible with NEC uPD765 and pin compatible with Intel 82077AA + Labelled "AHA-1542CF/552800-01 F/9513" + Clock input 24.000MHz + SCSI - 50-pin Centronics style external SCSI connector (DDK 57AE-40500-21D) + Z84C0010 - Zilog Z84C0010VEC Z80 CPU. Clock input 20/2 [10.000MHz] sourced from AIC-7970Q (PLCC44) + 93C46.U11 - Atmel 93C46 128b x8-bit / 64b x16-bit (1kB) EEPROM labelled '545120A' (SOIC8) + 6264 - Unicorn Microelectronics UM6264BM-10L 8k x8-bit Static RAM (SOJ28) + MCODE.U15 - ST Microelectronics M27C256B 32k x8-bit EPROM labelled 'ADAPTEC INC 553801-00 E MCODE 4B81' (DIP28) + BIOS.U16 - ST Microelectronics M27C256B 32k x8-bit EPROM labelled 'ADAPTEC INC 553601-00 E BIOS 7600' (DIP28) + BIOS 0x7600h is revision 2.10 + PAL - AMD PALCE16V8H-15JC/4 PAL (SOJ20) + AIC-7970Q - Adaptec AIC-7970Q Fast SCSI Controller IC. Clock input 20.000MHz (QFP144) + DS2107AS - Dallas DS2107AS SCSI Active Terminator (SOIC16) + DS1 - Internal Drive Activity LED + SCSI50 - 50-pin Right Angled Flat Cable Connector With Support For Up To 7 SCSI Drives + FLOPPY34 - 34-pin Right Angled Flat Cable Connector With Support For Up To 2 Floppy Drives (360kb,720kb,1.2MB,1.44MB) + + +Table A - S1 DIP Switch Description +----------------------------------- + +Default: All DIP Switches OFF (i.e. Settings changed via BIOS and saved in EEPROM) +Software Defaults = * +----------------------+-----+-----+-----+-----+-----+-----+-----+-----+ + | SW1 | SW2 | SW3 | SW4 | SW5 | SW6 | SW7 | SW8 | +----------------------|-----+-----+-----+-----+-----+-----+-----+-----+ +Termination Enabled | ON | | | | | | | | + Set In BIOS*| OFF | | | | | | | | +----------------------+-----+-----+-----+-----+ | | | | +I/O Port 330H*| | OFF | OFF | OFF | | | | | + 334H | | ON | OFF | OFF | | | | | + 230H | | OFF | ON | OFF | | | | | + 234H | | ON | ON | OFF | | | | | + 130H | | OFF | OFF | ON | | | | | + 134H | | ON | OFF | ON | | | | | + Reserved | | OFF | ON | ON | | | | | + Reserved | | ON | ON | ON | | | | | +----------------------+-----+-----+-----+-----+-----+ | | | +Enable Floppy Yes*| | OFF | | | | + No | | ON | | | | +----------------------+-----------------------+-----+-----+-----+-----+ +BIOS Address DC000H*| | OFF | OFF | OFF | + D8000H | | ON | OFF | OFF | + D4000H | | OFF | ON | OFF | + D0000H | | ON | ON | OFF | + CC000H | | OFF | OFF | ON | + C8000H | | ON | OFF | ON | + Reserved | | OFF | ON | ON | + BIOS Disabled | | ON | ON | ON | +----------------------+-----------------------------+-----+-----+-----+ + +Documentation: +Adaptec AHA-1540CF/1542CF Installation Guide +http://download.adaptec.com/pdfs/installation_guides/aha1540cf_ig.pdf + */ + +#include "emu.h" +#include "aha1542c.h" +#include "cpu/z80/z80.h" + +// I/O Port interface +// READ Port x+0: STATUS +// WRITE Port x+0: CONTROL +// +// READ Port x+1: DATA +// WRITE Port x+1: COMMAND +// +// READ Port x+2: INTERRUPT STATUS +// WRITE Port x+2: (undefined?) +// +// R/W Port x+3: (undefined) + +// READ STATUS flags +#define STAT_STST 0x80 // self-test in progress +#define STAT_DIAGF 0x40 // internal diagnostic failure +#define STAT_INIT 0x20 // mailbox initialization required +#define STAT_IDLE 0x10 // HBA is idle +#define STAT_CDFULL 0x08 // Command/Data output port is full +#define STAT_DFULL 0x04 // Data input port is full +#define STAT_INVCMD 0x01 // Invalid command + +// READ INTERRUPT STATUS flags +#define INTR_ANY 0x80 // any interrupt +#define INTR_SRCD 0x08 // SCSI reset detected +#define INTR_HACC 0x04 // HA command complete +#define INTR_MBOA 0x02 // MBO empty +#define INTR_MBIF 0x01 // MBI full + +// WRITE CONTROL commands +#define CTRL_HRST 0x80 // Hard reset +#define CTRL_SRST 0x40 // Soft reset +#define CTRL_IRST 0x20 // interrupt reset +#define CTRL_SCRST 0x10 // SCSI bus reset + +// READ/WRITE DATA commands +#define CMD_NOP 0x00 // No operation +#define CMD_MBINIT 0x01 // mailbox initialization +#define CMD_START_SCSI 0x02 // Start SCSI command +#define CMD_BIOSCMD 0x03 // undocumented BIOS conmmand (shadow RAM etc.) +#define CMD_INQUIRY 0x04 // Adapter inquiry +#define CMD_EMBOI 0x05 // enable Mailbox Out Interrupt +#define CMD_SELTIMEOUT 0x06 // Set SEL timeout +#define CMD_BUSON_TIME 0x07 // set bus-On time +#define CMD_BUSOFF_TIME 0x08 // set bus-off time +#define CMD_DMASPEED 0x09 // set ISA DMA speed +#define CMD_RETDEVS 0x0a // return installed devices +#define CMD_RETCONF 0x0b // return configuration data +#define CMD_TARGET 0x0c // set HBA to target mode +#define CMD_RETSETUP 0x0d // return setup data +#define CMD_ECHO 0x1f // ECHO command data (NetBSD says it is 0x1e) + +// these are for 1541C only: +#define CMD_RETDEVSHI 0x23 // return devices 8-15 (from NetBSD) +#define CMD_EXTBIOS 0x28 // return extended BIOS information +#define CMD_MBENABLE 0x29 // set mailbox interface enable + +DEFINE_DEVICE_TYPE(AHA1542C, aha1542c_device, "aha1542c", "AHA-1542C SCSI Controller") +DEFINE_DEVICE_TYPE(AHA1542CF, aha1542cf_device, "aha1542cf", "AHA-1542CF SCSI Controller") +DEFINE_DEVICE_TYPE(AHA1542CP, aha1542cp_device, "aha1542cp", "AHA-1542CP SCSI Controller") + +#define Z84C0010_TAG "z84c0010" + +READ8_MEMBER( aha1542c_device::aha1542_r ) +{ + logerror("%s aha1542_r(): offset=%d\n", machine().describe_context(), offset); + return 0xff; +} + +WRITE8_MEMBER( aha1542c_device::aha1542_w ) +{ + logerror("%s aha1542_w(): offset=%d data=0x%02x\n", machine().describe_context(), offset, data); +} + + +ROM_START( aha1542c ) + ROM_REGION( 0x8000, "aha1542", 0 ) + ROM_SYSTEM_BIOS( 0, "v101", "AHA-1540C/1542C BIOS v1.01" ) + ROMX_LOAD( "adaptec_inc_534201-00_d_bios_144c_1993.u15", 0x0000, 0x8000, CRC(35178004) SHA1(2b38f2e40cd02a1b32966ead7b202b0fca130cb8), ROM_BIOS(0) ) + ROM_SYSTEM_BIOS( 1, "v102", "AHA-1540C/1542C BIOS v1.02" ) + ROMX_LOAD( "b_91c5.bin", 0x0000, 0x8000, CRC(076ac252) SHA1(d640b980e85d07029d8ce11a52fa26ba0f93c5de), ROM_BIOS(1) ) + + ROM_REGION( 0x8000, Z84C0010_TAG, 0 ) + ROMX_LOAD( "adaptec_inc_534001-00_d_mcode_a3c2_1993.u5", 0x0000, 0x8000, CRC(220dd5a2) SHA1(4fc51c9dd63b45a50edcd56baa706d61decbef38), ROM_BIOS(0) ) + ROMX_LOAD( "m_866a.bin", 0x0000, 0x8000, CRC(ef09053a) SHA1(ae7900653357d5f32a2734bc13d9ec63bd805597), ROM_BIOS(1) ) +ROM_END + +ROM_START( aha1542cf ) + ROM_REGION( 0x8000, "aha1542", 0 ) + ROM_SYSTEM_BIOS( 0, "v201", "Adaptec 1540CF/1542CF BIOS v2.01" ) + ROMX_LOAD( "adaptec_inc_553601-00_c_bios_c38d_1993.u16", 0x0000, 0x8000, CRC(ab22fc02) SHA1(f9f783e0272fc14ba3de32316997f1f6cadc67d0), ROM_BIOS(0) ) + ROM_SYSTEM_BIOS( 1, "v210", "Adaptec 1540CF/1542CF BIOS v2.10" ) + ROMX_LOAD( "adaptec_inc_553601-00_e_bios_7600_1994.u16", 0x0000, 0x8000, CRC(8f3a2692) SHA1(b9dbd49baeec55098195131d0ed1a9bfe8463640), ROM_BIOS(1) ) + ROM_SYSTEM_BIOS( 2, "v211", "Adaptec 1540CF/1542CF BIOS v2.11" ) + ROMX_LOAD( "adaptec_inc_553601-00_g_bios_b402_1995.u16", 0x0000, 0x8000, CRC(fddd0b83) SHA1(aabd227cb338d8812e0bb5c17c08ea06c5aedd36), ROM_BIOS(2) ) + + ROM_REGION( 0x8000, Z84C0010_TAG, 0 ) + ROMX_LOAD( "adaptec_inc_553801-00_c_mcode_563d_1993.u15", 0x0000, 0x8000, CRC(7824397e) SHA1(35bc2c8fab31aad3190a478f2dc8f3a72958cf04), ROM_BIOS(0) ) + ROMX_LOAD( "adaptec_inc_553801-00_e_mcode_4b81_1994.u15", 0x0000, 0x8000, CRC(dd651476) SHA1(cda508281302be53ebdcf8daa61754c89ad12111), ROM_BIOS(1) ) + ROMX_LOAD( "adaptec_inc_553801-00_g_mcode_2cde_1995.u15", 0x0000, 0x8000, CRC(896873cd) SHA1(6edbdd9b0b15ef31ca0741cac31556d2d5266b6e), ROM_BIOS(2) ) +ROM_END + +ROM_START( aha1542cp ) + ROM_REGION( 0x8000, "aha1542", 0 ) + ROM_LOAD( "adaptec_inc_908501-00_d_bios_a91e_1995.u7", 0x0000, 0x8000, CRC(0646c35e) SHA1(3a7c2731abd8295438cfa1f2a525be53e9512b1a) ) + + ROM_REGION( 0x8000, Z84C0010_TAG, 0 ) + ROM_LOAD( "908301-00_f_mcode_17c9.u12", 0x0000, 0x8000, CRC(04494022) SHA1(431dfc26312556ddd24fccc429b2b3e93bac5c2f) ) +ROM_END + + +void aha1542c_device::local_latch_w(u8 data) +{ + m_eeprom->cs_write(BIT(data, 2)); + m_eeprom->clk_write(BIT(data, 1)); + m_eeprom->di_write(BIT(data, 0)); + // TODO: several other bits are used +} + +void aha1542c_device::z84c0010_mem(address_map &map) +{ + map(0x0000, 0x7fff).rom().region(Z84C0010_TAG, 0); + map(0x8000, 0x9fff).ram(); // 2kb RAM chip + map(0xa000, 0xa000).portr("SWITCHES"); + map(0xb000, 0xb000).w(FUNC(aha1542c_device::local_latch_w)); + map(0xe000, 0xe0ff).ram(); // probably PC<->Z80 communication area + map(0xe003, 0xe003).lr8("e003_r", []() { return 0x20; }); +} + +u8 aha1542cp_device::eeprom_r() +{ + // TODO: bits 4 and 5 are also used + return m_eeprom->do_read(); +} + +void aha1542cp_device::eeprom_w(u8 data) +{ + m_eeprom->cs_write(BIT(data, 2)); + m_eeprom->clk_write(BIT(data, 1)); + m_eeprom->di_write(BIT(data, 0)); +} + +void aha1542cp_device::local_mem(address_map &map) +{ + map(0x0000, 0x7fff).rom().region(Z84C0010_TAG, 0); + map(0x8000, 0x9fff).ram(); + map(0xc000, 0xc000).portr("SWITCHES"); + map(0xc001, 0xc001).rw(FUNC(aha1542cp_device::eeprom_r), FUNC(aha1542cp_device::eeprom_w)); + map(0xe003, 0xe003).nopr(); +} + +static INPUT_PORTS_START( aha1542c ) + PORT_START("SWITCHES") + PORT_DIPNAME(0x07, 0x07, "I/O Port Address") PORT_DIPLOCATION("S1:2,3,4") + PORT_DIPSETTING(0x07, "330-333h") + PORT_DIPSETTING(0x06, "334-337h") + PORT_DIPSETTING(0x05, "230-233h") + PORT_DIPSETTING(0x04, "234-237h") + PORT_DIPSETTING(0x03, "130-133h") + PORT_DIPSETTING(0x02, "134-137h") + PORT_DIPSETTING(0x00, "Diagnostics Only") // not documented + PORT_DIPNAME(0x08, 0x08, "SCSI Termination") PORT_DIPLOCATION("S1:1") + PORT_DIPSETTING(0x00, "Installed") + PORT_DIPSETTING(0x08, "Software Controlled") + PORT_DIPNAME(0x70, 0x70, "BIOS Address") PORT_DIPLOCATION("S1:6,7,8") + PORT_DIPSETTING(0x00, "Disabled") + PORT_DIPSETTING(0x20, "C8000h") + PORT_DIPSETTING(0x30, "CC000h") + PORT_DIPSETTING(0x40, "D0000h") + PORT_DIPSETTING(0x50, "D4000h") + PORT_DIPSETTING(0x60, "D8000h") + PORT_DIPSETTING(0x70, "DC000h") + PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_CUSTOM) PORT_READ_LINE_DEVICE_MEMBER("eeprom", eeprom_serial_93cxx_device, do_read) + + PORT_START("FDC_CONFIG") + PORT_DIPNAME(0x1, 0x1, "Floppy Disk Controller") PORT_DIPLOCATION("S1:5") + PORT_DIPSETTING(0x0, "Disabled") + PORT_DIPSETTING(0x1, "Enabled") +INPUT_PORTS_END + +static INPUT_PORTS_START( aha1542cp ) + PORT_START("SWITCHES") + PORT_DIPNAME(0x0e, 0x0e, "I/O Port Address") PORT_DIPLOCATION("S1:2,3,4") + PORT_DIPSETTING(0x0e, "330-333h") + PORT_DIPSETTING(0x0c, "334-337h") + PORT_DIPSETTING(0x0a, "230-233h") + PORT_DIPSETTING(0x08, "234-237h") + PORT_DIPSETTING(0x06, "130-133h") + PORT_DIPSETTING(0x04, "134-137h") + PORT_DIPSETTING(0x00, "Diagnostics Only") // not documented + PORT_DIPNAME(0x10, 0x10, "Plug and Play") PORT_DIPLOCATION("S1:1") + PORT_DIPSETTING(0x00, "Disabled") + PORT_DIPSETTING(0x10, "Enabled") + PORT_DIPNAME(0xe0, 0xe0, "BIOS Address") PORT_DIPLOCATION("S1:6,7,8") + PORT_DIPSETTING(0x00, "Disabled") + PORT_DIPSETTING(0x40, "C8000h") + PORT_DIPSETTING(0x60, "CC000h") + PORT_DIPSETTING(0x80, "D0000h") + PORT_DIPSETTING(0xa0, "D4000h") + PORT_DIPSETTING(0xc0, "D8000h") + PORT_DIPSETTING(0xe0, "DC000h") + + PORT_START("FDC_CONFIG") + PORT_DIPNAME(0x1, 0x1, "Floppy Disk Controller") PORT_DIPLOCATION("S1:5") + PORT_DIPSETTING(0x0, "Disabled") + PORT_DIPSETTING(0x1, "Enabled") +INPUT_PORTS_END + +ioport_constructor aha1542c_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( aha1542c ); +} + +ioport_constructor aha1542cp_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( aha1542cp ); +} + +const tiny_rom_entry *aha1542c_device::device_rom_region() const +{ + return ROM_NAME( aha1542c ); +} + +const tiny_rom_entry *aha1542cf_device::device_rom_region() const +{ + return ROM_NAME( aha1542cf ); +} + +const tiny_rom_entry *aha1542cp_device::device_rom_region() const +{ + return ROM_NAME( aha1542cp ); +} + +void aha1542c_device::device_add_mconfig(machine_config &config) +{ + z80_device &cpu(Z80(config, Z84C0010_TAG, 10'000'000)); + cpu.set_addrmap(AS_PROGRAM, &aha1542c_device::z84c0010_mem); + + EEPROM_93C46_16BIT(config, m_eeprom); +} + +void aha1542cp_device::device_add_mconfig(machine_config &config) +{ + z80_device &cpu(Z80(config, Z84C0010_TAG, 10'000'000)); + cpu.set_addrmap(AS_PROGRAM, &aha1542cp_device::local_mem); + + EEPROM_93C46_16BIT(config, m_eeprom); +} + +aha1542c_device::aha1542c_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock) + : device_t(mconfig, type, tag, owner, clock) + , device_isa16_card_interface(mconfig, *this) + , m_eeprom(*this, "eeprom") +{ +} + +aha1542c_device::aha1542c_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) + : aha1542c_device(mconfig, AHA1542C, tag, owner, clock) +{ +} + +aha1542cf_device::aha1542cf_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) + : aha1542c_device(mconfig, AHA1542CF, tag, owner, clock) +{ +} + +aha1542cp_device::aha1542cp_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) + : aha1542c_device(mconfig, AHA1542CP, tag, owner, clock) +{ +} + +void aha1542c_device::device_start() +{ + set_isa_device(); + m_isa->install_rom(this, 0xdc000, 0xdffff, "aha1542", "aha1542"); + m_isa->install_device(0x330, 0x333, read8_delegate(FUNC( aha1542cf_device::aha1542_r ), this), + write8_delegate(FUNC( aha1542cf_device::aha1542_w ), this) ); +} + + +void aha1542c_device::device_reset() +{ +} diff --git a/src/devices/bus/isa/aha1542c.h b/src/devices/bus/isa/aha1542c.h new file mode 100644 index 00000000000..005c688c053 --- /dev/null +++ b/src/devices/bus/isa/aha1542c.h @@ -0,0 +1,96 @@ +// license:BSD-3-Clause +// copyright-holders:Darkstar +/********************************************************************** + * + * Adaptec AHA-1542{C,CF,CP} SCSI Controller + * + ********************************************************************** + + + + **********************************************************************/ + +#ifndef MAME_BUS_AHA1542C_H +#define MAME_BUS_AHA1542C_H + +#pragma once + + +#include "isa.h" +#include "machine/eepromser.h" + +//********************************************************************* +// TYPE DEFINITIONS +//********************************************************************* + +// ====================> aha1542cf_device + +class aha1542c_device : public device_t, + public device_isa16_card_interface +{ +public: + static constexpr feature_type unemulated_features() { return feature::DISK; } + // construction/destruction + aha1542c_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); + + DECLARE_READ8_MEMBER( aha1542_r ); + DECLARE_WRITE8_MEMBER( aha1542_w ); + +protected: + aha1542c_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock); + + void local_latch_w(u8 data); + + // device-level overrides + virtual void device_start() override; + virtual void device_reset() override; + + // optional information overrides + virtual ioport_constructor device_input_ports() const override; + virtual const tiny_rom_entry *device_rom_region() const override; + virtual void device_add_mconfig(machine_config &config) override; + + required_device<eeprom_serial_93cxx_device> m_eeprom; + +private: + void z84c0010_mem(address_map &map); +}; + +// ====================> aha1542cf_device + +class aha1542cf_device : public aha1542c_device +{ +public: + // construction/destruction + aha1542cf_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); + +protected: + virtual const tiny_rom_entry *device_rom_region() const override; +}; + +// ====================> aha1542cp_device + +class aha1542cp_device : public aha1542c_device +{ +public: + // construction/destruction + aha1542cp_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); + +protected: + virtual ioport_constructor device_input_ports() const override; + virtual void device_add_mconfig(machine_config &config) override; + virtual const tiny_rom_entry *device_rom_region() const override; + +private: + u8 eeprom_r(); + void eeprom_w(u8 data); + + void local_mem(address_map &map); +}; + +// device type definitions +DECLARE_DEVICE_TYPE(AHA1542C, aha1542c_device) +DECLARE_DEVICE_TYPE(AHA1542CF, aha1542cf_device) +DECLARE_DEVICE_TYPE(AHA1542CP, aha1542cp_device) + +#endif // MAME_BUS_AHA1542C_H diff --git a/src/devices/bus/isa/aha174x.cpp b/src/devices/bus/isa/aha174x.cpp new file mode 100644 index 00000000000..06b6ddf5f62 --- /dev/null +++ b/src/devices/bus/isa/aha174x.cpp @@ -0,0 +1,160 @@ +// license:BSD-3-Clause +// copyright-holders:AJR +/*************************************************************************** + + Adaptec AHA-1740/44 and AHA-1740A/42A Fast SCSI host adapters + + These are actually EISA cards, though they also have a compatibility + mode that provides an interface like the older ISA AHA-154X series. + + On the AHA-1740 and AHA-1744, the HPC microcode is stored in an EEPROM + (of unknown type), allowing it to be reprogrammed by the host. This is + not possible on the AHA-1740A and AHA-1744A, which use a conventional + 27C256 EPROM for the microcode. In both cases the HPC copies the code + to and then executes it out of RAM. + + Though the AHA-1740 and AHA-1740A have different board layouts, they + share the following ICs: + + AIC-565 Bus Auxiliary Interface Chip + AIC-575 EISA Configuration Chip + AIC-4600 HPC (HPC46003V20) + AIC-6251A SCSI Interface and Protocol Chip + IDT7201 512x9 FIFO (2 on board) + Intel 82355 Bus Master Interface Controller + + AHA-1742A is the same as AHA-1740A, only with the FDC populated. + + AHA-1744 uses the same layout as AHA-1740, but populates the area + around the SCSI port with DS36F95J differential drivers. + +***************************************************************************/ + +#include "emu.h" +#include "aha174x.h" + +#include "machine/aic6250.h" +//#include "machine/i82355.h" +#include "machine/nscsi_bus.h" +#include "machine/nscsi_hd.h" + +DEFINE_DEVICE_TYPE(AHA1740, aha1740_device, "aha1740", "AHA-1740 Fast SCSI Host Adapter") +DEFINE_DEVICE_TYPE(AHA1742A, aha1742a_device, "aha1742a", "AHA-1742A Fast SCSI Host Adapter") + + +aha174x_device::aha174x_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock) + : device_t(mconfig, type, tag, owner, clock) + , device_isa16_card_interface(mconfig, *this) + , m_hpc(*this, "hpc") + , m_bios(*this, "bios") +{ +} + +aha1740_device::aha1740_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) + : aha174x_device(mconfig, AHA1740, tag, owner, clock) +{ +} + +aha1742a_device::aha1742a_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) + : aha174x_device(mconfig, AHA1742A, tag, owner, clock) + , m_fdc(*this, "fdc") +{ +} + +void aha174x_device::device_start() +{ +} + + +void aha174x_device::hpc_map(address_map &map) +{ + map(0x5000, 0x500f).m("scsi:7:scsic", FUNC(aic6251a_device::map)); + map(0x8000, 0xffff).rom().region("mcode", 0); +} + +static void aha174x_scsi_devices(device_slot_interface &device) +{ + device.option_add("harddisk", NSCSI_HARDDISK); + device.option_add_internal("scsic", AIC6251A); +} + +void aha174x_device::scsic_config(device_t *device) +{ + device->set_clock(40_MHz_XTAL / 2); // divider not verified +} + +void aha1740_device::device_add_mconfig(machine_config &config) +{ + HPC46003(config, m_hpc, 40_MHz_XTAL / 2); + m_hpc->set_addrmap(AS_PROGRAM, &aha1740_device::hpc_map); + + NSCSI_BUS(config, "scsi"); + NSCSI_CONNECTOR(config, "scsi:0", aha174x_scsi_devices, nullptr); + NSCSI_CONNECTOR(config, "scsi:1", aha174x_scsi_devices, nullptr); + NSCSI_CONNECTOR(config, "scsi:2", aha174x_scsi_devices, nullptr); + NSCSI_CONNECTOR(config, "scsi:3", aha174x_scsi_devices, nullptr); + NSCSI_CONNECTOR(config, "scsi:4", aha174x_scsi_devices, nullptr); + NSCSI_CONNECTOR(config, "scsi:5", aha174x_scsi_devices, nullptr); + NSCSI_CONNECTOR(config, "scsi:6", aha174x_scsi_devices, nullptr); + NSCSI_CONNECTOR(config, "scsi:7", aha174x_scsi_devices, "scsic", true) + .set_option_machine_config("scsic", [this] (device_t *device) { scsic_config(device); }); +} + +void aha1742a_device::device_add_mconfig(machine_config &config) +{ + HPC46003(config, m_hpc, 40_MHz_XTAL / 2); + m_hpc->set_addrmap(AS_PROGRAM, &aha1742a_device::hpc_map); + + NSCSI_BUS(config, "scsi"); + NSCSI_CONNECTOR(config, "scsi:0", aha174x_scsi_devices, nullptr); + NSCSI_CONNECTOR(config, "scsi:1", aha174x_scsi_devices, nullptr); + NSCSI_CONNECTOR(config, "scsi:2", aha174x_scsi_devices, nullptr); + NSCSI_CONNECTOR(config, "scsi:3", aha174x_scsi_devices, nullptr); + NSCSI_CONNECTOR(config, "scsi:4", aha174x_scsi_devices, nullptr); + NSCSI_CONNECTOR(config, "scsi:5", aha174x_scsi_devices, nullptr); + NSCSI_CONNECTOR(config, "scsi:6", aha174x_scsi_devices, nullptr); + NSCSI_CONNECTOR(config, "scsi:7", aha174x_scsi_devices, "scsic", true) + .set_option_machine_config("scsic", [this] (device_t *device) { scsic_config(device); }); + + N82077AA(config, m_fdc, 24_MHz_XTAL); +} + + +ROM_START(aha1740) + ROM_REGION(0x4000, "bios", 0) + ROM_LOAD("b_dc00.bin", 0x0000, 0x4000, CRC(056d75ec) SHA1(8ca143adfc7d20ad5d49f14dedabc8276454bf9e)) + + ROM_REGION16_LE(0x8000, "mcode", 0) + ROM_SYSTEM_BIOS(0, "v140st", "BIOS v1.40 (Standard Mode)") + ROMX_LOAD("standard.bin", 0x0000, 0x8000, CRC(8c15c6a2) SHA1(77e15b0244e3a814f53f957270e6474a8a839955), ROM_BIOS(0)) + ROM_SYSTEM_BIOS(1, "v140en", "BIOS v1.40 (Enhanced Mode)") + ROMX_LOAD("enhanced.bin", 0x0000, 0x8000, CRC(84b3df89) SHA1(a718c3ea5443a609b4b20bfe48be18193737ad25), ROM_BIOS(1)) + // Adaptec's help file claims that "the EEPROM on the board can hold firmware for both modes simultaneously." + // The AHA-174XA firmware images obviously have this, but the files provided here do not agree. +ROM_END + +ROM_START(aha1742a) + ROM_REGION(0x4000, "bios", 0) + ROM_DEFAULT_BIOS("v140") + ROM_SYSTEM_BIOS(0, "v134", "BIOS v1.34") + ROMX_LOAD("adaptec_inc_450214-00_a_bios_8800_1991.u47", 0x0000, 0x4000, CRC(6cf06151) SHA1(0da45634b12b33fc886920d065cc8ffb2cf376b8), ROM_BIOS(0)) + ROM_SYSTEM_BIOS(1, "v140", "BIOS v1.40") + ROMX_LOAD("adaptec_inc_450216-00_a_bios_dc00_1992.u47", 0x0000, 0x4000, CRC(056d75ec) SHA1(8ca143adfc7d20ad5d49f14dedabc8276454bf9e), ROM_BIOS(1)) + ROM_SYSTEM_BIOS(2, "v140s", "BIOS v1.40 (Extended Timeout)") + ROMX_LOAD("b_f100.bin", 0x0000, 0x4000, CRC(b695acc0) SHA1(683112fafdf83d5eb89237d9215f7d6eacc6eeaf), ROM_BIOS(2)) + + ROM_REGION16_LE(0x8000, "mcode", 0) + ROMX_LOAD("adaptec_inc_450117-00_c_mcode_23a8_1991.u10", 0x0000, 0x8000, NO_DUMP, ROM_BIOS(0)) + ROMX_LOAD("adaptec_inc_450113-00_d_mcode_b7d6_1992.u10", 0x0000, 0x8000, CRC(0a55a555) SHA1(ff400f56b33f0ad94e34564d7715a0773b335844), ROM_BIOS(1)) + ROMX_LOAD("m_c7b8.bin", 0x0000, 0x8000, CRC(21282e86) SHA1(18cb3960dc47f2c14beb88f9680c1f66c4652b04), ROM_BIOS(2)) +ROM_END + +const tiny_rom_entry *aha1740_device::device_rom_region() const +{ + return ROM_NAME(aha1740); +} + +const tiny_rom_entry *aha1742a_device::device_rom_region() const +{ + return ROM_NAME(aha1742a); +} diff --git a/src/devices/bus/isa/aha174x.h b/src/devices/bus/isa/aha174x.h new file mode 100644 index 00000000000..f65ee7de93a --- /dev/null +++ b/src/devices/bus/isa/aha174x.h @@ -0,0 +1,61 @@ +// license:BSD-3-Clause +// copyright-holders:AJR +/*************************************************************************** + + Adaptec AHA-1540/42A and AHA-1540/42B SCSI controllers + +***************************************************************************/ + +#ifndef MAME_BUS_ISA_AHA174X_H +#define MAME_BUS_ISA_AHA174X_H + +#pragma once + +#include "isa.h" +#include "cpu/hpc/hpc.h" +#include "machine/upd765.h" + +class aha174x_device : public device_t, public device_isa16_card_interface +{ +protected: + aha174x_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock); + + virtual void device_start() override; + + void hpc_map(address_map &map); + void scsic_config(device_t *device); + + required_device<hpc46003_device> m_hpc; + required_region_ptr<u8> m_bios; +}; + +class aha1740_device : public aha174x_device +{ +public: + aha1740_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); + + static constexpr feature_type unemulated_features() { return feature::DISK; } + +protected: + virtual void device_add_mconfig(machine_config &config) override; + virtual const tiny_rom_entry *device_rom_region() const override; +}; + +class aha1742a_device : public aha174x_device +{ +public: + aha1742a_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); + + static constexpr feature_type unemulated_features() { return feature::DISK; } + +protected: + virtual void device_add_mconfig(machine_config &config) override; + virtual const tiny_rom_entry *device_rom_region() const override; + + required_device<upd765_family_device> m_fdc; +}; + +DECLARE_DEVICE_TYPE(AHA1740, aha1740_device) +DECLARE_DEVICE_TYPE(AHA1742A, aha1742a_device) + +#endif // MAME_BUS_ISA_AHA174X_H diff --git a/src/devices/bus/isa/bt54x.cpp b/src/devices/bus/isa/bt54x.cpp index baab0247854..d8ef31a848f 100644 --- a/src/devices/bus/isa/bt54x.cpp +++ b/src/devices/bus/isa/bt54x.cpp @@ -9,6 +9,9 @@ believed that these chips are largely compatible with each other, as are the NCR 53CF94 and Emulex FAS216 SCSI controllers. + 2.41/2.21 is the last BIOS version compatible with revisions A-G of + the BT-542B. + ***************************************************************************/ #include "emu.h" @@ -19,10 +22,12 @@ #include "machine/nscsi_cd.h" #include "machine/nscsi_hd.h" +DEFINE_DEVICE_TYPE(BT542B, bt542b_device, "bt542b", "BusTek BT-542B SCSI Host Adapter") // Rev. G or earlier +DEFINE_DEVICE_TYPE(BT542BH, bt542bh_device, "bt542bh", "BusLogic BT-542B SCSI Host Adapter (Rev. H)") DEFINE_DEVICE_TYPE(BT545S, bt545s_device, "bt545s", "BusLogic BT-545S Fast SCSI Host Adapter") -bt545s_device::bt545s_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) - : device_t(mconfig, BT545S, tag, owner, clock) +bt54x_device::bt54x_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock) + : device_t(mconfig, type, tag, owner, clock) , device_isa16_card_interface(mconfig, *this) , m_mpu(*this, "mpu") , m_fdc(*this, "fdc") @@ -30,50 +35,78 @@ bt545s_device::bt545s_device(const machine_config &mconfig, const char *tag, dev { } -void bt545s_device::device_start() +bt542b_device::bt542b_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) + : bt54x_device(mconfig, BT542B, tag, owner, clock) +{ +} + +bt542bh_device::bt542bh_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) + : bt54x_device(mconfig, BT542BH, tag, owner, clock) { } -u8 bt545s_device::local_status_r() +bt545s_device::bt545s_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) + : bt54x_device(mconfig, BT545S, tag, owner, clock) +{ +} + +void bt54x_device::device_start() +{ +} + +u8 bt54x_device::local_status_r() { return 0; } -void bt545s_device::local_map(address_map &map) +void bt54x_device::local_map(address_map &map) { map(0x00000, 0x01fff).ram(); //map(0x02000, 0x0201f).rw("busintf", FUNC(ncr86c05_device::local_read), FUNC(ncr86c05_device::local_write)); - map(0x02080, 0x0208f).m("scsi:7:fsc", FUNC(ncr53cf94_device::map)); - map(0x02180, 0x02180).r(FUNC(bt545s_device::local_status_r)); + map(0x02080, 0x0208f).m("scsi:7:scsic", FUNC(ncr53cf94_device::map)); + map(0x02180, 0x02180).r(FUNC(bt54x_device::local_status_r)); map(0xf8000, 0xfffff).rom().region("mpu", 0); } +static void scsi_devices(device_slot_interface &device) +{ + device.option_add("cdrom", NSCSI_CDROM); + device.option_add("harddisk", NSCSI_HARDDISK); + device.option_add_internal("scsic", NCR53C94); +} + static void fast_scsi_devices(device_slot_interface &device) { - // FIXME: these device options are placeholders device.option_add("cdrom", NSCSI_CDROM); device.option_add("harddisk", NSCSI_HARDDISK); - device.option_add_internal("fsc", NCR53CF94); // FAS216 + device.option_add_internal("scsic", NCR53CF94); // FAS216 +} + +void bt54x_device::asc_config(device_t *device) +{ + ncr53c94_device &asc = downcast<ncr53c94_device &>(*device); + + asc.set_clock(25_MHz_XTAL); // not verified; perhaps selectable? (40 MHz XTAL also on board) + + asc.irq_handler_cb().set(m_mpu, FUNC(i80188_cpu_device::int0_w)); + //asc.drq_handler_cb().set("busintf", FUNC(ncr86c05_device::dma_req_w)); } -void bt545s_device::fsc_config(device_t *device) +void bt54x_device::fsc_config(device_t *device) { ncr53cf94_device &fsc = downcast<ncr53cf94_device &>(*device); fsc.set_clock(40_MHz_XTAL); - fsc.irq_handler_cb().set(m_mpu, FUNC(i80188_cpu_device::int0_w)); // mostly polled + fsc.irq_handler_cb().set(m_mpu, FUNC(i80188_cpu_device::int0_w)); // mostly polled on BT-545S //fsc.drq_handler_cb().set("busintf", FUNC(ncr86c05_device::dma_req_w)); } -void bt545s_device::device_add_mconfig(machine_config &config) +void bt54x_device::fsc_base(machine_config &config) { - I80188(config, m_mpu, 40_MHz_XTAL / 2); // SAB80188-1-N; clock guessed - m_mpu->set_addrmap(AS_PROGRAM, &bt545s_device::local_map); - //ncr86c05_device &busintf(NCR86C05(config, "busintf", 0)); //busintf.mint_callback().set(m_mpu, FUNC(i80188_cpu_device::int1_w)); - //busintf.dma_ack_callback().set("scsi:7:fsc", FUNC(ncr53cf94_device::dma_w)); + //busintf.dma_ack_callback().set("scsi:7:scsic", FUNC(ncr53cf94_device::dma_w)); NSCSI_BUS(config, "scsi"); NSCSI_CONNECTOR(config, "scsi:0", fast_scsi_devices, nullptr); @@ -83,11 +116,67 @@ void bt545s_device::device_add_mconfig(machine_config &config) NSCSI_CONNECTOR(config, "scsi:4", fast_scsi_devices, nullptr); NSCSI_CONNECTOR(config, "scsi:5", fast_scsi_devices, nullptr); NSCSI_CONNECTOR(config, "scsi:6", fast_scsi_devices, nullptr); - NSCSI_CONNECTOR(config, "scsi:7", fast_scsi_devices, "fsc", true).set_option_machine_config("fsc", [this] (device_t *device) { fsc_config(device); }); + NSCSI_CONNECTOR(config, "scsi:7", fast_scsi_devices, "scsic", true).set_option_machine_config("scsic", [this] (device_t *device) { fsc_config(device); }); +} + +void bt542b_device::device_add_mconfig(machine_config &config) +{ + I80188(config, m_mpu, 16_MHz_XTAL); + m_mpu->set_addrmap(AS_PROGRAM, &bt542b_device::local_map); + + //ncr86c05_device &busintf(NCR86C05(config, "busintf", 0)); + //busintf.mint_callback().set(m_mpu, FUNC(i80188_cpu_device::int1_w)); + //busintf.dma_ack_callback().set("scsi:7:scsic", FUNC(ncr53c94_device::dma_w)); + + NSCSI_BUS(config, "scsi"); + NSCSI_CONNECTOR(config, "scsi:0", scsi_devices, nullptr); + NSCSI_CONNECTOR(config, "scsi:1", scsi_devices, nullptr); + NSCSI_CONNECTOR(config, "scsi:2", scsi_devices, nullptr); + NSCSI_CONNECTOR(config, "scsi:3", scsi_devices, nullptr); + NSCSI_CONNECTOR(config, "scsi:4", scsi_devices, nullptr); + NSCSI_CONNECTOR(config, "scsi:5", scsi_devices, nullptr); + NSCSI_CONNECTOR(config, "scsi:6", scsi_devices, nullptr); + NSCSI_CONNECTOR(config, "scsi:7", scsi_devices, "scsic", true).set_option_machine_config("scsic", [this] (device_t *device) { asc_config(device); }); + + DP8473(config, m_fdc, 24_MHz_XTAL); +} + +void bt542bh_device::device_add_mconfig(machine_config &config) +{ + I80188(config, m_mpu, 40_MHz_XTAL / 2); // clock guessed + m_mpu->set_addrmap(AS_PROGRAM, &bt542bh_device::local_map); + + fsc_base(config); + + DP8473(config, m_fdc, 24_MHz_XTAL); +} + +void bt545s_device::device_add_mconfig(machine_config &config) +{ + I80188(config, m_mpu, 40_MHz_XTAL / 2); // SAB80188-1-N; clock guessed + m_mpu->set_addrmap(AS_PROGRAM, &bt545s_device::local_map); + + fsc_base(config); PC8477A(config, m_fdc, 24_MHz_XTAL); // actually PC8477BV } +ROM_START(bt542b) + ROM_REGION(0x4000, "bios", 0) // "(C) Copyright 1991 BIOS Version 2.41" + ROM_LOAD("1000006-2.41_bustek.u15", 0x0000, 0x4000, CRC(5eb00d0f) SHA1(74a8bbae1c2b42f0c605b0ac98660f1e16ac5c4e)) + + ROM_REGION(0x8000, "mpu", 0) // "(C) Copyright 1991 BusTek Corporation 542B 91/12/14" + ROM_LOAD("1000005-2.21_bustek.u2", 0x0000, 0x8000, CRC(c2c66653) SHA1(054ba1ea71b2aaab31ab9dd5aca955d861f5333b)) +ROM_END + +ROM_START(bt542bh) + ROM_REGION(0x8000, "bios", 0) // "(C) Copyright 1992 BIOS Version 4.70M" + ROM_LOAD("5000006-4.70_buslogic.u15", 0x0000, 0x8000, CRC(f5a5e116) SHA1(d7b73015532838dc694edf24308ebbab6f4dd5bb)) + + ROM_REGION(0x8000, "mpu", 0) // "(C) Copyright 1992 BusLogic Inc. 542BH93/05/23" + ROM_LOAD("5000005-3.35_buslogic.u2", 0x0000, 0x8000, CRC(181966c3) SHA1(b9b327d50cd13f3e5b5b53892b18f233aff065b7)) +ROM_END + ROM_START(bt545s) ROM_REGION(0x4000, "bios", 0) // "(C) Copyright 1992 BIOS Version 4.50" ROM_LOAD("u15_27128_5002026-4.50.bin", 0x0000, 0x4000, CRC(1bd3247b) SHA1(9d46a99f4b3057e94ef422f387218de2c4553c1a)) @@ -96,6 +185,16 @@ ROM_START(bt545s) ROM_LOAD("u2_27256_5002005-3.31.bin", 0x0000, 0x8000, CRC(20473714) SHA1(797a8dba182049949f7a5c14d8bef4b4e908305b)) ROM_END +const tiny_rom_entry *bt542b_device::device_rom_region() const +{ + return ROM_NAME(bt542b); +} + +const tiny_rom_entry *bt542bh_device::device_rom_region() const +{ + return ROM_NAME(bt542bh); +} + const tiny_rom_entry *bt545s_device::device_rom_region() const { return ROM_NAME(bt545s); diff --git a/src/devices/bus/isa/bt54x.h b/src/devices/bus/isa/bt54x.h index 754d561978b..dfdd0009416 100644 --- a/src/devices/bus/isa/bt54x.h +++ b/src/devices/bus/isa/bt54x.h @@ -15,29 +15,60 @@ #include "cpu/i86/i186.h" #include "machine/upd765.h" -class bt545s_device : public device_t, public device_isa16_card_interface +class bt54x_device : public device_t, public device_isa16_card_interface { public: - bt545s_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); - static constexpr feature_type unemulated_features() { return feature::DISK; } protected: - virtual void device_add_mconfig(machine_config &config) override; - virtual const tiny_rom_entry *device_rom_region() const override; + bt54x_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock); + virtual void device_start() override; -private: u8 local_status_r(); void local_map(address_map &map); + void asc_config(device_t *device); void fsc_config(device_t *device); + void fsc_base(machine_config &config); required_device<i80188_cpu_device> m_mpu; required_device<upd765_family_device> m_fdc; required_region_ptr<u8> m_bios; }; +class bt542b_device : public bt54x_device +{ +public: + bt542b_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); + +protected: + virtual void device_add_mconfig(machine_config &config) override; + virtual const tiny_rom_entry *device_rom_region() const override; +}; + +class bt542bh_device : public bt54x_device +{ +public: + bt542bh_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); + +protected: + virtual void device_add_mconfig(machine_config &config) override; + virtual const tiny_rom_entry *device_rom_region() const override; +}; + +class bt545s_device : public bt54x_device +{ +public: + bt545s_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); + +protected: + virtual void device_add_mconfig(machine_config &config) override; + virtual const tiny_rom_entry *device_rom_region() const override; +}; + +DECLARE_DEVICE_TYPE(BT542B, bt542b_device) +DECLARE_DEVICE_TYPE(BT542BH, bt542bh_device) DECLARE_DEVICE_TYPE(BT545S, bt545s_device) #endif // MAME_BUS_ISA_BT54X_H diff --git a/src/devices/bus/isa/com.cpp b/src/devices/bus/isa/com.cpp index e9ad68ebee3..6ab3c393ccd 100644 --- a/src/devices/bus/isa/com.cpp +++ b/src/devices/bus/isa/com.cpp @@ -118,10 +118,10 @@ isa8_com_device::isa8_com_device(const machine_config &mconfig, device_type type void isa8_com_device::device_start() { set_isa_device(); - m_isa->install_device(0x03f8, 0x03ff, read8_delegate(FUNC(ins8250_device::ins8250_r), subdevice<ins8250_uart_device>("uart_0")), write8_delegate(FUNC(ins8250_device::ins8250_w), subdevice<ins8250_uart_device>("uart_0")) ); - m_isa->install_device(0x02f8, 0x02ff, read8_delegate(FUNC(ins8250_device::ins8250_r), subdevice<ins8250_uart_device>("uart_1")), write8_delegate(FUNC(ins8250_device::ins8250_w), subdevice<ins8250_uart_device>("uart_1")) ); -// m_isa->install_device(0x03e8, 0x03ef, read8_delegate(FUNC(ins8250_device::ins8250_r), subdevice<ins8250_uart_device>("uart_2")), write8_delegate(FUNC(ins8250_device::ins8250_w), subdevice<ins8250_uart_device>("uart_2")) ); -// m_isa->install_device(0x02e8, 0x02ef, read8_delegate(FUNC(ins8250_device::ins8250_r), subdevice<ins8250_uart_device>("uart_3")), write8_delegate(FUNC(ins8250_device::ins8250_w), subdevice<ins8250_uart_device>("uart_3")) ); + m_isa->install_device(0x03f8, 0x03ff, read8sm_delegate(FUNC(ins8250_device::ins8250_r), subdevice<ins8250_uart_device>("uart_0")), write8sm_delegate(FUNC(ins8250_device::ins8250_w), subdevice<ins8250_uart_device>("uart_0")) ); + m_isa->install_device(0x02f8, 0x02ff, read8sm_delegate(FUNC(ins8250_device::ins8250_r), subdevice<ins8250_uart_device>("uart_1")), write8sm_delegate(FUNC(ins8250_device::ins8250_w), subdevice<ins8250_uart_device>("uart_1")) ); +// m_isa->install_device(0x03e8, 0x03ef, read8sm_delegate(FUNC(ins8250_device::ins8250_r), subdevice<ins8250_uart_device>("uart_2")), write8sm_delegate(FUNC(ins8250_device::ins8250_w), subdevice<ins8250_uart_device>("uart_2")) ); +// m_isa->install_device(0x02e8, 0x02ef, read8sm_delegate(FUNC(ins8250_device::ins8250_r), subdevice<ins8250_uart_device>("uart_3")), write8sm_delegate(FUNC(ins8250_device::ins8250_w), subdevice<ins8250_uart_device>("uart_3")) ); } //------------------------------------------------- diff --git a/src/devices/bus/isa/dcb.cpp b/src/devices/bus/isa/dcb.cpp new file mode 100644 index 00000000000..db5768d6758 --- /dev/null +++ b/src/devices/bus/isa/dcb.cpp @@ -0,0 +1,70 @@ +// license:BSD-3-Clause +// copyright-holders:AJR +/*************************************************************************** + + Novell Disk Coprocessor Board (DCB) + + This special SCSI host adapter, later acquired by ADIC, was designed + for use with Novell NetWare. + +***************************************************************************/ + +#include "emu.h" +#include "dcb.h" + +DEFINE_DEVICE_TYPE(NOVELL_DCB, novell_dcb_device, "novell_dcb", "Novell Disk Coprocessor Board (#738-133-001)") + +novell_dcb_device::novell_dcb_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) + : device_t(mconfig, NOVELL_DCB, tag, owner, clock) + , device_isa16_card_interface(mconfig, *this) + , m_localcpu(*this, "localcpu") + , m_eeprom(*this, "eeprom") +{ +} + +void novell_dcb_device::device_start() +{ +} + +void novell_dcb_device::eeprom_w(u8 data) +{ + m_eeprom->cs_write(BIT(data, 5)); + m_eeprom->clk_write(BIT(data, 6)); + m_eeprom->di_write(BIT(data, 7)); +} + +u8 novell_dcb_device::misc_r() +{ + return m_eeprom->do_read() << 7; +} + +void novell_dcb_device::mem_map(address_map &map) +{ + map(0x00000, 0x03fff).ram(); + map(0xfe000, 0xfffff).rom().region("localcpu", 0); +} + +void novell_dcb_device::io_map(address_map &map) +{ + map(0x0100, 0x0100).w(FUNC(novell_dcb_device::eeprom_w)); + map(0x0180, 0x0180).r(FUNC(novell_dcb_device::misc_r)); +} + +void novell_dcb_device::device_add_mconfig(machine_config &config) +{ + I80188(config, m_localcpu, 16_MHz_XTAL); + m_localcpu->set_addrmap(AS_PROGRAM, &novell_dcb_device::mem_map); + m_localcpu->set_addrmap(AS_IO, &novell_dcb_device::io_map); + + EEPROM_93C06_16BIT(config, m_eeprom); // NMC9306 +} + +ROM_START(novell_dcb) + ROM_REGION(0x2000, "localcpu", 0) + ROM_LOAD("817-186-001_rev_e_5800_11-04-86.bin", 0x0000, 0x2000, CRC(2e2037f4) SHA1(a13c0aab46084a0805256f1d2b8b8beaccc9e253)) +ROM_END + +const tiny_rom_entry *novell_dcb_device::device_rom_region() const +{ + return ROM_NAME(novell_dcb); +} diff --git a/src/devices/bus/isa/dcb.h b/src/devices/bus/isa/dcb.h new file mode 100644 index 00000000000..fbca0303978 --- /dev/null +++ b/src/devices/bus/isa/dcb.h @@ -0,0 +1,43 @@ +// license:BSD-3-Clause +// copyright-holders:AJR +/*************************************************************************** + + Novell Disk Coprocessor Board (DCB) + +***************************************************************************/ + +#ifndef MAME_BUS_ISA_DCB_H +#define MAME_BUS_ISA_DCB_H + +#pragma once + +#include "isa.h" +#include "cpu/i86/i186.h" +#include "machine/eepromser.h" + +class novell_dcb_device : public device_t, public device_isa16_card_interface +{ +public: + novell_dcb_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); + + static constexpr feature_type unemulated_features() { return feature::DISK; } + +protected: + virtual void device_add_mconfig(machine_config &config) override; + virtual const tiny_rom_entry *device_rom_region() const override; + virtual void device_start() override; + +private: + void eeprom_w(u8 data); + u8 misc_r(); + + void mem_map(address_map &map); + void io_map(address_map &map); + + required_device<i80188_cpu_device> m_localcpu; + required_device<eeprom_serial_93cxx_device> m_eeprom; +}; + +DECLARE_DEVICE_TYPE(NOVELL_DCB, novell_dcb_device) + +#endif // MAME_BUS_ISA_DCB_H diff --git a/src/devices/bus/isa/isa_cards.cpp b/src/devices/bus/isa/isa_cards.cpp index 5b52dbd0546..5b0c2315f38 100644 --- a/src/devices/bus/isa/isa_cards.cpp +++ b/src/devices/bus/isa/isa_cards.cpp @@ -31,13 +31,17 @@ #include "ide.h" #include "xtide.h" #include "side116.h" -#include "aha1542.h" +#include "aha1542b.h" +#include "aha1542c.h" +#include "aha174x.h" #include "wd1002a_wx1.h" #include "wd1007a.h" #include "mcd.h" #include "lbaenhancer.h" #include "cl_sh260.h" #include "bt54x.h" +#include "dcb.h" +#include "ultra12f.h" // sound #include "adlib.h" @@ -153,7 +157,13 @@ void pc_isa16_cards(device_slot_interface &device) // 16-bit device.option_add("ide", ISA16_IDE); device.option_add("ne2000", NE2000); - device.option_add("aha1542", AHA1542); + device.option_add("aha1542a", AHA1542A); + device.option_add("aha1542b", AHA1542B); + device.option_add("aha1542c", AHA1542C); + device.option_add("aha1542cf", AHA1542CF); + device.option_add("aha1542cp", AHA1542CP); + device.option_add("aha1740", AHA1740); // actually an EISA card + device.option_add("aha1742a", AHA1742A); // actually an EISA card device.option_add("gus",ISA16_GUS); device.option_add("sblaster_16", ISA16_SOUND_BLASTER_16); device.option_add("svga_s3", ISA16_SVGA_S3); @@ -174,5 +184,9 @@ void pc_isa16_cards(device_slot_interface &device) device.option_add("wd1007a", WD1007A); device.option_add("ev346", EV346); device.option_add("jc1310", JC1310); + device.option_add("bt542b", BT542B); + device.option_add("bt542bh", BT542BH); device.option_add("bt545s", BT545S); + device.option_add("dcb", NOVELL_DCB); + device.option_add("ultra12f", ULTRA12F); } diff --git a/src/devices/bus/isa/np600.cpp b/src/devices/bus/isa/np600.cpp index 064c1d40191..b38dc008347 100644 --- a/src/devices/bus/isa/np600.cpp +++ b/src/devices/bus/isa/np600.cpp @@ -11,7 +11,6 @@ #include "cpu/i86/i186.h" #include "machine/74259.h" -//#include "machine/i82586.h" DEFINE_DEVICE_TYPE(NP600A3, np600a3_device, "np600a3", "InterLan NP600A-3 Intelligent Protocol Processor") @@ -19,6 +18,7 @@ np600a3_device::np600a3_device(const machine_config &mconfig, const char *tag, d : device_t(mconfig, NP600A3, tag, owner, clock) , device_isa16_card_interface(mconfig, *this) , m_npcpu(*this, "npcpu") + , m_lcc(*this, "lcc") { } @@ -26,6 +26,18 @@ void np600a3_device::device_start() { } +void np600a3_device::lcc_ca_w(u16 data) +{ + m_lcc->ca(0); + m_lcc->ca(1); +} + +WRITE_LINE_MEMBER(np600a3_device::lcc_reset_w) +{ + if (!state) + m_lcc->reset(); +} + u16 np600a3_device::status_r() { return 0; @@ -33,25 +45,35 @@ u16 np600a3_device::status_r() void np600a3_device::mem_map(address_map &map) { - map(0x00000, 0x7ffff).ram(); // GM71256-12 x16 + map(0x00000, 0x7ffff).ram().share("netram"); // GM71256-12 x16 map(0xfc000, 0xfffff).rom().region("npcpu", 0); } void np600a3_device::io_map(address_map &map) { - map(0x0070, 0x007f).w("latch70", FUNC(ls259_device::write_a0)); + map(0x0000, 0x0001).w(FUNC(np600a3_device::lcc_ca_w)); + map(0x0070, 0x007f).w("bitlatch", FUNC(ls259_device::write_a0)); map(0x0080, 0x0081).r(FUNC(np600a3_device::status_r)); } +void np600a3_device::lcc_map(address_map &map) +{ + map(0x000000, 0x07ffff).ram().share("netram"); + map(0xf80000, 0xffffff).ram().share("netram"); +} + void np600a3_device::device_add_mconfig(machine_config &config) { I80186(config, m_npcpu, 16_MHz_XTAL); m_npcpu->set_addrmap(AS_PROGRAM, &np600a3_device::mem_map); m_npcpu->set_addrmap(AS_IO, &np600a3_device::io_map); - LS259(config, "latch70"); // U28 + ls259_device &bitlatch(LS259(config, "bitlatch")); // U28 + bitlatch.q_out_cb<4>().set(FUNC(np600a3_device::lcc_reset_w)); - //I82586(config, "enet", 20_MHz_XTAL); + I82586(config, m_lcc, 20_MHz_XTAL); + m_lcc->set_addrmap(0, &np600a3_device::lcc_map); + m_lcc->out_irq_cb().set(m_npcpu, FUNC(i80186_cpu_device::tmrin1_w)); } ROM_START(np600a3) diff --git a/src/devices/bus/isa/np600.h b/src/devices/bus/isa/np600.h index 7831d804922..e1068b54758 100644 --- a/src/devices/bus/isa/np600.h +++ b/src/devices/bus/isa/np600.h @@ -12,6 +12,7 @@ #pragma once #include "isa.h" +#include "machine/i82586.h" class np600a3_device : public device_t, public device_isa16_card_interface { @@ -26,12 +27,16 @@ protected: virtual const tiny_rom_entry *device_rom_region() const override; private: + void lcc_ca_w(u16 data); + DECLARE_WRITE_LINE_MEMBER(lcc_reset_w); u16 status_r(); void mem_map(address_map &map); void io_map(address_map &map); + void lcc_map(address_map &map); required_device<cpu_device> m_npcpu; + required_device<i82586_device> m_lcc; }; DECLARE_DEVICE_TYPE(NP600A3, np600a3_device) diff --git a/src/devices/bus/isa/ultra12f.cpp b/src/devices/bus/isa/ultra12f.cpp new file mode 100644 index 00000000000..f2f93507548 --- /dev/null +++ b/src/devices/bus/isa/ultra12f.cpp @@ -0,0 +1,64 @@ +// license:BSD-3-Clause +// copyright-holders:AJR +/*************************************************************************** + + UltraStor Ultra 12F ESDI Caching Disk Controller + +***************************************************************************/ + +#include "emu.h" +#include "ultra12f.h" + +DEFINE_DEVICE_TYPE(ULTRA12F, ultra12f_device, "ultra12f", "Ultra 12F ESDI Caching Disk Controller") + +ultra12f_device::ultra12f_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) + : device_t(mconfig, ULTRA12F, tag, owner, clock) + , device_isa16_card_interface(mconfig, *this) + , m_hpc(*this, "hpc") + , m_bios(*this, "bios") +{ +} + +void ultra12f_device::device_start() +{ + // Firmware EPROM has a couple of lines scrambled + u8 *firmware = memregion("firmware")->base(); + for (offs_t b = 0; b < 0x8000; b += 0x100) + { + for (offs_t x = 0; x < 0x10; x++) + { + std::swap(firmware[b | x | 0x10], firmware[b | x | 0x80]); + std::swap(firmware[b | x | 0x30], firmware[b | x | 0xa0]); + std::swap(firmware[b | x | 0x50], firmware[b | x | 0xc0]); + std::swap(firmware[b | x | 0x70], firmware[b | x | 0xe0]); + } + } +} + +void ultra12f_device::hpc_map(address_map &map) +{ + map(0x8000, 0xffff).rom().region("firmware", 0); +} + +void ultra12f_device::device_add_mconfig(machine_config &config) +{ + HPC46003(config, m_hpc, 24_MHz_XTAL); // apparently a HPC46003V30 custom-labeled as "USC010-1-30" + m_hpc->set_addrmap(AS_PROGRAM, &ultra12f_device::hpc_map); +} + +ROM_START(ultra12f) + ROM_REGION(0x4000, "bios", 0) + ROM_SYSTEM_BIOS(0, "v202", "UBIOS 2.02") // "Date : 04/05/90 Version 2.02" + ROMX_LOAD("38001-009.bin", 0x0000, 0x4000, CRC(b96c4839) SHA1(4e601c4ff1deae959c0807479d25de6db4e6cf3e), ROM_BIOS(0)) // 27C128, 150ns EPROM + ROM_SYSTEM_BIOS(1, "v300", "UBIOS 3.00") // "Date : 06/18/91 Version 3.00" + ROMX_LOAD("38001-010.bin", 0x0000, 0x4000, CRC(aa80d74e) SHA1(b507e6ead79e836969b8b6f2fa88ca99d6b354ad), ROM_BIOS(1)) // 27C128-12 + + ROM_REGION(0x8000, "firmware", 0) + ROMX_LOAD("28001-009.bin", 0x0000, 0x8000, CRC(0b6c74a1) SHA1(1a9eb5866f2104e94295d0915fe10c4c1745665b), ROM_BIOS(0)) // 27C256, 120ns EPROM + ROMX_LOAD("28001-012.bin", 0x0000, 0x8000, CRC(62fd2f69) SHA1(48d6e65001a262b3e99d373fa59e0672c5ec4284), ROM_BIOS(1)) // 27C256-12 +ROM_END + +const tiny_rom_entry *ultra12f_device::device_rom_region() const +{ + return ROM_NAME(ultra12f); +} diff --git a/src/devices/bus/isa/ultra12f.h b/src/devices/bus/isa/ultra12f.h new file mode 100644 index 00000000000..6b259aefa6b --- /dev/null +++ b/src/devices/bus/isa/ultra12f.h @@ -0,0 +1,38 @@ +// license:BSD-3-Clause +// copyright-holders:AJR +/*************************************************************************** + + UltraStor Ultra 12F ESDI Caching Disk Controller + +***************************************************************************/ + +#ifndef MAME_BUS_ISA_ULTRA12F_H +#define MAME_BUS_ISA_ULTRA12F_H + +#pragma once + +#include "isa.h" +#include "cpu/hpc/hpc.h" + +class ultra12f_device : public device_t, public device_isa16_card_interface +{ +public: + ultra12f_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); + + static constexpr feature_type unemulated_features() { return feature::DISK; } + +protected: + virtual void device_start() override; + virtual void device_add_mconfig(machine_config &config) override; + virtual const tiny_rom_entry *device_rom_region() const override; + +private: + void hpc_map(address_map &map); + + required_device<hpc_device> m_hpc; + required_region_ptr<u8> m_bios; +}; + +DECLARE_DEVICE_TYPE(ULTRA12F, ultra12f_device) + +#endif // MAME_BUS_ISA_ULTRA12F_H diff --git a/src/devices/bus/mtx/sdx.cpp b/src/devices/bus/mtx/sdx.cpp index 27f7285d6d2..44687e09f08 100644 --- a/src/devices/bus/mtx/sdx.cpp +++ b/src/devices/bus/mtx/sdx.cpp @@ -268,15 +268,15 @@ void mtx_sdxcpm_device::device_reset() READ8_MEMBER(mtx_sdx_device::sdx_status_r) { /* - bit description - 0 Head load: 1 - head load on drive - 1 Double-sided: 1 if drive double-sided - 2 TPI: 0 - 48 TPI drive. 1 - 96 TPI drive - 3 Track stepping rate: 0 - 12ms, 1 - 6ms - 4 No. of drives: 0 - 1 drive, 1 - 2 drives - 5 Ready: 1 - drive ready - 6 Interrupt: 1 - FDC interrupt request - 7 Data request: 1 - FDC data request + bit description + 0 Head load: 1 - head load on drive + 1 Double-sided: 1 if drive double-sided + 2 TPI: 0 - 48 TPI drive. 1 - 96 TPI drive + 3 Track stepping rate: 0 - 12ms, 1 - 6ms + 4 No. of drives: 0 - 1 drive, 1 - 2 drives + 5 Ready: 1 - drive ready + 6 Interrupt: 1 - FDC interrupt request + 7 Data request: 1 - FDC data request */ uint8_t data = 0x00; @@ -297,12 +297,12 @@ READ8_MEMBER(mtx_sdx_device::sdx_status_r) WRITE8_MEMBER(mtx_sdx_device::sdx_control_w) { /* - bit description - 0 Drive select: 0 - drive A, 1 - drive B - 1 Side select: 0 - side 0, 1 - side 1 - 2 Motor on: 1 - turns drive motor on - 3 Motor ready: 1 - drive motor ready - 4 Density: 0 - FM, 1 - MFM + bit description + 0 Drive select: 0 - drive A, 1 - drive B + 1 Side select: 0 - side 0, 1 - side 1 + 2 Motor on: 1 - turns drive motor on + 3 Motor ready: 1 - drive motor ready + 4 Density: 0 - FM, 1 - MFM */ m_control = data; diff --git a/src/devices/bus/nes/konami.cpp b/src/devices/bus/nes/konami.cpp index e979132223d..b936b06b48a 100644 --- a/src/devices/bus/nes/konami.cpp +++ b/src/devices/bus/nes/konami.cpp @@ -81,7 +81,7 @@ nes_konami_vrc6_device::nes_konami_vrc6_device(const machine_config &mconfig, co } nes_konami_vrc7_device::nes_konami_vrc7_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : nes_konami_vrc4_device(mconfig, NES_VRC7, tag, owner, clock), m_ym2413(*this, "ym") + : nes_konami_vrc4_device(mconfig, NES_VRC7, tag, owner, clock), m_vrc7snd(*this, "vrc7snd") { } @@ -560,8 +560,6 @@ void nes_konami_vrc4_device::write_h(offs_t offset, uint8_t data) In MESS: Supported. It also uses konami_irq (there are IRQ issues though: see Akumajou Densetsu intro). - TODO: Add sound capabilities support! - -------------------------------------------------*/ void nes_konami_vrc6_device::write_h(offs_t offset, uint8_t data) @@ -644,7 +642,7 @@ void nes_konami_vrc6_device::device_add_mconfig(machine_config &config) // TODO: this is not how VRC6 clock signaling works! // The board uses the CLK pin in reality, not hardcoded NTSC values! - VRC6(config, m_vrc6snd, XTAL(21'477'272)/12).add_route(ALL_OUTPUTS, "addon", 0.5); + VRC6(config, m_vrc6snd, XTAL(21'477'272)/12).add_route(ALL_OUTPUTS, "addon", 1.0); } /*------------------------------------------------- @@ -681,11 +679,11 @@ void nes_konami_vrc7_device::write_h(offs_t offset, uint8_t data) case 0x1010: case 0x1018: - m_ym2413->register_port_w(data); + m_vrc7snd->register_port_w(data); break; case 0x1030: case 0x1038: - m_ym2413->data_port_w(data); + m_vrc7snd->data_port_w(data); break; case 0x2000: @@ -758,8 +756,6 @@ void nes_konami_vrc7_device::write_h(offs_t offset, uint8_t data) // and has one output pin for audio, multiplexed for all 6 channels; OPLL has two output pins, one for // FM and one for Rhythm, and has no special status pin. -// FIXME: we currently emulate this as a base YM2413! - void nes_konami_vrc7_device::device_add_mconfig(machine_config &config) { // additional sound hardware @@ -767,5 +763,5 @@ void nes_konami_vrc7_device::device_add_mconfig(machine_config &config) // TODO: this is not how VRC7 clock signaling works! // The board uses the CLK pin in reality, not hardcoded NTSC values! - YM2413(config, m_ym2413, XTAL(21'477'272)/12).add_route(ALL_OUTPUTS, "addon", 0.5); + VRC7(config, m_vrc7snd, XTAL(21'477'272)/6).add_route(0, "addon", 1.0).add_route(1, "addon", 0.0); } diff --git a/src/devices/bus/nes/konami.h b/src/devices/bus/nes/konami.h index ed8d0caea3c..86afa1832e1 100644 --- a/src/devices/bus/nes/konami.h +++ b/src/devices/bus/nes/konami.h @@ -157,7 +157,7 @@ protected: virtual void device_add_mconfig(machine_config &config) override; private: - required_device<ym2413_device> m_ym2413; + required_device<vrc7snd_device> m_vrc7snd; }; diff --git a/src/devices/bus/nes/mmc5.cpp b/src/devices/bus/nes/mmc5.cpp index b512f914e8b..1feef95aa67 100644 --- a/src/devices/bus/nes/mmc5.cpp +++ b/src/devices/bus/nes/mmc5.cpp @@ -18,6 +18,7 @@ #include "emu.h" #include "mmc5.h" +#include "speaker.h" #ifdef NES_PCB_DEBUG #define VERBOSE 1 @@ -46,7 +47,7 @@ nes_exrom_device::nes_exrom_device(const machine_config &mconfig, const char *ta , m_prg_mode(0), m_chr_mode(0), m_wram_protect_1(0), m_wram_protect_2(0), m_exram_control(0), m_wram_base(0), m_last_chr(0), m_ex1_chr(0) , m_split_chr(0), m_ex1_bank(0), m_high_chr(0), m_split_scr(0), m_split_rev(0), m_split_ctrl(0), m_split_yst(0), m_split_bank(0), m_vcount(0) , m_ppu(*this, ":ppu") // FIXME: this dependency should not exist - , m_sound(*this, ":maincpu:nesapu") // FIXME: this is a hack, it should have extra channels, not pass to the existing APU!!! + , m_sound(*this, "mmc5snd") // FIXME: this is a hack, it should be separated device, similar not same as NES APU!!! { } @@ -677,3 +678,16 @@ void nes_exrom_device::write_h(offs_t offset, uint8_t data) else if (!m_prgram.empty()) m_prgram[(((m_ram_hi_banks[bank] & 3) * 0x2000) + (offset & 0x1fff)) & (m_prgram.size() - 1)] = data; } + +//------------------------------------------------- +// device_add_mconfig - add device configuration +//------------------------------------------------- + +void nes_exrom_device::device_add_mconfig(machine_config &config) +{ + // additional sound hardware + SPEAKER(config, "addon").front_center(); + + // TODO: temporary; will be separated device + NES_APU(config, m_sound, XTAL(21'477'272)/12).add_route(ALL_OUTPUTS, "addon", 0.50); +} diff --git a/src/devices/bus/nes/mmc5.h b/src/devices/bus/nes/mmc5.h index 093a64471d0..86914fec177 100644 --- a/src/devices/bus/nes/mmc5.h +++ b/src/devices/bus/nes/mmc5.h @@ -36,6 +36,7 @@ public: protected: // device-level overrides + virtual void device_add_mconfig(machine_config &config) override; virtual void device_start() override; void set_mirror(int page, int src); diff --git a/src/devices/bus/nes/namcot.cpp b/src/devices/bus/nes/namcot.cpp index e2898d6b9ba..256e5d65f3b 100644 --- a/src/devices/bus/nes/namcot.cpp +++ b/src/devices/bus/nes/namcot.cpp @@ -16,7 +16,6 @@ * Namcot 340 [mapper 210] TODO: - - add sound feature of Namcot-163 - Quinty is not working (same issue of Mendel Palace on TxROM boards, of course) ***********************************************************************************************************/ @@ -26,6 +25,8 @@ #include "namcot.h" #include "ui/uimain.h" +#include "speaker.h" + #ifdef NES_PCB_DEBUG #define VERBOSE 1 #else @@ -83,7 +84,7 @@ nes_namcot175_device::nes_namcot175_device(const machine_config &mconfig, const } nes_namcot163_device::nes_namcot163_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : nes_namcot340_device(mconfig, NES_NAMCOT163, tag, owner, clock), m_wram_protect(0), m_latch(0), m_chr_bank(0) + : nes_namcot340_device(mconfig, NES_NAMCOT163, tag, owner, clock), m_wram_protect(0), m_latch(0), m_chr_bank(0), m_namco163snd(*this, "n163") { } @@ -550,13 +551,11 @@ void nes_namcot175_device::write_h(offs_t offset, uint8_t data) Compared to Namcot-175 here we have mapper controlled mirroring, NTRAM mapping to VRAM and additional - sound hw inside the chip (currently unemulated) and - some internal RAM. + sound hw inside the chip and some internal RAM. iNES: mapper 19 - In MESS: Supported (with no emulation of the - sound component) + In MESS: Supported -------------------------------------------------*/ @@ -614,7 +613,7 @@ void nes_namcot163_device::write_l(offs_t offset, uint8_t data) switch (offset & 0x1800) { case 0x0800: - LOG_MMC(("Namcot-163 sound reg write, data: %02x\n", data)); + m_namco163snd->data_w(data); break; default: n340_lowrite(offset, data); @@ -630,8 +629,7 @@ uint8_t nes_namcot163_device::read_l(offs_t offset) switch (offset & 0x1800) { case 0x0800: - LOG_MMC(("Namcot-163 sound reg read\n")); - return 0; + return m_namco163snd->data_r(); default: return n340_loread(offset); } @@ -667,7 +665,7 @@ void nes_namcot163_device::write_h(offs_t offset, uint8_t data) set_mirror(page, data); break; case 0x6000: - // TODO: data & 40 (or data & c0) disable sound if set + m_namco163snd->disable_w((data & 0x40) ? ASSERT_LINE : CLEAR_LINE); prg8_89(data & 0x3f); break; case 0x6800: @@ -677,10 +675,23 @@ void nes_namcot163_device::write_h(offs_t offset, uint8_t data) case 0x7800: // the lower 4 bits work *BOTH* as WRAM write protect *AND* as sound address! m_wram_protect = data & 0x0f; - LOG_MMC(("Namcot-163 sound address write, data: %02x\n", data)); + m_namco163snd->addr_w(data); break; default: n340_hiwrite(offset, data); break; } } + +//------------------------------------------------- +// device_add_mconfig - add device configuration +//------------------------------------------------- + +void nes_namcot163_device::device_add_mconfig(machine_config &config) +{ + // additional sound hardware + SPEAKER(config, "addon").front_center(); + + // TODO: Correct clock input / divider? + NAMCO_163(config, m_namco163snd, XTAL(21'477'272)/12).add_route(ALL_OUTPUTS, "addon", 0.5); +} diff --git a/src/devices/bus/nes/namcot.h b/src/devices/bus/nes/namcot.h index bcf72f5bad4..1dcf237fa90 100644 --- a/src/devices/bus/nes/namcot.h +++ b/src/devices/bus/nes/namcot.h @@ -6,6 +6,7 @@ #pragma once #include "nxrom.h" +#include "sound/namco_163.h" // ======================> nes_namcot3433_device @@ -157,11 +158,13 @@ protected: // device-level overrides virtual void device_start() override; + virtual void device_add_mconfig(machine_config &config) override; + private: void set_mirror(uint8_t page, uint8_t data); uint8_t m_wram_protect, m_latch, m_chr_bank; - // TODO: add emulation of the sound part of the chip + required_device<namco_163_sound_device> m_namco163snd; }; diff --git a/src/devices/bus/nubus/bootbug.cpp b/src/devices/bus/nubus/bootbug.cpp index bebfda194fa..24763b64dc2 100644 --- a/src/devices/bus/nubus/bootbug.cpp +++ b/src/devices/bus/nubus/bootbug.cpp @@ -115,10 +115,10 @@ void nubus_bootbug_device::device_reset() WRITE32_MEMBER( nubus_bootbug_device::dev_w ) { - m_uart->ins8250_w(space, offset, data & 0xff); + m_uart->ins8250_w(offset, data & 0xff); } READ32_MEMBER( nubus_bootbug_device::dev_r ) { - return m_uart->ins8250_r(space, offset); + return m_uart->ins8250_r(offset); } diff --git a/src/devices/bus/pc_kbd/pcat101.cpp b/src/devices/bus/pc_kbd/pcat101.cpp index e36a3062492..77dfca9cbb7 100644 --- a/src/devices/bus/pc_kbd/pcat101.cpp +++ b/src/devices/bus/pc_kbd/pcat101.cpp @@ -14,7 +14,8 @@ * 1391401 US English 101-key * * TODO - * - matrix and mcu ports (skeleton only) + * - requires mask rom 6805u3 and timer + * - fix issue receiving commands */ #include "emu.h" @@ -45,173 +46,184 @@ const tiny_rom_entry *ibm_pc_at_101_keyboard_device::device_rom_region() const void ibm_pc_at_101_keyboard_device::device_add_mconfig(machine_config &config) { - M68705U3(config, m_maincpu, 0); + // FIXME: really a 6805U3 (mask ROM, not EPROM) part + M68705U3(config, m_mcu, 4_MHz_XTAL); - //m_maincpu->portb_r_cb().set(FUNC(ibm_pc_at_101_keyboard_device::portb_r)); - //m_maincpu->portb_w_cb().set(FUNC(ibm_pc_at_101_keyboard_device::portb_w)); + // ports A and C control the matrix column select + m_mcu->porta_w().set([this](u8 data) { m_porta = data; }); + m_mcu->portc_w().set([this](u8 data) { m_portc = data; }); + + // port D reads the matrix row output + m_mcu->portd_r().set(FUNC(ibm_pc_at_101_keyboard_device::portd_r)); + + // port B controls clock I/O, data output and LED output + m_mcu->portb_r().set(FUNC(ibm_pc_at_101_keyboard_device::portb_r)); + m_mcu->portb_w().set(FUNC(ibm_pc_at_101_keyboard_device::portb_w)); + + // TODO: timer is held high + //m_mcu->timer_r().set_constant(1); } -// FIXME: copied from ibm_pc_at_84_keyboard - probably completely wrong INPUT_PORTS_START(ibm_pc_at_101_keyboard) - PORT_START("column00") - PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_F9) PORT_CHAR(UCHAR_MAMEKEY(F9)) - PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_F7) PORT_CHAR(UCHAR_MAMEKEY(F7)) - PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_F5) PORT_CHAR(UCHAR_MAMEKEY(F5)) - PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_F3) PORT_CHAR(UCHAR_MAMEKEY(F3)) - PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_F1) PORT_CHAR(UCHAR_MAMEKEY(F1)) - PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_F2) PORT_CHAR(UCHAR_MAMEKEY(F2)) - PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_UNUSED) + PORT_START("col.0") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_UNUSED) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_UNUSED) + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_LCONTROL) PORT_CHAR(UCHAR_MAMEKEY(LCONTROL)) + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_UNUSED) + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_UNUSED) + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_UNUSED) + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_RCONTROL) PORT_CHAR(UCHAR_MAMEKEY(RCONTROL)) PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_UNUSED) - PORT_START("column01") - PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_F10) PORT_CHAR(UCHAR_MAMEKEY(F10)) - PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_F8) PORT_CHAR(UCHAR_MAMEKEY(F8)) - PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_F6) PORT_CHAR(UCHAR_MAMEKEY(F6)) - PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_F4) PORT_CHAR(UCHAR_MAMEKEY(F4)) - PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_TAB) PORT_CHAR(UCHAR_MAMEKEY(TAB)) + PORT_START("col.1") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_UNUSED) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_LSHIFT) PORT_CHAR(UCHAR_MAMEKEY(LSHIFT)) + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_UNUSED) + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_UNUSED) + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_UNUSED) PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_UNUSED) - PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_UNUSED) + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_RSHIFT) PORT_CHAR(UCHAR_MAMEKEY(RSHIFT)) PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_UNUSED) - PORT_START("column02") - PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_LALT) PORT_CHAR(UCHAR_MAMEKEY(LALT)) - PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_LSHIFT) PORT_CHAR(UCHAR_SHIFT_1) - PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_UNUSED) - PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_LCONTROL) PORT_CHAR(UCHAR_SHIFT_2) - PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_Q) PORT_CHAR('q') PORT_CHAR('Q') - PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_1) PORT_CHAR('1') PORT_CHAR('!') - PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_UNUSED) + PORT_START("col.2") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_ESC) PORT_CHAR(UCHAR_MAMEKEY(ESC)) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_TAB) PORT_CHAR(UCHAR_MAMEKEY(TAB)) + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_TILDE) PORT_CHAR('`') PORT_CHAR('~') + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_1) PORT_CHAR('1') PORT_CHAR('!') + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_Q) PORT_CHAR('q') PORT_CHAR('Q') + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_A) PORT_CHAR('a') PORT_CHAR('A') + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_Z) PORT_CHAR('z') PORT_CHAR('Z') PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_UNUSED) - PORT_START("column03") + PORT_START("col.3") PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_UNUSED) - PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_Z) PORT_CHAR('z') PORT_CHAR('Z') - PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_S) PORT_CHAR('s') PORT_CHAR('S') - PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_A) PORT_CHAR('a') PORT_CHAR('A') - PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_W) PORT_CHAR('w') PORT_CHAR('W') - PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_2) PORT_CHAR('2') PORT_CHAR('@') - PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_UNUSED) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_CAPSLOCK) PORT_CHAR(UCHAR_MAMEKEY(CAPSLOCK)) + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_F1) PORT_CHAR(UCHAR_MAMEKEY(F1)) + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_2) PORT_CHAR('2') PORT_CHAR('@') + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_W) PORT_CHAR('w') PORT_CHAR('W') + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_S) PORT_CHAR('s') PORT_CHAR('S') + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_X) PORT_CHAR('x') PORT_CHAR('X') PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_UNUSED) - PORT_START("column04") - PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_C) PORT_CHAR('c') PORT_CHAR('C') - PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_X) PORT_CHAR('x') PORT_CHAR('X') - PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_D) PORT_CHAR('d') PORT_CHAR('D') - PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_E) PORT_CHAR('e') PORT_CHAR('E') - PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_4) PORT_CHAR('4') PORT_CHAR('$') - PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_3) PORT_CHAR('3') PORT_CHAR('#') - PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_UNUSED) + PORT_START("col.4") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_F4) PORT_CHAR(UCHAR_MAMEKEY(F4)) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_F3) PORT_CHAR(UCHAR_MAMEKEY(F3)) + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_F2) PORT_CHAR(UCHAR_MAMEKEY(F2)) + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_3) PORT_CHAR('3') PORT_CHAR('#') + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_E) PORT_CHAR('e') PORT_CHAR('E') + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_C) PORT_CHAR('c') PORT_CHAR('C') + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_D) PORT_CHAR('d') PORT_CHAR('D') PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_UNUSED) - PORT_START("column05") - PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ') - PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_V) PORT_CHAR('v') PORT_CHAR('V') - PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_F) PORT_CHAR('f') PORT_CHAR('F') - PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_T) PORT_CHAR('t') PORT_CHAR('T') - PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_R) PORT_CHAR('r') PORT_CHAR('R') - PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_5) PORT_CHAR('5') PORT_CHAR('%') - PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_UNUSED) - PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_UNUSED) + PORT_START("col.5") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_G) PORT_CHAR('g') PORT_CHAR('G') + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_T) PORT_CHAR('t') PORT_CHAR('T') + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_5) PORT_CHAR('5') PORT_CHAR('%') + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_4) PORT_CHAR('4') PORT_CHAR('$') + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_R) PORT_CHAR('r') PORT_CHAR('R') + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_F) PORT_CHAR('f') PORT_CHAR('F') + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_V) PORT_CHAR('v') PORT_CHAR('V') + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_B) PORT_CHAR('b') PORT_CHAR('B') - PORT_START("column06") - PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_N) PORT_CHAR('n') PORT_CHAR('N') - PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_B) PORT_CHAR('b') PORT_CHAR('B') - PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_H) PORT_CHAR('h') PORT_CHAR('H') - PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_G) PORT_CHAR('g') PORT_CHAR('G') - PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_Y) PORT_CHAR('y') PORT_CHAR('Y') - PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_6) PORT_CHAR('6') PORT_CHAR('^') - PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_UNUSED) + PORT_START("col.6") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_F5) PORT_CHAR(UCHAR_MAMEKEY(F5)) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_BACKSPACE) PORT_CHAR(8) + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_F9) PORT_CHAR(UCHAR_MAMEKEY(F9)) + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_F10) PORT_CHAR(UCHAR_MAMEKEY(F10)) + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_UNUSED) + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_BACKSLASH) PORT_CHAR('\\') PORT_CHAR('|') + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_ENTER) PORT_CHAR(13) + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ') + + PORT_START("col.7") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_H) PORT_CHAR('h') PORT_CHAR('H') + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_Y) PORT_CHAR('y') PORT_CHAR('Y') + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_6) PORT_CHAR('6') PORT_CHAR('^') + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_7) PORT_CHAR('7') PORT_CHAR('&') + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_U) PORT_CHAR('u') PORT_CHAR('U') + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_J) PORT_CHAR('j') PORT_CHAR('J') + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_M) PORT_CHAR('m') PORT_CHAR('M') + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_N) PORT_CHAR('n') PORT_CHAR('N') + + PORT_START("col.8") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_F6) PORT_CHAR(UCHAR_MAMEKEY(F6)) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR(']') PORT_CHAR('}') + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_EQUALS) PORT_CHAR('=') PORT_CHAR('+') + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_8) PORT_CHAR('8') PORT_CHAR('*') + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_I) PORT_CHAR('i') PORT_CHAR('I') + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_K) PORT_CHAR('k') PORT_CHAR('K') + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',') PORT_CHAR('<') PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_UNUSED) - PORT_START("column07") + PORT_START("col.9") PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_UNUSED) - PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_M) PORT_CHAR('m') PORT_CHAR('M') - PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_J) PORT_CHAR('j') PORT_CHAR('J') - PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_U) PORT_CHAR('u') PORT_CHAR('U') - PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_7) PORT_CHAR('7') PORT_CHAR('&') - PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_8) PORT_CHAR('8') PORT_CHAR('*') - PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_UNUSED) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_F7) PORT_CHAR(UCHAR_MAMEKEY(F7)) + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_F8) PORT_CHAR(UCHAR_MAMEKEY(F8)) + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_9) PORT_CHAR('9') PORT_CHAR('(') + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_O) PORT_CHAR('o') PORT_CHAR('O') + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_L) PORT_CHAR('l') PORT_CHAR('L') + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') PORT_CHAR('>') PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_UNUSED) - PORT_START("column08") - PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',') PORT_CHAR('<') - PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_K) PORT_CHAR('k') PORT_CHAR('K') - PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_I) PORT_CHAR('i') PORT_CHAR('I') - PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_O) PORT_CHAR('o') PORT_CHAR('O') - PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_0) PORT_CHAR('0') PORT_CHAR(')') - PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_9) PORT_CHAR('9') PORT_CHAR('(') + PORT_START("col.a") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_QUOTE) PORT_CHAR('\'') PORT_CHAR('"') + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR('[') PORT_CHAR('{') + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_MINUS) PORT_CHAR('-') PORT_CHAR('_') + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_0) PORT_CHAR('0') PORT_CHAR(')') + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_P) PORT_CHAR('p') PORT_CHAR('P') + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_COLON) PORT_CHAR(';') PORT_CHAR(':') PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_UNUSED) - PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_UNUSED) + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_SLASH) PORT_CHAR('/') PORT_CHAR('?') - PORT_START("column09") - PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') PORT_CHAR('>') - PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_SLASH) PORT_CHAR('/') PORT_CHAR('?') - PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_L) PORT_CHAR('l') PORT_CHAR('L') - PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_COLON) PORT_CHAR(';') PORT_CHAR(':') - PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_P) PORT_CHAR('p') PORT_CHAR('P') - PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_MINUS) PORT_CHAR('-') PORT_CHAR('_') - PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_UNUSED) - PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_UNUSED) + PORT_START("col.b") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_UNUSED) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_4_PAD) PORT_CHAR(UCHAR_MAMEKEY(4_PAD)) + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_DEL) PORT_CHAR(UCHAR_MAMEKEY(DEL)) + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_F11) PORT_CHAR(UCHAR_MAMEKEY(F11)) + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_7_PAD) PORT_CHAR(UCHAR_MAMEKEY(7_PAD)) + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_1_PAD) PORT_CHAR(UCHAR_MAMEKEY(1_PAD)) + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_NUMLOCK) PORT_CHAR(UCHAR_MAMEKEY(NUMLOCK)) + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_DOWN) PORT_CHAR(UCHAR_MAMEKEY(DOWN)) - PORT_START("column10") - PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_CUSTOM) - PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_QUOTE) PORT_CHAR('\'') PORT_CHAR('"') - PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_UNUSED) - PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR('[') PORT_CHAR('{') - PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_EQUALS) PORT_CHAR('=') PORT_CHAR('+') - PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_UNUSED) - PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_CAPSLOCK) PORT_CHAR(UCHAR_MAMEKEY(CAPSLOCK)) - PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_RSHIFT) PORT_CHAR(UCHAR_SHIFT_1) + PORT_START("col.c") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_0_PAD) PORT_CHAR(UCHAR_MAMEKEY(0_PAD)) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_5_PAD) PORT_CHAR(UCHAR_MAMEKEY(5_PAD)) + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_INSERT) PORT_CHAR(UCHAR_MAMEKEY(INSERT)) + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_F12) PORT_CHAR(UCHAR_MAMEKEY(F12)) + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_8_PAD) PORT_CHAR(UCHAR_MAMEKEY(8_PAD)) + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_2_PAD) PORT_CHAR(UCHAR_MAMEKEY(2_PAD)) + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_SLASH_PAD) PORT_CHAR(UCHAR_MAMEKEY(SLASH_PAD)) + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_RIGHT) PORT_CHAR(UCHAR_MAMEKEY(RIGHT)) - PORT_START("column11") - PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_UNUSED) - PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR(']') PORT_CHAR('}') - PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_ENTER) PORT_CHAR(13) - PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_TILDE) PORT_CHAR('`') PORT_CHAR('~') - PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_UNUSED) - PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_BACKSLASH) PORT_CHAR('\\') PORT_CHAR('|') - PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_UNUSED) - PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_UNUSED) + PORT_START("col.d") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_DEL_PAD) PORT_CHAR(UCHAR_MAMEKEY(DEL_PAD)) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_6_PAD) PORT_CHAR(UCHAR_MAMEKEY(6_PAD)) + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_PGUP) PORT_CHAR(UCHAR_MAMEKEY(PGUP)) + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_PGDN) PORT_CHAR(UCHAR_MAMEKEY(PGDN)) + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_9_PAD) PORT_CHAR(UCHAR_MAMEKEY(9_PAD)) + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_3_PAD) PORT_CHAR(UCHAR_MAMEKEY(3_PAD)) + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_ASTERISK) PORT_CHAR(UCHAR_MAMEKEY(ASTERISK)) + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_MINUS_PAD) PORT_CHAR(UCHAR_MAMEKEY(MINUS_PAD)) - PORT_START("column12") - PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_UNUSED) + PORT_START("col.e") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_UP) PORT_CHAR(UCHAR_MAMEKEY(UP)) PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_UNUSED) - PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_UNUSED) - PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_UNUSED) - PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_UNUSED) - PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_UNUSED) - PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_BACKSPACE) PORT_CHAR(8) - PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_UNUSED) + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_HOME) PORT_CHAR(UCHAR_MAMEKEY(HOME)) + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_END) PORT_CHAR(UCHAR_MAMEKEY(END)) + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_PLUS_PAD) PORT_CHAR(UCHAR_MAMEKEY(PLUS_PAD)) + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_ENTER_PAD) PORT_CHAR(UCHAR_MAMEKEY(ENTER_PAD)) + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_PAUSE) PORT_CHAR(UCHAR_MAMEKEY(PAUSE)) + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_LEFT) PORT_CHAR(UCHAR_MAMEKEY(LEFT)) - PORT_START("column13") - PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_UNUSED) - PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Keypad 1 End") PORT_CODE(KEYCODE_1_PAD) PORT_CHAR(UCHAR_MAMEKEY(1_PAD)) + PORT_START("col.f") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_LALT) PORT_CHAR(UCHAR_MAMEKEY(LALT)) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_UNUSED) PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_UNUSED) - PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Keypad 4 " UTF8_LEFT) PORT_CODE(KEYCODE_4_PAD) PORT_CHAR(UCHAR_MAMEKEY(4_PAD)) - PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Keypad 7 Home") PORT_CODE(KEYCODE_7_PAD) PORT_CHAR(UCHAR_MAMEKEY(7_PAD)) + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_PRTSCR) PORT_CHAR(UCHAR_MAMEKEY(PRTSCR)) + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_SCRLOCK) PORT_CHAR(UCHAR_MAMEKEY(SCRLOCK)) PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_UNUSED) PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_UNUSED) - PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_UNUSED) - - PORT_START("column14") - PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Keypad 0 Ins") PORT_CODE(KEYCODE_0_PAD) PORT_CHAR(UCHAR_MAMEKEY(0_PAD)) - PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Keypad . Del") PORT_CODE(KEYCODE_DEL_PAD) PORT_CHAR(UCHAR_MAMEKEY(DEL_PAD)) - PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Keypad 2 " UTF8_DOWN) PORT_CODE(KEYCODE_2_PAD) PORT_CHAR(UCHAR_MAMEKEY(2_PAD)) - PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_5_PAD) PORT_CHAR(UCHAR_MAMEKEY(5_PAD)) - PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Keypad 6 " UTF8_RIGHT) PORT_CODE(KEYCODE_6_PAD) PORT_CHAR(UCHAR_MAMEKEY(6_PAD)) - PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Keypad 8 " UTF8_UP) PORT_CODE(KEYCODE_8_PAD) PORT_CHAR(UCHAR_MAMEKEY(8_PAD)) - PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_ESC) PORT_CHAR(UCHAR_MAMEKEY(ESC)) - PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_NUMLOCK) PORT_CHAR(UCHAR_MAMEKEY(NUMLOCK)) - - PORT_START("column15") - PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_UNUSED) - PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_PLUS_PAD) PORT_CHAR(UCHAR_MAMEKEY(PLUS_PAD)) - PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Keypad 3 PgDn") PORT_CODE(KEYCODE_3_PAD) PORT_CHAR(UCHAR_MAMEKEY(3_PAD)) - PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_MINUS_PAD) PORT_CHAR(UCHAR_MAMEKEY(MINUS_PAD)) - PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Keypad * PrtSc") PORT_CODE(KEYCODE_ASTERISK) PORT_CHAR(UCHAR_MAMEKEY(ASTERISK)) - PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Keypad 9 PgUp") PORT_CODE(KEYCODE_9_PAD) PORT_CHAR(UCHAR_MAMEKEY(9_PAD)) - PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Scroll Lock Break") PORT_CODE(KEYCODE_SCRLOCK) PORT_CHAR(UCHAR_MAMEKEY(SCRLOCK)) - PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Sys Req") + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_RALT) PORT_CHAR(UCHAR_MAMEKEY(RALT)) INPUT_PORTS_END ioport_constructor ibm_pc_at_101_keyboard_device::device_input_ports() const @@ -222,8 +234,8 @@ ioport_constructor ibm_pc_at_101_keyboard_device::device_input_ports() const ibm_pc_at_101_keyboard_device::ibm_pc_at_101_keyboard_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : device_t(mconfig, PC_KBD_IBM_PC_AT_101, tag, owner, clock) , device_pc_kbd_interface(mconfig, *this) - , m_maincpu(*this, "mcu") - , m_column(*this, "column%02u", 0U) + , m_mcu(*this, "mcu") + , m_matrix(*this, "col.%x", 0U) , m_leds(*this, "led%u", 0U) { } @@ -237,5 +249,46 @@ void ibm_pc_at_101_keyboard_device::device_start() void ibm_pc_at_101_keyboard_device::device_reset() { - m_maincpu->reset(); + m_mcu->reset(); +} + +void ibm_pc_at_101_keyboard_device::data_write(int state) +{ + m_mcu->set_input_line(M68705_IRQ_LINE, state); +} + +u8 ibm_pc_at_101_keyboard_device::portb_r() +{ + if (clock_signal()) + return m_portb & ~0x02; + else + return m_portb | 0x02; +} + +void ibm_pc_at_101_keyboard_device::portb_w(u8 data) +{ + m_leds[LED_CAPS] = BIT(data, 7) || BIT(data, 6) || BIT(data, 5); + m_leds[LED_NUM] = BIT(data, 4); + m_leds[LED_SCROLL] = BIT(data, 3); + + m_portb = data; + + m_pc_kbdc->data_write_from_kb(!BIT(data, 2)); + m_pc_kbdc->clock_write_from_kb(!BIT(data, 0)); +} + +u8 ibm_pc_at_101_keyboard_device::portd_r() +{ + u8 data = 0xff; + + for (unsigned i = 0; i < 8; i++) + { + if (!BIT(m_portc, i)) + data &= m_matrix[i + 0]->read(); + + if (!BIT(m_porta, i)) + data &= m_matrix[i + 8]->read(); + } + + return data; } diff --git a/src/devices/bus/pc_kbd/pcat101.h b/src/devices/bus/pc_kbd/pcat101.h index e727335aa77..3fe43d5a6c8 100644 --- a/src/devices/bus/pc_kbd/pcat101.h +++ b/src/devices/bus/pc_kbd/pcat101.h @@ -33,14 +33,9 @@ protected: virtual ioport_constructor device_input_ports() const override; // device_pc_kbd_interface overrides - virtual DECLARE_WRITE_LINE_MEMBER(clock_write) override { m_maincpu->set_input_line(M68705_IRQ_LINE, state); }; - virtual DECLARE_WRITE_LINE_MEMBER(data_write) override { }; + virtual void data_write(int state) override; private: - // ports A, C: matrix column - // port D: matrix row - // port B: clock/data and leds - enum { LED_SCROLL = 0, @@ -48,9 +43,17 @@ private: LED_CAPS }; - required_device<m68705_device> m_maincpu; - required_ioport_array<16> m_column; + u8 portb_r(); + void portb_w(u8 data); + u8 portd_r(); + + required_device<m68705_device> m_mcu; + required_ioport_array<16> m_matrix; output_finder<3> m_leds; + + u8 m_porta; + u8 m_portb; + u8 m_portc; }; // device type definition diff --git a/src/devices/bus/pofo/hpc102.cpp b/src/devices/bus/pofo/hpc102.cpp index 42bc8b550fe..00838036bf0 100644 --- a/src/devices/bus/pofo/hpc102.cpp +++ b/src/devices/bus/pofo/hpc102.cpp @@ -110,7 +110,7 @@ uint8_t pofo_hpc102_device::nrdi_r(offs_t offset, uint8_t data, bool iom, bool b if (!(offset & 0x08)) { - data = m_uart->ins8250_r(machine().dummy_space(), offset & 0x07); + data = m_uart->ins8250_r(offset & 0x07); } } @@ -133,7 +133,7 @@ void pofo_hpc102_device::nwri_w(offs_t offset, uint8_t data, bool iom, bool bcom if (!(offset & 0x08)) { - m_uart->ins8250_w(machine().dummy_space(), offset & 0x07, data); + m_uart->ins8250_w(offset & 0x07, data); } } } diff --git a/src/devices/bus/s100/wunderbus.cpp b/src/devices/bus/s100/wunderbus.cpp index c7db4417dcb..64eb9638d74 100644 --- a/src/devices/bus/s100/wunderbus.cpp +++ b/src/devices/bus/s100/wunderbus.cpp @@ -388,15 +388,15 @@ uint8_t s100_wunderbus_device::s100_sinp_r(offs_t offset) break; case 1: - data = m_ace1->ins8250_r(machine().dummy_space(), offset & 0x07); + data = m_ace1->ins8250_r(offset & 0x07); break; case 2: - data = m_ace2->ins8250_r(machine().dummy_space(), offset & 0x07); + data = m_ace2->ins8250_r(offset & 0x07); break; case 3: - data = m_ace3->ins8250_r(machine().dummy_space(), offset & 0x07); + data = m_ace3->ins8250_r(offset & 0x07); break; } } @@ -511,15 +511,15 @@ void s100_wunderbus_device::s100_sout_w(offs_t offset, uint8_t data) break; case 1: - m_ace1->ins8250_w(machine().dummy_space(), offset & 0x07, data); + m_ace1->ins8250_w(offset & 0x07, data); break; case 2: - m_ace2->ins8250_w(machine().dummy_space(), offset & 0x07, data); + m_ace2->ins8250_w(offset & 0x07, data); break; case 3: - m_ace3->ins8250_w(machine().dummy_space(), offset & 0x07, data); + m_ace3->ins8250_w(offset & 0x07, data); break; } } diff --git a/src/devices/bus/spectrum/exp.cpp b/src/devices/bus/spectrum/exp.cpp index b93be6c7162..850b9f88384 100644 --- a/src/devices/bus/spectrum/exp.cpp +++ b/src/devices/bus/spectrum/exp.cpp @@ -167,7 +167,7 @@ void spectrum_expansion_slot_device::mreq_w(offs_t offset, uint8_t data) #include "melodik.h" #include "mface.h" #include "mikroplus.h" -//#include "opus.h" +#include "opus.h" #include "plus2test.h" //#include "plusd.h" #include "protek.h" @@ -190,7 +190,7 @@ void spectrum_expansion_devices(device_slot_interface &device) device.option_add("mface128", SPECTRUM_MFACE128); device.option_add("mikroplus", SPECTRUM_MIKROPLUS); device.option_add("mprint", SPECTRUM_MPRINT); - //device.option_add("opus", SPECTRUM_OPUS); + device.option_add("opus", SPECTRUM_OPUS); //device.option_add("plusd", SPECTRUM_PLUSD); device.option_add("protek", SPECTRUM_PROTEK); device.option_add("specdrum", SPECTRUM_SPECDRUM); @@ -209,6 +209,7 @@ void spec128_expansion_devices(device_slot_interface &device) device.option_add("mface128", SPECTRUM_MFACE128); device.option_add("mikroplus", SPECTRUM_MIKROPLUS); device.option_add("mprint", SPECTRUM_MPRINT); + device.option_add("opus", SPECTRUM_OPUS); device.option_add("plus2test", SPECTRUM_PLUS2TEST); device.option_add("protek", SPECTRUM_PROTEK); device.option_add("specdrum", SPECTRUM_SPECDRUM); diff --git a/src/devices/bus/spectrum/melodik.cpp b/src/devices/bus/spectrum/melodik.cpp index f6001bac35c..f6abc0f98d6 100644 --- a/src/devices/bus/spectrum/melodik.cpp +++ b/src/devices/bus/spectrum/melodik.cpp @@ -115,4 +115,4 @@ void spectrum_melodik_device::iorq_w(offs_t offset, uint8_t data) break; } m_exp->iorq_w(offset, data); -}
\ No newline at end of file +} diff --git a/src/devices/bus/spectrum/opus.cpp b/src/devices/bus/spectrum/opus.cpp new file mode 100644 index 00000000000..be73ef01e92 --- /dev/null +++ b/src/devices/bus/spectrum/opus.cpp @@ -0,0 +1,289 @@ +// license:BSD-3-Clause +// copyright-holders:Nigel Barnes +/********************************************************************** + + Opus Discovery disc system + +**********************************************************************/ + + +#include "emu.h" +#include "opus.h" + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +DEFINE_DEVICE_TYPE(SPECTRUM_OPUS, spectrum_opus_device, "spectrum_opus", "Opus Discovery") + + +//------------------------------------------------- +// INPUT_PORTS( opus ) +//------------------------------------------------- + +static INPUT_PORTS_START( opus ) + PORT_START("JOY") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT) PORT_8WAY + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT) PORT_8WAY + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN) PORT_8WAY + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP) PORT_8WAY + PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_BUTTON1) +INPUT_PORTS_END + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor spectrum_opus_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( opus ); +} + +//------------------------------------------------- +// MACHINE_DRIVER( opus ) +//------------------------------------------------- + +FLOPPY_FORMATS_MEMBER( spectrum_opus_device::floppy_formats ) + FLOPPY_OPD_FORMAT +FLOPPY_FORMATS_END + +static void spectrum_floppies(device_slot_interface &device) +{ + device.option_add("35ssdd", FLOPPY_35_SSDD); + device.option_add("35dd", FLOPPY_35_DD); +} + +ROM_START(opus) + ROM_REGION(0x2000, "rom", 0) + ROM_DEFAULT_BIOS("opus22") + ROM_SYSTEM_BIOS(0, "opus22", "Opus v2.2") + ROMX_LOAD("opus-22.rom", 0x0000, 0x2000, CRC(50f0eae0) SHA1(0eee1c503f71709fce8b7560dadc2d07d15edb80), ROM_BIOS(0)) + ROM_SYSTEM_BIOS(1, "opus21", "Opus v2.1") + ROMX_LOAD("opus-21.rom", 0x0000, 0x2000, CRC(619973f9) SHA1(31999a68901392bba907cf5a15e264b6759f1a29), ROM_BIOS(1)) + ROM_SYSTEM_BIOS(2, "opus222", "Opus v2.22") + ROMX_LOAD("opus-222.rom", 0x0000, 0x2000, CRC(08ce9949) SHA1(71f1c8a8b923f7751d1ff48d30b8e18a15b92591), ROM_BIOS(2)) + ROM_SYSTEM_BIOS(3, "quickdos", "QuickDOS v2.31") // MegaSoft + ROMX_LOAD("quickdos-231.rom", 0x0000, 0x2000, CRC(d042b32a) SHA1(2975f7eb61d44e898cdd6e3196893e95637f17ff), ROM_BIOS(3)) + ROM_SYSTEM_BIOS(4, "excom", "EXCOM v2.28") // Paul Cheffings + ROMX_LOAD("excom-228.rom", 0x0000, 0x2000, CRC(29257418) SHA1(098a812c4707251f647553a2abc1436afa38f43c), ROM_BIOS(4)) +ROM_END + + +//------------------------------------------------- +// device_add_mconfig - add device configuration +//------------------------------------------------- + +void spectrum_opus_device::device_add_mconfig(machine_config &config) +{ + WD1770(config, m_fdc, 16_MHz_XTAL / 2); + m_fdc->drq_wr_callback().set(DEVICE_SELF_OWNER, FUNC(spectrum_expansion_slot_device::nmi_w)); + + FLOPPY_CONNECTOR(config, "fdc:0", spectrum_floppies, "35dd", spectrum_opus_device::floppy_formats).enable_sound(true); + FLOPPY_CONNECTOR(config, "fdc:1", spectrum_floppies, "35dd", spectrum_opus_device::floppy_formats).enable_sound(true); + + /* parallel printer port */ + CENTRONICS(config, m_centronics, centronics_devices, "printer"); + m_centronics->ack_handler().set(m_pia, FUNC(pia6821_device::ca2_w)); + m_centronics->busy_handler().set(FUNC(spectrum_opus_device::busy_w)); + + /* pia */ + PIA6821(config, m_pia, 0); + m_pia->writepa_handler().set(FUNC(spectrum_opus_device::pia_out_a)); + m_pia->writepb_handler().set(FUNC(spectrum_opus_device::pia_out_b)); + m_pia->cb2_handler().set("centronics", FUNC(centronics_device::write_strobe)); + + /* software list */ + SOFTWARE_LIST(config, "flop_list").set_original("spectrum_flop_opus"); + + /* passthru without NMI */ + SPECTRUM_EXPANSION_SLOT(config, m_exp, spectrum_expansion_devices, nullptr); + m_exp->irq_handler().set(DEVICE_SELF_OWNER, FUNC(spectrum_expansion_slot_device::irq_w)); +} + +const tiny_rom_entry *spectrum_opus_device::device_rom_region() const +{ + return ROM_NAME( opus ); +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// spectrum_opus_device - constructor +//------------------------------------------------- + +spectrum_opus_device::spectrum_opus_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : device_t(mconfig, SPECTRUM_OPUS, tag, owner, clock) + , device_spectrum_expansion_interface(mconfig, *this) + , m_joy(*this, "JOY") + , m_rom(*this, "rom") + , m_pia(*this, "pia") + , m_fdc(*this, "fdc") + , m_floppy0(*this, "fdc:0") + , m_floppy1(*this, "fdc:1") + , m_centronics(*this, "centronics") + , m_exp(*this, "exp") +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void spectrum_opus_device::device_start() +{ + memset(m_ram, 0, sizeof(m_ram)); + + save_item(NAME(m_romcs)); + save_item(NAME(m_ram)); + save_item(NAME(m_last_pc)); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void spectrum_opus_device::device_reset() +{ + m_romcs = 0; + m_last_pc = 0x0000; +} + + +//************************************************************************** +// IMPLEMENTATION +//************************************************************************** + +READ_LINE_MEMBER(spectrum_opus_device::romcs) +{ + return m_romcs | m_exp->romcs(); +} + +void spectrum_opus_device::opcode_fetch(offs_t offset) +{ + m_exp->opcode_fetch(offset); + + if (!machine().side_effects_disabled()) + { + switch (m_last_pc) + { + case 0x0008: case 0x0048: case 0x1708: + m_romcs = 1; + break; + case 0x1748: + m_romcs = 0; + break; + } + } + m_last_pc = offset; +} + +uint8_t spectrum_opus_device::iorq_r(offs_t offset) +{ + uint8_t data = m_exp->iorq_r(offset); + + // PIA bit 7 is enable joystick and selected on A5 only + if (!BIT(m_pia->a_output(), 7) && (~offset & 0x20)) + { + data &= m_joy->read() & 0x1f; + } + return data; +} + +void spectrum_opus_device::iorq_w(offs_t offset, uint8_t data) +{ + m_exp->iorq_w(offset, data); +} + +uint8_t spectrum_opus_device::mreq_r(offs_t offset) +{ + uint8_t data = 0xff; + + if (m_romcs) + { + switch (offset & 0xf800) + { + case 0x0000: case 0x0800: case 0x1000: case 0x1800: + data = m_rom->base()[offset & 0x1fff]; + break; + case 0x2000: + data = m_ram[offset & 0x7ff]; + break; + case 0x2800: + data = m_fdc->read(offset & 0x03); + break; + case 0x3000: + data = m_pia->read(offset & 0x03); + break; + case 0x3800: // Extra 2K described in QuickDOS manual - not used + data = m_ram[offset & 0xfff]; + break; + } + } + + if (m_exp->romcs()) + data &= m_exp->mreq_r(offset); + + return data; +} + +void spectrum_opus_device::mreq_w(offs_t offset, uint8_t data) +{ + if (m_romcs) + { + switch (offset & 0xf800) + { + case 0x2000: + m_ram[offset & 0x7ff] = data; + break; + case 0x2800: + m_fdc->write(offset & 0x03, data); + break; + case 0x3000: + m_pia->write(offset & 0x03, data); + break; + case 0x3800: // Extra 2K described in QuickDOS manual - not used + m_ram[offset & 0xfff] = data; + break; + } + } + + if (m_exp->romcs()) + m_exp->mreq_w(offset, data); +} + +WRITE8_MEMBER(spectrum_opus_device::pia_out_a) +{ + floppy_image_device *floppy = nullptr; + + // bit 0, 1: drive select + if (!BIT(data, 0)) floppy = m_floppy1->get_device(); + if (!BIT(data, 1)) floppy = m_floppy0->get_device(); + m_fdc->set_floppy(floppy); + + // bit 4: side select + if (floppy) + floppy->ss_w(BIT(data, 4)); + + // bit 5: density + m_fdc->dden_w(BIT(data, 5)); +} + +WRITE8_MEMBER(spectrum_opus_device::pia_out_b) +{ + m_centronics->write_data1(BIT(data, 1)); + m_centronics->write_data2(BIT(data, 2)); + m_centronics->write_data3(BIT(data, 3)); + m_centronics->write_data4(BIT(data, 4)); + m_centronics->write_data5(BIT(data, 5)); + m_centronics->write_data6(BIT(data, 6)); + m_centronics->write_data7(BIT(data, 7)); +} + +WRITE_LINE_MEMBER(spectrum_opus_device::busy_w) +{ + m_pia->set_a_input(state << 6, 0xbf); +} diff --git a/src/devices/bus/spectrum/opus.h b/src/devices/bus/spectrum/opus.h new file mode 100644 index 00000000000..8d72d8be94b --- /dev/null +++ b/src/devices/bus/spectrum/opus.h @@ -0,0 +1,75 @@ +// license:BSD-3-Clause +// copyright-holders:Nigel Barnes +/********************************************************************** + + Opus Discovery disc system + +**********************************************************************/ + +#ifndef MAME_BUS_SPECTRUM_OPUS_H +#define MAME_BUS_SPECTRUM_OPUS_H + +#include "exp.h" +#include "softlist.h" +#include "imagedev/floppy.h" +#include "machine/wd_fdc.h" +#include "machine/6821pia.h" +#include "bus/centronics/ctronics.h" +#include "formats/opd_dsk.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class spectrum_opus_device: + public device_t, + public device_spectrum_expansion_interface + +{ +public: + // construction/destruction + spectrum_opus_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + DECLARE_FLOPPY_FORMATS(floppy_formats); + +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; + virtual ioport_constructor device_input_ports() const override; + virtual const tiny_rom_entry *device_rom_region() const override; + + virtual void opcode_fetch(offs_t offset) override; + virtual uint8_t mreq_r(offs_t offset) override; + virtual void mreq_w(offs_t offset, uint8_t data) override; + virtual uint8_t iorq_r(offs_t offset) override; + virtual void iorq_w(offs_t offset, uint8_t data) override; + virtual DECLARE_READ_LINE_MEMBER(romcs) override; + +private: + DECLARE_WRITE8_MEMBER(pia_out_a); + DECLARE_WRITE8_MEMBER(pia_out_b); + DECLARE_WRITE_LINE_MEMBER(busy_w); + + required_ioport m_joy; + required_memory_region m_rom; + required_device<pia6821_device> m_pia; + required_device<wd_fdc_device_base> m_fdc; + required_device<floppy_connector> m_floppy0; + required_device<floppy_connector> m_floppy1; + required_device<centronics_device> m_centronics; + required_device<spectrum_expansion_slot_device> m_exp; + + int m_romcs; + uint8_t m_ram[4 * 1024]; + offs_t m_last_pc; +}; + + +// device type definition +DECLARE_DEVICE_TYPE(SPECTRUM_OPUS, spectrum_opus_device) + +#endif // MAME_BUS_SPECTRUM_OPUS_H diff --git a/src/devices/bus/svi3x8/expander/sv603.cpp b/src/devices/bus/svi3x8/expander/sv603.cpp index ce4a9f11bcf..fc8e8c86d96 100644 --- a/src/devices/bus/svi3x8/expander/sv603.cpp +++ b/src/devices/bus/svi3x8/expander/sv603.cpp @@ -36,10 +36,10 @@ const tiny_rom_entry *sv603_device::device_rom_region() const // device_add_mconfig - add device configuration //------------------------------------------------- -MACHINE_CONFIG_START(sv603_device::device_add_mconfig) +void sv603_device::device_add_mconfig(machine_config &config) +{ SPEAKER(config, "mono").front_center(); - MCFG_DEVICE_ADD("snd", SN76489A, XTAL(10'738'635) / 3) - MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.00) + SN76489A(config, m_snd, XTAL(10'738'635) / 3).add_route(ALL_OUTPUTS, "mono", 1.00); // controller ports COLECOVISION_CONTROL_PORT(config, m_joy[0], colecovision_control_port_devices, "hand"); @@ -50,7 +50,7 @@ MACHINE_CONFIG_START(sv603_device::device_add_mconfig) // cartridge slot COLECOVISION_CARTRIDGE_SLOT(config, m_cart, colecovision_cartridges, nullptr); SOFTWARE_LIST(config, "cart_list").set_original("coleco"); -MACHINE_CONFIG_END +} //************************************************************************** diff --git a/src/devices/bus/svi3x8/slot/sv805.cpp b/src/devices/bus/svi3x8/slot/sv805.cpp index cdcaee6f167..a5ceadf3577 100644 --- a/src/devices/bus/svi3x8/slot/sv805.cpp +++ b/src/devices/bus/svi3x8/slot/sv805.cpp @@ -77,7 +77,7 @@ uint8_t sv805_device::iorq_r(offs_t offset) case 0x2d: case 0x2e: case 0x2f: - return m_uart->ins8250_r(machine().dummy_space(), offset & 0x07); + return m_uart->ins8250_r(offset & 0x07); } return 0xff; @@ -95,7 +95,7 @@ void sv805_device::iorq_w(offs_t offset, uint8_t data) case 0x2d: case 0x2e: case 0x2f: - m_uart->ins8250_w(machine().dummy_space(), offset & 0x07, data); + m_uart->ins8250_w(offset & 0x07, data); } } diff --git a/src/devices/bus/vme/vme.cpp b/src/devices/bus/vme/vme.cpp index 757874abae2..61ca35c2199 100644 --- a/src/devices/bus/vme/vme.cpp +++ b/src/devices/bus/vme/vme.cpp @@ -359,6 +359,36 @@ void vme_device::install_device(vme_amod_t amod, offs_t start, offs_t end, read8 } } +void vme_device::install_device(vme_amod_t amod, offs_t start, offs_t end, read8smo_delegate rhandler, write8smo_delegate whandler, uint32_t mask) +{ + LOG("%s %s AM%d D%02x\n", tag(), FUNCNAME, amod, m_prgwidth); + + LOG(" - width:%d\n", m_prgwidth); + + // TODO: support address modifiers and buscycles other than single access cycles + switch(amod) + { + case A16_SC: break; + case A24_SC: break; + case A32_SC: break; + default: fatalerror("VME D8: Non supported Address modifier: AM%02x\n", amod); + } + + switch(m_prgwidth) + { + case 16: + m_prgspace->install_readwrite_handler(start, end, rhandler, whandler, (uint16_t)(mask & 0x0000ffff)); + break; + case 24: + m_prgspace->install_readwrite_handler(start, end, rhandler, whandler, (uint32_t)(mask & 0x00ffffff)); + break; + case 32: + m_prgspace->install_readwrite_handler(start, end, rhandler, whandler, mask); + break; + default: fatalerror("VME D8: Bus width %d not supported\n", m_prgwidth); + } +} + // D16 bit devices in A16, A24 and A32 void vme_device::install_device(vme_amod_t amod, offs_t start, offs_t end, read16_delegate rhandler, write16_delegate whandler, uint32_t mask) { diff --git a/src/devices/bus/vme/vme.h b/src/devices/bus/vme/vme.h index 755330f7689..2849b07f8b3 100644 --- a/src/devices/bus/vme/vme.h +++ b/src/devices/bus/vme/vme.h @@ -183,6 +183,7 @@ public: }; void install_device(vme_amod_t amod, offs_t start, offs_t end, read8_delegate rhandler, write8_delegate whandler, uint32_t mask); void install_device(vme_amod_t amod, offs_t start, offs_t end, read8sm_delegate rhandler, write8sm_delegate whandler, uint32_t mask); + void install_device(vme_amod_t amod, offs_t start, offs_t end, read8smo_delegate rhandler, write8smo_delegate whandler, uint32_t mask); // void install_device(vme_amod_t amod, offs_t start, offs_t end, read8_delegate rhandler, write8_delegate whandler); void install_device(vme_amod_t amod, offs_t start, offs_t end, read16_delegate rhandler, write16_delegate whandler, uint32_t mask); void install_device(vme_amod_t amod, offs_t start, offs_t end, read32_delegate rhandler, write32_delegate whandler, uint32_t mask); diff --git a/src/devices/bus/vme/vme_mzr8300.cpp b/src/devices/bus/vme/vme_mzr8300.cpp index 362beef2546..133c17e9f49 100644 --- a/src/devices/bus/vme/vme_mzr8300.cpp +++ b/src/devices/bus/vme/vme_mzr8300.cpp @@ -175,17 +175,17 @@ void vme_mzr8300_card_device::device_start() // m_vme->static_set_custom_spaces(*this); m_vme->install_device(vme_device::A16_SC, base + 0, base + 1, // Channel B - Data - read8_delegate(FUNC(z80sio_device::db_r), subdevice<z80sio_device>("sio0")), - write8_delegate(FUNC(z80sio_device::db_w), subdevice<z80sio_device>("sio0")), 0x00ff); + read8smo_delegate(FUNC(z80sio_device::db_r), subdevice<z80sio_device>("sio0")), + write8smo_delegate(FUNC(z80sio_device::db_w), subdevice<z80sio_device>("sio0")), 0x00ff); m_vme->install_device(vme_device::A16_SC, base + 2, base + 3, // Channel B - Control - read8_delegate(FUNC(z80sio_device::cb_r), subdevice<z80sio_device>("sio0")), - write8_delegate(FUNC(z80sio_device::cb_w), subdevice<z80sio_device>("sio0")), 0x00ff); + read8smo_delegate(FUNC(z80sio_device::cb_r), subdevice<z80sio_device>("sio0")), + write8smo_delegate(FUNC(z80sio_device::cb_w), subdevice<z80sio_device>("sio0")), 0x00ff); m_vme->install_device(vme_device::A16_SC, base + 4, base + 5, // Channel A - Data - read8_delegate(FUNC(z80sio_device::da_r), subdevice<z80sio_device>("sio0")), - write8_delegate(FUNC(z80sio_device::da_w), subdevice<z80sio_device>("sio0")), 0x00ff); + read8smo_delegate(FUNC(z80sio_device::da_r), subdevice<z80sio_device>("sio0")), + write8smo_delegate(FUNC(z80sio_device::da_w), subdevice<z80sio_device>("sio0")), 0x00ff); m_vme->install_device(vme_device::A16_SC, base + 6, base + 7, // Channel A - Control - read8_delegate(FUNC(z80sio_device::ca_r), subdevice<z80sio_device>("sio0")), - write8_delegate(FUNC(z80sio_device::ca_w), subdevice<z80sio_device>("sio0")), 0x00ff); + read8smo_delegate(FUNC(z80sio_device::ca_r), subdevice<z80sio_device>("sio0")), + write8smo_delegate(FUNC(z80sio_device::ca_w), subdevice<z80sio_device>("sio0")), 0x00ff); m_vme->install_device(vme_device::A16_SC, base + 0x10, base + 0x13, // Am9513 read8sm_delegate(FUNC(am9513_device::read8), subdevice<am9513_device>("stc")), write8sm_delegate(FUNC(am9513_device::write8), subdevice<am9513_device>("stc")), 0x00ff); diff --git a/src/devices/bus/wangpc/mcc.cpp b/src/devices/bus/wangpc/mcc.cpp index 5b029ed38d2..a3419f7c373 100644 --- a/src/devices/bus/wangpc/mcc.cpp +++ b/src/devices/bus/wangpc/mcc.cpp @@ -143,7 +143,7 @@ uint16_t wangpc_mcc_device::wangpcbus_iorc_r(offs_t offset, uint16_t mem_mask) case 0x06/2: if (ACCESSING_BITS_0_7) { - data = 0xff00 | m_sio->cd_ba_r(machine().dummy_space(), offset >> 1); + data = 0xff00 | m_sio->cd_ba_r(offset >> 1); } break; @@ -153,7 +153,7 @@ uint16_t wangpc_mcc_device::wangpcbus_iorc_r(offs_t offset, uint16_t mem_mask) case 0x0e/2: if (ACCESSING_BITS_0_7) { - data = 0xff00 | m_dart->cd_ba_r(machine().dummy_space(), offset >> 1); + data = 0xff00 | m_dart->cd_ba_r(offset >> 1); } break; @@ -208,14 +208,14 @@ void wangpc_mcc_device::wangpcbus_aiowc_w(offs_t offset, uint16_t mem_mask, uint case 0x02/2: case 0x04/2: case 0x06/2: - m_sio->cd_ba_w(machine().dummy_space(), offset >> 1, data & 0xff); + m_sio->cd_ba_w(offset >> 1, data & 0xff); break; case 0x08/2: case 0x0a/2: case 0x0c/2: case 0x0e/2: - m_dart->cd_ba_w(machine().dummy_space(), offset >> 1, data & 0xff); + m_dart->cd_ba_w(offset >> 1, data & 0xff); break; case 0x12/2: diff --git a/src/devices/bus/wangpc/wdc.cpp b/src/devices/bus/wangpc/wdc.cpp index 2ad74d8c8fd..8b816a50ece 100644 --- a/src/devices/bus/wangpc/wdc.cpp +++ b/src/devices/bus/wangpc/wdc.cpp @@ -325,11 +325,11 @@ WRITE8_MEMBER( wangpc_wdc_device::status_w ) } -READ8_MEMBER( wangpc_wdc_device::ctc_ch0_r ) { return m_ctc->read(machine().dummy_space(), 0); } -WRITE8_MEMBER( wangpc_wdc_device::ctc_ch0_w ) { m_ctc->write(machine().dummy_space(), 0, data); } -READ8_MEMBER( wangpc_wdc_device::ctc_ch1_r ) { return m_ctc->read(machine().dummy_space(), 1); } -WRITE8_MEMBER( wangpc_wdc_device::ctc_ch1_w ) { m_ctc->write(machine().dummy_space(), 1, data); } -READ8_MEMBER( wangpc_wdc_device::ctc_ch2_r ) { return m_ctc->read(machine().dummy_space(), 2); } -WRITE8_MEMBER( wangpc_wdc_device::ctc_ch2_w ) { m_ctc->write(machine().dummy_space(), 2, data); } -READ8_MEMBER( wangpc_wdc_device::ctc_ch3_r ) { return m_ctc->read(machine().dummy_space(), 3); } -WRITE8_MEMBER( wangpc_wdc_device::ctc_ch3_w ) { m_ctc->write(machine().dummy_space(), 3, data); } +READ8_MEMBER( wangpc_wdc_device::ctc_ch0_r ) { return m_ctc->read(0); } +WRITE8_MEMBER( wangpc_wdc_device::ctc_ch0_w ) { m_ctc->write(0, data); } +READ8_MEMBER( wangpc_wdc_device::ctc_ch1_r ) { return m_ctc->read(1); } +WRITE8_MEMBER( wangpc_wdc_device::ctc_ch1_w ) { m_ctc->write(1, data); } +READ8_MEMBER( wangpc_wdc_device::ctc_ch2_r ) { return m_ctc->read(2); } +WRITE8_MEMBER( wangpc_wdc_device::ctc_ch2_w ) { m_ctc->write(2, data); } +READ8_MEMBER( wangpc_wdc_device::ctc_ch3_r ) { return m_ctc->read(3); } +WRITE8_MEMBER( wangpc_wdc_device::ctc_ch3_w ) { m_ctc->write(3, data); } diff --git a/src/devices/cpu/h8/h83003.cpp b/src/devices/cpu/h8/h83003.cpp index 4e3e59c15cf..7b7b468d7b5 100644 --- a/src/devices/cpu/h8/h83003.cpp +++ b/src/devices/cpu/h8/h83003.cpp @@ -136,7 +136,9 @@ void h83003_device::map(address_map &map) map(0xffffd2, 0xffffd2).rw("port9", FUNC(h8_port_device::port_r), FUNC(h8_port_device::dr_w)); map(0xffffd3, 0xffffd3).rw("porta", FUNC(h8_port_device::port_r), FUNC(h8_port_device::dr_w)); map(0xffffd4, 0xffffd4).w("portb", FUNC(h8_port_device::ddr_w)); + map(0xffffd5, 0xffffd5).w("portc", FUNC(h8_port_device::ddr_w)); map(0xffffd6, 0xffffd6).rw("portb", FUNC(h8_port_device::port_r), FUNC(h8_port_device::dr_w)); + map(0xffffd7, 0xffffd7).rw("portc", FUNC(h8_port_device::port_r), FUNC(h8_port_device::dr_w)); map(0xffffda, 0xffffda).rw("port4", FUNC(h8_port_device::pcr_r), FUNC(h8_port_device::pcr_w)); map(0xffffe0, 0xffffe7).r("adc", FUNC(h8_adc_device::addr8_r)); @@ -167,6 +169,7 @@ void h83003_device::device_add_mconfig(machine_config &config) H8_PORT(config, "port9", h8_device::PORT_9, 0x00, 0xc0); H8_PORT(config, "porta", h8_device::PORT_A, 0x00, 0x00); H8_PORT(config, "portb", h8_device::PORT_B, 0x00, 0x00); + H8_PORT(config, "portc", h8_device::PORT_C, 0x00, 0x00); H8_TIMER16(config, "timer16", 5, 0xe0); H8H_TIMER16_CHANNEL(config, "timer16:0", 2, 2, "intc", 24); H8H_TIMER16_CHANNEL(config, "timer16:1", 2, 2, "intc", 28); diff --git a/src/devices/cpu/i386/cache.h b/src/devices/cpu/i386/cache.h index 548a1fb9f85..a04f2cacf2e 100644 --- a/src/devices/cpu/i386/cache.h +++ b/src/devices/cpu/i386/cache.h @@ -222,37 +222,37 @@ u8 memory[memorysize]; void readline(u8 *data, u32 address) { - for (int n = 0; n < 64; n++) - data[n] = memory[address + n]; + for (int n = 0; n < 64; n++) + data[n] = memory[address + n]; } void writeline(u8 *data, u32 address) { - for (int n = 0; n < 64; n++) - memory[address + n] = data[n]; + for (int n = 0; n < 64; n++) + memory[address + n] = data[n]; } void cache_tester() { - cpucache<18, 8, 6, 2> cache; - bool r; - u8 *data; - int address; - u8 value; + cpucache<18, 8, 6, 2> cache; + bool r; + u8 *data; + int address; + u8 value; - for (int n = 0; n < memorysize; n++) - memory[n] = 0xaa ^ n; - address = std::rand() & (memorysize - 1); - r = cache.search(address, &data); - if (r == false) - { - r = cache.allocate(address, &data); - if (r == true) - writeline(data, cache.base(address)); - readline(data, cache.base(address)); - } - value = data[address & 63]; - if (value != memory[address]) - printf("Error reading address %d\n\r", address); + for (int n = 0; n < memorysize; n++) + memory[n] = 0xaa ^ n; + address = std::rand() & (memorysize - 1); + r = cache.search(address, &data); + if (r == false) + { + r = cache.allocate(address, &data); + if (r == true) + writeline(data, cache.base(address)); + readline(data, cache.base(address)); + } + value = data[address & 63]; + if (value != memory[address]) + printf("Error reading address %d\n\r", address); } */ diff --git a/src/devices/cpu/i386/i386.h b/src/devices/cpu/i386/i386.h index d8422780710..90aab9f0667 100644 --- a/src/devices/cpu/i386/i386.h +++ b/src/devices/cpu/i386/i386.h @@ -1637,7 +1637,7 @@ protected: virtual void device_start() override; virtual void device_reset() override; - virtual u8 mem_pr8(offs_t address) override { return opcode_read_cache<u8, NATIVE_ENDIAN_VALUE_LE_BE(0, 3)>(address); } + virtual u8 mem_pr8(offs_t address) override { return opcode_read_cache<u8, NATIVE_ENDIAN_VALUE_LE_BE(0, 3)>(address); } virtual u16 mem_pr16(offs_t address) override { return opcode_read_cache<u16, NATIVE_ENDIAN_VALUE_LE_BE(0, 2)>(address); } virtual u32 mem_pr32(offs_t address) override { return opcode_read_cache<u32, 0>(address); } virtual u8 mem_prd8(offs_t address) override { return program_read_cache<u8, NATIVE_ENDIAN_VALUE_LE_BE(0, 3)>(address); } diff --git a/src/devices/cpu/m68000/m68000.h b/src/devices/cpu/m68000/m68000.h index d6afd83d534..0ee41f348b5 100644 --- a/src/devices/cpu/m68000/m68000.h +++ b/src/devices/cpu/m68000/m68000.h @@ -148,6 +148,7 @@ public: void set_tas_write_callback(write8_delegate callback); uint16_t get_fc(); void set_hmmu_enable(int enable); + int get_pmmu_enable() {return m_pmmu_enabled;}; void set_fpu_enable(int enable); void set_buserror_details(uint32_t fault_addr, uint8_t rw, uint8_t fc); @@ -377,21 +378,6 @@ protected: const device_type type, uint32_t prg_data_width, uint32_t prg_address_bits, address_map_constructor internal_map); }; -class m68301_device : public m68000_base_device -{ -public: - // construction/destruction - m68301_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); - - virtual std::unique_ptr<util::disasm_interface> create_disassembler() override; - - virtual uint32_t execute_min_cycles() const override { return 4; }; - virtual uint32_t execute_max_cycles() const override { return 158; }; - - // device-level overrides - virtual void device_start() override; -}; - @@ -649,7 +635,6 @@ public: DECLARE_DEVICE_TYPE(M68000, m68000_device) -DECLARE_DEVICE_TYPE(M68301, m68301_device) DECLARE_DEVICE_TYPE(M68008, m68008_device) DECLARE_DEVICE_TYPE(M68008PLCC, m68008plcc_device) DECLARE_DEVICE_TYPE(M68010, m68010_device) diff --git a/src/devices/cpu/m68000/m68kcpu.cpp b/src/devices/cpu/m68000/m68kcpu.cpp index e875b377af3..851c27163ea 100644 --- a/src/devices/cpu/m68000/m68kcpu.cpp +++ b/src/devices/cpu/m68000/m68kcpu.cpp @@ -2019,11 +2019,6 @@ std::unique_ptr<util::disasm_interface> m68000_device::create_disassembler() return std::make_unique<m68k_disassembler>(m68k_disassembler::TYPE_68000); } -std::unique_ptr<util::disasm_interface> m68301_device::create_disassembler() -{ - return std::make_unique<m68k_disassembler>(m68k_disassembler::TYPE_68000); -} - std::unique_ptr<util::disasm_interface> m68008_device::create_disassembler() { return std::make_unique<m68k_disassembler>(m68k_disassembler::TYPE_68008); @@ -2362,7 +2357,6 @@ device_memory_interface::space_config_vector m68000_base_device::memory_space_co DEFINE_DEVICE_TYPE(M68000, m68000_device, "m68000", "Motorola MC68000") -DEFINE_DEVICE_TYPE(M68301, m68301_device, "m68301", "Motorola MC68301") DEFINE_DEVICE_TYPE(M68008, m68008_device, "m68008", "Motorola MC68008") DEFINE_DEVICE_TYPE(M68008PLCC, m68008plcc_device, "m68008plcc", "Motorola MC68008PLCC") DEFINE_DEVICE_TYPE(M68010, m68010_device, "m68010", "Motorola MC68010") @@ -2405,21 +2399,6 @@ m68000_device::m68000_device(const machine_config &mconfig, const char *tag, dev -m68301_device::m68301_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : m68000_base_device(mconfig, tag, owner, clock, M68301, 16,24) -{ -} - - -void m68301_device::device_start() -{ - init_cpu_m68000(); -} - - - - - /* m68008_device */ diff --git a/src/devices/cpu/m68000/m68kmmu.h b/src/devices/cpu/m68000/m68kmmu.h index 114d89ff5c1..99481039b0f 100644 --- a/src/devices/cpu/m68000/m68kmmu.h +++ b/src/devices/cpu/m68000/m68kmmu.h @@ -33,7 +33,7 @@ static constexpr uint32_t M68K_MMU_DF_WP = 0x00000004; static constexpr uint32_t M68K_MMU_DF_USED = 0x00000008; static constexpr uint32_t M68K_MMU_DF_MODIFIED = 0x00000010; static constexpr uint32_t M68K_MMU_DF_CI = 0x00000040; -static constexpr uint32_t M68K_MMU_DF_SUPERVISOR = 0000000100; +static constexpr uint32_t M68K_MMU_DF_SUPERVISOR = 0x00000100; static constexpr uint32_t M68K_MMU_DF_ADDR_MASK = 0xfffffff0; static constexpr uint32_t M68K_MMU_DF_IND_ADDR_MASK = 0xfffffffc; diff --git a/src/devices/cpu/mcs51/mcs51.cpp b/src/devices/cpu/mcs51/mcs51.cpp index 60d39a25139..c307c19a611 100644 --- a/src/devices/cpu/mcs51/mcs51.cpp +++ b/src/devices/cpu/mcs51/mcs51.cpp @@ -874,6 +874,8 @@ uint8_t mcs51_cpu_device::bit_address_r(uint8_t offset) int distance; /* distance between bit addressable words */ /* 1 for normal bits, 8 for sfr bit addresses */ + m_last_bit = offset; + //User defined bit addresses 0x20-0x2f (values are 0x0-0x7f) if (offset < 0x80) { distance = 1; @@ -1358,6 +1360,8 @@ void mcs51_cpu_device::execute_op(uint8_t op) m_recalc_parity = 0; } + m_last_op = op; + switch( op ) { case 0x00: nop(op); break; //NOP @@ -1777,6 +1781,10 @@ void mcs51_cpu_device::check_irqs() return; } + // Hack to work around polling latency issue with JB INT0/INT1 + if (m_last_op == 0x20 && ((int_vec == V_IE0 && m_last_bit == 0xb2) || (int_vec == V_IE1 && m_last_bit == 0xb3))) + PC = PPC + 3; + //Save current pc to stack, set pc to new interrupt vector push_pc(); PC = int_vec; @@ -2126,6 +2134,8 @@ void mcs51_cpu_device::device_start() save_item(NAME(m_ppc)); save_item(NAME(m_pc)); + save_item(NAME(m_last_op)); + save_item(NAME(m_last_bit)); save_item(NAME(m_rwm) ); save_item(NAME(m_cur_irq_prio) ); save_item(NAME(m_last_line_state) ); @@ -2213,6 +2223,8 @@ void mcs51_cpu_device::device_reset() /* Flag as NO IRQ in Progress */ m_irq_active = 0; m_cur_irq_prio = -1; + m_last_op = 0; + m_last_bit = 0; /* these are all defined reset states */ PC = 0; diff --git a/src/devices/cpu/mcs51/mcs51.h b/src/devices/cpu/mcs51/mcs51.h index e0d4028f493..bd7b6d7b085 100644 --- a/src/devices/cpu/mcs51/mcs51.h +++ b/src/devices/cpu/mcs51/mcs51.h @@ -122,6 +122,10 @@ protected: uint8_t m_forced_inputs[4]; /* allow read even if configured as output */ + // JB-related hacks + uint8_t m_last_op; + uint8_t m_last_bit; + int m_icount; struct mcs51_uart diff --git a/src/devices/cpu/ns32000/ns32000.cpp b/src/devices/cpu/ns32000/ns32000.cpp new file mode 100644 index 00000000000..6bf23e28289 --- /dev/null +++ b/src/devices/cpu/ns32000/ns32000.cpp @@ -0,0 +1,160 @@ +// license:BSD-3-Clause +// copyright-holders:Nigel Barnes +/***************************************************************************** +* +* ns32000.cpp +* +* NS32000 CPU family +* +*****************************************************************************/ + +#include "emu.h" +#include "ns32000.h" +#include "ns32000dasm.h" +#include "debugger.h" + +//************************************************************************** +// DEVICE INTERFACE +//************************************************************************** + +DEFINE_DEVICE_TYPE(NS32008, ns32008_cpu_device, "ns32008", "National Semiconductor NS32008") +DEFINE_DEVICE_TYPE(NS32016, ns32016_cpu_device, "ns32016", "National Semiconductor NS32016") +DEFINE_DEVICE_TYPE(NS32032, ns32032_cpu_device, "ns32032", "National Semiconductor NS32032") + + +//------------------------------------------------- +// ns32000_cpu_device - constructor +//------------------------------------------------- + +ns32000_cpu_device::ns32000_cpu_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, int databits, int addrbits) + : cpu_device(mconfig, type, tag, owner, clock) + , m_program_config("program", ENDIANNESS_LITTLE, databits, addrbits, 0) + , m_icount(0) +{ +} + +ns32008_cpu_device::ns32008_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) + : ns32000_cpu_device(mconfig, NS32008, tag, owner, clock, 8, 24) +{ +} + +ns32016_cpu_device::ns32016_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) + : ns32000_cpu_device(mconfig, NS32016, tag, owner, clock, 16, 24) +{ +} + +ns32032_cpu_device::ns32032_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) + : ns32000_cpu_device(mconfig, NS32032, tag, owner, clock, 32, 24) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void ns32000_cpu_device::device_start() +{ + set_icountptr(m_icount); + + save_item(NAME(m_pc)); + save_item(NAME(m_r)); + save_item(NAME(m_f)); + + state_add(STATE_GENPC, "GENPC", m_pc).noshow(); + state_add(STATE_GENPCBASE, "CURPC", m_pc).noshow(); + + // dedicated registers + state_add(NS32000_PC, "PC", m_pc); + state_add(NS32000_SB, "SB", m_sb); + state_add(NS32000_FP, "FP", m_fp); + state_add(NS32000_SP1, "SP1", m_sp1); + state_add(NS32000_SP0, "SP0", m_sp0); + state_add(NS32000_INTBASE, "INTBASE", m_intbase); + state_add(NS32000_PSR, "PSR", m_psr); + state_add(NS32000_MOD, "MOD", m_mod); + + // general registers + for (unsigned i = 0; i < 8; i++) + state_add(NS32000_R0 + i, util::string_format("R%d", i).c_str(), m_r[i]); + + // floating point registers + //for (unsigned i = 0; i < 8; i++) + // state_add(NS32000_R7 + i, util::string_format("F%d", i).c_str(), m_f[i]); + + // set our instruction counter + //set_icountptr(m_icount); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void ns32000_cpu_device::device_reset() +{ + m_nmi_line = false; + m_irq_line = false; + + m_pc = 0; +} + +//------------------------------------------------- +// execute_run - execute a timeslice's worth of +// opcodes +//------------------------------------------------- + +void ns32000_cpu_device::execute_run() +{ + while (m_icount > 0) + { + debugger_instruction_hook(m_pc); + + m_icount--; + } +} + +//------------------------------------------------- +// execute_set_input - act on a changed input/ +// interrupt line +//------------------------------------------------- + +void ns32000_cpu_device::execute_set_input(int inputnum, int state) +{ + switch (inputnum) + { + case INPUT_LINE_NMI: + // NMI is edge triggered + m_nmi_line = m_nmi_line || (state == ASSERT_LINE); + break; + + case INPUT_LINE_IRQ0: + // IRQ is line triggered + m_irq_line = state == ASSERT_LINE; + break; + } +} + +//------------------------------------------------- +// memory_space_config - return the configuration +// of the specified address space, or nullptr if +// the space doesn't exist +//------------------------------------------------- + +device_memory_interface::space_config_vector ns32000_cpu_device::memory_space_config() const +{ + return space_config_vector{ std::make_pair(AS_PROGRAM, &m_program_config) }; +} + +bool ns32000_cpu_device::memory_translate(int spacenum, int intention, offs_t &address) +{ + return true; +} + +//------------------------------------------------- +// disassemble - call the disassembly +// helper function +//------------------------------------------------- + +std::unique_ptr<util::disasm_interface> ns32000_cpu_device::create_disassembler() +{ + return std::make_unique<ns32000_disassembler>(); +} diff --git a/src/devices/cpu/ns32000/ns32000.h b/src/devices/cpu/ns32000/ns32000.h new file mode 100644 index 00000000000..7b17cafba99 --- /dev/null +++ b/src/devices/cpu/ns32000/ns32000.h @@ -0,0 +1,149 @@ +// license:BSD-3-Clause +// copyright-holders:Nigel Barnes +/***************************************************************************** +* +* ns32000.h +* +* NS32000 CPU family +* +*****************************************************************************/ + +#ifndef MAME_CPU_NS32016_NS32016_H +#define MAME_CPU_NS32016_NS32016_H + +#pragma once + + +/*********************************************************************** + CONSTANTS +***********************************************************************/ + + + +/*********************************************************************** + TYPE DEFINITIONS +***********************************************************************/ + +class ns32000_cpu_device : public cpu_device +{ +public: + // construction/destruction + ns32000_cpu_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock); + +protected: + ns32000_cpu_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, int databits, int addrbits); + + // device-level overrides + virtual void device_start() override; + virtual void device_reset() override; + + // device_execute_interface overrides + virtual u32 execute_min_cycles() const override { return 1; } + virtual u32 execute_max_cycles() const override { return 6; } + virtual u32 execute_input_lines() const override { return 2; } + virtual void execute_run() override; + virtual void execute_set_input(int inputnum, int state) override; + virtual bool execute_input_edge_triggered(int inputnum) const override { return inputnum == INPUT_LINE_NMI; } + + + // device_memory_interface overrides + virtual space_config_vector memory_space_config() const override; + virtual bool memory_translate(int spacenum, int intention, offs_t &address) override; + + // device_disasm_interface overrides + virtual std::unique_ptr<util::disasm_interface> create_disassembler() override; + + // addressing modes + enum + { + ADDRESSING_MODE_REGISTER_0 = 0, + ADDRESSING_MODE_REGISTER_1, + ADDRESSING_MODE_REGISTER_2, + ADDRESSING_MODE_REGISTER_3, + ADDRESSING_MODE_REGISTER_4, + ADDRESSING_MODE_REGISTER_5, + ADDRESSING_MODE_REGISTER_6, + ADDRESSING_MODE_REGISTER_7, + ADDRESSING_MODE_REGISTER_0_RELATIVE, + ADDRESSING_MODE_REGISTER_1_RELATIVE, + ADDRESSING_MODE_REGISTER_2_RELATIVE, + ADDRESSING_MODE_REGISTER_3_RELATIVE, + ADDRESSING_MODE_REGISTER_4_RELATIVE, + ADDRESSING_MODE_REGISTER_5_RELATIVE, + ADDRESSING_MODE_REGISTER_6_RELATIVE, + ADDRESSING_MODE_REGISTER_7_RELATIVE, + ADDRESSING_MODE_FRAME_MEMORY_RELATIVE, + ADDRESSING_MODE_STACK_MEMORY_RELATIVE, + ADDRESSING_MODE_STATIC_MEMORY_RELATIVE, + ADDRESSING_MODE_RESERVED, + ADDRESSING_MODE_IMMEDIATE, + ADDRESSING_MODE_ABSOLUTE, + ADDRESSING_MODE_EXTERNAL, + ADDRESSING_MODE_TOP_OF_STACK, + ADDRESSING_MODE_FRAME_MEMORY, + ADDRESSING_MODE_STACK_MEMORY, + ADDRESSING_MODE_STATIC_MEMORY, + ADDRESSING_MODE_PROGRAM_MEMORY, + ADDRESSING_MODE_INDEX_BYTES, + ADDRESSING_MODE_INDEX_WORDS, + ADDRESSING_MODE_INDEX_DOUBLE_WORDS, + ADDRESSING_MODE_INDEX_QUAD_WORDS, + }; + + // registers + enum + { + NS32000_PC = 1, + NS32000_SB, NS32000_FP, NS32000_SP1, NS32000_SP0, NS32000_INTBASE, NS32000_PSR, NS32000_MOD, + NS32000_R0, NS32000_R1, NS32000_R2, NS32000_R3, NS32000_R4, NS32000_R5, NS32000_R6, NS32000_R7, + }; + +private: + // configuration + address_space_config m_program_config; + + // emulation state + int m_icount; + + u32 m_pc; + u32 m_sb; + u32 m_fp; + u32 m_sp1; + u32 m_sp0; + u32 m_intbase; + u32 m_psr; + u32 m_mod; + u32 m_r[8]; + u32 m_f[8]; + + u8 m_irq_line; + u8 m_nmi_line; +}; + +class ns32008_cpu_device : public ns32000_cpu_device +{ +public: + ns32008_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); +}; + +class ns32016_cpu_device : public ns32000_cpu_device +{ +public: + ns32016_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); +}; + +class ns32032_cpu_device : public ns32000_cpu_device +{ +public: + ns32032_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); +}; + +/*********************************************************************** + DEVICE TYPE DECLARATIONS +***********************************************************************/ + +DECLARE_DEVICE_TYPE(NS32008, ns32008_cpu_device) +DECLARE_DEVICE_TYPE(NS32016, ns32016_cpu_device) +DECLARE_DEVICE_TYPE(NS32032, ns32032_cpu_device) + +#endif // MAME_CPU_NS32016_NS32016_H diff --git a/src/devices/cpu/ns32000/ns32000dasm.cpp b/src/devices/cpu/ns32000/ns32000dasm.cpp new file mode 100644 index 00000000000..8bc25f48c60 --- /dev/null +++ b/src/devices/cpu/ns32000/ns32000dasm.cpp @@ -0,0 +1,835 @@ +// license:BSD-3-Clause +// copyright-holders:Nigel Barnes +/***************************************************************************** +* +* ns32000dasm.cpp +* +* NS32000 CPU Disassembly +* +*****************************************************************************/ + +#include "emu.h" +#include "ns32000dasm.h" + +// instruction field extraction +#define Format0cond(x) ((x >> 4) & 0x0f) + +#define Format1op(x) ((x >> 4) & 0x0f) + +#define Format2i(x) ((x >> 0) & 0x03) +#define Format2op(x) ((x >> 4) & 0x07) +#define Format2short(x) ((x >> 7) & 0x0f) +#define Format2gen(x) ((x >> 11) & 0x1f) + +#define Format3i(x) ((x >> 0) & 0x03) +#define Format3op(x) ((x >> 7) & 0x0f) +#define Format3gen(x) ((x >> 11) & 0x1f) + +#define Format4i(x) ((x >> 0) & 0x03) +#define Format4op(x) ((x >> 2) & 0x0f) +#define Format4gen2(x) ((x >> 6) & 0x1f) +#define Format4gen1(x) ((x >> 11) & 0x1f) + +#define Format5i(x) ((x >> 8) & 0x03) +#define Format5op(x) ((x >> 10) & 0x07) +#define Format5short(x) ((x >> 15) & 0x0f) + +#define Format6i(x) ((x >> 8) & 0x03) +#define Format6op(x) ((x >> 10) & 0x0f) +#define Format6gen2(x) ((x >> 14) & 0x1f) +#define Format6gen1(x) ((x >> 19) & 0x1f) + +#define Format7i(x) ((x >> 8) & 0x03) +#define Format7op(x) ((x >> 10) & 0x0f) +#define Format7gen2(x) ((x >> 14) & 0x1f) +#define Format7gen1(x) ((x >> 19) & 0x1f) + +#define Format8i(x) ((x >> 8) & 0x03) +#define Format8op(x) (((x >> 8) & 0x04) | ((x >> 6) & 0x03)) +#define Format8reg(x) ((x >> 11) & 0x07) +#define Format8gen2(x) ((x >> 14) & 0x1f) +#define Format8gen1(x) ((x >> 19) & 0x1f) + +#define Format9i(x) ((x >> 8) & 0x03) +#define Format9f(x) ((x >> 10) & 0x01) +#define Format9op(x) ((x >> 11) & 0x07) +#define Format9gen2(x) ((x >> 14) & 0x1f) +#define Format9gen1(x) ((x >> 19) & 0x1f) + +#define Format11f(x) ((x >> 8) & 0x01) +#define Format11op(x) ((x >> 10) & 0x0f) +#define Format11gen2(x) ((x >> 14) & 0x1f) +#define Format11gen1(x) ((x >> 19) & 0x1f) + +#define Format14i(x) ((x >> 8) & 0x01) +#define Format14op(x) ((x >> 10) & 0x0f) +#define Format14short(x) ((x >> 15) & 0x1f) +#define Format14gen1(x) ((x >> 19) & 0x1f) + +// instructions +const ns32000_disassembler::NS32000_OPCODE ns32000_disassembler::format0_op[1] = +{ + { "Bcond", DISP, 0, 0, 0, 0 } +}; +const ns32000_disassembler::NS32000_OPCODE ns32000_disassembler::format1_op[16] = +{ + { "BSR", DISP, 0, 0, 0, STEP_OVER }, + { "RET", DISP, 0, 0, 0, STEP_OUT }, + { "CXP", DISP, 0, 0, 0, STEP_OVER }, + { "RXP", DISP, 0, 0, 0, STEP_OUT }, + { "RETT", 0, 0, 0, 0, STEP_OUT }, + { "RETI", DISP, 0, 0, 0, STEP_OUT }, + { "SAVE", IMM, 0, 0, 0, 0 }, + { "RESTORE", IMM, 0, 0, 0, 0 }, + { "ENTER", IMM, DISP, 0, 0, 0 }, + { "EXIT", IMM, 0, 0, 0, 0 }, + { "NOP", 0, 0, 0, 0, 0 }, + { "WAIT", 0, 0, 0, 0, 0 }, + { "DIA", 0, 0, 0, 0, 0 }, + { "FLAG", 0, 0, 0, 0, 0 }, + { "SVC", 0, 0, 0, 0, 0 }, + { "BPT", 0, 0, 0, 0, 0 }, +}; +const ns32000_disassembler::NS32000_OPCODE ns32000_disassembler::format2_op[8] = +{ + { "ADDQi", QUICK, GEN | RMW | I, 0, 0, 0 }, + { "CMPQi", QUICK, GEN | READ | I, 0, 0, 0 }, + { "SPRi", SHORT, GEN | WRITE | I, 0, 0, 0 }, + { "Scondi", GEN | WRITE | I, 0, 0, 0, 0 }, + { "ACBi", QUICK, GEN | RMW | I, DISP, 0, 0 }, + { "MOVQi", QUICK, GEN | WRITE | I, 0, 0, 0 }, + { "LPRi", SHORT, GEN | READ | I, 0, 0, 0 }, + { "Trap (UND)", 0, 0, 0, 0, 0 }, +}; +const ns32000_disassembler::NS32000_OPCODE ns32000_disassembler::format3_op[16] = +{ + { "CXPD", GEN | ADDR, 0, 0, 0, STEP_OVER }, + { "Trap (UND)", 0, 0, 0, 0, 0 }, + { "BICPSRi", GEN | READ | I, 0, 0, 0, 0 }, + { "Trap (UND)", 0, 0, 0, 0, 0 }, + { "JUMP", GEN | ADDR, 0, 0, 0, 0 }, + { "Trap (UND)", 0, 0, 0, 0, 0 }, + { "BISPSRB", GEN | READ | B, 0, 0, 0, 0 }, + { "Trap (UND)", 0, 0, 0, 0, 0 }, + { "Trap (UND)", 0, 0, 0, 0, 0 }, + { "Trap (UND)", 0, 0, 0, 0, 0 }, + { "ADJSPi", GEN | READ | I, 0, 0, 0, 0 }, + { "Trap (UND)", 0, 0, 0, 0, 0 }, + { "JSR", GEN | ADDR, 0, 0, 0, STEP_OVER }, + { "Trap (UND)", 0, 0, 0, 0, 0 }, + { "CASEi", GEN | READ | I, 0, 0, 0, 0 }, + { "Trap (UND)", 0, 0, 0, 0, 0 }, +}; +const ns32000_disassembler::NS32000_OPCODE ns32000_disassembler::format4_op[16] = +{ + { "ADDi", GEN | READ | I, GEN | RMW | I, 0, 0, 0 }, + { "CMPi", GEN | READ | I, GEN | READ | I, 0, 0, 0 }, + { "BICi", GEN | READ | I, GEN | RMW | I, 0, 0, 0 }, + { "Trap (UND)", 0, 0, 0, 0, 0 }, + { "ADDCi", GEN | READ | I, GEN | RMW | I, 0, 0, 0 }, + { "MOVi", GEN | READ | I, GEN | WRITE | I, 0, 0, 0 }, + { "ORi", GEN | READ | I, GEN | RMW | I, 0, 0, 0 }, + { "Trap (UND)", 0, 0, 0, 0, 0 }, + { "SUBi", GEN | READ | I, GEN | RMW | I, 0, 0, 0 }, + { "ADDR", GEN | ADDR, GEN | WRITE | D, 0, 0, 0 }, + { "ANDi", GEN | READ | I, GEN | RMW | I, 0, 0, 0 }, + { "Trap (UND)", 0, 0, 0, 0, 0 }, + { "SUBCi", GEN | READ | I, GEN | RMW | I, 0, 0, 0 }, + { "TBITi", GEN | READ | I, GEN | REGADDR, 0, 0, 0 }, + { "XORi", GEN | READ | I, GEN | RMW | I, 0, 0, 0 }, + { "Trap (UND)", 0, 0, 0, 0, 0 }, +}; +const ns32000_disassembler::NS32000_OPCODE ns32000_disassembler::format5_op[16] = +{ + { "MOVSi", OPTIONS, 0, 0, 0, 0 }, + { "CMPSi", OPTIONS, 0, 0, 0, 0 }, + { "SETCFG", SHORT, 0, 0, 0, 0 }, + { "SKPSi", OPTIONS, 0, 0, 0, 0 }, + { "Trap (UND)", 0, 0, 0, 0, 0 }, + { "Trap (UND)", 0, 0, 0, 0, 0 }, + { "Trap (UND)", 0, 0, 0, 0, 0 }, + { "Trap (UND)", 0, 0, 0, 0, 0 }, + { "Trap (UND)", 0, 0, 0, 0, 0 }, + { "Trap (UND)", 0, 0, 0, 0, 0 }, + { "Trap (UND)", 0, 0, 0, 0, 0 }, + { "Trap (UND)", 0, 0, 0, 0, 0 }, + { "Trap (UND)", 0, 0, 0, 0, 0 }, + { "Trap (UND)", 0, 0, 0, 0, 0 }, + { "Trap (UND)", 0, 0, 0, 0, 0 }, + { "Trap (UND)", 0, 0, 0, 0, 0 }, +}; +const ns32000_disassembler::NS32000_OPCODE ns32000_disassembler::format6_op[16] = +{ + { "ROTi", GEN | READ | B, GEN | RMW | I, 0, 0, 0 }, + { "ASHi", GEN | READ | B, GEN | RMW | I, 0, 0, 0 }, + { "CBITi", GEN | READ | I, GEN | REGADDR, 0, 0, 0 }, + { "CBITIi", GEN | READ | I, GEN | REGADDR, 0, 0, 0 }, + { "Trap (UND)", 0, 0, 0, 0, 0 }, + { "LSHi", GEN | READ | B, GEN | RMW | I, 0, 0, 0 }, + { "SBITi", GEN | READ | I, GEN | REGADDR, 0, 0, 0 }, + { "SBITIi", GEN | READ | I, GEN | REGADDR, 0, 0, 0 }, + { "NEGi", GEN | READ | I, GEN | WRITE | I, 0, 0, 0 }, + { "NOTi", GEN | READ | I, GEN | WRITE | I, 0, 0, 0 }, + { "Trap (UND)", 0, 0, 0, 0, 0 }, + { "SUBPi", GEN | READ | I, GEN | RMW | I, 0, 0, 0 }, + { "ABSi", GEN | READ | I, GEN | READ | I, 0, 0, 0 }, + { "COM", GEN | READ | I, GEN | WRITE | I, 0, 0, 0 }, + { "IBITi", GEN | READ | I, GEN | REGADDR, 0, 0, 0 }, + { "ADDPi", GEN | READ | I, GEN | RMW | I, 0, 0, 0 }, +}; +const ns32000_disassembler::NS32000_OPCODE ns32000_disassembler::format7_op[16] = +{ + { "MOVMi", GEN | ADDR, GEN | ADDR, DISP, 0, 0 }, + { "CMPMi", GEN | ADDR, GEN | ADDR, DISP, 0, 0 }, + { "INSSi", GEN | READ | I, GEN | REGADDR, IMM, 0, 0 }, + { "EXTSi", GEN | REGADDR, GEN | WRITE | I, IMM, 0, 0 }, + { "MOVXBW", GEN | READ | B, GEN | WRITE | W, 0, 0, 0 }, + { "MOVZBW", GEN | READ | B, GEN | WRITE | W, 0, 0, 0 }, + { "MOVZiD", GEN | READ | I, GEN | WRITE | D, 0, 0, 0 }, + { "MOVXiD", GEN | READ | I, GEN | WRITE | D, 0, 0, 0 }, + { "MULi", GEN | READ | I, GEN | RMW | I, 0, 0, 0 }, + { "MEIi", GEN | READ | I, GEN | RMW | I2, 0, 0, 0 }, + { "Trap (UND)", 0, 0, 0, 0, 0 }, + { "DEIi", GEN | READ | I, GEN | RMW | I2, 0, 0, 0 }, + { "QUOi", GEN | READ | I, GEN | RMW | I, 0, 0, 0 }, + { "REMi", GEN | READ | I, GEN | RMW | I, 0, 0, 0 }, + { "MODi", GEN | READ | I, GEN | RMW | I, 0, 0, 0 }, + { "DIVi", GEN | READ | I, GEN | RMW | I, 0, 0, 0 }, +}; +const ns32000_disassembler::NS32000_OPCODE ns32000_disassembler::format8_op[] = +{ + { "EXTi", REG, GEN | REGADDR, GEN | WRITE | I, DISP, 0 }, + { "CVTP", REG, GEN | ADDR, GEN | WRITE | D, 0, 0 }, + { "INSi", REG, GEN | READ | I, GEN | REGADDR, DISP, 0 }, + { "CHECKi", REG, GEN | ADDR, GEN | READ | I, 0, 0 }, + { "INDEXi", REG, GEN | READ | I, GEN | READ | I, 0, 0 }, + { "FFSi", GEN | READ | I, GEN | RMW | B, 0, 0, 0 }, + { "MOVSUi", GEN | ADDR, GEN | ADDR, 0, 0, 0 }, + { "MOVUSi", GEN | ADDR, GEN | ADDR, 0, 0, 0 } +}; +const ns32000_disassembler::NS32000_OPCODE ns32000_disassembler::format9_op[] = +{ + { "MOVif", GEN | READ | I, GEN | WRITE | F, 0, 0, 0 }, + { "LFSR", GEN | READ | D, 0, 0, 0, 0 }, + { "MOVLF", GEN | READ | L, GEN | WRITE | F, 0, 0, 0 }, + { "MOVFL", GEN | READ | F, GEN | WRITE | L, 0, 0, 0 }, + { "ROUNDfi", GEN | READ | F, GEN | WRITE | I, 0, 0, 0 }, + { "TRUNCfi", GEN | READ | F, GEN | WRITE | I, 0, 0, 0 }, + { "SFSR", GEN | WRITE | D, 0, 0, 0, 0 }, + { "FLOORfi", GEN | READ | F, GEN | WRITE | I, 0, 0, 0 }, +}; +const ns32000_disassembler::NS32000_OPCODE ns32000_disassembler::format11_op[] = +{ + { "ADDf", GEN | READ | F, GEN | RMW | F, 0, 0, 0 }, + { "MOVf", GEN | READ | F, GEN | WRITE | F, 0, 0, 0 }, + { "CMPf", GEN | READ | F, GEN | READ | F, 0, 0, 0 }, // POLYf + { "Trap (SLAVE)", 0, 0, 0, 0, 0 }, // DOTf + { "SUBf", GEN | READ | F, GEN | RMW | F, 0, 0, 0 }, // SCALBf + { "NEGf", GEN | READ | F, GEN | WRITE | F, 0, 0, 0 }, // LOGBf + { "Trap (UND)", 0, 0, 0, 0, 0 }, + { "Trap (UND)", 0, 0, 0, 0, 0 }, + { "DIVf", GEN | READ | F, GEN | RMW | F, 0, 0, 0 }, + { "Trap (SLAVE)", 0, 0, 0, 0, 0 }, + { "Trap (UND)", 0, 0, 0, 0, 0 }, + { "Trap (UND)", 0, 0, 0, 0, 0 }, + { "MULf", GEN | READ | F, GEN | RMW | F, 0, 0, 0 }, + { "ABSf", GEN | READ | F, GEN | READ | F, 0, 0, 0 }, + { "Trap (UND)", 0, 0, 0, 0, 0 }, + { "Trap (UND)", 0, 0, 0, 0, 0 }, +}; +const ns32000_disassembler::NS32000_OPCODE ns32000_disassembler::format14_op[] = +{ + { "RDVAL", GEN | ADDR, 0, 0, 0, 0 }, + { "WRVAL", GEN | ADDR, 0, 0, 0, 0 }, + { "LMR", SHORT, GEN | READ | D, 0, 0, 0 }, + { "SMR", SHORT, GEN | WRITE | D, 0, 0, 0 }, + { "Trap (UND)", 0, 0, 0, 0, 0 }, + { "Trap (UND)", 0, 0, 0, 0, 0 }, + { "Trap (UND)", 0, 0, 0, 0, 0 }, + { "Trap (UND)", 0, 0, 0, 0, 0 }, + { "Trap (UND)", 0, 0, 0, 0, 0 }, + { "Trap (UND)", 0, 0, 0, 0, 0 }, // CINV + { "Trap (UND)", 0, 0, 0, 0, 0 }, + { "Trap (UND)", 0, 0, 0, 0, 0 }, + { "Trap (UND)", 0, 0, 0, 0, 0 }, + { "Trap (UND)", 0, 0, 0, 0, 0 }, + { "Trap (UND)", 0, 0, 0, 0, 0 }, + { "Trap (UND)", 0, 0, 0, 0, 0 }, +}; + + +const char *const ns32000_disassembler::Format0[] = +{ + "Bcond" +}; +const char *const ns32000_disassembler::Format1[] = +{ + "BSR", "RET", "CXP", "RXP", "RETT", "RETI", "SAVE", "RESTORE", "ENTER", "EXIT", "NOP", "WAIT", "DIA", "FLAG", "SVC", "BPT" +}; +const char *const ns32000_disassembler::Format2[] = +{ + "ADDQi", "CMPQi", "SPRi", "Scondi", "ACBi", "MOVQi", "LPRi" +}; +const char *const ns32000_disassembler::Format3[] = +{ + "CXPD", "Trap (UND)", "BICPSR", "Trap (UND)", "JUMP", "Trap (UND)", "BISPSR", "Trap (UND)", "Trap (UND)", "Trap (UND)", "ADJSPi", "Trap (UND)", "JSR", "Trap (UND)", "CASEi", "Trap (UND)" +}; +const char *const ns32000_disassembler::Format4[] = +{ + "ADDi", "CMPi", "BICi", "Trap (UND)", "ADDCi", "MOVi", "ORi", "Trap (UND)", "SUBi", "ADDR", "ANDi", "Trap (UND)", "SUBCi", "TBITi", "XORi", "Trap (UND)" +}; +const char *const ns32000_disassembler::Format5[] = +{ + "MOVSi", "CMPSi", "SETCFG", "SKPSi", "Trap (UND)", "Trap (UND)", "Trap (UND)", "Trap (UND)", "Trap (UND)", "Trap (UND)", "Trap (UND)", "Trap (UND)", "Trap (UND)", "Trap (UND)", "Trap (UND)", "Trap (UND)" +}; +const char *const ns32000_disassembler::Format6[] = +{ + "ROTi", "ASHi", "CBITi", "CBITIi", "Trap (UND)", "LSHi", "SBITi", "SBITIi", "NEGi", "NOTi", "Trap (UND)", "SUBPi", "ABSi", "COM", "IBITi", "ADDPi" +}; +const char *const ns32000_disassembler::Format7[] = +{ + "MOVMi", "CMPMi", "INSSi", "EXTSi", "MOVXBW", "MOVZBW", "MOVZiD", "MOVXiD", "MULi", "MEIi", "Trap (UND)", "DEIi", "QUOi", "REMi", "MODi", "DIVi" +}; +const char *const ns32000_disassembler::Format8[] = +{ + "EXTi", "CVTP", "INSi", "CHECKi", "INDEXi", "FFSi", "MOVSUi", "MOVUSi" +}; +const char *const ns32000_disassembler::Format9[] = +{ + "MOVif", "LFSR", "MOVLF", "MOVFL", "ROUNDfi", "TRUNCfi", "SFSR", "FLOORfi" +}; +const char *const ns32000_disassembler::Format11[] = +{ + "ADDf", "MOVf", "CMPf", "Trap (SLAVE)", "SUBf", "NEGf", "Trap (UND)", "Trap (UND)", "DIVf", "Trap (SLAVE)", "Trap (UND)", "Trap (UND)", "MULf", "ABSf", "Trap (UND)", "Trap (UND)" +}; +const char *const ns32000_disassembler::Format14[] = +{ + "RDVAL", "WRVAL", "LMR", "SMR", "Trap (UND)", "Trap (UND)", "Trap (UND)", "Trap (UND)", "Trap (UND)", "Trap (UND)", "Trap (UND)", "Trap (UND)", "Trap (UND)", "Trap (UND)", "Trap (UND)", "Trap (UND)" +}; + +// types +const char *const ns32000_disassembler::iType[] = +{ + "B", "W", " ", "D" +}; +const char *const ns32000_disassembler::fType[] = +{ + "L", "F" +}; +const char *const ns32000_disassembler::cType[] = +{ + "Q", "D" +}; + +// index byte sizes +const char *const ns32000_disassembler::indexSize[] = +{ + "B", "W", "D", "Q" +}; + +// short codes +const char *const ns32000_disassembler::cond[] = +{ + "EQ", "NE", "CS", "CC", "HI", "LS", "GT", "LE", "FS", "FC", "LO", "HS", "LT", "GE", "R", "N" +}; +const char *const ns32000_disassembler::areg[] = +{ + "US", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "FP", "SP", "SB", "(reserved)", "(reserved)", "PSR", "INTBASE", "MOD" +}; +const char *const ns32000_disassembler::mreg[] = +{ + "BPR0", "BPR1", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "MSR", "BCNT", "PTB0", "PTB1", "(reserved)", "EIA" +}; + +// register names +const char *const ns32000_disassembler::R[] = +{ + "R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7" +}; +const char *const ns32000_disassembler::M[] = +{ + "FP", "SP", "SB" +}; +const char *const ns32000_disassembler::PR[] = +{ + "UPSR", "DCR", "BPC", "DSR", "CAR", "", "", "", "FP", "SP", "SB", "USP", "CFG", "PSR", "INTBASE", "MOD" +}; + +int8_t ns32000_disassembler::short2int(uint8_t val) +{ + return (val & 0x08) ? val | 0xf0 : val; +} + +std::string ns32000_disassembler::mnemonic_index(std::string form, std::string itype, std::string ftype) +{ + if (itype.size() && form.find('i') != std::string::npos) + form.replace(form.find('i'), 1, itype); + if (ftype.size() && form.find('f') != std::string::npos) + form.replace(form.find('f'), 1, ftype); + return form; +} + +uint8_t ns32000_disassembler::opcode_format(uint8_t byte) +{ + switch (byte & 0x0f) + { + case 0x0a: return 0; + case 0x02: return 1; + case 0x0c: + case 0x0d: + case 0x0f: + if ((byte & 0x70) != 0x70) + return 2; + else + return 3; + } + + if ((byte & 0x03) != 0x02) return 4; + + switch (byte) + { + case 0x0e: return 5; + case 0x4e: return 6; + case 0xce: return 7; + case 0x2e: + case 0x6e: + case 0xae: + case 0xee: return 8; + case 0x3e: return 9; + case 0x7e: return 10; + case 0xbe: return 11; + case 0xfe: return 12; + case 0x9e: return 13; + case 0x1e: return 14; + } + + return 99; /* unknown format */ +} + +inline std::string ns32000_disassembler::get_option_list(uint8_t cfg) +{ + std::string option_list; + + option_list.append("["); + if (BIT(cfg, 0)) option_list.append("I,"); + if (BIT(cfg, 1)) option_list.append("F,"); + if (BIT(cfg, 2)) option_list.append("M,"); + if (BIT(cfg, 3)) option_list.append("C,"); + if (option_list.back() == ',') option_list.pop_back(); + option_list.append("]"); + + return option_list; +} + +inline std::string ns32000_disassembler::get_options(uint8_t opts) +{ + std::string options; + + options.append(" "); + if ((opts & 0x02) == 0x02) options.append("B,"); + if ((opts & 0x04) == 0x04) options.append("W,"); + if ((opts & 0x0c) == 0x0c) options.append("U,"); + if (options.back() == ',') options.pop_back(); + + return options; +} + +inline int32_t ns32000_disassembler::get_disp(offs_t &pc, const data_buffer &opcodes) +{ + /* displacement can be upto 3 bytes */ + uint32_t disp = bitswap<32>(opcodes.r32(pc), 7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8, 23, 22, 21, 20, 19, 18, 17, 16, 31, 30, 29, 28, 27, 26, 25, 24); + + switch ((disp >> 29) & 0x07) + { + case 0: case 1: /* 7 bit positive */ + disp = (disp >> 24); + pc += 1; + break; + + case 2: case 3: /* 7 bit negative */ + disp = (disp >> 24) | 0xffffff80; + pc += 1; + break; + + case 4: /* 14 bit positive */ + disp = (disp >> 16) & 0x3fff; + pc += 2; + break; + + case 5: /* 14 bit negative */ + disp = (disp >> 16) | 0xffffc000; + pc += 2; + break; + + case 6: /* 30 bit positive */ + disp = disp & 0x3fffffff; + pc += 4; + break; + + case 7: /* 30 bit negative */ + pc += 4; + break; + } + + return disp; +} + +inline std::string ns32000_disassembler::get_reg_list(offs_t &pc, const data_buffer &opcodes, bool reverse) +{ + std::string reg_list; + + uint8_t byte = opcodes.r8(pc++); + + reg_list.append("["); + for (int i = 0; i < 8; i++) + { + if (BIT(byte, i)) reg_list.append(R[reverse ? (~i & 7) : (i & 7)]).append(","); + } + if (reg_list.back() == ',') reg_list.pop_back(); + reg_list.append("]"); + + return reg_list; +} + +void ns32000_disassembler::stream_gen(std::ostream &stream, u8 gen_addr, u8 op_len, offs_t &pc, const data_buffer &opcodes) +{ + uint8_t index_byte; + int32_t disp1, disp2; + + switch (gen_addr) + { + case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: + /* Register */ + util::stream_format(stream, "%s", R[gen_addr & 0x07]); + break; + case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: + /* Register Relative */ + disp1 = get_disp(pc, opcodes); + util::stream_format(stream, "%+d(%s)", disp1, R[gen_addr & 0x07]); + break; + case 0x10: case 0x11: case 0x12: + /* Memory Relative */ + disp1 = get_disp(pc, opcodes); + disp2 = get_disp(pc, opcodes); + util::stream_format(stream, "#X%02X(#X%02X(%s))", disp2, disp1, M[gen_addr & 0x03]); + break; + case 0x13: + /* Reserved */ + util::stream_format(stream, "(reserved)"); + break; + case 0x14: + /* Immediate */ + disp1 = bitswap<32>(opcodes.r32(pc), 7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8, 23, 22, 21, 20, 19, 18, 17, 16, 31, 30, 29, 28, 27, 26, 25, 24); + util::stream_format(stream, "#X%02X", (op_len == 0 ? (disp1 >> 24) : (op_len == 1 ? (disp1 >> 16) : disp1))); + pc += op_len + 1; + break; + case 0x15: + /* Absolute */ + disp1 = get_disp(pc, opcodes); + util::stream_format(stream, "@#X%02X", disp1); + break; + case 0x16: + /* External */ + disp1 = get_disp(pc, opcodes); + disp2 = get_disp(pc, opcodes); + util::stream_format(stream, "EXT(%d)+%d", disp1, disp2); + break; + case 0x17: + /* Top Of Stack */ + util::stream_format(stream, "TOS"); + break; + case 0x18: case 0x19: case 0x1a: + /* Memory Space */ + disp1 = get_disp(pc, opcodes); + util::stream_format(stream, "#X%02X(%s)", disp1, M[gen_addr & 0x03]); + break; + case 0x1b: + /* Memory Space */ + disp1 = get_disp(pc, opcodes); + util::stream_format(stream, "#X%06X", m_base_pc + disp1); + break; + case 0x1c: + /* Scaled Index */ + index_byte = opcodes.r8(pc++); + stream_gen(stream, index_byte >> 3, op_len, pc, opcodes); + util::stream_format(stream, "[%s:%c]", R[index_byte & 0x07], indexSize[gen_addr & 0x03]); + break; + } +} + +offs_t ns32000_disassembler::disassemble(std::ostream &stream, offs_t pc, const data_buffer &opcodes, const data_buffer ¶ms) +{ + uint32_t flags = SUPPORTED; + + uint32_t opcode; + std::string mnemonic; + uint8_t temp8; + + /* opcode can be upto 3 bytes */ + opcode = opcodes.r32(pc); + m_base_pc = pc; + + switch (opcode_format(opcode)) + { + case 0: /* Format 0 */ + pc += 1; + util::stream_format(stream, "%-8s #X%06X", std::string("B").append(cond[Format0cond(opcode)]), m_base_pc + get_disp(pc, opcodes)); + break; + + case 0x01: /* Format 1 */ + pc += 1; + switch (Format1op(opcode)) + { + case 0x00: + util::stream_format(stream, "%-8s #X%06X", Format1[Format1op(opcode)], m_base_pc + get_disp(pc, opcodes)); + break; + case 0x01: + util::stream_format(stream, "%-8s #X%02X", Format1[Format1op(opcode)], get_disp(pc, opcodes) & 0xffffff); + break; + case 0x02: + util::stream_format(stream, "%-8s EXT(%d)", Format1[Format1op(opcode)], get_disp(pc, opcodes)); + break; + case 0x03: case 0x04: + util::stream_format(stream, "%-8s #X%02X", Format1[Format1op(opcode)], get_disp(pc, opcodes) & 0xffffff); + break; + case 0x05: + util::stream_format(stream, "%-8s", Format1[Format1op(opcode)]); + break; + case 0x06: + util::stream_format(stream, "%-8s %s", Format1[Format1op(opcode)], get_reg_list(pc, opcodes, false)); + break; + case 0x07: case 0x09: + util::stream_format(stream, "%-8s %s", Format1[Format1op(opcode)], get_reg_list(pc, opcodes, true)); + break; + case 0x08: + util::stream_format(stream, "%-8s %s, %d", Format1[Format1op(opcode)], get_reg_list(pc, opcodes, false), get_disp(pc, opcodes)); + break; + case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: + util::stream_format(stream, "%-8s", Format1[Format1op(opcode)]); + break; + } + break; + + case 0x02: /* Format 2 */ + pc += 2; + mnemonic = mnemonic_index(Format2[Format2op(opcode)], iType[Format2i(opcode)], ""); + switch (Format2op(opcode)) + { + case 0x00: case 0x01: case 0x05: + util::stream_format(stream, "%-8s %+d, ", mnemonic, short2int(Format2short(opcode))); + stream_gen(stream, Format2gen(opcode), Format2i(opcode), pc, opcodes); + break; + case 0x02: case 0x06: + util::stream_format(stream, "%-8s %s, ", mnemonic, areg[Format2short(opcode)]); + stream_gen(stream, Format2gen(opcode), Format2i(opcode), pc, opcodes); + break; + case 0x03: + util::stream_format(stream, "%-8s ", std::string("S").append(cond[Format2short(opcode)]).append(iType[Format2i(opcode)])); + stream_gen(stream, Format2gen(opcode), Format2i(opcode), pc, opcodes); + break; + case 0x04: + util::stream_format(stream, "%-8s %+d, ", mnemonic, short2int(Format2short(opcode))); + stream_gen(stream, Format2gen(opcode), Format2i(opcode), pc, opcodes); + util::stream_format(stream, ", #X%06x", m_base_pc + get_disp(pc, opcodes)); + break; + } + break; + + case 0x03: /* Format 3 */ + pc += 2; + mnemonic = mnemonic_index(Format3[Format3op(opcode)], iType[Format3i(opcode)], ""); + switch (Format3op(opcode)) + { + case 0x00: case 0x02: case 0x04: case 0x06: case 0x0a: case 0x0c: case 0x0e: + util::stream_format(stream, "%-8s ", mnemonic); + stream_gen(stream, Format3gen(opcode), Format3i(opcode), pc, opcodes); + break; + default: /* Trap */ + util::stream_format(stream, "%-8s ", mnemonic); + break; + } + break; + + case 0x04: /* Format 4 */ + pc += 2; + mnemonic = mnemonic_index(Format4[Format4op(opcode)], iType[Format4i(opcode)], ""); + util::stream_format(stream, "%-8s ", mnemonic); + stream_gen(stream, Format4gen1(opcode), Format4i(opcode), pc, opcodes); + util::stream_format(stream, ", "); + stream_gen(stream, Format4gen2(opcode), Format4i(opcode), pc, opcodes); + break; + + case 0x05: /* Format 5 */ + pc += 3; + mnemonic = mnemonic_index(Format5[Format5op(opcode)], iType[Format5i(opcode)], ""); + switch ((opcode >> 10) & 0x0f) + { + case 0x00: case 0x01: case 0x03: + if (Format5short(opcode) & 0x01) + util::stream_format(stream, "%-8s %s", std::string(Format5[Format5op(opcode)]).append("T"), get_options(Format5short(opcode))); + else + util::stream_format(stream, "%-8s %s", mnemonic, get_options(Format5short(opcode))); + break; + case 0x02: + util::stream_format(stream, "%-8s %s", Format5[Format5op(opcode)], get_option_list(Format5short(opcode))); + break; + default: /* Trap */ + util::stream_format(stream, "%-8s ", mnemonic); + break; + } + break; + + case 0x06: /* Format 6 */ + pc += 3; + mnemonic = mnemonic_index(Format6[Format6op(opcode)], iType[Format6i(opcode)], ""); + switch ((opcode >> 10) & 0x0f) + { + case 0x00: case 0x01: case 0x02: case 0x03: case 0x05: case 0x06: case 0x07: case 0x08: case 0x09: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: + util::stream_format(stream, "%-8s ", mnemonic); + stream_gen(stream, Format6gen1(opcode), Format6i(opcode), pc, opcodes); + util::stream_format(stream, ", "); + stream_gen(stream, Format6gen2(opcode), Format6i(opcode), pc, opcodes); + break; + default: /* Trap */ + util::stream_format(stream, "%-8s ", mnemonic); + break; + } + break; + + case 0x07: /* Format 7 */ + pc += 3; + mnemonic = mnemonic_index(Format7[Format7op(opcode)], iType[Format7i(opcode)], ""); + switch (Format7op(opcode)) + { + case 0x00: case 0x01: + util::stream_format(stream, "%-8s ", mnemonic); + stream_gen(stream, Format7gen1(opcode), Format7i(opcode), pc, opcodes); + util::stream_format(stream, ", "); + stream_gen(stream, Format7gen2(opcode), Format7i(opcode), pc, opcodes); + util::stream_format(stream, ", %d", get_disp(pc, opcodes)); + break; + case 0x02: case 0x03: + util::stream_format(stream, "%-8s ", mnemonic); + stream_gen(stream, Format7gen1(opcode), Format7i(opcode), pc, opcodes); + util::stream_format(stream, ", "); + stream_gen(stream, Format7gen2(opcode), Format7i(opcode), pc, opcodes); + temp8 = opcodes.r8(pc++); + util::stream_format(stream, ", %d, %d", temp8 >> 5, temp8 + 1); + break; + case 0x04: case 0x05: case 0x06: case 0x07: case 0x08: case 0x09: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: + util::stream_format(stream, "%-8s ", mnemonic); + stream_gen(stream, Format7gen1(opcode), Format7i(opcode), pc, opcodes); + util::stream_format(stream, ", "); + stream_gen(stream, Format7gen2(opcode), Format7i(opcode), pc, opcodes); + break; + default: /* Trap */ + util::stream_format(stream, "%-8s ", mnemonic); + break; + } + break; + + case 0x08: /* Format 8 */ + pc += 3; + mnemonic = mnemonic_index(Format8[Format8op(opcode)], iType[Format8i(opcode)], ""); + switch (Format8op(opcode)) + { + case 0x00: case 0x02: + util::stream_format(stream, "%-8s %s, ", mnemonic, R[Format8reg(opcode)]); + stream_gen(stream, Format8gen2(opcode), Format8i(opcode), pc, opcodes); + util::stream_format(stream, ", "); + stream_gen(stream, Format8gen1(opcode), Format8i(opcode), pc, opcodes); + util::stream_format(stream, ", %d", get_disp(pc, opcodes)); + break; + case 0x01: case 0x03: case 0x04: + util::stream_format(stream, "%-8s %s, ", mnemonic, R[Format8reg(opcode)]); + stream_gen(stream, Format8gen2(opcode), Format8i(opcode), pc, opcodes); + util::stream_format(stream, ", "); + stream_gen(stream, Format8gen1(opcode), Format8i(opcode), pc, opcodes); + break; + case 0x05: + util::stream_format(stream, "%-8s ", mnemonic); + stream_gen(stream, Format8gen2(opcode), Format8i(opcode), pc, opcodes); + util::stream_format(stream, ", "); + stream_gen(stream, Format8gen1(opcode), Format8i(opcode), pc, opcodes); + break; + case 0x06: + if (Format8reg(opcode) == 0x01) + util::stream_format(stream, "%-8s ", std::string(Format8[Format8op(opcode)]).append(iType[Format8i(opcode)])); + else + util::stream_format(stream, "%-8s ", std::string(Format8[Format8op(opcode) + 1]).append(iType[Format8i(opcode)])); + stream_gen(stream, Format8gen2(opcode), Format8i(opcode), pc, opcodes); + util::stream_format(stream, ", "); + stream_gen(stream, Format8gen1(opcode), Format8i(opcode), pc, opcodes); + break; + } + break; + + case 0x09: /* Format 9 */ + pc += 3; + mnemonic = mnemonic_index(Format9[Format9op(opcode)], iType[Format9i(opcode)], fType[Format9f(opcode)]); + switch (Format9op(opcode)) + { + case 0x00: case 0x02: case 0x04: case 0x05: case 0x07: + util::stream_format(stream, "%-8s ", mnemonic); + stream_gen(stream, Format9gen1(opcode), Format9i(opcode), pc, opcodes); + util::stream_format(stream, ", "); + stream_gen(stream, Format9gen2(opcode), Format9i(opcode), pc, opcodes); + break; + case 0x01: case 0x06: + util::stream_format(stream, "%-8s ", mnemonic); + stream_gen(stream, Format9gen1(opcode), Format9i(opcode), pc, opcodes); + break; + } + break; + + case 0x0b: /* Format 11 */ + pc += 3; + mnemonic = mnemonic_index(Format11[Format11op(opcode)], "", fType[Format11f(opcode)]); + switch (Format11op(opcode)) + { + case 0x00: case 0x01: case 0x02: case 0x04: case 0x05 : case 0x08: case 0x0c : case 0x0d: + util::stream_format(stream, "%-8s ", mnemonic); + stream_gen(stream, Format11gen1(opcode), Format11f(opcode), pc, opcodes); + util::stream_format(stream, ","); + stream_gen(stream, Format11gen2(opcode), Format11f(opcode), pc, opcodes); + break; + default: /* Trap */ + util::stream_format(stream, "%-8s ", mnemonic); + break; + } + break; + + case 0x0a: /* Format 10 */ + case 0x0c: /* Format 12 */ + case 0x0d: /* Format 13 */ + pc += 3; + util::stream_format(stream, "Trap (UND)"); + break; + + case 0x0e: /* Format 14 */ + pc += 3; + mnemonic = mnemonic_index(Format14[Format14op(opcode)], iType[Format14i(opcode)], ""); + switch (Format14op(opcode)) + { + case 0x00: case 0x01: + util::stream_format(stream, "%-8s ", mnemonic); + stream_gen(stream, Format14gen1(opcode), Format14i(opcode), pc, opcodes); + break; + case 0x02: case 0x03: + util::stream_format(stream, "%-8s %s, ", mnemonic, mreg[Format14short(opcode)]); + stream_gen(stream, Format14gen1(opcode), Format14i(opcode), pc, opcodes); + break; + default: /* Trap */ + util::stream_format(stream, "%-8s ", mnemonic); + break; + } + break; + + default: + pc += 1; + util::stream_format(stream, "unknown instruction format"); + break; + } + + return (pc - m_base_pc) | flags; +} diff --git a/src/devices/cpu/ns32000/ns32000dasm.h b/src/devices/cpu/ns32000/ns32000dasm.h new file mode 100644 index 00000000000..4cbf4cf3bda --- /dev/null +++ b/src/devices/cpu/ns32000/ns32000dasm.h @@ -0,0 +1,117 @@ +// license:BSD-3-Clause +// copyright-holders:Nigel Barnes +/***************************************************************************** +* +* ns32000dasm.cpp +* +* NS32000 CPU Disassembly +* +*****************************************************************************/ + +#ifndef MAME_CPU_NS32000_NS32000DASM_H +#define MAME_CPU_NS32000_NS32000DASM_H + +#pragma once + +class ns32000_disassembler : public util::disasm_interface +{ +public: + + ns32000_disassembler() = default; + virtual ~ns32000_disassembler() = default; + + virtual u32 opcode_alignment() const override { return 1; } + virtual offs_t disassemble(std::ostream &stream, offs_t pc, const data_buffer &opcodes, const data_buffer ¶ms) override; + +private: + /* implied operand attributes */ + enum + { + REG = 16, + QUICK, + SHORT, + IMM, + DISP, + GEN, + OPTIONS, + }; + /* access classes */ + enum + { + READ = 8, + WRITE, + RMW, + ADDR, + REGADDR + }; + /* length attributes */ + enum + { + B = 0, + W = 1, + D = 3, + I, + I2, + F, + L + }; + struct NS32000_OPCODE { + const char *mnemonic; + u32 operand1; + u32 operand; + u32 operand3; + u32 operand4; + offs_t dasm_flags; + }; + + static const NS32000_OPCODE format0_op[1]; + static const NS32000_OPCODE format1_op[16]; + static const NS32000_OPCODE format2_op[8]; + static const NS32000_OPCODE format3_op[16]; + static const NS32000_OPCODE format4_op[16]; + static const NS32000_OPCODE format5_op[16]; + static const NS32000_OPCODE format6_op[16]; + static const NS32000_OPCODE format7_op[16]; + static const NS32000_OPCODE format8_op[16]; + static const NS32000_OPCODE format9_op[16]; + static const NS32000_OPCODE format11_op[16]; + static const NS32000_OPCODE format14_op[16]; + + + static char const *const Format0[]; + static char const *const Format1[]; + static char const *const Format2[]; + static char const *const Format3[]; + static char const *const Format4[]; + static char const *const Format5[]; + static char const *const Format6[]; + static char const *const Format7[]; + static char const *const Format8[]; + static char const *const Format9[]; + static char const *const Format11[]; + static char const *const Format14[]; + static char const *const iType[]; + static char const *const fType[]; + static char const *const cType[]; + static char const *const indexSize[]; + static char const *const cond[]; + static char const *const areg[]; + static char const *const mreg[]; + static char const *const R[]; + static char const *const M[]; + static char const *const PR[]; + + std::string mnemonic_index(std::string form, std::string itype, std::string ftype); + uint8_t opcode_format(uint8_t byte); + int8_t short2int(uint8_t val); + static inline int32_t get_disp(offs_t &pc, const data_buffer &opcodes); + static inline std::string get_option_list(uint8_t cfg); + static inline std::string get_options(uint8_t opts); + static inline std::string get_reg_list(offs_t &pc, const data_buffer &opcodes, bool reverse); + + void stream_gen(std::ostream &stream, u8 gen_addr, u8 op_len, offs_t &pc, const data_buffer &opcodes); + + u32 m_base_pc; +}; + +#endif diff --git a/src/devices/cpu/tms9900/tms9900.cpp b/src/devices/cpu/tms9900/tms9900.cpp index d1576197247..840fd5d631a 100644 --- a/src/devices/cpu/tms9900/tms9900.cpp +++ b/src/devices/cpu/tms9900/tms9900.cpp @@ -2167,6 +2167,7 @@ void tms99xx_device::alu_clr_swpb() bool setstatus = true; bool check_ov = true; + bool check_c = true; switch (m_command) { @@ -2184,6 +2185,7 @@ void tms99xx_device::alu_clr_swpb() // LAE dest_new = ~src_val & 0xffff; check_ov = false; + check_c = false; break; case NEG: // LAECO @@ -2226,7 +2228,7 @@ void tms99xx_device::alu_clr_swpb() if (setstatus) { if (check_ov) set_status_bit(ST_OV, ((src_val & 0x8000)==sign) && ((dest_new & 0x8000)!=sign)); - set_status_bit(ST_C, (dest_new & 0x10000) != 0); + if (check_c) set_status_bit(ST_C, (dest_new & 0x10000) != 0); m_current_value = dest_new & 0xffff; compare_and_set_lae(m_current_value, 0); } @@ -2518,6 +2520,7 @@ void tms99xx_device::alu_shift() uint16_t sign = 0; uint32_t value; int count; + bool check_ov = false; switch (m_state) { @@ -2575,6 +2578,7 @@ void tms99xx_device::alu_shift() case SLA: carry = ((value & 0x8000)!=0); value <<= 1; + check_ov = true; if (carry != ((value&0x8000)!=0)) overflow = true; break; case SRC: @@ -2587,7 +2591,7 @@ void tms99xx_device::alu_shift() m_current_value = value & 0xffff; set_status_bit(ST_C, carry); - set_status_bit(ST_OV, overflow); + if (check_ov) set_status_bit(ST_OV, overflow); // only SLA compare_and_set_lae(m_current_value, 0); m_address = m_address_saved; // Register address if (TRACE_STATUS) logerror("ST = %04x (val=%04x)\n", ST, m_current_value); diff --git a/src/devices/cpu/tms9900/tms9995.cpp b/src/devices/cpu/tms9900/tms9995.cpp index c52a6c5cc39..09509f4623e 100644 --- a/src/devices/cpu/tms9900/tms9995.cpp +++ b/src/devices/cpu/tms9900/tms9995.cpp @@ -3090,6 +3090,7 @@ void tms9995_device::alu_shift() uint16_t sign = 0; uint32_t value; int count; + bool check_ov = false; switch (m_inst_state) { @@ -3138,6 +3139,7 @@ void tms9995_device::alu_shift() case SLA: carry = ((value & 0x8000)!=0); value <<= 1; + check_ov = true; if (carry != ((value&0x8000)!=0)) overflow = true; break; case SRC: @@ -3150,7 +3152,7 @@ void tms9995_device::alu_shift() m_current_value = value & 0xffff; set_status_bit(ST_C, carry); - set_status_bit(ST_OV, overflow); + if (check_ov) set_status_bit(ST_OV, overflow); // only SLA compare_and_set_lae(m_current_value, 0); m_address = m_address_saved; // Register address LOGMASKED(LOG_STATUS, "ST = %04x (val=%04x)\n", ST, m_current_value); @@ -3168,6 +3170,7 @@ void tms9995_device::alu_single_arithm() uint32_t src_val = m_current_value & 0x0000ffff; uint16_t sign = 0; bool check_ov = true; + bool check_c = true; switch (m_command) { @@ -3218,6 +3221,7 @@ void tms9995_device::alu_single_arithm() // LAE dest_new = ~src_val & 0xffff; check_ov = false; + check_c = false; break; case NEG: // LAECO @@ -3245,7 +3249,7 @@ void tms9995_device::alu_single_arithm() } if (check_ov) set_status_bit(ST_OV, ((src_val & 0x8000)==sign) && ((dest_new & 0x8000)!=sign)); - set_status_bit(ST_C, (dest_new & 0x10000) != 0); + if (check_c) set_status_bit(ST_C, (dest_new & 0x10000) != 0); m_current_value = dest_new & 0xffff; compare_and_set_lae(m_current_value, 0); diff --git a/src/devices/imagedev/flopdrv.cpp b/src/devices/imagedev/flopdrv.cpp index cc8f693ca84..bf42b1070ea 100644 --- a/src/devices/imagedev/flopdrv.cpp +++ b/src/devices/imagedev/flopdrv.cpp @@ -533,16 +533,6 @@ int floppy_get_drive_by_type(legacy_floppy_image_device *image,int ftype) return -1; } -int floppy_get_count(running_machine &machine) -{ - int cnt = 0; - if (machine.device<legacy_floppy_image_device>(FLOPPY_0)) cnt++; - if (machine.device<legacy_floppy_image_device>(FLOPPY_1)) cnt++; - if (machine.device<legacy_floppy_image_device>(FLOPPY_2)) cnt++; - if (machine.device<legacy_floppy_image_device>(FLOPPY_3)) cnt++; - return cnt; -} - /* drive select 0 */ WRITE_LINE_MEMBER( legacy_floppy_image_device::floppy_ds0_w ) diff --git a/src/devices/imagedev/flopdrv.h b/src/devices/imagedev/flopdrv.h index 5751365260d..97ae6a77859 100644 --- a/src/devices/imagedev/flopdrv.h +++ b/src/devices/imagedev/flopdrv.h @@ -1,7 +1,6 @@ // license:BSD-3-Clause // copyright-holders:Nathan Woods, Miodrag Milanovic /* flopdrv provides simple emulation of a disc drive */ -/* the 8271, upd765 and wd179x use this */ #ifndef MAME_DEVICES_IMAGEDV_FLOPDRV_H #define MAME_DEVICES_IMAGEDV_FLOPDRV_H @@ -251,6 +250,5 @@ protected: legacy_floppy_image_device *floppy_get_device(running_machine &machine,int drive); legacy_floppy_image_device *floppy_get_device_by_type(running_machine &machine,int ftype,int drive); int floppy_get_drive_by_type(legacy_floppy_image_device *image,int ftype); -int floppy_get_count(running_machine &machine); #endif // MAME_DEVICES_IMAGEDV_FLOPDRV_H diff --git a/src/devices/machine/68307.cpp b/src/devices/machine/68307.cpp index 3d670d40e4a..ae13e090488 100644 --- a/src/devices/machine/68307.cpp +++ b/src/devices/machine/68307.cpp @@ -90,6 +90,14 @@ void m68307_cpu_device::device_reset() set_ipl(0); } +void m68307_cpu_device::m68k_reset_peripherals() +{ + m_duart->reset(); + + if (m_m68307MBUS) m_m68307MBUS->reset(); + if (m_m68307TIMER) m_m68307TIMER->reset(); +} + /* todo: is it possible to calculate the address map based on CS when they change and install handlers? Going through this logic for every memory access is diff --git a/src/devices/machine/68307.h b/src/devices/machine/68307.h index 591d0c9cced..6d5ef10b61c 100644 --- a/src/devices/machine/68307.h +++ b/src/devices/machine/68307.h @@ -44,6 +44,8 @@ protected: virtual uint32_t execute_min_cycles() const override { return 4; } virtual uint32_t execute_max_cycles() const override { return 158; } + virtual void m68k_reset_peripherals() override; + private: void set_ipl(int level); DECLARE_WRITE_LINE_MEMBER(timer0_interrupt); diff --git a/src/devices/machine/74157.cpp b/src/devices/machine/74157.cpp index f5a68cc4465..1dc7eb1289b 100644 --- a/src/devices/machine/74157.cpp +++ b/src/devices/machine/74157.cpp @@ -35,7 +35,7 @@ DEFINE_DEVICE_TYPE(LS157_X2, ls157_x2_device, "ls157_x2", "74LS157 Quad 2-to-1 M // ls157_device - constructor //------------------------------------------------- -ls157_device::ls157_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) +ls157_device::ls157_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) : ls157_device(mconfig, LS157, tag, owner, clock, 0x0f) { } @@ -58,7 +58,7 @@ ls157_device::ls157_device(const machine_config &mconfig, device_type type, cons // ls157_x2_device - constructor //------------------------------------------------- -ls157_x2_device::ls157_x2_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) +ls157_x2_device::ls157_x2_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) : ls157_device(mconfig, LS157_X2, tag, owner, clock, 0xff) { } @@ -92,7 +92,7 @@ void ls157_device::device_start() // a_w -- write nibble to A1-A4 //------------------------------------------------- -void ls157_device::write_a(u8 data) +void ls157_device::a_w(u8 data) { m_a = data & m_data_mask; update_output(); @@ -103,7 +103,7 @@ void ls157_device::write_a(u8 data) // b_w -- write nibble to B1-B4 //------------------------------------------------- -void ls157_device::write_b(u8 data) +void ls157_device::b_w(u8 data) { m_b = data & m_data_mask; update_output(); @@ -115,7 +115,7 @@ void ls157_device::write_b(u8 data) // low nibble to B1-B4 //------------------------------------------------- -void ls157_device::write_ab(u8 data) +void ls157_device::ab_w(u8 data) { assert(m_data_mask == 0x0f); m_a = data >> 4; @@ -129,7 +129,7 @@ void ls157_device::write_ab(u8 data) // low nibble to A1-A4 //------------------------------------------------- -void ls157_device::write_ba(u8 data) +void ls157_device::ba_w(u8 data) { assert(m_data_mask == 0x0f); m_b = data >> 4; @@ -143,7 +143,7 @@ void ls157_device::write_ba(u8 data) // A1-A4 and write odd-numbered bits to B1-B4 //------------------------------------------------- -void ls157_device::write_interleave(u8 data) +void ls157_device::interleave_w(u8 data) { assert(m_data_mask == 0x0f); m_b = bitswap<4>(data, 7, 5, 3, 1); @@ -260,7 +260,7 @@ void ls157_device::update_output() // DATA OUTPUTS //************************************************************************** -READ8_MEMBER(ls157_device::output_r) +u8 ls157_device::output_r() { if (m_strobe) return 0; @@ -277,7 +277,7 @@ READ8_MEMBER(ls157_device::output_r) DEFINE_DEVICE_TYPE(HC157, hc157_device, "hc157", "74HC157 Quad 2-to-1 Multiplexer") -hc157_device::hc157_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) +hc157_device::hc157_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) : ls157_device(mconfig, HC157, tag, owner, clock, 0x0f) { } @@ -289,7 +289,7 @@ hc157_device::hc157_device(const machine_config &mconfig, const char *tag, devic DEFINE_DEVICE_TYPE(HCT157, hct157_device, "hct157", "74HCT157 Quad 2-to-1 Multiplexer") -hct157_device::hct157_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) +hct157_device::hct157_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) : ls157_device(mconfig, HCT157, tag, owner, clock, 0x0f) { } diff --git a/src/devices/machine/74157.h b/src/devices/machine/74157.h index 4bd4685546c..52875cc0a76 100644 --- a/src/devices/machine/74157.h +++ b/src/devices/machine/74157.h @@ -42,16 +42,11 @@ public: auto out_callback() { return m_out_cb.bind(); } // data writes - DECLARE_WRITE8_MEMBER(a_w) { write_a(data); } - void write_a(u8 data); - DECLARE_WRITE8_MEMBER(b_w) { write_b(data); } - void write_b(u8 data); - DECLARE_WRITE8_MEMBER(ab_w) { write_ab(data); } - void write_ab(u8 data); - DECLARE_WRITE8_MEMBER(ba_w) { write_ba(data); } - void write_ba(u8 data); - DECLARE_WRITE8_MEMBER(interleave_w) { write_interleave(data); } - void write_interleave(u8 data); + void a_w(u8 data); + void b_w(u8 data); + void ab_w(u8 data); + void ba_w(u8 data); + void interleave_w(u8 data); // data line writes DECLARE_WRITE_LINE_MEMBER(a0_w); @@ -68,7 +63,7 @@ public: DECLARE_WRITE_LINE_MEMBER(strobe_w); // output read - DECLARE_READ8_MEMBER(output_r); + u8 output_r(); protected: ls157_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, u8 mask); diff --git a/src/devices/machine/aic6250.cpp b/src/devices/machine/aic6250.cpp index 769968569c8..adf90fe99b5 100644 --- a/src/devices/machine/aic6250.cpp +++ b/src/devices/machine/aic6250.cpp @@ -41,13 +41,14 @@ #include "logmacro.h" -DEFINE_DEVICE_TYPE(AIC6250, aic6250_device, "aic6250", "Adaptec 6250 High-Performance SCSI Protocol Chip") +DEFINE_DEVICE_TYPE(AIC6250, aic6250_device, "aic6250", "Adaptec AIC-6250 High-Performance SCSI Protocol Chip") +DEFINE_DEVICE_TYPE(AIC6251A, aic6251a_device, "aic6251a", "Adaptec AIC-6251A Fast SCSI Protocol Chip") static char const *const nscsi_phase[] = { "DATA OUT", "DATA IN", "COMMAND", "STATUS", "*", "*", "MESSAGE OUT", "MESSAGE IN" }; static char const *const aic6250_phase[] = { "DATA OUT", "*", "DATA IN", "*", "COMMAND", "MESSAGE OUT", "STATUS", "MESSAGE IN" }; -aic6250_device::aic6250_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : nscsi_device(mconfig, AIC6250, tag, owner, clock) +aic6250_device::aic6250_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) + : nscsi_device(mconfig, type, tag, owner, clock) , m_int_cb(*this) , m_breq_cb(*this) , m_port_a_r_cb(*this) @@ -57,6 +58,16 @@ aic6250_device::aic6250_device(const machine_config &mconfig, const char *tag, d { } +aic6250_device::aic6250_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : aic6250_device(mconfig, AIC6250, tag, owner, clock) +{ +} + +aic6251a_device::aic6251a_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : aic6250_device(mconfig, AIC6251A, tag, owner, clock) +{ +} + void aic6250_device::map(address_map &map) { map(0x0, 0x0).rw(FUNC(aic6250_device::dma_count_l_r), FUNC(aic6250_device::dma_count_l_w)); diff --git a/src/devices/machine/aic6250.h b/src/devices/machine/aic6250.h index 6dce153ca65..2a4ba02d118 100644 --- a/src/devices/machine/aic6250.h +++ b/src/devices/machine/aic6250.h @@ -34,6 +34,8 @@ public: void dma16_w(u16 data); protected: + aic6250_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock); + // standard device_interface overrides virtual void device_start() override; virtual void device_reset() override; @@ -277,6 +279,13 @@ private: util::fifo <u8, 8> m_fifo; }; +class aic6251a_device : public aic6250_device +{ +public: + aic6251a_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); +}; + DECLARE_DEVICE_TYPE(AIC6250, aic6250_device) +DECLARE_DEVICE_TYPE(AIC6251A, aic6251a_device) #endif // MAME_MACHINE_AIC6250_H diff --git a/src/devices/machine/f3853.cpp b/src/devices/machine/f3853.cpp index 45511f334ab..26b06b858db 100644 --- a/src/devices/machine/f3853.cpp +++ b/src/devices/machine/f3853.cpp @@ -106,8 +106,9 @@ void f3851_device::device_resolve_objects() void f3853_device::device_start() { // lookup table for 3851/3853 lfsr timer + m_value_to_cycle[0xff] = 0xff; uint8_t reg = 0xfe; // Known to get 0xfe after 255 cycles - for(int i = reg; i >= 0; i--) + for (int i = reg; i >= 0; i--) { m_value_to_cycle[reg] = i; reg = reg << 1 | (BIT(reg,7) ^ BIT(reg,5) ^ BIT(reg,4) ^ BIT(reg,3) ^ 1); @@ -189,25 +190,27 @@ IRQ_CALLBACK_MEMBER(f3853_device::int_acknowledge) void f3853_device::timer_start(uint8_t value) { - attotime period = (value != 0xff) ? attotime::from_hz(clock()) * (m_value_to_cycle[value] * m_prescaler) : attotime::never; + attotime period = (value != 0xff) ? attotime::from_hz(clock()) * (m_prescaler * m_value_to_cycle[value]) : attotime::never; m_timer->adjust(period); } TIMER_CALLBACK_MEMBER(f3853_device::timer_callback) { - if(m_timer_int_enable) + if (m_timer_int_enable) { m_request_flipflop = true; set_interrupt_request_line(); } - timer_start(0xfe); + + // next timeout after 255 timer counts (prescaler doesn't reset) + m_timer->adjust(attotime::from_hz(clock()) * (m_prescaler * 0xff)); } WRITE_LINE_MEMBER(f3853_device::ext_int_w) { - if(m_external_interrupt_line && !state && m_external_int_enable) + if (m_external_interrupt_line && !state && m_external_int_enable) { m_request_flipflop = true; } diff --git a/src/devices/machine/f3853.h b/src/devices/machine/f3853.h index b880f56e9bc..762f46950fb 100644 --- a/src/devices/machine/f3853.h +++ b/src/devices/machine/f3853.h @@ -59,7 +59,7 @@ _I/O B0 20 |_____________| 21 DB0 F38T56 is internal in F3870 - note: STROBE is N/C on F3851 + note: STROBE is N/C on F3851 */ diff --git a/src/devices/machine/fdc37c665gt.cpp b/src/devices/machine/fdc37c665gt.cpp index f2df880d2e8..2f2adb42976 100644 --- a/src/devices/machine/fdc37c665gt.cpp +++ b/src/devices/machine/fdc37c665gt.cpp @@ -16,11 +16,11 @@ READ8_MEMBER(fdc37c665gt_device::read) if ((offset & 0x3f8) == 0x3f8) { - data = m_uart1->ins8250_r(space, offset & 7, mem_mask); + data = m_uart1->ins8250_r(offset & 7); } else if ((offset & 0x3f8) == 0x2f8) { - data = m_uart2->ins8250_r(space, offset & 7, mem_mask); + data = m_uart2->ins8250_r(offset & 7); } else { @@ -33,11 +33,11 @@ WRITE8_MEMBER(fdc37c665gt_device::write) { if ((offset & 0x3f8) == 0x3f8) { - m_uart1->ins8250_w(space, offset & 7, data, mem_mask); + m_uart1->ins8250_w(offset & 7, data); } else if ((offset & 0x3f8) == 0x2f8) { - m_uart2->ins8250_w(space, offset & 7, data, mem_mask); + m_uart2->ins8250_w(offset & 7, data); } else { diff --git a/src/devices/machine/fdc37c93x.cpp b/src/devices/machine/fdc37c93x.cpp index 8ff5afc76d4..0d5b80f2d7d 100644 --- a/src/devices/machine/fdc37c93x.cpp +++ b/src/devices/machine/fdc37c93x.cpp @@ -581,12 +581,12 @@ void fdc37c93x_device::map_serial1(address_map &map) READ8_MEMBER(fdc37c93x_device::serial1_read) { - return pc_serial1_comdev->ins8250_r(space, offset, mem_mask); + return pc_serial1_comdev->ins8250_r(offset); } WRITE8_MEMBER(fdc37c93x_device::serial1_write) { - pc_serial1_comdev->ins8250_w(space, offset, data, mem_mask); + pc_serial1_comdev->ins8250_w(offset, data); } void fdc37c93x_device::map_serial1_addresses() @@ -610,12 +610,12 @@ void fdc37c93x_device::map_serial2(address_map &map) READ8_MEMBER(fdc37c93x_device::serial2_read) { - return pc_serial2_comdev->ins8250_r(space, offset, mem_mask); + return pc_serial2_comdev->ins8250_r(offset); } WRITE8_MEMBER(fdc37c93x_device::serial2_write) { - pc_serial2_comdev->ins8250_w(space, offset, data, mem_mask); + pc_serial2_comdev->ins8250_w(offset, data); } void fdc37c93x_device::map_serial2_addresses() diff --git a/src/devices/machine/gen_latch.cpp b/src/devices/machine/gen_latch.cpp index 7f1b382e0ab..b96d39a14be 100644 --- a/src/devices/machine/gen_latch.cpp +++ b/src/devices/machine/gen_latch.cpp @@ -2,7 +2,7 @@ // copyright-holders:Miodrag Milanovic /*************************************************************************** - Generic 8bit and 16 bit latch devices + Generic 8 bit and 16 bit latch devices ***************************************************************************/ @@ -89,14 +89,14 @@ void generic_latch_base_device::set_latch_written(bool latch_written) } } -READ8_MEMBER(generic_latch_base_device::acknowledge_r) +u8 generic_latch_base_device::acknowledge_r(address_space &space) { if (!machine().side_effects_disabled()) set_latch_written(false); return space.unmap(); } -WRITE8_MEMBER(generic_latch_base_device::acknowledge_w) +void generic_latch_base_device::acknowledge_w(u8 data) { set_latch_written(false); } @@ -111,24 +111,24 @@ generic_latch_8_device::generic_latch_8_device(const machine_config &mconfig, co { } -READ8_MEMBER( generic_latch_8_device::read ) +u8 generic_latch_8_device::read() { if (!has_separate_acknowledge() && !machine().side_effects_disabled()) set_latch_written(false); return m_latched_value; } -WRITE8_MEMBER( generic_latch_8_device::write ) +void generic_latch_8_device::write(u8 data) { machine().scheduler().synchronize(timer_expired_delegate(FUNC(generic_latch_8_device::sync_callback), this), data); } -WRITE8_MEMBER( generic_latch_8_device::preset_w ) +void generic_latch_8_device::preset_w(u8 data) { - m_latched_value = 0xff; + m_latched_value = data; } -WRITE8_MEMBER( generic_latch_8_device::clear_w ) +void generic_latch_8_device::clear_w(u8 data) { m_latched_value = 0x00; } @@ -182,24 +182,24 @@ generic_latch_16_device::generic_latch_16_device(const machine_config &mconfig, { } -READ16_MEMBER( generic_latch_16_device::read ) +u16 generic_latch_16_device::read() { if (!has_separate_acknowledge() && !machine().side_effects_disabled()) set_latch_written(false); return m_latched_value; } -WRITE16_MEMBER( generic_latch_16_device::write ) +void generic_latch_16_device::write(u16 data) { machine().scheduler().synchronize(timer_expired_delegate(FUNC(generic_latch_16_device::sync_callback), this), data); } -WRITE16_MEMBER( generic_latch_16_device::preset_w ) +void generic_latch_16_device::preset_w(u16 data) { - m_latched_value = 0xffff; + m_latched_value = data; } -WRITE16_MEMBER( generic_latch_16_device::clear_w ) +void generic_latch_16_device::clear_w(u16 data) { m_latched_value = 0x0000; } diff --git a/src/devices/machine/gen_latch.h b/src/devices/machine/gen_latch.h index d98bf428646..4080cbebe8d 100644 --- a/src/devices/machine/gen_latch.h +++ b/src/devices/machine/gen_latch.h @@ -2,7 +2,7 @@ // copyright-holders:Miodrag Milanovic /*************************************************************************** - Generic 8bit and 16 bit latch devices + Generic 8 bit and 16 bit latch devices ***************************************************************************/ @@ -36,8 +36,8 @@ public: DECLARE_READ_LINE_MEMBER(pending_r); - DECLARE_READ8_MEMBER( acknowledge_r ); - DECLARE_WRITE8_MEMBER( acknowledge_w ); + u8 acknowledge_r(address_space &space); + void acknowledge_w(u8 data = 0); protected: // construction/destruction @@ -67,16 +67,14 @@ public: // construction/destruction generic_latch_8_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock = 0); - DECLARE_READ8_MEMBER( read ); - DECLARE_WRITE8_MEMBER( write ); + u8 read(); + void write(u8 data); - DECLARE_WRITE8_MEMBER( preset_w ); - DECLARE_WRITE8_MEMBER( clear_w ); + void preset_w(u8 data = 0xff); + void clear_w(u8 data = 0); DECLARE_WRITE_LINE_MEMBER( preset ); DECLARE_WRITE_LINE_MEMBER( clear ); - void preset_w(u8 value) { m_latched_value = value; } - protected: virtual void device_start() override; @@ -95,16 +93,14 @@ public: // construction/destruction generic_latch_16_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock = 0); - DECLARE_READ16_MEMBER( read ); - DECLARE_WRITE16_MEMBER( write ); + u16 read(); + void write(u16 data); - DECLARE_WRITE16_MEMBER( preset_w ); - DECLARE_WRITE16_MEMBER( clear_w ); + void preset_w(u16 data = 0xffff); + void clear_w(u16 data = 0); DECLARE_WRITE_LINE_MEMBER( preset ); DECLARE_WRITE_LINE_MEMBER( clear ); - void preset_w(u16 value) { m_latched_value = value; } - protected: virtual void device_start() override; diff --git a/src/devices/machine/ins8154.cpp b/src/devices/machine/ins8154.cpp index ff1cd79906e..11943cdee2c 100644 --- a/src/devices/machine/ins8154.cpp +++ b/src/devices/machine/ins8154.cpp @@ -78,6 +78,7 @@ void ins8154_device::device_start() save_item(NAME(m_mdr)); save_item(NAME(m_odra)); save_item(NAME(m_odrb)); + save_item(NAME(m_ram)); } @@ -97,7 +98,7 @@ void ins8154_device::device_reset() } -READ8_MEMBER(ins8154_device::ins8154_r) +uint8_t ins8154_device::read_io(offs_t offset) { uint8_t val = 0xff; @@ -146,7 +147,12 @@ READ8_MEMBER(ins8154_device::ins8154_r) return val; } -WRITE8_MEMBER(ins8154_device::ins8154_porta_w) +uint8_t ins8154_device::read_ram(offs_t offset) +{ + return m_ram[offset & 0x7f]; +} + +void ins8154_device::porta_w(uint8_t data) { m_out_a = data; @@ -155,7 +161,7 @@ WRITE8_MEMBER(ins8154_device::ins8154_porta_w) m_out_a_cb(offs_t(0), (data & m_odra) | (m_odra ^ 0xff)); } -WRITE8_MEMBER(ins8154_device::ins8154_portb_w) +void ins8154_device::portb_w(uint8_t data) { LOG("%s: INS8154 Write PortB %02x with odrb: %02x\n", machine().describe_context(), data, m_odrb); m_out_b = data; @@ -165,7 +171,7 @@ WRITE8_MEMBER(ins8154_device::ins8154_portb_w) m_out_b_cb(offs_t(0), (data & m_odrb) | (m_odrb ^ 0xff)); } -WRITE8_MEMBER(ins8154_device::ins8154_w) +void ins8154_device::write_io(offs_t offset, uint8_t data) { if (offset > 0x24) { @@ -176,11 +182,11 @@ WRITE8_MEMBER(ins8154_device::ins8154_w) switch (offset) { case 0x20: - ins8154_porta_w(space, 0, data); + porta_w(data); break; case 0x21: - ins8154_portb_w(space, 0, data); + portb_w(data); break; case 0x22: @@ -205,12 +211,12 @@ WRITE8_MEMBER(ins8154_device::ins8154_w) if (offset < 0x08) { LOGBITS("%s: INS8154 Port A set bit %02x\n", machine().describe_context(), offset & 0x07); - ins8154_porta_w(space, 0, m_out_a |= (1 << (offset & 0x07))); + porta_w(m_out_a |= (1 << (offset & 0x07))); } else { LOGBITS("%s: INS8154 Port B set bit %02x\n", machine().describe_context(), offset & 0x07); - ins8154_portb_w(space, 0, m_out_b |= (1 << (offset & 0x07))); + portb_w(m_out_b |= (1 << (offset & 0x07))); } } else @@ -219,14 +225,19 @@ WRITE8_MEMBER(ins8154_device::ins8154_w) if (offset < 0x08) { LOGBITS("%s: INS8154 Port A clear bit %02x\n", machine().describe_context(), offset & 0x07); - ins8154_porta_w(space, 0, m_out_a & ~(1 << (offset & 0x07))); + porta_w(m_out_a & ~(1 << (offset & 0x07))); } else { LOGBITS("%s: INS8154 Port B clear bit %02x\n", machine().describe_context(), offset & 0x07); - ins8154_portb_w(space, 0, m_out_b & ~(1 << (offset & 0x07))); + portb_w(m_out_b & ~(1 << (offset & 0x07))); } } break; } } + +void ins8154_device::write_ram(offs_t offset, uint8_t data) +{ + m_ram[offset & 0x7f] = data; +} diff --git a/src/devices/machine/ins8154.h b/src/devices/machine/ins8154.h index 5ba94ab9cda..2ce40ec9e70 100644 --- a/src/devices/machine/ins8154.h +++ b/src/devices/machine/ins8154.h @@ -47,11 +47,13 @@ public: auto out_b() { return m_out_b_cb.bind(); } auto out_irq() { return m_out_irq_cb.bind(); } - DECLARE_READ8_MEMBER( ins8154_r ); - DECLARE_WRITE8_MEMBER( ins8154_w ); + uint8_t read_io(offs_t offset); + void write_io(offs_t offset, uint8_t data); + uint8_t read_ram(offs_t offset); + void write_ram(offs_t offset, uint8_t data); - DECLARE_WRITE8_MEMBER( ins8154_porta_w ); - DECLARE_WRITE8_MEMBER( ins8154_portb_w ); + void porta_w(uint8_t data); + void portb_w(uint8_t data); protected: // device-level overrides @@ -77,6 +79,9 @@ private: uint8_t m_mdr; /* Mode Definition Register */ uint8_t m_odra; /* Output Definition Register Port A */ uint8_t m_odrb; /* Output Definition Register Port B */ + + /* on-board RAM */ + uint8_t m_ram[0x80]; }; diff --git a/src/devices/machine/ins8250.cpp b/src/devices/machine/ins8250.cpp index d127ce0e40d..d586816c511 100644 --- a/src/devices/machine/ins8250.cpp +++ b/src/devices/machine/ins8250.cpp @@ -107,7 +107,7 @@ DEFINE_DEVICE_TYPE(NS16450, ns16450_device, "ns16450", "National Semiconductor DEFINE_DEVICE_TYPE(NS16550, ns16550_device, "ns16550", "National Semiconductor NS16550 UART") DEFINE_DEVICE_TYPE(PC16552D, pc16552_device, "pc16552d", "National Semiconductor PC16552D UART") -ins8250_uart_device::ins8250_uart_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, dev_type device_type) +ins8250_uart_device::ins8250_uart_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, dev_type device_type) : device_t(mconfig, type, tag, owner, clock) , device_serial_interface(mconfig, *this) , m_device_type(device_type) @@ -126,22 +126,22 @@ ins8250_uart_device::ins8250_uart_device(const machine_config &mconfig, device_t m_regs.ier = 0; } -ins8250_device::ins8250_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) +ins8250_device::ins8250_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) : ins8250_uart_device(mconfig, INS8250, tag, owner, clock, dev_type::INS8250) { } -ns16450_device::ns16450_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) +ns16450_device::ns16450_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) : ins8250_uart_device(mconfig, NS16450, tag, owner, clock, dev_type::NS16450) { } -ns16550_device::ns16550_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) +ns16550_device::ns16550_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) : ins8250_uart_device(mconfig, NS16550, tag, owner, clock, dev_type::NS16550) { } -pc16552_device::pc16552_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) +pc16552_device::pc16552_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) : device_t(mconfig, PC16552D, tag, owner, clock) { } @@ -159,27 +159,27 @@ void pc16552_device::device_start() #define COM_INT_PENDING_MODEM_STATUS_REGISTER 0x0008 #define COM_INT_PENDING_CHAR_TIMEOUT 0x0011 -static constexpr uint8_t INS8250_LSR_TSRE = 0x40; -static constexpr uint8_t INS8250_LSR_THRE = 0x20; -static constexpr uint8_t INS8250_LSR_BI = 0x10; -static constexpr uint8_t INS8250_LSR_FE = 0x08; -static constexpr uint8_t INS8250_LSR_PE = 0x04; -static constexpr uint8_t INS8250_LSR_OE = 0x02; -static constexpr uint8_t INS8250_LSR_DR = 0x01; - -static constexpr uint8_t INS8250_MCR_DTR = 0x01; -static constexpr uint8_t INS8250_MCR_RTS = 0x02; -static constexpr uint8_t INS8250_MCR_OUT1 = 0x04; -static constexpr uint8_t INS8250_MCR_OUT2 = 0x08; -static constexpr uint8_t INS8250_MCR_LOOPBACK = 0x10; - -static constexpr uint8_t INS8250_LCR_BITCOUNT_MASK= 0x03; -static constexpr uint8_t INS8250_LCR_2STOP_BITS = 0x04; -//static constexpr uint8_t INS8250_LCR_PEN = 0x08; -//static constexpr uint8_t INS8250_LCR_EVEN_PAR = 0x10; -//static constexpr uint8_t INS8250_LCR_PARITY = 0x20; -//static constexpr uint8_t INS8250_LCR_BREAK = 0x40; -static constexpr uint8_t INS8250_LCR_DLAB = 0x80; +static constexpr u8 INS8250_LSR_TSRE = 0x40; +static constexpr u8 INS8250_LSR_THRE = 0x20; +static constexpr u8 INS8250_LSR_BI = 0x10; +static constexpr u8 INS8250_LSR_FE = 0x08; +static constexpr u8 INS8250_LSR_PE = 0x04; +static constexpr u8 INS8250_LSR_OE = 0x02; +static constexpr u8 INS8250_LSR_DR = 0x01; + +static constexpr u8 INS8250_MCR_DTR = 0x01; +static constexpr u8 INS8250_MCR_RTS = 0x02; +static constexpr u8 INS8250_MCR_OUT1 = 0x04; +static constexpr u8 INS8250_MCR_OUT2 = 0x08; +static constexpr u8 INS8250_MCR_LOOPBACK = 0x10; + +static constexpr u8 INS8250_LCR_BITCOUNT_MASK= 0x03; +static constexpr u8 INS8250_LCR_2STOP_BITS = 0x04; +//static constexpr u8 INS8250_LCR_PEN = 0x08; +//static constexpr u8 INS8250_LCR_EVEN_PAR = 0x10; +//static constexpr u8 INS8250_LCR_PARITY = 0x20; +//static constexpr u8 INS8250_LCR_BREAK = 0x40; +static constexpr u8 INS8250_LCR_DLAB = 0x80; /* ints will continue to be set for as long as there are ints pending */ void ins8250_uart_device::update_interrupt() @@ -257,7 +257,7 @@ void ins8250_uart_device::update_baud_rate() tra_complete(); } -WRITE8_MEMBER( ins8250_uart_device::ins8250_w ) +void ins8250_uart_device::ins8250_w(offs_t offset, u8 data) { int tmp; @@ -399,7 +399,7 @@ WRITE8_MEMBER( ins8250_uart_device::ins8250_w ) } } -READ8_MEMBER( ins8250_uart_device::ins8250_r ) +u8 ins8250_uart_device::ins8250_r(offs_t offset) { int data = 0x0ff; @@ -484,7 +484,7 @@ void ns16550_device::rcv_complete() return; } - uint8_t errors = 0; + u8 errors = 0; if (is_receive_framing_error()) errors |= INS8250_LSR_FE; if (is_receive_parity_error()) @@ -578,7 +578,7 @@ void ins8250_uart_device::tra_callback() void ins8250_uart_device::update_msr() { - uint8_t data; + u8 data; int change; if (m_regs.mcr & INS8250_MCR_LOOPBACK) @@ -720,15 +720,15 @@ void ns16550_device::device_timer(emu_timer &timer, device_timer_id id, int para } } -void ns16550_device::push_tx(uint8_t data) +void ns16550_device::push_tx(u8 data) { m_tfifo[m_thead] = data; ++m_thead &= 0x0f; } -uint8_t ns16550_device::pop_rx() +u8 ns16550_device::pop_rx() { - uint8_t data = m_rfifo[m_rtail]; + u8 data = m_rfifo[m_rtail]; clear_int(COM_INT_PENDING_CHAR_TIMEOUT & ~1); // don't clear bit 1 yet if(m_rnum) @@ -758,7 +758,7 @@ uint8_t ns16550_device::pop_rx() return data; } -void ns16550_device::set_fcr(uint8_t data) +void ns16550_device::set_fcr(u8 data) { const int bytes_per_int[] = {1, 4, 8, 14}; if(!(data & 1)) diff --git a/src/devices/machine/ins8250.h b/src/devices/machine/ins8250.h index 3047b8d6c05..5f9a6bd1793 100644 --- a/src/devices/machine/ins8250.h +++ b/src/devices/machine/ins8250.h @@ -27,8 +27,8 @@ public: auto out_out1_callback() { return m_out_out1_cb.bind(); } auto out_out2_callback() { return m_out_out2_cb.bind(); } - DECLARE_WRITE8_MEMBER(ins8250_w); - DECLARE_READ8_MEMBER(ins8250_r); + void ins8250_w(offs_t offset, u8 data); + u8 ins8250_r(offs_t offset); DECLARE_WRITE_LINE_MEMBER(dcd_w); DECLARE_WRITE_LINE_MEMBER(dsr_w); @@ -46,7 +46,7 @@ protected: NS16550A }; - ins8250_uart_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, dev_type device_type); + ins8250_uart_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, dev_type device_type); virtual void device_start() override; virtual void device_reset() override; @@ -54,9 +54,9 @@ protected: virtual void tra_complete() override; virtual void tra_callback() override; - virtual void set_fcr(uint8_t data) { } - virtual void push_tx(uint8_t data) { } - virtual uint8_t pop_rx() { return 0; } + virtual void set_fcr(u8 data) { } + virtual void push_tx(u8 data) { } + virtual u8 pop_rx() { return 0; } void trigger_int(int flag); void clear_int(int flag); @@ -65,20 +65,20 @@ protected: const dev_type m_device_type; struct { - uint8_t thr; /* 0 -W transmitter holding register */ - uint8_t rbr; /* 0 R- receiver buffer register */ - uint8_t ier; /* 1 RW interrupt enable register */ - uint16_t dl; /* 0/1 RW divisor latch (if DLAB = 1) */ - uint8_t iir; /* 2 R- interrupt identification register */ - uint8_t fcr; - uint8_t lcr; /* 3 RW line control register (bit 7: DLAB) */ - uint8_t mcr; /* 4 RW modem control register */ - uint8_t lsr; /* 5 R- line status register */ - uint8_t msr; /* 6 R- modem status register */ - uint8_t scr; /* 7 RW scratch register */ + u8 thr; /* 0 -W transmitter holding register */ + u8 rbr; /* 0 R- receiver buffer register */ + u8 ier; /* 1 RW interrupt enable register */ + u16 dl; /* 0/1 RW divisor latch (if DLAB = 1) */ + u8 iir; /* 2 R- interrupt identification register */ + u8 fcr; + u8 lcr; /* 3 RW line control register (bit 7: DLAB) */ + u8 mcr; /* 4 RW modem control register */ + u8 lsr; /* 5 R- line status register */ + u8 msr; /* 6 R- modem status register */ + u8 scr; /* 7 RW scratch register */ } m_regs; private: - uint8_t m_int_pending; + u8 m_int_pending; devcb_write_line m_out_tx_cb; devcb_write_line m_out_dtr_cb; @@ -101,34 +101,34 @@ private: class ins8250_device : public ins8250_uart_device { public: - ins8250_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + ins8250_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); }; class ns16450_device : public ins8250_uart_device { public: - ns16450_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + ns16450_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); }; class ns16550_device : public ins8250_uart_device { public: - ns16550_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + ns16550_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); protected: virtual void device_start() override; virtual void device_reset() override; virtual void rcv_complete() override; virtual void tra_complete() override; virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override; - virtual void set_fcr(uint8_t data) override; - virtual void push_tx(uint8_t data) override; - virtual uint8_t pop_rx() override; + virtual void set_fcr(u8 data) override; + virtual void push_tx(u8 data) override; + virtual u8 pop_rx() override; private: void set_timer() { m_timeout->adjust(attotime::from_hz((clock()*4*8)/(m_regs.dl*16))); } int m_rintlvl; - uint8_t m_rfifo[16]; - uint8_t m_efifo[16]; - uint8_t m_tfifo[16]; + u8 m_rfifo[16]; + u8 m_efifo[16]; + u8 m_tfifo[16]; int m_rhead, m_rtail, m_rnum; int m_thead, m_ttail; emu_timer *m_timeout; @@ -137,10 +137,10 @@ private: class pc16552_device : public device_t { public: - pc16552_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + pc16552_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); - DECLARE_READ8_MEMBER(read) { return ((offset & 8) ? m_chan1 : m_chan0)->ins8250_r(space, offset & 7, mem_mask); } - DECLARE_WRITE8_MEMBER(write) { ((offset & 8) ? m_chan1 : m_chan0)->ins8250_w(space, offset & 7, data, mem_mask); } + u8 read(offs_t offset) { return ((offset & 8) ? m_chan1 : m_chan0)->ins8250_r(offset & 7); } + void write(offs_t offset, u8 data) { ((offset & 8) ? m_chan1 : m_chan0)->ins8250_w(offset & 7, data); } protected: virtual void device_start() override; diff --git a/src/devices/machine/nscsi_cd.cpp b/src/devices/machine/nscsi_cd.cpp index 0446c600e9f..b58a179161a 100644 --- a/src/devices/machine/nscsi_cd.cpp +++ b/src/devices/machine/nscsi_cd.cpp @@ -378,6 +378,22 @@ void nscsi_cdrom_device::scsi_command() scsi_cmdbuf[pos++] = 0x00; // Double meh break; + case 0x01: // Read-write error recovery + scsi_cmdbuf[pos++] = 0x01; // PS, page id + scsi_cmdbuf[pos++] = 0x0a; // Page length + scsi_cmdbuf[pos++] = 0x01; + scsi_cmdbuf[pos++] = 0x01; + scsi_cmdbuf[pos++] = 0x00; + scsi_cmdbuf[pos++] = 0x00; + scsi_cmdbuf[pos++] = 0x00; + scsi_cmdbuf[pos++] = 0x00; + scsi_cmdbuf[pos++] = 0x00; + scsi_cmdbuf[pos++] = 0x00; + scsi_cmdbuf[pos++] = 0x00; + scsi_cmdbuf[pos++] = 0x00; + scsi_cmdbuf[pos++] = 0x00; + break; + case 0x02: // Disconnect/reconnect control parameters (guessed) scsi_cmdbuf[pos++] = 0x82; // PS, page id scsi_cmdbuf[pos++] = 0x0e; // Page length diff --git a/src/devices/machine/spg110.cpp b/src/devices/machine/spg110.cpp index df614deb314..060ae511f0c 100644 --- a/src/devices/machine/spg110.cpp +++ b/src/devices/machine/spg110.cpp @@ -17,352 +17,61 @@ DEFINE_DEVICE_TYPE(SPG110, spg110_device, "spg110", "SPG110 System-on-a-Chip") spg110_device::spg110_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) - : device_t(mconfig, type, tag, owner, clock), - device_memory_interface(mconfig, *this), - m_space_config("spg110", ENDIANNESS_BIG, 16, 32, 0, address_map_constructor(FUNC(spg110_device::map_video), this)), - m_cpu(*this, finder_base::DUMMY_TAG), - m_palette(*this, "palette"), - m_gfxdecode(*this, "gfxdecode"), - m_palram(*this, "palram") + : device_t(mconfig, type, tag, owner, clock) + , m_cpu(*this, finder_base::DUMMY_TAG) + , m_screen(*this, finder_base::DUMMY_TAG) + , m_spg_io(*this, "spg_io") + , m_spg_video(*this, "spg_video") + , m_porta_out(*this) + , m_portb_out(*this) + , m_portc_out(*this) + , m_porta_in(*this) + , m_portb_in(*this) + , m_portc_in(*this) + , m_adc_in{{*this}, {*this}} + , m_chip_sel(*this) { } -template<spg110_device::flipx_t FlipX> -void spg110_device::blit(const rectangle &cliprect, uint32_t line, uint32_t xoff, uint32_t yoff, uint32_t attr, uint32_t ctrl, uint32_t bitmap_addr, uint16_t tile) -{ - address_space &space = m_cpu->space(AS_PROGRAM); - - int32_t h = 8 << ((attr & PAGE_TILE_HEIGHT_MASK) >> PAGE_TILE_HEIGHT_SHIFT); - int32_t w = 8 << ((attr & PAGE_TILE_WIDTH_MASK) >> PAGE_TILE_WIDTH_SHIFT); - - uint32_t yflipmask = attr & TILE_Y_FLIP ? h - 1 : 0; - - uint32_t nc = ((attr & 0x0003) + 1) << 1; - - uint32_t palette_offset = (attr & 0x0f00) >> 4; - - palette_offset >>= nc; - palette_offset <<= nc; - - uint32_t bits_per_row = nc * w / 16; - uint32_t words_per_tile = bits_per_row * h; - uint32_t m = bitmap_addr + words_per_tile * tile + bits_per_row * (line ^ yflipmask); - uint32_t bits = 0; - uint32_t nbits = 0; - uint32_t y = line; - - int yy = (yoff + y) & 0x1ff; - if (yy >= 0x01c0) - yy -= 0x0200; - - if (yy > 240 || yy < 0) - return; - - int y_index = yy * 320; - - for (int32_t x = FlipX ? (w - 1) : 0; FlipX ? x >= 0 : x < w; FlipX ? x-- : x++) - { - int xx = xoff + x; - - bits <<= nc; - - if (nbits < nc) - { - uint16_t b = space.read_word(m++ & 0x3fffff); - //b = (b << 8) | (b >> 8); - bits |= b << (nc - nbits); - nbits += 16; - } - nbits -= nc; - - uint32_t pal = palette_offset + (bits >> 16); - bits &= 0xffff; - - xx &= 0x01ff; - if (xx >= 0x01c0) - xx -= 0x0200; - - if (xx >= 0 && xx < 320) - { - // TODO, this is completely wrong for this palette system - int pix_index = xx + y_index; - uint16_t rawpal = m_palram[pal]; - const pen_t *pens = m_palette->pens(); - uint32_t paldata = pens[pal]; - - if (!(rawpal & 0x8000)) - { - m_screenbuf[pix_index] = paldata; - } - } - } -} - -void spg110_device::blit_page(const rectangle &cliprect, uint32_t scanline, int depth, uint32_t bitmap_addr, uint16_t *regs) -{ - uint32_t xscroll = regs[0]; - uint32_t yscroll = regs[1]; - uint32_t attr = regs[2]; - uint32_t ctrl = regs[3]; - uint32_t tilemap = regs[4]; - uint32_t palette_map = regs[5]; - address_space &space2 = this->space(0); - - if (!(ctrl & PAGE_ENABLE_MASK)) - { - return; - } - - if (((attr & PAGE_DEPTH_FLAG_MASK) >> PAGE_DEPTH_FLAG_SHIFT) != depth) - { - return; - } - - uint32_t tile_h = 8 << ((attr & PAGE_TILE_HEIGHT_MASK) >> PAGE_TILE_HEIGHT_SHIFT); - uint32_t tile_w = 8 << ((attr & PAGE_TILE_WIDTH_MASK) >> PAGE_TILE_WIDTH_SHIFT); - - uint32_t tile_count_x = 512 / tile_w; - - uint32_t bitmap_y = (scanline + yscroll) & 0xff; - uint32_t y0 = bitmap_y / tile_h; - uint32_t tile_scanline = bitmap_y % tile_h; - uint32_t tile_address = tile_count_x * y0; - - for (uint32_t x0 = 0; x0 < tile_count_x; x0++, tile_address++) - { - uint32_t yy = ((tile_h * y0 - yscroll + 0x10) & 0xff) - 0x10; - uint32_t xx = (tile_w * x0 - xscroll) & 0x1ff; - uint16_t tile = (ctrl & PAGE_WALLPAPER_MASK) ? space2.read_word(tilemap*2) : space2.read_word((tilemap + tile_address)*2); - uint16_t palette = 0; - - if (!tile) - continue; - - palette = space2.read_word(palette_map + tile_address / 2); - if (x0 & 1) - palette = (palette & 0xff00) >> 8; - else - palette = (palette & 0x00ff); - - - bool flip_x = 0;//(tileattr & TILE_X_FLIP); - - if (flip_x) - blit<FlipXOn>(cliprect, tile_scanline, xx, yy, attr, ctrl, bitmap_addr, tile); - else - blit<FlipXOff>(cliprect, tile_scanline, xx, yy, attr, ctrl, bitmap_addr, tile); - - } -} - - -/* correct, 4bpp gfxs */ -static const gfx_layout charlayout = -{ - 8,8, - RGN_FRAC(1,1), - 4, - { STEP4(0,1) }, - { 0*4,1*4,2*4,3*4,4*4,5*4,6*4,7*4 }, - { STEP8(0,4*8) }, - 8*8*4 -}; - -static const gfx_layout charlayout6 = -{ - 8,8, - RGN_FRAC(1,1), - 6, - { 0,1,2,3,4,5 }, - { STEP8(0,6) }, - { STEP8(0,6*8) }, - 8*8*6 -}; - -static const gfx_layout char16layout = -{ - 16,16, - RGN_FRAC(1,1), - 4, - { STEP4(0,1) }, - { 0*4,1*4,2*4,3*4,4*4,5*4,6*4,7*4, 8*4,9*4,10*4,11*4,12*4,13*4,14*4,15*4 }, - { STEP16(0,4*16) }, - 16*16*4 -}; - -static const gfx_layout char32layout = -{ - 32,32, - RGN_FRAC(1,1), - 4, - { STEP4(0,1) }, - { STEP32(0,4) }, - { STEP32(0,4*32) }, - 32*32*4 -}; - - - -static GFXDECODE_START( gfx ) - GFXDECODE_ENTRY( ":maincpu", 0, charlayout, 0, 16 ) - GFXDECODE_ENTRY( ":maincpu", 0, char16layout, 0, 16 ) - GFXDECODE_ENTRY( ":maincpu", 0, char32layout, 0, 16 ) - GFXDECODE_ENTRY( ":maincpu", 0, charlayout6, 0, 16 ) // correct for lots of the tiles inc. startup text -GFXDECODE_END - - - -void spg110_device::device_add_mconfig(machine_config &config) -{ -// PALETTE(config, m_palette).set_format(palette_device::xRGB_555, 0x100); -// PALETTE(config, m_palette).set_format(palette_device::RGB_565, 0x100); -// PALETTE(config, m_palette).set_format(palette_device::IRGB_4444, 0x100); -// PALETTE(config, m_palette).set_format(palette_device::RGBI_4444, 0x100); -// PALETTE(config, m_palette).set_format(palette_device::xRGB_555, 0x100); - PALETTE(config, m_palette, palette_device::BLACK, 256); - - GFXDECODE(config, m_gfxdecode, m_palette, gfx); -} - - -device_memory_interface::space_config_vector spg110_device::memory_space_config() const -{ - return space_config_vector { - std::make_pair(0, &m_space_config) - }; -} spg110_device::spg110_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : spg110_device(mconfig, SPG110, tag, owner, clock) { } -// irq source or similar? -READ16_MEMBER(spg110_device::spg110_2063_r) -{ - // checks for bits 0x20 and 0x08 in the IRQ function (all IRQs point to the same place) - return 0x0008; -} - -WRITE16_MEMBER(spg110_device::spg110_2063_w) +WRITE_LINE_MEMBER(spg110_device::videoirq_w) { - // writes 0x28, probably clears the IRQ / IRQ sources? 0x63 is the same offset for this in spg2xx but bits used seem to be different - m_cpu->set_state_unsynced(UNSP_IRQ0_LINE, CLEAR_LINE); + m_cpu->set_state_unsynced(UNSP_IRQ0_LINE, state); } -READ16_MEMBER(spg110_device::datasegment_r) +void spg110_device::configure_spg_io(spg2xx_io_device* io) { - uint16_t val = m_cpu->get_ds(); - return val; + io->porta_in().set(FUNC(spg110_device::porta_r)); + io->portb_in().set(FUNC(spg110_device::portb_r)); + io->portc_in().set(FUNC(spg110_device::portc_r)); + io->porta_out().set(FUNC(spg110_device::porta_w)); + io->portb_out().set(FUNC(spg110_device::portb_w)); + io->portc_out().set(FUNC(spg110_device::portc_w)); + io->adc_in<0>().set(FUNC(spg110_device::adc_r<0>)); + io->adc_in<1>().set(FUNC(spg110_device::adc_r<1>)); + io->chip_select().set(FUNC(spg110_device::cs_w)); +// io->pal_read_callback().set(FUNC(spg110_device::get_pal_r)); +// io->write_timer_irq_callback().set(FUNC(spg110_device::timerirq_w)); +// io->write_uart_adc_irq_callback().set(FUNC(spg110_device::uartirq_w)); +// io->write_external_irq_callback().set(FUNC(spg110_device::extirq_w)); +// io->write_ffrq_tmr1_irq_callback().set(FUNC(spg110_device::ffreq1_w)); +// io->write_ffrq_tmr2_irq_callback().set(FUNC(spg110_device::ffreq2_w)); } -WRITE16_MEMBER(spg110_device::datasegment_w) +void spg110_device::device_add_mconfig(machine_config &config) { - m_cpu->set_ds(data & 0x3f); -} + SPG24X_IO(config, m_spg_io, DERIVED_CLOCK(1, 1), m_cpu, m_screen); + configure_spg_io(m_spg_io); -WRITE16_MEMBER(spg110_device::spg110_3221_w) -{ - /* first write on startup? */ + SPG110_VIDEO(config, m_spg_video, DERIVED_CLOCK(1, 1), m_cpu, m_screen); + m_spg_video->write_video_irq_callback().set(FUNC(spg110_device::videoirq_w)); } -WRITE16_MEMBER(spg110_device::spg110_3223_w) { } -WRITE16_MEMBER(spg110_device::spg110_3225_w) { } - - -WRITE16_MEMBER(spg110_device::spg110_201c_w) { } -WRITE16_MEMBER(spg110_device::spg110_2020_w) { } -WRITE16_MEMBER(spg110_device::spg110_2042_w) { } -WRITE16_MEMBER(spg110_device::spg110_2031_w) { } -WRITE16_MEMBER(spg110_device::spg110_2032_w) { } -WRITE16_MEMBER(spg110_device::spg110_2033_w) { } -WRITE16_MEMBER(spg110_device::spg110_2034_w) { } -WRITE16_MEMBER(spg110_device::spg110_2035_w) { } -WRITE16_MEMBER(spg110_device::spg110_2036_w) { COMBINE_DATA(&m_2036_scroll); } -WRITE16_MEMBER(spg110_device::spg110_2039_w) { } -WRITE16_MEMBER(spg110_device::spg110_2037_w) { } -WRITE16_MEMBER(spg110_device::spg110_203c_w) { } -WRITE16_MEMBER(spg110_device::spg110_203d_w) { } -WRITE16_MEMBER(spg110_device::spg110_2045_w) { } - - -WRITE16_MEMBER(spg110_device::spg110_2028_w) { } -WRITE16_MEMBER(spg110_device::spg110_2029_w) { } - -READ16_MEMBER(spg110_device::spg110_2028_r) { return 0x0000; } -READ16_MEMBER(spg110_device::spg110_2029_r) { return 0x0000; } - - -WRITE16_MEMBER(spg110_device::spg110_2050_w) { } -WRITE16_MEMBER(spg110_device::spg110_2051_w) { } -WRITE16_MEMBER(spg110_device::spg110_2052_w) { } -WRITE16_MEMBER(spg110_device::spg110_2053_w) { } -WRITE16_MEMBER(spg110_device::spg110_2054_w) { } -WRITE16_MEMBER(spg110_device::spg110_2055_w) { } -WRITE16_MEMBER(spg110_device::spg110_2056_w) { } -WRITE16_MEMBER(spg110_device::spg110_2057_w) { } -WRITE16_MEMBER(spg110_device::spg110_2058_w) { } -WRITE16_MEMBER(spg110_device::spg110_2059_w) { } -WRITE16_MEMBER(spg110_device::spg110_205a_w) { } -WRITE16_MEMBER(spg110_device::spg110_205b_w) { } -WRITE16_MEMBER(spg110_device::spg110_205c_w) { } -WRITE16_MEMBER(spg110_device::spg110_205d_w) { } -WRITE16_MEMBER(spg110_device::spg110_205e_w) { } -WRITE16_MEMBER(spg110_device::spg110_205f_w) { } - -WRITE16_MEMBER(spg110_device::dma_unk_2061_w) { COMBINE_DATA(&m_dma_unk_2061); } -WRITE16_MEMBER(spg110_device::dma_dst_step_w) { COMBINE_DATA(&m_dma_dst_step); } -WRITE16_MEMBER(spg110_device::dma_unk_2067_w) { COMBINE_DATA(&m_dma_unk_2067); } -WRITE16_MEMBER(spg110_device::dma_src_step_w) { COMBINE_DATA(&m_dma_src_step); } - -WRITE16_MEMBER(spg110_device::dma_dst_w) { COMBINE_DATA(&m_dma_dst); } -WRITE16_MEMBER(spg110_device::dma_src_w) { COMBINE_DATA(&m_dma_src); } - -WRITE16_MEMBER(spg110_device::dma_len_trigger_w) -{ - int length = data & 0x1fff; - - // this is presumably a counter that underflows to 0x1fff, because that's what the wait loop waits for? - logerror("%s: (trigger len) %04x with values (unk) %04x (dststep) %04x (unk) %04x (src step) %04x | (dst) %04x (src) %04x\n", machine().describe_context(), data, m_dma_unk_2061, m_dma_dst_step, m_dma_unk_2067, m_dma_src_step, m_dma_dst, m_dma_src); - - if ((m_dma_unk_2061!=0x0000) || (m_dma_unk_2067 != 0x0000)) - fatalerror("unknown DMA params are not zero!\n"); - - int source = m_dma_src; - int dest = m_dma_dst; - - for (int i = 0; i < length; i++) - { - address_space &mem = m_cpu->space(AS_PROGRAM); - uint16_t val = mem.read_word(source); - - this->space(0).write_word(dest * 2, val, 0xffff); - - source+=m_dma_src_step; - dest+=m_dma_dst_step; - } -} - -READ16_MEMBER(spg110_device::dma_len_status_r) -{ - return 0x1fff; // DMA related? -} - -READ16_MEMBER(spg110_device::spg110_2037_r) { return 0x0000; } -READ16_MEMBER(spg110_device::spg110_2042_r) { return 0x0000; } - -WRITE16_MEMBER(spg110_device::spg110_3200_w) { } -WRITE16_MEMBER(spg110_device::spg110_3201_w) { } -WRITE16_MEMBER(spg110_device::spg110_3203_w) { } -WRITE16_MEMBER(spg110_device::spg110_3204_w) { } -WRITE16_MEMBER(spg110_device::spg110_3206_w) { } -WRITE16_MEMBER(spg110_device::spg110_3208_w) { } -WRITE16_MEMBER(spg110_device::spg110_3209_w) { } - -READ16_MEMBER(spg110_device::spg110_3201_r) { return 0x0000; } -READ16_MEMBER(spg110_device::spg110_3225_r) { return 0x0000; } -READ16_MEMBER(spg110_device::spg110_322c_r) { return 0x0000; } - WRITE16_MEMBER(spg110_device::spg110_3100_w) { } WRITE16_MEMBER(spg110_device::spg110_3101_w) { } WRITE16_MEMBER(spg110_device::spg110_3102_w) { } @@ -378,128 +87,60 @@ WRITE16_MEMBER(spg110_device::spg110_310d_w) { } READ16_MEMBER(spg110_device::spg110_310f_r) { return 0x0000; } -READ16_MEMBER(spg110_device::tmap0_regs_r) { return tmap0_regs[offset]; } -READ16_MEMBER(spg110_device::tmap1_regs_r) { return tmap1_regs[offset]; } - -void spg110_device::tilemap_write_regs(int which, uint16_t* regs, int regno, uint16_t data) -{ - switch (regno) - { - case 0x0: // Page X scroll - logerror("video_w: Page %d X Scroll = %04x\n", which, data & 0x01ff); - regs[regno] = data & 0x01ff; - break; - - case 0x1: // Page Y scroll - logerror("video_w: Page %d Y Scroll = %04x\n", which, data & 0x00ff); - regs[regno] = data & 0x00ff; - break; - - case 0x2: // Page Attributes - // 'depth' (aka z value) can't be depth here as it is on spg2xx, or the scores in attract will be behind the table, it really seems to be per attribute bit instead - - logerror("video_w: Page %d Attributes = %04x (Depth:%d, Palette:%d, VSize:%d, HSize:%d, FlipY:%d, FlipX:%d, BPP:%d)\n", which, data - , (data >> 12) & 3, (data >> 8) & 15, 8 << ((data >> 6) & 3), 8 << ((data >> 4) & 3), BIT(data, 3), BIT(data, 2), 2 * ((data & 3) + 1)); - regs[regno] = data; - break; - - case 0x3: // Page Control - logerror("video_w: Page %d Control = %04x (Blend:%d, HiColor:%d, RowScroll:%d, Enable:%d, Wallpaper:%d, RegSet:%d, Bitmap:%d)\n", which, data - , BIT(data, 8), BIT(data, 7), BIT(data, 4), BIT(data, 3), BIT(data, 2), BIT(data, 1), BIT(data, 0)); - regs[regno] = data; - break; - - case 0x4: // Page Tile Address - logerror("video_w: Page %d Tile Address = %04x\n", which, data); - regs[regno] = data; - break; - - case 0x5: // Page Attribute Address - logerror("video_w: Page %d Attribute Address = %04x\n", which, data); - regs[regno] = data; - break; - } -} - - -WRITE16_MEMBER(spg110_device::tmap0_regs_w) -{ - tilemap_write_regs(0, tmap0_regs,offset,data); -} - - -WRITE16_MEMBER(spg110_device::tmap1_regs_w) -{ - tilemap_write_regs(1, tmap1_regs,offset,data); -} - void spg110_device::map(address_map &map) { map(0x000000, 0x000fff).ram(); - // vregs are at 2000? - map(0x002010, 0x002015).rw(FUNC(spg110_device::tmap0_regs_r), FUNC(spg110_device::tmap0_regs_w)); - map(0x002016, 0x00201b).rw(FUNC(spg110_device::tmap1_regs_r), FUNC(spg110_device::tmap1_regs_w)); - - map(0x00201c, 0x00201c).w(FUNC(spg110_device::spg110_201c_w)); + map(0x002010, 0x002015).rw(m_spg_video, FUNC(spg110_video_device::tmap0_regs_r), FUNC(spg110_video_device::tmap0_regs_w)); + map(0x002016, 0x00201b).rw(m_spg_video, FUNC(spg110_video_device::tmap1_regs_r), FUNC(spg110_video_device::tmap1_regs_w)); - map(0x002020, 0x002020).w(FUNC(spg110_device::spg110_2020_w)); +#if 1 // more vregs? + map(0x00201c, 0x00201c).w(m_spg_video, FUNC(spg110_video_device::spg110_201c_w)); - map(0x002028, 0x002028).rw(FUNC(spg110_device::spg110_2028_r), FUNC(spg110_device::spg110_2028_w)); - map(0x002029, 0x002029).rw(FUNC(spg110_device::spg110_2029_r), FUNC(spg110_device::spg110_2029_w)); + map(0x002020, 0x002020).w(m_spg_video, FUNC(spg110_video_device::spg110_2020_w)); - map(0x002031, 0x002031).w(FUNC(spg110_device::spg110_2031_w)); // sometimes 14a? - map(0x002032, 0x002032).w(FUNC(spg110_device::spg110_2032_w)); // always 14a? - map(0x002033, 0x002033).w(FUNC(spg110_device::spg110_2033_w)); - map(0x002034, 0x002034).w(FUNC(spg110_device::spg110_2034_w)); - map(0x002035, 0x002035).w(FUNC(spg110_device::spg110_2035_w)); - map(0x002036, 0x002036).w(FUNC(spg110_device::spg110_2036_w)); // possible scroll register? - map(0x002037, 0x002037).rw(FUNC(spg110_device::spg110_2037_r), FUNC(spg110_device::spg110_2037_w)); + map(0x002028, 0x002028).rw(m_spg_video, FUNC(spg110_video_device::spg110_2028_r), FUNC(spg110_video_device::spg110_2028_w)); + map(0x002029, 0x002029).rw(m_spg_video, FUNC(spg110_video_device::spg110_2029_r), FUNC(spg110_video_device::spg110_2029_w)); - map(0x002039, 0x002039).w(FUNC(spg110_device::spg110_2039_w)); + map(0x002031, 0x002031).w(m_spg_video, FUNC(spg110_video_device::spg110_2031_w)); // sometimes 14a? + map(0x002032, 0x002032).w(m_spg_video, FUNC(spg110_video_device::spg110_2032_w)); // always 14a? + map(0x002033, 0x002033).w(m_spg_video, FUNC(spg110_video_device::spg110_2033_w)); + map(0x002034, 0x002034).w(m_spg_video, FUNC(spg110_video_device::spg110_2034_w)); + map(0x002035, 0x002035).w(m_spg_video, FUNC(spg110_video_device::spg110_2035_w)); + map(0x002036, 0x002036).w(m_spg_video, FUNC(spg110_video_device::spg110_2036_w)); // possible scroll register? + map(0x002037, 0x002037).rw(m_spg_video, FUNC(spg110_video_device::spg110_2037_r), FUNC(spg110_video_device::spg110_2037_w)); - map(0x00203c, 0x00203c).w(FUNC(spg110_device::spg110_203c_w)); + map(0x002039, 0x002039).w(m_spg_video, FUNC(spg110_video_device::spg110_2039_w)); - map(0x00203d, 0x00203d).w(FUNC(spg110_device::spg110_203d_w)); // possible scroll register? + map(0x00203c, 0x00203c).w(m_spg_video, FUNC(spg110_video_device::spg110_203c_w)); - map(0x002042, 0x002042).rw(FUNC(spg110_device::spg110_2042_r),FUNC(spg110_device::spg110_2042_w)); + map(0x00203d, 0x00203d).w(m_spg_video, FUNC(spg110_video_device::spg110_203d_w)); // possible scroll register? - map(0x002045, 0x002045).w(FUNC(spg110_device::spg110_2045_w)); + map(0x002042, 0x002042).rw(m_spg_video, FUNC(spg110_video_device::spg110_2042_r),FUNC(spg110_video_device::spg110_2042_w)); - // seems to be 16 entries for.. something? - map(0x002050, 0x002050).w(FUNC(spg110_device::spg110_2050_w)); - map(0x002051, 0x002051).w(FUNC(spg110_device::spg110_2051_w)); - map(0x002052, 0x002052).w(FUNC(spg110_device::spg110_2052_w)); - map(0x002053, 0x002053).w(FUNC(spg110_device::spg110_2053_w)); - map(0x002054, 0x002054).w(FUNC(spg110_device::spg110_2054_w)); - map(0x002055, 0x002055).w(FUNC(spg110_device::spg110_2055_w)); - map(0x002056, 0x002056).w(FUNC(spg110_device::spg110_2056_w)); - map(0x002057, 0x002057).w(FUNC(spg110_device::spg110_2057_w)); - map(0x002058, 0x002058).w(FUNC(spg110_device::spg110_2058_w)); - map(0x002059, 0x002059).w(FUNC(spg110_device::spg110_2059_w)); - map(0x00205a, 0x00205a).w(FUNC(spg110_device::spg110_205a_w)); - map(0x00205b, 0x00205b).w(FUNC(spg110_device::spg110_205b_w)); - map(0x00205c, 0x00205c).w(FUNC(spg110_device::spg110_205c_w)); - map(0x00205d, 0x00205d).w(FUNC(spg110_device::spg110_205d_w)); - map(0x00205e, 0x00205e).w(FUNC(spg110_device::spg110_205e_w)); - map(0x00205f, 0x00205f).w(FUNC(spg110_device::spg110_205f_w)); + map(0x002045, 0x002045).w(m_spg_video, FUNC(spg110_video_device::spg110_2045_w)); +#endif - //map(0x002010, 0x00205f).ram(); + // seems to be 16 entries for.. something? on jak_capb these seem connected to the palette DMA operations, 0x2050 for 0x8000, 0x2051 for 0x8020, 0x2052 for 0x8040 etc. maybe 1 bit per pen? + map(0x002050, 0x00205f).ram().w(m_spg_video, FUNC(spg110_video_device::spg110_205x_w)).share("spg_video:palctrlram"); // everything (dma? and interrupt flag?!) - map(0x002060, 0x002060).w(FUNC(spg110_device::dma_dst_w)); - map(0x002061, 0x002061).w(FUNC(spg110_device::dma_unk_2061_w)); - map(0x002062, 0x002062).rw(FUNC(spg110_device::dma_len_status_r),FUNC(spg110_device::dma_len_trigger_w)); - map(0x002063, 0x002063).rw(FUNC(spg110_device::spg110_2063_r),FUNC(spg110_device::spg110_2063_w)); // this looks like interrupt stuff and is checked in the irq like an irq source, but why in the middle of what otherwise look like some kind of DMA? - map(0x002064, 0x002064).w(FUNC(spg110_device::dma_dst_step_w)); - map(0x002066, 0x002066).w(FUNC(spg110_device::dma_src_w)); - map(0x002067, 0x002067).w(FUNC(spg110_device::dma_unk_2067_w)); - map(0x002068, 0x002068).w(FUNC(spg110_device::dma_src_step_w)); - - map(0x002200, 0x0022ff).ram(); // looks like per-pen brightness or similar? strange because palette isn't memory mapped here - - map(0x003000, 0x00307f).ram(); // sound registers? seems to be 8 long entries, only uses up to 0x7f? + map(0x002060, 0x002060).w(m_spg_video, FUNC(spg110_video_device::dma_dst_w)); + map(0x002061, 0x002061).w(m_spg_video, FUNC(spg110_video_device::dma_unk_2061_w)); + map(0x002062, 0x002062).rw(m_spg_video, FUNC(spg110_video_device::dma_len_status_r),FUNC(spg110_video_device::dma_len_trigger_w)); + map(0x002063, 0x002063).rw(m_spg_video, FUNC(spg110_video_device::spg110_2063_r),FUNC(spg110_video_device::spg110_2063_w)); // Video IRQ source / ack (3 different things checked here instead of 2 on spg2xx?) + map(0x002064, 0x002064).w(m_spg_video, FUNC(spg110_video_device::dma_dst_step_w)); + map(0x002065, 0x002065).rw(m_spg_video, FUNC(spg110_video_device::dma_manual_r), FUNC(spg110_video_device::dma_manual_w)); + map(0x002066, 0x002066).w(m_spg_video, FUNC(spg110_video_device::dma_src_w)); + map(0x002067, 0x002067).w(m_spg_video, FUNC(spg110_video_device::dma_unk_2067_w)); + map(0x002068, 0x002068).w(m_spg_video, FUNC(spg110_video_device::dma_src_step_w)); + + map(0x002100, 0x0021ff).ram(); // jak_spdmo only + map(0x002200, 0x0022ff).ram(); // looks like per-pen brightness or similar? strange because palette isn't memory mapped here (maybe rowscroll?) + +#if 1 // sound registers? seems to be 8 long entries, only uses up to 0x7f? (register mapping seems similar to spg2xx, maybe with less channels?) + map(0x003000, 0x00307f).ram(); map(0x003080, 0x0030ff).ram(); map(0x003100, 0x003100).w(FUNC(spg110_device::spg110_3100_w)); @@ -518,157 +159,28 @@ void spg110_device::map(address_map &map) map(0x00310d, 0x00310d).w(FUNC(spg110_device::spg110_310d_w)); map(0x00310f, 0x00310f).r(FUNC(spg110_device::spg110_310f_r)); +#endif // 0032xx looks like it could be the same as 003d00 on spg2xx - map(0x003200, 0x003200).w(FUNC(spg110_device::spg110_3200_w)); - - map(0x003201, 0x003201).rw(FUNC(spg110_device::spg110_3201_r),FUNC(spg110_device::spg110_3201_w)); - - map(0x003203, 0x003203).w(FUNC(spg110_device::spg110_3203_w)); - map(0x003204, 0x003204).w(FUNC(spg110_device::spg110_3204_w)); - - map(0x003206, 0x003206).w(FUNC(spg110_device::spg110_3206_w)); - - map(0x003208, 0x003208).w(FUNC(spg110_device::spg110_3208_w)); - map(0x003209, 0x003209).w(FUNC(spg110_device::spg110_3209_w)); - - map(0x003221, 0x003221).w(FUNC(spg110_device::spg110_3221_w)); - map(0x003223, 0x003223).w(FUNC(spg110_device::spg110_3223_w)); - map(0x003225, 0x003225).rw(FUNC(spg110_device::spg110_3225_r),FUNC(spg110_device::spg110_3225_w)); - map(0x00322c, 0x00322c).r(FUNC(spg110_device::spg110_322c_r)); - - map(0x00322f, 0x00322f).rw(FUNC(spg110_device::datasegment_r),FUNC(spg110_device::datasegment_w)); + map(0x003200, 0x00322f).rw(m_spg_io, FUNC(spg2xx_io_device::io_r), FUNC(spg2xx_io_device::io_w)); } -// this seems to be a different, non-cpu mapped space only accessible via the DMA? -void spg110_device::map_video(address_map &map) -{ - // are these addresses hardcoded, or can they move (in which case tilemap system isn't really suitable) - map(0x00000, 0x03fff).ram(); // 2fff? - - map(0x04000, 0x04fff).ram(); // seems to be 3 blocks, almost certainly spritelist - -// map(0x08000, 0x081ff).ram().w(m_palette, FUNC(palette_device::write16)).share("palette"); // probably? format unknown tho - map(0x08000, 0x081ff).ram().share("palram"); -} - - -/* -TIMER_CALLBACK_MEMBER(spg110_device::test_timer) -{ - // -} -*/ - - void spg110_device::device_start() { -// m_test_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(spg110_device::test_timer), this)); - save_item(NAME(m_dma_src_step)); - save_item(NAME(m_dma_dst_step)); - save_item(NAME(m_dma_unk_2061)); - save_item(NAME(m_dma_unk_2067)); - save_item(NAME(m_dma_dst)); - save_item(NAME(m_dma_src)); - save_item(NAME(m_bg_scrollx)); - save_item(NAME(m_bg_scrolly)); - save_item(NAME(m_2036_scroll)); -} - -void spg110_device::device_reset() -{ - m_dma_src_step = 0; - m_dma_dst_step = 0; - m_dma_unk_2061 = 0; - m_dma_unk_2067 = 0; - m_dma_dst = 0; - m_dma_src = 0; - m_bg_scrollx = 0; - m_bg_scrolly = 0; - m_2036_scroll = 0; -} + m_porta_out.resolve_safe(); + m_portb_out.resolve_safe(); + m_portc_out.resolve_safe(); + m_porta_in.resolve_safe(0); + m_portb_in.resolve_safe(0); + m_portc_in.resolve_safe(0); + m_adc_in[0].resolve_safe(0x0fff); + m_adc_in[1].resolve_safe(0x0fff); + m_chip_sel.resolve_safe(); -double spg110_device::hue2rgb(double p, double q, double t) -{ - if (t < 0) t += 1; - if (t > 1) t -= 1; - if (t < 1 / 6.0f) return p + (q - p) * 6 * t; - if (t < 1 / 2.0f) return q; - if (t < 2 / 3.0f) return p + (q - p) * (2 / 3.0f - t) * 6; - return p; } -uint32_t spg110_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) +void spg110_device::device_reset() { - // Palette, this is still wrong! - int offs = 0; - for (int index = 0;index < 256; index++) - { - uint16_t dat = m_palram[offs++]; - - // llll lsss sshh hhhh - int l_raw = (dat & 0xf800) >> 11; - int sl_raw = (dat & 0x07c0) >> 6; - int h_raw = (dat & 0x003f) >> 0; - - double l = (double)l_raw / 31.0f; - double s = (double)sl_raw / 31.0f; - double h = (double)h_raw / 47.0f; - - double r, g, b; - - if (s == 0) { - r = g = b = l; // greyscale - } else { - double q = l < 0.5f ? l * (1 + s) : l + s - l * s; - double p = 2 * l - q; - r = hue2rgb(p, q, h + 1/3.0f); - g = hue2rgb(p, q, h); - b = hue2rgb(p, q, h - 1/3.0f); - } - - int r_real = r * 255.0f; - int g_real = g * 255.0f; - int b_real = b * 255.0f; - - m_palette->set_pen_color(index, r_real, g_real, b_real); - } - - memset(&m_screenbuf[320 * cliprect.min_y], 0, 4 * 320 * ((cliprect.max_y - cliprect.min_y) + 1)); - - const uint32_t page1_addr = 0;//0x40 * m_video_regs[0x20]; - const uint32_t page2_addr = 0;//0x40 * m_video_regs[0x21]; - uint16_t *page1_regs = tmap0_regs; - uint16_t *page2_regs = tmap1_regs; - - for (uint32_t scanline = (uint32_t)cliprect.min_y; scanline <= (uint32_t)cliprect.max_y; scanline++) - { - for (int i = 0; i < 4; i++) - { - blit_page(cliprect, scanline, i, page2_addr, page2_regs); - blit_page(cliprect, scanline, i, page1_addr, page1_regs); - //blit_sprites(cliprect, scanline, i); - } - } - - for (int y = cliprect.min_y; y <= cliprect.max_y; y++) - { - uint32_t *dest = &bitmap.pix32(y, cliprect.min_x); - uint32_t *src = &m_screenbuf[cliprect.min_x + 320 * y]; - memcpy(dest, src, sizeof(uint32_t) * ((cliprect.max_x - cliprect.min_x) + 1)); - } - - return 0; } -WRITE_LINE_MEMBER(spg110_device::vblank) -{ - if (!state) - { - m_cpu->set_state_unsynced(UNSP_IRQ0_LINE, ASSERT_LINE); - // m_test_timer->adjust(attotime::from_usec(100), 0); - } - - return; -} diff --git a/src/devices/machine/spg110.h b/src/devices/machine/spg110.h index dd51e1883b1..91a715fc755 100644 --- a/src/devices/machine/spg110.h +++ b/src/devices/machine/spg110.h @@ -9,28 +9,39 @@ //#include "spg2xx.h" #include "cpu/unsp/unsp.h" #include "emupal.h" +#include "spg2xx_io.h" +#include "spg110_video.h" - -class spg110_device : public device_t, public device_memory_interface +class spg110_device : public device_t { public: spg110_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock); spg110_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); - template <typename T> - spg110_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, T &&cpu_tag) + template <typename T, typename U> + spg110_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, T &&cpu_tag, U &&screen_tag) : spg110_device(mconfig, tag, owner, clock) { m_cpu.set_tag(std::forward<T>(cpu_tag)); + m_screen.set_tag(std::forward<U>(screen_tag)); } void map(address_map &map); - void map_video(address_map &map); - double hue2rgb(double p, double q, double t); - uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); - DECLARE_WRITE_LINE_MEMBER(vblank); + auto porta_out() { return m_porta_out.bind(); } + auto portb_out() { return m_portb_out.bind(); } + auto portc_out() { return m_portc_out.bind(); } + auto porta_in() { return m_porta_in.bind(); } + auto portb_in() { return m_portb_in.bind(); } + auto portc_in() { return m_portc_in.bind(); } + + template <size_t Line> auto adc_in() { return m_adc_in[Line].bind(); } + + auto chip_select() { return m_chip_sel.bind(); } + + uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) { return m_spg_video->screen_update(screen,bitmap,cliprect); } + DECLARE_WRITE_LINE_MEMBER(vblank) { m_spg_video->vblank(state); } protected: virtual void device_start() override; @@ -38,119 +49,13 @@ protected: virtual void device_add_mconfig(machine_config &config) override; - virtual space_config_vector memory_space_config() const override; - - address_space_config m_space_config; - private: - enum - { - PAGE_ENABLE_MASK = 0x0008, - PAGE_WALLPAPER_MASK = 0x0004, - - PAGE_DEPTH_FLAG_MASK = 0x3000, - PAGE_DEPTH_FLAG_SHIFT = 12, - PAGE_TILE_HEIGHT_MASK = 0x00c0, - PAGE_TILE_HEIGHT_SHIFT = 6, - PAGE_TILE_WIDTH_MASK = 0x0030, - PAGE_TILE_WIDTH_SHIFT = 4, - - TILE_X_FLIP = 0x0004, - TILE_Y_FLIP = 0x0008 - }; - - enum flipx_t : bool - { - FlipXOff = false, - FlipXOn = true - }; required_device<unsp_device> m_cpu; - required_device<palette_device> m_palette; - required_device<gfxdecode_device> m_gfxdecode; - required_shared_ptr<uint16_t> m_palram; - - //TIMER_CALLBACK_MEMBER(test_timer); - //emu_timer *m_test_timer; - - - DECLARE_WRITE16_MEMBER(spg110_201c_w); - DECLARE_WRITE16_MEMBER(spg110_2020_w); - - DECLARE_WRITE16_MEMBER(spg110_2028_w); - DECLARE_WRITE16_MEMBER(spg110_2029_w); - - DECLARE_READ16_MEMBER(spg110_2028_r); - DECLARE_READ16_MEMBER(spg110_2029_r); - - DECLARE_WRITE16_MEMBER(spg110_2031_w); - DECLARE_WRITE16_MEMBER(spg110_2032_w); - DECLARE_WRITE16_MEMBER(spg110_2033_w); - DECLARE_WRITE16_MEMBER(spg110_2034_w); - DECLARE_WRITE16_MEMBER(spg110_2035_w); - DECLARE_WRITE16_MEMBER(spg110_2036_w); - DECLARE_WRITE16_MEMBER(spg110_2037_w); - DECLARE_WRITE16_MEMBER(spg110_2039_w); - - DECLARE_WRITE16_MEMBER(spg110_203c_w); - DECLARE_WRITE16_MEMBER(spg110_203d_w); - - DECLARE_WRITE16_MEMBER(spg110_2042_w); - - DECLARE_WRITE16_MEMBER(spg110_2045_w); - - DECLARE_WRITE16_MEMBER(spg110_2050_w); - DECLARE_WRITE16_MEMBER(spg110_2051_w); - DECLARE_WRITE16_MEMBER(spg110_2052_w); - DECLARE_WRITE16_MEMBER(spg110_2053_w); - DECLARE_WRITE16_MEMBER(spg110_2054_w); - DECLARE_WRITE16_MEMBER(spg110_2055_w); - DECLARE_WRITE16_MEMBER(spg110_2056_w); - DECLARE_WRITE16_MEMBER(spg110_2057_w); - DECLARE_WRITE16_MEMBER(spg110_2058_w); - DECLARE_WRITE16_MEMBER(spg110_2059_w); - DECLARE_WRITE16_MEMBER(spg110_205a_w); - DECLARE_WRITE16_MEMBER(spg110_205b_w); - DECLARE_WRITE16_MEMBER(spg110_205c_w); - DECLARE_WRITE16_MEMBER(spg110_205d_w); - DECLARE_WRITE16_MEMBER(spg110_205e_w); - DECLARE_WRITE16_MEMBER(spg110_205f_w); - - - DECLARE_READ16_MEMBER(spg110_2037_r); - DECLARE_READ16_MEMBER(spg110_2042_r); - - DECLARE_WRITE16_MEMBER(dma_dst_w); - DECLARE_WRITE16_MEMBER(dma_unk_2061_w); - DECLARE_WRITE16_MEMBER(dma_len_trigger_w); - DECLARE_WRITE16_MEMBER(spg110_2063_w); - DECLARE_WRITE16_MEMBER(dma_dst_step_w); - DECLARE_WRITE16_MEMBER(dma_src_w); - DECLARE_WRITE16_MEMBER(dma_unk_2067_w); - DECLARE_WRITE16_MEMBER(dma_src_step_w); - - DECLARE_READ16_MEMBER(dma_len_status_r); - DECLARE_READ16_MEMBER(spg110_2063_r); - - DECLARE_WRITE16_MEMBER(spg110_3200_w); - DECLARE_WRITE16_MEMBER(spg110_3201_w); - DECLARE_WRITE16_MEMBER(spg110_3203_w); - DECLARE_WRITE16_MEMBER(spg110_3204_w); - DECLARE_WRITE16_MEMBER(spg110_3206_w); - DECLARE_WRITE16_MEMBER(spg110_3208_w); - DECLARE_WRITE16_MEMBER(spg110_3209_w); - - DECLARE_READ16_MEMBER(spg110_3201_r); - - DECLARE_WRITE16_MEMBER(spg110_3221_w); - DECLARE_WRITE16_MEMBER(spg110_3223_w); - DECLARE_WRITE16_MEMBER(spg110_3225_w); - - DECLARE_READ16_MEMBER(spg110_3225_r); - DECLARE_READ16_MEMBER(spg110_322c_r); - - READ16_MEMBER(datasegment_r); - WRITE16_MEMBER(datasegment_w); + required_device<screen_device> m_screen; + + required_device<spg2xx_io_device> m_spg_io; + required_device<spg110_video_device> m_spg_video; DECLARE_WRITE16_MEMBER(spg110_3100_w); @@ -169,32 +74,29 @@ private: DECLARE_READ16_MEMBER(spg110_310f_r); - DECLARE_READ16_MEMBER(tmap0_regs_r); - DECLARE_READ16_MEMBER(tmap1_regs_r); - DECLARE_WRITE16_MEMBER(tmap0_regs_w); - DECLARE_WRITE16_MEMBER(tmap1_regs_w); - - uint16_t tmap0_regs[0x6]; - uint16_t tmap1_regs[0x6]; - - uint16_t m_dma_src_step; - uint16_t m_dma_dst_step; - uint16_t m_dma_unk_2061; - uint16_t m_dma_unk_2067; - - uint16_t m_dma_dst; - uint16_t m_dma_src; - - uint16_t m_bg_scrollx; - uint16_t m_bg_scrolly; - uint16_t m_2036_scroll; - - void tilemap_write_regs(int which, uint16_t* regs, int regno, uint16_t data); - - template<flipx_t FlipX> - void blit(const rectangle &cliprect, uint32_t line, uint32_t xoff, uint32_t yoff, uint32_t attr, uint32_t ctrl, uint32_t bitmap_addr, uint16_t tile); - void blit_page(const rectangle &cliprect, uint32_t scanline, int depth, uint32_t bitmap_addr, uint16_t *regs); - uint32_t m_screenbuf[320 * 240]; + devcb_write16 m_porta_out; + devcb_write16 m_portb_out; + devcb_write16 m_portc_out; + devcb_read16 m_porta_in; + devcb_read16 m_portb_in; + devcb_read16 m_portc_in; + + devcb_read16 m_adc_in[2]; + + devcb_write8 m_chip_sel; + + DECLARE_READ16_MEMBER(porta_r) { return m_porta_in(); } + DECLARE_READ16_MEMBER(portb_r) { return m_portb_in(); } + DECLARE_READ16_MEMBER(portc_r) { return m_portc_in(); } + DECLARE_WRITE16_MEMBER(porta_w) { m_porta_out(offset, data, mem_mask); } + DECLARE_WRITE16_MEMBER(portb_w) { m_portb_out(offset, data, mem_mask); } + DECLARE_WRITE16_MEMBER(portc_w) { m_portc_out(offset, data, mem_mask); } + template <size_t Line> DECLARE_READ16_MEMBER(adc_r) { return m_adc_in[Line](); } + DECLARE_WRITE8_MEMBER(cs_w) { m_chip_sel(offset, data, mem_mask); } + DECLARE_READ16_MEMBER(get_pal_r) { return 0; /*m_pal_flag;*/ } + void configure_spg_io(spg2xx_io_device* io); + + DECLARE_WRITE_LINE_MEMBER(videoirq_w); }; DECLARE_DEVICE_TYPE(SPG110, spg110_device) diff --git a/src/devices/machine/spg110_video.cpp b/src/devices/machine/spg110_video.cpp new file mode 100644 index 00000000000..9a9600b914d --- /dev/null +++ b/src/devices/machine/spg110_video.cpp @@ -0,0 +1,666 @@ +// license:BSD-3-Clause +// copyright-holders:David Haywood + +#include "emu.h" +#include "spg110_video.h" + +DEFINE_DEVICE_TYPE(SPG110_VIDEO, spg110_video_device, "spg110_video", "SPG110 System-on-a-Chip (Video)") + +spg110_video_device::spg110_video_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) + : device_t(mconfig, type, tag, owner, clock) + , device_memory_interface(mconfig, *this) + , m_space_config("spg110_video", ENDIANNESS_BIG, 16, 32, 0, address_map_constructor(FUNC(spg110_video_device::map_video), this)) + , m_cpu(*this, finder_base::DUMMY_TAG) + , m_screen(*this, finder_base::DUMMY_TAG) + , m_palette(*this, "palette") + , m_gfxdecode(*this, "gfxdecode") + , m_palram(*this, "palram") + , m_palctrlram(*this, "palctrlram") + , m_sprtileno(*this, "sprtileno") + , m_sprattr1(*this, "sprattr1") + , m_sprattr2(*this, "sprattr2") + , m_video_irq_cb(*this) +{ +} + +spg110_video_device::spg110_video_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : spg110_video_device(mconfig, SPG110_VIDEO, tag, owner, clock) +{ +} + +template<spg110_video_device::flipx_t FlipX> +void spg110_video_device::draw(const rectangle &cliprect, uint32_t line, uint32_t xoff, uint32_t yoff, uint32_t ctrl, uint32_t bitmap_addr, uint16_t tile, uint8_t yflipmask, uint8_t pal, int32_t h, int32_t w, uint8_t bpp) +{ + address_space &space = m_cpu->space(AS_PROGRAM); + + uint32_t nc = (bpp + 1) << 1; + + uint32_t palette_offset = pal; + + palette_offset <<= nc; + + uint32_t bits_per_row = nc * w / 16; + uint32_t words_per_tile = bits_per_row * h; + uint32_t m = bitmap_addr + words_per_tile * tile + bits_per_row * (line ^ yflipmask); + uint32_t bits = 0; + uint32_t nbits = 0; + uint32_t y = line; + + int yy = (yoff + y) & 0x1ff; + if (yy >= 0x01c0) + yy -= 0x0200; + + if (yy > 240 || yy < 0) + return; + + int y_index = yy * 320; + + for (int32_t x = FlipX ? (w - 1) : 0; FlipX ? x >= 0 : x < w; FlipX ? x-- : x++) + { + int xx = xoff + x; + + bits <<= nc; + + if (nbits < nc) + { + uint16_t b = space.read_word(m++ & 0x3fffff); + //b = (b << 8) | (b >> 8); + bits |= b << (nc - nbits); + nbits += 16; + } + nbits -= nc; + + uint32_t pal = palette_offset + (bits >> 16); + bits &= 0xffff; + + xx &= 0x01ff; + if (xx >= 0x01c0) + xx -= 0x0200; + + if (xx >= 0 && xx < 320) + { + int pix_index = xx + y_index; + const pen_t *pens = m_palette->pens(); + uint32_t paldata = pens[pal]; + + int transmap = m_palctrlram[(pal & 0xf0)>>4]; + + bool trans = false; + + if (transmap & 0x10) // maybe values other than 0x010 have other meanings, like blending? + if ((pal & 0x0f) == (transmap & 0xf)) + trans = true; + + if (!trans) + { + m_screenbuf[pix_index] = paldata; + } + } + } +} + +void spg110_video_device::draw_page(const rectangle &cliprect, uint32_t scanline, int priority, uint32_t bitmap_addr, uint16_t *regs) +{ + uint32_t xscroll = regs[0]; + uint32_t yscroll = regs[1]; + uint32_t attr = regs[2]; + uint32_t ctrl = regs[3]; + uint32_t tilemap = regs[4]; + uint32_t palette_map = regs[5]; + address_space &space2 = this->space(0); + + if (!(ctrl & PAGE_ENABLE_MASK)) + { + return; + } + +// if (((attr & PAGE_PRIORITY_FLAG_MASK) >> PAGE_PRIORITY_FLAG_SHIFT) != priority) +// { +// return; +// } + + uint8_t bpp = attr & 0x03; + + uint32_t tile_h = 8 << ((attr & PAGE_TILE_HEIGHT_MASK) >> PAGE_TILE_HEIGHT_SHIFT); + uint32_t tile_w = 8 << ((attr & PAGE_TILE_WIDTH_MASK) >> PAGE_TILE_WIDTH_SHIFT); + + uint32_t tile_count_x = 512 / tile_w; + + uint32_t bitmap_y = (scanline + yscroll) & 0xff; + uint32_t y0 = bitmap_y / tile_h; + uint32_t tile_scanline = bitmap_y % tile_h; + uint32_t tile_address = tile_count_x * y0; + + for (uint32_t x0 = 0; x0 < tile_count_x; x0++, tile_address++) + { + uint32_t yy = ((tile_h * y0 - yscroll + 0x10) & 0xff) - 0x10; + uint32_t xx = (tile_w * x0 - xscroll) & 0x1ff; + uint16_t tile = (ctrl & PAGE_WALLPAPER_MASK) ? space2.read_word(tilemap*2) : space2.read_word((tilemap + tile_address)*2); + uint16_t extra_attribute = 0; + + if (!tile) + continue; + + extra_attribute = space2.read_word((palette_map*2) + tile_address); + if (x0 & 1) + extra_attribute = (extra_attribute & 0x00ff); + else + extra_attribute = (extra_attribute & 0xff00) >> 8; + + uint8_t pal = extra_attribute & 0x0f; + uint8_t pri = (extra_attribute & 0x30) >> 4; + bool flip_x = extra_attribute & 0x40; + + if (pri == priority) + { + + if (flip_x) + draw<FlipXOn>(cliprect, tile_scanline, xx, yy, ctrl, bitmap_addr, tile, 0, pal, tile_h, tile_w, bpp); + else + draw<FlipXOff>(cliprect, tile_scanline, xx, yy, ctrl, bitmap_addr, tile, 0, pal, tile_h, tile_w, bpp); + } + + } +} + + +void spg110_video_device::draw_sprite(const rectangle &cliprect, uint32_t scanline, int priority, uint32_t base_addr) +{ + + // m_sprtileno tttt tttt tttt tttt t = tile number (all bits?) + // m_sprattr1 xxxx xxxx yyyy yyyy x = low x bits, y = low y bits + // m_sprattr2 YXzz pppp hhww fFbb X = high x bit, z = priority, p = palette, h = height, w = width, f = flipy, F = flipx, b = bpp, Y = high y bit + + uint16_t tile = m_sprtileno[base_addr]; + + if (!tile) + { + return; + } + + uint32_t bitmap_addr = 0x40 * m_tilebase; + uint16_t attr1 = m_sprattr1[base_addr]; + uint16_t attr2 = m_sprattr2[base_addr]; + + int x = (attr1 >> 8) & 0xff; + int y = (attr1) & 0xff; + uint8_t pri = (attr2 & 0x3000)>>12; + bool flip_x = (attr2 & 0x0004)>>2; + bool flip_y = (attr2 & 0x0008)>>3; + + if (!(attr2 & 0x4000)) + x+= 0x100; + + if (!(attr2 & 0x8000)) + y+= 0x100; + + const uint32_t h = 8 << ((attr2 & PAGE_TILE_HEIGHT_MASK) >> PAGE_TILE_HEIGHT_SHIFT); + const uint32_t w = 8 << ((attr2 & PAGE_TILE_WIDTH_MASK) >> PAGE_TILE_WIDTH_SHIFT); + +// if (!(m_video_regs[0x42] & SPRITE_COORD_TL_MASK)) +// { +// x = (160 + x) - w / 2; +// y = (120 - y) - (h / 2) + 8; +// } + + y = 0x1ff - y - 128 + 1; + x = x - 128 + 32; + + x -= (w / 2); + y -= (h / 2); + + x &= 0x01ff; + y &= 0x01ff; + + uint32_t tile_line = ((scanline - y)) % h; + int16_t test_y = (y + tile_line) & 0x1ff; + if (test_y >= 0x01c0) + test_y -= 0x0200; + + if (test_y != scanline) + { + return; + } + + //bool blend = (attr & 0x4000); + const uint8_t bpp = attr2 & 0x0003; + const uint32_t yflipmask = flip_y ? h - 1 : 0; + const uint32_t palette_offset = (attr2 & 0x0f00) >> 8; + + if (pri == priority) + { + if (flip_x) + draw<FlipXOn>(cliprect, tile_line, x, y, 0, bitmap_addr, tile, yflipmask, palette_offset, h, w, bpp); + else + draw<FlipXOff>(cliprect, tile_line, x, y, 0, bitmap_addr, tile, yflipmask, palette_offset, h, w, bpp); + } +} + + + +void spg110_video_device::draw_sprites(const rectangle &cliprect, uint32_t scanline, int priority) +{ + //if (!(m_video_regs[0x42] & SPRITE_ENABLE_MASK)) + //{ + // return; + //} + + for (uint32_t n = 0; n < 256; n++) + { + draw_sprite(cliprect, scanline, priority, n); + } +} + + +/* correct, 4bpp gfxs */ +static const gfx_layout charlayout = +{ + 8,8, + RGN_FRAC(1,1), + 4, + { STEP4(0,1) }, + { 0*4,1*4,2*4,3*4,4*4,5*4,6*4,7*4 }, + { STEP8(0,4*8) }, + 8*8*4 +}; + +static const gfx_layout charlayout6 = +{ + 8,8, + RGN_FRAC(1,1), + 6, + { 0,1,2,3,4,5 }, + { STEP8(0,6) }, + { STEP8(0,6*8) }, + 8*8*6 +}; + +static const gfx_layout char16layout = +{ + 16,16, + RGN_FRAC(1,1), + 4, + { STEP4(0,1) }, + { 0*4,1*4,2*4,3*4,4*4,5*4,6*4,7*4, 8*4,9*4,10*4,11*4,12*4,13*4,14*4,15*4 }, + { STEP16(0,4*16) }, + 16*16*4 +}; + +static const gfx_layout char32layout = +{ + 32,32, + RGN_FRAC(1,1), + 4, + { STEP4(0,1) }, + { STEP32(0,4) }, + { STEP32(0,4*32) }, + 32*32*4 +}; + + + +static GFXDECODE_START( gfx ) + GFXDECODE_ENTRY( ":maincpu", 0, charlayout, 0, 16 ) + GFXDECODE_ENTRY( ":maincpu", 0, char16layout, 0, 16 ) + GFXDECODE_ENTRY( ":maincpu", 0, char32layout, 0, 16 ) + GFXDECODE_ENTRY( ":maincpu", 0, charlayout6, 0, 16 ) // correct for lots of the tiles inc. startup text +GFXDECODE_END + + +void spg110_video_device::device_add_mconfig(machine_config &config) +{ + PALETTE(config, m_palette).set_entries(0x100); + + GFXDECODE(config, m_gfxdecode, m_palette, gfx); +} + + +device_memory_interface::space_config_vector spg110_video_device::memory_space_config() const +{ + return space_config_vector { + std::make_pair(0, &m_space_config) + }; +} + + +// irq source or similar? +READ16_MEMBER(spg110_video_device::spg110_2063_r) +{ + // checks for bits 0x20 and 0x08 in the IRQ function (all IRQs point to the same place) + + // HACK! jak_spdo checks for 0x400 or 0x200 starting some of the games + return m_video_irq_status | 0x600; +} + +WRITE16_MEMBER(spg110_video_device::spg110_2063_w) +{ + // writes 0x28, probably clears the IRQ / IRQ sources? 0x63 is the same offset for this in spg2xx but bits used seem to be different + const uint16_t old = m_video_irq_enable & m_video_irq_status; + m_video_irq_status &= ~data; + const uint16_t changed = old ^ (m_video_irq_enable & m_video_irq_status); + if (changed) + check_video_irq(); +} + + +WRITE16_MEMBER(spg110_video_device::spg110_201c_w) { logerror("%s: 201c: %04x\n", machine().describe_context(), data); } // during startup text only +WRITE16_MEMBER(spg110_video_device::spg110_2020_w) { COMBINE_DATA(&m_tilebase); logerror("%s: 2020: %04x\n", machine().describe_context(), data); } // confirmed as tile base, seems to apply to both layers and sprites, unlike spg2xx which has separate registers + +WRITE16_MEMBER(spg110_video_device::spg110_2028_w) { logerror("%s: 2028: %04x\n", machine().describe_context(), data); } // startup +READ16_MEMBER(spg110_video_device::spg110_2028_r) { return 0x0000; } + +WRITE16_MEMBER(spg110_video_device::spg110_2029_w) { logerror("%s: 2029: %04x\n", machine().describe_context(), data); } // 0006, 0008 on startup +READ16_MEMBER(spg110_video_device::spg110_2029_r) { return 0x0000; } + +WRITE16_MEMBER(spg110_video_device::spg110_2031_w) { logerror("%s: 2031: %04x\n", machine().describe_context(), data); } // 014a or 0000 when ball is in trap +WRITE16_MEMBER(spg110_video_device::spg110_2032_w) { logerror("%s: 2032: %04x\n", machine().describe_context(), data); } // 014a most of the time, 0000 very rarely +WRITE16_MEMBER(spg110_video_device::spg110_2033_w) { logerror("%s: 2033: %04x\n", machine().describe_context(), data); } // changes, situational, eg when pausing +WRITE16_MEMBER(spg110_video_device::spg110_2034_w) { logerror("%s: 2034: %04x\n", machine().describe_context(), data); } // 0141 on every scene transition +WRITE16_MEMBER(spg110_video_device::spg110_2035_w) { logerror("%s: 2035: %04x\n", machine().describe_context(), data); } // 0141 on every scene transition +WRITE16_MEMBER(spg110_video_device::spg110_2036_w) { logerror("%s: 2036: %04x\n", machine().describe_context(), data); COMBINE_DATA(&m_2036_scroll); } // seems related to ball y position, not scrolling (possibly shadow sprite related?) + +READ16_MEMBER(spg110_video_device::spg110_2037_r) { return 0x0000; } // added to something from the PRNG +WRITE16_MEMBER(spg110_video_device::spg110_2037_w) { logerror("%s: 2037: %04x\n", machine().describe_context(), data); } // 0126 (always?) + +WRITE16_MEMBER(spg110_video_device::spg110_2039_w) { logerror("%s: 2039: %04x\n", machine().describe_context(), data); } // 0803 on every scene transition + +WRITE16_MEMBER(spg110_video_device::spg110_203c_w) { logerror("%s: 203c: %04x\n", machine().describe_context(), data); } // 0006 on startup, twice + +WRITE16_MEMBER(spg110_video_device::spg110_203d_w) { logerror("%s: 203d: %04x\n", machine().describe_context(), data); } // changes, usually between scenes + +READ16_MEMBER(spg110_video_device::spg110_2042_r) { return 0x0000; } +WRITE16_MEMBER(spg110_video_device::spg110_2042_w) { logerror("%s: 2042: %04x\n", machine().describe_context(), data); } // sets bit 0x0004, masks with 0xfffb etc. + +WRITE16_MEMBER(spg110_video_device::spg110_2045_w) { logerror("%s: 2045: %04x\n", machine().describe_context(), data); } // 0006 on startup, once + + +WRITE16_MEMBER(spg110_video_device::spg110_205x_w) +{ + COMBINE_DATA(&m_palctrlram[offset]); +} + + +WRITE16_MEMBER(spg110_video_device::dma_unk_2061_w) { COMBINE_DATA(&m_dma_unk_2061); } +WRITE16_MEMBER(spg110_video_device::dma_dst_step_w) { COMBINE_DATA(&m_dma_dst_step); } +WRITE16_MEMBER(spg110_video_device::dma_unk_2067_w) { COMBINE_DATA(&m_dma_src_high); } +WRITE16_MEMBER(spg110_video_device::dma_src_step_w) { COMBINE_DATA(&m_dma_src_step); } + +WRITE16_MEMBER(spg110_video_device::dma_dst_w) { COMBINE_DATA(&m_dma_dst); } +WRITE16_MEMBER(spg110_video_device::dma_src_w) { COMBINE_DATA(&m_dma_src); } + +WRITE16_MEMBER(spg110_video_device::dma_len_trigger_w) +{ + int length = data & 0x1fff; + + // this is presumably a counter that underflows to 0x1fff, because that's what the wait loop waits for? + logerror("%s: (trigger len) %04x with values (unk) %04x (dststep) %04x (unk) %04x (src step) %04x | (dst) %04x (src) %04x\n", machine().describe_context(), data, m_dma_unk_2061, m_dma_dst_step, m_dma_src_high, m_dma_src_step, m_dma_dst, m_dma_src); + + if (m_dma_src_high != 0x0000) + { + logerror("unknown DMA params are not zero!\n"); + } + + int source = m_dma_src | m_dma_src_high << 16; + int dest = m_dma_dst; + + for (int i = 0; i < length; i++) + { + address_space &mem = m_cpu->space(AS_PROGRAM); + uint16_t val = mem.read_word(source); + + this->space(0).write_word(dest * 2, val, 0xffff); + + source+=m_dma_src_step; + dest+=m_dma_dst_step; + } + + // not sure, spiderman would suggest that some of these need to reset (unless a missing IRQ clears them) + m_dma_unk_2061 = 0; + m_dma_dst_step = 0; + m_dma_src_high = 0; + m_dma_src_step = 0; + m_dma_dst = 0; + m_dma_src = 0; + + // HACK: it really seems this interrupt status is related to the DMA, but jak_capb doesn't ack it, so must also be a way to disable it? + if (m_is_spiderman) + { + const int i = 0x0002; + + if (m_video_irq_enable & 1) + { + m_video_irq_status |= i; + check_video_irq(); + } + } +} + +WRITE16_MEMBER(spg110_video_device::dma_manual_w) +{ + this->space(0).write_word(m_dma_dst * 2, data, 0xffff); +} + +READ16_MEMBER(spg110_video_device::dma_manual_r) +{ + uint16_t val = this->space(0).read_word(m_dma_dst * 2); + return val; +} + +READ16_MEMBER(spg110_video_device::dma_len_status_r) +{ + return 0x1fff; // DMA related? +} + + +READ16_MEMBER(spg110_video_device::tmap0_regs_r) { return tmap0_regs[offset]; } +READ16_MEMBER(spg110_video_device::tmap1_regs_r) { return tmap1_regs[offset]; } + +void spg110_video_device::tilemap_write_regs(int which, uint16_t* regs, int regno, uint16_t data) +{ + switch (regno) + { + case 0x0: // Page X scroll + logerror("video_w: Page %d X Scroll = %04x\n", which, data & 0x01ff); + regs[regno] = data & 0x01ff; + break; + + case 0x1: // Page Y scroll + logerror("video_w: Page %d Y Scroll = %04x\n", which, data & 0x00ff); + regs[regno] = data & 0x00ff; + break; + + case 0x2: // Page Attributes + // 'priority' can't be priority here as it is on spg2xx, or the scores in attract will be behind the table, it really seems to be per attribute bit instead + + logerror("video_w: Page %d Attributes = %04x (Priority:%d, Palette:%d, VSize:%d, HSize:%d, FlipY:%d, FlipX:%d, BPP:%d)\n", which, data + , (data >> 12) & 3, (data >> 8) & 15, 8 << ((data >> 6) & 3), 8 << ((data >> 4) & 3), BIT(data, 3), BIT(data, 2), 2 * ((data & 3) + 1)); + regs[regno] = data; + break; + + case 0x3: // Page Control + logerror("video_w: Page %d Control = %04x (Blend:%d, HiColor:%d, RowScroll:%d, Enable:%d, Wallpaper:%d, RegSet:%d, Bitmap:%d)\n", which, data + , BIT(data, 8), BIT(data, 7), BIT(data, 4), BIT(data, 3), BIT(data, 2), BIT(data, 1), BIT(data, 0)); + regs[regno] = data; + break; + + case 0x4: // Page Tile Address + logerror("video_w: Page %d Tile Address = %04x\n", which, data); + regs[regno] = data; + break; + + case 0x5: // Page Attribute Address + logerror("video_w: Page %d Attribute Address = %04x\n", which, data); + regs[regno] = data; + break; + } +} + + +WRITE16_MEMBER(spg110_video_device::tmap0_regs_w) +{ + tilemap_write_regs(0, tmap0_regs,offset,data); +} + + +WRITE16_MEMBER(spg110_video_device::tmap1_regs_w) +{ + tilemap_write_regs(1, tmap1_regs,offset,data); +} + +// this seems to be a different, non-cpu mapped space only accessible via the DMA? +void spg110_video_device::map_video(address_map &map) +{ + // are these addresses hardcoded, or can they move (in which case tilemap system isn't really suitable) + map(0x00000, 0x03fff).ram(); // 2fff? + + map(0x04000, 0x041ff).ram().share("sprtileno"); // seems to be 3 blocks, almost certainly spritelist + map(0x04200, 0x043ff).ram().share("sprattr1"); + map(0x04400, 0x045ff).ram().share("sprattr2"); + + map(0x08000, 0x081ff).ram().w(FUNC(spg110_video_device::palette_w)).share("palram"); // palette format unknown +} + +void spg110_video_device::device_start() +{ + save_item(NAME(m_dma_src_step)); + save_item(NAME(m_dma_dst_step)); + save_item(NAME(m_dma_unk_2061)); + save_item(NAME(m_dma_src_high)); + save_item(NAME(m_dma_dst)); + save_item(NAME(m_dma_src)); + save_item(NAME(m_bg_scrollx)); + save_item(NAME(m_bg_scrolly)); + save_item(NAME(m_2036_scroll)); + + m_video_irq_cb.resolve(); + + if (!strcmp(machine().system().name, "jak_spdmo")) + m_is_spiderman = true; + else + m_is_spiderman = false; +} + +void spg110_video_device::device_reset() +{ + m_dma_src_step = 0; + m_dma_dst_step = 0; + m_dma_unk_2061 = 0; + m_dma_src_high = 0; + m_dma_dst = 0; + m_dma_src = 0; + m_bg_scrollx = 0; + m_bg_scrolly = 0; + m_2036_scroll = 0; + + // is there actually an enable register here? + m_video_irq_enable = 0xffff; + m_video_irq_status = 0x0000; +} + +double spg110_video_device::hue2rgb(double p, double q, double t) +{ + if (t < 0) t += 1; + if (t > 1) t -= 1; + if (t < 1 / 6.0f) return p + (q - p) * 6 * t; + if (t < 1 / 2.0f) return q; + if (t < 2 / 3.0f) return p + (q - p) * (2 / 3.0f - t) * 6; + return p; +} + + +// wrong format! +WRITE16_MEMBER(spg110_video_device::palette_w) +{ + // probably not + const double h_add = 0.65f; + const double h_divide = 43.2f; + + COMBINE_DATA(&m_palram[offset]); + + uint16_t dat = m_palram[offset]; + + // llll lsss sshh hhhh + int l_raw = (dat & 0xfe00) >> 10; + int sl_raw = (dat & 0x03c0) >> 6; + int h_raw = (dat & 0x003f) >> 0; + + double l = (double)l_raw / 63.0f; + double s = (double)sl_raw / 15.0f; + double h = (double)h_raw / h_divide; + + // probably not + h += h_add; + + if (h>1.0f) + h-= 1.0f; + + double r, g, b; + + if (s == 0) { + r = g = b = l; // greyscale + } else { + double q = l < 0.5f ? l * (1 + s) : l + s - l * s; + double p = 2 * l - q; + r = hue2rgb(p, q, h + 1/3.0f); + g = hue2rgb(p, q, h); + b = hue2rgb(p, q, h - 1/3.0f); + } + + int r_real = r * 255.0f; + int g_real = g * 255.0f; + int b_real = b * 255.0f; + + m_palette->set_pen_color(offset, r_real, g_real, b_real); +} + +uint32_t spg110_video_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + memset(&m_screenbuf[320 * cliprect.min_y], 0, 4 * 320 * ((cliprect.max_y - cliprect.min_y) + 1)); + + const uint32_t page1_addr = 0x40 * m_tilebase;//0x40 * m_video_regs[0x20]; + const uint32_t page2_addr = 0x40 * m_tilebase;//0x40 * m_video_regs[0x21]; + uint16_t *page1_regs = tmap0_regs; + uint16_t *page2_regs = tmap1_regs; + + for (uint32_t scanline = (uint32_t)cliprect.min_y; scanline <= (uint32_t)cliprect.max_y; scanline++) + { + for (int i = 0; i < 4; i++) + { + draw_page(cliprect, scanline, i, page2_addr, page2_regs); + draw_page(cliprect, scanline, i, page1_addr, page1_regs); + draw_sprites(cliprect, scanline, i); + } + } + + for (int y = cliprect.min_y; y <= cliprect.max_y; y++) + { + uint32_t *dest = &bitmap.pix32(y, cliprect.min_x); + uint32_t *src = &m_screenbuf[cliprect.min_x + 320 * y]; + memcpy(dest, src, sizeof(uint32_t) * ((cliprect.max_x - cliprect.min_x) + 1)); + } + + return 0; +} + +WRITE_LINE_MEMBER(spg110_video_device::vblank) +{ + const int i = 0x0008; + + if (!state) + { + m_video_irq_status &= ~i; + check_video_irq(); + return; + } + + if (m_video_irq_enable & 1) + { + m_video_irq_status |= i; + check_video_irq(); + } +} + +void spg110_video_device::check_video_irq() +{ + m_video_irq_cb((m_video_irq_status & m_video_irq_enable) ? ASSERT_LINE : CLEAR_LINE); +}
\ No newline at end of file diff --git a/src/devices/machine/spg110_video.h b/src/devices/machine/spg110_video.h new file mode 100644 index 00000000000..bd8a7fa8e04 --- /dev/null +++ b/src/devices/machine/spg110_video.h @@ -0,0 +1,171 @@ +// license:BSD-3-Clause +// copyright-holders:David Haywood + +#ifndef MAME_MACHINE_SPG110_VIDEO_H +#define MAME_MACHINE_SPG110_VIDEO_H + +#pragma once + +#include "cpu/unsp/unsp.h" +#include "emupal.h" +#include "screen.h" +//#include "machine/timer.h" + + +class spg110_video_device : public device_t, public device_memory_interface + +{ +public: + spg110_video_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock); + spg110_video_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + template <typename T, typename U> + spg110_video_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, T &&cpu_tag, U &&screen_tag) + : spg110_video_device(mconfig, tag, owner, clock) + { + m_cpu.set_tag(std::forward<T>(cpu_tag)); + m_screen.set_tag(std::forward<U>(screen_tag)); + } + + void map_video(address_map &map); + + double hue2rgb(double p, double q, double t); + uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); + DECLARE_WRITE_LINE_MEMBER(vblank); + + DECLARE_WRITE16_MEMBER(spg110_201c_w); + DECLARE_WRITE16_MEMBER(spg110_2020_w); + + DECLARE_WRITE16_MEMBER(spg110_2028_w); + DECLARE_WRITE16_MEMBER(spg110_2029_w); + + DECLARE_READ16_MEMBER(spg110_2028_r); + DECLARE_READ16_MEMBER(spg110_2029_r); + + DECLARE_WRITE16_MEMBER(spg110_2031_w); + DECLARE_WRITE16_MEMBER(spg110_2032_w); + DECLARE_WRITE16_MEMBER(spg110_2033_w); + DECLARE_WRITE16_MEMBER(spg110_2034_w); + DECLARE_WRITE16_MEMBER(spg110_2035_w); + DECLARE_WRITE16_MEMBER(spg110_2036_w); + DECLARE_WRITE16_MEMBER(spg110_2037_w); + DECLARE_WRITE16_MEMBER(spg110_2039_w); + + DECLARE_WRITE16_MEMBER(spg110_203c_w); + DECLARE_WRITE16_MEMBER(spg110_203d_w); + + DECLARE_WRITE16_MEMBER(spg110_2042_w); + + DECLARE_WRITE16_MEMBER(spg110_2045_w); + + DECLARE_WRITE16_MEMBER(spg110_205x_w); + + + DECLARE_READ16_MEMBER(spg110_2037_r); + DECLARE_READ16_MEMBER(spg110_2042_r); + + DECLARE_WRITE16_MEMBER(dma_dst_w); + DECLARE_WRITE16_MEMBER(dma_unk_2061_w); + DECLARE_WRITE16_MEMBER(dma_len_trigger_w); + DECLARE_WRITE16_MEMBER(spg110_2063_w); + DECLARE_WRITE16_MEMBER(dma_dst_step_w); + DECLARE_WRITE16_MEMBER(dma_src_w); + DECLARE_WRITE16_MEMBER(dma_unk_2067_w); + DECLARE_WRITE16_MEMBER(dma_src_step_w); + + DECLARE_READ16_MEMBER(dma_len_status_r); + DECLARE_READ16_MEMBER(spg110_2063_r); + + DECLARE_READ16_MEMBER(dma_manual_r); + DECLARE_WRITE16_MEMBER(dma_manual_w); + + DECLARE_READ16_MEMBER(tmap0_regs_r); + DECLARE_READ16_MEMBER(tmap1_regs_r); + DECLARE_WRITE16_MEMBER(tmap0_regs_w); + DECLARE_WRITE16_MEMBER(tmap1_regs_w); + + auto write_video_irq_callback() { return m_video_irq_cb.bind(); }; + +protected: + virtual void device_start() override; + virtual void device_reset() override; + + virtual void device_add_mconfig(machine_config &config) override; + + virtual space_config_vector memory_space_config() const override; + + address_space_config m_space_config; + +private: + enum + { + PAGE_ENABLE_MASK = 0x0008, + PAGE_WALLPAPER_MASK = 0x0004, + + PAGE_PRIORITY_FLAG_MASK = 0x3000, + PAGE_PRIORITY_FLAG_SHIFT = 12, + PAGE_TILE_HEIGHT_MASK = 0x00c0, + PAGE_TILE_HEIGHT_SHIFT = 6, + PAGE_TILE_WIDTH_MASK = 0x0030, + PAGE_TILE_WIDTH_SHIFT = 4, + + TILE_X_FLIP = 0x0004, + TILE_Y_FLIP = 0x0008 + }; + + enum flipx_t : bool + { + FlipXOff = false, + FlipXOn = true + }; + + required_device<unsp_device> m_cpu; + required_device<screen_device> m_screen; + required_device<palette_device> m_palette; + required_device<gfxdecode_device> m_gfxdecode; + required_shared_ptr<uint16_t> m_palram; + required_shared_ptr<uint16_t> m_palctrlram; + required_shared_ptr<uint16_t> m_sprtileno; + required_shared_ptr<uint16_t> m_sprattr1; + required_shared_ptr<uint16_t> m_sprattr2; + + DECLARE_WRITE16_MEMBER(palette_w); + + uint16_t tmap0_regs[0x6]; + uint16_t tmap1_regs[0x6]; + + uint16_t m_dma_src_step; + uint16_t m_dma_dst_step; + uint16_t m_dma_unk_2061; + uint16_t m_dma_src_high; + + uint16_t m_dma_dst; + uint16_t m_dma_src; + + uint16_t m_bg_scrollx; + uint16_t m_bg_scrolly; + uint16_t m_2036_scroll; + + uint16_t m_tilebase; + + uint16_t m_video_irq_enable; + uint16_t m_video_irq_status; + void check_video_irq(); + + void tilemap_write_regs(int which, uint16_t* regs, int regno, uint16_t data); + + template<flipx_t FlipX> + void draw(const rectangle &cliprect, uint32_t line, uint32_t xoff, uint32_t yoff, uint32_t ctrl, uint32_t bitmap_addr, uint16_t tile, uint8_t yflipmask, uint8_t pal, int32_t h, int32_t w, uint8_t bpp); + void draw_page(const rectangle &cliprect, uint32_t scanline, int priority, uint32_t bitmap_addr, uint16_t *regs); + void draw_sprite(const rectangle &cliprect, uint32_t scanline, int priority, uint32_t base_addr); + void draw_sprites(const rectangle &cliprect, uint32_t scanline, int priority); + + uint32_t m_screenbuf[320 * 240]; + bool m_is_spiderman; + + devcb_write_line m_video_irq_cb; +}; + +DECLARE_DEVICE_TYPE(SPG110_VIDEO, spg110_video_device) + +#endif // MAME_MACHINE_SPG110_VIDEO_H diff --git a/src/devices/machine/spg2xx.cpp b/src/devices/machine/spg2xx.cpp index 5345f12b639..6d9d18fb3a2 100644 --- a/src/devices/machine/spg2xx.cpp +++ b/src/devices/machine/spg2xx.cpp @@ -17,55 +17,14 @@ DEFINE_DEVICE_TYPE(SPG24X, spg24x_device, "spg24x", "SPG240-series System-on-a-Chip") DEFINE_DEVICE_TYPE(SPG28X, spg28x_device, "spg28x", "SPG280-series System-on-a-Chip") -#define LOG_IO_READS (1U << 1) -#define LOG_IO_WRITES (1U << 2) -#define LOG_UNKNOWN_IO (1U << 3) -#define LOG_IRQS (1U << 4) -#define LOG_VLINES (1U << 5) -#define LOG_GPIO (1U << 6) -#define LOG_UART (1U << 7) -#define LOG_I2C (1U << 8) -#define LOG_DMA (1U << 9) -#define LOG_SEGMENT (1U << 10) -#define LOG_WATCHDOG (1U << 11) -#define LOG_TIMERS (1U << 12) -#define LOG_SPU_READS (1U << 13) -#define LOG_SPU_WRITES (1U << 14) -#define LOG_UNKNOWN_SPU (1U << 15) -#define LOG_CHANNEL_READS (1U << 16) -#define LOG_CHANNEL_WRITES (1U << 17) -#define LOG_ENVELOPES (1U << 18) -#define LOG_SAMPLES (1U << 19) -#define LOG_RAMPDOWN (1U << 20) -#define LOG_BEAT (1U << 21) -#define LOG_PPU_READS (1U << 22) -#define LOG_PPU_WRITES (1U << 23) -#define LOG_UNKNOWN_PPU (1U << 24) -#define LOG_FIQ (1U << 25) -#define LOG_SIO (1U << 26) -#define LOG_EXT_MEM (1U << 27) -#define LOG_EXTINT (1U << 28) -#define LOG_IO (LOG_IO_READS | LOG_IO_WRITES | LOG_IRQS | LOG_GPIO | LOG_UART | LOG_I2C | LOG_DMA | LOG_TIMERS | LOG_EXTINT | LOG_UNKNOWN_IO) -#define LOG_CHANNELS (LOG_CHANNEL_READS | LOG_CHANNEL_WRITES) -#define LOG_SPU (LOG_SPU_READS | LOG_SPU_WRITES | LOG_UNKNOWN_SPU | LOG_CHANNEL_READS | LOG_CHANNEL_WRITES \ - | LOG_ENVELOPES | LOG_SAMPLES | LOG_RAMPDOWN | LOG_BEAT) -#define LOG_PPU (LOG_PPU_READS | LOG_PPU_WRITES | LOG_UNKNOWN_PPU) -#define LOG_ALL (LOG_IO | LOG_SPU | LOG_PPU | LOG_VLINES | LOG_SEGMENT | LOG_FIQ) - -#define VERBOSE (0) -#include "logmacro.h" - -#define SPG_DEBUG_VIDEO (0) - -#define IO_IRQ_ENABLE m_io_regs[0x21] -#define IO_IRQ_STATUS m_io_regs[0x22] -#define VIDEO_IRQ_ENABLE m_video_regs[0x62] -#define VIDEO_IRQ_STATUS m_video_regs[0x63] spg2xx_device::spg2xx_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) : device_t(mconfig, type, tag, owner, clock) , device_mixer_interface(mconfig, *this, 2) , m_spg_audio(*this, "spgaudio") + , m_spg_io(*this, "spgio") + , m_spg_sysdma(*this, "spgsysdma") + , m_spg_video(*this, "spgvideo") , m_rowscrolloffset(15) , m_porta_out(*this) , m_portb_out(*this) @@ -80,9 +39,6 @@ spg2xx_device::spg2xx_device(const machine_config &mconfig, device_type type, co , m_chip_sel(*this) , m_cpu(*this, finder_base::DUMMY_TAG) , m_screen(*this, finder_base::DUMMY_TAG) - , m_scrollram(*this, "scrollram") - , m_paletteram(*this, "paletteram") - , m_spriteram(*this, "spriteram") { } @@ -99,28 +55,20 @@ spg28x_device::spg28x_device(const machine_config &mconfig, const char *tag, dev void spg2xx_device::map(address_map &map) { map(0x000000, 0x0027ff).ram(); - map(0x002800, 0x0028ff).rw(FUNC(spg2xx_device::video_r), FUNC(spg2xx_device::video_w)); - map(0x002900, 0x002aff).ram().share("scrollram"); - map(0x002b00, 0x002bff).ram().share("paletteram"); - map(0x002c00, 0x002fff).ram().share("spriteram"); + map(0x002800, 0x0028ff).rw(m_spg_video, FUNC(spg2xx_video_device::video_r), FUNC(spg2xx_video_device::video_w)); + map(0x002900, 0x002aff).ram().share("spgvideo:scrollram"); + map(0x002b00, 0x002bff).ram().share("spgvideo:paletteram"); + map(0x002c00, 0x002fff).ram().share("spgvideo:spriteram"); map(0x003000, 0x0031ff).rw(m_spg_audio, FUNC(spg2xx_audio_device::audio_r), FUNC(spg2xx_audio_device::audio_w)); map(0x003200, 0x0033ff).rw(m_spg_audio, FUNC(spg2xx_audio_device::audio_phase_r), FUNC(spg2xx_audio_device::audio_phase_w)); map(0x003400, 0x0037ff).rw(m_spg_audio, FUNC(spg2xx_audio_device::audio_ctrl_r), FUNC(spg2xx_audio_device::audio_ctrl_w)); - map(0x003d00, 0x003eff).rw(FUNC(spg2xx_device::io_r), FUNC(spg2xx_device::io_w)); + map(0x003d00, 0x003d2f).rw(m_spg_io, FUNC(spg2xx_io_device::io_r), FUNC(spg2xx_io_device::io_w)); + map(0x003d30, 0x003dff).rw(m_spg_io, FUNC(spg2xx_io_device::io_extended_r), FUNC(spg2xx_io_device::io_extended_w)); + map(0x003e00, 0x003e03).rw(m_spg_sysdma, FUNC(spg2xx_sysdma_device::dma_r), FUNC(spg2xx_sysdma_device::dma_w)); } void spg2xx_device::device_start() { - for (uint8_t i = 0; i < 32; i++) - { - m_rgb5_to_rgb8[i] = (i << 3) | (i >> 2); - } - for (uint16_t i = 0; i < 0x8000; i++) - { - m_rgb555_to_rgb888[i] = (m_rgb5_to_rgb8[(i >> 10) & 0x1f] << 16) | - (m_rgb5_to_rgb8[(i >> 5) & 0x1f] << 8) | - (m_rgb5_to_rgb8[(i >> 0) & 0x1f] << 0); - } m_porta_out.resolve_safe(); m_portb_out.resolve_safe(); m_portc_out.resolve_safe(); @@ -134,2028 +82,115 @@ void spg2xx_device::device_start() m_uart_tx.resolve_safe(); m_chip_sel.resolve_safe(); - m_tmb1 = timer_alloc(TIMER_TMB1); - m_tmb2 = timer_alloc(TIMER_TMB2); - m_tmb1->adjust(attotime::never); - m_tmb2->adjust(attotime::never); - - m_screenpos_timer = timer_alloc(TIMER_SCREENPOS); - m_screenpos_timer->adjust(attotime::never); - - m_uart_tx_timer = timer_alloc(TIMER_UART_TX); - m_uart_tx_timer->adjust(attotime::never); - - m_uart_rx_timer = timer_alloc(TIMER_UART_RX); - m_uart_rx_timer->adjust(attotime::never); - - m_4khz_timer = timer_alloc(TIMER_4KHZ); - m_4khz_timer->adjust(attotime::never); - - m_timer_src_ab = timer_alloc(TIMER_SRC_AB); - m_timer_src_ab->adjust(attotime::never); - - m_timer_src_c = timer_alloc(TIMER_SRC_C); - m_timer_src_c->adjust(attotime::never); - - save_item(NAME(m_timer_a_preload)); - save_item(NAME(m_timer_b_preload)); - save_item(NAME(m_timer_b_divisor)); - save_item(NAME(m_timer_b_tick_rate)); - - save_item(NAME(m_hide_page0)); - save_item(NAME(m_hide_page1)); - save_item(NAME(m_hide_sprites)); - save_item(NAME(m_debug_sprites)); - save_item(NAME(m_debug_blit)); - save_item(NAME(m_debug_palette)); - save_item(NAME(m_sprite_index_to_debug)); - - save_item(NAME(m_io_regs)); - save_item(NAME(m_uart_rx_fifo)); - save_item(NAME(m_uart_rx_fifo_start)); - save_item(NAME(m_uart_rx_fifo_end)); - save_item(NAME(m_uart_rx_fifo_count)); - save_item(NAME(m_uart_rx_available)); - save_item(NAME(m_uart_rx_irq)); - save_item(NAME(m_uart_tx_irq)); - - save_item(NAME(m_extint)); - - save_item(NAME(m_video_regs)); save_item(NAME(m_sprite_limit)); save_item(NAME(m_pal_flag)); - - save_item(NAME(m_2khz_divider)); - save_item(NAME(m_1khz_divider)); - save_item(NAME(m_4hz_divider)); - - save_item(NAME(m_uart_baud_rate)); } void spg2xx_device::device_reset() { - memset(m_video_regs, 0, 0x100 * sizeof(uint16_t)); - memset(m_io_regs, 0, 0x200 * sizeof(uint16_t)); - - m_timer_a_preload = 0; - m_timer_b_preload = 0; - m_timer_b_divisor = 0; - m_timer_b_tick_rate = 0; - - m_io_regs[0x23] = 0x0028; - m_io_regs[0x2c] = 0x1418; - m_io_regs[0x2d] = 0x1658; - - m_uart_rx_available = false; - memset(m_uart_rx_fifo, 0, ARRAY_LENGTH(m_uart_rx_fifo)); - m_uart_rx_fifo_start = 0; - m_uart_rx_fifo_end = 0; - m_uart_rx_fifo_count = 0; - m_uart_tx_irq = false; - m_uart_rx_irq = false; - - memset(m_extint, 0, sizeof(bool) * 2); - - m_video_regs[0x36] = 0xffff; - m_video_regs[0x37] = 0xffff; - m_video_regs[0x3c] = 0x0020; - m_video_regs[0x42] = 0x0001; - - m_hide_page0 = false; - m_hide_page1 = false; - m_hide_sprites = false; - m_debug_sprites = false; - m_debug_blit = false; - m_debug_palette = false; - m_sprite_index_to_debug = 0; - - m_4khz_timer->adjust(attotime::from_hz(4096), 0, attotime::from_hz(4096)); - - m_2khz_divider = 0; - m_1khz_divider = 0; - m_4hz_divider = 0; } -WRITE_LINE_MEMBER(spg2xx_device::audioirq_w) +WRITE_LINE_MEMBER(spg2xx_device::videoirq_w) { - if (state == ASSERT_LINE) - { - m_cpu->set_state_unsynced(UNSP_IRQ4_LINE, ASSERT_LINE); - } - else - { - m_cpu->set_state_unsynced(UNSP_IRQ4_LINE, CLEAR_LINE); - } + m_cpu->set_state_unsynced(UNSP_IRQ0_LINE, state); } -READ16_MEMBER(spg2xx_device::space_r) +WRITE_LINE_MEMBER(spg2xx_device::timerirq_w) { - address_space &cpuspace = m_cpu->space(AS_PROGRAM); - return cpuspace.read_word(offset); + m_cpu->set_state_unsynced(UNSP_IRQ2_LINE, state); } -/************************* -* Video Hardware * -*************************/ - -// Perform a lerp between a and b -inline uint8_t spg2xx_device::mix_channel(uint8_t bottom, uint8_t top) +WRITE_LINE_MEMBER(spg2xx_device::uartirq_w) { - uint8_t alpha = (m_video_regs[0x2a] & 3) << 6; - return ((256 - alpha) * bottom + alpha * top) >> 8; + m_cpu->set_state_unsynced(UNSP_IRQ3_LINE, state); } -template<spg2xx_device::blend_enable_t Blend, spg2xx_device::rowscroll_enable_t RowScroll, spg2xx_device::flipx_t FlipX> -void spg2xx_device::blit(const rectangle &cliprect, uint32_t line, uint32_t xoff, uint32_t yoff, uint32_t attr, uint32_t ctrl, uint32_t bitmap_addr, uint16_t tile) -{ - address_space &space = m_cpu->space(AS_PROGRAM); - - int32_t h = 8 << ((attr & PAGE_TILE_HEIGHT_MASK) >> PAGE_TILE_HEIGHT_SHIFT); - int32_t w = 8 << ((attr & PAGE_TILE_WIDTH_MASK) >> PAGE_TILE_WIDTH_SHIFT); - - uint32_t yflipmask = attr & TILE_Y_FLIP ? h - 1 : 0; - - uint32_t nc = ((attr & 0x0003) + 1) << 1; - - uint32_t palette_offset = (attr & 0x0f00) >> 4; - if (SPG_DEBUG_VIDEO && m_debug_blit) - { - printf("s:%d line:%d xy:%08x,%08x attr:%08x ctrl:%08x bitmap_addr:%08x tile:%04x\n", cliprect.min_x, line, xoff, yoff, attr, ctrl, bitmap_addr, tile); - printf("hw:%d,%d f:%d,%d yfm:%d ncols:%d pobs:%02x ", w, h, (attr & TILE_X_FLIP) ? 1 : 0, (attr & TILE_Y_FLIP) ? 1 : 0, yflipmask, nc, palette_offset); - } - palette_offset >>= nc; - palette_offset <<= nc; - if (SPG_DEBUG_VIDEO && m_debug_blit) - { - printf("poas:%02x\n", palette_offset); - } - - uint32_t bits_per_row = nc * w / 16; - uint32_t words_per_tile = bits_per_row * h; - uint32_t m = bitmap_addr + words_per_tile * tile + bits_per_row * (line ^ yflipmask); - uint32_t bits = 0; - uint32_t nbits = 0; - uint32_t y = line; - - int yy = (yoff + y) & 0x1ff; - if (yy >= 0x01c0) - yy -= 0x0200; - - if (yy > 240 || yy < 0) - return; - - if (SPG_DEBUG_VIDEO && m_debug_blit) - printf("%3d:\n", yy); - - int y_index = yy * 320; - - for (int32_t x = FlipX ? (w - 1) : 0; FlipX ? x >= 0 : x < w; FlipX ? x-- : x++) - { - int xx = xoff + x; - - bits <<= nc; - if (SPG_DEBUG_VIDEO && m_debug_blit) - printf(" %08x:%d ", bits, nbits); - if (nbits < nc) - { - uint16_t b = space.read_word(m++ & 0x3fffff); - b = (b << 8) | (b >> 8); - bits |= b << (nc - nbits); - nbits += 16; - if (SPG_DEBUG_VIDEO && m_debug_blit) - printf("(%04x:%08x:%d) ", b, bits, nbits); - } - nbits -= nc; - - uint32_t pal = palette_offset + (bits >> 16); - if (SPG_DEBUG_VIDEO && m_debug_blit) - printf("%02x:%02x:%04x ", bits >> 16, pal, bits & 0xffff); - bits &= 0xffff; - - if (RowScroll) - xx -= (int16_t)m_scrollram[(yy + m_rowscrolloffset) & 0x1ff]; - - xx &= 0x01ff; - if (xx >= 0x01c0) - xx -= 0x0200; - - if (xx >= 0 && xx < 320) - { - int pix_index = xx + y_index; - - uint16_t rgb = m_paletteram[pal]; - if (SPG_DEBUG_VIDEO && m_debug_blit) - printf("rgb:%04x ", rgb); - - if (!(rgb & 0x8000)) - { - if (Blend) - { - if (SPG_DEBUG_VIDEO && m_debug_blit) - printf("M\n"); - m_screenbuf[pix_index] = (mix_channel((uint8_t)(m_screenbuf[pix_index] >> 16), m_rgb5_to_rgb8[(rgb >> 10) & 0x1f]) << 16) | - (mix_channel((uint8_t)(m_screenbuf[pix_index] >> 8), m_rgb5_to_rgb8[(rgb >> 5) & 0x1f]) << 8) | - (mix_channel((uint8_t)(m_screenbuf[pix_index] >> 0), m_rgb5_to_rgb8[rgb & 0x1f])); - } - else - { - if (SPG_DEBUG_VIDEO && m_debug_blit) - printf("S\n"); - m_screenbuf[pix_index] = m_rgb555_to_rgb888[rgb]; - } - } - else if (SPG_DEBUG_VIDEO && m_debug_blit) - { - printf("X\n"); - } - } - } -} - -void spg2xx_device::blit_page(const rectangle &cliprect, uint32_t scanline, int depth, uint32_t bitmap_addr, uint16_t *regs) -{ - uint32_t xscroll = regs[0]; - uint32_t yscroll = regs[1]; - uint32_t attr = regs[2]; - uint32_t ctrl = regs[3]; - uint32_t tilemap = regs[4]; - uint32_t palette_map = regs[5]; - address_space &space = m_cpu->space(AS_PROGRAM); - - if (!(ctrl & PAGE_ENABLE_MASK)) - { - return; - } - - if (((attr & PAGE_DEPTH_FLAG_MASK) >> PAGE_DEPTH_FLAG_SHIFT) != depth) - { - return; - } - - uint32_t tile_h = 8 << ((attr & PAGE_TILE_HEIGHT_MASK) >> PAGE_TILE_HEIGHT_SHIFT); - uint32_t tile_w = 8 << ((attr & PAGE_TILE_WIDTH_MASK) >> PAGE_TILE_WIDTH_SHIFT); - - uint32_t tile_count_x = 512 / tile_w; - - uint32_t bitmap_y = (scanline + yscroll) & 0xff; - uint32_t y0 = bitmap_y / tile_h; - uint32_t tile_scanline = bitmap_y % tile_h; - uint32_t tile_address = tile_count_x * y0; - if (SPG_DEBUG_VIDEO && machine().input().code_pressed(KEYCODE_H)) - printf("s:%3d | baddr:%08x | yscr:%3d | bity:%3d | y0:%2d | ts:%2d\n", scanline, bitmap_addr, yscroll, bitmap_y, y0, tile_scanline); - - if (SPG_DEBUG_VIDEO && machine().input().code_pressed(KEYCODE_EQUALS)) - m_debug_blit = true; - for (uint32_t x0 = 0; x0 < tile_count_x; x0++, tile_address++) - { - uint32_t yy = ((tile_h * y0 - yscroll + 0x10) & 0xff) - 0x10; - uint32_t xx = (tile_w * x0 - xscroll) & 0x1ff; - uint16_t tile = (ctrl & PAGE_WALLPAPER_MASK) ? space.read_word(tilemap) : space.read_word(tilemap + tile_address); - uint16_t palette = 0; - - if (!tile) - continue; - - palette = (ctrl & PAGE_WALLPAPER_MASK) ? space.read_word(palette_map) : space.read_word(palette_map + tile_address / 2); - if (x0 & 1) - palette >>= 8; - - uint32_t tileattr = attr; - uint32_t tilectrl = ctrl; - if ((ctrl & 2) == 0) - { // -(1) bld(1) flip(2) pal(4) - tileattr &= ~0x000c; - tileattr |= (palette >> 2) & 0x000c; // flip - - tileattr &= ~0x0f00; - tileattr |= (palette << 8) & 0x0f00; // palette - - tilectrl &= ~0x0100; - tilectrl |= (palette << 2) & 0x0100; // blend - } - - bool blend = (tileattr & 0x4000 || tilectrl & 0x0100); - bool row_scroll = (tilectrl & 0x0010); - bool flip_x = (tileattr & TILE_X_FLIP); - - if (blend) - { - if (row_scroll) - { - if (flip_x) - blit<BlendOn, RowScrollOn, FlipXOn>(cliprect, tile_scanline, xx, yy, tileattr, tilectrl, bitmap_addr, tile); - else - blit<BlendOn, RowScrollOn, FlipXOff>(cliprect, tile_scanline, xx, yy, tileattr, tilectrl, bitmap_addr, tile); - } - else - { - if (flip_x) - blit<BlendOn, RowScrollOff, FlipXOn>(cliprect, tile_scanline, xx, yy, tileattr, tilectrl, bitmap_addr, tile); - else - blit<BlendOn, RowScrollOff, FlipXOff>(cliprect, tile_scanline, xx, yy, tileattr, tilectrl, bitmap_addr, tile); - } - } - else - { - if (row_scroll) - { - if (flip_x) - blit<BlendOff, RowScrollOn, FlipXOn>(cliprect, tile_scanline, xx, yy, tileattr, tilectrl, bitmap_addr, tile); - else - blit<BlendOff, RowScrollOn, FlipXOff>(cliprect, tile_scanline, xx, yy, tileattr, tilectrl, bitmap_addr, tile); - } - else - { - if (flip_x) - blit<BlendOff, RowScrollOff, FlipXOn>(cliprect, tile_scanline, xx, yy, tileattr, tilectrl, bitmap_addr, tile); - else - blit<BlendOff, RowScrollOff, FlipXOff>(cliprect, tile_scanline, xx, yy, tileattr, tilectrl, bitmap_addr, tile); - } - } - } - if (SPG_DEBUG_VIDEO && machine().input().code_pressed(KEYCODE_EQUALS)) - m_debug_blit = false; -} - -void spg2xx_device::blit_sprite(const rectangle &cliprect, uint32_t scanline, int depth, uint32_t base_addr) -{ - uint32_t bitmap_addr = 0x40 * m_video_regs[0x22]; - uint16_t tile = m_spriteram[base_addr + 0]; - int16_t x = m_spriteram[base_addr + 1]; - int16_t y = m_spriteram[base_addr + 2]; - uint16_t attr = m_spriteram[base_addr + 3]; - - if (!tile) - { - return; - } - - if (((attr & PAGE_DEPTH_FLAG_MASK) >> PAGE_DEPTH_FLAG_SHIFT) != depth) - { - return; - } - - const uint32_t h = 8 << ((attr & PAGE_TILE_HEIGHT_MASK) >> PAGE_TILE_HEIGHT_SHIFT); - const uint32_t w = 8 << ((attr & PAGE_TILE_WIDTH_MASK) >> PAGE_TILE_WIDTH_SHIFT); - - if (!(m_video_regs[0x42] & SPRITE_COORD_TL_MASK)) - { - x = (160 + x) - w / 2; - y = (120 - y) - (h / 2) + 8; - } - - x &= 0x01ff; - y &= 0x01ff; - - uint32_t tile_line = ((scanline - y) + 0x200) % h; - int16_t test_y = (y + tile_line) & 0x1ff; - if (test_y >= 0x01c0) - test_y -= 0x0200; - - if (test_y != scanline) - { - return; - } - - bool blend = (attr & 0x4000); - bool flip_x = (attr & TILE_X_FLIP); - -#if SPG_DEBUG_VIDEO - if (m_debug_sprites && machine().input().code_pressed(KEYCODE_MINUS)) - m_debug_blit = true; - if (blend) - { - if (flip_x) - blit<BlendOn, RowScrollOff, FlipXOn>(cliprect, tile_line, x, y, attr, 0, bitmap_addr, tile); - else - blit<BlendOn, RowScrollOff, FlipXOff>(cliprect, tile_line, x, y, attr, 0, bitmap_addr, tile); - } - else - { - if (flip_x) - blit<BlendOff, RowScrollOff, FlipXOn>(cliprect, tile_line, x, y, attr, 0, bitmap_addr, tile); - else - blit<BlendOff, RowScrollOff, FlipXOff>(cliprect, tile_line, x, y, attr, 0, bitmap_addr, tile); - } - m_debug_blit = false; -#else - if (blend) - { - if (flip_x) - blit<BlendOn, RowScrollOff, FlipXOn>(cliprect, tile_line, x, y, attr, 0, bitmap_addr, tile); - else - blit<BlendOn, RowScrollOff, FlipXOff>(cliprect, tile_line, x, y, attr, 0, bitmap_addr, tile); - } - else - { - if (flip_x) - blit<BlendOff, RowScrollOff, FlipXOn>(cliprect, tile_line, x, y, attr, 0, bitmap_addr, tile); - else - blit<BlendOff, RowScrollOff, FlipXOff>(cliprect, tile_line, x, y, attr, 0, bitmap_addr, tile); - } -#endif -} - -void spg2xx_device::blit_sprites(const rectangle &cliprect, uint32_t scanline, int depth) -{ - if (!(m_video_regs[0x42] & SPRITE_ENABLE_MASK)) - { - return; - } - -#if SPG_DEBUG_VIDEO - if (!m_debug_sprites) - { -#endif - for (uint32_t n = 0; n < m_sprite_limit; n++) - { - blit_sprite(cliprect, scanline, depth, 4 * n); - } -#if SPG_DEBUG_VIDEO - } - else - { - blit_sprite(cliprect, scanline, depth, 4 * m_sprite_index_to_debug); - } -#endif -} - -void spg2xx_device::apply_saturation(const rectangle &cliprect) -{ - static const float s_u8_to_float = 1.0f / 255.0f; - static const float s_gray_r = 0.299f; - static const float s_gray_g = 0.587f; - static const float s_gray_b = 0.114f; - const float sat_adjust = (0xff - (m_video_regs[0x3c] & 0x00ff)) / (float)(0xff - 0x20); - for (int y = cliprect.min_y; y <= cliprect.max_y; y++) - { - uint32_t *src = &m_screenbuf[cliprect.min_x + 320 * y]; - for (int x = cliprect.min_x; x <= cliprect.max_x; x++) - { - const uint32_t src_rgb = *src; - const float src_r = (uint8_t)(src_rgb >> 16) * s_u8_to_float; - const float src_g = (uint8_t)(src_rgb >> 8) * s_u8_to_float; - const float src_b = (uint8_t)(src_rgb >> 0) * s_u8_to_float; - const float luma = src_r * s_gray_r + src_g * s_gray_g + src_b * s_gray_b; - const float adjusted_r = luma + (src_r - luma) * sat_adjust; - const float adjusted_g = luma + (src_g - luma) * sat_adjust; - const float adjusted_b = luma + (src_b - luma) * sat_adjust; - const int integer_r = (int)floor(adjusted_r * 255.0f); - const int integer_g = (int)floor(adjusted_g * 255.0f); - const int integer_b = (int)floor(adjusted_b * 255.0f); - *src++ = (integer_r > 255 ? 0xff0000 : (integer_r < 0 ? 0 : ((uint8_t)integer_r << 16))) | - (integer_g > 255 ? 0x00ff00 : (integer_g < 0 ? 0 : ((uint8_t)integer_g << 8))) | - (integer_b > 255 ? 0x0000ff : (integer_b < 0 ? 0 : (uint8_t)integer_b)); - } - } -} - -void spg2xx_device::apply_fade(const rectangle &cliprect) -{ - const uint16_t fade_offset = m_video_regs[0x30]; - for (int y = cliprect.min_y; y <= cliprect.max_y; y++) - { - uint32_t *src = &m_screenbuf[cliprect.min_x + 320 * y]; - for (int x = cliprect.min_x; x <= cliprect.max_x; x++) - { - const uint32_t src_rgb = *src; - const uint8_t src_r = (src_rgb >> 16) & 0xff; - const uint8_t src_g = (src_rgb >> 8) & 0xff; - const uint8_t src_b = (src_rgb >> 0) & 0xff; - const uint8_t r = src_r - fade_offset; - const uint8_t g = src_g - fade_offset; - const uint8_t b = src_b - fade_offset; - *src++ = (r > src_r ? 0 : (r << 16)) | - (g > src_g ? 0 : (g << 8)) | - (b > src_b ? 0 : (b << 0)); - } - } -} - -uint32_t spg2xx_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) -{ - memset(&m_screenbuf[320 * cliprect.min_y], 0, 4 * 320 * ((cliprect.max_y - cliprect.min_y) + 1)); - - const uint32_t page1_addr = 0x40 * m_video_regs[0x20]; - const uint32_t page2_addr = 0x40 * m_video_regs[0x21]; - uint16_t *page1_regs = m_video_regs + 0x10; - uint16_t *page2_regs = m_video_regs + 0x16; - - for (uint32_t scanline = (uint32_t)cliprect.min_y; scanline <= (uint32_t)cliprect.max_y; scanline++) - { - for (int i = 0; i < 4; i++) - { - if (!SPG_DEBUG_VIDEO || !m_hide_page0) - blit_page(cliprect, scanline, i, page1_addr, page1_regs); - if (!SPG_DEBUG_VIDEO || !m_hide_page1) - blit_page(cliprect, scanline, i, page2_addr, page2_regs); - if (!SPG_DEBUG_VIDEO || !m_hide_sprites) - blit_sprites(cliprect, scanline, i); - } - } - - if ((m_video_regs[0x3c] & 0x00ff) != 0x0020) - { - apply_saturation(cliprect); - } - - if (m_video_regs[0x30] != 0) - { - apply_fade(cliprect); - } - - for (int y = cliprect.min_y; y <= cliprect.max_y; y++) - { - uint32_t *dest = &bitmap.pix32(y, cliprect.min_x); - uint32_t *src = &m_screenbuf[cliprect.min_x + 320 * y]; - memcpy(dest, src, sizeof(uint32_t) * ((cliprect.max_x - cliprect.min_x) + 1)); - } - - if (SPG_DEBUG_VIDEO && m_debug_palette) - { - for (int y = cliprect.min_y; y <= cliprect.max_y && y < 128; y++) - { - const uint16_t high_nybble = (y / 8) << 4; - uint32_t *dest = &bitmap.pix32(y, cliprect.min_x); - for (int x = cliprect.min_x; x <= cliprect.max_x && x < 256; x++) - { - const uint16_t low_nybble = x / 16; - const uint16_t palette_entry = high_nybble | low_nybble; - const uint16_t color = m_paletteram[palette_entry]; - if (!(color & 0x8000)) - { - *dest = m_rgb555_to_rgb888[color & 0x7fff]; - } - dest++; - } - } - } - - return 0; -} - -void spg2xx_device::do_sprite_dma(uint32_t len) -{ - address_space &mem = m_cpu->space(AS_PROGRAM); - - uint32_t src = m_video_regs[0x70] & 0x3fff; - uint32_t dst = m_video_regs[0x71]; - - for (uint32_t j = 0; j < len; j++) - { - m_spriteram[(dst + j) & 0x3ff] = mem.read_word(src + j); - } - - m_video_regs[0x72] = 0; - if (VIDEO_IRQ_ENABLE & 4) - { - const uint16_t old = VIDEO_IRQ_STATUS; - VIDEO_IRQ_STATUS |= 4; - const uint16_t changed = old ^ (VIDEO_IRQ_ENABLE & VIDEO_IRQ_STATUS); - if (changed) - check_video_irq(); - } -} - -READ16_MEMBER(spg2xx_device::video_r) -{ - switch (offset) - { - case 0x38: // Current Line - LOGMASKED(LOG_VLINES, "video_r: Current Line: %04x\n", m_screen->vpos()); - return m_screen->vpos(); - - case 0x62: // Video IRQ Enable - LOGMASKED(LOG_IRQS, "video_r: Video IRQ Enable: %04x\n", VIDEO_IRQ_ENABLE); - return VIDEO_IRQ_ENABLE; - - case 0x63: // Video IRQ Status - LOGMASKED(LOG_IRQS, "video_r: Video IRQ Status: %04x\n", VIDEO_IRQ_STATUS); - return VIDEO_IRQ_STATUS; - - default: - LOGMASKED(LOG_UNKNOWN_PPU, "video_r: Unknown register %04x = %04x\n", 0x2800 + offset, m_video_regs[offset]); - break; - } - return m_video_regs[offset]; -} - -WRITE16_MEMBER(spg2xx_device::video_w) -{ - switch (offset) - { - case 0x10: // Page 1 X scroll - LOGMASKED(LOG_PPU_WRITES, "video_w: Page 1 X Scroll = %04x\n", data & 0x01ff); - m_video_regs[offset] = data & 0x01ff; - break; - - case 0x11: // Page 1 Y scroll - LOGMASKED(LOG_PPU_WRITES, "video_w: Page 1 Y Scroll = %04x\n", data & 0x00ff); - m_video_regs[offset] = data & 0x00ff; - break; - - case 0x12: // Page 1 Attributes - LOGMASKED(LOG_PPU_WRITES, "video_w: Page 1 Attributes = %04x (Depth:%d, Palette:%d, VSize:%d, HSize:%d, FlipY:%d, FlipX:%d, BPP:%d)\n", data - , (data >> 12) & 3, (data >> 8) & 15, 8 << ((data >> 6) & 3), 8 << ((data >> 4) & 3), BIT(data, 3), BIT(data, 2), 2 * ((data & 3) + 1)); - m_video_regs[offset] = data; - break; - - case 0x13: // Page 1 Control - LOGMASKED(LOG_PPU_WRITES, "video_w: Page 1 Control = %04x (Blend:%d, HiColor:%d, RowScroll:%d, Enable:%d, Wallpaper:%d, RegSet:%d, Bitmap:%d)\n", data - , BIT(data, 8), BIT(data, 7), BIT(data, 4), BIT(data, 3), BIT(data, 2), BIT(data, 1), BIT(data, 0)); - m_video_regs[offset] = data; - break; - - case 0x14: // Page 1 Tile Address - LOGMASKED(LOG_PPU_WRITES, "video_w: Page 1 Tile Address = %04x\n", data & 0x1fff); - m_video_regs[offset] = data; - break; - - case 0x15: // Page 1 Attribute Address - LOGMASKED(LOG_PPU_WRITES, "video_w: Page 1 Attribute Address = %04x\n", data & 0x1fff); - m_video_regs[offset] = data; - break; - - case 0x16: // Page 2 X scroll - LOGMASKED(LOG_PPU_WRITES, "video_w: Page 2 X Scroll = %04x\n", data & 0x01ff); - m_video_regs[offset] = data & 0x01ff; - break; - - case 0x17: // Page 2 Y scroll - LOGMASKED(LOG_PPU_WRITES, "video_w: Page 2 Y Scroll: %04x = %04x\n", 0x2800 | offset, data & 0x00ff); - m_video_regs[offset] = data & 0x00ff; - break; - - case 0x18: // Page 2 Attributes - LOGMASKED(LOG_PPU_WRITES, "video_w: Page 2 Attributes = %04x (Depth:%d, Palette:%d, VSize:%d, HSize:%d, FlipY:%d, FlipX:%d, BPP:%d)\n", data - , (data >> 12) & 3, (data >> 8) & 15, 8 << ((data >> 6) & 3), 8 << ((data >> 4) & 3), BIT(data, 3), BIT(data, 2), 2 * ((data & 3) + 1)); - m_video_regs[offset] = data; - break; - - case 0x19: // Page 2 Control - LOGMASKED(LOG_PPU_WRITES, "video_w: Page 2 Control = %04x (Blend:%d, HiColor:%d, RowScroll:%d, Enable:%d, Wallpaper:%d, RegSet:%d, Bitmap:%d)\n", data - , BIT(data, 8), BIT(data, 7), BIT(data, 4), BIT(data, 3), BIT(data, 2), BIT(data, 1), BIT(data, 0)); - m_video_regs[offset] = data; - break; - - case 0x1a: // Page 2 Tile Address - LOGMASKED(LOG_PPU_WRITES, "video_w: Page 2 Tile Address = %04x\n", data & 0x1fff); - m_video_regs[offset] = data; - break; - - case 0x1b: // Page 2 Attribute Address - LOGMASKED(LOG_PPU_WRITES, "video_w: Page 2 Attribute Address = %04x\n", data & 0x1fff); - m_video_regs[offset] = data; - break; - - case 0x20: // Page 1 Segment Address - LOGMASKED(LOG_PPU_WRITES, "video_w: Page 1 Segment Address = %04x\n", data); - m_video_regs[offset] = data; - break; - - case 0x21: // Page 2 Segment Address - LOGMASKED(LOG_PPU_WRITES, "video_w: Page 2 Segment Address = %04x\n", data); - m_video_regs[offset] = data; - break; - - case 0x22: // Sprite Segment Address - LOGMASKED(LOG_PPU_WRITES, "video_w: Sprite Segment Address = %04x\n", data); - m_video_regs[offset] = data; - break; - - case 0x2a: // Blend Level Control - LOGMASKED(LOG_PPU_WRITES, "video_w: Blend Level Control = %04x\n", data & 0x0003); - m_video_regs[offset] = data & 0x0003; - break; - - case 0x30: // Fade Effect Control - LOGMASKED(LOG_PPU_WRITES, "video_w: Fade Effect Control = %04x\n", data & 0x00ff); - m_video_regs[offset] = data & 0x00ff; - break; - - case 0x36: // IRQ pos V - case 0x37: // IRQ pos H - m_video_regs[offset] = data & 0x01ff; - LOGMASKED(LOG_IRQS, "video_w: Video IRQ Position: %04x,%04x (%04x)\n", m_video_regs[0x37], m_video_regs[0x36], 0x2800 | offset); - if (m_video_regs[0x37] < 160 && m_video_regs[0x36] < 240) - m_screenpos_timer->adjust(m_screen->time_until_pos(m_video_regs[0x36], m_video_regs[0x37] << 1)); - else - m_screenpos_timer->adjust(attotime::never); - break; - - case 0x39: // Latch 1st Line Pen Pulse - LOGMASKED(LOG_PPU_WRITES, "video_w: Latch 1st Line Pen Pulse = %04x\n", data & 0x0001); - m_video_regs[offset] = data & 0x0001; - break; - - case 0x3c: // TV Control 1 - LOGMASKED(LOG_PPU_WRITES, "video_w: TV Control 1 = %04x (Hue:%02x, Saturation:%02x)\n", data, data >> 8, data & 0x00ff); - m_video_regs[offset] = data; - break; - - case 0x3d: // TV Control 2 - { - static const char* const s_lpf_mode[4] = { "LPF1", "LPF2", "All", "Edge" }; - LOGMASKED(LOG_PPU_WRITES, "video_w: TV Control 2 = %04x (LPFMode:%s, Enable:%d, Interlace:%d)\n", data & 0x000f - , s_lpf_mode[(data >> 2) & 3], BIT(data, 1), BIT(data, 0)); - m_video_regs[offset] = data & 0x000f; - break; - } - - case 0x3e: // Light Pen Y Position - LOGMASKED(LOG_PPU_WRITES, "video_w: Light Pen Y (read only) = %04x\n", data & 0x01ff); - break; - - case 0x3f: // Light Pen YXPosition - LOGMASKED(LOG_PPU_WRITES, "video_w: Light Pen X (read only) = %04x\n", data & 0x01ff); - break; - - case 0x42: // Sprite Control - LOGMASKED(LOG_PPU_WRITES, "video_w: Sprite Control = %04x (TopLeft:%d, Enable:%d)\n", data & 0x0003, BIT(data, 1), BIT(data, 0)); - m_video_regs[offset] = data & 0x0003; - break; - - case 0x62: // Video IRQ Enable - { - LOGMASKED(LOG_IRQS, "video_w: Video IRQ Enable = %04x (DMA:%d, Timing:%d, Blanking:%d)\n", data & 0x0007, BIT(data, 2), BIT(data, 1), BIT(data, 0)); - const uint16_t old = VIDEO_IRQ_ENABLE & VIDEO_IRQ_STATUS; - VIDEO_IRQ_ENABLE = data & 0x0007; - const uint16_t changed = old ^ (VIDEO_IRQ_ENABLE & VIDEO_IRQ_STATUS); - if (changed) - check_video_irq(); - break; - } - - case 0x63: // Video IRQ Acknowledge - { - LOGMASKED(LOG_IRQS, "video_w: Video IRQ Acknowledge = %04x\n", data); - const uint16_t old = VIDEO_IRQ_ENABLE & VIDEO_IRQ_STATUS; - VIDEO_IRQ_STATUS &= ~data; - const uint16_t changed = old ^ (VIDEO_IRQ_ENABLE & VIDEO_IRQ_STATUS); - if (changed) - check_video_irq(); - break; - } - - case 0x70: // Sprite DMA Source - LOGMASKED(LOG_DMA, "video_w: Sprite DMA Source = %04x\n", data & 0x3fff); - m_video_regs[offset] = data & 0x3fff; - break; - - case 0x71: // Sprite DMA Dest - LOGMASKED(LOG_DMA, "video_w: Sprite DMA Dest = %04x\n", data & 0x03ff); - m_video_regs[offset] = data & 0x03ff; - break; - - case 0x72: // Sprite DMA Length - { - LOGMASKED(LOG_DMA, "video_w: Sprite DMA Length = %04x\n", data & 0x03ff); - uint16_t length = data & 0x3ff; - do_sprite_dma(length ? length : 0x400); - break; - } - - default: - LOGMASKED(LOG_UNKNOWN_PPU, "video_w: Unknown register %04x = %04x\n", 0x2800 + offset, data); - m_video_regs[offset] = data; - break; - } -} - -WRITE_LINE_MEMBER(spg2xx_device::vblank) -{ - if (!state) - { - VIDEO_IRQ_STATUS &= ~1; - LOGMASKED(LOG_IRQS, "Setting video IRQ status to %04x\n", VIDEO_IRQ_STATUS); - check_video_irq(); - return; - } - -#if SPG_DEBUG_VIDEO - if (machine().input().code_pressed_once(KEYCODE_5)) - m_hide_page0 = !m_hide_page0; - if (machine().input().code_pressed_once(KEYCODE_6)) - m_hide_page1 = !m_hide_page1; - if (machine().input().code_pressed_once(KEYCODE_7)) - m_hide_sprites = !m_hide_sprites; - if (machine().input().code_pressed_once(KEYCODE_8)) - m_debug_sprites = !m_debug_sprites; - if (machine().input().code_pressed_once(KEYCODE_9)) - m_sprite_index_to_debug--; - if (machine().input().code_pressed_once(KEYCODE_0)) - m_sprite_index_to_debug++; - if (machine().input().code_pressed_once(KEYCODE_L)) - m_debug_palette = !m_debug_palette; -#endif - - if (VIDEO_IRQ_ENABLE & 1) - { - VIDEO_IRQ_STATUS |= 1; - LOGMASKED(LOG_IRQS, "Setting video IRQ status to %04x\n", VIDEO_IRQ_STATUS); - check_video_irq(); - } -} - -void spg2xx_device::check_video_irq() -{ - LOGMASKED(LOG_IRQS, "%ssserting IRQ0 (%04x, %04x)\n", (VIDEO_IRQ_STATUS & VIDEO_IRQ_ENABLE) ? "A" : "Dea", VIDEO_IRQ_STATUS, VIDEO_IRQ_ENABLE); - m_cpu->set_state_unsynced(UNSP_IRQ0_LINE, (VIDEO_IRQ_STATUS & VIDEO_IRQ_ENABLE) ? ASSERT_LINE : CLEAR_LINE); -} - - -/************************* -* Machine Hardware * -*************************/ - -void spg2xx_device::uart_rx(uint8_t data) -{ - LOGMASKED(LOG_UART, "uart_rx: Pulling %02x into receive FIFO\n", data); - if (BIT(m_io_regs[0x30], 6)) - { - m_uart_rx_fifo[m_uart_rx_fifo_end] = data; - m_uart_rx_fifo_end = (m_uart_rx_fifo_end + 1) % ARRAY_LENGTH(m_uart_rx_fifo); - m_uart_rx_fifo_count++; - if (m_uart_rx_timer->remaining() == attotime::never) - m_uart_rx_timer->adjust(attotime::from_ticks(BIT(m_io_regs[0x30], 5) ? 11 : 10, m_uart_baud_rate)); - } -} - -READ16_MEMBER(spg2xx_device::io_r) -{ - static const char *const gpioregs[] = { "GPIO Data Port", "GPIO Buffer Port", "GPIO Direction Port", "GPIO Attribute Port", "GPIO IRQ/Latch Port" }; - static const char gpioports[] = { 'A', 'B', 'C' }; - - uint16_t val = m_io_regs[offset]; - - switch (offset) - { - case 0x01: case 0x06: case 0x0b: // GPIO Data Port A/B/C - do_gpio(offset, false); - LOGMASKED(LOG_GPIO, "%s: io_r: %s %c = %04x\n", machine().describe_context(), gpioregs[(offset - 1) % 5], gpioports[(offset - 1) / 5], m_io_regs[offset]); - val = m_io_regs[offset]; - break; - - case 0x02: case 0x03: case 0x04: case 0x05: - case 0x07: case 0x08: case 0x09: case 0x0a: - case 0x0c: case 0x0d: case 0x0e: case 0x0f: // Other GPIO regs - LOGMASKED(LOG_GPIO, "%s: io_r: %s %c = %04x\n", machine().describe_context(), gpioregs[(offset - 1) % 5], gpioports[(offset - 1) / 5], m_io_regs[offset]); - break; - - case 0x10: // Timebase Control - LOGMASKED(LOG_IO_READS, "io_r: Timebase Control = %04x\n", val); - break; - - case 0x12: // Timer A Data - LOGMASKED(LOG_IO_WRITES, "io_r: Timer A Data = %04x\n", val); - break; - - case 0x1c: // Video line counter - val = m_screen->vpos(); - LOGMASKED(LOG_VLINES, "io_r: Video Line = %04x\n", val); - break; - - case 0x20: // System Control - LOGMASKED(LOG_IO_READS, "io_r: System Control = %04x\n", val); - break; - - case 0x21: // IRQ Control - LOGMASKED(LOG_IRQS, "%s: io_r: I/O IRQ Control = %04x\n", machine().describe_context(), val); - break; - - case 0x22: // IRQ Status - LOGMASKED(LOG_IRQS, "%s: io_r: I/O IRQ Status = %04x\n", machine().describe_context(), val); - break; - - case 0x23: // External Memory Control - LOGMASKED(LOG_IO_READS, "%s: io_r: Ext. Memory Control = %04x\n", machine().describe_context(), val); - break; - - case 0x25: // ADC Control - LOGMASKED(LOG_IO_READS, "io_r: ADC Control = %04x\n", val); - break; - - case 0x27: // ADC Data - { - m_io_regs[0x27] = 0; - const uint16_t old = IO_IRQ_STATUS; - IO_IRQ_STATUS &= ~0x2000; - const uint16_t changed = (old & IO_IRQ_ENABLE) ^ (IO_IRQ_STATUS & IO_IRQ_ENABLE); - if (changed) - check_irqs(changed); - LOGMASKED(LOG_IO_READS, "%s: io_r: ADC Data = %04x\n", machine().describe_context(), val); - break; - } - - case 0x29: // Wakeup Source - LOGMASKED(LOG_IO_READS, "io_r: Wakeup Source = %04x\n", val); - break; - - case 0x2b: - LOGMASKED(LOG_IO_READS, "io_r: NTSC/PAL = %04x\n", m_pal_flag); - return m_pal_flag; - - case 0x2c: // PRNG 0 - { - const uint16_t value = m_io_regs[0x2c]; - m_io_regs[0x2c] = ((value << 1) | (BIT(value, 14) ^ BIT(value, 13))) & 0x7fff; - return value; - } - - case 0x2d: // PRNG 1 - { - const uint16_t value = m_io_regs[0x2d]; - m_io_regs[0x2d] = ((value << 1) | (BIT(value, 14) ^ BIT(value, 13))) & 0x7fff; - return value; - } - - case 0x2e: // FIQ Source Select - LOGMASKED(LOG_FIQ, "io_r: FIQ Source Select = %04x\n", val); - break; - - case 0x2f: // Data Segment - val = m_cpu->get_ds(); - LOGMASKED(LOG_SEGMENT, "io_r: Data Segment = %04x\n", val); - break; - - case 0x30: // UART Control - LOGMASKED(LOG_UART, "%s: io_r: UART Control = %04x\n", machine().describe_context(), val); - break; - - case 0x31: // UART Status - //LOGMASKED(LOG_UART, "%s: io_r: UART Status = %04x\n", machine().describe_context(), val); - break; - - case 0x36: // UART RX Data - if (m_uart_rx_available) - { - m_io_regs[0x31] &= ~0x0081; - LOGMASKED(LOG_UART, "UART Rx data is available, clearing bits\n"); - if (m_uart_rx_fifo_count) - { - LOGMASKED(LOG_UART, "Remaining count %d, value %02x\n", m_uart_rx_fifo_count, m_uart_rx_fifo[m_uart_rx_fifo_start]); - m_io_regs[0x36] = m_uart_rx_fifo[m_uart_rx_fifo_start]; - val = m_io_regs[0x36]; - m_uart_rx_fifo_start = (m_uart_rx_fifo_start + 1) % ARRAY_LENGTH(m_uart_rx_fifo); - m_uart_rx_fifo_count--; - - if (m_uart_rx_fifo_count == 0) - { - m_uart_rx_available = false; - } - else - { - LOGMASKED(LOG_UART, "Remaining count %d, setting up timer\n", m_uart_rx_fifo_count); - //uart_receive_tick(); - if (m_uart_rx_timer->remaining() == attotime::never) - m_uart_rx_timer->adjust(attotime::from_ticks(BIT(m_io_regs[0x30], 5) ? 11 : 10, m_uart_baud_rate)); - } - } - else - { - m_uart_rx_available = false; - } - } - else - { - m_io_regs[0x37] |= 0x2000; - } - LOGMASKED(LOG_UART, "%s: io_r: UART Rx Data = %04x\n", machine().describe_context(), val); - break; - - case 0x37: // UART Rx FIFO Control - val &= ~0x0070; - val |= (m_uart_rx_available ? 7 : 0) << 4; - LOGMASKED(LOG_UART, "io_r: UART Rx FIFO Control = %04x\n", machine().describe_context(), val); - break; - - case 0x51: // unknown, polled by ClickStart cartridges ( clikstrt ) - return 0x8000; - - case 0x59: // I2C Status - LOGMASKED(LOG_I2C, "io_r: I2C Status = %04x\n", val); - break; - - case 0x5e: // I2C Data In - LOGMASKED(LOG_I2C, "io_r: I2C Data In = %04x\n", val); - break; - - case 0x100: // DMA Source (L) - LOGMASKED(LOG_DMA, "io_r: DMA Source (lo) = %04x\n", val); - break; - - case 0x101: // DMA Source (H) - LOGMASKED(LOG_DMA, "io_r: DMA Source (hi) = %04x\n", val); - break; - - case 0x102: // DMA Length - LOGMASKED(LOG_DMA, "io_r: DMA Length = %04x\n", 0); - val = 0; - break; - - case 0x103: // DMA Destination - LOGMASKED(LOG_DMA, "io_r: DMA Dest = %04x\n", val); - break; - - default: - LOGMASKED(LOG_UNKNOWN_IO, "io_r: Unknown register %04x\n", 0x3d00 + offset); - break; - } - - return val; -} - -void spg2xx_device::update_porta_special_modes() -{ - static const char* const s_pa_special[4][16] = - { - // Input, Special 0 - // Input, Special 1 - // Output, Special 0 - // Output, Special 1 - - { "LP", "ExtClk2", "ExtClk1", "-", "SDA", "SlvRDY", "-", "-", "SPICLK", "-", "RxD", "SPISSB", "-", "-", "-", "-" }, - { "-", "-", "-", "SCK", "-", "SWS", "-", "-", "-", "-", "-", "-", "IRQ2B", "-", "-", "IRQ1B" }, - { "-", "-", "-", "SCK", "SDA", "SWS", "-", "-", "SPICLK", "TxD", "-", "SPISSB", "TAPWM", "TM1", "TBPWM", "TM2" }, - { "CSB3", "CSB2", "CSB1", "SCK", "SDA", "VSYNC", "HSYNC", "SYSCLK3", "SPICLK", "TxD", "SWS", "SPISSB", "-", "VSYNC", "HSYNC", "CSYNC" }, - }; - for (int bit = 15; bit >= 0; bit--) - { - if (!BIT(m_io_regs[0x05], bit)) - continue; - uint8_t type = (BIT(m_io_regs[0x03], bit) << 1) | BIT(m_io_regs[0x00], 0); - LOGMASKED(LOG_GPIO, " Bit %2d: %s\n", bit, s_pa_special[type][bit]); - } -} - -void spg2xx_device::update_portb_special_modes() -{ - static const char* const s_pb_special[4][8] = - { - // Input, Special 0 - // Input, Special 1 - // Output, Special 0 - // Output, Special 1 - - { "-", "-", "-", "-", "-", "-", "SDA", "SlvRDY" }, - { "-", "-", "-", "-", "-", "-", "SDA", "SlvRDY" }, - { "VSYNC", "HSYNC", "CSYNC", "-", "-", "SCK", "SDA", "SWS" }, - { "CSB3", "CSB2", "CSB1", "TBPWM", "TM2", "-", "-", "SYSCLK2" }, - }; - for (int bit = 7; bit >= 0; bit--) - { - if (!BIT(m_io_regs[0x0a], bit)) - continue; - uint8_t type = (BIT(m_io_regs[0x08], bit) << 1) | BIT(m_io_regs[0x00], 1); - LOGMASKED(LOG_GPIO, " Bit %2d: %s\n", bit, s_pb_special[type][bit]); - } -} - -void spg2xx_device::update_timer_b_rate() -{ - switch (m_io_regs[0x17] & 7) - { - case 0: - case 1: - case 5: - case 6: - case 7: - m_timer_src_c->adjust(attotime::never); - break; - case 2: - m_timer_src_c->adjust(attotime::from_hz(32768), 0, attotime::from_hz(32768)); - break; - case 3: - m_timer_src_c->adjust(attotime::from_hz(8192), 0, attotime::from_hz(8192)); - break; - case 4: - m_timer_src_c->adjust(attotime::from_hz(4096), 0, attotime::from_hz(4096)); - break; - } -} - -void spg2xx_device::update_timer_ab_src() -{ - if (m_timer_b_tick_rate == 0) - return; - - m_timer_b_divisor++; - if (m_timer_b_divisor >= m_timer_b_tick_rate) - { - m_timer_b_divisor = 0; - increment_timer_a(); - } -} - -void spg2xx_device::increment_timer_a() -{ - m_io_regs[0x12]++; - if (m_io_regs[0x12] == 0) - { - m_io_regs[0x12] = m_timer_a_preload; - const uint16_t old = IO_IRQ_STATUS; - IO_IRQ_STATUS |= 0x0800; - const uint16_t changed = (old & IO_IRQ_ENABLE) ^ (IO_IRQ_STATUS & IO_IRQ_ENABLE); - if (changed) - { - //printf("Timer A overflow\n"); - check_irqs(0x0800); - } - } -} - -void spg2xx_device::update_timer_c_src() -{ - m_io_regs[0x16]++; - if (m_io_regs[0x16] == 0) - { - m_io_regs[0x16] = m_timer_b_preload; - const uint16_t old = IO_IRQ_STATUS; - IO_IRQ_STATUS |= 0x0400; - const uint16_t changed = (old & IO_IRQ_ENABLE) ^ (IO_IRQ_STATUS & IO_IRQ_ENABLE); - if (changed) - { - printf("Timer B overflow\n"); - check_irqs(0x0400); - } - } -} - - -WRITE16_MEMBER(spg28x_device::io_w) -{ - if (offset == 0x33) - { - m_io_regs[offset] = data; - m_uart_baud_rate = 27000000 / (0x10000 - m_io_regs[0x33]); - LOGMASKED(LOG_UART, "%s: io_w: UART Baud Rate scaler = %04x (%d baud)\n", machine().describe_context(), data, m_uart_baud_rate); - } - else - { - spg2xx_device::io_w(space, offset, data, mem_mask); - } -} - -WRITE16_MEMBER(spg2xx_device::io_w) -{ - static const char *const gpioregs[] = { "GPIO Data Port", "GPIO Buffer Port", "GPIO Direction Port", "GPIO Attribute Port", "GPIO IRQ/Latch Port" }; - static const char gpioports[3] = { 'A', 'B', 'C' }; - - switch (offset) - { - case 0x00: // GPIO special function select - { - LOGMASKED(LOG_GPIO, "%s: io_w: GPIO Configuration = %04x (IOBWake:%d, IOAWake:%d, IOBSpecSel:%d, IOASpecSel:%d)\n", machine().describe_context(), data - , BIT(data, 4), BIT(data, 3), BIT(data, 1), BIT(data, 0)); - const uint16_t old = m_io_regs[offset]; - m_io_regs[offset] = data; - const uint16_t changed = old ^ data; - if (BIT(changed, 0)) - update_porta_special_modes(); - if (BIT(changed, 1)) - update_portb_special_modes(); - break; - } - - case 0x01: case 0x06: case 0x0b: // GPIO data, port A/B/C - offset++; - // Intentional fallthrough - we redirect data register writes to the buffer register. - - case 0x02: case 0x04: // Port A - case 0x07: case 0x09: // Port B - case 0x0c: case 0x0d: case 0x0e: case 0x0f: // Port C - LOGMASKED(LOG_GPIO, "%s: io_w: %s %c = %04x\n", machine().describe_context(), gpioregs[(offset - 1) % 5], gpioports[(offset - 1) / 5], data); - m_io_regs[offset] = data; - do_gpio(offset, true); - break; - - case 0x03: // Port A Direction - LOGMASKED(LOG_GPIO, "%s: io_w: GPIO Direction Port A = %04x\n", machine().describe_context(), data); - m_io_regs[offset] = data; - update_porta_special_modes(); - do_gpio(offset, true); - break; - - case 0x08: // Port B Direction - LOGMASKED(LOG_GPIO, "%s: io_w: GPIO Direction Port B = %04x\n", machine().describe_context(), data); - m_io_regs[offset] = data; - update_portb_special_modes(); - do_gpio(offset, true); - break; - - case 0x05: // Port A Special - LOGMASKED(LOG_GPIO, "%s: io_w: Port A Special Function Select: %04x\n", machine().describe_context(), data); - m_io_regs[offset] = data; - update_porta_special_modes(); - break; - - case 0x0a: // Port B Special - LOGMASKED(LOG_GPIO, "%s: io_w: Port B Special Function Select: %04x\n", machine().describe_context(), data); - m_io_regs[offset] = data; - update_portb_special_modes(); - break; - - case 0x10: // Timebase Control - { - static const char* const s_tmb1_sel[2][4] = - { - { "8Hz", "16Hz", "32Hz", "64Hz" }, - { "12kHz", "24kHz", "40kHz", "40kHz" } - }; - static const char* const s_tmb2_sel[2][4] = - { - { "128Hz", "256Hz", "512Hz", "1024Hz" }, - { "105kHz", "210kHz", "420kHz", "840kHz" } - }; - static const uint32_t s_tmb1_freq[2][4] = - { - { 8, 16, 32, 64 }, - { 12000, 24000, 40000, 40000 } - }; - static const uint32_t s_tmb2_freq[2][4] = - { - { 128, 256, 512, 1024 }, - { 105000, 210000, 420000, 840000 } - }; - LOGMASKED(LOG_TIMERS, "io_w: Timebase Control = %04x (Source:%s, TMB2:%s, TMB1:%s)\n", data, - BIT(data, 4) ? "27MHz" : "32768Hz", s_tmb2_sel[BIT(data, 4)][(data >> 2) & 3], s_tmb1_sel[BIT(data, 4)][data & 3]); - m_io_regs[offset] = data; - const uint8_t hifreq = BIT(data, 4); - const uint32_t tmb1freq = s_tmb1_freq[hifreq][data & 3]; - m_tmb1->adjust(attotime::from_hz(tmb1freq), 0, attotime::from_hz(tmb1freq)); - const uint32_t tmb2freq = s_tmb2_freq[hifreq][(data >> 2) & 3]; - m_tmb2->adjust(attotime::from_hz(tmb2freq), 0, attotime::from_hz(tmb2freq)); - break; - } - - case 0x11: // Timebase Clear - LOGMASKED(LOG_TIMERS, "io_w: Timebase Clear = %04x\n", data); - break; - - case 0x12: // Timer A Data - LOGMASKED(LOG_TIMERS, "io_w: Timer A Data = %04x\n", data); - m_io_regs[offset] = data; - m_timer_a_preload = data; - break; - - case 0x13: // Timer A Control - { - static const char* const s_source_a[8] = { "0", "0", "32768Hz", "8192Hz", "4096Hz", "1", "0", "ExtClk1" }; - static const char* const s_source_b[8] = { "2048Hz", "1024Hz", "256Hz", "TMB1", "4Hz", "2Hz", "1", "ExtClk2" }; - LOGMASKED(LOG_TIMERS, "io_w: Timer A Control = %04x (Source A:%s, Source B:%s)\n", data, - s_source_a[data & 7], s_source_b[(data >> 3) & 7]); - m_io_regs[offset] = data; - int timer_a_rate = 0; - switch (data & 7) - { - case 0: - case 1: - case 5: - case 6: - case 7: - m_timer_src_ab->adjust(attotime::never); - break; - case 2: - m_timer_src_ab->adjust(attotime::from_hz(32768), 0, attotime::from_hz(32768)); - timer_a_rate = 32768; - break; - case 3: - m_timer_src_ab->adjust(attotime::from_hz(8192), 0, attotime::from_hz(8192)); - timer_a_rate = 8192; - break; - case 4: - m_timer_src_ab->adjust(attotime::from_hz(4096), 0, attotime::from_hz(4096)); - timer_a_rate = 4096; - break; - } - switch ((data >> 3) & 7) - { - case 0: - m_timer_b_tick_rate = timer_a_rate / 2048; - break; - case 1: - m_timer_b_tick_rate = timer_a_rate / 1024; - break; - case 2: - m_timer_b_tick_rate = timer_a_rate / 256; - break; - case 3: - m_timer_b_tick_rate = 0; - break; - case 4: - m_timer_b_tick_rate = timer_a_rate / 4; - break; - case 5: - m_timer_b_tick_rate = timer_a_rate / 2; - break; - case 6: - m_timer_b_tick_rate = 1; - break; - case 7: - m_timer_b_tick_rate = 0; - break; - } - break; - } - - case 0x15: // Timer A IRQ Clear - { - LOGMASKED(LOG_TIMERS, "io_w: Timer A IRQ Clear\n"); - const uint16_t old = IO_IRQ_STATUS; - IO_IRQ_STATUS &= ~0x0800; - const uint16_t changed = (old & IO_IRQ_ENABLE) ^ (IO_IRQ_STATUS & IO_IRQ_ENABLE); - if (changed) - check_irqs(0x0800); - break; - } - - case 0x16: // Timer B Data - LOGMASKED(LOG_TIMERS, "io_w: Timer B Data = %04x\n", data); - m_io_regs[offset] = data; - m_timer_b_preload = data; - break; - - case 0x17: // Timer B Control - { - static const char* const s_source_c[8] = { "0", "0", "32768Hz", "8192Hz", "4096Hz", "1", "0", "ExtClk1" }; - LOGMASKED(LOG_TIMERS, "io_w: Timer B Control = %04x (Source C:%s)\n", data, s_source_c[data & 7]); - m_io_regs[offset] = data; - if (m_io_regs[0x18] == 1) - { - update_timer_b_rate(); - } - break; - } - - case 0x18: // Timer B Enable - { - LOGMASKED(LOG_TIMERS, "io_w: Timer B Enable = %04x\n", data); - m_io_regs[offset] = data & 1; - if (data & 1) - { - update_timer_b_rate(); - } - else - { - m_timer_src_c->adjust(attotime::never); - } - break; - } - - case 0x19: // Timer B IRQ Clear - { - LOGMASKED(LOG_TIMERS, "io_w: Timer B IRQ Clear\n"); - const uint16_t old = IO_IRQ_STATUS; - IO_IRQ_STATUS &= ~0x0400; - const uint16_t changed = (old & IO_IRQ_ENABLE) ^ (IO_IRQ_STATUS & IO_IRQ_ENABLE); - if (changed) - check_irqs(0x0400); - break; - } - - case 0x20: // System Control - { - static const char* const s_sysclk[4] = { "13.5MHz", "27MHz", "27MHz NoICE", "54MHz" }; - static const char* const s_lvd_voltage[4] = { "2.7V", "2.9V", "3.1V", "3.3V" }; - static const char* const s_weak_strong[2] = { "Weak", "Strong" }; - LOGMASKED(LOG_IO_WRITES, "io_w: System Control = %04x (Watchdog:%d, Sleep:%d, SysClk:%s, SysClkInv:%d, LVROutEn:%d, LVREn:%d\n" - , data, BIT(data, 15), BIT(data, 14), s_sysclk[(data >> 12) & 3], BIT(data, 11), BIT(data, 9), BIT(data, 8)); - LOGMASKED(LOG_IO_WRITES, " LVDEn:%d, LVDVoltSel:%s, 32kHzDisable:%d, StrWkMode:%s, VDACDisable:%d, ADACDisable:%d, ADACOutDisable:%d)\n" - , BIT(data, 7), s_lvd_voltage[(data >> 5) & 3], BIT(data, 4), s_weak_strong[BIT(data, 3)], BIT(data, 2), BIT(data, 1), BIT(data, 0)); - m_io_regs[offset] = data; - break; - } - - case 0x21: // IRQ Enable - { - LOGMASKED(LOG_IRQS, "io_w: IRQ Enable = %04x\n", data); - const uint16_t old = IO_IRQ_ENABLE; - m_io_regs[offset] = data; - const uint16_t changed = (old & IO_IRQ_ENABLE) ^ (IO_IRQ_STATUS & IO_IRQ_ENABLE); - if (changed) - check_irqs(changed); - break; - } - - case 0x22: // IRQ Acknowledge - { - LOGMASKED(LOG_IRQS, "io_w: IRQ Acknowledge = %04x\n", data); - const uint16_t old = IO_IRQ_STATUS; - IO_IRQ_STATUS &= ~data; - const uint16_t changed = (old & IO_IRQ_ENABLE) ^ (IO_IRQ_STATUS & IO_IRQ_ENABLE); - if (m_uart_rx_irq || m_uart_tx_irq) - { - LOGMASKED(LOG_IRQS | LOG_UART, "Re-setting UART IRQ due to still-unacknowledged Rx or Tx.\n"); - IO_IRQ_STATUS |= 0x0100; - } - if (changed) - check_irqs(changed); - break; - } - - case 0x23: // External Memory Control - { - static const char* const s_bus_arb[8] = - { - "Forbidden", "Forbidden", "Forbidden", "Forbidden", "Forbidden", "1:SPU/2:PPU/3:CPU", "Forbidden", "1:PPU/2:SPU/3:CPU" - }; - static const char* const s_addr_decode[4] = - { - "ROMCSB: 4000-3fffff, CSB1: ---, CSB2: ---, CSB3: ---", - "ROMCSB: 4000-1fffff, CSB1: 200000-3fffff, CSB2: ---, CSB3: ---", - "ROMCSB: 4000-0fffff, CSB1: 100000-1fffff, CSB2: 200000-2fffff, CSB3: 300000-3fffff", - "ROMCSB: 4000-0fffff, CSB1: 100000-1fffff, CSB2: 200000-2fffff, CSB3: 300000-3fffff" - }; - static const char* const s_ram_decode[16] = - { - "None", "None", "None", "None", "None", "None", "None", "None", - "4KW, 3ff000-3fffff\n", - "8KW, 3fe000-3fffff\n", - "16KW, 3fc000-3fffff\n", - "32KW, 3f8000-3fffff\n", - "64KW, 3f0000-3fffff\n", - "128KW, 3e0000-3fffff\n", - "256KW, 3c0000-3fffff\n", - "512KW, 380000-3fffff\n" - }; - LOGMASKED(LOG_EXT_MEM, "io_w: Ext. Memory Control (not yet implemented) = %04x:\n", data); - LOGMASKED(LOG_EXT_MEM, " WaitStates:%d, BusArbPrio:%s\n", (data >> 1) & 3, s_bus_arb[(data >> 3) & 7]); - LOGMASKED(LOG_EXT_MEM, " ROMAddrDecode:%s\n", s_addr_decode[(data >> 6) & 3]); - LOGMASKED(LOG_EXT_MEM, " RAMAddrDecode:%s\n", s_ram_decode[(data >> 8) & 15]); - m_chip_sel((data >> 6) & 3); - m_io_regs[offset] = data; - break; - } - - case 0x24: // Watchdog - LOGMASKED(LOG_WATCHDOG, "io_w: Watchdog Pet = %04x\n", data); - break; - - case 0x25: // ADC Control - { - LOGMASKED(LOG_IO_WRITES, "%s: io_w: ADC Control = %04x\n", machine().describe_context(), data); - m_io_regs[offset] = data & ~0x1000; - if (BIT(data, 0)) - { - m_io_regs[0x27] = 0x8000 | (m_adc_in[BIT(data, 5)]() & 0x7fff); - m_io_regs[0x25] |= 0x2000; - } - if (BIT(data, 12) && !BIT(m_io_regs[offset], 1)) - { - const uint16_t old = IO_IRQ_STATUS; - IO_IRQ_STATUS |= 0x2000; - const uint16_t changed = (old & IO_IRQ_ENABLE) ^ (IO_IRQ_STATUS & IO_IRQ_ENABLE); - if (changed) - { - check_irqs(changed); - } - } - break; - } - - case 0x28: // Sleep Mode - LOGMASKED(LOG_IO_WRITES, "io_w: Sleep Mode (%s enter value) = %04x\n", data == 0xaa55 ? "valid" : "invalid", data); - m_io_regs[offset] = data; - break; - - case 0x29: // Wakeup Source - { - m_io_regs[offset] = data; - static const char* const s_sources[8] = - { - "TMB1", "TMB2", "2Hz", "4Hz", "1024Hz", "2048Hz", "4096Hz", "Key" - }; - - LOGMASKED(LOG_IO_WRITES, "io_w: Wakeup Source = %04x:\n", data); - bool comma = false; - char buf[1024]; - int char_idx = 0; - for (int i = 7; i >= 0; i--) - { - if (BIT(data, i)) - { - char_idx += sprintf(&buf[char_idx], "%s%s", comma ? ", " : "", s_sources[i]); - comma = true; - } - } - buf[char_idx] = 0; - LOGMASKED(LOG_IO_WRITES, " %s\n", buf); - break; - } - - case 0x2c: // PRNG 0 seed - LOGMASKED(LOG_IO_WRITES, "io_w: PRNG 0 seed = %04x\n", data & 0x7fff); - m_io_regs[offset] = data & 0x7fff; - break; - - case 0x2d: // PRNG 1 seed - LOGMASKED(LOG_IO_WRITES, "io_w: PRNG 1 seed = %04x\n", data & 0x7fff); - m_io_regs[offset] = data & 0x7fff; - break; - - case 0x2e: // FIQ Source Select - { - static const char* const s_fiq_select[8] = - { - "PPU", "SPU Channel", "Timer A", "Timer B", "UART/SPI", "External", "Reserved", "None" - }; - LOGMASKED(LOG_FIQ, "io_w: FIQ Source Select (not yet implemented) = %04x, %s\n", data, s_fiq_select[data & 7]); - m_io_regs[offset] = data; - break; - } - - case 0x2f: // Data Segment - m_cpu->set_ds(data & 0x3f); - LOGMASKED(LOG_SEGMENT, "io_w: Data Segment = %04x\n", data); - break; - - case 0x30: // UART Control - { - static const char* const s_9th_bit[4] = { "0", "1", "Odd", "Even" }; - LOGMASKED(LOG_UART, "%s: io_w: UART Control = %04x (TxEn:%d, RxEn:%d, Bits:%d, MultiProc:%d, 9thBit:%s, TxIntEn:%d, RxIntEn:%d\n", - machine().describe_context(), data, BIT(data, 7), BIT(data, 6), BIT(data, 5) ? 9 : 8, BIT(data, 4), s_9th_bit[(data >> 2) & 3], - BIT(data, 1), BIT(data, 0)); - const uint16_t changed = m_io_regs[offset] ^ data; - m_io_regs[offset] = data; - if (!BIT(data, 6)) - { - m_uart_rx_available = false; - m_io_regs[0x36] = 0; - } - if (BIT(changed, 7)) - { - if (BIT(data, 7)) - { - m_io_regs[0x31] |= 0x0002; - } - else - { - m_io_regs[0x31] &= ~0x0042; - m_uart_tx_timer->adjust(attotime::never); - } - } - break; - } - - case 0x31: // UART Status - LOGMASKED(LOG_UART, "%s: io_w: UART Status = %04x\n", machine().describe_context(), data); - if (BIT(data, 0)) - { - m_io_regs[0x31] &= ~1; - m_uart_rx_irq = false; - } - if (BIT(data, 1)) - { - m_io_regs[0x31] &= ~2; - m_uart_tx_irq = false; - } - if (!m_uart_rx_irq && !m_uart_tx_irq) - { - const uint16_t old = IO_IRQ_STATUS; - IO_IRQ_STATUS &= ~0x0100; - const uint16_t changed = (old & IO_IRQ_ENABLE) ^ (IO_IRQ_STATUS & IO_IRQ_ENABLE); - if (changed) - check_irqs(0x0100); - } - break; - - case 0x33: // UART Baud Rate (low byte) - case 0x34: // UART Baud Rate (high byte) - { - m_io_regs[offset] = data; - const uint32_t divisor = 16 * (0x10000 - ((m_io_regs[0x34] << 8) | m_io_regs[0x33])); - LOGMASKED(LOG_UART, "%s: io_w: UART Baud Rate (%s byte): Baud rate = %d\n", offset == 0x33 ? "low" : "high", machine().describe_context(), 27000000 / divisor); - m_uart_baud_rate = 27000000 / divisor; - break; - } - - case 0x35: // UART TX Data - LOGMASKED(LOG_UART, "%s: io_w: UART Tx Data = %02x\n", machine().describe_context(), data & 0x00ff); - m_io_regs[offset] = data; - if (BIT(m_io_regs[0x30], 7)) - { - LOGMASKED(LOG_UART, "io_w: UART Tx: Clearing ready bit, setting busy bit, setting up timer\n"); - m_uart_tx_timer->adjust(attotime::from_ticks(BIT(m_io_regs[0x30], 5) ? 11 : 10, m_uart_baud_rate)); - m_io_regs[0x31] &= ~0x0002; - m_io_regs[0x31] |= 0x0040; - } - break; - - case 0x36: // UART RX Data - LOGMASKED(LOG_UART, "%s: io_w: UART Rx Data (read-only) = %04x\n", machine().describe_context(), data); - break; - - case 0x37: // UART Rx FIFO Control - LOGMASKED(LOG_UART, "%s: io_w: UART Rx FIFO Control = %04x (Reset:%d, Overrun:%d, Underrun:%d, Count:%d, Threshold:%d)\n", - machine().describe_context(), data, BIT(data, 15), BIT(data, 14), BIT(data, 13), (data >> 4) & 7, data & 7); - if (data & 0x8000) - { - m_uart_rx_available = false; - m_io_regs[0x36] = 0; - } - m_io_regs[offset] &= ~data & 0x6000; - m_io_regs[offset] &= ~0x0007; - m_io_regs[offset] |= data & 0x0007; - break; - - case 0x50: // SIO Setup - { - static const char* const s_addr_mode[4] = { "16-bit", "None", "8-bit", "24-bit" }; - static const char* const s_baud_rate[4] = { "/16", "/4", "/8", "/32" }; - LOGMASKED(LOG_SIO, "io_w: SIO Setup (not implemented) = %04x (DS301Ready:%d, Start:%d, Auto:%d, IRQEn:%d, Width:%d, Related:%d\n", data - , BIT(data, 11), BIT(data, 10), BIT(data, 9), BIT(data, 8), BIT(data, 7) ? 16 : 8, BIT(data, 6)); - LOGMASKED(LOG_SIO, " (Mode:%s, RWProtocol:%d, Rate:sysclk%s, AddrMode:%s)\n" - , BIT(data, 5), BIT(data, 4), s_baud_rate[(data >> 2) & 3], s_addr_mode[data & 3]); - break; - } - - case 0x52: // SIO Start Address (low) - LOGMASKED(LOG_SIO, "io_w: SIO Stat Address (low) (not implemented) = %04x\n", data); - break; - - case 0x53: // SIO Start Address (hi) - LOGMASKED(LOG_SIO, "io_w: SIO Stat Address (hi) (not implemented) = %04x\n", data); - break; - - case 0x54: // SIO Data - LOGMASKED(LOG_SIO, "io_w: SIO Data (not implemented) = %04x\n", data); - break; - - case 0x55: // SIO Automatic Transmit Count - LOGMASKED(LOG_SIO, "io_w: SIO Auto Transmit Count (not implemented) = %04x\n", data); - break; - - case 0x58: // I2C Command - LOGMASKED(LOG_I2C, "io_w: I2C Command = %04x\n", data); - m_io_regs[offset] = data; - do_i2c(); - break; - - case 0x59: // I2C Status / Acknowledge - LOGMASKED(LOG_I2C, "io_w: I2C Acknowledge = %04x\n", data); - m_io_regs[offset] &= ~data; - break; - - case 0x5a: // I2C Access Mode - LOGMASKED(LOG_I2C, "io_w: I2C Access Mode = %04x\n", data); - m_io_regs[offset] = data; - break; - - case 0x5b: // I2C Device Address - LOGMASKED(LOG_I2C, "io_w: I2C Device Address = %04x\n", data); - m_io_regs[offset] = data; - break; - - case 0x5c: // I2C Sub-Address - LOGMASKED(LOG_I2C, "io_w: I2C Sub-Address = %04x\n", data); - m_io_regs[offset] = data; - break; - - case 0x5d: // I2C Data Out - LOGMASKED(LOG_I2C, "io_w: I2C Data Out = %04x\n", data); - m_io_regs[offset] = data; - break; - - case 0x5e: // I2C Data In - LOGMASKED(LOG_I2C, "io_w: I2C Data In = %04x\n", data); - m_io_regs[offset] = data; - break; - - case 0x5f: // I2C Controller Mode - LOGMASKED(LOG_I2C, "io_w: I2C Controller Mode = %04x\n", data); - m_io_regs[offset] = data; - break; - - case 0x100: // DMA Source (lo) - LOGMASKED(LOG_DMA, "io_w: DMA Source (lo) = %04x\n", data); - m_io_regs[offset] = data; - break; - - case 0x101: // DMA Source (hi) - LOGMASKED(LOG_DMA, "io_w: DMA Source (hi) = %04x\n", data); - m_io_regs[offset] = data; - break; - - case 0x103: // DMA Destination - LOGMASKED(LOG_DMA, "io_w: DMA Dest = %04x\n", data); - m_io_regs[offset] = data; - break; - - case 0x102: // DMA Length - LOGMASKED(LOG_DMA, "io_w: DMA Length = %04x\n", data); - if (!(data & 0xc000)) // jak_dora writes 0xffff here which ends up trashing registers etc. why? such writes can't be valid - do_cpu_dma(data); - - break; - - default: - LOGMASKED(LOG_UNKNOWN_IO, "io_w: Unknown register %04x = %04x\n", 0x3d00 + offset, data); - m_io_regs[offset] = data; - break; - } -} - -void spg2xx_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) -{ - switch (id) - { - case TIMER_TMB1: - { - LOGMASKED(LOG_TIMERS, "TMB1 elapsed, setting IRQ Status bit 0 (old:%04x, new:%04x, enable:%04x)\n", IO_IRQ_STATUS, IO_IRQ_STATUS | 1, IO_IRQ_ENABLE); - const uint16_t old = IO_IRQ_STATUS; - IO_IRQ_STATUS |= 1; - const uint16_t changed = (old & IO_IRQ_ENABLE) ^ (IO_IRQ_STATUS & IO_IRQ_ENABLE); - if (changed) - check_irqs(0x0001); - break; - } - - case TIMER_TMB2: - { - LOGMASKED(LOG_TIMERS, "TMB2 elapsed, setting IRQ Status bit 1 (old:%04x, new:%04x, enable:%04x)\n", IO_IRQ_STATUS, IO_IRQ_STATUS | 2, IO_IRQ_ENABLE); - const uint16_t old = IO_IRQ_STATUS; - IO_IRQ_STATUS |= 2; - const uint16_t changed = (old & IO_IRQ_ENABLE) ^ (IO_IRQ_STATUS & IO_IRQ_ENABLE); - if (changed) - check_irqs(0x0002); - break; - } - - case TIMER_SCREENPOS: - { - if (VIDEO_IRQ_ENABLE & 2) - { - VIDEO_IRQ_STATUS |= 2; - check_video_irq(); - } - m_screen->update_partial(m_screen->vpos()); - - // fire again, jak_dbz pinball needs this - m_screenpos_timer->adjust(m_screen->time_until_pos(m_video_regs[0x36], m_video_regs[0x37] << 1)); - break; - } - - case TIMER_UART_TX: - uart_transmit_tick(); - break; - - case TIMER_UART_RX: - uart_receive_tick(); - break; - - case TIMER_4KHZ: - system_timer_tick(); - break; - - case TIMER_SRC_AB: - update_timer_ab_src(); - break; - - case TIMER_SRC_C: - update_timer_c_src(); - break; - } -} - -void spg2xx_device::system_timer_tick() -{ - const uint16_t old = IO_IRQ_STATUS; - uint16_t check_mask = 0x0040; - IO_IRQ_STATUS |= 0x0040; - - m_2khz_divider++; - if (m_2khz_divider == 2) - { - m_2khz_divider = 0; - IO_IRQ_STATUS |= 0x0020; - check_mask |= 0x0020; - - m_1khz_divider++; - if (m_1khz_divider == 2) - { - m_1khz_divider = 0; - IO_IRQ_STATUS |= 0x0010; - check_mask |= 0x0010; - - m_4hz_divider++; - if (m_4hz_divider == 256) - { - m_4hz_divider = 0; - IO_IRQ_STATUS |= 0x0008; - check_mask |= 0x0008; - } - } - } - - const uint16_t changed = (old & IO_IRQ_ENABLE) ^ (IO_IRQ_STATUS & IO_IRQ_ENABLE); - if (changed) - check_irqs(check_mask); -} - -void spg2xx_device::uart_transmit_tick() +WRITE_LINE_MEMBER(spg2xx_device::audioirq_w) { - LOGMASKED(LOG_UART, "uart_transmit_tick: Transmitting %02x, setting TxReady, clearing TxBusy\n", (uint8_t)m_io_regs[0x35]); - m_uart_tx((uint8_t)m_io_regs[0x35]); - m_io_regs[0x31] |= 0x0002; - m_io_regs[0x31] &= ~0x0040; - if (BIT(m_io_regs[0x30], 1)) - { - const uint16_t old = IO_IRQ_STATUS; - IO_IRQ_STATUS |= 0x0100; - m_uart_tx_irq = true; - LOGMASKED(LOG_UART, "uart_transmit_tick: Setting UART IRQ bit\n"); - if (IO_IRQ_STATUS != old) - { - LOGMASKED(LOG_UART, "uart_transmit_tick: Bit newly set, checking IRQs\n"); - check_irqs(0x0100); - } - } + m_cpu->set_state_unsynced(UNSP_IRQ4_LINE, state); } -void spg2xx_device::uart_receive_tick() +WRITE_LINE_MEMBER(spg2xx_device::extirq_w) { - LOGMASKED(LOG_UART, "uart_receive_tick: Setting RBF and RxRDY\n"); - m_io_regs[0x31] |= 0x81; - m_uart_rx_available = true; - if (BIT(m_io_regs[0x30], 0)) - { - LOGMASKED(LOG_UART, "uart_receive_tick: RxIntEn is set, setting rx_irq to true and setting UART IRQ\n"); - m_uart_rx_irq = true; - IO_IRQ_STATUS |= 0x0100; - check_irqs(0x0100); - } + m_cpu->set_state_unsynced(UNSP_IRQ5_LINE, state); } -void spg2xx_device::extint_w(int channel, bool state) +WRITE_LINE_MEMBER(spg2xx_device::ffreq1_w) { - LOGMASKED(LOG_EXTINT, "Setting extint channel %d to %s\n", channel, state ? "true" : "false"); - bool old = m_extint[channel]; - m_extint[channel] = state; - if (old != state) - { - check_extint_irq(channel); - } + m_cpu->set_state_unsynced(UNSP_IRQ6_LINE, state); } -void spg2xx_device::check_extint_irq(int channel) +WRITE_LINE_MEMBER(spg2xx_device::ffreq2_w) { - LOGMASKED(LOG_EXTINT, "%sing extint %d interrupt\n", m_extint[channel] ? "rais" : "lower", channel + 1); - const uint16_t mask = (channel == 0) ? 0x0200 : 0x1000; - const uint16_t old_irq = IO_IRQ_STATUS; - if (m_extint[channel]) - IO_IRQ_STATUS |= mask; - else - IO_IRQ_STATUS &= ~mask; - - if (old_irq != IO_IRQ_STATUS) - { - LOGMASKED(LOG_EXTINT, "extint IRQ changed, so checking interrupts\n"); - check_irqs(mask); - } + m_cpu->set_state_unsynced(UNSP_IRQ7_LINE, state); } -void spg2xx_device::check_irqs(const uint16_t changed) -{ - // { - // m_cpu->set_state_unsynced(UNSP_IRQ1_LINE, ASSERT_LINE); - // } - - if (changed & 0x0c00) // Timer A, Timer B IRQ - { - LOGMASKED(LOG_TIMERS, "%ssserting IRQ2 (%04x, %04x)\n", (IO_IRQ_ENABLE & IO_IRQ_STATUS & 0x0c00) ? "A" : "Dea", (IO_IRQ_ENABLE & IO_IRQ_STATUS & 0x0c00), changed); - m_cpu->set_state_unsynced(UNSP_IRQ2_LINE, (IO_IRQ_ENABLE & IO_IRQ_STATUS & 0x0c00) ? ASSERT_LINE : CLEAR_LINE); - } - - if (changed & 0x2100) // UART, ADC IRQ - { - LOGMASKED(LOG_UART, "%ssserting IRQ3 (%04x, %04x)\n", (IO_IRQ_ENABLE & IO_IRQ_STATUS & 0x2100) ? "A" : "Dea", (IO_IRQ_ENABLE & IO_IRQ_STATUS & 0x2100), changed); - m_cpu->set_state_unsynced(UNSP_IRQ3_LINE, (IO_IRQ_ENABLE & IO_IRQ_STATUS & 0x2100) ? ASSERT_LINE : CLEAR_LINE); - } - if (changed & 0x1200) // External IRQ - { - LOGMASKED(LOG_UART, "%ssserting IRQ5 (%04x, %04x)\n", (IO_IRQ_ENABLE & IO_IRQ_STATUS & 0x1200) ? "A" : "Dea", (IO_IRQ_ENABLE & IO_IRQ_STATUS & 0x1200), changed); - m_cpu->set_state_unsynced(UNSP_IRQ5_LINE, (IO_IRQ_ENABLE & IO_IRQ_STATUS & 0x1200) ? ASSERT_LINE : CLEAR_LINE); - } - if (changed & 0x0070) // 1024Hz, 2048Hz, 4096Hz IRQ - { - LOGMASKED(LOG_TIMERS, "%ssserting IRQ6 (%04x, %04x)\n", (IO_IRQ_ENABLE & IO_IRQ_STATUS & 0x0070) ? "A" : "Dea", (IO_IRQ_ENABLE & IO_IRQ_STATUS & 0x0070), changed); - m_cpu->set_state_unsynced(UNSP_IRQ6_LINE, (IO_IRQ_ENABLE & IO_IRQ_STATUS & 0x0070) ? ASSERT_LINE : CLEAR_LINE); - } - - if (changed & 0x008b) // TMB1, TMB2, 4Hz, key change IRQ - { - LOGMASKED(LOG_IRQS, "%ssserting IRQ7 (%04x, %04x)\n", (IO_IRQ_ENABLE & IO_IRQ_STATUS & 0x008b) ? "A" : "Dea", (IO_IRQ_ENABLE & IO_IRQ_STATUS & 0x008b), changed); - m_cpu->set_state_unsynced(UNSP_IRQ7_LINE, (IO_IRQ_ENABLE & IO_IRQ_STATUS & 0x008b) ? ASSERT_LINE : CLEAR_LINE); - } -} - -uint16_t spg2xx_device::do_special_gpio(uint32_t index, uint16_t mask) +READ16_MEMBER(spg2xx_device::space_r) { - uint16_t data = 0; - switch (index) - { - case 0: // Port A - if (mask & 0xe000) - { - const uint8_t csel = m_cpu->get_csb() & 0x0e; - data = (csel << 12) & mask; - } - break; - case 1: // Port B - // To do - break; - case 2: // Port C - // To do - break; - default: - // Can't happen - break; - } - return data; + address_space &cpuspace = m_cpu->space(AS_PROGRAM); + return cpuspace.read_word(offset); } -void spg2xx_device::do_gpio(uint32_t offset, bool write) +void spg2xx_device::configure_spg_io(spg2xx_io_device* io) { - uint32_t index = (offset - 1) / 5; - uint16_t buffer = m_io_regs[5 * index + 2]; - uint16_t dir = m_io_regs[5 * index + 3]; - uint16_t attr = m_io_regs[5 * index + 4]; - uint16_t special = m_io_regs[5 * index + 5]; - - uint16_t push = dir; - uint16_t pull = ~dir; - uint16_t what = (buffer & (push | pull)); - what ^= (dir & ~attr); - what &= ~special; - - switch (index) - { - case 0: - if (write) - m_porta_out(0, what, push &~ special); - what = (what & ~pull); - if (!write) - what |= m_porta_in(0, pull &~ special) & pull; - break; - case 1: - if (write) - m_portb_out(0, what, push &~ special); - what = (what & ~pull); - if (!write) - what |= m_portb_in(0, pull &~ special) & pull; - break; - case 2: - if (write) - m_portc_out(0, what, push &~ special); - what = (what & ~pull); - if (!write) - what |= m_portc_in(0, pull &~ special) & pull; - break; - } - - what |= do_special_gpio(index, special); - m_io_regs[5 * index + 1] = what; + io->porta_in().set(FUNC(spg2xx_device::porta_r)); + io->portb_in().set(FUNC(spg2xx_device::portb_r)); + io->portc_in().set(FUNC(spg2xx_device::portc_r)); + io->porta_out().set(FUNC(spg2xx_device::porta_w)); + io->portb_out().set(FUNC(spg2xx_device::portb_w)); + io->portc_out().set(FUNC(spg2xx_device::portc_w)); + io->adc_in<0>().set(FUNC(spg2xx_device::adc_r<0>)); + io->adc_in<1>().set(FUNC(spg2xx_device::adc_r<1>)); + io->eeprom_w().set(FUNC(spg2xx_device::eepromx_w)); + io->eeprom_r().set(FUNC(spg2xx_device::eepromx_r)); + io->uart_tx().set(FUNC(spg2xx_device::tx_w)); + io->chip_select().set(FUNC(spg2xx_device::cs_w)); + io->pal_read_callback().set(FUNC(spg2xx_device::get_pal_ntsc)); + io->write_timer_irq_callback().set(FUNC(spg2xx_device::timerirq_w)); + io->write_uart_adc_irq_callback().set(FUNC(spg2xx_device::uartirq_w)); + io->write_external_irq_callback().set(FUNC(spg2xx_device::extirq_w)); + io->write_ffrq_tmr1_irq_callback().set(FUNC(spg2xx_device::ffreq1_w)); + io->write_ffrq_tmr2_irq_callback().set(FUNC(spg2xx_device::ffreq2_w)); } -void spg2xx_device::do_i2c() +void spg24x_device::device_add_mconfig(machine_config &config) { - const uint16_t addr = ((m_io_regs[0x5b] & 0x06) << 7) | (uint8_t)m_io_regs[0x5c]; - - if (m_io_regs[0x58] & 0x40) // Serial EEPROM read - m_io_regs[0x5e] = m_eeprom_r(addr); - else - m_eeprom_w(addr, m_io_regs[0x5d]); - - m_io_regs[0x59] |= 1; -} + SPG2XX_AUDIO(config, m_spg_audio, DERIVED_CLOCK(1, 1)); + m_spg_audio->write_irq_callback().set(FUNC(spg24x_device::audioirq_w)); + m_spg_audio->space_read_callback().set(FUNC(spg24x_device::space_r)); -void spg2xx_device::do_cpu_dma(uint32_t len) -{ - address_space &mem = m_cpu->space(AS_PROGRAM); + m_spg_audio->add_route(0, *this, 1.0, AUTO_ALLOC_INPUT, 0); + m_spg_audio->add_route(1, *this, 1.0, AUTO_ALLOC_INPUT, 1); - uint32_t src = ((m_io_regs[0x101] & 0x3f) << 16) | m_io_regs[0x100]; - uint32_t dst = m_io_regs[0x103] & 0x3fff; + SPG24X_IO(config, m_spg_io, DERIVED_CLOCK(1, 1), m_cpu, m_screen); + configure_spg_io(m_spg_io); - for (uint32_t j = 0; j < len; j++) - { - mem.write_word((dst + j) & 0x3fff, mem.read_word(src + j)); - } + SPG2XX_SYSDMA(config, m_spg_sysdma, DERIVED_CLOCK(1, 1), m_cpu); - src += len; - m_io_regs[0x100] = (uint16_t)src; - m_io_regs[0x101] = (src >> 16) & 0x3f; - m_io_regs[0x102] = 0; - m_io_regs[0x103] = (dst + len) & 0x3fff; + SPG24X_VIDEO(config, m_spg_video, DERIVED_CLOCK(1, 1), m_cpu, m_screen); + m_spg_video->sprlimit_read_callback().set(FUNC(spg24x_device::get_sprlimit)); + m_spg_video->rowscrolloffset_read_callback().set(FUNC(spg24x_device::get_rowscrolloffset)); + m_spg_video->write_video_irq_callback().set(FUNC(spg24x_device::videoirq_w)); } -void spg2xx_device::device_add_mconfig(machine_config &config) +void spg28x_device::device_add_mconfig(machine_config &config) { SPG2XX_AUDIO(config, m_spg_audio, DERIVED_CLOCK(1, 1)); - m_spg_audio->write_irq_callback().set(FUNC(spg2xx_device::audioirq_w)); - m_spg_audio->space_read_callback().set(FUNC(spg2xx_device::space_r)); + m_spg_audio->write_irq_callback().set(FUNC(spg28x_device::audioirq_w)); + m_spg_audio->space_read_callback().set(FUNC(spg28x_device::space_r)); m_spg_audio->add_route(0, *this, 1.0, AUTO_ALLOC_INPUT, 0); m_spg_audio->add_route(1, *this, 1.0, AUTO_ALLOC_INPUT, 1); + + SPG28X_IO(config, m_spg_io, DERIVED_CLOCK(1, 1), m_cpu, m_screen); + configure_spg_io(m_spg_io); + + SPG2XX_SYSDMA(config, m_spg_sysdma, DERIVED_CLOCK(1, 1), m_cpu); + + SPG24X_VIDEO(config, m_spg_video, DERIVED_CLOCK(1, 1), m_cpu, m_screen); + m_spg_video->sprlimit_read_callback().set(FUNC(spg28x_device::get_sprlimit)); + m_spg_video->rowscrolloffset_read_callback().set(FUNC(spg28x_device::get_rowscrolloffset)); + m_spg_video->write_video_irq_callback().set(FUNC(spg28x_device::videoirq_w)); } diff --git a/src/devices/machine/spg2xx.h b/src/devices/machine/spg2xx.h index b35559d0dd3..806e8395c4d 100644 --- a/src/devices/machine/spg2xx.h +++ b/src/devices/machine/spg2xx.h @@ -36,6 +36,9 @@ #include "cpu/unsp/unsp.h" #include "spg2xx_audio.h" +#include "spg2xx_io.h" +#include "spg2xx_sysdma.h" +#include "spg2xx_video.h" #include "screen.h" class spg2xx_device : public device_t, public device_mixer_interface @@ -64,14 +67,16 @@ public: auto chip_select() { return m_chip_sel.bind(); } - void uart_rx(uint8_t data); - - void extint_w(int channel, bool state); + required_device<spg2xx_audio_device> m_spg_audio; + required_device<spg2xx_io_device> m_spg_io; + required_device<spg2xx_sysdma_device> m_spg_sysdma; + required_device<spg2xx_video_device> m_spg_video; - uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); - DECLARE_WRITE_LINE_MEMBER(vblank); + void extint_w(int channel, bool state) { m_spg_io->extint_w(channel, state); } + void uart_rx(uint8_t data) { m_spg_io->uart_rx(data); } - required_device<spg2xx_audio_device> m_spg_audio; + DECLARE_WRITE_LINE_MEMBER(vblank) { m_spg_video->vblank(state); } + uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) { return m_spg_video->screen_update(screen, bitmap, cliprect); } protected: spg2xx_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, const uint32_t sprite_limit) @@ -80,132 +85,28 @@ protected: m_sprite_limit = sprite_limit; } - virtual void device_add_mconfig(machine_config &config) override; - - enum - { - PAGE_ENABLE_MASK = 0x0008, - PAGE_WALLPAPER_MASK = 0x0004, - - SPRITE_ENABLE_MASK = 0x0001, - SPRITE_COORD_TL_MASK = 0x0002, - - PAGE_DEPTH_FLAG_MASK = 0x3000, - PAGE_DEPTH_FLAG_SHIFT = 12, - PAGE_TILE_HEIGHT_MASK = 0x00c0, - PAGE_TILE_HEIGHT_SHIFT = 6, - PAGE_TILE_WIDTH_MASK = 0x0030, - PAGE_TILE_WIDTH_SHIFT = 4, - TILE_X_FLIP = 0x0004, - TILE_Y_FLIP = 0x0008 - }; - - DECLARE_READ16_MEMBER(video_r); - DECLARE_WRITE16_MEMBER(video_w); - - virtual DECLARE_READ16_MEMBER(io_r); - virtual DECLARE_WRITE16_MEMBER(io_w); - + DECLARE_WRITE_LINE_MEMBER(videoirq_w); DECLARE_WRITE_LINE_MEMBER(audioirq_w); - DECLARE_READ16_MEMBER(space_r); + DECLARE_WRITE_LINE_MEMBER(timerirq_w); + DECLARE_WRITE_LINE_MEMBER(uartirq_w); + DECLARE_WRITE_LINE_MEMBER(extirq_w); + DECLARE_WRITE_LINE_MEMBER(ffreq1_w); + DECLARE_WRITE_LINE_MEMBER(ffreq2_w); - void check_extint_irq(int channel); - void check_irqs(const uint16_t changed); - inline void check_video_irq(); + DECLARE_READ16_MEMBER(space_r); void spg2xx_map(address_map &map); - static const device_timer_id TIMER_TMB1 = 0; - static const device_timer_id TIMER_TMB2 = 1; - static const device_timer_id TIMER_SCREENPOS = 2; - static const device_timer_id TIMER_BEAT = 3; - static const device_timer_id TIMER_UART_TX = 4; - static const device_timer_id TIMER_UART_RX = 5; - static const device_timer_id TIMER_4KHZ = 6; - static const device_timer_id TIMER_SRC_AB = 7; - static const device_timer_id TIMER_SRC_C = 8; - virtual void device_start() override; virtual void device_reset() override; - virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override; - - void update_porta_special_modes(); - void update_portb_special_modes(); - void do_gpio(uint32_t offset, bool write); - uint16_t do_special_gpio(uint32_t index, uint16_t mask); - - void update_timer_b_rate(); - void update_timer_ab_src(); - void update_timer_c_src(); - void increment_timer_a(); - - void uart_transmit_tick(); - void uart_receive_tick(); - - void system_timer_tick(); - - void do_i2c(); - void do_cpu_dma(uint32_t len); - void do_sprite_dma(uint32_t len); - - enum blend_enable_t : bool - { - BlendOff = false, - BlendOn = true - }; - - enum rowscroll_enable_t : bool - { - RowScrollOff = false, - RowScrollOn = true - }; - - enum flipx_t : bool - { - FlipXOff = false, - FlipXOn = true - }; - - void apply_saturation(const rectangle &cliprect); - void apply_fade(const rectangle &cliprect); - - template<blend_enable_t Blend, rowscroll_enable_t RowScroll, flipx_t FlipX> - void blit(const rectangle &cliprect, uint32_t line, uint32_t xoff, uint32_t yoff, uint32_t attr, uint32_t ctrl, uint32_t bitmap_addr, uint16_t tile); - void blit_page(const rectangle &cliprect, uint32_t scanline, int depth, uint32_t bitmap_addr, uint16_t *regs); - void blit_sprite(const rectangle &cliprect, uint32_t scanline, int depth, uint32_t base_addr); - void blit_sprites(const rectangle &cliprect, uint32_t scanline, int depth); - - uint8_t mix_channel(uint8_t a, uint8_t b); - - uint32_t m_screenbuf[320 * 240]; - uint8_t m_rgb5_to_rgb8[32]; - uint32_t m_rgb555_to_rgb888[0x8000]; - - bool m_hide_page0; - bool m_hide_page1; - bool m_hide_sprites; - bool m_debug_sprites; - bool m_debug_blit; - bool m_debug_palette; - uint8_t m_sprite_index_to_debug; - - - uint16_t m_io_regs[0x200]; - uint8_t m_uart_rx_fifo[8]; - uint8_t m_uart_rx_fifo_start; - uint8_t m_uart_rx_fifo_end; - uint8_t m_uart_rx_fifo_count; - bool m_uart_rx_available; - bool m_uart_rx_irq; - bool m_uart_tx_irq; - - bool m_extint[2]; - - uint16_t m_video_regs[0x100]; - uint32_t m_sprite_limit; - int m_rowscrolloffset; // auto racing in 'zone60' minigames needs this to be 15, the JAKKS games (Star Wars Revenge of the sith - Gunship Battle, Wheel of Fortune, Namco Ms. Pac-Man 5-in-1 Pole Position) need it to be 0, where does it come from? + // TODO: these are fixed values, put them in relevant devices? + uint16_t m_sprite_limit; + uint16_t m_rowscrolloffset; // auto racing in 'zone60' minigames needs this to be 15, the JAKKS games (Star Wars Revenge of the sith - Gunship Battle, Wheel of Fortune, Namco Ms. Pac-Man 5-in-1 Pole Position) need it to be 0, where does it come from? uint16_t m_pal_flag; + DECLARE_READ16_MEMBER(get_sprlimit) { return m_sprite_limit; } + DECLARE_READ16_MEMBER(get_rowscrolloffset) { return m_rowscrolloffset; } + DECLARE_READ16_MEMBER(get_pal_ntsc) { return m_pal_flag; } devcb_write16 m_porta_out; devcb_write16 m_portb_out; @@ -223,31 +124,26 @@ protected: devcb_write8 m_chip_sel; - uint16_t m_timer_a_preload; - uint16_t m_timer_b_preload; - uint16_t m_timer_b_divisor; - uint16_t m_timer_b_tick_rate; - - emu_timer *m_tmb1; - emu_timer *m_tmb2; - emu_timer *m_timer_src_ab; - emu_timer *m_timer_src_c; emu_timer *m_screenpos_timer; - emu_timer *m_4khz_timer; - uint32_t m_2khz_divider; - uint32_t m_1khz_divider; - uint32_t m_4hz_divider; - - uint32_t m_uart_baud_rate; - emu_timer *m_uart_tx_timer; - emu_timer *m_uart_rx_timer; - required_device<unsp_device> m_cpu; required_device<screen_device> m_screen; - required_shared_ptr<uint16_t> m_scrollram; - required_shared_ptr<uint16_t> m_paletteram; - required_shared_ptr<uint16_t> m_spriteram; + + void configure_spg_io(spg2xx_io_device* io); + + DECLARE_READ16_MEMBER(porta_r) { return m_porta_in(); } + DECLARE_READ16_MEMBER(portb_r) { return m_portb_in(); } + DECLARE_READ16_MEMBER(portc_r) { return m_portc_in(); } + DECLARE_WRITE16_MEMBER(porta_w) { m_porta_out(offset, data, mem_mask); } + DECLARE_WRITE16_MEMBER(portb_w) { m_portb_out(offset, data, mem_mask); } + DECLARE_WRITE16_MEMBER(portc_w) { m_portc_out(offset, data, mem_mask); } + template <size_t Line> DECLARE_READ16_MEMBER(adc_r) { return m_adc_in[Line](); } + + DECLARE_WRITE8_MEMBER(eepromx_w) { m_eeprom_w(offset, data, mem_mask); } + DECLARE_READ8_MEMBER(eepromx_r) { return m_eeprom_r(); }; + + DECLARE_WRITE8_MEMBER(tx_w) { m_uart_tx(offset, data, mem_mask); } + DECLARE_WRITE8_MEMBER(cs_w) { m_chip_sel(offset, data, mem_mask); } }; class spg24x_device : public spg2xx_device @@ -262,6 +158,9 @@ public: } spg24x_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + virtual void device_add_mconfig(machine_config &config) override; + }; class spg28x_device : public spg2xx_device @@ -277,7 +176,8 @@ public: spg28x_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); - virtual DECLARE_WRITE16_MEMBER(io_w) override; + virtual void device_add_mconfig(machine_config &config) override; + }; DECLARE_DEVICE_TYPE(SPG24X, spg24x_device) diff --git a/src/devices/machine/spg2xx_audio.h b/src/devices/machine/spg2xx_audio.h index 2ea8b26651a..22f5108e405 100644 --- a/src/devices/machine/spg2xx_audio.h +++ b/src/devices/machine/spg2xx_audio.h @@ -204,7 +204,7 @@ protected: AUDIO_CHAN_OFFSET_MASK = 0xf0f, }; - + enum // at audio write offset 0x400 in spg2xx { diff --git a/src/devices/machine/spg2xx_io.cpp b/src/devices/machine/spg2xx_io.cpp new file mode 100644 index 00000000000..f8daaef5bd0 --- /dev/null +++ b/src/devices/machine/spg2xx_io.cpp @@ -0,0 +1,1313 @@ +// license:BSD-3-Clause +// copyright-holders:Ryan Holtz + +/* this is used by the SPG110, SPG24x and SPG28x + basic I/O behavior is definitely the same on the SPG110 but + the rest needs verifying */ + +#include "emu.h" +#include "spg2xx_io.h" + +DEFINE_DEVICE_TYPE(SPG24X_IO, spg24x_io_device, "spg24x_io", "SPG240-series System-on-a-Chip I/O") +DEFINE_DEVICE_TYPE(SPG28X_IO, spg28x_io_device, "spg28x_io", "SPG280-series System-on-a-Chip I/O") + +#define LOG_IO_READS (1U << 1) +#define LOG_IO_WRITES (1U << 2) +#define LOG_UNKNOWN_IO (1U << 3) +#define LOG_IRQS (1U << 4) +#define LOG_VLINES (1U << 5) +#define LOG_GPIO (1U << 6) +#define LOG_UART (1U << 7) +#define LOG_I2C (1U << 8) +#define LOG_SEGMENT (1U << 10) +#define LOG_WATCHDOG (1U << 11) +#define LOG_TIMERS (1U << 12) +#define LOG_FIQ (1U << 25) +#define LOG_SIO (1U << 26) +#define LOG_EXT_MEM (1U << 27) +#define LOG_EXTINT (1U << 28) +#define LOG_IO (LOG_IO_READS | LOG_IO_WRITES | LOG_IRQS | LOG_GPIO | LOG_UART | LOG_I2C | LOG_TIMERS | LOG_EXTINT | LOG_UNKNOWN_IO) +#define LOG_ALL (LOG_IO | LOG_VLINES | LOG_SEGMENT | LOG_WATCHDOG | LOG_FIQ | LOG_SIO | LOG_EXT_MEM) + +#define VERBOSE (0) +#include "logmacro.h" + + +#define IO_IRQ_ENABLE m_io_regs[0x21] +#define IO_IRQ_STATUS m_io_regs[0x22] + +spg2xx_io_device::spg2xx_io_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) + : device_t(mconfig, type, tag, owner, clock) + , m_porta_out(*this) + , m_portb_out(*this) + , m_portc_out(*this) + , m_porta_in(*this) + , m_portb_in(*this) + , m_portc_in(*this) + , m_adc_in{{*this}, {*this}} + , m_eeprom_w(*this) + , m_eeprom_r(*this) + , m_uart_tx(*this) + , m_chip_sel(*this) + , m_cpu(*this, finder_base::DUMMY_TAG) + , m_screen(*this, finder_base::DUMMY_TAG) + , m_pal_read_cb(*this) + , m_timer_irq_cb(*this) + , m_uart_adc_irq_cb(*this) + , m_external_irq_cb(*this) + , m_ffreq_tmr1_irq_cb(*this) + , m_ffreq_tmr2_irq_cb(*this) +{ +} + +spg24x_io_device::spg24x_io_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : spg2xx_io_device(mconfig, SPG24X_IO, tag, owner, clock, 256) +{ +} + +spg28x_io_device::spg28x_io_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : spg2xx_io_device(mconfig, SPG28X_IO, tag, owner, clock, 64) +{ +} + + +void spg2xx_io_device::device_start() +{ + m_porta_out.resolve_safe(); + m_portb_out.resolve_safe(); + m_portc_out.resolve_safe(); + m_porta_in.resolve_safe(0); + m_portb_in.resolve_safe(0); + m_portc_in.resolve_safe(0); + m_adc_in[0].resolve_safe(0x0fff); + m_adc_in[1].resolve_safe(0x0fff); + m_eeprom_w.resolve_safe(); + m_eeprom_r.resolve_safe(0); + m_uart_tx.resolve_safe(); + m_chip_sel.resolve_safe(); + m_pal_read_cb.resolve_safe(0); + + m_timer_irq_cb.resolve(); + m_uart_adc_irq_cb.resolve(); + m_external_irq_cb.resolve(); + m_ffreq_tmr1_irq_cb.resolve(); + m_ffreq_tmr2_irq_cb.resolve(); + + m_tmb1 = timer_alloc(TIMER_TMB1); + m_tmb2 = timer_alloc(TIMER_TMB2); + m_tmb1->adjust(attotime::never); + m_tmb2->adjust(attotime::never); + + m_uart_tx_timer = timer_alloc(TIMER_UART_TX); + m_uart_tx_timer->adjust(attotime::never); + + m_uart_rx_timer = timer_alloc(TIMER_UART_RX); + m_uart_rx_timer->adjust(attotime::never); + + m_4khz_timer = timer_alloc(TIMER_4KHZ); + m_4khz_timer->adjust(attotime::never); + + m_timer_src_ab = timer_alloc(TIMER_SRC_AB); + m_timer_src_ab->adjust(attotime::never); + + m_timer_src_c = timer_alloc(TIMER_SRC_C); + m_timer_src_c->adjust(attotime::never); + + save_item(NAME(m_timer_a_preload)); + save_item(NAME(m_timer_b_preload)); + save_item(NAME(m_timer_b_divisor)); + save_item(NAME(m_timer_b_tick_rate)); + + save_item(NAME(m_io_regs)); + + save_item(NAME(m_extint)); + + save_item(NAME(m_2khz_divider)); + save_item(NAME(m_1khz_divider)); + save_item(NAME(m_4hz_divider)); + + save_item(NAME(m_uart_baud_rate)); + +} + +void spg2xx_io_device::device_reset() +{ + memset(m_io_regs, 0, 0x100 * sizeof(uint16_t)); + + m_timer_a_preload = 0; + m_timer_b_preload = 0; + m_timer_b_divisor = 0; + m_timer_b_tick_rate = 0; + + m_io_regs[0x23] = 0x0028; + m_io_regs[0x2c] = 0x1418; + m_io_regs[0x2d] = 0x1658; + + m_uart_rx_available = false; + memset(m_uart_rx_fifo, 0, ARRAY_LENGTH(m_uart_rx_fifo)); + m_uart_rx_fifo_start = 0; + m_uart_rx_fifo_end = 0; + m_uart_rx_fifo_count = 0; + m_uart_tx_irq = false; + m_uart_rx_irq = false; + + memset(m_extint, 0, sizeof(bool) * 2); + + m_4khz_timer->adjust(attotime::from_hz(4096), 0, attotime::from_hz(4096)); + + m_2khz_divider = 0; + m_1khz_divider = 0; + m_4hz_divider = 0; +} + +/************************* +* Machine Hardware * +*************************/ + +void spg2xx_io_device::uart_rx(uint8_t data) +{ + LOGMASKED(LOG_UART, "uart_rx: Pulling %02x into receive FIFO\n", data); + if (BIT(m_io_regs[0x30], 6)) + { + m_uart_rx_fifo[m_uart_rx_fifo_end] = data; + m_uart_rx_fifo_end = (m_uart_rx_fifo_end + 1) % ARRAY_LENGTH(m_uart_rx_fifo); + m_uart_rx_fifo_count++; + if (m_uart_rx_timer->remaining() == attotime::never) + m_uart_rx_timer->adjust(attotime::from_ticks(BIT(m_io_regs[0x30], 5) ? 11 : 10, m_uart_baud_rate)); + } +} + +READ16_MEMBER(spg2xx_io_device::io_r) +{ + static const char *const gpioregs[] = { "GPIO Data Port", "GPIO Buffer Port", "GPIO Direction Port", "GPIO Attribute Port", "GPIO IRQ/Latch Port" }; + static const char gpioports[] = { 'A', 'B', 'C' }; + + uint16_t val = m_io_regs[offset]; + + switch (offset) + { + case 0x01: case 0x06: case 0x0b: // GPIO Data Port A/B/C + do_gpio(offset, false); + LOGMASKED(LOG_GPIO, "%s: io_r: %s %c = %04x\n", machine().describe_context(), gpioregs[(offset - 1) % 5], gpioports[(offset - 1) / 5], m_io_regs[offset]); + val = m_io_regs[offset]; + break; + + case 0x02: case 0x03: case 0x04: case 0x05: + case 0x07: case 0x08: case 0x09: case 0x0a: + case 0x0c: case 0x0d: case 0x0e: case 0x0f: // Other GPIO regs + LOGMASKED(LOG_GPIO, "%s: io_r: %s %c = %04x\n", machine().describe_context(), gpioregs[(offset - 1) % 5], gpioports[(offset - 1) / 5], m_io_regs[offset]); + break; + + case 0x10: // Timebase Control + LOGMASKED(LOG_IO_READS, "io_r: Timebase Control = %04x\n", val); + break; + + case 0x12: // Timer A Data + LOGMASKED(LOG_IO_WRITES, "io_r: Timer A Data = %04x\n", val); + break; + + case 0x1c: // Video line counter + val = m_screen->vpos(); + LOGMASKED(LOG_VLINES, "io_r: Video Line = %04x\n", val); + break; + + case 0x20: // System Control + LOGMASKED(LOG_IO_READS, "io_r: System Control = %04x\n", val); + break; + + case 0x21: // IRQ Control + LOGMASKED(LOG_IRQS, "%s: io_r: I/O IRQ Control = %04x\n", machine().describe_context(), val); + break; + + case 0x22: // IRQ Status + LOGMASKED(LOG_IRQS, "%s: io_r: I/O IRQ Status = %04x\n", machine().describe_context(), val); + break; + + case 0x23: // External Memory Control + LOGMASKED(LOG_IO_READS, "%s: io_r: Ext. Memory Control = %04x\n", machine().describe_context(), val); + break; + + case 0x25: // ADC Control + LOGMASKED(LOG_IO_READS, "io_r: ADC Control = %04x\n", val); + break; + + case 0x27: // ADC Data + { + m_io_regs[0x27] = 0; + const uint16_t old = IO_IRQ_STATUS; + IO_IRQ_STATUS &= ~0x2000; + const uint16_t changed = (old & IO_IRQ_ENABLE) ^ (IO_IRQ_STATUS & IO_IRQ_ENABLE); + if (changed) + check_irqs(changed); + LOGMASKED(LOG_IO_READS, "%s: io_r: ADC Data = %04x\n", machine().describe_context(), val); + break; + } + + case 0x29: // Wakeup Source + LOGMASKED(LOG_IO_READS, "io_r: Wakeup Source = %04x\n", val); + break; + + case 0x2b: + { + uint16_t pal = m_pal_read_cb(); + LOGMASKED(LOG_IO_READS, "io_r: NTSC/PAL = %04x\n", pal); + return pal; + } + + case 0x2c: // PRNG 0 + { + const uint16_t value = m_io_regs[0x2c]; + m_io_regs[0x2c] = ((value << 1) | (BIT(value, 14) ^ BIT(value, 13))) & 0x7fff; + return value; + } + + case 0x2d: // PRNG 1 + { + const uint16_t value = m_io_regs[0x2d]; + m_io_regs[0x2d] = ((value << 1) | (BIT(value, 14) ^ BIT(value, 13))) & 0x7fff; + return value; + } + + case 0x2e: // FIQ Source Select + LOGMASKED(LOG_FIQ, "io_r: FIQ Source Select = %04x\n", val); + break; + + case 0x2f: // Data Segment + val = m_cpu->get_ds(); + LOGMASKED(LOG_SEGMENT, "io_r: Data Segment = %04x\n", val); + break; + + default: + LOGMASKED(LOG_UNKNOWN_IO, "io_r: Unknown register %04x\n", 0x3d00 + offset); + break; + } + + return val; +} + +READ16_MEMBER(spg2xx_io_device::io_extended_r) +{ + // this set of registers might only be on the 24x not the 11x + + offset += 0x30; + + uint16_t val = m_io_regs[offset]; + + switch (offset) + { + case 0x30: // UART Control + LOGMASKED(LOG_UART, "%s: io_r: UART Control = %04x\n", machine().describe_context(), val); + break; + + case 0x31: // UART Status + //LOGMASKED(LOG_UART, "%s: io_r: UART Status = %04x\n", machine().describe_context(), val); + break; + + case 0x36: // UART RX Data + if (m_uart_rx_available) + { + m_io_regs[0x31] &= ~0x0081; + LOGMASKED(LOG_UART, "UART Rx data is available, clearing bits\n"); + if (m_uart_rx_fifo_count) + { + LOGMASKED(LOG_UART, "Remaining count %d, value %02x\n", m_uart_rx_fifo_count, m_uart_rx_fifo[m_uart_rx_fifo_start]); + m_io_regs[0x36] = m_uart_rx_fifo[m_uart_rx_fifo_start]; + val = m_io_regs[0x36]; + m_uart_rx_fifo_start = (m_uart_rx_fifo_start + 1) % ARRAY_LENGTH(m_uart_rx_fifo); + m_uart_rx_fifo_count--; + + if (m_uart_rx_fifo_count == 0) + { + m_uart_rx_available = false; + } + else + { + LOGMASKED(LOG_UART, "Remaining count %d, setting up timer\n", m_uart_rx_fifo_count); + //uart_receive_tick(); + if (m_uart_rx_timer->remaining() == attotime::never) + m_uart_rx_timer->adjust(attotime::from_ticks(BIT(m_io_regs[0x30], 5) ? 11 : 10, m_uart_baud_rate)); + } + } + else + { + m_uart_rx_available = false; + } + } + else + { + m_io_regs[0x37] |= 0x2000; + } + LOGMASKED(LOG_UART, "%s: io_r: UART Rx Data = %04x\n", machine().describe_context(), val); + break; + + case 0x37: // UART Rx FIFO Control + val &= ~0x0070; + val |= (m_uart_rx_available ? 7 : 0) << 4; + LOGMASKED(LOG_UART, "io_r: UART Rx FIFO Control = %04x\n", machine().describe_context(), val); + break; + + case 0x51: // unknown, polled by ClickStart cartridges ( clikstrt ) + return 0x8000; + + case 0x59: // I2C Status + LOGMASKED(LOG_I2C, "io_r: I2C Status = %04x\n", val); + break; + + case 0x5e: // I2C Data In + LOGMASKED(LOG_I2C, "io_r: I2C Data In = %04x\n", val); + break; + + default: + LOGMASKED(LOG_UNKNOWN_IO, "io_r: Unknown register %04x\n", 0x3d00 + offset); + break; + } + + return val; +} + +void spg2xx_io_device::update_porta_special_modes() +{ + static const char* const s_pa_special[4][16] = + { + // Input, Special 0 + // Input, Special 1 + // Output, Special 0 + // Output, Special 1 + + { "LP", "ExtClk2", "ExtClk1", "-", "SDA", "SlvRDY", "-", "-", "SPICLK", "-", "RxD", "SPISSB", "-", "-", "-", "-" }, + { "-", "-", "-", "SCK", "-", "SWS", "-", "-", "-", "-", "-", "-", "IRQ2B", "-", "-", "IRQ1B" }, + { "-", "-", "-", "SCK", "SDA", "SWS", "-", "-", "SPICLK", "TxD", "-", "SPISSB", "TAPWM", "TM1", "TBPWM", "TM2" }, + { "CSB3", "CSB2", "CSB1", "SCK", "SDA", "VSYNC", "HSYNC", "SYSCLK3", "SPICLK", "TxD", "SWS", "SPISSB", "-", "VSYNC", "HSYNC", "CSYNC" }, + }; + for (int bit = 15; bit >= 0; bit--) + { + if (!BIT(m_io_regs[0x05], bit)) + continue; + uint8_t type = (BIT(m_io_regs[0x03], bit) << 1) | BIT(m_io_regs[0x00], 0); + LOGMASKED(LOG_GPIO, " Bit %2d: %s\n", bit, s_pa_special[type][bit]); + } +} + +void spg2xx_io_device::update_portb_special_modes() +{ + static const char* const s_pb_special[4][8] = + { + // Input, Special 0 + // Input, Special 1 + // Output, Special 0 + // Output, Special 1 + + { "-", "-", "-", "-", "-", "-", "SDA", "SlvRDY" }, + { "-", "-", "-", "-", "-", "-", "SDA", "SlvRDY" }, + { "VSYNC", "HSYNC", "CSYNC", "-", "-", "SCK", "SDA", "SWS" }, + { "CSB3", "CSB2", "CSB1", "TBPWM", "TM2", "-", "-", "SYSCLK2" }, + }; + for (int bit = 7; bit >= 0; bit--) + { + if (!BIT(m_io_regs[0x0a], bit)) + continue; + uint8_t type = (BIT(m_io_regs[0x08], bit) << 1) | BIT(m_io_regs[0x00], 1); + LOGMASKED(LOG_GPIO, " Bit %2d: %s\n", bit, s_pb_special[type][bit]); + } +} + +void spg2xx_io_device::update_timer_b_rate() +{ + switch (m_io_regs[0x17] & 7) + { + case 0: + case 1: + case 5: + case 6: + case 7: + m_timer_src_c->adjust(attotime::never); + break; + case 2: + m_timer_src_c->adjust(attotime::from_hz(32768), 0, attotime::from_hz(32768)); + break; + case 3: + m_timer_src_c->adjust(attotime::from_hz(8192), 0, attotime::from_hz(8192)); + break; + case 4: + m_timer_src_c->adjust(attotime::from_hz(4096), 0, attotime::from_hz(4096)); + break; + } +} + +void spg2xx_io_device::update_timer_ab_src() +{ + if (m_timer_b_tick_rate == 0) + return; + + m_timer_b_divisor++; + if (m_timer_b_divisor >= m_timer_b_tick_rate) + { + m_timer_b_divisor = 0; + increment_timer_a(); + } +} + +void spg2xx_io_device::increment_timer_a() +{ + m_io_regs[0x12]++; + if (m_io_regs[0x12] == 0) + { + m_io_regs[0x12] = m_timer_a_preload; + const uint16_t old = IO_IRQ_STATUS; + IO_IRQ_STATUS |= 0x0800; + const uint16_t changed = (old & IO_IRQ_ENABLE) ^ (IO_IRQ_STATUS & IO_IRQ_ENABLE); + if (changed) + { + //printf("Timer A overflow\n"); + check_irqs(0x0800); + } + } +} + +void spg2xx_io_device::update_timer_c_src() +{ + m_io_regs[0x16]++; + if (m_io_regs[0x16] == 0) + { + m_io_regs[0x16] = m_timer_b_preload; + const uint16_t old = IO_IRQ_STATUS; + IO_IRQ_STATUS |= 0x0400; + const uint16_t changed = (old & IO_IRQ_ENABLE) ^ (IO_IRQ_STATUS & IO_IRQ_ENABLE); + if (changed) + { + printf("Timer B overflow\n"); + check_irqs(0x0400); + } + } +} + + +WRITE16_MEMBER(spg28x_io_device::io_extended_w) +{ + offset += 0x30; + + if (offset == 0x33) + { + m_io_regs[offset] = data; + m_uart_baud_rate = 27000000 / (0x10000 - m_io_regs[0x33]); + LOGMASKED(LOG_UART, "%s: io_w: UART Baud Rate scaler = %04x (%d baud)\n", machine().describe_context(), data, m_uart_baud_rate); + } + else + { + spg2xx_io_device::io_extended_w(space, offset-0x30, data, mem_mask); + } +} + +WRITE16_MEMBER(spg2xx_io_device::io_w) +{ + static const char *const gpioregs[] = { "GPIO Data Port", "GPIO Buffer Port", "GPIO Direction Port", "GPIO Attribute Port", "GPIO IRQ/Latch Port" }; + static const char gpioports[3] = { 'A', 'B', 'C' }; + + switch (offset) + { + case 0x00: // GPIO special function select + { + LOGMASKED(LOG_GPIO, "%s: io_w: GPIO Configuration = %04x (IOBWake:%d, IOAWake:%d, IOBSpecSel:%d, IOASpecSel:%d)\n", machine().describe_context(), data + , BIT(data, 4), BIT(data, 3), BIT(data, 1), BIT(data, 0)); + const uint16_t old = m_io_regs[offset]; + m_io_regs[offset] = data; + const uint16_t changed = old ^ data; + if (BIT(changed, 0)) + update_porta_special_modes(); + if (BIT(changed, 1)) + update_portb_special_modes(); + break; + } + + case 0x01: case 0x06: case 0x0b: // GPIO data, port A/B/C + offset++; + // Intentional fallthrough - we redirect data register writes to the buffer register. + + case 0x02: case 0x04: // Port A + case 0x07: case 0x09: // Port B + case 0x0c: case 0x0d: case 0x0e: case 0x0f: // Port C + LOGMASKED(LOG_GPIO, "%s: io_w: %s %c = %04x\n", machine().describe_context(), gpioregs[(offset - 1) % 5], gpioports[(offset - 1) / 5], data); + m_io_regs[offset] = data; + do_gpio(offset, true); + break; + + case 0x03: // Port A Direction + LOGMASKED(LOG_GPIO, "%s: io_w: GPIO Direction Port A = %04x\n", machine().describe_context(), data); + m_io_regs[offset] = data; + update_porta_special_modes(); + do_gpio(offset, true); + break; + + case 0x08: // Port B Direction + LOGMASKED(LOG_GPIO, "%s: io_w: GPIO Direction Port B = %04x\n", machine().describe_context(), data); + m_io_regs[offset] = data; + update_portb_special_modes(); + do_gpio(offset, true); + break; + + case 0x05: // Port A Special + LOGMASKED(LOG_GPIO, "%s: io_w: Port A Special Function Select: %04x\n", machine().describe_context(), data); + m_io_regs[offset] = data; + update_porta_special_modes(); + break; + + case 0x0a: // Port B Special + LOGMASKED(LOG_GPIO, "%s: io_w: Port B Special Function Select: %04x\n", machine().describe_context(), data); + m_io_regs[offset] = data; + update_portb_special_modes(); + break; + + case 0x10: // Timebase Control + { + static const char* const s_tmb1_sel[2][4] = + { + { "8Hz", "16Hz", "32Hz", "64Hz" }, + { "12kHz", "24kHz", "40kHz", "40kHz" } + }; + static const char* const s_tmb2_sel[2][4] = + { + { "128Hz", "256Hz", "512Hz", "1024Hz" }, + { "105kHz", "210kHz", "420kHz", "840kHz" } + }; + static const uint32_t s_tmb1_freq[2][4] = + { + { 8, 16, 32, 64 }, + { 12000, 24000, 40000, 40000 } + }; + static const uint32_t s_tmb2_freq[2][4] = + { + { 128, 256, 512, 1024 }, + { 105000, 210000, 420000, 840000 } + }; + LOGMASKED(LOG_TIMERS, "io_w: Timebase Control = %04x (Source:%s, TMB2:%s, TMB1:%s)\n", data, + BIT(data, 4) ? "27MHz" : "32768Hz", s_tmb2_sel[BIT(data, 4)][(data >> 2) & 3], s_tmb1_sel[BIT(data, 4)][data & 3]); + m_io_regs[offset] = data; + const uint8_t hifreq = BIT(data, 4); + const uint32_t tmb1freq = s_tmb1_freq[hifreq][data & 3]; + m_tmb1->adjust(attotime::from_hz(tmb1freq), 0, attotime::from_hz(tmb1freq)); + const uint32_t tmb2freq = s_tmb2_freq[hifreq][(data >> 2) & 3]; + m_tmb2->adjust(attotime::from_hz(tmb2freq), 0, attotime::from_hz(tmb2freq)); + break; + } + + case 0x11: // Timebase Clear + LOGMASKED(LOG_TIMERS, "io_w: Timebase Clear = %04x\n", data); + break; + + case 0x12: // Timer A Data + LOGMASKED(LOG_TIMERS, "io_w: Timer A Data = %04x\n", data); + m_io_regs[offset] = data; + m_timer_a_preload = data; + break; + + case 0x13: // Timer A Control + { + static const char* const s_source_a[8] = { "0", "0", "32768Hz", "8192Hz", "4096Hz", "1", "0", "ExtClk1" }; + static const char* const s_source_b[8] = { "2048Hz", "1024Hz", "256Hz", "TMB1", "4Hz", "2Hz", "1", "ExtClk2" }; + LOGMASKED(LOG_TIMERS, "io_w: Timer A Control = %04x (Source A:%s, Source B:%s)\n", data, + s_source_a[data & 7], s_source_b[(data >> 3) & 7]); + m_io_regs[offset] = data; + int timer_a_rate = 0; + switch (data & 7) + { + case 0: + case 1: + case 5: + case 6: + case 7: + m_timer_src_ab->adjust(attotime::never); + break; + case 2: + m_timer_src_ab->adjust(attotime::from_hz(32768), 0, attotime::from_hz(32768)); + timer_a_rate = 32768; + break; + case 3: + m_timer_src_ab->adjust(attotime::from_hz(8192), 0, attotime::from_hz(8192)); + timer_a_rate = 8192; + break; + case 4: + m_timer_src_ab->adjust(attotime::from_hz(4096), 0, attotime::from_hz(4096)); + timer_a_rate = 4096; + break; + } + switch ((data >> 3) & 7) + { + case 0: + m_timer_b_tick_rate = timer_a_rate / 2048; + break; + case 1: + m_timer_b_tick_rate = timer_a_rate / 1024; + break; + case 2: + m_timer_b_tick_rate = timer_a_rate / 256; + break; + case 3: + m_timer_b_tick_rate = 0; + break; + case 4: + m_timer_b_tick_rate = timer_a_rate / 4; + break; + case 5: + m_timer_b_tick_rate = timer_a_rate / 2; + break; + case 6: + m_timer_b_tick_rate = 1; + break; + case 7: + m_timer_b_tick_rate = 0; + break; + } + break; + } + + case 0x15: // Timer A IRQ Clear + { + LOGMASKED(LOG_TIMERS, "io_w: Timer A IRQ Clear\n"); + const uint16_t old = IO_IRQ_STATUS; + IO_IRQ_STATUS &= ~0x0800; + const uint16_t changed = (old & IO_IRQ_ENABLE) ^ (IO_IRQ_STATUS & IO_IRQ_ENABLE); + if (changed) + check_irqs(0x0800); + break; + } + + case 0x16: // Timer B Data + LOGMASKED(LOG_TIMERS, "io_w: Timer B Data = %04x\n", data); + m_io_regs[offset] = data; + m_timer_b_preload = data; + break; + + case 0x17: // Timer B Control + { + static const char* const s_source_c[8] = { "0", "0", "32768Hz", "8192Hz", "4096Hz", "1", "0", "ExtClk1" }; + LOGMASKED(LOG_TIMERS, "io_w: Timer B Control = %04x (Source C:%s)\n", data, s_source_c[data & 7]); + m_io_regs[offset] = data; + if (m_io_regs[0x18] == 1) + { + update_timer_b_rate(); + } + break; + } + + case 0x18: // Timer B Enable + { + LOGMASKED(LOG_TIMERS, "io_w: Timer B Enable = %04x\n", data); + m_io_regs[offset] = data & 1; + if (data & 1) + { + update_timer_b_rate(); + } + else + { + m_timer_src_c->adjust(attotime::never); + } + break; + } + + case 0x19: // Timer B IRQ Clear + { + LOGMASKED(LOG_TIMERS, "io_w: Timer B IRQ Clear\n"); + const uint16_t old = IO_IRQ_STATUS; + IO_IRQ_STATUS &= ~0x0400; + const uint16_t changed = (old & IO_IRQ_ENABLE) ^ (IO_IRQ_STATUS & IO_IRQ_ENABLE); + if (changed) + check_irqs(0x0400); + break; + } + + case 0x20: // System Control + { + static const char* const s_sysclk[4] = { "13.5MHz", "27MHz", "27MHz NoICE", "54MHz" }; + static const char* const s_lvd_voltage[4] = { "2.7V", "2.9V", "3.1V", "3.3V" }; + static const char* const s_weak_strong[2] = { "Weak", "Strong" }; + LOGMASKED(LOG_IO_WRITES, "io_w: System Control = %04x (Watchdog:%d, Sleep:%d, SysClk:%s, SysClkInv:%d, LVROutEn:%d, LVREn:%d\n" + , data, BIT(data, 15), BIT(data, 14), s_sysclk[(data >> 12) & 3], BIT(data, 11), BIT(data, 9), BIT(data, 8)); + LOGMASKED(LOG_IO_WRITES, " LVDEn:%d, LVDVoltSel:%s, 32kHzDisable:%d, StrWkMode:%s, VDACDisable:%d, ADACDisable:%d, ADACOutDisable:%d)\n" + , BIT(data, 7), s_lvd_voltage[(data >> 5) & 3], BIT(data, 4), s_weak_strong[BIT(data, 3)], BIT(data, 2), BIT(data, 1), BIT(data, 0)); + m_io_regs[offset] = data; + break; + } + + case 0x21: // IRQ Enable + { + LOGMASKED(LOG_IRQS, "io_w: IRQ Enable = %04x\n", data); + const uint16_t old = IO_IRQ_ENABLE; + m_io_regs[offset] = data; + const uint16_t changed = (old & IO_IRQ_ENABLE) ^ (IO_IRQ_STATUS & IO_IRQ_ENABLE); + if (changed) + check_irqs(changed); + break; + } + + case 0x22: // IRQ Acknowledge + { + LOGMASKED(LOG_IRQS, "io_w: IRQ Acknowledge = %04x\n", data); + const uint16_t old = IO_IRQ_STATUS; + IO_IRQ_STATUS &= ~data; + const uint16_t changed = (old & IO_IRQ_ENABLE) ^ (IO_IRQ_STATUS & IO_IRQ_ENABLE); + if (m_uart_rx_irq || m_uart_tx_irq) + { + LOGMASKED(LOG_IRQS | LOG_UART, "Re-setting UART IRQ due to still-unacknowledged Rx or Tx.\n"); + IO_IRQ_STATUS |= 0x0100; + } + if (changed) + check_irqs(changed); + break; + } + + case 0x23: // External Memory Control + { + static const char* const s_bus_arb[8] = + { + "Forbidden", "Forbidden", "Forbidden", "Forbidden", "Forbidden", "1:SPU/2:PPU/3:CPU", "Forbidden", "1:PPU/2:SPU/3:CPU" + }; + static const char* const s_addr_decode[4] = + { + "ROMCSB: 4000-3fffff, CSB1: ---, CSB2: ---, CSB3: ---", + "ROMCSB: 4000-1fffff, CSB1: 200000-3fffff, CSB2: ---, CSB3: ---", + "ROMCSB: 4000-0fffff, CSB1: 100000-1fffff, CSB2: 200000-2fffff, CSB3: 300000-3fffff", + "ROMCSB: 4000-0fffff, CSB1: 100000-1fffff, CSB2: 200000-2fffff, CSB3: 300000-3fffff" + }; + static const char* const s_ram_decode[16] = + { + "None", "None", "None", "None", "None", "None", "None", "None", + "4KW, 3ff000-3fffff\n", + "8KW, 3fe000-3fffff\n", + "16KW, 3fc000-3fffff\n", + "32KW, 3f8000-3fffff\n", + "64KW, 3f0000-3fffff\n", + "128KW, 3e0000-3fffff\n", + "256KW, 3c0000-3fffff\n", + "512KW, 380000-3fffff\n" + }; + LOGMASKED(LOG_EXT_MEM, "io_w: Ext. Memory Control (not yet implemented) = %04x:\n", data); + LOGMASKED(LOG_EXT_MEM, " WaitStates:%d, BusArbPrio:%s\n", (data >> 1) & 3, s_bus_arb[(data >> 3) & 7]); + LOGMASKED(LOG_EXT_MEM, " ROMAddrDecode:%s\n", s_addr_decode[(data >> 6) & 3]); + LOGMASKED(LOG_EXT_MEM, " RAMAddrDecode:%s\n", s_ram_decode[(data >> 8) & 15]); + m_chip_sel((data >> 6) & 3); + m_io_regs[offset] = data; + break; + } + + case 0x24: // Watchdog + LOGMASKED(LOG_WATCHDOG, "io_w: Watchdog Pet = %04x\n", data); + break; + + case 0x25: // ADC Control + { + LOGMASKED(LOG_IO_WRITES, "%s: io_w: ADC Control = %04x\n", machine().describe_context(), data); + m_io_regs[offset] = data & ~0x1000; + if (BIT(data, 0)) + { + m_io_regs[0x27] = 0x8000 | (m_adc_in[BIT(data, 5)]() & 0x7fff); + m_io_regs[0x25] |= 0x2000; + } + if (BIT(data, 12) && !BIT(m_io_regs[offset], 1)) + { + const uint16_t old = IO_IRQ_STATUS; + IO_IRQ_STATUS |= 0x2000; + const uint16_t changed = (old & IO_IRQ_ENABLE) ^ (IO_IRQ_STATUS & IO_IRQ_ENABLE); + if (changed) + { + check_irqs(changed); + } + } + break; + } + + case 0x28: // Sleep Mode + LOGMASKED(LOG_IO_WRITES, "io_w: Sleep Mode (%s enter value) = %04x\n", data == 0xaa55 ? "valid" : "invalid", data); + m_io_regs[offset] = data; + break; + + case 0x29: // Wakeup Source + { + m_io_regs[offset] = data; + static const char* const s_sources[8] = + { + "TMB1", "TMB2", "2Hz", "4Hz", "1024Hz", "2048Hz", "4096Hz", "Key" + }; + + LOGMASKED(LOG_IO_WRITES, "io_w: Wakeup Source = %04x:\n", data); + bool comma = false; + char buf[1024]; + int char_idx = 0; + for (int i = 7; i >= 0; i--) + { + if (BIT(data, i)) + { + char_idx += sprintf(&buf[char_idx], "%s%s", comma ? ", " : "", s_sources[i]); + comma = true; + } + } + buf[char_idx] = 0; + LOGMASKED(LOG_IO_WRITES, " %s\n", buf); + break; + } + + case 0x2c: // PRNG 0 seed + LOGMASKED(LOG_IO_WRITES, "io_w: PRNG 0 seed = %04x\n", data & 0x7fff); + m_io_regs[offset] = data & 0x7fff; + break; + + case 0x2d: // PRNG 1 seed + LOGMASKED(LOG_IO_WRITES, "io_w: PRNG 1 seed = %04x\n", data & 0x7fff); + m_io_regs[offset] = data & 0x7fff; + break; + + case 0x2e: // FIQ Source Select + { + static const char* const s_fiq_select[8] = + { + "PPU", "SPU Channel", "Timer A", "Timer B", "UART/SPI", "External", "Reserved", "None" + }; + LOGMASKED(LOG_FIQ, "io_w: FIQ Source Select (not yet implemented) = %04x, %s\n", data, s_fiq_select[data & 7]); + m_io_regs[offset] = data; + break; + } + + case 0x2f: // Data Segment + m_cpu->set_ds(data & 0x3f); + LOGMASKED(LOG_SEGMENT, "io_w: Data Segment = %04x\n", data); + break; + + default: + LOGMASKED(LOG_UNKNOWN_IO, "io_w: Unknown register %04x = %04x\n", 0x3d00 + offset, data); + m_io_regs[offset] = data; + break; + } +} + + + + +WRITE16_MEMBER(spg2xx_io_device::io_extended_w) +{ + // this set of registers might only be on the 24x not the 11x + + offset += 0x30; + + switch (offset) + { + + case 0x30: // UART Control + { + static const char* const s_9th_bit[4] = { "0", "1", "Odd", "Even" }; + LOGMASKED(LOG_UART, "%s: io_w: UART Control = %04x (TxEn:%d, RxEn:%d, Bits:%d, MultiProc:%d, 9thBit:%s, TxIntEn:%d, RxIntEn:%d\n", + machine().describe_context(), data, BIT(data, 7), BIT(data, 6), BIT(data, 5) ? 9 : 8, BIT(data, 4), s_9th_bit[(data >> 2) & 3], + BIT(data, 1), BIT(data, 0)); + const uint16_t changed = m_io_regs[offset] ^ data; + m_io_regs[offset] = data; + if (!BIT(data, 6)) + { + m_uart_rx_available = false; + m_io_regs[0x36] = 0; + } + if (BIT(changed, 7)) + { + if (BIT(data, 7)) + { + m_io_regs[0x31] |= 0x0002; + } + else + { + m_io_regs[0x31] &= ~0x0042; + m_uart_tx_timer->adjust(attotime::never); + } + } + break; + } + + case 0x31: // UART Status + LOGMASKED(LOG_UART, "%s: io_w: UART Status = %04x\n", machine().describe_context(), data); + if (BIT(data, 0)) + { + m_io_regs[0x31] &= ~1; + m_uart_rx_irq = false; + } + if (BIT(data, 1)) + { + m_io_regs[0x31] &= ~2; + m_uart_tx_irq = false; + } + if (!m_uart_rx_irq && !m_uart_tx_irq) + { + const uint16_t old = IO_IRQ_STATUS; + IO_IRQ_STATUS &= ~0x0100; + const uint16_t changed = (old & IO_IRQ_ENABLE) ^ (IO_IRQ_STATUS & IO_IRQ_ENABLE); + if (changed) + check_irqs(0x0100); + } + break; + + case 0x33: // UART Baud Rate (low byte) + case 0x34: // UART Baud Rate (high byte) + { + m_io_regs[offset] = data; + const uint32_t divisor = 16 * (0x10000 - ((m_io_regs[0x34] << 8) | m_io_regs[0x33])); + LOGMASKED(LOG_UART, "%s: io_w: UART Baud Rate (%s byte): Baud rate = %d\n", offset == 0x33 ? "low" : "high", machine().describe_context(), 27000000 / divisor); + m_uart_baud_rate = 27000000 / divisor; + break; + } + + case 0x35: // UART TX Data + LOGMASKED(LOG_UART, "%s: io_w: UART Tx Data = %02x\n", machine().describe_context(), data & 0x00ff); + m_io_regs[offset] = data; + if (BIT(m_io_regs[0x30], 7)) + { + LOGMASKED(LOG_UART, "io_w: UART Tx: Clearing ready bit, setting busy bit, setting up timer\n"); + m_uart_tx_timer->adjust(attotime::from_ticks(BIT(m_io_regs[0x30], 5) ? 11 : 10, m_uart_baud_rate)); + m_io_regs[0x31] &= ~0x0002; + m_io_regs[0x31] |= 0x0040; + } + break; + + case 0x36: // UART RX Data + LOGMASKED(LOG_UART, "%s: io_w: UART Rx Data (read-only) = %04x\n", machine().describe_context(), data); + break; + + case 0x37: // UART Rx FIFO Control + LOGMASKED(LOG_UART, "%s: io_w: UART Rx FIFO Control = %04x (Reset:%d, Overrun:%d, Underrun:%d, Count:%d, Threshold:%d)\n", + machine().describe_context(), data, BIT(data, 15), BIT(data, 14), BIT(data, 13), (data >> 4) & 7, data & 7); + if (data & 0x8000) + { + m_uart_rx_available = false; + m_io_regs[0x36] = 0; + } + m_io_regs[offset] &= ~data & 0x6000; + m_io_regs[offset] &= ~0x0007; + m_io_regs[offset] |= data & 0x0007; + break; + + case 0x50: // SIO Setup + { + static const char* const s_addr_mode[4] = { "16-bit", "None", "8-bit", "24-bit" }; + static const char* const s_baud_rate[4] = { "/16", "/4", "/8", "/32" }; + LOGMASKED(LOG_SIO, "io_w: SIO Setup (not implemented) = %04x (DS301Ready:%d, Start:%d, Auto:%d, IRQEn:%d, Width:%d, Related:%d\n", data + , BIT(data, 11), BIT(data, 10), BIT(data, 9), BIT(data, 8), BIT(data, 7) ? 16 : 8, BIT(data, 6)); + LOGMASKED(LOG_SIO, " (Mode:%s, RWProtocol:%d, Rate:sysclk%s, AddrMode:%s)\n" + , BIT(data, 5), BIT(data, 4), s_baud_rate[(data >> 2) & 3], s_addr_mode[data & 3]); + break; + } + + case 0x52: // SIO Start Address (low) + LOGMASKED(LOG_SIO, "io_w: SIO Stat Address (low) (not implemented) = %04x\n", data); + break; + + case 0x53: // SIO Start Address (hi) + LOGMASKED(LOG_SIO, "io_w: SIO Stat Address (hi) (not implemented) = %04x\n", data); + break; + + case 0x54: // SIO Data + LOGMASKED(LOG_SIO, "io_w: SIO Data (not implemented) = %04x\n", data); + break; + + case 0x55: // SIO Automatic Transmit Count + LOGMASKED(LOG_SIO, "io_w: SIO Auto Transmit Count (not implemented) = %04x\n", data); + break; + + case 0x58: // I2C Command + LOGMASKED(LOG_I2C, "io_w: I2C Command = %04x\n", data); + m_io_regs[offset] = data; + do_i2c(); + break; + + case 0x59: // I2C Status / Acknowledge + LOGMASKED(LOG_I2C, "io_w: I2C Acknowledge = %04x\n", data); + m_io_regs[offset] &= ~data; + break; + + case 0x5a: // I2C Access Mode + LOGMASKED(LOG_I2C, "io_w: I2C Access Mode = %04x\n", data); + m_io_regs[offset] = data; + break; + + case 0x5b: // I2C Device Address + LOGMASKED(LOG_I2C, "io_w: I2C Device Address = %04x\n", data); + m_io_regs[offset] = data; + break; + + case 0x5c: // I2C Sub-Address + LOGMASKED(LOG_I2C, "io_w: I2C Sub-Address = %04x\n", data); + m_io_regs[offset] = data; + break; + + case 0x5d: // I2C Data Out + LOGMASKED(LOG_I2C, "io_w: I2C Data Out = %04x\n", data); + m_io_regs[offset] = data; + break; + + case 0x5e: // I2C Data In + LOGMASKED(LOG_I2C, "io_w: I2C Data In = %04x\n", data); + m_io_regs[offset] = data; + break; + + case 0x5f: // I2C Controller Mode + LOGMASKED(LOG_I2C, "io_w: I2C Controller Mode = %04x\n", data); + m_io_regs[offset] = data; + break; + + default: + LOGMASKED(LOG_UNKNOWN_IO, "io_w: Unknown register %04x = %04x\n", 0x3d00 + offset, data); + m_io_regs[offset] = data; + break; + } +} + +void spg2xx_io_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch (id) + { + case TIMER_TMB1: + { + LOGMASKED(LOG_TIMERS, "TMB1 elapsed, setting IRQ Status bit 0 (old:%04x, new:%04x, enable:%04x)\n", IO_IRQ_STATUS, IO_IRQ_STATUS | 1, IO_IRQ_ENABLE); + const uint16_t old = IO_IRQ_STATUS; + IO_IRQ_STATUS |= 1; + const uint16_t changed = (old & IO_IRQ_ENABLE) ^ (IO_IRQ_STATUS & IO_IRQ_ENABLE); + if (changed) + check_irqs(0x0001); + break; + } + + case TIMER_TMB2: + { + LOGMASKED(LOG_TIMERS, "TMB2 elapsed, setting IRQ Status bit 1 (old:%04x, new:%04x, enable:%04x)\n", IO_IRQ_STATUS, IO_IRQ_STATUS | 2, IO_IRQ_ENABLE); + const uint16_t old = IO_IRQ_STATUS; + IO_IRQ_STATUS |= 2; + const uint16_t changed = (old & IO_IRQ_ENABLE) ^ (IO_IRQ_STATUS & IO_IRQ_ENABLE); + if (changed) + check_irqs(0x0002); + break; + } + + case TIMER_UART_TX: + uart_transmit_tick(); + break; + + case TIMER_UART_RX: + uart_receive_tick(); + break; + + case TIMER_4KHZ: + system_timer_tick(); + break; + + case TIMER_SRC_AB: + update_timer_ab_src(); + break; + + case TIMER_SRC_C: + update_timer_c_src(); + break; + } +} + +void spg2xx_io_device::system_timer_tick() +{ + const uint16_t old = IO_IRQ_STATUS; + uint16_t check_mask = 0x0040; + IO_IRQ_STATUS |= 0x0040; + + m_2khz_divider++; + if (m_2khz_divider == 2) + { + m_2khz_divider = 0; + IO_IRQ_STATUS |= 0x0020; + check_mask |= 0x0020; + + m_1khz_divider++; + if (m_1khz_divider == 2) + { + m_1khz_divider = 0; + IO_IRQ_STATUS |= 0x0010; + check_mask |= 0x0010; + + m_4hz_divider++; + if (m_4hz_divider == 256) + { + m_4hz_divider = 0; + IO_IRQ_STATUS |= 0x0008; + check_mask |= 0x0008; + } + } + } + + const uint16_t changed = (old & IO_IRQ_ENABLE) ^ (IO_IRQ_STATUS & IO_IRQ_ENABLE); + if (changed) + check_irqs(check_mask); +} + +void spg2xx_io_device::uart_transmit_tick() +{ + LOGMASKED(LOG_UART, "uart_transmit_tick: Transmitting %02x, setting TxReady, clearing TxBusy\n", (uint8_t)m_io_regs[0x35]); + m_uart_tx((uint8_t)m_io_regs[0x35]); + m_io_regs[0x31] |= 0x0002; + m_io_regs[0x31] &= ~0x0040; + if (BIT(m_io_regs[0x30], 1)) + { + const uint16_t old = IO_IRQ_STATUS; + IO_IRQ_STATUS |= 0x0100; + m_uart_tx_irq = true; + LOGMASKED(LOG_UART, "uart_transmit_tick: Setting UART IRQ bit\n"); + if (IO_IRQ_STATUS != old) + { + LOGMASKED(LOG_UART, "uart_transmit_tick: Bit newly set, checking IRQs\n"); + check_irqs(0x0100); + } + } +} + +void spg2xx_io_device::uart_receive_tick() +{ + LOGMASKED(LOG_UART, "uart_receive_tick: Setting RBF and RxRDY\n"); + m_io_regs[0x31] |= 0x81; + m_uart_rx_available = true; + if (BIT(m_io_regs[0x30], 0)) + { + LOGMASKED(LOG_UART, "uart_receive_tick: RxIntEn is set, setting rx_irq to true and setting UART IRQ\n"); + m_uart_rx_irq = true; + IO_IRQ_STATUS |= 0x0100; + check_irqs(0x0100); + } +} + +void spg2xx_io_device::extint_w(int channel, bool state) +{ + LOGMASKED(LOG_EXTINT, "Setting extint channel %d to %s\n", channel, state ? "true" : "false"); + bool old = m_extint[channel]; + m_extint[channel] = state; + if (old != state) + { + check_extint_irq(channel); + } +} + +void spg2xx_io_device::check_extint_irq(int channel) +{ + LOGMASKED(LOG_EXTINT, "%sing extint %d interrupt\n", m_extint[channel] ? "rais" : "lower", channel + 1); + const uint16_t mask = (channel == 0) ? 0x0200 : 0x1000; + const uint16_t old_irq = IO_IRQ_STATUS; + if (m_extint[channel]) + IO_IRQ_STATUS |= mask; + else + IO_IRQ_STATUS &= ~mask; + + if (old_irq != IO_IRQ_STATUS) + { + LOGMASKED(LOG_EXTINT, "extint IRQ changed, so checking interrupts\n"); + check_irqs(mask); + } +} + +void spg2xx_io_device::check_irqs(const uint16_t changed) +{ + if (changed & 0x0c00) // Timer A, Timer B IRQ + { + LOGMASKED(LOG_TIMERS, "%ssserting IRQ2 (%04x, %04x)\n", (IO_IRQ_ENABLE & IO_IRQ_STATUS & 0x0c00) ? "A" : "Dea", (IO_IRQ_ENABLE & IO_IRQ_STATUS & 0x0c00), changed); + m_timer_irq_cb((IO_IRQ_ENABLE & IO_IRQ_STATUS & 0x0c00) ? ASSERT_LINE : CLEAR_LINE); + } + + if (changed & 0x2100) // UART, ADC IRQ + { + LOGMASKED(LOG_UART, "%ssserting IRQ3 (%04x, %04x)\n", (IO_IRQ_ENABLE & IO_IRQ_STATUS & 0x2100) ? "A" : "Dea", (IO_IRQ_ENABLE & IO_IRQ_STATUS & 0x2100), changed); + m_uart_adc_irq_cb((IO_IRQ_ENABLE & IO_IRQ_STATUS & 0x2100) ? ASSERT_LINE : CLEAR_LINE); + } + + if (changed & 0x1200) // External IRQ + { + LOGMASKED(LOG_UART, "%ssserting IRQ5 (%04x, %04x)\n", (IO_IRQ_ENABLE & IO_IRQ_STATUS & 0x1200) ? "A" : "Dea", (IO_IRQ_ENABLE & IO_IRQ_STATUS & 0x1200), changed); + m_external_irq_cb((IO_IRQ_ENABLE & IO_IRQ_STATUS & 0x1200) ? ASSERT_LINE : CLEAR_LINE); + } + + if (changed & 0x0070) // 1024Hz, 2048Hz, 4096Hz IRQ + { + LOGMASKED(LOG_TIMERS, "%ssserting IRQ6 (%04x, %04x)\n", (IO_IRQ_ENABLE & IO_IRQ_STATUS & 0x0070) ? "A" : "Dea", (IO_IRQ_ENABLE & IO_IRQ_STATUS & 0x0070), changed); //m_cpu->set_state_unsynced(UNSP_IRQ6_LINE, (IO_IRQ_ENABLE & IO_IRQ_STATUS & 0x0070) ? ASSERT_LINE : CLEAR_LINE); + m_ffreq_tmr1_irq_cb((IO_IRQ_ENABLE & IO_IRQ_STATUS & 0x0070) ? ASSERT_LINE : CLEAR_LINE); + } + + if (changed & 0x008b) // TMB1, TMB2, 4Hz, key change IRQ + { + LOGMASKED(LOG_IRQS, "%ssserting IRQ7 (%04x, %04x)\n", (IO_IRQ_ENABLE & IO_IRQ_STATUS & 0x008b) ? "A" : "Dea", (IO_IRQ_ENABLE & IO_IRQ_STATUS & 0x008b), changed); + m_ffreq_tmr2_irq_cb((IO_IRQ_ENABLE & IO_IRQ_STATUS & 0x008b) ? ASSERT_LINE : CLEAR_LINE); + } +} + +uint16_t spg2xx_io_device::do_special_gpio(uint32_t index, uint16_t mask) +{ + uint16_t data = 0; + switch (index) + { + case 0: // Port A + if (mask & 0xe000) + { + const uint8_t csel = m_cpu->get_csb() & 0x0e; + data = (csel << 12) & mask; + } + break; + case 1: // Port B + // To do + break; + case 2: // Port C + // To do + break; + default: + // Can't happen + break; + } + return data; +} + +void spg2xx_io_device::do_gpio(uint32_t offset, bool write) +{ + uint32_t index = (offset - 1) / 5; + uint16_t buffer = m_io_regs[5 * index + 2]; + uint16_t dir = m_io_regs[5 * index + 3]; + uint16_t attr = m_io_regs[5 * index + 4]; + uint16_t special = m_io_regs[5 * index + 5]; + + uint16_t push = dir; + uint16_t pull = ~dir; + uint16_t what = (buffer & (push | pull)); + what ^= (dir & ~attr); + what &= ~special; + + switch (index) + { + case 0: + if (write) + m_porta_out(0, what, push &~ special); + what = (what & ~pull); + if (!write) + what |= m_porta_in(0, pull &~ special) & pull; + break; + case 1: + if (write) + m_portb_out(0, what, push &~ special); + what = (what & ~pull); + if (!write) + what |= m_portb_in(0, pull &~ special) & pull; + break; + case 2: + if (write) + m_portc_out(0, what, push &~ special); + what = (what & ~pull); + if (!write) + what |= m_portc_in(0, pull &~ special) & pull; + break; + } + + what |= do_special_gpio(index, special); + m_io_regs[5 * index + 1] = what; +} + +void spg2xx_io_device::do_i2c() +{ + const uint16_t addr = ((m_io_regs[0x5b] & 0x06) << 7) | (uint8_t)m_io_regs[0x5c]; + + if (m_io_regs[0x58] & 0x40) // Serial EEPROM read + m_io_regs[0x5e] = m_eeprom_r(addr); + else + m_eeprom_w(addr, m_io_regs[0x5d]); + + m_io_regs[0x59] |= 1; +} diff --git a/src/devices/machine/spg2xx_io.h b/src/devices/machine/spg2xx_io.h new file mode 100644 index 00000000000..d829915cbec --- /dev/null +++ b/src/devices/machine/spg2xx_io.h @@ -0,0 +1,183 @@ +// license:BSD-3-Clause +// copyright-holders:Ryan Holtz + +#ifndef MAME_MACHINE_SPG2XX_IO_H +#define MAME_MACHINE_SPG2XX_IO_H + +#pragma once + +#include "cpu/unsp/unsp.h" +#include "screen.h" + +class spg2xx_io_device : public device_t +{ +public: + spg2xx_io_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock); + + auto porta_out() { return m_porta_out.bind(); } + auto portb_out() { return m_portb_out.bind(); } + auto portc_out() { return m_portc_out.bind(); } + auto porta_in() { return m_porta_in.bind(); } + auto portb_in() { return m_portb_in.bind(); } + auto portc_in() { return m_portc_in.bind(); } + + template <size_t Line> auto adc_in() { return m_adc_in[Line].bind(); } + + auto eeprom_w() { return m_eeprom_w.bind(); } + auto eeprom_r() { return m_eeprom_r.bind(); } + + auto uart_tx() { return m_uart_tx.bind(); } + + auto chip_select() { return m_chip_sel.bind(); } + + void uart_rx(uint8_t data); + + void extint_w(int channel, bool state); + + DECLARE_READ16_MEMBER(io_r); + DECLARE_WRITE16_MEMBER(io_w); + + virtual DECLARE_READ16_MEMBER(io_extended_r); + virtual DECLARE_WRITE16_MEMBER(io_extended_w); + + + auto pal_read_callback() { return m_pal_read_cb.bind(); }; + + auto write_timer_irq_callback() { return m_timer_irq_cb.bind(); }; + auto write_uart_adc_irq_callback() { return m_uart_adc_irq_cb.bind(); }; + auto write_external_irq_callback() { return m_external_irq_cb.bind(); }; + auto write_ffrq_tmr1_irq_callback() { return m_ffreq_tmr1_irq_cb.bind(); }; + auto write_ffrq_tmr2_irq_callback() { return m_ffreq_tmr2_irq_cb.bind(); }; + +protected: + spg2xx_io_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, const uint32_t sprite_limit) + : spg2xx_io_device(mconfig, type, tag, owner, clock) + { + } + + void check_extint_irq(int channel); + void check_irqs(const uint16_t changed); + + static const device_timer_id TIMER_TMB1 = 0; + static const device_timer_id TIMER_TMB2 = 1; + + static const device_timer_id TIMER_UART_TX = 4; + static const device_timer_id TIMER_UART_RX = 5; + static const device_timer_id TIMER_4KHZ = 6; + static const device_timer_id TIMER_SRC_AB = 7; + static const device_timer_id TIMER_SRC_C = 8; + + virtual void device_start() override; + virtual void device_reset() override; + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override; + + void update_porta_special_modes(); + void update_portb_special_modes(); + void do_gpio(uint32_t offset, bool write); + uint16_t do_special_gpio(uint32_t index, uint16_t mask); + + void update_timer_b_rate(); + void update_timer_ab_src(); + void update_timer_c_src(); + void increment_timer_a(); + + void uart_transmit_tick(); + void uart_receive_tick(); + + void system_timer_tick(); + + void do_i2c(); + + uint16_t m_io_regs[0x100]; + + uint8_t m_uart_rx_fifo[8]; + uint8_t m_uart_rx_fifo_start; + uint8_t m_uart_rx_fifo_end; + uint8_t m_uart_rx_fifo_count; + bool m_uart_rx_available; + bool m_uart_rx_irq; + bool m_uart_tx_irq; + + bool m_extint[2]; + + devcb_write16 m_porta_out; + devcb_write16 m_portb_out; + devcb_write16 m_portc_out; + devcb_read16 m_porta_in; + devcb_read16 m_portb_in; + devcb_read16 m_portc_in; + + devcb_read16 m_adc_in[2]; + + devcb_write8 m_eeprom_w; + devcb_read8 m_eeprom_r; + + devcb_write8 m_uart_tx; + + devcb_write8 m_chip_sel; + + uint16_t m_timer_a_preload; + uint16_t m_timer_b_preload; + uint16_t m_timer_b_divisor; + uint16_t m_timer_b_tick_rate; + + emu_timer *m_tmb1; + emu_timer *m_tmb2; + emu_timer *m_timer_src_ab; + emu_timer *m_timer_src_c; + + emu_timer *m_4khz_timer; + uint32_t m_2khz_divider; + uint32_t m_1khz_divider; + uint32_t m_4hz_divider; + + uint32_t m_uart_baud_rate; + emu_timer *m_uart_tx_timer; + emu_timer *m_uart_rx_timer; + + required_device<unsp_device> m_cpu; + required_device<screen_device> m_screen; + + devcb_read16 m_pal_read_cb; + + devcb_write_line m_timer_irq_cb; + devcb_write_line m_uart_adc_irq_cb; + devcb_write_line m_external_irq_cb; + devcb_write_line m_ffreq_tmr1_irq_cb; + devcb_write_line m_ffreq_tmr2_irq_cb; +}; + +class spg24x_io_device : public spg2xx_io_device +{ +public: + template <typename T, typename U> + spg24x_io_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, T &&cpu_tag, U &&screen_tag) + : spg24x_io_device(mconfig, tag, owner, clock) + { + m_cpu.set_tag(std::forward<T>(cpu_tag)); + m_screen.set_tag(std::forward<U>(screen_tag)); + } + + spg24x_io_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); +}; + +class spg28x_io_device : public spg2xx_io_device +{ +public: + template <typename T, typename U> + spg28x_io_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, T &&cpu_tag, U &&screen_tag) + : spg28x_io_device(mconfig, tag, owner, clock) + { + m_cpu.set_tag(std::forward<T>(cpu_tag)); + m_screen.set_tag(std::forward<U>(screen_tag)); + } + + spg28x_io_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + virtual DECLARE_WRITE16_MEMBER(io_extended_w) override; +}; + +DECLARE_DEVICE_TYPE(SPG24X_IO, spg24x_io_device) +DECLARE_DEVICE_TYPE(SPG28X_IO, spg28x_io_device) + +#endif // MAME_MACHINE_SPG2XX_IO_H diff --git a/src/devices/machine/spg2xx_sysdma.cpp b/src/devices/machine/spg2xx_sysdma.cpp new file mode 100644 index 00000000000..fe0d61ea395 --- /dev/null +++ b/src/devices/machine/spg2xx_sysdma.cpp @@ -0,0 +1,117 @@ +// license:BSD-3-Clause +// copyright-holders:Ryan Holtz +/***************************************************************************** + + SunPlus SPG2xx-series SoC peripheral emulation (System DMA) + +**********************************************************************/ + +#include "emu.h" +#include "spg2xx_sysdma.h" + +DEFINE_DEVICE_TYPE(SPG2XX_SYSDMA, spg2xx_sysdma_device, "spg2xx_sysdma", "SPG240-series System-on-a-Chip System DMA") + +#define LOG_DMA (1U << 9) +#define LOG_ALL (LOG_DMA) + +#define VERBOSE (0) +#include "logmacro.h" + + + +spg2xx_sysdma_device::spg2xx_sysdma_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : device_t(mconfig, SPG2XX_SYSDMA, tag, owner, clock) + , m_cpu(*this, finder_base::DUMMY_TAG) +{ +} + +void spg2xx_sysdma_device::device_start() +{ + save_item(NAME(m_dma_regs)); +} + +void spg2xx_sysdma_device::device_reset() +{ + memset(m_dma_regs, 0, 0x4 * sizeof(uint16_t)); +} + +/************************* +* Machine Hardware * +*************************/ + +READ16_MEMBER(spg2xx_sysdma_device::dma_r) +{ + offset &= 0x3; + + uint16_t val = m_dma_regs[offset]; + switch (offset) + { + + case 0x000: // DMA Source (L) + LOGMASKED(LOG_DMA, "dma_r: DMA Source (lo) = %04x\n", val); + break; + + case 0x001: // DMA Source (H) + LOGMASKED(LOG_DMA, "dma_r: DMA Source (hi) = %04x\n", val); + break; + + case 0x002: // DMA Length + LOGMASKED(LOG_DMA, "dma_r: DMA Length = %04x\n", 0); + val = 0; + break; + + case 0x003: // DMA Destination + LOGMASKED(LOG_DMA, "dma_r: DMA Dest = %04x\n", val); + break; + } + + return val; +} + +WRITE16_MEMBER(spg2xx_sysdma_device::dma_w) +{ + offset &= 0x3; + + switch (offset) + { + case 0x000: // DMA Source (lo) + LOGMASKED(LOG_DMA, "dma_w: DMA Source (lo) = %04x\n", data); + m_dma_regs[offset] = data; + break; + + case 0x001: // DMA Source (hi) + LOGMASKED(LOG_DMA, "dma_w: DMA Source (hi) = %04x\n", data); + m_dma_regs[offset] = data; + break; + + case 0x002: // DMA Length + LOGMASKED(LOG_DMA, "dma_w: DMA Length = %04x\n", data); + if (!(data & 0xc000)) // jak_dora writes 0xffff here which ends up trashing registers etc. why? such writes can't be valid + do_cpu_dma(data); + break; + + case 0x003: // DMA Destination + LOGMASKED(LOG_DMA, "dma_w: DMA Dest = %04x\n", data); + m_dma_regs[offset] = data; + break; + } +} + +void spg2xx_sysdma_device::do_cpu_dma(uint32_t len) +{ + address_space &mem = m_cpu->space(AS_PROGRAM); + + uint32_t src = ((m_dma_regs[0x001] & 0x3f) << 16) | m_dma_regs[0x000]; + uint32_t dst = m_dma_regs[0x003] & 0x3fff; + + for (uint32_t j = 0; j < len; j++) + { + mem.write_word((dst + j) & 0x3fff, mem.read_word(src + j)); + } + + src += len; + m_dma_regs[0x000] = (uint16_t)src; + m_dma_regs[0x001] = (src >> 16) & 0x3f; + m_dma_regs[0x002] = 0; + m_dma_regs[0x003] = (dst + len) & 0x3fff; +} diff --git a/src/devices/machine/spg2xx_sysdma.h b/src/devices/machine/spg2xx_sysdma.h new file mode 100644 index 00000000000..bea7755bcd9 --- /dev/null +++ b/src/devices/machine/spg2xx_sysdma.h @@ -0,0 +1,46 @@ +// license:BSD-3-Clause +// copyright-holders:Ryan Holtz +/***************************************************************************** + + SunPlus SPG2xx-series SoC peripheral emulation (System DMA) + +**********************************************************************/ + +#ifndef MAME_MACHINE_SPG2XX_SYSDMA_H +#define MAME_MACHINE_SPG2XX_SYSDMA_H + +#pragma once + +#include "cpu/unsp/unsp.h" + +DECLARE_DEVICE_TYPE(SPG2XX_SYSDMA, spg2xx_sysdma_device) + + +class spg2xx_sysdma_device : public device_t +{ +public: + template <typename T> + spg2xx_sysdma_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, T &&cpu_tag) + : spg2xx_sysdma_device(mconfig, tag, owner, clock) + { + m_cpu.set_tag(std::forward<T>(cpu_tag)); + } + + spg2xx_sysdma_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + DECLARE_READ16_MEMBER(dma_r); + DECLARE_WRITE16_MEMBER(dma_w); + +protected: + virtual void device_start() override; + virtual void device_reset() override; + +private: + void do_cpu_dma(uint32_t len); + + uint16_t m_dma_regs[0x4]; + + required_device<unsp_device> m_cpu; +}; + + +#endif // MAME_MACHINE_SPG2XX_SYSDMA_H diff --git a/src/devices/machine/spg2xx_video.cpp b/src/devices/machine/spg2xx_video.cpp new file mode 100644 index 00000000000..daef752bc82 --- /dev/null +++ b/src/devices/machine/spg2xx_video.cpp @@ -0,0 +1,828 @@ +// license:BSD-3-Clause +// copyright-holders:Ryan Holtz +/***************************************************************************** + + SunPlus SPG2xx-series SoC peripheral emulation (Video) + +**********************************************************************/ + +#include "emu.h" +#include "spg2xx_video.h" + +DEFINE_DEVICE_TYPE(SPG24X_VIDEO, spg24x_video_device, "spg24x_video", "SPG240-series System-on-a-Chip (Video)") + +#define LOG_IRQS (1U << 4) +#define LOG_VLINES (1U << 5) +#define LOG_DMA (1U << 9) +#define LOG_PPU_READS (1U << 22) +#define LOG_PPU_WRITES (1U << 23) +#define LOG_UNKNOWN_PPU (1U << 24) +#define LOG_PPU (LOG_PPU_READS | LOG_PPU_WRITES | LOG_UNKNOWN_PPU) +#define LOG_ALL (LOG_IRQS | LOG_PPU | LOG_VLINES | LOG_DMA ) + +#define VERBOSE (0) +#include "logmacro.h" + +#define SPG_DEBUG_VIDEO (0) + +#define VIDEO_IRQ_ENABLE m_video_regs[0x62] +#define VIDEO_IRQ_STATUS m_video_regs[0x63] + +spg2xx_video_device::spg2xx_video_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) + : device_t(mconfig, type, tag, owner, clock) + , m_sprlimit_read_cb(*this) + , m_rowscrolloffset_read_cb(*this) + , m_cpu(*this, finder_base::DUMMY_TAG) + , m_screen(*this, finder_base::DUMMY_TAG) + , m_scrollram(*this, "scrollram") + , m_paletteram(*this, "paletteram") + , m_spriteram(*this, "spriteram") + , m_video_irq_cb(*this) +{ +} + +spg24x_video_device::spg24x_video_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : spg2xx_video_device(mconfig, SPG24X_VIDEO, tag, owner, clock) +{ +} + +void spg2xx_video_device::device_start() +{ + for (uint8_t i = 0; i < 32; i++) + { + m_rgb5_to_rgb8[i] = (i << 3) | (i >> 2); + } + for (uint16_t i = 0; i < 0x8000; i++) + { + m_rgb555_to_rgb888[i] = (m_rgb5_to_rgb8[(i >> 10) & 0x1f] << 16) | + (m_rgb5_to_rgb8[(i >> 5) & 0x1f] << 8) | + (m_rgb5_to_rgb8[(i >> 0) & 0x1f] << 0); + } + + m_screenpos_timer = timer_alloc(TIMER_SCREENPOS); + m_screenpos_timer->adjust(attotime::never); + + save_item(NAME(m_hide_page0)); + save_item(NAME(m_hide_page1)); + save_item(NAME(m_hide_sprites)); + save_item(NAME(m_debug_sprites)); + save_item(NAME(m_debug_blit)); + save_item(NAME(m_debug_palette)); + save_item(NAME(m_sprite_index_to_debug)); + + save_item(NAME(m_video_regs)); + + m_sprlimit_read_cb.resolve_safe(0); + m_rowscrolloffset_read_cb.resolve_safe(0); + + m_video_irq_cb.resolve(); + +} + +void spg2xx_video_device::device_reset() +{ + memset(m_video_regs, 0, 0x100 * sizeof(uint16_t)); + + m_video_regs[0x36] = 0xffff; + m_video_regs[0x37] = 0xffff; + m_video_regs[0x3c] = 0x0020; + m_video_regs[0x42] = 0x0001; + + m_hide_page0 = false; + m_hide_page1 = false; + m_hide_sprites = false; + m_debug_sprites = false; + m_debug_blit = false; + m_debug_palette = false; + m_sprite_index_to_debug = 0; +} + +/************************* +* Video Hardware * +*************************/ + +// Perform a lerp between a and b +inline uint8_t spg2xx_video_device::mix_channel(uint8_t bottom, uint8_t top) +{ + uint8_t alpha = (m_video_regs[0x2a] & 3) << 6; + return ((256 - alpha) * bottom + alpha * top) >> 8; +} + +template<spg2xx_video_device::blend_enable_t Blend, spg2xx_video_device::rowscroll_enable_t RowScroll, spg2xx_video_device::flipx_t FlipX> +void spg2xx_video_device::draw(const rectangle &cliprect, uint32_t line, uint32_t xoff, uint32_t yoff, uint32_t bitmap_addr, uint16_t tile, int32_t h, int32_t w, uint8_t bpp, uint32_t yflipmask, uint32_t palette_offset) +{ + address_space &space = m_cpu->space(AS_PROGRAM); + + uint32_t nc_bpp = ((bpp) + 1) << 1; + + if (SPG_DEBUG_VIDEO && m_debug_blit) + { + printf("s:%d line:%d xy:%08x,%08x bitmap_addr:%08x tile:%04x\n", cliprect.min_x, line, xoff, yoff, bitmap_addr, tile); + printf("hw:%d,%d yfm:%d nc_bppols:%d pobs:%02x ", w, h, yflipmask, nc_bpp, palette_offset); + } + palette_offset >>= nc_bpp; + palette_offset <<= nc_bpp; + if (SPG_DEBUG_VIDEO && m_debug_blit) + { + printf("poas:%02x\n", palette_offset); + } + + uint32_t bits_per_row = nc_bpp * w / 16; + uint32_t words_per_tile = bits_per_row * h; + uint32_t m = bitmap_addr + words_per_tile * tile + bits_per_row * (line ^ yflipmask); + uint32_t bits = 0; + uint32_t nbits = 0; + uint32_t y = line; + + int yy = (yoff + y) & 0x1ff; + if (yy >= 0x01c0) + yy -= 0x0200; + + if (yy > 240 || yy < 0) + return; + + if (SPG_DEBUG_VIDEO && m_debug_blit) + printf("%3d:\n", yy); + + int y_index = yy * 320; + + for (int32_t x = FlipX ? (w - 1) : 0; FlipX ? x >= 0 : x < w; FlipX ? x-- : x++) + { + int xx = xoff + x; + + bits <<= nc_bpp; + if (SPG_DEBUG_VIDEO && m_debug_blit) + printf(" %08x:%d ", bits, nbits); + if (nbits < nc_bpp) + { + uint16_t b = space.read_word(m++ & 0x3fffff); + b = (b << 8) | (b >> 8); + bits |= b << (nc_bpp - nbits); + nbits += 16; + if (SPG_DEBUG_VIDEO && m_debug_blit) + printf("(%04x:%08x:%d) ", b, bits, nbits); + } + nbits -= nc_bpp; + + uint32_t pal = palette_offset + (bits >> 16); + if (SPG_DEBUG_VIDEO && m_debug_blit) + printf("%02x:%02x:%04x ", bits >> 16, pal, bits & 0xffff); + bits &= 0xffff; + + if (RowScroll) + xx -= (int16_t)m_scrollram[(yy + m_rowscrolloffset_read_cb()) & 0x1ff]; + + xx &= 0x01ff; + if (xx >= 0x01c0) + xx -= 0x0200; + + if (xx >= 0 && xx < 320) + { + int pix_index = xx + y_index; + + uint16_t rgb = m_paletteram[pal]; + if (SPG_DEBUG_VIDEO && m_debug_blit) + printf("rgb:%04x ", rgb); + + if (!(rgb & 0x8000)) + { + if (Blend) + { + if (SPG_DEBUG_VIDEO && m_debug_blit) + printf("M\n"); + m_screenbuf[pix_index] = (mix_channel((uint8_t)(m_screenbuf[pix_index] >> 16), m_rgb5_to_rgb8[(rgb >> 10) & 0x1f]) << 16) | + (mix_channel((uint8_t)(m_screenbuf[pix_index] >> 8), m_rgb5_to_rgb8[(rgb >> 5) & 0x1f]) << 8) | + (mix_channel((uint8_t)(m_screenbuf[pix_index] >> 0), m_rgb5_to_rgb8[rgb & 0x1f])); + } + else + { + if (SPG_DEBUG_VIDEO && m_debug_blit) + printf("S\n"); + m_screenbuf[pix_index] = m_rgb555_to_rgb888[rgb]; + } + } + else if (SPG_DEBUG_VIDEO && m_debug_blit) + { + printf("X\n"); + } + } + } +} + +void spg2xx_video_device::draw_page(const rectangle &cliprect, uint32_t scanline, int priority, uint32_t bitmap_addr, uint16_t *regs) +{ + uint32_t xscroll = regs[0]; + uint32_t yscroll = regs[1]; + uint32_t attr = regs[2]; + uint32_t ctrl = regs[3]; + uint32_t tilemap = regs[4]; + uint32_t palette_map = regs[5]; + address_space &space = m_cpu->space(AS_PROGRAM); + + if (!(ctrl & PAGE_ENABLE_MASK)) + { + return; + } + + if (((attr & PAGE_PRIORITY_FLAG_MASK) >> PAGE_PRIORITY_FLAG_SHIFT) != priority) + { + return; + } + + uint32_t tile_h = 8 << ((attr & PAGE_TILE_HEIGHT_MASK) >> PAGE_TILE_HEIGHT_SHIFT); + uint32_t tile_w = 8 << ((attr & PAGE_TILE_WIDTH_MASK) >> PAGE_TILE_WIDTH_SHIFT); + + uint32_t tile_count_x = 512 / tile_w; + + uint32_t bitmap_y = (scanline + yscroll) & 0xff; + uint32_t y0 = bitmap_y / tile_h; + uint32_t tile_scanline = bitmap_y % tile_h; + uint32_t tile_address = tile_count_x * y0; + if (SPG_DEBUG_VIDEO && machine().input().code_pressed(KEYCODE_H)) + printf("s:%3d | baddr:%08x | yscr:%3d | bity:%3d | y0:%2d | ts:%2d\n", scanline, bitmap_addr, yscroll, bitmap_y, y0, tile_scanline); + + if (SPG_DEBUG_VIDEO && machine().input().code_pressed(KEYCODE_EQUALS)) + m_debug_blit = true; + for (uint32_t x0 = 0; x0 < tile_count_x; x0++, tile_address++) + { + uint32_t yy = ((tile_h * y0 - yscroll + 0x10) & 0xff) - 0x10; + uint32_t xx = (tile_w * x0 - xscroll) & 0x1ff; + uint16_t tile = (ctrl & PAGE_WALLPAPER_MASK) ? space.read_word(tilemap) : space.read_word(tilemap + tile_address); + uint16_t palette = 0; + + if (!tile) + continue; + + palette = (ctrl & PAGE_WALLPAPER_MASK) ? space.read_word(palette_map) : space.read_word(palette_map + tile_address / 2); + if (x0 & 1) + palette >>= 8; + + uint32_t tileattr = attr; + uint32_t tilectrl = ctrl; + if ((ctrl & 2) == 0) + { // -(1) bld(1) flip(2) pal(4) + tileattr &= ~0x000c; + tileattr |= (palette >> 2) & 0x000c; // flip + + tileattr &= ~0x0f00; + tileattr |= (palette << 8) & 0x0f00; // palette + + tilectrl &= ~0x0100; + tilectrl |= (palette << 2) & 0x0100; // blend + } + + const bool blend = (tileattr & 0x4000 || tilectrl & 0x0100); + const bool row_scroll = (tilectrl & 0x0010); + const bool flip_x = (tileattr & TILE_X_FLIP); + const uint32_t yflipmask = tileattr & TILE_Y_FLIP ? tile_h - 1 : 0; + const uint32_t palette_offset = (tileattr & 0x0f00) >> 4; + + const uint8_t bpp = tileattr & 0x0003; + + if (blend) + { + if (row_scroll) + { + if (flip_x) + draw<BlendOn, RowScrollOn, FlipXOn>(cliprect, tile_scanline, xx, yy, bitmap_addr, tile, tile_h, tile_w, bpp, yflipmask, palette_offset); + else + draw<BlendOn, RowScrollOn, FlipXOff>(cliprect, tile_scanline, xx, yy, bitmap_addr, tile, tile_h, tile_w, bpp, yflipmask, palette_offset); + } + else + { + if (flip_x) + draw<BlendOn, RowScrollOff, FlipXOn>(cliprect, tile_scanline, xx, yy, bitmap_addr, tile, tile_h, tile_w, bpp, yflipmask, palette_offset); + else + draw<BlendOn, RowScrollOff, FlipXOff>(cliprect, tile_scanline, xx, yy, bitmap_addr, tile, tile_h, tile_w, bpp, yflipmask, palette_offset); + } + } + else + { + if (row_scroll) + { + if (flip_x) + draw<BlendOff, RowScrollOn, FlipXOn>(cliprect, tile_scanline, xx, yy, bitmap_addr, tile, tile_h, tile_w, bpp, yflipmask, palette_offset); + else + draw<BlendOff, RowScrollOn, FlipXOff>(cliprect, tile_scanline, xx, yy, bitmap_addr, tile, tile_h, tile_w, bpp, yflipmask, palette_offset); + } + else + { + if (flip_x) + draw<BlendOff, RowScrollOff, FlipXOn>(cliprect, tile_scanline, xx, yy, bitmap_addr, tile, tile_h, tile_w, bpp, yflipmask, palette_offset); + else + draw<BlendOff, RowScrollOff, FlipXOff>(cliprect, tile_scanline, xx, yy, bitmap_addr, tile, tile_h, tile_w, bpp, yflipmask, palette_offset); + } + } + } + if (SPG_DEBUG_VIDEO && machine().input().code_pressed(KEYCODE_EQUALS)) + m_debug_blit = false; +} + +void spg2xx_video_device::draw_sprite(const rectangle &cliprect, uint32_t scanline, int priority, uint32_t base_addr) +{ + uint32_t bitmap_addr = 0x40 * m_video_regs[0x22]; + uint16_t tile = m_spriteram[base_addr + 0]; + int16_t x = m_spriteram[base_addr + 1]; + int16_t y = m_spriteram[base_addr + 2]; + uint16_t attr = m_spriteram[base_addr + 3]; + + if (!tile) + { + return; + } + + if (((attr & PAGE_PRIORITY_FLAG_MASK) >> PAGE_PRIORITY_FLAG_SHIFT) != priority) + { + return; + } + + const uint32_t h = 8 << ((attr & PAGE_TILE_HEIGHT_MASK) >> PAGE_TILE_HEIGHT_SHIFT); + const uint32_t w = 8 << ((attr & PAGE_TILE_WIDTH_MASK) >> PAGE_TILE_WIDTH_SHIFT); + + if (!(m_video_regs[0x42] & SPRITE_COORD_TL_MASK)) + { + x = (160 + x) - w / 2; + y = (120 - y) - (h / 2) + 8; + } + + x &= 0x01ff; + y &= 0x01ff; + + uint32_t tile_line = ((scanline - y) + 0x200) % h; + int16_t test_y = (y + tile_line) & 0x1ff; + if (test_y >= 0x01c0) + test_y -= 0x0200; + + if (test_y != scanline) + { + return; + } + + bool blend = (attr & 0x4000); + bool flip_x = (attr & TILE_X_FLIP); + const uint8_t bpp = attr & 0x0003; + const uint32_t yflipmask = attr & TILE_Y_FLIP ? h - 1 : 0; + const uint32_t palette_offset = (attr & 0x0f00) >> 4; + +#if SPG_DEBUG_VIDEO + if (m_debug_sprites && machine().input().code_pressed(KEYCODE_MINUS)) + m_debug_blit = true; + if (blend) + { + if (flip_x) + draw<BlendOn, RowScrollOff, FlipXOn>(cliprect, tile_line, x, y, bitmap_addr, tile, h, w, bpp, yflipmask, palette_offset); + else + draw<BlendOn, RowScrollOff, FlipXOff>(cliprect, tile_line, x, y, bitmap_addr, tile, h, w, bpp, yflipmask, palette_offset); + } + else + { + if (flip_x) + draw<BlendOff, RowScrollOff, FlipXOn>(cliprect, tile_line, x, y, bitmap_addr, tile, h, w, bpp, yflipmask, palette_offset); + else + draw<BlendOff, RowScrollOff, FlipXOff>(cliprect, tile_line, x, y, bitmap_addr, tile, h, w, bpp, yflipmask, palette_offset); + } + m_debug_blit = false; +#else + if (blend) + { + if (flip_x) + draw<BlendOn, RowScrollOff, FlipXOn>(cliprect, tile_line, x, y, bitmap_addr, tile, h, w, bpp, yflipmask, palette_offset); + else + draw<BlendOn, RowScrollOff, FlipXOff>(cliprect, tile_line, x, y, bitmap_addr, tile, h, w, bpp, yflipmask, palette_offset); + } + else + { + if (flip_x) + draw<BlendOff, RowScrollOff, FlipXOn>(cliprect, tile_line, x, y, bitmap_addr, tile, h, w, bpp, yflipmask, palette_offset); + else + draw<BlendOff, RowScrollOff, FlipXOff>(cliprect, tile_line, x, y, bitmap_addr, tile, h, w, bpp, yflipmask, palette_offset); + } +#endif +} + +void spg2xx_video_device::draw_sprites(const rectangle &cliprect, uint32_t scanline, int priority) +{ + if (!(m_video_regs[0x42] & SPRITE_ENABLE_MASK)) + { + return; + } + +#if SPG_DEBUG_VIDEO + if (!m_debug_sprites) + { +#endif + for (uint32_t n = 0; n < m_sprlimit_read_cb(); n++) + { + draw_sprite(cliprect, scanline, priority, 4 * n); + } +#if SPG_DEBUG_VIDEO + } + else + { + draw_sprite(cliprect, scanline, priority, 4 * m_sprite_index_to_debug); + } +#endif +} + +void spg2xx_video_device::apply_saturation(const rectangle &cliprect) +{ + static const float s_u8_to_float = 1.0f / 255.0f; + static const float s_gray_r = 0.299f; + static const float s_gray_g = 0.587f; + static const float s_gray_b = 0.114f; + const float sat_adjust = (0xff - (m_video_regs[0x3c] & 0x00ff)) / (float)(0xff - 0x20); + for (int y = cliprect.min_y; y <= cliprect.max_y; y++) + { + uint32_t *src = &m_screenbuf[cliprect.min_x + 320 * y]; + for (int x = cliprect.min_x; x <= cliprect.max_x; x++) + { + const uint32_t src_rgb = *src; + const float src_r = (uint8_t)(src_rgb >> 16) * s_u8_to_float; + const float src_g = (uint8_t)(src_rgb >> 8) * s_u8_to_float; + const float src_b = (uint8_t)(src_rgb >> 0) * s_u8_to_float; + const float luma = src_r * s_gray_r + src_g * s_gray_g + src_b * s_gray_b; + const float adjusted_r = luma + (src_r - luma) * sat_adjust; + const float adjusted_g = luma + (src_g - luma) * sat_adjust; + const float adjusted_b = luma + (src_b - luma) * sat_adjust; + const int integer_r = (int)floor(adjusted_r * 255.0f); + const int integer_g = (int)floor(adjusted_g * 255.0f); + const int integer_b = (int)floor(adjusted_b * 255.0f); + *src++ = (integer_r > 255 ? 0xff0000 : (integer_r < 0 ? 0 : ((uint8_t)integer_r << 16))) | + (integer_g > 255 ? 0x00ff00 : (integer_g < 0 ? 0 : ((uint8_t)integer_g << 8))) | + (integer_b > 255 ? 0x0000ff : (integer_b < 0 ? 0 : (uint8_t)integer_b)); + } + } +} + +void spg2xx_video_device::apply_fade(const rectangle &cliprect) +{ + const uint16_t fade_offset = m_video_regs[0x30]; + for (int y = cliprect.min_y; y <= cliprect.max_y; y++) + { + uint32_t *src = &m_screenbuf[cliprect.min_x + 320 * y]; + for (int x = cliprect.min_x; x <= cliprect.max_x; x++) + { + const uint32_t src_rgb = *src; + const uint8_t src_r = (src_rgb >> 16) & 0xff; + const uint8_t src_g = (src_rgb >> 8) & 0xff; + const uint8_t src_b = (src_rgb >> 0) & 0xff; + const uint8_t r = src_r - fade_offset; + const uint8_t g = src_g - fade_offset; + const uint8_t b = src_b - fade_offset; + *src++ = (r > src_r ? 0 : (r << 16)) | + (g > src_g ? 0 : (g << 8)) | + (b > src_b ? 0 : (b << 0)); + } + } +} + +uint32_t spg2xx_video_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + memset(&m_screenbuf[320 * cliprect.min_y], 0, 4 * 320 * ((cliprect.max_y - cliprect.min_y) + 1)); + + const uint32_t page1_addr = 0x40 * m_video_regs[0x20]; + const uint32_t page2_addr = 0x40 * m_video_regs[0x21]; + uint16_t *page1_regs = m_video_regs + 0x10; + uint16_t *page2_regs = m_video_regs + 0x16; + + for (uint32_t scanline = (uint32_t)cliprect.min_y; scanline <= (uint32_t)cliprect.max_y; scanline++) + { + for (int i = 0; i < 4; i++) + { + if (!SPG_DEBUG_VIDEO || !m_hide_page0) + draw_page(cliprect, scanline, i, page1_addr, page1_regs); + if (!SPG_DEBUG_VIDEO || !m_hide_page1) + draw_page(cliprect, scanline, i, page2_addr, page2_regs); + if (!SPG_DEBUG_VIDEO || !m_hide_sprites) + draw_sprites(cliprect, scanline, i); + } + } + + if ((m_video_regs[0x3c] & 0x00ff) != 0x0020) + { + apply_saturation(cliprect); + } + + if (m_video_regs[0x30] != 0) + { + apply_fade(cliprect); + } + + for (int y = cliprect.min_y; y <= cliprect.max_y; y++) + { + uint32_t *dest = &bitmap.pix32(y, cliprect.min_x); + uint32_t *src = &m_screenbuf[cliprect.min_x + 320 * y]; + memcpy(dest, src, sizeof(uint32_t) * ((cliprect.max_x - cliprect.min_x) + 1)); + } + + if (SPG_DEBUG_VIDEO && m_debug_palette) + { + for (int y = cliprect.min_y; y <= cliprect.max_y && y < 128; y++) + { + const uint16_t high_nybble = (y / 8) << 4; + uint32_t *dest = &bitmap.pix32(y, cliprect.min_x); + for (int x = cliprect.min_x; x <= cliprect.max_x && x < 256; x++) + { + const uint16_t low_nybble = x / 16; + const uint16_t palette_entry = high_nybble | low_nybble; + const uint16_t color = m_paletteram[palette_entry]; + if (!(color & 0x8000)) + { + *dest = m_rgb555_to_rgb888[color & 0x7fff]; + } + dest++; + } + } + } + + return 0; +} + +void spg2xx_video_device::do_sprite_dma(uint32_t len) +{ + address_space &mem = m_cpu->space(AS_PROGRAM); + + uint32_t src = m_video_regs[0x70] & 0x3fff; + uint32_t dst = m_video_regs[0x71]; + + for (uint32_t j = 0; j < len; j++) + { + m_spriteram[(dst + j) & 0x3ff] = mem.read_word(src + j); + } + + m_video_regs[0x72] = 0; + if (VIDEO_IRQ_ENABLE & 4) + { + const uint16_t old = VIDEO_IRQ_STATUS; + VIDEO_IRQ_STATUS |= 4; + const uint16_t changed = old ^ (VIDEO_IRQ_ENABLE & VIDEO_IRQ_STATUS); + if (changed) + check_video_irq(); + } +} + +READ16_MEMBER(spg2xx_video_device::video_r) +{ + switch (offset) + { + case 0x38: // Current Line + LOGMASKED(LOG_VLINES, "video_r: Current Line: %04x\n", m_screen->vpos()); + return m_screen->vpos(); + + case 0x62: // Video IRQ Enable + LOGMASKED(LOG_IRQS, "video_r: Video IRQ Enable: %04x\n", VIDEO_IRQ_ENABLE); + return VIDEO_IRQ_ENABLE; + + case 0x63: // Video IRQ Status + LOGMASKED(LOG_IRQS, "video_r: Video IRQ Status: %04x\n", VIDEO_IRQ_STATUS); + return VIDEO_IRQ_STATUS; + + default: + LOGMASKED(LOG_UNKNOWN_PPU, "video_r: Unknown register %04x = %04x\n", 0x2800 + offset, m_video_regs[offset]); + break; + } + return m_video_regs[offset]; +} + +WRITE16_MEMBER(spg2xx_video_device::video_w) +{ + switch (offset) + { + case 0x10: // Page 1 X scroll + LOGMASKED(LOG_PPU_WRITES, "video_w: Page 1 X Scroll = %04x\n", data & 0x01ff); + m_video_regs[offset] = data & 0x01ff; + break; + + case 0x11: // Page 1 Y scroll + LOGMASKED(LOG_PPU_WRITES, "video_w: Page 1 Y Scroll = %04x\n", data & 0x00ff); + m_video_regs[offset] = data & 0x00ff; + break; + + case 0x12: // Page 1 Attributes + LOGMASKED(LOG_PPU_WRITES, "video_w: Page 1 Attributes = %04x (Depth:%d, Palette:%d, VSize:%d, HSize:%d, FlipY:%d, FlipX:%d, BPP:%d)\n", data + , (data >> 12) & 3, (data >> 8) & 15, 8 << ((data >> 6) & 3), 8 << ((data >> 4) & 3), BIT(data, 3), BIT(data, 2), 2 * ((data & 3) + 1)); + m_video_regs[offset] = data; + break; + + case 0x13: // Page 1 Control + LOGMASKED(LOG_PPU_WRITES, "video_w: Page 1 Control = %04x (Blend:%d, HiColor:%d, RowScroll:%d, Enable:%d, Wallpaper:%d, RegSet:%d, Bitmap:%d)\n", data + , BIT(data, 8), BIT(data, 7), BIT(data, 4), BIT(data, 3), BIT(data, 2), BIT(data, 1), BIT(data, 0)); + m_video_regs[offset] = data; + break; + + case 0x14: // Page 1 Tile Address + LOGMASKED(LOG_PPU_WRITES, "video_w: Page 1 Tile Address = %04x\n", data & 0x1fff); + m_video_regs[offset] = data; + break; + + case 0x15: // Page 1 Attribute Address + LOGMASKED(LOG_PPU_WRITES, "video_w: Page 1 Attribute Address = %04x\n", data & 0x1fff); + m_video_regs[offset] = data; + break; + + case 0x16: // Page 2 X scroll + LOGMASKED(LOG_PPU_WRITES, "video_w: Page 2 X Scroll = %04x\n", data & 0x01ff); + m_video_regs[offset] = data & 0x01ff; + break; + + case 0x17: // Page 2 Y scroll + LOGMASKED(LOG_PPU_WRITES, "video_w: Page 2 Y Scroll: %04x = %04x\n", 0x2800 | offset, data & 0x00ff); + m_video_regs[offset] = data & 0x00ff; + break; + + case 0x18: // Page 2 Attributes + LOGMASKED(LOG_PPU_WRITES, "video_w: Page 2 Attributes = %04x (Depth:%d, Palette:%d, VSize:%d, HSize:%d, FlipY:%d, FlipX:%d, BPP:%d)\n", data + , (data >> 12) & 3, (data >> 8) & 15, 8 << ((data >> 6) & 3), 8 << ((data >> 4) & 3), BIT(data, 3), BIT(data, 2), 2 * ((data & 3) + 1)); + m_video_regs[offset] = data; + break; + + case 0x19: // Page 2 Control + LOGMASKED(LOG_PPU_WRITES, "video_w: Page 2 Control = %04x (Blend:%d, HiColor:%d, RowScroll:%d, Enable:%d, Wallpaper:%d, RegSet:%d, Bitmap:%d)\n", data + , BIT(data, 8), BIT(data, 7), BIT(data, 4), BIT(data, 3), BIT(data, 2), BIT(data, 1), BIT(data, 0)); + m_video_regs[offset] = data; + break; + + case 0x1a: // Page 2 Tile Address + LOGMASKED(LOG_PPU_WRITES, "video_w: Page 2 Tile Address = %04x\n", data & 0x1fff); + m_video_regs[offset] = data; + break; + + case 0x1b: // Page 2 Attribute Address + LOGMASKED(LOG_PPU_WRITES, "video_w: Page 2 Attribute Address = %04x\n", data & 0x1fff); + m_video_regs[offset] = data; + break; + + case 0x20: // Page 1 Segment Address + LOGMASKED(LOG_PPU_WRITES, "video_w: Page 1 Segment Address = %04x\n", data); + m_video_regs[offset] = data; + break; + + case 0x21: // Page 2 Segment Address + LOGMASKED(LOG_PPU_WRITES, "video_w: Page 2 Segment Address = %04x\n", data); + m_video_regs[offset] = data; + break; + + case 0x22: // Sprite Segment Address + LOGMASKED(LOG_PPU_WRITES, "video_w: Sprite Segment Address = %04x\n", data); + m_video_regs[offset] = data; + break; + + case 0x2a: // Blend Level Control + LOGMASKED(LOG_PPU_WRITES, "video_w: Blend Level Control = %04x\n", data & 0x0003); + m_video_regs[offset] = data & 0x0003; + break; + + case 0x30: // Fade Effect Control + LOGMASKED(LOG_PPU_WRITES, "video_w: Fade Effect Control = %04x\n", data & 0x00ff); + m_video_regs[offset] = data & 0x00ff; + break; + + case 0x36: // IRQ pos V + case 0x37: // IRQ pos H + m_video_regs[offset] = data & 0x01ff; + LOGMASKED(LOG_IRQS, "video_w: Video IRQ Position: %04x,%04x (%04x)\n", m_video_regs[0x37], m_video_regs[0x36], 0x2800 | offset); + if (m_video_regs[0x37] < 160 && m_video_regs[0x36] < 240) + m_screenpos_timer->adjust(m_screen->time_until_pos(m_video_regs[0x36], m_video_regs[0x37] << 1)); + else + m_screenpos_timer->adjust(attotime::never); + break; + + case 0x39: // Latch 1st Line Pen Pulse + LOGMASKED(LOG_PPU_WRITES, "video_w: Latch 1st Line Pen Pulse = %04x\n", data & 0x0001); + m_video_regs[offset] = data & 0x0001; + break; + + case 0x3c: // TV Control 1 + LOGMASKED(LOG_PPU_WRITES, "video_w: TV Control 1 = %04x (Hue:%02x, Saturation:%02x)\n", data, data >> 8, data & 0x00ff); + m_video_regs[offset] = data; + break; + + case 0x3d: // TV Control 2 + { + static const char* const s_lpf_mode[4] = { "LPF1", "LPF2", "All", "Edge" }; + LOGMASKED(LOG_PPU_WRITES, "video_w: TV Control 2 = %04x (LPFMode:%s, Enable:%d, Interlace:%d)\n", data & 0x000f + , s_lpf_mode[(data >> 2) & 3], BIT(data, 1), BIT(data, 0)); + m_video_regs[offset] = data & 0x000f; + break; + } + + case 0x3e: // Light Pen Y Position + LOGMASKED(LOG_PPU_WRITES, "video_w: Light Pen Y (read only) = %04x\n", data & 0x01ff); + break; + + case 0x3f: // Light Pen YXPosition + LOGMASKED(LOG_PPU_WRITES, "video_w: Light Pen X (read only) = %04x\n", data & 0x01ff); + break; + + case 0x42: // Sprite Control + LOGMASKED(LOG_PPU_WRITES, "video_w: Sprite Control = %04x (TopLeft:%d, Enable:%d)\n", data & 0x0003, BIT(data, 1), BIT(data, 0)); + m_video_regs[offset] = data & 0x0003; + break; + + case 0x62: // Video IRQ Enable + { + LOGMASKED(LOG_IRQS, "video_w: Video IRQ Enable = %04x (DMA:%d, Timing:%d, Blanking:%d)\n", data & 0x0007, BIT(data, 2), BIT(data, 1), BIT(data, 0)); + const uint16_t old = VIDEO_IRQ_ENABLE & VIDEO_IRQ_STATUS; + VIDEO_IRQ_ENABLE = data & 0x0007; + const uint16_t changed = old ^ (VIDEO_IRQ_ENABLE & VIDEO_IRQ_STATUS); + if (changed) + check_video_irq(); + break; + } + + case 0x63: // Video IRQ Acknowledge + { + LOGMASKED(LOG_IRQS, "video_w: Video IRQ Acknowledge = %04x\n", data); + const uint16_t old = VIDEO_IRQ_ENABLE & VIDEO_IRQ_STATUS; + VIDEO_IRQ_STATUS &= ~data; + const uint16_t changed = old ^ (VIDEO_IRQ_ENABLE & VIDEO_IRQ_STATUS); + if (changed) + check_video_irq(); + break; + } + + case 0x70: // Sprite DMA Source + LOGMASKED(LOG_DMA, "video_w: Sprite DMA Source = %04x\n", data & 0x3fff); + m_video_regs[offset] = data & 0x3fff; + break; + + case 0x71: // Sprite DMA Dest + LOGMASKED(LOG_DMA, "video_w: Sprite DMA Dest = %04x\n", data & 0x03ff); + m_video_regs[offset] = data & 0x03ff; + break; + + case 0x72: // Sprite DMA Length + { + LOGMASKED(LOG_DMA, "video_w: Sprite DMA Length = %04x\n", data & 0x03ff); + uint16_t length = data & 0x3ff; + do_sprite_dma(length ? length : 0x400); + break; + } + + default: + LOGMASKED(LOG_UNKNOWN_PPU, "video_w: Unknown register %04x = %04x\n", 0x2800 + offset, data); + m_video_regs[offset] = data; + break; + } +} + +WRITE_LINE_MEMBER(spg2xx_video_device::vblank) +{ + if (!state) + { + VIDEO_IRQ_STATUS &= ~1; + LOGMASKED(LOG_IRQS, "Setting video IRQ status to %04x\n", VIDEO_IRQ_STATUS); + check_video_irq(); + return; + } + +#if SPG_DEBUG_VIDEO + if (machine().input().code_pressed_once(KEYCODE_5)) + m_hide_page0 = !m_hide_page0; + if (machine().input().code_pressed_once(KEYCODE_6)) + m_hide_page1 = !m_hide_page1; + if (machine().input().code_pressed_once(KEYCODE_7)) + m_hide_sprites = !m_hide_sprites; + if (machine().input().code_pressed_once(KEYCODE_8)) + m_debug_sprites = !m_debug_sprites; + if (machine().input().code_pressed_once(KEYCODE_9)) + m_sprite_index_to_debug--; + if (machine().input().code_pressed_once(KEYCODE_0)) + m_sprite_index_to_debug++; + if (machine().input().code_pressed_once(KEYCODE_L)) + m_debug_palette = !m_debug_palette; +#endif + + if (VIDEO_IRQ_ENABLE & 1) + { + VIDEO_IRQ_STATUS |= 1; + LOGMASKED(LOG_IRQS, "Setting video IRQ status to %04x\n", VIDEO_IRQ_STATUS); + check_video_irq(); + } +} + +void spg2xx_video_device::check_video_irq() +{ + LOGMASKED(LOG_IRQS, "%ssserting IRQ0 (%04x, %04x)\n", (VIDEO_IRQ_STATUS & VIDEO_IRQ_ENABLE) ? "A" : "Dea", VIDEO_IRQ_STATUS, VIDEO_IRQ_ENABLE); + m_video_irq_cb((VIDEO_IRQ_STATUS & VIDEO_IRQ_ENABLE) ? ASSERT_LINE : CLEAR_LINE); +} + +void spg2xx_video_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch (id) + { + case TIMER_SCREENPOS: + { + if (VIDEO_IRQ_ENABLE & 2) + { + VIDEO_IRQ_STATUS |= 2; + check_video_irq(); + } + m_screen->update_partial(m_screen->vpos()); + + // fire again, jak_dbz pinball needs this + m_screenpos_timer->adjust(m_screen->time_until_pos(m_video_regs[0x36], m_video_regs[0x37] << 1)); + break; + } + } +} diff --git a/src/devices/machine/spg2xx_video.h b/src/devices/machine/spg2xx_video.h new file mode 100644 index 00000000000..064e3cb9757 --- /dev/null +++ b/src/devices/machine/spg2xx_video.h @@ -0,0 +1,137 @@ +// license:BSD-3-Clause +// copyright-holders:Ryan Holtz +/***************************************************************************** + + SunPlus SPG2xx-series SoC peripheral emulation (Video) + +**********************************************************************/ + +#ifndef MAME_MACHINE_SPG2XX_VIDEO_H +#define MAME_MACHINE_SPG2XX_VIDEO_H + +#pragma once + +#include "cpu/unsp/unsp.h" +#include "screen.h" + +class spg2xx_video_device : public device_t +{ +public: + spg2xx_video_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock); + + uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); + DECLARE_WRITE_LINE_MEMBER(vblank); + + DECLARE_READ16_MEMBER(video_r); + DECLARE_WRITE16_MEMBER(video_w); + + auto sprlimit_read_callback() { return m_sprlimit_read_cb.bind(); }; + auto rowscrolloffset_read_callback() { return m_rowscrolloffset_read_cb.bind(); }; + + auto write_video_irq_callback() { return m_video_irq_cb.bind(); }; + +protected: + + enum + { + PAGE_ENABLE_MASK = 0x0008, + PAGE_WALLPAPER_MASK = 0x0004, + + SPRITE_ENABLE_MASK = 0x0001, + SPRITE_COORD_TL_MASK = 0x0002, + + PAGE_PRIORITY_FLAG_MASK = 0x3000, + PAGE_PRIORITY_FLAG_SHIFT = 12, + PAGE_TILE_HEIGHT_MASK = 0x00c0, + PAGE_TILE_HEIGHT_SHIFT = 6, + PAGE_TILE_WIDTH_MASK = 0x0030, + PAGE_TILE_WIDTH_SHIFT = 4, + TILE_X_FLIP = 0x0004, + TILE_Y_FLIP = 0x0008 + }; + + + inline void check_video_irq(); + + static const device_timer_id TIMER_SCREENPOS = 2; + + virtual void device_start() override; + virtual void device_reset() override; + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override; + + void do_sprite_dma(uint32_t len); + + enum blend_enable_t : bool + { + BlendOff = false, + BlendOn = true + }; + + enum rowscroll_enable_t : bool + { + RowScrollOff = false, + RowScrollOn = true + }; + + enum flipx_t : bool + { + FlipXOff = false, + FlipXOn = true + }; + + void apply_saturation(const rectangle &cliprect); + void apply_fade(const rectangle &cliprect); + + template<blend_enable_t Blend, rowscroll_enable_t RowScroll, flipx_t FlipX> + void draw(const rectangle &cliprect, uint32_t line, uint32_t xoff, uint32_t yoff, uint32_t bitmap_addr, uint16_t tile, int32_t h, int32_t w, uint8_t bpp, uint32_t yflipmask, uint32_t palette_offset); + void draw_page(const rectangle &cliprect, uint32_t scanline, int priority, uint32_t bitmap_addr, uint16_t *regs); + void draw_sprite(const rectangle &cliprect, uint32_t scanline, int priority, uint32_t base_addr); + void draw_sprites(const rectangle &cliprect, uint32_t scanline, int priority); + + uint8_t mix_channel(uint8_t a, uint8_t b); + + uint32_t m_screenbuf[320 * 240]; + uint8_t m_rgb5_to_rgb8[32]; + uint32_t m_rgb555_to_rgb888[0x8000]; + + bool m_hide_page0; + bool m_hide_page1; + bool m_hide_sprites; + bool m_debug_sprites; + bool m_debug_blit; + bool m_debug_palette; + uint8_t m_sprite_index_to_debug; + + uint16_t m_video_regs[0x100]; + + devcb_read16 m_sprlimit_read_cb; + devcb_read16 m_rowscrolloffset_read_cb; + + emu_timer *m_screenpos_timer; + + required_device<unsp_device> m_cpu; + required_device<screen_device> m_screen; + required_shared_ptr<uint16_t> m_scrollram; + required_shared_ptr<uint16_t> m_paletteram; + required_shared_ptr<uint16_t> m_spriteram; + + devcb_write_line m_video_irq_cb; +}; + +class spg24x_video_device : public spg2xx_video_device +{ +public: + template <typename T, typename U> + spg24x_video_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, T &&cpu_tag, U &&screen_tag) + : spg24x_video_device(mconfig, tag, owner, clock) + { + m_cpu.set_tag(std::forward<T>(cpu_tag)); + m_screen.set_tag(std::forward<U>(screen_tag)); + } + + spg24x_video_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); +}; + +DECLARE_DEVICE_TYPE(SPG24X_VIDEO, spg24x_video_device) + +#endif // MAME_MACHINE_SPG2XX_VIDEO_H diff --git a/src/devices/machine/tmp68301.cpp b/src/devices/machine/tmp68301.cpp index ebc710bcde5..1eea072c64a 100644 --- a/src/devices/machine/tmp68301.cpp +++ b/src/devices/machine/tmp68301.cpp @@ -23,7 +23,8 @@ DEFINE_DEVICE_TYPE(TMP68301, tmp68301_device, "tmp68301", "Toshiba TMP68301") void tmp68301_device::tmp68301_regs(address_map &map) { -// AM_RANGE(0x000,0x3ff) AM_RAM + map(0x000, 0x3ff).rw(FUNC(tmp68301_device::regs_r), FUNC(tmp68301_device::regs_w)); + map(0x080, 0x093).rw(FUNC(tmp68301_device::icr_r), FUNC(tmp68301_device::icr_w)).umask16(0x00ff); map(0x094, 0x095).rw(FUNC(tmp68301_device::imr_r), FUNC(tmp68301_device::imr_w)); @@ -134,9 +135,7 @@ WRITE8_MEMBER(tmp68301_device::icr_w) } tmp68301_device::tmp68301_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : device_t(mconfig, TMP68301, tag, owner, clock), - device_memory_interface(mconfig, *this), - m_cpu(*this, finder_base::DUMMY_TAG), + : m68000_device(mconfig, TMP68301, tag, owner, clock), m_in_parallel_cb(*this), m_out_parallel_cb(*this), m_ipl(0), @@ -145,8 +144,7 @@ tmp68301_device::tmp68301_device(const machine_config &mconfig, const char *tag, m_iisr(0), m_scr(0), m_pdir(0), - m_pdr(0), - m_space_config("regs", ENDIANNESS_LITTLE, 16, 10, 0, address_map_constructor(FUNC(tmp68301_device::tmp68301_regs), this)) + m_pdr(0) { memset(m_regs, 0, sizeof(m_regs)); memset(m_icr, 0, sizeof(m_icr)); @@ -159,13 +157,17 @@ tmp68301_device::tmp68301_device(const machine_config &mconfig, const char *tag, void tmp68301_device::device_start() { - int i; - for (i = 0; i < 3; i++) + m68000_device::device_start(); + + for (int i = 0; i < 3; i++) m_tmp68301_timer[i] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(tmp68301_device::timer_callback), this)); m_in_parallel_cb.resolve_safe(0); m_out_parallel_cb.resolve_safe(); + m_program->install_device(0xfffc00, 0xffffff, *this, &tmp68301_device::tmp68301_regs); + m_int_ack_callback = device_irq_acknowledge_delegate(FUNC(tmp68301_device::irq_callback), this); + save_item(NAME(m_regs)); save_item(NAME(m_icr)); save_item(NAME(m_ipl)); @@ -183,6 +185,8 @@ void tmp68301_device::device_start() void tmp68301_device::device_reset() { + m68000_device::device_reset(); + m_ipr = 0; m_iisr = 0; m_imr = 0x7f7; // mask all irqs @@ -190,40 +194,10 @@ void tmp68301_device::device_reset() update_ipl(); } -//------------------------------------------------- -// memory_space_config - return a description of -// any address spaces owned by this device -//------------------------------------------------- - -device_memory_interface::space_config_vector tmp68301_device::memory_space_config() const -{ - return space_config_vector { - std::make_pair(0, &m_space_config) - }; -} - //************************************************************************** // INLINE HELPERS //************************************************************************** -//------------------------------------------------- -// read_byte - read a byte at the given address -//------------------------------------------------- - -inline uint16_t tmp68301_device::read_word(offs_t address) -{ - return space(0).read_word(address << 1); -} - -//------------------------------------------------- -// write_byte - write a byte at the given address -//------------------------------------------------- - -inline void tmp68301_device::write_word(offs_t address, uint16_t data) -{ - space(0).write_word(address << 1, data); -} - IRQ_CALLBACK_MEMBER(tmp68301_device::irq_callback) { uint8_t IVNR = m_regs[0x9a/2] & 0xe0; // Interrupt Vector Number Register (IVNR) @@ -312,7 +286,7 @@ void tmp68301_device::update_timer(int i) { int scale = (TCR & 0x3c00)>>10; // P4..1 if (scale > 8) scale = 8; - duration = attotime::from_hz(m_cpu->unscaled_clock()) * ((1 << scale) * max); + duration = attotime::from_hz(unscaled_clock()) * ((1 << scale) * max); } break; } @@ -343,9 +317,9 @@ void tmp68301_device::update_ipl() if (new_ipl != m_ipl) { if (m_ipl != 0) - m_cpu->set_input_line(m_ipl, CLEAR_LINE); + set_input_line(m_ipl, CLEAR_LINE); if (new_ipl != 0) - m_cpu->set_input_line(new_ipl, ASSERT_LINE); + set_input_line(new_ipl, ASSERT_LINE); m_ipl = new_ipl; } @@ -366,18 +340,16 @@ uint8_t tmp68301_device::serial_interrupt_cause(int channel) READ16_MEMBER( tmp68301_device::regs_r ) { - return read_word(offset); + return m_regs[offset]; } WRITE16_MEMBER( tmp68301_device::regs_w ) { COMBINE_DATA(&m_regs[offset]); - write_word(offset,m_regs[offset]); - if (!ACCESSING_BITS_0_7) return; -// logerror("CPU #0 PC %06X: TMP68301 Reg %04X<-%04X & %04X\n", m_cpu->pc(),offset*2,data,mem_mask^0xffff); +// logerror("CPU #0 PC %06X: TMP68301 Reg %04X<-%04X & %04X\n", >pc(),offset*2,data,mem_mask^0xffff); switch( offset * 2 ) { diff --git a/src/devices/machine/tmp68301.h b/src/devices/machine/tmp68301.h index e019387802b..c350b9b0be6 100644 --- a/src/devices/machine/tmp68301.h +++ b/src/devices/machine/tmp68301.h @@ -16,27 +16,19 @@ -class tmp68301_device : public device_t, - public device_memory_interface +class tmp68301_device : public m68000_device { public: tmp68301_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); - template <typename T> void set_cputag(T &&tag) { m_cpu.set_tag(std::forward<T>(tag)); } // FIXME: M68000 ought to be a parent class, not an external object auto in_parallel_callback() { return m_in_parallel_cb.bind(); } auto out_parallel_callback() { return m_out_parallel_cb.bind(); } - // Hardware Registers - DECLARE_READ16_MEMBER( regs_r ); - DECLARE_WRITE16_MEMBER( regs_w ); - // Interrupts void external_interrupt_0(); void external_interrupt_1(); void external_interrupt_2(); - IRQ_CALLBACK_MEMBER(irq_callback); - private: DECLARE_READ16_MEMBER(imr_r); DECLARE_WRITE16_MEMBER(imr_w); @@ -53,13 +45,18 @@ private: DECLARE_READ8_MEMBER(icr_r); DECLARE_WRITE8_MEMBER(icr_w); + // Hardware Registers + DECLARE_READ16_MEMBER( regs_r ); + DECLARE_WRITE16_MEMBER( regs_w ); + void tmp68301_regs(address_map &map); + IRQ_CALLBACK_MEMBER(irq_callback); + protected: // device-level overrides virtual void device_start() override; virtual void device_reset() override; - virtual space_config_vector memory_space_config() const override; private: TIMER_CALLBACK_MEMBER(timer_callback); @@ -78,11 +75,6 @@ private: static constexpr uint16_t TIMER1_IRQ = 1 << 9; static constexpr uint16_t TIMER2_IRQ = 1 << 10; - inline uint16_t read_word(offs_t address); - inline void write_word(offs_t address, uint16_t data); - - required_device<m68000_base_device> m_cpu; - devcb_read16 m_in_parallel_cb; devcb_write16 m_out_parallel_cb; @@ -100,8 +92,6 @@ private: uint16_t m_pdir; uint16_t m_pdr; uint8_t m_icr[10]; - - const address_space_config m_space_config; }; DECLARE_DEVICE_TYPE(TMP68301, tmp68301_device) diff --git a/src/devices/machine/tms5501.cpp b/src/devices/machine/tms5501.cpp index f7581a30a72..d067497567a 100644 --- a/src/devices/machine/tms5501.cpp +++ b/src/devices/machine/tms5501.cpp @@ -263,6 +263,9 @@ READ8_MEMBER( tms5501_device::rst_r ) READ8_MEMBER( tms5501_device::sta_r ) { + if(is_transmit_register_empty()) + m_sta |= STA_XBE; + uint8_t data = m_sta; m_sta &= ~STA_OE; diff --git a/src/devices/machine/upd765.cpp b/src/devices/machine/upd765.cpp index d6dbe6cedea..64b844dd222 100644 --- a/src/devices/machine/upd765.cpp +++ b/src/devices/machine/upd765.cpp @@ -2292,6 +2292,9 @@ void upd765_family_device::read_id_start(floppy_info &fi) return; } + for(int i=0; i<4; i++) + cur_live.idbuf[i] = command[i+2]; + read_id_continue(fi); } diff --git a/src/devices/machine/vrc5074.cpp b/src/devices/machine/vrc5074.cpp index b04b689bd9b..0aeef7ebfdc 100644 --- a/src/devices/machine/vrc5074.cpp +++ b/src/devices/machine/vrc5074.cpp @@ -1008,7 +1008,7 @@ WRITE_LINE_MEMBER(vrc5074_device::uart_irq_callback) READ32_MEMBER(vrc5074_device::serial_r) { - uint32_t result = m_uart->ins8250_r(space, offset>>1); + uint32_t result = m_uart->ins8250_r(offset>>1); if (0 && LOG_NILE) logerror("%s serial_r offset %03X = %08X (%08x)\n", machine().describe_context(), offset>>1, result, offset*4); @@ -1017,7 +1017,7 @@ READ32_MEMBER(vrc5074_device::serial_r) WRITE32_MEMBER(vrc5074_device::serial_w) { - m_uart->ins8250_w(space, offset>>1, data); + m_uart->ins8250_w(offset>>1, data); if (PRINTF_SERIAL && offset == NREG_UARTTHR) { static std::string debugStr; printf("%c", data); diff --git a/src/devices/machine/z80ctc.cpp b/src/devices/machine/z80ctc.cpp index 1bd0f887397..74adf998feb 100644 --- a/src/devices/machine/z80ctc.cpp +++ b/src/devices/machine/z80ctc.cpp @@ -91,7 +91,7 @@ z80ctc_device::z80ctc_device(const machine_config &mconfig, const char *tag, dev // read - standard handler for reading //------------------------------------------------- -READ8_MEMBER( z80ctc_device::read ) +uint8_t z80ctc_device::read(offs_t offset) { return m_channel[offset & 3]->read(); } @@ -101,7 +101,7 @@ READ8_MEMBER( z80ctc_device::read ) // write - standard handler for writing //------------------------------------------------- -WRITE8_MEMBER( z80ctc_device::write ) +void z80ctc_device::write(offs_t offset, uint8_t data) { m_channel[offset & 3]->write(data); } diff --git a/src/devices/machine/z80ctc.h b/src/devices/machine/z80ctc.h index 0b388eb3933..98dd852ddd2 100644 --- a/src/devices/machine/z80ctc.h +++ b/src/devices/machine/z80ctc.h @@ -88,8 +88,8 @@ public: template <int Channel> void set_clk(const XTAL &xtal) { channel_config(Channel).set_clock(xtal); } // read/write handlers - DECLARE_READ8_MEMBER( read ); - DECLARE_WRITE8_MEMBER( write ); + uint8_t read(offs_t offset); + void write(offs_t offset, uint8_t data); DECLARE_WRITE_LINE_MEMBER( trg0 ); DECLARE_WRITE_LINE_MEMBER( trg1 ); DECLARE_WRITE_LINE_MEMBER( trg2 ); diff --git a/src/devices/machine/z80dart.cpp b/src/devices/machine/z80dart.cpp index 05a7aef03f3..116f9264598 100644 --- a/src/devices/machine/z80dart.cpp +++ b/src/devices/machine/z80dart.cpp @@ -392,7 +392,7 @@ int z80dart_device::m1_r() // cd_ba_r - //------------------------------------------------- -READ8_MEMBER( z80dart_device::cd_ba_r ) +uint8_t z80dart_device::cd_ba_r(offs_t offset) { int ba = BIT(offset, 0); int cd = BIT(offset, 1); @@ -406,7 +406,7 @@ READ8_MEMBER( z80dart_device::cd_ba_r ) // cd_ba_w - //------------------------------------------------- -WRITE8_MEMBER( z80dart_device::cd_ba_w ) +void z80dart_device::cd_ba_w(offs_t offset, uint8_t data) { int ba = BIT(offset, 0); int cd = BIT(offset, 1); @@ -423,7 +423,7 @@ WRITE8_MEMBER( z80dart_device::cd_ba_w ) // ba_cd_r - //------------------------------------------------- -READ8_MEMBER( z80dart_device::ba_cd_r ) +uint8_t z80dart_device::ba_cd_r(offs_t offset) { int ba = BIT(offset, 1); int cd = BIT(offset, 0); @@ -437,7 +437,7 @@ READ8_MEMBER( z80dart_device::ba_cd_r ) // ba_cd_w - //------------------------------------------------- -WRITE8_MEMBER( z80dart_device::ba_cd_w ) +void z80dart_device::ba_cd_w(offs_t offset, uint8_t data) { int ba = BIT(offset, 1); int cd = BIT(offset, 0); diff --git a/src/devices/machine/z80dart.h b/src/devices/machine/z80dart.h index 6abceefa5d9..976eafe7f7b 100644 --- a/src/devices/machine/z80dart.h +++ b/src/devices/machine/z80dart.h @@ -418,20 +418,20 @@ public: m_txcb = txb; } - DECLARE_READ8_MEMBER( cd_ba_r ); - DECLARE_WRITE8_MEMBER( cd_ba_w ); - DECLARE_READ8_MEMBER( ba_cd_r ); - DECLARE_WRITE8_MEMBER( ba_cd_w ); + uint8_t cd_ba_r(offs_t offset); + void cd_ba_w(offs_t offset, uint8_t data); + uint8_t ba_cd_r(offs_t offset); + void ba_cd_w(offs_t offset, uint8_t data); - DECLARE_READ8_MEMBER( da_r ) { return m_chanA->data_read(); } - DECLARE_WRITE8_MEMBER( da_w ) { m_chanA->data_write(data); } - DECLARE_READ8_MEMBER( db_r ) { return m_chanB->data_read(); } - DECLARE_WRITE8_MEMBER( db_w ) { m_chanB->data_write(data); } + uint8_t da_r() { return m_chanA->data_read(); } + void da_w(uint8_t data) { m_chanA->data_write(data); } + uint8_t db_r() { return m_chanB->data_read(); } + void db_w(uint8_t data) { m_chanB->data_write(data); } - DECLARE_READ8_MEMBER( ca_r ) { return m_chanA->control_read(); } - DECLARE_WRITE8_MEMBER( ca_w ) { m_chanA->control_write(data); } - DECLARE_READ8_MEMBER( cb_r ) { return m_chanB->control_read(); } - DECLARE_WRITE8_MEMBER( cb_w ) { m_chanB->control_write(data); } + uint8_t ca_r() { return m_chanA->control_read(); } + void ca_w(uint8_t data) { m_chanA->control_write(data); } + uint8_t cb_r() { return m_chanB->control_read(); } + void cb_w(uint8_t data) { m_chanB->control_write(data); } // interrupt acknowledge int m1_r(); @@ -580,7 +580,7 @@ public: // construction/destruction i8274_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); - DECLARE_READ8_MEMBER( inta_r ) { return m1_r(); }; + uint8_t inta_r() { return m1_r(); }; }; diff --git a/src/devices/machine/z80sio.cpp b/src/devices/machine/z80sio.cpp index 8337aeafdf6..b985340e576 100644 --- a/src/devices/machine/z80sio.cpp +++ b/src/devices/machine/z80sio.cpp @@ -845,7 +845,7 @@ int i8274_new_device::m1_r() //------------------------------------------------- // cd_ba_r - //------------------------------------------------- -READ8_MEMBER( z80sio_device::cd_ba_r ) +uint8_t z80sio_device::cd_ba_r(offs_t offset) { int ba = BIT(offset, 0); int cd = BIT(offset, 1); @@ -858,7 +858,7 @@ READ8_MEMBER( z80sio_device::cd_ba_r ) //------------------------------------------------- // cd_ba_w - //------------------------------------------------- -WRITE8_MEMBER( z80sio_device::cd_ba_w ) +void z80sio_device::cd_ba_w(offs_t offset, uint8_t data) { int ba = BIT(offset, 0); int cd = BIT(offset, 1); @@ -874,7 +874,7 @@ WRITE8_MEMBER( z80sio_device::cd_ba_w ) //------------------------------------------------- // ba_cd_r - //------------------------------------------------- -READ8_MEMBER( z80sio_device::ba_cd_r ) +uint8_t z80sio_device::ba_cd_r(offs_t offset) { int ba = BIT(offset, 1); int cd = BIT(offset, 0); @@ -887,7 +887,7 @@ READ8_MEMBER( z80sio_device::ba_cd_r ) //------------------------------------------------- // ba_cd_w - //------------------------------------------------- -WRITE8_MEMBER( z80sio_device::ba_cd_w ) +void z80sio_device::ba_cd_w(offs_t offset, uint8_t data) { int ba = BIT(offset, 1); int cd = BIT(offset, 0); diff --git a/src/devices/machine/z80sio.h b/src/devices/machine/z80sio.h index eff587dc281..fabe6a20bfc 100644 --- a/src/devices/machine/z80sio.h +++ b/src/devices/machine/z80sio.h @@ -305,20 +305,20 @@ public: template <typename T> void set_cputag(T &&tag) { m_hostcpu.set_tag(std::forward<T>(tag)); } - DECLARE_READ8_MEMBER( cd_ba_r ); - DECLARE_WRITE8_MEMBER( cd_ba_w ); - DECLARE_READ8_MEMBER( ba_cd_r ); - DECLARE_WRITE8_MEMBER( ba_cd_w ); - - DECLARE_READ8_MEMBER( da_r ) { return m_chanA->data_read(); } - DECLARE_WRITE8_MEMBER( da_w ) { m_chanA->data_write(data); } - DECLARE_READ8_MEMBER( db_r ) { return m_chanB->data_read(); } - DECLARE_WRITE8_MEMBER( db_w ) { m_chanB->data_write(data); } - - DECLARE_READ8_MEMBER( ca_r ) { return m_chanA->control_read(); } - DECLARE_WRITE8_MEMBER( ca_w ) { m_chanA->control_write(data); } - DECLARE_READ8_MEMBER( cb_r ) { return m_chanB->control_read(); } - DECLARE_WRITE8_MEMBER( cb_w ) { m_chanB->control_write(data); } + uint8_t cd_ba_r(offs_t offset); + void cd_ba_w(offs_t offset, uint8_t data); + uint8_t ba_cd_r(offs_t offset); + void ba_cd_w(offs_t offset, uint8_t data); + + uint8_t da_r() { return m_chanA->data_read(); } + void da_w(uint8_t data) { m_chanA->data_write(data); } + uint8_t db_r() { return m_chanB->data_read(); } + void db_w(uint8_t data) { m_chanB->data_write(data); } + + uint8_t ca_r() { return m_chanA->control_read(); } + void ca_w(uint8_t data) { m_chanA->control_write(data); } + uint8_t cb_r() { return m_chanB->control_read(); } + void cb_w(uint8_t data) { m_chanB->control_write(data); } // interrupt acknowledge virtual int m1_r(); diff --git a/src/devices/sound/c6280.cpp b/src/devices/sound/c6280.cpp index 0e5873c86de..6c6f2410166 100644 --- a/src/devices/sound/c6280.cpp +++ b/src/devices/sound/c6280.cpp @@ -92,16 +92,16 @@ void c6280_device::sound_stream_update(sound_stream &stream, stream_sample_t **i if((ch >= 4) && (m_channel[ch].m_noise_control & 0x80)) { /* Noise mode */ - uint32_t step = m_noise_freq_tab[(m_channel[ch].m_noise_control & 0x1F) ^ 0x1F]; + uint32_t step = (m_channel[ch].m_noise_control & 0x1F) ^ 0x1F; for (int i = 0; i < samples; i += 1) { static int data = 0; - m_channel[ch].m_noise_counter += step; - if(m_channel[ch].m_noise_counter >= 0x800) + if(m_channel[ch].m_noise_counter <= 0) { + m_channel[ch].m_noise_counter = step << 2; data = (machine().rand() & 1) ? 0x1F : 0; } - m_channel[ch].m_noise_counter &= 0x7FF; + m_channel[ch].m_noise_counter--; outputs[0][i] += (int16_t)(vll * (data - 16)); outputs[1][i] += (int16_t)(vlr * (data - 16)); } @@ -118,28 +118,40 @@ void c6280_device::sound_stream_update(sound_stream &stream, stream_sample_t **i } else { - if ((m_lfo_control & 0x80) && (ch < 2)) + if ((m_lfo_control & 3) && (ch < 2)) { if (ch == 0) // CH 0 only, CH 1 is muted { /* Waveform mode with LFO */ - uint32_t step = m_channel[0].m_frequency; - uint16_t lfo_step = m_channel[1].m_frequency; + uint16_t lfo_step = m_channel[1].m_frequency ? m_channel[1].m_frequency : 0x1000; for (int i = 0; i < samples; i += 1) { - int offset, lfooffset; - int16_t data, lfo_data; - lfooffset = (m_channel[1].m_counter >> 12) & 0x1F; - m_channel[1].m_counter += m_wave_freq_tab[(lfo_step * m_lfo_frequency) & 0xfff]; // TODO : multiply? verify this from real hardware. - m_channel[1].m_counter &= 0x1FFFF; - lfo_data = m_channel[1].m_waveform[lfooffset]; - if (m_lfo_control & 3) + int32_t step = m_channel[0].m_frequency ? m_channel[0].m_frequency : 0x1000; + if (m_lfo_control & 0x80) // reset LFO + { + m_channel[1].m_tick = lfo_step * m_lfo_frequency; + m_channel[1].m_counter = 0; + } + else + { + int lfooffset = m_channel[1].m_counter; + m_channel[1].m_tick--; + if (m_channel[1].m_tick <= 0) + { + m_channel[1].m_tick = lfo_step * m_lfo_frequency; // TODO : multiply? verify this from real hardware. + m_channel[1].m_counter = (m_channel[1].m_counter + 1) & 0x1f; + } + int16_t lfo_data = m_channel[1].m_waveform[lfooffset]; step += ((lfo_data - 16) << (((m_lfo_control & 3)-1)<<1)); // verified from patent, TODO : same in real hardware? - - offset = (m_channel[0].m_counter >> 12) & 0x1F; - m_channel[0].m_counter += m_wave_freq_tab[step & 0xfff]; - m_channel[0].m_counter &= 0x1FFFF; - data = m_channel[0].m_waveform[offset]; + } + int offset = m_channel[0].m_counter; + m_channel[0].m_tick--; + if (m_channel[0].m_tick <= 0) + { + m_channel[0].m_tick = step; + m_channel[0].m_counter = (m_channel[0].m_counter + 1) & 0x1f; + } + int16_t data = m_channel[0].m_waveform[offset]; outputs[0][i] += (int16_t)(vll * (data - 16)); outputs[1][i] += (int16_t)(vlr * (data - 16)); } @@ -148,15 +160,17 @@ void c6280_device::sound_stream_update(sound_stream &stream, stream_sample_t **i else { /* Waveform mode */ - uint32_t step = m_wave_freq_tab[m_channel[ch].m_frequency]; + uint32_t step = m_channel[ch].m_frequency ? m_channel[ch].m_frequency : 0x1000; for (int i = 0; i < samples; i += 1) { - int offset; - int16_t data; - offset = (m_channel[ch].m_counter >> 12) & 0x1F; - m_channel[ch].m_counter += step; - m_channel[ch].m_counter &= 0x1FFFF; - data = m_channel[ch].m_waveform[offset]; + int offset = m_channel[ch].m_counter; + m_channel[ch].m_tick--; + if (m_channel[ch].m_tick <= 0) + { + m_channel[ch].m_tick = step; + m_channel[ch].m_counter = (m_channel[ch].m_counter + 1) & 0x1f; + } + int16_t data = m_channel[ch].m_waveform[offset]; outputs[0][i] += (int16_t)(vll * (data - 16)); outputs[1][i] += (int16_t)(vlr * (data - 16)); } @@ -205,6 +219,10 @@ WRITE8_MEMBER( c6280_device::c6280_w ) { chan->m_index = 0; } + if(((chan->m_control & 0x80) == 0) && (data & 0x80)) + { + chan->m_tick = chan->m_frequency; + } chan->m_control = data; break; @@ -261,38 +279,9 @@ c6280_device::c6280_device(const machine_config &mconfig, const char *tag, devic { } -//------------------------------------------------- -// calculate_clocks - (re)calculate clock-derived -// members -//------------------------------------------------- - -void c6280_device::calculate_clocks() -{ - int rate = clock() / 16; - - /* Make waveform frequency table */ - for (int i = 0; i < 4096; i += 1) - { - double step = (16 * 4096) / (i + 1); - m_wave_freq_tab[(1 + i) & 0xFFF] = (uint32_t)step; - } - - /* Make noise frequency table */ - for (int i = 0; i < 32; i += 1) - { - double step = (16 * 32) / (i+1); - m_noise_freq_tab[i] = (uint32_t)step; - } - - if (m_stream != nullptr) - m_stream->set_sample_rate(rate); - else - m_stream = machine().sound().stream_alloc(*this, 0, 2, rate); -} - void c6280_device::device_clock_changed() { - calculate_clocks(); + m_stream->set_sample_rate(clock()); } //------------------------------------------------- @@ -311,7 +300,7 @@ void c6280_device::device_start() m_lfo_control = 0; memset(m_channel, 0, sizeof(channel) * 8); - calculate_clocks(); + m_stream = machine().sound().stream_alloc(*this, 0, 2, clock()); /* Make volume table */ /* PSG has 48dB volume range spread over 32 steps */ @@ -338,5 +327,6 @@ void c6280_device::device_start() save_item(NAME(m_channel[chan].m_noise_control), chan); save_item(NAME(m_channel[chan].m_noise_counter), chan); save_item(NAME(m_channel[chan].m_counter), chan); + save_item(NAME(m_channel[chan].m_tick), chan); } } diff --git a/src/devices/sound/c6280.h b/src/devices/sound/c6280.h index 5b7f94bce7f..0cfdc34799b 100644 --- a/src/devices/sound/c6280.h +++ b/src/devices/sound/c6280.h @@ -8,6 +8,8 @@ class c6280_device : public device_t, public device_sound_interface { public: + static constexpr feature_type imperfect_features() { return feature::SOUND; } // Incorrect / Not verified noise / LFO output + c6280_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); // write only @@ -22,8 +24,6 @@ protected: virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) override; private: - void calculate_clocks(); - struct channel { uint16_t m_frequency; uint8_t m_control; @@ -32,8 +32,9 @@ private: uint8_t m_index; int16_t m_dda; uint8_t m_noise_control; - uint32_t m_noise_counter; + int32_t m_noise_counter; uint32_t m_counter; + int32_t m_tick; }; // internal state @@ -44,8 +45,6 @@ private: uint8_t m_lfo_control; channel m_channel[8]; int16_t m_volume_table[32]; - uint32_t m_noise_freq_tab[32]; - uint32_t m_wave_freq_tab[4096]; }; DECLARE_DEVICE_TYPE(C6280, c6280_device) diff --git a/src/devices/sound/es8712.cpp b/src/devices/sound/es8712.cpp index e0b2699edd0..00ec7fe90d3 100644 --- a/src/devices/sound/es8712.cpp +++ b/src/devices/sound/es8712.cpp @@ -228,7 +228,7 @@ WRITE_LINE_MEMBER(es8712_device::msm_int) } else { - m_adpcm_select->write_ab(read_byte(m_base_offset)); + m_adpcm_select->ab_w(read_byte(m_base_offset)); m_adpcm_select->select_w(m_adpcm_trigger); m_adpcm_trigger ^= 1; if (m_adpcm_trigger == 0) diff --git a/src/devices/sound/meg.cpp b/src/devices/sound/meg.cpp new file mode 100644 index 00000000000..a1f9d67b293 --- /dev/null +++ b/src/devices/sound/meg.cpp @@ -0,0 +1,384 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert + +// Yamaha MEG - Multiple effects generator +// +// Audio dsp dedicated to effects generation + +#include "emu.h" +#include "debugger.h" +#include "meg.h" + +DEFINE_DEVICE_TYPE(MEG, meg_device, "meg", "Multiple Effects Generator (HD62098 / XM309A00)") +DEFINE_DEVICE_TYPE(MEGEMB, meg_embedded_device, "megemb", "Multiple Effects Generator (embedded)") + +void meg_base_device::prg_map(address_map &map) +{ + map(0, m_prg_size - 1).ram(); +} + +void meg_base_device::fp_map(address_map &map) +{ + map(0, m_prg_size - 1).ram(); +} + +void meg_base_device::offsets_map(address_map &map) +{ + map(0, 0x7f).ram(); +} + +meg_base_device::meg_base_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, u32 prg_size) : + cpu_device(mconfig, type, tag, owner, clock), + m_program_config("program", ENDIANNESS_BIG, 64, prg_size > 256 ? 9 : 8, -3, address_map_constructor(FUNC(meg_base_device::prg_map), this)), + m_fp_config("fp", ENDIANNESS_BIG, 16, prg_size > 256 ? 9 : 8, -1, address_map_constructor(FUNC(meg_base_device::fp_map), this)), + m_offsets_config("offsets", ENDIANNESS_BIG, 16, prg_size > 256 ? 7 : 7, -1, address_map_constructor(FUNC(meg_base_device::offsets_map), this)), + m_prg_size(prg_size) +{ +} + + +void meg_base_device::prg_w(u16 address, u64 opcode) +{ + m_program->write_qword(address, opcode); +} + +void meg_base_device::fp_w(u16 address, u16 value) +{ + m_fp->write_word(address, value); +} + +void meg_base_device::offset_w(u16 address, u16 value) +{ + m_offsets->write_word(address, value); +} + +void meg_base_device::lfo_w(u8 reg, u16 value) +{ + m_lfo[reg] = value; + + static const int dt[8] = { 0, 32, 64, 128, 256, 512, 1024, 2048 }; + static const int sh[8] = { 0, 0, 1, 2, 3, 4, 5, 6 }; + + int scale = (value >> 5) & 7; + int step = ((value & 31) << sh[scale]) + dt[scale]; + logerror("lfo_w %02x freq=%5.2f phase=%6.4f\n", reg, step * 44100.0/4194304, (value >> 8)/256.0); +} + +void meg_base_device::map_w(u8 reg, u16 value) +{ + m_map[reg] = value; +} + +u64 meg_base_device::prg_r(u16 address) const +{ + return m_program->read_qword(address); +} + +u16 meg_base_device::fp_r(u16 address) const +{ + return m_fp->read_word(address); +} + +u16 meg_base_device::offset_r(u16 address) const +{ + return m_offsets->read_word(address); +} + +u16 meg_base_device::lfo_r(u8 reg) const +{ + return m_lfo[reg]; +} + +u16 meg_base_device::map_r(u8 reg) const +{ + return m_map[reg]; +} + + +void meg_base_device::device_start() +{ + m_program = &space(AS_PROGRAM); + m_fp = &space(AS_FP); + m_offsets = &space(AS_OFFSETS); + + state_add(STATE_GENPC, "GENPC", m_pc).noshow(); + state_add(STATE_GENPCBASE, "CURPC", m_pc).noshow(); + state_add(0, "PC", m_pc); + + set_icountptr(m_icount); + + save_item(NAME(m_lfo)); + save_item(NAME(m_map)); + save_item(NAME(m_pc)); +} + +void meg_base_device::device_reset() +{ + memset(m_lfo, 0, sizeof(m_lfo)); + memset(m_map, 0, sizeof(m_map)); + m_pc = 0; +} + +uint32_t meg_base_device::execute_min_cycles() const +{ + return 1; +} + +uint32_t meg_base_device::execute_max_cycles() const +{ + return 1; +} + +uint32_t meg_base_device::execute_input_lines() const +{ + return 0; +} + +void meg_base_device::execute_run() +{ + if(machine().debug_flags & DEBUG_FLAG_ENABLED) + debugger_instruction_hook(m_pc); + m_icount = 0; +} + +device_memory_interface::space_config_vector meg_base_device::memory_space_config() const +{ + return space_config_vector { + std::make_pair(AS_PROGRAM, &m_program_config), + std::make_pair(AS_FP, &m_fp_config), + std::make_pair(AS_OFFSETS, &m_offsets_config) + }; +} + +void meg_base_device::state_import(const device_state_entry &entry) +{ +} + +void meg_base_device::state_export(const device_state_entry &entry) +{ +} + +void meg_base_device::state_string_export(const device_state_entry &entry, std::string &str) const +{ +} + +std::unique_ptr<util::disasm_interface> meg_base_device::create_disassembler() +{ + return std::make_unique<meg_disassembler>(this); +} + +meg_embedded_device::meg_embedded_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : + meg_base_device(mconfig, MEGEMB, tag, owner, clock, 384) +{ +} + +meg_device::meg_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : + meg_base_device(mconfig, MEG, tag, owner, clock, 256) +{ +} + + +// vl70: +// 6d1e: write 1, r0l +// 6d26: write 2, r0l +// 6d2e: read 2 +// 6d36: write 3, r0l +// 6d3e: write reg 4:r0h, r0l +// 6d52: write reg 5:r0h, r0l-1 +// 6d68: write 7, r0l +// 6d70: write reg 8:r0h, r0l +// 6d84: write reg 9:r0h, r0l +// 6dac: write a, r0l +// 6db4: write reg cd:r1l, r0 +// 6dd4: write reg e:r0h, r0l +// 6dee: write reg f:r0h, r0l +// 6e08: read 10,11 +// 6e1c: write reg 1213:r1l, r0 +// 6e3c: write reg 14:r0h, r0l +// 6e50: write 15, r0l +// 6e58: write reg 16:r0h, r0l +// 6e6c: write reg 17:r0h, r0l +// 6e80: write reg 18:e0h, e0l + +void meg_device::map(address_map &map) +{ + map(0x00, 0x00).w(FUNC(meg_device::select_w)); + map(0x01, 0x01).w(FUNC(meg_device::s1_w)); + map(0x02, 0x02).rw(FUNC(meg_device::s2_r), FUNC(meg_device::s2_w)); + map(0x03, 0x03).w(FUNC(meg_device::s3_w)); + map(0x04, 0x04).w(FUNC(meg_device::s4_w)); + map(0x05, 0x05).w(FUNC(meg_device::s5_w)); + map(0x07, 0x07).w(FUNC(meg_device::s7_w)); + map(0x08, 0x08).w(FUNC(meg_device::s8_w)); + map(0x09, 0x09).w(FUNC(meg_device::s9_w)); + map(0x0a, 0x0a).w(FUNC(meg_device::sa_w)); + map(0x0c, 0x0c).w(FUNC(meg_device::fph_w)); + map(0x0d, 0x0d).w(FUNC(meg_device::fpl_w)); + map(0x0e, 0x0e).w(FUNC(meg_device::se_w)); + map(0x0f, 0x0f).w(FUNC(meg_device::sf_w)); + map(0x10, 0x10).r(FUNC(meg_device::s10_r)); + map(0x11, 0x11).r(FUNC(meg_device::s11_r)); + map(0x12, 0x12).w(FUNC(meg_device::offseth_w)); + map(0x13, 0x13).w(FUNC(meg_device::offsetl_w)); + map(0x14, 0x14).w(FUNC(meg_device::s14_w)); + map(0x15, 0x15).w(FUNC(meg_device::s15_w)); + map(0x16, 0x16).w(FUNC(meg_device::s16_w)); + map(0x17, 0x17).w(FUNC(meg_device::s17_w)); + map(0x18, 0x18).w(FUNC(meg_device::s18_w)); +} + +u8 meg_device::s2_r() +{ + logerror("read r2 %s\n", machine().describe_context()); + return 0x00; +} + +void meg_device::select_w(u8 data) +{ + m_reg = data; +} + +void meg_device::s1_w(u8 data) +{ + logerror("r1 %02x %s\n", data, machine().describe_context()); +} + +void meg_device::s2_w(u8 data) +{ + logerror("r2 %02x %s\n", data, machine().describe_context()); +} + +void meg_device::s3_w(u8 data) +{ + logerror("r3 %02x %s\n", data, machine().describe_context()); +} + +void meg_device::s4_w(u8 data) +{ + if(m_r4[m_reg] != data) { + m_r4[m_reg] = data; + logerror("r4[%02x] = %02x %s\n", m_reg, data, machine().describe_context()); + } +} + +void meg_device::s5_w(u8 data) +{ + if(m_r5[m_reg] != data) { + m_r5[m_reg] = data; + logerror("r5[%02x] = %02x %s\n", m_reg, data, machine().describe_context()); + } +} + +void meg_device::s7_w(u8 data) +{ + logerror("r7 %02x %s\n", data, machine().describe_context()); +} + +void meg_device::s8_w(u8 data) +{ + if(m_r8[m_reg] != data) { + m_r8[m_reg] = data; + logerror("r8[%02x] = %02x %s\n", m_reg, data, machine().describe_context()); + } +} + + +void meg_device::s9_w(u8 data) +{ + if(m_r9[m_reg] != data) { + m_r9[m_reg] = data; + logerror("r9[%02x] = %02x %s\n", m_reg, data, machine().describe_context()); + } +} + +void meg_device::sa_w(u8 data) +{ + logerror("ra %02x %s\n", data, machine().describe_context()); +} + +void meg_device::fph_w(u8 data) +{ + fp_w(m_reg, (fp_r(m_reg) & 0x00ff) | (data << 8)); +} + + +void meg_device::fpl_w(u8 data) +{ + fp_w(m_reg, (fp_r(m_reg) & 0xff00) | data); +} + +void meg_device::se_w(u8 data) +{ + if(m_re[m_reg] != data) { + m_re[m_reg] = data; + logerror("re[%02x] = %02x %s\n", m_reg, data, machine().describe_context()); + } +} + + +void meg_device::sf_w(u8 data) +{ + if(m_rf[m_reg] != data) { + m_rf[m_reg] = data; + logerror("rf[%02x] = %02x %s\n", m_reg, data, machine().describe_context()); + } +} + +u8 meg_device::s10_r() +{ + logerror("read r10 %s\n", machine().describe_context()); + return 0x00; +} + +u8 meg_device::s11_r() +{ + logerror("read r11 %s\n", machine().describe_context()); + return 0x00; +} + +void meg_device::offseth_w(u8 data) +{ + offset_w(m_reg, (offset_r(m_reg) & 0x00ff) | (data << 8)); +} + +void meg_device::offsetl_w(u8 data) +{ + offset_w(m_reg, (offset_r(m_reg) & 0xff00) | data); +} + +void meg_device::s14_w(u8 data) +{ + if(m_r14[m_reg] != data) { + m_r14[m_reg] = data; + logerror("r14[%02x] = %02x %s\n", m_reg, data, machine().describe_context()); + } +} + +void meg_device::s15_w(u8 data) +{ + logerror("r15 %02x %s\n", data, machine().describe_context()); +} + +void meg_device::s16_w(u8 data) +{ + if(m_r16[m_reg] != data) { + m_r16[m_reg] = data; + logerror("r16[%02x] = %02x %s\n", m_reg, data, machine().describe_context()); + } +} + +void meg_device::s17_w(u8 data) +{ + if(m_r17[m_reg] != data) { + m_r17[m_reg] = data; + logerror("r17[%02x] = %02x %s\n", m_reg, data, machine().describe_context()); + } +} + +void meg_device::s18_w(u8 data) +{ + if(m_r18[m_reg] != data) { + m_r18[m_reg] = data; + logerror("r18[%02x] = %02x %s\n", m_reg, data, machine().describe_context()); + } +} diff --git a/src/devices/sound/meg.h b/src/devices/sound/meg.h new file mode 100644 index 00000000000..e9ff44f990a --- /dev/null +++ b/src/devices/sound/meg.h @@ -0,0 +1,122 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert + +// Yamaha MEG - Multiple effects generator +// +// Audio dsp dedicated to effects generation + +#ifndef DEVICES_SOUND_MEG_H +#define DEVICES_SOUND_MEG_H + +#pragma once + +#include "megd.h" + + +class meg_base_device : public cpu_device, public meg_disassembler::info +{ +public: + enum { + AS_FP = 1, + AS_OFFSETS = 2 + }; + + meg_base_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, u32 prg_size); + + void prg_w(u16 address, u64 opcode); + void fp_w(u16 address, u16 value); + void offset_w(u16 address, u16 value); + void lfo_w(u8 reg, u16 value); + void map_w(u8 reg, u16 value); + u64 prg_r(u16 address) const; + virtual u16 fp_r(u16 address) const override; + virtual u16 offset_r(u16 address) const override; + u16 lfo_r(u8 reg) const; + u16 map_r(u8 reg) const; + +protected: + virtual void device_start() override; + virtual void device_reset() override; + virtual uint32_t execute_min_cycles() const override; + virtual uint32_t execute_max_cycles() const override; + virtual uint32_t execute_input_lines() const override; + virtual void execute_run() override; + virtual space_config_vector memory_space_config() const override; + virtual void state_import(const device_state_entry &entry) override; + virtual void state_export(const device_state_entry &entry) override; + virtual void state_string_export(const device_state_entry &entry, std::string &str) const override; + virtual std::unique_ptr<util::disasm_interface> create_disassembler() override; + +private: + address_space_config m_program_config, m_fp_config, m_offsets_config; + address_space *m_program, *m_fp, *m_offsets; + + u32 m_prg_size, m_pc; + int m_icount; + + u16 m_lfo[0x18], m_map[8]; + + void prg_map(address_map &map); + void fp_map(address_map &map); + void offsets_map(address_map &map); +}; + +class meg_embedded_device : public meg_base_device +{ +public: + meg_embedded_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 44100*384); +}; + +class meg_device : public meg_base_device +{ +public: + meg_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 44100*256); + void map(address_map &map); + +private: + u8 m_r4[256]; + u8 m_r5[256]; + u8 m_r8[256]; + u8 m_r9[256]; + u8 m_re[256]; + u8 m_rf[256]; + u8 m_r12[256]; + u8 m_r13[256]; + u8 m_r14[256]; + u8 m_r16[256]; + u8 m_r17[256]; + u8 m_r18[256]; + u8 m_reg; + u8 s2_r(); + u8 s10_r(); + u8 s11_r(); + void select_w(u8 reg); + void s1_w(u8 data); + void s2_w(u8 data); + void s3_w(u8 data); + void s4_w(u8 data); + void s5_w(u8 data); + void s7_w(u8 data); + void s8_w(u8 data); + void s9_w(u8 data); + void sa_w(u8 data); + void fph_w(u8 data); + void fpl_w(u8 data); + void se_w(u8 data); + void sf_w(u8 data); + void s10_w(u8 data); + void s11_w(u8 data); + void offseth_w(u8 data); + void offsetl_w(u8 data); + void s14_w(u8 data); + void s15_w(u8 data); + void s16_w(u8 data); + void s17_w(u8 data); + void s18_w(u8 data); +}; + + +DECLARE_DEVICE_TYPE(MEG, meg_device) +DECLARE_DEVICE_TYPE(MEGEMB, meg_embedded_device) + +#endif diff --git a/src/devices/sound/megd.cpp b/src/devices/sound/megd.cpp new file mode 100644 index 00000000000..2790a7ca69c --- /dev/null +++ b/src/devices/sound/megd.cpp @@ -0,0 +1,118 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert + +// Yamaha MEG - Multiple effects generator +// +// Audio dsp dedicated to effects generation +// +// Disassembler + +#include "emu.h" +#include "megd.h" + +meg_disassembler::meg_disassembler(info *inf) : m_info(inf) +{ +} + +u32 meg_disassembler::opcode_alignment() const +{ + return 1; +} + +std::string meg_disassembler::gfp(offs_t address) const +{ + if(!m_info) + return util::string_format("fp%03x", address); + s16 fp = m_info->fp_r(address); + return util::string_format("%g", fp / 16384.0); +} + +std::string meg_disassembler::goffset(offs_t address) const +{ + return m_info ? util::string_format("%x", m_info->offset_r(address)) : util::string_format("of%02x", address); +} + +u32 meg_disassembler::b(u64 opc, u32 start, u32 count) +{ + return (opc >> start) & ((1 << count) - 1); +} + +void meg_disassembler::append(std::string &r, std::string e) +{ + if(r != "") + r += " ; "; + r += e; +} + +// 33333333 33333333 22222222 22222222 11111111 11111111 00000000 00000000 +// fedcba98 76543210 fedcba98 76543210 fedcba98 76543210 fedcba98 76543210 + +// 66665555 55555544 44444444 33333333 33222222 22221111 11111100 00000000 +// 32109876 54321098 76543210 98765432 10987654 32109876 54321098 76543210 +// XLB----- -rrrrrrr r--mmmmm m-MM---- -P-----* -----Arr rrrrrrmm mmmm---- + +// m = low is read port, high is write port, memory register +// r = low is read port, high is high port, rotating register + +// X = used for lo-fi variation only +// L = lfo read +// * = compute mul +// A = mul input = m or r +// P = P sent for register write +// B = register write to mbuf +// M = memory mode, none/read/write/read+1 + +offs_t meg_disassembler::disassemble(std::ostream &stream, offs_t pc, const data_buffer &opcodes, const data_buffer ¶ms) +{ + u64 opc = opcodes.r64(pc); + + std::string r; + + r = util::string_format("[m%02x]", b(opc, 39, 6)); + + if(b(opc, 62, 1)) + append(r, "lfo"); + + if(b(opc, 23, 1)) + switch(b(opc, 24, 2)) { + case 0: + if(b(opc, 18, 1)) + append(r, util::string_format("p += %s*m%02x", gfp(pc), b(opc, 4, 6))); + else + append(r, util::string_format("p += %s*r%02x", gfp(pc), b(opc, 10, 8))); + break; + case 1: + append(r, util::string_format("p = %s*(r%02x+m%02x)", gfp(pc), b(opc, 10, 8), b(opc, 4, 6))); + break; + case 2: + append(r, util::string_format("p ?= %s*(r%02x+m%02x)", gfp(pc), b(opc, 10, 8), b(opc, 4, 6))); + break; + case 3: + if(b(opc, 18, 1)) + append(r, util::string_format("p = %s*m%02x", gfp(pc), b(opc, 4, 6))); + else + append(r, util::string_format("p = %s*r%02x", gfp(pc), b(opc, 10, 8))); + break; + } + + if(b(opc, 30, 1)) { + if(b(opc, 61, 1)) + append(r, "mb = p"); + else if(b(opc, 46, 1) == 1) + append(r, util::string_format("m%02x = p", b(opc, 39, 6))); + else + append(r, util::string_format("r%02x = p", b(opc, 47, 8))); + } + + u32 memmode = b(opc, 36, 2); + if(memmode) { + static const char *modes[4] = { nullptr, "w", "r", "rw" }; + + append(r, util::string_format("mem_%s %x +%s", modes[memmode], b(opc, 33, 3), goffset(pc/3))); + r += util::string_format("-> m%02x", b(opcodes.r64(pc+2), 39, 6)); + } + + stream << r; + + return 1 | SUPPORTED; +} diff --git a/src/devices/sound/megd.h b/src/devices/sound/megd.h new file mode 100644 index 00000000000..59a13aa0ea4 --- /dev/null +++ b/src/devices/sound/megd.h @@ -0,0 +1,39 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert + +// Yamaha MEG - Multiple effects generator +// +// Audio dsp dedicated to effects generation +// +// Disassembler + +#ifndef DEVICES_SOUND_MEGD_H +#define DEVICES_SOUND_MEGD_H + +#pragma once + +class meg_disassembler : public util::disasm_interface +{ +public: + class info { + public: + virtual u16 fp_r(u16 address) const = 0; + virtual u16 offset_r(u16 address) const = 0; + }; + + meg_disassembler(info *inf = nullptr); + + virtual u32 opcode_alignment() const override; + virtual offs_t disassemble(std::ostream &stream, offs_t pc, const data_buffer &opcodes, const data_buffer ¶ms) override; + +private: + info *m_info; + + std::string gfp(offs_t address) const; + std::string goffset(offs_t address) const; + + static inline u32 b(u64 opc, u32 start, u32 count); + static inline void append(std::string &r, std::string e); +}; + +#endif diff --git a/src/devices/sound/namco_163.cpp b/src/devices/sound/namco_163.cpp new file mode 100644 index 00000000000..6fdde572537 --- /dev/null +++ b/src/devices/sound/namco_163.cpp @@ -0,0 +1,176 @@ +// license:BSD-3-Clause +// copyright-holders:cam900 +/*************************************************************************** + + Namco 163 internal sound emulation by cam900 + 4 bit wavetable (variable length), 1 ~ 8 channel + Reference : https://wiki.nesdev.com/w/index.php/Namco_163_audio + +***************************************************************************/ + +#include "emu.h" +#include "namco_163.h" + + +DEFINE_DEVICE_TYPE(NAMCO_163, namco_163_sound_device, "namco_163_sound", "Namco 163 (Sound)") + +namco_163_sound_device::namco_163_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) + : device_t(mconfig, NAMCO_163, tag, owner, clock) + , device_sound_interface(mconfig, *this) + , m_ram(nullptr) + , m_reg_addr(0x78) + , m_addr(0) + , m_inc(false) + , m_disable(false) + , m_stream(nullptr) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void namco_163_sound_device::device_start() +{ + m_ram = make_unique_clear<u8[]>(0x80); + m_stream = machine().sound().stream_alloc(*this, 0, 1, clock() / 15); + + save_pointer(NAME(m_ram), 0x80); + save_item(NAME(m_reg_addr)); + save_item(NAME(m_addr)); + save_item(NAME(m_inc)); + save_item(NAME(m_disable)); +} + + +//------------------------------------------------- +// device_clock_changed - called if the clock +// changes +//------------------------------------------------- + +void namco_163_sound_device::device_clock_changed() +{ + m_stream->set_sample_rate(clock() / 15); +} + + +inline s8 namco_163_sound_device::get_sample(u16 addr) +{ + return ((m_ram[(addr >> 1) & 0x7f] >> ((addr & 1) << 2)) & 0xf) - 8; +} + + +WRITE_LINE_MEMBER(namco_163_sound_device::disable_w) +{ + m_disable = state; +} + + +/********************************************************************************/ + +/* + Register Map (in RAM) + + 40 ffff ffff Channel 0 Frequency bits 0 - 7 + 41 pppp pppp Channel 0 Phase bits 0 - 7 + 42 ffff ffff Channel 0 Frequency bits 8 - 15 + 43 pppp pppp Channel 0 Phase bits 8 - 15 + 44 ---- --ff Channel 0 Frequency bits 16 - 17 + llll ll-- Channel 0 Waveform Length (256 - (l * 4)) 4 bit samples + 45 pppp pppp Channel 0 Phase bits 16 - 23 + 46 oooo oooo Channel 0 Waveform Offset at 4 bit samples + 47 ---- cccc Channel 0 Volume + + 48 ffff ffff Channel 1 Frequency bits 0 - 7 + 49 pppp pppp Channel 1 Phase bits 0 - 7 + 4a ffff ffff Channel 1 Frequency bits 8 - 15 + 4b pppp pppp Channel 1 Phase bits 8 - 15 + 4c ---- --ff Channel 1 Frequency bits 16 - 17 + llll ll-- Channel 1 Waveform Length (256 - (l * 4)) 4 bit samples + 4d pppp pppp Channel 1 Phase bits 16 - 23 + 4e oooo oooo Channel 1 Waveform Offset at 4 bit samples + 4f ---- cccc Channel 1 Volume + + . + . + . + + 78 ffff ffff Channel 7 Frequency bits 0 - 7 + 79 pppp pppp Channel 7 Phase bits 0 - 7 + 7a ffff ffff Channel 7 Frequency bits 8 - 15 + 7b pppp pppp Channel 7 Phase bits 8 - 15 + 7c ---- --ff Channel 7 Frequency bits 16 - 17 + llll ll-- Channel 7 Waveform Length (256 - (l * 4)) 4 bit samples + 7d pppp pppp Channel 7 Phase bits 16 - 23 + 7e oooo oooo Channel 7 Waveform Offset at 4 bit samples + 7f ---- cccc Channel 7 Volume + -ccc ---- Enable channels + -000 ---- Enable channel 7 only + -001 ---- Enable channel 7, 6 + -010 ---- Enable channel 7, 6, 5 + + . + . + . + + -111 ---- Enable all channels +*/ + +void namco_163_sound_device::addr_w(u8 data) +{ + m_inc = data & 0x80; + m_addr = data & 0x7f; +} + + +void namco_163_sound_device::data_w(u8 data) +{ + m_stream->update(); + m_ram[m_addr] = data; + if (m_inc) + m_addr = (m_addr + 1) & 0x7f; +} + + +u8 namco_163_sound_device::data_r() +{ + u8 val = m_ram[m_addr]; + if (m_inc) + m_addr = (m_addr + 1) & 0x7f; + + return val; +} + + +void namco_163_sound_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + std::fill_n(&outputs[0][0], samples, 0); + + if (m_disable) + return; + + // Slightly noisy but closer to real hardware behavior + for (int s = 0; s < samples; s++) + { + u32 phase = (m_ram[m_reg_addr + 5] << 16) | (m_ram[m_reg_addr + 3] << 8) | m_ram[m_reg_addr + 1]; + const u32 freq = ((m_ram[m_reg_addr + 4] & 0x3) << 16) | (m_ram[m_reg_addr + 2] << 8) | m_ram[m_reg_addr + 0]; + const u16 length = 256 - (m_ram[m_reg_addr + 4] & 0xfc); + const u16 offset = m_ram[m_reg_addr + 6]; + const u8 vol = m_ram[m_reg_addr + 7] & 0xf; + + phase = (phase + freq) % (length << 16); + s32 output = get_sample((phase >> 16) + offset) * vol; + + m_ram[m_reg_addr + 1] = phase & 0xff; + m_ram[m_reg_addr + 3] = phase >> 8; + m_ram[m_reg_addr + 5] = phase >> 16; + + m_reg_addr += 8; + if (m_reg_addr >= 0x80) + { + m_reg_addr = 0x78 - ((m_ram[0x7f] & 0x70) >> 1); + } + outputs[0][s] = (output << 8); + } +} diff --git a/src/devices/sound/namco_163.h b/src/devices/sound/namco_163.h new file mode 100644 index 00000000000..1256884242b --- /dev/null +++ b/src/devices/sound/namco_163.h @@ -0,0 +1,42 @@ +// license:BSD-3-Clause +// copyright-holders:cam900 +#ifndef MAME_SOUND_NAMCO_163_H +#define MAME_SOUND_NAMCO_163_H + +#pragma once + + +class namco_163_sound_device : public device_t, + public device_sound_interface +{ +public: + namco_163_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); + + DECLARE_WRITE_LINE_MEMBER(disable_w); + + void addr_w(u8 data); + void data_w(u8 data); + u8 data_r(); + +protected: + // device-level overrides + virtual void device_start() override; + virtual void device_clock_changed() override; + + // global sound parameters + std::unique_ptr<u8[]> m_ram; + u8 m_reg_addr; + u8 m_addr; + bool m_inc; + bool m_disable; + sound_stream *m_stream; + + // internals + inline s8 get_sample(u16 addr); + + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) override; +}; + +DECLARE_DEVICE_TYPE(NAMCO_163, namco_163_sound_device) + +#endif // MAME_SOUND_NAMCO_163_H diff --git a/src/devices/sound/swp30.cpp b/src/devices/sound/swp30.cpp index 56870df5ec7..f43df8084f9 100644 --- a/src/devices/sound/swp30.cpp +++ b/src/devices/sound/swp30.cpp @@ -150,8 +150,15 @@ DEFINE_DEVICE_TYPE(SWP30, swp30_device, "swp30", "Yamaha SWP30 sound chip") swp30_device::swp30_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : device_t(mconfig, SWP30, tag, owner, clock), device_sound_interface(mconfig, *this), - device_rom_interface(mconfig, *this, 25+2, ENDIANNESS_LITTLE, 32) + device_rom_interface(mconfig, *this, 25+2, ENDIANNESS_LITTLE, 32), + m_meg(*this, "meg") { + (void)m_map; +} + +void swp30_device::device_add_mconfig(machine_config &config) +{ + MEGEMB(config, m_meg); } void swp30_device::device_start() @@ -160,7 +167,7 @@ void swp30_device::device_start() // Attenuantion for panning is 4.4 floating point. That means 0 // to -96.3dB. Since it's a nice range, we assume it's the same - // for other attenuation values. Computed value is is 1.16 + // for other attenuation values. Computed value is 1.16 // format, to avoid overflow for(int i=0; i<256; i++) @@ -328,8 +335,8 @@ void swp30_device::map(address_map &map) rchan(map, 0x27).rw(FUNC(swp30_device::prg_fp_r<3>), FUNC(swp30_device::prg_fp_w<3>)); rchan(map, 0x29).rw(FUNC(swp30_device::prg_fp_r<4>), FUNC(swp30_device::prg_fp_w<4>)); rchan(map, 0x2b).rw(FUNC(swp30_device::prg_fp_r<5>), FUNC(swp30_device::prg_fp_w<5>)); - rchan(map, 0x30).rw(FUNC(swp30_device::prg_int_r<0>), FUNC(swp30_device::prg_int_w<0>)); - rchan(map, 0x31).rw(FUNC(swp30_device::prg_int_r<1>), FUNC(swp30_device::prg_int_w<1>)); + rchan(map, 0x30).rw(FUNC(swp30_device::prg_off_r<0>), FUNC(swp30_device::prg_off_w<0>)); + rchan(map, 0x31).rw(FUNC(swp30_device::prg_off_r<1>), FUNC(swp30_device::prg_off_w<1>)); rchan(map, 0x3e).rw(FUNC(swp30_device::prg_lfo_r<0>), FUNC(swp30_device::prg_lfo_w<0>)); rchan(map, 0x3f).rw(FUNC(swp30_device::prg_lfo_r<1>), FUNC(swp30_device::prg_lfo_w<1>)); } @@ -381,14 +388,14 @@ void swp30_device::prg_address_w(u16 data) template<int sel> u16 swp30_device::prg_r() { constexpr offs_t shift = 48-16*sel; - return m_program[m_program_address] >> shift; + return m_meg->prg_r(m_program_address) >> shift; } template<int sel> void swp30_device::prg_w(u16 data) { constexpr offs_t shift = 48-16*sel; constexpr u64 mask = ~(u64(0xffff) << shift); - m_program[m_program_address] = (m_program[m_program_address] & mask) | (u64(data) << shift); + m_meg->prg_w(m_program_address, (m_meg->prg_r(m_program_address) & mask) | (u64(data) << shift)); if(sel == 3) { if(0) @@ -402,14 +409,12 @@ template<int sel> void swp30_device::prg_w(u16 data) template<int sel> u16 swp30_device::map_r() { - return m_map[sel]; + return m_meg->map_r(sel); } template<int sel> void swp30_device::map_w(u16 data) { - m_map[sel] = data; - if(0) - logerror("map %d: type=%02x offset=%05x size=%05x\n", sel, data >> 11, (data & 0xff) << 10, 0x400 << ((data >> 8) & 7)); + m_meg->map_w(sel, data); } @@ -656,54 +661,36 @@ void swp30_device::address_l_w(offs_t offset, u16 data) } -// MEG registers (Multiple Effects Generator) +// MEG registers forwarding template<int sel> u16 swp30_device::prg_fp_r(offs_t offset) { - offs_t adr = (offset >> 6)*6 + sel; - return m_program_pfp[adr]; + return m_meg->fp_r((offset >> 6)*6 + sel); } template<int sel> void swp30_device::prg_fp_w(offs_t offset, u16 data) { - offs_t adr = (offset >> 6)*6 + sel; - m_program_pfp[adr] = data; - if(0) - logerror("prg_fp_w %03x, %04x\n", adr, data); + m_meg->fp_w((offset >> 6)*6 + sel, data); } -template<int sel> u16 swp30_device::prg_int_r(offs_t offset) +template<int sel> u16 swp30_device::prg_off_r(offs_t offset) { - offs_t adr = (offset >> 6)*2 + sel; - return m_program_pint[adr]; + return m_meg->offset_r((offset >> 6)*2 + sel); } -template<int sel> void swp30_device::prg_int_w(offs_t offset, u16 data) +template<int sel> void swp30_device::prg_off_w(offs_t offset, u16 data) { - offs_t adr = (offset >> 6)*2 + sel; - m_program_pint[adr] = data; - if(0) - logerror("prg_int_w %02x, %04x\n", adr, data); + m_meg->offset_w((offset >> 6)*2 + sel, data); } template<int sel> u16 swp30_device::prg_lfo_r(offs_t offset) { - offs_t adr = (offset >> 6)*2 + sel; - return m_program_plfo[adr]; + return m_meg->lfo_r((offset >> 6)*2 + sel); } template<int sel> void swp30_device::prg_lfo_w(offs_t offset, u16 data) { - offs_t adr = (offset >> 6)*2 + sel; - m_program_plfo[adr] = data; - - static const int dt[8] = { 0, 32, 64, 128, 256, 512, 1024, 2048 }; - static const int sh[8] = { 0, 0, 1, 2, 3, 4, 5, 6 }; - - int scale = (data >> 5) & 7; - int step = ((data & 31) << sh[scale]) + dt[scale]; - if(0) - logerror("prg_lfo_w %02x freq=%5.2f phase=%6.4f\n", adr, step * 44100.0/4194304, (data >> 8)/256.0); + m_meg->lfo_w((offset >> 6)*2 + sel, data); } diff --git a/src/devices/sound/swp30.h b/src/devices/sound/swp30.h index 56e24b453f0..dd95a8dd85f 100644 --- a/src/devices/sound/swp30.h +++ b/src/devices/sound/swp30.h @@ -8,6 +8,8 @@ #pragma once +#include "meg.h" + class swp30_device : public device_t, public device_sound_interface, public device_rom_interface { public: @@ -20,8 +22,11 @@ protected: virtual void device_reset() override; virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) override; virtual void rom_bank_updated() override; + virtual void device_add_mconfig(machine_config &config) override; private: + required_device<meg_embedded_device> m_meg; + sound_stream *m_stream; s32 m_sample_increment[0x4000]; @@ -99,8 +104,8 @@ private: // MEG registers template<int sel> u16 prg_fp_r(offs_t offset); template<int sel> void prg_fp_w(offs_t offset, u16 data); - template<int sel> u16 prg_int_r(offs_t offset); - template<int sel> void prg_int_w(offs_t offset, u16 data); + template<int sel> u16 prg_off_r(offs_t offset); + template<int sel> void prg_off_w(offs_t offset, u16 data); template<int sel> u16 prg_lfo_r(offs_t offset); template<int sel> void prg_lfo_w(offs_t offset, u16 data); diff --git a/src/devices/sound/vrc6.cpp b/src/devices/sound/vrc6.cpp index 29729fc9fcc..b769fde4043 100644 --- a/src/devices/sound/vrc6.cpp +++ b/src/devices/sound/vrc6.cpp @@ -2,7 +2,7 @@ // copyright-holders:R. Belmont /*************************************************************************** - vrc6.c + vrc6.cpp Konami VRC6 additional sound channels Emulation by R. Belmont @@ -16,8 +16,6 @@ #include "emu.h" #include "vrc6.h" -#define DISABLE_VRC6_SOUND // not ready yet - // device type definition DEFINE_DEVICE_TYPE(VRC6, vrc6snd_device, "vrc6snd", "Konami VRC6 (Sound)") @@ -29,10 +27,10 @@ DEFINE_DEVICE_TYPE(VRC6, vrc6snd_device, "vrc6snd", "Konami VRC6 (Sound)") // vrc6snd_device - constructor //------------------------------------------------- -vrc6snd_device::vrc6snd_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) +vrc6snd_device::vrc6snd_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) : device_t(mconfig, VRC6, tag, owner, clock) , device_sound_interface(mconfig, *this) - , m_freqctrl(0), m_pulsectrl{ 0, 0 }, m_sawrate(0) + , m_freqctrl(0), m_pulsectrl{ 0, 0 }, m_sawrate(0), m_master_freq(0) , m_pulsefrql{ 0, 0 }, m_pulsefrqh{ 0, 0 }, m_pulseduty{ 0, 0 } , m_sawfrql(0), m_sawfrqh(0), m_sawclock(0), m_sawaccum(0) , m_ticks{ 0, 0, 0 } @@ -55,10 +53,12 @@ void vrc6snd_device::device_start() m_ticks[0] = m_ticks[1] = m_ticks[2] = 0; m_output[0] = m_output[1] = m_output[2] = 0; m_pulseduty[0] = m_pulseduty[1] = 15; + m_master_freq = 0; save_item(NAME(m_freqctrl)); save_item(NAME(m_pulsectrl)); save_item(NAME(m_sawrate)); + save_item(NAME(m_master_freq)); save_item(NAME(m_sawaccum)); save_item(NAME(m_pulsefrql)); save_item(NAME(m_pulsefrqh)); @@ -85,6 +85,7 @@ void vrc6snd_device::device_reset() m_output[0] = m_output[1] = m_output[2] = 0; m_pulseduty[0] = m_pulseduty[1] = 15; m_pulsefrqh[0] = m_pulsefrqh[1] = m_sawfrqh = 0; + m_master_freq = 0; } //------------------------------------------------- @@ -94,27 +95,22 @@ void vrc6snd_device::device_reset() void vrc6snd_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) { - stream_sample_t *out = outputs[0]; - int16_t tmp; - int i; + std::fill_n(&outputs[0][0], samples, 0); // check global halt bit if (m_freqctrl & 1) - { return; - } - for (i = 0; i < samples; i++) + for (int i = 0; i < samples; i++) { // update pulse1 if (m_pulsefrqh[0] & 0x80) { - m_ticks[0]--; if (m_ticks[0] == 0) { - m_ticks[0] = m_pulsefrql[0] | (m_pulsefrqh[0] & 0xf)<<4; + m_ticks[0] = (m_pulsefrql[0] | ((m_pulsefrqh[0] & 0xf) << 8)) >> m_master_freq; - m_pulseduty[0]--; + m_pulseduty[0] = (m_pulseduty[0] - 1) & 0xf; if (m_pulsectrl[0] & 0x80) { m_output[0] = m_pulsectrl[0] & 0xf; @@ -130,12 +126,9 @@ void vrc6snd_device::sound_stream_update(sound_stream &stream, stream_sample_t * m_output[0] = 0; } } - - if (m_pulseduty[0] == 0) - { - m_pulseduty[0] = 15; - } } + else + m_ticks[0]--; } else { @@ -145,12 +138,11 @@ void vrc6snd_device::sound_stream_update(sound_stream &stream, stream_sample_t * // update pulse2 if (m_pulsefrqh[1] & 0x80) { - m_ticks[1]--; if (m_ticks[1] == 0) { - m_ticks[1] = m_pulsefrql[1] | (m_pulsefrqh[1] & 0xf)<<4; + m_ticks[1] = (m_pulsefrql[1] | ((m_pulsefrqh[1] & 0xf) << 8)) >> m_master_freq; - m_pulseduty[1]--; + m_pulseduty[1] = (m_pulseduty[1] - 1) & 0xf; if (m_pulsectrl[1] & 0x80) { m_output[1] = m_pulsectrl[1] & 0xf; @@ -166,12 +158,9 @@ void vrc6snd_device::sound_stream_update(sound_stream &stream, stream_sample_t * m_output[1] = 0; } } - - if (m_pulseduty[1] == 0) - { - m_pulseduty[1] = 15; - } } + else + m_ticks[1]--; } else { @@ -181,10 +170,9 @@ void vrc6snd_device::sound_stream_update(sound_stream &stream, stream_sample_t * // update saw if (m_sawfrqh & 0x80) { - m_ticks[2]--; if (m_ticks[2] == 0) { - m_ticks[2] = m_sawfrql | (m_sawfrqh & 0xf)<<4; + m_ticks[2] = (m_sawfrql | ((m_sawfrqh & 0xf) << 8)) >> m_master_freq; // only update on even steps if ((m_sawclock > 0) && (!(m_sawclock & 1))) @@ -200,6 +188,8 @@ void vrc6snd_device::sound_stream_update(sound_stream &stream, stream_sample_t * m_output[2] = 0; } } + else + m_ticks[2]--; } else { @@ -207,10 +197,10 @@ void vrc6snd_device::sound_stream_update(sound_stream &stream, stream_sample_t * } // sum 2 4-bit pulses, 1 5-bit saw = unsigned 6 bit output - tmp = (int16_t)(uint8_t)(m_output[0] + m_output[1] + m_output[2]); + s16 tmp = (s16)(u8)(m_output[0] + m_output[1] + m_output[2]); tmp <<= 8; - out[i] = tmp; + outputs[0][i] = tmp; } } @@ -218,7 +208,7 @@ void vrc6snd_device::sound_stream_update(sound_stream &stream, stream_sample_t * // write - write to the chip's registers //--------------------------------------- -void vrc6snd_device::write(offs_t offset, uint8_t data) +void vrc6snd_device::write(offs_t offset, u8 data) { switch (offset >> 8) { @@ -232,28 +222,43 @@ void vrc6snd_device::write(offs_t offset, uint8_t data) case 1: m_pulsefrql[0] = data; - if (!(m_pulsefrqh[1] & 0x80)) + if (!(m_pulsefrqh[0] & 0x80)) { - m_ticks[0] &= ~0xff; - m_ticks[0] |= m_pulsefrql[0]; + m_ticks[0] = (m_pulsefrql[0] | ((m_pulsefrqh[0] & 0xf) << 8)) >> m_master_freq; } break; case 2: - #ifndef DISABLE_VRC6_SOUND m_pulsefrqh[0] = data; // if disabling channel, reset phase if (!(data & 0x80)) { m_pulseduty[0] = 15; - m_ticks[0] &= 0xff; - m_ticks[0] |= (m_pulsefrqh[0] & 0xf)<<4; + m_ticks[0] = (m_pulsefrql[0] | ((m_pulsefrqh[0] & 0xf) << 8)) >> m_master_freq; } - #endif break; case 3: m_freqctrl = data; + if (m_freqctrl & 4) + m_master_freq = 0x8; + else if (m_freqctrl & 2) + m_master_freq = 0x4; + else + m_master_freq = 0; + + if (!(m_pulsefrqh[0] & 0x80)) + { + m_ticks[0] = (m_pulsefrql[0] | ((m_pulsefrqh[0] & 0xf) << 8)) >> m_master_freq; + } + if (!(m_pulsefrqh[1] & 0x80)) + { + m_ticks[1] = (m_pulsefrql[1] | ((m_pulsefrqh[1] & 0xf) << 8)) >> m_master_freq; + } + if (!(m_sawfrqh & 0x80)) + { + m_ticks[2] = (m_sawfrql | ((m_sawfrqh & 0xf) << 8)) >> m_master_freq; + } break; } break; @@ -270,22 +275,18 @@ void vrc6snd_device::write(offs_t offset, uint8_t data) m_pulsefrql[1] = data; if (!(m_pulsefrqh[1] & 0x80)) { - m_ticks[1] &= ~0xff; - m_ticks[1] |= m_pulsefrql[1]; + m_ticks[1] = (m_pulsefrql[1] | ((m_pulsefrqh[1] & 0xf) << 8)) >> m_master_freq; } break; case 2: - #ifndef DISABLE_VRC6_SOUND m_pulsefrqh[1] = data; // if disabling channel, reset phase if (!(data & 0x80)) { m_pulseduty[1] = 15; - m_ticks[1] &= 0xff; - m_ticks[1] |= (m_pulsefrqh[1] & 0xf)<<4; + m_ticks[1] = (m_pulsefrql[1] | ((m_pulsefrqh[1] & 0xf) << 8)) >> m_master_freq; } - #endif break; } break; @@ -302,22 +303,18 @@ void vrc6snd_device::write(offs_t offset, uint8_t data) m_sawfrql = data; if (!(m_sawfrqh & 0x80)) { - m_ticks[2] &= ~0xff; - m_ticks[2] |= m_sawfrql; + m_ticks[2] = (m_sawfrql | ((m_sawfrqh & 0xf) << 8)) >> m_master_freq; } break; case 2: - #ifndef DISABLE_VRC6_SOUND m_sawfrqh = data; // if disabling channel, reset phase if (!(data & 0x80)) { m_sawaccum = 0; - m_ticks[2] &= 0xff; - m_ticks[2] |= (m_sawfrqh & 0xf)<<4; + m_ticks[2] = (m_sawfrql | ((m_sawfrqh & 0xf) << 8)) >> m_master_freq; } - #endif break; } break; diff --git a/src/devices/sound/vrc6.h b/src/devices/sound/vrc6.h index a24d34a90c4..f1ea8f5c9e3 100644 --- a/src/devices/sound/vrc6.h +++ b/src/devices/sound/vrc6.h @@ -22,9 +22,9 @@ class vrc6snd_device : public device_t, public device_sound_interface { public: // construction/destruction - vrc6snd_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + vrc6snd_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); - void write(offs_t offset, uint8_t data); + void write(offs_t offset, u8 data); protected: // device-level overrides @@ -34,11 +34,11 @@ protected: virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) override; private: - uint8_t m_freqctrl, m_pulsectrl[2], m_sawrate; - uint8_t m_pulsefrql[2], m_pulsefrqh[2], m_pulseduty[2]; - uint8_t m_sawfrql, m_sawfrqh, m_sawclock, m_sawaccum; - uint16_t m_ticks[3]; - uint8_t m_output[3]; + u8 m_freqctrl, m_pulsectrl[2], m_sawrate, m_master_freq; + u8 m_pulsefrql[2], m_pulsefrqh[2], m_pulseduty[2]; + u8 m_sawfrql, m_sawfrqh, m_sawclock, m_sawaccum; + u16 m_ticks[3]; + u8 m_output[3]; sound_stream *m_stream; }; diff --git a/src/devices/sound/ym2413.cpp b/src/devices/sound/ym2413.cpp index 3935b1baa0e..755e66ea629 100644 --- a/src/devices/sound/ym2413.cpp +++ b/src/devices/sound/ym2413.cpp @@ -42,6 +42,8 @@ to do: #include "emu.h" #include "ym2413.h" +#include <algorithm> + #define FREQ_SH 16 /* 16.16 fixed point (frequency calculations) */ #define EG_SH 16 /* 16.16 fixed point (EG timing) */ #define LFO_SH 24 /* 8.24 fixed point (LFO calculations) */ @@ -131,7 +133,7 @@ const uint32_t ym2413_device::sl_tab[16] = { }; #undef SC -const unsigned char ym2413_device::eg_inc[15*RATE_STEPS] = { +const uint8_t ym2413_device::eg_inc[15*RATE_STEPS] = { /*cycle:0 1 2 3 4 5 6 7*/ /* 0 */ 0,1, 0,1, 0,1, 0,1, /* rates 00..12 0 (increment by 0 or 1) */ @@ -158,7 +160,7 @@ const unsigned char ym2413_device::eg_inc[15*RATE_STEPS] = { #define O(a) (a*RATE_STEPS) /*note that there is no O(13) in this table - it's directly in the code */ -const unsigned char ym2413_device::eg_rate_select[16+64+16] = { /* Envelope Generator rates (16 + 64 rates + 16 RKS) */ +const uint8_t ym2413_device::eg_rate_select[16+64+16] = { /* Envelope Generator rates (16 + 64 rates + 16 RKS) */ /* 16 infinite time rates */ O(14),O(14),O(14),O(14),O(14),O(14),O(14),O(14), O(14),O(14),O(14),O(14),O(14),O(14),O(14),O(14), @@ -199,7 +201,7 @@ const unsigned char ym2413_device::eg_rate_select[16+64+16] = { /* Envelope Ge /*mask 8191, 4095, 2047, 1023, 511, 255, 127, 63, 31, 15, 7, 3, 1, 0, 0, 0 */ #define O(a) (a*1) -const unsigned char ym2413_device::eg_rate_shift[16+64+16] = { /* Envelope Generator counter shifts (16 + 64 rates + 16 RKS) */ +const uint8_t ym2413_device::eg_rate_shift[16+64+16] = { /* Envelope Generator counter shifts (16 + 64 rates + 16 RKS) */ /* 16 infinite time rates */ O(0),O(0),O(0),O(0),O(0),O(0),O(0),O(0), O(0),O(0),O(0),O(0),O(0),O(0),O(0),O(0), @@ -350,9 +352,10 @@ const int8_t ym2413_device::lfo_pm_table[8*8] = { - waveform DC and DM select are 100% correct */ -const unsigned char ym2413_device::table[19][8] = { +const uint8_t ym2413_device::table[19][8] = { /* MULT MULT modTL DcDmFb AR/DR AR/DR SL/RR SL/RR */ /* 0 1 2 3 4 5 6 7 */ +/* These YM2413(OPLL) patch dumps are done via audio analysis (and a/b testing?) from Jarek and are known to be inaccurate */ {0x49, 0x4c, 0x4c, 0x12, 0x00, 0x00, 0x00, 0x00 }, //0 {0x61, 0x61, 0x1e, 0x17, 0xf0, 0x78, 0x00, 0x17 }, //1 @@ -385,9 +388,45 @@ const unsigned char ym2413_device::table[19][8] = { /* drum instruments definitions */ /* MULTI MULTI modTL xxx AR/DR AR/DR SL/RR SL/RR */ /* 0 1 2 3 4 5 6 7 */ - {0x01, 0x01, 0x16, 0x00, 0xfd, 0xf8, 0x2f, 0x6d },/* BD(multi verified, modTL verified, mod env - verified(close), carr. env verifed) */ - {0x01, 0x01, 0x00, 0x00, 0xd8, 0xd8, 0xf9, 0xf8 },/* HH(multi verified), SD(multi not used) */ - {0x05, 0x01, 0x00, 0x00, 0xf8, 0xba, 0x49, 0x55 },/* TOM(multi,env verified), TOP CYM(multi verified, env verified) */ +/* old dumps via audio analysis (and a/b testing?) from Jarek */ +//{0x01, 0x01, 0x16, 0x00, 0xfd, 0xf8, 0x2f, 0x6d },/* BD(multi verified, modTL verified, mod env - verified(close), carr. env verifed) */ +//{0x01, 0x01, 0x00, 0x00, 0xd8, 0xd8, 0xf9, 0xf8 },/* HH(multi verified), SD(multi not used) */ +//{0x05, 0x01, 0x00, 0x00, 0xf8, 0xba, 0x49, 0x55 },/* TOM(multi,env verified), TOP CYM(multi verified, env verified) */ +/* Drums dumped from the VRC7 using debug mode, these are likely also correct for ym2413(OPLL) but need verification */ + {0x01, 0x01, 0x18, 0x0f, 0xdf, 0xf8, 0x6a, 0x6d },/* BD */ + {0x01, 0x01, 0x00, 0x00, 0xc8, 0xd8, 0xa7, 0x68 },/* HH, SD */ + {0x05, 0x01, 0x00, 0x00, 0xf8, 0xaa, 0x59, 0x55 },/* TOM, TOP CYM */ +}; + +// VRC7 Instruments : Dumped from internal ROM +// reference : https://siliconpr0n.org/archive/doku.php?id=vendor:yamaha:opl2 +const uint8_t vrc7snd_device::vrc7_table[19][8] = { +/* MULT MULT modTL DcDmFb AR/DR AR/DR SL/RR SL/RR */ +/* 0 1 2 3 4 5 6 7 */ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, //0 (This is the user-defined instrument, should this default to anything?) + + {0x03, 0x21, 0x05, 0x06, 0xe8, 0x81, 0x42, 0x27 }, //1 + {0x13, 0x41, 0x14, 0x0d, 0xd8, 0xf6, 0x23, 0x12 }, //2 + {0x11, 0x11, 0x08, 0x08, 0xfa, 0xb2, 0x20, 0x12 }, //3 + {0x31, 0x61, 0x0c, 0x07, 0xa8, 0x64, 0x61, 0x27 }, //4 + {0x32, 0x21, 0x1e, 0x06, 0xe1, 0x76, 0x01, 0x28 }, //5 + {0x02, 0x01, 0x06, 0x00, 0xa3, 0xe2, 0xf4, 0xf4 }, //6 + {0x21, 0x61, 0x1d, 0x07, 0x82, 0x81, 0x11, 0x07 }, //7 + {0x23, 0x21, 0x22, 0x17, 0xa2, 0x72, 0x01, 0x17 }, //8 + {0x35, 0x11, 0x25, 0x00, 0x40, 0x73, 0x72, 0x01 }, //9 + {0xb5, 0x01, 0x0f, 0x0f, 0xa8, 0xa5, 0x51, 0x02 }, //A + {0x17, 0xc1, 0x24, 0x07, 0xf8, 0xf8, 0x22, 0x12 }, //B + {0x71, 0x23, 0x11, 0x06, 0x65, 0x74, 0x18, 0x16 }, //C + {0x01, 0x02, 0xd3, 0x05, 0xc9, 0x95, 0x03, 0x02 }, //D + {0x61, 0x63, 0x0c, 0x00, 0x94, 0xc0, 0x33, 0xf6 }, //E + {0x21, 0x72, 0x0d, 0x00, 0xc1, 0xd5, 0x56, 0x06 }, //F + +/* Drums (silent due to no RO output pin(?) on VRC7, but present internally; these are probably shared with YM2413) */ +/* MULTI MULTI modTL xxx AR/DR AR/DR SL/RR SL/RR */ +/* 0 1 2 3 4 5 6 7 */ + {0x01, 0x01, 0x18, 0x0f, 0xdf, 0xf8, 0x6a, 0x6d },/* BD */ + {0x01, 0x01, 0x00, 0x00, 0xc8, 0xd8, 0xa7, 0x68 },/* HH, SD */ + {0x05, 0x01, 0x00, 0x00, 0xf8, 0xaa, 0x59, 0x55 },/* TOM, TOP CYM */ }; /* work table */ @@ -823,21 +862,21 @@ void ym2413_device::rhythm_calc( OPLL_CH *CH, unsigned int noise ) */ /* base frequency derived from operator 1 in channel 7 */ - unsigned char bit7 = ((SLOT7_1->phase>>FREQ_SH)>>7)&1; - unsigned char bit3 = ((SLOT7_1->phase>>FREQ_SH)>>3)&1; - unsigned char bit2 = ((SLOT7_1->phase>>FREQ_SH)>>2)&1; + uint8_t bit7 = ((SLOT7_1->phase>>FREQ_SH)>>7)&1; + uint8_t bit3 = ((SLOT7_1->phase>>FREQ_SH)>>3)&1; + uint8_t bit2 = ((SLOT7_1->phase>>FREQ_SH)>>2)&1; - unsigned char res1 = (bit2 ^ bit7) | bit3; + uint8_t res1 = (bit2 ^ bit7) | bit3; /* when res1 = 0 phase = 0x000 | 0xd0; */ /* when res1 = 1 phase = 0x200 | (0xd0>>2); */ uint32_t phase = res1 ? (0x200|(0xd0>>2)) : 0xd0; /* enable gate based on frequency of operator 2 in channel 8 */ - unsigned char bit5e= ((SLOT8_2->phase>>FREQ_SH)>>5)&1; - unsigned char bit3e= ((SLOT8_2->phase>>FREQ_SH)>>3)&1; + uint8_t bit5e= ((SLOT8_2->phase>>FREQ_SH)>>5)&1; + uint8_t bit3e= ((SLOT8_2->phase>>FREQ_SH)>>3)&1; - unsigned char res2 = (bit3e | bit5e); + uint8_t res2 = (bit3e | bit5e); /* when res2 = 0 pass the phase from calculation above (res1); */ /* when res2 = 1 phase = 0x200 | (0xd0>>2); */ @@ -868,7 +907,7 @@ void ym2413_device::rhythm_calc( OPLL_CH *CH, unsigned int noise ) if( env < ENV_QUIET ) { /* base frequency derived from operator 1 in channel 7 */ - unsigned char bit8 = ((SLOT7_1->phase>>FREQ_SH)>>8)&1; + uint8_t bit8 = ((SLOT7_1->phase>>FREQ_SH)>>8)&1; /* when bit8 = 0 phase = 0x100; */ /* when bit8 = 1 phase = 0x200; */ @@ -894,21 +933,21 @@ void ym2413_device::rhythm_calc( OPLL_CH *CH, unsigned int noise ) if( env < ENV_QUIET ) { /* base frequency derived from operator 1 in channel 7 */ - unsigned char bit7 = ((SLOT7_1->phase>>FREQ_SH)>>7)&1; - unsigned char bit3 = ((SLOT7_1->phase>>FREQ_SH)>>3)&1; - unsigned char bit2 = ((SLOT7_1->phase>>FREQ_SH)>>2)&1; + uint8_t bit7 = ((SLOT7_1->phase>>FREQ_SH)>>7)&1; + uint8_t bit3 = ((SLOT7_1->phase>>FREQ_SH)>>3)&1; + uint8_t bit2 = ((SLOT7_1->phase>>FREQ_SH)>>2)&1; - unsigned char res1 = (bit2 ^ bit7) | bit3; + uint8_t res1 = (bit2 ^ bit7) | bit3; /* when res1 = 0 phase = 0x000 | 0x100; */ /* when res1 = 1 phase = 0x200 | 0x100; */ uint32_t phase = res1 ? 0x300 : 0x100; /* enable gate based on frequency of operator 2 in channel 8 */ - unsigned char bit5e= ((SLOT8_2->phase>>FREQ_SH)>>5)&1; - unsigned char bit3e= ((SLOT8_2->phase>>FREQ_SH)>>3)&1; + uint8_t bit5e= ((SLOT8_2->phase>>FREQ_SH)>>5)&1; + uint8_t bit3e= ((SLOT8_2->phase>>FREQ_SH)>>3)&1; - unsigned char res2 = (bit3e | bit5e); + uint8_t res2 = (bit3e | bit5e); /* when res2 = 0 pass the phase from calculation above (res1); */ /* when res2 = 1 phase = 0x200 | 0x100; */ if (res2) @@ -1635,11 +1674,14 @@ void ym2413_device::device_reset() noise_rng = 1; /* noise shift register */ /* setup instruments table */ - for (int i=0; i<19; i++) + if (m_inst_table != nullptr) { - for (int c=0; c<8; c++) + for (int i=0; i<19; i++) { - inst_tab[i][c] = table[i][c]; + for (int c=0; c<8; c++) + { + inst_tab[i][c] = m_inst_table[i][c]; + } } } @@ -1686,7 +1728,37 @@ void ym2413_device::data_port_w(u8 data) DEFINE_DEVICE_TYPE(YM2413, ym2413_device, "ym2413", "Yamaha YM2413 OPLL") ym2413_device::ym2413_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : device_t(mconfig, YM2413, tag, owner, clock) + : ym2413_device(mconfig, YM2413, tag, owner, clock) +{ + for (int i = 0; i < 19; i++) + { + for (int c = 0; c < 8; c++) + { + m_inst_table[i][c] = table[i][c]; + } + } +} + +ym2413_device::ym2413_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) + : device_t(mconfig, type, tag, owner, clock) , device_sound_interface(mconfig, *this) { + for (int i = 0; i < 19; i++) + { + std::fill_n(&m_inst_table[i][0], 8, 0); + } +} + +DEFINE_DEVICE_TYPE(VRC7, vrc7snd_device, "vrc7snd", "Konami VRC7 (Sound)") + +vrc7snd_device::vrc7snd_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : ym2413_device(mconfig, VRC7, tag, owner, clock) +{ + for (int i = 0; i < 19; i++) + { + for (int c = 0; c < 8; c++) + { + m_inst_table[i][c] = vrc7_table[i][c]; + } + } } diff --git a/src/devices/sound/ym2413.h b/src/devices/sound/ym2413.h index 32114624eff..1b0d9869770 100644 --- a/src/devices/sound/ym2413.h +++ b/src/devices/sound/ym2413.h @@ -17,6 +17,8 @@ public: void data_port_w(u8 data); protected: + ym2413_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock); + // device-level overrides virtual void device_start() override; virtual void device_clock_changed() override; @@ -25,6 +27,8 @@ protected: // sound stream update overrides virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) override; + uint8_t m_inst_table[19][8]; + private: struct OPLL_SLOT { @@ -106,13 +110,13 @@ private: static const double ksl_tab[8*16]; static const uint32_t ksl_shift[4]; static const uint32_t sl_tab[16]; - static const unsigned char eg_inc[15*RATE_STEPS]; - static const unsigned char eg_rate_select[16+64+16]; - static const unsigned char eg_rate_shift[16+64+16]; + static const uint8_t eg_inc[15*RATE_STEPS]; + static const uint8_t eg_rate_select[16+64+16]; + static const uint8_t eg_rate_shift[16+64+16]; static const uint8_t mul_tab[16]; static const uint8_t lfo_am_table[LFO_AM_TAB_ELEMENTS]; static const int8_t lfo_pm_table[8*8]; - static const unsigned char table[19][8]; + static const uint8_t table[19][8]; int tl_tab[TL_TAB_LEN]; @@ -185,4 +189,15 @@ private: DECLARE_DEVICE_TYPE(YM2413, ym2413_device) +class vrc7snd_device : public ym2413_device +{ +public: + vrc7snd_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + +private: + static const uint8_t vrc7_table[19][8]; +}; + +DECLARE_DEVICE_TYPE(VRC7, vrc7snd_device) + #endif // MAME_SOUND_YM2413_H diff --git a/src/devices/video/mm5445.h b/src/devices/video/mm5445.h index 2ee2b8ed8cb..7d16d4f2ee2 100644 --- a/src/devices/video/mm5445.h +++ b/src/devices/video/mm5445.h @@ -37,8 +37,8 @@ VSS 20 |___________| 21 CLOCK IN O# = OUTPUT BIT # - MM5446, MM5448 don't have the brightness control pin, an extra output pin instead - MM5447, MM5448 don't have the data enable pin(always enabled), but another extra output pin + MM5446, MM5448 don't have the brightness control pin, an extra output pin instead + MM5447, MM5448 don't have the data enable pin(always enabled), but another extra output pin */ diff --git a/src/devices/video/tms9927.cpp b/src/devices/video/tms9927.cpp index bc8e187f8e8..7764aba05f7 100644 --- a/src/devices/video/tms9927.cpp +++ b/src/devices/video/tms9927.cpp @@ -54,6 +54,7 @@ tms9927_device::tms9927_device(const machine_config &mconfig, device_type type, , m_selfload(*this, finder_base::DUMMY_TAG) , m_reset(false) , m_valid_config(false) + , m_custom_visarea(0, 0, 0, 0) { std::fill(std::begin(m_reg), std::end(m_reg), 0x00); } @@ -349,6 +350,9 @@ void tms9927_device::recompute_parameters(bool postload) rectangle visarea(0, m_overscan_left + m_visible_hpix + m_overscan_right - 1, 0, m_overscan_top + m_visible_vpix + m_overscan_bottom - 1); + if (m_custom_visarea.width() > 1 && m_custom_visarea.height() > 1) + visarea = m_custom_visarea; + attotime refresh = clocks_to_attotime(HCOUNT * m_total_vpix); osd_printf_debug("TMS9927: Total = %dx%d, Visible = %dx%d, HSync = %d-%d, VSync = %d-%d, Skew=%d, Upscroll=%d, Period=%f Hz\n", m_total_hpix, m_total_vpix, m_visible_hpix, m_visible_vpix, m_hsyn_start, m_hsyn_end, m_vsyn_start, m_vsyn_end, SKEW_BITS, m_start_datarow, refresh.as_hz()); diff --git a/src/devices/video/tms9927.h b/src/devices/video/tms9927.h index 2e00344c1e7..7a23bd9fbe7 100644 --- a/src/devices/video/tms9927.h +++ b/src/devices/video/tms9927.h @@ -26,6 +26,7 @@ public: m_overscan_top = top; m_overscan_bottom = bottom; } + void set_visarea(s16 minx, s16 maxx, s16 miny, s16 maxy) { m_custom_visarea.set(minx, maxx, miny, maxy); } DECLARE_WRITE8_MEMBER(write); DECLARE_READ8_MEMBER(read); @@ -80,6 +81,7 @@ private: bool m_valid_config; uint16_t m_total_hpix, m_total_vpix; uint16_t m_visible_hpix, m_visible_vpix; + rectangle m_custom_visarea; uint16_t m_vsyn_start, m_vsyn_end; uint16_t m_hsyn_start, m_hsyn_end; diff --git a/src/devices/video/tms9928a.cpp b/src/devices/video/tms9928a.cpp index 31486b77f8b..c068d8b4ce8 100644 --- a/src/devices/video/tms9928a.cpp +++ b/src/devices/video/tms9928a.cpp @@ -166,11 +166,11 @@ void tms9928a_device::write(offs_t offset, uint8_t data) u8 tms9928a_device::vram_read() { - // prevent debugger from changing the address base - if (machine().side_effects_disabled()) return 0; - uint8_t data = m_ReadAhead; + // prevent debugger from changing the address base + if (machine().side_effects_disabled()) return data; + m_ReadAhead = m_vram_space->read_byte(m_Addr); m_Addr = (m_Addr + 1) & (m_vram_size - 1); m_latch = 0; @@ -193,11 +193,11 @@ void tms9928a_device::vram_write(u8 data) u8 tms9928a_device::register_read() { - // prevent debugger from changing the internal state - if (machine().side_effects_disabled()) return 0; - uint8_t data = m_StatusReg; + // prevent debugger from changing the internal state + if (machine().side_effects_disabled()) return data; + m_StatusReg = m_FifthSprite; check_interrupt(); m_latch = 0; |