diff options
Diffstat (limited to 'src')
72 files changed, 3302 insertions, 1254 deletions
diff --git a/src/devices/bus/a2bus/pc_xporter.cpp b/src/devices/bus/a2bus/pc_xporter.cpp new file mode 100644 index 00000000000..2a5f9b38acf --- /dev/null +++ b/src/devices/bus/a2bus/pc_xporter.cpp @@ -0,0 +1,255 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************* + + pcxporter.cpp + + Implementation of the Applied Engineering PC Transporter card + Preliminary version by R. Belmont + + The PC Transporter is basically a PC-XT on an Apple II card. + Features include: + - V30 CPU @ 4.77 MHz + - 768K of RAM, which defines the V30 address space from 0x00000 to 0xBFFFF + and is fully read/writable by the Apple's CPU. + - Usual XT hardware, mostly inside custom ASICs. There's a discrete + NEC uPD71054 (i8254-compatible PIT) though. + - CGA-compatible video, output to a separate CGA monitor or NTSC-compliant analog + RGB monitor (e.g. the IIgs RGB monitor). + - XT-compatible keyboard interface. + - PC-style floppy controller: supports 360K 5.25" disks and 720K 3.5" disks + - HDD controller which is redirected to a file on the Apple's filesystem + + The V30 BIOS is downloaded by the Apple; the Apple also writes text to the CGA screen prior to + the V30's being launched. + + The board was developed by The Engineering Department, a company made up mostly of early Apple + engineers including Apple /// designer Dr. Wendall Sander and ProDOS creator Dick Huston. + + Software and user documentation at: + http://mirrors.apple2.org.za/Apple%20II%20Documentation%20Project/Interface%20Cards/CPU/AE%20PC%20Transporter/ + + Notes: + Registers live at CFxx; access CFFF to clear C800 reservation, + then read Cn00 to map C800-CFFF first. + + PC RAM from 0xA0000-0xAFFFF is where the V30 BIOS is downloaded, + plus used for general storage by the system. + RAM from 0xB0000-0xBFFFF is the CGA framebuffer as usual. + + CF00: PC memory pointer (bits 0-7) + CF01: PC memory pointer (bits 8-15) + CF02: PC memory pointer (bits 16-23) + CF03: read/write PC memory at the pointer and increment the pointer + CF04: read/write PC memory at the pointer and *don't* increment the pointer + + TODO: + - A2 probably also can access the V30's I/O space: where's that at? CF0E/CF0F + are suspects... + - There's likely A2 ROM at CnXX and C800-CBFF to support the "Slinky" memory + expansion card emulation function inside one of the custom ASICs. Need to + dump this... + +*********************************************************************/ + +#include "pc_xporter.h" + +/*************************************************************************** + PARAMETERS +***************************************************************************/ + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type A2BUS_PCXPORTER = &device_creator<a2bus_pcxporter_device>; + +static MACHINE_CONFIG_FRAGMENT( pcxporter ) +MACHINE_CONFIG_END + +/*************************************************************************** + FUNCTION PROTOTYPES +***************************************************************************/ + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor a2bus_pcxporter_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( pcxporter ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +a2bus_pcxporter_device::a2bus_pcxporter_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_a2bus_card_interface(mconfig, *this) +{ +} + +a2bus_pcxporter_device::a2bus_pcxporter_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, A2BUS_PCXPORTER, "Applied Engineering PC Transporter", tag, owner, clock, "a2pcxport", __FILE__), + device_a2bus_card_interface(mconfig, *this) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void a2bus_pcxporter_device::device_start() +{ + // set_a2bus_device makes m_slot valid + set_a2bus_device(); + + memset(m_ram, 0, 768*1024); + memset(m_regs, 0, 0x400); + m_offset = 0; + + save_item(NAME(m_ram)); + save_item(NAME(m_regs)); + save_item(NAME(m_offset)); +} + +void a2bus_pcxporter_device::device_reset() +{ +} + + +/*------------------------------------------------- + read_c0nx - called for reads from this card's c0nx space +-------------------------------------------------*/ + +UINT8 a2bus_pcxporter_device::read_c0nx(address_space &space, UINT8 offset) +{ + switch (offset) + { + default: + printf("Read c0n%x (PC=%x)\n", offset, space.device().safe_pc()); + break; + } + + return 0xff; +} + + +/*------------------------------------------------- + write_c0nx - called for writes to this card's c0nx space +-------------------------------------------------*/ + +void a2bus_pcxporter_device::write_c0nx(address_space &space, UINT8 offset, UINT8 data) +{ + switch (offset) + { + default: + printf("Write %02x to c0n%x (PC=%x)\n", data, offset, space.device().safe_pc()); + break; + } +} + +/*------------------------------------------------- + read_cnxx - called for reads from this card's cnxx space +-------------------------------------------------*/ + +UINT8 a2bus_pcxporter_device::read_cnxx(address_space &space, UINT8 offset) +{ + // read only to trigger C800? + return 0xff; +} + +void a2bus_pcxporter_device::write_cnxx(address_space &space, UINT8 offset, UINT8 data) +{ + printf("Write %02x to cn%02x (PC=%x)\n", data, offset, space.device().safe_pc()); +} + +/*------------------------------------------------- + read_c800 - called for reads from this card's c800 space +-------------------------------------------------*/ + +UINT8 a2bus_pcxporter_device::read_c800(address_space &space, UINT16 offset) +{ +// printf("Read C800 at %x\n", offset + 0xc800); + + if (offset < 0x400) + { + return 0xff; + } + else + { + UINT8 rv; + + switch (offset) + { + case 0x700: + return m_offset & 0xff; + + case 0x701: + return (m_offset >> 8) & 0xff; + + case 0x702: + return (m_offset >> 16) & 0xff; + + case 0x703: // read with increment + rv = m_ram[m_offset]; + m_offset++; + return rv; + + case 0x704: // read w/o increment + rv = m_ram[m_offset]; + return rv; + } + + return m_regs[offset]; + } +} + +/*------------------------------------------------- + write_c800 - called for writes to this card's c800 space +-------------------------------------------------*/ +void a2bus_pcxporter_device::write_c800(address_space &space, UINT16 offset, UINT8 data) +{ + if (offset < 0x400) + { + } + else + { + switch (offset) + { + case 0x700: + m_offset &= ~0xff; + m_offset |= data; +// printf("offset now %x (PC=%x)\n", m_offset, space.device().safe_pc()); + break; + + case 0x701: + m_offset &= ~0xff00; + m_offset |= (data<<8); +// printf("offset now %x (PC=%x)\n", m_offset, space.device().safe_pc()); + break; + + case 0x702: + m_offset &= ~0xff0000; + m_offset |= (data<<16); +// printf("offset now %x (PC=%x)\n", m_offset, space.device().safe_pc()); + break; + + case 0x703: // write w/increment + m_ram[m_offset] = data; + m_offset++; + break; + + case 0x704: // write w/o increment + m_ram[m_offset] = data; + break; + + default: + printf("%02x to C800 at %x\n", data, offset + 0xc800); + m_regs[offset] = data; + break; + } + } +} diff --git a/src/devices/bus/a2bus/pc_xporter.h b/src/devices/bus/a2bus/pc_xporter.h new file mode 100644 index 00000000000..7126439a265 --- /dev/null +++ b/src/devices/bus/a2bus/pc_xporter.h @@ -0,0 +1,53 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************* + + pc_xporter.h + + Implementation of the Applied Engineering PC Transporter card + +*********************************************************************/ + +#pragma once + +#include "emu.h" +#include "a2bus.h" +#include "machine/genpc.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class a2bus_pcxporter_device: + public device_t, + public device_a2bus_card_interface +{ +public: + // construction/destruction + a2bus_pcxporter_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + a2bus_pcxporter_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const override; + +protected: + virtual void device_start() override; + virtual void device_reset() override; + + // overrides of standard a2bus slot functions + virtual UINT8 read_c0nx(address_space &space, UINT8 offset) override; + virtual void write_c0nx(address_space &space, UINT8 offset, UINT8 data) override; + virtual UINT8 read_cnxx(address_space &space, UINT8 offset) override; + virtual void write_cnxx(address_space &space, UINT8 offset, UINT8 data) override; + virtual UINT8 read_c800(address_space &space, UINT16 offset) override; + virtual void write_c800(address_space &space, UINT16 offset, UINT8 data) override; + +private: + UINT8 m_ram[768*1024]; + UINT8 m_regs[0x400]; + UINT32 m_offset; +}; + +// device type definition +extern const device_type A2BUS_PCXPORTER; + diff --git a/src/devices/bus/coleco/exp.cpp b/src/devices/bus/coleco/exp.cpp index 53953f82859..2b2093f2b1d 100644 --- a/src/devices/bus/coleco/exp.cpp +++ b/src/devices/bus/coleco/exp.cpp @@ -38,7 +38,7 @@ void device_colecovision_cartridge_interface::rom_alloc(size_t size) { if (m_rom == nullptr) { - m_rom = device().machine().memory().region_alloc("coleco_cart:rom", size, 1, ENDIANNESS_LITTLE)->base(); + m_rom = device().machine().memory().region_alloc(":coleco_cart:rom", size, 1, ENDIANNESS_LITTLE)->base(); m_rom_size = size; } } diff --git a/src/devices/bus/coleco/exp.h b/src/devices/bus/coleco/exp.h index e64e3c8d6d1..09511c5357f 100644 --- a/src/devices/bus/coleco/exp.h +++ b/src/devices/bus/coleco/exp.h @@ -88,7 +88,7 @@ protected: virtual bool is_creatable() const override { return 0; } virtual bool must_be_loaded() const override { return 0; } virtual bool is_reset_on_load() const override { return 1; } - virtual const char *image_interface() const override { return "coleco_cart"; } + virtual const char *image_interface() const override { return ":coleco_cart"; } virtual const char *file_extensions() const override { return "rom,col,bin"; } virtual const option_guide *create_option_guide() const override { return nullptr; } diff --git a/src/devices/bus/megadrive/md_slot.cpp b/src/devices/bus/megadrive/md_slot.cpp index f44e0597cd4..5a496ac124a 100644 --- a/src/devices/bus/megadrive/md_slot.cpp +++ b/src/devices/bus/megadrive/md_slot.cpp @@ -87,7 +87,7 @@ void device_md_cart_interface::rom_alloc(size_t size, const char *tag) { if (m_rom == nullptr) { - m_rom = (UINT16 *)device().machine().memory().region_alloc(std::string(tag).append(MDSLOT_ROM_REGION_TAG).c_str(), size, 2, ENDIANNESS_LITTLE)->base(); + m_rom = (UINT16 *)device().machine().memory().region_alloc(std::string(tag).append(MDSLOT_ROM_REGION_TAG).c_str(), size, 2, ENDIANNESS_BIG)->base(); m_rom_size = size; } } diff --git a/src/devices/bus/sms_ctrl/joypad.cpp b/src/devices/bus/sms_ctrl/joypad.cpp index b2537453c6a..99ca264cec4 100644 --- a/src/devices/bus/sms_ctrl/joypad.cpp +++ b/src/devices/bus/sms_ctrl/joypad.cpp @@ -2,7 +2,22 @@ // copyright-holders:Fabio Priuli /********************************************************************** - Sega Master System "Control Pad"/generic joystick emulation + Sega Mark III "Joypad" / Master System "Control Pad" emulation + + +Release data from the Sega Retro project: + +- Joypad: + + Year: 1985 Country/region: JP Model code: SJ-152 + +- Control Pad: + + Year: 1986 Country/region: US Model code: 3020 + Year: 1987 Country/region: JP Model code: 3020 + Year: 1987 Country/region: EU Model code: ? + Year: 1989 Country/region: BR Model code: 011770 + Year: 1989 Country/region: KR Model code: ? **********************************************************************/ diff --git a/src/devices/bus/sms_ctrl/joypad.h b/src/devices/bus/sms_ctrl/joypad.h index a67dd5f78b0..d8028bef6c3 100644 --- a/src/devices/bus/sms_ctrl/joypad.h +++ b/src/devices/bus/sms_ctrl/joypad.h @@ -2,7 +2,7 @@ // copyright-holders:Fabio Priuli /********************************************************************** - Sega Master System "Control Pad"/generic joystick emulation + Sega Mark III "Joypad" / Master System "Control Pad" emulation **********************************************************************/ diff --git a/src/devices/bus/sms_ctrl/lphaser.cpp b/src/devices/bus/sms_ctrl/lphaser.cpp index 7c1056da5f0..8a49c9a1554 100644 --- a/src/devices/bus/sms_ctrl/lphaser.cpp +++ b/src/devices/bus/sms_ctrl/lphaser.cpp @@ -4,6 +4,14 @@ Sega Master System "Light Phaser" (light gun) emulation + +Release data from the Sega Retro project: + + Year: 1986 Country/region: US Model code: 3050 + Year: 1987 Country/region: EU Model code: ? + Year: 1989 Country/region: BR Model code: 010470 + Year: 198? Country/region: KR Model code: ? + **********************************************************************/ #include "lphaser.h" diff --git a/src/devices/bus/sms_ctrl/paddle.cpp b/src/devices/bus/sms_ctrl/paddle.cpp index 5486c9a50bd..ec5acd4a5ee 100644 --- a/src/devices/bus/sms_ctrl/paddle.cpp +++ b/src/devices/bus/sms_ctrl/paddle.cpp @@ -2,7 +2,24 @@ // copyright-holders:Fabio Priuli /********************************************************************** - Sega Master System "Paddle Control" emulation + Sega Mark III "Paddle Control" emulation + + +Release data from the Sega Retro project: + + Year: 1987 Country/region: JP Model code: HPD-200 + +Notes: + + The main chip contained in the device is labeled 315-5243. + + The Paddle Control was only released in Japan. To work with the device, + paddle games need to detect the system region as Japanese, else they switch + to a different mode that uses the TH line as output to select which nibble + of the X axis will be read. This other mode is similar to how the US Sports + Pad works, so on an Export system, paddle games are somewhat playable with + that device, though it needs to be used inverted and the trackball needs to + be moved slowly, else the software for the paddle think it's moving backward. **********************************************************************/ diff --git a/src/devices/bus/sms_ctrl/paddle.h b/src/devices/bus/sms_ctrl/paddle.h index 8e092d63afe..fae7a93fb19 100644 --- a/src/devices/bus/sms_ctrl/paddle.h +++ b/src/devices/bus/sms_ctrl/paddle.h @@ -2,7 +2,7 @@ // copyright-holders:Fabio Priuli /********************************************************************** - Sega Master System "Paddle Control" emulation + Sega Mark III "Paddle Control" emulation **********************************************************************/ diff --git a/src/devices/bus/sms_ctrl/rfu.cpp b/src/devices/bus/sms_ctrl/rfu.cpp index 0ccc5ae4e9c..3c27307c137 100644 --- a/src/devices/bus/sms_ctrl/rfu.cpp +++ b/src/devices/bus/sms_ctrl/rfu.cpp @@ -2,12 +2,22 @@ // copyright-holders:Fabio Priuli /********************************************************************** - Sega Master System "Rapid Fire Unit" emulation + Sega SG-1000/Mark-III/SMS "Rapid Fire Unit" emulation -**********************************************************************/ -// This emulated device is the version released by Sega. In Brazil, Tec Toy -// released a version that does not have any switch to turn on/off auto-repeat. +Release data from the Sega Retro project: + + Year: 1985 Country/region: JP Model code: RF-150 + Year: 1987 Country/region: US Model code: 3046 + Year: 1988 Country/region: EU Model code: MK-3046-50 + Year: 1989 Country/region: BR Model code: 011050 + +Notes: + + This emulated device is the version released by Sega. In Brazil, Tec Toy + released a version that does not have any switch to turn on/off auto-repeat. + +**********************************************************************/ #include "rfu.h" diff --git a/src/devices/bus/sms_ctrl/rfu.h b/src/devices/bus/sms_ctrl/rfu.h index adc9a3443ba..6a56b06ae3a 100644 --- a/src/devices/bus/sms_ctrl/rfu.h +++ b/src/devices/bus/sms_ctrl/rfu.h @@ -2,7 +2,7 @@ // copyright-holders:Fabio Priuli /********************************************************************** - Sega Master System "Rapid Fire Unit" emulation + Sega SG-1000/Mark-III/SMS "Rapid Fire Unit" emulation **********************************************************************/ diff --git a/src/devices/bus/sms_ctrl/sports.cpp b/src/devices/bus/sms_ctrl/sports.cpp index 77356cec41f..b4bd54d81a1 100644 --- a/src/devices/bus/sms_ctrl/sports.cpp +++ b/src/devices/bus/sms_ctrl/sports.cpp @@ -4,29 +4,43 @@ Sega Master System "Sports Pad" (US model) emulation -**********************************************************************/ -// The games designed for the US model of the Sports Pad controller use the -// TH line of the controller port to select which nibble, of the two axis -// bytes, will be read at a time. The Japanese cartridge Sports Pad Soccer -// uses a different mode, because the Sega Mark III lacks the TH line, so -// there is a different Sports Pad model released in Japan (see sportsjp.c). - -// The Japanese SMS has the TH line connected, but doesn't report TH input -// on port 0xDD. However, a magazine raffled the US Sports Pad along with a -// Great Ice Hockey cartridge, in Japanese format, to owners of that console. -// So, Great Ice Hockey seems to just need TH pin as output to work, while -// other games designed for the US Sports Pad don't work on the Japanese SMS. - -// It was discovered that games designed for the Paddle Controller, released -// in Japan, switch to a mode incompatible with the original Paddle when -// detect the system region as Export. Similar to how the US model of the -// Sports Pad works, that mode uses the TH line as output to select which -// nibble of the X axis will be read. So, on an Export console version, paddle -// games are somewhat playable with the US Sport Pad model, though it needs to -// be used inverted and the trackball needs to be moved slowly, else the -// software for the paddle think it's moving backward. -// See http://mametesters.org/view.php?id=5872 for discussion. +Release data from the Sega Retro project: + + Year: 1987 Country/region: US Model code: 3040 + +TODO: + +- For low-level emulation, a device for the TMP42C66P, a Toshiba 4bit + microcontroller, needs to be created, but a dump of its internal ROM + seems to be required. +- Auto-repeat and Control/Sports mode switches are not emulated. + +Notes: + + Games designed for the US model of the Sports Pad controller use the + TH line of the controller port to select which nibble, of the two axis + bytes, will be read at a time. The Japanese cartridge Sports Pad Soccer + uses a different mode, because the Sega Mark III lacks the TH line, so + there is a different Sports Pad model released in Japan (see sportsjp.c). + + The Japanese SMS has the TH line connected, but doesn't report TH input + on port 0xDD. However, a magazine raffled the US Sports Pad along with a + Great Ice Hockey cartridge, in Japanese format, to owners of that console. + So, Great Ice Hockey seems to just need TH pin as output to work, while + other games designed for the US Sports Pad don't work on the Japanese SMS. + + It was discovered that games designed for the Paddle Controller, released + in Japan, switch to a mode incompatible with the original Paddle when + detect the system region as Export. Similar to how the US model of the + Sports Pad works, that mode uses the TH line as output to select which + nibble of the X axis will be read. So, on an Export console version, + paddle games are somewhat playable with the US Sport Pad model, though it + needs to be used inverted and the trackball needs to be moved slowly, else + the software for the paddle think it's moving backward. + See http://mametesters.org/view.php?id=5872 for discussion. + +**********************************************************************/ #include "sports.h" diff --git a/src/devices/bus/sms_ctrl/sportsjp.cpp b/src/devices/bus/sms_ctrl/sportsjp.cpp index 16c5198721c..ca2c3de1748 100644 --- a/src/devices/bus/sms_ctrl/sportsjp.cpp +++ b/src/devices/bus/sms_ctrl/sportsjp.cpp @@ -4,12 +4,25 @@ Sega Master System "Sports Pad" (Japanese model) emulation -**********************************************************************/ -// The Japanese Sports Pad controller is only required to play the cartridge -// Sports Pad Soccer, released in Japan. It uses a different mode than the -// used by the US model, due to the missing TH line on Sega Mark III -// controller ports. +Release data from the Sega Retro project: + + Year: 1988 Country/region: JP Model code: SP-500 + +TODO: + +- For low-level emulation, a device for the TMP42C66P, a Toshiba 4bit + microcontroller, needs to be created, but a dump of its internal ROM + seems to be required. + +Notes: + + The Japanese Sports Pad controller is only required to play the cartridge + Sports Pad Soccer, released in Japan. It uses a different mode than the + used by the US model, due to the missing TH line on Sega Mark III + controller ports. + +**********************************************************************/ #include "sportsjp.h" diff --git a/src/devices/bus/sms_exp/gender.cpp b/src/devices/bus/sms_exp/gender.cpp index 3de8961050c..49ccc50e24e 100644 --- a/src/devices/bus/sms_exp/gender.cpp +++ b/src/devices/bus/sms_exp/gender.cpp @@ -4,14 +4,14 @@ Sega Master System "Gender Adapter" emulation -**********************************************************************/ +The Gender Adapter is not an official Sega product. It is produced since 2006 +by the SMSPower website to permit to plug a cartridge on the expansion slot +on any SMS 1 model. This includes the Japanese SMS, which has FM sound, so +it is a way to get FM music of western cartridges that have FM code but were +not released in Japan. Some games have compatibility issues, confirmed on the +real hardware, when run plugged-in to the SMS expansion slot. -// The Gender Adapter is not an official Sega product. It is produced by the -// SMSPower website to permit to plug a cartridge on the expansion slot on any -// SMS 1 model. This includes the Japanese SMS, which has FM sound, so it is -// a way to get FM music of western cartridges that have FM code but were not -// released in Japan. Some games have compatibility issues, confirmed on the -// real hardware, when run plugged-in to the SMS expansion slot. +**********************************************************************/ #include "gender.h" diff --git a/src/devices/cpu/sm510/sm510op.cpp b/src/devices/cpu/sm510/sm510op.cpp index c2d0658ba6f..3f0659bac16 100644 --- a/src/devices/cpu/sm510/sm510op.cpp +++ b/src/devices/cpu/sm510/sm510op.cpp @@ -67,7 +67,7 @@ void sm510_base_device::op_lb() UINT8 hi = 0; switch (m_bl) { - case 0: hi = 3; break; + case 0: hi = 0; break; case 1: hi = 0; break; case 2: hi = 0; break; case 3: hi = 3; break; diff --git a/src/emu/emuopts.cpp b/src/emu/emuopts.cpp index 35a8fae6333..e5906562d2a 100644 --- a/src/emu/emuopts.cpp +++ b/src/emu/emuopts.cpp @@ -376,6 +376,9 @@ void emu_options::remove_device_options() remove_entry(*curentry); } + // take also care of ramsize options + set_default_value(OPTION_RAMSIZE, ""); + // reset counters m_slot_options = 0; m_device_options = 0; @@ -541,20 +544,66 @@ void emu_options::set_system_name(const char *name) { // remember the original system name std::string old_system_name(system_name()); + bool new_system = old_system_name.compare(name)!=0; // if the system name changed, fix up the device options - if (old_system_name.compare(name)!=0) + if (new_system) { // first set the new name std::string error; set_value(OPTION_SYSTEMNAME, name, OPTION_PRIORITY_CMDLINE, error); assert(error.empty()); - // remove any existing device options and then add them afresh + // remove any existing device options remove_device_options(); - while (add_slot_options()) { } + } + + // get the new system + const game_driver *cursystem = system(); + if (cursystem == nullptr) + return; + + if (*software_name() != 0) + { + std::string sw_load(software_name()); + std::string sw_list, sw_name, sw_part, sw_instance, option_errors, error_string; + int left = sw_load.find_first_of(':'); + int middle = sw_load.find_first_of(':', left + 1); + int right = sw_load.find_last_of(':'); + + sw_list = sw_load.substr(0, left - 1); + sw_name = sw_load.substr(left + 1, middle - left - 1); + sw_part = sw_load.substr(middle + 1, right - middle - 1); + sw_instance = sw_load.substr(right + 1); + sw_load.assign(sw_load.substr(0, right)); + + // look up the software part + machine_config config(*cursystem, *this); + software_list_device *swlist = software_list_device::find_by_name(config, sw_list.c_str()); + software_info *swinfo = swlist != nullptr ? swlist->find(sw_name.c_str()) : nullptr; + software_part *swpart = swinfo != nullptr ? swinfo->find_part(sw_part.c_str()) : nullptr; // then add the options + if (new_system) + { + while (add_slot_options(swpart)) { } + add_device_options(); + } + + set_value(OPTION_SOFTWARENAME, sw_name.c_str(), OPTION_PRIORITY_CMDLINE, error_string); + if (exists(sw_instance.c_str())) + set_value(sw_instance.c_str(), sw_load.c_str(), OPTION_PRIORITY_SUBCMD, error_string); + + int num; + do { + num = options_count(); + update_slot_options(swpart); + } while(num != options_count()); + } + else if (new_system) + { + // add the options afresh + while (add_slot_options()) { } add_device_options(); int num; do { diff --git a/src/emu/luaengine.cpp b/src/emu/luaengine.cpp index 0cf57ef61c0..fbd2e64fc76 100644 --- a/src/emu/luaengine.cpp +++ b/src/emu/luaengine.cpp @@ -245,6 +245,16 @@ int lua_engine::l_emu_romname(lua_State *L) } //------------------------------------------------- +// emu_softname - returns softlist name +//------------------------------------------------- + +int lua_engine::l_emu_softname(lua_State *L) +{ + lua_pushstring(L, luaThis->machine().options().software_name()); + return 1; +} + +//------------------------------------------------- // emu_pause/emu_unpause - pause/unpause game //------------------------------------------------- @@ -1418,6 +1428,7 @@ void lua_engine::initialize() .addCFunction ("app_version", l_emu_app_version ) .addCFunction ("gamename", l_emu_gamename ) .addCFunction ("romname", l_emu_romname ) + .addCFunction ("softname", l_emu_softname ) .addCFunction ("keypost", l_emu_keypost ) .addCFunction ("hook_output", l_emu_hook_output ) .addCFunction ("sethook", l_emu_set_hook ) diff --git a/src/emu/luaengine.h b/src/emu/luaengine.h index 19c362c66a2..2f0f4ad7a34 100644 --- a/src/emu/luaengine.h +++ b/src/emu/luaengine.h @@ -106,6 +106,7 @@ private: static int l_emu_time(lua_State *L); static int l_emu_gamename(lua_State *L); static int l_emu_romname(lua_State *L); + static int l_emu_softname(lua_State *L); static int l_emu_keypost(lua_State *L); static int l_emu_hook_output(lua_State *L); static int l_emu_exit(lua_State *L); diff --git a/src/emu/machine.cpp b/src/emu/machine.cpp index 7c465be0cd8..d76ad49676d 100644 --- a/src/emu/machine.cpp +++ b/src/emu/machine.cpp @@ -356,7 +356,7 @@ int running_machine::run(bool firstrun) ui().initialize(*this); // display the startup screens - ui().display_startup_screens(firstrun, false); + ui().display_startup_screens(firstrun); // perform a soft reset -- this takes us to the running phase soft_reset(); diff --git a/src/emu/mame.cpp b/src/emu/mame.cpp index 9232ee9443f..9e872c7a96f 100644 --- a/src/emu/mame.cpp +++ b/src/emu/mame.cpp @@ -251,40 +251,9 @@ int machine_manager::execute() // check the state of the machine if (m_new_driver_pending) { - std::string old_system_name(m_options.system_name()); - bool new_system = (old_system_name.compare(m_new_driver_pending->name)!=0); - // first: if we scheduled a new system, remove device options of the old system - // notice that, if we relaunch the same system, there is no effect on the emulation - if (new_system) - m_options.remove_device_options(); - // second: set up new system name (and the related device options) + // set up new system name and adjust device options accordingly m_options.set_system_name(m_new_driver_pending->name); - // third: if we scheduled a new system, take also care of ramsize options - if (new_system) - { - std::string error_string; - m_options.set_value(OPTION_RAMSIZE, "", OPTION_PRIORITY_CMDLINE, error_string); - } firstrun = true; - if (m_options.software_name()) - { - std::string sw_load(m_options.software_name()); - std::string sw_list, sw_name, sw_part, sw_instance, option_errors, error_string; - int left = sw_load.find_first_of(':'); - int middle = sw_load.find_first_of(':', left + 1); - int right = sw_load.find_last_of(':'); - - sw_list = sw_load.substr(0, left - 1); - sw_name = sw_load.substr(left + 1, middle - left - 1); - sw_part = sw_load.substr(middle + 1, right - middle - 1); - sw_instance = sw_load.substr(right + 1); - sw_load.assign(sw_load.substr(0, right)); - - char arg[] = "mame"; - char *argv = &arg[0]; - m_options.set_value(OPTION_SOFTWARENAME, sw_name.c_str(), OPTION_PRIORITY_CMDLINE, error_string); - m_options.parse_slot_devices(1, &argv, option_errors, sw_instance.c_str(), sw_load.c_str()); - } } else { diff --git a/src/emu/rendlay.cpp b/src/emu/rendlay.cpp index a69ea831e44..41fffd964aa 100644 --- a/src/emu/rendlay.cpp +++ b/src/emu/rendlay.cpp @@ -1303,7 +1303,7 @@ void layout_element::component::draw_beltreel(running_machine &machine, bitmap_a //------------------------------------------------- -// load_bitmap - load a PNG file with artwork for +// load_bitmap - load a PNG/JPG file with artwork for // a component //------------------------------------------------- @@ -1317,6 +1317,10 @@ void layout_element::component::load_bitmap() if (m_bitmap[0].valid() && !m_alphafile[0].empty()) render_load_png(m_bitmap[0], *m_file[0], m_dirname.c_str(), m_alphafile[0].c_str(), true); + // PNG failed, let's try JPG + if (!m_bitmap[0].valid()) + render_load_jpeg(m_bitmap[0], *m_file[0], m_dirname.c_str(), m_imagefile[0].c_str()); + // if we can't load the bitmap, allocate a dummy one and report an error if (!m_bitmap[0].valid()) { diff --git a/src/emu/rendutil.cpp b/src/emu/rendutil.cpp index 4c49c6c8a62..eed35713a92 100644 --- a/src/emu/rendutil.cpp +++ b/src/emu/rendutil.cpp @@ -12,7 +12,7 @@ #include "rendutil.h" #include "png.h" - +#include "libjpeg/jpeglib.h" /*************************************************************************** FUNCTION PROTOTYPES @@ -524,6 +524,89 @@ void render_line_to_quad(const render_bounds *bounds, float width, render_bounds /*------------------------------------------------- + render_load_jpeg - load a JPG file into a + bitmap +-------------------------------------------------*/ + +void render_load_jpeg(bitmap_argb32 &bitmap, emu_file &file, const char *dirname, const char *filename) +{ + // deallocate previous bitmap + bitmap.reset(); + + // define file's full name + std::string fname; + + if (dirname == nullptr) + fname = filename; + else + fname.assign(dirname).append(PATH_SEPARATOR).append(filename); + + osd_file::error filerr = file.open(fname.c_str()); + + if (filerr != osd_file::error::NONE) + return; + + // define standard JPEG structures + jpeg_decompress_struct cinfo; + jpeg_error_mgr jerr; + cinfo.err = jpeg_std_error(&jerr); + jpeg_create_decompress(&cinfo); + + // allocates a buffer for the image + UINT64 jpg_size = file.size(); + unsigned char *jpg_buffer = global_alloc_array(unsigned char, jpg_size + 100); + + // read data from the file and set them in the buffer + file.read(jpg_buffer, jpg_size); + jpeg_mem_src(&cinfo, jpg_buffer, jpg_size); + + // read JPEG header and start decompression + jpeg_read_header(&cinfo, TRUE); + jpeg_start_decompress(&cinfo); + + // allocates the destination bitmap + int w = cinfo.output_width; + int h = cinfo.output_height; + int s = cinfo.output_components; + bitmap.allocate(w, h); + + // allocates a buffer to receive the information and copy them into the bitmap + int row_stride = cinfo.output_width * cinfo.output_components; + JSAMPARRAY buffer = (JSAMPARRAY)malloc(sizeof(JSAMPROW)); + buffer[0] = (JSAMPROW)malloc(sizeof(JSAMPLE) * row_stride); + + while ( cinfo.output_scanline < cinfo.output_height ) + { + int j = cinfo.output_scanline; + jpeg_read_scanlines(&cinfo, buffer, 1); + + if (s == 1) + for (int i = 0; i < w; ++i) + bitmap.pix32(j, i) = rgb_t(0xFF, buffer[0][i], buffer[0][i], buffer[0][i]); + + else if (s == 3) + for (int i = 0; i < w; ++i) + bitmap.pix32(j, i) = rgb_t(0xFF, buffer[0][i * s], buffer[0][i * s + 1], buffer[0][i * s + 2]); + + else + { + osd_printf_error("Cannot read JPEG data from %s file.\n", fname.c_str()); + bitmap.reset(); + break; + } + } + + // finish decompression and frees the memory + jpeg_finish_decompress(&cinfo); + jpeg_destroy_decompress(&cinfo); + file.close(); + free(buffer[0]); + free(buffer); + global_free_array(jpg_buffer); +} + + +/*------------------------------------------------- render_load_png - load a PNG file into a bitmap -------------------------------------------------*/ diff --git a/src/emu/rendutil.h b/src/emu/rendutil.h index 34a9c2ef75c..bdf01592307 100644 --- a/src/emu/rendutil.h +++ b/src/emu/rendutil.h @@ -25,6 +25,7 @@ void render_resample_argb_bitmap_hq(bitmap_argb32 &dest, bitmap_argb32 &source, int render_clip_line(render_bounds *bounds, const render_bounds *clip); int render_clip_quad(render_bounds *bounds, const render_bounds *clip, render_quad_texuv *texcoords); void render_line_to_quad(const render_bounds *bounds, float width, render_bounds *bounds0, render_bounds *bounds1); +void render_load_jpeg(bitmap_argb32 &bitmap, emu_file &file, const char *dirname, const char *filename); bool render_load_png(bitmap_argb32 &bitmap, emu_file &file, const char *dirname, const char *filename, bool load_as_alpha_to_existing = false); diff --git a/src/emu/ui/sliders.cpp b/src/emu/ui/sliders.cpp index 86f85bd0026..25dd8afa06d 100644 --- a/src/emu/ui/sliders.cpp +++ b/src/emu/ui/sliders.cpp @@ -44,6 +44,9 @@ void ui_menu_sliders::handle() const slider_state *slider = (const slider_state *)menu_event->itemref; INT32 curvalue = (*slider->update)(machine(), slider->arg, nullptr, SLIDER_NOCHANGE); INT32 increment = 0; + bool alt_pressed = machine().input().code_pressed(KEYCODE_LALT) || machine().input().code_pressed(KEYCODE_RALT); + bool ctrl_pressed = machine().input().code_pressed(KEYCODE_LCONTROL) || machine().input().code_pressed(KEYCODE_RCONTROL); + bool shift_pressed = machine().input().code_pressed(KEYCODE_LSHIFT) || machine().input().code_pressed(KEYCODE_RSHIFT); switch (menu_event->iptkey) { @@ -57,11 +60,13 @@ void ui_menu_sliders::handle() /* decrease value */ case IPT_UI_LEFT: - if (machine().input().code_pressed(KEYCODE_LALT) || machine().input().code_pressed(KEYCODE_RALT)) + if (alt_pressed && shift_pressed) increment = -1; - else if (machine().input().code_pressed(KEYCODE_LSHIFT) || machine().input().code_pressed(KEYCODE_RSHIFT)) + if (alt_pressed) + increment = -(curvalue - slider->minval); + else if (shift_pressed) increment = (slider->incval > 10) ? -(slider->incval / 10) : -1; - else if (machine().input().code_pressed(KEYCODE_LCONTROL) || machine().input().code_pressed(KEYCODE_RCONTROL)) + else if (ctrl_pressed) increment = -slider->incval * 10; else increment = -slider->incval; @@ -69,11 +74,13 @@ void ui_menu_sliders::handle() /* increase value */ case IPT_UI_RIGHT: - if (machine().input().code_pressed(KEYCODE_LALT) || machine().input().code_pressed(KEYCODE_RALT)) + if (alt_pressed && shift_pressed) increment = 1; - else if (machine().input().code_pressed(KEYCODE_LSHIFT) || machine().input().code_pressed(KEYCODE_RSHIFT)) + if (alt_pressed) + increment = slider->maxval - curvalue; + else if (shift_pressed) increment = (slider->incval > 10) ? (slider->incval / 10) : 1; - else if (machine().input().code_pressed(KEYCODE_LCONTROL) || machine().input().code_pressed(KEYCODE_RCONTROL)) + else if (ctrl_pressed) increment = slider->incval * 10; else increment = slider->incval; diff --git a/src/emu/ui/ui.cpp b/src/emu/ui/ui.cpp index cc8b18c8154..0b15f24edc6 100644 --- a/src/emu/ui/ui.cpp +++ b/src/emu/ui/ui.cpp @@ -359,9 +359,9 @@ UINT32 ui_manager::set_handler(ui_callback callback, UINT32 param) // various startup screens //------------------------------------------------- -void ui_manager::display_startup_screens(bool first_time, bool show_disclaimer) +void ui_manager::display_startup_screens(bool first_time) { - const int maxstate = 4; + const int maxstate = 3; int str = machine().options().seconds_to_run(); bool show_gameinfo = !machine().options().skip_gameinfo(); bool show_warnings = true, show_mandatory_fileman = true; @@ -370,11 +370,11 @@ void ui_manager::display_startup_screens(bool first_time, bool show_disclaimer) // disable everything if we are using -str for 300 or fewer seconds, or if we're the empty driver, // or if we are debugging if (!first_time || (str > 0 && str < 60*5) || &machine().system() == &GAME_NAME(___empty) || (machine().debug_flags & DEBUG_FLAG_ENABLED) != 0) - show_gameinfo = show_warnings = show_disclaimer = show_mandatory_fileman = FALSE; + show_gameinfo = show_warnings = show_mandatory_fileman = FALSE; #if defined(EMSCRIPTEN) // also disable for the JavaScript port since the startup screens do not run asynchronously - show_gameinfo = show_warnings = show_disclaimer = FALSE; + show_gameinfo = show_warnings = FALSE; #endif // loop over states @@ -388,14 +388,9 @@ void ui_manager::display_startup_screens(bool first_time, bool show_disclaimer) switch (state) { case 0: - if (show_disclaimer && disclaimer_string(messagebox_text).length() > 0) - set_handler(handler_messagebox_ok, 0); - break; - - case 1: if (show_warnings && warnings_string(messagebox_text).length() > 0) { - set_handler(handler_messagebox_ok, 0); + set_handler(handler_messagebox_anykey, 0); if (machine().system().flags & (MACHINE_WRONG_COLORS | MACHINE_IMPERFECT_COLORS | MACHINE_REQUIRES_ARTWORK | MACHINE_IMPERFECT_GRAPHICS | MACHINE_IMPERFECT_SOUND | MACHINE_IMPERFECT_KEYBOARD | MACHINE_NO_SOUND)) messagebox_backcolor = UI_YELLOW_COLOR; if (machine().system().flags & (MACHINE_NOT_WORKING | MACHINE_UNEMULATED_PROTECTION | MACHINE_MECHANICAL)) @@ -403,12 +398,12 @@ void ui_manager::display_startup_screens(bool first_time, bool show_disclaimer) } break; - case 2: + case 1: if (show_gameinfo && game_info_astring(messagebox_text).length() > 0) set_handler(handler_messagebox_anykey, 0); break; - case 3: + case 2: if (show_mandatory_fileman && machine().image().mandatory_scan(messagebox_text).length() > 0) { std::string warning; @@ -1033,22 +1028,6 @@ bool ui_manager::show_timecode_total() ***************************************************************************/ //------------------------------------------------- -// disclaimer_string - print the disclaimer -// text to the given buffer -//------------------------------------------------- - -std::string &ui_manager::disclaimer_string(std::string &str) -{ - str = string_format( - _("Usage of emulators in conjunction with ROMs you don't own is forbidden by copyright law.\n\n" - "IF YOU ARE NOT LEGALLY ENTITLED TO PLAY \"%1$s\" ON THIS EMULATOR, PRESS ESC.\n\n" - "Otherwise, type OK or move the joystick left then right to continue"), - machine().system().description); - return str; -} - - -//------------------------------------------------- // warnings_string - print the warning flags // text to the given buffer //------------------------------------------------- @@ -1174,7 +1153,7 @@ std::string &ui_manager::warnings_string(std::string &str) } // add the 'press OK' string - str.append(_("\n\nType OK or move the joystick left then right to continue")); + str.append(_("\n\nPress any key to continue")); return str; } @@ -1317,35 +1296,6 @@ UINT32 ui_manager::handler_messagebox(running_machine &machine, render_container //------------------------------------------------- -// handler_messagebox_ok - displays the current -// messagebox_text string and waits for an OK -//------------------------------------------------- - -UINT32 ui_manager::handler_messagebox_ok(running_machine &machine, render_container *container, UINT32 state) -{ - // draw a standard message window - machine.ui().draw_text_box(container, messagebox_text.c_str(), JUSTIFY_LEFT, 0.5f, 0.5f, messagebox_backcolor); - - // an 'O' or left joystick kicks us to the next state - if (state == 0 && (machine.input().code_pressed_once(KEYCODE_O) || machine.ui_input().pressed(IPT_UI_LEFT))) - state++; - - // a 'K' or right joystick exits the state - else if (state == 1 && (machine.input().code_pressed_once(KEYCODE_K) || machine.ui_input().pressed(IPT_UI_RIGHT))) - state = UI_HANDLER_CANCEL; - - // if the user cancels, exit out completely - else if (machine.ui_input().pressed(IPT_UI_CANCEL)) - { - machine.schedule_exit(); - state = UI_HANDLER_CANCEL; - } - - return state; -} - - -//------------------------------------------------- // handler_messagebox_anykey - displays the // current messagebox_text string and waits for // any keypress diff --git a/src/emu/ui/ui.h b/src/emu/ui/ui.h index c50d444120e..ea117a74d82 100644 --- a/src/emu/ui/ui.h +++ b/src/emu/ui/ui.h @@ -129,7 +129,7 @@ public: // methods void initialize(running_machine &machine); UINT32 set_handler(ui_callback callback, UINT32 param); - void display_startup_screens(bool first_time, bool show_disclaimer); + void display_startup_screens(bool first_time); void set_startup_text(const char *text, bool force); void update_and_render(render_container *container); render_font *get_font(); @@ -213,12 +213,10 @@ private: static slider_state *slider_current; // text generators - std::string &disclaimer_string(std::string &buffer); std::string &warnings_string(std::string &buffer); // UI handlers static UINT32 handler_messagebox(running_machine &machine, render_container *container, UINT32 state); - static UINT32 handler_messagebox_ok(running_machine &machine, render_container *container, UINT32 state); static UINT32 handler_messagebox_anykey(running_machine &machine, render_container *container, UINT32 state); static UINT32 handler_ingame(running_machine &machine, render_container *container, UINT32 state); static UINT32 handler_load_save(running_machine &machine, render_container *container, UINT32 state); diff --git a/src/emu/ui/utils.h b/src/emu/ui/utils.h index a8737fb2e6b..81107c0911c 100644 --- a/src/emu/ui/utils.h +++ b/src/emu/ui/utils.h @@ -14,8 +14,7 @@ #define __UI_UTILS_H__ #include "osdepend.h" -#include "render.h" -#include "libjpeg/jpeglib.h" +#include "rendutil.h" #define MAX_CHAR_INFO 256 #define MAX_CUST_FILTER 8 @@ -255,90 +254,5 @@ char* chartrimcarriage(char str[]); const char* strensure(const char* s); -// jpeg loader -template <typename _T> -void render_load_jpeg(_T &bitmap, emu_file &file, const char *dirname, const char *filename) -{ - // deallocate previous bitmap - bitmap.reset(); - - bitmap_format format = bitmap.format(); - - // define file's full name - std::string fname; - - if (dirname == nullptr) - fname = filename; - else - fname.assign(dirname).append(PATH_SEPARATOR).append(filename); - - osd_file::error filerr = file.open(fname.c_str()); - - if (filerr != osd_file::error::NONE) - return; - - // define standard JPEG structures - jpeg_decompress_struct cinfo; - jpeg_error_mgr jerr; - cinfo.err = jpeg_std_error(&jerr); - jpeg_create_decompress(&cinfo); - - // allocates a buffer for the image - UINT64 jpg_size = file.size(); - unsigned char *jpg_buffer = global_alloc_array(unsigned char, jpg_size + 100); - - // read data from the file and set them in the buffer - file.read(jpg_buffer, jpg_size); - jpeg_mem_src(&cinfo, jpg_buffer, jpg_size); - - // read JPEG header and start decompression - jpeg_read_header(&cinfo, TRUE); - jpeg_start_decompress(&cinfo); - - // allocates the destination bitmap - int w = cinfo.output_width; - int h = cinfo.output_height; - int s = cinfo.output_components; - bitmap.allocate(w, h); - - // allocates a buffer to receive the information and copy them into the bitmap - int row_stride = cinfo.output_width * cinfo.output_components; - JSAMPARRAY buffer = (JSAMPARRAY)malloc(sizeof(JSAMPROW)); - buffer[0] = (JSAMPROW)malloc(sizeof(JSAMPLE) * row_stride); - - while ( cinfo.output_scanline < cinfo.output_height ) - { - int j = cinfo.output_scanline; - jpeg_read_scanlines(&cinfo, buffer, 1); - - if (s == 1) - for (int i = 0; i < w; ++i) - if (format == BITMAP_FORMAT_ARGB32) - bitmap.pix32(j, i) = rgb_t(0xFF, buffer[0][i], buffer[0][i], buffer[0][i]); - else - bitmap.pix32(j, i) = rgb_t(buffer[0][i], buffer[0][i], buffer[0][i]); - - else if (s == 3) - for (int i = 0; i < w; ++i) - if (format == BITMAP_FORMAT_ARGB32) - bitmap.pix32(j, i) = rgb_t(0xFF, buffer[0][i * s], buffer[0][i * s + 1], buffer[0][i * s + 2]); - else - bitmap.pix32(j, i) = rgb_t(buffer[0][i * s], buffer[0][i * s + 1], buffer[0][i * s + 2]); - - else - { - osd_printf_info("Error! Cannot read JPEG data from %s file.\n", fname.c_str()); - break; - } - } - - // finish decompression and frees the memory - jpeg_finish_decompress(&cinfo); - jpeg_destroy_decompress(&cinfo); - file.close(); - free(buffer[0]); - free(buffer); - global_free_array(jpg_buffer); -} #endif /* __UI_UTILS_H__ */ diff --git a/src/lib/netlist/devices/nld_mm5837.cpp b/src/lib/netlist/devices/nld_mm5837.cpp index 7f7ab6f8660..82e774b4923 100644 --- a/src/lib/netlist/devices/nld_mm5837.cpp +++ b/src/lib/netlist/devices/nld_mm5837.cpp @@ -5,7 +5,7 @@ * */ -#include <solver/nld_solver.h> +#include <solver/nld_matrix_solver.h> #include "nld_mm5837.h" #include "nl_setup.h" diff --git a/src/lib/netlist/devices/nld_system.cpp b/src/lib/netlist/devices/nld_system.cpp index dbf6926437d..e861bf05171 100644 --- a/src/lib/netlist/devices/nld_system.cpp +++ b/src/lib/netlist/devices/nld_system.cpp @@ -6,6 +6,7 @@ */ #include <solver/nld_solver.h> +#include <solver/nld_matrix_solver.h> #include "nld_system.h" NETLIB_NAMESPACE_DEVICES_START() diff --git a/src/lib/netlist/macro/nlm_ttl74xx.cpp b/src/lib/netlist/macro/nlm_ttl74xx.cpp index de42f26d730..49fea3c55c8 100644 --- a/src/lib/netlist/macro/nlm_ttl74xx.cpp +++ b/src/lib/netlist/macro/nlm_ttl74xx.cpp @@ -84,7 +84,7 @@ NETLIST_START(TTL74XX_lib) TT_FAMILY("74XX") TRUTHTABLE_END() - TRUTHTABLE_START(TTL_7400_NAND, 2, 1, 0, "+A,B") + TRUTHTABLE_START(TTL_7400_NAND, 2, 1, 0, "A,B") TT_HEAD("A,B|Q ") TT_LINE("0,X|1|22") TT_LINE("X,0|1|22") diff --git a/src/lib/netlist/nl_base.cpp b/src/lib/netlist/nl_base.cpp index 6ea052b4132..7afa0285ef8 100644 --- a/src/lib/netlist/nl_base.cpp +++ b/src/lib/netlist/nl_base.cpp @@ -5,7 +5,8 @@ * */ -#include <solver/nld_solver.h> +#include <solver/nld_matrix_solver.h> + #include <cstring> #include <algorithm> @@ -840,10 +841,10 @@ ATTR_COLD void core_terminal_t::set_net(net_t &anet) ATTR_COLD terminal_t::terminal_t() : analog_t(TERMINAL) +, m_otherterm(NULL) , m_Idr1(NULL) , m_go1(NULL) , m_gt1(NULL) -, m_otherterm(NULL) { } diff --git a/src/lib/netlist/nl_base.h b/src/lib/netlist/nl_base.h index 24f2cde585a..52a91704607 100644 --- a/src/lib/netlist/nl_base.h +++ b/src/lib/netlist/nl_base.h @@ -551,10 +551,6 @@ namespace netlist ATTR_COLD terminal_t(); - nl_double *m_Idr1; // drive current - nl_double *m_go1; // conductance for Voltage from other term - nl_double *m_gt1; // conductance for total conductance - terminal_t *m_otherterm; ATTR_HOT void set(const nl_double G) @@ -581,19 +577,31 @@ namespace netlist ATTR_HOT void schedule_solve(); ATTR_HOT void schedule_after(const netlist_time &after); + void set_ptrs(nl_double *gt, nl_double *go, nl_double *Idr) + { + m_gt1 = gt; + m_go1 = go; + m_Idr1 = Idr; + } + protected: virtual void save_register() override; virtual void reset() override; private: - ATTR_HOT void set_ptr(nl_double *ptr, const nl_double val) + ATTR_HOT void set_ptr(nl_double *ptr, const nl_double val) { if (ptr != NULL && *ptr != val) { *ptr = val; } } - }; + + nl_double *m_Idr1; // drive current + nl_double *m_go1; // conductance for Voltage from other term + nl_double *m_gt1; // conductance for total conductance + +}; // ----------------------------------------------------------------------------- @@ -1054,7 +1062,7 @@ namespace netlist ATTR_HOT nl_double INPANALOG(const analog_input_t &inp) const { return inp.Q_Analog(); } - ATTR_HOT nl_double TERMANALOG(const terminal_t &term) const { return term.net().as_analog().Q_Analog(); } + ATTR_HOT nl_double TERMANALOG(const terminal_t &term) const { return term.net().Q_Analog(); } ATTR_HOT void OUTANALOG(analog_output_t &out, const nl_double val) { diff --git a/src/lib/netlist/nl_util.h b/src/lib/netlist/nl_util.h index bb5a564dd74..87ec2270231 100644 --- a/src/lib/netlist/nl_util.h +++ b/src/lib/netlist/nl_util.h @@ -41,8 +41,8 @@ private: public: ATTR_HOT inline static float exp(const float x) { return std::exp(x); } - ATTR_HOT inline static double abs(const double x) { return std::abs(x); } - ATTR_HOT inline static float abs(const float x) { return std::abs(x); } + ATTR_HOT inline static double abs(const double x) { return std::fabs(x); } + ATTR_HOT inline static float abs(const float x) { return std::fabs(x); } ATTR_HOT inline static double log(const double x) { return std::log(x); } ATTR_HOT inline static float log(const float x) { return std::log(x); } #if defined(_MSC_VER) && _MSC_VER < 1800 diff --git a/src/lib/netlist/plib/pfmtlog.h b/src/lib/netlist/plib/pfmtlog.h index 7a63d14fc3a..d72bdc6ce6b 100644 --- a/src/lib/netlist/plib/pfmtlog.h +++ b/src/lib/netlist/plib/pfmtlog.h @@ -110,6 +110,10 @@ public: ATTR_COLD P & e(const double x, const char *f = "") { format_element(f, "", "e", x); return static_cast<P &>(*this); } ATTR_COLD P & g(const double x, const char *f = "") { format_element(f, "", "g", x); return static_cast<P &>(*this); } + ATTR_COLD P &operator ()(const float x, const char *f = "") { format_element(f, "", "f", x); return static_cast<P &>(*this); } + ATTR_COLD P & e(const float x, const char *f = "") { format_element(f, "", "e", x); return static_cast<P &>(*this); } + ATTR_COLD P & g(const float x, const char *f = "") { format_element(f, "", "g", x); return static_cast<P &>(*this); } + ATTR_COLD P &operator ()(const char *x, const char *f = "") { format_element(f, "", "s", x); return static_cast<P &>(*this); } ATTR_COLD P &operator ()(char *x, const char *f = "") { format_element(f, "", "s", x); return static_cast<P &>(*this); } ATTR_COLD P &operator ()(const void *x, const char *f = "") { format_element(f, "", "p", x); return static_cast<P &>(*this); } diff --git a/src/lib/netlist/solver/nld_matrix_solver.h b/src/lib/netlist/solver/nld_matrix_solver.h new file mode 100644 index 00000000000..715eab6756a --- /dev/null +++ b/src/lib/netlist/solver/nld_matrix_solver.h @@ -0,0 +1,144 @@ +// license:GPL-2.0+ +// copyright-holders:Couriersud +/* + * nld_matrix_solver.h + * + */ + +#ifndef NLD_MATRIX_SOLVER_H_ +#define NLD_MATRIX_SOLVER_H_ + +#include "solver/nld_solver.h" + +NETLIB_NAMESPACE_DEVICES_START() + +class terms_t +{ + P_PREVENT_COPYING(terms_t) + + public: + ATTR_COLD terms_t() : m_railstart(0) + {} + + ATTR_COLD void clear() + { + m_term.clear(); + m_net_other.clear(); + m_gt.clear(); + m_go.clear(); + m_Idr.clear(); + m_other_curanalog.clear(); + } + + ATTR_COLD void add(terminal_t *term, int net_other, bool sorted); + + inline unsigned count() { return m_term.size(); } + + inline terminal_t **terms() { return m_term.data(); } + inline int *net_other() { return m_net_other.data(); } + inline nl_double *gt() { return m_gt.data(); } + inline nl_double *go() { return m_go.data(); } + inline nl_double *Idr() { return m_Idr.data(); } + inline nl_double **other_curanalog() { return m_other_curanalog.data(); } + + ATTR_COLD void set_pointers(); + + unsigned m_railstart; + + pvector_t<unsigned> m_nz; /* all non zero for multiplication */ + pvector_t<unsigned> m_nzrd; /* non zero right of the diagonal for elimination, may include RHS element */ + pvector_t<unsigned> m_nzbd; /* non zero below of the diagonal for elimination */ +private: + pvector_t<terminal_t *> m_term; + pvector_t<int> m_net_other; + pvector_t<nl_double> m_go; + pvector_t<nl_double> m_gt; + pvector_t<nl_double> m_Idr; + pvector_t<nl_double *> m_other_curanalog; +}; + +class matrix_solver_t : public device_t +{ +public: + typedef pvector_t<matrix_solver_t *> list_t; + typedef core_device_t::list_t dev_list_t; + + enum eSolverType + { + GAUSSIAN_ELIMINATION, + GAUSS_SEIDEL + }; + + matrix_solver_t(const eSolverType type, const solver_parameters_t *params); + virtual ~matrix_solver_t(); + + void setup(analog_net_t::list_t &nets) { vsetup(nets); } + + netlist_time solve_base(); + + netlist_time solve(); + + inline bool is_dynamic() const { return m_dynamic_devices.size() > 0; } + inline bool is_timestep() const { return m_step_devices.size() > 0; } + + void update_forced(); + void update_after(const netlist_time after) + { + m_Q_sync.net().reschedule_in_queue(after); + } + + /* netdevice functions */ + virtual void update() override; + virtual void start() override; + virtual void reset() override; + + ATTR_COLD int get_net_idx(net_t *net); + + eSolverType type() const { return m_type; } + plog_base<NL_DEBUG> &log() { return netlist().log(); } + + virtual void log_stats(); + +protected: + + ATTR_COLD void setup_base(analog_net_t::list_t &nets); + void update_dynamic(); + + virtual void add_term(int net_idx, terminal_t *term) = 0; + virtual void vsetup(analog_net_t::list_t &nets) = 0; + virtual int vsolve_non_dynamic(const bool newton_raphson) = 0; + virtual netlist_time compute_next_timestep() = 0; + + pvector_t<analog_net_t *> m_nets; + pvector_t<analog_output_t *> m_inps; + + int m_stat_calculations; + int m_stat_newton_raphson; + int m_stat_vsolver_calls; + int m_iterative_fail; + int m_iterative_total; + + const solver_parameters_t &m_params; + + inline nl_double current_timestep() { return m_cur_ts; } +private: + + netlist_time m_last_step; + nl_double m_cur_ts; + dev_list_t m_step_devices; + dev_list_t m_dynamic_devices; + + logic_input_t m_fb_sync; + logic_output_t m_Q_sync; + + void step(const netlist_time &delta); + + void update_inputs(); + + const eSolverType m_type; +}; + + +NETLIB_NAMESPACE_DEVICES_END() + +#endif /* NLD_MS_DIRECT_H_ */ diff --git a/src/lib/netlist/solver/nld_ms_direct.h b/src/lib/netlist/solver/nld_ms_direct.h index bdcec31ad44..6911e6aa360 100644 --- a/src/lib/netlist/solver/nld_ms_direct.h +++ b/src/lib/netlist/solver/nld_ms_direct.h @@ -13,11 +13,18 @@ #include "solver/nld_solver.h" #include "solver/vector_base.h" +/* Disabling dynamic allocation gives a ~10% boost in performance + * This flag has been added to support continuous storage for arrays + * going forward in case we implement cuda solvers in the future. + */ +#define NL_USE_DYNAMIC_ALLOCATION (0) + + NETLIB_NAMESPACE_DEVICES_START() //#define nl_ext_double __float128 // slow, very slow //#define nl_ext_double long double // slightly slower -#define nl_ext_double double +#define nl_ext_double nl_double template <unsigned m_N, unsigned _storage_N> class matrix_solver_direct_t: public matrix_solver_t @@ -32,48 +39,57 @@ public: virtual void vsetup(analog_net_t::list_t &nets) override; virtual void reset() override { matrix_solver_t::reset(); } - ATTR_HOT inline unsigned N() const { if (m_N == 0) return m_dim; else return m_N; } - - ATTR_HOT inline int vsolve_non_dynamic(const bool newton_raphson); - protected: virtual void add_term(int net_idx, terminal_t *term) override; + virtual int vsolve_non_dynamic(const bool newton_raphson) override; + int solve_non_dynamic(const bool newton_raphson); - ATTR_HOT virtual nl_double vsolve() override; + inline const unsigned N() const { if (m_N == 0) return m_dim; else return m_N; } - ATTR_HOT int solve_non_dynamic(const bool newton_raphson); - ATTR_HOT void build_LE_A(); - ATTR_HOT void build_LE_RHS(nl_double * RESTRICT rhs); - ATTR_HOT void LE_solve(); - ATTR_HOT void LE_back_subst(nl_double * RESTRICT x); + void build_LE_A(); + void build_LE_RHS(); + void LE_solve(); - /* Full LU back substitution, not used currently, in for future use */ + template <typename T> + void LE_back_subst(T * RESTRICT x); - ATTR_HOT void LE_back_subst_full(nl_double * RESTRICT x); + template <typename T> + T delta(const T * RESTRICT V); - ATTR_HOT nl_double delta(const nl_double * RESTRICT V); - ATTR_HOT void store(const nl_double * RESTRICT V); + template <typename T> + void store(const T * RESTRICT V); - /* bring the whole system to the current time - * Don't schedule a new calculation time. The recalculation has to be - * triggered by the caller after the netlist element was changed. - */ - ATTR_HOT nl_double compute_next_timestep(); + virtual netlist_time compute_next_timestep() override; +#if (NL_USE_DYNAMIC_ALLOCATION) template <typename T1, typename T2> - inline nl_ext_double &A(const T1 r, const T2 c) { return m_A[r][c]; } - - ATTR_ALIGN nl_double m_RHS[_storage_N]; + inline nl_ext_double &A(const T1 &r, const T2 &c) { return m_A[r * m_pitch + c]; } + template <typename T1> + inline nl_ext_double &RHS(const T1 &r) { return m_A[r * m_pitch + N()]; } +#else + template <typename T1, typename T2> + inline nl_ext_double &A(const T1 &r, const T2 &c) { return m_A[r][c]; } + template <typename T1> + inline nl_ext_double &RHS(const T1 &r) { return m_A[r][N()]; } +#endif ATTR_ALIGN nl_double m_last_RHS[_storage_N]; // right hand side - contains currents ATTR_ALIGN nl_double m_last_V[_storage_N]; - terms_t **m_terms; + terms_t * m_terms[_storage_N]; terms_t *m_rails_temp; private: - ATTR_ALIGN nl_ext_double m_A[_storage_N][((_storage_N + 7) / 8) * 8]; + static const std::size_t m_pitch = (((_storage_N + 1) + 7) / 8) * 8; +#if (NL_USE_DYNAMIC_ALLOCATION) + ATTR_ALIGN nl_ext_double * RESTRICT m_A; +#else + ATTR_ALIGN nl_ext_double m_A[_storage_N][m_pitch]; + ATTR_ALIGN nl_ext_double m_B[_storage_N][m_pitch]; +#endif + //ATTR_ALIGN nl_ext_double m_RHSx[_storage_N]; const unsigned m_dim; + }; // ---------------------------------------------------------------------------------------- @@ -87,12 +103,14 @@ matrix_solver_direct_t<m_N, _storage_N>::~matrix_solver_direct_t() { pfree(m_terms[k]); } - pfree_array(m_terms); pfree_array(m_rails_temp); +#if (NL_USE_DYNAMIC_ALLOCATION) + pfree_array(m_A); +#endif } template <unsigned m_N, unsigned _storage_N> -ATTR_HOT nl_double matrix_solver_direct_t<m_N, _storage_N>::compute_next_timestep() +netlist_time matrix_solver_direct_t<m_N, _storage_N>::compute_next_timestep() { nl_double new_solver_timestep = m_params.m_max_timestep; @@ -121,13 +139,15 @@ ATTR_HOT nl_double matrix_solver_direct_t<m_N, _storage_N>::compute_next_timeste if (new_net_timestep < new_solver_timestep) new_solver_timestep = new_net_timestep; + + m_last_V[k] = n->Q_Analog(); } if (new_solver_timestep < m_params.m_min_timestep) new_solver_timestep = m_params.m_min_timestep; } //if (new_solver_timestep > 10.0 * hn) // new_solver_timestep = 10.0 * hn; - return new_solver_timestep; + return netlist_time::from_double(new_solver_timestep); } template <unsigned m_N, unsigned _storage_N> @@ -166,7 +186,7 @@ ATTR_COLD void matrix_solver_direct_t<m_N, _storage_N>::vsetup(analog_net_t::lis m_rails_temp[k].clear(); } - matrix_solver_t::setup(nets); + matrix_solver_t::setup_base(nets); for (unsigned k = 0; k < N(); k++) { @@ -249,19 +269,23 @@ ATTR_COLD void matrix_solver_direct_t<m_N, _storage_N>::vsetup(analog_net_t::lis } } - for (unsigned j = 0; j < N(); j++) + for (unsigned i = 0; i < t->m_railstart; i++) { - for (unsigned i = 0; i < t->m_railstart; i++) - { - if (!t->m_nzrd.contains(other[i]) && other[i] >= (int) (k + 1)) - t->m_nzrd.push_back(other[i]); - if (!t->m_nz.contains(other[i])) - t->m_nz.push_back(other[i]); - } + if (!t->m_nzrd.contains(other[i]) && other[i] >= (int) (k + 1)) + t->m_nzrd.push_back(other[i]); + if (!t->m_nz.contains(other[i])) + t->m_nz.push_back(other[i]); } + + /* Add RHS element */ + if (!t->m_nzrd.contains(N())) + t->m_nzrd.push_back(N()); + + /* and sort */ psort_list(t->m_nzrd); t->m_nz.push_back(k); // add diagonal + psort_list(t->m_nz); } @@ -304,7 +328,6 @@ ATTR_COLD void matrix_solver_direct_t<m_N, _storage_N>::vsetup(analog_net_t::lis /* * save states */ - save(NLNAME(m_RHS)); save(NLNAME(m_last_RHS)); save(NLNAME(m_last_V)); @@ -312,6 +335,8 @@ ATTR_COLD void matrix_solver_direct_t<m_N, _storage_N>::vsetup(analog_net_t::lis { pstring num = pfmt("{1}")(k); + save(RHS(k), "RHS" + num); + save(m_terms[k]->go(),"GO" + num, m_terms[k]->count()); save(m_terms[k]->gt(),"GT" + num, m_terms[k]->count()); save(m_terms[k]->Idr(),"IDR" + num , m_terms[k]->count()); @@ -321,7 +346,7 @@ ATTR_COLD void matrix_solver_direct_t<m_N, _storage_N>::vsetup(analog_net_t::lis template <unsigned m_N, unsigned _storage_N> -ATTR_HOT void matrix_solver_direct_t<m_N, _storage_N>::build_LE_A() +void matrix_solver_direct_t<m_N, _storage_N>::build_LE_A() { const unsigned iN = N(); for (unsigned k = 0; k < iN; k++) @@ -350,7 +375,7 @@ ATTR_HOT void matrix_solver_direct_t<m_N, _storage_N>::build_LE_A() } template <unsigned m_N, unsigned _storage_N> -ATTR_HOT void matrix_solver_direct_t<m_N, _storage_N>::build_LE_RHS(nl_double * RESTRICT rhs) +void matrix_solver_direct_t<m_N, _storage_N>::build_LE_RHS() { const unsigned iN = N(); for (unsigned k = 0; k < iN; k++) @@ -370,12 +395,12 @@ ATTR_HOT void matrix_solver_direct_t<m_N, _storage_N>::build_LE_RHS(nl_double * //rhsk = rhsk + go[i] * terms[i]->m_otherterm->net().as_analog().Q_Analog(); rhsk_b = rhsk_b + go[i] * *other_cur_analog[i]; - rhs[k] = rhsk_a + rhsk_b; + RHS(k) = rhsk_a + rhsk_b; } } template <unsigned m_N, unsigned _storage_N> -ATTR_HOT void matrix_solver_direct_t<m_N, _storage_N>::LE_solve() +void matrix_solver_direct_t<m_N, _storage_N>::LE_solve() { const unsigned kN = N(); @@ -395,10 +420,10 @@ ATTR_HOT void matrix_solver_direct_t<m_N, _storage_N>::LE_solve() if (maxrow != i) { /* Swap the maxrow and ith row */ - for (unsigned k = 0; k < kN; k++) { + for (unsigned k = 0; k < kN + 1; k++) { std::swap(A(i,k), A(maxrow,k)); } - std::swap(m_RHS[i], m_RHS[maxrow]); + //std::swap(RHS(i), RHS(maxrow)); } /* FIXME: Singular matrix? */ const nl_double f = 1.0 / A(i,i); @@ -410,14 +435,18 @@ ATTR_HOT void matrix_solver_direct_t<m_N, _storage_N>::LE_solve() const nl_double f1 = - A(j,i) * f; if (f1 != NL_FCONST(0.0)) { - nl_double * RESTRICT pi = &m_A[i][i+1]; - nl_double * RESTRICT pj = &m_A[j][i+1]; + const nl_double * RESTRICT pi = &A(i,i+1); + nl_double * RESTRICT pj = &A(j,i+1); +#if 1 + vec_add_mult_scalar(kN-i,pi,f1,pj); +#else vec_add_mult_scalar(kN-i-1,pj,f1,pi); //for (unsigned k = i+1; k < kN; k++) // pj[k] = pj[k] + pi[k] * f1; //for (unsigned k = i+1; k < kN; k++) //A(j,k) += A(i,k) * f1; - m_RHS[j] += m_RHS[i] * f1; + RHS(j) += RHS(i) * f1; +#endif } } } @@ -436,23 +465,18 @@ ATTR_HOT void matrix_solver_direct_t<m_N, _storage_N>::LE_solve() { const unsigned j = pb[jb]; const nl_double f1 = - A(j,i) * f; -#if 0 - nl_double * RESTRICT pi = &m_A[i][i+1]; - nl_double * RESTRICT pj = &m_A[j][i+1]; - vec_add_mult_scalar(kN-i-1,pi,f1,pj); -#else for (unsigned k = 0; k < e; k++) A(j,p[k]) += A(i,p[k]) * f1; -#endif - m_RHS[j] += m_RHS[i] * f1; + //RHS(j) += RHS(i) * f1; } } } } template <unsigned m_N, unsigned _storage_N> -ATTR_HOT void matrix_solver_direct_t<m_N, _storage_N>::LE_back_subst( - nl_double * RESTRICT x) +template <typename T> +void matrix_solver_direct_t<m_N, _storage_N>::LE_back_subst( + T * RESTRICT x) { const unsigned kN = N(); @@ -461,68 +485,36 @@ ATTR_HOT void matrix_solver_direct_t<m_N, _storage_N>::LE_back_subst( { for (int j = kN - 1; j >= 0; j--) { - nl_double tmp = 0; + T tmp = 0; for (unsigned k = j+1; k < kN; k++) tmp += A(j,k) * x[k]; - x[j] = (m_RHS[j] - tmp) / A(j,j); + x[j] = (RHS(j) - tmp) / A(j,j); } } else { for (int j = kN - 1; j >= 0; j--) { - nl_double tmp = 0; + T tmp = 0; const unsigned *p = m_terms[j]->m_nzrd.data(); - const unsigned e = m_terms[j]->m_nzrd.size(); + const unsigned e = m_terms[j]->m_nzrd.size() - 1; /* exclude RHS element */ for (unsigned k = 0; k < e; k++) { const unsigned pk = p[k]; tmp += A(j,pk) * x[pk]; } - x[j] = (m_RHS[j] - tmp) / A(j,j); + x[j] = (RHS(j) - tmp) / A(j,j); } } } -template <unsigned m_N, unsigned _storage_N> -ATTR_HOT void matrix_solver_direct_t<m_N, _storage_N>::LE_back_subst_full( - nl_double * RESTRICT x) -{ - const unsigned kN = N(); - - /* back substitution */ - - // int ip; - // ii=-1 - - //for (int i=0; i < kN; i++) - // x[i] = m_RHS[i]; - - for (int i=0; i < kN; i++) - { - //ip=indx[i]; USE_PIVOT_SEARCH - //sum=b[ip]; - //b[ip]=b[i]; - double sum=m_RHS[i];//x[i]; - for (int j=0; j < i; j++) - sum -= A(i,j) * x[j]; - x[i]=sum; - } - for (int i=kN-1; i >= 0; i--) - { - double sum=x[i]; - for (int j = i+1; j < kN; j++) - sum -= A(i,j)*x[j]; - x[i] = sum / A(i,i); - } - -} template <unsigned m_N, unsigned _storage_N> -ATTR_HOT nl_double matrix_solver_direct_t<m_N, _storage_N>::delta( - const nl_double * RESTRICT V) +template <typename T> +T matrix_solver_direct_t<m_N, _storage_N>::delta( + const T * RESTRICT V) { /* FIXME: Ideally we should also include currents (RHS) here. This would * need a revaluation of the right hand side after voltages have been updated @@ -530,15 +522,16 @@ ATTR_HOT nl_double matrix_solver_direct_t<m_N, _storage_N>::delta( */ const unsigned iN = this->N(); - nl_double cerr = 0; + T cerr = 0; for (unsigned i = 0; i < iN; i++) - cerr = std::max(cerr, nl_math::abs(V[i] - this->m_nets[i]->m_cur_Analog)); + cerr = std::fmax(cerr, nl_math::abs(V[i] - (T) this->m_nets[i]->m_cur_Analog)); return cerr; } template <unsigned m_N, unsigned _storage_N> -ATTR_HOT void matrix_solver_direct_t<m_N, _storage_N>::store( - const nl_double * RESTRICT V) +template <typename T> +void matrix_solver_direct_t<m_N, _storage_N>::store( + const T * RESTRICT V) { for (unsigned i = 0, iN=N(); i < iN; i++) { @@ -546,19 +539,13 @@ ATTR_HOT void matrix_solver_direct_t<m_N, _storage_N>::store( } } -template <unsigned m_N, unsigned _storage_N> -ATTR_HOT nl_double matrix_solver_direct_t<m_N, _storage_N>::vsolve() -{ - this->solve_base(this); - return this->compute_next_timestep(); -} - template <unsigned m_N, unsigned _storage_N> -ATTR_HOT int matrix_solver_direct_t<m_N, _storage_N>::solve_non_dynamic(ATTR_UNUSED const bool newton_raphson) +int matrix_solver_direct_t<m_N, _storage_N>::solve_non_dynamic(ATTR_UNUSED const bool newton_raphson) { nl_double new_V[_storage_N]; // = { 0.0 }; + this->LE_solve(); this->LE_back_subst(new_V); if (newton_raphson) @@ -577,18 +564,15 @@ ATTR_HOT int matrix_solver_direct_t<m_N, _storage_N>::solve_non_dynamic(ATTR_UNU } template <unsigned m_N, unsigned _storage_N> -ATTR_HOT inline int matrix_solver_direct_t<m_N, _storage_N>::vsolve_non_dynamic(const bool newton_raphson) +inline int matrix_solver_direct_t<m_N, _storage_N>::vsolve_non_dynamic(const bool newton_raphson) { this->build_LE_A(); - this->build_LE_RHS(m_last_RHS); + this->build_LE_RHS(); for (unsigned i=0, iN=N(); i < iN; i++) - m_RHS[i] = m_last_RHS[i]; - - this->LE_solve(); + m_last_RHS[i] = RHS(i); this->m_stat_calculations++; - return this->solve_non_dynamic(newton_raphson); } @@ -597,9 +581,10 @@ matrix_solver_direct_t<m_N, _storage_N>::matrix_solver_direct_t(const solver_par : matrix_solver_t(GAUSSIAN_ELIMINATION, params) , m_dim(size) { - m_terms = palloc_array(terms_t *, N()); m_rails_temp = palloc_array(terms_t, N()); - +#if (NL_USE_DYNAMIC_ALLOCATION) + m_A = palloc_array(nl_ext_double, N() * m_pitch); +#endif for (unsigned k = 0; k < N(); k++) { m_terms[k] = palloc(terms_t); @@ -613,9 +598,10 @@ matrix_solver_direct_t<m_N, _storage_N>::matrix_solver_direct_t(const eSolverTyp : matrix_solver_t(type, params) , m_dim(size) { - m_terms = palloc_array(terms_t *, N()); m_rails_temp = palloc_array(terms_t, N()); - +#if (NL_USE_DYNAMIC_ALLOCATION) + m_A = palloc_array(nl_ext_double, N() * m_pitch); +#endif for (unsigned k = 0; k < N(); k++) { m_terms[k] = palloc(terms_t); diff --git a/src/lib/netlist/solver/nld_ms_direct1.h b/src/lib/netlist/solver/nld_ms_direct1.h index fe5a439a9db..ab19c92a4cb 100644 --- a/src/lib/netlist/solver/nld_ms_direct1.h +++ b/src/lib/netlist/solver/nld_ms_direct1.h @@ -20,43 +20,33 @@ public: matrix_solver_direct1_t(const solver_parameters_t *params) : matrix_solver_direct_t<1, 1>(params, 1) {} - ATTR_HOT inline int vsolve_non_dynamic(const bool newton_raphson); -protected: - ATTR_HOT virtual nl_double vsolve() override; -private: + virtual int vsolve_non_dynamic(const bool newton_raphson) override; + }; // ---------------------------------------------------------------------------------------- // matrix_solver - Direct1 // ---------------------------------------------------------------------------------------- -ATTR_HOT nl_double matrix_solver_direct1_t::vsolve() -{ - solve_base<matrix_solver_direct1_t>(this); - return this->compute_next_timestep(); -} - -ATTR_HOT inline int matrix_solver_direct1_t::vsolve_non_dynamic(ATTR_UNUSED const bool newton_raphson) +inline int matrix_solver_direct1_t::vsolve_non_dynamic(ATTR_UNUSED const bool newton_raphson) { - analog_net_t *net = m_nets[0]; this->build_LE_A(); - this->build_LE_RHS(m_RHS); + this->build_LE_RHS(); //NL_VERBOSE_OUT(("{1} {2}\n", new_val, m_RHS[0] / m_A[0][0]); - nl_double new_val = m_RHS[0] / A(0,0); + nl_double new_val[1] = { RHS(0) / A(0,0) }; - nl_double e = (new_val - net->Q_Analog()); - nl_double cerr = nl_math::abs(e); - - net->m_cur_Analog = new_val; - - if (is_dynamic() && (cerr > m_params.m_accuracy)) + if (is_dynamic()) { - return 2; + nl_double err = this->delta(new_val); + store(new_val); + if (err > m_params.m_accuracy ) + return 2; + else + return 1; } - else - return 1; - + store(new_val); + return 1; } NETLIB_NAMESPACE_DEVICES_END() diff --git a/src/lib/netlist/solver/nld_ms_direct2.h b/src/lib/netlist/solver/nld_ms_direct2.h index 06f00302d3c..2488e573bf2 100644 --- a/src/lib/netlist/solver/nld_ms_direct2.h +++ b/src/lib/netlist/solver/nld_ms_direct2.h @@ -20,26 +20,18 @@ public: matrix_solver_direct2_t(const solver_parameters_t *params) : matrix_solver_direct_t<2, 2>(params, 2) {} - ATTR_HOT inline int vsolve_non_dynamic(const bool newton_raphson); -protected: - ATTR_HOT virtual nl_double vsolve() override; -private: + virtual int vsolve_non_dynamic(const bool newton_raphson) override; + }; // ---------------------------------------------------------------------------------------- // matrix_solver - Direct2 // ---------------------------------------------------------------------------------------- -ATTR_HOT nl_double matrix_solver_direct2_t::vsolve() -{ - solve_base<matrix_solver_direct2_t>(this); - return this->compute_next_timestep(); -} - -ATTR_HOT inline int matrix_solver_direct2_t::vsolve_non_dynamic(ATTR_UNUSED const bool newton_raphson) +inline int matrix_solver_direct2_t::vsolve_non_dynamic(ATTR_UNUSED const bool newton_raphson) { build_LE_A(); - build_LE_RHS(m_RHS); + build_LE_RHS(); const nl_double a = A(0,0); const nl_double b = A(0,1); @@ -47,8 +39,8 @@ ATTR_HOT inline int matrix_solver_direct2_t::vsolve_non_dynamic(ATTR_UNUSED cons const nl_double d = A(1,1); nl_double new_val[2]; - new_val[1] = (a * m_RHS[1] - c * m_RHS[0]) / (a * d - b * c); - new_val[0] = (m_RHS[0] - b * new_val[1]) / a; + new_val[1] = (a * RHS(1) - c * RHS(0)) / (a * d - b * c); + new_val[0] = (RHS(0) - b * new_val[1]) / a; if (is_dynamic()) { diff --git a/src/lib/netlist/solver/nld_ms_direct_lu.h b/src/lib/netlist/solver/nld_ms_direct_lu.h index 07b3b9cb568..2109b0f3e41 100644 --- a/src/lib/netlist/solver/nld_ms_direct_lu.h +++ b/src/lib/netlist/solver/nld_ms_direct_lu.h @@ -33,18 +33,16 @@ public: virtual void vsetup(analog_net_t::list_t &nets) override; virtual void reset() override { matrix_solver_t::reset(); } - ATTR_HOT inline unsigned N() const { if (m_N == 0) return m_dim; else return m_N; } + inline unsigned N() const { if (m_N == 0) return m_dim; else return m_N; } - ATTR_HOT inline int vsolve_non_dynamic(const bool newton_raphson); + inline int vsolve_non_dynamic(const bool newton_raphson); protected: virtual void add_term(int net_idx, terminal_t *term) override; - ATTR_HOT virtual nl_double vsolve() override; - - ATTR_HOT int solve_non_dynamic(const bool newton_raphson); - ATTR_HOT void build_LE_A(); - ATTR_HOT void build_LE_RHS(nl_double * RESTRICT rhs); + int solve_non_dynamic(const bool newton_raphson); + void build_LE_A(); + void build_LE_RHS(nl_double * RESTRICT rhs); template<unsigned k> void LEk() @@ -68,7 +66,7 @@ protected: } } - ATTR_HOT void LE_solve() + void LE_solve() { const unsigned kN = N(); unsigned sk = 1; @@ -127,15 +125,15 @@ protected: } } } - ATTR_HOT void LE_back_subst(nl_double * RESTRICT x); - ATTR_HOT nl_double delta(const nl_double * RESTRICT V); - ATTR_HOT void store(const nl_double * RESTRICT V); + void LE_back_subst(nl_double * RESTRICT x); + nl_double delta(const nl_double * RESTRICT V); + void store(const nl_double * RESTRICT V); /* bring the whole system to the current time * Don't schedule a new calculation time. The recalculation has to be * triggered by the caller after the netlist element was changed. */ - ATTR_HOT nl_double compute_next_timestep(); + nl_double compute_next_timestep(); template <typename T1, typename T2> inline nl_ext_double &A(const T1 r, const T2 c) { return m_A[r][c]; } @@ -171,7 +169,7 @@ matrix_solver_direct_t<m_N, _storage_N>::~matrix_solver_direct_t() } template <unsigned m_N, unsigned _storage_N> -ATTR_HOT nl_double matrix_solver_direct_t<m_N, _storage_N>::compute_next_timestep() +nl_double matrix_solver_direct_t<m_N, _storage_N>::compute_next_timestep() { nl_double new_solver_timestep = m_params.m_max_timestep; @@ -245,7 +243,7 @@ ATTR_COLD void matrix_solver_direct_t<m_N, _storage_N>::vsetup(analog_net_t::lis m_rails_temp[k].clear(); } - matrix_solver_t::setup(nets); + matrix_solver_t::setup_base(nets); for (unsigned k = 0; k < N(); k++) { @@ -373,7 +371,7 @@ ATTR_COLD void matrix_solver_direct_t<m_N, _storage_N>::vsetup(analog_net_t::lis template <unsigned m_N, unsigned _storage_N> -ATTR_HOT void matrix_solver_direct_t<m_N, _storage_N>::build_LE_A() +void matrix_solver_direct_t<m_N, _storage_N>::build_LE_A() { const unsigned iN = N(); for (unsigned k = 0; k < iN; k++) @@ -399,7 +397,7 @@ ATTR_HOT void matrix_solver_direct_t<m_N, _storage_N>::build_LE_A() } template <unsigned m_N, unsigned _storage_N> -ATTR_HOT void matrix_solver_direct_t<m_N, _storage_N>::build_LE_RHS(nl_double * RESTRICT rhs) +void matrix_solver_direct_t<m_N, _storage_N>::build_LE_RHS(nl_double * RESTRICT rhs) { const unsigned iN = N(); for (unsigned k = 0; k < iN; k++) @@ -427,7 +425,7 @@ ATTR_HOT void matrix_solver_direct_t<m_N, _storage_N>::build_LE_RHS(nl_double * #else // Crout algo template <unsigned m_N, unsigned _storage_N> -ATTR_HOT void matrix_solver_direct_t<m_N, _storage_N>::LE_solve() +void matrix_solver_direct_t<m_N, _storage_N>::LE_solve() { const unsigned kN = N(); @@ -509,7 +507,7 @@ ATTR_HOT void matrix_solver_direct_t<m_N, _storage_N>::LE_solve() #endif template <unsigned m_N, unsigned _storage_N> -ATTR_HOT void matrix_solver_direct_t<m_N, _storage_N>::LE_back_subst( +void matrix_solver_direct_t<m_N, _storage_N>::LE_back_subst( nl_double * RESTRICT x) { const unsigned kN = N(); @@ -543,7 +541,7 @@ ATTR_HOT void matrix_solver_direct_t<m_N, _storage_N>::LE_back_subst( } template <unsigned m_N, unsigned _storage_N> -ATTR_HOT nl_double matrix_solver_direct_t<m_N, _storage_N>::delta( +nl_double matrix_solver_direct_t<m_N, _storage_N>::delta( const nl_double * RESTRICT V) { /* FIXME: Ideally we should also include currents (RHS) here. This would @@ -554,12 +552,12 @@ ATTR_HOT nl_double matrix_solver_direct_t<m_N, _storage_N>::delta( const unsigned iN = this->N(); nl_double cerr = 0; for (unsigned i = 0; i < iN; i++) - cerr = std::max(cerr, nl_math::abs(V[i] - this->m_nets[i]->m_cur_Analog)); + cerr = std::fmax(cerr, nl_math::abs(V[i] - this->m_nets[i]->m_cur_Analog)); return cerr; } template <unsigned m_N, unsigned _storage_N> -ATTR_HOT void matrix_solver_direct_t<m_N, _storage_N>::store( +void matrix_solver_direct_t<m_N, _storage_N>::store( const nl_double * RESTRICT V) { for (unsigned i = 0, iN=N(); i < iN; i++) @@ -568,16 +566,9 @@ ATTR_HOT void matrix_solver_direct_t<m_N, _storage_N>::store( } } -template <unsigned m_N, unsigned _storage_N> -ATTR_HOT nl_double matrix_solver_direct_t<m_N, _storage_N>::vsolve() -{ - this->solve_base(this); - return this->compute_next_timestep(); -} - template <unsigned m_N, unsigned _storage_N> -ATTR_HOT int matrix_solver_direct_t<m_N, _storage_N>::solve_non_dynamic(ATTR_UNUSED const bool newton_raphson) +int matrix_solver_direct_t<m_N, _storage_N>::solve_non_dynamic(ATTR_UNUSED const bool newton_raphson) { nl_double new_V[_storage_N]; // = { 0.0 }; @@ -599,7 +590,7 @@ ATTR_HOT int matrix_solver_direct_t<m_N, _storage_N>::solve_non_dynamic(ATTR_UNU } template <unsigned m_N, unsigned _storage_N> -ATTR_HOT inline int matrix_solver_direct_t<m_N, _storage_N>::vsolve_non_dynamic(const bool newton_raphson) +inline int matrix_solver_direct_t<m_N, _storage_N>::vsolve_non_dynamic(const bool newton_raphson) { this->build_LE_A(); this->build_LE_RHS(m_last_RHS); @@ -607,8 +598,6 @@ ATTR_HOT inline int matrix_solver_direct_t<m_N, _storage_N>::vsolve_non_dynamic( for (unsigned i=0, iN=N(); i < iN; i++) m_RHS[i] = m_last_RHS[i]; - this->LE_solve(); - return this->solve_non_dynamic(newton_raphson); } diff --git a/src/lib/netlist/solver/nld_ms_gmres.h b/src/lib/netlist/solver/nld_ms_gmres.h index 0ae7f5eab56..6ff0d43f421 100644 --- a/src/lib/netlist/solver/nld_ms_gmres.h +++ b/src/lib/netlist/solver/nld_ms_gmres.h @@ -54,13 +54,11 @@ public: } virtual void vsetup(analog_net_t::list_t &nets) override; - ATTR_HOT virtual int vsolve_non_dynamic(const bool newton_raphson); -protected: - ATTR_HOT virtual nl_double vsolve() override; + virtual int vsolve_non_dynamic(const bool newton_raphson) override; private: - int solve_ilu_gmres(nl_double * RESTRICT x, nl_double * RESTRICT rhs, const unsigned restart_max, const unsigned mr, nl_double accuracy); + int solve_ilu_gmres(nl_double * RESTRICT x, const nl_double * RESTRICT rhs, const unsigned restart_max, const unsigned mr, nl_double accuracy); pvector_t<int> m_term_cr[_storage_N]; @@ -126,14 +124,7 @@ void matrix_solver_GMRES_t<m_N, _storage_N>::vsetup(analog_net_t::list_t &nets) } template <unsigned m_N, unsigned _storage_N> -ATTR_HOT nl_double matrix_solver_GMRES_t<m_N, _storage_N>::vsolve() -{ - this->solve_base(this); - return this->compute_next_timestep(); -} - -template <unsigned m_N, unsigned _storage_N> -ATTR_HOT inline int matrix_solver_GMRES_t<m_N, _storage_N>::vsolve_non_dynamic(const bool newton_raphson) +int matrix_solver_GMRES_t<m_N, _storage_N>::vsolve_non_dynamic(const bool newton_raphson) { const unsigned iN = this->N(); @@ -166,6 +157,7 @@ ATTR_HOT inline int matrix_solver_GMRES_t<m_N, _storage_N>::vsolve_non_dynamic(c const nl_double * const * RESTRICT other_cur_analog = this->m_terms[k]->other_curanalog(); l_V[k] = new_V[k] = this->m_nets[k]->m_cur_Analog; + for (unsigned i = 0; i < term_count; i++) { gtot_t = gtot_t + gt[i]; @@ -189,7 +181,7 @@ ATTR_HOT inline int matrix_solver_GMRES_t<m_N, _storage_N>::vsolve_non_dynamic(c mat.ia[iN] = mat.nz_num; const nl_double accuracy = this->m_params.m_accuracy; -#if 1 + int mr = _storage_N; if (_storage_N > 3 ) mr = (int) sqrt(iN); @@ -197,19 +189,12 @@ ATTR_HOT inline int matrix_solver_GMRES_t<m_N, _storage_N>::vsolve_non_dynamic(c int iter = 4; int gsl = solve_ilu_gmres(new_V, RHS, iter, mr, accuracy); int failed = mr * iter; -#else - int failed = 6; - //int gsl = tt_ilu_cr(new_V, RHS, failed, accuracy); - int gsl = tt_gs_cr(new_V, RHS, failed, accuracy); -#endif + this->m_iterative_total += gsl; this->m_stat_calculations++; if (gsl>=failed) { - //for (int k = 0; k < iN; k++) - // this->m_nets[k]->m_cur_Analog = new_V[k]; - // Fallback to direct solver ... this->m_iterative_fail++; return matrix_solver_direct_t<m_N, _storage_N>::vsolve_non_dynamic(newton_raphson); } @@ -235,17 +220,18 @@ ATTR_HOT inline int matrix_solver_GMRES_t<m_N, _storage_N>::vsolve_non_dynamic(c } } -static inline void givens_mult( const nl_double c, const nl_double s, nl_double * RESTRICT g0, nl_double * RESTRICT g1 ) +template <typename T> +inline void givens_mult( const T c, const T s, T & g0, T & g1 ) { - const double tg0 = c * *g0 - s * *g1; - const double tg1 = s * *g0 + c * *g1; + const T tg0 = c * g0 - s * g1; + const T tg1 = s * g0 + c * g1; - *g0 = tg0; - *g1 = tg1; + g0 = tg0; + g1 = tg1; } template <unsigned m_N, unsigned _storage_N> -int matrix_solver_GMRES_t<m_N, _storage_N>::solve_ilu_gmres (nl_double * RESTRICT x, nl_double * RESTRICT rhs, const unsigned restart_max, const unsigned mr, nl_double accuracy) +int matrix_solver_GMRES_t<m_N, _storage_N>::solve_ilu_gmres (nl_double * RESTRICT x, const nl_double * RESTRICT rhs, const unsigned restart_max, const unsigned mr, nl_double accuracy) { /*------------------------------------------------------------------------- * The code below was inspired by code published by John Burkardt under @@ -351,7 +337,7 @@ int matrix_solver_GMRES_t<m_N, _storage_N>::solve_ilu_gmres (nl_double * RESTRIC vec_scale(n, m_v[k1], NL_FCONST(1.0) / m_ht[k1][k]); for (unsigned j = 0; j < k; j++) - givens_mult(m_c[j], m_s[j], &m_ht[j][k], &m_ht[j+1][k]); + givens_mult(m_c[j], m_s[j], m_ht[j][k], m_ht[j+1][k]); mu = std::sqrt(std::pow(m_ht[k][k], 2) + std::pow(m_ht[k1][k], 2)); @@ -360,7 +346,7 @@ int matrix_solver_GMRES_t<m_N, _storage_N>::solve_ilu_gmres (nl_double * RESTRIC m_ht[k][k] = m_c[k] * m_ht[k][k] - m_s[k] * m_ht[k1][k]; m_ht[k1][k] = 0.0; - givens_mult(m_c[k], m_s[k], &m_g[k], &m_g[k1]); + givens_mult(m_c[k], m_s[k], m_g[k], m_g[k1]); rho = std::abs(m_g[k1]); diff --git a/src/lib/netlist/solver/nld_ms_sm.h b/src/lib/netlist/solver/nld_ms_sm.h new file mode 100644 index 00000000000..7336e060510 --- /dev/null +++ b/src/lib/netlist/solver/nld_ms_sm.h @@ -0,0 +1,674 @@ +// license:GPL-2.0+ +// copyright-holders:Couriersud +/* + * nld_ms_direct.h + * + * + * Sherman-Morrison Solver + * + * Computes the updated inverse of A given that the change in A is + * + * A <- A + (u x v) u,v vectors + * + * In this specific implementation, u is a unit vector specifying the row which + * changed. Thus v contains the changed column. + * + * Than z = A⁻¹ u , w = transpose(A⁻¹) v , lambda = v z + * + * A⁻¹ <- 1.0 / (1.0 + lambda) * (z x w) + * + * The approach is iterative and applied for each row changed. + * + * The performance for a typical circuit like kidniki compared to Gaussian + * elimination is poor: + * + * a) The code needs to be run for each row change. + * b) The inverse of A typically is fully occupied. + * + * It may have advantages for circuits with a high number of elements and only + * few dynamic/active components. + * + */ + +#ifndef NLD_MS_SM_H_ +#define NLD_MS_SM_H_ + +#include <algorithm> + +#include "solver/nld_solver.h" +#include "solver/vector_base.h" + +NETLIB_NAMESPACE_DEVICES_START() + +//#define nl_ext_double __float128 // slow, very slow +//#define nl_ext_double long double // slightly slower +#define nl_ext_double nl_double + +template <unsigned m_N, unsigned _storage_N> +class matrix_solver_sm_t: public matrix_solver_t +{ +public: + + matrix_solver_sm_t(const solver_parameters_t *params, const int size); + matrix_solver_sm_t(const eSolverType type, const solver_parameters_t *params, const int size); + + virtual ~matrix_solver_sm_t(); + + virtual void vsetup(analog_net_t::list_t &nets) override; + virtual void reset() override { matrix_solver_t::reset(); } + +protected: + virtual void add_term(int net_idx, terminal_t *term) override; + virtual int vsolve_non_dynamic(const bool newton_raphson) override; + int solve_non_dynamic(const bool newton_raphson); + + inline const unsigned N() const { if (m_N == 0) return m_dim; else return m_N; } + + void build_LE_A(); + void build_LE_RHS(); + void LE_invert(); + + template <typename T> + void LE_compute_x(T * RESTRICT x); + + template <typename T> + T delta(const T * RESTRICT V); + + template <typename T> + void store(const T * RESTRICT V); + + virtual netlist_time compute_next_timestep() override; + + template <typename T1, typename T2> + inline nl_ext_double &A(const T1 &r, const T2 &c) { return m_A[r][c]; } + template <typename T1, typename T2> + inline nl_ext_double &W(const T1 &r, const T2 &c) { return m_W[r][c]; } + template <typename T1, typename T2> + inline nl_ext_double &Ainv(const T1 &r, const T2 &c) { return m_Ainv[r][c]; } + template <typename T1> + inline nl_ext_double &RHS(const T1 &r) { return m_RHS[r]; } + + + template <typename T1, typename T2> + inline nl_ext_double &lA(const T1 &r, const T2 &c) { return m_lA[r][c]; } + template <typename T1, typename T2> + inline nl_ext_double &lAinv(const T1 &r, const T2 &c) { return m_lAinv[r][c]; } + + ATTR_ALIGN nl_double m_last_RHS[_storage_N]; // right hand side - contains currents + ATTR_ALIGN nl_double m_last_V[_storage_N]; + + terms_t * m_terms[_storage_N]; + terms_t *m_rails_temp; + +private: + static const std::size_t m_pitch = ((( _storage_N) + 7) / 8) * 8; + ATTR_ALIGN nl_ext_double m_A[_storage_N][m_pitch]; + ATTR_ALIGN nl_ext_double m_Ainv[_storage_N][m_pitch]; + ATTR_ALIGN nl_ext_double m_W[_storage_N][m_pitch]; + ATTR_ALIGN nl_ext_double m_RHS[_storage_N]; // right hand side - contains currents + + ATTR_ALIGN nl_ext_double m_lA[_storage_N][m_pitch]; + ATTR_ALIGN nl_ext_double m_lAinv[_storage_N][m_pitch]; + + //ATTR_ALIGN nl_ext_double m_RHSx[_storage_N]; + + const unsigned m_dim; + +}; + +// ---------------------------------------------------------------------------------------- +// matrix_solver_direct +// ---------------------------------------------------------------------------------------- + +template <unsigned m_N, unsigned _storage_N> +matrix_solver_sm_t<m_N, _storage_N>::~matrix_solver_sm_t() +{ + for (unsigned k = 0; k < N(); k++) + { + pfree(m_terms[k]); + } + pfree_array(m_rails_temp); +#if (NL_USE_DYNAMIC_ALLOCATION) + pfree_array(m_A); +#endif +} + +template <unsigned m_N, unsigned _storage_N> +netlist_time matrix_solver_sm_t<m_N, _storage_N>::compute_next_timestep() +{ + nl_double new_solver_timestep = m_params.m_max_timestep; + + if (m_params.m_dynamic) + { + /* + * FIXME: We should extend the logic to use either all nets or + * only output nets. + */ + for (unsigned k = 0, iN=N(); k < iN; k++) + { + analog_net_t *n = m_nets[k]; + + const nl_double DD_n = (n->Q_Analog() - m_last_V[k]); + const nl_double hn = current_timestep(); + + nl_double DD2 = (DD_n / hn - n->m_DD_n_m_1 / n->m_h_n_m_1) / (hn + n->m_h_n_m_1); + nl_double new_net_timestep; + + n->m_h_n_m_1 = hn; + n->m_DD_n_m_1 = DD_n; + if (nl_math::abs(DD2) > NL_FCONST(1e-30)) // avoid div-by-zero + new_net_timestep = nl_math::sqrt(m_params.m_lte / nl_math::abs(NL_FCONST(0.5)*DD2)); + else + new_net_timestep = m_params.m_max_timestep; + + if (new_net_timestep < new_solver_timestep) + new_solver_timestep = new_net_timestep; + + m_last_V[k] = n->Q_Analog(); + } + if (new_solver_timestep < m_params.m_min_timestep) + new_solver_timestep = m_params.m_min_timestep; + } + //if (new_solver_timestep > 10.0 * hn) + // new_solver_timestep = 10.0 * hn; + return netlist_time::from_double(new_solver_timestep); +} + +template <unsigned m_N, unsigned _storage_N> +ATTR_COLD void matrix_solver_sm_t<m_N, _storage_N>::add_term(int k, terminal_t *term) +{ + if (term->m_otherterm->net().isRailNet()) + { + m_rails_temp[k].add(term, -1, false); + } + else + { + int ot = get_net_idx(&term->m_otherterm->net()); + if (ot>=0) + { + m_terms[k]->add(term, ot, true); + } + /* Should this be allowed ? */ + else // if (ot<0) + { + m_rails_temp[k].add(term, ot, true); + log().fatal("found term with missing othernet {1}\n", term->name()); + } + } +} + + +template <unsigned m_N, unsigned _storage_N> +ATTR_COLD void matrix_solver_sm_t<m_N, _storage_N>::vsetup(analog_net_t::list_t &nets) +{ + if (m_dim < nets.size()) + log().fatal("Dimension {1} less than {2}", m_dim, nets.size()); + + for (unsigned k = 0; k < N(); k++) + { + m_terms[k]->clear(); + m_rails_temp[k].clear(); + } + + matrix_solver_t::setup_base(nets); + + for (unsigned k = 0; k < N(); k++) + { + m_terms[k]->m_railstart = m_terms[k]->count(); + for (unsigned i = 0; i < m_rails_temp[k].count(); i++) + this->m_terms[k]->add(m_rails_temp[k].terms()[i], m_rails_temp[k].net_other()[i], false); + + m_rails_temp[k].clear(); // no longer needed + m_terms[k]->set_pointers(); + } + +#if 1 + + /* Sort in descending order by number of connected matrix voltages. + * The idea is, that for Gauss-Seidel algo the first voltage computed + * depends on the greatest number of previous voltages thus taking into + * account the maximum amout of information. + * + * This actually improves performance on popeye slightly. Average + * GS computations reduce from 2.509 to 2.370 + * + * Smallest to largest : 2.613 + * Unsorted : 2.509 + * Largest to smallest : 2.370 + * + * Sorting as a general matrix pre-conditioning is mentioned in + * literature but I have found no articles about Gauss Seidel. + * + * For Gaussian Elimination however increasing order is better suited. + * FIXME: Even better would be to sort on elements right of the matrix diagonal. + * + */ + + int sort_order = (type() == GAUSS_SEIDEL ? 1 : -1); + + for (unsigned k = 0; k < N() / 2; k++) + for (unsigned i = 0; i < N() - 1; i++) + { + if ((m_terms[i]->m_railstart - m_terms[i+1]->m_railstart) * sort_order < 0) + { + std::swap(m_terms[i], m_terms[i+1]); + std::swap(m_nets[i], m_nets[i+1]); + } + } + + for (unsigned k = 0; k < N(); k++) + { + int *other = m_terms[k]->net_other(); + for (unsigned i = 0; i < m_terms[k]->count(); i++) + if (other[i] != -1) + other[i] = get_net_idx(&m_terms[k]->terms()[i]->m_otherterm->net()); + } + +#endif + + /* create a list of non zero elements right of the diagonal + * These list anticipate the population of array elements by + * Gaussian elimination. + */ + for (unsigned k = 0; k < N(); k++) + { + terms_t * t = m_terms[k]; + /* pretty brutal */ + int *other = t->net_other(); + + t->m_nz.clear(); + + if (k==0) + t->m_nzrd.clear(); + else + { + t->m_nzrd = m_terms[k-1]->m_nzrd; + unsigned j=0; + while(j < t->m_nzrd.size()) + { + if (t->m_nzrd[j] < k + 1) + t->m_nzrd.remove_at(j); + else + j++; + } + } + + for (unsigned i = 0; i < t->m_railstart; i++) + { + if (!t->m_nzrd.contains(other[i]) && other[i] >= (int) (k + 1)) + t->m_nzrd.push_back(other[i]); + if (!t->m_nz.contains(other[i])) + t->m_nz.push_back(other[i]); + } + + /* and sort */ + psort_list(t->m_nzrd); + + t->m_nz.push_back(k); // add diagonal + + psort_list(t->m_nz); + } + + /* create a list of non zero elements below diagonal k + * This should reduce cache misses ... + */ + + bool touched[_storage_N][_storage_N] = { { false } }; + for (unsigned k = 0; k < N(); k++) + { + m_terms[k]->m_nzbd.clear(); + for (unsigned j = 0; j < m_terms[k]->m_nz.size(); j++) + touched[k][m_terms[k]->m_nz[j]] = true; + } + + for (unsigned k = 0; k < N(); k++) + { + for (unsigned row = k + 1; row < N(); row++) + { + if (touched[row][k]) + { + if (!m_terms[k]->m_nzbd.contains(row)) + m_terms[k]->m_nzbd.push_back(row); + for (unsigned col = k; col < N(); col++) + if (touched[k][col]) + touched[row][col] = true; + } + } + } + + if (0) + for (unsigned k = 0; k < N(); k++) + { + pstring line = pfmt("{1}")(k, "3"); + for (unsigned j = 0; j < m_terms[k]->m_nzrd.size(); j++) + line += pfmt(" {1}")(m_terms[k]->m_nzrd[j], "3"); + log().verbose("{1}", line); + } + + /* + * save states + */ + save(NLNAME(m_last_RHS)); + save(NLNAME(m_last_V)); + + for (unsigned k = 0; k < N(); k++) + { + pstring num = pfmt("{1}")(k); + + save(RHS(k), "RHS" + num); + + save(m_terms[k]->go(),"GO" + num, m_terms[k]->count()); + save(m_terms[k]->gt(),"GT" + num, m_terms[k]->count()); + save(m_terms[k]->Idr(),"IDR" + num , m_terms[k]->count()); + } + +} + + +template <unsigned m_N, unsigned _storage_N> +void matrix_solver_sm_t<m_N, _storage_N>::build_LE_A() +{ + const unsigned iN = N(); + for (unsigned k = 0; k < iN; k++) + { + for (unsigned i=0; i < iN; i++) + A(k,i) = 0.0; + + const unsigned terms_count = m_terms[k]->count(); + const unsigned railstart = m_terms[k]->m_railstart; + const nl_double * RESTRICT gt = m_terms[k]->gt(); + + { + nl_double akk = 0.0; + for (unsigned i = 0; i < terms_count; i++) + akk += gt[i]; + + A(k,k) = akk; + } + + const nl_double * RESTRICT go = m_terms[k]->go(); + const int * RESTRICT net_other = m_terms[k]->net_other(); + + for (unsigned i = 0; i < railstart; i++) + A(k,net_other[i]) -= go[i]; + } +} + +template <unsigned m_N, unsigned _storage_N> +void matrix_solver_sm_t<m_N, _storage_N>::build_LE_RHS() +{ + const unsigned iN = N(); + for (unsigned k = 0; k < iN; k++) + { + nl_double rhsk_a = 0.0; + nl_double rhsk_b = 0.0; + + const int terms_count = m_terms[k]->count(); + const nl_double * RESTRICT go = m_terms[k]->go(); + const nl_double * RESTRICT Idr = m_terms[k]->Idr(); + const nl_double * const * RESTRICT other_cur_analog = m_terms[k]->other_curanalog(); + + for (int i = 0; i < terms_count; i++) + rhsk_a = rhsk_a + Idr[i]; + + for (int i = m_terms[k]->m_railstart; i < terms_count; i++) + //rhsk = rhsk + go[i] * terms[i]->m_otherterm->net().as_analog().Q_Analog(); + rhsk_b = rhsk_b + go[i] * *other_cur_analog[i]; + + RHS(k) = rhsk_a + rhsk_b; + } +} + +template <unsigned m_N, unsigned _storage_N> +void matrix_solver_sm_t<m_N, _storage_N>::LE_invert() +{ + const unsigned kN = N(); + + for (unsigned i = 0; i < kN; i++) + { + for (unsigned j = 0; j < kN; j++) + { + W(i,j) = lA(i,j) = A(i,j); + Ainv(i,j) = 0.0; + } + Ainv(i,i) = 1.0; + } + /* down */ + for (unsigned i = 0; i < kN; i++) + { + /* FIXME: Singular matrix? */ + const nl_double f = 1.0 / W(i,i); + const unsigned * RESTRICT const p = m_terms[i]->m_nzrd.data(); + const unsigned e = m_terms[i]->m_nzrd.size(); + + /* Eliminate column i from row j */ + + const unsigned * RESTRICT const pb = m_terms[i]->m_nzbd.data(); + const unsigned eb = m_terms[i]->m_nzbd.size(); + for (unsigned jb = 0; jb < eb; jb++) + { + const unsigned j = pb[jb]; + const nl_double f1 = - W(j,i) * f; + if (f1 != 0.0) + { + for (unsigned k = 0; k < e; k++) + W(j,p[k]) += W(i,p[k]) * f1; + for (unsigned k = 0; k <= i; k ++) + Ainv(j,k) += Ainv(i,k) * f1; + } + } + } + /* up */ + for (int i = kN - 1; i >= 0; i--) + { + /* FIXME: Singular matrix? */ + const nl_double f = 1.0 / W(i,i); + for (int j = i - 1; j>=0; j--) + { + const nl_double f1 = - W(j,i) * f; + if (f1 != 0.0) + { + for (unsigned k = i; k < kN; k++) + W(j,k) += W(i,k) * f1; + for (unsigned k = 0; k < kN; k++) + Ainv(j,k) += Ainv(i,k) * f1; + } + } + for (unsigned k = 0; k < kN; k++) + { + Ainv(i,k) *= f; + lAinv(i,k) = Ainv(i,k); + } + } +} + +template <unsigned m_N, unsigned _storage_N> +template <typename T> +void matrix_solver_sm_t<m_N, _storage_N>::LE_compute_x( + T * RESTRICT x) +{ + const unsigned kN = N(); + + for (int i=0; i<kN; i++) + x[i] = 0.0; + + for (int k=0; k<kN; k++) + { + const nl_double f = RHS(k); + + for (int i=0; i<kN; i++) + x[i] += Ainv(i,k) * f; + } +} + + +template <unsigned m_N, unsigned _storage_N> +template <typename T> +T matrix_solver_sm_t<m_N, _storage_N>::delta( + const T * RESTRICT V) +{ + /* FIXME: Ideally we should also include currents (RHS) here. This would + * need a revaluation of the right hand side after voltages have been updated + * and thus belong into a different calculation. This applies to all solvers. + */ + + const unsigned iN = this->N(); + T cerr = 0; + for (unsigned i = 0; i < iN; i++) + cerr = std::fmax(cerr, nl_math::abs(V[i] - (T) this->m_nets[i]->m_cur_Analog)); + return cerr; +} + +template <unsigned m_N, unsigned _storage_N> +template <typename T> +void matrix_solver_sm_t<m_N, _storage_N>::store( + const T * RESTRICT V) +{ + for (unsigned i = 0, iN=N(); i < iN; i++) + { + this->m_nets[i]->m_cur_Analog = V[i]; + } +} + + +template <unsigned m_N, unsigned _storage_N> +int matrix_solver_sm_t<m_N, _storage_N>::solve_non_dynamic(ATTR_UNUSED const bool newton_raphson) +{ + static const bool incremental = true; + static uint cnt = 0; + + nl_double new_V[_storage_N]; // = { 0.0 }; + + if (0 || ((cnt % 200) == 0)) + { + /* complete calculation */ + this->LE_invert(); + } + else + { + const auto iN = N(); + + if (not incremental) + { + for (int row = 0; row < iN; row ++) + for (int k = 0; k < iN; k++) + Ainv(row,k) = lAinv(row, k); + } + for (int row = 0; row < iN; row ++) + { + nl_double v[m_pitch] = {0}; + unsigned cols[m_pitch]; + unsigned colcount = 0; + + auto &nz = m_terms[row]->m_nz; + for (auto & col : nz) + { + v[col] = A(row,col) - lA(row,col); + if (incremental) + lA(row,col) = A(row,col); + if (v[col] != 0.0) + cols[colcount++] = col; + } + + if (colcount > 0) + { + nl_double lamba = 0.0; + nl_double w[m_pitch] = {0}; + nl_double z[m_pitch]; + /* compute w and lamba */ + for (unsigned i = 0; i < iN; i++) + z[i] = Ainv(i, row); /* u is row'th column */ + + for (unsigned j = 0; j < colcount; j++) + lamba += v[cols[j]] * z[cols[j]]; + + for (unsigned j=0; j<colcount; j++) + { + auto col = cols[j]; + auto f = v[col]; + for (unsigned k = 0; k < iN; k++) + w[k] += Ainv(col,k) * f; /* Transpose(Ainv) * v */ + } + + lamba = -1.0 / (1.0 + lamba); + for (int i=0; i<iN; i++) + { + const nl_double f = lamba * z[i]; + if (f != 0.0) + for (int k = 0; k < iN; k++) + Ainv(i,k) += f * w[k]; + } + } + + } + } + + cnt++; + + this->LE_compute_x(new_V); + + if (newton_raphson) + { + nl_double err = delta(new_V); + + store(new_V); + + return (err > this->m_params.m_accuracy) ? 2 : 1; + } + else + { + store(new_V); + return 1; + } +} + +template <unsigned m_N, unsigned _storage_N> +inline int matrix_solver_sm_t<m_N, _storage_N>::vsolve_non_dynamic(const bool newton_raphson) +{ + this->build_LE_A(); + this->build_LE_RHS(); + + for (unsigned i=0, iN=N(); i < iN; i++) + m_last_RHS[i] = RHS(i); + + this->m_stat_calculations++; + return this->solve_non_dynamic(newton_raphson); +} + +template <unsigned m_N, unsigned _storage_N> +matrix_solver_sm_t<m_N, _storage_N>::matrix_solver_sm_t(const solver_parameters_t *params, const int size) +: matrix_solver_t(GAUSSIAN_ELIMINATION, params) +, m_dim(size) +{ + m_rails_temp = palloc_array(terms_t, N()); +#if (NL_USE_DYNAMIC_ALLOCATION) + m_A = palloc_array(nl_ext_double, N() * m_pitch); +#endif + for (unsigned k = 0; k < N(); k++) + { + m_terms[k] = palloc(terms_t); + m_last_RHS[k] = 0.0; + m_last_V[k] = 0.0; + } +} + +template <unsigned m_N, unsigned _storage_N> +matrix_solver_sm_t<m_N, _storage_N>::matrix_solver_sm_t(const eSolverType type, const solver_parameters_t *params, const int size) +: matrix_solver_t(type, params) +, m_dim(size) +{ + m_rails_temp = palloc_array(terms_t, N()); +#if (NL_USE_DYNAMIC_ALLOCATION) + m_A = palloc_array(nl_ext_double, N() * m_pitch); +#endif + for (unsigned k = 0; k < N(); k++) + { + m_terms[k] = palloc(terms_t); + m_last_RHS[k] = 0.0; + m_last_V[k] = 0.0; + } +} + +NETLIB_NAMESPACE_DEVICES_END() + +#endif /* NLD_MS_DIRECT_H_ */ diff --git a/src/lib/netlist/solver/nld_ms_sor.h b/src/lib/netlist/solver/nld_ms_sor.h index 556e9fddd7f..1805b23a9d0 100644 --- a/src/lib/netlist/solver/nld_ms_sor.h +++ b/src/lib/netlist/solver/nld_ms_sor.h @@ -33,9 +33,7 @@ public: virtual ~matrix_solver_SOR_t() {} virtual void vsetup(analog_net_t::list_t &nets) override; - ATTR_HOT virtual int vsolve_non_dynamic(const bool newton_raphson); -protected: - ATTR_HOT virtual nl_double vsolve() override; + virtual int vsolve_non_dynamic(const bool newton_raphson) override; private: nl_double m_lp_fact; @@ -54,14 +52,7 @@ void matrix_solver_SOR_t<m_N, _storage_N>::vsetup(analog_net_t::list_t &nets) } template <unsigned m_N, unsigned _storage_N> -ATTR_HOT nl_double matrix_solver_SOR_t<m_N, _storage_N>::vsolve() -{ - this->solve_base(this); - return this->compute_next_timestep(); -} - -template <unsigned m_N, unsigned _storage_N> -ATTR_HOT inline int matrix_solver_SOR_t<m_N, _storage_N>::vsolve_non_dynamic(const bool newton_raphson) +int matrix_solver_SOR_t<m_N, _storage_N>::vsolve_non_dynamic(const bool newton_raphson) { const unsigned iN = this->N(); bool resched = false; diff --git a/src/lib/netlist/solver/nld_ms_sor_mat.h b/src/lib/netlist/solver/nld_ms_sor_mat.h index 4312c3039be..a4fce8dec2a 100644 --- a/src/lib/netlist/solver/nld_ms_sor_mat.h +++ b/src/lib/netlist/solver/nld_ms_sor_mat.h @@ -37,9 +37,7 @@ public: virtual void vsetup(analog_net_t::list_t &nets) override; - ATTR_HOT inline int vsolve_non_dynamic(const bool newton_raphson); -protected: - ATTR_HOT virtual nl_double vsolve() override; + virtual int vsolve_non_dynamic(const bool newton_raphson) override; private: nl_double m_Vdelta[_storage_N]; @@ -65,9 +63,10 @@ void matrix_solver_SOR_mat_t<m_N, _storage_N>::vsetup(analog_net_t::list_t &nets this->save(NLNAME(m_Vdelta)); } - +#if 0 +//FIXME: move to solve_base template <unsigned m_N, unsigned _storage_N> -ATTR_HOT nl_double matrix_solver_SOR_mat_t<m_N, _storage_N>::vsolve() +nl_double matrix_solver_SOR_mat_t<m_N, _storage_N>::vsolve() { /* * enable linear prediction on first newton pass @@ -111,9 +110,10 @@ ATTR_HOT nl_double matrix_solver_SOR_mat_t<m_N, _storage_N>::vsolve() return this->compute_next_timestep(); } +#endif template <unsigned m_N, unsigned _storage_N> -ATTR_HOT inline int matrix_solver_SOR_mat_t<m_N, _storage_N>::vsolve_non_dynamic(const bool newton_raphson) +int matrix_solver_SOR_mat_t<m_N, _storage_N>::vsolve_non_dynamic(const bool newton_raphson) { /* The matrix based code looks a lot nicer but actually is 30% slower than * the optimized code which works directly on the data structures. @@ -129,7 +129,7 @@ ATTR_HOT inline int matrix_solver_SOR_mat_t<m_N, _storage_N>::vsolve_non_dynamic int resched_cnt = 0; this->build_LE_A(); - this->build_LE_RHS(this->m_RHS); + this->build_LE_RHS(); #if 0 static int ws_cnt = 0; @@ -184,7 +184,7 @@ ATTR_HOT inline int matrix_solver_SOR_mat_t<m_N, _storage_N>::vsolve_non_dynamic for (unsigned i = 0; i < e; i++) Idrive = Idrive + this->A(k,p[i]) * new_v[p[i]]; - const nl_double delta = m_omega * (this->m_RHS[k] - Idrive) / this->A(k,k); + const nl_double delta = m_omega * (this->RHS(k) - Idrive) / this->A(k,k); cerr = std::max(cerr, nl_math::abs(delta)); new_v[k] += delta; } @@ -204,7 +204,6 @@ ATTR_HOT inline int matrix_solver_SOR_mat_t<m_N, _storage_N>::vsolve_non_dynamic //this->netlist().warning("Falling back to direct solver .. Consider increasing RESCHED_LOOPS"); this->m_gs_fail++; - this->LE_solve(); return matrix_solver_direct_t<m_N, _storage_N>::solve_non_dynamic(newton_raphson); } else { diff --git a/src/lib/netlist/solver/nld_solver.cpp b/src/lib/netlist/solver/nld_solver.cpp index 3c8b0f4a663..388f21bda77 100644 --- a/src/lib/netlist/solver/nld_solver.cpp +++ b/src/lib/netlist/solver/nld_solver.cpp @@ -31,23 +31,27 @@ #include <iostream> #include <algorithm> +//#include "nld_twoterm.h" +#include "nl_lists.h" + +#if HAS_OPENMP +#include "omp.h" +#endif + #include "nld_solver.h" +#include "nld_matrix_solver.h" + #if 1 #include "nld_ms_direct.h" #else #include "nld_ms_direct_lu.h" #endif +#include "nld_ms_sm.h" #include "nld_ms_direct1.h" #include "nld_ms_direct2.h" #include "nld_ms_sor.h" #include "nld_ms_sor_mat.h" #include "nld_ms_gmres.h" -//#include "nld_twoterm.h" -#include "nl_lists.h" - -#if HAS_OPENMP -#include "omp.h" -#endif NETLIB_NAMESPACE_DEVICES_START() @@ -79,9 +83,7 @@ ATTR_COLD void terms_t::set_pointers() { for (unsigned i = 0; i < count(); i++) { - m_term[i]->m_gt1 = &m_gt[i]; - m_term[i]->m_go1 = &m_go[i]; - m_term[i]->m_Idr1 = &m_Idr[i]; + m_term[i]->set_ptrs(&m_gt[i], &m_go[i], &m_Idr[i]); m_other_curanalog[i] = &m_term[i]->m_otherterm->net().m_cur_Analog; } } @@ -107,7 +109,7 @@ ATTR_COLD matrix_solver_t::~matrix_solver_t() m_inps.clear_and_free(); } -ATTR_COLD void matrix_solver_t::setup(analog_net_t::list_t &nets) +ATTR_COLD void matrix_solver_t::setup_base(analog_net_t::list_t &nets) { log().debug("New solver setup\n"); @@ -187,14 +189,14 @@ ATTR_COLD void matrix_solver_t::setup(analog_net_t::list_t &nets) } -ATTR_HOT void matrix_solver_t::update_inputs() +void matrix_solver_t::update_inputs() { // avoid recursive calls. Inputs are updated outside this call for (std::size_t i=0; i<m_inps.size(); i++) m_inps[i]->set_Q(m_inps[i]->m_proxied_net->Q_Analog()); } -ATTR_HOT void matrix_solver_t::update_dynamic() +void matrix_solver_t::update_dynamic() { /* update all non-linear devices */ for (std::size_t i=0; i < m_dynamic_devices.size(); i++) @@ -224,29 +226,28 @@ ATTR_COLD void matrix_solver_t::reset() ATTR_COLD void matrix_solver_t::update() { - const nl_double new_timestep = solve(); + const netlist_time new_timestep = solve(); - if (m_params.m_dynamic && is_timestep() && new_timestep > 0) - m_Q_sync.net().reschedule_in_queue(netlist_time::from_double(new_timestep)); + if (m_params.m_dynamic && is_timestep() && new_timestep > netlist_time::zero) + m_Q_sync.net().reschedule_in_queue(new_timestep); } ATTR_COLD void matrix_solver_t::update_forced() { - ATTR_UNUSED const nl_double new_timestep = solve(); + ATTR_UNUSED const netlist_time new_timestep = solve(); if (m_params.m_dynamic && is_timestep()) m_Q_sync.net().reschedule_in_queue(netlist_time::from_double(m_params.m_min_timestep)); } -ATTR_HOT void matrix_solver_t::step(const netlist_time delta) +void matrix_solver_t::step(const netlist_time &delta) { const nl_double dd = delta.as_double(); for (std::size_t k=0; k < m_step_devices.size(); k++) m_step_devices[k]->step_time(dd); } -template<class C > -void matrix_solver_t::solve_base(C *p) +netlist_time matrix_solver_t::solve_base() { m_stat_vsolver_calls++; if (is_dynamic()) @@ -257,7 +258,7 @@ void matrix_solver_t::solve_base(C *p) { update_dynamic(); // Gauss-Seidel will revert to Gaussian elemination if steps exceeded. - this_resched = p->vsolve_non_dynamic(true); + this_resched = this->vsolve_non_dynamic(true); newton_loops++; } while (this_resched > 1 && newton_loops < m_params.m_nr_loops); @@ -271,11 +272,12 @@ void matrix_solver_t::solve_base(C *p) } else { - p->vsolve_non_dynamic(false); + this->vsolve_non_dynamic(false); } + return this->compute_next_timestep(); } -ATTR_HOT nl_double matrix_solver_t::solve() +netlist_time matrix_solver_t::solve() { const netlist_time now = netlist().time(); const netlist_time delta = now - m_last_step; @@ -283,7 +285,7 @@ ATTR_HOT nl_double matrix_solver_t::solve() // We are already up to date. Avoid oscillations. // FIXME: Make this a parameter! if (delta < netlist_time::from_nsec(1)) // 20000 - return -1.0; + return netlist_time::from_nsec(0); /* update all terminals for new time step */ m_last_step = now; @@ -291,7 +293,7 @@ ATTR_HOT nl_double matrix_solver_t::solve() step(delta); - const nl_double next_time_step = vsolve(); + const netlist_time next_time_step = solve_base(); update_inputs(); return next_time_step; @@ -307,7 +309,7 @@ ATTR_COLD int matrix_solver_t::get_net_idx(net_t *net) void matrix_solver_t::log_stats() { - //if (this->m_stat_calculations != 0 && this->m_params.m_log_stats) + if (this->m_stat_calculations != 0 && this->m_stat_vsolver_calls && this->m_params.m_log_stats) { log().verbose("=============================================="); log().verbose("Solver {1}", this->name()); @@ -360,7 +362,7 @@ NETLIB_START(solver) /* automatic time step */ register_param("DYNAMIC_TS", m_dynamic, 0); - register_param("LTE", m_lte, 5e-5); // diff/timestep + register_param("DYNAMIC_LTE", m_lte, 5e-5); // diff/timestep register_param("MIN_TIMESTEP", m_min_timestep, 1e-6); // nl_double timestep resolution register_param("LOG_STATS", m_log_stats, 1); // nl_double timestep resolution @@ -429,7 +431,7 @@ NETLIB_UPDATE(solver) for (auto & solver : m_mat_solvers) if (solver->is_timestep()) // Ignore return value - ATTR_UNUSED const nl_double ts = solver->solve(); + ATTR_UNUSED const netlist_time ts = solver->solve(); #endif /* step circuit */ @@ -457,7 +459,13 @@ matrix_solver_t * NETLIB_NAME(solver)::create_solver(int size, const bool use_sp } else if (pstring("MAT").equals(m_iterative_solver)) { - typedef matrix_solver_direct_t<m_N,_storage_N> solver_mat; + typedef matrix_solver_sm_t<m_N,_storage_N> solver_mat; + return palloc(solver_mat(&m_params, size)); + } + else if (pstring("SM").equals(m_iterative_solver)) + { + /* Sherman-Morrison Formula */ + typedef matrix_solver_sm_t<m_N,_storage_N> solver_mat; return palloc(solver_mat(&m_params, size)); } else if (pstring("SOR").equals(m_iterative_solver)) @@ -620,7 +628,7 @@ ATTR_COLD void NETLIB_NAME(solver)::post_start() register_sub(pfmt("Solver_{1}")(m_mat_solvers.size()), *ms); - ms->vsetup(grp); + ms->setup(grp); m_mat_solvers.push_back(ms); diff --git a/src/lib/netlist/solver/nld_solver.h b/src/lib/netlist/solver/nld_solver.h index 06a98d063c6..6d08e0bbb73 100644 --- a/src/lib/netlist/solver/nld_solver.h +++ b/src/lib/netlist/solver/nld_solver.h @@ -48,134 +48,7 @@ struct solver_parameters_t }; -class terms_t -{ - P_PREVENT_COPYING(terms_t) - - public: - ATTR_COLD terms_t() : m_railstart(0) - {} - - ATTR_COLD void clear() - { - m_term.clear(); - m_net_other.clear(); - m_gt.clear(); - m_go.clear(); - m_Idr.clear(); - m_other_curanalog.clear(); - } - - ATTR_COLD void add(terminal_t *term, int net_other, bool sorted); - - ATTR_HOT inline unsigned count() { return m_term.size(); } - - ATTR_HOT inline terminal_t **terms() { return m_term.data(); } - ATTR_HOT inline int *net_other() { return m_net_other.data(); } - ATTR_HOT inline nl_double *gt() { return m_gt.data(); } - ATTR_HOT inline nl_double *go() { return m_go.data(); } - ATTR_HOT inline nl_double *Idr() { return m_Idr.data(); } - ATTR_HOT inline nl_double **other_curanalog() { return m_other_curanalog.data(); } - - ATTR_COLD void set_pointers(); - - unsigned m_railstart; - - pvector_t<unsigned> m_nz; /* all non zero for multiplication */ - pvector_t<unsigned> m_nzrd; /* non zero right of the diagonal for elimination */ - pvector_t<unsigned> m_nzbd; /* non zero below of the diagonal for elimination */ -private: - pvector_t<terminal_t *> m_term; - pvector_t<int> m_net_other; - pvector_t<nl_double> m_go; - pvector_t<nl_double> m_gt; - pvector_t<nl_double> m_Idr; - pvector_t<nl_double *> m_other_curanalog; -}; - -class matrix_solver_t : public device_t -{ -public: - typedef pvector_t<matrix_solver_t *> list_t; - typedef core_device_t::list_t dev_list_t; - - enum eSolverType - { - GAUSSIAN_ELIMINATION, - GAUSS_SEIDEL - }; - - ATTR_COLD matrix_solver_t(const eSolverType type, const solver_parameters_t *params); - virtual ~matrix_solver_t(); - - virtual void vsetup(analog_net_t::list_t &nets) = 0; - - template<class C> - void solve_base(C *p); - - ATTR_HOT nl_double solve(); - - ATTR_HOT inline bool is_dynamic() { return m_dynamic_devices.size() > 0; } - ATTR_HOT inline bool is_timestep() { return m_step_devices.size() > 0; } - - ATTR_HOT void update_forced(); - ATTR_HOT inline void update_after(const netlist_time after) - { - m_Q_sync.net().reschedule_in_queue(after); - } - - /* netdevice functions */ - ATTR_HOT virtual void update() override; - virtual void start() override; - virtual void reset() override; - - ATTR_COLD int get_net_idx(net_t *net); - - inline eSolverType type() const { return m_type; } - plog_base<NL_DEBUG> &log() { return netlist().log(); } - - virtual void log_stats(); - -protected: - - ATTR_COLD void setup(analog_net_t::list_t &nets); - ATTR_HOT void update_dynamic(); - - // should return next time step - ATTR_HOT virtual nl_double vsolve() = 0; - - virtual void add_term(int net_idx, terminal_t *term) = 0; - - pvector_t<analog_net_t *> m_nets; - pvector_t<analog_output_t *> m_inps; - - int m_stat_calculations; - int m_stat_newton_raphson; - int m_stat_vsolver_calls; - int m_iterative_fail; - int m_iterative_total; - - const solver_parameters_t &m_params; - - ATTR_HOT inline nl_double current_timestep() { return m_cur_ts; } -private: - - netlist_time m_last_step; - nl_double m_cur_ts; - dev_list_t m_step_devices; - dev_list_t m_dynamic_devices; - - logic_input_t m_fb_sync; - logic_output_t m_Q_sync; - - ATTR_HOT void step(const netlist_time delta); - - ATTR_HOT void update_inputs(); - - const eSolverType m_type; -}; - - +class matrix_solver_t; class NETLIB_NAME(solver) : public device_t { @@ -188,13 +61,13 @@ public: ATTR_COLD void post_start(); ATTR_COLD void stop() override; - ATTR_HOT inline nl_double gmin() { return m_gmin.Value(); } + inline nl_double gmin() { return m_gmin.Value(); } protected: - ATTR_HOT void update() override; - ATTR_HOT void start() override; - ATTR_HOT void reset() override; - ATTR_HOT void update_param() override; + void update() override; + void start() override; + void reset() override; + void update_param() override; logic_input_t m_fb_step; logic_output_t m_Q_step; @@ -217,7 +90,7 @@ protected: param_logic_t m_log_stats; - matrix_solver_t::list_t m_mat_solvers; + pvector_t<matrix_solver_t *> m_mat_solvers; private: solver_parameters_t m_params; diff --git a/src/mame/audio/irem.cpp b/src/mame/audio/irem.cpp index 0020c880c30..0a7469091fc 100644 --- a/src/mame/audio/irem.cpp +++ b/src/mame/audio/irem.cpp @@ -419,11 +419,14 @@ NETLIST_START(kidniki_interface) PARAM(Solver.NR_LOOPS, 300) PARAM(Solver.GS_LOOPS, 1) PARAM(Solver.GS_THRESHOLD, 6) - //PARAM(Solver.ITERATIVE, "SOR") + PARAM(Solver.ITERATIVE, "SOR") //PARAM(Solver.ITERATIVE, "MAT") - PARAM(Solver.ITERATIVE, "GMRES") - PARAM(Solver.PARALLEL, 1) + //PARAM(Solver.ITERATIVE, "GMRES") + PARAM(Solver.PARALLEL, 0) PARAM(Solver.SOR_FACTOR, 1.00) + PARAM(Solver.DYNAMIC_TS, 0) + PARAM(Solver.DYNAMIC_LTE, 5e-4) + PARAM(Solver.MIN_TIMESTEP, 20e-6) #else SOLVER(Solver, 12000) PARAM(Solver.ACCURACY, 1e-8) diff --git a/src/mame/drivers/apple2e.cpp b/src/mame/drivers/apple2e.cpp index 7727c74379f..27b3dd0fc59 100644 --- a/src/mame/drivers/apple2e.cpp +++ b/src/mame/drivers/apple2e.cpp @@ -144,6 +144,7 @@ Address bus A0-A11 is Y0-Y11 #include "bus/a2bus/timemasterho.h" #include "bus/a2bus/mouse.h" #include "bus/a2bus/ezcgi.h" +#include "bus/a2bus/pc_xporter.h" #include "bus/a2bus/a2eauxslot.h" #include "bus/a2bus/a2estd80col.h" #include "bus/a2bus/a2eext80col.h" @@ -3188,6 +3189,7 @@ static SLOT_INTERFACE_START(apple2_cards) SLOT_INTERFACE("ezcgi9938", A2BUS_EZCGI_9938) /* E-Z Color Graphics Interface (TMS9938) */ SLOT_INTERFACE("ezcgi9958", A2BUS_EZCGI_9958) /* E-Z Color Graphics Interface (TMS9958) */ // SLOT_INTERFACE("magicmusician", A2BUS_MAGICMUSICIAN) /* Magic Musician Card */ + SLOT_INTERFACE("pcxport", A2BUS_PCXPORTER) /* Applied Engineering PC Transporter */ SLOT_INTERFACE_END static SLOT_INTERFACE_START(apple2eaux_cards) diff --git a/src/mame/drivers/chihiro.cpp b/src/mame/drivers/chihiro.cpp index 5cd8a9dd229..c63b2043d53 100644 --- a/src/mame/drivers/chihiro.cpp +++ b/src/mame/drivers/chihiro.cpp @@ -240,8 +240,8 @@ Notes: 24LC64 - Microchip 24LC64 64K I2C Serial EEPROM (SOIC8) 24LC024 - Microchip 24LC024 2K I2C Serial EEPROM (SOIC8) M68AF127B - ST Microelectronics 1Mbit (128K x8), 5V Asynchronous SRAM (SOP32) - AN2131QC - Cypress AN2131 EZ-USB-Family 8051-based High-Speed USB IC's (QFP80) - AN2131SC / (QFP44) + AN2131QC - Cypress AN2131 EZ-USB-Family 8051-based High-Speed USB IC's (QFP80) firmware in IC11 + AN2131SC / (QFP44) firmware in IC32 ADM3222 - Analog Devices ADM3222 High-Speed, +3.3V, 2-Channel RS232/V.28 Interface Device (SOIC20) SN65240 - Texas Instruments SN65240 USB Port Transient Suppressor (SOIC8) BA7623 - Rohm BA7623 75-Ohm driver IC with 3 internal circuits (SOIC8) @@ -572,7 +572,7 @@ static const struct { UINT32 address; UINT8 write_byte; } modify[16]; -} hacks[2] = { { "chihiro", { { 0x6a79f, 0x01 }, { 0x6a7a0, 0x00 }, { 0x6b575, 0x00 }, { 0x6b576, 0x00 }, { 0x6b5af, 0x75 }, { 0x6b78a, 0x75 }, { 0x6b7ca, 0x00 }, { 0x6b7b8, 0x00 }, { 0x8f5b2, 0x75 }, { 0x79a9e, 0x74 }, { 0x79b80, 0x74 }, { 0x79b97, 0x74 }, { 0, 0 } } }, +} hacks[2] = { { "chihiro", { { 0x6a79f/*3f79f*/, 0x01 }, { 0x6a7a0/*3f7a0*/, 0x00 }, { 0x6b575/*40575*/, 0x00 }, { 0x6b576/*40576*/, 0x00 }, { 0x6b5af/*405af*/, 0x75 }, { 0x6b78a/*4078a*/, 0x75 }, { 0x6b7ca/*407ca*/, 0x00 }, { 0x6b7b8/*407b8*/, 0x00 }, { 0x8f5b2, 0x75 }, { 0x79a9e/*2ea9e*/, 0x74 }, { 0x79b80/*2eb80*/, 0x74 }, { 0x79b97/*2eb97*/, 0x74 }, { 0, 0 } } }, { "outr2", { { 0x12e4cf, 0x01 }, { 0x12e4d0, 0x00 }, { 0x4793e, 0x01 }, { 0x4793f, 0x00 }, { 0x47aa3, 0x01 }, { 0x47aa4, 0x00 }, { 0x14f2b6, 0x84 }, { 0x14f2d1, 0x75 }, { 0x8732f, 0x7d }, { 0x87384, 0x7d }, { 0x87388, 0xeb }, { 0, 0 } } } }; void chihiro_state::hack_usb() diff --git a/src/mame/drivers/crimfght.cpp b/src/mame/drivers/crimfght.cpp index 460e133caa6..d2d96443c6d 100644 --- a/src/mame/drivers/crimfght.cpp +++ b/src/mame/drivers/crimfght.cpp @@ -134,8 +134,8 @@ static INPUT_PORTS_START( crimfght ) PORT_DIPSETTING( 0x0b, DEF_STR( 1C_5C )) PORT_DIPSETTING( 0x0a, DEF_STR( 1C_6C )) PORT_DIPSETTING( 0x09, DEF_STR( 1C_7C )) - PORT_DIPSETTING( 0x00, "Void") - PORT_DIPNAME(0xf0, 0x00, "Coin B (unused)") PORT_DIPLOCATION("SW1:5,6,7,8") + PORT_DIPSETTING( 0x00, DEF_STR( Free_Play )) + PORT_DIPNAME(0xf0, 0xf0, "Coin B") PORT_DIPLOCATION("SW1:5,6,7,8") PORT_DIPSETTING( 0x20, DEF_STR( 4C_1C )) PORT_DIPSETTING( 0x50, DEF_STR( 3C_1C )) PORT_DIPSETTING( 0x80, DEF_STR( 2C_1C )) @@ -151,11 +151,14 @@ static INPUT_PORTS_START( crimfght ) PORT_DIPSETTING( 0xb0, DEF_STR( 1C_5C )) PORT_DIPSETTING( 0xa0, DEF_STR( 1C_6C )) PORT_DIPSETTING( 0x90, DEF_STR( 1C_7C )) - PORT_DIPSETTING( 0x00, "Void") + PORT_DIPSETTING( 0x00, DEF_STR( Unused )) PORT_START("DSW2") - PORT_DIPUNUSED_DIPLOC(0x01, 0x01, "SW2:1") - PORT_DIPUNUSED_DIPLOC(0x02, 0x02, "SW2:2") + PORT_DIPNAME( 0x03, 0x02, DEF_STR( Lives ) ) PORT_DIPLOCATION("SW2:1,2") + PORT_DIPSETTING( 0x03, "1" ) + PORT_DIPSETTING( 0x02, "2" ) + PORT_DIPSETTING( 0x01, "3" ) + PORT_DIPSETTING( 0x00, "4" ) PORT_DIPUNUSED_DIPLOC(0x04, 0x04, "SW2:3") PORT_DIPUNUSED_DIPLOC(0x08, 0x08, "SW2:4") PORT_DIPUNUSED_DIPLOC(0x10, 0x10, "SW2:5") @@ -178,63 +181,74 @@ static INPUT_PORTS_START( crimfght ) PORT_BIT(0xf0, IP_ACTIVE_HIGH, IPT_SPECIAL) PORT_CUSTOM_MEMBER(DEVICE_SELF, crimfght_state, system_r, NULL) PORT_START("P1") - KONAMI8_B12_UNK(1) + KONAMI8_B123_START(1) PORT_START("P2") - KONAMI8_B12_UNK(2) + KONAMI8_B123_START(2) PORT_START("P3") - KONAMI8_B12_UNK(3) + PORT_BIT( 0xff, IP_ACTIVE_LOW, IPT_UNKNOWN ) PORT_START("P4") - KONAMI8_B12_UNK(4) + PORT_BIT( 0xff, IP_ACTIVE_LOW, IPT_UNKNOWN ) PORT_START("SYSTEM") PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_COIN1) PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_COIN2) - PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_COIN3) - PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_COIN4) + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_UNKNOWN) + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_UNKNOWN) PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_SERVICE1) PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_SERVICE2) - PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_SERVICE3) - PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_SERVICE4) + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_UNKNOWN) + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_UNKNOWN) INPUT_PORTS_END -static INPUT_PORTS_START( crimfghtj ) +static INPUT_PORTS_START( crimfghtu ) PORT_INCLUDE( crimfght ) PORT_MODIFY("DSW1") - KONAMI_COINAGE_LOC(DEF_STR( Free_Play ), "No Coin B", SW1) - /* "No Coin B" = coins produce sound, but no effect on coin counter */ + PORT_DIPNAME(0xf0, 0x00, "Coin B (Unused)") PORT_DIPLOCATION("SW1:5,6,7,8") + PORT_DIPSETTING( 0x20, DEF_STR( 4C_1C )) + PORT_DIPSETTING( 0x50, DEF_STR( 3C_1C )) + PORT_DIPSETTING( 0x80, DEF_STR( 2C_1C )) + PORT_DIPSETTING( 0x40, DEF_STR( 3C_2C )) + PORT_DIPSETTING( 0x10, DEF_STR( 4C_3C )) + PORT_DIPSETTING( 0xf0, DEF_STR( 1C_1C )) + PORT_DIPSETTING( 0x30, DEF_STR( 3C_4C )) + PORT_DIPSETTING( 0x70, DEF_STR( 2C_3C )) + PORT_DIPSETTING( 0xe0, DEF_STR( 1C_2C )) + PORT_DIPSETTING( 0x60, DEF_STR( 2C_5C )) + PORT_DIPSETTING( 0xd0, DEF_STR( 1C_3C )) + PORT_DIPSETTING( 0xc0, DEF_STR( 1C_4C )) + PORT_DIPSETTING( 0xb0, DEF_STR( 1C_5C )) + PORT_DIPSETTING( 0xa0, DEF_STR( 1C_6C )) + PORT_DIPSETTING( 0x90, DEF_STR( 1C_7C )) + PORT_DIPSETTING( 0x00, DEF_STR( Unused )) PORT_MODIFY("DSW2") - PORT_DIPNAME( 0x03, 0x02, DEF_STR( Lives ) ) PORT_DIPLOCATION("SW2:1,2") - PORT_DIPSETTING( 0x03, "1" ) - PORT_DIPSETTING( 0x02, "2" ) - PORT_DIPSETTING( 0x01, "3" ) - PORT_DIPSETTING( 0x00, "4" ) + PORT_DIPUNUSED_DIPLOC(0x01, 0x01, "SW2:1") + PORT_DIPUNUSED_DIPLOC(0x02, 0x02, "SW2:2") - PORT_MODIFY("P1") - KONAMI8_B123_START(1) + PORT_MODIFY("P1") + KONAMI8_B12_UNK(1) - PORT_MODIFY("P2") - KONAMI8_B123_START(2) + PORT_MODIFY("P2") + KONAMI8_B12_UNK(2) - PORT_MODIFY("P3") - PORT_BIT( 0xff, IP_ACTIVE_LOW, IPT_UNKNOWN ) + PORT_MODIFY("P3") + KONAMI8_B12_UNK(3) - PORT_MODIFY("P4") - PORT_BIT( 0xff, IP_ACTIVE_LOW, IPT_UNKNOWN ) + PORT_MODIFY("P4") + KONAMI8_B12_UNK(4) PORT_MODIFY("SYSTEM") - PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_UNKNOWN ) - PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_UNKNOWN ) - PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNKNOWN ) - PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNKNOWN ) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_COIN3 ) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_COIN4 ) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_SERVICE3 ) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_SERVICE4 ) INPUT_PORTS_END - /*************************************************************************** Machine Driver @@ -344,7 +358,7 @@ MACHINE_CONFIG_END ROM_START( crimfght ) ROM_REGION( 0x20000, "maincpu", 0 ) /* code + banked roms */ - ROM_LOAD( "821l02.f24", 0x00000, 0x20000, CRC(588e7da6) SHA1(285febb3bcca31f82b34af3695a59eafae01cd30) ) + ROM_LOAD( "821r02.f24", 0x00000, 0x20000, CRC(4ecdd923) SHA1(78e5260c4bb9b18d7818fb6300d7e1d3a577fb63) ) ROM_REGION( 0x10000, "audiocpu", 0 ) /* 64k for the sound CPU */ ROM_LOAD( "821l01.h4", 0x0000, 0x8000, CRC(0faca89e) SHA1(21c9c6d736b398a29e8709e1187c5bf3cacdc99d) ) @@ -386,9 +400,9 @@ ROM_START( crimfghtj ) ROM_LOAD( "821k03.e5", 0x00000, 0x40000, CRC(fef8505a) SHA1(5c5121609f69001838963e961cb227d6b64e4f5f) ) ROM_END -ROM_START( crimfght2 ) +ROM_START( crimfghtu ) ROM_REGION( 0x20000, "maincpu", 0 ) /* code + banked roms */ - ROM_LOAD( "821r02.f24", 0x00000, 0x20000, CRC(4ecdd923) SHA1(78e5260c4bb9b18d7818fb6300d7e1d3a577fb63) ) + ROM_LOAD( "821l02.f24", 0x00000, 0x20000, CRC(588e7da6) SHA1(285febb3bcca31f82b34af3695a59eafae01cd30) ) ROM_REGION( 0x10000, "audiocpu", 0 ) /* 64k for the sound CPU */ ROM_LOAD( "821l01.h4", 0x0000, 0x8000, CRC(0faca89e) SHA1(21c9c6d736b398a29e8709e1187c5bf3cacdc99d) ) @@ -414,6 +428,6 @@ ROM_END ***************************************************************************/ -GAME( 1989, crimfght, 0, crimfght, crimfght, driver_device, 0, ROT0, "Konami", "Crime Fighters (US 4 players)", MACHINE_SUPPORTS_SAVE ) -GAME( 1989, crimfght2, crimfght, crimfght, crimfghtj, driver_device,0, ROT0, "Konami", "Crime Fighters (World 2 Players)", MACHINE_SUPPORTS_SAVE ) -GAME( 1989, crimfghtj, crimfght, crimfght, crimfghtj, driver_device,0, ROT0, "Konami", "Crime Fighters (Japan 2 Players)", MACHINE_SUPPORTS_SAVE ) +GAME( 1989, crimfght, 0, crimfght, crimfght, driver_device, 0, ROT0, "Konami", "Crime Fighters (World 2 players)", MACHINE_SUPPORTS_SAVE ) +GAME( 1989, crimfghtu, crimfght, crimfght, crimfghtu, driver_device,0, ROT0, "Konami", "Crime Fighters (US 4 Players)", MACHINE_SUPPORTS_SAVE ) +GAME( 1989, crimfghtj, crimfght, crimfght, crimfght, driver_device,0, ROT0, "Konami", "Crime Fighters (Japan 2 Players)", MACHINE_SUPPORTS_SAVE ) diff --git a/src/mame/drivers/eolith.cpp b/src/mame/drivers/eolith.cpp index 101d6788365..80879dbb7ae 100644 --- a/src/mame/drivers/eolith.cpp +++ b/src/mame/drivers/eolith.cpp @@ -36,7 +36,8 @@ 1999 - Land Breaker (pcb ver 3.03) (MCU internal flash dump is missing) 1999 - Land Breaker (pcb ver 3.02) 1999 - New Hidden Catch (pcb ver 3.02) - 1999 - Penfan Girls + 1999 - Penfan Girls (set 1, pcb ver 3.03) + 1999 - Penfan Girls (set 2, pcb ver 3.03P) 2000 - Hidden Catch 3 (v. 1.00 / pcb ver 3.05) 2001 - Fortress 2 Blue Arcade (v. 1.01 / pcb ver 3.05) 2001 - Fortress 2 Blue Arcade (v. 1.00 / pcb ver 3.05) @@ -1199,8 +1200,9 @@ ROM_START( penfana ) ROM_LOAD32_WORD_SWAP( "11.u11", 0x1400002, 0x200000, CRC(ddcd2bae) SHA1(c4fa5ebbaf801a7f06222150658033955966fe1b) ) ROM_LOAD32_WORD_SWAP( "12.u17", 0x1800000, 0x200000, CRC(2eed0f64) SHA1(3b9e65e41d8699a93ea74225ba12a3f66ecba11d) ) ROM_LOAD32_WORD_SWAP( "13.u12", 0x1800002, 0x200000, CRC(cc3068a8) SHA1(0022fad5a4d36678d35e99092c870f2b99d3d8d4) ) - ROM_LOAD32_WORD_SWAP( "14.u18", 0x1c00000, 0x200000, CRC(20a9a08e) SHA1(fe4071cdf78d362bccaee92cdc70c66f7e30f817) ) // not checked by rom check - ROM_LOAD32_WORD_SWAP( "15.u13", 0x1c00002, 0x200000, CRC(872fa9c4) SHA1(4902faa97c9a3a9671cfefc6a711cfcd25f2d6bc) ) // not checked by rom check + // The 3.03P version doesn't even have these populated + //ROM_LOAD32_WORD_SWAP( "14.u18", 0x1c00000, 0x200000, CRC(20a9a08e) SHA1(fe4071cdf78d362bccaee92cdc70c66f7e30f817) ) // not checked by rom check + //ROM_LOAD32_WORD_SWAP( "15.u13", 0x1c00002, 0x200000, CRC(872fa9c4) SHA1(4902faa97c9a3a9671cfefc6a711cfcd25f2d6bc) ) // not checked by rom check ROM_REGION( 0x008000, "soundcpu", 0 ) /* Sound (80c301) CPU Code */ ROM_LOAD( "pfg.u111", 0x0000, 0x8000, CRC(79012474) SHA1(09a2d5705d7bc52cc2d1644c87c1e31ee44813ef) ) diff --git a/src/mame/drivers/hh_hmcs40.cpp b/src/mame/drivers/hh_hmcs40.cpp index acf581c19b5..783f16be481 100644 --- a/src/mame/drivers/hh_hmcs40.cpp +++ b/src/mame/drivers/hh_hmcs40.cpp @@ -1035,7 +1035,7 @@ INPUT_CHANGED_MEMBER(bzaxxon_state::input_changed) static MACHINE_CONFIG_START( bzaxxon, bzaxxon_state ) /* basic machine hardware */ - MCFG_CPU_ADD("maincpu", HD38800, 400000) // approximation + MCFG_CPU_ADD("maincpu", HD38800, 450000) // approximation MCFG_HMCS40_WRITE_R_CB(0, WRITE8(bzaxxon_state, plate_w)) MCFG_HMCS40_WRITE_R_CB(1, WRITE8(bzaxxon_state, plate_w)) MCFG_HMCS40_WRITE_R_CB(2, WRITE8(bzaxxon_state, plate_w)) @@ -4087,7 +4087,7 @@ CONS( 1979, bmboxing, 0, 0, bmboxing, bmboxing, driver_device, 0, "Bambi CONS( 1982, bfriskyt, 0, 0, bfriskyt, bfriskyt, driver_device, 0, "Bandai", "Frisky Tom (Bandai)", MACHINE_SUPPORTS_SAVE | MACHINE_REQUIRES_ARTWORK ) CONS( 1981, packmon, 0, 0, packmon, packmon, driver_device, 0, "Bandai", "Packri Monster", MACHINE_SUPPORTS_SAVE | MACHINE_REQUIRES_ARTWORK ) CONS( 1982, msthawk, 0, 0, msthawk, msthawk, driver_device, 0, "Bandai (Mattel license)", "Star Hawk (Mattel)", MACHINE_SUPPORTS_SAVE | MACHINE_REQUIRES_ARTWORK ) -CONS( 1982, bzaxxon, 0, 0, bzaxxon, bzaxxon, driver_device, 0, "Bandai", "Zaxxon (Bandai)", MACHINE_SUPPORTS_SAVE | MACHINE_REQUIRES_ARTWORK | MACHINE_NOT_WORKING ) +CONS( 1982, bzaxxon, 0, 0, bzaxxon, bzaxxon, driver_device, 0, "Bandai", "Zaxxon (Bandai)", MACHINE_SUPPORTS_SAVE | MACHINE_REQUIRES_ARTWORK ) CONS( 1983, zackman, 0, 0, zackman, zackman, driver_device, 0, "Bandai", "Zackman", MACHINE_SUPPORTS_SAVE | MACHINE_REQUIRES_ARTWORK ) CONS( 1983, bpengo, 0, 0, bpengo, bpengo, driver_device, 0, "Bandai", "Pengo (Bandai)", MACHINE_SUPPORTS_SAVE | MACHINE_REQUIRES_ARTWORK ) CONS( 1983, bbtime, 0, 0, bbtime, bbtime, driver_device, 0, "Bandai", "Burger Time (Bandai)", MACHINE_SUPPORTS_SAVE | MACHINE_REQUIRES_ARTWORK ) diff --git a/src/mame/drivers/mcr3.cpp b/src/mame/drivers/mcr3.cpp index 150e0f54b32..3d2bc6b2d5b 100644 --- a/src/mame/drivers/mcr3.cpp +++ b/src/mame/drivers/mcr3.cpp @@ -535,51 +535,6 @@ static ADDRESS_MAP_START( spyhunt_portmap, AS_IO, 8, mcr3_state ) ADDRESS_MAP_END - -WRITE8_MEMBER(mcr3_state::spyhuntpr_fd00_w) -{ -} - -static ADDRESS_MAP_START( spyhuntpr_map, AS_PROGRAM, 8, mcr3_state ) - ADDRESS_MAP_UNMAP_HIGH - AM_RANGE(0xa800, 0xa8ff) AM_RAM // the ROM is a solid fill in these areas, and they get tested as RAM, I think they moved the 'real' scroll regs here - AM_RANGE(0xa900, 0xa9ff) AM_RAM - - AM_RANGE(0x0000, 0xdfff) AM_ROM - - - - - AM_RANGE(0xe000, 0xe7ff) AM_RAM_WRITE(spyhunt_videoram_w) AM_SHARE("videoram") - AM_RANGE(0xe800, 0xebff) AM_MIRROR(0x0400) AM_RAM_WRITE(spyhunt_alpharam_w) AM_SHARE("spyhunt_alpha") - AM_RANGE(0xf000, 0xf7ff) AM_RAM //AM_SHARE("nvram") - AM_RANGE(0xf800, 0xf9ff) AM_RAM AM_SHARE("spriteram") - AM_RANGE(0xfa00, 0xfa7f) AM_MIRROR(0x0180) AM_RAM_WRITE(spyhuntpr_paletteram_w) AM_SHARE("paletteram") - - AM_RANGE(0xfc00, 0xfc00) AM_READ_PORT("DSW0") - AM_RANGE(0xfc01, 0xfc01) AM_READ_PORT("DSW1") - AM_RANGE(0xfc02, 0xfc02) AM_READ_PORT("IN2") - AM_RANGE(0xfc03, 0xfc03) AM_READ_PORT("IN3") - - AM_RANGE(0xfd00, 0xfd00) AM_WRITE( spyhuntpr_fd00_w ) - - AM_RANGE(0xfe00, 0xffff) AM_RAM // a modified copy of spriteram for this hw?? -ADDRESS_MAP_END - -WRITE8_MEMBER(mcr3_state::spyhuntpr_port04_w) -{ -} - -static ADDRESS_MAP_START( spyhuntpr_portmap, AS_IO, 8, mcr3_state ) - ADDRESS_MAP_UNMAP_HIGH - ADDRESS_MAP_GLOBAL_MASK(0xff) - AM_RANGE(0x04, 0x04) AM_WRITE(spyhuntpr_port04_w) - AM_RANGE(0x84, 0x86) AM_WRITE(spyhunt_scroll_value_w) - AM_RANGE(0xe0, 0xe0) AM_WRITENOP // was watchdog -// AM_RANGE(0xe8, 0xe8) AM_WRITENOP - AM_RANGE(0xf0, 0xf3) AM_DEVREADWRITE("ctc", z80ctc_device, read, write) -ADDRESS_MAP_END - /************************************* * * Port definitions @@ -979,109 +934,6 @@ static INPUT_PORTS_START( spyhunt ) PORT_BIT( 0xff, 0x74, IPT_PADDLE ) PORT_MINMAX(0x34,0xb4) PORT_SENSITIVITY(40) PORT_KEYDELTA(10) INPUT_PORTS_END -static INPUT_PORTS_START( spyhuntpr ) - PORT_START("DSW0") - PORT_DIPNAME( 0x01, 0x01, "DSW0-01" ) - PORT_DIPSETTING( 0x01, DEF_STR( Off ) ) - PORT_DIPSETTING( 0x00, DEF_STR( On ) ) - PORT_DIPNAME( 0x02, 0x02, "DSW0-02" ) - PORT_DIPSETTING( 0x02, DEF_STR( Off ) ) - PORT_DIPSETTING( 0x00, DEF_STR( On ) ) - PORT_DIPNAME( 0x04, 0x04, "DSW0-04" ) - PORT_DIPSETTING( 0x04, DEF_STR( Off ) ) - PORT_DIPSETTING( 0x00, DEF_STR( On ) ) - PORT_DIPNAME( 0x08, 0x08, "DSW0-08" ) - PORT_DIPSETTING( 0x08, DEF_STR( Off ) ) - PORT_DIPSETTING( 0x00, DEF_STR( On ) ) - PORT_DIPNAME( 0x10, 0x10, "DSW0-10" ) - PORT_DIPSETTING( 0x10, DEF_STR( Off ) ) - PORT_DIPSETTING( 0x00, DEF_STR( On ) ) - PORT_DIPNAME( 0x20, 0x20, "DSW0-20" ) - PORT_DIPSETTING( 0x20, DEF_STR( Off ) ) - PORT_DIPSETTING( 0x00, DEF_STR( On ) ) - PORT_DIPNAME( 0x40, 0x40, "DSW0-40" ) - PORT_DIPSETTING( 0x40, DEF_STR( Off ) ) - PORT_DIPSETTING( 0x00, DEF_STR( On ) ) - PORT_DIPNAME( 0x80, 0x80, "DSW0-80" ) - PORT_DIPSETTING( 0x80, DEF_STR( Off ) ) - PORT_DIPSETTING( 0x00, DEF_STR( On ) ) - - PORT_START("DSW1") - PORT_DIPNAME( 0x01, 0x01, "DSW1-01" ) - PORT_DIPSETTING( 0x01, DEF_STR( Off ) ) - PORT_DIPSETTING( 0x00, DEF_STR( On ) ) - PORT_DIPNAME( 0x02, 0x02, "DSW1-02" ) - PORT_DIPSETTING( 0x02, DEF_STR( Off ) ) - PORT_DIPSETTING( 0x00, DEF_STR( On ) ) - PORT_SERVICE( 0x04, IP_ACTIVE_LOW ) - PORT_DIPNAME( 0x08, 0x08, "DSW1-08" ) - PORT_DIPSETTING( 0x08, DEF_STR( Off ) ) - PORT_DIPSETTING( 0x00, DEF_STR( On ) ) - PORT_DIPNAME( 0x10, 0x10, "DSW1-10" ) - PORT_DIPSETTING( 0x10, DEF_STR( Off ) ) - PORT_DIPSETTING( 0x00, DEF_STR( On ) ) - PORT_DIPNAME( 0x20, 0x20, "DSW1-20" ) - PORT_DIPSETTING( 0x20, DEF_STR( Off ) ) - PORT_DIPSETTING( 0x00, DEF_STR( On ) ) - PORT_DIPNAME( 0x40, 0x40, "DSW1-40" ) - PORT_DIPSETTING( 0x40, DEF_STR( Off ) ) - PORT_DIPSETTING( 0x00, DEF_STR( On ) ) - PORT_DIPNAME( 0x80, 0x80, "DSW1-80" ) - PORT_DIPSETTING( 0x80, DEF_STR( Off ) ) - PORT_DIPSETTING( 0x00, DEF_STR( On ) ) - - PORT_START("IN2") - PORT_DIPNAME( 0x0001, 0x0001, "2" ) - PORT_DIPSETTING( 0x0001, DEF_STR( Off ) ) - PORT_DIPSETTING( 0x0000, DEF_STR( On ) ) - PORT_DIPNAME( 0x0002, 0x0002, "start" ) // start - PORT_DIPSETTING( 0x0002, DEF_STR( Off ) ) - PORT_DIPSETTING( 0x0000, DEF_STR( On ) ) - PORT_DIPNAME( 0x0004, 0x0004, DEF_STR( Unknown ) ) - PORT_DIPSETTING( 0x0004, DEF_STR( Off ) ) - PORT_DIPSETTING( 0x0000, DEF_STR( On ) ) - PORT_DIPNAME( 0x0008, 0x0008, DEF_STR( Unknown ) ) - PORT_DIPSETTING( 0x0008, DEF_STR( Off ) ) - PORT_DIPSETTING( 0x0000, DEF_STR( On ) ) - PORT_DIPNAME( 0x0010, 0x0010, "handbrake?" ) - PORT_DIPSETTING( 0x0010, DEF_STR( Off ) ) - PORT_DIPSETTING( 0x0000, DEF_STR( On ) ) - PORT_DIPNAME( 0x0020, 0x0020, DEF_STR( Unknown ) ) - PORT_DIPSETTING( 0x0020, DEF_STR( Off ) ) - PORT_DIPSETTING( 0x0000, DEF_STR( On ) ) - PORT_DIPNAME( 0x0040, 0x0040, "pedal inverse" ) - PORT_DIPSETTING( 0x0040, DEF_STR( Off ) ) - PORT_DIPSETTING( 0x0000, DEF_STR( On ) ) - PORT_DIPNAME( 0x0080, 0x0080, DEF_STR( Unknown ) ) - PORT_DIPSETTING( 0x0080, DEF_STR( Off ) ) - PORT_DIPSETTING( 0x0000, DEF_STR( On ) ) - - PORT_START("IN3") - PORT_DIPNAME( 0x0001, 0x0001, "3" ) - PORT_DIPSETTING( 0x0001, DEF_STR( Off ) ) - PORT_DIPSETTING( 0x0000, DEF_STR( On ) ) - PORT_DIPNAME( 0x0002, 0x0002, DEF_STR( Unknown ) ) - PORT_DIPSETTING( 0x0002, DEF_STR( Off ) ) - PORT_DIPSETTING( 0x0000, DEF_STR( On ) ) - PORT_DIPNAME( 0x0004, 0x0004, DEF_STR( Unknown ) ) - PORT_DIPSETTING( 0x0004, DEF_STR( Off ) ) - PORT_DIPSETTING( 0x0000, DEF_STR( On ) ) - PORT_DIPNAME( 0x0008, 0x0008, DEF_STR( Unknown ) ) - PORT_DIPSETTING( 0x0008, DEF_STR( Off ) ) - PORT_DIPSETTING( 0x0000, DEF_STR( On ) ) - PORT_DIPNAME( 0x0010, 0x0010, DEF_STR( Unknown ) ) - PORT_DIPSETTING( 0x0010, DEF_STR( Off ) ) - PORT_DIPSETTING( 0x0000, DEF_STR( On ) ) - PORT_DIPNAME( 0x0020, 0x0020, DEF_STR( Unknown ) ) - PORT_DIPSETTING( 0x0020, DEF_STR( Off ) ) - PORT_DIPSETTING( 0x0000, DEF_STR( On ) ) - PORT_DIPNAME( 0x0040, 0x0040, "coin" ) // coin? - PORT_DIPSETTING( 0x0040, DEF_STR( Off ) ) - PORT_DIPSETTING( 0x0000, DEF_STR( On ) ) - PORT_DIPNAME( 0x0080, 0x0080, "machineguns" ) // machine guns - PORT_DIPSETTING( 0x0080, DEF_STR( Off ) ) - PORT_DIPSETTING( 0x0000, DEF_STR( On ) ) -INPUT_PORTS_END /* not verified, no manual found */ static INPUT_PORTS_START( crater ) @@ -1206,52 +1058,6 @@ static const gfx_layout spyhunt_alphalayout = 16*8 }; -static const gfx_layout spyhuntpr_alphalayout = -{ - 16,8, - RGN_FRAC(1,1), - 2, - { 0, 4}, - { 0, 0, 1, 1, 2, 2, 3, 3, 8, 8, 9, 9, 10, 10, 11, 11 }, - { 0, 2*8, 4*8, 6*8, 8*8, 10*8, 12*8, 14*8 }, - 16*8 -}; - - -const gfx_layout spyhuntpr_sprite_layout = -{ - 32,16, - RGN_FRAC(1,4), - 4, - { RGN_FRAC(3,4), RGN_FRAC(2,4), RGN_FRAC(1,4), RGN_FRAC(0,4) }, - { 6,7, 4,5, 2,3, 0,1, 14,15, 12,13, 10,11, 8,9, 22,23, 20,21, 18,19, 16,17, 30,31, 28,29, 26,27, 24,25 }, - { 0*32,1*32,2*32,3*32,4*32,5*32,6*32,7*32,8*32,9*32,10*32,11*32,12*32,13*32,14*32,15*32 }, - - 16*32 -}; - - -static const UINT32 spyhuntp_charlayout_xoffset[64] = -{ - 0x0000*8,0x0000*8, 0x0000*8+1,0x0000*8+1, 0x0000*8+2,0x0000*8+2, 0x0000*8+3,0x0000*8+3, 0x0000*8+4,0x0000*8+4, 0x0000*8+5,0x0000*8+5, 0x0000*8+6,0x0000*8+6, 0x0000*8+7,0x0000*8+7, - 0x1000*8,0x1000*8, 0x1000*8+1,0x1000*8+1, 0x1000*8+2,0x1000*8+2, 0x1000*8+3,0x1000*8+3, 0x1000*8+4,0x1000*8+4, 0x1000*8+5,0x1000*8+5, 0x1000*8+6,0x1000*8+6, 0x1000*8+7,0x1000*8+7, - 0x2000*8,0x2000*8, 0x2000*8+1,0x2000*8+1, 0x2000*8+2,0x2000*8+2, 0x2000*8+3,0x2000*8+3, 0x2000*8+4,0x2000*8+4, 0x2000*8+5,0x2000*8+5, 0x2000*8+6,0x2000*8+6, 0x2000*8+7,0x2000*8+7, - 0x3000*8,0x3000*8, 0x3000*8+1,0x3000*8+1, 0x3000*8+2,0x3000*8+2, 0x3000*8+3,0x3000*8+3, 0x3000*8+4,0x3000*8+4, 0x3000*8+5,0x3000*8+5, 0x3000*8+6,0x3000*8+6, 0x3000*8+7,0x3000*8+7, -}; - - -static const gfx_layout spyhuntpr_charlayout = -{ - 64,16, - RGN_FRAC(1,8), - 4, - { 0*8, 0x4000*8 + 2*8, 0x4000*8 + 0*8, 2*8 }, - EXTENDED_XOFFS, - { 0*8, 4*8, 8*8, 12*8, 16*8, 20*8, 24*8, 28*8, 1*8, 5*8, 9*8, 13*8, 17*8, 21*8, 25*8, 29*8 }, - 32*8, - spyhuntp_charlayout_xoffset, - nullptr -}; static GFXDECODE_START( mcr3 ) GFXDECODE_SCALE( "gfx1", 0, mcr_bg_layout, 0, 4, 2, 2 ) @@ -1265,11 +1071,6 @@ static GFXDECODE_START( spyhunt ) GFXDECODE_ENTRY( "gfx3", 0, spyhunt_alphalayout, 4*16, 1 ) GFXDECODE_END -static GFXDECODE_START( spyhuntpr ) - GFXDECODE_ENTRY( "gfx1", 0, spyhuntpr_charlayout, 3*16, 1 ) - GFXDECODE_ENTRY( "gfx2", 0, spyhuntpr_sprite_layout, 0*16, 4 ) - GFXDECODE_ENTRY( "gfx3", 0, spyhuntpr_alphalayout, 4*16, 1 ) -GFXDECODE_END /************************************* * @@ -1379,78 +1180,6 @@ MACHINE_CONFIG_END -static ADDRESS_MAP_START( spyhuntpr_sound_map, AS_PROGRAM, 8, mcr3_state ) - AM_RANGE(0x0000, 0x1fff) AM_ROM - AM_RANGE(0x8000, 0x83ff) AM_RAM -// AM_RANGE(0xfe00, 0xffff) AM_RAM -ADDRESS_MAP_END - -static ADDRESS_MAP_START( spyhuntpr_sound_portmap, AS_IO, 8, mcr3_state ) - ADDRESS_MAP_UNMAP_HIGH - ADDRESS_MAP_GLOBAL_MASK(0xff) - - AM_RANGE(0x12, 0x13) AM_DEVWRITE("ay1", ay8912_device, address_data_w) - AM_RANGE(0x14, 0x15) AM_DEVWRITE("ay2", ay8912_device, address_data_w) - AM_RANGE(0x18, 0x19) AM_DEVWRITE("ay3", ay8912_device, address_data_w) - -ADDRESS_MAP_END - - - -static MACHINE_CONFIG_START( spyhuntpr, mcr3_state ) - -// note: no ctc, no nvram -// 2*z80, 3*ay8912 - - /* basic machine hardware */ - MCFG_CPU_ADD("maincpu", Z80, MASTER_CLOCK/4) - MCFG_CPU_PROGRAM_MAP(spyhuntpr_map) - MCFG_CPU_IO_MAP(spyhuntpr_portmap) - MCFG_CPU_CONFIG(mcr_daisy_chain) - MCFG_TIMER_DRIVER_ADD_SCANLINE("scantimer", mcr3_state, mcr_interrupt, "screen", 0, 1) - - MCFG_DEVICE_ADD("ctc", Z80CTC, MASTER_CLOCK/4 /* same as "maincpu" */) - MCFG_Z80CTC_INTR_CB(INPUTLINE("maincpu", INPUT_LINE_IRQ0)) - MCFG_Z80CTC_ZC0_CB(DEVWRITELINE("ctc", z80ctc_device, trg1)) - - //MCFG_WATCHDOG_VBLANK_INIT(16) - MCFG_MACHINE_START_OVERRIDE(mcr3_state,mcr) - MCFG_MACHINE_RESET_OVERRIDE(mcr3_state,mcr) - -// MCFG_NVRAM_ADD_0FILL("nvram") - - /* video hardware */ - MCFG_SCREEN_ADD("screen", RASTER) - MCFG_SCREEN_VIDEO_ATTRIBUTES(VIDEO_UPDATE_BEFORE_VBLANK) - MCFG_SCREEN_REFRESH_RATE(60) - MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(2500) /* not accurate */) - MCFG_SCREEN_SIZE(30*16, 30*8) - MCFG_SCREEN_VISIBLE_AREA(0, 30*16-1, 0, 30*8-1) - MCFG_SCREEN_UPDATE_DRIVER(mcr3_state, screen_update_spyhuntpr) - MCFG_SCREEN_PALETTE("palette") - - MCFG_GFXDECODE_ADD("gfxdecode", "palette", spyhuntpr) - MCFG_PALETTE_ADD("palette", 64+4) - - MCFG_PALETTE_INIT_OWNER(mcr3_state,spyhunt) - MCFG_VIDEO_START_OVERRIDE(mcr3_state,spyhuntpr) - - - MCFG_CPU_ADD("audiocpu", Z80, 3000000 ) - MCFG_CPU_PROGRAM_MAP(spyhuntpr_sound_map) - MCFG_CPU_IO_MAP(spyhuntpr_sound_portmap) -// MCFG_CPU_PERIODIC_INT_DRIVER(mcr3_state, irq0_line_hold, 4*60) - - MCFG_SPEAKER_STANDARD_MONO("mono") - - MCFG_SOUND_ADD("ay1", AY8912, 3000000/2) // AY-3-8912 - MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25) - MCFG_SOUND_ADD("ay2", AY8912, 3000000/2) // " - MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25) - MCFG_SOUND_ADD("ay3", AY8912, 3000000/2) // " - MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25) - -MACHINE_CONFIG_END @@ -1729,93 +1458,6 @@ ROM_START( spyhuntp ) ROM_END -ROM_START( spyhuntpr ) - ROM_REGION( 0x10000, "maincpu", 0 ) - ROM_LOAD( "1.bin", 0x0000, 0x4000, CRC(2a2f77cb) SHA1(e1b74c951efb2a49bef0507ab3268b274515f339) ) - ROM_LOAD( "2.bin", 0x4000, 0x4000, CRC(00778aff) SHA1(7c0b24c393f841e8379d4bba57ba502e3d2512f9) ) - ROM_LOAD( "3.bin", 0x8000, 0x4000, CRC(2183b4af) SHA1(2b958afc40b26c9bc8d5254b0600426649f4ebf0) ) - ROM_LOAD( "4.bin", 0xc000, 0x2000, CRC(3ea6a65c) SHA1(1320ce17044307ed3c4f2459631a9aa1734f1f30) ) - - ROM_REGION( 0x10000, "audiocpu", 0 ) - ROM_LOAD( "5.bin", 0x0000, 0x2000, CRC(33fe2829) SHA1(e6950dbf681242bf23542ca6604e62eacb431101) ) - - - ROM_REGION( 0x08000, "gfx1", 0 ) - ROM_LOAD32_BYTE( "6.bin", 0x0000, 0x200, CRC(6b76f46a) SHA1(4b398084c42a60fcfa4a9bf14f844e36a3f42723) ) - ROM_CONTINUE(0x0001, 0x200) - ROM_CONTINUE(0x0800, 0x200) - ROM_CONTINUE(0x0801, 0x200) - ROM_CONTINUE(0x1000, 0x200) - ROM_CONTINUE(0x1001, 0x200) - ROM_CONTINUE(0x1800, 0x200) - ROM_CONTINUE(0x1801, 0x200) - ROM_CONTINUE(0x2000, 0x200) - ROM_CONTINUE(0x2001, 0x200) - ROM_CONTINUE(0x2800, 0x200) - ROM_CONTINUE(0x2801, 0x200) - ROM_CONTINUE(0x3000, 0x200) - ROM_CONTINUE(0x3001, 0x200) - ROM_CONTINUE(0x3800, 0x200) - ROM_CONTINUE(0x3801, 0x200) - ROM_LOAD32_BYTE( "7.bin", 0x0002, 0x200, CRC(085bd7a7) SHA1(c35c309b6c6485baec54d4434dea44abf4d48f41) ) - ROM_CONTINUE(0x0003, 0x200) - ROM_CONTINUE(0x0802, 0x200) - ROM_CONTINUE(0x0803, 0x200) - ROM_CONTINUE(0x1002, 0x200) - ROM_CONTINUE(0x1003, 0x200) - ROM_CONTINUE(0x1802, 0x200) - ROM_CONTINUE(0x1803, 0x200) - ROM_CONTINUE(0x2002, 0x200) - ROM_CONTINUE(0x2003, 0x200) - ROM_CONTINUE(0x2802, 0x200) - ROM_CONTINUE(0x2803, 0x200) - ROM_CONTINUE(0x3002, 0x200) - ROM_CONTINUE(0x3003, 0x200) - ROM_CONTINUE(0x3802, 0x200) - ROM_CONTINUE(0x3803, 0x200) - ROM_LOAD32_BYTE( "8.bin", 0x4000, 0x200, CRC(e699b329) SHA1(cb4b8c7b6fa1cb1144a18f1442dc3b267c408914) ) - ROM_CONTINUE(0x4001, 0x200) - ROM_CONTINUE(0x4800, 0x200) - ROM_CONTINUE(0x4801, 0x200) - ROM_CONTINUE(0x5000, 0x200) - ROM_CONTINUE(0x5001, 0x200) - ROM_CONTINUE(0x5800, 0x200) - ROM_CONTINUE(0x5801, 0x200) - ROM_CONTINUE(0x6000, 0x200) - ROM_CONTINUE(0x6001, 0x200) - ROM_CONTINUE(0x6800, 0x200) - ROM_CONTINUE(0x6801, 0x200) - ROM_CONTINUE(0x7000, 0x200) - ROM_CONTINUE(0x7001, 0x200) - ROM_CONTINUE(0x7800, 0x200) - ROM_CONTINUE(0x7801, 0x200) - ROM_LOAD32_BYTE( "9.bin", 0x4002, 0x200, CRC(6d462ec7) SHA1(0ff37f75b0eeceb86177a3f7c93834d5c0e24515) ) - ROM_CONTINUE(0x4003, 0x200) - ROM_CONTINUE(0x4802, 0x200) - ROM_CONTINUE(0x4803, 0x200) - ROM_CONTINUE(0x5002, 0x200) - ROM_CONTINUE(0x5003, 0x200) - ROM_CONTINUE(0x5802, 0x200) - ROM_CONTINUE(0x5803, 0x200) - ROM_CONTINUE(0x6002, 0x200) - ROM_CONTINUE(0x6003, 0x200) - ROM_CONTINUE(0x6802, 0x200) - ROM_CONTINUE(0x6803, 0x200) - ROM_CONTINUE(0x7002, 0x200) - ROM_CONTINUE(0x7003, 0x200) - ROM_CONTINUE(0x7802, 0x200) - ROM_CONTINUE(0x7803, 0x200) - - ROM_REGION( 0x10000, "gfx2", ROMREGION_INVERT ) - ROM_LOAD( "10.bin", 0x00000, 0x4000, CRC(6f9fd416) SHA1(a51c86e5b22c91fc44673f53400b58af40b18065) ) - ROM_LOAD( "11.bin", 0x04000, 0x4000, CRC(75526ffe) SHA1(ff1adf6f9b6595114d0bd06b72d9eb7bbf70144d) ) - ROM_LOAD( "12.bin", 0x08000, 0x4000, CRC(82ee7a4d) SHA1(184720de76680275bf7c4a171f03a0ce771d91fc) ) - ROM_LOAD( "13.bin", 0x0c000, 0x4000, CRC(0cc592a3) SHA1(b3563bde83432cdbaedb88d4d222da30bf679b08) ) - - - ROM_REGION( 0x01000, "gfx3", 0 ) - ROM_LOAD( "14.bin", 0x00000, 0x1000, CRC(87a4c130) SHA1(7792afdc36b0f3bd51c387d04d38f60c85fd2e93) ) -ROM_END ROM_START( crater ) @@ -1976,16 +1618,7 @@ DRIVER_INIT_MEMBER(mcr3_state,spyhunt) m_spyhunt_scroll_offset = 16; } -DRIVER_INIT_MEMBER(mcr3_state,spyhuntpr) -{ - mcr_common_init(); -// machine().device<midway_ssio_device>("ssio")->set_custom_input(1, 0x60, read8_delegate(FUNC(mcr3_state::spyhunt_ip1_r),this)); -// machine().device<midway_ssio_device>("ssio")->set_custom_input(2, 0xff, read8_delegate(FUNC(mcr3_state::spyhunt_ip2_r),this)); -// machine().device<midway_ssio_device>("ssio")->set_custom_output(4, 0xff, write8_delegate(FUNC(mcr3_state::spyhunt_op4_w),this)); - m_spyhunt_sprite_color_mask = 0x00; - m_spyhunt_scroll_offset = 16; -} DRIVER_INIT_MEMBER(mcr3_state,crater) { @@ -2036,6 +1669,3 @@ GAMEL(1983, spyhuntp, spyhunt, mcrsc_csd, spyhunt, mcr3_state, spyhunt, ROT9 GAME( 1984, crater, 0, mcrscroll, crater, mcr3_state, crater, ORIENTATION_FLIP_X, "Bally Midway", "Crater Raider", MACHINE_SUPPORTS_SAVE ) GAMEL(1985, turbotag, 0, mcrsc_csd, turbotag, mcr3_state, turbotag, ROT90, "Bally Midway", "Turbo Tag (prototype)", MACHINE_SUPPORTS_SAVE, layout_turbotag ) -// very different hardware, probably bootleg despite the license text printed on the PCB, similar to '1942p' in 1942.c. Probably should be put in separate driver. -// PCB made by Tecfri for Recreativos Franco S.A. in Spain, has Bally Midway logo, and licensing text on the PCB. Board is dated '85' so seems to be a low-cost rebuild? it is unclear if it made it to market. -GAME (1983, spyhuntpr,spyhunt, spyhuntpr, spyhuntpr,mcr3_state, spyhuntpr,ROT90, "Bally Midway (Recreativos Franco S.A. license)", "Spy Hunter (Spain, Tecfri / Recreativos Franco S.A. PCB)", MACHINE_NOT_WORKING | MACHINE_SUPPORTS_SAVE ) diff --git a/src/mame/drivers/spartanxtec.cpp b/src/mame/drivers/spartanxtec.cpp new file mode 100644 index 00000000000..e6e31577864 --- /dev/null +++ b/src/mame/drivers/spartanxtec.cpp @@ -0,0 +1,441 @@ +// license:BSD-3-Clause +// copyright-holders:David Haywood +/* + +Kung-Fu Master / Spartan X (Tecfri bootleg) +single PCB with 2x Z80 +similar looking to the '1942p' and 'spyhuntpr' PCBs + + +P2 inputs don't work in 'cocktail' mode (maybe it's just unsupported on this PCB?) + +DIPS etc. are near the 2nd CPU, should it be reading them? + +visible area is 16 lines less than the original, otherwise you get bad sprites +but I think this is probably correct. + +some sprites are a bit glitchy when entering playfield (see title screen) +probably an original bug? + +*/ + +#include "emu.h" +#include "cpu/z80/z80.h" +#include "includes/iremipt.h" +#include "sound/ay8910.h" + +class spartanxtec_state : public driver_device +{ +public: + spartanxtec_state(const machine_config &mconfig, device_type type, const char *tag) + : driver_device(mconfig, type, tag), + m_m62_tileram(*this, "m62_tileram"), + m_spriteram(*this, "spriteram"), + m_scroll_lo(*this, "scroll_lo"), + m_scroll_hi(*this, "scroll_hi"), + m_maincpu(*this, "maincpu"), + m_audiocpu(*this, "audiocpu"), + m_palette(*this, "palette"), + m_gfxdecode(*this, "gfxdecode") + { } + + required_shared_ptr<UINT8> m_m62_tileram; + required_shared_ptr<UINT8> m_spriteram; + required_shared_ptr<UINT8> m_scroll_lo; + required_shared_ptr<UINT8> m_scroll_hi; + required_device<cpu_device> m_maincpu; + required_device<cpu_device> m_audiocpu; + + virtual void machine_start() override; + virtual void machine_reset() override; + virtual void video_start() override; + void draw_sprites(bitmap_ind16 &bitmap, const rectangle &cliprect); + UINT32 screen_update_spartanxtec(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); + DECLARE_PALETTE_INIT(spartanxtec); + + tilemap_t* m_bg_tilemap; + DECLARE_WRITE8_MEMBER(kungfum_tileram_w); + TILE_GET_INFO_MEMBER(get_kungfum_bg_tile_info); + DECLARE_WRITE8_MEMBER(spartanxtec_soundlatch_w); + DECLARE_WRITE8_MEMBER(a801_w); + DECLARE_WRITE8_MEMBER(sound_irq_ack); + DECLARE_WRITE8_MEMBER(irq_ack); + + required_device<palette_device> m_palette; + required_device<gfxdecode_device> m_gfxdecode; + + +}; + + + + +WRITE8_MEMBER(spartanxtec_state::kungfum_tileram_w) +{ + m_m62_tileram[offset] = data; + m_bg_tilemap->mark_tile_dirty(offset & 0x7ff); +} + + +TILE_GET_INFO_MEMBER(spartanxtec_state::get_kungfum_bg_tile_info) +{ + int code; + int color; + int flags; + code = m_m62_tileram[tile_index]; + color = m_m62_tileram[tile_index + 0x800]; + flags = 0; + if ((color & 0x20)) + { + flags |= TILE_FLIPX; + } + SET_TILE_INFO_MEMBER(0, code | ((color & 0xc0)<< 2), color & 0x1f, flags); + + /* is the following right? */ + if ((tile_index / 64) < 6 || ((color & 0x1f) >> 1) > 0x0c) + tileinfo.category = 1; + else + tileinfo.category = 0; +} + +void spartanxtec_state::video_start() +{ + m_bg_tilemap = &machine().tilemap().create(m_gfxdecode, tilemap_get_info_delegate(FUNC(spartanxtec_state::get_kungfum_bg_tile_info),this), TILEMAP_SCAN_ROWS, 8, 8, 64, 32); + m_bg_tilemap->set_scroll_rows(32); +} + + +void spartanxtec_state::draw_sprites(bitmap_ind16 &bitmap, const rectangle &cliprect ) +{ + gfx_element *gfx = m_gfxdecode->gfx(1); + + for (int i = 0; i < 0x400; i += 4) + { + int x = m_spriteram[i+2]+128; + int y = (224-m_spriteram[i+1])&0xff; + int code = m_spriteram[i+0]; + int attr = m_spriteram[i+3]; + code |= (attr & 0xc0) << 2; + + int colour = attr & 0x1f; + int flipx = attr & 0x20; + int flipy = 0; + + gfx->transpen(bitmap,cliprect,code,colour,flipx,flipy,x,y,7); + + } + + +} + + +UINT32 spartanxtec_state::screen_update_spartanxtec(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) +{ + // there are 4 sets of scroll registers + // how to split them isn't clear, 4 groups of 8 rows would be logical + // but only 6 rows should use the first scroll register and the + // remaining 2 rows scroll values from there can't wrap onto the bottom + // as that doesn't work. (breaks bottom 2 lines of playfield scroll) + // HOWEVER sprites are also broken in that area, so I think this bootleg + // probably just displays less lines. + + + for (int i = 0; i < 32; i++) + { + int scrollval; + + scrollval = m_scroll_lo[i/8] | (m_scroll_hi[i/8] << 8); + + m_bg_tilemap->set_scrollx((i-2)&0xff, scrollval+28-128); + } + + m_bg_tilemap->draw(screen, bitmap, cliprect, 0, 0); + draw_sprites(bitmap, cliprect); + m_bg_tilemap->draw(screen, bitmap, cliprect, 1, 0); + + return 0; +} + + + + +WRITE8_MEMBER(spartanxtec_state::spartanxtec_soundlatch_w) +{ + soundlatch_byte_w(space, 0, data); + m_audiocpu->set_input_line(INPUT_LINE_NMI, PULSE_LINE); +} + +WRITE8_MEMBER(spartanxtec_state::a801_w) +{ + if (data != 0xf0) printf("a801_w %02x\n", data); +} + +WRITE8_MEMBER(spartanxtec_state::irq_ack) +{ + m_maincpu->set_input_line(INPUT_LINE_IRQ0, CLEAR_LINE); +} + + +static ADDRESS_MAP_START( spartanxtec_map, AS_PROGRAM, 8, spartanxtec_state ) + AM_RANGE(0x0000, 0x7fff) AM_ROM + AM_RANGE(0xc400, 0xc7ff) AM_RAM AM_SHARE("spriteram") + + AM_RANGE(0x8000, 0x8000) AM_WRITE(spartanxtec_soundlatch_w) + + AM_RANGE(0x8100, 0x8100) AM_READ_PORT("DSW1") + AM_RANGE(0x8101, 0x8101) AM_READ_PORT("DSW2") + AM_RANGE(0x8102, 0x8102) AM_READ_PORT("SYSTEM") + AM_RANGE(0x8103, 0x8103) AM_READ_PORT("P1") + + AM_RANGE(0x8200, 0x8200) AM_WRITE(irq_ack) + + AM_RANGE(0xA801, 0xA801) AM_WRITE(a801_w) + + AM_RANGE(0xa900, 0xa903) AM_RAM AM_SHARE("scroll_lo") + AM_RANGE(0xa980, 0xa983) AM_RAM AM_SHARE("scroll_hi") + + AM_RANGE(0xd000, 0xdfff) AM_RAM_WRITE(kungfum_tileram_w) AM_SHARE("m62_tileram") + + AM_RANGE(0xe000, 0xefff) AM_RAM + +ADDRESS_MAP_END + + + +WRITE8_MEMBER(spartanxtec_state::sound_irq_ack) +{ + m_audiocpu->set_input_line(INPUT_LINE_IRQ0, CLEAR_LINE); +} + + +static ADDRESS_MAP_START( spartanxtec_sound_map, AS_PROGRAM, 8, spartanxtec_state ) + + AM_RANGE(0x0000, 0x0fff) AM_ROM + AM_RANGE(0x8000, 0x83ff) AM_RAM + + AM_RANGE(0xc000, 0xc000) AM_READ(soundlatch_byte_r) +ADDRESS_MAP_END + +static ADDRESS_MAP_START( spartanxtec_sound_io, AS_IO, 8, spartanxtec_state ) + ADDRESS_MAP_GLOBAL_MASK(0xff) + AM_RANGE(0x0000, 0x0000) AM_WRITE( sound_irq_ack ) + + AM_RANGE(0x0012, 0x0013) AM_DEVWRITE("ay3", ay8910_device, address_data_w) + AM_RANGE(0x0012, 0x0012) AM_DEVREAD("ay3", ay8910_device, data_r) + + AM_RANGE(0x0014, 0x0015) AM_DEVWRITE("ay1", ay8910_device, address_data_w) + AM_RANGE(0x0014, 0x0014) AM_DEVREAD("ay1", ay8910_device, data_r) + + AM_RANGE(0x0018, 0x0019) AM_DEVWRITE("ay2", ay8910_device, address_data_w) + AM_RANGE(0x0018, 0x0018) AM_DEVREAD("ay2", ay8910_device, data_r) +ADDRESS_MAP_END + + + + +static INPUT_PORTS_START( spartanxtec ) + PORT_START("DSW1") + PORT_DIPNAME( 0x01, 0x01, DEF_STR( Difficulty ) ) PORT_DIPLOCATION("SW1:1") + PORT_DIPSETTING( 0x01, DEF_STR( Easy ) ) + PORT_DIPSETTING( 0x00, DEF_STR( Hard ) ) + PORT_DIPNAME( 0x02, 0x02, "Energy Loss" ) PORT_DIPLOCATION("SW1:2") + PORT_DIPSETTING( 0x02, "Slow" ) + PORT_DIPSETTING( 0x00, "Fast" ) + PORT_DIPNAME( 0x0c, 0x0c, DEF_STR( Lives ) ) PORT_DIPLOCATION("SW1:3,4") + PORT_DIPSETTING( 0x08, "2" ) + PORT_DIPSETTING( 0x0c, "3" ) + PORT_DIPSETTING( 0x04, "4" ) + PORT_DIPSETTING( 0x00, "5" ) + /* Manual says that only coin mode 1 is available and SW2:3 should be always OFF */ + /* However, coin mode 2 works perfectly. */ + IREM_Z80_COINAGE_TYPE_3_LOC(SW1) + + PORT_START("DSW2") + PORT_DIPNAME( 0x01, 0x01, DEF_STR( Flip_Screen ) ) PORT_DIPLOCATION("SW2:1") + PORT_DIPSETTING( 0x01, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x00, DEF_STR( On ) ) + PORT_DIPNAME( 0x02, 0x00, DEF_STR( Cabinet ) ) PORT_DIPLOCATION("SW2:2") + PORT_DIPSETTING( 0x00, DEF_STR( Upright ) ) + PORT_DIPSETTING( 0x02, "Cocktail (invalid?)" ) + PORT_DIPNAME( 0x04, 0x04, "Coin Mode" ) PORT_DIPLOCATION("SW2:3") + PORT_DIPSETTING( 0x04, "Mode 1" ) + PORT_DIPSETTING( 0x00, "Mode 2" ) + /* In slowmo mode, press 2 to slow game speed */ + PORT_DIPNAME( 0x08, 0x08, "Slow Motion Mode (Cheat)" ) PORT_DIPLOCATION("SW2:4") + PORT_DIPSETTING( 0x08, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x00, DEF_STR( On ) ) + /* In freeze mode, press 2 to stop and 1 to restart */ + PORT_DIPNAME( 0x10, 0x10, "Freeze (Cheat)" ) PORT_DIPLOCATION("SW2:5") + PORT_DIPSETTING( 0x10, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x00, DEF_STR( On ) ) + /* In level selection mode, press 1 to select and 2 to restart */ + PORT_DIPNAME( 0x20, 0x20, "Level Selection Mode (Cheat)" ) PORT_DIPLOCATION("SW2:6") + PORT_DIPSETTING( 0x20, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x00, DEF_STR( On ) ) + PORT_DIPNAME( 0x40, 0x40, "Invulnerability (Cheat)" ) PORT_DIPLOCATION("SW2:7") + PORT_DIPSETTING( 0x40, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x00, DEF_STR( On ) ) + PORT_SERVICE_DIPLOC( 0x80, IP_ACTIVE_LOW, "SW2:8" ) + + PORT_START("SYSTEM") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_START1 ) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_START2 ) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_SERVICE1 ) PORT_IMPULSE(19) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_COIN1 ) + PORT_BIT( 0xf0, IP_ACTIVE_LOW, IPT_UNUSED ) + + PORT_START("P1") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_8WAY + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_8WAY + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_8WAY + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_8WAY + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_UNKNOWN ) /* probably unused */ + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_BUTTON2 ) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNKNOWN ) /* probably unused */ + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_BUTTON1 ) +INPUT_PORTS_END + + +static const gfx_layout tiles8x8_layout = +{ + 8,8, + RGN_FRAC(1,3), + 3, + { RGN_FRAC(0,3),RGN_FRAC(1,3),RGN_FRAC(2,3) }, + { 0,1,2,3,4,5,6,7 }, + { 0*8, 1*8, 2*8, 3*8, 4*8, 5*8, 6*8, 7*8 }, + 8*8 +}; + +static const gfx_layout tiles16x16_layout = +{ + 16,16, + RGN_FRAC(1,3), + 3, + { RGN_FRAC(0,3),RGN_FRAC(1,3),RGN_FRAC(2,3) }, + { 0,1,2,3,4,5,6,7, 128, 129, 130, 131, 132, 133, 134, 135 }, + { 0*8, 1*8, 2*8, 3*8, 4*8, 5*8, 6*8, 7*8, 8*8, 9*8, 10*8, 11*8, 12*8, 13*8, 14*8, 15*8 }, + 32*8 +}; + + +static GFXDECODE_START( news ) + GFXDECODE_ENTRY( "gfx1", 0, tiles8x8_layout, 0x100, 32 ) + GFXDECODE_ENTRY( "gfx2", 0, tiles16x16_layout, 0, 32 ) +GFXDECODE_END + + + +void spartanxtec_state::machine_start() +{ +} + +void spartanxtec_state::machine_reset() +{ +} + +PALETTE_INIT_MEMBER(spartanxtec_state, spartanxtec) +{ + // todo, proper weights for this bootleg PCB + const UINT8 *color_prom = memregion("cprom")->base(); + for (int i = 0; i < 0x200; i++) + { + int r, g, b; + + b = (color_prom[i+0x000]&0x0f)<<4; + g = (color_prom[i+0x200]&0x0f)<<4; + r = (color_prom[i+0x400]&0x0f)<<4; + + palette.set_pen_color(i, rgb_t(r,g,b)); + } +} + + + +static MACHINE_CONFIG_START( spartanxtec, spartanxtec_state ) + + /* basic machine hardware */ + MCFG_CPU_ADD("maincpu", Z80,4000000) /* ? MHz */ + MCFG_CPU_PROGRAM_MAP(spartanxtec_map) + MCFG_CPU_VBLANK_INT_DRIVER("screen", spartanxtec_state, irq0_line_assert) + + MCFG_CPU_ADD("audiocpu", Z80,4000000) + MCFG_CPU_PROGRAM_MAP(spartanxtec_sound_map) + MCFG_CPU_IO_MAP(spartanxtec_sound_io) + MCFG_CPU_PERIODIC_INT_DRIVER(spartanxtec_state, irq0_line_assert, 1000) // controls speed of music +// MCFG_CPU_VBLANK_INT_DRIVER("screen", spartanxtec_state, irq0_line_hold) + + /* video hardware */ + // todo, proper screen timings for this bootleg PCB - as visible area is less it's probably ~60hz, not 55 + MCFG_SCREEN_ADD("screen", RASTER) + MCFG_SCREEN_REFRESH_RATE(60) + MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(1790)) + MCFG_SCREEN_SIZE(64*8, 32*8) + MCFG_SCREEN_VISIBLE_AREA((64*8-256)/2, 64*8-(64*8-256)/2-1, 0*8, 32*8-1-16) + MCFG_SCREEN_UPDATE_DRIVER(spartanxtec_state, screen_update_spartanxtec) + MCFG_SCREEN_PALETTE("palette") + + MCFG_PALETTE_ADD("palette", 0x200) + MCFG_PALETTE_INIT_OWNER(spartanxtec_state,spartanxtec) + + MCFG_GFXDECODE_ADD("gfxdecode", "palette", news) + + /* sound hardware */ + MCFG_SPEAKER_STANDARD_MONO("mono") + + MCFG_SOUND_ADD("ay1", AY8910, 1000000) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25) + MCFG_SOUND_ADD("ay2", AY8910, 1000000) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25) + MCFG_SOUND_ADD("ay3", AY8910, 1000000) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25) + +MACHINE_CONFIG_END + + + +ROM_START( spartanxtec ) + ROM_REGION( 0x10000, "maincpu", 0 ) + ROM_LOAD( "1.bin", 0x00000, 0x04000, CRC(d5d6cddf) SHA1(baaec83be455bf2267d51ea2a2c1fcda22f27bd5) ) + ROM_LOAD( "2.bin", 0x04000, 0x04000, CRC(2803bb72) SHA1(d0f93c61f3f08fb866e2a4617a7824e72f61c97f) ) + + ROM_REGION( 0x10000, "audiocpu", 0 ) + ROM_LOAD( "3.bin", 0x00000, 0x01000, CRC(9a18af94) SHA1(1644295aa0c837dced5934360e41d77e0a93ccd1) ) + + ROM_REGION( 0x6000, "gfx1", ROMREGION_INVERT ) + ROM_LOAD( "5.bin", 0x00000, 0x0800, CRC(8a3d2978) SHA1(e50ba8d63e894c6a555d92c3144682be68f111b0)) + ROM_CONTINUE(0x1000, 0x0800) + ROM_CONTINUE(0x0800, 0x0800) + ROM_CONTINUE(0x1800, 0x0800) + ROM_LOAD( "6.bin", 0x02000, 0x0800, CRC(b1570b6b) SHA1(380a692309690e6ff6b57fda657192fff95167e0) ) + ROM_CONTINUE(0x3000, 0x0800) + ROM_CONTINUE(0x2800, 0x0800) + ROM_CONTINUE(0x3800, 0x0800) + ROM_LOAD( "4.bin", 0x04000, 0x0800, CRC(b55672ef) SHA1(7bd556a76e130be1262aa7db09df84c6463ce9ef) ) + ROM_CONTINUE(0x5000, 0x0800) + ROM_CONTINUE(0x4800, 0x0800) + ROM_CONTINUE(0x5800, 0x0800) + + ROM_REGION( 0x18000, "gfx2", ROMREGION_INVERT ) + ROM_LOAD( "7.bin", 0x00000, 0x08000, CRC(aa897e30) SHA1(90b3b316800be106d3baa6783ca894703f369d4e) ) + ROM_LOAD( "8.bin", 0x08000, 0x08000, CRC(98a1803b) SHA1(3edfc45c289f850b07a0231ce0b792cbec6fb245) ) + ROM_LOAD( "9.bin", 0x10000, 0x08000, CRC(e3bf0d73) SHA1(4562422c07399e240081792b96b9018d1e7dd97b) ) + + ROM_REGION( 0x600, "cprom", 0 ) + // first half of all of these is empty + ROM_LOAD( "4_MCM7643_82s137.BIN", 0x0000, 0x0200, CRC(548a0ab1) SHA1(e414b61feba73bcc1a53e17c848aceea3b8100e7) ) ROM_CONTINUE(0x0000,0x0200) + ROM_LOAD( "5_MCM7643_82s137.BIN", 0x0200, 0x0200, CRC(a678480e) SHA1(515fa2b09c666a46dc145313eda3c465afff4451) ) ROM_CONTINUE(0x0200,0x0200) + ROM_LOAD( "6_MCM7643_82s137.BIN", 0x0400, 0x0200, CRC(5a707f85) SHA1(35932daf453787780550464b78465581e1ef35e1) ) ROM_CONTINUE(0x0400,0x0200) + + ROM_REGION( 0x18000, "timing", 0 ) // i think + ROM_LOAD( "7_82s147.BIN", 0x0000, 0x0200, CRC(54a9e294) SHA1(d44d21ab8141bdfe697fd303cdc1b5c4177909bc) ) + + ROM_REGION( 0x18000, "unkprom", 0 ) // just linear increasing value + ROM_LOAD( "1_tbp24s10_82s129.BIN", 0x0000, 0x0100, CRC(b6135ee0) SHA1(248a978987cff86c2bbad10ef332f63a6abd5bee) ) + ROM_LOAD( "2_tbp24s10_82s129.BIN", 0x0000, 0x0100, CRC(b6135ee0) SHA1(248a978987cff86c2bbad10ef332f63a6abd5bee) ) +ROM_END + + + +GAME( 1987, spartanxtec, kungfum, spartanxtec, spartanxtec, driver_device, 0, ROT0, "bootleg (Tecfri)", "Spartan X (Tecfri hardware bootleg)", 0 ) + diff --git a/src/mame/drivers/spyhuntertec.cpp b/src/mame/drivers/spyhuntertec.cpp new file mode 100644 index 00000000000..783dc87905c --- /dev/null +++ b/src/mame/drivers/spyhuntertec.cpp @@ -0,0 +1,795 @@ +// license:BSD-3-Clause +// copyright-holders:David Haywood +/* + +Spy Hunter(Tecfri bootleg) +single PCB with 2x Z80 + +significant changes compared to original HW + +Very different hardware, probably bootleg despite the license text printed on the PCB, similar to '1942p' and 'spartanxtec.cpp' +PCB made by Tecfri for Recreativos Franco S.A. in Spain, has Bally Midway logo, and licensing text on the PCB. +Board is dated '85' so seems to be a low-cost rebuild? it is unclear if it made it to market. + +non-interlaced + +sound system appears to be the same as 'spartanxtec.cpp' + +analog inputs seem to be read by the sound CPU, with serial communication + +*/ + +#include "emu.h" +#include "cpu/z80/z80.h" +#include "sound/ay8910.h" + + +#define MASTER_CLOCK XTAL_20MHz // ?? + +class spyhuntertec_state : public driver_device +{ +public: + spyhuntertec_state(const machine_config &mconfig, device_type type, const char *tag) + : driver_device(mconfig, type, tag), + m_audiocpu(*this, "audiocpu"), + m_videoram(*this, "videoram"), + m_spriteram(*this, "spriteram"), + m_spriteram2(*this, "spriteram2"), + m_paletteram(*this, "paletteram"), + m_spyhunt_alpharam(*this, "spyhunt_alpha"), + m_palette(*this, "palette"), + m_gfxdecode(*this, "gfxdecode"), + m_screen(*this, "screen") + { } + + + required_device<cpu_device> m_audiocpu; + required_shared_ptr<UINT8> m_videoram; + required_shared_ptr<UINT8> m_spriteram; + required_shared_ptr<UINT8> m_spriteram2; + required_shared_ptr<UINT8> m_paletteram; + required_shared_ptr<UINT8> m_spyhunt_alpharam; + + virtual void machine_start() override; + virtual void machine_reset() override; + virtual void video_start() override; + void draw_sprites(bitmap_ind16 &bitmap, const rectangle &cliprect); + UINT32 screen_update_spyhuntertec(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); + + + required_device<palette_device> m_palette; + required_device<gfxdecode_device> m_gfxdecode; + required_device<screen_device> m_screen; + + UINT8 m_spyhunt_sprite_color_mask; + INT16 m_spyhunt_scroll_offset; + INT16 m_spyhunt_scrollx; + INT16 m_spyhunt_scrolly; + + int mcr_cocktail_flip; + + tilemap_t *m_alpha_tilemap; + tilemap_t *m_bg_tilemap; + DECLARE_WRITE8_MEMBER(spyhuntertec_paletteram_w); + DECLARE_DRIVER_INIT(spyhuntertec); +// DECLARE_VIDEO_START(spyhuntertec); +// UINT32 screen_update_spyhuntertec(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); + DECLARE_WRITE8_MEMBER(spyhuntertec_port04_w); + DECLARE_WRITE8_MEMBER(spyhuntertec_fd00_w); + DECLARE_WRITE8_MEMBER(spyhuntertec_portf0_w); + + DECLARE_WRITE8_MEMBER(spyhunt_videoram_w); + DECLARE_WRITE8_MEMBER(spyhunt_alpharam_w); + DECLARE_WRITE8_MEMBER(spyhunt_scroll_value_w); + DECLARE_WRITE8_MEMBER(sound_irq_ack); + + + DECLARE_WRITE8_MEMBER(ay1_porta_w); + DECLARE_READ8_MEMBER(ay1_porta_r); + + DECLARE_WRITE8_MEMBER(ay2_porta_w); + DECLARE_READ8_MEMBER(ay2_porta_r); + + DECLARE_READ8_MEMBER(spyhuntertec_in2_r); + DECLARE_READ8_MEMBER(spyhuntertec_in3_r); + + TILEMAP_MAPPER_MEMBER(spyhunt_bg_scan); + TILE_GET_INFO_MEMBER(spyhunt_get_bg_tile_info); + TILE_GET_INFO_MEMBER(spyhunt_get_alpha_tile_info); + void mcr3_update_sprites(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect, int color_mask, int code_xor, int dx, int dy, int interlaced); + + +}; + +WRITE8_MEMBER(spyhuntertec_state::ay1_porta_w) +{ +// printf("ay1_porta_w %02x\n", data); +} + +READ8_MEMBER(spyhuntertec_state::ay1_porta_r) +{ +// printf("ay1_porta_r\n"); + return 0; +} + + + +WRITE8_MEMBER(spyhuntertec_state::ay2_porta_w) +{ +// printf("ay2_porta_w %02x\n", data); +} + +READ8_MEMBER(spyhuntertec_state::ay2_porta_r) +{ +// read often, even if port is set to output mode +// maybe latches something? +// printf("ay2_porta_r\n"); + return rand(); +} + +WRITE8_MEMBER(spyhuntertec_state::spyhunt_videoram_w) +{ + UINT8 *videoram = m_videoram; + videoram[offset] = data; + m_bg_tilemap->mark_tile_dirty(offset); +} + + +WRITE8_MEMBER(spyhuntertec_state::spyhunt_alpharam_w) +{ + m_spyhunt_alpharam[offset] = data; + m_alpha_tilemap->mark_tile_dirty(offset); +} + + +WRITE8_MEMBER(spyhuntertec_state::spyhunt_scroll_value_w) +{ + switch (offset) + { + case 0: + /* low 8 bits of horizontal scroll */ + m_spyhunt_scrollx = (m_spyhunt_scrollx & ~0xff) | data; + break; + + case 1: + /* upper 3 bits of horizontal scroll and upper 1 bit of vertical scroll */ + m_spyhunt_scrollx = (m_spyhunt_scrollx & 0xff) | ((data & 0x07) << 8); + m_spyhunt_scrolly = (m_spyhunt_scrolly & 0xff) | ((data & 0x80) << 1); + break; + + case 2: + /* low 8 bits of vertical scroll */ + m_spyhunt_scrolly = (m_spyhunt_scrolly & ~0xff) | data; + break; + } +} + + +WRITE8_MEMBER(spyhuntertec_state::spyhuntertec_paletteram_w) +{ + m_paletteram[offset] = data; + offset = (offset & 0x0f) | (offset & 0x60) >> 1; + + int r = (data & 0x07) >> 0; + int g = (data & 0x38) >> 3; + int b = (data & 0xc0) >> 6; + + m_palette->set_pen_color(offset^0xf, rgb_t(r<<5,g<<5,b<<6)); +} + + +TILEMAP_MAPPER_MEMBER(spyhuntertec_state::spyhunt_bg_scan) +{ + /* logical (col,row) -> memory offset */ + return (row & 0x0f) | ((col & 0x3f) << 4) | ((row & 0x10) << 6); +} + + +TILE_GET_INFO_MEMBER(spyhuntertec_state::spyhunt_get_bg_tile_info) +{ + UINT8 *videoram = m_videoram; + int data = videoram[tile_index]; + int code = (data & 0x3f) | ((data >> 1) & 0x40); + SET_TILE_INFO_MEMBER(0, code, 0, (data & 0x40) ? TILE_FLIPY : 0); +} + + +TILE_GET_INFO_MEMBER(spyhuntertec_state::spyhunt_get_alpha_tile_info) +{ + SET_TILE_INFO_MEMBER(2, m_spyhunt_alpharam[tile_index], 0, 0); +} + + + +void spyhuntertec_state::video_start() +{ + /* initialize the background tilemap */ + m_bg_tilemap = &machine().tilemap().create(m_gfxdecode, tilemap_get_info_delegate(FUNC(spyhuntertec_state::spyhunt_get_bg_tile_info),this), tilemap_mapper_delegate(FUNC(spyhuntertec_state::spyhunt_bg_scan),this), 64,16, 64,32); + + /* initialize the text tilemap */ + m_alpha_tilemap = &machine().tilemap().create(m_gfxdecode, tilemap_get_info_delegate(FUNC(spyhuntertec_state::spyhunt_get_alpha_tile_info),this), TILEMAP_SCAN_COLS, 16,8, 32,32); + m_alpha_tilemap->set_transparent_pen(0); + m_alpha_tilemap->set_scrollx(0, 16); + + save_item(NAME(m_spyhunt_sprite_color_mask)); + save_item(NAME(m_spyhunt_scrollx)); + save_item(NAME(m_spyhunt_scrolly)); + save_item(NAME(m_spyhunt_scroll_offset)); +} + + + + +void spyhuntertec_state::mcr3_update_sprites(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect, int color_mask, int code_xor, int dx, int dy, int interlaced) +{ + UINT8 *spriteram = m_spriteram; + int offs; + + m_screen->priority().fill(1, cliprect); + + /* loop over sprite RAM */ + for (offs = m_spriteram.bytes() - 4; offs >= 0; offs -= 4) + { + int code, color, flipx, flipy, sx, sy, flags; + + /* skip if zero */ + if (spriteram[offs] == 0) + continue; + +/* + monoboard: + flags.d0 -> ICG0~ -> PCG0~/PCG2~/PCG4~/PCG6~ -> bit 4 of linebuffer + flags.d1 -> ICG1~ -> PCG1~/PCG3~/PCG5~/PCG7~ -> bit 5 of linebuffer + flags.d2 -> IPPR -> PPR0 /PPR1 /PPR2 /PPR3 -> bit 6 of linebuffer + flags.d3 -> IRA15 ----------------------------> address line 15 of FG ROMs + flags.d4 -> HFLIP + flags.d5 -> VFLIP + +*/ + + /* extract the bits of information */ + flags = spriteram[offs + 1]; + code = spriteram[offs + 2] + 256 * ((flags >> 3) & 0x01); + color = ~flags & color_mask; + flipx = flags & 0x10; + flipy = flags & 0x20; + sx = (spriteram[offs + 3] - 3) * 2; + sy = (241 - spriteram[offs]); + + if (interlaced == 1) sy *= 2; + + code ^= code_xor; + + sx += dx; + sy += dy; + + /* sprites use color 0 for background pen and 8 for the 'under tile' pen. + The color 8 is used to cover over other sprites. */ + if (!mcr_cocktail_flip) + { + /* first draw the sprite, visible */ + m_gfxdecode->gfx(1)->prio_transmask(bitmap,cliprect, code, color, flipx, flipy, sx, sy, + screen.priority(), 0x00, 0x0101); + + /* then draw the mask, behind the background but obscuring following sprites */ + m_gfxdecode->gfx(1)->prio_transmask(bitmap,cliprect, code, color, flipx, flipy, sx, sy, + screen.priority(), 0x02, 0xfeff); + } + else + { + /* first draw the sprite, visible */ + m_gfxdecode->gfx(1)->prio_transmask(bitmap,cliprect, code, color, !flipx, !flipy, 480 - sx, 452 - sy, + screen.priority(), 0x00, 0x0101); + + /* then draw the mask, behind the background but obscuring following sprites */ + m_gfxdecode->gfx(1)->prio_transmask(bitmap,cliprect, code, color, !flipx, !flipy, 480 - sx, 452 - sy, + screen.priority(), 0x02, 0xfeff); + } + } +} + + +UINT32 spyhuntertec_state::screen_update_spyhuntertec(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) +{ + /* for every character in the Video RAM, check if it has been modified */ + /* since last time and update it accordingly. */ + m_bg_tilemap->set_scrollx(0, m_spyhunt_scrollx * 2 + m_spyhunt_scroll_offset); + m_bg_tilemap->set_scrolly(0, m_spyhunt_scrolly * 2); + m_bg_tilemap->draw(screen, bitmap, cliprect, 0, 0); + + /* draw the sprites */ + mcr3_update_sprites(screen, bitmap, cliprect, m_spyhunt_sprite_color_mask, 0, -12, 0, 0); + + /* render any characters on top */ + m_alpha_tilemap->draw(screen, bitmap, cliprect, 0, 0); + return 0; +} + + + +WRITE8_MEMBER(spyhuntertec_state::spyhuntertec_fd00_w) +{ +// printf("%04x spyhuntertec_fd00_w %02x\n", space.device().safe_pc(), data); + soundlatch_byte_w(space, 0, data); + m_audiocpu->set_input_line(INPUT_LINE_NMI, PULSE_LINE); +} + +READ8_MEMBER(spyhuntertec_state::spyhuntertec_in2_r) +{ + // it writes 04 / 14 to the sound latch (spyhuntertec_fd00_w) before + // reading bit 6 here a minimum of 32 times. + // seems to be how it reads the analog controls? probably via sound CPU?? + + /* note, these commands trigger a read from ay2_porta on the sound cpu side, followed by 2 writes + + a52a spyhuntertec_fd00_w 14 + ay2_porta_r + ay2_porta_w 80 + ay2_porta_w 00 + a52a spyhuntertec_fd00_w 04 + ay2_porta_r + ay2_porta_w 81 + ay2_porta_w 01 + */ + + /* + + -- input reading code here + A388: 3E 14 ld a,$14 + A38A: 28 04 jr z,$A390 + A38C: DD 23 inc ix + A38E: 3E 04 ld a,$04 + A390: CD 20 A5 call $A520 << write command to sub-cpu + + -- delay loop / timeout loop for reading result? value of b doesn't get used in the end + A393: 06 1F ld b,$1F << loop counter + A395: 21 02 FC ld hl,$FC02 + loopstart: + A398: CB 76 bit 6,(hl) + A39A: 28 06 jr z,$A3A2 to dest2 + A39C: 10 FA djnz $A398 (to loopstart) + + A39E: 06 0F ld b,$0F < + A3A0: 18 1E jr $A3C0 to dest 3 + + dest2: + A3A2: 06 33 ld b,$33 << loop counter + loop2start: + A3A4: CB 76 bit 6,(hl) + A3A6: 20 11 jr nz,$A3B9 (to outofloop) + A3A8: CB 76 bit 6,(hl) + A3AA: 00 nop + A3AB: CB 76 bit 6,(hl) + A3AD: 20 0A jr nz,$A3B9 (to outofloop) + A3AF: 10 F3 djnz $A3A4 (to loop2start) + + A3B1: 00 nop + A3B2: 00 nop + A3B3: 00 nop + A3B4: 00 nop + A3B5: 00 nop + A3B6: 00 nop + A3B7: 00 nop + A3B8: 00 nop + + outofloop: + A3B9: 78 ld a,b + A3BA: FE 20 cp $20 + A3BC: 38 02 jr c,$A3C0 + A3BE: 06 1F ld b,$1F + + dest3: + A3C0: 21 B6 A6 ld hl,$A6B6 + ... + + + */ + + UINT8 ret = ioport("IN2")->read(); +// printf("%04x spyhuntertec_in2_r\n", space.device().safe_pc()); + return ret; +} + +READ8_MEMBER(spyhuntertec_state::spyhuntertec_in3_r) +{ + UINT8 ret = ioport("IN3")->read(); +// printf("%04x spyhuntertec_in3_r\n", space.device().safe_pc()); + return ret; +} + +static ADDRESS_MAP_START( spyhuntertec_map, AS_PROGRAM, 8, spyhuntertec_state ) + ADDRESS_MAP_UNMAP_HIGH + AM_RANGE(0xa800, 0xa8ff) AM_RAM // the ROM is a solid fill in these areas, and they get tested as RAM, I think they moved the 'real' scroll regs here + AM_RANGE(0xa900, 0xa9ff) AM_RAM + + AM_RANGE(0x0000, 0xdfff) AM_ROM + + AM_RANGE(0xe000, 0xe7ff) AM_RAM_WRITE(spyhunt_videoram_w) AM_SHARE("videoram") + AM_RANGE(0xe800, 0xebff) AM_MIRROR(0x0400) AM_RAM_WRITE(spyhunt_alpharam_w) AM_SHARE("spyhunt_alpha") + AM_RANGE(0xf000, 0xf7ff) AM_RAM //AM_SHARE("nvram") + AM_RANGE(0xf800, 0xf9ff) AM_RAM AM_SHARE("spriteram") // origional spriteram + AM_RANGE(0xfa00, 0xfa7f) AM_MIRROR(0x0180) AM_RAM_WRITE(spyhuntertec_paletteram_w) AM_SHARE("paletteram") + + AM_RANGE(0xfc00, 0xfc00) AM_READ_PORT("DSW0") + AM_RANGE(0xfc01, 0xfc01) AM_READ_PORT("DSW1") + AM_RANGE(0xfc02, 0xfc02) AM_READ(spyhuntertec_in2_r) + AM_RANGE(0xfc03, 0xfc03) AM_READ(spyhuntertec_in3_r) + + AM_RANGE(0xfd00, 0xfd00) AM_WRITE( spyhuntertec_fd00_w ) + + AM_RANGE(0xfe00, 0xffff) AM_RAM AM_SHARE("spriteram2") // actual spriteram for this hw?? +ADDRESS_MAP_END + +WRITE8_MEMBER(spyhuntertec_state::spyhuntertec_port04_w) +{ +} + +WRITE8_MEMBER(spyhuntertec_state::spyhuntertec_portf0_w) +{ + // 0x08 on startup, then 0x03, probably CTC leftovers from the original. + if ((data != 0x03) && (data != 0x08)) printf("spyhuntertec_portf0_w %02x\n", data); +} + +static ADDRESS_MAP_START( spyhuntertec_portmap, AS_IO, 8, spyhuntertec_state ) + ADDRESS_MAP_UNMAP_HIGH + ADDRESS_MAP_GLOBAL_MASK(0xff) + AM_RANGE(0x04, 0x04) AM_WRITE(spyhuntertec_port04_w) + AM_RANGE(0x84, 0x86) AM_WRITE(spyhunt_scroll_value_w) + AM_RANGE(0xe0, 0xe0) AM_WRITENOP // was watchdog +// AM_RANGE(0xe8, 0xe8) AM_WRITENOP + AM_RANGE(0xf0, 0xf0) AM_WRITE( spyhuntertec_portf0_w ) +ADDRESS_MAP_END + + +static ADDRESS_MAP_START( spyhuntertec_sound_map, AS_PROGRAM, 8, spyhuntertec_state ) + AM_RANGE(0x0000, 0x1fff) AM_ROM + AM_RANGE(0x8000, 0x83ff) AM_RAM + + AM_RANGE(0xc000, 0xc000) AM_READ(soundlatch_byte_r) +ADDRESS_MAP_END + + +WRITE8_MEMBER(spyhuntertec_state::sound_irq_ack) +{ + m_audiocpu->set_input_line(INPUT_LINE_IRQ0, CLEAR_LINE); +} + +static ADDRESS_MAP_START( spyhuntertec_sound_portmap, AS_IO, 8, spyhuntertec_state ) + ADDRESS_MAP_UNMAP_HIGH + ADDRESS_MAP_GLOBAL_MASK(0xff) + + AM_RANGE(0x00, 0x00) AM_WRITE(sound_irq_ack) + + AM_RANGE(0x0012, 0x0013) AM_DEVWRITE("ay3", ay8910_device, address_data_w) + AM_RANGE(0x0012, 0x0012) AM_DEVREAD("ay3", ay8910_device, data_r) + + AM_RANGE(0x0014, 0x0015) AM_DEVWRITE("ay1", ay8910_device, address_data_w) + AM_RANGE(0x0014, 0x0014) AM_DEVREAD("ay1", ay8910_device, data_r) + + AM_RANGE(0x0018, 0x0019) AM_DEVWRITE("ay2", ay8910_device, address_data_w) // data written to port a + AM_RANGE(0x0018, 0x0018) AM_DEVREAD("ay2", ay8910_device, data_r) // actually read + +ADDRESS_MAP_END + + + +static INPUT_PORTS_START( spyhuntertec ) + PORT_START("DSW0") + PORT_DIPNAME( 0x01, 0x01, "DSW0-01" ) + PORT_DIPSETTING( 0x01, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x00, DEF_STR( On ) ) + PORT_DIPNAME( 0x02, 0x02, "DSW0-02" ) + PORT_DIPSETTING( 0x02, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x00, DEF_STR( On ) ) + PORT_DIPNAME( 0x04, 0x04, "DSW0-04" ) + PORT_DIPSETTING( 0x04, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x00, DEF_STR( On ) ) + PORT_DIPNAME( 0x08, 0x08, "DSW0-08" ) + PORT_DIPSETTING( 0x08, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x00, DEF_STR( On ) ) + PORT_DIPNAME( 0x10, 0x10, "DSW0-10" ) + PORT_DIPSETTING( 0x10, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x00, DEF_STR( On ) ) + PORT_DIPNAME( 0x20, 0x20, "DSW0-20" ) + PORT_DIPSETTING( 0x20, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x00, DEF_STR( On ) ) + PORT_DIPNAME( 0x40, 0x40, "DSW0-40" ) + PORT_DIPSETTING( 0x40, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x00, DEF_STR( On ) ) + PORT_DIPNAME( 0x80, 0x80, "DSW0-80" ) + PORT_DIPSETTING( 0x80, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x00, DEF_STR( On ) ) + + PORT_START("DSW1") + PORT_DIPNAME( 0x01, 0x01, "DSW1-01" ) + PORT_DIPSETTING( 0x01, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x00, DEF_STR( On ) ) + PORT_DIPNAME( 0x02, 0x02, "DSW1-02" ) + PORT_DIPSETTING( 0x02, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x00, DEF_STR( On ) ) + PORT_SERVICE( 0x04, IP_ACTIVE_LOW ) + PORT_DIPNAME( 0x08, 0x08, "DSW1-08" ) + PORT_DIPSETTING( 0x08, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x00, DEF_STR( On ) ) + PORT_DIPNAME( 0x10, 0x10, "DSW1-10" ) + PORT_DIPSETTING( 0x10, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x00, DEF_STR( On ) ) + PORT_DIPNAME( 0x20, 0x20, "DSW1-20" ) + PORT_DIPSETTING( 0x20, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x00, DEF_STR( On ) ) + PORT_DIPNAME( 0x40, 0x40, "DSW1-40" ) + PORT_DIPSETTING( 0x40, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x00, DEF_STR( On ) ) + PORT_DIPNAME( 0x80, 0x80, "DSW1-80" ) + PORT_DIPSETTING( 0x80, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x00, DEF_STR( On ) ) + + PORT_START("IN2") + PORT_DIPNAME( 0x0001, 0x0001, "2" ) + PORT_DIPSETTING( 0x0001, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x0000, DEF_STR( On ) ) + PORT_DIPNAME( 0x0002, 0x0002, "start" ) // start + PORT_DIPSETTING( 0x0002, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x0000, DEF_STR( On ) ) + PORT_DIPNAME( 0x0004, 0x0004, DEF_STR( Unknown ) ) + PORT_DIPSETTING( 0x0004, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x0000, DEF_STR( On ) ) + PORT_DIPNAME( 0x0008, 0x0008, DEF_STR( Unknown ) ) + PORT_DIPSETTING( 0x0008, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x0000, DEF_STR( On ) ) + PORT_DIPNAME( 0x0010, 0x0010, "handbrake?" ) + PORT_DIPSETTING( 0x0010, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x0000, DEF_STR( On ) ) + PORT_DIPNAME( 0x0020, 0x0020, DEF_STR( Unknown ) ) + PORT_DIPSETTING( 0x0020, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x0000, DEF_STR( On ) ) + PORT_DIPNAME( 0x0040, 0x0040, "pedal inverse" ) + PORT_DIPSETTING( 0x0040, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x0000, DEF_STR( On ) ) + PORT_DIPNAME( 0x0080, 0x0080, DEF_STR( Unknown ) ) + PORT_DIPSETTING( 0x0080, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x0000, DEF_STR( On ) ) + + PORT_START("IN3") + PORT_DIPNAME( 0x0001, 0x0001, "3" ) + PORT_DIPSETTING( 0x0001, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x0000, DEF_STR( On ) ) + PORT_DIPNAME( 0x0002, 0x0002, DEF_STR( Unknown ) ) + PORT_DIPSETTING( 0x0002, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x0000, DEF_STR( On ) ) + PORT_DIPNAME( 0x0004, 0x0004, DEF_STR( Unknown ) ) + PORT_DIPSETTING( 0x0004, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x0000, DEF_STR( On ) ) + PORT_DIPNAME( 0x0008, 0x0008, DEF_STR( Unknown ) ) + PORT_DIPSETTING( 0x0008, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x0000, DEF_STR( On ) ) + PORT_DIPNAME( 0x0010, 0x0010, DEF_STR( Unknown ) ) + PORT_DIPSETTING( 0x0010, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x0000, DEF_STR( On ) ) + PORT_DIPNAME( 0x0020, 0x0020, DEF_STR( Unknown ) ) + PORT_DIPSETTING( 0x0020, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x0000, DEF_STR( On ) ) + PORT_DIPNAME( 0x0040, 0x0040, "coin" ) // coin? + PORT_DIPSETTING( 0x0040, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x0000, DEF_STR( On ) ) + PORT_DIPNAME( 0x0080, 0x0080, "machineguns" ) // machine guns + PORT_DIPSETTING( 0x0080, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x0000, DEF_STR( On ) ) +INPUT_PORTS_END + + +static const gfx_layout spyhuntertec_alphalayout = +{ + 16,8, + RGN_FRAC(1,1), + 2, + { 0, 4}, + { 0, 0, 1, 1, 2, 2, 3, 3, 8, 8, 9, 9, 10, 10, 11, 11 }, + { 0, 2*8, 4*8, 6*8, 8*8, 10*8, 12*8, 14*8 }, + 16*8 +}; + + +const gfx_layout spyhuntertec_sprite_layout = +{ + 32,16, + RGN_FRAC(1,4), + 4, + { RGN_FRAC(3,4), RGN_FRAC(2,4), RGN_FRAC(1,4), RGN_FRAC(0,4) }, + { 6,7, 4,5, 2,3, 0,1, 14,15, 12,13, 10,11, 8,9, 22,23, 20,21, 18,19, 16,17, 30,31, 28,29, 26,27, 24,25 }, + { 0*32,1*32,2*32,3*32,4*32,5*32,6*32,7*32,8*32,9*32,10*32,11*32,12*32,13*32,14*32,15*32 }, + + 16*32 +}; + + +static const UINT32 spyhuntp_charlayout_xoffset[64] = +{ + 0x0000*8,0x0000*8, 0x0000*8+1,0x0000*8+1, 0x0000*8+2,0x0000*8+2, 0x0000*8+3,0x0000*8+3, 0x0000*8+4,0x0000*8+4, 0x0000*8+5,0x0000*8+5, 0x0000*8+6,0x0000*8+6, 0x0000*8+7,0x0000*8+7, + 0x1000*8,0x1000*8, 0x1000*8+1,0x1000*8+1, 0x1000*8+2,0x1000*8+2, 0x1000*8+3,0x1000*8+3, 0x1000*8+4,0x1000*8+4, 0x1000*8+5,0x1000*8+5, 0x1000*8+6,0x1000*8+6, 0x1000*8+7,0x1000*8+7, + 0x2000*8,0x2000*8, 0x2000*8+1,0x2000*8+1, 0x2000*8+2,0x2000*8+2, 0x2000*8+3,0x2000*8+3, 0x2000*8+4,0x2000*8+4, 0x2000*8+5,0x2000*8+5, 0x2000*8+6,0x2000*8+6, 0x2000*8+7,0x2000*8+7, + 0x3000*8,0x3000*8, 0x3000*8+1,0x3000*8+1, 0x3000*8+2,0x3000*8+2, 0x3000*8+3,0x3000*8+3, 0x3000*8+4,0x3000*8+4, 0x3000*8+5,0x3000*8+5, 0x3000*8+6,0x3000*8+6, 0x3000*8+7,0x3000*8+7, +}; + + +static const gfx_layout spyhuntertec_charlayout = +{ + 64,16, + RGN_FRAC(1,8), + 4, + { 0*8, 0x4000*8 + 2*8, 0x4000*8 + 0*8, 2*8 }, + EXTENDED_XOFFS, + { 0*8, 4*8, 8*8, 12*8, 16*8, 20*8, 24*8, 28*8, 1*8, 5*8, 9*8, 13*8, 17*8, 21*8, 25*8, 29*8 }, + 32*8, + spyhuntp_charlayout_xoffset, + nullptr +}; + + +static GFXDECODE_START( spyhuntertec ) + GFXDECODE_ENTRY( "gfx1", 0, spyhuntertec_charlayout, 3*16, 1 ) + GFXDECODE_ENTRY( "gfx2", 0, spyhuntertec_sprite_layout, 0*16, 4 ) + GFXDECODE_ENTRY( "gfx3", 0, spyhuntertec_alphalayout, 4*16, 1 ) +GFXDECODE_END + + + +void spyhuntertec_state::machine_start() +{ +} + +void spyhuntertec_state::machine_reset() +{ +} + + + + +static MACHINE_CONFIG_START( spyhuntertec, spyhuntertec_state ) + +// note: no ctc, no nvram +// 2*z80, 3*ay8912 + + /* basic machine hardware */ + MCFG_CPU_ADD("maincpu", Z80, MASTER_CLOCK/4) + MCFG_CPU_PROGRAM_MAP(spyhuntertec_map) + MCFG_CPU_IO_MAP(spyhuntertec_portmap) + MCFG_CPU_VBLANK_INT_DRIVER("screen", spyhuntertec_state, irq0_line_hold) + + /* video hardware */ + MCFG_SCREEN_ADD("screen", RASTER) + MCFG_SCREEN_VIDEO_ATTRIBUTES(VIDEO_UPDATE_BEFORE_VBLANK) + MCFG_SCREEN_REFRESH_RATE(60) + MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(2500) /* not accurate */) + MCFG_SCREEN_SIZE(30*16, 30*8) + MCFG_SCREEN_VISIBLE_AREA(0, 30*16-1, 0, 30*8-1) + MCFG_SCREEN_UPDATE_DRIVER(spyhuntertec_state, screen_update_spyhuntertec) + MCFG_SCREEN_PALETTE("palette") + + MCFG_GFXDECODE_ADD("gfxdecode", "palette", spyhuntertec) + MCFG_PALETTE_ADD("palette", 64+4) + +// MCFG_PALETTE_INIT_OWNER(spyhuntertec_state,spyhunt) + + + MCFG_CPU_ADD("audiocpu", Z80, 4000000 ) + MCFG_CPU_PROGRAM_MAP(spyhuntertec_sound_map) + MCFG_CPU_IO_MAP(spyhuntertec_sound_portmap) + MCFG_CPU_PERIODIC_INT_DRIVER(spyhuntertec_state, irq0_line_assert, 1000) + + MCFG_SPEAKER_STANDARD_MONO("mono") + + MCFG_SOUND_ADD("ay1", AY8912, 3000000/2) // AY-3-8912 + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25) + MCFG_AY8910_PORT_A_READ_CB(READ8(spyhuntertec_state, ay1_porta_r)) + MCFG_AY8910_PORT_A_WRITE_CB(WRITE8(spyhuntertec_state, ay1_porta_w)) + + MCFG_SOUND_ADD("ay2", AY8912, 3000000/2) // " + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25) + MCFG_AY8910_PORT_A_READ_CB(READ8(spyhuntertec_state, ay2_porta_r)) + MCFG_AY8910_PORT_A_WRITE_CB(WRITE8(spyhuntertec_state, ay2_porta_w)) + + MCFG_SOUND_ADD("ay3", AY8912, 3000000/2) // " + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25) + +MACHINE_CONFIG_END + + + + +ROM_START( spyhuntpr ) + ROM_REGION( 0x10000, "maincpu", 0 ) + ROM_LOAD( "1.bin", 0x0000, 0x4000, CRC(2a2f77cb) SHA1(e1b74c951efb2a49bef0507ab3268b274515f339) ) + ROM_LOAD( "2.bin", 0x4000, 0x4000, CRC(00778aff) SHA1(7c0b24c393f841e8379d4bba57ba502e3d2512f9) ) + ROM_LOAD( "3.bin", 0x8000, 0x4000, CRC(2183b4af) SHA1(2b958afc40b26c9bc8d5254b0600426649f4ebf0) ) + ROM_LOAD( "4.bin", 0xc000, 0x2000, CRC(3ea6a65c) SHA1(1320ce17044307ed3c4f2459631a9aa1734f1f30) ) + + ROM_REGION( 0x10000, "audiocpu", 0 ) + ROM_LOAD( "5.bin", 0x0000, 0x2000, CRC(33fe2829) SHA1(e6950dbf681242bf23542ca6604e62eacb431101) ) + + + ROM_REGION( 0x08000, "gfx1", 0 ) + ROM_LOAD32_BYTE( "6.bin", 0x0000, 0x200, CRC(6b76f46a) SHA1(4b398084c42a60fcfa4a9bf14f844e36a3f42723) ) + ROM_CONTINUE(0x0001, 0x200) + ROM_CONTINUE(0x0800, 0x200) + ROM_CONTINUE(0x0801, 0x200) + ROM_CONTINUE(0x1000, 0x200) + ROM_CONTINUE(0x1001, 0x200) + ROM_CONTINUE(0x1800, 0x200) + ROM_CONTINUE(0x1801, 0x200) + ROM_CONTINUE(0x2000, 0x200) + ROM_CONTINUE(0x2001, 0x200) + ROM_CONTINUE(0x2800, 0x200) + ROM_CONTINUE(0x2801, 0x200) + ROM_CONTINUE(0x3000, 0x200) + ROM_CONTINUE(0x3001, 0x200) + ROM_CONTINUE(0x3800, 0x200) + ROM_CONTINUE(0x3801, 0x200) + ROM_LOAD32_BYTE( "7.bin", 0x0002, 0x200, CRC(085bd7a7) SHA1(c35c309b6c6485baec54d4434dea44abf4d48f41) ) + ROM_CONTINUE(0x0003, 0x200) + ROM_CONTINUE(0x0802, 0x200) + ROM_CONTINUE(0x0803, 0x200) + ROM_CONTINUE(0x1002, 0x200) + ROM_CONTINUE(0x1003, 0x200) + ROM_CONTINUE(0x1802, 0x200) + ROM_CONTINUE(0x1803, 0x200) + ROM_CONTINUE(0x2002, 0x200) + ROM_CONTINUE(0x2003, 0x200) + ROM_CONTINUE(0x2802, 0x200) + ROM_CONTINUE(0x2803, 0x200) + ROM_CONTINUE(0x3002, 0x200) + ROM_CONTINUE(0x3003, 0x200) + ROM_CONTINUE(0x3802, 0x200) + ROM_CONTINUE(0x3803, 0x200) + ROM_LOAD32_BYTE( "8.bin", 0x4000, 0x200, CRC(e699b329) SHA1(cb4b8c7b6fa1cb1144a18f1442dc3b267c408914) ) + ROM_CONTINUE(0x4001, 0x200) + ROM_CONTINUE(0x4800, 0x200) + ROM_CONTINUE(0x4801, 0x200) + ROM_CONTINUE(0x5000, 0x200) + ROM_CONTINUE(0x5001, 0x200) + ROM_CONTINUE(0x5800, 0x200) + ROM_CONTINUE(0x5801, 0x200) + ROM_CONTINUE(0x6000, 0x200) + ROM_CONTINUE(0x6001, 0x200) + ROM_CONTINUE(0x6800, 0x200) + ROM_CONTINUE(0x6801, 0x200) + ROM_CONTINUE(0x7000, 0x200) + ROM_CONTINUE(0x7001, 0x200) + ROM_CONTINUE(0x7800, 0x200) + ROM_CONTINUE(0x7801, 0x200) + ROM_LOAD32_BYTE( "9.bin", 0x4002, 0x200, CRC(6d462ec7) SHA1(0ff37f75b0eeceb86177a3f7c93834d5c0e24515) ) + ROM_CONTINUE(0x4003, 0x200) + ROM_CONTINUE(0x4802, 0x200) + ROM_CONTINUE(0x4803, 0x200) + ROM_CONTINUE(0x5002, 0x200) + ROM_CONTINUE(0x5003, 0x200) + ROM_CONTINUE(0x5802, 0x200) + ROM_CONTINUE(0x5803, 0x200) + ROM_CONTINUE(0x6002, 0x200) + ROM_CONTINUE(0x6003, 0x200) + ROM_CONTINUE(0x6802, 0x200) + ROM_CONTINUE(0x6803, 0x200) + ROM_CONTINUE(0x7002, 0x200) + ROM_CONTINUE(0x7003, 0x200) + ROM_CONTINUE(0x7802, 0x200) + ROM_CONTINUE(0x7803, 0x200) + + ROM_REGION( 0x10000, "gfx2", ROMREGION_INVERT ) + ROM_LOAD( "10.bin", 0x00000, 0x4000, CRC(6f9fd416) SHA1(a51c86e5b22c91fc44673f53400b58af40b18065) ) + ROM_LOAD( "11.bin", 0x04000, 0x4000, CRC(75526ffe) SHA1(ff1adf6f9b6595114d0bd06b72d9eb7bbf70144d) ) + ROM_LOAD( "12.bin", 0x08000, 0x4000, CRC(82ee7a4d) SHA1(184720de76680275bf7c4a171f03a0ce771d91fc) ) + ROM_LOAD( "13.bin", 0x0c000, 0x4000, CRC(0cc592a3) SHA1(b3563bde83432cdbaedb88d4d222da30bf679b08) ) + + + ROM_REGION( 0x01000, "gfx3", 0 ) + ROM_LOAD( "14.bin", 0x00000, 0x1000, CRC(87a4c130) SHA1(7792afdc36b0f3bd51c387d04d38f60c85fd2e93) ) +ROM_END + +DRIVER_INIT_MEMBER(spyhuntertec_state,spyhuntertec) +{ + m_spyhunt_sprite_color_mask = 0x00; + m_spyhunt_scroll_offset = 16; +} + + +GAME (1983, spyhuntpr,spyhunt, spyhuntertec, spyhuntertec,spyhuntertec_state, spyhuntertec,ROT90, "Bally Midway (Recreativos Franco S.A. license)", "Spy Hunter (Spain, Tecfri / Recreativos Franco S.A. PCB)", MACHINE_NOT_WORKING | MACHINE_SUPPORTS_SAVE ) diff --git a/src/mame/drivers/toki.cpp b/src/mame/drivers/toki.cpp index 5799e0d239c..46d0ef11f0f 100644 --- a/src/mame/drivers/toki.cpp +++ b/src/mame/drivers/toki.cpp @@ -542,6 +542,47 @@ ROM_START( toki ) ROM_END +ROM_START( tokip ) + ROM_REGION( 0x60000, "maincpu", 0 ) /* 6*64k for 68000 code */ + ROM_LOAD16_BYTE( "6 10-M", 0x00000, 0x20000, CRC(91b554a3) SHA1(ab003e82552eba381099eb2d00577f952cad42f7) ) // different + ROM_LOAD16_BYTE( "4 10-K", 0x00001, 0x20000, CRC(404220f7) SHA1(f614692d05f1280cbe801fe0486a611f38b5e866) ) // different + ROM_LOAD16_BYTE( "5 12-M", 0x40000, 0x10000, CRC(d6a82808) SHA1(9fcd3e97f7eaada5374347383dc8a6cea2378f7f) ) + ROM_LOAD16_BYTE( "3 12-K", 0x40001, 0x10000, CRC(a01a5b10) SHA1(76d6da114105402aab9dd5167c0c00a0bddc3bba) ) + + ROM_REGION( 0x20000, "audiocpu", 0 ) /* Z80 code, banked data */ + ROM_LOAD( "8 3-M", 0x00000, 0x02000, CRC(6c87c4c5) SHA1(d76822bcde3d42afae72a0945b6acbf3c6a1d955) ) /* encrypted */ + ROM_LOAD( "7 7-M", 0x10000, 0x10000, CRC(a67969c4) SHA1(99781fbb005b6ba4a19a9cc83c8b257a3b425fa6) ) /* banked stuff */ + + ROM_REGION( 0x020000, "gfx1", 0 ) + ROM_LOAD( "1 5-C", 0x000000, 0x10000, CRC(fd0ff303) SHA1(e861b8efd7b3050b95a7d9ff1732bb9641e4dbcc) ) /* chars */ // different + ROM_LOAD( "2 3-C", 0x010000, 0x10000, CRC(86e87e48) SHA1(29634d8c58ef7195cd0ce166f1b7fae01bbc110b) ) + + ROM_REGION( 0x100000, "gfx2", 0 ) + ROM_LOAD16_BYTE( "OBJ 1-0.ROM10", 0x00000, 0x20000, CRC(a027bd8e) SHA1(33cc4ae75332ab35df1c03f74db8cb17f2749ead) ) + ROM_LOAD16_BYTE( "OBJ 1-1.ROM9", 0x00001, 0x20000, CRC(43a767ea) SHA1(bfc879ff714828f7a1b8f784db8728c91287ed20) ) + ROM_LOAD16_BYTE( "OBJ 1-2.ROM12", 0x40000, 0x20000, CRC(1aecc9d8) SHA1(e7a79783e71de472f07761f9dc71f2a78e629676) ) + ROM_LOAD16_BYTE( "OBJ 1-3.ROM11", 0x40001, 0x20000, CRC(d65c0c6d) SHA1(6b895ce06dae1ecc21c64993defbb3be6b6f8ac2) ) + ROM_LOAD16_BYTE( "OBJ 2-0.ROM14", 0x80000, 0x20000, CRC(cedaccaf) SHA1(82f135c9f6a51e49df543e370861918d582a7923) ) + ROM_LOAD16_BYTE( "OBJ 2-1.ROM13", 0x80001, 0x20000, CRC(013f539b) SHA1(d62c048a95b9c331cedc5343f70947bb50e49c87) ) + ROM_LOAD16_BYTE( "OBJ 2-2.ROM16", 0xc0000, 0x20000, CRC(6a8e6e22) SHA1(a6144201e9a18aa46f65957694653a40071d92d4) ) + ROM_LOAD16_BYTE( "OBJ 2-3.ROM15", 0xc0001, 0x20000, CRC(25d9a16c) SHA1(059d1e2e874bb41f8ef576e0cf33bdbffb57ddc0) ) + + ROM_REGION( 0x080000, "gfx3", 0 ) + ROM_LOAD16_BYTE( "BACK 1-0.ROM5", 0x00000, 0x20000, CRC(fac7e32f) SHA1(13f789c209aa6a6866dfc5a83ca68d83271b12c6) ) + ROM_LOAD16_BYTE( "BACK 1-1.ROM6", 0x00001, 0x20000 ,CRC(ee1135d6) SHA1(299bb3f82d6ded4f401fb407e298842a47a45b1d) ) + ROM_LOAD16_BYTE( "BACK 1-2.ROM7", 0x40000, 0x20000, CRC(78db8d57) SHA1(a03bb854205c410c05d9a82f20354370c0af0bda) ) + ROM_LOAD16_BYTE( "BACK 1-3.ROM8", 0x40001, 0x20000, CRC(d719de71) SHA1(decbb5213d97f75b80ae74e4ccf2ff465d1dfad9) ) + + ROM_REGION( 0x080000, "gfx4", 0 ) + ROM_LOAD16_BYTE( "BACK 2-0.ROM1", 0x00000, 0x20000, CRC(949d8025) SHA1(919821647d1bfd0b5b35afcb1c76fddc51a74854)) + ROM_LOAD16_BYTE( "BACK 2-1.ROM2", 0x00001, 0x20000, CRC(4b28b4b4) SHA1(22e5d9098069833ab1dcc89abe07f9ade1b00459) ) + ROM_LOAD16_BYTE( "BACK 2-2.ROM3", 0x40000, 0x20000, CRC(1aa9a5cf) SHA1(305101589f6f56584c8147456dbb4360eaa31fef) ) + ROM_LOAD16_BYTE( "BACK 2-3.ROM4", 0x40001, 0x20000, CRC(6759571f) SHA1(bff3a73ed33c236b38425570f3eb0bbf9a3ca84c) ) + + ROM_REGION( 0x40000, "oki", 0 ) /* ADPCM samples */ + ROM_LOAD( "9 1-M", 0x00000, 0x20000, CRC(ae7a6b8b) SHA1(1d410f91354ffd1774896b2e64f20a2043607805) ) // +ROM_END + ROM_START( tokia ) ROM_REGION( 0x60000, "maincpu", 0 ) /* 6*64k for 68000 code */ ROM_LOAD16_BYTE( "6.m10", 0x00000, 0x20000, CRC(03d726b1) SHA1(bbe3a1ea1943cd73b821b3de4d5bf3dfbffd2168) ) @@ -912,6 +953,9 @@ DRIVER_INIT_MEMBER(toki_state,jujuba) GAME( 1989, toki, 0, tokie, toki, toki_state, toki, ROT0, "TAD Corporation", "Toki (World, set 1)", MACHINE_SUPPORTS_SAVE ) GAME( 1989, tokiu, toki, tokie, toki, toki_state, toki, ROT0, "TAD Corporation (Fabtek license)", "Toki (US, set 1)", MACHINE_SUPPORTS_SAVE ) +GAME( 1989, tokip, toki, tokie, toki, toki_state, toki, ROT0, "TAD Corporation (Fabtek license)", "Toki (US, prototype?)", MACHINE_SUPPORTS_SAVE ) + + // these 3 are all the same revision, only the region byte differs GAME( 1989, tokia, toki, tokie, toki, toki_state, toki, ROT0, "TAD Corporation", "Toki (World, set 2)", MACHINE_SUPPORTS_SAVE ) GAME( 1989, tokiua,toki, tokie, toki, toki_state, toki, ROT0, "TAD Corporation (Fabtek license)", "Toki (US, set 2)", MACHINE_SUPPORTS_SAVE ) diff --git a/src/mame/drivers/tourvis.cpp b/src/mame/drivers/tourvis.cpp index 769171d5b2f..153c8f6e2ce 100644 --- a/src/mame/drivers/tourvis.cpp +++ b/src/mame/drivers/tourvis.cpp @@ -92,13 +92,12 @@ USA Pro Basketball Veigues * Vigilante - # Volfied + Volfied W-Ring Winning Shot Xevious * Denotes Not Dumped -# Denotes Redump Needed _______________________________________________________________________________________________________________________________________________ | | @@ -1008,7 +1007,7 @@ ROM_END /* Volfied - Taito */ ROM_START(tvvolfd) ROM_REGION( 0x100000, "maincpu", 0 ) - ROM_LOAD( "tourv_volfd.bin", 0x00000, 0x100000, BAD_DUMP CRC(c33efba5) SHA1(41ad4f85e551321487be61e2adbeae67e65c47de) ) + ROM_LOAD( "tourv_volfd.bin", 0x00000, 0x100000, CRC(6349113d) SHA1(b413342122409ea4ed981bd5077285cdcf337890) ) TOURVISION_BIOS ROM_END diff --git a/src/mame/includes/mcr3.h b/src/mame/includes/mcr3.h index dbfcb3529e9..18e2b688d09 100644 --- a/src/mame/includes/mcr3.h +++ b/src/mame/includes/mcr3.h @@ -33,7 +33,6 @@ public: tilemap_t *m_bg_tilemap; tilemap_t *m_alpha_tilemap; - DECLARE_WRITE8_MEMBER(spyhuntpr_paletteram_w); DECLARE_WRITE8_MEMBER(mcr3_videoram_w); DECLARE_WRITE8_MEMBER(spyhunt_videoram_w); DECLARE_WRITE8_MEMBER(spyhunt_alpharam_w); @@ -67,7 +66,6 @@ public: DECLARE_DRIVER_INIT(maxrpm); DECLARE_DRIVER_INIT(rampage); DECLARE_DRIVER_INIT(spyhunt); - DECLARE_DRIVER_INIT(spyhuntpr); DECLARE_DRIVER_INIT(sarge); TILE_GET_INFO_MEMBER(mcrmono_get_bg_tile_info); TILEMAP_MAPPER_MEMBER(spyhunt_bg_scan); @@ -75,14 +73,10 @@ public: TILE_GET_INFO_MEMBER(spyhunt_get_alpha_tile_info); DECLARE_VIDEO_START(mcrmono); DECLARE_VIDEO_START(spyhunt); - DECLARE_VIDEO_START(spyhuntpr); DECLARE_PALETTE_INIT(spyhunt); UINT32 screen_update_mcr3(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); UINT32 screen_update_spyhunt(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); - UINT32 screen_update_spyhuntpr(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); void mcr3_update_sprites(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect, int color_mask, int code_xor, int dx, int dy, int interlaced); void mcr_common_init(); - DECLARE_WRITE8_MEMBER(spyhuntpr_port04_w); - DECLARE_WRITE8_MEMBER(spyhuntpr_fd00_w); }; diff --git a/src/mame/includes/xbox.h b/src/mame/includes/xbox.h index 5022fda6b7b..0dd37a23405 100644 --- a/src/mame/includes/xbox.h +++ b/src/mame/includes/xbox.h @@ -261,7 +261,7 @@ class ohci_function_device { public: ohci_function_device(running_machine &machine); void execute_reset(); - int execute_transfer(int address, int endpoint, int pid, UINT8 *buffer, int size) ; + int execute_transfer(int address, int endpoint, int pid, UINT8 *buffer, int size); protected: virtual int handle_nonstandard_request(int endpoint, USBSetupPacket *setup) { return -1; }; virtual int handle_get_status_request(int endpoint, USBSetupPacket *setup) { return 0; }; @@ -269,6 +269,8 @@ protected: virtual int handle_set_feature_request(int endpoint, USBSetupPacket *setup) { return 0; }; virtual int handle_set_descriptor_request(int endpoint, USBSetupPacket *setup) { return 0; }; virtual int handle_synch_frame_request(int endpoint, USBSetupPacket *setup) { return 0; }; + virtual void handle_status_stage(int endpoint) { return; }; + virtual int handle_bulk_pid(int endpoint, int pid, UINT8 *buffer, int size) { return 0; }; void add_device_descriptor(const USBStandardDeviceDescriptor &descriptor); void add_configuration_descriptor(const USBStandardConfigurationDescriptor &descriptor); @@ -297,6 +299,7 @@ protected: int configurationvalue; UINT8 *descriptors; int descriptors_pos; + bool wantstatuscallback; USBStandardDeviceDescriptor device_descriptor; std::forward_list<usb_device_configuration *> configurations; std::forward_list<usb_device_string *> device_strings; @@ -323,6 +326,8 @@ class ohci_hlean2131qc_device: public ohci_function_device public: ohci_hlean2131qc_device(running_machine &machine); int handle_nonstandard_request(int endpoint, USBSetupPacket *setup) override; + int handle_bulk_pid(int endpoint, int pid, UINT8 *buffer, int size) override; + void set_region_base(UINT8 *data); private: static const USBStandardDeviceDescriptor devdesc; static const USBStandardConfigurationDescriptor condesc; @@ -340,6 +345,8 @@ private: static const UINT8 strdesc0[]; static const UINT8 strdesc1[]; static const UINT8 strdesc2[]; + int maximum_send; + UINT8 *region; }; class ohci_hlean2131sc_device : public ohci_function_device diff --git a/src/mame/machine/xbox.cpp b/src/mame/machine/xbox.cpp index 8924adf9cbf..295347c1d06 100644 --- a/src/mame/machine/xbox.cpp +++ b/src/mame/machine/xbox.cpp @@ -984,6 +984,7 @@ ohci_function_device::ohci_function_device(running_machine &machine) endpoints[e].position = nullptr; } endpoints[0].type = ControlEndpoint; + wantstatuscallback = false; settingaddress = false; configurationvalue = 0; selected_configuration = nullptr; @@ -1253,13 +1254,22 @@ int ohci_function_device::execute_transfer(int address, int endpoint, int pid, U if (pid == SetupPid) { USBSetupPacket *p=(USBSetupPacket *)buffer; + // control transfers are done in 3 stages: first the setup stage, then an optional data stage, then a status stage + // so there are 3 cases: + // 1- control transfer with a data stage where the host sends data to the device + // in this case the sequence of pids transferred is control pid, data out pid, data in pid + // 2- control transfer with a data stage where the host receives data from the device + // in this case the sequence of pids transferred is control pid, data in pid, data out pid + // 3- control transfer without a data stage + // in this case the sequence of pids transferred is control pid, data in pid // define direction 0:host->device 1:device->host - // case == 1, IN data stage and OUT status stage - // case == 0, OUT data stage and IN status stage - // data stage is optional, IN status stage + // direction == 1 -> IN data stage and OUT status stage + // direction == 0 -> OUT data stage and IN status stage + // data stage not present -> IN status stage endpoints[endpoint].controldirection = (p->bmRequestType & 128) >> 7; endpoints[endpoint].controltype = (p->bmRequestType & 0x60) >> 5; endpoints[endpoint].controlrecipient = p->bmRequestType & 0x1f; + wantstatuscallback = false; if (endpoint == 0) { endpoints[endpoint].position = nullptr; // number of byte to transfer in data stage (0 no data stage) @@ -1341,23 +1351,26 @@ int ohci_function_device::execute_transfer(int address, int endpoint, int pid, U return handle_nonstandard_request(endpoint, p); } else if (pid == InPid) { - if (endpoint == 0) { + if (endpoints[endpoint].type == ControlEndpoint) { //if (endpoint == 0) { // if no data has been transferred (except for the setup stage) // and the lenght of this IN transaction is 0 // assume this is the status stage - if ((size == 0) && (endpoints[endpoint].remain == 0)) { - if (settingaddress == true) + if ((endpoints[endpoint].remain == 0) && (size == 0)) { + if ((endpoint == 0) && (settingaddress == true)) { // set of address is active at end of status stage address = newaddress; settingaddress = false; state = AddressState; } + if (wantstatuscallback == true) + handle_status_stage(endpoint); + wantstatuscallback = false; return 0; } // case ==1, give data // case ==0, nothing - // if device->host + // if device->host, since InPid then this is data stage if (endpoints[endpoint].controldirection == DeviceToHost) { // data stage if (size > endpoints[endpoint].remain) @@ -1367,15 +1380,22 @@ int ohci_function_device::execute_transfer(int address, int endpoint, int pid, U endpoints[endpoint].position = endpoints[endpoint].position + size; endpoints[endpoint].remain = endpoints[endpoint].remain - size; } + else { + if (wantstatuscallback == true) + handle_status_stage(endpoint); + wantstatuscallback = false; + } } + else if (endpoints[endpoint].type == BulkEndpoint) + return handle_bulk_pid(endpoint, pid, buffer, size); else return -1; } else if (pid == OutPid) { - if (endpoint == 0) { + if (endpoints[endpoint].type == ControlEndpoint) { //if (endpoint == 0) { // case ==1, nothing // case ==0, give data - // if host->device + // if host->device, since OutPid then this is data stage if (endpoints[endpoint].controldirection == HostToDevice) { // data stage if (size > endpoints[endpoint].remain) @@ -1385,7 +1405,14 @@ int ohci_function_device::execute_transfer(int address, int endpoint, int pid, U endpoints[endpoint].position = endpoints[endpoint].position + size; endpoints[endpoint].remain = endpoints[endpoint].remain - size; } + else { + if (wantstatuscallback == true) + handle_status_stage(endpoint); + wantstatuscallback = false; + } } + else if (endpoints[endpoint].type == BulkEndpoint) + return handle_bulk_pid(endpoint, pid, buffer, size); else return -1; } @@ -1454,25 +1481,43 @@ ohci_hlean2131qc_device::ohci_hlean2131qc_device(running_machine &machine) : add_device_descriptor(devdesc); add_configuration_descriptor(condesc); add_interface_descriptor(intdesc); - add_endpoint_descriptor(enddesc81); - add_endpoint_descriptor(enddesc82); - add_endpoint_descriptor(enddesc83); - add_endpoint_descriptor(enddesc84); - add_endpoint_descriptor(enddesc85); + // it is important to add the endpoints in the same order they are found in the device firmware add_endpoint_descriptor(enddesc01); add_endpoint_descriptor(enddesc02); add_endpoint_descriptor(enddesc03); add_endpoint_descriptor(enddesc04); add_endpoint_descriptor(enddesc05); + add_endpoint_descriptor(enddesc81); + add_endpoint_descriptor(enddesc82); + add_endpoint_descriptor(enddesc83); + add_endpoint_descriptor(enddesc84); + add_endpoint_descriptor(enddesc85); add_string_descriptor(strdesc0); add_string_descriptor(strdesc1); add_string_descriptor(strdesc2); + maximum_send = 0; + region = nullptr; +} + +void ohci_hlean2131qc_device::set_region_base(UINT8 *data) +{ + region = data; } int ohci_hlean2131qc_device::handle_nonstandard_request(int endpoint, USBSetupPacket *setup) { if (endpoint != 0) return -1; + printf("Control request: %x %x %x %x %x %x %x\n\r", endpoint, endpoints[endpoint].controldirection, setup->bmRequestType, setup->bRequest, setup->wValue, setup->wIndex, setup->wLength); + //if ((setup->bRequest == 0x18) && (setup->wValue == 0x8000)) + if (setup->bRequest == 0x17) + { + maximum_send = setup->wIndex; + if (maximum_send > 0x40) + maximum_send = 0x40; + endpoints[2].remain = maximum_send; + endpoints[2].position = region + 0x2000 + setup->wValue; + } for (int n = 0; n < setup->wLength; n++) endpoints[endpoint].buffer[n] = 0xa0 ^ n; endpoints[endpoint].buffer[0] = 0; @@ -1481,6 +1526,20 @@ int ohci_hlean2131qc_device::handle_nonstandard_request(int endpoint, USBSetupPa return 0; } +int ohci_hlean2131qc_device::handle_bulk_pid(int endpoint, int pid, UINT8 *buffer, int size) +{ + printf("Bulk request: %x %d %x\n\r", endpoint, pid, size); + if ((endpoint == 2) && (pid == InPid)) + { + if (size > endpoints[2].remain) + size = endpoints[2].remain; + memcpy(buffer, endpoints[2].position, size); + endpoints[2].position = endpoints[3].position + size; + endpoints[2].remain = endpoints[3].remain - size; + } + return size; +} + //pc20 const USBStandardDeviceDescriptor ohci_hlean2131sc_device::devdesc = { 0x12,0x01,0x0100,0x60,0x01,0x00,0x40,0x0CA3,0x0003,0x0110,0x01,0x02,0x00,0x01 }; const USBStandardConfigurationDescriptor ohci_hlean2131sc_device::condesc = { 0x09,0x02,0x003C,0x01,0x01,0x00,0x80,0x96 }; @@ -1501,12 +1560,13 @@ ohci_hlean2131sc_device::ohci_hlean2131sc_device(running_machine &machine) : add_device_descriptor(devdesc); add_configuration_descriptor(condesc); add_interface_descriptor(intdesc); - add_endpoint_descriptor(enddesc81); - add_endpoint_descriptor(enddesc82); - add_endpoint_descriptor(enddesc83); + // it is important to add the endpoints in the same order they are found in the device firmware add_endpoint_descriptor(enddesc01); add_endpoint_descriptor(enddesc02); add_endpoint_descriptor(enddesc03); + add_endpoint_descriptor(enddesc81); + add_endpoint_descriptor(enddesc82); + add_endpoint_descriptor(enddesc83); add_string_descriptor(strdesc0); add_string_descriptor(strdesc1); add_string_descriptor(strdesc2); @@ -2221,6 +2281,7 @@ void xbox_base_state::machine_start() ohcist.timer->enable(false); //usb_device = new ohci_game_controller_device(machine()); usb_device = new ohci_hlean2131qc_device(machine()); + usb_device->set_region_base(memregion(":others")->base()); // temporary, should be in chihiro //usb_device = new ohci_hlean2131sc_device(machine()); usb_ohci_plug(1, usb_device); // test connect #endif diff --git a/src/mame/mame.lst b/src/mame/mame.lst index 2c65ae0d192..b689e94997f 100644 --- a/src/mame/mame.lst +++ b/src/mame/mame.lst @@ -9935,8 +9935,8 @@ crgolfc // (c) 1984 Nasco Japan crgolfhi // (c) 1984 Nasco Japan @source:crimfght.cpp -crimfght // GX821 (c) 1989 (US) -crimfght2 // GX821 (c) 1989 (World) +crimfght // GX821 (c) 1989 (World) +crimfghtu // GX821 (c) 1989 (US) crimfghtj // GX821 (c) 1989 (Japan) @source:crospang.cpp @@ -16757,6 +16757,9 @@ spelunkrj // (c) 1985 licensed from Broderbund yanchamr // (c) 1986 (Japan) youjyudn // (c) 1986 (Japan) +@source:spartanxtec.cpp +spartanxtec + @source:m63.cpp atomboy // M63 (c) 1985 Irem + Memetron license atomboya // M63 (c) 1985 Irem + Memetron license @@ -34978,6 +34981,7 @@ tokia // (c) 1989 Tad (World) tokib // bootleg tokiu // (c) 1989 Tad + Fabtek license (US) tokiua // (c) 1989 Tad + Fabtek license (US) +tokip @source:tokyocop.cpp tokyocop // (c) 2003 (Arcade TV Game List - P.168, Right, 19 from bottom) diff --git a/src/mame/video/mcr3.cpp b/src/mame/video/mcr3.cpp index 9385307c12f..ecd8b72a49a 100644 --- a/src/mame/video/mcr3.cpp +++ b/src/mame/video/mcr3.cpp @@ -125,40 +125,8 @@ VIDEO_START_MEMBER(mcr3_state,spyhunt) save_item(NAME(m_spyhunt_scroll_offset)); } -VIDEO_START_MEMBER(mcr3_state,spyhuntpr) -{ - /* initialize the background tilemap */ - m_bg_tilemap = &machine().tilemap().create(m_gfxdecode, tilemap_get_info_delegate(FUNC(mcr3_state::spyhunt_get_bg_tile_info),this), tilemap_mapper_delegate(FUNC(mcr3_state::spyhunt_bg_scan),this), 64,16, 64,32); - /* initialize the text tilemap */ - m_alpha_tilemap = &machine().tilemap().create(m_gfxdecode, tilemap_get_info_delegate(FUNC(mcr3_state::spyhunt_get_alpha_tile_info),this), TILEMAP_SCAN_COLS, 16,8, 32,32); - m_alpha_tilemap->set_transparent_pen(0); - m_alpha_tilemap->set_scrollx(0, 16); - save_item(NAME(m_spyhunt_sprite_color_mask)); - save_item(NAME(m_spyhunt_scrollx)); - save_item(NAME(m_spyhunt_scrolly)); - save_item(NAME(m_spyhunt_scroll_offset)); -} - - -/************************************* - * - * Palette RAM writes - * - *************************************/ - -WRITE8_MEMBER(mcr3_state::spyhuntpr_paletteram_w) -{ - m_paletteram[offset] = data; - offset = (offset & 0x0f) | (offset & 0x60) >> 1; - - int r = (data & 0x07) >> 0; - int g = (data & 0x38) >> 3; - int b = (data & 0xc0) >> 6; - - m_palette->set_pen_color(offset^0xf, rgb_t(r<<5,g<<5,b<<6)); -} /************************************* @@ -326,19 +294,3 @@ UINT32 mcr3_state::screen_update_spyhunt(screen_device &screen, bitmap_ind16 &bi return 0; } - -UINT32 mcr3_state::screen_update_spyhuntpr(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) -{ - /* for every character in the Video RAM, check if it has been modified */ - /* since last time and update it accordingly. */ - m_bg_tilemap->set_scrollx(0, m_spyhunt_scrollx * 2 + m_spyhunt_scroll_offset); - m_bg_tilemap->set_scrolly(0, m_spyhunt_scrolly * 2); - m_bg_tilemap->draw(screen, bitmap, cliprect, 0, 0); - - /* draw the sprites */ - mcr3_update_sprites(screen, bitmap, cliprect, m_spyhunt_sprite_color_mask, 0, -12, 0, 0); - - /* render any characters on top */ - m_alpha_tilemap->draw(screen, bitmap, cliprect, 0, 0); - return 0; -} diff --git a/src/osd/modules/file/posixfile.cpp b/src/osd/modules/file/posixfile.cpp index a5e3fe6a54e..513a3cbfd70 100644 --- a/src/osd/modules/file/posixfile.cpp +++ b/src/osd/modules/file/posixfile.cpp @@ -88,7 +88,7 @@ public: { ssize_t result; -#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__DragonFly__) || defined(EMSCRIPTEN) +#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__DragonFly__) || defined(EMSCRIPTEN) || defined(__ANDROID__) result = ::pread(m_fd, buffer, size_t(count), off_t(std::make_unsigned_t<off_t>(offset))); #elif defined(WIN32) || defined(SDLMAME_NO64BITIO) if (lseek(m_fd, off_t(std::make_unsigned_t<off_t>(offset)), SEEK_SET) < 0) @@ -109,7 +109,7 @@ public: { ssize_t result; -#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__DragonFly__) || defined(EMSCRIPTEN) +#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__DragonFly__) || defined(EMSCRIPTEN) || defined(__ANDROID__) result = ::pwrite(m_fd, buffer, size_t(count), off_t(std::make_unsigned_t<off_t>(offset))); #elif defined(WIN32) || defined(SDLMAME_NO64BITIO) if (lseek(m_fd, off_t(std::make_unsigned_t<off_t>(offset)), SEEK_SET) < 0) @@ -130,7 +130,7 @@ public: { int result; -#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__DragonFly__) || defined(EMSCRIPTEN) || defined(WIN32) || defined(SDLMAME_NO64BITIO) +#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__DragonFly__) || defined(EMSCRIPTEN) || defined(WIN32) || defined(SDLMAME_NO64BITIO) || defined(__ANDROID__) result = ::ftruncate(m_fd, off_t(std::make_unsigned_t<off_t>(offset))); #else result = ::ftruncate64(m_fd, off64_t(offset)); @@ -236,7 +236,7 @@ osd_file::error osd_file::open(std::string const &path, std::uint32_t openflags, // attempt to open the file int fd = -1; -#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__DragonFly__) || defined(__HAIKU__) || defined(WIN32) || defined(SDLMAME_NO64BITIO) +#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__DragonFly__) || defined(__HAIKU__) || defined(WIN32) || defined(SDLMAME_NO64BITIO) || defined(__ANDROID__) fd = ::open(dst.c_str(), access, 0666); #else fd = ::open64(dst.c_str(), access, 0666); @@ -256,7 +256,7 @@ osd_file::error osd_file::open(std::string const &path, std::uint32_t openflags, // attempt to reopen the file if (error == osd_file::error::NONE) { -#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__DragonFly__) || defined(__HAIKU__) || defined(WIN32) || defined(SDLMAME_NO64BITIO) +#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__DragonFly__) || defined(__HAIKU__) || defined(WIN32) || defined(SDLMAME_NO64BITIO) || defined(__ANDROID__) fd = ::open(dst.c_str(), access, 0666); #else fd = ::open64(dst.c_str(), access, 0666); @@ -273,7 +273,7 @@ osd_file::error osd_file::open(std::string const &path, std::uint32_t openflags, } // get the file size -#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__DragonFly__) || defined(__HAIKU__) || defined(WIN32) || defined(SDLMAME_NO64BITIO) +#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__DragonFly__) || defined(__HAIKU__) || defined(WIN32) || defined(SDLMAME_NO64BITIO) || defined(__ANDROID__) struct stat st; if (::fstat(fd, &st) < 0) #else @@ -340,7 +340,7 @@ int osd_get_physical_drive_geometry(const char *filename, UINT32 *cylinders, UIN osd_directory_entry *osd_stat(const std::string &path) { -#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__DragonFly__) || defined(__HAIKU__) || defined(WIN32) || defined(SDLMAME_NO64BITIO) +#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__DragonFly__) || defined(__HAIKU__) || defined(WIN32) || defined(SDLMAME_NO64BITIO) || defined(__ANDROID__) struct stat st; int const err = ::stat(path.c_str(), &st); #else diff --git a/src/osd/modules/file/posixptty.cpp b/src/osd/modules/file/posixptty.cpp index b84838c0578..f7842574312 100644 --- a/src/osd/modules/file/posixptty.cpp +++ b/src/osd/modules/file/posixptty.cpp @@ -22,7 +22,7 @@ #if defined(__FreeBSD__) || defined(__DragonFly__) #include <termios.h> #include <libutil.h> -#elif defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__) +#elif defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__) || defined(__ANDROID__) #include <termios.h> #include <util.h> #elif defined(__linux__) || defined(EMSCRIPTEN) @@ -141,7 +141,10 @@ osd_file::error posix_open_ptty(std::uint32_t openflags, osd_file::ptr &file, st ::close(masterfd); return errno_to_file_error(err); } -#else +#elif defined(__ANDROID__) + int masterfd = -1, slavefd = -1; + char slavepath[PATH_MAX]; +#else struct termios tios; std::memset(&tios, 0, sizeof(tios)); ::cfmakeraw(&tios); diff --git a/src/osd/modules/font/font_sdl.cpp b/src/osd/modules/font/font_sdl.cpp index c6f45635623..c5a73b0a541 100644 --- a/src/osd/modules/font/font_sdl.cpp +++ b/src/osd/modules/font/font_sdl.cpp @@ -8,7 +8,7 @@ #include "font_module.h" #include "modules/osdmodule.h" -#if defined(SDLMAME_UNIX) && !defined(SDLMAME_MACOSX) && !defined(SDLMAME_SOLARIS) && !defined(SDLMAME_HAIKU) +#if defined(SDLMAME_UNIX) && !defined(SDLMAME_MACOSX) && !defined(SDLMAME_SOLARIS) && !defined(SDLMAME_HAIKU) && !defined(SDLMAME_ANDROID) #include "corestr.h" #include "corealloc.h" diff --git a/src/osd/modules/render/bgfx/chainentry.cpp b/src/osd/modules/render/bgfx/chainentry.cpp index ff56559e430..f3bbbb42378 100644 --- a/src/osd/modules/render/bgfx/chainentry.cpp +++ b/src/osd/modules/render/bgfx/chainentry.cpp @@ -179,7 +179,7 @@ bool bgfx_chain_entry::setup_view(int view, uint16_t screen_width, uint16_t scre bx::mtxOrtho(projMat, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 100.0f); bgfx::setViewTransform(view, nullptr, projMat); - bgfx::setViewClear(view, BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH, 0x00ff00ff, 1.0f, 0); + bgfx::setViewClear(view, BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH, 0x00000000, 1.0f, 0); return true; } diff --git a/src/osd/modules/render/drawbgfx.cpp b/src/osd/modules/render/drawbgfx.cpp index 3ef04cbf5cf..d955f8c76f2 100644 --- a/src/osd/modules/render/drawbgfx.cpp +++ b/src/osd/modules/render/drawbgfx.cpp @@ -5,10 +5,6 @@ // drawbgfx.cpp - BGFX renderer // //============================================================ -#define __STDC_LIMIT_MACROS -#define __STDC_FORMAT_MACROS -#define __STDC_CONSTANT_MACROS - #if defined(SDLMAME_WIN32) || defined(OSD_WINDOWS) // standard windows headers #define WIN32_LEAN_AND_MEAN @@ -65,6 +61,7 @@ const char* renderer_bgfx::WINDOW_PREFIX = "Window 0, "; //============================================================ #define GIBBERISH (0) +#define SCENE_VIEW (0) //============================================================ // STATICS @@ -95,7 +92,7 @@ static void* sdlNativeWindowHandle(SDL_Window* _window) return wmi.info.win.window; # elif BX_PLATFORM_STEAMLINK return wmi.info.vivante.window; -# elif BX_PLATFORM_EMSCRIPTEN +# elif BX_PLATFORM_EMSCRIPTEN || BX_PLATFORM_ANDROID return nullptr; # endif // BX_PLATFORM_ } @@ -304,8 +301,13 @@ void renderer_bgfx::put_packed_quad(render_primitive *prim, UINT32 hash, ScreenV v0 += 0.5f / float(CACHE_SIZE); UINT32 rgba = u32Color(prim->color.r * 255, prim->color.g * 255, prim->color.b * 255, prim->color.a * 255); - float x[4] = { prim->bounds.x0, prim->bounds.x1, prim->bounds.x0, prim->bounds.x1 }; - float y[4] = { prim->bounds.y0, prim->bounds.y0, prim->bounds.y1, prim->bounds.y1 }; + const float x0 = prim->bounds.x0; + const float x1 = prim->bounds.x1; + const float y0 = prim->bounds.y0; + const float y1 = prim->bounds.y1; + + float x[4] = { x0, x1, x0, x1 }; + float y[4] = { y0, y0, y1, y1 }; float u[4] = { u0, u1, u0, u1 }; float v[4] = { v0, v0, v1, v1 }; @@ -410,28 +412,6 @@ void renderer_bgfx::render_post_screen_quad(int view, render_primitive* prim, bg float u[4] = { prim->texcoords.tl.u, prim->texcoords.tr.u, prim->texcoords.bl.u, prim->texcoords.br.u }; float v[4] = { prim->texcoords.tl.v, prim->texcoords.tr.v, prim->texcoords.bl.v, prim->texcoords.br.v }; - if (false)//PRIMFLAG_GET_TEXORIENT(prim->flags) & ORIENTATION_SWAP_XY) - { - std::swap(u[1], u[2]); - std::swap(v[1], v[2]); - } - - if (false)//PRIMFLAG_GET_TEXORIENT(prim->flags) & ORIENTATION_FLIP_X) - { - std::swap(u[0], u[1]); - std::swap(v[0], v[1]); - std::swap(u[2], u[3]); - std::swap(v[2], v[3]); - } - - if (false)//PRIMFLAG_GET_TEXORIENT(prim->flags) & ORIENTATION_FLIP_Y) - { - std::swap(u[0], u[2]); - std::swap(v[0], v[2]); - std::swap(u[1], u[3]); - std::swap(v[1], v[3]); - } - vertex[0].m_x = x[0]; vertex[0].m_y = y[0]; vertex[0].m_z = 0; @@ -480,7 +460,7 @@ void renderer_bgfx::render_post_screen_quad(int view, render_primitive* prim, bg m_screen_effect[blend]->submit(view); } -void renderer_bgfx::render_textured_quad(int view, render_primitive* prim, bgfx::TransientVertexBuffer* buffer) +void renderer_bgfx::render_textured_quad(render_primitive* prim, bgfx::TransientVertexBuffer* buffer) { ScreenVertex* vertex = reinterpret_cast<ScreenVertex*>(buffer->data); @@ -547,7 +527,7 @@ void renderer_bgfx::render_textured_quad(int view, render_primitive* prim, bgfx: UINT32 blend = PRIMFLAG_GET_BLENDMODE(prim->flags); bgfx::setVertexBuffer(buffer); bgfx::setTexture(0, effects[blend]->uniform("s_tex")->handle(), texture); - effects[blend]->submit(view); + effects[blend]->submit(m_ui_view); bgfx::destroyTexture(texture); } @@ -847,63 +827,29 @@ int renderer_bgfx::draw(int update) s_current_view = 0; } - handle_screen_chains(); - int view_index = s_current_view; + m_ui_view = -1; // Set view 0 default viewport. osd_dim wdim = window().get_size(); m_width[window_index] = wdim.width(); m_height[window_index] = wdim.height(); - if (window_index == 0) + handle_screen_chains(); + + bool skip_frame = update_dimensions(); + if (skip_frame) { - if ((m_dimensions != osd_dim(m_width[window_index], m_height[window_index]))) - { - bgfx::reset(m_width[window_index], m_height[window_index], video_config.waitvsync ? BGFX_RESET_VSYNC : BGFX_RESET_NONE); - m_dimensions = osd_dim(m_width[window_index], m_height[window_index]); - } + return 0; } - else - { - if ((m_dimensions != osd_dim(m_width[window_index], m_height[window_index]))) - { - bgfx::reset(window().m_main->get_size().width(), window().m_main->get_size().height(), video_config.waitvsync ? BGFX_RESET_VSYNC : BGFX_RESET_NONE); - delete m_framebuffer; -#ifdef OSD_WINDOWS - m_framebuffer = m_targets->create_backbuffer(window().m_hwnd, m_width[window_index], m_height[window_index]); -#else - m_framebuffer = m_targets->create_backbuffer(sdlNativeWindowHandle(window().sdl_window()), m_width[window_index], m_height[window_index]); -#endif - bgfx::setViewFrameBuffer(view_index, m_framebuffer->target()); - m_dimensions = osd_dim(m_width[window_index], m_height[window_index]); - bgfx::setViewClear(view_index - , BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH - , 0x00ff00ff - , 1.0f - , 0 - ); - bgfx::touch(view_index); - bgfx::frame(); - return 0; - } - bgfx::setViewFrameBuffer(view_index, m_framebuffer->target()); + if (s_current_view > m_max_view) + { + m_max_view = s_current_view; + } + else + { + s_current_view = m_max_view; } - - bgfx::setViewSeq(view_index, true); - bgfx::setViewRect(view_index, 0, 0, m_width[window_index], m_height[window_index]); - - // Setup view transform. - float proj[16]; - bx::mtxOrtho(proj, 0.0f, m_width[window_index], m_height[window_index], 0.0f, 0.0f, 100.0f); - bgfx::setViewTransform(view_index, nullptr, proj); - - bgfx::setViewClear(view_index - , BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH - , 0x000000ff - , 1.0f - , 0 - ); window().m_primlist->acquire_lock(); @@ -919,7 +865,7 @@ int renderer_bgfx::draw(int update) bgfx::TransientVertexBuffer buffer; allocate_buffer(prim, blend, &buffer); - int32_t screen = 0; + int32_t screen = -1; if (PRIMFLAG_GET_SCREENTEX(prim->flags)) { for (screen = 0; screen < screens.size(); screen++) @@ -935,13 +881,13 @@ int renderer_bgfx::draw(int update) } } - buffer_status status = buffer_primitives(view_index, atlas_valid, &prim, &buffer, screen); + buffer_status status = buffer_primitives(atlas_valid, &prim, &buffer, screen); if (status != BUFFER_EMPTY && status != BUFFER_SCREEN) { bgfx::setVertexBuffer(&buffer); bgfx::setTexture(0, m_gui_effect[blend]->uniform("s_tex")->handle(), m_texture_cache->texture()); - m_gui_effect[blend]->submit(view_index); + m_gui_effect[blend]->submit(m_ui_view); } if (status != BUFFER_DONE && status != BUFFER_PRE_FLUSH) @@ -954,7 +900,7 @@ int renderer_bgfx::draw(int update) // This dummy draw call is here to make sure that view 0 is cleared // if no other draw calls are submitted to view 0. - bgfx::touch(view_index); + bgfx::touch(s_current_view > 0 ? s_current_view - 1 : 0); // Advance to next frame. Rendering thread will be kicked to // process submitted rendering primitives. @@ -963,12 +909,113 @@ int renderer_bgfx::draw(int update) bgfx::frame(); } - s_current_view++; - return 0; } -renderer_bgfx::buffer_status renderer_bgfx::buffer_primitives(int view, bool atlas_valid, render_primitive** prim, bgfx::TransientVertexBuffer* buffer, int32_t screen) +bool renderer_bgfx::update_dimensions() +{ + const uint32_t window_index = window().m_index; + const uint32_t width = m_width[window_index]; + const uint32_t height = m_height[window_index]; + + if (window_index == 0) + { + if ((m_dimensions != osd_dim(width, height))) + { + bgfx::reset(width, height, video_config.waitvsync ? BGFX_RESET_VSYNC : BGFX_RESET_NONE); + m_dimensions = osd_dim(width, height); + } + } + else + { + if ((m_dimensions != osd_dim(width, height))) + { + bgfx::reset(window().m_main->get_size().width(), window().m_main->get_size().height(), video_config.waitvsync ? BGFX_RESET_VSYNC : BGFX_RESET_NONE); + m_dimensions = osd_dim(width, height); + + delete m_framebuffer; +#ifdef OSD_WINDOWS + m_framebuffer = m_targets->create_backbuffer(window().m_hwnd, width, height); +#else + m_framebuffer = m_targets->create_backbuffer(sdlNativeWindowHandle(window().sdl_window()), width, height); +#endif + + bgfx::setViewFrameBuffer(s_current_view, m_framebuffer->target()); + bgfx::setViewClear(s_current_view, BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH, 0x000000ff, 1.0f, 0); + bgfx::touch(s_current_view); + bgfx::frame(); + return true; + } + } + return false; +} + +void renderer_bgfx::setup_view(uint32_t view_index, bool screen) +{ + const uint32_t window_index = window().m_index; + const uint32_t width = m_width[window_index]; + const uint32_t height = m_height[window_index]; + + if (window_index != 0) + { + bgfx::setViewFrameBuffer(view_index, m_framebuffer->target()); + } + + bgfx::setViewSeq(view_index, true); + bgfx::setViewRect(view_index, 0, 0, width, height); + +#if SCENE_VIEW + if (view_index == m_max_view) +#endif + { + bgfx::setViewClear(view_index, BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH, 0x00000000, 1.0f, 0); + } + + setup_matrices(view_index, screen); +} + +void renderer_bgfx::setup_matrices(uint32_t view_index, bool screen) +{ + const uint32_t window_index = window().m_index; + const uint32_t width = m_width[window_index]; + const uint32_t height = m_height[window_index]; + + float proj[16]; + float view[16]; + if (screen) + { + static float offset = 0.0f; + offset += 0.5f; + float up[3] = { 0.0f, -1.0f, 0.0f }; + float cam_z = width * 0.5f * (float(height) / float(width)); + cam_z *= 1.05f; + float eye_height = height * 0.5f * 1.05f; + float at[3] = { width * 0.5f, height * 0.5f, 0.0f }; + float eye[3] = { width * 0.5f, eye_height, cam_z }; + bx::mtxLookAt(view, eye, at, up); + + bx::mtxProj(proj, 90.0f, float(width) / float(height), 0.1f, 5000.0f); + } + else + { + bx::mtxIdentity(view); + bx::mtxOrtho(proj, 0.0f, width, height, 0.0f, 0.0f, 100.0f); + } + + bgfx::setViewTransform(view_index, view, proj); +} + +void renderer_bgfx::init_ui_view() +{ + if (m_ui_view < 0) + { + m_ui_view = s_current_view; + setup_view(m_ui_view, false); + s_current_view++; + } +} + +renderer_bgfx::buffer_status renderer_bgfx::buffer_primitives(bool atlas_valid, render_primitive** prim, bgfx::TransientVertexBuffer* buffer, int32_t screen) { int vertices = 0; @@ -978,6 +1025,7 @@ renderer_bgfx::buffer_status renderer_bgfx::buffer_primitives(int view, bool atl switch ((*prim)->type) { case render_primitive::LINE: + init_ui_view(); put_line((*prim)->bounds.x0, (*prim)->bounds.y0, (*prim)->bounds.x1, (*prim)->bounds.y1, 1.0f, u32Color((*prim)->color.r * 255, (*prim)->color.g * 255, (*prim)->color.b * 255, (*prim)->color.a * 255), (ScreenVertex*)buffer->data + vertices, 1.0f); vertices += 30; break; @@ -985,6 +1033,7 @@ renderer_bgfx::buffer_status renderer_bgfx::buffer_primitives(int view, bool atl case render_primitive::QUAD: if ((*prim)->texture.base == nullptr) { + init_ui_view(); put_packed_quad(*prim, WHITE_HASH, (ScreenVertex*)buffer->data + vertices); vertices += 6; } @@ -993,6 +1042,7 @@ renderer_bgfx::buffer_status renderer_bgfx::buffer_primitives(int view, bool atl const UINT32 hash = get_texture_hash(*prim); if (atlas_valid && (*prim)->packable(PACKABLE_SIZE) && hash != 0 && m_hash_to_entry[hash].hash()) { + init_ui_view(); put_packed_quad(*prim, hash, (ScreenVertex*)buffer->data + vertices); vertices += 6; } @@ -1005,12 +1055,21 @@ renderer_bgfx::buffer_status renderer_bgfx::buffer_primitives(int view, bool atl if (PRIMFLAG_GET_SCREENTEX((*prim)->flags) && m_screen_chains.size() > window().m_index && screen < m_screen_chains[window().m_index].size()) { - render_post_screen_quad(view, *prim, buffer, screen); +#if SCENE_VIEW + setup_view(s_current_view, true); + render_post_screen_quad(s_current_view, *prim, buffer, screen); + s_current_view++; + m_ui_view = -1; +#else + init_ui_view(); + render_post_screen_quad(m_ui_view, *prim, buffer, screen); +#endif return BUFFER_SCREEN; } else { - render_textured_quad(view, *prim, buffer); + init_ui_view(); + render_textured_quad(*prim, buffer); return BUFFER_EMPTY; } } diff --git a/src/osd/modules/render/drawbgfx.h b/src/osd/modules/render/drawbgfx.h index 95cd613bb2f..823472f5c4a 100644 --- a/src/osd/modules/render/drawbgfx.h +++ b/src/osd/modules/render/drawbgfx.h @@ -30,6 +30,7 @@ public: renderer_bgfx(osd_window *w) : osd_renderer(w, FLAG_NONE) , m_dimensions(0, 0) + , m_max_view(0) { } virtual ~renderer_bgfx(); @@ -64,6 +65,11 @@ private: void parse_screen_chains(std::string chain_str); bgfx_chain* screen_chain(int32_t screen); + bool update_dimensions(); + void setup_view(uint32_t view_index, bool screen); + void init_ui_view(); + void setup_matrices(uint32_t view_index, bool screen); + void allocate_buffer(render_primitive *prim, UINT32 blend, bgfx::TransientVertexBuffer *buffer); enum buffer_status { @@ -73,10 +79,10 @@ private: BUFFER_EMPTY, BUFFER_DONE }; - buffer_status buffer_primitives(int view, bool atlas_valid, render_primitive** prim, bgfx::TransientVertexBuffer* buffer, int32_t screen); + buffer_status buffer_primitives(bool atlas_valid, render_primitive** prim, bgfx::TransientVertexBuffer* buffer, int32_t screen); void process_screen_quad(int view, render_primitive* prim); - void render_textured_quad(int view, render_primitive* prim, bgfx::TransientVertexBuffer* buffer); + void render_textured_quad(render_primitive* prim, bgfx::TransientVertexBuffer* buffer); void render_post_screen_quad(int view, render_primitive* prim, bgfx::TransientVertexBuffer* buffer, int32_t screen); void put_packed_quad(render_primitive *prim, UINT32 hash, ScreenVertex* vertex); @@ -117,6 +123,8 @@ private: uint32_t m_width[16]; uint32_t m_height[16]; uint32_t m_white[16*16]; + int32_t m_ui_view; + uint32_t m_max_view; static const uint16_t CACHE_SIZE; static const uint32_t PACKABLE_SIZE; diff --git a/src/osd/sdl/sdldir.cpp b/src/osd/sdl/sdldir.cpp index 439eb0a9792..abf1f126b94 100644 --- a/src/osd/sdl/sdldir.cpp +++ b/src/osd/sdl/sdldir.cpp @@ -50,7 +50,7 @@ #define INVPATHSEPCH '\\' #endif -#if defined(SDLMAME_DARWIN) || defined(SDLMAME_WIN32) || defined(SDLMAME_NO64BITIO) || defined(SDLMAME_BSD) || defined(SDLMAME_HAIKU) || defined(SDLMAME_EMSCRIPTEN) +#if defined(SDLMAME_DARWIN) || defined(SDLMAME_WIN32) || defined(SDLMAME_NO64BITIO) || defined(SDLMAME_BSD) || defined(SDLMAME_HAIKU) || defined(SDLMAME_EMSCRIPTEN) || defined(SDLMAME_ANDROID) typedef struct dirent sdl_dirent; typedef struct stat sdl_stat; #define sdl_readdir readdir diff --git a/src/osd/sdl/sdlmain.cpp b/src/osd/sdl/sdlmain.cpp index ad71a48aa08..ef4c6b7c927 100644 --- a/src/osd/sdl/sdlmain.cpp +++ b/src/osd/sdl/sdlmain.cpp @@ -10,7 +10,7 @@ #ifdef SDLMAME_UNIX -#if (!defined(SDLMAME_MACOSX)) && (!defined(SDLMAME_EMSCRIPTEN)) +#if (!defined(SDLMAME_MACOSX)) && (!defined(SDLMAME_EMSCRIPTEN)) && (!defined(SDLMAME_ANDROID)) #ifndef SDLMAME_HAIKU #include <fontconfig/fontconfig.h> #endif @@ -202,7 +202,7 @@ int main(int argc, char *argv[]) #ifdef SDLMAME_UNIX sdl_entered_debugger = 0; -#if (!defined(SDLMAME_MACOSX)) && (!defined(SDLMAME_HAIKU)) && (!defined(SDLMAME_EMSCRIPTEN)) +#if (!defined(SDLMAME_MACOSX)) && (!defined(SDLMAME_HAIKU)) && (!defined(SDLMAME_EMSCRIPTEN)) && (!defined(SDLMAME_ANDROID)) FcInit(); #endif #endif @@ -216,7 +216,7 @@ int main(int argc, char *argv[]) } #ifdef SDLMAME_UNIX -#if (!defined(SDLMAME_MACOSX)) && (!defined(SDLMAME_HAIKU)) && (!defined(SDLMAME_EMSCRIPTEN)) +#if (!defined(SDLMAME_MACOSX)) && (!defined(SDLMAME_HAIKU)) && (!defined(SDLMAME_EMSCRIPTEN)) && (!defined(SDLMAME_ANDROID)) if (!sdl_entered_debugger) { FcFini(); diff --git a/src/osd/sdl/sdlos_unix.cpp b/src/osd/sdl/sdlos_unix.cpp index 23080512e91..82e11ebc07c 100644 --- a/src/osd/sdl/sdlos_unix.cpp +++ b/src/osd/sdl/sdlos_unix.cpp @@ -23,6 +23,12 @@ // MAME headers #include "osdcore.h" +#ifdef SDLMAME_ANDROID +char *osd_get_clipboard_text(void) +{ + return nullptr; +} +#else //============================================================ // osd_get_clipboard_text //============================================================ @@ -40,3 +46,5 @@ char *osd_get_clipboard_text(void) } return result; } + +#endif
\ No newline at end of file diff --git a/src/osd/sdl/sdlprefix.h b/src/osd/sdl/sdlprefix.h index 2acc6a9d98e..9ba0001ccc5 100644 --- a/src/osd/sdl/sdlprefix.h +++ b/src/osd/sdl/sdlprefix.h @@ -70,6 +70,10 @@ struct _IO_FILE {}; //_IO_FILE is an opaque type in the emscripten libc which makes clang cranky #endif +#if defined(__ANDROID__) +#define SDLMAME_ANDROID 1 +#endif + // fix for Ubuntu 8.10 #ifdef _FORTIFY_SOURCE #undef _FORTIFY_SOURCE |