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/dp8510.cpp211
-rw-r--r--src/devices/video/dp8510.h88
4 files changed, 312 insertions, 0 deletions
diff --git a/scripts/src/video.lua b/scripts/src/video.lua
index 59ed7ef18f8..035717a2da1 100644
--- a/scripts/src/video.lua
+++ b/scripts/src/video.lua
@@ -1033,3 +1033,15 @@ if (VIDEOS["I4100"]~=null) then
MAME_DIR .. "src/devices/video/imagetek_i4100.h",
}
end
+
+--------------------------------------------------
+--
+--@src/devices/video/dp8510.h,VIDEOS["DP8510"] = true
+--------------------------------------------------
+
+if (VIDEOS["DP8510"]~=null) then
+ files {
+ MAME_DIR .. "src/devices/video/dp8510.cpp",
+ MAME_DIR .. "src/devices/video/dp8510.h",
+ }
+end
diff --git a/scripts/target/mame/mess.lua b/scripts/target/mame/mess.lua
index 3814eb5d019..65c89bc15ce 100644
--- a/scripts/target/mame/mess.lua
+++ b/scripts/target/mame/mess.lua
@@ -353,6 +353,7 @@ VIDEOS["GB_LCD"] = true
VIDEOS["GBA_LCD"] = true
VIDEOS["MGA2064W"] = true
VIDEOS["PPU2C0X"] = true
+VIDEOS["DP8510"] = true
--------------------------------------------------
-- specify available machine cores
diff --git a/src/devices/video/dp8510.cpp b/src/devices/video/dp8510.cpp
new file mode 100644
index 00000000000..d0e64deb307
--- /dev/null
+++ b/src/devices/video/dp8510.cpp
@@ -0,0 +1,211 @@
+// license:BSD-3-Clause
+// copyright-holders:Patrick Mackinlay
+
+/*
+ * An implementation of the National Semiconductor DP8510 BITBLT Processing Unit.
+ *
+ * This device is designed to perform shifting, masking and logic operations on
+ * source and destination video memory data values. The device relies on
+ * external logic to drive the system video memory, and to control input lines
+ * on the device to enable it to read or write its inputs and outputs on the
+ * data bus. The device has a 16 bit data bus, as well as a 16 slot internal
+ * fifo, which enables it to work with up to 16 words containing 16 bits of
+ * pixel data at a time. The expected design was that a single BPU would handle
+ * each video bitplane, with multiple devices being used in parallel to handle
+ * multiple planes.
+ *
+ * This device is used in the InterPro GT family graphics, which do not make
+ * use of the line drawing mode, and is therefore currently unimplemented.
+ *
+ * Reference: http://bitsavers.org/components/national/_dataBooks/1988_National_Graphics_Handbook.pdf
+ *
+ * TODO
+ * - line drawing mode
+ */
+
+#include "emu.h"
+#include "dp8510.h"
+
+#define VERBOSE 0
+#include "logmacro.h"
+
+DEFINE_DEVICE_TYPE(DP8510, dp8510_device, "dp8510", "National Semiconductor BITBLT Processing Unit")
+
+const char *const dp8510_device::BITBLT_OP[] = {
+ "0", "~s & ~d", "~s & d", "~s", "s & ~d", "~d", "s ^ d", "~s | ~d",
+ "s & d", "~s ^ ~d", "d", "~s | d", "s", "s | ~d", "s | d", "1"
+};
+
+dp8510_device::dp8510_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
+ : device_t(mconfig, DP8510, tag, owner, clock)
+ , m_line_drawing(CLEAR_LINE)
+ , m_barrel_input_select(CLEAR_LINE)
+ , m_pixel_data_input(CLEAR_LINE)
+ , m_data_output_select(CLEAR_LINE)
+ , m_left_mask(CLEAR_LINE)
+ , m_right_mask(CLEAR_LINE)
+{
+}
+
+void dp8510_device::device_start()
+{
+ // input lines
+ save_item(NAME(m_line_drawing));
+ save_item(NAME(m_barrel_input_select));
+ save_item(NAME(m_pixel_data_input));
+ save_item(NAME(m_data_output_select));
+ save_item(NAME(m_left_mask));
+ save_item(NAME(m_right_mask));
+
+ // registers and latches
+ save_item(NAME(m_control));
+ save_item(NAME(m_barrel_input_latch));
+ save_item(NAME(m_logic_output));
+ save_item(NAME(m_fifo_output_latch));
+
+ // fifo
+ save_item(NAME(m_fifo[FIFO_SIZE]));
+ save_item(NAME(m_fifo_head));
+ save_item(NAME(m_fifo_tail));
+
+ // helper internal state
+ save_item(NAME(m_f0));
+ save_item(NAME(m_f1));
+ save_item(NAME(m_f2));
+ save_item(NAME(m_f3));
+}
+
+void dp8510_device::device_reset()
+{
+ m_fifo_head = 0;
+ m_fifo_tail = 0;
+}
+
+void dp8510_device::control_w(const u16 data)
+{
+ LOG("control_w function select %d shift number %d left mask %d right mask %d (%s)\n",
+ (data & CONTROL_FS) >> 12,
+ (data & CONTROL_SN) >> 8,
+ (data & CONTROL_LM) >> 4,
+ (data & CONTROL_RM) >> 0,
+ machine().describe_context());
+
+ m_control = data;
+
+ // expand function select bits to 16 bit size for convenience
+ m_f0 = (data & FS_0) ? ~u16(0) : 0;
+ m_f1 = (data & FS_1) ? ~u16(0) : 0;
+ m_f2 = (data & FS_2) ? ~u16(0) : 0;
+ m_f3 = (data & FS_3) ? ~u16(0) : 0;
+}
+
+void dp8510_device::source_w(const u16 data, const bool fifo_write)
+{
+ if (fifo_write)
+ {
+ // execute barrel shift
+ const u8 shift_amount = (m_control & CONTROL_SN) >> 8;
+ const u16 shift_result = m_barrel_input_select
+ ? (data << shift_amount) | (m_barrel_input_latch >> (16 - shift_amount))
+ : (m_barrel_input_latch << shift_amount) | (data >> (16 - shift_amount));
+
+ LOG("source_w 0x%04x shifted data 0x%04x written to fifo\n", data, shift_result);
+
+ // write result to fifo
+ fifo_w(shift_result);
+ }
+ else
+ LOG("source_w barrel input latch 0x%04x\n", data);
+
+ // save data in input latch
+ m_barrel_input_latch = data;
+}
+
+u16 dp8510_device::logic_unit(const u16 src, const u16 dst) const
+{
+ // compute logic unit result
+ const u16 result =
+ (m_f3 & src & dst) +
+ (m_f2 & src & ~dst) +
+ (m_f1 & ~src & dst) +
+ (m_f0 & ~src & ~dst);
+
+ LOG("logic_unit operation %s source 0x%04x destination 0x%04x result 0x%04x\n",
+ BITBLT_OP[(m_control & CONTROL_FS) >> 12], src, dst, result);
+
+ return result;
+}
+
+void dp8510_device::destination_w(const u16 data, const bool fifo_write)
+{
+ // fetch the source from the pixel data input or fifo
+ const u16 source = m_line_drawing ? m_pixel_data_input ? 0xffff : 0 : m_fifo_output_latch = fifo_r();
+
+ // compute the result
+ u16 result = logic_unit(source, data);
+
+ // apply left mask
+ if (m_left_mask)
+ {
+ const u16 left_mask = 0xffffU >> ((m_control & CONTROL_LM) >> 4);
+ if (left_mask != 0xffff)
+ LOG("destination_w left mask 0x%04x applied\n", left_mask);
+
+ result = (result & left_mask) | (data & ~left_mask);
+ }
+
+ // apply right mask
+ if (m_right_mask)
+ {
+ const u16 right_mask = s16(0x8000) >> (m_control & CONTROL_RM);
+ if (right_mask != 0xffff)
+ LOG("destination_w right mask 0x%04x applied\n", right_mask);
+
+ result = (result & right_mask) | (data & ~right_mask);
+ }
+
+ // latch output
+ m_logic_output = result;
+
+ // write the result back to the fifo
+ if (fifo_write)
+ {
+ LOG("destination_w masked data 0x%04x written to fifo\n", m_logic_output);
+ fifo_w(m_logic_output);
+ }
+ else
+ LOG("destination_w masked data 0x%04x latched\n", m_logic_output);
+}
+
+u16 dp8510_device::output_r() const
+{
+ // return output from fifo or logic unit
+ if (m_data_output_select)
+ return m_fifo_output_latch;
+ else
+ return m_logic_output;
+}
+
+u8 dp8510_device::pixel_r(const offs_t pixel_address) const
+{
+ return (m_logic_output >> (~pixel_address & 0xf)) & 0x1;
+}
+
+u16 dp8510_device::fifo_r()
+{
+ const u16 data = m_fifo[m_fifo_head++];
+
+ m_fifo_head %= FIFO_SIZE;
+
+ return data;
+}
+
+void dp8510_device::fifo_w(const u16 data)
+{
+ m_fifo[m_fifo_tail++] = data;
+
+ m_fifo_tail %= FIFO_SIZE;
+
+ if (m_fifo_tail == m_fifo_head)
+ logerror("fifo_w warning fifo full (%s)\n", machine().describe_context());
+}
diff --git a/src/devices/video/dp8510.h b/src/devices/video/dp8510.h
new file mode 100644
index 00000000000..946dd0d8c15
--- /dev/null
+++ b/src/devices/video/dp8510.h
@@ -0,0 +1,88 @@
+// license:BSD-3-Clause
+// copyright-holders:Patrick Mackinlay
+#ifndef MAME_VIDEO_DP8510_H
+#define MAME_VIDEO_DP8510_H
+
+#pragma once
+
+#include "video/dp8510.h"
+
+class dp8510_device : public device_t
+{
+public:
+ dp8510_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
+
+ static const char *const BITBLT_OP[];
+ static const int FIFO_SIZE = 16;
+
+ DECLARE_WRITE_LINE_MEMBER(line_drawing) { m_line_drawing = state; }
+ DECLARE_WRITE_LINE_MEMBER(barrel_input_select) { m_barrel_input_select = state; }
+ DECLARE_WRITE_LINE_MEMBER(pixel_data_input) { m_pixel_data_input = state; }
+ DECLARE_WRITE_LINE_MEMBER(data_output_select) { m_data_output_select = state; }
+ DECLARE_WRITE_LINE_MEMBER(left_mask_enable) { m_left_mask = state; }
+ DECLARE_WRITE_LINE_MEMBER(right_mask_enable) { m_right_mask = state; }
+
+ enum control_mask : u16
+ {
+ CONTROL_RM = 0x000f, // right mask
+ CONTROL_LM = 0x00f0, // left mask
+ CONTROL_SN = 0x0f00, // shift number
+ CONTROL_FS = 0xf000 // function select
+ };
+
+ enum control_fs_mask : u16
+ {
+ FS_0 = 0x1000,
+ FS_1 = 0x2000,
+ FS_2 = 0x4000,
+ FS_3 = 0x8000
+ };
+
+ void control_w(const u16 data);
+
+ void source_w(const u16 data, const bool fifo_write = true);
+ void destination_w(const u16 data, const bool fifo_write = false);
+
+ u16 output_r() const;
+ u8 pixel_r(const offs_t pixel_address) const;
+
+protected:
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+ u16 logic_unit(const u16 src, const u16 dst) const;
+
+ u16 fifo_r();
+ void fifo_w(const u16 data);
+
+private:
+ // input lines
+ int m_line_drawing;
+ int m_barrel_input_select;
+ int m_pixel_data_input;
+ int m_data_output_select;
+ int m_left_mask;
+ int m_right_mask;
+
+ // registers and latches
+ u16 m_control;
+ u16 m_barrel_input_latch;
+ u16 m_logic_output;
+ u16 m_fifo_output_latch;
+
+ // fifo
+ u16 m_fifo[FIFO_SIZE];
+ u8 m_fifo_head;
+ u8 m_fifo_tail;
+
+ // helper internal state
+ u16 m_f0;
+ u16 m_f1;
+ u16 m_f2;
+ u16 m_f3;
+};
+
+// device type definition
+DECLARE_DEVICE_TYPE(DP8510, dp8510_device)
+
+#endif // MAME_VIDEO_DP8510_H