rc759: wip. initial version of the intel 82730 text coprocessor, and

added more meat to the driver. currently dies testing the cassette.
This commit is contained in:
Dirk Best 2015-06-27 19:44:50 +02:00
parent 48990c4ae4
commit caa26040c7
5 changed files with 1023 additions and 51 deletions

View File

@ -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

View File

@ -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

527
src/emu/video/i82730.c Normal file
View File

@ -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<i82730_device>;
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<i82730_device &>(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<cpu_device>(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;
}

157
src/emu/video/i82730.h Normal file
View File

@ -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<void (bitmap_rgb32 &bitmap, UINT16 *data, UINT8 lc, UINT16 y, int x_count)> 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<class _Object> static devcb_base &set_sint_handler(device_t &device, _Object object)
{ return downcast<i82730_device &>(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<i82730_device &>(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__

View File

@ -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<i80186_cpu_device> m_maincpu;
required_device<pic8259_device> m_pic;
required_device<nvram_device> m_nvram;
required_device<i8255_device> m_ppi;
required_device<i82730_device> m_txt;
required_device<cassette_image_device> m_cas;
required_device<isbx_slot_device> m_isbx;
required_device<speaker_sound_device> m_speaker;
required_device<sn76489a_device> m_snd;
required_device<mm58167_device> m_rtc;
required_device<centronics_device> m_centronics;
required_device<wd2797_t> m_fdc;
required_device<floppy_connector> m_floppy0;
required_device<floppy_connector> m_floppy1;
required_shared_ptr<UINT16> m_vram;
required_ioport m_config;
std::vector<UINT8> 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 )