From 194691c63475ed5b5beee0174e119e946944613b Mon Sep 17 00:00:00 2001 From: Patrick Mackinlay Date: Thu, 29 Aug 2019 19:49:21 +0700 Subject: 4dpi: graphics wip (nw) --- scripts/target/mame/mess.lua | 8 + src/mame/drivers/4dpi.cpp | 22 +- src/mame/video/sgi_ge5.cpp | 532 +++++++++++++++++++++++++++++++++++++++++++ src/mame/video/sgi_ge5.h | 110 +++++++++ src/mame/video/sgi_gr1.cpp | 472 ++++++++++++++++++++++++++++++++++++++ src/mame/video/sgi_gr1.h | 232 +++++++++++++++++++ src/mame/video/sgi_re2.cpp | 80 +++++++ src/mame/video/sgi_re2.h | 96 ++++++++ 8 files changed, 1550 insertions(+), 2 deletions(-) create mode 100644 src/mame/video/sgi_ge5.cpp create mode 100644 src/mame/video/sgi_ge5.h create mode 100644 src/mame/video/sgi_gr1.cpp create mode 100644 src/mame/video/sgi_gr1.h create mode 100644 src/mame/video/sgi_re2.cpp create mode 100644 src/mame/video/sgi_re2.h diff --git a/scripts/target/mame/mess.lua b/scripts/target/mame/mess.lua index 8ec66c6aff9..f7899a5dc7c 100644 --- a/scripts/target/mame/mess.lua +++ b/scripts/target/mame/mess.lua @@ -395,6 +395,7 @@ VIDEOS["MB88303"] = true VIDEOS["PS2GS"] = true VIDEOS["PS2GIF"] = true VIDEOS["DECSFB"] = true +VIDEOS["BT431"] = true -------------------------------------------------- -- specify available machine cores @@ -719,6 +720,7 @@ MACHINES["DC7085"] = true MACHINES["I82357"] = true MACHINES["XC1700E"] = true MACHINES["EDLC"] = true +MACHINES["WTL3132"] = true -------------------------------------------------- -- specify available bus cores @@ -3193,6 +3195,12 @@ files { MAME_DIR .. "src/mame/video/light.h", MAME_DIR .. "src/mame/video/crime.cpp", MAME_DIR .. "src/mame/video/crime.h", + MAME_DIR .. "src/mame/video/sgi_gr1.cpp", + MAME_DIR .. "src/mame/video/sgi_gr1.h", + MAME_DIR .. "src/mame/video/sgi_ge5.cpp", + MAME_DIR .. "src/mame/video/sgi_ge5.h", + MAME_DIR .. "src/mame/video/sgi_re2.cpp", + MAME_DIR .. "src/mame/video/sgi_re2.h", } createMESSProjects(_target, _subtarget, "sharp") diff --git a/src/mame/drivers/4dpi.cpp b/src/mame/drivers/4dpi.cpp index 5f5add7c5c7..76310244261 100644 --- a/src/mame/drivers/4dpi.cpp +++ b/src/mame/drivers/4dpi.cpp @@ -66,7 +66,7 @@ #include "bus/rs232/hlemouse.h" // video and audio -#include "screen.h" +#include "video/sgi_gr1.h" #define LOG_GENERAL (1U << 0) @@ -87,6 +87,7 @@ public: , m_enet(*this, "enet") , m_duart(*this, "duart%u", 0U) , m_serial(*this, "serial%u", 1U) + , m_gfx(*this, "gfx") , m_leds(*this, "led%u", 0U) { } @@ -107,6 +108,7 @@ private: required_device m_enet; required_device_array m_duart; required_device_array m_serial; + required_device m_gfx; enum leds : unsigned { @@ -241,6 +243,7 @@ void pi4d2x_state::map(address_map &map) //map(0x1e000000, 0x1effffff); // vme a24 modifier 0x39 non-privileged //map(0x1f000000, 0x1fbfffff); // local I/O (duarts, timers, etc.) + map(0x1f000000, 0x1f003fff).m(m_gfx, FUNC(sgi_gr1_device::map)); map(0x1f800000, 0x1f800003).lrw8("memcfg", [this]() { return m_memcfg; }, [this](u8 data) { m_memcfg = data; }).umask32(0xff000000); map(0x1f800000, 0x1f800003).r(FUNC(pi4d2x_state::sysid_r)).umask32(0x00ff0000); @@ -291,7 +294,7 @@ void pi4d2x_state::map(address_map &map) m_eeprom->cs_write(BIT(data, 5)); m_eeprom->clk_write(BIT(data, 6)); - //BIT(data, 7); // gfx_reset: reset graphics subsystem + m_gfx->reset_w(BIT(data, 7)); m_cpuauxctl = data; }).umask32(0xff000000); @@ -593,6 +596,21 @@ void pi4d2x_state::common(machine_config &config) m_serial[1]->cts_handler().set(m_duart[1], FUNC(scn2681_device::ip1_w)); m_serial[1]->dcd_handler().set(m_duart[1], FUNC(scn2681_device::ip2_w)); + // graphics + SGI_GR12(config, m_gfx, 0); + m_gfx->out_vblank().set( + [this](int state) + { + if (state) + m_lio_isr |= LIO_VRSTAT; + else + m_lio_isr &= ~LIO_VRSTAT; + + lio_interrupt(LIO_VR, state); + }); + m_gfx->out_int_ge().set(*this, FUNC(pi4d2x_state::lio_interrupt)).invert(); + m_gfx->out_int_fifo().set(*this, FUNC(pi4d2x_state::lio_interrupt)).invert(); + // TODO: vme slot, cpu interrupt 0 } diff --git a/src/mame/video/sgi_ge5.cpp b/src/mame/video/sgi_ge5.cpp new file mode 100644 index 00000000000..d7e471aa6fd --- /dev/null +++ b/src/mame/video/sgi_ge5.cpp @@ -0,0 +1,532 @@ +// license:BSD-3-Clause +// copyright-holders:Patrick Mackinlay + +/* + * Silicon Graphics GE5 and HQ1 devices. + * + * This board handles the interface to the host, and mainly consists of the HQ1 + * instruction sequencer and the WTL3132 floating-point accelerator. The board + * also contains instruction and data RAM for the HQ1, and a FIFO for host + * communication. + * + * The undocumented HQ1 microcode instruction format is relatively well decoded + * now, but the exact timing and function of many operations remains incomplete. + * + * TODO: + * - skeleton only + * + */ + +#include "emu.h" +#include "debugger.h" +#include "sgi_ge5.h" + +#define LOG_GENERAL (1U << 0) + +//#define VERBOSE (LOG_GENERAL) +#include "logmacro.h" + +DEFINE_DEVICE_TYPE(SGI_GE5, sgi_ge5_device, "ge5", "SGI Geometry Engine 5") + +sgi_ge5_device::sgi_ge5_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock) + : cpu_device(mconfig, SGI_GE5, tag, owner, clock) + , m_code_config("code", ENDIANNESS_BIG, 64, 15, -3, address_map_constructor(FUNC(sgi_ge5_device::code_map), this)) + , m_data_config("data", ENDIANNESS_BIG, 32, 13, -2, address_map_constructor(FUNC(sgi_ge5_device::data_map), this)) + , m_fpu(*this, "fpu") + , m_int_cb(*this) + , m_fifo_empty(*this) + , m_fifo_read(*this) + , m_re_r(*this) + , m_re_w(*this) + , m_icount(0) +{ +} + +void sgi_ge5_device::device_add_mconfig(machine_config &config) +{ + WTL3132(config, m_fpu, clock()); + m_fpu->out_fpcn().set([this](int state) { m_fpu_c = state; }); + m_fpu->out_zero().set([this](int state) { m_fpu_z = state; }); + m_fpu->out_port_x().set([this](u32 data) { m_bus = data; LOG("m_bus = %x\n", data); }); +} + + +void sgi_ge5_device::code_map(address_map &map) +{ + map(0x0000, 0x3fff).ram().share("code"); +} + +void sgi_ge5_device::data_map(address_map &map) +{ + map(0x0000, 0x1fff).ram().share("data"); +} + +void sgi_ge5_device::device_start() +{ + m_int_cb.resolve_safe(); + m_fifo_empty.resolve(); + m_fifo_read.resolve(); + m_re_r.resolve(); + m_re_w.resolve(); + + // TODO: save state + state_add(STATE_GENPC, "GENPC", m_pc).noshow(); + state_add(STATE_GENPCBASE, "CURPC", m_pc).noshow(); + state_add(0, "PC", m_pc).formatstr("%04X"); + + state_add(1, "MEMPTR", m_memptr).formatstr("%04X"); + state_add(2, "REPTR", m_reptr).formatstr("%04X"); + + set_icountptr(m_icount); +} + +void sgi_ge5_device::device_reset() +{ + m_reptr = 0; + m_memptr = 0; + + m_sp = 0; + + if (m_int_state) + { + m_int_state = 0; + m_int_cb(m_int_state); + } + + suspend(SUSPEND_REASON_HALT, false); + LOG("stalled\n"); +} + +device_memory_interface::space_config_vector sgi_ge5_device::memory_space_config() const +{ + return space_config_vector + { + std::make_pair(AS_PROGRAM, &m_code_config), + std::make_pair(AS_DATA, &m_data_config), + }; +} + +std::unique_ptr sgi_ge5_device::create_disassembler() +{ + return std::make_unique(); +} + +enum cx_mask : u8 +{ + INCMEM = 0x08, // increment memptr + FIELD2 = 0x10, // second field active + INCRE = 0x20, // increment reptr + SRC = 0xc0, // data bus source + DST = 0x06, // data bus source + STALL = 0x01, +}; + +void sgi_ge5_device::execute_run() +{ + if (m_fetch) + { + // stall if fifo empty + if (m_fifo_empty()) + { + suspend(SUSPEND_REASON_HALT, false); + return; + } + + // fetch from fifo and set pc + u64 data = m_fifo_read(); + m_bus = u32(data); + m_pc = (data >> 31) & 0x1fe; + m_fetch = false; + } + + while (m_icount > 0) + { + debugger_instruction_hook(m_pc); + + u64 const insn = space(AS_PROGRAM).read_qword(m_pc); + LOG("pc 0x%04x code 0x%011x\n", m_pc, insn); + + u8 const hq1_op = (insn >> 32) & 0xff; + unsigned const src = (hq1_op & SRC) >> 6; + unsigned const dst = (hq1_op & DST) >> 1; + bool const stall = (hq1_op & STALL); + if (hq1_op & FIELD2) + LOG("hq1 op 0x%02x src %d dst %d stall %d branch %d\n", hq1_op, src, dst, stall, (insn >> 29) & 7); + else + LOG("hq1 op 0x%02x src %d dst %d stall %d\n", hq1_op, src, dst, stall); + + // stall when fifo empty and reading from fifo or stall flag + if (((src == 1) || stall) && m_fifo_empty()) + { + // enter fetch mode if destination is fetch + m_fetch = (dst == 1); + LOG(m_fetch ? "FETCH\n" : "STALL\n"); + suspend(SUSPEND_REASON_HALT, false); + m_icount = 0; + continue; + } + + u16 branch = 0; + if (hq1_op & FIELD2) + { + // handle field2 + u64 const field2 = space(AS_PROGRAM).read_qword(++m_pc); + u16 const immediate = (field2 >> 19) & 0x7fff; + + LOG("pc 0x%04x pref 0x%011x immediate 0x%04x\n", m_pc, field2, immediate); + + switch ((field2 >> 32) & 0xfc) + { + case 0x8c: + m_reptr = m_bus; + LOG("REPTR=0x%04x\n", m_reptr); + break; + case 0x9c: + m_reptr = immediate; + LOG("REPTR=0x%04x\n", m_reptr); + break; + case 0xb0: + m_memptr = m_bus; + branch = immediate; + LOG("MEMPTR=0x%04x BRANCH=0x%04x\n", m_memptr, branch); + break; + case 0xb4: + m_memptr = immediate; + LOG("MEMPTR=0x%04x\n", m_memptr); + break; + case 0xb8: + m_memptr_temp = immediate; + LOG("MEMPTR_TMP=0x%04x\n", m_memptr_temp); + break; + case 0xbc: + branch = immediate; + LOG("BRANCH=0x%04x\n", branch); + break; + case 0xfc: // also clear interrupt? + if (!m_int_state) + { + LOG("ge interrupt asserted\n"); + m_int_state = 1; + m_int_cb(m_int_state); + } + break; + //case 0xfe: // set dma count? + default: + LOG("unknown pref 0x%02x\n", (field2 >> 32) & 0xfc); + break; + } + } + + // increment memptr + if (hq1_op & INCMEM) + { + m_memptr++; + LOG("MEMPTR++\n"); + } + + // increment reptr + if (hq1_op & INCRE) + { + m_reptr++; + LOG("REPTR++\n"); + } + + // xx - source (re, fifo, ram, fpu) + // x - increment reptr + // x - field2 + // x - increment memptr + // xx - destination (re, fetch, ram, fpu) + // x - stall? (if fifo empty) + // xxx - branch + + // 00xx xxxx -> ? + // 01xx xxxx -> read fifo + // 10xx xxxx -> read ram + // 11xx xxxx -> read fpu + + u64 fpu_ctrl = + (m_cwen ? wtl3132_device::M_CWEN : 0) | + (2ULL << wtl3132_device::S_ENCN); + + // 43 - get fifo tag + // 46 - get fifo data + // 83 - stall? + // generally reading the fifo causes stalls + // 83 also causes a stall (because can't read code from data ram? + + switch (src) + { + case 0: + m_bus = m_re_r(m_reptr); + LOG("LOAD RE offset 0x%08x data 0x%08x\n", m_reptr, m_bus); + break; + case 1: + m_bus = m_fifo_read(); + LOG("LOAD FIFO 0x%08x\n", m_bus); + break; + case 2: + m_bus = space(AS_DATA).read_dword(m_memptr); + LOG("LOAD MEM offset 0x%04x data 0x%08x\n", m_memptr, m_bus); + break; + case 3: + // tells this instruction to write to the bus in two cycles from now + LOG("FSTORE\n"); + fpu_ctrl |= (2ULL << wtl3132_device::S_IOCT); + break; + } + + // i/o dst + switch (dst) + { + case 0: + LOG("STORE RE offset 0x%02x data 0x%08x\n", m_reptr, m_bus); + m_re_w(m_reptr, m_bus); + break; + case 1: // fetch + if (stall) + { + m_pc = (m_bus >> 31) & 0x1fe; + m_icount--; + // skip pc update and fpu step? + continue; + } + break; + case 2: + space(AS_DATA).write_dword(m_memptr, m_bus); + LOG("STORE MEM offset 0x%02x data 0x%08x\n", m_memptr, m_bus); + break; + case 3: + m_fpu->x_port_w(m_bus); + fpu_ctrl |= (3ULL << wtl3132_device::S_IOCT); + LOG("FLOAD 0x%08x\n", m_bus); + break; + } + + // hq1 branch + if (hq1_op & FIELD2) + { + switch ((insn >> 29) & 7) + { + case 0: m_pc++; break; + case 1: + m_pc = branch; + LOG("J 0x%04x\n", m_pc); + break; + case 2: + if (m_fpu_c) + { + m_pc = branch; + LOG("JC 0x%04x\n", m_pc); + } + break; + case 3: + if (!m_fpu_c) + { + m_pc = branch; + LOG("JNC 0x%04x\n", m_pc); + } + break; + case 4: + m_stack[m_sp] = m_pc + 1; + m_sp = (m_sp + 1) & 7; + m_pc = branch; + LOG("CALL 0x%04x\n", m_pc); + break; + case 5: + if (m_fpu_z) + { + m_pc = branch; + LOG("JZ 0x%04x\n", m_pc); + } + break; + case 6: + if (!m_fpu_z) + { + m_pc = branch; + LOG("JNZ 0x%04x\n", m_pc); + } + break; + case 7: + m_sp = (m_sp + 7) & 7; + m_pc = m_stack[m_sp]; + LOG("RET 0x%04x\n", m_pc); + break; + } + } + else + m_pc++; + + // step fpu + u64 const fpu = ((insn & 0x1fff'f800ULL) << 5) | ((insn & 0x0000'07ffULL) << 2); + + m_fpu->c_port_w(fpu | fpu_ctrl); + m_fpu->clk_w(1); + + m_icount--; + } +} + +void sgi_ge5_device::command_w(offs_t offset, u16 data, u16 mem_mask) +{ + switch (offset) + { + case 0x00: // clear stall + //resume(SUSPEND_REASON_HALT); + LOG("unstalled\n"); + break; + + case 0x10: // setss + case 0x20: // clearss + case 0x30: // executess + break; + + case 0x50: // clearintr + if (m_int_state) + { + LOG("ge interrupt cleared\n"); + m_int_state = 0; + m_int_cb(m_int_state); + } + break; + } +} + +u32 sgi_ge5_device::code_r(offs_t offset) +{ + m_pc = offset | offs_t(m_mar & 0x7f) << 8; + u64 const data = space(AS_PROGRAM).read_qword(m_pc); + + return m_mar_msb ? u32(data >> 32) : u32(data); +} + +void sgi_ge5_device::code_w(offs_t offset, u32 data, u32 mem_mask) +{ + m_pc = offset | offs_t(m_mar & 0x7f) << 8; + + LOG("code_w msb %d offset 0x%08x data 0x%08x mask 0x%08x (%s)\n", m_mar_msb, m_pc, data, mem_mask, machine().describe_context()); + + if (m_mar_msb) + { + u64 const mask = u64(mem_mask & 0x000000ffU) << 32; + + space(AS_PROGRAM).write_qword(m_pc, u64(data) << 32, mask); + } + else + space(AS_PROGRAM).write_qword(m_pc, data, mem_mask); +} + +u32 sgi_ge5_device::data_r(offs_t offset) +{ + m_memptr = offset | offs_t(m_mar & 0x1f) << 8; + + return space(AS_DATA).read_dword(m_memptr); +} + +void sgi_ge5_device::data_w(offs_t offset, u32 data, u32 mem_mask) +{ + m_memptr = offset | offs_t(m_mar & 0x1f) << 8; + + LOG("data_w offset 0x%08x data 0x%08x mask 0x%08x (%s)\n", m_memptr, data, mem_mask, machine().describe_context()); + + space(AS_DATA).write_dword(m_memptr, data, mem_mask); +} + +offs_t sgi_ge5_disassembler::disassemble(std::ostream &stream, offs_t pc, data_buffer const &opcodes, data_buffer const ¶ms) +{ + std::string prefix = ""; + std::string src, dst; + u16 branch; + + u64 const insn = opcodes.r64(pc); + + if (BIT(insn, 36)) + { + u64 const insn_prefix = opcodes.r64(pc + 1); + u16 const immediate = (insn_prefix >> 19) & 0x7fff; + + switch ((insn_prefix >> 32) & 0xfc) + { + case 0x8c: prefix = std::string("LOAD REPTR"); break; + case 0x9c: prefix = util::string_format("REPTR=%04x", immediate); break; + case 0xb0: prefix = std::string("LOAD MEMPTR"); branch = immediate; break; + case 0xb4: prefix = util::string_format("MEMPTR=%04x", immediate); break; + case 0xb8: prefix = util::string_format("MEMPTR_TEMP=%04x", immediate); break; + case 0xbc: branch = immediate; break; + case 0xfc: prefix = std::string("SET_INT"); break; + //case 0xfe: // set dma count? + } + } + + u8 const hq1_op = (insn >> 32) & 0xff; + + // pre-increment memptr + //if (BIT(hq1_op, 3)) + // ; + + // pre-increment reptr + //if (BIT(hq1_op, 5)) + // ; + + // xx - source (?, fifo, ram, fpu) + // x - increment reptr + // x - ? + // x - increment memptr + // xxx - destination (re, ?, bus, stall?, ram, ?, fpu, ?) + + // 00xx xxxx -> ? + // 01xx xxxx -> read fifo + // 10xx xxxx -> read ram + // 11xx xxxx -> read fpu + + u64 fpu_ctrl = 0x2'8000'0000; // ENCN=2, IOCT=2 + + switch (hq1_op >> 6) + { + case 0: src = std::string("0?"); break; + case 1: src = std::string("fifo"); break; + case 2: src = std::string("bus"); break; + case 3: src = std::string("fpu"); break; // IOCT=2 + } + + // i/o dst + switch (hq1_op & 7) + { + case 0: dst = std::string("REPTR"); break; + case 1: dst = std::string("1?"); break; + case 2: dst = std::string("bus?"); break; + case 3: dst = std::string("stall?"); break; + case 4: dst = std::string("MEMPTR"); break; + case 5: dst = std::string("5?"); break; + case 6: dst = std::string("FPU"); fpu_ctrl |= 0x4000'0000; break; // fpu IOCT=3 + case 7: dst = std::string("7?"); break; + } + + std::string fpu = wtl3132_device::disassemble( + bitswap<34>((insn & 0x0fff'ffff) | fpu_ctrl, + 28, 27, 26, // f + 25, 24, 23, 22, 21, // aadd + 20, 19, 18, 17, 16, // badd + 15, 14, 13, 12, 11, // cadd + 29, // cwen* + 31, 30, // ioct* + 10, 9, 8, 7, 6, // dadd + 5, 4, 3, // abin + 2, 1, // adst + 0, // mbin + 33, 32)); // encn* + + // hq1 branch + switch ((insn >> 29) & 7) + { + case 0: util::stream_format(stream, "%s; %s; R:%s, W:%s", prefix, fpu, src, dst); break; + case 1: util::stream_format(stream, "%s; %s; R:%s, W:%s; J:%04x", prefix, fpu, src, dst, branch); break; + case 2: util::stream_format(stream, "%s; %s; R:%s, W:%s; JC:%04x", prefix, fpu, src, dst, branch); break; + case 3: util::stream_format(stream, "%s; %s; R:%s, W:%s; JNC:%04x", prefix, fpu, src, dst, branch); break; + case 4: util::stream_format(stream, "%s; %s; R:%s, W:%s; CALL:%04x", prefix, fpu, src, dst, branch); break; + case 5: util::stream_format(stream, "%s; %s; R:%s, W:%s; JZ:%04x", prefix, fpu, src, dst, branch); break; + case 6: util::stream_format(stream, "%s; %s; R:%s, W:%s; JNZ:%04x", prefix, fpu, src, dst, branch); break; + case 7: util::stream_format(stream, "%s; %s; R:%s, W:%s; RET", prefix, fpu, src, dst); break; + } + + return BIT(insn, 36) ? 2 : 1; +} diff --git a/src/mame/video/sgi_ge5.h b/src/mame/video/sgi_ge5.h new file mode 100644 index 00000000000..91cf029a211 --- /dev/null +++ b/src/mame/video/sgi_ge5.h @@ -0,0 +1,110 @@ +// license:BSD-3-Clause +// copyright-holders:Patrick Mackinlay + +#ifndef MAME_VIDEO_SGI_GE5_H +#define MAME_VIDEO_SGI_GE5_H + +#pragma once + +#include "machine/wtl3132.h" + +class sgi_ge5_device : public cpu_device +{ +public: + sgi_ge5_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock); + + auto out_int() { return m_int_cb.bind(); } + auto fifo_empty() { return m_fifo_empty.bind(); } + auto fifo_read() { return m_fifo_read.bind(); } + + auto re_r() { return m_re_r.bind(); } + auto re_w() { return m_re_w.bind(); } + + // device_t overrides + virtual void device_add_mconfig(machine_config &config) override; + virtual void device_start() override; + virtual void device_reset() override; + + // device_memory_interface overrides + virtual space_config_vector memory_space_config() const override; + + // device_disasm_interface overrides + virtual std::unique_ptr create_disassembler() override; + + // device_execute_interface overrides + virtual u32 execute_min_cycles() const override { return 1; } + virtual u32 execute_max_cycles() const override { return 1; } + virtual u32 execute_input_lines() const override { return 1; } + virtual void execute_run() override; + virtual void execute_set_input(int inputnum, int state) override {} + + u32 code_r(offs_t offset); + u32 data_r(offs_t offset); + void code_w(offs_t offset, u32 data, u32 mem_mask); + void data_w(offs_t offset, u32 data, u32 mem_mask); + + void command_w(offs_t offset, u16 data, u16 mem_mask); + u16 pc_r() { return m_pc; } + void mar_w(offs_t offset, u32 data, u32 mem_mask) { m_mar = offset & 0x7f; } + void mar_msb_w(offs_t offset, u32 data, u32 mem_mask) { m_mar_msb = bool(offset); } + void cwen_w(int state) { m_cwen = bool(state); } + +protected: + void code_map(address_map &map); + void data_map(address_map &map); + +private: + // device configuration state + address_space_config m_code_config; + address_space_config m_data_config; + + required_device m_fpu; + + devcb_write_line m_int_cb; + int m_int_state; + + devcb_read_line m_fifo_empty; + devcb_read64 m_fifo_read; + devcb_read32 m_re_r; + devcb_write32 m_re_w; + + // runtime state + int m_icount; + + // cpu state + bool m_fetch; + u16 m_pc; + unsigned m_sp; + u16 m_stack[8]; + + u16 m_memptr; + u16 m_memptr_temp; + u8 m_reptr; + u16 m_dma_count; + + u64 m_bus; + + u8 m_mar; + bool m_mar_msb; + + int m_fpu_c; + int m_fpu_z; + + bool m_cwen; +}; + +class sgi_ge5_disassembler : public util::disasm_interface +{ +public: + sgi_ge5_disassembler() = default; + virtual ~sgi_ge5_disassembler() = default; + + virtual u32 opcode_alignment() const override { return 1; } + virtual offs_t disassemble(std::ostream &stream, offs_t pc, data_buffer const &opcodes, data_buffer const ¶ms) override; + +private: +}; + +DECLARE_DEVICE_TYPE(SGI_GE5, sgi_ge5_device) + +#endif // MAME_VIDEO_SGI_GE5_H diff --git a/src/mame/video/sgi_gr1.cpp b/src/mame/video/sgi_gr1.cpp new file mode 100644 index 00000000000..cd29fe65f61 --- /dev/null +++ b/src/mame/video/sgi_gr1.cpp @@ -0,0 +1,472 @@ +// license:BSD-3-Clause +// copyright-holders:Patrick Mackinlay + +/* + * Silicon Graphics GR1 (aka Eclipse) graphics hardware. + * + * This graphics system was first designed for the Personal Iris 4D/20, + * connecting via a unique graphics port interface. The system was later + * adapted and released under the IrisVision brand, initially with a Micro + * Channel Architecture bus interface and support for IBM RS/6000 and some IBM + * PS/2 systems. A final variant has a 16-bit ISA bus interface enabling use in + * PC-AT and compatible systems. + * + * The TG-V variation fits into the VME chassis and slots of the SGI V20 and + * V30/35, however control and data signals are delivered via a ribbon cable to + * the CPU and I/O boards, and only draws power and ground from the VME slot. + * + * All versions of the hardware consist of two primary boards which mount into + * host system slots, plus several daughter-boards which mount on the two + * primary boards. + * + * The board set consists of: + * + * Name Description Function + * Geometry Engine host interface and geometry engine (HQ1, GE5) + * Display Engine raster video and display subsystem (RE2 + 1-2 Bt431 cursor chips + 8 pixel, 2 overlay/underlay, 2 wid bitplanes) + * Video Driver basic video daughter-board (5 XPC1 ASICs, Bt458 RGB RAMDAC) + * Video Driver enhanced video daughter-board (5 XMAP2 ASICs, 8K color map, 3 Bt457 RAMDACs) + * OP1 Bitplane Board optional bitplane expansion (adds 2 overlay/underlay, 2 wid planes) + * BP4 Bitplane Board optional bitplane expansion (adds 16 pixel, 2 overlay/underlay, 2 wid planes, 4k color map) + * ZB3 Z-buffer Z-buffer option (adds 24 Z-buffer planes, requires BP4) + * GT1/GT2 Turbo Board turbo graphics option (4 TMS320C30 DSPs) + * + * Sources: + * - http://ohlandl.ipv7.net/video/Iris.html + * - https://www.4crawler.com/IrisVision/index.shtml + * - http://archive.irix.cc/sgistuff/hardware/graphics/eclipse.html + * + * TODO: + * - ge5/hq1 + * - raster engine + * - dma + * - slotify (SGI, MCA, ISA) + * - everything else + */ + +#include "emu.h" +#include "sgi_gr1.h" + +#define LOG_GENERAL (1U << 0) +#define LOG_READS (1U << 1) + +//#define VERBOSE (LOG_GENERAL) + +#include "logmacro.h" + +DEFINE_DEVICE_TYPE(SGI_GR11, sgi_gr11_device, "sgi_gr11", "SGI GR1.1 Graphics") +DEFINE_DEVICE_TYPE(SGI_GR12, sgi_gr12_device, "sgi_gr12", "SGI GR1.2 Graphics") + +sgi_gr1_device::sgi_gr1_device(machine_config const &mconfig, device_type type, char const *tag, device_t *owner, u32 clock) + : device_t(mconfig, type, tag, owner, clock) + , m_screen(*this, "screen") + , m_re(*this, "re2") + , m_ge(*this, "ge5") + , m_cursor(*this, "cursor%u", 0U) + , m_vblank_cb(*this) + , m_int_fifo_cb(*this) +{ +} + +sgi_gr11_device::sgi_gr11_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock) + : sgi_gr1_device(mconfig, SGI_GR11, tag, owner, clock) + , m_ramdac(*this, "ramdac") +{ +} + +sgi_gr12_device::sgi_gr12_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock) + : sgi_gr1_device(mconfig, SGI_GR12, tag, owner, clock) + , m_ramdac(*this, "ramdac%u", 0U) +{ +} + +void sgi_gr1_device::map(address_map &map) +{ + // TODO: bank based on mar_msb + + map(0x0000, 0x03ff).rw(m_ge, FUNC(sgi_ge5_device::code_r), FUNC(sgi_ge5_device::code_w)); + + map(0x04c0, 0x04c3).rw(FUNC(sgi_gr1_device::dr1_r), FUNC(sgi_gr1_device::dr1_w)).umask32(0xff000000); + map(0x04e0, 0x04e3).rw(FUNC(sgi_gr1_device::dr0_r), FUNC(sgi_gr1_device::dr0_w)).umask32(0xff000000); + + map(0x0560, 0x056f).m(m_cursor[0], FUNC(bt431_device::map)).umask32(0xff000000); + map(0x0580, 0x058f).m(m_cursor[1], FUNC(bt431_device::map)).umask32(0xff000000); + + map(0x05a0, 0x05a3).rw(FUNC(sgi_gr1_device::dr4_r), FUNC(sgi_gr1_device::dr4_w)).umask32(0xff000000); + map(0x05c0, 0x05c3).rw(FUNC(sgi_gr1_device::dr3_r), FUNC(sgi_gr1_device::dr3_w)).umask32(0xff000000); + map(0x05e0, 0x05e3).rw(FUNC(sgi_gr1_device::dr2_r), FUNC(sgi_gr1_device::dr2_w)).umask32(0xff000000); + + map(0x0640, 0x783).w(m_ge, FUNC(sgi_ge5_device::command_w)).umask32(0xffff0000); + map(0x0740, 0x743).r(m_ge, FUNC(sgi_ge5_device::pc_r)).umask32(0xffff0000); + + map(0x0800, 0x0bff).w(FUNC(sgi_gr1_device::fifo_w)); + map(0x0c00, 0x0dff).w(m_ge, FUNC(sgi_ge5_device::mar_w)); + map(0x0e00, 0x0e07).w(m_ge, FUNC(sgi_ge5_device::mar_msb_w)); + + map(0x1400, 0x17ff).rw(m_ge, FUNC(sgi_ge5_device::data_r), FUNC(sgi_ge5_device::data_w)); + map(0x2000, 0x2007).lrw32("ff", + [this](offs_t offset) { LOG("read finish flag %d\n", offset); return m_ff[offset]; }, + [this](offs_t offset, u32 data, u32 mem_mask) { LOG("write finish flag %d data %d\n", offset, data); m_ff[offset] = data; }); + //map(0x207c, 0x207f); // gr1 vs gr2 +} + +void sgi_gr11_device::map(address_map &map) +{ + sgi_gr1_device::map(map); + + map(0x0510, 0x0517).rw(FUNC(sgi_gr11_device::xpc1_r<0>), FUNC(sgi_gr11_device::xpc1_w<0>)).umask32(0x000000ff); + map(0x0530, 0x0537).rw(FUNC(sgi_gr11_device::xpc1_r<1>), FUNC(sgi_gr11_device::xpc1_w<1>)).umask32(0x000000ff); + map(0x0550, 0x0557).rw(FUNC(sgi_gr11_device::xpc1_r<2>), FUNC(sgi_gr11_device::xpc1_w<2>)).umask32(0x000000ff); + map(0x0570, 0x0577).rw(FUNC(sgi_gr11_device::xpc1_r<3>), FUNC(sgi_gr11_device::xpc1_w<3>)).umask32(0x000000ff); + map(0x0590, 0x0597).rw(FUNC(sgi_gr11_device::xpc1_r<4>), FUNC(sgi_gr11_device::xpc1_w<4>)).umask32(0x000000ff); + + map(0x05b0, 0x05b7).w(FUNC(sgi_gr11_device::xpc1_bc_w)).umask32(0x000000ff); + + map(0x05d0, 0x05df).m(m_ramdac, FUNC(bt458_device::map)); +} + +void sgi_gr12_device::map(address_map &map) +{ + sgi_gr1_device::map(map); + + map(0x0400, 0x041f).rw(FUNC(sgi_gr12_device::xmap2_r<0>), FUNC(sgi_gr12_device::xmap2_w<0>)).umask32(0x000000ff); + map(0x0420, 0x043f).rw(FUNC(sgi_gr12_device::xmap2_r<1>), FUNC(sgi_gr12_device::xmap2_w<1>)).umask32(0x000000ff); + map(0x0440, 0x045f).rw(FUNC(sgi_gr12_device::xmap2_r<2>), FUNC(sgi_gr12_device::xmap2_w<2>)).umask32(0x000000ff); + map(0x0460, 0x047f).rw(FUNC(sgi_gr12_device::xmap2_r<3>), FUNC(sgi_gr12_device::xmap2_w<3>)).umask32(0x000000ff); + map(0x0480, 0x049f).rw(FUNC(sgi_gr12_device::xmap2_r<4>), FUNC(sgi_gr12_device::xmap2_w<4>)).umask32(0x000000ff); + map(0x04a0, 0x04bf).w(FUNC(sgi_gr12_device::xmap2_bc_w)).umask32(0x000000ff); + + map(0x0500, 0x050f).m(m_ramdac[0], FUNC(bt457_device::map)).umask32(0x000000ff); + map(0x0520, 0x052f).m(m_ramdac[1], FUNC(bt457_device::map)).umask32(0x000000ff); + map(0x0540, 0x054f).m(m_ramdac[2], FUNC(bt457_device::map)).umask32(0x000000ff); +} + +void sgi_gr1_device::device_add_mconfig(machine_config &config) +{ + unsigned pixel_clock = 107'352'000; + + //ADDRESS_MAP_BANK(config, m_ext).set_map(&lle_device_base::ext_map).set_options(ENDIANNESS_NATIVE, 8, 12, 0x100); + + /* + * 1280x1024 @ 60Hz + * 107.352MHz pixel clock + * horizontal sync 63.9kHz, pulse width == 120 pixels + * vertical sync 60Hz, front/sync/back == 3/3/35 lines + * + // SGI GR1 offsets: + // 1280: Cx:D+H-P=0+246-57, Cy:V-32=39-32 (189, 7) + // 1024: Cx:D+H-P=0+126-57, Cy:V-32=43-32 + // NTSC: Cx:D+H-P=-6, Cy:V-32=-554 + // PAL: Cx:D+H-P=24, Cy:V-32=-457 + // 30HZ: Cx:D+H-P=39, Cy:V-32=18 + // STEREO: Cx:D+H-P=0+246-57, Cy:V-32=39-32+1 + * + */ + SCREEN(config, m_screen, SCREEN_TYPE_RASTER); + m_screen->set_raw(pixel_clock, 1680, 246, 246 + 1280, 1065, 39, 39 + 1024); + m_screen->set_screen_update(FUNC(sgi_gr1_device::screen_update)); + m_screen->screen_vblank().set([this](int state) { m_vblank_cb(state); }); + + SGI_RE2(config, m_re, 0); + + SGI_GE5(config, m_ge, 10_MHz_XTAL); + m_ge->fifo_empty().set([this]() { return int(m_fifo.empty()); }); + m_ge->fifo_read().set([this]() { return m_fifo.dequeue(); }); + m_ge->re_r().set(m_re, FUNC(sgi_re2_device::reg_r)); + m_ge->re_w().set(m_re, FUNC(sgi_re2_device::reg_w)); + + BT431(config, m_cursor[0], pixel_clock / 5); + BT431(config, m_cursor[1], pixel_clock / 5); +} + +void sgi_gr11_device::device_add_mconfig(machine_config &config) +{ + sgi_gr1_device::device_add_mconfig(config); + + BT458(config, m_ramdac, 107'352'000); +} + +void sgi_gr12_device::device_add_mconfig(machine_config &config) +{ + sgi_gr1_device::device_add_mconfig(config); + + BT457(config, m_ramdac[0], 107'352'000); + BT457(config, m_ramdac[1], 107'352'000); + BT457(config, m_ramdac[2], 107'352'000); +} + +void sgi_gr1_device::device_start() +{ + m_vblank_cb.resolve_safe(); + m_int_fifo_cb.resolve_safe(); + + //save_item(NAME()); +} + +void sgi_gr11_device::device_start() +{ + sgi_gr1_device::device_start(); +} + +void sgi_gr12_device::device_start() +{ + sgi_gr1_device::device_start(); + + m_vram = std::make_unique(1280 * 1024); +} + +void sgi_gr1_device::device_reset() +{ + //m_dr0 = DR0_ZBIN; + //m_dr2 = DR2_BPIN; + //m_dr3 = DR3_MS; + m_dr4 = 0; + + m_fifo.clear(); +} + +void sgi_gr11_device::device_reset() +{ + sgi_gr1_device::device_reset(); +} + +void sgi_gr12_device::device_reset() +{ + sgi_gr1_device::device_reset(); + + //m_dr0 &= ~DR0_ZBIN; + //m_dr2 &= ~DR2_BPIN; +} + +u32 sgi_gr11_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, rectangle const &cliprect) +{ + /* + * fb_pixel (8) bits, cursor (2 bits), pup (2 bits), wid (2 bits) + * + * iterate through 5 xpc1 channels + * mode = xpc1[channel][wid] + * + */ + + return 0; +} + +u32 sgi_gr12_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, rectangle const &cliprect) +{ + // TODO: underlay + + unsigned offset = 0; + + 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 += 5) + for (unsigned c = 0; c < 5; c++) + { + u8 const overlay = (m_cursor[0]->cur_r(x + c, y) ? 1 : 0) | (m_cursor[1]->cur_r(x + c, y) ? 2 : 0); + u32 const data = m_vram[offset++]; + u16 const mode = m_xmap2[c].mode[data >> 28]; + + switch (mode & 0x07) + { + case 0: // 8 bit ci single buffer + { + u16 const ci = BIT(mode, 9) ? (mode & 0x0f00) | u8(data) : u8(data); + rgb_t const cm = m_xmap2[c].color[(m_dr4 & DR4_MS) ? ci | 0x1000 : ci]; + + bitmap.pix(y, x) = rgb_t( + m_ramdac[0]->lookup(cm.r(), overlay), + m_ramdac[1]->lookup(cm.g(), overlay), + m_ramdac[2]->lookup(cm.b(), overlay)); + } + break; + + case 1: // 4 bit ci double buffer + { + u8 const fb = BIT(mode, 3) ? u8(data) >> 4 : data & 0x0f; + u16 const ci = BIT(mode, 9) ? (mode & 0x0f00) | fb : fb; + rgb_t const cm = m_xmap2[c].color[(m_dr4 & DR4_MS) ? ci | 0x1000 : ci]; + + bitmap.pix(y, x) = rgb_t( + m_ramdac[0]->lookup(cm.r(), overlay), + m_ramdac[1]->lookup(cm.g(), overlay), + m_ramdac[2]->lookup(cm.b(), overlay)); + } + break; + + case 2: // 12 bit ci double buffer + { + u8 const fb = u16(BIT(mode, 3) ? data >> 12 : data) & 0x0fff; + u16 const ci = BIT(mode, 9) ? (mode & 0x0f00) | (fb & 0xff) : fb; + rgb_t const cm = m_xmap2[c].color[(m_dr4 & DR4_MS) ? ci | 0x1000 : ci]; + + bitmap.pix(y, x) = rgb_t( + m_ramdac[0]->lookup(cm.r(), overlay), + m_ramdac[1]->lookup(cm.g(), overlay), + m_ramdac[2]->lookup(cm.b(), overlay)); + } + break; + + case 4: // 24 bit rgb single buffer + bitmap.pix(y, x) = rgb_t( + m_ramdac[0]->lookup(u8(data >> 0), overlay), + m_ramdac[1]->lookup(u8(data >> 8), overlay), + m_ramdac[2]->lookup(u8(data >> 16), overlay)); + break; + + case 5: // 12 bit rgb double buffer + bitmap.pix(y, x) = BIT(mode, 3) ? + rgb_t( + m_ramdac[0]->lookup((u8(data >> 0) & 0xf0) | (u8(data >> 4) & 0x0f), overlay), + m_ramdac[1]->lookup((u8(data >> 8) & 0xf0) | (u8(data >> 12) & 0x0f), overlay), + m_ramdac[2]->lookup((u8(data >> 16) & 0xf0) | (u8(data >> 20) & 0x0f), overlay)) : + rgb_t( + m_ramdac[0]->lookup((u8(data << 4) & 0xf0) | (u8(data >> 0) & 0x0f), overlay), + m_ramdac[1]->lookup((u8(data >> 4) & 0xf0) | (u8(data >> 8) & 0x0f), overlay), + m_ramdac[2]->lookup((u8(data >> 12) & 0xf0) | (u8(data >> 16) & 0x0f), overlay)); + break; + } + } + + return 0; +} + +void sgi_gr1_device::fifo_w(offs_t offset, u32 data, u32 mem_mask) +{ + if (m_fifo.full()) + fatalerror("fifo_w: fifo overflow (%s)", machine().describe_context().c_str()); + + LOG("fifo_w 0x%010x\n", (u64(offset) << 32) | data); + + m_fifo.enqueue((u64(offset) << 32) | data); + + if (m_fifo.queue_length() > 256) + m_int_fifo_cb(ASSERT_LINE); + + //if (m_ge->suspended()) + // m_ge->resume(SUSPEND_REASON_HALT); +} + +void sgi_gr1_device::reset_w(int state) +{ + if (state) + { + LOG("reset_w %d\n", state); + m_ge->pulse_input_line(INPUT_LINE_RESET, attotime::from_ticks(1, 10_MHz_XTAL)); + } +} + +template u8 sgi_gr12_device::xmap2_r(offs_t offset) +{ + xmap2 const x = m_xmap2[Channel]; + + switch (offset) + { + case 0: // nop + break; + + case 1: // blue data + if (x.addr & 0x1000) + return x.color[(m_dr4 & DR4_MS) ? x.addr : (x.addr & 0xfff)].b(); + else if (x.addr < 0x10) + return x.overlay[x.addr].b(); + break; + + case 2: // green data + if (x.addr & 0x1000) + return x.color[(m_dr4 & DR4_MS) ? x.addr : (x.addr & 0xfff)].g(); + else if (x.addr < 0x10) + return x.overlay[x.addr].g(); + break; + + case 3: // red data + if (x.addr & 0x1000) + return x.color[(m_dr4 & DR4_MS) ? x.addr : (x.addr & 0xfff)].r(); + else if (x.addr < 0x10) + return x.overlay[x.addr].r(); + break; + + case 4: // increment address + // TODO: should reading increment the address register? + //x.addr = (x.addr + 1) & 0x1fff; + LOG("read address increment\n"); + break; + + case 5: // other data + if (x.addr < 0x20) + { + u16 const mode = x.mode[(x.addr >> 1) & 0xf]; + + return BIT(x.addr, 0) ? (mode >> 8) : u8(mode); + } + else if (x.addr == 0x20) + return x.wid_aux; + else if (x.addr == 0x21) + return 0x18; // z-buffer and bit-plane expansion not present? + break; + + case 6: // address msb + return x.addr >> 8; + + case 7: // address lsb + return u8(x.addr); + } + + return 0; +} + +template void sgi_gr12_device::xmap2_w(offs_t offset, u8 data) +{ + xmap2 &x = m_xmap2[Channel]; + + switch (offset) + { + case 0: // nop + break; + + case 1: // blue data + if (x.addr & 0x1000) + x.color[(m_dr4 & DR4_MS) ? x.addr : (x.addr & 0xfff)].set_b(data); + else if (x.addr < 0x10) + x.overlay[x.addr].set_b(data); + break; + + case 2: // green data + if (x.addr & 0x1000) + x.color[(m_dr4 & DR4_MS) ? x.addr : (x.addr & 0xfff)].set_g(data); + else if (x.addr < 0x10) + x.overlay[x.addr].set_g(data); + break; + + case 3: // red data + if (x.addr & 0x1000) + x.color[(m_dr4 & DR4_MS) ? x.addr : (x.addr & 0xfff)].set_r(data); + else if (x.addr < 0x10) + x.overlay[x.addr].set_r(data); + break; + + case 4: // increment address + x.addr = (x.addr + 1) & 0x1fff; + break; + + case 5: // other data + if (x.addr < 0x20) + { + u16 &mode = x.mode[(x.addr >> 1) & 0xf]; + + if (BIT(x.addr, 0)) + mode = (u16(data & 0x3f) << 8) | (mode & 0x00ff); + else + mode = (mode & 0x3f00) | data; + } + else if (x.addr == 0x20) + x.wid_aux = BIT(data, 0); + break; + + case 6: // address msb + x.addr = u16((data & 0x1f) << 8) | (x.addr & 0x00ff); + break; + + case 7: // address lsb + x.addr = (x.addr & 0x1f00) | data; + break; + } +} diff --git a/src/mame/video/sgi_gr1.h b/src/mame/video/sgi_gr1.h new file mode 100644 index 00000000000..40b3196c01b --- /dev/null +++ b/src/mame/video/sgi_gr1.h @@ -0,0 +1,232 @@ +// license:BSD-3-Clause +// copyright-holders:Patrick Mackinlay + +#ifndef MAME_VIDEO_SGI_GR1_H +#define MAME_VIDEO_SGI_GR1_H + +#pragma once + +#include "machine/bankdev.h" +#include "screen.h" +#include "video/sgi_ge5.h" +#include "video/sgi_re2.h" +#include "video/bt45x.h" +#include "video/bt431.h" + +class sgi_gr1_device : public device_t +{ +public: + static constexpr feature_type imperfect_features() { return feature::GRAPHICS; } + + // configuration + auto out_vblank() { return m_vblank_cb.bind(); } + auto out_int_ge() { return subdevice("ge5")->out_int(); } + auto out_int_fifo() { return m_int_fifo_cb.bind(); } + + void reset_w(int state); + + virtual void map(address_map &map); + +protected: + sgi_gr1_device(machine_config const &mconfig, device_type type, char const *tag, device_t *owner, u32 clock); + + // device_t overrides + virtual void device_add_mconfig(machine_config &config) override; + virtual void device_start() override; + virtual void device_reset() override; + + virtual u32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, rectangle const &cliprect) = 0; + + u8 dr0_r() { return m_dr0; } + u8 dr1_r() { return m_dr1; } + u8 dr2_r() { return m_dr2; } + u8 dr3_r() { return m_dr3 | (m_fifo.empty() ? 0 : DR3_FIFOEMPTY); } + u8 dr4_r() { return m_dr4 & DR4_RM; } + void dr0_w(u8 data) { m_dr0 = (m_dr0 & ~DR0_WM) | (data & DR0_WM); } + void dr1_w(u8 data) { m_dr1 = (m_dr1 & ~DR1_WM) | (data & DR1_WM); m_ge->cwen_w(BIT(data, 1)); } + void dr2_w(u8 data) { m_dr2 = (m_dr2 & ~DR2_WM) | (data & DR2_WM); } + void dr3_w(u8 data) { m_dr3 = (m_dr3 & ~DR3_WM) | (data & DR3_WM); } + void dr4_w(u8 data) { m_dr4 = (m_dr4 & ~DR4_WM) | (data & DR4_WM); } + + void fifo_w(offs_t offset, u32 data, u32 mem_mask); + +//private: + required_device m_screen; + required_device m_re; + required_device m_ge; + required_device_array m_cursor; + + devcb_write_line m_vblank_cb; + devcb_write_line m_int_fifo_cb; + + enum dr0_mask : u8 + { + DR0_GRF1EN = 0x01, // grf1 board enable (active low, disable for RE2) + DR0_PGRINBIT = 0x02, // reflects PGROUTBIT (PGR) + DR0_PGROUTBIT = 0x04, // routed to PGRINBIT (PGR) + DR0_ZBUF0 = 0x08, // mzb1 card is installed (active low, ro, MGR) + DR0_SMALLMON0 = 0x08, // small monitor installed (active low, non-MGR) + + DR0_WM = 0xf7, // write mask + }; + enum dr1_mask : u8 + { + DR1_SE = 0x01, // sync on green enable (active low, rw) + DR1_CWEN = 0x02, // wtl3132 cwen- + DR1_VRLS = 0x04, // vertical retrace latency select + DR1_MTYPE = 0x06, // monitor type msb (rw) + DR1_TURBO = 0x08, // turbo option installed (active low, ro) + DR1_OVERLAY0A = 0x10, // dac overlay bit 0 bank a (ro) + + DR1_WM = 0xf7, // write mask + }; + enum dr2_mask : u8 + { + DR2_SCREENON = 0x01, // standby (rw) + DR2_UNCOM2 = 0x02, // uncomitted bit to xilinx + DR2_LEDOFF = 0x04, // disable led + DR2_BITPLANES = 0x08, // extra bitplanes installed (active low, ro) + DR2_ZBUF = 0x10, // z-buffer installed (active low, non-MGR, ro) + + DR2_WM = 0xf1, // write mask + }; + enum dr3_mask : u8 + { + DR3_GENSTATEN = 0x01, // enable genlock status out + DR3_LSBBLUEOUT = 0x01, // latch blue lsb out (VGR only) + DR3_LCARESET = 0x02, // reset xilix lca (active low, rw) + DR3_MONITORRESET = 0x04, // monitor set (rw) + DR3_FIFOEMPTY = 0x08, // fifo empty (active low, ro) + DR3_FIFOFULL = 0x10, // fifo half full (active low, ro) + + DR3_WM = 0xf7, // write mask + }; + enum dr4_mask : u8 + { + DR4_MONITORMASK = 0x03, // monitor type lsb (rw) + DR4_EXTCLKSEL = 0x04, // select external pixel clock (rw) + DR4_MEGOPT = 0x08, // 1M video rams installed (ro) + DR4_GESTALL = 0x10, // ge stalled (active low, ro) + DR4_ACLKEN = 0x20, // asynchronous clock enabled (wo) + DR4_SCLKEN = 0x40, // synchronous clock enabled (wo) + DR4_MS = 0x80, // select upper 4K color map (rw) + + DR4_RM = 0x9f, // read mask + DR4_WM = 0xff, // write mask + }; + + u8 m_dr0; + u8 m_dr1; + u8 m_dr2; + u8 m_dr3; + u8 m_dr4; + + util::fifo m_fifo; + u32 m_ff[2]; +}; + +class sgi_gr11_device : public sgi_gr1_device +{ +public: + sgi_gr11_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock); + + virtual void map(address_map &map) override; + +protected: + // device_t overrides + virtual void device_add_mconfig(machine_config &config) override; + virtual void device_start() override; + virtual void device_reset() override; + + virtual u32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, rectangle const &cliprect) override; + + template u8 xpc1_r(offs_t offset) + { + if (offset) + { + unsigned const address = m_xpc1_addr[Channel]; + u16 const mode = m_xpc1_mode[Channel][address >> 1]; + + return BIT(address, 0) ? (mode >> 8) : u8(mode); + } + else + return m_xpc1_addr[Channel]; + } + + template void xpc1_w(offs_t offset, u8 data) + { + if (offset) + { + unsigned const address = m_xpc1_addr[Channel]; + u16 &mode = m_xpc1_mode[Channel][address >> 1]; + + if (BIT(address, 0)) + mode = (u16(data & 0x3f) << 8) | (mode & 0x00ff); + else + mode = (mode & 0x3f00) | data; + } + else + m_xpc1_addr[Channel] = data & 7; + } + void xpc1_bc_w(offs_t offset, u8 data) + { + xpc1_w<0>(offset, data); + xpc1_w<1>(offset, data); + xpc1_w<2>(offset, data); + xpc1_w<3>(offset, data); + xpc1_w<4>(offset, data); + } + +private: + required_device m_ramdac; + + u8 m_xpc1_addr[5]; + u16 m_xpc1_mode[5][4]; +}; + +class sgi_gr12_device : public sgi_gr1_device +{ +public: + sgi_gr12_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock); + + virtual void map(address_map &map) override; + +protected: + // device_t overrides + virtual void device_add_mconfig(machine_config &config) override; + virtual void device_start() override; + virtual void device_reset() override; + + virtual u32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, rectangle const &cliprect) override; + + template u8 xmap2_r(offs_t offset); + template void xmap2_w(offs_t offset, u8 data); + void xmap2_bc_w(offs_t offset, u8 data) + { + xmap2_w<0>(offset, data); + xmap2_w<1>(offset, data); + xmap2_w<2>(offset, data); + xmap2_w<3>(offset, data); + xmap2_w<4>(offset, data); + } + +private: + required_device_array m_ramdac; + + std::unique_ptr m_vram; + + struct xmap2 + { + u16 addr; + rgb_t color[8192]; + rgb_t overlay[16]; + u16 mode[16]; + bool wid_aux; + } + m_xmap2[5]; +}; + +DECLARE_DEVICE_TYPE(SGI_GR11, sgi_gr11_device) +DECLARE_DEVICE_TYPE(SGI_GR12, sgi_gr12_device) + +#endif // MAME_VIDEO_SGI_GR1_H diff --git a/src/mame/video/sgi_re2.cpp b/src/mame/video/sgi_re2.cpp new file mode 100644 index 00000000000..225ab16a598 --- /dev/null +++ b/src/mame/video/sgi_re2.cpp @@ -0,0 +1,80 @@ +// license:BSD-3-Clause +// copyright-holders:Patrick Mackinlay + +/* + * Silicon Graphics RE2 device. + * + * TODO: + * - skeleton only + * + */ + +#include "emu.h" +#include "debugger.h" +#include "sgi_re2.h" + +#define LOG_GENERAL (1U << 0) +#define LOG_REG (1U << 1) + +//#define VERBOSE (LOG_GENERAL|LOG_REG) +#include "logmacro.h" + +static char const *const regnames[] = +{ + nullptr, nullptr, nullptr, nullptr, "ENABRGB", "BIGENDIAN", "FUNC", "HADDR", + "NOPUP", "XYFRAC", "RGB", "YX", "PUPDATA", "PATL", "PATH", "DZI", + "DZF", "DR", "DG", "DB", "Z", "R", "G", "B", + "STIP", "STIPCOUNT", "DX", "DY", "NUMPIX", "X", "Y", "IR", + + "RWDATA", "PIXMASK", "AUXMASK", "WIDDATA", "UAUXDATA", "RWMODE", "READBUF", "PIXTYPE", + "ASELECT", "ALIGNPAT", "ENABPAT", "ENABSTIP", "ENABDITH", "ENABWID", "CURWID", "DEPTHFN", + "REPSTIP", "ENABLWID", "FBOPTION", "TOPSCAN", nullptr, nullptr, "ZBOPTION", "XZOOM", + "UPACMODE", "YMIN", "YMAX", "XMIN", "XMAX", "COLORCMP", "MEGOPTION", nullptr, +}; + +DEFINE_DEVICE_TYPE(SGI_RE2, sgi_re2_device, "sgi_re2", "SGI Raster Engine 2") + +sgi_re2_device::sgi_re2_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock) + : device_t(mconfig, SGI_RE2, tag, owner, clock) +{ +} + +void sgi_re2_device::device_start() +{ + // TODO: save state +} + +void sgi_re2_device::device_reset() +{ +} + +u32 sgi_re2_device::reg_r(offs_t offset) +{ + u32 data = 0; + + switch (offset) + { + case RE2_STIP: data = m_stip; break; + case RE2_STIPCOUNT: data = m_stipcount; break; + case RE2_RWDATA: data = m_rwdata; break; + default: + logerror("reg_r unhandled register 0x%x\n", offset); + break; + } + + return data; +} + +void sgi_re2_device::reg_w(offs_t offset, u32 data) +{ + if ((offset < 64) && regnames[offset]) + LOGMASKED(LOG_REG, "reg_w register 0x%x (%s) data 0x%x\n", offset, regnames[offset], data); + else + logerror("reg_w unhandled register 0x%x data 0x%x\n", offset, data); + + switch (offset) + { + case RE2_STIP: m_stip = data; break; + case RE2_STIPCOUNT: m_stipcount = data; break; + } +} diff --git a/src/mame/video/sgi_re2.h b/src/mame/video/sgi_re2.h new file mode 100644 index 00000000000..c82708aa85b --- /dev/null +++ b/src/mame/video/sgi_re2.h @@ -0,0 +1,96 @@ +// license:BSD-3-Clause +// copyright-holders:Patrick Mackinlay + +#ifndef MAME_VIDEO_SGI_RE2_H +#define MAME_VIDEO_SGI_RE2_H + +#pragma once + +class sgi_re2_device : public device_t +{ +public: + sgi_re2_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock); + + // device_t overrides + virtual void device_start() override; + virtual void device_reset() override; + + enum register_number : unsigned + { + // buffered registers (write only unless noted) + RE2_ENABRGB = 0x04, // enable 8 bit rgb (1) + RE2_BIGENDIAN = 0x05, // enable big endian mode (1) + RE2_FUNC = 0x06, // raster op function (4) + RE2_HADDR = 0x07, // starting pixel location (2) + RE2_NOPUP = 0x08, // size of uaux (1) + RE2_XYFRAC = 0x09, // initial xyfrac (4) + RE2_RGB = 0x0a, // initial color values (27) + RE2_YX = 0x0b, // initial y and x (22) + RE2_PUPDATA = 0x0c, // pup data (2) + RE2_PATL = 0x0d, // pattern mask low (16) + RE2_PATH = 0x0e, // pattern mask high (16) + RE2_DZI = 0x0f, // delta z integer (24) + RE2_DZF = 0x10, // delta z fraction (14) + RE2_DR = 0x11, // delta red (24) + RE2_DG = 0x12, // delta green (20) + RE2_DB = 0x13, // delta blue (20) + RE2_Z = 0x14, // initial z integer (24) + RE2_R = 0x15, // initial red (23) + RE2_G = 0x16, // initial green (19) + RE2_B = 0x17, // initial blue (19) + RE2_STIP = 0x18, // stipple pattern (16, rw) + RE2_STIPCOUNT = 0x19, // stipple repeat (8, rw) + RE2_DX = 0x1a, // delta x (16) + RE2_DY = 0x1b, // delta y (16) + RE2_NUMPIX = 0x1c, // pixel count (11) + RE2_X = 0x1d, // initial x (12) + RE2_Y = 0x1e, // initial y (11) + RE2_IR = 0x1f, // instruction (3) + + // unbuffered registers (write only unless noted) + RE2_RWDATA = 0x20, // read/write data (32, rw) + RE2_PIXMASK = 0x21, // pixel mask (24) + RE2_AUXMASK = 0x22, // auxiliary mask (9) + RE2_WIDDATA = 0x23, // window id (4) + RE2_UAUXDATA = 0x24, // uaux data (4) + RE2_RWMODE = 0x25, // read/write mode (3) + RE2_READBUF = 0x26, // buffer select (1) + RE2_PIXTYPE = 0x27, // pixel type (2) + RE2_ASELECT = 0x28, // antialias select (6) + RE2_ALIGNPAT = 0x29, // pattern alignment (1) + RE2_ENABPAT = 0x2a, // enable pattern mask (1) + RE2_ENABSTIP = 0x2b, // enable stipple (1) + RE2_ENABDITH = 0x2c, // enable dithering (1) + RE2_ENABWID = 0x2d, // enable wid check (1) + RE2_CURWID = 0x2e, // current wid (4) + RE2_DEPTHFN = 0x2f, // depth function (4) + RE2_REPSTIP = 0x30, // stipple repeat (8) + RE2_ENABLWID = 0x31, // enable line wid (1) + RE2_FBOPTION = 0x32, // frame buffer option (2) + RE2_TOPSCAN = 0x33, // first row/column (18) + RE2_ZBOPTION = 0x36, // z buffer option (1) + RE2_XZOOM = 0x37, // x zoom factor (8) + RE2_UPACMODE = 0x38, // packing mode (2) + RE2_YMIN = 0x39, // bottom screen mask (11) + RE2_YMAX = 0x3a, // top screen mask (11) + RE2_XMIN = 0x3b, // left screen mask (12) + RE2_XMAX = 0x3c, // right screen mask (12) + RE2_COLORCMP = 0x3d, // z compare source (1) + RE2_MEGOPTION = 0x3e, // vram size (1) + }; + + u32 reg_r(offs_t offset); + void reg_w(offs_t offset, u32 data); + +protected: + +private: + u16 m_stip; + u8 m_stipcount; + + u32 m_rwdata; +}; + +DECLARE_DEVICE_TYPE(SGI_RE2, sgi_re2_device) + +#endif // MAME_VIDEO_SGI_RE2_H -- cgit v1.2.3