4dpi: refactoring (nw)

* added dip switches for graphics hardware
* devicified xmap2
* overlay/underlay support
This commit is contained in:
Patrick Mackinlay 2019-09-19 17:21:01 +07:00
parent 1b016d02dc
commit 4cfde79a28
8 changed files with 418 additions and 268 deletions

View File

@ -3216,6 +3216,8 @@ files {
MAME_DIR .. "src/mame/video/sgi_ge5.h",
MAME_DIR .. "src/mame/video/sgi_re2.cpp",
MAME_DIR .. "src/mame/video/sgi_re2.h",
MAME_DIR .. "src/mame/video/sgi_xmap2.cpp",
MAME_DIR .. "src/mame/video/sgi_xmap2.h",
}
createMESSProjects(_target, _subtarget, "sharp")

View File

@ -31,7 +31,7 @@
* - https://github.com/NetBSD/src/tree/trunk/sys/arch/sgimips/
*
* TODO:
* - graphics, audio, printer
* - audio, printer
* - devicify ioc1 and ctl1
*
* Status:

View File

@ -38,10 +38,10 @@
*
* TODO:
* - host dma
* - refactor display subsystem
* - display registers
* - save state
* - slotify (SGI, MCA, ISA)
* - separate raster and display systems?
*/
/*
* Irix 4.0.5 IDE WIP
@ -71,8 +71,9 @@ DEFINE_DEVICE_TYPE(SGI_GR1, sgi_gr1_device, "sgi_gr1", "SGI GR1 Graphics")
sgi_gr1_device::sgi_gr1_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock)
: device_t(mconfig, SGI_GR1, tag, owner, clock)
, m_screen(*this, "screen")
, m_re(*this, "re2")
, m_ge(*this, "ge5")
, m_re(*this, "re2")
, m_xmap(*this, "xmap%u", 0U)
, m_cursor(*this, "cursor%u", 0U)
, m_ramdac(*this, "ramdac%u", 0U)
, m_vblank_cb(*this)
@ -80,18 +81,33 @@ sgi_gr1_device::sgi_gr1_device(machine_config const &mconfig, char const *tag, d
{
}
static INPUT_PORTS_START(sgi_gr1)
PORT_START("options")
PORT_DIPNAME(0x08, 0x08, "Turbo")
PORT_DIPSETTING(0x00, DEF_STR(Yes))
PORT_DIPSETTING(0x08, DEF_STR(No))
PORT_DIPNAME(0x10, 0x00, "Z Buffer")
PORT_DIPSETTING(0x00, DEF_STR(Yes))
PORT_DIPSETTING(0x10, DEF_STR(No))
INPUT_PORTS_END
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(0x0400, 0x041f).rw(FUNC(sgi_gr1_device::xmap2_r<0>), FUNC(sgi_gr1_device::xmap2_w<0>)).umask32(0x000000ff);
map(0x0420, 0x043f).rw(FUNC(sgi_gr1_device::xmap2_r<1>), FUNC(sgi_gr1_device::xmap2_w<1>)).umask32(0x000000ff);
map(0x0440, 0x045f).rw(FUNC(sgi_gr1_device::xmap2_r<2>), FUNC(sgi_gr1_device::xmap2_w<2>)).umask32(0x000000ff);
map(0x0460, 0x047f).rw(FUNC(sgi_gr1_device::xmap2_r<3>), FUNC(sgi_gr1_device::xmap2_w<3>)).umask32(0x000000ff);
map(0x0480, 0x049f).rw(FUNC(sgi_gr1_device::xmap2_r<4>), FUNC(sgi_gr1_device::xmap2_w<4>)).umask32(0x000000ff);
map(0x04a0, 0x04bf).w(FUNC(sgi_gr1_device::xmap2_bc_w)).umask32(0x000000ff);
map(0x0400, 0x041f).rw(m_xmap[0], FUNC(sgi_xmap2_device::reg_r), FUNC(sgi_xmap2_device::reg_w)).umask32(0x000000ff);
map(0x0420, 0x043f).rw(m_xmap[1], FUNC(sgi_xmap2_device::reg_r), FUNC(sgi_xmap2_device::reg_w)).umask32(0x000000ff);
map(0x0440, 0x045f).rw(m_xmap[2], FUNC(sgi_xmap2_device::reg_r), FUNC(sgi_xmap2_device::reg_w)).umask32(0x000000ff);
map(0x0460, 0x047f).rw(m_xmap[3], FUNC(sgi_xmap2_device::reg_r), FUNC(sgi_xmap2_device::reg_w)).umask32(0x000000ff);
map(0x0480, 0x049f).rw(m_xmap[4], FUNC(sgi_xmap2_device::reg_r), FUNC(sgi_xmap2_device::reg_w)).umask32(0x000000ff);
map(0x04a0, 0x04bf).lw8("xmap_broadcast",
[this](offs_t offset, u8 data)
{
for (sgi_xmap2_device *xmap : m_xmap)
xmap->reg_w(offset, data);
}).umask32(0x000000ff);
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);
@ -143,38 +159,39 @@ void sgi_gr1_device::device_add_mconfig(machine_config &config)
*/
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->set_screen_update(m_re.finder_tag(), FUNC(sgi_re2_device::screen_update));
m_screen->screen_vblank().set([this](int state) { m_vblank_cb(state); });
SGI_GE5(config, m_ge, 10_MHz_XTAL);
m_ge->fifo_empty().set([this]() { return int(m_fifo.empty()); });
m_ge->fifo_read().set(FUNC(sgi_gr1_device::ge_fifo_r));
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);
SGI_RE2(config, m_re, 0);
m_re->out_rdy().set(m_ge, FUNC(sgi_ge5_device::re_rdy_w));
m_re->out_drq().set(m_ge, FUNC(sgi_ge5_device::re_drq_w));
m_re->vram_r().set(
[this](offs_t offset)
{
return m_vram[offset];
});
m_re->vram_w().set(
[this](offs_t offset, u32 data, u32 mem_mask)
{
COMBINE_DATA(&m_vram[offset]);
});
SGI_XMAP2(config, m_xmap[0], pixel_clock / 5);
SGI_XMAP2(config, m_xmap[1], pixel_clock / 5);
SGI_XMAP2(config, m_xmap[2], pixel_clock / 5);
SGI_XMAP2(config, m_xmap[3], pixel_clock / 5);
SGI_XMAP2(config, m_xmap[4], pixel_clock / 5);
BT431(config, m_cursor[0], pixel_clock / 5);
BT431(config, m_cursor[1], pixel_clock / 5);
BT457(config, m_ramdac[0], pixel_clock);
BT457(config, m_ramdac[1], pixel_clock);
BT457(config, m_ramdac[2], pixel_clock);
}
ioport_constructor sgi_gr1_device::device_input_ports() const
{
return INPUT_PORTS_NAME(sgi_gr1);
}
void sgi_gr1_device::device_start()
{
m_vblank_cb.resolve_safe();
@ -182,9 +199,6 @@ void sgi_gr1_device::device_start()
//save_item(NAME());
m_vram = std::make_unique<u32[]>(1280 * 1024);
m_dram = std::make_unique<u32[]>(1280 * 1024);
m_reset = true;
}
@ -199,83 +213,14 @@ void sgi_gr1_device::device_reset()
m_fifo.clear();
}
u32 sgi_gr1_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, rectangle const &cliprect)
void sgi_gr1_device::dr4_w(u8 data)
{
// TODO: underlay
LOG("dr4_w 0x%02x\n", data);
// TODO: variable topscan row and column
for (unsigned screen_y = screen.visible_area().min_y, mem_y = 1023; screen_y <= screen.visible_area().max_y; screen_y++, mem_y--)
for (unsigned screen_x = screen.visible_area().min_x, mem_x = 0; screen_x <= screen.visible_area().max_x; screen_x++, mem_x++)
{
unsigned const offset = (mem_y * 0x500) + mem_x;
unsigned const bank = mem_x % 5;
m_dr4 = (m_dr4 & ~DR4_WM) | (data & DR4_WM);
u32 const data = m_vram[offset];
u8 const overlay = (m_cursor[0]->cur_r(screen_x, screen_y) ? 1 : 0) | (m_cursor[1]->cur_r(screen_x, screen_y) ? 2 : 0);
u16 const mode = m_xmap2[bank].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[bank].color[(m_dr4 & DR4_MS) ? ci | 0x1000 : ci];
bitmap.pix(screen_y, screen_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[bank].color[(m_dr4 & DR4_MS) ? ci | 0x1000 : ci];
bitmap.pix(screen_y, screen_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[bank].color[(m_dr4 & DR4_MS) ? ci | 0x1000 : ci];
bitmap.pix(screen_y, screen_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(screen_y, screen_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(screen_y, screen_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;
for (sgi_xmap2_device *xmap : m_xmap)
xmap->map_select_w(m_dr4 & DR4_MS);
}
u64 sgi_gr1_device::ge_fifo_r()
@ -324,120 +269,3 @@ void sgi_gr1_device::reset_w(int state)
m_reset = !state;
}
template <unsigned Channel> u8 sgi_gr1_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 0x0; // 0x08==no turbo option, 0x10==no z buffer
break;
case 6: // address msb
return x.addr >> 8;
case 7: // address lsb
return u8(x.addr);
}
return 0;
}
template <unsigned Channel> void sgi_gr1_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;
}
}

View File

@ -10,6 +10,7 @@
#include "screen.h"
#include "video/sgi_ge5.h"
#include "video/sgi_re2.h"
#include "video/sgi_xmap2.h"
#include "video/bt45x.h"
#include "video/bt431.h"
@ -31,12 +32,11 @@ public:
protected:
// device_t overrides
virtual ioport_constructor device_input_ports() const override;
virtual void device_add_mconfig(machine_config &config) override;
virtual void device_start() override;
virtual void device_reset() override;
u32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, rectangle const &cliprect);
u8 dr0_r() { return m_dr0; }
u8 dr1_r() { return m_dr1; }
u8 dr2_r() { return m_dr2; }
@ -46,27 +46,17 @@ protected:
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 dr4_w(u8 data);
u64 ge_fifo_r();
u32 fifo_r() { return u32(ge_fifo_r()); }
void fifo_w(offs_t offset, u32 data, u32 mem_mask);
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<screen_device> m_screen;
required_device<sgi_re2_device> m_re;
required_device<sgi_ge5_device> m_ge;
required_device<sgi_re2_device> m_re;
required_device_array<sgi_xmap2_device, 5> m_xmap;
required_device_array<bt431_device, 2> m_cursor;
required_device_array<bt457_device, 3> m_ramdac;
@ -137,19 +127,6 @@ private:
util::fifo<u64, 512> m_fifo;
std::unique_ptr<u32[]> m_vram;
std::unique_ptr<u32[]> m_dram;
struct xmap2
{
u16 addr;
rgb_t color[8192];
rgb_t overlay[16];
u16 mode[16];
bool wid_aux;
}
m_xmap2[5];
bool m_reset;
};

View File

@ -51,10 +51,12 @@ 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)
, m_xmap(*this, "^xmap%u", 0U)
, m_cursor(*this, "^cursor%u", 0U)
, m_ramdac(*this, "^ramdac%u", 0U)
, m_options_port(*this, "^options")
, m_rdy_cb(*this)
, m_drq_cb(*this)
, m_vram_r(*this)
, m_vram_w(*this)
, m_rdy(false)
, m_drq(false)
{
@ -65,8 +67,8 @@ void sgi_re2_device::device_start()
m_rdy_cb.resolve();
m_drq_cb.resolve();
m_vram_r.resolve();
m_vram_w.resolve();
m_vram = std::make_unique<u32[]>(1280 * 1024);
m_dram = std::make_unique<u32[]>(1280 * 1024);
// save state
for (unsigned i = 0; i < ARRAY_LENGTH(m_reg); i++)
@ -81,6 +83,10 @@ void sgi_re2_device::device_start()
void sgi_re2_device::device_reset()
{
u8 const options = m_options_port->read();
m_vram_mask = 0xffffffffU;
m_dram_mask = (options & 0x10) ? 0xffffffff : 0;
m_state = IDLE;
m_ir_pending = false;
@ -281,12 +287,12 @@ void sgi_re2_device::draw_shaded_span()
{
/*
* raster operation logic:
*
u32 const result =
(m_func[0] & src & dst) +
(m_func[1] & src & ~dst) +
(m_func[2] & ~src & dst) +
(m_func[3] & ~src & ~dst);
*
u32 const result =
(m_func[0] & src & dst) +
(m_func[1] & src & ~dst) +
(m_func[2] & ~src & dst) +
(m_func[3] & ~src & ~dst);
*/
u32 const mask = (m_reg[REG_AUXMASK] << 24) | m_reg[REG_PIXMASK];
@ -307,7 +313,7 @@ void sgi_re2_device::draw_shaded_span()
{
u32 const color = (m_r >> 11) << 0 | (m_g >> 11) << 8 | (m_b >> 11) << 16;
m_vram_w(offset, aux | color, mask);
vram_w(offset, aux | color, mask);
}
}
}
@ -332,7 +338,7 @@ void sgi_re2_device::draw_flat_span(unsigned const n)
{
u32 const color = (m_r >> 11) << 0 | (m_g >> 11) << 8 | (m_b >> 11) << 16;
m_vram_w(offset + i, aux | color, mask);
vram_w(offset + i, aux | color, mask);
}
if ((i % n) == 0)
@ -360,7 +366,7 @@ void sgi_re2_device::read_buffer()
switch (m_reg[REG_RWMODE])
{
case RWMODE_FB_P:
m_reg[REG_RWDATA] = m_vram_r((m_y >> 14) * 0x500 + (m_x >> 14));
m_reg[REG_RWDATA] = m_vram[(m_y >> 14) * 0x500 + (m_x >> 14)];
break;
}
@ -401,7 +407,7 @@ void sgi_re2_device::write_buffer()
switch (m_reg[REG_RWMODE])
{
case RWMODE_UAUX:
m_vram_w(offset, data << 24, (m_reg[REG_AUXMASK] & (m_nopup ? 0xf : 0xc)) << 24);
vram_w(offset, data << 24, (m_reg[REG_AUXMASK] & (m_nopup ? 0xf : 0xc)) << 24);
break;
}
}
@ -439,9 +445,10 @@ bool sgi_re2_device::wid(unsigned const ir, offs_t const offset)
if ((ir == IR_TOPLINE || ir == IR_BOTLINE) && !m_reg[REG_ENABLWID])
return true;
unsigned const wid = m_vram_r(offset) >> 28;
unsigned const wid = m_vram[offset] >> 28;
if (m_reg[REG_FBOPTION])
// 2 or 4 wid bitplanes?
if (m_reg[REG_FBOPTION] & 1)
{
if (BIT(m_reg[REG_DEPTHFN], 3))
return (wid & 0xe) == (m_reg[REG_CURWID] & 0xe);
@ -461,3 +468,76 @@ bool sgi_re2_device::pattern(unsigned const x, unsigned const n) const
return BIT(m_pat, 31 - index);
}
u32 sgi_re2_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, rectangle const &cliprect)
{
// TODO: variable topscan row and column
for (unsigned screen_y = screen.visible_area().min_y, mem_y = 1023; screen_y <= screen.visible_area().max_y; screen_y++, mem_y--)
for (unsigned screen_x = screen.visible_area().min_x, mem_x = 0; screen_x <= screen.visible_area().max_x; screen_x++, mem_x++)
{
unsigned const channel = mem_x % 5;
u32 const data = m_vram[(mem_y * 0x500) + mem_x];
u16 const mode = m_xmap[channel]->mode_r(data >> 28);
// default is 24 bit rgb single buffered
rgb_t color = rgb_t(data >> 0, data >> 8, data >> 16);
// check overlay or underlay
if (((data >> 20) & mode & sgi_xmap2_device::MODE_OE) || ((mode & sgi_xmap2_device::MODE_UE) && !(data & 0x00ffffffU)))
color = m_xmap[channel]->overlay_r(data >> 24);
else
switch (mode & sgi_xmap2_device::MODE_DM)
{
case 0: // 8 bit indexed single buffered
{
u16 const index = BIT(mode, sgi_xmap2_device::BIT_ME) ? ((mode & sgi_xmap2_device::MODE_MC) >> 2) | u8(data) : u8(data);
color = m_xmap[channel]->pen_color(index);
}
break;
case 1: // 4 bit indexed double buffered
{
u8 const buffer = BIT(mode, sgi_xmap2_device::BIT_BS) ? u8(data) >> 4 : data & 0x0f;
u16 const index = BIT(mode, sgi_xmap2_device::BIT_ME) ? ((mode & sgi_xmap2_device::MODE_MC) >> 2) | buffer : buffer;
color = m_xmap[channel]->pen_color(index);
}
break;
case 2: // 12 bit indexed double buffered
{
u16 const buffer = u16(BIT(mode, sgi_xmap2_device::BIT_BS) ? data >> 12 : data) & 0x0fff;
u16 const index = BIT(mode, sgi_xmap2_device::BIT_ME) ? ((mode & sgi_xmap2_device::MODE_MC) >> 2) | (buffer & 0xff) : buffer;
color = m_xmap[channel]->pen_color(index);
}
break;
case 5: // 12 bit rgb double buffered
color = BIT(mode, sgi_xmap2_device::BIT_BS) ?
rgb_t(
((data >> 0x00) & 0xf0) | ((data >> 0x04) & 0x0f),
((data >> 0x08) & 0xf0) | ((data >> 0x0c) & 0x0f),
((data >> 0x10) & 0xf0) | ((data >> 0x14) & 0x0f)) :
rgb_t(
((data << 0x04) & 0xf0) | ((data >> 0x00) & 0x0f),
((data >> 0x04) & 0xf0) | ((data >> 0x08) & 0x0f),
((data >> 0x0c) & 0xf0) | ((data >> 0x10) & 0x0f));
break;
}
// read the cursor devices
u8 const cursor =
(m_cursor[0]->cur_r(screen_x, screen_y) ? 1 : 0) |
(m_cursor[1]->cur_r(screen_x, screen_y) ? 2 : 0);
// apply the gamma ramp and output the pixel
bitmap.pix(screen_y, screen_x) = rgb_t(
m_ramdac[0]->lookup(color.r(), cursor),
m_ramdac[1]->lookup(color.g(), cursor),
m_ramdac[2]->lookup(color.b(), cursor));
}
return 0;
}

View File

@ -6,6 +6,11 @@
#pragma once
#include "video/sgi_xmap2.h"
#include "video/bt45x.h"
#include "video/bt431.h"
#include "screen.h"
class sgi_re2_device : public device_t
{
public:
@ -14,13 +19,12 @@ public:
auto out_rdy() { return m_rdy_cb.bind(); }
auto out_drq() { return m_drq_cb.bind(); }
auto vram_r() { return m_vram_r.bind(); }
auto vram_w() { return m_vram_w.bind(); }
// device_t overrides
virtual void device_start() override;
virtual void device_reset() override;
u32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, rectangle const &cliprect);
enum re_register : unsigned
{
// buffered registers (write only unless noted)
@ -149,13 +153,17 @@ protected:
void increment();
void vram_w(offs_t const offset, u32 const data, u32 const mem_mask) { m_vram[offset] = (m_vram[offset] & ~mem_mask) | (data & mem_mask & m_vram_mask); }
private:
required_device_array<sgi_xmap2_device, 5> m_xmap;
required_device_array<bt431_device, 2> m_cursor;
required_device_array<bt457_device, 3> m_ramdac;
required_ioport m_options_port;
devcb_write_line m_rdy_cb;
devcb_write_line m_drq_cb;
devcb_read32 m_vram_r;
devcb_write32 m_vram_w;
// state machine
emu_timer *m_step;
enum re_state : unsigned
@ -202,6 +210,11 @@ private:
unsigned m_ir;
rectangle m_clip;
std::unique_ptr<u32[]> m_vram;
std::unique_ptr<u32[]> m_dram;
u32 m_vram_mask;
u32 m_dram_mask;
};
DECLARE_DEVICE_TYPE(SGI_RE2, sgi_re2_device)

View File

@ -0,0 +1,190 @@
// license:BSD-3-Clause
// copyright-holders:Patrick Mackinlay
/*
* Silicon Graphics Multiplexed Multimode Graphics Processor (XMAP2).
*/
#include "emu.h"
#include "sgi_xmap2.h"
#define LOG_GENERAL (1U << 0)
//#define VERBOSE (LOG_GENERAL)
#include "logmacro.h"
DEFINE_DEVICE_TYPE(SGI_XMAP2, sgi_xmap2_device, "sgi_xmap2", "SGI XMAP2")
sgi_xmap2_device::sgi_xmap2_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock)
: device_t(mconfig, SGI_XMAP2, tag, owner, clock)
, device_palette_interface(mconfig, *this)
, m_options_port(*this, "^options")
, m_map_select(false)
{
}
void sgi_xmap2_device::device_start()
{
// save state
save_item(NAME(m_addr));
save_item(NAME(m_color));
save_item(NAME(m_overlay));
save_item(NAME(m_mode));
save_item(NAME(m_wid_aux));
save_item(NAME(m_map_select));
}
void sgi_xmap2_device::device_reset()
{
m_options = m_options_port->read();
}
u8 sgi_xmap2_device::reg_r(offs_t offset)
{
switch (offset)
{
case 0: // nop
break;
case 1: // blue data
if (m_addr & 0x1000)
return m_color[m_map_select ? m_addr : (m_addr & 0xfff)].b();
else if (m_addr < 0x10)
return m_overlay[m_addr].b();
break;
case 2: // green data
if (m_addr & 0x1000)
return m_color[m_map_select ? m_addr : (m_addr & 0xfff)].g();
else if (m_addr < 0x10)
return m_overlay[m_addr].g();
break;
case 3: // red data
if (m_addr & 0x1000)
return m_color[m_map_select ? m_addr : (m_addr & 0xfff)].r();
else if (m_addr < 0x10)
return m_overlay[m_addr].r();
break;
case 4: // increment address
// TODO: should reading increment the address register?
//m_addr = (m_addr + 1) & 0x1fff;
LOG("read address increment\n");
break;
case 5: // other data
if (m_addr < 0x20)
{
u16 const mode = m_mode[(m_addr >> 1) & 0xf];
return BIT(m_addr, 0) ? (mode >> 8) : u8(mode);
}
else if (m_addr == 0x20)
return m_wid_aux;
else if (m_addr == 0x21)
return m_options;
break;
case 6: // address msb
return m_addr >> 8;
case 7: // address lsb
return u8(m_addr);
}
return 0;
}
void sgi_xmap2_device::reg_w(offs_t offset, u8 data)
{
switch (offset)
{
case 0: // nop
break;
case 1: // blue data
if (m_addr & 0x1000)
{
unsigned const index = m_map_select ? m_addr : (m_addr & 0xfff);
m_color[index].set_b(data);
set_pen_blue_level(index & 0xfff, data);
}
else if (m_addr < 0x10)
{
m_overlay[m_addr].set_b(data);
set_pen_blue_level(0x1000 + m_addr, data);
}
break;
case 2: // green data
if (m_addr & 0x1000)
{
unsigned const index = m_map_select ? m_addr : (m_addr & 0xfff);
m_color[index].set_g(data);
set_pen_green_level(index & 0xfff, data);
}
else if (m_addr < 0x10)
{
m_overlay[m_addr].set_g(data);
set_pen_green_level(0x1000 + m_addr, data);
}
break;
case 3: // red data
if (m_addr & 0x1000)
{
unsigned const index = m_map_select ? m_addr : (m_addr & 0xfff);
m_color[index].set_r(data);
set_pen_red_level(index & 0xfff, data);
}
else if (m_addr < 0x10)
{
m_overlay[m_addr].set_r(data);
set_pen_red_level(0x1000 + m_addr, data);
}
break;
case 4: // increment address
m_addr = (m_addr + 1) & 0x1fff;
break;
case 5: // other data
if (m_addr < 0x20)
{
u16 &mode = m_mode[(m_addr >> 1) & 0xf];
if (BIT(m_addr, 0))
mode = (u16(data & 0x3f) << 8) | (mode & 0x00ff);
else
mode = (mode & 0x3f00) | data;
}
else if (m_addr == 0x20)
m_wid_aux = BIT(data, 0);
break;
case 6: // address msb
m_addr = u16((data & 0x1f) << 8) | (m_addr & 0x00ff);
break;
case 7: // address lsb
m_addr = (m_addr & 0x1f00) | data;
break;
}
}
void sgi_xmap2_device::map_select_w(int state)
{
if (m_map_select ^ bool(state))
{
m_map_select = bool(state);
// update mame palette
unsigned const base = m_map_select ? 4096 : 0;
for (unsigned i = 0; i < 4096; i++)
set_pen_color(i, m_color[base + i]);
}
}

View File

@ -0,0 +1,60 @@
// license:BSD-3-Clause
// copyright-holders:Patrick Mackinlay
#ifndef MAME_VIDEO_SGI_XMAP2_H
#define MAME_VIDEO_SGI_XMAP2_H
#pragma once
class sgi_xmap2_device
: public device_t
, public device_palette_interface
{
public:
sgi_xmap2_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;
// device_palette_interface overrides
virtual u32 palette_entries() const override { return 4096 + 16; }
u8 reg_r(offs_t offset);
void reg_w(offs_t offset, u8 data);
void map_select_w(int state);
u16 mode_r(unsigned const index) const { return m_mode[index]; }
rgb_t overlay_r(u8 data) const { return m_wid_aux ? m_overlay[data & 0x3] : m_overlay[data & 0xf]; }
enum mode_mask : u16
{
MODE_MC = 0x3c00, // multimap constant
MODE_ME = 0x0200, // multimap enable
MODE_UE = 0x0100, // underlay enable
MODE_OE = 0x00f0, // overlay enable
MODE_BS = 0x0008, // buffer select
MODE_DM = 0x0007, // display mode
};
enum mode_bits : unsigned
{
BIT_ME = 9, // multimap enable
BIT_UE = 8, // underlay enable
BIT_BS = 3, // buffer select
};
private:
required_ioport m_options_port;
u16 m_addr;
rgb_t m_color[8192];
rgb_t m_overlay[16];
u16 m_mode[16];
bool m_wid_aux;
bool m_map_select;
u8 m_options;
};
DECLARE_DEVICE_TYPE(SGI_XMAP2, sgi_xmap2_device)
#endif // MAME_VIDEO_SGI_XMAP2_H