4dpi: graphics wip (nw)

This commit is contained in:
Patrick Mackinlay 2019-08-29 19:49:21 +07:00
parent 23a5e12303
commit 194691c634
8 changed files with 1550 additions and 2 deletions

View File

@ -395,6 +395,7 @@ VIDEOS["MB88303"] = true
VIDEOS["PS2GS"] = true VIDEOS["PS2GS"] = true
VIDEOS["PS2GIF"] = true VIDEOS["PS2GIF"] = true
VIDEOS["DECSFB"] = true VIDEOS["DECSFB"] = true
VIDEOS["BT431"] = true
-------------------------------------------------- --------------------------------------------------
-- specify available machine cores -- specify available machine cores
@ -719,6 +720,7 @@ MACHINES["DC7085"] = true
MACHINES["I82357"] = true MACHINES["I82357"] = true
MACHINES["XC1700E"] = true MACHINES["XC1700E"] = true
MACHINES["EDLC"] = true MACHINES["EDLC"] = true
MACHINES["WTL3132"] = true
-------------------------------------------------- --------------------------------------------------
-- specify available bus cores -- specify available bus cores
@ -3193,6 +3195,12 @@ files {
MAME_DIR .. "src/mame/video/light.h", MAME_DIR .. "src/mame/video/light.h",
MAME_DIR .. "src/mame/video/crime.cpp", MAME_DIR .. "src/mame/video/crime.cpp",
MAME_DIR .. "src/mame/video/crime.h", 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") createMESSProjects(_target, _subtarget, "sharp")

View File

@ -66,7 +66,7 @@
#include "bus/rs232/hlemouse.h" #include "bus/rs232/hlemouse.h"
// video and audio // video and audio
#include "screen.h" #include "video/sgi_gr1.h"
#define LOG_GENERAL (1U << 0) #define LOG_GENERAL (1U << 0)
@ -87,6 +87,7 @@ public:
, m_enet(*this, "enet") , m_enet(*this, "enet")
, m_duart(*this, "duart%u", 0U) , m_duart(*this, "duart%u", 0U)
, m_serial(*this, "serial%u", 1U) , m_serial(*this, "serial%u", 1U)
, m_gfx(*this, "gfx")
, m_leds(*this, "led%u", 0U) , m_leds(*this, "led%u", 0U)
{ {
} }
@ -107,6 +108,7 @@ private:
required_device<am7990_device> m_enet; required_device<am7990_device> m_enet;
required_device_array<scn2681_device, 2> m_duart; required_device_array<scn2681_device, 2> m_duart;
required_device_array<rs232_port_device, 2> m_serial; required_device_array<rs232_port_device, 2> m_serial;
required_device<sgi_gr1_device> m_gfx;
enum leds : unsigned enum leds : unsigned
{ {
@ -241,6 +243,7 @@ void pi4d2x_state::map(address_map &map)
//map(0x1e000000, 0x1effffff); // vme a24 modifier 0x39 non-privileged //map(0x1e000000, 0x1effffff); // vme a24 modifier 0x39 non-privileged
//map(0x1f000000, 0x1fbfffff); // local I/O (duarts, timers, etc.) //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).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); 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->cs_write(BIT(data, 5));
m_eeprom->clk_write(BIT(data, 6)); 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; m_cpuauxctl = data;
}).umask32(0xff000000); }).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]->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)); 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<LIO_GE>)).invert();
m_gfx->out_int_fifo().set(*this, FUNC(pi4d2x_state::lio_interrupt<LIO_FIFO>)).invert();
// TODO: vme slot, cpu interrupt 0 // TODO: vme slot, cpu interrupt 0
} }

532
src/mame/video/sgi_ge5.cpp Normal file
View File

@ -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<util::disasm_interface> sgi_ge5_device::create_disassembler()
{
return std::make_unique<sgi_ge5_disassembler>();
}
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 &params)
{
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;
}

110
src/mame/video/sgi_ge5.h Normal file
View File

@ -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<util::disasm_interface> 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<wtl3132_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 &params) override;
private:
};
DECLARE_DEVICE_TYPE(SGI_GE5, sgi_ge5_device)
#endif // MAME_VIDEO_SGI_GE5_H

472
src/mame/video/sgi_gr1.cpp Normal file
View File

@ -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<u32[]>(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 <unsigned Channel> 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 <unsigned Channel> 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;
}
}

232
src/mame/video/sgi_gr1.h Normal file
View File

@ -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<sgi_ge5_device>("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<screen_device> m_screen;
required_device<sgi_re2_device> m_re;
required_device<sgi_ge5_device> m_ge;
required_device_array<bt431_device, 2> 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<u64, 512> 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 <unsigned Channel> 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 <unsigned Channel> 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<bt458_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 <unsigned Channel> u8 xmap2_r(offs_t offset);
template <unsigned Channel> 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<bt457_device, 3> m_ramdac;
std::unique_ptr<u32[]> 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

View File

@ -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;
}
}

96
src/mame/video/sgi_re2.h Normal file
View File

@ -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