622 lines
19 KiB
Diff
622 lines
19 KiB
Diff
--- a/src/mame/sharp/x68k.h
|
|
+++ b/src/mame/sharp/x68k.h
|
|
@@ -20,7 +20,7 @@
|
|
#include "cpu/m68000/m68000.h"
|
|
#include "cpu/m68000/m68030.h"
|
|
#include "imagedev/floppy.h"
|
|
-#include "machine/8530scc.h"
|
|
+#include "machine/z80scc.h"
|
|
#include "machine/hd63450.h"
|
|
#include "machine/i8255.h"
|
|
#include "machine/mb87030.h"
|
|
@@ -64,9 +64,6 @@
|
|
, m_expansion(*this, "exp%u", 1U)
|
|
, m_adpcm_out(*this, {"adpcm_outl", "adpcm_outr"})
|
|
, m_options(*this, "options")
|
|
- , m_mouse1(*this, "mouse1")
|
|
- , m_mouse2(*this, "mouse2")
|
|
- , m_mouse3(*this, "mouse3")
|
|
, m_eject_drv_out(*this, "eject_drv%u", 0U)
|
|
, m_ctrl_drv_out(*this, "ctrl_drv%u", 0U)
|
|
, m_access_drv_out(*this, "access_drv%u", 0U)
|
|
@@ -100,7 +97,7 @@
|
|
required_device<palette_device> m_pcgpalette;
|
|
required_device<mc68901_device> m_mfpdev;
|
|
required_device<rp5c15_device> m_rtc;
|
|
- required_device<scc8530_legacy_device> m_scc;
|
|
+ required_device<scc8530_device> m_scc;
|
|
required_device<ym2151_device> m_ym2151;
|
|
required_device<i8255_device> m_ppi;
|
|
required_device<screen_device> m_screen;
|
|
@@ -111,9 +108,6 @@
|
|
required_device_array<filter_volume_device, 2> m_adpcm_out;
|
|
|
|
required_ioport m_options;
|
|
- required_ioport m_mouse1;
|
|
- required_ioport m_mouse2;
|
|
- required_ioport m_mouse3;
|
|
|
|
output_finder<4> m_eject_drv_out;
|
|
output_finder<4> m_ctrl_drv_out;
|
|
@@ -178,24 +172,21 @@
|
|
uint8_t hdcvector = 0;
|
|
uint8_t prnvector = 0;
|
|
} m_ioc;
|
|
- struct
|
|
- {
|
|
- int inputtype = 0; // determines which input is to be received
|
|
- bool irqactive = false; // true if IRQ is being serviced
|
|
- uint8_t irqvector = 0;
|
|
- char last_mouse_x = 0; // previous mouse x-axis value
|
|
- char last_mouse_y = 0; // previous mouse y-axis value
|
|
- int bufferempty = 0; // non-zero if buffer is empty
|
|
- } m_mouse;
|
|
uint8_t m_ppi_portc = 0;
|
|
bool m_dmac_int = false;
|
|
bool m_mfp_int = false;
|
|
+ bool m_scc_int = false;
|
|
bool m_exp_irq2[2]{};
|
|
bool m_exp_irq4[2]{};
|
|
bool m_exp_nmi[2]{};
|
|
uint8_t m_current_ipl = 0;
|
|
int m_led_state = 0;
|
|
- emu_timer* m_mouse_timer = nullptr;
|
|
+ // Extra cycles charged per VRAM access, over and above a main-memory
|
|
+ // access, in 16.16 fixed point. Set from measured values in machine_start
|
|
+ // for the machines those measurements cover; 0 (unmodelled) otherwise.
|
|
+ uint32_t m_gvram_wait = 0;
|
|
+ uint32_t m_tvram_wait = 0;
|
|
+ uint32_t m_vram_wait_accum = 0; // 16.16 carry between accesses
|
|
emu_timer* m_led_timer = nullptr;
|
|
unsigned char m_scc_prev = 0;
|
|
emu_timer* m_fdc_tc = nullptr;
|
|
@@ -233,7 +224,6 @@
|
|
void dma_irq(int state);
|
|
void dma_end(offs_t offset, uint8_t data);
|
|
|
|
- int read_mouse();
|
|
void set_adpcm();
|
|
|
|
void fm_irq(int state);
|
|
@@ -241,8 +231,6 @@
|
|
template <int N> void irq4_line(int state);
|
|
template <int N> void nmi_line(int state);
|
|
|
|
- void scc_w(offs_t offset, uint16_t data);
|
|
- uint16_t scc_r(offs_t offset);
|
|
void fdc_w(offs_t offset, uint16_t data);
|
|
uint16_t fdc_r(offs_t offset);
|
|
void ioc_w(offs_t offset, uint16_t data);
|
|
@@ -265,6 +253,15 @@
|
|
uint16_t exp_r(offs_t offset, uint16_t mem_mask = ~0);
|
|
void exp_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
|
|
|
|
+ // VRAM wait states. The X68000's video RAM is slower than main memory;
|
|
+ // MAME charged nothing for it, so VRAM-bound code ran optimistically
|
|
+ // fast. These trampolines charge the difference and forward to the CRTC.
|
|
+ void charge_vram_wait(uint32_t increment);
|
|
+ uint16_t gvram_wait_r(offs_t offset);
|
|
+ void gvram_wait_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
|
|
+ uint16_t tvram_wait_r(offs_t offset);
|
|
+ void tvram_wait_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
|
|
+
|
|
uint16_t spritereg_r(offs_t offset);
|
|
void spritereg_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
|
|
uint16_t spriteram_r(offs_t offset);
|
|
--- a/src/mame/sharp/x68k.cpp
|
|
+++ b/src/mame/sharp/x68k.cpp
|
|
@@ -119,6 +119,7 @@
|
|
#include "x68k.h"
|
|
#include "x68k_hdc.h"
|
|
#include "x68k_kbd.h"
|
|
+#include "x68k_mouse.h"
|
|
|
|
#include "machine/nvram.h"
|
|
|
|
@@ -174,127 +175,6 @@
|
|
|
|
}
|
|
|
|
-
|
|
-// mouse input
|
|
-// port B of the Z8530 SCC
|
|
-// typically read from the SCC data port on receive buffer full interrupt per byte
|
|
-int x68k_state::read_mouse()
|
|
-{
|
|
- char val = 0;
|
|
- char ipt = 0;
|
|
-
|
|
- if(!(m_scc->get_reg_b(5) & 0x02))
|
|
- return 0xff;
|
|
-
|
|
- switch(m_mouse.inputtype)
|
|
- {
|
|
- case 0:
|
|
- ipt = m_mouse1->read();
|
|
- break;
|
|
- case 1:
|
|
- val = m_mouse2->read();
|
|
- ipt = val - m_mouse.last_mouse_x;
|
|
- m_mouse.last_mouse_x = val;
|
|
- break;
|
|
- case 2:
|
|
- val = m_mouse3->read();
|
|
- ipt = val - m_mouse.last_mouse_y;
|
|
- m_mouse.last_mouse_y = val;
|
|
- break;
|
|
- }
|
|
- m_mouse.inputtype++;
|
|
- if(m_mouse.inputtype > 2)
|
|
- {
|
|
- int i_val = m_scc->get_reg_b(0);
|
|
- m_mouse.inputtype = 0;
|
|
- m_mouse.bufferempty = 1;
|
|
- i_val &= ~0x01;
|
|
- m_scc->set_reg_b(0, i_val);
|
|
- LOGMASKED(LOG_SYS, "SCC: mouse buffer empty\n");
|
|
- }
|
|
-
|
|
- return ipt;
|
|
-}
|
|
-
|
|
-/*
|
|
- 0xe98001 - Z8530 command port B
|
|
- 0xe98003 - Z8530 data port B (mouse input)
|
|
- 0xe98005 - Z8530 command port A
|
|
- 0xe98007 - Z8530 data port A (RS232)
|
|
-*/
|
|
-uint16_t x68k_state::scc_r(offs_t offset)
|
|
-{
|
|
- offset %= 4;
|
|
- switch(offset)
|
|
- {
|
|
- case 0:
|
|
- return m_scc->reg_r(0);
|
|
- case 1:
|
|
- return read_mouse();
|
|
- case 2:
|
|
- return m_scc->reg_r(1);
|
|
- case 3:
|
|
- return m_scc->reg_r(3);
|
|
- default:
|
|
- return 0xff;
|
|
- }
|
|
-}
|
|
-
|
|
-void x68k_state::scc_w(offs_t offset, uint16_t data)
|
|
-{
|
|
- offset %= 4;
|
|
-
|
|
- switch(offset)
|
|
- {
|
|
- case 0:
|
|
- m_scc->reg_w(0,(uint8_t)data);
|
|
- if((m_scc->get_reg_b(5) & 0x02) != m_scc_prev)
|
|
- {
|
|
- if(m_scc->get_reg_b(5) & 0x02) // Request to Send
|
|
- {
|
|
- int val = m_scc->get_reg_b(0);
|
|
- m_mouse.bufferempty = 0;
|
|
- val |= 0x01;
|
|
- m_scc->set_reg_b(0,val);
|
|
- }
|
|
- }
|
|
- break;
|
|
- case 1:
|
|
- m_scc->reg_w(2,(uint8_t)data);
|
|
- break;
|
|
- case 2:
|
|
- m_scc->reg_w(1,(uint8_t)data);
|
|
- break;
|
|
- case 3:
|
|
- m_scc->reg_w(3,(uint8_t)data);
|
|
- break;
|
|
- }
|
|
- m_scc_prev = m_scc->get_reg_b(5) & 0x02;
|
|
-}
|
|
-
|
|
-TIMER_CALLBACK_MEMBER(x68k_state::scc_ack)
|
|
-{
|
|
- if(m_mouse.bufferempty != 0) // nothing to do if the mouse data buffer is empty
|
|
- return;
|
|
-
|
|
-// if((m_ioc.irqstatus & 0xc0) != 0)
|
|
-// return;
|
|
-
|
|
- // hard-code the IRQ vector for now, until the SCC code is more complete
|
|
- if((m_scc->get_reg_a(9) & 0x08) || (m_scc->get_reg_b(9) & 0x08)) // SCC reg WR9 is the same for both channels
|
|
- {
|
|
- if((m_scc->get_reg_b(1) & 0x18) != 0) // if bits 3 and 4 of WR1 are 0, then Rx IRQs are disabled on this channel
|
|
- {
|
|
- if(m_scc->get_reg_b(5) & 0x02) // RTS signal
|
|
- {
|
|
- m_mouse.irqactive = true;
|
|
- m_mouse.irqvector = 0x54;
|
|
- update_ipl();
|
|
- }
|
|
- }
|
|
- }
|
|
-}
|
|
-
|
|
void x68k_state::set_adpcm()
|
|
{
|
|
uint32_t rate = adpcm_div[m_adpcm.rate];
|
|
@@ -837,7 +717,7 @@
|
|
new_ipl = 7;
|
|
else if (m_mfp_int)
|
|
new_ipl = 6;
|
|
- else if (m_mouse.irqactive)
|
|
+ else if (m_scc_int)
|
|
new_ipl = 5;
|
|
else if (m_exp_irq4[0] || m_exp_irq4[1])
|
|
new_ipl = 4;
|
|
@@ -950,18 +830,6 @@
|
|
return 0x18; // spurious interrupt
|
|
}
|
|
|
|
-uint8_t x68k_state::iack5()
|
|
-{
|
|
- if (!machine().side_effects_disabled())
|
|
- {
|
|
- m_mouse.irqactive = false;
|
|
- update_ipl();
|
|
- }
|
|
-
|
|
- // TODO: use vector from SCC
|
|
- return m_mouse.irqvector;
|
|
-}
|
|
-
|
|
void x68k_state::cpu_space_map(address_map &map)
|
|
{
|
|
map.global_mask(0xffffff);
|
|
@@ -969,7 +837,7 @@
|
|
map(0xfffff5, 0xfffff5).r(FUNC(x68k_state::iack2));
|
|
map(0xfffff7, 0xfffff7).r(m_hd63450, FUNC(hd63450_device::iack));
|
|
map(0xfffff9, 0xfffff9).r(FUNC(x68k_state::iack4));
|
|
- map(0xfffffb, 0xfffffb).r(FUNC(x68k_state::iack5));
|
|
+ map(0xfffffb, 0xfffffb).lr8(NAME([this]() { return m_scc->m1_r(); }));
|
|
map(0xfffffd, 0xfffffd).r(m_mfpdev, FUNC(mc68901_device::get_vector));
|
|
map(0xffffff, 0xffffff).lr8(NAME([] () { return m68000_base_device::autovector(7); }));
|
|
}
|
|
@@ -992,12 +860,80 @@
|
|
// Is this an undocumented MB89352 feature, an ASIC register, an original code bug or a bad dump?
|
|
}
|
|
|
|
+// VRAM wait states.
|
|
+//
|
|
+// The 68000 in an X68000 does not reach video RAM as fast as it reaches main
|
|
+// memory, and MAME modelled no wait at all -- so any VRAM-bound inner loop ran
|
|
+// optimistically fast, which is exactly the code a graphics library cares
|
|
+// about. The figures used here are Makoto Kamada's real-hardware measurements
|
|
+// distributed with XEiJ (credited there to uchopon, tnb and ita), taken by
|
|
+// timing tst.w against each region on five 10 MHz X68000 variants:
|
|
+//
|
|
+// region tst.w time (us) derived wait (cycles)
|
|
+// main memory 1.642 .. 1.663 0.123
|
|
+// GVRAM 1.734 .. 1.770 1.145
|
|
+// TVRAM 1.829 .. 1.850 2.046
|
|
+//
|
|
+// MAME charges nothing for main memory, so what is added here is the wait
|
|
+// RELATIVE to main memory: 1.145 - 0.123 = 1.022 cycles for GVRAM and
|
|
+// 2.046 - 0.123 = 1.923 for TVRAM. Cross-check against the raw measurements:
|
|
+// GVRAM - main memory averages ~1.03 cycles and TVRAM - main memory ~1.92
|
|
+// across the five machines, which agrees.
|
|
+//
|
|
+// Main memory's own 0.123 cycles (DRAM refresh) is deliberately NOT modelled:
|
|
+// it would mean interposing on the hottest path in the driver to recover ~0.1
|
|
+// cycles per access, and it is a uniform offset that does not change the
|
|
+// relative cost of VRAM versus RAM, which is the thing being measured.
|
|
+//
|
|
+// The wait is fractional, so it accumulates in 16.16 fixed point and whole
|
|
+// cycles are charged as they carry out -- the same technique the apple2gs
|
|
+// driver uses for its 1 MHz cycles (see slow_cycle() there).
|
|
+#define X68K_GVRAM_WAIT 0x000105a2 // 1.022 cycles, 16.16
|
|
+#define X68K_TVRAM_WAIT 0x0001ec4a // 1.923 cycles, 16.16
|
|
+
|
|
+void x68k_state::charge_vram_wait(uint32_t increment)
|
|
+{
|
|
+ // side_effects_disabled() covers debugger and Lua reads, which must not
|
|
+ // perturb the timing they are measuring.
|
|
+ if (increment == 0 || machine().side_effects_disabled())
|
|
+ return;
|
|
+ m_vram_wait_accum += increment;
|
|
+ int const cycles = m_vram_wait_accum >> 16;
|
|
+ m_vram_wait_accum &= 0xffff;
|
|
+ if (cycles != 0)
|
|
+ m_maincpu->adjust_icount(-cycles);
|
|
+}
|
|
+
|
|
+uint16_t x68k_state::gvram_wait_r(offs_t offset)
|
|
+{
|
|
+ charge_vram_wait(m_gvram_wait);
|
|
+ return m_crtc->gvram_r(offset);
|
|
+}
|
|
+
|
|
+void x68k_state::gvram_wait_w(offs_t offset, uint16_t data, uint16_t mem_mask)
|
|
+{
|
|
+ charge_vram_wait(m_gvram_wait);
|
|
+ m_crtc->gvram_w(offset, data, mem_mask);
|
|
+}
|
|
+
|
|
+uint16_t x68k_state::tvram_wait_r(offs_t offset)
|
|
+{
|
|
+ charge_vram_wait(m_tvram_wait);
|
|
+ return m_crtc->tvram_r(offset);
|
|
+}
|
|
+
|
|
+void x68k_state::tvram_wait_w(offs_t offset, uint16_t data, uint16_t mem_mask)
|
|
+{
|
|
+ charge_vram_wait(m_tvram_wait);
|
|
+ m_crtc->tvram_w(offset, data, mem_mask);
|
|
+}
|
|
+
|
|
void x68k_state::x68k_base_map(address_map &map)
|
|
{
|
|
map(0x000000, 0xbffffb).rw(FUNC(x68k_state::emptyram_r), FUNC(x68k_state::emptyram_w));
|
|
map(0xbffffc, 0xbfffff).rw(FUNC(x68k_state::rom0_r), FUNC(x68k_state::rom0_w));
|
|
- map(0xc00000, 0xdfffff).rw(m_crtc, FUNC(x68k_crtc_device::gvram_r), FUNC(x68k_crtc_device::gvram_w));
|
|
- map(0xe00000, 0xe7ffff).rw(m_crtc, FUNC(x68k_crtc_device::tvram_r), FUNC(x68k_crtc_device::tvram_w));
|
|
+ map(0xc00000, 0xdfffff).rw(FUNC(x68k_state::gvram_wait_r), FUNC(x68k_state::gvram_wait_w));
|
|
+ map(0xe00000, 0xe7ffff).rw(FUNC(x68k_state::tvram_wait_r), FUNC(x68k_state::tvram_wait_w));
|
|
map(0xe80000, 0xe81fff).rw(m_crtc, FUNC(x68k_crtc_device::crtc_r), FUNC(x68k_crtc_device::crtc_w));
|
|
map(0xe82400, 0xe83fff).rw(FUNC(x68k_state::vid_r), FUNC(x68k_state::vid_w));
|
|
map(0xe84000, 0xe85fff).rw(m_hd63450, FUNC(hd63450_device::read), FUNC(hd63450_device::write));
|
|
@@ -1009,7 +945,7 @@
|
|
map(0xe90000, 0xe91fff).rw(m_ym2151, FUNC(ym2151_device::read), FUNC(ym2151_device::write)).umask16(0x00ff);
|
|
map(0xe94000, 0xe94003).m(m_upd72065, FUNC(upd72065_device::map)).umask16(0x00ff);
|
|
map(0xe94004, 0xe94007).rw(FUNC(x68k_state::fdc_r), FUNC(x68k_state::fdc_w));
|
|
- map(0xe98000, 0xe99fff).rw(FUNC(x68k_state::scc_r), FUNC(x68k_state::scc_w));
|
|
+ map(0xe98000, 0xe99fff).rw(m_scc, FUNC(scc8530_device::ab_dc_r), FUNC(scc8530_device::ab_dc_w)).umask16(0x00ff);
|
|
map(0xe9a000, 0xe9bfff).rw(FUNC(x68k_state::ppi_r), FUNC(x68k_state::ppi_w));
|
|
map(0xe9c000, 0xe9dfff).rw(FUNC(x68k_state::ioc_r), FUNC(x68k_state::ioc_w));
|
|
map(0xe9e000, 0xe9e3ff).rw(FUNC(x68k_state::exp_r), FUNC(x68k_state::exp_w)); // FPU (Optional)
|
|
@@ -1072,16 +1008,6 @@
|
|
PORT_CONFNAME( 0x02, 0x02, "Enable fake bus errors")
|
|
PORT_CONFSETTING( 0x00, DEF_STR( Off ))
|
|
PORT_CONFSETTING( 0x02, DEF_STR( On ))
|
|
-
|
|
- PORT_START("mouse1") // mouse buttons
|
|
- PORT_BIT( 0x00000001, IP_ACTIVE_HIGH, IPT_BUTTON9) PORT_NAME("Left mouse button") PORT_CODE(MOUSECODE_BUTTON1)
|
|
- PORT_BIT( 0x00000002, IP_ACTIVE_HIGH, IPT_BUTTON10) PORT_NAME("Right mouse button") PORT_CODE(MOUSECODE_BUTTON2)
|
|
-
|
|
- PORT_START("mouse2") // X-axis
|
|
- PORT_BIT( 0xff, 0x00, IPT_MOUSE_X) PORT_SENSITIVITY(100) PORT_KEYDELTA(0) PORT_PLAYER(1)
|
|
-
|
|
- PORT_START("mouse3") // Y-axis
|
|
- PORT_BIT( 0xff, 0x00, IPT_MOUSE_Y) PORT_SENSITIVITY(100) PORT_KEYDELTA(0) PORT_PLAYER(1)
|
|
INPUT_PORTS_END
|
|
|
|
void x68k_state::floppy_load_unload(bool load, floppy_image_device *dev)
|
|
@@ -1155,9 +1081,23 @@
|
|
m_spriteram = (uint16_t*)(memregion("user1")->base());
|
|
space.install_ram(0x000000,m_ram->size()-1,m_ram->pointer());
|
|
|
|
- // start mouse timer
|
|
- m_mouse_timer->adjust(attotime::zero, 0, attotime::from_msec(1)); // a guess for now
|
|
- m_mouse.inputtype = 0;
|
|
+ // VRAM wait states, applied only to the machine the measurements cover.
|
|
+ // The published figures are for a 10 MHz 68000 X68000; XEiJ's table also
|
|
+ // lists a 25 MHz X68030 (GVRAM 6.377, TVRAM 6.623) but those machines are
|
|
+ // MACHINE_NOT_WORKING here and cannot be validated, so they are left
|
|
+ // unmodelled rather than given invented numbers.
|
|
+ if (m_maincpu->clock() == 10'000'000)
|
|
+ {
|
|
+ m_gvram_wait = X68K_GVRAM_WAIT;
|
|
+ m_tvram_wait = X68K_TVRAM_WAIT;
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ m_gvram_wait = 0;
|
|
+ m_tvram_wait = 0;
|
|
+ }
|
|
+ m_vram_wait_accum = 0;
|
|
+ save_item(NAME(m_vram_wait_accum));
|
|
|
|
// start LED timer
|
|
m_led_timer->adjust(attotime::zero, 0, attotime::from_msec(400));
|
|
@@ -1177,11 +1117,11 @@
|
|
|
|
m_dmac_int = false;
|
|
m_mfp_int = false;
|
|
+ m_scc_int = false;
|
|
m_exp_irq2[0] = m_exp_irq2[1] = false;
|
|
m_exp_irq4[0] = m_exp_irq4[1] = false;
|
|
m_exp_nmi[0] = m_exp_nmi[1] = false;
|
|
m_ioc.irqstatus = 0;
|
|
- m_mouse.irqactive = false;
|
|
m_current_ipl = 0;
|
|
m_adpcm.rate = 0;
|
|
m_adpcm.clock = 0;
|
|
@@ -1208,7 +1148,6 @@
|
|
// copy last half of BIOS to a user region, to use for initial startup
|
|
memcpy(user2,(rom+0xff0000),0x10000);
|
|
|
|
- m_mouse_timer = timer_alloc(FUNC(x68ksupr_state::scc_ack), this);
|
|
m_led_timer = timer_alloc(FUNC(x68ksupr_state::led_callback), this);
|
|
m_fdc_tc = timer_alloc(FUNC(x68ksupr_state::floppy_tc_tick), this);
|
|
m_adpcm_timer = timer_alloc(FUNC(x68ksupr_state::adpcm_drq_tick), this);
|
|
@@ -1253,6 +1192,11 @@
|
|
device.option_add("x68k", X68K_KEYBOARD);
|
|
}
|
|
|
|
+static void mouse_devices(device_slot_interface &device)
|
|
+{
|
|
+ device.option_add("x68k", X68K_MOUSE);
|
|
+}
|
|
+
|
|
void x68k_state::x68000_base(machine_config &config)
|
|
{
|
|
config.set_maximum_quantum(attotime::from_hz(60));
|
|
@@ -1285,7 +1229,26 @@
|
|
m_hd63450->dma_read<0>().set("upd72065", FUNC(upd72065_device::dma_r));
|
|
m_hd63450->dma_write<0>().set("upd72065", FUNC(upd72065_device::dma_w));
|
|
|
|
- SCC8530(config, m_scc, 40_MHz_XTAL / 8);
|
|
+ SCC8530N(config, m_scc, 40_MHz_XTAL / 8);
|
|
+ m_scc->out_int_callback().set([this](int state) { m_scc_int = state; update_ipl(); });
|
|
+
|
|
+ rs232_port_device &mouse(RS232_PORT(config, "mouse_port", mouse_devices, "x68k"));
|
|
+ mouse.rxd_handler().set(m_scc, FUNC(scc8530_device::rxb_w));
|
|
+ m_scc->out_rtsb_callback().set(mouse, FUNC(rs232_port_device::write_rts));
|
|
+
|
|
+ // RS-232C -- SCC channel A. Only channel B (the mouse) was ever wired, so
|
|
+ // the machine's actual serial port had no connection at all and could not
|
|
+ // be exercised. Exposing it as a standard rs232 slot makes
|
|
+ // `-rs232c null_modem` (TCP socket) and `-rs232c pty` available, which is
|
|
+ // what an automated both-directions serial test needs.
|
|
+ m_scc->out_txda_callback().set("rs232c", FUNC(rs232_port_device::write_txd));
|
|
+ m_scc->out_dtra_callback().set("rs232c", FUNC(rs232_port_device::write_dtr));
|
|
+ m_scc->out_rtsa_callback().set("rs232c", FUNC(rs232_port_device::write_rts));
|
|
+
|
|
+ rs232_port_device &rs232c(RS232_PORT(config, "rs232c", default_rs232_devices, nullptr));
|
|
+ rs232c.rxd_handler().set(m_scc, FUNC(scc8530_device::rxa_w));
|
|
+ rs232c.dcd_handler().set(m_scc, FUNC(scc8530_device::dcda_w));
|
|
+ rs232c.cts_handler().set(m_scc, FUNC(scc8530_device::ctsa_w));
|
|
|
|
RP5C15(config, m_rtc, 32.768_kHz_XTAL);
|
|
m_rtc->alarm().set(m_mfpdev, FUNC(mc68901_device::i0_w));
|
|
--- /dev/null
|
|
+++ b/src/mame/sharp/x68k_mouse.h
|
|
@@ -0,0 +1,36 @@
|
|
+// license:BSD-3-Clause
|
|
+// copyright-holders:Patrick Mackinlay
|
|
+
|
|
+#ifndef MAME_SHARP_X68K_MOUSE_H
|
|
+#define MAME_SHARP_X68K_MOUSE_H
|
|
+
|
|
+#pragma once
|
|
+
|
|
+#include "bus/rs232/rs232.h"
|
|
+
|
|
+class x68k_mouse_device : public buffered_rs232_device<3>
|
|
+{
|
|
+public:
|
|
+ x68k_mouse_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock = 0);
|
|
+
|
|
+ virtual void input_rts(int state) override; // MSCTRL (active low)
|
|
+
|
|
+protected:
|
|
+ virtual ioport_constructor device_input_ports() const override ATTR_COLD;
|
|
+ virtual void device_start() override ATTR_COLD;
|
|
+
|
|
+ virtual void received_byte(u8 byte) override {}
|
|
+
|
|
+private:
|
|
+ required_ioport m_buttons;
|
|
+ required_ioport m_x_axis;
|
|
+ required_ioport m_y_axis;
|
|
+
|
|
+ u8 m_b;
|
|
+ u16 m_x;
|
|
+ u16 m_y;
|
|
+};
|
|
+
|
|
+DECLARE_DEVICE_TYPE(X68K_MOUSE, x68k_mouse_device)
|
|
+
|
|
+#endif // MAME_SHARP_X68K_MOUSE_H
|
|
--- /dev/null
|
|
+++ b/src/mame/sharp/x68k_mouse.cpp
|
|
@@ -0,0 +1,103 @@
|
|
+// license:BSD-3-Clause
|
|
+// copyright-holders:Patrick Mackinlay
|
|
+
|
|
+#include "emu.h"
|
|
+#include "x68k_mouse.h"
|
|
+
|
|
+#include <algorithm>
|
|
+
|
|
+//#define VERBOSE (LOG_GENERAL)
|
|
+#include "logmacro.h"
|
|
+
|
|
+enum status_mask : u8
|
|
+{
|
|
+ STS_RB = 0x01, // right button
|
|
+ STS_LB = 0x02, // left button
|
|
+ STS_OX = 0x10, // x overflow
|
|
+ STS_UX = 0x20, // x underflow
|
|
+ STS_OY = 0x40, // y overflow
|
|
+ STS_UY = 0x80, // y underflow
|
|
+};
|
|
+
|
|
+DEFINE_DEVICE_TYPE(X68K_MOUSE, x68k_mouse_device, "x68k_mouse", "Sharp X68000 Mouse")
|
|
+
|
|
+x68k_mouse_device::x68k_mouse_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock)
|
|
+ : buffered_rs232_device<3>(mconfig, X68K_MOUSE, tag, owner, clock)
|
|
+ , m_buttons(*this, "BTN")
|
|
+ , m_x_axis(*this, "X")
|
|
+ , m_y_axis(*this, "Y")
|
|
+{
|
|
+}
|
|
+
|
|
+void x68k_mouse_device::device_start()
|
|
+{
|
|
+ buffered_rs232_device<3>::device_start();
|
|
+
|
|
+ save_item(NAME(m_b));
|
|
+ save_item(NAME(m_x));
|
|
+ save_item(NAME(m_y));
|
|
+
|
|
+ set_data_frame(1, 8, PARITY_NONE, STOP_BITS_2);
|
|
+ set_tra_rate(4'800);
|
|
+
|
|
+ transmit_register_reset();
|
|
+
|
|
+ m_b = 0;
|
|
+ m_x = 0;
|
|
+ m_y = 0;
|
|
+}
|
|
+
|
|
+s16 read_axis(ioport_port &port, u16 &old_val)
|
|
+{
|
|
+ u16 const new_val = port.read();
|
|
+ s16 const delta = new_val - old_val;
|
|
+
|
|
+ old_val = new_val;
|
|
+
|
|
+ return delta;
|
|
+}
|
|
+
|
|
+void x68k_mouse_device::input_rts(int state)
|
|
+{
|
|
+ if (!state && fifo_empty())
|
|
+ {
|
|
+ u8 status = m_buttons->read();
|
|
+ s16 const dx = read_axis(*m_x_axis, m_x);
|
|
+ s16 const dy = read_axis(*m_y_axis, m_y);
|
|
+
|
|
+ if (dx || dy || m_b != status)
|
|
+ {
|
|
+ if (dy < -128)
|
|
+ status |= STS_UY;
|
|
+ if (dy > 127)
|
|
+ status |= STS_OY;
|
|
+ if (dx < -128)
|
|
+ status |= STS_UX;
|
|
+ if (dx > 127)
|
|
+ status |= STS_OX;
|
|
+
|
|
+ transmit_byte(status);
|
|
+ transmit_byte(s8(std::clamp<s16>(dx, -128, 127)));
|
|
+ transmit_byte(s8(std::clamp<s16>(dy, -128, 127)));
|
|
+
|
|
+ m_b = status & (STS_LB | STS_RB);
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+INPUT_PORTS_START(x68k)
|
|
+ PORT_START("BTN")
|
|
+ PORT_BIT(0x0002, IP_ACTIVE_HIGH, IPT_BUTTON1) PORT_CODE(MOUSECODE_BUTTON1)
|
|
+ PORT_BIT(0x0001, IP_ACTIVE_HIGH, IPT_BUTTON2) PORT_CODE(MOUSECODE_BUTTON2)
|
|
+
|
|
+ PORT_START("X")
|
|
+ PORT_BIT(0xfff, 0x000, IPT_MOUSE_X) PORT_SENSITIVITY(100) PORT_KEYDELTA(0)
|
|
+
|
|
+ PORT_START("Y")
|
|
+ PORT_BIT(0xfff, 0x000, IPT_MOUSE_Y) PORT_SENSITIVITY(100) PORT_KEYDELTA(0)
|
|
+INPUT_PORTS_END
|
|
+
|
|
+ioport_constructor x68k_mouse_device::device_input_ports() const
|
|
+{
|
|
+ return INPUT_PORTS_NAME(x68k);
|
|
+}
|