mirror of
https://github.com/holub/mame
synced 2025-04-23 00:39:36 +03:00
bt459: new device
Used in InterPro graphics boards.
This commit is contained in:
parent
412ede0ef8
commit
9a68224e4a
@ -1010,3 +1010,14 @@ if (VIDEOS["PPU2C0X"]~=null) then
|
||||
}
|
||||
end
|
||||
|
||||
--------------------------------------------------
|
||||
--
|
||||
--@src/devices/video/bt459.h,VIDEOS["BT459"] = true
|
||||
--------------------------------------------------
|
||||
|
||||
if (VIDEOS["BT459"]~=null) then
|
||||
files {
|
||||
MAME_DIR .. "src/devices/video/bt459.cpp",
|
||||
MAME_DIR .. "src/devices/video/bt459.h",
|
||||
}
|
||||
end
|
||||
|
646
src/devices/video/bt459.cpp
Normal file
646
src/devices/video/bt459.cpp
Normal file
@ -0,0 +1,646 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Patrick Mackinlay
|
||||
|
||||
/*
|
||||
* An implementation of the Brooktree Bt459 150MHz Monolithic CMOS 256x24 Color Palette RAMDAC device.
|
||||
*
|
||||
* The device was initially rated at 135MHz and increased to 150MHz with revision B. The revision
|
||||
* register (the only software-visible change) is implemented in this emulation.
|
||||
*
|
||||
* Reference: http://www.bitsavers.org/components/brooktree/_dataBooks/1991_Brooktree_Product_Databook.pdf
|
||||
*
|
||||
* TODO
|
||||
* - blink masking and blinking
|
||||
* - pixel pan and zoom
|
||||
* - dual cursor logic
|
||||
* - X Windows modes
|
||||
* - overlay/underlay
|
||||
* - optimisation
|
||||
*/
|
||||
|
||||
#include "emu.h"
|
||||
#include "bt459.h"
|
||||
|
||||
#include "screen.h"
|
||||
|
||||
#define VERBOSE 0
|
||||
#include "logmacro.h"
|
||||
|
||||
DEFINE_DEVICE_TYPE(BT459, bt459_device, "bt459", "Brooktree 150MHz Monolithic CMOS 256x24 Color Palette RAMDAC")
|
||||
|
||||
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)
|
||||
{
|
||||
}
|
||||
|
||||
void bt459_device::device_start()
|
||||
{
|
||||
save_item(NAME(m_address));
|
||||
save_item(NAME(m_address_rgb));
|
||||
|
||||
save_item(NAME(m_overlay_color));
|
||||
save_item(NAME(m_cursor_color));
|
||||
|
||||
save_item(NAME(m_command_0));
|
||||
save_item(NAME(m_command_1));
|
||||
save_item(NAME(m_command_2));
|
||||
save_item(NAME(m_pixel_read_mask));
|
||||
save_item(NAME(m_pixel_blink_mask));
|
||||
save_item(NAME(m_overlay_read_mask));
|
||||
save_item(NAME(m_overlay_blink_mask));
|
||||
save_item(NAME(m_interleave));
|
||||
save_item(NAME(m_test));
|
||||
save_item(NAME(m_red_signature));
|
||||
save_item(NAME(m_green_signature));
|
||||
save_item(NAME(m_blue_signature));
|
||||
save_item(NAME(m_cursor_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_cursor_ram));
|
||||
save_item(NAME(m_palette_ram));
|
||||
}
|
||||
|
||||
void bt459_device::device_reset()
|
||||
{
|
||||
}
|
||||
|
||||
u8 bt459_device::get_component(rgb_t *arr, int index)
|
||||
{
|
||||
switch (m_address_rgb)
|
||||
{
|
||||
case 0: // red component
|
||||
m_address_rgb = 1;
|
||||
return (m_command_2 & CR2524) == CR2524_RED ? arr[index].g() : arr[index].r();
|
||||
|
||||
case 1: // green component
|
||||
m_address_rgb = 2;
|
||||
return arr[index].g();
|
||||
|
||||
case 2: // blue component
|
||||
m_address_rgb = 0;
|
||||
m_address = (m_address + 1) & ADDRESS_MASK;
|
||||
return (m_command_2 & CR2524) == CR2524_BLUE ? arr[index].g() : arr[index].b();
|
||||
}
|
||||
|
||||
// can't happen
|
||||
return 0;
|
||||
}
|
||||
|
||||
void bt459_device::set_component(rgb_t *arr, int index, u8 data)
|
||||
{
|
||||
switch (m_address_rgb)
|
||||
{
|
||||
case 0: // red component
|
||||
m_address_rgb = 1;
|
||||
(m_command_2 & CR2524) == CR2524_RED ? arr[index].set_g(data) : arr[index].set_r(data);
|
||||
break;
|
||||
|
||||
case 1: // green component
|
||||
m_address_rgb = 2;
|
||||
arr[index].set_g(data);
|
||||
break;
|
||||
|
||||
case 2: // blue component
|
||||
m_address_rgb = 0;
|
||||
m_address = (m_address + 1) & ADDRESS_MASK;
|
||||
(m_command_2 & CR2524) == CR2524_BLUE ? arr[index].set_g(data) : arr[index].set_b(data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
READ8_MEMBER(bt459_device::read)
|
||||
{
|
||||
u8 result = 0;
|
||||
|
||||
switch (offset)
|
||||
{
|
||||
case ADDRESS_LO:
|
||||
// reset component pointer and return address register lsb
|
||||
m_address_rgb = 0;
|
||||
return m_address & ADDRESS_LSB;
|
||||
|
||||
case ADDRESS_HI:
|
||||
// reset component pointer and return address register msb
|
||||
m_address_rgb = 0;
|
||||
return (m_address & ADDRESS_MSB) >> 8;
|
||||
|
||||
case PALETTE:
|
||||
// return component from palette ram
|
||||
return get_component(m_palette_ram, m_address & 0xff);
|
||||
}
|
||||
|
||||
switch (m_address)
|
||||
{
|
||||
case REG_OVERLAY_COLOR_0:
|
||||
case REG_OVERLAY_COLOR_1:
|
||||
case REG_OVERLAY_COLOR_2:
|
||||
case REG_OVERLAY_COLOR_3:
|
||||
case REG_OVERLAY_COLOR_4:
|
||||
case REG_OVERLAY_COLOR_5:
|
||||
case REG_OVERLAY_COLOR_6:
|
||||
case REG_OVERLAY_COLOR_7:
|
||||
case REG_OVERLAY_COLOR_8:
|
||||
case REG_OVERLAY_COLOR_9:
|
||||
case REG_OVERLAY_COLOR_10:
|
||||
case REG_OVERLAY_COLOR_11:
|
||||
case REG_OVERLAY_COLOR_12:
|
||||
case REG_OVERLAY_COLOR_13:
|
||||
case REG_OVERLAY_COLOR_14:
|
||||
case REG_OVERLAY_COLOR_15:
|
||||
return get_component(m_overlay_color, m_address & 0xf);
|
||||
|
||||
case REG_CURSOR_COLOR_1: return get_component(m_cursor_color, 0);
|
||||
case REG_CURSOR_COLOR_2: return get_component(m_cursor_color, 1);
|
||||
case REG_CURSOR_COLOR_3: return get_component(m_cursor_color, 2);
|
||||
|
||||
case REG_ID:
|
||||
result = m_id;
|
||||
LOG("id register read (%s)\n", machine().describe_context());
|
||||
break;
|
||||
|
||||
case REG_COMMAND_0: result = m_command_0; break;
|
||||
case REG_COMMAND_1: result = m_command_1; break;
|
||||
case REG_COMMAND_2: result = m_command_2; break;
|
||||
case REG_PIXEL_READ_MASK: result = m_pixel_read_mask; break;
|
||||
|
||||
case REG_PIXEL_BLINK_MASK: result = m_pixel_blink_mask; break;
|
||||
|
||||
case REG_OVERLAY_READ_MASK: result = m_overlay_read_mask; break;
|
||||
case REG_OVERLAY_BLINK_MASK: result = m_overlay_blink_mask; break;
|
||||
case REG_INTERLEAVE: result = m_interleave; break;
|
||||
|
||||
case REG_TEST: result = m_test; break;
|
||||
case REG_RED_SIGNATURE: result = m_red_signature; break;
|
||||
case REG_GREEN_SIGNATURE: result = m_green_signature; break;
|
||||
case REG_BLUE_SIGNATURE: result = m_blue_signature; break;
|
||||
|
||||
case REG_REVISION:
|
||||
result = m_revision;
|
||||
LOG("revision register read (%s)\n", machine().describe_context());
|
||||
break;
|
||||
|
||||
case REG_CURSOR_COMMAND: result = m_cursor_command; break;
|
||||
|
||||
case REG_CURSOR_X_LO: result = m_cursor_x & 0xff; break;
|
||||
case REG_CURSOR_X_HI: result = (m_cursor_x >> 8); break;
|
||||
case REG_CURSOR_Y_LO: result = m_cursor_y & 0xff; break;
|
||||
case REG_CURSOR_Y_HI: result = (m_cursor_y >> 8); break;
|
||||
|
||||
case REG_WINDOW_X_LO: result = m_window_x & 0xff; break;
|
||||
case REG_WINDOW_X_HI: result = (m_window_x >> 8); break;
|
||||
case REG_WINDOW_Y_LO: result = m_window_y & 0xff; break;
|
||||
case REG_WINDOW_Y_HI: result = (m_window_y >> 8); break;
|
||||
|
||||
case REG_WINDOW_W_LO: result = m_window_w & 0xff; break;
|
||||
case REG_WINDOW_W_HI: result = (m_window_w >> 8); break;
|
||||
case REG_WINDOW_H_LO: result = m_window_h & 0xff; break;
|
||||
case REG_WINDOW_H_HI: result = (m_window_h >> 8); break;
|
||||
|
||||
default:
|
||||
if (m_address >= CURSOR_RAM_START && m_address <= CURSOR_RAM_END)
|
||||
result = m_cursor_ram[m_address & CURSOR_RAM_MASK];
|
||||
else
|
||||
LOG("read from unknown address 0x%04x (%s)\n", m_address, machine().describe_context());
|
||||
break;
|
||||
}
|
||||
|
||||
// increment address register and return result
|
||||
m_address = (m_address + 1) & ADDRESS_MASK;
|
||||
return result;
|
||||
}
|
||||
|
||||
WRITE8_MEMBER(bt459_device::write)
|
||||
{
|
||||
int index;
|
||||
|
||||
switch (offset)
|
||||
{
|
||||
case ADDRESS_LO:
|
||||
// reset component pointer and set address register lsb
|
||||
m_address_rgb = 0;
|
||||
m_address = (m_address & ADDRESS_MSB) | data;
|
||||
return;
|
||||
|
||||
case ADDRESS_HI:
|
||||
// reset component pointer and set address register msb
|
||||
m_address_rgb = 0;
|
||||
m_address = ((data << 8) | (m_address & ADDRESS_LSB)) & ADDRESS_MASK;
|
||||
return;
|
||||
|
||||
case PALETTE:
|
||||
// set component in color palette ram
|
||||
index = m_address & 0xff;
|
||||
set_component(m_palette_ram, index, data);
|
||||
|
||||
// update the mame palette to match the device
|
||||
if (m_address_rgb == 0)
|
||||
set_pen_color(index, m_palette_ram[index]);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (m_address)
|
||||
{
|
||||
case REG_COMMAND_0:
|
||||
m_command_0 = data;
|
||||
LOG("command register 0: multiplex select %s, use %s, blink rate %s, block mode %d bits per pixel\n",
|
||||
(data & CR0706) == CR0706_51MPX ? "5:1" :
|
||||
(data & CR0706) == CR0706_11MPX ? "1:1" :
|
||||
(data & CR0706) == CR0706_41MPX ? "4:1" : "reserved",
|
||||
(data & CR05) ? "overlay color 0" : "color palette RAM",
|
||||
(data & CR0302) == CR0302_6464 ? "64 on 64 off" :
|
||||
(data & CR0302) == CR0302_3232 ? "32 on 32 off" :
|
||||
(data & CR0302) == CR0302_1616 ? "16 on 16 off" : "16 on 48 off",
|
||||
8 >> (data & CR0100));
|
||||
break;
|
||||
|
||||
case REG_COMMAND_1:
|
||||
m_command_1 = data;
|
||||
LOG("command register 1: pan select %d pixels, zoom factor %dx\n",
|
||||
(data >> 5), (data & CR1310) + 1);
|
||||
break;
|
||||
|
||||
case REG_COMMAND_2:
|
||||
m_command_2 = data;
|
||||
LOG("command register 2: %s sync, %s IRE pedestal, load palette RAM select %s, PLL select %s, %s overlays, %s cursor, %s test\n",
|
||||
(data & CR27) ? "enable" : "disable",
|
||||
(data & CR26) ? "7.5" : "0",
|
||||
(data & CR2524) == CR2524_BLUE ? "blue RAMDAC" :
|
||||
(data & CR2524) == CR2524_GREEN ? "green RAMDAC" :
|
||||
(data & CR2524) == CR2524_RED ? "red RAMDAC" : "normal",
|
||||
(data & CR23) ? "BLANK*" : "SYNC*",
|
||||
(data & CR22) ? "X Windows" : "normal",
|
||||
(data & CR21) ? "X Windows" : "normal",
|
||||
(data & CR20) ? "data strobe" : "signature analysis");
|
||||
break;
|
||||
|
||||
case REG_PIXEL_READ_MASK:
|
||||
m_pixel_read_mask = data;
|
||||
LOG("pixel read mask register: 0x%02x\n", data);
|
||||
break;
|
||||
|
||||
case REG_PIXEL_BLINK_MASK:
|
||||
m_pixel_blink_mask = data;
|
||||
LOG("pixel blink mask register: 0x%02x\n", data);
|
||||
break;
|
||||
|
||||
case REG_OVERLAY_READ_MASK:
|
||||
m_overlay_read_mask = data;
|
||||
LOG("overlay read mask register: 0x%02x\n", data);
|
||||
break;
|
||||
|
||||
case REG_OVERLAY_BLINK_MASK:
|
||||
m_overlay_blink_mask = data;
|
||||
LOG("overlay blink mask register: 0x%02x\n", data);
|
||||
break;
|
||||
|
||||
case REG_INTERLEAVE:
|
||||
m_interleave = data;
|
||||
LOG("interleave register: interleave select %d pixels, first pixel select pixel %c, overlay interleave %s, underlay %s\n",
|
||||
data >> 5,
|
||||
((data & CR3432) >> 2) + 'A',
|
||||
(data & CR31) ? "enabled" : "disabled",
|
||||
(data & CR30) ? "enabled" : "disabled");
|
||||
break;
|
||||
|
||||
case REG_TEST:
|
||||
m_test = data;
|
||||
LOG("test register: 0x%02x\n", data);
|
||||
break;
|
||||
|
||||
case REG_RED_SIGNATURE:
|
||||
m_red_signature = data;
|
||||
LOG("red signature register: 0x%02x\n", data);
|
||||
break;
|
||||
case REG_GREEN_SIGNATURE:
|
||||
m_green_signature = data;
|
||||
LOG("green signature register: 0x%02x\n", data);
|
||||
break;
|
||||
case REG_BLUE_SIGNATURE:
|
||||
m_blue_signature = data;
|
||||
LOG("blue signature register: 0x%02x\n", data);
|
||||
break;
|
||||
|
||||
case REG_CURSOR_COMMAND:
|
||||
m_cursor_command = data;
|
||||
LOG("cursor command register: 64x64 cursor plane1 %s, 64x64 cursor plane0 %s, cross hair cursor plane1 %s, "
|
||||
"cross hair cursor plane0 %s, cursor format %s, cross hair thickness %d pixels, cursor blink %s\n",
|
||||
(data & CR47) ? "enable" : "disable",
|
||||
(data & CR46) ? "enable" : "disable",
|
||||
(data & CR45) ? "enable" : "disable",
|
||||
(data & CR44) ? "enable" : "disable",
|
||||
(data & CR43) ? "OR" : "XOR",
|
||||
(data & CR4241) + 1,
|
||||
(data & CR40) ? "enable" : "disable"
|
||||
);
|
||||
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;
|
||||
|
||||
case REG_OVERLAY_COLOR_0:
|
||||
case REG_OVERLAY_COLOR_1:
|
||||
case REG_OVERLAY_COLOR_2:
|
||||
case REG_OVERLAY_COLOR_3:
|
||||
case REG_OVERLAY_COLOR_4:
|
||||
case REG_OVERLAY_COLOR_5:
|
||||
case REG_OVERLAY_COLOR_6:
|
||||
case REG_OVERLAY_COLOR_7:
|
||||
case REG_OVERLAY_COLOR_8:
|
||||
case REG_OVERLAY_COLOR_9:
|
||||
case REG_OVERLAY_COLOR_10:
|
||||
case REG_OVERLAY_COLOR_11:
|
||||
case REG_OVERLAY_COLOR_12:
|
||||
case REG_OVERLAY_COLOR_13:
|
||||
case REG_OVERLAY_COLOR_14:
|
||||
case REG_OVERLAY_COLOR_15:
|
||||
index = m_address & 0xf;
|
||||
set_component(m_overlay_color, index, data);
|
||||
|
||||
// update the mame palette to match the device
|
||||
if (m_address_rgb == 0)
|
||||
set_pen_color(BT459_PIXEL_COLORS + index, m_overlay_color[index]);
|
||||
return;
|
||||
|
||||
case REG_CURSOR_COLOR_1:
|
||||
set_component(m_cursor_color, 0, data);
|
||||
|
||||
// update the mame palette to match the device
|
||||
if (m_address_rgb == 0)
|
||||
set_pen_color(BT459_PIXEL_COLORS + BT459_OVERLAY_COLORS + 0, m_cursor_color[0]);
|
||||
return;
|
||||
|
||||
case REG_CURSOR_COLOR_2:
|
||||
set_component(m_cursor_color, 1, data);
|
||||
|
||||
// update the mame palette to match the device
|
||||
if (m_address_rgb == 0)
|
||||
set_pen_color(BT459_PIXEL_COLORS + BT459_OVERLAY_COLORS + 1, m_cursor_color[1]);
|
||||
return;
|
||||
|
||||
case REG_CURSOR_COLOR_3:
|
||||
set_component(m_cursor_color, 2, data);
|
||||
|
||||
// update the mame palette to match the device
|
||||
if (m_address_rgb == 0)
|
||||
set_pen_color(BT459_PIXEL_COLORS + BT459_OVERLAY_COLORS + 2, m_cursor_color[2]);
|
||||
return;
|
||||
|
||||
default:
|
||||
if (m_address >= CURSOR_RAM_START && m_address <= CURSOR_RAM_END)
|
||||
m_cursor_ram[m_address & CURSOR_RAM_MASK] = data;
|
||||
else
|
||||
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;
|
||||
}
|
||||
|
||||
void bt459_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect, u8 *pixel_data)
|
||||
{
|
||||
// draw pixel data
|
||||
switch (m_command_0 & CR0100)
|
||||
{
|
||||
case CR0100_1BPP:
|
||||
for (int y = 0; y < screen.height(); y++)
|
||||
for (int x = 0; x < screen.width(); x += 8)
|
||||
{
|
||||
u8 data = *pixel_data++;
|
||||
|
||||
bitmap.pix(y, x + 7) = get_rgb(data & 0x1); data >>= 1;
|
||||
bitmap.pix(y, x + 6) = get_rgb(data & 0x1); data >>= 1;
|
||||
bitmap.pix(y, x + 5) = get_rgb(data & 0x1); data >>= 1;
|
||||
bitmap.pix(y, x + 4) = get_rgb(data & 0x1); data >>= 1;
|
||||
bitmap.pix(y, x + 3) = get_rgb(data & 0x1); data >>= 1;
|
||||
bitmap.pix(y, x + 2) = get_rgb(data & 0x1); data >>= 1;
|
||||
bitmap.pix(y, x + 1) = get_rgb(data & 0x1); data >>= 1;
|
||||
bitmap.pix(y, x + 0) = get_rgb(data & 0x1);
|
||||
}
|
||||
break;
|
||||
|
||||
case CR0100_2BPP:
|
||||
for (int y = 0; y < screen.height(); y++)
|
||||
for (int x = 0; x < screen.width(); x += 4)
|
||||
{
|
||||
u8 data = *pixel_data++;
|
||||
|
||||
bitmap.pix(y, x + 3) = get_rgb(data & 0x3); data >>= 2;
|
||||
bitmap.pix(y, x + 2) = get_rgb(data & 0x3); data >>= 2;
|
||||
bitmap.pix(y, x + 1) = get_rgb(data & 0x3); data >>= 2;
|
||||
bitmap.pix(y, x + 0) = get_rgb(data & 0x3);
|
||||
}
|
||||
break;
|
||||
|
||||
case CR0100_4BPP:
|
||||
for (int y = 0; y < screen.height(); y++)
|
||||
for (int x = 0; x < screen.width(); x += 2)
|
||||
{
|
||||
u8 data = *pixel_data++;
|
||||
|
||||
bitmap.pix(y, x + 1) = get_rgb(data & 0x7); data >>= 4;
|
||||
bitmap.pix(y, x + 0) = get_rgb(data & 0x7);
|
||||
}
|
||||
break;
|
||||
|
||||
case CR0100_8BPP:
|
||||
for (int y = 0; y < screen.height(); y++)
|
||||
for (int x = 0; x < screen.width(); x++)
|
||||
bitmap.pix(y, x) = get_rgb(*pixel_data++);
|
||||
break;
|
||||
}
|
||||
|
||||
// draw cursors
|
||||
if (m_cursor_command & (CR47 | CR46 | CR45 | CR44))
|
||||
{
|
||||
/*
|
||||
* The cursor (x) value to be written is calculated as follows:
|
||||
*
|
||||
* Cx = desired display screen (x) position + H - P
|
||||
*
|
||||
* where
|
||||
*
|
||||
* P = 37 if 1:1 input multiplexing, 52 if 4:1 input multiplexing, 57 if 5:1 input multiplexing
|
||||
* H = number of pixels between the first rising edge of LD* following the falling edge of HSYNC*
|
||||
* to active video
|
||||
*
|
||||
* 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 second sync pulse during vertical blanking 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.
|
||||
*/
|
||||
int cursor_x = m_cursor_x - screen.visible_area().min_x + (
|
||||
(m_command_0 & CR0706) == CR0706_11MPX ? 37 :
|
||||
(m_command_0 & CR0706) == CR0706_41MPX ? 52 :
|
||||
(m_command_0 & CR0706) == CR0706_51MPX ? 57 : 0);
|
||||
int cursor_y = (m_cursor_y < 0xfc0 ? m_cursor_y : m_cursor_y - 0x1000) - screen.visible_area().min_y + 32;
|
||||
|
||||
// 64x64 cursor
|
||||
if (m_cursor_command & (CR47 | CR46))
|
||||
{
|
||||
// compute target 64x64 rectangle
|
||||
rectangle cursor(cursor_x - 31, cursor_x + 32, cursor_y - 31, cursor_y + 32);
|
||||
|
||||
// intersect with bitmap
|
||||
cursor &= bitmap.cliprect();
|
||||
|
||||
// draw if any portion is visible
|
||||
if (!cursor.empty())
|
||||
{
|
||||
u8 cursor_mask = ((m_cursor_command & CR47) ? 0x2 : 0) | ((m_cursor_command & CR46) ? 0x1 : 0);
|
||||
int cursor_offset = 0;
|
||||
|
||||
for (int y = cursor_y - 31; y <= cursor_y + 32; y++)
|
||||
for (int x = cursor_x - 31; x <= cursor_x + 32; x += 4)
|
||||
{
|
||||
// fetch 4x2 bits of cursor data
|
||||
u8 data = m_cursor_ram[cursor_offset++];
|
||||
int cursor_color;
|
||||
|
||||
// write cursor pixels which are visible
|
||||
if ((cursor_color = ((data >>= 0) & cursor_mask)) && cursor.contains(x + 3, y))
|
||||
bitmap.pix(y, x + 3) = m_cursor_color[cursor_color - 1];
|
||||
|
||||
if ((cursor_color = ((data >>= 2) & cursor_mask)) && cursor.contains(x + 2, y))
|
||||
bitmap.pix(y, x + 2) = m_cursor_color[cursor_color - 1];
|
||||
|
||||
if ((cursor_color = ((data >>= 2) & cursor_mask)) && cursor.contains(x + 1, y))
|
||||
bitmap.pix(y, x + 1) = m_cursor_color[cursor_color - 1];
|
||||
|
||||
if ((cursor_color = ((data >>= 2) & cursor_mask)) && cursor.contains(x + 0, y))
|
||||
bitmap.pix(y, x + 0) = m_cursor_color[cursor_color - 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// cross hair cursor
|
||||
if (m_cursor_command & (CR45 | CR44))
|
||||
{
|
||||
// get the cross hair cursor color
|
||||
rgb_t cursor_color = m_cursor_color[(((m_cursor_command & CR45) ? 0x2 : 0) | ((m_cursor_command & CR44) ? 0x1 : 0)) - 1];
|
||||
|
||||
// get half the cross hair line thickness
|
||||
int thickness = (m_cursor_command & CR4241) >> 1;
|
||||
|
||||
/*
|
||||
* The window (x) value to be written is calculated as follows:
|
||||
*
|
||||
* Wx = desired display screen (x) position + H - P
|
||||
*
|
||||
* where
|
||||
*
|
||||
* P = 5 if 1:1 input multiplexing, 20 if 4:1 input multiplexing, 25 if 5:1 input multiplexing
|
||||
* H = number of pixels between the first rising edge of LD* following the falling edge of HSYNC*
|
||||
* to active video
|
||||
*
|
||||
* The window (y) value to be written is calculated as follows:
|
||||
*
|
||||
* Wy = desired display screen (y) position + V
|
||||
*
|
||||
* where
|
||||
*
|
||||
* V = number of scan lines from the second sync pulse during vertical blanking to active video
|
||||
*
|
||||
* Values from $0000 to $0FFF may be written to the window (x) and (y) registers. A full-screen cross hair
|
||||
* is implemented by loading the window (x,y) registers with $0000, and the window width and height registers with
|
||||
* $0FFF.
|
||||
*/
|
||||
int window_x = m_window_x - screen.visible_area().min_x + (
|
||||
(m_command_0 & CR0706) == CR0706_11MPX ? 5 :
|
||||
(m_command_0 & CR0706) == CR0706_41MPX ? 20 :
|
||||
(m_command_0 & CR0706) == CR0706_51MPX ? 25 : 0);
|
||||
int window_y = m_window_y - screen.visible_area().min_y;
|
||||
|
||||
/*
|
||||
* The actual window width is 2, 8 or 10 pixels more than the value specified by the window width register, depending
|
||||
* on whether 1:1, 4:1 or 5:1 input multiplexing is specified. The actual window height is 2 pixels more than the
|
||||
* value specified by the window height register. Therefore, the minimum window width is 2, 8 or 10 pixels for 1:1,
|
||||
* 4:1 and 5:1 multiplexing, respectively. The minimum window height is 2 pixels.
|
||||
*
|
||||
* Values from $0000 to $0FFF may be written to the window width and height registers.
|
||||
*/
|
||||
int window_w = m_window_w + (
|
||||
(m_command_0 & CR0706) == CR0706_11MPX ? 2 :
|
||||
(m_command_0 & CR0706) == CR0706_41MPX ? 8 :
|
||||
(m_command_0 & CR0706) == CR0706_51MPX ? 10 : 0);
|
||||
int window_h = m_window_h + 2;
|
||||
|
||||
// draw the vertical line
|
||||
rectangle vertical(cursor_x - thickness, cursor_x + thickness, window_y, window_y + window_h);
|
||||
|
||||
vertical &= bitmap.cliprect();
|
||||
|
||||
if (!vertical.empty())
|
||||
bitmap.fill(cursor_color, vertical);
|
||||
|
||||
// draw the horizontal line
|
||||
rectangle horizontal(window_x, window_x + window_w, cursor_y - thickness, cursor_y + thickness);
|
||||
|
||||
horizontal &= bitmap.cliprect();
|
||||
|
||||
if (!horizontal.empty())
|
||||
bitmap.fill(cursor_color, horizontal);
|
||||
}
|
||||
}
|
||||
}
|
244
src/devices/video/bt459.h
Normal file
244
src/devices/video/bt459.h
Normal file
@ -0,0 +1,244 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Patrick Mackinlay
|
||||
#ifndef MAME_VIDEO_BT459_H
|
||||
#define MAME_VIDEO_BT459_H
|
||||
|
||||
#pragma once
|
||||
|
||||
class bt459_device : public device_t, public device_palette_interface
|
||||
{
|
||||
public:
|
||||
bt459_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
||||
|
||||
static const u8 BT459_ID = 0x4a; // magic number found in the id register
|
||||
static const u8 BT459_REV = 0xb0; // device revision B found in revision register
|
||||
|
||||
static const int BT459_PIXEL_COLORS = 256;
|
||||
static const int BT459_OVERLAY_COLORS = 16;
|
||||
static const int BT459_CURSOR_COLORS = 3;
|
||||
|
||||
enum control_input
|
||||
{
|
||||
ADDRESS_LO = 0x0,
|
||||
ADDRESS_HI = 0x1,
|
||||
REGISTERS = 0x2,
|
||||
PALETTE = 0x3
|
||||
};
|
||||
|
||||
enum address_mask
|
||||
{
|
||||
REG_OVERLAY_COLOR_0 = 0x0100,
|
||||
REG_OVERLAY_COLOR_1 = 0x0101,
|
||||
REG_OVERLAY_COLOR_2 = 0x0102,
|
||||
REG_OVERLAY_COLOR_3 = 0x0103,
|
||||
REG_OVERLAY_COLOR_4 = 0x0104,
|
||||
REG_OVERLAY_COLOR_5 = 0x0105,
|
||||
REG_OVERLAY_COLOR_6 = 0x0106,
|
||||
REG_OVERLAY_COLOR_7 = 0x0107,
|
||||
REG_OVERLAY_COLOR_8 = 0x0108,
|
||||
REG_OVERLAY_COLOR_9 = 0x0109,
|
||||
REG_OVERLAY_COLOR_10 = 0x010a,
|
||||
REG_OVERLAY_COLOR_11 = 0x010b,
|
||||
REG_OVERLAY_COLOR_12 = 0x010c,
|
||||
REG_OVERLAY_COLOR_13 = 0x010d,
|
||||
REG_OVERLAY_COLOR_14 = 0x010e,
|
||||
REG_OVERLAY_COLOR_15 = 0x010f,
|
||||
|
||||
REG_CURSOR_COLOR_1 = 0x0181,
|
||||
REG_CURSOR_COLOR_2 = 0x0182,
|
||||
REG_CURSOR_COLOR_3 = 0x0183,
|
||||
|
||||
REG_ID = 0x0200,
|
||||
REG_COMMAND_0 = 0x0201,
|
||||
REG_COMMAND_1 = 0x0202,
|
||||
REG_COMMAND_2 = 0x0203,
|
||||
REG_PIXEL_READ_MASK = 0x0204,
|
||||
|
||||
REG_PIXEL_BLINK_MASK = 0x0206,
|
||||
|
||||
REG_OVERLAY_READ_MASK = 0x0208,
|
||||
REG_OVERLAY_BLINK_MASK = 0x0209,
|
||||
REG_INTERLEAVE = 0x020a,
|
||||
REG_TEST = 0x020b,
|
||||
REG_RED_SIGNATURE = 0x020c,
|
||||
REG_GREEN_SIGNATURE = 0x020d,
|
||||
REG_BLUE_SIGNATURE = 0x020e,
|
||||
|
||||
REG_REVISION = 0x0220,
|
||||
|
||||
REG_CURSOR_COMMAND = 0x0300,
|
||||
REG_CURSOR_X_LO = 0x0301,
|
||||
REG_CURSOR_X_HI = 0x0302,
|
||||
REG_CURSOR_Y_LO = 0x0303,
|
||||
REG_CURSOR_Y_HI = 0x0304,
|
||||
REG_WINDOW_X_LO = 0x0305,
|
||||
REG_WINDOW_X_HI = 0x0306,
|
||||
REG_WINDOW_Y_LO = 0x0307,
|
||||
REG_WINDOW_Y_HI = 0x0308,
|
||||
REG_WINDOW_W_LO = 0x0309,
|
||||
REG_WINDOW_W_HI = 0x030a,
|
||||
REG_WINDOW_H_LO = 0x030b,
|
||||
REG_WINDOW_H_HI = 0x030c,
|
||||
|
||||
CURSOR_RAM_START = 0x0400,
|
||||
CURSOR_RAM_END = 0x07ff,
|
||||
CURSOR_RAM_MASK = 0x03ff,
|
||||
|
||||
ADDRESS_LSB = 0x00ff,
|
||||
ADDRESS_MSB = 0x0f00,
|
||||
ADDRESS_MASK = 0x0fff
|
||||
};
|
||||
|
||||
enum command_0_mask
|
||||
{
|
||||
CR0706 = 0xc0, // multiplex select
|
||||
CR05 = 0x20, // overlay 0 enable
|
||||
CR04 = 0x10, // reserved
|
||||
CR0302 = 0x0c, // blink rate selection
|
||||
CR0100 = 0x03 // block mode
|
||||
};
|
||||
enum cr0706_mask
|
||||
{
|
||||
CR0706_51MPX = 0xc0, // 5:1 multiplex
|
||||
CR0706_11MPX = 0x80, // 1:1 multiplex
|
||||
CR0706_41MPX = 0x40, // 4:1 multiplex
|
||||
CR0706_RESERVED = 0x00 // reserved
|
||||
};
|
||||
enum cr0302_mask
|
||||
{
|
||||
CR0302_6464 = 0x0c, // 64 on 64 off, 50/50
|
||||
CR0302_3232 = 0x08, // 32 on 32 off, 50/50
|
||||
CR0302_1616 = 0x04, // 16 on 16 off, 50/50
|
||||
CR0302_1648 = 0x00 // 16 on 48 off, 25/75
|
||||
};
|
||||
enum cr0100_mask
|
||||
{
|
||||
CR0100_1BPP = 0x03, // 1 bit per pixel
|
||||
CR0100_2BPP = 0x02, // 2 bits per pixel
|
||||
CR0100_4BPP = 0x01, // 4 bits per pixel
|
||||
CR0100_8BPP = 0x00 // 8 bits per pixel
|
||||
};
|
||||
|
||||
enum command_1_mask
|
||||
{
|
||||
CR1715 = 0xe0, // pan select
|
||||
CR14 = 0x10, // reserved
|
||||
CR1310 = 0x0f // zoom factor
|
||||
};
|
||||
|
||||
enum command_2_mask
|
||||
{
|
||||
CR27 = 0x80, // sync enable
|
||||
CR26 = 0x40, // pedestal enable
|
||||
CR2524 = 0x30, // load palette RAM select
|
||||
CR23 = 0x08, // PLL select
|
||||
CR22 = 0x04, // X Windows overlay select
|
||||
CR21 = 0x02, // X Windows cursor select
|
||||
CR20 = 0x01 // test mode select
|
||||
};
|
||||
enum cr2524_mask
|
||||
{
|
||||
CR2524_BLUE = 0x30,
|
||||
CR2524_GREEN = 0x20,
|
||||
CR2524_RED = 0x10,
|
||||
CR2524_NORMAL = 0x00
|
||||
};
|
||||
|
||||
enum interleave_mask
|
||||
{
|
||||
CR3735 = 0xe0, // interleave select
|
||||
CR3432 = 0x1c, // first pixel select
|
||||
CR31 = 0x02, // overlay interleave enable
|
||||
CR30 = 0x01 // underlay enable
|
||||
};
|
||||
enum cr3735_mask
|
||||
{
|
||||
CR3735_4PIX = 0x80, // 4 pixels
|
||||
CR3735_3PIX = 0x60, // 3 pixels
|
||||
CR3735_2PIX = 0x40, // 2 pixels
|
||||
CR3735_1PIX = 0x20, // 1 pixel
|
||||
CR3735_0PIX = 0x00 // 0 pixels
|
||||
};
|
||||
enum cr3432_mask
|
||||
{
|
||||
CR3432_PIX_E = 0x10, // pixel E
|
||||
CR3432_PIX_D = 0x0c, // pixel D
|
||||
CR3432_PIX_C = 0x08, // pixel C
|
||||
CR3432_PIX_B = 0x04, // pixel B
|
||||
CR3432_PIX_A = 0x00 // pixel A
|
||||
};
|
||||
|
||||
enum cursor_command_mask
|
||||
{
|
||||
CR47 = 0x80, // 64x64 cursor plane 1 enable
|
||||
CR46 = 0x40, // 64x64 cursor plane 0 enable
|
||||
CR45 = 0x20, // cross hair plane 1 enable
|
||||
CR44 = 0x10, // cross hair plane 0 enable
|
||||
CR43 = 0x08, // cursor format
|
||||
CR4241 = 0x06, // cross hair thickness
|
||||
CR40 = 0x01 // cursor blink enable
|
||||
};
|
||||
|
||||
enum cr4241_mask
|
||||
{
|
||||
CR4241_1PIX = 0x00, // cross hair thickness 1 pixel
|
||||
CR4241_3PIX = 0x02, // cross hair thickness 3 pixels
|
||||
CR4241_5PIX = 0x04, // cross hair thickness 5 pixels
|
||||
CR4241_7PIX = 0x06 // cross hair thickness 7 pixels
|
||||
};
|
||||
|
||||
DECLARE_READ8_MEMBER(read);
|
||||
DECLARE_WRITE8_MEMBER(write);
|
||||
|
||||
void screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect, u8 *pixel_data);
|
||||
|
||||
protected:
|
||||
virtual void device_start() override;
|
||||
virtual void device_reset() override;
|
||||
|
||||
virtual u32 palette_entries() const override { return BT459_PIXEL_COLORS + BT459_OVERLAY_COLORS + BT459_CURSOR_COLORS; }
|
||||
|
||||
private:
|
||||
// helper functions
|
||||
u8 get_component(rgb_t *arr, int index);
|
||||
void set_component(rgb_t *arr, int index, u8 data);
|
||||
u32 get_rgb(u8 data) const { return m_palette_ram[data & m_pixel_read_mask]; }
|
||||
|
||||
// device state in memory map order
|
||||
u16 m_address;
|
||||
int m_address_rgb;
|
||||
|
||||
rgb_t m_overlay_color[BT459_OVERLAY_COLORS];
|
||||
rgb_t m_cursor_color[BT459_CURSOR_COLORS];
|
||||
|
||||
// registers
|
||||
const u8 m_id = BT459_ID;
|
||||
u8 m_command_0;
|
||||
u8 m_command_1;
|
||||
u8 m_command_2;
|
||||
u8 m_pixel_read_mask;
|
||||
u8 m_pixel_blink_mask;
|
||||
u8 m_overlay_read_mask;
|
||||
u8 m_overlay_blink_mask;
|
||||
u8 m_interleave;
|
||||
u8 m_test;
|
||||
u8 m_red_signature;
|
||||
u8 m_green_signature;
|
||||
u8 m_blue_signature;
|
||||
const u8 m_revision = BT459_REV;
|
||||
u8 m_cursor_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_cursor_ram[1024];
|
||||
rgb_t m_palette_ram[BT459_PIXEL_COLORS];
|
||||
};
|
||||
|
||||
DECLARE_DEVICE_TYPE(BT459, bt459_device)
|
||||
|
||||
#endif // MAME_VIDEO_BT459_H
|
Loading…
Reference in New Issue
Block a user