diff options
Diffstat (limited to 'src/devices/bus/nubus/nubus_specpdq.cpp')
-rw-r--r-- | src/devices/bus/nubus/nubus_specpdq.cpp | 783 |
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") |