bt431: new device (nw)

This commit is contained in:
Patrick Mackinlay 2019-07-23 17:55:17 +07:00
parent 2c918774ea
commit ca8cd90e2b
3 changed files with 390 additions and 0 deletions

View File

@ -1218,3 +1218,15 @@ if (VIDEOS["BT47X"]~=null) then
MAME_DIR .. "src/devices/video/bt47x.h",
}
end
--------------------------------------------------
--
--@src/devices/video/bt431.h,VIDEOS["BT431"] = true
--------------------------------------------------
if (VIDEOS["BT431"]~=null) then
files {
MAME_DIR .. "src/devices/video/bt431.cpp",
MAME_DIR .. "src/devices/video/bt431.h",
}
end

283
src/devices/video/bt431.cpp Normal file
View File

@ -0,0 +1,283 @@
// license:BSD-3-Clause
// copyright-holders:Patrick Mackinlay
/*
* Brooktree Bt431 Monolithic CMOS 64x64 Pixel Cursor Generator.
*
* Sources:
* - http://bitsavers.org/components/brooktree/_dataBooks/1993_Brooktree_Graphics_and_Imaging_Product_Databook.pdf
*
* TODO:
* - test, profile and optimize
*/
#include "emu.h"
#include "bt431.h"
#define LOG_GENERAL (1U << 0)
//#define VERBOSE (LOG_GENERAL)
#include "logmacro.h"
DEFINE_DEVICE_TYPE(BT431, bt431_device, "bt431", "Bt431 64x64 Pixel Cursor Generator")
bt431_device::bt431_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock)
: device_t(mconfig, BT431, tag, owner, clock)
{
}
void bt431_device::device_start()
{
save_item(NAME(m_address));
save_item(NAME(m_command));
save_item(NAME(m_cursor_x));
save_item(NAME(m_cursor_y));
save_item(NAME(m_window_x));
save_item(NAME(m_window_y));
save_item(NAME(m_window_w));
save_item(NAME(m_window_h));
save_item(NAME(m_ram));
}
void bt431_device::device_reset()
{
m_address = 0;
m_command = 0;
update();
}
void bt431_device::map(address_map &map)
{
map(0x00, 0x00).rw(FUNC(bt431_device::addr_r<0>), FUNC(bt431_device::addr_w<0>));
map(0x01, 0x01).rw(FUNC(bt431_device::addr_r<8>), FUNC(bt431_device::addr_w<8>));
map(0x02, 0x02).rw(FUNC(bt431_device::ram_r), FUNC(bt431_device::ram_w));
map(0x03, 0x03).rw(FUNC(bt431_device::reg_r), FUNC(bt431_device::reg_w));
}
u8 bt431_device::ram_r()
{
u8 const data = m_ram[m_address & ADDRESS_MASK];
// increment address register
if (!machine().side_effects_disabled())
m_address = (m_address + 1) & ADDRESS_MASK;
return data;
}
void bt431_device::ram_w(u8 data)
{
m_ram[m_address & ADDRESS_MASK] = data;
// increment address register
if (!machine().side_effects_disabled())
m_address = (m_address + 1) & ADDRESS_MASK;
}
u8 bt431_device::reg_r()
{
u8 data = 0;
switch (m_address & 0xf)
{
case REG_COMMAND: data = m_command; break;
case REG_CURSOR_X_LO: data = m_cursor_x & 0xff; break;
case REG_CURSOR_X_HI: data = (m_cursor_x >> 8); break;
case REG_CURSOR_Y_LO: data = m_cursor_y & 0xff; break;
case REG_CURSOR_Y_HI: data = (m_cursor_y >> 8); break;
case REG_WINDOW_X_LO: data = m_window_x & 0xff; break;
case REG_WINDOW_X_HI: data = (m_window_x >> 8); break;
case REG_WINDOW_Y_LO: data = m_window_y & 0xff; break;
case REG_WINDOW_Y_HI: data = (m_window_y >> 8); break;
case REG_WINDOW_W_LO: data = m_window_w & 0xff; break;
case REG_WINDOW_W_HI: data = (m_window_w >> 8); break;
case REG_WINDOW_H_LO: data = m_window_h & 0xff; break;
case REG_WINDOW_H_HI: data = (m_window_h >> 8); break;
default:
LOG("read from unknown address 0x%04x (%s)\n",
m_address, machine().describe_context());
break;
}
// increment address register
if (!machine().side_effects_disabled())
m_address = (m_address + 1) & ADDRESS_MASK;
return data;
}
void bt431_device::reg_w(u8 data)
{
switch (m_address & 0xf)
{
case REG_COMMAND:
m_command = data;
LOG("64x64 cursor %s, cross hair cursor %s, cursor format %s, cross hair thickness %d\n",
(data & CR_D6) ? "enable" : "disable",
(data & CR_D5) ? "enable" : "disable",
(data & CR_D4) ? "OR" : "XOR",
((data & CR_D1D0) << 1) + 1);
break;
case REG_CURSOR_X_LO:
m_cursor_x = (m_cursor_x & 0x0f00) | data;
LOG("cursor x low register: 0x%02x\n", data);
break;
case REG_CURSOR_X_HI:
m_cursor_x = ((data & 0xf) << 8) | (m_cursor_x & 0xff);
LOG("cursor x high register: 0x%02x\n", data);
break;
case REG_CURSOR_Y_LO:
m_cursor_y = (m_cursor_y & 0x0f00) | data;
LOG("cursor y low register: 0x%02x\n", data);
break;
case REG_CURSOR_Y_HI:
m_cursor_y = ((data & 0xf) << 8) | (m_cursor_y & 0xff);
LOG("cursor y high register: 0x%02x\n", data);
break;
case REG_WINDOW_X_LO:
m_window_x = (m_window_x & 0x0f00) | data;
LOG("window x low register: 0x%02x\n", data);
break;
case REG_WINDOW_X_HI:
m_window_x = ((data & 0xf) << 8) | (m_window_x & 0xff);
LOG("window x high register: 0x%02x\n", data);
break;
case REG_WINDOW_Y_LO:
m_window_y = (m_window_y & 0x0f00) | data;
LOG("window y low register: 0x%02x\n", data);
break;
case REG_WINDOW_Y_HI:
m_window_y = ((data & 0xf) << 8) | (m_window_y & 0xff);
LOG("window y high register: 0x%02x\n", data);
break;
case REG_WINDOW_W_LO:
m_window_w = (m_window_w & 0x0f00) | data;
LOG("window width low register: 0x%02x\n", data);
break;
case REG_WINDOW_W_HI:
m_window_w = ((data & 0xf) << 8) | (m_window_w & 0xff);
LOG("window width high register: 0x%02x\n", data);
break;
case REG_WINDOW_H_LO:
m_window_h = (m_window_h & 0x0f00) | data;
LOG("window height low register: 0x%02x\n", data);
break;
case REG_WINDOW_H_HI:
m_window_h = ((data & 0xf) << 8) | (m_window_h & 0xff);
LOG("window height high register: 0x%02x\n", data);
break;
default:
LOG("write to unknown address 0x%04x data 0x%02x (%s)\n",
m_address, data, machine().describe_context());
break;
}
// increment address register
m_address = (m_address + 1) & ADDRESS_MASK;
update();
}
void bt431_device::update()
{
/*
* The cursor (x) value to be written is calculated as follows:
*
* Cx = desired display screen (x) position + D + H - P
*
* where
*
* P = 37 if 1:1 output multiplexing, 52 if 4:1 output multiplexing,
* 57 if 5:1 output multiplexing
* D = skew (in pixels) between the output cursor data and external pixel
* data
* H = number of pixels between the first rising edge of CLOCK
* following the falling edge of HSYNC* to active video
*
* The P value is one-half cursor RAM width + (internal pipeline delay in
* clock cycles * one, four or five, depending on multiplex selection).
*
* The cursor (y) value to be written is calculated as follows:
*
* Cy = desired display screen (y) position + V - 32
*
* where
*
* V = number of scan lines from the first falling edge of HSYNC* that is
* two or more clock cycles after the falling edge of VSYNC* to
* active video.
*
* Values from $0FC0 (-64) to $0FBF (+4031) may be loaded into the
* cursor (y) register. The negative values ($0FC0 to $0FFF) are used
* in situations where V < 32, and the cursor must be moved off the
* top of the screen.
*/
const int cursor_x = m_cursor_x + (
(m_command & CR_D3D2) == CR_D3D2_11 ? 37 :
(m_command & CR_D3D2) == CR_D3D2_41 ? 52 :
(m_command & CR_D3D2) == CR_D3D2_51 ? 57 : 0);
const int cursor_y = (m_cursor_y < 0xfc0 ? m_cursor_y : m_cursor_y - 0x1000) + 32;
// update bitmap cursor drawing rectangle
m_bm_window.set(cursor_x - 31, cursor_x + 32, cursor_y - 31, cursor_y + 32);
// update cross hair cursor drawing rectangles
const int thickness = m_command & CR_D1D0;
if (m_window_x == 0 && m_window_y == 0 && m_window_w == 0x0fff && m_window_h == 0x0fff)
{
// full screen cross hair cursor
m_ch_v.set(cursor_x - thickness, cursor_x + thickness, m_window_y, m_window_y + m_window_h - 1);
m_ch_h.set(m_window_x, m_window_x + m_window_w - 1, cursor_y - thickness, cursor_y + thickness);
}
else
{
// windowed cross hair cursor
const int window_x = m_window_x + (
(m_command & CR_D3D2) == CR_D3D2_11 ? 5 :
(m_command & CR_D3D2) == CR_D3D2_41 ? 20 :
(m_command & CR_D3D2) == CR_D3D2_51 ? 25 : 0);
const int window_y = m_window_y;
const int window_w = m_window_w + (
(m_command & CR_D3D2) == CR_D3D2_11 ? 2 :
(m_command & CR_D3D2) == CR_D3D2_41 ? 8 :
(m_command & CR_D3D2) == CR_D3D2_51 ? 10 : 0);
const int window_h = m_window_h + 2;
m_ch_v.set(cursor_x - thickness, cursor_x + thickness, window_y + 1, window_y + window_h - 2);
m_ch_h.set(window_x + 1, window_x + window_w - 2, cursor_y - thickness, cursor_y + thickness);
}
}
bool bt431_device::cur_r(unsigned x, unsigned y) const
{
bool data = false;
// cross hair cursor
if ((m_command & CR_D5) && (m_ch_h.contains(x, y) || m_ch_v.contains(x, y)))
data = true;
// bitmap cursor
if ((m_command & CR_D6) && m_bm_window.contains(x, y))
{
bool const bit = BIT(m_ram[(y - m_bm_window.top()) * 8 + (x - m_bm_window.left()) / 8], 7 - (x - m_bm_window.left()) % 8);
if (m_command & CR_D4)
data |= bit;
else
data ^= bit;
}
return data;
}

95
src/devices/video/bt431.h Normal file
View File

@ -0,0 +1,95 @@
// license:BSD-3-Clause
// copyright-holders:Patrick Mackinlay
#ifndef MAME_VIDEO_BT431_H
#define MAME_VIDEO_BT431_H
#pragma once
class bt431_device : public device_t
{
public:
bt431_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock);
enum register_number : unsigned
{
REG_COMMAND = 0,
REG_CURSOR_X_LO = 1,
REG_CURSOR_X_HI = 2,
REG_CURSOR_Y_LO = 3,
REG_CURSOR_Y_HI = 4,
REG_WINDOW_X_LO = 5,
REG_WINDOW_X_HI = 6,
REG_WINDOW_Y_LO = 7,
REG_WINDOW_Y_HI = 8,
REG_WINDOW_W_LO = 9,
REG_WINDOW_W_HI = 10,
REG_WINDOW_H_LO = 11,
REG_WINDOW_H_HI = 12,
};
enum command_mask : u8
{
CR_D1D0 = 0x03, // cross hair cursor thickness
CR_D3D2 = 0x0c, // multiplex control
CR_D4 = 0x10, // cursor format control
CR_D5 = 0x20, // cross hair cursor enable
CR_D6 = 0x40, // 64x64 cursor enable
};
enum cr_d1d0_mask : u8
{
CR_D1D0_1PIX = 0x00, // 1 pixel
CR_D1D0_3PIX = 0x01, // 3 pixels
CR_D1D0_5PIX = 0x02, // 5 pixels
CR_D1D0_7PIX = 0x03, // 7 pixels
};
enum cr_d3d2_mask : u8
{
CR_D3D2_11 = 0x00, // 1:1 multiplexing
CR_D3D2_41 = 0x04, // 4:1 multiplexing
CR_D3D2_51 = 0x08, // 5:1 multiplexing
};
void map(address_map &map);
bool cur_r(unsigned x, unsigned y) const;
protected:
static constexpr u16 ADDRESS_MASK = 0x01ff;
// device_t overrides
virtual void device_start() override;
virtual void device_reset() override;
template <unsigned S> u8 addr_r() { return m_address >> S; }
template <unsigned S> void addr_w(u8 data) { m_address = (m_address & (0xff00 >> S)) | (u16(data) << S); }
u8 ram_r();
void ram_w(u8 data);
u8 reg_r();
void reg_w(u8 data);
private:
void update();
// registers
u16 m_address;
u8 m_command;
u16 m_cursor_x;
u16 m_cursor_y;
u16 m_window_x;
u16 m_window_y;
u16 m_window_w;
u16 m_window_h;
u8 m_ram[512];
rectangle m_bm_window;
rectangle m_ch_h;
rectangle m_ch_v;
};
DECLARE_DEVICE_TYPE(BT431, bt431_device)
#endif // MAME_VIDEO_BT431_H