// license:BSD-3-Clause // copyright-holders:Wilbert Pol /*************************************************************************** Color Graphics Adapter (CGA) section Notes on Port 3D8 (http://www.clipx.net/ng/interrupts_and_ports/ng2d045.php) Port 3D8 - Color/VGA Mode control register xx1x xxxx Attribute bit 7. 0=blink, 1=Intesity xxx1 xxxx 640x200 mode xxxx 1xxx Enable video signal xxxx x1xx Select B/W mode xxxx xx1x Select graphics xxxx xxx1 80x25 text The usage of the above control register for various modes is: xx10 1100 40x25 alpha B/W xx10 1000 40x25 alpha color xx10 1101 80x25 alpha B/W xx10 1001 80x25 alpha color xxx0 1110 320x200 graph B/W xxx0 1010 320x200 graph color xxx1 1110 640x200 graph B/W PC1512 display notes The PC1512 built-in display adaptor is an emulation of IBM's CGA. Unlike a real CGA, it is not built around a real MC6845 controller, and so attempts to get custom video modes out of it may not work as expected. Its 640x200 CGA mode can be set up to be a 16-color mode rather than mono. If you program it with BIOS calls, the PC1512 behaves just like a real CGA, except: - The 'greyscale' text modes (0 and 2) behave just like the 'color' ones (1 and 3). On a color monitor both are in color; on a mono monitor both are in greyscale. - Mode 5 (the 'greyscale' graphics mode) displays in color, using an alternative color palette: Cyan, Red and White. - The undocumented 160x100x16 "graphics" mode works correctly. (source John Elliott http://www.seasip.info/AmstradXT/pc1512disp.html) Cursor signal handling: The alpha dots signal is set when a character pixel should be set. This signal is also set when the cursor should be displayed. The following formula for alpha dots is derived from the schematics: ALPHA DOTS = ( ( CURSOR DLY ) AND ( CURSOR BLINK ) ) OR ( ( ( NOT AT7 ) OR CURSOR DLY OR -BLINK OR NOT ENABLE BLINK ) AND ( CHG DOTS ) ) -CURSOR BLINK = VSYNC DLY (LS393) (changes every 8 vsyncs) -BLINK = -CURSOR BLINK (LS393) (changes every 16 vsyncs) -CURSOR DLY = -CURSOR signal from mc6845 and LS174 CHG DOTS = character pixel (from character rom) For non-blinking modes this formula reduces to: ALPHA DOTS = ( ( CURSOR DLY ) AND ( CURSOR BLINK ) ) OR ( CHG DOTS ) This means the cursor switches on/off state every 8 vsyncs. For blinking modes this formula reduces to: ALPHA DOTS = ( ( CURSOR DLY ) AND ( CURSOR BLINK ) ) OR ( ( ( NOT AT7 ) OR CURSOR DLY OR -BLINK ) AND ( CHG DOTS ) ) So, at the cursor location the attribute blinking is ignored and only regular cursor blinking takes place (state switches every 8 vsyncs). On non-cursor locations with the highest attribute bits set the character will switch on/off every 16 vsyncs. In all other cases the character is displayed as usual. TODO: - Update more drivers in MESS and MAME and unify with src/emu/video/pc_cga.c - Separate out more cards/implementations ***************************************************************************/ #include "emu.h" #include "video/mc6845.h" #include "cga.h" #include "video/cgapal.h" #define VERBOSE_CGA 0 /* CGA (Color Graphics Adapter) */ #define CGA_SCREEN_NAME "screen" #define CGA_MC6845_NAME "mc6845_cga" #define CGA_LOG(N,M,A) \ do { \ if(VERBOSE_CGA>=N) \ { \ if( M ) \ logerror("%11.6f: %-24s",machine().time().as_double(),(char*)M ); \ logerror A; \ } \ } while (0) enum { CGA_TEXT_INTEN = 0, CGA_TEXT_INTEN_ALT, CGA_TEXT_INTEN_CG, CGA_TEXT_BLINK, CGA_TEXT_BLINK_ALT, CGA_TEXT_BLINK_SI, CGA_GFX_1BPP, CGA_GFX_2BPP, CGA_GFX_4BPPL, CGA_GFX_4BPPH, PC1512_GFX_4BPP }; /*************************************************************************** Static declarations ***************************************************************************/ static INPUT_PORTS_START( cga ) PORT_START( "cga_config" ) PORT_CONFNAME( 0x03, 0x00, "CGA character set") PORT_CONFSETTING(0x00, DEF_STR( Normal )) PORT_CONFSETTING(0x01, "Alternative") PORT_CONFNAME( 0x1C, 0x00, "CGA monitor type") PORT_CONFSETTING(0x00, "Colour RGB") PORT_CONFSETTING(0x04, "Mono RGB") PORT_CONFSETTING(0x08, "Colour composite") PORT_CONFSETTING(0x0C, "Television") PORT_CONFSETTING(0x10, "LCD") PORT_CONFNAME( 0xE0, 0x00, "CGA chipset") PORT_CONFSETTING(0x00, "IBM") PORT_CONFSETTING(0x20, "Amstrad PC1512") PORT_CONFSETTING(0x40, "Amstrad PPC512") PORT_CONFSETTING(0x60, "ATI") PORT_CONFSETTING(0x80, "Paradise") INPUT_PORTS_END static INPUT_PORTS_START( pc1512 ) PORT_START( "cga_config" ) PORT_CONFNAME( 0x03, 0x03, "CGA character set") PORT_CONFSETTING(0x00, "Greek") PORT_CONFSETTING(0x01, "Danish 2") PORT_CONFSETTING(0x02, "Danish 1") PORT_CONFSETTING(0x03, "Default") PORT_CONFNAME( 0x1C, 0x00, "CGA monitor type") PORT_CONFSETTING(0x00, "Colour RGB") PORT_CONFSETTING(0x04, "Mono RGB") PORT_BIT ( 0xE0, 0x20, IPT_UNUSED ) /* Chipset is always PC1512 */ INPUT_PORTS_END /* Dipswitch for font selection */ #define CGA_FONT (m_cga_config->read() & m_font_selection_mask) /* Dipswitch for monitor selection */ #define CGA_MONITOR (m_cga_config->read()&0x1C) #define CGA_MONITOR_RGB 0x00 /* Colour RGB */ #define CGA_MONITOR_MONO 0x04 /* Greyscale RGB */ #define CGA_MONITOR_COMPOSITE 0x08 /* Colour composite */ #define CGA_MONITOR_TELEVISION 0x0C /* Television */ #define CGA_MONITOR_LCD 0x10 /* LCD, eg PPC512 */ /* Dipswitch for chipset selection */ /* TODO: Get rid of this; these should be handled by separate classes */ #define CGA_CHIPSET (m_cga_config->read() & 0xE0) #define CGA_CHIPSET_IBM 0x00 /* Original IBM CGA */ #define CGA_CHIPSET_PC1512 0x20 /* PC1512 CGA subset */ #define CGA_CHIPSET_PC200 0x40 /* PC200 in CGA mode */ #define CGA_CHIPSET_ATI 0x60 /* ATI (supports Plantronics) */ #define CGA_CHIPSET_PARADISE 0x80 /* Paradise (used in PC1640) */ MC6845_UPDATE_ROW( isa8_cga_device::crtc_update_row ) { if (m_update_row_type == -1) return; y = m_y; if(m_y >= bitmap.height()) return; switch (m_update_row_type) { case CGA_TEXT_INTEN: cga_text(bitmap, cliprect, ma, ra, y, x_count, cursor_x, de, hbp, vbp); break; case CGA_TEXT_INTEN_ALT: cga_text(bitmap, cliprect, ma, ra, y, x_count, cursor_x, de, hbp, vbp); break; case CGA_TEXT_INTEN_CG: cga_text(bitmap, cliprect, ma, ra, y, x_count, cursor_x, de, hbp, vbp); break; case CGA_TEXT_BLINK: cga_text(bitmap, cliprect, ma, ra, y, x_count, cursor_x, de, hbp, vbp); break; case CGA_TEXT_BLINK_ALT: cga_text(bitmap, cliprect, ma, ra, y, x_count, cursor_x, de, hbp, vbp); break; case CGA_TEXT_BLINK_SI: cga_text(bitmap, cliprect, ma, ra, y, x_count, cursor_x, de, hbp, vbp); break; case CGA_GFX_1BPP: cga_gfx_1bpp_update_row(bitmap, cliprect, ma, ra, y, x_count, cursor_x, de, hbp, vbp); break; case CGA_GFX_2BPP: cga_gfx_2bpp_update_row(bitmap, cliprect, ma, ra, y, x_count, cursor_x, de, hbp, vbp); break; case CGA_GFX_4BPPL: cga_gfx_4bppl_update_row(bitmap, cliprect, ma, ra, y, x_count, cursor_x, de, hbp, vbp); break; case CGA_GFX_4BPPH: cga_gfx_4bpph_update_row(bitmap, cliprect, ma, ra, y, x_count, cursor_x, de, hbp, vbp); break; } } MC6845_UPDATE_ROW( isa8_cga_pc1512_device::crtc_update_row ) { if (m_update_row_type == -1) return; switch (m_update_row_type) { case PC1512_GFX_4BPP: pc1512_gfx_4bpp_update_row(bitmap, cliprect, ma, ra, y, x_count, cursor_x, de, hbp, vbp); break; default: isa8_cga_device::crtc_update_row(bitmap, cliprect, ma, ra, y, x_count, cursor_x, de, hbp, vbp); break; } } #define CGA_HCLK (XTAL(14'318'181)/8) #define CGA_LCLK (XTAL(14'318'181)/16) ROM_START( cga ) /* IBM 1501981(CGA) and 1501985(MDA) Character rom */ ROM_REGION(0x2000,"gfx1", 0) ROM_LOAD("5788005.u33", 0x00000, 0x2000, CRC(0bf56d70) SHA1(c2a8b10808bf51a3c123ba3eb1e9dd608231916f)) /* "AMI 8412PI // 5788005 // (C) IBM CORP. 1981 // KOREA" */ ROM_END //************************************************************************** // GLOBAL VARIABLES //************************************************************************** DEFINE_DEVICE_TYPE(ISA8_CGA, isa8_cga_device, "cga", "IBM Color/Graphics Monitor Adapter") //------------------------------------------------- // device_add_mconfig - add device configuration //------------------------------------------------- void isa8_cga_device::device_add_mconfig(machine_config &config) { screen_device &screen(SCREEN(config, CGA_SCREEN_NAME, SCREEN_TYPE_RASTER)); screen.set_raw(XTAL(14'318'181), 912, 0, 640, 262, 0, 200); screen.set_screen_update(FUNC(isa8_cga_device::screen_update)); PALETTE(config, m_palette).set_entries(/* CGA_PALETTE_SETS * 16*/ 65536); MC6845(config, m_crtc, XTAL(14'318'181)/16); m_crtc->set_screen(nullptr); m_crtc->set_show_border_area(false); m_crtc->set_char_width(8); m_crtc->set_update_row_callback(FUNC(isa8_cga_device::crtc_update_row), this); m_crtc->out_hsync_callback().set(FUNC(isa8_cga_device::hsync_changed)); m_crtc->out_vsync_callback().set(FUNC(isa8_cga_device::vsync_changed)); m_crtc->set_reconfigure_callback(FUNC(isa8_cga_device::reconfigure), this); } ioport_constructor isa8_cga_device::device_input_ports() const { return INPUT_PORTS_NAME( cga ); } //------------------------------------------------- // rom_region - device-specific ROM region //------------------------------------------------- const tiny_rom_entry *isa8_cga_device::device_rom_region() const { return ROM_NAME( cga ); } //------------------------------------------------- // isa8_cga_device - constructor //------------------------------------------------- isa8_cga_device::isa8_cga_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : isa8_cga_device(mconfig, ISA8_CGA, tag, owner, clock) { } isa8_cga_device::isa8_cga_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) : device_t(mconfig, type, tag, owner, clock), device_isa8_card_interface(mconfig, *this), m_crtc(*this, CGA_MC6845_NAME), m_cga_config(*this, "cga_config"), m_framecnt(0), m_mode_control(0), m_color_select(0), m_update_row_type(-1), m_y(0), m_chr_gen_base(nullptr), m_chr_gen(nullptr), m_vsync(0), m_hsync(0), m_vram_size( 0x4000 ), m_plantronics(0), m_palette(*this, "palette"), m_screen(*this, "screen") { m_chr_gen_offset[0] = m_chr_gen_offset[2] = 0x1800; m_chr_gen_offset[1] = m_chr_gen_offset[3] = 0x1000; m_font_selection_mask = 0x01; m_start_offset = 0; m_superimpose = false; } //------------------------------------------------- // device_start - device-specific startup //------------------------------------------------- void isa8_cga_device::device_start() { if (m_palette != nullptr && !m_palette->started()) throw device_missing_dependencies(); set_isa_device(); m_vram.resize(m_vram_size); m_isa->install_device(0x3d0, 0x3df, read8_delegate( FUNC(isa8_cga_device::io_read), this ), write8_delegate( FUNC(isa8_cga_device::io_write), this ) ); m_isa->install_bank(0xb8000, 0xb8000 + (std::min)(0x8000, m_vram_size) - 1, "bank_cga", &m_vram[0]); if(m_vram_size == 0x4000) m_isa->install_bank(0xbc000, 0xbffff, "bank_cga", &m_vram[0]); /* Initialise the cga palette */ int i; for ( i = 0; i < CGA_PALETTE_SETS * 16; i++ ) { m_palette->set_pen_color( i, cga_palette[i][0], cga_palette[i][1], cga_palette[i][2] ); } i = 0x8000; for ( int r = 0; r < 32; r++ ) { for ( int g = 0; g < 32; g++ ) { for ( int b = 0; b < 32; b++ ) { m_palette->set_pen_color( i, r << 3, g << 3, b << 3 ); i++; } } } m_chr_gen_base = memregion(subtag("gfx1").c_str())->base(); m_chr_gen = m_chr_gen_base + m_chr_gen_offset[1]; save_item(NAME(m_framecnt)); save_item(NAME(m_mode_control)); save_item(NAME(m_color_select)); //save_item(NAME(m_status)); uncomment when used save_item(NAME(m_update_row_type)); save_item(NAME(m_vsync)); save_item(NAME(m_hsync)); save_item(NAME(m_vram)); save_item(NAME(m_plantronics)); save_item(NAME(m_y)); } //------------------------------------------------- // device_reset - device-specific reset //------------------------------------------------- void isa8_cga_device::device_reset() { m_framecnt = 0; m_mode_control = 0; m_vsync = 0; m_hsync = 0; m_color_select = 0; m_y = 0; memset(m_palette_lut_2bpp, 0, sizeof(m_palette_lut_2bpp)); } /*************************************************************************** Methods ***************************************************************************/ uint32_t isa8_cga_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) { m_crtc->screen_update( screen, bitmap, cliprect); /* Check for changes in font dipsetting */ switch ( CGA_FONT ) { case 0: m_chr_gen = m_chr_gen_base + m_chr_gen_offset[0]; break; case 1: m_chr_gen = m_chr_gen_base + m_chr_gen_offset[1]; break; case 2: m_chr_gen = m_chr_gen_base + m_chr_gen_offset[2]; break; case 3: m_chr_gen = m_chr_gen_base + m_chr_gen_offset[3]; break; } return 0; } DEFINE_DEVICE_TYPE(ISA8_CGA_POISK2, isa8_cga_poisk2_device, "cga_poisk2", "ISA8_CGA_POISK2") //------------------------------------------------- // isa8_cga_poisk2_device - constructor //------------------------------------------------- isa8_cga_poisk2_device::isa8_cga_poisk2_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : isa8_cga_device(mconfig, ISA8_CGA_POISK2, tag, owner, clock) { m_chr_gen_offset[0] = 0x0000; m_chr_gen_offset[1] = 0x0800; } ROM_START( cga_poisk2 ) ROM_REGION(0x2000,"gfx1", 0) ROM_LOAD( "p2_ecga.rf4", 0x0000, 0x2000, CRC(d537f665) SHA1(d70f085b9b0cbd53df7c3122fbe7592998ba8fed)) ROM_END //------------------------------------------------- // rom_region - device-specific ROM region //------------------------------------------------- const tiny_rom_entry *isa8_cga_poisk2_device::device_rom_region() const { return ROM_NAME( cga_poisk2 ); } /* for superimposing CGA over a different source video (i.e. tetriskr) */ DEFINE_DEVICE_TYPE(ISA8_CGA_SUPERIMPOSE, isa8_cga_superimpose_device, "cga_superimpose", "ISA8_CGA_SUPERIMPOSE") //------------------------------------------------- // isa8_cga_superimpose_device - constructor //------------------------------------------------- isa8_cga_superimpose_device::isa8_cga_superimpose_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : isa8_cga_superimpose_device(mconfig, ISA8_CGA_SUPERIMPOSE, tag, owner, clock) { } isa8_cga_superimpose_device::isa8_cga_superimpose_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) : isa8_cga_device(mconfig, type, tag, owner, clock) { m_superimpose = true; } template MC6845_UPDATE_ROW( isa8_cga_device::cga_text ) { uint8_t *videoram = &m_vram[m_start_offset]; uint32_t *p = &bitmap.pix32(y); const rgb_t *palette = m_palette->palette()->entry_list_raw(); int i; if ( y == 0 ) CGA_LOG(1,"cga_text_8",("\n")); for ( i = 0; i < x_count; i++ ) { uint16_t offset = ( ( ma + i ) << 1 ) & 0x3fff; uint8_t chr = videoram[ offset ]; uint8_t attr = videoram[ offset +1 ]; uint8_t data = m_chr_gen[ chr * width + ra ]; uint16_t fg, bg; uint8_t xi; if ( comp ) { fg = 0x10 + ( attr & 0x0F ); bg = alt ? 0 : ( 0x10 + ( ( attr >> 4 ) & 0x07 ) ); } else { fg = attr & 0x0F; bg = alt ? 0 : ( ( attr >> 4 ) & ( blink ? 0x07 : 0x0f ) ); } if ( ( i == cursor_x ) && ( m_framecnt & 0x08 ) ) data = 0xFF; else if ( blink && ( attr & 0x80 ) && ( m_framecnt & 0x10 ) ) { data = 0x00; bg = ( attr >> 4 ) & 0x07; } for(xi=0;xi<8;xi++) { uint8_t pen_data, dot; dot = (data & (1 << (7-xi))); pen_data = dot ? fg : bg; if(!si || (pen_data || dot)) *p = palette[pen_data]; p++; } } } /* The lo-res (320x200) graphics mode on a colour composite monitor */ MC6845_UPDATE_ROW( isa8_cga_device::cga_gfx_4bppl_update_row ) { uint8_t *videoram = &m_vram[m_start_offset]; uint32_t *p = &bitmap.pix32(y); const rgb_t *palette = m_palette->palette()->entry_list_raw(); int i; if ( y == 0 ) CGA_LOG(1,"cga_gfx_4bppl_update_row",("\n")); for ( i = 0; i < x_count; i++ ) { uint16_t offset = ( ( ( ma + i ) << 1 ) & 0x1fff ) | ( ( y & 1 ) << 13 ); uint8_t data = videoram[ offset ]; *p = palette[data >> 4]; p++; *p = palette[data >> 4]; p++; *p = palette[data & 0x0F]; p++; *p = palette[data & 0x0F]; p++; data = videoram[ offset + 1 ]; *p = palette[data >> 4]; p++; *p = palette[data >> 4]; p++; *p = palette[data & 0x0F]; p++; *p = palette[data & 0x0F]; p++; } } #if 0 /* The hi-res graphics mode on a colour composite monitor * * The different scaling factors mean that the '160x200' versions of screens * are the same size as the normal colour ones. */ static const uint8_t yc_lut2[4] = { 0, 182, 71, 255 }; static const uint8_t yc_lut[16][8] = { { 0, 0, 0, 0, 0, 0, 0, 0 }, /* black */ { 0, 0, 0, 0, 1, 1, 1, 1 }, /* blue */ { 0, 1, 1, 1, 1, 0, 0, 0 }, /* green */ { 0, 0, 1, 1, 1, 1, 0, 0 }, /* cyan */ { 1, 1, 0, 0, 0, 0, 1, 1 }, /* red */ { 1, 0, 0, 0, 0, 1, 1, 1 }, /* magenta */ { 1, 1, 1, 1, 0, 0, 0, 0 }, /* yellow */ { 1, 1, 1, 1, 1, 1, 1, 1 }, /* white */ /* Intensity set */ { 2, 2, 2, 2, 2, 2, 2, 2 }, /* black */ { 2, 2, 2, 2, 3, 3, 3, 3 }, /* blue */ { 2, 3, 3, 3, 3, 2, 2, 2 }, /* green */ { 2, 2, 3, 3, 3, 3, 2, 2 }, /* cyan */ { 3, 3, 2, 2, 2, 2, 3, 3 }, /* red */ { 3, 2, 2, 2, 2, 3, 3, 3 }, /* magenta */ { 3, 3, 3, 3, 2, 2, 2, 2 }, /* yellow */ { 3, 3, 3, 3, 3, 3, 3, 3 }, /* white */ }; #endif MC6845_UPDATE_ROW( isa8_cga_device::cga_gfx_4bpph_update_row ) { uint8_t *videoram = &m_vram[m_start_offset]; uint32_t *p = &bitmap.pix32(y); const rgb_t *palette = m_palette->palette()->entry_list_raw(); int i; if ( y == 0 ) CGA_LOG(1,"cga_gfx_4bpph_update_row",("\n")); for ( i = 0; i < x_count; i++ ) { uint16_t offset = ( ( ( ma + i ) << 1 ) & 0x1fff ) | ( ( y & 1 ) << 13 ); uint8_t data = videoram[ offset ]; *p = palette[data >> 4]; p++; *p = palette[data >> 4]; p++; *p = palette[data >> 4]; p++; *p = palette[data >> 4]; p++; *p = palette[data & 0x0F]; p++; *p = palette[data & 0x0F]; p++; *p = palette[data & 0x0F]; p++; *p = palette[data & 0x0F]; p++; data = videoram[ offset + 1 ]; *p = palette[data >> 4]; p++; *p = palette[data >> 4]; p++; *p = palette[data >> 4]; p++; *p = palette[data >> 4]; p++; *p = palette[data & 0x0F]; p++; *p = palette[data & 0x0F]; p++; *p = palette[data & 0x0F]; p++; *p = palette[data & 0x0F]; p++; } } /*************************************************************************** Draw graphics mode with 320x200 pixels (default) with 2 bits/pixel. Even scanlines are from CGA_base + 0x0000, odd from CGA_base + 0x2000 cga fetches 2 byte per mc6845 access. ***************************************************************************/ MC6845_UPDATE_ROW( isa8_cga_device::cga_gfx_2bpp_update_row ) { uint8_t *videoram = &m_vram[m_start_offset]; uint32_t *p = &bitmap.pix32(y); const rgb_t *palette = m_palette->palette()->entry_list_raw(); int i; if ( y == 0 ) CGA_LOG(1,"cga_gfx_2bpp_update_row",("\n")); for ( i = 0; i < x_count; i++ ) { uint16_t offset = ( ( ( ma + i ) << 1 ) & 0x1fff ) | ( ( ra & 1 ) << 13 ); uint8_t data = videoram[ offset ]; *p = palette[m_palette_lut_2bpp[ ( data >> 6 ) & 0x03 ]]; p++; *p = palette[m_palette_lut_2bpp[ ( data >> 4 ) & 0x03 ]]; p++; *p = palette[m_palette_lut_2bpp[ ( data >> 2 ) & 0x03 ]]; p++; *p = palette[m_palette_lut_2bpp[ data & 0x03 ]]; p++; data = videoram[ offset+1 ]; *p = palette[m_palette_lut_2bpp[ ( data >> 6 ) & 0x03 ]]; p++; *p = palette[m_palette_lut_2bpp[ ( data >> 4 ) & 0x03 ]]; p++; *p = palette[m_palette_lut_2bpp[ ( data >> 2 ) & 0x03 ]]; p++; *p = palette[m_palette_lut_2bpp[ data & 0x03 ]]; p++; } } /*************************************************************************** Draw graphics mode with 640x200 pixels (default). The cell size is 1x1 (1 scanline is the real default) Even scanlines are from CGA_base + 0x0000, odd from CGA_base + 0x2000 ***************************************************************************/ MC6845_UPDATE_ROW( isa8_cga_device::cga_gfx_1bpp_update_row ) { uint8_t *videoram = &m_vram[m_start_offset]; uint32_t *p = &bitmap.pix32(y); const rgb_t *palette = m_palette->palette()->entry_list_raw(); uint8_t fg = m_color_select & 0x0F; int i; if ( y == 0 ) CGA_LOG(1,"cga_gfx_1bpp_update_row",("\n")); for ( i = 0; i < x_count; i++ ) { uint16_t offset = ( ( ( ma + i ) << 1 ) & 0x1fff ) | ( ( ra & 1 ) << 13 ); uint8_t data = videoram[ offset ]; *p = palette[( data & 0x80 ) ? fg : 0]; p++; *p = palette[( data & 0x40 ) ? fg : 0]; p++; *p = palette[( data & 0x20 ) ? fg : 0]; p++; *p = palette[( data & 0x10 ) ? fg : 0]; p++; *p = palette[( data & 0x08 ) ? fg : 0]; p++; *p = palette[( data & 0x04 ) ? fg : 0]; p++; *p = palette[( data & 0x02 ) ? fg : 0]; p++; *p = palette[( data & 0x01 ) ? fg : 0]; p++; data = videoram[ offset + 1 ]; *p = palette[( data & 0x80 ) ? fg : 0]; p++; *p = palette[( data & 0x40 ) ? fg : 0]; p++; *p = palette[( data & 0x20 ) ? fg : 0]; p++; *p = palette[( data & 0x10 ) ? fg : 0]; p++; *p = palette[( data & 0x08 ) ? fg : 0]; p++; *p = palette[( data & 0x04 ) ? fg : 0]; p++; *p = palette[( data & 0x02 ) ? fg : 0]; p++; *p = palette[( data & 0x01 ) ? fg : 0]; p++; } } WRITE_LINE_MEMBER( isa8_cga_device::hsync_changed ) { m_hsync = state ? 1 : 0; if(state && !m_vsync) { m_screen->update_now(); m_y++; } } WRITE_LINE_MEMBER( isa8_cga_device::vsync_changed ) { if ( state ) { m_framecnt++; } else { m_screen->reset_origin(); m_y = 0; } m_vsync = state ? 9 : 0; } MC6845_RECONFIGURE( isa8_cga_device::reconfigure ) { rectangle curvisarea = m_screen->visible_area(); m_screen->set_visible_area(visarea.min_x, visarea.max_x, curvisarea.min_y, curvisarea.max_y); } void isa8_cga_device::set_palette_luts(void) { /* Setup 2bpp palette lookup table */ if ( m_mode_control & 0x10 ) { m_palette_lut_2bpp[0] = 0; } else { m_palette_lut_2bpp[0] = m_color_select & 0x0F; } if ( m_mode_control & 0x04 ) { m_palette_lut_2bpp[1] = ( ( m_color_select & 0x10 ) >> 1 ) | 3; m_palette_lut_2bpp[2] = ( ( m_color_select & 0x10 ) >> 1 ) | 4; m_palette_lut_2bpp[3] = ( ( m_color_select & 0x10 ) >> 1 ) | 7; } else { if ( m_color_select & 0x20 ) { m_palette_lut_2bpp[1] = ( ( m_color_select & 0x10 ) >> 1 ) | 3; m_palette_lut_2bpp[2] = ( ( m_color_select & 0x10 ) >> 1 ) | 5; m_palette_lut_2bpp[3] = ( ( m_color_select & 0x10 ) >> 1 ) | 7; } else { m_palette_lut_2bpp[1] = ( ( m_color_select & 0x10 ) >> 1 ) | 2; m_palette_lut_2bpp[2] = ( ( m_color_select & 0x10 ) >> 1 ) | 4; m_palette_lut_2bpp[3] = ( ( m_color_select & 0x10 ) >> 1 ) | 6; } } //logerror("2bpp lut set to %d,%d,%d,%d\n", cga.palette_lut_2bpp[0], cga.palette_lut_2bpp[1], cga.palette_lut_2bpp[2], cga.palette_lut_2bpp[3]); } /* * rW CGA mode control register (see #P138) * * x x x 0 1 0 0 0 - 320x200, 40x25 text. Colour on RGB and composite monitors. * x x x 0 1 0 0 1 - 640x200, 80x25 text. Colour on RGB and composite monitors. * x x x 0 1 0 1 0 - 320x200 graphics. Colour on RGB and composite monitors. * x x x 0 1 0 1 1 - unknown/invalid. * x x x 0 1 1 0 0 - 320x200, 40x25 text. Colour on RGB, greyscale on composite monitors. * x x x 0 1 1 0 1 - 640x200, 80x25 text. Colour on RGB, greyscale on composite monitors. * x x x 0 1 1 1 0 - 320x200 graphics. Alternative palette on RGB, greyscale on composite monitors. * x x x 0 1 1 1 1 - unknown/invalid. * x x x 1 1 0 0 0 - unknown/invalid. * x x x 1 1 0 0 1 - unknown/invalid. * x x x 1 1 0 1 0 - 160x200/640x200 graphics. 640x200 ?? on RGB monitor, 160x200 on composite monitor. * x x x 1 1 0 1 1 - unknown/invalid. * x x x 1 1 1 0 0 - unknown/invalid. * x x x 1 1 1 0 1 - unknown/invalid. * x x x 1 1 1 1 0 - 640x200 graphics. Colour on black on RGB monitor, monochrome on composite monitor. * x x x 1 1 1 1 1 - unknown/invalid. */ void isa8_cga_device::mode_control_w(uint8_t data) { uint8_t monitor = CGA_MONITOR; m_mode_control = data; //logerror("mode set to %02X\n", cga.mode_control & 0x3F ); switch ( m_mode_control & 0x3F ) { case 0x08: case 0x09: case 0x0C: case 0x0D: m_crtc->set_hpixels_per_column( 8 ); if ( monitor == CGA_MONITOR_COMPOSITE ) { if ( m_mode_control & 0x04 ) { /* Composite greyscale */ m_update_row_type = CGA_TEXT_INTEN_CG; } else { /* Composite colour */ m_update_row_type = CGA_TEXT_INTEN; } } else { /* RGB colour */ m_update_row_type = CGA_TEXT_INTEN; } break; case 0x0A: case 0x0B: case 0x2A: case 0x2B: m_crtc->set_hpixels_per_column( 8 ); if ( monitor == CGA_MONITOR_COMPOSITE ) { m_update_row_type = CGA_GFX_4BPPL; } else { m_update_row_type = CGA_GFX_2BPP; } break; case 0x0E: case 0x0F: case 0x2E: case 0x2F: m_crtc->set_hpixels_per_column( 8 ); m_update_row_type = CGA_GFX_2BPP; break; case 0x18: case 0x19: case 0x1C: case 0x1D: m_crtc->set_hpixels_per_column( 8 ); m_update_row_type = CGA_TEXT_INTEN_ALT; break; case 0x1A: case 0x1B: case 0x3A: case 0x3B: m_crtc->set_hpixels_per_column( 16 ); if ( monitor == CGA_MONITOR_COMPOSITE ) { m_update_row_type = CGA_GFX_4BPPH; } else { m_update_row_type = CGA_GFX_1BPP; } break; case 0x1E: case 0x1F: case 0x3E: case 0x3F: m_crtc->set_hpixels_per_column( 16 ); m_update_row_type = CGA_GFX_1BPP; break; case 0x28: case 0x29: case 0x2C: case 0x2D: m_crtc->set_hpixels_per_column( 8 ); if ( monitor == CGA_MONITOR_COMPOSITE ) { if ( m_mode_control & 0x04 ) { /* Composite greyscale */ m_update_row_type = m_superimpose ? CGA_TEXT_BLINK_SI : CGA_TEXT_BLINK; } else { /* Composite colour */ m_update_row_type = m_superimpose ? CGA_TEXT_BLINK_SI : CGA_TEXT_BLINK; } } else { /* RGB colour */ m_update_row_type = m_superimpose ? CGA_TEXT_BLINK_SI : CGA_TEXT_BLINK; } break; case 0x38: case 0x39: case 0x3C: case 0x3D: m_crtc->set_hpixels_per_column( 8 ); m_update_row_type = CGA_TEXT_BLINK_ALT; break; default: m_update_row_type = -1; break; } // The lowest bit of the mode register selects, among others, the // input clock to the 6845. m_crtc->set_unscaled_clock( ( m_mode_control & 1 ) ? CGA_HCLK : CGA_LCLK ); set_palette_luts(); } /* * Select Plantronics modes */ void isa8_cga_device::plantronics_w(uint8_t data) { if ( ( CGA_CHIPSET ) != CGA_CHIPSET_ATI) return; data &= 0x70; /* Only bits 6-4 are used */ m_plantronics = data; } /************************************************************************* * * CGA * color graphics adapter * *************************************************************************/ READ8_MEMBER( isa8_cga_device::io_read ) { uint8_t data = 0xff; switch( offset ) { case 0: case 2: case 4: case 6: /* return last written mc6845 address value here? */ break; case 1: case 3: case 5: case 7: data = m_crtc->register_r(); break; case 10: data = m_vsync | ( ( data & 0x40 ) >> 4 ) | m_hsync; break; } return data; } WRITE8_MEMBER( isa8_cga_device::io_write ) { switch(offset) { case 0: case 2: case 4: case 6: m_crtc->address_w(data); break; case 1: case 3: case 5: case 7: m_crtc->register_w(data); break; case 8: mode_control_w(data); break; case 9: m_color_select = data; set_palette_luts(); break; case 0x0d: plantronics_w(data); break; } } /* Old plantronics rendering code, leaving it uncommented until we have re-implemented it */ // // From choosevideomode: // // /* Plantronics high-res */ // if ((cga.mode_control & 2) && (cga.plantronics & 0x20)) // proc = cga_pgfx_2bpp; // /* Plantronics low-res */ // if ((cga.mode_control & 2) && (cga.plantronics & 0x10)) // proc = cga_pgfx_4bpp; // //static inline void pgfx_plot_unit_4bpp(bitmap_ind16 &bitmap, // int x, int y, int offs) //{ // int color, values[2]; // int i; // // if (cga.plantronics & 0x40) // { // values[0] = videoram[offs | 0x4000]; // values[1] = videoram[offs]; // } // else // { // values[0] = videoram[offs]; // values[1] = videoram[offs | 0x4000]; // } // for (i=3; i>=0; i--) // { // color = ((values[0] & 0x3) << 1) | // ((values[1] & 2) >> 1) | // ((values[1] & 1) << 3); // bitmap.pix16(y, x+i) = Machine->pens[color]; // values[0]>>=2; // values[1]>>=2; // } //} // // // ///*************************************************************************** // Draw graphics mode with 640x200 pixels (default) with 2 bits/pixel. // Even scanlines are from CGA_base + 0x0000, odd from CGA_base + 0x2000 // Second plane at CGA_base + 0x4000 / 0x6000 //***************************************************************************/ // //static void cga_pgfx_4bpp(bitmap_ind16 &bitmap, struct mscrtc6845 *crtc) //{ // int i, sx, sy, sh; // int offs = mscrtc6845_get_start(crtc)*2; // int lines = mscrtc6845_get_char_lines(crtc); // int height = mscrtc6845_get_char_height(crtc); // int columns = mscrtc6845_get_char_columns(crtc)*2; // // for (sy=0; sy=0; i--) // { // bmap[0] = bmap[0] << 1; if (values[0] & 0x80) bmap[0] |= 1; // bmap[0] = bmap[0] << 1; if (values[1] & 0x80) bmap[0] |= 1; // bmap[1] = bmap[1] << 1; if (values[0] & 0x08) bmap[1] |= 1; // bmap[1] = bmap[1] << 1; if (values[1] & 0x08) bmap[1] |= 1; // values[0] = values[0] << 1; // values[1] = values[1] << 1; // } // // dest = &bitmap.pix16(y, x); // *(dest++) = palette[(bmap[0] >> 6) & 0x03]; // *(dest++) = palette[(bmap[0] >> 4) & 0x03]; // *(dest++) = palette[(bmap[0] >> 2) & 0x03]; // *(dest++) = palette[(bmap[0] >> 0) & 0x03]; // *(dest++) = palette[(bmap[1] >> 6) & 0x03]; // *(dest++) = palette[(bmap[1] >> 4) & 0x03]; // *(dest++) = palette[(bmap[1] >> 2) & 0x03]; // *(dest++) = palette[(bmap[1] >> 0) & 0x03]; //} // // // ///*************************************************************************** // Draw graphics mode with 320x200 pixels (default) with 2 bits/pixel. // Even scanlines are from CGA_base + 0x0000, odd from CGA_base + 0x2000 // cga fetches 2 byte per mscrtc6845 access (not modeled here)! //***************************************************************************/ // //static void cga_pgfx_2bpp(bitmap_ind16 &bitmap, struct mscrtc6845 *crtc) //{ // int i, sx, sy, sh; // int offs = mscrtc6845_get_start(crtc)*2; // int lines = mscrtc6845_get_char_lines(crtc); // int height = mscrtc6845_get_char_height(crtc); // int columns = mscrtc6845_get_char_columns(crtc)*2; // int colorset = cga.color_select & 0x3F; // const uint16_t *palette; // // /* Most chipsets use bit 2 of the mode control register to // * access a third palette. But not consistently. */ // pc_cga_check_palette(); // switch(CGA_CHIPSET) // { // /* The IBM Professional Graphics Controller behaves like // * the PC1512, btw. */ // case CGA_CHIPSET_PC1512: // if ((colorset < 32) && (cga.mode_control & 4)) colorset += 64; // break; // // case CGA_CHIPSET_IBM: // case CGA_CHIPSET_PC200: // case CGA_CHIPSET_ATI: // case CGA_CHIPSET_PARADISE: // if (cga.mode_control & 4) colorset = (colorset & 0x1F) + 64; // break; // } // // // /* The fact that our palette is located in cga_colortable is a vestigial // * aspect from when we were doing that ugly trick where drawgfx() would // * handle graphics drawing. Truthfully, we should probably be using // * palette_set_color_rgb() here and not doing the palette lookup in the loop // */ // palette = &cga_colortable[256*2 + 16*2] + colorset * 4; // // for (sy=0; sypalette()->entry_list_raw(); uint16_t offset_base = ra << 13; int j; if ( y == 0 ) CGA_LOG(1,"pc1512_gfx_4bpp_update_row",("\n")); for ( j = 0; j < x_count; j++ ) { uint16_t offset = offset_base | ( ( ma + j ) & 0x1FFF ); uint16_t i = ( m_color_select & 8 ) ? videoram[ isa8_cga_pc1512_device::vram_offset[3] | offset ] << 3 : 0; uint16_t r = ( m_color_select & 4 ) ? videoram[ isa8_cga_pc1512_device::vram_offset[2] | offset ] << 2 : 0; uint16_t g = ( m_color_select & 2 ) ? videoram[ isa8_cga_pc1512_device::vram_offset[1] | offset ] << 1 : 0; uint16_t b = ( m_color_select & 1 ) ? videoram[ isa8_cga_pc1512_device::vram_offset[0] | offset ] : 0; *p = palette[( ( i & 0x400 ) | ( r & 0x200 ) | ( g & 0x100 ) | ( b & 0x80 ) ) >> 7]; p++; *p = palette[( ( i & 0x200 ) | ( r & 0x100 ) | ( g & 0x080 ) | ( b & 0x40 ) ) >> 6]; p++; *p = palette[( ( i & 0x100 ) | ( r & 0x080 ) | ( g & 0x040 ) | ( b & 0x20 ) ) >> 5]; p++; *p = palette[( ( i & 0x080 ) | ( r & 0x040 ) | ( g & 0x020 ) | ( b & 0x10 ) ) >> 4]; p++; *p = palette[( ( i & 0x040 ) | ( r & 0x020 ) | ( g & 0x010 ) | ( b & 0x08 ) ) >> 3]; p++; *p = palette[( ( i & 0x020 ) | ( r & 0x010 ) | ( g & 0x008 ) | ( b & 0x04 ) ) >> 2]; p++; *p = palette[( ( i & 0x010 ) | ( r & 0x008 ) | ( g & 0x004 ) | ( b & 0x02 ) ) >> 1]; p++; *p = palette[ ( i & 0x008 ) | ( r & 0x004 ) | ( g & 0x002 ) | ( b & 0x01 ) ]; p++; } } WRITE8_MEMBER( isa8_cga_pc1512_device::io_write ) { switch (offset) { case 0: case 2: case 4: case 6: data &= 0x1F; m_crtc->address_w(data); m_mc6845_address = data; break; case 1: case 3: case 5: case 7: if ( ! m_mc6845_locked_register[m_mc6845_address] ) { m_crtc->register_w(data); if ( isa8_cga_pc1512_device::mc6845_writeonce_register[m_mc6845_address] ) { m_mc6845_locked_register[m_mc6845_address] = 1; } } break; case 0x8: /* Check if we're changing to graphics mode 2 */ if ( ( m_mode_control & 0x12 ) != 0x12 && ( data & 0x12 ) == 0x12 ) { m_write = 0x0F; } else { membank("bank1")->set_base(&m_vram[isa8_cga_pc1512_device::vram_offset[0]]); } m_mode_control = data; switch( m_mode_control & 0x3F ) { case 0x08: case 0x09: case 0x0C: case 0x0D: m_crtc->set_hpixels_per_column( 8 ); m_update_row_type = CGA_TEXT_INTEN; break; case 0x0A: case 0x0B: case 0x2A: case 0x2B: m_crtc->set_hpixels_per_column( 8 ); if ( ( CGA_MONITOR ) == CGA_MONITOR_COMPOSITE ) { m_update_row_type = CGA_GFX_4BPPL; } else { m_update_row_type = CGA_GFX_2BPP; } break; case 0x0E: case 0x0F: case 0x2E: case 0x2F: m_crtc->set_hpixels_per_column( 8 ); m_update_row_type = CGA_GFX_2BPP; break; case 0x18: case 0x19: case 0x1C: case 0x1D: m_crtc->set_hpixels_per_column( 8 ); m_update_row_type = CGA_TEXT_INTEN_ALT; break; case 0x1A: case 0x1B: case 0x3A: case 0x3B: m_crtc->set_hpixels_per_column( 8 ); m_update_row_type = PC1512_GFX_4BPP; break; case 0x1E: case 0x1F: case 0x3E: case 0x3F: m_crtc->set_hpixels_per_column( 16 ); m_update_row_type = CGA_GFX_1BPP; break; case 0x28: case 0x29: case 0x2C: case 0x2D: m_crtc->set_hpixels_per_column( 8 ); m_update_row_type = CGA_TEXT_BLINK; break; case 0x38: case 0x39: case 0x3C: case 0x3D: m_crtc->set_hpixels_per_column( 8 ); m_update_row_type = CGA_TEXT_BLINK_ALT; break; default: m_update_row_type = -1; break; } break; case 0xd: m_write = data; break; case 0xe: m_read = data; if ( ( m_mode_control & 0x12 ) == 0x12 ) { membank("bank1")->set_base(&m_vram[isa8_cga_pc1512_device::vram_offset[data & 3]]); } break; default: isa8_cga_device::io_write(space, offset,data); break; } } READ8_MEMBER( isa8_cga_pc1512_device::io_read ) { uint8_t data; switch (offset) { case 0xd: data = m_write; break; case 0xe: data = m_read; break; default: data = isa8_cga_device::io_read(space, offset); break; } return data; } WRITE8_MEMBER( isa8_cga_pc1512_device::vram_w ) { if ( ( m_mode_control & 0x12 ) == 0x12 ) { if (m_write & 1) m_vram[offset+isa8_cga_pc1512_device::vram_offset[0]] = data; /* blue plane */ if (m_write & 2) m_vram[offset+isa8_cga_pc1512_device::vram_offset[1]] = data; /* green */ if (m_write & 4) m_vram[offset+isa8_cga_pc1512_device::vram_offset[2]] = data; /* red */ if (m_write & 8) m_vram[offset+isa8_cga_pc1512_device::vram_offset[3]] = data; /* intensity (text, 4color) */ } else { m_vram[offset + isa8_cga_pc1512_device::vram_offset[0]] = data; } } DEFINE_DEVICE_TYPE(ISA8_CGA_PC1512, isa8_cga_pc1512_device, "cga_pc1512", "ISA8_CGA_PC1512") const offs_t isa8_cga_pc1512_device::vram_offset[4]= { 0x0000, 0x4000, 0x8000, 0xC000 }; const uint8_t isa8_cga_pc1512_device::mc6845_writeonce_register[31] = { 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; //------------------------------------------------- // isa8_cga_pc1512_device - constructor //------------------------------------------------- isa8_cga_pc1512_device::isa8_cga_pc1512_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : isa8_cga_device(mconfig, ISA8_CGA_PC1512, tag, owner, clock), m_write(0), m_read(0), m_mc6845_address(0) { m_vram_size = 0x10000; m_chr_gen_offset[0] = 0x0000; m_chr_gen_offset[1] = 0x0800; m_chr_gen_offset[2] = 0x1000; m_chr_gen_offset[3] = 0x1800; } const tiny_rom_entry *isa8_cga_pc1512_device::device_rom_region() const { return nullptr; } ioport_constructor isa8_cga_pc1512_device::device_input_ports() const { return INPUT_PORTS_NAME( pc1512 ); } //------------------------------------------------- // device_start - device-specific startup //------------------------------------------------- void isa8_cga_pc1512_device::device_start() { isa8_cga_device::device_start(); m_isa->install_device(0x3d0, 0x3df, read8_delegate( FUNC(isa8_cga_pc1512_device::io_read), this ), write8_delegate( FUNC(isa8_cga_pc1512_device::io_write), this ) ); m_isa->install_bank(0xb8000, 0xbbfff, "bank1", &m_vram[0]); address_space &space = m_isa->memspace(); space.install_write_handler( 0xb8000, 0xbbfff, write8_delegate( FUNC(isa8_cga_pc1512_device::vram_w), this ) ); space.install_write_handler( 0xbc000, 0xbffff, write8_delegate( FUNC(isa8_cga_pc1512_device::vram_w), this ) ); } void isa8_cga_pc1512_device::device_reset() { isa8_cga_device::device_reset(); m_write = 0x0f; m_read = 0; m_mc6845_address = 0; for (auto & elem : m_mc6845_locked_register) { elem = 0; } membank("bank1")->set_base(&m_vram[isa8_cga_pc1512_device::vram_offset[0]]); } void isa8_wyse700_device::change_resolution(uint8_t mode) { int width = 0, height = 0; if (mode & 2) { machine().root_device().membank("bank_wy1")->set_base(&m_vram[0x10000]); } else { machine().root_device().membank("bank_wy1")->set_base(&m_vram[0x00000]); } if ((m_control & 0xf0) == (mode & 0xf0)) return; switch(mode & 0xf0) { case 0xc0: width = 1280; height = 800; break; case 0xa0: width = 1280; height = 400; break; case 0x80: width = 640; height = 400; break; case 0x00: width = 640; height = 400; break; // unhandled } rectangle visarea(0, width-1, 0, height-1); m_screen->configure(width, height, visarea, HZ_TO_ATTOSECONDS(60)); } WRITE8_MEMBER( isa8_wyse700_device::io_write ) { switch (offset) { case 0xd: m_bank_offset = data; break; case 0xe: m_bank_base = data; break; case 0xf: change_resolution(data); m_control = data; break; default: isa8_cga_device::io_write(space, offset,data); break; } } READ8_MEMBER( isa8_wyse700_device::io_read ) { uint8_t data; switch (offset) { case 0xd: data = m_bank_offset; break; case 0xe: data = m_bank_base; break; case 0xf: data = m_control; break; default: data = isa8_cga_device::io_read(space, offset); break; } return data; } DEFINE_DEVICE_TYPE(ISA8_WYSE700, isa8_wyse700_device, "wyse700", "Wyse 700") //------------------------------------------------- // isa8_wyse700_device - constructor //------------------------------------------------- isa8_wyse700_device::isa8_wyse700_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : isa8_cga_device(mconfig, ISA8_WYSE700, tag, owner, clock), m_bank_offset(0), m_bank_base(0), m_control(0) { m_vram_size = 0x20000; m_start_offset = 0x18000; } /* Character ROMs: 250211-03.e5: Character ROM Label: "(C) WYSE TECH / REV.A / 250211-03" 250212-03.f5: Character ROM Label: "(C) WYSE TECH / REV.A / 250212-03" Not dumped: 250026-03.2d: MC68705 MCU Label: "(C) WYSE TECH / REV.1 / 250026-03" 250270-01.8b: PAL? Label: "250270-01" 250024-01.8g: PAL? Label: "250024-01" 250210-01.c2: PAL? Label: "250210-01" */ ROM_START( wyse700 ) ROM_REGION(0x4000,"gfx1", 0) ROM_LOAD( "250211-03.e5", 0x0000, 0x2000, CRC(58b61f63) SHA1(29ecb7cf7d07d692f0fc54e2dea8389f17a65f1a)) ROM_LOAD( "250212-03.f5", 0x2000, 0x2000, CRC(6930d741) SHA1(1beeb133c5e39eee9914bdc5924039d70b5edcad)) ROM_END const tiny_rom_entry *isa8_wyse700_device::device_rom_region() const { return ROM_NAME( wyse700 ); } //------------------------------------------------- // device_start - device-specific startup //------------------------------------------------- void isa8_wyse700_device::device_start() { isa8_cga_device::device_start(); m_isa->install_device(0x3d0, 0x3df, read8_delegate( FUNC(isa8_wyse700_device::io_read), this ), write8_delegate( FUNC(isa8_wyse700_device::io_write), this ) ); m_isa->install_bank(0xa0000, 0xaffff, "bank_wy1", &m_vram[0x00000]); m_isa->install_bank(0xb0000, 0xbffff, "bank_cga", &m_vram[0x10000]); } void isa8_wyse700_device::device_reset() { isa8_cga_device::device_reset(); m_control = 0; m_bank_offset = 0; m_bank_base = 0; } uint32_t isa8_wyse700_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) { if (m_control & 0x08) { const rgb_t *palette = m_palette->palette()->entry_list_raw(); uint8_t fg = m_color_select & 0x0F; uint32_t addr = 0; for (int y = 0; y < 800; y++) { uint8_t *src = &m_vram[addr]; if (y & 1) { src += 0x10000; addr += 160; } for (int x = 0; x < (1280 / 8); x++) { uint8_t val = src[x]; for (int i = 0; i < 8; i++) { bitmap.pix32(y,x*8+i) = (val & 0x80) ? palette[fg] : palette[0x00]; val <<= 1; } } } } else { return isa8_cga_device::screen_update(screen, bitmap, cliprect); } return 0; } DEFINE_DEVICE_TYPE(ISA8_EC1841_0002, isa8_ec1841_0002_device, "ec1841_0002", "EC 1841.0002 (CGA)") //------------------------------------------------- // isa8_ec1841_0002_device - constructor //------------------------------------------------- isa8_ec1841_0002_device::isa8_ec1841_0002_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : isa8_cga_device(mconfig, ISA8_EC1841_0002, tag, owner, clock), m_p3df(0) { } //------------------------------------------------- // device_start - device-specific startup //------------------------------------------------- void isa8_ec1841_0002_device::device_start() { isa8_cga_device::device_start(); m_isa->install_device(0x3d0, 0x3df, read8_delegate( FUNC(isa8_ec1841_0002_device::io_read), this ), write8_delegate( FUNC(isa8_ec1841_0002_device::io_write), this ) ); } void isa8_ec1841_0002_device::device_reset() { isa8_cga_device::device_reset(); m_p3df = 0; } WRITE8_MEMBER( isa8_ec1841_0002_device::char_ram_write ) { offset ^= BIT(offset, 12); // logerror("write char ram %04x %02x\n",offset,data); m_chr_gen_base[offset + 0x0000] = data; m_chr_gen_base[offset + 0x0800] = data; m_chr_gen_base[offset + 0x1000] = data; m_chr_gen_base[offset + 0x1800] = data; } READ8_MEMBER( isa8_ec1841_0002_device::char_ram_read ) { offset ^= BIT(offset, 12); return m_chr_gen_base[offset]; } WRITE8_MEMBER( isa8_ec1841_0002_device::io_write ) { switch (offset) { case 0x0f: m_p3df = data; if (data & 1) { m_isa->install_memory(0xb8000, 0xb9fff, read8_delegate( FUNC(isa8_ec1841_0002_device::char_ram_read), this), write8_delegate(FUNC(isa8_ec1841_0002_device::char_ram_write), this) ); if(m_vram_size == 0x4000) m_isa->install_memory(0xbc000, 0xbdfff, read8_delegate( FUNC(isa8_ec1841_0002_device::char_ram_read), this), write8_delegate(FUNC(isa8_ec1841_0002_device::char_ram_write), this) ); } else { m_isa->install_bank(0xb8000, 0xb8000 + (std::min)(0x8000, m_vram_size) - 1, "bank_cga", &m_vram[0]); if(m_vram_size == 0x4000) m_isa->install_bank(0xbc000, 0xbffff, "bank_cga", &m_vram[0]); } break; default: isa8_cga_device::io_write(space, offset, data); break; } } READ8_MEMBER( isa8_ec1841_0002_device::io_read ) { uint8_t data; switch (offset) { case 0x0f: data = m_p3df; break; default: data = isa8_cga_device::io_read(space, offset); break; } return data; } DEFINE_DEVICE_TYPE(ISA8_CGA_MC1502, isa8_cga_mc1502_device, "cga_mc1502", "MC1502 CGA") //------------------------------------------------- // isa8_cga_mc1502_device - constructor //------------------------------------------------- isa8_cga_mc1502_device::isa8_cga_mc1502_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : isa8_cga_device(mconfig, ISA8_CGA_MC1502, tag, owner, clock) { m_vram_size = 0x8000; m_chr_gen_offset[0] = 0x0000; m_chr_gen_offset[1] = 0x0800; } ROM_START( cga_iskr1031 ) ROM_REGION(0x2000,"gfx1", 0) ROM_LOAD( "iskra-1031_font.bin", 0x0000, 0x2000, CRC(f4d62e80) SHA1(ad7e81a0c9abc224671422bbcf6f6262da92b510)) ROM_END //------------------------------------------------- // rom_region - device-specific ROM region //------------------------------------------------- const tiny_rom_entry *isa8_cga_iskr1031_device::device_rom_region() const { return ROM_NAME( cga_iskr1031 ); } DEFINE_DEVICE_TYPE(ISA8_CGA_ISKR1031, isa8_cga_iskr1031_device, "cga_iskr1031", "Iskra-1031 CGA") //------------------------------------------------- // isa8_cga_iskr1031_device - constructor //------------------------------------------------- isa8_cga_iskr1031_device::isa8_cga_iskr1031_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : isa8_cga_device(mconfig, ISA8_CGA_ISKR1031, tag, owner, clock) { } ROM_START( cga_iskr1030m ) ROM_REGION(0x2000,"gfx1", 0) ROM_LOAD( "iskra-1030m.chr", 0x0000, 0x2000, CRC(50b162eb) SHA1(5bd7cb1705a69bd16115a4c9ed1c2748a5c8ad51)) ROM_END //------------------------------------------------- // rom_region - device-specific ROM region //------------------------------------------------- const tiny_rom_entry *isa8_cga_iskr1030m_device::device_rom_region() const { return ROM_NAME( cga_iskr1030m ); } DEFINE_DEVICE_TYPE(ISA8_CGA_ISKR1030M, isa8_cga_iskr1030m_device, "cga_iskr1030m", "Iskra-1030M CGA") //------------------------------------------------- // isa8_cga_iskr1030m_device - constructor //------------------------------------------------- isa8_cga_iskr1030m_device::isa8_cga_iskr1030m_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : isa8_cga_device(mconfig, ISA8_CGA_ISKR1030M, tag, owner, clock) { } // XXX ROM_START( mc1502 ) ROM_REGION(0x2000,"gfx1", 0) // taken from mc1502 ROM_LOAD( "symgen.rom", 0x0000, 0x2000, CRC(b2747a52) SHA1(6766d275467672436e91ac2997ac6b77700eba1e)) ROM_END const tiny_rom_entry *isa8_cga_mc1502_device::device_rom_region() const { return ROM_NAME( mc1502 ); } DEFINE_DEVICE_TYPE(ISA8_CGA_M24, isa8_cga_m24_device, "cga_m24", "Olivetti M24 CGA") void isa8_cga_m24_device::device_add_mconfig(machine_config &config) { isa8_cga_device::device_add_mconfig(config); subdevice(CGA_SCREEN_NAME)->set_raw(XTAL(14'318'181), 912, 0, 640, 462, 0, 400); m_crtc->set_reconfigure_callback(FUNC(isa8_cga_m24_device::reconfigure), this); } isa8_cga_m24_device::isa8_cga_m24_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : isa8_cga_m24_device(mconfig, ISA8_CGA_M24, tag, owner, clock) { } isa8_cga_m24_device::isa8_cga_m24_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) : isa8_cga_device(mconfig, type, tag, owner, clock), m_mode2(0), m_index(0) { m_vram_size = 0x8000; } ROM_START(cga_m24) ROM_REGION(0x2000, "gfx1", 0) ROM_LOAD("m24 graphics board go380 258 pqbq.bin", 0x00000, 0x1000, CRC(04495786) SHA1(ea34ee527c5632d049ec11a7ae0fde9e6dee545f)) ROM_REGION(0x1000, "crtc_prom", 0) ROM_LOAD("m24 graphics board go380 gi 9433-0088.bin", 0x00000, 0x1000, CRC(5725e660) SHA1(634c2d165d401883a955e144a0abfa2078a47013)) ROM_END const tiny_rom_entry *isa8_cga_m24_device::device_rom_region() const { return ROM_NAME(cga_m24); } void isa8_cga_m24_device::device_reset() { isa8_cga_device::device_reset(); m_mode2 = 0; m_start_offset = 0; m_chr_gen_offset[0] = m_chr_gen_offset[2] = 0x0000; m_chr_gen_offset[1] = m_chr_gen_offset[3] = 0x0000; } MC6845_RECONFIGURE( isa8_cga_m24_device::reconfigure ) { // just reconfigure the screen, the apb sets it to 256 lines rather than 400 m_screen->configure(width, height, visarea, frame_period); } WRITE8_MEMBER( isa8_cga_m24_device::io_write ) { switch(offset) { case 0: case 2: case 4: case 6: m_index = data; m_crtc->address_w(data); break; case 1: case 3: case 5: case 7: switch(m_index & 0x1f) // TODO: this is handled by a pal and prom { case 0: data &= 0x7f; break; case 9: if((data < 0x80) && (data != 3)) data = (data << 1) + 1; break; case 10: data = ((data << 1) & 0x1f) | (data & 0x60); break; case 11: data <<= 1; break; } m_crtc->register_w(data); break; case 0x0e: m_mode2 = data; if((data & 8) && !(data & 1)) m_start_offset = 0x4000; else m_start_offset = 0; break; default: isa8_cga_device::io_write(space, offset, data); break; } } READ8_MEMBER( isa8_cga_m24_device::io_read ) { uint8_t data = 0xff; switch(offset) { case 0x0a: data = 0xc0 | m_vsync | ( ( data & 0x40 ) >> 4 ) | m_hsync; // 0xc0 == no expansion break; case 0x0e: data = m_mode2; break; default: data = isa8_cga_device::io_read(space, offset); break; } return data; } MC6845_UPDATE_ROW(isa8_cga_m24_device::crtc_update_row) { if(m_mode2 & 1) { m24_gfx_1bpp_m24_update_row(bitmap, cliprect, ma, ra, y, x_count, cursor_x, de, hbp, vbp); return; } if (m_update_row_type == -1) return; y = m_y; if(m_y >= bitmap.height()) return; switch (m_update_row_type) { case CGA_TEXT_INTEN: cga_text(bitmap, cliprect, ma, ra, y, x_count, cursor_x, de, hbp, vbp); break; case CGA_TEXT_INTEN_ALT: cga_text(bitmap, cliprect, ma, ra, y, x_count, cursor_x, de, hbp, vbp); break; case CGA_TEXT_INTEN_CG: // this hardware doesn't support composite break; case CGA_TEXT_BLINK: cga_text(bitmap, cliprect, ma, ra, y, x_count, cursor_x, de, hbp, vbp); break; case CGA_TEXT_BLINK_ALT: cga_text(bitmap, cliprect, ma, ra, y, x_count, cursor_x, de, hbp, vbp); break; case CGA_TEXT_BLINK_SI: break; case CGA_GFX_1BPP: cga_gfx_1bpp_update_row(bitmap, cliprect, ma, ra >> 1, y, x_count, cursor_x, de, hbp, vbp); break; case CGA_GFX_2BPP: cga_gfx_2bpp_update_row(bitmap, cliprect, ma, ra >> 1, y, x_count, cursor_x, de, hbp, vbp); break; case CGA_GFX_4BPPL: cga_gfx_4bppl_update_row(bitmap, cliprect, ma, ra >> 1, y, x_count, cursor_x, de, hbp, vbp); break; case CGA_GFX_4BPPH: cga_gfx_4bpph_update_row(bitmap, cliprect, ma, ra >> 1, y, x_count, cursor_x, de, hbp, vbp); break; } } MC6845_UPDATE_ROW( isa8_cga_m24_device::m24_gfx_1bpp_m24_update_row ) { uint8_t *videoram = &m_vram[m_start_offset]; uint32_t *p = &bitmap.pix32(y); const rgb_t *palette = m_palette->palette()->entry_list_raw(); uint8_t fg = m_color_select & 0x0F; int i; if ( y == 0 ) CGA_LOG(1,"m24_gfx_1bpp_m24_update_row",("\n")); for ( i = 0; i < x_count; i++ ) { uint16_t offset = ( ( ( ma + i ) << 1 ) & 0x1fff ) | ( ( ra & 3 ) << 13 ); uint8_t data = videoram[ offset ]; *p = palette[( data & 0x80 ) ? fg : 0]; p++; *p = palette[( data & 0x40 ) ? fg : 0]; p++; *p = palette[( data & 0x20 ) ? fg : 0]; p++; *p = palette[( data & 0x10 ) ? fg : 0]; p++; *p = palette[( data & 0x08 ) ? fg : 0]; p++; *p = palette[( data & 0x04 ) ? fg : 0]; p++; *p = palette[( data & 0x02 ) ? fg : 0]; p++; *p = palette[( data & 0x01 ) ? fg : 0]; p++; data = videoram[ offset + 1 ]; *p = palette[( data & 0x80 ) ? fg : 0]; p++; *p = palette[( data & 0x40 ) ? fg : 0]; p++; *p = palette[( data & 0x20 ) ? fg : 0]; p++; *p = palette[( data & 0x10 ) ? fg : 0]; p++; *p = palette[( data & 0x08 ) ? fg : 0]; p++; *p = palette[( data & 0x04 ) ? fg : 0]; p++; *p = palette[( data & 0x02 ) ? fg : 0]; p++; *p = palette[( data & 0x01 ) ? fg : 0]; p++; } } DEFINE_DEVICE_TYPE(ISA8_CGA_CPORTIII, isa8_cga_cportiii_device, "cga_cportiii", "Compaq Portable III CGA") void isa8_cga_cportiii_device::device_add_mconfig(machine_config &config) { isa8_cga_m24_device::device_add_mconfig(config); subdevice(CGA_SCREEN_NAME)->set_color(rgb_t(255, 125, 0)); } isa8_cga_cportiii_device::isa8_cga_cportiii_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : isa8_cga_m24_device(mconfig, ISA8_CGA_CPORTIII, tag, owner, clock) { } ROM_START(cga_cportiii) ROM_REGION(0x2000, "gfx1", 0) ROM_FILL(0, 0x2000, 0) ROM_END const tiny_rom_entry *isa8_cga_cportiii_device::device_rom_region() const { return ROM_NAME(cga_cportiii); } void isa8_cga_cportiii_device::device_reset() { isa8_cga_m24_device::device_reset(); m_isa->install_device(0x13c6, 0x13c7, read8_delegate(FUNC(isa8_cga_cportiii_device::port_13c6_r), this), write8_delegate(FUNC(isa8_cga_cportiii_device::port_13c6_w), this)); m_isa->install_device(0x23c6, 0x23c7, read8_delegate(FUNC(isa8_cga_cportiii_device::port_23c6_r), this), write8_delegate(FUNC(isa8_cga_cportiii_device::port_23c6_w), this)); m_palette->set_pen_color(0, 100, 25, 0); m_chr_gen_offset[0] = m_chr_gen_offset[2] = 0x0000; m_chr_gen_offset[1] = m_chr_gen_offset[3] = 0x1000; } WRITE8_MEMBER(isa8_cga_cportiii_device::char_ram_write) { m_chr_gen_base[offset] = data; } READ8_MEMBER(isa8_cga_cportiii_device::char_ram_read) { return m_chr_gen_base[offset]; } READ8_MEMBER(isa8_cga_cportiii_device::port_13c6_r) { return 0x04; } WRITE8_MEMBER(isa8_cga_cportiii_device::port_13c6_w) { } READ8_MEMBER(isa8_cga_cportiii_device::port_23c6_r) { return 0; } WRITE8_MEMBER(isa8_cga_cportiii_device::port_23c6_w) { m_mode2 = data & 1; if(BIT(data, 3)) m_isa->install_memory(0xb8000, 0xb9fff, read8_delegate(FUNC(isa8_cga_cportiii_device::char_ram_read), this), write8_delegate(FUNC(isa8_cga_cportiii_device::char_ram_write), this)); else m_isa->install_bank(0xb8000, 0xb8000 + 0x8000 - 1, "bank_cga", &m_vram[0]); }