From e79f7c804f660fda399c9ef7c94f51390d96df18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A4rt=20P=C3=B5der?= Date: Sat, 18 Jan 2025 17:03:55 +0200 Subject: [PATCH] ussr/juku.cpp: Use a memory view for switching memory mapping, added mouse and fixed timer. (#13205) ussr/jukumouse.cpp: Emulated Juku mouse interface. --- src/mame/ussr/juku.cpp | 110 +++++++++++++++------------------ src/mame/ussr/jukumouse.cpp | 118 ++++++++++++++++++++++++++++++++++++ src/mame/ussr/jukumouse.h | 35 +++++++++++ 3 files changed, 201 insertions(+), 62 deletions(-) create mode 100644 src/mame/ussr/jukumouse.cpp create mode 100644 src/mame/ussr/jukumouse.h diff --git a/src/mame/ussr/juku.cpp b/src/mame/ussr/juku.cpp index 31f24760ac3..12981bc284e 100644 --- a/src/mame/ussr/juku.cpp +++ b/src/mame/ussr/juku.cpp @@ -21,22 +21,24 @@ and T to boot from tape/disk/network TODO: + - E5103 (Juss) and IBM AT keyboard layouts? - Work out how the floppy interface really works? - Tape? (split up to E5101 batch as tape only?) + - Separate FDC 1791, 1792 and 1793 versions - И41 (=Multibus-1) compatibility? - Network? - Ramdisk? - Memory extensions? - - Mouse! ***************************************************************************/ #include "emu.h" +#include "jukumouse.h" + #include "cpu/i8085/i8085.h" #include "imagedev/floppy.h" #include "machine/74148.h" -#include "machine/bankdev.h" #include "machine/i8251.h" #include "machine/i8255.h" #include "machine/pic8259.h" @@ -80,7 +82,11 @@ public: juku_state(const machine_config &mconfig, device_type type, const char *tag) : driver_device(mconfig, type, tag), m_maincpu(*this, "maincpu"), - m_bank(*this, "bank"), + m_rom(*this, "maincpu"), + m_exp(*this, "expcart"), + m_ram(*this, "ram"), + m_ext(*this, "ext%u", 0U, 0x8000U, ENDIANNESS_LITTLE), + m_mode(*this, "mode"), m_pic(*this, "pic"), m_pit(*this, "pit%u", 0U), m_pio(*this, "pio%u", 0U), @@ -91,7 +97,8 @@ public: m_keys(*this, "COL.%u", 0U), m_key_special(*this, "SPECIAL"), m_screen(*this, "screen"), - m_speaker(*this, "speaker") + m_speaker(*this, "speaker"), + m_mouse(*this, "mouse") { } void juku(machine_config &config); @@ -102,7 +109,11 @@ protected: private: required_device m_maincpu; - required_device m_bank; + required_region_ptr m_rom; + optional_region_ptr m_exp; + required_shared_ptr m_ram; + memory_share_array_creator m_ext; + memory_view m_mode; required_device m_pic; required_device_array m_pit; required_device_array m_pio; @@ -114,6 +125,7 @@ private: required_ioport m_key_special; required_device m_screen; required_device m_speaker; + optional_device m_mouse; int32_t m_width, m_height, m_hbporch, m_vbporch; @@ -126,10 +138,7 @@ private: uint8_t m_fdc_cur_cmd; - std::unique_ptr m_ram; - void mem_map(address_map &map) ATTR_COLD; - void bank_map(address_map &map) ATTR_COLD; void io_map(address_map &map) ATTR_COLD; void pio0_porta_w(uint8_t data); @@ -163,25 +172,16 @@ private: void juku_state::mem_map(address_map &map) { - map(0x0000, 0xffff).m(m_bank, FUNC(address_map_bank_device::amap8)); -} - -void juku_state::bank_map(address_map &map) -{ - // memory mode 0 - map(0x00000, 0x03fff).rom().region("maincpu", 0); - map(0x00000, 0x03fff).bankw("ram_0000"); - map(0x04000, 0x0ffff).bankrw("ram_4000"); - // memory mode 1 - map(0x10000, 0x1ffff).bankrw("ram_0000"); - map(0x1d800, 0x1ffff).bankr("rom_d800"); - // memory mode 2 - map(0x20000, 0x23fff).bankrw("ram_0000"); - map(0x24000, 0x2bfff).rom().region("extension", 0); - map(0x2c000, 0x2ffff).bankrw("ram_c000"); - map(0x2d800, 0x2ffff).bankr("rom_d800"); - // memory mode 3 - map(0x30000, 0x3ffff).bankrw("ram_0000"); + map(0x0000, 0xffff).ram().share(m_ram); + map(0x0000, 0xffff).view(m_mode); + m_mode[0](0x0000, 0x3fff).rom().region("maincpu", 0x0000); + m_mode[1](0xd800, 0xffff).rom().region("maincpu", 0x1800); + // optional BASIC expansion cartridge + m_mode[2](0x4000, 0xbfff).rom().region("expcart", 0x0000); + // no info on programs actually using extra 32kb "memory window" + //m_mode[2](0x4000, 0xbfff).ram().share(m_ext[0]); + m_mode[2](0xd800, 0xffff).rom().region("maincpu", 0x1800); + m_mode[3]; // let everything fall through to RAM } void juku_state::io_map(address_map &map) @@ -206,6 +206,7 @@ void juku_state::io_map(address_map &map) map(0x1f, 0x1f).rw(FUNC(juku_state::fdc_data_r), FUNC(juku_state::fdc_data_w)); // mapping for cassette version (E5101?) // map(0x1c, 0x1d).rw(m_sio[1], FUNC(i8251_device::read), FUNC(i8251_device::write)); + map(0x80, 0x80).r(m_mouse, FUNC(juku_mouse_device::mouse_port_r)); // TODO: turn this into a Multibus expansion } @@ -645,19 +646,11 @@ void juku_state::pio0_portc_w(uint8_t data) floppy->ss_w(BIT(data, 6)); } - m_bank->set_bank(data & 0x03); + m_mode.select(data & 0b11); } void juku_state::machine_start() { - m_ram = std::make_unique(0x10000); - - membank("rom_d800")->set_base(memregion("maincpu")->base() + 0x1800); - - membank("ram_0000")->set_base(&m_ram[0x0000]); - membank("ram_4000")->set_base(&m_ram[0x4000]); - membank("ram_c000")->set_base(&m_ram[0xc000]); - // register for save states save_item(NAME(m_width)); save_item(NAME(m_height)); @@ -671,12 +664,11 @@ void juku_state::machine_start() save_item(NAME(m_beep_state)); save_item(NAME(m_beep_level)); save_item(NAME(m_fdc_cur_cmd)); - save_pointer(NAME(m_ram), 0x10000); } void juku_state::machine_reset() { - m_bank->set_bank(0); + m_mode.select(0); m_key_encoder->enable_input_w(0); m_beep_state = 0; m_beep_level = 0; @@ -701,13 +693,7 @@ void juku_state::juku(machine_config &config) I8080A(config, m_maincpu, 20_MHz_XTAL/10); m_maincpu->set_addrmap(AS_PROGRAM, &juku_state::mem_map); m_maincpu->set_addrmap(AS_IO, &juku_state::io_map); - m_maincpu->in_inta_func().set("pic", FUNC(pic8259_device::acknowledge)); - - ADDRESS_MAP_BANK(config, m_bank); - m_bank->set_map(&juku_state::bank_map); - m_bank->set_data_width(8); - m_bank->set_addr_width(18); - m_bank->set_stride(0x10000); + m_maincpu->in_inta_func().set(m_pic, FUNC(pic8259_device::acknowledge)); // КР580ВН59 PIC8259(config, m_pic, 0); @@ -721,30 +707,26 @@ void juku_state::juku(machine_config &config) m_pit[0]->out_handler<0>().set(m_pit[1], FUNC(pit8253_device::write_clk0)); m_pit[0]->out_handler<0>().append(m_pit[0], FUNC(pit8253_device::write_gate1)); m_pit[0]->out_handler<0>().append(m_pit[0], FUNC(pit8253_device::write_gate2)); - //m_pit[0]->out_handler<1>().set(, ); // HOR RTR - //m_pit[0]->out_handler<1>().append(, ); // HOR RTR + //m_pit[0]->out_handler<1>().set(?, ?); // HOR RTR // КР580ВИ53 #2 PIT8253(config, m_pit[1], 0); - m_pit[0]->out_handler<2>().set(m_pit[1], FUNC(pit8253_device::write_clk1)); // H SYNC DSL + m_pit[0]->out_handler<2>().set(m_pit[1], FUNC(pit8253_device::write_clk1)); // HOR SYNC DSL m_pit[0]->out_handler<2>().append(m_pit[1], FUNC(pit8253_device::write_clk2)); m_pit[1]->out_handler<0>().append(m_pit[1], FUNC(pit8253_device::write_gate1)); m_pit[1]->out_handler<0>().append(m_pit[1], FUNC(pit8253_device::write_gate2)); m_pit[1]->out_handler<1>().set(m_pic, FUNC(pic8259_device::ir5_w)); // VER RTR / FRAME INT - - //m_pit[1]->out_handler<2>().append(m_pit[1], FUNC(pit8253_device::write_clk1)); // VERT SYNC DSL + //m_pit[1]->out_handler<2>().set(m_pit[1], FUNC(pit8253_device::write_clk1)); // VERT SYNC DSL //m_pit[1]->out_handler<2>().append(m_pit[1], FUNC(pit8253_device::write_clk2)); // КР580ВИ53 #3 PIT8253(config, m_pit[2], 0); - m_pit[2]->set_clk<0>(16_MHz_XTAL/13); // 1.23 MHz m_pit[2]->set_clk<1>(16_MHz_XTAL/8); // 2 MHz - m_pit[2]->set_clk<2>(16_MHz_XTAL/13); // 1.23 MHz - - //m_pit[1]->out_handler<0>().append(...); // BAUD RATE + m_pit[1]->out_handler<1>().append(m_pit[2], FUNC(pit8253_device::write_clk2)); // ~49.92 Hz + //m_pit[2]->out_handler<0>().set(?, ?); // BAUD RATE m_pit[2]->out_handler<1>().append(FUNC(juku_state::speaker_w)); // SOUND - //m_pit[1]->out_handler<2>().append(...); // SYNC BAUD RATE + //m_pit[2]->out_handler<2>().set(?, ?); // SYNC BAUD RATE // КР580ВВ55A #1 (=КР580ИК55) I8255A(config, m_pio[0]); @@ -757,13 +739,13 @@ void juku_state::juku(machine_config &config) // КР580ВВ51A I8251(config, m_sio[0], 0); - m_sio[0]->rxrdy_handler().set("pic", FUNC(pic8259_device::ir2_w)); - m_sio[0]->txrdy_handler().set("pic", FUNC(pic8259_device::ir3_w)); + m_sio[0]->rxrdy_handler().set(m_pic, FUNC(pic8259_device::ir2_w)); + m_sio[0]->txrdy_handler().set(m_pic, FUNC(pic8259_device::ir3_w)); // КР580ВВ51A (instead of FDC?) I8251(config, m_sio[1], 0); - m_sio[1]->rxrdy_handler().set("pic", FUNC(pic8259_device::ir0_w)); - m_sio[1]->txrdy_handler().set("pic", FUNC(pic8259_device::ir1_w)); + m_sio[1]->rxrdy_handler().set(m_pic, FUNC(pic8259_device::ir0_w)); + m_sio[1]->txrdy_handler().set(m_pic, FUNC(pic8259_device::ir1_w)); // Электроника МС 6105.1 "Колокольчик" (DEC VR201 analog) SCREEN(config, m_screen, SCREEN_TYPE_RASTER); @@ -778,6 +760,10 @@ void juku_state::juku(machine_config &config) // К155ИВ1 TTL74148(config, m_key_encoder, 0); + // E4701 (joystick like mouse device) + JUKU_MOUSE(config, m_mouse); + m_mouse->int_handler().set(m_pic, FUNC(pic8259_device::ir6_w)); + // КР1818ВГ93 (for E6502 disk drive) KR1818VG93(config, m_fdc, 16_MHz_XTAL/16); m_fdc->drq_wr_callback().set(FUNC(juku_state::fdc_drq_w)); @@ -796,8 +782,8 @@ ROM_START( juku ) ROM_DEFAULT_BIOS("3.43m_37") ROM_REGION(0x4000, "maincpu", 0) - // Monitor 3.3 with Bootstrap 3.3, FDC 1791 from early 1985 prototype - // Does not seem to be compatible with JBASIC extension cartridge + // Monitor 3.3 with Bootstrap 3.3, FDC 1791 from early prototypes + // Does not seem to be compatible with JBASIC expansion cartridge ROM_SYSTEM_BIOS(0, "jmon3.3", "Monitor/Bootstrap 3.3 \\w JBASIC") ROMX_LOAD("jmon33.bin", 0x0000, 0x4000, CRC(ed22c287) SHA1(76407d99bf83035ef526d980c9468cb04972608c), ROM_BIOS(0)) @@ -826,7 +812,7 @@ ROM_START( juku ) ROM_SYSTEM_BIOS(5, "2.43m_43", "Tape/Disk \\w AT keyb (2.43m #0043)") ROMX_LOAD("ekta43.bin", 0x0000, 0x4000, CRC(05678f9f) SHA1(a7419bfd8249871cc7dbf5c6ea85022d6963fc9a), ROM_BIOS(5)) - ROM_REGION(0x8000, "extension", 0) + ROM_REGION(0x8000, "expcart", 0) // EKTA JBASIC cartridge (buggy) seems similar to v1.1 from 14.09.1987. // There is also a version with additional HEX$ directive for EKDOS. diff --git a/src/mame/ussr/jukumouse.cpp b/src/mame/ussr/jukumouse.cpp new file mode 100644 index 00000000000..441849d7900 --- /dev/null +++ b/src/mame/ussr/jukumouse.cpp @@ -0,0 +1,118 @@ +// license:BSD-3-Clause +// copyright-holders:Märt Põder + +#include "emu.h" +#include "jukumouse.h" + +//#define VERBOSE 1 +//#define LOG_OUTPUT_FUNC osd_printf_info + +#include "logmacro.h" + +// measured avg in heavy use 442-520, max ~1400Hz +static constexpr int MOUSE_RATE_HZ = 600; + +DEFINE_DEVICE_TYPE(JUKU_MOUSE, juku_mouse_device, "juku_mouse", "Juku E510x mouse") + +juku_mouse_device::juku_mouse_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : + device_t(mconfig, JUKU_MOUSE, tag, owner, clock), + m_mouse_x(*this, "MOUSE_X"), + m_mouse_y(*this, "MOUSE_Y"), + m_mouse_b(*this, "BUTTONS"), + m_int_handler(*this) +{ +} + +void juku_mouse_device::device_start() +{ + save_item(NAME(m_prev_mouse_y)); + save_item(NAME(m_prev_mouse_x)); + save_item(NAME(m_prev_byte)); + m_mouse_timer = timer_alloc(FUNC(juku_mouse_device::poll_delta), this); +} + +void juku_mouse_device::device_reset() +{ + m_prev_mouse_y = 0; + m_prev_mouse_x = 0; + m_prev_byte = 0; + m_mouse_timer->adjust(attotime::zero, 0, attotime::from_hz(MOUSE_RATE_HZ)); +} + +/* + * Calculate positive/negative delta from old and new relative value + */ +inline int delta(int o, int n) +{ + if (o > n) { + if (o-n < 128) return n - o; + else return n + 255 - o; + } + if (o < n) { + if (n-o < 128) return n - o; + else return n - 255 - o; + } + + return 0; +} + +TIMER_CALLBACK_MEMBER( juku_mouse_device::poll_delta ) +{ + uint8_t buttons = m_mouse_b->read(); + int x = m_mouse_x->read(), y = m_mouse_y->read(); + int dx = delta(m_prev_mouse_x, x); + int dy = delta(m_prev_mouse_y, y); + + if (dx != 0 || dy != 0 || (m_prev_byte & 0b11) != buttons) { + m_int_handler(CLEAR_LINE); + m_int_handler(ASSERT_LINE); + } +} + +static INPUT_PORTS_START( juku_mouse ) + PORT_START("MOUSE_X") + PORT_BIT(0xff, 0x00, IPT_MOUSE_X) PORT_CODE(MOUSECODE_X) PORT_SENSITIVITY(23) + + PORT_START("MOUSE_Y") + PORT_BIT(0xff, 0x00, IPT_MOUSE_Y) PORT_CODE(MOUSECODE_Y) PORT_SENSITIVITY(23) + + PORT_START("BUTTONS") + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_BUTTON1) PORT_CODE(MOUSECODE_BUTTON1) PORT_NAME("Left Button") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_BUTTON2) PORT_CODE(MOUSECODE_BUTTON2) PORT_NAME("Right Button") +INPUT_PORTS_END + +uint8_t juku_mouse_device::mouse_port_r() +{ + // 7------- always 1 + // -6------ always 0 + // --5----- vertical active + // ---4---- vertical direction + // ----3--- horizontal active + // -----2-- horizontal direction + // ------1- left button + // -------0 right button + + uint8_t data = 0b10000000 | m_mouse_b->read(); + int x = m_mouse_x->read(), y = m_mouse_y->read(); + int dx = delta(m_prev_mouse_x, x); + int dy = delta(m_prev_mouse_y, y); + + if (dx != 0) { + data |= (dx > 0) ? 0b00001000 : 0b00001100; + m_prev_mouse_x = x; + } + + if (dy != 0) { + data |= (dy > 0) ? 0b00110000 : 0b00100000; + m_prev_mouse_y = y; + } + + m_prev_byte = data; + + return data; +} + +ioport_constructor juku_mouse_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( juku_mouse ); +} diff --git a/src/mame/ussr/jukumouse.h b/src/mame/ussr/jukumouse.h new file mode 100644 index 00000000000..47dfa219adf --- /dev/null +++ b/src/mame/ussr/jukumouse.h @@ -0,0 +1,35 @@ +// license: BSD-3-Clause +// copyright-holders:Märt Põder + +#ifndef MAME_USSR_JUKUMOUSE_H +#define MAME_USSR_JUKUMOUSE_H + +#pragma once + +class juku_mouse_device : public device_t +{ +public: + juku_mouse_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0); + + auto int_handler() { return m_int_handler.bind(); } + + uint8_t mouse_port_r(); + +protected: + virtual void device_start() override ATTR_COLD; + virtual void device_reset() override ATTR_COLD; + virtual ioport_constructor device_input_ports() const override ATTR_COLD; + + TIMER_CALLBACK_MEMBER( poll_delta ); + +private: + required_ioport m_mouse_x, m_mouse_y, m_mouse_b; + uint8_t m_prev_mouse_x, m_prev_mouse_y; + uint8_t m_prev_byte; + devcb_write_line m_int_handler; + emu_timer *m_mouse_timer; +}; + +DECLARE_DEVICE_TYPE(JUKU_MOUSE, juku_mouse_device) + +#endif // MAME_USSR_JUKUMOUSE_H