summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/bus
diff options
context:
space:
mode:
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
commit7e6feb2c33b9ae1ec41a5d54ab0a825020faae8c (patch)
tree3f62bc48700d8fbfcee40ddd27f87e685f7737d7 /src/devices/bus
parentaf2b2c05364283141b103cb10446fa5a2b1db428 (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.cpp651
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)")