diff options
author | 2017-10-19 19:36:01 +0700 | |
---|---|---|
committer | 2017-10-19 19:36:01 +0700 | |
commit | 9a68224e4a7952fefbb3067a3e72effee6467d76 (patch) | |
tree | 1f7e7554a0437d3abb125ad58aad4e39c1e96001 | |
parent | 412ede0ef86fbdd7f38024c03ba0fe300fdce924 (diff) |
bt459: new device
Used in InterPro graphics boards.
-rw-r--r-- | scripts/src/video.lua | 11 | ||||
-rw-r--r-- | src/devices/video/bt459.cpp | 646 | ||||
-rw-r--r-- | src/devices/video/bt459.h | 244 |
3 files changed, 901 insertions, 0 deletions
diff --git a/scripts/src/video.lua b/scripts/src/video.lua index f883a45f592..789dfc9403c 100644 --- a/scripts/src/video.lua +++ b/scripts/src/video.lua @@ -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 diff --git a/src/devices/video/bt459.cpp b/src/devices/video/bt459.cpp new file mode 100644 index 00000000000..c8b1c93760e --- /dev/null +++ b/src/devices/video/bt459.cpp @@ -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); + } + } +} diff --git a/src/devices/video/bt459.h b/src/devices/video/bt459.h new file mode 100644 index 00000000000..11c81cfc5b4 --- /dev/null +++ b/src/devices/video/bt459.h @@ -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 |