From cc75eccd812f362b5a4e30ba7a865432c7750528 Mon Sep 17 00:00:00 2001 From: "R. Belmont" Date: Sun, 26 Jan 2014 02:49:09 +0000 Subject: [PATCH] (MESS) Apple II: Support for the Videx UltraTerm card. [R. Belmont] --- .gitattributes | 2 + src/emu/bus/a2bus/a2ultraterm.c | 412 ++++++++++++++++++++++++++++++++ src/emu/bus/a2bus/a2ultraterm.h | 76 ++++++ src/emu/bus/bus.mak | 1 + src/mess/drivers/apple2.c | 3 + 5 files changed, 494 insertions(+) create mode 100644 src/emu/bus/a2bus/a2ultraterm.c create mode 100644 src/emu/bus/a2bus/a2ultraterm.h diff --git a/.gitattributes b/.gitattributes index 887c3387604..3bb600feb04 100644 --- a/.gitattributes +++ b/.gitattributes @@ -416,6 +416,8 @@ src/emu/bus/a2bus/a2themill.c svneol=native#text/plain src/emu/bus/a2bus/a2themill.h svneol=native#text/plain src/emu/bus/a2bus/a2thunderclock.c svneol=native#text/plain src/emu/bus/a2bus/a2thunderclock.h svneol=native#text/plain +src/emu/bus/a2bus/a2ultraterm.c svneol=native#text/plain +src/emu/bus/a2bus/a2ultraterm.h svneol=native#text/plain src/emu/bus/a2bus/a2videoterm.c svneol=native#text/plain src/emu/bus/a2bus/a2videoterm.h svneol=native#text/plain src/emu/bus/a2bus/a2vulcan.c svneol=native#text/plain diff --git a/src/emu/bus/a2bus/a2ultraterm.c b/src/emu/bus/a2bus/a2ultraterm.c new file mode 100644 index 00000000000..0c5ffa1ec09 --- /dev/null +++ b/src/emu/bus/a2bus/a2ultraterm.c @@ -0,0 +1,412 @@ +/********************************************************************* + + a2ultraterm.c + + Implementation of the Videx UltraTerm 80/132/160-column card + + Notes: + + C0nX: C0n0 is 6845 register address, + C0n1 is 6845 register data. + C0n2 is control 1: b7 = 0 to read RAM at cc00, 1 for ROM (writes always to RAM) + b6 = 0 for Apple II video, 1 for 6845 + b5 = 0 for 17.430 MHz 6845 clock, 1 for 28.7595 MHz 6845 clock + b4 = 0 for 512 byte RAM block addressing (VideoTerm emulation), 1 for 256-byte RAM page addressing + b3-b0 = page select + C0n3 is control 2: b7 = 0 for attributes software controllable, 1 for DIP switches control attributes + b5 = 0 for normal video if bit 7 set, 1 for inverse if bit 7 set + b4 = 0 for lowlight if bit 7 set, 1 for highlight if bit 7 set + b2 = 0 for high-density character set, 1 for low-density character set + b1 = same as b5 + b0 = same as b4 + + C800-CBFF: ROM page 1 + CC00-CFEF: VRAM window or ROM page 2 + +*********************************************************************/ + +#include "a2ultraterm.h" +#include "includes/apple2.h" + + +/*************************************************************************** + PARAMETERS +***************************************************************************/ + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type A2BUS_ULTRATERM = &device_creator; +const device_type A2BUS_ULTRATERMENH = &device_creator; + +#define ULTRATERM_ROM_REGION "uterm_rom" +#define ULTRATERM_GFX_REGION "uterm_gfx" +#define ULTRATERM_SCREEN_NAME "uterm_screen" +#define ULTRATERM_MC6845_NAME "mc6845_uterm" + +#define CLOCK_LOW 17430000 +#define CLOCK_HIGH 28759500 + +#define CT1_MEMSEL (0x80) // 0 for read RAM at cc00, 1 for read ROM +#define CT1_VIDSEL (0x40) // 0 for Apple video passthrough, 1 for 6845 video +#define CT1_CLKSEL (0x20) // 0 for Videoterm clock, 1 for faster clock +#define CT1_VTEMU (0x10) // Videoterm emulation mode if 0 +#define CT1_PAGEMASK (0x0f) + +#define CT2_USEDIPS (0x80) // 0 to use the rest of ctrl2's bits, 1 to use DIPs +#define CT2_INVBIT7H (0x20) +#define CT2_HLBIT7H (0x10) +#define CT2_HIDENSITY (0x04) +#define CT2_INVBIT7L (0x02) +#define CT2_HLBIT7L (0x01) + +static MC6845_UPDATE_ROW( ultraterm_update_row ); + +static MC6845_INTERFACE( mc6845_mda_intf ) +{ + false, /* show border area */ + 0,0,0,0, /* visarea adjustment */ + 8, /* number of pixels per video memory address */ + NULL, /* begin_update */ + ultraterm_update_row, /* update_row */ + NULL, /* end_update */ + DEVCB_NULL, /* on_de_changed */ + DEVCB_NULL, /* on_cur_changed */ + DEVCB_NULL, /* on hsync changed */ + DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, a2bus_videx160_device, vsync_changed), /* on_vsync_changed */ + NULL +}; + +static const rgb_t ultraterm_palette[4] = +{ + MAKE_RGB(0x00,0x00,0x00), + MAKE_RGB(0x55,0x55,0x55), + MAKE_RGB(0xaa,0xaa,0xaa), + MAKE_RGB(0xff,0xff,0xff) +}; + +MACHINE_CONFIG_FRAGMENT( a2ultraterm ) + MCFG_SCREEN_ADD( ULTRATERM_SCREEN_NAME, RASTER) + MCFG_SCREEN_RAW_PARAMS(CLOCK_LOW, 882, 0, 720, 370, 0, 350 ) + MCFG_SCREEN_UPDATE_DEVICE( ULTRATERM_MC6845_NAME, mc6845_device, screen_update ) + + MCFG_MC6845_ADD( ULTRATERM_MC6845_NAME, MC6845, ULTRATERM_SCREEN_NAME, CLOCK_LOW/9, mc6845_mda_intf) +MACHINE_CONFIG_END + +ROM_START( a2ultraterm ) + ROM_REGION(0x1000, ULTRATERM_ROM_REGION, 0) + ROM_LOAD( "frm_b537.bin", 0x000000, 0x001000, CRC(1e85a93e) SHA1(b4acd1775c08ae43996ab4edf6d8e28f4736346b) ) + + ROM_REGION(0x1000, ULTRATERM_GFX_REGION, 0) + ROM_LOAD( "chs_7859.bin", 0x000000, 0x001000, CRC(ebe8f333) SHA1(3517fa9e7a39573f1cb159b3161d6939dec199ba) ) + + ROM_REGION(0x400, "pal", 0) + ROM_LOAD( "ult_2a313.jed", 0x000000, 0x000305, CRC(dcd51dea) SHA1(0ad0c5e802e48495da27f7bd26ee3ab1c92d74dd) ) +ROM_END + +ROM_START( a2ultratermenh ) + ROM_REGION(0x1000, ULTRATERM_ROM_REGION, 0) + ROM_LOAD( "frm_b5c9.bin", 0x000000, 0x001000, CRC(b71e05e0) SHA1(092e3eda4644d4f465809864a7f023ac7d1d1542) ) + + ROM_REGION(0x1000, ULTRATERM_GFX_REGION, 0) + ROM_LOAD( "chs_5604.bin", 0x000000, 0x001000, CRC(3fb4e90a) SHA1(94ff75199232a9b613585c22f88470f73fb7dd09) ) + + ROM_REGION(0x400, "pal", 0) + ROM_LOAD( "ult_251c.jed", 0x000000, 0x000305, CRC(12fabb0d) SHA1(d4a36837cb98bb65f7ddef7455eb5a7f8e648a82) ) +ROM_END + +/*************************************************************************** + FUNCTION PROTOTYPES +***************************************************************************/ + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor a2bus_videx160_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( a2ultraterm ); +} + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *a2bus_ultraterm_device::device_rom_region() const +{ + return ROM_NAME( a2ultraterm ); +} + +const rom_entry *a2bus_ultratermenh_device::device_rom_region() const +{ + return ROM_NAME( a2ultratermenh ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +a2bus_videx160_device::a2bus_videx160_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_a2bus_card_interface(mconfig, *this), + m_crtc(*this, ULTRATERM_MC6845_NAME) +{ +} + +a2bus_ultraterm_device::a2bus_ultraterm_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + a2bus_videx160_device(mconfig, A2BUS_ULTRATERM, "Videx UltraTerm (original)", tag, owner, clock, "a2ulttrm", __FILE__) +{ +} + +a2bus_ultratermenh_device::a2bus_ultratermenh_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + a2bus_videx160_device(mconfig, A2BUS_ULTRATERMENH, "Videx UltraTerm (enhanced //e)", tag, owner, clock, "a2ultrme", __FILE__) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void a2bus_videx160_device::device_start() +{ + // set_a2bus_device makes m_slot valid + set_a2bus_device(); + + astring tempstring; + m_rom = device().machine().root_device().memregion(this->subtag(tempstring, ULTRATERM_ROM_REGION))->base(); + + astring tempstring2; + m_chrrom = device().machine().root_device().memregion(this->subtag(tempstring2, ULTRATERM_GFX_REGION))->base(); + + memset(m_ram, 0, 256*16); + + save_item(NAME(m_ram)); + save_item(NAME(m_framecnt)); + save_item(NAME(m_rambank)); + save_item(NAME(m_ctrl1)); + save_item(NAME(m_ctrl2)); +} + +void a2bus_videx160_device::device_reset() +{ + m_rambank = 0; + m_framecnt = 0; +} + + +/*------------------------------------------------- + read_c0nx - called for reads from this card's c0nx space +-------------------------------------------------*/ + +UINT8 a2bus_videx160_device::read_c0nx(address_space &space, UINT8 offset) +{ +// printf("Read c0n%x (PC=%x)\n", offset, space.device().safe_pc()); + + if (!(m_ctrl1 & CT1_VTEMU)) + { + m_rambank = ((offset>>2) & 3) * 512; + } + + switch (offset) + { + case 1: + return m_crtc->register_r(space, offset); // status_r? + + case 2: + return m_ctrl1; + + case 3: + return m_ctrl2; + } + + return 0xff; +} + + +/*------------------------------------------------- + write_c0nx - called for writes to this card's c0nx space +-------------------------------------------------*/ + +void a2bus_videx160_device::write_c0nx(address_space &space, UINT8 offset, UINT8 data) +{ +// printf("Write %02x to c0n%x (PC=%x)\n", data, offset, space.device().safe_pc()); + + switch (offset) + { + case 0: + m_crtc->address_w(space, offset, data); + break; + + case 1: + m_crtc->register_w(space, offset, data); + break; + + case 2: + m_ctrl1 = data; +// printf("%02x to ctrl1\n", data); + + // if disabling Videoterm emulation, change RAM banking + if (data & CT1_VTEMU) + { + m_rambank = (data & CT1_PAGEMASK) * 256; + } + break; + + case 3: + m_ctrl2 = data; +// printf("%02x to ctrl2\n", data); + break; + } + + if (!(m_ctrl1 & CT1_VTEMU)) + { + m_rambank = ((offset >> 2) & 3) * 512; + } +} + +/*------------------------------------------------- + read_cnxx - called for reads from this card's cnxx space +-------------------------------------------------*/ + +UINT8 a2bus_videx160_device::read_cnxx(address_space &space, UINT8 offset) +{ + return m_rom[offset+(m_slot * 0x100)]; +} + +/*------------------------------------------------- + write_cnxx - called for writes to this card's cnxx space + the firmware writes here to switch in our $C800 a lot +-------------------------------------------------*/ +void a2bus_videx160_device::write_cnxx(address_space &space, UINT8 offset, UINT8 data) +{ +} + +/*------------------------------------------------- + read_c800 - called for reads from this card's c800 space +-------------------------------------------------*/ + +UINT8 a2bus_videx160_device::read_c800(address_space &space, UINT16 offset) +{ + // ROM at c800-cbff + // bankswitched RAM at cc00-cdff + if (offset < 0x400) + { +// printf("Read VRAM at %x = %02x\n", offset+m_rambank, m_ram[offset + m_rambank]); + return m_rom[offset + 0x800]; + } + else + { + if (m_ctrl1 & CT1_MEMSEL) // read ROM? + { + return m_rom[offset + 0x800]; + } + + return m_ram[(offset - 0x400) + m_rambank]; + } +} + +/*------------------------------------------------- + write_c800 - called for writes to this card's c800 space +-------------------------------------------------*/ +void a2bus_videx160_device::write_c800(address_space &space, UINT16 offset, UINT8 data) +{ + if (offset >= 0x400) + { +// printf("%02x to VRAM at %x\n", data, offset-0x400+m_rambank); + m_ram[(offset-0x400) + m_rambank] = data; + } +} + +static MC6845_UPDATE_ROW( ultraterm_update_row ) +{ + a2bus_videx160_device *uterm = downcast(device->owner()); + UINT32 *p = &bitmap.pix32(y); + UINT16 chr_base = ra; + int i; + + for ( i = 0; i < x_count; i++ ) + { + UINT16 offset = ( ma + i ); + UINT8 chr = uterm->m_ram[ offset ]; + UINT8 data = uterm->m_chrrom[ chr_base + (chr * 16) ]; + UINT8 fg = 2; + UINT8 bg = 0; + UINT8 tmp; + + // apply attributes + if (!(uterm->m_ctrl2 & CT2_USEDIPS)) + { + // this set and bit 7 in char, highlight + if ((uterm->m_ctrl2 & CT2_HLBIT7H) && (chr & 0x80)) + { + fg = 3; + bg = 0; + } + + // this set and NOT bit 7 in char, highlight + if ((uterm->m_ctrl2 & CT2_HLBIT7L) && (!(chr & 0x80))) + { + fg = 3; + bg = 0; + } + + // this clear and bit 7 in char, lowlight + if (!(uterm->m_ctrl2 & CT2_HLBIT7H) && (chr & 0x80)) + { + fg = 1; + bg = 0; + } + + // this clear and NOT bit 7 in char, lowlight + if (!(uterm->m_ctrl2 & CT2_HLBIT7L) && (!(chr & 0x80))) + { + fg = 1; + bg = 0; + } + + // invert last so invert + hilight/invert + lowlight are possible + // invert if char bit 7 is set + if ((uterm->m_ctrl2 & CT2_INVBIT7H) && (chr & 0x80)) + { + tmp = fg; + fg = bg; + bg = tmp; + } + + // invert if char bit 7 is clear + if ((uterm->m_ctrl2 & CT2_INVBIT7L) && (!(chr & 0x80))) + { + tmp = fg; + fg = bg; + bg = tmp; + } + } + + if ( i == cursor_x ) + { + if ( uterm->m_framecnt & 0x08 ) + { + data = 0xFF; + } + } + + *p = ultraterm_palette[( data & 0x80 ) ? fg : bg]; p++; + *p = ultraterm_palette[( data & 0x40 ) ? fg : bg]; p++; + *p = ultraterm_palette[( data & 0x20 ) ? fg : bg]; p++; + *p = ultraterm_palette[( data & 0x10 ) ? fg : bg]; p++; + *p = ultraterm_palette[( data & 0x08 ) ? fg : bg]; p++; + *p = ultraterm_palette[( data & 0x04 ) ? fg : bg]; p++; + *p = ultraterm_palette[( data & 0x02 ) ? fg : bg]; p++; + *p = ultraterm_palette[( data & 0x01 ) ? fg : bg]; p++; + } +} + +WRITE_LINE_MEMBER( a2bus_videx160_device::vsync_changed ) +{ + if ( state ) + { + m_framecnt++; + } +} diff --git a/src/emu/bus/a2bus/a2ultraterm.h b/src/emu/bus/a2bus/a2ultraterm.h new file mode 100644 index 00000000000..4d6225f160a --- /dev/null +++ b/src/emu/bus/a2bus/a2ultraterm.h @@ -0,0 +1,76 @@ +/********************************************************************* + + a2ultraterm.h + + Implementation of the Videx UltraTerm 80/132/160-column video card + +*********************************************************************/ + +#ifndef __A2BUS_ULTRATERM__ +#define __A2BUS_ULTRATERM__ + +#include "emu.h" +#include "a2bus.h" +#include "video/mc6845.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class a2bus_videx160_device: + public device_t, + public device_a2bus_card_interface +{ +public: + // construction/destruction + a2bus_videx160_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); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + + DECLARE_WRITE_LINE_MEMBER(vsync_changed); + + UINT8 *m_rom, *m_chrrom; + UINT8 m_ram[256*16]; + int m_framecnt; + UINT8 m_ctrl1, m_ctrl2; + +protected: + virtual void device_start(); + virtual void device_reset(); + + // overrides of standard a2bus slot functions + virtual UINT8 read_c0nx(address_space &space, UINT8 offset); + virtual void write_c0nx(address_space &space, UINT8 offset, UINT8 data); + virtual UINT8 read_cnxx(address_space &space, UINT8 offset); + virtual void write_cnxx(address_space &space, UINT8 offset, UINT8 data); + virtual UINT8 read_c800(address_space &space, UINT16 offset); + virtual void write_c800(address_space &space, UINT16 offset, UINT8 data); + + required_device m_crtc; + +private: + int m_rambank; +}; + +class a2bus_ultraterm_device : public a2bus_videx160_device +{ +public: + a2bus_ultraterm_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual const rom_entry *device_rom_region() const; +}; + +class a2bus_ultratermenh_device : public a2bus_videx160_device +{ +public: + a2bus_ultratermenh_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual const rom_entry *device_rom_region() const; +}; + +// device type definition +extern const device_type A2BUS_ULTRATERM; +extern const device_type A2BUS_ULTRATERMENH; + +#endif /* __A2BUS_ULTRATERM__ */ diff --git a/src/emu/bus/bus.mak b/src/emu/bus/bus.mak index c420e5f957a..ef4e2f0b480 100644 --- a/src/emu/bus/bus.mak +++ b/src/emu/bus/bus.mak @@ -534,6 +534,7 @@ BUSOBJS += $(BUSOBJ)/a2bus/a2vulcan.o BUSOBJS += $(BUSOBJ)/a2bus/a2zipdrive.o BUSOBJS += $(BUSOBJ)/a2bus/a2applicard.o BUSOBJS += $(BUSOBJ)/a2bus/a2hsscsi.o +BUSOBJS += $(BUSOBJ)/a2bus/a2ultraterm.o BUSOBJS += $(BUSOBJ)/a2bus/a2estd80col.o BUSOBJS += $(BUSOBJ)/a2bus/a2eext80col.o BUSOBJS += $(BUSOBJ)/a2bus/a2eramworks3.o diff --git a/src/mess/drivers/apple2.c b/src/mess/drivers/apple2.c index 22cc1fbf584..d2cdc6d5ab7 100644 --- a/src/mess/drivers/apple2.c +++ b/src/mess/drivers/apple2.c @@ -214,6 +214,7 @@ Apple 3.5 and Apple 5.25 drives - up to three devices #include "bus/a2bus/a2midi.h" #include "bus/a2bus/a2zipdrive.h" #include "bus/a2bus/a2applicard.h" +#include "bus/a2bus/a2ultraterm.h" #include "bus/a2bus/a2estd80col.h" #include "bus/a2bus/a2eext80col.h" #include "bus/a2bus/a2eramworks3.h" @@ -641,6 +642,8 @@ static SLOT_INTERFACE_START(apple2_cards) SLOT_INTERFACE("scsi", A2BUS_SCSI) /* Apple II SCSI Card */ SLOT_INTERFACE("applicard", A2BUS_APPLICARD) /* PCPI Applicard */ SLOT_INTERFACE("aesms", A2BUS_AESMS) /* Applied Engineering Super Music Synthesizer */ + SLOT_INTERFACE("ultraterm", A2BUS_ULTRATERM) /* Videx UltraTerm (original) */ + SLOT_INTERFACE("ultratermenh", A2BUS_ULTRATERMENH) /* Videx UltraTerm (enhanced //e) */ SLOT_INTERFACE_END static SLOT_INTERFACE_START(apple2eaux_cards)