From 6423aae854ba85fd1f2a3d34851ea29e0f2da5c4 Mon Sep 17 00:00:00 2001 From: smf- Date: Fri, 25 Oct 2024 15:11:27 +0100 Subject: Added a new modular JVS framework New devices added: Namco Cyber Lead I/O LED(I/O) PCB 8699014200 Namco Cyber Lead I/O LED(I/O) PCB 8699014200 (compatibility patch) Namco Cyber Lead I/O LED(LED) PCB 8699014500 Namco AMC PCB (Extra I/O,JPN,Ver1.10) Namco ASCA-1 (Multipurpose I/O,JPN,Ver2.00) Namco ASCA-3 (Multipurpose + Rotary Encoder,JPN,Ver2.04) Namco ASCA-3 (Multipurpose + Rotary Encoder,JPN,Ver2.02) Namco ASCA-5 (Multipurpose,JPN,Ver2.09) Namco CSZ1 MIU-I/O (GUN-EXTENTION,JPN,Ver2.05) Namco EM I/O1-02 (Techno-Drive I/O,JPN&EXP,Ver2.00) Namco TSS-I/O (GUN-EXTENTION,JPN,Ver2.02) Namco XMIU1 TSS-I/O (GUN-EXTENTION,JPN,Ver2.11,Ver2.12) Note: the Cyber Lead compatibility patch is required because later versions aren't Namco FCA-1 (Multipurpose + Rotary Encoder,JPN,Ver1.00) Namco FCA-1 (Multipurpose + Rotary Encoder,JPN,Ver1.01) Namco FCB (TouchPanel&Multipurpose,JPN,Ver1.02) Note: These use ASCA3 patched to return the correct ID string as the full ROM is yet to be extracted Namco EM Pri1-01 Note: The printer for Techno Drive is HLE'd only enough to make the game happy --- scripts/src/bus.lua | 27 + src/devices/bus/jvs/cyberlead.cpp | 486 ++++++++++++ src/devices/bus/jvs/cyberlead.h | 95 +++ src/devices/bus/jvs/jvs.cpp | 450 +++++++++++ src/devices/bus/jvs/jvs.h | 157 ++++ src/devices/bus/jvs/jvshle.cpp | 868 ++++++++++++++++++++ src/devices/bus/jvs/jvshle.h | 175 +++++ src/devices/bus/jvs/namcoio.cpp | 1564 +++++++++++++++++++++++++++++++++++++ src/devices/bus/jvs/namcoio.h | 73 ++ src/devices/bus/rs232/rs232.h | 2 +- src/emu/layout/cyberlead.lay | 14 + 11 files changed, 3910 insertions(+), 1 deletion(-) create mode 100644 src/devices/bus/jvs/cyberlead.cpp create mode 100644 src/devices/bus/jvs/cyberlead.h create mode 100644 src/devices/bus/jvs/jvs.cpp create mode 100644 src/devices/bus/jvs/jvs.h create mode 100644 src/devices/bus/jvs/jvshle.cpp create mode 100644 src/devices/bus/jvs/jvshle.h create mode 100644 src/devices/bus/jvs/namcoio.cpp create mode 100644 src/devices/bus/jvs/namcoio.h create mode 100644 src/emu/layout/cyberlead.lay diff --git a/scripts/src/bus.lua b/scripts/src/bus.lua index b037f0381fd..dabbbd82731 100644 --- a/scripts/src/bus.lua +++ b/scripts/src/bus.lua @@ -5559,6 +5559,33 @@ if (BUSES["PC8801"]~=null) then } end +--------------------------------------------------- +-- +--@src/devices/bus/jvs/jvs.h,BUSES["JVS"] = true +--------------------------------------------------- + +if (BUSES["JVS"]~=null) then + files { + MAME_DIR .. "src/devices/bus/jvs/cyberlead.cpp", + MAME_DIR .. "src/devices/bus/jvs/cyberlead.h", + MAME_DIR .. "src/devices/bus/jvs/jvs.cpp", + MAME_DIR .. "src/devices/bus/jvs/jvs.h", + MAME_DIR .. "src/devices/bus/jvs/jvshle.cpp", + MAME_DIR .. "src/devices/bus/jvs/jvshle.h", + MAME_DIR .. "src/devices/bus/jvs/namcoio.cpp", + MAME_DIR .. "src/devices/bus/jvs/namcoio.h", + } + + dependency { + { MAME_DIR .. "src/devices/bus/jvs/cyberlead.cpp", GEN_DIR .. "emu/layout/cyberlead.lh" }, + } + + custombuildtask { + layoutbuildtask("emu/layout", "cyberlead"), + } +end + + --------------------------------------------------- -- --@src/devices/bus/mtu130/board.h,BUSES["MTU130"] = true diff --git a/src/devices/bus/jvs/cyberlead.cpp b/src/devices/bus/jvs/cyberlead.cpp new file mode 100644 index 00000000000..5598da24cd9 --- /dev/null +++ b/src/devices/bus/jvs/cyberlead.cpp @@ -0,0 +1,486 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/* + Namco Cyber Lead cabinet PCB + + CL1 I/OB I/O LED (I/O) PCB 8699014200 + CL1 LEDA I/O LED (LED) PCB 8699014500 + Both boards are required and use the same PCB, populated differently + |------------------------------------------------------------------------------------------------| + | J3 J4 J6 | + | J2 J5 | + | PROG I/OLEDM1 | + | AT29C020 SED1351F B A | + | C77 14.764Mhz PST592F J7 | + | HC257 HC257 HC257 N341256 | + | J1 | + | SW1 SW2 SW3 SW4 SW5 9264LF10L 12MHZ | + | 1P 2P | + | J13 J12 J11 J10 | + |------------------------------------------------------------------------------------------------| + +Notes: + J1 - 6 pin connector (I/O Only) + J2 - 2 pin power connector + J3 - 10 pin connector (I/O Only) + J4 - 12 pin connector (I/O Only) + J5 PROG - ? + J6 - 6 pin Mini DIN connector + J7 - 20 pin connector (LED Only) + J10 - 2 pin connector (I/O Only) + J11 - 12 pin connector (I/O Only) + J12 - 12 pin connector (I/O Only) + J13 - 2 pin connector (I/O Only) + A - USB A connector (I/O Only) + B - USB B connector (I/O Only) + HC257 - Quad 2-input multiplexer; 3-state (I/O Only) @IC1,IC2,IC3 + N341256 - NEC N341256 32k x8 SRAM @IC4 + AT29C020 - Atmel AT29C020 256k x8 FlashROM @IC5 + C77 - Namco C77 H8 MCU @IC6 + 14.76 - X1 14.7SC6M + SW1 - A push button + SW2 - B push button + SW3 - DSW4 + SW4 - Service push button + SW5 - Test push button + SED1351F - EPSON SED1351F LCD controller (LED Only) @IC7 + 9264LF10L - 8192x8 Bit Static RAM (LED Only) @IC8 + I/OLEDM1 - Altera EPM7064 @IC9 + PST592F - System reset @IC10 + 12MHz - OSC1 (LED Only) + ADM485JR - Analog Devices ADM485 low power EIA RS-485 transceiver (I/O Only) @IC11 + +Known games with LED data + + Aqua Rush + Attack Pla Rail (*) + Ehrgeiz (*) + Fighting Layer (Japan) (*) + Libero Grande + Mr. Driller + Soul Calibur + Super World Stadium '98 + Super World Stadium '99 + Tekken 3 (* up to rev D) + Tekken Tag Tournament + + (*) The only games that work with the unpatched CL1 I/OB Ver 1.03 rom +*/ + +#include "emu.h" +#include "cyberlead.h" +#include "cyberlead.lh" + +namco_cyberlead_device::namco_cyberlead_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : + namco_cyberlead_device(mconfig, NAMCO_CYBERLEAD, tag, owner, clock) +{ +} + +namco_cyberlead_device::namco_cyberlead_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) : + device_t(mconfig, type, tag, owner, clock), + device_jvs_interface(mconfig, *this), + m_iocpu(*this, "iocpu"), + m_dsw(*this, "DSW"), + m_port7(*this, "PORT7"), + m_rs232(*this, "rs232") +{ +} + +void namco_cyberlead_device::device_add_mconfig(machine_config &config) +{ + NAMCO_C77(config, m_iocpu, 14.7456_MHz_XTAL); + m_iocpu->set_addrmap(AS_PROGRAM, &namco_cyberlead_device::iocpu_program_map); + m_iocpu->read_port4().set(FUNC(namco_cyberlead_device::iocpu_port_4_r)); + m_iocpu->write_port4().set(FUNC(namco_cyberlead_device::iocpu_port_4_w)); + m_iocpu->read_port5().set(FUNC(namco_cyberlead_device::iocpu_port_5_r)); + m_iocpu->write_port5().set(FUNC(namco_cyberlead_device::iocpu_port_5_w)); + m_iocpu->read_port6().set(FUNC(namco_cyberlead_device::iocpu_port_6_r)); + m_iocpu->write_port6().set(FUNC(namco_cyberlead_device::iocpu_port_6_w)); + m_iocpu->read_port7().set(FUNC(namco_cyberlead_device::iocpu_port_7_r)); + + m_iocpu->write_sci_tx<0>().set(FUNC(namco_cyberlead_device::txd)); + + config.set_maximum_quantum(attotime::from_hz(2 * 115200)); + + RS232_PORT(config, m_rs232); + m_rs232->option_add("namco_cyberlead_led", NAMCO_CYBERLEAD_LED); + m_rs232->set_option_machine_config("namco_cyberlead_led", [&config](device_t *device) + { + if (!(config.gamedrv().flags & machine_flags::SWAP_XY)) + config.set_default_layout(layout_cyberlead); + }); + + m_rs232->set_default_option("namco_cyberlead_led"); + m_rs232->rxd_handler().set(m_iocpu, FUNC(h8_device::sci_rx_w<1>)); + m_iocpu->write_sci_tx<1>().set(m_rs232, FUNC(rs232_port_device::write_txd)); + + add_jvs_port(config); +} + +namespace { + +static INPUT_PORTS_START(cyberleadjvs) + PORT_START("DSW") + PORT_DIPUNKNOWN_DIPLOC(0x08, IP_ACTIVE_LOW, "SW3:1") + PORT_DIPUNKNOWN_DIPLOC(0x04, IP_ACTIVE_LOW, "SW3:2") + PORT_DIPUNKNOWN_DIPLOC(0x02, IP_ACTIVE_LOW, "SW3:3") + PORT_DIPUNUSED_DIPLOC(0x01, IP_ACTIVE_LOW, "SW3:4") + + PORT_START("PORT7") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYPAD) PORT_NAME("LED Mode B") PORT_CODE(KEYCODE_B) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYPAD) PORT_NAME("LED Mode A") PORT_CODE(KEYCODE_A) + PORT_BIT(0x8c, IP_ACTIVE_LOW, IPT_UNKNOWN) // inputs? + PORT_BIT(0x70, IP_ACTIVE_LOW, IPT_UNKNOWN) // outputs? +INPUT_PORTS_END + +static INPUT_PORTS_START(cyberleadjvs_default) + PORT_INCLUDE(cyberleadjvs) + + PORT_START("SYSTEM") + PORT_SERVICE_NO_TOGGLE(0x80, IP_ACTIVE_HIGH) + + PORT_START("PLAYER1") + PORT_BIT(0x00000080, IP_ACTIVE_HIGH, IPT_START) + PORT_BIT(0x00000040, IP_ACTIVE_HIGH, IPT_SERVICE1) + PORT_BIT(0x00000020, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP) + PORT_BIT(0x00000010, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN) + PORT_BIT(0x00000008, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT) + PORT_BIT(0x00000004, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT) + PORT_BIT(0x00000002, IP_ACTIVE_HIGH, IPT_BUTTON1) + PORT_BIT(0x00000001, IP_ACTIVE_HIGH, IPT_BUTTON2) + PORT_BIT(0x00008000, IP_ACTIVE_HIGH, IPT_BUTTON3) + PORT_BIT(0x00004000, IP_ACTIVE_HIGH, IPT_BUTTON4) + PORT_BIT(0x00002000, IP_ACTIVE_HIGH, IPT_BUTTON5) + PORT_BIT(0x00001000, IP_ACTIVE_HIGH, IPT_BUTTON6) + + PORT_START("PLAYER2") + PORT_BIT(0x00000080, IP_ACTIVE_HIGH, IPT_START) PORT_PLAYER(2) + PORT_BIT(0x00000020, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP) PORT_PLAYER(2) + PORT_BIT(0x00000010, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN) PORT_PLAYER(2) + PORT_BIT(0x00000008, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT) PORT_PLAYER(2) + PORT_BIT(0x00000004, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT) PORT_PLAYER(2) + PORT_BIT(0x00000002, IP_ACTIVE_HIGH, IPT_BUTTON1) PORT_PLAYER(2) + PORT_BIT(0x00000001, IP_ACTIVE_HIGH, IPT_BUTTON2) PORT_PLAYER(2) + PORT_BIT(0x00008000, IP_ACTIVE_HIGH, IPT_BUTTON3) PORT_PLAYER(2) + PORT_BIT(0x00004000, IP_ACTIVE_HIGH, IPT_BUTTON4) PORT_PLAYER(2) + PORT_BIT(0x00002000, IP_ACTIVE_HIGH, IPT_BUTTON5) PORT_PLAYER(2) + PORT_BIT(0x00001000, IP_ACTIVE_HIGH, IPT_BUTTON6) PORT_PLAYER(2) + + PORT_START("COIN1") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_COIN1) + + PORT_START("COIN2") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_COIN2) +INPUT_PORTS_END + +} // anonymous namespace + +ioport_constructor namco_cyberlead_device::device_input_ports() const +{ + return m_default_inputs ? INPUT_PORTS_NAME(cyberleadjvs_default) : INPUT_PORTS_NAME(cyberleadjvs); +} + +namespace { + +ROM_START( cyberleadjvs ) + ROM_REGION( 0x040000, "iocpu", 0 ) + ROM_LOAD( "cl1-iob.ic5", 0x000000, 0x040000, CRC(abb90360) SHA1(d938b1e1ae596d0ab1007352f61b0b800363c762) ) + ROM_FILL( 0xa6b, 0x1, 0x12 ) // HACK to improve compatibility, until newer revision is dumped +ROM_END + +} // anonymous namespace + +const tiny_rom_entry *namco_cyberlead_device::device_rom_region() const +{ + return ROM_NAME(cyberleadjvs); +} + +void namco_cyberlead_device::device_start() +{ +} + +void namco_cyberlead_device::rxd(int state) +{ + m_iocpu->sci_rx_w<0>(state); +} + +void namco_cyberlead_device::iocpu_program_map(address_map &map) +{ + map(0x0000, 0x3fff).rom().region("iocpu", 0); + map(0xc000, 0xfb7f).ram(); + map(0xff80, 0xff83).r(FUNC(namco_cyberlead_device::iocpu_in_r)); +} + +uint8_t namco_cyberlead_device::iocpu_in_r(offs_t offset) +{ + if (offset == 0) + { + const auto p1 = player_r(0, 0x80bf); + return ~bitswap<8>(p1, 15, 0, 1, 7, 2, 3, 4, 5); // BUTTON3, BUTTON2, BUTTON1, START, RIGHT, LEFT, DOWN, UP + } + else if (offset == 1) + { + const auto p2 = player_r(1, 0x80bf); + return ~bitswap<8>(p2, 15, 0, 1, 7, 2, 3, 4, 5); // BUTTON3, BUTTON2, BUTTON1, START, RIGHT, LEFT, DOWN, UP + } + else if (offset == 2) + { + const auto p1 = player_r(0, 0x7000); + const auto c1 = coin_r(0, 0x01); + return ~((BIT(c1, 0) << 3) | bitswap<3>(p1, 12, 13, 14)); // COIN, BUTTON6, BUTTON5, BUTTON4 + } + else if (offset == 3) + { + const auto p2 = player_r(1, 0x7000); + const auto c2 = coin_r(1, 0x01); + return ~((BIT(c2, 0) << 3) | bitswap<3>(p2, 12, 13, 14)); // COIN, BUTTON6, BUTTON5, BUTTON4 + } + + return 0xff; +} + +uint8_t namco_cyberlead_device::iocpu_port_4_r() +{ + return (1 << 7) | // unknown input + 0x63 | // unknown outputs + ((m_jvs_sense != jvs_port_device::sense::None) << 4) | ((m_jvs_sense != jvs_port_device::sense::Initialized) << 3) | + (1 << 2);// sense output +} + +void namco_cyberlead_device::iocpu_port_4_w(uint8_t data) +{ + sense(BIT(data, 2) ? jvs_port_device::sense::Initialized : jvs_port_device::sense::Uninitialized); +} + +uint8_t namco_cyberlead_device::iocpu_port_5_r() +{ + return 0xe9 | // unknown outputs + (1 << 4) | // unknown input + (1 << 2) | // rts + (1 << 1); // unknown input +} + +void namco_cyberlead_device::iocpu_port_5_w(uint8_t data) +{ + rts(BIT(data, 2)); +} + +uint8_t namco_cyberlead_device::iocpu_port_6_r() +{ + const auto system = system_r(0x80); + const auto p1 = player_r(0, 0x40); + + return (1 << 7) | // unknown + (3 << 5) | // coin counters + (BIT(~p1, 6) << 4) | // SERVICE1 + (BIT(m_dsw->read(), 1, 3) << 1) | // DSW1-3 TODO: confirm + (BIT(~system, 7) << 0); // TEST +} + +void namco_cyberlead_device::iocpu_port_6_w(uint8_t data) +{ + machine().bookkeeping().coin_counter_w(0, BIT(data, 6)); + machine().bookkeeping().coin_counter_w(1, BIT(data, 5)); +} + +uint8_t namco_cyberlead_device::iocpu_port_7_r() +{ + return m_port7->read(); +} + + +namco_cyberlead_led_device::namco_cyberlead_led_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : + device_t(mconfig, NAMCO_CYBERLEAD_LED, tag, owner, clock), + device_rs232_port_interface(mconfig, *this), + m_ledcpu(*this, "ledcpu"), + m_flash(*this, "flash"), + m_screen(*this, "led"), + m_scroll(*this, "scroll"), + m_sed1351f_ram(*this, "sed1351f_ram"), + m_sed1351f_control(*this, "sed1351f_control"), + m_dsw(*this, "DSW") +{ +} + +namespace { + +} // anonymous namespace + +void namco_cyberlead_led_device::device_add_mconfig(machine_config &config) +{ + NAMCO_C77(config, m_ledcpu, 14.7456_MHz_XTAL); + m_ledcpu->set_addrmap(AS_PROGRAM, &namco_cyberlead_led_device::ledcpu_program_map); + m_ledcpu->read_port6().set(FUNC(namco_cyberlead_led_device::ledcpu_port_6_r)); + + m_ledcpu->write_sci_tx<1>().set(FUNC(namco_cyberlead_led_device::output_rxd)); + + ATMEL_29C020(config, m_flash); + + SCREEN(config, m_screen, SCREEN_TYPE_RASTER); + m_screen->set_native_aspect(); + m_screen->set_size(96 * 8, 16 * 8); + m_screen->set_visarea(0, (96 * 8) - 1, 0, (16 * 8) - 1); + m_screen->set_screen_update(FUNC(namco_cyberlead_led_device::screen_update)); + m_screen->set_refresh_hz(60); + m_screen->set_vblank_time(ATTOSECONDS_IN_USEC(2500)); + m_screen->set_orientation(ROT180); + m_screen->screen_vblank().set([this](int state) + { + m_ledcpu->set_input_line(6, state ? ASSERT_LINE : CLEAR_LINE); + }); +} + +namespace { + +static INPUT_PORTS_START(cyberleadled) + PORT_START("DSW") + PORT_DIPNAME(0x08, 0x08, "Display Test") PORT_DIPLOCATION("SW3:1") // c9fb + PORT_DIPSETTING(0x08, "1 Time") + PORT_DIPSETTING(0x00, "4 Times") + PORT_DIPNAME(0x04, 0x04, "Disable Epilepsy Filter") PORT_DIPLOCATION("SW3:2") // c9fc + PORT_DIPSETTING(0x04, DEF_STR(Off)) + PORT_DIPSETTING(0x00, DEF_STR(On)) + PORT_DIPUNKNOWN_DIPLOC(0x02, IP_ACTIVE_LOW, "SW3:3") + PORT_DIPUNUSED_DIPLOC(0x01, IP_ACTIVE_LOW, "SW3:4") +INPUT_PORTS_END + +} // anonymous namespace + +ioport_constructor namco_cyberlead_led_device::device_input_ports() const +{ + return INPUT_PORTS_NAME(cyberleadled); +} + +namespace { + +static const uint16_t led_gfx[] = +{ + 0b0001101010010000, + 0b0110111111100100, + 0b1011111111111001, + 0b1011111111111001, + 0b1011111111111001, + 0b0110111111100100, + 0b0001101010010000, + 0b0000010101000000, +}; + +ROM_START( cyberleadled ) + ROM_REGION( 0x40000, "flash", 0 ) + ROM_LOAD( "cl1-leda.ic5", 0x000000, 0x040000, CRC(5717e05f) SHA1(61d61338e1bb414af32dbdc1e24d54c02fb9196e) ) +ROM_END + +} // anonymous namespace + +const tiny_rom_entry *namco_cyberlead_led_device::device_rom_region() const +{ + return ROM_NAME(cyberleadled); +} + +void namco_cyberlead_led_device::device_start() +{ + for (int c = 0; c < 4; c++) + for (int i = 0; i < 4; i++) + { + int r = ((((0xff * c) / 3) + 0x2f) * i) / 3; + m_palette[c][i] = rgb_t(std::min(r, 0xff), r / 4, r / 3); + } + + m_flash_bank = 0; + + save_item(NAME(m_flash_bank)); +} + +void namco_cyberlead_led_device::input_txd(int state) +{ + m_ledcpu->sci_rx_w<1>(state); +} + +void namco_cyberlead_led_device::ledcpu_program_map(address_map &map) +{ + map(0x0000, 0x3fff).rw(m_flash, FUNC(intelfsh8_device::read), FUNC(intelfsh8_device::write)); + map(0x4000, 0x5fff).ram().share(m_sed1351f_ram); + map(0x6000, 0x600f).ram().share(m_sed1351f_control); + map(0x7000, 0x7001).ram().share(m_scroll); + map(0x8000, 0xbfff).rw(FUNC(namco_cyberlead_led_device::ledcpu_banked_flash_r), FUNC(namco_cyberlead_led_device::ledcpu_banked_flash_w)); + map(0xc000, 0xfb7f).ram(); + map(0xff84, 0xff87).w(FUNC(namco_cyberlead_led_device::ledcpu_flash_bank_w)); +} + +uint8_t namco_cyberlead_led_device::ledcpu_banked_flash_r(offs_t offset) +{ + return m_flash->read(offset + m_flash_bank); +} + +void namco_cyberlead_led_device::ledcpu_banked_flash_w(offs_t offset, uint8_t data) +{ + m_flash->write(offset + m_flash_bank, data); +} + +void namco_cyberlead_led_device::ledcpu_flash_bank_w(offs_t offset, uint8_t data) +{ + m_flash_bank = 0x4000 * (offset | (data << 2)); +} + +uint8_t namco_cyberlead_led_device::ledcpu_port_6_r() +{ + const auto system = 0; + const auto p1 = 0; + + return (1 << 7) | // unknown + (3 << 5) | // coin counters + (BIT(~p1, 6) << 4) | // SERVICE1 + (BIT(m_dsw->read(), 1, 3) << 1) | // DSW1-3 TODO: confirm + (BIT(~system, 7) << 0); // TEST +} + +uint32_t namco_cyberlead_led_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + int start = swapendian_int16(m_sed1351f_control[6 / 2]) & 0x1fff; + int scroll = ~m_ledcpu->space(AS_PROGRAM).read_byte(0xd0bf) & 3; + int scrollx = ((start & 0x1f) * 4) + scroll; + int scrolly = start >> 5; + + for (int y = cliprect.min_y; y <= cliprect.max_y; y++) + { + uint32_t *dst = &bitmap.pix(y, cliprect.min_x); + uint16_t *src = &m_sed1351f_ram[((scrolly + (y >> 3)) & 511) * 16]; + uint16_t gfx = led_gfx[y & 7]; + for (int x = cliprect.min_x; x <= cliprect.max_x; x++) + { + int p = (scrollx + (x >> 3)) & 127; + *dst++ = m_palette[BIT(src[p >> 3], (~p & 7) * 2, 2)][BIT(gfx, (x & 7) << 1, 2)]; + } + } + return 0; +} + +namespace { + +ROM_START( cyberleadajvs ) + ROM_REGION( 0x040000, "iocpu", 0 ) + ROM_LOAD( "cl1-iob.ic5", 0x000000, 0x040000, CRC(abb90360) SHA1(d938b1e1ae596d0ab1007352f61b0b800363c762) ) +ROM_END + +class namco_cyberleada_device : + public namco_cyberlead_device +{ +public: + namco_cyberleada_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0) + : namco_cyberlead_device(mconfig, NAMCO_CYBERLEADA, tag, owner, clock) + { + } + +protected: + virtual const tiny_rom_entry *device_rom_region() const override ATTR_COLD + { + return ROM_NAME(cyberleadajvs); + } +}; + +} // anonymous namespace + + +DEFINE_DEVICE_TYPE(NAMCO_CYBERLEAD, namco_cyberlead_device, "namco_cyberlead", "Namco Cyber Lead I/O LED(I/O) PCB 8699014200 (compatibility patch)") +DEFINE_DEVICE_TYPE_PRIVATE(NAMCO_CYBERLEADA, device_jvs_interface, namco_cyberleada_device, "namco_cyberleada", "Namco Cyber Lead I/O LED(I/O) PCB 8699014200") +DEFINE_DEVICE_TYPE(NAMCO_CYBERLEAD_LED, namco_cyberlead_led_device, "namco_cyberlead_led", "Namco Cyber Lead I/O LED(LED) PCB 8699014500") diff --git a/src/devices/bus/jvs/cyberlead.h b/src/devices/bus/jvs/cyberlead.h new file mode 100644 index 00000000000..08c1873a4ad --- /dev/null +++ b/src/devices/bus/jvs/cyberlead.h @@ -0,0 +1,95 @@ +// license:BSD-3-Clause +// copyright-holders:smf + +#ifndef MAME_BUS_JVS_CYBERLEAD_H +#define MAME_BUS_JVS_CYBERLEAD_H + +#pragma once + +#include "jvs.h" +#include "bus/rs232/rs232.h" +#include "cpu/h8/c77.h" +#include "machine/intelfsh.h" +#include "emupal.h" +#include "screen.h" +#include "tilemap.h" + +class namco_cyberlead_device : + public device_t, + public device_jvs_interface +{ +public: + namco_cyberlead_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0); + + auto &rs232() const { if (m_rs232) return *m_rs232; return *subdevice(m_rs232.finder_tag()); } + +protected: + namco_cyberlead_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock = 0); + + // device_t + virtual void device_add_mconfig(machine_config &config) override ATTR_COLD; + virtual ioport_constructor device_input_ports() const override ATTR_COLD; + virtual const tiny_rom_entry *device_rom_region() const override ATTR_COLD; + virtual void device_start() override ATTR_COLD; + + // device_jvs_interface + virtual void rxd(int state) override; + +private: + void iocpu_program_map(address_map &map); + + uint8_t iocpu_in_r(offs_t offset); + uint8_t iocpu_port_4_r(); + void iocpu_port_4_w(uint8_t data); + uint8_t iocpu_port_5_r(); + void iocpu_port_5_w(uint8_t data); + uint8_t iocpu_port_6_r(); + void iocpu_port_6_w(uint8_t data); + uint8_t iocpu_port_7_r(); + + required_device m_iocpu; + required_ioport m_dsw; + required_ioport m_port7; + required_device m_rs232; +}; + +class namco_cyberlead_led_device : + public device_t, + public device_rs232_port_interface +{ +public: + namco_cyberlead_led_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0); + +protected: + // device_t + virtual void device_add_mconfig(machine_config &config) override ATTR_COLD; + virtual ioport_constructor device_input_ports() const override ATTR_COLD; + virtual const tiny_rom_entry *device_rom_region() const override ATTR_COLD; + virtual void device_start() override ATTR_COLD; + + // device_rs232_port_interface + virtual void input_txd(int state) override; + + uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); + void ledcpu_program_map(address_map &map); + uint8_t ledcpu_banked_flash_r(offs_t offset); + void ledcpu_banked_flash_w(offs_t offset, uint8_t data); + void ledcpu_flash_bank_w(offs_t offset, uint8_t data); + uint8_t ledcpu_port_6_r(); + + required_device m_ledcpu; + required_device m_flash; + required_device m_screen; + required_shared_ptr m_scroll; + required_shared_ptr m_sed1351f_ram; + required_shared_ptr m_sed1351f_control; + required_ioport m_dsw; + rgb_t m_palette[4][4]; + int m_flash_bank; +}; + +DECLARE_DEVICE_TYPE(NAMCO_CYBERLEAD, namco_cyberlead_device) +DECLARE_DEVICE_TYPE(NAMCO_CYBERLEADA, device_jvs_interface) +DECLARE_DEVICE_TYPE(NAMCO_CYBERLEAD_LED, namco_cyberlead_led_device) + +#endif diff --git a/src/devices/bus/jvs/jvs.cpp b/src/devices/bus/jvs/jvs.cpp new file mode 100644 index 00000000000..5bc224e085b --- /dev/null +++ b/src/devices/bus/jvs/jvs.cpp @@ -0,0 +1,450 @@ +// license:BSD-3-Clause +// copyright-holders:smf + +#include "emu.h" +#include "jvs.h" + +#define LOG_PACKETS (1U << 1) +#define LOG_SIGNALS (1U << 2) +#define LOG_IGNORED (1U << 3) +#define LOG_CONFLICT (1U << 4) + +//#define VERBOSE (LOG_PACKETS /*| LOG_SIGNALS | LOG_IGNORED | LOG_CONFLICT*/) +//#define LOG_OUTPUT_FUNC osd_printf_info +#include "logmacro.h" + +#define LOGPACKETS(...) LOGMASKED(LOG_PACKETS, __VA_ARGS__) +#define LOGSIGNALS(...) LOGMASKED(LOG_SIGNALS, __VA_ARGS__) +#define LOGIGNORED(...) LOGMASKED(LOG_IGNORED, __VA_ARGS__) +#define LOGCONFLICT(...) LOGMASKED(LOG_CONFLICT, __VA_ARGS__) + +DEFINE_DEVICE_TYPE(JVS_PORT, jvs_port_device, "jvs_port", "JVS IO Port") + +#define FIX_CONFLICT (1) + +jvs_port_device::jvs_port_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : + device_t(mconfig, JVS_PORT, tag, owner, clock), + device_single_card_slot_interface(mconfig, *this), + m_device(nullptr), + m_debug_timer(nullptr), + m_rxd_cb(*this), + m_sense_cb(*this), + m_rts(0), + m_rxd(0), + m_txd(1) +{ +} + +jvs_port_device::~jvs_port_device() +{ +} + +void jvs_port_device::device_config_complete() +{ + m_device = get_card_device(); +} + +void jvs_port_device::device_start() +{ + device_jvs_interface *intf; + if (!owner()->interface(intf)) + { + if (VERBOSE & LOG_PACKETS) + m_debug_timer = timer_alloc(FUNC(jvs_port_device::debug_timer_callback), this); + + m_debug_bit = -1; + m_debug_index = 0; + m_debug_rxd = 1; + std::fill_n(m_debug_buffer, std::size(m_debug_buffer), 0); + + update_rxd(); + + save_item(NAME(m_debug_bit)); + save_item(NAME(m_debug_index)); + save_item(NAME(m_debug_rxd)); + save_item(NAME(m_debug_buffer)); + } + + save_item(NAME(m_rts)); + save_item(NAME(m_txd)); + save_item(NAME(m_rxd)); +} + +void jvs_port_device::rts(int state) +{ + if (m_rts != state) + { + LOGSIGNALS("%s rts %d\n", machine().describe_context(), state); + + if (machine().scheduler().currently_executing()) + machine().scheduler().synchronize(timer_expired_delegate(FUNC(jvs_port_device::update_rts), this), state); + else + update_rts(state); + } +} + +void jvs_port_device::update_rts(s32 state) +{ + debug_flush(); + debug_stop(); + + m_rts = state; + + if (m_device) + { + if (m_rts && !m_rxd && !(FIX_CONFLICT && m_txd)) + m_rxd_cb(1); + + update_rxd(); + } +} + +void jvs_port_device::txd(int state) +{ + if (m_txd != state) + { + LOGSIGNALS("%s txd %d\n", machine().describe_context(), state); + m_txd = state; + + update_rxd(); + } +} + +void jvs_port_device::update_rxd() +{ + int high = 0; + int low = 0; + + if (m_rts) + { + high += (m_txd != 0); + low += (m_txd == 0); + } + else if (!m_txd) + LOGIGNORED("ignored txd\n"); + + for (device_jvs_interface *intf = m_device; intf; intf = intf->m_jvs ? intf->m_jvs->m_device : nullptr) + { + if (intf->m_rts) + { + high += (intf->m_txd != 0); + low += (intf->m_txd == 0); + } + else if (!intf->m_txd) + LOGIGNORED("ignored txd %s\n", intf->device().tag()); + } + + if (high + low > 1 && ((VERBOSE & LOG_CONFLICT) || FIX_CONFLICT)) + { + debug_flush('@'); + + std::string conflict; + if (VERBOSE & LOG_CONFLICT) + conflict = util::string_format("conflict detected between %d devices (%d high, %d low)", high + low, high, low); + + if (m_rts) + { + if (VERBOSE & LOG_CONFLICT) + conflict += util::string_format(",%s (%d)", tag(), m_txd); + + if (FIX_CONFLICT && low && m_txd) + m_rts = 0; + } + + for (device_jvs_interface *intf = m_device; intf; intf = intf->m_jvs ? intf->m_jvs->m_device : nullptr) + if (intf->m_rts) + { + if (VERBOSE & LOG_CONFLICT) + conflict += util::string_format(",%s (%d)", intf->device().tag(), intf->m_txd); + + if (FIX_CONFLICT && low && intf->m_txd) + intf->m_rts = 0; + } + + LOGCONFLICT("%s\n", conflict); + + if (FIX_CONFLICT && low) + high = 0; + } + + int rxd = low && !high ? 0 : 1; + if (m_rxd != rxd) + { + m_rxd = rxd; + + for (device_jvs_interface *intf = m_device; intf; intf = intf->m_jvs ? intf->m_jvs->m_device : nullptr) + if (!intf->m_rts) + intf->rxd(m_rxd); + + if (!m_rts) + m_rxd_cb(m_rxd); + + debug_rxd(m_rxd); + } + + if (high + low == 0) + { + debug_flush(); + debug_stop(); + } +} + +void jvs_port_device::debug_rxd(int state) +{ + if (!state && m_debug_rxd && m_debug_timer && m_debug_timer->expire().is_never()) + m_debug_timer->adjust(attotime::from_hz(115200 * 2), 0, attotime::from_hz(115200)); + + m_debug_rxd = state; +} + +void jvs_port_device::debug_flush(wchar_t ch) +{ + if (m_debug_index) + { + if (VERBOSE & LOG_PACKETS) + { + std::string debug; + debug += m_rts ? ">" : "<"; + for (int i = 0; i < m_debug_index; i++) + debug += util::string_format(" %02x", m_debug_buffer[i]); + if (ch) + debug += ch; + debug += "\n"; + + LOGPACKETS("%s", debug); + } + + std::fill_n(m_debug_buffer, m_debug_index, 0); + m_debug_index = 0; + + debug_stop(); + } +} + +void jvs_port_device::debug_stop() +{ + if (m_debug_timer) + m_debug_timer->adjust(attotime::never); + m_debug_bit = -1; +} + +TIMER_CALLBACK_MEMBER(jvs_port_device::debug_timer_callback) +{ + if (m_debug_bit < 0) + { + if (m_debug_rxd) + debug_stop(); + else + m_debug_bit = 0; + } + else if (m_debug_bit == 8) + { + m_debug_index++; + + if (!m_debug_rxd) + debug_flush('*'); + else if (m_debug_index >= std::size(m_debug_buffer)) + debug_flush('!'); + + debug_stop(); + } + else + { + if (m_debug_rxd) + m_debug_buffer[m_debug_index] |= 1 << m_debug_bit; + + m_debug_bit++; + } +} + +device_jvs_interface::device_jvs_interface(const machine_config &mconfig, device_t &device) : + device_interface(device, "jvs"), + m_jvs(*this, "jvs"), + m_jvs_sense(jvs_port_device::sense::None), + m_default_inputs(true), + m_output_cb(*this), + m_analog_output_cb(*this), + m_system(*this, "SYSTEM"), + m_system_cb(*this, 0), + m_player(*this, "PLAYER%u", 1U), + m_player_cb(*this, 0), + m_coin(*this, "COIN%u", 1U), + m_coin_cb(*this, 0), + m_analog_input(*this, "ANALOG_INPUT%u", 1U), + m_analog_input_cb(*this, 0), + m_rotary_input(*this, "ROTARY_INPUT%u", 1U), + m_rotary_input_cb(*this, 0), + m_screen_position_enable(*this, "SCREEN_POSITION_INPUT_ENABLE%u", 1U), + m_screen_position_enable_cb(*this, 0xffff), + m_screen_position_x(*this, "SCREEN_POSITION_INPUT_X%u", 1U), + m_screen_position_x_cb(*this, 0), + m_screen_position_y(*this, "SCREEN_POSITION_INPUT_Y%u", 1U), + m_screen_position_y_cb(*this, 0), + m_rts(0), + m_sense(jvs_port_device::sense::None), + m_txd(1) +{ + m_port = dynamic_cast(device.owner()); + + m_root = m_port; + if (m_root) + { + device_jvs_interface *intf; + while (m_root->owner() && m_root->owner()->interface(intf) && m_root->owner()->owner()) + m_root = dynamic_cast(m_root->owner()->owner()); + } +} + +void device_jvs_interface::interface_post_start() +{ + sense(jvs_port_device::sense::Uninitialized); + + device().save_item(NAME(m_jvs_sense)); + device().save_item(NAME(m_rts)); + device().save_item(NAME(m_sense)); + device().save_item(NAME(m_txd)); +} + +device_jvs_interface::~device_jvs_interface() +{ +} + +void device_jvs_interface::rts(int state) +{ + if (m_rts != state) + { + if (device().machine().scheduler().currently_executing()) + device().machine().scheduler().synchronize(timer_expired_delegate(FUNC(device_jvs_interface::update_rts), this), state); + else + update_rts(state); + } +} + +void device_jvs_interface::update_rts(int32_t state) +{ + m_rts = state; + + if (m_root) + { + if (m_rts && !m_root->m_rxd && !(FIX_CONFLICT && m_txd)) + rxd(1); + + m_root->update_rxd(); + } +} + +void device_jvs_interface::txd(int state) +{ + if (m_txd != state) + { + m_txd = state; + + if (m_root) + m_root->update_rxd(); + } +} + +void device_jvs_interface::sense(uint8_t state) +{ + if (m_sense != state) + { + if (device().machine().scheduler().currently_executing()) + device().machine().scheduler().synchronize(timer_expired_delegate(FUNC(device_jvs_interface::update_sense), this), state); + else + update_sense(state); + } +} + +void device_jvs_interface::update_sense(int32_t state) +{ + m_sense = state; + + if (m_port) + { +#if VERBOSE & LOG_SIGNALS + device(). + LOG_OUTPUT_FUNC("%s sense %s %d\n", device().tag(), + m_sense == jvs_port_device::sense::Initialized ? "Initialized" : + m_sense == jvs_port_device::sense::Uninitialized ? "Uninitialized" : + m_sense == jvs_port_device::sense::None ? "None" : "", state); +#endif + + device_jvs_interface *intf; + if (m_port->owner()->interface(intf)) + intf->jvs_sense(m_sense); + else + m_port->m_sense_cb(m_sense); + } +} + +uint8_t device_jvs_interface::system_r(uint8_t mem_mask) +{ + return (m_default_inputs ? m_system.read_safe(0) : m_system_cb(mem_mask)) & mem_mask; +} + +uint32_t device_jvs_interface::player_r(offs_t offset, uint32_t mem_mask) +{ + return (m_default_inputs ? m_player[offset].read_safe(0) : m_player_cb[offset](0, mem_mask)) & mem_mask; +} + +uint8_t device_jvs_interface::coin_r(offs_t offset, uint8_t mem_mask) +{ + return (m_default_inputs ? m_coin[offset].read_safe(0) : m_coin_cb[offset](0, mem_mask)) & mem_mask; +} + +uint16_t device_jvs_interface::analog_input_r(offs_t offset, uint16_t mem_mask) +{ + return (m_default_inputs ? m_analog_input[offset].read_safe(0) : m_analog_input_cb[offset](0, mem_mask)) & mem_mask; +} + +uint16_t device_jvs_interface::rotary_input_r(offs_t offset) +{ + return m_default_inputs ? m_rotary_input[offset].read_safe(0) : m_rotary_input_cb[offset](); +} + +uint16_t device_jvs_interface::screen_position_enable_r(offs_t offset) +{ + return m_default_inputs ? m_screen_position_enable[offset].read_safe(0xffff) : m_screen_position_enable_cb[offset](); +} + +uint16_t device_jvs_interface::screen_position_x_r(offs_t offset) +{ + return m_default_inputs ? m_screen_position_x[offset].read_safe(0) : m_screen_position_x_cb[offset](); +} + +uint16_t device_jvs_interface::screen_position_y_r(offs_t offset) +{ + return m_default_inputs ? m_screen_position_y[offset].read_safe(0) : m_screen_position_y_cb[offset](); +} + +void device_jvs_interface::add_jvs_port(machine_config &config) +{ + JVS_PORT(config, m_jvs, jvs_port_devices, nullptr); +} + +void device_jvs_interface::jvs_sense(uint8_t state) +{ + m_jvs_sense = state; +} + +#include "cyberlead.h" +#include "namcoio.h" + +void jvs_port_devices(device_slot_interface &device) +{ + device.option_add("namco_amc", NAMCO_AMC); + device.option_add("namco_asca1", NAMCO_ASCA1); + device.option_add("namco_asca3", NAMCO_ASCA3); + device.option_add("namco_asca3a", NAMCO_ASCA3A); + device.option_add("namco_asca5", NAMCO_ASCA5); + device.option_add("namco_csz1", NAMCO_CSZ1); + device.option_add("namco_cyberlead", NAMCO_CYBERLEAD); + device.option_add("namco_cyberleada", NAMCO_CYBERLEADA); + device.option_add("namco_emio102", NAMCO_EMIO102); + device.option_add("namco_empri101", NAMCO_EMPRI101); + device.option_add("namco_fca10", NAMCO_FCA10); + device.option_add("namco_fca11", NAMCO_FCA11); + device.option_add("namco_fcb", NAMCO_FCB); + device.option_add("namco_tssio", NAMCO_TSSIO); + device.option_add("namco_xmiu1", NAMCO_XMIU1); +} diff --git a/src/devices/bus/jvs/jvs.h b/src/devices/bus/jvs/jvs.h new file mode 100644 index 00000000000..66b62c26ba9 --- /dev/null +++ b/src/devices/bus/jvs/jvs.h @@ -0,0 +1,157 @@ +// license:BSD-3-Clause +// copyright-holders:smf + +#ifndef MAME_BUS_JVS_JVS_H +#define MAME_BUS_JVS_JVS_H + +#pragma once + +class device_jvs_interface; + +class jvs_port_device : + public device_t, + public device_single_card_slot_interface +{ + friend class device_jvs_interface; + +public: + template + jvs_port_device(machine_config const &mconfig, char const *tag, device_t *owner, T &&opts, char const *dflt) + : jvs_port_device(mconfig, tag, owner, 0) + { + option_reset(); + opts(*this); + set_default_option(dflt); + set_fixed(false); + } + + jvs_port_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0); + virtual ~jvs_port_device(); + + struct sense { enum : uint8_t + { + Initialized = 0, // 0V + Uninitialized = 1, // 2.5V + None = 2 // 5v + }; }; + + auto rxd() { return m_rxd_cb.bind(); } + auto sense() { return m_sense_cb.bind(); } + + void txd(int state); + void rts(int state); + +protected: + // device_t + virtual void device_config_complete() override; + virtual void device_start() override ATTR_COLD; + + device_jvs_interface *m_device; + +private: + void debug_rxd(int state); + void debug_flush(wchar_t ch = 0); + void debug_stop(); + TIMER_CALLBACK_MEMBER(debug_timer_callback); + + emu_timer *m_debug_timer; + int8_t m_debug_bit; + uint16_t m_debug_index; + int8_t m_debug_rxd; + uint8_t m_debug_buffer[0x102]; + + void update_rts(int32_t state); + void update_rxd(); + + devcb_write_line m_rxd_cb; + devcb_write8 m_sense_cb; + int8_t m_rts; + int8_t m_rxd; + int8_t m_txd; +}; + +class device_jvs_interface : + public device_interface +{ + friend class jvs_port_device; + +public: + virtual ~device_jvs_interface(); + + auto system() { m_default_inputs = false; return m_system_cb.bind(); } + template auto player() { m_default_inputs = false; return m_player_cb[N].bind(); } + template auto coin() { m_default_inputs = false; return m_coin_cb[N].bind(); } + template auto analog_input() { m_default_inputs = false; return m_analog_input_cb[N].bind(); } + template auto rotary_input() { m_default_inputs = false; return m_rotary_input_cb[N].bind(); } + template auto screen_position_enable() { m_default_inputs = false; return m_screen_position_enable_cb[N].bind(); } + template auto screen_position_x() { m_default_inputs = false; return m_screen_position_x_cb[N].bind(); } + template auto screen_position_y() { m_default_inputs = false; return m_screen_position_y_cb[N].bind(); } + auto output() { return m_output_cb.bind(); } + template auto analog_output() { return m_analog_output_cb[N].bind(); } + + auto jvs() const { if (m_jvs.target()) return m_jvs.target(); return device().subdevice(m_jvs.finder_tag()); } + +protected: + device_jvs_interface(const machine_config &mconfig, device_t &device); + + // device_interface + virtual void interface_post_start() override; + + virtual void rxd(int state) = 0; + + void rts(int state); + void txd(int state); + void sense(uint8_t state); + virtual void jvs_sense(uint8_t state); + + void add_jvs_port(machine_config &config); + + uint8_t system_r(uint8_t mem_mask); + uint32_t player_r(offs_t offset, uint32_t mem_mask); + uint8_t coin_r(offs_t offset, uint8_t mem_mask); + uint16_t analog_input_r(offs_t offset, uint16_t mem_mask); + uint16_t rotary_input_r(offs_t offset); + uint16_t screen_position_enable_r(offs_t offset); + uint16_t screen_position_x_r(offs_t offset); + uint16_t screen_position_y_r(offs_t offset); + + optional_device m_jvs; + uint8_t m_jvs_sense; + + bool m_default_inputs; + devcb_write64 m_output_cb; + devcb_write16::array<8> m_analog_output_cb; + +private: + optional_ioport m_system; + devcb_read8 m_system_cb; + optional_ioport_array<8> m_player; + devcb_read32::array<8> m_player_cb; + optional_ioport_array<8> m_coin; + devcb_read8::array<8> m_coin_cb; + optional_ioport_array<8> m_analog_input; + devcb_read16::array<8> m_analog_input_cb; + optional_ioport_array<8> m_rotary_input; + devcb_read16::array<8> m_rotary_input_cb; + optional_ioport_array<8> m_screen_position_enable; + devcb_read16::array<8> m_screen_position_enable_cb; + optional_ioport_array<8> m_screen_position_x; + devcb_read16::array<8> m_screen_position_x_cb; + optional_ioport_array<8> m_screen_position_y; + devcb_read16::array<8> m_screen_position_y_cb; + + jvs_port_device *m_port; + jvs_port_device *m_root; + void update_rts(int32_t state); + void update_sense(int32_t state); + + int8_t m_rts; + uint8_t m_sense; + int8_t m_txd; +}; + +DECLARE_DEVICE_TYPE(JVS_PORT, jvs_port_device) + +void jvs_port_devices(device_slot_interface &device); + +#endif // MAME_BUS_JVS_JVS_H diff --git a/src/devices/bus/jvs/jvshle.cpp b/src/devices/bus/jvs/jvshle.cpp new file mode 100644 index 00000000000..50ef59402c1 --- /dev/null +++ b/src/devices/bus/jvs/jvshle.cpp @@ -0,0 +1,868 @@ +// license:BSD-3-Clause +// copyright-holders:smf + +#include "emu.h" +#include "jvshle.h" +#include + +#define LOG_COMMAND (1U << 1) +#define LOG_ERROR (1U << 2) +#define LOG_OUTPUT (1U << 3) + +//#define VERBOSE (/*LOG_COMMAND | */LOG_ERROR | LOG_OUTPUT) +//#define LOG_OUTPUT_FUNC osd_printf_info +#include "logmacro.h" + +#define LOGCOMMAND(...) LOGMASKED(LOG_COMMAND, __VA_ARGS__) +#define LOGERROR(...) LOGMASKED(LOG_ERROR, __VA_ARGS__) +#define LOGOUTPUT(...) LOGMASKED(LOG_OUTPUT, __VA_ARGS__) + +namespace { + +struct State { enum : uint8_t +{ + Sync, + Escape, + EscapedData, + Data +}; }; + +static constexpr uint8_t Sync = 0xe0; +static constexpr uint8_t Escape = 0xd0; + +} // anonymous namespace + +jvs_hle_device::jvs_hle_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) : + device_t(mconfig, type, tag, owner, clock), + device_jvs_interface(mconfig, *this), + m_rxd(1), + m_output(0), + m_analog_output{}, + m_analog_output_channels(0) +{ +} + +void jvs_hle_device::device_start() +{ + m_rx_timer = timer_alloc(FUNC(jvs_hle_device::rx_timer_callback), this); + m_tx_timer = timer_alloc(FUNC(jvs_hle_device::tx_timer_callback), this); + + m_coin_timer = timer_alloc(FUNC(jvs_hle_device::coin_timer_callback), this); + + m_mainid.resize(100); + m_mainid_length = 0; + m_retransmit_buffer.resize(0x102); + m_retransmit_length = 3; + m_rx_bit = -1; + m_rx_buffer.resize(0x102); + m_rx_length = 0; + m_rx_state = State::Sync; + m_tx_bit = -1; + m_tx_buffer.resize(0x102); + m_tx_index = 0; + m_tx_length = 0; + m_tx_state = State::Sync; + + save_item(NAME(m_address)); + save_item(NAME(m_mainid)); + save_item(NAME(m_mainid_length)); + save_item(NAME(m_retransmit_buffer)); + save_item(NAME(m_retransmit_length)); + save_item(NAME(m_rx_bit)); + save_item(NAME(m_rx_buffer)); + save_item(NAME(m_rx_index)); + save_item(NAME(m_rx_length)); + save_item(NAME(m_rx_state)); + save_item(NAME(m_rxd)); + save_item(NAME(m_tx_bit)); + save_item(NAME(m_tx_buffer)); + save_item(NAME(m_tx_index)); + save_item(NAME(m_tx_length)); + save_item(NAME(m_tx_safe_length)); + save_item(NAME(m_tx_state)); + + save_item(NAME(m_player_count)); + save_item(NAME(m_switch_count)); + save_item(NAME(m_switch_mask)); + save_item(NAME(m_coin_counter)); + save_item(NAME(m_coin_offset)); + save_item(NAME(m_coin_prev)); + save_item(NAME(m_analog_input_channels)); + save_item(NAME(m_analog_input_bits)); + save_item(NAME(m_rotary_input_channels)); + save_item(NAME(m_screen_position_input_channels)); + save_item(NAME(m_screen_position_input_xbits)); + save_item(NAME(m_screen_position_input_ybits)); + save_item(NAME(m_output)); + save_item(NAME(m_output_mask)); + save_item(NAME(m_output_slots)); + save_item(NAME(m_analog_output)); + save_item(NAME(m_analog_output_channels)); +} + +void jvs_hle_device::device_reset() +{ + rts(0); + sense(jvs_port_device::sense::Uninitialized); + rx_stop(); + rx_clear(); + + std::fill_n(m_mainid.begin(), m_mainid_length, 0); + m_mainid_length = 0; + m_address = 0xff; + m_retransmit_buffer[0] = 0x00; // destination + m_retransmit_buffer[2] = StatusCode::Normal; + std::fill_n(m_retransmit_buffer.begin() + 3, m_retransmit_length - 3, 0); + m_retransmit_length = 3; + m_rx_index = 0; + + m_player_count = player_count(); + m_switch_count = switch_count(); + m_switch_mask = switch_mask(); + m_coin_slots = coin_slots(); + m_coin_offset = coin_offset(); + + m_coin_counter.fill(0); + attotime const coin_timer_rate = m_coin_slots ? attotime::from_hz(120) : attotime::never; + m_coin_timer->adjust(coin_timer_rate, 0, coin_timer_rate); + m_coin_prev.fill(0xff); + + m_analog_input_channels = analog_input_channels(); + m_analog_input_bits = analog_input_bits(); + m_rotary_input_channels = rotary_input_channels(); + m_screen_position_input_channels = screen_position_input_channels(); + m_screen_position_input_xbits = screen_position_input_xbits(); + m_screen_position_input_xbits = screen_position_input_ybits(); + + m_output_slots = output_slots(); + m_output_mask = jvs_bitmask(m_output_slots); + update_output(0); + + for (int i = 0; i < m_analog_output_channels; i++) + update_analog_output(i, 0); + + m_analog_output_channels = analog_output_channels(); +} + +const char *jvs_hle_device::device_id() +{ + return ""; +} + +uint8_t jvs_hle_device::command_revision() +{ + return 0x13; +} + +uint8_t jvs_hle_device::jvs_revision() +{ + return 0x30; +} + +uint8_t jvs_hle_device::communication_revision() +{ + return 0x10; +} + +void jvs_hle_device::feature_check() +{ + uint8_t *response; + if (m_player_count && m_switch_count && produce(4, response)) + { + response[0] = FunctionCode::SwitchInput; + response[1] = m_player_count; + response[2] = m_switch_count; + response[3] = 0; + } + + if (m_coin_slots && produce(4, response)) + { + response[0] = FunctionCode::CoinInput; + response[1] = m_coin_slots; + response[2] = 0; + response[3] = 0; + } + + if (m_analog_input_channels && produce(4, response)) + { + response[0] = FunctionCode::AnalogInput; + response[1] = m_analog_input_channels; + response[2] = m_analog_input_bits; + response[3] = 0; + } + + if (m_rotary_input_channels && produce(4, response)) + { + response[0] = FunctionCode::RotaryInput; + response[1] = m_rotary_input_channels; + response[2] = 0; + response[3] = 0; + } + + if (m_screen_position_input_channels && produce(4, response)) + { + response[0] = FunctionCode::ScreenPositionInput; + response[1] = m_screen_position_input_xbits; + response[2] = m_screen_position_input_ybits; + response[3] = m_screen_position_input_channels; + } + + if (m_output_slots && produce(4, response)) + { + response[0] = FunctionCode::GeneralPurposeOutput; + response[1] = m_output_slots; + response[2] = 0; + response[3] = 0; + } + + if (m_analog_output_channels && produce(4, response)) + { + response[0] = FunctionCode::AnalogOutput; + response[1] = m_analog_output_channels; + response[2] = 0; + response[3] = 0; + } +} + +void jvs_hle_device::execute(uint8_t command) +{ + uint8_t const *parameters; + uint8_t *response; + + switch (command) + { + case CommandCode::Reset: + if (consume(1, parameters) && parameters[0] == 0xd9) + device_reset(); + break; + + case CommandCode::SetAddress: + if (consume(1, parameters) && m_jvs_sense != jvs_port_device::sense::Uninitialized && m_address == 0xff && + produce(1, response)) + { + m_address = parameters[0]; + response[0] = ReportCode::Normal; + } + break; + + case CommandCode::IOIDENT: + { + const char *id = device_id(); + int len = strlen(id) + 1; + if (produce(1 + len, response)) + { + response[0] = ReportCode::Normal; + memcpy(&response[1], id, len); + } + break; + } + + case CommandCode::CMDREV: + if (produce(2, response)) + { + response[0] = ReportCode::Normal; + response[1] = command_revision(); + } + break; + + case CommandCode::JVSREV: + if (produce(2, response)) + { + response[0] = ReportCode::Normal; + response[1] = jvs_revision(); + } + break; + + case CommandCode::COMMVER: + if (produce(2, response)) + { + response[0] = ReportCode::Normal; + response[1] = communication_revision(); + } + break; + + case CommandCode::FEATCHK: + if (produce(1, response)) + { + response[0] = ReportCode::Normal; + feature_check(); + if (produce(1, response)) + response[0] = 0x00; + } + break; + + case CommandCode::MAINID: + if (consume(1, parameters)) + { + uint8_t const *mainid = parameters; + size_t const size = m_rx_length - m_rx_index; + size_t length = 0; + while (mainid[length] && length < size) + length++; + + if (consume(length, parameters)) + { + if (length < size && length < m_mainid.size()) + { + if (produce(1, response)) + { + std::copy_n(mainid, length, m_mainid.begin()); + if (m_mainid_length > length) + std::fill_n(&m_mainid[length], m_mainid_length - length, 0); + m_mainid_length = length; + + //std::string s(m_mainid.begin(), m_mainid.begin() + length); + //osd_printf_info("mainid = %s\n", s); + + response[0] = ReportCode::Normal; + } + } + else if (produce(1, response)) + response[0] = ReportCode::InvalidParameter; + } + } + break; + + case CommandCode::SWINP: + if (consume(2, parameters)) + { + uint8_t const players = parameters[0]; + uint8_t const bytes = parameters[1]; + + if (players <= m_player_count && bytes <= (m_switch_count + 7) / 8) + { + if (produce((players * bytes) + 2, response)) + { + response[0] = ReportCode::Normal; + response[1] = system_r(0xff); + + uint32_t mask = m_switch_mask & jvs_bitmask(bytes * 8); + for (int i = 0; i < players; i++) + { + uint32_t val = player_r(i, mask); + for (int j = 0; j < bytes; j++) + response[(i * bytes) + j + 2] = val >> (j * 8); + } + } + } + else if (produce(1, response)) + response[0] = ReportCode::InvalidParameter; + } + break; + + case CommandCode::COININP: + if (consume(1, parameters)) + { + uint8_t const count = parameters[0]; + + if (count <= m_coin_slots) + { + if (produce((count * 2) + 1, response)) + { + response[0] = ReportCode::Normal; + + for (int i = 0; i < count; i++) + { + response[(i * 2) + 1] = (m_coin_counter[i] >> 8) & 0x3f; + response[(i * 2) + 2] = m_coin_counter[i]; + } + } + } + else if (produce(1, response)) + response[0] = ReportCode::InvalidParameter; + } + break; + + case CommandCode::ANLINP: + if (consume(1, parameters)) + { + uint8_t const count = parameters[0]; + + if (count <= m_analog_input_channels) + { + if (produce((count * 2) + 1, response)) + { + uint16_t const analog_input_mask = m_analog_input_bits > 0 && m_analog_input_bits < 16 ? make_bitmask(m_analog_input_bits) << (16 - m_analog_input_bits) : 0xffff; + + response[0] = ReportCode::Normal; + + for (int i = 0; i < count; i++) + { + uint16_t const analog_input = analog_input_r(i, analog_input_mask); + response[(i * 2) + 1] = analog_input >> 8; + response[(i * 2) + 2] = analog_input; + } + } + } + else if (produce(1, response)) + response[0] = ReportCode::InvalidParameter; + } + break; + + case CommandCode::ROTINP: + if (consume(1, parameters)) + { + uint8_t const count = parameters[0]; + + if (count <= m_rotary_input_channels) + { + if (produce((count * 2) + 1, response)) + { + response[0] = ReportCode::Normal; + + for (int i = 0; i < count; i++) + { + uint16_t const rotary_input = rotary_input_r(i); + response[(i * 2) + 1] = rotary_input >> 8; + response[(i * 2) + 2] = rotary_input; + } + } + } + else if (produce(1, response)) + response[0] = ReportCode::InvalidParameter; + } + break; + + case CommandCode::SCRPOSINP: + if (consume(1, parameters)) + { + uint8_t const index = parameters[0] - 1; + if (index < m_screen_position_input_channels) + { + if (produce(5, response)) + { + uint16_t const enable = screen_position_enable_r(index); + uint16_t const x = enable ? screen_position_x_r(index) : 0xffff; + uint16_t const y = enable ? screen_position_y_r(index) : 0xffff; + response[0] = ReportCode::Normal; + response[1] = x >> 8; + response[2] = x; + response[3] = y >> 8; + response[4] = y; + } + } + else if (produce(1, response)) + response[0] = ReportCode::InvalidParameter; + } + break; + + case CommandCode::RETRANSMIT: + std::copy_n(m_retransmit_buffer.begin(), m_retransmit_length, m_tx_buffer.begin()); + m_tx_length = m_retransmit_length; + break; + + case CommandCode::COINDEC: + if (consume(3, parameters)) + { + uint8_t const index = parameters[0] - m_coin_offset; + uint16_t const amount = (parameters[1] << 8) | parameters[2]; + + if (index < m_coin_slots) + { + if (produce(1, response)) + { + m_coin_counter[index] = (m_coin_counter[index] < amount) ? 0 : m_coin_counter[index] - amount; + response[0] = ReportCode::Normal; + } + } + else if (produce(1, response)) + response[0] = ReportCode::InvalidParameter; + } + break; + + case CommandCode::OUTPUT1: + if (consume(1, parameters)) + { + uint8_t const count = parameters[0]; + + if (consume(count, parameters)) + { + if (count <= (m_output_slots + 7) / 8) + { + if (produce(1, response)) + { + uint64_t output = m_output & ~jvs_bitmask(count * 8); + for (int i = 0; i < count; i++) + output |= (uint64_t)parameters[i] << (i * 8); + + update_output(output); + response[0] = ReportCode::Normal; + } + } + else if (produce(1, response)) + response[0] = ReportCode::InvalidParameter; + } + } + break; + + case CommandCode::ANLOUT: + if (consume(1, parameters)) + { + uint8_t const count = parameters[0]; + + if (consume(count * 2, parameters)) + { + if (count <= m_analog_output_channels) + { + if (produce(1, response)) + { + for (int i = 0; i < count; i++) + update_analog_output(i, (parameters[i * 2] << 8) | parameters[(i * 2) + 1]); + + response[0] = ReportCode::Normal; + } + } + else if (produce(1, response)) + response[0] = ReportCode::InvalidParameter; + } + } + break; + + case CommandCode::COININC: + if (consume(3, parameters)) + { + uint8_t const index = parameters[0] - m_coin_offset; + uint16_t const amount = (parameters[1] << 8) | parameters[2]; + + if (index < m_coin_slots) + { + if (produce(1, response)) + { + m_coin_counter[index] = (m_coin_counter[index] + amount) & 0x3fff; + response[0] = ReportCode::Normal; + } + } + else if (produce(1, response)) + response[0] = ReportCode::InvalidParameter; + } + break; + + case CommandCode::OUTPUT2: + if (consume(2, parameters)) + { + uint8_t const index = parameters[0] - 1; + uint8_t const output = parameters[1]; + + if (index < (m_output_slots + 7) / 8) + { + if (produce(1, response)) + { + update_output((m_output & ~(0xffULL << (index * 8))) | ((uint64_t)output << (index * 8))); + response[0] = ReportCode::Normal; + } + } + else if (produce(1, response)) + response[0] = ReportCode::InvalidParameter; + } + break; + + case CommandCode::OUTPUT3: + if (consume(2, parameters)) + { + uint8_t const index = parameters[0]; + uint8_t const output = parameters[1]; + + if (index < m_output_slots && output <= 2) + { + if (produce(1, response)) + { + if (output == 2 || BIT(m_output, index ^ 7) != output) + update_output(m_output ^ (1ULL << (index ^ 7))); + + response[0] = ReportCode::Normal; + } + } + else if (produce(1, response)) + response[0] = ReportCode::InvalidParameter; + } + break; + + default: + LOGERROR("unknown JVS command % 02x\n", command); + status_code(StatusCode::UnknownCommand); + break; + } +} + +void jvs_hle_device::status_code(uint8_t status_code) +{ + m_tx_buffer[2] = status_code; +} + +bool jvs_hle_device::consume(int size, uint8_t const *¶meters) +{ + if (m_rx_index + size < m_rx_length) + { + parameters = &m_rx_buffer[m_rx_index]; + m_rx_index += size; + return true; + } + + uint8_t *response; + if (produce(1, response)) + response[0] = ReportCode::IncorrectNumberOfParameters; + + m_rx_index = m_rx_length - 1; + parameters = nullptr; + return false; +} + +bool jvs_hle_device::produce(int size, uint8_t *&response) +{ + if (m_tx_length + size >= std::size(m_tx_buffer)) + { + status_code(StatusCode::AcknowledgeOverflow); + m_tx_length = m_tx_safe_length; + } + + if (m_tx_buffer[2] == StatusCode::Normal) + { + response = &m_tx_buffer[m_tx_length]; + m_tx_length += size; + return true; + } + + response = nullptr; + return false; +} + +void jvs_hle_device::packet_received() +{ + m_tx_bit = -1; + std::fill_n(m_tx_buffer.begin(), m_tx_length, 0); + m_tx_index = 0; + m_tx_length = 0; + + if (m_rx_length >= 4 && (m_rx_buffer[0] == 0xff || m_rx_buffer[0] == m_address)) + { + m_tx_buffer[0] = 0x00; // destination + + uint8_t checksum = std::accumulate(m_rx_buffer.begin(), m_rx_buffer.begin() + m_rx_length - 1, 0); + if (m_rx_buffer[m_rx_length - 1] != checksum) + { + LOGERROR("jvs checksum %02x expected %02x\n", checksum, m_rx_buffer[m_rx_length - 1]); + + if (m_rx_buffer[0] != 0xff) + { + status_code(StatusCode::ChecksumError); + m_tx_length = 3; + } + } + else + { + if (VERBOSE & LOG_COMMAND) + { + std::string jvsin; + for (int i = 0; i < m_rx_length; i++) + jvsin += util::string_format(" %02x", m_rx_buffer[i]); + + LOGCOMMAND("jvs in %s\n", jvsin); + } + + status_code(StatusCode::Normal); + + m_rx_index = 2; + m_tx_length = 3; + + while (m_tx_buffer[2] == StatusCode::Normal && m_rx_index < m_rx_length - 1) + { + m_tx_safe_length = m_tx_length; + execute(m_rx_buffer[m_rx_index++]); + } + + if (m_tx_length == 3 && m_tx_buffer[2] == StatusCode::Normal) + m_tx_length = 0; + else + { + std::copy_n(m_tx_buffer.begin(), m_tx_length, m_retransmit_buffer.begin()); + m_retransmit_length = m_tx_length; + } + } + + if (m_tx_length) + { + m_tx_buffer[1] = m_tx_length - 1; + uint8_t checksum = std::accumulate(m_tx_buffer.begin(), m_tx_buffer.begin() + m_tx_length, 0); + m_tx_buffer[m_tx_length++] = checksum; + + if (VERBOSE & LOG_COMMAND) + { + std::string jvsout; + for (int i = 0; i < m_tx_length; i++) + jvsout += util::string_format(" %02x", m_tx_buffer[i]); + + LOGCOMMAND("jvs out %s\n", jvsout); + } + + m_tx_timer->adjust(attotime::from_hz(115200) * 10, 0, attotime::from_hz(115200)); + } + } + + rx_clear(); +} + +void jvs_hle_device::rxd(int state) +{ + if (m_rxd && !state && m_rx_timer && m_rx_timer->expire().is_never()) + m_rx_timer->adjust(attotime::from_hz(115200) / 2, 0, attotime::from_hz(115200)); + + m_rxd = state; +} + +TIMER_CALLBACK_MEMBER(jvs_hle_device::rx_timer_callback) +{ + if (m_rx_bit < 0) + { + if (m_rxd) + rx_stop(); + else + m_rx_bit = 0; + } + else if (m_rx_bit < 8) + { + if (m_rxd) + m_rx_buffer[m_rx_length] |= 1 << m_rx_bit; + + m_rx_bit++; + } + else + { + m_rx_length++; + + if (!m_rxd) + rx_clear(); // frame error + else if (m_rx_buffer[m_rx_length - 1] == Sync) + { + rx_clear(); + m_rx_state = State::Data; + } + else if (m_rx_state == State::Sync) + rx_discard(); + else if (m_rx_buffer[m_rx_length - 1] == Escape) + { + rx_discard(); + m_rx_state = State::EscapedData; + } + else + { + if (m_rx_state == State::EscapedData) + { + m_rx_buffer[m_rx_length - 1]++; + m_rx_state = State::Data; + } + + if (m_rx_length >= 2 && m_rx_length == m_rx_buffer[1] + 2) + packet_received(); + else if (m_rx_length == m_rx_buffer.size()) + rx_clear(); + } + + rx_stop(); + } +} + +TIMER_CALLBACK_MEMBER(jvs_hle_device::tx_timer_callback) +{ + if (m_tx_bit < 0) + { + if (m_tx_index >= m_tx_length) + { + m_tx_timer->adjust(attotime::never); + m_tx_state = State::Sync; + rts(0); + sense(jvs_port_device::sense::Initialized); + } + else + { + if (m_tx_index == 0) + rts(1); + txd(0); + m_tx_bit = 0; + } + } + else if (m_tx_bit < 8) + { + uint8_t data = (m_tx_state == State::Sync) ? Sync : + (m_tx_state == State::Escape) ? Escape : + (m_tx_state == State::EscapedData) ? m_tx_buffer[m_tx_index] - 1 : + m_tx_buffer[m_tx_index]; + + txd(BIT(data, m_tx_bit)); + m_tx_bit++; + } + else + { + txd(1); + m_tx_bit = -1; + + if (m_tx_state == State::Escape) + m_tx_state = State::EscapedData; + else + { + if (m_tx_state != State::Sync) + m_tx_index++; + + if (m_tx_index < m_tx_length && (m_tx_buffer[m_tx_index] == Sync || m_tx_buffer[m_tx_index] == Escape)) + m_tx_state = State::Escape; + else + m_tx_state = State::Data; + } + } +} + +TIMER_CALLBACK_MEMBER(jvs_hle_device::coin_timer_callback) +{ + for (int i = 0; i < m_coin_slots; i++) + { + uint8_t coin = coin_r(i, 0x01); + if (BIT(coin & ~m_coin_prev[i], 0)) + m_coin_counter[i] = (m_coin_counter[i] + 1) & 0x3fff; + + m_coin_prev[i] = coin; + } +} + +void jvs_hle_device::rx_clear() +{ + std::fill_n(m_rx_buffer.begin(), m_rx_length, 0); + m_rx_length = 0; + m_rx_state = State::Sync; +} + +void jvs_hle_device::rx_discard() +{ + m_rx_buffer[--m_rx_length] = 0; +} + +void jvs_hle_device::rx_stop() +{ + m_rx_timer->adjust(attotime::never); + m_rx_bit = -1; +} + +uint32_t jvs_hle_device::switch_mask() +{ + return jvs_bitmask(switch_count()); +} + +void jvs_hle_device::update_output(uint64_t output) +{ + output &= m_output_mask; + + if (m_output != output) + { + LOGOUTPUT("update_output %0*llx\n", (m_output_slots + 3) / 4, output); + m_output_cb(0, output, output ^ m_output); + m_output = output; + } +} + +void jvs_hle_device::update_analog_output(int offset, uint16_t output) +{ + if (m_analog_output[offset] != output) + { + LOGOUTPUT("update_fanalog_output %d %04x\n", offset, output); + m_analog_output_cb[offset](0, output, 0xffff); + m_analog_output[offset] = output; + } +} diff --git a/src/devices/bus/jvs/jvshle.h b/src/devices/bus/jvs/jvshle.h new file mode 100644 index 00000000000..67f7b9fc859 --- /dev/null +++ b/src/devices/bus/jvs/jvshle.h @@ -0,0 +1,175 @@ +// license:BSD-3-Clause +// copyright-holders:smf +#ifndef MAME_BUS_JVS_JVSDEV_H +#define MAME_BUS_JVS_JVSDEV_H + +#pragma once + +#include "jvs.h" + +class jvs_hle_device : + public device_t, + public device_jvs_interface +{ +protected: + jvs_hle_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock = 0); + + // device_t + virtual void device_start() override ATTR_COLD; + virtual void device_reset() override ATTR_COLD; + + // device_jvs_interface + virtual void rxd(int state) override; + + virtual const char *device_id(); + virtual uint8_t command_revision(); + virtual uint8_t jvs_revision(); + virtual uint8_t communication_revision(); + virtual uint8_t player_count() { return 0; } + virtual uint8_t switch_count() { return 0; } + virtual uint32_t switch_mask(); + virtual uint8_t coin_slots() { return 0; } + virtual uint8_t coin_offset() { return 1; } + virtual uint8_t analog_input_channels() { return 0; } + virtual uint8_t analog_input_bits() { return 0; } + virtual uint8_t rotary_input_channels() { return 0; } + virtual uint8_t screen_position_input_channels() { return 0; } + virtual uint8_t screen_position_input_xbits() { return 0; } + virtual uint8_t screen_position_input_ybits() { return 0; } + virtual uint8_t output_slots() { return 0; } + virtual uint8_t analog_output_channels() { return 0; } + virtual void feature_check(); + virtual void execute(uint8_t command); + void status_code(uint8_t status_code); + bool consume(int size, const uint8_t *¶meters); + bool produce(int size, uint8_t *&response); + + template constexpr T jvs_bitmask(U n) + { + return make_bitmask((n + 7) & ~7) ^ (make_bitmask((-n) & 7) << (n & ~7)); + } + + struct CommandCode { enum : uint8_t + { + Reset = 0xf0, + SetAddress = 0xf1, + CommMethodChange = 0xf2, + + IOIDENT = 0x10, + CMDREV = 0x11, + JVSREV = 0x12, + COMMVER = 0x13, + FEATCHK = 0x14, + MAINID = 0x15, + + SWINP = 0x20, + COININP = 0x21, + ANLINP = 0x22, + ROTINP = 0x23, + KEYINP = 0x24, + SCRPOSINP = 0x25, + MISCSWINP = 0x26, + + PAYCNT = 0x2e, + RETRANSMIT = 0x2f, + COINDEC = 0x30, + PAYINC = 0x31, + OUTPUT1 = 0x32, + ANLOUT = 0x33, + CHAROUT = 0x34, + COININC = 0x35, + PAYDEC = 0x36, + OUTPUT2 = 0x37, + OUTPUT3 = 0x38, + }; }; + + struct StatusCode { enum : uint8_t + { + Normal = 0x01, + UnknownCommand = 0x02, + ChecksumError = 0x03, + AcknowledgeOverflow = 0x04, + }; }; + + struct ReportCode { enum : uint8_t + { + Normal = 0x01, + IncorrectNumberOfParameters = 0x02, + InvalidParameter = 0x03, + Busy = 0x04, + }; }; + + struct FunctionCode { enum : uint8_t + { + End = 0x00, + + SwitchInput = 0x01, + CoinInput = 0x02, + AnalogInput = 0x03, + RotaryInput = 0x04, + KeycodeInput = 0x05, + ScreenPositionInput = 0x06, + MiscSwitchInput = 0x07, + + CardSystem = 0x10, + MedalHopper = 0x11, + GeneralPurposeOutput = 0x12, + AnalogOutput = 0x13, + CharacterOutput = 0x14, + Backup = 0x15, + }; }; + +private: + void packet_received(); + TIMER_CALLBACK_MEMBER(rx_timer_callback); + TIMER_CALLBACK_MEMBER(tx_timer_callback); + TIMER_CALLBACK_MEMBER(coin_timer_callback); + void rx_clear(); + void rx_discard(); + void rx_stop(); + void update_output(uint64_t output); + void update_analog_output(int offset, uint16_t output); + + emu_timer *m_tx_timer; + emu_timer *m_rx_timer; + emu_timer *m_coin_timer; + + uint8_t m_address; + std::vector m_mainid; + uint8_t m_mainid_length; + std::vector m_retransmit_buffer; + uint16_t m_retransmit_length; + uint16_t m_rx_index; + int32_t m_rx_bit; + std::vector m_rx_buffer; + int32_t m_rx_length; + uint8_t m_rx_state; + int32_t m_rxd; + int32_t m_tx_bit; + std::vector m_tx_buffer; + int32_t m_tx_index; + uint32_t m_tx_length; + uint32_t m_tx_safe_length; + uint8_t m_tx_state; + + uint8_t m_player_count; + uint8_t m_switch_count; + uint32_t m_switch_mask; + uint8_t m_coin_slots; + std::array m_coin_counter; + uint8_t m_coin_offset; + std::array m_coin_prev; + uint8_t m_analog_input_channels; + uint8_t m_analog_input_bits; + uint8_t m_rotary_input_channels; + uint8_t m_screen_position_input_channels; + uint8_t m_screen_position_input_xbits; + uint8_t m_screen_position_input_ybits; + uint64_t m_output; + uint64_t m_output_mask; + uint8_t m_output_slots; + std::array m_analog_output; + uint8_t m_analog_output_channels; +}; + +#endif // MAME_BUS_JVS_JVSDEV_H diff --git a/src/devices/bus/jvs/namcoio.cpp b/src/devices/bus/jvs/namcoio.cpp new file mode 100644 index 00000000000..fc9580423ff --- /dev/null +++ b/src/devices/bus/jvs/namcoio.cpp @@ -0,0 +1,1564 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/* +Namco I/O PCBs +-------------- + +ASCA-1A PCB +8662968202 (8662978202) +|--------------------------------------------------------| +|J105 J104 J103 J102 J101 | +| NJM2904 |-------| | +| ADM485 |ALTERA | | +| NJM2904 |EPM7064| | +| | | | +| |-------| |-------| | +| |---| | | | +| IC13| | C78 | SW2 LB1235 LB1233 | +| |---| | | 14.7460MHz LB1235 | +| JP1|-------| | +| 62256 PST592D | +| MB87078 J106 | +|--------------------------------------------------------| +Notes: + IC13 - Atmel AT29C020 2MBit EEPROM labelled 'ASC1IO-A' (PLCC32) + C78 - Namco Custom MCU, positively identified as a Hitachi H8/3334 (PLCC84) + Clock input 14.7460MHz + EPM7064 - Altera EPM7064LC68-15 CPLD, labelled 'ASCA DR0' (PLCC68) + PST592D - System Reset IC (SOIC4) + 62256 - Hitachi HM62256 32kB x8-bit SRAM + ADM485 - Analog Devices +ADM485 5V Low Power EIA RS-485 Transceiver (SOIC8) + MB87078 - Fujitsu MB87078 Electronic Volume Control IC (SOIC24) + NJM2904 - New Japan Radio Co. NJM2904 Dual Operational Amplifier + LB1235 - Sanyo LB1235 65V 1.5A 4-channel Darlington Driver + LB1233 - Sanyo LB1233 Darlington Transistor Array with Built-in Current Limiting Resistors + J101 - 64 pin connector joining to ? + J102 - USB-A connector \ both tied together with common connections + J103 - USB-B connector / + J104 - Dual Red/White RCA Jacks (Twin Stereo Audio) + J105 - 9 pin connector + J106 - 12 pin connector + JP1 - 3 pin jumper labelled 'WE' and 'NC'. Default position is NC. This is used to write enable + the EEPROM for factory programming. + SW2 - DIP switch with 4 switches (default all off) + +This board is used with Final Furlong. This board connects to GORgON AV PCB + + +V187 ASCA-2A PCB +2477960102 (2477970102) +|--------------------------------------------------------| +| J105 | +| |-------| 14.7456MHz | +| J104 |ALTERA | ADM485 PST592D| +| |EPM7064| |-------| | +| | | | | | +| |-------| | C78 | | +| LC78815 | | | +| |-------| | +| MB87078 |---| | +| LA4705 LB1233 |IC1| 62256 | +| LB1235 |---| | +| J101 J102 | +|--------------------------------------------------------| +Notes: + IC1 - Atmel AT29C020 2MBit EEPROM labelled 'ASCA1 I/O-A' (PLCC32) + C78 - Namco Custom MCU, positively identified as a Hitachi H8/3334 (PLCC84) + Clock input 14.7456MHz + EPM7064 - Altera EPM7064LC68-15 CPLD, labelled 'ASCA DR0' (PLCC68) + PST592D - System Reset IC (SOIC4) + ADM485 - Analog Devices +ADM485 5V Low Power EIA RS-485 Transceiver (SOIC8) + 62256 - Hitachi HM62256 32kB x8-bit SRAM + LB1235 - Sanyo LB1235 65V 1.5A 4-channel Darlington Driver + LB1233 - Sanyo LB1233 Darlington Transistor Array with Built-in Current Limiting Resistors + MB87078 - Fujitsu MB87078 Electronic Volume Control IC (SOIC24) + LC78815 - Sanyo LC78815 2-Channel 16-Bit D/A Converter (SOIC20) + LA4705 - Sanyo LA4705 15W 2-channel Power Amplifier + J101 - 34 pin flat cable connector for filter board + J102 - 50 pin flat cable connector for filter board + J104 - 8 pin JVS power connector (+5V, +12V, +3.3V) + J105 - 64 pin connector for connection of Main PCB + +This board is used with Rapid River but also works with Final Furlong. + + +ASCA-3A PCB 8662968301 (8662978301) +This is used with Motocross Go! +It's identical to the one shown below (ASCA-4A) but the ROM is a surface mounted +PLCC32 instead of a socketed DIP32 chip. Everything else is identical. + +ASCA-4A PCB 8662968401 (8662978401) +(Used with most games and [for testing purposes] is able to boot all S23/SS23/Evolution2 games) +Sticker for Gunmen Wars: ASCA5 PCB 86629615 +|---------------------------------------------------| +| PST592 62256 | +| 14.7460MHz |-------| | +| | C78 | | +| LB1235 DSW(4) | | 27C1001 | +| LB1233 LB1235 |-------| | +| | +| |------| ADM485 | +| |ALTERA| | +| |EPM7096 | +| J101 |------| J102 J103 | +|---------------------------------------------------| +Notes: + J101 - 64 pin connector for power + inputs. This joins to another PCB at 90 degrees containing + a bunch of connectors named 'ASCA 4B PCB 8662968702 (8662978702)'. This is where ALL of the + inputs/outputs for game control and inter-PCB communication are connected + PST592 - System Reset IC (SOIC4) + C78 - Hitachi HD643334 H8/3334 Microcontroller rebadged as 'C78'. Clock input 14.746MHz (PLCC84) + 27C1001 - 128k x8 EPROM (DIP32) + - For Downhill Bikers labelled 'ASC3 IO-C' + - For Panic Park labelled 'ASC3 IO-C' + - For Race On! labelled 'ASC5 IO-A' + - For Gunmen Wars labelled 'ASC5 IO-A' + 62256 - 32k x8 SRAM (SOP28) + EPM7096 - Altera EPM7096 CPLD with sticker 'ASCA,DR1' (PLCC68) + ADM485 - Analog Devices ADM485 +5V Low Power EIA RS-485 Transceiver (SOIC8) + J102/J103- Standard USB A and B connectors. These are not populated on most games, but are populated for + use with Motocross Go! on the ASCA-3A PCB. + + +FCA PCB 8662969102 (8662979102) +(Used with 500GP and Angler King. Another identical board is used with Ridge Racer V on System 246) +|---------------------------------------------------| +| J101 J106 | +| 4.9152MHz | +| DSW(6) | +| LED2 |-----| | +| | MCU | | +| LEDS3-10 | | | +| PIC16F84 |-----| | +| JP1 LED1 ADM485 | +| | +| J102 J104 | +|---------------------------------------------------| +Notes: + J101 - 6 pin connector for power input + J102 - 60 pin flat cable connector + J104 - 5 pin connector + J106 - 30 pin flat cable connector + JP1 - 3 pin jumper, set to 'NORM'. Alt setting 'WR' + 3771 - Fujitsu MB3771 System Reset IC (SOIC8) + PIC16F84 - Microchip PIC16F84 PIC (SOIC20) + - For 500GP and Angler King stamped 'CAP10' + - For Ridge Racer V (on System 246) stamped 'CAP11' + MCU - Fujitsu MB90F574 F2MC-16LX Family Microcontroller (QFP120) + - For 500 GP and Angler King stamped 'FCAF10' + - For Ridge Racer V (on System 246) stamped 'FCAF11' + ADM485 - Analog Devices ADM485 +5V Low Power EIA RS-485 Transceiver (SOIC8) + + +Drive/Feedback PCB +------------------ + +V183 AMC PCB 2473966102 (2473970102) +|---------------------------------------------------| +| | +| | +| 4.9152MHz J2| +| |-----| | +| | MCU | | +| | | | +| SS22 FFB |-----| | +| |------| | +| |ALTERA| DSW(4) | +| |EPM7096 | +| |------| | +| J4| +| ADM485 | +| 27C1024 62256x2 J5| +| | +|---------------------------------------------------| +Notes: + This board is used only with Motocross Go! to control the steering feedback motor. It communicates as a slave JVS + I/O board to both the game board and the ASCA I/O board. Another signal labelled as 'FREEZE/RELAY' connects between + this board to its ASCA I/O board. + + MCU - Fujitsu MB90611A F2MC-16F Family Microcontroller. Clock input 4.9152MHz (QFP100) + 62256 - 32k x2 SRAM (SOP28) + EPM7096 - Altera EPM7064 CPLD labelled 'MG1,P LD0A' (PLCC44) + 27C1001 - 128k x8 EPROM labelled 'MG1-PRG0' (DIP40) + ADM485 - Analog Devices ADM485 +5V Low Power EIA RS-485 Transceiver (SOIC8) + J4/J5 - Standard USB A and B connectors. + J2 - Ribbon cable connector. + SS22 FFB - The recycled System 22 v147 motor drive board portion. + + From testing on an actual Motocross Go! cabinet, the game doesn't like it if this board is disconnected in any way. + It needs both an ASCA and AMC I/O board chained in order to fully boot with properly working I/O. The following happens + if any portion of an AMC pcb is disconnected (only applies to Motocross Go!). + + AMC board powered off: Board doesn't properly initialize its subcpu giving a 'subcpu timeout'. + AMC board powered on, JVS comms disconnected, freeze/relay connected: Board initializes the subcpu properly but + intentionally disables inputs. + AMC board powered on, JVS comms connected, freeze/relay disconnected: Board initializes the subcpu properly. + Main inputs work. Motor doesn't respond (if freeze/relay is reconnected, the motor will respond again). + + In RS232 mode, the data should be sent at 9600 8n1 in the following format: + byte 0: 0xff + byte 1: 0x00-0x7f Analog output 0 + byte 2: 0x00-0x0f/0x80-0x8f digital output + byte 3: 0x00-0xff Analog output 1 + + +I/O Boards for gun games +------------------------ + +Type 1: + +V185 I/O PCB +2479961102 (2479971102) +|-----------------------------------------| +| J601 LED1 LED2 |-------| | +| DSW(4)JP1 |-------| |TSSIO | | +| |-----| | C78 |14.746MHz|PLD | | +| |TSSIO| | |PST592 |-------| | +| |PROG | |-------| | +| |-----| | +| | +| 62256 | +|ADM485 | +|J1 SLA4060 J5| +| J3 J4 | +|-----------------------------------------| +Notes: + TSSIOPROG - Atmel AT29C020 EEPROM stamped 'TSSIOP8' (PLCC32) + C78 - Namco Custom C78, actually a rebadged Hitachi HD643334 MCU, clock input 14.746MHz (PLCC84) + TSSIOPLD - Altera MAX EPM7128ELC84 CPLD with label 'TSSIOPLD' (PLCC84) + SLA4060 - Sanken Electric SLA4060 NPN general purpose darlington transistor (used to drive the kick-back solenoid in the gun) + PST592 - System Reset IC (SOIC4) + J1 - 12 position connector for power and I/O communication + J3 - 12 position connector for gun connection (trigger/buttons/optical signal/power) + J4 - not used? + J5 - 6 position connector for network + J601 - not used? + JP1 - jumper set to 1-2 (lower position), labelled 'WR' + DSW - 4 position dipswitch block, all off + +This board is used only on Time Crisis II. +Note the gun is a standard light gun. + + +Type 2: + +V221 MIU PCB +2512960101 (2512970101) +additional sticker for Time Crisis 3 says '2591961001 V291 XMIU PCB' +|---------------------------------------------| +|J10 J9 29C020 LC35256 DSW(4) | +| M0105 PRG.8F LED | +|2267 6393 LED | +| T082 T082 |------| | +| |--------| | C78 | J8 | +| |ALTERA | | | | +|J11 |MAX | |------| J7| +| LM1881 |EPM7128 | 3771 | +|R305526 |--------| | +| ZUW1R51212 14.746MHz | +| ADM485 J6| +| | +| J1 J2 J3 J4 J5 | +|---------------------------------------------| +Notes: + 2267 - JRC2267 Current limiting diode array? (SOIC8) + R305526 - Some kind of mini transformer or regulator? + LC35256 - Sanyo LC35256 32k x8 SRAM (SOP28) + LM1881 - National Semiconductor LM1881 Video Sync Separator (SOIC8) + M0105 - Matsushita Panasonic 0105 = ? (SOIC16) + T082 - Texas Instruments T082 (=TL082) JFET-Input operational amplifier (SOIC8) + 6393 - Sanyo 6393 (LA6393) High Performance Dual Comparator (SOIC8) + ADM485 - Analog Devices ADM485 5V Low Power EIA RS-485 Transceiver (SOIC8) + 3771 - Fujitsu MB3771 Power Supply Monitor and Master Reset IC (SOIC8) + EPM7128 - Altera MAX EPM7128SLC84-15 PLD labelled 'TMIU1/PLD0' (Time Crisis 3) + 29C020 - location for 29C020 PLCC32 Flash/EP ROM (not populated) + ZUW1R51212 - Cosel ZUW1R51212 DC to DC Power Supply Module (input 9-18VDC, output +-12VDC or +24VDC) + DSW - 4 position dipswitch block, all off + J1 - 6-pin power input connector + J2 - 12-pin connector (cabinet buttons UP/DOWN/ENTER plus TEST/SERVICE/COIN etc) + J3 - 4 pin connector (not used) + J4 - 9 pin Namco female plug connector for gun (solenoid +24V/trigger/pedal/sensor) + J5 - 5 pin connector used for I/O --> S246 communications (connects to USB link connection on main unit) + J6 - 7-pin connector (not used) + J9 - 6-pin connector (not used) + J10 - 2-pin Namco female plug connector (not used) + J11 - 6-pin Namco female plug connector (video input from CCD camera) + PRG.8F - 27C1001 EPROM with label + 'XMIU1 PRG0' (I/O program for Time Crisis 3) + 'CSZ1 PRG0A' (I/O program for Crisis Zone) + +This board is used on Crisis Zone (System 23 Evolution2) and Time Crisis 3 (System 246) +Note both games use a CCD camera for the gun sensor. + +*/ + +#include "emu.h" +#include "namcoio.h" +#include "jvshle.h" +#include "cpu/f2mc16/mb90570.h" + +#define LOG_OUTPUT (1U << 1) + +//#define VERBOSE (LOG_OUTPUT) +//#define LOG_OUTPUT_FUNC osd_printf_info +#include "logmacro.h" + +#define LOGOUTPUT(...) LOGMASKED(LOG_OUTPUT, __VA_ARGS__) + +namco_amc_device::namco_amc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : + device_t(mconfig, NAMCO_AMC, tag, owner, clock), + device_jvs_interface(mconfig, *this), + device_rs232_port_interface(mconfig, *this), + m_iocpu(*this, "iocpu"), + m_analog_output{}, + m_clear_output(1), + m_output(0), + m_ppg_duty(0), + m_ppg_flags(0), + m_sense_latch(0), + m_unknown_output(0) +{ +} + +void namco_amc_device::device_add_mconfig(machine_config &config) +{ + MB90611A(config, m_iocpu, 4.9152_MHz_XTAL); + m_iocpu->set_addrmap(AS_PROGRAM, &namco_amc_device::iocpu_program_map); + m_iocpu->ppg().output<1>().set([this](offs_t offset, uint32_t data, uint32_t mem_mask) + { + m_ppg_duty = mem_mask >> 26; + update_analog_output0(); + }); + m_iocpu->adc().channel<0>().set(FUNC(namco_amc_device::adc_r<0>)); + m_iocpu->adc().channel<1>().set(FUNC(namco_amc_device::adc_r<1>)); + m_iocpu->adc().channel<2>().set(FUNC(namco_amc_device::adc_r<2>)); + m_iocpu->adc().channel<3>().set(FUNC(namco_amc_device::adc_r<3>)); + m_iocpu->port<0x2>().read().set([this]() + { + return (BIT(m_clear_output, 0) << 7) | + ((m_jvs_sense != jvs_port_device::sense::Initialized) << 6) | + ((m_jvs_sense != jvs_port_device::sense::None) << 5) | + (1 << 4) | // sense + (15 << 0); // output + }); + m_iocpu->port<0x2>().write().set([this](uint8_t data) + { + m_sense_latch = BIT(data, 4); // HACK: improve compatibility by delaying sense::Initialized + if (!m_sense_latch) + sense(jvs_port_device::sense::Uninitialized); + + uint8_t output = bitswap<4>(data, 0, 1, 2, 3) << 4; + if (m_output != output) + { + LOGOUTPUT("output_w %02x\n", output); + m_output_cb(0, output, output ^ m_output); + m_output = output; + } + }); + m_iocpu->port<0x3>().read().set([this](uint8_t data) + { + return ~bitswap<8>(player_r(0, 0xfc03), 10, 11, 12, 13, 14, 15, 0, 1); + }); + m_iocpu->port<0x7>().read().set_ioport("DSW"); + m_iocpu->port<0x8>().write().set([this](uint8_t data) + { + m_ppg_flags = BIT(data, 0, 2); + update_analog_output0(); + + m_unknown_output = BIT(data, 2); // RS232 bit 7 of digital data, JVS unknown? + // BIT(data, 5); // set at startup + }); + m_iocpu->port<0x9>().write().set([this](uint8_t data) + { + if (m_sense_latch) + sense(jvs_port_device::sense::Initialized); // HACK: improve compatibility by delaying sense::Initialized + + // BIT(data, 1); // set at startup + rts(BIT(data, 2)); + // BIT(data, 3); // toggles to indicate activity/error? + // BIT(data, 4); // "" + }); + + m_iocpu->uart<1>().sot().set(FUNC(namco_amc_device::txd)); + + config.set_maximum_quantum(attotime::from_hz(2 * 115200)); + + add_jvs_port(config); +} + +namespace { + +struct DSW { enum : uint8_t +{ + Interface = 0x08, +}; }; + +static INPUT_PORTS_START(namco_amc) + PORT_START("DSW") + PORT_DIPNAME(0x08, 0x08, "Interface") PORT_DIPLOCATION("SW1:4") + PORT_DIPSETTING(0x08, "JVS") + PORT_DIPSETTING(0x00, "RS232") + PORT_DIPNAME(0x04, 0x04, "Output Test") PORT_DIPLOCATION("SW1:3") + PORT_DIPSETTING(0x04, DEF_STR(Off)) + PORT_DIPSETTING(0x00, DEF_STR(On)) // interface must be set to JVS + PORT_DIPNAME(0x02, 0x00, "JVS Timeout") PORT_DIPLOCATION("SW1:2") // HACK: improve compatibility by setting default to Continue + PORT_DIPSETTING(0x02, "Stop") // outputs are cleared and board requires power cycling + PORT_DIPSETTING(0x00, "Continue") // outputs are cleared, but board still responds + PORT_DIPUNKNOWN_DIPLOC(0x01, 0x01, "SW1:1") +INPUT_PORTS_END + +static INPUT_PORTS_START(namco_amc_default) + PORT_INCLUDE(namco_amc) + + PORT_START("PLAYER1") + PORT_BIT(0x00000002, IP_ACTIVE_HIGH, IPT_BUTTON1) + PORT_BIT(0x00000001, IP_ACTIVE_HIGH, IPT_BUTTON2) + PORT_BIT(0x00008000, IP_ACTIVE_HIGH, IPT_BUTTON3) + PORT_BIT(0x00004000, IP_ACTIVE_HIGH, IPT_BUTTON4) + PORT_BIT(0x00002000, IP_ACTIVE_HIGH, IPT_BUTTON5) + PORT_BIT(0x00001000, IP_ACTIVE_HIGH, IPT_BUTTON6) + PORT_BIT(0x00000800, IP_ACTIVE_HIGH, IPT_BUTTON7) + PORT_BIT(0x00000400, IP_ACTIVE_HIGH, IPT_BUTTON8) + + PORT_START("ANALOG_INPUT1") + PORT_BIT(0xffff, 0x8000, IPT_PADDLE) PORT_MINMAX(0x0000, 0xffff) PORT_SENSITIVITY(100) PORT_KEYDELTA(2560) PORT_NAME("Analog Input 1") + + PORT_START("ANALOG_INPUT2") + PORT_BIT(0xffff, 0x8000, IPT_PADDLE) PORT_MINMAX(0x0000, 0xffff) PORT_SENSITIVITY(100) PORT_KEYDELTA(2560) PORT_NAME("Analog Input 2") + + PORT_START("ANALOG_INPUT3") + PORT_BIT(0xffff, 0x8000, IPT_PADDLE) PORT_MINMAX(0x0000, 0xffff) PORT_SENSITIVITY(100) PORT_KEYDELTA(2560) PORT_NAME("Analog Input 3") + + PORT_START("ANALOG_INPUT4") + PORT_BIT(0xffff, 0x8000, IPT_PADDLE) PORT_MINMAX(0x0000, 0xffff) PORT_SENSITIVITY(100) PORT_KEYDELTA(2560) PORT_NAME("Analog Input 4") + + PORT_START("CLEAR") + PORT_BIT(0x0001, IP_ACTIVE_LOW, IPT_BUTTON9) PORT_NAME("Clear Output") PORT_WRITE_LINE_MEMBER(FUNC(namco_amc_device::clear_output)) +INPUT_PORTS_END + +ROM_START( namco_amc ) + ROM_REGION( 0x020000, "iocpu", 0 ) + ROM_LOAD( "mg1prog0a.3a", 0x000000, 0x020000, CRC(b2b5be8f) SHA1(803652b7b8fde2196b7fb742ba8b9843e4fcd2de) ) +ROM_END + +} // anonymous namespace + +ioport_constructor namco_amc_device::device_input_ports() const +{ + return m_default_inputs ? INPUT_PORTS_NAME(namco_amc_default) : INPUT_PORTS_NAME(namco_amc); +} + +const tiny_rom_entry *namco_amc_device::device_rom_region() const +{ + return ROM_NAME(namco_amc); +} + +void namco_amc_device::device_start() +{ + save_item(NAME(m_analog_output)); + save_item(NAME(m_clear_output)); + save_item(NAME(m_output)); + save_item(NAME(m_ppg_duty)); + save_item(NAME(m_ppg_flags)); + save_item(NAME(m_sense_latch)); + save_item(NAME(m_unknown_output)); +} + +void namco_amc_device::rxd(int state) +{ + m_iocpu->uart<1>().sin(state); +} + +void namco_amc_device::input_txd(int state) +{ + m_iocpu->uart<0>().sin(state); +} + +void namco_amc_device::iocpu_program_map(address_map &map) +{ + map(0x0000c8, 0x0000c8).w(FUNC(namco_amc_device::analog_output_w<1>)); + map(0xfc0000, 0xfcffff).ram(); + map(0xfe0000, 0xffffff).rom().region("iocpu", 0); +} + +void namco_amc_device::update_analog_output0() +{ + analog_output_w<0>((BIT(m_ppg_flags, 0) ? 0 : m_ppg_duty) | (!BIT(m_ppg_flags, 1) << 6)); +} + +template +void namco_amc_device::analog_output_w(uint8_t data) +{ + if (m_analog_output[N] != data) + { + m_analog_output[N] = data; + LOGOUTPUT("analog_output_w %04x %04x\n", m_analog_output[0] * 0x101, m_analog_output[1] * 0x101); + m_analog_output_cb[N](data * 0x101); + } +} + +template +uint16_t namco_amc_device::adc_r() +{ + return analog_input_r(N, 0xffc0) >> 6; +} + +void namco_amc_device::clear_output(int state) +{ + m_clear_output = state; +} + +int namco_amc_device::unknown_output() +{ + return m_unknown_output; +} + + +namespace { + +static INPUT_PORTS_START(namco_c78_io) + PORT_START("DSW") + PORT_DIPNAME(0x08, 0x08, "DIP SW1") PORT_DIPLOCATION("SW2:1") + PORT_DIPSETTING(0x08, DEF_STR(Off)) + PORT_DIPSETTING(0x00, DEF_STR(On)) + PORT_DIPNAME(0x04, 0x04, "DIP SW2") PORT_DIPLOCATION("SW2:2") + PORT_DIPSETTING(0x04, DEF_STR(Off)) + PORT_DIPSETTING(0x00, DEF_STR(On)) + PORT_DIPNAME(0x02, 0x02, "Output Test") PORT_DIPLOCATION("SW2:3") + PORT_DIPSETTING(0x02, DEF_STR(Off)) + PORT_DIPSETTING(0x00, DEF_STR(On)) + PORT_DIPUNUSED_DIPLOC(0x01, 0x01, "SW2:4") +INPUT_PORTS_END + +class namco_c78_jvs_io_device : + public device_t, + public device_jvs_interface +{ +protected: + namco_c78_jvs_io_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) : + device_t(mconfig, type, tag, owner, clock), + device_jvs_interface(mconfig, *this), + m_iocpu(*this, "iocpu"), + m_dsw(*this, "DSW") + { + } + + // device_t + virtual void device_add_mconfig(machine_config &config) override ATTR_COLD + { + H83334(config, m_iocpu, 14.7456_MHz_XTAL); + m_iocpu->set_addrmap(AS_PROGRAM, &namco_c78_jvs_io_device::iocpu_program_map); + m_iocpu->write_port1().set_nop(); // unused + m_iocpu->write_port2().set_nop(); // unused + m_iocpu->write_port3().set_nop(); // unused + m_iocpu->read_port4().set(FUNC(namco_c78_jvs_io_device::iocpu_port_4_r)); + m_iocpu->write_port4().set(FUNC(namco_c78_jvs_io_device::iocpu_port_4_w)); + m_iocpu->read_port5().set(FUNC(namco_c78_jvs_io_device::iocpu_port_5_r)); + m_iocpu->write_port5().set(FUNC(namco_c78_jvs_io_device::iocpu_port_5_w)); + m_iocpu->read_port6().set(FUNC(namco_c78_jvs_io_device::iocpu_port_6_r)); + m_iocpu->write_port6().set(FUNC(namco_c78_jvs_io_device::iocpu_port_6_w)); + + m_iocpu->write_sci_tx<0>().set(FUNC(namco_c78_jvs_io_device::txd)); + + config.set_maximum_quantum(attotime::from_hz(2 * 115200)); + + add_jvs_port(config); + } + + virtual ioport_constructor device_input_ports() const override ATTR_COLD + { + return INPUT_PORTS_NAME(namco_c78_io); + } + + virtual void device_start() override ATTR_COLD + { + } + + // device_jvs_interface + virtual void rxd(int state) override + { + m_iocpu->sci_rx_w<0>(state); + } + + virtual void iocpu_program_map(address_map &map) ATTR_COLD + { + map(0x0000, 0x3fff).rom().region("iocpu", 0); + map(0xc000, 0xfb7f).ram(); + } + + uint8_t iocpu_port_4_r() + { + return (1 << 7) | // unknown input + (BIT(m_dsw->read(), 2, 2) << 5) | + ((m_jvs_sense != jvs_port_device::sense::None) << 4) | + ((m_jvs_sense != jvs_port_device::sense::Initialized) << 3) | + (1 << 2) | // sense + (3 << 0); // unknown output + } + + void iocpu_port_4_w(uint8_t data) + { + sense(BIT(data, 2) ? jvs_port_device::sense::Initialized : jvs_port_device::sense::Uninitialized); + // BIT(data, 1) // set at startup + } + + uint8_t iocpu_port_5_r() + { + return (31 << 3) | // unknown input + (1 << 2) | // rts + (1 << 1) | // unknown input + (1 << 0); // unknown output + } + + void iocpu_port_5_w(uint8_t data) + { + rts(BIT(data, 2)); + } + + uint8_t iocpu_port_6_r() + { + return (1 << 7) | // unknown input + (3 << 5) | // coin counters + (BIT(~player_r(0, 0x40), 6) << 4) | + (3 << 2) | // unknown output + (BIT(m_dsw->read(), 1) << 1) | // TODO: confirm DSW hookup + (1 << 0); // unused input + } + + void iocpu_port_6_w(uint8_t data) + { + machine().bookkeeping().coin_counter_w(0, BIT(data, 6)); + machine().bookkeeping().coin_counter_w(1, BIT(data, 5)); // except tssio/csz1/xmiu1 + // BIT(data, 3); // toggles (except asca1) + // BIT(data, 2); // toggles (except asca1) + } + + required_device m_iocpu; + required_ioport m_dsw; +}; + + +static INPUT_PORTS_START(namco_asca1) + PORT_INCLUDE(namco_c78_io) + + PORT_START("SYSTEM") + PORT_SERVICE(0x80, IP_ACTIVE_HIGH) + + PORT_START("PLAYER1") + PORT_BIT(0x00000040, IP_ACTIVE_HIGH, IPT_SERVICE1) + PORT_BIT(0x00000020, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP) + PORT_BIT(0x00000010, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN) + PORT_BIT(0x00000002, IP_ACTIVE_HIGH, IPT_BUTTON1) + PORT_BIT(0x00000001, IP_ACTIVE_HIGH, IPT_BUTTON2) + PORT_BIT(0x00008000, IP_ACTIVE_HIGH, IPT_BUTTON3) + PORT_BIT(0x00004000, IP_ACTIVE_HIGH, IPT_BUTTON4) + PORT_BIT(0x00002000, IP_ACTIVE_HIGH, IPT_BUTTON5) + PORT_BIT(0x00001000, IP_ACTIVE_HIGH, IPT_BUTTON6) + PORT_BIT(0x00000800, IP_ACTIVE_HIGH, IPT_BUTTON7) + PORT_BIT(0x00000400, IP_ACTIVE_HIGH, IPT_BUTTON8) + PORT_BIT(0x00000200, IP_ACTIVE_HIGH, IPT_BUTTON9) + PORT_BIT(0x00000100, IP_ACTIVE_HIGH, IPT_BUTTON10) + PORT_BIT(0x00800000, IP_ACTIVE_HIGH, IPT_BUTTON11) + PORT_BIT(0x00400000, IP_ACTIVE_HIGH, IPT_BUTTON12) + PORT_BIT(0x00200000, IP_ACTIVE_HIGH, IPT_BUTTON13) + + PORT_START("COIN1") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_COIN1) + + PORT_START("COIN2") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_COIN2) + + PORT_START("ANALOG_INPUT1") + PORT_BIT(0xffff, 0x8000, IPT_PADDLE) PORT_MINMAX(0x0000, 0xffff) PORT_SENSITIVITY(100) PORT_KEYDELTA(2560) PORT_NAME("Analog Input 1") + + PORT_START("ANALOG_INPUT2") + PORT_BIT(0xffff, 0x8000, IPT_PADDLE) PORT_MINMAX(0x0000, 0xffff) PORT_SENSITIVITY(100) PORT_KEYDELTA(2560) PORT_NAME("Analog Input 2") + + PORT_START("ANALOG_INPUT3") + PORT_BIT(0xffff, 0x8000, IPT_PADDLE) PORT_MINMAX(0x0000, 0xffff) PORT_SENSITIVITY(100) PORT_KEYDELTA(2560) PORT_NAME("Analog Input 3") + + PORT_START("ANALOG_INPUT4") + PORT_BIT(0xffff, 0x8000, IPT_PADDLE) PORT_MINMAX(0x0000, 0xffff) PORT_SENSITIVITY(100) PORT_KEYDELTA(2560) PORT_NAME("Analog Input 4") + + PORT_START("ANALOG_INPUT5") + PORT_BIT(0xffff, 0x8000, IPT_PADDLE) PORT_MINMAX(0x0000, 0xffff) PORT_SENSITIVITY(100) PORT_KEYDELTA(2560) PORT_NAME("Analog Input 5") + + PORT_START("ANALOG_INPUT6") + PORT_BIT(0xffff, 0x8000, IPT_PADDLE) PORT_MINMAX(0x0000, 0xffff) PORT_SENSITIVITY(100) PORT_KEYDELTA(2560) PORT_NAME("Analog Input 6") + + PORT_START("ANALOG_INPUT7") + PORT_BIT(0xffff, 0x8000, IPT_PADDLE) PORT_MINMAX(0x0000, 0xffff) PORT_SENSITIVITY(100) PORT_KEYDELTA(2560) PORT_NAME("Analog Input 7") + + PORT_START("ANALOG_INPUT8") + PORT_BIT(0xffff, 0x8000, IPT_PADDLE) PORT_MINMAX(0x0000, 0xffff) PORT_SENSITIVITY(100) PORT_KEYDELTA(2560) PORT_NAME("Analog Input 8") +INPUT_PORTS_END + +ROM_START( namco_asca1 ) + ROM_REGION( 0x040000, "iocpu", 0 ) + ROM_LOAD( "asc1_io-a.ic13", 0x000000, 0x040000, CRC(77cdf69a) SHA1(497af1059f85c07bea2dd0d303481623f6019dcf) ) +ROM_END + +class namco_asca_1_device : + public namco_c78_jvs_io_device +{ +public: + namco_asca_1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0) : + namco_asca_1_device(mconfig, NAMCO_ASCA1, tag, owner, clock) + { + } + +protected: + namco_asca_1_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) : + namco_c78_jvs_io_device(mconfig, type, tag, owner, clock), + m_output(0) + { + } + + // device_t + virtual ioport_constructor device_input_ports() const override ATTR_COLD + { + return m_default_inputs ? INPUT_PORTS_NAME(namco_asca1) : namco_c78_jvs_io_device::device_input_ports(); + } + + virtual void device_add_mconfig(machine_config &config) override ATTR_COLD + { + namco_c78_jvs_io_device::device_add_mconfig(config); + + m_iocpu->read_port8().set(FUNC(namco_asca_1_device::iocpu_port_8_r)); + m_iocpu->write_port8().set(FUNC(namco_asca_1_device::iocpu_port_8_w)); + m_iocpu->read_port9().set(FUNC(namco_asca_1_device::iocpu_port_9_r)); + m_iocpu->write_port9().set(FUNC(namco_asca_1_device::iocpu_port_9_w)); + + m_iocpu->read_adc<0>().set(FUNC(namco_asca_1_device::adc_r<0>)); + m_iocpu->read_adc<1>().set(FUNC(namco_asca_1_device::adc_r<1>)); + m_iocpu->read_adc<2>().set(FUNC(namco_asca_1_device::adc_r<2>)); + m_iocpu->read_adc<3>().set(FUNC(namco_asca_1_device::adc_r<3>)); + m_iocpu->read_adc<4>().set(FUNC(namco_asca_1_device::adc_r<4>)); + m_iocpu->read_adc<5>().set(FUNC(namco_asca_1_device::adc_r<5>)); + m_iocpu->read_adc<6>().set(FUNC(namco_asca_1_device::adc_r<6>)); + m_iocpu->read_adc<7>().set(FUNC(namco_asca_1_device::adc_r<7>)); + } + + virtual const tiny_rom_entry *device_rom_region() const override ATTR_COLD + { + return ROM_NAME(namco_asca1); + } + + virtual void device_start() override ATTR_COLD + { + namco_c78_jvs_io_device::device_start(); + + save_item(NAME(m_output)); + } + + // namco_c78_jvs_io_device + virtual void iocpu_program_map(address_map &map) override + { + namco_c78_jvs_io_device::iocpu_program_map(map); + + map(0x6000, 0x6003).r(FUNC(namco_asca_1_device::in_r)); + map(0x6004, 0x6005).w(FUNC(namco_asca_1_device::output_w)); + } + + uint8_t iocpu_port_8_r() + { + return (1 << 7) | // unknown output + (3 << 5) | // unknown input + (31 << 0); // unknown output + } + + void iocpu_port_8_w(uint8_t data) + { + // BIT(data, 6) // set at startup, is set to input? + } + + uint8_t iocpu_port_9_r() + { + return (3 << 6) | // unknown input + (31 << 1) | // unknown output + (1 << 0); // unknown input + } + + void iocpu_port_9_w(uint8_t data) + { + } + + uint8_t in_r(offs_t offset) + { + if (offset == 0) + { + const auto system = system_r(0x80); + const auto p1 = player_r(0, 0xe033); + + return ~((BIT(p1, 13) << 7) | + (BIT(p1, 14) << 6) | + (BIT(p1, 15) << 5) | + (BIT(p1, 0) << 4) | + (BIT(p1, 1) << 3) | + (BIT(p1, 4) << 2) | + (BIT(p1, 5) << 1) | + (BIT(system, 7) << 0)); + } + else if (offset == 1) + { + const auto p1 = player_r(0, 0xe00300); + + return ~((BIT(p1, 21) << 4) | + (BIT(p1, 22) << 3) | + (BIT(p1, 23) << 2) | + (BIT(p1, 8) << 1) | + (BIT(p1, 9) << 0)); + } + else if (offset == 2) + { + const auto p1 = player_r(0, 0x1c00); + const auto c1 = coin_r(0, 0x01); + + return ~((BIT(c1, 0) << 3) | + (BIT(p1, 10) << 2) | + (BIT(p1, 11) << 1) | + (BIT(p1, 12) << 0)); + } + else if (offset == 3) + { + const auto c1 = coin_r(0, 0x80); + const auto c2 = coin_r(1, 0x81); + + return ~((BIT(c2, 0) << 3) | + (BIT(~c2, 7) << 1) | // not asca1 + (BIT(~c1, 7) << 0)); // not asca1 + } + return 0xff; + } + + template uint16_t adc_r() + { + return analog_input_r(N, 0xffc0) >> 6; + } + + virtual void output_w(offs_t offset, uint8_t data) + { + uint16_t output = ((m_output & ~(0xff << (offset * 8))) | bitswap<8>(data, 0, 1, 2, 3, 4, 5, 6, 7) << (offset * 8)) & 0xf8ff; + + if (m_output != output) + { + LOGOUTPUT("output_w %04x\n", output); + m_output_cb(0, output, output ^ m_output); + m_output = output; + } + } + + uint64_t m_output; +}; + + +static INPUT_PORTS_START(namco_asca3) + PORT_INCLUDE(namco_asca1) + + PORT_MODIFY("COIN1") + PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_TILT2) PORT_NAME("Counter 1 disconnected") + + PORT_MODIFY("COIN2") + PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_TILT3) PORT_NAME("Counter 2 disconnected") + + PORT_START("ROTARY_INPUT1") + PORT_BIT(0xff, 0, IPT_MOUSE_X) PORT_SENSITIVITY(15) PORT_KEYDELTA(8) PORT_NAME("Rotary Input 1") + + PORT_START("ROTARY_INPUT2") + PORT_BIT(0xff, 0, IPT_MOUSE_Y) PORT_SENSITIVITY(15) PORT_KEYDELTA(8) PORT_REVERSE PORT_NAME("Rotary Input 2") +INPUT_PORTS_END + +ROM_START( namco_asca3 ) + ROM_REGION( 0x040000, "iocpu", 0 ) + ROM_LOAD( "asc3_io-c.ic14", 0x000000, 0x020000, CRC(2f272a7b) SHA1(9d7ebe274c0d26f5f38747224d42d0375e2ed14c) ) +ROM_END + +class namco_asca_3_device : + public namco_asca_1_device +{ +public: + namco_asca_3_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0) : + namco_asca_3_device(mconfig, NAMCO_ASCA3, tag, owner, clock) + { + } + +protected: + namco_asca_3_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) : + namco_asca_1_device(mconfig, type, tag, owner, clock), + m_rotary_prev{} + { + } + + // device_t + virtual ioport_constructor device_input_ports() const override ATTR_COLD + { + return m_default_inputs ? INPUT_PORTS_NAME(namco_asca3) : namco_c78_jvs_io_device::device_input_ports(); + } + + virtual const tiny_rom_entry *device_rom_region() const override ATTR_COLD + { + return ROM_NAME(namco_asca3); + } + + virtual void device_start() override ATTR_COLD + { + m_analog_output_timer = timer_alloc(FUNC(namco_asca_3_device::analog_output_timer_callback), this); + + namco_asca_1_device::device_start(); + + save_item(NAME(m_analog_output)); + save_item(NAME(m_analog_output_cycles)); + save_item(NAME(m_analog_output_state)); + save_item(NAME(m_rotary_prev)); + } + + // namco_c78_jvs_io_device + virtual void iocpu_program_map(address_map &map) override + { + namco_asca_1_device::iocpu_program_map(map); + + map(0x6006, 0x6007).r(FUNC(namco_asca_3_device::rotary_diff_r)); + } + + virtual void output_w(offs_t offset, uint8_t data) override + { + if (offset == 1) + { + namco_asca_1_device::output_w(offset, data & ~(1 << 4)); + + int analog_output_state = BIT(data, 4); + if (analog_output_state != m_analog_output_state) + { + if (analog_output_state) + { + uint64_t high = m_analog_output_cycles[0] - m_analog_output_cycles[1]; + uint64_t low = m_iocpu->total_cycles() - m_analog_output_cycles[0]; + update_analog_output((high ? (0xff * high) / (high + low) : 0x0000) * 0x101); + } + + m_analog_output_cycles[analog_output_state] = m_iocpu->total_cycles(); + m_analog_output_timer->adjust(attotime::from_hz(18)); + m_analog_output_state = analog_output_state; + } + } + else + namco_asca_1_device::output_w(offset, data); + } + + TIMER_CALLBACK_MEMBER(analog_output_timer_callback) + { + update_analog_output(m_analog_output_state ? 0xffff : 0x0000); + } + + void update_analog_output(uint16_t data) + { + if (m_analog_output != data) + { + m_analog_output = data; + LOGOUTPUT("analog_output_w %04x\n", data); + m_analog_output_cb[0](data); + } + } + + virtual uint8_t rotary_diff_r(offs_t offset) + { + uint8_t data = rotary_input_r(offset) - m_rotary_prev[offset]; + m_rotary_prev[offset] += data; + return data; + } + + emu_timer *m_analog_output_timer; + uint16_t m_analog_output; + uint64_t m_analog_output_cycles[2]; + uint8_t m_analog_output_state; + uint8_t m_rotary_prev[2]; +}; + + +ROM_START( namco_asca3a ) + ROM_REGION( 0x040000, "iocpu", 0 ) + ROM_LOAD( "asca-3a.ic14", 0x000000, 0x040000, CRC(8e9266e5) SHA1(ffa8782ca641d71d57df23ed1c5911db05d3df97) ) +ROM_END + +class namco_asca_3a_device : + public namco_asca_3_device +{ +public: + namco_asca_3a_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0) : + namco_asca_3_device(mconfig, NAMCO_ASCA3A, tag, owner, clock) + { + } + +protected: + // device_t + virtual const tiny_rom_entry *device_rom_region() const override ATTR_COLD + { + return ROM_NAME(namco_asca3a); + } +}; + + +ROM_START( namco_asca5 ) + ROM_REGION( 0x040000, "iocpu", 0 ) + ROM_LOAD( "asc5_io-a.ic14", 0x000000, 0x020000, CRC(5964767f) SHA1(320db5e78ae23c5f94e368432d51573b409995db) ) +ROM_END + +class namco_asca_5_device : + public namco_asca_3_device +{ +public: + namco_asca_5_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0) : + namco_asca_3_device(mconfig, NAMCO_ASCA5, tag, owner, clock) + { + } + +protected: + // device_t + virtual const tiny_rom_entry *device_rom_region() const override ATTR_COLD + { + return ROM_NAME(namco_asca5); + } +}; + + +ROM_START( namco_emio102 ) + ROM_REGION( 0x040000, "iocpu", 0 ) + ROM_LOAD( "th1io-a.4f", 0x000000, 0x040000, CRC(1cbbce27) SHA1(71d61d9218543e1b0b2a6c550a8ff2b7c6267257) ) +ROM_END + +class namco_em_io1_02_device : + public namco_asca_1_device +{ +public: + namco_em_io1_02_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0) : + namco_asca_1_device(mconfig, NAMCO_EMIO102, tag, owner, clock) + { + } + +protected: + // device_t + virtual const tiny_rom_entry *device_rom_region() const override ATTR_COLD + { + return ROM_NAME(namco_emio102); + } + + virtual void device_start() override ATTR_COLD + { + namco_c78_jvs_io_device::device_start(); + + save_item(NAME(m_multiplexed_output)); + } + + virtual void output_w(offs_t offset, uint8_t data) override + { + if (m_multiplexed_output[offset] != data) + { + m_multiplexed_output[offset] = data; + + if (m_multiplexed_output[1] < 3) + { + int shift = m_multiplexed_output[1] == 2 ? 16 : + m_multiplexed_output[1] == 0 ? 8 : 0; + + uint64_t output = (m_output & ~(0xff << shift)) | (m_multiplexed_output[0] << shift); + + if (m_output != output) + { + LOGOUTPUT("output_w %06x\n", output); + m_output_cb(0, output, output ^ m_output); + m_output = output; + } + } + } + } + + uint8_t m_multiplexed_output[2]; +}; + + +static INPUT_PORTS_START(namco_tssio) + PORT_INCLUDE(namco_c78_io) + + PORT_START("SYSTEM") + PORT_SERVICE(0x80, IP_ACTIVE_HIGH) + + PORT_START("PLAYER1") + PORT_BIT(0x00000040, IP_ACTIVE_HIGH, IPT_SERVICE1) + PORT_BIT(0x00000020, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP) + PORT_BIT(0x00000010, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN) + PORT_BIT(0x00000002, IP_ACTIVE_HIGH, IPT_BUTTON1) + PORT_BIT(0x00000001, IP_ACTIVE_HIGH, IPT_BUTTON2) + PORT_BIT(0x00008000, IP_ACTIVE_HIGH, IPT_BUTTON3) + PORT_BIT(0x00004000, IP_ACTIVE_HIGH, IPT_BUTTON4) + PORT_BIT(0x00002000, IP_ACTIVE_HIGH, IPT_BUTTON5) + PORT_BIT(0x00001000, IP_ACTIVE_HIGH, IPT_BUTTON6) + + PORT_START("COIN1") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_COIN1) + PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_TILT2) PORT_NAME("Counter disconnected") + + PORT_START("SCREEN_POSITION_INPUT_X1") // tuned for CRT + PORT_BIT(0xfff, 91 + 733 / 2, IPT_LIGHTGUN_X) PORT_CROSSHAIR(X, 1.0, 0.0, 0) PORT_MINMAX(91, 91 + 733) PORT_SENSITIVITY(100) PORT_KEYDELTA(12) + + PORT_START("SCREEN_POSITION_INPUT_Y1") // tuned for CRT - can't shoot below the statusbar? + PORT_BIT(0xfff, 38 + 247 / 2, IPT_LIGHTGUN_Y) PORT_CROSSHAIR(Y, 1.0, 0.0, 0) PORT_MINMAX(38, 38 + 247) PORT_SENSITIVITY(100) PORT_KEYDELTA(4) +INPUT_PORTS_END + +ROM_START( namco_tssio ) + ROM_REGION( 0x040000, "iocpu", 0 ) + ROM_LOAD( "tssioprog.ic3", 0x000000, 0x040000, CRC(edad4538) SHA1(1330189184a636328d956c0e435f8d9ad2e96a80) ) +ROM_END + +class namco_tss_io_device : + public namco_c78_jvs_io_device +{ +public: + namco_tss_io_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0) : + namco_tss_io_device(mconfig, NAMCO_TSSIO, tag, owner, clock) + { + } + +protected: + namco_tss_io_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock = 0) : + namco_c78_jvs_io_device(mconfig, type, tag, owner, clock), + m_output(0) + { + } + + // device_t + virtual void device_add_mconfig(machine_config &config) override ATTR_COLD + { + namco_c78_jvs_io_device::device_add_mconfig(config); + + m_iocpu->read_port8().set(FUNC(namco_tss_io_device::iocpu_port_8_r)); + m_iocpu->write_port8().set(FUNC(namco_tss_io_device::iocpu_port_8_w)); + m_iocpu->read_port9().set(FUNC(namco_tss_io_device::iocpu_port_9_r)); + m_iocpu->write_port9().set(FUNC(namco_tss_io_device::iocpu_port_9_w)); + } + + virtual ioport_constructor device_input_ports() const override ATTR_COLD + { + return m_default_inputs ? INPUT_PORTS_NAME(namco_tssio) : namco_c78_jvs_io_device::device_input_ports(); + } + + virtual const tiny_rom_entry *device_rom_region() const override ATTR_COLD + { + return ROM_NAME(namco_tssio); + } + + virtual void device_start() override ATTR_COLD + { + namco_c78_jvs_io_device::device_start(); + + save_item(NAME(m_output)); + } + + // namco_c78_jvs_io_device + virtual void iocpu_program_map(address_map &map) override + { + namco_c78_jvs_io_device::iocpu_program_map(map); + + map(0x6000, 0x6001).r(FUNC(namco_tss_io_device::in_r)); + map(0x6002, 0x6002).w(FUNC(namco_tss_io_device::output_w)); + map(0x7000, 0x7005).r(FUNC(namco_tss_io_device::gun_r)); + map(0x7007, 0x7007).r(FUNC(namco_tss_io_device::gun_ack_r)); // guessed, result ignored + } + + uint8_t iocpu_port_8_r() + { + return (1 << 7) | // unknown output + (3 << 5) | // unknown input + (1 << 4) | // unknown output + (15 << 0); // unknown input + } + + void iocpu_port_8_w(uint8_t data) + { + } + + uint8_t iocpu_port_9_r() + { + return (1 << 7) | // unknown input + (15 << 3) | // unknown output + (7 << 0); // unknown input + } + + void iocpu_port_9_w(uint8_t data) + { + } + + uint8_t gun_r(offs_t offset) + { + uint16_t data = (offset % 3) == 0 ? screen_position_x_r(0) : + (offset % 3) == 1 ? screen_position_y_r(0) : // ystart + screen_position_y_r(0) + 1;// yend + return (offset < 3) ? data & 0xff : data >> 8; + } + + uint8_t gun_ack_r() + { + return 0x00; + } + + uint8_t in_r(offs_t offset) + { + if (offset == 0) + { + const auto system = system_r(0x80); + const auto p1 = player_r(0, 0x32); + const auto c1 = coin_r(0, 0x81); + + return ~((BIT(p1, 1) << 7) | + (BIT(p1, 4) << 6) | + (BIT(p1, 5) << 5) | + (BIT(system, 7) << 4) | + (0 << 3) | // unknown input + (BIT(~c1, 7) << 2) | + (0 << 1) | // unknown input + (BIT(c1, 0) << 0)); + } + else if (offset == 1) + { + const auto p1 = player_r(0, 0xf001); + + return ~((BIT(p1, 12) << 4) | + (BIT(p1, 13) << 3) | + (BIT(p1, 14) << 2) | + (BIT(p1, 15) << 1) | + (BIT(p1, 0) << 0)); + } + + return 0xff; + } + + void output_w(uint8_t data) + { + data = bitswap<3>(data, 0, 1, 2) << 5; + if (m_output != data) + { + LOGOUTPUT("output_w %02x\n", data); + m_output_cb(0, data, data ^ m_output); + m_output = data; + } + } + + uint8_t m_output; +}; + + +ROM_START( namco_csz1 ) + ROM_REGION( 0x040000, "iocpu", 0 ) + ROM_LOAD( "csz1prg0a.8f", 0x000000, 0x020000, CRC(8edc36b3) SHA1(b5df211988d856572fcc313480e693c8561784e4) ) +ROM_END + +class namco_csz1_device : + public namco_tss_io_device +{ +public: + namco_csz1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0) : + namco_tss_io_device(mconfig, NAMCO_CSZ1, tag, owner, clock) + { + } + +protected: + // device_t + virtual const tiny_rom_entry *device_rom_region() const override ATTR_COLD + { + return ROM_NAME(namco_csz1); + } + + virtual void device_start() override ATTR_COLD + { + namco_tss_io_device::device_start(); + + m_analog_output = 0; + + save_item(NAME(m_analog_output)); + } + + // namco_c78_jvs_io_device + virtual void iocpu_program_map(address_map &map) override + { + namco_tss_io_device::iocpu_program_map(map); + + map(0x6003, 0x6003).w(FUNC(namco_csz1_device::analog_output_w)); + } + + void analog_output_w(uint8_t data) + { + if (m_analog_output != data) + { + m_analog_output = data; + LOGOUTPUT("analog_output_w %04x\n", data * 0x101); + m_analog_output_cb[0](data * 0x101); + } + } + + uint8_t m_analog_output; +}; + + +ROM_START( namco_xmiu1 ) + ROM_REGION( 0x040000, "iocpu", 0 ) + ROM_LOAD( "csz1prg0a.8f", 0x000000, 0x040000, CRC(bb112fe0) SHA1(6fa5dc81d258137c1b1ad427d49d136d0bbf53fa) ) +ROM_END + +class namco_xmiu1_device : + public namco_tss_io_device +{ +public: + namco_xmiu1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0) : + namco_tss_io_device(mconfig, NAMCO_XMIU1, tag, owner, clock) + { + } + +protected: + // device_t + virtual const tiny_rom_entry *device_rom_region() const override ATTR_COLD + { + return ROM_NAME(namco_xmiu1); + } +}; + + +ROM_START( namco_fca11 ) + ROM_REGION( 0x040000, "iocpu2", 0 ) // 256KB internal flash ROM + ROM_LOAD( "fcaf11.ic4", 0x030000, 0x010000, CRC(13d936df) SHA1(fbb2191263b2b326f1f49729767ee6fae2db21f7) ) // almost good dump, all JVS related code and data is in place + ROM_FILL( 0x000000, 0x034000, 0x67 ) // dump was made from $0000 to $ffff, not $fc0000. The ROM only appears in memory from $4000-$ffff + + ROM_REGION( 0x040000, "iocpu", 0 ) + ROM_LOAD( "asc3_io-c.ic14", 0x000000, 0x020000, CRC(2f272a7b) SHA1(9d7ebe274c0d26f5f38747224d42d0375e2ed14c) ) + ROM_COPY( "iocpu2", 0x039040, 0x001082, 0x00003b ) // patch ASCA3 ROM to report FCA11 description + + ROM_REGION( 0x10000, "pic", 0 ) // I/O board PIC16F84 code + ROM_LOAD( "fcap11.ic2", 0x000000, 0x004010, CRC(1b2592ce) SHA1(a1a487361053af564f6ec67e545413e370a3b38c) ) +ROM_END + +class namco_fca_11_device : + public namco_asca_3_device +{ +public: + namco_fca_11_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0) : + namco_fca_11_device(mconfig, NAMCO_FCA11, tag, owner, clock) + { + } + +protected: + namco_fca_11_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) : + namco_asca_3_device(mconfig, type, tag, owner, clock), + m_iocpu2(*this, "iocpu2") + { + } + + // device_t + virtual void device_add_mconfig(machine_config &config) override ATTR_COLD + { + namco_asca_3_device::device_add_mconfig(config); + + MB90F574(config, m_iocpu2, 4.9152_MHz_XTAL); + m_iocpu2->set_addrmap(AS_PROGRAM, &namco_fca_11_device::iocpu2_program_map); + } + + virtual const tiny_rom_entry *device_rom_region() const override ATTR_COLD + { + return ROM_NAME(namco_fca11); + } + + virtual void device_reset() override ATTR_COLD + { + namco_asca_3_device::device_reset(); + + m_iocpu2->set_input_line(INPUT_LINE_RESET, ASSERT_LINE); + } + + // device_jvs_interface + virtual void rxd(int state) override + { + namco_asca_3_device::rxd(state); + + m_iocpu2->uart<1>().sin(state); + } + + void iocpu2_program_map(address_map &map) + { + map(0x004000, 0x00ffff).rom().region("iocpu2", 0x034000); + map(0xfc0000, 0xffffff).rom().region("iocpu2", 0); + } + + required_device m_iocpu2; +}; + + +ROM_START( namco_fca10 ) + ROM_REGION( 0x040000, "iocpu2", ROMREGION_ERASE00 ) // 256KB internal flash ROM + ROM_LOAD( "fcaf10.bin", 0x000000, 0x040000, NO_DUMP ) + + ROM_REGION( 0x040000, "iocpu", 0 ) + ROM_LOAD( "asc3_io-c.ic14", 0x000000, 0x020000, CRC(2f272a7b) SHA1(9d7ebe274c0d26f5f38747224d42d0375e2ed14c) ) + + ROM_REGION( 0x10000, "pic", 0 ) // I/O board PIC16F84 code + ROM_LOAD( "fcap10.ic2", 0x000000, 0x004010, NO_DUMP ) +ROM_END + +class namco_fca_10_device : + public namco_fca_11_device +{ +public: + namco_fca_10_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0) : + namco_fca_11_device(mconfig, NAMCO_FCA10, tag, owner, clock) + { + } + +protected: + // device_t + virtual const tiny_rom_entry *device_rom_region() const override ATTR_COLD + { + return ROM_NAME(namco_fca10); + } + + virtual void device_start() override ATTR_COLD + { + namco_fca_11_device::device_start(); + + // patch ASCA3 ROM to report FCA10 description + auto iocpu = memregion("iocpu")->base(); + for (int i = 0; i < 0x30; i++) + iocpu[BYTE_XOR_BE(i + 0x108d)] = "FCA-1;Ver1.00;JPN,Multipurpose + Rotary Encoder"[i]; + } +}; + + +ROM_START( namco_fcb ) + ROM_REGION( 0x040000, "iocpu2", 0 ) // 256KB internal flash ROM + ROM_LOAD( "fcb1_io-0b.ic4", 0x034000, 0x00c000, BAD_DUMP CRC(5e25b73f) SHA1(fa805a422ff8793989b0ce901cc868ec1a87c7ac) ) // most JVS handling code is in undumped area + ROM_FILL( 0x000000, 0x034000, 0x67 ) // dump was made from $0000 to $ffff, not $fc0000. The ROM only appears in memory from $4000-$ffff + + ROM_REGION( 0x040000, "iocpu", 0 ) + ROM_LOAD( "asc3_io-c.ic14", 0x000000, 0x020000, CRC(2f272a7b) SHA1(9d7ebe274c0d26f5f38747224d42d0375e2ed14c) ) + ROM_COPY( "iocpu2", 0x03436a, 0x001082, 0x00003b ) // patch ASCA3 ROM to report FCB description + + ROM_REGION( 0x10000, "pic", 0 ) // I/O board PIC16F84 code + ROM_LOAD( "fcb_pic", 0x000000, 0x004010, NO_DUMP ) +ROM_END + +class namco_fcb_device : + public namco_fca_11_device +{ +public: + namco_fcb_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0) : + namco_fca_11_device(mconfig, NAMCO_FCB, tag, owner, clock) + { + } + +protected: + // device_t + virtual const tiny_rom_entry *device_rom_region() const override ATTR_COLD + { + return ROM_NAME(namco_fcb); + } +}; + + +class namco_em_pri1_01_device : + public jvs_hle_device +{ +public: + namco_em_pri1_01_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0) : + jvs_hle_device(mconfig, NAMCO_EMPRI101, tag, owner, clock) + { + } + + // device_t + static constexpr feature_type imperfect_features() { return feature::PRINTER; } + + virtual void device_add_mconfig(machine_config &config) override ATTR_COLD + { + add_jvs_port(config); + } + + // jvs_hle_device + virtual const char *device_id() override + { + return "namco ltd.;EM Pri1-01;Ver2.00;JPN&EXP,Techno-Drive PRN"; + } + + virtual void execute(uint8_t command) override + { + const uint8_t *parameters; + uint8_t *response; + + switch (command) + { + case 0x72: + if (consume(1, parameters)) + { + switch (parameters[0]) + { + case 0x01: // initialise? + if (produce(1, response)) + response[0] = ReportCode::Normal; + break; + + case 0x02: // end transmit? + if (produce(1, response)) + response[0] = ReportCode::Normal; + break; + + case 0x03: // get status + if (produce(2, response)) + { + response[0] = ReportCode::Normal; + response[1] = 0x01; // 1=ok/2=busy/4=paper empty + } + break; + + case 0x04: // begin transmit? + if (produce(1, response)) + response[0] = ReportCode::Normal; + break; + + case 0x05: // end of print job? + if (consume(1, parameters) && produce(1, response)) + response[0] = (parameters[0] == 1) ? ReportCode::Normal : ReportCode::InvalidParameter; + break; + + case 0x07: // transmit data + if (consume(1, parameters)) + { + uint8_t length = parameters[0]; + + if (consume(length, parameters) && produce(1, response)) + response[0] = ReportCode::Normal; + } + break; + + default: + status_code(StatusCode::UnknownCommand); + break; + } + } + break; + + default: + jvs_hle_device::execute(command); + break; + } + } +}; + +} // anonymous namespace + + +DEFINE_DEVICE_TYPE(NAMCO_AMC, namco_amc_device, "namco_amc", "Namco AMC PCB (Extra I/O,JPN,Ver1.10)") +DEFINE_DEVICE_TYPE_PRIVATE(NAMCO_ASCA1, device_jvs_interface, namco_asca_1_device, "namco_asca1", "Namco ASCA-1 (Multipurpose I/O,JPN,Ver2.00)") +DEFINE_DEVICE_TYPE_PRIVATE(NAMCO_ASCA3, device_jvs_interface, namco_asca_3_device, "namco_asca3", "Namco ASCA-3 (Multipurpose + Rotary Encoder,JPN,Ver2.04)") +DEFINE_DEVICE_TYPE_PRIVATE(NAMCO_ASCA3A, device_jvs_interface, namco_asca_3a_device, "namco_asca3a", "Namco ASCA-3 (Multipurpose + Rotary Encoder,JPN,Ver2.02)") +DEFINE_DEVICE_TYPE_PRIVATE(NAMCO_ASCA5, device_jvs_interface, namco_asca_5_device, "namco_asca5", "Namco ASCA-5 (Multipurpose,JPN,Ver2.09)") +DEFINE_DEVICE_TYPE_PRIVATE(NAMCO_CSZ1, device_jvs_interface, namco_csz1_device, "namco_csz1", "Namco CSZ1 MIU-I/O (GUN-EXTENTION,JPN,Ver2.05)") +DEFINE_DEVICE_TYPE_PRIVATE(NAMCO_EMIO102, device_jvs_interface, namco_em_io1_02_device, "namco_emio102", "Namco EM I/O1-02 (Techno-Drive I/O,JPN&EXP,Ver2.00)") +DEFINE_DEVICE_TYPE_PRIVATE(NAMCO_EMPRI101, device_jvs_interface, namco_em_pri1_01_device, "namco_empri101", "Namco EM Pri1-01") +DEFINE_DEVICE_TYPE_PRIVATE(NAMCO_FCA10, device_jvs_interface, namco_fca_10_device, "namco_fca10", "Namco FCA-1 (Multipurpose + Rotary Encoder,JPN,Ver1.00)") +DEFINE_DEVICE_TYPE_PRIVATE(NAMCO_FCA11, device_jvs_interface, namco_fca_11_device, "namco_fca11", "Namco FCA-1 (Multipurpose + Rotary Encoder,JPN,Ver1.01)") +DEFINE_DEVICE_TYPE_PRIVATE(NAMCO_FCB, device_jvs_interface, namco_fcb_device, "namco_fcb", "Namco FCB (TouchPanel&Multipurpose,JPN,Ver1.02)") +DEFINE_DEVICE_TYPE_PRIVATE(NAMCO_TSSIO, device_jvs_interface, namco_tss_io_device, "namco_tssio", "Namco TSS-I/O (GUN-EXTENTION,JPN,Ver2.02)") +DEFINE_DEVICE_TYPE_PRIVATE(NAMCO_XMIU1, device_jvs_interface, namco_xmiu1_device, "namco_xmiu1", "Namco XMIU1 TSS-I/O (GUN-EXTENTION,JPN,Ver2.11,Ver2.12)") diff --git a/src/devices/bus/jvs/namcoio.h b/src/devices/bus/jvs/namcoio.h new file mode 100644 index 00000000000..c3d38ff8bb1 --- /dev/null +++ b/src/devices/bus/jvs/namcoio.h @@ -0,0 +1,73 @@ +// license:BSD-3-Clause +// copyright-holders:smf + +#ifndef MAME_BUS_JVS_NAMCOIO_H +#define MAME_BUS_JVS_NAMCOIO_H + +#pragma once + +#include "jvs.h" +#include "bus/rs232/rs232.h" +#include "cpu/f2mc16/mb90610a.h" +#include "cpu/h8/h83337.h" + +class namco_amc_device : + public device_t, + public device_jvs_interface, + public device_rs232_port_interface +{ +public: + namco_amc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0); + + void clear_output(int state); + int unknown_output(); + + static constexpr DEVICE_INPUT_DEFAULTS_START(dsw_rs232) + DEVICE_INPUT_DEFAULTS("DSW", 0x08, 0x00) + DEVICE_INPUT_DEFAULTS_END + +protected: + // device_t + virtual void device_add_mconfig(machine_config &config) override ATTR_COLD; + virtual ioport_constructor device_input_ports() const override ATTR_COLD; + virtual const tiny_rom_entry *device_rom_region() const override ATTR_COLD; + virtual void device_start() override ATTR_COLD; + + // device_jvs_interface + virtual void rxd(int state) override; + + // device_rs232_port_interface + virtual void input_txd(int state) override; + + virtual void iocpu_program_map(address_map &map); + + template uint16_t adc_r(); + void update_analog_output0(); + template void analog_output_w(uint8_t data); + + required_device m_iocpu; + std::array m_analog_output; + uint8_t m_clear_output; + uint8_t m_output; + uint8_t m_ppg_duty; + uint8_t m_ppg_flags; + uint8_t m_sense_latch; + uint8_t m_unknown_output; +}; + + +DECLARE_DEVICE_TYPE(NAMCO_AMC, namco_amc_device) +DECLARE_DEVICE_TYPE(NAMCO_ASCA1, device_jvs_interface) +DECLARE_DEVICE_TYPE(NAMCO_ASCA3, device_jvs_interface) +DECLARE_DEVICE_TYPE(NAMCO_ASCA3A, device_jvs_interface) +DECLARE_DEVICE_TYPE(NAMCO_ASCA5, device_jvs_interface) +DECLARE_DEVICE_TYPE(NAMCO_CSZ1, device_jvs_interface) +DECLARE_DEVICE_TYPE(NAMCO_EMIO102, device_jvs_interface) +DECLARE_DEVICE_TYPE(NAMCO_EMPRI101, device_jvs_interface) +DECLARE_DEVICE_TYPE(NAMCO_FCA10, device_jvs_interface) +DECLARE_DEVICE_TYPE(NAMCO_FCA11, device_jvs_interface) +DECLARE_DEVICE_TYPE(NAMCO_FCB, device_jvs_interface) +DECLARE_DEVICE_TYPE(NAMCO_TSSIO, device_jvs_interface) +DECLARE_DEVICE_TYPE(NAMCO_XMIU1, device_jvs_interface) + +#endif diff --git a/src/devices/bus/rs232/rs232.h b/src/devices/bus/rs232/rs232.h index 2de3aedd9d7..2ac20051b8e 100644 --- a/src/devices/bus/rs232/rs232.h +++ b/src/devices/bus/rs232/rs232.h @@ -117,7 +117,7 @@ public: set_default_option(dflt); set_fixed(false); } - rs232_port_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + rs232_port_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0); virtual ~rs232_port_device(); // static configuration helpers diff --git a/src/emu/layout/cyberlead.lay b/src/emu/layout/cyberlead.lay new file mode 100644 index 00000000000..9eb4e87e472 --- /dev/null +++ b/src/emu/layout/cyberlead.lay @@ -0,0 +1,14 @@ + + + + + + + + + + + + -- cgit v1.2.3