summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/video
diff options
context:
space:
mode:
author Curt Coder <curtcoder@mail.com>2013-03-07 15:28:25 +0000
committer Curt Coder <curtcoder@mail.com>2013-03-07 15:28:25 +0000
commit76ac08a0b805820f12be6dac3daee17f8eb26953 (patch)
tree74a1a81d8e2a6cf242d498978b3573015c4d7a0c /src/emu/video
parent7e0b63efa9978e8611337c4ac80ffc293bb527ee (diff)
Moved some files to where they belong. (nw)
Diffstat (limited to 'src/emu/video')
-rw-r--r--src/emu/video/dl1416.c344
-rw-r--r--src/emu/video/dl1416.h90
-rw-r--r--src/emu/video/hd44352.c456
-rw-r--r--src/emu/video/hd44352.h87
-rw-r--r--src/emu/video/hd44780.c556
-rw-r--r--src/emu/video/hd44780.h141
-rw-r--r--src/emu/video/hd66421.c256
-rw-r--r--src/emu/video/hd66421.h79
-rw-r--r--src/emu/video/mc6847.c1732
-rw-r--r--src/emu/video/mc6847.h648
-rw-r--r--src/emu/video/tms3556.c588
-rw-r--r--src/emu/video/tms3556.h112
-rw-r--r--src/emu/video/upd7220.c1673
-rw-r--r--src/emu/video/upd7220.h233
14 files changed, 6995 insertions, 0 deletions
diff --git a/src/emu/video/dl1416.c b/src/emu/video/dl1416.c
new file mode 100644
index 00000000000..32bf1f5a3c2
--- /dev/null
+++ b/src/emu/video/dl1416.c
@@ -0,0 +1,344 @@
+/*****************************************************************************
+ *
+ * video/dl1416.c
+ *
+ * DL1416
+ *
+ * 4-Digit 16-Segment Alphanumeric Intelligent Display
+ * with Memory/Decoder/Driver
+ *
+ * Notes:
+ * - Currently supports the DL1416T and by virtue of it being nearly the same, the DL1414.
+ * - Partial support for DL1416B is available, it just needs the right
+ * character set and MAME core support for its display.
+ * - Cursor support is implemented but not tested, as the AIM65 does not
+ * seem to use it.
+ *
+ * Todo:
+ * - Is the DL1416A identical to the DL1416T? If not, we need to add
+ * support for it.
+ * - Add proper support for DL1414 (pretty much DL1416T without the cursor)
+ *
+ * Changes:
+ * - 2007-07-30: Initial version. [Dirk Best]
+ * - 2008-02-25: Converted to the new device interface. [Dirk Best]
+ * - 2008-12-18: Cleanups. [Dirk Best]
+ * - 2011-10-08: Changed the ram to store character rather than segment data. [Lord Nightmare]
+ *
+ *
+ * We use the following order for the segments:
+ *
+ * 000 111
+ * 7D A E2
+ * 7 D A E 2
+ * 7 DAE 2
+ * 888 999
+ * 6 CBF 3
+ * 6 C B F 3
+ * 6C B F3
+ * 555 444
+ *
+ ****************************************************************************/
+
+#include "emu.h"
+#include "dl1416.h"
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+#define SEG_UNDEF (-2)
+#define SEG_BLANK (0)
+#define SEG_CURSOR (0xffff)
+#define CURSOR_ON (1)
+#define CURSOR_OFF (0)
+
+/* character set DL1416T */
+static const int dl1416t_segments[128] = {
+ SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, /* undefined */
+ SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, /* undefined */
+ SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, /* undefined */
+ SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, /* undefined */
+ SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, /* undefined */
+ SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, /* undefined */
+ SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, /* undefined */
+ SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, /* undefined */
+ 0x0000, 0x2421, 0x0480, 0x0f3c, /* ! " # */
+ 0x0fbb, 0x5f99, 0xa579, 0x4000, /* $ % & ' */
+ 0xc000, 0x3000, 0xff00, 0x0f00, /* ( ) * + */
+ 0x1000, 0x0300, 0x0020, 0x5000, /* , - . / */
+ 0x0ce1, 0x0c00, 0x0561, 0x0d21, /* 0 1 2 3 */
+ 0x0d80, 0x09a1, 0x09e1, 0x0c01, /* 4 5 6 7 */
+ 0x0de1, 0x0da1, 0x0021, 0x1001, /* 8 9 : ; */
+ 0x5030, 0x0330, 0xa030, 0x0a07, /* < = > ? */
+ 0x097f, 0x03cf, 0x0e3f, 0x00f3, /* @ A B C */
+ 0x0c3f, 0x01f3, 0x01c3, 0x02fb, /* D E F G */
+ 0x03cc, 0x0c33, 0x0c63, 0xc1c0, /* H I J K */
+ 0x00f0, 0x60cc, 0xa0cc, 0x00ff, /* L M N O */
+ 0x03c7, 0x80ff, 0x83c7, 0x03bb, /* P Q R S */
+ 0x0c03, 0x00fc, 0x50c0, 0x90cc, /* T U V W */
+ 0xf000, 0x6800, 0x5033, 0x00e1, /* X Y Z [ */
+ 0xa000, 0x001e, 0x9000, 0x0030, /* \ ] ^ _ */
+ SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, /* undefined */
+ SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, /* undefined */
+ SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, /* undefined */
+ SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, /* undefined */
+ SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, /* undefined */
+ SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, /* undefined */
+ SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, /* undefined */
+ SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, SEG_UNDEF /* undefined */
+};
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+struct dl1416_state
+{
+ int write_enable;
+ int chip_enable;
+ int cursor_enable;
+
+ UINT16 digit_ram[4]; // holds the digit code for each position
+ UINT8 cursor_state[4]; // holds the cursor state for each position, 0=off, 1=on
+};
+
+
+/*****************************************************************************
+ INLINE FUNCTIONS
+*****************************************************************************/
+
+INLINE dl1416_state *get_safe_token(device_t *device)
+{
+ assert(device != NULL);
+ assert(device->type() == DL1416B || device->type() == DL1416T);
+
+ return (dl1416_state *)downcast<dl1416_device *>(device)->token();
+}
+
+
+/*****************************************************************************
+ DEVICE INTERFACE
+*****************************************************************************/
+
+static DEVICE_START( dl1416 )
+{
+ dl1416_state *dl1416 = get_safe_token(device);
+
+ /* register for state saving */
+ state_save_register_item(device->machine(), "dl1416", device->tag(), 0, dl1416->chip_enable);
+ state_save_register_item(device->machine(), "dl1416", device->tag(), 0, dl1416->cursor_enable);
+ state_save_register_item(device->machine(), "dl1416", device->tag(), 0, dl1416->write_enable);
+ state_save_register_item_array(device->machine(), "dl1416", device->tag(), 0, dl1416->digit_ram);
+}
+
+
+static DEVICE_RESET( dl1416 )
+{
+ int i, pattern;
+ dl1416_state *chip = get_safe_token(device);
+ const dl1416_interface *intf = (const dl1416_interface *)device->static_config();
+ /* disable all lines */
+ chip->chip_enable = FALSE;
+ chip->write_enable = FALSE;
+ chip->cursor_enable = FALSE;
+
+ /* randomize digit and cursor memory */
+ for (i = 0; i < 4; i++)
+ {
+ chip->digit_ram[i] = device->machine().rand()&0x3F;
+ // TODO: only enable the following line if the device actually has a cursor (DL1416T and DL1416B), if DL1414 then cursor is always 0!
+ //chip->cursor_state[i] = ((device->machine().rand()&0xFF) >= 0x80) ? CURSOR_ON : CURSOR_OFF;
+ chip->cursor_state[i] = CURSOR_OFF;
+ pattern = dl1416t_segments[chip->digit_ram[i]];
+
+ /* If cursor for this digit position is enabled and segment is not */
+ /* undefined, replace digit with cursor */
+ if ((chip->cursor_state[i] == CURSOR_ON) && (pattern != SEG_UNDEF))
+ pattern = SEG_CURSOR;
+
+ /* Undefined characters are replaced by blanks */
+ if (pattern == SEG_UNDEF)
+ pattern = SEG_BLANK;
+
+ /* Call update function */
+ if (intf->update)
+ intf->update(device, i, pattern);
+ }
+}
+
+
+/*****************************************************************************
+ IMPLEMENTATION
+*****************************************************************************/
+
+/* write enable, active low */
+WRITE_LINE_DEVICE_HANDLER( dl1416_wr_w )
+{
+ dl1416_state *chip = get_safe_token(device);
+ chip->write_enable = !state;
+}
+
+/* chip enable, active low */
+WRITE_LINE_DEVICE_HANDLER( dl1416_ce_w )
+{
+ dl1416_state *chip = get_safe_token(device);
+ chip->chip_enable = !state;
+}
+
+/* cursor enable, active low */
+WRITE_LINE_DEVICE_HANDLER( dl1416_cu_w )
+{
+ dl1416_state *chip = get_safe_token(device);
+ chip->cursor_enable = !state;
+}
+
+/* data */
+WRITE8_DEVICE_HANDLER( dl1416_data_w )
+{
+ dl1416_state *chip = get_safe_token(device);
+ const dl1416_interface *intf = (const dl1416_interface *)device->static_config();
+
+ offset &= 0x03; /* A0-A1 */
+ data &= 0x7f; /* D0-D6 */
+
+ /* Only try to update the data if we are enabled and write is enabled */
+ if (chip->chip_enable && chip->write_enable)
+ {
+ /* fprintf(stderr,"DL1416 Write: Cursor: %d, Offset: %d, Data: %02X\n (%c)", chip->cursor_enable, offset, data, data); */
+ int i, pattern, previous_state;
+
+ if (chip->cursor_enable) /* cursor enable is set */
+ {
+ if (device->type() == DL1416B)
+ {
+ /* DL1416B uses offset to decide cursor pos to change and D0 to hold new state */
+
+ /* The cursor will be set if D0 is high and the original */
+ /* character restored otherwise */
+ previous_state = chip->cursor_state[offset];
+ chip->cursor_state[offset] = data & 1 ? CURSOR_ON : CURSOR_OFF;
+
+ if (previous_state != chip->cursor_state[offset])
+ {
+ pattern = dl1416t_segments[chip->digit_ram[offset]];
+
+ /* If cursor for this digit position is enabled and segment is not */
+ /* undefined, replace digit with cursor */
+ if ((chip->cursor_state[offset] == CURSOR_ON) && (pattern != SEG_UNDEF))
+ pattern = SEG_CURSOR;
+
+ /* Undefined characters are replaced by blanks */
+ if (pattern == SEG_UNDEF)
+ pattern = SEG_BLANK;
+
+ /* Call update function */
+ if (intf->update)
+ intf->update(device, offset, pattern);
+ }
+ }
+ else {
+ /* DL1416T uses a bitmap of 4 data bits D0,D1,D2,D3 to decide cursor pos to change and new state */
+
+ for (i = 0; i < 4; i++)
+ {
+ /* The cursor will be set if D0-D3 is high and the original */
+ /* character at the appropriate position restored otherwise */
+ previous_state = chip->cursor_state[i];
+ chip->cursor_state[i] = data & (1<<i) ? CURSOR_ON : CURSOR_OFF;
+
+ if (previous_state != chip->cursor_state[i])
+ {
+ pattern = dl1416t_segments[chip->digit_ram[i]];
+
+ /* If cursor for this digit position is enabled and segment is not */
+ /* undefined, replace digit with cursor */
+ if ((chip->cursor_state[i] == CURSOR_ON) && (pattern != SEG_UNDEF))
+ pattern = SEG_CURSOR;
+
+ /* Undefined characters are replaced by blanks */
+ if (pattern == SEG_UNDEF)
+ pattern = SEG_BLANK;
+
+ /* Call update function */
+ if (intf->update)
+ intf->update(device, i, pattern);
+ }
+ }
+ }
+ }
+ else /* cursor enable is not set, so standard write */
+ {
+ /* Save written value */
+ chip->digit_ram[offset] = data&0x3f;
+
+ /* Load segment pattern from ROM */
+ pattern = dl1416t_segments[data]; /** TODO: handle DL1416T vs DL1416B vs DL1414 here */
+
+ /* If cursor for this digit position is enabled and segment is not */
+ /* undefined, replace digit with cursor */
+ if ((chip->cursor_state[offset] == CURSOR_ON) && (pattern != SEG_UNDEF))
+ pattern = SEG_CURSOR;
+
+ /* Undefined characters are replaced by blanks */
+ if (pattern == SEG_UNDEF)
+ pattern = SEG_BLANK;
+
+ /* Call update function */
+ if (intf->update)
+ intf->update(device, offset, pattern);
+ }
+ }
+}
+
+dl1416_device::dl1416_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, type, name, tag, owner, clock)
+{
+ m_token = global_alloc_clear(dl1416_state);
+}
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void dl1416_device::device_config_complete()
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void dl1416_device::device_start()
+{
+ DEVICE_START_NAME( dl1416 )(this);
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void dl1416_device::device_reset()
+{
+ DEVICE_RESET_NAME( dl1416 )(this);
+}
+
+
+const device_type DL1416B = &device_creator<dl1416b_device>;
+
+dl1416b_device::dl1416b_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : dl1416_device(mconfig, DL1416B, "DL1416B", tag, owner, clock)
+{
+}
+
+
+const device_type DL1416T = &device_creator<dl1416t_device>;
+
+dl1416t_device::dl1416t_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : dl1416_device(mconfig, DL1416T, "DL1416T", tag, owner, clock)
+{
+}
diff --git a/src/emu/video/dl1416.h b/src/emu/video/dl1416.h
new file mode 100644
index 00000000000..e1ecf8f000a
--- /dev/null
+++ b/src/emu/video/dl1416.h
@@ -0,0 +1,90 @@
+/*****************************************************************************
+ *
+ * video/dl1416.h
+ *
+ * DL1416
+ *
+ * 4-Digit 16-Segment Alphanumeric Intelligent Display
+ * with Memory/Decoder/Driver
+ *
+ * See video/dl1416.c for more info
+ *
+ ****************************************************************************/
+
+#ifndef DL1416_H_
+#define DL1416_H_
+
+#include "devcb.h"
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef void (*dl1416_update_func)(device_t *device, int digit, int data);
+
+struct dl1416_interface
+{
+ dl1416_update_func update;
+};
+
+
+/***************************************************************************
+ DEVICE CONFIGURATION MACROS
+***************************************************************************/
+
+#define MCFG_DL1416B_ADD(_tag, _config) \
+ MCFG_DEVICE_ADD(_tag, DL1416B, 0) \
+ MCFG_DEVICE_CONFIG(_config)
+
+#define MCFG_DL1416T_ADD(_tag, _config) \
+ MCFG_DEVICE_ADD(_tag, DL1416T, 0) \
+ MCFG_DEVICE_CONFIG(_config)
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+/* inputs */
+WRITE_LINE_DEVICE_HANDLER( dl1416_wr_w ); /* write enable */
+WRITE_LINE_DEVICE_HANDLER( dl1416_ce_w ); /* chip enable */
+WRITE_LINE_DEVICE_HANDLER( dl1416_cu_w ); /* cursor enable */
+DECLARE_WRITE8_DEVICE_HANDLER( dl1416_data_w );
+
+/* device get info callback */
+class dl1416_device : public device_t
+{
+public:
+ dl1416_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock);
+ ~dl1416_device() { global_free(m_token); }
+
+ // access to legacy token
+ void *token() const { assert(m_token != NULL); return m_token; }
+protected:
+ // device-level overrides
+ virtual void device_config_complete();
+ virtual void device_start();
+ virtual void device_reset();
+private:
+ // internal state
+ void *m_token;
+};
+
+class dl1416b_device : public dl1416_device
+{
+public:
+ dl1416b_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+};
+
+extern const device_type DL1416B;
+
+class dl1416t_device : public dl1416_device
+{
+public:
+ dl1416t_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+};
+
+extern const device_type DL1416T;
+
+
+#endif /* DL1416_H_ */
diff --git a/src/emu/video/hd44352.c b/src/emu/video/hd44352.c
new file mode 100644
index 00000000000..9cd6142c9b1
--- /dev/null
+++ b/src/emu/video/hd44352.c
@@ -0,0 +1,456 @@
+/***************************************************************************
+
+ Hitachi HD44352 LCD controller
+
+***************************************************************************/
+
+#include "emu.h"
+#include "video/hd44352.h"
+
+#define LCD_BYTE_INPUT 0x01
+#define LCD_BYTE_OUTPUT 0x02
+#define LCD_CHAR_OUTPUT 0x03
+#define LCD_ON_OFF 0x04
+#define LCD_CURSOR_GRAPHIC 0x06
+#define LCD_CURSOR_CHAR 0x07
+#define LCD_SCROLL_CHAR_WIDTH 0x08
+#define LCD_CURSOR_STATUS 0x09
+#define LCD_USER_CHARACTER 0x0b
+#define LCD_CONTRAST 0x0c
+#define LCD_IRQ_FREQUENCY 0x0d
+#define LCD_CURSOR_POSITION 0x0e
+
+
+// devices
+const device_type HD44352 = &device_creator<hd44352_device>;
+
+//**************************************************************************
+// live device
+//**************************************************************************
+
+//-------------------------------------------------
+// hd44352_device - constructor
+//-------------------------------------------------
+
+hd44352_device::hd44352_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock):
+ device_t(mconfig, HD44352, "hd44352", tag, owner, clock)
+{
+}
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void hd44352_device::device_config_complete()
+{
+ // inherit a copy of the static data
+ const hd44352_interface *intf = reinterpret_cast<const hd44352_interface *>(static_config());
+ if (intf != NULL)
+ *static_cast<hd44352_interface *>(this) = *intf;
+
+ // or initialize to defaults if none provided
+ else
+ {
+ memset(&m_on, 0, sizeof(m_on));
+ }
+}
+
+//-------------------------------------------------
+// device_validity_check - perform validity checks
+// on this device
+//-------------------------------------------------
+
+void hd44352_device::device_validity_check(validity_checker &valid) const
+{
+}
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void hd44352_device::device_start()
+{
+ m_on.resolve(m_on_cb, *this);
+
+ m_on_timer = timer_alloc(ON_TIMER);
+ m_on_timer->adjust(attotime::from_hz(m_clock/16384), 0, attotime::from_hz(m_clock/16384));
+
+ save_item( NAME(m_control_lines));
+ save_item( NAME(m_data_bus));
+ save_item( NAME(m_state));
+ save_item( NAME(m_offset));
+ save_item( NAME(m_char_width));
+ save_item( NAME(m_bank));
+ save_item( NAME(m_lcd_on));
+ save_item( NAME(m_scroll));
+ save_item( NAME(m_contrast));
+ save_item( NAME(m_byte_count));
+ save_item( NAME(m_cursor_status));
+ save_item( NAME(m_cursor_x));
+ save_item( NAME(m_cursor_y));
+ save_item( NAME(m_cursor_lcd));
+ save_item( NAME(m_video_ram[0]));
+ save_item( NAME(m_video_ram[1]));
+ save_item( NAME(m_par));
+ save_item( NAME(m_cursor));
+ save_item( NAME(m_custom_char[0]));
+ save_item( NAME(m_custom_char[1]));
+ save_item( NAME(m_custom_char[2]));
+ save_item( NAME(m_custom_char[3]));
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void hd44352_device::device_reset()
+{
+ memset(m_video_ram, 0x00, sizeof(m_video_ram));
+ memset(m_par, 0x00, sizeof(m_par));
+ memset(m_custom_char, 0x00, sizeof(m_custom_char));
+ memset(m_cursor, 0x00, sizeof(m_cursor));
+ m_control_lines = 0;
+ m_data_bus = 0xff;
+ m_state = 0;
+ m_bank = 0;
+ m_offset = 0;
+ m_char_width = 6;
+ m_lcd_on = 0;
+ m_scroll = 0;
+ m_byte_count = 0;
+ m_cursor_status = 0;
+ m_cursor_x = 0;
+ m_cursor_y = 0;
+ m_cursor_lcd = 0;
+ m_contrast = 0;
+}
+
+
+//-------------------------------------------------
+// device_timer - handler timer events
+//-------------------------------------------------
+void hd44352_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+ switch(id)
+ {
+ case ON_TIMER:
+ if (m_control_lines & 0x40)
+ {
+ m_on(ASSERT_LINE);
+ m_on(CLEAR_LINE);
+ }
+ break;
+ }
+}
+
+//**************************************************************************
+// device interface
+//**************************************************************************
+
+UINT32 hd44352_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
+{
+ UINT8 cw = m_char_width;
+
+ bitmap.fill(0, cliprect);
+
+ if (m_control_lines&0x80 && m_lcd_on)
+ {
+ for (int a=0; a<2; a++)
+ for (int py=0; py<4; py++)
+ for (int px=0; px<16; px++)
+ if (BIT(m_cursor_status, 4) && px == m_cursor_x && py == m_cursor_y && a == m_cursor_lcd)
+ {
+ //draw the cursor
+ for (int c=0; c<cw; c++)
+ {
+ UINT8 d = compute_newval((m_cursor_status>>5) & 0x07, m_video_ram[a][py*16*cw + px*cw + c + m_scroll * 48], m_cursor[c]);
+ for (int b=0; b<8; b++)
+ {
+ bitmap.pix16(py*8 + b, a*cw*16 + px*cw + c) = BIT(d, 7-b);
+ }
+ }
+ }
+ else
+ {
+ for (int c=0; c<cw; c++)
+ {
+ UINT8 d = m_video_ram[a][py*16*cw + px*cw + c + m_scroll * 48];
+ for (int b=0; b<8; b++)
+ {
+ bitmap.pix16(py*8 + b, a*cw*16 + px*cw + c) = BIT(d, 7-b);
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+
+void hd44352_device::control_write(UINT8 data)
+{
+ if(m_control_lines == data)
+ m_state = 0;
+
+ m_control_lines = data;
+}
+
+UINT8 hd44352_device::compute_newval(UINT8 type, UINT8 oldval, UINT8 newval)
+{
+ switch(type & 0x07)
+ {
+ case 0x00:
+ return (~oldval) & newval;
+ case 0x01:
+ return oldval ^ newval;
+ case 0x03:
+ return oldval & (~newval);
+ case 0x04:
+ return newval;
+ case 0x05:
+ return oldval | newval;
+ case 0x07:
+ return oldval;
+ case 0x02:
+ case 0x06:
+ default:
+ return 0;
+ }
+}
+
+UINT8 hd44352_device::get_char(UINT16 pos)
+{
+ switch ((UINT8)pos/8)
+ {
+ case 0xcf:
+ return m_custom_char[0][pos%8];
+ case 0xdf:
+ return m_custom_char[1][pos%8];
+ case 0xef:
+ return m_custom_char[2][pos%8];
+ case 0xff:
+ return m_custom_char[3][pos%8];
+ default:
+ return region()->u8(pos);
+ }
+}
+
+void hd44352_device::data_write(UINT8 data)
+{
+ // verify that controller is active
+ if (!(m_control_lines&0x80))
+ return;
+
+ if (m_control_lines & 0x01)
+ {
+ if (!(m_control_lines&0x02) && !(m_control_lines&0x04))
+ return;
+
+ switch (m_state)
+ {
+ case 0: //parameter 0
+ m_par[m_state++] = data;
+ break;
+ case 1: //parameter 1
+ m_par[m_state++] = data;
+ break;
+ case 2: //parameter 2
+ m_par[m_state++] = data;
+ break;
+ }
+
+ switch (m_par[0] & 0x0f)
+ {
+ case LCD_BYTE_INPUT:
+ case LCD_CHAR_OUTPUT:
+ {
+ if (m_state == 1)
+ m_bank = BIT(data, 4);
+ else if (m_state == 2)
+ m_offset = ((data>>1)&0x3f) % 48 + (BIT(data,7) * 48);
+ else if (m_state == 3)
+ m_offset += ((data & 0x03) * 96);
+ }
+ break;
+ case LCD_BYTE_OUTPUT:
+ {
+ if (m_state == 1)
+ m_bank = BIT(data, 4);
+ else if (m_state == 2)
+ m_offset = ((data>>1)&0x3f) % 48 + (BIT(data,7) * 48);
+ else if (m_state == 3)
+ m_offset += ((data & 0x03) * 96);
+ }
+ break;
+ case LCD_ON_OFF:
+ {
+ if (m_state == 1)
+ m_lcd_on = BIT(data, 4);
+ m_data_bus = 0xff;
+ m_state = 0;
+ }
+ break;
+ case LCD_SCROLL_CHAR_WIDTH:
+ {
+ if (m_state == 1)
+ {
+ m_char_width = 8-((data>>4)&3);
+ m_scroll = ((data>>6)&3);
+ }
+
+ m_data_bus = 0xff;
+ m_state = 0;
+ }
+ break;
+ case LCD_CURSOR_STATUS:
+ {
+ if (m_state == 1)
+ m_cursor_status = data;
+ m_data_bus = 0xff;
+ m_state = 0;
+ }
+ break;
+ case LCD_CONTRAST:
+ {
+ if (m_state == 1)
+ m_contrast = (m_contrast & 0x00ffff) | (data<<16);
+ else if (m_state == 2)
+ m_contrast = (m_contrast & 0xff00ff) | (data<<8);
+ else if (m_state == 3)
+ {
+ m_contrast = (m_contrast & 0xffff00) | (data<<0);
+ m_state = 0;
+ }
+
+ m_data_bus = 0xff;
+ }
+ break;
+ case LCD_IRQ_FREQUENCY:
+ {
+ if (m_state == 1)
+ {
+ UINT32 on_timer_rate;
+
+ switch((data>>4) & 0x0f)
+ {
+ case 0x00: on_timer_rate = 16384; break;
+ case 0x01: on_timer_rate = 8; break;
+ case 0x02: on_timer_rate = 16; break;
+ case 0x03: on_timer_rate = 32; break;
+ case 0x04: on_timer_rate = 64; break;
+ case 0x05: on_timer_rate = 128; break;
+ case 0x06: on_timer_rate = 256; break;
+ case 0x07: on_timer_rate = 512; break;
+ case 0x08: on_timer_rate = 1024; break;
+ case 0x09: on_timer_rate = 2048; break;
+ case 0x0a: on_timer_rate = 4096; break;
+ case 0x0b: on_timer_rate = 4096; break;
+ default: on_timer_rate = 8192; break;
+ }
+
+ m_on_timer->adjust(attotime::from_hz(m_clock/on_timer_rate), 0, attotime::from_hz(m_clock/on_timer_rate));
+ }
+ m_data_bus = 0xff;
+ m_state = 0;
+ }
+ break;
+ case LCD_CURSOR_POSITION:
+ {
+ if (m_state == 1)
+ m_cursor_lcd = BIT(data, 4); //0:left lcd 1:right lcd;
+ else if (m_state == 2)
+ m_cursor_x = ((data>>1)&0x3f) % 48 + (BIT(data,7) * 48);
+ else if (m_state == 3)
+ {
+ m_cursor_y = data & 0x03;
+ m_state = 0;
+ }
+
+ m_data_bus = 0xff;
+ }
+ break;
+ }
+
+ m_byte_count = 0;
+ m_data_bus = 0xff;
+ }
+ else
+ {
+ switch (m_par[0] & 0x0f)
+ {
+ case LCD_BYTE_INPUT:
+ {
+ if (((m_par[0]>>5) & 0x07) != 0x03)
+ break;
+
+ m_offset %= 0x180;
+ m_data_bus = ((m_video_ram[m_bank][m_offset]<<4)&0xf0) | ((m_video_ram[m_bank][m_offset]>>4)&0x0f);
+ m_offset++; m_byte_count++;
+ }
+ break;
+ case LCD_BYTE_OUTPUT:
+ {
+ m_offset %= 0x180;
+ m_video_ram[m_bank][m_offset] = compute_newval((m_par[0]>>5) & 0x07, m_video_ram[m_bank][m_offset], data);
+ m_offset++; m_byte_count++;
+
+ m_data_bus = 0xff;
+ }
+ break;
+ case LCD_CHAR_OUTPUT:
+ {
+ int char_pos = data*8;
+
+ for (int i=0; i<m_char_width; i++)
+ {
+ m_offset %= 0x180;
+ m_video_ram[m_bank][m_offset] = compute_newval((m_par[0]>>5) & 0x07, m_video_ram[m_bank][m_offset], get_char(char_pos));
+ m_offset++; char_pos++;
+ }
+
+ m_byte_count++;
+ m_data_bus = 0xff;
+ }
+ break;
+ case LCD_CURSOR_GRAPHIC:
+ if (m_byte_count<8)
+ {
+ m_cursor[m_byte_count] = data;
+ m_byte_count++;
+ m_data_bus = 0xff;
+ }
+ break;
+ case LCD_CURSOR_CHAR:
+ if (m_byte_count<1)
+ {
+ UINT8 char_code = ((data<<4)&0xf0) | ((data>>4)&0x0f);
+
+ for (int i=0; i<8; i++)
+ m_cursor[i] = get_char(char_code*8 + i);
+
+ m_byte_count++;
+ m_data_bus = 0xff;
+ }
+ break;
+ case LCD_USER_CHARACTER:
+ if (m_byte_count<8)
+ {
+ m_custom_char[(m_par[1]&0x03)][m_byte_count] = data;
+ m_byte_count++;
+ m_data_bus = 0xff;
+ }
+ break;
+ default:
+ m_data_bus = 0xff;
+ }
+
+ m_state=0;
+ }
+}
+
+UINT8 hd44352_device::data_read()
+{
+ return m_data_bus;
+}
diff --git a/src/emu/video/hd44352.h b/src/emu/video/hd44352.h
new file mode 100644
index 00000000000..0a7fb4d7481
--- /dev/null
+++ b/src/emu/video/hd44352.h
@@ -0,0 +1,87 @@
+/***************************************************************************
+
+ Hitachi HD44352 LCD controller
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __hd44352_H__
+#define __hd44352_H__
+
+
+#define MCFG_HD44352_ADD( _tag, _clock, _config) \
+ MCFG_DEVICE_ADD( _tag, HD44352, _clock ) \
+ MCFG_DEVICE_CONFIG( _config )
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+
+// ======================> hd44352_interface
+
+struct hd44352_interface
+{
+ devcb_write_line m_on_cb; // ON line
+};
+
+// ======================> hd44352_device
+
+class hd44352_device :
+ public device_t,
+ public hd44352_interface
+{
+public:
+ // construction/destruction
+ hd44352_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device interface
+ UINT8 data_read();
+ void data_write(UINT8 data);
+ void control_write(UINT8 data);
+
+ UINT32 screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+ virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);
+ virtual void device_config_complete();
+ virtual void device_validity_check(validity_checker &valid) const;
+
+private:
+ UINT8 compute_newval(UINT8 type, UINT8 oldval, UINT8 newval);
+ UINT8 get_char(UINT16 pos);
+
+ static const device_timer_id ON_TIMER = 1;
+ emu_timer *m_on_timer;
+
+ UINT8 m_video_ram[2][0x180];
+ UINT8 m_control_lines;
+ UINT8 m_data_bus;
+ UINT8 m_par[3];
+ UINT8 m_state;
+ UINT16 m_bank;
+ UINT16 m_offset;
+ UINT8 m_char_width;
+ UINT8 m_lcd_on;
+ UINT8 m_scroll;
+ UINT32 m_contrast;
+
+ UINT8 m_custom_char[4][8]; // 4 chars * 8 bytes
+ UINT8 m_byte_count;
+ UINT8 m_cursor_status;
+ UINT8 m_cursor[8];
+ UINT8 m_cursor_x;
+ UINT8 m_cursor_y;
+ UINT8 m_cursor_lcd;
+
+ devcb_resolved_write_line m_on; // ON line callback
+};
+
+// device type definition
+extern const device_type HD44352;
+
+#endif
diff --git a/src/emu/video/hd44780.c b/src/emu/video/hd44780.c
new file mode 100644
index 00000000000..fe69a3cec1a
--- /dev/null
+++ b/src/emu/video/hd44780.c
@@ -0,0 +1,556 @@
+/***************************************************************************
+
+ Hitachi HD44780 LCD controller
+
+ TODO:
+ - dump internal CGROM
+
+***************************************************************************/
+
+#include "emu.h"
+#include "video/hd44780.h"
+
+#define LOG 0
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type HD44780 = &device_creator<hd44780_device>;
+const device_type KS0066_F05 = &device_creator<ks0066_f05_device>;
+
+
+//-------------------------------------------------
+// ROM( hd44780 )
+//-------------------------------------------------
+
+ROM_START( hd44780_a00 )
+ ROM_REGION( 0x1000, "cgrom", 0 )
+ ROM_LOAD( "hd44780_a00.bin", 0x0000, 0x1000, BAD_DUMP CRC(01d108e2) SHA1(bc0cdf0c9ba895f22e183c7bd35a3f655f2ca96f)) // from page 17 of the HD44780 datasheet
+ROM_END
+
+ROM_START( ks0066_f05 )
+ ROM_REGION( 0x1000, "cgrom", 0 )
+ ROM_LOAD( "ks0066_f05.bin", 0x0000, 0x1000, BAD_DUMP CRC(af9e7bd6) SHA1(0196e871584ee5d370856e7307c0f9d1466e3e51)) // from page 51 of the KS0066 datasheet
+ROM_END
+
+//**************************************************************************
+// live device
+//**************************************************************************
+
+//-------------------------------------------------
+// hd44780_device - constructor
+//-------------------------------------------------
+
+hd44780_device::hd44780_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, HD44780, "HD44780 A00", tag, owner, clock),
+ m_pixel_update_func(NULL)
+{
+ m_shortname = "hd44780_a00";
+ set_charset_type(CHARSET_HD44780_A00);
+}
+
+hd44780_device::hd44780_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, type, name, tag, owner, clock),
+ m_pixel_update_func(NULL)
+{
+}
+
+ks0066_f05_device::ks0066_f05_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ hd44780_device(mconfig, KS0066_F05, "KS0066 F05", tag, owner, clock)
+{
+ m_shortname = "ks0066_f05";
+ set_charset_type(CHARSET_KS0066_F05);
+}
+
+
+//-------------------------------------------------
+// rom_region - device-specific ROM region
+//-------------------------------------------------
+
+const rom_entry *hd44780_device::device_rom_region() const
+{
+ switch (m_charset_type)
+ {
+ case CHARSET_HD44780_A00: return ROM_NAME( hd44780_a00 );
+ case CHARSET_KS0066_F05: return ROM_NAME( ks0066_f05 );
+ }
+
+ return NULL;
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void hd44780_device::device_start()
+{
+ if (region())
+ m_cgrom = (UINT8*)(*region());
+ else
+ m_cgrom = (UINT8*)(*memregion("cgrom"));
+
+ m_busy_timer = timer_alloc(TIMER_BUSY);
+ m_blink_timer = timer_alloc(TIMER_BLINKING);
+ m_blink_timer->adjust(attotime::from_msec(409), 0, attotime::from_msec(409));
+
+ // state saving
+ save_item(NAME(m_busy_flag));
+ save_item(NAME(m_ac));
+ save_item(NAME(m_dr));
+ save_item(NAME(m_ir));
+ save_item(NAME(m_active_ram));
+ save_item(NAME(m_display_on));
+ save_item(NAME(m_cursor_on));
+ save_item(NAME(m_shift_on));
+ save_item(NAME(m_blink_on));
+ save_item(NAME(m_direction));
+ save_item(NAME(m_data_len));
+ save_item(NAME(m_num_line));
+ save_item(NAME(m_char_size));
+ save_item(NAME(m_disp_shift));
+ save_item(NAME(m_blink));
+ save_item(NAME(m_ddram));
+ save_item(NAME(m_cgram));
+ save_item(NAME(m_nibble));
+ save_item(NAME(m_rs_state));
+ save_item(NAME(m_rw_state));
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void hd44780_device::device_reset()
+{
+ memset(m_ddram, 0x20, sizeof(m_ddram)); // can't use 0 here as it would show CGRAM instead of blank space on a soft reset
+ memset(m_cgram, 0, sizeof(m_cgram));
+
+ m_ac = 0;
+ m_dr = 0;
+ m_ir = 0;
+ m_active_ram = DDRAM;
+ m_display_on = false;
+ m_cursor_on = false;
+ m_blink_on = false;
+ m_shift_on = false;
+ m_direction = 1;
+ m_data_len = 8;
+ m_num_line = 1;
+ m_char_size = 8;
+ m_disp_shift = 0;
+ m_blink = false;
+ m_nibble = false;
+ m_first_cmd = true;
+ m_rs_state = 0;
+ m_rw_state = 0;
+
+ set_busy_flag(1520);
+}
+
+
+//-------------------------------------------------
+// device_timer - handler timer events
+//-------------------------------------------------
+
+void hd44780_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+ switch(id)
+ {
+ case TIMER_BUSY:
+ m_busy_flag = false;
+ break;
+
+ case TIMER_BLINKING:
+ m_blink = !m_blink;
+ break;
+ }
+}
+
+
+//**************************************************************************
+// HELPERS
+//**************************************************************************
+
+void hd44780_device::set_charset_type(int type)
+{
+ m_charset_type = type;
+}
+
+void hd44780_device::set_busy_flag(UINT16 usec)
+{
+ m_busy_flag = true;
+ m_busy_timer->adjust( attotime::from_usec( usec ) );
+}
+
+void hd44780_device::update_ac(int direction)
+{
+ if (m_active_ram == DDRAM)
+ {
+ if(direction == 1)
+ {
+ if(m_num_line == 2 && m_ac == 0x27)
+ m_ac = 0x40;
+ else if((m_num_line == 2 && m_ac == 0x67) || (m_num_line == 1 && m_ac == 0x4f))
+ m_ac = 0x00;
+ else
+ m_ac = (m_ac + direction) & 0x7f;
+ }
+ else
+ {
+ if(m_num_line == 2 && m_ac == 0x00)
+ m_ac = 0x67;
+ else if(m_num_line == 1 && m_ac == 0x00)
+ m_ac = 0x4f;
+ else if(m_num_line == 2 && m_ac == 0x40)
+ m_ac = 0x27;
+ else
+ m_ac = (m_ac + direction) & 0x7f;
+ }
+ }
+ else
+ {
+ m_ac = (m_ac + direction) & 0x3f;
+ }
+}
+
+void hd44780_device::shift_display(int direction)
+{
+ if (direction == 1)
+ {
+ if(m_disp_shift == 0x4f)
+ m_disp_shift = 0x00;
+ else
+ m_disp_shift++;
+ }
+ else
+ {
+ if(m_disp_shift == 0x00)
+ m_disp_shift = 0x4f;
+ else
+ m_disp_shift--;
+ }
+}
+
+void hd44780_device::update_nibble(int rs, int rw)
+{
+ if (m_rs_state != rs || m_rw_state != rw)
+ {
+ m_rs_state = rs;
+ m_rw_state = rw;
+ m_nibble = false;
+ }
+
+ m_nibble = !m_nibble;
+}
+
+inline void hd44780_device::pixel_update(bitmap_ind16 &bitmap, UINT8 line, UINT8 pos, UINT8 y, UINT8 x, int state)
+{
+ if (m_pixel_update_func != NULL)
+ {
+ m_pixel_update_func(*this, bitmap, line, pos, y, x, state);
+ }
+ else
+ {
+ UINT8 line_heigh = (m_char_size == 8) ? m_char_size : m_char_size + 1;
+
+ if (m_lines <= 2)
+ {
+ if (pos < m_chars)
+ bitmap.pix16(line * (line_heigh+1) + y, pos * 6 + x) = state;
+ }
+ else if (m_lines <= 4)
+ {
+ if (pos < m_chars*2)
+ {
+ if (pos >= m_chars)
+ {
+ line += 2;
+ pos -= m_chars;
+ }
+
+ if (line < m_lines)
+ bitmap.pix16(line * (line_heigh+1) + y, pos * 6 + x) = state;
+ }
+ }
+ else
+ {
+ fatalerror("%s: use a custom callback for this LCD configuration (%d x %d)\n", tag(), m_lines, m_chars);
+ }
+ }
+}
+
+
+//**************************************************************************
+// device interface
+//**************************************************************************
+
+UINT32 hd44780_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
+{
+ bitmap.fill(0, cliprect);
+
+ if (m_display_on)
+ {
+ UINT8 line_size = 80 / m_num_line;
+
+ for (int line=0; line<m_num_line; line++)
+ {
+ for (int pos=0; pos<line_size; pos++)
+ {
+ UINT16 char_pos = line * 0x40 + ((pos + m_disp_shift) % line_size);
+
+ int char_base = 0;
+ if (m_ddram[char_pos] < 0x10)
+ {
+ // draw CGRAM characters
+ if (m_char_size == 8)
+ char_base = (m_ddram[char_pos] & 0x07) * 8;
+ else
+ char_base = ((m_ddram[char_pos]>>1) & 0x03) * 16;
+ }
+ else
+ {
+ // draw CGROM characters
+ char_base = m_ddram[char_pos] * 0x10;
+ }
+
+ for (int y=0; y<m_char_size; y++)
+ {
+ UINT8 * charset = (m_ddram[char_pos] < 0x10) ? m_cgram : m_cgrom;
+
+ for (int x=0; x<5; x++)
+ pixel_update(bitmap, line, pos, y, x, BIT(charset[char_base + y], 4 - x));
+ }
+
+ // if is the correct position draw cursor and blink
+ if (char_pos == m_ac)
+ {
+ // draw the cursor
+ UINT8 cursor_pos = (m_char_size == 8) ? m_char_size : m_char_size + 1;
+ if (m_cursor_on)
+ for (int x=0; x<5; x++)
+ pixel_update(bitmap, line, pos, cursor_pos - 1, x, 1);
+
+ if (!m_blink && m_blink_on)
+ for (int y=0; y<(cursor_pos - 1); y++)
+ for (int x=0; x<5; x++)
+ pixel_update(bitmap, line, pos, y, x, 1);
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+READ8_MEMBER(hd44780_device::read)
+{
+ switch(offset & 0x01)
+ {
+ case 0: return control_read(space, 0);
+ case 1: return data_read(space, 0);
+ }
+
+ return 0;
+}
+
+WRITE8_MEMBER(hd44780_device::write)
+{
+ switch(offset & 0x01)
+ {
+ case 0: control_write(space, 0, data); break;
+ case 1: data_write(space, 0, data); break;
+ }
+}
+
+WRITE8_MEMBER(hd44780_device::control_write)
+{
+ if (m_data_len == 4)
+ {
+ update_nibble(0, 0);
+
+ if (m_nibble)
+ {
+ m_ir = data & 0xf0;
+ return;
+ }
+ else
+ {
+ m_ir |= ((data>>4) & 0x0f);
+ }
+ }
+ else
+ {
+ m_ir = data;
+ }
+
+ if (BIT(m_ir, 7)) // set DDRAM address
+ {
+ m_active_ram = DDRAM;
+ m_ac = m_ir & 0x7f;
+ set_busy_flag(37);
+
+ if (LOG) logerror("HD44780 '%s': set DDRAM address %x\n", tag(), m_ac);
+ }
+ else if (BIT(m_ir, 6)) // set CGRAM address
+ {
+ m_active_ram = CGRAM;
+ m_ac = m_ir & 0x3f;
+ set_busy_flag(37);
+
+ if (LOG) logerror("HD44780 '%s': set CGRAM address %x\n", tag(), m_ac);
+ }
+ else if (BIT(m_ir, 5)) // function set
+ {
+ if (!m_first_cmd && m_data_len == (BIT(m_ir, 4) ? 8 : 4) && (m_char_size != (BIT(m_ir, 2) ? 10 : 8) || m_num_line != (BIT(m_ir, 3) + 1)))
+ {
+ logerror("HD44780 '%s': function set cannot be executed after other instructions unless the interface data length is changed\n", tag());
+ return;
+ }
+
+ m_char_size = BIT(m_ir, 2) ? 10 : 8;
+ m_data_len = BIT(m_ir, 4) ? 8 : 4;
+ m_num_line = BIT(m_ir, 3) + 1;
+ set_busy_flag(37);
+
+ if (LOG) logerror("HD44780 '%s': char size 5x%d, data len %d, lines %d\n", tag(), m_char_size, m_data_len, m_num_line);
+ return;
+ }
+ else if (BIT(m_ir, 4)) // cursor or display shift
+ {
+ int direct = (BIT(m_ir, 2)) ? +1 : -1;
+
+ if (LOG) logerror("HD44780 '%s': %s shift %d\n", tag(), BIT(m_ir, 3) ? "display" : "cursor", direct);
+
+ if (BIT(m_ir, 3))
+ shift_display(direct);
+ else
+ update_ac(direct);
+
+ set_busy_flag(37);
+ }
+ else if (BIT(m_ir, 3)) // display on/off control
+ {
+ m_display_on = BIT(m_ir, 2);
+ m_cursor_on = BIT(m_ir, 1);
+ m_blink_on = BIT(m_ir, 0);
+ set_busy_flag(37);
+
+ if (LOG) logerror("HD44780 '%s': display %d, cursor %d, blink %d\n", tag(), m_display_on, m_cursor_on, m_blink_on);
+ }
+ else if (BIT(m_ir, 2)) // entry mode set
+ {
+ m_direction = (BIT(m_ir, 1)) ? +1 : -1;
+ m_shift_on = BIT(m_ir, 0);
+ set_busy_flag(37);
+
+ if (LOG) logerror("HD44780 '%s': entry mode set: direction %d, shift %d\n", tag(), m_direction, m_shift_on);
+ }
+ else if (BIT(m_ir, 1)) // return home
+ {
+ if (LOG) logerror("HD44780 '%s': return home\n", tag());
+
+ m_ac = 0;
+ m_active_ram = DDRAM;
+ m_direction = 1;
+ m_disp_shift = 0;
+ set_busy_flag(1520);
+ }
+ else if (BIT(m_ir, 0)) // clear display
+ {
+ if (LOG) logerror("HD44780 '%s': clear display\n", tag());
+
+ m_ac = 0;
+ m_active_ram = DDRAM;
+ m_direction = 1;
+ m_disp_shift = 0;
+ memset(m_ddram, 0x20, sizeof(m_ddram));
+ set_busy_flag(1520);
+ }
+
+ m_first_cmd = false;
+}
+
+READ8_MEMBER(hd44780_device::control_read)
+{
+ if (m_data_len == 4)
+ {
+ if (!space.debugger_access())
+ update_nibble(0, 1);
+
+ if (m_nibble)
+ return (m_busy_flag ? 0x80 : 0) | (m_ac & 0x70);
+ else
+ return (m_ac<<4) & 0xf0;
+ }
+ else
+ {
+ return (m_busy_flag ? 0x80 : 0) | (m_ac & 0x7f);
+ }
+}
+
+WRITE8_MEMBER(hd44780_device::data_write)
+{
+ if (m_busy_flag)
+ {
+ logerror("HD44780 '%s': Ignoring data write %02x due of busy flag\n", tag(), data);
+ return;
+ }
+
+ if (m_data_len == 4)
+ {
+ update_nibble(1, 0);
+
+ if (m_nibble)
+ {
+ m_dr = data & 0xf0;
+ return;
+ }
+ else
+ {
+ m_dr |= ((data>>4) & 0x0f);
+ }
+ }
+ else
+ {
+ m_dr = data;
+ }
+
+ if (LOG) logerror("HD44780 '%s': %sRAM write %x %x '%c'\n", tag(), m_active_ram == DDRAM ? "DD" : "CG", m_ac, m_dr, isprint(m_dr) ? m_dr : '.');
+
+ if (m_active_ram == DDRAM)
+ m_ddram[m_ac] = m_dr;
+ else
+ m_cgram[m_ac] = m_dr;
+
+ update_ac(m_direction);
+ if (m_shift_on)
+ shift_display(m_direction);
+ set_busy_flag(41);
+}
+
+READ8_MEMBER(hd44780_device::data_read)
+{
+ UINT8 data = (m_active_ram == DDRAM) ? m_ddram[m_ac] : m_cgram[m_ac];
+
+ if (LOG) logerror("HD44780 '%s': %sRAM read %x %c\n", tag(), m_active_ram == DDRAM ? "DD" : "CG", m_ac, data);
+
+ if (m_data_len == 4)
+ {
+ if (!space.debugger_access())
+ update_nibble(1, 1);
+
+ if (m_nibble)
+ return data & 0xf0;
+ else
+ data = (data<<4) & 0xf0;
+ }
+
+ if (!space.debugger_access())
+ {
+ update_ac(m_direction);
+ set_busy_flag(41);
+ }
+
+ return data;
+}
diff --git a/src/emu/video/hd44780.h b/src/emu/video/hd44780.h
new file mode 100644
index 00000000000..9f6f5f84792
--- /dev/null
+++ b/src/emu/video/hd44780.h
@@ -0,0 +1,141 @@
+/***************************************************************************
+
+ Hitachi HD44780 LCD controller
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __HD44780_H__
+#define __HD44780_H__
+
+
+#define MCFG_HD44780_ADD( _tag ) \
+ MCFG_DEVICE_ADD( _tag, HD44780, 0 )
+
+#define MCFG_KS0066_F05_ADD( _tag ) \
+ MCFG_DEVICE_ADD( _tag, KS0066_F05, 0 )
+
+#define MCFG_HD44780_LCD_SIZE(_lines, _chars) \
+ hd44780_device::static_set_lcd_size(*device, _lines, _chars);
+
+#define MCFG_HD44780_PIXEL_UPDATE_CB(_cb) \
+ hd44780_device::static_set_pixel_update_cb(*device, _cb);
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+typedef void (*hd44780_pixel_update_func)(device_t &device, bitmap_ind16 &bitmap, UINT8 line, UINT8 pos, UINT8 y, UINT8 x, int state);
+#define HD44780_PIXEL_UPDATE(name) void name(device_t &device, bitmap_ind16 &bitmap, UINT8 line, UINT8 pos, UINT8 y, UINT8 x, int state)
+
+
+// ======================> hd44780_device
+
+class hd44780_device : public device_t
+{
+public:
+ // construction/destruction
+ hd44780_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ hd44780_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock);
+
+ // static configuration helpers
+ static void static_set_lcd_size(device_t &device, int _lines, int _chars) { hd44780_device &dev=downcast<hd44780_device &>(device); dev.m_lines = _lines; dev.m_chars = _chars; }
+ static void static_set_pixel_update_cb(device_t &device, hd44780_pixel_update_func _cb) { downcast<hd44780_device &>(device).m_pixel_update_func = _cb; }
+
+ // device interface
+ virtual DECLARE_WRITE8_MEMBER(write);
+ virtual DECLARE_READ8_MEMBER(read);
+ virtual DECLARE_WRITE8_MEMBER(control_write);
+ virtual DECLARE_READ8_MEMBER(control_read);
+ virtual DECLARE_WRITE8_MEMBER(data_write);
+ virtual DECLARE_READ8_MEMBER(data_read);
+ virtual UINT32 screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+ virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);
+
+ // optional information overrides
+ virtual const rom_entry *device_rom_region() const;
+
+ // charset
+ enum
+ {
+ CHARSET_HD44780_A00,
+ CHARSET_KS0066_F05,
+ /*
+ CHARSET_HD44780_A01,
+ CHARSET_HD44780_A02,
+ CHARSET_KS0066_F00,
+ CHARSET_KS0066_F03,
+ CHARSET_KS0066_F04,
+ CHARSET_KS0066_F06,
+ CHARSET_KS0066_F59,
+ */
+ };
+
+ void set_charset_type(int type);
+
+private:
+ // internal helper
+ void set_busy_flag(UINT16 usec);
+ void update_ac(int direction);
+ void update_nibble(int rs, int rw);
+ void shift_display(int direction);
+ void pixel_update(bitmap_ind16 &bitmap, UINT8 line, UINT8 pos, UINT8 y, UINT8 x, int state);
+
+ // internal state
+ static const device_timer_id TIMER_BUSY = 0;
+ static const device_timer_id TIMER_BLINKING = 1;
+
+ emu_timer * m_blink_timer;
+ emu_timer * m_busy_timer;
+
+ UINT8 m_lines; // number of lines
+ UINT8 m_chars; // chars for line
+ hd44780_pixel_update_func m_pixel_update_func; // pixel update callback
+
+ bool m_busy_flag; // busy flag
+ UINT8 m_ddram[0x80]; // internal display data RAM
+ UINT8 m_cgram[0x40]; // internal chargen RAM
+ UINT8 * m_cgrom; // internal chargen ROM
+ INT8 m_ac; // address counter
+ UINT8 m_dr; // data register
+ UINT8 m_ir; // instruction register
+ UINT8 m_active_ram; // DDRAM or CGRAM
+ bool m_display_on; // display on/off
+ bool m_cursor_on; // cursor on/off
+ bool m_blink_on; // blink on/off
+ bool m_shift_on; // shift on/off
+ UINT8 m_disp_shift; // display shift
+ INT8 m_direction; // auto increment/decrement
+ UINT8 m_data_len; // interface data length 4 or 8 bit
+ UINT8 m_num_line; // number of lines
+ UINT8 m_char_size; // char size 5x8 or 5x10
+ bool m_blink;
+ bool m_first_cmd;
+ int m_rs_state;
+ int m_rw_state;
+ bool m_nibble;
+ int m_charset_type;
+
+ enum { DDRAM, CGRAM };
+};
+
+// ======================> ks0066_f05_device
+
+class ks0066_f05_device : public hd44780_device
+{
+public:
+ // construction/destruction
+ ks0066_f05_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+};
+
+// device type definition
+extern const device_type HD44780;
+extern const device_type KS0066_F05;
+
+#endif
diff --git a/src/emu/video/hd66421.c b/src/emu/video/hd66421.c
new file mode 100644
index 00000000000..c3d81390c95
--- /dev/null
+++ b/src/emu/video/hd66421.c
@@ -0,0 +1,256 @@
+/*
+
+ Hitachi HD66421 LCD Controller/Driver
+
+ (c) 2001-2007 Tim Schuerewegen
+
+*/
+
+#include "emu.h"
+#include "hd66421.h"
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+#define LOG_LEVEL 1
+#define _logerror(level,x) do { if (LOG_LEVEL > level) logerror x; } while (0)
+
+#define HD66421_RAM_SIZE (HD66421_WIDTH * HD66421_HEIGHT / 4) // 2-bits per pixel
+
+// R0 - control register 1
+#define LCD_R0_RMW 0x80 // read-modify-write mode
+#define LCD_R0_DISP 0x40 // display on/off
+#define LCD_R0_STBY 0x20 // standby (internal operation and power circuit halt)
+#define LCD_R0_PWR 0x10
+#define LCD_R0_AMP 0x08
+#define LCD_R0_REV 0x04 // reverse
+#define LCD_R0_HOLT 0x02
+#define LCD_R0_ADC 0x01
+
+// R1 - control register 2
+#define LCD_R1_BIS1 0x80 // bias ratio (bit 1)
+#define LCD_R1_BIS0 0x40 // bias ratio (bit 0)
+#define LCD_R1_WLS 0x20
+#define LCD_R1_GRAY 0x10 // grayscale palette 4/32
+#define LCD_R1_DTY1 0x08 // display duty cycle (bit 1)
+#define LCD_R1_DTY0 0x04 // display duty cycle (bit 0)
+#define LCD_R1_INC 0x02
+#define LCD_R1_BLK 0x01 // blink function
+
+// register 0 to 16
+#define LCD_REG_CONTROL_1 0x00 // control register 1
+#define LCD_REG_CONTROL_2 0x01 // control register 2
+#define LCD_REG_ADDR_X 0x02 // x address register
+#define LCD_REG_ADDR_Y 0x03 // y address register
+#define LCD_REG_RAM 0x04 // display ram access register
+#define LCD_REG_START_Y 0x05 // display start line register
+#define LCD_REG_BLINK_START 0x06 // blink start line register
+#define LCD_REG_BLINK_END 0x07 // blink end line register
+#define LCD_REG_BLINK_1 0x08 // blink register 1
+#define LCD_REG_BLINK_2 0x09 // blink register 2
+#define LCD_REG_BLINK_3 0x0A // blink register 3
+#define LCD_REG_PARTIAL 0x0B // partial display block register
+#define LCD_REG_COLOR_1 0x0C // gray scale palette 1 (0,0)
+#define LCD_REG_COLOR_2 0x0D // gray scale palette 2 (0,1)
+#define LCD_REG_COLOR_3 0x0E // gray scale palette 3 (1,0)
+#define LCD_REG_COLOR_4 0x0F // gray scale palette 4 (1,1)
+#define LCD_REG_CONTRAST 0x10 // contrast control register
+#define LCD_REG_PLANE 0x11 // plane selection register
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+// devices
+const device_type HD66421 = &device_creator<hd66421_device>;
+
+
+// default address map
+static ADDRESS_MAP_START( hd66421, AS_0, 8, hd66421_device )
+ AM_RANGE(0x0000, HD66421_RAM_SIZE) AM_RAM
+ADDRESS_MAP_END
+
+//-------------------------------------------------
+// memory_space_config - return a description of
+// any address spaces owned by this device
+//-------------------------------------------------
+
+const address_space_config *hd66421_device::memory_space_config(address_spacenum spacenum) const
+{
+ return (spacenum == AS_0) ? &m_space_config : NULL;
+}
+
+
+//**************************************************************************
+// INLINE HELPERS
+//**************************************************************************
+
+//-------------------------------------------------
+// readbyte - read a byte at the given address
+//-------------------------------------------------
+
+inline UINT8 hd66421_device::readbyte(offs_t address)
+{
+ return space().read_byte(address);
+}
+
+
+//-------------------------------------------------
+// writebyte - write a byte at the given address
+//-------------------------------------------------
+
+inline void hd66421_device::writebyte(offs_t address, UINT8 data)
+{
+ space().write_byte(address, data);
+}
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// hd66421_device - constructor
+//-------------------------------------------------
+
+hd66421_device::hd66421_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, HD66421, "Hitachi HD66421 LCD Controller", tag, owner, clock),
+ device_memory_interface(mconfig, *this),
+ m_space_config("videoram", ENDIANNESS_LITTLE, 8, 17, 0, NULL, *ADDRESS_MAP_NAME(hd66421)),
+ m_cmd(0),
+ m_x(0),
+ m_y(0)
+{
+ for (int i = 0; i < 32; i++)
+ {
+ m_reg[i] = 0;
+ }
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void hd66421_device::device_start()
+{
+ // register for state saving
+ save_item(NAME(m_cmd));
+ save_item(NAME(m_reg));
+ save_item(NAME(m_x));
+ save_item(NAME(m_y));
+}
+
+READ8_MEMBER( hd66421_device::reg_idx_r )
+{
+ _logerror( 2, ("reg_idx_r\n"));
+ return m_cmd;
+}
+
+WRITE8_MEMBER( hd66421_device::reg_idx_w )
+{
+ _logerror( 2, ("reg_idx_w (%02X)\n", data));
+ m_cmd = data;
+}
+
+READ8_MEMBER( hd66421_device::reg_dat_r )
+{
+ _logerror( 2, ("reg_dat_r\n"));
+ return m_reg[m_cmd];
+}
+
+WRITE8_MEMBER( hd66421_device::reg_dat_w )
+{
+ _logerror( 2, ("reg_dat_w (%02X)\n", data));
+ m_reg[m_cmd] = data;
+
+ switch (m_cmd)
+ {
+ case LCD_REG_ADDR_X :
+ m_x = data;
+ break;
+
+ case LCD_REG_ADDR_Y :
+ m_y = data;
+ break;
+
+ case LCD_REG_RAM :
+ {
+ UINT8 r1;
+ writebyte(m_y * (HD66421_WIDTH / 4) + m_x, data);
+ r1 = m_reg[LCD_REG_CONTROL_2];
+ if (r1 & 0x02)
+ m_x++;
+ else
+ m_y++;
+
+ if (m_x >= (HD66421_WIDTH / 4))
+ {
+ m_x = 0;
+ m_y++;
+ }
+
+ if (m_y >= HD66421_HEIGHT)
+ m_y = 0;
+ }
+ break;
+ }
+}
+
+void hd66421_device::plot_pixel(bitmap_ind16 &bitmap, int x, int y, UINT32 color)
+{
+ bitmap.pix16(y, x) = (UINT16)color;
+}
+
+UINT32 hd66421_device::update_screen(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
+{
+ pen_t pen[4];
+
+ _logerror( 1, ("video_update_hd66421\n"));
+
+ // update palette
+ for (int i = 0; i < 4; i++)
+ {
+ double bright;
+ int temp;
+ temp = 31 - (m_reg[LCD_REG_COLOR_1 + i] - m_reg[LCD_REG_CONTRAST] + 0x03);
+ if (temp < 0) temp = 0;
+ if (temp > 31) temp = 31;
+ bright = 1.0 * temp / 31;
+ pen[i] = i;
+ #ifdef HD66421_BRIGHTNESS_DOES_NOT_WORK
+ palette_set_color(machine(), pen[i], 255 * bright, 255 * bright, 255 * bright);
+ #else
+ palette_set_pen_contrast(machine(), pen[i], bright);
+ #endif
+ }
+
+ // draw bitmap (bottom to top)
+ if (m_reg[0] & LCD_R0_DISP)
+ {
+ int x, y;
+ x = 0;
+ y = HD66421_HEIGHT - 1;
+
+ for (int i = 0; i < HD66421_RAM_SIZE; i++)
+ {
+ plot_pixel(bitmap, x++, y, pen[(readbyte(i) >> 6) & 3]);
+ plot_pixel(bitmap, x++, y, pen[(readbyte(i) >> 4) & 3]);
+ plot_pixel(bitmap, x++, y, pen[(readbyte(i) >> 2) & 3]);
+ plot_pixel(bitmap, x++, y, pen[(readbyte(i) >> 0) & 3]);
+ if (x >= HD66421_WIDTH)
+ {
+ x = 0;
+ y = y - 1;
+ }
+ }
+ }
+ else
+ {
+ rectangle rect(0, HD66421_WIDTH - 1, 0, HD66421_HEIGHT - 1);
+ bitmap.fill(get_white_pen(machine()), rect);
+ }
+
+ return 0;
+}
diff --git a/src/emu/video/hd66421.h b/src/emu/video/hd66421.h
new file mode 100644
index 00000000000..11a9dfa9b85
--- /dev/null
+++ b/src/emu/video/hd66421.h
@@ -0,0 +1,79 @@
+/***************************************************************************
+
+ Hitachi HD66421 LCD Controller
+
+ (c) 2001-2007 Tim Schuerewegen
+
+ ***************************************************************************/
+
+#pragma once
+
+#ifndef __HD66421_H__
+#define __HD66421_H__
+
+
+///*************************************************************************
+// MACROS / CONSTANTS
+///*************************************************************************
+
+//#define HD66421_BRIGHTNESS_DOES_NOT_WORK
+
+#define HD66421_WIDTH 160
+#define HD66421_HEIGHT 100
+
+
+/*----------- defined in video/hd66421.c -----------*/
+
+///*************************************************************************
+// INTERFACE CONFIGURATION MACROS
+///*************************************************************************
+
+#define MCFG_HD66421_ADD(_tag) \
+ MCFG_DEVICE_ADD(_tag, HD66421, 0)
+
+///*************************************************************************
+// TYPE DEFINITIONS
+///*************************************************************************
+
+// ======================> hd66421_device
+
+class hd66421_device : public device_t,
+ public device_memory_interface
+{
+public:
+ // construction/destruction
+ hd66421_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ DECLARE_READ8_MEMBER( reg_idx_r );
+ DECLARE_WRITE8_MEMBER( reg_idx_w );
+ DECLARE_READ8_MEMBER( reg_dat_r );
+ DECLARE_WRITE8_MEMBER( reg_dat_w );
+
+ UINT32 update_screen(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+
+ // device_config_memory_interface overrides
+ virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const;
+
+ // address space configurations
+ const address_space_config m_space_config;
+
+ inline UINT8 readbyte(offs_t address);
+ inline void writebyte(offs_t address, UINT8 data);
+
+ void plot_pixel(bitmap_ind16 &bitmap, int x, int y, UINT32 color);
+
+private:
+ UINT8 m_cmd, m_reg[32];
+ int m_x, m_y;
+};
+
+
+// device type definition
+extern const device_type HD66421;
+
+
+#endif
diff --git a/src/emu/video/mc6847.c b/src/emu/video/mc6847.c
new file mode 100644
index 00000000000..d89c8e2b27d
--- /dev/null
+++ b/src/emu/video/mc6847.c
@@ -0,0 +1,1732 @@
+/*********************************************************************
+
+ mc6847.c
+
+ Implementation of Motorola 6847 video hardware chip
+
+ Sources:
+ M6847 data sheet
+ M6847T1 info from Rainbow magazine (10/1986-12/1986)
+
+
+ AG AS INTEXT INV GM2 GM1 GM0
+ -- -- ------ --- --- --- ---
+ 0 0 0 0 X X X Internal Alphanumerics
+ 0 0 0 1 X X X Internal Alphanumerics Inverted
+ 0 0 1 0 X X X External Alphanumerics
+ 0 0 1 1 X X X External Alphanumerics Inverted
+ 0 1 0 X X X X Semigraphics 4
+ 0 1 1 X X X X Semigraphics 6
+ 1 X X X 0 0 0 Graphics CG1 (64x64x4) (16 bpr)
+ 1 X X X 0 0 1 Graphics RG1 (128x64x2) (16 bpr)
+ 1 X X X 0 1 0 Graphics CG2 (128x64x4) (32 bpr)
+ 1 X X X 0 1 1 Graphics RG2 (128x96x2) (16 bpr)
+ 1 X X X 1 0 0 Graphics CG3 (128x96x4) (32 bpr)
+ 1 X X X 1 0 1 Graphics RG3 (128x192x2) (16 bpr)
+ 1 X X X 1 1 0 Graphics CG6 (128x192x4) (32 bpr)
+ 1 X X X 1 1 1 Graphics RG6 (256x192x2) (32 bpr)
+
+ Note: The M6847 relies on an external source (typically a 6883 SAM chip)
+ to feed it bytes; so the BPR (bytes per row) figures are effectively
+ suggestions. Mismatching modes is responsible for the semigraphic modes
+ on the CoCo.
+
+ Timing: (source Motorola M6847 Manual, experimentation, SockMaster)
+
+ Horizontal Sync: Total Period: 228 clock cycles
+ @ CLK(0) + DHS_F - falling edge (high to low)
+ @ CLK(16.5) + DHS_R - rising edge (low to high)
+ @ CLK(42) - left border start
+ @ CLK(71.5) - body start
+ @ CLK(199.5) - right border start
+ @ CLK(228) + DHS_F - falling edge (high to low)
+ ...
+
+ Field Sync: Total Period 262*228 clock cycles
+ @ CLK(0) + DFS_F - falling edge (high to low)
+ @ CLK(32*228) + DFS_R - rising edge (low to high)
+ @ CLK(262*228) + DFS_F - falling edge (high to low) (262.5 for the M6847Y)
+
+ DHS_F: 550ns
+ DHS_R: 740ns
+ DFS_F: 520ns
+ DFS_R: 500ns
+
+ The M6847T1 is a later variant of the M6847 chip that implements lower
+ case support and some other nifty features. This chip is in the CoCo 2B.
+ I have not been able to find a pinout diagram for this chip so I am
+ assuming that the extra text modes on the CoCo 2B are activated by the
+ GM2-0 pins. This needs to be confirmed.
+
+ The MC6847 datasheet states that a scanline is 227.5 clock cycles,
+ but experimentation suggests that it is 228. The game "Dragon Fire"
+ has a fine tuned loop that runs in 57 clock cycles by the CPU's
+ reckoning (228 actual clock cycles) and would not function correctly
+ if skew existed. SockMaster has confirmed that scanlines are in
+ fact 228 clock cycles.
+
+**********************************************************************/
+
+
+#include "emu.h"
+#include "video/mc6847.h"
+
+
+//**************************************************************************
+// CONSTANTS
+//**************************************************************************
+
+#define TOP_BORDER 25
+#define USE_HORIZONTAL_CLIP false
+
+#define TIMER_HSYNC_PERIOD (228)
+#define TIMER_HSYNC_OFF_TIME (10.0)
+#define TIMER_HSYNC_ON_TIME (TIMER_HSYNC_OFF_TIME + 16.5)
+#define TIMER_FSYNC_OFF_TIME (TIMER_HSYNC_PERIOD * TOP_BORDER + TIMER_HSYNC_ON_TIME)
+#define TIMER_FSYNC_ON_TIME (TIMER_HSYNC_PERIOD * (TOP_BORDER + 192) + TIMER_HSYNC_ON_TIME)
+
+#define LOG_SCANLINE 0
+#define LOG_HSYNC 0
+#define LOG_FSYNC 1
+#define LOG_FLUSH 1
+#define LOG_INPUT 0
+
+
+const UINT32 mc6847_base_device::s_palette[mc6847_base_device::PALETTE_LENGTH] =
+{
+ MAKE_RGB(0x07, 0xff, 0x00), /* GREEN */
+ MAKE_RGB(0xff, 0xff, 0x00), /* YELLOW */
+ MAKE_RGB(0x3b, 0x08, 0xff), /* BLUE */
+ MAKE_RGB(0xcc, 0x00, 0x3b), /* RED */
+ MAKE_RGB(0xff, 0xff, 0xff), /* BUFF */
+ MAKE_RGB(0x07, 0xe3, 0x99), /* CYAN */
+ MAKE_RGB(0xff, 0x1c, 0xff), /* MAGENTA */
+ MAKE_RGB(0xff, 0x81, 0x00), /* ORANGE */
+
+ MAKE_RGB(0x00, 0x00, 0x00), /* BLACK */
+ MAKE_RGB(0x07, 0xff, 0x00), /* GREEN */
+ MAKE_RGB(0x00, 0x00, 0x00), /* BLACK */
+ MAKE_RGB(0xff, 0xff, 0xff), /* BUFF */
+
+ MAKE_RGB(0x00, 0x7c, 0x00), /* ALPHANUMERIC DARK GREEN */
+ MAKE_RGB(0x07, 0xff, 0x00), /* ALPHANUMERIC BRIGHT GREEN */
+ MAKE_RGB(0x91, 0x00, 0x00), /* ALPHANUMERIC DARK ORANGE */
+ MAKE_RGB(0xff, 0x81, 0x00) /* ALPHANUMERIC BRIGHT ORANGE */
+};
+
+
+
+//**************************************************************************
+// FRIEND DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// ctor
+//-------------------------------------------------
+
+mc6847_friend_device::mc6847_friend_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock,
+ const UINT8 *fontdata, bool is_mc6847t1, double tpfs, int field_sync_falling_edge_scanline, bool supports_partial_body_scanlines)
+ : device_t(mconfig, type, name, tag, owner, clock),
+ m_character_map(fontdata, is_mc6847t1)
+{
+ m_tpfs = tpfs;
+ m_supports_partial_body_scanlines = supports_partial_body_scanlines;
+
+ // The MC6847 and the GIME apply field sync on different scanlines
+ m_field_sync_falling_edge_scanline = field_sync_falling_edge_scanline;
+}
+
+
+
+//-------------------------------------------------
+// setup_timer - sets up a single timer relative
+// to the clock
+//-------------------------------------------------
+
+ATTR_FORCE_INLINE emu_timer *mc6847_friend_device::setup_timer(device_timer_id id, double offset, double period)
+{
+ emu_timer *timer = timer_alloc(id);
+ timer->adjust(
+ attotime::from_ticks(offset * 4, m_clock * 4),
+ 0,
+ attotime::from_ticks(period * 4, m_clock * 4));
+ return timer;
+}
+
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void mc6847_friend_device::device_start(void)
+{
+ /* create the timers */
+ m_frame_timer = setup_timer( TIMER_FRAME, 0, m_tpfs * TIMER_HSYNC_PERIOD);
+ m_hsync_on_timer = setup_timer( TIMER_HSYNC_ON, TIMER_HSYNC_ON_TIME, TIMER_HSYNC_PERIOD);
+ m_hsync_off_timer = setup_timer(TIMER_HSYNC_OFF, TIMER_HSYNC_OFF_TIME, TIMER_HSYNC_PERIOD);
+ m_fsync_timer = timer_alloc(TIMER_FSYNC);
+
+ m_top_border_scanlines = 0;
+ m_body_scanlines = 0;
+ m_wide = false;
+ m_recording_scanline = false;
+ m_physical_scanline = 0;
+ m_logical_scanline_zone = 0;
+ m_field_sync = false;
+ m_horizontal_sync = false;
+ set_geometry(25, 192, false);
+
+ /* save states */
+ save_item(NAME(m_physical_scanline));
+ save_item(NAME(m_logical_scanline));
+ save_item(NAME(m_logical_scanline_zone));
+ save_item(NAME(m_horizontal_sync));
+ save_item(NAME(m_field_sync));
+
+ /* artifacting */
+ m_artifacter.setup_config(this);
+}
+
+
+
+//-------------------------------------------------
+// device_start - device-specific reset
+//-------------------------------------------------
+
+void mc6847_friend_device::device_reset(void)
+{
+ device_t::device_reset();
+ m_video_changed = true;
+}
+
+
+
+//-------------------------------------------------
+// device_post_load - device-specific post load
+//-------------------------------------------------
+
+void mc6847_friend_device::device_post_load(void)
+{
+ device_t::device_post_load();
+ m_video_changed = true;
+}
+
+
+
+//-------------------------------------------------
+// update_field_sync_timer
+//-------------------------------------------------
+
+void mc6847_friend_device::update_field_sync_timer(void)
+{
+ /* are we expecting field sync? */
+ bool expected_field_sync = (m_physical_scanline < m_field_sync_falling_edge_scanline)
+ || (m_logical_scanline_zone == SCANLINE_ZONE_VBLANK);
+
+ /* determine the duration */
+ attotime duration = (expected_field_sync != m_field_sync) ? attotime::from_ticks(160, m_clock) : attotime::never;
+
+ /* and reset the timer */
+ m_fsync_timer->adjust(duration, expected_field_sync ? 1 : 0);
+}
+
+
+
+//-------------------------------------------------
+// device_timer
+//-------------------------------------------------
+
+void mc6847_friend_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+ switch(id)
+ {
+ case TIMER_FRAME: new_frame(); break;
+ case TIMER_HSYNC_ON: change_horizontal_sync(true); break;
+ case TIMER_HSYNC_OFF: change_horizontal_sync(false); break;
+ case TIMER_FSYNC: change_field_sync(param != 0); break;
+ }
+}
+
+
+
+//-------------------------------------------------
+// new_frame
+//-------------------------------------------------
+
+ATTR_FORCE_INLINE void mc6847_friend_device::new_frame(void)
+{
+ m_physical_scanline = 0;
+ m_logical_scanline = 0;
+ m_logical_scanline_zone = SCANLINE_ZONE_FRAME_END;
+}
+
+
+
+//-------------------------------------------------
+// scanline_zone_string
+//-------------------------------------------------
+
+const char *mc6847_friend_device::scanline_zone_string(scanline_zone zone)
+{
+ const char *result;
+ switch(zone)
+ {
+ case SCANLINE_ZONE_TOP_BORDER: result = "SCANLINE_ZONE_TOP_BORDER"; break;
+ case SCANLINE_ZONE_BODY: result = "SCANLINE_ZONE_BODY"; break;
+ case SCANLINE_ZONE_BOTTOM_BORDER: result = "SCANLINE_ZONE_BOTTOM_BORDER"; break;
+ case SCANLINE_ZONE_RETRACE: result = "SCANLINE_ZONE_RETRACE"; break;
+ case SCANLINE_ZONE_VBLANK: result = "SCANLINE_ZONE_VBLANK"; break;
+ case SCANLINE_ZONE_FRAME_END: result = "SCANLINE_ZONE_FRAME_END"; break;
+ default:
+ fatalerror("Should not get here\n");
+ break;
+ }
+ return result;
+}
+
+
+
+//-------------------------------------------------
+// change_horizontal_sync
+//-------------------------------------------------
+
+ATTR_FORCE_INLINE void mc6847_friend_device::change_horizontal_sync(bool line)
+{
+ g_profiler.start(PROFILER_USER1);
+ if (line && !m_horizontal_sync)
+ {
+ if (LOG_SCANLINE)
+ logerror("%s: change_horizontal_sync(): Recording scanline\n", describe_context());
+
+ /* first store the scanline */
+ g_profiler.start(PROFILER_USER2);
+ switch((scanline_zone) m_logical_scanline_zone)
+ {
+ case SCANLINE_ZONE_TOP_BORDER:
+ case SCANLINE_ZONE_BOTTOM_BORDER:
+ record_border_scanline(m_physical_scanline);
+ break;
+
+ case SCANLINE_ZONE_BODY:
+ m_recording_scanline = true;
+ if (m_partial_scanline_clocks > 0)
+ record_partial_body_scanline(m_physical_scanline, m_logical_scanline, m_partial_scanline_clocks, 228);
+ else
+ record_body_scanline(m_physical_scanline, m_logical_scanline);
+ m_recording_scanline = false;
+ break;
+
+ case SCANLINE_ZONE_RETRACE:
+ case SCANLINE_ZONE_VBLANK:
+ case SCANLINE_ZONE_FRAME_END:
+ /* do nothing */
+ break;
+ }
+ g_profiler.stop();
+
+ /* advance to next scanline */
+ next_scanline();
+ }
+
+ /* finally output horizontal sync */
+ if (line != m_horizontal_sync)
+ {
+ m_horizontal_sync = line;
+
+ /* log if apprpriate */
+ if (LOG_HSYNC)
+ logerror("%s: change_horizontal_sync(): line=%d\n", describe_context(), line ? 1 : 0);
+
+ /* invoke callback */
+ if (!m_res_out_hsync_func.isnull())
+ m_res_out_hsync_func(line);
+
+ /* call virtual function */
+ horizontal_sync_changed(m_horizontal_sync);
+ }
+
+ /* and update the field sync timer */
+ update_field_sync_timer();
+ g_profiler.stop();
+}
+
+
+
+//-------------------------------------------------
+// change_field_sync
+//-------------------------------------------------
+
+ATTR_FORCE_INLINE void mc6847_friend_device::change_field_sync(bool line)
+{
+ /* output field sync */
+ if (line != m_field_sync)
+ {
+ m_field_sync = line;
+
+ /* log if apprpriate */
+ if (LOG_FSYNC)
+ logerror("%s: change_field_sync(): line=%d\n", describe_context(), line ? 1 : 0);
+
+ /* invoke callback */
+ if (!m_res_out_fsync_func.isnull())
+ m_res_out_fsync_func(line);
+
+ /* call virtual function */
+ field_sync_changed(m_field_sync);
+ }
+}
+
+
+
+//-------------------------------------------------
+// next_scanline
+//-------------------------------------------------
+
+ATTR_FORCE_INLINE void mc6847_friend_device::next_scanline(void)
+{
+ /* advance to next scanline */
+ m_physical_scanline++;
+ m_logical_scanline++;
+ m_partial_scanline_clocks = 0;
+
+ /* check for movement into the next "zone" */
+ if (m_logical_scanline_zone == SCANLINE_ZONE_FRAME_END)
+ {
+ /* we're now in the top border */
+ m_logical_scanline = 0;
+ m_logical_scanline_zone = SCANLINE_ZONE_TOP_BORDER;
+ }
+ else if ((m_logical_scanline_zone < SCANLINE_ZONE_VBLANK) && (m_physical_scanline >= 25+192+26+6))
+ {
+ /* we're now into vblank */
+ m_logical_scanline = 0;
+ m_logical_scanline_zone = SCANLINE_ZONE_VBLANK;
+ }
+ else if ((m_logical_scanline_zone < SCANLINE_ZONE_RETRACE) && (m_physical_scanline >= 25+192+26))
+ {
+ /* we're now into retrace */
+ m_logical_scanline = 0;
+ m_logical_scanline_zone = SCANLINE_ZONE_RETRACE;
+ }
+ else if ((m_logical_scanline_zone == SCANLINE_ZONE_TOP_BORDER) && (m_logical_scanline >= m_top_border_scanlines))
+ {
+ /* we're now into the body */
+ m_logical_scanline = 0;
+ m_logical_scanline_zone = SCANLINE_ZONE_BODY;
+ }
+ else if ((m_logical_scanline_zone == SCANLINE_ZONE_BODY) && (m_logical_scanline >= m_body_scanlines))
+ {
+ /* we're now into the bottom border */
+ m_logical_scanline = 0;
+ m_logical_scanline_zone = SCANLINE_ZONE_BOTTOM_BORDER;
+ enter_bottom_border();
+ }
+}
+
+
+
+//-------------------------------------------------
+// horizontal_sync_changed
+//-------------------------------------------------
+
+void mc6847_friend_device::horizontal_sync_changed(bool line)
+{
+}
+
+
+
+//-------------------------------------------------
+// field_sync_changed
+//-------------------------------------------------
+
+void mc6847_friend_device::field_sync_changed(bool line)
+{
+}
+
+
+
+//-------------------------------------------------
+// enter_bottom_border
+//-------------------------------------------------
+
+void mc6847_friend_device::enter_bottom_border(void)
+{
+}
+
+
+
+//-------------------------------------------------
+// record_border_scanline
+//-------------------------------------------------
+
+void mc6847_friend_device::record_border_scanline(UINT16 physical_scanline)
+{
+}
+
+
+
+//-------------------------------------------------
+// get_clocks_since_hsync
+//-------------------------------------------------
+
+INT32 mc6847_friend_device::get_clocks_since_hsync()
+{
+ UINT64 hsync_on_clocks = attotime_to_clocks(m_hsync_on_timer->start());
+ UINT64 current_clocks = attotime_to_clocks(machine().time());
+ return (INT32) (current_clocks - hsync_on_clocks);
+}
+
+
+
+//-------------------------------------------------
+// video_flush
+//-------------------------------------------------
+
+void mc6847_friend_device::video_flush()
+{
+ // first, only flush if...
+ // 1. We support partial scanlines
+ // 2. We're not already recording
+ // 3. We're in the body
+ if (m_supports_partial_body_scanlines && !m_recording_scanline && (m_logical_scanline_zone == SCANLINE_ZONE_BODY))
+ {
+ UINT32 new_partial_scanline_clocks = get_clocks_since_hsync();
+ if (m_partial_scanline_clocks < new_partial_scanline_clocks)
+ {
+ if (LOG_FLUSH)
+ logerror("%s: new_partial_scanline_clocks=%u\n", describe_context(), new_partial_scanline_clocks);
+
+ m_recording_scanline = true;
+ record_partial_body_scanline(m_physical_scanline, m_logical_scanline, m_partial_scanline_clocks, new_partial_scanline_clocks);
+ m_recording_scanline = false;
+
+ m_partial_scanline_clocks = new_partial_scanline_clocks;
+ }
+ }
+}
+
+
+
+//-------------------------------------------------
+// describe_context
+//-------------------------------------------------
+
+const char *mc6847_friend_device::describe_context(void)
+{
+ static char buffer[128];
+ snprintf(buffer, ARRAY_LENGTH(buffer), "%s (scanline %s:%d)",
+ machine().describe_context(),
+ scanline_zone_string((scanline_zone) m_logical_scanline_zone),
+ m_logical_scanline);
+ return buffer;
+}
+
+
+
+//**************************************************************************
+// BASE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// ctor
+//-------------------------------------------------
+
+mc6847_base_device::mc6847_base_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const UINT8 *fontdata, double tpfs)
+ : mc6847_friend_device(mconfig, type, name, tag, owner, clock, fontdata, (type == MC6847T1_NTSC) || (type == MC6847T1_PAL), tpfs, 25+191, true)
+{
+ m_palette = s_palette;
+
+ for (int i = 0; i < ARRAY_LENGTH(s_palette); i++)
+ {
+ m_bw_palette[i] = black_and_white(s_palette[i]);
+ }
+}
+
+
+
+//-------------------------------------------------
+// setup_fixed_mode - sets up a particular video
+// mode bit with a decb callback
+//-------------------------------------------------
+
+void mc6847_base_device::setup_fixed_mode(struct devcb_read_line callback, UINT8 mode)
+{
+ if (callback.type == DEVCB_TYPE_NULL)
+ {
+ // do nothing
+ }
+ else if (callback.type == DEVCB_TYPE_CONSTANT && (callback.index == 0 || callback.index == 1))
+ {
+ // this mode is fixed
+ m_fixed_mode |= (callback.index ? mode : 0x00);
+ m_fixed_mode_mask |= mode;
+ }
+ else
+ {
+ // for reasons of performance, we currently only support DEVCB_NULL,
+ // DEVCB_LINE_GND and DEVCB_LINE_VCC
+ emu_fatalerror("mc6847 does not support this callback type for mode bits\n");
+ }
+}
+
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void mc6847_base_device::device_start()
+{
+ const mc6847_interface *config = (const mc6847_interface *) static_config();
+ assert(config);
+
+ /* inherited function */
+ mc6847_friend_device::device_start();
+
+ /* setup */
+ memset(m_data, 0, sizeof(m_data));
+
+ /* resolve callbacks */
+ m_res_input_func.resolve(config->m_input_func, *this);
+ m_res_out_hsync_func.resolve(config->m_out_hsync_func, *this);
+ m_res_out_fsync_func.resolve(config->m_out_fsync_func, *this);
+ m_get_char_rom = config->m_get_char_rom;
+
+ /* set up fixed mode */
+ m_fixed_mode = 0x00;
+ m_fixed_mode_mask = 0x00;
+ setup_fixed_mode(config->m_in_gm2_func, MODE_GM2);
+ setup_fixed_mode(config->m_in_gm1_func, MODE_GM1);
+ setup_fixed_mode(config->m_in_gm0_func, MODE_GM0);
+ setup_fixed_mode(config->m_in_intext_func, MODE_INTEXT);
+ setup_fixed_mode(config->m_in_inv_func, MODE_INV);
+ setup_fixed_mode(config->m_in_as_func, MODE_AS);
+ setup_fixed_mode(config->m_in_ag_func, MODE_AG);
+ setup_fixed_mode(config->m_in_css_func, MODE_CSS);
+
+ m_dirty = false;
+
+ /* state save */
+ save_item(NAME(m_dirty));
+ save_item(NAME(m_mode));
+
+ /* colors */
+ m_palette = config->m_black_and_white ? m_bw_palette : s_palette;
+}
+
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void mc6847_base_device::device_reset()
+{
+ mc6847_friend_device::device_reset();
+ m_mode = m_fixed_mode;
+}
+
+
+
+//-------------------------------------------------
+// input
+//-------------------------------------------------
+
+UINT8 mc6847_base_device::input(UINT16 address)
+{
+ UINT8 data = m_res_input_func(address);
+ if (LOG_INPUT)
+ logerror("%s: input: address=0x%04X data=0x%02X\n", describe_context(), address, data);
+ return data;
+}
+
+
+
+//-------------------------------------------------
+// record_scanline_res
+//-------------------------------------------------
+
+template<int sample_count, int yres>
+void mc6847_base_device::record_scanline_res(int scanline, INT32 start_pos, INT32 end_pos)
+{
+ UINT8 current_sample_count = (start_pos > 0) ? m_data[scanline].m_sample_count : 0;
+
+ // main loop
+ for (INT32 pos = start_pos; pos < end_pos; pos++)
+ {
+ // set address at beginning of line
+ if (pos == 0)
+ m_video_address = scanline / (192 / yres) * sample_count;
+
+ if ((sample_count == 32) || ((pos % 1) == 0))
+ {
+ // input data
+ UINT8 data = input(m_video_address++);
+
+ if (pos < 32)
+ {
+ // update values
+ //assert(current_sample_count >= 0);
+ assert(current_sample_count < ARRAY_LENGTH(m_data[scanline].m_mode));
+ update_value(&m_data[scanline].m_mode[current_sample_count], simplify_mode(data, m_mode));
+ update_value(&m_data[scanline].m_data[current_sample_count], data);
+ current_sample_count++;
+ }
+ }
+ }
+
+ // update sample count
+ update_value(&m_data[scanline].m_sample_count, current_sample_count);
+}
+
+
+
+//-------------------------------------------------
+// record_body_scanline
+//-------------------------------------------------
+
+ATTR_FORCE_INLINE void mc6847_base_device::record_body_scanline(UINT16 physical_scanline, UINT16 scanline, INT32 start_pos, INT32 end_pos)
+{
+ // sanity checks
+ assert(scanline < 192);
+
+ if (m_mode & MODE_AG)
+ {
+ switch(m_mode & (MODE_GM2|MODE_GM1|MODE_GM0))
+ {
+ case 0:
+ case MODE_GM0:
+ record_scanline_res<16, 64>(scanline, start_pos, end_pos);
+ break;
+
+ case MODE_GM1:
+ record_scanline_res<32, 64>(scanline, start_pos, end_pos);
+ break;
+
+ case MODE_GM1|MODE_GM0:
+ record_scanline_res<16, 96>(scanline, start_pos, end_pos);
+ break;
+
+ case MODE_GM2:
+ record_scanline_res<32, 96>(scanline, start_pos, end_pos);
+ break;
+
+ case MODE_GM2|MODE_GM0:
+ record_scanline_res<16, 192>(scanline, start_pos, end_pos);
+ break;
+
+ case MODE_GM2|MODE_GM1:
+ case MODE_GM2|MODE_GM1|MODE_GM0:
+ record_scanline_res<32, 192>(scanline, start_pos, end_pos);
+ break;
+
+ default:
+ /* should not get here */
+ fatalerror("should not get here\n");
+ break;
+ }
+ }
+ else
+ {
+ record_scanline_res<32, 16>(scanline, start_pos, end_pos);
+ }
+}
+
+
+
+//-------------------------------------------------
+// record_body_scanline
+//-------------------------------------------------
+
+void mc6847_base_device::record_body_scanline(UINT16 physical_scanline, UINT16 scanline)
+{
+ record_body_scanline(physical_scanline, scanline, 0, 32);
+}
+
+
+
+//-------------------------------------------------
+// record_partial_body_scanline
+//-------------------------------------------------
+
+void mc6847_base_device::record_partial_body_scanline(UINT16 physical_scanline, UINT16 scanline, INT32 start_clock, INT32 end_clock)
+{
+ INT32 start_pos = MAX(scanline_position_from_clock(start_clock), 0);
+ INT32 end_pos = MIN(scanline_position_from_clock(end_clock), 42);
+
+ if (start_pos < end_pos)
+ record_body_scanline(physical_scanline, scanline, start_pos, end_pos);
+}
+
+
+
+//-------------------------------------------------
+// scanline_position_from_clock
+//-------------------------------------------------
+
+INT32 mc6847_base_device::scanline_position_from_clock(INT32 clocks_since_hsync)
+{
+ return (clocks_since_hsync - 20) / 4;
+}
+
+
+
+//-------------------------------------------------
+// field_sync_changed
+//-------------------------------------------------
+
+void mc6847_base_device::field_sync_changed(bool line)
+{
+ /* when field sync is on, the DA* enter the Hi-Z state */
+ if (line && !m_res_input_func.isnull())
+ m_res_input_func(~0);
+}
+
+
+
+//-------------------------------------------------
+// border_value
+//-------------------------------------------------
+
+ATTR_FORCE_INLINE mc6847_base_device::pixel_t mc6847_base_device::border_value(UINT8 mode, const pixel_t *palette, bool is_mc6847t1)
+{
+ pixel_t result;
+ switch(mc6847_friend_device::border_value(mode, is_mc6847t1))
+ {
+ case BORDER_COLOR_BLACK:
+ result = palette[8];
+ break;
+ case BORDER_COLOR_GREEN:
+ result = palette[0];
+ break;
+ case BORDER_COLOR_WHITE:
+ result = palette[4];
+ break;
+ case BORDER_COLOR_ORANGE:
+ result = palette[7];
+ break;
+ default:
+ fatalerror("Should not get here\n");
+ break;
+ }
+ return result;
+}
+
+
+
+//-------------------------------------------------
+// update
+//-------------------------------------------------
+
+UINT32 mc6847_base_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
+{
+ int base_x = 32;
+ int base_y = 25;
+ int x, x2, y;
+ bool is_mc6847t1 = (type() == MC6847T1_NTSC) || (type() == MC6847T1_PAL);
+ int min_x = USE_HORIZONTAL_CLIP ? cliprect.min_x : 0;
+ int max_x = USE_HORIZONTAL_CLIP ? cliprect.max_x : (base_x * 2 + 256 - 1);
+ int min_y = cliprect.min_y;
+ int max_y = cliprect.max_y;
+ const pixel_t *palette = m_palette;
+
+ /* if the video didn't change, indicate as much */
+ if (!has_video_changed())
+ return UPDATE_HAS_NOT_CHANGED;
+
+ /* top border */
+ for (y = min_y; y < base_y; y++)
+ {
+ for (x = min_x; x <= max_x; x++)
+ {
+ *bitmap_addr(bitmap, y, x) = border_value(m_data[0].m_mode[0], palette, is_mc6847t1);
+ }
+ }
+
+ for (y = MAX(0, min_y - base_y); y <= MIN(192, max_y - base_y); y++)
+ {
+ /* left border */
+ for (x = min_x; x < base_x; x++)
+ {
+ *bitmap_addr(bitmap, y + base_y, x) = border_value(m_data[y].m_mode[0], palette, is_mc6847t1);
+ }
+
+ /* body */
+ x = 0;
+ int width = m_data[y].m_sample_count;
+ pixel_t *RESTRICT pixels = bitmap_addr(bitmap, base_y + y, base_x);
+ while(x < width)
+ {
+ /* determine how many bytes exist for which the mode is identical */
+ for (x2 = x + 1; (x2 < width) && (m_data[y].m_mode[x] == m_data[y].m_mode[x2]); x2++)
+ ;
+
+ /* emit the samples */
+ pixels += emit_mc6847_samples<1>(
+ m_data[y].m_mode[x],
+ &m_data[y].m_data[x],
+ x2 - x,
+ pixels,
+ m_palette,
+ m_get_char_rom,
+ x,
+ y);
+
+ /* update x */
+ x = x2;
+ }
+
+ /* right border */
+ for (x = base_x + 256; x <= max_x; x++)
+ {
+ *bitmap_addr(bitmap, y + base_y, x) = border_value(m_data[y].m_mode[width - 1], palette, is_mc6847t1);
+ }
+
+ /* artifacting */
+ m_artifacter.process_artifacts<1>(bitmap_addr(bitmap, y + base_y, base_x), m_data[y].m_mode[0], palette);
+ }
+
+ /* bottom border */
+ for (y = base_y + 192; y <= max_y; y++)
+ {
+ for (x = min_x; x <= max_x; x++)
+ {
+ int width = m_data[191].m_sample_count;
+ *bitmap_addr(bitmap, y, x) = border_value(m_data[191].m_mode[width - 1], palette, is_mc6847t1);
+ }
+ }
+ return 0;
+}
+
+
+
+//**************************************************************************
+// CHARACTER MAP
+//**************************************************************************
+
+mc6847_friend_device::character_map::character_map(const UINT8 *text_fontdata, bool is_mc6847t1)
+{
+ int mode, i;
+
+ // set up font data
+ for (i = 0; i < 64*12; i++)
+ {
+ m_text_fontdata_inverse[i] = text_fontdata[i] ^ 0xFF;
+ m_text_fontdata_lower_case[i] = text_fontdata[i + (i < 32*12 ? 64*12 : 0)] ^ (i < 32*12 ? 0xFF : 0x00);
+ m_text_fontdata_lower_case_inverse[i] = m_text_fontdata_lower_case[i] ^ 0xFF;
+ }
+
+ // loop through all modes
+ for (mode = 0; mode < sizeof(m_entries) / sizeof(m_entries[0]); mode++)
+ {
+ const UINT8 *fontdata;
+ UINT8 character_mask;
+ UINT8 color_shift_0 = 0;
+ UINT8 color_shift_1 = 0;
+ UINT8 color_mask_0 = 0x00;
+ UINT8 color_mask_1 = 0x00;
+ UINT16 color_base_0;
+ UINT16 color_base_1;
+
+ if ((mode & MODE_INTEXT) && !is_mc6847t1)
+ {
+ // semigraphics 6
+ fontdata = semigraphics6_fontdata8x12;
+ character_mask = 0x3F;
+ color_base_0 = 8;
+ color_base_1 = mode & MODE_CSS ? 4 : 0;
+ color_shift_1 = 6;
+ color_mask_1 = 0x03;
+ }
+ else if (mode & MODE_AS)
+ {
+ // semigraphics 4
+ fontdata = semigraphics4_fontdata8x12;
+ character_mask = 0x0F;
+ color_base_0 = 8;
+ color_base_1 = 0;
+ color_shift_1 = 4;
+ color_mask_1 = 0x07;
+ }
+ else
+ {
+ // text
+ bool is_lower_case = is_mc6847t1 && ((mode & MODE_INV) == 0) && (mode & MODE_GM0);
+ bool is_inverse1 = (mode & MODE_INV) ? true : false;
+ bool is_inverse2 = is_mc6847t1 && (mode & MODE_GM1);
+ bool is_inverse = (is_inverse1 && !is_inverse2) || (!is_inverse1 && is_inverse2);
+ fontdata = is_inverse
+ ? (is_lower_case ? m_text_fontdata_lower_case_inverse : m_text_fontdata_inverse)
+ : (is_lower_case ? m_text_fontdata_lower_case : text_fontdata);
+ character_mask = 0x3F;
+ color_base_0 = (mode & MODE_CSS ? 14 : 12);
+ color_base_1 = (mode & MODE_CSS ? 15 : 13);
+ }
+
+ // populate the entry
+ memset(&m_entries[mode], 0, sizeof(m_entries[mode]));
+ m_entries[mode].m_fontdata = fontdata;
+ m_entries[mode].m_character_mask = character_mask;
+ m_entries[mode].m_color_shift_0 = color_shift_0;
+ m_entries[mode].m_color_shift_1 = color_shift_1;
+ m_entries[mode].m_color_mask_0 = color_mask_0;
+ m_entries[mode].m_color_mask_1 = color_mask_1;
+ m_entries[mode].m_color_base_0 = color_base_0;
+ m_entries[mode].m_color_base_1 = color_base_1;
+ }
+}
+
+
+
+//-------------------------------------------------
+// pal_round_fontdata8x12
+//-------------------------------------------------
+
+const UINT8 mc6847_friend_device::pal_round_fontdata8x12[] =
+{
+ 0x00, 0x00, 0x38, 0x44, 0x04, 0x34, 0x4C, 0x4C, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x28, 0x44, 0x44, 0x7C, 0x44, 0x44, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x78, 0x24, 0x24, 0x38, 0x24, 0x24, 0x78, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x44, 0x40, 0x40, 0x40, 0x44, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x78, 0x24, 0x24, 0x24, 0x24, 0x24, 0x78, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7C, 0x40, 0x40, 0x70, 0x40, 0x40, 0x7C, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7C, 0x40, 0x40, 0x70, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x44, 0x40, 0x40, 0x4C, 0x44, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x44, 0x44, 0x44, 0x7C, 0x44, 0x44, 0x44, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x10, 0x10, 0x10, 0x10, 0x10, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x44, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x44, 0x48, 0x50, 0x60, 0x50, 0x48, 0x44, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x7C, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x44, 0x6C, 0x54, 0x54, 0x44, 0x44, 0x44, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x44, 0x44, 0x64, 0x54, 0x4C, 0x44, 0x44, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x44, 0x44, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x78, 0x44, 0x44, 0x78, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x44, 0x44, 0x44, 0x54, 0x48, 0x34, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x78, 0x44, 0x44, 0x78, 0x50, 0x48, 0x44, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x44, 0x40, 0x38, 0x04, 0x44, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7C, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x44, 0x44, 0x44, 0x28, 0x28, 0x10, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x44, 0x44, 0x44, 0x44, 0x54, 0x6C, 0x44, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x44, 0x44, 0x28, 0x10, 0x28, 0x44, 0x44, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x44, 0x44, 0x28, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7C, 0x04, 0x08, 0x10, 0x20, 0x40, 0x7C, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x20, 0x20, 0x20, 0x20, 0x20, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x40, 0x20, 0x10, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x08, 0x08, 0x08, 0x08, 0x08, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x38, 0x54, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x10, 0x20, 0x7C, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x28, 0x28, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x28, 0x28, 0x7C, 0x28, 0x7C, 0x28, 0x28, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x3C, 0x50, 0x38, 0x14, 0x78, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x60, 0x64, 0x08, 0x10, 0x20, 0x4C, 0x0C, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x20, 0x50, 0x50, 0x20, 0x54, 0x48, 0x34, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x08, 0x10, 0x20, 0x20, 0x20, 0x10, 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x20, 0x10, 0x08, 0x08, 0x08, 0x10, 0x20, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x10, 0x54, 0x38, 0x38, 0x54, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x10, 0x10, 0x7C, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x20, 0x40, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x04, 0x08, 0x10, 0x20, 0x40, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x44, 0x4C, 0x54, 0x64, 0x44, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x30, 0x10, 0x10, 0x10, 0x10, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x44, 0x04, 0x38, 0x40, 0x40, 0x7C, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x44, 0x04, 0x08, 0x04, 0x44, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x08, 0x18, 0x28, 0x48, 0x7C, 0x08, 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7C, 0x40, 0x78, 0x04, 0x04, 0x44, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x40, 0x40, 0x78, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7C, 0x04, 0x08, 0x10, 0x20, 0x40, 0x40, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x44, 0x44, 0x38, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x44, 0x44, 0x3C, 0x04, 0x04, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x10, 0x20, 0x00, 0x00,
+ 0x00, 0x00, 0x08, 0x10, 0x20, 0x40, 0x20, 0x10, 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x20, 0x10, 0x08, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x44, 0x04, 0x08, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00,
+
+ /* Lower case */
+ 0x00, 0x00, 0x18, 0x24, 0x20, 0x70, 0x20, 0x24, 0x78, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x38, 0x04, 0x3C, 0x44, 0x3C, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x40, 0x40, 0x58, 0x64, 0x44, 0x64, 0x58, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x38, 0x44, 0x40, 0x44, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x04, 0x04, 0x34, 0x4C, 0x44, 0x4C, 0x34, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x38, 0x44, 0x7C, 0x40, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x08, 0x14, 0x10, 0x38, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x34, 0x4C, 0x44, 0x4C, 0x34, 0x04, 0x38, 0x00,
+ 0x00, 0x00, 0x40, 0x40, 0x58, 0x64, 0x44, 0x44, 0x44, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x00, 0x30, 0x10, 0x10, 0x10, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x04, 0x00, 0x04, 0x04, 0x04, 0x04, 0x44, 0x38, 0x00, 0x00,
+ 0x00, 0x00, 0x40, 0x40, 0x48, 0x50, 0x60, 0x50, 0x48, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x30, 0x10, 0x10, 0x10, 0x10, 0x10, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x78, 0x54, 0x54, 0x54, 0x54, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x58, 0x64, 0x44, 0x44, 0x44, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x38, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x78, 0x44, 0x44, 0x44, 0x78, 0x40, 0x40, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3C, 0x44, 0x44, 0x44, 0x3C, 0x04, 0x04, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x58, 0x64, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3C, 0x40, 0x38, 0x04, 0x78, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x20, 0x20, 0x70, 0x20, 0x20, 0x24, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x4C, 0x34, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x28, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x44, 0x54, 0x54, 0x28, 0x28, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x44, 0x28, 0x10, 0x28, 0x44, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x3C, 0x04, 0x38, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x7C, 0x08, 0x10, 0x20, 0x7C, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x08, 0x10, 0x10, 0x20, 0x10, 0x10, 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x10, 0x10, 0x00, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x20, 0x10, 0x10, 0x08, 0x10, 0x10, 0x20, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x20, 0x54, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x00
+};
+
+
+
+//-------------------------------------------------
+// pal_square_fontdata8x12
+//-------------------------------------------------
+
+const UINT8 mc6847_friend_device::pal_square_fontdata8x12[] =
+{
+ 0x00, 0x00, 0x00, 0x1C, 0x22, 0x02, 0x1A, 0x2A, 0x2A, 0x1C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08, 0x14, 0x22, 0x22, 0x3E, 0x22, 0x22, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x3C, 0x12, 0x12, 0x1C, 0x12, 0x12, 0x3C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x1C, 0x22, 0x20, 0x20, 0x20, 0x22, 0x1C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x3C, 0x12, 0x12, 0x12, 0x12, 0x12, 0x3C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x3E, 0x20, 0x20, 0x3C, 0x20, 0x20, 0x3E, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x3E, 0x20, 0x20, 0x3C, 0x20, 0x20, 0x20, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x1E, 0x20, 0x20, 0x26, 0x22, 0x22, 0x1E, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x3E, 0x22, 0x22, 0x22, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x1C, 0x08, 0x08, 0x08, 0x08, 0x08, 0x1C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x22, 0x22, 0x1C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x22, 0x24, 0x28, 0x30, 0x28, 0x24, 0x22, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3E, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x22, 0x36, 0x2A, 0x2A, 0x22, 0x22, 0x22, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x22, 0x32, 0x2A, 0x26, 0x22, 0x22, 0x22, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x3E, 0x22, 0x22, 0x22, 0x22, 0x22, 0x3E, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x3C, 0x22, 0x22, 0x3C, 0x20, 0x20, 0x20, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x1C, 0x22, 0x22, 0x22, 0x2A, 0x24, 0x1A, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x3C, 0x22, 0x22, 0x3C, 0x28, 0x24, 0x22, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x1C, 0x22, 0x10, 0x08, 0x04, 0x22, 0x1C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x3E, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x1C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x14, 0x14, 0x08, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x2A, 0x2A, 0x36, 0x22, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x22, 0x22, 0x14, 0x08, 0x14, 0x22, 0x22, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x22, 0x22, 0x14, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x3E, 0x02, 0x04, 0x08, 0x10, 0x20, 0x3E, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x38, 0x20, 0x20, 0x20, 0x20, 0x20, 0x38, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x20, 0x20, 0x10, 0x08, 0x04, 0x02, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x0E, 0x02, 0x02, 0x02, 0x02, 0x02, 0x0E, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08, 0x1C, 0x2A, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x08, 0x10, 0x3E, 0x10, 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x14, 0x14, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x14, 0x14, 0x36, 0x00, 0x36, 0x14, 0x14, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08, 0x1E, 0x20, 0x1C, 0x02, 0x3C, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x32, 0x32, 0x04, 0x08, 0x10, 0x26, 0x26, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x10, 0x28, 0x28, 0x10, 0x2A, 0x24, 0x1A, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08, 0x10, 0x20, 0x20, 0x20, 0x10, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08, 0x04, 0x02, 0x02, 0x02, 0x04, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x08, 0x1C, 0x3E, 0x1C, 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x3E, 0x08, 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x10, 0x20, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x02, 0x02, 0x04, 0x08, 0x10, 0x20, 0x20, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x24, 0x24, 0x24, 0x24, 0x24, 0x18, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08, 0x18, 0x08, 0x08, 0x08, 0x08, 0x1C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x1C, 0x22, 0x02, 0x1C, 0x20, 0x20, 0x3E, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x1C, 0x22, 0x02, 0x0C, 0x02, 0x22, 0x1C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x04, 0x0C, 0x14, 0x3E, 0x04, 0x04, 0x04, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x3E, 0x20, 0x3C, 0x02, 0x02, 0x22, 0x1C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x1C, 0x20, 0x20, 0x3C, 0x22, 0x22, 0x1C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x3E, 0x02, 0x04, 0x08, 0x10, 0x20, 0x20, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x1C, 0x22, 0x22, 0x1C, 0x22, 0x22, 0x1C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x1C, 0x22, 0x22, 0x1E, 0x02, 0x02, 0x1C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x08, 0x10, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x04, 0x08, 0x10, 0x20, 0x10, 0x08, 0x04, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x10, 0x08, 0x04, 0x02, 0x04, 0x08, 0x10, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x24, 0x04, 0x08, 0x08, 0x00, 0x08, 0x00, 0x00,
+
+ /* Lower case */
+ 0x00, 0x00, 0x00, 0x0C, 0x12, 0x10, 0x38, 0x10, 0x12, 0x3C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x02, 0x1E, 0x22, 0x1E, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x20, 0x20, 0x3C, 0x22, 0x22, 0x22, 0x3C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x20, 0x20, 0x20, 0x1C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x02, 0x02, 0x1E, 0x22, 0x22, 0x22, 0x1E, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x22, 0x3E, 0x20, 0x1C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x0C, 0x12, 0x10, 0x38, 0x10, 0x10, 0x10, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x22, 0x22, 0x22, 0x1E, 0x02, 0x1C,
+ 0x00, 0x00, 0x00, 0x20, 0x20, 0x3C, 0x22, 0x22, 0x22, 0x22, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08, 0x00, 0x18, 0x08, 0x08, 0x08, 0x1C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x04, 0x04, 0x04, 0x04, 0x24, 0x18,
+ 0x00, 0x00, 0x00, 0x20, 0x20, 0x24, 0x28, 0x38, 0x24, 0x22, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x08, 0x08, 0x08, 0x08, 0x08, 0x1C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x2A, 0x2A, 0x2A, 0x2A, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x2C, 0x32, 0x22, 0x22, 0x22, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x22, 0x22, 0x22, 0x1C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x22, 0x22, 0x22, 0x3C, 0x20, 0x20,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x22, 0x22, 0x22, 0x1E, 0x02, 0x03,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x2C, 0x32, 0x20, 0x20, 0x20, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x20, 0x1C, 0x02, 0x3C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x10, 0x3C, 0x10, 0x10, 0x10, 0x12, 0x0C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x26, 0x1A, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x14, 0x14, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x2A, 0x2A, 0x1C, 0x14, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x14, 0x08, 0x14, 0x22, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x1E, 0x02, 0x1C,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x04, 0x08, 0x10, 0x3E, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08, 0x10, 0x10, 0x20, 0x10, 0x10, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x00, 0x08, 0x08, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08, 0x04, 0x04, 0x02, 0x04, 0x04, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x2A, 0x1C, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08, 0x04, 0x3E, 0x04, 0x08, 0x00, 0x00, 0x00, 0x00,
+};
+
+
+
+//-------------------------------------------------
+// ntsc_round_fontdata8x12
+//-------------------------------------------------
+
+const UINT8 mc6847_friend_device::ntsc_round_fontdata8x12[] =
+{
+ 0x00, 0x00, 0x38, 0x44, 0x04, 0x34, 0x4C, 0x4C, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x28, 0x44, 0x44, 0x7C, 0x44, 0x44, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x78, 0x24, 0x24, 0x38, 0x24, 0x24, 0x78, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x44, 0x40, 0x40, 0x40, 0x44, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x78, 0x24, 0x24, 0x24, 0x24, 0x24, 0x78, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7C, 0x40, 0x40, 0x70, 0x40, 0x40, 0x7C, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7C, 0x40, 0x40, 0x70, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x44, 0x40, 0x40, 0x4C, 0x44, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x44, 0x44, 0x44, 0x7C, 0x44, 0x44, 0x44, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x10, 0x10, 0x10, 0x10, 0x10, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x44, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x44, 0x48, 0x50, 0x60, 0x50, 0x48, 0x44, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x7C, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x44, 0x6C, 0x54, 0x54, 0x44, 0x44, 0x44, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x44, 0x44, 0x64, 0x54, 0x4C, 0x44, 0x44, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x44, 0x44, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x78, 0x44, 0x44, 0x78, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x44, 0x44, 0x44, 0x54, 0x48, 0x34, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x78, 0x44, 0x44, 0x78, 0x50, 0x48, 0x44, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x44, 0x40, 0x38, 0x04, 0x44, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7C, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x44, 0x44, 0x44, 0x28, 0x28, 0x10, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x44, 0x44, 0x44, 0x44, 0x54, 0x6C, 0x44, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x44, 0x44, 0x28, 0x10, 0x28, 0x44, 0x44, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x44, 0x44, 0x28, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7C, 0x04, 0x08, 0x10, 0x20, 0x40, 0x7C, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x20, 0x20, 0x20, 0x20, 0x20, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x40, 0x20, 0x10, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x08, 0x08, 0x08, 0x08, 0x08, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x38, 0x54, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x10, 0x20, 0x7C, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x28, 0x28, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x28, 0x28, 0x7C, 0x28, 0x7C, 0x28, 0x28, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x3C, 0x50, 0x38, 0x14, 0x78, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x60, 0x64, 0x08, 0x10, 0x20, 0x4C, 0x0C, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x20, 0x50, 0x50, 0x20, 0x54, 0x48, 0x34, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x08, 0x10, 0x20, 0x20, 0x20, 0x10, 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x20, 0x10, 0x08, 0x08, 0x08, 0x10, 0x20, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x10, 0x54, 0x38, 0x38, 0x54, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x10, 0x10, 0x7C, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x20, 0x40, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x04, 0x08, 0x10, 0x20, 0x40, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x44, 0x4C, 0x54, 0x64, 0x44, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x30, 0x10, 0x10, 0x10, 0x10, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x44, 0x04, 0x38, 0x40, 0x40, 0x7C, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x44, 0x04, 0x08, 0x04, 0x44, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x08, 0x18, 0x28, 0x48, 0x7C, 0x08, 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7C, 0x40, 0x78, 0x04, 0x04, 0x44, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x40, 0x40, 0x78, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7C, 0x04, 0x08, 0x10, 0x20, 0x40, 0x40, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x44, 0x44, 0x38, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x44, 0x44, 0x3C, 0x04, 0x04, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x10, 0x20, 0x00, 0x00,
+ 0x00, 0x00, 0x08, 0x10, 0x20, 0x40, 0x20, 0x10, 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x20, 0x10, 0x08, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x44, 0x04, 0x08, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00,
+
+ /* Lower case */
+ 0x00, 0x00, 0x10, 0x28, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x38, 0x04, 0x3C, 0x44, 0x3C, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x40, 0x40, 0x58, 0x64, 0x44, 0x64, 0x58, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x38, 0x44, 0x40, 0x44, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x04, 0x04, 0x34, 0x4C, 0x44, 0x4C, 0x34, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x38, 0x44, 0x7C, 0x40, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x08, 0x14, 0x10, 0x38, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x34, 0x4C, 0x44, 0x4C, 0x34, 0x04, 0x38, 0x00,
+ 0x00, 0x00, 0x40, 0x40, 0x58, 0x64, 0x44, 0x44, 0x44, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x00, 0x30, 0x10, 0x10, 0x10, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x04, 0x00, 0x04, 0x04, 0x04, 0x04, 0x44, 0x38, 0x00, 0x00,
+ 0x00, 0x00, 0x40, 0x40, 0x48, 0x50, 0x60, 0x50, 0x48, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x30, 0x10, 0x10, 0x10, 0x10, 0x10, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x78, 0x54, 0x54, 0x54, 0x54, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x58, 0x64, 0x44, 0x44, 0x44, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x38, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x78, 0x44, 0x44, 0x44, 0x78, 0x40, 0x40, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3C, 0x44, 0x44, 0x44, 0x3C, 0x04, 0x04, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x58, 0x64, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3C, 0x40, 0x38, 0x04, 0x78, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x20, 0x20, 0x70, 0x20, 0x20, 0x24, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x4C, 0x34, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x28, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x44, 0x54, 0x54, 0x28, 0x28, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x44, 0x28, 0x10, 0x28, 0x44, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x3C, 0x04, 0x38, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x7C, 0x08, 0x10, 0x20, 0x7C, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x08, 0x10, 0x10, 0x20, 0x10, 0x10, 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x10, 0x10, 0x00, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x20, 0x10, 0x10, 0x08, 0x10, 0x10, 0x20, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x20, 0x54, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x00,
+};
+
+
+
+//-------------------------------------------------
+// ntsc_square_fontdata8x12
+//-------------------------------------------------
+
+const UINT8 mc6847_friend_device::ntsc_square_fontdata8x12[] =
+{
+ 0x00, 0x00, 0x00, 0x1C, 0x22, 0x02, 0x1A, 0x2A, 0x2A, 0x1C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08, 0x14, 0x22, 0x22, 0x3E, 0x22, 0x22, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x3C, 0x12, 0x12, 0x1C, 0x12, 0x12, 0x3C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x1C, 0x22, 0x20, 0x20, 0x20, 0x22, 0x1C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x3C, 0x12, 0x12, 0x12, 0x12, 0x12, 0x3C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x3E, 0x20, 0x20, 0x38, 0x20, 0x20, 0x3E, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x3E, 0x20, 0x20, 0x38, 0x20, 0x20, 0x20, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x1E, 0x20, 0x20, 0x26, 0x22, 0x22, 0x1E, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x3E, 0x22, 0x22, 0x22, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x1C, 0x08, 0x08, 0x08, 0x08, 0x08, 0x1C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x22, 0x22, 0x1C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x22, 0x24, 0x28, 0x30, 0x28, 0x24, 0x22, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3E, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x22, 0x36, 0x2A, 0x2A, 0x22, 0x22, 0x22, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x22, 0x32, 0x2A, 0x26, 0x22, 0x22, 0x22, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x3E, 0x22, 0x22, 0x22, 0x22, 0x22, 0x3E, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x3C, 0x22, 0x22, 0x3C, 0x20, 0x20, 0x20, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x1C, 0x22, 0x22, 0x22, 0x2A, 0x24, 0x1A, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x3C, 0x22, 0x22, 0x3C, 0x28, 0x24, 0x22, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x1C, 0x22, 0x10, 0x08, 0x04, 0x22, 0x1C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x3E, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x1C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x14, 0x14, 0x08, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x2A, 0x2A, 0x36, 0x22, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x22, 0x22, 0x14, 0x08, 0x14, 0x22, 0x22, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x22, 0x22, 0x14, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x3E, 0x02, 0x04, 0x08, 0x10, 0x20, 0x3E, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x38, 0x20, 0x20, 0x20, 0x20, 0x20, 0x38, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x20, 0x20, 0x10, 0x08, 0x04, 0x02, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x0E, 0x02, 0x02, 0x02, 0x02, 0x02, 0x0E, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08, 0x1C, 0x2A, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x08, 0x10, 0x3E, 0x10, 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x14, 0x14, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x14, 0x14, 0x36, 0x00, 0x36, 0x14, 0x14, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08, 0x1E, 0x20, 0x1C, 0x02, 0x3C, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x32, 0x32, 0x04, 0x08, 0x10, 0x26, 0x26, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x10, 0x28, 0x28, 0x10, 0x2A, 0x24, 0x1A, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08, 0x10, 0x20, 0x20, 0x20, 0x10, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08, 0x04, 0x02, 0x02, 0x02, 0x04, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x08, 0x1C, 0x3E, 0x1C, 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x3E, 0x08, 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x10, 0x20, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x02, 0x02, 0x04, 0x08, 0x10, 0x20, 0x20, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x24, 0x24, 0x24, 0x24, 0x24, 0x18, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08, 0x18, 0x08, 0x08, 0x08, 0x08, 0x1C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x1C, 0x22, 0x02, 0x1C, 0x20, 0x20, 0x3E, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x1C, 0x22, 0x02, 0x04, 0x02, 0x22, 0x1C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x04, 0x0C, 0x14, 0x3E, 0x04, 0x04, 0x04, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x3E, 0x20, 0x3C, 0x02, 0x02, 0x22, 0x1C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x1C, 0x20, 0x20, 0x3C, 0x22, 0x22, 0x1C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x3E, 0x02, 0x04, 0x08, 0x10, 0x20, 0x20, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x1C, 0x22, 0x22, 0x1C, 0x22, 0x22, 0x1C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x1C, 0x22, 0x22, 0x1E, 0x02, 0x02, 0x1C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x08, 0x10, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x04, 0x08, 0x10, 0x20, 0x10, 0x08, 0x04, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x10, 0x08, 0x04, 0x02, 0x04, 0x08, 0x10, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x24, 0x04, 0x08, 0x08, 0x00, 0x08, 0x00, 0x00,
+
+ /* Lower case */
+ 0x00, 0x00, 0x00, 0x0C, 0x12, 0x10, 0x38, 0x10, 0x12, 0x3C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x02, 0x1E, 0x22, 0x1E, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x20, 0x20, 0x3C, 0x22, 0x22, 0x22, 0x3C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x20, 0x20, 0x20, 0x1C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x02, 0x02, 0x1E, 0x22, 0x22, 0x22, 0x1E, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x22, 0x3E, 0x20, 0x1C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x0C, 0x12, 0x10, 0x38, 0x10, 0x10, 0x10, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x22, 0x22, 0x22, 0x1E, 0x02, 0x1C,
+ 0x00, 0x00, 0x00, 0x20, 0x20, 0x3C, 0x22, 0x22, 0x22, 0x22, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08, 0x00, 0x18, 0x08, 0x08, 0x08, 0x1C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x04, 0x04, 0x04, 0x04, 0x24, 0x18,
+ 0x00, 0x00, 0x00, 0x20, 0x20, 0x24, 0x28, 0x38, 0x24, 0x22, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x08, 0x08, 0x08, 0x08, 0x08, 0x1C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x2A, 0x2A, 0x2A, 0x2A, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x2C, 0x32, 0x22, 0x22, 0x22, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x22, 0x22, 0x22, 0x1C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x22, 0x22, 0x22, 0x3C, 0x20, 0x20,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x22, 0x22, 0x22, 0x1E, 0x02, 0x03,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x2C, 0x32, 0x20, 0x20, 0x20, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x20, 0x1C, 0x02, 0x3C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x10, 0x3C, 0x10, 0x10, 0x10, 0x12, 0x0C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x26, 0x1A, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x14, 0x14, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x2A, 0x2A, 0x1C, 0x14, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x14, 0x08, 0x14, 0x22, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x1E, 0x02, 0x1C,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x04, 0x08, 0x10, 0x3E, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08, 0x10, 0x10, 0x20, 0x10, 0x10, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x00, 0x08, 0x08, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08, 0x04, 0x04, 0x02, 0x04, 0x04, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x2A, 0x1C, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08, 0x04, 0x3E, 0x04, 0x08, 0x00, 0x00, 0x00, 0x00
+};
+
+
+
+//-------------------------------------------------
+// semigraphics4_fontdata8x12
+//-------------------------------------------------
+
+const UINT8 mc6847_friend_device::semigraphics4_fontdata8x12[] =
+{
+ /* Block Graphics (Semigraphics 4 Graphics ) */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F,
+ 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
+ 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F,
+ 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
+ 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+};
+
+
+
+//-------------------------------------------------
+// semigraphics6_fontdata8x12
+//-------------------------------------------------
+
+const UINT8 mc6847_friend_device::semigraphics6_fontdata8x12[] =
+{
+ /* Semigraphics 6 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x0F, 0x0F,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F,
+ 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x0F, 0x0F, 0xF0, 0xF0, 0xF0, 0xF0,
+ 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x0F, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x00, 0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0, 0x0F, 0x0F, 0x0F, 0x0F,
+ 0x00, 0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
+ 0x00, 0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x0F, 0x0F, 0x0F,
+ 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, 0xF0, 0xF0,
+ 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x0F, 0x0F,
+ 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0,
+ 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00,
+ 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F,
+ 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0xF0, 0xF0, 0xF0, 0xF0,
+ 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x0F, 0x0F, 0x0F, 0x0F, 0xF0, 0xF0, 0xF0, 0xF0, 0x00, 0x00, 0x00, 0x00,
+ 0x0F, 0x0F, 0x0F, 0x0F, 0xF0, 0xF0, 0xF0, 0xF0, 0x0F, 0x0F, 0x0F, 0x0F,
+ 0x0F, 0x0F, 0x0F, 0x0F, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
+ 0x0F, 0x0F, 0x0F, 0x0F, 0xF0, 0xF0, 0xF0, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x0F, 0x0F, 0x0F, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
+ 0x0F, 0x0F, 0x0F, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x0F, 0x0F, 0x0F,
+ 0x0F, 0x0F, 0x0F, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, 0xF0, 0xF0,
+ 0x0F, 0x0F, 0x0F, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xF0, 0xF0, 0xF0, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xF0, 0xF0, 0xF0, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x0F, 0x0F,
+ 0xF0, 0xF0, 0xF0, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0,
+ 0xF0, 0xF0, 0xF0, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xF0, 0xF0, 0xF0, 0xF0, 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00,
+ 0xF0, 0xF0, 0xF0, 0xF0, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F,
+ 0xF0, 0xF0, 0xF0, 0xF0, 0x0F, 0x0F, 0x0F, 0x0F, 0xF0, 0xF0, 0xF0, 0xF0,
+ 0xF0, 0xF0, 0xF0, 0xF0, 0x0F, 0x0F, 0x0F, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0x00, 0x00, 0x00, 0x00,
+ 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0x0F, 0x0F, 0x0F, 0x0F,
+ 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
+ 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xF0, 0xF0, 0xF0, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
+ 0xF0, 0xF0, 0xF0, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x0F, 0x0F, 0x0F,
+ 0xF0, 0xF0, 0xF0, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, 0xF0, 0xF0,
+ 0xF0, 0xF0, 0xF0, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x0F, 0x0F,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x0F, 0x0F, 0x0F, 0xF0, 0xF0, 0xF0, 0xF0,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x0F, 0x0F, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, 0xF0, 0xF0, 0x00, 0x00, 0x00, 0x00,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, 0xF0, 0xF0, 0x0F, 0x0F, 0x0F, 0x0F,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, 0xF0, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x0F, 0x0F, 0x0F,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, 0xF0, 0xF0,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+};
+
+
+
+//**************************************************************************
+// ARTIFACTING
+//**************************************************************************
+
+INPUT_PORTS_START(mc6847_artifacting)
+ PORT_START(ARTIFACTING_TAG)
+ PORT_CONFNAME( 0x03, 0x01, "Artifacting" )
+ PORT_CONFSETTING( 0x00, DEF_STR( Off ) )
+ PORT_CONFSETTING( 0x01, DEF_STR( Standard ) )
+ PORT_CONFSETTING( 0x02, DEF_STR( Reverse ) )
+INPUT_PORTS_END
+
+ioport_constructor mc6847_base_device::device_input_ports() const
+{
+ return INPUT_PORTS_NAME(mc6847_artifacting);
+}
+
+
+
+//-------------------------------------------------
+// ctor
+//-------------------------------------------------
+
+mc6847_base_device::artifacter::artifacter()
+{
+ m_config = NULL;
+ m_artifacting = 0;
+ m_saved_artifacting = 0;
+ m_saved_c0 = 0;
+ m_saved_c1 = 0;
+ memset(m_expanded_colors, 0, sizeof(m_expanded_colors));
+}
+
+
+
+//-------------------------------------------------
+// artifacter::setup_config
+//-------------------------------------------------
+
+void mc6847_base_device::artifacter::setup_config(device_t *device)
+{
+ char port_name[32];
+ snprintf(port_name, ARRAY_LENGTH(port_name), "%s:%s", device->tag(), ARTIFACTING_TAG);
+ m_config = device->ioport(port_name);
+}
+
+
+
+//-------------------------------------------------
+// artifacter::update_colors
+//-------------------------------------------------
+
+void mc6847_base_device::artifacter::update_colors(pixel_t c0, pixel_t c1)
+{
+ /* Boy this code sucks; this code was adapted from the old M6847
+ * artifacting implmentation. The only reason that it didn't look as
+ * horrible was because the code around it sucked as well. Now that I
+ * have cleaned everything up, the ugliness is much more prominent.
+ *
+ * Hopefully we will have a generic artifacting algorithm that plugs into
+ * the MESS/MAME core directly so we can chuck this hack */
+ static const double artifact_colors[14*3] =
+ {
+ 0.157, 0.000, 0.157, /* [ 1] - dk purple (reverse 2) */
+ 0.000, 0.157, 0.000, /* [ 2] - dk green (reverse 1) */
+ 1.000, 0.824, 1.000, /* [ 3] - lt purple (reverse 4) */
+ 0.824, 1.000, 0.824, /* [ 4] - lt green (reverse 3) */
+ 0.706, 0.236, 0.118, /* [ 5] - dk blue (reverse 6) */
+ 0.000, 0.197, 0.471, /* [ 6] - dk red (reverse 5) */
+ 1.000, 0.550, 0.393, /* [ 7] - lt blue (reverse 8) */
+ 0.275, 0.785, 1.000, /* [ 8] - lt red (reverse 7) */
+ 0.000, 0.500, 1.000, /* [ 9] - red (reverse 10) */
+ 1.000, 0.500, 0.000, /* [10] - blue (reverse 9) */
+ 1.000, 0.942, 0.785, /* [11] - cyan (reverse 12) */
+ 0.393, 0.942, 1.000, /* [12] - yellow (reverse 11) */
+ 0.236, 0.000, 0.000, /* [13] - black-blue (reverse 14) */
+ 0.000, 0.000, 0.236 /* [14] - black-red (reverse 13) */
+ };
+
+ static const UINT8 artifact_correction[128] =
+ {
+ 0, 0, 0, 0, 0, 6, 0, 2,
+ 5, 7, 5, 7, 1, 3, 1, 11,
+ 8, 6, 8, 14, 8, 9, 8, 9,
+ 4, 4, 4, 15, 12, 12, 12, 15,
+
+ 5, 13, 5, 13, 13, 0, 13, 2,
+ 10, 10, 10, 10, 10, 15, 10, 11,
+ 3, 1, 3, 1, 15, 9, 15, 9,
+ 11, 11, 11, 11, 15, 15, 15, 15,
+
+ 14, 0, 14, 0, 14, 6, 14, 2,
+ 0, 7, 0, 7, 1, 3, 1, 11,
+ 9, 6, 9, 14, 9, 9, 9, 9,
+ 15, 4, 15, 15, 12, 12, 12, 15,
+
+ 2, 13, 2, 13, 2, 0, 2, 2,
+ 10, 10, 10, 10, 10, 15, 10, 11,
+ 12, 1, 12, 1, 12, 9, 12, 9,
+ 15, 11, 15, 11, 15, 15, 15, 15
+ };
+
+ pixel_t colors[16];
+ int i;
+
+ /* do we need to update our artifact colors table? */
+ if ((m_artifacting != m_saved_artifacting) || (c0 != m_saved_c0) || (c1 != m_saved_c1))
+ {
+ m_saved_artifacting = m_artifacting;
+ m_saved_c0 = colors[0] = c0;
+ m_saved_c1 = colors[15] = c1;
+
+ /* mix the other colors */
+ for (i = 1; i <= 14; i++)
+ {
+ const double *factors = &artifact_colors[((i - 1) ^ (m_artifacting & 0x01)) * 3];
+
+ colors[i] = (mix_color(factors[0], c0 >> 16, c1 >> 16) << 16)
+ | (mix_color(factors[1], c0 >> 8, c1 >> 8) << 8)
+ | (mix_color(factors[2], c0 >> 0, c1 >> 0) << 0);
+ }
+ for (i = 0; i < 128; i++)
+ {
+ m_expanded_colors[i] = colors[artifact_correction[i]];
+ }
+ }
+}
+
+
+
+//-------------------------------------------------
+// artifacter::update
+//-------------------------------------------------
+
+mc6847_base_device::pixel_t mc6847_base_device::artifacter::mix_color(double factor, UINT8 c0, UINT8 c1)
+{
+ return (UINT32) (UINT8) ((c0 * (1.0 - factor)) + (c1 * (0.0 + factor)) + 0.5);
+}
+
+
+
+//**************************************************************************
+// VARIATIONS
+//**************************************************************************
+
+const device_type MC6847_NTSC = &device_creator<mc6847_ntsc_device>;
+const device_type MC6847_PAL = &device_creator<mc6847_pal_device>;
+const device_type MC6847Y_NTSC = &device_creator<mc6847y_ntsc_device>;
+const device_type MC6847Y_PAL = &device_creator<mc6847y_pal_device>;
+const device_type MC6847T1_NTSC = &device_creator<mc6847t1_ntsc_device>;
+const device_type MC6847T1_PAL = &device_creator<mc6847t1_pal_device>;
+
+
+
+//-------------------------------------------------
+// mc6847_ntsc_device
+//-------------------------------------------------
+
+mc6847_ntsc_device::mc6847_ntsc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : mc6847_base_device(mconfig, MC6847_NTSC, "MC6847_NTSC", tag, owner, clock, ntsc_square_fontdata8x12, 262.0)
+{
+}
+
+
+
+//-------------------------------------------------
+// mc6847_pal_device
+//-------------------------------------------------
+
+mc6847_pal_device::mc6847_pal_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : mc6847_base_device(mconfig, MC6847_PAL, "MC6847_PAL", tag, owner, clock, pal_square_fontdata8x12, 262.0)
+{
+}
+
+
+
+//-------------------------------------------------
+// mc6847y_ntsc_device
+//-------------------------------------------------
+
+mc6847y_ntsc_device::mc6847y_ntsc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : mc6847_base_device(mconfig, MC6847Y_NTSC, "MC6847Y_NTSC", tag, owner, clock, ntsc_square_fontdata8x12, 262.5)
+{
+}
+
+
+
+//-------------------------------------------------
+// mc6847y_pal_device
+//-------------------------------------------------
+
+mc6847y_pal_device::mc6847y_pal_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : mc6847_base_device(mconfig, MC6847Y_PAL, "MC6847Y_PAL", tag, owner, clock, pal_square_fontdata8x12, 262.5)
+{
+}
+
+
+
+//-------------------------------------------------
+// mc6847t1_ntsc_device
+//-------------------------------------------------
+
+mc6847t1_ntsc_device::mc6847t1_ntsc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : mc6847_base_device(mconfig, MC6847T1_NTSC, "MC6847T1_NTSC", tag, owner, clock, ntsc_round_fontdata8x12, 262.0)
+{
+}
+
+
+
+//-------------------------------------------------
+// mc6847t1_pal_device
+//-------------------------------------------------
+
+mc6847t1_pal_device::mc6847t1_pal_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : mc6847_base_device(mconfig, MC6847T1_PAL, "MC6847T1_PAL", tag, owner, clock, pal_round_fontdata8x12, 262.0)
+{
+}
diff --git a/src/emu/video/mc6847.h b/src/emu/video/mc6847.h
new file mode 100644
index 00000000000..88027023d65
--- /dev/null
+++ b/src/emu/video/mc6847.h
@@ -0,0 +1,648 @@
+/*********************************************************************
+
+ mc6847.h
+
+ Implementation of Motorola 6847 video hardware chip
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __MC6847__
+#define __MC6847__
+
+
+//**************************************************************************
+// MC6847 CONFIGURATION / INTERFACE
+//**************************************************************************
+
+#define MCFG_MC6847_REMOVE(_tag) \
+ MCFG_DEVICE_REMOVE(_tag)
+
+#define MCFG_MC6847_ADD(_tag, _variant, _clock, _config) \
+ MCFG_DEVICE_ADD(_tag, _variant, _clock) \
+ MCFG_DEVICE_CONFIG(_config)
+
+#define MCFG_SCREEN_MC6847_NTSC_ADD(_tag, _mctag) \
+ MCFG_SCREEN_ADD(_tag, RASTER) \
+ MCFG_SCREEN_UPDATE_DEVICE(_mctag, mc6847_base_device, screen_update) \
+ MCFG_SCREEN_REFRESH_RATE(60) \
+ MCFG_SCREEN_SIZE(320, 243) \
+ MCFG_SCREEN_VISIBLE_AREA(0, 320-1, 1, 241-1) \
+ MCFG_SCREEN_VBLANK_TIME(0)
+#define MCFG_SCREEN_MC6847_PAL_ADD(_tag, _mctag) \
+ MCFG_SCREEN_ADD(_tag, RASTER) \
+ MCFG_SCREEN_UPDATE_DEVICE(_mctag, mc6847_base_device, screen_update) \
+ MCFG_SCREEN_REFRESH_RATE(50) \
+ MCFG_SCREEN_SIZE(320, 243) \
+ MCFG_SCREEN_VISIBLE_AREA(0, 320-1, 1, 241-1) \
+ MCFG_SCREEN_VBLANK_TIME(0)
+/* interface */
+struct mc6847_interface
+{
+ /* screen we are acting on */
+ const char *m_screen_tag;
+
+ /* if specified, this gets called whenever reading a byte (offs_t ~0 specifies DA* entering the tristate mode) */
+ devcb_read8 m_input_func;
+
+ /* if specified, this gets called for every change of the HS pin (pin 38) */
+ devcb_write_line m_out_hsync_func;
+
+ /* if specified, this gets called for every change of the FS pin (pin 37) */
+ devcb_write_line m_out_fsync_func;
+
+ /* mode control lines input */
+ devcb_read_line m_in_ag_func;
+ devcb_read_line m_in_gm2_func;
+ devcb_read_line m_in_gm1_func;
+ devcb_read_line m_in_gm0_func;
+ devcb_read_line m_in_css_func;
+ devcb_read_line m_in_as_func;
+ devcb_read_line m_in_intext_func;
+ devcb_read_line m_in_inv_func;
+
+ /* if specified, this reads the external char rom off of the driver state */
+ UINT8 (*m_get_char_rom)(running_machine &machine, UINT8 ch, int line);
+
+ /* if true, this is black and white */
+ bool m_black_and_white;
+};
+
+#define ARTIFACTING_TAG "artifacting"
+
+INPUT_PORTS_EXTERN(mc6847_artifacting);
+
+
+//**************************************************************************
+// MC6847 CORE
+//**************************************************************************
+
+PALETTE_INIT( mc6847 );
+PALETTE_INIT( mc6847_bw );
+
+// base class so that the GIME emulation can access mc6847 stuff
+class mc6847_friend_device : public device_t
+{
+public:
+ // inlines
+ bool hs_r(void) { return m_horizontal_sync; }
+ bool fs_r(void) { return m_field_sync; }
+
+protected:
+ mc6847_friend_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock,
+ const UINT8 *fontdata, bool is_mc6847t1, double tpfs, int field_sync_falling_edge_scanline, bool supports_partial_body_scanlines);
+
+ // video mode constants
+ static const UINT8 MODE_AG = 0x80;
+ static const UINT8 MODE_GM2 = 0x40;
+ static const UINT8 MODE_GM1 = 0x20;
+ static const UINT8 MODE_GM0 = 0x10;
+ static const UINT8 MODE_CSS = 0x08;
+ static const UINT8 MODE_AS = 0x04;
+ static const UINT8 MODE_INTEXT = 0x02;
+ static const UINT8 MODE_INV = 0x01;
+
+ // timer constants
+ static const device_timer_id TIMER_FRAME = 0;
+ static const device_timer_id TIMER_HSYNC_OFF = 1;
+ static const device_timer_id TIMER_HSYNC_ON = 2;
+ static const device_timer_id TIMER_FSYNC = 3;
+
+ // fonts
+ static const UINT8 pal_round_fontdata8x12[];
+ static const UINT8 pal_square_fontdata8x12[];
+ static const UINT8 ntsc_round_fontdata8x12[];
+ static const UINT8 ntsc_square_fontdata8x12[];
+ static const UINT8 semigraphics4_fontdata8x12[];
+ static const UINT8 semigraphics6_fontdata8x12[];
+
+ // pixel definitions
+ typedef UINT32 pixel_t;
+
+ pixel_t *bitmap_addr(bitmap_rgb32 &bitmap, int y, int x)
+ {
+ return &bitmap.pix32(y, x);
+ }
+
+ static UINT8 simplify_mode(UINT8 data, UINT8 mode)
+ {
+ // simplifies MC6847 modes to drop mode flags that are not significant
+ return mode & ~((mode & MODE_AG) ? (MODE_AS | MODE_INV) : 0);
+ }
+
+ // internal class that represents a MC6847 character map
+ class character_map
+ {
+ public:
+ // constructor that sets up the font data
+ character_map(const UINT8 *fontdata, bool is_mc6847t1);
+
+ // optimized template function that emits a single character
+ template<int xscale>
+ ATTR_FORCE_INLINE void emit_character(UINT8 mode, const UINT8 *data, int length, pixel_t *RESTRICT pixels, int y, const pixel_t *palette)
+ {
+ for (int i = 0; i < length; i++)
+ {
+ // get the character
+ UINT8 character = data[i];
+
+ // based on the mode, determine which entry to use
+ const entry *e = &m_entries[mode % (sizeof(m_entries) / sizeof(m_entries[0]))];
+
+ // identify the character in the font data
+ const UINT8 *font_character = e->m_fontdata + (character & e->m_character_mask) * 12;
+
+ // get the particular slice out
+ UINT8 font_character_slice = font_character[y % 12];
+
+ // get the two colors
+ UINT16 color_base_0 = e->m_color_base_0 + ((character >> e->m_color_shift_0) & e->m_color_mask_0);
+ UINT16 color_base_1 = e->m_color_base_1 + ((character >> e->m_color_shift_1) & e->m_color_mask_1);
+ pixel_t color_0 = palette[color_base_0];
+ pixel_t color_1 = palette[color_base_1];
+
+ // emit the bits
+ for (int j = 0; j < 8; j++)
+ {
+ for (int k = 0; k < xscale; k++)
+ {
+ pixels[(i * 8 + j) * xscale + k] = bit_test(font_character_slice, j, color_0, color_1);
+ }
+ }
+ }
+ };
+
+ private:
+ struct entry
+ {
+ const UINT8 *m_fontdata;
+ UINT8 m_character_mask;
+ UINT8 m_color_shift_0;
+ UINT8 m_color_shift_1;
+ UINT8 m_color_mask_0;
+ UINT8 m_color_mask_1;
+ UINT16 m_color_base_0;
+ UINT16 m_color_base_1;
+ };
+
+ // lookup table for MC6847 modes to determine font data and color
+ entry m_entries[128];
+
+ // text font data calculated on startup
+ UINT8 m_text_fontdata_inverse[64*12];
+ UINT8 m_text_fontdata_lower_case[64*12];
+ UINT8 m_text_fontdata_lower_case_inverse[64*12];
+
+ // optimized function that tests a single bit
+ ATTR_FORCE_INLINE pixel_t bit_test(UINT8 data, int shift, pixel_t color_0, pixel_t color_1)
+ {
+ return data & (0x80 >> shift) ? color_1 : color_0;
+ }
+ };
+
+ // artficater internal class
+ class artifacter
+ {
+ public:
+ artifacter();
+
+ // artifacting config
+ void setup_config(device_t *device);
+ void poll_config(void) { m_artifacting = (m_config!=NULL) ? m_config->read() : 0; }
+
+ // artifacting application
+ template<int xscale>
+ ATTR_FORCE_INLINE void process_artifacts(pixel_t *pixels, UINT8 mode, const pixel_t *palette)
+ {
+ if (((mode & (MODE_AG|MODE_GM2|MODE_GM1|MODE_GM0)) == (MODE_AG|MODE_GM2|MODE_GM1|MODE_GM0))
+ && (m_artifacting != 0))
+ {
+ // identify the new colors and update
+ pixel_t c0 = palette[(mode & MODE_CSS) ? 10 : 8];
+ pixel_t c1 = palette[(mode & MODE_CSS) ? 11 : 9];
+ update_colors(c0, c1);
+
+ // generate the new line
+ pixel_t new_line[256];
+ int x, i;
+ for (x = 0; x < 256; x += 2)
+ {
+ UINT8 val = ((pixels[(x - 2) * xscale] == c1) ? 0x20 : 0x00)
+ | ((pixels[(x - 1) * xscale] == c1) ? 0x10 : 0x00)
+ | ((pixels[(x + 0) * xscale] == c1) ? 0x08 : 0x00)
+ | ((pixels[(x + 1) * xscale] == c1) ? 0x04 : 0x00)
+ | ((pixels[(x + 2) * xscale] == c1) ? 0x02 : 0x00)
+ | ((pixels[(x + 3) * xscale] == c1) ? 0x01 : 0x00);
+
+ new_line[x + 0] = m_expanded_colors[val * 2 + 0];
+ new_line[x + 1] = m_expanded_colors[val * 2 + 1];
+ }
+
+ // and copy it in
+ for (x = 0; x < 256; x++)
+ {
+ for (i = 0; i < xscale; i++)
+ pixels[x * xscale + i] = new_line[x];
+ }
+ }
+ }
+
+ private:
+ ioport_port *m_config;
+ ioport_value m_artifacting;
+ ioport_value m_saved_artifacting;
+ pixel_t m_saved_c0, m_saved_c1;
+ pixel_t m_expanded_colors[128];
+
+ void update_colors(pixel_t c0, pixel_t c1);
+ static pixel_t mix_color(double factor, UINT8 c0, UINT8 c1);
+ };
+
+ enum border_color_t
+ {
+ BORDER_COLOR_BLACK,
+ BORDER_COLOR_GREEN,
+ BORDER_COLOR_WHITE,
+ BORDER_COLOR_ORANGE
+ };
+
+ // callbacks
+ devcb_resolved_write_line m_res_out_hsync_func;
+ devcb_resolved_write_line m_res_out_fsync_func;
+
+ // incidentals
+ character_map m_character_map;
+ artifacter m_artifacter;
+
+ // device-level overrides
+ virtual void device_start(void);
+ virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);
+ virtual void device_reset(void);
+ virtual void device_post_load(void);
+
+ // other overridables
+ virtual void new_frame(void);
+ virtual void horizontal_sync_changed(bool line);
+ virtual void field_sync_changed(bool line);
+ virtual void enter_bottom_border(void);
+ virtual void record_border_scanline(UINT16 physical_scanline);
+ virtual void record_body_scanline(UINT16 physical_scanline, UINT16 logical_scanline) = 0;
+ virtual void record_partial_body_scanline(UINT16 physical_scanline, UINT16 logical_scanline, INT32 start_clock, INT32 end_clock) = 0;
+
+ // miscellaneous
+ void video_flush(void);
+ const char *describe_context(void);
+
+ // setup functions
+ emu_timer *setup_timer(device_timer_id id, double offset, double period);
+
+ // converts to B&W
+ static pixel_t black_and_white(pixel_t color)
+ {
+ UINT8 average_color = (RGB_RED(color) + RGB_GREEN(color) + RGB_BLUE(color)) / 3;
+ return MAKE_RGB(average_color, average_color, average_color);
+ }
+
+ // changes the geometry
+ ATTR_FORCE_INLINE void set_geometry(UINT16 top_border_scanlines, UINT16 body_scanlines, bool wide)
+ {
+ if (UNEXPECTED((m_top_border_scanlines != top_border_scanlines)
+ || (m_body_scanlines != body_scanlines)
+ || (m_wide != wide)))
+ {
+ m_top_border_scanlines = top_border_scanlines;
+ m_body_scanlines = body_scanlines;
+ m_wide = wide;
+ update_field_sync_timer();
+ }
+ }
+
+ // calculates the border color
+ static ATTR_FORCE_INLINE border_color_t border_value(UINT8 mode, bool is_mc6847t1)
+ {
+ border_color_t result;
+
+ if (mode & MODE_AG)
+ {
+ // graphics
+ result = mode & MODE_CSS ? BORDER_COLOR_WHITE : BORDER_COLOR_GREEN;
+ }
+ else if (!is_mc6847t1 || ((mode & MODE_GM2) == 0))
+ {
+ // text, black border
+ result = BORDER_COLOR_BLACK;
+ }
+ else
+ {
+ // text, green or orange border
+ result = mode & MODE_CSS ? BORDER_COLOR_ORANGE : BORDER_COLOR_GREEN;
+ }
+ return result;
+ }
+
+ // checks to see if the video has changed
+ ATTR_FORCE_INLINE bool has_video_changed(void)
+ {
+ /* poll the artifacting config */
+ m_artifacter.poll_config();
+
+ /* if the video didn't change, indicate as much */
+ bool video_changed = m_video_changed;
+ m_video_changed = false;
+ return video_changed;
+ }
+
+ // updates a byte in the video state
+ template<class T>
+ ATTR_FORCE_INLINE bool update_value(T *ptr, T byte)
+ {
+ bool result = false;
+ if (*ptr != byte)
+ {
+ *ptr = byte;
+ m_video_changed = true;
+ result = true;
+ }
+ return result;
+ };
+
+ // template function for emitting graphics bytes
+ template<int bits_per_pixel, int xscale>
+ ATTR_FORCE_INLINE void emit_graphics(const UINT8 *data, int length, pixel_t *RESTRICT pixels, UINT16 color_base, const pixel_t *RESTRICT palette)
+ {
+ for (int i = 0; i < length; i++)
+ {
+ for (int j = 0; j < (8 / bits_per_pixel); j++)
+ {
+ for (int k = 0; k < xscale; k++)
+ {
+ UINT16 color = color_base + ((data[i] >> (8 - (j + 1) * bits_per_pixel)) & ((1 << bits_per_pixel) - 1));
+ pixels[(i * (8 / bits_per_pixel) + j) * xscale + k] = palette[color];
+ }
+ }
+ }
+ }
+
+ // template function for emitting samples
+ template<int xscale>
+ UINT32 emit_mc6847_samples(UINT8 mode, const UINT8 *data, int length, pixel_t *RESTRICT pixels, const pixel_t *RESTRICT palette,
+ UINT8 (*get_char_rom)(running_machine &machine, UINT8 ch, int line), int x, int y)
+ {
+ UINT32 result = 0;
+ if (mode & MODE_AG)
+ {
+ /* graphics */
+ switch(mode & (MODE_GM2|MODE_GM1|MODE_GM0))
+ {
+ case 0:
+ emit_graphics<2, xscale * 4>(data, length, pixels, (mode & MODE_CSS) ? 4 : 0, palette);
+ result = length * 8 * xscale * 2;
+ break;
+
+ case MODE_GM0:
+ case MODE_GM1|MODE_GM0:
+ case MODE_GM2|MODE_GM0:
+ emit_graphics<1, xscale * 2>(data, length, pixels, (mode & MODE_CSS) ? 10 : 8, palette);
+ result = length * 8 * xscale * 2;
+ break;
+
+ case MODE_GM1:
+ case MODE_GM2:
+ case MODE_GM2|MODE_GM1:
+ emit_graphics<2, xscale * 2>(data, length, pixels, (mode & MODE_CSS) ? 4 : 0, palette);
+ result = length * 8 * xscale;
+ break;
+
+ case MODE_GM2|MODE_GM1|MODE_GM0:
+ emit_graphics<1, xscale * 1>(data, length, pixels, (mode & MODE_CSS) ? 10 : 8, palette);
+ result = length * 8 * xscale;
+ break;
+
+ default:
+ /* should not get here */
+ fatalerror("Should not get here\n");
+ break;
+ }
+ }
+ else if ((get_char_rom != NULL) && ((mode & (MODE_AG|MODE_AS|MODE_INTEXT)) == MODE_INTEXT))
+ {
+ /* external ROM */
+ for (int i = 0; i < length; i++)
+ {
+ UINT8 byte = get_char_rom(machine(), data[i], y % 12) ^ (mode & MODE_INV ? 0xFF : 0x00);
+ emit_graphics<2, xscale * 2>(&byte, 1, &pixels[i * 8], (mode & MODE_CSS) ? 14 : 12, palette);
+ }
+ result = length * 8 * xscale;
+ }
+ else
+ {
+ /* text/semigraphics */
+ m_character_map.emit_character<xscale>(mode, data, length, pixels, y, palette);
+ result = length * 8 * xscale;
+ }
+ return result;
+ }
+
+private:
+ enum scanline_zone
+ {
+ SCANLINE_ZONE_TOP_BORDER,
+ SCANLINE_ZONE_BODY,
+ SCANLINE_ZONE_BOTTOM_BORDER,
+ SCANLINE_ZONE_RETRACE,
+ SCANLINE_ZONE_VBLANK,
+ SCANLINE_ZONE_FRAME_END
+ };
+
+ // timers
+ emu_timer *m_frame_timer;
+ emu_timer *m_hsync_on_timer;
+ emu_timer *m_hsync_off_timer;
+ emu_timer *m_fsync_timer;
+
+ // incidentals
+ double m_tpfs;
+ int m_field_sync_falling_edge_scanline;
+ bool m_wide;
+ bool m_video_changed;
+ UINT16 m_top_border_scanlines;
+ UINT16 m_body_scanlines;
+ bool m_recording_scanline;
+ bool m_supports_partial_body_scanlines;
+
+ // video state
+ UINT16 m_physical_scanline;
+ UINT16 m_logical_scanline;
+ UINT16 m_logical_scanline_zone;
+ bool m_horizontal_sync;
+ bool m_field_sync;
+ UINT32 m_partial_scanline_clocks;
+
+ // functions
+ void change_horizontal_sync(bool line);
+ void change_field_sync(bool line);
+ void update_field_sync_timer(void);
+ void next_scanline(void);
+ INT32 get_clocks_since_hsync();
+
+ // debugging
+ const char *scanline_zone_string(scanline_zone zone);
+};
+
+// actual base class for MC6847 family of devices
+class mc6847_base_device : public mc6847_friend_device
+{
+public:
+ /* updates the screen -- this will call begin_update(),
+ followed by update_row() reapeatedly and after all row
+ updating is complete, end_update() */
+ UINT32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
+
+ // mode changing operations
+ DECLARE_WRITE_LINE_MEMBER( ag_w ) { change_mode(MODE_AG, state); }
+ DECLARE_WRITE_LINE_MEMBER( gm2_w ) { change_mode(MODE_GM2, state); }
+ DECLARE_WRITE_LINE_MEMBER( gm1_w ) { change_mode(MODE_GM1, state); }
+ DECLARE_WRITE_LINE_MEMBER( gm0_w ) { change_mode(MODE_GM0, state); }
+ DECLARE_WRITE_LINE_MEMBER( as_w ) { change_mode(MODE_AS, state); }
+ DECLARE_WRITE_LINE_MEMBER( css_w ) { change_mode(MODE_CSS, state); }
+ DECLARE_WRITE_LINE_MEMBER( intext_w ) { change_mode(MODE_INTEXT, state); }
+ DECLARE_WRITE_LINE_MEMBER( inv_w ) { change_mode(MODE_INV, state); }
+
+protected:
+ mc6847_base_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const UINT8 *fontdata, double tpfs);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+ virtual ioport_constructor device_input_ports() const;
+
+ // other overrides
+ virtual void field_sync_changed(bool line);
+ virtual void record_body_scanline(UINT16 physical_scanline, UINT16 scanline);
+ virtual void record_partial_body_scanline(UINT16 physical_scanline, UINT16 logical_scanline, INT32 start_clock, INT32 end_clock);
+
+private:
+ struct video_scanline
+ {
+ UINT8 m_sample_count;
+ UINT8 m_mode[32];
+ UINT8 m_data[32];
+ };
+
+ // palette
+ static const int PALETTE_LENGTH = 16;
+ static const UINT32 s_palette[PALETTE_LENGTH];
+
+ // callbacks
+ devcb_resolved_read8 m_res_input_func;
+ UINT8 (*m_get_char_rom)(running_machine &machine, UINT8 ch, int line);
+
+ // incidentals
+ UINT8 m_fixed_mode;
+ UINT8 m_fixed_mode_mask;
+ const pixel_t *m_palette;
+ pixel_t m_bw_palette[PALETTE_LENGTH];
+
+ // state
+ UINT8 m_mode;
+ UINT16 m_video_address;
+ bool m_dirty;
+ video_scanline m_data[192];
+
+ void change_mode(UINT8 mode, int state)
+ {
+ // sanity check, to ensure that we're not changing fixed modes
+ assert((mode & m_fixed_mode_mask) == 0);
+
+ // calculate new mode
+ UINT8 new_mode;
+ if (state)
+ new_mode = m_mode | mode;
+ else
+ new_mode = m_mode & ~mode;
+
+ // has the mode changed?
+ if (new_mode != m_mode)
+ {
+ // it has! check dirty flag
+ video_flush();
+ if (!m_dirty)
+ {
+ m_dirty = true;
+ }
+
+ // and set the new mode
+ m_mode = new_mode;
+ }
+ }
+
+ // setup functions
+ void setup_fixed_mode(struct devcb_read_line callback, UINT8 mode);
+
+ // runtime functions
+ void record_body_scanline(UINT16 physical_scanline, UINT16 scanline, INT32 start_pos, INT32 end_pos);
+ pixel_t border_value(UINT8 mode, const pixel_t *palette, bool is_mc6847t1);
+
+ template<int xscale>
+ void emit_samples(UINT8 mode, const UINT8 *data, int length, pixel_t *pixels, int x, int y);
+
+ // template function for doing video update collection
+ template<int sample_count, int yres>
+ void record_scanline_res(int scanline, INT32 start_pos, INT32 end_pos);
+
+ // miscellaneous
+ UINT8 input(UINT16 address);
+ INT32 scanline_position_from_clock(INT32 clocks_since_hsync);
+};
+
+
+//**************************************************************************
+// VARIATIONS
+//**************************************************************************
+
+class mc6847_ntsc_device : public mc6847_base_device
+{
+public:
+ mc6847_ntsc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+};
+
+class mc6847_pal_device : public mc6847_base_device
+{
+public:
+ mc6847_pal_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+};
+
+class mc6847y_ntsc_device : public mc6847_base_device
+{
+public:
+ mc6847y_ntsc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+};
+
+class mc6847y_pal_device : public mc6847_base_device
+{
+public:
+ mc6847y_pal_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+};
+
+class mc6847t1_ntsc_device : public mc6847_base_device
+{
+public:
+ mc6847t1_ntsc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+};
+
+class mc6847t1_pal_device : public mc6847_base_device
+{
+public:
+ mc6847t1_pal_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+};
+
+
+extern const device_type MC6847_NTSC;
+extern const device_type MC6847_PAL;
+extern const device_type MC6847Y_NTSC;
+extern const device_type MC6847Y_PAL;
+extern const device_type MC6847T1_NTSC;
+extern const device_type MC6847T1_PAL;
+
+#endif /* __MC6847__ */
diff --git a/src/emu/video/tms3556.c b/src/emu/video/tms3556.c
new file mode 100644
index 00000000000..03f2ef1f2ca
--- /dev/null
+++ b/src/emu/video/tms3556.c
@@ -0,0 +1,588 @@
+/*
+ tms3556 emulation
+
+ TODO:
+ * implement remaining flags in control registers
+ * test the whole thing
+ * find the bloody tms3556 manual. I mean the register and VRAM interfaces
+ are mostly guesswork full of hacks, and I'd like to compare it with
+ documentation.
+
+ Raphael Nabet, 2004
+*/
+
+#include "emu.h"
+#include "tms3556.h"
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+#define LOG 0
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+// devices
+const device_type TMS3556 = &device_creator<tms3556_device>;
+
+
+// default address map
+static ADDRESS_MAP_START( tms3556, AS_0, 8, tms3556_device )
+ AM_RANGE(0x0000, 0xffff) AM_RAM
+ADDRESS_MAP_END
+
+//-------------------------------------------------
+// memory_space_config - return a description of
+// any address spaces owned by this device
+//-------------------------------------------------
+
+const address_space_config *tms3556_device::memory_space_config(address_spacenum spacenum) const
+{
+ return (spacenum == AS_0) ? &m_space_config : NULL;
+}
+
+
+//**************************************************************************
+// INLINE HELPERS
+//**************************************************************************
+
+//-------------------------------------------------
+// readbyte - read a byte at the given address
+//-------------------------------------------------
+
+inline UINT8 tms3556_device::readbyte(offs_t address)
+{
+ return space().read_byte(address);
+}
+
+
+//-------------------------------------------------
+// writebyte - write a byte at the given address
+//-------------------------------------------------
+
+inline void tms3556_device::writebyte(offs_t address, UINT8 data)
+{
+ space().write_byte(address, data);
+}
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// tms3556_device - constructor
+//-------------------------------------------------
+
+tms3556_device::tms3556_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, TMS3556, "Texas Instruments VDP TMS3556", tag, owner, clock),
+ device_memory_interface(mconfig, *this),
+ m_space_config("videoram", ENDIANNESS_LITTLE, 8, 17, 0, NULL, *ADDRESS_MAP_NAME(tms3556)),
+ m_write_ptr(0),
+ m_reg_ptr(0),
+ m_reg_access_phase(0),
+ m_magical_mystery_flag(0),
+ m_scanline(0),
+ m_blink(0),
+ m_blink_count(0)
+{
+ for (int i = 0; i < 8; i++)
+ {
+ m_control_regs[i] = 0;
+ m_address_regs[i] = 0;
+ }
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void tms3556_device::device_start()
+{
+ // register for state saving
+ save_item(NAME(m_control_regs));
+ save_item(NAME(m_address_regs));
+ save_item(NAME(m_write_ptr));
+ save_item(NAME(m_reg_ptr));
+ save_item(NAME(m_reg_access_phase));
+ save_item(NAME(m_magical_mystery_flag));
+ save_item(NAME(m_scanline));
+ save_item(NAME(m_blink));
+ save_item(NAME(m_blink_count));
+ save_item(NAME(m_bg_color));
+ save_item(NAME(m_name_offset));
+ save_item(NAME(m_cg_flag));
+ save_item(NAME(m_char_line_counter));
+ save_item(NAME(m_dbl_h_phase));
+
+ machine().primary_screen->register_screen_bitmap(m_bitmap);
+}
+
+
+/*static const char *const tms3556_mode_names[] = { "DISPLAY OFF", "TEXT", "GRAPHIC", "MIXED" };*/
+
+
+UINT32 tms3556_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
+{
+ copybitmap(bitmap, m_bitmap, 0, 0, 0, 0, cliprect);
+ return 0;
+}
+
+
+//-------------------------------------------------
+// vram_r - VRAM read
+//-------------------------------------------------
+
+READ8_MEMBER( tms3556_device::vram_r )
+{
+ if (LOG) logerror("TMS3556 VRAM Read: %06x\n", offset);
+
+ if (m_magical_mystery_flag)
+ {
+ m_write_ptr = ((m_control_regs[2] << 8) | m_control_regs[1]) + 1;
+ m_magical_mystery_flag = 0;
+ }
+
+ return readbyte(m_address_regs[1]++);
+}
+
+//-------------------------------------------------
+// vram_w - VRAM write
+//-------------------------------------------------
+
+WRITE8_MEMBER( tms3556_device::vram_w )
+{
+ if (LOG) logerror("TMS3556 VRAM Write: %06x = %02x\n", offset, data);
+
+ if (m_magical_mystery_flag)
+ {
+ m_write_ptr = (m_control_regs[2] << 8) | m_control_regs[1];
+ m_magical_mystery_flag = 0;
+ }
+
+ writebyte(m_write_ptr++, data);
+}
+
+
+//-------------------------------------------------
+// reg_r - read from register port
+//-------------------------------------------------
+
+READ8_MEMBER( tms3556_device::reg_r )
+{
+ if (LOG) logerror("TMS3556 Reg Read: %06x\n", offset);
+
+ int reply = 0;
+
+ if (m_reg_ptr < 8)
+ {
+ reply = m_control_regs[m_reg_ptr];
+ m_reg_access_phase = 0;
+ }
+ else
+ {
+ // ???
+ }
+
+ return reply;
+}
+
+//-------------------------------------------------
+// reg_w - write to register port
+//-------------------------------------------------
+
+WRITE8_MEMBER( tms3556_device::reg_w )
+{
+ if (LOG) logerror("TMS3556 Reg Write: %06x = %02x\n", offset, data);
+
+ if ((m_reg_access_phase == 3) && (data))
+ m_reg_access_phase = 0; /* ???????????? */
+
+ switch (m_reg_access_phase)
+ {
+ case 0:
+ m_reg_ptr = data & 0x0f;
+ m_reg_access_phase = 1;
+ break;
+
+ case 1:
+ if (m_reg_ptr < 8)
+ {
+ m_control_regs[m_reg_ptr] = data;
+ m_reg_access_phase = 0;
+ if (m_reg_ptr == 2)
+ m_magical_mystery_flag = 1;
+ }
+ else if (m_reg_ptr == 9)
+ { /* I don't understand what is going on, but it is the only way to
+ get this to work */
+ m_address_regs[m_reg_ptr - 8] = ((m_control_regs[2] << 8) | m_control_regs[1]) + 1;
+ m_reg_access_phase = 0;
+ m_magical_mystery_flag = 0;
+ }
+ else
+ {
+ m_address_regs[m_reg_ptr - 8] = (m_control_regs[m_reg_ptr - 8] & 0xff00) | m_control_regs[1];
+ m_reg_access_phase = 2;
+ m_magical_mystery_flag = 0;
+ }
+ break;
+
+ case 2:
+ m_address_regs[m_reg_ptr - 8] = (m_control_regs[m_reg_ptr - 8] & 0x00ff) | (m_control_regs[2] << 8);
+ if ((m_reg_ptr <= 10) || (m_reg_ptr == 15))
+ m_address_regs[m_reg_ptr - 8]++;
+ else
+ m_address_regs[m_reg_ptr - 8] += 2;
+ m_reg_access_phase = 3;
+ break;
+
+ case 3:
+ m_reg_access_phase = 0;
+ break;
+ }
+}
+
+
+//-------------------------------------------------
+// redraw code
+//-------------------------------------------------
+
+
+//-------------------------------------------------
+// draw_line_empty - draw an empty line (used for
+// top and bottom borders, and screen off mode)
+//-------------------------------------------------
+
+void tms3556_device::draw_line_empty(UINT16 *ln)
+{
+ int i;
+
+ for (i = 0; i < TMS3556_TOTAL_WIDTH; i++)
+#if TMS3556_DOUBLE_WIDTH
+ *ln++ = m_bg_color;
+#endif
+ *ln++ = m_bg_color;
+}
+
+
+//-------------------------------------------------
+// draw_line_text_common - draw a line of text
+// (called by draw_line_text and draw_line_mixed)
+//-------------------------------------------------
+
+void tms3556_device::draw_line_text_common(UINT16 *ln)
+{
+ int pattern, x, xx, i, name_offset;
+ UINT16 fg, bg;
+ offs_t nametbl_base;
+ offs_t patterntbl_base[4];
+ int name_hi, name_lo;
+ int pattern_ix;
+ int alphanumeric_mode, dbl_w, dbl_h, dbl_w_phase = 0;
+
+ nametbl_base = m_address_regs[2];
+ for (i = 0; i < 4; i++)
+ patterntbl_base[i] = m_address_regs[i + 3];
+
+ for (xx = 0; xx < TMS3556_LEFT_BORDER; xx++)
+#if TMS3556_DOUBLE_WIDTH
+ *ln++ = m_bg_color;
+#endif
+ *ln++ = m_bg_color;
+
+ name_offset = m_name_offset;
+
+ for (x = 0; x < 40; x++)
+ {
+ name_hi = readbyte(nametbl_base + name_offset);
+ name_lo = readbyte(nametbl_base + name_offset + 1);
+ pattern_ix = ((name_hi >> 2) & 2) | ((name_hi >> 4) & 1);
+ alphanumeric_mode = (pattern_ix < 2) || ((pattern_ix == 3) && !(m_control_regs[7] & 0x08));
+ fg = (name_hi >> 5) & 0x7;
+ if (alphanumeric_mode)
+ {
+ if (name_hi & 4)
+ { /* inverted color */
+ bg = fg;
+ fg = m_bg_color;
+ }
+ else
+ bg = m_bg_color;
+ dbl_w = name_hi & 0x2;
+ dbl_h = name_hi & 0x1;
+ }
+ else
+ {
+ bg = name_hi & 0x7;
+ dbl_w = 0;
+ dbl_h = 0;
+ }
+ if ((name_lo & 0x80) && m_blink)
+ fg = bg; /* blink off time */
+ if (! dbl_h)
+ { /* single height */
+ pattern = readbyte(patterntbl_base[pattern_ix] + (name_lo & 0x7f) + 128 * m_char_line_counter);
+ if (m_char_line_counter == 0)
+ m_dbl_h_phase[x] = 0;
+ }
+ else
+ { /* double height */
+ if (! m_dbl_h_phase[x])
+ /* first phase: pattern from upper half */
+ pattern = readbyte(patterntbl_base[pattern_ix] + (name_lo & 0x7f) + 128 * (5 + (m_char_line_counter >> 1)));
+ else
+ /* second phase: pattern from lower half */
+ pattern = readbyte(patterntbl_base[pattern_ix] + (name_lo & 0x7f) + 128 * (m_char_line_counter >> 1));
+ if (m_char_line_counter == 0)
+ m_dbl_h_phase[x] = !m_dbl_h_phase[x];
+ }
+ if (!dbl_w)
+ { /* single width */
+ for (xx = 0; xx < 8; xx++)
+ {
+ UINT16 color = (pattern & 0x80) ? fg : bg;
+#if TMS3556_DOUBLE_WIDTH
+ *ln++ = color;
+#endif
+ *ln++ = color;
+ pattern <<= 1;
+ }
+ dbl_w_phase = 0;
+ }
+ else
+ { /* double width */
+ if (dbl_w_phase)
+ /* second phase: display right half */
+ pattern <<= 4;
+ for (xx = 0; xx < 4; xx++)
+ {
+ UINT16 color = (pattern & 0x80) ? fg : bg;
+#if TMS3556_DOUBLE_WIDTH
+ *ln++ = color; *ln++ = color;
+#endif
+ *ln++ = color; *ln++ = color;
+ pattern <<= 1;
+ }
+ dbl_w_phase = !dbl_w_phase;
+ }
+ name_offset += 2;
+ }
+
+ for (xx = 0; xx < TMS3556_RIGHT_BORDER; xx++)
+#if TMS3556_DOUBLE_WIDTH
+ *ln++ = m_bg_color;
+#endif
+ *ln++ = m_bg_color;
+
+ if (m_char_line_counter == 0)
+ m_name_offset = name_offset;
+}
+
+
+//-------------------------------------------------
+// draw_line_bitmap_common - draw a line of bitmap
+// (called by draw_line_bitmap and draw_line_mixed)
+//-------------------------------------------------
+
+void tms3556_device::draw_line_bitmap_common(UINT16 *ln)
+{
+ int x, xx;
+ offs_t nametbl_base;
+ int name_b, name_g, name_r;
+
+ nametbl_base = m_address_regs[2];
+
+ for (xx = 0; xx < TMS3556_LEFT_BORDER; xx++)
+#if TMS3556_DOUBLE_WIDTH
+ *ln++ = m_bg_color;
+#endif
+ *ln++ = m_bg_color;
+
+ for (x = 0; x < 40; x++)
+ {
+ name_b = readbyte(nametbl_base + m_name_offset);
+ name_g = readbyte(nametbl_base + m_name_offset + 1);
+ name_r = readbyte(nametbl_base + m_name_offset + 2);
+ for (xx = 0; xx < 8; xx++)
+ {
+ UINT16 color = ((name_b >> 5) & 0x4) | ((name_g >> 6) & 0x2) | ((name_r >> 7) & 0x1);
+#if TMS3556_DOUBLE_WIDTH
+ *ln++ = color;
+#endif
+ *ln++ = color;
+ name_b <<= 1;
+ name_g <<= 1;
+ name_r <<= 1;
+ }
+ m_name_offset += 3;
+ }
+
+ for (xx = 0; xx < TMS3556_RIGHT_BORDER; xx++)
+#if TMS3556_DOUBLE_WIDTH
+ *ln++ = m_bg_color;
+#endif
+ *ln++ = m_bg_color;
+}
+
+
+//-------------------------------------------------
+// draw_line_text - draw a line in text mode
+//-------------------------------------------------
+
+void tms3556_device::draw_line_text(UINT16 *ln)
+{
+ if (m_char_line_counter == 0)
+ m_char_line_counter = 10;
+ m_char_line_counter--;
+ draw_line_text_common(ln);
+}
+
+
+//-------------------------------------------------
+// draw_line_bitmap - draw a line in bitmap mode
+//-------------------------------------------------
+
+void tms3556_device::draw_line_bitmap(UINT16 *ln)
+{
+ draw_line_bitmap_common(ln);
+ m_bg_color = (readbyte(m_address_regs[2] + m_name_offset) >> 5) & 0x7;
+ m_name_offset += 2;
+}
+
+
+//-------------------------------------------------
+// draw_line_mixed - draw a line in mixed mode
+//-------------------------------------------------
+
+void tms3556_device::draw_line_mixed(UINT16 *ln)
+{
+ if (m_cg_flag)
+ { /* bitmap line */
+ draw_line_bitmap_common(ln);
+ m_bg_color = (readbyte(m_address_regs[2] + m_name_offset) >> 5) & 0x7;
+ m_cg_flag = (readbyte(m_address_regs[2] + m_name_offset) >> 4) & 0x1;
+ m_name_offset += 2;
+ }
+ else
+ { /* text line */
+ if (m_char_line_counter == 0)
+ m_char_line_counter = 10;
+ m_char_line_counter--;
+ draw_line_text_common(ln);
+ if (m_char_line_counter == 0)
+ {
+ m_bg_color = (readbyte(m_address_regs[2] + m_name_offset) >> 5) & 0x7;
+ m_cg_flag = (readbyte(m_address_regs[2] + m_name_offset) >> 4) & 0x1;
+ m_name_offset += 2;
+ }
+ }
+}
+
+
+//-------------------------------------------------
+// draw_line - draw a line. If non-interlaced mode,
+// duplicate the line.
+//-------------------------------------------------
+
+void tms3556_device::draw_line(bitmap_ind16 &bmp, int line)
+{
+ int double_lines = 0;
+ UINT16 *ln, *ln2 = NULL;
+
+// if (m_control_regs[4] & 0x??)
+// { // interlaced mode
+// ln = &bmp->pix16(line, m_field);
+// }
+// else
+ { /* non-interlaced mode */
+ ln = &bmp.pix16(line);
+ ln2 = &bmp.pix16(line, 1);
+ double_lines = 1;
+ }
+
+ if ((line < TMS3556_TOP_BORDER) || (line >= (TMS3556_TOP_BORDER + 250)))
+ {
+ /* draw top and bottom borders */
+ draw_line_empty(ln);
+ }
+ else
+ {
+ /* draw useful area */
+ switch (m_control_regs[6] >> 6)
+ {
+ case TMS3556_MODE_OFF:
+ draw_line_empty(ln);
+ break;
+ case TMS3556_MODE_TEXT:
+ draw_line_text(ln);
+ break;
+ case TMS3556_MODE_BITMAP:
+ draw_line_bitmap(ln);
+ break;
+ case TMS3556_MODE_MIXED:
+ draw_line_mixed(ln);
+ break;
+ }
+ }
+
+ if (double_lines)
+ {
+ memcpy (ln2, ln, TMS3556_TOTAL_WIDTH * (TMS3556_DOUBLE_WIDTH ? 2 : 1));
+ }
+}
+
+
+//-------------------------------------------------
+// interrupt_start_vblank - Do vblank-time tasks
+//-------------------------------------------------
+
+void tms3556_device::interrupt_start_vblank(void)
+{
+ /* at every frame, vdp switches fields */
+ //m_field = !m_field;
+
+ /* color blinking */
+ if (m_blink_count)
+ m_blink_count--;
+ if (!m_blink_count)
+ {
+ m_blink = !m_blink;
+ m_blink_count = 60; /*no idea what the real value is*/
+ }
+ /* reset background color */
+ m_bg_color = (m_control_regs[7] >> 5) & 0x7;
+ /* reset name offset */
+ m_name_offset = 0;
+ /* reset character line counter */
+ m_char_line_counter = 0;
+ /* reset c/g flag */
+ m_cg_flag = 0;
+ /* reset double height phase flags */
+ memset(m_dbl_h_phase, 0, sizeof(m_dbl_h_phase));
+}
+
+
+//-------------------------------------------------
+// interrupt - scanline handler
+//-------------------------------------------------
+
+void tms3556_device::interrupt(running_machine &machine)
+{
+ /* check for start of vblank */
+ if (m_scanline == 310) /*no idea what the real value is*/
+ interrupt_start_vblank();
+
+ /* render the current line */
+ if ((m_scanline >= 0) && (m_scanline < TMS3556_TOTAL_HEIGHT))
+ {
+ //if (!video_skip_this_frame())
+ draw_line(m_bitmap, m_scanline);
+ }
+
+ if (++m_scanline == 313)
+ m_scanline = 0;
+}
diff --git a/src/emu/video/tms3556.h b/src/emu/video/tms3556.h
new file mode 100644
index 00000000000..3a91009bb16
--- /dev/null
+++ b/src/emu/video/tms3556.h
@@ -0,0 +1,112 @@
+/***************************************************************************
+
+ Texas Instruments TMS3556 Video Display Processor
+
+ ***************************************************************************/
+
+
+#pragma once
+
+#ifndef __TMS3556_H__
+#define __TMS3556_H__
+
+///*************************************************************************
+// MACROS / CONSTANTS
+///*************************************************************************
+
+#define TMS3556_TOP_BORDER 1
+#define TMS3556_BOTTOM_BORDER 1
+#define TMS3556_LEFT_BORDER 8
+#define TMS3556_RIGHT_BORDER 8
+#define TMS3556_TOTAL_WIDTH (320 + TMS3556_LEFT_BORDER + TMS3556_RIGHT_BORDER)
+#define TMS3556_TOTAL_HEIGHT (250 + TMS3556_TOP_BORDER + TMS3556_BOTTOM_BORDER)
+
+/* if DOUBLE_WIDTH set, the horizontal resolution is doubled */
+#define TMS3556_DOUBLE_WIDTH 1
+
+#define TMS3556_MODE_OFF 0
+#define TMS3556_MODE_TEXT 1
+#define TMS3556_MODE_BITMAP 2
+#define TMS3556_MODE_MIXED 3
+
+
+///*************************************************************************
+// INTERFACE CONFIGURATION MACROS
+///*************************************************************************
+
+#define MCFG_TMS3556_ADD(_tag) \
+ MCFG_DEVICE_ADD(_tag, TMS3556, 0)
+
+///*************************************************************************
+// TYPE DEFINITIONS
+///*************************************************************************
+
+// ======================> tms3556_device
+
+class tms3556_device : public device_t,
+ public device_memory_interface
+{
+public:
+ // construction/destruction
+ tms3556_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ DECLARE_READ8_MEMBER( vram_r );
+ DECLARE_WRITE8_MEMBER( vram_w );
+ DECLARE_READ8_MEMBER( reg_r );
+ DECLARE_WRITE8_MEMBER( reg_w );
+
+ void interrupt(running_machine &machine);
+
+ UINT32 screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+
+ // device_config_memory_interface overrides
+ virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const;
+
+ // address space configurations
+ const address_space_config m_space_config;
+
+ inline UINT8 readbyte(offs_t address);
+ inline void writebyte(offs_t address, UINT8 data);
+
+ void draw_line_empty(UINT16 *ln);
+ void draw_line_text_common(UINT16 *ln);
+ void draw_line_bitmap_common(UINT16 *ln);
+ void draw_line_text(UINT16 *ln);
+ void draw_line_bitmap(UINT16 *ln);
+ void draw_line_mixed(UINT16 *ln);
+ void draw_line(bitmap_ind16 &bmp, int line);
+ void interrupt_start_vblank(void);
+
+private:
+ // registers
+ UINT8 m_control_regs[8];
+ UINT16 m_address_regs[8];
+ UINT16 m_write_ptr;
+
+ // register interface
+ int m_reg_ptr;
+ int m_reg_access_phase;
+ int m_magical_mystery_flag;
+
+ int m_scanline; // scanline counter
+ int m_blink, m_blink_count; // blinking
+ int m_bg_color; // background color for current line
+ int m_name_offset; // current offset in name table
+ int m_cg_flag; // c/g flag (mixed mode only)
+ int m_char_line_counter; // character line counter (decrements from 10, 0 when we have reached
+ // last line of character row)
+ int m_dbl_h_phase[40]; // double height phase flags (one per horizontal character position)
+
+ bitmap_ind16 m_bitmap;
+};
+
+
+// device type definition
+extern const device_type TMS3556;
+
+
+#endif
diff --git a/src/emu/video/upd7220.c b/src/emu/video/upd7220.c
new file mode 100644
index 00000000000..d2000fc5416
--- /dev/null
+++ b/src/emu/video/upd7220.c
@@ -0,0 +1,1673 @@
+/**********************************************************************
+
+ Intel 82720 Graphics Display Controller emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+/*
+
+ TODO:
+
+ - implement FIFO as ring buffer
+ - commands
+ - DMAR
+ - DMAW
+ - incomplete / unimplemented FIGD / GCHRD draw modes
+ - Arc
+ - FIGD character
+ - slanted character
+ - GCHRD character (needs rewrite)
+ - read-modify-write cycle
+ - read data
+ - modify data
+ - write data
+ - QX-10 diagnostic test has positioning bugs with the bitmap display test;
+ - QX-10 diagnostic test misses the zooming factor (external pin);
+ - compis2 SAD address for bitmap is 0x20000 for whatever reason (presumably missing banking);
+ - A5105 has a FIFO bug with the RDAT, should be a lot larger when it scrolls up.
+ The problem is that DMA-ing with RDAT/WDAT shouldn't be instant;
+
+ - honor visible area
+ - wide mode (32-bit access)
+ - light pen
+
+*/
+
+#include "emu.h"
+#include "upd7220.h"
+
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+#define VERBOSE 0
+#define LOG(x) do { if (VERBOSE) logerror x; } while (0)
+
+
+// todo typedef
+enum
+{
+ COMMAND_INVALID = -1,
+ COMMAND_RESET,
+ COMMAND_SYNC,
+ COMMAND_VSYNC,
+ COMMAND_CCHAR,
+ COMMAND_START,
+ COMMAND_BCTRL,
+ COMMAND_ZOOM,
+ COMMAND_CURS,
+ COMMAND_PRAM,
+ COMMAND_PITCH,
+ COMMAND_WDAT,
+ COMMAND_MASK,
+ COMMAND_FIGS,
+ COMMAND_FIGD,
+ COMMAND_GCHRD,
+ COMMAND_RDAT,
+ COMMAND_CURD,
+ COMMAND_LPRD,
+ COMMAND_DMAR,
+ COMMAND_DMAW,
+ COMMAND_5A
+};
+
+enum
+{
+ FIFO_READ = 0,
+ FIFO_WRITE
+};
+
+enum
+{
+ FIFO_EMPTY = -1,
+ FIFO_PARAMETER,
+ FIFO_COMMAND
+};
+
+#define UPD7220_COMMAND_RESET 0x00
+#define UPD7220_COMMAND_SYNC 0x0e // & 0xfe
+#define UPD7220_COMMAND_VSYNC 0x6e // & 0xfe
+#define UPD7220_COMMAND_CCHAR 0x4b
+#define UPD7220_COMMAND_START 0x6b
+#define UPD7220_COMMAND_BCTRL 0x0c // & 0xfe
+#define UPD7220_COMMAND_ZOOM 0x46
+#define UPD7220_COMMAND_CURS 0x49
+#define UPD7220_COMMAND_PRAM 0x70 // & 0xf0
+#define UPD7220_COMMAND_PITCH 0x47
+#define UPD7220_COMMAND_WDAT 0x20 // & 0xe4
+#define UPD7220_COMMAND_MASK 0x4a
+#define UPD7220_COMMAND_FIGS 0x4c
+#define UPD7220_COMMAND_FIGD 0x6c
+#define UPD7220_COMMAND_GCHRD 0x68
+#define UPD7220_COMMAND_RDAT 0xa0 // & 0xe4
+#define UPD7220_COMMAND_CURD 0xe0
+#define UPD7220_COMMAND_LPRD 0xc0
+#define UPD7220_COMMAND_DMAR 0xa4 // & 0xe4
+#define UPD7220_COMMAND_DMAW 0x24 // & 0xe4
+#define UPD7220_COMMAND_5A 0x5a
+
+#define UPD7220_SR_DATA_READY 0x01
+#define UPD7220_SR_FIFO_FULL 0x02
+#define UPD7220_SR_FIFO_EMPTY 0x04
+#define UPD7220_SR_DRAWING_IN_PROGRESS 0x08
+#define UPD7220_SR_DMA_EXECUTE 0x10
+#define UPD7220_SR_VSYNC_ACTIVE 0x20
+#define UPD7220_SR_HBLANK_ACTIVE 0x40
+#define UPD7220_SR_LIGHT_PEN_DETECT 0x80
+
+#define UPD7220_MODE_S 0x01
+#define UPD7220_MODE_REFRESH_RAM 0x04
+#define UPD7220_MODE_I 0x08
+#define UPD7220_MODE_DRAW_ON_RETRACE 0x10
+#define UPD7220_MODE_DISPLAY_MASK 0x22
+#define UPD7220_MODE_DISPLAY_MIXED 0x00
+#define UPD7220_MODE_DISPLAY_GRAPHICS 0x02
+#define UPD7220_MODE_DISPLAY_CHARACTER 0x20
+#define UPD7220_MODE_DISPLAY_INVALID 0x22
+
+static const int x_dir[8] = { 0, 1, 1, 1, 0,-1,-1,-1};
+static const int y_dir[8] = { 1, 1, 0,-1,-1,-1, 0, 1};
+static const int x_dir_dot[8] = { 1, 1, 0,-1,-1,-1, 0, 1};
+static const int y_dir_dot[8] = { 0,-1,-1,-1, 0, 1, 1, 1};
+
+
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+// devices
+const device_type UPD7220 = &device_creator<upd7220_device>;
+
+
+// default address map
+static ADDRESS_MAP_START( upd7220_vram, AS_0, 8, upd7220_device )
+ AM_RANGE(0x00000, 0x3ffff) AM_RAM
+ADDRESS_MAP_END
+
+
+// internal 128x14 control ROM
+ROM_START( upd7220 )
+ ROM_REGION( 0x100, "upd7220", 0 )
+ ROM_LOAD( "upd7220.bin", 0x000, 0x100, NO_DUMP )
+ROM_END
+
+
+//-------------------------------------------------
+// memory_space_config - return a description of
+// any address spaces owned by this device
+//-------------------------------------------------
+
+const address_space_config *upd7220_device::memory_space_config(address_spacenum spacenum) const
+{
+ return (spacenum == AS_0) ? &m_space_config : NULL;
+}
+
+
+//-------------------------------------------------
+// rom_region - device-specific ROM region
+//-------------------------------------------------
+
+const rom_entry *upd7220_device::device_rom_region() const
+{
+ return ROM_NAME( upd7220 );
+}
+
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void upd7220_device::device_config_complete()
+{
+ // inherit a copy of the static data
+ const upd7220_interface *intf = reinterpret_cast<const upd7220_interface *>(static_config());
+ if (intf != NULL)
+ *static_cast<upd7220_interface *>(this) = *intf;
+
+ // or initialize to defaults if none provided
+ else
+ {
+ memset(&m_out_drq_cb, 0, sizeof(m_out_drq_cb));
+ memset(&m_out_hsync_cb, 0, sizeof(m_out_hsync_cb));
+ memset(&m_out_vsync_cb, 0, sizeof(m_out_vsync_cb));
+ memset(&m_out_blank_cb, 0, sizeof(m_out_blank_cb));
+ }
+}
+
+
+
+//**************************************************************************
+// INLINE HELPERS
+//**************************************************************************
+
+//-------------------------------------------------
+// readbyte - read a byte at the given address
+//-------------------------------------------------
+
+inline UINT8 upd7220_device::readbyte(offs_t address)
+{
+ return space().read_byte(address);
+}
+
+
+//-------------------------------------------------
+// writebyte - write a byte at the given address
+//-------------------------------------------------
+
+inline void upd7220_device::writebyte(offs_t address, UINT8 data)
+{
+ space().write_byte(address, data);
+}
+
+
+//-------------------------------------------------
+// fifo_clear -
+//-------------------------------------------------
+
+inline void upd7220_device::fifo_clear()
+{
+ for (int i = 0; i < 16; i++)
+ {
+ m_fifo[i] = 0;
+ m_fifo_flag[i] = FIFO_EMPTY;
+ }
+
+ m_fifo_ptr = -1;
+
+ m_sr &= ~UPD7220_SR_DATA_READY;
+ m_sr |= UPD7220_SR_FIFO_EMPTY;
+ m_sr &= ~UPD7220_SR_FIFO_FULL;
+}
+
+
+//-------------------------------------------------
+// fifo_param_count -
+//-------------------------------------------------
+
+inline int upd7220_device::fifo_param_count()
+{
+ int i;
+
+ for (i = 0; i < 16; i++)
+ {
+ if (m_fifo_flag[i] != FIFO_PARAMETER) break;
+ }
+
+ return i;
+}
+
+
+//-------------------------------------------------
+// fifo_set_direction -
+//-------------------------------------------------
+
+inline void upd7220_device::fifo_set_direction(int dir)
+{
+ if (m_fifo_dir != dir)
+ {
+ fifo_clear();
+ }
+
+ m_fifo_dir = dir;
+}
+
+
+//-------------------------------------------------
+// queue -
+//-------------------------------------------------
+
+inline void upd7220_device::queue(UINT8 data, int flag)
+{
+ if (m_fifo_ptr < 15)
+ {
+ m_fifo_ptr++;
+
+ m_fifo[m_fifo_ptr] = data;
+ m_fifo_flag[m_fifo_ptr] = flag;
+
+ if (m_fifo_ptr == 16)
+ {
+ m_sr |= UPD7220_SR_FIFO_FULL;
+ }
+
+ m_sr &= ~UPD7220_SR_FIFO_EMPTY;
+ }
+ else
+ {
+ // TODO what happen? somebody set us up the bomb
+ printf("FIFO?\n");
+ }
+}
+
+
+//-------------------------------------------------
+// dequeue -
+//-------------------------------------------------
+
+inline void upd7220_device::dequeue(UINT8 *data, int *flag)
+{
+ *data = m_fifo[0];
+ *flag = m_fifo_flag[0];
+
+ if (m_fifo_ptr > -1)
+ {
+ for (int i = 0; i < 15; i++)
+ {
+ m_fifo[i] = m_fifo[i + 1];
+ m_fifo_flag[i] = m_fifo_flag[i + 1];
+ }
+
+ m_fifo[15] = 0;
+ m_fifo_flag[15] = 0;
+
+ m_fifo_ptr--;
+
+ if (m_fifo_ptr == -1)
+ {
+ m_sr &= ~UPD7220_SR_DATA_READY;
+ m_sr |= UPD7220_SR_FIFO_EMPTY;
+ }
+ }
+}
+
+
+//-------------------------------------------------
+// update_vsync_timer -
+//-------------------------------------------------
+
+inline void upd7220_device::update_vsync_timer(int state)
+{
+ int next_y = state ? m_vs : 0;
+
+ attotime duration = m_screen->time_until_pos(next_y, 0);
+
+ m_vsync_timer->adjust(duration, !state);
+}
+
+
+//-------------------------------------------------
+// update_hsync_timer -
+//-------------------------------------------------
+
+inline void upd7220_device::update_hsync_timer(int state)
+{
+ int y = m_screen->vpos();
+
+ int next_x = state ? m_hs : 0;
+ int next_y = state ? y : ((y + 1) % m_al);
+
+ attotime duration = m_screen->time_until_pos(next_y, next_x);
+
+ m_hsync_timer->adjust(duration, !state);
+}
+
+
+//-------------------------------------------------
+// update_blank_timer -
+//-------------------------------------------------
+
+inline void upd7220_device::update_blank_timer(int state)
+{
+ int y = m_screen->vpos();
+
+ int next_x = state ? (m_hs + m_hbp) : (m_hs + m_hbp + (m_aw << 3));
+ int next_y = state ? ((y + 1) % (m_vs + m_vbp + m_al + m_vfp - 1)) : y;
+
+ attotime duration = m_screen->time_until_pos(next_y, next_x);
+
+ m_hsync_timer->adjust(duration, !state);
+}
+
+
+//-------------------------------------------------
+// recompute_parameters -
+//-------------------------------------------------
+
+inline void upd7220_device::recompute_parameters()
+{
+ /* TODO: assume that the pitch also controls number of horizontal pixels in a single cell */
+ int horiz_mult = ((m_pitch == 40) ? 16 : 8);
+ int horiz_pix_total = (m_hs + m_hbp + m_aw + m_hfp) * horiz_mult;
+ int vert_pix_total = m_vs + m_vbp + m_al + m_vfp;
+
+ //printf("%d %d %d %d\n",m_hs,m_hbp,m_aw,m_hfp);
+ //printf("%d %d\n",m_aw * 8,m_pitch * 8);
+
+ if (horiz_pix_total == 0 || vert_pix_total == 0) //bail out if screen params aren't valid
+ return;
+
+ attoseconds_t refresh = HZ_TO_ATTOSECONDS(clock() * horiz_mult) * horiz_pix_total * vert_pix_total;
+
+ rectangle visarea;
+
+ visarea.min_x = 0; //(m_hs + m_hbp) * 8;
+ visarea.min_y = 0; //m_vs + m_vbp;
+ visarea.max_x = m_aw * horiz_mult - 1;//horiz_pix_total - (m_hfp * 8) - 1;
+ visarea.max_y = m_al - 1;//vert_pix_total - m_vfp - 1;
+
+ LOG(("uPD7220 '%s' Screen: %u x %u @ %f Hz\n", tag(), horiz_pix_total, vert_pix_total, 1 / ATTOSECONDS_TO_DOUBLE(refresh)));
+ LOG(("Visible Area: (%u, %u) - (%u, %u)\n", visarea.min_x, visarea.min_y, visarea.max_x, visarea.max_y));
+ LOG(("%d %d %d %d %d\n",m_hs,m_hbp,m_aw,m_hfp,m_pitch));
+ LOG(("%d %d %d %d\n",m_vs,m_vbp,m_al,m_vfp));
+
+ if (m_m)
+ {
+ m_screen->configure(horiz_pix_total, vert_pix_total, visarea, refresh);
+
+ update_hsync_timer(0);
+ update_vsync_timer(0);
+ }
+ else
+ {
+ m_hsync_timer->enable(0);
+ m_vsync_timer->enable(0);
+ }
+
+ update_blank_timer(0);
+}
+
+
+//-------------------------------------------------
+// reset_figs_param -
+//-------------------------------------------------
+
+inline void upd7220_device::reset_figs_param()
+{
+ m_figs.m_dc = 0x0000;
+ m_figs.m_d = 0x0008;
+ m_figs.m_d1 = 0x0008;
+ m_figs.m_d2 = 0x0000;
+ m_figs.m_dm = 0x0000;
+}
+
+
+//-------------------------------------------------
+// advance_ead -
+//-------------------------------------------------
+
+inline void upd7220_device::advance_ead()
+{
+ #define EAD m_ead
+ #define DAD m_dad
+ #define P x_dir[m_figs.m_dir] + (y_dir[m_figs.m_dir] * m_pitch)
+ #define MSB(value) (BIT(value, 15))
+ #define LSB(value) (BIT(value, 0))
+ #define LR(value) ((value << 1) | MSB(value))
+ #define RR(value) ((LSB(value) << 15) | (value >> 1))
+
+ switch (m_draw_mode & 0x07)
+ {
+ case 0:
+ EAD += P;
+ break;
+
+ case 1:
+ EAD += P;
+ if (MSB(DAD)) EAD++;
+ DAD = LR(DAD);
+ break;
+
+ case 2:
+ if (MSB(DAD)) EAD++;
+ DAD = LR(DAD);
+ break;
+
+ case 3:
+ EAD -= P;
+ if (MSB(DAD)) EAD++;
+ DAD = LR(DAD);
+ break;
+
+ case 4:
+ EAD -= P;
+ break;
+
+ case 5:
+ EAD -= P;
+ if (LSB(DAD)) EAD--;
+ DAD = RR(DAD);
+ break;
+
+ case 6:
+ if (LSB(DAD)) EAD--;
+ DAD = RR(DAD);
+ break;
+
+ case 7:
+ EAD += P;
+ if (LSB(DAD)) EAD--;
+ DAD = RR(DAD);
+ break;
+ }
+
+ EAD &= 0x3ffff;
+}
+
+
+//-------------------------------------------------
+// read_vram -
+//-------------------------------------------------
+
+inline void upd7220_device::read_vram(UINT8 type, UINT8 mod)
+{
+ if (type == 1)
+ {
+ LOG (("uPD7220 invalid type 1 RDAT parameter\n"));
+ return;
+ }
+
+ if (mod)
+ LOG (("uPD7220 RDAT used with mod = %02x?\n",mod));
+
+ for (int i = 0; i < m_figs.m_dc; i++)
+ {
+ switch(type)
+ {
+ case 0:
+ queue(readbyte(m_ead*2), 0);
+ queue(readbyte(m_ead*2+1), 0);
+ break;
+ case 2:
+ queue(readbyte(m_ead*2), 0);
+ break;
+ case 3:
+ queue(readbyte(m_ead*2+1), 0);
+ break;
+ }
+
+ advance_ead();
+ }
+}
+
+
+//-------------------------------------------------
+// write_vram -
+//-------------------------------------------------
+
+inline void upd7220_device::write_vram(UINT8 type, UINT8 mod)
+{
+ UINT16 result;
+
+ if (type == 1)
+ {
+ printf("uPD7220 invalid type 1 WDAT parameter\n");
+ return;
+ }
+
+ result = 0;
+
+ switch(type)
+ {
+ case 0:
+ result = (m_pr[1] & 0xff);
+ result |= (m_pr[2] << 8);
+ result &= m_mask;
+ break;
+ case 2:
+ result = (m_pr[1] & 0xff);
+ result &= (m_mask & 0xff);
+ break;
+ case 3:
+ result = (m_pr[1] << 8);
+ result &= (m_mask & 0xff00);
+ break;
+ }
+
+ //if(result)
+ {
+ //printf("%04x %02x %02x %04x %02x %02x\n",readbyte(m_ead),m_pr[1],m_pr[2],m_mask,type,mod);
+ //printf("%04x %02x %02x\n",m_ead,m_figs.m_dir,m_pitch);
+ //printf("%04x %04x %02x %04x\n",m_ead,result,mod,m_figs.m_dc);
+ }
+
+ for(int i = 0; i < m_figs.m_dc + 1; i++)
+ {
+ switch(mod & 3)
+ {
+ case 0x00: //replace
+ if(type == 0 || type == 2)
+ writebyte(m_ead*2+0, result & 0xff);
+ if(type == 0 || type == 3)
+ writebyte(m_ead*2+1, result >> 8);
+ break;
+ case 0x01: //complement
+ if(type == 0 || type == 2)
+ writebyte(m_ead*2+0, readbyte(m_ead*2+0) ^ (result & 0xff));
+ if(type == 0 || type == 3)
+ writebyte(m_ead*2+1, readbyte(m_ead*2+1) ^ (result >> 8));
+ break;
+ case 0x02: //reset to zero
+ if(type == 0 || type == 2)
+ writebyte(m_ead*2+0, readbyte(m_ead*2+0) & ~(result & 0xff));
+ if(type == 0 || type == 3)
+ writebyte(m_ead*2+1, readbyte(m_ead*2+1) & ~(result >> 8));
+ break;
+ case 0x03: //set to one
+ if(type == 0 || type == 2)
+ writebyte(m_ead*2+0, readbyte(m_ead*2+0) | (result & 0xff));
+ if(type == 0 || type == 3)
+ writebyte(m_ead*2+1, readbyte(m_ead*2+1) | (result >> 8));
+ break;
+ }
+
+ advance_ead();
+ }
+}
+
+
+//-------------------------------------------------
+// check_pattern -
+//-------------------------------------------------
+
+inline UINT16 upd7220_device::check_pattern(UINT16 pattern)
+{
+ UINT16 res = 0;
+
+ switch (m_bitmap_mod & 3)
+ {
+ case 0: res = pattern; break; //replace
+ case 1: res = pattern; break; //complement
+ case 2: res = 0; break; //reset to zero
+ case 3: res |= 0xffff; break; //set to one
+ }
+
+ return res;
+}
+
+
+//-------------------------------------------------
+// get_text_partition -
+//-------------------------------------------------
+
+inline void upd7220_device::get_text_partition(int index, UINT32 *sad, UINT16 *len, int *im, int *wd)
+{
+ *sad = ((m_ra[(index * 4) + 1] & 0x1f) << 8) | m_ra[(index * 4) + 0];
+ *len = ((m_ra[(index * 4) + 3] & 0x3f) << 4) | (m_ra[(index * 4) + 2] >> 4);
+ *im = BIT(m_ra[(index * 4) + 3], 6);
+ *wd = BIT(m_ra[(index * 4) + 3], 7);
+}
+
+
+//-------------------------------------------------
+// get_graphics_partition -
+//-------------------------------------------------
+
+inline void upd7220_device::get_graphics_partition(int index, UINT32 *sad, UINT16 *len, int *im, int *wd)
+{
+ *sad = ((m_ra[(index * 4) + 2] & 0x03) << 16) | (m_ra[(index * 4) + 1] << 8) | m_ra[(index * 4) + 0];
+ *len = ((m_ra[(index * 4) + 3] & 0x3f) << 4) | (m_ra[(index * 4) + 2] >> 4);
+ *im = BIT(m_ra[(index * 4) + 3], 6);
+ *wd = BIT(m_ra[(index * 4) + 3], 7);
+}
+
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// upd7220_device - constructor
+//-------------------------------------------------
+
+upd7220_device::upd7220_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, UPD7220, "uPD7220", tag, owner, clock),
+ device_memory_interface(mconfig, *this),
+ m_mask(0),
+ m_pitch(0),
+ m_ead(0),
+ m_dad(0),
+ m_lad(0),
+ m_ra_addr(0),
+ m_sr(UPD7220_SR_FIFO_EMPTY),
+ m_cr(0),
+ m_param_ptr(0),
+ m_fifo_ptr(-1),
+ m_fifo_dir(0),
+ m_mode(0),
+ m_draw_mode(0),
+ m_de(0),
+ m_m(0),
+ m_aw(0),
+ m_al(0),
+ m_vs(0),
+ m_vfp(0),
+ m_vbp(0),
+ m_hs(0),
+ m_hfp(0),
+ m_hbp(0),
+ m_dc(0),
+ m_sc(0),
+ m_br(0),
+ m_ctop(0),
+ m_cbot(0),
+ m_lr(0),
+ m_disp(0),
+ m_gchr(0),
+ m_bitmap_mod(0),
+ m_space_config("videoram", ENDIANNESS_LITTLE, 8, 18, 0, NULL, *ADDRESS_MAP_NAME(upd7220_vram))
+{
+ m_shortname = "upd7220";
+ for (int i = 0; i < 16; i++)
+ {
+ m_fifo[i] = 0;
+ m_fifo_flag[i] = FIFO_EMPTY;
+
+ m_ra[i] = 0;
+ }
+
+ for (int i = 0; i < 17; i++)
+ {
+ m_pr[i] = 0;
+ }
+
+ m_figs.m_dir = 0;
+ m_figs.m_figure_type = 0;
+ m_figs.m_dc = 0;
+ m_figs.m_d = 0;
+ m_figs.m_d1 = 0;
+ m_figs.m_d2 = 0;
+ m_figs.m_dm = 0;
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void upd7220_device::device_start()
+{
+ // allocate timers
+ m_vsync_timer = timer_alloc(TIMER_VSYNC);
+ m_hsync_timer = timer_alloc(TIMER_HSYNC);
+ m_blank_timer = timer_alloc(TIMER_BLANK);
+
+ // resolve callbacks
+ m_out_drq_func.resolve(m_out_drq_cb, *this);
+ m_out_hsync_func.resolve(m_out_hsync_cb, *this);
+ m_out_vsync_func.resolve(m_out_vsync_cb, *this);
+ m_out_blank_func.resolve(m_out_blank_cb, *this);
+
+ // find screen
+ m_screen = machine().device<screen_device>(m_screen_tag);
+
+ if (m_screen == NULL)
+ {
+ m_screen = owner()->subdevice<screen_device>(m_screen_tag);
+ }
+
+ assert(m_screen);
+
+ // register for state saving
+ save_item(NAME(m_ra));
+ save_item(NAME(m_sr));
+ save_item(NAME(m_mode));
+ save_item(NAME(m_de));
+ save_item(NAME(m_aw));
+ save_item(NAME(m_al));
+ save_item(NAME(m_vs));
+ save_item(NAME(m_vfp));
+ save_item(NAME(m_vbp));
+ save_item(NAME(m_hs));
+ save_item(NAME(m_hfp));
+ save_item(NAME(m_hbp));
+ save_item(NAME(m_m));
+ save_item(NAME(m_dc));
+ save_item(NAME(m_sc));
+ save_item(NAME(m_br));
+ save_item(NAME(m_lr));
+ save_item(NAME(m_ctop));
+ save_item(NAME(m_cbot));
+ save_item(NAME(m_ead));
+ save_item(NAME(m_dad));
+ save_item(NAME(m_lad));
+ save_item(NAME(m_disp));
+ save_item(NAME(m_gchr));
+ save_item(NAME(m_mask));
+ save_item(NAME(m_pitch));
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void upd7220_device::device_reset()
+{
+ m_out_drq_func(CLEAR_LINE);
+}
+
+
+//-------------------------------------------------
+// device_timer - handler timer events
+//-------------------------------------------------
+
+void upd7220_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+ switch (id)
+ {
+ case TIMER_HSYNC:
+ if (param)
+ {
+ m_sr |= UPD7220_SR_HBLANK_ACTIVE;
+ }
+ else
+ {
+ m_sr &= ~UPD7220_SR_HBLANK_ACTIVE;
+ }
+
+ m_out_hsync_func(param);
+
+ update_hsync_timer(param);
+ break;
+
+ case TIMER_VSYNC:
+ if (param)
+ {
+ m_sr |= UPD7220_SR_VSYNC_ACTIVE;
+ }
+ else
+ {
+ m_sr &= ~UPD7220_SR_VSYNC_ACTIVE;
+ }
+
+ m_out_vsync_func(param);
+
+ update_vsync_timer(param);
+ break;
+
+ case TIMER_BLANK:
+ if (param)
+ {
+ m_sr |= UPD7220_SR_HBLANK_ACTIVE;
+ }
+ else
+ {
+ m_sr &= ~UPD7220_SR_HBLANK_ACTIVE;
+ }
+
+ m_out_blank_func(param);
+
+ update_blank_timer(param);
+ break;
+ }
+}
+
+
+//-------------------------------------------------
+// draw_pixel -
+//-------------------------------------------------
+
+void upd7220_device::draw_pixel(int x, int y, UINT8 tile_data)
+{
+ UINT32 addr = (y * m_pitch * 2 + (x >> 3)) & 0x3ffff;
+ int dad = x & 0x7;
+ UINT8 data = readbyte(addr);
+ UINT8 new_pixel = (tile_data) & (0x80 >> (dad));
+
+ switch(m_bitmap_mod)
+ {
+ case 0: //replace
+ writebyte(addr, data & ~(0x80 >> (dad)));
+ writebyte(addr, data | new_pixel);
+ break;
+ case 1: //complement
+ writebyte(addr, data ^ (new_pixel));
+ break;
+ case 2: //reset
+ writebyte(addr, data & ((new_pixel) ? 0xff : ~(0x80 >> (dad))));
+ break;
+ case 3: //set
+ writebyte(addr, data | new_pixel);
+ break;
+ }
+}
+
+
+//-------------------------------------------------
+// draw_line -
+//-------------------------------------------------
+
+void upd7220_device::draw_line(int x, int y)
+{
+ int line_size,i;
+ const int line_x_dir[8] = { 0, 1, 1, 0, 0,-1,-1, 0};
+ const int line_y_dir[8] = { 1, 0, 0,-1,-1, 0, 0, 1};
+ const int line_x_step[8] = { 1, 0, 0, 1,-1, 0, 0,-1 };
+ const int line_y_step[8] = { 0, 1,-1, 0, 0,-1, 1, 0 };
+ UINT16 line_pattern;
+ int line_step = 0;
+ UINT8 dot;
+
+ line_size = m_figs.m_dc + 1;
+ line_pattern = check_pattern((m_ra[8]) | (m_ra[9]<<8));
+
+ for(i = 0;i<line_size;i++)
+ {
+ line_step = (m_figs.m_d1 * i);
+ line_step/= (m_figs.m_dc + 1);
+ line_step >>= 1;
+ dot = ((line_pattern >> (i & 0xf)) & 1) << 7;
+ draw_pixel(x + (line_step*line_x_step[m_figs.m_dir]),y + (line_step*line_y_step[m_figs.m_dir]),dot >> ((x + line_step*line_x_step[m_figs.m_dir]) & 0x7));
+ x += line_x_dir[m_figs.m_dir];
+ y += line_y_dir[m_figs.m_dir];
+ }
+
+ /* TODO: check me*/
+ x += (line_step*line_x_step[m_figs.m_dir]);
+ y += (line_step*line_y_step[m_figs.m_dir]);
+
+ m_ead = (x >> 4) + (y * m_pitch);
+ m_dad = x & 0x0f;
+}
+
+
+//-------------------------------------------------
+// draw_rectangle -
+//-------------------------------------------------
+
+void upd7220_device::draw_rectangle(int x, int y)
+{
+ int i;
+ const int rect_x_dir[8] = { 0, 1, 0,-1, 1, 1,-1,-1 };
+ const int rect_y_dir[8] = { 1, 0,-1, 0, 1,-1,-1, 1 };
+ UINT8 rect_type,rect_dir;
+ UINT16 line_pattern;
+ UINT8 dot;
+
+ LOG(("uPD7220 rectangle check: %d %d %02x %08x\n",x,y,m_figs.m_dir,m_ead));
+
+ line_pattern = check_pattern((m_ra[8]) | (m_ra[9]<<8));
+ rect_type = (m_figs.m_dir & 1) << 2;
+ rect_dir = rect_type | (((m_figs.m_dir >> 1) + 0) & 3);
+
+ for(i = 0;i < m_figs.m_d;i++)
+ {
+ dot = ((line_pattern >> ((i+m_dad) & 0xf)) & 1) << 7;
+ draw_pixel(x,y,dot >> (x & 0x7));
+ x+=rect_x_dir[rect_dir];
+ y+=rect_y_dir[rect_dir];
+ }
+
+ rect_dir = rect_type | (((m_figs.m_dir >> 1) + 1) & 3);
+
+ for(i = 0;i < m_figs.m_d2;i++)
+ {
+ dot = ((line_pattern >> ((i+m_dad) & 0xf)) & 1) << 7;
+ draw_pixel(x,y,dot >> (x & 0x7));
+ x+=rect_x_dir[rect_dir];
+ y+=rect_y_dir[rect_dir];
+ }
+
+ rect_dir = rect_type | (((m_figs.m_dir >> 1) + 2) & 3);
+
+ for(i = 0;i < m_figs.m_d;i++)
+ {
+ dot = ((line_pattern >> ((i+m_dad) & 0xf)) & 1) << 7;
+ draw_pixel(x,y,dot >> (x & 0x7));
+ x+=rect_x_dir[rect_dir];
+ y+=rect_y_dir[rect_dir];
+ }
+
+ rect_dir = rect_type | (((m_figs.m_dir >> 1) + 3) & 3);
+
+ for(i = 0;i < m_figs.m_d2;i++)
+ {
+ dot = ((line_pattern >> ((i+m_dad) & 0xf)) & 1) << 7;
+ draw_pixel(x,y,dot >> (x & 0x7));
+ x+=rect_x_dir[rect_dir];
+ y+=rect_y_dir[rect_dir];
+ }
+
+ m_ead = (x >> 4) + (y * m_pitch);
+ m_dad = x & 0x0f;
+
+}
+
+
+//-------------------------------------------------
+// draw_char -
+//-------------------------------------------------
+
+void upd7220_device::draw_char(int x, int y)
+{
+ int xi,yi;
+ int xsize,ysize;
+ UINT8 tile_data;
+
+ /* snippet for character checking */
+ #if 0
+ for(yi=0;yi<8;yi++)
+ {
+ for(xi=0;xi<8;xi++)
+ {
+ printf("%d",(m_ra[(yi & 7) | 8] >> xi) & 1);
+ }
+ printf("\n");
+ }
+ #endif
+
+ xsize = m_figs.m_d & 0x3ff;
+ /* Guess: D has presumably upper bits for ysize, QX-10 relies on this (TODO: check this on any real HW) */
+ ysize = ((m_figs.m_d & 0x400) + m_figs.m_dc) + 1;
+
+ /* TODO: internal direction, zooming, size stuff bigger than 8, rewrite using draw_pixel function */
+ for(yi=0;yi<ysize;yi++)
+ {
+ switch(m_figs.m_dir & 7)
+ {
+ case 0: tile_data = BITSWAP8(m_ra[((yi) & 7) | 8],0,1,2,3,4,5,6,7); break; // TODO
+ case 2: tile_data = BITSWAP8(m_ra[((yi) & 7) | 8],0,1,2,3,4,5,6,7); break;
+ case 6: tile_data = BITSWAP8(m_ra[((ysize-1-yi) & 7) | 8],7,6,5,4,3,2,1,0); break;
+ default: tile_data = BITSWAP8(m_ra[((yi) & 7) | 8],7,6,5,4,3,2,1,0);
+ printf("%d %d %d\n",m_figs.m_dir,xsize,ysize);
+ break;
+ }
+
+ for(xi=0;xi<xsize;xi++)
+ {
+ UINT32 addr = ((y+yi) * m_pitch * 2) + ((x+xi) >> 3);
+
+ writebyte(addr & 0x3ffff, readbyte(addr & 0x3ffff) & ~(1 << (xi & 7)));
+ writebyte(addr & 0x3ffff, readbyte(addr & 0x3ffff) | ((tile_data) & (1 << (xi & 7))));
+ }
+ }
+
+ m_ead = ((x+8*x_dir_dot[m_figs.m_dir]) >> 4) + ((y+8*y_dir_dot[m_figs.m_dir]) * m_pitch);
+ m_dad = ((x+8*x_dir_dot[m_figs.m_dir]) & 0xf);
+}
+
+
+//-------------------------------------------------
+// translate_command -
+//-------------------------------------------------
+
+int upd7220_device::translate_command(UINT8 data)
+{
+ int command = COMMAND_INVALID;
+
+ switch (data)
+ {
+ case UPD7220_COMMAND_RESET: command = COMMAND_RESET; break;
+ case UPD7220_COMMAND_CCHAR: command = COMMAND_CCHAR; break;
+ case UPD7220_COMMAND_START: command = COMMAND_START; break;
+ case UPD7220_COMMAND_ZOOM: command = COMMAND_ZOOM; break;
+ case UPD7220_COMMAND_CURS: command = COMMAND_CURS; break;
+ case UPD7220_COMMAND_PITCH: command = COMMAND_PITCH; break;
+ case UPD7220_COMMAND_MASK: command = COMMAND_MASK; break;
+ case UPD7220_COMMAND_FIGS: command = COMMAND_FIGS; break;
+ case UPD7220_COMMAND_FIGD: command = COMMAND_FIGD; break;
+ case UPD7220_COMMAND_GCHRD: command = COMMAND_GCHRD; break;
+ case UPD7220_COMMAND_CURD: command = COMMAND_CURD; break;
+ case UPD7220_COMMAND_LPRD: command = COMMAND_LPRD; break;
+ case UPD7220_COMMAND_5A: command = COMMAND_5A; break;
+ default:
+ switch (data & 0xfe)
+ {
+ case UPD7220_COMMAND_SYNC: command = COMMAND_SYNC; break;
+ case UPD7220_COMMAND_VSYNC: command = COMMAND_VSYNC; break;
+ case UPD7220_COMMAND_BCTRL: command = COMMAND_BCTRL; break;
+ default:
+ switch (data & 0xf0)
+ {
+ case UPD7220_COMMAND_PRAM: command = COMMAND_PRAM; break;
+ default:
+ switch (data & 0xe4)
+ {
+ case UPD7220_COMMAND_WDAT: command = COMMAND_WDAT; break;
+ case UPD7220_COMMAND_RDAT: command = COMMAND_RDAT; break;
+ case UPD7220_COMMAND_DMAR: command = COMMAND_DMAR; break;
+ case UPD7220_COMMAND_DMAW: command = COMMAND_DMAW; break;
+ }
+ }
+ }
+ }
+
+ return command;
+}
+
+
+//-------------------------------------------------
+// process_fifo -
+//-------------------------------------------------
+
+void upd7220_device::process_fifo()
+{
+ UINT8 data;
+ int flag;
+
+ dequeue(&data, &flag);
+
+ if (flag == FIFO_COMMAND)
+ {
+ m_cr = data;
+ m_param_ptr = 1;
+ }
+ else
+ {
+ m_pr[m_param_ptr] = data;
+ m_param_ptr++;
+ }
+
+ switch (translate_command(m_cr))
+ {
+ case COMMAND_INVALID:
+ printf("uPD7220 '%s' Invalid Command Byte %02x\n", tag(), m_cr);
+ break;
+
+ case COMMAND_5A:
+ if (m_param_ptr == 4)
+ printf("uPD7220 '%s' Undocumented Command 0x5A Executed %02x %02x %02x\n", tag(),m_pr[1],m_pr[2],m_pr[3] );
+ break;
+
+ case COMMAND_RESET: /* reset */
+ switch (m_param_ptr)
+ {
+ case 0:
+ LOG(("uPD7220 '%s' RESET\n", tag()));
+
+ m_de = 0;
+ m_ra[0] = m_ra[1] = m_ra[2] = 0;
+ m_ra[3] = 0x19;
+ m_ead = 0;
+ m_dad = 0;
+ m_mask = 0;
+ break;
+
+ case 9:
+ m_mode = m_pr[1];
+ m_aw = m_pr[2] + 2;
+ m_hs = (m_pr[3] & 0x1f) + 1;
+ m_vs = ((m_pr[4] & 0x03) << 3) | (m_pr[3] >> 5);
+ m_hfp = (m_pr[4] >> 2) + 1;
+ m_hbp = (m_pr[5] & 0x3f) + 1;
+ m_vfp = m_pr[6] & 0x3f;
+ m_al = ((m_pr[8] & 0x03) << 8) | m_pr[7];
+ m_vbp = m_pr[8] >> 2;
+
+ m_pitch = m_aw;
+
+ LOG(("uPD7220 '%s' Mode: %02x\n", tag(), m_mode));
+ LOG(("uPD7220 '%s' AW: %u\n", tag(), m_aw));
+ LOG(("uPD7220 '%s' HS: %u\n", tag(), m_hs));
+ LOG(("uPD7220 '%s' VS: %u\n", tag(), m_vs));
+ LOG(("uPD7220 '%s' HFP: %u\n", tag(), m_hfp));
+ LOG(("uPD7220 '%s' HBP: %u\n", tag(), m_hbp));
+ LOG(("uPD7220 '%s' VFP: %u\n", tag(), m_vfp));
+ LOG(("uPD7220 '%s' AL: %u\n", tag(), m_al));
+ LOG(("uPD7220 '%s' VBP: %u\n", tag(), m_vbp));
+ LOG(("uPD7220 '%s' PITCH: %u\n", tag(), m_pitch));
+
+ recompute_parameters();
+ break;
+ }
+ break;
+
+ case COMMAND_SYNC: /* sync format specify */
+ if (m_param_ptr == 9)
+ {
+ m_mode = m_pr[1];
+ m_aw = m_pr[2] + 2;
+ m_hs = (m_pr[3] & 0x1f) + 1;
+ m_vs = ((m_pr[4] & 0x03) << 3) | (m_pr[3] >> 5);
+ m_hfp = (m_pr[4] >> 2) + 1;
+ m_hbp = (m_pr[5] & 0x3f) + 1;
+ m_vfp = m_pr[6] & 0x3f;
+ m_al = ((m_pr[8] & 0x03) << 8) | m_pr[7];
+ m_vbp = m_pr[8] >> 2;
+
+ m_pitch = m_aw;
+
+ LOG(("uPD7220 '%s' Mode: %02x\n", tag(), m_mode));
+ LOG(("uPD7220 '%s' AW: %u\n", tag(), m_aw));
+ LOG(("uPD7220 '%s' HS: %u\n", tag(), m_hs));
+ LOG(("uPD7220 '%s' VS: %u\n", tag(), m_vs));
+ LOG(("uPD7220 '%s' HFP: %u\n", tag(), m_hfp));
+ LOG(("uPD7220 '%s' HBP: %u\n", tag(), m_hbp));
+ LOG(("uPD7220 '%s' VFP: %u\n", tag(), m_vfp));
+ LOG(("uPD7220 '%s' AL: %u\n", tag(), m_al));
+ LOG(("uPD7220 '%s' VBP: %u\n", tag(), m_vbp));
+ LOG(("uPD7220 '%s' PITCH: %u\n", tag(), m_pitch));
+
+ recompute_parameters();
+ }
+ break;
+
+ case COMMAND_VSYNC: /* vertical sync mode */
+ m_m = m_cr & 0x01;
+
+ LOG(("uPD7220 '%s' M: %u\n", tag(), m_m));
+
+ recompute_parameters();
+ break;
+
+ case COMMAND_CCHAR: /* cursor & character characteristics */
+ if(m_param_ptr == 2)
+ {
+ m_lr = (m_pr[1] & 0x1f) + 1;
+ m_dc = BIT(m_pr[1], 7);
+
+ LOG(("uPD7220 '%s' LR: %u\n", tag(), m_lr));
+ LOG(("uPD7220 '%s' DC: %u\n", tag(), m_dc));
+ }
+
+ if(m_param_ptr == 3)
+ {
+ m_ctop = m_pr[2] & 0x1f;
+ m_sc = BIT(m_pr[2], 5);
+ m_br = (m_pr[2] >> 6); /* guess, assume that blink rate clears upper bits (if any) */
+
+ LOG(("uPD7220 '%s' CTOP: %u\n", tag(), m_ctop));
+ LOG(("uPD7220 '%s' SC: %u\n", tag(), m_sc));
+ }
+
+ if(m_param_ptr == 4)
+ {
+ m_br = ((m_pr[3] & 0x07) << 2) | (m_pr[2] >> 6);
+ m_cbot = m_pr[3] >> 3;
+
+ LOG(("uPD7220 '%s' BR: %u\n", tag(), m_br));
+ LOG(("uPD7220 '%s' CBOT: %u\n", tag(), m_cbot));
+ }
+ break;
+
+ case COMMAND_START: /* start display & end idle mode */
+ m_de = 1;
+
+ //LOG(("uPD7220 '%s' DE: 1\n", tag()));
+ break;
+
+ case COMMAND_BCTRL: /* display blanking control */
+ m_de = m_cr & 0x01;
+
+ //LOG(("uPD7220 '%s' DE: %u\n", tag(), m_de));
+ break;
+
+ case COMMAND_ZOOM: /* zoom factors specify */
+ if (flag == FIFO_PARAMETER)
+ {
+ m_gchr = m_pr[1] & 0x0f;
+ m_disp = m_pr[1] >> 4;
+
+ LOG(("uPD7220 '%s' GCHR: %01x\n", tag(), m_gchr));
+ LOG(("uPD7220 '%s' DISP: %01x\n", tag(), m_disp));
+ }
+ break;
+
+ case COMMAND_CURS: /* cursor position specify */
+ if (m_param_ptr >= 3)
+ {
+ UINT8 upper_addr = (m_param_ptr == 3) ? 0 : (m_pr[3] & 0x03);
+
+ m_ead = (upper_addr << 16) | (m_pr[2] << 8) | m_pr[1];
+
+ //LOG(("uPD7220 '%s' EAD: %06x\n", tag(), m_ead));
+
+ if(m_param_ptr == 4)
+ {
+ m_dad = m_pr[3] >> 4;
+ //LOG(("uPD7220 '%s' DAD: %01x\n", tag(), m_dad));
+ }
+ }
+ break;
+
+ case COMMAND_PRAM: /* parameter RAM load */
+ if (flag == FIFO_COMMAND)
+ {
+ m_ra_addr = m_cr & 0x0f;
+ }
+ else
+ {
+ if (m_ra_addr < 16)
+ {
+ LOG(("uPD7220 '%s' RA%u: %02x\n", tag(), m_ra_addr, data));
+
+ m_ra[m_ra_addr] = data;
+ m_ra_addr++;
+ }
+
+ m_param_ptr = 0;
+ }
+ break;
+
+ case COMMAND_PITCH: /* pitch specification */
+ if (flag == FIFO_PARAMETER)
+ {
+ m_pitch = data;
+
+ LOG(("uPD7220 '%s' PITCH: %u\n", tag(), m_pitch));
+ }
+ break;
+
+ case COMMAND_WDAT: /* write data into display memory */
+ m_bitmap_mod = m_cr & 3;
+
+ if (m_param_ptr == 3 || (m_param_ptr == 2 && m_cr & 0x10))
+ {
+ //printf("%02x = %02x %02x (%c) %04x\n",m_cr,m_pr[2],m_pr[1],m_pr[1],EAD);
+ fifo_set_direction(FIFO_WRITE);
+
+ write_vram((m_cr & 0x18) >> 3,m_cr & 3);
+ reset_figs_param();
+ m_param_ptr = 1;
+ }
+ break;
+
+ case COMMAND_MASK: /* mask register load */
+ if (m_param_ptr == 3)
+ {
+ m_mask = (m_pr[2] << 8) | m_pr[1];
+
+ LOG(("uPD7220 '%s' MASK: %04x\n", tag(), m_mask));
+ }
+ break;
+
+ case COMMAND_FIGS: /* figure drawing parameters specify */
+ if (m_param_ptr == 2)
+ {
+ m_figs.m_dir = m_pr[1] & 0x7;
+ m_figs.m_figure_type = (m_pr[1] & 0xf8) >> 3;
+
+ //if(m_figs.m_dir != 2)
+ // printf("DIR %02x\n",m_pr[1]);
+ }
+
+ // the Decision Mate V during start-up test upload only 2 params before execute the
+ // RDAT command, so I assume this is the expected behaviour, but this needs to be verified.
+ if (m_param_ptr == 3)
+ m_figs.m_dc = (m_pr[2]) | (m_figs.m_dc & 0x3f00);
+
+ if (m_param_ptr == 4)
+ m_figs.m_dc = (m_pr[2]) | ((m_pr[3] & 0x3f) << 8);
+
+ if (m_param_ptr == 6)
+ m_figs.m_d = (m_pr[4]) | ((m_pr[5] & 0x3f) << 8);
+
+ if (m_param_ptr == 8)
+ m_figs.m_d2 = (m_pr[6]) | ((m_pr[7] & 0x3f) << 8);
+
+ if (m_param_ptr == 10)
+ m_figs.m_d1 = (m_pr[8]) | ((m_pr[9] & 0x3f) << 8);
+
+ if (m_param_ptr == 12)
+ m_figs.m_dm = (m_pr[10]) | ((m_pr[11] & 0x3f) << 8);
+
+ break;
+
+ case COMMAND_FIGD: /* figure draw start */
+ if(m_figs.m_figure_type == 0)
+ {
+ UINT16 line_pattern = check_pattern((m_ra[8]) | (m_ra[9]<<8));
+ UINT8 dot = ((line_pattern >> (0 & 0xf)) & 1) << 7;
+
+ draw_pixel(((m_ead % m_pitch) << 4) | (m_dad & 0xf),(m_ead / m_pitch),dot);
+ }
+ else if(m_figs.m_figure_type == 1)
+ draw_line(((m_ead % m_pitch) << 4) | (m_dad & 0xf),(m_ead / m_pitch));
+ else if(m_figs.m_figure_type == 8)
+ draw_rectangle(((m_ead % m_pitch) << 4) | (m_dad & 0xf),(m_ead / m_pitch));
+ else
+ printf("uPD7220 '%s' Unimplemented command FIGD %02x\n", tag(),m_figs.m_figure_type);
+
+ reset_figs_param();
+ m_sr |= UPD7220_SR_DRAWING_IN_PROGRESS;
+ break;
+
+ case COMMAND_GCHRD: /* graphics character draw and area filling start */
+ if(m_figs.m_figure_type == 2)
+ draw_char(((m_ead % m_pitch) << 4) | (m_dad & 0xf),(m_ead / m_pitch));
+ else
+ printf("uPD7220 '%s' Unimplemented command GCHRD %02x\n", tag(),m_figs.m_figure_type);
+
+ reset_figs_param();
+ m_sr |= UPD7220_SR_DRAWING_IN_PROGRESS;
+ break;
+
+ case COMMAND_RDAT: /* read data from display memory */
+ fifo_set_direction(FIFO_READ);
+
+ read_vram((m_cr & 0x18) >> 3,m_cr & 3);
+ reset_figs_param();
+
+ m_sr |= UPD7220_SR_DATA_READY;
+ break;
+
+ case COMMAND_CURD: /* cursor address read */
+ fifo_set_direction(FIFO_READ);
+
+ queue(m_ead & 0xff, 0);
+ queue((m_ead >> 8) & 0xff, 0);
+ queue(m_ead >> 16, 0);
+ queue(m_dad & 0xff, 0);
+ queue(m_dad >> 8, 0);
+
+ m_sr |= UPD7220_SR_DATA_READY;
+ break;
+
+ case COMMAND_LPRD: /* light pen address read */
+ fifo_set_direction(FIFO_READ);
+
+ queue(m_lad & 0xff, 0);
+ queue((m_lad >> 8) & 0xff, 0);
+ queue(m_lad >> 16, 0);
+
+ m_sr |= UPD7220_SR_DATA_READY;
+ m_sr &= ~UPD7220_SR_LIGHT_PEN_DETECT;
+ break;
+
+ case COMMAND_DMAR: /* DMA read request */
+ printf("uPD7220 '%s' Unimplemented command DMAR\n", tag());
+ break;
+
+ case COMMAND_DMAW: /* DMA write request */
+ printf("uPD7220 '%s' Unimplemented command DMAW\n", tag());
+ break;
+ }
+}
+
+
+//-------------------------------------------------
+// read -
+//-------------------------------------------------
+
+READ8_MEMBER( upd7220_device::read )
+{
+ UINT8 data;
+
+ if (offset & 1)
+ {
+ /* FIFO read */
+ int flag;
+ fifo_set_direction(FIFO_READ);
+ dequeue(&data, &flag);
+ }
+ else
+ {
+ /* status register */
+ data = m_sr;
+
+ /* TODO: timing of these */
+ m_sr &= ~UPD7220_SR_DRAWING_IN_PROGRESS;
+ m_sr &= ~UPD7220_SR_DMA_EXECUTE;
+ }
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// write -
+//-------------------------------------------------
+
+WRITE8_MEMBER( upd7220_device::write )
+{
+ if (offset & 1)
+ {
+ /* command into FIFO */
+ fifo_set_direction(FIFO_WRITE);
+ queue(data, 1);
+ }
+ else
+ {
+ /* parameter into FIFO */
+// fifo_set_direction(FIFO_WRITE);
+ queue(data, 0);
+ }
+
+ process_fifo();
+}
+
+
+//-------------------------------------------------
+// dack_r -
+//-------------------------------------------------
+
+READ8_MEMBER( upd7220_device::dack_r )
+{
+ return 0;
+}
+
+
+//-------------------------------------------------
+// dack_w -
+//-------------------------------------------------
+
+WRITE8_MEMBER( upd7220_device::dack_w )
+{
+}
+
+
+//-------------------------------------------------
+// ext_sync_w -
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( upd7220_device::ext_sync_w )
+{
+ //LOG(("uPD7220 '%s' External Synchronization: %u\n", tag(), state));
+
+ if (state)
+ {
+ m_sr |= UPD7220_SR_VSYNC_ACTIVE;
+ }
+ else
+ {
+ m_sr &= ~UPD7220_SR_VSYNC_ACTIVE;
+ }
+}
+
+
+//-------------------------------------------------
+// ext_sync_w -
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( upd7220_device::lpen_w )
+{
+ /* only if 2 rising edges on the lpen input occur at the same
+ point during successive video fields are the pulses accepted */
+
+ /*
+
+ 1. compute the address of the location on the CRT
+ 2. compare with LAD
+ 3. if not equal move address to LAD
+ 4. if equal set LPEN DETECT flag to 1
+
+ */
+}
+
+
+//-------------------------------------------------
+// update_text -
+//-------------------------------------------------
+
+void upd7220_device::update_text(bitmap_rgb32 &bitmap, const rectangle &cliprect)
+{
+ UINT32 addr, sad;
+ UINT16 len;
+ int im, wd;
+ int y, sy = 0;
+
+ for (int area = 0; area < 4; area++)
+ {
+ get_text_partition(area, &sad, &len, &im, &wd);
+
+ for (y = sy; y < sy + len; y++)
+ {
+ addr = sad + (y * m_pitch);
+
+ if (m_draw_text_cb)
+ m_draw_text_cb(this, bitmap, addr, y, wd, m_pitch, m_lr, m_dc, m_ead);
+ }
+
+ sy = y + 1;
+ }
+}
+
+
+//-------------------------------------------------
+// draw_graphics_line -
+//-------------------------------------------------
+
+void upd7220_device::draw_graphics_line(bitmap_rgb32 &bitmap, UINT32 addr, int y, int wd)
+{
+ int sx;
+
+ for (sx = 0; sx < m_pitch * 2; sx++)
+ {
+ if((sx << 3) < m_aw * 16 && y < m_al)
+ m_display_cb(this, bitmap, y, sx << 3, addr);
+
+ addr+= wd + 1;
+ }
+}
+
+
+//-------------------------------------------------
+// update_graphics -
+//-------------------------------------------------
+
+void upd7220_device::update_graphics(bitmap_rgb32 &bitmap, const rectangle &cliprect, int force_bitmap)
+{
+ UINT32 addr, sad;
+ UINT16 len;
+ int im, wd, area;
+ int y = 0, tsy = 0, bsy = 0;
+
+ for (area = 0; area < 4; area++)
+ {
+ get_graphics_partition(area, &sad, &len, &im, &wd);
+
+ if (im || force_bitmap)
+ {
+ get_graphics_partition(area, &sad, &len, &im, &wd);
+
+ if(area >= 2) // TODO: correct?
+ break;
+
+ for (y = 0; y < len; y++)
+ {
+ addr = ((sad << 1) & 0x3ffff) + (y * m_pitch * 2);
+
+ if (m_display_cb)
+ draw_graphics_line(bitmap, addr, y + bsy, wd);
+ }
+ }
+ else
+ {
+ get_text_partition(area, &sad, &len, &im, &wd);
+
+ if(m_lr)
+ {
+ for (y = 0; y < len; y+=m_lr)
+ {
+ addr = (sad & 0x3ffff) + ((y / m_lr) * m_pitch);
+
+ if (m_draw_text_cb)
+ m_draw_text_cb(this, bitmap, addr, (y + tsy) / m_lr, wd, m_pitch, m_lr, m_dc, m_ead);
+ }
+ }
+ }
+
+ if (m_lr)
+ tsy += y;
+ bsy += y;
+ }
+}
+
+
+//-------------------------------------------------
+// update_screen -
+//-------------------------------------------------
+
+UINT32 upd7220_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
+{
+ if (m_de)
+ {
+ switch (m_mode & UPD7220_MODE_DISPLAY_MASK)
+ {
+ case UPD7220_MODE_DISPLAY_MIXED:
+ update_graphics(bitmap, cliprect, 0);
+ break;
+
+ case UPD7220_MODE_DISPLAY_GRAPHICS:
+ update_graphics(bitmap, cliprect, 1);
+ break;
+
+ case UPD7220_MODE_DISPLAY_CHARACTER:
+ update_text(bitmap, cliprect);
+ break;
+
+ case UPD7220_MODE_DISPLAY_INVALID:
+ LOG(("uPD7220 '%s' Invalid Display Mode!\n", tag()));
+ }
+ }
+ return 0;
+}
diff --git a/src/emu/video/upd7220.h b/src/emu/video/upd7220.h
new file mode 100644
index 00000000000..a9318ba9d13
--- /dev/null
+++ b/src/emu/video/upd7220.h
@@ -0,0 +1,233 @@
+/**********************************************************************
+
+ NEC uPD7220 Graphics Display Controller emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************
+ _____ _____
+ 2xWCLK 1 |* \_/ | 40 Vcc
+ _DBIN 2 | | 39 A17
+ HSYNC 3 | | 38 A16
+ V/EXT SYNC 4 | | 37 AD15
+ BLANK 5 | | 36 AD14
+ ALE 6 | | 35 AD13
+ DRQ 7 | | 34 AD12
+ _DACK 8 | | 33 AD11
+ _RD 9 | | 32 AD10
+ _WR 10 | uPD7220 | 31 AD9
+ A0 11 | 82720 | 30 AD8
+ DB0 12 | | 29 AD7
+ DB1 13 | | 28 AD6
+ DB2 14 | | 27 AD5
+ DB3 15 | | 26 AD4
+ DB4 16 | | 25 AD3
+ DB5 17 | | 24 AD2
+ DB6 18 | | 23 AD1
+ DB7 19 | | 22 AD0
+ GND 20 |_____________| 21 LPEN
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __UPD7220__
+#define __UPD7220__
+
+#include "emu.h"
+
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+
+
+
+//**************************************************************************
+// INTERFACE CONFIGURATION MACROS
+//**************************************************************************
+
+#define MCFG_UPD7220_ADD(_tag, _clock, _config, _map) \
+ MCFG_DEVICE_ADD(_tag, UPD7220, _clock) \
+ MCFG_DEVICE_CONFIG(_config) \
+ MCFG_DEVICE_ADDRESS_MAP(AS_0, _map)
+
+#define UPD7220_INTERFACE(name) \
+ const upd7220_interface (name) =
+
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+typedef void (*upd7220_display_pixels_func)(device_t *device, bitmap_rgb32 &bitmap, int y, int x, UINT32 address);
+#define UPD7220_DISPLAY_PIXELS(name) void name(device_t *device, bitmap_rgb32 &bitmap, int y, int x, UINT32 address)
+
+typedef void (*upd7220_draw_text_line)(device_t *device, bitmap_rgb32 &bitmap, UINT32 addr, int y, int wd, int pitch, int lr, int cursor_on, int cursor_addr);
+#define UPD7220_DRAW_TEXT_LINE(name) void name(device_t *device, bitmap_rgb32 &bitmap, UINT32 addr, int y, int wd, int pitch, int lr, int cursor_on, int cursor_addr)
+
+
+// ======================> upd7220_interface
+
+struct upd7220_interface
+{
+ const char *m_screen_tag;
+
+ upd7220_display_pixels_func m_display_cb;
+ upd7220_draw_text_line m_draw_text_cb;
+
+ devcb_write_line m_out_drq_cb;
+ devcb_write_line m_out_hsync_cb;
+ devcb_write_line m_out_vsync_cb;
+ devcb_write_line m_out_blank_cb;
+};
+
+// ======================> upd7220_device
+
+class upd7220_device : public device_t,
+ public device_memory_interface,
+ public upd7220_interface
+{
+public:
+ // construction/destruction
+ upd7220_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ DECLARE_READ8_MEMBER( read );
+ DECLARE_WRITE8_MEMBER( write );
+
+ DECLARE_READ8_MEMBER( dack_r );
+ DECLARE_WRITE8_MEMBER( dack_w );
+
+ DECLARE_WRITE_LINE_MEMBER( ext_sync_w );
+ DECLARE_WRITE_LINE_MEMBER( lpen_w );
+
+ DECLARE_WRITE8_MEMBER( bank_w );
+ DECLARE_READ8_MEMBER( vram_r );
+ DECLARE_WRITE8_MEMBER( vram_w );
+
+ UINT32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
+ virtual const rom_entry *device_rom_region() const;
+ virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const;
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+ virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);
+ virtual void device_config_complete();
+
+private:
+ static const device_timer_id TIMER_VSYNC = 0;
+ static const device_timer_id TIMER_HSYNC = 1;
+ static const device_timer_id TIMER_BLANK = 2;
+
+ inline UINT8 readbyte(offs_t address);
+ inline void writebyte(offs_t address, UINT8 data);
+ inline void fifo_clear();
+ inline int fifo_param_count();
+ inline void fifo_set_direction(int dir);
+ inline void queue(UINT8 data, int flag);
+ inline void dequeue(UINT8 *data, int *flag);
+ inline void update_vsync_timer(int state);
+ inline void update_hsync_timer(int state);
+ inline void update_blank_timer(int state);
+ inline void recompute_parameters();
+ inline void reset_figs_param();
+ inline void advance_ead();
+ inline void read_vram(UINT8 type, UINT8 mod);
+ inline void write_vram(UINT8 type, UINT8 mod);
+ inline UINT16 check_pattern(UINT16 pattern);
+ inline void get_text_partition(int index, UINT32 *sad, UINT16 *len, int *im, int *wd);
+ inline void get_graphics_partition(int index, UINT32 *sad, UINT16 *len, int *im, int *wd);
+
+ void draw_pixel(int x, int y, UINT8 tile_data);
+ void draw_line(int x, int y);
+ void draw_rectangle(int x, int y);
+ void draw_char(int x, int y);
+ int translate_command(UINT8 data);
+ void process_fifo();
+ void update_text(bitmap_rgb32 &bitmap, const rectangle &cliprect);
+ void draw_graphics_line(bitmap_rgb32 &bitmap, UINT32 addr, int y, int wd);
+ void update_graphics(bitmap_rgb32 &bitmap, const rectangle &cliprect, int force_bitmap);
+
+ devcb_resolved_write_line m_out_drq_func;
+ devcb_resolved_write_line m_out_hsync_func;
+ devcb_resolved_write_line m_out_vsync_func;
+ devcb_resolved_write_line m_out_blank_func;
+
+ screen_device *m_screen;
+
+ UINT16 m_mask; // mask register
+ UINT8 m_pitch; // number of word addresses in display memory in the horizontal direction
+ UINT32 m_ead; // execute word address
+ UINT16 m_dad; // dot address within the word
+ UINT32 m_lad; // light pen address
+
+ UINT8 m_ra[16]; // parameter RAM
+ int m_ra_addr; // parameter RAM address
+
+ UINT8 m_sr; // status register
+ UINT8 m_cr; // command register
+ UINT8 m_pr[17]; // parameter byte register
+ int m_param_ptr; // parameter pointer
+
+ UINT8 m_fifo[16]; // FIFO data queue
+ int m_fifo_flag[16]; // FIFO flag queue
+ int m_fifo_ptr; // FIFO pointer
+ int m_fifo_dir; // FIFO direction
+
+ UINT8 m_mode; // mode of operation
+ UINT8 m_draw_mode; // mode of drawing
+
+ int m_de; // display enabled
+ int m_m; // 0 = accept external vertical sync (slave mode) / 1 = generate & output vertical sync (master mode)
+ int m_aw; // active display words per line - 2 (must be even number with bit 0 = 0)
+ int m_al; // active display lines per video field
+ int m_vs; // vertical sync width - 1
+ int m_vfp; // vertical front porch width - 1
+ int m_vbp; // vertical back porch width - 1
+ int m_hs; // horizontal sync width - 1
+ int m_hfp; // horizontal front porch width - 1
+ int m_hbp; // horizontal back porch width - 1
+
+ int m_dc; // display cursor
+ int m_sc; // 0 = blinking cursor / 1 = steady cursor
+ int m_br; // blink rate
+ int m_ctop; // cursor top line number in the row
+ int m_cbot; // cursor bottom line number in the row (CBOT < LR)
+ int m_lr; // lines per character row - 1
+
+ int m_disp; // display zoom factor
+ int m_gchr; // zoom factor for graphics character writing and area filling
+
+ UINT8 m_bitmap_mod;
+
+ struct {
+ UINT8 m_dir; // figs param 0: drawing direction
+ UINT8 m_figure_type; // figs param 1: figure type
+ UINT16 m_dc; // figs param 2:
+ UINT16 m_d; // figs param 3:
+ UINT16 m_d1; // figs param 4:
+ UINT16 m_d2; // figs param 5:
+ UINT16 m_dm; // figs param 6:
+ } m_figs;
+
+ // timers
+ emu_timer *m_vsync_timer; // vertical sync timer
+ emu_timer *m_hsync_timer; // horizontal sync timer
+ emu_timer *m_blank_timer; // CRT blanking timer
+
+ const address_space_config m_space_config;
+};
+
+
+// device type definition
+extern const device_type UPD7220;
+
+
+
+#endif