diff options
author | Vas Crabb <vas@vastheman.com> | 2022-06-26 03:35:10 +1000 |
---|---|---|
committer | Vas Crabb <vas@vastheman.com> | 2022-06-26 03:43:11 +1000 |
commit | 7e6feb2c33b9ae1ec41a5d54ab0a825020faae8c (patch) | |
tree | 3f62bc48700d8fbfcee40ddd27f87e685f7737d7 /src/devices/bus | |
parent | af2b2c05364283141b103cb10446fa5a2b1db428 (diff) |
bus/nubus: Tidy up more loose ends with the Macintosh Display Cards.
* Implemented VRAM size selection.
* Added readback for most registers that are implemented.
* Made CRTC calculations more sensible.
* Added version strings from ROMs to device descriptions.
* Improved logging and made it more configurable.
Diffstat (limited to 'src/devices/bus')
-rw-r--r-- | src/devices/bus/nubus/nubus_48gc.cpp | 651 |
1 files changed, 363 insertions, 288 deletions
diff --git a/src/devices/bus/nubus/nubus_48gc.cpp b/src/devices/bus/nubus/nubus_48gc.cpp index 98cec4cd568..9646eb8c2e8 100644 --- a/src/devices/bus/nubus/nubus_48gc.cpp +++ b/src/devices/bus/nubus/nubus_48gc.cpp @@ -18,7 +18,6 @@ “Uncorrected Gamma” profile if you don’t like it. TODO: - * RAM size configuration. * Interlaced modes. ***************************************************************************/ @@ -31,11 +30,20 @@ #include <algorithm> -//#define VERBOSE 1 +#define LOG_CRTC (1U << 1) +#define LOG_RAMDAC (1U << 2) +#define LOG_CLUT (1U << 3) +#define LOG_CLKGEN (1U << 4) + +//#define VERBOSE (LOG_GENERAL | LOG_CRTC | LOG_RAMDAC | LOG_CLKGEN) +//#define LOG_OUTPUT_FUNC osd_printf_error #include "logmacro.h" +#define LOGCRTC(...) LOGMASKED(LOG_CRTC, __VA_ARGS__) +#define LOGRAMDAC(...) LOGMASKED(LOG_RAMDAC, __VA_ARGS__) +#define LOGCLUT(...) LOGMASKED(LOG_CLUT, __VA_ARGS__) +#define LOGCLKGEN(...) LOGMASKED(LOG_CLKGEN, __VA_ARGS__) -#define VRAM_SIZE (0x20'0000) // 2 megs, maxed out #define GC48_SCREEN_NAME "screen" #define GC48_ROM_REGION "48gc_rom" @@ -69,30 +77,34 @@ protected: uint32_t palette_entries() const override; private: + static constexpr offs_t VRAM_MAX = 0x10'0000 / 4; // chip supports 2M but card can only use 1M + TIMER_CALLBACK_MEMBER(vbl_tick); uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); void update_crtc(); - uint32_t jmfb_r(offs_t offset, uint32_t mem_mask = ~0); - uint32_t crtc_r(offs_t offset, uint32_t mem_mask = ~0); - void jmfb_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0); - void crtc_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0); - void ramdac_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0); - void clkgen_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0); + uint32_t jmfb_r(offs_t offset); + uint32_t crtc_r(offs_t offset); + uint32_t ramdac_r(offs_t offset); + void jmfb_w(offs_t offset, uint32_t data); + void crtc_w(offs_t offset, uint32_t data); + void ramdac_w(offs_t offset, uint32_t data); + void clkgen_w(offs_t offset, uint32_t data); uint32_t rgb_unpack(offs_t offset, uint32_t mem_mask = ~0); void rgb_pack(offs_t offset, uint32_t data, uint32_t mem_mask = ~0); - required_ioport m_monitor; + required_ioport m_config; memory_view m_vram_view; emu_timer *m_timer; + bool m_configured; + bool m_clut_addr_read; uint8_t m_monitor_type; - std::vector<uint32_t> m_vram; - uint32_t m_vbl_disable, m_toggle; - uint8_t m_sense; + std::unique_ptr<uint32_t []> m_vram; + uint16_t m_control; uint16_t m_preload; uint32_t m_base, m_stride; @@ -100,6 +112,8 @@ private: uint16_t m_hactive, m_hbporch, m_hsync, m_hfporch; uint16_t m_vactive, m_vbporch, m_vsync, m_vfporch; + uint32_t m_vbl_disable, m_toggle; + uint16_t m_multiplier; uint16_t m_modulus; uint8_t m_pdiv; @@ -132,28 +146,42 @@ protected: INPUT_PORTS_START( 48gc ) - PORT_START("MONITOR") + PORT_START("CONFIG") PORT_CONFNAME(0x0f, 0x06, u8"Attached monitor") PORT_CONFSETTING( 0x00, u8"Macintosh Two-Page Monitor (1152\u00d7870)") PORT_CONFSETTING( 0x01, u8"Macintosh Portrait Display (B&W 15\" 640\u00d7870)") PORT_CONFSETTING( 0x02, u8"Macintosh RGB Display (12\" 512\u00d7384)") PORT_CONFSETTING( 0x03, u8"Macintosh Two-Page Monitor (B&W 21\" 1152\u00d7870)") - //PORT_CONFSETTING( 0x04, u8"NTSC Monitor") requires implementing interlace modes + //PORT_CONFSETTING( 0x04, u8"NTSC Monitor") requires interlace modes PORT_CONFSETTING( 0x05, u8"Macintosh Portrait Display (640\u00d7870)") PORT_CONFSETTING( 0x06, u8"Macintosh Hi-Res Display (12-14\" 640\u00d7480)") + //PORT_CONFSETTING( 0x0b, u8"NTSC Encoder") requires interlace modes + PORT_CONFNAME(0x10, 0x00, u8"VRAM size") + PORT_CONFSETTING( 0x00, u8"512 kB (4\u20228)") + PORT_CONFSETTING( 0x10, u8"1 MB (8\u202224)") + PORT_CONFNAME(0x20, 0x00, u8"CLUT address read") + PORT_CONFSETTING( 0x00, "Disable") + PORT_CONFSETTING( 0x20, "Enable") INPUT_PORTS_END INPUT_PORTS_START( 824gc ) - PORT_START("MONITOR") + PORT_START("CONFIG") PORT_CONFNAME(0x0f, 0x06, u8"Attached monitor") PORT_CONFSETTING( 0x00, u8"Mac 21\" Color Display (1152\u00d7870)") PORT_CONFSETTING( 0x01, u8"Mac Portrait Display (B&W 15\" 640\u00d7870)") PORT_CONFSETTING( 0x02, u8"Mac RGB Display (12\" 512\u00d7384)") PORT_CONFSETTING( 0x03, u8"Mac Two-Page Display (B&W 21\" 1152\u00d7870)") - //PORT_CONFSETTING( 0x04, u8"NTSC Monitor") requires implementing interlace modes + //PORT_CONFSETTING( 0x04, u8"NTSC Monitor") requires interlace modes PORT_CONFSETTING( 0x06, u8"Mac Hi-Res Display (12-14\" 640\u00d7480)") + //PORT_CONFSETTING( 0x0b, u8"NTSC Encoder") requires interlace modes PORT_CONFSETTING( 0x0d, u8"Mac 16\" Color Display (832\u00d7624)") + PORT_CONFNAME(0x10, 0x10, u8"VRAM size") + PORT_CONFSETTING( 0x00, u8"512 kB (4\u20228)") + PORT_CONFSETTING( 0x10, u8"1 MB (8\u202224)") + PORT_CONFNAME(0x20, 0x00, u8"CLUT address read") + PORT_CONFSETTING( 0x00, "Disable") + PORT_CONFSETTING( 0x20, "Enable") INPUT_PORTS_END @@ -255,11 +283,9 @@ jmfb_device::jmfb_device(const machine_config &mconfig, device_type type, const device_nubus_card_interface(mconfig, *this), device_video_interface(mconfig, *this), device_palette_interface(mconfig, *this), - m_monitor(*this, "MONITOR"), + m_config(*this, "CONFIG"), m_vram_view(*this, "vram"), - m_timer(nullptr), - m_vbl_disable(0), m_toggle(0), - m_count(0), m_clutoffs(0), m_mode(0) + m_timer(nullptr) { set_screen(*this, GC48_SCREEN_NAME); } @@ -286,41 +312,33 @@ void jmfb_device::device_start() LOG("[JMFB %p] slotspace = %x\n", this, slotspace); - m_vram.resize(VRAM_SIZE / sizeof(uint32_t)); - install_view( - slotspace, slotspace + VRAM_SIZE - 1, - m_vram_view); - m_vram_view[0].install_ram( - slotspace, slotspace + VRAM_SIZE - 1, - &m_vram[0]); - m_vram_view[1].install_readwrite_handler( - slotspace, slotspace + VRAM_SIZE - 1, - read32s_delegate(*this, FUNC(jmfb_device::rgb_unpack)), write32s_delegate(*this, FUNC(jmfb_device::rgb_pack))); - m_vram_view.select(0); + m_vram = std::make_unique<uint32_t []>(VRAM_MAX); + install_view(slotspace, slotspace + 0x1f'ffff, m_vram_view); nubus().install_device( - slotspace + 0x200000, slotspace + 0x20000f, - read32s_delegate(*this, FUNC(jmfb_device::jmfb_r)), write32s_delegate(*this, FUNC(jmfb_device::jmfb_w))); + slotspace + 0x20'0000, slotspace + 0x20'000f, + read32sm_delegate(*this, FUNC(jmfb_device::jmfb_r)), write32sm_delegate(*this, FUNC(jmfb_device::jmfb_w))); + nubus().install_device( + slotspace + 0x20'0100, slotspace + 0x20'01ff, + read32sm_delegate(*this, FUNC(jmfb_device::crtc_r)), write32sm_delegate(*this, FUNC(jmfb_device::crtc_w))); nubus().install_device( - slotspace + 0x200100, slotspace + 0x2001ff, - read32s_delegate(*this, FUNC(jmfb_device::crtc_r)), write32s_delegate(*this, FUNC(jmfb_device::crtc_w))); - nubus().install_writeonly_device( slotspace + 0x200200, slotspace + 0x20020f, - write32s_delegate(*this, FUNC(jmfb_device::ramdac_w))); + read32sm_delegate(*this, FUNC(jmfb_device::ramdac_r)), write32sm_delegate(*this, FUNC(jmfb_device::ramdac_w))); nubus().install_writeonly_device( slotspace + 0x200300, slotspace + 0x20033f, - write32s_delegate(*this, FUNC(jmfb_device::clkgen_w))); + write32sm_delegate(*this, FUNC(jmfb_device::clkgen_w))); m_timer = timer_alloc(FUNC(jmfb_device::vbl_tick), this); + m_configured = false; + m_clut_addr_read = false; m_monitor_type = 0; + m_mode = 0; save_item(NAME(m_monitor_type)); - save_item(NAME(m_vram)); - save_item(NAME(m_vbl_disable)); - save_item(NAME(m_toggle)); - save_item(NAME(m_sense)); + save_pointer(NAME(m_vram), VRAM_MAX); + save_item(NAME(m_control)); save_item(NAME(m_preload)); save_item(NAME(m_base)); save_item(NAME(m_stride)); @@ -336,6 +354,8 @@ void jmfb_device::device_start() save_item(NAME(m_vbporch)); save_item(NAME(m_vsync)); save_item(NAME(m_vfporch)); + save_item(NAME(m_vbl_disable)); + save_item(NAME(m_toggle)); save_item(NAME(m_multiplier)); save_item(NAME(m_modulus)); save_item(NAME(m_pdiv)); @@ -347,18 +367,34 @@ void jmfb_device::device_start() void jmfb_device::device_reset() { - m_vram_view.select(0); - - m_monitor_type = m_monitor->read(); - if (m_monitor_type > std::size(f_monitors)) + if (!m_configured) { - throw emu_fatalerror("%s: Invalid monitor selection %d\n", tag(), m_monitor_type); + m_configured = true; + ioport_value const config = m_config->read(); + + m_monitor_type = config & 0x0f; + if (m_monitor_type > std::size(f_monitors)) + { + throw emu_fatalerror("%s: Invalid monitor selection %d\n", tag(), m_monitor_type); + } + + uint32_t const slotspace = get_slotspace(); + uint32_t const vramsize = VRAM_MAX * 4 / (BIT(config, 4) ? 1 : 2); + m_vram_view[0].install_ram(slotspace, slotspace + vramsize - 1, &m_vram[0]); + m_vram_view[1].install_readwrite_handler( + slotspace, slotspace + (vramsize / 3 * 4) - 1, + read32s_delegate(*this, FUNC(jmfb_device::rgb_unpack)), write32s_delegate(*this, FUNC(jmfb_device::rgb_pack))); + // TODO: in packed RGB mode, there are one or two bytes that aren't a multiple of 3 - handle them + + m_clut_addr_read = BIT(config, 5); } - std::fill(m_vram.begin(), m_vram.end(), 0); + m_vram_view.select(0); + + std::fill_n(&m_vram[0], VRAM_MAX, 0); m_vbl_disable = 1; m_toggle = 0; - m_sense = 0; + m_control = 0x0002; m_preload = 256 - 8; m_base = 0; m_stride = 80 / 4; @@ -410,89 +446,89 @@ uint32_t jmfb_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, switch (m_mode) { - case 0x0: // 1bpp - for (int y = cliprect.top(); y <= cliprect.bottom(); y++) + case 0x0: // 1bpp + for (int y = cliprect.top(); y <= cliprect.bottom(); y++) + { + auto const rowbase = screenbase + (y * m_stride * 4); + uint32_t *scanline = &bitmap.pix(y); + for (int x = 0; x <= xres/8; x++) { - auto const rowbase = screenbase + (y * m_stride * 4); - uint32_t *scanline = &bitmap.pix(y); - for (int x = 0; x <= xres/8; x++) - { - uint8_t const pixels = rowbase[x]; - - *scanline++ = trans(pen_color(BIT(pixels, 7))); - *scanline++ = trans(pen_color(BIT(pixels, 6))); - *scanline++ = trans(pen_color(BIT(pixels, 5))); - *scanline++ = trans(pen_color(BIT(pixels, 4))); - *scanline++ = trans(pen_color(BIT(pixels, 3))); - *scanline++ = trans(pen_color(BIT(pixels, 2))); - *scanline++ = trans(pen_color(BIT(pixels, 1))); - *scanline++ = trans(pen_color(BIT(pixels, 0))); - } + uint8_t const pixels = rowbase[x]; + + *scanline++ = trans(pen_color(BIT(pixels, 7))); + *scanline++ = trans(pen_color(BIT(pixels, 6))); + *scanline++ = trans(pen_color(BIT(pixels, 5))); + *scanline++ = trans(pen_color(BIT(pixels, 4))); + *scanline++ = trans(pen_color(BIT(pixels, 3))); + *scanline++ = trans(pen_color(BIT(pixels, 2))); + *scanline++ = trans(pen_color(BIT(pixels, 1))); + *scanline++ = trans(pen_color(BIT(pixels, 0))); } - break; + } + break; - case 0x4: // 2bpp - for (int y = cliprect.top(); y <= cliprect.bottom(); y++) + case 0x4: // 2bpp + for (int y = cliprect.top(); y <= cliprect.bottom(); y++) + { + auto const rowbase = screenbase + (y * m_stride * 4); + uint32_t *scanline = &bitmap.pix(y); + for (int x = 0; x <= xres/4; x++) { - auto const rowbase = screenbase + (y * m_stride * 4); - uint32_t *scanline = &bitmap.pix(y); - for (int x = 0; x <= xres/4; x++) - { - uint8_t const pixels = rowbase[x]; - - *scanline++ = trans(pen_color(BIT(pixels, 6, 2))); - *scanline++ = trans(pen_color(BIT(pixels, 4, 2))); - *scanline++ = trans(pen_color(BIT(pixels, 2, 2))); - *scanline++ = trans(pen_color(BIT(pixels, 0, 2))); - } + uint8_t const pixels = rowbase[x]; + + *scanline++ = trans(pen_color(BIT(pixels, 6, 2))); + *scanline++ = trans(pen_color(BIT(pixels, 4, 2))); + *scanline++ = trans(pen_color(BIT(pixels, 2, 2))); + *scanline++ = trans(pen_color(BIT(pixels, 0, 2))); } - break; + } + break; - case 0x8: // 4 bpp - for (int y = cliprect.top(); y <= cliprect.bottom(); y++) + case 0x8: // 4 bpp + for (int y = cliprect.top(); y <= cliprect.bottom(); y++) + { + auto const rowbase = screenbase + (y * m_stride * 4); + uint32_t *scanline = &bitmap.pix(y); + for (int x = 0; x <= xres/2; x++) { - auto const rowbase = screenbase + (y * m_stride * 4); - uint32_t *scanline = &bitmap.pix(y); - for (int x = 0; x <= xres/2; x++) - { - uint8_t const pixels = rowbase[x]; - - *scanline++ = trans(pen_color(BIT(pixels, 4, 4))); - *scanline++ = trans(pen_color(BIT(pixels, 0, 4))); - } + uint8_t const pixels = rowbase[x]; + + *scanline++ = trans(pen_color(BIT(pixels, 4, 4))); + *scanline++ = trans(pen_color(BIT(pixels, 0, 4))); } - break; + } + break; - case 0xc: // 8 bpp - for (int y = cliprect.top(); y <= cliprect.bottom(); y++) + case 0xc: // 8 bpp + for (int y = cliprect.top(); y <= cliprect.bottom(); y++) + { + auto const rowbase = screenbase + (y * m_stride * 4); + uint32_t *scanline = &bitmap.pix(y); + for (int x = 0; x <= xres; x++) { - auto const rowbase = screenbase + (y * m_stride * 4); - uint32_t *scanline = &bitmap.pix(y); - for (int x = 0; x <= xres; x++) - { - *scanline++ = trans(pen_color(rowbase[x])); - } + *scanline++ = trans(pen_color(rowbase[x])); } - break; + } + break; - case 0xd: // 24 bpp - for (int y = cliprect.top(); y <= cliprect.bottom(); y++) + case 0xd: // 24 bpp + for (int y = cliprect.top(); y <= cliprect.bottom(); y++) + { + auto source = util::big_endian_cast<uint8_t const>(&m_vram[0]) + (m_base << 6) + (y * m_stride * 8); + uint32_t *scanline = &bitmap.pix(y); + for (int x = 0; x <= xres; x++) { - auto source = util::big_endian_cast<uint8_t const>(&m_vram[0]) + (m_base << 6) + (y * m_stride * 8); - uint32_t *scanline = &bitmap.pix(y); - for (int x = 0; x <= xres; x++) - { - if (!f_monitors[m_monitor_type].mono) - *scanline++ = rgb_t(source[0], source[1], source[2]); - else - *scanline++ = rgb_t(source[2], source[2], source[2]); - source += 3; - } + if (!f_monitors[m_monitor_type].mono) + *scanline++ = rgb_t(source[0], source[1], source[2]); + else + *scanline++ = rgb_t(source[2], source[2], source[2]); + source += 3; } - break; + } + break; - default: - throw emu_fatalerror("%s: Unsupported RAMDAC mode %d\n", tag(), m_mode); + default: + throw emu_fatalerror("%s: Unsupported RAMDAC mode %d\n", tag(), m_mode); } return 0; @@ -509,34 +545,34 @@ void jmfb_device::update_crtc() XTAL const vcoout = refclk * m_multiplier; XTAL const pixclk = vcoout / (1 << m_pdiv); XTAL const dacclk = pixclk / divider; - LOG("reference clock %d VCO output %d pixel clock %d RAMDAC clock %d\n", + LOGCLKGEN("reference clock %d VCO output %d pixel clock %d RAMDAC longword load clock %d\n", refclk.value(), vcoout.value(), pixclk.value(), dacclk.value()); - int const htotal = (m_hactive + m_hbporch + m_hsync + m_hfporch + 8) * 32 / divider; - int const hactive = (m_hactive + 2) * 32 / divider; + int const htotal = m_hactive + m_hbporch + m_hsync + m_hfporch + 8; + int const hactive = m_hactive + 2; int scale = 0; switch (m_mode) { - case 0x0: // 1bpp: - scale = 0; - break; - case 0x4: // 2bpp: - scale = 1; - break; - case 0x8: // 4bpp: - scale = 2; - break; - case 0xc: // 8bpp: - scale = 3; - break; - case 0xd: // 24bpp: - scale = 5; - break; + case 0x0: // 1bpp - 32 pixels/longword + scale = 5; + break; + case 0x4: // 2bpp - 16 pixels/longword + scale = 4; + break; + case 0x8: // 4bpp - 8 pixels/longword + scale = 3; + break; + case 0xc: // 8bpp - 4 pixels/longword + scale = 2; + break; + case 0xd: // 24bpp - 1 pixel/longword + scale = 0; + break; } - int const hpixels = htotal >> scale; - int const width = hactive >> scale; - LOG("horizontal total %d active %d (mode %x %d/%d)\n", + int const hpixels = (htotal << scale) / divider; + int const width = (hactive << scale) / divider; + LOGCRTC("horizontal total %d active %d (mode %x %d/%d)\n", htotal, hactive, m_mode, width, hpixels); screen().configure( @@ -549,194 +585,233 @@ void jmfb_device::update_crtc() } } -uint32_t jmfb_device::jmfb_r(offs_t offset, uint32_t mem_mask) +uint32_t jmfb_device::jmfb_r(offs_t offset) { -// printf("%s jmfb_r: @ %x, mask %08x\n", machine().describe_context().c_str(), offset, mem_mask); - switch (offset) { - case 0x00/4: - { - uint32_t result = f_monitors[m_monitor_type].sense[0]; - if (BIT(m_sense, 2)) - result &= f_monitors[m_monitor_type].sense[1]; - if (BIT(m_sense, 1)) - result &= f_monitors[m_monitor_type].sense[2]; - if (BIT(m_sense, 0)) - result &= f_monitors[m_monitor_type].sense[3]; - return result << 9; - } - } + case 0x00/4: + { + uint16_t sense = f_monitors[m_monitor_type].sense[0]; + if (BIT(m_control, 11)) + sense &= f_monitors[m_monitor_type].sense[1]; + if (BIT(m_control, 10)) + sense &= f_monitors[m_monitor_type].sense[2]; + if (BIT(m_control, 9)) + sense &= f_monitors[m_monitor_type].sense[3]; + return (m_control & 0xf1ff) | (sense << 9); + } - return 0; + case 0x04/4: return m_preload; // RAMDAC longword load clock divider preload + case 0x08/4: return m_base; // base - 32-byte increments for indexed, 64-byte increments for direct + case 0x0c/4: return m_stride; // stride - 4-byte increments for indexed, 8-byte increments for direct + + default: + LOG("%s: read unimplemented JMFB register %x/4\n", machine().describe_context(), offset * 4); + return 0; + } } -uint32_t jmfb_device::crtc_r(offs_t offset, uint32_t mem_mask) +uint32_t jmfb_device::crtc_r(offs_t offset) { // printf("%s crtc_r: @ %x, mask %08x\n", machine().describe_context().c_str(), offset, mem_mask); switch (offset) { - case 0xc0/4: - m_toggle ^= 0xffffffff; - return m_toggle; + case 0x0c/4: return m_hactive; // active pixel cells - 2 + case 0x10/4: return m_hbporch; // horizontal back porch - 2 + case 0x14/4: return m_hsync; // horizontal sync pulse width - 2 + case 0x18/4: return m_hfporch; // horizontal front porch - 2 + + case 0x24/4: return m_vactive; // active lines * 2 + case 0x28/4: return m_vbporch; // vertical back porch * 2 + case 0x2c/4: return m_vsync; // vertical sync pulse width * 2 + case 0x30/4: return m_vfporch; // vertical front porch * 2 + + case 0xc0/4: // seems to be frame position flags or something? + m_toggle ^= 0xffffffff; + return m_toggle; } return 0; } -void jmfb_device::jmfb_w(offs_t offset, uint32_t data, uint32_t mem_mask) +uint32_t jmfb_device::ramdac_r(offs_t offset) { switch (offset) { - case 0x00/4: // control - LOG("%s: %04x to control\n", machine().describe_context(), data); - if (BIT(data, 7)) - { - m_vram_view.select(BIT(data, 2)); // packed RGB mode - } - m_sense = (data >> 9) & 0x07; - break; - - case 0x04/4: - LOG("%s: %02x to preload\n", machine().describe_context(), data); - m_preload = data & 0xff; - update_crtc(); - break; - - case 0x08/4: // base - LOG("%s: %x to base\n", machine().describe_context(), data); - m_base = data & 0xffff; - break; - - case 0x0c/4: // stride - LOG("%s: %x to stride\n", machine().describe_context(), data); - // this value is in DWORDs for 1-8 bpp and, uhh, strange for 24bpp - m_stride = data & 0xffff; - break; + case 0x00/4: // CLUT address + // The firmware explicitly checks whether it can read the value written to the CLUT address + // What difference this makes is not known + return m_clut_addr_read ? m_clutoffs : 0; + + default: + LOGRAMDAC("%s: read unimplemented RAMDAC register %x/4\n", machine().describe_context(), offset * 4); + return 0; } } -void jmfb_device::crtc_w(offs_t offset, uint32_t data, uint32_t mem_mask) +void jmfb_device::jmfb_w(offs_t offset, uint32_t data) { + data &= 0xffff; // 16 bits wide, but lane select is ignored and firmware relies on smearing switch (offset) { - case 0x0c/4: // active pixel cells - 2 - LOG("%s: %d-2 to active cells\n", machine().describe_context(), data + 2); - m_hactive = data; - update_crtc(); - break; - - case 0x10/4: // horizontal back porch - LOG("%s: %d to horizontal back porch\n", machine().describe_context(), data + 2); - m_hbporch = data; - update_crtc(); - break; - - case 0x14/4: // horizontal sync pulse - LOG("%s: %d-2 to horizontal sync pulse\n", machine().describe_context(), data + 2); - m_hsync = data; - update_crtc(); - break; - - case 0x18/4: // horizontal front porch - LOG("%s: %d-2 to horizontal front porch\n", machine().describe_context(), data + 2); - m_hfporch = data; - update_crtc(); - break; - - case 0x24/4: // active lines * 2 - LOG("%s: %d*2 to active lines\n", machine().describe_context(), data / 2); - m_vactive = data; - update_crtc(); - break; - - case 0x28/4: // vertical back porch * 2 - LOG("%s: %d*2 to vertical back porch\n", machine().describe_context(), data / 2); - m_vbporch = data; - update_crtc(); - break; - - case 0x2c/4: // vertical sync width * 2 - LOG("%s: %d*2 to vertical sync pulse width\n", machine().describe_context(), data / 2); - m_vsync = data; - update_crtc(); - break; - - case 0x30/4: // vertical front porch * 2 - LOG("%s: %d*2 to vertical front porch\n", machine().describe_context(), data / 2); - m_vfporch = data; - update_crtc(); - break; - - case 0x3c/4: // bit 1 = VBL disable (1=no interrupts) - m_vbl_disable = (data & 2) ? 1 : 0; - break; + case 0x00/4: // control + LOG("%s: %04x to control (sense %x interlace %x RGB %x RAM %dk)\n", + machine().describe_context(), data, + BIT(data, 9, 3), BIT(data, 4), BIT(data, 2), BIT(data, 0) ? 256 : 128); + m_control = data; + m_vram_view.select(BIT(data, 2)); // packed RGB mode + break; + + case 0x04/4: // RAMDAC longword load clock divider preload + LOG("%s: 256-%d to preload\n", machine().describe_context(), data & 0xff); + m_preload = data & 0xff; + update_crtc(); + break; + + case 0x08/4: // base - 32-byte increments for indexed, 64-byte increments for direct + LOG("%s: %x to base\n", machine().describe_context(), data); + m_base = data; + break; + + case 0x0c/4: // stride - 4-byte increments for indexed, 8-byte increments for direct + LOG("%s: %x to stride\n", machine().describe_context(), data); + m_stride = data; + break; + } +} - case 0x48/4: // write here to clear interrupt - lower_slot_irq(); - break; +void jmfb_device::crtc_w(offs_t offset, uint32_t data) +{ + data &= 0xffff; // 16 bits wide, but lane select is ignored and firmware relies on smearing + switch (offset) + { + case 0x0c/4: // active pixel cells - 2 + LOGCRTC("%s: %d+2 to active cells\n", machine().describe_context(), data); + m_hactive = data & 0x0fff; + update_crtc(); + break; + + case 0x10/4: // horizontal back porch - 2 + LOGCRTC("%s: %d+2 to horizontal back porch\n", machine().describe_context(), data); + m_hbporch = data & 0x0fff; + update_crtc(); + break; + + case 0x14/4: // horizontal sync pulse width - 2 + LOGCRTC("%s: %d+2 to horizontal sync pulse width\n", machine().describe_context(), data); + m_hsync = data & 0x0fff; + update_crtc(); + break; + + case 0x18/4: // horizontal front porch - 2 + LOGCRTC("%s: %d+2 to horizontal front porch\n", machine().describe_context(), data); + m_hfporch = data & 0x0fff; + update_crtc(); + break; + + case 0x24/4: // active lines * 2 + LOGCRTC("%s: %d/2 to active lines\n", machine().describe_context(), data); + m_vactive = data & 0x0fff; + update_crtc(); + break; + + case 0x28/4: // vertical back porch * 2 + LOGCRTC("%s: %d/2 to vertical back porch\n", machine().describe_context(), data); + m_vbporch = data & 0x0fff; + update_crtc(); + break; + + case 0x2c/4: // vertical sync pulse width * 2 + LOGCRTC("%s: %d/2 to vertical sync pulse width\n", machine().describe_context(), data); + m_vsync = data & 0x0fff; + update_crtc(); + break; + + case 0x30/4: // vertical front porch * 2 + LOGCRTC("%s: %d/2 to vertical front porch\n", machine().describe_context(), data); + m_vfporch = data & 0x0fff; + update_crtc(); + break; + + case 0x3c/4: // bit 1 = VBL disable (1=no interrupts) + m_vbl_disable = (data & 2) ? 1 : 0; + break; + + case 0x48/4: // write here to clear interrupt + lower_slot_irq(); + break; + + default: + LOGCRTC("%s: %03x to unimplemented CRTC register %x/4\n", machine().describe_context(), data, offset * 4); } } -void jmfb_device::ramdac_w(offs_t offset, uint32_t data, uint32_t mem_mask) +void jmfb_device::ramdac_w(offs_t offset, uint32_t data) { + data &= 0xff; // 8 bits wide, but lane select is ignored and firmware relies on smearing switch (offset) { - case 0x00/4: // CLUT address - LOG("%s: %02x to CLUT address\n", machine().describe_context(), data & 0xff); - m_clutoffs = data; + case 0x00/4: // CLUT address + LOGCLUT("%s: %u to RAMDAC color address\n", machine().describe_context(), data); + m_clutoffs = data; + m_count = 0; + break; + + case 0x04/4: // CLUT data + m_colors[m_count++] = data & 0xff; + if (m_count == 3) + { + LOGCLUT("%s: RAMDAC color %u = %02x %02x %02x\n", machine().describe_context(), m_clutoffs, m_colors[0], m_colors[1], m_colors[2]); + set_pen_color(m_clutoffs, rgb_t(m_colors[0], m_colors[1], m_colors[2])); + m_clutoffs++; m_count = 0; - break; + } + break; - case 0x04/4: // CLUT data - m_colors[m_count++] = data & 0xff; - if (m_count == 3) - { - LOG("%s: RAMDAC: color %d = %02x %02x %02x\n", machine().describe_context(), m_clutoffs, m_colors[0], m_colors[1], m_colors[2]); - set_pen_color(m_clutoffs, rgb_t(m_colors[0], m_colors[1], m_colors[2])); - m_clutoffs++; - m_count = 0; - } - break; + case 0x08/4: // RAMDAC mode control + m_mode = (data >> 1) & 0xf; + LOGRAMDAC("%s: %02x to RAMDAC control (mode = %x)\n", machine().describe_context(), data, m_mode); + update_crtc(); + break; - case 0x08/4: // mode control - m_mode = (data >> 1) & 0xf; - LOG("%s: %02x to RAMDAC mode (mode = %x)\n", machine().describe_context(), data, m_mode); - update_crtc(); - break; + default: + LOGRAMDAC("%s: %02x to unimplemented RAMDAC register %x/4\n", machine().describe_context(), data, offset * 4); } } -void jmfb_device::clkgen_w(offs_t offset, uint32_t data, uint32_t mem_mask) +void jmfb_device::clkgen_w(offs_t offset, uint32_t data) { + data &= 0x0f; // four bits wide, but lane select is ignored and firmware relies on smearing switch (offset) { - case 0x00/4: - case 0x04/4: - case 0x08/4: - case 0x0c/4: - m_multiplier &= ~(0x0f << ((offset & 3) * 4)); - m_multiplier |= (data & 0x0f) << ((offset & 3) * 4); - LOG("%s: %d to multiplier\n", machine().describe_context(), m_multiplier); - update_crtc(); - break; - - case 0x10/4: - case 0x14/4: - case 0x18/4: - m_modulus &= ~(0x0f << ((offset & 3) * 4)); - m_modulus |= (data & 0x0f) << ((offset & 3) * 4); - LOG("%s: %d to modulus\n", machine().describe_context(), m_modulus); - if (offset == 0x318/4) // avoid bad intermediate values - update_crtc(); - break; - - case 0x24/4: - LOG("%s: 1<<%d to pixel cell divider\n", machine().describe_context(), data); - m_pdiv = data & 0x0f; - update_crtc(); - break; + case 0x00/4: + case 0x04/4: + case 0x08/4: + case 0x0c/4: + m_multiplier &= ~(0x0f << ((offset & 3) * 4)); + m_multiplier |= data << ((offset & 3) * 4); + LOGCLKGEN("%s: %d to multiplier\n", machine().describe_context(), m_multiplier); + update_crtc(); + break; + + case 0x10/4: + case 0x14/4: + case 0x18/4: + m_modulus &= ~(0x0f << ((offset & 3) * 4)); + m_modulus |= data << ((offset & 3) * 4); + LOGCLKGEN("%s: %d to reference clock divider\n", machine().describe_context(), m_modulus); + update_crtc(); + break; + + case 0x24/4: + m_pdiv = data; + LOGCLKGEN("%s: 1<<%d to pixel clock divider\n", machine().describe_context(), m_pdiv); + update_crtc(); + break; + + default: + LOGCRTC("%s: %x to unimplemented clock synthesiser register %x/4\n", machine().describe_context(), data, offset * 4); } } @@ -764,5 +839,5 @@ void jmfb_device::rgb_pack(offs_t offset, uint32_t data, uint32_t mem_mask) // DEVICE TYPE DEFINITIONS //************************************************************************** -DEFINE_DEVICE_TYPE_PRIVATE(NUBUS_MDC48, device_nubus_card_interface, nubus_48gc_device, "nb_mdc48", "Apple Macintosh Display Card 4*8") -DEFINE_DEVICE_TYPE_PRIVATE(NUBUS_MDC824, device_nubus_card_interface, nubus_824gc_device, "nb_mdc824", "Apple Macintosh Display Card 8*24") +DEFINE_DEVICE_TYPE_PRIVATE(NUBUS_MDC48, device_nubus_card_interface, nubus_48gc_device, "nb_mdc48", "Apple Macintosh Display Card 4/8 (MDC 1.0.1)") +DEFINE_DEVICE_TYPE_PRIVATE(NUBUS_MDC824, device_nubus_card_interface, nubus_824gc_device, "nb_mdc824", "Apple Macintosh Display Card 8/24 (MDC 1.2)") |