// license:BSD-3-Clause
// copyright-holders:Nathan Woods
/*********************************************************************
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. coco_cart:drgnfire
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.
PAL info from chats with Ciaran (XRoar) and from his page
https://www.6809.org.uk/dragon/hardware.shtml :
The 6847 does not directly support PAL, but many PAL machines
with a 6847 add circuitry to stuff scalines into the frame,
to pad it out to be consistent with PAL CRTs. This padding
consists of a top and bottom region of black lines. Some
Dragon 64s turn off HS during the padding; other Dragons enable
HS all the way. Some Dragons use the same 14.31818MHz crystal
as NTSC machines; other Dragons use 14.218MHz. In either case,
the 6847, 6883 (SAM), and 6809 (CPU) base their timings on the
same crystal (divided appropriately).
Many of the cycle counts below were derived via experimentation
with coco_cart:drgnfire and with Stewart Orchard's highly
detailed tmgtest_v1_3 test suite. Although Stewart's tests were
designed for Dragons, many apply to the NTSC CoCos, and in fact
tuning to those tests improved emulation of coco_cart:drgnfire on
NTSC CoCos. There are still many tests in tmgtest_v1_3 that
fail and may require work in other components.
**********************************************************************/
#include "emu.h"
#include "mc6847.h"
#define LOG_SCANLINE (1U << 1)
#define LOG_HSYNC (1U << 2)
#define LOG_FSYNC (1U << 3)
#define LOG_FLUSH (1U << 4)
#define LOG_INPUT (1U << 5)
#define LOG_NEXTLINE (1U << 6)
#define VERBOSE (0)
#include "logmacro.h"
//**************************************************************************
// CONSTANTS
//**************************************************************************
namespace {
constexpr int LINES_TOP_BORDER = 25;
constexpr int LINES_ACTIVE_VIDEO = 192;
constexpr int LINES_BOTTOM_BORDER = 26;
constexpr int LINES_VERTICAL_RETRACE = 6;
constexpr int LINES_VBLANK = 13;
constexpr int LINES_UNTIL_RETRACE_NTSC = LINES_TOP_BORDER + LINES_ACTIVE_VIDEO + LINES_BOTTOM_BORDER;
constexpr int LINES_UNTIL_VBLANK_NTSC = LINES_UNTIL_RETRACE_NTSC + LINES_VERTICAL_RETRACE;
constexpr int LINES_PADDING_TOP_PAL = 25;
constexpr int LINES_PADDING_BOTTOM_PAL = 25;
constexpr int LINES_UNTIL_PADDING_BOTTOM_PAL = LINES_PADDING_TOP_PAL + LINES_TOP_BORDER + LINES_ACTIVE_VIDEO +
LINES_BOTTOM_BORDER - 2;
constexpr int LINES_UNTIL_RETRACE_PAL = LINES_PADDING_TOP_PAL + LINES_TOP_BORDER + LINES_ACTIVE_VIDEO +
LINES_BOTTOM_BORDER + LINES_PADDING_BOTTOM_PAL;
constexpr int LINES_UNTIL_VBLANK_PAL = LINES_UNTIL_RETRACE_PAL + LINES_VERTICAL_RETRACE;
constexpr bool USE_HORIZONTAL_CLIP = false;
constexpr int CLOCKS_HSYNC_PERIOD = 228;
constexpr int CLOCKS_ACTIVE_VIDEO = 128;
constexpr int CLOCKS_L_OR_R_BORDER = 29;
constexpr int CLOCKS_ACTIVE_VIDEO_AND_BORDERS = CLOCKS_ACTIVE_VIDEO + (2*CLOCKS_L_OR_R_BORDER);
constexpr int TIMER_HSYNC_OFF_TIME = 212;
constexpr int TIMER_HSYNC_ON_TIME = 228;
constexpr int TIMER_FSYNC_TIME = 212;
// These units are the screen device's bitmap pixels. Multiplied by 2 because
// the pixel clock is the mc6847's clock * 2
constexpr int BMP_L_OR_R_BORDER = CLOCKS_L_OR_R_BORDER * 2;
constexpr int BMP_ACTIVE_VIDEO = CLOCKS_ACTIVE_VIDEO * 2;
} // anonymous namespace
const uint32_t mc6847_base_device::s_palette[mc6847_base_device::PALETTE_LENGTH] =
{
rgb_t(0x30, 0xd2, 0x00), // GREEN
rgb_t(0xc1, 0xe5, 0x00), // YELLOW
rgb_t(0x4c, 0x3a, 0xb4), // BLUE
rgb_t(0x9a, 0x32, 0x36), // RED
rgb_t(0xbf, 0xc8, 0xad), // BUFF
rgb_t(0x41, 0xaf, 0x71), // CYAN
rgb_t(0xc8, 0x4e, 0xf0), // MAGENTA
rgb_t(0xd4, 0x7f, 0x00), // ORANGE
rgb_t(0x26, 0x30, 0x16), // BLACK
rgb_t(0x30, 0xd2, 0x00), // GREEN
rgb_t(0x26, 0x30, 0x16), // BLACK
rgb_t(0xbf, 0xc8, 0xad), // BUFF
rgb_t(0x00, 0x7c, 0x00), // ALPHANUMERIC DARK GREEN
rgb_t(0x30, 0xd2, 0x00), // ALPHANUMERIC BRIGHT GREEN
rgb_t(0x6b, 0x27, 0x00), // ALPHANUMERIC DARK ORANGE
rgb_t(0xff, 0xb7, 0x00) // ALPHANUMERIC BRIGHT ORANGE
};
//**************************************************************************
// FRIEND DEVICE
//**************************************************************************
//-------------------------------------------------
// ctor
//-------------------------------------------------
mc6847_friend_device::mc6847_friend_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock,
const uint8_t *fontdata, bool is_mc6847t1, double tpfs, int field_sync_falling_edge_scanline, int divider,
bool supports_partial_body_scanlines, bool pal)
: device_t(mconfig, type, tag, owner, clock)
, device_video_interface(mconfig, *this)
, m_write_hsync(*this)
, m_write_fsync(*this)
, m_charrom_cb(*this)
, m_character_map(fontdata, is_mc6847t1)
, m_tpfs(tpfs)
, m_divider(divider)
, m_field_sync_falling_edge_scanline(pal ? field_sync_falling_edge_scanline + LINES_PADDING_TOP_PAL : field_sync_falling_edge_scanline)
, m_supports_partial_body_scanlines(supports_partial_body_scanlines)
, m_pal(pal)
, m_lines_top_border(pal ? LINES_TOP_BORDER + LINES_PADDING_TOP_PAL : LINES_TOP_BORDER)
, m_lines_until_vblank(pal ? LINES_UNTIL_VBLANK_PAL : LINES_UNTIL_VBLANK_NTSC)
, m_lines_until_retrace(pal ? LINES_UNTIL_RETRACE_PAL : LINES_UNTIL_RETRACE_NTSC)
{
// Note: field_sync_falling_edge_scanline is parameterized because the MC6847
// and the GIME apply field sync on different scanlines
}
//-------------------------------------------------
// device_start - device-specific startup
//-------------------------------------------------
void mc6847_friend_device::device_start()
{
/* create the timers */
m_hsync_on_timer = timer_alloc(FUNC(mc6847_friend_device::change_horizontal_sync), this);
m_hsync_off_timer = timer_alloc(FUNC(mc6847_friend_device::change_horizontal_sync), this);
m_fsync_timer = timer_alloc(FUNC(mc6847_friend_device::change_field_sync), this);
m_hsync_on_timer->adjust(clocks_to_attotime(TIMER_HSYNC_ON_TIME * m_divider), 1, clocks_to_attotime(CLOCKS_HSYNC_PERIOD * m_divider));
m_hsync_off_timer->adjust(clocks_to_attotime(TIMER_HSYNC_OFF_TIME * m_divider), 0, clocks_to_attotime(CLOCKS_HSYNC_PERIOD * m_divider));
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(m_lines_top_border, LINES_ACTIVE_VIDEO, 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);
screen().reset_origin(0, 0);
}
//-------------------------------------------------
// device_start - device-specific reset
//-------------------------------------------------
void mc6847_friend_device::device_reset()
{
device_t::device_reset();
m_video_changed = true;
}
//-------------------------------------------------
// device_post_load - device-specific post load
//-------------------------------------------------
void mc6847_friend_device::device_post_load()
{
device_t::device_post_load();
m_video_changed = true;
}
//-------------------------------------------------
// update_field_sync_timer
//
// Unlike hsync, fsync uses a single timer to handle
// both ON (FS high) and OFF (FS low). When hsync-ON
// occurs for a line before we expect FS to change,
// this is called to set up an fsync for the next line.
// Which line of the field that is determines whether
// the fsync will signal an ON or OFF
//-------------------------------------------------
void mc6847_friend_device::update_field_sync_timer()
{
// field sync is expected high from the line before vblanking starts (i.e., from last
// vertical retracing line) until but excluding m_field_sync_falling_edge_scanline
bool expected_field_sync = (m_physical_scanline < m_field_sync_falling_edge_scanline)
|| (m_physical_scanline >= m_lines_until_vblank - 1);
// do we need to adjust the timer?
if (expected_field_sync != m_field_sync)
{
// if so, determine the duration
attotime duration = clocks_to_attotime(TIMER_FSYNC_TIME * m_divider);
// and reset the timer
m_fsync_timer->adjust(duration, expected_field_sync ? 1 : 0);
}
}
//-------------------------------------------------
// scanline_zone_string
//-------------------------------------------------
std::string mc6847_friend_device::scanline_zone_string(scanline_zone zone) const
{
std::string 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;
default:
fatalerror("Should not get here\n");
}
return result;
}
//-------------------------------------------------
// change_horizontal_sync
//-------------------------------------------------
TIMER_CALLBACK_MEMBER(mc6847_friend_device::change_horizontal_sync)
{
bool line = (bool)param;
auto profile1 = g_profiler.start(PROFILER_USER1);
// are we on a rising edge?
if (line && !m_horizontal_sync)
{
LOGMASKED(LOG_SCANLINE, "%s: change_horizontal_sync(): Recording scanline. line=%d, (vpos,hpos)=(%d,%d), m_physical_scanline=%d\n", describe_context(), line ? 1 : 0, screen().vpos(), screen().hpos(), m_physical_scanline);
// first store the scanline
{
auto profile2 = 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, CLOCKS_HSYNC_PERIOD);
else
record_full_body_scanline(m_physical_scanline, m_logical_scanline);
m_recording_scanline = false;
break;
case SCANLINE_ZONE_RETRACE:
case SCANLINE_ZONE_VBLANK:
// do nothing
break;
}
// stop profiling USER2
}
// advance to next scanline
next_scanline();
// and update the field sync timer
update_field_sync_timer();
}
// finally output horizontal sync
if (line != m_horizontal_sync)
{
m_horizontal_sync = line;
// log if apprpriate
LOGMASKED(LOG_HSYNC, "%s: change_horizontal_sync(): line=%d, (vpos,hpos)=(%d,%d), m_physical_scanline=%d\n", describe_context(), line ? 1 : 0, screen().vpos(), screen().hpos(), m_physical_scanline);
// invoke callback (to issue interrupt) if this isn't a PAL padding line
// TODO: Apparently HS is inhibited during PAL padding on Dragon 64, but
// not Dragon 32. I do not know the behavior on other PAL 6847 machines.
// For now, inhibiting for all PAL machines
if (!is_pal_padding_line(m_physical_scanline))
m_write_hsync(line);
// call virtual function
horizontal_sync_changed(m_horizontal_sync);
}
}
//-------------------------------------------------
// change_field_sync
//-------------------------------------------------
TIMER_CALLBACK_MEMBER(mc6847_friend_device::change_field_sync)
{
bool line = (bool)param;
/* output field sync */
if (line != m_field_sync)
{
m_field_sync = line;
/* log if apprpriate */
LOGMASKED(LOG_FSYNC, "%s: change_field_sync(): line=%d, (vpos,hpos)=(%d,%d), m_physical_scanline=%d\n", describe_context(), line ? 1 : 0, screen().vpos(), screen().hpos(), m_physical_scanline);
/* invoke callback */
m_write_fsync(line);
/* call virtual function */
field_sync_changed(m_field_sync);
}
}
//-------------------------------------------------
// next_scanline
//-------------------------------------------------
inline void mc6847_friend_device::next_scanline()
{
/* 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_VBLANK) &&
(m_logical_scanline >= LINES_VBLANK))
{
/* new frame, starts at top border */
m_physical_scanline = 0;
m_logical_scanline = 0;
m_logical_scanline_zone = SCANLINE_ZONE_TOP_BORDER;
new_frame();
}
else if ((m_logical_scanline_zone < SCANLINE_ZONE_VBLANK) && (m_physical_scanline >= m_lines_until_vblank))
{
/* 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 >= m_lines_until_retrace))
{
/* 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();
}
LOGMASKED(
LOG_NEXTLINE,
"mc6847_friend_device::next_scanline(): (vpos,hpos)=(%d,%d), m_physical_scanline='%d', m_logical_scanline_zone='%s', m_logical_scanline='%d'\n",
screen().vpos(),
screen().hpos(),
m_physical_scanline,
scanline_zone_string((scanline_zone)m_logical_scanline_zone),
m_logical_scanline);
}
//-------------------------------------------------
// is_top_pal_padding_line
//-------------------------------------------------
inline bool mc6847_friend_device::is_top_pal_padding_line(int scanline) const
{
// PAL adds 25 padding scanlines before top border
return m_pal && scanline < LINES_PADDING_TOP_PAL;
}
//-------------------------------------------------
// is_bottom_pal_padding_line
//-------------------------------------------------
inline bool mc6847_friend_device::is_bottom_pal_padding_line(int scanline) const
{
// PAL adds 25 padding scanlines nested INSIDE the bottom border
// (just a couple lines up from the end of the bottom border).
return m_pal &&
LINES_UNTIL_PADDING_BOTTOM_PAL <= scanline &&
scanline < LINES_UNTIL_PADDING_BOTTOM_PAL + LINES_PADDING_BOTTOM_PAL;
}
//-------------------------------------------------
// is_pal_padding_line
//-------------------------------------------------
inline bool mc6847_friend_device::is_pal_padding_line(int scanline) const
{
return is_top_pal_padding_line(scanline) || is_bottom_pal_padding_line(scanline);
}
//-------------------------------------------------
// new_frame
//-------------------------------------------------
void mc6847_friend_device::new_frame()
{
}
//-------------------------------------------------
// horizontal_sync_changed
//-------------------------------------------------
TIMER_CALLBACK_MEMBER(mc6847_friend_device::horizontal_sync_changed)
{
}
//-------------------------------------------------
// field_sync_changed
//-------------------------------------------------
void mc6847_friend_device::field_sync_changed(bool line)
{
}
//-------------------------------------------------
// enter_bottom_border
//-------------------------------------------------
void mc6847_friend_device::enter_bottom_border()
{
}
//-------------------------------------------------
// record_border_scanline
//-------------------------------------------------
void mc6847_friend_device::record_border_scanline(uint16_t physical_scanline)
{
}
//-------------------------------------------------
// get_clocks_since_hsync
//-------------------------------------------------
int32_t mc6847_friend_device::get_clocks_since_hsync()
{
uint64_t hsync_on_clocks = attotime_to_clocks(m_hsync_on_timer->start()) / m_divider;
uint64_t current_clocks = attotime_to_clocks(machine().time()) / m_divider;
return (int32_t) (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_t new_partial_scanline_clocks = get_clocks_since_hsync();
if (m_partial_scanline_clocks < new_partial_scanline_clocks)
{
LOGMASKED(LOG_FLUSH, "%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
//-------------------------------------------------
std::string mc6847_friend_device::describe_context() const
{
return string_format("%s (scanline %s:%d)",
machine().describe_context(),
scanline_zone_string((scanline_zone) m_logical_scanline_zone),
m_logical_scanline);
}
//**************************************************************************
// BASE DEVICE
//**************************************************************************
//-------------------------------------------------
// ctor
//-------------------------------------------------
mc6847_base_device::mc6847_base_device(
const machine_config &mconfig,
device_type type,
const char *tag,
device_t *owner,
uint32_t clock,
const uint8_t *fontdata,
double tpfs,
bool pal) :
mc6847_friend_device(mconfig, type, tag, owner, clock, fontdata, (type == MC6847T1_NTSC) || (type == MC6847T1_PAL),
tpfs, LINES_TOP_BORDER + LINES_ACTIVE_VIDEO - 1, 1, true, pal),
m_input_cb(*this, 0),
m_black_and_white(false),
m_fixed_mode(0),
m_fixed_mode_mask(0)
{
set_palette(s_palette);
}
//-------------------------------------------------
// setup_fixed_mode - sets up fixed mode mask
//-------------------------------------------------
void mc6847_base_device::setup_fixed_mode()
{
for (int i = 0; i < 8; i++)
{
if (BIT(m_fixed_mode, i))
m_fixed_mode_mask |= (1 << i);
}
}
//-------------------------------------------------
// device_config_complete - perform any
// operations now that the configuration is
// complete
//-------------------------------------------------
void mc6847_base_device::device_config_complete()
{
if (!has_screen())
return;
if (!screen().refresh_attoseconds())
{
// It is preferred to initialize the screen device using set_raw.
// Setting screen device's raw parameters requires values in terms of pixels.
// Multiplying the 6847's clock by 2 produces a pixel clock that allows
// 256 pixels of active video area per line, with apparently no roundoff
// error or drift.
screen().set_raw(
uint32_t(clock() * 2),
456, // htotal
0, // hbend
BMP_L_OR_R_BORDER * 2 + BMP_ACTIVE_VIDEO, // hbstart
m_tpfs, // vtotal
0, // vbend
m_lines_until_retrace); // vbstart
}
if (!screen().has_screen_update())
screen().set_screen_update(*this, FUNC(mc6847_base_device::screen_update));
}
//-------------------------------------------------
// device_start - device-specific startup
//-------------------------------------------------
void mc6847_base_device::device_start()
{
/* inherited function */
mc6847_friend_device::device_start();
/* setup */
memset(m_data, 0, sizeof(m_data));
/* resolve callbacks */
m_charrom_cb.resolve();
/* set up fixed mode */
setup_fixed_mode();
m_dirty = false;
m_mode = 0;
/* state save */
save_item(NAME(m_dirty));
save_item(NAME(m_mode));
/* colors */
if (m_black_and_white)
{
for (int i = 0; i < PALETTE_LENGTH; i++)
m_bw_palette[i] = black_and_white(m_palette[i]);
m_palette = m_bw_palette;
}
m_artifacter.create_color_blend_table(m_palette);
}
//-------------------------------------------------
// device_reset - device-specific reset
//-------------------------------------------------
void mc6847_base_device::device_reset()
{
mc6847_friend_device::device_reset();
m_mode = m_fixed_mode;
}
//-------------------------------------------------
// input
//-------------------------------------------------
uint8_t mc6847_base_device::input(uint16_t address)
{
uint8_t data = m_input_cb(address);
LOGMASKED(LOG_INPUT, "%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_t start_pos, int32_t end_pos)
{
// determine the "sample_modulo" (e.g. - for 32 samples per row, query the video RAM every
// position, for 16 samples per row, query every other position)
const int sample_modulo = 32 / sample_count;
static_assert((32 / sample_modulo) == sample_count, "Expected 32 to be divisible by sample_count");
uint8_t current_sample_count = (start_pos > 0) ? m_data[scanline].m_sample_count : 0;
// main loop
for (int32_t pos = start_pos; pos < end_pos; pos++)
{
// set address at beginning of line
if (pos == 0)
m_video_address = scanline / (LINES_ACTIVE_VIDEO / yres) * sample_count;
// are we sampling this position?
if ((pos % sample_modulo) == 0)
{
// input data
uint8_t data = input(m_video_address++);
if (pos < 32)
{
// update values
//assert(current_sample_count >= 0);
assert(current_sample_count < std::size(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
//-------------------------------------------------
void mc6847_base_device::record_body_scanline(uint8_t mode, uint16_t physical_scanline, uint16_t scanline, int32_t start_pos, int32_t end_pos)
{
// sanity checks
assert(scanline < LINES_ACTIVE_VIDEO);
if (mode & MODE_AG)
{
switch(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");
}
}
else
{
record_scanline_res<32, 16>(scanline, start_pos, end_pos);
}
}
//-------------------------------------------------
// record_body_scanline
//-------------------------------------------------
void mc6847_base_device::record_full_body_scanline(uint16_t physical_scanline, uint16_t scanline)
{
record_body_scanline(m_mode, physical_scanline, scanline, 0, 32);
}
//-------------------------------------------------
// record_partial_body_scanline
//-------------------------------------------------
void mc6847_base_device::record_partial_body_scanline(uint16_t physical_scanline, uint16_t scanline, int32_t start_clock, int32_t end_clock)
{
int32_t start_pos = std::max(scanline_position_from_clock(start_clock), 0);
int32_t end_pos = std::min(scanline_position_from_clock(end_clock), 42);
if (start_pos < end_pos)
record_body_scanline(m_mode, physical_scanline, scanline, start_pos, end_pos);
}
//-------------------------------------------------
// scanline_position_from_clock
//
// The hsync ON interrupt marks the end of the
// previous line and the beginning of the next
// line. Measuring clocks since hsync ON gives
// an offset into the current line. This converts
// the clocks offset into a "position" offset for
// use by the record functions as index into
// the video_scanline arrays
//-------------------------------------------------
int32_t mc6847_base_device::scanline_position_from_clock(int32_t clocks_since_hsync)
{
// This value determined by experimentation with coco_cart:drgnfire,
// which uses precise timing measurements to change video modes
// multiple times mid-line. This value seems to minimize video
// garbage, but doesn't eliminate it, so there are likely timing
// issues elsewhere.
//
// Unfortunately, I don't understand why this value isn't
// simply 0. I believe hsync-on appears AFTER the front-porch +
// HS pulse + back-porch combo, which should be the entirety of
// the horizontal blanking. But this value makes coco_cart:drgnfire
// significantly better than 0 does.
const int CLOCKS_OFFSET_TO_FIRST_VISIBLE_PIXEL = 25;
// Dividing by 4 converts 128 clocks per horizontal active video
// into 32 bytes per horizontal active video. The borders come
// along for the ride. They are 58 clocks total (for L + R), and
// dividing by 4 gives 14.5 bytes
return (clocks_since_hsync - CLOCKS_OFFSET_TO_FIRST_VISIBLE_PIXEL) / 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_input_cb(~0);
}
//-------------------------------------------------
// border_value
//-------------------------------------------------
uint8_t mc6847_base_device::border_value(uint8_t mode)
{
if (mode & MODE_AG)
{
// graphics, green or white
return (~mode & MODE_CSS) ? 0 : 4;
}
else
{
// text, black
return 8;
}
}
//-------------------------------------------------
// update
//-------------------------------------------------
uint32_t mc6847_base_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
int base_x = BMP_L_OR_R_BORDER;
int base_y = m_lines_top_border;
int min_x = USE_HORIZONTAL_CLIP ? cliprect.min_x : 0;
int max_x = USE_HORIZONTAL_CLIP ? cliprect.max_x : (base_x * 2 + BMP_ACTIVE_VIDEO - 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 (!m_artifacter.poll_config() && !has_video_changed())
return UPDATE_HAS_NOT_CHANGED;
/* top border */
for (int y = min_y; y < base_y; y++)
{
// PAL padding is always black, even when border isn't
const pixel_t color = is_top_pal_padding_line(y)
? palette[8]
: palette[border_value(m_data[0].m_mode[0])];
for (int x = min_x; x <= max_x; x++)
{
*bitmap_addr(bitmap, y, x) = color;
}
}
for (int y = std::max(0, min_y - base_y); y < std::min(LINES_ACTIVE_VIDEO, max_y - base_y); y++)
{
/* left border */
for (int x = min_x; x < base_x; x++)
{
*bitmap_addr(bitmap, y + base_y, x) = palette[border_value(m_data[y].m_mode[0])];
}
/* body */
const int width = m_data[y].m_sample_count;
pixel_t *RESTRICT pixels = bitmap_addr(bitmap, base_y + y, base_x);
for (int x = 0; x < width; )
{
/* determine how many bytes exist for which the mode is identical */
int x2;
for (x2 = x + 1; (x2 < width) && (m_data[y].m_mode[x] == m_data[y].m_mode[x2]); x2++)
;
/* emit the samples */
pixels += emit_samples(
m_data[y].m_mode[x],
&m_data[y].m_data[x],
x2 - x,
pixels,
m_palette,
m_charrom_cb,
x,
y);
/* update x */
x = x2;
}
/* right border */
if (width)
for (int x = base_x + BMP_ACTIVE_VIDEO; x <= max_x; x++)
*bitmap_addr(bitmap, y + base_y, x) = palette[border_value(m_data[y].m_mode[width - 1])];
/* artifacting */
if (m_artifacter.get_pal_artifacting())
{
if (y % 2)
m_artifacter.process_artifacts_pal<1>(bitmap, y - 1, base_x, base_y, m_data[y].m_mode[0], palette);
}
else
{
m_artifacter.process_artifacts<1>(bitmap_addr(bitmap, y + base_y, base_x), m_data[y].m_mode[0], palette);
}
}
const int width = m_data[LINES_ACTIVE_VIDEO-1].m_sample_count;
/* bottom border */
if (width)
{
for (int y = base_y + LINES_ACTIVE_VIDEO; y <= max_y; y++)
{
// PAL padding is always black, even when border isn't
pixel_t color = is_bottom_pal_padding_line(y)
? palette[8]
: palette[border_value(m_data[LINES_ACTIVE_VIDEO - 1].m_mode[width - 1])];
for (int x = min_x; x <= max_x; x++)
{
*bitmap_addr(bitmap, y, x) = color;
}
}
}
return 0;
}
//**************************************************************************
// CHARACTER MAP
//**************************************************************************
mc6847_friend_device::character_map::character_map(const uint8_t *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;
}
for (int i = 0; i < 128*12; i++)
m_stripes[i] = ~(i / 12);
// loop through all modes
for (mode = 0; mode < std::size(m_entries); mode++)
{
const uint8_t *fontdata;
uint8_t character_mask;
uint8_t color_shift_0 = 0;
uint8_t color_shift_1 = 0;
uint8_t color_mask_0 = 0x00;
uint8_t color_mask_1 = 0x00;
uint16_t color_base_0;
uint16_t color_base_1;
if ((mode & ((is_mc6847t1 ? 0 : MODE_INTEXT) | MODE_AS)) == 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 if (((mode & (MODE_INTEXT | MODE_AS)) == (MODE_INTEXT | MODE_AS)) && !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_INTEXT | MODE_AS)) == MODE_INTEXT) && !is_mc6847t1)
{
// so-called "stripe" mode - this is when INTEXT is specified but we don't have
// an external ROM nor are we on an MC6847T1
fontdata = m_stripes;
character_mask = 0x7F;
color_base_0 = (mode & MODE_CSS ? 14 : 12);
color_base_1 = (mode & MODE_CSS ? 15 : 13);
}
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;
}
}
//-------------------------------------------------
// vdg_t1_fontdata8x12
//-------------------------------------------------
const uint8_t mc6847_friend_device::vdg_t1_fontdata8x12[] =
{
0x00, 0x1C, 0x22, 0x02, 0x1A, 0x26, 0x22, 0x1C, 0x00, 0x00, 0x00, 0x00, /* @ */
0x00, 0x08, 0x14, 0x22, 0x22, 0x3E, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00, /* A */
0x00, 0x3C, 0x12, 0x12, 0x1C, 0x12, 0x12, 0x3C, 0x00, 0x00, 0x00, 0x00, /* B */
0x00, 0x1C, 0x22, 0x20, 0x20, 0x20, 0x22, 0x1C, 0x00, 0x00, 0x00, 0x00, /* C */
0x00, 0x3C, 0x12, 0x12, 0x12, 0x12, 0x12, 0x3C, 0x00, 0x00, 0x00, 0x00, /* D */
0x00, 0x3E, 0x20, 0x20, 0x38, 0x20, 0x20, 0x3E, 0x00, 0x00, 0x00, 0x00, /* E */
0x00, 0x3E, 0x20, 0x20, 0x38, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, /* F */
0x00, 0x1E, 0x20, 0x20, 0x26, 0x22, 0x22, 0x1E, 0x00, 0x00, 0x00, 0x00, /* G */
0x00, 0x22, 0x22, 0x22, 0x3E, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00, /* H */
0x00, 0x1C, 0x08, 0x08, 0x08, 0x08, 0x08, 0x1C, 0x00, 0x00, 0x00, 0x00, /* I */
0x00, 0x02, 0x02, 0x02, 0x02, 0x22, 0x22, 0x1C, 0x00, 0x00, 0x00, 0x00, /* J */
0x00, 0x22, 0x24, 0x28, 0x30, 0x28, 0x24, 0x22, 0x00, 0x00, 0x00, 0x00, /* K */
0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3E, 0x00, 0x00, 0x00, 0x00, /* L */
0x00, 0x22, 0x36, 0x2A, 0x2A, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00, /* M */
0x00, 0x22, 0x22, 0x32, 0x2A, 0x26, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00, /* N */
0x00, 0x1C, 0x22, 0x22, 0x22, 0x22, 0x22, 0x1C, 0x00, 0x00, 0x00, 0x00, /* O */
0x00, 0x3C, 0x22, 0x22, 0x3C, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, /* P */
0x00, 0x1C, 0x22, 0x22, 0x22, 0x2A, 0x24, 0x1A, 0x00, 0x00, 0x00, 0x00, /* Q */
0x00, 0x3C, 0x22, 0x22, 0x3C, 0x28, 0x24, 0x22, 0x00, 0x00, 0x00, 0x00, /* R */
0x00, 0x1C, 0x22, 0x20, 0x1C, 0x02, 0x22, 0x1C, 0x00, 0x00, 0x00, 0x00, /* S */
0x00, 0x3E, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, /* T */
0x00, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x1C, 0x00, 0x00, 0x00, 0x00, /* U */
0x00, 0x22, 0x22, 0x22, 0x14, 0x14, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, /* V */
0x00, 0x22, 0x22, 0x22, 0x22, 0x2A, 0x36, 0x22, 0x00, 0x00, 0x00, 0x00, /* W */
0x00, 0x22, 0x22, 0x14, 0x08, 0x14, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00, /* X */
0x00, 0x22, 0x22, 0x14, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, /* Y */
0x00, 0x3E, 0x02, 0x04, 0x08, 0x10, 0x20, 0x3E, 0x00, 0x00, 0x00, 0x00, /* Z */
0x00, 0x1C, 0x10, 0x10, 0x10, 0x10, 0x10, 0x1C, 0x00, 0x00, 0x00, 0x00, /* [ */
0x00, 0x00, 0x20, 0x10, 0x08, 0x04, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, /* \ */
0x00, 0x1C, 0x04, 0x04, 0x04, 0x04, 0x04, 0x1C, 0x00, 0x00, 0x00, 0x00, /* ] */
0x00, 0x08, 0x1C, 0x2A, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, /* up arrow */
0x00, 0x00, 0x08, 0x10, 0x3E, 0x10, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, /* left arrow */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* space */
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, 0x3E, 0x00, 0x3E, 0x14, 0x14, 0x00, 0x00, 0x00, 0x00, /* # */
0x00, 0x08, 0x1E, 0x20, 0x1C, 0x02, 0x3C, 0x08, 0x00, 0x00, 0x00, 0x00, /* $ */
0x00, 0x30, 0x32, 0x04, 0x08, 0x10, 0x26, 0x06, 0x00, 0x00, 0x00, 0x00, /* % */
0x00, 0x10, 0x28, 0x28, 0x10, 0x2A, 0x24, 0x1A, 0x00, 0x00, 0x00, 0x00, /* & */
0x00, 0x18, 0x18, 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' */
0x00, 0x04, 0x08, 0x10, 0x10, 0x10, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, /* ( */
0x00, 0x10, 0x08, 0x04, 0x04, 0x04, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, /* ) */
0x00, 0x00, 0x08, 0x2A, 0x1C, 0x1C, 0x2A, 0x08, 0x00, 0x00, 0x00, 0x00, /* * */
0x00, 0x00, 0x08, 0x08, 0x3E, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, /* + */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x10, 0x20, 0x00, 0x00, /* , */
0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* - */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, /* . */
0x00, 0x00, 0x02, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, /* / */
0x00, 0x1C, 0x22, 0x26, 0x2A, 0x32, 0x22, 0x1C, 0x00, 0x00, 0x00, 0x00, /* 0 */
0x00, 0x08, 0x18, 0x08, 0x08, 0x08, 0x08, 0x1C, 0x00, 0x00, 0x00, 0x00, /* 1 */
0x00, 0x1C, 0x22, 0x02, 0x1C, 0x20, 0x20, 0x3E, 0x00, 0x00, 0x00, 0x00, /* 2 */
0x00, 0x1C, 0x22, 0x02, 0x0C, 0x02, 0x22, 0x1C, 0x00, 0x00, 0x00, 0x00, /* 3 */
0x00, 0x04, 0x0C, 0x14, 0x24, 0x3E, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, /* 4 */
0x00, 0x3E, 0x20, 0x3C, 0x02, 0x02, 0x22, 0x1C, 0x00, 0x00, 0x00, 0x00, /* 5 */
0x00, 0x0C, 0x10, 0x20, 0x3C, 0x22, 0x22, 0x1C, 0x00, 0x00, 0x00, 0x00, /* 6 */
0x00, 0x3E, 0x02, 0x04, 0x08, 0x10, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, /* 7 */
0x00, 0x1C, 0x22, 0x22, 0x1C, 0x22, 0x22, 0x1C, 0x00, 0x00, 0x00, 0x00, /* 8 */
0x00, 0x1C, 0x22, 0x22, 0x1E, 0x02, 0x04, 0x18, 0x00, 0x00, 0x00, 0x00, /* 9 */
0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, /* : */
0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x10, 0x20, 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, 0x1C, 0x22, 0x02, 0x04, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, /* ? */
/* lower case */
0x00, 0x08, 0x14, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ^ */
0x00, 0x00, 0x00, 0x1C, 0x02, 0x1E, 0x22, 0x1E, 0x00, 0x00, 0x00, 0x00, /* a */
0x00, 0x20, 0x20, 0x2C, 0x32, 0x22, 0x32, 0x2C, 0x00, 0x00, 0x00, 0x00, /* b */
0x00, 0x00, 0x00, 0x1C, 0x22, 0x20, 0x22, 0x1C, 0x00, 0x00, 0x00, 0x00, /* c */
0x00, 0x02, 0x02, 0x1A, 0x26, 0x22, 0x26, 0x1A, 0x00, 0x00, 0x00, 0x00, /* d */
0x00, 0x00, 0x00, 0x1C, 0x22, 0x3E, 0x20, 0x1C, 0x00, 0x00, 0x00, 0x00, /* e */
0x00, 0x04, 0x0A, 0x08, 0x1C, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, /* f */
0x00, 0x00, 0x00, 0x1A, 0x26, 0x26, 0x1A, 0x02, 0x22, 0x1C, 0x00, 0x00, /* g */
0x00, 0x20, 0x20, 0x2C, 0x32, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00, /* h */
0x00, 0x08, 0x00, 0x18, 0x08, 0x08, 0x08, 0x1C, 0x00, 0x00, 0x00, 0x00, /* i */
0x00, 0x00, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x22, 0x1C, 0x00, 0x00, /* j */
0x00, 0x20, 0x20, 0x24, 0x28, 0x30, 0x28, 0x24, 0x00, 0x00, 0x00, 0x00, /* k */
0x00, 0x18, 0x08, 0x08, 0x08, 0x08, 0x08, 0x1C, 0x00, 0x00, 0x00, 0x00, /* l */
0x00, 0x00, 0x00, 0x34, 0x2A, 0x2A, 0x2A, 0x2A, 0x00, 0x00, 0x00, 0x00, /* m */
0x00, 0x00, 0x00, 0x2C, 0x32, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00, /* n */
0x00, 0x00, 0x00, 0x1C, 0x22, 0x22, 0x22, 0x1C, 0x00, 0x00, 0x00, 0x00, /* o */
0x00, 0x00, 0x00, 0x2C, 0x32, 0x22, 0x32, 0x2C, 0x20, 0x20, 0x00, 0x00, /* p */
0x00, 0x00, 0x00, 0x1A, 0x26, 0x22, 0x26, 0x1A, 0x02, 0x02, 0x00, 0x00, /* q */
0x00, 0x00, 0x00, 0x2C, 0x32, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, /* r */
0x00, 0x00, 0x00, 0x1E, 0x20, 0x1C, 0x02, 0x3C, 0x00, 0x00, 0x00, 0x00, /* s */
0x00, 0x08, 0x08, 0x3E, 0x08, 0x08, 0x0A, 0x04, 0x00, 0x00, 0x00, 0x00, /* t */
0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x26, 0x1A, 0x00, 0x00, 0x00, 0x00, /* u */
0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x14, 0x08, 0x00, 0x00, 0x00, 0x00, /* v */
0x00, 0x00, 0x00, 0x22, 0x22, 0x2A, 0x2A, 0x14, 0x00, 0x00, 0x00, 0x00, /* w */
0x00, 0x00, 0x00, 0x22, 0x14, 0x08, 0x14, 0x22, 0x00, 0x00, 0x00, 0x00, /* x */
0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x1E, 0x02, 0x22, 0x1C, 0x00, 0x00, /* y */
0x00, 0x00, 0x00, 0x3E, 0x04, 0x08, 0x10, 0x3E, 0x00, 0x00, 0x00, 0x00, /* z */
0x00, 0x04, 0x08, 0x08, 0x10, 0x08, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, /* { */
0x00, 0x08, 0x08, 0x08, 0x00, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, /* | */
0x00, 0x10, 0x08, 0x08, 0x04, 0x08, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, /* } */
0x00, 0x10, 0x2A, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ~ */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00 /* _ */
};
//-------------------------------------------------
// vdg_fontdata8x12
//-------------------------------------------------
const uint8_t mc6847_friend_device::vdg_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, /* A */
0x00, 0x00, 0x00, 0x3C, 0x12, 0x12, 0x1C, 0x12, 0x12, 0x3C, 0x00, 0x00, /* B */
0x00, 0x00, 0x00, 0x1C, 0x22, 0x20, 0x20, 0x20, 0x22, 0x1C, 0x00, 0x00, /* C */
0x00, 0x00, 0x00, 0x3C, 0x12, 0x12, 0x12, 0x12, 0x12, 0x3C, 0x00, 0x00, /* D */
0x00, 0x00, 0x00, 0x3E, 0x20, 0x20, 0x3C, 0x20, 0x20, 0x3E, 0x00, 0x00, /* E */
0x00, 0x00, 0x00, 0x3E, 0x20, 0x20, 0x3C, 0x20, 0x20, 0x20, 0x00, 0x00, /* F */
0x00, 0x00, 0x00, 0x1E, 0x20, 0x20, 0x26, 0x22, 0x22, 0x1E, 0x00, 0x00, /* G */
0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x3E, 0x22, 0x22, 0x22, 0x00, 0x00, /* H */
0x00, 0x00, 0x00, 0x1C, 0x08, 0x08, 0x08, 0x08, 0x08, 0x1C, 0x00, 0x00, /* I */
0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x22, 0x22, 0x1C, 0x00, 0x00, /* J */
0x00, 0x00, 0x00, 0x22, 0x24, 0x28, 0x30, 0x28, 0x24, 0x22, 0x00, 0x00, /* K */
0x00, 0x00, 0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3E, 0x00, 0x00, /* L */
0x00, 0x00, 0x00, 0x22, 0x36, 0x2A, 0x2A, 0x22, 0x22, 0x22, 0x00, 0x00, /* M */
0x00, 0x00, 0x00, 0x22, 0x32, 0x2A, 0x26, 0x22, 0x22, 0x22, 0x00, 0x00, /* N */
0x00, 0x00, 0x00, 0x3E, 0x22, 0x22, 0x22, 0x22, 0x22, 0x3E, 0x00, 0x00, /* O */
0x00, 0x00, 0x00, 0x3C, 0x22, 0x22, 0x3C, 0x20, 0x20, 0x20, 0x00, 0x00, /* P */
0x00, 0x00, 0x00, 0x1C, 0x22, 0x22, 0x22, 0x2A, 0x24, 0x1A, 0x00, 0x00, /* Q */
0x00, 0x00, 0x00, 0x3C, 0x22, 0x22, 0x3C, 0x28, 0x24, 0x22, 0x00, 0x00, /* R */
0x00, 0x00, 0x00, 0x1C, 0x22, 0x10, 0x08, 0x04, 0x22, 0x1C, 0x00, 0x00, /* S */
0x00, 0x00, 0x00, 0x3E, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, /* T */
0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x1C, 0x00, 0x00, /* U */
0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x14, 0x14, 0x08, 0x08, 0x00, 0x00, /* V */
0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x2A, 0x2A, 0x36, 0x22, 0x00, 0x00, /* W */
0x00, 0x00, 0x00, 0x22, 0x22, 0x14, 0x08, 0x14, 0x22, 0x22, 0x00, 0x00, /* X */
0x00, 0x00, 0x00, 0x22, 0x22, 0x14, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, /* Y */
0x00, 0x00, 0x00, 0x3E, 0x02, 0x04, 0x08, 0x10, 0x20, 0x3E, 0x00, 0x00, /* Z */
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, /* up arrow */
0x00, 0x00, 0x00, 0x00, 0x08, 0x10, 0x3E, 0x10, 0x08, 0x00, 0x00, 0x00, /* left arrow */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* space */
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, /* 0 */
0x00, 0x00, 0x00, 0x08, 0x18, 0x08, 0x08, 0x08, 0x08, 0x1C, 0x00, 0x00, /* 1 */
0x00, 0x00, 0x00, 0x1C, 0x22, 0x02, 0x1C, 0x20, 0x20, 0x3E, 0x00, 0x00, /* 2 */
0x00, 0x00, 0x00, 0x1C, 0x22, 0x02, 0x0C, 0x02, 0x22, 0x1C, 0x00, 0x00, /* 3 */
0x00, 0x00, 0x00, 0x04, 0x0C, 0x14, 0x3E, 0x04, 0x04, 0x04, 0x00, 0x00, /* 4 */
0x00, 0x00, 0x00, 0x3E, 0x20, 0x3C, 0x02, 0x02, 0x22, 0x1C, 0x00, 0x00, /* 5 */
0x00, 0x00, 0x00, 0x1C, 0x20, 0x20, 0x3C, 0x22, 0x22, 0x1C, 0x00, 0x00, /* 6 */
0x00, 0x00, 0x00, 0x3E, 0x02, 0x04, 0x08, 0x10, 0x20, 0x20, 0x00, 0x00, /* 7 */
0x00, 0x00, 0x00, 0x1C, 0x22, 0x22, 0x1C, 0x22, 0x22, 0x1C, 0x00, 0x00, /* 8 */
0x00, 0x00, 0x00, 0x1C, 0x22, 0x22, 0x1E, 0x02, 0x02, 0x1C, 0x00, 0x00, /* 9 */
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, /* a */
0x00, 0x00, 0x00, 0x20, 0x20, 0x3C, 0x22, 0x22, 0x22, 0x3C, 0x00, 0x00, /* b */
0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x20, 0x20, 0x20, 0x1C, 0x00, 0x00, /* c */
0x00, 0x00, 0x00, 0x02, 0x02, 0x1E, 0x22, 0x22, 0x22, 0x1E, 0x00, 0x00, /* d */
0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x22, 0x3E, 0x20, 0x1C, 0x00, 0x00, /* e */
0x00, 0x00, 0x00, 0x0C, 0x12, 0x10, 0x38, 0x10, 0x10, 0x10, 0x00, 0x00, /* f */
0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x22, 0x22, 0x22, 0x1E, 0x02, 0x1C, /* g */
0x00, 0x00, 0x00, 0x20, 0x20, 0x3C, 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, /* h */
0x00, 0x00, 0x00, 0x08, 0x00, 0x18, 0x08, 0x08, 0x08, 0x1C, 0x00, 0x00, /* i */
0x00, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x04, 0x04, 0x04, 0x04, 0x24, 0x18, /* j */
0x00, 0x00, 0x00, 0x20, 0x20, 0x24, 0x28, 0x38, 0x24, 0x22, 0x00, 0x00, /* k */
0x00, 0x00, 0x00, 0x18, 0x08, 0x08, 0x08, 0x08, 0x08, 0x1C, 0x00, 0x00, /* l */
0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x2A, 0x2A, 0x2A, 0x2A, 0x00, 0x00, /* m */
0x00, 0x00, 0x00, 0x00, 0x00, 0x2C, 0x32, 0x22, 0x22, 0x22, 0x00, 0x00, /* n */
0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x22, 0x22, 0x22, 0x1C, 0x00, 0x00, /* o */
0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x22, 0x22, 0x22, 0x3C, 0x20, 0x20, /* p */
0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x22, 0x22, 0x22, 0x1E, 0x02, 0x03, /* q */
0x00, 0x00, 0x00, 0x00, 0x00, 0x2C, 0x32, 0x20, 0x20, 0x20, 0x00, 0x00, /* r */
0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x20, 0x1C, 0x02, 0x3C, 0x00, 0x00, /* s */
0x00, 0x00, 0x00, 0x10, 0x3C, 0x10, 0x10, 0x10, 0x12, 0x0C, 0x00, 0x00, /* t */
0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x26, 0x1A, 0x00, 0x00, /* u */
0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x14, 0x14, 0x08, 0x00, 0x00, /* v */
0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x2A, 0x2A, 0x1C, 0x14, 0x00, 0x00, /* w */
0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x14, 0x08, 0x14, 0x22, 0x00, 0x00, /* x */
0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x1E, 0x02, 0x1C, /* y */
0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x04, 0x08, 0x10, 0x3E, 0x00, 0x00, /* z */
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 /* _ */
};
//-------------------------------------------------
// s68047_fontdata8x12
//-------------------------------------------------
const uint8_t mc6847_friend_device::s68047_fontdata8x12[] =
{
0x00, 0x00, 0x00, 0x1C, 0x22, 0x2A, 0x2A, 0x2C, 0x20, 0x1E, 0x00, 0x00,
0x00, 0x00, 0x00, 0x08, 0x14, 0x22, 0x22, 0x3E, 0x22, 0x22, 0x00, 0x00,
0x00, 0x00, 0x00, 0x3C, 0x22, 0x22, 0x3C, 0x22, 0x22, 0x3C, 0x00, 0x00,
0x00, 0x00, 0x00, 0x1C, 0x22, 0x20, 0x20, 0x20, 0x22, 0x1C, 0x00, 0x00,
0x00, 0x00, 0x00, 0x3C, 0x22, 0x22, 0x22, 0x22, 0x22, 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, 0x1C, 0x22, 0x20, 0x20, 0x26, 0x22, 0x1C, 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, 0x02, 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, 0x32, 0x2A, 0x26, 0x26, 0x22, 0x00, 0x00,
0x00, 0x00, 0x00, 0x1C, 0x22, 0x22, 0x22, 0x22, 0x22, 0x1C, 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, 0x20, 0x1C, 0x02, 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, 0x2A, 0x14, 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, 0x1C, 0x10, 0x10, 0x10, 0x10, 0x10, 0x1C, 0x00, 0x00,
0x00, 0x00, 0x00, 0x20, 0x20, 0x10, 0x08, 0x04, 0x02, 0x02, 0x00, 0x00,
0x00, 0x00, 0x00, 0x1C, 0x04, 0x04, 0x04, 0x04, 0x04, 0x1C, 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, 0x3E, 0x14, 0x3E, 0x14, 0x14, 0x00, 0x00,
0x00, 0x00, 0x00, 0x08, 0x1E, 0x28, 0x1C, 0x0A, 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, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x04, 0x08, 0x10, 0x10, 0x10, 0x08, 0x04, 0x00, 0x00,
0x00, 0x00, 0x00, 0x10, 0x08, 0x04, 0x04, 0x04, 0x08, 0x10, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x08, 0x2A, 0x1C, 0x2A, 0x08, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x3E, 0x08, 0x08, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x10, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00,
0x00, 0x00, 0x00, 0x02, 0x02, 0x04, 0x08, 0x10, 0x20, 0x20, 0x00, 0x00,
0x00, 0x00, 0x00, 0x1C, 0x22, 0x26, 0x2A, 0x32, 0x22, 0x1C, 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, 0x3E, 0x02, 0x04, 0x0C, 0x02, 0x22, 0x1C, 0x00, 0x00,
0x00, 0x00, 0x00, 0x04, 0x0C, 0x14, 0x24, 0x3E, 0x04, 0x04, 0x00, 0x00,
0x00, 0x00, 0x00, 0x3E, 0x20, 0x3C, 0x02, 0x02, 0x22, 0x1C, 0x00, 0x00,
0x00, 0x00, 0x00, 0x0E, 0x10, 0x20, 0x3C, 0x22, 0x22, 0x1C, 0x00, 0x00,
0x00, 0x00, 0x00, 0x3E, 0x02, 0x02, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00,
0x00, 0x00, 0x00, 0x1C, 0x22, 0x22, 0x1C, 0x22, 0x22, 0x1C, 0x00, 0x00,
0x00, 0x00, 0x00, 0x1C, 0x22, 0x22, 0x1E, 0x02, 0x04, 0x38, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x08, 0x08, 0x10, 0x00, 0x00,
0x00, 0x00, 0x00, 0x06, 0x08, 0x10, 0x20, 0x10, 0x08, 0x06, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x30, 0x08, 0x04, 0x02, 0x04, 0x08, 0x30, 0x00, 0x00,
0x00, 0x00, 0x00, 0x1C, 0x22, 0x02, 0x04, 0x08, 0x00, 0x08, 0x00, 0x00,
// No lower case, copy/paste of first 32 characters
0x00, 0x00, 0x00, 0x1C, 0x22, 0x2A, 0x2A, 0x2C, 0x20, 0x1E, 0x00, 0x00,
0x00, 0x00, 0x00, 0x08, 0x14, 0x22, 0x22, 0x3E, 0x22, 0x22, 0x00, 0x00,
0x00, 0x00, 0x00, 0x3C, 0x22, 0x22, 0x3C, 0x22, 0x22, 0x3C, 0x00, 0x00,
0x00, 0x00, 0x00, 0x1C, 0x22, 0x20, 0x20, 0x20, 0x22, 0x1C, 0x00, 0x00,
0x00, 0x00, 0x00, 0x3C, 0x22, 0x22, 0x22, 0x22, 0x22, 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, 0x1C, 0x22, 0x20, 0x20, 0x26, 0x22, 0x1C, 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, 0x02, 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, 0x32, 0x2A, 0x26, 0x26, 0x22, 0x00, 0x00,
0x00, 0x00, 0x00, 0x1C, 0x22, 0x22, 0x22, 0x22, 0x22, 0x1C, 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, 0x20, 0x1C, 0x02, 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, 0x2A, 0x14, 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, 0x1C, 0x10, 0x10, 0x10, 0x10, 0x10, 0x1C, 0x00, 0x00,
0x00, 0x00, 0x00, 0x20, 0x20, 0x10, 0x08, 0x04, 0x02, 0x02, 0x00, 0x00,
0x00, 0x00, 0x00, 0x1C, 0x04, 0x04, 0x04, 0x04, 0x04, 0x1C, 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,
};
//-------------------------------------------------
// semigraphics4_fontdata8x12
//-------------------------------------------------
const uint8_t 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_t 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_palartifacting = false;
m_config = nullptr;
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)
{
std::string port_name = util::string_format("%s:%s", device->tag(), ARTIFACTING_TAG);
m_config = device->ioport(port_name);
}
//-------------------------------------------------
// artifacter::poll_config
//-------------------------------------------------
bool mc6847_base_device::artifacter::poll_config()
{
ioport_value new_artifacting = m_config ? m_config->read() : 0;
bool changed = new_artifacting != m_artifacting;
m_artifacting = new_artifacting;
return changed;
}
//-------------------------------------------------
// 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 implementation. 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_t 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_t c0, uint8_t c1)
{
return (uint32_t) (uint8_t) ((c0 * (1.0 - factor)) + (c1 * (0.0 + factor)) + 0.5);
}
//-------------------------------------------------
// artifacter::create_color_blend_table
//-------------------------------------------------
void mc6847_base_device::artifacter::create_color_blend_table( const pixel_t *palette )
{
// PAL color blend map
m_palcolorblendmap.insert(std::pair<std::pair<pixel_t,pixel_t>,pixel_t>(std::pair<pixel_t,pixel_t>(palette[3],palette[2]),rgb_t(0x7c, 0x2e, 0x81))); /* RED-BLUE */
m_palcolorblendmap.insert(std::pair<std::pair<pixel_t,pixel_t>,pixel_t>(std::pair<pixel_t,pixel_t>(palette[2],palette[3]),rgb_t(0x6b, 0x3e, 0x6b))); /* BLUE-RED */
m_palcolorblendmap.insert(std::pair<std::pair<pixel_t,pixel_t>,pixel_t>(std::pair<pixel_t,pixel_t>(palette[7],palette[6]),rgb_t(0xbe, 0x73, 0x65))); /* ORANGE-MAGENTA */
m_palcolorblendmap.insert(std::pair<std::pair<pixel_t,pixel_t>,pixel_t>(std::pair<pixel_t,pixel_t>(palette[6],palette[7]),rgb_t(0xde, 0x5f, 0x6a))); /* MAGENTA-ORANGE */
m_palcolorblendmap.insert(std::pair<std::pair<pixel_t,pixel_t>,pixel_t>(std::pair<pixel_t,pixel_t>(palette[7],palette[5]),rgb_t(0x7e, 0xa2, 0x00))); /* ORANGE-CYAN */
m_palcolorblendmap.insert(std::pair<std::pair<pixel_t,pixel_t>,pixel_t>(std::pair<pixel_t,pixel_t>(palette[5],palette[7]),rgb_t(0x99, 0x8d, 0x3c))); /* CYAN-ORANGE */
m_palcolorblendmap.insert(std::pair<std::pair<pixel_t,pixel_t>,pixel_t>(std::pair<pixel_t,pixel_t>(palette[5],palette[6]),rgb_t(0x82, 0x80, 0xc5))); /* CYAN-MAGENTA */
m_palcolorblendmap.insert(std::pair<std::pair<pixel_t,pixel_t>,pixel_t>(std::pair<pixel_t,pixel_t>(palette[6],palette[5]),rgb_t(0x89, 0x80, 0x9f))); /* MAGENTA-CYAN */
m_palcolorblendmap.insert(std::pair<std::pair<pixel_t,pixel_t>,pixel_t>(std::pair<pixel_t,pixel_t>(palette[0],palette[5]),rgb_t(0x44, 0xb7, 0x1b))); /* GREEN-CYAN */
m_palcolorblendmap.insert(std::pair<std::pair<pixel_t,pixel_t>,pixel_t>(std::pair<pixel_t,pixel_t>(palette[5],palette[0]),rgb_t(0x4a, 0xf2, 0x70))); /* CYAN-GREEN */
m_palcolorblendmap.insert(std::pair<std::pair<pixel_t,pixel_t>,pixel_t>(std::pair<pixel_t,pixel_t>(palette[1],palette[4]),rgb_t(0xdc, 0xd2, 0x57))); /* YELLOW-BUFF */
m_palcolorblendmap.insert(std::pair<std::pair<pixel_t,pixel_t>,pixel_t>(std::pair<pixel_t,pixel_t>(palette[4],palette[1]),rgb_t(0xd1, 0xf6, 0x95))); /* BUFF-YELLOW */
m_palcolorblendmap.insert(std::pair<std::pair<pixel_t,pixel_t>,pixel_t>(std::pair<pixel_t,pixel_t>(palette[0],palette[6]),rgb_t(0xa6, 0x86, 0x10))); /* GREEN-MAGENTA */
m_palcolorblendmap.insert(std::pair<std::pair<pixel_t,pixel_t>,pixel_t>(std::pair<pixel_t,pixel_t>(palette[6],palette[0]),rgb_t(0x6b, 0xbe, 0xb3))); /* MAGENTA-GREEN */
m_palcolorblendmap.insert(std::pair<std::pair<pixel_t,pixel_t>,pixel_t>(std::pair<pixel_t,pixel_t>(palette[0],palette[7]),rgb_t(0x91, 0xc5, 0x3b))); /* GREEN-ORANGE */
m_palcolorblendmap.insert(std::pair<std::pair<pixel_t,pixel_t>,pixel_t>(std::pair<pixel_t,pixel_t>(palette[7],palette[0]),rgb_t(0xad, 0xbc, 0x22))); /* ORANGE-GREEN */
}
//**************************************************************************
// VARIATIONS
//**************************************************************************
DEFINE_DEVICE_TYPE(MC6847_NTSC, mc6847_ntsc_device, "mc6847_ntsc", "Motorola MC6847 VDG (NTSC)")
DEFINE_DEVICE_TYPE(MC6847_PAL, mc6847_pal_device, "mc6847_pal", "Motorola MC6847 VDG (PAL)")
DEFINE_DEVICE_TYPE(MC6847Y_NTSC, mc6847y_ntsc_device, "mc6847y_ntsc", "Motorola MC6847Y VDG (NTSC)")
DEFINE_DEVICE_TYPE(MC6847Y_PAL, mc6847y_pal_device, "mc6847y_pal", "Motorola MC6847Y VDG (PAL)")
DEFINE_DEVICE_TYPE(MC6847T1_NTSC, mc6847t1_ntsc_device, "mc6847t1_ntsc", "Motorola MC6847T1 VDG (NTSC)")
DEFINE_DEVICE_TYPE(MC6847T1_PAL, mc6847t1_pal_device, "mc6847t1_pal", "Motorola MC6847T1 VDG (PAL)")
DEFINE_DEVICE_TYPE(S68047, s68047_device, "s68047", "AMI S68047 VDG")
DEFINE_DEVICE_TYPE(M5C6847P1, m5c6847p1_device, "m5c6847p1", "Mitsubishi M5C6847P-1 VDG")
//-------------------------------------------------
// mc6847_ntsc_device
//-------------------------------------------------
mc6847_ntsc_device::mc6847_ntsc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: mc6847_base_device(mconfig, MC6847_NTSC, tag, owner, clock, vdg_fontdata8x12, 262.0, false)
{
}
//-------------------------------------------------
// mc6847_pal_device
//-------------------------------------------------
mc6847_pal_device::mc6847_pal_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: mc6847_base_device(mconfig, MC6847_PAL, tag, owner, clock, vdg_fontdata8x12, 312.0, true)
{
m_artifacter.set_pal_artifacting(true);
}
//-------------------------------------------------
// mc6847y_ntsc_device
//-------------------------------------------------
mc6847y_ntsc_device::mc6847y_ntsc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: mc6847_base_device(mconfig, MC6847Y_NTSC, tag, owner, clock, vdg_fontdata8x12, 262.5, false)
{
}
//-------------------------------------------------
// mc6847y_pal_device
//-------------------------------------------------
mc6847y_pal_device::mc6847y_pal_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: mc6847_base_device(mconfig, MC6847Y_PAL, tag, owner, clock, vdg_fontdata8x12, 312.0, true)
{
m_artifacter.set_pal_artifacting(true);
}
//-------------------------------------------------
// mc6847t1_ntsc_device
//-------------------------------------------------
mc6847t1_ntsc_device::mc6847t1_ntsc_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, const uint8_t *fontdata, double tpfs, bool pal)
: mc6847_base_device(mconfig, type, tag, owner, clock, fontdata, tpfs, pal)
{
}
mc6847t1_ntsc_device::mc6847t1_ntsc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: mc6847t1_ntsc_device(mconfig, MC6847T1_NTSC, tag, owner, clock, vdg_t1_fontdata8x12, 262.0, false)
{
}
uint8_t mc6847t1_ntsc_device::border_value(uint8_t mode)
{
if (mode & MODE_AG)
{
// graphics, green or white
return (~mode & MODE_CSS) ? 0 : 4;
}
else if (mode & MODE_GM2)
{
// text, green or orange
return (~mode & MODE_CSS) ? 0 : 7;
}
else
{
// text, black
return 8;
}
}
//-------------------------------------------------
// mc6847t1_pal_device
//-------------------------------------------------
mc6847t1_pal_device::mc6847t1_pal_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: mc6847t1_ntsc_device(mconfig, MC6847T1_PAL, tag, owner, clock, vdg_t1_fontdata8x12, 312.0, true)
{
m_artifacter.set_pal_artifacting(true);
}
//-------------------------------------------------
// s68047_device
//-------------------------------------------------
s68047_device::s68047_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: mc6847_base_device(mconfig, S68047, tag, owner, clock, s68047_fontdata8x12, 262.0, false)
{
set_palette(s_s68047_palette);
}
// AMI S68047 colors are different from MC6847
const uint32_t s68047_device::s_s68047_palette[16] =
{
rgb_t(0x30, 0xd2, 0x00), // GREEN
rgb_t(0xc1, 0xe5, 0x00), // YELLOW
rgb_t(0x41, 0xaf, 0x71), // CYAN
rgb_t(0x9a, 0x32, 0x36), // RED
rgb_t(0x4c, 0x3a, 0xb4), // BLUE
rgb_t(0x20, 0xd8, 0xe0), // CYAN/BLUE
rgb_t(0xc8, 0x4e, 0xf0), // MAGENTA
rgb_t(0xd4, 0x7f, 0x00), // ORANGE
rgb_t(0x26, 0x30, 0x16), // BLACK
rgb_t(0x30, 0xd2, 0x00), // GREEN
rgb_t(0x26, 0x30, 0x16), // BLACK
rgb_t(0x20, 0xd8, 0xe0), // CYAN/BLUE
rgb_t(0x00, 0x7c, 0x00), // BLACK
rgb_t(0x30, 0xd2, 0x00), // GREEN
rgb_t(0x00, 0x00, 0x6a), // BLACK
rgb_t(0x4c, 0x3a, 0xb4) // BLUE
};
uint8_t s68047_device::border_value(uint8_t mode)
{
if (mode & MODE_AG)
{
// graphics, green or cyan/blue
return (~mode & MODE_CSS) ? 9 : 11;
}
else
{
// text, same as text background
return (~mode & MODE_CSS) ? 12 : 14;
}
}
// GRAPHICS 5 mode (GM0 + GM2) is 256*96 instead of 128*192
void s68047_device::record_body_scanline(uint8_t mode, uint16_t physical_scanline, uint16_t scanline, int32_t start_pos, int32_t end_pos)
{
if ((mode & (MODE_AG|MODE_GM2|MODE_GM1|MODE_GM0)) == (MODE_AG|MODE_GM2|MODE_GM0))
record_scanline_res<32, 96>(scanline, start_pos, end_pos);
else
mc6847_base_device::record_body_scanline(mode, physical_scanline, scanline, start_pos, end_pos);
}
uint32_t s68047_device::emit_samples(uint8_t mode, const uint8_t *data, int length, pixel_t *RESTRICT pixels,
const pixel_t *RESTRICT palette, get_char_rom_delegate const &get_char_rom, int x, int y)
{
if ((mode & (MODE_AG|MODE_GM2|MODE_GM1|MODE_GM0)) == (MODE_AG|MODE_GM2|MODE_GM0))
{
emit_graphics<1, 1>(data, length, pixels, (mode & MODE_CSS) ? 10 : 8, palette);
return length * 8;
}
else
return emit_mc6847_samples<1>(mode, data, length, pixels, palette, get_char_rom, x, y);
}
//-------------------------------------------------
// m5c6847p1_device
//-------------------------------------------------
m5c6847p1_device::m5c6847p1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: mc6847_base_device(mconfig, M5C6847P1, tag, owner, clock, vdg_fontdata8x12, 262.5, false)
{
}