diff options
Diffstat (limited to 'src/devices/video/dp8510.cpp')
-rw-r--r-- | src/devices/video/dp8510.cpp | 211 |
1 files changed, 211 insertions, 0 deletions
diff --git a/src/devices/video/dp8510.cpp b/src/devices/video/dp8510.cpp new file mode 100644 index 00000000000..a98ea433322 --- /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)); + 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()); +} |