summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/bus/isa/pgc.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/bus/isa/pgc.c')
-rw-r--r--src/devices/bus/isa/pgc.c372
1 files changed, 372 insertions, 0 deletions
diff --git a/src/devices/bus/isa/pgc.c b/src/devices/bus/isa/pgc.c
new file mode 100644
index 00000000000..ed191e070c3
--- /dev/null
+++ b/src/devices/bus/isa/pgc.c
@@ -0,0 +1,372 @@
+// license:BSD-3-Clause
+// copyright-holders:Sergey Svishchev
+
+/***************************************************************************
+
+ IBM Professional Graphics Controller (PGC), skeleton driver.
+
+ Designed for IBM by Vermont Microsystems. References:
+
+ IBM Options and Adapters manual
+ http://www.minuszerodegrees.net/oa/OA%20-%20IBM%20Professional%20Graphics%20Controller.pdf
+ http://bitsavers.org/pdf/ibm/pc/cards/Technical_Reference_Options_and_Adapters_Volume_3.pdf
+ IBM Systems Journal white paper
+ http://wayback.archive.org/web/20061015235146/http://www.research.ibm.com/journal/sj/241/ibmsj2401D.pdf
+ John Elliott's page
+ http://www.seasip.info/VintagePC/pgc.html
+
+ To do:
+ - memory map (restore ROM mapping on reset, ...)
+ - various VRAM write modes
+ - what's up with irq 3 (= vblank irq)?
+ - "test pin of the microprocessor samples the hsync pulse"
+ - CGA emulator
+ - bus state handling?
+ - VRAM address translator ROM?
+
+***************************************************************************/
+
+#include "emu.h"
+
+//nclude "machine/ram.h"
+
+#include "pgc.h"
+
+#define VERBOSE_PGC 1
+
+#define DBG_LOG(N,M,A) \
+ do { \
+ if(VERBOSE_PGC>=N) \
+ { \
+ if( M ) \
+ logerror("%11.6f at %s: %-24s",machine().time().as_double(),machine().describe_context(),(char*)M ); \
+ logerror A; \
+ } \
+ } while (0)
+
+#define PGC_SCREEN_NAME "pgc_screen"
+
+#define PGC_TOTAL_HORZ 820
+#define PGC_DISP_HORZ 640
+#define PGC_HORZ_START 80
+
+#define PGC_TOTAL_VERT 508
+#define PGC_DISP_VERT 480
+#define PGC_VERT_START 10
+
+/*
+ Prototypes
+*/
+
+ROM_START( pgc )
+ ROM_REGION(0x100000, "maincpu", 0)
+ ROM_DEFAULT_BIOS("1985")
+
+ ROM_SYSTEM_BIOS(0, "1984", "1984 firmware, P/N 6137322/3")
+ ROMX_LOAD("ibm_6137323_pgc_card_27256.bin", 0x00000, 0x8000, CRC(f564f342) SHA1(c5ef17fd1569043cb59f61faf828ea8b0ee95526), ROM_BIOS(1))
+ ROMX_LOAD("ibm_6137322_pgc_card_27256.bin", 0x08000, 0x8000, CRC(5e6cc82f) SHA1(45b3ffb5a9c51986862f8d47b3e03dcaaf4073d5), ROM_BIOS(1))
+
+ ROM_SYSTEM_BIOS(1, "1985", "1985 firmware, P/N 59X7354/5")
+ ROMX_LOAD("pgc_u44.bin", 0x00000, 0x8000, CRC(71280241) SHA1(7042ccd4ebd03f576a256a433b8aa38d1b4fefa8), ROM_BIOS(2))
+ ROMX_LOAD("pgc_u43.bin", 0x08000, 0x8000, CRC(923f5ea3) SHA1(2b2a55d64b20d3a613b00c51443105aa03eca5d6), ROM_BIOS(2))
+
+ ROM_REGION(0x800, "commarea", ROMREGION_ERASE00)
+
+ ROM_REGION(0x1000, "chargen", 0)
+ ROM_LOAD("pgc_u27.bin", 0x0000, 0x1000, CRC(6be256cc) SHA1(deb1195886268dcddce10459911e020f7a9f74f7))
+ROM_END
+
+static INPUT_PORTS_START( pgc )
+ PORT_START("DSW")
+/*
+ PORT_DIPNAME( 0x01, 0x00, "CGA emulator")
+ PORT_DIPSETTING( 0x00, DEF_STR(No) )
+ PORT_DIPSETTING( 0x01, DEF_STR(Yes) )
+*/
+ PORT_DIPNAME( 0x02, 0x00, "Communication area")
+ PORT_DIPSETTING( 0x00, "C6000" )
+ PORT_DIPSETTING( 0x02, "C6400" )
+INPUT_PORTS_END
+
+/*
+write only
+ 30000 LUT WR O L
+ 30001 LUT WR I L
+ 32000 MODE WT L
+ 32001 NIBBLE WT L
+ 3200A ??
+ 34000 FUNCTION WT L
+ 34001 STARTADD WT L
+ 36001 CURSOR WT L
+
+read only
+ 38000 LUT RD O L
+ 38001 LUT RD I L
+ 3C001 INIT L/INIT H
+*/
+
+static ADDRESS_MAP_START( pgc_map, AS_PROGRAM, 8, isa8_pgc_device )
+ ADDRESS_MAP_UNMAP_HIGH
+ AM_RANGE(0x00000, 0x07fff) AM_ROM
+ AM_RANGE(0x08000, 0x0ffff) AM_ROM AM_REGION("maincpu", 0x8000)
+ AM_RANGE(0x10000, 0x1001f) AM_READWRITE(stateparam_r, stateparam_w)
+// AM_RANGE(0x18000, 0x18fff) AM_RAM // ??
+ AM_RANGE(0x28000, 0x287ff) AM_RAM AM_REGION("commarea", 0) AM_MIRROR(0x800)
+ AM_RANGE(0x3c000, 0x3c001) AM_READ(init_r)
+// AM_RANGE(0x3e000, 0x3efff) AM_RAM // ??
+ AM_RANGE(0xf8000, 0xfffff) AM_ROM AM_REGION("maincpu", 0x8000)
+ADDRESS_MAP_END
+
+static ADDRESS_MAP_START( pgc_io, AS_IO, 8, isa8_pgc_device )
+ ADDRESS_MAP_UNMAP_HIGH
+ADDRESS_MAP_END
+
+static const gfx_layout pgc_charlayout =
+{
+ 8, 16, /* 8x16 pixels */
+ 256, /* 256 characters */
+ 1, /* 1 bits per pixel */
+ { 0 }, /* no bitplanes */
+ /* x offsets */
+ { 0, 1, 2, 3, 4, 5, 6, 7 },
+ /* y offsets */
+ { 0*8, 1*8, 2*8, 3*8, 4*8, 5*8, 6*8, 7*8, 8*8, 9*8, 10*8, 11*8, 12*8, 13*8, 14*8, 15*8 },
+ 8*16 /* every char takes 10 bytes */
+};
+
+static GFXDECODE_START( pgc )
+ GFXDECODE_REVERSEBITS("chargen", 0, pgc_charlayout, 0, 1)
+GFXDECODE_END
+
+MACHINE_CONFIG_FRAGMENT( pcvideo_pgc )
+ MCFG_CPU_ADD("maincpu", I8088, XTAL_24MHz/3)
+ MCFG_CPU_PROGRAM_MAP(pgc_map)
+ MCFG_CPU_IO_MAP(pgc_io)
+#if 0
+ MCFG_CPU_VBLANK_INT_DRIVER(PGC_SCREEN_NAME, isa8_pgc_device, vblank_irq)
+ MCFG_CPU_IRQ_ACKNOWLEDGE_DRIVER(isa8_pgc_device, irq_callback)
+#endif
+
+ MCFG_TIMER_DRIVER_ADD_PERIODIC("scantimer", isa8_pgc_device, scanline_callback,
+ attotime::from_hz(60*PGC_TOTAL_VERT))
+ MCFG_TIMER_START_DELAY(attotime::from_hz(XTAL_50MHz/(2*PGC_HORZ_START)))
+
+ MCFG_SCREEN_ADD(PGC_SCREEN_NAME, RASTER)
+ MCFG_SCREEN_RAW_PARAMS(XTAL_50MHz/2,
+ PGC_TOTAL_HORZ, PGC_HORZ_START, PGC_HORZ_START+PGC_DISP_HORZ,
+ PGC_TOTAL_VERT, PGC_VERT_START, PGC_VERT_START+PGC_DISP_VERT)
+ MCFG_SCREEN_UPDATE_DRIVER(isa8_pgc_device, screen_update)
+ MCFG_SCREEN_PALETTE("palette")
+
+ MCFG_GFXDECODE_ADD("gfxdecode", "palette", pgc)
+ MCFG_PALETTE_ADD( "palette", 256 )
+MACHINE_CONFIG_END
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type ISA8_PGC = &device_creator<isa8_pgc_device>;
+
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor isa8_pgc_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( pcvideo_pgc );
+}
+
+//-------------------------------------------------
+// rom_region - device-specific ROM region
+//-------------------------------------------------
+
+const rom_entry *isa8_pgc_device::device_rom_region() const
+{
+ return ROM_NAME( pgc );
+}
+
+//-------------------------------------------------
+// input_ports - device-specific input ports
+//-------------------------------------------------
+
+ioport_constructor isa8_pgc_device::device_input_ports() const
+{
+ return INPUT_PORTS_NAME( pgc );
+}
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// isa8_pgc_device - constructor
+//-------------------------------------------------
+
+isa8_pgc_device::isa8_pgc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, ISA8_PGC, "IBM Professional Graphics Controller", tag, owner, clock, "isa_ibm_pgc", __FILE__),
+ device_isa8_card_interface(mconfig, *this),
+ m_cpu(*this, "maincpu"),
+ m_screen(*this, PGC_SCREEN_NAME),
+ m_palette(*this, "palette")
+{
+}
+
+isa8_pgc_device::isa8_pgc_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) :
+ device_t(mconfig, type, name, tag, owner, clock, shortname, source),
+ device_isa8_card_interface(mconfig, *this),
+ m_cpu(*this, "maincpu"),
+ m_screen(*this, PGC_SCREEN_NAME),
+ m_palette(*this, "palette")
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void isa8_pgc_device::device_start()
+{
+ address_space &space = m_cpu->space( AS_PROGRAM );
+ int width = PGC_DISP_HORZ;
+ int height = PGC_DISP_VERT;
+
+ if (m_palette != NULL && !m_palette->started())
+ throw device_missing_dependencies();
+
+ set_isa_device();
+
+ for (int i = 0; i < 256; i++ )
+ {
+ m_palette->set_pen_color( i, 0, 0, 0 );
+ }
+
+ m_bitmap = auto_bitmap_ind16_alloc(machine(), width, height);
+ m_bitmap->fill(0);
+
+ m_vram = auto_alloc_array(machine(), UINT8, 0x78000);
+ space.install_readwrite_bank(0x80000, 0xf7fff, "vram");
+ membank("vram")->set_base(m_vram);
+
+ m_eram = auto_alloc_array(machine(), UINT8, 0x8000);
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void isa8_pgc_device::device_reset()
+{
+ memset(m_stateparam, 0, sizeof(m_stateparam));
+ memset(m_lut, 0, sizeof(m_lut));
+
+ m_commarea = memregion("commarea")->base();
+ if (BIT(ioport("DSW")->read(), 1))
+ m_isa->install_bank(0xc6400, 0xc67ff, 0, 0, "commarea", m_commarea);
+ else
+ m_isa->install_bank(0xc6000, 0xc63ff, 0, 0, "commarea", m_commarea);
+#if 0
+ address_space &space = m_cpu->space( AS_PROGRAM );
+
+ space.unmap_readwrite(0xf8000, 0xfffff);
+ space.install_rom(0xf8000, 0xfffff,
+ space.machine().root_device().memregion("maincpu")->base() + 0x8000);
+#endif
+}
+
+//
+
+INTERRUPT_GEN_MEMBER(isa8_pgc_device::vblank_irq)
+{
+ DBG_LOG(2,"irq",("vblank_irq\n"));
+ m_cpu->set_input_line(0, ASSERT_LINE);
+}
+
+IRQ_CALLBACK_MEMBER(isa8_pgc_device::irq_callback)
+{
+ DBG_LOG(2,"irq",("irq_callback\n"));
+ m_cpu->set_input_line(0, CLEAR_LINE);
+ return 3;
+}
+
+// memory handlers
+
+READ8_MEMBER( isa8_pgc_device::stateparam_r ) {
+ UINT8 ret;
+
+ ret = m_stateparam[offset >> 1];
+ if ((machine().debug_flags & DEBUG_FLAG_ENABLED) != 0)
+ {
+ DBG_LOG(1,"stateparam",("R @ %02x == %02x\n", offset, ret));
+ }
+ return ret;
+}
+
+WRITE8_MEMBER( isa8_pgc_device::stateparam_w ) {
+ if ((machine().debug_flags & DEBUG_FLAG_ENABLED) != 0)
+ {
+ DBG_LOG(1,"stateparam",("W @ %02x <- %02x\n", offset, data));
+ }
+ m_stateparam[offset >> 1] = data;
+}
+
+WRITE8_MEMBER( isa8_pgc_device::lut_w ) {
+ UINT8 o = (offset >> 1) * 3;
+
+ if (offset & 1) {
+ m_lut[o + 2] = (data & 15) << 4;
+ m_palette->set_pen_color( offset >> 1, m_lut[o], m_lut[o + 1], m_lut[o + 2] );
+ DBG_LOG(1,"lut",("W @ %02X <- %d %d %d\n",
+ offset >> 1, m_lut[o], m_lut[o + 1], m_lut[o + 2] ));
+ } else {
+ m_lut[o ] = data & 0xf0;
+ m_lut[o + 1] = (data & 15) << 4;
+ }
+}
+
+READ8_MEMBER( isa8_pgc_device::init_r ) {
+ DBG_LOG(1,"INIT",("unmapping ROM\n"));
+ space.unmap_read(0xf8000, 0xfffff);
+
+ DBG_LOG(1,"INIT",("mapping emulator RAM\n"));
+ space.install_readwrite_bank(0xf8000, 0xfffff, "eram");
+ membank("eram")->set_base(m_eram);
+
+ DBG_LOG(1,"INIT",("mapping LUT\n"));
+ space.install_write_handler(0xf8400, 0xf85ff,
+ write8_delegate(FUNC(isa8_pgc_device::lut_w), this));
+
+ return 0; // XXX ignored
+}
+
+TIMER_DEVICE_CALLBACK_MEMBER(isa8_pgc_device::scanline_callback)
+{
+ UINT16 x, y = m_screen->vpos();
+ UINT16 *p;
+ UINT8 *v;
+
+ // XXX hpos shifts every frame -- fix
+ if (y == 0) DBG_LOG(2,"scanline_cb",
+ ("frame %d x %.4d y %.3d\n",
+ (int) m_screen->frame_number(), m_screen->hpos(), y));
+
+ if (y < PGC_VERT_START) return;
+ y -= PGC_VERT_START;
+ if (y >= PGC_DISP_VERT) return;
+
+ // XXX address translation happens in hardware
+ v = &m_vram[y * 1024];
+ p = &m_bitmap->pix16(y, 0);
+
+ for (x = 0; x < PGC_DISP_HORZ; x++) {
+ *p++ = *v++;
+ }
+}
+
+UINT32 isa8_pgc_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
+{
+ copybitmap(bitmap, *m_bitmap, 0, 0, PGC_HORZ_START, PGC_VERT_START, cliprect);
+ return 0;
+}