diff options
| author | 2026-02-10 13:12:03 +0700 | |
|---|---|---|
| committer | 2026-02-10 13:12:03 +0700 | |
| commit | 6ba52f7299edb531a97a053ca186c2c00d43a752 (patch) | |
| tree | 9772934b113c8752b5e909a2892993be99199183 | |
| parent | 24c1f51a6d8cbafc4bd0e9f1e39528086cc6a1d6 (diff) | |
sgi/iris: add wip hle gl1 graphics
| -rw-r--r-- | src/mame/sgi/gl1.cpp | 380 | ||||
| -rw-r--r-- | src/mame/sgi/gl1.h | 13 | ||||
| -rw-r--r-- | src/mame/sgi/iris.cpp | 12 | ||||
| -rw-r--r-- | src/mame/sgi/pm2.cpp | 44 |
4 files changed, 414 insertions, 35 deletions
diff --git a/src/mame/sgi/gl1.cpp b/src/mame/sgi/gl1.cpp new file mode 100644 index 00000000000..35e5df76004 --- /dev/null +++ b/src/mame/sgi/gl1.cpp @@ -0,0 +1,380 @@ +// license:BSD-3-Clause +// copyright-holders:Patrick Mackinlay + +/* + * SGI IRIS GL1 high-level emulation + * + * This device is an interim high-level emulation of a combination of GF1, UC3, + * DC3 and BP2 boards. Currently, it supports the limited subset of functions + * used by the IRIS 1400 firmware to display the monitor. When the hardware is + * better understood and more software becomes usable, this device should be + * replaced by individual Multibus devices emulating each of the four cards + * mentioned earlier. + * + * Sources: + * - IRIS 3.7 source code + * + * TODO: + * - everything + */ + +#include "emu.h" + +#include "gl1.h" + +#include "emupal.h" +#include "screen.h" + +//#define VERBOSE (LOG_GENERAL) +#include "logmacro.h" + +namespace { + +class sgi_gl1_device + : public device_t + , public device_multibus_interface +{ +public: + sgi_gl1_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock) + : device_t(mconfig, SGI_GL1, tag, owner, clock) + , device_multibus_interface(mconfig, *this) + , m_screen(*this, "screen") + , m_cmap(*this, "cmap") + , m_font(*this, "font", 0x8000, ENDIANNESS_BIG) + , m_bp(nullptr) + , m_installed(false) + { + } + + static constexpr feature_type imperfect_features() { return feature::GRAPHICS; } + +protected: + virtual void device_add_mconfig(machine_config &config) override ATTR_COLD; + virtual void device_start() override ATTR_COLD; + virtual void device_reset() override ATTR_COLD; + + // GF1 + u16 fbc_readdpx_r(); + void fbc_clrint_w(u16 data); + u16 fbc_flags_r(); + void fbc_flags_w(u16 data); + u16 fbc_data_r(); + void fbc_data_w(u16 data); + void ge_flags_w(u16 data); + + // DC3 + void flags_w(u16 data); + template <unsigned Channel> void colormap_w(offs_t offset, u16 data, u16 mem_mask); + u32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, rectangle const &cliprect); + + // BP2 + void bp_w(offs_t offset, u8 data, u8 mask); + +private: + required_device<screen_device> m_screen; + required_device<palette_device> m_cmap; + memory_share_creator<u16> m_font; + + std::unique_ptr<u8[]> m_bp; + + //u16 m_ed; // error delta + //u16 m_ec; // error correct + u16 m_xs; // x start + u16 m_xe; // x end + u16 m_ys; // y start + u16 m_ye; // y end + u16 m_fma; // font memory address + //u16 m_cf; // config + + u16 m_ch; // character height + u16 m_cw; // character width + u16 m_cs; // character spacing + + u16 m_ca; // cursor address + u16 m_cm; // cursor color + u16 m_cx; // cursor x + u16 m_cy; // cursor y + + u16 m_color; + u16 m_wrten; + + u16 m_flags; + + util::fifo<u16, 16> m_params; + u8 m_expect; + + bool m_installed; +}; + +void sgi_gl1_device::device_start() +{ + m_bp = std::make_unique<u8[]>(0x10'0000); // 1024x1024x4 (not packed) + + save_pointer(NAME(m_bp), 0x10'0000); +} + +void sgi_gl1_device::device_reset() +{ + if (!m_installed) + { + // GF1 handlers + m_bus->space(AS_IO).install_readwrite_handler(0x1000, 0x1001, + emu::rw_delegate(*this, FUNC(sgi_gl1_device::fbc_readdpx_r)), + emu::rw_delegate(*this, FUNC(sgi_gl1_device::fbc_clrint_w))); + + m_bus->space(AS_IO).install_readwrite_handler(0x1400, 0x1401, + emu::rw_delegate(*this, FUNC(sgi_gl1_device::fbc_flags_r)), + emu::rw_delegate(*this, FUNC(sgi_gl1_device::fbc_flags_w))); + + m_bus->space(AS_IO).install_readwrite_handler(0x1800, 0x1801, + emu::rw_delegate(*this, FUNC(sgi_gl1_device::fbc_data_r)), + emu::rw_delegate(*this, FUNC(sgi_gl1_device::fbc_data_w))); + + m_bus->space(AS_IO).install_write_handler(0x1c00, 0x1c01, + emu::rw_delegate(*this, FUNC(sgi_gl1_device::ge_flags_w))); + + // DC3 handlers + m_bus->space(AS_IO).install_write_handler(0x4000, 0x4001, emu::rw_delegate(*this, FUNC(sgi_gl1_device::flags_w))); + m_bus->space(AS_IO).install_write_handler(0x4200, 0x43ff, emu::rw_delegate(*this, FUNC(sgi_gl1_device::colormap_w<0>))); + m_bus->space(AS_IO).install_write_handler(0x4400, 0x45ff, emu::rw_delegate(*this, FUNC(sgi_gl1_device::colormap_w<1>))); + m_bus->space(AS_IO).install_write_handler(0x4600, 0x47ff, emu::rw_delegate(*this, FUNC(sgi_gl1_device::colormap_w<2>))); + + m_installed = true; + } + + m_params.clear(); + m_expect = 0; +} + +static const gfx_layout gl1_layout = +{ + 8, 16, 1024, 1, + { 0 }, + { 8, 9, 10, 11, 12, 13, 14, 15 } , + { 15 * 16, 14 * 16, 13 * 16, 12 * 16, 11 * 16, 10 * 16, 9 * 16, 8 * 16, 7 * 16, 6 * 16, 5 * 16, 4 * 16, 3 * 16, 2 * 16, 1 * 16, 0 * 16 }, + 16 * 16 +}; + +static GFXDECODE_START(gl1_gfx) + GFXDECODE_RAM("font", 0x0, gl1_layout, 0, 1) +GFXDECODE_END + +void sgi_gl1_device::device_add_mconfig(machine_config &config) +{ + SCREEN(config, m_screen, SCREEN_TYPE_RASTER); + m_screen->set_raw(1024 * 768 * 60, 1024, 0, 1024, 768, 0, 768); + m_screen->set_screen_update(FUNC(sgi_gl1_device::screen_update)); + + // MCM6168P45 x8x3 (4096x4 SRAM) 16K x3 + PALETTE(config, m_cmap); + m_cmap->set_entries(4096); + + // gfxdecode is only to show the font data in the tile viewer + GFXDECODE(config, "gfx", m_cmap, gl1_gfx); +} + +u32 sgi_gl1_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, rectangle const &cliprect) +{ + u8 const *src = m_bp.get(); + + for (unsigned y = screen.visible_area().min_y; y <= screen.visible_area().max_y; y++) + { + for (unsigned x = screen.visible_area().min_x; x <= screen.visible_area().max_x; x++) + { + bitmap.pix(screen.visible_area().max_y - y, x) = m_cmap->pen_color(*src++); + } + } + + return 0; +} + +u16 sgi_gl1_device::fbc_readdpx_r() +{ + return 0; +} + +void sgi_gl1_device::fbc_clrint_w(u16 data) +{ + LOG("%s: fbc_clrint_w 0x%04x\n", machine().describe_context(), data); +} + +u16 sgi_gl1_device::fbc_flags_r() +{ + return 0x0002; +} + +void sgi_gl1_device::fbc_flags_w(u16 data) +{ + //LOG("%s: fbc_flags_w 0x%04x\n", machine().describe_context(), data); +} + +static const unsigned num_params[] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 4, 0, 2, 2, 1, 8, + 8, 0, 0, 0, 0, 6, 4, 1, + + 0, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 3, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 8, 0, 0, 0, 0, 0, 0, +}; + +u16 sgi_gl1_device::fbc_data_r() +{ + return 0x40; // HACK: always ready +} + +void sgi_gl1_device::fbc_data_w(u16 data) +{ + LOG("%s: fbc_data_w 0x%04x expect %u\n", machine().describe_context(), data, m_expect); + + if (m_params.empty()) + { + // enqueue command + m_params.enqueue(data); + + m_expect = num_params[data & 0x3f]; + } + else if (m_expect) + { + // enqueue parameter + m_params.enqueue(data); + m_expect--; + } + + // more parameters expected? + if (m_expect) + return; + + u8 const command = m_params.dequeue(); + LOG("command 0x%02x params %u\n", command, m_params.queue_length()); + + switch (command & 0x3f) + { + case 0x12: // point + m_xs = m_params.dequeue() & 0xfffU; + m_params.dequeue(); + m_params.dequeue(); + m_ys = m_params.dequeue() & 0xfffU; + break; + + case 0x14: // color + m_color = m_params.dequeue(); + m_color &= m_params.dequeue(); + break; + case 0x15: // wrten + m_wrten = m_params.dequeue(); + m_wrten |= m_params.dequeue(); + break; + //case 0x16: // config + case 0x17: // loadmasks (passthrough) + m_fma = m_params.dequeue(); + while (!m_params.empty()) + m_font[m_fma++ & 0x3fff] = m_params.dequeue(); + break; + //case 0x18: // fbviewport + + case 0x1d: // selectcursor + m_ca = m_params.dequeue(); + m_cm = m_params.dequeue(); + m_params.dequeue(); + m_params.dequeue(); + m_params.dequeue(); + m_params.dequeue(); + break; + case 0x1e: // drawcursor + m_cx = m_params.dequeue() & 0xfffU; + m_params.dequeue(); + m_params.dequeue(); + m_cy = m_params.dequeue() & 0xfffU; + + for (int y = 0; y <= m_ch; y++) + { + u8 const data = m_font[(m_ca + (y & 0xfU)) & 0x3fff]; + + for (int x = 0; x <= m_cw; x++) + bp_w((m_cy + y) * 0x400 + m_cx + x, BIT(data, (x & 7) ^ 7) ? m_cm : 0, m_cm); + } + break; + case 0x1f: // undrawcursor + m_params.dequeue(); + for (int y = 0; y <= m_ch; y++) + for (int x = 0; x <= m_cw; x++) + bp_w((m_cy + y) * 0x400 + m_cx + x, 0, m_cm); + break; + + //case 0x21: // polystipple + + case 0x2c: // fixcharload + m_ch = m_params.dequeue(); + m_cw = m_params.dequeue(); + m_cs = m_params.dequeue(); + break; + case 0x2d: // fixchardraw + m_fma = m_params.dequeue(); + for (int y = 0; y <= m_ch; y++) + { + u8 const data = m_font[(m_fma + (y & 0xfU)) & 0x3fff]; + + for (int x = 0; x <= m_cw; x++) + bp_w((m_ys + y) * 0x400 + m_xs + x, BIT(data, (x & 7) ^ 7) ? m_color : 0, m_wrten); + } + m_xs = (m_xs + m_cs) & 0x0fff; + break; + + case 0x39: // blockfill + m_xs = m_params.dequeue() & 0x0fff; + m_params.dequeue(); + m_params.dequeue(); + m_ys = m_params.dequeue() & 0x0fff; + m_xe = m_params.dequeue() & 0x0fff; + m_params.dequeue(); + m_params.dequeue(); + m_ye = m_params.dequeue() & 0x0fff; + + for (int y = m_ys; y < m_ye; y++) + for (int x = m_xs; x < m_xe; x++) + bp_w(y * 0x400 + x, m_color, m_wrten); + break; + + default: + LOG("command 0x%02x unemulated\n", command); + m_params.clear(); + break; + } +} + +void sgi_gl1_device::ge_flags_w(u16 data) +{ + LOG("%s: ge_flags_w 0x%04x\n", machine().describe_context(), data); +} + +void sgi_gl1_device::flags_w(u16 data) +{ + LOG("%s: flags_w 0x%04x\n", machine().describe_context(), data); + + m_flags = data; +} + +template <unsigned Channel> void sgi_gl1_device::colormap_w(offs_t offset, u16 data, u16 mem_mask) +{ + unsigned const index = BIT(m_flags, 4, 4) << 8 | offset; + + switch (Channel) + { + case 0: m_cmap->set_pen_red_level(index, data); break; + case 1: m_cmap->set_pen_green_level(index, data); break; + case 2: m_cmap->set_pen_blue_level(index, data); break; + } +} + +void sgi_gl1_device::bp_w(offs_t offset, u8 data, u8 mask) +{ + m_bp[offset] = (m_bp[offset] & ~mask) | (data & mask); +} + +} // anonymous namespace + +DEFINE_DEVICE_TYPE_PRIVATE(SGI_GL1, device_multibus_interface, sgi_gl1_device, "sgi_gl1", "Silicon Graphics GL1") diff --git a/src/mame/sgi/gl1.h b/src/mame/sgi/gl1.h new file mode 100644 index 00000000000..aff9b54835a --- /dev/null +++ b/src/mame/sgi/gl1.h @@ -0,0 +1,13 @@ +// license:BSD-3-Clause +// copyright-holders:Patrick Mackinlay + +#ifndef MAME_SGI_GL1_H +#define MAME_SGI_GL1_H + +#pragma once + +#include "bus/multibus/multibus.h" + +DECLARE_DEVICE_TYPE(SGI_GL1, device_multibus_interface) + +#endif // MAME_SGI_GL1_H diff --git a/src/mame/sgi/iris.cpp b/src/mame/sgi/iris.cpp index 5d53989d054..76cf18c7ad6 100644 --- a/src/mame/sgi/iris.cpp +++ b/src/mame/sgi/iris.cpp @@ -45,6 +45,8 @@ #include "ip2.h" #include "pm2.h" +#include "gl1.h" + #include "iris1400.lh" namespace { @@ -81,6 +83,9 @@ void iris_state::machine_reset() } static DEVICE_INPUT_DEFAULTS_START(dsd) + // winchester drive class 5 + DEVICE_INPUT_DEFAULTS("W6", 0x1c, 0x14) + // wake-up address 0x7f00 DEVICE_INPUT_DEFAULTS("W7", 0x01, 0x01) DEVICE_INPUT_DEFAULTS("W7", 0x02, 0x02) @@ -138,6 +143,7 @@ static void iris_p_cards(device_slot_interface &device) static void iris_g_cards(device_slot_interface &device) { // graphics side cards + device.option_add("gl1", SGI_GL1); } // 20-slot chassis, card positions assumed from 2xxx @@ -167,7 +173,7 @@ void iris_state::common(machine_config &config) MULTIBUS_SLOT(config, m_slot[16], m_bus, iris_g_cards, nullptr, false); // bit plane MULTIBUS_SLOT(config, m_slot[17], m_bus, iris_g_cards, nullptr, false); // display controller MULTIBUS_SLOT(config, m_slot[18], m_bus, iris_g_cards, nullptr, false); // update controller - MULTIBUS_SLOT(config, m_slot[19], m_bus, iris_g_cards, nullptr, false); // frame buffer + MULTIBUS_SLOT(config, m_slot[19], m_bus, iris_g_cards, nullptr, false); // graphics processor/frame buffer controller } void iris_state::iris1400(machine_config &config) @@ -175,8 +181,11 @@ void iris_state::iris1400(machine_config &config) common(config); m_slot[1]->set_default_option("pm2"); + m_slot[2]->set_default_option("nex"); m_slot[3]->set_default_option("dsd"); + m_slot[19]->set_default_option("gl1"); + config.set_default_layout(layout_iris1400); } @@ -185,6 +194,7 @@ void iris_state::iris3130(machine_config &config) common(config); m_slot[1]->set_default_option("ip2"); + m_slot[2]->set_default_option("nex"); m_slot[3]->set_default_option("dsd"); } diff --git a/src/mame/sgi/pm2.cpp b/src/mame/sgi/pm2.cpp index a733de8b66a..43b35b8085a 100644 --- a/src/mame/sgi/pm2.cpp +++ b/src/mame/sgi/pm2.cpp @@ -87,8 +87,6 @@ protected: virtual void device_start() override ATTR_COLD; virtual void device_reset() override ATTR_COLD; - void gfx_mconfig(machine_config &config); - void mem_map(address_map &map) ATTR_COLD; u16 status_r(); @@ -113,9 +111,6 @@ private: required_ioport m_config; output_finder<> m_led; - memory_access<24, 1, 0, ENDIANNESS_BIG>::specific m_cpu_mem; - memory_access<24, 1, 0, ENDIANNESS_BIG>::specific m_cpu_spc; - u16 m_status; u16 m_exception; u16 m_map[240]; // AM2148-55DC 1Kx4 SRAM (x3)? @@ -129,9 +124,6 @@ void sgi_pm2_device::device_start() save_item(NAME(m_exception)); save_item(NAME(m_map)); - m_cpu->space(AS_PROGRAM).specific(m_cpu_mem); - m_cpu->space(m68000_device::AS_CPU_SPACE).specific(m_cpu_spc); - m_led.resolve(); } @@ -195,8 +187,8 @@ void sgi_pm2_device::device_add_mconfig(machine_config &config) MC68681(config, m_duart[0], 3.6864_MHz_XTAL).irq_cb().set(irq6, FUNC(input_merger_any_high_device::in_w<0>)); MC68681(config, m_duart[1], 3.6864_MHz_XTAL).irq_cb().set(irq6, FUNC(input_merger_any_high_device::in_w<1>)); - RS232_PORT(config, m_port[0], keyboard_devices, nullptr); - RS232_PORT(config, m_port[1], default_rs232_devices, "terminal"); + RS232_PORT(config, m_port[0], keyboard_devices, "kbd"); + RS232_PORT(config, m_port[1], default_rs232_devices, nullptr); RS232_PORT(config, m_port[2], default_rs232_devices, nullptr); RS232_PORT(config, m_port[3], default_rs232_devices, nullptr); @@ -209,8 +201,6 @@ void sgi_pm2_device::device_add_mconfig(machine_config &config) m_port[1]->rxd_handler().set(m_duart[0], FUNC(scn2681_device::rx_b_w)); m_port[2]->rxd_handler().set(m_duart[1], FUNC(scn2681_device::rx_a_w)); m_port[3]->rxd_handler().set(m_duart[1], FUNC(scn2681_device::rx_b_w)); - - gfx_mconfig(config); } void sgi_pm2_device::device_config_complete() @@ -226,8 +216,12 @@ void sgi_pm2_device::mem_map(address_map &map) // TODO: was there a 2M PM2 variant? map(0x00'0000, 0x17'ffff).ram().share("ram"); // mt4264-15 64kx1 DRAM (8x9) + 1M on PM2M board + map(0x18'0000, 0xf7'ffff).noprw(); // HACK: silence ram sizing + map(0xf8'0000, 0xf8'7fff).rom().region("prom0", 0); map(0xf9'0000, 0xf9'7fff).rom().region("prom1", 0); + // 0xfa'0000 prom2 + // 0xfb'0000 prom3 - DC4? map(0xfc'0000, 0xfc'1fff).rw(m_mmu, FUNC(pm2_mmu_device::page_r), FUNC(pm2_mmu_device::page_w)); map(0xfc'2000, 0xfc'3fff).rw(m_mmu, FUNC(pm2_mmu_device::prot_r), FUNC(pm2_mmu_device::prot_w)); @@ -285,7 +279,8 @@ u16 sgi_pm2_device::mem_r(offs_t offset, u16 mem_mask) offs_t const physical = map(offset); data = m_ram[physical]; - LOG("%s: mem_r 0x%06x physical 0x%06x data 0x%04x\n", machine().describe_context(), offset << 1, physical << 1, data); + if (!machine().side_effects_disabled()) + LOG("%s: mem_r 0x%06x physical 0x%06x data 0x%04x\n", machine().describe_context(), offset << 1, physical << 1, data); if ((offset < 0x8000) && (m_status & STATUS_MBOX)) irq4_w<EXCEPTION_MBOX>(1); @@ -302,7 +297,8 @@ void sgi_pm2_device::mem_w(offs_t offset, u16 data, u16 mem_mask) { offs_t const physical = map(offset); - LOG("%s: mem_w 0x%06x physical 0x%06x data 0x%04x\n", machine().describe_context(), offset << 1, physical << 1, data); + if (!machine().side_effects_disabled()) + LOG("%s: mem_w 0x%06x physical 0x%06x data 0x%04x\n", machine().describe_context(), offset << 1, physical << 1, data); COMBINE_DATA(&m_ram[physical]); @@ -335,26 +331,6 @@ void sgi_pm2_device::map_w(offs_t offset, u16 data, u16 mem_mask) m_map[offset >> 11] = data; } -static const gfx_layout sgi_pm2 = -{ - 8, 16, 144, 1, - { 0 }, - { 0, 1, 2, 3, 4, 5, 6, 7 }, - { 15 * 8, 14 * 8, 13 * 8, 12 * 8, 11 * 8, 10 * 8, 9 * 8, 8 * 8, 7 * 8, 6 * 8, 5 * 8, 4 * 8, 3 * 8, 2 * 8, 1 * 8, 0 * 8 }, - 8 * 16 -}; - -static GFXDECODE_START(sgi_pm2_gfx) - GFXDECODE_ENTRY("prom1", 0x1b8c, sgi_pm2, 0, 1) -GFXDECODE_END - -void sgi_pm2_device::gfx_mconfig(machine_config &config) -{ - // gfxdecode is only to show the font data in the tile viewer - PALETTE(config, "palette", palette_device::MONOCHROME); - GFXDECODE(config, "gfx", "palette", sgi_pm2_gfx); -} - ROM_START(sgi_pm2) ROM_DEFAULT_BIOS("v36") ROM_SYSTEM_BIOS(0, "v36", "V3.6 February 28, 1985") |
