276 lines
10 KiB
Diff
276 lines
10 KiB
Diff
--- a/src/mame/sharp/x68k_crtc.h 2026-08-04 16:07:13.182675756 -0500
|
|
+++ b/src/mame/sharp/x68k_crtc.h 2026-08-04 16:32:58.889623301 -0500
|
|
@@ -61,7 +61,7 @@
|
|
private:
|
|
// internal helpers
|
|
void text_copy(unsigned src, unsigned dest, u8 planes);
|
|
- TIMER_CALLBACK_MEMBER(operation_end);
|
|
+ void do_fast_clear();
|
|
void refresh_mode();
|
|
TIMER_CALLBACK_MEMBER(hsync);
|
|
TIMER_CALLBACK_MEMBER(raster_end);
|
|
@@ -84,6 +84,12 @@
|
|
// internal state
|
|
u16 m_reg[24]; // registers
|
|
u8 m_operation; // operation port (0xe80481)
|
|
+ // Graphic high-speed clear (operation port bit 1). Writing 1 only
|
|
+ // RESERVES the clear; it starts at the next vertical display start and
|
|
+ // runs for one frame (two when interlaced). Reads of bit 1 report
|
|
+ // m_clear_frames != 0, so software can wait for start then for end.
|
|
+ bool m_clear_standby; // clear reserved, waiting for vertical display start
|
|
+ u8 m_clear_frames; // frames remaining in the running clear (0 = idle)
|
|
bool m_vblank; // true if in VBlank
|
|
bool m_hblank; // true if in HBlank
|
|
u16 m_htotal; // Horizontal Total (in characters)
|
|
@@ -111,7 +117,6 @@
|
|
emu_timer *m_raster_irq_timer;
|
|
emu_timer *m_vblank_irq_timer;
|
|
emu_timer *m_raster_end_timer;
|
|
- emu_timer *m_operation_end_timer;
|
|
};
|
|
|
|
class vinas_device : public x68k_crtc_device
|
|
--- a/src/mame/sharp/x68k_crtc.cpp 2026-08-04 16:07:13.181675761 -0500
|
|
+++ b/src/mame/sharp/x68k_crtc.cpp 2026-08-04 16:32:58.889623301 -0500
|
|
@@ -25,6 +25,8 @@
|
|
, m_clock_69m(0)
|
|
, m_clock_50m(0)
|
|
, m_operation(0)
|
|
+ , m_clear_standby(false)
|
|
+ , m_clear_frames(0)
|
|
, m_vblank(false)
|
|
, m_hblank(false)
|
|
, m_htotal(0)
|
|
@@ -58,7 +60,6 @@
|
|
void x68k_crtc_device::device_start()
|
|
{
|
|
m_scanline_timer = timer_alloc(FUNC(x68k_crtc_device::hsync), this);
|
|
- m_operation_end_timer = timer_alloc(FUNC(x68k_crtc_device::operation_end), this);
|
|
m_raster_end_timer = timer_alloc(FUNC(x68k_crtc_device::raster_end), this);
|
|
m_raster_irq_timer = timer_alloc(FUNC(x68k_crtc_device::raster_irq), this);
|
|
m_vblank_irq_timer = timer_alloc(FUNC(x68k_crtc_device::vblank_irq), this);
|
|
@@ -66,6 +67,8 @@
|
|
// save state
|
|
save_item(NAME(m_reg));
|
|
save_item(NAME(m_operation));
|
|
+ save_item(NAME(m_clear_standby));
|
|
+ save_item(NAME(m_clear_frames));
|
|
save_item(NAME(m_vblank));
|
|
save_item(NAME(m_hblank));
|
|
save_item(NAME(m_htotal));
|
|
@@ -97,6 +100,10 @@
|
|
m_reg[7] = 552; // Vertical end
|
|
m_reg[8] = 27; // Horizontal adjust
|
|
|
|
+ // No graphic high-speed clear is reserved or running out of reset.
|
|
+ m_clear_standby = false;
|
|
+ m_clear_frames = 0;
|
|
+
|
|
//m_scanline = screen().vpos();// = m_reg[6]; // Vertical start
|
|
|
|
// start VBlank timer
|
|
@@ -127,15 +134,58 @@
|
|
}
|
|
}
|
|
|
|
-TIMER_CALLBACK_MEMBER(x68k_crtc_device::operation_end)
|
|
-{
|
|
- if(!(m_operation & param))
|
|
+// Graphic high-speed clear, performed when the operation actually starts
|
|
+// (at a vertical display start), not when the register is written.
|
|
+//
|
|
+// Range is determined by the screen size, the real screen size and PAGE 0's
|
|
+// scroll position. When the real screen is 1024x1024 the page select is
|
|
+// ignored and every page is cleared.
|
|
+void x68k_crtc_device::do_fast_clear()
|
|
+{
|
|
+ // this is based on the docs except for the higher color depth modes which isn't
|
|
+ // explicitly described this way but is likely based on how the plane scroll works
|
|
+ // XXX: not sufficiently tested especially in hires modes
|
|
+ // it seems that it only uses the 0 page scroll registers for where to clear see atomrobo
|
|
+ uint16_t xscr = xscr_gfx(0) & 0x1ff;
|
|
+ uint16_t yscr = yscr_gfx(0) & 0x1ff;
|
|
+ uint16_t mask = 0;
|
|
+ for (int page = 0; page < 4; page++)
|
|
{
|
|
- m_operation |= param;
|
|
- m_operation_end_timer->adjust(attotime::from_msec(5), param);
|
|
+ if (!(m_reg[21] & (1 << page)))
|
|
+ mask |= (0xf << (page * 4));
|
|
+ }
|
|
+ for (int y = yscr; y < (m_height + yscr); y++)
|
|
+ {
|
|
+ if (is_1024x1024())
|
|
+ {
|
|
+ if (m_width > 256)
|
|
+ {
|
|
+ for (int x = 0; x < 512; x++)
|
|
+ {
|
|
+ uint16_t data = m_gvram_read_callback(((y * 512) + x) & 0x3ffff, 0xffff);
|
|
+ m_gvram_write_callback(((y * 512) + x) & 0x3ffff, data & mask, 0xffff);
|
|
+ }
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ for (int x = 0; x < 256; x++)
|
|
+ {
|
|
+ uint16_t data = m_gvram_read_callback(((y * 512) + x + xscr) & 0x3ffff, 0xffff);
|
|
+ m_gvram_write_callback(((y * 512) + x + xscr) & 0x3ffff, data & mask, 0xffff);
|
|
+ data = m_gvram_read_callback(((y * 512) + x + xscr + 256) & 0x3ffff, 0xffff);
|
|
+ m_gvram_write_callback(((y * 512) + x + xscr + 256) & 0x3ffff, data & mask, mask);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ for (int x = 0; x < m_width; x++)
|
|
+ {
|
|
+ uint16_t data = m_gvram_read_callback(((y * 512) + x + xscr) & 0x3ffff, 0xffff);
|
|
+ m_gvram_write_callback(((y * 512) + x + xscr) & 0x3ffff, data & mask, 0xffff);
|
|
+ }
|
|
+ }
|
|
}
|
|
- else
|
|
- m_operation &= ~param;
|
|
}
|
|
|
|
void x68k_crtc_device::refresh_mode()
|
|
@@ -215,9 +265,6 @@
|
|
m_hblank = hstate;
|
|
m_hsync_callback(!m_hblank);
|
|
|
|
- if (m_operation & 8)
|
|
- text_copy((m_reg[22] & 0xff00) >> 8, (m_reg[22] & 0x00ff), (m_reg[21] & 0xf));
|
|
-
|
|
int scan = screen().vpos();
|
|
if (hstate == 1)
|
|
{
|
|
@@ -228,6 +275,18 @@
|
|
}
|
|
if (hstate == 0)
|
|
{
|
|
+ // Text raster copy, done ONCE per horizontal period at the start of
|
|
+ // the horizontal front porch (this callback fires at m_hend, the
|
|
+ // horizontal display end). Operation port bit 3 is a level-sensitive
|
|
+ // switch that the CRTC never clears and that has no busy indication:
|
|
+ // while it is set, one raster block is copied every scanline. Running
|
|
+ // this at the top of the callback instead copied on BOTH hsync edges,
|
|
+ // i.e. twice per scanline -- harmless while R22 is stable, but wrong
|
|
+ // for the documented idiom of leaving bit 3 on and pacing R22 updates
|
|
+ // against hsync.
|
|
+ if (m_operation & 8)
|
|
+ text_copy((m_reg[22] & 0xff00) >> 8, (m_reg[22] & 0x00ff), (m_reg[21] & 0xf));
|
|
+
|
|
if (scan == (m_vtotal - 1))
|
|
scan = 0;
|
|
else
|
|
@@ -278,6 +337,30 @@
|
|
if (val == 0) // V-DISP off
|
|
{
|
|
m_vblank = 0;
|
|
+ // This branch is the VDISP 0->1 edge (it asserts m_vdisp_callback
|
|
+ // below), which is where the graphic high-speed clear is serviced.
|
|
+ // A running clear counts down one frame; otherwise a reservation
|
|
+ // made via the operation port starts here. Only one of the two
|
|
+ // happens per frame, so a clear reserved during the frame in which
|
|
+ // a previous clear is still running does not start until that one
|
|
+ // has finished -- which is what makes a write immediately after
|
|
+ // busy drops miss the next frame on hardware.
|
|
+ if (m_clear_frames != 0)
|
|
+ {
|
|
+ m_clear_frames--;
|
|
+ }
|
|
+ else if (m_clear_standby)
|
|
+ {
|
|
+ m_clear_standby = false;
|
|
+ // One vertical period, and no interlace special case: refresh_mode()
|
|
+ // divides the vertical timing by m_vmultiple (0.5 when interlaced),
|
|
+ // so an interlaced screen already spans BOTH fields. One VDISP-to-
|
|
+ // VDISP here is therefore already the two vertical periods an
|
|
+ // interlaced clear occupies on hardware.
|
|
+ m_clear_frames = 1;
|
|
+ if (m_reg[21] & 0xf)
|
|
+ do_fast_clear();
|
|
+ }
|
|
vblank_line = m_vend;
|
|
if (vblank_line > m_vtotal)
|
|
vblank_line = m_vtotal;
|
|
@@ -412,54 +495,14 @@
|
|
break;
|
|
case 576: // operation register
|
|
m_operation = data & ~2;
|
|
- if ((data & 0x02) && (m_reg[21] & 0xf)) // high-speed graphic screen clear
|
|
- {
|
|
- // this is based on the docs except for the higher color depth modes which isn't
|
|
- // explicitly described this way but is likely based on how the plane scroll works
|
|
- // XXX: not sufficiently tested especially in hires modes
|
|
- // it seems that it only uses the 0 page scroll registers for where to clear see atomrobo
|
|
- uint16_t xscr = xscr_gfx(0) & 0x1ff;
|
|
- uint16_t yscr = yscr_gfx(0) & 0x1ff;
|
|
- uint16_t mask = 0;
|
|
- for (int page = 0; page < 4; page++)
|
|
- {
|
|
- if (!(m_reg[21] & (1 << page)))
|
|
- mask |= (0xf << (page * 4));
|
|
- }
|
|
- for (int y = yscr; y < (m_height + yscr); y++)
|
|
- {
|
|
- if (is_1024x1024())
|
|
- {
|
|
- if (m_width > 256)
|
|
- {
|
|
- for (int x = 0; x < 512; x++)
|
|
- {
|
|
- uint16_t data = m_gvram_read_callback(((y * 512) + x) & 0x3ffff, 0xffff);
|
|
- m_gvram_write_callback(((y * 512) + x) & 0x3ffff, data & mask, 0xffff);
|
|
- }
|
|
- }
|
|
- else
|
|
- {
|
|
- for (int x = 0; x < 256; x++)
|
|
- {
|
|
- uint16_t data = m_gvram_read_callback(((y * 512) + x + xscr) & 0x3ffff, 0xffff);
|
|
- m_gvram_write_callback(((y * 512) + x + xscr) & 0x3ffff, data & mask, 0xffff);
|
|
- data = m_gvram_read_callback(((y * 512) + x + xscr + 256) & 0x3ffff, 0xffff);
|
|
- m_gvram_write_callback(((y * 512) + x + xscr + 256) & 0x3ffff, data & mask, mask);
|
|
- }
|
|
- }
|
|
- }
|
|
- else
|
|
- {
|
|
- for (int x = 0; x < m_width; x++)
|
|
- {
|
|
- uint16_t data = m_gvram_read_callback(((y * 512) + x + xscr) & 0x3ffff, 0xffff);
|
|
- m_gvram_write_callback(((y * 512) + x + xscr) & 0x3ffff, data & mask, 0xffff);
|
|
- }
|
|
- }
|
|
- }
|
|
- }
|
|
- if (data & 0x02) m_operation_end_timer->adjust(attotime::from_msec(5), 0x02); // time taken to do operation is a complete guess.
|
|
+ // Bit 1 only RESERVES the graphic high-speed clear -- it does not
|
|
+ // perform it. Hardware latches the request and starts the clear at the
|
|
+ // next vertical display start; see vblank_irq(). Writing 0 cannot
|
|
+ // cancel or abort a reservation that has already been made, and a
|
|
+ // request made while a clear is already running is dropped rather than
|
|
+ // queued: the reservation only takes when bit 1 reads back as 0.
|
|
+ if ((data & 0x02) && m_clear_frames == 0)
|
|
+ m_clear_standby = true;
|
|
break;
|
|
}
|
|
// LOG("%s CRTC: Wrote %04x to CRTC register %i\n",machine().describe_context(), data, offset);
|
|
@@ -493,7 +536,14 @@
|
|
}
|
|
}
|
|
if (offset == 576) // operation port, operation bits are set to 0 when operation is complete
|
|
- return m_operation;
|
|
+ {
|
|
+ // Bit 1 reads as the graphic high-speed clear's busy state: it is set
|
|
+ // from the vertical display start at which the clear begins until the
|
|
+ // vertical display start one frame later (two when interlaced). The
|
|
+ // documented wait sequence is to poll for bit 1 becoming set (start)
|
|
+ // and then for it becoming clear again (end).
|
|
+ return m_operation | (m_clear_frames != 0 ? 0x02 : 0x00);
|
|
+ }
|
|
// LOG("CRTC: [%08x] Read from unknown CRTC register %i\n",activecpu_get_pc(),offset);
|
|
return 0xffff;
|
|
}
|