summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--scripts/src/video.lua12
-rw-r--r--scripts/target/mame/mess.lua1
-rw-r--r--src/devices/video/bt459.cpp10
-rw-r--r--src/devices/video/bt45x.cpp442
-rw-r--r--src/devices/video/bt45x.h181
5 files changed, 642 insertions, 4 deletions
diff --git a/scripts/src/video.lua b/scripts/src/video.lua
index b3ca841fde0..6931f1152e6 100644
--- a/scripts/src/video.lua
+++ b/scripts/src/video.lua
@@ -1057,3 +1057,15 @@ if (VIDEOS["DP8510"]~=null) then
MAME_DIR .. "src/devices/video/dp8510.h",
}
end
+
+--------------------------------------------------
+--
+--@src/devices/video/bt45x.h,VIDEOS["BT45X"] = true
+--------------------------------------------------
+
+if (VIDEOS["BT45X"]~=null) then
+ files {
+ MAME_DIR .. "src/devices/video/bt45x.cpp",
+ MAME_DIR .. "src/devices/video/bt45x.h",
+ }
+end
diff --git a/scripts/target/mame/mess.lua b/scripts/target/mame/mess.lua
index a72f7e1e4f4..4e1485464c4 100644
--- a/scripts/target/mame/mess.lua
+++ b/scripts/target/mame/mess.lua
@@ -279,6 +279,7 @@ SOUNDS["UPD934G"] = true
VIDEOS["SEGA315_5124"] = true
VIDEOS["SEGA315_5313"] = true
--VIDEOS+= BUFSPRITE"] = true
+VIDEOS["BT45X"] = true
VIDEOS["BT459"] = true
VIDEOS["CDP1861"] = true
VIDEOS["CDP1862"] = true
diff --git a/src/devices/video/bt459.cpp b/src/devices/video/bt459.cpp
index 604c8de93ef..c66b61c44c6 100644
--- a/src/devices/video/bt459.cpp
+++ b/src/devices/video/bt459.cpp
@@ -22,7 +22,7 @@
#define VERBOSE 0
#include "logmacro.h"
-DEFINE_DEVICE_TYPE(BT459, bt459_device, "bt459", "Brooktree 150MHz Monolithic CMOS 256x24 Color Palette RAMDAC")
+DEFINE_DEVICE_TYPE(BT459, bt459_device, "bt459", "Brooktree Bt459 256 Color RAMDAC")
void bt459_device::map(address_map &map)
{
@@ -33,8 +33,8 @@ void bt459_device::map(address_map &map)
}
bt459_device::bt459_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : device_t(mconfig, BT459, tag, owner, clock),
- device_palette_interface(mconfig, *this)
+ : device_t(mconfig, BT459, tag, owner, clock)
+ , device_palette_interface(mconfig, *this)
{
}
@@ -255,7 +255,9 @@ READ8_MEMBER(bt459_device::register_r)
}
// increment address register and return result
- m_address = (m_address + 1) & ADDRESS_MASK;
+ if (!machine().side_effects_disabled())
+ m_address = (m_address + 1) & ADDRESS_MASK;
+
return result;
}
diff --git a/src/devices/video/bt45x.cpp b/src/devices/video/bt45x.cpp
new file mode 100644
index 00000000000..c2e1a3904c6
--- /dev/null
+++ b/src/devices/video/bt45x.cpp
@@ -0,0 +1,442 @@
+// license:BSD-3-Clause
+// copyright-holders:Patrick Mackinlay
+
+/*
+ * An implementation of the Brooktree Bt45x family (except the Bt459) of RAMDAC
+ * devices. The 453, 454 and 455 are simpler, and have no command or control
+ * registers, whereas the others in the family use these to support additional
+ * options such as multiplexing, blinking etc. Otherwise the devices are quite
+ * similar, and vary only in terms of maximum clock speed, number of color or
+ * overlay bits, and quantity and number bits of resolution of DAC output.
+ *
+ * Max. Input Output
+ * Part Clock Color Overlay Num. Levels Other
+ * Bt451 165MHz 8 bit 2 bit 3 4 bit blinking, multiplexing
+ * Bt453 66MHz 8 bit 2 bit 3 8 bit
+ * Bt454 170MHz 4 bit 1 bit 3 4 bit
+ * Bt455 170MHz 4 bit 1 bit 1 4 bit
+ * Bt457 165Mhz 8 bit 2 bit 1 8 bit blinking, multiplexing
+ * Bt458 165MHz 8 bit 2 bit 3 8 bit blinking, multiplexing
+ *
+ * Reference: http://www.bitsavers.org/components/brooktree/_dataBooks/1991_Brooktree_Product_Databook.pdf
+ *
+ * The bt45x_mono_device_base uses the standard red/green/blue read/write
+ * cycles defined in the databook, with color data active on the green cycle.
+ *
+ * TODO
+ * - refactor to separate devices with registers
+ * - implement blinking and overlay
+ * - unsure about address masking when accessing overlay colors
+ */
+
+#include "emu.h"
+#include "bt45x.h"
+
+#define LOG_GENERAL (1U << 0)
+#define LOG_READS (1U << 1)
+
+#define VERBOSE (0)
+
+#include "logmacro.h"
+
+DEFINE_DEVICE_TYPE(BT451, bt451_device, "bt451", "Brooktree Bt451 256 Color RAMDAC")
+DEFINE_DEVICE_TYPE(BT453, bt453_device, "bt453", "Brooktree Bt453 256 Color RAMDAC")
+DEFINE_DEVICE_TYPE(BT454, bt454_device, "bt454", "Brooktree Bt454 16 Color RAMDAC")
+DEFINE_DEVICE_TYPE(BT455, bt455_device, "bt455", "Brooktree Bt455 16 Color RAMDAC")
+DEFINE_DEVICE_TYPE(BT457, bt457_device, "bt457", "Brooktree Bt457 256 Color RAMDAC")
+DEFINE_DEVICE_TYPE(BT458, bt458_device, "bt458", "Brooktree Bt458 256 Color RAMDAC")
+
+void bt45x_device_base::map(address_map &map)
+{
+ map(0x00, 0x00).rw(this, FUNC(bt45x_device_base::address_r), FUNC(bt45x_device_base::address_w));
+ map(0x01, 0x01).rw(this, FUNC(bt45x_device_base::palette_r), FUNC(bt45x_device_base::palette_w));
+ map(0x02, 0x02).rw(this, FUNC(bt45x_device_base::register_r), FUNC(bt45x_device_base::register_w));
+ map(0x03, 0x03).rw(this, FUNC(bt45x_device_base::overlay_r), FUNC(bt45x_device_base::overlay_w));
+}
+
+void bt453_device::map(address_map &map)
+{
+ map(0x00, 0x00).rw(this, FUNC(bt453_device::address_r), FUNC(bt453_device::address_w));
+ map(0x01, 0x01).rw(this, FUNC(bt453_device::palette_r), FUNC(bt453_device::palette_w));
+ map(0x02, 0x02).rw(this, FUNC(bt453_device::address_r), FUNC(bt453_device::address_w));
+ map(0x03, 0x03).rw(this, FUNC(bt453_device::overlay_r), FUNC(bt453_device::overlay_w));
+}
+
+void bt454_device::map(address_map &map)
+{
+ map(0x00, 0x00).rw(this, FUNC(bt454_device::address_r), FUNC(bt454_device::address_w));
+ map(0x01, 0x01).rw(this, FUNC(bt454_device::palette_r), FUNC(bt454_device::palette_w));
+ // FIXME: not clear what happens here
+ //map(0x02, 0x02).rw(this, FUNC(bt454_device::address_r), FUNC(bt454_device::address_w));
+ map(0x03, 0x03).rw(this, FUNC(bt454_device::overlay_r), FUNC(bt454_device::overlay_w));
+}
+
+void bt455_device::map(address_map &map)
+{
+ map(0x00, 0x00).rw(this, FUNC(bt455_device::address_r), FUNC(bt455_device::address_w));
+ map(0x01, 0x01).rw(this, FUNC(bt455_device::palette_r), FUNC(bt455_device::palette_w));
+ // FIXME: not clear what happens here
+ //map(0x02, 0x02).rw(this, FUNC(bt455_device::address_r), FUNC(bt455_device::address_w));
+ map(0x03, 0x03).rw(this, FUNC(bt455_device::overlay_r), FUNC(bt455_device::overlay_w));
+}
+
+bt45x_device_base::bt45x_device_base(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, const u32 palette_colors, const u32 overlay_colors)
+ : device_t(mconfig, type, tag, owner, clock)
+ , m_palette_colors(palette_colors)
+ , m_overlay_colors(overlay_colors)
+{
+}
+
+bt45x_rgb_device_base::bt45x_rgb_device_base(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, const u32 palette_colors, const u32 overlay_colors)
+ : bt45x_device_base(mconfig, type, tag, owner, clock, palette_colors, overlay_colors)
+ , device_palette_interface(mconfig, *this)
+{
+}
+
+bt45x_mono_device_base::bt45x_mono_device_base(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, const u32 palette_colors, const u32 overlay_colors)
+ : bt45x_device_base(mconfig, type, tag, owner, clock, palette_colors, overlay_colors)
+{
+}
+
+bt451_device::bt451_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : bt45x_rgb_device_base(mconfig, BT451, tag, owner, clock, 256, 3)
+{
+}
+
+bt453_device::bt453_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : bt45x_rgb_device_base(mconfig, BT453, tag, owner, clock, 256, 3)
+{
+}
+
+bt454_device::bt454_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : bt45x_rgb_device_base(mconfig, BT454, tag, owner, clock, 16, 1)
+{
+}
+
+bt455_device::bt455_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : bt45x_mono_device_base(mconfig, BT455, tag, owner, clock, 16, 1)
+{
+}
+bt457_device::bt457_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : bt45x_mono_device_base(mconfig, BT457, tag, owner, clock, 256, 3)
+{
+}
+
+bt458_device::bt458_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : bt45x_rgb_device_base(mconfig, BT458, tag, owner, clock, 256, 3)
+{
+}
+
+void bt45x_device_base::device_start()
+{
+ save_item(NAME(m_address));
+ save_item(NAME(m_address_rgb));
+
+ save_item(NAME(m_read_mask));
+ save_item(NAME(m_blink_mask));
+ save_item(NAME(m_command));
+ save_item(NAME(m_control));
+
+ save_item(NAME(m_blink_start));
+}
+
+void bt45x_rgb_device_base::device_start()
+{
+ bt45x_device_base::device_start();
+
+ m_color_ram = std::make_unique<std::array<u8, 3>[]>(m_palette_colors + m_overlay_colors);
+
+ //save_pointer(NAME(m_color_ram.get()), m_palette_colors + m_overlay_colors);
+}
+
+void bt45x_mono_device_base::device_start()
+{
+ bt45x_device_base::device_start();
+
+ m_color_ram = std::make_unique<u8[]>(m_palette_colors + m_overlay_colors);
+
+ save_pointer(NAME(m_color_ram.get()), m_palette_colors + m_overlay_colors);
+}
+
+void bt45x_device_base::device_reset()
+{
+ m_blink_start = -1;
+}
+
+READ8_MEMBER(bt45x_device_base::address_r)
+{
+ LOGMASKED(LOG_READS, "address_r 0x%02x\n", m_address & (m_palette_colors - 1));
+
+ if (!machine().side_effects_disabled())
+ m_address_rgb = 0;
+
+ return m_address & (m_palette_colors - 1);
+}
+
+WRITE8_MEMBER(bt45x_device_base::address_w)
+{
+ LOG("address_w 0x%02x\n", data);
+ m_address_rgb = 0;
+
+ m_address = data & (m_palette_colors - 1);
+}
+
+void bt45x_device_base::increment_address(const bool side_effects)
+{
+ if (!machine().side_effects_disabled() || side_effects)
+ {
+ // increment component index and address register
+ m_address_rgb = (m_address_rgb + 1) % 3;
+ if (m_address_rgb == 0)
+ m_address = (m_address + 1) & (m_palette_colors - 1);
+ }
+}
+
+void bt457_device::increment_address(const bool side_effects)
+{
+ if (!machine().side_effects_disabled() || side_effects)
+ {
+ // check for rgb mode
+ if (m_control & RGB)
+ {
+ // increment component index and address register
+ m_address_rgb = (m_address_rgb + 1) % 3;
+ if (m_address_rgb == 0)
+ m_address++;
+ }
+ else
+ m_address++;
+ }
+}
+
+READ8_MEMBER(bt45x_rgb_device_base::palette_r)
+{
+ const u8 data = m_color_ram[m_address][m_address_rgb];
+
+ increment_address();
+
+ LOGMASKED(LOG_READS, "palette_r 0x%02x\n", data & get_mask());
+
+ return data & get_mask();
+}
+
+READ8_MEMBER(bt45x_mono_device_base::palette_r)
+{
+ u8 data = space.unmap();
+
+ if (m_address_rgb == 1)
+ data = m_color_ram[m_address];
+
+ increment_address();
+
+ LOGMASKED(LOG_READS, "palette_r 0x%02x\n", data & get_mask());
+
+ return data & get_mask();
+}
+
+READ8_MEMBER(bt457_device::palette_r)
+{
+ u8 data = space.unmap();
+
+ // normal mode or rgb mode and selected
+ if (!(m_control & RGB) || (m_control & RGB) == (1 << m_address_rgb))
+ data = m_color_ram[m_address];
+
+ increment_address();
+
+ LOGMASKED(LOG_READS, "palette_r 0x%02x\n", data);
+
+ return data;
+}
+
+WRITE8_MEMBER(bt45x_rgb_device_base::palette_w)
+{
+ LOG("palette_w 0x%02x\n", data);
+
+ m_color_ram[m_address][m_address_rgb] = data & get_mask();
+
+ // update the mame palette to match the device
+ if (m_address_rgb == 2)
+ set_pen_color(m_address, rgb_t(m_color_ram[m_address][0], m_color_ram[m_address][1], m_color_ram[m_address][2]));
+
+ increment_address(true);
+}
+
+WRITE8_MEMBER(bt45x_mono_device_base::palette_w)
+{
+ LOG("palette_w 0x%02x\n", data);
+
+ if (m_address_rgb == 1)
+ m_color_ram[m_address] = data & get_mask();
+
+ increment_address(true);
+}
+
+WRITE8_MEMBER(bt457_device::palette_w)
+{
+ LOG("palette_w 0x%02x\n", data);
+
+ // device in normal mode, or rgb mode and selected
+ if (!(m_control & RGB) || (m_control & RGB) == (1 << m_address_rgb))
+ m_color_ram[m_address] = data;
+
+ increment_address(true);
+}
+
+READ8_MEMBER(bt45x_device_base::register_r)
+{
+ LOGMASKED(LOG_READS, "register_r 0x%02x\n", m_address);
+
+ switch (m_address)
+ {
+ case REG_READ_MASK: return m_read_mask;
+ case REG_BLINK_MASK: return m_blink_mask;
+ case REG_COMMAND: return m_command;
+ case REG_CONTROL: return m_control;
+ }
+
+ return space.unmap();
+}
+
+WRITE8_MEMBER(bt45x_device_base::register_w)
+{
+ switch (m_address)
+ {
+ case REG_READ_MASK:
+ LOG("read mask 0x%02x\n", data);
+ m_read_mask = data;
+ break;
+
+ case REG_BLINK_MASK:
+ LOG("blink mask 0x%02x\n", data);
+ m_blink_mask = data;
+ break;
+
+ case REG_COMMAND:
+ LOG("command 0x%02x, %d:1 multiplexing, use %s, %s, OL1 %s blinking, OL0 %s blinking, OL1 display %s, OL0 display %s\n",
+ data,
+ (data & CR7) ? 5 : 4,
+ (data & CR6) ? "color palette RAM" : "overlay color 0",
+ (data & CR54) == CR54_6464 ? "64 on 64 off (50/50)" :
+ (data & CR54) == CR54_3232 ? "32 on 32 off (50/50)" :
+ (data & CR54) == CR54_1616 ? "16 on 16 off (50/50)" :
+ "16 on 48 off (25/75)",
+ (data & CR3) ? "enable" : "disable",
+ (data & CR2) ? "enable" : "disable",
+ (data & CR1) ? "enable" : "disable",
+ (data & CR0) ? "enable" : "disable");
+ m_command = data;
+ break;
+
+ case REG_CONTROL:
+ LOG("control 0x%02x, %s nibble%s%s%s\n",
+ data,
+ (data & D3) ? "low" : "high",
+ (data & D2) ? ", blue channel enable" : "",
+ (data & D1) ? ", green channel enable" : "",
+ (data & D0) ? ", red channel enable" : "");
+ m_control = data & 0xf;
+ break;
+ }
+}
+
+READ8_MEMBER(bt45x_rgb_device_base::overlay_r)
+{
+ // address is ignored for 1 bit overlay devices
+ const u8 address = (m_overlay_colors == 1) ? 0 : m_address;
+
+ u8 data = space.unmap();
+
+ if (address < m_overlay_colors)
+ data = m_color_ram[m_palette_colors + address][m_address_rgb];
+
+ increment_address();
+
+ LOGMASKED(LOG_READS, "overlay_r 0x%02x\n", data & get_mask());
+
+ return data & get_mask();
+}
+
+READ8_MEMBER(bt45x_mono_device_base::overlay_r)
+{
+ // address is ignored for 1 bit overlay devices
+ const u8 address = (m_overlay_colors == 1) ? 0 : m_address;
+
+ u8 data = space.unmap();
+
+ if (address < m_overlay_colors && m_address_rgb == 1)
+ data = m_color_ram[m_palette_colors + address];
+
+ increment_address();
+
+ LOGMASKED(LOG_READS, "overlay_r 0x%02x\n", data & get_mask());
+
+ return data & get_mask();
+}
+
+READ8_MEMBER(bt457_device::overlay_r)
+{
+ u8 data = space.unmap();
+
+ if (m_address < m_overlay_colors)
+ {
+ // device in normal mode, or rgb mode and selected
+ if (!(m_control & RGB) || (m_control & RGB) == (1 << m_address_rgb))
+ data = m_color_ram[m_address + m_palette_colors];
+ }
+
+ increment_address();
+
+ LOGMASKED(LOG_READS, "overlay_r 0x%02x\n", data);
+
+ return data;
+}
+
+WRITE8_MEMBER(bt45x_rgb_device_base::overlay_w)
+{
+ LOG("overlay_w 0x%02x\n", data);
+
+ // address is ignored for 1 bit overlay devices
+ const u8 address = (m_overlay_colors == 1) ? 0 : m_address;
+
+ if (address < m_overlay_colors)
+ {
+ m_color_ram[m_palette_colors + address][m_address_rgb] = data & get_mask();
+
+ // update the mame palette to match the device
+ if (m_address_rgb == 2)
+ set_pen_color(m_palette_colors + address, rgb_t(
+ m_color_ram[m_palette_colors + address][0],
+ m_color_ram[m_palette_colors + address][1],
+ m_color_ram[m_palette_colors + address][2]));
+ }
+
+ increment_address(true);
+}
+
+WRITE8_MEMBER(bt45x_mono_device_base::overlay_w)
+{
+ LOG("overlay_w 0x%02x\n", data);
+
+ // address is ignored for 1 bit overlay devices
+ const u8 address = (m_overlay_colors == 1) ? 0 : m_address;
+
+ if (address < m_overlay_colors)
+ m_color_ram[m_palette_colors + address] = data & get_mask();
+
+ increment_address(true);
+}
+
+WRITE8_MEMBER(bt457_device::overlay_w)
+{
+ LOG("overlay_w 0x%02x\n", data);
+
+ if (m_address < m_overlay_colors)
+ {
+ // device in normal mode, or rgb mode and selected
+ if (!(m_control & RGB) || (m_control & RGB) == (1 << m_address_rgb))
+ m_color_ram[m_palette_colors + m_address] = data;
+ }
+
+ increment_address(true);
+}
diff --git a/src/devices/video/bt45x.h b/src/devices/video/bt45x.h
new file mode 100644
index 00000000000..a81b415eca6
--- /dev/null
+++ b/src/devices/video/bt45x.h
@@ -0,0 +1,181 @@
+// license:BSD-3-Clause
+// copyright-holders:Patrick Mackinlay
+#ifndef MAME_VIDEO_BT45X_H
+#define MAME_VIDEO_BT45X_H
+
+#pragma once
+
+class bt45x_device_base : public device_t
+{
+public:
+ enum address_mask : u8
+ {
+ REG_READ_MASK = 0x04,
+ REG_BLINK_MASK = 0x05,
+ REG_COMMAND = 0x06,
+ REG_CONTROL = 0x07
+ };
+ enum command_mask : u8
+ {
+ CR7 = 0x80, // multiplex select
+ CR6 = 0x40, // ram enable
+ CR54 = 0x30, // blink rate selection
+ CR3 = 0x08, // OL1 blink enable
+ CR2 = 0x04, // OL0 blink enable
+ CR1 = 0x02, // OL1 display enable
+ CR0 = 0x01, // OL0 display enable
+ };
+ enum control_mask : u8
+ {
+ D3 = 0x08, // low nibble
+ D2 = 0x04, // blue channel enable
+ D1 = 0x02, // green channel enable
+ D0 = 0x01, // red channel enable
+
+ RGB = 0x07 // rgb mode enable
+ };
+ enum cr54_mask : u8
+ {
+ CR54_6464 = 0x30, // 64 on 64 off, 50/50
+ CR54_3232 = 0x20, // 32 on 32 off, 50/50
+ CR54_1616 = 0x10, // 16 on 16 off, 50/50
+ CR54_1648 = 0x00 // 16 on 48 off, 25/75
+ };
+
+ virtual void map(address_map &map);
+
+protected:
+ bt45x_device_base(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, const u32 palette_colors, const u32 overlay_colors);
+
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+ DECLARE_READ8_MEMBER(address_r);
+ DECLARE_WRITE8_MEMBER(address_w);
+ virtual DECLARE_READ8_MEMBER(palette_r) = 0;
+ virtual DECLARE_WRITE8_MEMBER(palette_w) = 0;
+ DECLARE_READ8_MEMBER(register_r);
+ DECLARE_WRITE8_MEMBER(register_w);
+ virtual DECLARE_READ8_MEMBER(overlay_r) = 0;
+ virtual DECLARE_WRITE8_MEMBER(overlay_w) = 0;
+
+ // helpers
+ virtual void increment_address(const bool side_effects = false);
+ virtual u8 get_mask() const { return m_palette_colors - 1; }
+
+ // device state
+ u8 m_address;
+ u8 m_address_rgb;
+ u8 m_read_mask;
+ u8 m_blink_mask;
+ u8 m_command;
+ u8 m_control;
+
+ // internal state
+ const u32 m_palette_colors;
+ const u32 m_overlay_colors;
+ u64 m_blink_start;
+};
+
+class bt45x_rgb_device_base : public bt45x_device_base, public device_palette_interface
+{
+protected:
+ bt45x_rgb_device_base(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, const u32 palette_colors, const u32 overlay_colors);
+
+ virtual void device_start() override;
+
+ virtual u32 palette_entries() const override { return m_palette_colors + m_overlay_colors; }
+
+ virtual DECLARE_READ8_MEMBER(palette_r) override;
+ virtual DECLARE_WRITE8_MEMBER(palette_w) override;
+ virtual DECLARE_READ8_MEMBER(overlay_r) override;
+ virtual DECLARE_WRITE8_MEMBER(overlay_w) override;
+
+ std::unique_ptr<std::array<u8, 3>[]> m_color_ram;
+};
+
+class bt45x_mono_device_base : public bt45x_device_base
+{
+public:
+ // helpers instead of a device_palette_interface
+ u8 palette_lookup(u8 index) const { return m_color_ram[index & m_read_mask]; }
+ u8 overlay_lookup(u8 index) const { return m_color_ram[m_palette_colors + index]; }
+
+protected:
+ bt45x_mono_device_base(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, const u32 palette_colors, const u32 overlay_colors);
+
+ virtual void device_start() override;
+
+ virtual DECLARE_READ8_MEMBER(palette_r) override;
+ virtual DECLARE_WRITE8_MEMBER(palette_w) override;
+ virtual DECLARE_READ8_MEMBER(overlay_r) override;
+ virtual DECLARE_WRITE8_MEMBER(overlay_w) override;
+
+ std::unique_ptr<u8[]> m_color_ram;
+};
+
+class bt451_device : public bt45x_rgb_device_base
+{
+public:
+ bt451_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+protected:
+ /*
+ * The Bt451 is different in having an 8 bit data bus, but 4 bit DACs. The
+ * lower 4 bits are masked off when reading or writing colour data.
+ */
+ virtual u8 get_mask() const override { return 0xf0; }
+};
+
+class bt453_device : public bt45x_rgb_device_base
+{
+public:
+ bt453_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ virtual void map(address_map &map) override;
+};
+
+class bt454_device : public bt45x_rgb_device_base
+{
+public:
+ bt454_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ virtual void map(address_map &map) override;
+};
+
+class bt455_device : public bt45x_mono_device_base
+{
+public:
+ bt455_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ virtual void map(address_map &map) override;
+};
+
+class bt457_device : public bt45x_mono_device_base
+{
+public:
+ bt457_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+protected:
+ virtual DECLARE_READ8_MEMBER(palette_r) override;
+ virtual DECLARE_WRITE8_MEMBER(palette_w) override;
+ virtual DECLARE_READ8_MEMBER(overlay_r) override;
+ virtual DECLARE_WRITE8_MEMBER(overlay_w) override;
+
+ virtual void increment_address(const bool side_effects = false) override;
+};
+
+class bt458_device : public bt45x_rgb_device_base
+{
+public:
+ bt458_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+};
+
+DECLARE_DEVICE_TYPE(BT451, bt451_device)
+DECLARE_DEVICE_TYPE(BT453, bt453_device)
+DECLARE_DEVICE_TYPE(BT454, bt454_device)
+DECLARE_DEVICE_TYPE(BT455, bt455_device)
+DECLARE_DEVICE_TYPE(BT457, bt457_device)
+DECLARE_DEVICE_TYPE(BT458, bt458_device)
+
+#endif // MAME_VIDEO_BT45X_H