diff options
Diffstat (limited to 'src/devices/bus/isa/mda.cpp')
| -rw-r--r-- | src/devices/bus/isa/mda.cpp | 1288 |
1 files changed, 496 insertions, 792 deletions
diff --git a/src/devices/bus/isa/mda.cpp b/src/devices/bus/isa/mda.cpp index 77ac7d6028e..43155d35885 100644 --- a/src/devices/bus/isa/mda.cpp +++ b/src/devices/bus/isa/mda.cpp @@ -1,977 +1,681 @@ // license:BSD-3-Clause // copyright-holders:Wilbert Pol, Miodrag Milanovic -/*************************************************************************** - Monochrome Display Adapter (MDA) section - -***************************************************************************/ +/* + * IBM Monochrome Display and Printer Adapter (MDA) + * Hercules Graphics Card (HGC) + * EC1840.0002 (MDA) + * + * TODO: + * - EC1840 testing + */ #include "emu.h" #include "mda.h" -#include "screen.h" +#include "machine/pc_lpt.h" +#include "video/mc6845.h" +#include "dipalette.h" +#include "screen.h" -#define LOG_READ (1U << 1) -#define LOG_SETUP (1U << 2) -#define LOG_ROW (1U << 3) -#define LOG_MODE (1U << 4) -#define LOG_CHRG (1U << 5) -#define LOG_STAT (1U << 6) +#define LOG_REGW (1U << 1) +#define LOG_REGR (1U << 2) -//#define VERBOSE (LOG_MODE|LOG_STAT) +//#define VERBOSE (LOG_REGW) //#define LOG_OUTPUT_STREAM std::cout #include "logmacro.h" -#define LOGR(...) LOGMASKED(LOG_READ, __VA_ARGS__) -#define LOGSETUP(...) LOGMASKED(LOG_SETUP, __VA_ARGS__) -#define LOGROW(...) LOGMASKED(LOG_ROW, __VA_ARGS__) -#define LOGMODE(...) LOGMASKED(LOG_MODE, __VA_ARGS__) -#define LOGCHRG(...) LOGMASKED(LOG_CHRG, __VA_ARGS__) -#define LOGSTAT(...) LOGMASKED(LOG_STAT, __VA_ARGS__) - -#ifdef _MSC_VER -#define FUNCNAME __func__ -#else -#define FUNCNAME __PRETTY_FUNCTION__ -#endif - -#define MDA_SCREEN_NAME "mda_screen" -#define MC6845_NAME "mc6845" +static constexpr XTAL MDA_CLOCK(16'257'000); -/* - Hercules video card - */ -#define HERCULES_SCREEN_NAME "hercules_screen" -#define MDA_CLOCK XTAL(16'257'000) +enum mode_mask : u8 +{ + MODE_HIRES = 0x01, // high resolution mode + MODE_GFX = 0x02, // graphics mode (Hercules only) + MODE_VIDEO = 0x08, // video enable + MODE_BLINK = 0x20, // blink enable + MODE_PG1 = 0x80, // page select (Hercules only) +}; -static const unsigned char mda_palette[4][3] = +enum status_mask : u8 { - { 0x00,0x00,0x00 }, - { 0x00,0x55,0x00 }, - { 0x00,0xaa,0x00 }, - { 0x00,0xff,0x00 } + STATUS_HSYNC = 0x01, + STATUS_VIDEO = 0x08, + STATUS_VSYNC = 0x80, // 0=retrace, 1=active (Hercules only) }; -enum +class isa8_mda_device + : public device_t + , public device_isa8_card_interface + , public device_palette_interface { - MDA_TEXT_INTEN = 0, - MDA_TEXT_BLINK, - HERCULES_GFX_BLINK, - MDA_LOWRES_TEXT_INTEN, - MDA_LOWRES_TEXT_BLINK +public: + isa8_mda_device(machine_config const &mconfig, char const *const tag, device_t *owner, u32 clock) + : isa8_mda_device(mconfig, ISA8_MDA, tag, owner, clock) + { + } + +protected: + isa8_mda_device(machine_config const &mconfig, device_type type, char const *const tag, device_t *owner, u32 clock) + : device_t(mconfig, type, tag, owner, clock) + , device_isa8_card_interface(mconfig, *this) + , device_palette_interface(mconfig, *this) + , m_screen(*this, "screen") + , m_crtc(*this, "mc6845") + , m_lpt(*this, "lpt") + , m_gfx(*this, "gfx") + , m_font(*this, "font") + , m_vram(nullptr) + { + } + + // device_t implementation + virtual tiny_rom_entry const *device_rom_region() const override ATTR_COLD; + virtual void device_add_mconfig(machine_config &config) override ATTR_COLD; + virtual void device_start() override ATTR_COLD; + virtual void device_reset() override ATTR_COLD; + + // device_palette_interface implementation + virtual u32 palette_entries() const noexcept override { return 4; } + + virtual void isa_pio_map(address_map &map); + virtual u8 status_r(); + virtual void mode_w(u8 data); + + virtual MC6845_UPDATE_ROW(update_row); + + required_device<screen_device> m_screen; + required_device<mc6845_device> m_crtc; + required_device<pc_lpt_device> m_lpt; + required_device<gfxdecode_device> m_gfx; + + required_region_ptr<u8> m_font; + std::unique_ptr<u8[]> m_vram; + + u8 m_mode; // mode control register + u8 m_status; // status register + + // internal state + u8 m_frame; }; -/* F4 Character Displayer */ -static const gfx_layout pc_16_charlayout = +DEFINE_DEVICE_TYPE_PRIVATE(ISA8_MDA, device_isa8_card_interface, isa8_mda_device, "isa_ibm_mda", "IBM Monochrome Display and Printer Adapter") + +static std::tuple<unsigned, unsigned> decode_colors(u8 att, bool const blink) +{ + switch (att) + { + case 0x00: + case 0x08: + case 0x80: + case 0x88: + // no display + return std::tuple<unsigned, unsigned>(0, 0); + break; + case 0x70: + // reverse: black on green + return std::tuple<unsigned, unsigned>(0, 2); + break; + case 0x78: + // reverse: dark green on green + return std::tuple<unsigned, unsigned>(1, 2); + break; + case 0xf0: + // reverse: black on bright green (or green if blinking enabled) + return std::tuple<unsigned, unsigned>(0, blink ? 2 : 3); + break; + case 0xf8: + // reverse: dark green on bright green (or green if blinking enabled) + return std::tuple<unsigned, unsigned>(1, blink ? 2 : 3); + break; + default: + // default: green or bright green on black + return std::tuple<unsigned, unsigned>(BIT(att, 3) ? 3 : 2, 0); + } +} + +static gfx_layout const pc_16_charlayout = { - 8, 16, /* 8 x 16 characters */ - 256, /* 256 characters */ - 1, /* 1 bits per pixel */ - { 0 }, /* no bitplanes */ - /* x offsets */ + 8, 16, // 8 x 16 characters + 256, // 256 characters + 1, // 1 bit per pixel + { 0 }, // no bitplanes + // x offsets { 0, 1, 2, 3, 4, 5, 6, 7 }, - /* y offsets */ + // y offsets { 0*8, 1*8, 2*8, 3*8, 4*8, 5*8, 6*8, 7*8, 2048*8, 2049*8, 2050*8, 2051*8, 2052*8, 2053*8, 2054*8, 2055*8 }, - 8*8 /* every char takes 2 x 8 bytes */ + 8*8 // every char takes 2 x 8 bytes }; -static const gfx_layout pc_8_charlayout = +static gfx_layout const pc_8_charlayout = { - 8, 8, /* 8 x 8 characters */ - 512, /* 512 characters */ - 1, /* 1 bits per pixel */ - { 0 }, /* no bitplanes */ - /* x offsets */ + 8, 8, // 8 x 8 characters + 512, // 512 characters + 1, // 1 bit per pixel + { 0 }, // no bitplanes + // x offsets { 0, 1, 2, 3, 4, 5, 6, 7 }, - /* y offsets */ + // y offsets { 0*8, 1*8, 2*8, 3*8, 4*8, 5*8, 6*8, 7*8 }, - 8*8 /* every char takes 8 bytes */ + 8*8 // every char takes 8 bytes }; -static GFXDECODE_START( gfx_pcmda ) - GFXDECODE_ENTRY( "gfx1", 0x0000, pc_16_charlayout, 1, 1 ) - GFXDECODE_ENTRY( "gfx1", 0x1000, pc_8_charlayout, 1, 1 ) +static GFXDECODE_START( gfx_mda ) + GFXDECODE_ENTRY( "font", 0x0000, pc_16_charlayout, 1, 1 ) + GFXDECODE_ENTRY( "font", 0x1000, pc_8_charlayout, 1, 1 ) GFXDECODE_END - -void isa8_mda_device::pc_cpu_line(int state) -{ - m_isa->irq7_w(state); -} - - ROM_START( mda ) - /* IBM 1501981(CGA) and 1501985(MDA) Character rom */ - ROM_REGION(0x08100,"gfx1", 0) - ROM_LOAD("5788005.u33", 0x00000, 0x02000, CRC(0bf56d70) SHA1(c2a8b10808bf51a3c123ba3eb1e9dd608231916f)) /* "AMI 8412PI // 5788005 // (C) IBM CORP. 1981 // KOREA" */ + // IBM 1501981(CGA) and 1501985(MDA) Character rom + ROM_REGION(0x08100,"font", 0) + ROM_LOAD("5788005.u33", 0x00000, 0x02000, CRC(0bf56d70) SHA1(c2a8b10808bf51a3c123ba3eb1e9dd608231916f)) // "AMI 8412PI // 5788005 // (C) IBM CORP. 1981 // KOREA" ROM_END -//************************************************************************** -// GLOBAL VARIABLES -//************************************************************************** - -DEFINE_DEVICE_TYPE(ISA8_MDA, isa8_mda_device, "isa_ibm_mda", "IBM Monochrome Display and Printer Adapter") - - -//------------------------------------------------- -// device_add_mconfig - add device configuration -//------------------------------------------------- +tiny_rom_entry const *isa8_mda_device::device_rom_region() const +{ + return ROM_NAME( mda ); +} void isa8_mda_device::device_add_mconfig(machine_config &config) { - screen_device &screen(SCREEN(config, MDA_SCREEN_NAME, SCREEN_TYPE_RASTER)); - screen.set_raw(MDA_CLOCK, 882, 0, 720, 370, 0, 350); - screen.set_screen_update(MC6845_NAME, FUNC(mc6845_device::screen_update)); - - PALETTE(config, m_palette).set_entries(4); + SCREEN(config, m_screen, SCREEN_TYPE_RASTER); + m_screen->set_raw(MDA_CLOCK, 882, 0, 720, 370, 0, 350); + m_screen->set_screen_update(m_crtc, FUNC(mc6845_device::screen_update)); - MC6845(config, m_crtc, MDA_CLOCK/9); - m_crtc->set_screen(MDA_SCREEN_NAME); + MC6845(config, m_crtc, MDA_CLOCK / 9); + m_crtc->set_screen(m_screen); m_crtc->set_show_border_area(false); m_crtc->set_char_width(9); - m_crtc->set_update_row_callback(FUNC(isa8_mda_device::crtc_update_row)); - m_crtc->out_hsync_callback().set(FUNC(isa8_mda_device::hsync_changed)); - m_crtc->out_vsync_callback().set(FUNC(isa8_mda_device::vsync_changed)); + m_crtc->set_update_row_callback(FUNC(isa8_mda_device::update_row)); + m_crtc->out_hsync_callback().set( + [this](int state) + { + if (state) + m_status |= STATUS_HSYNC; + else + m_status &= ~STATUS_HSYNC; + }); + m_crtc->out_vsync_callback().set([this](int state) { m_frame += state; }); - GFXDECODE(config, "gfxdecode", m_palette, gfx_pcmda); + GFXDECODE(config, m_gfx, *this, gfx_mda); PC_LPT(config, m_lpt); - m_lpt->irq_handler().set(FUNC(isa8_mda_device::pc_cpu_line)); + m_lpt->irq_handler().set([this](int state) { m_isa->irq7_w(state); }); } -//------------------------------------------------- -// rom_region - device-specific ROM region -//------------------------------------------------- - -const tiny_rom_entry *isa8_mda_device::device_rom_region() const +void isa8_mda_device::device_start() { - return ROM_NAME( mda ); -} - -//************************************************************************** -// LIVE DEVICE -//************************************************************************** + set_isa_device(); -//------------------------------------------------- -// isa8_mda_device - constructor -//------------------------------------------------- + save_item(NAME(m_mode)); + save_item(NAME(m_status)); + save_item(NAME(m_frame)); -isa8_mda_device::isa8_mda_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : - isa8_mda_device(mconfig, ISA8_MDA, tag, owner, clock) -{ -} + // allow derived devices to allocate vram + if (!m_vram) + { + m_vram = std::make_unique<u8[]>(0x1000); -isa8_mda_device::isa8_mda_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, MC6845_NAME), m_lpt(*this, "lpt"), m_framecnt(0), m_mode_control(0), - m_update_row_type(-1), m_chr_gen(nullptr), m_vsync(0), m_hsync(0), m_pixel(0), - m_palette(*this, "palette") -{ -} + save_pointer(NAME(m_vram), 0x1000); + } -//------------------------------------------------- -// device_start - device-specific startup -//------------------------------------------------- + m_isa->install_device(0x3b0, 0x3bf, *this, &isa8_mda_device::isa_pio_map); -void isa8_mda_device::device_start() -{ - if (m_palette != nullptr && !m_palette->started()) - throw device_missing_dependencies(); + m_isa->install_bank(0xb0000, 0xb0fff, m_vram.get()); + m_isa->install_bank(0xb1000, 0xb1fff, m_vram.get()); + m_isa->install_bank(0xb2000, 0xb2fff, m_vram.get()); + m_isa->install_bank(0xb3000, 0xb3fff, m_vram.get()); + m_isa->install_bank(0xb4000, 0xb4fff, m_vram.get()); + m_isa->install_bank(0xb5000, 0xb5fff, m_vram.get()); + m_isa->install_bank(0xb6000, 0xb6fff, m_vram.get()); + m_isa->install_bank(0xb7000, 0xb7fff, m_vram.get()); - set_isa_device(); - m_videoram.resize(0x1000); - m_isa->install_device(0x3b0, 0x3bf, read8sm_delegate(*this, FUNC(isa8_mda_device::io_read)), write8sm_delegate(*this, FUNC(isa8_mda_device::io_write))); - m_isa->install_bank(0xb0000, 0xb0fff, &m_videoram[0]); - m_isa->install_bank(0xb1000, 0xb1fff, &m_videoram[0]); - m_isa->install_bank(0xb2000, 0xb2fff, &m_videoram[0]); - m_isa->install_bank(0xb3000, 0xb3fff, &m_videoram[0]); - m_isa->install_bank(0xb4000, 0xb4fff, &m_videoram[0]); - m_isa->install_bank(0xb5000, 0xb5fff, &m_videoram[0]); - m_isa->install_bank(0xb6000, 0xb6fff, &m_videoram[0]); - m_isa->install_bank(0xb7000, 0xb7fff, &m_videoram[0]); - - /* Initialise the mda palette */ - for (int i = 0; i < 4; i++) - m_palette->set_pen_color(i, rgb_t(mda_palette[i][0], mda_palette[i][1], mda_palette[i][2])); + set_pen_color(0, rgb_t{ 0x00,0x00,0x00 }); // black + set_pen_color(1, rgb_t{ 0x00,0x55,0x00 }); // dark green + set_pen_color(2, rgb_t{ 0x00,0xaa,0x00 }); // green + set_pen_color(3, rgb_t{ 0x00,0xff,0x00 }); // bright green } -//------------------------------------------------- -// device_reset - device-specific reset -//------------------------------------------------- - void isa8_mda_device::device_reset() { - m_framecnt = 0; - m_mode_control = 0; - m_vsync = 0; - m_hsync = 0; - m_pixel = 0; - - m_chr_gen = memregion(subtag("gfx1").c_str())->base(); + m_mode = 0; + m_status = 0xf0; + m_frame = 0; } -/*************************************************************************** - - Monochrome Display Adapter (MDA) section - -***************************************************************************/ - -/*************************************************************************** - Draw text mode with 80x25 characters (default) and intense background. - The character cell size is 9x15. Column 9 is column 8 repeated for - character codes 176 to 223. -***************************************************************************/ -MC6845_UPDATE_ROW( isa8_mda_device::mda_text_inten_update_row ) +void isa8_mda_device::isa_pio_map(address_map &map) { - rgb_t const *const palette = m_palette->palette()->entry_list_raw(); - uint32_t *p = &bitmap.pix(y); - uint16_t const chr_base = (ra & 0x08) ? 0x800 | (ra & 0x07) : ra; + map.unmap_value_high(); - if (y == 0) LOGROW("%11.6f: %-24s\n", machine().time().as_double(), FUNCNAME); - for (int i = 0; i < x_count; i++) - { - uint16_t const offset = ((ma + i) << 1) & 0x0fff; - uint8_t const chr = m_videoram[offset]; - uint8_t const attr = m_videoram[offset + 1]; - uint8_t data = m_chr_gen[chr_base + chr * 8]; - uint8_t fg = (attr & 0x08) ? 3 : 2; - uint8_t bg = 0; - - if ((attr & ~0x88) == 0) - { - data = 0x00; - } - - switch (attr) - { - case 0x70: - bg = 2; - fg = 0; - break; - case 0x78: - bg = 2; - fg = 1; - break; - case 0xf0: - bg = 3; - fg = 0; - break; - case 0xf8: - bg = 3; - fg = 1; - break; - } - - if ((i == cursor_x && (m_framecnt & 0x08)) || (attr & 0x07) == 0x01) - { - data = 0xff; - } - - *p++ = palette[(data & 0x80) ? fg : bg]; - *p++ = palette[(data & 0x40) ? fg : bg]; - *p++ = palette[(data & 0x20) ? fg : bg]; - *p++ = palette[(data & 0x10) ? fg : bg]; - *p++ = palette[(data & 0x08) ? fg : bg]; - *p++ = palette[(data & 0x04) ? fg : bg]; - *p++ = palette[(data & 0x02) ? fg : bg]; - *p++ = palette[(data & 0x01) ? fg : bg]; - if ((chr & 0xe0) == 0xc0) - { - *p++ = palette[(data & 0x01) ? fg : bg]; - } - else - { - *p++ = palette[bg]; - } - } + map(0x0, 0x0).mirror(0x6).w(m_crtc, FUNC(mc6845_device::address_w)); + map(0x1, 0x1).mirror(0x6).rw(m_crtc, FUNC(mc6845_device::register_r), FUNC(mc6845_device::register_w)); + map(0x8, 0x8).w(FUNC(isa8_mda_device::mode_w)); + map(0xa, 0xa).r(FUNC(isa8_mda_device::status_r)); + map(0xc, 0xe).rw(m_lpt, FUNC(pc_lpt_device::read), FUNC(pc_lpt_device::write)); } - -/*************************************************************************** - Draw text mode with 80x25 characters (default) and blinking characters. - The character cell size is 9x15. Column 9 is column 8 repeated for - character codes 176 to 223. -***************************************************************************/ - -MC6845_UPDATE_ROW( isa8_mda_device::mda_text_blink_update_row ) +void isa8_mda_device::mode_w(u8 data) { - rgb_t const *const palette = m_palette->palette()->entry_list_raw(); - uint32_t *p = &bitmap.pix(y); - uint16_t const chr_base = (ra & 0x08) ? 0x800 | (ra & 0x07) : ra; + LOGMASKED(LOG_REGW, "%s: mode_w 0x%02x\n", machine().describe_context(), data); - if (y == 0) LOGROW("%11.6f: %-24s\n", machine().time().as_double(), FUNCNAME); - for (int i = 0; i < x_count; i++) - { - uint16_t const offset = ((ma + i) << 1) & 0x0fff; - uint8_t const chr = m_videoram[offset]; - uint8_t const attr = m_videoram[offset + 1]; - uint8_t data = m_chr_gen[chr_base + chr * 8]; - uint8_t fg = (attr & 0x08) ? 3 : 2; - uint8_t bg = 0; - - if ((attr & ~0x88) == 0) - { - data = 0x00; - } - - switch (attr) - { - case 0x70: - case 0xf0: - bg = 2; - fg = 0; - break; - case 0x78: - case 0xf8: - bg = 2; - fg = 1; - break; - } - - if ((attr & 0x07) == 0x01) - { - data = 0xff; - } - - if (i == cursor_x) - { - if (m_framecnt & 0x08) - { - data = 0xff; - } - } - else - { - if ((attr & 0x80) && (m_framecnt & 0x10)) - { - data = 0x00; - } - } - - *p++ = palette[(data & 0x80) ? fg : bg]; - *p++ = palette[(data & 0x40) ? fg : bg]; - *p++ = palette[(data & 0x20) ? fg : bg]; - *p++ = palette[(data & 0x10) ? fg : bg]; - *p++ = palette[(data & 0x08) ? fg : bg]; - *p++ = palette[(data & 0x04) ? fg : bg]; - *p++ = palette[(data & 0x02) ? fg : bg]; - *p++ = palette[(data & 0x01) ? fg : bg]; - if ((chr & 0xe0) == 0xc0) - { - *p++ = palette[(data & 0x01) ? fg : bg]; - } - else - { - *p++ = palette[bg]; - } - } + m_mode = data; } -MC6845_UPDATE_ROW( isa8_mda_device::crtc_update_row ) +u8 isa8_mda_device::status_r() { - if (m_update_row_type == -1) - return; - - switch (m_update_row_type) - { - case MDA_TEXT_INTEN: - mda_text_inten_update_row(bitmap, cliprect, ma, ra, y, x_count, cursor_x, de, hbp, vbp); - break; - case MDA_TEXT_BLINK: - mda_text_blink_update_row(bitmap, cliprect, ma, ra, y, x_count, cursor_x, de, hbp, vbp); - break; - } -} - + // fake pixel stream + if (!machine().side_effects_disabled()) + m_status ^= STATUS_VIDEO; -MC6845_UPDATE_ROW( isa8_hercules_device::crtc_update_row ) -{ - if (m_update_row_type == -1) - return; + LOGMASKED(LOG_REGR, "%s: status_r 0x%02x\n", machine().describe_context(), m_status); - switch (m_update_row_type) - { - case HERCULES_GFX_BLINK: - hercules_gfx_update_row(bitmap, cliprect, ma, ra, y, x_count, cursor_x, de, hbp, vbp); - break; - default: - isa8_mda_device::crtc_update_row(bitmap, cliprect, ma, ra, y, x_count, cursor_x, de, hbp, vbp); - break; - } + return m_status; } - -void isa8_mda_device::hsync_changed(int state) +MC6845_UPDATE_ROW(isa8_mda_device::update_row) { - m_hsync = state ? 1 : 0; -} + // check video enabled + if (!(m_mode & MODE_VIDEO)) + return; + // text mode, 80x25 characters in 9x14 cells + bool const blink = m_mode & MODE_BLINK; + offs_t const font_row = (ra & 0x08) ? 0x800 | (ra & 0x07) : ra; + u32 *pixel = &bitmap.pix(y); -void isa8_mda_device::vsync_changed(int state) -{ - m_vsync = state ? 0x80 : 0; - if ( state ) + for (unsigned i = 0; i < x_count; i++) { - m_framecnt++; - } -} - + offs_t const offset = ((ma + i) << 1) & 0x0fff; + u8 const chr = m_vram[offset + 0]; + u8 const att = m_vram[offset + 1]; -/* - * rW MDA mode control register (see #P138) - */ -void isa8_mda_device::mode_control_w(uint8_t data) -{ - m_mode_control = data; - - switch( m_mode_control & 0x2a ) - { - case 0x08: - m_update_row_type = MDA_TEXT_INTEN; - break; - case 0x28: - m_update_row_type = MDA_TEXT_BLINK; - break; - default: - m_update_row_type = -1; - } -} + bool duplicate = ((chr & 0xe0) == 0xc0); // duplicate 8th pixel for some characters + u8 data = m_font[chr * 8 + font_row]; // read font data + auto const [fg, bg] = decode_colors(att, blink); -/* R- CRT status register (see #P139) - * (EGA/VGA) input status 1 register - * 7 HGC vertical sync in progress - * 6-4 adapter 000 hercules - * 001 hercules+ - * 101 hercules InColor - * else unknown - * 3 pixel stream (0 black, 1 white) - * 2-1 reserved - * 0 horizontal drive enable - */ -uint8_t isa8_mda_device::status_r() -{ - // Faking pixel stream here - if (!machine().side_effects_disabled()) - m_pixel++; + // underline + if ((ra == 12) && (BIT(att, 0, 3) == 1)) + { + duplicate = true; + data = 0xff; + } - return 0xF0 | (m_pixel & 0x08) | m_hsync; -} + // blink characters every 16 frames + if ((m_frame & 0x10) && blink && BIT(att, 7)) + data = 0; + // blink cursor every 8 frames + if ((i == cursor_x) && (m_frame & 0x08)) + { + duplicate = true; + data = 0xff; + } -/************************************************************************* - * - * MDA - * monochrome display adapter - * - *************************************************************************/ -void isa8_mda_device::io_write(offs_t offset, uint8_t data) -{ - switch( offset ) - { - case 0x00: case 0x02: case 0x04: case 0x06: - m_crtc->address_w(data); - break; - case 0x01: case 0x03: case 0x05: case 0x07: - m_crtc->register_w(data); - break; - case 0x08: - mode_control_w(data); - break; - case 0x0c: case 0x0d: case 0x0e: - m_lpt->write(offset - 0x0c, data); - break; + // output first 8 pixels + *pixel++ = pen_color(BIT(data, 7) ? fg : bg); + *pixel++ = pen_color(BIT(data, 6) ? fg : bg); + *pixel++ = pen_color(BIT(data, 5) ? fg : bg); + *pixel++ = pen_color(BIT(data, 4) ? fg : bg); + *pixel++ = pen_color(BIT(data, 3) ? fg : bg); + *pixel++ = pen_color(BIT(data, 2) ? fg : bg); + *pixel++ = pen_color(BIT(data, 1) ? fg : bg); + *pixel++ = pen_color(BIT(data, 0) ? fg : bg); + + // output 9th pixel + if (duplicate) + *pixel++ = pen_color(BIT(data, 0) ? fg : bg); + else + *pixel++ = pen_color(bg); } } -uint8_t isa8_mda_device::io_read(offs_t offset) +class isa8_hercules_device : public isa8_mda_device { - int data = 0xff; - switch( offset ) +public: + isa8_hercules_device(machine_config const &mconfig, char const *const tag, device_t *owner, u32 clock) + : isa8_mda_device(mconfig, ISA8_HERCULES, tag, owner, clock) { - case 0x00: case 0x02: case 0x04: case 0x06: - /* return last written mc6845 address value here? */ - break; - case 0x01: case 0x03: case 0x05: case 0x07: - data = m_crtc->register_r(); - break; - case 0x0a: - data = status_r(); - break; - /* LPT ports */ - case 0x0c: case 0x0d: case 0x0e: - data = m_lpt->read(offset - 0x0c); - break; } - return data; -} - -/*************************************************************************** +protected: + // device_t implementation + virtual tiny_rom_entry const *device_rom_region() const override ATTR_COLD; + virtual void device_add_mconfig(machine_config &config) override ATTR_COLD; + virtual void device_start() override ATTR_COLD; + virtual void device_reset() override ATTR_COLD; - Hercules Display Adapter section (re-uses parts from the MDA section) + virtual void isa_pio_map(address_map &map) override; + virtual void mode_w(u8 data) override; + void config_w(u8 data); -***************************************************************************/ + virtual MC6845_UPDATE_ROW(update_row) override; -/* -When the Hercules changes to graphics mode, the number of pixels per access and -clock divider should be changed. The correct mc6845 implementation does not -allow this. - -The divder/pixels per 6845 clock is 9 for text mode and 16 for graphics mode. -*/ +private: + enum config_mask : u8 + { + CONFIG_GFXEN = 0x01, // graphics mode enable + CONFIG_PG1EN = 0x02, // page 1 enable + }; + u8 m_config; // configuration register +}; -static GFXDECODE_START( gfx_pcherc ) - GFXDECODE_ENTRY( "gfx1", 0x0000, pc_16_charlayout, 1, 1 ) -GFXDECODE_END +DEFINE_DEVICE_TYPE_PRIVATE(ISA8_HERCULES, device_isa8_card_interface, isa8_hercules_device, "isa_hercules", "Hercules Graphics Card") ROM_START( hercules ) - ROM_REGION(0x1000, "gfx1", 0) + ROM_REGION(0x1000, "font", 0) ROM_SYSTEM_BIOS(0, "cp437", "Code page 437") ROMX_LOAD("um2301.bin", 0x0000, 0x1000, CRC(0827bdac) SHA1(15f1aceeee8b31f0d860ff420643e3c7f29b5ffc), ROM_BIOS(0)) ROM_SYSTEM_BIOS(1, "mzv", "Mazovia (Polish)") // dumped from a Taiwanese-made card using the SiS 86C22 chip ROMX_LOAD("hgc_mzv_2301.bin", 0x0000, 0x1000, CRC(9431b9e0) SHA1(3279dfeed4a0f5daa7b57d455c96eafdcbb6bf41), ROM_BIOS(1)) ROM_END -//************************************************************************** -// GLOBAL VARIABLES -//************************************************************************** - -DEFINE_DEVICE_TYPE(ISA8_HERCULES, isa8_hercules_device, "isa_hercules", "Hercules Graphics Card") - -//------------------------------------------------- -// device_add_mconfig - add device configuration -//------------------------------------------------- - -void isa8_hercules_device::device_add_mconfig(machine_config &config) +tiny_rom_entry const *isa8_hercules_device::device_rom_region() const { - screen_device &screen(SCREEN(config, HERCULES_SCREEN_NAME, SCREEN_TYPE_RASTER)); - screen.set_raw(MDA_CLOCK, 882, 0, 720, 370, 0, 350); - screen.set_screen_update(MC6845_NAME, FUNC(mc6845_device::screen_update)); - - PALETTE(config, m_palette).set_entries(4); - - MC6845(config, m_crtc, MDA_CLOCK/9); - m_crtc->set_screen(HERCULES_SCREEN_NAME); - m_crtc->set_show_border_area(false); - m_crtc->set_char_width(9); - m_crtc->set_update_row_callback(FUNC(isa8_hercules_device::crtc_update_row)); - m_crtc->out_hsync_callback().set(FUNC(isa8_mda_device::hsync_changed)); - m_crtc->out_vsync_callback().set(FUNC(isa8_mda_device::vsync_changed)); - - GFXDECODE(config, "gfxdecode", m_palette, gfx_pcherc); - - PC_LPT(config, m_lpt); - m_lpt->irq_handler().set(FUNC(isa8_mda_device::pc_cpu_line)); + return ROM_NAME(hercules); } -//------------------------------------------------- -// rom_region - device-specific ROM region -//------------------------------------------------- +static GFXDECODE_START( gfx_hercules ) + GFXDECODE_ENTRY( "font", 0x0000, pc_16_charlayout, 1, 1 ) +GFXDECODE_END -const tiny_rom_entry *isa8_hercules_device::device_rom_region() const +void isa8_hercules_device::device_add_mconfig(machine_config &config) { - return ROM_NAME( hercules ); -} + isa8_mda_device::device_add_mconfig(config); -//************************************************************************** -// LIVE DEVICE -//************************************************************************** - -//------------------------------------------------- -// isa8_hercules_device - constructor -//------------------------------------------------- + m_crtc->out_vsync_callback().append( + [this](int state) + { + if (state) + m_status &= ~STATUS_VSYNC; + else + m_status |= STATUS_VSYNC; + }); -isa8_hercules_device::isa8_hercules_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : - isa8_mda_device(mconfig, ISA8_HERCULES, tag, owner, clock), m_configuration_switch(0) -{ + m_gfx->set_info(gfx_hercules); } -//------------------------------------------------- -// device_start - device-specific startup -//------------------------------------------------- - void isa8_hercules_device::device_start() { - if (m_palette != nullptr && !m_palette->started()) - throw device_missing_dependencies(); + m_vram = std::make_unique<u8[]>(0x10000); - m_videoram.resize(0x10000); - set_isa_device(); - m_isa->install_device(0x3b0, 0x3bf, read8sm_delegate(*this, FUNC(isa8_hercules_device::io_read)), write8sm_delegate(*this, FUNC(isa8_hercules_device::io_write))); - m_isa->install_bank(0xb0000, 0xbffff, &m_videoram[0]); + isa8_mda_device::device_start(); - /* Initialise the mda palette */ - for(int i = 0; i < (sizeof(mda_palette) / 3); i++) - m_palette->set_pen_color(i, mda_palette[i][0], mda_palette[i][1], mda_palette[i][2]); -} + save_item(NAME(m_config)); + + save_pointer(NAME(m_vram), 0x10000); -//------------------------------------------------- -// device_reset - device-specific reset -//------------------------------------------------- + m_isa->install_bank(0xb0000, 0xb7fff, m_vram.get()); +} void isa8_hercules_device::device_reset() { isa8_mda_device::device_reset(); - m_configuration_switch = 0; - m_chr_gen = memregion(subtag("gfx1").c_str())->base(); + m_status = 0; + m_config = 0; } -/*************************************************************************** - Draw graphics with 720x348 pixels (default); so called Hercules gfx. - The memory layout is divided into 4 banks where of size 0x2000. - Every bank holds data for every n'th scanline, 8 pixels per byte, - bit 7 being the leftmost. -***************************************************************************/ - -MC6845_UPDATE_ROW( isa8_hercules_device::hercules_gfx_update_row ) +void isa8_hercules_device::isa_pio_map(address_map &map) { - rgb_t const *const palette = m_palette->palette()->entry_list_raw(); - uint32_t *p = &bitmap.pix(y); - uint16_t const gfx_base = ((m_mode_control & 0x80) ? 0x8000 : 0x0000) | ((ra & 0x03) << 13); + isa8_mda_device::isa_pio_map(map); - if (y == 0) LOGROW("%11.6f: %-24s\n", machine().time().as_double(), FUNCNAME); - for (int i = 0; i < x_count; i++) - { - uint8_t data; - - data = m_videoram[gfx_base + ((ma + i) << 1)]; - - *p++ = palette[(data & 0x80) ? 2 : 0]; - *p++ = palette[(data & 0x40) ? 2 : 0]; - *p++ = palette[(data & 0x20) ? 2 : 0]; - *p++ = palette[(data & 0x10) ? 2 : 0]; - *p++ = palette[(data & 0x08) ? 2 : 0]; - *p++ = palette[(data & 0x04) ? 2 : 0]; - *p++ = palette[(data & 0x02) ? 2 : 0]; - *p++ = palette[(data & 0x01) ? 2 : 0]; - - data = m_videoram[gfx_base + ((ma + i) << 1) + 1]; - - *p++ = palette[(data & 0x80) ? 2 : 0]; - *p++ = palette[(data & 0x40) ? 2 : 0]; - *p++ = palette[(data & 0x20) ? 2 : 0]; - *p++ = palette[(data & 0x10) ? 2 : 0]; - *p++ = palette[(data & 0x08) ? 2 : 0]; - *p++ = palette[(data & 0x04) ? 2 : 0]; - *p++ = palette[(data & 0x02) ? 2 : 0]; - *p++ = palette[(data & 0x01) ? 2 : 0]; - } + map(0xf, 0xf).w(FUNC(isa8_hercules_device::config_w)); } +void isa8_hercules_device::mode_w(u8 data) +{ + LOGMASKED(LOG_REGW, "%s: mode_w 0x%02x\n", machine().describe_context(), data); + + if (!(m_config & CONFIG_GFXEN)) + data &= ~MODE_GFX; + + if (!(m_config & CONFIG_PG1EN)) + data &= ~MODE_PG1; + + m_mode = data; -void isa8_hercules_device::mode_control_w(uint8_t data) + m_crtc->set_unscaled_clock(MDA_CLOCK / ((m_mode & MODE_GFX) ? 16 : 9)); + m_crtc->set_hpixels_per_column((m_mode & MODE_GFX) ? 16 : 9); +} + +void isa8_hercules_device::config_w(u8 data) { - m_mode_control = data; + LOGMASKED(LOG_REGW, "%s: config_w 0x%02x\n", machine().describe_context(), data); + + // TODO: does clearing GFXEN force text mode? - switch( m_mode_control & 0x2a ) + if ((data ^ m_config) & CONFIG_PG1EN) { - case 0x08: - m_update_row_type = MDA_TEXT_INTEN; - break; - case 0x28: - m_update_row_type = MDA_TEXT_BLINK; - break; - case 0x0A: /* Hercules modes */ - case 0x2A: - m_update_row_type = HERCULES_GFX_BLINK; - break; - default: - m_update_row_type = -1; + if (data & CONFIG_PG1EN) + m_isa->install_bank(0xb8000, 0xbffff, &m_vram[0x8000]); + else + m_isa->unmap_bank(0xb8000, 0xbffff); } - m_crtc->set_unscaled_clock( MDA_CLOCK / (m_mode_control & 0x02 ? 16 : 9) ); - m_crtc->set_hpixels_per_column( m_mode_control & 0x02 ? 16 : 9 ); + m_config = data; } - -void isa8_hercules_device::io_write(offs_t offset, uint8_t data) +MC6845_UPDATE_ROW(isa8_hercules_device::update_row) { - switch( offset ) + // check video enabled + if (!(m_mode & MODE_VIDEO)) + return; + + if (m_mode & MODE_GFX) + { + // graphics, 720x348 pixels, 2 x 32KiB pages + u8 const *vram = &m_vram[((m_mode & MODE_PG1) ? 0x8000 : 0x0000) | ((ra & 0x03) << 13) + ma * 2]; + u32 *pixel = &bitmap.pix(y); + + for (int i = 0; i < x_count; i++) + { + u8 data = *vram++; + + *pixel++ = pen_color(BIT(data, 7) ? 2 : 0); + *pixel++ = pen_color(BIT(data, 6) ? 2 : 0); + *pixel++ = pen_color(BIT(data, 5) ? 2 : 0); + *pixel++ = pen_color(BIT(data, 4) ? 2 : 0); + *pixel++ = pen_color(BIT(data, 3) ? 2 : 0); + *pixel++ = pen_color(BIT(data, 2) ? 2 : 0); + *pixel++ = pen_color(BIT(data, 1) ? 2 : 0); + *pixel++ = pen_color(BIT(data, 0) ? 2 : 0); + + data = *vram++; + + *pixel++ = pen_color(BIT(data, 7) ? 2 : 0); + *pixel++ = pen_color(BIT(data, 6) ? 2 : 0); + *pixel++ = pen_color(BIT(data, 5) ? 2 : 0); + *pixel++ = pen_color(BIT(data, 4) ? 2 : 0); + *pixel++ = pen_color(BIT(data, 3) ? 2 : 0); + *pixel++ = pen_color(BIT(data, 2) ? 2 : 0); + *pixel++ = pen_color(BIT(data, 1) ? 2 : 0); + *pixel++ = pen_color(BIT(data, 0) ? 2 : 0); + } + } + else + isa8_mda_device::update_row(bitmap, cliprect, ma, ra, y, x_count, cursor_x, de, hbp, vbp); +} + +class isa8_ec1840_0002_device + : public device_t + , public device_isa8_card_interface + , public device_palette_interface +{ +public: + isa8_ec1840_0002_device(machine_config const &mconfig, char const *const tag, device_t *owner, u32 clock) + : device_t(mconfig, ISA8_EC1840_0002, tag, owner, clock) + , device_isa8_card_interface(mconfig, *this) + , device_palette_interface(mconfig, *this) + , m_screen(*this, "screen") + , m_crtc(*this, "mc6845") + , m_vram(nullptr) + , m_font(nullptr) { - case 0x00: case 0x02: case 0x04: case 0x06: - m_crtc->address_w(data); - break; - case 0x01: case 0x03: case 0x05: case 0x07: - m_crtc->register_w(data); - break; - case 0x08: - mode_control_w(data); - break; - case 0x0c: case 0x0d: case 0x0e: - m_lpt->write(offset - 12, data); - break; - case 0x0f: - m_configuration_switch = data; - break; } -} +protected: + // device_t implementation + virtual void device_add_mconfig(machine_config &config) override ATTR_COLD; + virtual void device_start() override ATTR_COLD; + virtual void device_reset() override ATTR_COLD; -/* R- CRT status register (see #P139) - * (EGA/VGA) input status 1 register - * 7 HGC vertical sync in progress - * 6-4 adapter 000 hercules - * 001 hercules+ - * 101 hercules InColor - * else unknown - * 3 pixel stream (0 black, 1 white) - * 2-1 reserved - * 0 horizontal drive enable - */ -uint8_t isa8_hercules_device::status_r() -{ - // Faking pixel stream here - if (!machine().side_effects_disabled()) - m_pixel++; + // device_palette_interface implementation + virtual u32 palette_entries() const noexcept override { return 4; } - return m_vsync | ( m_pixel & 0x08 ) | m_hsync; -} + void isa_pio_map(address_map &map); + u8 status_r(); + void mode_w(u8 data); + MC6845_UPDATE_ROW(update_row); -uint8_t isa8_hercules_device::io_read(offs_t offset) -{ - int data = 0xff; - switch( offset ) - { - case 0x00: case 0x02: case 0x04: case 0x06: - /* return last written mc6845 address value here? */ - break; - case 0x01: case 0x03: case 0x05: case 0x07: - data = m_crtc->register_r(); - break; - case 0x0a: - data = status_r(); - break; - /* LPT ports */ - case 0xc: case 0xd: case 0xe: - data = m_lpt->read(offset - 0x0c); - break; - } - return data; -} +private: + required_device<screen_device> m_screen; + required_device<mc6845_device> m_crtc; -DEFINE_DEVICE_TYPE(ISA8_EC1840_0002, isa8_ec1840_0002_device, "ec1840_0002", "EC1840.0002 (MDA)") + std::unique_ptr<u8[]> m_vram; + std::unique_ptr<u8[]> m_font; + u8 m_mode; // mode control register + u8 m_status; // status register -//------------------------------------------------- -// device_add_mconfig - add device configuration -//------------------------------------------------- + // internal state + u8 m_frame; +}; + +DEFINE_DEVICE_TYPE_PRIVATE(ISA8_EC1840_0002, device_isa8_card_interface, isa8_ec1840_0002_device, "ec1840_0002", "EC1840.0002 (MDA)") -// XXX void isa8_ec1840_0002_device::device_add_mconfig(machine_config &config) { - screen_device &screen(SCREEN(config, MDA_SCREEN_NAME, SCREEN_TYPE_RASTER)); - screen.set_raw(MDA_CLOCK, 792, 0, 640, 370, 0, 350); - screen.set_screen_update(MC6845_NAME, FUNC(mc6845_device::screen_update)); - - PALETTE(config, m_palette).set_entries(4); + SCREEN(config, m_screen, SCREEN_TYPE_RASTER); + m_screen->set_raw(MDA_CLOCK, 792, 0, 640, 370, 0, 350); + m_screen->set_screen_update(m_crtc, FUNC(mc6845_device::screen_update)); - MC6845(config, m_crtc, MDA_CLOCK/8); - m_crtc->set_screen(MDA_SCREEN_NAME); + MC6845(config, m_crtc, MDA_CLOCK / 8); + m_crtc->set_screen(m_screen); m_crtc->set_show_border_area(false); m_crtc->set_char_width(8); - m_crtc->set_update_row_callback(FUNC(isa8_mda_device::crtc_update_row)); - m_crtc->out_hsync_callback().set(FUNC(isa8_mda_device::hsync_changed)); - m_crtc->out_vsync_callback().set(FUNC(isa8_mda_device::vsync_changed)); + m_crtc->set_update_row_callback(FUNC(isa8_ec1840_0002_device::update_row)); + m_crtc->out_hsync_callback().set( + [this](int state) + { + if (state) + m_status |= STATUS_HSYNC; + else + m_status &= ~STATUS_HSYNC; + }); + m_crtc->out_vsync_callback().set([this](int state) { m_frame += state; }); } -//------------------------------------------------- -// isa8_ec1840_0002_device - constructor -//------------------------------------------------- - -isa8_ec1840_0002_device::isa8_ec1840_0002_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : - isa8_mda_device(mconfig, ISA8_EC1840_0002, tag, owner, clock), m_soft_chr_gen(nullptr) +void isa8_ec1840_0002_device::device_start() { -} + set_isa_device(); -//------------------------------------------------- -// device_start - device-specific startup -//------------------------------------------------- + m_vram = std::make_unique<u8[]>(0x1000); + m_font = std::make_unique<u8[]>(0x2000); -void isa8_ec1840_0002_device::device_start() -{ - isa8_mda_device::device_start(); + save_item(NAME(m_mode)); + save_item(NAME(m_status)); + save_item(NAME(m_frame)); + + save_pointer(NAME(m_vram), 0x1000); + save_pointer(NAME(m_font), 0x2000); + + m_isa->install_device(0x3b0, 0x3bf, *this, &isa8_ec1840_0002_device::isa_pio_map); + + m_isa->install_bank(0xb0000, 0xb0fff, m_vram.get()); + m_isa->install_bank(0xb1000, 0xb1fff, m_vram.get()); + m_isa->install_bank(0xb2000, 0xb2fff, m_vram.get()); + m_isa->install_bank(0xb3000, 0xb3fff, m_vram.get()); + m_isa->install_bank(0xb4000, 0xb4fff, m_vram.get()); + m_isa->install_bank(0xb5000, 0xb5fff, m_vram.get()); + m_isa->install_bank(0xb6000, 0xb6fff, m_vram.get()); + m_isa->install_bank(0xb7000, 0xb7fff, m_vram.get()); + + m_isa->install_bank(0xdc000, 0xddfff, m_font.get()); + m_isa->install_bank(0xde000, 0xdffff, m_font.get()); - m_soft_chr_gen = std::make_unique<uint8_t[]>(0x2000); - m_isa->install_bank(0xdc000, 0xddfff, m_soft_chr_gen.get()); - m_isa->install_bank(0xde000, 0xdffff, m_soft_chr_gen.get()); + set_pen_color(0, rgb_t{ 0x00,0x00,0x00 }); // black + set_pen_color(1, rgb_t{ 0x00,0x55,0x00 }); // dark green + set_pen_color(2, rgb_t{ 0x00,0xaa,0x00 }); // green + set_pen_color(3, rgb_t{ 0x00,0xff,0x00 }); // bright green } void isa8_ec1840_0002_device::device_reset() { - isa8_mda_device::device_reset(); - - m_chr_gen = m_soft_chr_gen.get(); + m_mode = 0; + m_status = 0xf0; + m_frame = 0; } +void isa8_ec1840_0002_device::isa_pio_map(address_map &map) +{ + map.unmap_value_high(); -/*************************************************************************** - Draw text mode with 80x25 characters (default) and intense background. - The character cell size is 8x14. -***************************************************************************/ + map(0x0, 0x0).mirror(0x6).w(m_crtc, FUNC(mc6845_device::address_w)); + map(0x1, 0x1).mirror(0x6).rw(m_crtc, FUNC(mc6845_device::register_r), FUNC(mc6845_device::register_w)); + map(0x8, 0x8).w(FUNC(isa8_ec1840_0002_device::mode_w)); + map(0xa, 0xa).r(FUNC(isa8_ec1840_0002_device::status_r)); +} -MC6845_UPDATE_ROW( isa8_ec1840_0002_device::mda_lowres_text_inten_update_row ) +void isa8_ec1840_0002_device::mode_w(u8 data) { - rgb_t const *const palette = m_palette->palette()->entry_list_raw(); - uint32_t *p = &bitmap.pix(y); - uint16_t const chr_base = ra; + LOGMASKED(LOG_REGW, "%s: mode_w 0x%02x\n", machine().describe_context(), data); - if (y == 0) LOGROW("%11.6f: %-24s\n", machine().time().as_double(), FUNCNAME); - for (int i = 0; i < x_count; i++) - { - uint16_t const offset = ((ma + i) << 1) & 0x0fff; - uint8_t const chr = m_videoram[offset]; - uint8_t const attr = m_videoram[offset + 1]; - uint8_t data = m_chr_gen[(chr_base + chr * 16) << 1]; - uint8_t fg = (attr & 0x08) ? 3 : 2; - uint8_t bg = 0; - - if ((attr & ~0x88) == 0) - { - data = 0x00; - } + m_mode = data; +} - switch (attr) - { - case 0x70: - bg = 2; - fg = 0; - break; - case 0x78: - bg = 2; - fg = 1; - break; - case 0xf0: - bg = 3; - fg = 0; - break; - case 0xf8: - bg = 3; - fg = 1; - break; - } +u8 isa8_ec1840_0002_device::status_r() +{ + // fake pixel stream + if (!machine().side_effects_disabled()) + m_status ^= STATUS_VIDEO; - if ((i == cursor_x && (m_framecnt & 0x08)) || (attr & 0x07) == 0x01) - { - data = 0xff; - } + LOGMASKED(LOG_REGR, "%s: status_r 0x%02x\n", machine().describe_context(), m_status); - *p++ = palette[(data & 0x80) ? fg : bg]; - *p++ = palette[(data & 0x40) ? fg : bg]; - *p++ = palette[(data & 0x20) ? fg : bg]; - *p++ = palette[(data & 0x10) ? fg : bg]; - *p++ = palette[(data & 0x08) ? fg : bg]; - *p++ = palette[(data & 0x04) ? fg : bg]; - *p++ = palette[(data & 0x02) ? fg : bg]; - *p++ = palette[(data & 0x01) ? fg : bg]; - } + return m_status; } - -/*************************************************************************** - Draw text mode with 80x25 characters (default) and blinking characters. - The character cell size is 8x14. -***************************************************************************/ - -MC6845_UPDATE_ROW( isa8_ec1840_0002_device::mda_lowres_text_blink_update_row ) +MC6845_UPDATE_ROW(isa8_ec1840_0002_device::update_row) { - rgb_t const *const palette = m_palette->palette()->entry_list_raw(); - uint32_t *p = &bitmap.pix(y); - uint16_t const chr_base = ra; - - if (y == 0) LOGROW("%11.6f: %-24s\n", machine().time().as_double(), FUNCNAME); - for (int i = 0; i < x_count; i++) - { - uint16_t const offset = ((ma + i) << 1) & 0x0fff; - uint8_t const chr = m_videoram[offset]; - uint8_t const attr = m_videoram[offset + 1]; - uint8_t data = m_chr_gen[(chr_base + chr * 16) << 1]; - uint8_t fg = (attr & 0x08) ? 3 : 2; - uint8_t bg = 0; - - if ((attr & ~0x88) == 0) - { - data = 0x00; - } + // check video enabled + if (!(m_mode & MODE_VIDEO)) + return; - switch (attr) - { - case 0x70: - case 0xf0: - bg = 2; - fg = 0; - break; - case 0x78: - case 0xf8: - bg = 2; - fg = 1; - break; - } + // text mode, 80x25 characters in 8x14 cells + bool const blink = m_mode & MODE_BLINK; + u32 *pixel = &bitmap.pix(y); - if ((attr & 0x07) == 0x01) - { - data = 0xff; - } + for (unsigned i = 0; i < x_count; i++) + { + offs_t const offset = ((ma + i) << 1) & 0x0fff; + u8 const chr = m_vram[offset + 0]; + u8 const att = m_vram[offset + 1]; - if (i == cursor_x) - { - if (m_framecnt & 0x08) - { - data = 0xff; - } - } - else - { - if ((attr & 0x80) && (m_framecnt & 0x10)) - { - data = 0x00; - } - } + u8 data = m_font[(ra + chr * 16) << 1]; - *p++ = palette[(data & 0x80) ? fg : bg]; - *p++ = palette[(data & 0x40) ? fg : bg]; - *p++ = palette[(data & 0x20) ? fg : bg]; - *p++ = palette[(data & 0x10) ? fg : bg]; - *p++ = palette[(data & 0x08) ? fg : bg]; - *p++ = palette[(data & 0x04) ? fg : bg]; - *p++ = palette[(data & 0x02) ? fg : bg]; - *p++ = palette[(data & 0x01) ? fg : bg]; - } -} + auto const [fg, bg] = decode_colors(att, blink); -void isa8_ec1840_0002_device::mode_control_w(uint8_t data) -{ - m_mode_control = data; + // underline + if ((ra == 12) && (BIT(att, 0, 3) == 1)) + data = 0xff; - switch( m_mode_control & 0x2a ) - { - case 0x08: - m_update_row_type = MDA_LOWRES_TEXT_INTEN; - break; - case 0x28: - m_update_row_type = MDA_LOWRES_TEXT_BLINK; - break; - default: - m_update_row_type = -1; - } -} + // blink characters every 16 frames + if ((m_frame & 0x10) && blink && BIT(att, 7)) + data = 0; -MC6845_UPDATE_ROW( isa8_ec1840_0002_device::crtc_update_row ) -{ - if (m_update_row_type == -1) - return; + // blink cursor every 8 frames + if ((i == cursor_x) && (m_frame & 0x08)) + data = 0xff; - switch (m_update_row_type) - { - case MDA_LOWRES_TEXT_INTEN: - mda_lowres_text_inten_update_row(bitmap, cliprect, ma, ra, y, x_count, cursor_x, de, hbp, vbp); - break; - case MDA_LOWRES_TEXT_BLINK: - mda_lowres_text_blink_update_row(bitmap, cliprect, ma, ra, y, x_count, cursor_x, de, hbp, vbp); - break; + *pixel++ = pen_color(BIT(data, 7) ? fg : bg); + *pixel++ = pen_color(BIT(data, 6) ? fg : bg); + *pixel++ = pen_color(BIT(data, 5) ? fg : bg); + *pixel++ = pen_color(BIT(data, 4) ? fg : bg); + *pixel++ = pen_color(BIT(data, 3) ? fg : bg); + *pixel++ = pen_color(BIT(data, 2) ? fg : bg); + *pixel++ = pen_color(BIT(data, 1) ? fg : bg); + *pixel++ = pen_color(BIT(data, 0) ? fg : bg); } } |
