summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/bus/nubus/nubus_specpdq.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/bus/nubus/nubus_specpdq.cpp')
-rw-r--r--src/devices/bus/nubus/nubus_specpdq.cpp783
1 files changed, 509 insertions, 274 deletions
diff --git a/src/devices/bus/nubus/nubus_specpdq.cpp b/src/devices/bus/nubus/nubus_specpdq.cpp
index c00938c6102..c496fa77d05 100644
--- a/src/devices/bus/nubus/nubus_specpdq.cpp
+++ b/src/devices/bus/nubus/nubus_specpdq.cpp
@@ -1,53 +1,138 @@
// license:BSD-3-Clause
-// copyright-holders:R. Belmont
+// copyright-holders:R. Belmont, Vas Crabb
/***************************************************************************
SuperMac Spectrum PDQ video card
- Accelerated only in 256 color mode. Accleration is not yet emulated
- properly (pattern fill works but has glitches). Use in B&W or 16 colors
- for full functionality right now.
+ Accelerated only in 256 color mode.
blitter info:
- ctrl 1 = ?
- ctrl 2 = low 3 bits of Y position in bits 3-5, low 3 bits of X position in bits 0-2
- ctrl 3 = width
- ctrl 4 = height
- ctrl 5 = ?
- ctrl 6 = VRAM offset * 4
- ctrl 7 = command/execute (00000002 for pattern fill, 00000100 for copy)
+ 06 = ?
+ 07 = command - 002 = pattern fill, 100/101 = copy forward/backward
+ 08 = pattern Y offset * 8
+ 09 = VRAM destination * 4
+ 0a = VRAM source * 4
+ 0b = height (inclusive)
+ 0e = width (exclusive)
Busy flag at Fs800000 (bit 8)
- There is 256 bytes of pattern RAM arranged as 32 pixels horizontally by 8
- vertically.
+ There is 256 bytes of pattern RAM arranged as 32 pixels horizontally by
+ 8 vertically.
+
+ TODO:
+ * Having no alternate oscillator installed is not emulated.
+ * Work out how active line length is configured.
+ * Alternate oscillator calibration is currently failing. Fixing this
+ probably requires a complete cycle-accurate Mac II.
***************************************************************************/
#include "emu.h"
#include "nubus_specpdq.h"
+
+#include "supermac.h"
+
+#include "layout/generic.h"
#include "screen.h"
+#include <algorithm>
+
//#define VERBOSE 1
#include "logmacro.h"
-#define SPECPDQ_SCREEN_NAME "specpdq_screen"
+#define SPECPDQ_SCREEN_NAME "screen"
#define SPECPDQ_ROM_REGION "specpdq_rom"
-#define VRAM_SIZE (0x400000)
+#define VRAM_SIZE (0x40'0000)
-ROM_START( specpdq )
- ROM_REGION(0x10000, SPECPDQ_ROM_REGION, 0)
- ROM_LOAD( "specpdq.bin", 0x000000, 0x010000, CRC(82a35f78) SHA1(9511c2df47140f4279196d3b8836b53429879dd9) )
-ROM_END
+
+namespace {
//**************************************************************************
-// GLOBAL VARIABLES
+// TYPE DEFINITIONS
//**************************************************************************
-DEFINE_DEVICE_TYPE(NUBUS_SPECPDQ, nubus_specpdq_device, "nb_spdq", "SuperMac Spectrum PDQ video card")
+class nubus_specpdq_device :
+ public device_t,
+ public device_nubus_card_interface,
+ public device_video_interface,
+ public device_palette_interface
+{
+public:
+ // construction/destruction
+ nubus_specpdq_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+protected:
+ nubus_specpdq_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
+
+ // device-level overrides
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+ // optional information overrides
+ virtual void device_add_mconfig(machine_config &config) override;
+ virtual const tiny_rom_entry *device_rom_region() const override;
+ virtual ioport_constructor device_input_ports() const override;
+
+ // palette implementation
+ virtual uint32_t palette_entries() const noexcept override;
+
+ TIMER_CALLBACK_MEMBER(vbl_tick);
+
+private:
+ uint32_t specpdq_r(offs_t offset, uint32_t mem_mask = ~0);
+ void specpdq_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0);
+ uint32_t vram_r(offs_t offset, uint32_t mem_mask = ~0);
+ void vram_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0);
+
+ void blitter_pattern_fill();
+ void blitter_copy_forward();
+ void blitter_copy_backward();
+
+ void update_crtc();
+
+ uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
+
+ required_ioport m_userosc;
+ emu_timer *m_timer;
+
+ supermac_spec_crtc m_crtc;
+ supermac_spec_shift_reg m_shiftreg;
+
+ std::vector<uint32_t> m_vram;
+ uint32_t m_mode, m_vbl_disable;
+ uint32_t m_colors[3], m_count, m_clutoffs;
+
+ uint16_t m_stride;
+ uint16_t m_vint;
+ uint8_t m_hdelay;
+ uint8_t m_osc;
+
+ uint16_t m_blit_stride;
+ uint32_t m_blit_src, m_blit_dst;
+ uint32_t m_blit_width, m_blit_height;
+ uint8_t m_blit_patoffs;
+ uint32_t m_blit_pat[64];
+
+ uint32_t m_7xxxxx_regs[0x100000 / 4];
+};
+
+
+INPUT_PORTS_START( specpdq )
+ PORT_START("USEROSC")
+ PORT_CONFNAME(0x07, 0x00, "Alternate oscillator")
+ PORT_CONFSETTING( 0x00, "55.00 MHz (SuperMac 16\")")
+ PORT_CONFSETTING( 0x01, "57.28 MHz (Apple Portrait)")
+ PORT_CONFSETTING( 0x02, "64.00 MHz (SuperMac 19\" 60hz)")
+INPUT_PORTS_END
+
+ROM_START( specpdq )
+ ROM_REGION(0x10000, SPECPDQ_ROM_REGION, 0)
+ ROM_LOAD( "specpdq.bin", 0x000000, 0x010000, CRC(82a35f78) SHA1(9511c2df47140f4279196d3b8836b53429879dd9) )
+ROM_END
//-------------------------------------------------
@@ -56,13 +141,12 @@ DEFINE_DEVICE_TYPE(NUBUS_SPECPDQ, nubus_specpdq_device, "nb_spdq", "SuperMac Spe
void nubus_specpdq_device::device_add_mconfig(machine_config &config)
{
+ config.set_default_layout(layout_monitors);
+
screen_device &screen(SCREEN(config, SPECPDQ_SCREEN_NAME, SCREEN_TYPE_RASTER));
screen.set_screen_update(FUNC(nubus_specpdq_device::screen_update));
- screen.set_raw(25175000, 800, 0, 640, 525, 0, 480);
- screen.set_size(1280, 1024);
- screen.set_visarea(0, 1152-1, 0, 844-1);
-
- PALETTE(config, m_palette).set_entries(256);
+ screen.set_raw(100.000_MHz_XTAL, 1'456, 108, 1'260, 915, 39, 909);
+ screen.set_video_attributes(VIDEO_UPDATE_SCANLINE);
}
//-------------------------------------------------
@@ -74,6 +158,25 @@ const tiny_rom_entry *nubus_specpdq_device::device_rom_region() const
return ROM_NAME( specpdq );
}
+//-------------------------------------------------
+// input_ports - device-specific I/O ports
+//-------------------------------------------------
+
+ioport_constructor nubus_specpdq_device::device_input_ports() const
+{
+ return INPUT_PORTS_NAME( specpdq );
+}
+
+//-------------------------------------------------
+// palette_entries - entries in color palette
+//-------------------------------------------------
+
+uint32_t nubus_specpdq_device::palette_entries() const noexcept
+{
+ return 256;
+}
+
+
//**************************************************************************
// LIVE DEVICE
//**************************************************************************
@@ -89,11 +192,12 @@ nubus_specpdq_device::nubus_specpdq_device(const machine_config &mconfig, const
nubus_specpdq_device::nubus_specpdq_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_video_interface(mconfig, *this),
device_nubus_card_interface(mconfig, *this),
- m_vram32(nullptr), m_mode(0), m_vbl_disable(0), m_count(0), m_clutoffs(0), m_timer(nullptr),
- m_width(0), m_height(0), m_patofsx(0), m_patofsy(0), m_vram_addr(0), m_vram_src(0),
- m_palette(*this, "palette")
+ device_video_interface(mconfig, *this),
+ device_palette_interface(mconfig, *this),
+ m_userosc(*this, "USEROSC"),
+ m_timer(nullptr),
+ m_mode(0)
{
set_screen(*this, SPECPDQ_SCREEN_NAME);
}
@@ -104,21 +208,38 @@ nubus_specpdq_device::nubus_specpdq_device(const machine_config &mconfig, device
void nubus_specpdq_device::device_start()
{
- uint32_t slotspace;
+ install_declaration_rom(SPECPDQ_ROM_REGION);
- install_declaration_rom(this, SPECPDQ_ROM_REGION);
+ uint32_t const slotspace = get_slotspace();
+ LOG("[specpdq %p] slotspace = %x\n", this, slotspace);
- slotspace = get_slotspace();
-
-// logerror("[specpdq %p] slotspace = %x\n", this, slotspace);
-
- m_vram.resize(VRAM_SIZE);
- m_vram32 = (uint32_t *)&m_vram[0];
+ m_vram.resize(VRAM_SIZE / sizeof(uint32_t));
nubus().install_device(slotspace, slotspace+VRAM_SIZE-1, read32s_delegate(*this, FUNC(nubus_specpdq_device::vram_r)), write32s_delegate(*this, FUNC(nubus_specpdq_device::vram_w)));
nubus().install_device(slotspace+0x400000, slotspace+0xfbffff, read32s_delegate(*this, FUNC(nubus_specpdq_device::specpdq_r)), write32s_delegate(*this, FUNC(nubus_specpdq_device::specpdq_w)));
- m_timer = timer_alloc(0, nullptr);
- m_timer->adjust(screen().time_until_pos(843, 0), 0);
+ m_timer = timer_alloc(FUNC(nubus_specpdq_device::vbl_tick), this);
+
+ m_crtc.register_save(*this);
+ m_shiftreg.register_save(*this);
+
+ save_item(NAME(m_vram));
+ save_item(NAME(m_mode));
+ save_item(NAME(m_vbl_disable));
+ save_item(NAME(m_colors));
+ save_item(NAME(m_count));
+ save_item(NAME(m_clutoffs));
+ save_item(NAME(m_stride));
+ save_item(NAME(m_vint));
+ save_item(NAME(m_hdelay));
+ save_item(NAME(m_osc));
+ save_item(NAME(m_blit_stride));
+ save_item(NAME(m_blit_src));
+ save_item(NAME(m_blit_dst));
+ save_item(NAME(m_blit_width));
+ save_item(NAME(m_blit_height));
+ save_item(NAME(m_blit_patoffs));
+ save_item(NAME(m_blit_pat));
+ save_item(NAME(m_7xxxxx_regs));
}
//-------------------------------------------------
@@ -127,26 +248,41 @@ void nubus_specpdq_device::device_start()
void nubus_specpdq_device::device_reset()
{
+ m_crtc.reset();
+ m_shiftreg.reset();
+
+ std::fill(m_vram.begin(), m_vram.end(), 0);
+ m_mode = 0;
+ m_vbl_disable = 1;
+ std::fill(std::begin(m_colors), std::end(m_colors), 0);
m_count = 0;
m_clutoffs = 0;
- m_vbl_disable = 1;
- m_mode = 0;
- memset(&m_vram[0], 0, VRAM_SIZE);
- memset(m_palette_val, 0, sizeof(m_palette_val));
- m_palette_val[0] = rgb_t(255, 255, 255);
- m_palette_val[0x80] = rgb_t(0, 0, 0);
+ m_stride = 0;
+ m_vint = 0;
+ m_hdelay = 0;
+ m_osc = 0;
+
+ m_blit_stride = 0;
+ m_blit_src = 0;
+ m_blit_dst = 0;
+ m_blit_width = 0;
+ m_blit_height = 0;
+ m_blit_patoffs = 0;
+ std::fill(std::begin(m_blit_pat), std::end(m_blit_pat), 0);
+
+ std::fill(std::begin(m_7xxxxx_regs), std::end(m_7xxxxx_regs), 0);
}
-void nubus_specpdq_device::device_timer(emu_timer &timer, device_timer_id tid, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(nubus_specpdq_device::vbl_tick)
{
if (!m_vbl_disable)
{
raise_slot_irq();
}
- m_timer->adjust(screen().time_until_pos(843, 0), 0);
+ m_timer->adjust(screen().time_until_pos(m_vint));
}
/***************************************************************************
@@ -155,77 +291,180 @@ void nubus_specpdq_device::device_timer(emu_timer &timer, device_timer_id tid, i
***************************************************************************/
+void nubus_specpdq_device::update_crtc()
+{
+ XTAL oscillator = 100.000_MHz_XTAL; // no default constructor
+ switch (m_osc)
+ {
+ case 0:
+ switch (m_userosc->read())
+ {
+ case 0:
+ oscillator = 55.00_MHz_XTAL;
+ break;
+ case 1:
+ oscillator = 57.28_MHz_XTAL;
+ break;
+ case 2:
+ oscillator = 64.00_MHz_XTAL;
+ break;
+ default:
+ throw emu_fatalerror("%s: specpdq: invalid user oscillator selection %d\n", tag(), m_userosc->read());
+ }
+ break;
+ case 1:
+ oscillator = 80.00_MHz_XTAL;
+ break;
+ case 2:
+ oscillator = 100.00_MHz_XTAL;
+ break;
+ case 3:
+ oscillator = 30.24_MHz_XTAL;
+ break;
+ }
+
+ // for some reason you temporarily get invalid screen parameters - ignore them
+ if (m_crtc.valid(*this))
+ {
+ rectangle active(
+ m_crtc.h_start(16) + (m_hdelay * 4),
+ m_crtc.h_end(16) - 1,
+ m_crtc.v_start(),
+ m_crtc.v_end() - 1);
+
+ // FIXME: work out how it actually configures the RAMDAC end-of-line
+ // this is a horrible hack
+ if (active.width() < 832)
+ active.set_width(640);
+ else if (active.width() < 1024)
+ active.set_width(832);
+ else if (active.width() < 1152)
+ active.set_width(1024);
+ else
+ active.set_width(1152);
+
+ screen().configure(
+ m_crtc.h_total(16),
+ m_crtc.v_total(),
+ active,
+ m_crtc.frame_time(16, oscillator));
+
+ m_timer->adjust(screen().time_until_pos(m_vint + m_crtc.v_start() - 1));
+ }
+}
+
uint32_t nubus_specpdq_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
- // first time? kick off the VBL timer
- uint8_t const *const vram = &m_vram[0x9000];
+ auto const screenbase = util::big_endian_cast<uint8_t const>(&m_vram[0]) + 0x9000;
+
+ int const hstart = m_crtc.h_start(16);
+ int const width = m_crtc.h_active(16);
+ int const vstart = m_crtc.v_start();
+ int const vend = m_crtc.v_end();
+ int const hdelay = m_hdelay * 4;
switch (m_mode)
{
case 0: // 1 bpp
- for (int y = 0; y < 844; y++)
+ for (int y = cliprect.top(); y <= cliprect.bottom(); y++)
{
- uint32_t *scanline = &bitmap.pix(y);
- for (int x = 0; x < 1152/8; x++)
+ uint32_t *scanline = &bitmap.pix(y, hstart);
+ if ((y >= vstart) && (y < vend))
+ {
+ scanline = std::fill_n(scanline, hdelay, 0);
+ auto const rowbase = screenbase + ((y - vstart) * m_stride * 4);
+ for (int x = 0; x < ((width - hdelay + 7) / 8); x++)
+ {
+ uint8_t const pixels = rowbase[x];
+
+ *scanline++ = pen_color((pixels << 0) & 0x80);
+ *scanline++ = pen_color((pixels << 1) & 0x80);
+ *scanline++ = pen_color((pixels << 2) & 0x80);
+ *scanline++ = pen_color((pixels << 3) & 0x80);
+ *scanline++ = pen_color((pixels << 4) & 0x80);
+ *scanline++ = pen_color((pixels << 5) & 0x80);
+ *scanline++ = pen_color((pixels << 6) & 0x80);
+ *scanline++ = pen_color((pixels << 7) & 0x80);
+ }
+ }
+ else
{
- uint8_t const pixels = vram[(y * 512) + (BYTE4_XOR_BE(x))];
-
- *scanline++ = m_palette_val[(pixels&0x80)];
- *scanline++ = m_palette_val[((pixels<<1)&0x80)];
- *scanline++ = m_palette_val[((pixels<<2)&0x80)];
- *scanline++ = m_palette_val[((pixels<<3)&0x80)];
- *scanline++ = m_palette_val[((pixels<<4)&0x80)];
- *scanline++ = m_palette_val[((pixels<<5)&0x80)];
- *scanline++ = m_palette_val[((pixels<<6)&0x80)];
- *scanline++ = m_palette_val[((pixels<<7)&0x80)];
+ std::fill_n(scanline, width, 0);
}
}
break;
case 1: // 2 bpp
- for (int y = 0; y < 844; y++)
+ for (int y = cliprect.top(); y <= cliprect.bottom(); y++)
{
- uint32_t *scanline = &bitmap.pix(y);
- for (int x = 0; x < 1152/4; x++)
+ uint32_t *scanline = &bitmap.pix(y, hstart);
+ if ((y >= vstart) && (y < vend))
{
- uint8_t const pixels = vram[(y * 512) + (BYTE4_XOR_BE(x))];
+ scanline = std::fill_n(scanline, hdelay, 0);
+ auto const rowbase = screenbase + ((y - vstart) * m_stride * 4);
+ for (int x = 0; x < ((width - hdelay) / 4); x++)
+ {
+ uint8_t const pixels = rowbase[x];
- *scanline++ = m_palette_val[(pixels&0xc0)];
- *scanline++ = m_palette_val[((pixels<<2)&0xc0)];
- *scanline++ = m_palette_val[((pixels<<4)&0xc0)];
- *scanline++ = m_palette_val[((pixels<<6)&0xc0)];
+ *scanline++ = pen_color((pixels << 0) & 0xc0);
+ *scanline++ = pen_color((pixels << 2) & 0xc0);
+ *scanline++ = pen_color((pixels << 4) & 0xc0);
+ *scanline++ = pen_color((pixels << 6) & 0xc0);
+ }
+ }
+ else
+ {
+ std::fill_n(scanline, width, 0);
}
}
break;
case 2: // 4 bpp
- for (int y = 0; y < 844; y++)
+ for (int y = cliprect.top(); y <= cliprect.bottom(); y++)
{
- uint32_t *scanline = &bitmap.pix(y);
- for (int x = 0; x < 1152/2; x++)
+ uint32_t *scanline = &bitmap.pix(y, hstart);
+ if ((y >= vstart) && (y < vend))
{
- uint8_t const pixels = vram[(y * 1024) + (BYTE4_XOR_BE(x))];
+ scanline = std::fill_n(scanline, hdelay, 0);
+ auto const rowbase = screenbase + ((y - vstart) * m_stride * 4);
+ for (int x = 0; x < ((width - hdelay) / 2); x++)
+ {
+ uint8_t const pixels = rowbase[x];
- *scanline++ = m_palette_val[(pixels&0xf0)];
- *scanline++ = m_palette_val[((pixels<<4)&0xf0)];
+ *scanline++ = pen_color((pixels << 0) & 0xf0);
+ *scanline++ = pen_color((pixels << 4) & 0xf0);
+ }
+ }
+ else
+ {
+ std::fill_n(scanline, width, 0);
}
}
break;
case 3: // 8 bpp
- for (int y = 0; y < 844; y++)
+ for (int y = cliprect.top(); y <= cliprect.bottom(); y++)
{
- uint32_t *scanline = &bitmap.pix(y);
- for (int x = 0; x < 1152; x++)
+ uint32_t *scanline = &bitmap.pix(y, hstart);
+ if ((y >= vstart) && (y < vend))
+ {
+ scanline = std::fill_n(scanline, hdelay, 0);
+ auto const rowbase = screenbase + ((y - vstart) * m_stride * 4);
+ for (int x = 0; x < (width - hdelay); x++)
+ {
+ uint8_t const pixels = rowbase[x];
+ *scanline++ = pen_color(pixels);
+ }
+ }
+ else
{
- uint8_t const pixels = vram[(y * 1152) + (BYTE4_XOR_BE(x))];
- *scanline++ = m_palette_val[pixels];
+ std::fill_n(scanline, width, 0);
}
}
break;
default:
- fatalerror("specpdq: unknown video mode %d\n", m_mode);
+ throw emu_fatalerror("specpdq: unknown video mode %d\n", m_mode);
}
return 0;
}
@@ -237,10 +476,31 @@ void nubus_specpdq_device::specpdq_w(offs_t offset, uint32_t data, uint32_t mem_
COMBINE_DATA(&m_7xxxxx_regs[offset-0xc0000]);
}
- switch (offset)
+ if ((offset >= 0xc0000) && (offset <= 0xc002a))
+ {
+ m_crtc.write(*this, offset - 0xc0000, data >> 24);
+ update_crtc();
+ }
+ else if ((offset >= 0x181000) && (offset <= 0x18103f))
+ {
+ // 256 pixels worth at 8 bpp
+ m_blit_pat[offset & 0x3f] = ~data;
+ }
+ else switch (offset)
{
- case 0xc0054: // mode 1
- LOG("%x to mode1\n", data);
+ case 0xc0030:
+ case 0xc0032:
+ m_vint &= BIT(offset, 1) ? 0x00ff : 0xff00;
+ m_vint |= (~data & 0xff000000) >> (BIT(offset, 1) ? 16 : 24);
+ update_crtc();
+ LOG("%s: %u to vint\n", machine().describe_context(), m_vint);
+ break;
+
+ case 0xc0054:
+ case 0xc0056:
+ m_stride &= BIT(offset, 1) ? 0x00ff : 0xff00;
+ m_stride |= (~data & 0xff000000) >> (BIT(offset, 1) ? 16 : 24);
+ LOG("%s: %u to stride\n", machine().describe_context(), m_stride);
break;
case 0xc005c: // interrupt control
@@ -258,227 +518,120 @@ void nubus_specpdq_device::specpdq_w(offs_t offset, uint32_t data, uint32_t mem_
case 0xc005e: // not sure, interrupt related?
break;
- case 0xc007a:
- LOG("%x to mode2\n", data);
-
- switch (data)
- {
- case 0xff7fffff:
- m_mode = 0;
- break;
-
- case 0xfeffffff:
- m_mode = 2;
- break;
-
- case 0xfedfffff:
- m_mode = 3;
- break;
- }
+ case 0xc006a:
+ LOG("%s: %u to hdelay\n", machine().describe_context(), ~data & 0xff);
+ m_hdelay = ~data & 0xff;
+ update_crtc();
+ break;
- LOG("m_mode = %d\n", m_mode);
+ case 0xc0078:
+ case 0xc007a:
+ m_blit_stride &= BIT(offset, 1) ? 0x00ff : 0xff00;
+ m_blit_stride |= (~data & 0xff000000) >> (BIT(offset, 1) ? 16 : 24);
+ LOG("%s: %u to blitter stride\n", machine().describe_context(), m_blit_stride);
break;
case 0x120000: // DAC address
- LOG("%08x to DAC control %s\n", data,machine().describe_context());
- m_clutoffs = ((data>>8)&0xff)^0xff;
+ LOG("%s: %08x to DAC control\n", machine().describe_context(), data);
+ m_clutoffs = ~data & 0xff;
break;
case 0x120001: // DAC data
- m_colors[m_count++] = ((data>>8)&0xff)^0xff;
+ m_colors[m_count++] = ~(data >> 8) & 0xff;
if (m_count == 3)
{
LOG("RAMDAC: color %d = %02x %02x %02x %s\n", m_clutoffs, m_colors[0], m_colors[1], m_colors[2], machine().describe_context());
- m_palette->set_pen_color(m_clutoffs, rgb_t(m_colors[0], m_colors[1], m_colors[2]));
- m_palette_val[m_clutoffs] = rgb_t(m_colors[0], m_colors[1], m_colors[2]);
- m_clutoffs++;
- if (m_clutoffs > 255)
- {
- m_clutoffs = 0;
- }
+ set_pen_color(m_clutoffs, rgb_t(m_colors[0], m_colors[1], m_colors[2]));
+ m_clutoffs = (m_clutoffs + 1) & 0xff;
m_count = 0;
}
break;
- // blitter texture? pattern? 256 pixels worth at 8bpp
- case 0x181000:
- case 0x181001:
- case 0x181002:
- case 0x181003:
- case 0x181004:
- case 0x181005:
- case 0x181006:
- case 0x181007:
- case 0x181008:
- case 0x181009:
- case 0x18100a:
- case 0x18100b:
- case 0x18100c:
- case 0x18100d:
- case 0x18100e:
- case 0x18100f:
- case 0x181010:
- case 0x181011:
- case 0x181012:
- case 0x181013:
- case 0x181014:
- case 0x181015:
- case 0x181016:
- case 0x181017:
- case 0x181018:
- case 0x181019:
- case 0x18101a:
- case 0x18101b:
- case 0x18101c:
- case 0x18101d:
- case 0x18101e:
- case 0x18101f:
- case 0x181020:
- case 0x181021:
- case 0x181022:
- case 0x181023:
- case 0x181024:
- case 0x181025:
- case 0x181026:
- case 0x181027:
- case 0x181028:
- case 0x181029:
- case 0x18102a:
- case 0x18102b:
- case 0x18102c:
- case 0x18102d:
- case 0x18102e:
- case 0x18102f:
- case 0x181030:
- case 0x181031:
- case 0x181032:
- case 0x181033:
- case 0x181034:
- case 0x181035:
- case 0x181036:
- case 0x181037:
- case 0x181038:
- case 0x181039:
- case 0x18103a:
- case 0x18103b:
- case 0x18103c:
- case 0x18103d:
- case 0x18103e:
- case 0x18103f:
- if(offset == 0x181000) {
- machine().debug_break();
- LOG("Pattern %08x @ %x\n", data ^ 0xffffffff, offset);
+ case 0x140000:
+ m_shiftreg.write_data(*this, data);
+ if (m_shiftreg.ready())
+ {
+ switch (m_shiftreg.select())
+ {
+ case 0:
+ // bit depth in low bits, other bits unknown
+ LOG("%s: %x to mode\n", machine().describe_context(), m_shiftreg.value());
+ m_mode = m_shiftreg.value() & 0x03;
+ break;
+ default:
+ LOG("%s: %x to param %x\n", machine().describe_context(), m_shiftreg.value(), m_shiftreg.select());
+ }
}
- m_fillbytes[((offset&0x3f)*4)] = ((data>>24) & 0xff) ^ 0xff;
- m_fillbytes[((offset&0x3f)*4)+1] = ((data>>16) & 0xff) ^ 0xff;
- m_fillbytes[((offset&0x3f)*4)+2] = ((data>>8) & 0xff) ^ 0xff;
- m_fillbytes[((offset&0x3f)*4)+3] = (data& 0xff) ^ 0xff;
break;
- // blitter control
- case 0x182006:
- LOG("%08x (%d) to blitter ctrl 1 %s rectangle\n", data^0xffffffff, data^0xffffffff, machine().describe_context());
+ case 0x160000:
+ case 0x160001:
+ m_osc &= ~(1 << (BIT(offset, 0)));
+ m_osc |= BIT(~data, 0) << BIT(offset, 0);
+ LOG("%s: %u to osc\n", machine().describe_context(), m_osc);
break;
- case 0x182008:
- LOG("%08x (%d) to blitter ctrl 2 %s rectangle\n", data^0xffffffff, data^0xffffffff, machine().describe_context());
- m_patofsx = (data ^ 0xffffffff) & 7;
- m_patofsy = ((data ^ 0xffffffff)>>3) & 7;
+ case 0x160007:
+ m_shiftreg.write_control(*this, data);
break;
- case 0x18200e:
- LOG("%08x (%d) to blitter ctrl 3 %s\n", data^0xffffffff, data^0xffffffff, machine().describe_context());
- m_width = data ^ 0xffffffff;
+ case 0x182006:
+ data = ~data;
+ LOG("%08x (%d) to blitter ctrl 1 %s rectangle\n", data, data, machine().describe_context());
break;
- case 0x18200b:
- LOG("%08x (%d) to blitter ctrl 4 %s\n", data^0xffffffff, data^0xffffffff, machine().describe_context());
- m_height = (data ^ 0xffffffff) & 0xffff;
+ case 0x182007:
+ data = ~data;
+ LOG("%s: %08x to blitter command\n", machine().describe_context(), data);
+ switch (data)
+ {
+ case 0x002:
+ blitter_pattern_fill();
+ break;
+ case 0x100:
+ blitter_copy_forward();
+ break;
+ case 0x101:
+ blitter_copy_backward();
+ break;
+ default:
+ logerror("Unknown blitter command %08x\n", data);
+ }
break;
- case 0x18200a:
- data ^= 0xffffffff;
- LOG("%08x to blitter ctrl 5 %s\n", data, machine().describe_context());
- m_vram_src = data>>2;
+ case 0x182008:
+ data = ~data;
+ LOG("%s: %08x (%d) to blitter ctrl 2 rectangle\n", machine().describe_context(), data, data);
+ m_blit_patoffs = (data >> 3) & 0x1fff;
break;
case 0x182009:
- data ^= 0xffffffff;
- LOG("%08x to blitter ctrl 6 %s\n", data, machine().describe_context());
- m_vram_addr = data>>2;
+ data = ~data;
+ LOG("%s: %08x to blitter destination\n", machine().describe_context(), data);
+ m_blit_dst = (data >> 2) & 0x3fffff;
break;
- case 0x182007:
- data ^= 0xffffffff;
- LOG("%08x to blitter ctrl 7 %s\n", data, machine().describe_context());
-
- // fill rectangle
- if (data == 2)
- {
- int x, y;
- uint8_t *vram = &m_vram[m_vram_addr & ~3];
-
- int ddx = m_vram_addr & 3;
-
- LOG("Fill rectangle with %02x %02x %02x %02x, adr %x (%d, %d) width %d height %d delta %d %d\n", m_fillbytes[0], m_fillbytes[1], m_fillbytes[2], m_fillbytes[3], m_vram_addr, m_vram_addr % 1152, m_vram_addr / 1152, m_width, m_height, m_patofsx, m_patofsy);
-
- for (y = 0; y <= m_height; y++)
- {
- for (x = 0; x <= m_width; x++)
- {
- vram[(y * 1152)+BYTE4_XOR_BE(x + ddx)] = m_fillbytes[((m_patofsx + x) & 0x1f)+(((m_patofsy + y) & 0x7) << 5)];
- }
- }
- }
- else if (data == 0x100)
- {
- int x, y;
- uint8_t *vram = &m_vram[m_vram_addr & ~3];
- uint8_t *vramsrc = &m_vram[m_vram_src & ~3];
-
- int sdx = m_vram_src & 3;
- int ddx = m_vram_addr & 3;
-
- LOG("Copy rectangle forwards, width %d height %d dst %x (%d, %d) src %x (%d, %d)\n", m_width, m_height, m_vram_addr, m_vram_addr % 1152, m_vram_addr / 1152, m_vram_src, m_vram_src % 1152, m_vram_src / 1152);
-
- for (y = 0; y <= m_height; y++)
- {
- for (x = 0; x <= m_width; x++)
- {
- vram[(y * 1152)+BYTE4_XOR_BE(x + ddx)] = vramsrc[(y * 1152)+BYTE4_XOR_BE(x + sdx)];
- }
- }
- (void)vramsrc; (void)sdx;
- }
- else if (data == 0x101)
- {
- int x, y;
- uint8_t *vram = &m_vram[m_vram_addr & ~3];
- uint8_t *vramsrc = &m_vram[m_vram_src & ~3];
-
- int sdx = m_vram_src & 3;
- int ddx = m_vram_addr & 3;
+ case 0x18200a:
+ data = ~data;
+ LOG("%s: %08x to blitter source\n", machine().describe_context(), data);
+ m_blit_src = (data >> 2) & 0x3fffff;
+ break;
- LOG("Copy rectangle backwards, width %d height %d dst %x (%d, %d) src %x (%d, %d)\n", m_width, m_height, m_vram_addr, m_vram_addr % 1152, m_vram_addr / 1152, m_vram_src, m_vram_src % 1152, m_vram_src / 1152);
+ case 0x18200b:
+ data = ~data;
+ LOG("%s: %08x (%d) to blitter height\n", machine().describe_context(), data, data);
+ m_blit_height = data;
+ break;
- for (y = 0; y < m_height; y++)
- {
- for (x = 0; x < m_width; x++)
- {
- vram[(-y * 1152)+BYTE4_XOR_BE(-x + ddx)] = vramsrc[(-y * 1152)+BYTE4_XOR_BE(-x + sdx)];
- }
- }
- (void)vramsrc; (void)sdx;
- }
- else
- {
- LOG("Unknown blitter command %08x\n", data);
- }
+ case 0x18200e:
+ data = ~data;
+ LOG("%s: %08x (%d) to blitter width\n", machine().describe_context(), data, data);
+ m_blit_width = data;
break;
default:
- LOG("specpdq_w: %08x @ %x (mask %08x %s)\n", data^0xffffffff, offset, mem_mask, machine().describe_context());
+ LOG("%s: specpdq_w: %08x @ %x (mask %08x)\n", machine().describe_context(), data^0xffffffff, offset, mem_mask);
break;
}
}
@@ -487,6 +640,24 @@ uint32_t nubus_specpdq_device::specpdq_r(offs_t offset, uint32_t mem_mask)
{
// if (offset != 0xc005c && offset != 0xc005e) logerror("specpdq_r: @ %x (mask %08x %s)\n", offset, mem_mask, machine().describe_context());
+ switch (offset)
+ {
+ case 0xc002c:
+ case 0xc002e:
+ /*
+ * FIXME: Oscillator calibration is failing.
+ * Set breakpoint at 0x2e0c on Mac II with card in
+ * slot 9 to catch user oscillator measurement. See the
+ * measured value in D0.b when PC = 0x2e48.
+ *
+ * Measured:
+ * 55.00 MHz 64 detected as 55.00 MHz
+ * 57.28 MHz 1 detected as 55.00 MHz
+ * 64.00 MHz 9 detected as 57.28 MHz
+ */
+ return ~((u32(screen().vpos()) << (BIT(offset, 1) ? 16 : 24)) & 0xff000000);
+ }
+
if (offset >= 0xc0000 && offset < 0x100000)
{
return m_7xxxxx_regs[offset-0xc0000];
@@ -497,11 +668,75 @@ uint32_t nubus_specpdq_device::specpdq_r(offs_t offset, uint32_t mem_mask)
void nubus_specpdq_device::vram_w(offs_t offset, uint32_t data, uint32_t mem_mask)
{
- data ^= 0xffffffff;
- COMBINE_DATA(&m_vram32[offset]);
+ data = ~data;
+ COMBINE_DATA(&m_vram[offset]);
}
uint32_t nubus_specpdq_device::vram_r(offs_t offset, uint32_t mem_mask)
{
- return m_vram32[offset] ^ 0xffffffff;
+ return ~m_vram[offset];
+}
+
+void nubus_specpdq_device::blitter_pattern_fill()
+{
+ auto const source = util::big_endian_cast<uint8_t const>(m_blit_pat);
+ auto const dest = util::big_endian_cast<uint8_t>(&m_vram[0]);
+ uint32_t const patofsx = m_blit_dst & 0x3;
+ uint32_t const stride = m_blit_stride * 4;
+ LOG("Fill rectangle with %02x %02x %02x %02x, adr %x (%d, %d) width %d height %d delta %d\n",
+ source[0], source[1], source[2], source[3],
+ m_blit_dst, m_blit_dst % (m_blit_stride * 4), m_blit_dst / (m_blit_stride * 4),
+ m_blit_width, m_blit_height, m_blit_patoffs);
+ for (int y = 0; y <= m_blit_height; y++)
+ {
+ for (int x = 0; x < m_blit_width; x++)
+ {
+ dest[(m_blit_dst + (y * stride) + x) & (VRAM_SIZE - 1)] = source[(((m_blit_patoffs + y) & 0x7) << 5) | ((patofsx + x) & 0x1f)];
+ }
+ }
+}
+
+void nubus_specpdq_device::blitter_copy_forward()
+{
+ LOG("Copy rectangle forwards, width %d height %d dst %x (%d, %d) src %x (%d, %d)\n",
+ m_blit_width, m_blit_height,
+ m_blit_dst, m_blit_dst % (m_blit_stride * 4), m_blit_dst / (m_blit_stride * 4),
+ m_blit_src, m_blit_src % (m_blit_stride * 4), m_blit_src / (m_blit_stride * 4));
+ auto const source = util::big_endian_cast<uint8_t const>(&m_vram[0]);
+ auto const dest = util::big_endian_cast<uint8_t>(&m_vram[0]);
+ uint32_t const stride = m_blit_stride * 4;
+ for (int y = 0; y <= m_blit_height; y++)
+ {
+ for (int x = 0; x < m_blit_width; x++)
+ {
+ dest[(m_blit_dst + (y * stride) + x) & (VRAM_SIZE - 1)] = source[(m_blit_src + (y * stride) + x) & (VRAM_SIZE - 1)];
+ }
+ }
+}
+
+void nubus_specpdq_device::blitter_copy_backward()
+{
+ LOG("Copy rectangle backwards, width %d height %d dst %x (%d, %d) src %x (%d, %d)\n",
+ m_blit_width, m_blit_height,
+ m_blit_dst, m_blit_dst % (m_blit_stride * 4), m_blit_dst / (m_blit_stride * 4),
+ m_blit_src, m_blit_src % (m_blit_stride * 4), m_blit_src / (m_blit_stride * 4));
+ auto const source = util::big_endian_cast<uint8_t const>(&m_vram[0]);
+ auto const dest = util::big_endian_cast<uint8_t>(&m_vram[0]);
+ uint32_t const stride = m_blit_stride * 4;
+ for (int y = 0; y <= m_blit_height; y++)
+ {
+ for (int x = 0; x < m_blit_width; x++)
+ {
+ dest[(m_blit_dst - (y * stride) - x) & (VRAM_SIZE - 1)] = source[(m_blit_src - (y * stride) - x) & (VRAM_SIZE - 1)];
+ }
+ }
}
+
+} // anonymous namespace
+
+
+//**************************************************************************
+// DEVICE TYPE DEFINITIONS
+//**************************************************************************
+
+DEFINE_DEVICE_TYPE_PRIVATE(NUBUS_SPECPDQ, device_nubus_card_interface, nubus_specpdq_device, "nb_spdq", "SuperMac Spectrum PDQ video card")