diff options
author | 2013-03-07 15:28:25 +0000 | |
---|---|---|
committer | 2013-03-07 15:28:25 +0000 | |
commit | 76ac08a0b805820f12be6dac3daee17f8eb26953 (patch) | |
tree | 74a1a81d8e2a6cf242d498978b3573015c4d7a0c /src/emu/video | |
parent | 7e0b63efa9978e8611337c4ac80ffc293bb527ee (diff) |
Moved some files to where they belong. (nw)
Diffstat (limited to 'src/emu/video')
-rw-r--r-- | src/emu/video/dl1416.c | 344 | ||||
-rw-r--r-- | src/emu/video/dl1416.h | 90 | ||||
-rw-r--r-- | src/emu/video/hd44352.c | 456 | ||||
-rw-r--r-- | src/emu/video/hd44352.h | 87 | ||||
-rw-r--r-- | src/emu/video/hd44780.c | 556 | ||||
-rw-r--r-- | src/emu/video/hd44780.h | 141 | ||||
-rw-r--r-- | src/emu/video/hd66421.c | 256 | ||||
-rw-r--r-- | src/emu/video/hd66421.h | 79 | ||||
-rw-r--r-- | src/emu/video/mc6847.c | 1732 | ||||
-rw-r--r-- | src/emu/video/mc6847.h | 648 | ||||
-rw-r--r-- | src/emu/video/tms3556.c | 588 | ||||
-rw-r--r-- | src/emu/video/tms3556.h | 112 | ||||
-rw-r--r-- | src/emu/video/upd7220.c | 1673 | ||||
-rw-r--r-- | src/emu/video/upd7220.h | 233 |
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 |