From caa26040c7427a3708a03214205f55c2ccecbf27 Mon Sep 17 00:00:00 2001 From: Dirk Best Date: Sat, 27 Jun 2015 19:44:50 +0200 Subject: [PATCH] rc759: wip. initial version of the intel 82730 text coprocessor, and added more meat to the driver. currently dies testing the cassette. --- scripts/src/video.lua | 12 + scripts/target/mame/mess.lua | 1 + src/emu/video/i82730.c | 527 +++++++++++++++++++++++++++++++++++ src/emu/video/i82730.h | 157 +++++++++++ src/mess/drivers/rc759.c | 377 +++++++++++++++++++++---- 5 files changed, 1023 insertions(+), 51 deletions(-) create mode 100644 src/emu/video/i82730.c create mode 100644 src/emu/video/i82730.h diff --git a/scripts/src/video.lua b/scripts/src/video.lua index e94884a51a3..e37fda6dd5a 100644 --- a/scripts/src/video.lua +++ b/scripts/src/video.lua @@ -368,6 +368,18 @@ if (VIDEOS["I8244"]~=null) then } end +-------------------------------------------------- +-- +--@src/emu/video/i82730.h,VIDEOS["I82730"] = true +-------------------------------------------------- + +if (VIDEOS["I82730"]~=null) then + files { + MAME_DIR .. "src/emu/video/i82730.c", + MAME_DIR .. "src/emu/video/i82730.h", + } +end + -------------------------------------------------- -- --@src/emu/video/i8275.h,VIDEOS["I8275"] = true diff --git a/scripts/target/mame/mess.lua b/scripts/target/mame/mess.lua index a86990f07b7..d75ba606e4c 100644 --- a/scripts/target/mame/mess.lua +++ b/scripts/target/mame/mess.lua @@ -287,6 +287,7 @@ VIDEOS["HUC6261"] = true VIDEOS["HUC6270"] = true VIDEOS["HUC6272"] = true VIDEOS["I8244"] = true +VIDEOS["I82730"] = true VIDEOS["I8275"] = true --VIDEOS+= M50458"] = true --VIDEOS+= MB90082"] = true diff --git a/src/emu/video/i82730.c b/src/emu/video/i82730.c new file mode 100644 index 00000000000..5bcc3240a35 --- /dev/null +++ b/src/emu/video/i82730.c @@ -0,0 +1,527 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/*************************************************************************** + + Intel 82730 + + Text Coprocessor + +***************************************************************************/ + +#include "i82730.h" + + +//************************************************************************** +// CONSTANTS +//************************************************************************** + +#define VERBOSE 1 +#define VERBOSE_COMMANDS 1 +#define VERBOSE_DATASTREAM 0 + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type I82730 = &device_creator; + +const char *i82730_device::m_command_names[] = +{ + /* 00 */ "NOP", + /* 01 */ "START DISPLAY", + /* 02 */ "START VIRTUAL DISPLAY", + /* 03 */ "STOP DISPLAY", + /* 04 */ "MODE SET", + /* 05 */ "LOAD CBP", + /* 06 */ "LOAD INTMASK", + /* 07 */ "LPEN ENABLE", + /* 08 */ "READ STATUS", + /* 09 */ "LD CUR POS", + /* 0a */ "SELF TEST", + /* 0b */ "TEST ROW BUFFER" +}; + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// i82730_device - constructor +//------------------------------------------------- + +i82730_device::i82730_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, I82730, "I82730", tag, owner, clock, "i82730", __FILE__), + device_video_interface(mconfig, *this), + m_sint_handler(*this), + m_cpu_tag(NULL), m_program(NULL), + m_row_timer(NULL), + m_initialized(false), m_mode_set(false), + m_ca(0), + m_sysbus(0x00), m_ibp(0x0000), m_cbp(0x0000), m_intmask(0xffff), m_status(0x0000), + m_list_switch(0), m_auto_line_feed(0), m_max_dma_count(0), + m_lptr(0), m_sptr(0), + m_dma_burst_space(0), m_dma_burst_length(0), + m_hfldstrt(0), m_margin(0), m_lpr(0), m_field_attribute_mask(0), m_vsyncstp(0), m_vfldstrt(0), m_vfldstp(0), + m_frame_int_count(0), + m_row_index(0) +{ +} + +//------------------------------------------------- +// set_cpu_tag - set cpu we are attached to +//------------------------------------------------- + +void i82730_device::set_cpu_tag(device_t &device, device_t *owner, const char *tag) +{ + i82730_device &dev = dynamic_cast(device); + dev.m_cpu_tag = tag; +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void i82730_device::device_start() +{ + // register bitmap + m_screen->register_screen_bitmap(m_bitmap); + + // resolve callbacks + m_sint_handler.resolve_safe(); + + // bind delegates + m_update_row_cb.bind_relative_to(*owner()); + + // allocate row timer + m_row_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(i82730_device::row_update), this)); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void i82730_device::device_reset() +{ + cpu_device *cpu = m_owner->subdevice(m_cpu_tag); + m_program = &cpu->space(AS_PROGRAM); + + m_initialized = false; + m_mode_set = false; + + m_ca = 0; + m_status = 0x0000; +} + + +//************************************************************************** +// MEMORY ACCESS +//************************************************************************** + +UINT8 i82730_device::read_byte(offs_t address) +{ + return m_program->read_byte(address); +} + +UINT16 i82730_device::read_word(offs_t address) +{ + UINT16 data = 0xffff; + + if (sysbus_16bit() && !(address & 1)) + { + data = m_program->read_word(address); + } + else + { + data = m_program->read_byte(address); + data |= m_program->read_byte(address + 1) << 8; + } + + return data; +} + +void i82730_device::write_byte(offs_t address, UINT8 data) +{ + m_program->write_byte(address, data); +} + +void i82730_device::write_word(offs_t address, UINT16 data) +{ + if (sysbus_16bit() && !(address & 1)) + { + m_program->write_word(address, data); + } + else + { + m_program->write_byte(address, data & 0xff); + m_program->write_byte(address + 1, (data >> 8) & 0xff); + } +} + + +//************************************************************************** +// IMPLEMENTATION +//************************************************************************** + +void i82730_device::update_interrupts() +{ + UINT16 code = m_status & ~m_intmask & ~(VDIP | DIP); + write_word(m_cbp + 20, code); + + if (code) + m_sint_handler(1); +} + +void i82730_device::mode_set() +{ + UINT32 mptr = (read_word(m_cbp + 32) << 16) | read_word(m_cbp + 30); + UINT16 tmp; + + tmp = read_word(mptr); + m_dma_burst_space = tmp & 0x7f; + m_dma_burst_length = (tmp >> 8) & 0x7f; + + tmp = read_word(mptr + 2); + UINT8 hsyncstp = tmp & 0xff; + UINT8 line_length = (tmp >> 8) & 0xff; + + tmp = read_word(mptr + 4); + UINT8 hfldstp = tmp & 0xff; + m_hfldstrt = (tmp >> 8) & 0xff; + + tmp = read_word(mptr + 6); + UINT8 hbrdstp = tmp & 0xff; + UINT8 hbrdstrt = (tmp >> 8) & 0xff; + + tmp = read_word(mptr + 8); + m_margin = tmp & 0x1f; + + tmp = read_word(mptr + 10); + m_lpr = tmp & 0x1f; + + tmp = read_word(mptr + 24); + m_field_attribute_mask = tmp & 0x7fff; + + tmp = read_word(mptr + 26); + UINT16 frame_length = tmp & 0x7ff; + + tmp = read_word(mptr + 28); + m_vsyncstp = tmp & 0x7ff; + + tmp = read_word(mptr + 30); + m_vfldstrt = tmp & 0x7ff; + + tmp = read_word(mptr + 32); + m_vfldstp = tmp & 0x7ff; + + tmp = read_word(mptr + 38); + m_frame_int_count = tmp & 0x0f; + + // setup screen mode + rectangle visarea(hbrdstrt * 16, hbrdstp * 16 - 1, m_vsyncstp, m_vfldstp + m_margin + 1 + m_lpr - 1); + attoseconds_t period = HZ_TO_ATTOSECONDS(clock() * 16) * line_length * 16 * frame_length; + m_screen->configure(line_length * 16, frame_length, visarea, period); + + // start display is now valid + m_mode_set = true; + + // adjust timer for the new mode + m_row_timer->adjust(m_screen->time_until_pos(0)); + + // output some debug info + if (VERBOSE) + { + logerror("%s('%s'): ---- setting mode ----\n", shortname(), basetag()); + logerror("%s('%s'): dma burst length %02x, space %02x\n", shortname(), basetag(), m_dma_burst_length, m_dma_burst_space); + logerror("%s('%s'): margin %02x, lpr %02x\n", shortname(), basetag(), m_margin, m_lpr); + logerror("%s('%s'): hsyncstp: %02x, line_length: %02x, hfldstrt: %02x, hbrdstart: %02x, hfldstop: %02x, hbrdstop: %02x\n", + shortname(), basetag(), hsyncstp, line_length, m_hfldstrt, hbrdstrt, hfldstp, hbrdstp); + logerror("%s('%s'): frame_length %04x, vsyncstp: %04x, vfldstrt: %04x, vfldstp: %04x\n", + shortname(), basetag(), frame_length, m_vsyncstp, m_vfldstrt, m_vfldstp); + } +} + +void i82730_device::execute_command() +{ + UINT8 command = read_byte(m_cbp + 1); + UINT16 tmp; + + if (VERBOSE_COMMANDS && command < ARRAY_LENGTH(m_command_names)) + logerror("%s('%s'): executing command: %s [cbp = %08x]\n", shortname(), basetag(), m_command_names[command], m_cbp); + + tmp = read_word(m_cbp + 2); + m_list_switch = BIT(tmp, 6); + m_auto_line_feed = BIT(tmp, 7); + + tmp = read_word(m_cbp + 4); + m_max_dma_count = tmp & 0xff; + + switch (command) + { + // NOP + case 0x00: + break; + + // START DISPLAY + case 0x01: + if (m_mode_set) + m_status = (m_status & ~VDIP) | DIP; + break; + + // START VIRTUAL DISPLAY + case 0x02: + if (m_mode_set) + m_status = VDIP | (m_status & ~DIP); + break; + + // STOP DISPLAY + case 0x03: + m_status &= ~(VDIP | DIP); + break; + + // MODE SET + case 0x04: + mode_set(); + break; + + // LOAD CBP + case 0x05: + m_cbp = (read_word(m_cbp + 16) << 16) | read_word(m_cbp + 14); + execute_command(); + break; + + // LOAD INTMASK + case 0x06: + m_intmask = read_word(m_cbp + 22); + if (VERBOSE_COMMANDS) + logerror("%s('%s'): intmask now %04x\n", shortname(), basetag(), m_intmask); + break; + + // LPEN ENABLE + case 0x07: + fatalerror("%s('%s'): Unimplemented command %s\n", shortname(), basetag(), m_command_names[command]); + break; + + // READ STATUS + case 0x08: + write_word(m_cbp + 18, m_status); + m_status &= (VDIP | DIP); + break; + + // LD CUR POS + case 0x09: + fatalerror("%s('%s'): Unimplemented command %s\n", shortname(), basetag(), m_command_names[command]); + break; + + // SELF TEST + case 0x0a: + fatalerror("%s('%s'): Unimplemented command %s\n", shortname(), basetag(), m_command_names[command]); + break; + + // TEST ROW BUFFER + case 0x0b: + fatalerror("%s('%s'): Unimplemented command %s\n", shortname(), basetag(), m_command_names[command]); + break; + + default: + if (VERBOSE_COMMANDS) + logerror("%s('%s'): executing command: (reserved) [cbp = %08x]\n", shortname(), basetag(), m_cbp); + m_status |= RCC; + update_interrupts(); + break; + } + + // clear busy + write_word(m_cbp, read_word(m_cbp) & 0xff00); +} + +void i82730_device::load_row() +{ + bool finished = false; + + m_row[m_row_index].count = 0; + + while (!finished) + { + UINT16 data = read_word(m_sptr); + m_sptr += 2; + + if (BIT(data, 15)) + { + switch (data >> 8) + { + case 0x8e: + m_field_attribute_mask = read_word(m_sptr) & 0x7fff; + m_sptr += 2; + + if (VERBOSE_DATASTREAM) + logerror("%s('%s'): SET FIELD ATTRIB to %04x\n", shortname(), basetag(), m_field_attribute_mask); + + break; + + default: + fatalerror("%s('%s'): Unimplemented datastream command %02x\n", shortname(), basetag(), data >> 8); + } + } + else + { + // maximum row size is 200 + if (m_row[m_row_index].count < m_max_dma_count && m_row[m_row_index].count < 200) + { + m_row[m_row_index].data[m_row[m_row_index].count++] = data; + } + else + { +#if 0 + // move to next string? + if (m_auto_line_feed == 0) + { + m_sptr = (read_word(m_lptr + 2) << 16) | read_word(m_lptr); + m_lptr += 4; + } +#endif + finished = true; + } + } + } + + m_sptr -= 2; +} + +TIMER_CALLBACK_MEMBER( i82730_device::row_update ) +{ + int y = m_screen->vpos(); + + if (y == 0) + { + // clear interrupt status flags + m_status &= (VDIP | DIP); + + // clear field attribute mask + m_field_attribute_mask = 0; + + // get listbase + if (m_list_switch) + m_lptr = (read_word(m_cbp + 8) << 16) | read_word(m_cbp + 6); + else + m_lptr = (read_word(m_cbp + 12) << 16) | read_word(m_cbp + 10); + + m_sptr = (read_word(m_lptr + 2) << 16) | read_word(m_lptr); + m_lptr += 4; + + // fetch initial row + m_row_index = 0; + load_row(); + } + else if (y >= m_vsyncstp && y < m_vfldstrt) + { + // blank (top border) + } + else if (y >= m_vfldstrt && y < m_vfldstp) + { + UINT8 lc = (y - m_vfldstrt) % (m_lpr + 1); + + // call driver + m_update_row_cb(m_bitmap, m_row[m_row_index].data, lc, y - m_vsyncstp, m_row[m_row_index].count); + + // swap buffers at end of row + if (lc == m_lpr) + { + m_row_index ^= 1; + load_row(); + } + } + else if (y >= m_vfldstp && y < m_vfldstp + m_margin + 1) + { + // margin + } + else if (y >= m_vfldstp + m_margin + 1 && y < m_vfldstp + m_margin + 1 + m_lpr + 1) + { + UINT8 lc = (y - (m_vfldstp + m_margin + 1)) % (m_lpr + 1); + + m_sptr = (read_word(m_cbp + 36) << 16) | read_word(m_cbp + 34); + load_row(); + + // call driver + m_update_row_cb(m_bitmap, m_row[m_row_index].data, lc, y - m_vsyncstp, m_row[m_row_index].count); + } + else if (y == m_vfldstp + m_margin + 1 + m_lpr + 1) + { + // todo: check ca + + // frame interrupt? + if ((m_screen->frame_number() % m_frame_int_count) == 0) + m_status |= EONF; + + // check interrupts + update_interrupts(); + } + else + { + // vblank + } + + m_row_timer->adjust(m_screen->time_until_pos((y + 1) % m_screen->height())); +} + +WRITE_LINE_MEMBER( i82730_device::ca_w ) +{ + if (VERBOSE) + logerror("%s('%s'): ca_w %d\n", shortname(), basetag(), state); + + // falling edge + if (m_ca == 1 && state == 0) + { + if (!m_initialized) + { + // get system bus width + m_sysbus = m_program->read_byte(0xfffffff6); + + // get intermediate block pointer + m_ibp = (read_word(0xfffffffe) << 16) | read_word(0xfffffffc); + + // get system configuration byte + UINT8 scb = read_byte(m_ibp + 6); + + // clear busy + write_word(m_ibp, read_word(m_ibp) & 0xff00); + + // done + m_initialized = true; + + // output some debug info + if (VERBOSE) + { + logerror("%s('%s'): ---- initializing ----\n", shortname(), basetag()); + logerror("%s('%s'): %s system bus\n", shortname(), basetag(), sysbus_16bit() ? "16-bit" : "8-bit"); + logerror("%s('%s'): intermediate block pointer: %08x\n", shortname(), basetag(), m_ibp); + logerror("%s('%s'): addrbus: %s, clno: %d, clpos: %d, mode: %s, dtw16: %s, srdy: %s\n", shortname(), basetag(), + BIT(scb, 0) ? "32-bit" : "16-bit", (scb >> 1) & 0x03, (scb >> 3) & 0x03, + BIT(scb, 5) ? "master" : "slave", BIT(scb, 6) ? "16-bit" : "8-bit", BIT(scb, 7) ? "synchronous" : "asynchronous"); + } + } + + // fetch command block pointer + m_cbp = (read_word(m_ibp + 4) << 16) | read_word(m_ibp + 2); + + // and execute command + execute_command(); + } + + m_ca = state; +} + +WRITE_LINE_MEMBER( i82730_device::irst_w ) +{ + if (VERBOSE) + logerror("%s('%s'): irst_w %d\n", shortname(), basetag(), state); + + m_sint_handler(0); +} + +UINT32 i82730_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + copybitmap(bitmap, m_bitmap, 0, 0, m_hfldstrt * 16, 0, cliprect); + return 0; +} diff --git a/src/emu/video/i82730.h b/src/emu/video/i82730.h new file mode 100644 index 00000000000..5df4e46a5de --- /dev/null +++ b/src/emu/video/i82730.h @@ -0,0 +1,157 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/*************************************************************************** + + Intel 82730 + + Text Coprocessor + +***************************************************************************/ + +#pragma once + +#ifndef __I82730_H__ +#define __I82730_H__ + +#include "emu.h" + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_I82730_ADD(_tag, _cpu_tag, _clock) \ + MCFG_DEVICE_ADD(_tag, I82730, _clock) \ + i82730_device::set_cpu_tag(*device, owner, _cpu_tag); + +#define MCFG_I82730_SINT_HANDLER(_devcb) \ + devcb = &i82730_device::set_sint_handler(*device, DEVCB_##_devcb); + +#define MCFG_I82730_UPDATE_ROW_CB(_class, _method) \ + i82730_device::set_update_row_callback(*device, i82730_update_row_delegate(&_class::_method, #_class "::" #_method, downcast<_class *>(owner))); + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +typedef device_delegate i82730_update_row_delegate; + +#define I82730_UPDATE_ROW(name) \ + void name(bitmap_rgb32 &bitmap, UINT16 *data, UINT8 lc, UINT16 y, int x_count) + + +// ======================> i82730_device + +class i82730_device : public device_t, public device_video_interface +{ +public: + // construction/destruction + i82730_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // callbacks + template static devcb_base &set_sint_handler(device_t &device, _Object object) + { return downcast(device).m_sint_handler.set_callback(object); } + + // inline configuration + static void set_cpu_tag(device_t &device, device_t *owner, const char *tag); + static void set_update_row_callback(device_t &device, i82730_update_row_delegate callback) { downcast(device).m_update_row_cb = callback; } + + UINT32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); + + DECLARE_WRITE_LINE_MEMBER(ca_w); + DECLARE_WRITE_LINE_MEMBER(irst_w); + +protected: + virtual void device_start(); + virtual void device_reset(); + +private: + // status + enum + { + DUR = 0x001, // data underrun + LPU = 0x002, // light pen update + DBOR = 0x004, // data buffer overrun + EONF = 0x008, // end of n frames + FDE = 0x010, // frame data error + RCC = 0x020, // reserved channel command executed + RDC = 0x040, // reserved data stream command executed + DIP = 0x080, // display in progress + VDIP = 0x100 // virtual display in progress + }; + + static const char* m_command_names[]; + + bool sysbus_16bit() { return BIT(m_sysbus, 0); } + + UINT8 read_byte(offs_t address); + UINT16 read_word(offs_t address); + void write_byte(offs_t address, UINT8 data); + void write_word(offs_t address, UINT16 data); + + void update_interrupts(); + void mode_set(); + void execute_command(); + void load_row(); + + TIMER_CALLBACK_MEMBER(row_update); + + devcb_write_line m_sint_handler; + i82730_update_row_delegate m_update_row_cb; + + const char *m_cpu_tag; + address_space *m_program; + + emu_timer *m_row_timer; + + bitmap_rgb32 m_bitmap; + + bool m_initialized; + bool m_mode_set; + + int m_ca; + + // internal registers + UINT8 m_sysbus; + UINT32 m_ibp; + UINT32 m_cbp; + UINT16 m_intmask; + UINT16 m_status; + + int m_list_switch; + int m_auto_line_feed; + UINT8 m_max_dma_count; + + UINT32 m_lptr; + UINT32 m_sptr; + + int m_dma_burst_space; + int m_dma_burst_length; + + // display parameters + int m_hfldstrt; + int m_margin; + int m_lpr; + UINT16 m_field_attribute_mask; + int m_vsyncstp; + int m_vfldstrt; + int m_vfldstp; + + int m_frame_int_count; + + // row buffers + struct row_buffer + { + UINT16 data[200]; + int count; + }; + + row_buffer m_row[2]; + int m_row_index; +}; + +// device type definition +extern const device_type I82730; + +#endif // __I82730_H__ diff --git a/src/mess/drivers/rc759.c b/src/mess/drivers/rc759.c index cfe48a89093..175ea21037c 100644 --- a/src/mess/drivers/rc759.c +++ b/src/mess/drivers/rc759.c @@ -2,14 +2,9 @@ // copyright-holders:Dirk Best /*************************************************************************** - Regnecentralen RC759 + Regnecentralen RC759 Piccoline - TODO: - - Emulate the Intel 82730 CRT controller and figure out the rest - - Connect iSBX bus - - (much later) move floppy/external printer to the slot interface - - Status: Hangs waiting for an answer from the 82730 + Status: Error 32 (cassette data error) ***************************************************************************/ @@ -17,10 +12,17 @@ #include "cpu/i86/i186.h" #include "machine/ram.h" #include "machine/nvram.h" +#include "machine/mm58167.h" #include "machine/pic8259.h" #include "machine/i8255.h" +#include "video/i82730.h" +#include "sound/speaker.h" +#include "sound/sn76496.h" +#include "machine/keyboard.h" +#include "bus/centronics/ctronics.h" #include "machine/wd_fdc.h" #include "imagedev/cassette.h" +#include "bus/isbx/isbx.h" //************************************************************************** @@ -34,19 +36,31 @@ public: driver_device(mconfig, type, tag), m_maincpu(*this, "maincpu"), m_pic(*this, "pic"), + m_nvram(*this, "nvram"), m_ppi(*this, "ppi"), + m_txt(*this, "txt"), m_cas(*this, "cas"), + m_isbx(*this, "isbx"), + m_speaker(*this, "speaker"), + m_snd(*this, "snd"), + m_rtc(*this, "rtc"), + m_centronics(*this, "centronics"), m_fdc(*this, "fdc"), m_floppy0(*this, "fdc:0"), m_floppy1(*this, "fdc:1"), m_vram(*this, "vram"), - m_cas_enabled(0), + m_config(*this, "config"), + m_cas_enabled(0), m_cas_data(0), m_drq_source(0), m_nvram_bank(0), m_gfx_mode(0), - m_keyboard_enable(0) + m_keyboard_enable(0), m_keyboard_key(0x00), + m_centronics_strobe(0), m_centronics_init(0), m_centronics_select_in(0), m_centronics_busy(0), + m_centronics_ack(0), m_centronics_fault(0), m_centronics_perror(0), m_centronics_select(0), + m_centronics_data(0xff) { } + DECLARE_WRITE8_MEMBER(keyb_put); DECLARE_READ8_MEMBER(keyboard_r); DECLARE_WRITE8_MEMBER(floppy_control_w); @@ -58,9 +72,27 @@ public: DECLARE_READ8_MEMBER(ppi_portb_r); DECLARE_WRITE8_MEMBER(ppi_portc_w); + DECLARE_WRITE_LINE_MEMBER(centronics_busy_w); + DECLARE_WRITE_LINE_MEMBER(centronics_ack_w); + DECLARE_WRITE_LINE_MEMBER(centronics_fault_w); + DECLARE_WRITE_LINE_MEMBER(centronics_perror_w); + DECLARE_WRITE_LINE_MEMBER(centronics_select_w); + + DECLARE_READ8_MEMBER(centronics_data_r); + DECLARE_WRITE8_MEMBER(centronics_data_w); + DECLARE_READ8_MEMBER(centronics_control_r); + DECLARE_WRITE8_MEMBER(centronics_control_w); + + I82730_UPDATE_ROW(txt_update_row); + DECLARE_WRITE16_MEMBER(txt_ca_w); + DECLARE_WRITE16_MEMBER(txt_irst_w); DECLARE_READ8_MEMBER(palette_r); DECLARE_WRITE8_MEMBER(palette_w); + DECLARE_WRITE_LINE_MEMBER(i186_timer0_w); + DECLARE_WRITE_LINE_MEMBER(i186_timer1_w); + + void nvram_init(nvram_device &nvram, void *data, size_t size); DECLARE_READ8_MEMBER(nvram_r); DECLARE_WRITE8_MEMBER(nvram_w); DECLARE_READ8_MEMBER(rtc_r); @@ -75,18 +107,40 @@ protected: private: required_device m_maincpu; required_device m_pic; + required_device m_nvram; required_device m_ppi; + required_device m_txt; required_device m_cas; + required_device m_isbx; + required_device m_speaker; + required_device m_snd; + required_device m_rtc; + required_device m_centronics; required_device m_fdc; required_device m_floppy0; required_device m_floppy1; required_shared_ptr m_vram; + required_ioport m_config; + + std::vector m_nvram_mem; int m_cas_enabled; + int m_cas_data; int m_drq_source; int m_nvram_bank; int m_gfx_mode; int m_keyboard_enable; + UINT8 m_keyboard_key; + + int m_centronics_strobe; + int m_centronics_init; + int m_centronics_select_in; + int m_centronics_busy; + int m_centronics_ack; + int m_centronics_fault; + int m_centronics_perror; + int m_centronics_select; + UINT8 m_centronics_data; }; @@ -94,24 +148,35 @@ private: // I/O //************************************************************************** -// pic ir1 keyboard +WRITE8_MEMBER( rc759_state::keyb_put ) +{ + m_keyboard_key = data; + m_pic->ir1_w(1); +} + READ8_MEMBER( rc759_state::keyboard_r ) { logerror("keyboard_r\n"); - return 0xff; + + m_pic->ir1_w(0); + + if (m_keyboard_enable) + return m_keyboard_key; + else + return 0x00; } READ8_MEMBER( rc759_state::ppi_porta_r ) { UINT8 data = 0; - data |= m_cas->input() > 0 ? 1 : 0; - data |= 1 << 1; // 0 = isbx module installed - data |= 0 << 2; // option0 from isbx - data |= 0 << 3; // option1 from isbx + data |= m_cas_enabled ? m_cas_data : (m_cas->input() > 0 ? 1 : 0); + data |= m_isbx->mpst_r() << 1; + data |= m_isbx->opt0_r() << 2; + data |= m_isbx->opt1_r() << 3; data |= 1 << 4; // mem ident0 data |= 1 << 5; // mem ident1 (both 1 = 256k installed) - data |= 0 << 6; // dpc connect (0 = external floppy/printer installed) + data |= 1 << 6; // dpc connect (0 = external floppy/printer installed) data |= 1 << 7; // not used return data; @@ -122,27 +187,102 @@ READ8_MEMBER( rc759_state::ppi_portb_r ) UINT8 data = 0; data |= 1 << 0; // 0 = micronet controller installed - data |= 0 << 1; // rtc type, 0 = cdp1879 - data |= 1 << 2; // sound generator detect + data |= 1 << 1; // rtc type, mm58167/cdp1879 + data |= m_snd->ready_r() << 2; data |= 1 << 3; // not used data |= 1 << 4; // not used - data |= 0 << 5; // 0 = color monitor, 1 = monochrome - data |= 1 << 6; // 0 = 15khz, 1 = 22khz monitor - data |= 1 << 7; // not used + data |= m_config->read(); // monitor type and frequency + data |= 1 << 7; // 0 = enable remote hardware debug (using an isbx351 module) return data; } WRITE8_MEMBER( rc759_state::ppi_portc_w ) { - logerror("ppi_portc_w: %02x\n", data); - m_cas_enabled = BIT(data, 0); m_cas->change_state(BIT(data, 1) ? CASSETTE_MOTOR_DISABLED : CASSETTE_MOTOR_ENABLED, CASSETTE_MASK_MOTOR); m_drq_source = (data >> 2) & 0x03; m_nvram_bank = (data >> 4) & 0x03; m_gfx_mode = BIT(data, 6); m_keyboard_enable = BIT(data, 7); + + logerror("ppi_portc_w: cas_enabled: %d, cas_motor: %d, drq_source: %d, nvram_bank: %d, gfx_mode: %d, keyb_enable: %d\n", + m_cas_enabled, BIT(data, 1), m_drq_source, m_nvram_bank, m_gfx_mode, m_keyboard_enable); +} + +WRITE_LINE_MEMBER( rc759_state::centronics_busy_w ) +{ + m_centronics_busy = state; + m_pic->ir6_w(state); +} + +WRITE_LINE_MEMBER( rc759_state::centronics_ack_w ) +{ + m_centronics_ack = state; +} + +WRITE_LINE_MEMBER( rc759_state::centronics_fault_w ) +{ + m_centronics_fault = state; +} + +WRITE_LINE_MEMBER( rc759_state::centronics_perror_w ) +{ + m_centronics_perror = state; +} + +WRITE_LINE_MEMBER( rc759_state::centronics_select_w ) +{ + m_centronics_select = state; +} + +READ8_MEMBER( rc759_state::centronics_data_r ) +{ + return m_centronics_data; +} + +WRITE8_MEMBER( rc759_state::centronics_data_w ) +{ + m_centronics_data = data; + + m_centronics->write_data0(BIT(data, 0)); + m_centronics->write_data1(BIT(data, 1)); + m_centronics->write_data2(BIT(data, 2)); + m_centronics->write_data3(BIT(data, 3)); + m_centronics->write_data4(BIT(data, 4)); + m_centronics->write_data5(BIT(data, 5)); + m_centronics->write_data6(BIT(data, 6)); + m_centronics->write_data7(BIT(data, 7)); +} + +READ8_MEMBER( rc759_state::centronics_control_r ) +{ + UINT8 data = 0; + + data |= m_centronics_busy << 0; + data |= m_centronics_ack << 1; + data |= m_centronics_fault << 2; + data |= m_centronics_perror << 3; + data |= m_centronics_select << 4; + data |= !m_centronics_strobe << 5; + data |= !m_centronics_init << 6; + data |= !m_centronics_select_in << 7; + + return data; +} + +WRITE8_MEMBER( rc759_state::centronics_control_w ) +{ + logerror("centronics_control_w: %02x\n", data); + + m_centronics_strobe = BIT(data, 0); + m_centronics_init = BIT(data, 2); + m_centronics_select_in = BIT(data, 4); + + m_centronics->write_strobe(m_centronics_strobe); + m_centronics->write_autofd(BIT(data, 1)); + m_centronics->write_init(m_centronics_init); + m_centronics->write_select_in(m_centronics_select_in); } WRITE8_MEMBER( rc759_state::floppy_control_w ) @@ -187,6 +327,41 @@ WRITE8_MEMBER( rc759_state::floppy_release_w ) // VIDEO EMULATION //************************************************************************** +I82730_UPDATE_ROW( rc759_state::txt_update_row ) +{ + for (int i = 0; i < x_count; i++) + { + UINT16 gfx = m_vram[(data[i] & 0x3ff) << 4 | lc]; + + // pretty crude detection if char sizes have been initialized, need something better + if ((gfx & 0xff) == 0) + continue; + + // figure out char width + int width; + for (width = 0; width < 16; width++) + if (BIT(gfx, width) == 0) + break; + + width = 15 - width; + + for (int p = 0; p < width; p++) + bitmap.pix32(y, i * width + p) = BIT(gfx, 15 - p) ? rgb_t::white : rgb_t::black; + } +} + +WRITE16_MEMBER( rc759_state::txt_ca_w ) +{ + m_txt->ca_w(1); + m_txt->ca_w(0); +} + +WRITE16_MEMBER( rc759_state::txt_irst_w ) +{ + m_txt->irst_w(1); + m_txt->irst_w(0); +} + READ8_MEMBER( rc759_state::palette_r ) { logerror("palette_r(%02x)\n", offset); @@ -200,10 +375,9 @@ WRITE8_MEMBER( rc759_state::palette_w ) //************************************************************************** -// MACHINE EMULATION +// SOUND/RTC //************************************************************************** -// pic ir3 rtc READ8_MEMBER( rc759_state::rtc_r ) { logerror("rtc_r(%02x)\n", offset); @@ -215,16 +389,54 @@ WRITE8_MEMBER( rc759_state::rtc_w ) logerror("rtc_w(%02x): %02x\n", offset, data); } -// 256x4 nvram is bank-switched using the ppi port c, bit 4 and 5 + +//************************************************************************** +// MACHINE EMULATION +//************************************************************************** + +WRITE_LINE_MEMBER( rc759_state::i186_timer0_w ) +{ + if (m_cas_enabled) + { + m_cas_data = state; + m_cas->output(state ? -1.0 : 1.0); + } +} + +WRITE_LINE_MEMBER( rc759_state::i186_timer1_w ) +{ + m_speaker->level_w(state); +} + +// 256x4 nvram is bank-switched using ppi port c, bit 4 and 5 +void rc759_state::nvram_init(nvram_device &nvram, void *data, size_t size) +{ + memset(data, 0x00, size); + memset(data, 0xaa, 1); +} + READ8_MEMBER( rc759_state::nvram_r ) { - logerror("nvram_r(%02x)\n", offset); - return 0xff; + offs_t addr = (m_nvram_bank << 6) | offset; + + logerror("nvram_r(%02x)\n", addr); + + if (addr & 1) + return (m_nvram_mem[addr >> 1] & 0xf0) >> 4; + else + return (m_nvram_mem[addr >> 1] & 0x0f) >> 0; } WRITE8_MEMBER( rc759_state::nvram_w ) { - logerror("nvram_w(%02x): %02x\n", offset, data); + offs_t addr = (m_nvram_bank << 6) | offset; + + logerror("nvram_w(%02x): %02x\n", addr, data); + + if (addr & 1) + m_nvram_mem[addr >> 1] = ((data << 4) & 0xf0) | (m_nvram_mem[addr >> 1] & 0x0f); + else + m_nvram_mem[addr >> 1] = (m_nvram_mem[addr >> 1] & 0xf0) | (data & 0x0f); } READ8_MEMBER( rc759_state::irq_callback ) @@ -234,6 +446,8 @@ READ8_MEMBER( rc759_state::irq_callback ) void rc759_state::machine_start() { + m_nvram_mem.resize(256 / 2); + m_nvram->set_base(&m_nvram_mem[0], 256 / 2); } void rc759_state::machine_reset() @@ -253,33 +467,50 @@ ADDRESS_MAP_END static ADDRESS_MAP_START( rc759_io, AS_IO, 16, rc759_state ) ADDRESS_MAP_UNMAP_HIGH - AM_RANGE(0x000, 0x003) AM_DEVREADWRITE8("pic", pic8259_device, read, write, 0x00ff) + AM_RANGE(0x000, 0x003) AM_MIRROR(0x0c) AM_DEVREADWRITE8("pic", pic8259_device, read, write, 0x00ff) AM_RANGE(0x020, 0x021) AM_READ8(keyboard_r, 0x00ff) - AM_RANGE(0x050, 0x05f) AM_READWRITE8(rtc_r, rtc_w, 0x00ff) // and sound -// AM_RANGE(0x060, 0x06f) AM_WRITE8(crt_control_w, 0x00ff) - AM_RANGE(0x070, 0x077) AM_DEVREADWRITE8("ppi", i8255_device, read, write, 0x00ff) + AM_RANGE(0x056, 0x057) AM_NOP // in reality, access to sound and rtc is a bit more involved + AM_RANGE(0x05a, 0x05b) AM_DEVWRITE8("snd", sn76489a_device, write, 0x00ff) + AM_RANGE(0x05c, 0x05d) AM_READWRITE8(rtc_r, rtc_w, 0x00ff) +// AM_RANGE(0x060, 0x06f) AM_WRITE8(crt_control_w, 0x00ff) + AM_RANGE(0x070, 0x077) AM_MIRROR(0x08) AM_DEVREADWRITE8("ppi", i8255_device, read, write, 0x00ff) AM_RANGE(0x080, 0x0ff) AM_READWRITE8(nvram_r, nvram_w, 0x00ff) // AM_RANGE(0x100, 0x101) net AM_RANGE(0x180, 0x1bf) AM_READWRITE8(palette_r, palette_w, 0x00ff) -// AM_RANGE(0x230, 0x231) crt reset -// AM_RANGE(0x240, 0x241) crt ch. att. -// AM_RANGE(0x250, 0x251) local printer data (centronics) -// AM_RANGE(0x260, 0x261) local printer control (centronics) + AM_RANGE(0x230, 0x231) AM_WRITE(txt_irst_w) + AM_RANGE(0x240, 0x241) AM_WRITE(txt_ca_w) + AM_RANGE(0x250, 0x251) AM_READWRITE8(centronics_data_r, centronics_data_w, 0x00ff) + AM_RANGE(0x260, 0x261) AM_READWRITE8(centronics_control_r, centronics_control_w, 0x00ff) AM_RANGE(0x280, 0x287) AM_DEVREADWRITE8("fdc", wd2797_t, read, write, 0x00ff) AM_RANGE(0x288, 0x289) AM_WRITE8(floppy_control_w, 0x00ff) // AM_RANGE(0x28a, 0x28b) external printer data // AM_RANGE(0x28d, 0x28d) external printer control AM_RANGE(0x28e, 0x28f) AM_READWRITE8(floppy_ack_r, floppy_reserve_w, 0x00ff) AM_RANGE(0x290, 0x291) AM_WRITE8(floppy_release_w, 0x00ff) -// AM_RANGE(0x292, 0x293) AM_READWRITE8(printer_ack_r, printer_reserve_w, 0x00ff) -// AM_RANGE(0x294, 0x295) AM_WRITE8(printer_release_w, 0x00ff) -// AM_RANGE(0x300, 0x30f) isbx1 -// AM_RANGE(0x310, 0x31f) isbx2 -// AM_RANGE(0x320, 0x321) isbx dma ack -// AM_RANGE(0x330, 0x331) isbx tc +// AM_RANGE(0x292, 0x293) AM_READWRITE8(printer_ack_r, printer_reserve_w, 0x00ff) +// AM_RANGE(0x294, 0x295) AM_WRITE8(printer_release_w, 0x00ff) + AM_RANGE(0x300, 0x30f) AM_DEVREADWRITE8("isbx", isbx_slot_device, mcs0_r, mcs0_w, 0x00ff) + AM_RANGE(0x310, 0x31f) AM_DEVREADWRITE8("isbx", isbx_slot_device, mcs1_r, mcs1_w, 0x00ff) +// AM_RANGE(0x320, 0x321) isbx dma ack +// AM_RANGE(0x330, 0x331) isbx tc ADDRESS_MAP_END +//************************************************************************** +// INPUTS +//************************************************************************** + +static INPUT_PORTS_START( rc759 ) + PORT_START("config") + PORT_CONFNAME(0x20, 0x00, "Monitor Type") + PORT_CONFSETTING(0x00, "Color") + PORT_CONFSETTING(0x20, "Monochrome") + PORT_CONFNAME(0x40, 0x00, "Monitor Frequency") + PORT_CONFSETTING(0x00, "15 kHz") + PORT_CONFSETTING(0x40, "22 kHz") +INPUT_PORTS_END + + //************************************************************************** // MACHINE DRIVERS //************************************************************************** @@ -293,28 +524,72 @@ static MACHINE_CONFIG_START( rc759, rc759_state ) MCFG_CPU_PROGRAM_MAP(rc759_map) MCFG_CPU_IO_MAP(rc759_io) MCFG_80186_IRQ_SLAVE_ACK(READ8(rc759_state, irq_callback)) + MCFG_80186_TMROUT0_HANDLER(WRITELINE(rc759_state, i186_timer0_w)) + MCFG_80186_TMROUT1_HANDLER(WRITELINE(rc759_state, i186_timer1_w)) // interrupt controller MCFG_PIC8259_ADD("pic", DEVWRITELINE("maincpu", i80186_cpu_device, int0_w), VCC, NULL) + // nvram + MCFG_NVRAM_ADD_CUSTOM_DRIVER("nvram", rc759_state, nvram_init) + // ppi MCFG_DEVICE_ADD("ppi", I8255, 0) MCFG_I8255_IN_PORTA_CB(READ8(rc759_state, ppi_porta_r)) MCFG_I8255_IN_PORTB_CB(READ8(rc759_state, ppi_portb_r)) MCFG_I8255_OUT_PORTC_CB(WRITE8(rc759_state, ppi_portc_w)) - // floppy disk controller - MCFG_WD2797_ADD("fdc", 1000000) - MCFG_WD_FDC_INTRQ_CALLBACK(DEVWRITELINE("pic", pic8259_device, ir0_w)) - MCFG_WD_FDC_DRQ_CALLBACK(DEVWRITELINE("maincpu", i80186_cpu_device, drq1_w)) + // rtc + MCFG_DEVICE_ADD("rtc", MM58167, XTAL_32_768kHz) + MCFG_MM58167_IRQ_CALLBACK(DEVWRITELINE("pic", pic8259_device, ir3_w)) - // floppy drives - MCFG_FLOPPY_DRIVE_ADD("fdc:0", rc759_floppies, "hd", floppy_image_device::default_floppy_formats) - MCFG_FLOPPY_DRIVE_ADD("fdc:1", rc759_floppies, "hd", floppy_image_device::default_floppy_formats) + // video + MCFG_SCREEN_ADD("screen", RASTER) + MCFG_SCREEN_RAW_PARAMS(1250000 * 16, 896, 96, 816, 377, 4, 364) // 22 kHz setting + MCFG_SCREEN_UPDATE_DEVICE("txt", i82730_device, screen_update) + + MCFG_I82730_ADD("txt", "maincpu", 1250000) + MCFG_VIDEO_SET_SCREEN("screen") + MCFG_I82730_UPDATE_ROW_CB(rc759_state, txt_update_row) + MCFG_I82730_SINT_HANDLER(DEVWRITELINE("pic", pic8259_device, ir4_w)) + + // keyboard + MCFG_DEVICE_ADD("keyb", GENERIC_KEYBOARD, 0) + MCFG_GENERIC_KEYBOARD_CB(WRITE8(rc759_state, keyb_put)) // cassette MCFG_CASSETTE_ADD("cas") MCFG_CASSETTE_DEFAULT_STATE(CASSETTE_PLAY | CASSETTE_MOTOR_DISABLED | CASSETTE_SPEAKER_MUTED) + + // sound + MCFG_SPEAKER_STANDARD_MONO("mono") + MCFG_SOUND_ADD("speaker", SPEAKER_SOUND, 0) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.50) + MCFG_SOUND_ADD("snd", SN76489A, XTAL_20MHz / 10) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.0) + + // internal centronics + MCFG_CENTRONICS_ADD("centronics", centronics_devices, "printer") + MCFG_CENTRONICS_BUSY_HANDLER(WRITELINE(rc759_state, centronics_busy_w)) + MCFG_CENTRONICS_ACK_HANDLER(WRITELINE(rc759_state, centronics_ack_w)) + MCFG_CENTRONICS_FAULT_HANDLER(WRITELINE(rc759_state, centronics_fault_w)) + MCFG_CENTRONICS_PERROR_HANDLER(WRITELINE(rc759_state, centronics_perror_w)) + MCFG_CENTRONICS_SELECT_HANDLER(WRITELINE(rc759_state, centronics_select_w)) + + // isbx slot + MCFG_ISBX_SLOT_ADD("isbx", 0, isbx_cards, NULL) + MCFG_ISBX_SLOT_MINTR0_CALLBACK(DEVWRITELINE("maincpu", i80186_cpu_device, int1_w)) + MCFG_ISBX_SLOT_MINTR1_CALLBACK(DEVWRITELINE("maincpu", i80186_cpu_device, int3_w)) + MCFG_ISBX_SLOT_MDRQT_CALLBACK(DEVWRITELINE("maincpu", i80186_cpu_device, drq0_w)) + + // floppy disk controller + MCFG_WD2797_ADD("fdc", 1000000) +// MCFG_WD_FDC_INTRQ_CALLBACK(DEVWRITELINE("pic", pic8259_device, ir0_w)) +// MCFG_WD_FDC_DRQ_CALLBACK(DEVWRITELINE("maincpu", i80186_cpu_device, drq1_w)) + + // floppy drives + MCFG_FLOPPY_DRIVE_ADD("fdc:0", rc759_floppies, "hd", floppy_image_device::default_floppy_formats) + MCFG_FLOPPY_DRIVE_ADD("fdc:1", rc759_floppies, "hd", floppy_image_device::default_floppy_formats) MACHINE_CONFIG_END @@ -339,4 +614,4 @@ ROM_END // SYSTEM DRIVERS //************************************************************************** -COMP( 1984, rc759, 0, 0, rc759, 0, driver_device, 0, "Regnecentralen", "RC759", GAME_NOT_WORKING | GAME_NO_SOUND ) +COMP( 1984, rc759, 0, 0, rc759, rc759, driver_device, 0, "Regnecentralen", "RC759 Piccoline", GAME_NOT_WORKING | GAME_NO_SOUND )