dp8510: new device

An implementation of the National Semiconductor DP8510 BITBLT Processing Unit. This is used on the InterPro GT family graphics boards, and this implementation seems to be correct enough to enable me to progress there, hence the PR. While I'd love to have another system to test against, I'm not aware of any other systems that ever used this device other than some NatSemi reference designs, which are not (yet) in MAME.
This commit is contained in:
Patrick Mackinlay 2017-12-06 18:58:55 +07:00
parent 7e7bff3543
commit ad9b6fe4e5
4 changed files with 312 additions and 0 deletions

View File

@ -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

View File

@ -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

View File

@ -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());
}

View File

@ -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