// license:BSD-3-Clause // copyright-holders:Nathan Woods /********************************************************************* mc6847.cpp 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_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) , 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) { // 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, 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 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) { // set up font data for (int 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 (int 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 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]; /* 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 (int 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 (int 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,pixel_t>(std::pair(palette[3],palette[2]),rgb_t(0x7c, 0x2e, 0x81))); /* RED-BLUE */ m_palcolorblendmap.insert(std::pair,pixel_t>(std::pair(palette[2],palette[3]),rgb_t(0x6b, 0x3e, 0x6b))); /* BLUE-RED */ m_palcolorblendmap.insert(std::pair,pixel_t>(std::pair(palette[7],palette[6]),rgb_t(0xbe, 0x73, 0x65))); /* ORANGE-MAGENTA */ m_palcolorblendmap.insert(std::pair,pixel_t>(std::pair(palette[6],palette[7]),rgb_t(0xde, 0x5f, 0x6a))); /* MAGENTA-ORANGE */ m_palcolorblendmap.insert(std::pair,pixel_t>(std::pair(palette[7],palette[5]),rgb_t(0x7e, 0xa2, 0x00))); /* ORANGE-CYAN */ m_palcolorblendmap.insert(std::pair,pixel_t>(std::pair(palette[5],palette[7]),rgb_t(0x99, 0x8d, 0x3c))); /* CYAN-ORANGE */ m_palcolorblendmap.insert(std::pair,pixel_t>(std::pair(palette[5],palette[6]),rgb_t(0x82, 0x80, 0xc5))); /* CYAN-MAGENTA */ m_palcolorblendmap.insert(std::pair,pixel_t>(std::pair(palette[6],palette[5]),rgb_t(0x89, 0x80, 0x9f))); /* MAGENTA-CYAN */ m_palcolorblendmap.insert(std::pair,pixel_t>(std::pair(palette[0],palette[5]),rgb_t(0x44, 0xb7, 0x1b))); /* GREEN-CYAN */ m_palcolorblendmap.insert(std::pair,pixel_t>(std::pair(palette[5],palette[0]),rgb_t(0x4a, 0xf2, 0x70))); /* CYAN-GREEN */ m_palcolorblendmap.insert(std::pair,pixel_t>(std::pair(palette[1],palette[4]),rgb_t(0xdc, 0xd2, 0x57))); /* YELLOW-BUFF */ m_palcolorblendmap.insert(std::pair,pixel_t>(std::pair(palette[4],palette[1]),rgb_t(0xd1, 0xf6, 0x95))); /* BUFF-YELLOW */ m_palcolorblendmap.insert(std::pair,pixel_t>(std::pair(palette[0],palette[6]),rgb_t(0xa6, 0x86, 0x10))); /* GREEN-MAGENTA */ m_palcolorblendmap.insert(std::pair,pixel_t>(std::pair(palette[6],palette[0]),rgb_t(0x6b, 0xbe, 0xb3))); /* MAGENTA-GREEN */ m_palcolorblendmap.insert(std::pair,pixel_t>(std::pair(palette[0],palette[7]),rgb_t(0x91, 0xc5, 0x3b))); /* GREEN-ORANGE */ m_palcolorblendmap.insert(std::pair,pixel_t>(std::pair(palette[7],palette[0]),rgb_t(0xad, 0xbc, 0x22))); /* ORANGE-GREEN */ } //************************************************************************** // VARIATIONS //************************************************************************** DEFINE_DEVICE_TYPE(MC6847, mc6847_device, "mc6847", "Motorola MC6847 VDG") DEFINE_DEVICE_TYPE(MC6847Y, mc6847y_device, "mc6847y", "Motorola MC6847Y VDG") DEFINE_DEVICE_TYPE(MC6847T1, mc6847t1_device, "mc6847t1", "Motorola MC6847T1 VDG") DEFINE_DEVICE_TYPE(S68047, s68047_device, "s68047", "AMI S68047 VDG") DEFINE_DEVICE_TYPE(M5C6847P1, m5c6847p1_device, "m5c6847p1", "Mitsubishi M5C6847P-1 VDG") //------------------------------------------------- // mc6847_device //------------------------------------------------- mc6847_device::mc6847_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, bool pal) : mc6847_base_device(mconfig, MC6847, tag, owner, clock, vdg_fontdata8x12, pal ? 312.0 : 262.0, pal) { m_artifacter.set_pal_artifacting(pal); } //------------------------------------------------- // mc6847y_device //------------------------------------------------- mc6847y_device::mc6847y_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, bool pal) : mc6847_base_device(mconfig, MC6847Y, tag, owner, clock, vdg_fontdata8x12, pal ? 312.0 : 262.5, pal) { m_artifacter.set_pal_artifacting(pal); } //------------------------------------------------- // mc6847t1_device //------------------------------------------------- mc6847t1_device::mc6847t1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, bool pal) : mc6847_base_device(mconfig, MC6847T1, tag, owner, clock, vdg_t1_fontdata8x12, pal ? 312.0 : 262.0, pal) { m_artifacter.set_pal_artifacting(pal); } uint8_t mc6847t1_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; } } //------------------------------------------------- // 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, bool pal) : mc6847_base_device(mconfig, M5C6847P1, tag, owner, clock, vdg_fontdata8x12, pal ? 312.0 : 262.5, pal) { m_artifacter.set_pal_artifacting(pal); }