summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/bus/isa/mda.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/bus/isa/mda.cpp')
-rw-r--r--src/devices/bus/isa/mda.cpp1288
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);
}
}