// license:BSD-3-Clause // copyright-holders:Bryan McPhail /*************************************************************************** decrmc3.cpp Data East custom palette device. ***************************************************************************/ #include "emu.h" #include "decrmc3.h" //************************************************************************** // DEVICE DEFINITIONS //************************************************************************** DEFINE_DEVICE_TYPE(DECO_RMC3, deco_rmc3_device, "deco_rmc3", "DECO RM-C3 PALETTE") deco_rmc3_device::deco_rmc3_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) : device_t(mconfig, DECO_RMC3, tag, owner, clock) , device_palette_interface(mconfig, *this) , m_entries(0) , m_indirect_entries(0) , m_prom_region(*this, finder_base::DUMMY_TAG) , m_init(*this) { } //************************************************************************** // GENERIC WRITE HANDLERS //************************************************************************** //------------------------------------------------- // update_for_write - given a write of a given // length to a given byte offset, update all // potentially modified palette entries //------------------------------------------------- inline void deco_rmc3_device::update_for_write(offs_t byte_offset, int bytes_modified, bool indirect) { assert((m_indirect_entries != 0) == indirect); // determine how many entries were modified int bpe = m_paletteram.bytes_per_entry(); assert(bpe != 0); int count = (bytes_modified + bpe - 1) / bpe; // for each entry modified, fetch the palette data and set the pen color or indirect color offs_t base = byte_offset / bpe; for (int index = 0; index < count; index++) { if (indirect) set_indirect_color(base + index, deco_rgb_decoder(read_entry(base + index))); else set_pen_color(base + index, deco_rgb_decoder(read_entry(base + index))); } } //------------------------------------------------- // write - write a byte to the base paletteram //------------------------------------------------- WRITE8_MEMBER(deco_rmc3_device::write8) { m_paletteram.write8(offset, data); update_for_write(offset, 1); } WRITE16_MEMBER(deco_rmc3_device::write16) { m_paletteram.write16(offset, data, mem_mask); update_for_write(offset * 2, 2); } WRITE32_MEMBER(deco_rmc3_device::write32) { m_paletteram.write32(offset, data, mem_mask); update_for_write(offset * 4, 4); } READ8_MEMBER(deco_rmc3_device::read8) { return m_paletteram.read8(offset); } READ16_MEMBER(deco_rmc3_device::read16) { return m_paletteram.read16(offset); } READ32_MEMBER(deco_rmc3_device::read32) { return m_paletteram.read32(offset); } //------------------------------------------------- // write_ext - write a byte to the extended // paletteram //------------------------------------------------- WRITE8_MEMBER(deco_rmc3_device::write8_ext) { m_paletteram_ext.write8(offset, data); update_for_write(offset, 1); } WRITE16_MEMBER(deco_rmc3_device::write16_ext) { m_paletteram_ext.write16(offset, data, mem_mask); update_for_write(offset * 2, 2); } //------------------------------------------------- // write_indirect - write a byte to the base // paletteram, updating indirect colors //------------------------------------------------- WRITE8_MEMBER(deco_rmc3_device::write_indirect) { m_paletteram.write8(offset, data); update_for_write(offset, 1, true); } //------------------------------------------------- // write_ext - write a byte to the extended // paletteram, updating indirect colors //------------------------------------------------- WRITE8_MEMBER(deco_rmc3_device::write_indirect_ext) { m_paletteram_ext.write8(offset, data); update_for_write(offset, 1, true); } //************************************************************************** // DEVICE MANAGEMENT //************************************************************************** //------------------------------------------------- // device_start - start up the device //------------------------------------------------- void deco_rmc3_device::device_start() { // bind the init function m_init.resolve(); // find the memory, if present const memory_share *share = memshare(tag()); if (share != nullptr) { // find the extended (split) memory, if present std::string tag_ext = std::string(tag()).append("_ext"); const memory_share *share_ext = memshare(tag_ext.c_str()); // determine bytes per entry and configure int bytes_per_entry = 2; if (share_ext == nullptr) m_paletteram.set(*share, bytes_per_entry); else { m_paletteram.set(*share, bytes_per_entry / 2); m_paletteram_ext.set(*share_ext, bytes_per_entry / 2); } } // call the initialization helper if present if (!m_init.isnull()) m_init(*this); } // This conversion mimics the specific weighting used by the Data East // custom resistor pack marked DECO RM-C3 to convert the digital // palette for analog output. It is used on games such as The Real // Ghostbusters, Gondomania, Cobra Command, Psychonics Oscar. // // Resistor values are 220 ohms (MSB), 470 ohms, 1 kohm, 2.2 kohm (LSB) void deco_rmc3_device::palette_init_proms(deco_rmc3_device &palette) { if (!m_prom_region.found()) throw emu_fatalerror("Unable to find color PROM region '%s'.", m_prom_region.finder_tag()); const u8 *colors = m_prom_region->base(); for (int i = 0; i < palette.entries(); i++) { u8 r = colors[i]&0xf; u8 g = (colors[i]>>4)&0xf; u8 b = colors[i + palette.entries()]&0xf; r = 0x0e * BIT(r,0) + 0x1f * BIT(r,1) + 0x43 * BIT(r,2) + 0x8f * BIT(r,3); g = 0x0e * BIT(g,0) + 0x1f * BIT(g,1) + 0x43 * BIT(g,2) + 0x8f * BIT(g,3); b = 0x0e * BIT(b,0) + 0x1f * BIT(b,1) + 0x43 * BIT(b,2) + 0x8f * BIT(b,3); palette.set_pen_color(i, rgb_t(r,g,b)); } } rgb_t deco_rmc3_device::deco_rgb_decoder(u32 raw) { u8 r = raw&0xf; u8 g = (raw>>4)&0xf; u8 b = (raw>>8)&0xf; r = 0x0e * BIT(r,0) + 0x1f * BIT(r,1) + 0x43 * BIT(r,2) + 0x8f * BIT(r,3); g = 0x0e * BIT(g,0) + 0x1f * BIT(g,1) + 0x43 * BIT(g,2) + 0x8f * BIT(g,3); b = 0x0e * BIT(b,0) + 0x1f * BIT(b,1) + 0x43 * BIT(b,2) + 0x8f * BIT(b,3); return rgb_t(r, g, b); }